summaryrefslogtreecommitdiffstats
path: root/drivers/macintosh/windfarm_pm81.c
Commit message (Collapse)AuthorAgeFilesLines
* treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 246Thomas Gleixner2019-06-191-3/+1Star
| | | | | | | | | | | | | | | | | | | | Based on 1 normalized pattern(s): released under the term of the gnu gpl v2 extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference in 16 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Allison Randal <allison@lohutok.net> Reviewed-by: Enrico Weigelt <info@metux.net> Reviewed-by: Alexios Zavras <alexios.zavras@intel.com> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190602204654.922331175@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* macintosh/windfarm: fix spelling mistake: "ttarged" -> "ttarget"Colin Ian King2018-05-141-1/+1
| | | | | | | | Trivial fix to spelling mistake in debug messages of a structure field name Signed-off-by: Colin Ian King <colin.king@canonical.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
* macintosh: change some data types from int to boolGustavo A. R. Silva2018-01-281-2/+3
| | | | | | | | | | | | | | | | Change the data type of the following variables from int to bool across all macintosh drivers: started slots_started pm121_started wf_smu_started Some of these issues were detected with the help of Coccinelle. Suggested-by: Michael Ellerman <mpe@ellerman.id.au> Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
* macintosh: drop owner assignment from platform_driversWolfram Sang2014-10-201-1/+0Star
| | | | | | | A platform_driver does not need to set an owner, it will be populated by the driver core. Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
* powerpc/windfarm: Fix overtemperature clearingAaro Koskinen2013-07-011-1/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | With pm81/pm91/pm121, when the overtemperature state is entered, and when it remains on after skipped ticks, the driver will try to leave it too soon (immediately on the next tick). This is because the active FAILURE_OVERTEMP state is not visible in "new_failure" variable of the current tick. Furthermore, the driver will keep trying to clear condition in subsequent ticks as FAILURE_OVERTEMP remains set in the "last_failure" variable. These will start to trigger WARNINGS from windfarm core: [ 100.082735] windfarm: Clamping CPU frequency to minimum ! [ 100.108132] windfarm: Overtemp condition detected ! [ 101.952908] windfarm: Overtemp condition cleared ! [...] [ 102.980388] WARNING: at drivers/macintosh/windfarm_core.c:463 [...] [ 103.982227] WARNING: at drivers/macintosh/windfarm_core.c:463 [...] [ 105.030494] WARNING: at drivers/macintosh/windfarm_core.c:463 [...] [ 105.973666] WARNING: at drivers/macintosh/windfarm_core.c:463 [...] [ 106.977913] WARNING: at drivers/macintosh/windfarm_core.c:463 Fix by adding a helper global variable. We leave the overtemp state only after all failure bits have been cleared. I saw this error on iMac G5 iSight (pm121). Also pm81/pm91 are fixed based on the observation that these are almost identical/copy-pasted code. Signed-off-by: Aaro Koskinen <aaro.koskinen@iki.fi> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
* Drivers: macintosh: remove __dev* attributes.Greg Kroah-Hartman2013-01-041-2/+2
| | | | | | | | | | | | | | | CONFIG_HOTPLUG is going away as an option. As a result, the __dev* markings need to be removed. This change removes the use of __devinit, __devexit_p, __devinitconst, and __devexit from these drivers. Based on patches originally written by Bill Pemberton, but redone by me in order to handle some of the coding style issues better, by hand. Cc: Bill Pemberton <wfp5p@virginia.edu> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* powerpc/windfarm: Add useful accessorsBenjamin Herrenschmidt2012-04-301-13/+12Star
| | | | | | Makes the code more readable Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
* Remove all #inclusions of asm/system.hDavid Howells2012-03-281-1/+0Star
| | | | | | | | | Remove all #inclusions of asm/system.h preparatory to splitting and killing it. Performed with the following command: perl -p -i -e 's!^#\s*include\s*<asm/system[.]h>.*\n!!' `grep -Irl '^#\s*include\s*<asm/system[.]h>' *` Signed-off-by: David Howells <dhowells@redhat.com>
* Merge branch 'next' of ↵Linus Torvalds2010-05-211-4/+2Star
|\ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (92 commits) powerpc: Remove unused 'protect4gb' boot parameter powerpc: Build-in e1000e for pseries & ppc64_defconfig powerpc/pseries: Make request_ras_irqs() available to other pseries code powerpc/numa: Use ibm,architecture-vec-5 to detect form 1 affinity powerpc/numa: Set a smaller value for RECLAIM_DISTANCE to enable zone reclaim powerpc: Use smt_snooze_delay=-1 to always busy loop powerpc: Remove check of ibm,smt-snooze-delay OF property powerpc/kdump: Fix race in kdump shutdown powerpc/kexec: Fix race in kexec shutdown powerpc/kexec: Speedup kexec hash PTE tear down powerpc/pseries: Add hcall to read 4 ptes at a time in real mode powerpc: Use more accurate limit for first segment memory allocations powerpc/kdump: Use chip->shutdown to disable IRQs powerpc/kdump: CPUs assume the context of the oopsing CPU powerpc/crashdump: Do not fail on NULL pointer dereferencing powerpc/eeh: Fix oops when probing in early boot powerpc/pci: Check devices status property when scanning OF tree powerpc/vio: Switch VIO Bus PM to use generic helpers powerpc: Avoid bad relocations in iSeries code powerpc: Use common cpu_die (fixes SMP+SUSPEND build) ...
| * powerpc/pmac/windfarm: Don't test pointers before kfree()d binderman2010-04-071-4/+2Star
| | | | | | | | | | | | | | | | | | | | Fix minor nits found by cppcheck [./macintosh/windfarm_pm81.c:760]: (style) Redundant condition. It is safe to deallocate a NULL pointer [./macintosh/windfarm_pm81.c:762]: (style) Redundant condition. It is safe to deallocate a NULL pointer Signed-off-by: David Binderman <dcb314@hotmail.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
* | Fix typos in commentsThomas Weber2010-03-161-1/+1
|/ | | | | | | | | | | [Ss]ytem => [Ss]ystem udpate => update paramters => parameters orginal => original Signed-off-by: Thomas Weber <swirl@gmx.li> Acked-by: Randy Dunlap <rdunlap@xenotime.net> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
* of: add 'of_' prefix to machine_is_compatible()Grant Likely2010-02-091-2/+2
| | | | | | | | machine is compatible is an OF-specific call. It should have the of_ prefix to protect the global namespace. Signed-off-by: Grant Likely <grant.likely@secretlab.ca> Acked-by: Michal Simek <monstr@monstr.eu>
* [POWERPC] macintosh/windfarm: Fix platform driver hotplug/coldplugKay Sievers2008-04-241-2/+2
| | | | | | | | | | | | | Since 43cc71eed1250755986da4c0f9898f9a635cb3bf, the platform modalias is prefixed with "platform:". Add MODULE_ALIAS() to the hotpluggable "macintosh" platform drivers, to re-enable auto loading. [dbrownell@users.sourceforge.net: registration fixes] Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
* [PATCH] powerpc: windfarm shall request it's sub modulesBenjamin Herrenschmidt2006-11-161-0/+1
| | | | | | | | | | | | The windfarm code, in it's current incarnation, uses request_module() to load the various submodules it needs for a given platform so that only the main platform control module needs to be modprobed. However, it was missing various bits. This fixes it. In the future, we'll use some hotplug mecanisms to try to get all of this auto-loaded on the platforms where it matters but that isn't ready yet. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
* [POWERPC] Fix windfarm platform device usageBenjamin Herrenschmidt2006-10-101-14/+10Star
| | | | | | | | | The windfarm code uses a struct device_driver instead of platform_driver, which can cause crashes if any of the callbacks are called (like on module removal). This fixes it. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
* [POWERPC] powermac: Constify & voidify get_property()Jeremy Kerr2006-07-311-2/+2
| | | | | | | | | | | | | Now that get_property() returns a void *, there's no need to cast its return value. Also, treat the return value as const, so we can constify get_property later. powermac platform & macintosh driver changes. Built for pmac32_defconfig, g5_defconfig Signed-off-by: Jeremy Kerr <jk@ozlabs.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
* [PATCH] powerpc: Thermal control for dual core G5sBenjamin Herrenschmidt2006-02-081-75/+12Star
| | | | | | | | | | | | | This patch adds a windfarm module, windfarm_pm112, for the dual core G5s (both 2 and 4 core models), keeping the machine from getting into vacuum-cleaner mode ;) For proper credits, the patch was initially written by Paul Mackerras, and slightly reworked by me to add overtemp handling among others. The patch also removes the sysfs attributes from windfarm_pm81 and windfarm_pm91 and instead adds code to the windfarm core to automagically expose attributes for sensor & controls. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
* spelling: s/retreive/retrieve/Adrian Bunk2006-01-101-1/+1
| | | | Signed-off-by: Adrian Bunk <bunk@stusta.de>
* [PATCH] Fix windfarm model-id tableMichal Ostrowski2005-12-091-2/+2
| | | | | | | | | | model_id fields of wf_smu_sys_all_params should match the model ID they are supposed to represent (as commented). Fixes windfarm on some iMac 8,1 models. Signed-off-by: Michal Ostrowski <mostrows at watson ibm com> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
* [PATCH] ppc64: Thermal control for SMU based machinesBenjamin Herrenschmidt2005-11-081-0/+879
This adds a new thermal control framework for PowerMac, along with the implementation for PowerMac8,1, PowerMac8,2 (iMac G5 rev 1 and 2), and PowerMac9,1 (latest single CPU desktop). In the future, I expect to move the older G5 thermal control to the new framework as well. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
ation/arm64/memory.txt?id=24e7ea3bea94fe05eae5019f5f12bcdc98fc5157&id2=ad6599ab3ac98a4474544086e048ce86ec15a4d1'>Documentation/arm64/memory.txt16
-rw-r--r--Documentation/blackfin/00-INDEX6
-rw-r--r--Documentation/block/00-INDEX2
-rw-r--r--Documentation/blockdev/drbd/data-structure-v9.txt38
-rw-r--r--Documentation/connector/cn_test.c2
-rw-r--r--Documentation/cpu-freq/core.txt4
-rw-r--r--Documentation/cpu-freq/cpu-drivers.txt8
-rw-r--r--Documentation/device-mapper/cache.txt11
-rw-r--r--Documentation/device-mapper/thin-provisioning.txt34
-rw-r--r--Documentation/devices.txt10
-rw-r--r--Documentation/devicetree/00-INDEX2
-rw-r--r--Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt8
-rw-r--r--Documentation/devicetree/bindings/arm/atmel-adc.txt5
-rw-r--r--Documentation/devicetree/bindings/arm/marvell,dove.txt22
-rw-r--r--Documentation/devicetree/bindings/arm/omap/omap.txt2
-rw-r--r--Documentation/devicetree/bindings/ata/ahci-platform.txt22
-rw-r--r--Documentation/devicetree/bindings/ata/apm-xgene.txt76
-rw-r--r--Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt4
-rw-r--r--Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt16
-rw-r--r--Documentation/devicetree/bindings/gpio/cirrus,clps711x-mctrl-gpio.txt17
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-davinci.txt25
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-zevio.txt16
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio.txt60
-rw-r--r--Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt60
-rw-r--r--Documentation/devicetree/bindings/graph.txt129
-rw-r--r--Documentation/devicetree/bindings/i2c/trivial-devices.txt1
-rw-r--r--Documentation/devicetree/bindings/iio/adc/vf610-adc.txt22
-rw-r--r--Documentation/devicetree/bindings/iio/adc/xilinx-xadc.txt113
-rw-r--r--Documentation/devicetree/bindings/input/clps711x-keypad.txt27
-rw-r--r--Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt89
-rw-r--r--Documentation/devicetree/bindings/input/qcom,pm8xxx-pwrkey.txt46
-rw-r--r--Documentation/devicetree/bindings/input/qcom,pm8xxx-vib.txt22
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt55
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/zforce_ts.txt30
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt4
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/allwinner,sun67i-sc-nmi.txt27
-rw-r--r--Documentation/devicetree/bindings/media/img-ir-rev1.txt34
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/fsl/ifc.txt (renamed from Documentation/devicetree/bindings/powerpc/fsl/ifc.txt)0
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/ti-aemif.txt210
-rw-r--r--Documentation/devicetree/bindings/mfd/s2mpa01.txt90
-rw-r--r--Documentation/devicetree/bindings/mfd/s2mps11.txt12
-rw-r--r--Documentation/devicetree/bindings/mfd/tps65910.txt2
-rw-r--r--Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt4
-rw-r--r--Documentation/devicetree/bindings/misc/atmel-ssc.txt8
-rw-r--r--Documentation/devicetree/bindings/misc/sram.txt35
-rw-r--r--Documentation/devicetree/bindings/mmc/atmel-hsmci.txt5
-rw-r--r--Documentation/devicetree/bindings/net/allwinner,sun4i-emac.txt11
-rw-r--r--Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt5
-rw-r--r--Documentation/devicetree/bindings/net/altera_tse.txt114
-rw-r--r--Documentation/devicetree/bindings/net/arc_emac.txt11
-rw-r--r--Documentation/devicetree/bindings/net/broadcom-bcmgenet.txt121
-rw-r--r--Documentation/devicetree/bindings/net/can/sja1000.txt4
-rw-r--r--Documentation/devicetree/bindings/net/cavium-mix.txt7
-rw-r--r--Documentation/devicetree/bindings/net/cavium-pip.txt7
-rw-r--r--Documentation/devicetree/bindings/net/cdns-emac.txt6
-rw-r--r--Documentation/devicetree/bindings/net/cpsw.txt5
-rw-r--r--Documentation/devicetree/bindings/net/davicom-dm9000.txt2
-rw-r--r--Documentation/devicetree/bindings/net/davinci_emac.txt3
-rw-r--r--Documentation/devicetree/bindings/net/ethernet.txt25
-rw-r--r--Documentation/devicetree/bindings/net/fsl-fec.txt5
-rw-r--r--Documentation/devicetree/bindings/net/fsl-tsec-phy.txt13
-rw-r--r--Documentation/devicetree/bindings/net/lpc-eth.txt5
-rw-r--r--Documentation/devicetree/bindings/net/macb.txt6
-rw-r--r--Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt6
-rw-r--r--Documentation/devicetree/bindings/net/marvell-orion-net.txt4
-rw-r--r--Documentation/devicetree/bindings/net/micrel-ks8851.txt2
-rw-r--r--Documentation/devicetree/bindings/net/micrel.txt18
-rw-r--r--Documentation/devicetree/bindings/net/nfc/trf7970a.txt34
-rw-r--r--Documentation/devicetree/bindings/net/opencores-ethoc.txt22
-rw-r--r--Documentation/devicetree/bindings/net/phy.txt10
-rw-r--r--Documentation/devicetree/bindings/net/samsung-sxgbe.txt52
-rw-r--r--Documentation/devicetree/bindings/net/sh_eth.txt55
-rw-r--r--Documentation/devicetree/bindings/net/smsc-lan91c111.txt3
-rw-r--r--Documentation/devicetree/bindings/net/smsc911x.txt5
-rw-r--r--Documentation/devicetree/bindings/net/sti-dwmac.txt58
-rw-r--r--Documentation/devicetree/bindings/net/stmmac.txt7
-rw-r--r--Documentation/devicetree/bindings/net/wireless/ti,wl1251.txt39
-rw-r--r--Documentation/devicetree/bindings/phy/apm-xgene-phy.txt79
-rw-r--r--Documentation/devicetree/bindings/phy/samsung-phy.txt54
-rw-r--r--Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt26
-rw-r--r--Documentation/devicetree/bindings/phy/ti-phy.txt86
-rw-r--r--Documentation/devicetree/bindings/pinctrl/brcm,bcm11351-pinctrl.txt (renamed from Documentation/devicetree/bindings/pinctrl/brcm,capri-pinctrl.txt)8
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt1
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt82
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt80
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt1
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt1
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt1
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt2
-rw-r--r--Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt7
-rw-r--r--Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt73
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.txt14
-rw-r--r--Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt1
-rw-r--r--Documentation/devicetree/bindings/power/bq2415x.txt47
-rw-r--r--Documentation/devicetree/bindings/powerpc/fsl/l2cache.txt23
-rw-r--r--Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt27
-rw-r--r--Documentation/devicetree/bindings/regulator/gpio-regulator.txt4
-rw-r--r--Documentation/devicetree/bindings/regulator/pfuze100.txt96
-rw-r--r--Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt13
-rw-r--r--Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt6
-rw-r--r--Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt133
-rw-r--r--Documentation/devicetree/bindings/rtc/sunxi-rtc.txt4
-rw-r--r--Documentation/devicetree/bindings/serial/efm32-uart.txt4
-rw-r--r--Documentation/devicetree/bindings/serial/fsl-lpuart.txt21
-rw-r--r--Documentation/devicetree/bindings/serial/maxim,max310x.txt36
-rw-r--r--Documentation/devicetree/bindings/serial/renesas,sci-serial.txt2
-rw-r--r--Documentation/devicetree/bindings/sound/armada-370db-audio.txt27
-rw-r--r--Documentation/devicetree/bindings/sound/cs42xx8.txt28
-rw-r--r--Documentation/devicetree/bindings/sound/da9055.txt22
-rw-r--r--Documentation/devicetree/bindings/sound/davinci-evm-audio.txt9
-rw-r--r--Documentation/devicetree/bindings/sound/eukrea-tlv320.txt21
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,esai.txt5
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,spdif.txt5
-rw-r--r--Documentation/devicetree/bindings/sound/mvebu-audio.txt1
-rw-r--r--Documentation/devicetree/bindings/sound/pcm512x.txt30
-rw-r--r--Documentation/devicetree/bindings/sound/renesas,rsnd.txt105
-rw-r--r--Documentation/devicetree/bindings/sound/simple-card.txt65
-rw-r--r--Documentation/devicetree/bindings/sound/sirf-audio-codec.txt17
-rw-r--r--Documentation/devicetree/bindings/sound/sirf-audio-port.txt20
-rw-r--r--Documentation/devicetree/bindings/sound/sirf-audio.txt41
-rw-r--r--Documentation/devicetree/bindings/sound/tdm-slot.txt20
-rw-r--r--Documentation/devicetree/bindings/sound/tlv320aic31xx.txt61
-rw-r--r--Documentation/devicetree/bindings/sound/tlv320aic32x4.txt30
-rw-r--r--Documentation/devicetree/bindings/sound/tlv320aic3x.txt1
-rw-r--r--Documentation/devicetree/bindings/sound/widgets.txt20
-rw-r--r--Documentation/devicetree/bindings/spi/efm32-spi.txt8
-rw-r--r--Documentation/devicetree/bindings/spi/qcom,spi-qup.txt85
-rw-r--r--Documentation/devicetree/bindings/spi/sh-hspi.txt28
-rw-r--r--Documentation/devicetree/bindings/spi/sh-msiof.txt42
-rw-r--r--Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt2
-rw-r--r--Documentation/devicetree/bindings/spi/spi-rspi.txt61
-rw-r--r--Documentation/devicetree/bindings/spi/spi-sun4i.txt24
-rw-r--r--Documentation/devicetree/bindings/spi/spi-sun6i.txt24
-rw-r--r--Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt9
-rw-r--r--Documentation/devicetree/bindings/spi/spi_atmel.txt5
-rw-r--r--Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt61
-rw-r--r--Documentation/devicetree/bindings/spmi/spmi.txt41
-rw-r--r--Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt48
-rw-r--r--Documentation/devicetree/bindings/staging/imx-drm/hdmi.txt58
-rw-r--r--Documentation/devicetree/bindings/staging/imx-drm/ldb.txt20
-rw-r--r--Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt4
-rw-r--r--Documentation/devicetree/bindings/timer/ti,keystone-timer.txt29
-rw-r--r--Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt2
-rw-r--r--Documentation/devicetree/bindings/usb/ci-hdrc-zevio.txt17
-rw-r--r--Documentation/devicetree/bindings/usb/dwc3.txt6
-rw-r--r--Documentation/devicetree/bindings/usb/fsl-usb.txt4
-rw-r--r--Documentation/devicetree/bindings/usb/mxs-phy.txt8
-rw-r--r--Documentation/devicetree/bindings/usb/omap-usb.txt24
-rw-r--r--Documentation/devicetree/bindings/usb/usb-ehci.txt27
-rw-r--r--Documentation/devicetree/bindings/usb/usb-ohci.txt25
-rw-r--r--Documentation/devicetree/bindings/usb/usb-phy.txt48
-rw-r--r--Documentation/devicetree/bindings/usb/usb-uhci.txt (renamed from Documentation/devicetree/bindings/usb/platform-uhci.txt)4
-rw-r--r--Documentation/devicetree/bindings/usb/usb-xhci.txt4
-rw-r--r--Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt15
-rw-r--r--Documentation/devicetree/bindings/usb/vt8500-ehci.txt12
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt23
-rw-r--r--Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt23
-rw-r--r--Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt6
-rwxr-xr-xDocumentation/dvb/get_dvb_firmware22
-rw-r--r--Documentation/dvb/it9137.txt9
-rw-r--r--Documentation/edac.txt2
-rw-r--r--Documentation/fb/00-INDEX6
-rw-r--r--Documentation/filesystems/00-INDEX2
-rw-r--r--Documentation/filesystems/Locking6
-rw-r--r--Documentation/filesystems/autofs4-mount-control.txt2
-rw-r--r--Documentation/filesystems/hfsplus.txt2
-rw-r--r--Documentation/filesystems/nfs/00-INDEX4
-rw-r--r--Documentation/filesystems/nilfs2.txt12
-rw-r--r--Documentation/filesystems/ntfs.txt2
-rw-r--r--Documentation/filesystems/porting6
-rw-r--r--Documentation/filesystems/vfs.txt16
-rw-r--r--Documentation/fmc/fmc-write-eeprom.txt77
-rw-r--r--Documentation/futex-requeue-pi.txt2
-rw-r--r--Documentation/gpio/consumer.txt1
-rw-r--r--Documentation/gpio/driver.txt35
-rw-r--r--Documentation/hid/hid-transport.txt317
-rw-r--r--Documentation/hid/uhid.txt11
-rw-r--r--Documentation/hwmon/adc128d81847
-rw-r--r--Documentation/hwmon/k10temp6
-rw-r--r--Documentation/hwmon/lm952458
-rw-r--r--Documentation/hwmon/ltc294584
-rw-r--r--Documentation/hwmon/ltc297817
-rw-r--r--Documentation/hwmon/ltc426056
-rw-r--r--Documentation/i2c/instantiating-devices41
-rw-r--r--Documentation/ide/00-INDEX2
-rw-r--r--Documentation/input/multi-touch-protocol.txt2
-rw-r--r--Documentation/ja_JP/SubmittingPatches9
-rw-r--r--Documentation/kernel-parameters.txt51
-rw-r--r--Documentation/kernel-per-CPU-kthreads.txt13
-rw-r--r--Documentation/kmemcheck.txt2
-rw-r--r--Documentation/kmemleak.txt23
-rw-r--r--Documentation/laptops/00-INDEX6
-rw-r--r--Documentation/leds/00-INDEX8
-rw-r--r--Documentation/m68k/00-INDEX2
-rw-r--r--Documentation/memory-barriers.txt139
-rw-r--r--Documentation/module-signing.txt10
-rw-r--r--Documentation/networking/00-INDEX30
-rw-r--r--Documentation/networking/3c505.txt45
-rw-r--r--Documentation/networking/altera_tse.txt263
-rw-r--r--Documentation/networking/bonding.txt96
-rw-r--r--Documentation/networking/can.txt8
-rw-r--r--Documentation/networking/filter.txt125
-rw-r--r--Documentation/networking/gianfar.txt30
-rw-r--r--Documentation/networking/igb.txt48
-rw-r--r--Documentation/networking/netlink_mmap.txt4
-rw-r--r--Documentation/networking/packet_mmap.txt2
-rw-r--r--Documentation/networking/phy.txt11
-rw-r--r--Documentation/networking/pktgen.txt24
-rw-r--r--Documentation/networking/rxrpc.txt81
-rw-r--r--Documentation/networking/spider_net.txt2
-rw-r--r--Documentation/networking/tcp.txt2
-rw-r--r--Documentation/networking/timestamping.txt58
-rw-r--r--Documentation/phy.txt26
-rw-r--r--Documentation/phy/samsung-usb2.txt135
-rw-r--r--Documentation/power/00-INDEX6
-rw-r--r--Documentation/power/devices.txt2
-rw-r--r--Documentation/power/pm_qos_interface.txt82
-rw-r--r--Documentation/power/runtime_pm.txt29
-rw-r--r--Documentation/ptp/testptp.c96
-rw-r--r--Documentation/s390/00-INDEX8
-rw-r--r--Documentation/scheduler/00-INDEX2
-rw-r--r--Documentation/scsi/00-INDEX16
-rw-r--r--Documentation/scsi/ChangeLog.megaraid_sas13
-rw-r--r--Documentation/security/Smack.txt2
-rw-r--r--Documentation/serial/00-INDEX6
-rw-r--r--Documentation/sgi-visws.txt13
-rw-r--r--Documentation/sound/oss/vwsnd293
-rw-r--r--Documentation/spi/00-INDEX22
-rw-r--r--Documentation/spi/spi-summary17
-rw-r--r--Documentation/spi/spidev6
-rw-r--r--Documentation/spi/spidev_fdx.c8
-rw-r--r--Documentation/spi/spidev_test.c45
-rw-r--r--Documentation/sysctl/kernel.txt15
-rw-r--r--Documentation/sysctl/vm.txt33
-rw-r--r--Documentation/timers/00-INDEX2
-rw-r--r--Documentation/trace/events-power.txt2
-rw-r--r--Documentation/trace/ftrace-design.txt5
-rw-r--r--Documentation/trace/ring-buffer-design.txt2
-rw-r--r--Documentation/usb/WUSB-Design-overview.txt2
-rw-r--r--Documentation/video4linux/CARDLIST.bttv1
-rw-r--r--Documentation/video4linux/CARDLIST.cx238855
-rw-r--r--Documentation/video4linux/CARDLIST.em28xx6
-rw-r--r--Documentation/video4linux/gspca.txt1
-rw-r--r--Documentation/video4linux/v4l2-framework.txt5
-rw-r--r--Documentation/video4linux/v4l2-pci-skeleton.c913
-rw-r--r--Documentation/virtual/kvm/00-INDEX2
-rw-r--r--Documentation/virtual/kvm/api.txt49
-rw-r--r--Documentation/virtual/kvm/devices/s390_flic.txt91
-rw-r--r--Documentation/vm/00-INDEX4
-rw-r--r--Documentation/vm/unevictable-lru.txt2
-rw-r--r--Documentation/w1/masters/00-INDEX4
-rw-r--r--Documentation/w1/masters/ds24902
-rw-r--r--Documentation/w1/slaves/00-INDEX2
-rw-r--r--Documentation/w1/w1.netlink8
-rw-r--r--Documentation/watchdog/watchdog-parameters.txt7
-rw-r--r--Documentation/x86/00-INDEX18
-rw-r--r--Documentation/x86/boot.txt4
-rw-r--r--Documentation/zh_CN/SubmittingPatches8
-rw-r--r--Documentation/zh_CN/arm64/booting.txt65
-rw-r--r--Documentation/zh_CN/arm64/memory.txt46
-rw-r--r--Documentation/zh_CN/arm64/tagged-pointers.txt52
-rw-r--r--MAINTAINERS426
-rw-r--r--Makefile17
-rw-r--r--arch/alpha/include/asm/Kbuild8
-rw-r--r--arch/alpha/include/asm/cputime.h6
-rw-r--r--arch/alpha/kernel/pci.c6
-rw-r--r--arch/arc/Kconfig1
-rw-r--r--arch/arc/include/asm/Kbuild7
-rw-r--r--arch/arc/mm/cache_arc700.c4
-rw-r--r--arch/arm/Kconfig7
-rw-r--r--arch/arm/Makefile7
-rw-r--r--arch/arm/boot/compressed/.gitignore1
-rw-r--r--arch/arm/boot/dts/Makefile8
-rw-r--r--arch/arm/boot/dts/am335x-evmsk.dts11
-rw-r--r--arch/arm/boot/dts/armada-xp-mv78260.dtsi3
-rw-r--r--arch/arm/boot/dts/at91-sama5d3_xplained.dts229
-rw-r--r--arch/arm/boot/dts/at91sam9263.dtsi2
-rw-r--r--arch/arm/boot/dts/at91sam9n12ek.dts4
-rw-r--r--arch/arm/boot/dts/atlas6.dtsi17
-rw-r--r--arch/arm/boot/dts/bcm11351.dtsi2
-rw-r--r--arch/arm/boot/dts/dove.dtsi11
-rw-r--r--arch/arm/boot/dts/imx51-apf51dev.dts11
-rw-r--r--arch/arm/boot/dts/imx51-babbage.dts26
-rw-r--r--arch/arm/boot/dts/imx51.dtsi22
-rw-r--r--arch/arm/boot/dts/imx53-m53evk.dts13
-rw-r--r--arch/arm/boot/dts/imx53-mba53.dts13
-rw-r--r--arch/arm/boot/dts/imx53-qsb.dts13
-rw-r--r--arch/arm/boot/dts/imx53.dtsi64
-rw-r--r--arch/arm/boot/dts/imx6dl-hummingboard.dts10
-rw-r--r--arch/arm/boot/dts/imx6dl.dtsi17
-rw-r--r--arch/arm/boot/dts/imx6q.dtsi123
-rw-r--r--arch/arm/boot/dts/imx6qdl-cubox-i.dtsi10
-rw-r--r--arch/arm/boot/dts/imx6qdl.dtsi137
-rw-r--r--arch/arm/boot/dts/keystone-clocks.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-gta04.dts8
-rw-r--r--arch/arm/boot/dts/omap3-igep0020.dts2
-rw-r--r--arch/arm/boot/dts/omap3-igep0030.dts2
-rw-r--r--arch/arm/boot/dts/omap3-n9.dts2
-rw-r--r--arch/arm/boot/dts/omap3-n900.dts4
-rw-r--r--arch/arm/boot/dts/omap3-n950.dts2
-rw-r--r--arch/arm/boot/dts/omap3-overo-storm-tobi.dts22
-rw-r--r--arch/arm/boot/dts/omap3-overo-tobi-common.dtsi (renamed from arch/arm/boot/dts/omap3-tobi.dts)3
-rw-r--r--arch/arm/boot/dts/omap3-overo-tobi.dts22
-rw-r--r--arch/arm/boot/dts/omap3-overo.dtsi3
-rw-r--r--arch/arm/boot/dts/prima2.dtsi20
-rw-r--r--arch/arm/boot/dts/r8a7791.dtsi2
-rw-r--r--arch/arm/boot/dts/sama5d3.dtsi2
-rw-r--r--arch/arm/boot/dts/sama5d36.dtsi2
-rw-r--r--arch/arm/boot/dts/ste-href.dtsi1
-rw-r--r--arch/arm/boot/dts/sun4i-a10.dtsi14
-rw-r--r--arch/arm/boot/dts/sun5i-a10s.dtsi12
-rw-r--r--arch/arm/boot/dts/sun5i-a13.dtsi8
-rw-r--r--arch/arm/boot/dts/sun6i-a31.dtsi10
-rw-r--r--arch/arm/boot/dts/sun7i-a20.dtsi26
-rw-r--r--arch/arm/boot/dts/tegra114.dtsi4
-rw-r--r--arch/arm/boot/dts/tegra20.dtsi4
-rw-r--r--arch/arm/boot/dts/tegra30-cardhu.dtsi2
-rw-r--r--arch/arm/boot/dts/tegra30.dtsi4
-rw-r--r--arch/arm/boot/dts/testcases/tests.dtsi2
-rw-r--r--arch/arm/boot/dts/versatile-pb.dts4
-rw-r--r--arch/arm/boot/dts/zynq-7000.dtsi6
-rw-r--r--arch/arm/configs/multi_v7_defconfig1
-rw-r--r--arch/arm/configs/tegra_defconfig3
-rw-r--r--arch/arm/include/asm/Kbuild5
-rw-r--r--arch/arm/include/asm/cacheflush.h1
-rw-r--r--arch/arm/include/asm/dma-iommu.h12
-rw-r--r--arch/arm/include/asm/kvm_arm.h4
-rw-r--r--arch/arm/include/asm/kvm_asm.h4
-rw-r--r--arch/arm/include/asm/kvm_host.h9
-rw-r--r--arch/arm/include/asm/kvm_mmu.h30
-rw-r--r--arch/arm/include/asm/memory.h9
-rw-r--r--arch/arm/include/asm/pgtable-3level.h15
-rw-r--r--arch/arm/include/asm/spinlock.h15
-rw-r--r--arch/arm/include/asm/topology.h3
-rw-r--r--arch/arm/include/asm/xen/page.h15
-rw-r--r--arch/arm/kernel/asm-offsets.c1
-rw-r--r--arch/arm/kernel/bios32.c9
-rw-r--r--arch/arm/kernel/ftrace.c4
-rw-r--r--arch/arm/kernel/head-common.S12
-rw-r--r--arch/arm/kernel/head.S2
-rw-r--r--arch/arm/kernel/process.c16
-rw-r--r--arch/arm/kernel/setup.c2
-rw-r--r--arch/arm/kernel/smp.c3
-rw-r--r--arch/arm/kernel/smp_twd.c2
-rw-r--r--arch/arm/kernel/sys_oabi-compat.c3
-rw-r--r--arch/arm/kvm/arm.c3
-rw-r--r--arch/arm/kvm/coproc.c84
-rw-r--r--arch/arm/kvm/coproc.h14
-rw-r--r--arch/arm/kvm/coproc_a15.c2
-rw-r--r--arch/arm/kvm/coproc_a7.c2
-rw-r--r--arch/arm/kvm/guest.c1
-rw-r--r--arch/arm/kvm/interrupts.S11
-rw-r--r--arch/arm/kvm/interrupts_head.S21
-rw-r--r--arch/arm/kvm/mmu.c110
-rw-r--r--arch/arm/mach-davinci/da850.c2
-rw-r--r--arch/arm/mach-davinci/devices-da8xx.c99
-rw-r--r--arch/arm/mach-exynos/Kconfig1
-rw-r--r--arch/arm/mach-hisi/Kconfig2
-rw-r--r--arch/arm/mach-imx/Makefile2
-rw-r--r--arch/arm/mach-imx/clk-imx6q.c3
-rw-r--r--arch/arm/mach-imx/clk-imx6sl.c3
-rw-r--r--arch/arm/mach-imx/common.h4
-rw-r--r--arch/arm/mach-imx/mach-mx31moboard.c21
-rw-r--r--arch/arm/mach-imx/pm-imx6q.c9
-rw-r--r--arch/arm/mach-mmp/pm-mmp2.c16
-rw-r--r--arch/arm/mach-mmp/pm-pxa910.c20
-rw-r--r--arch/arm/mach-moxart/Kconfig1
-rw-r--r--arch/arm/mach-mvebu/Kconfig1
-rw-r--r--arch/arm/mach-omap1/ams-delta-fiq.c7
-rw-r--r--arch/arm/mach-omap1/board-nokia770.c1
-rw-r--r--arch/arm/mach-omap2/Kconfig13
-rw-r--r--arch/arm/mach-omap2/board-cm-t35.c16
-rw-r--r--arch/arm/mach-omap2/board-omap3pandora.c6
-rw-r--r--arch/arm/mach-omap2/board-rx51-peripherals.c13
-rw-r--r--arch/arm/mach-omap2/cclock3xxx_data.c2
-rw-r--r--arch/arm/mach-omap2/cpuidle44xx.c8
-rw-r--r--arch/arm/mach-omap2/dpll3xxx.c92
-rw-r--r--arch/arm/mach-omap2/gpmc.c4
-rw-r--r--arch/arm/mach-omap2/io.c9
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c20
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_7xx_data.c9
-rw-r--r--arch/arm/mach-omap2/pdata-quirks.c21
-rw-r--r--arch/arm/mach-omap2/prminst44xx.c4
-rw-r--r--arch/arm/mach-pxa/am300epd.c1
-rw-r--r--arch/arm/mach-pxa/include/mach/balloon3.h2
-rw-r--r--arch/arm/mach-pxa/include/mach/corgi.h1
-rw-r--r--arch/arm/mach-pxa/include/mach/csb726.h2
-rw-r--r--arch/arm/mach-pxa/include/mach/gumstix.h1
-rw-r--r--arch/arm/mach-pxa/include/mach/idp.h1
-rw-r--r--arch/arm/mach-pxa/include/mach/palmld.h2
-rw-r--r--arch/arm/mach-pxa/include/mach/palmt5.h2
-rw-r--r--arch/arm/mach-pxa/include/mach/palmtc.h2
-rw-r--r--arch/arm/mach-pxa/include/mach/palmtx.h2
-rw-r--r--arch/arm/mach-pxa/include/mach/pcm027.h2
-rw-r--r--arch/arm/mach-pxa/include/mach/pcm990_baseboard.h1
-rw-r--r--arch/arm/mach-pxa/include/mach/poodle.h2
-rw-r--r--arch/arm/mach-pxa/include/mach/spitz.h2
-rw-r--r--arch/arm/mach-pxa/include/mach/tosa.h2
-rw-r--r--arch/arm/mach-pxa/include/mach/trizeps4.h2
-rw-r--r--arch/arm/mach-pxa/mioa701.c9
-rw-r--r--arch/arm/mach-pxa/viper.c3
-rw-r--r--arch/arm/mach-sa1100/include/mach/collie.h2
-rw-r--r--arch/arm/mach-shmobile/Kconfig42
-rw-r--r--arch/arm/mach-shmobile/board-armadillo800eva.c4
-rw-r--r--arch/arm/mach-shmobile/board-bockw.c16
-rw-r--r--arch/arm/mach-shmobile/board-kzm9g.c4
-rw-r--r--arch/arm/mach-shmobile/board-mackerel.c6
-rw-r--r--arch/arm/mach-spear/Kconfig2
-rw-r--r--arch/arm/mach-spear/spear1310.c1
-rw-r--r--arch/arm/mach-spear/spear1340.c1
-rw-r--r--arch/arm/mach-tegra/Kconfig1
-rw-r--r--arch/arm/mach-tegra/pm.c1
-rw-r--r--arch/arm/mach-tegra/tegra.c10
-rw-r--r--arch/arm/mach-u300/Makefile2
-rw-r--r--arch/arm/mach-zynq/Kconfig4
-rw-r--r--arch/arm/mach-zynq/common.c17
-rw-r--r--arch/arm/mm/dma-mapping.c146
-rw-r--r--arch/arm/mm/dump.c3
-rw-r--r--arch/arm/mm/init.c2
-rw-r--r--arch/arm/mm/mm.h1
-rw-r--r--arch/arm/mm/mmu.c7
-rw-r--r--arch/arm/mm/proc-v6.S3
-rw-r--r--arch/arm/mm/proc-v7.S2
-rw-r--r--arch/arm/net/bpf_jit_32.c7
-rw-r--r--arch/arm/xen/p2m.c32
-rw-r--r--arch/arm64/Kconfig29
-rw-r--r--arch/arm64/boot/dts/apm-storm.dtsi152
-rw-r--r--arch/arm64/include/asm/Kbuild8
-rw-r--r--arch/arm64/include/asm/barrier.h1
-rw-r--r--arch/arm64/include/asm/cacheflush.h7
-rw-r--r--arch/arm64/include/asm/compat.h2
-rw-r--r--arch/arm64/include/asm/cpufeature.h29
-rw-r--r--arch/arm64/include/asm/debug-monitors.h64
-rw-r--r--arch/arm64/include/asm/dma-mapping.h7
-rw-r--r--arch/arm64/include/asm/hwcap.h9
-rw-r--r--arch/arm64/include/asm/io.h2
-rw-r--r--arch/arm64/include/asm/irqflags.h23
-rw-r--r--arch/arm64/include/asm/kgdb.h84
-rw-r--r--arch/arm64/include/asm/kvm_arm.h18
-rw-r--r--arch/arm64/include/asm/kvm_asm.h3
-rw-r--r--arch/arm64/include/asm/kvm_mmu.h22
-rw-r--r--arch/arm64/include/asm/percpu.h8
-rw-r--r--arch/arm64/include/asm/pgtable-hwdef.h5
-rw-r--r--arch/arm64/include/asm/pgtable.h70
-rw-r--r--arch/arm64/include/asm/psci.h2
-rw-r--r--arch/arm64/include/asm/ptrace.h5
-rw-r--r--arch/arm64/include/asm/tlb.h136
-rw-r--r--arch/arm64/include/asm/topology.h39
-rw-r--r--arch/arm64/include/asm/uaccess.h4
-rw-r--r--arch/arm64/include/asm/unistd.h1
-rw-r--r--arch/arm64/include/uapi/asm/Kbuild1
-rw-r--r--arch/arm64/include/uapi/asm/kvm.h9
-rw-r--r--arch/arm64/include/uapi/asm/perf_regs.h40
-rw-r--r--arch/arm64/kernel/Makefile6
-rw-r--r--arch/arm64/kernel/debug-monitors.c10
-rw-r--r--arch/arm64/kernel/head.S20
-rw-r--r--arch/arm64/kernel/kgdb.c336
-rw-r--r--arch/arm64/kernel/perf_event.c75
-rw-r--r--arch/arm64/kernel/perf_regs.c44
-rw-r--r--arch/arm64/kernel/process.c18
-rw-r--r--arch/arm64/kernel/psci.c13
-rw-r--r--arch/arm64/kernel/setup.c33
-rw-r--r--arch/arm64/kernel/smp.c12
-rw-r--r--arch/arm64/kernel/smp_spin_table.c2
-rw-r--r--arch/arm64/kernel/stacktrace.c6
-rw-r--r--arch/arm64/kernel/topology.c95
-rw-r--r--arch/arm64/kernel/vdso.c42
-rw-r--r--arch/arm64/kvm/hyp-init.S6
-rw-r--r--arch/arm64/kvm/hyp.S27
-rw-r--r--arch/arm64/kvm/sys_regs.c99
-rw-r--r--arch/arm64/kvm/sys_regs.h2
-rw-r--r--arch/arm64/mm/cache.S80
-rw-r--r--arch/arm64/mm/dma-mapping.c246
-rw-r--r--arch/arm64/mm/init.c34
-rw-r--r--arch/arm64/mm/proc.S14
-rw-r--r--arch/avr32/Makefile2
-rw-r--r--arch/avr32/boards/mimc200/Makefile2
-rw-r--r--arch/avr32/boards/mimc200/fram.c81
-rw-r--r--arch/avr32/include/asm/Kbuild42
-rw-r--r--arch/avr32/include/asm/bugs.h2
-rw-r--r--arch/avr32/include/asm/io.h2
-rw-r--r--arch/avr32/include/asm/processor.h7
-rw-r--r--arch/avr32/kernel/cpu.c48
-rw-r--r--arch/avr32/mm/cache.c1
-rw-r--r--arch/blackfin/include/asm/Kbuild7
-rw-r--r--arch/blackfin/include/asm/irq.h9
-rw-r--r--arch/blackfin/kernel/ftrace.c5
-rw-r--r--arch/c6x/include/asm/Kbuild5
-rw-r--r--arch/c6x/include/asm/cache.h1
-rw-r--r--arch/cris/arch-v32/drivers/Kconfig2
-rw-r--r--arch/cris/include/asm/Kbuild4
-rw-r--r--arch/cris/include/asm/bitops.h2
-rw-r--r--arch/cris/include/asm/cputime.h6
-rw-r--r--arch/frv/include/asm/Kbuild6
-rw-r--r--arch/frv/include/asm/cputime.h6
-rw-r--r--arch/frv/mb93090-mb00/pci-frv.c2
-rw-r--r--arch/hexagon/include/asm/Kbuild7
-rw-r--r--arch/ia64/configs/generic_defconfig5
-rw-r--r--arch/ia64/configs/tiger_defconfig1
-rw-r--r--arch/ia64/configs/zx1_defconfig1
-rw-r--r--arch/ia64/hp/common/sba_iommu.c38
-rw-r--r--arch/ia64/include/asm/Kbuild5
-rw-r--r--arch/ia64/include/asm/pci.h2
-rw-r--r--arch/ia64/include/asm/topology.h1
-rw-r--r--arch/ia64/kernel/acpi.c32
-rw-r--r--arch/ia64/kernel/efi.c7
-rw-r--r--arch/ia64/kernel/ftrace.c4
-rw-r--r--arch/ia64/kernel/irq_ia64.c14
-rw-r--r--arch/ia64/kernel/mca.c10
-rw-r--r--arch/ia64/kernel/msi_ia64.c10
-rw-r--r--arch/ia64/kernel/perfmon.c1
-rw-r--r--arch/ia64/kernel/time.c2
-rw-r--r--arch/ia64/kernel/uncached.c2
-rw-r--r--arch/ia64/kvm/kvm-ia64.c1
-rw-r--r--arch/ia64/pci/fixup.c25
-rw-r--r--arch/ia64/pci/pci.c10
-rw-r--r--arch/ia64/sn/kernel/irq.c4
-rw-r--r--arch/ia64/sn/kernel/msi_sn.c2
-rw-r--r--arch/m32r/include/asm/Kbuild6
-rw-r--r--arch/m32r/include/asm/cputime.h6
-rw-r--r--arch/m68k/Kconfig1
-rw-r--r--arch/m68k/amiga/cia.c1
-rw-r--r--arch/m68k/atari/ataints.c1
-rw-r--r--arch/m68k/configs/amiga_defconfig10
-rw-r--r--arch/m68k/configs/apollo_defconfig10
-rw-r--r--arch/m68k/configs/atari_defconfig10
-rw-r--r--arch/m68k/configs/bvme6000_defconfig10
-rw-r--r--arch/m68k/configs/hp300_defconfig10
-rw-r--r--arch/m68k/configs/mac_defconfig10
-rw-r--r--arch/m68k/configs/multi_defconfig10
-rw-r--r--arch/m68k/configs/mvme147_defconfig10
-rw-r--r--arch/m68k/configs/mvme16x_defconfig10
-rw-r--r--arch/m68k/configs/q40_defconfig10
-rw-r--r--arch/m68k/configs/sun3_defconfig10
-rw-r--r--arch/m68k/configs/sun3x_defconfig10
-rw-r--r--arch/m68k/include/asm/Kbuild9
-rw-r--r--arch/m68k/include/asm/barrier.h8
-rw-r--r--arch/m68k/include/asm/unistd.h2
-rw-r--r--arch/m68k/include/uapi/asm/unistd.h2
-rw-r--r--arch/m68k/kernel/head.S70
-rw-r--r--arch/m68k/kernel/ints.c2
-rw-r--r--arch/m68k/kernel/syscalltable.S2
-rw-r--r--arch/metag/Kconfig2
-rw-r--r--arch/metag/include/asm/Kbuild5
-rw-r--r--arch/metag/include/asm/topology.h27
-rw-r--r--arch/metag/kernel/ftrace.c5
-rw-r--r--arch/metag/kernel/irq.c22
-rw-r--r--arch/metag/kernel/signal.c48
-rw-r--r--arch/microblaze/include/asm/Kbuild6
-rw-r--r--arch/microblaze/include/asm/cputime.h1
-rw-r--r--arch/microblaze/include/asm/delay.h2
-rw-r--r--arch/microblaze/include/asm/io.h6
-rw-r--r--arch/microblaze/kernel/ftrace.c5
-rw-r--r--arch/microblaze/kernel/head.S2
-rw-r--r--arch/microblaze/pci/pci-common.c5
-rw-r--r--arch/mips/Kconfig166
-rw-r--r--arch/mips/Kconfig.debug10
-rw-r--r--arch/mips/Makefile5
-rw-r--r--arch/mips/alchemy/Kconfig24
-rw-r--r--arch/mips/alchemy/Platform16
-rw-r--r--arch/mips/alchemy/board-gpr.c4
-rw-r--r--arch/mips/alchemy/board-mtx1.c4
-rw-r--r--arch/mips/alchemy/common/setup.c10
-rw-r--r--arch/mips/alchemy/common/sleeper.S6
-rw-r--r--arch/mips/alchemy/devboards/Makefile4
-rw-r--r--arch/mips/alchemy/devboards/db1000.c47
-rw-r--r--arch/mips/alchemy/devboards/db1200.c78
-rw-r--r--arch/mips/alchemy/devboards/db1300.c40
-rw-r--r--arch/mips/alchemy/devboards/db1550.c10
-rw-r--r--arch/mips/alchemy/devboards/db1xxx.c (renamed from arch/mips/alchemy/devboards/db1235.c)41
-rw-r--r--arch/mips/ar7/time.c1
-rw-r--r--arch/mips/ath79/Kconfig8
-rw-r--r--arch/mips/bcm47xx/Makefile2
-rw-r--r--arch/mips/bcm47xx/bcm47xx_private.h3
-rw-r--r--arch/mips/bcm47xx/board.c26
-rw-r--r--arch/mips/bcm47xx/buttons.c31
-rw-r--r--arch/mips/bcm47xx/leds.c49
-rw-r--r--arch/mips/bcm47xx/nvram.c2
-rw-r--r--arch/mips/bcm47xx/setup.c3
-rw-r--r--arch/mips/bcm47xx/workarounds.c31
-rw-r--r--arch/mips/bcm63xx/cpu.c3
-rw-r--r--arch/mips/cavium-octeon/octeon-irq.c22
-rw-r--r--arch/mips/configs/db1000_defconfig359
-rw-r--r--arch/mips/configs/db1235_defconfig434
-rw-r--r--arch/mips/configs/db1xxx_defconfig245
-rw-r--r--arch/mips/configs/loongson3_defconfig362
-rw-r--r--arch/mips/configs/malta_defconfig9
-rw-r--r--arch/mips/configs/malta_kvm_defconfig10
-rw-r--r--arch/mips/configs/malta_kvm_guest_defconfig7
-rw-r--r--arch/mips/configs/maltaaprp_defconfig3
-rw-r--r--arch/mips/configs/maltasmtc_defconfig4
-rw-r--r--arch/mips/configs/maltasmvp_defconfig5
-rw-r--r--arch/mips/configs/maltasmvp_eva_defconfig200
-rw-r--r--arch/mips/configs/maltaup_defconfig3
-rw-r--r--arch/mips/include/asm/Kbuild5
-rw-r--r--arch/mips/include/asm/asm-eva.h135
-rw-r--r--arch/mips/include/asm/asm.h13
-rw-r--r--arch/mips/include/asm/asmmacro-32.h128
-rw-r--r--arch/mips/include/asm/asmmacro.h345
-rw-r--r--arch/mips/include/asm/atomic.h40
-rw-r--r--arch/mips/include/asm/bitops.h28
-rw-r--r--arch/mips/include/asm/bootinfo.h26
-rw-r--r--arch/mips/include/asm/checksum.h44
-rw-r--r--arch/mips/include/asm/cmpxchg.h20
-rw-r--r--arch/mips/include/asm/cpu-features.h10
-rw-r--r--arch/mips/include/asm/cpu-info.h28
-rw-r--r--arch/mips/include/asm/cpu-type.h6
-rw-r--r--arch/mips/include/asm/cpu.h15
-rw-r--r--arch/mips/include/asm/dma-mapping.h5
-rw-r--r--arch/mips/include/asm/fpu.h4
-rw-r--r--arch/mips/include/asm/ftrace.h20
-rw-r--r--arch/mips/include/asm/futex.h25
-rw-r--r--arch/mips/include/asm/fw/fw.h2
-rw-r--r--arch/mips/include/asm/gcmpregs.h125
-rw-r--r--arch/mips/include/asm/gic.h3
-rw-r--r--arch/mips/include/asm/io.h8
-rw-r--r--arch/mips/include/asm/kvm_host.h417
-rw-r--r--arch/mips/include/asm/local.h8
-rw-r--r--arch/mips/include/asm/mach-au1x00/au1000.h12
-rw-r--r--arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h8
-rw-r--r--arch/mips/include/asm/mach-db1x00/db1200.h91
-rw-r--r--arch/mips/include/asm/mach-db1x00/db1300.h40
-rw-r--r--arch/mips/include/asm/mach-loongson/boot_param.h163
-rw-r--r--arch/mips/include/asm/mach-loongson/dma-coherence.h22
-rw-r--r--arch/mips/include/asm/mach-loongson/irq.h44
-rw-r--r--arch/mips/include/asm/mach-loongson/loongson.h28
-rw-r--r--arch/mips/include/asm/mach-loongson/machine.h6
-rw-r--r--arch/mips/include/asm/mach-loongson/pci.h5
-rw-r--r--arch/mips/include/asm/mach-loongson/spaces.h9
-rw-r--r--arch/mips/include/asm/mach-malta/kernel-entry-init.h115
-rw-r--r--arch/mips/include/asm/mach-malta/spaces.h46
-rw-r--r--arch/mips/include/asm/mach-pmcs-msp71xx/msp_regops.h12
-rw-r--r--arch/mips/include/asm/mips-boards/malta.h5
-rw-r--r--arch/mips/include/asm/mips-boards/piix4.h5
-rw-r--r--arch/mips/include/asm/mips-cm.h322
-rw-r--r--arch/mips/include/asm/mips-cpc.h150
-rw-r--r--arch/mips/include/asm/mips_mt.h5
-rw-r--r--arch/mips/include/asm/mipsmtregs.h11
-rw-r--r--arch/mips/include/asm/mipsregs.h22
-rw-r--r--arch/mips/include/asm/module.h2
-rw-r--r--arch/mips/include/asm/msa.h203
-rw-r--r--arch/mips/include/asm/page.h2
-rw-r--r--arch/mips/include/asm/pgtable-bits.h9
-rw-r--r--arch/mips/include/asm/processor.h45
-rw-r--r--arch/mips/include/asm/ptrace.h2
-rw-r--r--arch/mips/include/asm/r4kcache.h175
-rw-r--r--arch/mips/include/asm/sigcontext.h2
-rw-r--r--arch/mips/include/asm/smp-cps.h33
-rw-r--r--arch/mips/include/asm/smp-ops.h17
-rw-r--r--arch/mips/include/asm/smp.h1
-rw-r--r--arch/mips/include/asm/stackframe.h2
-rw-r--r--arch/mips/include/asm/switch_to.h22
-rw-r--r--arch/mips/include/asm/syscall.h42
-rw-r--r--arch/mips/include/asm/thread_info.h7
-rw-r--r--arch/mips/include/asm/topology.h4
-rw-r--r--arch/mips/include/asm/uaccess.h559
-rw-r--r--arch/mips/include/asm/unistd.h1
-rw-r--r--arch/mips/include/uapi/asm/inst.h29
-rw-r--r--arch/mips/include/uapi/asm/sigcontext.h8
-rw-r--r--arch/mips/kernel/Makefile5
-rw-r--r--arch/mips/kernel/asm-offsets.c82
-rw-r--r--arch/mips/kernel/bmips_vec.S2
-rw-r--r--arch/mips/kernel/cps-vec.S191
-rw-r--r--arch/mips/kernel/cpu-probe.c74
-rw-r--r--arch/mips/kernel/ftrace.c14
-rw-r--r--arch/mips/kernel/genex.S8
-rw-r--r--arch/mips/kernel/head.S2
-rw-r--r--arch/mips/kernel/idle.c9
-rw-r--r--arch/mips/kernel/irq-gic.c1
-rw-r--r--arch/mips/kernel/kgdb.c18
-rw-r--r--arch/mips/kernel/mips-cm.c121
-rw-r--r--arch/mips/kernel/mips-cpc.c52
-rw-r--r--arch/mips/kernel/mips_ksyms.c24
-rw-r--r--arch/mips/kernel/perf_event_mipsxx.c80
-rw-r--r--arch/mips/kernel/proc.c25
-rw-r--r--arch/mips/kernel/process.c23
-rw-r--r--arch/mips/kernel/ptrace.c161
-rw-r--r--arch/mips/kernel/ptrace32.c67
-rw-r--r--arch/mips/kernel/r4k_fpu.S231
-rw-r--r--arch/mips/kernel/r4k_switch.S60
-rw-r--r--arch/mips/kernel/rtlx-cmp.c3
-rw-r--r--arch/mips/kernel/rtlx-mt.c3
-rw-r--r--arch/mips/kernel/scall32-o32.S24
-rw-r--r--arch/mips/kernel/scall64-64.S5
-rw-r--r--arch/mips/kernel/scall64-n32.S5
-rw-r--r--arch/mips/kernel/scall64-o32.S17
-rw-r--r--arch/mips/kernel/signal.c170
-rw-r--r--arch/mips/kernel/signal32.c137
-rw-r--r--arch/mips/kernel/smp-cmp.c55
-rw-r--r--arch/mips/kernel/smp-cps.c335
-rw-r--r--arch/mips/kernel/smp-gic.c53
-rw-r--r--arch/mips/kernel/smp-mt.c45
-rw-r--r--arch/mips/kernel/smtc-proc.c23
-rw-r--r--arch/mips/kernel/smtc.c2
-rw-r--r--arch/mips/kernel/spram.c5
-rw-r--r--arch/mips/kernel/syscall.c4
-rw-r--r--arch/mips/kernel/traps.c144
-rw-r--r--arch/mips/kernel/unaligned.c135
-rw-r--r--arch/mips/kvm/kvm_mips_emul.c40
-rw-r--r--arch/mips/lasat/picvue_proc.c2
-rw-r--r--arch/mips/lib/csum_partial.S282
-rw-r--r--arch/mips/lib/memcpy.S416
-rw-r--r--arch/mips/lib/memset.S146
-rw-r--r--arch/mips/lib/strlen_user.S36
-rw-r--r--arch/mips/lib/strncpy_user.S40
-rw-r--r--arch/mips/lib/strnlen_user.S36
-rw-r--r--arch/mips/loongson/Kconfig47
-rw-r--r--arch/mips/loongson/Makefile6
-rw-r--r--arch/mips/loongson/Platform1
-rw-r--r--arch/mips/loongson/common/Makefile5
-rw-r--r--arch/mips/loongson/common/dma-swiotlb.c136
-rw-r--r--arch/mips/loongson/common/env.c67
-rw-r--r--arch/mips/loongson/common/init.c11
-rw-r--r--arch/mips/loongson/common/machtype.c4
-rw-r--r--arch/mips/loongson/common/mem.c42
-rw-r--r--arch/mips/loongson/common/pci.c6
-rw-r--r--arch/mips/loongson/common/reset.c21
-rw-r--r--arch/mips/loongson/common/serial.c26
-rw-r--r--arch/mips/loongson/common/setup.c8
-rw-r--r--arch/mips/loongson/common/uart_base.c9
-rw-r--r--arch/mips/loongson/loongson-3/Makefile6
-rw-r--r--arch/mips/loongson/loongson-3/irq.c126
-rw-r--r--arch/mips/loongson/loongson-3/smp.c443
-rw-r--r--arch/mips/loongson/loongson-3/smp.h29
-rw-r--r--arch/mips/math-emu/cp1emu.c64
-rw-r--r--arch/mips/math-emu/kernel_linkage.c76
-rw-r--r--arch/mips/mm/c-r4k.c147
-rw-r--r--arch/mips/mm/cache.c4
-rw-r--r--arch/mips/mm/init.c12
-rw-r--r--arch/mips/mm/sc-mips.c2
-rw-r--r--arch/mips/mm/tlb-r4k.c5
-rw-r--r--arch/mips/mm/tlbex.c6
-rw-r--r--arch/mips/mti-malta/malta-amon.c2
-rw-r--r--arch/mips/mti-malta/malta-init.c30
-rw-r--r--arch/mips/mti-malta/malta-int.c93
-rw-r--r--arch/mips/mti-malta/malta-memory.c58
-rw-r--r--arch/mips/mti-malta/malta-setup.c30
-rw-r--r--arch/mips/mti-sead3/sead3-mtd.c3
-rw-r--r--arch/mips/oprofile/common.c3
-rw-r--r--arch/mips/oprofile/op_model_mipsxx.c9
-rw-r--r--arch/mips/pci/Makefile1
-rw-r--r--arch/mips/pci/fixup-loongson3.c66
-rw-r--r--arch/mips/pci/fixup-malta.c13
-rw-r--r--arch/mips/pci/msi-octeon.c1
-rw-r--r--arch/mips/pci/ops-loongson3.c101
-rw-r--r--arch/mips/pci/pci-alchemy.c5
-rw-r--r--arch/mips/pci/pci-malta.c22
-rw-r--r--arch/mips/pmcs-msp71xx/msp_setup.c2
-rw-r--r--arch/mips/power/hibernate.S1
-rw-r--r--arch/mips/ralink/Kconfig6
-rw-r--r--arch/mips/sgi-ip22/ip22-int.c2
-rw-r--r--arch/mips/sgi-ip22/ip22-time.c2
-rw-r--r--arch/mips/sibyte/bcm1480/irq.c2
-rw-r--r--arch/mips/sibyte/bcm1480/smp.c2
-rw-r--r--arch/mips/sibyte/sb1250/irq.c2
-rw-r--r--arch/mips/sibyte/sb1250/smp.c2
-rw-r--r--arch/mn10300/include/asm/Kbuild4
-rw-r--r--arch/mn10300/include/asm/cputime.h1
-rw-r--r--arch/mn10300/kernel/cevt-mn10300.c2
-rw-r--r--arch/mn10300/kernel/mn10300-serial.c6
-rw-r--r--arch/mn10300/kernel/mn10300-watchdog.c2
-rw-r--r--arch/mn10300/kernel/smp.c2
-rw-r--r--arch/mn10300/unit-asb2364/irq-fpga.c2
-rw-r--r--arch/openrisc/include/asm/Kbuild11
-rw-r--r--arch/parisc/include/asm/Kbuild32
-rw-r--r--arch/parisc/include/asm/page.h11
-rw-r--r--arch/parisc/include/asm/spinlock.h4
-rw-r--r--arch/parisc/include/uapi/asm/unistd.h4
-rw-r--r--arch/parisc/kernel/cache.c64
-rw-r--r--arch/parisc/kernel/irq.c2
-rw-r--r--arch/parisc/kernel/syscall_table.S1
-rw-r--r--arch/powerpc/Kconfig16
-rw-r--r--arch/powerpc/boot/Makefile5
-rw-r--r--arch/powerpc/boot/dts/fsl/b4420si-post.dtsi36
-rw-r--r--arch/powerpc/boot/dts/fsl/b4420si-pre.dtsi2
-rw-r--r--arch/powerpc/boot/dts/fsl/b4860si-post.dtsi36
-rw-r--r--arch/powerpc/boot/dts/fsl/b4860si-pre.dtsi4
-rw-r--r--arch/powerpc/boot/dts/fsl/p2041si-post.dtsi60
-rw-r--r--arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi4
-rw-r--r--arch/powerpc/boot/dts/fsl/p3041si-post.dtsi61
-rw-r--r--arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi4
-rw-r--r--arch/powerpc/boot/dts/fsl/p4080si-post.dtsi113
-rw-r--r--arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi8
-rw-r--r--arch/powerpc/boot/dts/fsl/p5020si-post.dtsi43
-rw-r--r--arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi2
-rw-r--r--arch/powerpc/boot/dts/fsl/p5040si-post.dtsi61
-rw-r--r--arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi4
-rw-r--r--arch/powerpc/boot/dts/fsl/t4240si-post.dtsi86
-rw-r--r--arch/powerpc/boot/dts/fsl/t4240si-pre.dtsi12
-rw-r--r--arch/powerpc/boot/dts/t4240qds.dts42
-rw-r--r--arch/powerpc/configs/40x/acadia_defconfig1
-rw-r--r--arch/powerpc/configs/40x/ep405_defconfig1
-rw-r--r--arch/powerpc/configs/40x/kilauea_defconfig1
-rw-r--r--arch/powerpc/configs/40x/makalu_defconfig1
-rw-r--r--arch/powerpc/configs/40x/walnut_defconfig1
-rw-r--r--arch/powerpc/configs/44x/arches_defconfig1
-rw-r--r--arch/powerpc/configs/44x/bluestone_defconfig1
-rw-r--r--arch/powerpc/configs/44x/canyonlands_defconfig1
-rw-r--r--arch/powerpc/configs/44x/ebony_defconfig1
-rw-r--r--arch/powerpc/configs/44x/eiger_defconfig1
-rw-r--r--arch/powerpc/configs/44x/icon_defconfig1
-rw-r--r--arch/powerpc/configs/44x/iss476-smp_defconfig1
-rw-r--r--arch/powerpc/configs/44x/katmai_defconfig1
-rw-r--r--arch/powerpc/configs/44x/rainier_defconfig1
-rw-r--r--arch/powerpc/configs/44x/redwood_defconfig1
-rw-r--r--arch/powerpc/configs/44x/sequoia_defconfig1
-rw-r--r--arch/powerpc/configs/44x/taishan_defconfig1
-rw-r--r--arch/powerpc/configs/44x/warp_defconfig1
-rw-r--r--arch/powerpc/configs/52xx/cm5200_defconfig1
-rw-r--r--arch/powerpc/configs/52xx/motionpro_defconfig1
-rw-r--r--arch/powerpc/configs/52xx/pcm030_defconfig1
-rw-r--r--arch/powerpc/configs/52xx/tqm5200_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/asp8347_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/mpc8313_rdb_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/mpc8315_rdb_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/mpc836x_mds_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/mpc836x_rdk_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/sbc834x_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/ksi8560_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/ppa8548_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/socrates_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/tqm8540_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/tqm8541_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/tqm8548_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/tqm8555_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/tqm8560_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/xes_mpc85xx_defconfig1
-rw-r--r--arch/powerpc/configs/86xx/gef_ppc9a_defconfig1
-rw-r--r--arch/powerpc/configs/86xx/gef_sbc310_defconfig1
-rw-r--r--arch/powerpc/configs/86xx/gef_sbc610_defconfig1
-rw-r--r--arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig1
-rw-r--r--arch/powerpc/configs/86xx/sbc8641d_defconfig1
-rw-r--r--arch/powerpc/configs/c2k_defconfig1
-rw-r--r--arch/powerpc/configs/corenet64_smp_defconfig2
-rw-r--r--arch/powerpc/configs/linkstation_defconfig1
-rw-r--r--arch/powerpc/configs/mpc85xx_defconfig2
-rw-r--r--arch/powerpc/configs/mpc85xx_smp_defconfig2
-rw-r--r--arch/powerpc/configs/ppc40x_defconfig1
-rw-r--r--arch/powerpc/configs/ppc44x_defconfig1
-rw-r--r--arch/powerpc/configs/ppc64_defconfig70
-rw-r--r--arch/powerpc/configs/ppc64e_defconfig70
-rw-r--r--arch/powerpc/configs/prpmc2800_defconfig108
-rw-r--r--arch/powerpc/configs/pseries_defconfig55
-rw-r--r--arch/powerpc/configs/pseries_le_defconfig53
-rw-r--r--arch/powerpc/configs/storcenter_defconfig1
-rw-r--r--arch/powerpc/configs/tqm8xx_defconfig1
-rw-r--r--arch/powerpc/include/asm/Kbuild5
-rw-r--r--arch/powerpc/include/asm/compat.h9
-rw-r--r--arch/powerpc/include/asm/cputable.h6
-rw-r--r--arch/powerpc/include/asm/dma-mapping.h1
-rw-r--r--arch/powerpc/include/asm/eeh.h21
-rw-r--r--arch/powerpc/include/asm/exception-64e.h15
-rw-r--r--arch/powerpc/include/asm/exception-64s.h8
-rw-r--r--arch/powerpc/include/asm/hugetlb.h2
-rw-r--r--arch/powerpc/include/asm/hvcall.h5
-rw-r--r--arch/powerpc/include/asm/iommu.h1
-rw-r--r--arch/powerpc/include/asm/kvm_book3s.h5
-rw-r--r--arch/powerpc/include/asm/kvm_book3s_64.h12
-rw-r--r--arch/powerpc/include/asm/kvm_book3s_asm.h2
-rw-r--r--arch/powerpc/include/asm/kvm_booke_hv_asm.h17
-rw-r--r--arch/powerpc/include/asm/kvm_ppc.h2
-rw-r--r--arch/powerpc/include/asm/machdep.h7
-rw-r--r--arch/powerpc/include/asm/mce.h3
-rw-r--r--arch/powerpc/include/asm/mmu-book3e.h9
-rw-r--r--arch/powerpc/include/asm/opal.h66
-rw-r--r--arch/powerpc/include/asm/paca.h9
-rw-r--r--arch/powerpc/include/asm/perf_event_server.h1
-rw-r--r--arch/powerpc/include/asm/pgtable-ppc64.h26
-rw-r--r--arch/powerpc/include/asm/pgtable.h22
-rw-r--r--arch/powerpc/include/asm/processor.h1
-rw-r--r--arch/powerpc/include/asm/ptrace.h16
-rw-r--r--arch/powerpc/include/asm/reg.h19
-rw-r--r--arch/powerpc/include/asm/rtas.h1
-rw-r--r--arch/powerpc/include/asm/sections.h12
-rw-r--r--arch/powerpc/include/asm/smp.h2
-rw-r--r--arch/powerpc/include/asm/time.h1
-rw-r--r--arch/powerpc/include/asm/tm.h4
-rw-r--r--arch/powerpc/include/asm/topology.h1
-rw-r--r--arch/powerpc/include/asm/vdso.h6
-rw-r--r--arch/powerpc/kernel/asm-offsets.c2
-rw-r--r--arch/powerpc/kernel/cacheinfo.c7
-rw-r--r--arch/powerpc/kernel/cputable.c2
-rw-r--r--arch/powerpc/kernel/crash_dump.c8
-rw-r--r--arch/powerpc/kernel/dma.c10
-rw-r--r--arch/powerpc/kernel/eeh.c32
-rw-r--r--arch/powerpc/kernel/eeh_driver.c33
-rw-r--r--arch/powerpc/kernel/exceptions-64e.S435
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S15
-rw-r--r--arch/powerpc/kernel/ftrace.c8
-rw-r--r--arch/powerpc/kernel/idle_power7.S90
-rw-r--r--arch/powerpc/kernel/iommu.c12
-rw-r--r--arch/powerpc/kernel/irq.c13
-rw-r--r--arch/powerpc/kernel/machine_kexec.c14
-rw-r--r--arch/powerpc/kernel/machine_kexec_64.c6
-rw-r--r--arch/powerpc/kernel/mce.c4
-rw-r--r--arch/powerpc/kernel/mce_power.c37
-rw-r--r--arch/powerpc/kernel/misc_32.S5
-rw-r--r--arch/powerpc/kernel/pci_64.c4
-rw-r--r--arch/powerpc/kernel/process.c9
-rw-r--r--arch/powerpc/kernel/prom.c8
-rw-r--r--arch/powerpc/kernel/reloc_64.S5
-rw-r--r--arch/powerpc/kernel/rtas.c22
-rw-r--r--arch/powerpc/kernel/setup_32.c5
-rw-r--r--arch/powerpc/kernel/setup_64.c20
-rw-r--r--arch/powerpc/kernel/signal_64.c4
-rw-r--r--arch/powerpc/kernel/smp.c25
-rw-r--r--arch/powerpc/kernel/time.c90
-rw-r--r--arch/powerpc/kernel/traps.c5
-rw-r--r--arch/powerpc/kernel/vdso.c8
-rw-r--r--arch/powerpc/kernel/vdso32/getcpu.S2
-rw-r--r--arch/powerpc/kernel/vdso32/vdso32_wrapper.S2
-rw-r--r--arch/powerpc/kernel/vdso64/getcpu.S2
-rw-r--r--arch/powerpc/kernel/vdso64/vdso64_wrapper.S2
-rw-r--r--arch/powerpc/kernel/vio.c3
-rw-r--r--arch/powerpc/kvm/book3s_64_mmu_hv.c9
-rw-r--r--arch/powerpc/kvm/book3s_64_vio_hv.c28
-rw-r--r--arch/powerpc/kvm/book3s_hv.c159
-rw-r--r--arch/powerpc/kvm/book3s_hv_interrupts.S22
-rw-r--r--arch/powerpc/kvm/book3s_hv_rm_mmu.c6
-rw-r--r--arch/powerpc/kvm/book3s_hv_rmhandlers.S262
-rw-r--r--arch/powerpc/kvm/book3s_interrupts.S4
-rw-r--r--arch/powerpc/kvm/book3s_rtas.c7
-rw-r--r--arch/powerpc/kvm/bookehv_interrupts.S21
-rw-r--r--arch/powerpc/lib/memcpy_64.S2
-rw-r--r--arch/powerpc/mm/hash_utils_64.c14
-rw-r--r--arch/powerpc/mm/mem.c7
-rw-r--r--arch/powerpc/mm/pgtable_64.c17
-rw-r--r--arch/powerpc/mm/subpage-prot.c2
-rw-r--r--arch/powerpc/mm/tlb_low_64e.S66
-rw-r--r--arch/powerpc/mm/tlb_nohash.c11
-rw-r--r--arch/powerpc/net/bpf_jit_comp.c7
-rw-r--r--arch/powerpc/oprofile/op_model_cell.c3
-rw-r--r--arch/powerpc/perf/Makefile2
-rw-r--r--arch/powerpc/perf/core-book3s.c177
-rw-r--r--arch/powerpc/perf/hv-24x7-catalog.h33
-rw-r--r--arch/powerpc/perf/hv-24x7.c510
-rw-r--r--arch/powerpc/perf/hv-24x7.h109
-rw-r--r--arch/powerpc/perf/hv-common.c39
-rw-r--r--arch/powerpc/perf/hv-common.h36
-rw-r--r--arch/powerpc/perf/hv-gpci.c294
-rw-r--r--arch/powerpc/perf/hv-gpci.h73
-rw-r--r--arch/powerpc/perf/power7-events-list.h10
-rw-r--r--arch/powerpc/perf/power8-pmu.c222
-rw-r--r--arch/powerpc/platforms/44x/Kconfig1
-rw-r--r--arch/powerpc/platforms/85xx/c293pcie.c1
-rw-r--r--arch/powerpc/platforms/85xx/common.c6
-rw-r--r--arch/powerpc/platforms/85xx/corenet_generic.c17
-rw-r--r--arch/powerpc/platforms/85xx/ge_imp3a.c1
-rw-r--r--arch/powerpc/platforms/85xx/mpc8536_ds.c1
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx.h2
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_cds.c1
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_ds.c3
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_mds.c4
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_rdb.c16
-rw-r--r--arch/powerpc/platforms/85xx/p1010rdb.c1
-rw-r--r--arch/powerpc/platforms/85xx/p1022_ds.c1
-rw-r--r--arch/powerpc/platforms/85xx/p1022_rdk.c1
-rw-r--r--arch/powerpc/platforms/85xx/p1023_rds.c2
-rw-r--r--arch/powerpc/platforms/85xx/qemu_e500.c1
-rw-r--r--arch/powerpc/platforms/85xx/sbc8548.c1
-rw-r--r--arch/powerpc/platforms/85xx/twr_p102x.c1
-rw-r--r--arch/powerpc/platforms/85xx/xes_mpc85xx.c3
-rw-r--r--arch/powerpc/platforms/cell/interrupt.c2
-rw-r--r--arch/powerpc/platforms/cell/ras.c3
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c1
-rw-r--r--arch/powerpc/platforms/embedded6xx/Kconfig10
-rw-r--r--arch/powerpc/platforms/embedded6xx/Makefile1
-rw-r--r--arch/powerpc/platforms/embedded6xx/prpmc2800.c156
-rw-r--r--arch/powerpc/platforms/powernv/Makefile4
-rw-r--r--arch/powerpc/platforms/powernv/eeh-ioda.c128
-rw-r--r--arch/powerpc/platforms/powernv/eeh-powernv.c2
-rw-r--r--arch/powerpc/platforms/powernv/opal-async.c203
-rw-r--r--arch/powerpc/platforms/powernv/opal-dump.c525
-rw-r--r--arch/powerpc/platforms/powernv/opal-elog.c313
-rw-r--r--arch/powerpc/platforms/powernv/opal-sensor.c64
-rw-r--r--arch/powerpc/platforms/powernv/opal-sysparam.c290
-rw-r--r--arch/powerpc/platforms/powernv/opal-wrappers.S15
-rw-r--r--arch/powerpc/platforms/powernv/opal-xscom.c21
-rw-r--r--arch/powerpc/platforms/powernv/opal.c106
-rw-r--r--arch/powerpc/platforms/powernv/pci-ioda.c84
-rw-r--r--arch/powerpc/platforms/powernv/pci.c230
-rw-r--r--arch/powerpc/platforms/powernv/pci.h6
-rw-r--r--arch/powerpc/platforms/powernv/powernv.h8
-rw-r--r--arch/powerpc/platforms/powernv/setup.c23
-rw-r--r--arch/powerpc/platforms/ps3/Kconfig2
-rw-r--r--arch/powerpc/platforms/ps3/smp.c2
-rw-r--r--arch/powerpc/platforms/pseries/Kconfig13
-rw-r--r--arch/powerpc/platforms/pseries/dlpar.c2
-rw-r--r--arch/powerpc/platforms/pseries/eeh_pseries.c2
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-cpu.c24
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-memory.c83
-rw-r--r--arch/powerpc/platforms/pseries/mobility.c26
-rw-r--r--arch/powerpc/platforms/pseries/pci.c22
-rw-r--r--arch/powerpc/platforms/pseries/pci_dlpar.c6
-rw-r--r--arch/powerpc/platforms/pseries/reconfig.c2
-rw-r--r--arch/powerpc/platforms/pseries/setup.c37
-rw-r--r--arch/powerpc/platforms/pseries/suspend.c44
-rw-r--r--arch/powerpc/sysdev/Makefile1
-rw-r--r--arch/powerpc/sysdev/ehv_pic.c10
-rw-r--r--arch/powerpc/sysdev/fsl_pci.c178
-rw-r--r--arch/powerpc/sysdev/fsl_pci.h8
-rw-r--r--arch/powerpc/sysdev/mpic.c38
-rw-r--r--arch/powerpc/sysdev/msi_bitmap.c2
-rw-r--r--arch/powerpc/xmon/xmon.c28
-rw-r--r--arch/s390/Kconfig6
-rw-r--r--arch/s390/appldata/appldata_base.c1
-rw-r--r--arch/s390/appldata/appldata_os.c2
-rw-r--r--arch/s390/configs/default_defconfig46
-rw-r--r--arch/s390/configs/gcov_defconfig33
-rw-r--r--arch/s390/configs/performance_defconfig33
-rw-r--r--arch/s390/configs/zfcpdump_defconfig1
-rw-r--r--arch/s390/defconfig10
-rw-r--r--arch/s390/hypfs/hypfs_vm.c9
-rw-r--r--arch/s390/include/asm/Kbuild5
-rw-r--r--arch/s390/include/asm/airq.h14
-rw-r--r--arch/s390/include/asm/bitops.h8
-rw-r--r--arch/s390/include/asm/ccwdev.h4
-rw-r--r--arch/s390/include/asm/ccwgroup.h1
-rw-r--r--arch/s390/include/asm/checksum.h11
-rw-r--r--arch/s390/include/asm/cio.h2
-rw-r--r--arch/s390/include/asm/compat.h6
-rw-r--r--arch/s390/include/asm/futex.h13
-rw-r--r--arch/s390/include/asm/irq.h1
-rw-r--r--arch/s390/include/asm/kvm_host.h101
-rw-r--r--arch/s390/include/asm/mmu_context.h39
-rw-r--r--arch/s390/include/asm/pgalloc.h18
-rw-r--r--arch/s390/include/asm/pgtable.h107
-rw-r--r--arch/s390/include/asm/processor.h1
-rw-r--r--arch/s390/include/asm/ptrace.h1
-rw-r--r--arch/s390/include/asm/sclp.h1
-rw-r--r--arch/s390/include/asm/setup.h3
-rw-r--r--arch/s390/include/asm/thread_info.h3
-rw-r--r--arch/s390/include/asm/uaccess.h171
-rw-r--r--arch/s390/include/uapi/asm/kvm.h43
-rw-r--r--arch/s390/include/uapi/asm/ptrace.h6
-rw-r--r--arch/s390/kernel/Makefile5
-rw-r--r--arch/s390/kernel/compat_exec_domain.c29
-rw-r--r--arch/s390/kernel/compat_linux.c116
-rw-r--r--arch/s390/kernel/compat_linux.h81
-rw-r--r--arch/s390/kernel/compat_signal.c4
-rw-r--r--arch/s390/kernel/compat_wrapper.S1425
-rw-r--r--arch/s390/kernel/compat_wrapper.c215
-rw-r--r--arch/s390/kernel/early.c2
-rw-r--r--arch/s390/kernel/entry.S9
-rw-r--r--arch/s390/kernel/entry.h6
-rw-r--r--arch/s390/kernel/entry64.S9
-rw-r--r--arch/s390/kernel/ftrace.c3
-rw-r--r--arch/s390/kernel/head64.S7
-rw-r--r--arch/s390/kernel/irq.c2
-rw-r--r--arch/s390/kernel/perf_event.c2
-rw-r--r--arch/s390/kernel/ptrace.c13
-rw-r--r--arch/s390/kernel/setup.c17
-rw-r--r--arch/s390/kernel/smp.c8
-rw-r--r--arch/s390/kernel/syscalls.S504
-rw-r--r--arch/s390/kernel/topology.c1
-rw-r--r--arch/s390/kvm/Kconfig4
-rw-r--r--arch/s390/kvm/Makefile2
-rw-r--r--arch/s390/kvm/diag.c87
-rw-r--r--arch/s390/kvm/interrupt.c704
-rw-r--r--arch/s390/kvm/irq.h22
-rw-r--r--arch/s390/kvm/kvm-s390.c237
-rw-r--r--arch/s390/kvm/kvm-s390.h9
-rw-r--r--arch/s390/kvm/priv.c48
-rw-r--r--arch/s390/kvm/sigp.c157
-rw-r--r--arch/s390/kvm/trace.h46
-rw-r--r--arch/s390/lib/Makefile3
-rw-r--r--arch/s390/lib/find.c2
-rw-r--r--arch/s390/lib/uaccess.h8
-rw-r--r--arch/s390/lib/uaccess_mvcos.c116
-rw-r--r--arch/s390/lib/uaccess_pt.c69
-rw-r--r--arch/s390/mm/fault.c26
-rw-r--r--arch/s390/mm/maccess.c28
-rw-r--r--arch/s390/mm/page-states.c10
-rw-r--r--arch/s390/mm/pgtable.c158
-rw-r--r--arch/s390/net/bpf_jit_comp.c13
-rw-r--r--arch/s390/pci/pci.c16
-rw-r--r--arch/s390/pci/pci_debug.c2
-rw-r--r--arch/s390/pci/pci_dma.c8
-rw-r--r--arch/s390/pci/pci_sysfs.c18
-rw-r--r--arch/score/Kconfig6
-rw-r--r--arch/score/include/asm/Kbuild6
-rw-r--r--arch/score/include/asm/cputime.h6
-rw-r--r--arch/sh/Kconfig85
-rw-r--r--arch/sh/boards/board-sh7757lcr.c2
-rw-r--r--arch/sh/boards/mach-ecovec24/setup.c4
-rw-r--r--arch/sh/boards/mach-se/7724/setup.c4
-rw-r--r--arch/sh/drivers/pci/pci.c5
-rw-r--r--arch/sh/drivers/pci/pcie-sh7786.h3
-rw-r--r--arch/sh/include/asm/Kbuild9
-rw-r--r--arch/sh/include/asm/syscalls_32.h12
-rw-r--r--arch/sh/include/asm/traps_32.h16
-rw-r--r--arch/sh/include/cpu-sh2/cpu/cache.h2
-rw-r--r--arch/sh/include/cpu-sh2a/cpu/cache.h4
-rw-r--r--arch/sh/include/cpu-sh3/cpu/cache.h2
-rw-r--r--arch/sh/include/cpu-sh4/cpu/cache.h2
-rw-r--r--arch/sh/kernel/cpu/init.c4
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7757.c2
-rw-r--r--arch/sh/kernel/dumpstack.c2
-rw-r--r--arch/sh/kernel/entry-common.S15
-rw-r--r--arch/sh/kernel/ftrace.c5
-rw-r--r--arch/sh/kernel/idle.c4
-rw-r--r--arch/sh/kernel/irq.c18
-rw-r--r--arch/sh/kernel/signal_32.c12
-rw-r--r--arch/sh/kernel/sys_sh32.c7
-rw-r--r--arch/sh/kernel/traps_32.c23
-rw-r--r--arch/sh/math-emu/math.c18
-rw-r--r--arch/sh/mm/cache-debugfs.c2
-rw-r--r--arch/sh/mm/cache-sh2.c4
-rw-r--r--arch/sh/mm/cache-sh2a.c6
-rw-r--r--arch/sh/mm/cache-sh4.c4
-rw-r--r--arch/sh/mm/cache-shx3.c4
-rw-r--r--arch/sh/mm/cache.c4
-rw-r--r--arch/sparc/Kconfig2
-rw-r--r--arch/sparc/include/asm/Kbuild11
-rw-r--r--arch/sparc/include/asm/smp_64.h1
-rw-r--r--arch/sparc/include/asm/topology_64.h2
-rw-r--r--arch/sparc/kernel/ftrace.c6
-rw-r--r--arch/sparc/kernel/leon_pci.c5
-rw-r--r--arch/sparc/kernel/leon_pci_grpci2.c1
-rw-r--r--arch/sparc/kernel/mdesc.c4
-rw-r--r--arch/sparc/kernel/process_64.c4
-rw-r--r--arch/sparc/kernel/prom_64.c3
-rw-r--r--arch/sparc/kernel/smp_64.c2
-rw-r--r--arch/sparc/kernel/sun4m_irq.c2
-rw-r--r--arch/sparc/kernel/syscalls.S4
-rw-r--r--arch/sparc/kernel/time_64.c5
-rw-r--r--arch/sparc/mm/srmmu.c2
-rw-r--r--arch/sparc/mm/tsb.c2
-rw-r--r--arch/sparc/net/bpf_jit_comp.c5
-rw-r--r--arch/tile/include/asm/Kbuild5
-rw-r--r--arch/tile/kernel/ftrace.c4
-rw-r--r--arch/tile/kernel/pci_gx.c12
-rw-r--r--arch/um/drivers/net_kern.c2
-rw-r--r--arch/um/include/asm/Kbuild34
-rw-r--r--arch/unicore32/include/asm/Kbuild5
-rw-r--r--arch/x86/Kconfig130
-rw-r--r--arch/x86/Kconfig.cpu6
-rw-r--r--arch/x86/Kconfig.debug9
-rw-r--r--arch/x86/Makefile5
-rw-r--r--arch/x86/boot/Makefile2
-rw-r--r--arch/x86/boot/boot.h13
-rw-r--r--arch/x86/boot/compressed/aslr.c9
-rw-r--r--arch/x86/boot/compressed/eboot.c1017
-rw-r--r--arch/x86/boot/compressed/eboot.h60
-rw-r--r--arch/x86/boot/compressed/efi_stub_64.S29
-rw-r--r--arch/x86/boot/compressed/head_32.S52
-rw-r--r--arch/x86/boot/compressed/head_64.S111
-rw-r--r--arch/x86/boot/compressed/misc.c51
-rw-r--r--arch/x86/boot/compressed/string.c46
-rw-r--r--arch/x86/boot/cpucheck.c21
-rw-r--r--arch/x86/boot/edd.c1
-rw-r--r--arch/x86/boot/header.S25
-rw-r--r--arch/x86/boot/main.c1
-rw-r--r--arch/x86/boot/regs.c1
-rw-r--r--arch/x86/boot/string.c14
-rw-r--r--arch/x86/boot/string.h21
-rw-r--r--arch/x86/boot/tools/build.c77
-rw-r--r--arch/x86/boot/video-vesa.c1
-rw-r--r--arch/x86/configs/i386_defconfig1
-rw-r--r--arch/x86/configs/x86_64_defconfig1
-rw-r--r--arch/x86/crypto/Makefile3
-rw-r--r--arch/x86/crypto/blowfish_glue.c3
-rw-r--r--arch/x86/crypto/cast5_avx_glue.c3
-rw-r--r--arch/x86/crypto/ghash-clmulni-intel_asm.S29
-rw-r--r--arch/x86/crypto/ghash-clmulni-intel_glue.c14
-rw-r--r--arch/x86/crypto/sha1_avx2_x86_64_asm.S708
-rw-r--r--arch/x86/crypto/sha1_ssse3_glue.c53
-rw-r--r--arch/x86/include/asm/Kbuild2
-rw-r--r--arch/x86/include/asm/apic.h14
-rw-r--r--arch/x86/include/asm/barrier.h8
-rw-r--r--arch/x86/include/asm/clocksource.h4
-rw-r--r--arch/x86/include/asm/cpufeature.h16
-rw-r--r--arch/x86/include/asm/cputime.h1
-rw-r--r--arch/x86/include/asm/efi.h46
-rw-r--r--arch/x86/include/asm/elf.h4
-rw-r--r--arch/x86/include/asm/fixmap.h14
-rw-r--r--arch/x86/include/asm/floppy.h4
-rw-r--r--arch/x86/include/asm/hardirq.h3
-rw-r--r--arch/x86/include/asm/hw_irq.h1
-rw-r--r--arch/x86/include/asm/io.h2
-rw-r--r--arch/x86/include/asm/kvm_host.h18
-rw-r--r--arch/x86/include/asm/mmzone_32.h3
-rw-r--r--arch/x86/include/asm/mpspec.h6
-rw-r--r--arch/x86/include/asm/mshyperv.h4
-rw-r--r--arch/x86/include/asm/msr.h2
-rw-r--r--arch/x86/include/asm/nmi.h3
-rw-r--r--arch/x86/include/asm/numaq.h171
-rw-r--r--arch/x86/include/asm/pci.h7
-rw-r--r--arch/x86/include/asm/pgtable.h3
-rw-r--r--arch/x86/include/asm/pgtable_types.h11
-rw-r--r--arch/x86/include/asm/processor.h9
-rw-r--r--arch/x86/include/asm/setup.h6
-rw-r--r--arch/x86/include/asm/special_insns.h8
-rw-r--r--arch/x86/include/asm/spinlock.h5
-rw-r--r--arch/x86/include/asm/thread_info.h53
-rw-r--r--arch/x86/include/asm/topology.h23
-rw-r--r--arch/x86/include/asm/tsc.h2
-rw-r--r--arch/x86/include/asm/unistd.h3
-rw-r--r--arch/x86/include/asm/vdso.h52
-rw-r--r--arch/x86/include/asm/vdso32.h11
-rw-r--r--arch/x86/include/asm/vgtod.h71
-rw-r--r--arch/x86/include/asm/visws/cobalt.h127
-rw-r--r--arch/x86/include/asm/visws/lithium.h53
-rw-r--r--arch/x86/include/asm/visws/piix4.h107
-rw-r--r--arch/x86/include/asm/visws/sgivw.h5
-rw-r--r--arch/x86/include/asm/vmx.h4
-rw-r--r--arch/x86/include/asm/vvar.h29
-rw-r--r--arch/x86/include/asm/xen/page.h11
-rw-r--r--arch/x86/include/asm/xsave.h18
-rw-r--r--arch/x86/include/uapi/asm/msr-index.h76
-rw-r--r--arch/x86/kernel/Makefile2
-rw-r--r--arch/x86/kernel/acpi/boot.c24
-rw-r--r--arch/x86/kernel/amd_nb.c2
-rw-r--r--arch/x86/kernel/aperture_64.c20
-rw-r--r--arch/x86/kernel/apic/Makefile3
-rw-r--r--arch/x86/kernel/apic/apic.c14
-rw-r--r--arch/x86/kernel/apic/apic_flat_64.c4
-rw-r--r--arch/x86/kernel/apic/apic_noop.c3
-rw-r--r--arch/x86/kernel/apic/apic_numachip.c2
-rw-r--r--arch/x86/kernel/apic/bigsmp_32.c3
-rw-r--r--arch/x86/kernel/apic/es7000_32.c746
-rw-r--r--arch/x86/kernel/apic/numaq_32.c525
-rw-r--r--arch/x86/kernel/apic/probe_32.c3
-rw-r--r--arch/x86/kernel/apic/summit_32.c551
-rw-r--r--arch/x86/kernel/apic/x2apic_cluster.c2
-rw-r--r--arch/x86/kernel/apic/x2apic_phys.c2
-rw-r--r--arch/x86/kernel/apic/x2apic_uv_x.c2
-rw-r--r--arch/x86/kernel/cpu/amd.c50
-rw-r--r--arch/x86/kernel/cpu/centaur.c272
-rw-r--r--arch/x86/kernel/cpu/common.c18
-rw-r--r--arch/x86/kernel/cpu/intel.c57
-rw-r--r--arch/x86/kernel/cpu/match.c42
-rw-r--r--arch/x86/kernel/cpu/mshyperv.c84
-rw-r--r--arch/x86/kernel/cpu/perf_event.c54
-rw-r--r--arch/x86/kernel/cpu/perf_event.h9
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel.c11
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_uncore.c557
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_uncore.h5
-rw-r--r--arch/x86/kernel/cpu/perf_event_p4.c34
-rw-r--r--arch/x86/kernel/cpu/perf_event_p6.c48
-rw-r--r--arch/x86/kernel/crash.c2
-rw-r--r--arch/x86/kernel/dumpstack_32.c46
-rw-r--r--arch/x86/kernel/dumpstack_64.c118
-rw-r--r--arch/x86/kernel/early-quirks.c15
-rw-r--r--arch/x86/kernel/ftrace.c138
-rw-r--r--arch/x86/kernel/head_32.S7
-rw-r--r--arch/x86/kernel/head_64.S6
-rw-r--r--arch/x86/kernel/hpet.c6
-rw-r--r--arch/x86/kernel/i387.c15
-rw-r--r--arch/x86/kernel/irq.c6
-rw-r--r--arch/x86/kernel/irq_32.c83
-rw-r--r--arch/x86/kernel/kvm.c1
-rw-r--r--arch/x86/kernel/kvmclock.c2
-rw-r--r--arch/x86/kernel/machine_kexec_64.c2
-rw-r--r--arch/x86/kernel/module.c46
-rw-r--r--arch/x86/kernel/nmi.c37
-rw-r--r--arch/x86/kernel/pci-dma.c4
-rw-r--r--arch/x86/kernel/process.c5
-rw-r--r--arch/x86/kernel/process_32.c4
-rw-r--r--arch/x86/kernel/ptrace.c8
-rw-r--r--arch/x86/kernel/quirks.c2
-rw-r--r--arch/x86/kernel/reboot.c15
-rw-r--r--arch/x86/kernel/setup.c17
-rw-r--r--arch/x86/kernel/smpboot.c20
-rw-r--r--arch/x86/kernel/time.c4
-rw-r--r--arch/x86/kernel/tsc.c16
-rw-r--r--arch/x86/kernel/tsc_msr.c30
-rw-r--r--arch/x86/kernel/vmlinux.lds.S8
-rw-r--r--arch/x86/kernel/vsyscall_64.c45
-rw-r--r--arch/x86/kernel/vsyscall_gtod.c69
-rw-r--r--arch/x86/kvm/cpuid.c39
-rw-r--r--arch/x86/kvm/emulate.c8
-rw-r--r--arch/x86/kvm/mmu.c3
-rw-r--r--arch/x86/kvm/paging_tmpl.h7
-rw-r--r--arch/x86/kvm/svm.c90
-rw-r--r--arch/x86/kvm/vmx.c336
-rw-r--r--arch/x86/kvm/x86.c147
-rw-r--r--arch/x86/kvm/x86.h5
-rw-r--r--arch/x86/lib/hash.c22
-rw-r--r--arch/x86/lib/memcpy_32.c6
-rw-r--r--arch/x86/lib/msr.c89
-rw-r--r--arch/x86/mm/dump_pagetables.c84
-rw-r--r--arch/x86/mm/fault.c68
-rw-r--r--arch/x86/mm/numa.c4
-rw-r--r--arch/x86/mm/pageattr.c70
-rw-r--r--arch/x86/mm/srat.c12
-rw-r--r--arch/x86/net/bpf_jit.S2
-rw-r--r--arch/x86/net/bpf_jit_comp.c11
-rw-r--r--arch/x86/pci/Makefile3
-rw-r--r--arch/x86/pci/acpi.c59
-rw-r--r--arch/x86/pci/amd_bus.c10
-rw-r--r--arch/x86/pci/bus_numa.c13
-rw-r--r--arch/x86/pci/common.c133
-rw-r--r--arch/x86/pci/fixup.c24
-rw-r--r--arch/x86/pci/irq.c6
-rw-r--r--arch/x86/pci/legacy.c4
-rw-r--r--arch/x86/pci/numaq_32.c165
-rw-r--r--arch/x86/pci/visws.c87
-rw-r--r--arch/x86/pci/xen.c29
-rw-r--r--arch/x86/platform/Makefile1
-rw-r--r--arch/x86/platform/efi/Makefile1
-rw-r--r--arch/x86/platform/efi/efi-bgrt.c2
-rw-r--r--arch/x86/platform/efi/efi.c436
-rw-r--r--arch/x86/platform/efi/efi_32.c13
-rw-r--r--arch/x86/platform/efi/efi_64.c377
-rw-r--r--arch/x86/platform/efi/efi_stub_64.S166
-rw-r--r--arch/x86/platform/efi/efi_thunk_64.S65
-rw-r--r--arch/x86/platform/ts5500/ts5500.c2
-rw-r--r--arch/x86/platform/visws/Makefile1
-rw-r--r--arch/x86/platform/visws/visws_quirks.c608
-rw-r--r--arch/x86/syscalls/syscall_64.tbl1
-rw-r--r--arch/x86/tools/relocs.c2
-rw-r--r--arch/x86/um/asm/barrier.h4
-rw-r--r--arch/x86/vdso/Makefile26
-rw-r--r--arch/x86/vdso/vclock_gettime.c256
-rw-r--r--arch/x86/vdso/vdso-layout.lds.S29
-rw-r--r--arch/x86/vdso/vdso.S22
-rw-r--r--arch/x86/vdso/vdso32-setup.c301
-rw-r--r--arch/x86/vdso/vdso32.S21
-rw-r--r--arch/x86/vdso/vdso32/vclock_gettime.c30
-rw-r--r--arch/x86/vdso/vdso32/vdso32.lds.S15
-rw-r--r--arch/x86/vdso/vdsox32.S22
-rw-r--r--arch/x86/vdso/vma.c20
-rw-r--r--arch/x86/xen/Kconfig7
-rw-r--r--arch/x86/xen/mmu.c1
-rw-r--r--arch/x86/xen/p2m.c121
-rw-r--r--arch/x86/xen/spinlock.c2
-rw-r--r--arch/xtensa/Kconfig3
-rw-r--r--arch/xtensa/boot/dts/xtfpga.dtsi12
-rw-r--r--arch/xtensa/include/asm/Kbuild5
-rw-r--r--arch/xtensa/include/asm/io.h2
-rw-r--r--arch/xtensa/include/asm/traps.h44
-rw-r--r--arch/xtensa/include/asm/vectors.h2
-rw-r--r--arch/xtensa/include/uapi/asm/unistd.h7
-rw-r--r--arch/xtensa/kernel/entry.S449
-rw-r--r--arch/xtensa/kernel/irq.c22
-rw-r--r--arch/xtensa/kernel/setup.c2
-rw-r--r--arch/xtensa/kernel/time.c1
-rw-r--r--arch/xtensa/kernel/vectors.S2
-rw-r--r--arch/xtensa/kernel/xtensa_ksyms.c2
-rw-r--r--arch/xtensa/mm/init.c13
-rw-r--r--arch/xtensa/mm/mmu.c2
-rw-r--r--arch/xtensa/platforms/xtfpga/setup.c7
-rw-r--r--arch/xtensa/variants/fsf/include/variant/tie.h9
-rw-r--r--block/blk-cgroup.c13
-rw-r--r--block/blk-cgroup.h22
-rw-r--r--block/blk-core.c23
-rw-r--r--block/blk-exec.c2
-rw-r--r--block/blk-flush.c108
-rw-r--r--block/blk-ioc.c2
-rw-r--r--block/blk-iopoll.c3
-rw-r--r--block/blk-lib.c8
-rw-r--r--block/blk-map.c2
-rw-r--r--block/blk-merge.c91
-rw-r--r--block/blk-mq-cpu.c14
-rw-r--r--block/blk-mq-cpumap.c10
-rw-r--r--block/blk-mq-sysfs.c31
-rw-r--r--block/blk-mq-tag.c2
-rw-r--r--block/blk-mq.c307
-rw-r--r--block/blk-mq.h7
-rw-r--r--block/blk-softirq.c19
-rw-r--r--block/blk-sysfs.c2
-rw-r--r--block/blk-throttle.c8
-rw-r--r--block/blk-timeout.c2
-rw-r--r--block/blk.h2
-rw-r--r--block/cfq-iosched.c15
-rw-r--r--block/deadline-iosched.c8
-rw-r--r--block/partitions/atari.h4
-rw-r--r--block/partitions/efi.h9
-rw-r--r--block/partitions/karma.c3
-rw-r--r--crypto/Kconfig4
-rw-r--r--crypto/Makefile2
-rw-r--r--crypto/ahash.c147
-rw-r--r--crypto/blkcipher.c81
-rw-r--r--crypto/crc32c_generic.c (renamed from crypto/crc32c.c)2
-rw-r--r--crypto/crypto_null.c6
-rw-r--r--crypto/crypto_wq.c2
-rw-r--r--crypto/tcrypt.c8
-rw-r--r--crypto/testmgr.c32
-rw-r--r--crypto/testmgr.h180
-rw-r--r--drivers/Kconfig4
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/acpi/Kconfig28
-rw-r--r--drivers/acpi/ac.c27
-rw-r--r--drivers/acpi/acpi_cmos_rtc.c2
-rw-r--r--drivers/acpi/acpi_lpss.c82
-rw-r--r--drivers/acpi/acpi_pad.c24
-rw-r--r--drivers/acpi/acpica/Makefile4
-rw-r--r--drivers/acpi/acpica/accommon.h2
-rw-r--r--drivers/acpi/acpica/acdebug.h4
-rw-r--r--drivers/acpi/acpica/acdispat.h15
-rw-r--r--drivers/acpi/acpica/acevents.h2
-rw-r--r--drivers/acpi/acpica/acglobal.h364
-rw-r--r--drivers/acpi/acpica/achware.h2
-rw-r--r--drivers/acpi/acpica/acinterp.h10
-rw-r--r--drivers/acpi/acpica/aclocal.h2
-rw-r--r--drivers/acpi/acpica/acmacros.h16
-rw-r--r--drivers/acpi/acpica/acnamesp.h2
-rw-r--r--drivers/acpi/acpica/acobject.h5
-rw-r--r--drivers/acpi/acpica/acopcode.h2
-rw-r--r--drivers/acpi/acpica/acparser.h2
-rw-r--r--drivers/acpi/acpica/acpredef.h16
-rw-r--r--drivers/acpi/acpica/acresrc.h2
-rw-r--r--drivers/acpi/acpica/acstruct.h5
-rw-r--r--drivers/acpi/acpica/actables.h2
-rw-r--r--drivers/acpi/acpica/acutils.h4
-rw-r--r--drivers/acpi/acpica/amlcode.h2
-rw-r--r--drivers/acpi/acpica/amlresrc.h2
-rw-r--r--drivers/acpi/acpica/dsargs.c2
-rw-r--r--drivers/acpi/acpica/dscontrol.c2
-rw-r--r--drivers/acpi/acpica/dsfield.c2
-rw-r--r--drivers/acpi/acpica/dsinit.c61
-rw-r--r--drivers/acpi/acpica/dsmethod.c158
-rw-r--r--drivers/acpi/acpica/dsmthdat.c2
-rw-r--r--drivers/acpi/acpica/dsobject.c2
-rw-r--r--drivers/acpi/acpica/dsopcode.c2
-rw-r--r--drivers/acpi/acpica/dsutils.c2
-rw-r--r--drivers/acpi/acpica/dswexec.c2
-rw-r--r--drivers/acpi/acpica/dswload.c18
-rw-r--r--drivers/acpi/acpica/dswload2.c2
-rw-r--r--drivers/acpi/acpica/dswscope.c2
-rw-r--r--drivers/acpi/acpica/dswstate.c2
-rw-r--r--drivers/acpi/acpica/evevent.c2
-rw-r--r--drivers/acpi/acpica/evglock.c2
-rw-r--r--drivers/acpi/acpica/evgpe.c2
-rw-r--r--drivers/acpi/acpica/evgpeblk.c2
-rw-r--r--drivers/acpi/acpica/evgpeinit.c2
-rw-r--r--drivers/acpi/acpica/evgpeutil.c2
-rw-r--r--drivers/acpi/acpica/evhandler.c2
-rw-r--r--drivers/acpi/acpica/evmisc.c2
-rw-r--r--drivers/acpi/acpica/evregion.c13
-rw-r--r--drivers/acpi/acpica/evrgnini.c2
-rw-r--r--drivers/acpi/acpica/evsci.c2
-rw-r--r--drivers/acpi/acpica/evxface.c2
-rw-r--r--drivers/acpi/acpica/evxfevnt.c2
-rw-r--r--drivers/acpi/acpica/evxfgpe.c21
-rw-r--r--drivers/acpi/acpica/evxfregn.c2
-rw-r--r--drivers/acpi/acpica/exconfig.c2
-rw-r--r--drivers/acpi/acpica/exconvrt.c2
-rw-r--r--drivers/acpi/acpica/excreate.c2
-rw-r--r--drivers/acpi/acpica/exdebug.c2
-rw-r--r--drivers/acpi/acpica/exdump.c231
-rw-r--r--drivers/acpi/acpica/exfield.c2
-rw-r--r--drivers/acpi/acpica/exfldio.c2
-rw-r--r--drivers/acpi/acpica/exmisc.c2
-rw-r--r--drivers/acpi/acpica/exmutex.c2
-rw-r--r--drivers/acpi/acpica/exnames.c2
-rw-r--r--drivers/acpi/acpica/exoparg1.c2
-rw-r--r--drivers/acpi/acpica/exoparg2.c2
-rw-r--r--drivers/acpi/acpica/exoparg3.c2
-rw-r--r--drivers/acpi/acpica/exoparg6.c2
-rw-r--r--drivers/acpi/acpica/exprep.c2
-rw-r--r--drivers/acpi/acpica/exregion.c2
-rw-r--r--drivers/acpi/acpica/exresnte.c2
-rw-r--r--drivers/acpi/acpica/exresolv.c2
-rw-r--r--drivers/acpi/acpica/exresop.c2
-rw-r--r--drivers/acpi/acpica/exstore.c2
-rw-r--r--drivers/acpi/acpica/exstoren.c2
-rw-r--r--drivers/acpi/acpica/exstorob.c2
-rw-r--r--drivers/acpi/acpica/exsystem.c14
-rw-r--r--drivers/acpi/acpica/exutils.c82
-rw-r--r--drivers/acpi/acpica/hwacpi.c2
-rw-r--r--drivers/acpi/acpica/hwesleep.c2
-rw-r--r--drivers/acpi/acpica/hwgpe.c2
-rw-r--r--drivers/acpi/acpica/hwpci.c2
-rw-r--r--drivers/acpi/acpica/hwregs.c2
-rw-r--r--drivers/acpi/acpica/hwsleep.c2
-rw-r--r--drivers/acpi/acpica/hwtimer.c2
-rw-r--r--drivers/acpi/acpica/hwvalid.c2
-rw-r--r--drivers/acpi/acpica/hwxface.c2
-rw-r--r--drivers/acpi/acpica/hwxfsleep.c2
-rw-r--r--drivers/acpi/acpica/nsaccess.c2
-rw-r--r--drivers/acpi/acpica/nsalloc.c2
-rw-r--r--drivers/acpi/acpica/nsarguments.c2
-rw-r--r--drivers/acpi/acpica/nsconvert.c2
-rw-r--r--drivers/acpi/acpica/nsdump.c2
-rw-r--r--drivers/acpi/acpica/nsdumpdv.c2
-rw-r--r--drivers/acpi/acpica/nseval.c2
-rw-r--r--drivers/acpi/acpica/nsinit.c7
-rw-r--r--drivers/acpi/acpica/nsload.c6
-rw-r--r--drivers/acpi/acpica/nsnames.c2
-rw-r--r--drivers/acpi/acpica/nsobject.c12
-rw-r--r--drivers/acpi/acpica/nsparse.c2
-rw-r--r--drivers/acpi/acpica/nspredef.c2
-rw-r--r--drivers/acpi/acpica/nsprepkg.c42
-rw-r--r--drivers/acpi/acpica/nsrepair.c31
-rw-r--r--drivers/acpi/acpica/nsrepair2.c39
-rw-r--r--drivers/acpi/acpica/nssearch.c2
-rw-r--r--drivers/acpi/acpica/nsutils.c2
-rw-r--r--drivers/acpi/acpica/nswalk.c2
-rw-r--r--drivers/acpi/acpica/nsxfeval.c35
-rw-r--r--drivers/acpi/acpica/nsxfname.c2
-rw-r--r--drivers/acpi/acpica/nsxfobj.c2
-rw-r--r--drivers/acpi/acpica/psargs.c2
-rw-r--r--drivers/acpi/acpica/psloop.c6
-rw-r--r--drivers/acpi/acpica/psobject.c9
-rw-r--r--drivers/acpi/acpica/psopcode.c2
-rw-r--r--drivers/acpi/acpica/psopinfo.c2
-rw-r--r--drivers/acpi/acpica/psparse.c2
-rw-r--r--drivers/acpi/acpica/psscope.c2
-rw-r--r--drivers/acpi/acpica/pstree.c2
-rw-r--r--drivers/acpi/acpica/psutils.c2
-rw-r--r--drivers/acpi/acpica/pswalk.c2
-rw-r--r--drivers/acpi/acpica/psxface.c2
-rw-r--r--drivers/acpi/acpica/rsaddr.c2
-rw-r--r--drivers/acpi/acpica/rscalc.c4
-rw-r--r--drivers/acpi/acpica/rscreate.c12
-rw-r--r--drivers/acpi/acpica/rsdump.c5
-rw-r--r--drivers/acpi/acpica/rsdumpinfo.c4
-rw-r--r--drivers/acpi/acpica/rsinfo.c6
-rw-r--r--drivers/acpi/acpica/rsio.c2
-rw-r--r--drivers/acpi/acpica/rsirq.c2
-rw-r--r--drivers/acpi/acpica/rslist.c2
-rw-r--r--drivers/acpi/acpica/rsmemory.c2
-rw-r--r--drivers/acpi/acpica/rsmisc.c2
-rw-r--r--drivers/acpi/acpica/rsserial.c2
-rw-r--r--drivers/acpi/acpica/rsutils.c2
-rw-r--r--drivers/acpi/acpica/rsxface.c2
-rw-r--r--drivers/acpi/acpica/tbfadt.c2
-rw-r--r--drivers/acpi/acpica/tbfind.c2
-rw-r--r--drivers/acpi/acpica/tbinstal.c17
-rw-r--r--drivers/acpi/acpica/tbprint.c22
-rw-r--r--drivers/acpi/acpica/tbutils.c2
-rw-r--r--drivers/acpi/acpica/tbxface.c2
-rw-r--r--drivers/acpi/acpica/tbxfload.c2
-rw-r--r--drivers/acpi/acpica/tbxfroot.c2
-rw-r--r--drivers/acpi/acpica/utaddress.c2
-rw-r--r--drivers/acpi/acpica/utalloc.c2
-rw-r--r--drivers/acpi/acpica/utbuffer.c2
-rw-r--r--drivers/acpi/acpica/utcache.c2
-rw-r--r--drivers/acpi/acpica/utcopy.c8
-rw-r--r--drivers/acpi/acpica/utdebug.c2
-rw-r--r--drivers/acpi/acpica/utdecode.c2
-rw-r--r--drivers/acpi/acpica/utdelete.c17
-rw-r--r--drivers/acpi/acpica/uterror.c2
-rw-r--r--drivers/acpi/acpica/uteval.c2
-rw-r--r--drivers/acpi/acpica/utexcep.c2
-rw-r--r--drivers/acpi/acpica/utglobal.c39
-rw-r--r--drivers/acpi/acpica/utids.c2
-rw-r--r--drivers/acpi/acpica/utinit.c2
-rw-r--r--drivers/acpi/acpica/utlock.c2
-rw-r--r--drivers/acpi/acpica/utmath.c2
-rw-r--r--drivers/acpi/acpica/utmisc.c2
-rw-r--r--drivers/acpi/acpica/utmutex.c2
-rw-r--r--drivers/acpi/acpica/utobject.c2
-rw-r--r--drivers/acpi/acpica/utosi.c28
-rw-r--r--drivers/acpi/acpica/utownerid.c2
-rw-r--r--drivers/acpi/acpica/utpredef.c2
-rw-r--r--drivers/acpi/acpica/utresrc.c5
-rw-r--r--drivers/acpi/acpica/utstate.c2
-rw-r--r--drivers/acpi/acpica/utstring.c2
-rw-r--r--drivers/acpi/acpica/uttrack.c5
-rw-r--r--drivers/acpi/acpica/utxface.c2
-rw-r--r--drivers/acpi/acpica/utxferror.c2
-rw-r--r--drivers/acpi/acpica/utxfinit.c2
-rw-r--r--drivers/acpi/acpica/utxfmutex.c2
-rw-r--r--drivers/acpi/apei/Kconfig2
-rw-r--r--drivers/acpi/battery.c9
-rw-r--r--drivers/acpi/battery.h10
-rw-r--r--drivers/acpi/blacklist.c58
-rw-r--r--drivers/acpi/bus.c63
-rw-r--r--drivers/acpi/button.c6
-rw-r--r--drivers/acpi/container.c10
-rw-r--r--drivers/acpi/device_pm.c41
-rw-r--r--drivers/acpi/dock.c463
-rw-r--r--drivers/acpi/ec.c64
-rw-r--r--drivers/acpi/fan.c12
-rw-r--r--drivers/acpi/glue.c12
-rw-r--r--drivers/acpi/internal.h13
-rw-r--r--drivers/acpi/numa.c16
-rw-r--r--drivers/acpi/osl.c43
-rw-r--r--drivers/acpi/pci_irq.c37
-rw-r--r--drivers/acpi/pci_link.c2
-rw-r--r--drivers/acpi/pci_root.c4
-rw-r--r--drivers/acpi/power.c2
-rw-r--r--drivers/acpi/processor_core.c52
-rw-r--r--drivers/acpi/processor_driver.c2
-rw-r--r--drivers/acpi/processor_perflib.c14
-rw-r--r--drivers/acpi/processor_throttling.c69
-rw-r--r--drivers/acpi/resource.c10
-rw-r--r--drivers/acpi/sbs.c6
-rw-r--r--drivers/acpi/scan.c261
-rw-r--r--drivers/acpi/sleep.c32
-rw-r--r--drivers/acpi/sysfs.c2
-rw-r--r--drivers/acpi/tables.c128
-rw-r--r--drivers/acpi/thermal.c39
-rw-r--r--drivers/acpi/utils.c16
-rw-r--r--drivers/acpi/video.c149
-rw-r--r--drivers/acpi/video_detect.c18
-rw-r--r--drivers/ata/Kconfig57
-rw-r--r--drivers/ata/Makefile8
-rw-r--r--drivers/ata/acard-ahci.c1
-rw-r--r--drivers/ata/ahci.c39
-rw-r--r--drivers/ata/ahci.h14
-rw-r--r--drivers/ata/ahci_da850.c114
-rw-r--r--drivers/ata/ahci_imx.c333
-rw-r--r--drivers/ata/ahci_platform.c291
-rw-r--r--drivers/ata/ahci_st.c245
-rw-r--r--drivers/ata/ahci_sunxi.c249
-rw-r--r--drivers/ata/ahci_xgene.c486
-rw-r--r--drivers/ata/ata_generic.c1
-rw-r--r--drivers/ata/libahci.c38
-rw-r--r--drivers/ata/libahci_platform.c541
-rw-r--r--drivers/ata/libata-acpi.c73
-rw-r--r--drivers/ata/libata-core.c142
-rw-r--r--drivers/ata/libata-eh.c18
-rw-r--r--drivers/ata/libata-pmp.c7
-rw-r--r--drivers/ata/libata-zpodd.c21
-rw-r--r--drivers/ata/pata_acpi.c1
-rw-r--r--drivers/ata/pata_amd.c1
-rw-r--r--drivers/ata/pata_arasan_cf.c2
-rw-r--r--drivers/ata/pata_artop.c1
-rw-r--r--drivers/ata/pata_at91.c1
-rw-r--r--drivers/ata/pata_atiixp.c1
-rw-r--r--drivers/ata/pata_atp867x.c1
-rw-r--r--drivers/ata/pata_cmd640.c1
-rw-r--r--drivers/ata/pata_cmd64x.c1
-rw-r--r--drivers/ata/pata_cs5520.c1
-rw-r--r--drivers/ata/pata_cs5530.c1
-rw-r--r--drivers/ata/pata_cs5535.c1
-rw-r--r--drivers/ata/pata_cs5536.c1
-rw-r--r--drivers/ata/pata_cypress.c1
-rw-r--r--drivers/ata/pata_efar.c1
-rw-r--r--drivers/ata/pata_ep93xx.c1
-rw-r--r--drivers/ata/pata_hpt366.c1
-rw-r--r--drivers/ata/pata_hpt37x.c1
-rw-r--r--drivers/ata/pata_hpt3x2n.c1
-rw-r--r--drivers/ata/pata_hpt3x3.c1
-rw-r--r--drivers/ata/pata_imx.c26
-rw-r--r--drivers/ata/pata_it8213.c1
-rw-r--r--drivers/ata/pata_it821x.c1
-rw-r--r--drivers/ata/pata_jmicron.c1
-rw-r--r--drivers/ata/pata_legacy.c1
-rw-r--r--drivers/ata/pata_marvell.c1
-rw-r--r--drivers/ata/pata_mpiix.c1
-rw-r--r--drivers/ata/pata_netcell.c1
-rw-r--r--drivers/ata/pata_ninja32.c1
-rw-r--r--drivers/ata/pata_ns87410.c1
-rw-r--r--drivers/ata/pata_ns87415.c1
-rw-r--r--drivers/ata/pata_oldpiix.c1
-rw-r--r--drivers/ata/pata_opti.c1
-rw-r--r--drivers/ata/pata_optidma.c1
-rw-r--r--drivers/ata/pata_pcmcia.c1
-rw-r--r--drivers/ata/pata_pdc2027x.c1
-rw-r--r--drivers/ata/pata_pdc202xx_old.c1
-rw-r--r--drivers/ata/pata_piccolo.c1
-rw-r--r--drivers/ata/pata_platform.c1
-rw-r--r--drivers/ata/pata_pxa.c1
-rw-r--r--drivers/ata/pata_radisys.c1
-rw-r--r--drivers/ata/pata_rdc.c1
-rw-r--r--drivers/ata/pata_rz1000.c1
-rw-r--r--drivers/ata/pata_sc1200.c1
-rw-r--r--drivers/ata/pata_scc.c1
-rw-r--r--drivers/ata/pata_sch.c1
-rw-r--r--drivers/ata/pata_serverworks.c1
-rw-r--r--drivers/ata/pata_sil680.c1
-rw-r--r--drivers/ata/pata_sis.c1
-rw-r--r--drivers/ata/pata_sl82c105.c1
-rw-r--r--drivers/ata/pata_triflex.c1
-rw-r--r--drivers/ata/pata_via.c1
-rw-r--r--drivers/ata/pdc_adma.c1
-rw-r--r--drivers/ata/sata_dwc_460ex.c4
-rw-r--r--drivers/ata/sata_highbank.c6
-rw-r--r--drivers/ata/sata_mv.c16
-rw-r--r--drivers/ata/sata_nv.c1
-rw-r--r--drivers/ata/sata_promise.c1
-rw-r--r--drivers/ata/sata_qstor.c1
-rw-r--r--drivers/ata/sata_sil.c2
-rw-r--r--drivers/ata/sata_sis.c1
-rw-r--r--drivers/ata/sata_svw.c1
-rw-r--r--drivers/ata/sata_sx4.c10
-rw-r--r--drivers/ata/sata_uli.c1
-rw-r--r--drivers/ata/sata_via.c1
-rw-r--r--drivers/ata/sata_vsc.c1
-rw-r--r--drivers/atm/ambassador.c2
-rw-r--r--drivers/atm/firestream.c6
-rw-r--r--drivers/atm/idt77105.c6
-rw-r--r--drivers/atm/nicstar.c24
-rw-r--r--drivers/atm/solos-pci.c2
-rw-r--r--drivers/base/Kconfig3
-rw-r--r--drivers/base/attribute_container.c1
-rw-r--r--drivers/base/bus.c2
-rw-r--r--drivers/base/component.c8
-rw-r--r--drivers/base/core.c20
-rw-r--r--drivers/base/cpu.c46
-rw-r--r--drivers/base/devres.c26
-rw-r--r--drivers/base/dma-buf.c43
-rw-r--r--drivers/base/firmware_class.c14
-rw-r--r--drivers/base/node.c4
-rw-r--r--drivers/base/platform.c11
-rw-r--r--drivers/base/power/Makefile3
-rw-r--r--drivers/base/power/clock_ops.c1
-rw-r--r--drivers/base/power/common.c1
-rw-r--r--drivers/base/power/domain.c3
-rw-r--r--drivers/base/power/domain_governor.c1
-rw-r--r--drivers/base/power/generic_ops.c2
-rw-r--r--drivers/base/power/main.c280
-rw-r--r--drivers/base/power/opp.c1
-rw-r--r--drivers/base/power/power.h4
-rw-r--r--drivers/base/power/qos.c220
-rw-r--r--drivers/base/power/runtime.c164
-rw-r--r--drivers/base/power/sysfs.c97
-rw-r--r--drivers/base/regmap/internal.h2
-rw-r--r--drivers/base/regmap/regcache.c13
-rw-r--r--drivers/base/regmap/regmap-debugfs.c2
-rw-r--r--drivers/base/regmap/regmap-i2c.c1
-rw-r--r--drivers/base/regmap/regmap-irq.c6
-rw-r--r--drivers/base/regmap/regmap-mmio.c57
-rw-r--r--drivers/base/regmap/regmap-spi.c1
-rw-r--r--drivers/base/regmap/regmap-spmi.c228
-rw-r--r--drivers/base/regmap/regmap.c353
-rw-r--r--drivers/base/topology.c1
-rw-r--r--drivers/bcma/driver_gpio.c9
-rw-r--r--drivers/block/DAC960.c34
-rw-r--r--drivers/block/aoe/aoecmd.c4
-rw-r--r--drivers/block/ataflop.c16
-rw-r--r--drivers/block/cciss.c2
-rw-r--r--drivers/block/drbd/drbd_actlog.c629
-rw-r--r--drivers/block/drbd/drbd_bitmap.c368
-rw-r--r--drivers/block/drbd/drbd_int.h1130
-rw-r--r--drivers/block/drbd/drbd_main.c2009
-rw-r--r--drivers/block/drbd/drbd_nl.c1653
-rw-r--r--drivers/block/drbd/drbd_proc.c140
-rw-r--r--drivers/block/drbd/drbd_protocol.h295
-rw-r--r--drivers/block/drbd/drbd_receiver.c2532
-rw-r--r--drivers/block/drbd/drbd_req.c464
-rw-r--r--drivers/block/drbd/drbd_req.h20
-rw-r--r--drivers/block/drbd/drbd_state.c859
-rw-r--r--drivers/block/drbd/drbd_state.h40
-rw-r--r--drivers/block/drbd/drbd_strings.c1
-rw-r--r--drivers/block/drbd/drbd_strings.h9
-rw-r--r--drivers/block/drbd/drbd_worker.c944
-rw-r--r--drivers/block/drbd/drbd_wrappers.h14
-rw-r--r--drivers/block/floppy.c42
-rw-r--r--drivers/block/mtip32xx/mtip32xx.c94
-rw-r--r--drivers/block/mtip32xx/mtip32xx.h4
-rw-r--r--drivers/block/null_blk.c97
-rw-r--r--drivers/block/nvme-core.c51
-rw-r--r--drivers/block/rbd.c1
-rw-r--r--drivers/block/skd_main.c67
-rw-r--r--drivers/block/swim3.c18
-rw-r--r--drivers/block/virtio_blk.c30
-rw-r--r--drivers/block/xen-blkback/blkback.c66
-rw-r--r--drivers/block/xen-blkback/common.h5
-rw-r--r--drivers/block/xen-blkback/xenbus.c14
-rw-r--r--drivers/block/xen-blkfront.c11
-rw-r--r--drivers/block/zram/zram_drv.c2
-rw-r--r--drivers/bluetooth/Kconfig3
-rw-r--r--drivers/bluetooth/ath3k.c97
-rw-r--r--drivers/bluetooth/bfusb.c14
-rw-r--r--drivers/bluetooth/bluecard_cs.c11
-rw-r--r--drivers/bluetooth/bt3c_cs.c7
-rw-r--r--drivers/bluetooth/btmrvl_main.c11
-rw-r--r--drivers/bluetooth/btuart_cs.c6
-rw-r--r--drivers/bluetooth/btusb.c59
-rw-r--r--drivers/bluetooth/dtl1_cs.c9
-rw-r--r--drivers/bluetooth/hci_bcsp.c31
-rw-r--r--drivers/bluetooth/hci_h5.c10
-rw-r--r--drivers/bluetooth/hci_ldisc.c9
-rw-r--r--drivers/bluetooth/hci_vhci.c3
-rw-r--r--drivers/bus/mvebu-mbus.c4
-rw-r--r--drivers/char/Kconfig1
-rw-r--r--drivers/char/agp/frontend.c1
-rw-r--r--drivers/char/agp/generic.c1
-rw-r--r--drivers/char/agp/intel-gtt.c1
-rw-r--r--drivers/char/agp/sgi-agp.c1
-rw-r--r--drivers/char/hw_random/atmel-rng.c23
-rw-r--r--drivers/char/hw_random/bcm2835-rng.c1
-rw-r--r--drivers/char/hw_random/core.c18
-rw-r--r--drivers/char/hw_random/exynos-rng.c1
-rw-r--r--drivers/char/hw_random/n2-drv.c1
-rw-r--r--drivers/char/hw_random/nomadik-rng.c14
-rw-r--r--drivers/char/hw_random/octeon-rng.c1
-rw-r--r--drivers/char/hw_random/omap3-rom-rng.c3
-rw-r--r--drivers/char/hw_random/picoxcell-rng.c27
-rw-r--r--drivers/char/hw_random/timeriomem-rng.c40
-rw-r--r--drivers/char/hw_random/virtio-rng.c3
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c1
-rw-r--r--drivers/char/mem.c6
-rw-r--r--drivers/char/mwave/3780i.c1
-rw-r--r--drivers/char/raw.c2
-rw-r--r--drivers/char/tile-srom.c1
-rw-r--r--drivers/char/tpm/tpm_i2c_infineon.c1
-rw-r--r--drivers/char/tpm/tpm_i2c_stm_st33.c1
-rw-r--r--drivers/clk/at91/clk-master.c2
-rw-r--r--drivers/clk/clk-nomadik.c3
-rw-r--r--drivers/clk/clk.c13
-rw-r--r--drivers/clk/keystone/gate.c1
-rw-r--r--drivers/clk/mvebu/armada-370.c21
-rw-r--r--drivers/clk/mvebu/armada-xp.c20
-rw-r--r--drivers/clk/mvebu/dove.c19
-rw-r--r--drivers/clk/mvebu/kirkwood.c34
-rw-r--r--drivers/clk/shmobile/clk-rcar-gen2.c48
-rw-r--r--drivers/clk/tegra/clk-divider.c2
-rw-r--r--drivers/clk/tegra/clk-id.h4
-rw-r--r--drivers/clk/tegra/clk-tegra-periph.c10
-rw-r--r--drivers/clk/tegra/clk-tegra-super-gen4.c2
-rw-r--r--drivers/clk/tegra/clk-tegra114.c8
-rw-r--r--drivers/clk/tegra/clk-tegra124.c48
-rw-r--r--drivers/clk/tegra/clk-tegra20.c2
-rw-r--r--drivers/clocksource/Kconfig48
-rw-r--r--drivers/clocksource/Makefile3
-rw-r--r--drivers/clocksource/arm_arch_timer.c1
-rw-r--r--drivers/clocksource/bcm_kona_timer.c54
-rw-r--r--drivers/clocksource/cadence_ttc_timer.c121
-rw-r--r--drivers/clocksource/cyclone.c113
-rw-r--r--drivers/clocksource/exynos_mct.c2
-rw-r--r--drivers/clocksource/sun4i_timer.c2
-rw-r--r--drivers/clocksource/time-armada-370-xp.c12
-rw-r--r--drivers/clocksource/time-orion.c28
-rw-r--r--drivers/clocksource/timer-keystone.c241
-rw-r--r--drivers/clocksource/timer-u300.c (renamed from arch/arm/mach-u300/timer.c)4
-rw-r--r--drivers/clocksource/vf_pit_timer.c2
-rw-r--r--drivers/connector/cn_proc.c18
-rw-r--r--drivers/connector/connector.c21
-rw-r--r--drivers/cpufreq/Kconfig2
-rw-r--r--drivers/cpufreq/Kconfig.arm17
-rw-r--r--drivers/cpufreq/acpi-cpufreq.c1
-rw-r--r--drivers/cpufreq/arm_big_little.c6
-rw-r--r--drivers/cpufreq/blackfin-cpufreq.c1
-rw-r--r--drivers/cpufreq/cpufreq-cpu0.c1
-rw-r--r--drivers/cpufreq/cpufreq-nforce2.c4
-rw-r--r--drivers/cpufreq/cpufreq.c553
-rw-r--r--drivers/cpufreq/cpufreq_stats.c40
-rw-r--r--drivers/cpufreq/cris-artpec3-cpufreq.c1
-rw-r--r--drivers/cpufreq/cris-etraxfs-cpufreq.c1
-rw-r--r--drivers/cpufreq/davinci-cpufreq.c1
-rw-r--r--drivers/cpufreq/e_powersaver.c1
-rw-r--r--drivers/cpufreq/elanfreq.c1
-rw-r--r--drivers/cpufreq/exynos-cpufreq.c97
-rw-r--r--drivers/cpufreq/exynos5440-cpufreq.c5
-rw-r--r--drivers/cpufreq/freq_table.c46
-rw-r--r--drivers/cpufreq/gx-suspmod.c4
-rw-r--r--drivers/cpufreq/ia64-acpi-cpufreq.c1
-rw-r--r--drivers/cpufreq/imx6q-cpufreq.c1
-rw-r--r--drivers/cpufreq/integrator-cpufreq.c4
-rw-r--r--drivers/cpufreq/intel_pstate.c99
-rw-r--r--drivers/cpufreq/kirkwood-cpufreq.c1
-rw-r--r--drivers/cpufreq/longhaul.c5
-rw-r--r--drivers/cpufreq/loongson2_cpufreq.c1
-rw-r--r--drivers/cpufreq/omap-cpufreq.c1
-rw-r--r--drivers/cpufreq/p4-clockmod.c1
-rw-r--r--drivers/cpufreq/pasemi-cpufreq.c1
-rw-r--r--drivers/cpufreq/pcc-cpufreq.c4
-rw-r--r--drivers/cpufreq/powernow-k6.c5
-rw-r--r--drivers/cpufreq/powernow-k7.c6
-rw-r--r--drivers/cpufreq/powernow-k8.c16
-rw-r--r--drivers/cpufreq/ppc-corenet-cpufreq.c5
-rw-r--r--drivers/cpufreq/ppc_cbe_cpufreq.c1
-rw-r--r--drivers/cpufreq/pxa2xx-cpufreq.c1
-rw-r--r--drivers/cpufreq/pxa3xx-cpufreq.c1
-rw-r--r--drivers/cpufreq/s3c24xx-cpufreq.c4
-rw-r--r--drivers/cpufreq/s5pv210-cpufreq.c49
-rw-r--r--drivers/cpufreq/sc520_freq.c1
-rw-r--r--drivers/cpufreq/sh-cpufreq.c5
-rw-r--r--drivers/cpufreq/sparc-us2e-cpufreq.c4
-rw-r--r--drivers/cpufreq/sparc-us3-cpufreq.c4
-rw-r--r--drivers/cpufreq/spear-cpufreq.c14
-rw-r--r--drivers/cpufreq/speedstep-centrino.c2
-rw-r--r--drivers/cpufreq/speedstep-ich.c1
-rw-r--r--drivers/cpufreq/speedstep-smi.c1
-rw-r--r--drivers/cpufreq/tegra-cpufreq.c47
-rw-r--r--drivers/cpufreq/unicore2-cpufreq.c4
-rw-r--r--drivers/cpuidle/coupled.c2
-rw-r--r--drivers/cpuidle/cpuidle-powernv.c107
-rw-r--r--drivers/cpuidle/cpuidle-pseries.c6
-rw-r--r--drivers/cpuidle/cpuidle.c108
-rw-r--r--drivers/cpuidle/driver.c2
-rw-r--r--drivers/cpuidle/governors/menu.c75
-rw-r--r--drivers/crypto/Kconfig22
-rw-r--r--drivers/crypto/Makefile2
-rw-r--r--drivers/crypto/bfin_crc.c45
-rw-r--r--drivers/crypto/caam/caamalg.c384
-rw-r--r--drivers/crypto/caam/caamrng.c17
-rw-r--r--drivers/crypto/caam/compat.h1
-rw-r--r--drivers/crypto/caam/ctrl.c61
-rw-r--r--drivers/crypto/caam/ctrl.h2
-rw-r--r--drivers/crypto/caam/desc_constr.h27
-rw-r--r--drivers/crypto/caam/regs.h4
-rw-r--r--drivers/crypto/ccp/ccp-crypto-main.c224
-rw-r--r--drivers/crypto/ccp/ccp-crypto-sha.c130
-rw-r--r--drivers/crypto/ccp/ccp-crypto.h8
-rw-r--r--drivers/crypto/ccp/ccp-dev.c21
-rw-r--r--drivers/crypto/ccp/ccp-ops.c108
-rw-r--r--drivers/crypto/mxs-dcp.c83
-rw-r--r--drivers/crypto/nx/nx-842.c29
-rw-r--r--drivers/crypto/omap-aes.c4
-rw-r--r--drivers/crypto/omap-des.c1216
-rw-r--r--drivers/crypto/omap-sham.c12
-rw-r--r--drivers/crypto/picoxcell_crypto.c16
-rw-r--r--drivers/crypto/s5p-sss.c13
-rw-r--r--drivers/crypto/sahara.c26
-rw-r--r--drivers/crypto/talitos.c4
-rw-r--r--drivers/crypto/tegra-aes.c1087
-rw-r--r--drivers/crypto/tegra-aes.h103
-rw-r--r--drivers/devfreq/devfreq.c31
-rw-r--r--drivers/dma/Kconfig1
-rw-r--r--drivers/dma/imx-sdma.c1
-rw-r--r--drivers/dma/ioat/dma.c52
-rw-r--r--drivers/dma/ioat/dma.h1
-rw-r--r--drivers/dma/ioat/dma_v2.c11
-rw-r--r--drivers/dma/ioat/dma_v3.c3
-rw-r--r--drivers/dma/mv_xor.c24
-rw-r--r--drivers/dma/ste_dma40.c4
-rw-r--r--drivers/edac/amd64_edac.c38
-rw-r--r--drivers/edac/amd64_edac.h3
-rw-r--r--drivers/edac/amd8111_edac.c44
-rw-r--r--drivers/edac/e752x_edac.c30
-rw-r--r--drivers/edac/edac_mc.c13
-rw-r--r--drivers/edac/edac_mc_sysfs.c12
-rw-r--r--drivers/edac/edac_module.h2
-rw-r--r--drivers/edac/ghes_edac.c2
-rw-r--r--drivers/edac/i3200_edac.c2
-rw-r--r--drivers/edac/i5100_edac.c17
-rw-r--r--drivers/edac/i5400_edac.c6
-rw-r--r--drivers/edac/i7300_edac.c42
-rw-r--r--drivers/edac/i7core_edac.c23
-rw-r--r--drivers/edac/i82875p_edac.c2
-rw-r--r--drivers/edac/mce_amd.c65
-rw-r--r--drivers/edac/mpc85xx_edac.c6
-rw-r--r--drivers/edac/octeon_edac-lmc.c179
-rw-r--r--drivers/edac/sb_edac.c31
-rw-r--r--drivers/extcon/Kconfig4
-rw-r--r--drivers/extcon/Makefile2
-rw-r--r--drivers/extcon/extcon-arizona.c12
-rw-r--r--drivers/extcon/extcon-class.c42
-rw-r--r--drivers/extcon/extcon-gpio.c4
-rw-r--r--drivers/extcon/extcon-palmas.c5
-rw-r--r--drivers/extcon/of_extcon.c64
-rw-r--r--drivers/firewire/core-device.c22
-rw-r--r--drivers/firewire/net.c6
-rw-r--r--drivers/firewire/ohci.c15
-rw-r--r--drivers/firewire/sbp2.c17
-rw-r--r--drivers/firmware/dcdbas.c2
-rw-r--r--drivers/firmware/efi/efi-stub-helper.c136
-rw-r--r--drivers/firmware/efi/efi.c5
-rw-r--r--drivers/firmware/efi/efivars.c2
-rw-r--r--drivers/firmware/google/gsmi.c7
-rw-r--r--drivers/firmware/google/memconsole.c47
-rw-r--r--drivers/fmc/fmc-core.c22
-rw-r--r--drivers/fmc/fmc-sdb.c41
-rw-r--r--drivers/fmc/fmc-write-eeprom.c2
-rw-r--r--drivers/gpio/Kconfig41
-rw-r--r--drivers/gpio/Makefile4
-rw-r--r--drivers/gpio/gpio-adnp.c15
-rw-r--r--drivers/gpio/gpio-adp5588.c16
-rw-r--r--drivers/gpio/gpio-bcm-kona.c113
-rw-r--r--drivers/gpio/gpio-clps711x.c2
-rw-r--r--drivers/gpio/gpio-davinci.c75
-rw-r--r--drivers/gpio/gpio-dwapb.c438
-rw-r--r--drivers/gpio/gpio-em.c14
-rw-r--r--drivers/gpio/gpio-generic.c20
-rw-r--r--drivers/gpio/gpio-ich.c70
-rw-r--r--drivers/gpio/gpio-intel-mid.c26
-rw-r--r--drivers/gpio/gpio-iop.c2
-rw-r--r--drivers/gpio/gpio-lynxpoint.c16
-rw-r--r--drivers/gpio/gpio-max732x.c9
-rw-r--r--drivers/gpio/gpio-mcp23s08.c36
-rw-r--r--drivers/gpio/gpio-moxart.c40
-rw-r--r--drivers/gpio/gpio-mvebu.c7
-rw-r--r--drivers/gpio/gpio-mxs.c3
-rw-r--r--drivers/gpio/gpio-omap.c20
-rw-r--r--drivers/gpio/gpio-pca953x.c10
-rw-r--r--drivers/gpio/gpio-pch.c8
-rw-r--r--drivers/gpio/gpio-pl061.c108
-rw-r--r--drivers/gpio/gpio-rc5t583.c2
-rw-r--r--drivers/gpio/gpio-rcar.c32
-rw-r--r--drivers/gpio/gpio-samsung.c1
-rw-r--r--drivers/gpio/gpio-syscon.c191
-rw-r--r--drivers/gpio/gpio-tnetv107x.c206
-rw-r--r--drivers/gpio/gpio-twl4030.c6
-rw-r--r--drivers/gpio/gpio-tz1090.c28
-rw-r--r--drivers/gpio/gpio-vr41xx.c20
-rw-r--r--drivers/gpio/gpio-xtensa.c16
-rw-r--r--drivers/gpio/gpio-zevio.c220
-rw-r--r--drivers/gpio/gpiolib-acpi.c474
-rw-r--r--drivers/gpio/gpiolib-of.c3
-rw-r--r--drivers/gpio/gpiolib.c417
-rw-r--r--drivers/gpio/gpiolib.h3
-rw-r--r--drivers/gpu/drm/armada/armada_drv.c10
-rw-r--r--drivers/gpu/drm/bochs/Kconfig1
-rw-r--r--drivers/gpu/drm/drm_cache.c10
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c2
-rw-r--r--drivers/gpu/drm/drm_fops.c3
-rw-r--r--drivers/gpu/drm/drm_ioctl.c12
-rw-r--r--drivers/gpu/drm/drm_pci.c2
-rw-r--r--drivers/gpu/drm/drm_prime.c2
-rw-r--r--drivers/gpu/drm/exynos/Kconfig4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dmabuf.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c18
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_g2d.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_iommu.c6
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_iommu.h1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_ipp.c3
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c66
-rw-r--r--drivers/gpu/drm/gma500/Kconfig1
-rw-r--r--drivers/gpu/drm/gma500/mmu.c2
-rw-r--r--drivers/gpu/drm/i2c/tda998x_drv.c19
-rw-r--r--drivers/gpu/drm/i915/Kconfig1
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c23
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h8
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c2
-rw-r--r--drivers/gpu/drm/i915/i915_gem_stolen.c26
-rw-r--r--drivers/gpu/drm/i915/i915_gpu_error.c5
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c74
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c1
-rw-r--r--drivers/gpu/drm/i915/intel_display.c22
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c43
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c6
-rw-r--r--drivers/gpu/drm/i915/intel_i2c.c7
-rw-r--r--drivers/gpu/drm/i915/intel_opregion.c9
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c4
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c6
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c21
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h1
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c179
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c4
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c7
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c2
-rw-r--r--drivers/gpu/drm/msm/msm_gem_submit.c9
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.c3
-rw-r--r--drivers/gpu/drm/nouveau/Kconfig3
-rw-r--r--drivers/gpu/drm/nouveau/Makefile1
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv40.c10
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv50.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv50.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/mc.h1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/base.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c45
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_acpi.c26
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c17
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_vga.c4
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c31
-rw-r--r--drivers/gpu/drm/radeon/atombios_encoders.c9
-rw-r--r--drivers/gpu/drm/radeon/btc_dpm.c32
-rw-r--r--drivers/gpu/drm/radeon/btcd.h4
-rw-r--r--drivers/gpu/drm/radeon/cik.c10
-rw-r--r--drivers/gpu/drm/radeon/cik_sdma.c14
-rw-r--r--drivers/gpu/drm/radeon/dce6_afmt.c15
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c7
-rw-r--r--drivers/gpu/drm/radeon/evergreen_hdmi.c26
-rw-r--r--drivers/gpu/drm/radeon/evergreen_smc.h2
-rw-r--r--drivers/gpu/drm/radeon/kv_dpm.c2
-rw-r--r--drivers/gpu/drm/radeon/ni.c3
-rw-r--r--drivers/gpu/drm/radeon/ni_dpm.c10
-rw-r--r--drivers/gpu/drm/radeon/r100.c2
-rw-r--r--drivers/gpu/drm/radeon/r300.c2
-rw-r--r--drivers/gpu/drm/radeon/r420.c2
-rw-r--r--drivers/gpu/drm/radeon/r520.c2
-rw-r--r--drivers/gpu/drm/radeon/r600.c7
-rw-r--r--drivers/gpu/drm/radeon/r600_audio.c14
-rw-r--r--drivers/gpu/drm/radeon/r600_hdmi.c15
-rw-r--r--drivers/gpu/drm/radeon/radeon.h10
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_atpx_handler.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c5
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c17
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c16
-rw-r--r--drivers/gpu/drm/radeon/radeon_ring.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_semaphore.c19
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c5
-rw-r--r--drivers/gpu/drm/radeon/radeon_uvd.c2
-rw-r--r--drivers/gpu/drm/radeon/rs400.c2
-rw-r--r--drivers/gpu/drm/radeon/rs600.c2
-rw-r--r--drivers/gpu/drm/radeon/rs690.c2
-rw-r--r--drivers/gpu/drm/radeon/rv515.c2
-rw-r--r--drivers/gpu/drm/radeon/rv770.c5
-rw-r--r--drivers/gpu/drm/radeon/rv770_dpm.c14
-rw-r--r--drivers/gpu/drm/radeon/si.c7
-rw-r--r--drivers/gpu/drm/radeon/si_dpm.c5
-rw-r--r--drivers/gpu/drm/radeon/sumo_dpm.c2
-rw-r--r--drivers/gpu/drm/radeon/trinity_dpm.c3
-rw-r--r--drivers/gpu/drm/radeon/uvd_v2_2.c1
-rw-r--r--drivers/gpu/drm/tegra/drm.c2
-rw-r--r--drivers/gpu/drm/tegra/rgb.c11
-rw-r--r--drivers/gpu/drm/ttm/ttm_agp_backend.c1
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c8
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_vm.c12
-rw-r--r--drivers/gpu/drm/udl/udl_gem.c11
-rw-r--r--drivers/gpu/drm/vmwgfx/svga3d_reg.h129
-rw-r--r--drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h11
-rw-r--r--drivers/gpu/drm/vmwgfx/svga_reg.h9
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_context.c9
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c3
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h3
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c9
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c3
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_mob.c35
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_resource.c3
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_shader.c16
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_surface.c18
-rw-r--r--drivers/gpu/host1x/job.c2
-rw-r--r--drivers/hid/Kconfig19
-rw-r--r--drivers/hid/Makefile1
-rw-r--r--drivers/hid/hid-apple.c3
-rw-r--r--drivers/hid/hid-core.c56
-rw-r--r--drivers/hid/hid-cp2112.c1073
-rw-r--r--drivers/hid/hid-hyperv.c21
-rw-r--r--drivers/hid/hid-ids.h16
-rw-r--r--drivers/hid/hid-input.c23
-rw-r--r--drivers/hid/hid-lg.c6
-rw-r--r--drivers/hid/hid-lg4ff.c2
-rw-r--r--drivers/hid/hid-logitech-dj.c111
-rw-r--r--drivers/hid/hid-magicmouse.c4
-rw-r--r--drivers/hid/hid-microsoft.c78
-rw-r--r--drivers/hid/hid-multitouch.c286
-rw-r--r--drivers/hid/hid-picolcd_cir.c2
-rw-r--r--drivers/hid/hid-prodikeys.c5
-rw-r--r--drivers/hid/hid-sensor-hub.c220
-rw-r--r--drivers/hid/hid-sony.c823
-rw-r--r--drivers/hid/hid-thingm.c4
-rw-r--r--drivers/hid/hid-wacom.c28
-rw-r--r--drivers/hid/hid-wiimote-core.c4
-rw-r--r--drivers/hid/hidraw.c31
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c139
-rw-r--r--drivers/hid/uhid.c103
-rw-r--r--drivers/hid/usbhid/hid-core.c102
-rw-r--r--drivers/hid/usbhid/hid-quirks.c1
-rw-r--r--drivers/hv/Makefile2
-rw-r--r--drivers/hv/channel.c42
-rw-r--r--drivers/hv/connection.c13
-rw-r--r--drivers/hv/hv_balloon.c3
-rw-r--r--drivers/hv/hv_fcopy.c414
-rw-r--r--drivers/hv/hv_kvp.c4
-rw-r--r--drivers/hv/hv_snapshot.c2
-rw-r--r--drivers/hv/hv_util.c11
-rw-r--r--drivers/hv/hyperv_vmbus.h8
-rw-r--r--drivers/hv/ring_buffer.c17
-rw-r--r--drivers/hv/vmbus_drv.c108
-rw-r--r--drivers/hwmon/Kconfig612
-rw-r--r--drivers/hwmon/Makefile5
-rw-r--r--drivers/hwmon/adc128d818.c491
-rw-r--r--drivers/hwmon/coretemp.c71
-rw-r--r--drivers/hwmon/emc2103.c2
-rw-r--r--drivers/hwmon/hwmon.c5
-rw-r--r--drivers/hwmon/ibmpowernv.c529
-rw-r--r--drivers/hwmon/iio_hwmon.c37
-rw-r--r--drivers/hwmon/jz4740-hwmon.c25
-rw-r--r--drivers/hwmon/k10temp.c1
-rw-r--r--drivers/hwmon/lm95241.c93
-rw-r--r--drivers/hwmon/lm95245.c112
-rw-r--r--drivers/hwmon/ltc2945.c519
-rw-r--r--drivers/hwmon/ltc4215.c51
-rw-r--r--drivers/hwmon/ltc4222.c237
-rw-r--r--drivers/hwmon/ltc4245.c30
-rw-r--r--drivers/hwmon/ltc4260.c200
-rw-r--r--drivers/hwmon/max1668.c81
-rw-r--r--drivers/hwmon/max6639.c91
-rw-r--r--drivers/hwmon/max6650.c257
-rw-r--r--drivers/hwmon/ntc_thermistor.c6
-rw-r--r--drivers/hwmon/pmbus/ltc2978.c25
-rw-r--r--drivers/hwmon/smm665.c2
-rw-r--r--drivers/i2c/busses/Kconfig2
-rw-r--r--drivers/i2c/busses/i2c-cpm.c2
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c33
-rw-r--r--drivers/iio/accel/bma180.c20
-rw-r--r--drivers/iio/adc/Kconfig33
-rw-r--r--drivers/iio/adc/Makefile4
-rw-r--r--drivers/iio/adc/max1363.c18
-rw-r--r--drivers/iio/adc/men_z188_adc.c172
-rw-r--r--drivers/iio/adc/ti_am335x_adc.c1
-rw-r--r--drivers/iio/adc/twl6030-gpadc.c1
-rw-r--r--drivers/iio/adc/vf610_adc.c711
-rw-r--r--drivers/iio/adc/viperboard_adc.c2
-rw-r--r--drivers/iio/adc/xilinx-xadc-core.c1333
-rw-r--r--drivers/iio/adc/xilinx-xadc-events.c254
-rw-r--r--drivers/iio/adc/xilinx-xadc.h209
-rw-r--r--drivers/iio/buffer_cb.c7
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.c39
-rw-r--r--drivers/iio/dac/ad7303.c2
-rw-r--r--drivers/iio/dac/max517.c1
-rw-r--r--drivers/iio/dac/mcp4725.c1
-rw-r--r--drivers/iio/gyro/Kconfig2
-rw-r--r--drivers/iio/gyro/st_gyro.h1
-rw-r--r--drivers/iio/gyro/st_gyro_core.c9
-rw-r--r--drivers/iio/gyro/st_gyro_i2c.c1
-rw-r--r--drivers/iio/gyro/st_gyro_spi.c1
-rw-r--r--drivers/iio/humidity/Kconfig10
-rw-r--r--drivers/iio/humidity/Makefile1
-rw-r--r--drivers/iio/humidity/si7005.c189
-rw-r--r--drivers/iio/imu/Kconfig4
-rw-r--r--drivers/iio/imu/adis16400.h1
-rw-r--r--drivers/iio/imu/adis16400_core.c12
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c3
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h38
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c1
-rw-r--r--drivers/iio/industrialio-buffer.c16
-rw-r--r--drivers/iio/industrialio-core.c51
-rw-r--r--drivers/iio/industrialio-event.c100
-rw-r--r--drivers/iio/industrialio-trigger.c11
-rw-r--r--drivers/iio/light/Kconfig26
-rw-r--r--drivers/iio/light/Makefile2
-rw-r--r--drivers/iio/light/adjd_s311.c3
-rw-r--r--drivers/iio/light/cm32181.c16
-rw-r--r--drivers/iio/light/cm36651.c45
-rw-r--r--drivers/iio/light/hid-sensor-prox.c375
-rw-r--r--drivers/iio/light/ltr501.c445
-rw-r--r--drivers/iio/light/tcs3472.c2
-rw-r--r--drivers/iio/light/tsl2563.c16
-rw-r--r--drivers/iio/magnetometer/ak8975.c17
-rw-r--r--drivers/iio/magnetometer/mag3110.c25
-rw-r--r--drivers/iio/pressure/Kconfig16
-rw-r--r--drivers/iio/pressure/Makefile1
-rw-r--r--drivers/iio/pressure/hid-sensor-press.c376
-rw-r--r--drivers/iio/pressure/mpl3115.c2
-rw-r--r--drivers/iio/pressure/st_pressure.h1
-rw-r--r--drivers/iio/pressure/st_pressure_core.c87
-rw-r--r--drivers/iio/pressure/st_pressure_i2c.c1
-rw-r--r--drivers/iio/pressure/st_pressure_spi.c1
-rw-r--r--drivers/infiniband/core/cm.c17
-rw-r--r--drivers/infiniband/core/cma.c26
-rw-r--r--drivers/infiniband/core/mad.c14
-rw-r--r--drivers/infiniband/core/umem.c120
-rw-r--r--drivers/infiniband/core/verbs.c47
-rw-r--r--drivers/infiniband/hw/amso1100/c2.c4
-rw-r--r--drivers/infiniband/hw/amso1100/c2_provider.c23
-rw-r--r--drivers/infiniband/hw/amso1100/c2_rnic.c3
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c19
-rw-r--r--drivers/infiniband/hw/cxgb4/cm.c133
-rw-r--r--drivers/infiniband/hw/cxgb4/cq.c31
-rw-r--r--drivers/infiniband/hw/cxgb4/device.c183
-rw-r--r--drivers/infiniband/hw/cxgb4/iw_cxgb4.h11
-rw-r--r--drivers/infiniband/hw/cxgb4/mem.c55
-rw-r--r--drivers/infiniband/hw/cxgb4/provider.c45
-rw-r--r--drivers/infiniband/hw/cxgb4/qp.c148
-rw-r--r--drivers/infiniband/hw/cxgb4/t4.h6
-rw-r--r--drivers/infiniband/hw/cxgb4/user.h5
-rw-r--r--drivers/infiniband/hw/ehca/ehca_classes.h2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_cq.c1
-rw-r--r--drivers/infiniband/hw/ehca/ehca_mrmw.c257
-rw-r--r--drivers/infiniband/hw/ipath/ipath_diag.c66
-rw-r--r--drivers/infiniband/hw/ipath/ipath_dma.c43
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mr.c39
-rw-r--r--drivers/infiniband/hw/mlx4/alias_GUID.c2
-rw-r--r--drivers/infiniband/hw/mlx4/cm.c80
-rw-r--r--drivers/infiniband/hw/mlx4/cq.c42
-rw-r--r--drivers/infiniband/hw/mlx4/doorbell.c4
-rw-r--r--drivers/infiniband/hw/mlx4/mad.c122
-rw-r--r--drivers/infiniband/hw/mlx4/main.c231
-rw-r--r--drivers/infiniband/hw/mlx4/mcg.c5
-rw-r--r--drivers/infiniband/hw/mlx4/mlx4_ib.h24
-rw-r--r--drivers/infiniband/hw/mlx4/mr.c39
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c321
-rw-r--r--drivers/infiniband/hw/mlx4/sysfs.c5
-rw-r--r--drivers/infiniband/hw/mlx5/Kconfig2
-rw-r--r--drivers/infiniband/hw/mlx5/cq.c62
-rw-r--r--drivers/infiniband/hw/mlx5/doorbell.c4
-rw-r--r--drivers/infiniband/hw/mlx5/main.c38
-rw-r--r--drivers/infiniband/hw/mlx5/mem.c80
-rw-r--r--drivers/infiniband/hw/mlx5/mlx5_ib.h14
-rw-r--r--drivers/infiniband/hw/mlx5/mr.c157
-rw-r--r--drivers/infiniband/hw/mlx5/qp.c556
-rw-r--r--drivers/infiniband/hw/mlx5/user.h7
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.c43
-rw-r--r--drivers/infiniband/hw/nes/nes.c5
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c121
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.h3
-rw-r--r--drivers/infiniband/hw/nes/nes_user.h5
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.c261
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.h1
-rw-r--r--drivers/infiniband/hw/ocrdma/Makefile2
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma.h110
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_abi.h7
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_ah.c2
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_hw.c299
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_hw.h6
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_main.c83
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_sli.h261
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_stats.c623
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_stats.h54
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_verbs.c237
-rw-r--r--drivers/infiniband/hw/qib/qib.h12
-rw-r--r--drivers/infiniband/hw/qib/qib_diag.c52
-rw-r--r--drivers/infiniband/hw/qib/qib_dma.c21
-rw-r--r--drivers/infiniband/hw/qib/qib_file_ops.c5
-rw-r--r--drivers/infiniband/hw/qib/qib_fs.c1
-rw-r--r--drivers/infiniband/hw/qib/qib_iba6120.c11
-rw-r--r--drivers/infiniband/hw/qib/qib_iba7220.c12
-rw-r--r--drivers/infiniband/hw/qib/qib_iba7322.c42
-rw-r--r--drivers/infiniband/hw/qib/qib_init.c96
-rw-r--r--drivers/infiniband/hw/qib/qib_mad.c44
-rw-r--r--drivers/infiniband/hw/qib/qib_mr.c14
-rw-r--r--drivers/infiniband/hw/qib/qib_rc.c2
-rw-r--r--drivers/infiniband/hw/qib/qib_ruc.c1
-rw-r--r--drivers/infiniband/hw/qib/qib_ud.c6
-rw-r--r--drivers/infiniband/hw/qib/qib_user_sdma.c136
-rw-r--r--drivers/infiniband/hw/qib/qib_verbs.c8
-rw-r--r--drivers/infiniband/hw/qib/qib_verbs.h16
-rw-r--r--drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c9
-rw-r--r--drivers/infiniband/hw/usnic/usnic_uiom.c2
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c93
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.h85
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c157
-rw-r--r--drivers/infiniband/ulp/iser/iser_memory.c470
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c329
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.c181
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.h7
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c83
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.h1
-rw-r--r--drivers/infiniband/ulp/srpt/ib_srpt.c14
-rw-r--r--drivers/input/evdev.c4
-rw-r--r--drivers/input/keyboard/Kconfig22
-rw-r--r--drivers/input/keyboard/Makefile2
-rw-r--r--drivers/input/keyboard/adp5588-keys.c12
-rw-r--r--drivers/input/keyboard/clps711x-keypad.c207
-rw-r--r--drivers/input/keyboard/imx_keypad.c4
-rw-r--r--drivers/input/keyboard/pmic8xxx-keypad.c348
-rw-r--r--drivers/input/keyboard/tnetv107x-keypad.c329
-rw-r--r--drivers/input/misc/Kconfig12
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/arizona-haptics.c19
-rw-r--r--drivers/input/misc/da9052_onkey.c29
-rw-r--r--drivers/input/misc/ims-pcu.c258
-rw-r--r--drivers/input/misc/pm8xxx-vibrator.c9
-rw-r--r--drivers/input/misc/pmic8xxx-pwrkey.c33
-rw-r--r--drivers/input/misc/sirfsoc-onkey.c111
-rw-r--r--drivers/input/misc/soc_button_array.c218
-rw-r--r--drivers/input/misc/uinput.c97
-rw-r--r--drivers/input/misc/wistron_btns.c19
-rw-r--r--drivers/input/mouse/appletouch.c143
-rw-r--r--drivers/input/mouse/cypress_ps2.c1
-rw-r--r--drivers/input/mouse/synaptics.c55
-rw-r--r--drivers/input/mousedev.c73
-rw-r--r--drivers/input/serio/Kconfig2
-rw-r--r--drivers/input/serio/hp_sdc.c2
-rw-r--r--drivers/input/sparse-keymap.c2
-rw-r--r--drivers/input/tablet/gtco.c2
-rw-r--r--drivers/input/touchscreen/Kconfig9
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/edt-ft5x06.c519
-rw-r--r--drivers/input/touchscreen/st1232.c3
-rw-r--r--drivers/input/touchscreen/tnetv107x-ts.c384
-rw-r--r--drivers/input/touchscreen/zforce_ts.c95
-rw-r--r--drivers/iommu/amd_iommu_types.h1
-rw-r--r--drivers/iommu/arm-smmu.c105
-rw-r--r--drivers/iommu/omap-iommu-debug.c4
-rw-r--r--drivers/iommu/shmobile-iommu.c2
-rw-r--r--drivers/irqchip/Makefile1
-rw-r--r--drivers/irqchip/irq-armada-370-xp.c98
-rw-r--r--drivers/irqchip/irq-bcm2835.c4
-rw-r--r--drivers/irqchip/irq-gic.c11
-rw-r--r--drivers/irqchip/irq-metag-ext.c2
-rw-r--r--drivers/irqchip/irq-metag.c2
-rw-r--r--drivers/irqchip/irq-mmp.c6
-rw-r--r--drivers/irqchip/irq-moxart.c2
-rw-r--r--drivers/irqchip/irq-orion.c24
-rw-r--r--drivers/irqchip/irq-sirfsoc.c2
-rw-r--r--drivers/irqchip/irq-sun4i.c42
-rw-r--r--drivers/irqchip/irq-sunxi-nmi.c208
-rw-r--r--drivers/irqchip/irq-vic.c2
-rw-r--r--drivers/irqchip/irq-vt8500.c3
-rw-r--r--drivers/irqchip/irq-xtensa-mx.c2
-rw-r--r--drivers/irqchip/irq-zevio.c2
-rw-r--r--drivers/irqchip/irqchip.c3
-rw-r--r--drivers/isdn/act2000/module.c2
-rw-r--r--drivers/isdn/capi/Kconfig18
-rw-r--r--drivers/isdn/divert/divert_procfs.c7
-rw-r--r--drivers/isdn/hisax/elsa.c9
-rw-r--r--drivers/isdn/hisax/elsa_ser.c3
-rw-r--r--drivers/isdn/hisax/q931.c2
-rw-r--r--drivers/isdn/hysdn/hysdn_proclog.c7
-rw-r--r--drivers/isdn/i4l/isdn_common.c15
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c61
-rw-r--r--drivers/isdn/pcbit/drv.c6
-rw-r--r--drivers/isdn/sc/init.c4
-rw-r--r--drivers/macintosh/adb.c57
-rw-r--r--drivers/mcb/Kconfig31
-rw-r--r--drivers/mcb/Makefile7
-rw-r--r--drivers/mcb/mcb-core.c414
-rw-r--r--drivers/mcb/mcb-internal.h118
-rw-r--r--drivers/mcb/mcb-parse.c159
-rw-r--r--drivers/mcb/mcb-pci.c114
-rw-r--r--drivers/md/Kconfig10
-rw-r--r--drivers/md/bcache/Kconfig8
-rw-r--r--drivers/md/bcache/alloc.c173
-rw-r--r--drivers/md/bcache/bcache.h60
-rw-r--r--drivers/md/bcache/bset.c9
-rw-r--r--drivers/md/bcache/bset.h6
-rw-r--r--drivers/md/bcache/btree.c596
-rw-r--r--drivers/md/bcache/btree.h12
-rw-r--r--drivers/md/bcache/extents.c36
-rw-r--r--drivers/md/bcache/journal.c46
-rw-r--r--drivers/md/bcache/journal.h1
-rw-r--r--drivers/md/bcache/movinggc.c18
-rw-r--r--drivers/md/bcache/request.c207
-rw-r--r--drivers/md/bcache/request.h19
-rw-r--r--drivers/md/bcache/stats.c3
-rw-r--r--drivers/md/bcache/super.c64
-rw-r--r--drivers/md/bcache/sysfs.c157
-rw-r--r--drivers/md/bcache/trace.c2
-rw-r--r--drivers/md/dm-cache-policy-mq.c4
-rw-r--r--drivers/md/dm-cache-target.c24
-rw-r--r--drivers/md/dm-io.c23
-rw-r--r--drivers/md/dm-log-userspace-transfer.c2
-rw-r--r--drivers/md/dm-mpath.c7
-rw-r--r--drivers/md/dm-raid1.c3
-rw-r--r--drivers/md/dm-snap-persistent.c3
-rw-r--r--drivers/md/dm-thin-metadata.c58
-rw-r--r--drivers/md/dm-thin-metadata.h21
-rw-r--r--drivers/md/dm-thin.c343
-rw-r--r--drivers/md/persistent-data/Kconfig10
-rw-r--r--drivers/md/persistent-data/dm-space-map-metadata.c115
-rw-r--r--drivers/md/persistent-data/dm-space-map-metadata.h11
-rw-r--r--drivers/md/raid1.c13
-rw-r--r--drivers/md/raid5.c90
-rw-r--r--drivers/media/common/siano/smsdvb-debugfs.c2
-rw-r--r--drivers/media/common/siano/smsir.c2
-rw-r--r--drivers/media/dvb-core/dvb-usb-ids.h1
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c10
-rw-r--r--drivers/media/dvb-frontends/Kconfig12
-rw-r--r--drivers/media/dvb-frontends/Makefile2
-rw-r--r--drivers/media/dvb-frontends/af9033.c59
-rw-r--r--drivers/media/dvb-frontends/af9033.h34
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/Kconfig7
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/Makefile6
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/bsp_i2c.h139
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/drx39xxj.h45
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/drx_dap_fasi.h256
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/drx_driver.h2343
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/drx_driver_version.h72
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/drxj.c12400
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/drxj.h650
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/drxj_map.h15055
-rw-r--r--drivers/media/dvb-frontends/drxd_hard.c4
-rw-r--r--drivers/media/dvb-frontends/ds3000.c2
-rw-r--r--drivers/media/dvb-frontends/it913x-fe-priv.h1051
-rw-r--r--drivers/media/dvb-frontends/it913x-fe.c1045
-rw-r--r--drivers/media/dvb-frontends/it913x-fe.h237
-rw-r--r--drivers/media/dvb-frontends/m88ds3103.c30
-rw-r--r--drivers/media/dvb-frontends/m88rs2000.c19
-rw-r--r--drivers/media/dvb-frontends/mb86a20s.c4
-rw-r--r--drivers/media/dvb-frontends/mb86a20s.h2
-rw-r--r--drivers/media/dvb-frontends/rtl2832.c191
-rw-r--r--drivers/media/dvb-frontends/rtl2832.h34
-rw-r--r--drivers/media/dvb-frontends/rtl2832_priv.h54
-rw-r--r--drivers/media/dvb-frontends/s921.c4
-rw-r--r--drivers/media/dvb-frontends/s921.h2
-rw-r--r--drivers/media/dvb-frontends/stb6100.c2
-rw-r--r--drivers/media/dvb-frontends/stv0900_sw.c2
-rw-r--r--drivers/media/dvb-frontends/tda10071.c68
-rw-r--r--drivers/media/dvb-frontends/tda10071.h2
-rw-r--r--drivers/media/i2c/Kconfig16
-rw-r--r--drivers/media/i2c/Makefile1
-rw-r--r--drivers/media/i2c/ad9389b.c2
-rw-r--r--drivers/media/i2c/adv7180.c118
-rw-r--r--drivers/media/i2c/adv7343.c4
-rw-r--r--drivers/media/i2c/adv7511.c2
-rw-r--r--drivers/media/i2c/adv7604.c4
-rw-r--r--drivers/media/i2c/adv7842.c153
-rw-r--r--drivers/media/i2c/ir-kbd-i2c.c4
-rw-r--r--drivers/media/i2c/lm3560.c22
-rw-r--r--drivers/media/i2c/lm3646.c414
-rw-r--r--drivers/media/i2c/mt9p031.c53
-rw-r--r--drivers/media/i2c/mt9t001.c229
-rw-r--r--drivers/media/i2c/mt9v011.c4
-rw-r--r--drivers/media/i2c/mt9v032.c10
-rw-r--r--drivers/media/i2c/s5k5baf.c3
-rw-r--r--drivers/media/i2c/sr030pc30.c2
-rw-r--r--drivers/media/i2c/ths8200.c26
-rw-r--r--drivers/media/i2c/tvp514x.c3
-rw-r--r--drivers/media/i2c/tvp5150.c8
-rw-r--r--drivers/media/i2c/tvp7002.c3
-rw-r--r--drivers/media/parport/bw-qcam.c8
-rw-r--r--drivers/media/pci/bt8xx/bttv-cards.c17
-rw-r--r--drivers/media/pci/bt8xx/bttv-input.c1
-rw-r--r--drivers/media/pci/bt8xx/bttv.h1
-rw-r--r--drivers/media/pci/cx18/cx18-alsa-main.c9
-rw-r--r--drivers/media/pci/cx23885/cx23885-alsa.c5
-rw-r--r--drivers/media/pci/cx23885/cx23885-dvb.c1
-rw-r--r--drivers/media/pci/cx23885/cx23885-input.c2
-rw-r--r--drivers/media/pci/cx25821/cx25821-alsa.c7
-rw-r--r--drivers/media/pci/cx88/cx88-alsa.c6
-rw-r--r--drivers/media/pci/cx88/cx88-input.c2
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-core.c6
-rw-r--r--drivers/media/pci/ivtv/ivtv-alsa-main.c9
-rw-r--r--drivers/media/pci/saa7134/saa7134-alsa.c6
-rw-r--r--drivers/media/pci/saa7134/saa7134-cards.c4
-rw-r--r--drivers/media/pci/sta2x11/sta2x11_vip.c7
-rw-r--r--drivers/media/pci/ttpci/av7110_hw.c2
-rw-r--r--drivers/media/platform/Kconfig2
-rw-r--r--drivers/media/platform/arv.c6
-rw-r--r--drivers/media/platform/blackfin/bfin_capture.c2
-rw-r--r--drivers/media/platform/coda.c7
-rw-r--r--drivers/media/platform/davinci/vpbe_display.c9
-rw-r--r--drivers/media/platform/davinci/vpif_capture.c9
-rw-r--r--drivers/media/platform/davinci/vpif_display.c9
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-m2m.c12
-rw-r--r--drivers/media/platform/exynos4-is/fimc-capture.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is.c6
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-m2m.c7
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.c13
-rw-r--r--drivers/media/platform/exynos4-is/mipi-csis.c5
-rw-r--r--drivers/media/platform/m2m-deinterlace.c11
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.c3
-rw-r--r--drivers/media/platform/mem2mem_testdev.c95
-rw-r--r--drivers/media/platform/mx2_emmaprp.c13
-rw-r--r--drivers/media/platform/omap/omap_vout.c1
-rw-r--r--drivers/media/platform/omap/omap_vout_vrfb.c3
-rw-r--r--drivers/media/platform/omap3isp/isp.c7
-rw-r--r--drivers/media/platform/omap3isp/isp.h12
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.c10
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.h6
-rw-r--r--drivers/media/platform/omap3isp/ispccp2.c6
-rw-r--r--drivers/media/platform/omap3isp/isphist.c4
-rw-r--r--drivers/media/platform/omap3isp/isppreview.c22
-rw-r--r--drivers/media/platform/omap3isp/ispqueue.c2
-rw-r--r--drivers/media/platform/omap3isp/ispresizer.c6
-rw-r--r--drivers/media/platform/omap3isp/ispresizer.h4
-rw-r--r--drivers/media/platform/omap3isp/ispstat.c4
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.c12
-rw-r--r--drivers/media/platform/s3c-camif/camif-capture.c17
-rw-r--r--drivers/media/platform/s5p-g2d/g2d.c7
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.c7
-rw-r--r--drivers/media/platform/s5p-mfc/regs-mfc-v6.h1
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc.c17
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_common.h2
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c2
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_enc.c24
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c8
-rw-r--r--drivers/media/platform/s5p-tv/mixer_video.c6
-rw-r--r--drivers/media/platform/soc_camera/atmel-isi.c2
-rw-r--r--drivers/media/platform/soc_camera/mx2_camera.c2
-rw-r--r--drivers/media/platform/soc_camera/mx3_camera.c2
-rw-r--r--drivers/media/platform/soc_camera/rcar_vin.c11
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c2
-rw-r--r--drivers/media/platform/ti-vpe/vpe.c6
-rw-r--r--drivers/media/platform/vivi.c54
-rw-r--r--drivers/media/platform/vsp1/vsp1.h2
-rw-r--r--drivers/media/platform/vsp1/vsp1_drv.c2
-rw-r--r--drivers/media/platform/vsp1/vsp1_entity.c2
-rw-r--r--drivers/media/platform/vsp1/vsp1_entity.h2
-rw-r--r--drivers/media/platform/vsp1/vsp1_lif.c2
-rw-r--r--drivers/media/platform/vsp1/vsp1_lif.h2
-rw-r--r--drivers/media/platform/vsp1/vsp1_rpf.c2
-rw-r--r--drivers/media/platform/vsp1/vsp1_rwpf.c2
-rw-r--r--drivers/media/platform/vsp1/vsp1_rwpf.h2
-rw-r--r--drivers/media/platform/vsp1/vsp1_uds.c2
-rw-r--r--drivers/media/platform/vsp1/vsp1_uds.h2
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.c4
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.h2
-rw-r--r--drivers/media/platform/vsp1/vsp1_wpf.c2
-rw-r--r--drivers/media/radio/radio-cadet.c46
-rw-r--r--drivers/media/radio/radio-keene.c19
-rw-r--r--drivers/media/radio/si4713/Kconfig6
-rw-r--r--drivers/media/radio/si4713/radio-usb-si4713.c4
-rw-r--r--drivers/media/rc/Kconfig11
-rw-r--r--drivers/media/rc/Makefile2
-rw-r--r--drivers/media/rc/ati_remote.c2
-rw-r--r--drivers/media/rc/ene_ir.c2
-rw-r--r--drivers/media/rc/fintek-cir.c2
-rw-r--r--drivers/media/rc/gpio-ir-recv.c4
-rw-r--r--drivers/media/rc/iguanair.c31
-rw-r--r--drivers/media/rc/img-ir/Kconfig61
-rw-r--r--drivers/media/rc/img-ir/Makefile11
-rw-r--r--drivers/media/rc/img-ir/img-ir-core.c176
-rw-r--r--drivers/media/rc/img-ir/img-ir-hw.c1053
-rw-r--r--drivers/media/rc/img-ir/img-ir-hw.h269
-rw-r--r--drivers/media/rc/img-ir/img-ir-jvc.c81
-rw-r--r--drivers/media/rc/img-ir/img-ir-nec.c148
-rw-r--r--drivers/media/rc/img-ir/img-ir-raw.c151
-rw-r--r--drivers/media/rc/img-ir/img-ir-raw.h60
-rw-r--r--drivers/media/rc/img-ir/img-ir-sanyo.c122
-rw-r--r--drivers/media/rc/img-ir/img-ir-sharp.c99
-rw-r--r--drivers/media/rc/img-ir/img-ir-sony.c145
-rw-r--r--drivers/media/rc/img-ir/img-ir.h166
-rw-r--r--drivers/media/rc/imon.c7
-rw-r--r--drivers/media/rc/ir-jvc-decoder.c2
-rw-r--r--drivers/media/rc/ir-lirc-codec.c2
-rw-r--r--drivers/media/rc/ir-mce_kbd-decoder.c2
-rw-r--r--drivers/media/rc/ir-nec-decoder.c11
-rw-r--r--drivers/media/rc/ir-raw.c5
-rw-r--r--drivers/media/rc/ir-rc5-decoder.c10
-rw-r--r--drivers/media/rc/ir-rc5-sz-decoder.c4
-rw-r--r--drivers/media/rc/ir-rc6-decoder.c6
-rw-r--r--drivers/media/rc/ir-sanyo-decoder.c6
-rw-r--r--drivers/media/rc/ir-sharp-decoder.c200
-rw-r--r--drivers/media/rc/ir-sony-decoder.c10
-rw-r--r--drivers/media/rc/ite-cir.c2
-rw-r--r--drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c4
-rw-r--r--drivers/media/rc/keymaps/rc-apac-viewcomp.c4
-rw-r--r--drivers/media/rc/keymaps/rc-asus-pc39.c4
-rw-r--r--drivers/media/rc/keymaps/rc-asus-ps3-100.c4
-rw-r--r--drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c4
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-a16d.c4
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-cardbus.c4
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-dvbt.c4
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-m135a.c4
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c2
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia.c4
-rw-r--r--drivers/media/rc/keymaps/rc-avertv-303.c4
-rw-r--r--drivers/media/rc/keymaps/rc-behold-columbus.c4
-rw-r--r--drivers/media/rc/keymaps/rc-behold.c4
-rw-r--r--drivers/media/rc/keymaps/rc-budget-ci-old.c4
-rw-r--r--drivers/media/rc/keymaps/rc-cinergy-1400.c4
-rw-r--r--drivers/media/rc/keymaps/rc-cinergy.c4
-rw-r--r--drivers/media/rc/keymaps/rc-dib0700-nec.c4
-rw-r--r--drivers/media/rc/keymaps/rc-dib0700-rc5.c4
-rw-r--r--drivers/media/rc/keymaps/rc-dm1105-nec.c4
-rw-r--r--drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c4
-rw-r--r--drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c4
-rw-r--r--drivers/media/rc/keymaps/rc-em-terratec.c4
-rw-r--r--drivers/media/rc/keymaps/rc-encore-enltv-fm53.c4
-rw-r--r--drivers/media/rc/keymaps/rc-encore-enltv.c4
-rw-r--r--drivers/media/rc/keymaps/rc-encore-enltv2.c4
-rw-r--r--drivers/media/rc/keymaps/rc-evga-indtube.c4
-rw-r--r--drivers/media/rc/keymaps/rc-eztv.c4
-rw-r--r--drivers/media/rc/keymaps/rc-flydvb.c4
-rw-r--r--drivers/media/rc/keymaps/rc-flyvideo.c4
-rw-r--r--drivers/media/rc/keymaps/rc-fusionhdtv-mce.c4
-rw-r--r--drivers/media/rc/keymaps/rc-gadmei-rm008z.c4
-rw-r--r--drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c4
-rw-r--r--drivers/media/rc/keymaps/rc-gotview7135.c4
-rw-r--r--drivers/media/rc/keymaps/rc-hauppauge.c4
-rw-r--r--drivers/media/rc/keymaps/rc-iodata-bctv7e.c4
-rw-r--r--drivers/media/rc/keymaps/rc-kaiomy.c4
-rw-r--r--drivers/media/rc/keymaps/rc-kworld-315u.c4
-rw-r--r--drivers/media/rc/keymaps/rc-kworld-pc150u.c2
-rw-r--r--drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c4
-rw-r--r--drivers/media/rc/keymaps/rc-manli.c4
-rw-r--r--drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c4
-rw-r--r--drivers/media/rc/keymaps/rc-msi-tvanywhere.c4
-rw-r--r--drivers/media/rc/keymaps/rc-nebula.c4
-rw-r--r--drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c6
-rw-r--r--drivers/media/rc/keymaps/rc-norwood.c4
-rw-r--r--drivers/media/rc/keymaps/rc-npgtech.c4
-rw-r--r--drivers/media/rc/keymaps/rc-pctv-sedna.c4
-rw-r--r--drivers/media/rc/keymaps/rc-pinnacle-color.c4
-rw-r--r--drivers/media/rc/keymaps/rc-pinnacle-grey.c4
-rw-r--r--drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c4
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview-002t.c4
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview-mk12.c4
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview-new.c4
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview.c4
-rw-r--r--drivers/media/rc/keymaps/rc-powercolor-real-angel.c4
-rw-r--r--drivers/media/rc/keymaps/rc-proteus-2309.c4
-rw-r--r--drivers/media/rc/keymaps/rc-purpletv.c4
-rw-r--r--drivers/media/rc/keymaps/rc-pv951.c4
-rw-r--r--drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c4
-rw-r--r--drivers/media/rc/keymaps/rc-tbs-nec.c4
-rw-r--r--drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c4
-rw-r--r--drivers/media/rc/keymaps/rc-tevii-nec.c4
-rw-r--r--drivers/media/rc/keymaps/rc-tivo.c86
-rw-r--r--drivers/media/rc/keymaps/rc-tt-1500.c4
-rw-r--r--drivers/media/rc/keymaps/rc-videomate-s350.c4
-rw-r--r--drivers/media/rc/keymaps/rc-videomate-tv-pvr.c4
-rw-r--r--drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c4
-rw-r--r--drivers/media/rc/keymaps/rc-winfast.c4
-rw-r--r--drivers/media/rc/mceusb.c184
-rw-r--r--drivers/media/rc/nuvoton-cir.c12
-rw-r--r--drivers/media/rc/nuvoton-cir.h1
-rw-r--r--drivers/media/rc/rc-core-priv.h15
-rw-r--r--drivers/media/rc/rc-loopback.c2
-rw-r--r--drivers/media/rc/rc-main.c253
-rw-r--r--drivers/media/rc/redrat3.c2
-rw-r--r--drivers/media/rc/st_rc.c2
-rw-r--r--drivers/media/rc/streamzap.c2
-rw-r--r--drivers/media/rc/ttusbir.c2
-rw-r--r--drivers/media/rc/winbond-cir.c2
-rw-r--r--drivers/media/tuners/Kconfig1
-rw-r--r--drivers/media/tuners/e4000.c608
-rw-r--r--drivers/media/tuners/e4000.h21
-rw-r--r--drivers/media/tuners/e4000_priv.h88
-rw-r--r--drivers/media/tuners/mt2063.c4
-rw-r--r--drivers/media/tuners/r820t.c4
-rw-r--r--drivers/media/tuners/tda18212.c12
-rw-r--r--drivers/media/tuners/tda18212.h2
-rw-r--r--drivers/media/tuners/tuner-xc2028.c3
-rw-r--r--drivers/media/usb/au0828/au0828-cards.c23
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-audio.c5
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-input.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/Kconfig9
-rw-r--r--drivers/media/usb/dvb-usb-v2/Makefile4
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.c102
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.h2
-rw-r--r--drivers/media/usb/dvb-usb-v2/az6007.c4
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_core.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/it913x.c828
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c123
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.h2
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-remote.c2
-rw-r--r--drivers/media/usb/em28xx/Kconfig2
-rw-r--r--drivers/media/usb/em28xx/em28xx-audio.c108
-rw-r--r--drivers/media/usb/em28xx/em28xx-camera.c4
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c129
-rw-r--r--drivers/media/usb/em28xx/em28xx-core.c54
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c193
-rw-r--r--drivers/media/usb/em28xx/em28xx-i2c.c41
-rw-r--r--drivers/media/usb/em28xx/em28xx-input.c55
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c56
-rw-r--r--drivers/media/usb/em28xx/em28xx.h15
-rw-r--r--drivers/media/usb/gspca/kinect.c7
-rw-r--r--drivers/media/usb/gspca/sn9c20x.c1
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c2
-rw-r--r--drivers/media/usb/gspca/topro.c10
-rw-r--r--drivers/media/usb/pwc/pwc-if.c19
-rw-r--r--drivers/media/usb/s2255/Kconfig2
-rw-r--r--drivers/media/usb/s2255/s2255drv.c1271
-rw-r--r--drivers/media/usb/siano/smsusb.c2
-rw-r--r--drivers/media/usb/stk1160/stk1160-ac97.c6
-rw-r--r--drivers/media/usb/stk1160/stk1160-v4l.c2
-rw-r--r--drivers/media/usb/tlg2300/pd-alsa.c3
-rw-r--r--drivers/media/usb/tm6000/tm6000-alsa.c8
-rw-r--r--drivers/media/usb/tm6000/tm6000-dvb.c2
-rw-r--r--drivers/media/usb/tm6000/tm6000-input.c2
-rw-r--r--drivers/media/usb/tm6000/tm6000-stds.c2
-rw-r--r--drivers/media/usb/usbtv/Makefile3
-rw-r--r--drivers/media/usb/usbtv/usbtv-core.c134
-rw-r--r--drivers/media/usb/usbtv/usbtv-video.c (renamed from drivers/media/usb/usbtv/usbtv.c)171
-rw-r--r--drivers/media/usb/usbtv/usbtv.h99
-rw-r--r--drivers/media/usb/usbvision/usbvision.h8
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c24
-rw-r--r--drivers/media/usb/uvc/uvc_queue.c29
-rw-r--r--drivers/media/usb/uvc/uvc_v4l2.c11
-rw-r--r--drivers/media/usb/uvc/uvc_video.c23
-rw-r--r--drivers/media/usb/uvc/uvcvideo.h16
-rw-r--r--drivers/media/v4l2-core/v4l2-compat-ioctl32.c135
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c33
-rw-r--r--drivers/media/v4l2-core/v4l2-dev.c32
-rw-r--r--drivers/media/v4l2-core/v4l2-dv-timings.c8
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c91
-rw-r--r--drivers/media/v4l2-core/v4l2-of.c133
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c18
-rw-r--r--drivers/media/v4l2-core/videobuf2-core.c658
-rw-r--r--drivers/media/v4l2-core/videobuf2-dma-contig.c2
-rw-r--r--drivers/memory/Kconfig15
-rw-r--r--drivers/memory/Makefile2
-rw-r--r--drivers/memory/fsl_ifc.c (renamed from arch/powerpc/sysdev/fsl_ifc.c)8
-rw-r--r--drivers/memory/ti-aemif.c427
-rw-r--r--drivers/message/i2o/i2o_config.c4
-rw-r--r--drivers/message/i2o/iop.c85
-rw-r--r--drivers/mfd/arizona-core.c4
-rw-r--r--drivers/mfd/da9055-i2c.c12
-rw-r--r--drivers/mfd/max14577.c2
-rw-r--r--drivers/mfd/max8997.c6
-rw-r--r--drivers/mfd/max8998.c6
-rw-r--r--drivers/mfd/sec-core.c114
-rw-r--r--drivers/mfd/sec-irq.c97
-rw-r--r--drivers/mfd/tps65217.c4
-rw-r--r--drivers/mfd/wm5102-tables.c21
-rw-r--r--drivers/mfd/wm8994-core.c2
-rw-r--r--drivers/misc/Kconfig3
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/ad525x_dpot.c1
-rw-r--r--drivers/misc/apds9802als.c1
-rw-r--r--drivers/misc/atmel-ssc.c6
-rw-r--r--drivers/misc/bmp085.c1
-rw-r--r--drivers/misc/carma/carma-fpga.c1
-rw-r--r--drivers/misc/ds1682.c1
-rw-r--r--drivers/misc/echo/Kconfig (renamed from drivers/staging/echo/Kconfig)0
-rw-r--r--drivers/misc/echo/Makefile (renamed from drivers/staging/echo/Makefile)0
-rw-r--r--drivers/misc/echo/echo.c (renamed from drivers/staging/echo/echo.c)0
-rw-r--r--drivers/misc/echo/echo.h (renamed from drivers/staging/echo/echo.h)0
-rw-r--r--drivers/misc/echo/fir.h (renamed from drivers/staging/echo/fir.h)0
-rw-r--r--drivers/misc/echo/oslec.h (renamed from drivers/staging/echo/oslec.h)0
-rw-r--r--drivers/misc/eeprom/at25.c1
-rw-r--r--drivers/misc/eeprom/eeprom.c1
-rw-r--r--drivers/misc/eeprom/eeprom_93xx46.c1
-rw-r--r--drivers/misc/eeprom/max6875.c1
-rw-r--r--drivers/misc/eeprom/sunxi_sid.c3
-rw-r--r--drivers/misc/genwqe/card_debugfs.c1
-rw-r--r--drivers/misc/genwqe/card_dev.c1
-rw-r--r--drivers/misc/hmc6352.c1
-rw-r--r--drivers/misc/isl29003.c1
-rw-r--r--drivers/misc/isl29020.c1
-rw-r--r--drivers/misc/lattice-ecp3-config.c1
-rw-r--r--drivers/misc/lis3lv02d/lis3lv02d.c1
-rw-r--r--drivers/misc/lis3lv02d/lis3lv02d_i2c.c1
-rw-r--r--drivers/misc/lis3lv02d/lis3lv02d_spi.c1
-rw-r--r--drivers/misc/lkdtm.c74
-rw-r--r--drivers/misc/mei/Kconfig9
-rw-r--r--drivers/misc/mei/Makefile6
-rw-r--r--drivers/misc/mei/amthif.c72
-rw-r--r--drivers/misc/mei/bus.c21
-rw-r--r--drivers/misc/mei/client.c297
-rw-r--r--drivers/misc/mei/client.h30
-rw-r--r--drivers/misc/mei/debugfs.c54
-rw-r--r--drivers/misc/mei/hbm.c281
-rw-r--r--drivers/misc/mei/hbm.h1
-rw-r--r--drivers/misc/mei/hw-me.c30
-rw-r--r--drivers/misc/mei/hw-me.h1
-rw-r--r--drivers/misc/mei/hw-txe-regs.h294
-rw-r--r--drivers/misc/mei/hw-txe.c1107
-rw-r--r--drivers/misc/mei/hw-txe.h74
-rw-r--r--drivers/misc/mei/hw.h20
-rw-r--r--drivers/misc/mei/init.c43
-rw-r--r--drivers/misc/mei/interrupt.c159
-rw-r--r--drivers/misc/mei/main.c23
-rw-r--r--drivers/misc/mei/mei_dev.h54
-rw-r--r--drivers/misc/mei/nfc.c14
-rw-r--r--drivers/misc/mei/pci-me.c14
-rw-r--r--drivers/misc/mei/pci-txe.c293
-rw-r--r--drivers/misc/mei/wd.c136
-rw-r--r--drivers/misc/mic/Kconfig2
-rw-r--r--drivers/misc/mic/card/mic_device.h1
-rw-r--r--drivers/misc/mic/host/mic_device.h1
-rw-r--r--drivers/misc/mic/host/mic_intr.c2
-rw-r--r--drivers/misc/mic/host/mic_virtio.c3
-rw-r--r--drivers/misc/pch_phub.c5
-rw-r--r--drivers/misc/sgi-gru/grukdump.c11
-rw-r--r--drivers/misc/sgi-xp/xpc_uv.c2
-rw-r--r--drivers/misc/sram.c127
-rw-r--r--drivers/misc/ti-st/st_core.c1
-rw-r--r--drivers/misc/ti_dac7512.c1
-rw-r--r--drivers/misc/tsl2550.c1
-rw-r--r--drivers/misc/vmw_vmci/vmci_guest.c7
-rw-r--r--drivers/mmc/card/queue.c2
-rw-r--r--drivers/mmc/core/host.c2
-rw-r--r--drivers/mmc/host/dw_mmc.c2
-rw-r--r--drivers/mtd/nand/Kconfig1
-rw-r--r--drivers/mtd/nand/fsl_ifc_nand.c2
-rw-r--r--drivers/mtd/nand/nand_base.c2
-rw-r--r--drivers/mtd/nand/omap2.c61
-rw-r--r--drivers/mtd/nand/sh_flctl.c2
-rw-r--r--drivers/mtd/ubi/Kconfig16
-rw-r--r--drivers/mtd/ubi/Makefile1
-rw-r--r--drivers/mtd/ubi/block.c647
-rw-r--r--drivers/mtd/ubi/build.c11
-rw-r--r--drivers/mtd/ubi/cdev.c20
-rw-r--r--drivers/mtd/ubi/fastmap.c8
-rw-r--r--drivers/mtd/ubi/ubi.h20
-rw-r--r--drivers/net/Kconfig7
-rw-r--r--drivers/net/bonding/bond_3ad.c96
-rw-r--r--drivers/net/bonding/bond_3ad.h176
-rw-r--r--drivers/net/bonding/bond_alb.c140
-rw-r--r--drivers/net/bonding/bond_debugfs.c10
-rw-r--r--drivers/net/bonding/bond_main.c621
-rw-r--r--drivers/net/bonding/bond_netlink.c8
-rw-r--r--drivers/net/bonding/bond_options.c331
-rw-r--r--drivers/net/bonding/bond_options.h62
-rw-r--r--drivers/net/bonding/bond_procfs.c14
-rw-r--r--drivers/net/bonding/bond_sysfs.c24
-rw-r--r--drivers/net/bonding/bonding.h86
-rw-r--r--drivers/net/caif/caif_serial.c1
-rw-r--r--drivers/net/caif/caif_spi.c1
-rw-r--r--drivers/net/can/Kconfig2
-rw-r--r--drivers/net/can/at91_can.c10
-rw-r--r--drivers/net/can/bfin_can.c1
-rw-r--r--drivers/net/can/c_can/c_can.c349
-rw-r--r--drivers/net/can/c_can/c_can.h29
-rw-r--r--drivers/net/can/c_can/c_can_platform.c47
-rw-r--r--drivers/net/can/cc770/cc770.c1
-rw-r--r--drivers/net/can/dev.c198
-rw-r--r--drivers/net/can/flexcan.c190
-rw-r--r--drivers/net/can/grcan.c1
-rw-r--r--drivers/net/can/janz-ican3.c85
-rw-r--r--drivers/net/can/mcp251x.c22
-rw-r--r--drivers/net/can/mscan/mscan.c7
-rw-r--r--drivers/net/can/pch_can.c1
-rw-r--r--drivers/net/can/sja1000/Kconfig13
-rw-r--r--drivers/net/can/sja1000/Makefile1
-rw-r--r--drivers/net/can/sja1000/ems_pci.c1
-rw-r--r--drivers/net/can/sja1000/ems_pcmcia.c1
-rw-r--r--drivers/net/can/sja1000/kvaser_pci.c1
-rw-r--r--drivers/net/can/sja1000/peak_pci.c1
-rw-r--r--drivers/net/can/sja1000/peak_pcmcia.c1
-rw-r--r--drivers/net/can/sja1000/plx_pci.c1
-rw-r--r--drivers/net/can/sja1000/sja1000.c10
-rw-r--r--drivers/net/can/sja1000/sja1000_of_platform.c220
-rw-r--r--drivers/net/can/sja1000/sja1000_platform.c194
-rw-r--r--drivers/net/can/slcan.c6
-rw-r--r--drivers/net/can/softing/softing_main.c2
-rw-r--r--drivers/net/can/ti_hecc.c1
-rw-r--r--drivers/net/can/usb/ems_usb.c1
-rw-r--r--drivers/net/can/usb/esd_usb2.c2
-rw-r--r--drivers/net/can/usb/kvaser_usb.c4
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_core.c2
-rw-r--r--drivers/net/can/usb/usb_8dev.c3
-rw-r--r--drivers/net/can/vcan.c9
-rw-r--r--drivers/net/dummy.c12
-rw-r--r--drivers/net/ethernet/3com/3c509.c2
-rw-r--r--drivers/net/ethernet/3com/3c589_cs.c1127
-rw-r--r--drivers/net/ethernet/3com/3c59x.c4
-rw-r--r--drivers/net/ethernet/8390/lib8390.c2
-rw-r--r--drivers/net/ethernet/Kconfig2
-rw-r--r--drivers/net/ethernet/Makefile2
-rw-r--r--drivers/net/ethernet/adi/bfin_mac.c9
-rw-r--r--drivers/net/ethernet/aeroflex/greth.c6
-rw-r--r--drivers/net/ethernet/allwinner/sun4i-emac.c5
-rw-r--r--drivers/net/ethernet/altera/Kconfig8
-rw-r--r--drivers/net/ethernet/altera/Makefile7
-rw-r--r--drivers/net/ethernet/altera/altera_msgdma.c202
-rw-r--r--drivers/net/ethernet/altera/altera_msgdma.h34
-rw-r--r--drivers/net/ethernet/altera/altera_msgdmahw.h167
-rw-r--r--drivers/net/ethernet/altera/altera_sgdma.c509
-rw-r--r--drivers/net/ethernet/altera/altera_sgdma.h35
-rw-r--r--drivers/net/ethernet/altera/altera_sgdmahw.h124
-rw-r--r--drivers/net/ethernet/altera/altera_tse.h486
-rw-r--r--drivers/net/ethernet/altera/altera_tse_ethtool.c235
-rw-r--r--drivers/net/ethernet/altera/altera_tse_main.c1543
-rw-r--r--drivers/net/ethernet/altera/altera_utils.c44
-rw-r--r--drivers/net/ethernet/altera/altera_utils.h27
-rw-r--r--drivers/net/ethernet/amd/7990.c2
-rw-r--r--drivers/net/ethernet/amd/am79c961a.c2
-rw-r--r--drivers/net/ethernet/amd/amd8111e.c3
-rw-r--r--drivers/net/ethernet/amd/pcnet32.c124
-rw-r--r--drivers/net/ethernet/atheros/alx/main.c19
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_main.c34
-rw-r--r--drivers/net/ethernet/atheros/atl1e/atl1e_main.c18
-rw-r--r--drivers/net/ethernet/atheros/atlx/atl1.c15
-rw-r--r--drivers/net/ethernet/atheros/atlx/atl2.c10
-rw-r--r--drivers/net/ethernet/broadcom/Kconfig11
-rw-r--r--drivers/net/ethernet/broadcom/Makefile1
-rw-r--r--drivers/net/ethernet/broadcom/b44.c22
-rw-r--r--drivers/net/ethernet/broadcom/bcm63xx_enet.c3
-rw-r--r--drivers/net/ethernet/broadcom/bnx2.c63
-rw-r--r--drivers/net/ethernet/broadcom/bnx2.h5
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x.h45
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c175
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h52
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c8
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c11
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h1
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h31
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c397
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c155
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h21
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c1882
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h368
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c619
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h22
-rw-r--r--drivers/net/ethernet/broadcom/cnic.c111
-rw-r--r--drivers/net/ethernet/broadcom/cnic.h2
-rw-r--r--drivers/net/ethernet/broadcom/cnic_defs.h2
-rw-r--r--drivers/net/ethernet/broadcom/cnic_if.h16
-rw-r--r--drivers/net/ethernet/broadcom/genet/Makefile2
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.c2584
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.h628
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmmii.c464
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c55
-rw-r--r--drivers/net/ethernet/broadcom/tg3.h6
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc.c2
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.c105
-rw-r--r--drivers/net/ethernet/cadence/macb.c22
-rw-r--r--drivers/net/ethernet/calxeda/xgmac.c6
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c26
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/sge.c6
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4.h16
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c231
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h1
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/sge.c172
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.c152
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_msg.h1
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_regs.h9
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h4
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c43
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/sge.c6
-rw-r--r--drivers/net/ethernet/cirrus/cs89x0.c2
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_main.c24
-rw-r--r--drivers/net/ethernet/davicom/dm9000.c2
-rw-r--r--drivers/net/ethernet/dec/tulip/dmfe.c4
-rw-r--r--drivers/net/ethernet/dec/tulip/tulip_core.c1
-rw-r--r--drivers/net/ethernet/dec/tulip/uli526x.c4
-rw-r--r--drivers/net/ethernet/dlink/sundance.c2
-rw-r--r--drivers/net/ethernet/dnet.c6
-rw-r--r--drivers/net/ethernet/emulex/benet/Kconfig8
-rw-r--r--drivers/net/ethernet/emulex/benet/be.h31
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.c213
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.h97
-rw-r--r--drivers/net/ethernet/emulex/benet/be_ethtool.c30
-rw-r--r--drivers/net/ethernet/emulex/benet/be_hw.h9
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c551
-rw-r--r--drivers/net/ethernet/emulex/benet/be_roce.c8
-rw-r--r--drivers/net/ethernet/emulex/benet/be_roce.h5
-rw-r--r--drivers/net/ethernet/ethoc.c144
-rw-r--r--drivers/net/ethernet/faraday/ftgmac100.c6
-rw-r--r--drivers/net/ethernet/freescale/Makefile3
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c50
-rw-r--r--drivers/net/ethernet/freescale/fec_ptp.c1
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c3
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/mii-fec.c7
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c1327
-rw-r--r--drivers/net/ethernet/freescale/gianfar.h114
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ethtool.c165
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ptp.c1
-rw-r--r--drivers/net/ethernet/freescale/gianfar_sysfs.c340
-rw-r--r--drivers/net/ethernet/freescale/ucc_geth.c2
-rw-r--r--drivers/net/ethernet/i825xx/lib82596.c2
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_main.c6
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c31
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.h1
-rw-r--r--drivers/net/ethernet/intel/e100.c6
-rw-r--r--drivers/net/ethernet/intel/e1000e/80003es2lan.c47
-rw-r--r--drivers/net/ethernet/intel/e1000e/80003es2lan.h47
-rw-r--r--drivers/net/ethernet/intel/e1000e/82571.c47
-rw-r--r--drivers/net/ethernet/intel/e1000e/82571.h47
-rw-r--r--drivers/net/ethernet/intel/e1000e/Makefile7
-rw-r--r--drivers/net/ethernet/intel/e1000e/defines.h55
-rw-r--r--drivers/net/ethernet/intel/e1000e/e1000.h52
-rw-r--r--drivers/net/ethernet/intel/e1000e/ethtool.c64
-rw-r--r--drivers/net/ethernet/intel/e1000e/hw.h55
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.c427
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.h72
-rw-r--r--drivers/net/ethernet/intel/e1000e/mac.c47
-rw-r--r--drivers/net/ethernet/intel/e1000e/mac.h47
-rw-r--r--drivers/net/ethernet/intel/e1000e/manage.c47
-rw-r--r--drivers/net/ethernet/intel/e1000e/manage.h47
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c373
-rw-r--r--drivers/net/ethernet/intel/e1000e/nvm.c47
-rw-r--r--drivers/net/ethernet/intel/e1000e/nvm.h47
-rw-r--r--drivers/net/ethernet/intel/e1000e/param.c53
-rw-r--r--drivers/net/ethernet/intel/e1000e/phy.c47
-rw-r--r--drivers/net/ethernet/intel/e1000e/phy.h47
-rw-r--r--drivers/net/ethernet/intel/e1000e/ptp.c53
-rw-r--r--drivers/net/ethernet/intel/e1000e/regs.h48
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e.h50
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_adminq.c5
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_common.c370
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_dcb.c9
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_debugfs.c87
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ethtool.c476
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_main.c546
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_nvm.c117
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_prototype.h7
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.c434
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_type.h12
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c135
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h5
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h2
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_common.c369
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_prototype.h7
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_txrx.c90
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_type.h16
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40evf.h48
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c13
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40evf_main.c299
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c27
-rw-r--r--drivers/net/ethernet/intel/igb/Makefile5
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_82575.c15
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_82575.h12
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_defines.h75
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_hw.h5
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_i210.c25
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_i210.h14
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mac.c5
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mac.h5
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mbx.c5
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mbx.h5
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_nvm.c5
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_nvm.h5
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_phy.c76
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_phy.h6
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_regs.h36
-rw-r--r--drivers/net/ethernet/intel/igb/igb.h18
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ethtool.c76
-rw-r--r--drivers/net/ethernet/intel/igb/igb_hwmon.c5
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c170
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ptp.c64
-rw-r--r--drivers/net/ethernet/intel/igbvf/netdev.c10
-rw-r--r--drivers/net/ethernet/intel/ixgb/ixgb_main.c6
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe.h9
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c33
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c360
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_common.c200
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_common.h14
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c18
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c11
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c17
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c218
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c45
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h8
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c39
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_type.h29
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c6
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ethtool.c141
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ixgbevf.h12
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c161
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/regs.h12
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/vf.h33
-rw-r--r--drivers/net/ethernet/jme.c16
-rw-r--r--drivers/net/ethernet/lantiq_etop.c2
-rw-r--r--drivers/net/ethernet/marvell/Kconfig6
-rw-r--r--drivers/net/ethernet/marvell/mv643xx_eth.c4
-rw-r--r--drivers/net/ethernet/marvell/mvmdio.c6
-rw-r--r--drivers/net/ethernet/marvell/mvneta.c70
-rw-r--r--drivers/net/ethernet/marvell/skge.c4
-rw-r--r--drivers/net/ethernet/marvell/sky2.c28
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/Kconfig9
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/cmd.c179
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_clock.c1
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_main.c45
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c138
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_port.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_rx.c28
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_selftest.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_tx.c44
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/eq.c48
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/fw.c119
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c186
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mcg.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4.h18
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h25
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/port.c267
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/resource_tracker.c289
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/Kconfig2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/main.c22
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/mr.c85
-rw-r--r--drivers/net/ethernet/micrel/ks8851.c30
-rw-r--r--drivers/net/ethernet/micrel/ksz884x.c2
-rw-r--r--drivers/net/ethernet/myricom/myri10ge/myri10ge.c40
-rw-r--r--drivers/net/ethernet/neterion/s2io.c14
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-main.c41
-rw-r--r--drivers/net/ethernet/nvidia/forcedeth.c57
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c11
-rw-r--r--drivers/net/ethernet/qlogic/Kconfig10
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c5
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic.h121
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c11
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h11
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c91
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c4
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c23
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c22
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h9
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c179
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c90
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c233
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c15
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c102
-rw-r--r--drivers/net/ethernet/qlogic/qlge/qlge_main.c29
-rw-r--r--drivers/net/ethernet/rdc/r6040.c6
-rw-r--r--drivers/net/ethernet/realtek/8139cp.c7
-rw-r--r--drivers/net/ethernet/realtek/8139too.c12
-rw-r--r--drivers/net/ethernet/realtek/r8169.c18
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.c271
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.h3
-rw-r--r--drivers/net/ethernet/samsung/Kconfig16
-rw-r--r--drivers/net/ethernet/samsung/Makefile5
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/Kconfig9
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/Makefile4
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h535
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c262
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.c515
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.h298
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.c382
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.h50
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c524
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c2317
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_mdio.c244
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.c254
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.h104
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c259
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h488
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_xpcs.c91
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_xpcs.h38
-rw-r--r--drivers/net/ethernet/sfc/ef10.c27
-rw-r--r--drivers/net/ethernet/sfc/ef10_regs.h61
-rw-r--r--drivers/net/ethernet/sfc/efx.c33
-rw-r--r--drivers/net/ethernet/sfc/efx.h2
-rw-r--r--drivers/net/ethernet/sfc/ethtool.c39
-rw-r--r--drivers/net/ethernet/sfc/falcon.c6
-rw-r--r--drivers/net/ethernet/sfc/farch.c5
-rw-r--r--drivers/net/ethernet/sfc/filter.h2
-rw-r--r--drivers/net/ethernet/sfc/mcdi.c14
-rw-r--r--drivers/net/ethernet/sfc/mcdi_port.c4
-rw-r--r--drivers/net/ethernet/sfc/net_driver.h1
-rw-r--r--drivers/net/ethernet/sfc/nic.c1
-rw-r--r--drivers/net/ethernet/sfc/ptp.c100
-rw-r--r--drivers/net/ethernet/sfc/selftest.c6
-rw-r--r--drivers/net/ethernet/sfc/siena_sriov.c13
-rw-r--r--drivers/net/ethernet/sfc/tx.c23
-rw-r--r--drivers/net/ethernet/silan/sc92031.c2
-rw-r--r--drivers/net/ethernet/sis/sis900.c2
-rw-r--r--drivers/net/ethernet/smsc/smc911x.c2
-rw-r--r--drivers/net/ethernet/smsc/smc91x.c4
-rw-r--r--drivers/net/ethernet/smsc/smsc911x.c7
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Kconfig21
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/chain_mode.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h20
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c130
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c330
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/ring_mode.c9
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h6
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c95
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c8
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c1
-rw-r--r--drivers/net/ethernet/sun/niu.c11
-rw-r--r--drivers/net/ethernet/sun/sungem.c2
-rw-r--r--drivers/net/ethernet/ti/cpsw.c69
-rw-r--r--drivers/net/ethernet/ti/cpts.c11
-rw-r--r--drivers/net/ethernet/ti/davinci_cpdma.c4
-rw-r--r--drivers/net/ethernet/ti/davinci_emac.c53
-rw-r--r--drivers/net/ethernet/tile/tilegx.c6
-rw-r--r--drivers/net/ethernet/tile/tilepro.c11
-rw-r--r--drivers/net/ethernet/toshiba/spider_net.c2
-rw-r--r--drivers/net/ethernet/toshiba/tc35815.c3
-rw-r--r--drivers/net/ethernet/via/via-rhine.c24
-rw-r--r--drivers/net/ethernet/via/via-velocity.c2
-rw-r--r--drivers/net/ethernet/wiznet/w5100.c9
-rw-r--r--drivers/net/ethernet/wiznet/w5300.c9
-rw-r--r--drivers/net/ethernet/xilinx/ll_temac_main.c4
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_main.c15
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_emaclite.c15
-rw-r--r--drivers/net/ethernet/xscale/Kconfig1
-rw-r--r--drivers/net/ethernet/xscale/ixp4xx_eth.c11
-rw-r--r--drivers/net/hamradio/yam.c2
-rw-r--r--drivers/net/hyperv/hyperv_net.h207
-rw-r--r--drivers/net/hyperv/netvsc.c93
-rw-r--r--drivers/net/hyperv/netvsc_drv.c390
-rw-r--r--drivers/net/hyperv/rndis_filter.c208
-rw-r--r--drivers/net/ieee802154/Kconfig34
-rw-r--r--drivers/net/ieee802154/at86rf230.c531
-rw-r--r--drivers/net/ieee802154/fakehard.c22
-rw-r--r--drivers/net/ieee802154/mrf24j40.c17
-rw-r--r--drivers/net/ifb.c11
-rw-r--r--drivers/net/irda/Kconfig7
-rw-r--r--drivers/net/irda/Makefile1
-rw-r--r--drivers/net/irda/ep7211-sir.c70
-rw-r--r--drivers/net/irda/irtty-sir.c1
-rw-r--r--drivers/net/loopback.c16
-rw-r--r--drivers/net/macvlan.c25
-rw-r--r--drivers/net/nlmon.c18
-rw-r--r--drivers/net/phy/Kconfig6
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/at803x.c30
-rw-r--r--drivers/net/phy/bcm7xxx.c359
-rw-r--r--drivers/net/phy/broadcom.c52
-rw-r--r--drivers/net/phy/dp83640.c126
-rw-r--r--drivers/net/phy/mdio-sun4i.c9
-rw-r--r--drivers/net/phy/mdio_bus.c20
-rw-r--r--drivers/net/phy/micrel.c49
-rw-r--r--drivers/net/phy/phy.c62
-rw-r--r--drivers/net/phy/phy_device.c114
-rw-r--r--drivers/net/ppp/ppp_generic.c60
-rw-r--r--drivers/net/team/team.c30
-rw-r--r--drivers/net/team/team_mode_loadbalance.c4
-rw-r--r--drivers/net/tun.c14
-rw-r--r--drivers/net/usb/Kconfig15
-rw-r--r--drivers/net/usb/Makefile3
-rw-r--r--drivers/net/usb/asix_devices.c3
-rw-r--r--drivers/net/usb/ax88179_178a.c46
-rw-r--r--drivers/net/usb/cdc_ether.c14
-rw-r--r--drivers/net/usb/cdc_ncm.c65
-rw-r--r--drivers/net/usb/gl620a.c4
-rw-r--r--drivers/net/usb/hso.c32
-rw-r--r--drivers/net/usb/lg-vl600.c2
-rw-r--r--drivers/net/usb/mcs7830.c5
-rw-r--r--drivers/net/usb/net1080.c4
-rw-r--r--drivers/net/usb/qmi_wwan.c18
-rw-r--r--drivers/net/usb/r8152.c1148
-rw-r--r--drivers/net/usb/r815x.c248
-rw-r--r--drivers/net/usb/rndis_host.c4
-rw-r--r--drivers/net/usb/smsc75xx.c4
-rw-r--r--drivers/net/usb/smsc95xx.c4
-rw-r--r--drivers/net/usb/sr9800.c874
-rw-r--r--drivers/net/usb/sr9800.h202
-rw-r--r--drivers/net/usb/usbnet.c58
-rw-r--r--drivers/net/veth.c29
-rw-r--r--drivers/net/virtio_net.c21
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c131
-rw-r--r--drivers/net/vxlan.c146
-rw-r--r--drivers/net/wan/dlci.c5
-rw-r--r--drivers/net/wimax/i2400m/netdev.c3
-rw-r--r--drivers/net/wireless/Kconfig11
-rw-r--r--drivers/net/wireless/Makefile1
-rw-r--r--drivers/net/wireless/airo.c17
-rw-r--r--drivers/net/wireless/ath/ar5523/ar5523.c2
-rw-r--r--drivers/net/wireless/ath/ath.h15
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.c16
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.h9
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c36
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h81
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.h2
-rw-r--r--drivers/net/wireless/ath/ath10k/hif.h25
-rw-r--r--drivers/net/wireless/ath/ath10k/htc.c25
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.h18
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c269
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_tx.c205
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h6
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c850
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c536
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.h28
-rw-r--r--drivers/net/wireless/ath/ath10k/txrx.c32
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c132
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h34
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c3
-rw-r--r--drivers/net/wireless/ath/ath5k/mac80211-ops.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c2
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c27
-rw-r--r--drivers/net/wireless/ath/ath6kl/usb.c6
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/Kconfig12
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile5
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c11
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.c52
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_phy.c85
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_calib.c235
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.c67
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h35
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c203
-rw-r--r--drivers/net/wireless/ath/ath9k/common-beacon.c180
-rw-r--r--drivers/net/wireless/ath/ath9k/common-beacon.h26
-rw-r--r--drivers/net/wireless/ath/ath9k/common-init.c244
-rw-r--r--drivers/net/wireless/ath/ath9k/common-init.h20
-rw-r--r--drivers/net/wireless/ath/ath9k/common.c244
-rw-r--r--drivers/net/wireless/ath/ath9k/common.h35
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c86
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_debug.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h29
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_beacon.c260
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c246
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c117
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c179
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_hst.c36
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_hst.h12
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c16
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c255
-rw-r--r--drivers/net/wireless/ath/ath9k/link.c16
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h9
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c69
-rw-r--r--drivers/net/wireless/ath/ath9k/mci.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c1495
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.h248
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c329
-rw-r--r--drivers/net/wireless/ath/ath9k/tx99.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/wow.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c33
-rw-r--r--drivers/net/wireless/ath/carl9170/rx.c2
-rw-r--r--drivers/net/wireless/ath/regd.c10
-rw-r--r--drivers/net/wireless/ath/wcn36xx/dxe.c10
-rw-r--r--drivers/net/wireless/ath/wcn36xx/dxe.h4
-rw-r--r--drivers/net/wireless/ath/wcn36xx/hal.h4
-rw-r--r--drivers/net/wireless/ath/wcn36xx/main.c72
-rw-r--r--drivers/net/wireless/ath/wcn36xx/smd.c64
-rw-r--r--drivers/net/wireless/ath/wcn36xx/smd.h5
-rw-r--r--drivers/net/wireless/ath/wcn36xx/txrx.c7
-rw-r--r--drivers/net/wireless/ath/wcn36xx/wcn36xx.h10
-rw-r--r--drivers/net/wireless/ath/wil6210/Makefile1
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c241
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c181
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c33
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c234
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c5
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c37
-rw-r--r--drivers/net/wireless/ath/wil6210/rx_reorder.c177
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c334
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.h7
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h164
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c136
-rw-r--r--drivers/net/wireless/atmel.c8
-rw-r--r--drivers/net/wireless/b43/Kconfig2
-rw-r--r--drivers/net/wireless/b43/debugfs.h2
-rw-r--r--drivers/net/wireless/b43/main.c2
-rw-r--r--drivers/net/wireless/b43/main.h35
-rw-r--r--drivers/net/wireless/b43/phy_common.c4
-rw-r--r--drivers/net/wireless/b43/pio.c10
-rw-r--r--drivers/net/wireless/b43/sysfs.c2
-rw-r--r--drivers/net/wireless/b43/xmit.c14
-rw-r--r--drivers/net/wireless/b43legacy/main.c4
-rw-r--r--drivers/net/wireless/b43legacy/sysfs.c2
-rw-r--r--drivers/net/wireless/b43legacy/xmit.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/Makefile4
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c107
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/chip.c1034
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/chip.h91
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c4
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c1000
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwil.c5
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwil.h2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h10
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/p2p.c6
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c972
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h231
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h91
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c283
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h21
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c20
-rw-r--r--drivers/net/wireless/brcm80211/include/brcm_hw_ids.h1
-rw-r--r--drivers/net/wireless/brcm80211/include/brcmu_wifi.h3
-rw-r--r--drivers/net/wireless/cw1200/fwio.c4
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_proc.c2
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.c2
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c2
-rw-r--r--drivers/net/wireless/iwlegacy/3945-mac.c13
-rw-r--r--drivers/net/wireless/iwlegacy/3945-rs.c3
-rw-r--r--drivers/net/wireless/iwlegacy/4965-mac.c15
-rw-r--r--drivers/net/wireless/iwlegacy/4965-rs.c3
-rw-r--r--drivers/net/wireless/iwlegacy/commands.h3
-rw-r--r--drivers/net/wireless/iwlegacy/common.c83
-rw-r--r--drivers/net/wireless/iwlegacy/common.h17
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig14
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/agn.h4
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/devices.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/mac80211.c24
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/main.c12
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/rs.c23
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/rs.h2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/rx.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/sta.c1
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/tx.c14
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-7000.c27
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-8000.c132
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-config.h19
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h66
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.c60
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.h14
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-file.h17
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw.h47
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.c19
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-modparams.h13
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-nvm-parse.c275
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-nvm-parse.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-op-mode.h35
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-phy-db.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h69
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h40
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/Makefile4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/coex.c (renamed from drivers/net/wireless/iwlwifi/mvm/bt-coex.c)481
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/constants.h4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c226
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c119
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs.c485
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h (renamed from drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h)21
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h14
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-power.h33
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h3
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h31
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h3
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h134
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h106
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw.c79
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/led.c2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c78
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c621
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h261
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/nvm.c87
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/offloading.c215
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c481
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/power.c426
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/power_legacy.c319
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/quota.c100
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.c210
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rx.c33
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/scan.c260
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c215
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.h62
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/time-event.c8
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tt.c7
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tx.c134
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/utils.c140
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/drv.c93
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/internal.h4
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/rx.c52
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c410
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/tx.c73
-rw-r--r--drivers/net/wireless/libertas/cfg.c5
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c4
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c113
-rw-r--r--drivers/net/wireless/mac80211_hwsim.h6
-rw-r--r--drivers/net/wireless/mwifiex/11ac.c195
-rw-r--r--drivers/net/wireless/mwifiex/11ac.h2
-rw-r--r--drivers/net/wireless/mwifiex/11h.c4
-rw-r--r--drivers/net/wireless/mwifiex/11n.c109
-rw-r--r--drivers/net/wireless/mwifiex/11n.h58
-rw-r--r--drivers/net/wireless/mwifiex/11n_rxreorder.c203
-rw-r--r--drivers/net/wireless/mwifiex/11n_rxreorder.h3
-rw-r--r--drivers/net/wireless/mwifiex/Makefile1
-rw-r--r--drivers/net/wireless/mwifiex/README2
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c403
-rw-r--r--drivers/net/wireless/mwifiex/cfp.c205
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c161
-rw-r--r--drivers/net/wireless/mwifiex/debugfs.c8
-rw-r--r--drivers/net/wireless/mwifiex/decl.h23
-rw-r--r--drivers/net/wireless/mwifiex/fw.h202
-rw-r--r--drivers/net/wireless/mwifiex/ie.c6
-rw-r--r--drivers/net/wireless/mwifiex/init.c8
-rw-r--r--drivers/net/wireless/mwifiex/ioctl.h25
-rw-r--r--drivers/net/wireless/mwifiex/join.c66
-rw-r--r--drivers/net/wireless/mwifiex/main.c12
-rw-r--r--drivers/net/wireless/mwifiex/main.h112
-rw-r--r--drivers/net/wireless/mwifiex/pcie.c214
-rw-r--r--drivers/net/wireless/mwifiex/pcie.h5
-rw-r--r--drivers/net/wireless/mwifiex/scan.c623
-rw-r--r--drivers/net/wireless/mwifiex/sdio.c11
-rw-r--r--drivers/net/wireless/mwifiex/sdio.h6
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c471
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c130
-rw-r--r--drivers/net/wireless/mwifiex/sta_event.c52
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c164
-rw-r--r--drivers/net/wireless/mwifiex/sta_rx.c34
-rw-r--r--drivers/net/wireless/mwifiex/sta_tx.c3
-rw-r--r--drivers/net/wireless/mwifiex/tdls.c1044
-rw-r--r--drivers/net/wireless/mwifiex/uap_cmd.c24
-rw-r--r--drivers/net/wireless/mwifiex/uap_event.c130
-rw-r--r--drivers/net/wireless/mwifiex/uap_txrx.c22
-rw-r--r--drivers/net/wireless/mwifiex/usb.c23
-rw-r--r--drivers/net/wireless/mwifiex/util.c118
-rw-r--r--drivers/net/wireless/mwifiex/util.h20
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c134
-rw-r--r--drivers/net/wireless/mwifiex/wmm.h18
-rw-r--r--drivers/net/wireless/mwl8k.c197
-rw-r--r--drivers/net/wireless/orinoco/cfg.c5
-rw-r--r--drivers/net/wireless/orinoco/hw.c2
-rw-r--r--drivers/net/wireless/orinoco/scan.c5
-rw-r--r--drivers/net/wireless/orinoco/wext.c2
-rw-r--r--drivers/net/wireless/p54/p54usb.c6
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c2
-rw-r--r--drivers/net/wireless/rndis_wlan.c7
-rw-r--r--drivers/net/wireless/rsi/Kconfig30
-rw-r--r--drivers/net/wireless/rsi/Makefile12
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_core.c342
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_debugfs.c339
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_mac80211.c1008
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_main.c295
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_mgmt.c1304
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_pkt.c196
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_sdio.c850
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_sdio_ops.c566
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_usb.c575
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_usb_ops.c177
-rw-r--r--drivers/net/wireless/rsi/rsi_boot_params.h126
-rw-r--r--drivers/net/wireless/rsi/rsi_common.h87
-rw-r--r--drivers/net/wireless/rsi/rsi_debugfs.h48
-rw-r--r--drivers/net/wireless/rsi/rsi_main.h218
-rw-r--r--drivers/net/wireless/rsi/rsi_mgmt.h285
-rw-r--r--drivers/net/wireless/rsi/rsi_sdio.h129
-rw-r--r--drivers/net/wireless/rsi/rsi_usb.h68
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c5
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c5
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c11
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c12
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.c2
-rw-r--r--drivers/net/wireless/rtl818x/Kconfig4
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/Makefile2
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/dev.c1030
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/rtl8180.h76
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/rtl8225.c23
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/rtl8225se.c475
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/rtl8225se.h61
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/dev.c20
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/rtl8187.h10
-rw-r--r--drivers/net/wireless/rtl818x/rtl818x.h269
-rw-r--r--drivers/net/wireless/rtlwifi/Kconfig27
-rw-r--r--drivers/net/wireless/rtlwifi/Makefile3
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/Makefile7
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h75
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c3698
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h173
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c1011
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h559
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c218
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h52
-rw-r--r--drivers/net/wireless/rtlwifi/core.c124
-rw-r--r--drivers/net/wireless/rtlwifi/core.h4
-rw-r--r--drivers/net/wireless/rtlwifi/pci.c131
-rw-r--r--drivers/net/wireless/rtlwifi/pci.h14
-rw-r--r--drivers/net/wireless/rtlwifi/ps.c121
-rw-r--r--drivers/net/wireless/rtlwifi/ps.h60
-rw-r--r--drivers/net/wireless/rtlwifi/rc.c3
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/Makefile1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/dm.c11
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/fw.c4
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/hw.c128
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/phy.c63
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/reg.h16
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/sw.c1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/trx.c14
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/trx.h8
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/hw.c52
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/phy.c71
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/reg.h16
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/trx.c7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/trx.h7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/hw.c31
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/phy.c71
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/trx.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/trx.h2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/dm.c50
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/hw.c18
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/phy.c429
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/reg.h14
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/rf.c6
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/trx.c5
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/trx.h7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/hw.c48
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/phy.c87
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/reg.h12
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/rf.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/trx.c7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/trx.h8
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/Makefile1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/def.h5
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/dm.c47
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/dm.h1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/fw.c260
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/fw.h18
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c8
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/hw.c127
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/phy.c530
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/phy.h21
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/reg.h16
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/sw.c13
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/trx.c11
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/trx.h13
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/Makefile19
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/def.h248
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/dm.c1325
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/dm.h310
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/fw.c620
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/fw.h248
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/hw.c2523
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/hw.h64
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/led.c153
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/led.h35
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/phy.c2156
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/phy.h217
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.c106
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h304
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.c140
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.h95
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/reg.h2277
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/rf.c504
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/rf.h43
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/sw.c384
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/sw.h35
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/table.c572
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/table.h43
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/trx.c960
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/trx.h617
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723com/Makefile9
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723com/dm_common.c65
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723com/dm_common.h33
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c329
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h126
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723com/main.c33
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723com/phy_common.c434
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723com/phy_common.h89
-rw-r--r--drivers/net/wireless/rtlwifi/usb.c4
-rw-r--r--drivers/net/wireless/rtlwifi/wifi.h518
-rw-r--r--drivers/net/wireless/ti/wilink_platform_data.c37
-rw-r--r--drivers/net/wireless/ti/wl1251/cmd.c2
-rw-r--r--drivers/net/wireless/ti/wl1251/rx.c2
-rw-r--r--drivers/net/wireless/ti/wl1251/sdio.c31
-rw-r--r--drivers/net/wireless/ti/wl1251/spi.c71
-rw-r--r--drivers/net/wireless/ti/wl1251/wl1251.h4
-rw-r--r--drivers/net/wireless/ti/wl12xx/main.c67
-rw-r--r--drivers/net/wireless/ti/wl12xx/wl12xx.h53
-rw-r--r--drivers/net/wireless/ti/wl18xx/main.c85
-rw-r--r--drivers/net/wireless/ti/wl18xx/tx.c4
-rw-r--r--drivers/net/wireless/ti/wl18xx/wl18xx.h62
-rw-r--r--drivers/net/wireless/ti/wlcore/acx.c7
-rw-r--r--drivers/net/wireless/ti/wlcore/acx.h6
-rw-r--r--drivers/net/wireless/ti/wlcore/cmd.c24
-rw-r--r--drivers/net/wireless/ti/wlcore/cmd.h9
-rw-r--r--drivers/net/wireless/ti/wlcore/event.c4
-rw-r--r--drivers/net/wireless/ti/wlcore/hw_ops.h9
-rw-r--r--drivers/net/wireless/ti/wlcore/init.c6
-rw-r--r--drivers/net/wireless/ti/wlcore/io.h8
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c200
-rw-r--r--drivers/net/wireless/ti/wlcore/ps.c6
-rw-r--r--drivers/net/wireless/ti/wlcore/rx.c19
-rw-r--r--drivers/net/wireless/ti/wlcore/rx.h2
-rw-r--r--drivers/net/wireless/ti/wlcore/spi.c4
-rw-r--r--drivers/net/wireless/ti/wlcore/sysfs.c2
-rw-r--r--drivers/net/wireless/ti/wlcore/tx.c45
-rw-r--r--drivers/net/wireless/ti/wlcore/tx.h1
-rw-r--r--drivers/net/wireless/ti/wlcore/wlcore.h27
-rw-r--r--drivers/net/wireless/ti/wlcore/wlcore_i.h86
-rw-r--r--drivers/net/wireless/wl3501_cs.c6
-rw-r--r--drivers/net/wireless/zd1201.c9
-rw-r--r--drivers/net/xen-netback/common.h118
-rw-r--r--drivers/net/xen-netback/interface.c145
-rw-r--r--drivers/net/xen-netback/netback.c864
-rw-r--r--drivers/net/xen-netfront.c20
-rw-r--r--drivers/nfc/Kconfig12
-rw-r--r--drivers/nfc/Makefile1
-rw-r--r--drivers/nfc/pn533.c28
-rw-r--r--drivers/nfc/pn544/i2c.c194
-rw-r--r--drivers/nfc/pn544/pn544.c2
-rw-r--r--drivers/nfc/pn544/pn544.h3
-rw-r--r--drivers/nfc/port100.c25
-rw-r--r--drivers/nfc/trf7970a.c1370
-rw-r--r--drivers/of/Kconfig18
-rw-r--r--drivers/of/Makefile1
-rw-r--r--drivers/of/address.c13
-rw-r--r--drivers/of/base.c586
-rw-r--r--drivers/of/fdt.c145
-rw-r--r--drivers/of/of_mdio.c45
-rw-r--r--drivers/of/of_net.c33
-rw-r--r--drivers/of/of_reserved_mem.c217
-rw-r--r--drivers/of/pdt.c3
-rw-r--r--drivers/of/selftest.c129
-rw-r--r--drivers/of/testcase-data/testcases.dtsi3
-rw-r--r--drivers/of/testcase-data/tests-interrupts.dtsi (renamed from arch/arm/boot/dts/testcases/tests-interrupts.dtsi)0
-rw-r--r--drivers/of/testcase-data/tests-match.dtsi19
-rw-r--r--drivers/of/testcase-data/tests-phandle.dtsi (renamed from arch/arm/boot/dts/testcases/tests-phandle.dtsi)3
-rw-r--r--drivers/parport/share.c3
-rw-r--r--drivers/pci/Makefile23
-rw-r--r--drivers/pci/bus.c8
-rw-r--r--drivers/pci/host-bridge.c8
-rw-r--r--drivers/pci/host/Kconfig2
-rw-r--r--drivers/pci/host/pci-imx6.c47
-rw-r--r--drivers/pci/host/pci-mvebu.c37
-rw-r--r--drivers/pci/host/pci-rcar-gen2.c180
-rw-r--r--drivers/pci/host/pcie-designware.c6
-rw-r--r--drivers/pci/hotplug/acpiphp.h16
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c544
-rw-r--r--drivers/pci/hotplug/cpqphp_core.c4
-rw-r--r--drivers/pci/hotplug/pciehp.h5
-rw-r--r--drivers/pci/hotplug/pciehp_acpi.c1
-rw-r--r--drivers/pci/hotplug/pciehp_core.c8
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c173
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c75
-rw-r--r--drivers/pci/hotplug/pciehp_pci.c2
-rw-r--r--drivers/pci/iov.c119
-rw-r--r--drivers/pci/msi.c10
-rw-r--r--drivers/pci/pci-driver.c33
-rw-r--r--drivers/pci/pci-sysfs.c17
-rw-r--r--drivers/pci/pci.c131
-rw-r--r--drivers/pci/pci.h4
-rw-r--r--drivers/pci/probe.c93
-rw-r--r--drivers/pci/quirks.c190
-rw-r--r--drivers/pci/rom.c2
-rw-r--r--drivers/pci/search.c10
-rw-r--r--drivers/pci/setup-res.c37
-rw-r--r--drivers/pcmcia/sa11xx_base.c3
-rw-r--r--drivers/pcmcia/yenta_socket.c18
-rw-r--r--drivers/phy/Kconfig110
-rw-r--r--drivers/phy/Makefile9
-rw-r--r--drivers/phy/phy-bcm-kona-usb2.c4
-rw-r--r--drivers/phy/phy-core.c152
-rw-r--r--drivers/phy/phy-exynos-dp-video.c8
-rw-r--r--drivers/phy/phy-exynos-mipi-video.c10
-rw-r--r--drivers/phy/phy-exynos4210-usb2.c261
-rw-r--r--drivers/phy/phy-exynos4x12-usb2.c328
-rw-r--r--drivers/phy/phy-exynos5250-sata.c251
-rw-r--r--drivers/phy/phy-exynos5250-usb2.c404
-rw-r--r--drivers/phy/phy-mvebu-sata.c10
-rw-r--r--drivers/phy/phy-omap-control.c (renamed from drivers/usb/phy/phy-omap-control.c)169
-rw-r--r--drivers/phy/phy-omap-usb2.c139
-rw-r--r--drivers/phy/phy-samsung-usb2.c228
-rw-r--r--drivers/phy/phy-samsung-usb2.h67
-rw-r--r--drivers/phy/phy-sun4i-usb.c331
-rw-r--r--drivers/phy/phy-ti-pipe3.c470
-rw-r--r--drivers/phy/phy-twl4030-usb.c16
-rw-r--r--drivers/phy/phy-xgene.c1750
-rw-r--r--drivers/pinctrl/Kconfig8
-rw-r--r--drivers/pinctrl/devicetree.c4
-rw-r--r--drivers/pinctrl/mvebu/Kconfig9
-rw-r--r--drivers/pinctrl/mvebu/Makefile2
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-370.c20
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-375.c459
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-38x.c462
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-xp.c24
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-dove.c404
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-kirkwood.c25
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-mvebu.c122
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-mvebu.h55
-rw-r--r--drivers/pinctrl/pinctrl-adi2-bf54x.c138
-rw-r--r--drivers/pinctrl/pinctrl-adi2-bf60x.c128
-rw-r--r--drivers/pinctrl/pinctrl-adi2.c32
-rw-r--r--drivers/pinctrl/pinctrl-adi2.h8
-rw-r--r--drivers/pinctrl/pinctrl-at91.c39
-rw-r--r--drivers/pinctrl/pinctrl-baytrail.c56
-rw-r--r--drivers/pinctrl/pinctrl-capri.c2
-rw-r--r--drivers/pinctrl/pinctrl-coh901.c186
-rw-r--r--drivers/pinctrl/pinctrl-exynos.c82
-rw-r--r--drivers/pinctrl/pinctrl-imx.c2
-rw-r--r--drivers/pinctrl/pinctrl-msm.c124
-rw-r--r--drivers/pinctrl/pinctrl-msm.h5
-rw-r--r--drivers/pinctrl/pinctrl-msm8x74.c14
-rw-r--r--drivers/pinctrl/pinctrl-nomadik.c178
-rw-r--r--drivers/pinctrl/pinctrl-samsung.c2
-rw-r--r--drivers/pinctrl/pinctrl-samsung.h1
-rw-r--r--drivers/pinctrl/pinctrl-single.c3
-rw-r--r--drivers/pinctrl/pinctrl-st.c462
-rw-r--r--drivers/pinctrl/pinctrl-sunxi-pins.h12
-rw-r--r--drivers/pinctrl/pinctrl-sunxi.c6
-rw-r--r--drivers/pinctrl/pinctrl-sunxi.h6
-rw-r--r--drivers/pinctrl/pinctrl-tegra.c38
-rw-r--r--drivers/pinctrl/pinctrl-tegra.h4
-rw-r--r--drivers/pinctrl/pinctrl-tegra114.c1100
-rw-r--r--drivers/pinctrl/pinctrl-tegra124.c1243
-rw-r--r--drivers/pinctrl/pinctrl-tegra20.c640
-rw-r--r--drivers/pinctrl/pinctrl-tegra30.c1287
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7790.c171
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7791.c602
-rw-r--r--drivers/pinctrl/sirf/pinctrl-atlas6.c46
-rw-r--r--drivers/pinctrl/sirf/pinctrl-prima2.c3
-rw-r--r--drivers/pinctrl/sirf/pinctrl-sirf.c19
-rw-r--r--drivers/platform/x86/Kconfig2
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c1
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c6
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c15
-rw-r--r--drivers/pnp/pnpbios/bioscalls.c9
-rw-r--r--drivers/pnp/resource.c2
-rw-r--r--drivers/power/ds2782_battery.c2
-rw-r--r--drivers/power/isp1704_charger.c2
-rw-r--r--drivers/power/max17040_battery.c5
-rw-r--r--drivers/powercap/intel_rapl.c17
-rw-r--r--drivers/ps3/ps3-vuart.c4
-rw-r--r--drivers/ptp/Kconfig1
-rw-r--r--drivers/ptp/ptp_chardev.c128
-rw-r--r--drivers/ptp/ptp_clock.c23
-rw-r--r--drivers/ptp/ptp_ixp46x.c1
-rw-r--r--drivers/ptp/ptp_pch.c1
-rw-r--r--drivers/ptp/ptp_private.h8
-rw-r--r--drivers/ptp/ptp_sysfs.c115
-rw-r--r--drivers/pwm/pwm-lp3943.c4
-rw-r--r--drivers/rapidio/devices/tsi721.h1
-rw-r--r--drivers/rapidio/devices/tsi721_dma.c27
-rw-r--r--drivers/regulator/88pm800.c4
-rw-r--r--drivers/regulator/88pm8607.c8
-rw-r--r--drivers/regulator/Kconfig45
-rw-r--r--drivers/regulator/Makefile4
-rw-r--r--drivers/regulator/aat2870-regulator.c1
-rw-r--r--drivers/regulator/act8865-regulator.c21
-rw-r--r--drivers/regulator/anatop-regulator.c124
-rw-r--r--drivers/regulator/arizona-ldo1.c11
-rw-r--r--drivers/regulator/arizona-micsupp.c4
-rw-r--r--drivers/regulator/as3711-regulator.c15
-rw-r--r--drivers/regulator/as3722-regulator.c1
-rw-r--r--drivers/regulator/bcm590xx-regulator.c403
-rw-r--r--drivers/regulator/core.c66
-rw-r--r--drivers/regulator/da9052-regulator.c29
-rw-r--r--drivers/regulator/da9055-regulator.c73
-rw-r--r--drivers/regulator/da9063-regulator.c17
-rw-r--r--drivers/regulator/da9210-regulator.c5
-rw-r--r--drivers/regulator/db8500-prcmu.c2
-rw-r--r--drivers/regulator/dbx500-prcmu.c16
-rw-r--r--drivers/regulator/dummy.c6
-rw-r--r--drivers/regulator/fan53555.c13
-rw-r--r--drivers/regulator/fixed.c46
-rw-r--r--drivers/regulator/gpio-regulator.c34
-rw-r--r--drivers/regulator/helpers.c48
-rw-r--r--drivers/regulator/lp3971.c2
-rw-r--r--drivers/regulator/lp872x.c4
-rw-r--r--drivers/regulator/max14577.c18
-rw-r--r--drivers/regulator/max1586.c15
-rw-r--r--drivers/regulator/max77686.c15
-rw-r--r--drivers/regulator/max77693.c44
-rw-r--r--drivers/regulator/max8649.c8
-rw-r--r--drivers/regulator/max8660.c35
-rw-r--r--drivers/regulator/max8907-regulator.c16
-rw-r--r--drivers/regulator/max8925-regulator.c8
-rw-r--r--drivers/regulator/max8952.c26
-rw-r--r--drivers/regulator/max8973-regulator.c6
-rw-r--r--drivers/regulator/max8997.c22
-rw-r--r--drivers/regulator/max8998.c27
-rw-r--r--drivers/regulator/mc13xxx-regulator-core.c12
-rw-r--r--drivers/regulator/pfuze100-regulator.c204
-rw-r--r--drivers/regulator/rc5t583-regulator.c13
-rw-r--r--drivers/regulator/s2mpa01.c481
-rw-r--r--drivers/regulator/s2mps11.c364
-rw-r--r--drivers/regulator/s5m8767.c175
-rw-r--r--drivers/regulator/st-pwm.c190
-rw-r--r--drivers/regulator/ti-abb-regulator.c140
-rw-r--r--drivers/regulator/tps51632-regulator.c8
-rw-r--r--drivers/regulator/tps62360-regulator.c9
-rw-r--r--drivers/regulator/tps6507x-regulator.c29
-rw-r--r--drivers/regulator/tps65090-regulator.c13
-rw-r--r--drivers/regulator/tps65217-regulator.c17
-rw-r--r--drivers/regulator/tps65218-regulator.c285
-rw-r--r--drivers/regulator/tps6524x-regulator.c5
-rw-r--r--drivers/regulator/tps6586x-regulator.c20
-rw-r--r--drivers/regulator/tps65910-regulator.c21
-rw-r--r--drivers/regulator/tps80031-regulator.c6
-rw-r--r--drivers/regulator/wm831x-dcdc.c16
-rw-r--r--drivers/regulator/wm831x-isink.c4
-rw-r--r--drivers/regulator/wm831x-ldo.c12
-rw-r--r--drivers/regulator/wm8350-regulator.c4
-rw-r--r--drivers/regulator/wm8994-regulator.c4
-rw-r--r--drivers/rtc/Kconfig12
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/interface.c3
-rw-r--r--drivers/rtc/rtc-as3722.c5
-rw-r--r--drivers/rtc/rtc-at32ap700x.c4
-rw-r--r--drivers/rtc/rtc-cmos.c8
-rw-r--r--drivers/rtc/rtc-coh901331.c18
-rw-r--r--drivers/rtc/rtc-da9052.c4
-rw-r--r--drivers/rtc/rtc-da9055.c4
-rw-r--r--drivers/rtc/rtc-davinci.c33
-rw-r--r--drivers/rtc/rtc-ds1305.c10
-rw-r--r--drivers/rtc/rtc-ds1307.c243
-rw-r--r--drivers/rtc/rtc-ds1347.c166
-rw-r--r--drivers/rtc/rtc-ds1390.c5
-rw-r--r--drivers/rtc/rtc-ds1511.c21
-rw-r--r--drivers/rtc/rtc-ds1553.c21
-rw-r--r--drivers/rtc/rtc-ds1672.c11
-rw-r--r--drivers/rtc/rtc-ds1742.c5
-rw-r--r--drivers/rtc/rtc-ds3232.c100
-rw-r--r--drivers/rtc/rtc-imxdi.c4
-rw-r--r--drivers/rtc/rtc-isl12057.c1
-rw-r--r--drivers/rtc/rtc-jz4740.c25
-rw-r--r--drivers/rtc/rtc-lpc32xx.c5
-rw-r--r--drivers/rtc/rtc-mc13xxx.c139
-rw-r--r--drivers/rtc/rtc-moxart.c4
-rw-r--r--drivers/rtc/rtc-nuc900.c5
-rw-r--r--drivers/rtc/rtc-palmas.c5
-rw-r--r--drivers/rtc/rtc-pm8xxx.c288
-rw-r--r--drivers/rtc/rtc-rv3029c2.c12
-rw-r--r--drivers/rtc/rtc-rx8025.c1
-rw-r--r--drivers/rtc/rtc-s3c.c21
-rw-r--r--drivers/rtc/rtc-sirfsoc.c68
-rw-r--r--drivers/rtc/rtc-spear.c4
-rw-r--r--drivers/rtc/rtc-stk17ta8.c3
-rw-r--r--drivers/rtc/rtc-sunxi.c2
-rw-r--r--drivers/rtc/rtc-test.c9
-rw-r--r--drivers/rtc/rtc-tx4939.c4
-rw-r--r--drivers/rtc/rtc-vt8500.c28
-rw-r--r--drivers/rtc/rtc-x1205.c2
-rw-r--r--drivers/s390/block/dcssblk.c14
-rw-r--r--drivers/s390/char/con3215.c8
-rw-r--r--drivers/s390/char/con3270.c13
-rw-r--r--drivers/s390/char/raw3270.c26
-rw-r--r--drivers/s390/char/raw3270.h3
-rw-r--r--drivers/s390/char/sclp_early.c31
-rw-r--r--drivers/s390/cio/airq.c66
-rw-r--r--drivers/s390/cio/ccwgroup.c26
-rw-r--r--drivers/s390/cio/chsc.c1
-rw-r--r--drivers/s390/cio/chsc_sch.c3
-rw-r--r--drivers/s390/cio/cio.c52
-rw-r--r--drivers/s390/cio/device.c52
-rw-r--r--drivers/s390/cio/qdio.h14
-rw-r--r--drivers/s390/cio/qdio_main.c2
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype6.c24
-rw-r--r--drivers/s390/kvm/virtio_ccw.c323
-rw-r--r--drivers/s390/net/qeth_core.h7
-rw-r--r--drivers/s390/net/qeth_core_main.c13
-rw-r--r--drivers/s390/net/qeth_l2_main.c9
-rw-r--r--drivers/s390/net/qeth_l3_main.c3
-rw-r--r--drivers/sbus/char/jsflash.c1
-rw-r--r--drivers/scsi/NCR5380.c2
-rw-r--r--drivers/scsi/aacraid/aacraid.h2
-rw-r--r--drivers/scsi/aacraid/rx.c9
-rw-r--r--drivers/scsi/aacraid/sa.c3
-rw-r--r--drivers/scsi/aacraid/src.c4
-rw-r--r--drivers/scsi/aha152x.c4
-rw-r--r--drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h1
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c7
-rw-r--r--drivers/scsi/arm/acornscsi.c2
-rw-r--r--drivers/scsi/arm/cumana_1.c2
-rw-r--r--drivers/scsi/arm/cumana_2.c2
-rw-r--r--drivers/scsi/arm/powertec.c2
-rw-r--r--drivers/scsi/atari_scsi.c12
-rw-r--r--drivers/scsi/be2iscsi/be.h11
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.c121
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.h10
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c13
-rw-r--r--drivers/scsi/be2iscsi/be_main.c313
-rw-r--r--drivers/scsi/be2iscsi/be_main.h23
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.c22
-rw-r--r--drivers/scsi/bfa/bfa_ioc.c11
-rw-r--r--drivers/scsi/bfa/bfad_bsg.c4
-rw-r--r--drivers/scsi/bfa/bfad_im.c7
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc.h3
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_fcoe.c8
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_io.c35
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_tgt.c39
-rw-r--r--drivers/scsi/bnx2i/bnx2i_hwi.c98
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c31
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/cxgb4i.c59
-rw-r--r--drivers/scsi/dtc.c2
-rw-r--r--drivers/scsi/eata.c2
-rw-r--r--drivers/scsi/eata_pio.c4
-rw-r--r--drivers/scsi/esas2r/esas2r_init.c2
-rw-r--r--drivers/scsi/esas2r/esas2r_log.c8
-rw-r--r--drivers/scsi/g_NCR5380.c2
-rw-r--r--drivers/scsi/gdth.c6
-rw-r--r--drivers/scsi/hosts.c2
-rw-r--r--drivers/scsi/hpsa.c2618
-rw-r--r--drivers/scsi/hpsa.h171
-rw-r--r--drivers/scsi/hpsa_cmd.h270
-rw-r--r--drivers/scsi/ibmvscsi/ibmvstgt.c2
-rw-r--r--drivers/scsi/in2000.c2
-rw-r--r--drivers/scsi/initio.c2
-rw-r--r--drivers/scsi/ipr.c382
-rw-r--r--drivers/scsi/ipr.h22
-rw-r--r--drivers/scsi/isci/host.h5
-rw-r--r--drivers/scsi/isci/init.c2
-rw-r--r--drivers/scsi/isci/port_config.c7
-rw-r--r--drivers/scsi/isci/request.c8
-rw-r--r--drivers/scsi/isci/task.c2
-rw-r--r--drivers/scsi/iscsi_boot_sysfs.c1
-rw-r--r--drivers/scsi/iscsi_tcp.c25
-rw-r--r--drivers/scsi/libiscsi.c264
-rw-r--r--drivers/scsi/libiscsi_tcp.c71
-rw-r--r--drivers/scsi/libsas/sas_ata.c35
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c2
-rw-r--r--drivers/scsi/lpfc/lpfc.h22
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c628
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c3
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h24
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c108
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c200
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c39
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h1
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h6
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c277
-rw-r--r--drivers/scsi/lpfc/lpfc_mem.c47
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c56
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c552
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.h18
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c267
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h21
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/megaraid.c120
-rw-r--r--drivers/scsi/megaraid.h3
-rw-r--r--drivers/scsi/megaraid/megaraid_mm.c2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h114
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c815
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fp.c11
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.c272
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.h3
-rw-r--r--drivers/scsi/pas16.c2
-rw-r--r--drivers/scsi/pm8001/pm8001_ctl.c38
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.c105
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c12
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.c3
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.h12
-rw-r--r--drivers/scsi/pm8001/pm80xx_hwi.c97
-rw-r--r--drivers/scsi/qla1280.c7
-rw-r--r--drivers/scsi/qla2xxx/Makefile2
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c193
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c12
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c134
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.h7
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h68
-rw-r--r--drivers/scsi/qla2xxx/qla_dfs.c3
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h4
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h12
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c11
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c426
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c44
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c139
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c50
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_mr.c252
-rw-r--r--drivers/scsi/qla2xxx/qla_mr.h57
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.c21
-rw-r--r--drivers/scsi/qla2xxx/qla_nx2.c22
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c171
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c65
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c44
-rw-r--r--drivers/scsi/qla2xxx/qla_target.h3
-rw-r--r--drivers/scsi/qla2xxx/qla_tmpl.c909
-rw-r--r--drivers/scsi/qla2xxx/qla_tmpl.h205
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h4
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c158
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.h7
-rw-r--r--drivers/scsi/qla4xxx/ql4_83xx.c36
-rw-r--r--drivers/scsi/qla4xxx/ql4_bsg.c4
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h17
-rw-r--r--drivers/scsi/qla4xxx/ql4_fw.h31
-rw-r--r--drivers/scsi/qla4xxx/ql4_glbl.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_init.c7
-rw-r--r--drivers/scsi/qla4xxx/ql4_isr.c69
-rw-r--r--drivers/scsi/qla4xxx/ql4_mbx.c25
-rw-r--r--drivers/scsi/qla4xxx/ql4_nx.c89
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c232
-rw-r--r--drivers/scsi/qla4xxx/ql4_version.h2
-rw-r--r--drivers/scsi/scsi.c373
-rw-r--r--drivers/scsi/scsi_debug.c141
-rw-r--r--drivers/scsi/scsi_error.c6
-rw-r--r--drivers/scsi/scsi_lib.c114
-rw-r--r--drivers/scsi/scsi_scan.c115
-rw-r--r--drivers/scsi/scsi_sysfs.c257
-rw-r--r--drivers/scsi/scsi_tgt_lib.c3
-rw-r--r--drivers/scsi/scsi_transport_fc.c1
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c6
-rw-r--r--drivers/scsi/scsi_transport_srp.c1
-rw-r--r--drivers/scsi/sd.c42
-rw-r--r--drivers/scsi/sd.h6
-rw-r--r--drivers/scsi/ses.c38
-rw-r--r--drivers/scsi/st.c11
-rw-r--r--drivers/scsi/storvsc_drv.c3
-rw-r--r--drivers/scsi/t128.c2
-rw-r--r--drivers/scsi/u14-34f.c2
-rw-r--r--drivers/scsi/vmw_pvscsi.c242
-rw-r--r--drivers/scsi/vmw_pvscsi.h19
-rw-r--r--drivers/scsi/wd7000.c2
-rw-r--r--drivers/spi/Kconfig59
-rw-r--r--drivers/spi/Makefile5
-rw-r--r--drivers/spi/spi-altera.c7
-rw-r--r--drivers/spi/spi-ath79.c5
-rw-r--r--drivers/spi/spi-atmel.c51
-rw-r--r--drivers/spi/spi-au1550.c39
-rw-r--r--drivers/spi/spi-bcm2835.c1
-rw-r--r--drivers/spi/spi-bcm63xx-hsspi.c8
-rw-r--r--drivers/spi/spi-bcm63xx.c6
-rw-r--r--drivers/spi/spi-bfin-sport.c1
-rw-r--r--drivers/spi/spi-bfin-v3.c3
-rw-r--r--drivers/spi/spi-bfin5xx.c8
-rw-r--r--drivers/spi/spi-bitbang.c5
-rw-r--r--drivers/spi/spi-butterfly.c3
-rw-r--r--drivers/spi/spi-clps711x.c227
-rw-r--r--drivers/spi/spi-coldfire-qspi.c118
-rw-r--r--drivers/spi/spi-davinci.c14
-rw-r--r--drivers/spi/spi-dw-mmio.c2
-rw-r--r--drivers/spi/spi-dw.c17
-rw-r--r--drivers/spi/spi-efm32.c46
-rw-r--r--drivers/spi/spi-ep93xx.c21
-rw-r--r--drivers/spi/spi-falcon.c5
-rw-r--r--drivers/spi/spi-fsl-dspi.c100
-rw-r--r--drivers/spi/spi-fsl-espi.c5
-rw-r--r--drivers/spi/spi-fsl-lib.c14
-rw-r--r--drivers/spi/spi-fsl-spi.c30
-rw-r--r--drivers/spi/spi-gpio.c8
-rw-r--r--drivers/spi/spi-imx.c11
-rw-r--r--drivers/spi/spi-mpc512x-psc.c17
-rw-r--r--drivers/spi/spi-mpc52xx-psc.c1
-rw-r--r--drivers/spi/spi-mpc52xx.c17
-rw-r--r--drivers/spi/spi-mxs.c7
-rw-r--r--drivers/spi/spi-nuc900.c30
-rw-r--r--drivers/spi/spi-oc-tiny.c3
-rw-r--r--drivers/spi/spi-octeon.c80
-rw-r--r--drivers/spi/spi-omap-100k.c52
-rw-r--r--drivers/spi/spi-omap-uwire.c34
-rw-r--r--drivers/spi/spi-omap2-mcspi.c65
-rw-r--r--drivers/spi/spi-orion.c80
-rw-r--r--drivers/spi/spi-pl022.c80
-rw-r--r--drivers/spi/spi-ppc4xx.c1
-rw-r--r--drivers/spi/spi-pxa2xx-dma.c1
-rw-r--r--drivers/spi/spi-pxa2xx-pxadma.c1
-rw-r--r--drivers/spi/spi-pxa2xx.c3
-rw-r--r--drivers/spi/spi-qup.c779
-rw-r--r--drivers/spi/spi-rspi.c842
-rw-r--r--drivers/spi/spi-s3c24xx.c19
-rw-r--r--drivers/spi/spi-s3c64xx.c424
-rw-r--r--drivers/spi/spi-sc18is602.c29
-rw-r--r--drivers/spi/spi-sh-hspi.c43
-rw-r--r--drivers/spi/spi-sh-msiof.c385
-rw-r--r--drivers/spi/spi-sh-sci.c8
-rw-r--r--drivers/spi/spi-sirf.c116
-rw-r--r--drivers/spi/spi-sun4i.c478
-rw-r--r--drivers/spi/spi-sun6i.c484
-rw-r--r--drivers/spi/spi-tegra114.c27
-rw-r--r--drivers/spi/spi-tegra20-sflash.c26
-rw-r--r--drivers/spi/spi-tegra20-slink.c20
-rw-r--r--drivers/spi/spi-ti-qspi.c5
-rw-r--r--drivers/spi/spi-ti-ssp.c378
-rw-r--r--drivers/spi/spi-topcliff-pch.c62
-rw-r--r--drivers/spi/spi-txx9.c25
-rw-r--r--drivers/spi/spi-xcomm.c13
-rw-r--r--drivers/spi/spi-xilinx.c27
-rw-r--r--drivers/spi/spi-xtensa-xtfpga.c170
-rw-r--r--drivers/spi/spi.c251
-rw-r--r--drivers/spi/spidev.c23
-rw-r--r--drivers/spmi/Kconfig27
-rw-r--r--drivers/spmi/Makefile6
-rw-r--r--drivers/spmi/spmi-pmic-arb.c778
-rw-r--r--drivers/spmi/spmi.c574
-rw-r--r--drivers/staging/Kconfig12
-rw-r--r--drivers/staging/Makefile6
-rw-r--r--drivers/staging/android/Kconfig15
-rw-r--r--drivers/staging/android/android_alarm.h44
-rw-r--r--drivers/staging/android/ashmem.c45
-rw-r--r--drivers/staging/android/ashmem.h30
-rw-r--r--drivers/staging/android/binder.c271
-rw-r--r--drivers/staging/android/binder.h308
-rw-r--r--drivers/staging/android/binder_trace.h14
-rw-r--r--drivers/staging/android/ion/compat_ion.c26
-rw-r--r--drivers/staging/android/ion/ion.c156
-rw-r--r--drivers/staging/android/ion/ion_cma_heap.c2
-rw-r--r--drivers/staging/android/ion/ion_dummy_driver.c24
-rw-r--r--drivers/staging/android/ion/ion_heap.c69
-rw-r--r--drivers/staging/android/ion/ion_page_pool.c8
-rw-r--r--drivers/staging/android/ion/ion_priv.h90
-rw-r--r--drivers/staging/android/ion/ion_system_heap.c90
-rw-r--r--drivers/staging/android/ion/tegra/tegra_ion.c10
-rw-r--r--drivers/staging/android/lowmemorykiller.c5
-rw-r--r--drivers/staging/android/sw_sync.h37
-rw-r--r--drivers/staging/android/sync.c14
-rw-r--r--drivers/staging/android/sync.h88
-rw-r--r--drivers/staging/android/timed_gpio.c8
-rw-r--r--drivers/staging/android/timed_output.h4
-rw-r--r--drivers/staging/android/uapi/android_alarm.h62
-rw-r--r--drivers/staging/android/uapi/ashmem.h47
-rw-r--r--drivers/staging/android/uapi/binder.h351
-rw-r--r--drivers/staging/android/uapi/sw_sync.h32
-rw-r--r--drivers/staging/android/uapi/sync.h97
-rw-r--r--drivers/staging/bcm/Adapter.h6
-rw-r--r--drivers/staging/bcm/Bcmchar.c3439
-rw-r--r--drivers/staging/bcm/Bcmnet.c2
-rw-r--r--drivers/staging/bcm/CmHost.c61
-rw-r--r--drivers/staging/bcm/DDRInit.c32
-rw-r--r--drivers/staging/bcm/InterfaceInit.c416
-rw-r--r--drivers/staging/bcm/InterfaceIsr.c223
-rw-r--r--drivers/staging/bcm/Kconfig1
-rw-r--r--drivers/staging/bcm/Qos.c35
-rw-r--r--drivers/staging/bcm/Typedefs.h22
-rw-r--r--drivers/staging/bcm/headers.h2
-rw-r--r--drivers/staging/bcm/hostmibs.c8
-rw-r--r--drivers/staging/bcm/nvm.c30
-rw-r--r--drivers/staging/ced1401/ced_ioc.c163
-rw-r--r--drivers/staging/ced1401/ced_ioctl.h31
-rw-r--r--drivers/staging/ced1401/usb1401.c195
-rw-r--r--drivers/staging/ced1401/usb1401.h6
-rw-r--r--drivers/staging/ced1401/use14_ioc.h5
-rw-r--r--drivers/staging/ced1401/userspace/use1401.c10
-rw-r--r--drivers/staging/comedi/Kconfig24
-rw-r--r--drivers/staging/comedi/comedi_fops.c191
-rw-r--r--drivers/staging/comedi/comedidev.h56
-rw-r--r--drivers/staging/comedi/drivers.c32
-rw-r--r--drivers/staging/comedi/drivers/8255_pci.c37
-rw-r--r--drivers/staging/comedi/drivers/Makefile2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c597
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c1187
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c857
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c106
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c73
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c24
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_035.c14
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1500.c24
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1564.c16
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3120.c26
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3200.c36
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3501.c6
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3xxx.c57
-rw-r--r--drivers/staging/comedi/drivers/adl_pci6208.c22
-rw-r--r--drivers/staging/comedi/drivers/adl_pci7x3x.c3
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9111.c73
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9118.c92
-rw-r--r--drivers/staging/comedi/drivers/adq12b.c31
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1710.c84
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1723.c2
-rw-r--r--drivers/staging/comedi/drivers/adv_pci_dio.c10
-rw-r--r--drivers/staging/comedi/drivers/aio_aio12_8.c31
-rw-r--r--drivers/staging/comedi/drivers/aio_iiro_16.c2
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200_common.c2
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc236.c35
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc263.c2
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci224.c29
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci230.c42
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci263.c2
-rw-r--r--drivers/staging/comedi/drivers/c6xdigio.c491
-rw-r--r--drivers/staging/comedi/drivers/cb_das16_cs.c150
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas.c51
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas64.c59
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidda.c2
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdas.c41
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdda.c4
-rw-r--r--drivers/staging/comedi/drivers/comedi_bond.c5
-rw-r--r--drivers/staging/comedi/drivers/comedi_fc.c99
-rw-r--r--drivers/staging/comedi/drivers/comedi_fc.h84
-rw-r--r--drivers/staging/comedi/drivers/comedi_test.c7
-rw-r--r--drivers/staging/comedi/drivers/contec_pci_dio.c2
-rw-r--r--drivers/staging/comedi/drivers/dac02.c172
-rw-r--r--drivers/staging/comedi/drivers/daqboard2000.c85
-rw-r--r--drivers/staging/comedi/drivers/das08.c35
-rw-r--r--drivers/staging/comedi/drivers/das16.c19
-rw-r--r--drivers/staging/comedi/drivers/das16m1.c38
-rw-r--r--drivers/staging/comedi/drivers/das1800.c10
-rw-r--r--drivers/staging/comedi/drivers/das6402.c672
-rw-r--r--drivers/staging/comedi/drivers/das800.c43
-rw-r--r--drivers/staging/comedi/drivers/dmm32at.c83
-rw-r--r--drivers/staging/comedi/drivers/dt2811.c23
-rw-r--r--drivers/staging/comedi/drivers/dt2814.c29
-rw-r--r--drivers/staging/comedi/drivers/dt2815.c39
-rw-r--r--drivers/staging/comedi/drivers/dt282x.c73
-rw-r--r--drivers/staging/comedi/drivers/dt3000.c8
-rw-r--r--drivers/staging/comedi/drivers/dyna_pci10xx.c40
-rw-r--r--drivers/staging/comedi/drivers/fl512.c207
-rw-r--r--drivers/staging/comedi/drivers/gsc_hpdi.c1099
-rw-r--r--drivers/staging/comedi/drivers/icp_multi.c109
-rw-r--r--drivers/staging/comedi/drivers/ii_pci20kc.c20
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.c891
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.h6
-rw-r--r--drivers/staging/comedi/drivers/ke_counter.c209
-rw-r--r--drivers/staging/comedi/drivers/me4000.c3
-rw-r--r--drivers/staging/comedi/drivers/me_daq.c36
-rw-r--r--drivers/staging/comedi/drivers/mf6x4.c23
-rw-r--r--drivers/staging/comedi/drivers/mite.c11
-rw-r--r--drivers/staging/comedi/drivers/mite.h6
-rw-r--r--drivers/staging/comedi/drivers/mpc624.c30
-rw-r--r--drivers/staging/comedi/drivers/multiq3.c38
-rw-r--r--drivers/staging/comedi/drivers/ni_660x.c11
-rw-r--r--drivers/staging/comedi/drivers/ni_670x.c3
-rw-r--r--drivers/staging/comedi/drivers/ni_at_a2150.c55
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio16d.c61
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_700.c56
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_dio24.c4
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.c33
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_common.c78
-rw-r--r--drivers/staging/comedi/drivers/ni_pcidio.c16
-rw-r--r--drivers/staging/comedi/drivers/ni_pcimio.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_tio.h8
-rw-r--r--drivers/staging/comedi/drivers/pcl711.c26
-rw-r--r--drivers/staging/comedi/drivers/pcl812.c1484
-rw-r--r--drivers/staging/comedi/drivers/pcl816.c1045
-rw-r--r--drivers/staging/comedi/drivers/pcl818.c1523
-rw-r--r--drivers/staging/comedi/drivers/pcm3724.c6
-rw-r--r--drivers/staging/comedi/drivers/pcmad.c21
-rw-r--r--drivers/staging/comedi/drivers/pcmmio.c42
-rw-r--r--drivers/staging/comedi/drivers/plx9080.h8
-rw-r--r--drivers/staging/comedi/drivers/poc.c157
-rw-r--r--drivers/staging/comedi/drivers/quatech_daqp_cs.c5
-rw-r--r--drivers/staging/comedi/drivers/rtd520.c86
-rw-r--r--drivers/staging/comedi/drivers/rti800.c29
-rw-r--r--drivers/staging/comedi/drivers/rti802.c127
-rw-r--r--drivers/staging/comedi/drivers/s526.c34
-rw-r--r--drivers/staging/comedi/drivers/s626.c174
-rw-r--r--drivers/staging/comedi/drivers/skel.c43
-rw-r--r--drivers/staging/comedi/drivers/ssv_dnp.c3
-rw-r--r--drivers/staging/comedi/drivers/usbduxfast.c51
-rw-r--r--drivers/staging/comedi/drivers/usbduxsigma.c6
-rw-r--r--drivers/staging/comedi/kcomedilib/kcomedilib_main.c3
-rw-r--r--drivers/staging/comedi/proc.c48
-rw-r--r--drivers/staging/comedi/range.c37
-rw-r--r--drivers/staging/crystalhd/bcm_70012_regs.h3
-rw-r--r--drivers/staging/crystalhd/crystalhd_hw.c8
-rw-r--r--drivers/staging/crystalhd/crystalhd_lnx.c21
-rw-r--r--drivers/staging/crystalhd/crystalhd_lnx.h4
-rw-r--r--drivers/staging/crystalhd/crystalhd_misc.c2
-rw-r--r--drivers/staging/crystalhd/crystalhd_misc.h2
-rw-r--r--drivers/staging/cxt1e1/Makefile1
-rw-r--r--drivers/staging/cxt1e1/comet.c44
-rw-r--r--drivers/staging/cxt1e1/comet_tables.c1
-rw-r--r--drivers/staging/cxt1e1/functions.c373
-rw-r--r--drivers/staging/cxt1e1/hwprobe.c598
-rw-r--r--drivers/staging/cxt1e1/libsbew.h56
-rw-r--r--drivers/staging/cxt1e1/linux.c1641
-rw-r--r--drivers/staging/cxt1e1/musycc.c43
-rw-r--r--drivers/staging/cxt1e1/ossiRelease.c29
-rw-r--r--drivers/staging/cxt1e1/pmc93x6_eeprom.c6
-rw-r--r--drivers/staging/cxt1e1/pmcc4.h1
-rw-r--r--drivers/staging/cxt1e1/pmcc4_drv.c116
-rw-r--r--drivers/staging/cxt1e1/pmcc4_private.h1
-rw-r--r--drivers/staging/cxt1e1/pmcc4_sysdep.h1
-rw-r--r--drivers/staging/cxt1e1/sbeproc.c4
-rw-r--r--drivers/staging/dgap/Makefile6
-rw-r--r--drivers/staging/dgap/dgap.c7675
-rw-r--r--drivers/staging/dgap/dgap.h1322
-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.c1030
-rw-r--r--drivers/staging/dgap/dgap_driver.h620
-rw-r--r--drivers/staging/dgap/dgap_fep5.c1938
-rw-r--r--drivers/staging/dgap/dgap_fep5.h253
-rw-r--r--drivers/staging/dgap/dgap_kcompat.h64
-rw-r--r--drivers/staging/dgap/dgap_parse.c1374
-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.c186
-rw-r--r--drivers/staging/dgap/dgap_trace.h36
-rw-r--r--drivers/staging/dgap/dgap_tty.c3580
-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/dgnc_cls.c11
-rw-r--r--drivers/staging/dgnc/dgnc_driver.c4
-rw-r--r--drivers/staging/dgnc/dgnc_mgmt.c27
-rw-r--r--drivers/staging/dgnc/dgnc_neo.c3
-rw-r--r--drivers/staging/dgnc/dgnc_tty.c53
-rw-r--r--drivers/staging/dgrp/dgrp_net_ops.c330
-rw-r--r--drivers/staging/dgrp/dgrp_sysfs.c4
-rw-r--r--drivers/staging/dgrp/dgrp_tty.c22
-rw-r--r--drivers/staging/echo/TODO5
-rw-r--r--drivers/staging/et131x/et131x.c23
-rw-r--r--drivers/staging/frontier/Kconfig1
-rw-r--r--drivers/staging/frontier/alphatrack.c11
-rw-r--r--drivers/staging/frontier/tranzport.c12
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_hw.c2
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_ioctl.h8
-rw-r--r--drivers/staging/ft1000/ft1000.h156
-rw-r--r--drivers/staging/fwserial/fwserial.c13
-rw-r--r--drivers/staging/fwserial/fwserial.h1
-rw-r--r--drivers/staging/gdm724x/gdm_lte.c187
-rw-r--r--drivers/staging/gdm724x/gdm_lte.h2
-rw-r--r--drivers/staging/gdm724x/gdm_mux.c26
-rw-r--r--drivers/staging/gdm724x/gdm_usb.c56
-rw-r--r--drivers/staging/gdm724x/netlink_k.c3
-rw-r--r--drivers/staging/gdm72xx/TODO2
-rw-r--r--drivers/staging/gdm72xx/gdm_sdio.c50
-rw-r--r--drivers/staging/gdm72xx/gdm_usb.c40
-rw-r--r--drivers/staging/gdm72xx/gdm_wimax.c77
-rw-r--r--drivers/staging/gdm72xx/gdm_wimax.h20
-rw-r--r--drivers/staging/gs_fpgaboot/Kconfig8
-rw-r--r--drivers/staging/gs_fpgaboot/Makefile4
-rw-r--r--drivers/staging/gs_fpgaboot/README71
-rw-r--r--drivers/staging/gs_fpgaboot/TODO7
-rw-r--r--drivers/staging/gs_fpgaboot/gs_fpgaboot.c422
-rw-r--r--drivers/staging/gs_fpgaboot/gs_fpgaboot.h56
-rw-r--r--drivers/staging/gs_fpgaboot/io.c294
-rw-r--r--drivers/staging/gs_fpgaboot/io.h90
-rw-r--r--drivers/staging/iio/Documentation/iio_utils.h28
-rw-r--r--drivers/staging/iio/Documentation/lsiio.c157
-rw-r--r--drivers/staging/iio/accel/sca3000.h26
-rw-r--r--drivers/staging/iio/accel/sca3000_core.c172
-rw-r--r--drivers/staging/iio/accel/sca3000_ring.c2
-rw-r--r--drivers/staging/iio/adc/ad799x.h10
-rw-r--r--drivers/staging/iio/adc/ad799x_core.c65
-rw-r--r--drivers/staging/iio/adc/mxs-lradc.c22
-rw-r--r--drivers/staging/iio/addac/adt7316.c21
-rw-r--r--drivers/staging/iio/addac/adt7316.h8
-rw-r--r--drivers/staging/iio/impedance-analyzer/ad5933.c2
-rw-r--r--drivers/staging/iio/light/tsl2583.c6
-rw-r--r--drivers/staging/iio/light/tsl2x7x_core.c8
-rw-r--r--drivers/staging/iio/resolver/ad2s1210.c4
-rw-r--r--drivers/staging/imx-drm/Kconfig1
-rw-r--r--drivers/staging/imx-drm/Makefile3
-rw-r--r--drivers/staging/imx-drm/TODO5
-rw-r--r--drivers/staging/imx-drm/imx-drm-core.c894
-rw-r--r--drivers/staging/imx-drm/imx-drm.h44
-rw-r--r--drivers/staging/imx-drm/imx-fb.c47
-rw-r--r--drivers/staging/imx-drm/imx-fbdev.c74
-rw-r--r--drivers/staging/imx-drm/imx-hdmi.c713
-rw-r--r--drivers/staging/imx-drm/imx-ldb.c150
-rw-r--r--drivers/staging/imx-drm/imx-tve.c137
-rw-r--r--drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h2
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-dc.c2
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-di.c317
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c3
-rw-r--r--drivers/staging/imx-drm/ipuv3-crtc.c93
-rw-r--r--drivers/staging/imx-drm/ipuv3-plane.c4
-rw-r--r--drivers/staging/imx-drm/parallel-display.c127
-rw-r--r--drivers/staging/keucr/common.h8
-rw-r--r--drivers/staging/keucr/init.c16
-rw-r--r--drivers/staging/keucr/init.h6
-rw-r--r--drivers/staging/keucr/smil.h112
-rw-r--r--drivers/staging/keucr/smilecc.c58
-rw-r--r--drivers/staging/keucr/smilmain.c82
-rw-r--r--drivers/staging/keucr/smilsub.c170
-rw-r--r--drivers/staging/keucr/smscsi.c28
-rw-r--r--drivers/staging/keucr/transport.c8
-rw-r--r--drivers/staging/keucr/transport.h6
-rw-r--r--drivers/staging/keucr/usb.c6
-rw-r--r--drivers/staging/keucr/usb.h86
-rw-r--r--drivers/staging/line6/audio.c5
-rw-r--r--drivers/staging/line6/capture.c1
-rw-r--r--drivers/staging/line6/driver.c56
-rw-r--r--drivers/staging/line6/driver.h2
-rw-r--r--drivers/staging/line6/midi.c7
-rw-r--r--drivers/staging/line6/pcm.c2
-rw-r--r--drivers/staging/line6/usbdefs.h8
-rw-r--r--drivers/staging/lustre/TODO5
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/curproc.h9
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h2
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h8
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_kernelcomm.h2
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h9
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_private.h2
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_string.h30
-rw-r--r--drivers/staging/lustre/include/linux/lnet/lib-lnet.h2
-rw-r--r--drivers/staging/lustre/include/linux/lnet/lib-types.h16
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c132
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c12
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c6
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c20
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c3
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c6
-rw-r--r--drivers/staging/lustre/lnet/lnet/acceptor.c3
-rw-r--r--drivers/staging/lustre/lnet/lnet/api-ni.c5
-rw-r--r--drivers/staging/lustre/lnet/lnet/config.c12
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-eq.c7
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-ptl.c2
-rw-r--r--drivers/staging/lustre/lnet/lnet/peer.c3
-rw-r--r--drivers/staging/lustre/lnet/lnet/router.c12
-rw-r--r--drivers/staging/lustre/lnet/lnet/router_proc.c4
-rw-r--r--drivers/staging/lustre/lnet/selftest/conrpc.c3
-rw-r--r--drivers/staging/lustre/lnet/selftest/console.c24
-rw-r--r--drivers/staging/lustre/lnet/selftest/rpc.c3
-rw-r--r--drivers/staging/lustre/lnet/selftest/selftest.h6
-rw-r--r--drivers/staging/lustre/lustre/fid/fid_request.c34
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_cache.c6
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_internal.h2
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_request.c15
-rw-r--r--drivers/staging/lustre/lustre/include/cl_object.h14
-rw-r--r--drivers/staging/lustre/lustre/include/ioctl.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lclient.h4
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lustre_acl.h2
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lustre_compat25.h4
-rw-r--r--drivers/staging/lustre/lustre/include/linux/obd.h3
-rw-r--r--drivers/staging/lustre/lustre/include/lustre/lustre_idl.h85
-rw-r--r--drivers/staging/lustre/lustre/include/lustre/lustre_user.h25
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_cfg.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_disk.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_dlm.h4
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_dlm_flags.h18
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_export.h21
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_fid.h12
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_import.h21
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_lib.h8
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_linkea.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_mdc.h11
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_net.h26
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_quota.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_sec.h4
-rw-r--r--drivers/staging/lustre/lustre/include/md_object.h2
-rw-r--r--drivers/staging/lustre/lustre/include/obd.h11
-rw-r--r--drivers/staging/lustre/lustre/include/obd_class.h15
-rw-r--r--drivers/staging/lustre/lustre/include/obd_support.h2
-rw-r--r--drivers/staging/lustre/lustre/lclient/lcommon_cl.c4
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_flock.c41
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_lock.c2
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c5
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_request.c2
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_resource.c4
-rw-r--r--drivers/staging/lustre/lustre/libcfs/debug.c4
-rw-r--r--drivers/staging/lustre/lustre/libcfs/fail.c4
-rw-r--r--drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c102
-rw-r--r--drivers/staging/lustre/lustre/libcfs/libcfs_string.c54
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c19
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c65
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-module.c4
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-prim.c38
-rw-r--r--drivers/staging/lustre/lustre/libcfs/nidstrings.c7
-rw-r--r--drivers/staging/lustre/lustre/libcfs/tracefile.c5
-rw-r--r--drivers/staging/lustre/lustre/libcfs/upcall_cache.c5
-rw-r--r--drivers/staging/lustre/lustre/libcfs/workitem.c10
-rw-r--r--drivers/staging/lustre/lustre/llite/dcache.c328
-rw-r--r--drivers/staging/lustre/lustre/llite/dir.c37
-rw-r--r--drivers/staging/lustre/lustre/llite/file.c105
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_close.c2
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_internal.h42
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_lib.c32
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_mmap.c4
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_nfs.c6
-rw-r--r--drivers/staging/lustre/lustre/llite/lloop.c6
-rw-r--r--drivers/staging/lustre/lustre/llite/namei.c124
-rw-r--r--drivers/staging/lustre/lustre/llite/rw.c10
-rw-r--r--drivers/staging/lustre/lustre/llite/statahead.c14
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_io.c37
-rw-r--r--drivers/staging/lustre/lustre/llite/xattr.c31
-rw-r--r--drivers/staging/lustre/lustre/llite/xattr_cache.c125
-rw-r--r--drivers/staging/lustre/lustre/lmv/lmv_intent.c1
-rw-r--r--drivers/staging/lustre/lustre/lmv/lmv_obd.c5
-rw-r--r--drivers/staging/lustre/lustre/lmv/lproc_lmv.c5
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_ea.c2
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_io.c1
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_obd.c6
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_object.c16
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_pack.c3
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_request.c2
-rw-r--r--drivers/staging/lustre/lustre/lov/lovsub_dev.c4
-rw-r--r--drivers/staging/lustre/lustre/lvfs/lvfs_linux.c4
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_internal.h4
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_lib.c2
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_locks.c117
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_reint.c3
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_request.c80
-rw-r--r--drivers/staging/lustre/lustre/mgc/mgc_request.c92
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_io.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_lock.c4
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_object.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/genops.c12
-rw-r--r--drivers/staging/lustre/lustre/obdclass/linux/linux-module.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_cat.c6
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_lvfs.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_osd.c6
-rw-r--r--drivers/staging/lustre/lustre/obdclass/local_storage.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lprocfs_status.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lu_object.c10
-rw-r--r--drivers/staging/lustre/lustre/obdclass/md_attrs.c6
-rw-r--r--drivers/staging/lustre/lustre/obdclass/obd_config.c54
-rw-r--r--drivers/staging/lustre/lustre/obdclass/obd_mount.c4
-rw-r--r--drivers/staging/lustre/lustre/obdclass/obdo.c6
-rw-r--r--drivers/staging/lustre/lustre/obdecho/echo.c3
-rw-r--r--drivers/staging/lustre/lustre/obdecho/echo_client.c20
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_cache.c12
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_io.c16
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_page.c2
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_quota.c20
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/client.c187
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/events.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/gss_cli_upcall.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/gss_generic_token.c36
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/gss_keyring.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/gss_krb5_mech.c4
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/gss_pipefs.c4
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/gss_svc_upcall.c8
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/sec_gss.c14
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/import.c37
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/layout.c5
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c4
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/niobuf.c8
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/nrs.c4
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/pack_generic.c14
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c4
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/recover.c57
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec.c18
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c6
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_config.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/service.c12
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/wiretest.c2
-rw-r--r--drivers/staging/media/Kconfig2
-rw-r--r--drivers/staging/media/Makefile2
-rw-r--r--drivers/staging/media/as102/as10x_handle.h14
-rw-r--r--drivers/staging/media/cxd2099/cxd2099.c12
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c2
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c6
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_video.c3
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_video.h2
-rw-r--r--drivers/staging/media/dt3155v4l/dt3155v4l.c7
-rw-r--r--drivers/staging/media/go7007/Kconfig3
-rw-r--r--drivers/staging/media/go7007/go7007-loader.c2
-rw-r--r--drivers/staging/media/go7007/go7007-v4l2.c25
-rw-r--r--drivers/staging/media/go7007/snd-go7007.c5
-rw-r--r--drivers/staging/media/lirc/lirc_igorplugusb.c2
-rw-r--r--drivers/staging/media/lirc/lirc_imon.c4
-rw-r--r--drivers/staging/media/lirc/lirc_parallel.c26
-rw-r--r--drivers/staging/media/lirc/lirc_sasem.c13
-rw-r--r--drivers/staging/media/msi3101/Kconfig7
-rw-r--r--drivers/staging/media/msi3101/Makefile1
-rw-r--r--drivers/staging/media/msi3101/msi001.c500
-rw-r--r--drivers/staging/media/msi3101/sdr-msi3101.c1566
-rw-r--r--drivers/staging/media/omap24xx/tcm825x.c8
-rw-r--r--drivers/staging/media/omap24xx/tcm825x.h2
-rw-r--r--drivers/staging/media/omap4iss/iss_video.c2
-rw-r--r--drivers/staging/media/rtl2832u_sdr/Kconfig7
-rw-r--r--drivers/staging/media/rtl2832u_sdr/Makefile6
-rw-r--r--drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c1500
-rw-r--r--drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.h54
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_core.c85
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_hv7131d.c15
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_hv7131r.c15
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_ov7630.c24
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_ov7660.c24
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_pas106b.c18
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_pas202bcb.c15
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-core.c2
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-g723.c6
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-tw28.c2
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c46
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-v4l2.c2
-rw-r--r--drivers/staging/netlogic/xlr_net.c10
-rw-r--r--drivers/staging/nokia_h4p/Kconfig9
-rw-r--r--drivers/staging/nokia_h4p/Makefile6
-rw-r--r--drivers/staging/nokia_h4p/TODO132
-rw-r--r--drivers/staging/nokia_h4p/hci_h4p.h222
-rw-r--r--drivers/staging/nokia_h4p/nokia_core.c1206
-rw-r--r--drivers/staging/nokia_h4p/nokia_fw-bcm.c148
-rw-r--r--drivers/staging/nokia_h4p/nokia_fw-csr.c149
-rw-r--r--drivers/staging/nokia_h4p/nokia_fw-ti1273.c110
-rw-r--r--drivers/staging/nokia_h4p/nokia_fw.c208
-rw-r--r--drivers/staging/nokia_h4p/nokia_uart.c199
-rw-r--r--drivers/staging/nvec/nvec.c3
-rw-r--r--drivers/staging/nvec/nvec_ps2.c2
-rw-r--r--drivers/staging/octeon-usb/octeon-hcd.c1017
-rw-r--r--drivers/staging/octeon/ethernet-defines.h4
-rw-r--r--drivers/staging/octeon/ethernet-mdio.c20
-rw-r--r--drivers/staging/octeon/ethernet-mem.c11
-rw-r--r--drivers/staging/octeon/ethernet-rgmii.c23
-rw-r--r--drivers/staging/octeon/ethernet-tx.c8
-rw-r--r--drivers/staging/octeon/ethernet.c10
-rw-r--r--drivers/staging/octeon/octeon-ethernet.h2
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon.h2
-rw-r--r--drivers/staging/ozwpan/ozcdev.c4
-rw-r--r--drivers/staging/ozwpan/ozhcd.c8
-rw-r--r--drivers/staging/ozwpan/ozpd.c31
-rw-r--r--drivers/staging/ozwpan/ozpd.h5
-rw-r--r--drivers/staging/ozwpan/ozproto.c54
-rw-r--r--drivers/staging/ozwpan/ozproto.h2
-rw-r--r--drivers/staging/ozwpan/ozprotocol.h6
-rw-r--r--drivers/staging/ozwpan/ozusbif.h2
-rw-r--r--drivers/staging/ozwpan/ozusbsvc1.c2
-rw-r--r--drivers/staging/panel/panel.c41
-rw-r--r--drivers/staging/rtl8187se/Kconfig1
-rw-r--r--drivers/staging/rtl8187se/Module.symvers0
-rw-r--r--drivers/staging/rtl8187se/ieee80211/dot11d.h11
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211.h12
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c14
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c15
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c1203
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c151
-rw-r--r--drivers/staging/rtl8187se/r8180.h750
-rw-r--r--drivers/staging/rtl8187se/r8180_core.c894
-rw-r--r--drivers/staging/rtl8187se/r8180_dm.c6
-rw-r--r--drivers/staging/rtl8187se/r8180_rtl8225.h21
-rw-r--r--drivers/staging/rtl8187se/r8180_rtl8225z2.c59
-rw-r--r--drivers/staging/rtl8187se/r8180_wx.c10
-rw-r--r--drivers/staging/rtl8187se/r8185b_init.c62
-rw-r--r--drivers/staging/rtl8188eu/Kconfig5
-rw-r--r--drivers/staging/rtl8188eu/Makefile1
-rw-r--r--drivers/staging/rtl8188eu/TODO5
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ap.c81
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_br_ext.c13
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_cmd.c220
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_debug.c12
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_efuse.c59
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ieee80211.c58
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_io.c28
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ioctl_set.c52
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_led.c4
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme.c303
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme_ext.c302
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mp.c16
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mp_ioctl.c78
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_p2p.c50
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_pwrctrl.c27
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_recv.c502
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_security.c93
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_sta_mgt.c87
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_wlan_util.c68
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_xmit.c129
-rw-r--r--drivers/staging/rtl8188eu/hal/Hal8188ERateAdaptive.c13
-rw-r--r--drivers/staging/rtl8188eu/hal/HalPhyRf_8188e.c37
-rw-r--r--drivers/staging/rtl8188eu/hal/hal_intf.c4
-rw-r--r--drivers/staging/rtl8188eu/hal/odm.c15
-rw-r--r--drivers/staging/rtl8188eu/hal/odm_RegConfig8188E.c4
-rw-r--r--drivers/staging/rtl8188eu/hal/odm_interface.c101
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c12
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_dm.c2
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c87
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_mp.c10
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c37
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c3
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c6
-rw-r--r--drivers/staging/rtl8188eu/hal/usb_halinit.c10
-rw-r--r--drivers/staging/rtl8188eu/hal/usb_ops_linux.c63
-rw-r--r--drivers/staging/rtl8188eu/include/drv_types.h6
-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/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/nic_spec.h44
-rw-r--r--drivers/staging/rtl8188eu/include/odm_interface.h23
-rw-r--r--drivers/staging/rtl8188eu/include/osdep_service.h34
-rw-r--r--drivers/staging/rtl8188eu/include/recv_osdep.h10
-rw-r--r--drivers/staging/rtl8188eu/include/rtl8188e_hal.h11
-rw-r--r--drivers/staging/rtl8188eu/include/rtl8188e_recv.h7
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_debug.h24
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_io.h44
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_ioctl.h2
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mlme.h32
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mlme_ext.h49
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_pwrctrl.h4
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_recv.h139
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_xmit.h5
-rw-r--r--drivers/staging/rtl8188eu/include/wifi.h2
-rw-r--r--drivers/staging/rtl8188eu/os_dep/ioctl_linux.c254
-rw-r--r--drivers/staging/rtl8188eu/os_dep/mlme_linux.c9
-rw-r--r--drivers/staging/rtl8188eu/os_dep/os_intfs.c12
-rw-r--r--drivers/staging/rtl8188eu/os_dep/osdep_service.c35
-rw-r--r--drivers/staging/rtl8188eu/os_dep/recv_linux.c44
-rw-r--r--drivers/staging/rtl8188eu/os_dep/rtw_android.c1
-rw-r--r--drivers/staging/rtl8188eu/os_dep/usb_intf.c22
-rw-r--r--drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c5
-rw-r--r--drivers/staging/rtl8188eu/os_dep/xmit_linux.c17
-rw-r--r--drivers/staging/rtl8192e/dot11d.c9
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/Kconfig1
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_pci.h52
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_wx.c2
-rw-r--r--drivers/staging/rtl8192e/rtllib_tx.c4
-rw-r--r--drivers/staging/rtl8192u/Kconfig1
-rw-r--r--drivers/staging/rtl8192u/ieee80211/EndianFree.h194
-rw-r--r--drivers/staging/rtl8192u/ieee80211/aes.c468
-rw-r--r--drivers/staging/rtl8192u/ieee80211/arc4.c103
-rw-r--r--drivers/staging/rtl8192u/ieee80211/autoload.c40
-rw-r--r--drivers/staging/rtl8192u/ieee80211/cipher.c298
-rw-r--r--drivers/staging/rtl8192u/ieee80211/compress.c64
-rw-r--r--drivers/staging/rtl8192u/ieee80211/crypto_compat.h58
-rw-r--r--drivers/staging/rtl8192u/ieee80211/digest.c108
-rw-r--r--drivers/staging/rtl8192u/ieee80211/dot11d.c173
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211.h2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c22
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c107
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c5
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/internal.h81
-rw-r--r--drivers/staging/rtl8192u/ieee80211/michael_mic.c194
-rw-r--r--drivers/staging/rtl8192u/ieee80211/proc.c112
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c12
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c70
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c39
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl_crypto.h398
-rw-r--r--drivers/staging/rtl8192u/ieee80211/scatterwalk.c117
-rw-r--r--drivers/staging/rtl8192u/ieee80211/scatterwalk.h51
-rw-r--r--drivers/staging/rtl8192u/r8180_93cx6.c10
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c138
-rw-r--r--drivers/staging/rtl8192u/r8192U_dm.c99
-rw-r--r--drivers/staging/rtl8192u/r8192U_dm.h40
-rw-r--r--drivers/staging/rtl8192u/r819xU_HTGen.h12
-rw-r--r--drivers/staging/rtl8192u/r819xU_HTType.h379
-rw-r--r--drivers/staging/rtl8192u/r819xU_cmdpkt.c2
-rw-r--r--drivers/staging/rtl8192u/r819xU_firmware.c50
-rw-r--r--drivers/staging/rtl8192u/r819xU_firmware_img.c1
-rw-r--r--drivers/staging/rtl8192u/r819xU_phy.c29
-rw-r--r--drivers/staging/rtl8712/Kconfig2
-rw-r--r--drivers/staging/rtl8712/drv_types.h2
-rw-r--r--drivers/staging/rtl8712/ieee80211.c6
-rw-r--r--drivers/staging/rtl8712/os_intfs.c2
-rw-r--r--drivers/staging/rtl8712/osdep_service.h5
-rw-r--r--drivers/staging/rtl8712/rtl8712_recv.c2
-rw-r--r--drivers/staging/rtl8712/rtl871x_cmd.c11
-rw-r--r--drivers/staging/rtl8712/rtl871x_security.c13
-rw-r--r--drivers/staging/rtl8821ae/Kconfig2
-rw-r--r--drivers/staging/rtl8821ae/base.c199
-rw-r--r--drivers/staging/rtl8821ae/btcoexist/HalBtc8812a1Ant.c2
-rw-r--r--drivers/staging/rtl8821ae/btcoexist/habtc8723a1ant.c2
-rw-r--r--drivers/staging/rtl8821ae/btcoexist/halbtc8192e1ant.c2
-rw-r--r--drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.c2
-rw-r--r--drivers/staging/rtl8821ae/btcoexist/halbtc8723a2ant.c2
-rw-r--r--drivers/staging/rtl8821ae/btcoexist/halbtc8723b1ant.c2
-rw-r--r--drivers/staging/rtl8821ae/btcoexist/halbtc8723b2ant.c2
-rw-r--r--drivers/staging/rtl8821ae/btcoexist/halbtcoutsrc.c12
-rw-r--r--drivers/staging/rtl8821ae/core.c12
-rw-r--r--drivers/staging/rtl8821ae/core.h8
-rw-r--r--drivers/staging/rtl8821ae/debug.c10
-rw-r--r--drivers/staging/rtl8821ae/debug.h12
-rw-r--r--drivers/staging/rtl8821ae/efuse.c26
-rw-r--r--drivers/staging/rtl8821ae/pci.c274
-rw-r--r--drivers/staging/rtl8821ae/pci.h8
-rw-r--r--drivers/staging/rtl8821ae/ps.c2
-rw-r--r--drivers/staging/rtl8821ae/rc.c1
-rw-r--r--drivers/staging/rtl8821ae/regd.c4
-rw-r--r--drivers/staging/rtl8821ae/regd.h4
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/dm.c24
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/fw.c8
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/hal_bt_coexist.h2
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/hal_btc.c6
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/hw.c13
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/phy.c8
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/phy.h2
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/pwrseq.h10
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/pwrseqcmd.c2
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/reg.h28
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/sw.c4
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/trx.c12
-rw-r--r--drivers/staging/rtl8821ae/wifi.h488
-rw-r--r--drivers/staging/rts5139/ms.c21
-rw-r--r--drivers/staging/rts5139/ms_mg.c1
-rw-r--r--drivers/staging/rts5139/rts51x.c6
-rw-r--r--drivers/staging/rts5139/rts51x_fop.c10
-rw-r--r--drivers/staging/rts5139/rts51x_fop.h4
-rw-r--r--drivers/staging/rts5139/rts51x_scsi.c4
-rw-r--r--drivers/staging/rts5139/rts51x_transport.c4
-rw-r--r--drivers/staging/rts5139/sd.c4
-rw-r--r--drivers/staging/rts5139/sd_cprm.c1
-rw-r--r--drivers/staging/rts5139/xd.c18
-rw-r--r--drivers/staging/rts5208/ms.c2
-rw-r--r--drivers/staging/rts5208/rtsx.c6
-rw-r--r--drivers/staging/rts5208/rtsx_card.c71
-rw-r--r--drivers/staging/rts5208/rtsx_scsi.c8
-rw-r--r--drivers/staging/rts5208/rtsx_transport.c4
-rw-r--r--drivers/staging/sb105x/Kconfig9
-rw-r--r--drivers/staging/sb105x/Makefile3
-rw-r--r--drivers/staging/sb105x/sb_mp_register.h295
-rw-r--r--drivers/staging/sb105x/sb_pci_mp.c3189
-rw-r--r--drivers/staging/sb105x/sb_pci_mp.h291
-rw-r--r--drivers/staging/sb105x/sb_ser_core.h368
-rw-r--r--drivers/staging/sbe-2t3e3/2t3e3.h21
-rw-r--r--drivers/staging/sbe-2t3e3/ctrl.c17
-rw-r--r--drivers/staging/sbe-2t3e3/ctrl.h16
-rw-r--r--drivers/staging/sbe-2t3e3/dc.c7
-rw-r--r--drivers/staging/sbe-2t3e3/intr.c4
-rw-r--r--drivers/staging/sbe-2t3e3/maps.c9
-rw-r--r--drivers/staging/sbe-2t3e3/module.c2
-rw-r--r--drivers/staging/sbe-2t3e3/netdev.c6
-rw-r--r--drivers/staging/sep/sep_crypto.c2
-rw-r--r--drivers/staging/sep/sep_main.c94
-rw-r--r--drivers/staging/serqt_usb2/serqt_usb2.c18
-rw-r--r--drivers/staging/silicom/bp_mod.h25
-rw-r--r--drivers/staging/silicom/bpctl_mod.c629
-rw-r--r--drivers/staging/silicom/bypasslib/bp_ioctl.h8
-rw-r--r--drivers/staging/silicom/bypasslib/libbp_sd.h313
-rw-r--r--drivers/staging/slicoss/README40
-rw-r--r--drivers/staging/slicoss/TODO38
-rw-r--r--drivers/staging/slicoss/slic.h9
-rw-r--r--drivers/staging/slicoss/slicoss.c73
-rw-r--r--drivers/staging/sm7xxfb/Kconfig13
-rw-r--r--drivers/staging/sm7xxfb/Makefile1
-rw-r--r--drivers/staging/sm7xxfb/TODO9
-rw-r--r--drivers/staging/sm7xxfb/sm7xx.h779
-rw-r--r--drivers/staging/sm7xxfb/sm7xxfb.c1028
-rw-r--r--drivers/staging/speakup/serialio.c4
-rw-r--r--drivers/staging/speakup/speakup_dectlk.c6
-rw-r--r--drivers/staging/tidspbridge/Kconfig2
-rw-r--r--drivers/staging/tidspbridge/core/io_sm.c2
-rw-r--r--drivers/staging/tidspbridge/core/tiomap3430.c23
-rw-r--r--drivers/staging/tidspbridge/core/tiomap3430_pwr.c15
-rw-r--r--drivers/staging/tidspbridge/dynload/tramp.c2
-rw-r--r--drivers/staging/tidspbridge/rmgr/dbdcd.c4
-rw-r--r--drivers/staging/tidspbridge/rmgr/drv.c2
-rw-r--r--drivers/staging/tidspbridge/rmgr/mgr.c8
-rw-r--r--drivers/staging/tidspbridge/rmgr/nldr.c5
-rw-r--r--drivers/staging/tidspbridge/rmgr/node.c20
-rw-r--r--drivers/staging/unisys/Documentation/overview.txt174
-rw-r--r--drivers/staging/unisys/Documentation/proc-entries.txt93
-rw-r--r--drivers/staging/unisys/Kconfig20
-rw-r--r--drivers/staging/unisys/MAINTAINERS6
-rw-r--r--drivers/staging/unisys/Makefile10
-rw-r--r--drivers/staging/unisys/TODO21
-rw-r--r--drivers/staging/unisys/channels/Kconfig10
-rw-r--r--drivers/staging/unisys/channels/Makefile13
-rw-r--r--drivers/staging/unisys/channels/channel.c219
-rw-r--r--drivers/staging/unisys/channels/chanstub.c70
-rw-r--r--drivers/staging/unisys/channels/chanstub.h23
-rw-r--r--drivers/staging/unisys/common-spar/include/channels/channel.h661
-rw-r--r--drivers/staging/unisys/common-spar/include/channels/channel_guid.h64
-rw-r--r--drivers/staging/unisys/common-spar/include/channels/controlframework.h77
-rw-r--r--drivers/staging/unisys/common-spar/include/channels/controlvmchannel.h619
-rw-r--r--drivers/staging/unisys/common-spar/include/channels/diagchannel.h427
-rw-r--r--drivers/staging/unisys/common-spar/include/channels/iochannel.h933
-rw-r--r--drivers/staging/unisys/common-spar/include/channels/vbuschannel.h135
-rw-r--r--drivers/staging/unisys/common-spar/include/controlvmcompletionstatus.h92
-rw-r--r--drivers/staging/unisys/common-spar/include/diagnostics/appos_subsystems.h310
-rw-r--r--drivers/staging/unisys/common-spar/include/iovmcall_gnuc.h53
-rw-r--r--drivers/staging/unisys/common-spar/include/vbusdeviceinfo.h209
-rw-r--r--drivers/staging/unisys/common-spar/include/version.h46
-rw-r--r--drivers/staging/unisys/common-spar/include/vmcallinterface.h167
-rw-r--r--drivers/staging/unisys/include/commontypes.h170
-rw-r--r--drivers/staging/unisys/include/guestlinuxdebug.h182
-rw-r--r--drivers/staging/unisys/include/guidutils.h203
-rw-r--r--drivers/staging/unisys/include/periodic_work.h40
-rw-r--r--drivers/staging/unisys/include/procobjecttree.h48
-rw-r--r--drivers/staging/unisys/include/sparstop.h30
-rw-r--r--drivers/staging/unisys/include/timskmod.h324
-rw-r--r--drivers/staging/unisys/include/timskmodutils.h75
-rw-r--r--drivers/staging/unisys/include/uisqueue.h440
-rw-r--r--drivers/staging/unisys/include/uisthread.h46
-rw-r--r--drivers/staging/unisys/include/uisutils.h348
-rw-r--r--drivers/staging/unisys/include/uniklog.h193
-rw-r--r--drivers/staging/unisys/include/vbushelper.h47
-rw-r--r--drivers/staging/unisys/uislib/Kconfig10
-rw-r--r--drivers/staging/unisys/uislib/Makefile17
-rw-r--r--drivers/staging/unisys/uislib/uislib.c2421
-rw-r--r--drivers/staging/unisys/uislib/uisqueue.c160
-rw-r--r--drivers/staging/unisys/uislib/uisthread.c85
-rw-r--r--drivers/staging/unisys/uislib/uisutils.c350
-rw-r--r--drivers/staging/unisys/virthba/Kconfig10
-rw-r--r--drivers/staging/unisys/virthba/Makefile16
-rw-r--r--drivers/staging/unisys/virthba/virthba.c1823
-rw-r--r--drivers/staging/unisys/virthba/virthba.h31
-rw-r--r--drivers/staging/unisys/virtpci/Kconfig10
-rw-r--r--drivers/staging/unisys/virtpci/Makefile13
-rw-r--r--drivers/staging/unisys/virtpci/virtpci.c1771
-rw-r--r--drivers/staging/unisys/virtpci/virtpci.h104
-rw-r--r--drivers/staging/unisys/visorchannel/Kconfig10
-rw-r--r--drivers/staging/unisys/visorchannel/Makefile14
-rw-r--r--drivers/staging/unisys/visorchannel/globals.h29
-rw-r--r--drivers/staging/unisys/visorchannel/visorchannel.h106
-rw-r--r--drivers/staging/unisys/visorchannel/visorchannel_funcs.c674
-rw-r--r--drivers/staging/unisys/visorchannel/visorchannel_main.c49
-rw-r--r--drivers/staging/unisys/visorchipset/Kconfig10
-rw-r--r--drivers/staging/unisys/visorchipset/Makefile18
-rw-r--r--drivers/staging/unisys/visorchipset/controlvm.h27
-rw-r--r--drivers/staging/unisys/visorchipset/controlvm_direct.c62
-rw-r--r--drivers/staging/unisys/visorchipset/file.c226
-rw-r--r--drivers/staging/unisys/visorchipset/file.h26
-rw-r--r--drivers/staging/unisys/visorchipset/filexfer.c506
-rw-r--r--drivers/staging/unisys/visorchipset/filexfer.h147
-rw-r--r--drivers/staging/unisys/visorchipset/globals.h45
-rw-r--r--drivers/staging/unisys/visorchipset/parser.c474
-rw-r--r--drivers/staging/unisys/visorchipset/parser.h45
-rw-r--r--drivers/staging/unisys/visorchipset/testing.h41
-rw-r--r--drivers/staging/unisys/visorchipset/visorchipset.h307
-rw-r--r--drivers/staging/unisys/visorchipset/visorchipset_main.c2945
-rw-r--r--drivers/staging/unisys/visorchipset/visorchipset_umode.h37
-rw-r--r--drivers/staging/unisys/visorutil/Kconfig10
-rw-r--r--drivers/staging/unisys/visorutil/Makefile11
-rw-r--r--drivers/staging/unisys/visorutil/charqueue.c141
-rw-r--r--drivers/staging/unisys/visorutil/charqueue.h37
-rw-r--r--drivers/staging/unisys/visorutil/easyproc.c371
-rw-r--r--drivers/staging/unisys/visorutil/easyproc.h92
-rw-r--r--drivers/staging/unisys/visorutil/memregion.h43
-rw-r--r--drivers/staging/unisys/visorutil/memregion_direct.c223
-rw-r--r--drivers/staging/unisys/visorutil/periodic_work.c236
-rw-r--r--drivers/staging/unisys/visorutil/procobjecttree.c348
-rw-r--r--drivers/staging/unisys/visorutil/visorkmodutils.c71
-rw-r--r--drivers/staging/usbip/Kconfig4
-rw-r--r--drivers/staging/usbip/stub.h3
-rw-r--r--drivers/staging/usbip/stub_dev.c164
-rw-r--r--drivers/staging/usbip/stub_main.c45
-rw-r--r--drivers/staging/usbip/stub_rx.c28
-rw-r--r--drivers/staging/usbip/stub_tx.c16
-rw-r--r--drivers/staging/usbip/uapi/usbip.h26
-rw-r--r--drivers/staging/usbip/usbip_common.c35
-rw-r--r--drivers/staging/usbip/usbip_common.h19
-rw-r--r--drivers/staging/usbip/userspace/README8
-rw-r--r--drivers/staging/usbip/userspace/configure.ac12
-rw-r--r--drivers/staging/usbip/userspace/libsrc/Makefile.am3
-rw-r--r--drivers/staging/usbip/userspace/libsrc/list.h136
-rw-r--r--drivers/staging/usbip/userspace/libsrc/names.c8
-rw-r--r--drivers/staging/usbip/userspace/libsrc/sysfs_utils.c31
-rw-r--r--drivers/staging/usbip/userspace/libsrc/sysfs_utils.h8
-rw-r--r--drivers/staging/usbip/userspace/libsrc/usbip_common.c93
-rw-r--r--drivers/staging/usbip/userspace/libsrc/usbip_common.h41
-rw-r--r--drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c303
-rw-r--r--drivers/staging/usbip/userspace/libsrc/usbip_host_driver.h7
-rw-r--r--drivers/staging/usbip/userspace/libsrc/vhci_driver.c397
-rw-r--r--drivers/staging/usbip/userspace/libsrc/vhci_driver.h14
-rw-r--r--drivers/staging/usbip/userspace/src/Makefile.am1
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_attach.c1
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_bind.c195
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_detach.c2
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_list.c146
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_network.h1
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_unbind.c129
-rw-r--r--drivers/staging/usbip/userspace/src/usbipd.c21
-rw-r--r--drivers/staging/usbip/userspace/src/utils.c48
-rw-r--r--drivers/staging/usbip/vhci_hcd.c44
-rw-r--r--drivers/staging/usbip/vhci_sysfs.c18
-rw-r--r--drivers/staging/vt6655/80211mgr.c331
-rw-r--r--drivers/staging/vt6655/aes_ccmp.c36
-rw-r--r--drivers/staging/vt6655/desc.h15
-rw-r--r--drivers/staging/vt6655/dpc.c36
-rw-r--r--drivers/staging/vt6655/key.c8
-rw-r--r--drivers/staging/vt6655/mac.c10
-rw-r--r--drivers/staging/vt6655/mac.h2
-rw-r--r--drivers/staging/vt6655/michael.c14
-rw-r--r--drivers/staging/vt6655/michael.h6
-rw-r--r--drivers/staging/vt6655/rxtx.c62
-rw-r--r--drivers/staging/vt6655/wmgr.c30
-rw-r--r--drivers/staging/vt6656/80211hdr.h2
-rw-r--r--drivers/staging/vt6656/aes_ccmp.c6
-rw-r--r--drivers/staging/vt6656/card.h7
-rw-r--r--drivers/staging/vt6656/device.h85
-rw-r--r--drivers/staging/vt6656/dpc.c92
-rw-r--r--drivers/staging/vt6656/int.c150
-rw-r--r--drivers/staging/vt6656/int.h45
-rw-r--r--drivers/staging/vt6656/iwctl.c10
-rw-r--r--drivers/staging/vt6656/mac.c16
-rw-r--r--drivers/staging/vt6656/mac.h2
-rw-r--r--drivers/staging/vt6656/main_usb.c350
-rw-r--r--drivers/staging/vt6656/power.c50
-rw-r--r--drivers/staging/vt6656/rxtx.c185
-rw-r--r--drivers/staging/vt6656/rxtx.h92
-rw-r--r--drivers/staging/vt6656/usbpipe.c451
-rw-r--r--drivers/staging/vt6656/wcmd.c77
-rw-r--r--drivers/staging/vt6656/wcmd.h4
-rw-r--r--drivers/staging/vt6656/wmgr.c8
-rw-r--r--drivers/staging/winbond/localpara.h84
-rw-r--r--drivers/staging/winbond/wb35reg.c140
-rw-r--r--drivers/staging/winbond/wb35rx.c27
-rw-r--r--drivers/staging/wlags49_h2/dhf.c10
-rw-r--r--drivers/staging/wlags49_h2/hcf.c16
-rw-r--r--drivers/staging/wlags49_h2/sta_h2.c2
-rw-r--r--drivers/staging/wlags49_h2/wl_main.c311
-rw-r--r--drivers/staging/wlags49_h2/wl_netdev.c1992
-rw-r--r--drivers/staging/wlags49_h2/wl_util.c37
-rw-r--r--drivers/staging/wlags49_h2/wl_wext.c8
-rw-r--r--drivers/staging/wlan-ng/cfg80211.c11
-rw-r--r--drivers/staging/wlan-ng/hfa384x.h4
-rw-r--r--drivers/staging/wlan-ng/p80211mgmt.h172
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.c4
-rw-r--r--drivers/staging/wlan-ng/prism2fw.c2
-rw-r--r--drivers/staging/wlan-ng/prism2sta.c100
-rw-r--r--drivers/staging/xgifb/XGI_main_26.c15
-rw-r--r--drivers/staging/xillybus/Kconfig3
-rw-r--r--drivers/staging/xillybus/xillybus_core.c6
-rw-r--r--drivers/target/iscsi/iscsi_target.c10
-rw-r--r--drivers/target/iscsi/iscsi_target_erl1.c4
-rw-r--r--drivers/target/iscsi/iscsi_target_erl2.c16
-rw-r--r--drivers/target/iscsi/iscsi_target_tpg.c2
-rw-r--r--drivers/target/target_core_alua.c2
-rw-r--r--drivers/target/target_core_pr.c11
-rw-r--r--drivers/target/target_core_sbc.c39
-rw-r--r--drivers/target/target_core_spc.c4
-rw-r--r--drivers/target/target_core_transport.c8
-rw-r--r--drivers/thermal/Kconfig13
-rw-r--r--drivers/thermal/thermal_core.c27
-rw-r--r--drivers/thermal/x86_pkg_temp_thermal.c11
-rw-r--r--drivers/tty/hvc/hvc_console.c6
-rw-r--r--drivers/tty/hvc/hvc_opal.c8
-rw-r--r--drivers/tty/hvc/hvc_rtas.c12
-rw-r--r--drivers/tty/hvc/hvc_udbg.c9
-rw-r--r--drivers/tty/hvc/hvc_xen.c17
-rw-r--r--drivers/tty/ipwireless/tty.c3
-rw-r--r--drivers/tty/n_gsm.c11
-rw-r--r--drivers/tty/n_tty.c25
-rw-r--r--drivers/tty/serial/8250/8250_core.c37
-rw-r--r--drivers/tty/serial/8250/8250_dw.c4
-rw-r--r--drivers/tty/serial/8250/8250_pci.c46
-rw-r--r--drivers/tty/serial/Kconfig4
-rw-r--r--drivers/tty/serial/amba-pl011.c21
-rw-r--r--drivers/tty/serial/atmel_serial.c28
-rw-r--r--drivers/tty/serial/bcm63xx_uart.c16
-rw-r--r--drivers/tty/serial/clps711x.c21
-rw-r--r--drivers/tty/serial/crisv10.c112
-rw-r--r--drivers/tty/serial/efm32-uart.c5
-rw-r--r--drivers/tty/serial/fsl_lpuart.c430
-rw-r--r--drivers/tty/serial/imx.c82
-rw-r--r--drivers/tty/serial/max310x.c417
-rw-r--r--drivers/tty/serial/msm_serial.c140
-rw-r--r--drivers/tty/serial/msm_serial.h9
-rw-r--r--drivers/tty/serial/omap-serial.c22
-rw-r--r--drivers/tty/serial/pch_uart.c2
-rw-r--r--drivers/tty/serial/samsung.c40
-rw-r--r--drivers/tty/serial/serial_core.c20
-rw-r--r--drivers/tty/serial/sh-sci.c89
-rw-r--r--drivers/tty/serial/sirfsoc_uart.c199
-rw-r--r--drivers/tty/serial/sirfsoc_uart.h5
-rw-r--r--drivers/tty/serial/sunhv.c22
-rw-r--r--drivers/tty/serial/sunsab.c14
-rw-r--r--drivers/tty/serial/sunsu.c14
-rw-r--r--drivers/tty/serial/sunzilog.c14
-rw-r--r--drivers/tty/synclink.c1
-rw-r--r--drivers/tty/synclinkmp.c1
-rw-r--r--drivers/tty/tty_buffer.c20
-rw-r--r--drivers/tty/tty_io.c23
-rw-r--r--drivers/tty/tty_ldsem.c15
-rw-r--r--drivers/tty/vt/vt.c22
-rw-r--r--drivers/usb/Kconfig10
-rw-r--r--drivers/usb/chipidea/Makefile1
-rw-r--r--drivers/usb/chipidea/bits.h2
-rw-r--r--drivers/usb/chipidea/ci.h2
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c2
-rw-r--r--drivers/usb/chipidea/ci_hdrc_zevio.c72
-rw-r--r--drivers/usb/chipidea/core.c87
-rw-r--r--drivers/usb/chipidea/udc.c328
-rw-r--r--drivers/usb/core/Kconfig1
-rw-r--r--drivers/usb/core/config.c5
-rw-r--r--drivers/usb/core/devio.c286
-rw-r--r--drivers/usb/core/driver.c145
-rw-r--r--drivers/usb/core/generic.c1
-rw-r--r--drivers/usb/core/hcd.c38
-rw-r--r--drivers/usb/core/hub.c118
-rw-r--r--drivers/usb/core/hub.h2
-rw-r--r--drivers/usb/core/message.c10
-rw-r--r--drivers/usb/core/quirks.c4
-rw-r--r--drivers/usb/core/urb.c2
-rw-r--r--drivers/usb/core/usb.h11
-rw-r--r--drivers/usb/dwc2/core.c2
-rw-r--r--drivers/usb/dwc2/core_intr.c25
-rw-r--r--drivers/usb/dwc2/hcd.c11
-rw-r--r--drivers/usb/dwc2/hcd_intr.c14
-rw-r--r--drivers/usb/dwc2/platform.c3
-rw-r--r--drivers/usb/dwc3/core.c251
-rw-r--r--drivers/usb/dwc3/core.h105
-rw-r--r--drivers/usb/dwc3/dwc3-omap.c8
-rw-r--r--drivers/usb/dwc3/gadget.c183
-rw-r--r--drivers/usb/dwc3/gadget.h12
-rw-r--r--drivers/usb/gadget/Kconfig3
-rw-r--r--drivers/usb/gadget/at91_udc.c14
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c16
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.h2
-rw-r--r--drivers/usb/gadget/bcm63xx_udc.c58
-rw-r--r--drivers/usb/gadget/composite.c2
-rw-r--r--drivers/usb/gadget/f_fs.c623
-rw-r--r--drivers/usb/gadget/f_midi.c7
-rw-r--r--drivers/usb/gadget/f_subset.c2
-rw-r--r--drivers/usb/gadget/f_uac2.c4
-rw-r--r--drivers/usb/gadget/gr_udc.c10
-rw-r--r--drivers/usb/gadget/inode.c9
-rw-r--r--drivers/usb/gadget/lpc32xx_udc.c4
-rw-r--r--drivers/usb/gadget/printer.c10
-rw-r--r--drivers/usb/gadget/s3c-hsotg.c143
-rw-r--r--drivers/usb/gadget/s3c-hsudc.c1
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c2
-rw-r--r--drivers/usb/gadget/tcm_usb_gadget.c2
-rw-r--r--drivers/usb/gadget/u_ether.c101
-rw-r--r--drivers/usb/gadget/u_fs.h30
-rw-r--r--drivers/usb/gadget/u_serial.c4
-rw-r--r--drivers/usb/host/Kconfig4
-rw-r--r--drivers/usb/host/ehci-hcd.c13
-rw-r--r--drivers/usb/host/ehci-hub.c26
-rw-r--r--drivers/usb/host/ehci-platform.c182
-rw-r--r--drivers/usb/host/ehci-tegra.c4
-rw-r--r--drivers/usb/host/hwa-hc.c42
-rw-r--r--drivers/usb/host/ohci-platform.c199
-rw-r--r--drivers/usb/host/uhci-platform.c1
-rw-r--r--drivers/usb/host/xhci-dbg.c6
-rw-r--r--drivers/usb/host/xhci-hub.c8
-rw-r--r--drivers/usb/host/xhci-mem.c226
-rw-r--r--drivers/usb/host/xhci-pci.c23
-rw-r--r--drivers/usb/host/xhci-plat.c4
-rw-r--r--drivers/usb/host/xhci-ring.c214
-rw-r--r--drivers/usb/host/xhci.c57
-rw-r--r--drivers/usb/host/xhci.h46
-rw-r--r--drivers/usb/misc/Kconfig1
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c10
-rw-r--r--drivers/usb/misc/usbled.c34
-rw-r--r--drivers/usb/musb/Kconfig2
-rw-r--r--drivers/usb/musb/musb_core.c20
-rw-r--r--drivers/usb/musb/musb_cppi41.c69
-rw-r--r--drivers/usb/musb/musb_dsps.c58
-rw-r--r--drivers/usb/musb/musb_host.c33
-rw-r--r--drivers/usb/musb/musb_virthub.c26
-rw-r--r--drivers/usb/musb/omap2430.c4
-rw-r--r--drivers/usb/phy/Kconfig21
-rw-r--r--drivers/usb/phy/Makefile2
-rw-r--r--drivers/usb/phy/phy-fsm-usb.c9
-rw-r--r--drivers/usb/phy/phy-msm-usb.c60
-rw-r--r--drivers/usb/phy/phy-mxs-usb.c310
-rw-r--r--drivers/usb/phy/phy-omap-usb3.c361
-rw-r--r--drivers/usb/phy/phy-rcar-gen2-usb.c6
-rw-r--r--drivers/usb/phy/phy-twl6030-usb.c2
-rw-r--r--drivers/usb/phy/phy-ulpi.c2
-rw-r--r--drivers/usb/phy/phy.c8
-rw-r--r--drivers/usb/serial/ch341.c6
-rw-r--r--drivers/usb/serial/cyberjack.c2
-rw-r--r--drivers/usb/serial/cypress_m8.c21
-rw-r--r--drivers/usb/serial/ftdi_sio.c5
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h13
-rw-r--r--drivers/usb/serial/generic.c61
-rw-r--r--drivers/usb/serial/iuu_phoenix.c2
-rw-r--r--drivers/usb/serial/keyspan.c30
-rw-r--r--drivers/usb/serial/keyspan_pda.c2
-rw-r--r--drivers/usb/serial/kl5kusb105.c4
-rw-r--r--drivers/usb/serial/kobil_sct.c3
-rw-r--r--drivers/usb/serial/mos7720.c12
-rw-r--r--drivers/usb/serial/mos7840.c4
-rw-r--r--drivers/usb/serial/option.c6
-rw-r--r--drivers/usb/serial/qcserial.c3
-rw-r--r--drivers/usb/serial/quatech2.c2
-rw-r--r--drivers/usb/serial/spcp8x5.c7
-rw-r--r--drivers/usb/serial/symbolserial.c4
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c4
-rw-r--r--drivers/usb/serial/usb-serial-simple.c3
-rw-r--r--drivers/usb/serial/usb-serial.c17
-rw-r--r--drivers/usb/storage/Kconfig6
-rw-r--r--drivers/usb/storage/scsiglue.c6
-rw-r--r--drivers/usb/storage/uas-detect.h96
-rw-r--r--drivers/usb/storage/uas.c687
-rw-r--r--drivers/usb/storage/unusual_cypress.h2
-rw-r--r--drivers/usb/storage/unusual_devs.h12
-rw-r--r--drivers/usb/storage/unusual_uas.h52
-rw-r--r--drivers/usb/storage/usb.c26
-rw-r--r--drivers/usb/storage/usb.h3
-rw-r--r--drivers/usb/wusbcore/devconnect.c4
-rw-r--r--drivers/usb/wusbcore/wa-hc.c2
-rw-r--r--drivers/usb/wusbcore/wa-hc.h26
-rw-r--r--drivers/usb/wusbcore/wa-rpipe.c2
-rw-r--r--drivers/usb/wusbcore/wa-xfer.c583
-rw-r--r--drivers/vfio/Kconfig1
-rw-r--r--drivers/vfio/pci/vfio_pci_intrs.c12
-rw-r--r--drivers/vfio/vfio.c6
-rw-r--r--drivers/vfio/vfio_iommu_type1.c660
-rw-r--r--drivers/vhost/net.c67
-rw-r--r--drivers/vhost/scsi.c6
-rw-r--r--drivers/video/Kconfig19
-rw-r--r--drivers/video/Makefile3
-rw-r--r--drivers/video/backlight/aat2870_bl.c2
-rw-r--r--drivers/video/backlight/adp8860_bl.c4
-rw-r--r--drivers/video/backlight/adp8870_bl.c4
-rw-r--r--drivers/video/backlight/backlight.c28
-rw-r--r--drivers/video/backlight/corgi_lcd.c4
-rw-r--r--drivers/video/backlight/hx8357.c4
-rw-r--r--drivers/video/backlight/ili922x.c4
-rw-r--r--drivers/video/backlight/ili9320.c4
-rw-r--r--drivers/video/backlight/l4f00242t03.c5
-rw-r--r--drivers/video/backlight/lm3533_bl.c5
-rw-r--r--drivers/video/backlight/lms283gf05.c4
-rw-r--r--drivers/video/backlight/platform_lcd.c4
-rw-r--r--drivers/video/backlight/tps65217_bl.c5
-rw-r--r--drivers/video/exynos/Kconfig3
-rw-r--r--drivers/video/gbefb.c4
-rw-r--r--drivers/video/hyperv_fb.c88
-rw-r--r--drivers/video/logo/Kconfig2
-rw-r--r--drivers/video/logo/logo.c2
-rw-r--r--drivers/video/omap2/dss/dispc.c16
-rw-r--r--drivers/video/omap2/dss/dpi.c2
-rw-r--r--drivers/video/omap2/dss/sdi.c2
-rw-r--r--drivers/video/output.c133
-rw-r--r--drivers/video/sgivwfb.c889
-rw-r--r--drivers/video/uvesafb.c4
-rw-r--r--drivers/virtio/virtio_balloon.c14
-rw-r--r--drivers/virtio/virtio_pci.c6
-rw-r--r--drivers/virtio/virtio_ring.c12
-rw-r--r--drivers/vme/bridges/vme_ca91cx42.c33
-rw-r--r--drivers/vme/bridges/vme_tsi148.c22
-rw-r--r--drivers/w1/masters/Kconfig3
-rw-r--r--drivers/w1/masters/ds2490.c155
-rw-r--r--drivers/w1/masters/mxc_w1.c43
-rw-r--r--drivers/w1/masters/w1-gpio.c19
-rw-r--r--drivers/w1/slaves/Kconfig5
-rw-r--r--drivers/w1/slaves/w1_therm.c21
-rw-r--r--drivers/w1/w1.c269
-rw-r--r--drivers/w1/w1.h186
-rw-r--r--drivers/w1/w1_family.c8
-rw-r--r--drivers/w1/w1_family.h13
-rw-r--r--drivers/w1/w1_int.c25
-rw-r--r--drivers/w1/w1_io.c102
-rw-r--r--drivers/w1/w1_netlink.c359
-rw-r--r--drivers/w1/w1_netlink.h33
-rw-r--r--drivers/watchdog/Kconfig38
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/acquirewdt.c21
-rw-r--r--drivers/watchdog/advantechwdt.c21
-rw-r--r--drivers/watchdog/ar7_wdt.c1
-rw-r--r--drivers/watchdog/at32ap700x_wdt.c4
-rw-r--r--drivers/watchdog/ath79_wdt.c1
-rw-r--r--drivers/watchdog/bcm2835_wdt.c4
-rw-r--r--drivers/watchdog/bcm47xx_wdt.c1
-rw-r--r--drivers/watchdog/bcm63xx_wdt.c2
-rw-r--r--drivers/watchdog/booke_wdt.c8
-rw-r--r--drivers/watchdog/cpu5wdt.c1
-rw-r--r--drivers/watchdog/cpwd.c1
-rw-r--r--drivers/watchdog/da9052_wdt.c1
-rw-r--r--drivers/watchdog/da9055_wdt.c4
-rw-r--r--drivers/watchdog/davinci_wdt.c1
-rw-r--r--drivers/watchdog/ep93xx_wdt.c19
-rw-r--r--drivers/watchdog/geodewdt.c17
-rw-r--r--drivers/watchdog/hpwdt.c1
-rw-r--r--drivers/watchdog/i6300esb.c1
-rw-r--r--drivers/watchdog/iTCO_wdt.c8
-rw-r--r--drivers/watchdog/ib700wdt.c21
-rw-r--r--drivers/watchdog/ibmasr.c2
-rw-r--r--drivers/watchdog/indydog.c13
-rw-r--r--drivers/watchdog/intel_scu_watchdog.c4
-rw-r--r--drivers/watchdog/it87_wdt.c41
-rw-r--r--drivers/watchdog/jz4740_wdt.c1
-rw-r--r--drivers/watchdog/max63xx_wdt.c1
-rw-r--r--drivers/watchdog/mpc8xxx_wdt.c1
-rw-r--r--drivers/watchdog/mtx-1_wdt.c1
-rw-r--r--drivers/watchdog/nuc900_wdt.c1
-rw-r--r--drivers/watchdog/of_xilinx_wdt.c390
-rw-r--r--drivers/watchdog/omap_wdt.c23
-rw-r--r--drivers/watchdog/orion_wdt.c1
-rw-r--r--drivers/watchdog/pc87413_wdt.c7
-rw-r--r--drivers/watchdog/pcwd_usb.c4
-rw-r--r--drivers/watchdog/pnx4008_wdt.c1
-rw-r--r--drivers/watchdog/rdc321x_wdt.c1
-rw-r--r--drivers/watchdog/retu_wdt.c1
-rw-r--r--drivers/watchdog/riowd.c1
-rw-r--r--drivers/watchdog/s3c2410_wdt.c9
-rw-r--r--drivers/watchdog/sc520_wdt.c3
-rw-r--r--drivers/watchdog/shwdt.c2
-rw-r--r--drivers/watchdog/softdog.c2
-rw-r--r--drivers/watchdog/sp805_wdt.c19
-rw-r--r--drivers/watchdog/stmp3xxx_rtc_wdt.c1
-rw-r--r--drivers/watchdog/sunxi_wdt.c2
-rw-r--r--drivers/watchdog/tegra_wdt.c302
-rw-r--r--drivers/watchdog/ts72xx_wdt.c6
-rw-r--r--drivers/watchdog/w83697hf_wdt.c6
-rw-r--r--drivers/watchdog/wdt285.c3
-rw-r--r--drivers/watchdog/wdt_pci.c1
-rw-r--r--drivers/watchdog/wm831x_wdt.c1
-rw-r--r--drivers/xen/Makefile1
-rw-r--r--drivers/xen/balloon.c24
-rw-r--r--drivers/xen/events/events_2l.c15
-rw-r--r--drivers/xen/events/events_base.c110
-rw-r--r--drivers/xen/events/events_fifo.c8
-rw-r--r--drivers/xen/events/events_internal.h1
-rw-r--r--drivers/xen/grant-table.c73
-rw-r--r--drivers/xen/manage.c16
-rw-r--r--drivers/xen/pcpu.c1
-rw-r--r--drivers/xen/platform-pci.c2
-rw-r--r--drivers/xen/xen-acpi-cpuhotplug.c2
-rw-r--r--drivers/xen/xen-acpi-memhotplug.c2
-rw-r--r--drivers/xen/xen-acpi-pad.c26
-rw-r--r--drivers/xen/xen-acpi-processor.c15
-rw-r--r--drivers/xen/xen-pciback/pciback_ops.c3
-rw-r--r--drivers/xen/xen-selfballoon.c1
-rw-r--r--drivers/xen/xenbus/xenbus_client.c27
-rw-r--r--drivers/xen/xencomm.c219
-rw-r--r--fs/9p/vfs_inode.c2
-rw-r--r--fs/Kconfig1
-rw-r--r--fs/Makefile3
-rw-r--r--fs/affs/inode.c2
-rw-r--r--fs/afs/inode.c2
-rw-r--r--fs/afs/internal.h1
-rw-r--r--fs/afs/rxrpc.c12
-rw-r--r--fs/anon_inodes.c34
-rw-r--r--fs/befs/Makefile2
-rw-r--r--fs/befs/befs.h3
-rw-r--r--fs/befs/btree.c93
-rw-r--r--fs/befs/datastream.c87
-rw-r--r--fs/befs/debug.c74
-rw-r--r--fs/befs/inode.c10
-rw-r--r--fs/befs/io.c24
-rw-r--r--fs/befs/linuxvfs.c112
-rw-r--r--fs/bfs/inode.c2
-rw-r--r--fs/binfmt_elf.c9
-rw-r--r--fs/binfmt_misc.c1
-rw-r--r--fs/bio-integrity.c100
-rw-r--r--fs/bio.c18
-rw-r--r--fs/block_dev.c6
-rw-r--r--fs/btrfs/async-thread.c848
-rw-r--r--fs/btrfs/async-thread.h121
-rw-r--r--fs/btrfs/backref.c84
-rw-r--r--fs/btrfs/btrfs_inode.h14
-rw-r--r--fs/btrfs/compression.c2
-rw-r--r--fs/btrfs/ctree.c11
-rw-r--r--fs/btrfs/ctree.h73
-rw-r--r--fs/btrfs/delayed-inode.c6
-rw-r--r--fs/btrfs/delayed-ref.c29
-rw-r--r--fs/btrfs/dev-replace.c79
-rw-r--r--fs/btrfs/disk-io.c282
-rw-r--r--fs/btrfs/extent-tree.c58
-rw-r--r--fs/btrfs/extent_io.c15
-rw-r--r--fs/btrfs/extent_map.c56
-rw-r--r--fs/btrfs/extent_map.h10
-rw-r--r--fs/btrfs/file.c160
-rw-r--r--fs/btrfs/inode.c125
-rw-r--r--fs/btrfs/ioctl.c226
-rw-r--r--fs/btrfs/ordered-data.c68
-rw-r--r--fs/btrfs/ordered-data.h6
-rw-r--r--fs/btrfs/qgroup.c15
-rw-r--r--fs/btrfs/raid56.c21
-rw-r--r--fs/btrfs/reada.c4
-rw-r--r--fs/btrfs/relocation.c2
-rw-r--r--fs/btrfs/root-tree.c3
-rw-r--r--fs/btrfs/scrub.c97
-rw-r--r--fs/btrfs/send.c831
-rw-r--r--fs/btrfs/super.c48
-rw-r--r--fs/btrfs/sysfs.c43
-rw-r--r--fs/btrfs/sysfs.h5
-rw-r--r--fs/btrfs/transaction.c39
-rw-r--r--fs/btrfs/tree-log.c236
-rw-r--r--fs/btrfs/tree-log.h18
-rw-r--r--fs/btrfs/volumes.c46
-rw-r--r--fs/btrfs/volumes.h1
-rw-r--r--fs/buffer.c2
-rw-r--r--fs/cachefiles/namei.c4
-rw-r--r--fs/cachefiles/rdwr.c33
-rw-r--r--fs/ceph/acl.c11
-rw-r--r--fs/ceph/dir.c23
-rw-r--r--fs/ceph/file.c1
-rw-r--r--fs/ceph/super.c32
-rw-r--r--fs/ceph/super.h7
-rw-r--r--fs/ceph/xattr.c54
-rw-r--r--fs/cifs/cifsacl.c61
-rw-r--r--fs/cifs/cifsfs.c4
-rw-r--r--fs/cifs/cifsglob.h13
-rw-r--r--fs/cifs/cifsproto.h9
-rw-r--r--fs/cifs/cifssmb.c15
-rw-r--r--fs/cifs/dir.c2
-rw-r--r--fs/cifs/file.c94
-rw-r--r--fs/cifs/inode.c15
-rw-r--r--fs/cifs/smb1ops.c9
-rw-r--r--fs/cifs/smb2glob.h3
-rw-r--r--fs/cifs/smb2ops.c14
-rw-r--r--fs/cifs/smb2pdu.c9
-rw-r--r--fs/cifs/smb2proto.h3
-rw-r--r--fs/cifs/transport.c29
-rw-r--r--fs/cifs/xattr.c15
-rw-r--r--fs/coda/coda_int.h2
-rw-r--r--fs/coda/inode.c4
-rw-r--r--fs/compat.c162
-rw-r--r--fs/compat_binfmt_elf.c5
-rw-r--r--fs/compat_ioctl.c5
-rw-r--r--fs/cramfs/inode.c3
-rw-r--r--fs/dcache.c54
-rw-r--r--fs/debugfs/inode.c6
-rw-r--r--fs/direct-io.c1
-rw-r--r--fs/dlm/ast.c3
-rw-r--r--fs/dlm/dir.c4
-rw-r--r--fs/dlm/dlm_internal.h2
-rw-r--r--fs/dlm/lock.c7
-rw-r--r--fs/dlm/lockspace.c8
-rw-r--r--fs/dlm/member.c27
-rw-r--r--fs/dlm/recover.c10
-rw-r--r--fs/dlm/recoverd.c34
-rw-r--r--fs/drop_caches.c16
-rw-r--r--fs/ecryptfs/inode.c2
-rw-r--r--fs/ecryptfs/super.c2
-rw-r--r--fs/efivarfs/file.c13
-rw-r--r--fs/efs/super.c2
-rw-r--r--fs/exec.c8
-rw-r--r--fs/exofs/inode.c2
-rw-r--r--fs/ext2/inode.c2
-rw-r--r--fs/ext3/inode.c2
-rw-r--r--fs/ext4/file.c2
-rw-r--r--fs/ext4/inode.c5
-rw-r--r--fs/ext4/namei.c480
-rw-r--r--fs/f2fs/inode.c2
-rw-r--r--fs/fat/inode.c2
-rw-r--r--fs/fcntl.c37
-rw-r--r--fs/file.c49
-rw-r--r--fs/file_table.c3
-rw-r--r--fs/filesystems.c2
-rw-r--r--fs/freevxfs/vxfs_inode.c2
-rw-r--r--fs/freevxfs/vxfs_lookup.c2
-rw-r--r--fs/fs-writeback.c66
-rw-r--r--fs/fscache/object-list.c5
-rw-r--r--fs/fscache/object.c3
-rw-r--r--fs/fuse/cuse.c5
-rw-r--r--fs/fuse/dir.c119
-rw-r--r--fs/fuse/file.c286
-rw-r--r--fs/fuse/fuse_i.h22
-rw-r--r--fs/fuse/inode.c31
-rw-r--r--fs/gfs2/acl.c23
-rw-r--r--fs/gfs2/acl.h2
-rw-r--r--fs/gfs2/aops.c132
-rw-r--r--fs/gfs2/bmap.c115
-rw-r--r--fs/gfs2/bmap.h2
-rw-r--r--fs/gfs2/dir.c23
-rw-r--r--fs/gfs2/file.c13
-rw-r--r--fs/gfs2/glock.c28
-rw-r--r--fs/gfs2/glops.c2
-rw-r--r--fs/gfs2/incore.h37
-rw-r--r--fs/gfs2/inode.c75
-rw-r--r--fs/gfs2/lock_dlm.c10
-rw-r--r--fs/gfs2/log.c102
-rw-r--r--fs/gfs2/lops.c85
-rw-r--r--fs/gfs2/lops.h5
-rw-r--r--fs/gfs2/main.c4
-rw-r--r--fs/gfs2/meta_io.c14
-rw-r--r--fs/gfs2/meta_io.h3
-rw-r--r--fs/gfs2/ops_fstype.c89
-rw-r--r--fs/gfs2/quota.c18
-rw-r--r--fs/gfs2/recovery.c16
-rw-r--r--fs/gfs2/recovery.h6
-rw-r--r--fs/gfs2/rgrp.c32
-rw-r--r--fs/gfs2/super.c39
-rw-r--r--fs/gfs2/sys.c7
-rw-r--r--fs/gfs2/trans.c29
-rw-r--r--fs/gfs2/util.c101
-rw-r--r--fs/gfs2/util.h31
-rw-r--r--fs/hfs/inode.c2
-rw-r--r--fs/hfsplus/attributes.c2
-rw-r--r--fs/hfsplus/catalog.c41
-rw-r--r--fs/hfsplus/extents.c16
-rw-r--r--fs/hfsplus/hfsplus_fs.h3
-rw-r--r--fs/hfsplus/hfsplus_raw.h6
-rw-r--r--fs/hfsplus/inode.c9
-rw-r--r--fs/hfsplus/options.c2
-rw-r--r--fs/hfsplus/super.c2
-rw-r--r--fs/hostfs/hostfs_kern.c2
-rw-r--r--fs/hpfs/inode.c2
-rw-r--r--fs/hugetlbfs/inode.c17
-rw-r--r--fs/inode.c29
-rw-r--r--fs/jffs2/fs.c4
-rw-r--r--fs/jfs/acl.c2
-rw-r--r--fs/jfs/inode.c4
-rw-r--r--fs/kernfs/Kconfig7
-rw-r--r--fs/kernfs/dir.c753
-rw-r--r--fs/kernfs/file.c22
-rw-r--r--fs/kernfs/inode.c2
-rw-r--r--fs/kernfs/kernfs-internal.h15
-rw-r--r--fs/kernfs/mount.c47
-rw-r--r--fs/kernfs/symlink.c6
-rw-r--r--fs/lockd/svclock.c8
-rw-r--r--fs/locks.c389
-rw-r--r--fs/logfs/readwrite.c2
-rw-r--r--fs/minix/inode.c4
-rw-r--r--fs/mount.h4
-rw-r--r--fs/namei.c348
-rw-r--r--fs/namespace.c177
-rw-r--r--fs/ncpfs/inode.c2
-rw-r--r--fs/nfs/blocklayout/blocklayout.c2
-rw-r--r--fs/nfs/delegation.c11
-rw-r--r--fs/nfs/dir.c5
-rw-r--r--fs/nfs/inode.c16
-rw-r--r--fs/nfs/internal.h12
-rw-r--r--fs/nfs/nfs3proc.c1
-rw-r--r--fs/nfs/nfs4client.c7
-rw-r--r--fs/nfs/nfs4filelayout.c10
-rw-r--r--fs/nfs/nfs4namespace.c12
-rw-r--r--fs/nfs/nfs4proc.c24
-rw-r--r--fs/nfs/nfs4state.c19
-rw-r--r--fs/nfs/nfs4super.c2
-rw-r--r--fs/nfsd/auth.c5
-rw-r--r--fs/nfsd/nfs4acl.c9
-rw-r--r--fs/nfsd/vfs.c3
-rw-r--r--fs/nilfs2/cpfile.c12
-rw-r--r--fs/nilfs2/dat.c12
-rw-r--r--fs/nilfs2/inode.c6
-rw-r--r--fs/nilfs2/ioctl.c137
-rw-r--r--fs/nilfs2/sufile.c295
-rw-r--r--fs/nilfs2/sufile.h2
-rw-r--r--fs/nilfs2/the_nilfs.c10
-rw-r--r--fs/notify/dnotify/dnotify.c2
-rw-r--r--fs/notify/fanotify/fanotify.c71
-rw-r--r--fs/notify/fanotify/fanotify.h34
-rw-r--r--fs/notify/fanotify/fanotify_user.c198
-rw-r--r--fs/notify/fsnotify.c2
-rw-r--r--fs/notify/group.c8
-rw-r--r--fs/notify/inotify/inotify.h2
-rw-r--r--fs/notify/inotify/inotify_fsnotify.c3
-rw-r--r--fs/notify/inotify/inotify_user.c14
-rw-r--r--fs/notify/notification.c20
-rw-r--r--fs/ntfs/inode.c2
-rw-r--r--fs/ocfs2/acl.c1
-rw-r--r--fs/ocfs2/alloc.c5
-rw-r--r--fs/ocfs2/aops.c7
-rw-r--r--fs/ocfs2/aops.h5
-rw-r--r--fs/ocfs2/buffer_head_io.c2
-rw-r--r--fs/ocfs2/cluster/tcp.c28
-rw-r--r--fs/ocfs2/dcache.c61
-rw-r--r--fs/ocfs2/dcache.h12
-rw-r--r--fs/ocfs2/dir.c6
-rw-r--r--fs/ocfs2/dlm/dlmdomain.c27
-rw-r--r--fs/ocfs2/dlm/dlmrecovery.c29
-rw-r--r--fs/ocfs2/dlmglue.c44
-rw-r--r--fs/ocfs2/dlmglue.h3
-rw-r--r--fs/ocfs2/file.c129
-rw-r--r--fs/ocfs2/inode.c61
-rw-r--r--fs/ocfs2/inode.h17
-rw-r--r--fs/ocfs2/ioctl.c5
-rw-r--r--fs/ocfs2/journal.c6
-rw-r--r--fs/ocfs2/journal.h11
-rw-r--r--fs/ocfs2/locks.c2
-rw-r--r--fs/ocfs2/move_extents.c7
-rw-r--r--fs/ocfs2/namei.c25
-rw-r--r--fs/ocfs2/ocfs2.h33
-rw-r--r--fs/ocfs2/quota.h2
-rw-r--r--fs/ocfs2/quota_global.c62
-rw-r--r--fs/ocfs2/quota_local.c4
-rw-r--r--fs/ocfs2/stackglue.c18
-rw-r--r--fs/ocfs2/suballoc.c29
-rw-r--r--fs/ocfs2/suballoc.h4
-rw-r--r--fs/ocfs2/super.c53
-rw-r--r--fs/ocfs2/sysfile.c3
-rw-r--r--fs/ocfs2/xattr.c35
-rw-r--r--fs/omfs/inode.c2
-rw-r--r--fs/open.c4
-rw-r--r--fs/pnode.c26
-rw-r--r--fs/pnode.h4
-rw-r--r--fs/posix_acl.c5
-rw-r--r--fs/proc/Makefile1
-rw-r--r--fs/proc/base.c1
-rw-r--r--fs/proc/inode.c2
-rw-r--r--fs/proc/internal.h7
-rw-r--r--fs/proc/page.c5
-rw-r--r--fs/proc/proc_devtree.c241
-rw-r--r--fs/proc/root.c3
-rw-r--r--fs/proc/stat.c2
-rw-r--r--fs/proc/uptime.c2
-rw-r--r--fs/proc/vmcore.c26
-rw-r--r--fs/pstore/platform.c1
-rw-r--r--fs/pstore/ram.c19
-rw-r--r--fs/pstore/ram_core.c4
-rw-r--r--fs/quota/dquot.c18
-rw-r--r--fs/read_write.c80
-rw-r--r--fs/reiserfs/do_balan.c895
-rw-r--r--fs/reiserfs/inode.c2
-rw-r--r--fs/reiserfs/reiserfs.h1
-rw-r--r--fs/reiserfs/super.c3
-rw-r--r--fs/sync.c15
-rw-r--r--fs/sysfs/Kconfig1
-rw-r--r--fs/sysfs/dir.c44
-rw-r--r--fs/sysfs/file.c23
-rw-r--r--fs/sysfs/group.c7
-rw-r--r--fs/sysfs/mount.c7
-rw-r--r--fs/sysv/inode.c2
-rw-r--r--fs/timerfd.c1
-rw-r--r--fs/ubifs/super.c2
-rw-r--r--fs/udf/file.c14
-rw-r--r--fs/udf/inode.c5
-rw-r--r--fs/ufs/inode.c2
-rw-r--r--fs/xfs/xfs_iops.c16
-rw-r--r--fs/xfs/xfs_log_cil.c19
-rw-r--r--fs/xfs/xfs_mount.c24
-rw-r--r--fs/xfs/xfs_sb.c10
-rw-r--r--fs/xfs/xfs_super.c4
-rw-r--r--include/acpi/acbuffer.h2
-rw-r--r--include/acpi/acconfig.h2
-rw-r--r--include/acpi/acexcep.h2
-rw-r--r--include/acpi/acnames.h2
-rw-r--r--include/acpi/acoutput.h2
-rw-r--r--include/acpi/acpi.h5
-rw-r--r--include/acpi/acpi_bus.h49
-rw-r--r--include/acpi/acpi_drivers.h26
-rw-r--r--include/acpi/acpi_numa.h1
-rw-r--r--include/acpi/acpiosxf.h2
-rw-r--r--include/acpi/acpixf.h10
-rw-r--r--include/acpi/acrestyp.h2
-rw-r--r--include/acpi/actbl.h2
-rw-r--r--include/acpi/actbl1.h2
-rw-r--r--include/acpi/actbl2.h2
-rw-r--r--include/acpi/actbl3.h2
-rw-r--r--include/acpi/actypes.h66
-rw-r--r--include/acpi/platform/acenv.h2
-rw-r--r--include/acpi/platform/acgcc.h2
-rw-r--r--include/acpi/platform/aclinux.h20
-rw-r--r--include/asm-generic/bitops/const_hweight.h17
-rw-r--r--include/asm-generic/cputime_jiffies.h4
-rw-r--r--include/asm-generic/cputime_nsecs.h5
-rw-r--r--include/asm-generic/gpio.h2
-rw-r--r--include/asm-generic/mcs_spinlock.h13
-rw-r--r--include/asm-generic/pgtable.h52
-rw-r--r--include/asm-generic/rwsem.h10
-rw-r--r--include/asm-generic/vmlinux.lds.h11
-rw-r--r--include/crypto/algapi.h9
-rw-r--r--include/crypto/null.h11
-rw-r--r--include/drm/drmP.h3
-rw-r--r--include/drm/drm_crtc.h3
-rw-r--r--include/drm/drm_fb_helper.h2
-rw-r--r--include/drm/ttm/ttm_page_alloc.h2
-rw-r--r--include/dt-bindings/clock/tegra124-car.h4
-rw-r--r--include/dt-bindings/sound/tlv320aic31xx-micbias.h8
-rw-r--r--include/dt-bindings/spmi/spmi.h (renamed from include/linux/mfd/pm8xxx/rtc.h)19
-rw-r--r--include/kvm/arm_vgic.h5
-rw-r--r--include/linux/acpi.h13
-rw-r--r--include/linux/ahci_platform.h28
-rw-r--r--include/linux/atmel-ssc.h1
-rw-r--r--include/linux/audit.h3
-rw-r--r--include/linux/backing-dev.h2
-rw-r--r--include/linux/backlight.h6
-rw-r--r--include/linux/basic_mmio_gpio.h1
-rw-r--r--include/linux/bio.h12
-rw-r--r--include/linux/bitops.h15
-rw-r--r--include/linux/blk-iopoll.h2
-rw-r--r--include/linux/blk-mq.h21
-rw-r--r--include/linux/blkdev.h12
-rw-r--r--include/linux/brcmphy.h60
-rw-r--r--include/linux/can/dev.h9
-rw-r--r--include/linux/can/skb.h38
-rw-r--r--include/linux/ccp.h7
-rw-r--r--include/linux/ceph/ceph_fs.h5
-rw-r--r--include/linux/cgroup.h277
-rw-r--r--include/linux/cgroup_subsys.h30
-rw-r--r--include/linux/clk/ti.h4
-rw-r--r--include/linux/clockchips.h16
-rw-r--r--include/linux/compat.h86
-rw-r--r--include/linux/compiler-gcc4.h6
-rw-r--r--include/linux/connector.h2
-rw-r--r--include/linux/cpu.h7
-rw-r--r--include/linux/cpufeature.h60
-rw-r--r--include/linux/cpufreq.h37
-rw-r--r--include/linux/cpuidle.h23
-rw-r--r--include/linux/cpuset.h27
-rw-r--r--include/linux/cputime.h16
-rw-r--r--include/linux/cred.h2
-rw-r--r--include/linux/dcache.h8
-rw-r--r--include/linux/decompress/inflate.h4
-rw-r--r--include/linux/device.h3
-rw-r--r--include/linux/dma-buf.h2
-rw-r--r--include/linux/drbd.h8
-rw-r--r--include/linux/drbd_genl.h6
-rw-r--r--include/linux/efi.h268
-rw-r--r--include/linux/elevator.h11
-rw-r--r--include/linux/err.h7
-rw-r--r--include/linux/ethtool.h3
-rw-r--r--include/linux/extcon.h12
-rw-r--r--include/linux/extcon/of_extcon.h31
-rw-r--r--include/linux/file.h27
-rw-r--r--include/linux/filter.h118
-rw-r--r--include/linux/firewire.h1
-rw-r--r--include/linux/fmc-sdb.h2
-rw-r--r--include/linux/fs.h62
-rw-r--r--include/linux/fsl_ifc.h (renamed from arch/powerpc/include/asm/fsl_ifc.h)0
-rw-r--r--include/linux/fsnotify_backend.h6
-rw-r--r--include/linux/ftrace.h27
-rw-r--r--include/linux/ftrace_event.h32
-rw-r--r--include/linux/futex.h4
-rw-r--r--include/linux/gfp.h4
-rw-r--r--include/linux/gpio.h2
-rw-r--r--include/linux/gpio/consumer.h19
-rw-r--r--include/linux/gpio/driver.h48
-rw-r--r--include/linux/hardirq.h1
-rw-r--r--include/linux/hid-sensor-hub.h9
-rw-r--r--include/linux/hid-sensor-ids.h26
-rw-r--r--include/linux/hid.h76
-rw-r--r--include/linux/hrtimer.h4
-rw-r--r--include/linux/hsi/hsi.h2
-rw-r--r--include/linux/huge_mm.h41
-rw-r--r--include/linux/hugetlb.h10
-rw-r--r--include/linux/hugetlb_cgroup.h2
-rw-r--r--include/linux/hyperv.h355
-rw-r--r--include/linux/i2c/adp5588.h4
-rw-r--r--include/linux/idr.h2
-rw-r--r--include/linux/ieee80211.h239
-rw-r--r--include/linux/if_vlan.h9
-rw-r--r--include/linux/iio/iio.h16
-rw-r--r--include/linux/init.h20
-rw-r--r--include/linux/input/pmic8xxx-keypad.h52
-rw-r--r--include/linux/input/pmic8xxx-pwrkey.h31
-rw-r--r--include/linux/interrupt.h6
-rw-r--r--include/linux/io.h2
-rw-r--r--include/linux/ioport.h12
-rw-r--r--include/linux/ipc_namespace.h2
-rw-r--r--include/linux/irq.h9
-rw-r--r--include/linux/irq_work.h4
-rw-r--r--include/linux/isdn_ppp.h5
-rw-r--r--include/linux/kernel.h2
-rw-r--r--include/linux/kernel_stat.h10
-rw-r--r--include/linux/kernfs.h118
-rw-r--r--include/linux/kexec.h6
-rw-r--r--include/linux/kfifo.h2
-rw-r--r--include/linux/kmemleak.h2
-rw-r--r--include/linux/kobject.h1
-rw-r--r--include/linux/kvm_host.h20
-rw-r--r--include/linux/libata.h11
-rw-r--r--include/linux/linkage.h4
-rw-r--r--include/linux/list_lru.h8
-rw-r--r--include/linux/lockdep.h29
-rw-r--r--include/linux/mcb.h119
-rw-r--r--include/linux/memcontrol.h2
-rw-r--r--include/linux/mfd/arizona/registers.h6
-rw-r--r--include/linux/mfd/max8997-private.h2
-rw-r--r--include/linux/mfd/max8998-private.h2
-rw-r--r--include/linux/mfd/samsung/core.h22
-rw-r--r--include/linux/mfd/samsung/irq.h81
-rw-r--r--include/linux/mfd/samsung/rtc.h57
-rw-r--r--include/linux/mfd/samsung/s2mpa01.h192
-rw-r--r--include/linux/mfd/samsung/s2mps14.h154
-rw-r--r--include/linux/mfd/samsung/s5m8767.h7
-rw-r--r--include/linux/mfd/tps65217.h4
-rw-r--r--include/linux/miscdevice.h17
-rw-r--r--include/linux/mlx4/cmd.h8
-rw-r--r--include/linux/mlx4/device.h50
-rw-r--r--include/linux/mlx4/driver.h12
-rw-r--r--include/linux/mlx4/qp.h11
-rw-r--r--include/linux/mlx5/cq.h1
-rw-r--r--include/linux/mlx5/device.h43
-rw-r--r--include/linux/mlx5/driver.h44
-rw-r--r--include/linux/mlx5/qp.h67
-rw-r--r--include/linux/mm.h44
-rw-r--r--include/linux/mmc/sdio_ids.h1
-rw-r--r--include/linux/mmzone.h10
-rw-r--r--include/linux/mod_devicetable.h22
-rw-r--r--include/linux/module.h2
-rw-r--r--include/linux/mpls.h6
-rw-r--r--include/linux/mutex.h5
-rw-r--r--include/linux/netdev_features.h7
-rw-r--r--include/linux/netdevice.h195
-rw-r--r--include/linux/netfilter/ipset/ip_set.h15
-rw-r--r--include/linux/netfilter/nfnetlink.h21
-rw-r--r--include/linux/netpoll.h71
-rw-r--r--include/linux/nfs_xdr.h5
-rw-r--r--include/linux/nilfs2_fs.h52
-rw-r--r--include/linux/nl802154.h12
-rw-r--r--include/linux/nvme.h1
-rw-r--r--include/linux/of.h288
-rw-r--r--include/linux/of_device.h4
-rw-r--r--include/linux/of_fdt.h4
-rw-r--r--include/linux/of_graph.h66
-rw-r--r--include/linux/of_reserved_mem.h53
-rw-r--r--include/linux/pagemap.h43
-rw-r--r--include/linux/pagevec.h5
-rw-r--r--include/linux/pci-acpi.h4
-rw-r--r--include/linux/pci.h31
-rw-r--r--include/linux/pci_ids.h6
-rw-r--r--include/linux/phy.h56
-rw-r--r--include/linux/phy/omap_control_phy.h (renamed from include/linux/usb/omap_control_usb.h)36
-rw-r--r--include/linux/phy/omap_usb.h (renamed from include/linux/usb/omap_usb.h)14
-rw-r--r--include/linux/phy/phy.h29
-rw-r--r--include/linux/pipe_fs_i.h2
-rw-r--r--include/linux/platform_data/adau1977.h45
-rw-r--r--include/linux/platform_data/asoc-s3c.h3
-rw-r--r--include/linux/platform_data/asoc-s3c24xx_simtec.h3
-rw-r--r--include/linux/platform_data/ata-samsung_cf.h9
-rw-r--r--include/linux/platform_data/bt-nokia-h4p.h38
-rw-r--r--include/linux/platform_data/davinci_asp.h4
-rw-r--r--include/linux/platform_data/gpio-davinci.h4
-rw-r--r--include/linux/platform_data/max310x.h64
-rw-r--r--include/linux/platform_data/serial-imx.h2
-rw-r--r--include/linux/platform_data/spi-s3c64xx.h9
-rw-r--r--include/linux/platform_data/touchscreen-s3c2410.h17
-rw-r--r--include/linux/pm.h71
-rw-r--r--include/linux/pm_qos.h34
-rw-r--r--include/linux/pm_runtime.h4
-rw-r--r--include/linux/printk.h16
-rw-r--r--include/linux/ptp_classify.h103
-rw-r--r--include/linux/ptp_clock_kernel.h33
-rw-r--r--include/linux/quotaops.h8
-rw-r--r--include/linux/radix-tree.h55
-rw-r--r--include/linux/rculist.h17
-rw-r--r--include/linux/rcupdate.h96
-rw-r--r--include/linux/rcutiny.h20
-rw-r--r--include/linux/rcutree.h8
-rw-r--r--include/linux/regmap.h32
-rw-r--r--include/linux/regulator/driver.h8
-rw-r--r--include/linux/regulator/pfuze100.h14
-rw-r--r--include/linux/rmap.h3
-rw-r--r--include/linux/sched.h52
-rw-r--r--include/linux/sched/prio.h44
-rw-r--r--include/linux/sched/rt.h26
-rw-r--r--include/linux/seccomp.h1
-rw-r--r--include/linux/security.h22
-rw-r--r--include/linux/serial_bcm63xx.h2
-rw-r--r--include/linux/serial_sci.h93
-rw-r--r--include/linux/shmem_fs.h1
-rw-r--r--include/linux/skbuff.h132
-rw-r--r--include/linux/slab.h2
-rw-r--r--include/linux/smp.h11
-rw-r--r--include/linux/spi/spi.h46
-rw-r--r--include/linux/spi/spi_bitbang.h2
-rw-r--r--include/linux/spmi.h191
-rw-r--r--include/linux/srcu.h4
-rw-r--r--include/linux/swap.h36
-rw-r--r--include/linux/sxgbe_platform.h54
-rw-r--r--include/linux/syscalls.h10
-rw-r--r--include/linux/sysfs.h16
-rw-r--r--include/linux/tcp.h8
-rw-r--r--include/linux/torture.h100
-rw-r--r--include/linux/tracepoint.h24
-rw-r--r--include/linux/tty.h8
-rw-r--r--include/linux/tty_ldisc.h1
-rw-r--r--include/linux/u64_stats_sync.h16
-rw-r--r--include/linux/uinput.h2
-rw-r--r--include/linux/usb.h17
-rw-r--r--include/linux/usb/cdc_ncm.h2
-rw-r--r--include/linux/usb/chipidea.h1
-rw-r--r--include/linux/usb/composite.h2
-rw-r--r--include/linux/usb/hcd.h1
-rw-r--r--include/linux/usb/phy.h16
-rw-r--r--include/linux/usb/serial.h3
-rw-r--r--include/linux/usb/uas.h14
-rw-r--r--include/linux/usb/usbnet.h2
-rw-r--r--include/linux/usb_usual.h6
-rw-r--r--include/linux/vfio.h2
-rw-r--r--include/linux/video_output.h57
-rw-r--r--include/linux/vm_event_item.h1
-rw-r--r--include/linux/vmstat.h17
-rw-r--r--include/linux/wl12xx.h24
-rw-r--r--include/linux/workqueue.h45
-rw-r--r--include/linux/writeback.h2
-rw-r--r--include/media/adv7842.h3
-rw-r--r--include/media/lm3646.h87
-rw-r--r--include/media/rc-core.h80
-rw-r--r--include/media/rc-map.h6
-rw-r--r--include/media/v4l2-dev.h3
-rw-r--r--include/media/v4l2-ioctl.h10
-rw-r--r--include/media/v4l2-of.h33
-rw-r--r--include/media/v4l2-subdev.h9
-rw-r--r--include/media/videobuf2-core.h117
-rw-r--r--include/net/6lowpan.h (renamed from net/ieee802154/6lowpan.h)115
-rw-r--r--include/net/act_api.h22
-rw-r--r--include/net/addrconf.h6
-rw-r--r--include/net/af_ieee802154.h4
-rw-r--r--include/net/bluetooth/bluetooth.h1
-rw-r--r--include/net/bluetooth/hci.h76
-rw-r--r--include/net/bluetooth/hci_core.h209
-rw-r--r--include/net/bluetooth/l2cap.h8
-rw-r--r--include/net/bluetooth/mgmt.h63
-rw-r--r--include/net/bluetooth/rfcomm.h10
-rw-r--r--include/net/cfg80211.h90
-rw-r--r--include/net/checksum.h23
-rw-r--r--include/net/cls_cgroup.h2
-rw-r--r--include/net/datalink.h2
-rw-r--r--include/net/dn.h2
-rw-r--r--include/net/dn_route.h2
-rw-r--r--include/net/dst.h18
-rw-r--r--include/net/ethoc.h1
-rw-r--r--include/net/flow.h6
-rw-r--r--include/net/flowcache.h25
-rw-r--r--include/net/ieee80211_radiotap.h4
-rw-r--r--include/net/ieee802154.h28
-rw-r--r--include/net/ieee802154_netdev.h195
-rw-r--r--include/net/if_inet6.h4
-rw-r--r--include/net/ip.h13
-rw-r--r--include/net/ip6_fib.h3
-rw-r--r--include/net/ip6_route.h14
-rw-r--r--include/net/ip_tunnels.h1
-rw-r--r--include/net/ipx.h11
-rw-r--r--include/net/mac80211.h107
-rw-r--r--include/net/mac802154.h41
-rw-r--r--include/net/net_namespace.h12
-rw-r--r--include/net/netfilter/nf_conntrack.h13
-rw-r--r--include/net/netfilter/nf_conntrack_core.h9
-rw-r--r--include/net/netfilter/nf_conntrack_labels.h4
-rw-r--r--include/net/netfilter/nf_tables.h37
-rw-r--r--include/net/netfilter/nft_reject.h25
-rw-r--r--include/net/netns/conntrack.h13
-rw-r--r--include/net/netns/ieee802154_6lowpan.h22
-rw-r--r--include/net/netns/xfrm.h11
-rw-r--r--include/net/netprio_cgroup.h17
-rw-r--r--include/net/nfc/digital.h7
-rw-r--r--include/net/nfc/nfc.h3
-rw-r--r--include/net/nl802154.h6
-rw-r--r--include/net/regulatory.h21
-rw-r--r--include/net/route.h1
-rw-r--r--include/net/rtnetlink.h2
-rw-r--r--include/net/sctp/structs.h14
-rw-r--r--include/net/sock.h45
-rw-r--r--include/net/tc_act/tc_csum.h4
-rw-r--r--include/net/tc_act/tc_defact.h4
-rw-r--r--include/net/tc_act/tc_gact.h4
-rw-r--r--include/net/tc_act/tc_ipt.h4
-rw-r--r--include/net/tc_act/tc_mirred.h4
-rw-r--r--include/net/tc_act/tc_nat.h4
-rw-r--r--include/net/tc_act/tc_pedit.h4
-rw-r--r--include/net/tc_act/tc_skbedit.h4
-rw-r--r--include/net/tcp.h27
-rw-r--r--include/net/wpan-phy.h19
-rw-r--r--include/net/xfrm.h139
-rw-r--r--include/rdma/ib_cm.h1
-rw-r--r--include/rdma/ib_umem.h11
-rw-r--r--include/rdma/ib_verbs.h204
-rw-r--r--include/scsi/libiscsi.h21
-rw-r--r--include/scsi/libiscsi_tcp.h2
-rw-r--r--include/scsi/libsas.h1
-rw-r--r--include/scsi/scsi_cmnd.h6
-rw-r--r--include/scsi/scsi_device.h22
-rw-r--r--include/scsi/scsi_host.h7
-rw-r--r--include/scsi/scsi_transport_fc.h1
-rw-r--r--include/scsi/scsi_transport_iscsi.h1
-rw-r--r--include/scsi/scsi_transport_srp.h1
-rw-r--r--include/sound/core.h113
-rw-r--r--include/sound/emu10k1.h2
-rw-r--r--include/sound/hwdep.h3
-rw-r--r--include/sound/pcm.h8
-rw-r--r--include/sound/rawmidi.h2
-rw-r--r--include/sound/rcar_snd.h36
-rw-r--r--include/sound/simple_card.h6
-rw-r--r--include/sound/soc-dai.h3
-rw-r--r--include/sound/soc-dapm.h48
-rw-r--r--include/sound/soc.h152
-rw-r--r--include/target/iscsi/iscsi_transport.h1
-rw-r--r--include/target/target_core_base.h1
-rw-r--r--include/trace/events/bcache.h52
-rw-r--r--include/trace/events/block.h33
-rw-r--r--include/trace/events/btrfs.h137
-rw-r--r--include/trace/events/hswadsp.h384
-rw-r--r--include/trace/events/intel-sst.h148
-rw-r--r--include/trace/events/migrate.h2
-rw-r--r--include/trace/events/net.h12
-rw-r--r--include/trace/events/power.h11
-rw-r--r--include/trace/events/sunrpc.h4
-rw-r--r--include/trace/events/v4l2.h1
-rw-r--r--include/trace/events/writeback.h7
-rw-r--r--include/trace/ftrace.h45
-rw-r--r--include/uapi/asm-generic/fcntl.h19
-rw-r--r--include/uapi/asm-generic/unistd.h7
-rw-r--r--include/uapi/drm/drm.h2
-rw-r--r--include/uapi/drm/vmwgfx_drm.h1
-rw-r--r--include/uapi/linux/Kbuild1
-rw-r--r--include/uapi/linux/btrfs.h1
-rw-r--r--include/uapi/linux/can.h32
-rw-r--r--include/uapi/linux/can/netlink.h3
-rw-r--r--include/uapi/linux/capi.h2
-rw-r--r--include/uapi/linux/ethtool.h439
-rw-r--r--include/uapi/linux/fs.h3
-rw-r--r--include/uapi/linux/fuse.h7
-rw-r--r--include/uapi/linux/gfs2_ondisk.h12
-rw-r--r--include/uapi/linux/hyperv.h390
-rw-r--r--include/uapi/linux/if.h134
-rw-r--r--include/uapi/linux/if_ether.h6
-rw-r--r--include/uapi/linux/if_link.h1
-rw-r--r--include/uapi/linux/in.h4
-rw-r--r--include/uapi/linux/in6.h27
-rw-r--r--include/uapi/linux/kvm.h83
-rw-r--r--include/uapi/linux/libc-compat.h9
-rw-r--r--include/uapi/linux/mic_ioctl.h2
-rw-r--r--include/uapi/linux/mpls.h34
-rw-r--r--include/uapi/linux/netdevice.h6
-rw-r--r--include/uapi/linux/netfilter/ipset/ip_set.h12
-rw-r--r--include/uapi/linux/netfilter/nf_tables.h6
-rw-r--r--include/uapi/linux/nfc.h9
-rw-r--r--include/uapi/linux/nl80211.h92
-rw-r--r--include/uapi/linux/pfkeyv2.h15
-rw-r--r--include/uapi/linux/ptp_clock.h39
-rw-r--r--include/uapi/linux/snmp.h6
-rw-r--r--include/uapi/linux/spi/spidev.h14
-rw-r--r--include/uapi/linux/tcp.h3
-rw-r--r--include/uapi/linux/tcp_metrics.h7
-rw-r--r--include/uapi/linux/uhid.h23
-rw-r--r--include/uapi/linux/uinput.h13
-rw-r--r--include/uapi/linux/usb/cdc.h12
-rw-r--r--include/uapi/linux/usb/functionfs.h44
-rw-r--r--include/uapi/linux/usbdevice_fs.h12
-rw-r--r--include/uapi/linux/v4l2-common.h8
-rw-r--r--include/uapi/linux/v4l2-controls.h19
-rw-r--r--include/uapi/linux/v4l2-dv-timings.h17
-rw-r--r--include/uapi/linux/v4l2-subdev.h14
-rw-r--r--include/uapi/linux/vfio.h6
-rw-r--r--include/uapi/linux/videodev2.h74
-rw-r--r--include/uapi/linux/xattr.h7
-rw-r--r--include/uapi/linux/xfrm.h10
-rw-r--r--include/uapi/mtd/ubi-user.h22
-rw-r--r--include/uapi/xen/Kbuild2
-rw-r--r--include/uapi/xen/gntalloc.h (renamed from include/xen/gntalloc.h)0
-rw-r--r--include/uapi/xen/gntdev.h (renamed from include/xen/gntdev.h)0
-rw-r--r--include/video/sgivw.h681
-rw-r--r--include/xen/events.h6
-rw-r--r--include/xen/interface/io/blkif.h34
-rw-r--r--include/xen/interface/physdev.h10
-rw-r--r--include/xen/interface/xencomm.h41
-rw-r--r--include/xen/xen-ops.h4
-rw-r--r--include/xen/xenbus.h1
-rw-r--r--include/xen/xencomm.h77
-rw-r--r--init/Kconfig28
-rw-r--r--init/do_mounts.c4
-rw-r--r--init/main.c2
-rw-r--r--ipc/compat.c25
-rw-r--r--ipc/compat_mq.c51
-rw-r--r--ipc/mq_sysctl.c18
-rw-r--r--ipc/mqueue.c6
-rw-r--r--ipc/msg.c2
-rw-r--r--kernel/Makefile5
-rw-r--r--kernel/audit.c43
-rw-r--r--kernel/audit.h2
-rw-r--r--kernel/audit_tree.c2
-rw-r--r--kernel/audit_watch.c2
-rw-r--r--kernel/auditfilter.c10
-rw-r--r--kernel/capability.c29
-rw-r--r--kernel/cgroup.c3740
-rw-r--r--kernel/cgroup_freezer.c40
-rw-r--r--kernel/compat.c212
-rw-r--r--kernel/cpu/Makefile1
-rw-r--r--kernel/cpu/idle.c144
-rw-r--r--kernel/cpuset.c274
-rw-r--r--kernel/debug/debug_core.c2
-rw-r--r--kernel/events/core.c76
-rw-r--r--kernel/exit.c2
-rw-r--r--kernel/extable.c2
-rw-r--r--kernel/fork.c6
-rw-r--r--kernel/futex.c90
-rw-r--r--kernel/futex_compat.c2
-rw-r--r--kernel/groups.c14
-rw-r--r--kernel/hrtimer.c15
-rw-r--r--kernel/hung_task.c3
-rw-r--r--kernel/irq/chip.c48
-rw-r--r--kernel/irq/devres.c45
-rw-r--r--kernel/irq/handle.c5
-rw-r--r--kernel/irq/internals.h9
-rw-r--r--kernel/irq/irqdesc.c6
-rw-r--r--kernel/irq/irqdomain.c1
-rw-r--r--kernel/irq/manage.c132
-rw-r--r--kernel/irq/proc.c8
-rw-r--r--kernel/irq_work.c6
-rw-r--r--kernel/kexec.c12
-rw-r--r--kernel/ksysfs.c2
-rw-r--r--kernel/kthread.c4
-rw-r--r--kernel/locking/Makefile3
-rw-r--r--kernel/locking/lockdep.c23
-rw-r--r--kernel/locking/locktorture.c452
-rw-r--r--kernel/locking/mcs_spinlock.c178
-rw-r--r--kernel/locking/mcs_spinlock.h129
-rw-r--r--kernel/locking/mutex-debug.c6
-rw-r--r--kernel/locking/mutex.c104
-rw-r--r--kernel/locking/rtmutex.c12
-rw-r--r--kernel/locking/rwsem-xadd.c4
-rw-r--r--kernel/module.c6
-rw-r--r--kernel/notifier.c2
-rw-r--r--kernel/panic.c4
-rw-r--r--kernel/pid_namespace.c4
-rw-r--r--kernel/power/console.c1
-rw-r--r--kernel/power/hibernate.c22
-rw-r--r--kernel/power/main.c4
-rw-r--r--kernel/power/power.h2
-rw-r--r--kernel/power/qos.c18
-rw-r--r--kernel/power/snapshot.c2
-rw-r--r--kernel/power/suspend.c2
-rw-r--r--kernel/power/wakelock.c2
-rw-r--r--kernel/printk/printk.c17
-rw-r--r--kernel/profile.c6
-rw-r--r--kernel/ptrace.c4
-rw-r--r--kernel/rcu/Makefile2
-rw-r--r--kernel/rcu/rcu.h7
-rw-r--r--kernel/rcu/rcutorture.c (renamed from kernel/rcu/torture.c)1004
-rw-r--r--kernel/rcu/srcu.c11
-rw-r--r--kernel/rcu/tiny.c8
-rw-r--r--kernel/rcu/tiny_plugin.h4
-rw-r--r--kernel/rcu/tree.c80
-rw-r--r--kernel/rcu/tree.h4
-rw-r--r--kernel/rcu/tree_plugin.h19
-rw-r--r--kernel/rcu/tree_trace.c6
-rw-r--r--kernel/rcu/update.c5
-rw-r--r--kernel/relay.c2
-rw-r--r--kernel/resource.c14
-rw-r--r--kernel/sched/Makefile2
-rw-r--r--kernel/sched/auto_group.c2
-rw-r--r--kernel/sched/clock.c4
-rw-r--r--kernel/sched/core.c271
-rw-r--r--kernel/sched/cpuacct.c6
-rw-r--r--kernel/sched/cpudeadline.c6
-rw-r--r--kernel/sched/cputime.c20
-rw-r--r--kernel/sched/deadline.c76
-rw-r--r--kernel/sched/debug.c10
-rw-r--r--kernel/sched/fair.c610
-rw-r--r--kernel/sched/idle.c265
-rw-r--r--kernel/sched/idle_task.c25
-rw-r--r--kernel/sched/rt.c110
-rw-r--r--kernel/sched/sched.h76
-rw-r--r--kernel/sched/stats.c2
-rw-r--r--kernel/sched/stop_task.c15
-rw-r--r--kernel/seccomp.c121
-rw-r--r--kernel/signal.c2
-rw-r--r--kernel/smp.c139
-rw-r--r--kernel/softirq.c1
-rw-r--r--kernel/stop_machine.c2
-rw-r--r--kernel/sys.c8
-rw-r--r--kernel/sys_ni.c2
-rw-r--r--kernel/sysctl.c23
-rw-r--r--kernel/time/Kconfig2
-rw-r--r--kernel/time/Makefile5
-rw-r--r--kernel/time/clockevents.c40
-rw-r--r--kernel/time/jiffies.c6
-rw-r--r--kernel/time/ntp.c5
-rw-r--r--kernel/time/sched_clock.c46
-rw-r--r--kernel/time/tick-broadcast-hrtimer.c106
-rw-r--r--kernel/time/tick-broadcast.c86
-rw-r--r--kernel/time/tick-common.c16
-rw-r--r--kernel/time/tick-internal.h11
-rw-r--r--kernel/time/timekeeping.c3
-rw-r--r--kernel/time/timekeeping_debug.c2
-rw-r--r--kernel/timer.c59
-rw-r--r--kernel/torture.c719
-rw-r--r--kernel/trace/blktrace.c23
-rw-r--r--kernel/trace/ftrace.c162
-rw-r--r--kernel/trace/ring_buffer.c7
-rw-r--r--kernel/trace/ring_buffer_benchmark.c6
-rw-r--r--kernel/trace/trace.c214
-rw-r--r--kernel/trace/trace.h38
-rw-r--r--kernel/trace/trace_event_perf.c22
-rw-r--r--kernel/trace/trace_events.c46
-rw-r--r--kernel/trace/trace_export.c7
-rw-r--r--kernel/trace/trace_functions.c143
-rw-r--r--kernel/trace/trace_functions_graph.c3
-rw-r--r--kernel/trace/trace_irqsoff.c14
-rw-r--r--kernel/trace/trace_kprobe.c17
-rw-r--r--kernel/trace/trace_nop.c5
-rw-r--r--kernel/trace/trace_output.c31
-rw-r--r--kernel/trace/trace_probe.h17
-rw-r--r--kernel/trace/trace_sched_wakeup.c10
-rw-r--r--kernel/trace/trace_stack.c3
-rw-r--r--kernel/trace/trace_uprobe.c191
-rw-r--r--kernel/tracepoint.c252
-rw-r--r--kernel/up.c6
-rw-r--r--kernel/user.c3
-rw-r--r--kernel/user_namespace.c4
-rw-r--r--kernel/watchdog.c19
-rw-r--r--kernel/workqueue.c16
-rw-r--r--lib/Kconfig.debug20
-rw-r--r--lib/clz_ctz.c7
-rw-r--r--lib/decompress_inflate.c1
-rw-r--r--lib/devres.c12
-rw-r--r--lib/dma-debug.c131
-rw-r--r--lib/fonts/Kconfig6
-rw-r--r--lib/idr.c10
-rw-r--r--lib/kobject.c2
-rw-r--r--lib/kobject_uevent.c42
-rw-r--r--lib/nlattr.c10
-rw-r--r--lib/percpu_ida.c7
-rw-r--r--lib/radix-tree.c389
-rw-r--r--lib/random32.c89
-rw-r--r--lib/string.c2
-rw-r--r--lib/syscall.c1
-rw-r--r--lib/vsprintf.c58
-rw-r--r--mm/Kconfig4
-rw-r--r--mm/Makefile2
-rw-r--r--mm/backing-dev.c16
-rw-r--r--mm/compaction.c32
-rw-r--r--mm/filemap.c490
-rw-r--r--mm/fremap.c28
-rw-r--r--mm/huge_memory.c99
-rw-r--r--mm/hugetlb.c294
-rw-r--r--mm/hugetlb_cgroup.c11
-rw-r--r--mm/kmemleak.c140
-rw-r--r--mm/ksm.c2
-rw-r--r--mm/list_lru.c16
-rw-r--r--mm/memcontrol.c130
-rw-r--r--mm/memory-failure.c16
-rw-r--r--mm/memory.c415
-rw-r--r--mm/mempolicy.c104
-rw-r--r--mm/migrate.c43
-rw-r--r--mm/mincore.c20
-rw-r--r--mm/mmap.c24
-rw-r--r--mm/mmu_context.c3
-rw-r--r--mm/mprotect.c25
-rw-r--r--mm/nobootmem.c2
-rw-r--r--mm/nommu.c2
-rw-r--r--mm/page_alloc.c38
-rw-r--r--mm/page_cgroup.c12
-rw-r--r--mm/percpu.c208
-rw-r--r--mm/process_vm_access.c28
-rw-r--r--mm/readahead.c10
-rw-r--r--mm/rmap.c15
-rw-r--r--mm/shmem.c124
-rw-r--r--mm/slab.c4
-rw-r--r--mm/slub.c62
-rw-r--r--mm/sparse.c2
-rw-r--r--mm/swap.c57
-rw-r--r--mm/truncate.c148
-rw-r--r--mm/vmpressure.c1
-rw-r--r--mm/vmscan.c122
-rw-r--r--mm/vmstat.c6
-rw-r--r--mm/workingset.c414
-rw-r--r--net/8021q/vlan.c4
-rw-r--r--net/8021q/vlan.h4
-rw-r--r--net/8021q/vlan_core.c10
-rw-r--r--net/8021q/vlan_dev.c31
-rw-r--r--net/8021q/vlan_netlink.c4
-rw-r--r--net/9p/client.c2
-rw-r--r--net/9p/trans_virtio.c5
-rw-r--r--net/Kconfig6
-rw-r--r--net/appletalk/aarp.c4
-rw-r--r--net/appletalk/ddp.c100
-rw-r--r--net/atm/mpc.c2
-rw-r--r--net/batman-adv/Kconfig9
-rw-r--r--net/batman-adv/Makefile1
-rw-r--r--net/batman-adv/bat_iv_ogm.c40
-rw-r--r--net/batman-adv/bridge_loop_avoidance.c35
-rw-r--r--net/batman-adv/distributed-arp-table.c9
-rw-r--r--net/batman-adv/distributed-arp-table.h3
-rw-r--r--net/batman-adv/fragmentation.c4
-rw-r--r--net/batman-adv/gateway_client.c10
-rw-r--r--net/batman-adv/hard-interface.c22
-rw-r--r--net/batman-adv/icmp_socket.c11
-rw-r--r--net/batman-adv/main.c19
-rw-r--r--net/batman-adv/main.h4
-rw-r--r--net/batman-adv/multicast.c748
-rw-r--r--net/batman-adv/multicast.h80
-rw-r--r--net/batman-adv/network-coding.c26
-rw-r--r--net/batman-adv/originator.c47
-rw-r--r--net/batman-adv/originator.h4
-rw-r--r--net/batman-adv/packet.h53
-rw-r--r--net/batman-adv/routing.c21
-rw-r--r--net/batman-adv/send.c26
-rw-r--r--net/batman-adv/send.h7
-rw-r--r--net/batman-adv/soft-interface.c48
-rw-r--r--net/batman-adv/sysfs.c6
-rw-r--r--net/batman-adv/translation-table.c163
-rw-r--r--net/batman-adv/translation-table.h2
-rw-r--r--net/batman-adv/types.h90
-rw-r--r--net/bluetooth/6lowpan.c2
-rw-r--r--net/bluetooth/6lowpan.h21
-rw-r--r--net/bluetooth/Kconfig8
-rw-r--r--net/bluetooth/Makefile3
-rw-r--r--net/bluetooth/a2mp.c20
-rw-r--r--net/bluetooth/af_bluetooth.c2
-rw-r--r--net/bluetooth/hci_conn.c239
-rw-r--r--net/bluetooth/hci_core.c1197
-rw-r--r--net/bluetooth/hci_event.c566
-rw-r--r--net/bluetooth/hci_sock.c17
-rw-r--r--net/bluetooth/hci_sysfs.c18
-rw-r--r--net/bluetooth/hidp/core.c116
-rw-r--r--net/bluetooth/hidp/hidp.h4
-rw-r--r--net/bluetooth/l2cap_core.c706
-rw-r--r--net/bluetooth/l2cap_sock.c69
-rw-r--r--net/bluetooth/mgmt.c974
-rw-r--r--net/bluetooth/rfcomm/core.c96
-rw-r--r--net/bluetooth/rfcomm/sock.c34
-rw-r--r--net/bluetooth/rfcomm/tty.c262
-rw-r--r--net/bluetooth/sco.c10
-rw-r--r--net/bluetooth/smp.c585
-rw-r--r--net/bluetooth/smp.h21
-rw-r--r--net/bridge/br_device.c78
-rw-r--r--net/bridge/br_fdb.c137
-rw-r--r--net/bridge/br_forward.c9
-rw-r--r--net/bridge/br_if.c8
-rw-r--r--net/bridge/br_input.c15
-rw-r--r--net/bridge/br_multicast.c37
-rw-r--r--net/bridge/br_netfilter.c4
-rw-r--r--net/bridge/br_private.h21
-rw-r--r--net/bridge/br_stp_if.c2
-rw-r--r--net/bridge/br_vlan.c79
-rw-r--r--net/bridge/netfilter/ebt_among.c2
-rw-r--r--net/bridge/netfilter/ebt_dnat.c2
-rw-r--r--net/bridge/netfilter/ebt_redirect.c6
-rw-r--r--net/bridge/netfilter/ebt_snat.c2
-rw-r--r--net/caif/caif_dev.c1
-rw-r--r--net/caif/cfsrvl.c1
-rw-r--r--net/can/af_can.c3
-rw-r--r--net/can/bcm.c4
-rw-r--r--net/can/raw.c27
-rw-r--r--net/ceph/osd_client.c2
-rw-r--r--net/compat.c32
-rw-r--r--net/core/Makefile1
-rw-r--r--net/core/dev.c200
-rw-r--r--net/core/fib_rules.c7
-rw-r--r--net/core/filter.c1567
-rw-r--r--net/core/flow.c132
-rw-r--r--net/core/flow_dissector.c44
-rw-r--r--net/core/neighbour.c17
-rw-r--r--net/core/net-sysfs.c24
-rw-r--r--net/core/netclassid_cgroup.c15
-rw-r--r--net/core/netpoll.c591
-rw-r--r--net/core/netprio_cgroup.c41
-rw-r--r--net/core/pktgen.c32
-rw-r--r--net/core/ptp_classifier.c141
-rw-r--r--net/core/request_sock.c1
-rw-r--r--net/core/rtnetlink.c144
-rw-r--r--net/core/skbuff.c297
-rw-r--r--net/core/sock.c11
-rw-r--r--net/core/sock_diag.c23
-rw-r--r--net/core/timestamping.c19
-rw-r--r--net/dccp/ccids/lib/tfrc.c2
-rw-r--r--net/dccp/ccids/lib/tfrc.h1
-rw-r--r--net/decnet/af_decnet.c5
-rw-r--r--net/hsr/hsr_device.c10
-rw-r--r--net/hsr/hsr_framereg.c22
-rw-r--r--net/hsr/hsr_main.c6
-rw-r--r--net/ieee802154/6lowpan_iphc.c3
-rw-r--r--net/ieee802154/6lowpan_rtnl.c (renamed from net/ieee802154/6lowpan.c)411
-rw-r--r--net/ieee802154/Kconfig2
-rw-r--r--net/ieee802154/Makefile6
-rw-r--r--net/ieee802154/af802154.h5
-rw-r--r--net/ieee802154/af_ieee802154.c22
-rw-r--r--net/ieee802154/dgram.c60
-rw-r--r--net/ieee802154/header_ops.c287
-rw-r--r--net/ieee802154/ieee802154.h1
-rw-r--r--net/ieee802154/netlink.c1
-rw-r--r--net/ieee802154/nl-mac.c220
-rw-r--r--net/ieee802154/nl_policy.c10
-rw-r--r--net/ieee802154/raw.c18
-rw-r--r--net/ieee802154/reassembly.c571
-rw-r--r--net/ieee802154/reassembly.h41
-rw-r--r--net/ieee802154/wpan-class.c4
-rw-r--r--net/ipv4/Makefile2
-rw-r--r--net/ipv4/af_inet.c11
-rw-r--r--net/ipv4/ah4.c78
-rw-r--r--net/ipv4/devinet.c3
-rw-r--r--net/ipv4/esp4.c26
-rw-r--r--net/ipv4/fib_frontend.c2
-rw-r--r--net/ipv4/gre_demux.c8
-rw-r--r--net/ipv4/inet_fragment.c5
-rw-r--r--net/ipv4/ip_forward.c78
-rw-r--r--net/ipv4/ip_output.c15
-rw-r--r--net/ipv4/ip_sockglue.c21
-rw-r--r--net/ipv4/ip_tunnel.c116
-rw-r--r--net/ipv4/ip_tunnel_core.c46
-rw-r--r--net/ipv4/ip_vti.c310
-rw-r--r--net/ipv4/ipcomp.c26
-rw-r--r--net/ipv4/ipconfig.c2
-rw-r--r--net/ipv4/ipmr.c13
-rw-r--r--net/ipv4/netfilter.c2
-rw-r--r--net/ipv4/netfilter/Kconfig5
-rw-r--r--net/ipv4/netfilter/Makefile1
-rw-r--r--net/ipv4/netfilter/nf_nat_h323.c5
-rw-r--r--net/ipv4/netfilter/nf_nat_snmp_basic.c4
-rw-r--r--net/ipv4/netfilter/nft_reject_ipv4.c75
-rw-r--r--net/ipv4/ping.c2
-rw-r--r--net/ipv4/proc.c6
-rw-r--r--net/ipv4/raw.c2
-rw-r--r--net/ipv4/route.c25
-rw-r--r--net/ipv4/tcp.c23
-rw-r--r--net/ipv4/tcp_cong.c13
-rw-r--r--net/ipv4/tcp_cubic.c4
-rw-r--r--net/ipv4/tcp_highspeed.c1
-rw-r--r--net/ipv4/tcp_hybla.c13
-rw-r--r--net/ipv4/tcp_illinois.c2
-rw-r--r--net/ipv4/tcp_input.c196
-rw-r--r--net/ipv4/tcp_ipv4.c10
-rw-r--r--net/ipv4/tcp_lp.c2
-rw-r--r--net/ipv4/tcp_memcontrol.c4
-rw-r--r--net/ipv4/tcp_metrics.c83
-rw-r--r--net/ipv4/tcp_minisocks.c4
-rw-r--r--net/ipv4/tcp_output.c117
-rw-r--r--net/ipv4/tcp_probe.c2
-rw-r--r--net/ipv4/tcp_scalable.c1
-rw-r--r--net/ipv4/tcp_timer.c3
-rw-r--r--net/ipv4/tcp_vegas.c2
-rw-r--r--net/ipv4/tcp_veno.c1
-rw-r--r--net/ipv4/tcp_westwood.c1
-rw-r--r--net/ipv4/tcp_yeah.c2
-rw-r--r--net/ipv4/udp.c3
-rw-r--r--net/ipv4/udp_offload.c17
-rw-r--r--net/ipv4/xfrm4_input.c9
-rw-r--r--net/ipv4/xfrm4_mode_tunnel.c68
-rw-r--r--net/ipv4/xfrm4_policy.c1
-rw-r--r--net/ipv4/xfrm4_protocol.c286
-rw-r--r--net/ipv6/Kconfig1
-rw-r--r--net/ipv6/Makefile2
-rw-r--r--net/ipv6/addrconf.c200
-rw-r--r--net/ipv6/addrlabel.c59
-rw-r--r--net/ipv6/ah6.c80
-rw-r--r--net/ipv6/esp6.c26
-rw-r--r--net/ipv6/exthdrs_core.c2
-rw-r--r--net/ipv6/exthdrs_offload.c4
-rw-r--r--net/ipv6/icmp.c4
-rw-r--r--net/ipv6/ip6_checksum.c4
-rw-r--r--net/ipv6/ip6_fib.c121
-rw-r--r--net/ipv6/ip6_flowlabel.c6
-rw-r--r--net/ipv6/ip6_gre.c9
-rw-r--r--net/ipv6/ip6_offload.c20
-rw-r--r--net/ipv6/ip6_output.c53
-rw-r--r--net/ipv6/ip6_tunnel.c13
-rw-r--r--net/ipv6/ip6_vti.c316
-rw-r--r--net/ipv6/ip6mr.c13
-rw-r--r--net/ipv6/ipcomp6.c22
-rw-r--r--net/ipv6/ipv6_sockglue.c2
-rw-r--r--net/ipv6/mcast.c11
-rw-r--r--net/ipv6/netfilter/Kconfig5
-rw-r--r--net/ipv6/netfilter/Makefile1
-rw-r--r--net/ipv6/netfilter/nft_reject_ipv6.c76
-rw-r--r--net/ipv6/output_core.c27
-rw-r--r--net/ipv6/ping.c5
-rw-r--r--net/ipv6/route.c52
-rw-r--r--net/ipv6/sit.c29
-rw-r--r--net/ipv6/tcp_ipv6.c46
-rw-r--r--net/ipv6/udp_offload.c2
-rw-r--r--net/ipv6/xfrm6_mode_tunnel.c63
-rw-r--r--net/ipv6/xfrm6_policy.c7
-rw-r--r--net/ipv6/xfrm6_protocol.c270
-rw-r--r--net/ipx/af_ipx.c50
-rw-r--r--net/ipx/ipx_route.c4
-rw-r--r--net/iucv/af_iucv.c1
-rw-r--r--net/key/af_key.c58
-rw-r--r--net/l2tp/l2tp_core.c30
-rw-r--r--net/l2tp/l2tp_core.h1
-rw-r--r--net/l2tp/l2tp_netlink.c4
-rw-r--r--net/l2tp/l2tp_ppp.c16
-rw-r--r--net/mac80211/agg-tx.c2
-rw-r--r--net/mac80211/cfg.c350
-rw-r--r--net/mac80211/cfg.h2
-rw-r--r--net/mac80211/chan.c8
-rw-r--r--net/mac80211/debugfs_netdev.c13
-rw-r--r--net/mac80211/debugfs_sta.c2
-rw-r--r--net/mac80211/driver-ops.h12
-rw-r--r--net/mac80211/ht.c8
-rw-r--r--net/mac80211/ibss.c50
-rw-r--r--net/mac80211/ieee80211_i.h27
-rw-r--r--net/mac80211/iface.c46
-rw-r--r--net/mac80211/main.c21
-rw-r--r--net/mac80211/mesh.c96
-rw-r--r--net/mac80211/mesh_ps.c1
-rw-r--r--net/mac80211/mlme.c203
-rw-r--r--net/mac80211/pm.c14
-rw-r--r--net/mac80211/rate.c46
-rw-r--r--net/mac80211/rate.h2
-rw-r--r--net/mac80211/rc80211_minstrel.c2
-rw-r--r--net/mac80211/rc80211_minstrel.h2
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c7
-rw-r--r--net/mac80211/rc80211_pid_algo.c2
-rw-r--r--net/mac80211/rx.c116
-rw-r--r--net/mac80211/scan.c15
-rw-r--r--net/mac80211/sta_info.c67
-rw-r--r--net/mac80211/sta_info.h9
-rw-r--r--net/mac80211/status.c3
-rw-r--r--net/mac80211/tx.c52
-rw-r--r--net/mac80211/util.c90
-rw-r--r--net/mac80211/vht.c26
-rw-r--r--net/mac80211/wme.c5
-rw-r--r--net/mac80211/wpa.c9
-rw-r--r--net/mac802154/Makefile2
-rw-r--r--net/mac802154/ieee802154_dev.c85
-rw-r--r--net/mac802154/mac802154.h19
-rw-r--r--net/mac802154/mac_cmd.c5
-rw-r--r--net/mac802154/mib.c26
-rw-r--r--net/mac802154/rx.c1
-rw-r--r--net/mac802154/wpan.c457
-rw-r--r--net/netfilter/Kconfig6
-rw-r--r--net/netfilter/Makefile1
-rw-r--r--net/netfilter/ipset/Kconfig9
-rw-r--r--net/netfilter/ipset/Makefile1
-rw-r--r--net/netfilter/ipset/ip_set_core.c54
-rw-r--r--net/netfilter/ipset/ip_set_hash_gen.h43
-rw-r--r--net/netfilter/ipset/ip_set_hash_ip.c3
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipmark.c321
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipport.c3
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportip.c3
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportnet.c3
-rw-r--r--net/netfilter/ipset/ip_set_hash_net.c3
-rw-r--r--net/netfilter/ipset/ip_set_hash_netiface.c3
-rw-r--r--net/netfilter/ipset/ip_set_hash_netnet.c10
-rw-r--r--net/netfilter/ipset/ip_set_hash_netport.c3
-rw-r--r--net/netfilter/ipset/ip_set_hash_netportnet.c3
-rw-r--r--net/netfilter/ipset/pfxlen.c4
-rw-r--r--net/netfilter/ipvs/ip_vs_conn.c8
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c6
-rw-r--r--net/netfilter/ipvs/ip_vs_lblc.c13
-rw-r--r--net/netfilter/nf_conntrack_core.c479
-rw-r--r--net/netfilter/nf_conntrack_expect.c36
-rw-r--r--net/netfilter/nf_conntrack_h323_main.c4
-rw-r--r--net/netfilter/nf_conntrack_helper.c41
-rw-r--r--net/netfilter/nf_conntrack_netlink.c168
-rw-r--r--net/netfilter/nf_conntrack_sip.c8
-rw-r--r--net/netfilter/nf_nat_core.c56
-rw-r--r--net/netfilter/nf_synproxy_core.c5
-rw-r--r--net/netfilter/nf_tables_api.c160
-rw-r--r--net/netfilter/nf_tables_core.c6
-rw-r--r--net/netfilter/nfnetlink.c8
-rw-r--r--net/netfilter/nfnetlink_log.c8
-rw-r--r--net/netfilter/nfnetlink_queue_core.c9
-rw-r--r--net/netfilter/nft_compat.c4
-rw-r--r--net/netfilter/nft_ct.c52
-rw-r--r--net/netfilter/nft_hash.c261
-rw-r--r--net/netfilter/nft_immediate.c3
-rw-r--r--net/netfilter/nft_log.c8
-rw-r--r--net/netfilter/nft_lookup.c6
-rw-r--r--net/netfilter/nft_meta.c4
-rw-r--r--net/netfilter/nft_nat.c22
-rw-r--r--net/netfilter/nft_payload.c3
-rw-r--r--net/netfilter/nft_queue.c4
-rw-r--r--net/netfilter/nft_rbtree.c16
-rw-r--r--net/netfilter/nft_reject.c89
-rw-r--r--net/netfilter/nft_reject_inet.c63
-rw-r--r--net/netfilter/xt_AUDIT.c4
-rw-r--r--net/netfilter/xt_CT.c7
-rw-r--r--net/netfilter/xt_connlimit.c311
-rw-r--r--net/netfilter/xt_ipcomp.c2
-rw-r--r--net/netlink/af_netlink.c35
-rw-r--r--net/netlink/af_netlink.h1
-rw-r--r--net/nfc/core.c10
-rw-r--r--net/nfc/digital.h6
-rw-r--r--net/nfc/digital_core.c67
-rw-r--r--net/nfc/digital_technology.c247
-rw-r--r--net/nfc/hci/llc.c4
-rw-r--r--net/nfc/llcp_core.c16
-rw-r--r--net/nfc/nci/core.c5
-rw-r--r--net/nfc/nci/spi.c3
-rw-r--r--net/nfc/netlink.c8
-rw-r--r--net/openvswitch/datapath.c58
-rw-r--r--net/openvswitch/datapath.h2
-rw-r--r--net/openvswitch/flow.c29
-rw-r--r--net/openvswitch/flow_table.c88
-rw-r--r--net/openvswitch/flow_table.h2
-rw-r--r--net/openvswitch/vport.c14
-rw-r--r--net/packet/af_packet.c85
-rw-r--r--net/rds/iw.c3
-rw-r--r--net/rfkill/core.c9
-rw-r--r--net/rxrpc/Makefile5
-rw-r--r--net/rxrpc/af_rxrpc.c9
-rw-r--r--net/rxrpc/ar-ack.c61
-rw-r--r--net/rxrpc/ar-call.c213
-rw-r--r--net/rxrpc/ar-connection.c10
-rw-r--r--net/rxrpc/ar-error.c1
-rw-r--r--net/rxrpc/ar-input.c190
-rw-r--r--net/rxrpc/ar-internal.h40
-rw-r--r--net/rxrpc/ar-output.c15
-rw-r--r--net/rxrpc/ar-recvmsg.c25
-rw-r--r--net/rxrpc/ar-skbuff.c7
-rw-r--r--net/rxrpc/ar-transport.c10
-rw-r--r--net/rxrpc/sysctl.c146
-rw-r--r--net/sched/act_api.c142
-rw-r--r--net/sched/act_csum.c31
-rw-r--r--net/sched/act_gact.c34
-rw-r--r--net/sched/act_ipt.c68
-rw-r--r--net/sched/act_mirred.c56
-rw-r--r--net/sched/act_nat.c33
-rw-r--r--net/sched/act_pedit.c45
-rw-r--r--net/sched/act_police.c22
-rw-r--r--net/sched/act_simple.c64
-rw-r--r--net/sched/act_skbedit.c36
-rw-r--r--net/sched/cls_fw.c33
-rw-r--r--net/sched/sch_api.c15
-rw-r--r--net/sched/sch_atm.c3
-rw-r--r--net/sched/sch_cbq.c6
-rw-r--r--net/sched/sch_fq.c24
-rw-r--r--net/sched/sch_fq_codel.c3
-rw-r--r--net/sched/sch_generic.c2
-rw-r--r--net/sched/sch_hfsc.c3
-rw-r--r--net/sched/sch_hhf.c3
-rw-r--r--net/sched/sch_htb.c20
-rw-r--r--net/sched/sch_ingress.c3
-rw-r--r--net/sched/sch_netem.c79
-rw-r--r--net/sched/sch_pie.c21
-rw-r--r--net/sched/sch_tbf.c50
-rw-r--r--net/sctp/associola.c210
-rw-r--r--net/sctp/ipv6.c2
-rw-r--r--net/sctp/sm_make_chunk.c4
-rw-r--r--net/sctp/sm_sideeffect.c7
-rw-r--r--net/sctp/sm_statefuns.c12
-rw-r--r--net/sctp/socket.c47
-rw-r--r--net/sctp/sysctl.c18
-rw-r--r--net/sctp/transport.c1
-rw-r--r--net/sctp/ulpevent.c8
-rw-r--r--net/socket.c35
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c19
-rw-r--r--net/sunrpc/backchannel_rqst.c6
-rw-r--r--net/sunrpc/svc_xprt.c6
-rw-r--r--net/sunrpc/xprtsock.c6
-rw-r--r--net/tipc/addr.h2
-rw-r--r--net/tipc/bcast.c41
-rw-r--r--net/tipc/bcast.h4
-rw-r--r--net/tipc/bearer.c103
-rw-r--r--net/tipc/bearer.h13
-rw-r--r--net/tipc/config.c114
-rw-r--r--net/tipc/config.h5
-rw-r--r--net/tipc/core.c108
-rw-r--r--net/tipc/core.h3
-rw-r--r--net/tipc/discover.c23
-rw-r--r--net/tipc/discover.h5
-rw-r--r--net/tipc/handler.c1
-rw-r--r--net/tipc/link.c627
-rw-r--r--net/tipc/link.h57
-rw-r--r--net/tipc/name_distr.c22
-rw-r--r--net/tipc/name_distr.h2
-rw-r--r--net/tipc/name_table.c40
-rw-r--r--net/tipc/net.c19
-rw-r--r--net/tipc/netlink.c8
-rw-r--r--net/tipc/node.c119
-rw-r--r--net/tipc/node.h6
-rw-r--r--net/tipc/port.c301
-rw-r--r--net/tipc/port.h130
-rw-r--r--net/tipc/ref.c30
-rw-r--r--net/tipc/ref.h1
-rw-r--r--net/tipc/server.c19
-rw-r--r--net/tipc/server.h2
-rw-r--r--net/tipc/socket.c426
-rw-r--r--net/tipc/socket.h72
-rw-r--r--net/tipc/subscr.c48
-rw-r--r--net/unix/af_unix.c20
-rw-r--r--net/wireless/ap.c10
-rw-r--r--net/wireless/chan.c87
-rw-r--r--net/wireless/core.c23
-rw-r--r--net/wireless/core.h21
-rw-r--r--net/wireless/genregdb.awk10
-rw-r--r--net/wireless/ibss.c34
-rw-r--r--net/wireless/mesh.c12
-rw-r--r--net/wireless/mlme.c4
-rw-r--r--net/wireless/nl80211.c304
-rw-r--r--net/wireless/nl80211.h10
-rw-r--r--net/wireless/rdev-ops.h9
-rw-r--r--net/wireless/reg.c309
-rw-r--r--net/wireless/reg.h3
-rw-r--r--net/wireless/scan.c71
-rw-r--r--net/wireless/sme.c3
-rw-r--r--net/wireless/trace.h35
-rw-r--r--net/wireless/util.c57
-rw-r--r--net/wireless/wext-sme.c2
-rw-r--r--net/xfrm/xfrm_input.c97
-rw-r--r--net/xfrm/xfrm_policy.c42
-rw-r--r--net/xfrm/xfrm_state.c95
-rw-r--r--net/xfrm/xfrm_user.c48
-rw-r--r--samples/seccomp/Makefile14
-rw-r--r--scripts/Kbuild.include9
-rw-r--r--scripts/Makefile.build2
-rw-r--r--scripts/Makefile.lib13
-rwxr-xr-xscripts/checkpatch.pl239
-rw-r--r--scripts/dtc/dtc-parser.tab.c_shipped469
-rw-r--r--scripts/dtc/dtc-parser.tab.h_shipped36
-rw-r--r--scripts/dtc/dtc.c119
-rw-r--r--scripts/dtc/dtc.h1
-rw-r--r--scripts/dtc/srcpos.c6
-rwxr-xr-xscripts/dtc/update-dtc-source.sh54
-rw-r--r--scripts/dtc/util.c141
-rw-r--r--scripts/dtc/util.h107
-rw-r--r--scripts/dtc/version_gen.h2
-rw-r--r--scripts/gcc-ld29
-rw-r--r--scripts/gen_initramfs_list.sh2
-rw-r--r--scripts/genksyms/keywords.gperf5
-rw-r--r--scripts/genksyms/keywords.hash.c_shipped133
-rw-r--r--scripts/genksyms/lex.l51
-rw-r--r--scripts/genksyms/lex.lex.c_shipped51
-rw-r--r--scripts/genksyms/parse.tab.c_shipped608
-rw-r--r--scripts/genksyms/parse.tab.h_shipped29
-rw-r--r--scripts/genksyms/parse.y5
-rwxr-xr-xscripts/get_maintainer.pl2
-rwxr-xr-xscripts/ld-version.sh8
-rw-r--r--scripts/mod/devicetable-offsets.c3
-rw-r--r--scripts/mod/file2alias.c24
-rw-r--r--scripts/mod/modpost.c38
-rw-r--r--scripts/mod/modpost.h2
-rw-r--r--security/Makefile12
-rw-r--r--security/apparmor/lsm.c2
-rw-r--r--security/capability.c5
-rw-r--r--security/device_cgroup.c12
-rw-r--r--security/integrity/Makefile4
-rw-r--r--security/integrity/evm/Kconfig6
-rw-r--r--security/integrity/evm/evm.h28
-rw-r--r--security/integrity/evm/evm_crypto.c8
-rw-r--r--security/integrity/evm/evm_main.c6
-rw-r--r--security/integrity/evm/evm_secfs.c6
-rw-r--r--security/integrity/iint.c2
-rw-r--r--security/integrity/ima/ima.h2
-rw-r--r--security/integrity/ima/ima_api.c20
-rw-r--r--security/integrity/ima/ima_appraise.c4
-rw-r--r--security/integrity/ima/ima_crypto.c37
-rw-r--r--security/integrity/ima/ima_fs.c8
-rw-r--r--security/integrity/ima/ima_init.c9
-rw-r--r--security/integrity/ima/ima_main.c11
-rw-r--r--security/integrity/ima/ima_policy.c79
-rw-r--r--security/integrity/ima/ima_queue.c12
-rw-r--r--security/integrity/ima/ima_template.c19
-rw-r--r--security/integrity/ima/ima_template_lib.c29
-rw-r--r--security/integrity/integrity_audit.c7
-rw-r--r--security/keys/compat.c4
-rw-r--r--security/keys/encrypted-keys/encrypted.c2
-rw-r--r--security/keys/keyring.c6
-rw-r--r--security/keys/trusted.c6
-rw-r--r--security/security.c28
-rw-r--r--security/selinux/hooks.c76
-rw-r--r--security/selinux/include/security.h2
-rw-r--r--security/selinux/include/xfrm.h8
-rw-r--r--security/selinux/selinuxfs.c30
-rw-r--r--security/selinux/ss/policydb.c8
-rw-r--r--security/selinux/ss/services.c6
-rw-r--r--security/selinux/xfrm.c14
-rw-r--r--sound/aoa/aoa.h2
-rw-r--r--sound/aoa/codecs/onyx.c2
-rw-r--r--sound/aoa/codecs/tas.c2
-rw-r--r--sound/aoa/codecs/toonie.c2
-rw-r--r--sound/aoa/core/alsa.c7
-rw-r--r--sound/arm/aaci.c6
-rw-r--r--sound/arm/pxa2xx-ac97.c6
-rw-r--r--sound/atmel/abdac.c13
-rw-r--r--sound/atmel/ac97c.c10
-rw-r--r--sound/core/compress_offload.c2
-rw-r--r--sound/core/control.c17
-rw-r--r--sound/core/control_compat.c2
-rw-r--r--sound/core/device.c175
-rw-r--r--sound/core/hrtimer.c3
-rw-r--r--sound/core/hwdep.c53
-rw-r--r--sound/core/info.c15
-rw-r--r--sound/core/init.c186
-rw-r--r--sound/core/isadma.c2
-rw-r--r--sound/core/memalloc.c4
-rw-r--r--sound/core/oss/mixer_oss.c20
-rw-r--r--sound/core/oss/pcm_oss.c103
-rw-r--r--sound/core/pcm.c52
-rw-r--r--sound/core/pcm_lib.c28
-rw-r--r--sound/core/pcm_native.c51
-rw-r--r--sound/core/pcm_timer.c4
-rw-r--r--sound/core/rawmidi.c90
-rw-r--r--sound/core/rtctimer.c7
-rw-r--r--sound/core/seq/oss/seq_oss.c22
-rw-r--r--sound/core/seq/oss/seq_oss_device.h13
-rw-r--r--sound/core/seq/oss/seq_oss_init.c29
-rw-r--r--sound/core/seq/oss/seq_oss_ioctl.c18
-rw-r--r--sound/core/seq/oss/seq_oss_midi.c7
-rw-r--r--sound/core/seq/oss/seq_oss_readq.c4
-rw-r--r--sound/core/seq/oss/seq_oss_synth.c11
-rw-r--r--sound/core/seq/oss/seq_oss_timer.c7
-rw-r--r--sound/core/seq/seq_clientmgr.c16
-rw-r--r--sound/core/seq/seq_device.c18
-rw-r--r--sound/core/seq/seq_dummy.c2
-rw-r--r--sound/core/seq/seq_fifo.c2
-rw-r--r--sound/core/seq/seq_lock.c4
-rw-r--r--sound/core/seq/seq_memory.c8
-rw-r--r--sound/core/seq/seq_midi.c8
-rw-r--r--sound/core/seq/seq_midi_emul.c6
-rw-r--r--sound/core/seq/seq_ports.c4
-rw-r--r--sound/core/seq/seq_prioq.c14
-rw-r--r--sound/core/seq/seq_queue.c2
-rw-r--r--sound/core/seq/seq_timer.c10
-rw-r--r--sound/core/seq/seq_virmidi.c2
-rw-r--r--sound/core/sound.c29
-rw-r--r--sound/core/sound_oss.c7
-rw-r--r--sound/core/timer.c17
-rw-r--r--sound/core/vmaster.c2
-rw-r--r--sound/drivers/aloop.c4
-rw-r--r--sound/drivers/dummy.c6
-rw-r--r--sound/drivers/ml403-ac97cr.c5
-rw-r--r--sound/drivers/mpu401/mpu401.c12
-rw-r--r--sound/drivers/mtpav.c4
-rw-r--r--sound/drivers/mts64.c5
-rw-r--r--sound/drivers/opl3/opl3_lib.c4
-rw-r--r--sound/drivers/opl3/opl3_synth.c2
-rw-r--r--sound/drivers/pcsp/pcsp.c4
-rw-r--r--sound/drivers/pcsp/pcsp_input.c1
-rw-r--r--sound/drivers/portman2x4.c5
-rw-r--r--sound/drivers/serial-u16550.c5
-rw-r--r--sound/drivers/virmidi.c6
-rw-r--r--sound/firewire/dice.c4
-rw-r--r--sound/firewire/isight.c4
-rw-r--r--sound/firewire/scs1x.c4
-rw-r--r--sound/firewire/speakers.c4
-rw-r--r--sound/i2c/other/ak4113.c2
-rw-r--r--sound/i2c/other/ak4114.c2
-rw-r--r--sound/i2c/other/ak4117.c2
-rw-r--r--sound/isa/ad1816a/ad1816a.c6
-rw-r--r--sound/isa/ad1848/ad1848.c4
-rw-r--r--sound/isa/adlib.c4
-rw-r--r--sound/isa/als100.c6
-rw-r--r--sound/isa/azt2320.c6
-rw-r--r--sound/isa/cmi8328.c5
-rw-r--r--sound/isa/cmi8330.c13
-rw-r--r--sound/isa/cs423x/cs4231.c4
-rw-r--r--sound/isa/cs423x/cs4236.c16
-rw-r--r--sound/isa/es1688/es1688.c12
-rw-r--r--sound/isa/es18xx.c16
-rw-r--r--sound/isa/galaxy/galaxy.c6
-rw-r--r--sound/isa/gus/gusclassic.c4
-rw-r--r--sound/isa/gus/gusextreme.c6
-rw-r--r--sound/isa/gus/gusmax.c6
-rw-r--r--sound/isa/gus/interwave.c13
-rw-r--r--sound/isa/msnd/msnd_pinnacle.c11
-rw-r--r--sound/isa/opl3sa2.c16
-rw-r--r--sound/isa/opti9xx/miro.c11
-rw-r--r--sound/isa/opti9xx/opti92x-ad1848.c12
-rw-r--r--sound/isa/sb/jazz16.c6
-rw-r--r--sound/isa/sb/sb16.c13
-rw-r--r--sound/isa/sb/sb8.c6
-rw-r--r--sound/isa/sc6000.c6
-rw-r--r--sound/isa/sscape.c11
-rw-r--r--sound/isa/wavefront/wavefront.c13
-rw-r--r--sound/mips/au1x00.c241
-rw-r--r--sound/mips/hal2.c3
-rw-r--r--sound/mips/sgio2audio.c3
-rw-r--r--sound/oss/Kconfig9
-rw-r--r--sound/oss/Makefile1
-rw-r--r--sound/oss/pas2.h3
-rw-r--r--sound/oss/pas2_card.c2
-rw-r--r--sound/oss/vwsnd.c3506
-rw-r--r--sound/parisc/harmony.c4
-rw-r--r--sound/pci/Kconfig9
-rw-r--r--sound/pci/ac97/ac97_codec.c45
-rw-r--r--sound/pci/ac97/ac97_patch.c3
-rw-r--r--sound/pci/ac97/ac97_pcm.c15
-rw-r--r--sound/pci/ad1889.c37
-rw-r--r--sound/pci/ali5451/ali5451.c152
-rw-r--r--sound/pci/als300.c57
-rw-r--r--sound/pci/als4000.c22
-rw-r--r--sound/pci/asihpi/asihpi.c25
-rw-r--r--sound/pci/atiixp.c33
-rw-r--r--sound/pci/atiixp_modem.c28
-rw-r--r--sound/pci/au88x0/au88x0.c5
-rw-r--r--sound/pci/aw2/aw2-alsa.c46
-rw-r--r--sound/pci/aw2/aw2-saa7146.c6
-rw-r--r--sound/pci/azt3328.c351
-rw-r--r--sound/pci/bt87x.c41
-rw-r--r--sound/pci/ca0106/ca0106_main.c89
-rw-r--r--sound/pci/ca0106/ca_midi.c4
-rw-r--r--sound/pci/cmipci.c41
-rw-r--r--sound/pci/cs4281.c49
-rw-r--r--sound/pci/cs46xx/cs46xx.c3
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c145
-rw-r--r--sound/pci/cs46xx/dsp_spos.c126
-rw-r--r--sound/pci/cs46xx/dsp_spos_scb_lib.c57
-rw-r--r--sound/pci/cs5530.c27
-rw-r--r--sound/pci/cs5535audio/cs5535audio.c31
-rw-r--r--sound/pci/cs5535audio/cs5535audio_olpc.c7
-rw-r--r--sound/pci/cs5535audio/cs5535audio_pcm.c6
-rw-r--r--sound/pci/cs5535audio/cs5535audio_pm.c7
-rw-r--r--sound/pci/ctxfi/ctatc.c2
-rw-r--r--sound/pci/ctxfi/xfi.c3
-rw-r--r--sound/pci/echoaudio/echoaudio.c26
-rw-r--r--sound/pci/echoaudio/echoaudio_dsp.c9
-rw-r--r--sound/pci/echoaudio/midi.c3
-rw-r--r--sound/pci/emu10k1/emu10k1.c9
-rw-r--r--sound/pci/emu10k1/emu10k1_callback.c4
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c74
-rw-r--r--sound/pci/emu10k1/emu10k1_patch.c6
-rw-r--r--sound/pci/emu10k1/emu10k1x.c32
-rw-r--r--sound/pci/emu10k1/emufx.c12
-rw-r--r--sound/pci/emu10k1/emumixer.c6
-rw-r--r--sound/pci/emu10k1/emumpu401.c7
-rw-r--r--sound/pci/emu10k1/emupcm.c22
-rw-r--r--sound/pci/emu10k1/io.c13
-rw-r--r--sound/pci/emu10k1/irq.c21
-rw-r--r--sound/pci/emu10k1/memory.c12
-rw-r--r--sound/pci/emu10k1/p16v.c45
-rw-r--r--sound/pci/emu10k1/voice.c6
-rw-r--r--sound/pci/ens1370.c44
-rw-r--r--sound/pci/es1938.c79
-rw-r--r--sound/pci/es1968.c54
-rw-r--r--sound/pci/fm801.c31
-rw-r--r--sound/pci/hda/Kconfig45
-rw-r--r--sound/pci/hda/Makefile8
-rw-r--r--sound/pci/hda/hda_auto_parser.c65
-rw-r--r--sound/pci/hda/hda_beep.c36
-rw-r--r--sound/pci/hda/hda_beep.h6
-rw-r--r--sound/pci/hda/hda_codec.c272
-rw-r--r--sound/pci/hda/hda_codec.h8
-rw-r--r--sound/pci/hda/hda_controller.c2031
-rw-r--r--sound/pci/hda/hda_controller.h53
-rw-r--r--sound/pci/hda/hda_eld.c17
-rw-r--r--sound/pci/hda/hda_generic.c57
-rw-r--r--sound/pci/hda/hda_generic.h2
-rw-r--r--sound/pci/hda/hda_hwdep.c769
-rw-r--r--sound/pci/hda/hda_i915.c6
-rw-r--r--sound/pci/hda/hda_intel.c2712
-rw-r--r--sound/pci/hda/hda_local.h26
-rw-r--r--sound/pci/hda/hda_priv.h463
-rw-r--r--sound/pci/hda/hda_sysfs.c780
-rw-r--r--sound/pci/hda/patch_analog.c5
-rw-r--r--sound/pci/hda/patch_ca0110.c1
-rw-r--r--sound/pci/hda/patch_ca0132.c277
-rw-r--r--sound/pci/hda/patch_cirrus.c1
-rw-r--r--sound/pci/hda/patch_cmedia.c34
-rw-r--r--sound/pci/hda/patch_conexant.c850
-rw-r--r--sound/pci/hda/patch_hdmi.c109
-rw-r--r--sound/pci/hda/patch_realtek.c528
-rw-r--r--sound/pci/hda/patch_si3054.c5
-rw-r--r--sound/pci/hda/patch_sigmatel.c75
-rw-r--r--sound/pci/hda/patch_via.c8
-rw-r--r--sound/pci/hda/thinkpad_helper.c7
-rw-r--r--sound/pci/ice1712/aureon.c7
-rw-r--r--sound/pci/ice1712/delta.c35
-rw-r--r--sound/pci/ice1712/ews.c12
-rw-r--r--sound/pci/ice1712/ice1712.c123
-rw-r--r--sound/pci/ice1712/ice1724.c50
-rw-r--r--sound/pci/ice1712/juli.c14
-rw-r--r--sound/pci/ice1712/prodigy192.c13
-rw-r--r--sound/pci/ice1712/quartet.c6
-rw-r--r--sound/pci/intel8x0.c90
-rw-r--r--sound/pci/intel8x0m.c50
-rw-r--r--sound/pci/korg1212/korg1212.c5
-rw-r--r--sound/pci/lola/lola.c46
-rw-r--r--sound/pci/lola/lola_clock.c14
-rw-r--r--sound/pci/lola/lola_mixer.c22
-rw-r--r--sound/pci/lola/lola_pcm.c26
-rw-r--r--sound/pci/lx6464es/lx6464es.c162
-rw-r--r--sound/pci/lx6464es/lx_core.c173
-rw-r--r--sound/pci/maestro3.c42
-rw-r--r--sound/pci/mixart/mixart.c123
-rw-r--r--sound/pci/mixart/mixart_core.c49
-rw-r--r--sound/pci/mixart/mixart_hwdep.c65
-rw-r--r--sound/pci/mixart/mixart_mixer.c16
-rw-r--r--sound/pci/nm256/nm256.c79
-rw-r--r--sound/pci/oxygen/oxygen_io.c8
-rw-r--r--sound/pci/oxygen/oxygen_lib.c14
-rw-r--r--sound/pci/oxygen/xonar_dg.c30
-rw-r--r--sound/pci/oxygen/xonar_hdmi.c2
-rw-r--r--sound/pci/oxygen/xonar_lib.c4
-rw-r--r--sound/pci/pcxhr/pcxhr.c58
-rw-r--r--sound/pci/pcxhr/pcxhr_core.c108
-rw-r--r--sound/pci/pcxhr/pcxhr_hwdep.c31
-rw-r--r--sound/pci/pcxhr/pcxhr_mix22.c23
-rw-r--r--sound/pci/pcxhr/pcxhr_mixer.c13
-rw-r--r--sound/pci/riptide/riptide.c5
-rw-r--r--sound/pci/rme32.c10
-rw-r--r--sound/pci/rme96.c51
-rw-r--r--sound/pci/rme9652/hdsp.c133
-rw-r--r--sound/pci/rme9652/hdspm.c131
-rw-r--r--sound/pci/rme9652/rme9652.c24
-rw-r--r--sound/pci/sis7019.c5
-rw-r--r--sound/pci/sonicvibes.c240
-rw-r--r--sound/pci/trident/trident.c3
-rw-r--r--sound/pci/trident/trident_main.c90
-rw-r--r--sound/pci/via82xx.c73
-rw-r--r--sound/pci/via82xx_modem.c49
-rw-r--r--sound/pci/vx222/vx222.c12
-rw-r--r--sound/pci/vx222/vx222_ops.c19
-rw-r--r--sound/pci/ymfpci/ymfpci.c25
-rw-r--r--sound/pci/ymfpci/ymfpci_main.c28
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf.c5
-rw-r--r--sound/pcmcia/vx/vxpocket.c4
-rw-r--r--sound/ppc/powermac.c4
-rw-r--r--sound/ppc/snd_ps3.c4
-rw-r--r--sound/sh/aica.c5
-rw-r--r--sound/sh/sh_dac_audio.c2
-rw-r--r--sound/soc/Kconfig1
-rw-r--r--sound/soc/Makefile1
-rw-r--r--sound/soc/atmel/Kconfig2
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c13
-rw-r--r--sound/soc/atmel/sam9g20_wm8731.c20
-rw-r--r--sound/soc/blackfin/Kconfig20
-rw-r--r--sound/soc/cirrus/Kconfig4
-rw-r--r--sound/soc/cirrus/snappercl15.c18
-rw-r--r--sound/soc/codecs/88pm860x-codec.c120
-rw-r--r--sound/soc/codecs/Kconfig195
-rw-r--r--sound/soc/codecs/Makefile39
-rw-r--r--sound/soc/codecs/ad1836.c4
-rw-r--r--sound/soc/codecs/ad193x-i2c.c54
-rw-r--r--sound/soc/codecs/ad193x-spi.c48
-rw-r--r--sound/soc/codecs/ad193x.c154
-rw-r--r--sound/soc/codecs/ad193x.h7
-rw-r--r--sound/soc/codecs/ad1980.c4
-rw-r--r--sound/soc/codecs/adau1373.c39
-rw-r--r--sound/soc/codecs/adau1977-i2c.c59
-rw-r--r--sound/soc/codecs/adau1977-spi.c76
-rw-r--r--sound/soc/codecs/adau1977.c1018
-rw-r--r--sound/soc/codecs/adau1977.h37
-rw-r--r--sound/soc/codecs/adav801.c53
-rw-r--r--sound/soc/codecs/adav803.c50
-rw-r--r--sound/soc/codecs/adav80x.c159
-rw-r--r--sound/soc/codecs/adav80x.h7
-rw-r--r--sound/soc/codecs/ak4104.c2
-rw-r--r--sound/soc/codecs/ak4535.c9
-rw-r--r--sound/soc/codecs/ak4641.c24
-rw-r--r--sound/soc/codecs/ak4642.c8
-rw-r--r--sound/soc/codecs/ak4671.c250
-rw-r--r--sound/soc/codecs/ak4671.h2
-rw-r--r--sound/soc/codecs/alc5623.c120
-rw-r--r--sound/soc/codecs/alc5632.c48
-rw-r--r--sound/soc/codecs/arizona.c325
-rw-r--r--sound/soc/codecs/cq93vc.c3
-rw-r--r--sound/soc/codecs/cs4270.c9
-rw-r--r--sound/soc/codecs/cs4271.c63
-rw-r--r--sound/soc/codecs/cs42l51.c99
-rw-r--r--sound/soc/codecs/cs42l52.c109
-rw-r--r--sound/soc/codecs/cs42l73.c72
-rw-r--r--sound/soc/codecs/cs42xx8-i2c.c64
-rw-r--r--sound/soc/codecs/cs42xx8.c602
-rw-r--r--sound/soc/codecs/cs42xx8.h238
-rw-r--r--sound/soc/codecs/da7210.c28
-rw-r--r--sound/soc/codecs/da7213.c159
-rw-r--r--sound/soc/codecs/da732x.c208
-rw-r--r--sound/soc/codecs/da732x.h3
-rw-r--r--sound/soc/codecs/da9055.c111
-rw-r--r--sound/soc/codecs/isabelle.c71
-rw-r--r--sound/soc/codecs/lm4857.c3
-rw-r--r--sound/soc/codecs/lm49453.c47
-rw-r--r--sound/soc/codecs/max9768.c5
-rw-r--r--sound/soc/codecs/max98088.c47
-rw-r--r--sound/soc/codecs/max98090.c202
-rw-r--r--sound/soc/codecs/max98090.h1
-rw-r--r--sound/soc/codecs/max98095.c60
-rw-r--r--sound/soc/codecs/max9850.c8
-rw-r--r--sound/soc/codecs/mc13783.c30
-rw-r--r--sound/soc/codecs/ml26124.c22
-rw-r--r--sound/soc/codecs/pcm1681.c15
-rw-r--r--sound/soc/codecs/pcm1792a.c33
-rw-r--r--sound/soc/codecs/pcm512x-i2c.c71
-rw-r--r--sound/soc/codecs/pcm512x-spi.c69
-rw-r--r--sound/soc/codecs/pcm512x.c589
-rw-r--r--sound/soc/codecs/pcm512x.h171
-rw-r--r--sound/soc/codecs/rt5631.c84
-rw-r--r--sound/soc/codecs/rt5640.c87
-rw-r--r--sound/soc/codecs/sgtl5000.c18
-rw-r--r--sound/soc/codecs/si476x.c6
-rw-r--r--sound/soc/codecs/sirf-audio-codec.c524
-rw-r--r--sound/soc/codecs/sirf-audio-codec.h75
-rw-r--r--sound/soc/codecs/sn95031.c46
-rw-r--r--sound/soc/codecs/ssm2518.c24
-rw-r--r--sound/soc/codecs/ssm2602-i2c.c57
-rw-r--r--sound/soc/codecs/ssm2602-spi.c41
-rw-r--r--sound/soc/codecs/ssm2602.c180
-rw-r--r--sound/soc/codecs/ssm2602.h14
-rw-r--r--sound/soc/codecs/sta32x.c90
-rw-r--r--sound/soc/codecs/sta529.c15
-rw-r--r--sound/soc/codecs/stac9766.c38
-rw-r--r--sound/soc/codecs/tlv320aic23-i2c.c59
-rw-r--r--sound/soc/codecs/tlv320aic23-spi.c56
-rw-r--r--sound/soc/codecs/tlv320aic23.c79
-rw-r--r--sound/soc/codecs/tlv320aic23.h6
-rw-r--r--sound/soc/codecs/tlv320aic26.c7
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c1280
-rw-r--r--sound/soc/codecs/tlv320aic31xx.h258
-rw-r--r--sound/soc/codecs/tlv320aic32x4.c234
-rw-r--r--sound/soc/codecs/tlv320aic3x.c6
-rw-r--r--sound/soc/codecs/tlv320dac33.c35
-rw-r--r--sound/soc/codecs/twl4030.c101
-rw-r--r--sound/soc/codecs/twl6040.c17
-rw-r--r--sound/soc/codecs/uda134x.c3
-rw-r--r--sound/soc/codecs/uda1380.c43
-rw-r--r--sound/soc/codecs/wl1273.c9
-rw-r--r--sound/soc/codecs/wm2000.c2
-rw-r--r--sound/soc/codecs/wm2200.c25
-rw-r--r--sound/soc/codecs/wm5100.c43
-rw-r--r--sound/soc/codecs/wm5102.c32
-rw-r--r--sound/soc/codecs/wm5110.c22
-rw-r--r--sound/soc/codecs/wm8350.c4
-rw-r--r--sound/soc/codecs/wm8400.c37
-rw-r--r--sound/soc/codecs/wm8510.c10
-rw-r--r--sound/soc/codecs/wm8523.c11
-rw-r--r--sound/soc/codecs/wm8580.c9
-rw-r--r--sound/soc/codecs/wm8711.c8
-rw-r--r--sound/soc/codecs/wm8728.c11
-rw-r--r--sound/soc/codecs/wm8731.c11
-rw-r--r--sound/soc/codecs/wm8737.c56
-rw-r--r--sound/soc/codecs/wm8741.c40
-rw-r--r--sound/soc/codecs/wm8750.c6
-rw-r--r--sound/soc/codecs/wm8753.c12
-rw-r--r--sound/soc/codecs/wm8770.c10
-rw-r--r--sound/soc/codecs/wm8776.c6
-rw-r--r--sound/soc/codecs/wm8804.c10
-rw-r--r--sound/soc/codecs/wm8900.c52
-rw-r--r--sound/soc/codecs/wm8903.c118
-rw-r--r--sound/soc/codecs/wm8904.c86
-rw-r--r--sound/soc/codecs/wm8940.c26
-rw-r--r--sound/soc/codecs/wm8955.c19
-rw-r--r--sound/soc/codecs/wm8958-dsp2.c10
-rw-r--r--sound/soc/codecs/wm8960.c6
-rw-r--r--sound/soc/codecs/wm8961.c23
-rw-r--r--sound/soc/codecs/wm8962.c87
-rw-r--r--sound/soc/codecs/wm8971.c6
-rw-r--r--sound/soc/codecs/wm8974.c10
-rw-r--r--sound/soc/codecs/wm8978.c38
-rw-r--r--sound/soc/codecs/wm8983.c51
-rw-r--r--sound/soc/codecs/wm8985.c46
-rw-r--r--sound/soc/codecs/wm8988.c70
-rw-r--r--sound/soc/codecs/wm8990.c49
-rw-r--r--sound/soc/codecs/wm8991.c52
-rw-r--r--sound/soc/codecs/wm8993.c74
-rw-r--r--sound/soc/codecs/wm8994.c186
-rw-r--r--sound/soc/codecs/wm8995.c50
-rw-r--r--sound/soc/codecs/wm8996.c87
-rw-r--r--sound/soc/codecs/wm8997.c29
-rw-r--r--sound/soc/codecs/wm9081.c34
-rw-r--r--sound/soc/codecs/wm9090.c10
-rw-r--r--sound/soc/codecs/wm9705.c12
-rw-r--r--sound/soc/codecs/wm_adsp.c50
-rw-r--r--sound/soc/codecs/wm_hubs.c16
-rw-r--r--sound/soc/davinci/davinci-evm.c81
-rw-r--r--sound/soc/davinci/davinci-mcasp.c294
-rw-r--r--sound/soc/davinci/edma-pcm.c57
-rw-r--r--sound/soc/davinci/edma-pcm.h25
-rw-r--r--sound/soc/fsl/Kconfig14
-rw-r--r--sound/soc/fsl/eukrea-tlv320.c108
-rw-r--r--sound/soc/fsl/fsl_esai.c38
-rw-r--r--sound/soc/fsl/fsl_esai.h2
-rw-r--r--sound/soc/fsl/fsl_sai.c332
-rw-r--r--sound/soc/fsl/fsl_sai.h48
-rw-r--r--sound/soc/fsl/fsl_spdif.c9
-rw-r--r--sound/soc/fsl/fsl_utils.c27
-rw-r--r--sound/soc/fsl/fsl_utils.h4
-rw-r--r--sound/soc/fsl/imx-mc13783.c1
-rw-r--r--sound/soc/fsl/imx-pcm-fiq.c7
-rw-r--r--sound/soc/fsl/imx-sgtl5000.c10
-rw-r--r--sound/soc/fsl/imx-ssi.c2
-rw-r--r--sound/soc/fsl/imx-wm8962.c11
-rw-r--r--sound/soc/fsl/wm1133-ev1.c11
-rw-r--r--sound/soc/generic/simple-card.c385
-rw-r--r--sound/soc/intel/Kconfig42
-rw-r--r--sound/soc/intel/Makefile27
-rw-r--r--sound/soc/intel/byt-rt5640.c187
-rw-r--r--sound/soc/intel/haswell.c235
-rw-r--r--sound/soc/intel/mfld_machine.c108
-rw-r--r--sound/soc/intel/sst-acpi.c284
-rw-r--r--sound/soc/intel/sst-baytrail-dsp.c372
-rw-r--r--sound/soc/intel/sst-baytrail-ipc.c867
-rw-r--r--sound/soc/intel/sst-baytrail-ipc.h69
-rw-r--r--sound/soc/intel/sst-baytrail-pcm.c422
-rw-r--r--sound/soc/intel/sst-dsp-priv.h309
-rw-r--r--sound/soc/intel/sst-dsp.c385
-rw-r--r--sound/soc/intel/sst-dsp.h233
-rw-r--r--sound/soc/intel/sst-firmware.c587
-rw-r--r--sound/soc/intel/sst-haswell-dsp.c517
-rw-r--r--sound/soc/intel/sst-haswell-ipc.c1785
-rw-r--r--sound/soc/intel/sst-haswell-ipc.h488
-rw-r--r--sound/soc/intel/sst-haswell-pcm.c872
-rw-r--r--sound/soc/intel/sst-mfld-dsp.h (renamed from sound/soc/intel/sst_dsp.h)8
-rw-r--r--sound/soc/intel/sst-mfld-platform.c (renamed from sound/soc/intel/sst_platform.c)8
-rw-r--r--sound/soc/intel/sst-mfld-platform.h (renamed from sound/soc/intel/sst_platform.h)4
-rw-r--r--sound/soc/kirkwood/Kconfig11
-rw-r--r--sound/soc/kirkwood/Makefile2
-rw-r--r--sound/soc/kirkwood/armada-370-db.c148
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.c1
-rw-r--r--sound/soc/omap/Kconfig4
-rw-r--r--sound/soc/omap/ams-delta.c55
-rw-r--r--sound/soc/omap/n810.c26
-rw-r--r--sound/soc/omap/omap-abe-twl6040.c3
-rw-r--r--sound/soc/omap/rx51.c22
-rw-r--r--sound/soc/pxa/corgi.c49
-rw-r--r--sound/soc/pxa/e740_wm9705.c10
-rw-r--r--sound/soc/pxa/e750_wm9705.c10
-rw-r--r--sound/soc/pxa/e800_wm9712.c19
-rw-r--r--sound/soc/pxa/magician.c60
-rw-r--r--sound/soc/pxa/mioa701_wm9713.c19
-rw-r--r--sound/soc/pxa/poodle.c7
-rw-r--r--sound/soc/pxa/spitz.c58
-rw-r--r--sound/soc/pxa/tosa.c67
-rw-r--r--sound/soc/pxa/zylonite.c17
-rw-r--r--sound/soc/s6000/s6105-ipcam.c28
-rw-r--r--sound/soc/samsung/Kconfig8
-rw-r--r--sound/soc/samsung/h1940_uda1380.c7
-rw-r--r--sound/soc/samsung/neo1973_wm8753.c168
-rw-r--r--sound/soc/samsung/rx1950_uda1380.c5
-rw-r--r--sound/soc/samsung/smdk_wm8994.c2
-rw-r--r--sound/soc/samsung/tobermory.c2
-rw-r--r--sound/soc/sh/fsi.c2
-rw-r--r--sound/soc/sh/migor.c19
-rw-r--r--sound/soc/sh/rcar/Makefile2
-rw-r--r--sound/soc/sh/rcar/adg.c229
-rw-r--r--sound/soc/sh/rcar/core.c426
-rw-r--r--sound/soc/sh/rcar/gen.c113
-rw-r--r--sound/soc/sh/rcar/rsnd.h206
-rw-r--r--sound/soc/sh/rcar/scu.c384
-rw-r--r--sound/soc/sh/rcar/src.c727
-rw-r--r--sound/soc/sh/rcar/ssi.c388
-rw-r--r--sound/soc/sirf/Kconfig14
-rw-r--r--sound/soc/sirf/Makefile5
-rw-r--r--sound/soc/sirf/sirf-audio-port.c194
-rw-r--r--sound/soc/sirf/sirf-audio-port.h62
-rw-r--r--sound/soc/sirf/sirf-audio.c156
-rw-r--r--sound/soc/soc-cache.c13
-rw-r--r--sound/soc/soc-compress.c65
-rw-r--r--sound/soc/soc-core.c606
-rw-r--r--sound/soc/soc-dapm.c604
-rw-r--r--sound/soc/soc-io.c99
-rw-r--r--sound/soc/soc-jack.c5
-rw-r--r--sound/soc/soc-pcm.c109
-rw-r--r--sound/soc/spear/spdif_out.c10
-rw-r--r--sound/soc/tegra/Kconfig2
-rw-r--r--sound/soc/tegra/tegra20_ac97.c17
-rw-r--r--sound/soc/tegra/tegra20_ac97.h1
-rw-r--r--sound/soc/tegra/tegra20_das.c2
-rw-r--r--sound/soc/tegra/tegra20_i2s.c2
-rw-r--r--sound/soc/tegra/tegra20_spdif.c2
-rw-r--r--sound/soc/tegra/tegra30_ahub.c4
-rw-r--r--sound/soc/tegra/tegra30_i2s.c2
-rw-r--r--sound/soc/tegra/tegra_wm9712.c17
-rw-r--r--sound/soc/txx9/txx9aclc-ac97.c8
-rw-r--r--sound/sparc/amd7930.c4
-rw-r--r--sound/sparc/cs4231.c11
-rw-r--r--sound/sparc/dbri.c4
-rw-r--r--sound/spi/at73c213.c6
-rw-r--r--sound/usb/6fire/chip.c13
-rw-r--r--sound/usb/6fire/comm.c4
-rw-r--r--sound/usb/6fire/control.c18
-rw-r--r--sound/usb/6fire/firmware.c70
-rw-r--r--sound/usb/6fire/midi.c12
-rw-r--r--sound/usb/6fire/pcm.c46
-rw-r--r--sound/usb/caiaq/device.c6
-rw-r--r--sound/usb/card.c69
-rw-r--r--sound/usb/clock.c65
-rw-r--r--sound/usb/endpoint.c32
-rw-r--r--sound/usb/format.c68
-rw-r--r--sound/usb/hiface/chip.c10
-rw-r--r--sound/usb/midi.c45
-rw-r--r--sound/usb/misc/ua101.c7
-rw-r--r--sound/usb/mixer.c226
-rw-r--r--sound/usb/mixer.h7
-rw-r--r--sound/usb/mixer_maps.c9
-rw-r--r--sound/usb/mixer_quirks.c10
-rw-r--r--sound/usb/pcm.c83
-rw-r--r--sound/usb/quirks.c52
-rw-r--r--sound/usb/stream.c50
-rw-r--r--sound/usb/usbaudio.h9
-rw-r--r--sound/usb/usx2y/us122l.c11
-rw-r--r--sound/usb/usx2y/usbusx2y.c13
-rw-r--r--sound/usb/usx2y/usbusx2y.h2
-rw-r--r--sound/usb/usx2y/usbusx2yaudio.c60
-rw-r--r--sound/usb/usx2y/usx2yhwdeppcm.c76
-rw-r--r--tools/Makefile11
-rw-r--r--tools/hv/Makefile13
-rw-r--r--tools/hv/hv_fcopy_daemon.c195
-rw-r--r--tools/hv/hv_vss_daemon.c2
-rw-r--r--tools/include/linux/hash.h5
-rw-r--r--tools/lib/api/Makefile2
-rw-r--r--tools/lib/api/fs/fs.c (renamed from tools/perf/util/fs.c)11
-rw-r--r--tools/lib/api/fs/fs.h (renamed from tools/perf/util/include/linux/magic.h)12
-rw-r--r--tools/lib/lockdep/Makefile6
-rw-r--r--tools/lib/lockdep/preload.c2
-rwxr-xr-x[-rw-r--r--]tools/lib/lockdep/run_tests.sh0
-rw-r--r--tools/lib/lockdep/uinclude/asm/hash.h6
-rw-r--r--tools/lib/lockdep/uinclude/linux/rcu.h5
-rw-r--r--tools/net/Makefile2
-rw-r--r--tools/net/bpf_dbg.c119
-rw-r--r--tools/perf/Documentation/perf-mem.txt4
-rw-r--r--tools/perf/Documentation/perf-probe.txt2
-rw-r--r--tools/perf/MANIFEST1
-rw-r--r--tools/perf/Makefile.perf42
-rw-r--r--tools/perf/arch/arm/Makefile2
-rw-r--r--tools/perf/arch/arm/util/unwind-libunwind.c (renamed from tools/perf/arch/arm/util/unwind.c)2
-rw-r--r--tools/perf/arch/x86/Makefile9
-rw-r--r--tools/perf/arch/x86/include/perf_regs.h6
-rw-r--r--tools/perf/arch/x86/tests/dwarf-unwind.c59
-rw-r--r--tools/perf/arch/x86/tests/regs_load.S92
-rw-r--r--tools/perf/arch/x86/util/unwind-libdw.c51
-rw-r--r--tools/perf/arch/x86/util/unwind-libunwind.c (renamed from tools/perf/arch/x86/util/unwind.c)4
-rw-r--r--tools/perf/bench/bench.h3
-rw-r--r--tools/perf/bench/futex-hash.c212
-rw-r--r--tools/perf/bench/futex-requeue.c211
-rw-r--r--tools/perf/bench/futex-wake.c201
-rw-r--r--tools/perf/bench/futex.h71
-rw-r--r--tools/perf/bench/numa.c1
-rw-r--r--tools/perf/builtin-bench.c14
-rw-r--r--tools/perf/builtin-diff.c7
-rw-r--r--tools/perf/builtin-inject.c1
-rw-r--r--tools/perf/builtin-kvm.c12
-rw-r--r--tools/perf/builtin-probe.c12
-rw-r--r--tools/perf/builtin-record.c30
-rw-r--r--tools/perf/builtin-report.c68
-rw-r--r--tools/perf/builtin-sched.c10
-rw-r--r--tools/perf/builtin-timechart.c4
-rw-r--r--tools/perf/builtin-top.c18
-rw-r--r--tools/perf/builtin-trace.c32
-rw-r--r--tools/perf/config/Makefile234
-rw-r--r--tools/perf/config/feature-checks/Makefile8
-rw-r--r--tools/perf/config/feature-checks/test-all.c5
-rw-r--r--tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c13
-rw-r--r--tools/perf/design.txt12
-rw-r--r--tools/perf/perf-completion.sh2
-rw-r--r--tools/perf/perf.h10
-rw-r--r--tools/perf/tests/builtin-test.c8
-rw-r--r--tools/perf/tests/dwarf-unwind.c144
-rw-r--r--tools/perf/tests/hists_link.c1
-rw-r--r--tools/perf/tests/make25
-rw-r--r--tools/perf/tests/parse-events.c2
-rw-r--r--tools/perf/tests/sample-parsing.c17
-rw-r--r--tools/perf/tests/tests.h9
-rw-r--r--tools/perf/ui/browsers/hists.c122
-rw-r--r--tools/perf/ui/gtk/hists.c78
-rw-r--r--tools/perf/ui/hist.c138
-rw-r--r--tools/perf/ui/stdio/hist.c11
-rw-r--r--tools/perf/util/annotate.c23
-rw-r--r--tools/perf/util/annotate.h2
-rw-r--r--tools/perf/util/cpumap.c2
-rw-r--r--tools/perf/util/dso.c4
-rw-r--r--tools/perf/util/dso.h10
-rw-r--r--tools/perf/util/event.c188
-rw-r--r--tools/perf/util/event.h5
-rw-r--r--tools/perf/util/evsel.c60
-rw-r--r--tools/perf/util/evsel.h18
-rw-r--r--tools/perf/util/fs.h7
-rw-r--r--tools/perf/util/hist.c13
-rw-r--r--tools/perf/util/hist.h29
-rw-r--r--tools/perf/util/include/linux/bitops.h4
-rw-r--r--tools/perf/util/include/linux/hash.h5
-rw-r--r--tools/perf/util/include/linux/kernel.h6
-rw-r--r--tools/perf/util/include/linux/list.h1
-rw-r--r--tools/perf/util/include/linux/prefetch.h6
-rw-r--r--tools/perf/util/machine.c79
-rw-r--r--tools/perf/util/machine.h13
-rw-r--r--tools/perf/util/map.h10
-rw-r--r--tools/perf/util/parse-events.c17
-rw-r--r--tools/perf/util/parse-options.c37
-rw-r--r--tools/perf/util/parse-options.h8
-rw-r--r--tools/perf/util/perf_regs.c19
-rw-r--r--tools/perf/util/perf_regs.h13
-rw-r--r--tools/perf/util/pmu.c2
-rw-r--r--tools/perf/util/probe-event.c865
-rw-r--r--tools/perf/util/probe-event.h12
-rw-r--r--tools/perf/util/probe-finder.c198
-rw-r--r--tools/perf/util/probe-finder.h5
-rw-r--r--tools/perf/util/python-ext-sources2
-rw-r--r--tools/perf/util/record.c2
-rw-r--r--tools/perf/util/session.c13
-rw-r--r--tools/perf/util/symbol-elf.c8
-rw-r--r--tools/perf/util/symbol.c65
-rw-r--r--tools/perf/util/symbol.h14
-rw-r--r--tools/perf/util/thread.c21
-rw-r--r--tools/perf/util/thread.h11
-rw-r--r--tools/perf/util/trace-event-parse.c1
-rw-r--r--tools/perf/util/unwind-libdw.c210
-rw-r--r--tools/perf/util/unwind-libdw.h21
-rw-r--r--tools/perf/util/unwind-libunwind.c (renamed from tools/perf/util/unwind.c)50
-rw-r--r--tools/perf/util/unwind.h11
-rw-r--r--tools/perf/util/util.c2
-rw-r--r--tools/testing/selftests/ipc/msgque.c1
-rw-r--r--tools/testing/selftests/powerpc/Makefile2
-rw-r--r--tools/testing/selftests/powerpc/copyloops/Makefile29
-rw-r--r--tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h86
-rw-r--r--tools/testing/selftests/powerpc/copyloops/asm/processor.h0
l---------tools/testing/selftests/powerpc/copyloops/copyuser_64.S1
l---------tools/testing/selftests/powerpc/copyloops/copyuser_power7.S1
l---------tools/testing/selftests/powerpc/copyloops/memcpy_64.S1
l---------tools/testing/selftests/powerpc/copyloops/memcpy_power7.S1
-rw-r--r--tools/testing/selftests/powerpc/copyloops/validate.c99
-rw-r--r--tools/testing/selftests/powerpc/utils.h3
-rw-r--r--tools/testing/selftests/rcutorture/bin/functions.sh1
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh51
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh51
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck.sh13
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh (renamed from tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh)53
-rw-r--r--tools/testing/selftests/rcutorture/bin/kvm.sh276
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/BUSTED6
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/BUSTED.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/CFLIST1
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/CFcommon2
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/LOCK016
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh43
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/BUSTED7
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/BUSTED.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/CFLIST (renamed from tools/testing/selftests/rcutorture/configs/CFLIST)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/CFcommon2
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/SRCU-N (renamed from tools/testing/selftests/rcutorture/configs/SRCU-N)3
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/SRCU-N.boot (renamed from tools/testing/selftests/rcutorture/configs/SRCU-N.boot)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/SRCU-P (renamed from tools/testing/selftests/rcutorture/configs/SRCU-P)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/SRCU-P.boot (renamed from tools/testing/selftests/rcutorture/configs/SRCU-P.boot)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TINY01 (renamed from tools/testing/selftests/rcutorture/configs/TINY01)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TINY02 (renamed from tools/testing/selftests/rcutorture/configs/TINY02)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE01 (renamed from tools/testing/selftests/rcutorture/configs/TREE01)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot (renamed from tools/testing/selftests/rcutorture/configs/TREE01.boot)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE02 (renamed from tools/testing/selftests/rcutorture/configs/TREE02)3
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE03 (renamed from tools/testing/selftests/rcutorture/configs/TREE03)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE04 (renamed from tools/testing/selftests/rcutorture/configs/TREE04)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot (renamed from tools/testing/selftests/rcutorture/configs/TREE04.boot)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE05 (renamed from tools/testing/selftests/rcutorture/configs/TREE05)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE05.boot (renamed from tools/testing/selftests/rcutorture/configs/TREE05.boot)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE06 (renamed from tools/testing/selftests/rcutorture/configs/TREE06)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE07 (renamed from tools/testing/selftests/rcutorture/configs/TREE07)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE08 (renamed from tools/testing/selftests/rcutorture/configs/TREE08)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE08-T (renamed from tools/testing/selftests/rcutorture/configs/TREE08-T)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE09 (renamed from tools/testing/selftests/rcutorture/configs/TREE09)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/CFLIST (renamed from tools/testing/selftests/rcutorture/configs/v0.0/CFLIST)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/N1-S-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v0.0/N1-S-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/N2-2-t-nh-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v0.0/N2-2-t-nh-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/N3-3-T-nh-SD-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v0.0/N3-3-T-nh-SD-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/N4-A-t-NH-sd-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v0.0/N4-A-t-NH-sd-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/N5-U-T-NH-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v0.0/N5-U-T-NH-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT1-nh (renamed from tools/testing/selftests/rcutorture/configs/v0.0/NT1-nh)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT3-NH (renamed from tools/testing/selftests/rcutorture/configs/v0.0/NT3-NH)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v0.0/P1-S-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v0.0/P2-2-t-nh-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v0.0/P3-3-T-nh-SD-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v0.0/P4-A-t-NH-sd-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v0.0/P5-U-T-NH-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT1-nh (renamed from tools/testing/selftests/rcutorture/configs/v0.0/PT1-nh)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT2-NH (renamed from tools/testing/selftests/rcutorture/configs/v0.0/PT2-NH)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/ver_functions.sh (renamed from tools/testing/selftests/rcutorture/configs/v0.0/ver_functions.sh)22
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/CFLIST (renamed from tools/testing/selftests/rcutorture/configs/v3.12/CFLIST)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N1-S-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.12/N1-S-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N2-2-t-nh-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.12/N2-2-t-nh-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N3-3-T-nh-SD-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.12/N3-3-T-nh-SD-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N4-A-t-NH-sd-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.12/N4-A-t-NH-sd-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N5-U-T-NH-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.12/N5-U-T-NH-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N6---t-nh-SD-smp-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.12/N6---t-nh-SD-smp-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N7-4-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.12/N7-4-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N8-2-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.12/N8-2-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT1-nh (renamed from tools/testing/selftests/rcutorture/configs/v3.12/NT1-nh)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT3-NH (renamed from tools/testing/selftests/rcutorture/configs/v3.12/NT3-NH)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.12/P1-S-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.12/P2-2-t-nh-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.12/P3-3-T-nh-SD-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.12/P4-A-t-NH-sd-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.12/P5-U-T-NH-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.12/P6---t-nh-SD-smp-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all (renamed from tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-all)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none (renamed from tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-none)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT1-nh (renamed from tools/testing/selftests/rcutorture/configs/v3.12/PT1-nh)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT2-NH (renamed from tools/testing/selftests/rcutorture/configs/v3.12/PT2-NH)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/CFLIST (renamed from tools/testing/selftests/rcutorture/configs/v3.3/CFLIST)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/N1-S-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.3/N1-S-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/N2-2-t-nh-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.3/N2-2-t-nh-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/N3-3-T-nh-SD-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.3/N3-3-T-nh-SD-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/N4-A-t-NH-sd-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.3/N4-A-t-NH-sd-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/N5-U-T-NH-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.3/N5-U-T-NH-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT1-nh (renamed from tools/testing/selftests/rcutorture/configs/v3.3/NT1-nh)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT3-NH (renamed from tools/testing/selftests/rcutorture/configs/v3.3/NT3-NH)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.3/P1-S-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.3/P2-2-t-nh-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.3/P3-3-T-nh-SD-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.3/P4-A-t-NH-sd-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.3/P5-U-T-NH-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT1-nh (renamed from tools/testing/selftests/rcutorture/configs/v3.3/PT1-nh)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT2-NH (renamed from tools/testing/selftests/rcutorture/configs/v3.3/PT2-NH)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/ver_functions.sh (renamed from tools/testing/selftests/rcutorture/configs/ver_functions.sh)28
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/CFLIST (renamed from tools/testing/selftests/rcutorture/configs/v3.5/CFLIST)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/N1-S-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.5/N1-S-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/N2-2-t-nh-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.5/N2-2-t-nh-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/N3-3-T-nh-SD-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.5/N3-3-T-nh-SD-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/N4-A-t-NH-sd-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.5/N4-A-t-NH-sd-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/N5-U-T-NH-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.5/N5-U-T-NH-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT1-nh (renamed from tools/testing/selftests/rcutorture/configs/v3.5/NT1-nh)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT3-NH (renamed from tools/testing/selftests/rcutorture/configs/v3.5/NT3-NH)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.5/P1-S-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.5/P2-2-t-nh-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.5/P3-3-T-nh-SD-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.5/P4-A-t-NH-sd-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.5/P5-U-T-NH-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT1-nh (renamed from tools/testing/selftests/rcutorture/configs/v3.5/PT1-nh)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT2-NH (renamed from tools/testing/selftests/rcutorture/configs/v3.5/PT2-NH)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/ver_functions.sh (renamed from tools/testing/selftests/rcutorture/configs/v3.5/ver_functions.sh)23
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh (renamed from tools/testing/selftests/rcutorture/configs/v3.3/ver_functions.sh)26
-rw-r--r--tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt (renamed from tools/testing/selftests/rcutorture/doc/TREE_RCU-Kconfig.txt)0
-rw-r--r--tools/virtio/linux/kmemleak.h3
-rw-r--r--tools/virtio/linux/virtio.h4
-rw-r--r--tools/virtio/virtio_test.c2
-rw-r--r--virt/kvm/Kconfig4
-rw-r--r--virt/kvm/arm/vgic.c1
-rw-r--r--virt/kvm/async_pf.c27
-rw-r--r--virt/kvm/coalesced_mmio.c8
-rw-r--r--virt/kvm/eventfd.c8
-rw-r--r--virt/kvm/ioapic.c108
-rw-r--r--virt/kvm/kvm_main.c14
-rw-r--r--virt/kvm/vfio.c27
7582 files changed, 375534 insertions, 176748 deletions
diff --git a/.gitignore b/.gitignore
index 7e9932e55475..42fa0d5626a9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -92,3 +92,6 @@ extra_certificates
signing_key.priv
signing_key.x509
x509.genkey
+
+# Kconfig presets
+all.config
diff --git a/CREDITS b/CREDITS
index e371c5504a50..c322dcfb926d 100644
--- a/CREDITS
+++ b/CREDITS
@@ -630,6 +630,13 @@ N: Michael Elizabeth Chastain
E: mec@shout.net
D: Configure, Menuconfig, xconfig
+N: Mauro Carvalho Chehab
+E: m.chehab@samsung.org
+E: mchehab@infradead.org
+D: Media subsystem (V4L/DVB) drivers and core
+D: EDAC drivers and EDAC 3.0 core rework
+S: Brazil
+
N: Raymond Chen
E: raymondc@microsoft.com
D: Author of Configure script
@@ -1229,7 +1236,7 @@ E: philip@gladstonefamily.net
D: Kernel / timekeeping stuff
S: Carlisle, MA 01741
S: USA
-
+
N: Jan-Benedict Glaw
E: jbglaw@lug-owl.de
D: SRM environment driver (for Alpha systems)
@@ -2560,10 +2567,14 @@ S: 22 Seaview St
S: Fullarton 5063
S: South Australia
-N. Wolfgang Muees
+N: Wolfgang Muees
E: wolfgang@iksw-muees.de
D: Auerswald USB driver
+N: Paul Mundt
+E: paul.mundt@gmail.com
+D: SuperH maintainer
+
N: Ian A. Murdock
E: imurdock@gnu.ai.mit.edu
D: Creator of Debian distribution
@@ -2707,6 +2718,9 @@ N: Greg Page
E: gpage@sovereign.org
D: IPX development and support
+N: Venkatesh Pallipadi (Venki)
+D: x86/HPET
+
N: David Parsons
E: orc@pell.chi.il.us
D: improved memory detection code.
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index 38f8444bdd0e..27e67a98b7be 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -29,6 +29,8 @@ DMA-ISA-LPC.txt
- How to do DMA with ISA (and LPC) devices.
DMA-attributes.txt
- listing of the various possible attributes a DMA region can have
+dmatest.txt
+ - how to compile, configure and use the dmatest system.
DocBook/
- directory with DocBook templates etc. for kernel documentation.
EDID/
@@ -77,6 +79,8 @@ arm/
- directory with info about Linux on the ARM architecture.
arm64/
- directory with info about Linux on the 64 bit ARM architecture.
+assoc_array.txt
+ - generic associative array intro.
atomic_ops.txt
- semantics and behavior of atomic and bitmask operations.
auxdisplay/
@@ -87,6 +91,8 @@ bad_memory.txt
- how to use kernel parameters to exclude bad RAM regions.
basic_profiling.txt
- basic instructions for those who wants to profile Linux kernel.
+bcache.txt
+ - Block-layer cache on fast SSDs to improve slow (raid) I/O performance.
binfmt_misc.txt
- info on the kernel support for extra binary formats.
blackfin/
@@ -171,6 +177,8 @@ early-userspace/
- info about initramfs, klibc, and userspace early during boot.
edac.txt
- information on EDAC - Error Detection And Correction
+efi-stub.txt
+ - How to use the EFI boot stub to bypass GRUB or elilo on EFI systems.
eisa.txt
- info on EISA bus support.
email-clients.txt
@@ -195,8 +203,8 @@ futex-requeue-pi.txt
- info on requeueing of tasks from a non-PI futex to a PI futex
gcov.txt
- use of GCC's coverage testing tool "gcov" with the Linux kernel
-gpio.txt
- - overview of GPIO (General Purpose Input/Output) access conventions.
+gpio/
+ - gpio related documentation
hid/
- directory with information on human interface devices
highuid.txt
@@ -255,6 +263,8 @@ kernel-docs.txt
- listing of various WWW + books that document kernel internals.
kernel-parameters.txt
- summary listing of command line / boot prompt args for the kernel.
+kernel-per-CPU-kthreads.txt
+ - List of all per-CPU kthreads and how they introduce jitter.
kmemcheck.txt
- info on dynamic checker that detects uses of uninitialized memory.
kmemleak.txt
@@ -299,8 +309,6 @@ memory-devices/
- directory with info on parts like the Texas Instruments EMIF driver
memory-hotplug.txt
- Hotpluggable memory support, how to use and current status.
-memory.txt
- - info on typical Linux memory problems.
metag/
- directory with info about Linux on Meta architecture.
mips/
@@ -311,6 +319,8 @@ mmc/
- directory with info about the MMC subsystem
mn10300/
- directory with info about the mn10300 architecture port
+module-signing.txt
+ - Kernel module signing for increased security when loading modules.
mtd/
- directory with info about memory technology devices (flash)
mono.txt
@@ -343,6 +353,8 @@ pcmcia/
- info on the Linux PCMCIA driver.
percpu-rw-semaphore.txt
- RCU based read-write semaphore optimized for locking for reading
+phy.txt
+ - Description of the generic PHY framework.
pi-futex.txt
- documentation on lightweight priority inheritance futexes.
pinctrl.txt
@@ -401,8 +413,6 @@ serial-console.txt
- how to set up Linux with a serial line console as the default.
sgi-ioc4.txt
- description of the SGI IOC4 PCI (multi function) device.
-sgi-visws.txt
- - short blurb on the SGI Visual Workstations.
sh/
- directory with info on porting Linux to a new architecture.
smsc_ece1099.txt
@@ -431,6 +441,8 @@ sysrq.txt
- info on the magic SysRq key.
target/
- directory with info on generating TCM v4 fabric .ko modules
+this_cpu_ops.txt
+ - List rationale behind and the way to use this_cpu operations.
thermal/
- directory with information on managing thermal issues (CPU/temp)
trace/
@@ -469,6 +481,8 @@ wimax/
- directory with info about Intel Wireless Wimax Connections
workqueue.txt
- information on the Concurrency Managed Workqueue implementation
+ww-mutex-design.txt
+ - Intro to Mutex wait/would deadlock handling.s
x86/x86_64/
- directory with info on Linux support for AMD x86-64 (Hammer) machines.
xtensa/
diff --git a/Documentation/ABI/stable/sysfs-firmware-opal-dump b/Documentation/ABI/stable/sysfs-firmware-opal-dump
new file mode 100644
index 000000000000..32fe7f5c4880
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-firmware-opal-dump
@@ -0,0 +1,41 @@
+What: /sys/firmware/opal/dump
+Date: Feb 2014
+Contact: Stewart Smith <stewart@linux.vnet.ibm.com>
+Description:
+ This directory exposes interfaces for interacting with
+ the FSP and platform dumps through OPAL firmware interface.
+
+ This is only for the powerpc/powernv platform.
+
+ initiate_dump: When '1' is written to it,
+ we will initiate a dump.
+ Read this file for supported commands.
+
+ 0xXX-0xYYYY: A directory for dump of type 0xXX and
+ id 0xYYYY (in hex). The name of this
+ directory should not be relied upon to
+ be in this format, only that it's unique
+ among all dumps. For determining the type
+ and ID of the dump, use the id and type files.
+ Do not rely on any particular size of dump
+ type or dump id.
+
+ Each dump has the following files:
+ id: An ASCII representation of the dump ID
+ in hex (e.g. '0x01')
+ type: An ASCII representation of the type of
+ dump in the format "0x%x %s" with the ID
+ in hex and a description of the dump type
+ (or 'unknown').
+ Type '0xffffffff unknown' is used when
+ we could not get the type from firmware.
+ e.g. '0x02 System/Platform Dump'
+ dump: A binary file containing the dump.
+ The size of the dump is the size of this file.
+ acknowledge: When 'ack' is written to this, we will
+ acknowledge that we've retrieved the
+ dump to the service processor. It will
+ then remove it, making the dump
+ inaccessible.
+ Reading this file will get a list of
+ supported actions.
diff --git a/Documentation/ABI/stable/sysfs-firmware-opal-elog b/Documentation/ABI/stable/sysfs-firmware-opal-elog
new file mode 100644
index 000000000000..e1f3058f5954
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-firmware-opal-elog
@@ -0,0 +1,60 @@
+What: /sys/firmware/opal/elog
+Date: Feb 2014
+Contact: Stewart Smith <stewart@linux.vnet.ibm.com>
+Description:
+ This directory exposes error log entries retrieved
+ through the OPAL firmware interface.
+
+ Each error log is identified by a unique ID and will
+ exist until explicitly acknowledged to firmware.
+
+ Each log entry has a directory in /sys/firmware/opal/elog.
+
+ Log entries may be purged by the service processor
+ before retrieved by firmware or retrieved/acknowledged by
+ Linux if there is no room for more log entries.
+
+ In the event that Linux has retrieved the log entries
+ but not explicitly acknowledged them to firmware and
+ the service processor needs more room for log entries,
+ the only remaining copy of a log message may be in
+ Linux.
+
+ Typically, a user space daemon will monitor for new
+ entries, read them out and acknowledge them.
+
+ The service processor may be able to store more log
+ entries than firmware can, so after you acknowledge
+ an event from Linux you may instantly get another one
+ from the queue that was generated some time in the past.
+
+ The raw log format is a binary format. We currently
+ do not parse this at all in kernel, leaving it up to
+ user space to solve the problem. In future, we may
+ do more parsing in kernel and add more files to make
+ it easier for simple user space processes to extract
+ more information.
+
+ For each log entry (directory), there are the following
+ files:
+
+ id: An ASCII representation of the ID of the
+ error log, in hex - e.g. "0x01".
+
+ type: An ASCII representation of the type id and
+ description of the type of error log.
+ Currently just "0x00 PEL" - platform error log.
+ In the future there may be additional types.
+
+ raw: A read-only binary file that can be read
+ to get the raw log entry. These are
+ <16kb, often just hundreds of bytes and
+ "average" 2kb.
+
+ acknowledge: Writing 'ack' to this file will acknowledge
+ the error log to firmware (and in turn
+ the service processor, if applicable).
+ Shortly after acknowledging it, the log
+ entry will be removed from sysfs.
+ Reading this file will list the supported
+ operations (curently just acknowledge). \ No newline at end of file
diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-events b/Documentation/ABI/testing/sysfs-bus-event_source-devices-events
index 3c1cc24361bd..7b40a3cbc26a 100644
--- a/Documentation/ABI/testing/sysfs-bus-event_source-devices-events
+++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-events
@@ -57,6 +57,523 @@ What: /sys/devices/cpu/events/PM_1PLUS_PPC_CMPL
/sys/devices/cpu/events/PM_LD_REF_L1
/sys/devices/cpu/events/PM_RUN_CYC
/sys/devices/cpu/events/PM_RUN_INST_CMPL
+ /sys/devices/cpu/events/PM_IC_DEMAND_L2_BR_ALL
+ /sys/devices/cpu/events/PM_GCT_UTIL_7_TO_10_SLOTS
+ /sys/devices/cpu/events/PM_PMC2_SAVED
+ /sys/devices/cpu/events/PM_VSU0_16FLOP
+ /sys/devices/cpu/events/PM_MRK_LSU_DERAT_MISS
+ /sys/devices/cpu/events/PM_MRK_ST_CMPL
+ /sys/devices/cpu/events/PM_NEST_PAIR3_ADD
+ /sys/devices/cpu/events/PM_L2_ST_DISP
+ /sys/devices/cpu/events/PM_L2_CASTOUT_MOD
+ /sys/devices/cpu/events/PM_ISEG
+ /sys/devices/cpu/events/PM_MRK_INST_TIMEO
+ /sys/devices/cpu/events/PM_L2_RCST_DISP_FAIL_ADDR
+ /sys/devices/cpu/events/PM_LSU1_DC_PREF_STREAM_CONFIRM
+ /sys/devices/cpu/events/PM_IERAT_WR_64K
+ /sys/devices/cpu/events/PM_MRK_DTLB_MISS_16M
+ /sys/devices/cpu/events/PM_IERAT_MISS
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_LMEM
+ /sys/devices/cpu/events/PM_FLOP
+ /sys/devices/cpu/events/PM_THRD_PRIO_4_5_CYC
+ /sys/devices/cpu/events/PM_BR_PRED_TA
+ /sys/devices/cpu/events/PM_EXT_INT
+ /sys/devices/cpu/events/PM_VSU_FSQRT_FDIV
+ /sys/devices/cpu/events/PM_MRK_LD_MISS_EXPOSED_CYC
+ /sys/devices/cpu/events/PM_LSU1_LDF
+ /sys/devices/cpu/events/PM_IC_WRITE_ALL
+ /sys/devices/cpu/events/PM_LSU0_SRQ_STFWD
+ /sys/devices/cpu/events/PM_PTEG_FROM_RL2L3_MOD
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L31_SHR
+ /sys/devices/cpu/events/PM_DATA_FROM_L21_MOD
+ /sys/devices/cpu/events/PM_VSU1_SCAL_DOUBLE_ISSUED
+ /sys/devices/cpu/events/PM_VSU0_8FLOP
+ /sys/devices/cpu/events/PM_POWER_EVENT1
+ /sys/devices/cpu/events/PM_DISP_CLB_HELD_BAL
+ /sys/devices/cpu/events/PM_VSU1_2FLOP
+ /sys/devices/cpu/events/PM_LWSYNC_HELD
+ /sys/devices/cpu/events/PM_PTEG_FROM_DL2L3_SHR
+ /sys/devices/cpu/events/PM_INST_FROM_L21_MOD
+ /sys/devices/cpu/events/PM_IERAT_XLATE_WR_16MPLUS
+ /sys/devices/cpu/events/PM_IC_REQ_ALL
+ /sys/devices/cpu/events/PM_DSLB_MISS
+ /sys/devices/cpu/events/PM_L3_MISS
+ /sys/devices/cpu/events/PM_LSU0_L1_PREF
+ /sys/devices/cpu/events/PM_VSU_SCALAR_SINGLE_ISSUED
+ /sys/devices/cpu/events/PM_LSU1_DC_PREF_STREAM_CONFIRM_STRIDE
+ /sys/devices/cpu/events/PM_L2_INST
+ /sys/devices/cpu/events/PM_VSU0_FRSP
+ /sys/devices/cpu/events/PM_FLUSH_DISP
+ /sys/devices/cpu/events/PM_PTEG_FROM_L2MISS
+ /sys/devices/cpu/events/PM_VSU1_DQ_ISSUED
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_DMEM
+ /sys/devices/cpu/events/PM_LSU_FLUSH_ULD
+ /sys/devices/cpu/events/PM_PTEG_FROM_LMEM
+ /sys/devices/cpu/events/PM_MRK_DERAT_MISS_16M
+ /sys/devices/cpu/events/PM_THRD_ALL_RUN_CYC
+ /sys/devices/cpu/events/PM_MEM0_PREFETCH_DISP
+ /sys/devices/cpu/events/PM_MRK_STALL_CMPLU_CYC_COUNT
+ /sys/devices/cpu/events/PM_DATA_FROM_DL2L3_MOD
+ /sys/devices/cpu/events/PM_VSU_FRSP
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L21_MOD
+ /sys/devices/cpu/events/PM_PMC1_OVERFLOW
+ /sys/devices/cpu/events/PM_VSU0_SINGLE
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L3MISS
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L31_SHR
+ /sys/devices/cpu/events/PM_VSU0_VECTOR_SP_ISSUED
+ /sys/devices/cpu/events/PM_VSU1_FEST
+ /sys/devices/cpu/events/PM_MRK_INST_DISP
+ /sys/devices/cpu/events/PM_VSU0_COMPLEX_ISSUED
+ /sys/devices/cpu/events/PM_LSU1_FLUSH_UST
+ /sys/devices/cpu/events/PM_FXU_IDLE
+ /sys/devices/cpu/events/PM_LSU0_FLUSH_ULD
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_DL2L3_MOD
+ /sys/devices/cpu/events/PM_LSU_LMQ_SRQ_EMPTY_ALL_CYC
+ /sys/devices/cpu/events/PM_LSU1_REJECT_LMQ_FULL
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_L21_MOD
+ /sys/devices/cpu/events/PM_INST_FROM_RL2L3_MOD
+ /sys/devices/cpu/events/PM_SHL_CREATED
+ /sys/devices/cpu/events/PM_L2_ST_HIT
+ /sys/devices/cpu/events/PM_DATA_FROM_DMEM
+ /sys/devices/cpu/events/PM_L3_LD_MISS
+ /sys/devices/cpu/events/PM_FXU1_BUSY_FXU0_IDLE
+ /sys/devices/cpu/events/PM_DISP_CLB_HELD_RES
+ /sys/devices/cpu/events/PM_L2_SN_SX_I_DONE
+ /sys/devices/cpu/events/PM_STCX_CMPL
+ /sys/devices/cpu/events/PM_VSU0_2FLOP
+ /sys/devices/cpu/events/PM_L3_PREF_MISS
+ /sys/devices/cpu/events/PM_LSU_SRQ_SYNC_CYC
+ /sys/devices/cpu/events/PM_LSU_REJECT_ERAT_MISS
+ /sys/devices/cpu/events/PM_L1_ICACHE_MISS
+ /sys/devices/cpu/events/PM_LSU1_FLUSH_SRQ
+ /sys/devices/cpu/events/PM_LD_REF_L1_LSU0
+ /sys/devices/cpu/events/PM_VSU0_FEST
+ /sys/devices/cpu/events/PM_VSU_VECTOR_SINGLE_ISSUED
+ /sys/devices/cpu/events/PM_FREQ_UP
+ /sys/devices/cpu/events/PM_DATA_FROM_LMEM
+ /sys/devices/cpu/events/PM_LSU1_LDX
+ /sys/devices/cpu/events/PM_PMC3_OVERFLOW
+ /sys/devices/cpu/events/PM_MRK_BR_MPRED
+ /sys/devices/cpu/events/PM_SHL_MATCH
+ /sys/devices/cpu/events/PM_MRK_BR_TAKEN
+ /sys/devices/cpu/events/PM_ISLB_MISS
+ /sys/devices/cpu/events/PM_DISP_HELD_THERMAL
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_RL2L3_SHR
+ /sys/devices/cpu/events/PM_LSU1_SRQ_STFWD
+ /sys/devices/cpu/events/PM_PTEG_FROM_DMEM
+ /sys/devices/cpu/events/PM_VSU_2FLOP
+ /sys/devices/cpu/events/PM_GCT_FULL_CYC
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L3_CYC
+ /sys/devices/cpu/events/PM_LSU_SRQ_S0_ALLOC
+ /sys/devices/cpu/events/PM_MRK_DERAT_MISS_4K
+ /sys/devices/cpu/events/PM_BR_MPRED_TA
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_L2MISS
+ /sys/devices/cpu/events/PM_DPU_HELD_POWER
+ /sys/devices/cpu/events/PM_MRK_VSU_FIN
+ /sys/devices/cpu/events/PM_LSU_SRQ_S0_VALID
+ /sys/devices/cpu/events/PM_GCT_EMPTY_CYC
+ /sys/devices/cpu/events/PM_IOPS_DISP
+ /sys/devices/cpu/events/PM_RUN_SPURR
+ /sys/devices/cpu/events/PM_PTEG_FROM_L21_MOD
+ /sys/devices/cpu/events/PM_VSU0_1FLOP
+ /sys/devices/cpu/events/PM_SNOOP_TLBIE
+ /sys/devices/cpu/events/PM_DATA_FROM_L3MISS
+ /sys/devices/cpu/events/PM_VSU_SINGLE
+ /sys/devices/cpu/events/PM_DTLB_MISS_16G
+ /sys/devices/cpu/events/PM_FLUSH
+ /sys/devices/cpu/events/PM_L2_LD_HIT
+ /sys/devices/cpu/events/PM_NEST_PAIR2_AND
+ /sys/devices/cpu/events/PM_VSU1_1FLOP
+ /sys/devices/cpu/events/PM_IC_PREF_REQ
+ /sys/devices/cpu/events/PM_L3_LD_HIT
+ /sys/devices/cpu/events/PM_DISP_HELD
+ /sys/devices/cpu/events/PM_L2_LD
+ /sys/devices/cpu/events/PM_LSU_FLUSH_SRQ
+ /sys/devices/cpu/events/PM_BC_PLUS_8_CONV
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L31_MOD_CYC
+ /sys/devices/cpu/events/PM_L2_RCST_BUSY_RC_FULL
+ /sys/devices/cpu/events/PM_TB_BIT_TRANS
+ /sys/devices/cpu/events/PM_THERMAL_MAX
+ /sys/devices/cpu/events/PM_LSU1_FLUSH_ULD
+ /sys/devices/cpu/events/PM_LSU1_REJECT_LHS
+ /sys/devices/cpu/events/PM_LSU_LRQ_S0_ALLOC
+ /sys/devices/cpu/events/PM_L3_CO_L31
+ /sys/devices/cpu/events/PM_POWER_EVENT4
+ /sys/devices/cpu/events/PM_DATA_FROM_L31_SHR
+ /sys/devices/cpu/events/PM_BR_UNCOND
+ /sys/devices/cpu/events/PM_LSU1_DC_PREF_STREAM_ALLOC
+ /sys/devices/cpu/events/PM_PMC4_REWIND
+ /sys/devices/cpu/events/PM_L2_RCLD_DISP
+ /sys/devices/cpu/events/PM_THRD_PRIO_2_3_CYC
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L2MISS
+ /sys/devices/cpu/events/PM_IC_DEMAND_L2_BHT_REDIRECT
+ /sys/devices/cpu/events/PM_DATA_FROM_L31_SHR
+ /sys/devices/cpu/events/PM_IC_PREF_CANCEL_L2
+ /sys/devices/cpu/events/PM_MRK_FIN_STALL_CYC_COUNT
+ /sys/devices/cpu/events/PM_BR_PRED_CCACHE
+ /sys/devices/cpu/events/PM_GCT_UTIL_1_TO_2_SLOTS
+ /sys/devices/cpu/events/PM_MRK_ST_CMPL_INT
+ /sys/devices/cpu/events/PM_LSU_TWO_TABLEWALK_CYC
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L3MISS
+ /sys/devices/cpu/events/PM_LSU_SET_MPRED
+ /sys/devices/cpu/events/PM_FLUSH_DISP_TLBIE
+ /sys/devices/cpu/events/PM_VSU1_FCONV
+ /sys/devices/cpu/events/PM_DERAT_MISS_16G
+ /sys/devices/cpu/events/PM_INST_FROM_LMEM
+ /sys/devices/cpu/events/PM_IC_DEMAND_L2_BR_REDIRECT
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_L2
+ /sys/devices/cpu/events/PM_PTEG_FROM_L2
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L21_SHR_CYC
+ /sys/devices/cpu/events/PM_MRK_DTLB_MISS_4K
+ /sys/devices/cpu/events/PM_VSU0_FPSCR
+ /sys/devices/cpu/events/PM_VSU1_VECT_DOUBLE_ISSUED
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_RL2L3_MOD
+ /sys/devices/cpu/events/PM_MEM0_RQ_DISP
+ /sys/devices/cpu/events/PM_L2_LD_MISS
+ /sys/devices/cpu/events/PM_VMX_RESULT_SAT_1
+ /sys/devices/cpu/events/PM_L1_PREF
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_LMEM_CYC
+ /sys/devices/cpu/events/PM_GRP_IC_MISS_NONSPEC
+ /sys/devices/cpu/events/PM_PB_NODE_PUMP
+ /sys/devices/cpu/events/PM_SHL_MERGED
+ /sys/devices/cpu/events/PM_NEST_PAIR1_ADD
+ /sys/devices/cpu/events/PM_DATA_FROM_L3
+ /sys/devices/cpu/events/PM_LSU_FLUSH
+ /sys/devices/cpu/events/PM_LSU_SRQ_SYNC_COUNT
+ /sys/devices/cpu/events/PM_PMC2_OVERFLOW
+ /sys/devices/cpu/events/PM_LSU_LDF
+ /sys/devices/cpu/events/PM_POWER_EVENT3
+ /sys/devices/cpu/events/PM_DISP_WT
+ /sys/devices/cpu/events/PM_IC_BANK_CONFLICT
+ /sys/devices/cpu/events/PM_BR_MPRED_CR_TA
+ /sys/devices/cpu/events/PM_L2_INST_MISS
+ /sys/devices/cpu/events/PM_NEST_PAIR2_ADD
+ /sys/devices/cpu/events/PM_MRK_LSU_FLUSH
+ /sys/devices/cpu/events/PM_L2_LDST
+ /sys/devices/cpu/events/PM_INST_FROM_L31_SHR
+ /sys/devices/cpu/events/PM_VSU0_FIN
+ /sys/devices/cpu/events/PM_VSU1_FCONV
+ /sys/devices/cpu/events/PM_INST_FROM_RMEM
+ /sys/devices/cpu/events/PM_DISP_CLB_HELD_TLBIE
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_DMEM_CYC
+ /sys/devices/cpu/events/PM_BR_PRED_CR
+ /sys/devices/cpu/events/PM_LSU_REJECT
+ /sys/devices/cpu/events/PM_GCT_UTIL_3_TO_6_SLOTS
+ /sys/devices/cpu/events/PM_CMPLU_STALL_END_GCT_NOSLOT
+ /sys/devices/cpu/events/PM_LSU0_REJECT_LMQ_FULL
+ /sys/devices/cpu/events/PM_VSU_FEST
+ /sys/devices/cpu/events/PM_NEST_PAIR0_AND
+ /sys/devices/cpu/events/PM_PTEG_FROM_L3
+ /sys/devices/cpu/events/PM_POWER_EVENT2
+ /sys/devices/cpu/events/PM_IC_PREF_CANCEL_PAGE
+ /sys/devices/cpu/events/PM_VSU0_FSQRT_FDIV
+ /sys/devices/cpu/events/PM_MRK_GRP_CMPL
+ /sys/devices/cpu/events/PM_VSU0_SCAL_DOUBLE_ISSUED
+ /sys/devices/cpu/events/PM_GRP_DISP
+ /sys/devices/cpu/events/PM_LSU0_LDX
+ /sys/devices/cpu/events/PM_DATA_FROM_L2
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_RL2L3_MOD
+ /sys/devices/cpu/events/PM_VSU0_VECT_DOUBLE_ISSUED
+ /sys/devices/cpu/events/PM_VSU1_2FLOP_DOUBLE
+ /sys/devices/cpu/events/PM_THRD_PRIO_6_7_CYC
+ /sys/devices/cpu/events/PM_BC_PLUS_8_RSLV_TAKEN
+ /sys/devices/cpu/events/PM_BR_MPRED_CR
+ /sys/devices/cpu/events/PM_L3_CO_MEM
+ /sys/devices/cpu/events/PM_DATA_FROM_RL2L3_MOD
+ /sys/devices/cpu/events/PM_LSU_SRQ_FULL_CYC
+ /sys/devices/cpu/events/PM_TABLEWALK_CYC
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_RMEM
+ /sys/devices/cpu/events/PM_LSU_SRQ_STFWD
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_RMEM
+ /sys/devices/cpu/events/PM_FXU0_FIN
+ /sys/devices/cpu/events/PM_LSU1_L1_SW_PREF
+ /sys/devices/cpu/events/PM_PTEG_FROM_L31_MOD
+ /sys/devices/cpu/events/PM_PMC5_OVERFLOW
+ /sys/devices/cpu/events/PM_LD_REF_L1_LSU1
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_L21_SHR
+ /sys/devices/cpu/events/PM_DATA_FROM_RMEM
+ /sys/devices/cpu/events/PM_VSU0_SCAL_SINGLE_ISSUED
+ /sys/devices/cpu/events/PM_BR_MPRED_LSTACK
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_RL2L3_MOD_CYC
+ /sys/devices/cpu/events/PM_LSU0_FLUSH_UST
+ /sys/devices/cpu/events/PM_LSU_NCST
+ /sys/devices/cpu/events/PM_BR_TAKEN
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_LMEM
+ /sys/devices/cpu/events/PM_DTLB_MISS_4K
+ /sys/devices/cpu/events/PM_PMC4_SAVED
+ /sys/devices/cpu/events/PM_VSU1_PERMUTE_ISSUED
+ /sys/devices/cpu/events/PM_SLB_MISS
+ /sys/devices/cpu/events/PM_LSU1_FLUSH_LRQ
+ /sys/devices/cpu/events/PM_DTLB_MISS
+ /sys/devices/cpu/events/PM_VSU1_FRSP
+ /sys/devices/cpu/events/PM_VSU_VECTOR_DOUBLE_ISSUED
+ /sys/devices/cpu/events/PM_L2_CASTOUT_SHR
+ /sys/devices/cpu/events/PM_DATA_FROM_DL2L3_SHR
+ /sys/devices/cpu/events/PM_VSU1_STF
+ /sys/devices/cpu/events/PM_ST_FIN
+ /sys/devices/cpu/events/PM_PTEG_FROM_L21_SHR
+ /sys/devices/cpu/events/PM_L2_LOC_GUESS_WRONG
+ /sys/devices/cpu/events/PM_MRK_STCX_FAIL
+ /sys/devices/cpu/events/PM_LSU0_REJECT_LHS
+ /sys/devices/cpu/events/PM_IC_PREF_CANCEL_HIT
+ /sys/devices/cpu/events/PM_L3_PREF_BUSY
+ /sys/devices/cpu/events/PM_MRK_BRU_FIN
+ /sys/devices/cpu/events/PM_LSU1_NCLD
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_L31_MOD
+ /sys/devices/cpu/events/PM_LSU_NCLD
+ /sys/devices/cpu/events/PM_LSU_LDX
+ /sys/devices/cpu/events/PM_L2_LOC_GUESS_CORRECT
+ /sys/devices/cpu/events/PM_THRESH_TIMEO
+ /sys/devices/cpu/events/PM_L3_PREF_ST
+ /sys/devices/cpu/events/PM_DISP_CLB_HELD_SYNC
+ /sys/devices/cpu/events/PM_VSU_SIMPLE_ISSUED
+ /sys/devices/cpu/events/PM_VSU1_SINGLE
+ /sys/devices/cpu/events/PM_DATA_TABLEWALK_CYC
+ /sys/devices/cpu/events/PM_L2_RC_ST_DONE
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L21_MOD
+ /sys/devices/cpu/events/PM_LARX_LSU1
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_RMEM
+ /sys/devices/cpu/events/PM_DISP_CLB_HELD
+ /sys/devices/cpu/events/PM_DERAT_MISS_4K
+ /sys/devices/cpu/events/PM_L2_RCLD_DISP_FAIL_ADDR
+ /sys/devices/cpu/events/PM_SEG_EXCEPTION
+ /sys/devices/cpu/events/PM_FLUSH_DISP_SB
+ /sys/devices/cpu/events/PM_L2_DC_INV
+ /sys/devices/cpu/events/PM_PTEG_FROM_DL2L3_MOD
+ /sys/devices/cpu/events/PM_DSEG
+ /sys/devices/cpu/events/PM_BR_PRED_LSTACK
+ /sys/devices/cpu/events/PM_VSU0_STF
+ /sys/devices/cpu/events/PM_LSU_FX_FIN
+ /sys/devices/cpu/events/PM_DERAT_MISS_16M
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_DL2L3_MOD
+ /sys/devices/cpu/events/PM_GCT_UTIL_11_PLUS_SLOTS
+ /sys/devices/cpu/events/PM_INST_FROM_L3
+ /sys/devices/cpu/events/PM_MRK_IFU_FIN
+ /sys/devices/cpu/events/PM_ITLB_MISS
+ /sys/devices/cpu/events/PM_VSU_STF
+ /sys/devices/cpu/events/PM_LSU_FLUSH_UST
+ /sys/devices/cpu/events/PM_L2_LDST_MISS
+ /sys/devices/cpu/events/PM_FXU1_FIN
+ /sys/devices/cpu/events/PM_SHL_DEALLOCATED
+ /sys/devices/cpu/events/PM_L2_SN_M_WR_DONE
+ /sys/devices/cpu/events/PM_LSU_REJECT_SET_MPRED
+ /sys/devices/cpu/events/PM_L3_PREF_LD
+ /sys/devices/cpu/events/PM_L2_SN_M_RD_DONE
+ /sys/devices/cpu/events/PM_MRK_DERAT_MISS_16G
+ /sys/devices/cpu/events/PM_VSU_FCONV
+ /sys/devices/cpu/events/PM_ANY_THRD_RUN_CYC
+ /sys/devices/cpu/events/PM_LSU_LMQ_FULL_CYC
+ /sys/devices/cpu/events/PM_MRK_LSU_REJECT_LHS
+ /sys/devices/cpu/events/PM_MRK_LD_MISS_L1_CYC
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L2_CYC
+ /sys/devices/cpu/events/PM_INST_IMC_MATCH_DISP
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_RMEM_CYC
+ /sys/devices/cpu/events/PM_VSU0_SIMPLE_ISSUED
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_RL2L3_SHR
+ /sys/devices/cpu/events/PM_VSU_FMA_DOUBLE
+ /sys/devices/cpu/events/PM_VSU_4FLOP
+ /sys/devices/cpu/events/PM_VSU1_FIN
+ /sys/devices/cpu/events/PM_NEST_PAIR1_AND
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_RL2L3_MOD
+ /sys/devices/cpu/events/PM_PTEG_FROM_RMEM
+ /sys/devices/cpu/events/PM_LSU_LRQ_S0_VALID
+ /sys/devices/cpu/events/PM_LSU0_LDF
+ /sys/devices/cpu/events/PM_FLUSH_COMPLETION
+ /sys/devices/cpu/events/PM_ST_MISS_L1
+ /sys/devices/cpu/events/PM_L2_NODE_PUMP
+ /sys/devices/cpu/events/PM_INST_FROM_DL2L3_SHR
+ /sys/devices/cpu/events/PM_MRK_STALL_CMPLU_CYC
+ /sys/devices/cpu/events/PM_VSU1_DENORM
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L31_SHR_CYC
+ /sys/devices/cpu/events/PM_NEST_PAIR0_ADD
+ /sys/devices/cpu/events/PM_INST_FROM_L3MISS
+ /sys/devices/cpu/events/PM_EE_OFF_EXT_INT
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_DMEM
+ /sys/devices/cpu/events/PM_INST_FROM_DL2L3_MOD
+ /sys/devices/cpu/events/PM_PMC6_OVERFLOW
+ /sys/devices/cpu/events/PM_VSU_2FLOP_DOUBLE
+ /sys/devices/cpu/events/PM_TLB_MISS
+ /sys/devices/cpu/events/PM_FXU_BUSY
+ /sys/devices/cpu/events/PM_L2_RCLD_DISP_FAIL_OTHER
+ /sys/devices/cpu/events/PM_LSU_REJECT_LMQ_FULL
+ /sys/devices/cpu/events/PM_IC_RELOAD_SHR
+ /sys/devices/cpu/events/PM_GRP_MRK
+ /sys/devices/cpu/events/PM_MRK_ST_NEST
+ /sys/devices/cpu/events/PM_VSU1_FSQRT_FDIV
+ /sys/devices/cpu/events/PM_LSU0_FLUSH_LRQ
+ /sys/devices/cpu/events/PM_LARX_LSU0
+ /sys/devices/cpu/events/PM_IBUF_FULL_CYC
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_DL2L3_SHR_CYC
+ /sys/devices/cpu/events/PM_LSU_DC_PREF_STREAM_ALLOC
+ /sys/devices/cpu/events/PM_GRP_MRK_CYC
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_RL2L3_SHR_CYC
+ /sys/devices/cpu/events/PM_L2_GLOB_GUESS_CORRECT
+ /sys/devices/cpu/events/PM_LSU_REJECT_LHS
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_LMEM
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_L3
+ /sys/devices/cpu/events/PM_FREQ_DOWN
+ /sys/devices/cpu/events/PM_PB_RETRY_NODE_PUMP
+ /sys/devices/cpu/events/PM_INST_FROM_RL2L3_SHR
+ /sys/devices/cpu/events/PM_MRK_INST_ISSUED
+ /sys/devices/cpu/events/PM_PTEG_FROM_L3MISS
+ /sys/devices/cpu/events/PM_RUN_PURR
+ /sys/devices/cpu/events/PM_MRK_GRP_IC_MISS
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L3
+ /sys/devices/cpu/events/PM_PTEG_FROM_RL2L3_SHR
+ /sys/devices/cpu/events/PM_LSU_FLUSH_LRQ
+ /sys/devices/cpu/events/PM_MRK_DERAT_MISS_64K
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_DL2L3_MOD
+ /sys/devices/cpu/events/PM_L2_ST_MISS
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L21_SHR
+ /sys/devices/cpu/events/PM_LWSYNC
+ /sys/devices/cpu/events/PM_LSU0_DC_PREF_STREAM_CONFIRM_STRIDE
+ /sys/devices/cpu/events/PM_MRK_LSU_FLUSH_LRQ
+ /sys/devices/cpu/events/PM_INST_IMC_MATCH_CMPL
+ /sys/devices/cpu/events/PM_NEST_PAIR3_AND
+ /sys/devices/cpu/events/PM_PB_RETRY_SYS_PUMP
+ /sys/devices/cpu/events/PM_MRK_INST_FIN
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_DL2L3_SHR
+ /sys/devices/cpu/events/PM_INST_FROM_L31_MOD
+ /sys/devices/cpu/events/PM_MRK_DTLB_MISS_64K
+ /sys/devices/cpu/events/PM_LSU_FIN
+ /sys/devices/cpu/events/PM_MRK_LSU_REJECT
+ /sys/devices/cpu/events/PM_L2_CO_FAIL_BUSY
+ /sys/devices/cpu/events/PM_MEM0_WQ_DISP
+ /sys/devices/cpu/events/PM_DATA_FROM_L31_MOD
+ /sys/devices/cpu/events/PM_THERMAL_WARN
+ /sys/devices/cpu/events/PM_VSU0_4FLOP
+ /sys/devices/cpu/events/PM_BR_MPRED_CCACHE
+ /sys/devices/cpu/events/PM_L1_DEMAND_WRITE
+ /sys/devices/cpu/events/PM_FLUSH_BR_MPRED
+ /sys/devices/cpu/events/PM_MRK_DTLB_MISS_16G
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_DMEM
+ /sys/devices/cpu/events/PM_L2_RCST_DISP
+ /sys/devices/cpu/events/PM_LSU_PARTIAL_CDF
+ /sys/devices/cpu/events/PM_DISP_CLB_HELD_SB
+ /sys/devices/cpu/events/PM_VSU0_FMA_DOUBLE
+ /sys/devices/cpu/events/PM_FXU0_BUSY_FXU1_IDLE
+ /sys/devices/cpu/events/PM_IC_DEMAND_CYC
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L21_SHR
+ /sys/devices/cpu/events/PM_MRK_LSU_FLUSH_UST
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_L3MISS
+ /sys/devices/cpu/events/PM_VSU_DENORM
+ /sys/devices/cpu/events/PM_MRK_LSU_PARTIAL_CDF
+ /sys/devices/cpu/events/PM_INST_FROM_L21_SHR
+ /sys/devices/cpu/events/PM_IC_PREF_WRITE
+ /sys/devices/cpu/events/PM_BR_PRED
+ /sys/devices/cpu/events/PM_INST_FROM_DMEM
+ /sys/devices/cpu/events/PM_IC_PREF_CANCEL_ALL
+ /sys/devices/cpu/events/PM_LSU_DC_PREF_STREAM_CONFIRM
+ /sys/devices/cpu/events/PM_MRK_LSU_FLUSH_SRQ
+ /sys/devices/cpu/events/PM_MRK_FIN_STALL_CYC
+ /sys/devices/cpu/events/PM_L2_RCST_DISP_FAIL_OTHER
+ /sys/devices/cpu/events/PM_VSU1_DD_ISSUED
+ /sys/devices/cpu/events/PM_PTEG_FROM_L31_SHR
+ /sys/devices/cpu/events/PM_DATA_FROM_L21_SHR
+ /sys/devices/cpu/events/PM_LSU0_NCLD
+ /sys/devices/cpu/events/PM_VSU1_4FLOP
+ /sys/devices/cpu/events/PM_VSU1_8FLOP
+ /sys/devices/cpu/events/PM_VSU_8FLOP
+ /sys/devices/cpu/events/PM_LSU_LMQ_SRQ_EMPTY_CYC
+ /sys/devices/cpu/events/PM_DTLB_MISS_64K
+ /sys/devices/cpu/events/PM_THRD_CONC_RUN_INST
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L2
+ /sys/devices/cpu/events/PM_PB_SYS_PUMP
+ /sys/devices/cpu/events/PM_VSU_FIN
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L31_MOD
+ /sys/devices/cpu/events/PM_THRD_PRIO_0_1_CYC
+ /sys/devices/cpu/events/PM_DERAT_MISS_64K
+ /sys/devices/cpu/events/PM_PMC2_REWIND
+ /sys/devices/cpu/events/PM_INST_FROM_L2
+ /sys/devices/cpu/events/PM_GRP_BR_MPRED_NONSPEC
+ /sys/devices/cpu/events/PM_INST_DISP
+ /sys/devices/cpu/events/PM_MEM0_RD_CANCEL_TOTAL
+ /sys/devices/cpu/events/PM_LSU0_DC_PREF_STREAM_CONFIRM
+ /sys/devices/cpu/events/PM_L1_DCACHE_RELOAD_VALID
+ /sys/devices/cpu/events/PM_VSU_SCALAR_DOUBLE_ISSUED
+ /sys/devices/cpu/events/PM_L3_PREF_HIT
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L31_MOD
+ /sys/devices/cpu/events/PM_MRK_FXU_FIN
+ /sys/devices/cpu/events/PM_PMC4_OVERFLOW
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L3
+ /sys/devices/cpu/events/PM_LSU0_LMQ_LHR_MERGE
+ /sys/devices/cpu/events/PM_BTAC_HIT
+ /sys/devices/cpu/events/PM_L3_RD_BUSY
+ /sys/devices/cpu/events/PM_LSU0_L1_SW_PREF
+ /sys/devices/cpu/events/PM_INST_FROM_L2MISS
+ /sys/devices/cpu/events/PM_LSU0_DC_PREF_STREAM_ALLOC
+ /sys/devices/cpu/events/PM_L2_ST
+ /sys/devices/cpu/events/PM_VSU0_DENORM
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_DL2L3_SHR
+ /sys/devices/cpu/events/PM_BR_PRED_CR_TA
+ /sys/devices/cpu/events/PM_VSU0_FCONV
+ /sys/devices/cpu/events/PM_MRK_LSU_FLUSH_ULD
+ /sys/devices/cpu/events/PM_BTAC_MISS
+ /sys/devices/cpu/events/PM_MRK_LD_MISS_EXPOSED_CYC_COUNT
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L2
+ /sys/devices/cpu/events/PM_LSU_DCACHE_RELOAD_VALID
+ /sys/devices/cpu/events/PM_VSU_FMA
+ /sys/devices/cpu/events/PM_LSU0_FLUSH_SRQ
+ /sys/devices/cpu/events/PM_LSU1_L1_PREF
+ /sys/devices/cpu/events/PM_IOPS_CMPL
+ /sys/devices/cpu/events/PM_L2_SYS_PUMP
+ /sys/devices/cpu/events/PM_L2_RCLD_BUSY_RC_FULL
+ /sys/devices/cpu/events/PM_LSU_LMQ_S0_ALLOC
+ /sys/devices/cpu/events/PM_FLUSH_DISP_SYNC
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_DL2L3_MOD_CYC
+ /sys/devices/cpu/events/PM_L2_IC_INV
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L21_MOD_CYC
+ /sys/devices/cpu/events/PM_L3_PREF_LDST
+ /sys/devices/cpu/events/PM_LSU_SRQ_EMPTY_CYC
+ /sys/devices/cpu/events/PM_LSU_LMQ_S0_VALID
+ /sys/devices/cpu/events/PM_FLUSH_PARTIAL
+ /sys/devices/cpu/events/PM_VSU1_FMA_DOUBLE
+ /sys/devices/cpu/events/PM_1PLUS_PPC_DISP
+ /sys/devices/cpu/events/PM_DATA_FROM_L2MISS
+ /sys/devices/cpu/events/PM_SUSPENDED
+ /sys/devices/cpu/events/PM_VSU0_FMA
+ /sys/devices/cpu/events/PM_STCX_FAIL
+ /sys/devices/cpu/events/PM_VSU0_FSQRT_FDIV_DOUBLE
+ /sys/devices/cpu/events/PM_DC_PREF_DST
+ /sys/devices/cpu/events/PM_VSU1_SCAL_SINGLE_ISSUED
+ /sys/devices/cpu/events/PM_L3_HIT
+ /sys/devices/cpu/events/PM_L2_GLOB_GUESS_WRONG
+ /sys/devices/cpu/events/PM_MRK_DFU_FIN
+ /sys/devices/cpu/events/PM_INST_FROM_L1
+ /sys/devices/cpu/events/PM_IC_DEMAND_REQ
+ /sys/devices/cpu/events/PM_VSU1_FSQRT_FDIV_DOUBLE
+ /sys/devices/cpu/events/PM_VSU1_FMA
+ /sys/devices/cpu/events/PM_MRK_LD_MISS_L1
+ /sys/devices/cpu/events/PM_VSU0_2FLOP_DOUBLE
+ /sys/devices/cpu/events/PM_LSU_DC_PREF_STRIDED_STREAM_CONFIRM
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_L31_SHR
+ /sys/devices/cpu/events/PM_MRK_LSU_REJECT_ERAT_MISS
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L2MISS
+ /sys/devices/cpu/events/PM_DATA_FROM_RL2L3_SHR
+ /sys/devices/cpu/events/PM_INST_FROM_PREF
+ /sys/devices/cpu/events/PM_VSU1_SQ
+ /sys/devices/cpu/events/PM_L2_LD_DISP
+ /sys/devices/cpu/events/PM_L2_DISP_ALL
+ /sys/devices/cpu/events/PM_THRD_GRP_CMPL_BOTH_CYC
+ /sys/devices/cpu/events/PM_VSU_FSQRT_FDIV_DOUBLE
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_DL2L3_SHR
+ /sys/devices/cpu/events/PM_VSU_1FLOP
+ /sys/devices/cpu/events/PM_HV_CYC
+ /sys/devices/cpu/events/PM_MRK_LSU_FIN
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_RL2L3_SHR
+ /sys/devices/cpu/events/PM_DTLB_MISS_16M
+ /sys/devices/cpu/events/PM_LSU1_LMQ_LHR_MERGE
+ /sys/devices/cpu/events/PM_IFU_FIN
+ /sys/devices/cpu/events/PM_1THRD_CON_RUN_INSTR
+ /sys/devices/cpu/events/PM_CMPLU_STALL_COUNT
+ /sys/devices/cpu/events/PM_MEM0_PB_RD_CL
+ /sys/devices/cpu/events/PM_THRD_1_RUN_CYC
+ /sys/devices/cpu/events/PM_THRD_2_CONC_RUN_INSTR
+ /sys/devices/cpu/events/PM_THRD_2_RUN_CYC
+ /sys/devices/cpu/events/PM_THRD_3_CONC_RUN_INST
+ /sys/devices/cpu/events/PM_THRD_3_RUN_CYC
+ /sys/devices/cpu/events/PM_THRD_4_CONC_RUN_INST
+ /sys/devices/cpu/events/PM_THRD_4_RUN_CYC
Date: 2013/01/08
diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_24x7 b/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_24x7
new file mode 100644
index 000000000000..e78ee798d7bd
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_24x7
@@ -0,0 +1,23 @@
+What: /sys/bus/event_source/devices/hv_24x7/interface/catalog
+Date: February 2014
+Contact: Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+ Provides access to the binary "24x7 catalog" provided by the
+ hypervisor on POWER7 and 8 systems. This catalog lists events
+ avaliable from the powerpc "hv_24x7" pmu. Its format is
+ documented here:
+ https://raw.githubusercontent.com/jmesmon/catalog-24x7/master/hv-24x7-catalog.h
+
+What: /sys/bus/event_source/devices/hv_24x7/interface/catalog_length
+Date: February 2014
+Contact: Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+ A number equal to the length in bytes of the catalog. This is
+ also extractable from the provided binary "catalog" sysfs entry.
+
+What: /sys/bus/event_source/devices/hv_24x7/interface/catalog_version
+Date: February 2014
+Contact: Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+ Exposes the "version" field of the 24x7 catalog. This is also
+ extractable from the provided binary "catalog" sysfs entry.
diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_gpci b/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_gpci
new file mode 100644
index 000000000000..3fa58c23f13b
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_gpci
@@ -0,0 +1,43 @@
+What: /sys/bus/event_source/devices/hv_gpci/interface/collect_privileged
+Date: February 2014
+Contact: Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+ '0' if the hypervisor is configured to forbid access to event
+ counters being accumulated by other guests and to physical
+ domain event counters.
+ '1' if that access is allowed.
+
+What: /sys/bus/event_source/devices/hv_gpci/interface/ga
+Date: February 2014
+Contact: Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+ 0 or 1. Indicates whether we have access to "GA" events (listed
+ in arch/powerpc/perf/hv-gpci.h).
+
+What: /sys/bus/event_source/devices/hv_gpci/interface/expanded
+Date: February 2014
+Contact: Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+ 0 or 1. Indicates whether we have access to "EXPANDED" events (listed
+ in arch/powerpc/perf/hv-gpci.h).
+
+What: /sys/bus/event_source/devices/hv_gpci/interface/lab
+Date: February 2014
+Contact: Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+ 0 or 1. Indicates whether we have access to "LAB" events (listed
+ in arch/powerpc/perf/hv-gpci.h).
+
+What: /sys/bus/event_source/devices/hv_gpci/interface/version
+Date: February 2014
+Contact: Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+ A number indicating the version of the gpci interface that the
+ hypervisor reports supporting.
+
+What: /sys/bus/event_source/devices/hv_gpci/interface/kernel_version
+Date: February 2014
+Contact: Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+ A number indicating the latest version of the gpci interface
+ that the kernel is aware of.
diff --git a/Documentation/ABI/testing/sysfs-bus-mdio b/Documentation/ABI/testing/sysfs-bus-mdio
index 6349749ebc29..491baaf4285f 100644
--- a/Documentation/ABI/testing/sysfs-bus-mdio
+++ b/Documentation/ABI/testing/sysfs-bus-mdio
@@ -7,3 +7,23 @@ Description:
by the device during bus enumeration, encoded in hexadecimal.
This ID is used to match the device with the appropriate
driver.
+
+What: /sys/bus/mdio_bus/devices/.../phy_interface
+Date: February 2014
+KernelVersion: 3.15
+Contact: netdev@vger.kernel.org
+Description:
+ This attribute contains the PHY interface as configured by the
+ Ethernet driver during bus enumeration, encoded in string.
+ This interface mode is used to configure the Ethernet MAC with the
+ appropriate mode for its data lines to the PHY hardware.
+
+What: /sys/bus/mdio_bus/devices/.../phy_has_fixups
+Date: February 2014
+KernelVersion: 3.15
+Contact: netdev@vger.kernel.org
+Description:
+ This attribute contains the boolean value whether a given PHY
+ device has had any "fixup" workaround running on it, encoded as
+ a boolean. This information is provided to help troubleshooting
+ PHY configurations.
diff --git a/Documentation/ABI/testing/sysfs-class-net b/Documentation/ABI/testing/sysfs-class-net
new file mode 100644
index 000000000000..d922060e455d
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-net
@@ -0,0 +1,199 @@
+What: /sys/class/net/<iface>/addr_assign_type
+Date: July 2010
+KernelVersion: 3.2
+Contact: netdev@vger.kernel.org
+Description:
+ Indicates the address assignment type. Possible values are:
+ 0: permanent address
+ 1: randomly generated
+ 2: stolen from another device
+ 3: set using dev_set_mac_address
+
+What: /sys/class/net/<iface>/addr_len
+Date: April 2005
+KernelVersion: 2.6.12
+Contact: netdev@vger.kernel.org
+Description:
+ Indicates the hardware address size in bytes.
+ Values vary based on the lower-level protocol used by the
+ interface (Ethernet, FDDI, ATM, IEEE 802.15.4...). See
+ include/uapi/linux/if_*.h for actual values.
+
+What: /sys/class/net/<iface>/address
+Date: April 2005
+KernelVersion: 2.6.12
+Contact: netdev@vger.kernel.org
+Description:
+ Hardware address currently assigned to this interface.
+ Format is a string, e.g: 00:11:22:33:44:55 for an Ethernet MAC
+ address.
+
+What: /sys/class/net/<iface>/broadcast
+Date: April 2005
+KernelVersion: 2.6.12
+Contact: netdev@vger.kernel.org
+Description:
+ Hardware broadcast address for this interface. Format is a
+ string, e.g: ff:ff:ff:ff:ff:ff for an Ethernet broadcast MAC
+ address.
+
+What: /sys/class/net/<iface>/carrier
+Date: April 2005
+KernelVersion: 2.6.12
+Contact: netdev@vger.kernel.org
+Description:
+ Indicates the current physical link state of the interface.
+ Posssible values are:
+ 0: physical link is down
+ 1: physical link is up
+
+ Note: some special devices, e.g: bonding and team drivers will
+ allow this attribute to be written to force a link state for
+ operating correctly and designating another fallback interface.
+
+What: /sys/class/net/<iface>/dev_id
+Date: April 2008
+KernelVersion: 2.6.26
+Contact: netdev@vger.kernel.org
+Description:
+ Indicates the device unique identifier. Format is an hexadecimal
+ value. This is used to disambiguate interfaces which might be
+ stacked (e.g: VLAN interfaces) but still have the same MAC
+ address as their parent device.
+
+What: /sys/class/net/<iface>/dormant
+Date: March 2006
+KernelVersion: 2.6.17
+Contact: netdev@vger.kernel.org
+Description:
+ Indicates whether the interface is in dormant state. Possible
+ values are:
+ 0: interface is not dormant
+ 1: interface is dormant
+
+ This attribute can be used by supplicant software to signal that
+ the device is not usable unless some supplicant-based
+ authentication is performed (e.g: 802.1x). 'link_mode' attribute
+ will also reflect the dormant state.
+
+What: /sys/clas/net/<iface>/duplex
+Date: October 2009
+KernelVersion: 2.6.33
+Contact: netdev@vger.kernel.org
+Description:
+ Indicates the interface latest or current duplex value. Possible
+ values are:
+ half: half duplex
+ full: full duplex
+
+ Note: This attribute is only valid for interfaces that implement
+ the ethtool get_settings method (mostly Ethernet).
+
+What: /sys/class/net/<iface>/flags
+Date: April 2005
+KernelVersion: 2.6.12
+Contact: netdev@vger.kernel.org
+Description:
+ Indicates the interface flags as a bitmask in hexadecimal. See
+ include/uapi/linux/if.h for a list of all possible values and
+ the flags semantics.
+
+What: /sys/class/net/<iface>/ifalias
+Date: September 2008
+KernelVersion: 2.6.28
+Contact: netdev@vger.kernel.org
+Description:
+ Indicates/stores an interface alias name as a string. This can
+ be used for system management purposes.
+
+What: /sys/class/net/<iface>/ifindex
+Date: April 2005
+KernelVersion: 2.6.12
+Contact: netdev@vger.kernel.org
+Description:
+ Indicates the system-wide interface unique index identifier as a
+ decimal number. This attribute is used for mapping an interface
+ identifier to an interface name. It is used throughout the
+ networking stack for specifying the interface specific
+ requests/events.
+
+What: /sys/class/net/<iface>/iflink
+Date: April 2005
+KernelVersion: 2.6.12
+Contact: netdev@vger.kernel.org
+Description:
+ Indicates the system-wide interface unique index identifier a
+ the interface is linked to. Format is decimal. This attribute is
+ used to resolve interfaces chaining, linking and stacking.
+ Physical interfaces have the same 'ifindex' and 'iflink' values.
+
+What: /sys/class/net/<iface>/link_mode
+Date: March 2006
+KernelVersion: 2.6.17
+Contact: netdev@vger.kernel.org
+Description:
+ Indicates the interface link mode, as a decimal number. This
+ attribute should be used in conjunction with 'dormant' attribute
+ to determine the interface usability. Possible values:
+ 0: default link mode
+ 1: dormant link mode
+
+What: /sys/class/net/<iface>/mtu
+Date: April 2005
+KernelVersion: 2.6.12
+Contact: netdev@vger.kernel.org
+Description:
+ Indicates the interface currently configured MTU value, in
+ bytes, and in decimal format. Specific values depends on the
+ lower-level interface protocol used. Ethernet devices will show
+ a 'mtu' attribute value of 1500 unless changed.
+
+What: /sys/calss/net/<iface>/netdev_group
+Date: January 2011
+KernelVersion: 2.6.39
+Contact: netdev@vger.kernel.org
+Description:
+ Indicates the interface network device group, as a decimal
+ integer. Default value is 0 which corresponds to the initial
+ network devices group. The group can be changed to affect
+ routing decisions (see: net/ipv4/fib_rules and
+ net/ipv6/fib6_rules.c).
+
+What: /sys/class/net/<iface>/operstate
+Date: March 2006
+KernelVersion: 2.6.17
+Contact: netdev@vger.kernel.org
+Description:
+ Indicates the interface RFC2863 operational state as a string.
+ Possible values are:
+ "unknown", "notpresent", "down", "lowerlayerdown", "testing",
+ "dormant", "up".
+
+What: /sys/class/net/<iface>/speed
+Date: October 2009
+KernelVersion: 2.6.33
+Contact: netdev@vger.kernel.org
+Description:
+ Indicates the interface latest or current speed value. Value is
+ an integer representing the link speed in Mbits/sec.
+
+ Note: this attribute is only valid for interfaces that implement
+ the ethtool get_settings method (mostly Ethernet ).
+
+What: /sys/class/net/<iface>/tx_queue_len
+Date: April 2005
+KernelVersion: 2.6.12
+Contact: netdev@vger.kernel.org
+Description:
+ Indicates the interface transmit queue len in number of packets,
+ as an integer value. Value depend on the type of interface,
+ Ethernet network adapters have a default value of 1000 unless
+ configured otherwise
+
+What: /sys/class/net/<iface>/type
+Date: April 2005
+KernelVersion: 2.6.12
+Contact: netdev@vger.kernel.org
+Description:
+ Indicates the interface protocol type as a decimal value. See
+ include/uapi/linux/if_arp.h for all possible values.
diff --git a/Documentation/ABI/testing/sysfs-class-net-mesh b/Documentation/ABI/testing/sysfs-class-net-mesh
index 4793d3dff6af..c46406296631 100644
--- a/Documentation/ABI/testing/sysfs-class-net-mesh
+++ b/Documentation/ABI/testing/sysfs-class-net-mesh
@@ -76,6 +76,15 @@ Description:
is used to classify clients as "isolated" by the
Extended Isolation feature.
+What: /sys/class/net/<mesh_iface>/mesh/multicast_mode
+Date: Feb 2014
+Contact: Linus Lüssing <linus.luessing@web.de>
+Description:
+ Indicates whether multicast optimizations are enabled
+ or disabled. If set to zero then all nodes in the
+ mesh are going to use classic flooding for any
+ multicast packet with no optimizations.
+
What: /sys/class/net/<mesh_iface>/mesh/network_coding
Date: Nov 2012
Contact: Martin Hundeboll <martin@hundeboll.net>
diff --git a/Documentation/ABI/testing/sysfs-class-rc b/Documentation/ABI/testing/sysfs-class-rc
new file mode 100644
index 000000000000..b65674da43bb
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-rc
@@ -0,0 +1,111 @@
+What: /sys/class/rc/
+Date: Apr 2010
+KernelVersion: 2.6.35
+Contact: Mauro Carvalho Chehab <m.chehab@samsung.com>
+Description:
+ The rc/ class sub-directory belongs to the Remote Controller
+ core and provides a sysfs interface for configuring infrared
+ remote controller receivers.
+
+What: /sys/class/rc/rcN/
+Date: Apr 2010
+KernelVersion: 2.6.35
+Contact: Mauro Carvalho Chehab <m.chehab@samsung.com>
+Description:
+ A /sys/class/rc/rcN directory is created for each remote
+ control receiver device where N is the number of the receiver.
+
+What: /sys/class/rc/rcN/protocols
+Date: Jun 2010
+KernelVersion: 2.6.36
+Contact: Mauro Carvalho Chehab <m.chehab@samsung.com>
+Description:
+ Reading this file returns a list of available protocols,
+ something like:
+ "rc5 [rc6] nec jvc [sony]"
+ Enabled protocols are shown in [] brackets.
+ Writing "+proto" will add a protocol to the list of enabled
+ protocols.
+ Writing "-proto" will remove a protocol from the list of enabled
+ protocols.
+ Writing "proto" will enable only "proto".
+ Writing "none" will disable all protocols.
+ Write fails with EINVAL if an invalid protocol combination or
+ unknown protocol name is used.
+
+What: /sys/class/rc/rcN/filter
+Date: Jan 2014
+KernelVersion: 3.15
+Contact: Mauro Carvalho Chehab <m.chehab@samsung.com>
+Description:
+ Sets the scancode filter expected value.
+ Use in combination with /sys/class/rc/rcN/filter_mask to set the
+ expected value of the bits set in the filter mask.
+ If the hardware supports it then scancodes which do not match
+ the filter will be ignored. Otherwise the write will fail with
+ an error.
+ This value may be reset to 0 if the current protocol is altered.
+
+What: /sys/class/rc/rcN/filter_mask
+Date: Jan 2014
+KernelVersion: 3.15
+Contact: Mauro Carvalho Chehab <m.chehab@samsung.com>
+Description:
+ Sets the scancode filter mask of bits to compare.
+ Use in combination with /sys/class/rc/rcN/filter to set the bits
+ of the scancode which should be compared against the expected
+ value. A value of 0 disables the filter to allow all valid
+ scancodes to be processed.
+ If the hardware supports it then scancodes which do not match
+ the filter will be ignored. Otherwise the write will fail with
+ an error.
+ This value may be reset to 0 if the current protocol is altered.
+
+What: /sys/class/rc/rcN/wakeup_protocols
+Date: Feb 2014
+KernelVersion: 3.15
+Contact: Mauro Carvalho Chehab <m.chehab@samsung.com>
+Description:
+ Reading this file returns a list of available protocols to use
+ for the wakeup filter, something like:
+ "rc5 rc6 nec jvc [sony]"
+ The enabled wakeup protocol is shown in [] brackets.
+ Writing "+proto" will add a protocol to the list of enabled
+ wakeup protocols.
+ Writing "-proto" will remove a protocol from the list of enabled
+ wakeup protocols.
+ Writing "proto" will use "proto" for wakeup events.
+ Writing "none" will disable wakeup.
+ Write fails with EINVAL if an invalid protocol combination or
+ unknown protocol name is used, or if wakeup is not supported by
+ the hardware.
+
+What: /sys/class/rc/rcN/wakeup_filter
+Date: Jan 2014
+KernelVersion: 3.15
+Contact: Mauro Carvalho Chehab <m.chehab@samsung.com>
+Description:
+ Sets the scancode wakeup filter expected value.
+ Use in combination with /sys/class/rc/rcN/wakeup_filter_mask to
+ set the expected value of the bits set in the wakeup filter mask
+ to trigger a system wake event.
+ If the hardware supports it and wakeup_filter_mask is not 0 then
+ scancodes which match the filter will wake the system from e.g.
+ suspend to RAM or power off.
+ Otherwise the write will fail with an error.
+ This value may be reset to 0 if the wakeup protocol is altered.
+
+What: /sys/class/rc/rcN/wakeup_filter_mask
+Date: Jan 2014
+KernelVersion: 3.15
+Contact: Mauro Carvalho Chehab <m.chehab@samsung.com>
+Description:
+ Sets the scancode wakeup filter mask of bits to compare.
+ Use in combination with /sys/class/rc/rcN/wakeup_filter to set
+ the bits of the scancode which should be compared against the
+ expected value to trigger a system wake event.
+ If the hardware supports it and wakeup_filter_mask is not 0 then
+ scancodes which match the filter will wake the system from e.g.
+ suspend to RAM or power off.
+ Otherwise the write will fail with an error.
+ This value may be reset to 0 if the wakeup protocol is altered.
diff --git a/Documentation/ABI/testing/sysfs-class-scsi_host b/Documentation/ABI/testing/sysfs-class-scsi_host
index 29a4f892e433..0eb255e7db12 100644
--- a/Documentation/ABI/testing/sysfs-class-scsi_host
+++ b/Documentation/ABI/testing/sysfs-class-scsi_host
@@ -11,3 +11,19 @@ Description:
guaranteed. The 'isci_id' attribute unambiguously identifies
the controller index: '0' for the first controller,
'1' for the second.
+
+What: /sys/class/scsi_host/hostX/acciopath_status
+Date: November 2013
+Contact: Stephen M. Cameron <scameron@beardog.cce.hp.com>
+Description: This file contains the current status of the "SSD Smart Path"
+ feature of HP Smart Array RAID controllers using the hpsa
+ driver. SSD Smart Path, when enabled permits the driver to
+ send i/o requests directly to physical devices that are part
+ of a logical drive, bypassing the controllers firmware RAID
+ stack for a performance advantage when possible. A value of
+ '1' indicates the feature is enabled, and the controller may
+ use the direct i/o path to physical devices. A value of zero
+ means the feature is disabled and the controller may not use
+ the direct i/o path to physical devices. This setting is
+ controller wide, affecting all configured logical drives on the
+ controller. This file is readable and writable.
diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power
index efe449bdf811..7dbf96b724ed 100644
--- a/Documentation/ABI/testing/sysfs-devices-power
+++ b/Documentation/ABI/testing/sysfs-devices-power
@@ -187,7 +187,7 @@ Description:
Not all drivers support this attribute. If it isn't supported,
attempts to read or write it will yield I/O errors.
-What: /sys/devices/.../power/pm_qos_latency_us
+What: /sys/devices/.../power/pm_qos_resume_latency_us
Date: March 2012
Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
Description:
@@ -205,6 +205,31 @@ Description:
This attribute has no effect on system-wide suspend/resume and
hibernation.
+What: /sys/devices/.../power/pm_qos_latency_tolerance_us
+Date: January 2014
+Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
+Description:
+ The /sys/devices/.../power/pm_qos_latency_tolerance_us attribute
+ contains the PM QoS active state latency tolerance limit for the
+ given device in microseconds. That is the maximum memory access
+ latency the device can suffer without any visible adverse
+ effects on user space functionality. If that value is the
+ string "any", the latency does not matter to user space at all,
+ but hardware should not be allowed to set the latency tolerance
+ for the device automatically.
+
+ Reading "auto" from this file means that the maximum memory
+ access latency for the device may be determined automatically
+ by the hardware as needed. Writing "auto" to it allows the
+ hardware to be switched to this mode if there are no other
+ latency tolerance requirements from the kernel side.
+
+ This attribute is only present if the feature controlled by it
+ is supported by the hardware.
+
+ This attribute has no effect on runtime suspend and resume of
+ devices and on system-wide suspend/resume and hibernation.
+
What: /sys/devices/.../power/pm_qos_no_power_off
Date: September 2012
Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
diff --git a/Documentation/ABI/testing/sysfs-firmware-ofw b/Documentation/ABI/testing/sysfs-firmware-ofw
new file mode 100644
index 000000000000..f562b188e71d
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-firmware-ofw
@@ -0,0 +1,28 @@
+What: /sys/firmware/devicetree/*
+Date: November 2013
+Contact: Grant Likely <grant.likely@linaro.org>
+Description:
+ When using OpenFirmware or a Flattened Device Tree to enumerate
+ hardware, the device tree structure will be exposed in this
+ directory.
+
+ It is possible for multiple device-tree directories to exist.
+ Some device drivers use a separate detached device tree which
+ have no attachment to the system tree and will appear in a
+ different subdirectory under /sys/firmware/devicetree.
+
+ Userspace must not use the /sys/firmware/devicetree/base
+ path directly, but instead should follow /proc/device-tree
+ symlink. It is possible that the absolute path will change
+ in the future, but the symlink is the stable ABI.
+
+ The /proc/device-tree symlink replaces the devicetree /proc
+ filesystem support, and has largely the same semantics and
+ should be compatible with existing userspace.
+
+ The contents of /sys/firmware/devicetree/ is a
+ hierarchy of directories, one per device tree node. The
+ directory name is the resolved path component name (node
+ name plus address). Properties are represented as files
+ in the directory. The contents of each file is the exact
+ binary data from the device tree.
diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power
index 205a73878441..64c9276e9421 100644
--- a/Documentation/ABI/testing/sysfs-power
+++ b/Documentation/ABI/testing/sysfs-power
@@ -12,8 +12,9 @@ Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
Description:
The /sys/power/state file controls the system power state.
Reading from this file returns what states are supported,
- which is hard-coded to 'standby' (Power-On Suspend), 'mem'
- (Suspend-to-RAM), and 'disk' (Suspend-to-Disk).
+ which is hard-coded to 'freeze' (Low-Power Idle), 'standby'
+ (Power-On Suspend), 'mem' (Suspend-to-RAM), and 'disk'
+ (Suspend-to-Disk).
Writing to this file one of these strings causes the system to
transition into that state. Please see the file
diff --git a/Documentation/ABI/testing/sysfs-ptp b/Documentation/ABI/testing/sysfs-ptp
index 05aeedf17794..44806a678f12 100644
--- a/Documentation/ABI/testing/sysfs-ptp
+++ b/Documentation/ABI/testing/sysfs-ptp
@@ -54,6 +54,26 @@ Description:
This file contains the number of programmable periodic
output channels offered by the PTP hardware clock.
+What: /sys/class/ptp/ptpN/n_pins
+Date: March 2014
+Contact: Richard Cochran <richardcochran@gmail.com>
+Description:
+ This file contains the number of programmable pins
+ offered by the PTP hardware clock.
+
+What: /sys/class/ptp/ptpN/pins
+Date: March 2014
+Contact: Richard Cochran <richardcochran@gmail.com>
+Description:
+ This directory contains one file for each programmable
+ pin offered by the PTP hardware clock. The file name
+ is the hardware dependent pin name. Reading from this
+ file produces two numbers, the assigned function (see
+ the PTP_PF_ enumeration values in linux/ptp_clock.h)
+ and the channel number. The function and channel
+ assignment may be changed by two writing numbers into
+ the file.
+
What: /sys/class/ptp/ptpN/pps_avaiable
Date: September 2010
Contact: Richard Cochran <richardcochran@gmail.com>
diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl
index 46ad6faee9ab..044b76436e83 100644
--- a/Documentation/DocBook/80211.tmpl
+++ b/Documentation/DocBook/80211.tmpl
@@ -98,6 +98,8 @@
!Finclude/net/cfg80211.h priv_to_wiphy
!Finclude/net/cfg80211.h set_wiphy_dev
!Finclude/net/cfg80211.h wdev_priv
+!Finclude/net/cfg80211.h ieee80211_iface_limit
+!Finclude/net/cfg80211.h ieee80211_iface_combination
</chapter>
<chapter>
<title>Actions and configuration</title>
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 0f9c6ff41aac..8d96ebf524e9 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -14,7 +14,7 @@ DOCBOOKS := z8530book.xml device-drivers.xml \
genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
80211.xml debugobjects.xml sh.xml regulator.xml \
alsa-driver-api.xml writing-an-alsa-driver.xml \
- tracepoint.xml drm.xml media_api.xml
+ tracepoint.xml drm.xml media_api.xml w1.xml
include $(srctree)/Documentation/DocBook/media/Makefile
diff --git a/Documentation/DocBook/media/dvb/demux.xml b/Documentation/DocBook/media/dvb/demux.xml
index 86de89cfbd67..c8683d66f059 100644
--- a/Documentation/DocBook/media/dvb/demux.xml
+++ b/Documentation/DocBook/media/dvb/demux.xml
@@ -1042,7 +1042,14 @@ role="subsection"><title>DMX_ADD_PID</title>
</para>
<informaltable><tgroup cols="1"><tbody><row><entry
align="char">
-<para>This ioctl is undocumented. Documentation is welcome.</para>
+<para>This ioctl call allows to add multiple PIDs to a transport stream filter
+previously set up with DMX_SET_PES_FILTER and output equal to DMX_OUT_TSDEMUX_TAP.
+</para></entry></row><row><entry align="char"><para>
+It is used by readers of /dev/dvb/adapterX/demuxY.
+</para></entry></row><row><entry align="char"><para>
+It may be called at any time, i.e. before or after the first filter on the
+shared file descriptor was started. It makes it possible to record multiple
+services without the need to de-multiplex or re-multiplex TS packets.</para>
</entry>
</row></tbody></tgroup></informaltable>
<para>SYNOPSIS
@@ -1075,7 +1082,7 @@ role="subsection"><title>DMX_ADD_PID</title>
</para>
</entry><entry
align="char">
-<para>Undocumented.</para>
+<para>PID number to be filtered.</para>
</entry>
</row></tbody></tgroup></informaltable>
&return-value-dvb;
@@ -1087,7 +1094,15 @@ role="subsection"><title>DMX_REMOVE_PID</title>
</para>
<informaltable><tgroup cols="1"><tbody><row><entry
align="char">
-<para>This ioctl is undocumented. Documentation is welcome.</para>
+<para>This ioctl call allows to remove a PID when multiple PIDs are set on a
+transport stream filter, e. g. a filter previously set up with output equal to
+DMX_OUT_TSDEMUX_TAP, created via either DMX_SET_PES_FILTER or DMX_ADD_PID.
+</para></entry></row><row><entry align="char"><para>
+It is used by readers of /dev/dvb/adapterX/demuxY.
+</para></entry></row><row><entry align="char"><para>
+It may be called at any time, i.e. before or after the first filter on the
+shared file descriptor was started. It makes it possible to record multiple
+services without the need to de-multiplex or re-multiplex TS packets.</para>
</entry>
</row></tbody></tgroup></informaltable>
<para>SYNOPSIS
@@ -1120,7 +1135,7 @@ role="subsection"><title>DMX_REMOVE_PID</title>
</para>
</entry><entry
align="char">
-<para>Undocumented.</para>
+<para>PID of the PES filter to be removed.</para>
</entry>
</row></tbody></tgroup></informaltable>
&return-value-dvb;
diff --git a/Documentation/DocBook/media/dvb/dvbapi.xml b/Documentation/DocBook/media/dvb/dvbapi.xml
index 0197bcc7842d..4c15396c67e5 100644
--- a/Documentation/DocBook/media/dvb/dvbapi.xml
+++ b/Documentation/DocBook/media/dvb/dvbapi.xml
@@ -18,7 +18,7 @@
<firstname>Mauro</firstname>
<othername role="mi">Carvalho</othername>
<surname>Chehab</surname>
-<affiliation><address><email>mchehab@redhat.com</email></address></affiliation>
+<affiliation><address><email>m.chehab@samsung.com</email></address></affiliation>
<contrib>Ported document to Docbook XML.</contrib>
</author>
</authorgroup>
@@ -28,7 +28,7 @@
<holder>Convergence GmbH</holder>
</copyright>
<copyright>
- <year>2009-2012</year>
+ <year>2009-2014</year>
<holder>Mauro Carvalho Chehab</holder>
</copyright>
diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml
index a9b15e34c5b2..24c22cabc668 100644
--- a/Documentation/DocBook/media/dvb/dvbproperty.xml
+++ b/Documentation/DocBook/media/dvb/dvbproperty.xml
@@ -196,7 +196,7 @@ get/set up to 64 properties. The actual meaning of each property is described on
<para>1)For satellital delivery systems, it is measured in kHz.
For the other ones, it is measured in Hz.</para>
<para>2)For ISDB-T, the channels are usually transmitted with an offset of 143kHz.
- E.g. a valid frequncy could be 474143 kHz. The stepping is bound to the bandwidth of
+ E.g. a valid frequency could be 474143 kHz. The stepping is bound to the bandwidth of
the channel which is 6MHz.</para>
<para>3)As in ISDB-Tsb the channel consists of only one or three segments the
diff --git a/Documentation/DocBook/media/dvb/frontend.xml b/Documentation/DocBook/media/dvb/frontend.xml
index 0d6e81bd9ed2..8a6a6ff27af5 100644
--- a/Documentation/DocBook/media/dvb/frontend.xml
+++ b/Documentation/DocBook/media/dvb/frontend.xml
@@ -744,7 +744,7 @@ typedef enum fe_hierarchy {
</para>
<informaltable><tgroup cols="1"><tbody><row><entry
align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_READ_SNR">FE_READ_SNR</link>, int16_t
+<para>int ioctl(int fd, int request = <link linkend="FE_READ_SNR">FE_READ_SNR</link>, uint16_t
&#x22C6;snr);</para>
</entry>
</row></tbody></tgroup></informaltable>
@@ -766,7 +766,7 @@ typedef enum fe_hierarchy {
</entry>
</row><row><entry
align="char">
-<para>int16_t *snr</para>
+<para>uint16_t *snr</para>
</entry><entry
align="char">
<para>The signal-to-noise ratio is stored into *snr.</para>
@@ -791,7 +791,7 @@ typedef enum fe_hierarchy {
<informaltable><tgroup cols="1"><tbody><row><entry
align="char">
<para>int ioctl( int fd, int request =
- <link linkend="FE_READ_SIGNAL_STRENGTH">FE_READ_SIGNAL_STRENGTH</link>, int16_t &#x22C6;strength);</para>
+ <link linkend="FE_READ_SIGNAL_STRENGTH">FE_READ_SIGNAL_STRENGTH</link>, uint16_t &#x22C6;strength);</para>
</entry>
</row></tbody></tgroup></informaltable>
@@ -814,7 +814,7 @@ typedef enum fe_hierarchy {
</entry>
</row><row><entry
align="char">
-<para>int16_t *strength</para>
+<para>uint16_t *strength</para>
</entry><entry
align="char">
<para>The signal strength value is stored into *strength.</para>
diff --git a/Documentation/DocBook/media/v4l/common.xml b/Documentation/DocBook/media/v4l/common.xml
index 1ddf354aa997..71f6bf9e735e 100644
--- a/Documentation/DocBook/media/v4l/common.xml
+++ b/Documentation/DocBook/media/v4l/common.xml
@@ -38,70 +38,41 @@ the basic concepts applicable to all devices.</para>
<para>V4L2 drivers are implemented as kernel modules, loaded
manually by the system administrator or automatically when a device is
-first opened. The driver modules plug into the "videodev" kernel
+first discovered. The driver modules plug into the "videodev" kernel
module. It provides helper functions and a common application
interface specified in this document.</para>
<para>Each driver thus loaded registers one or more device nodes
-with major number 81 and a minor number between 0 and 255. Assigning
-minor numbers to V4L2 devices is entirely up to the system administrator,
-this is primarily intended to solve conflicts between devices.<footnote>
- <para>Access permissions are associated with character
-device special files, hence we must ensure device numbers cannot
-change with the module load order. To this end minor numbers are no
-longer automatically assigned by the "videodev" module as in V4L but
-requested by the driver. The defaults will suffice for most people
-unless two drivers compete for the same minor numbers.</para>
- </footnote> The module options to select minor numbers are named
-after the device special file with a "_nr" suffix. For example "video_nr"
-for <filename>/dev/video</filename> video capture devices. The number is
-an offset to the base minor number associated with the device type.
-<footnote>
- <para>In earlier versions of the V4L2 API the module options
-where named after the device special file with a "unit_" prefix, expressing
-the minor number itself, not an offset. Rationale for this change is unknown.
-Lastly the naming and semantics are just a convention among driver writers,
-the point to note is that minor numbers are not supposed to be hardcoded
-into drivers.</para>
- </footnote> When the driver supports multiple devices of the same
-type more than one minor number can be assigned, separated by commas:
-<informalexample>
+with major number 81 and a minor number between 0 and 255. Minor numbers
+are allocated dynamically unless the kernel is compiled with the kernel
+option CONFIG_VIDEO_FIXED_MINOR_RANGES. In that case minor numbers are
+allocated in ranges depending on the device node type (video, radio, etc.).</para>
+
+ <para>Many drivers support "video_nr", "radio_nr" or "vbi_nr"
+module options to select specific video/radio/vbi node numbers. This allows
+the user to request that the device node is named e.g. /dev/video5 instead
+of leaving it to chance. When the driver supports multiple devices of the same
+type more than one device node number can be assigned, separated by commas:
+ <informalexample>
<screen>
-&gt; insmod mydriver.o video_nr=0,1 radio_nr=0,1</screen>
+&gt; modprobe mydriver video_nr=0,1 radio_nr=0,1</screen>
</informalexample></para>
<para>In <filename>/etc/modules.conf</filename> this may be
written as: <informalexample>
<screen>
-alias char-major-81-0 mydriver
-alias char-major-81-1 mydriver
-alias char-major-81-64 mydriver <co id="alias" />
-options mydriver video_nr=0,1 radio_nr=0,1 <co id="options" />
+options mydriver video_nr=0,1 radio_nr=0,1
</screen>
- <calloutlist>
- <callout arearefs="alias">
- <para>When an application attempts to open a device
-special file with major number 81 and minor number 0, 1, or 64, load
-"mydriver" (and the "videodev" module it depends upon).</para>
- </callout>
- <callout arearefs="options">
- <para>Register the first two video capture devices with
-minor number 0 and 1 (base number is 0), the first two radio device
-with minor number 64 and 65 (base 64).</para>
- </callout>
- </calloutlist>
- </informalexample> When no minor number is given as module
-option the driver supplies a default. <xref linkend="devices" />
-recommends the base minor numbers to be used for the various device
-types. Obviously minor numbers must be unique. When the number is
-already in use the <emphasis>offending device</emphasis> will not be
-registered. <!-- Blessed by Linus Torvalds on
-linux-kernel@vger.kernel.org, 2002-11-20. --></para>
-
- <para>By convention system administrators create various
-character device special files with these major and minor numbers in
-the <filename>/dev</filename> directory. The names recommended for the
-different V4L2 device types are listed in <xref linkend="devices" />.
+ </informalexample> When no device node number is given as module
+option the driver supplies a default.</para>
+
+ <para>Normally udev will create the device nodes in /dev automatically
+for you. If udev is not installed, then you need to enable the
+CONFIG_VIDEO_FIXED_MINOR_RANGES kernel option in order to be able to correctly
+relate a minor number to a device node number. I.e., you need to be certain
+that minor number 5 maps to device node name video5. With this kernel option
+different device types have different minor number ranges. These ranges are
+listed in <xref linkend="devices" />.
</para>
<para>The creation of character special files (with
@@ -110,85 +81,66 @@ devices cannot be opened by major and minor number. That means
applications cannot <emphasis>reliable</emphasis> scan for loaded or
installed drivers. The user must enter a device name, or the
application can try the conventional device names.</para>
-
- <para>Under the device filesystem (devfs) the minor number
-options are ignored. V4L2 drivers (or by proxy the "videodev" module)
-automatically create the required device files in the
-<filename>/dev/v4l</filename> directory using the conventional device
-names above.</para>
</section>
<section id="related">
<title>Related Devices</title>
- <para>Devices can support several related functions. For example
-video capturing, video overlay and VBI capturing are related because
-these functions share, amongst other, the same video input and tuner
-frequency. V4L and earlier versions of V4L2 used the same device name
-and minor number for video capturing and overlay, but different ones
-for VBI. Experience showed this approach has several problems<footnote>
- <para>Given a device file name one cannot reliable find
-related devices. For once names are arbitrary and in a system with
-multiple devices, where only some support VBI capturing, a
-<filename>/dev/video2</filename> is not necessarily related to
-<filename>/dev/vbi2</filename>. The V4L
-<constant>VIDIOCGUNIT</constant> ioctl would require a search for a
-device file with a particular major and minor number.</para>
- </footnote>, and to make things worse the V4L videodev module
-used to prohibit multiple opens of a device.</para>
-
- <para>As a remedy the present version of the V4L2 API relaxed the
-concept of device types with specific names and minor numbers. For
-compatibility with old applications drivers must still register different
-minor numbers to assign a default function to the device. But if related
-functions are supported by the driver they must be available under all
-registered minor numbers. The desired function can be selected after
-opening the device as described in <xref linkend="devices" />.</para>
-
- <para>Imagine a driver supporting video capturing, video
-overlay, raw VBI capturing, and FM radio reception. It registers three
-devices with minor number 0, 64 and 224 (this numbering scheme is
-inherited from the V4L API). Regardless if
-<filename>/dev/video</filename> (81, 0) or
-<filename>/dev/vbi</filename> (81, 224) is opened the application can
-select any one of the video capturing, overlay or VBI capturing
-functions. Without programming (e.&nbsp;g. reading from the device
-with <application>dd</application> or <application>cat</application>)
-<filename>/dev/video</filename> captures video images, while
-<filename>/dev/vbi</filename> captures raw VBI data.
-<filename>/dev/radio</filename> (81, 64) is invariable a radio device,
-unrelated to the video functions. Being unrelated does not imply the
-devices can be used at the same time, however. The &func-open;
-function may very well return an &EBUSY;.</para>
+ <para>Devices can support several functions. For example
+video capturing, VBI capturing and radio support.</para>
+
+ <para>The V4L2 API creates different nodes for each of these functions.</para>
+
+ <para>The V4L2 API was designed with the idea that one device node could support
+all functions. However, in practice this never worked: this 'feature'
+was never used by applications and many drivers did not support it and if
+they did it was certainly never tested. In addition, switching a device
+node between different functions only works when using the streaming I/O
+API, not with the read()/write() API.</para>
+
+ <para>Today each device node supports just one function.</para>
<para>Besides video input or output the hardware may also
support audio sampling or playback. If so, these functions are
-implemented as OSS or ALSA PCM devices and eventually OSS or ALSA
-audio mixer. The V4L2 API makes no provisions yet to find these
-related devices. If you have an idea please write to the linux-media
-mailing list: &v4l-ml;.</para>
+implemented as ALSA PCM devices with optional ALSA audio mixer
+devices.</para>
+
+ <para>One problem with all these devices is that the V4L2 API
+makes no provisions to find these related devices. Some really
+complex devices use the Media Controller (see <xref linkend="media_controller" />)
+which can be used for this purpose. But most drivers do not use it,
+and while some code exists that uses sysfs to discover related devices
+(see libmedia_dev in the <ulink url="http://git.linuxtv.org/v4l-utils/">v4l-utils</ulink>
+git repository), there is no library yet that can provide a single API towards
+both Media Controller-based devices and devices that do not use the Media Controller.
+If you want to work on this please write to the linux-media mailing list: &v4l-ml;.</para>
</section>
<section>
<title>Multiple Opens</title>
- <para>In general, V4L2 devices can be opened more than once.
+ <para>V4L2 devices can be opened more than once.<footnote><para>
+There are still some old and obscure drivers that have not been updated to
+allow for multiple opens. This implies that for such drivers &func-open; can
+return an &EBUSY; when the device is already in use.</para></footnote>
When this is supported by the driver, users can for example start a
"panel" application to change controls like brightness or audio
volume, while another application captures video and audio. In other words, panel
-applications are comparable to an OSS or ALSA audio mixer application.
-When a device supports multiple functions like capturing and overlay
-<emphasis>simultaneously</emphasis>, multiple opens allow concurrent
-use of the device by forked processes or specialized applications.</para>
-
- <para>Multiple opens are optional, although drivers should
-permit at least concurrent accesses without data exchange, &ie; panel
-applications. This implies &func-open; can return an &EBUSY; when the
-device is already in use, as well as &func-ioctl; functions initiating
-data exchange (namely the &VIDIOC-S-FMT; ioctl), and the &func-read;
-and &func-write; functions.</para>
-
- <para>Mere opening a V4L2 device does not grant exclusive
+applications are comparable to an ALSA audio mixer application.
+Just opening a V4L2 device should not change the state of the device.<footnote>
+<para>Unfortunately, opening a radio device often switches the state of the
+device to radio mode in many drivers. This behavior should be fixed eventually
+as it violates the V4L2 specification.</para></footnote></para>
+
+ <para>Once an application has allocated the memory buffers needed for
+streaming data (by calling the &VIDIOC-REQBUFS; or &VIDIOC-CREATE-BUFS; ioctls,
+or implicitly by calling the &func-read; or &func-write; functions) that
+application (filehandle) becomes the owner of the device. It is no longer
+allowed to make changes that would affect the buffer sizes (e.g. by calling
+the &VIDIOC-S-FMT; ioctl) and other applications are no longer allowed to allocate
+buffers or start or stop streaming. The &EBUSY; will be returned instead.</para>
+
+ <para>Merely opening a V4L2 device does not grant exclusive
access.<footnote>
<para>Drivers could recognize the
<constant>O_EXCL</constant> open flag. Presently this is not required,
@@ -206,12 +158,7 @@ additional access privileges using the priority mechanism described in
<para>V4L2 drivers should not support multiple applications
reading or writing the same data stream on a device by copying
buffers, time multiplexing or similar means. This is better handled by
-a proxy application in user space. When the driver supports stream
-sharing anyway it must be implemented transparently. The V4L2 API does
-not specify how conflicts are solved. <!-- For example O_EXCL when the
-application does not want to be preempted, PROT_READ mmapped buffers
-which can be mapped twice, what happens when image formats do not
-match etc.--></para>
+a proxy application in user space.</para>
</section>
<section>
@@ -240,15 +187,15 @@ methods</link> supported by the device.</para>
<para>Starting with kernel version 3.1, VIDIOC-QUERYCAP will return the
V4L2 API version used by the driver, with generally matches the Kernel version.
-There's no need of using &VIDIOC-QUERYCAP; to check if an specific ioctl is
-supported, the V4L2 core now returns ENOIOCTLCMD if a driver doesn't provide
+There's no need of using &VIDIOC-QUERYCAP; to check if a specific ioctl is
+supported, the V4L2 core now returns ENOTTY if a driver doesn't provide
support for an ioctl.</para>
<para>Other features can be queried
by calling the respective ioctl, for example &VIDIOC-ENUMINPUT;
to learn about the number, types and names of video connectors on the
device. Although abstraction is a major objective of this API, the
-ioctl also allows driver specific applications to reliable identify
+&VIDIOC-QUERYCAP; ioctl also allows driver specific applications to reliably identify
the driver.</para>
<para>All V4L2 drivers must support
@@ -278,9 +225,7 @@ Applications requiring a different priority will usually call
the &VIDIOC-QUERYCAP; ioctl.</para>
<para>Ioctls changing driver properties, such as &VIDIOC-S-INPUT;,
-return an &EBUSY; after another application obtained higher priority.
-An event mechanism to notify applications about asynchronous property
-changes has been proposed but not added yet.</para>
+return an &EBUSY; after another application obtained higher priority.</para>
</section>
<section id="video">
@@ -288,9 +233,9 @@ changes has been proposed but not added yet.</para>
<para>Video inputs and outputs are physical connectors of a
device. These can be for example RF connectors (antenna/cable), CVBS
-a.k.a. Composite Video, S-Video or RGB connectors. Only video and VBI
-capture devices have inputs, output devices have outputs, at least one
-each. Radio devices have no video inputs or outputs.</para>
+a.k.a. Composite Video, S-Video or RGB connectors. Video and VBI
+capture devices have inputs. Video and VBI output devices have outputs,
+at least one each. Radio devices have no video inputs or outputs.</para>
<para>To learn about the number and attributes of the
available inputs and outputs applications can enumerate them with the
@@ -299,30 +244,13 @@ available inputs and outputs applications can enumerate them with the
ioctl also contains signal status information applicable when the
current video input is queried.</para>
- <para>The &VIDIOC-G-INPUT; and &VIDIOC-G-OUTPUT; ioctl return the
+ <para>The &VIDIOC-G-INPUT; and &VIDIOC-G-OUTPUT; ioctls return the
index of the current video input or output. To select a different
input or output applications call the &VIDIOC-S-INPUT; and
-&VIDIOC-S-OUTPUT; ioctl. Drivers must implement all the input ioctls
+&VIDIOC-S-OUTPUT; ioctls. Drivers must implement all the input ioctls
when the device has one or more inputs, all the output ioctls when the
device has one or more outputs.</para>
- <!--
- <figure id=io-tree>
- <title>Input and output enumeration is the root of most device properties.</title>
- <mediaobject>
- <imageobject>
- <imagedata fileref="links.pdf" format="ps" />
- </imageobject>
- <imageobject>
- <imagedata fileref="links.gif" format="gif" />
- </imageobject>
- <textobject>
- <phrase>Links between various device property structures.</phrase>
- </textobject>
- </mediaobject>
- </figure>
- -->
-
<example>
<title>Information about the current video input</title>
@@ -330,20 +258,20 @@ device has one or more outputs.</para>
&v4l2-input; input;
int index;
-if (-1 == ioctl (fd, &VIDIOC-G-INPUT;, &amp;index)) {
- perror ("VIDIOC_G_INPUT");
- exit (EXIT_FAILURE);
+if (-1 == ioctl(fd, &VIDIOC-G-INPUT;, &amp;index)) {
+ perror("VIDIOC_G_INPUT");
+ exit(EXIT_FAILURE);
}
-memset (&amp;input, 0, sizeof (input));
+memset(&amp;input, 0, sizeof(input));
input.index = index;
-if (-1 == ioctl (fd, &VIDIOC-ENUMINPUT;, &amp;input)) {
- perror ("VIDIOC_ENUMINPUT");
- exit (EXIT_FAILURE);
+if (-1 == ioctl(fd, &VIDIOC-ENUMINPUT;, &amp;input)) {
+ perror("VIDIOC_ENUMINPUT");
+ exit(EXIT_FAILURE);
}
-printf ("Current input: %s\n", input.name);
+printf("Current input: %s\n", input.name);
</programlisting>
</example>
@@ -355,9 +283,9 @@ int index;
index = 0;
-if (-1 == ioctl (fd, &VIDIOC-S-INPUT;, &amp;index)) {
- perror ("VIDIOC_S_INPUT");
- exit (EXIT_FAILURE);
+if (-1 == ioctl(fd, &VIDIOC-S-INPUT;, &amp;index)) {
+ perror("VIDIOC_S_INPUT");
+ exit(EXIT_FAILURE);
}
</programlisting>
</example>
@@ -397,7 +325,7 @@ available inputs and outputs applications can enumerate them with the
also contains signal status information applicable when the current
audio input is queried.</para>
- <para>The &VIDIOC-G-AUDIO; and &VIDIOC-G-AUDOUT; ioctl report
+ <para>The &VIDIOC-G-AUDIO; and &VIDIOC-G-AUDOUT; ioctls report
the current audio input and output, respectively. Note that, unlike
&VIDIOC-G-INPUT; and &VIDIOC-G-OUTPUT; these ioctls return a structure
as <constant>VIDIOC_ENUMAUDIO</constant> and
@@ -408,11 +336,11 @@ applications call the &VIDIOC-S-AUDIO; ioctl. To select an audio
output (which presently has no changeable properties) applications
call the &VIDIOC-S-AUDOUT; ioctl.</para>
- <para>Drivers must implement all input ioctls when the device
-has one or more inputs, all output ioctls when the device has one
-or more outputs. When the device has any audio inputs or outputs the
-driver must set the <constant>V4L2_CAP_AUDIO</constant> flag in the
-&v4l2-capability; returned by the &VIDIOC-QUERYCAP; ioctl.</para>
+ <para>Drivers must implement all audio input ioctls when the device
+has multiple selectable audio inputs, all audio output ioctls when the
+device has multiple selectable audio outputs. When the device has any
+audio inputs or outputs the driver must set the <constant>V4L2_CAP_AUDIO</constant>
+flag in the &v4l2-capability; returned by the &VIDIOC-QUERYCAP; ioctl.</para>
<example>
<title>Information about the current audio input</title>
@@ -420,14 +348,14 @@ driver must set the <constant>V4L2_CAP_AUDIO</constant> flag in the
<programlisting>
&v4l2-audio; audio;
-memset (&amp;audio, 0, sizeof (audio));
+memset(&amp;audio, 0, sizeof(audio));
-if (-1 == ioctl (fd, &VIDIOC-G-AUDIO;, &amp;audio)) {
- perror ("VIDIOC_G_AUDIO");
- exit (EXIT_FAILURE);
+if (-1 == ioctl(fd, &VIDIOC-G-AUDIO;, &amp;audio)) {
+ perror("VIDIOC_G_AUDIO");
+ exit(EXIT_FAILURE);
}
-printf ("Current input: %s\n", audio.name);
+printf("Current input: %s\n", audio.name);
</programlisting>
</example>
@@ -437,13 +365,13 @@ printf ("Current input: %s\n", audio.name);
<programlisting>
&v4l2-audio; audio;
-memset (&amp;audio, 0, sizeof (audio)); /* clear audio.mode, audio.reserved */
+memset(&amp;audio, 0, sizeof(audio)); /* clear audio.mode, audio.reserved */
audio.index = 0;
-if (-1 == ioctl (fd, &VIDIOC-S-AUDIO;, &amp;audio)) {
- perror ("VIDIOC_S_AUDIO");
- exit (EXIT_FAILURE);
+if (-1 == ioctl(fd, &VIDIOC-S-AUDIO;, &amp;audio)) {
+ perror("VIDIOC_S_AUDIO");
+ exit(EXIT_FAILURE);
}
</programlisting>
</example>
@@ -468,7 +396,7 @@ the tuner.</para>
video inputs.</para>
<para>To query and change tuner properties applications use the
-&VIDIOC-G-TUNER; and &VIDIOC-S-TUNER; ioctl, respectively. The
+&VIDIOC-G-TUNER; and &VIDIOC-S-TUNER; ioctls, respectively. The
&v4l2-tuner; returned by <constant>VIDIOC_G_TUNER</constant> also
contains signal status information applicable when the tuner of the
current video or radio input is queried. Note that
@@ -533,7 +461,7 @@ standards or variations of standards. Each video input and output may
support another set of standards. This set is reported by the
<structfield>std</structfield> field of &v4l2-input; and
&v4l2-output; returned by the &VIDIOC-ENUMINPUT; and
-&VIDIOC-ENUMOUTPUT; ioctl, respectively.</para>
+&VIDIOC-ENUMOUTPUT; ioctls, respectively.</para>
<para>V4L2 defines one bit for each analog video standard
currently in use worldwide, and sets aside bits for driver defined
@@ -564,28 +492,10 @@ automatically.</para>
<para>To query and select the standard used by the current video
input or output applications call the &VIDIOC-G-STD; and
&VIDIOC-S-STD; ioctl, respectively. The <emphasis>received</emphasis>
-standard can be sensed with the &VIDIOC-QUERYSTD; ioctl. Note that the parameter of all these ioctls is a pointer to a &v4l2-std-id; type (a standard set), <emphasis>not</emphasis> an index into the standard enumeration.<footnote>
- <para>An alternative to the current scheme is to use pointers
-to indices as arguments of <constant>VIDIOC_G_STD</constant> and
-<constant>VIDIOC_S_STD</constant>, the &v4l2-input; and
-&v4l2-output; <structfield>std</structfield> field would be a set of
-indices like <structfield>audioset</structfield>.</para>
- <para>Indices are consistent with the rest of the API
-and identify the standard unambiguously. In the present scheme of
-things an enumerated standard is looked up by &v4l2-std-id;. Now the
-standards supported by the inputs of a device can overlap. Just
-assume the tuner and composite input in the example above both
-exist on a device. An enumeration of "PAL-B/G", "PAL-H/I" suggests
-a choice which does not exist. We cannot merge or omit sets, because
-applications would be unable to find the standards reported by
-<constant>VIDIOC_G_STD</constant>. That leaves separate enumerations
-for each input. Also selecting a standard by &v4l2-std-id; can be
-ambiguous. Advantage of this method is that applications need not
-identify the standard indirectly, after enumerating.</para><para>So in
-summary, the lookup itself is unavoidable. The difference is only
-whether the lookup is necessary to find an enumerated standard or to
-switch to a standard by &v4l2-std-id;.</para>
- </footnote> Drivers must implement all video standard ioctls
+standard can be sensed with the &VIDIOC-QUERYSTD; ioctl. Note that the
+parameter of all these ioctls is a pointer to a &v4l2-std-id; type
+(a standard set), <emphasis>not</emphasis> an index into the standard
+enumeration. Drivers must implement all video standard ioctls
when the device has one or more video inputs or outputs.</para>
<para>Special rules apply to devices such as USB cameras where the notion of video
@@ -604,17 +514,10 @@ to zero and the <constant>VIDIOC_G_STD</constant>,
<constant>VIDIOC_S_STD</constant>,
<constant>VIDIOC_QUERYSTD</constant> and
<constant>VIDIOC_ENUMSTD</constant> ioctls shall return the
-&ENOTTY;.<footnote>
- <para>See <xref linkend="buffer" /> for a rationale.</para>
+&ENOTTY; or the &EINVAL;.</para>
<para>Applications can make use of the <xref linkend="input-capabilities" /> and
<xref linkend="output-capabilities"/> flags to determine whether the video standard ioctls
-are available for the device.</para>
-
- <para>See <xref linkend="buffer" /> for a rationale. Probably
-even USB cameras follow some well known video standard. It might have
-been better to explicitly indicate elsewhere if a device cannot live
-up to normal expectations, instead of this exception.</para>
- </footnote></para>
+can be used with the given input or output.</para>
<example>
<title>Information about the current video standard</title>
@@ -623,22 +526,22 @@ up to normal expectations, instead of this exception.</para>
&v4l2-std-id; std_id;
&v4l2-standard; standard;
-if (-1 == ioctl (fd, &VIDIOC-G-STD;, &amp;std_id)) {
+if (-1 == ioctl(fd, &VIDIOC-G-STD;, &amp;std_id)) {
/* Note when VIDIOC_ENUMSTD always returns ENOTTY this
is no video device or it falls under the USB exception,
and VIDIOC_G_STD returning ENOTTY is no error. */
- perror ("VIDIOC_G_STD");
- exit (EXIT_FAILURE);
+ perror("VIDIOC_G_STD");
+ exit(EXIT_FAILURE);
}
-memset (&amp;standard, 0, sizeof (standard));
+memset(&amp;standard, 0, sizeof(standard));
standard.index = 0;
-while (0 == ioctl (fd, &VIDIOC-ENUMSTD;, &amp;standard)) {
+while (0 == ioctl(fd, &VIDIOC-ENUMSTD;, &amp;standard)) {
if (standard.id &amp; std_id) {
- printf ("Current video standard: %s\n", standard.name);
- exit (EXIT_SUCCESS);
+ printf("Current video standard: %s\n", standard.name);
+ exit(EXIT_SUCCESS);
}
standard.index++;
@@ -648,8 +551,8 @@ while (0 == ioctl (fd, &VIDIOC-ENUMSTD;, &amp;standard)) {
empty unless this device falls under the USB exception. */
if (errno == EINVAL || standard.index == 0) {
- perror ("VIDIOC_ENUMSTD");
- exit (EXIT_FAILURE);
+ perror("VIDIOC_ENUMSTD");
+ exit(EXIT_FAILURE);
}
</programlisting>
</example>
@@ -662,26 +565,26 @@ input</title>
&v4l2-input; input;
&v4l2-standard; standard;
-memset (&amp;input, 0, sizeof (input));
+memset(&amp;input, 0, sizeof(input));
-if (-1 == ioctl (fd, &VIDIOC-G-INPUT;, &amp;input.index)) {
- perror ("VIDIOC_G_INPUT");
- exit (EXIT_FAILURE);
+if (-1 == ioctl(fd, &VIDIOC-G-INPUT;, &amp;input.index)) {
+ perror("VIDIOC_G_INPUT");
+ exit(EXIT_FAILURE);
}
-if (-1 == ioctl (fd, &VIDIOC-ENUMINPUT;, &amp;input)) {
- perror ("VIDIOC_ENUM_INPUT");
- exit (EXIT_FAILURE);
+if (-1 == ioctl(fd, &VIDIOC-ENUMINPUT;, &amp;input)) {
+ perror("VIDIOC_ENUM_INPUT");
+ exit(EXIT_FAILURE);
}
-printf ("Current input %s supports:\n", input.name);
+printf("Current input %s supports:\n", input.name);
-memset (&amp;standard, 0, sizeof (standard));
+memset(&amp;standard, 0, sizeof(standard));
standard.index = 0;
-while (0 == ioctl (fd, &VIDIOC-ENUMSTD;, &amp;standard)) {
+while (0 == ioctl(fd, &VIDIOC-ENUMSTD;, &amp;standard)) {
if (standard.id &amp; input.std)
- printf ("%s\n", standard.name);
+ printf("%s\n", standard.name);
standard.index++;
}
@@ -690,8 +593,8 @@ while (0 == ioctl (fd, &VIDIOC-ENUMSTD;, &amp;standard)) {
empty unless this device falls under the USB exception. */
if (errno != EINVAL || standard.index == 0) {
- perror ("VIDIOC_ENUMSTD");
- exit (EXIT_FAILURE);
+ perror("VIDIOC_ENUMSTD");
+ exit(EXIT_FAILURE);
}
</programlisting>
</example>
@@ -703,21 +606,21 @@ if (errno != EINVAL || standard.index == 0) {
&v4l2-input; input;
&v4l2-std-id; std_id;
-memset (&amp;input, 0, sizeof (input));
+memset(&amp;input, 0, sizeof(input));
-if (-1 == ioctl (fd, &VIDIOC-G-INPUT;, &amp;input.index)) {
- perror ("VIDIOC_G_INPUT");
- exit (EXIT_FAILURE);
+if (-1 == ioctl(fd, &VIDIOC-G-INPUT;, &amp;input.index)) {
+ perror("VIDIOC_G_INPUT");
+ exit(EXIT_FAILURE);
}
-if (-1 == ioctl (fd, &VIDIOC-ENUMINPUT;, &amp;input)) {
- perror ("VIDIOC_ENUM_INPUT");
- exit (EXIT_FAILURE);
+if (-1 == ioctl(fd, &VIDIOC-ENUMINPUT;, &amp;input)) {
+ perror("VIDIOC_ENUM_INPUT");
+ exit(EXIT_FAILURE);
}
if (0 == (input.std &amp; V4L2_STD_PAL_BG)) {
- fprintf (stderr, "Oops. B/G PAL is not supported.\n");
- exit (EXIT_FAILURE);
+ fprintf(stderr, "Oops. B/G PAL is not supported.\n");
+ exit(EXIT_FAILURE);
}
/* Note this is also supposed to work when only B
@@ -725,9 +628,9 @@ if (0 == (input.std &amp; V4L2_STD_PAL_BG)) {
std_id = V4L2_STD_PAL_BG;
-if (-1 == ioctl (fd, &VIDIOC-S-STD;, &amp;std_id)) {
- perror ("VIDIOC_S_STD");
- exit (EXIT_FAILURE);
+if (-1 == ioctl(fd, &VIDIOC-S-STD;, &amp;std_id)) {
+ perror("VIDIOC_S_STD");
+ exit(EXIT_FAILURE);
}
</programlisting>
</example>
@@ -740,26 +643,25 @@ corresponding video timings. Today there are many more different hardware interf
such as High Definition TV interfaces (HDMI), VGA, DVI connectors etc., that carry
video signals and there is a need to extend the API to select the video timings
for these interfaces. Since it is not possible to extend the &v4l2-std-id; due to
-the limited bits available, a new set of IOCTLs was added to set/get video timings at
-the input and output: </para><itemizedlist>
- <listitem>
- <para>DV Timings: This will allow applications to define detailed
-video timings for the interface. This includes parameters such as width, height,
-polarities, frontporch, backporch etc. The <filename>linux/v4l2-dv-timings.h</filename>
+the limited bits available, a new set of ioctls was added to set/get video timings at
+the input and output.</para>
+
+ <para>These ioctls deal with the detailed digital video timings that define
+each video format. This includes parameters such as the active video width and height,
+signal polarities, frontporches, backporches, sync widths etc. The <filename>linux/v4l2-dv-timings.h</filename>
header can be used to get the timings of the formats in the <xref linkend="cea861" /> and
<xref linkend="vesadmt" /> standards.
</para>
- </listitem>
- </itemizedlist>
- <para>To enumerate and query the attributes of the DV timings supported by a device,
+
+ <para>To enumerate and query the attributes of the DV timings supported by a device
applications use the &VIDIOC-ENUM-DV-TIMINGS; and &VIDIOC-DV-TIMINGS-CAP; ioctls.
- To set DV timings for the device, applications use the
+ To set DV timings for the device applications use the
&VIDIOC-S-DV-TIMINGS; ioctl and to get current DV timings they use the
&VIDIOC-G-DV-TIMINGS; ioctl. To detect the DV timings as seen by the video receiver applications
use the &VIDIOC-QUERY-DV-TIMINGS; ioctl.</para>
<para>Applications can make use of the <xref linkend="input-capabilities" /> and
-<xref linkend="output-capabilities"/> flags to decide what ioctls are available to set the
-video timings for the device.</para>
+<xref linkend="output-capabilities"/> flags to determine whether the digital video ioctls
+can be used with the given input or output.</para>
</section>
&sub-controls;
diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml
index c4cac6dbf9af..eee6f0f4aa43 100644
--- a/Documentation/DocBook/media/v4l/compat.xml
+++ b/Documentation/DocBook/media/v4l/compat.xml
@@ -397,7 +397,7 @@ linkend="control" />.</para>
<para>The <structfield>depth</structfield> (average number of
bits per pixel) of a video image is implied by the selected image
-format. V4L2 does not explicitely provide such information assuming
+format. V4L2 does not explicitly provide such information assuming
applications recognizing the format are aware of the image depth and
others need not know. The <structfield>palette</structfield> field
moved into the &v4l2-pix-format;:<informaltable>
@@ -2535,6 +2535,16 @@ fields changed from _s32 to _u32.
</orderedlist>
</section>
+ <section>
+ <title>V4L2 in Linux 3.15</title>
+ <orderedlist>
+ <listitem>
+ <para>Added Software Defined Radio (SDR) Interface.
+ </para>
+ </listitem>
+ </orderedlist>
+ </section>
+
<section id="other">
<title>Relation of V4L2 to other Linux multimedia APIs</title>
@@ -2651,6 +2661,9 @@ ioctls.</para>
<listitem>
<para>Exporting DMABUF files using &VIDIOC-EXPBUF; ioctl.</para>
</listitem>
+ <listitem>
+ <para>Software Defined Radio (SDR) Interface, <xref linkend="sdr" />.</para>
+ </listitem>
</itemizedlist>
</section>
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index a5a3188e5af7..47198eef75a4 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -2258,6 +2258,26 @@ Applicable to the MPEG1, MPEG2, MPEG4 encoders.</entry>
VBV buffer control.</entry>
</row>
+ <row><entry></entry></row>
+ <row id="v4l2-mpeg-video-hor-search-range">
+ <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE</constant>&nbsp;</entry>
+ <entry>integer</entry>
+ </row>
+ <row><entry spanname="descr">Horizontal search range defines maximum horizontal search area in pixels
+to search and match for the present Macroblock (MB) in the reference picture. This V4L2 control macro is used to set
+horizontal search range for motion estimation module in video encoder.</entry>
+ </row>
+
+ <row><entry></entry></row>
+ <row id="v4l2-mpeg-video-vert-search-range">
+ <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE</constant>&nbsp;</entry>
+ <entry>integer</entry>
+ </row>
+ <row><entry spanname="descr">Vertical search range defines maximum vertical search area in pixels
+to search and match for the present Macroblock (MB) in the reference picture. This V4L2 control macro is used to set
+vertical search range for motion estimation module in video encoder.</entry>
+ </row>
+
<row><entry></entry></row>
<row>
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE</constant>&nbsp;</entry>
@@ -4370,6 +4390,24 @@ interface and may change in the future.</para>
<entry>The flash controller has detected a short or open
circuit condition on the indicator LED.</entry>
</row>
+ <row>
+ <entry><constant>V4L2_FLASH_FAULT_UNDER_VOLTAGE</constant></entry>
+ <entry>Flash controller voltage to the flash LED
+ has been below the minimum limit specific to the flash
+ controller.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_FLASH_FAULT_INPUT_VOLTAGE</constant></entry>
+ <entry>The input voltage of the flash controller is below
+ the limit under which strobing the flash at full current
+ will not be possible.The condition persists until this flag
+ is no longer set.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_FLASH_FAULT_LED_OVER_TEMPERATURE</constant></entry>
+ <entry>The temperature of the LED has exceeded its
+ allowed upper limit.</entry>
+ </row>
</tbody>
</entrytbl>
</row>
@@ -4971,4 +5009,142 @@ defines possible values for de-emphasis. Here they are:</entry>
</table>
</section>
+
+ <section id="rf-tuner-controls">
+ <title>RF Tuner Control Reference</title>
+
+ <para>
+The RF Tuner (RF_TUNER) class includes controls for common features of devices
+having RF tuner.
+ </para>
+ <para>
+In this context, RF tuner is radio receiver circuit between antenna and
+demodulator. It receives radio frequency (RF) from the antenna and converts that
+received signal to lower intermediate frequency (IF) or baseband frequency (BB).
+Tuners that could do baseband output are often called Zero-IF tuners. Older
+tuners were typically simple PLL tuners inside a metal box, whilst newer ones
+are highly integrated chips without a metal box "silicon tuners". These controls
+are mostly applicable for new feature rich silicon tuners, just because older
+tuners does not have much adjustable features.
+ </para>
+ <para>
+For more information about RF tuners see
+<ulink url="http://en.wikipedia.org/wiki/Tuner_%28radio%29">Tuner (radio)</ulink>
+and
+<ulink url="http://en.wikipedia.org/wiki/RF_front_end">RF front end</ulink>
+from Wikipedia.
+ </para>
+
+ <table pgwide="1" frame="none" id="rf-tuner-control-id">
+ <title>RF_TUNER Control IDs</title>
+
+ <tgroup cols="4">
+ <colspec colname="c1" colwidth="1*" />
+ <colspec colname="c2" colwidth="6*" />
+ <colspec colname="c3" colwidth="2*" />
+ <colspec colname="c4" colwidth="6*" />
+ <spanspec namest="c1" nameend="c2" spanname="id" />
+ <spanspec namest="c2" nameend="c4" spanname="descr" />
+ <thead>
+ <row>
+ <entry spanname="id" align="left">ID</entry>
+ <entry align="left">Type</entry>
+ </row>
+ <row rowsep="1">
+ <entry spanname="descr" align="left">Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row><entry></entry></row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_RF_TUNER_CLASS</constant>&nbsp;</entry>
+ <entry>class</entry>
+ </row><row><entry spanname="descr">The RF_TUNER class
+descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
+description of this control class.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_RF_TUNER_BANDWIDTH_AUTO</constant>&nbsp;</entry>
+ <entry>boolean</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Enables/disables tuner radio channel
+bandwidth configuration. In automatic mode bandwidth configuration is performed
+by the driver.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_RF_TUNER_BANDWIDTH</constant>&nbsp;</entry>
+ <entry>integer</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Filter(s) on tuner signal path are used to
+filter signal according to receiving party needs. Driver configures filters to
+fulfill desired bandwidth requirement. Used when V4L2_CID_RF_TUNER_BANDWIDTH_AUTO is not
+set. Unit is in Hz. The range and step are driver-specific.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_RF_TUNER_LNA_GAIN_AUTO</constant>&nbsp;</entry>
+ <entry>boolean</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Enables/disables LNA automatic gain control (AGC)</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO</constant>&nbsp;</entry>
+ <entry>boolean</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Enables/disables mixer automatic gain control (AGC)</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_RF_TUNER_IF_GAIN_AUTO</constant>&nbsp;</entry>
+ <entry>boolean</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Enables/disables IF automatic gain control (AGC)</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_RF_TUNER_LNA_GAIN</constant>&nbsp;</entry>
+ <entry>integer</entry>
+ </row>
+ <row>
+ <entry spanname="descr">LNA (low noise amplifier) gain is first
+gain stage on the RF tuner signal path. It is located very close to tuner
+antenna input. Used when <constant>V4L2_CID_RF_TUNER_LNA_GAIN_AUTO</constant> is not set.
+The range and step are driver-specific.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_RF_TUNER_MIXER_GAIN</constant>&nbsp;</entry>
+ <entry>integer</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Mixer gain is second gain stage on the RF
+tuner signal path. It is located inside mixer block, where RF signal is
+down-converted by the mixer. Used when <constant>V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO</constant>
+is not set. The range and step are driver-specific.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_RF_TUNER_IF_GAIN</constant>&nbsp;</entry>
+ <entry>integer</entry>
+ </row>
+ <row>
+ <entry spanname="descr">IF gain is last gain stage on the RF tuner
+signal path. It is located on output of RF tuner. It controls signal level of
+intermediate frequency output or baseband output. Used when
+<constant>V4L2_CID_RF_TUNER_IF_GAIN_AUTO</constant> is not set. The range and step are
+driver-specific.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_RF_TUNER_PLL_LOCK</constant>&nbsp;</entry>
+ <entry>boolean</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Is synthesizer PLL locked? RF tuner is
+receiving given frequency when that control is set. This is a read-only control.
+</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
</section>
diff --git a/Documentation/DocBook/media/v4l/dev-osd.xml b/Documentation/DocBook/media/v4l/dev-osd.xml
index dd91d6134e8c..54853329140b 100644
--- a/Documentation/DocBook/media/v4l/dev-osd.xml
+++ b/Documentation/DocBook/media/v4l/dev-osd.xml
@@ -56,18 +56,18 @@ framebuffer device.</para>
unsigned int i;
int fb_fd;
-if (-1 == ioctl (fd, VIDIOC_G_FBUF, &amp;fbuf)) {
- perror ("VIDIOC_G_FBUF");
- exit (EXIT_FAILURE);
+if (-1 == ioctl(fd, VIDIOC_G_FBUF, &amp;fbuf)) {
+ perror("VIDIOC_G_FBUF");
+ exit(EXIT_FAILURE);
}
-for (i = 0; i &gt; 30; ++i) {
+for (i = 0; i &lt; 30; i++) {
char dev_name[16];
struct fb_fix_screeninfo si;
- snprintf (dev_name, sizeof (dev_name), "/dev/fb%u", i);
+ snprintf(dev_name, sizeof(dev_name), "/dev/fb%u", i);
- fb_fd = open (dev_name, O_RDWR);
+ fb_fd = open(dev_name, O_RDWR);
if (-1 == fb_fd) {
switch (errno) {
case ENOENT: /* no such file */
@@ -75,19 +75,19 @@ for (i = 0; i &gt; 30; ++i) {
continue;
default:
- perror ("open");
- exit (EXIT_FAILURE);
+ perror("open");
+ exit(EXIT_FAILURE);
}
}
- if (0 == ioctl (fb_fd, FBIOGET_FSCREENINFO, &amp;si)) {
- if (si.smem_start == (unsigned long) fbuf.base)
+ if (0 == ioctl(fb_fd, FBIOGET_FSCREENINFO, &amp;si)) {
+ if (si.smem_start == (unsigned long)fbuf.base)
break;
} else {
/* Apparently not a framebuffer device. */
}
- close (fb_fd);
+ close(fb_fd);
fb_fd = -1;
}
diff --git a/Documentation/DocBook/media/v4l/dev-sdr.xml b/Documentation/DocBook/media/v4l/dev-sdr.xml
new file mode 100644
index 000000000000..dc14804f5436
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/dev-sdr.xml
@@ -0,0 +1,110 @@
+ <title>Software Defined Radio Interface (SDR)</title>
+
+ <note>
+ <title>Experimental</title>
+ <para>This is an <link linkend="experimental"> experimental </link>
+ interface and may change in the future.</para>
+ </note>
+
+ <para>
+SDR is an abbreviation of Software Defined Radio, the radio device
+which uses application software for modulation or demodulation. This interface
+is intended for controlling and data streaming of such devices.
+ </para>
+
+ <para>
+SDR devices are accessed through character device special files named
+<filename>/dev/swradio0</filename> to <filename>/dev/swradio255</filename>
+with major number 81 and dynamically allocated minor numbers 0 to 255.
+ </para>
+
+ <section>
+ <title>Querying Capabilities</title>
+
+ <para>
+Devices supporting the SDR receiver interface set the
+<constant>V4L2_CAP_SDR_CAPTURE</constant> and
+<constant>V4L2_CAP_TUNER</constant> flag in the
+<structfield>capabilities</structfield> field of &v4l2-capability;
+returned by the &VIDIOC-QUERYCAP; ioctl. That flag means the device has an
+Analog to Digital Converter (ADC), which is a mandatory element for the SDR receiver.
+At least one of the read/write, streaming or asynchronous I/O methods must
+be supported.
+ </para>
+ </section>
+
+ <section>
+ <title>Supplemental Functions</title>
+
+ <para>
+SDR devices can support <link linkend="control">controls</link>, and must
+support the <link linkend="tuner">tuner</link> ioctls. Tuner ioctls are used
+for setting the ADC sampling rate (sampling frequency) and the possible RF tuner
+frequency.
+ </para>
+
+ <para>
+The <constant>V4L2_TUNER_ADC</constant> tuner type is used for ADC tuners, and
+the <constant>V4L2_TUNER_RF</constant> tuner type is used for RF tuners. The
+tuner index of the RF tuner (if any) must always follow the ADC tuner index.
+Normally the ADC tuner is #0 and the RF tuner is #1.
+ </para>
+
+ <para>
+The &VIDIOC-S-HW-FREQ-SEEK; ioctl is not supported.
+ </para>
+ </section>
+
+ <section>
+ <title>Data Format Negotiation</title>
+
+ <para>
+The SDR capture device uses the <link linkend="format">format</link> ioctls to
+select the capture format. Both the sampling resolution and the data streaming
+format are bound to that selectable format. In addition to the basic
+<link linkend="format">format</link> ioctls, the &VIDIOC-ENUM-FMT; ioctl
+must be supported as well.
+ </para>
+
+ <para>
+To use the <link linkend="format">format</link> ioctls applications set the
+<structfield>type</structfield> field of a &v4l2-format; to
+<constant>V4L2_BUF_TYPE_SDR_CAPTURE</constant> and use the &v4l2-sdr-format;
+<structfield>sdr</structfield> member of the <structfield>fmt</structfield>
+union as needed per the desired operation.
+Currently only the <structfield>pixelformat</structfield> field of
+&v4l2-sdr-format; is used. The content of that field is the V4L2 fourcc code
+of the data format.
+ </para>
+
+ <table pgwide="1" frame="none" id="v4l2-sdr-format">
+ <title>struct <structname>v4l2_sdr_format</structname></title>
+ <tgroup cols="3">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>pixelformat</structfield></entry>
+ <entry>
+The data format or type of compression, set by the application. This is a
+little endian <link linkend="v4l2-fourcc">four character code</link>.
+V4L2 defines SDR formats in <xref linkend="sdr-formats" />.
+ </entry>
+ </row>
+ <row>
+ <entry>__u8</entry>
+ <entry><structfield>reserved[28]</structfield></entry>
+ <entry>This array is reserved for future extensions.
+Drivers and applications must set it to zero.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+An SDR device may support <link linkend="rw">read/write</link>
+and/or streaming (<link linkend="mmap">memory mapping</link>
+or <link linkend="userp">user pointer</link>) I/O.
+ </para>
+
+ </section>
diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
index 2c4c068dde83..97a69bf6f3eb 100644
--- a/Documentation/DocBook/media/v4l/io.xml
+++ b/Documentation/DocBook/media/v4l/io.xml
@@ -339,8 +339,8 @@ returns immediately with an &EAGAIN; when no buffer is available. The
queues as a side effect. Since there is no notion of doing anything
"now" on a multitasking system, if an application needs to synchronize
with another event it should examine the &v4l2-buffer;
-<structfield>timestamp</structfield> of captured buffers, or set the
-field before enqueuing buffers for output.</para>
+<structfield>timestamp</structfield> of captured or outputted buffers.
+</para>
<para>Drivers implementing memory mapping I/O must
support the <constant>VIDIOC_REQBUFS</constant>,
@@ -457,7 +457,7 @@ queues and unlocks all buffers as a side effect. Since there is no
notion of doing anything "now" on a multitasking system, if an
application needs to synchronize with another event it should examine
the &v4l2-buffer; <structfield>timestamp</structfield> of captured
-buffers, or set the field before enqueuing buffers for output.</para>
+or outputted buffers.</para>
<para>Drivers implementing user pointer I/O must
support the <constant>VIDIOC_REQBUFS</constant>,
@@ -620,8 +620,7 @@ returns immediately with an &EAGAIN; when no buffer is available. The
unlocks all buffers as a side effect. Since there is no notion of doing
anything "now" on a multitasking system, if an application needs to synchronize
with another event it should examine the &v4l2-buffer;
-<structfield>timestamp</structfield> of captured buffers, or set the field
-before enqueuing buffers for output.</para>
+<structfield>timestamp</structfield> of captured or outputted buffers.</para>
<para>Drivers implementing DMABUF importing I/O must support the
<constant>VIDIOC_REQBUFS</constant>, <constant>VIDIOC_QBUF</constant>,
@@ -654,38 +653,19 @@ plane, are stored in struct <structname>v4l2_plane</structname> instead.
In that case, struct <structname>v4l2_buffer</structname> contains an array of
plane structures.</para>
- <para>Nominally timestamps refer to the first data byte transmitted.
-In practice however the wide range of hardware covered by the V4L2 API
-limits timestamp accuracy. Often an interrupt routine will
-sample the system clock shortly after the field or frame was stored
-completely in memory. So applications must expect a constant
-difference up to one field or frame period plus a small (few scan
-lines) random error. The delay and error can be much
-larger due to compression or transmission over an external bus when
-the frames are not properly stamped by the sender. This is frequently
-the case with USB cameras. Here timestamps refer to the instant the
-field or frame was received by the driver, not the capture time. These
-devices identify by not enumerating any video standards, see <xref
-linkend="standard" />.</para>
-
- <para>Similar limitations apply to output timestamps. Typically
-the video hardware locks to a clock controlling the video timing, the
-horizontal and vertical synchronization pulses. At some point in the
-line sequence, possibly the vertical blanking, an interrupt routine
-samples the system clock, compares against the timestamp and programs
-the hardware to repeat the previous field or frame, or to display the
-buffer contents.</para>
-
- <para>Apart of limitations of the video device and natural
-inaccuracies of all clocks, it should be noted system time itself is
-not perfectly stable. It can be affected by power saving cycles,
-warped to insert leap seconds, or even turned back or forth by the
-system administrator affecting long term measurements. <footnote>
- <para>Since no other Linux multimedia
-API supports unadjusted time it would be foolish to introduce here. We
-must use a universally supported clock to synchronize different media,
-hence time of day.</para>
- </footnote></para>
+ <para>Dequeued video buffers come with timestamps. The driver
+ decides at which part of the frame and with which clock the
+ timestamp is taken. Please see flags in the masks
+ <constant>V4L2_BUF_FLAG_TIMESTAMP_MASK</constant> and
+ <constant>V4L2_BUF_FLAG_TSTAMP_SRC_MASK</constant> in <xref
+ linkend="buffer-flags" />. These flags are always valid and constant
+ across all buffers during the whole video stream. Changes in these
+ flags may take place as a side effect of &VIDIOC-S-INPUT; or
+ &VIDIOC-S-OUTPUT; however. The
+ <constant>V4L2_BUF_FLAG_TIMESTAMP_COPY</constant> timestamp type
+ which is used by e.g. on mem-to-mem devices is an exception to the
+ rule: the timestamp source flags are copied from the OUTPUT video
+ buffer to the CAPTURE video buffer.</para>
<table frame="none" pgwide="1" id="v4l2-buffer">
<title>struct <structname>v4l2_buffer</structname></title>
@@ -696,10 +676,11 @@ hence time of day.</para>
<entry>__u32</entry>
<entry><structfield>index</structfield></entry>
<entry></entry>
- <entry>Number of the buffer, set by the application. This
-field is only used for <link linkend="mmap">memory mapping</link> I/O
-and can range from zero to the number of buffers allocated
-with the &VIDIOC-REQBUFS; ioctl (&v4l2-requestbuffers; <structfield>count</structfield>) minus one.</entry>
+ <entry>Number of the buffer, set by the application except
+when calling &VIDIOC-DQBUF;, then it is set by the driver.
+This field can range from zero to the number of buffers allocated
+with the &VIDIOC-REQBUFS; ioctl (&v4l2-requestbuffers; <structfield>count</structfield>),
+plus any buffers allocated with &VIDIOC-CREATE-BUFS; minus one.</entry>
</row>
<row>
<entry>__u32</entry>
@@ -718,7 +699,7 @@ linkend="v4l2-buf-type" /></entry>
buffer. It depends on the negotiated data format and may change with
each buffer for compressed variable size data like JPEG images.
Drivers must set this field when <structfield>type</structfield>
-refers to an input stream, applications when an output stream.</entry>
+refers to an input stream, applications when it refers to an output stream.</entry>
</row>
<row>
<entry>__u32</entry>
@@ -735,7 +716,7 @@ linkend="buffer-flags" />.</entry>
buffer, see <xref linkend="v4l2-field" />. This field is not used when
the buffer contains VBI data. Drivers must set it when
<structfield>type</structfield> refers to an input stream,
-applications when an output stream.</entry>
+applications when it refers to an output stream.</entry>
</row>
<row>
<entry>struct timeval</entry>
@@ -745,15 +726,13 @@ applications when an output stream.</entry>
byte was captured, as returned by the
<function>clock_gettime()</function> function for the relevant
clock id; see <constant>V4L2_BUF_FLAG_TIMESTAMP_*</constant> in
- <xref linkend="buffer-flags" />. For output streams the data
- will not be displayed before this time, secondary to the nominal
- frame rate determined by the current video standard in enqueued
- order. Applications can for example zero this field to display
- frames as soon as possible. The driver stores the time at which
- the first data byte was actually sent out in the
- <structfield>timestamp</structfield> field. This permits
+ <xref linkend="buffer-flags" />. For output streams the driver
+ stores the time at which the last data byte was actually sent out
+ in the <structfield>timestamp</structfield> field. This permits
applications to monitor the drift between the video and system
- clock.</para></entry>
+ clock. For output streams that use <constant>V4L2_BUF_FLAG_TIMESTAMP_COPY</constant>
+ the application has to fill in the timestamp which will be copied
+ by the driver to the capture stream.</para></entry>
</row>
<row>
<entry>&v4l2-timecode;</entry>
@@ -846,7 +825,8 @@ is the file descriptor associated with a DMABUF buffer.</entry>
<entry><structfield>length</structfield></entry>
<entry></entry>
<entry>Size of the buffer (not the payload) in bytes for the
- single-planar API. For the multi-planar API the application sets
+ single-planar API. This is set by the driver based on the calls to
+ &VIDIOC-REQBUFS; and/or &VIDIOC-CREATE-BUFS;. For the multi-planar API the application sets
this to the number of elements in the <structfield>planes</structfield>
array. The driver will fill in the actual number of valid elements in
that array.
@@ -880,13 +860,15 @@ should set this to 0.</entry>
<entry><structfield>bytesused</structfield></entry>
<entry></entry>
<entry>The number of bytes occupied by data in the plane
- (its payload).</entry>
+ (its payload). Drivers must set this field when <structfield>type</structfield>
+ refers to an input stream, applications when it refers to an output stream.</entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>length</structfield></entry>
<entry></entry>
- <entry>Size in bytes of the plane (not its payload).</entry>
+ <entry>Size in bytes of the plane (not its payload). This is set by the driver
+ based on the calls to &VIDIOC-REQBUFS; and/or &VIDIOC-CREATE-BUFS;.</entry>
</row>
<row>
<entry>union</entry>
@@ -925,7 +907,9 @@ should set this to 0.</entry>
<entry>__u32</entry>
<entry><structfield>data_offset</structfield></entry>
<entry></entry>
- <entry>Offset in bytes to video data in the plane, if applicable.
+ <entry>Offset in bytes to video data in the plane.
+ Drivers must set this field when <structfield>type</structfield>
+ refers to an input stream, applications when it refers to an output stream.
</entry>
</row>
<row>
@@ -1005,6 +989,12 @@ should set this to 0.</entry>
<entry>Buffer for video output overlay (OSD), see <xref
linkend="osd" />.</entry>
</row>
+ <row>
+ <entry><constant>V4L2_BUF_TYPE_SDR_CAPTURE</constant></entry>
+ <entry>11</entry>
+ <entry>Buffer for Software Defined Radio (SDR), see <xref
+ linkend="sdr" />.</entry>
+ </row>
</tbody>
</tgroup>
</table>
@@ -1016,7 +1006,7 @@ should set this to 0.</entry>
<tbody valign="top">
<row>
<entry><constant>V4L2_BUF_FLAG_MAPPED</constant></entry>
- <entry>0x0001</entry>
+ <entry>0x00000001</entry>
<entry>The buffer resides in device memory and has been mapped
into the application's address space, see <xref linkend="mmap" /> for details.
Drivers set or clear this flag when the
@@ -1026,7 +1016,7 @@ Drivers set or clear this flag when the
</row>
<row>
<entry><constant>V4L2_BUF_FLAG_QUEUED</constant></entry>
- <entry>0x0002</entry>
+ <entry>0x00000002</entry>
<entry>Internally drivers maintain two buffer queues, an
incoming and outgoing queue. When this flag is set, the buffer is
currently on the incoming queue. It automatically moves to the
@@ -1039,7 +1029,7 @@ cleared.</entry>
</row>
<row>
<entry><constant>V4L2_BUF_FLAG_DONE</constant></entry>
- <entry>0x0004</entry>
+ <entry>0x00000004</entry>
<entry>When this flag is set, the buffer is currently on
the outgoing queue, ready to be dequeued from the driver. Drivers set
or clear this flag when the <constant>VIDIOC_QUERYBUF</constant> ioctl
@@ -1049,11 +1039,11 @@ buffer cannot be on both queues at the same time, the
<constant>V4L2_BUF_FLAG_QUEUED</constant> and
<constant>V4L2_BUF_FLAG_DONE</constant> flag are mutually exclusive.
They can be both cleared however, then the buffer is in "dequeued"
-state, in the application domain to say so.</entry>
+state, in the application domain so to say.</entry>
</row>
<row>
<entry><constant>V4L2_BUF_FLAG_ERROR</constant></entry>
- <entry>0x0040</entry>
+ <entry>0x00000040</entry>
<entry>When this flag is set, the buffer has been dequeued
successfully, although the data might have been corrupted.
This is recoverable, streaming may continue as normal and
@@ -1063,35 +1053,43 @@ state, in the application domain to say so.</entry>
</row>
<row>
<entry><constant>V4L2_BUF_FLAG_KEYFRAME</constant></entry>
- <entry>0x0008</entry>
+ <entry>0x00000008</entry>
<entry>Drivers set or clear this flag when calling the
<constant>VIDIOC_DQBUF</constant> ioctl. It may be set by video
capture devices when the buffer contains a compressed image which is a
-key frame (or field), &ie; can be decompressed on its own.</entry>
+key frame (or field), &ie; can be decompressed on its own. Also know as
+an I-frame. Applications can set this bit when <structfield>type</structfield>
+refers to an output stream.</entry>
</row>
<row>
<entry><constant>V4L2_BUF_FLAG_PFRAME</constant></entry>
- <entry>0x0010</entry>
+ <entry>0x00000010</entry>
<entry>Similar to <constant>V4L2_BUF_FLAG_KEYFRAME</constant>
this flags predicted frames or fields which contain only differences to a
-previous key frame.</entry>
+previous key frame. Applications can set this bit when <structfield>type</structfield>
+refers to an output stream.</entry>
</row>
<row>
<entry><constant>V4L2_BUF_FLAG_BFRAME</constant></entry>
- <entry>0x0020</entry>
- <entry>Similar to <constant>V4L2_BUF_FLAG_PFRAME</constant>
- this is a bidirectional predicted frame or field. [ooc tbd]</entry>
+ <entry>0x00000020</entry>
+ <entry>Similar to <constant>V4L2_BUF_FLAG_KEYFRAME</constant>
+this flags a bi-directional predicted frame or field which contains only
+the differences between the current frame and both the preceding and following
+key frames to specify its content. Applications can set this bit when
+<structfield>type</structfield> refers to an output stream.</entry>
</row>
<row>
<entry><constant>V4L2_BUF_FLAG_TIMECODE</constant></entry>
- <entry>0x0100</entry>
+ <entry>0x00000100</entry>
<entry>The <structfield>timecode</structfield> field is valid.
Drivers set or clear this flag when the <constant>VIDIOC_DQBUF</constant>
-ioctl is called.</entry>
+ioctl is called. Applications can set this bit and the corresponding
+<structfield>timecode</structfield> structure when <structfield>type</structfield>
+refers to an output stream.</entry>
</row>
<row>
<entry><constant>V4L2_BUF_FLAG_PREPARED</constant></entry>
- <entry>0x0400</entry>
+ <entry>0x00000400</entry>
<entry>The buffer has been prepared for I/O and can be queued by the
application. Drivers set or clear this flag when the
<link linkend="vidioc-querybuf">VIDIOC_QUERYBUF</link>, <link
@@ -1101,7 +1099,7 @@ application. Drivers set or clear this flag when the
</row>
<row>
<entry><constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant></entry>
- <entry>0x0800</entry>
+ <entry>0x00000800</entry>
<entry>Caches do not have to be invalidated for this buffer.
Typically applications shall use this flag if the data captured in the buffer
is not going to be touched by the CPU, instead the buffer will, probably, be
@@ -1110,7 +1108,7 @@ passed on to a DMA-capable hardware unit for further processing or output.
</row>
<row>
<entry><constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant></entry>
- <entry>0x1000</entry>
+ <entry>0x00001000</entry>
<entry>Caches do not have to be cleaned for this buffer.
Typically applications shall use this flag for output buffers if the data
in this buffer has not been created by the CPU but by some DMA-capable unit,
@@ -1118,7 +1116,7 @@ in which case caches have not been used.</entry>
</row>
<row>
<entry><constant>V4L2_BUF_FLAG_TIMESTAMP_MASK</constant></entry>
- <entry>0xe000</entry>
+ <entry>0x0000e000</entry>
<entry>Mask for timestamp types below. To test the
timestamp type, mask out bits not belonging to timestamp
type by performing a logical and operation with buffer
@@ -1126,7 +1124,7 @@ in which case caches have not been used.</entry>
</row>
<row>
<entry><constant>V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN</constant></entry>
- <entry>0x0000</entry>
+ <entry>0x00000000</entry>
<entry>Unknown timestamp type. This type is used by
drivers before Linux 3.9 and may be either monotonic (see
below) or realtime (wall clock). Monotonic clock has been
@@ -1139,7 +1137,7 @@ in which case caches have not been used.</entry>
</row>
<row>
<entry><constant>V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC</constant></entry>
- <entry>0x2000</entry>
+ <entry>0x00002000</entry>
<entry>The buffer timestamp has been taken from the
<constant>CLOCK_MONOTONIC</constant> clock. To access the
same clock outside V4L2, use
@@ -1147,10 +1145,42 @@ in which case caches have not been used.</entry>
</row>
<row>
<entry><constant>V4L2_BUF_FLAG_TIMESTAMP_COPY</constant></entry>
- <entry>0x4000</entry>
+ <entry>0x00004000</entry>
<entry>The CAPTURE buffer timestamp has been taken from the
corresponding OUTPUT buffer. This flag applies only to mem2mem devices.</entry>
</row>
+ <row>
+ <entry><constant>V4L2_BUF_FLAG_TSTAMP_SRC_MASK</constant></entry>
+ <entry>0x00070000</entry>
+ <entry>Mask for timestamp sources below. The timestamp source
+ defines the point of time the timestamp is taken in relation to
+ the frame. Logical 'and' operation between the
+ <structfield>flags</structfield> field and
+ <constant>V4L2_BUF_FLAG_TSTAMP_SRC_MASK</constant> produces the
+ value of the timestamp source. Applications must set the timestamp
+ source when <structfield>type</structfield> refers to an output stream
+ and <constant>V4L2_BUF_FLAG_TIMESTAMP_COPY</constant> is set.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_BUF_FLAG_TSTAMP_SRC_EOF</constant></entry>
+ <entry>0x00000000</entry>
+ <entry>End Of Frame. The buffer timestamp has been taken
+ when the last pixel of the frame has been received or the
+ last pixel of the frame has been transmitted. In practice,
+ software generated timestamps will typically be read from
+ the clock a small amount of time after the last pixel has
+ been received or transmitten, depending on the system and
+ other activity in it.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_BUF_FLAG_TSTAMP_SRC_SOE</constant></entry>
+ <entry>0x00010000</entry>
+ <entry>Start Of Exposure. The buffer timestamp has been
+ taken when the exposure of the frame has begun. This is
+ only valid for the
+ <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> buffer
+ type.</entry>
+ </row>
</tbody>
</tgroup>
</table>
@@ -1440,10 +1470,9 @@ or application, depending on data direction, must set &v4l2-buffer;
<constant>V4L2_FIELD_BOTTOM</constant>. Any two successive fields pair
to build a frame. If fields are successive, without any dropped fields
between them (fields can drop individually), can be determined from
-the &v4l2-buffer; <structfield>sequence</structfield> field. Image
-sizes refer to the frame, not fields. This format cannot be selected
-when using the read/write I/O method.<!-- Where it's indistinguishable
-from V4L2_FIELD_SEQ_*. --></entry>
+the &v4l2-buffer; <structfield>sequence</structfield> field. This format
+cannot be selected when using the read/write I/O method since there
+is no way to communicate if a field was a top or bottom field.</entry>
</row>
<row>
<entry><constant>V4L2_FIELD_INTERLACED_TB</constant></entry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv16m.xml b/Documentation/DocBook/media/v4l/pixfmt-nv16m.xml
index c51d5a4cda09..fb2b5e35d665 100644
--- a/Documentation/DocBook/media/v4l/pixfmt-nv16m.xml
+++ b/Documentation/DocBook/media/v4l/pixfmt-nv16m.xml
@@ -12,18 +12,17 @@
<refsect1>
<title>Description</title>
- <para>This is a multi-planar, two-plane version of the YUV 4:2:0 format.
+ <para>This is a multi-planar, two-plane version of the YUV 4:2:2 format.
The three components are separated into two sub-images or planes.
<constant>V4L2_PIX_FMT_NV16M</constant> differs from <constant>V4L2_PIX_FMT_NV16
</constant> in that the two planes are non-contiguous in memory, i.e. the chroma
-plane does not necessarily immediately follows the luma plane.
+plane does not necessarily immediately follow the luma plane.
The luminance data occupies the first plane. The Y plane has one byte per pixel.
In the second plane there is chrominance data with alternating chroma samples.
The CbCr plane is the same width and height, in bytes, as the Y plane.
-Each CbCr pair belongs to four pixels. For example,
+Each CbCr pair belongs to two pixels. For example,
Cb<subscript>0</subscript>/Cr<subscript>0</subscript> belongs to
-Y'<subscript>00</subscript>, Y'<subscript>01</subscript>,
-Y'<subscript>10</subscript>, Y'<subscript>11</subscript>.
+Y'<subscript>00</subscript>, Y'<subscript>01</subscript>.
<constant>V4L2_PIX_FMT_NV61M</constant> is the same as <constant>V4L2_PIX_FMT_NV16M</constant>
except the Cb and Cr bytes are swapped, the CrCb plane starts with a Cr byte.</para>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml
index 166c8d65e4f7..e1c4f8b4c0b3 100644
--- a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml
+++ b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml
@@ -121,14 +121,14 @@ colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para>
<entry><constant>V4L2_PIX_FMT_RGB332</constant></entry>
<entry>'RGB1'</entry>
<entry></entry>
- <entry>b<subscript>1</subscript></entry>
- <entry>b<subscript>0</subscript></entry>
- <entry>g<subscript>2</subscript></entry>
- <entry>g<subscript>1</subscript></entry>
- <entry>g<subscript>0</subscript></entry>
<entry>r<subscript>2</subscript></entry>
<entry>r<subscript>1</subscript></entry>
<entry>r<subscript>0</subscript></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
</row>
<row id="V4L2-PIX-FMT-RGB444">
<entry><constant>V4L2_PIX_FMT_RGB444</constant></entry>
@@ -159,18 +159,18 @@ colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para>
<entry>g<subscript>2</subscript></entry>
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
- <entry>r<subscript>4</subscript></entry>
- <entry>r<subscript>3</subscript></entry>
- <entry>r<subscript>2</subscript></entry>
- <entry>r<subscript>1</subscript></entry>
- <entry>r<subscript>0</subscript></entry>
- <entry></entry>
- <entry>a</entry>
<entry>b<subscript>4</subscript></entry>
<entry>b<subscript>3</subscript></entry>
<entry>b<subscript>2</subscript></entry>
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
+ <entry></entry>
+ <entry>a</entry>
+ <entry>r<subscript>4</subscript></entry>
+ <entry>r<subscript>3</subscript></entry>
+ <entry>r<subscript>2</subscript></entry>
+ <entry>r<subscript>1</subscript></entry>
+ <entry>r<subscript>0</subscript></entry>
<entry>g<subscript>4</subscript></entry>
<entry>g<subscript>3</subscript></entry>
</row>
@@ -181,17 +181,17 @@ colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para>
<entry>g<subscript>2</subscript></entry>
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
- <entry>r<subscript>4</subscript></entry>
- <entry>r<subscript>3</subscript></entry>
- <entry>r<subscript>2</subscript></entry>
- <entry>r<subscript>1</subscript></entry>
- <entry>r<subscript>0</subscript></entry>
- <entry></entry>
<entry>b<subscript>4</subscript></entry>
<entry>b<subscript>3</subscript></entry>
<entry>b<subscript>2</subscript></entry>
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
+ <entry></entry>
+ <entry>r<subscript>4</subscript></entry>
+ <entry>r<subscript>3</subscript></entry>
+ <entry>r<subscript>2</subscript></entry>
+ <entry>r<subscript>1</subscript></entry>
+ <entry>r<subscript>0</subscript></entry>
<entry>g<subscript>5</subscript></entry>
<entry>g<subscript>4</subscript></entry>
<entry>g<subscript>3</subscript></entry>
@@ -201,32 +201,32 @@ colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para>
<entry>'RGBQ'</entry>
<entry></entry>
<entry>a</entry>
- <entry>b<subscript>4</subscript></entry>
- <entry>b<subscript>3</subscript></entry>
- <entry>b<subscript>2</subscript></entry>
- <entry>b<subscript>1</subscript></entry>
- <entry>b<subscript>0</subscript></entry>
- <entry>g<subscript>4</subscript></entry>
- <entry>g<subscript>3</subscript></entry>
- <entry></entry>
- <entry>g<subscript>2</subscript></entry>
- <entry>g<subscript>1</subscript></entry>
- <entry>g<subscript>0</subscript></entry>
<entry>r<subscript>4</subscript></entry>
<entry>r<subscript>3</subscript></entry>
<entry>r<subscript>2</subscript></entry>
<entry>r<subscript>1</subscript></entry>
<entry>r<subscript>0</subscript></entry>
- </row>
- <row id="V4L2-PIX-FMT-RGB565X">
- <entry><constant>V4L2_PIX_FMT_RGB565X</constant></entry>
- <entry>'RGBR'</entry>
+ <entry>g<subscript>4</subscript></entry>
+ <entry>g<subscript>3</subscript></entry>
<entry></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
<entry>b<subscript>4</subscript></entry>
<entry>b<subscript>3</subscript></entry>
<entry>b<subscript>2</subscript></entry>
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-PIX-FMT-RGB565X">
+ <entry><constant>V4L2_PIX_FMT_RGB565X</constant></entry>
+ <entry>'RGBR'</entry>
+ <entry></entry>
+ <entry>r<subscript>4</subscript></entry>
+ <entry>r<subscript>3</subscript></entry>
+ <entry>r<subscript>2</subscript></entry>
+ <entry>r<subscript>1</subscript></entry>
+ <entry>r<subscript>0</subscript></entry>
<entry>g<subscript>5</subscript></entry>
<entry>g<subscript>4</subscript></entry>
<entry>g<subscript>3</subscript></entry>
@@ -234,11 +234,11 @@ colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para>
<entry>g<subscript>2</subscript></entry>
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
- <entry>r<subscript>4</subscript></entry>
- <entry>r<subscript>3</subscript></entry>
- <entry>r<subscript>2</subscript></entry>
- <entry>r<subscript>1</subscript></entry>
- <entry>r<subscript>0</subscript></entry>
+ <entry>b<subscript>4</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
</row>
<row id="V4L2-PIX-FMT-BGR666">
<entry><constant>V4L2_PIX_FMT_BGR666</constant></entry>
@@ -385,6 +385,15 @@ colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para>
<entry><constant>V4L2_PIX_FMT_RGB32</constant></entry>
<entry>'RGB4'</entry>
<entry></entry>
+ <entry>a<subscript>7</subscript></entry>
+ <entry>a<subscript>6</subscript></entry>
+ <entry>a<subscript>5</subscript></entry>
+ <entry>a<subscript>4</subscript></entry>
+ <entry>a<subscript>3</subscript></entry>
+ <entry>a<subscript>2</subscript></entry>
+ <entry>a<subscript>1</subscript></entry>
+ <entry>a<subscript>0</subscript></entry>
+ <entry></entry>
<entry>r<subscript>7</subscript></entry>
<entry>r<subscript>6</subscript></entry>
<entry>r<subscript>5</subscript></entry>
@@ -411,25 +420,16 @@ colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para>
<entry>b<subscript>2</subscript></entry>
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
- <entry></entry>
- <entry>a<subscript>7</subscript></entry>
- <entry>a<subscript>6</subscript></entry>
- <entry>a<subscript>5</subscript></entry>
- <entry>a<subscript>4</subscript></entry>
- <entry>a<subscript>3</subscript></entry>
- <entry>a<subscript>2</subscript></entry>
- <entry>a<subscript>1</subscript></entry>
- <entry>a<subscript>0</subscript></entry>
</row>
</tbody>
</tgroup>
</table>
- <para>Bit 7 is the most significant bit. The value of a = alpha
+ <para>Bit 7 is the most significant bit. The value of the a = alpha
bits is undefined when reading from the driver, ignored when writing
to the driver, except when alpha blending has been negotiated for a
<link linkend="overlay">Video Overlay</link> or <link linkend="osd">
-Video Output Overlay</link> or when alpha component has been configured
+Video Output Overlay</link> or when the alpha component has been configured
for a <link linkend="capture">Video Capture</link> by means of <link
linkend="v4l2-alpha-component"> <constant>V4L2_CID_ALPHA_COMPONENT
</constant> </link> control.</para>
@@ -512,421 +512,6 @@ image</title>
</formalpara>
</example>
- <important>
- <para>Drivers may interpret these formats differently.</para>
- </important>
-
- <para>Some RGB formats above are uncommon and were probably
-defined in error. Drivers may interpret them as in <xref
- linkend="rgb-formats-corrected" />.</para>
-
- <table pgwide="1" frame="none" id="rgb-formats-corrected">
- <title>Packed RGB Image Formats (corrected)</title>
- <tgroup cols="37" align="center">
- <colspec colname="id" align="left" />
- <colspec colname="fourcc" />
- <colspec colname="bit" />
-
- <colspec colnum="4" colname="b07" align="center" />
- <colspec colnum="5" colname="b06" align="center" />
- <colspec colnum="6" colname="b05" align="center" />
- <colspec colnum="7" colname="b04" align="center" />
- <colspec colnum="8" colname="b03" align="center" />
- <colspec colnum="9" colname="b02" align="center" />
- <colspec colnum="10" colname="b01" align="center" />
- <colspec colnum="11" colname="b00" align="center" />
-
- <colspec colnum="13" colname="b17" align="center" />
- <colspec colnum="14" colname="b16" align="center" />
- <colspec colnum="15" colname="b15" align="center" />
- <colspec colnum="16" colname="b14" align="center" />
- <colspec colnum="17" colname="b13" align="center" />
- <colspec colnum="18" colname="b12" align="center" />
- <colspec colnum="19" colname="b11" align="center" />
- <colspec colnum="20" colname="b10" align="center" />
-
- <colspec colnum="22" colname="b27" align="center" />
- <colspec colnum="23" colname="b26" align="center" />
- <colspec colnum="24" colname="b25" align="center" />
- <colspec colnum="25" colname="b24" align="center" />
- <colspec colnum="26" colname="b23" align="center" />
- <colspec colnum="27" colname="b22" align="center" />
- <colspec colnum="28" colname="b21" align="center" />
- <colspec colnum="29" colname="b20" align="center" />
-
- <colspec colnum="31" colname="b37" align="center" />
- <colspec colnum="32" colname="b36" align="center" />
- <colspec colnum="33" colname="b35" align="center" />
- <colspec colnum="34" colname="b34" align="center" />
- <colspec colnum="35" colname="b33" align="center" />
- <colspec colnum="36" colname="b32" align="center" />
- <colspec colnum="37" colname="b31" align="center" />
- <colspec colnum="38" colname="b30" align="center" />
-
- <spanspec namest="b07" nameend="b00" spanname="b0" />
- <spanspec namest="b17" nameend="b10" spanname="b1" />
- <spanspec namest="b27" nameend="b20" spanname="b2" />
- <spanspec namest="b37" nameend="b30" spanname="b3" />
- <thead>
- <row>
- <entry>Identifier</entry>
- <entry>Code</entry>
- <entry>&nbsp;</entry>
- <entry spanname="b0">Byte&nbsp;0 in memory</entry>
- <entry spanname="b1">Byte&nbsp;1</entry>
- <entry spanname="b2">Byte&nbsp;2</entry>
- <entry spanname="b3">Byte&nbsp;3</entry>
- </row>
- <row>
- <entry>&nbsp;</entry>
- <entry>&nbsp;</entry>
- <entry>Bit</entry>
- <entry>7</entry>
- <entry>6</entry>
- <entry>5</entry>
- <entry>4</entry>
- <entry>3</entry>
- <entry>2</entry>
- <entry>1</entry>
- <entry>0</entry>
- <entry>&nbsp;</entry>
- <entry>7</entry>
- <entry>6</entry>
- <entry>5</entry>
- <entry>4</entry>
- <entry>3</entry>
- <entry>2</entry>
- <entry>1</entry>
- <entry>0</entry>
- <entry>&nbsp;</entry>
- <entry>7</entry>
- <entry>6</entry>
- <entry>5</entry>
- <entry>4</entry>
- <entry>3</entry>
- <entry>2</entry>
- <entry>1</entry>
- <entry>0</entry>
- <entry>&nbsp;</entry>
- <entry>7</entry>
- <entry>6</entry>
- <entry>5</entry>
- <entry>4</entry>
- <entry>3</entry>
- <entry>2</entry>
- <entry>1</entry>
- <entry>0</entry>
- </row>
- </thead>
- <tbody valign="top">
- <row><!-- id="V4L2-PIX-FMT-RGB332" -->
- <entry><constant>V4L2_PIX_FMT_RGB332</constant></entry>
- <entry>'RGB1'</entry>
- <entry></entry>
- <entry>r<subscript>2</subscript></entry>
- <entry>r<subscript>1</subscript></entry>
- <entry>r<subscript>0</subscript></entry>
- <entry>g<subscript>2</subscript></entry>
- <entry>g<subscript>1</subscript></entry>
- <entry>g<subscript>0</subscript></entry>
- <entry>b<subscript>1</subscript></entry>
- <entry>b<subscript>0</subscript></entry>
- </row>
- <row><!-- id="V4L2-PIX-FMT-RGB444" -->
- <entry><constant>V4L2_PIX_FMT_RGB444</constant></entry>
- <entry>'R444'</entry>
- <entry></entry>
- <entry>g<subscript>3</subscript></entry>
- <entry>g<subscript>2</subscript></entry>
- <entry>g<subscript>1</subscript></entry>
- <entry>g<subscript>0</subscript></entry>
- <entry>b<subscript>3</subscript></entry>
- <entry>b<subscript>2</subscript></entry>
- <entry>b<subscript>1</subscript></entry>
- <entry>b<subscript>0</subscript></entry>
- <entry></entry>
- <entry>a<subscript>3</subscript></entry>
- <entry>a<subscript>2</subscript></entry>
- <entry>a<subscript>1</subscript></entry>
- <entry>a<subscript>0</subscript></entry>
- <entry>r<subscript>3</subscript></entry>
- <entry>r<subscript>2</subscript></entry>
- <entry>r<subscript>1</subscript></entry>
- <entry>r<subscript>0</subscript></entry>
- </row>
- <row><!-- id="V4L2-PIX-FMT-RGB555" -->
- <entry><constant>V4L2_PIX_FMT_RGB555</constant></entry>
- <entry>'RGBO'</entry>
- <entry></entry>
- <entry>g<subscript>2</subscript></entry>
- <entry>g<subscript>1</subscript></entry>
- <entry>g<subscript>0</subscript></entry>
- <entry>b<subscript>4</subscript></entry>
- <entry>b<subscript>3</subscript></entry>
- <entry>b<subscript>2</subscript></entry>
- <entry>b<subscript>1</subscript></entry>
- <entry>b<subscript>0</subscript></entry>
- <entry></entry>
- <entry>a</entry>
- <entry>r<subscript>4</subscript></entry>
- <entry>r<subscript>3</subscript></entry>
- <entry>r<subscript>2</subscript></entry>
- <entry>r<subscript>1</subscript></entry>
- <entry>r<subscript>0</subscript></entry>
- <entry>g<subscript>4</subscript></entry>
- <entry>g<subscript>3</subscript></entry>
- </row>
- <row><!-- id="V4L2-PIX-FMT-RGB565" -->
- <entry><constant>V4L2_PIX_FMT_RGB565</constant></entry>
- <entry>'RGBP'</entry>
- <entry></entry>
- <entry>g<subscript>2</subscript></entry>
- <entry>g<subscript>1</subscript></entry>
- <entry>g<subscript>0</subscript></entry>
- <entry>b<subscript>4</subscript></entry>
- <entry>b<subscript>3</subscript></entry>
- <entry>b<subscript>2</subscript></entry>
- <entry>b<subscript>1</subscript></entry>
- <entry>b<subscript>0</subscript></entry>
- <entry></entry>
- <entry>r<subscript>4</subscript></entry>
- <entry>r<subscript>3</subscript></entry>
- <entry>r<subscript>2</subscript></entry>
- <entry>r<subscript>1</subscript></entry>
- <entry>r<subscript>0</subscript></entry>
- <entry>g<subscript>5</subscript></entry>
- <entry>g<subscript>4</subscript></entry>
- <entry>g<subscript>3</subscript></entry>
- </row>
- <row><!-- id="V4L2-PIX-FMT-RGB555X" -->
- <entry><constant>V4L2_PIX_FMT_RGB555X</constant></entry>
- <entry>'RGBQ'</entry>
- <entry></entry>
- <entry>a</entry>
- <entry>r<subscript>4</subscript></entry>
- <entry>r<subscript>3</subscript></entry>
- <entry>r<subscript>2</subscript></entry>
- <entry>r<subscript>1</subscript></entry>
- <entry>r<subscript>0</subscript></entry>
- <entry>g<subscript>4</subscript></entry>
- <entry>g<subscript>3</subscript></entry>
- <entry></entry>
- <entry>g<subscript>2</subscript></entry>
- <entry>g<subscript>1</subscript></entry>
- <entry>g<subscript>0</subscript></entry>
- <entry>b<subscript>4</subscript></entry>
- <entry>b<subscript>3</subscript></entry>
- <entry>b<subscript>2</subscript></entry>
- <entry>b<subscript>1</subscript></entry>
- <entry>b<subscript>0</subscript></entry>
- </row>
- <row><!-- id="V4L2-PIX-FMT-RGB565X" -->
- <entry><constant>V4L2_PIX_FMT_RGB565X</constant></entry>
- <entry>'RGBR'</entry>
- <entry></entry>
- <entry>r<subscript>4</subscript></entry>
- <entry>r<subscript>3</subscript></entry>
- <entry>r<subscript>2</subscript></entry>
- <entry>r<subscript>1</subscript></entry>
- <entry>r<subscript>0</subscript></entry>
- <entry>g<subscript>5</subscript></entry>
- <entry>g<subscript>4</subscript></entry>
- <entry>g<subscript>3</subscript></entry>
- <entry></entry>
- <entry>g<subscript>2</subscript></entry>
- <entry>g<subscript>1</subscript></entry>
- <entry>g<subscript>0</subscript></entry>
- <entry>b<subscript>4</subscript></entry>
- <entry>b<subscript>3</subscript></entry>
- <entry>b<subscript>2</subscript></entry>
- <entry>b<subscript>1</subscript></entry>
- <entry>b<subscript>0</subscript></entry>
- </row>
- <row><!-- id="V4L2-PIX-FMT-BGR666" -->
- <entry><constant>V4L2_PIX_FMT_BGR666</constant></entry>
- <entry>'BGRH'</entry>
- <entry></entry>
- <entry>b<subscript>5</subscript></entry>
- <entry>b<subscript>4</subscript></entry>
- <entry>b<subscript>3</subscript></entry>
- <entry>b<subscript>2</subscript></entry>
- <entry>b<subscript>1</subscript></entry>
- <entry>b<subscript>0</subscript></entry>
- <entry>g<subscript>5</subscript></entry>
- <entry>g<subscript>4</subscript></entry>
- <entry></entry>
- <entry>g<subscript>3</subscript></entry>
- <entry>g<subscript>2</subscript></entry>
- <entry>g<subscript>1</subscript></entry>
- <entry>g<subscript>0</subscript></entry>
- <entry>r<subscript>5</subscript></entry>
- <entry>r<subscript>4</subscript></entry>
- <entry>r<subscript>3</subscript></entry>
- <entry>r<subscript>2</subscript></entry>
- <entry></entry>
- <entry>r<subscript>1</subscript></entry>
- <entry>r<subscript>0</subscript></entry>
- <entry></entry>
- <entry></entry>
- <entry></entry>
- <entry></entry>
- <entry></entry>
- <entry></entry>
- <entry></entry>
- <entry></entry>
- <entry></entry>
- <entry></entry>
- <entry></entry>
- <entry></entry>
- <entry></entry>
- <entry></entry>
- </row>
- <row><!-- id="V4L2-PIX-FMT-BGR24" -->
- <entry><constant>V4L2_PIX_FMT_BGR24</constant></entry>
- <entry>'BGR3'</entry>
- <entry></entry>
- <entry>b<subscript>7</subscript></entry>
- <entry>b<subscript>6</subscript></entry>
- <entry>b<subscript>5</subscript></entry>
- <entry>b<subscript>4</subscript></entry>
- <entry>b<subscript>3</subscript></entry>
- <entry>b<subscript>2</subscript></entry>
- <entry>b<subscript>1</subscript></entry>
- <entry>b<subscript>0</subscript></entry>
- <entry></entry>
- <entry>g<subscript>7</subscript></entry>
- <entry>g<subscript>6</subscript></entry>
- <entry>g<subscript>5</subscript></entry>
- <entry>g<subscript>4</subscript></entry>
- <entry>g<subscript>3</subscript></entry>
- <entry>g<subscript>2</subscript></entry>
- <entry>g<subscript>1</subscript></entry>
- <entry>g<subscript>0</subscript></entry>
- <entry></entry>
- <entry>r<subscript>7</subscript></entry>
- <entry>r<subscript>6</subscript></entry>
- <entry>r<subscript>5</subscript></entry>
- <entry>r<subscript>4</subscript></entry>
- <entry>r<subscript>3</subscript></entry>
- <entry>r<subscript>2</subscript></entry>
- <entry>r<subscript>1</subscript></entry>
- <entry>r<subscript>0</subscript></entry>
- </row>
- <row><!-- id="V4L2-PIX-FMT-RGB24" -->
- <entry><constant>V4L2_PIX_FMT_RGB24</constant></entry>
- <entry>'RGB3'</entry>
- <entry></entry>
- <entry>r<subscript>7</subscript></entry>
- <entry>r<subscript>6</subscript></entry>
- <entry>r<subscript>5</subscript></entry>
- <entry>r<subscript>4</subscript></entry>
- <entry>r<subscript>3</subscript></entry>
- <entry>r<subscript>2</subscript></entry>
- <entry>r<subscript>1</subscript></entry>
- <entry>r<subscript>0</subscript></entry>
- <entry></entry>
- <entry>g<subscript>7</subscript></entry>
- <entry>g<subscript>6</subscript></entry>
- <entry>g<subscript>5</subscript></entry>
- <entry>g<subscript>4</subscript></entry>
- <entry>g<subscript>3</subscript></entry>
- <entry>g<subscript>2</subscript></entry>
- <entry>g<subscript>1</subscript></entry>
- <entry>g<subscript>0</subscript></entry>
- <entry></entry>
- <entry>b<subscript>7</subscript></entry>
- <entry>b<subscript>6</subscript></entry>
- <entry>b<subscript>5</subscript></entry>
- <entry>b<subscript>4</subscript></entry>
- <entry>b<subscript>3</subscript></entry>
- <entry>b<subscript>2</subscript></entry>
- <entry>b<subscript>1</subscript></entry>
- <entry>b<subscript>0</subscript></entry>
- </row>
- <row><!-- id="V4L2-PIX-FMT-BGR32" -->
- <entry><constant>V4L2_PIX_FMT_BGR32</constant></entry>
- <entry>'BGR4'</entry>
- <entry></entry>
- <entry>b<subscript>7</subscript></entry>
- <entry>b<subscript>6</subscript></entry>
- <entry>b<subscript>5</subscript></entry>
- <entry>b<subscript>4</subscript></entry>
- <entry>b<subscript>3</subscript></entry>
- <entry>b<subscript>2</subscript></entry>
- <entry>b<subscript>1</subscript></entry>
- <entry>b<subscript>0</subscript></entry>
- <entry></entry>
- <entry>g<subscript>7</subscript></entry>
- <entry>g<subscript>6</subscript></entry>
- <entry>g<subscript>5</subscript></entry>
- <entry>g<subscript>4</subscript></entry>
- <entry>g<subscript>3</subscript></entry>
- <entry>g<subscript>2</subscript></entry>
- <entry>g<subscript>1</subscript></entry>
- <entry>g<subscript>0</subscript></entry>
- <entry></entry>
- <entry>r<subscript>7</subscript></entry>
- <entry>r<subscript>6</subscript></entry>
- <entry>r<subscript>5</subscript></entry>
- <entry>r<subscript>4</subscript></entry>
- <entry>r<subscript>3</subscript></entry>
- <entry>r<subscript>2</subscript></entry>
- <entry>r<subscript>1</subscript></entry>
- <entry>r<subscript>0</subscript></entry>
- <entry></entry>
- <entry>a<subscript>7</subscript></entry>
- <entry>a<subscript>6</subscript></entry>
- <entry>a<subscript>5</subscript></entry>
- <entry>a<subscript>4</subscript></entry>
- <entry>a<subscript>3</subscript></entry>
- <entry>a<subscript>2</subscript></entry>
- <entry>a<subscript>1</subscript></entry>
- <entry>a<subscript>0</subscript></entry>
- </row>
- <row><!-- id="V4L2-PIX-FMT-RGB32" -->
- <entry><constant>V4L2_PIX_FMT_RGB32</constant></entry>
- <entry>'RGB4'</entry>
- <entry></entry>
- <entry>a<subscript>7</subscript></entry>
- <entry>a<subscript>6</subscript></entry>
- <entry>a<subscript>5</subscript></entry>
- <entry>a<subscript>4</subscript></entry>
- <entry>a<subscript>3</subscript></entry>
- <entry>a<subscript>2</subscript></entry>
- <entry>a<subscript>1</subscript></entry>
- <entry>a<subscript>0</subscript></entry>
- <entry></entry>
- <entry>r<subscript>7</subscript></entry>
- <entry>r<subscript>6</subscript></entry>
- <entry>r<subscript>5</subscript></entry>
- <entry>r<subscript>4</subscript></entry>
- <entry>r<subscript>3</subscript></entry>
- <entry>r<subscript>2</subscript></entry>
- <entry>r<subscript>1</subscript></entry>
- <entry>r<subscript>0</subscript></entry>
- <entry></entry>
- <entry>g<subscript>7</subscript></entry>
- <entry>g<subscript>6</subscript></entry>
- <entry>g<subscript>5</subscript></entry>
- <entry>g<subscript>4</subscript></entry>
- <entry>g<subscript>3</subscript></entry>
- <entry>g<subscript>2</subscript></entry>
- <entry>g<subscript>1</subscript></entry>
- <entry>g<subscript>0</subscript></entry>
- <entry></entry>
- <entry>b<subscript>7</subscript></entry>
- <entry>b<subscript>6</subscript></entry>
- <entry>b<subscript>5</subscript></entry>
- <entry>b<subscript>4</subscript></entry>
- <entry>b<subscript>3</subscript></entry>
- <entry>b<subscript>2</subscript></entry>
- <entry>b<subscript>1</subscript></entry>
- <entry>b<subscript>0</subscript></entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
<para>A test utility to determine which RGB formats a driver
actually supports is available from the LinuxTV v4l-dvb repository.
See &v4l-dvb; for access instructions.</para>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-sdr-cu08.xml b/Documentation/DocBook/media/v4l/pixfmt-sdr-cu08.xml
new file mode 100644
index 000000000000..2d80104c178b
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/pixfmt-sdr-cu08.xml
@@ -0,0 +1,44 @@
+<refentry id="V4L2-SDR-FMT-CU08">
+ <refmeta>
+ <refentrytitle>V4L2_SDR_FMT_CU8 ('CU08')</refentrytitle>
+ &manvol;
+ </refmeta>
+ <refnamediv>
+ <refname>
+ <constant>V4L2_SDR_FMT_CU8</constant>
+ </refname>
+ <refpurpose>Complex unsigned 8-bit IQ sample</refpurpose>
+ </refnamediv>
+ <refsect1>
+ <title>Description</title>
+ <para>
+This format contains sequence of complex number samples. Each complex number
+consist two parts, called In-phase and Quadrature (IQ). Both I and Q are
+represented as a 8 bit unsigned number. I value comes first and Q value after
+that.
+ </para>
+ <example>
+ <title><constant>V4L2_SDR_FMT_CU8</constant> 1 sample</title>
+ <formalpara>
+ <title>Byte Order.</title>
+ <para>Each cell is one byte.
+ <informaltable frame="none">
+ <tgroup cols="2" align="center">
+ <colspec align="left" colwidth="2*" />
+ <tbody valign="top">
+ <row>
+ <entry>start&nbsp;+&nbsp;0:</entry>
+ <entry>I'<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry>start&nbsp;+&nbsp;1:</entry>
+ <entry>Q'<subscript>0</subscript></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </para>
+ </formalpara>
+ </example>
+ </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-sdr-cu16le.xml b/Documentation/DocBook/media/v4l/pixfmt-sdr-cu16le.xml
new file mode 100644
index 000000000000..26288ffa9071
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/pixfmt-sdr-cu16le.xml
@@ -0,0 +1,46 @@
+<refentry id="V4L2-SDR-FMT-CU16LE">
+ <refmeta>
+ <refentrytitle>V4L2_SDR_FMT_CU16LE ('CU16')</refentrytitle>
+ &manvol;
+ </refmeta>
+ <refnamediv>
+ <refname>
+ <constant>V4L2_SDR_FMT_CU16LE</constant>
+ </refname>
+ <refpurpose>Complex unsigned 16-bit little endian IQ sample</refpurpose>
+ </refnamediv>
+ <refsect1>
+ <title>Description</title>
+ <para>
+This format contains sequence of complex number samples. Each complex number
+consist two parts, called In-phase and Quadrature (IQ). Both I and Q are
+represented as a 16 bit unsigned little endian number. I value comes first
+and Q value after that.
+ </para>
+ <example>
+ <title><constant>V4L2_SDR_FMT_CU16LE</constant> 1 sample</title>
+ <formalpara>
+ <title>Byte Order.</title>
+ <para>Each cell is one byte.
+ <informaltable frame="none">
+ <tgroup cols="3" align="center">
+ <colspec align="left" colwidth="2*" />
+ <tbody valign="top">
+ <row>
+ <entry>start&nbsp;+&nbsp;0:</entry>
+ <entry>I'<subscript>0[7:0]</subscript></entry>
+ <entry>I'<subscript>0[15:8]</subscript></entry>
+ </row>
+ <row>
+ <entry>start&nbsp;+&nbsp;2:</entry>
+ <entry>Q'<subscript>0[7:0]</subscript></entry>
+ <entry>Q'<subscript>0[15:8]</subscript></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </para>
+ </formalpara>
+ </example>
+ </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml
index 72d72bd67d0a..ea514d6075c5 100644
--- a/Documentation/DocBook/media/v4l/pixfmt.xml
+++ b/Documentation/DocBook/media/v4l/pixfmt.xml
@@ -25,7 +25,12 @@ capturing and output, for overlay frame buffer formats see also
<row>
<entry>__u32</entry>
<entry><structfield>height</structfield></entry>
- <entry>Image height in pixels.</entry>
+ <entry>Image height in pixels. If <structfield>field</structfield> is
+ one of <constant>V4L2_FIELD_TOP</constant>, <constant>V4L2_FIELD_BOTTOM</constant>
+ or <constant>V4L2_FIELD_ALTERNATE</constant> then height refers to the
+ number of lines in the field, otherwise it refers to the number of
+ lines in the frame (which is twice the field height for interlaced
+ formats).</entry>
</row>
<row>
<entry spanname="hspan">Applications set these fields to
@@ -54,7 +59,7 @@ linkend="reserved-formats" /></entry>
can request to capture or output only the top or bottom field, or both
fields interlaced or sequentially stored in one buffer or alternating
in separate buffers. Drivers return the actual field order selected.
-For details see <xref linkend="field-order" />.</entry>
+For more details on fields see <xref linkend="field-order" />.</entry>
</row>
<row>
<entry>__u32</entry>
@@ -81,7 +86,10 @@ plane and is divided by the same factor as the
example the Cb and Cr planes of a YUV 4:2:0 image have half as many
padding bytes following each line as the Y plane. To avoid ambiguities
drivers must return a <structfield>bytesperline</structfield> value
-rounded up to a multiple of the scale factor.</para></entry>
+rounded up to a multiple of the scale factor.</para>
+<para>For compressed formats the <structfield>bytesperline</structfield>
+value makes no sense. Applications and drivers must set this to 0 in
+that case.</para></entry>
</row>
<row>
<entry>__u32</entry>
@@ -97,7 +105,8 @@ hold an image.</entry>
<entry>&v4l2-colorspace;</entry>
<entry><structfield>colorspace</structfield></entry>
<entry>This information supplements the
-<structfield>pixelformat</structfield> and must be set by the driver,
+<structfield>pixelformat</structfield> and must be set by the driver for
+capture streams and by the application for output streams,
see <xref linkend="colorspaces" />.</entry>
</row>
<row>
@@ -135,7 +144,7 @@ set this field to zero.</entry>
<entry>__u16</entry>
<entry><structfield>bytesperline</structfield></entry>
<entry>Distance in bytes between the leftmost pixels in two adjacent
- lines.</entry>
+ lines. See &v4l2-pix-format;.</entry>
</row>
<row>
<entry>__u16</entry>
@@ -154,12 +163,12 @@ set this field to zero.</entry>
<row>
<entry>__u32</entry>
<entry><structfield>width</structfield></entry>
- <entry>Image width in pixels.</entry>
+ <entry>Image width in pixels. See &v4l2-pix-format;.</entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>height</structfield></entry>
- <entry>Image height in pixels.</entry>
+ <entry>Image height in pixels. See &v4l2-pix-format;.</entry>
</row>
<row>
<entry>__u32</entry>
@@ -811,6 +820,17 @@ extended control <constant>V4L2_CID_MPEG_STREAM_TYPE</constant>, see
</table>
</section>
+ <section id="sdr-formats">
+ <title>SDR Formats</title>
+
+ <para>These formats are used for <link linkend="sdr">SDR Capture</link>
+interface only.</para>
+
+ &sub-sdr-cu08;
+ &sub-sdr-cu16le;
+
+ </section>
+
<section id="pixfmt-reserved">
<title>Reserved Format Identifiers</title>
diff --git a/Documentation/DocBook/media/v4l/remote_controllers.xml b/Documentation/DocBook/media/v4l/remote_controllers.xml
index 160e464d44b7..5124a6c4daa8 100644
--- a/Documentation/DocBook/media/v4l/remote_controllers.xml
+++ b/Documentation/DocBook/media/v4l/remote_controllers.xml
@@ -1,10 +1,152 @@
+<partinfo>
+<authorgroup>
+<author>
+<firstname>Mauro</firstname>
+<surname>Chehab</surname>
+<othername role="mi">Carvalho</othername>
+<affiliation><address><email>m.chehab@samsung.com</email></address></affiliation>
+<contrib>Initial version.</contrib>
+</author>
+</authorgroup>
+<copyright>
+ <year>2009-2014</year>
+ <holder>Mauro Carvalho Chehab</holder>
+</copyright>
+
+<revhistory>
+<!-- Put document revisions here, newest first. -->
+<revision>
+<revnumber>3.15</revnumber>
+<date>2014-02-06</date>
+<authorinitials>mcc</authorinitials>
+<revremark>Added the interface description and the RC sysfs class description.</revremark>
+</revision>
+<revision>
+<revnumber>1.0</revnumber>
+<date>2009-09-06</date>
+<authorinitials>mcc</authorinitials>
+<revremark>Initial revision</revremark>
+</revision>
+</revhistory>
+</partinfo>
+
+ <title>Remote Controller API</title>
+ <chapter id="remote_controllers">
+
<title>Remote Controllers</title>
+
<section id="Remote_controllers_Intro">
<title>Introduction</title>
<para>Currently, most analog and digital devices have a Infrared input for remote controllers. Each
manufacturer has their own type of control. It is not rare for the same manufacturer to ship different
types of controls, depending on the device.</para>
+<para>A Remote Controller interface is mapped as a normal evdev/input interface, just like a keyboard or a mouse.
+So, it uses all ioctls already defined for any other input devices.</para>
+<para>However, remove controllers are more flexible than a normal input device, as the IR
+receiver (and/or transmitter) can be used in conjunction with a wide variety of different IR remotes.</para>
+<para>In order to allow flexibility, the Remote Controller subsystem allows controlling the
+RC-specific attributes via <link linkend="remote_controllers_sysfs_nodes">the sysfs class nodes</link>.</para>
+</section>
+
+<section id="remote_controllers_sysfs_nodes">
+<title>Remote Controller's sysfs nodes</title>
+<para>As defined at <constant>Documentation/ABI/testing/sysfs-class-rc</constant>, those are the sysfs nodes that control the Remote Controllers:</para>
+
+<section id="sys_class_rc">
+<title>/sys/class/rc/</title>
+<para>The <constant>/sys/class/rc/</constant> class sub-directory belongs to the Remote Controller
+core and provides a sysfs interface for configuring infrared remote controller receivers.
+</para>
+
+</section>
+<section id="sys_class_rc_rcN">
+<title>/sys/class/rc/rcN/</title>
+<para>A <constant>/sys/class/rc/rcN</constant> directory is created for each remote
+ control receiver device where N is the number of the receiver.</para>
+
+</section>
+<section id="sys_class_rc_rcN_protocols">
+<title>/sys/class/rc/rcN/protocols</title>
+<para>Reading this file returns a list of available protocols, something like:</para>
+<para><constant>rc5 [rc6] nec jvc [sony]</constant></para>
+<para>Enabled protocols are shown in [] brackets.</para>
+<para>Writing "+proto" will add a protocol to the list of enabled protocols.</para>
+<para>Writing "-proto" will remove a protocol from the list of enabled protocols.</para>
+<para>Writing "proto" will enable only "proto".</para>
+<para>Writing "none" will disable all protocols.</para>
+<para>Write fails with EINVAL if an invalid protocol combination or unknown protocol name is used.</para>
+
+</section>
+<section id="sys_class_rc_rcN_filter">
+<title>/sys/class/rc/rcN/filter</title>
+<para>Sets the scancode filter expected value.</para>
+<para>Use in combination with <constant>/sys/class/rc/rcN/filter_mask</constant> to set the
+expected value of the bits set in the filter mask.
+If the hardware supports it then scancodes which do not match
+the filter will be ignored. Otherwise the write will fail with
+an error.</para>
+<para>This value may be reset to 0 if the current protocol is altered.</para>
+
+</section>
+<section id="sys_class_rc_rcN_filter_mask">
+<title>/sys/class/rc/rcN/filter_mask</title>
+<para>Sets the scancode filter mask of bits to compare.
+Use in combination with <constant>/sys/class/rc/rcN/filter</constant> to set the bits
+of the scancode which should be compared against the expected
+value. A value of 0 disables the filter to allow all valid
+scancodes to be processed.</para>
+<para>If the hardware supports it then scancodes which do not match
+the filter will be ignored. Otherwise the write will fail with
+an error.</para>
+<para>This value may be reset to 0 if the current protocol is altered.</para>
+
+</section>
+<section id="sys_class_rc_rcN_wakeup_protocols">
+<title>/sys/class/rc/rcN/wakeup_protocols</title>
+<para>Reading this file returns a list of available protocols to use for the
+wakeup filter, something like:</para>
+<para><constant>rc5 rc6 nec jvc [sony]</constant></para>
+<para>The enabled wakeup protocol is shown in [] brackets.</para>
+<para>Writing "+proto" will add a protocol to the list of enabled wakeup
+protocols.</para>
+<para>Writing "-proto" will remove a protocol from the list of enabled wakeup
+protocols.</para>
+<para>Writing "proto" will use "proto" for wakeup events.</para>
+<para>Writing "none" will disable wakeup.</para>
+<para>Write fails with EINVAL if an invalid protocol combination or unknown
+protocol name is used, or if wakeup is not supported by the hardware.</para>
+
+</section>
+<section id="sys_class_rc_rcN_wakeup_filter">
+<title>/sys/class/rc/rcN/wakeup_filter</title>
+<para>Sets the scancode wakeup filter expected value.
+Use in combination with <constant>/sys/class/rc/rcN/wakeup_filter_mask</constant> to
+set the expected value of the bits set in the wakeup filter mask
+to trigger a system wake event.</para>
+<para>If the hardware supports it and wakeup_filter_mask is not 0 then
+scancodes which match the filter will wake the system from e.g.
+suspend to RAM or power off.
+Otherwise the write will fail with an error.</para>
+<para>This value may be reset to 0 if the wakeup protocol is altered.</para>
+
+</section>
+<section id="sys_class_rc_rcN_wakeup_filter_mask">
+<title>/sys/class/rc/rcN/wakeup_filter_mask</title>
+<para>Sets the scancode wakeup filter mask of bits to compare.
+Use in combination with <constant>/sys/class/rc/rcN/wakeup_filter</constant> to set
+the bits of the scancode which should be compared against the
+expected value to trigger a system wake event.</para>
+<para>If the hardware supports it and wakeup_filter_mask is not 0 then
+scancodes which match the filter will wake the system from e.g.
+suspend to RAM or power off.
+Otherwise the write will fail with an error.</para>
+<para>This value may be reset to 0 if the wakeup protocol is altered.</para>
+</section>
+</section>
+
+<section id="Remote_controllers_tables">
+<title>Remote controller tables</title>
<para>Unfortunately, for several years, there was no effort to create uniform IR keycodes for
different devices. This caused the same IR keyname to be mapped completely differently on
different IR devices. This resulted that the same IR keyname to be mapped completely different on
@@ -175,3 +317,4 @@ keymapping.</para>
</section>
&sub-lirc_device_interface;
+</chapter>
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
index 74b7f27af71a..b445161b912c 100644
--- a/Documentation/DocBook/media/v4l/v4l2.xml
+++ b/Documentation/DocBook/media/v4l/v4l2.xml
@@ -70,7 +70,7 @@ MPEG stream embedded, sliced VBI data format in this specification.
Remote Controller chapter.</contrib>
<affiliation>
<address>
- <email>mchehab@redhat.com</email>
+ <email>m.chehab@samsung.com</email>
</address>
</affiliation>
</author>
@@ -107,6 +107,16 @@ Remote Controller chapter.</contrib>
</address>
</affiliation>
</author>
+ <author>
+ <firstname>Antti</firstname>
+ <surname>Palosaari</surname>
+ <contrib>SDR API.</contrib>
+ <affiliation>
+ <address>
+ <email>crope@iki.fi</email>
+ </address>
+ </affiliation>
+ </author>
</authorgroup>
<copyright>
@@ -125,6 +135,7 @@ Remote Controller chapter.</contrib>
<year>2011</year>
<year>2012</year>
<year>2013</year>
+ <year>2014</year>
<holder>Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin
Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab,
Pawel Osciak</holder>
@@ -141,6 +152,16 @@ structs, ioctls) must be noted in more detail in the history chapter
applications. -->
<revision>
+ <revnumber>3.15</revnumber>
+ <date>2014-02-03</date>
+ <authorinitials>hv, ap</authorinitials>
+ <revremark>Update several sections of "Common API Elements": "Opening and Closing Devices"
+"Querying Capabilities", "Application Priority", "Video Inputs and Outputs", "Audio Inputs and Outputs"
+"Tuners and Modulators", "Video Standards" and "Digital Video (DV) Timings". Added SDR API.
+ </revremark>
+ </revision>
+
+ <revision>
<revnumber>3.14</revnumber>
<date>2013-11-25</date>
<authorinitials>rr</authorinitials>
@@ -537,6 +558,7 @@ and discussions on the V4L mailing list.</revremark>
<section id="ttx"> &sub-dev-teletext; </section>
<section id="radio"> &sub-dev-radio; </section>
<section id="rds"> &sub-dev-rds; </section>
+ <section id="sdr"> &sub-dev-sdr; </section>
<section id="event"> &sub-dev-event; </section>
<section id="subdev"> &sub-dev-subdev; </section>
</chapter>
@@ -585,6 +607,7 @@ and discussions on the V4L mailing list.</revremark>
&sub-g-crop;
&sub-g-ctrl;
&sub-g-dv-timings;
+ &sub-g-edid;
&sub-g-enc-index;
&sub-g-ext-ctrls;
&sub-g-fbuf;
@@ -616,7 +639,6 @@ and discussions on the V4L mailing list.</revremark>
&sub-subdev-enum-frame-size;
&sub-subdev-enum-mbus-code;
&sub-subdev-g-crop;
- &sub-subdev-g-edid;
&sub-subdev-g-fmt;
&sub-subdev-g-frame-interval;
&sub-subdev-g-selection;
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-freq-bands.xml b/Documentation/DocBook/media/v4l/vidioc-enum-freq-bands.xml
index 6541ba0175ed..4e8ea65f7282 100644
--- a/Documentation/DocBook/media/v4l/vidioc-enum-freq-bands.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-enum-freq-bands.xml
@@ -100,7 +100,7 @@ See <xref linkend="v4l2-tuner-type" /></entry>
<entry><structfield>capability</structfield></entry>
<entry spanname="hspan">The tuner/modulator capability flags for
this frequency band, see <xref linkend="tuner-capability" />. The <constant>V4L2_TUNER_CAP_LOW</constant>
-capability must be the same for all frequency bands of the selected tuner/modulator.
+or <constant>V4L2_TUNER_CAP_1HZ</constant> capability must be the same for all frequency bands of the selected tuner/modulator.
So either all bands have that capability set, or none of them have that capability.</entry>
</row>
<row>
@@ -109,7 +109,8 @@ So either all bands have that capability set, or none of them have that capabili
<entry spanname="hspan">The lowest tunable frequency in
units of 62.5 kHz, or if the <structfield>capability</structfield>
flag <constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
-Hz, for this frequency band.</entry>
+Hz, for this frequency band. A 1 Hz unit is used when the <structfield>capability</structfield> flag
+<constant>V4L2_TUNER_CAP_1HZ</constant> is set.</entry>
</row>
<row>
<entry>__u32</entry>
@@ -117,7 +118,8 @@ Hz, for this frequency band.</entry>
<entry spanname="hspan">The highest tunable frequency in
units of 62.5 kHz, or if the <structfield>capability</structfield>
flag <constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
-Hz, for this frequency band.</entry>
+Hz, for this frequency band. A 1 Hz unit is used when the <structfield>capability</structfield> flag
+<constant>V4L2_TUNER_CAP_1HZ</constant> is set.</entry>
</row>
<row>
<entry>__u32</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-edid.xml b/Documentation/DocBook/media/v4l/vidioc-g-edid.xml
index bbd18f0e6ede..ce4563b87131 100644
--- a/Documentation/DocBook/media/v4l/vidioc-subdev-g-edid.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-edid.xml
@@ -1,12 +1,12 @@
-<refentry id="vidioc-subdev-g-edid">
+<refentry id="vidioc-g-edid">
<refmeta>
- <refentrytitle>ioctl VIDIOC_SUBDEV_G_EDID, VIDIOC_SUBDEV_S_EDID</refentrytitle>
+ <refentrytitle>ioctl VIDIOC_G_EDID, VIDIOC_S_EDID</refentrytitle>
&manvol;
</refmeta>
<refnamediv>
- <refname>VIDIOC_SUBDEV_G_EDID</refname>
- <refname>VIDIOC_SUBDEV_S_EDID</refname>
+ <refname>VIDIOC_G_EDID</refname>
+ <refname>VIDIOC_S_EDID</refname>
<refpurpose>Get or set the EDID of a video receiver/transmitter</refpurpose>
</refnamediv>
@@ -16,7 +16,7 @@
<funcdef>int <function>ioctl</function></funcdef>
<paramdef>int <parameter>fd</parameter></paramdef>
<paramdef>int <parameter>request</parameter></paramdef>
- <paramdef>struct v4l2_subdev_edid *<parameter>argp</parameter></paramdef>
+ <paramdef>struct v4l2_edid *<parameter>argp</parameter></paramdef>
</funcprototype>
</funcsynopsis>
<funcsynopsis>
@@ -24,7 +24,7 @@
<funcdef>int <function>ioctl</function></funcdef>
<paramdef>int <parameter>fd</parameter></paramdef>
<paramdef>int <parameter>request</parameter></paramdef>
- <paramdef>const struct v4l2_subdev_edid *<parameter>argp</parameter></paramdef>
+ <paramdef>const struct v4l2_edid *<parameter>argp</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
@@ -42,7 +42,7 @@
<varlistentry>
<term><parameter>request</parameter></term>
<listitem>
- <para>VIDIOC_SUBDEV_G_EDID, VIDIOC_SUBDEV_S_EDID</para>
+ <para>VIDIOC_G_EDID, VIDIOC_S_EDID</para>
</listitem>
</varlistentry>
<varlistentry>
@@ -56,12 +56,20 @@
<refsect1>
<title>Description</title>
- <para>These ioctls can be used to get or set an EDID associated with an input pad
- from a receiver or an output pad of a transmitter subdevice.</para>
+ <para>These ioctls can be used to get or set an EDID associated with an input
+ from a receiver or an output of a transmitter device. They can be
+ used with subdevice nodes (/dev/v4l-subdevX) or with video nodes (/dev/videoX).</para>
+
+ <para>When used with video nodes the <structfield>pad</structfield> field represents the
+ input (for video capture devices) or output (for video output devices) index as
+ is returned by &VIDIOC-ENUMINPUT; and &VIDIOC-ENUMOUTPUT; respectively. When used
+ with subdevice nodes the <structfield>pad</structfield> field represents the
+ input or output pad of the subdevice. If there is no EDID support for the given
+ <structfield>pad</structfield> value, then the &EINVAL; will be returned.</para>
<para>To get the EDID data the application has to fill in the <structfield>pad</structfield>,
<structfield>start_block</structfield>, <structfield>blocks</structfield> and <structfield>edid</structfield>
- fields and call <constant>VIDIOC_SUBDEV_G_EDID</constant>. The current EDID from block
+ fields and call <constant>VIDIOC_G_EDID</constant>. The current EDID from block
<structfield>start_block</structfield> and of size <structfield>blocks</structfield>
will be placed in the memory <structfield>edid</structfield> points to. The <structfield>edid</structfield>
pointer must point to memory at least <structfield>blocks</structfield>&nbsp;*&nbsp;128 bytes
@@ -91,15 +99,17 @@
data in some way. In any case, the end result is the same: the EDID is no longer available.
</para>
- <table pgwide="1" frame="none" id="v4l2-subdev-edid">
- <title>struct <structname>v4l2_subdev_edid</structname></title>
+ <table pgwide="1" frame="none" id="v4l2-edid">
+ <title>struct <structname>v4l2_edid</structname></title>
<tgroup cols="3">
&cs-str;
<tbody valign="top">
<row>
<entry>__u32</entry>
<entry><structfield>pad</structfield></entry>
- <entry>Pad for which to get/set the EDID blocks.</entry>
+ <entry>Pad for which to get/set the EDID blocks. When used with a video device
+ node the pad represents the input or output index as returned by
+ &VIDIOC-ENUMINPUT; and &VIDIOC-ENUMOUTPUT; respectively.</entry>
</row>
<row>
<entry>__u32</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
index b3bb9575b2e0..e9f6735c0823 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
@@ -327,7 +327,12 @@ These controls are described in <xref
These controls are described in <xref
linkend="fm-rx-controls" />.</entry>
</row>
-
+ <row>
+ <entry><constant>V4L2_CTRL_CLASS_RF_TUNER</constant></entry>
+ <entry>0xa20000</entry>
+ <entry>The class containing RF tuner controls.
+These controls are described in <xref linkend="rf-tuner-controls" />.</entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml
index ee8f56e1bac0..4fe19a7a9a31 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml
@@ -172,6 +172,13 @@ capture and output devices.</entry>
</row>
<row>
<entry></entry>
+ <entry>&v4l2-sdr-format;</entry>
+ <entry><structfield>sdr</structfield></entry>
+ <entry>Definition of a data format, see
+<xref linkend="pixfmt" />, used by SDR capture devices.</entry>
+ </row>
+ <row>
+ <entry></entry>
<entry>__u8</entry>
<entry><structfield>raw_data</structfield>[200]</entry>
<entry>Place holder for future extensions.</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml b/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml
index c7a1c462e724..d1034fb61d15 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml
@@ -109,9 +109,10 @@ See <xref linkend="v4l2-tuner-type" /></entry>
<entry>__u32</entry>
<entry><structfield>frequency</structfield></entry>
<entry>Tuning frequency in units of 62.5 kHz, or if the
-&v4l2-tuner; or &v4l2-modulator; <structfield>capabilities</structfield> flag
+&v4l2-tuner; or &v4l2-modulator; <structfield>capability</structfield> flag
<constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
-Hz.</entry>
+Hz. A 1 Hz unit is used when the <structfield>capability</structfield> flag
+<constant>V4L2_TUNER_CAP_1HZ</constant> is set.</entry>
</row>
<row>
<entry>__u32</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml b/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml
index 7f4ac7e41fa8..7068b599a00d 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml
@@ -113,7 +113,8 @@ change for example with the current video standard.</entry>
<entry>The lowest tunable frequency in units of 62.5
KHz, or if the <structfield>capability</structfield> flag
<constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
-Hz.</entry>
+Hz, or if the <structfield>capability</structfield> flag
+<constant>V4L2_TUNER_CAP_1HZ</constant> is set, in units of 1 Hz.</entry>
</row>
<row>
<entry>__u32</entry>
@@ -121,7 +122,8 @@ Hz.</entry>
<entry>The highest tunable frequency in units of 62.5
KHz, or if the <structfield>capability</structfield> flag
<constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
-Hz.</entry>
+Hz, or if the <structfield>capability</structfield> flag
+<constant>V4L2_TUNER_CAP_1HZ</constant> is set, in units of 1 Hz.</entry>
</row>
<row>
<entry>__u32</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
index 6cc82010c736..b0d865933da6 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
@@ -134,7 +134,9 @@ the structure refers to a radio tuner the
<entry spanname="hspan">The lowest tunable frequency in
units of 62.5 kHz, or if the <structfield>capability</structfield>
flag <constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
-Hz. If multiple frequency bands are supported, then
+Hz, or if the <structfield>capability</structfield> flag
+<constant>V4L2_TUNER_CAP_1HZ</constant> is set, in units of 1 Hz.
+If multiple frequency bands are supported, then
<structfield>rangelow</structfield> is the lowest frequency
of all the frequency bands.</entry>
</row>
@@ -144,7 +146,9 @@ of all the frequency bands.</entry>
<entry spanname="hspan">The highest tunable frequency in
units of 62.5 kHz, or if the <structfield>capability</structfield>
flag <constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
-Hz. If multiple frequency bands are supported, then
+Hz, or if the <structfield>capability</structfield> flag
+<constant>V4L2_TUNER_CAP_1HZ</constant> is set, in units of 1 Hz.
+If multiple frequency bands are supported, then
<structfield>rangehigh</structfield> is the highest frequency
of all the frequency bands.</entry>
</row>
@@ -270,7 +274,7 @@ applications must set the array to zero.</entry>
<entry><constant>V4L2_TUNER_CAP_LOW</constant></entry>
<entry>0x0001</entry>
<entry>When set, tuning frequencies are expressed in units of
-62.5&nbsp;Hz, otherwise in units of 62.5&nbsp;kHz.</entry>
+62.5 Hz instead of 62.5 kHz.</entry>
</row>
<row>
<entry><constant>V4L2_TUNER_CAP_NORM</constant></entry>
@@ -360,6 +364,11 @@ radio tuners.</entry>
<entry>The range to search when using the hardware seek functionality
is programmable, see &VIDIOC-S-HW-FREQ-SEEK; for details.</entry>
</row>
+ <row>
+ <entry><constant>V4L2_TUNER_CAP_1HZ</constant></entry>
+ <entry>0x1000</entry>
+ <entry>When set, tuning frequencies are expressed in units of 1 Hz instead of 62.5 kHz.</entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/Documentation/DocBook/media/v4l/vidioc-querycap.xml b/Documentation/DocBook/media/v4l/vidioc-querycap.xml
index d5a3c97b206a..370d49d6fb64 100644
--- a/Documentation/DocBook/media/v4l/vidioc-querycap.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-querycap.xml
@@ -296,6 +296,12 @@ modulator programming see
<xref linkend="tuner" />.</entry>
</row>
<row>
+ <entry><constant>V4L2_CAP_SDR_CAPTURE</constant></entry>
+ <entry>0x00100000</entry>
+ <entry>The device supports the
+<link linkend="sdr">SDR Capture</link> interface.</entry>
+ </row>
+ <row>
<entry><constant>V4L2_CAP_READWRITE</constant></entry>
<entry>0x01000000</entry>
<entry>The device supports the <link
diff --git a/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml b/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml
index 5b379e752194..a5fc4c4880f3 100644
--- a/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml
@@ -121,7 +121,9 @@ field and the &v4l2-tuner; <structfield>index</structfield> field.</entry>
<entry>If non-zero, the lowest tunable frequency of the band to
search in units of 62.5 kHz, or if the &v4l2-tuner;
<structfield>capability</structfield> field has the
-<constant>V4L2_TUNER_CAP_LOW</constant> flag set, in units of 62.5 Hz.
+<constant>V4L2_TUNER_CAP_LOW</constant> flag set, in units of 62.5 Hz or if the &v4l2-tuner;
+<structfield>capability</structfield> field has the
+<constant>V4L2_TUNER_CAP_1HZ</constant> flag set, in units of 1 Hz.
If <structfield>rangelow</structfield> is zero a reasonable default value
is used.</entry>
</row>
@@ -131,7 +133,9 @@ is used.</entry>
<entry>If non-zero, the highest tunable frequency of the band to
search in units of 62.5 kHz, or if the &v4l2-tuner;
<structfield>capability</structfield> field has the
-<constant>V4L2_TUNER_CAP_LOW</constant> flag set, in units of 62.5 Hz.
+<constant>V4L2_TUNER_CAP_LOW</constant> flag set, in units of 62.5 Hz or if the &v4l2-tuner;
+<structfield>capability</structfield> field has the
+<constant>V4L2_TUNER_CAP_1HZ</constant> flag set, in units of 1 Hz.
If <structfield>rangehigh</structfield> is zero a reasonable default value
is used.</entry>
</row>
diff --git a/Documentation/DocBook/media/v4l/vidioc-streamon.xml b/Documentation/DocBook/media/v4l/vidioc-streamon.xml
index 65dff55079d7..df2c63d07bac 100644
--- a/Documentation/DocBook/media/v4l/vidioc-streamon.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-streamon.xml
@@ -52,16 +52,24 @@
<para>The <constant>VIDIOC_STREAMON</constant> and
<constant>VIDIOC_STREAMOFF</constant> ioctl start and stop the capture
or output process during streaming (<link linkend="mmap">memory
-mapping</link> or <link linkend="userp">user pointer</link>) I/O.</para>
+mapping</link>, <link linkend="userp">user pointer</link> or
+<link linkend="dmabuf">DMABUF</link>) I/O.</para>
- <para>Specifically the capture hardware is disabled and no input
+ <para>Capture hardware is disabled and no input
buffers are filled (if there are any empty buffers in the incoming
queue) until <constant>VIDIOC_STREAMON</constant> has been called.
-Accordingly the output hardware is disabled, no video signal is
+Output hardware is disabled and no video signal is
produced until <constant>VIDIOC_STREAMON</constant> has been called.
The ioctl will succeed when at least one output buffer is in the
incoming queue.</para>
+ <para>Memory-to-memory devices will not start until
+<constant>VIDIOC_STREAMON</constant> has been called for both the capture
+and output stream types.</para>
+
+ <para>If <constant>VIDIOC_STREAMON</constant> fails then any already
+queued buffers will remain queued.</para>
+
<para>The <constant>VIDIOC_STREAMOFF</constant> ioctl, apart of
aborting or finishing any DMA in progress, unlocks any user pointer
buffers locked in physical memory, and it removes all buffers from the
@@ -70,14 +78,22 @@ dequeued yet will be lost, likewise all images enqueued for output but
not transmitted yet. I/O returns to the same state as after calling
&VIDIOC-REQBUFS; and can be restarted accordingly.</para>
+ <para>If buffers have been queued with &VIDIOC-QBUF; and
+<constant>VIDIOC_STREAMOFF</constant> is called without ever having
+called <constant>VIDIOC_STREAMON</constant>, then those queued buffers
+will also be removed from the incoming queue and all are returned to the
+same state as after calling &VIDIOC-REQBUFS; and can be restarted
+accordingly.</para>
+
<para>Both ioctls take a pointer to an integer, the desired buffer or
stream type. This is the same as &v4l2-requestbuffers;
<structfield>type</structfield>.</para>
<para>If <constant>VIDIOC_STREAMON</constant> is called when streaming
is already in progress, or if <constant>VIDIOC_STREAMOFF</constant> is called
-when streaming is already stopped, then the ioctl does nothing and 0 is
-returned.</para>
+when streaming is already stopped, then 0 is returned. Nothing happens in the
+case of <constant>VIDIOC_STREAMON</constant>, but <constant>VIDIOC_STREAMOFF</constant>
+will return queued buffers to their starting state as mentioned above.</para>
<para>Note that applications can be preempted for unknown periods right
before or after the <constant>VIDIOC_STREAMON</constant> or
@@ -93,7 +109,7 @@ synchronize with other events.</para>
<varlistentry>
<term><errorcode>EINVAL</errorcode></term>
<listitem>
- <para>The buffer<structfield>type</structfield> is not supported,
+ <para>The buffer <structfield>type</structfield> is not supported,
or no buffers have been allocated (memory mapping) or enqueued
(output) yet.</para>
</listitem>
diff --git a/Documentation/DocBook/media_api.tmpl b/Documentation/DocBook/media_api.tmpl
index 4c8d282545a2..4decb46bfa76 100644
--- a/Documentation/DocBook/media_api.tmpl
+++ b/Documentation/DocBook/media_api.tmpl
@@ -34,22 +34,20 @@
<book id="media_api">
<bookinfo>
-<title>LINUX MEDIA INFRASTRUCTURE API</title>
-
-<copyright>
- <year>2009-2012</year>
- <holder>LinuxTV Developers</holder>
-</copyright>
-
-<legalnotice>
-
-<para>Permission is granted to copy, distribute and/or modify
-this document under the terms of the GNU Free Documentation License,
-Version 1.1 or any later version published by the Free Software
-Foundation. A copy of the license is included in the chapter entitled
-"GNU Free Documentation License"</para>
-</legalnotice>
-
+ <title>LINUX MEDIA INFRASTRUCTURE API</title>
+
+ <copyright>
+ <year>2009-2014</year>
+ <holder>LinuxTV Developers</holder>
+ </copyright>
+
+ <legalnotice>
+ <para>Permission is granted to copy, distribute and/or modify
+ this document under the terms of the GNU Free Documentation License,
+ Version 1.1 or any later version published by the Free Software
+ Foundation. A copy of the license is included in the chapter entitled
+ "GNU Free Documentation License"</para>
+ </legalnotice>
</bookinfo>
<toc></toc> <!-- autogenerated -->
@@ -58,12 +56,13 @@ Foundation. A copy of the license is included in the chapter entitled
<title>Introduction</title>
<para>This document covers the Linux Kernel to Userspace API's used by
- video and radio straming devices, including video cameras,
+ video and radio streaming devices, including video cameras,
analog and digital TV receiver cards, AM/FM receiver cards,
- streaming capture devices.</para>
+ streaming capture and output devices, codec devices and remote
+ controllers.</para>
<para>It is divided into four parts.</para>
- <para>The first part covers radio, capture,
- cameras and analog TV devices.</para>
+ <para>The first part covers radio, video capture and output,
+ cameras, analog TV devices and codecs.</para>
<para>The second part covers the
API used for digital TV and Internet reception via one of the
several digital tv standards. While it is called as DVB API,
@@ -75,55 +74,14 @@ Foundation. A copy of the license is included in the chapter entitled
<para>For additional information and for the latest development code,
see: <ulink url="http://linuxtv.org">http://linuxtv.org</ulink>.</para>
<para>For discussing improvements, reporting troubles, sending new drivers, etc, please mail to: <ulink url="http://vger.kernel.org/vger-lists.html#linux-media">Linux Media Mailing List (LMML).</ulink>.</para>
-
</preface>
-<part id="v4l2spec">
-&sub-v4l2;
-</part>
-<part id="dvbapi">
-&sub-dvbapi;
-</part>
-<part id="v4ldvb_common">
-<partinfo>
-<authorgroup>
-<author>
-<firstname>Mauro</firstname>
-<surname>Chehab</surname>
-<othername role="mi">Carvalho</othername>
-<affiliation><address><email>mchehab@redhat.com</email></address></affiliation>
-<contrib>Initial version.</contrib>
-</author>
-</authorgroup>
-<copyright>
- <year>2009-2012</year>
- <holder>Mauro Carvalho Chehab</holder>
-</copyright>
-
-<revhistory>
-<!-- Put document revisions here, newest first. -->
-<revision>
-<revnumber>1.0.0</revnumber>
-<date>2009-09-06</date>
-<authorinitials>mcc</authorinitials>
-<revremark>Initial revision</revremark>
-</revision>
-</revhistory>
-</partinfo>
-
-<title>Remote Controller API</title>
-<chapter id="remote_controllers">
-&sub-remote_controllers;
-</chapter>
-</part>
-<part id="media_common">
-&sub-media-controller;
-</part>
-
-<chapter id="gen_errors">
-&sub-gen-errors;
-</chapter>
+<part id="v4l2spec">&sub-v4l2;</part>
+<part id="dvbapi">&sub-dvbapi;</part>
+<part id="remotes">&sub-remote_controllers;</part>
+<part id="media_common">&sub-media-controller;</part>
+<chapter id="gen_errors">&sub-gen-errors;</chapter>
&sub-fdl-appendix;
diff --git a/Documentation/DocBook/w1.tmpl b/Documentation/DocBook/w1.tmpl
new file mode 100644
index 000000000000..b0228d4c81bb
--- /dev/null
+++ b/Documentation/DocBook/w1.tmpl
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="w1id">
+ <bookinfo>
+ <title>W1: Dallas' 1-wire bus</title>
+
+ <authorgroup>
+ <author>
+ <firstname>David</firstname>
+ <surname>Fries</surname>
+ <affiliation>
+ <address>
+ <email>David@Fries.net</email>
+ </address>
+ </affiliation>
+ </author>
+
+ </authorgroup>
+
+ <copyright>
+ <year>2013</year>
+ <!--
+ <holder></holder>
+ -->
+ </copyright>
+
+ <legalnotice>
+ <para>
+ This documentation is free software; you can redistribute
+ it and/or modify it under the terms of the GNU General Public
+ License version 2.
+ </para>
+
+ <para>
+ This program is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+ <toc></toc>
+
+ <chapter id="w1_internal">
+ <title>W1 API internal to the kernel</title>
+
+ <sect1 id="w1_internal_api">
+ <title>W1 API internal to the kernel</title>
+ <sect2 id="w1.h">
+ <title>drivers/w1/w1.h</title>
+ <para>W1 core functions.</para>
+!Idrivers/w1/w1.h
+ </sect2>
+
+ <sect2 id="w1.c">
+ <title>drivers/w1/w1.c</title>
+ <para>W1 core functions.</para>
+!Idrivers/w1/w1.c
+ </sect2>
+
+ <sect2 id="w1_family.h">
+ <title>drivers/w1/w1_family.h</title>
+ <para>Allows registering device family operations.</para>
+!Idrivers/w1/w1_family.h
+ </sect2>
+
+ <sect2 id="w1_family.c">
+ <title>drivers/w1/w1_family.c</title>
+ <para>Allows registering device family operations.</para>
+!Edrivers/w1/w1_family.c
+ </sect2>
+
+ <sect2 id="w1_int.c">
+ <title>drivers/w1/w1_int.c</title>
+ <para>W1 internal initialization for master devices.</para>
+!Edrivers/w1/w1_int.c
+ </sect2>
+
+ <sect2 id="w1_netlink.h">
+ <title>drivers/w1/w1_netlink.h</title>
+ <para>W1 external netlink API structures and commands.</para>
+!Idrivers/w1/w1_netlink.h
+ </sect2>
+
+ <sect2 id="w1_io.c">
+ <title>drivers/w1/w1_io.c</title>
+ <para>W1 input/output.</para>
+!Edrivers/w1/w1_io.c
+!Idrivers/w1/w1_io.c
+ </sect2>
+
+ </sect1>
+
+
+ </chapter>
+
+</book>
diff --git a/Documentation/DocBook/writing-an-alsa-driver.tmpl b/Documentation/DocBook/writing-an-alsa-driver.tmpl
index 06741e925985..d0056a4e9c53 100644
--- a/Documentation/DocBook/writing-an-alsa-driver.tmpl
+++ b/Documentation/DocBook/writing-an-alsa-driver.tmpl
@@ -468,8 +468,6 @@
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
*rchip = chip;
return 0;
}
@@ -492,7 +490,8 @@
}
/* (2) */
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
@@ -591,7 +590,8 @@
struct snd_card *card;
int err;
....
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
]]>
</programlisting>
</informalexample>
@@ -809,28 +809,34 @@
<para>
As mentioned above, to create a card instance, call
- <function>snd_card_create()</function>.
+ <function>snd_card_new()</function>.
<informalexample>
<programlisting>
<![CDATA[
struct snd_card *card;
int err;
- err = snd_card_create(index, id, module, extra_size, &card);
+ err = snd_card_new(&pci->dev, index, id, module, extra_size, &card);
]]>
</programlisting>
</informalexample>
</para>
<para>
- The function takes five arguments, the card-index number, the
- id string, the module pointer (usually
+ The function takes six arguments: the parent device pointer,
+ the card-index number, the id string, the module pointer (usually
<constant>THIS_MODULE</constant>),
the size of extra-data space, and the pointer to return the
card instance. The extra_size argument is used to
allocate card-&gt;private_data for the
chip-specific data. Note that these data
- are allocated by <function>snd_card_create()</function>.
+ are allocated by <function>snd_card_new()</function>.
+ </para>
+
+ <para>
+ The first argument, the pointer of struct
+ <structname>device</structname>, specifies the parent device.
+ For PCI devices, typically &amp;pci-&gt; is passed there.
</para>
</section>
@@ -916,16 +922,16 @@
</para>
<section id="card-management-chip-specific-snd-card-new">
- <title>1. Allocating via <function>snd_card_create()</function>.</title>
+ <title>1. Allocating via <function>snd_card_new()</function>.</title>
<para>
As mentioned above, you can pass the extra-data-length
- to the 4th argument of <function>snd_card_create()</function>, i.e.
+ to the 5th argument of <function>snd_card_new()</function>, i.e.
<informalexample>
<programlisting>
<![CDATA[
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct mychip), &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct mychip), &card);
]]>
</programlisting>
</informalexample>
@@ -954,7 +960,7 @@
<para>
After allocating a card instance via
- <function>snd_card_create()</function> (with
+ <function>snd_card_new()</function> (with
<constant>0</constant> on the 4th arg), call
<function>kzalloc()</function>.
@@ -963,7 +969,8 @@
<![CDATA[
struct snd_card *card;
struct mychip *chip;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
.....
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
]]>
@@ -1170,8 +1177,6 @@
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
*rchip = chip;
return 0;
}
@@ -1526,30 +1531,6 @@
</section>
- <section id="pci-resource-device-struct">
- <title>Registration of Device Struct</title>
- <para>
- At some point, typically after calling <function>snd_device_new()</function>,
- you need to register the struct <structname>device</structname> of the chip
- you're handling for udev and co. ALSA provides a macro for compatibility with
- older kernels. Simply call like the following:
- <informalexample>
- <programlisting>
-<![CDATA[
- snd_card_set_dev(card, &pci->dev);
-]]>
- </programlisting>
- </informalexample>
- so that it stores the PCI's device pointer to the card. This will be
- referred by ALSA core functions later when the devices are registered.
- </para>
- <para>
- In the case of non-PCI, pass the proper device struct pointer of the BUS
- instead. (In the case of legacy ISA without PnP, you don't have to do
- anything.)
- </para>
- </section>
-
<section id="pci-resource-entries">
<title>PCI Entries</title>
<para>
@@ -5740,7 +5721,8 @@ struct _snd_pcm_runtime {
struct mychip *chip;
int err;
....
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
....
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
....
@@ -5752,7 +5734,7 @@ struct _snd_pcm_runtime {
</informalexample>
When you created the chip data with
- <function>snd_card_create()</function>, it's anyway accessible
+ <function>snd_card_new()</function>, it's anyway accessible
via <structfield>private_data</structfield> field.
<informalexample>
@@ -5766,8 +5748,8 @@ struct _snd_pcm_runtime {
struct mychip *chip;
int err;
....
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct mychip), &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct mychip), &card);
....
chip = card->private_data;
....
diff --git a/Documentation/PCI/MSI-HOWTO.txt b/Documentation/PCI/MSI-HOWTO.txt
index a8d01005f480..10a93696e55a 100644
--- a/Documentation/PCI/MSI-HOWTO.txt
+++ b/Documentation/PCI/MSI-HOWTO.txt
@@ -82,7 +82,19 @@ Most of the hard work is done for the driver in the PCI layer. It simply
has to request that the PCI layer set up the MSI capability for this
device.
-4.2.1 pci_enable_msi_range
+4.2.1 pci_enable_msi
+
+int pci_enable_msi(struct pci_dev *dev)
+
+A successful call allocates ONE interrupt to the device, regardless
+of how many MSIs the device supports. The device is switched from
+pin-based interrupt mode to MSI mode. The dev->irq number is changed
+to a new number which represents the message signaled interrupt;
+consequently, this function should be called before the driver calls
+request_irq(), because an MSI is delivered via a vector that is
+different from the vector of a pin-based interrupt.
+
+4.2.2 pci_enable_msi_range
int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec)
@@ -147,6 +159,11 @@ static int foo_driver_enable_msi(struct pci_dev *pdev, int nvec)
return pci_enable_msi_range(pdev, nvec, nvec);
}
+Note, unlike pci_enable_msi_exact() function, which could be also used to
+enable a particular number of MSI-X interrupts, pci_enable_msi_range()
+returns either a negative errno or 'nvec' (not negative errno or 0 - as
+pci_enable_msi_exact() does).
+
4.2.1.3 Single MSI mode
The most notorious example of the request type described above is
@@ -158,7 +175,27 @@ static int foo_driver_enable_single_msi(struct pci_dev *pdev)
return pci_enable_msi_range(pdev, 1, 1);
}
-4.2.2 pci_disable_msi
+Note, unlike pci_enable_msi() function, which could be also used to
+enable the single MSI mode, pci_enable_msi_range() returns either a
+negative errno or 1 (not negative errno or 0 - as pci_enable_msi()
+does).
+
+4.2.3 pci_enable_msi_exact
+
+int pci_enable_msi_exact(struct pci_dev *dev, int nvec)
+
+This variation on pci_enable_msi_range() call allows a device driver to
+request exactly 'nvec' MSIs.
+
+If this function returns a negative number, it indicates an error and
+the driver should not attempt to request any more MSI interrupts for
+this device.
+
+By contrast with pci_enable_msi_range() function, pci_enable_msi_exact()
+returns zero in case of success, which indicates MSI interrupts have been
+successfully allocated.
+
+4.2.4 pci_disable_msi
void pci_disable_msi(struct pci_dev *dev)
@@ -172,7 +209,7 @@ on any interrupt for which it previously called request_irq().
Failure to do so results in a BUG_ON(), leaving the device with
MSI enabled and thus leaking its vector.
-4.2.3 pci_msi_vec_count
+4.2.4 pci_msi_vec_count
int pci_msi_vec_count(struct pci_dev *dev)
@@ -257,8 +294,8 @@ possible, likely up to the limit returned by pci_msix_vec_count() function:
static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
{
- return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
- 1, nvec);
+ return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+ 1, nvec);
}
Note the value of 'minvec' parameter is 1. As 'minvec' is inclusive,
@@ -269,8 +306,8 @@ In this case the function could look like this:
static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
{
- return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
- FOO_DRIVER_MINIMUM_NVEC, nvec);
+ return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+ FOO_DRIVER_MINIMUM_NVEC, nvec);
}
4.3.1.2 Exact number of MSI-X interrupts
@@ -282,10 +319,15 @@ parameters:
static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
{
- return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
- nvec, nvec);
+ return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+ nvec, nvec);
}
+Note, unlike pci_enable_msix_exact() function, which could be also used to
+enable a particular number of MSI-X interrupts, pci_enable_msix_range()
+returns either a negative errno or 'nvec' (not negative errno or 0 - as
+pci_enable_msix_exact() does).
+
4.3.1.3 Specific requirements to the number of MSI-X interrupts
As noted above, there could be devices that can not operate with just any
@@ -332,7 +374,64 @@ Note how pci_enable_msix_range() return value is analized for a fallback -
any error code other than -ENOSPC indicates a fatal error and should not
be retried.
-4.3.2 pci_disable_msix
+4.3.2 pci_enable_msix_exact
+
+int pci_enable_msix_exact(struct pci_dev *dev,
+ struct msix_entry *entries, int nvec)
+
+This variation on pci_enable_msix_range() call allows a device driver to
+request exactly 'nvec' MSI-Xs.
+
+If this function returns a negative number, it indicates an error and
+the driver should not attempt to allocate any more MSI-X interrupts for
+this device.
+
+By contrast with pci_enable_msix_range() function, pci_enable_msix_exact()
+returns zero in case of success, which indicates MSI-X interrupts have been
+successfully allocated.
+
+Another version of a routine that enables MSI-X mode for a device with
+specific requirements described in chapter 4.3.1.3 might look like this:
+
+/*
+ * Assume 'minvec' and 'maxvec' are non-zero
+ */
+static int foo_driver_enable_msix(struct foo_adapter *adapter,
+ int minvec, int maxvec)
+{
+ int rc;
+
+ minvec = roundup_pow_of_two(minvec);
+ maxvec = rounddown_pow_of_two(maxvec);
+
+ if (minvec > maxvec)
+ return -ERANGE;
+
+retry:
+ rc = pci_enable_msix_exact(adapter->pdev,
+ adapter->msix_entries, maxvec);
+
+ /*
+ * -ENOSPC is the only error code allowed to be analyzed
+ */
+ if (rc == -ENOSPC) {
+ if (maxvec == 1)
+ return -ENOSPC;
+
+ maxvec /= 2;
+
+ if (minvec > maxvec)
+ return -ENOSPC;
+
+ goto retry;
+ } else if (rc < 0) {
+ return rc;
+ }
+
+ return maxvec;
+}
+
+4.3.3 pci_disable_msix
void pci_disable_msix(struct pci_dev *dev)
diff --git a/Documentation/PCI/pci-iov-howto.txt b/Documentation/PCI/pci-iov-howto.txt
index 86551cc72e03..2d91ae251982 100644
--- a/Documentation/PCI/pci-iov-howto.txt
+++ b/Documentation/PCI/pci-iov-howto.txt
@@ -68,10 +68,6 @@ To disable SR-IOV capability:
echo 0 > \
/sys/bus/pci/devices/<DOMAIN:BUS:DEVICE.FUNCTION>/sriov_numvfs
-To notify SR-IOV core of Virtual Function Migration:
-(a) In the driver:
- irqreturn_t pci_sriov_migration(struct pci_dev *dev);
-
3.2 Usage example
Following piece of code illustrates the usage of the SR-IOV API.
diff --git a/Documentation/RCU/00-INDEX b/Documentation/RCU/00-INDEX
index 1d7a885761f5..fa57139f50bf 100644
--- a/Documentation/RCU/00-INDEX
+++ b/Documentation/RCU/00-INDEX
@@ -8,6 +8,8 @@ listRCU.txt
- Using RCU to Protect Read-Mostly Linked Lists
lockdep.txt
- RCU and lockdep checking
+lockdep-splat.txt
+ - RCU Lockdep splats explained.
NMI-RCU.txt
- Using RCU to Protect Dynamic NMI Handlers
rcubarrier.txt
diff --git a/Documentation/RCU/RTFP.txt b/Documentation/RCU/RTFP.txt
index 273e654d7d08..2f0fcb2112d2 100644
--- a/Documentation/RCU/RTFP.txt
+++ b/Documentation/RCU/RTFP.txt
@@ -31,6 +31,14 @@ has lapsed, so this approach may be used in non-GPL software, if desired.
(In contrast, implementation of RCU is permitted only in software licensed
under either GPL or LGPL. Sorry!!!)
+In 1987, Rashid et al. described lazy TLB-flush [RichardRashid87a].
+At first glance, this has nothing to do with RCU, but nevertheless
+this paper helped inspire the update-side batching used in the later
+RCU implementation in DYNIX/ptx. In 1988, Barbara Liskov published
+a description of Argus that noted that use of out-of-date values can
+be tolerated in some situations. Thus, this paper provides some early
+theoretical justification for use of stale data.
+
In 1990, Pugh [Pugh90] noted that explicitly tracking which threads
were reading a given data structure permitted deferred free to operate
in the presence of non-terminating threads. However, this explicit
@@ -41,11 +49,11 @@ providing a fine-grained locking design, however, it would be interesting
to see how much of the performance advantage reported in 1990 remains
today.
-At about this same time, Adams [Adams91] described ``chaotic relaxation'',
-where the normal barriers between successive iterations of convergent
-numerical algorithms are relaxed, so that iteration $n$ might use
-data from iteration $n-1$ or even $n-2$. This introduces error,
-which typically slows convergence and thus increases the number of
+At about this same time, Andrews [Andrews91textbook] described ``chaotic
+relaxation'', where the normal barriers between successive iterations
+of convergent numerical algorithms are relaxed, so that iteration $n$
+might use data from iteration $n-1$ or even $n-2$. This introduces
+error, which typically slows convergence and thus increases the number of
iterations required. However, this increase is sometimes more than made
up for by a reduction in the number of expensive barrier operations,
which are otherwise required to synchronize the threads at the end
@@ -55,7 +63,8 @@ is thus inapplicable to most data structures in operating-system kernels.
In 1992, Henry (now Alexia) Massalin completed a dissertation advising
parallel programmers to defer processing when feasible to simplify
-synchronization. RCU makes extremely heavy use of this advice.
+synchronization [HMassalinPhD]. RCU makes extremely heavy use of
+this advice.
In 1993, Jacobson [Jacobson93] verbally described what is perhaps the
simplest deferred-free technique: simply waiting a fixed amount of time
@@ -90,27 +99,29 @@ mechanism, which is quite similar to RCU [Gamsa99]. These operating
systems made pervasive use of RCU in place of "existence locks", which
greatly simplifies locking hierarchies and helps avoid deadlocks.
-2001 saw the first RCU presentation involving Linux [McKenney01a]
-at OLS. The resulting abundance of RCU patches was presented the
-following year [McKenney02a], and use of RCU in dcache was first
-described that same year [Linder02a].
+The year 2000 saw an email exchange that would likely have
+led to yet another independent invention of something like RCU
+[RustyRussell2000a,RustyRussell2000b]. Instead, 2001 saw the first
+RCU presentation involving Linux [McKenney01a] at OLS. The resulting
+abundance of RCU patches was presented the following year [McKenney02a],
+and use of RCU in dcache was first described that same year [Linder02a].
Also in 2002, Michael [Michael02b,Michael02a] presented "hazard-pointer"
techniques that defer the destruction of data structures to simplify
non-blocking synchronization (wait-free synchronization, lock-free
synchronization, and obstruction-free synchronization are all examples of
-non-blocking synchronization). In particular, this technique eliminates
-locking, reduces contention, reduces memory latency for readers, and
-parallelizes pipeline stalls and memory latency for writers. However,
-these techniques still impose significant read-side overhead in the
-form of memory barriers. Researchers at Sun worked along similar lines
-in the same timeframe [HerlihyLM02]. These techniques can be thought
-of as inside-out reference counts, where the count is represented by the
-number of hazard pointers referencing a given data structure rather than
-the more conventional counter field within the data structure itself.
-The key advantage of inside-out reference counts is that they can be
-stored in immortal variables, thus allowing races between access and
-deletion to be avoided.
+non-blocking synchronization). The corresponding journal article appeared
+in 2004 [MagedMichael04a]. This technique eliminates locking, reduces
+contention, reduces memory latency for readers, and parallelizes pipeline
+stalls and memory latency for writers. However, these techniques still
+impose significant read-side overhead in the form of memory barriers.
+Researchers at Sun worked along similar lines in the same timeframe
+[HerlihyLM02]. These techniques can be thought of as inside-out reference
+counts, where the count is represented by the number of hazard pointers
+referencing a given data structure rather than the more conventional
+counter field within the data structure itself. The key advantage
+of inside-out reference counts is that they can be stored in immortal
+variables, thus allowing races between access and deletion to be avoided.
By the same token, RCU can be thought of as a "bulk reference count",
where some form of reference counter covers all reference by a given CPU
@@ -123,8 +134,10 @@ can be thought of in other terms as well.
In 2003, the K42 group described how RCU could be used to create
hot-pluggable implementations of operating-system functions [Appavoo03a].
-Later that year saw a paper describing an RCU implementation of System
-V IPC [Arcangeli03], and an introduction to RCU in Linux Journal
+Later that year saw a paper describing an RCU implementation
+of System V IPC [Arcangeli03] (following up on a suggestion by
+Hugh Dickins [Dickins02a] and an implementation by Mingming Cao
+[MingmingCao2002IPCRCU]), and an introduction to RCU in Linux Journal
[McKenney03a].
2004 has seen a Linux-Journal article on use of RCU in dcache
@@ -383,6 +396,21 @@ for Programming Languages and Operating Systems}"
}
}
+@phdthesis{HMassalinPhD
+,author="H. Massalin"
+,title="Synthesis: An Efficient Implementation of Fundamental Operating
+System Services"
+,school="Columbia University"
+,address="New York, NY"
+,year="1992"
+,annotation={
+ Mondo optimizing compiler.
+ Wait-free stuff.
+ Good advice: defer work to avoid synchronization. See page 90
+ (PDF page 106), Section 5.4, fourth bullet point.
+}
+}
+
@unpublished{Jacobson93
,author="Van Jacobson"
,title="Avoid Read-Side Locking Via Delayed Free"
@@ -671,6 +699,20 @@ Orran Krieger and Rusty Russell and Dipankar Sarma and Maneesh Soni"
[Viewed October 18, 2004]"
}
+@conference{Michael02b
+,author="Maged M. Michael"
+,title="High Performance Dynamic Lock-Free Hash Tables and List-Based Sets"
+,Year="2002"
+,Month="August"
+,booktitle="{Proceedings of the 14\textsuperscript{th} Annual ACM
+Symposium on Parallel
+Algorithms and Architecture}"
+,pages="73-82"
+,annotation={
+Like the title says...
+}
+}
+
@Conference{Linder02a
,Author="Hanna Linder and Dipankar Sarma and Maneesh Soni"
,Title="Scalability of the Directory Entry Cache"
@@ -727,6 +769,24 @@ Andrea Arcangeli and Andi Kleen and Orran Krieger and Rusty Russell"
}
}
+@conference{Michael02a
+,author="Maged M. Michael"
+,title="Safe Memory Reclamation for Dynamic Lock-Free Objects Using Atomic
+Reads and Writes"
+,Year="2002"
+,Month="August"
+,booktitle="{Proceedings of the 21\textsuperscript{st} Annual ACM
+Symposium on Principles of Distributed Computing}"
+,pages="21-30"
+,annotation={
+ Each thread keeps an array of pointers to items that it is
+ currently referencing. Sort of an inside-out garbage collection
+ mechanism, but one that requires the accessing code to explicitly
+ state its needs. Also requires read-side memory barriers on
+ most architectures.
+}
+}
+
@unpublished{Dickins02a
,author="Hugh Dickins"
,title="Use RCU for System-V IPC"
@@ -735,6 +795,17 @@ Andrea Arcangeli and Andi Kleen and Orran Krieger and Rusty Russell"
,note="private communication"
}
+@InProceedings{HerlihyLM02
+,author={Maurice Herlihy and Victor Luchangco and Mark Moir}
+,title="The Repeat Offender Problem: A Mechanism for Supporting Dynamic-Sized,
+Lock-Free Data Structures"
+,booktitle={Proceedings of 16\textsuperscript{th} International
+Symposium on Distributed Computing}
+,year=2002
+,month="October"
+,pages="339-353"
+}
+
@unpublished{Sarma02b
,Author="Dipankar Sarma"
,Title="Some dcache\_rcu benchmark numbers"
@@ -749,6 +820,19 @@ Andrea Arcangeli and Andi Kleen and Orran Krieger and Rusty Russell"
}
}
+@unpublished{MingmingCao2002IPCRCU
+,Author="Mingming Cao"
+,Title="[PATCH]updated ipc lock patch"
+,month="October"
+,year="2002"
+,note="Available:
+\url{https://lkml.org/lkml/2002/10/24/262}
+[Viewed February 15, 2014]"
+,annotation={
+ Mingming Cao's patch to introduce RCU to SysV IPC.
+}
+}
+
@unpublished{LinusTorvalds2003a
,Author="Linus Torvalds"
,Title="Re: {[PATCH]} small fixes in brlock.h"
@@ -982,6 +1066,23 @@ Realtime Applications"
}
}
+@article{MagedMichael04a
+,author="Maged M. Michael"
+,title="Hazard Pointers: Safe Memory Reclamation for Lock-Free Objects"
+,Year="2004"
+,Month="June"
+,journal="IEEE Transactions on Parallel and Distributed Systems"
+,volume="15"
+,number="6"
+,pages="491-504"
+,url="Available:
+\url{http://www.research.ibm.com/people/m/michael/ieeetpds-2004.pdf}
+[Viewed March 1, 2005]"
+,annotation={
+ New canonical hazard-pointer citation.
+}
+}
+
@phdthesis{PaulEdwardMcKenneyPhD
,author="Paul E. McKenney"
,title="Exploiting Deferred Destruction:
diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt
index 91266193b8f4..9d10d1db16a5 100644
--- a/Documentation/RCU/checklist.txt
+++ b/Documentation/RCU/checklist.txt
@@ -256,10 +256,10 @@ over a rather long period of time, but improvements are always welcome!
variations on this theme.
b. Limiting update rate. For example, if updates occur only
- once per hour, then no explicit rate limiting is required,
- unless your system is already badly broken. The dcache
- subsystem takes this approach -- updates are guarded
- by a global lock, limiting their rate.
+ once per hour, then no explicit rate limiting is
+ required, unless your system is already badly broken.
+ Older versions of the dcache subsystem take this approach,
+ guarding updates with a global lock, limiting their rate.
c. Trusted update -- if updates can only be done manually by
superuser or some other trusted user, then it might not
@@ -268,7 +268,8 @@ over a rather long period of time, but improvements are always welcome!
the machine.
d. Use call_rcu_bh() rather than call_rcu(), in order to take
- advantage of call_rcu_bh()'s faster grace periods.
+ advantage of call_rcu_bh()'s faster grace periods. (This
+ is only a partial solution, though.)
e. Periodically invoke synchronize_rcu(), permitting a limited
number of updates per grace period.
@@ -276,6 +277,13 @@ over a rather long period of time, but improvements are always welcome!
The same cautions apply to call_rcu_bh(), call_rcu_sched(),
call_srcu(), and kfree_rcu().
+ Note that although these primitives do take action to avoid memory
+ exhaustion when any given CPU has too many callbacks, a determined
+ user could still exhaust memory. This is especially the case
+ if a system with a large number of CPUs has been configured to
+ offload all of its RCU callbacks onto a single CPU, or if the
+ system has relatively little free memory.
+
9. All RCU list-traversal primitives, which include
rcu_dereference(), list_for_each_entry_rcu(), and
list_for_each_safe_rcu(), must be either within an RCU read-side
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 26b1e31d5a13..2a8e89e13e45 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -14,7 +14,10 @@ Read Documentation/SubmitChecklist for a list of items to check
before submitting code. If you are submitting a driver, also read
Documentation/SubmittingDrivers.
-
+Many of these steps describe the default behavior of the git version
+control system; if you use git to prepare your patches, you'll find much
+of the mechanical work done for you, though you'll still need to prepare
+and document a sensible set of patches.
--------------------------------------------
SECTION 1 - CREATING AND SENDING YOUR CHANGE
@@ -25,7 +28,9 @@ SECTION 1 - CREATING AND SENDING YOUR CHANGE
1) "diff -up"
------------
-Use "diff -up" or "diff -uprN" to create patches.
+Use "diff -up" or "diff -uprN" to create patches. git generates patches
+in this form by default; if you're using git, you can skip this section
+entirely.
All changes to the Linux kernel occur in the form of patches, as
generated by diff(1). When creating your patch, make sure to create it
@@ -66,19 +71,14 @@ Make sure your patch does not include any extra files which do not
belong in a patch submission. Make sure to review your patch -after-
generated it with diff(1), to ensure accuracy.
-If your changes produce a lot of deltas, you may want to look into
-splitting them into individual patches which modify things in
-logical stages. This will facilitate easier reviewing by other
-kernel developers, very important if you want your patch accepted.
-There are a number of scripts which can aid in this:
-
-Quilt:
-http://savannah.nongnu.org/projects/quilt
+If your changes produce a lot of deltas, you need to split them into
+individual patches which modify things in logical stages; see section
+#3. This will facilitate easier reviewing by other kernel developers,
+very important if you want your patch accepted.
-Andrew Morton's patch scripts:
-http://userweb.kernel.org/~akpm/stuff/patch-scripts.tar.gz
-Instead of these scripts, quilt is the recommended patch management
-tool (see above).
+If you're using git, "git rebase -i" can help you with this process. If
+you're not using git, quilt <http://savannah.nongnu.org/projects/quilt>
+is another popular alternative.
@@ -106,8 +106,21 @@ I.e., the patch (series) and its description should be self-contained.
This benefits both the patch merger(s) and reviewers. Some reviewers
probably didn't even receive earlier versions of the patch.
+Describe your changes in imperative mood, e.g. "make xyzzy do frotz"
+instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy
+to do frotz", as if you are giving orders to the codebase to change
+its behaviour.
+
If the patch fixes a logged bug entry, refer to that bug entry by
-number and URL.
+number and URL. If the patch follows from a mailing list discussion,
+give a URL to the mailing list archive; use the https://lkml.kernel.org/
+redirector with a Message-Id, to ensure that the links cannot become
+stale.
+
+However, try to make your explanation understandable without external
+resources. In addition to giving a URL to a mailing list archive or
+bug, summarize the relevant points of the discussion that led to the
+patch as submitted.
If you want to refer to a specific commit, don't just refer to the
SHA-1 ID of the commit. Please also include the oneline summary of
@@ -594,7 +607,8 @@ patch.
If you are going to include a diffstat after the "---" marker, please
use diffstat options "-p 1 -w 70" so that filenames are listed from
the top of the kernel source tree and don't use too much horizontal
-space (easily fit in 80 columns, maybe with some indentation).
+space (easily fit in 80 columns, maybe with some indentation). (git
+generates appropriate diffstats by default.)
See more details on the proper patch format in the following
references.
@@ -725,7 +739,7 @@ SECTION 3 - REFERENCES
----------------------
Andrew Morton, "The perfect patch" (tpp).
- <http://userweb.kernel.org/~akpm/stuff/tpp.txt>
+ <http://www.ozlabs.org/~akpm/stuff/tpp.txt>
Jeff Garzik, "Linux kernel patch submission format".
<http://linux.yyz.us/patch-format.html>
@@ -738,7 +752,7 @@ Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer".
<http://www.kroah.com/log/linux/maintainer-05.html>
NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!
- <http://marc.theaimsgroup.com/?l=linux-kernel&m=112112749912944&w=2>
+ <https://lkml.org/lkml/2005/7/11/336>
Kernel Documentation/CodingStyle:
<http://users.sosdg.org/~qiyong/lxr/source/Documentation/CodingStyle>
diff --git a/Documentation/arm/00-INDEX b/Documentation/arm/00-INDEX
index 36420e116c90..a94090cc785d 100644
--- a/Documentation/arm/00-INDEX
+++ b/Documentation/arm/00-INDEX
@@ -4,6 +4,8 @@ Booting
- requirements for booting
Interrupts
- ARM Interrupt subsystem documentation
+IXP4xx
+ - Intel IXP4xx Network processor.
msm
- MSM specific documentation
Netwinder
@@ -24,8 +26,16 @@ SPEAr
- ST SPEAr platform Linux Overview
VFP/
- Release notes for Linux Kernel Vector Floating Point support code
+cluster-pm-race-avoidance.txt
+ - Algorithm for CPU and Cluster setup/teardown
empeg/
- Ltd's Empeg MP3 Car Audio Player
+firmware.txt
+ - Secure firmware registration and calling.
+kernel_mode_neon.txt
+ - How to use NEON instructions in kernel mode
+kernel_user_helpers.txt
+ - Helper functions in kernel space made available for userspace.
mem_alignment
- alignment abort handler documentation
memory.txt
@@ -34,3 +44,7 @@ nwfpe/
- NWFPE floating point emulator documentation
swp_emulation
- SWP/SWPB emulation handler/logging description
+tcm.txt
+ - ARM Tightly Coupled Memory
+vlocks.txt
+ - Voting locks, low-level mechanism relying on memory system atomic writes.
diff --git a/Documentation/arm64/memory.txt b/Documentation/arm64/memory.txt
index 5e054bfe4dde..85e24c4f215c 100644
--- a/Documentation/arm64/memory.txt
+++ b/Documentation/arm64/memory.txt
@@ -35,11 +35,13 @@ ffffffbc00000000 ffffffbdffffffff 8GB vmemmap
ffffffbe00000000 ffffffbffbbfffff ~8GB [guard, future vmmemap]
-ffffffbffbc00000 ffffffbffbdfffff 2MB earlyprintk device
+ffffffbffa000000 ffffffbffaffffff 16MB PCI I/O space
+
+ffffffbffb000000 ffffffbffbbfffff 12MB [guard]
-ffffffbffbe00000 ffffffbffbe0ffff 64KB PCI I/O space
+ffffffbffbc00000 ffffffbffbdfffff 2MB earlyprintk device
-ffffffbffbe10000 ffffffbcffffffff ~2MB [guard]
+ffffffbffbe00000 ffffffbffbffffff 2MB [guard]
ffffffbffc000000 ffffffbfffffffff 64MB modules
@@ -60,11 +62,13 @@ fffffdfc00000000 fffffdfdffffffff 8GB vmemmap
fffffdfe00000000 fffffdfffbbfffff ~8GB [guard, future vmmemap]
-fffffdfffbc00000 fffffdfffbdfffff 2MB earlyprintk device
+fffffdfffa000000 fffffdfffaffffff 16MB PCI I/O space
+
+fffffdfffb000000 fffffdfffbbfffff 12MB [guard]
-fffffdfffbe00000 fffffdfffbe0ffff 64KB PCI I/O space
+fffffdfffbc00000 fffffdfffbdfffff 2MB earlyprintk device
-fffffdfffbe10000 fffffdfffbffffff ~2MB [guard]
+fffffdfffbe00000 fffffdfffbffffff 2MB [guard]
fffffdfffc000000 fffffdffffffffff 64MB modules
diff --git a/Documentation/blackfin/00-INDEX b/Documentation/blackfin/00-INDEX
index 2df0365f2dff..c54fcdd4ae9f 100644
--- a/Documentation/blackfin/00-INDEX
+++ b/Documentation/blackfin/00-INDEX
@@ -1,8 +1,10 @@
00-INDEX
- This file
-
+Makefile
+ - Makefile for gptimers example file.
bfin-gpio-notes.txt
- Notes in developing/using bfin-gpio driver.
-
bfin-spi-notes.txt
- Notes for using bfin spi bus driver.
+gptimers-example.c
+ - gptimers example
diff --git a/Documentation/block/00-INDEX b/Documentation/block/00-INDEX
index 929d9904f74b..e840b47613f7 100644
--- a/Documentation/block/00-INDEX
+++ b/Documentation/block/00-INDEX
@@ -14,6 +14,8 @@ deadline-iosched.txt
- Deadline IO scheduler tunables
ioprio.txt
- Block io priorities (in CFQ scheduler)
+null_blk.txt
+ - Null block for block-layer benchmarking.
queue-sysfs.txt
- Queue's sysfs entries
request.txt
diff --git a/Documentation/blockdev/drbd/data-structure-v9.txt b/Documentation/blockdev/drbd/data-structure-v9.txt
new file mode 100644
index 000000000000..1e52a0e32624
--- /dev/null
+++ b/Documentation/blockdev/drbd/data-structure-v9.txt
@@ -0,0 +1,38 @@
+This describes the in kernel data structure for DRBD-9. Starting with
+Linux v3.14 we are reorganizing DRBD to use this data structure.
+
+Basic Data Structure
+====================
+
+A node has a number of DRBD resources. Each such resource has a number of
+devices (aka volumes) and connections to other nodes ("peer nodes"). Each DRBD
+device is represented by a block device locally.
+
+The DRBD objects are interconnected to form a matrix as depicted below; a
+drbd_peer_device object sits at each intersection between a drbd_device and a
+drbd_connection:
+
+ /--------------+---------------+.....+---------------\
+ | resource | device | | device |
+ +--------------+---------------+.....+---------------+
+ | connection | peer_device | | peer_device |
+ +--------------+---------------+.....+---------------+
+ : : : : :
+ : : : : :
+ +--------------+---------------+.....+---------------+
+ | connection | peer_device | | peer_device |
+ \--------------+---------------+.....+---------------/
+
+In this table, horizontally, devices can be accessed from resources by their
+volume number. Likewise, peer_devices can be accessed from connections by
+their volume number. Objects in the vertical direction are connected by double
+linked lists. There are back pointers from peer_devices to their connections a
+devices, and from connections and devices to their resource.
+
+All resources are in the drbd_resources double-linked list. In addition, all
+devices can be accessed by their minor device number via the drbd_devices idr.
+
+The drbd_resource, drbd_connection, and drbd_device objects are reference
+counted. The peer_device objects only serve to establish the links between
+devices and connections; their lifetime is determined by the lifetime of the
+device and connection which they reference.
diff --git a/Documentation/connector/cn_test.c b/Documentation/connector/cn_test.c
index adcca0368d60..d12cc944b696 100644
--- a/Documentation/connector/cn_test.c
+++ b/Documentation/connector/cn_test.c
@@ -145,7 +145,7 @@ static void cn_test_timer_func(unsigned long __data)
memcpy(m + 1, data, m->len);
- cn_netlink_send(m, 0, GFP_ATOMIC);
+ cn_netlink_send(m, 0, 0, GFP_ATOMIC);
kfree(m);
}
diff --git a/Documentation/cpu-freq/core.txt b/Documentation/cpu-freq/core.txt
index ce0666e51036..0060d76b445f 100644
--- a/Documentation/cpu-freq/core.txt
+++ b/Documentation/cpu-freq/core.txt
@@ -92,7 +92,3 @@ values:
cpu - number of the affected CPU
old - old frequency
new - new frequency
-
-If the cpufreq core detects the frequency has changed while the system
-was suspended, these notifiers are called with CPUFREQ_RESUMECHANGE as
-second argument.
diff --git a/Documentation/cpu-freq/cpu-drivers.txt b/Documentation/cpu-freq/cpu-drivers.txt
index 8b1a4451422e..48da5fdcb9f1 100644
--- a/Documentation/cpu-freq/cpu-drivers.txt
+++ b/Documentation/cpu-freq/cpu-drivers.txt
@@ -61,7 +61,13 @@ target_index - See below on the differences.
And optionally
-cpufreq_driver.exit - A pointer to a per-CPU cleanup function.
+cpufreq_driver.exit - A pointer to a per-CPU cleanup
+ function called during CPU_POST_DEAD
+ phase of cpu hotplug process.
+
+cpufreq_driver.stop_cpu - A pointer to a per-CPU stop function
+ called during CPU_DOWN_PREPARE phase of
+ cpu hotplug process.
cpufreq_driver.resume - A pointer to a per-CPU resume function
which is called with interrupts disabled
diff --git a/Documentation/device-mapper/cache.txt b/Documentation/device-mapper/cache.txt
index e6b72d355151..68c0f517c60e 100644
--- a/Documentation/device-mapper/cache.txt
+++ b/Documentation/device-mapper/cache.txt
@@ -124,12 +124,11 @@ the default being 204800 sectors (or 100MB).
Updating on-disk metadata
-------------------------
-On-disk metadata is committed every time a REQ_SYNC or REQ_FUA bio is
-written. If no such requests are made then commits will occur every
-second. This means the cache behaves like a physical disk that has a
-write cache (the same is true of the thin-provisioning target). If
-power is lost you may lose some recent writes. The metadata should
-always be consistent in spite of any crash.
+On-disk metadata is committed every time a FLUSH or FUA bio is written.
+If no such requests are made then commits will occur every second. This
+means the cache behaves like a physical disk that has a volatile write
+cache. If power is lost you may lose some recent writes. The metadata
+should always be consistent in spite of any crash.
The 'dirty' state for a cache block changes far too frequently for us
to keep updating it on the fly. So we treat it as a hint. In normal
diff --git a/Documentation/device-mapper/thin-provisioning.txt b/Documentation/device-mapper/thin-provisioning.txt
index 8a7a3d46e0da..05a27e9442bd 100644
--- a/Documentation/device-mapper/thin-provisioning.txt
+++ b/Documentation/device-mapper/thin-provisioning.txt
@@ -116,6 +116,35 @@ Resuming a device with a new table itself triggers an event so the
userspace daemon can use this to detect a situation where a new table
already exceeds the threshold.
+A low water mark for the metadata device is maintained in the kernel and
+will trigger a dm event if free space on the metadata device drops below
+it.
+
+Updating on-disk metadata
+-------------------------
+
+On-disk metadata is committed every time a FLUSH or FUA bio is written.
+If no such requests are made then commits will occur every second. This
+means the thin-provisioning target behaves like a physical disk that has
+a volatile write cache. If power is lost you may lose some recent
+writes. The metadata should always be consistent in spite of any crash.
+
+If data space is exhausted the pool will either error or queue IO
+according to the configuration (see: error_if_no_space). If metadata
+space is exhausted or a metadata operation fails: the pool will error IO
+until the pool is taken offline and repair is performed to 1) fix any
+potential inconsistencies and 2) clear the flag that imposes repair.
+Once the pool's metadata device is repaired it may be resized, which
+will allow the pool to return to normal operation. Note that if a pool
+is flagged as needing repair, the pool's data and metadata devices
+cannot be resized until repair is performed. It should also be noted
+that when the pool's metadata space is exhausted the current metadata
+transaction is aborted. Given that the pool will cache IO whose
+completion may have already been acknowledged to upper IO layers
+(e.g. filesystem) it is strongly suggested that consistency checks
+(e.g. fsck) be performed on those layers when repair of the pool is
+required.
+
Thin provisioning
-----------------
@@ -258,10 +287,9 @@ ii) Status
should register for the event and then check the target's status.
held metadata root:
- The location, in sectors, of the metadata root that has been
+ The location, in blocks, of the metadata root that has been
'held' for userspace read access. '-' indicates there is no
- held root. This feature is not yet implemented so '-' is
- always returned.
+ held root.
discard_passdown|no_discard_passdown
Whether or not discards are actually being passed down to the
diff --git a/Documentation/devices.txt b/Documentation/devices.txt
index 10378cc48374..87b4c5e82d39 100644
--- a/Documentation/devices.txt
+++ b/Documentation/devices.txt
@@ -353,6 +353,7 @@ Your cooperation is appreciated.
133 = /dev/exttrp External device trap
134 = /dev/apm_bios Advanced Power Management BIOS
135 = /dev/rtc Real Time Clock
+ 137 = /dev/vhci Bluetooth virtual HCI driver
139 = /dev/openprom SPARC OpenBoot PROM
140 = /dev/relay8 Berkshire Products Octal relay card
141 = /dev/relay16 Berkshire Products ISO-16 relay card
@@ -410,6 +411,7 @@ Your cooperation is appreciated.
194 = /dev/zkshim Zero-Knowledge network shim control
195 = /dev/elographics/e2201 Elographics touchscreen E271-2201
196 = /dev/vfio/vfio VFIO userspace driver interface
+ 197 = /dev/pxa3xx-gcu PXA3xx graphics controller unit driver
198 = /dev/sexec Signed executable interface
199 = /dev/scanners/cuecat :CueCat barcode scanner
200 = /dev/net/tun TAP/TUN network device
@@ -451,6 +453,7 @@ Your cooperation is appreciated.
236 = /dev/mapper/control Device-Mapper control device
237 = /dev/loop-control Loopback control device
238 = /dev/vhost-net Host kernel accelerator for virtio net
+ 239 = /dev/uhid User-space I/O driver support for HID subsystem
240-254 Reserved for local use
255 Reserved for MISC_DYNAMIC_MINOR
@@ -1491,10 +1494,17 @@ Your cooperation is appreciated.
64 = /dev/radio0 Radio device
...
127 = /dev/radio63 Radio device
+ 128 = /dev/swradio0 Software Defined Radio device
+ ...
+ 191 = /dev/swradio63 Software Defined Radio device
224 = /dev/vbi0 Vertical blank interrupt
...
255 = /dev/vbi31 Vertical blank interrupt
+ Minor numbers are allocated dynamically unless
+ CONFIG_VIDEO_FIXED_MINOR_RANGES (default n)
+ configuration option is set.
+
81 block I2O hard disk
0 = /dev/i2o/hdq 17th I2O hard disk, whole disk
16 = /dev/i2o/hdr 18th I2O hard disk, whole disk
diff --git a/Documentation/devicetree/00-INDEX b/Documentation/devicetree/00-INDEX
index b78f691fd847..8c4102c6a5e7 100644
--- a/Documentation/devicetree/00-INDEX
+++ b/Documentation/devicetree/00-INDEX
@@ -8,3 +8,5 @@ https://lists.ozlabs.org/listinfo/devicetree-discuss
- this file
booting-without-of.txt
- Booting Linux without Open Firmware, describes history and format of device trees.
+usage-model.txt
+ - How Linux uses DT and what DT aims to solve. \ No newline at end of file
diff --git a/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt b/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt
index d74091a8a3bf..5fc03134a999 100644
--- a/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt
+++ b/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt
@@ -1,4 +1,4 @@
-Marvell Armada 370 and Armada XP Interrupt Controller
+Marvell Armada 370, 375, 38x, XP Interrupt Controller
-----------------------------------------------------
Required properties:
@@ -16,7 +16,13 @@ Required properties:
automatically map to the interrupt controller registers of the
current CPU)
+Optional properties:
+- interrupts: If defined, then it indicates that this MPIC is
+ connected as a slave to another interrupt controller. This is
+ typically the case on Armada 375 and Armada 38x, where the MPIC is
+ connected as a slave to the Cortex-A9 GIC. The provided interrupt
+ indicate to which GIC interrupt the MPIC output is connected.
Example:
diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index d1061469f63d..9a1175b46f49 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -5,6 +5,9 @@ Required properties:
<chip> can be "at91sam9260", "at91sam9g45" or "at91sam9x5"
- reg: Should contain ADC registers location and length
- interrupts: Should contain the IRQ line for the ADC
+ - clock-names: tuple listing input clock names.
+ Required elements: "adc_clk", "adc_op_clk".
+ - clocks: phandles to input clocks.
- atmel,adc-channels-used: Bitmask of the channels muxed and enable for this
device
- atmel,adc-startup-time: Startup Time of the ADC in microseconds as
@@ -44,6 +47,8 @@ adc0: adc@fffb0000 {
compatible = "atmel,at91sam9260-adc";
reg = <0xfffb0000 0x100>;
interrupts = <20 4>;
+ clocks = <&adc_clk>, <&adc_op_clk>;
+ clock-names = "adc_clk", "adc_op_clk";
atmel,adc-channel-base = <0x30>;
atmel,adc-channels-used = <0xff>;
atmel,adc-drdy-mask = <0x10000>;
diff --git a/Documentation/devicetree/bindings/arm/marvell,dove.txt b/Documentation/devicetree/bindings/arm/marvell,dove.txt
new file mode 100644
index 000000000000..aaaf64c56e44
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/marvell,dove.txt
@@ -0,0 +1,22 @@
+Marvell Dove Platforms Device Tree Bindings
+-----------------------------------------------
+
+Boards with a Marvell Dove SoC shall have the following properties:
+
+Required root node property:
+- compatible: must contain "marvell,dove";
+
+* Global Configuration registers
+
+Global Configuration registers of Dove SoC are shared by a syscon node.
+
+Required properties:
+- compatible: must contain "marvell,dove-global-config" and "syscon".
+- reg: base address and size of the Global Configuration registers.
+
+Example:
+
+gconf: global-config@e802c {
+ compatible = "marvell,dove-global-config", "syscon";
+ reg = <0xe802c 0x14>;
+};
diff --git a/Documentation/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt
index 34dc40cffdfd..af9b4a0d902b 100644
--- a/Documentation/devicetree/bindings/arm/omap/omap.txt
+++ b/Documentation/devicetree/bindings/arm/omap/omap.txt
@@ -91,7 +91,7 @@ Boards:
compatible = "ti,omap3-beagle", "ti,omap3"
- OMAP3 Tobi with Overo : Commercial expansion board with daughter board
- compatible = "ti,omap3-tobi", "ti,omap3-overo", "ti,omap3"
+ compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap3"
- OMAP4 SDP : Software Development Board
compatible = "ti,omap4-sdp", "ti,omap4430"
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index 89de1564950c..48b285ffa3a6 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -4,17 +4,33 @@ SATA nodes are defined to describe on-chip Serial ATA controllers.
Each SATA controller should have its own node.
Required properties:
-- compatible : compatible list, contains "snps,spear-ahci"
+- compatible : compatible list, one of "snps,spear-ahci",
+ "snps,exynos5440-ahci", "ibm,476gtr-ahci",
+ "allwinner,sun4i-a10-ahci", "fsl,imx53-ahci"
+ "fsl,imx6q-ahci" or "snps,dwc-ahci"
- interrupts : <interrupt mapping for SATA IRQ>
- reg : <registers mapping>
Optional properties:
- dma-coherent : Present if dma operations are coherent
+- clocks : a list of phandle + clock specifier pairs
+- target-supply : regulator for SATA target power
-Example:
+"fsl,imx53-ahci", "fsl,imx6q-ahci" required properties:
+- clocks : must contain the sata, sata_ref and ahb clocks
+- clock-names : must contain "ahb" for the ahb clock
+
+Examples:
sata@ffe08000 {
compatible = "snps,spear-ahci";
reg = <0xffe08000 0x1000>;
interrupts = <115>;
-
};
+
+ ahci: sata@01c18000 {
+ compatible = "allwinner,sun4i-a10-ahci";
+ reg = <0x01c18000 0x1000>;
+ interrupts = <56>;
+ clocks = <&pll6 0>, <&ahb_gates 25>;
+ target-supply = <&reg_ahci_5v>;
+ };
diff --git a/Documentation/devicetree/bindings/ata/apm-xgene.txt b/Documentation/devicetree/bindings/ata/apm-xgene.txt
new file mode 100644
index 000000000000..7bcfbf59810e
--- /dev/null
+++ b/Documentation/devicetree/bindings/ata/apm-xgene.txt
@@ -0,0 +1,76 @@
+* APM X-Gene 6.0 Gb/s SATA host controller nodes
+
+SATA host controller nodes are defined to describe on-chip Serial ATA
+controllers. Each SATA controller (pair of ports) have its own node.
+
+Required properties:
+- compatible : Shall contain:
+ * "apm,xgene-ahci"
+- reg : First memory resource shall be the AHCI memory
+ resource.
+ Second memory resource shall be the host controller
+ core memory resource.
+ Third memory resource shall be the host controller
+ diagnostic memory resource.
+ 4th memory resource shall be the host controller
+ AXI memory resource.
+ 5th optional memory resource shall be the host
+ controller MUX memory resource if required.
+- interrupts : Interrupt-specifier for SATA host controller IRQ.
+- clocks : Reference to the clock entry.
+- phys : A list of phandles + phy-specifiers, one for each
+ entry in phy-names.
+- phy-names : Should contain:
+ * "sata-phy" for the SATA 6.0Gbps PHY
+
+Optional properties:
+- status : Shall be "ok" if enabled or "disabled" if disabled.
+ Default is "ok".
+
+Example:
+ sataclk: sataclk {
+ compatible = "fixed-clock";
+ #clock-cells = <1>;
+ clock-frequency = <100000000>;
+ clock-output-names = "sataclk";
+ };
+
+ phy2: phy@1f22a000 {
+ compatible = "apm,xgene-phy";
+ reg = <0x0 0x1f22a000 0x0 0x100>;
+ #phy-cells = <1>;
+ };
+
+ phy3: phy@1f23a000 {
+ compatible = "apm,xgene-phy";
+ reg = <0x0 0x1f23a000 0x0 0x100>;
+ #phy-cells = <1>;
+ };
+
+ sata2: sata@1a400000 {
+ compatible = "apm,xgene-ahci";
+ reg = <0x0 0x1a400000 0x0 0x1000>,
+ <0x0 0x1f220000 0x0 0x1000>,
+ <0x0 0x1f22d000 0x0 0x1000>,
+ <0x0 0x1f22e000 0x0 0x1000>,
+ <0x0 0x1f227000 0x0 0x1000>;
+ interrupts = <0x0 0x87 0x4>;
+ status = "ok";
+ clocks = <&sataclk 0>;
+ phys = <&phy2 0>;
+ phy-names = "sata-phy";
+ };
+
+ sata3: sata@1a800000 {
+ compatible = "apm,xgene-ahci-pcie";
+ reg = <0x0 0x1a800000 0x0 0x1000>,
+ <0x0 0x1f230000 0x0 0x1000>,
+ <0x0 0x1f23d000 0x0 0x1000>,
+ <0x0 0x1f23e000 0x0 0x1000>,
+ <0x0 0x1f237000 0x0 0x1000>;
+ interrupts = <0x0 0x88 0x4>;
+ status = "ok";
+ clocks = <&sataclk 0>;
+ phys = <&phy3 0>;
+ phy-names = "sata-phy";
+ };
diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
index a6a352c2771e..5992dceec7af 100644
--- a/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
+++ b/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
@@ -21,9 +21,9 @@ Required Properties:
must appear in the same order as the output clocks.
- #clock-cells: Must be 1
- clock-output-names: The name of the clocks as free-form strings
- - renesas,indices: Indices of the gate clocks into the group (0 to 31)
+ - renesas,clock-indices: Indices of the gate clocks into the group (0 to 31)
-The clocks, clock-output-names and renesas,indices properties contain one
+The clocks, clock-output-names and renesas,clock-indices properties contain one
entry per gate clock. The MSTP groups are sparsely populated. Unimplemented
gate clocks must not be declared.
diff --git a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
index 68b83ecc3850..ee9be9961524 100644
--- a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
+++ b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
@@ -1,12 +1,16 @@
* Freescale Smart Direct Memory Access (SDMA) Controller for i.MX
Required properties:
-- compatible : Should be "fsl,imx31-sdma", "fsl,imx31-to1-sdma",
- "fsl,imx31-to2-sdma", "fsl,imx35-sdma", "fsl,imx35-to1-sdma",
- "fsl,imx35-to2-sdma", "fsl,imx51-sdma", "fsl,imx53-sdma" or
- "fsl,imx6q-sdma". The -to variants should be preferred since they
- allow to determnine the correct ROM script addresses needed for
- the driver to work without additional firmware.
+- compatible : Should be one of
+ "fsl,imx25-sdma"
+ "fsl,imx31-sdma", "fsl,imx31-to1-sdma", "fsl,imx31-to2-sdma"
+ "fsl,imx35-sdma", "fsl,imx35-to1-sdma", "fsl,imx35-to2-sdma"
+ "fsl,imx51-sdma"
+ "fsl,imx53-sdma"
+ "fsl,imx6q-sdma"
+ The -to variants should be preferred since they allow to determnine the
+ correct ROM script addresses needed for the driver to work without additional
+ firmware.
- reg : Should contain SDMA registers location and length
- interrupts : Should contain SDMA interrupt
- #dma-cells : Must be <3>.
diff --git a/Documentation/devicetree/bindings/gpio/cirrus,clps711x-mctrl-gpio.txt b/Documentation/devicetree/bindings/gpio/cirrus,clps711x-mctrl-gpio.txt
new file mode 100644
index 000000000000..94ae9f82dcf8
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/cirrus,clps711x-mctrl-gpio.txt
@@ -0,0 +1,17 @@
+* ARM Cirrus Logic CLPS711X SYSFLG1 MCTRL GPIOs
+
+Required properties:
+- compatible: Should contain "cirrus,clps711x-mctrl-gpio".
+- gpio-controller: Marks the device node as a gpio controller.
+- #gpio-cells: Should be two. The first cell is the pin number and
+ the second cell is used to specify the gpio polarity:
+ 0 = Active high,
+ 1 = Active low.
+
+Example:
+ sysgpio: sysgpio {
+ compatible = "cirrus,ep7312-mctrl-gpio",
+ "cirrus,clps711x-mctrl-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
diff --git a/Documentation/devicetree/bindings/gpio/gpio-davinci.txt b/Documentation/devicetree/bindings/gpio/gpio-davinci.txt
index a2e839d6e338..5079ba7d6568 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-davinci.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-davinci.txt
@@ -1,13 +1,17 @@
-Davinci GPIO controller bindings
+Davinci/Keystone GPIO controller bindings
Required Properties:
-- compatible: should be "ti,dm6441-gpio"
+- compatible: should be "ti,dm6441-gpio", "ti,keystone-gpio"
- reg: Physical base address of the controller and the size of memory mapped
registers.
- gpio-controller : Marks the device node as a gpio controller.
+- #gpio-cells : Should be two.
+ - first cell is the pin number
+ - second cell is used to specify optional parameters (unused)
+
- interrupt-parent: phandle of the parent interrupt controller.
- interrupts: Array of GPIO interrupt number. Only banked or unbanked IRQs are
@@ -27,6 +31,7 @@ Example:
gpio: gpio@1e26000 {
compatible = "ti,dm6441-gpio";
gpio-controller;
+ #gpio-cells = <2>;
reg = <0x226000 0x1000>;
interrupt-parent = <&intc>;
interrupts = <42 IRQ_TYPE_EDGE_BOTH 43 IRQ_TYPE_EDGE_BOTH
@@ -39,3 +44,19 @@ gpio: gpio@1e26000 {
interrupt-controller;
#interrupt-cells = <2>;
};
+
+leds {
+ compatible = "gpio-leds";
+
+ led1 {
+ label = "davinci:green:usr1";
+ gpios = <&gpio 10 GPIO_ACTIVE_HIGH>;
+ ...
+ };
+
+ led2 {
+ label = "davinci:red:debug1";
+ gpios = <&gpio 11 GPIO_ACTIVE_HIGH>;
+ ...
+ };
+};
diff --git a/Documentation/devicetree/bindings/gpio/gpio-zevio.txt b/Documentation/devicetree/bindings/gpio/gpio-zevio.txt
new file mode 100644
index 000000000000..a37bd9ae2730
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-zevio.txt
@@ -0,0 +1,16 @@
+Zevio GPIO controller
+
+Required properties:
+- compatible: Should be "lsi,zevio-gpio"
+- reg: Address and length of the register set for the device
+- #gpio-cells: Should be two. The first cell is the pin number and the
+ second cell is used to specify optional parameters (currently unused).
+- gpio-controller: Marks the device node as a GPIO controller.
+
+Example:
+ gpio: gpio@90000000 {
+ compatible = "lsi,zevio-gpio";
+ reg = <0x90000000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt
index 0c85bb6e3a80..3fb8f53071b8 100644
--- a/Documentation/devicetree/bindings/gpio/gpio.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio.txt
@@ -13,11 +13,11 @@ properties, each containing a 'gpio-list':
gpio-specifier : Array of #gpio-cells specifying specific gpio
(controller specific)
-GPIO properties should be named "[<name>-]gpios". Exact
+GPIO properties should be named "[<name>-]gpios". The exact
meaning of each gpios property must be documented in the device tree
binding for each device.
-For example, the following could be used to describe gpios pins to use
+For example, the following could be used to describe GPIO pins used
as chip select lines; with chip selects 0, 1 and 3 populated, and chip
select 2 left empty:
@@ -44,35 +44,79 @@ whether pin is open-drain and whether pin is logically inverted.
Exact meaning of each specifier cell is controller specific, and must
be documented in the device tree binding for the device.
-Example of the node using GPIOs:
+Example of a node using GPIOs:
node {
gpios = <&qe_pio_e 18 0>;
};
In this example gpio-specifier is "18 0" and encodes GPIO pin number,
-and empty GPIO flags as accepted by the "qe_pio_e" gpio-controller.
+and GPIO flags as accepted by the "qe_pio_e" gpio-controller.
+
+1.1) GPIO specifier best practices
+----------------------------------
+
+A gpio-specifier should contain a flag indicating the GPIO polarity; active-
+high or active-low. If it does, the follow best practices should be followed:
+
+The gpio-specifier's polarity flag should represent the physical level at the
+GPIO controller that achieves (or represents, for inputs) a logically asserted
+value at the device. The exact definition of logically asserted should be
+defined by the binding for the device. If the board inverts the signal between
+the GPIO controller and the device, then the gpio-specifier will represent the
+opposite physical level than the signal at the device's pin.
+
+When the device's signal polarity is configurable, the binding for the
+device must either:
+
+a) Define a single static polarity for the signal, with the expectation that
+any software using that binding would statically program the device to use
+that signal polarity.
+
+The static choice of polarity may be either:
+
+a1) (Preferred) Dictated by a binding-specific DT property.
+
+or:
+
+a2) Defined statically by the DT binding itself.
+
+In particular, the polarity cannot be derived from the gpio-specifier, since
+that would prevent the DT from separately representing the two orthogonal
+concepts of configurable signal polarity in the device, and possible board-
+level signal inversion.
+
+or:
+
+b) Pick a single option for device signal polarity, and document this choice
+in the binding. The gpio-specifier should represent the polarity of the signal
+(at the GPIO controller) assuming that the device is configured for this
+particular signal polarity choice. If software chooses to program the device
+to generate or receive a signal of the opposite polarity, software will be
+responsible for correctly interpreting (inverting) the GPIO signal at the GPIO
+controller.
2) gpio-controller nodes
------------------------
-Every GPIO controller node must both an empty "gpio-controller"
-property, and have #gpio-cells contain the size of the gpio-specifier.
+Every GPIO controller node must contain both an empty "gpio-controller"
+property, and a #gpio-cells integer property, which indicates the number of
+cells in a gpio-specifier.
Example of two SOC GPIO banks defined as gpio-controller nodes:
qe_pio_a: gpio-controller@1400 {
- #gpio-cells = <2>;
compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank";
reg = <0x1400 0x18>;
gpio-controller;
+ #gpio-cells = <2>;
};
qe_pio_e: gpio-controller@1460 {
- #gpio-cells = <2>;
compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
reg = <0x1460 0x18>;
gpio-controller;
+ #gpio-cells = <2>;
};
2.1) gpio- and pin-controller interaction
diff --git a/Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt b/Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt
new file mode 100644
index 000000000000..dd5d2c0394b1
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt
@@ -0,0 +1,60 @@
+* Synopsys DesignWare APB GPIO controller
+
+Required properties:
+- compatible : Should contain "snps,dw-apb-gpio"
+- reg : Address and length of the register set for the device.
+- #address-cells : should be 1 (for addressing port subnodes).
+- #size-cells : should be 0 (port subnodes).
+
+The GPIO controller has a configurable number of ports, each of which are
+represented as child nodes with the following properties:
+
+Required properties:
+- compatible : "snps,dw-apb-gpio-port"
+- gpio-controller : Marks the device node as a gpio controller.
+- #gpio-cells : Should be two. The first cell is the pin number and
+ the second cell is used to specify the gpio polarity:
+ 0 = active high
+ 1 = active low
+- reg : The integer port index of the port, a single cell.
+
+Optional properties:
+- interrupt-controller : The first port may be configured to be an interrupt
+controller.
+- #interrupt-cells : Specifies the number of cells needed to encode an
+ interrupt. Shall be set to 2. The first cell defines the interrupt number,
+ the second encodes the triger flags encoded as described in
+ Documentation/devicetree/bindings/interrupts.txt
+- interrupt-parent : The parent interrupt controller.
+- interrupts : The interrupt to the parent controller raised when GPIOs
+ generate the interrupts.
+- snps,nr-gpios : The number of pins in the port, a single cell.
+
+Example:
+
+gpio: gpio@20000 {
+ compatible = "snps,dw-apb-gpio";
+ reg = <0x20000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ porta: gpio-controller@0 {
+ compatible = "snps,dw-apb-gpio-port";
+ gpio-controller;
+ #gpio-cells = <2>;
+ snps,nr-gpios = <8>;
+ reg = <0>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupt-parent = <&vic1>;
+ interrupts = <0>;
+ };
+
+ portb: gpio-controller@1 {
+ compatible = "snps,dw-apb-gpio-port";
+ gpio-controller;
+ #gpio-cells = <2>;
+ snps,nr-gpios = <8>;
+ reg = <1>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/graph.txt b/Documentation/devicetree/bindings/graph.txt
new file mode 100644
index 000000000000..1a69c078adf2
--- /dev/null
+++ b/Documentation/devicetree/bindings/graph.txt
@@ -0,0 +1,129 @@
+Common bindings for device graphs
+
+General concept
+---------------
+
+The hierarchical organisation of the device tree is well suited to describe
+control flow to devices, but there can be more complex connections between
+devices that work together to form a logical compound device, following an
+arbitrarily complex graph.
+There already is a simple directed graph between devices tree nodes using
+phandle properties pointing to other nodes to describe connections that
+can not be inferred from device tree parent-child relationships. The device
+tree graph bindings described herein abstract more complex devices that can
+have multiple specifiable ports, each of which can be linked to one or more
+ports of other devices.
+
+These common bindings do not contain any information about the direction or
+type of the connections, they just map their existence. Specific properties
+may be described by specialized bindings depending on the type of connection.
+
+To see how this binding applies to video pipelines, for example, see
+Documentation/device-tree/bindings/media/video-interfaces.txt.
+Here the ports describe data interfaces, and the links between them are
+the connecting data buses. A single port with multiple connections can
+correspond to multiple devices being connected to the same physical bus.
+
+Organisation of ports and endpoints
+-----------------------------------
+
+Ports are described by child 'port' nodes contained in the device node.
+Each port node contains an 'endpoint' subnode for each remote device port
+connected to this port. If a single port is connected to more than one
+remote device, an 'endpoint' child node must be provided for each link.
+If more than one port is present in a device node or there is more than one
+endpoint at a port, or a port node needs to be associated with a selected
+hardware interface, a common scheme using '#address-cells', '#size-cells'
+and 'reg' properties is used number the nodes.
+
+device {
+ ...
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ endpoint@0 {
+ reg = <0>;
+ ...
+ };
+ endpoint@1 {
+ reg = <1>;
+ ...
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ endpoint { ... };
+ };
+};
+
+All 'port' nodes can be grouped under an optional 'ports' node, which
+allows to specify #address-cells, #size-cells properties for the 'port'
+nodes independently from any other child device nodes a device might
+have.
+
+device {
+ ...
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ ...
+ endpoint@0 { ... };
+ endpoint@1 { ... };
+ };
+
+ port@1 { ... };
+ };
+};
+
+Links between endpoints
+-----------------------
+
+Each endpoint should contain a 'remote-endpoint' phandle property that points
+to the corresponding endpoint in the port of the remote device. In turn, the
+remote endpoint should contain a 'remote-endpoint' property. If it has one,
+it must not point to another than the local endpoint. Two endpoints with their
+'remote-endpoint' phandles pointing at each other form a link between the
+containing ports.
+
+device-1 {
+ port {
+ device_1_output: endpoint {
+ remote-endpoint = <&device_2_input>;
+ };
+ };
+};
+
+device-2 {
+ port {
+ device_2_input: endpoint {
+ remote-endpoint = <&device_1_output>;
+ };
+ };
+};
+
+
+Required properties
+-------------------
+
+If there is more than one 'port' or more than one 'endpoint' node or 'reg'
+property is present in port and/or endpoint nodes the following properties
+are required in a relevant parent node:
+
+ - #address-cells : number of cells required to define port/endpoint
+ identifier, should be 1.
+ - #size-cells : should be zero.
+
+Optional endpoint properties
+----------------------------
+
+- remote-endpoint: phandle to an 'endpoint' subnode of a remote device node.
+
diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
index 1a1ac2e560e9..f47e56bcf78d 100644
--- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt
+++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
@@ -18,6 +18,7 @@ atmel,24c02 i2c serial eeprom (24cxx)
atmel,at97sc3204t i2c trusted platform module (TPM)
capella,cm32181 CM32181: Ambient Light Sensor
catalyst,24c32 i2c serial eeprom
+cirrus,cs42l51 Cirrus Logic CS42L51 audio codec
dallas,ds1307 64 x 8, Serial, I2C Real-Time Clock
dallas,ds1338 I2C RTC with 56-Byte NV RAM
dallas,ds1339 I2C Serial Real-Time Clock
diff --git a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
new file mode 100644
index 000000000000..dcebff1928e1
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
@@ -0,0 +1,22 @@
+Freescale vf610 Analog to Digital Converter bindings
+
+The devicetree bindings are for the new ADC driver written for
+vf610/i.MX6slx and upward SoCs from Freescale.
+
+Required properties:
+- compatible: Should contain "fsl,vf610-adc"
+- reg: Offset and length of the register set for the device
+- interrupts: Should contain the interrupt for the device
+- clocks: The clock is needed by the ADC controller, ADC clock source is ipg clock.
+- clock-names: Must contain "adc", matching entry in the clocks property.
+- vref-supply: The regulator supply ADC refrence voltage.
+
+Example:
+adc0: adc@4003b000 {
+ compatible = "fsl,vf610-adc";
+ reg = <0x4003b000 0x1000>;
+ interrupts = <0 53 0x04>;
+ clocks = <&clks VF610_CLK_ADC0>;
+ clock-names = "adc";
+ vref-supply = <&reg_vcc_3v3_mcu>;
+};
diff --git a/Documentation/devicetree/bindings/iio/adc/xilinx-xadc.txt b/Documentation/devicetree/bindings/iio/adc/xilinx-xadc.txt
new file mode 100644
index 000000000000..d9ee909d2b78
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/xilinx-xadc.txt
@@ -0,0 +1,113 @@
+Xilinx XADC device driver
+
+This binding document describes the bindings for both of them since the
+bindings are very similar. The Xilinx XADC is a ADC that can be found in the
+series 7 FPGAs from Xilinx. The XADC has a DRP interface for communication.
+Currently two different frontends for the DRP interface exist. One that is only
+available on the ZYNQ family as a hardmacro in the SoC portion of the ZYNQ. The
+other one is available on all series 7 platforms and is a softmacro with a AXI
+interface. This binding document describes the bindings for both of them since
+the bindings are very similar.
+
+Required properties:
+ - compatible: Should be one of
+ * "xlnx,zynq-xadc-1.00.a": When using the ZYNQ device
+ configuration interface to interface to the XADC hardmacro.
+ * "xlnx,axi-xadc-1.00.a": When using the axi-xadc pcore to
+ interface to the XADC hardmacro.
+ - reg: Address and length of the register set for the device
+ - interrupts: Interrupt for the XADC control interface.
+ - clocks: When using the ZYNQ this must be the ZYNQ PCAP clock,
+ when using the AXI-XADC pcore this must be the clock that provides the
+ clock to the AXI bus interface of the core.
+
+Optional properties:
+ - interrupt-parent: phandle to the parent interrupt controller
+ - xlnx,external-mux:
+ * "none": No external multiplexer is used, this is the default
+ if the property is omitted.
+ * "single": External multiplexer mode is used with one
+ multiplexer.
+ * "dual": External multiplexer mode is used with two
+ multiplexers for simultaneous sampling.
+ - xlnx,external-mux-channel: Configures which pair of pins is used to
+ sample data in external mux mode.
+ Valid values for single external multiplexer mode are:
+ 0: VP/VN
+ 1: VAUXP[0]/VAUXN[0]
+ 2: VAUXP[1]/VAUXN[1]
+ ...
+ 16: VAUXP[15]/VAUXN[15]
+ Valid values for dual external multiplexer mode are:
+ 1: VAUXP[0]/VAUXN[0] - VAUXP[8]/VAUXN[8]
+ 2: VAUXP[1]/VAUXN[1] - VAUXP[9]/VAUXN[9]
+ ...
+ 8: VAUXP[7]/VAUXN[7] - VAUXP[15]/VAUXN[15]
+
+ This property needs to be present if the device is configured for
+ external multiplexer mode (either single or dual). If the device is
+ not using external multiplexer mode the property is ignored.
+ - xnlx,channels: List of external channels that are connected to the ADC
+ Required properties:
+ * #address-cells: Should be 1.
+ * #size-cells: Should be 0.
+
+ The child nodes of this node represent the external channels which are
+ connected to the ADC. If the property is no present no external
+ channels will be assumed to be connected.
+
+ Each child node represents one channel and has the following
+ properties:
+ Required properties:
+ * reg: Pair of pins the the channel is connected to.
+ 0: VP/VN
+ 1: VAUXP[0]/VAUXN[0]
+ 2: VAUXP[1]/VAUXN[1]
+ ...
+ 16: VAUXP[15]/VAUXN[15]
+ Note each channel number should only be used at most
+ once.
+ Optional properties:
+ * xlnx,bipolar: If set the channel is used in bipolar
+ mode.
+
+
+Examples:
+ xadc@f8007100 {
+ compatible = "xlnx,zynq-xadc-1.00.a";
+ reg = <0xf8007100 0x20>;
+ interrupts = <0 7 4>;
+ interrupt-parent = <&gic>;
+ clocks = <&pcap_clk>;
+
+ xlnx,channels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ channel@0 {
+ reg = <0>;
+ };
+ channel@1 {
+ reg = <1>;
+ };
+ channel@8 {
+ reg = <8>;
+ };
+ };
+ };
+
+ xadc@43200000 {
+ compatible = "xlnx,axi-xadc-1.00.a";
+ reg = <0x43200000 0x1000>;
+ interrupts = <0 53 4>;
+ interrupt-parent = <&gic>;
+ clocks = <&fpga1_clk>;
+
+ xlnx,channels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ channel@0 {
+ reg = <0>;
+ xlnx,bipolar;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/input/clps711x-keypad.txt b/Documentation/devicetree/bindings/input/clps711x-keypad.txt
new file mode 100644
index 000000000000..e68d2bbc6c07
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/clps711x-keypad.txt
@@ -0,0 +1,27 @@
+* Cirrus Logic CLPS711X matrix keypad device tree bindings
+
+Required Properties:
+- compatible: Shall contain "cirrus,clps711x-keypad".
+- row-gpios: List of GPIOs used as row lines.
+- poll-interval: Poll interval time in milliseconds.
+- linux,keymap: The definition can be found at
+ bindings/input/matrix-keymap.txt.
+
+Optional Properties:
+- autorepeat: Enable autorepeat feature.
+
+Example:
+ keypad {
+ compatible = "cirrus,ep7312-keypad", "cirrus,clps711x-keypad";
+ autorepeat;
+ poll-interval = <120>;
+ row-gpios = <&porta 0 0>,
+ <&porta 1 0>;
+
+ linux,keymap = <
+ MATRIX_KEY(0, 0, KEY_UP)
+ MATRIX_KEY(0, 1, KEY_DOWN)
+ MATRIX_KEY(1, 0, KEY_LEFT)
+ MATRIX_KEY(1, 1, KEY_RIGHT)
+ >;
+ };
diff --git a/Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt b/Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt
new file mode 100644
index 000000000000..7d8cb92831d7
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt
@@ -0,0 +1,89 @@
+Qualcomm PM8xxx PMIC Keypad
+
+PROPERTIES
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,pm8058-keypad"
+ "qcom,pm8921-keypad"
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: address of keypad control register
+
+- interrupts:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: the first interrupt specifies the key sense interrupt
+ and the second interrupt specifies the key stuck interrupt.
+ The format of the specifier is defined by the binding
+ document describing the node's interrupt parent.
+
+- linux,keymap:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: the linux keymap. More information can be found in
+ input/matrix-keymap.txt.
+
+- linux,keypad-no-autorepeat:
+ Usage: optional
+ Value type: <bool>
+ Definition: don't enable autorepeat feature.
+
+- linux,keypad-wakeup:
+ Usage: optional
+ Value type: <bool>
+ Definition: use any event on keypad as wakeup event.
+
+- keypad,num-rows:
+ Usage: required
+ Value type: <u32>
+ Definition: number of rows in the keymap. More information can be found
+ in input/matrix-keymap.txt.
+
+- keypad,num-columns:
+ Usage: required
+ Value type: <u32>
+ Definition: number of columns in the keymap. More information can be
+ found in input/matrix-keymap.txt.
+
+- debounce:
+ Usage: optional
+ Value type: <u32>
+ Definition: time in microseconds that key must be pressed or release
+ for key sense interrupt to trigger.
+
+- scan-delay:
+ Usage: optional
+ Value type: <u32>
+ Definition: time in microseconds to pause between successive scans
+ of the matrix array.
+
+- row-hold:
+ Usage: optional
+ Value type: <u32>
+ Definition: time in nanoseconds to pause between scans of each row in
+ the matrix array.
+
+EXAMPLE
+
+ keypad@148 {
+ compatible = "qcom,pm8921-keypad";
+ reg = <0x148>;
+ interrupt-parent = <&pmicintc>;
+ interrupts = <74 1>, <75 1>;
+ linux,keymap = <
+ MATRIX_KEY(0, 0, KEY_VOLUMEUP)
+ MATRIX_KEY(0, 1, KEY_VOLUMEDOWN)
+ MATRIX_KEY(0, 2, KEY_CAMERA_FOCUS)
+ MATRIX_KEY(0, 3, KEY_CAMERA)
+ >;
+ keypad,num-rows = <1>;
+ keypad,num-columns = <5>;
+ debounce = <15>;
+ scan-delay = <32>;
+ row-hold = <91500>;
+ };
diff --git a/Documentation/devicetree/bindings/input/qcom,pm8xxx-pwrkey.txt b/Documentation/devicetree/bindings/input/qcom,pm8xxx-pwrkey.txt
new file mode 100644
index 000000000000..588536cc96ed
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/qcom,pm8xxx-pwrkey.txt
@@ -0,0 +1,46 @@
+Qualcomm PM8xxx PMIC Power Key
+
+PROPERTIES
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,pm8058-pwrkey"
+ "qcom,pm8921-pwrkey"
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: address of power key control register
+
+- interrupts:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: the first interrupt specifies the key release interrupt
+ and the second interrupt specifies the key press interrupt.
+ The format of the specifier is defined by the binding
+ document describing the node's interrupt parent.
+
+- debounce:
+ Usage: optional
+ Value type: <u32>
+ Definition: time in microseconds that key must be pressed or release
+ for state change interrupt to trigger.
+
+- pull-up:
+ Usage: optional
+ Value type: <empty>
+ Definition: presence of this property indicates that the KPDPWR_N pin
+ should be configured for pull up.
+
+EXAMPLE
+
+ pwrkey@1c {
+ compatible = "qcom,pm8921-pwrkey";
+ reg = <0x1c>;
+ interrupt-parent = <&pmicintc>;
+ interrupts = <50 1>, <51 1>;
+ debounce = <15625>;
+ pull-up;
+ };
diff --git a/Documentation/devicetree/bindings/input/qcom,pm8xxx-vib.txt b/Documentation/devicetree/bindings/input/qcom,pm8xxx-vib.txt
new file mode 100644
index 000000000000..4ed467b1e402
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/qcom,pm8xxx-vib.txt
@@ -0,0 +1,22 @@
+Qualcomm PM8xxx PMIC Vibrator
+
+PROPERTIES
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,pm8058-vib"
+ "qcom,pm8921-vib"
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: address of vibration control register
+
+EXAMPLE
+
+ vibrator@4a {
+ compatible = "qcom,pm8058-vib";
+ reg = <0x4a>;
+ };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt
new file mode 100644
index 000000000000..76db96704a60
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt
@@ -0,0 +1,55 @@
+FocalTech EDT-FT5x06 Polytouch driver
+=====================================
+
+There are 3 variants of the chip for various touch panel sizes
+FT5206GE1 2.8" .. 3.8"
+FT5306DE4 4.3" .. 7"
+FT5406EE8 7" .. 8.9"
+
+The software interface is identical for all those chips, so that
+currently there is no need for the driver to distinguish between the
+different chips. Nevertheless distinct compatible strings are used so
+that a distinction can be added if necessary without changing the DT
+bindings.
+
+
+Required properties:
+ - compatible: "edt,edt-ft5206"
+ or: "edt,edt-ft5306"
+ or: "edt,edt-ft5406"
+
+ - reg: I2C slave address of the chip (0x38)
+ - interrupt-parent: a phandle pointing to the interrupt controller
+ serving the interrupt for this chip
+ - interrupts: interrupt specification for the touchdetect
+ interrupt
+
+Optional properties:
+ - reset-gpios: GPIO specification for the RESET input
+ - wake-gpios: GPIO specification for the WAKE input
+
+ - pinctrl-names: should be "default"
+ - pinctrl-0: a phandle pointing to the pin settings for the
+ control gpios
+
+ - threshold: allows setting the "click"-threshold in the range
+ from 20 to 80.
+
+ - gain: allows setting the sensitivity in the range from 0 to
+ 31. Note that lower values indicate higher
+ sensitivity.
+
+ - offset: allows setting the edge compensation in the range from
+ 0 to 31.
+
+Example:
+ polytouch: edt-ft5x06@38 {
+ compatible = "edt,edt-ft5406", "edt,edt-ft5x06";
+ reg = <0x38>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&edt_ft5x06_pins>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <5 0>;
+ reset-gpios = <&gpio2 6 1>;
+ wake-gpios = <&gpio4 9 0>;
+ };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/zforce_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/zforce_ts.txt
new file mode 100644
index 000000000000..2faf1f1fa39e
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/zforce_ts.txt
@@ -0,0 +1,30 @@
+* Neonode infrared touchscreen controller
+
+Required properties:
+- compatible: must be "neonode,zforce"
+- reg: I2C address of the chip
+- interrupts: interrupt to which the chip is connected
+- gpios: gpios the chip is connected to
+ first one is the interrupt gpio and second one the reset gpio
+- x-size: horizontal resolution of touchscreen
+- y-size: vertical resolution of touchscreen
+
+Example:
+
+ i2c@00000000 {
+ /* ... */
+
+ zforce_ts@50 {
+ compatible = "neonode,zforce";
+ reg = <0x50>;
+ interrupts = <2 0>;
+
+ gpios = <&gpio5 6 0>, /* INT */
+ <&gpio5 9 0>; /* RST */
+
+ x-size = <800>;
+ y-size = <600>;
+ };
+
+ /* ... */
+ };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt
index 32cec4b26cd0..b290ca150d30 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt
@@ -2,7 +2,7 @@ Allwinner Sunxi Interrupt Controller
Required properties:
-- compatible : should be "allwinner,sun4i-ic"
+- compatible : should be "allwinner,sun4i-a10-ic"
- reg : Specifies base physical address and size of the registers.
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Specifies the number of cells needed to encode an
@@ -11,7 +11,7 @@ Required properties:
Example:
intc: interrupt-controller {
- compatible = "allwinner,sun4i-ic";
+ compatible = "allwinner,sun4i-a10-ic";
reg = <0x01c20400 0x400>;
interrupt-controller;
#interrupt-cells = <1>;
diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun67i-sc-nmi.txt b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun67i-sc-nmi.txt
new file mode 100644
index 000000000000..d1c5cdabc3e0
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun67i-sc-nmi.txt
@@ -0,0 +1,27 @@
+Allwinner Sunxi NMI Controller
+==============================
+
+Required properties:
+
+- compatible : should be "allwinner,sun7i-a20-sc-nmi" or
+ "allwinner,sun6i-a31-sc-nmi"
+- reg : Specifies base physical address and size of the registers.
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+ interrupt source. The value shall be 2. The first cell is the IRQ number, the
+ second cell the trigger type as defined in interrupt.txt in this directory.
+- interrupt-parent: Specifies the parent interrupt controller.
+- interrupts: Specifies the interrupt line (NMI) which is handled by
+ the interrupt controller in the parent controller's notation. This value
+ shall be the NMI.
+
+Example:
+
+sc-nmi-intc@01c00030 {
+ compatible = "allwinner,sun7i-a20-sc-nmi";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x01c00030 0x0c>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 0 4>;
+};
diff --git a/Documentation/devicetree/bindings/media/img-ir-rev1.txt b/Documentation/devicetree/bindings/media/img-ir-rev1.txt
new file mode 100644
index 000000000000..5434ce61b925
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/img-ir-rev1.txt
@@ -0,0 +1,34 @@
+* ImgTec Infrared (IR) decoder version 1
+
+This binding is for Imagination Technologies' Infrared decoder block,
+specifically major revision 1.
+
+Required properties:
+- compatible: Should be "img,ir-rev1"
+- reg: Physical base address of the controller and length of
+ memory mapped region.
+- interrupts: The interrupt specifier to the cpu.
+
+Optional properties:
+- clocks: List of clock specifiers as described in standard
+ clock bindings.
+ Up to 3 clocks may be specified in the following order:
+ 1st: Core clock (defaults to 32.768KHz if omitted).
+ 2nd: System side (fast) clock.
+ 3rd: Power modulation clock.
+- clock-names: List of clock names corresponding to the clocks
+ specified in the clocks property.
+ Accepted clock names are:
+ "core": Core clock.
+ "sys": System clock.
+ "mod": Power modulation clock.
+
+Example:
+
+ ir@02006200 {
+ compatible = "img,ir-rev1";
+ reg = <0x02006200 0x100>;
+ interrupts = <29 4>;
+ clocks = <&clk_32khz>;
+ clock-names = "core";
+ };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt b/Documentation/devicetree/bindings/memory-controllers/fsl/ifc.txt
index d5e370450ac0..d5e370450ac0 100644
--- a/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt
+++ b/Documentation/devicetree/bindings/memory-controllers/fsl/ifc.txt
diff --git a/Documentation/devicetree/bindings/memory-controllers/ti-aemif.txt b/Documentation/devicetree/bindings/memory-controllers/ti-aemif.txt
new file mode 100644
index 000000000000..9592717f483f
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/ti-aemif.txt
@@ -0,0 +1,210 @@
+* Device tree bindings for Texas instruments AEMIF controller
+
+The Async External Memory Interface (EMIF16/AEMIF) controller is intended to
+provide a glue-less interface to a variety of asynchronous memory devices like
+ASRA M, NOR and NAND memory. A total of 256M bytes of any of these memories
+can be accessed at any given time via four chip selects with 64M byte access
+per chip select. Synchronous memories such as DDR1 SD RAM, SDR SDRAM
+and Mobile SDR are not supported.
+
+Documentation:
+Davinci DM646x - http://www.ti.com/lit/ug/sprueq7c/sprueq7c.pdf
+OMAP-L138 (DA850) - http://www.ti.com/lit/ug/spruh77a/spruh77a.pdf
+Kestone - http://www.ti.com/lit/ug/sprugz3a/sprugz3a.pdf
+
+Required properties:
+
+- compatible: "ti,davinci-aemif"
+ "ti,keystone-aemif"
+ "ti,da850-aemif"
+
+- reg: contains offset/length value for AEMIF control registers
+ space.
+
+- #address-cells: Must be 2. The partition number has to be encoded in the
+ first address cell and it may accept values 0..N-1
+ (N - total number of partitions). It's recommended to
+ assign N-1 number for the control partition. The second
+ cell is the offset into the partition.
+
+- #size-cells: Must be set to 1.
+
+- ranges: Contains memory regions. There are two types of
+ ranges/partitions:
+ - CS-specific partition/range. If continuous, must be
+ set up to reflect the memory layout for 4 chipselects,
+ if not then additional range/partition can be added and
+ child device can select the proper one.
+ - control partition which is common for all CS
+ interfaces.
+
+- clocks: the clock feeding the controller clock. Required only
+ if clock tree data present in device tree.
+ See clock-bindings.txt
+
+- clock-names: clock name. It has to be "aemif". Required only if clock
+ tree data present in device tree, in another case don't
+ use it.
+ See clock-bindings.txt
+
+- clock-ranges: Empty property indicating that child nodes can inherit
+ named clocks. Required only if clock tree data present
+ in device tree.
+ See clock-bindings.txt
+
+
+Child chip-select (cs) nodes contain the memory devices nodes connected to
+such as NOR (e.g. cfi-flash) and NAND (ti,davinci-nand, see davinci-nand.txt).
+There might be board specific devices like FPGAs.
+
+Required child cs node properties:
+
+- #address-cells: Must be 2.
+
+- #size-cells: Must be 1.
+
+- ranges: Empty property indicating that child nodes can inherit
+ memory layout.
+
+- clock-ranges: Empty property indicating that child nodes can inherit
+ named clocks. Required only if clock tree data present
+ in device tree.
+
+- ti,cs-chipselect: number of chipselect. Indicates on the aemif driver
+ which chipselect is used for accessing the memory. For
+ compatibles "ti,davinci-aemif" and "ti,keystone-aemif"
+ it can be in range [0-3]. For compatible
+ "ti,da850-aemif" range is [2-5].
+
+Optional child cs node properties:
+
+- ti,cs-bus-width: width of the asynchronous device's data bus
+ 8 or 16 if not preset 8
+
+- ti,cs-select-strobe-mode: enable/disable select strobe mode
+ In select strobe mode chip select behaves as
+ the strobe and is active only during the strobe
+ period. If present then enable.
+
+- ti,cs-extended-wait-mode: enable/disable extended wait mode
+ if set, the controller monitors the EMIFWAIT pin
+ mapped to that chip select to determine if the
+ device wants to extend the strobe period. If
+ present then enable.
+
+- ti,cs-min-turnaround-ns: minimum turn around time, ns
+ Time between the end of one asynchronous memory
+ access and the start of another asynchronous
+ memory access. This delay is not incurred
+ between a read followed by read or a write
+ followed by a write to same chip select.
+
+- ti,cs-read-setup-ns: read setup width, ns
+ Time between the beginning of a memory cycle
+ and the activation of read strobe.
+ Minimum value is 1 (0 treated as 1).
+
+- ti,cs-read-strobe-ns: read strobe width, ns
+ Time between the activation and deactivation of
+ the read strobe.
+ Minimum value is 1 (0 treated as 1).
+
+- ti,cs-read-hold-ns: read hold width, ns
+ Time between the deactivation of the read
+ strobe and the end of the cycle (which may be
+ either an address change or the deactivation of
+ the chip select signal.
+ Minimum value is 1 (0 treated as 1).
+
+- ti,cs-write-setup-ns: write setup width, ns
+ Time between the beginning of a memory cycle
+ and the activation of write strobe.
+ Minimum value is 1 (0 treated as 1).
+
+- ti,cs-write-strobe-ns: write strobe width, ns
+ Time between the activation and deactivation of
+ the write strobe.
+ Minimum value is 1 (0 treated as 1).
+
+- ti,cs-write-hold-ns: write hold width, ns
+ Time between the deactivation of the write
+ strobe and the end of the cycle (which may be
+ either an address change or the deactivation of
+ the chip select signal.
+ Minimum value is 1 (0 treated as 1).
+
+If any of the above parameters are absent, current parameter value will be taken
+from the corresponding HW reg.
+
+Example for aemif, davinci nand and nor flash chip select shown below.
+
+memory-controller@21000A00 {
+ compatible = "ti,davinci-aemif";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ clocks = <&clkaemif 0>;
+ clock-names = "aemif";
+ clock-ranges;
+ reg = <0x21000A00 0x00000100>;
+ ranges = <0 0 0x70000000 0x10000000
+ 1 0 0x21000A00 0x00000100>;
+ /*
+ * Partition0: CS-specific memory range which is
+ * implemented as continuous physical memory region
+ * Partition1: control memory range
+ */
+
+ nand:cs2 {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ clock-ranges;
+ ranges;
+
+ ti,cs-chipselect = <2>;
+ /* all timings in nanoseconds */
+ ti,cs-min-turnaround-ns = <0>;
+ ti,cs-read-hold-ns = <7>;
+ ti,cs-read-strobe-ns = <42>;
+ ti,cs-read-setup-ns = <14>;
+ ti,cs-write-hold-ns = <7>;
+ ti,cs-write-strobe-ns = <42>;
+ ti,cs-write-setup-ns = <14>;
+
+ nand@0,0x8000000 {
+ compatible = "ti,davinci-nand";
+ reg = <0 0x8000000 0x4000000
+ 1 0x0000000 0x0000100>;
+ /*
+ * Partition0, offset 0x8000000, size 0x4000000
+ * Partition1, offset 0x0000000, size 0x0000100
+ */
+
+ .. see davinci-nand.txt
+ };
+ };
+
+ nor:cs0 {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ clock-ranges;
+ ranges;
+
+ ti,cs-chipselect = <0>;
+ /* all timings in nanoseconds */
+ ti,cs-min-turnaround-ns = <0>;
+ ti,cs-read-hold-ns = <8>;
+ ti,cs-read-strobe-ns = <40>;
+ ti,cs-read-setup-ns = <14>;
+ ti,cs-write-hold-ns = <7>;
+ ti,cs-write-strobe-ns = <40>;
+ ti,cs-write-setup-ns = <14>;
+ ti,cs-bus-width = <16>;
+
+ flash@0,0x0000000 {
+ compatible = "cfi-flash";
+ reg = <0 0x0000000 0x4000000>;
+
+ ...
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/mfd/s2mpa01.txt b/Documentation/devicetree/bindings/mfd/s2mpa01.txt
new file mode 100644
index 000000000000..c13d3d8c3947
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/s2mpa01.txt
@@ -0,0 +1,90 @@
+
+* Samsung S2MPA01 Voltage and Current Regulator
+
+The Samsung S2MPA01 is a multi-function device which includes high
+efficiency buck converters including Dual-Phase buck converter, various LDOs,
+and an RTC. It is interfaced to the host controller using an I2C interface.
+Each sub-block is addressed by the host system using different I2C slave
+addresses.
+
+Required properties:
+- compatible: Should be "samsung,s2mpa01-pmic".
+- reg: Specifies the I2C slave address of the PMIC block. It should be 0x66.
+
+Optional properties:
+- interrupt-parent: Specifies the phandle of the interrupt controller to which
+ the interrupts from s2mpa01 are delivered to.
+- interrupts: An interrupt specifier for the sole interrupt generated by the
+ device.
+
+Optional nodes:
+- regulators: The regulators of s2mpa01 that have to be instantiated should be
+ included in a sub-node named 'regulators'. Regulator nodes and constraints
+ included in this sub-node use the standard regulator bindings which are
+ documented elsewhere.
+
+Properties for BUCK regulator nodes:
+- regulator-ramp-delay: ramp delay in uV/us. May be 6250, 12500
+ (default), 25000, or 50000. May be 0 for disabling the ramp delay on
+ BUCK{1,2,3,4}.
+
+ In the absence of the regulator-ramp-delay property, the default ramp
+ delay will be used.
+
+ NOTE: Some BUCKs share the ramp rate setting i.e. same ramp value will be set
+ for a particular group of BUCKs. So provide same regulator-ramp-delay=<value>.
+
+ The following BUCKs share ramp settings:
+ * 1 and 6
+ * 2 and 4
+ * 8, 9, and 10
+
+The following are the names of the regulators that the s2mpa01 PMIC block
+supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number
+as per the datasheet of s2mpa01.
+
+ - LDOn
+ - valid values for n are 1 to 26
+ - Example: LDO1, LD02, LDO26
+ - BUCKn
+ - valid values for n are 1 to 10.
+ - Example: BUCK1, BUCK2, BUCK9
+
+Example:
+
+ s2mpa01_pmic@66 {
+ compatible = "samsung,s2mpa01-pmic";
+ reg = <0x66>;
+
+ regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "VDD_ALIVE";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ ldo2_reg: LDO2 {
+ regulator-name = "VDDQ_MMC2";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "vdd_mif";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-ramp-delay = <50000>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/mfd/s2mps11.txt b/Documentation/devicetree/bindings/mfd/s2mps11.txt
index 15ee89c3cc7b..f69bec294f02 100644
--- a/Documentation/devicetree/bindings/mfd/s2mps11.txt
+++ b/Documentation/devicetree/bindings/mfd/s2mps11.txt
@@ -1,5 +1,5 @@
-* Samsung S2MPS11 Voltage and Current Regulator
+* Samsung S2MPS11 and S2MPS14 Voltage and Current Regulator
The Samsung S2MPS11 is a multi-function device which includes voltage and
current regulators, RTC, charger controller and other sub-blocks. It is
@@ -7,7 +7,7 @@ interfaced to the host controller using an I2C interface. Each sub-block is
addressed by the host system using different I2C slave addresses.
Required properties:
-- compatible: Should be "samsung,s2mps11-pmic".
+- compatible: Should be "samsung,s2mps11-pmic" or "samsung,s2mps14-pmic".
- reg: Specifies the I2C slave address of the pmic block. It should be 0x66.
Optional properties:
@@ -59,10 +59,14 @@ supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number
as per the datasheet of s2mps11.
- LDOn
- - valid values for n are 1 to 38
+ - valid values for n are:
+ - S2MPS11: 1 to 38
+ - S2MPS14: 1 to 25
- Example: LDO1, LD02, LDO28
- BUCKn
- - valid values for n are 1 to 10.
+ - valid values for n are:
+ - S2MPS11: 1 to 10
+ - S2MPS14: 1 to 5
- Example: BUCK1, BUCK2, BUCK9
Example:
diff --git a/Documentation/devicetree/bindings/mfd/tps65910.txt b/Documentation/devicetree/bindings/mfd/tps65910.txt
index b4bd98af1cc7..38833e63a59f 100644
--- a/Documentation/devicetree/bindings/mfd/tps65910.txt
+++ b/Documentation/devicetree/bindings/mfd/tps65910.txt
@@ -11,7 +11,7 @@ Required properties:
- #interrupt-cells: the number of cells to describe an IRQ, this should be 2.
The first cell is the IRQ number.
The second cell is the flags, encoded as the trigger masks from
- Documentation/devicetree/bindings/interrupts.txt
+ Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
- regulators: This is the list of child nodes that specify the regulator
initialization data for defined regulators. Not all regulators for the given
device need to be present. The definition for each of these nodes is defined
diff --git a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
index 68ba37295565..fabdf64a5737 100644
--- a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
+++ b/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
@@ -1,12 +1,12 @@
Allwinner sunxi-sid
Required properties:
-- compatible: "allwinner,sun4i-sid" or "allwinner,sun7i-a20-sid".
+- compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid"
- reg: Should contain registers location and length
Example for sun4i:
sid@01c23800 {
- compatible = "allwinner,sun4i-sid";
+ compatible = "allwinner,sun4i-a10-sid";
reg = <0x01c23800 0x10>
};
diff --git a/Documentation/devicetree/bindings/misc/atmel-ssc.txt b/Documentation/devicetree/bindings/misc/atmel-ssc.txt
index 60960b2755f4..efc98ea1f23d 100644
--- a/Documentation/devicetree/bindings/misc/atmel-ssc.txt
+++ b/Documentation/devicetree/bindings/misc/atmel-ssc.txt
@@ -17,6 +17,14 @@ Required properties for devices compatible with "atmel,at91sam9g45-ssc":
See Documentation/devicetree/bindings/dma/atmel-dma.txt for details.
- dma-names: Must be "tx", "rx".
+Optional properties:
+ - atmel,clk-from-rk-pin: bool property.
+ - When SSC works in slave mode, according to the hardware design, the
+ clock can get from TK pin, and also can get from RK pin. So, add
+ this parameter to choose where the clock from.
+ - By default the clock is from TK pin, if the clock from RK pin, this
+ property is needed.
+
Examples:
- PDC transfer:
ssc0: ssc@fffbc000 {
diff --git a/Documentation/devicetree/bindings/misc/sram.txt b/Documentation/devicetree/bindings/misc/sram.txt
index 4d0a00e453a8..36cbe5aea990 100644
--- a/Documentation/devicetree/bindings/misc/sram.txt
+++ b/Documentation/devicetree/bindings/misc/sram.txt
@@ -8,9 +8,44 @@ Required properties:
- reg : SRAM iomem address range
+Reserving sram areas:
+---------------------
+
+Each child of the sram node specifies a region of reserved memory. Each
+child node should use a 'reg' property to specify a specific range of
+reserved memory.
+
+Following the generic-names recommended practice, node names should
+reflect the purpose of the node. Unit address (@<address>) should be
+appended to the name.
+
+Required properties in the sram node:
+
+- #address-cells, #size-cells : should use the same values as the root node
+- ranges : standard definition, should translate from local addresses
+ within the sram to bus addresses
+
+Required properties in the area nodes:
+
+- reg : iomem address range, relative to the SRAM range
+
+Optional properties in the area nodes:
+
+- compatible : standard definition, should contain a vendor specific string
+ in the form <vendor>,[<device>-]<usage>
+
Example:
sram: sram@5c000000 {
compatible = "mmio-sram";
reg = <0x5c000000 0x40000>; /* 256 KiB SRAM at address 0x5c000000 */
+
+ #adress-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x5c000000 0x40000>;
+
+ smp-sram@100 {
+ compatible = "socvendor,smp-sram";
+ reg = <0x100 0x50>;
+ };
};
diff --git a/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
index 0a85c70cd30a..07ad02075a93 100644
--- a/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
+++ b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
@@ -13,6 +13,9 @@ Required properties:
- #address-cells: should be one. The cell is the slot id.
- #size-cells: should be zero.
- at least one slot node
+- clock-names: tuple listing input clock names.
+ Required elements: "mci_clk"
+- clocks: phandles to input clocks.
The node contains child nodes for each slot that the platform uses
@@ -24,6 +27,8 @@ mmc0: mmc@f0008000 {
interrupts = <12 4>;
#address-cells = <1>;
#size-cells = <0>;
+ clock-names = "mci_clk";
+ clocks = <&mci0_clk>;
[ child node definitions...]
};
diff --git a/Documentation/devicetree/bindings/net/allwinner,sun4i-emac.txt b/Documentation/devicetree/bindings/net/allwinner,sun4i-emac.txt
index b90bfcd138ff..10640b17c866 100644
--- a/Documentation/devicetree/bindings/net/allwinner,sun4i-emac.txt
+++ b/Documentation/devicetree/bindings/net/allwinner,sun4i-emac.txt
@@ -1,20 +1,17 @@
* Allwinner EMAC ethernet controller
Required properties:
-- compatible: should be "allwinner,sun4i-emac".
+- compatible: should be "allwinner,sun4i-a10-emac" (Deprecated:
+ "allwinner,sun4i-emac")
- reg: address and length of the register set for the device.
- interrupts: interrupt for the device
-- phy: A phandle to a phy node defining the PHY address (as the reg
- property, a single integer).
+- phy: see ethernet.txt file in the same directory.
- clocks: A phandle to the reference clock for this device
-Optional properties:
-- (local-)mac-address: mac address to be used by this driver
-
Example:
emac: ethernet@01c0b000 {
- compatible = "allwinner,sun4i-emac";
+ compatible = "allwinner,sun4i-a10-emac";
reg = <0x01c0b000 0x1000>;
interrupts = <55>;
clocks = <&ahb_gates 17>;
diff --git a/Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt b/Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt
index 00b9f9a3ec1d..4ec56413779d 100644
--- a/Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt
+++ b/Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt
@@ -1,7 +1,8 @@
* Allwinner A10 MDIO Ethernet Controller interface
Required properties:
-- compatible: should be "allwinner,sun4i-mdio".
+- compatible: should be "allwinner,sun4i-a10-mdio"
+ (Deprecated: "allwinner,sun4i-mdio").
- reg: address and length of the register set for the device.
Optional properties:
@@ -9,7 +10,7 @@ Optional properties:
Example at the SoC level:
mdio@01c0b080 {
- compatible = "allwinner,sun4i-mdio";
+ compatible = "allwinner,sun4i-a10-mdio";
reg = <0x01c0b080 0x14>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/Documentation/devicetree/bindings/net/altera_tse.txt b/Documentation/devicetree/bindings/net/altera_tse.txt
new file mode 100644
index 000000000000..a706297998e9
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/altera_tse.txt
@@ -0,0 +1,114 @@
+* Altera Triple-Speed Ethernet MAC driver (TSE)
+
+Required properties:
+- compatible: Should be "altr,tse-1.0" for legacy SGDMA based TSE, and should
+ be "altr,tse-msgdma-1.0" for the preferred MSGDMA based TSE.
+ ALTR is supported for legacy device trees, but is deprecated.
+ altr should be used for all new designs.
+- reg: Address and length of the register set for the device. It contains
+ the information of registers in the same order as described by reg-names
+- reg-names: Should contain the reg names
+ "control_port": MAC configuration space region
+ "tx_csr": xDMA Tx dispatcher control and status space region
+ "tx_desc": MSGDMA Tx dispatcher descriptor space region
+ "rx_csr" : xDMA Rx dispatcher control and status space region
+ "rx_desc": MSGDMA Rx dispatcher descriptor space region
+ "rx_resp": MSGDMA Rx dispatcher response space region
+ "s1": SGDMA descriptor memory
+- interrupts: Should contain the TSE interrupts and it's mode.
+- interrupt-names: Should contain the interrupt names
+ "rx_irq": xDMA Rx dispatcher interrupt
+ "tx_irq": xDMA Tx dispatcher interrupt
+- rx-fifo-depth: MAC receive FIFO buffer depth in bytes
+- tx-fifo-depth: MAC transmit FIFO buffer depth in bytes
+- phy-mode: See ethernet.txt in the same directory.
+- phy-handle: See ethernet.txt in the same directory.
+- phy-addr: See ethernet.txt in the same directory. A configuration should
+ include phy-handle or phy-addr.
+- altr,has-supplementary-unicast:
+ If present, TSE supports additional unicast addresses.
+ Otherwise additional unicast addresses are not supported.
+- altr,has-hash-multicast-filter:
+ If present, TSE supports a hash based multicast filter.
+ Otherwise, hash-based multicast filtering is not supported.
+
+- mdio device tree subnode: When the TSE has a phy connected to its local
+ mdio, there must be device tree subnode with the following
+ required properties:
+
+ - compatible: Must be "altr,tse-mdio".
+ - #address-cells: Must be <1>.
+ - #size-cells: Must be <0>.
+
+ For each phy on the mdio bus, there must be a node with the following
+ fields:
+
+ - reg: phy id used to communicate to phy.
+ - device_type: Must be "ethernet-phy".
+
+Optional properties:
+- local-mac-address: See ethernet.txt in the same directory.
+- max-frame-size: See ethernet.txt in the same directory.
+
+Example:
+
+ tse_sub_0_eth_tse_0: ethernet@0x1,00000000 {
+ compatible = "altr,tse-msgdma-1.0";
+ reg = <0x00000001 0x00000000 0x00000400>,
+ <0x00000001 0x00000460 0x00000020>,
+ <0x00000001 0x00000480 0x00000020>,
+ <0x00000001 0x000004A0 0x00000008>,
+ <0x00000001 0x00000400 0x00000020>,
+ <0x00000001 0x00000420 0x00000020>;
+ reg-names = "control_port", "rx_csr", "rx_desc", "rx_resp", "tx_csr", "tx_desc";
+ interrupt-parent = <&hps_0_arm_gic_0>;
+ interrupts = <0 41 4>, <0 40 4>;
+ interrupt-names = "rx_irq", "tx_irq";
+ rx-fifo-depth = <2048>;
+ tx-fifo-depth = <2048>;
+ address-bits = <48>;
+ max-frame-size = <1500>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ phy-mode = "gmii";
+ altr,has-supplementary-unicast;
+ altr,has-hash-multicast-filter;
+ phy-handle = <&phy0>;
+ mdio {
+ compatible = "altr,tse-mdio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ phy0: ethernet-phy@0 {
+ reg = <0x0>;
+ device_type = "ethernet-phy";
+ };
+
+ phy1: ethernet-phy@1 {
+ reg = <0x1>;
+ device_type = "ethernet-phy";
+ };
+
+ };
+ };
+
+ tse_sub_1_eth_tse_0: ethernet@0x1,00001000 {
+ compatible = "altr,tse-msgdma-1.0";
+ reg = <0x00000001 0x00001000 0x00000400>,
+ <0x00000001 0x00001460 0x00000020>,
+ <0x00000001 0x00001480 0x00000020>,
+ <0x00000001 0x000014A0 0x00000008>,
+ <0x00000001 0x00001400 0x00000020>,
+ <0x00000001 0x00001420 0x00000020>;
+ reg-names = "control_port", "rx_csr", "rx_desc", "rx_resp", "tx_csr", "tx_desc";
+ interrupt-parent = <&hps_0_arm_gic_0>;
+ interrupts = <0 43 4>, <0 42 4>;
+ interrupt-names = "rx_irq", "tx_irq";
+ rx-fifo-depth = <2048>;
+ tx-fifo-depth = <2048>;
+ address-bits = <48>;
+ max-frame-size = <1500>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ phy-mode = "gmii";
+ altr,has-supplementary-unicast;
+ altr,has-hash-multicast-filter;
+ phy-handle = <&phy1>;
+ };
diff --git a/Documentation/devicetree/bindings/net/arc_emac.txt b/Documentation/devicetree/bindings/net/arc_emac.txt
index bcbc3f009158..7fbb027218a1 100644
--- a/Documentation/devicetree/bindings/net/arc_emac.txt
+++ b/Documentation/devicetree/bindings/net/arc_emac.txt
@@ -6,19 +6,12 @@ Required properties:
- interrupts: Should contain the EMAC interrupts
- clock-frequency: CPU frequency. It is needed to calculate and set polling
period of EMAC.
-- max-speed: Maximum supported data-rate in Mbit/s. In some HW configurations
-bandwidth of external memory controller might be a limiting factor. That's why
-it's required to specify which data-rate is supported on current SoC or FPGA.
-For example if only 10 Mbit/s is supported (10BASE-T) set "10". If 100 Mbit/s is
-supported (100BASE-TX) set "100".
-- phy: PHY device attached to the EMAC via MDIO bus
+- max-speed: see ethernet.txt file in the same directory.
+- phy: see ethernet.txt file in the same directory.
Child nodes of the driver are the individual PHY devices connected to the
MDIO bus. They must have a "reg" property given the PHY address on the MDIO bus.
-Optional properties:
-- mac-address: 6 bytes, mac address
-
Examples:
ethernet@c0fc2000 {
diff --git a/Documentation/devicetree/bindings/net/broadcom-bcmgenet.txt b/Documentation/devicetree/bindings/net/broadcom-bcmgenet.txt
new file mode 100644
index 000000000000..f2febb94550e
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/broadcom-bcmgenet.txt
@@ -0,0 +1,121 @@
+* Broadcom BCM7xxx Ethernet Controller (GENET)
+
+Required properties:
+- compatible: should contain one of "brcm,genet-v1", "brcm,genet-v2",
+ "brcm,genet-v3", "brcm,genet-v4".
+- reg: address and length of the register set for the device
+- interrupts: must be two cells, the first cell is the general purpose
+ interrupt line, while the second cell is the interrupt for the ring
+ RX and TX queues operating in ring mode
+- phy-mode: see ethernet.txt file in the same directory
+- #address-cells: should be 1
+- #size-cells: should be 1
+
+Optional properties:
+- clocks: When provided, must be two phandles to the functional clocks nodes
+ of the GENET block. The first phandle is the main GENET clock used during
+ normal operation, while the second phandle is the Wake-on-LAN clock.
+- clock-names: When provided, names of the functional clock phandles, first
+ name should be "enet" and second should be "enet-wol".
+
+- phy-handle: See ethernet.txt file in the same directory; used to describe
+ configurations where a PHY (internal or external) is used.
+
+- fixed-link: When the GENET interface is connected to a MoCA hardware block or
+ when operating in a RGMII to RGMII type of connection, or when the MDIO bus is
+ voluntarily disabled, this property should be used to describe the "fixed link".
+ See Documentation/devicetree/bindings/net/fsl-tsec-phy.txt for information on
+ the property specifics
+
+Required child nodes:
+
+- mdio bus node: this node should always be present regarless of the PHY
+ configuration of the GENET instance
+
+MDIO bus node required properties:
+
+- compatible: should contain one of "brcm,genet-mdio-v1", "brcm,genet-mdio-v2"
+ "brcm,genet-mdio-v3", "brcm,genet-mdio-v4", the version has to match the
+ parent node compatible property (e.g: brcm,genet-v4 pairs with
+ brcm,genet-mdio-v4)
+- reg: address and length relative to the parent node base register address
+- #address-cells: address cell for MDIO bus addressing, should be 1
+- #size-cells: size of the cells for MDIO bus addressing, should be 0
+
+Ethernet PHY node properties:
+
+See Documentation/devicetree/bindings/net/phy.txt for the list of required and
+optional properties.
+
+Internal Gigabit PHY example:
+
+ethernet@f0b60000 {
+ phy-mode = "internal";
+ phy-handle = <&phy1>;
+ mac-address = [ 00 10 18 36 23 1a ];
+ compatible = "brcm,genet-v4";
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ reg = <0xf0b60000 0xfc4c>;
+ interrupts = <0x0 0x14 0x0>, <0x0 0x15 0x0>;
+
+ mdio@e14 {
+ compatible = "brcm,genet-mdio-v4";
+ #address-cells = <0x1>;
+ #size-cells = <0x0>;
+ reg = <0xe14 0x8>;
+
+ phy1: ethernet-phy@1 {
+ max-speed = <1000>;
+ reg = <0x1>;
+ compatible = "brcm,28nm-gphy", "ethernet-phy-ieee802.3-c22";
+ };
+ };
+};
+
+MoCA interface / MAC to MAC example:
+
+ethernet@f0b80000 {
+ phy-mode = "moca";
+ fixed-link = <1 0 1000 0 0>;
+ mac-address = [ 00 10 18 36 24 1a ];
+ compatible = "brcm,genet-v4";
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ reg = <0xf0b80000 0xfc4c>;
+ interrupts = <0x0 0x16 0x0>, <0x0 0x17 0x0>;
+
+ mdio@e14 {
+ compatible = "brcm,genet-mdio-v4";
+ #address-cells = <0x1>;
+ #size-cells = <0x0>;
+ reg = <0xe14 0x8>;
+ };
+};
+
+
+External MDIO-connected Gigabit PHY/switch:
+
+ethernet@f0ba0000 {
+ phy-mode = "rgmii";
+ phy-handle = <&phy0>;
+ mac-address = [ 00 10 18 36 26 1a ];
+ compatible = "brcm,genet-v4";
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ reg = <0xf0ba0000 0xfc4c>;
+ interrupts = <0x0 0x18 0x0>, <0x0 0x19 0x0>;
+
+ mdio@0e14 {
+ compatible = "brcm,genet-mdio-v4";
+ #address-cells = <0x1>;
+ #size-cells = <0x0>;
+ reg = <0xe14 0x8>;
+
+ phy0: ethernet-phy@0 {
+ max-speed = <1000>;
+ reg = <0x0>;
+ compatible = "brcm,bcm53125", "ethernet-phy-ieee802.3-c22";
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/net/can/sja1000.txt b/Documentation/devicetree/bindings/net/can/sja1000.txt
index f2105a47ec87..b4a6d53fb01a 100644
--- a/Documentation/devicetree/bindings/net/can/sja1000.txt
+++ b/Documentation/devicetree/bindings/net/can/sja1000.txt
@@ -12,6 +12,10 @@ Required properties:
Optional properties:
+- reg-io-width : Specify the size (in bytes) of the IO accesses that
+ should be performed on the device. Valid value is 1, 2 or 4.
+ Default to 1 (8 bits).
+
- nxp,external-clock-frequency : Frequency of the external oscillator
clock in Hz. Note that the internal clock frequency used by the
SJA1000 is half of that value. If not specified, a default value
diff --git a/Documentation/devicetree/bindings/net/cavium-mix.txt b/Documentation/devicetree/bindings/net/cavium-mix.txt
index 5da628db68bf..8d7c3096390f 100644
--- a/Documentation/devicetree/bindings/net/cavium-mix.txt
+++ b/Documentation/devicetree/bindings/net/cavium-mix.txt
@@ -18,12 +18,7 @@ Properties:
- interrupts: Two interrupt specifiers. The first is the MIX
interrupt routing and the second the routing for the AGL interrupts.
-- mac-address: Optional, the MAC address to assign to the device.
-
-- local-mac-address: Optional, the MAC address to assign to the device
- if mac-address is not specified.
-
-- phy-handle: Optional, a phandle for the PHY device connected to this device.
+- phy-handle: Optional, see ethernet.txt file in the same directory.
Example:
ethernet@1070000100800 {
diff --git a/Documentation/devicetree/bindings/net/cavium-pip.txt b/Documentation/devicetree/bindings/net/cavium-pip.txt
index d4c53ba04b3b..7dbd158810d2 100644
--- a/Documentation/devicetree/bindings/net/cavium-pip.txt
+++ b/Documentation/devicetree/bindings/net/cavium-pip.txt
@@ -35,12 +35,7 @@ Properties for PIP port which is a child the PIP interface:
- reg: The port number within the interface group.
-- mac-address: Optional, the MAC address to assign to the device.
-
-- local-mac-address: Optional, the MAC address to assign to the device
- if mac-address is not specified.
-
-- phy-handle: Optional, a phandle for the PHY device connected to this device.
+- phy-handle: Optional, see ethernet.txt file in the same directory.
Example:
diff --git a/Documentation/devicetree/bindings/net/cdns-emac.txt b/Documentation/devicetree/bindings/net/cdns-emac.txt
index 09055c2495f0..abd67c13d344 100644
--- a/Documentation/devicetree/bindings/net/cdns-emac.txt
+++ b/Documentation/devicetree/bindings/net/cdns-emac.txt
@@ -6,11 +6,7 @@ Required properties:
or the generic form: "cdns,emac".
- reg: Address and length of the register set for the device
- interrupts: Should contain macb interrupt
-- phy-mode: String, operation mode of the PHY interface.
- Supported values are: "mii", "rmii".
-
-Optional properties:
-- local-mac-address: 6 bytes, mac address
+- phy-mode: see ethernet.txt file in the same directory.
Examples:
diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
index 05d660e4ac64..ae2b8b7f9c38 100644
--- a/Documentation/devicetree/bindings/net/cpsw.txt
+++ b/Documentation/devicetree/bindings/net/cpsw.txt
@@ -28,9 +28,8 @@ Optional properties:
Slave Properties:
Required properties:
- phy_id : Specifies slave phy id
-- phy-mode : The interface between the SoC and the PHY (a string
- that of_get_phy_mode() can understand)
-- mac-address : Specifies slave MAC address
+- phy-mode : See ethernet.txt file in the same directory
+- mac-address : See ethernet.txt file in the same directory
Optional properties:
- dual_emac_res_vlan : Specifies VID to be used to segregate the ports
diff --git a/Documentation/devicetree/bindings/net/davicom-dm9000.txt b/Documentation/devicetree/bindings/net/davicom-dm9000.txt
index 2d39c990e641..28767ed7c1bd 100644
--- a/Documentation/devicetree/bindings/net/davicom-dm9000.txt
+++ b/Documentation/devicetree/bindings/net/davicom-dm9000.txt
@@ -9,8 +9,6 @@ Required properties:
- interrupts : interrupt specifier specific to interrupt controller
Optional properties:
-- local-mac-address : A bytestring of 6 bytes specifying Ethernet MAC address
- to use (from firmware or bootloader)
- davicom,no-eeprom : Configuration EEPROM is not available
- davicom,ext-phy : Use external PHY
diff --git a/Documentation/devicetree/bindings/net/davinci_emac.txt b/Documentation/devicetree/bindings/net/davinci_emac.txt
index 6e356d15154a..032808843f90 100644
--- a/Documentation/devicetree/bindings/net/davinci_emac.txt
+++ b/Documentation/devicetree/bindings/net/davinci_emac.txt
@@ -17,9 +17,8 @@ Required properties:
Miscellaneous Interrupt>
Optional properties:
-- phy-handle: Contains a phandle to an Ethernet PHY.
+- phy-handle: See ethernet.txt file in the same directory.
If absent, davinci_emac driver defaults to 100/FULL.
-- local-mac-address : 6 bytes, mac address
- ti,davinci-rmii-en: 1 byte, 1 means use RMII
- ti,davinci-no-bd-ram: boolean, does EMAC have BD RAM?
diff --git a/Documentation/devicetree/bindings/net/ethernet.txt b/Documentation/devicetree/bindings/net/ethernet.txt
new file mode 100644
index 000000000000..9ecd43d8792c
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/ethernet.txt
@@ -0,0 +1,25 @@
+The following properties are common to the Ethernet controllers:
+
+- local-mac-address: array of 6 bytes, specifies the MAC address that was
+ assigned to the network device;
+- mac-address: array of 6 bytes, specifies the MAC address that was last used by
+ the boot program; should be used in cases where the MAC address assigned to
+ the device by the boot program is different from the "local-mac-address"
+ property;
+- max-speed: number, specifies maximum speed in Mbit/s supported by the device;
+- max-frame-size: number, maximum transfer unit (IEEE defined MTU), rather than
+ the maximum frame size (there's contradiction in ePAPR).
+- phy-mode: string, operation mode of the PHY interface; supported values are
+ "mii", "gmii", "sgmii", "tbi", "rev-mii", "rmii", "rgmii", "rgmii-id",
+ "rgmii-rxid", "rgmii-txid", "rtbi", "smii", "xgmii"; this is now a de-facto
+ standard property;
+- phy-connection-type: the same as "phy-mode" property but described in ePAPR;
+- phy-handle: phandle, specifies a reference to a node representing a PHY
+ device; this property is described in ePAPR and so preferred;
+- phy: the same as "phy-handle" property, not recommended for new bindings.
+- phy-device: the same as "phy-handle" property, not recommended for new
+ bindings.
+
+Child nodes of the Ethernet controller are typically the individual PHY devices
+connected via the MDIO bus (sometimes the MDIO bus controller is separate).
+They are described in the phy.txt file in this same directory.
diff --git a/Documentation/devicetree/bindings/net/fsl-fec.txt b/Documentation/devicetree/bindings/net/fsl-fec.txt
index 845ff848d895..6bc84adb10c0 100644
--- a/Documentation/devicetree/bindings/net/fsl-fec.txt
+++ b/Documentation/devicetree/bindings/net/fsl-fec.txt
@@ -4,12 +4,9 @@ Required properties:
- compatible : Should be "fsl,<soc>-fec"
- reg : Address and length of the register set for the device
- interrupts : Should contain fec interrupt
-- phy-mode : String, operation mode of the PHY interface.
- Supported values are: "mii", "gmii", "sgmii", "tbi", "rmii",
- "rgmii", "rgmii-id", "rgmii-rxid", "rgmii-txid", "rtbi", "smii".
+- phy-mode : See ethernet.txt file in the same directory
Optional properties:
-- local-mac-address : 6 bytes, mac address
- phy-reset-gpios : Should specify the gpio for phy reset
- phy-reset-duration : Reset duration in milliseconds. Should present
only if property "phy-reset-gpios" is available. Missing the property
diff --git a/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt b/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
index d2ea4605d078..737cdef4f903 100644
--- a/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
+++ b/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
@@ -38,22 +38,17 @@ Properties:
- model : Model of the device. Can be "TSEC", "eTSEC", or "FEC"
- compatible : Should be "gianfar"
- reg : Offset and length of the register set for the device
- - local-mac-address : List of bytes representing the ethernet address of
- this controller
- interrupts : For FEC devices, the first interrupt is the device's
interrupt. For TSEC and eTSEC devices, the first interrupt is
transmit, the second is receive, and the third is error.
- - phy-handle : The phandle for the PHY connected to this ethernet
- controller.
+ - phy-handle : See ethernet.txt file in the same directory.
- fixed-link : <a b c d e> where a is emulated phy id - choose any,
but unique to the all specified fixed-links, b is duplex - 0 half,
1 full, c is link speed - d#10/d#100/d#1000, d is pause - 0 no
pause, 1 pause, e is asym_pause - 0 no asym_pause, 1 asym_pause.
- - phy-connection-type : a string naming the controller/PHY interface type,
- i.e., "mii" (default), "rmii", "gmii", "rgmii", "rgmii-id", "sgmii",
- "tbi", or "rtbi". This property is only really needed if the connection
- is of type "rgmii-id", as all other connection types are detected by
- hardware.
+ - phy-connection-type : See ethernet.txt file in the same directory.
+ This property is only really needed if the connection is of type
+ "rgmii-id", as all other connection types are detected by hardware.
- fsl,magic-packet : If present, indicates that the hardware supports
waking up via magic packet.
- bd-stash : If present, indicates that the hardware supports stashing
diff --git a/Documentation/devicetree/bindings/net/lpc-eth.txt b/Documentation/devicetree/bindings/net/lpc-eth.txt
index 585021acd178..b92e927808b6 100644
--- a/Documentation/devicetree/bindings/net/lpc-eth.txt
+++ b/Documentation/devicetree/bindings/net/lpc-eth.txt
@@ -6,10 +6,9 @@ Required properties:
- interrupts: Should contain ethernet controller interrupt
Optional properties:
-- phy-mode: String, operation mode of the PHY interface.
- Supported values are: "mii", "rmii" (default)
+- phy-mode: See ethernet.txt file in the same directory. If the property is
+ absent, "rmii" is assumed.
- use-iram: Use LPC32xx internal SRAM (IRAM) for DMA buffering
-- local-mac-address : 6 bytes, mac address
Example:
diff --git a/Documentation/devicetree/bindings/net/macb.txt b/Documentation/devicetree/bindings/net/macb.txt
index 70af2ec12b09..aaa696414f57 100644
--- a/Documentation/devicetree/bindings/net/macb.txt
+++ b/Documentation/devicetree/bindings/net/macb.txt
@@ -8,16 +8,12 @@ Required properties:
the Cadence GEM, or the generic form: "cdns,gem".
- reg: Address and length of the register set for the device
- interrupts: Should contain macb interrupt
-- phy-mode: String, operation mode of the PHY interface.
- Supported values are: "mii", "rmii", "gmii", "rgmii".
+- phy-mode: See ethernet.txt file in the same directory.
- clock-names: Tuple listing input clock names.
Required elements: 'pclk', 'hclk'
Optional elements: 'tx_clk'
- clocks: Phandles to input clocks.
-Optional properties:
-- local-mac-address: 6 bytes, mac address
-
Examples:
macb0: ethernet@fffc4000 {
diff --git a/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt b/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt
index 859a6fa7569c..750d577e8083 100644
--- a/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt
+++ b/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt
@@ -4,10 +4,8 @@ Required properties:
- compatible: should be "marvell,armada-370-neta".
- reg: address and length of the register set for the device.
- interrupts: interrupt for the device
-- phy: A phandle to a phy node defining the PHY address (as the reg
- property, a single integer).
-- phy-mode: The interface between the SoC and the PHY (a string that
- of_get_phy_mode() can understand)
+- phy: See ethernet.txt file in the same directory.
+- phy-mode: See ethernet.txt file in the same directory
- clocks: a pointer to the reference clock for this device.
Example:
diff --git a/Documentation/devicetree/bindings/net/marvell-orion-net.txt b/Documentation/devicetree/bindings/net/marvell-orion-net.txt
index c233b6114242..bce52b2ec55e 100644
--- a/Documentation/devicetree/bindings/net/marvell-orion-net.txt
+++ b/Documentation/devicetree/bindings/net/marvell-orion-net.txt
@@ -36,7 +36,7 @@ Required port properties:
"marvell,kirkwood-eth-port".
- reg: port number relative to ethernet controller, shall be 0, 1, or 2.
- interrupts: port interrupt.
- - local-mac-address: 6 bytes MAC address.
+ - local-mac-address: See ethernet.txt file in the same directory.
Optional port properties:
- marvell,tx-queue-size: size of the transmit ring buffer.
@@ -48,7 +48,7 @@ Optional port properties:
and
- - phy-handle: phandle reference to ethernet PHY.
+ - phy-handle: See ethernet.txt file in the same directory.
or
diff --git a/Documentation/devicetree/bindings/net/micrel-ks8851.txt b/Documentation/devicetree/bindings/net/micrel-ks8851.txt
index 11ace3c3d805..d54d0cc79487 100644
--- a/Documentation/devicetree/bindings/net/micrel-ks8851.txt
+++ b/Documentation/devicetree/bindings/net/micrel-ks8851.txt
@@ -6,4 +6,4 @@ Required properties:
- interrupts : interrupt connection
Optional properties:
-- local-mac-address : Ethernet mac address to use
+- vdd-supply: supply for Ethernet mac
diff --git a/Documentation/devicetree/bindings/net/micrel.txt b/Documentation/devicetree/bindings/net/micrel.txt
new file mode 100644
index 000000000000..98a3e61f9ee8
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/micrel.txt
@@ -0,0 +1,18 @@
+Micrel PHY properties.
+
+These properties cover the base properties Micrel PHYs.
+
+Optional properties:
+
+ - micrel,led-mode : LED mode value to set for PHYs with configurable LEDs.
+
+ Configure the LED mode with single value. The list of PHYs and
+ the bits that are currently supported:
+
+ KSZ8001: register 0x1e, bits 15..14
+ KSZ8041: register 0x1e, bits 15..14
+ KSZ8021: register 0x1f, bits 5..4
+ KSZ8031: register 0x1f, bits 5..4
+ KSZ8051: register 0x1f, bits 5..4
+
+ See the respective PHY datasheet for the mode values.
diff --git a/Documentation/devicetree/bindings/net/nfc/trf7970a.txt b/Documentation/devicetree/bindings/net/nfc/trf7970a.txt
new file mode 100644
index 000000000000..8dd3ef7bc56b
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/nfc/trf7970a.txt
@@ -0,0 +1,34 @@
+* Texas Instruments TRF7970A RFID/NFC/15693 Transceiver
+
+Required properties:
+- compatible: Should be "ti,trf7970a".
+- spi-max-frequency: Maximum SPI frequency (<= 2000000).
+- interrupt-parent: phandle of parent interrupt handler.
+- interrupts: A single interrupt specifier.
+- ti,enable-gpios: Two GPIO entries used for 'EN' and 'EN2' pins on the
+ TRF7970A.
+- vin-supply: Regulator for supply voltage to VIN pin
+
+Optional SoC Specific Properties:
+- pinctrl-names: Contains only one value - "default".
+- pintctrl-0: Specifies the pin control groups used for this controller.
+
+Example (for ARM-based BeagleBone with TRF7970A on SPI1):
+
+&spi1 {
+ status = "okay";
+
+ nfc@0 {
+ compatible = "ti,trf7970a";
+ reg = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&trf7970a_default>;
+ spi-max-frequency = <2000000>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <14 0>;
+ ti,enable-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>,
+ <&gpio2 5 GPIO_ACTIVE_LOW>;
+ vin-supply = <&ldo3_reg>;
+ status = "okay";
+ };
+};
diff --git a/Documentation/devicetree/bindings/net/opencores-ethoc.txt b/Documentation/devicetree/bindings/net/opencores-ethoc.txt
new file mode 100644
index 000000000000..2dc127c30d9b
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/opencores-ethoc.txt
@@ -0,0 +1,22 @@
+* OpenCores MAC 10/100 Mbps
+
+Required properties:
+- compatible: Should be "opencores,ethoc".
+- reg: two memory regions (address and length),
+ first region is for the device registers and descriptor rings,
+ second is for the device packet memory.
+- interrupts: interrupt for the device.
+
+Optional properties:
+- clocks: phandle to refer to the clk used as per
+ Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Examples:
+
+ enet0: ethoc@fd030000 {
+ compatible = "opencores,ethoc";
+ reg = <0xfd030000 0x4000 0xfd800000 0x4000>;
+ interrupts = <1>;
+ local-mac-address = [00 50 c2 13 6f 00];
+ clocks = <&osc>;
+ };
diff --git a/Documentation/devicetree/bindings/net/phy.txt b/Documentation/devicetree/bindings/net/phy.txt
index 58307d0931c8..5b8c58903077 100644
--- a/Documentation/devicetree/bindings/net/phy.txt
+++ b/Documentation/devicetree/bindings/net/phy.txt
@@ -21,10 +21,18 @@ Optional Properties:
elements.
- max-speed: Maximum PHY supported speed (10, 100, 1000...)
+ If the phy's identifier is known then the list may contain an entry
+ of the form: "ethernet-phy-idAAAA.BBBB" where
+ AAAA - The value of the 16 bit Phy Identifier 1 register as
+ 4 hex digits. This is the chip vendor OUI bits 3:18
+ BBBB - The value of the 16 bit Phy Identifier 2 register as
+ 4 hex digits. This is the chip vendor OUI bits 19:24,
+ followed by 10 bits of a vendor specific ID.
+
Example:
ethernet-phy@0 {
- compatible = "ethernet-phy-ieee802.3-c22";
+ compatible = "ethernet-phy-id0141.0e90", "ethernet-phy-ieee802.3-c22";
interrupt-parent = <40000>;
interrupts = <35 1>;
reg = <0>;
diff --git a/Documentation/devicetree/bindings/net/samsung-sxgbe.txt b/Documentation/devicetree/bindings/net/samsung-sxgbe.txt
new file mode 100644
index 000000000000..989f6c95cfd5
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/samsung-sxgbe.txt
@@ -0,0 +1,52 @@
+* Samsung 10G Ethernet driver (SXGBE)
+
+Required properties:
+- compatible: Should be "samsung,sxgbe-v2.0a"
+- reg: Address and length of the register set for the device
+- interrupt-parent: Should be the phandle for the interrupt controller
+ that services interrupts for this device
+- interrupts: Should contain the SXGBE interrupts
+ These interrupts are ordered by fixed and follows variable
+ trasmit DMA interrupts, receive DMA interrupts and lpi interrupt.
+ index 0 - this is fixed common interrupt of SXGBE and it is always
+ available.
+ index 1 to 25 - 8 variable trasmit interrupts, variable 16 receive interrupts
+ and 1 optional lpi interrupt.
+- phy-mode: String, operation mode of the PHY interface.
+ Supported values are: "sgmii", "xgmii".
+- samsung,pbl: Integer, Programmable Burst Length.
+ Supported values are 1, 2, 4, 8, 16, or 32.
+- samsung,burst-map: Integer, Program the possible bursts supported by sxgbe
+ This is an interger and represents allowable DMA bursts when fixed burst.
+ Allowable range is 0x01-0x3F. When this field is set fixed burst is enabled.
+ When fixed length is needed for burst mode, it can be set within allowable
+ range.
+
+Optional properties:
+- mac-address: 6 bytes, mac address
+- max-frame-size: Maximum Transfer Unit (IEEE defined MTU), rather
+ than the maximum frame size.
+
+Example:
+
+ aliases {
+ ethernet0 = <&sxgbe0>;
+ };
+
+ sxgbe0: ethernet@1a040000 {
+ compatible = "samsung,sxgbe-v2.0a";
+ reg = <0 0x1a040000 0 0x10000>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 209 4>, <0 185 4>, <0 186 4>, <0 187 4>,
+ <0 188 4>, <0 189 4>, <0 190 4>, <0 191 4>,
+ <0 192 4>, <0 193 4>, <0 194 4>, <0 195 4>,
+ <0 196 4>, <0 197 4>, <0 198 4>, <0 199 4>,
+ <0 200 4>, <0 201 4>, <0 202 4>, <0 203 4>,
+ <0 204 4>, <0 205 4>, <0 206 4>, <0 207 4>,
+ <0 208 4>, <0 210 4>;
+ samsung,pbl = <0x08>
+ samsung,burst-map = <0x20>
+ mac-address = [ 00 11 22 33 44 55 ]; /* Filled in by U-Boot */
+ max-frame-size = <9000>;
+ phy-mode = "xgmii";
+ };
diff --git a/Documentation/devicetree/bindings/net/sh_eth.txt b/Documentation/devicetree/bindings/net/sh_eth.txt
new file mode 100644
index 000000000000..e7106b50dbdc
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/sh_eth.txt
@@ -0,0 +1,55 @@
+* Renesas Electronics SH EtherMAC
+
+This file provides information on what the device node for the SH EtherMAC
+interface contains.
+
+Required properties:
+- compatible: "renesas,gether-r8a7740" if the device is a part of R8A7740 SoC.
+ "renesas,ether-r8a7778" if the device is a part of R8A7778 SoC.
+ "renesas,ether-r8a7779" if the device is a part of R8A7779 SoC.
+ "renesas,ether-r8a7790" if the device is a part of R8A7790 SoC.
+ "renesas,ether-r8a7791" if the device is a part of R8A7791 SoC.
+ "renesas,ether-r7s72100" if the device is a part of R7S72100 SoC.
+- reg: offset and length of (1) the E-DMAC/feLic register block (required),
+ (2) the TSU register block (optional).
+- interrupts: interrupt specifier for the sole interrupt.
+- phy-mode: see ethernet.txt file in the same directory.
+- phy-handle: see ethernet.txt file in the same directory.
+- #address-cells: number of address cells for the MDIO bus, must be equal to 1.
+- #size-cells: number of size cells on the MDIO bus, must be equal to 0.
+- clocks: clock phandle and specifier pair.
+- pinctrl-0: phandle, referring to a default pin configuration node.
+
+Optional properties:
+- interrupt-parent: the phandle for the interrupt controller that services
+ interrupts for this device.
+- pinctrl-names: pin configuration state name ("default").
+- renesas,no-ether-link: boolean, specify when a board does not provide a proper
+ Ether LINK signal.
+- renesas,ether-link-active-low: boolean, specify when the Ether LINK signal is
+ active-low instead of normal active-high.
+
+Example (Lager board):
+
+ ethernet@ee700000 {
+ compatible = "renesas,ether-r8a7790";
+ reg = <0 0xee700000 0 0x400>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 162 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp8_clks R8A7790_CLK_ETHER>;
+ phy-mode = "rmii";
+ phy-handle = <&phy1>;
+ pinctrl-0 = <&ether_pins>;
+ pinctrl-names = "default";
+ renesas,ether-link-active-low;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ interrupt-parent = <&irqc0>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ pinctrl-0 = <&phy1_pins>;
+ pinctrl-names = "default";
+ };
+ };
diff --git a/Documentation/devicetree/bindings/net/smsc-lan91c111.txt b/Documentation/devicetree/bindings/net/smsc-lan91c111.txt
index 5a41a8658daa..0f8487b88822 100644
--- a/Documentation/devicetree/bindings/net/smsc-lan91c111.txt
+++ b/Documentation/devicetree/bindings/net/smsc-lan91c111.txt
@@ -6,8 +6,7 @@ Required properties:
- interrupts : interrupt connection
Optional properties:
-- phy-device : phandle to Ethernet phy
-- local-mac-address : Ethernet mac address to use
+- phy-device : see ethernet.txt file in the same directory
- reg-io-width : Mask of sizes (in bytes) of the IO accesses that
are supported on the device. Valid value for SMSC LAN91c111 are
1, 2 or 4. If it's omitted or invalid, the size would be 2 meaning
diff --git a/Documentation/devicetree/bindings/net/smsc911x.txt b/Documentation/devicetree/bindings/net/smsc911x.txt
index adb5b5744ecd..3fed3c124411 100644
--- a/Documentation/devicetree/bindings/net/smsc911x.txt
+++ b/Documentation/devicetree/bindings/net/smsc911x.txt
@@ -6,9 +6,7 @@ Required properties:
- interrupts : Should contain SMSC LAN interrupt line
- interrupt-parent : Should be the phandle for the interrupt controller
that services interrupts for this device
-- phy-mode : String, operation mode of the PHY interface.
- Supported values are: "mii", "gmii", "sgmii", "tbi", "rmii",
- "rgmii", "rgmii-id", "rgmii-rxid", "rgmii-txid", "rtbi", "smii".
+- phy-mode : See ethernet.txt file in the same directory
Optional properties:
- reg-shift : Specify the quantity to shift the register offsets by
@@ -23,7 +21,6 @@ Optional properties:
external PHY
- smsc,save-mac-address : Indicates that mac address needs to be saved
before resetting the controller
-- local-mac-address : 6 bytes, mac address
Examples:
diff --git a/Documentation/devicetree/bindings/net/sti-dwmac.txt b/Documentation/devicetree/bindings/net/sti-dwmac.txt
new file mode 100644
index 000000000000..3dd3d0bf112f
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/sti-dwmac.txt
@@ -0,0 +1,58 @@
+STMicroelectronics SoC DWMAC glue layer controller
+
+The device node has following properties.
+
+Required properties:
+ - compatible : Can be "st,stih415-dwmac", "st,stih416-dwmac" or
+ "st,stid127-dwmac".
+ - reg : Offset of the glue configuration register map in system
+ configuration regmap pointed by st,syscon property and size.
+
+ - reg-names : Should be "sti-ethconf".
+
+ - st,syscon : Should be phandle to system configuration node which
+ encompases this glue registers.
+
+ - st,tx-retime-src: On STi Parts for Giga bit speeds, 125Mhz clocks can be
+ wired up in from different sources. One via TXCLK pin and other via CLK_125
+ pin. This wiring is totally board dependent. However the retiming glue
+ logic should be configured accordingly. Possible values for this property
+
+ "txclk" - if 125Mhz clock is wired up via txclk line.
+ "clk_125" - if 125Mhz clock is wired up via clk_125 line.
+
+ This property is only valid for Giga bit setup( GMII, RGMII), and it is
+ un-used for non-giga bit (MII and RMII) setups. Also note that internal
+ clockgen can not generate stable 125Mhz clock.
+
+ - st,ext-phyclk: This boolean property indicates who is generating the clock
+ for tx and rx. This property is only valid for RMII case where the clock can
+ be generated from the MAC or PHY.
+
+ - clock-names: should be "sti-ethclk".
+ - clocks: Should point to ethernet clockgen which can generate phyclk.
+
+
+Example:
+
+ethernet0: dwmac@fe810000 {
+ device_type = "network";
+ compatible = "st,stih416-dwmac", "snps,dwmac", "snps,dwmac-3.710";
+ reg = <0xfe810000 0x8000>, <0x8bc 0x4>;
+ reg-names = "stmmaceth", "sti-ethconf";
+ interrupts = <0 133 0>, <0 134 0>, <0 135 0>;
+ interrupt-names = "macirq", "eth_wake_irq", "eth_lpi";
+ phy-mode = "mii";
+
+ st,syscon = <&syscfg_rear>;
+
+ snps,pbl = <32>;
+ snps,mixed-burst;
+
+ resets = <&softreset STIH416_ETH0_SOFTRESET>;
+ reset-names = "stmmaceth";
+ pinctrl-0 = <&pinctrl_mii0>;
+ pinctrl-names = "default";
+ clocks = <&CLK_S_GMAC0_PHY>;
+ clock-names = "stmmaceth";
+};
diff --git a/Documentation/devicetree/bindings/net/stmmac.txt b/Documentation/devicetree/bindings/net/stmmac.txt
index 9d92d42140f2..5748351fb9df 100644
--- a/Documentation/devicetree/bindings/net/stmmac.txt
+++ b/Documentation/devicetree/bindings/net/stmmac.txt
@@ -10,8 +10,7 @@ Required properties:
- interrupt-names: Should contain the interrupt names "macirq"
"eth_wake_irq" if this interrupt is supported in the "interrupts"
property
-- phy-mode: String, operation mode of the PHY interface.
- Supported values are: "mii", "rmii", "gmii", "rgmii".
+- phy-mode: See ethernet.txt file in the same directory.
- snps,reset-gpio gpio number for phy reset.
- snps,reset-active-low boolean flag to indicate if phy reset is active low.
- snps,reset-delays-us is triplet of delays
@@ -28,12 +27,10 @@ Required properties:
ignored if force_thresh_dma_mode is set.
Optional properties:
-- mac-address: 6 bytes, mac address
- resets: Should contain a phandle to the STMMAC reset signal, if any
- reset-names: Should contain the reset signal name "stmmaceth", if a
reset phandle is given
-- max-frame-size: Maximum Transfer Unit (IEEE defined MTU), rather
- than the maximum frame size.
+- max-frame-size: See ethernet.txt file in the same directory
Examples:
diff --git a/Documentation/devicetree/bindings/net/wireless/ti,wl1251.txt b/Documentation/devicetree/bindings/net/wireless/ti,wl1251.txt
new file mode 100644
index 000000000000..189ae5cad8f7
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/wireless/ti,wl1251.txt
@@ -0,0 +1,39 @@
+* Texas Instruments wl1251 wireless lan controller
+
+The wl1251 chip can be connected via SPI or via SDIO. This
+document describes the binding for the SPI connected chip.
+
+Required properties:
+- compatible : Should be "ti,wl1251"
+- reg : Chip select address of device
+- spi-max-frequency : Maximum SPI clocking speed of device in Hz
+- interrupts : Should contain interrupt line
+- interrupt-parent : Should be the phandle for the interrupt controller
+ that services interrupts for this device
+- vio-supply : phandle to regulator providing VIO
+- ti,power-gpio : GPIO connected to chip's PMEN pin
+
+Optional properties:
+- ti,wl1251-has-eeprom : boolean, the wl1251 has an eeprom connected, which
+ provides configuration data (calibration, MAC, ...)
+- Please consult Documentation/devicetree/bindings/spi/spi-bus.txt
+ for optional SPI connection related properties,
+
+Examples:
+
+&spi1 {
+ wl1251@0 {
+ compatible = "ti,wl1251";
+
+ reg = <0>;
+ spi-max-frequency = <48000000>;
+ spi-cpol;
+ spi-cpha;
+
+ interrupt-parent = <&gpio2>;
+ interrupts = <10 IRQ_TYPE_NONE>; /* gpio line 42 */
+
+ vio-supply = <&vio>;
+ ti,power-gpio = <&gpio3 23 GPIO_ACTIVE_HIGH>; /* 87 */
+ };
+};
diff --git a/Documentation/devicetree/bindings/phy/apm-xgene-phy.txt b/Documentation/devicetree/bindings/phy/apm-xgene-phy.txt
new file mode 100644
index 000000000000..5f3a65a9dd88
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/apm-xgene-phy.txt
@@ -0,0 +1,79 @@
+* APM X-Gene 15Gbps Multi-purpose PHY nodes
+
+PHY nodes are defined to describe on-chip 15Gbps Multi-purpose PHY. Each
+PHY (pair of lanes) has its own node.
+
+Required properties:
+- compatible : Shall be "apm,xgene-phy".
+- reg : PHY memory resource is the SDS PHY access resource.
+- #phy-cells : Shall be 1 as it expects one argument for setting
+ the mode of the PHY. Possible values are 0 (SATA),
+ 1 (SGMII), 2 (PCIe), 3 (USB), and 4 (XFI).
+
+Optional properties:
+- status : Shall be "ok" if enabled or "disabled" if disabled.
+ Default is "ok".
+- clocks : Reference to the clock entry.
+- apm,tx-eye-tuning : Manual control to fine tune the capture of the serial
+ bit lines from the automatic calibrated position.
+ Two set of 3-tuple setting for each (up to 3)
+ supported link speed on the host. Range from 0 to
+ 127 in unit of one bit period. Default is 10.
+- apm,tx-eye-direction : Eye tuning manual control direction. 0 means sample
+ data earlier than the nominal sampling point. 1 means
+ sample data later than the nominal sampling point.
+ Two set of 3-tuple setting for each (up to 3)
+ supported link speed on the host. Default is 0.
+- apm,tx-boost-gain : Frequency boost AC (LSB 3-bit) and DC (2-bit)
+ gain control. Two set of 3-tuple setting for each
+ (up to 3) supported link speed on the host. Range is
+ between 0 to 31 in unit of dB. Default is 3.
+- apm,tx-amplitude : Amplitude control. Two set of 3-tuple setting for
+ each (up to 3) supported link speed on the host.
+ Range is between 0 to 199500 in unit of uV.
+ Default is 199500 uV.
+- apm,tx-pre-cursor1 : 1st pre-cursor emphasis taps control. Two set of
+ 3-tuple setting for each (up to 3) supported link
+ speed on the host. Range is 0 to 273000 in unit of
+ uV. Default is 0.
+- apm,tx-pre-cursor2 : 2st pre-cursor emphasis taps control. Two set of
+ 3-tuple setting for each (up to 3) supported link
+ speed on the host. Range is 0 to 127400 in unit uV.
+ Default is 0x0.
+- apm,tx-post-cursor : Post-cursor emphasis taps control. Two set of
+ 3-tuple setting for Gen1, Gen2, and Gen3. Range is
+ between 0 to 0x1f in unit of 18.2mV. Default is 0xf.
+- apm,tx-speed : Tx operating speed. One set of 3-tuple for each
+ supported link speed on the host.
+ 0 = 1-2Gbps
+ 1 = 2-4Gbps (1st tuple default)
+ 2 = 4-8Gbps
+ 3 = 8-15Gbps (2nd tuple default)
+ 4 = 2.5-4Gbps
+ 5 = 4-5Gbps
+ 6 = 5-6Gbps
+ 7 = 6-16Gbps (3rd tuple default)
+
+NOTE: PHY override parameters are board specific setting.
+
+Example:
+ phy1: phy@1f21a000 {
+ compatible = "apm,xgene-phy";
+ reg = <0x0 0x1f21a000 0x0 0x100>;
+ #phy-cells = <1>;
+ status = "disabled";
+ };
+
+ phy2: phy@1f22a000 {
+ compatible = "apm,xgene-phy";
+ reg = <0x0 0x1f22a000 0x0 0x100>;
+ #phy-cells = <1>;
+ status = "ok";
+ };
+
+ phy3: phy@1f23a000 {
+ compatible = "apm,xgene-phy";
+ reg = <0x0 0x1f23a000 0x0 0x100>;
+ #phy-cells = <1>;
+ status = "ok";
+ };
diff --git a/Documentation/devicetree/bindings/phy/samsung-phy.txt b/Documentation/devicetree/bindings/phy/samsung-phy.txt
index c0fccaa1671e..28f9edb8f19c 100644
--- a/Documentation/devicetree/bindings/phy/samsung-phy.txt
+++ b/Documentation/devicetree/bindings/phy/samsung-phy.txt
@@ -20,3 +20,57 @@ Required properties:
- compatible : should be "samsung,exynos5250-dp-video-phy";
- reg : offset and length of the Display Port PHY register set;
- #phy-cells : from the generic PHY bindings, must be 0;
+
+Samsung S5P/EXYNOS SoC series USB PHY
+-------------------------------------------------
+
+Required properties:
+- compatible : should be one of the listed compatibles:
+ - "samsung,exynos4210-usb2-phy"
+ - "samsung,exynos4x12-usb2-phy"
+ - "samsung,exynos5250-usb2-phy"
+- reg : a list of registers used by phy driver
+ - first and obligatory is the location of phy modules registers
+- samsung,sysreg-phandle - handle to syscon used to control the system registers
+- samsung,pmureg-phandle - handle to syscon used to control PMU registers
+- #phy-cells : from the generic phy bindings, must be 1;
+- clocks and clock-names:
+ - the "phy" clock is required by the phy module, used as a gate
+ - the "ref" clock is used to get the rate of the clock provided to the
+ PHY module
+
+The first phandle argument in the PHY specifier identifies the PHY, its
+meaning is compatible dependent. For the currently supported SoCs (Exynos 4210
+and Exynos 4212) it is as follows:
+ 0 - USB device ("device"),
+ 1 - USB host ("host"),
+ 2 - HSIC0 ("hsic0"),
+ 3 - HSIC1 ("hsic1"),
+
+Exynos 4210 and Exynos 4212 use mode switching and require that mode switch
+register is supplied.
+
+Example:
+
+For Exynos 4412 (compatible with Exynos 4212):
+
+usbphy: phy@125b0000 {
+ compatible = "samsung,exynos4x12-usb2-phy";
+ reg = <0x125b0000 0x100>;
+ clocks = <&clock 305>, <&clock 2>;
+ clock-names = "phy", "ref";
+ status = "okay";
+ #phy-cells = <1>;
+ samsung,sysreg-phandle = <&sys_reg>;
+ samsung,pmureg-phandle = <&pmu_reg>;
+};
+
+Then the PHY can be used in other nodes such as:
+
+phy-consumer@12340000 {
+ phys = <&usbphy 2>;
+ phy-names = "phy";
+};
+
+Refer to DT bindings documentation of particular PHY consumer devices for more
+information about required PHYs and the way of specification.
diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
new file mode 100644
index 000000000000..a82361b62015
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
@@ -0,0 +1,26 @@
+Allwinner sun4i USB PHY
+-----------------------
+
+Required properties:
+- compatible : should be one of "allwinner,sun4i-a10-usb-phy",
+ "allwinner,sun5i-a13-usb-phy" or "allwinner,sun7i-a20-usb-phy"
+- reg : a list of offset + length pairs
+- reg-names : "phy_ctrl", "pmu1" and for sun4i or sun7i "pmu2"
+- #phy-cells : from the generic phy bindings, must be 1
+- clocks : phandle + clock specifier for the phy clock
+- clock-names : "usb_phy"
+- resets : a list of phandle + reset specifier pairs
+- reset-names : "usb0_reset", "usb1_reset" and for sun4i or sun7i "usb2_reset"
+
+Example:
+ usbphy: phy@0x01c13400 {
+ #phy-cells = <1>;
+ compatible = "allwinner,sun4i-a10-usb-phy";
+ /* phy base regs, phy1 pmu reg, phy2 pmu reg */
+ reg = <0x01c13400 0x10 0x01c14800 0x4 0x01c1c800 0x4>;
+ reg-names = "phy_ctrl", "pmu1", "pmu2";
+ clocks = <&usb_clk 8>;
+ clock-names = "usb_phy";
+ resets = <&usb_clk 1>, <&usb_clk 2>;
+ reset-names = "usb1_reset", "usb2_reset";
+ };
diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt b/Documentation/devicetree/bindings/phy/ti-phy.txt
new file mode 100644
index 000000000000..788fb0fa3762
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/ti-phy.txt
@@ -0,0 +1,86 @@
+TI PHY: DT DOCUMENTATION FOR PHYs in TI PLATFORMs
+
+OMAP CONTROL PHY
+
+Required properties:
+ - compatible: Should be one of
+ "ti,control-phy-otghs" - if it has otghs_control mailbox register as on OMAP4.
+ "ti,control-phy-usb2" - if it has Power down bit in control_dev_conf register
+ e.g. USB2_PHY on OMAP5.
+ "ti,control-phy-pipe3" - if it has DPLL and individual Rx & Tx power control
+ e.g. USB3 PHY and SATA PHY on OMAP5.
+ "ti,control-phy-usb2-dra7" - if it has power down register like USB2 PHY on
+ DRA7 platform.
+ "ti,control-phy-usb2-am437" - if it has power down register like USB2 PHY on
+ AM437 platform.
+ - reg : Address and length of the register set for the device. It contains
+ the address of "otghs_control" for control-phy-otghs or "power" register
+ for other types.
+ - reg-names: should be "otghs_control" control-phy-otghs and "power" for
+ other types.
+
+omap_control_usb: omap-control-usb@4a002300 {
+ compatible = "ti,control-phy-otghs";
+ reg = <0x4a00233c 0x4>;
+ reg-names = "otghs_control";
+};
+
+OMAP USB2 PHY
+
+Required properties:
+ - compatible: Should be "ti,omap-usb2"
+ - reg : Address and length of the register set for the device.
+ - #phy-cells: determine the number of cells that should be given in the
+ phandle while referencing this phy.
+
+Optional properties:
+ - ctrl-module : phandle of the control module used by PHY driver to power on
+ the PHY.
+
+This is usually a subnode of ocp2scp to which it is connected.
+
+usb2phy@4a0ad080 {
+ compatible = "ti,omap-usb2";
+ reg = <0x4a0ad080 0x58>;
+ ctrl-module = <&omap_control_usb>;
+ #phy-cells = <0>;
+};
+
+TI PIPE3 PHY
+
+Required properties:
+ - compatible: Should be "ti,phy-usb3" or "ti,phy-pipe3-sata".
+ "ti,omap-usb3" is deprecated.
+ - reg : Address and length of the register set for the device.
+ - reg-names: The names of the register addresses corresponding to the registers
+ filled in "reg".
+ - #phy-cells: determine the number of cells that should be given in the
+ phandle while referencing this phy.
+ - clocks: a list of phandles and clock-specifier pairs, one for each entry in
+ clock-names.
+ - clock-names: should include:
+ * "wkupclk" - wakeup clock.
+ * "sysclk" - system clock.
+ * "refclk" - reference clock.
+
+Optional properties:
+ - ctrl-module : phandle of the control module used by PHY driver to power on
+ the PHY.
+
+This is usually a subnode of ocp2scp to which it is connected.
+
+usb3phy@4a084400 {
+ compatible = "ti,phy-usb3";
+ reg = <0x4a084400 0x80>,
+ <0x4a084800 0x64>,
+ <0x4a084c00 0x40>;
+ reg-names = "phy_rx", "phy_tx", "pll_ctrl";
+ ctrl-module = <&omap_control_usb>;
+ #phy-cells = <0>;
+ clocks = <&usb_phy_cm_clk32k>,
+ <&sys_clkin>,
+ <&usb_otg_ss_refclk960m>;
+ clock-names = "wkupclk",
+ "sysclk",
+ "refclk";
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,capri-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/brcm,bcm11351-pinctrl.txt
index 9e9e9ef9f852..c119debe6bab 100644
--- a/Documentation/devicetree/bindings/pinctrl/brcm,capri-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/brcm,bcm11351-pinctrl.txt
@@ -1,4 +1,4 @@
-Broadcom Capri Pin Controller
+Broadcom BCM281xx Pin Controller
This is a pin controller for the Broadcom BCM281xx SoC family, which includes
BCM11130, BCM11140, BCM11351, BCM28145, and BCM28155 SoCs.
@@ -7,14 +7,14 @@ BCM11130, BCM11140, BCM11351, BCM28145, and BCM28155 SoCs.
Required Properties:
-- compatible: Must be "brcm,capri-pinctrl".
+- compatible: Must be "brcm,bcm11351-pinctrl"
- reg: Base address of the PAD Controller register block and the size
of the block.
For example, the following is the bare minimum node:
pinctrl@35004800 {
- compatible = "brcm,capri-pinctrl";
+ compatible = "brcm,bcm11351-pinctrl";
reg = <0x35004800 0x430>;
};
@@ -119,7 +119,7 @@ Optional Properties (for HDMI pins):
Example:
// pin controller node
pinctrl@35004800 {
- compatible = "brcm,capri-pinctrl";
+ compatible = "brcmbcm11351-pinctrl";
reg = <0x35004800 0x430>;
// pin configuration node
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt
index 01ef408e205f..adda2a8d1d52 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt
@@ -5,6 +5,7 @@ part and usage.
Required properties:
- compatible: "marvell,88f6710-pinctrl"
+- reg: register specifier of MPP registers
Available mpp pins/groups and functions:
Note: brackets (x) are not part of the mpp name for marvell,function and given
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt
new file mode 100644
index 000000000000..7de0cda4a379
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt
@@ -0,0 +1,82 @@
+* Marvell Armada 375 SoC pinctrl driver for mpp
+
+Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding
+part and usage.
+
+Required properties:
+- compatible: "marvell,88f6720-pinctrl"
+- reg: register specifier of MPP registers
+
+Available mpp pins/groups and functions:
+Note: brackets (x) are not part of the mpp name for marvell,function and given
+only for more detailed description in this document.
+
+name pins functions
+================================================================================
+mpp0 0 gpio, dev(ad2), spi0(cs1), spi1(cs1)
+mpp1 1 gpio, dev(ad3), spi0(mosi), spi1(mosi)
+mpp2 2 gpio, dev(ad4), ptp(eventreq), led(c0), audio(sdi)
+mpp3 3 gpio, dev(ad5), ptp(triggen), led(p3), audio(mclk)
+mpp4 4 gpio, dev(ad6), spi0(miso), spi1(miso)
+mpp5 5 gpio, dev(ad7), spi0(cs2), spi1(cs2)
+mpp6 6 gpio, dev(ad0), led(p1), audio(rclk)
+mpp7 7 gpio, dev(ad1), ptp(clk), led(p2), audio(extclk)
+mpp8 8 gpio, dev (bootcs), spi0(cs0), spi1(cs0)
+mpp9 9 gpio, nf(wen), spi0(sck), spi1(sck)
+mpp10 10 gpio, nf(ren), dram(vttctrl), led(c1)
+mpp11 11 gpio, dev(a0), led(c2), audio(sdo)
+mpp12 12 gpio, dev(a1), audio(bclk)
+mpp13 13 gpio, dev(readyn), pcie0(rstoutn), pcie1(rstoutn)
+mpp14 14 gpio, i2c0(sda), uart1(txd)
+mpp15 15 gpio, i2c0(sck), uart1(rxd)
+mpp16 16 gpio, uart0(txd)
+mpp17 17 gpio, uart0(rxd)
+mpp18 18 gpio, tdm(intn)
+mpp19 19 gpio, tdm(rstn)
+mpp20 20 gpio, tdm(pclk)
+mpp21 21 gpio, tdm(fsync)
+mpp22 22 gpio, tdm(drx)
+mpp23 23 gpio, tdm(dtx)
+mpp24 24 gpio, led(p0), ge1(rxd0), sd(cmd), uart0(rts)
+mpp25 25 gpio, led(p2), ge1(rxd1), sd(d0), uart0(cts)
+mpp26 26 gpio, pcie0(clkreq), ge1(rxd2), sd(d2), uart1(rts)
+mpp27 27 gpio, pcie1(clkreq), ge1(rxd3), sd(d1), uart1(cts)
+mpp28 28 gpio, led(p3), ge1(txctl), sd(clk)
+mpp29 29 gpio, pcie1(clkreq), ge1(rxclk), sd(d3)
+mpp30 30 gpio, ge1(txd0), spi1(cs0)
+mpp31 31 gpio, ge1(txd1), spi1(mosi)
+mpp32 32 gpio, ge1(txd2), spi1(sck), ptp(triggen)
+mpp33 33 gpio, ge1(txd3), spi1(miso)
+mpp34 34 gpio, ge1(txclkout), spi1(sck)
+mpp35 35 gpio, ge1(rxctl), spi1(cs1), spi0(cs2)
+mpp36 36 gpio, pcie0(clkreq)
+mpp37 37 gpio, pcie0(clkreq), tdm(intn), ge(mdc)
+mpp38 38 gpio, pcie1(clkreq), ge(mdio)
+mpp39 39 gpio, ref(clkout)
+mpp40 40 gpio, uart1(txd)
+mpp41 41 gpio, uart1(rxd)
+mpp42 42 gpio, spi1(cs2), led(c0)
+mpp43 43 gpio, sata0(prsnt), dram(vttctrl)
+mpp44 44 gpio, sata0(prsnt)
+mpp45 45 gpio, spi0(cs2), pcie0(rstoutn)
+mpp46 46 gpio, led(p0), ge0(txd0), ge1(txd0)
+mpp47 47 gpio, led(p1), ge0(txd1), ge1(txd1)
+mpp48 48 gpio, led(p2), ge0(txd2), ge1(txd2)
+mpp49 49 gpio, led(p3), ge0(txd3), ge1(txd3)
+mpp50 50 gpio, led(c0), ge0(rxd0), ge1(rxd0)
+mpp51 51 gpio, led(c1), ge0(rxd1), ge1(rxd1)
+mpp52 52 gpio, led(c2), ge0(rxd2), ge1(rxd2)
+mpp53 53 gpio, pcie1(rstoutn), ge0(rxd3), ge1(rxd3)
+mpp54 54 gpio, pcie0(rstoutn), ge0(rxctl), ge1(rxctl)
+mpp55 55 gpio, ge0(rxclk), ge1(rxclk)
+mpp56 56 gpio, ge0(txclkout), ge1(txclkout)
+mpp57 57 gpio, ge0(txctl), ge1(txctl)
+mpp58 58 gpio, led(c0)
+mpp59 59 gpio, led(c1)
+mpp60 60 gpio, uart1(txd), led(c2)
+mpp61 61 gpio, i2c1(sda), uart1(rxd), spi1(cs2), led(p0)
+mpp62 62 gpio, i2c1(sck), led(p1)
+mpp63 63 gpio, ptp(triggen), led(p2)
+mpp64 64 gpio, dram(vttctrl), led(p3)
+mpp65 65 gpio, sata1(prsnt)
+mpp66 66 gpio, ptp(eventreq), spi1(cs3)
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt
new file mode 100644
index 000000000000..b17c96849fc9
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt
@@ -0,0 +1,80 @@
+* Marvell Armada 380/385 SoC pinctrl driver for mpp
+
+Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding
+part and usage.
+
+Required properties:
+- compatible: "marvell,88f6810-pinctrl", "marvell,88f6820-pinctrl" or
+ "marvell,88f6828-pinctrl" depending on the specific variant of the
+ SoC being used.
+- reg: register specifier of MPP registers
+
+Available mpp pins/groups and functions:
+Note: brackets (x) are not part of the mpp name for marvell,function and given
+only for more detailed description in this document.
+
+name pins functions
+================================================================================
+mpp0 0 gpio, ua0(rxd)
+mpp1 1 gpio, ua0(txd)
+mpp2 2 gpio, i2c0(sck)
+mpp3 3 gpio, i2c0(sda)
+mpp4 4 gpio, ge(mdc), ua1(txd), ua0(rts)
+mpp5 5 gpio, ge(mdio), ua1(rxd), ua0(cts)
+mpp6 6 gpio, ge0(txclkout), ge0(crs), dev(cs3)
+mpp7 7 gpio, ge0(txd0), dev(ad9)
+mpp8 8 gpio, ge0(txd1), dev(ad10)
+mpp9 9 gpio, ge0(txd2), dev(ad11)
+mpp10 10 gpio, ge0(txd3), dev(ad12)
+mpp11 11 gpio, ge0(txctl), dev(ad13)
+mpp12 12 gpio, ge0(rxd0), pcie0(rstout), pcie1(rstout) [1], spi0(cs1), dev(ad14)
+mpp13 13 gpio, ge0(rxd1), pcie0(clkreq), pcie1(clkreq) [1], spi0(cs2), dev(ad15)
+mpp14 14 gpio, ge0(rxd2), ptp(clk), m(vtt_ctrl), spi0(cs3), dev(wen1)
+mpp15 15 gpio, ge0(rxd3), ge(mdc slave), pcie0(rstout), spi0(mosi), pcie1(rstout) [1]
+mpp16 16 gpio, ge0(rxctl), ge(mdio slave), m(decc_err), spi0(miso), pcie0(clkreq)
+mpp17 17 gpio, ge0(rxclk), ptp(clk), ua1(rxd), spi0(sck), sata1(prsnt)
+mpp18 18 gpio, ge0(rxerr), ptp(trig_gen), ua1(txd), spi0(cs0), pcie1(rstout) [1]
+mpp19 19 gpio, ge0(col), ptp(event_req), pcie0(clkreq), sata1(prsnt), ua0(cts)
+mpp20 20 gpio, ge0(txclk), ptp(clk), pcie1(rstout) [1], sata0(prsnt), ua0(rts)
+mpp21 21 gpio, spi0(cs1), ge1(rxd0), sata0(prsnt), sd0(cmd), dev(bootcs)
+mpp22 22 gpio, spi0(mosi), dev(ad0)
+mpp23 23 gpio, spi0(sck), dev(ad2)
+mpp24 24 gpio, spi0(miso), ua0(cts), ua1(rxd), sd0(d4), dev(ready)
+mpp25 25 gpio, spi0(cs0), ua0(rts), ua1(txd), sd0(d5), dev(cs0)
+mpp26 26 gpio, spi0(cs2), i2c1(sck), sd0(d6), dev(cs1)
+mpp27 27 gpio, spi0(cs3), ge1(txclkout), i2c1(sda), sd0(d7), dev(cs2)
+mpp28 28 gpio, ge1(txd0), sd0(clk), dev(ad5)
+mpp29 29 gpio, ge1(txd1), dev(ale0)
+mpp30 30 gpio, ge1(txd2), dev(oen)
+mpp31 31 gpio, ge1(txd3), dev(ale1)
+mpp32 32 gpio, ge1(txctl), dev(wen0)
+mpp33 33 gpio, m(decc_err), dev(ad3)
+mpp34 34 gpio, dev(ad1)
+mpp35 35 gpio, ref(clk_out1), dev(a1)
+mpp36 36 gpio, ptp(trig_gen), dev(a0)
+mpp37 37 gpio, ptp(clk), ge1(rxclk), sd0(d3), dev(ad8)
+mpp38 38 gpio, ptp(event_req), ge1(rxd1), ref(clk_out0), sd0(d0), dev(ad4)
+mpp39 39 gpio, i2c1(sck), ge1(rxd2), ua0(cts), sd0(d1), dev(a2)
+mpp40 40 gpio, i2c1(sda), ge1(rxd3), ua0(rts), sd0(d2), dev(ad6)
+mpp41 41 gpio, ua1(rxd), ge1(rxctl), ua0(cts), spi1(cs3), dev(burst/last)
+mpp42 42 gpio, ua1(txd), ua0(rts), dev(ad7)
+mpp43 43 gpio, pcie0(clkreq), m(vtt_ctrl), m(decc_err), pcie0(rstout), dev(clkout)
+mpp44 44 gpio, sata0(prsnt), sata1(prsnt), sata2(prsnt) [2], sata3(prsnt) [3], pcie0(rstout)
+mpp45 45 gpio, ref(clk_out0), pcie0(rstout), pcie1(rstout) [1], pcie2(rstout), pcie3(rstout)
+mpp46 46 gpio, ref(clk_out1), pcie0(rstout), pcie1(rstout) [1], pcie2(rstout), pcie3(rstout)
+mpp47 47 gpio, sata0(prsnt), sata1(prsnt), sata2(prsnt) [2], spi1(cs2), sata3(prsnt) [2]
+mpp48 48 gpio, sata0(prsnt), m(vtt_ctrl), tdm2c(pclk), audio(mclk), sd0(d4)
+mpp49 49 gpio, sata2(prsnt) [2], sata3(prsnt) [2], tdm2c(fsync), audio(lrclk), sd0(d5)
+mpp50 50 gpio, pcie0(rstout), pcie1(rstout) [1], tdm2c(drx), audio(extclk), sd0(cmd)
+mpp51 51 gpio, tdm2c(dtx), audio(sdo), m(decc_err)
+mpp52 52 gpio, pcie0(rstout), pcie1(rstout) [1], tdm2c(intn), audio(sdi), sd0(d6)
+mpp53 53 gpio, sata1(prsnt), sata0(prsnt), tdm2c(rstn), audio(bclk), sd0(d7)
+mpp54 54 gpio, sata0(prsnt), sata1(prsnt), pcie0(rstout), pcie1(rstout) [1], sd0(d3)
+mpp55 55 gpio, ua1(cts), ge(mdio), pcie1(clkreq) [1], spi1(cs1), sd0(d0)
+mpp56 56 gpio, ua1(rts), ge(mdc), m(decc_err), spi1(mosi)
+mpp57 57 gpio, spi1(sck), sd0(clk)
+mpp58 58 gpio, pcie1(clkreq) [1], i2c1(sck), pcie2(clkreq), spi1(miso), sd0(d1)
+mpp59 59 gpio, pcie0(rstout), i2c1(sda), pcie1(rstout) [1], spi1(cs0), sd0(d2)
+
+[1]: only available on 88F6820 and 88F6828
+[2]: only available on 88F6828
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt
index bfa0a2e5e0cb..373dbccd7ab0 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt
@@ -6,6 +6,7 @@ part and usage.
Required properties:
- compatible: "marvell,mv78230-pinctrl", "marvell,mv78260-pinctrl",
"marvell,mv78460-pinctrl"
+- reg: register specifier of MPP registers
This driver supports all Armada XP variants, i.e. mv78230, mv78260, and mv78460.
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt
index 50ec3512a292..cf52477cc7ee 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt
@@ -6,6 +6,7 @@ part and usage.
Required properties:
- compatible: "marvell,dove-pinctrl"
- clocks: (optional) phandle of pdma clock
+- reg: register specifiers of MPP, MPP4, and PMU MPP registers
Available mpp pins/groups and functions:
Note: brackets (x) are not part of the mpp name for marvell,function and given
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt
index 95daf6335c37..730444a9a4de 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt
@@ -8,6 +8,7 @@ Required properties:
"marvell,88f6190-pinctrl", "marvell,88f6192-pinctrl",
"marvell,88f6281-pinctrl", "marvell,88f6282-pinctrl"
"marvell,98dx4122-pinctrl"
+- reg: register specifier of MPP registers
This driver supports all kirkwood variants, i.e. 88f6180, 88f619x, and 88f628x.
It also support the 88f6281-based variant in the 98dx412x Bobcat SoCs.
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt
index 0a26c3aa4e6d..0c09f4eb2af0 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt
@@ -37,7 +37,7 @@ uart1: serial@12100 {
pinctrl: pinctrl@d0200 {
compatible = "marvell,dove-pinctrl";
- reg = <0xd0200 0x20>;
+ reg = <0xd0200 0x14>, <0xd0440 0x04>, <0xd802c 0x08>;
pmx_uart1_sw: pmx-uart1-sw {
marvell,pins = "mpp_uart1";
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
index bc0dfdfdb148..66dcaa9efd74 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
@@ -63,6 +63,13 @@ Optional properties:
/* input, enable bits, disable bits, mask */
pinctrl-single,input-schmitt-enable = <0x30 0x40 0 0x70>;
+- pinctrl-single,low-power-mode : array of value that are used to configure
+ low power mode of this pin. For some silicons, the low power mode will
+ control the output of the pin when the pad including the pin enter low
+ power mode.
+ /* low power mode value, mask */
+ pinctrl-single,low-power-mode = <0x288 0x388>;
+
- pinctrl-single,gpio-range : list of value that are used to configure a GPIO
range. They're value of subnode phandle, pin base in pinctrl device, pin
number in this range, GPIO function value of this GPIO range.
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt
index 05bf82a07dfd..4bd5be0e5e7d 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt
@@ -11,18 +11,68 @@ Pull Up (PU) are driven by the related PIO block.
ST pinctrl driver controls PIO multiplexing block and also interacts with
gpio driver to configure a pin.
-Required properties: (PIO multiplexing block)
+GPIO bank can have one of the two possible types of interrupt-wirings.
+
+First type is via irqmux, single interrupt is used by multiple gpio banks. This
+reduces number of overall interrupts numbers required. All these banks belong to
+a single pincontroller.
+ _________
+ | |----> [gpio-bank (n) ]
+ | |----> [gpio-bank (n + 1)]
+ [irqN]-- | irq-mux |----> [gpio-bank (n + 2)]
+ | |----> [gpio-bank (... )]
+ |_________|----> [gpio-bank (n + 7)]
+
+Second type has a dedicated interrupt per gpio bank.
+
+ [irqN]----> [gpio-bank (n)]
+
+
+Pin controller node:
+Required properties:
- compatible : should be "st,<SOC>-<pio-block>-pinctrl"
like st,stih415-sbc-pinctrl, st,stih415-front-pinctrl and so on.
-- gpio-controller : Indicates this device is a GPIO controller
-- #gpio-cells : Should be one. The first cell is the pin number.
+- st,syscfg : Should be a phandle of the syscfg node.
- st,retime-pin-mask : Should be mask to specify which pins can be retimed.
If the property is not present, it is assumed that all the pins in the
bank are capable of retiming. Retiming is mainly used to improve the
IO timing margins of external synchronous interfaces.
-- st,bank-name : Should be a name string for this bank as
- specified in datasheet.
-- st,syscfg : Should be a phandle of the syscfg node.
+- ranges : defines mapping between pin controller node (parent) to gpio-bank
+ node (children).
+
+Optional properties:
+- interrupts : Interrupt number of the irqmux. If the interrupt is shared
+ with other gpio banks via irqmux.
+ a irqline and gpio banks.
+- reg : irqmux memory resource. If irqmux is present.
+- reg-names : irqmux resource should be named as "irqmux".
+
+GPIO controller/bank node.
+Required properties:
+- gpio-controller : Indicates this device is a GPIO controller
+- #gpio-cells : Should be one. The first cell is the pin number.
+- st,bank-name : Should be a name string for this bank as specified in
+ datasheet.
+
+Optional properties:
+- interrupts : Interrupt number for this gpio bank. If there is a dedicated
+ interrupt wired up for this gpio bank.
+
+- interrupt-controller : Indicates this device is a interrupt controller. GPIO
+ bank can be an interrupt controller iff one of the interrupt type either via
+irqmux or a dedicated interrupt per bank is specified.
+
+- #interrupt-cells: the value of this property should be 2.
+ - First Cell: represents the external gpio interrupt number local to the
+ gpio interrupt space of the controller.
+ - Second Cell: flags to identify the type of the interrupt
+ - 1 = rising edge triggered
+ - 2 = falling edge triggered
+ - 3 = rising and falling edge triggered
+ - 4 = high level triggered
+ - 8 = low level triggered
+for related macros look in:
+include/dt-bindings/interrupt-controller/irq.h
Example:
pin-controller-sbc {
@@ -30,10 +80,17 @@ Example:
#size-cells = <1>;
compatible = "st,stih415-sbc-pinctrl";
st,syscfg = <&syscfg_sbc>;
+ reg = <0xfe61f080 0x4>;
+ reg-names = "irqmux";
+ interrupts = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts-names = "irqmux";
ranges = <0 0xfe610000 0x5000>;
+
PIO0: gpio@fe610000 {
gpio-controller;
#gpio-cells = <1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
reg = <0 0x100>;
st,bank-name = "PIO0";
};
@@ -105,6 +162,10 @@ pin-controller {
sdhci0:sdhci@fe810000{
...
+ interrupt-parent = <&PIO3>;
+ #interrupt-cells = <2>;
+ interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; /* Interrupt line via PIO3-3 */
+ interrupts-names = "card-detect";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_mmc>;
};
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.txt
index 4c352be5dd61..9fb89e3f61ea 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.txt
@@ -1,7 +1,7 @@
Qualcomm MSM8974 TLMM block
Required properties:
-- compatible: "qcom,msm8x74-pinctrl"
+- compatible: "qcom,msm8974-pinctrl"
- reg: Should be the base address and length of the TLMM block.
- interrupts: Should be the parent IRQ of the TLMM block.
- interrupt-controller: Marks the device node as an interrupt controller.
@@ -42,14 +42,14 @@ Non-empty subnodes must specify the 'pins' property.
Note that not all properties are valid for all pins.
-Valid values for qcom,pins are:
+Valid values for pins are:
gpio0-gpio145
Supports mux, bias and drive-strength
sdc1_clk, sdc1_cmd, sdc1_data, sdc2_clk, sdc2_cmd, sdc2_data
Supports bias and drive-strength
-Valid values for qcom,function are:
+Valid values for function are:
blsp_i2c2, blsp_i2c6, blsp_i2c11, blsp_spi1, blsp_uart2, blsp_uart8, slimbus
(Note that this is not yet the complete list of functions)
@@ -73,18 +73,18 @@ Example:
uart2_default: uart2_default {
mux {
- qcom,pins = "gpio4", "gpio5";
- qcom,function = "blsp_uart2";
+ pins = "gpio4", "gpio5";
+ function = "blsp_uart2";
};
tx {
- qcom,pins = "gpio4";
+ pins = "gpio4";
drive-strength = <4>;
bias-disable;
};
rx {
- qcom,pins = "gpio5";
+ pins = "gpio5";
drive-strength = <2>;
bias-pull-up;
};
diff --git a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
index 257677de3e6b..2b32783ba821 100644
--- a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
@@ -16,6 +16,7 @@ Required Properties:
- "samsung,exynos4210-pinctrl": for Exynos4210 compatible pin-controller.
- "samsung,exynos4x12-pinctrl": for Exynos4x12 compatible pin-controller.
- "samsung,exynos5250-pinctrl": for Exynos5250 compatible pin-controller.
+ - "samsung,exynos5260-pinctrl": for Exynos5260 compatible pin-controller.
- "samsung,exynos5420-pinctrl": for Exynos5420 compatible pin-controller.
- reg: Base address of the pin controller hardware module and length of
diff --git a/Documentation/devicetree/bindings/power/bq2415x.txt b/Documentation/devicetree/bindings/power/bq2415x.txt
new file mode 100644
index 000000000000..d0327f0b59ad
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/bq2415x.txt
@@ -0,0 +1,47 @@
+Binding for TI bq2415x Li-Ion Charger
+
+Required properties:
+- compatible: Should contain one of the following:
+ * "ti,bq24150"
+ * "ti,bq24150"
+ * "ti,bq24150a"
+ * "ti,bq24151"
+ * "ti,bq24151a"
+ * "ti,bq24152"
+ * "ti,bq24153"
+ * "ti,bq24153a"
+ * "ti,bq24155"
+ * "ti,bq24156"
+ * "ti,bq24156a"
+ * "ti,bq24158"
+- reg: integer, i2c address of the device.
+- ti,current-limit: integer, initial maximum current charger can pull
+ from power supply in mA.
+- ti,weak-battery-voltage: integer, weak battery voltage threshold in mV.
+ The chip will use slow precharge if battery voltage
+ is below this value.
+- ti,battery-regulation-voltage: integer, maximum charging voltage in mV.
+- ti,charge-current: integer, maximum charging current in mA.
+- ti,termination-current: integer, charge will be terminated when current in
+ constant-voltage phase drops below this value (in mA).
+- ti,resistor-sense: integer, value of sensing resistor in milliohm.
+
+Optional properties:
+- ti,usb-charger-detection: phandle to usb charger detection device.
+ (required for auto mode)
+
+Example from Nokia N900:
+
+bq24150a {
+ compatible = "ti,bq24150a";
+ reg = <0x6b>;
+
+ ti,current-limit = <100>;
+ ti,weak-battery-voltage = <3400>;
+ ti,battery-regulation-voltage = <4200>;
+ ti,charge-current = <650>;
+ ti,termination-current = <100>;
+ ti,resistor-sense = <68>;
+
+ ti,usb-charger-detection = <&isp1704>;
+};
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/l2cache.txt b/Documentation/devicetree/bindings/powerpc/fsl/l2cache.txt
new file mode 100644
index 000000000000..c41b2187eaa8
--- /dev/null
+++ b/Documentation/devicetree/bindings/powerpc/fsl/l2cache.txt
@@ -0,0 +1,23 @@
+Freescale L2 Cache Controller
+
+L2 cache is present in Freescale's QorIQ and QorIQ Qonverge platforms.
+The cache bindings explained below are ePAPR compliant
+
+Required Properties:
+
+- compatible : Should include "fsl,chip-l2-cache-controller" and "cache"
+ where chip is the processor (bsc9132, npc8572 etc.)
+- reg : Address and size of L2 cache controller registers
+- cache-size : Size of the entire L2 cache
+- interrupts : Error interrupt of L2 controller
+- cache-line-size : Size of L2 cache lines
+
+Example:
+
+ L2: l2-cache-controller@20000 {
+ compatible = "fsl,bsc9132-l2-cache-controller", "cache";
+ reg = <0x20000 0x1000>;
+ cache-line-size = <32>; // 32 bytes
+ cache-size = <0x40000>; // L2,256K
+ interrupts = <16 2 1 0>;
+ };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt b/Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt
new file mode 100644
index 000000000000..f87856faf1ab
--- /dev/null
+++ b/Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt
@@ -0,0 +1,27 @@
+Freescale DDR memory controller
+
+Properties:
+
+- compatible : Should include "fsl,chip-memory-controller" where
+ chip is the processor (bsc9132, mpc8572 etc.), or
+ "fsl,qoriq-memory-controller".
+- reg : Address and size of DDR controller registers
+- interrupts : Error interrupt of DDR controller
+
+Example 1:
+
+ memory-controller@2000 {
+ compatible = "fsl,bsc9132-memory-controller";
+ reg = <0x2000 0x1000>;
+ interrupts = <16 2 1 8>;
+ };
+
+
+Example 2:
+
+ ddr1: memory-controller@8000 {
+ compatible = "fsl,qoriq-memory-controller-v4.7",
+ "fsl,qoriq-memory-controller";
+ reg = <0x8000 0x1000>;
+ interrupts = <16 2 1 23>;
+ };
diff --git a/Documentation/devicetree/bindings/regulator/gpio-regulator.txt b/Documentation/devicetree/bindings/regulator/gpio-regulator.txt
index 63c659800c03..e5cac1e0ca8a 100644
--- a/Documentation/devicetree/bindings/regulator/gpio-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/gpio-regulator.txt
@@ -8,8 +8,12 @@ Required properties:
Optional properties:
- enable-gpio : GPIO to use to enable/disable the regulator.
- gpios : GPIO group used to control voltage.
+- gpios-states : gpios pin's initial states array. 0: LOW, 1: HIGH.
+ defualt is LOW if nothing is specified.
- startup-delay-us : Startup time in microseconds.
- enable-active-high : Polarity of GPIO is active high (default is low).
+- regulator-type : Specifies what is being regulated, must be either
+ "voltage" or "current", defaults to current.
Any property defined as part of the core regulator binding defined in
regulator.txt can also be used.
diff --git a/Documentation/devicetree/bindings/regulator/pfuze100.txt b/Documentation/devicetree/bindings/regulator/pfuze100.txt
index fc989b2e8057..34ef5d16d0f1 100644
--- a/Documentation/devicetree/bindings/regulator/pfuze100.txt
+++ b/Documentation/devicetree/bindings/regulator/pfuze100.txt
@@ -1,7 +1,7 @@
PFUZE100 family of regulators
Required properties:
-- compatible: "fsl,pfuze100"
+- compatible: "fsl,pfuze100" or "fsl,pfuze200"
- reg: I2C slave address
Required child node:
@@ -10,11 +10,14 @@ Required child node:
Documentation/devicetree/bindings/regulator/regulator.txt.
The valid names for regulators are:
+ --PFUZE100
sw1ab,sw1c,sw2,sw3a,sw3b,sw4,swbst,vsnvs,vrefddr,vgen1~vgen6
+ --PFUZE200
+ sw1ab,sw2,sw3a,sw3b,swbst,vsnvs,vrefddr,vgen1~vgen6
Each regulator is defined using the standard binding for regulators.
-Example:
+Example 1: PFUZE100
pmic: pfuze100@08 {
compatible = "fsl,pfuze100";
@@ -113,3 +116,92 @@ Example:
};
};
};
+
+
+Example 2: PFUZE200
+
+ pmic: pfuze200@08 {
+ compatible = "fsl,pfuze200";
+ reg = <0x08>;
+
+ regulators {
+ sw1a_reg: sw1ab {
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <1875000>;
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-ramp-delay = <6250>;
+ };
+
+ sw2_reg: sw2 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ sw3a_reg: sw3a {
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <1975000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ sw3b_reg: sw3b {
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <1975000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ swbst_reg: swbst {
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5150000>;
+ };
+
+ snvs_reg: vsnvs {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vref_reg: vrefddr {
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vgen1_reg: vgen1 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1550000>;
+ };
+
+ vgen2_reg: vgen2 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1550000>;
+ };
+
+ vgen3_reg: vgen3 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vgen4_reg: vgen4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vgen5_reg: vgen5 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vgen6_reg: vgen6 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt b/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt
index fc6b38f035bd..d290988ed975 100644
--- a/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt
@@ -69,13 +69,16 @@ sub-node should be of the format as listed below.
};
};
The above regulator entries are defined in regulator bindings documentation
-except op_mode description.
+except these properties:
- op_mode: describes the different operating modes of the LDO's with
power mode change in SOC. The different possible values are,
0 - always off mode
1 - on in normal mode
2 - low power mode
3 - suspend mode
+ - s5m8767,pmic-ext-control-gpios: (optional) GPIO specifier for one
+ GPIO controlling this regulator (enable/disable); This is
+ valid only for buck9.
The following are the names of the regulators that the s5m8767 pmic block
supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number
@@ -148,5 +151,13 @@ Example:
regulator-always-on;
regulator-boot-on;
};
+
+ vemmc_reg: BUCK9 {
+ regulator-name = "VMEM_VDD_2.8V";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ op_mode = <3>; /* Standby Mode */
+ s5m8767,pmic-ext-control-gpios = <&gpk0 2 0>;
+ };
};
};
diff --git a/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt b/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt
index 2e57a33e9029..c58db75f959e 100644
--- a/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt
@@ -4,10 +4,14 @@ Required Properties:
- compatible: Should be one of:
- "ti,abb-v1" for older SoCs like OMAP3
- "ti,abb-v2" for newer SoCs like OMAP4, OMAP5
+ - "ti,abb-v3" for a generic definition where setup and control registers are
+ provided (example: DRA7)
- reg: Address and length of the register set for the device. It contains
the information of registers in the same order as described by reg-names
- reg-names: Should contain the reg names
- - "base-address" - contains base address of ABB module
+ - "base-address" - contains base address of ABB module (ti,abb-v1,ti,abb-v2)
+ - "control-address" - contains control register address of ABB module (ti,abb-v3)
+ - "setup-address" - contains setup register address of ABB module (ti,abb-v3)
- "int-address" - contains address of interrupt register for ABB module
(also see Optional properties)
- #address-cell: should be 0
diff --git a/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt
new file mode 100644
index 000000000000..3da0ebdba8d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt
@@ -0,0 +1,133 @@
+*** Reserved memory regions ***
+
+Reserved memory is specified as a node under the /reserved-memory node.
+The operating system shall exclude reserved memory from normal usage
+one can create child nodes describing particular reserved (excluded from
+normal use) memory regions. Such memory regions are usually designed for
+the special usage by various device drivers.
+
+Parameters for each memory region can be encoded into the device tree
+with the following nodes:
+
+/reserved-memory node
+---------------------
+#address-cells, #size-cells (required) - standard definition
+ - Should use the same values as the root node
+ranges (required) - standard definition
+ - Should be empty
+
+/reserved-memory/ child nodes
+-----------------------------
+Each child of the reserved-memory node specifies one or more regions of
+reserved memory. Each child node may either use a 'reg' property to
+specify a specific range of reserved memory, or a 'size' property with
+optional constraints to request a dynamically allocated block of memory.
+
+Following the generic-names recommended practice, node names should
+reflect the purpose of the node (ie. "framebuffer" or "dma-pool"). Unit
+address (@<address>) should be appended to the name if the node is a
+static allocation.
+
+Properties:
+Requires either a) or b) below.
+a) static allocation
+ reg (required) - standard definition
+b) dynamic allocation
+ size (required) - length based on parent's #size-cells
+ - Size in bytes of memory to reserve.
+ alignment (optional) - length based on parent's #size-cells
+ - Address boundary for alignment of allocation.
+ alloc-ranges (optional) - prop-encoded-array (address, length pairs).
+ - Specifies regions of memory that are
+ acceptable to allocate from.
+
+If both reg and size are present, then the reg property takes precedence
+and size is ignored.
+
+Additional properties:
+compatible (optional) - standard definition
+ - may contain the following strings:
+ - shared-dma-pool: This indicates a region of memory meant to be
+ used as a shared pool of DMA buffers for a set of devices. It can
+ be used by an operating system to instanciate the necessary pool
+ management subsystem if necessary.
+ - vendor specific string in the form <vendor>,[<device>-]<usage>
+no-map (optional) - empty property
+ - Indicates the operating system must not create a virtual mapping
+ of the region as part of its standard mapping of system memory,
+ nor permit speculative access to it under any circumstances other
+ than under the control of the device driver using the region.
+reusable (optional) - empty property
+ - The operating system can use the memory in this region with the
+ limitation that the device driver(s) owning the region need to be
+ able to reclaim it back. Typically that means that the operating
+ system can use that region to store volatile or cached data that
+ can be otherwise regenerated or migrated elsewhere.
+
+Linux implementation note:
+- If a "linux,cma-default" property is present, then Linux will use the
+ region for the default pool of the contiguous memory allocator.
+
+Device node references to reserved memory
+-----------------------------------------
+Regions in the /reserved-memory node may be referenced by other device
+nodes by adding a memory-region property to the device node.
+
+memory-region (optional) - phandle, specifier pairs to children of /reserved-memory
+
+Example
+-------
+This example defines 3 contiguous regions are defined for Linux kernel:
+one default of all device drivers (named linux,cma@72000000 and 64MiB in size),
+one dedicated to the framebuffer device (named framebuffer@78000000, 8MiB), and
+one for multimedia processing (named multimedia-memory@77000000, 64MiB).
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ memory {
+ reg = <0x40000000 0x40000000>;
+ };
+
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ /* global autoconfigured region for contiguous allocations */
+ linux,cma {
+ compatible = "shared-dma-pool";
+ reusable;
+ size = <0x4000000>;
+ alignment = <0x2000>;
+ linux,cma-default;
+ };
+
+ display_reserved: framebuffer@78000000 {
+ reg = <0x78000000 0x800000>;
+ };
+
+ multimedia_reserved: multimedia@77000000 {
+ compatible = "acme,multimedia-memory";
+ reg = <0x77000000 0x4000000>;
+ };
+ };
+
+ /* ... */
+
+ fb0: video@12300000 {
+ memory-region = <&display_reserved>;
+ /* ... */
+ };
+
+ scaler: scaler@12500000 {
+ memory-region = <&multimedia_reserved>;
+ /* ... */
+ };
+
+ codec: codec@12600000 {
+ memory-region = <&multimedia_reserved>;
+ /* ... */
+ };
+};
diff --git a/Documentation/devicetree/bindings/rtc/sunxi-rtc.txt b/Documentation/devicetree/bindings/rtc/sunxi-rtc.txt
index 7cb9dbf34878..6983aad376c3 100644
--- a/Documentation/devicetree/bindings/rtc/sunxi-rtc.txt
+++ b/Documentation/devicetree/bindings/rtc/sunxi-rtc.txt
@@ -3,7 +3,7 @@
RTC controller for the Allwinner A10/A20
Required properties:
-- compatible : Should be "allwinner,sun4i-rtc" or "allwinner,sun7i-a20-rtc"
+- compatible : Should be "allwinner,sun4i-a10-rtc" or "allwinner,sun7i-a20-rtc"
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: IRQ line for the RTC.
@@ -11,7 +11,7 @@ Required properties:
Example:
rtc: rtc@01c20d00 {
- compatible = "allwinner,sun4i-rtc";
+ compatible = "allwinner,sun4i-a10-rtc";
reg = <0x01c20d00 0x20>;
interrupts = <24>;
};
diff --git a/Documentation/devicetree/bindings/serial/efm32-uart.txt b/Documentation/devicetree/bindings/serial/efm32-uart.txt
index 8e080b893b49..1984bdfbd545 100644
--- a/Documentation/devicetree/bindings/serial/efm32-uart.txt
+++ b/Documentation/devicetree/bindings/serial/efm32-uart.txt
@@ -6,7 +6,7 @@ Required properties:
- interrupts : Should contain uart interrupt
Optional properties:
-- location : Decides the location of the USART I/O pins.
+- efm32,location : Decides the location of the USART I/O pins.
Allowed range : [0 .. 5]
Default: 0
@@ -16,5 +16,5 @@ uart@0x4000c400 {
compatible = "efm32,uart";
reg = <0x4000c400 0x400>;
interrupts = <15>;
- location = <0>;
+ efm32,location = <0>;
};
diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
index 6fd1dd1638dd..a1d1205d8185 100644
--- a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
+++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
@@ -4,11 +4,24 @@ Required properties:
- compatible : Should be "fsl,<soc>-lpuart"
- reg : Address and length of the register set for the device
- interrupts : Should contain uart interrupt
+- clocks : phandle + clock specifier pairs, one for each entry in clock-names
+- clock-names : should contain: "ipg" - the uart clock
+
+Optional properties:
+- dmas: A list of two dma specifiers, one for each entry in dma-names.
+- dma-names: should contain "tx" and "rx".
+
+Note: Optional properties for DMA support. Write them both or both not.
Example:
uart0: serial@40027000 {
- compatible = "fsl,vf610-lpuart";
- reg = <0x40027000 0x1000>;
- interrupts = <0 61 0x00>;
- };
+ compatible = "fsl,vf610-lpuart";
+ reg = <0x40027000 0x1000>;
+ interrupts = <0 61 0x00>;
+ clocks = <&clks VF610_CLK_UART0>;
+ clock-names = "ipg";
+ dmas = <&edma0 0 2>,
+ <&edma0 0 3>;
+ dma-names = "rx","tx";
+ };
diff --git a/Documentation/devicetree/bindings/serial/maxim,max310x.txt b/Documentation/devicetree/bindings/serial/maxim,max310x.txt
new file mode 100644
index 000000000000..83a919c241b0
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/maxim,max310x.txt
@@ -0,0 +1,36 @@
+* Maxim MAX310X advanced Universal Asynchronous Receiver-Transmitter (UART)
+
+Required properties:
+- compatible: Should be one of the following:
+ - "maxim,max3107" for Maxim MAX3107,
+ - "maxim,max3108" for Maxim MAX3108,
+ - "maxim,max3109" for Maxim MAX3109,
+ - "maxim,max14830" for Maxim MAX14830.
+- reg: SPI chip select number.
+- interrupt-parent: The phandle for the interrupt controller that
+ services interrupts for this IC.
+- interrupts: Specifies the interrupt source of the parent interrupt
+ controller. The format of the interrupt specifier depends on the
+ parent interrupt controller.
+- clocks: phandle to the IC source clock.
+- clock-names: Should be "xtal" if clock is an external crystal or
+ "osc" if an external clock source is used.
+
+Optional properties:
+- gpio-controller: Marks the device node as a GPIO controller.
+- #gpio-cells: Should be two. The first cell is the GPIO number and
+ the second cell is used to specify the GPIO polarity:
+ 0 = active high,
+ 1 = active low.
+
+Example:
+ max14830: max14830@0 {
+ compatible = "maxim,max14830";
+ reg = <0>;
+ clocks = <&clk20m>;
+ clock-names = "osc";
+ interrupt-parent = <&gpio3>;
+ interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
diff --git a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
index f372cf29068d..53e6c175db6c 100644
--- a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
+++ b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
@@ -37,7 +37,7 @@ Example:
};
scifa0: serial@e6c40000 {
- compatible = "renesas,scifa-r8a7790", "renesas,scifa-generic";
+ compatible = "renesas,scifa-r8a7790", "renesas,scifa";
reg = <0 0xe6c40000 0 64>;
interrupt-parent = <&gic>;
interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/Documentation/devicetree/bindings/sound/armada-370db-audio.txt b/Documentation/devicetree/bindings/sound/armada-370db-audio.txt
new file mode 100644
index 000000000000..bf984d238620
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/armada-370db-audio.txt
@@ -0,0 +1,27 @@
+Device Tree bindings for the Armada 370 DB audio
+================================================
+
+These Device Tree bindings are used to describe the audio complex
+found on the Armada 370 DB platform.
+
+Mandatory properties:
+
+ * compatible: must be "marvell,a370db-audio"
+
+ * marvell,audio-controller: a phandle that points to the audio
+ controller of the Armada 370 SoC.
+
+ * marvell,audio-codec: a set of three phandles that points to:
+
+ 1/ the analog audio codec connected to the Armada 370 SoC
+ 2/ the S/PDIF transceiver
+ 3/ the S/PDIF receiver
+
+Example:
+
+ sound {
+ compatible = "marvell,a370db-audio";
+ marvell,audio-controller = <&audio_controller>;
+ marvell,audio-codec = <&audio_codec &spdif_out &spdif_in>;
+ status = "okay";
+ };
diff --git a/Documentation/devicetree/bindings/sound/cs42xx8.txt b/Documentation/devicetree/bindings/sound/cs42xx8.txt
new file mode 100644
index 000000000000..f631fbca6284
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/cs42xx8.txt
@@ -0,0 +1,28 @@
+CS42448/CS42888 audio CODEC
+
+Required properties:
+
+ - compatible : must contain one of "cirrus,cs42448" and "cirrus,cs42888"
+
+ - reg : the I2C address of the device for I2C
+
+ - clocks : a list of phandles + clock-specifiers, one for each entry in
+ clock-names
+
+ - clock-names : must contain "mclk"
+
+ - VA-supply, VD-supply, VLS-supply, VLC-supply: power supplies for the device,
+ as covered in Documentation/devicetree/bindings/regulator/regulator.txt
+
+Example:
+
+codec: cs42888@48 {
+ compatible = "cirrus,cs42888";
+ reg = <0x48>;
+ clocks = <&codec_mclk 0>;
+ clock-names = "mclk";
+ VA-supply = <&reg_audio>;
+ VD-supply = <&reg_audio>;
+ VLS-supply = <&reg_audio>;
+ VLC-supply = <&reg_audio>;
+};
diff --git a/Documentation/devicetree/bindings/sound/da9055.txt b/Documentation/devicetree/bindings/sound/da9055.txt
new file mode 100644
index 000000000000..ed1b7cc6f249
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/da9055.txt
@@ -0,0 +1,22 @@
+* Dialog DA9055 Audio CODEC
+
+DA9055 provides Audio CODEC support (I2C only).
+
+The Audio CODEC device in DA9055 has it's own I2C address which is configurable,
+so the device is instantiated separately from the PMIC (MFD) device.
+
+For details on accompanying PMIC I2C device, see the following:
+Documentation/devicetree/bindings/mfd/da9055.txt
+
+Required properties:
+
+ - compatible: "dlg,da9055-codec"
+ - reg: Specifies the I2C slave address
+
+
+Example:
+
+ codec: da9055-codec@1a {
+ compatible = "dlg,da9055-codec";
+ reg = <0x1a>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
index 865178d5cdf3..963e100514c2 100644
--- a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
+++ b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
@@ -5,12 +5,19 @@ Required properties:
- ti,model : The user-visible name of this sound complex.
- ti,audio-codec : The phandle of the TLV320AIC3x audio codec
- ti,mcasp-controller : The phandle of the McASP controller
-- ti,codec-clock-rate : The Codec Clock rate (in Hz) applied to the Codec
- ti,audio-routing : A list of the connections between audio components.
Each entry is a pair of strings, the first being the connection's sink,
the second being the connection's source. Valid names for sources and
sinks are the codec's pins, and the jacks on the board:
+Optional properties:
+- ti,codec-clock-rate : The Codec Clock rate (in Hz) applied to the Codec.
+- clocks : Reference to the master clock
+- clock-names : The clock should be named "mclk"
+- Either codec-clock-rate or the codec-clock reference has to be defined. If
+ the both are defined the driver attempts to set referenced clock to the
+ defined rate and takes the rate from the clock reference.
+
Board connectors:
* Headphone Jack
diff --git a/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt b/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt
new file mode 100644
index 000000000000..0d7985c864af
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt
@@ -0,0 +1,21 @@
+Audio complex for Eukrea boards with tlv320aic23 codec.
+
+Required properties:
+- compatible : "eukrea,asoc-tlv320"
+- eukrea,model : The user-visible name of this sound complex.
+- ssi-controller : The phandle of the SSI controller.
+- fsl,mux-int-port : The internal port of the i.MX audio muxer (AUDMUX).
+- fsl,mux-ext-port : The external port of the i.MX audio muxer.
+
+Note: The AUDMUX port numbering should start at 1, which is consistent with
+hardware manual.
+
+Example:
+
+ sound {
+ compatible = "eukrea,asoc-tlv320";
+ eukrea,model = "imx51-eukrea-tlv320aic23";
+ ssi-controller = <&ssi2>;
+ fsl,mux-int-port = <2>;
+ fsl,mux-ext-port = <3>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.txt b/Documentation/devicetree/bindings/sound/fsl,esai.txt
index d7b99fa637b5..aeb8c4a0b88d 100644
--- a/Documentation/devicetree/bindings/sound/fsl,esai.txt
+++ b/Documentation/devicetree/bindings/sound/fsl,esai.txt
@@ -34,6 +34,10 @@ Required properties:
that ESAI would work in the synchronous mode, which means all the settings
for Receiving would be duplicated from Transmition related registers.
+ - big-endian : If this property is absent, the native endian mode will
+ be in use as default, or the big endian mode will be in use for all the
+ device registers.
+
Example:
esai: esai@02024000 {
@@ -46,5 +50,6 @@ esai: esai@02024000 {
dma-names = "rx", "tx";
fsl,fifo-depth = <128>;
fsl,esai-synchronous;
+ big-endian;
status = "disabled";
};
diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.txt b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
index f2ae335670f5..3e9e82c8eab3 100644
--- a/Documentation/devicetree/bindings/sound/fsl,spdif.txt
+++ b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
@@ -29,6 +29,10 @@ Required properties:
can also be referred to TxClk_Source
bit of register SPDIF_STC.
+ - big-endian : If this property is absent, the native endian mode will
+ be in use as default, or the big endian mode will be in use for all the
+ device registers.
+
Example:
spdif: spdif@02004000 {
@@ -50,5 +54,6 @@ spdif: spdif@02004000 {
"rxtx5", "rxtx6",
"rxtx7";
+ big-endian;
status = "okay";
};
diff --git a/Documentation/devicetree/bindings/sound/mvebu-audio.txt b/Documentation/devicetree/bindings/sound/mvebu-audio.txt
index f0062c5871b4..cb8c07c81ce4 100644
--- a/Documentation/devicetree/bindings/sound/mvebu-audio.txt
+++ b/Documentation/devicetree/bindings/sound/mvebu-audio.txt
@@ -5,6 +5,7 @@ Required properties:
- compatible:
"marvell,kirkwood-audio" for Kirkwood platforms
"marvell,dove-audio" for Dove platforms
+ "marvell,armada370-audio" for Armada 370 platforms
- reg: physical base address of the controller and length of memory mapped
region.
diff --git a/Documentation/devicetree/bindings/sound/pcm512x.txt b/Documentation/devicetree/bindings/sound/pcm512x.txt
new file mode 100644
index 000000000000..faff75e64573
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/pcm512x.txt
@@ -0,0 +1,30 @@
+PCM512x audio CODECs
+
+These devices support both I2C and SPI (configured with pin strapping
+on the board).
+
+Required properties:
+
+ - compatible : One of "ti,pcm5121" or "ti,pcm5122"
+
+ - reg : the I2C address of the device for I2C, the chip select
+ number for SPI.
+
+ - AVDD-supply, DVDD-supply, and CPVDD-supply : power supplies for the
+ device, as covered in bindings/regulator/regulator.txt
+
+Optional properties:
+
+ - clocks : A clock specifier for the clock connected as SCLK. If this
+ is absent the device will be configured to clock from BCLK.
+
+Example:
+
+ pcm5122: pcm5122@4c {
+ compatible = "ti,pcm5122";
+ reg = <0x4c>;
+
+ AVDD-supply = <&reg_3v3_analog>;
+ DVDD-supply = <&reg_1v8>;
+ CPVDD-supply = <&reg_3v3>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
new file mode 100644
index 000000000000..a44e9179faf5
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
@@ -0,0 +1,105 @@
+Renesas R-Car sound
+
+Required properties:
+- compatible : "renesas,rcar_sound-gen1" if generation1
+ "renesas,rcar_sound-gen2" if generation2
+- reg : Should contain the register physical address.
+ required register is
+ SRU/ADG/SSI if generation1
+ SRU/ADG/SSIU/SSI if generation2
+- rcar_sound,ssi : Should contain SSI feature.
+ The number of SSI subnode should be same as HW.
+ see below for detail.
+- rcar_sound,src : Should contain SRC feature.
+ The number of SRC subnode should be same as HW.
+ see below for detail.
+- rcar_sound,dai : DAI contents.
+ The number of DAI subnode should be same as HW.
+ see below for detail.
+
+SSI subnode properties:
+- interrupts : Should contain SSI interrupt for PIO transfer
+- shared-pin : if shared clock pin
+
+SRC subnode properties:
+no properties at this point
+
+DAI subnode properties:
+- playback : list of playback modules
+- capture : list of capture modules
+
+Example:
+
+rcar_sound: rcar_sound@0xffd90000 {
+ #sound-dai-cells = <1>;
+ compatible = "renesas,rcar_sound-gen2";
+ reg = <0 0xec500000 0 0x1000>, /* SCU */
+ <0 0xec5a0000 0 0x100>, /* ADG */
+ <0 0xec540000 0 0x1000>, /* SSIU */
+ <0 0xec541000 0 0x1280>; /* SSI */
+
+ rcar_sound,src {
+ src0: src@0 { };
+ src1: src@1 { };
+ src2: src@2 { };
+ src3: src@3 { };
+ src4: src@4 { };
+ src5: src@5 { };
+ src6: src@6 { };
+ src7: src@7 { };
+ src8: src@8 { };
+ src9: src@9 { };
+ };
+
+ rcar_sound,ssi {
+ ssi0: ssi@0 {
+ interrupts = <0 370 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ ssi1: ssi@1 {
+ interrupts = <0 371 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ ssi2: ssi@2 {
+ interrupts = <0 372 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ ssi3: ssi@3 {
+ interrupts = <0 373 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ ssi4: ssi@4 {
+ interrupts = <0 374 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ ssi5: ssi@5 {
+ interrupts = <0 375 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ ssi6: ssi@6 {
+ interrupts = <0 376 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ ssi7: ssi@7 {
+ interrupts = <0 377 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ ssi8: ssi@8 {
+ interrupts = <0 378 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ ssi9: ssi@9 {
+ interrupts = <0 379 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
+
+ rcar_sound,dai {
+ dai0 {
+ playback = <&ssi5 &src5>;
+ capture = <&ssi6>;
+ };
+ dai1 {
+ playback = <&ssi3>;
+ };
+ dai2 {
+ capture = <&ssi4>;
+ };
+ dai3 {
+ playback = <&ssi7>;
+ };
+ dai4 {
+ capture = <&ssi8>;
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt
index 19c84df5fffa..131aa2ad7f1a 100644
--- a/Documentation/devicetree/bindings/sound/simple-card.txt
+++ b/Documentation/devicetree/bindings/sound/simple-card.txt
@@ -8,16 +8,26 @@ Required properties:
Optional properties:
+- simple-audio-card,name : User specified audio sound card name, one string
+ property.
- simple-audio-card,format : CPU/CODEC common audio format.
"i2s", "right_j", "left_j" , "dsp_a"
"dsp_b", "ac97", "pdm", "msb", "lsb"
+- simple-audio-card,widgets : Please refer to widgets.txt.
- simple-audio-card,routing : A list of the connections between audio components.
Each entry is a pair of strings, the first being the
connection's sink, the second being the connection's
source.
+- dai-tdm-slot-num : Please refer to tdm-slot.txt.
+- dai-tdm-slot-width : Please refer to tdm-slot.txt.
Required subnodes:
+- simple-audio-card,dai-link : container for the CPU and CODEC sub-nodes
+ This container may be omitted when the
+ card has only one DAI link.
+ See the examples.
+
- simple-audio-card,cpu : CPU sub-node
- simple-audio-card,codec : CODEC sub-node
@@ -38,15 +48,29 @@ Optional CPU/CODEC subnodes properties:
clock node (= common clock), or "system-clock-frequency"
(if system doens't support common clock)
-Example:
+Note:
+ * For 'format', 'frame-master', 'bitclock-master', 'bitclock-inversion' and
+ 'frame-inversion', the simple card will use the settings of CODEC for both
+ CPU and CODEC sides as we need to keep the settings identical for both ends
+ of the link.
+
+Example 1 - single DAI link:
sound {
compatible = "simple-audio-card";
+ simple-audio-card,name = "VF610-Tower-Sound-Card";
simple-audio-card,format = "left_j";
+ simple-audio-card,widgets =
+ "Microphone", "Microphone Jack",
+ "Headphone", "Headphone Jack",
+ "Speaker", "External Speaker";
simple-audio-card,routing =
- "MIC_IN", "Mic Jack",
+ "MIC_IN", "Microphone Jack",
"Headphone Jack", "HP_OUT",
- "Ext Spk", "LINE_OUT";
+ "External Speaker", "LINE_OUT";
+
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <8>;
simple-audio-card,cpu {
sound-dai = <&sh_fsi2 0>;
@@ -75,3 +99,38 @@ sh_fsi2: sh_fsi2@ec230000 {
interrupt-parent = <&gic>;
interrupts = <0 146 0x4>;
};
+
+Example 2 - many DAI links:
+
+sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "Cubox Audio";
+ simple-audio-card,format = "i2s";
+
+ simple-audio-card,dai-link@0 { /* I2S - HDMI */
+ simple-audio-card,cpu {
+ sound-dai = <&audio1 0>;
+ };
+ simple-audio-card,codec {
+ sound-dai = <&tda998x 0>;
+ };
+ };
+
+ simple-audio-card,dai-link@1 { /* S/PDIF - HDMI */
+ simple-audio-card,cpu {
+ sound-dai = <&audio1 1>;
+ };
+ simple-audio-card,codec {
+ sound-dai = <&tda998x 1>;
+ };
+ };
+
+ simple-audio-card,dai-link@2 { /* S/PDIF - S/PDIF */
+ simple-audio-card,cpu {
+ sound-dai = <&audio1 1>;
+ };
+ simple-audio-card,codec {
+ sound-dai = <&spdif_codec>;
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/sound/sirf-audio-codec.txt b/Documentation/devicetree/bindings/sound/sirf-audio-codec.txt
new file mode 100644
index 000000000000..062f5ec36f9b
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/sirf-audio-codec.txt
@@ -0,0 +1,17 @@
+SiRF internal audio CODEC
+
+Required properties:
+
+ - compatible : "sirf,atlas6-audio-codec" or "sirf,prima2-audio-codec"
+
+ - reg : the register address of the device.
+
+ - clocks: the clock of SiRF internal audio codec
+
+Example:
+
+audiocodec: audiocodec@b0040000 {
+ compatible = "sirf,atlas6-audio-codec";
+ reg = <0xb0040000 0x10000>;
+ clocks = <&clks 27>;
+};
diff --git a/Documentation/devicetree/bindings/sound/sirf-audio-port.txt b/Documentation/devicetree/bindings/sound/sirf-audio-port.txt
new file mode 100644
index 000000000000..1f66de3c8f00
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/sirf-audio-port.txt
@@ -0,0 +1,20 @@
+* SiRF SoC audio port
+
+Required properties:
+- compatible: "sirf,audio-port"
+- reg: Base address and size entries:
+- dmas: List of DMA controller phandle and DMA request line ordered pairs.
+- dma-names: Identifier string for each DMA request line in the dmas property.
+ These strings correspond 1:1 with the ordered pairs in dmas.
+
+ One of the DMA channels will be responsible for transmission (should be
+ named "tx") and one for reception (should be named "rx").
+
+Example:
+
+audioport: audioport@b0040000 {
+ compatible = "sirf,audio-port";
+ reg = <0xb0040000 0x10000>;
+ dmas = <&dmac1 3>, <&dmac1 8>;
+ dma-names = "rx", "tx";
+};
diff --git a/Documentation/devicetree/bindings/sound/sirf-audio.txt b/Documentation/devicetree/bindings/sound/sirf-audio.txt
new file mode 100644
index 000000000000..c88882ca3704
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/sirf-audio.txt
@@ -0,0 +1,41 @@
+* SiRF atlas6 and prima2 internal audio codec and port based audio setups
+
+Required properties:
+- compatible: "sirf,sirf-audio-card"
+- sirf,audio-platform: phandle for the platform node
+- sirf,audio-codec: phandle for the SiRF internal codec node
+
+Optional properties:
+- hp-pa-gpios: Need to be present if the board need control external
+ headphone amplifier.
+- spk-pa-gpios: Need to be present if the board need control external
+ speaker amplifier.
+- hp-switch-gpios: Need to be present if the board capable to detect jack
+ insertion, removal.
+
+Available audio endpoints for the audio-routing table:
+
+Board connectors:
+ * Headset Stereophone
+ * Ext Spk
+ * Line In
+ * Mic
+
+SiRF internal audio codec pins:
+ * HPOUTL
+ * HPOUTR
+ * SPKOUT
+ * Ext Mic
+ * Mic Bias
+
+Example:
+
+sound {
+ compatible = "sirf,sirf-audio-card";
+ sirf,audio-codec = <&audiocodec>;
+ sirf,audio-platform = <&audioport>;
+ hp-pa-gpios = <&gpio 44 0>;
+ spk-pa-gpios = <&gpio 46 0>;
+ hp-switch-gpios = <&gpio 45 0>;
+};
+
diff --git a/Documentation/devicetree/bindings/sound/tdm-slot.txt b/Documentation/devicetree/bindings/sound/tdm-slot.txt
new file mode 100644
index 000000000000..6a2c84247f91
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/tdm-slot.txt
@@ -0,0 +1,20 @@
+TDM slot:
+
+This specifies audio DAI's TDM slot.
+
+TDM slot properties:
+dai-tdm-slot-num : Number of slots in use.
+dai-tdm-slot-width : Width in bits for each slot.
+
+For instance:
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <8>;
+
+And for each spcified driver, there could be one .of_xlate_tdm_slot_mask()
+to specify a explicit mapping of the channels and the slots. If it's absent
+the default snd_soc_of_xlate_tdm_slot_mask() will be used to generating the
+tx and rx masks.
+
+For snd_soc_of_xlate_tdm_slot_mask(), the tx and rx masks will use a 1 bit
+for an active slot as default, and the default active bits are at the LSB of
+the masks.
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
new file mode 100644
index 000000000000..74c66dee3e14
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
@@ -0,0 +1,61 @@
+Texas Instruments - tlv320aic31xx Codec module
+
+The tlv320aic31xx serial control bus communicates through I2C protocols
+
+Required properties:
+
+- compatible - "string" - One of:
+ "ti,tlv320aic310x" - Generic TLV320AIC31xx with mono speaker amp
+ "ti,tlv320aic311x" - Generic TLV320AIC31xx with stereo speaker amp
+ "ti,tlv320aic3100" - TLV320AIC3100 (mono speaker amp, no MiniDSP)
+ "ti,tlv320aic3110" - TLV320AIC3110 (stereo speaker amp, no MiniDSP)
+ "ti,tlv320aic3120" - TLV320AIC3120 (mono speaker amp, MiniDSP)
+ "ti,tlv320aic3111" - TLV320AIC3111 (stereo speaker amp, MiniDSP)
+
+- reg - <int> - I2C slave address
+
+
+Optional properties:
+
+- gpio-reset - gpio pin number used for codec reset
+- ai31xx-micbias-vg - MicBias Voltage setting
+ 1 or MICBIAS_2_0V - MICBIAS output is powered to 2.0V
+ 2 or MICBIAS_2_5V - MICBIAS output is powered to 2.5V
+ 3 or MICBIAS_AVDD - MICBIAS output is connected to AVDD
+ If this node is not mentioned or if the value is unknown, then
+ micbias is set to 2.0V.
+- HPVDD-supply, SPRVDD-supply, SPLVDD-supply, AVDD-supply, IOVDD-supply,
+ DVDD-supply : power supplies for the device as covered in
+ Documentation/devicetree/bindings/regulator/regulator.txt
+
+CODEC output pins:
+ * HPL
+ * HPR
+ * SPL, devices with stereo speaker amp
+ * SPR, devices with stereo speaker amp
+ * SPK, devices with mono speaker amp
+ * MICBIAS
+
+CODEC input pins:
+ * MIC1LP
+ * MIC1RP
+ * MIC1LM
+
+The pins can be used in referring sound node's audio-routing property.
+
+Example:
+#include <dt-bindings/sound/tlv320aic31xx-micbias.h>
+
+tlv320aic31xx: tlv320aic31xx@18 {
+ compatible = "ti,tlv320aic311x";
+ reg = <0x18>;
+
+ ai31xx-micbias-vg = <MICBIAS_OFF>;
+
+ HPVDD-supply = <&regulator>;
+ SPRVDD-supply = <&regulator>;
+ SPLVDD-supply = <&regulator>;
+ AVDD-supply = <&regulator>;
+ IOVDD-supply = <&regulator>;
+ DVDD-supply = <&regulator>;
+};
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt
new file mode 100644
index 000000000000..5e2741af27be
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt
@@ -0,0 +1,30 @@
+Texas Instruments - tlv320aic32x4 Codec module
+
+The tlv320aic32x4 serial control bus communicates through I2C protocols
+
+Required properties:
+ - compatible: Should be "ti,tlv320aic32x4"
+ - reg: I2C slave address
+ - supply-*: Required supply regulators are:
+ "iov" - digital IO power supply
+ "ldoin" - LDO power supply
+ "dv" - Digital core power supply
+ "av" - Analog core power supply
+ If you supply ldoin, dv and av are optional. Otherwise they are required
+ See regulator/regulator.txt for more information about the detailed binding
+ format.
+
+Optional properties:
+ - reset-gpios: Reset-GPIO phandle with args as described in gpio/gpio.txt
+ - clocks/clock-names: Clock named 'mclk' for the master clock of the codec.
+ See clock/clock-bindings.txt for information about the detailed format.
+
+
+Example:
+
+codec: tlv320aic32x4@18 {
+ compatible = "ti,tlv320aic32x4";
+ reg = <0x18>;
+ clocks = <&clks 201>;
+ clock-names = "mclk";
+};
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
index 9d8ea14db490..5e6040c2c2e9 100644
--- a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
+++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
@@ -6,7 +6,6 @@ Required properties:
- compatible - "string" - One of:
"ti,tlv320aic3x" - Generic TLV320AIC3x device
- "ti,tlv320aic32x4" - TLV320AIC32x4
"ti,tlv320aic33" - TLV320AIC33
"ti,tlv320aic3007" - TLV320AIC3007
"ti,tlv320aic3106" - TLV320AIC3106
diff --git a/Documentation/devicetree/bindings/sound/widgets.txt b/Documentation/devicetree/bindings/sound/widgets.txt
new file mode 100644
index 000000000000..b6de5ba3b2de
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/widgets.txt
@@ -0,0 +1,20 @@
+Widgets:
+
+This mainly specifies audio off-codec DAPM widgets.
+
+Each entry is a pair of strings in DT:
+
+ "template-wname", "user-supplied-wname"
+
+The "template-wname" being the template widget name and currently includes:
+"Microphone", "Line", "Headphone" and "Speaker".
+
+The "user-supplied-wname" being the user specified widget name.
+
+For instance:
+ simple-audio-widgets =
+ "Microphone", "Microphone Jack",
+ "Line", "Line In Jack",
+ "Line", "Line Out Jack",
+ "Headphone", "Headphone Jack",
+ "Speaker", "Speaker External";
diff --git a/Documentation/devicetree/bindings/spi/efm32-spi.txt b/Documentation/devicetree/bindings/spi/efm32-spi.txt
index a590ca51be75..8f081c96a4fa 100644
--- a/Documentation/devicetree/bindings/spi/efm32-spi.txt
+++ b/Documentation/devicetree/bindings/spi/efm32-spi.txt
@@ -3,24 +3,24 @@
Required properties:
- #address-cells: see spi-bus.txt
- #size-cells: see spi-bus.txt
-- compatible: should be "efm32,spi"
+- compatible: should be "energymicro,efm32-spi"
- reg: Offset and length of the register set for the controller
- interrupts: pair specifying rx and tx irq
- clocks: phandle to the spi clock
- cs-gpios: see spi-bus.txt
-- location: Value to write to the ROUTE register's LOCATION bitfield to configure the pinmux for the device, see datasheet for values.
+- efm32,location: Value to write to the ROUTE register's LOCATION bitfield to configure the pinmux for the device, see datasheet for values.
Example:
spi1: spi@0x4000c400 { /* USART1 */
#address-cells = <1>;
#size-cells = <0>;
- compatible = "efm32,spi";
+ compatible = "energymicro,efm32-spi";
reg = <0x4000c400 0x400>;
interrupts = <15 16>;
clocks = <&cmu 20>;
cs-gpios = <&gpio 51 1>; // D3
- location = <1>;
+ efm32,location = <1>;
status = "ok";
ks8851@0 {
diff --git a/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt b/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt
new file mode 100644
index 000000000000..b82a268f1bd4
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt
@@ -0,0 +1,85 @@
+Qualcomm Universal Peripheral (QUP) Serial Peripheral Interface (SPI)
+
+The QUP core is an AHB slave that provides a common data path (an output FIFO
+and an input FIFO) for serial peripheral interface (SPI) mini-core.
+
+SPI in master mode supports up to 50MHz, up to four chip selects, programmable
+data path from 4 bits to 32 bits and numerous protocol variants.
+
+Required properties:
+- compatible: Should contain "qcom,spi-qup-v2.1.1" or "qcom,spi-qup-v2.2.1"
+- reg: Should contain base register location and length
+- interrupts: Interrupt number used by this controller
+
+- clocks: Should contain the core clock and the AHB clock.
+- clock-names: Should be "core" for the core clock and "iface" for the
+ AHB clock.
+
+- #address-cells: Number of cells required to define a chip select
+ address on the SPI bus. Should be set to 1.
+- #size-cells: Should be zero.
+
+Optional properties:
+- spi-max-frequency: Specifies maximum SPI clock frequency,
+ Units - Hz. Definition as per
+ Documentation/devicetree/bindings/spi/spi-bus.txt
+
+SPI slave nodes must be children of the SPI master node and can contain
+properties described in Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Example:
+
+ spi_8: spi@f9964000 { /* BLSP2 QUP2 */
+
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xf9964000 0x1000>;
+ interrupts = <0 102 0>;
+ spi-max-frequency = <19200000>;
+
+ clocks = <&gcc GCC_BLSP2_QUP2_SPI_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
+ clock-names = "core", "iface";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi8_default>;
+
+ device@0 {
+ compatible = "arm,pl022-dummy";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <19200000>;
+ spi-cpol;
+ };
+
+ device@1 {
+ compatible = "arm,pl022-dummy";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <1>; /* Chip select 1 */
+ spi-max-frequency = <9600000>;
+ spi-cpha;
+ };
+
+ device@2 {
+ compatible = "arm,pl022-dummy";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <2>; /* Chip select 2 */
+ spi-max-frequency = <19200000>;
+ spi-cpol;
+ spi-cpha;
+ };
+
+ device@3 {
+ compatible = "arm,pl022-dummy";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <3>; /* Chip select 3 */
+ spi-max-frequency = <19200000>;
+ spi-cpol;
+ spi-cpha;
+ spi-cs-high;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/spi/sh-hspi.txt b/Documentation/devicetree/bindings/spi/sh-hspi.txt
index 30b57b1c8a13..319bad4af875 100644
--- a/Documentation/devicetree/bindings/spi/sh-hspi.txt
+++ b/Documentation/devicetree/bindings/spi/sh-hspi.txt
@@ -1,7 +1,29 @@
Renesas HSPI.
Required properties:
-- compatible : "renesas,hspi"
-- reg : Offset and length of the register set for the device
-- interrupts : interrupt line used by HSPI
+- compatible : "renesas,hspi-<soctype>", "renesas,hspi" as fallback.
+ Examples with soctypes are:
+ - "renesas,hspi-r8a7778" (R-Car M1)
+ - "renesas,hspi-r8a7779" (R-Car H1)
+- reg : Offset and length of the register set for the device
+- interrupt-parent : The phandle for the interrupt controller that
+ services interrupts for this device
+- interrupts : Interrupt specifier
+- #address-cells : Must be <1>
+- #size-cells : Must be <0>
+
+Pinctrl properties might be needed, too. See
+Documentation/devicetree/bindings/pinctrl/renesas,*.
+
+Example:
+
+ hspi0: spi@fffc7000 {
+ compatible = "renesas,hspi-r8a7778", "renesas,hspi";
+ reg = <0xfffc7000 0x18>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 63 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
diff --git a/Documentation/devicetree/bindings/spi/sh-msiof.txt b/Documentation/devicetree/bindings/spi/sh-msiof.txt
index e6222106ca36..f24baf3b6cc1 100644
--- a/Documentation/devicetree/bindings/spi/sh-msiof.txt
+++ b/Documentation/devicetree/bindings/spi/sh-msiof.txt
@@ -1,12 +1,40 @@
Renesas MSIOF spi controller
Required properties:
-- compatible : "renesas,sh-msiof" for SuperH or
- "renesas,sh-mobile-msiof" for SH Mobile series
-- reg : Offset and length of the register set for the device
-- interrupts : interrupt line used by MSIOF
+- compatible : "renesas,msiof-<soctype>" for SoCs,
+ "renesas,sh-msiof" for SuperH, or
+ "renesas,sh-mobile-msiof" for SH Mobile series.
+ Examples with soctypes are:
+ "renesas,msiof-r8a7790" (R-Car H2)
+ "renesas,msiof-r8a7791" (R-Car M2)
+- reg : Offset and length of the register set for the device
+- interrupt-parent : The phandle for the interrupt controller that
+ services interrupts for this device
+- interrupts : Interrupt specifier
+- #address-cells : Must be <1>
+- #size-cells : Must be <0>
Optional properties:
-- num-cs : total number of chip-selects
-- renesas,tx-fifo-size : Overrides the default tx fifo size given in words
-- renesas,rx-fifo-size : Overrides the default rx fifo size given in words
+- clocks : Must contain a reference to the functional clock.
+- num-cs : Total number of chip-selects (default is 1)
+
+Optional properties, deprecated for soctype-specific bindings:
+- renesas,tx-fifo-size : Overrides the default tx fifo size given in words
+ (default is 64)
+- renesas,rx-fifo-size : Overrides the default rx fifo size given in words
+ (default is 64, or 256 on R-Car H2 and M2)
+
+Pinctrl properties might be needed, too. See
+Documentation/devicetree/bindings/pinctrl/renesas,*.
+
+Example:
+
+ msiof0: spi@e6e20000 {
+ compatible = "renesas,msiof-r8a7791";
+ reg = <0 0xe6e20000 0 0x0064>;
+ interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp0_clks R8A7791_CLK_MSIOF0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
index a1fb3035a42b..5376de40f10b 100644
--- a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
+++ b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
@@ -10,6 +10,7 @@ Required properties:
- pinctrl-names: must contain a "default" entry.
- spi-num-chipselects : the number of the chipselect signals.
- bus-num : the slave chip chipselect signal number.
+- big-endian : if DSPI modudle is big endian, the bool will be set in node.
Example:
dspi0@4002c000 {
@@ -24,6 +25,7 @@ dspi0@4002c000 {
bus-num = <0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_dspi0_1>;
+ big-endian;
status = "okay";
sflash: at26df081a@0 {
diff --git a/Documentation/devicetree/bindings/spi/spi-rspi.txt b/Documentation/devicetree/bindings/spi/spi-rspi.txt
new file mode 100644
index 000000000000..d57d82a74054
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-rspi.txt
@@ -0,0 +1,61 @@
+Device tree configuration for Renesas RSPI/QSPI driver
+
+Required properties:
+- compatible : For Renesas Serial Peripheral Interface on legacy SH:
+ "renesas,rspi-<soctype>", "renesas,rspi" as fallback.
+ For Renesas Serial Peripheral Interface on RZ/A1H:
+ "renesas,rspi-<soctype>", "renesas,rspi-rz" as fallback.
+ For Quad Serial Peripheral Interface on R-Car Gen2:
+ "renesas,qspi-<soctype>", "renesas,qspi" as fallback.
+ Examples with soctypes are:
+ - "renesas,rspi-sh7757" (SH)
+ - "renesas,rspi-r7s72100" (RZ/A1H)
+ - "renesas,qspi-r8a7790" (R-Car H2)
+ - "renesas,qspi-r8a7791" (R-Car M2)
+- reg : Address start and address range size of the device
+- interrupts : A list of interrupt-specifiers, one for each entry in
+ interrupt-names.
+ If interrupt-names is not present, an interrupt specifier
+ for a single muxed interrupt.
+- interrupt-names : A list of interrupt names. Should contain (if present):
+ - "error" for SPEI,
+ - "rx" for SPRI,
+ - "tx" to SPTI,
+ - "mux" for a single muxed interrupt.
+- interrupt-parent : The phandle for the interrupt controller that
+ services interrupts for this device.
+- num-cs : Number of chip selects. Some RSPI cores have more than 1.
+- #address-cells : Must be <1>
+- #size-cells : Must be <0>
+
+Optional properties:
+- clocks : Must contain a reference to the functional clock.
+
+Pinctrl properties might be needed, too. See
+Documentation/devicetree/bindings/pinctrl/renesas,*.
+
+Examples:
+
+ spi0: spi@e800c800 {
+ compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz";
+ reg = <0xe800c800 0x24>;
+ interrupts = <0 238 IRQ_TYPE_LEVEL_HIGH>,
+ <0 239 IRQ_TYPE_LEVEL_HIGH>,
+ <0 240 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "error", "rx", "tx";
+ interrupt-parent = <&gic>;
+ num-cs = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ spi: spi@e6b10000 {
+ compatible = "renesas,qspi-r8a7791", "renesas,qspi";
+ reg = <0 0xe6b10000 0 0x2c>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7791_CLK_QSPI_MOD>;
+ num-cs = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/spi/spi-sun4i.txt b/Documentation/devicetree/bindings/spi/spi-sun4i.txt
new file mode 100644
index 000000000000..de827f5a301e
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-sun4i.txt
@@ -0,0 +1,24 @@
+Allwinner A10 SPI controller
+
+Required properties:
+- compatible: Should be "allwinner,sun4-a10-spi".
+- reg: Should contain register location and length.
+- interrupts: Should contain interrupt.
+- clocks: phandle to the clocks feeding the SPI controller. Two are
+ needed:
+ - "ahb": the gated AHB parent clock
+ - "mod": the parent module clock
+- clock-names: Must contain the clock names described just above
+
+Example:
+
+spi1: spi@01c06000 {
+ compatible = "allwinner,sun4i-a10-spi";
+ reg = <0x01c06000 0x1000>;
+ interrupts = <11>;
+ clocks = <&ahb_gates 21>, <&spi1_clk>;
+ clock-names = "ahb", "mod";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/spi/spi-sun6i.txt b/Documentation/devicetree/bindings/spi/spi-sun6i.txt
new file mode 100644
index 000000000000..21de73db6a05
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-sun6i.txt
@@ -0,0 +1,24 @@
+Allwinner A31 SPI controller
+
+Required properties:
+- compatible: Should be "allwinner,sun6i-a31-spi".
+- reg: Should contain register location and length.
+- interrupts: Should contain interrupt.
+- clocks: phandle to the clocks feeding the SPI controller. Two are
+ needed:
+ - "ahb": the gated AHB parent clock
+ - "mod": the parent module clock
+- clock-names: Must contain the clock names described just above
+- resets: phandle to the reset controller asserting this device in
+ reset
+
+Example:
+
+spi1: spi@01c69000 {
+ compatible = "allwinner,sun6i-a31-spi";
+ reg = <0x01c69000 0x1000>;
+ interrupts = <0 66 4>;
+ clocks = <&ahb1_gates 21>, <&spi1_clk>;
+ clock-names = "ahb", "mod";
+ resets = <&ahb1_rst 21>;
+};
diff --git a/Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt b/Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt
new file mode 100644
index 000000000000..b6ebe2bc7041
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt
@@ -0,0 +1,9 @@
+Cadence Xtensa XTFPGA platform SPI controller.
+
+This simple SPI master controller is built into xtfpga bitstreams and is used
+to control daughterboard audio codec.
+
+Required properties:
+- compatible: should be "cdns,xtfpga-spi".
+- reg: physical base address of the controller and length of memory mapped
+ region.
diff --git a/Documentation/devicetree/bindings/spi/spi_atmel.txt b/Documentation/devicetree/bindings/spi/spi_atmel.txt
index 07e04cdc0c9e..4f8184d069cb 100644
--- a/Documentation/devicetree/bindings/spi/spi_atmel.txt
+++ b/Documentation/devicetree/bindings/spi/spi_atmel.txt
@@ -5,6 +5,9 @@ Required properties:
- reg: Address and length of the register set for the device
- interrupts: Should contain spi interrupt
- cs-gpios: chipselects
+- clock-names: tuple listing input clock names.
+ Required elements: "spi_clk"
+- clocks: phandles to input clocks.
Example:
@@ -14,6 +17,8 @@ spi1: spi@fffcc000 {
interrupts = <13 4 5>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&spi1_clk>;
+ clock-names = "spi_clk";
cs-gpios = <&pioB 3 0>;
status = "okay";
diff --git a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt
new file mode 100644
index 000000000000..715d0998af8e
--- /dev/null
+++ b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt
@@ -0,0 +1,61 @@
+Qualcomm SPMI Controller (PMIC Arbiter)
+
+The SPMI PMIC Arbiter is found on the Snapdragon 800 Series. It is an SPMI
+controller with wrapping arbitration logic to allow for multiple on-chip
+devices to control a single SPMI master.
+
+The PMIC Arbiter can also act as an interrupt controller, providing interrupts
+to slave devices.
+
+See spmi.txt for the generic SPMI controller binding requirements for child
+nodes.
+
+See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt for
+generic interrupt controller binding documentation.
+
+Required properties:
+- compatible : should be "qcom,spmi-pmic-arb".
+- reg-names : must contain:
+ "core" - core registers
+ "intr" - interrupt controller registers
+ "cnfg" - configuration registers
+- reg : address + size pairs describing the PMIC arb register sets; order must
+ correspond with the order of entries in reg-names
+- #address-cells : must be set to 2
+- #size-cells : must be set to 0
+- qcom,ee : indicates the active Execution Environment identifier (0-5)
+- qcom,channel : which of the PMIC Arb provided channels to use for accesses (0-5)
+- interrupts : interrupt list for the PMIC Arb controller, must contain a
+ single interrupt entry for the peripheral interrupt
+- interrupt-names : corresponding interrupt names for the interrupts
+ listed in the 'interrupts' property, must contain:
+ "periph_irq" - summary interrupt for PMIC peripherals
+- interrupt-controller : boolean indicator that the PMIC arbiter is an interrupt controller
+- #interrupt-cells : must be set to 4. Interrupts are specified as a 4-tuple:
+ cell 1: slave ID for the requested interrupt (0-15)
+ cell 2: peripheral ID for requested interrupt (0-255)
+ cell 3: the requested peripheral interrupt (0-7)
+ cell 4: interrupt flags indicating level-sense information, as defined in
+ dt-bindings/interrupt-controller/irq.h
+
+Example:
+
+ spmi {
+ compatible = "qcom,spmi-pmic-arb";
+ reg-names = "core", "intr", "cnfg";
+ reg = <0xfc4cf000 0x1000>,
+ <0xfc4cb000 0x1000>,
+ <0xfc4ca000 0x1000>;
+
+ interrupt-names = "periph_irq";
+ interrupts = <0 190 0>;
+
+ qcom,ee = <0>;
+ qcom,channel = <0>;
+
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ interrupt-controller;
+ #interrupt-cells = <4>;
+ };
diff --git a/Documentation/devicetree/bindings/spmi/spmi.txt b/Documentation/devicetree/bindings/spmi/spmi.txt
new file mode 100644
index 000000000000..462a42fb3a1e
--- /dev/null
+++ b/Documentation/devicetree/bindings/spmi/spmi.txt
@@ -0,0 +1,41 @@
+System Power Management Interface (SPMI) Controller
+
+This document defines a generic set of bindings for use by SPMI controllers. A
+controller is modelled in device tree as a node with zero or more child nodes,
+each representing a unique slave on the bus.
+
+Required properties:
+- #address-cells : must be set to 2
+- #size-cells : must be set to 0
+
+Child nodes:
+
+An SPMI controller node can contain zero or more child nodes representing slave
+devices on the bus. Child 'reg' properties are specified as an address, type
+pair. The address must be in the range 0-15 (4 bits). The type must be one of
+SPMI_USID (0) or SPMI_GSID (1) for Unique Slave ID or Group Slave ID respectively.
+These are the identifiers "statically assigned by the system integrator", as
+per the SPMI spec.
+
+Each child node must have one and only one 'reg' entry of type SPMI_USID.
+
+#include <dt-bindings/spmi/spmi.h>
+
+ spmi@.. {
+ compatible = "...";
+ reg = <...>;
+
+ #address-cells = <2>;
+ #size-cells <0>;
+
+ child@0 {
+ compatible = "...";
+ reg = <0 SPMI_USID>;
+ };
+
+ child@7 {
+ compatible = "...";
+ reg = <7 SPMI_USID
+ 3 SPMI_GSID>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
index b876d4925a57..3be5ce7a9654 100644
--- a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
+++ b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
@@ -1,3 +1,22 @@
+Freescale i.MX DRM master device
+================================
+
+The freescale i.MX DRM master device is a virtual device needed to list all
+IPU or other display interface nodes that comprise the graphics subsystem.
+
+Required properties:
+- compatible: Should be "fsl,imx-display-subsystem"
+- ports: Should contain a list of phandles pointing to display interface ports
+ of IPU devices
+
+example:
+
+display-subsystem {
+ compatible = "fsl,display-subsystem";
+ ports = <&ipu_di0>;
+};
+
+
Freescale i.MX IPUv3
====================
@@ -7,18 +26,31 @@ Required properties:
datasheet
- interrupts: Should contain sync interrupt and error interrupt,
in this order.
-- #crtc-cells: 1, See below
- resets: phandle pointing to the system reset controller and
reset line index, see reset/fsl,imx-src.txt for details
+Optional properties:
+- port@[0-3]: Port nodes with endpoint definitions as defined in
+ Documentation/devicetree/bindings/media/video-interfaces.txt.
+ Ports 0 and 1 should correspond to CSI0 and CSI1,
+ ports 2 and 3 should correspond to DI0 and DI1, respectively.
example:
ipu: ipu@18000000 {
- #crtc-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
compatible = "fsl,imx53-ipu";
reg = <0x18000000 0x080000000>;
interrupts = <11 10>;
resets = <&src 2>;
+
+ ipu_di0: port@2 {
+ reg = <2>;
+
+ ipu_di0_disp0: endpoint {
+ remote-endpoint = <&display_in>;
+ };
+ };
};
Parallel display support
@@ -26,19 +58,25 @@ Parallel display support
Required properties:
- compatible: Should be "fsl,imx-parallel-display"
-- crtc: the crtc this display is connected to, see below
Optional properties:
- interface_pix_fmt: How this display is connected to the
- crtc. Currently supported types: "rgb24", "rgb565", "bgr666"
+ display interface. Currently supported types: "rgb24", "rgb565", "bgr666"
- edid: verbatim EDID data block describing attached display.
- ddc: phandle describing the i2c bus handling the display data
channel
+- port: A port node with endpoint definitions as defined in
+ Documentation/devicetree/bindings/media/video-interfaces.txt.
example:
display@di0 {
compatible = "fsl,imx-parallel-display";
edid = [edid-data];
- crtc = <&ipu 0>;
interface-pix-fmt = "rgb24";
+
+ port {
+ display_in: endpoint {
+ remote-endpoint = <&ipu_di0_disp0>;
+ };
+ };
};
diff --git a/Documentation/devicetree/bindings/staging/imx-drm/hdmi.txt b/Documentation/devicetree/bindings/staging/imx-drm/hdmi.txt
new file mode 100644
index 000000000000..1b756cf9afb0
--- /dev/null
+++ b/Documentation/devicetree/bindings/staging/imx-drm/hdmi.txt
@@ -0,0 +1,58 @@
+Device-Tree bindings for HDMI Transmitter
+
+HDMI Transmitter
+================
+
+The HDMI Transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
+with accompanying PHY IP.
+
+Required properties:
+ - #address-cells : should be <1>
+ - #size-cells : should be <0>
+ - compatible : should be "fsl,imx6q-hdmi" or "fsl,imx6dl-hdmi".
+ - gpr : should be <&gpr>.
+ The phandle points to the iomuxc-gpr region containing the HDMI
+ multiplexer control register.
+ - clocks, clock-names : phandles to the HDMI iahb and isrf clocks, as described
+ in Documentation/devicetree/bindings/clock/clock-bindings.txt and
+ Documentation/devicetree/bindings/clock/imx6q-clock.txt.
+ - port@[0-4]: Up to four port nodes with endpoint definitions as defined in
+ Documentation/devicetree/bindings/media/video-interfaces.txt,
+ corresponding to the four inputs to the HDMI multiplexer.
+
+Optional properties:
+ - ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+
+example:
+
+ gpr: iomuxc-gpr@020e0000 {
+ /* ... */
+ };
+
+ hdmi: hdmi@0120000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,imx6q-hdmi";
+ reg = <0x00120000 0x9000>;
+ interrupts = <0 115 0x04>;
+ gpr = <&gpr>;
+ clocks = <&clks 123>, <&clks 124>;
+ clock-names = "iahb", "isfr";
+ ddc-i2c-bus = <&i2c2>;
+
+ port@0 {
+ reg = <0>;
+
+ hdmi_mux_0: endpoint {
+ remote-endpoint = <&ipu1_di0_hdmi>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ hdmi_mux_1: endpoint {
+ remote-endpoint = <&ipu1_di1_hdmi>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt b/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt
index ed9377811ee2..578a1fca366e 100644
--- a/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt
+++ b/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt
@@ -50,12 +50,14 @@ have a look at Documentation/devicetree/bindings/video/display-timing.txt.
Required properties:
- reg : should be <0> or <1>
- - crtcs : a list of phandles with index pointing to the IPU display interfaces
- that can be used as video source for this channel.
- fsl,data-mapping : should be "spwg" or "jeida"
This describes how the color bits are laid out in the
serialized LVDS signal.
- fsl,data-width : should be <18> or <24>
+ - port: A port node with endpoint definitions as defined in
+ Documentation/devicetree/bindings/media/video-interfaces.txt.
+ On i.MX6, there should be four ports (port@[0-3]) that correspond
+ to the four LVDS multiplexer inputs.
example:
@@ -77,23 +79,33 @@ ldb: ldb@53fa8008 {
lvds-channel@0 {
reg = <0>;
- crtcs = <&ipu 0>;
fsl,data-mapping = "spwg";
fsl,data-width = <24>;
display-timings {
/* ... */
};
+
+ port {
+ lvds0_in: endpoint {
+ remote-endpoint = <&ipu_di0_lvds0>;
+ };
+ };
};
lvds-channel@1 {
reg = <1>;
- crtcs = <&ipu 1>;
fsl,data-mapping = "spwg";
fsl,data-width = <24>;
display-timings {
/* ... */
};
+
+ port {
+ lvds1_in: endpoint {
+ remote-endpoint = <&ipu_di1_lvds1>;
+ };
+ };
};
};
diff --git a/Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt b/Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt
index 48aeb7884ed3..5c2e23574ca0 100644
--- a/Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt
+++ b/Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt
@@ -2,7 +2,7 @@ Allwinner A1X SoCs Timer Controller
Required properties:
-- compatible : should be "allwinner,sun4i-timer"
+- compatible : should be "allwinner,sun4i-a10-timer"
- reg : Specifies base physical address and size of the registers.
- interrupts : The interrupt of the first timer
- clocks: phandle to the source clock (usually a 24 MHz fixed clock)
@@ -10,7 +10,7 @@ Required properties:
Example:
timer {
- compatible = "allwinner,sun4i-timer";
+ compatible = "allwinner,sun4i-a10-timer";
reg = <0x01c20c00 0x400>;
interrupts = <22>;
clocks = <&osc>;
diff --git a/Documentation/devicetree/bindings/timer/ti,keystone-timer.txt b/Documentation/devicetree/bindings/timer/ti,keystone-timer.txt
new file mode 100644
index 000000000000..5fbe361252b4
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/ti,keystone-timer.txt
@@ -0,0 +1,29 @@
+* Device tree bindings for Texas instruments Keystone timer
+
+This document provides bindings for the 64-bit timer in the KeyStone
+architecture devices. The timer can be configured as a general-purpose 64-bit
+timer, dual general-purpose 32-bit timers. When configured as dual 32-bit
+timers, each half can operate in conjunction (chain mode) or independently
+(unchained mode) of each other.
+
+It is global timer is a free running up-counter and can generate interrupt
+when the counter reaches preset counter values.
+
+Documentation:
+http://www.ti.com/lit/ug/sprugv5a/sprugv5a.pdf
+
+Required properties:
+
+- compatible : should be "ti,keystone-timer".
+- reg : specifies base physical address and count of the registers.
+- interrupts : interrupt generated by the timer.
+- clocks : the clock feeding the timer clock.
+
+Example:
+
+timer@22f0000 {
+ compatible = "ti,keystone-timer";
+ reg = <0x022f0000 0x80>;
+ interrupts = <GIC_SPI 110 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&clktimer15>;
+};
diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt
index b4b5b7906c88..a6a32cb7f777 100644
--- a/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt
+++ b/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt
@@ -18,6 +18,7 @@ Optional properties:
- vbus-supply: regulator for vbus
- disable-over-current: disable over current detect
- external-vbus-divider: enables off-chip resistor divider for Vbus
+- maximum-speed: limit the maximum connection speed to "full-speed".
Examples:
usb@02184000 { /* USB OTG */
@@ -28,4 +29,5 @@ usb@02184000 { /* USB OTG */
fsl,usbmisc = <&usbmisc 0>;
disable-over-current;
external-vbus-divider;
+ maximum-speed = "full-speed";
};
diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-zevio.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-zevio.txt
new file mode 100644
index 000000000000..abbcb2aea38c
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/ci-hdrc-zevio.txt
@@ -0,0 +1,17 @@
+* LSI Zevio USB OTG Controller
+
+Required properties:
+- compatible: Should be "lsi,zevio-usb"
+- reg: Should contain registers location and length
+- interrupts: Should contain controller interrupt
+
+Optional properties:
+- vbus-supply: regulator for vbus
+
+Examples:
+ usb0: usb@b0000000 {
+ reg = <0xb0000000 0x1000>;
+ compatible = "lsi,zevio-usb";
+ interrupts = <8>;
+ vbus-supply = <&vbus_reg>;
+ };
diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt
index e807635f9e1c..471366d6a129 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -6,11 +6,13 @@ Required properties:
- compatible: must be "snps,dwc3"
- reg : Address and length of the register set for the device
- interrupts: Interrupts used by the dwc3 controller.
+
+Optional properties:
- usb-phy : array of phandle for the PHY device. The first element
in the array is expected to be a handle to the USB2/HS PHY and
the second element is expected to be a handle to the USB3/SS PHY
-
-Optional properties:
+ - phys: from the *Generic PHY* bindings
+ - phy-names: from the *Generic PHY* bindings
- tx-fifo-resize: determines if the FIFO *has* to be reallocated.
This is usually a subnode to DWC3 glue to which it is connected.
diff --git a/Documentation/devicetree/bindings/usb/fsl-usb.txt b/Documentation/devicetree/bindings/usb/fsl-usb.txt
index bd5723f0b67e..4779c029b675 100644
--- a/Documentation/devicetree/bindings/usb/fsl-usb.txt
+++ b/Documentation/devicetree/bindings/usb/fsl-usb.txt
@@ -8,7 +8,9 @@ and additions :
Required properties :
- compatible : Should be "fsl-usb2-mph" for multi port host USB
controllers, or "fsl-usb2-dr" for dual role USB controllers
- or "fsl,mpc5121-usb2-dr" for dual role USB controllers of MPC5121
+ or "fsl,mpc5121-usb2-dr" for dual role USB controllers of MPC5121.
+ Wherever applicable, the IP version of the USB controller should
+ also be mentioned (for eg. fsl-usb2-dr-v2.2 for bsc9132).
- phy_type : For multi port host USB controllers, should be one of
"ulpi", or "serial". For dual role USB controllers, should be
one of "ulpi", "utmi", "utmi_wide", or "serial".
diff --git a/Documentation/devicetree/bindings/usb/mxs-phy.txt b/Documentation/devicetree/bindings/usb/mxs-phy.txt
index 5835b27146ea..cef181a9d8bd 100644
--- a/Documentation/devicetree/bindings/usb/mxs-phy.txt
+++ b/Documentation/devicetree/bindings/usb/mxs-phy.txt
@@ -1,13 +1,19 @@
* Freescale MXS USB Phy Device
Required properties:
-- compatible: Should be "fsl,imx23-usbphy"
+- compatible: should contain:
+ * "fsl,imx23-usbphy" for imx23 and imx28
+ * "fsl,imx6q-usbphy" for imx6dq and imx6dl
+ * "fsl,imx6sl-usbphy" for imx6sl
+ "fsl,imx23-usbphy" is still a fallback for other strings
- reg: Should contain registers location and length
- interrupts: Should contain phy interrupt
+- fsl,anatop: phandle for anatop register, it is only for imx6 SoC series
Example:
usbphy1: usbphy@020c9000 {
compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy";
reg = <0x020c9000 0x1000>;
interrupts = <0 44 0x04>;
+ fsl,anatop = <&anatop>;
};
diff --git a/Documentation/devicetree/bindings/usb/omap-usb.txt b/Documentation/devicetree/bindings/usb/omap-usb.txt
index c495135115cb..38b2faec4199 100644
--- a/Documentation/devicetree/bindings/usb/omap-usb.txt
+++ b/Documentation/devicetree/bindings/usb/omap-usb.txt
@@ -76,27 +76,3 @@ omap_dwc3 {
ranges;
};
-OMAP CONTROL USB
-
-Required properties:
- - compatible: Should be one of
- "ti,control-phy-otghs" - if it has otghs_control mailbox register as on OMAP4.
- "ti,control-phy-usb2" - if it has Power down bit in control_dev_conf register
- e.g. USB2_PHY on OMAP5.
- "ti,control-phy-pipe3" - if it has DPLL and individual Rx & Tx power control
- e.g. USB3 PHY and SATA PHY on OMAP5.
- "ti,control-phy-dra7usb2" - if it has power down register like USB2 PHY on
- DRA7 platform.
- "ti,control-phy-am437usb2" - if it has power down register like USB2 PHY on
- AM437 platform.
- - reg : Address and length of the register set for the device. It contains
- the address of "otghs_control" for control-phy-otghs or "power" register
- for other types.
- - reg-names: should be "otghs_control" control-phy-otghs and "power" for
- other types.
-
-omap_control_usb: omap-control-usb@4a002300 {
- compatible = "ti,control-phy-otghs";
- reg = <0x4a00233c 0x4>;
- reg-names = "otghs_control";
-};
diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
index fa18612f757b..ff151ec084c4 100644
--- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
@@ -1,19 +1,20 @@
USB EHCI controllers
Required properties:
- - compatible : should be "usb-ehci".
+ - compatible : should be "generic-ehci".
- reg : should contain at least address and length of the standard EHCI
register set for the device. Optional platform-dependent registers
(debug-port or other) can be also specified here, but only after
definition of standard EHCI registers.
- interrupts : one EHCI interrupt should be described here.
-If device registers are implemented in big endian mode, the device
-node should have "big-endian-regs" property.
-If controller implementation operates with big endian descriptors,
-"big-endian-desc" property should be specified.
-If both big endian registers and descriptors are used by the controller
-implementation, "big-endian" property can be specified instead of having
-both "big-endian-regs" and "big-endian-desc".
+
+Optional properties:
+ - big-endian-regs : boolean, set this for hcds with big-endian registers
+ - big-endian-desc : boolean, set this for hcds with big-endian descriptors
+ - big-endian : boolean, for hcds with big-endian-regs + big-endian-desc
+ - clocks : a list of phandle + clock specifier pairs
+ - phys : phandle + phy specifier pair
+ - phy-names : "usb"
Example (Sequoia 440EPx):
ehci@e0000300 {
@@ -23,3 +24,13 @@ Example (Sequoia 440EPx):
reg = <0 e0000300 90 0 e0000390 70>;
big-endian;
};
+
+Example (Allwinner sun4i A10 SoC):
+ ehci0: usb@01c14000 {
+ compatible = "allwinner,sun4i-a10-ehci", "generic-ehci";
+ reg = <0x01c14000 0x100>;
+ interrupts = <39>;
+ clocks = <&ahb_gates 1>;
+ phys = <&usbphy 1>;
+ phy-names = "usb";
+ };
diff --git a/Documentation/devicetree/bindings/usb/usb-ohci.txt b/Documentation/devicetree/bindings/usb/usb-ohci.txt
new file mode 100644
index 000000000000..45f67d91e888
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/usb-ohci.txt
@@ -0,0 +1,25 @@
+USB OHCI controllers
+
+Required properties:
+- compatible : "generic-ohci"
+- reg : ohci controller register range (address and length)
+- interrupts : ohci controller interrupt
+
+Optional properties:
+- big-endian-regs : boolean, set this for hcds with big-endian registers
+- big-endian-desc : boolean, set this for hcds with big-endian descriptors
+- big-endian : boolean, for hcds with big-endian-regs + big-endian-desc
+- clocks : a list of phandle + clock specifier pairs
+- phys : phandle + phy specifier pair
+- phy-names : "usb"
+
+Example:
+
+ ohci0: usb@01c14400 {
+ compatible = "allwinner,sun4i-a10-ohci", "generic-ohci";
+ reg = <0x01c14400 0x100>;
+ interrupts = <64>;
+ clocks = <&usb_clk 6>, <&ahb_gates 2>;
+ phys = <&usbphy 1>;
+ phy-names = "usb";
+ };
diff --git a/Documentation/devicetree/bindings/usb/usb-phy.txt b/Documentation/devicetree/bindings/usb/usb-phy.txt
deleted file mode 100644
index c0245c888982..000000000000
--- a/Documentation/devicetree/bindings/usb/usb-phy.txt
+++ /dev/null
@@ -1,48 +0,0 @@
-USB PHY
-
-OMAP USB2 PHY
-
-Required properties:
- - compatible: Should be "ti,omap-usb2"
- - reg : Address and length of the register set for the device.
- - #phy-cells: determine the number of cells that should be given in the
- phandle while referencing this phy.
-
-Optional properties:
- - ctrl-module : phandle of the control module used by PHY driver to power on
- the PHY.
-
-This is usually a subnode of ocp2scp to which it is connected.
-
-usb2phy@4a0ad080 {
- compatible = "ti,omap-usb2";
- reg = <0x4a0ad080 0x58>;
- ctrl-module = <&omap_control_usb>;
- #phy-cells = <0>;
-};
-
-OMAP USB3 PHY
-
-Required properties:
- - compatible: Should be "ti,omap-usb3"
- - reg : Address and length of the register set for the device.
- - reg-names: The names of the register addresses corresponding to the registers
- filled in "reg".
- - #phy-cells: determine the number of cells that should be given in the
- phandle while referencing this phy.
-
-Optional properties:
- - ctrl-module : phandle of the control module used by PHY driver to power on
- the PHY.
-
-This is usually a subnode of ocp2scp to which it is connected.
-
-usb3phy@4a084400 {
- compatible = "ti,omap-usb3";
- reg = <0x4a084400 0x80>,
- <0x4a084800 0x64>,
- <0x4a084c00 0x40>;
- reg-names = "phy_rx", "phy_tx", "pll_ctrl";
- ctrl-module = <&omap_control_usb>;
- #phy-cells = <0>;
-};
diff --git a/Documentation/devicetree/bindings/usb/platform-uhci.txt b/Documentation/devicetree/bindings/usb/usb-uhci.txt
index a4fb0719d157..298133416c97 100644
--- a/Documentation/devicetree/bindings/usb/platform-uhci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-uhci.txt
@@ -2,14 +2,14 @@ Generic Platform UHCI Controller
-----------------------------------------------------
Required properties:
-- compatible : "platform-uhci"
+- compatible : "generic-uhci" (deprecated: "platform-uhci")
- reg : Should contain 1 register ranges(address and length)
- interrupts : UHCI controller interrupt
Example:
uhci@d8007b00 {
- compatible = "platform-uhci";
+ compatible = "generic-uhci";
reg = <0xd8007b00 0x200>;
interrupts = <43>;
};
diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt
index 5752df0e17a2..90f8f607d125 100644
--- a/Documentation/devicetree/bindings/usb/usb-xhci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt
@@ -1,14 +1,14 @@
USB xHCI controllers
Required properties:
- - compatible: should be "xhci-platform".
+ - compatible: should be "generic-xhci" (deprecated: "xhci-platform").
- reg: should contain address and length of the standard XHCI
register set for the device.
- interrupts: one XHCI interrupt should be described here.
Example:
usb@f0931000 {
- compatible = "xhci-platform";
+ compatible = "generic-xhci";
reg = <0xf0931000 0x8c8>;
interrupts = <0x0 0x4e 0x0>;
};
diff --git a/Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt b/Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt
deleted file mode 100644
index 17b3ad1d97e7..000000000000
--- a/Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-VIA/Wondermedia VT8500 EHCI Controller
------------------------------------------------------
-
-Required properties:
-- compatible : "via,vt8500-ehci"
-- reg : Should contain 1 register ranges(address and length)
-- interrupts : ehci controller interrupt
-
-Example:
-
- ehci@d8007900 {
- compatible = "via,vt8500-ehci";
- reg = <0xd8007900 0x200>;
- interrupts = <43>;
- };
diff --git a/Documentation/devicetree/bindings/usb/vt8500-ehci.txt b/Documentation/devicetree/bindings/usb/vt8500-ehci.txt
deleted file mode 100644
index 5fb8fd6e250c..000000000000
--- a/Documentation/devicetree/bindings/usb/vt8500-ehci.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-VIA VT8500 and Wondermedia WM8xxx SoC USB controllers.
-
-Required properties:
- - compatible: Should be "via,vt8500-ehci" or "wm,prizm-ehci".
- - reg: Address range of the ehci registers. size should be 0x200
- - interrupts: Should contain the ehci interrupt.
-
-usb: ehci@D8007100 {
- compatible = "wm,prizm-ehci", "usb-ehci";
- reg = <0xD8007100 0x200>;
- interrupts = <1>;
-};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 3f900cd51bf0..95465d57eb31 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -3,21 +3,26 @@ Device tree binding vendor prefix registry. Keep list in alphabetical order.
This isn't an exhaustive list, but you should add new prefixes to it before
using them to avoid name-space collisions.
+abilis Abilis Systems
active-semi Active-Semi International Inc
ad Avionic Design GmbH
adi Analog Devices, Inc.
aeroflexgaisler Aeroflex Gaisler AB
ak Asahi Kasei Corp.
+allwinner Allwinner Technology Co., Ltd.
altr Altera Corp.
amcc Applied Micro Circuits Corporation (APM, formally AMCC)
+amd Advanced Micro Devices (AMD), Inc.
amstaos AMS-Taos Inc.
apm Applied Micro Circuits Corporation (APM)
arm ARM Ltd.
+armadeus ARMadeus Systems SARL
atmel Atmel Corporation
auo AU Optronics Corporation
avago Avago Technologies
bosch Bosch Sensortec GmbH
brcm Broadcom Corporation
+calxeda Calxeda
capella Capella Microsystems, Inc
cavium Cavium, Inc.
cdns Cadence Design Systems Inc.
@@ -25,8 +30,10 @@ chrp Common Hardware Reference Platform
chunghwa Chunghwa Picture Tubes Ltd.
cirrus Cirrus Logic, Inc.
cortina Cortina Systems, Inc.
+crystalfontz Crystalfontz America, Inc.
dallas Maxim Integrated Products (formerly Dallas Semiconductor)
davicom DAVICOM Semiconductor, Inc.
+dlink D-Link Systems, Inc.
denx Denx Software Engineering
edt Emerging Display Technologies
emmicro EM Microelectronic
@@ -36,17 +43,23 @@ est ESTeem Wireless Modems
fsl Freescale Semiconductor
GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc.
gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+globalscale Globalscale Technologies, Inc.
gmt Global Mixed-mode Technology, Inc.
+google Google, Inc.
gumstix Gumstix, Inc.
haoyu Haoyu Microelectronic Co. Ltd.
hisilicon Hisilicon Limited.
+honeywell Honeywell
hp Hewlett Packard
ibm International Business Machines (IBM)
idt Integrated Device Technologies, Inc.
img Imagination Technologies Ltd.
+intel Intel Corporation
intercontrol Inter Control Group
isl Intersil
karo Ka-Ro electronics GmbH
+lacie LaCie
+lantiq Lantiq Semiconductor
lg LG Corporation
linux Linux-specific binding
lsi LSI Corp. (LSI Logic)
@@ -54,17 +67,22 @@ marvell Marvell Technology Group Ltd.
maxim Maxim Integrated Products
microchip Microchip Technology Inc.
mosaixtech Mosaix Technologies, Inc.
+moxa Moxa
national National Semiconductor
+neonode Neonode Inc.
+netgear NETGEAR
nintendo Nintendo
+nokia Nokia
nvidia NVIDIA
nxp NXP Semiconductors
onnn ON Semiconductor Corp.
+opencores OpenCores.org
panasonic Panasonic Corporation
phytec PHYTEC Messtechnik GmbH
picochip Picochip Ltd
powervr PowerVR (deprecated, use img)
qca Qualcomm Atheros, Inc.
-qcom Qualcomm, Inc.
+qcom Qualcomm Technologies, Inc
ralink Mediatek/Ralink Technology Corp.
ramtron Ramtron International
realtek Realtek Semiconductor Corp.
@@ -77,7 +95,9 @@ sil Silicon Image
silabs Silicon Laboratories
simtek
sirf SiRF Technology, Inc.
+smsc Standard Microsystems Corporation
snps Synopsys, Inc.
+spansion Spansion Inc.
st STMicroelectronics
ste ST-Ericsson
stericsson ST-Ericsson
@@ -90,4 +110,5 @@ via VIA Technologies, Inc.
winbond Winbond Electronics corp.
wlf Wolfson Microelectronics
wm Wondermedia Technologies, Inc.
+xes Extreme Engineering Solutions (X-ES)
xlnx Xilinx
diff --git a/Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt b/Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt
new file mode 100644
index 000000000000..6d63782a7378
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt
@@ -0,0 +1,23 @@
+Xilinx AXI/PLB soft-core watchdog Device Tree Bindings
+---------------------------------------------------------
+
+Required properties:
+- compatible : Should be "xlnx,xps-timebase-wdt-1.00.a" or
+ "xlnx,xps-timebase-wdt-1.01.a".
+- reg : Physical base address and size
+
+Optional properties:
+- clock-frequency : Frequency of clock in Hz
+- xlnx,wdt-enable-once : 0 - Watchdog can be restarted
+ 1 - Watchdog can be enabled just once
+- xlnx,wdt-interval : Watchdog timeout interval in 2^<val> clock cycles,
+ <val> is integer from 8 to 31.
+
+Example:
+axi-timebase-wdt@40100000 {
+ clock-frequency = <50000000>;
+ compatible = "xlnx,xps-timebase-wdt-1.00.a";
+ reg = <0x40100000 0x10000>;
+ xlnx,wdt-enable-once = <0x0>;
+ xlnx,wdt-interval = <0x1b>;
+} ;
diff --git a/Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt b/Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt
index e39cb266c8f4..b8f75c51453a 100644
--- a/Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt
@@ -2,13 +2,13 @@ Allwinner SoCs Watchdog timer
Required properties:
-- compatible : should be "allwinner,<soc-family>-wdt", the currently supported
- SoC families being sun4i and sun6i
+- compatible : should be either "allwinner,sun4i-a10-wdt" or
+ "allwinner,sun6i-a31-wdt"
- reg : Specifies base physical address and size of the registers.
Example:
wdt: watchdog@01c20c90 {
- compatible = "allwinner,sun4i-wdt";
+ compatible = "allwinner,sun4i-a10-wdt";
reg = <0x01c20c90 0x10>;
};
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
index 5d5ee4c13fa6..d91b8be80b66 100755
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -28,8 +28,8 @@ use IO::Handle;
"opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718",
"af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395",
"lme2510c_s7395_old", "drxk", "drxk_terratec_h5",
- "drxk_hauppauge_hvr930c", "tda10071", "it9135", "it9137",
- "drxk_pctv", "drxk_terratec_htc_stick", "sms1xxx_hcw");
+ "drxk_hauppauge_hvr930c", "tda10071", "it9135", "drxk_pctv",
+ "drxk_terratec_htc_stick", "sms1xxx_hcw");
# Check args
syntax() if (scalar(@ARGV) != 1);
@@ -727,24 +727,6 @@ sub it9135 {
"$fwfile1 $fwfile2"
}
-sub it9137 {
- my $url = "http://kworld.server261.com/kworld/CD/ITE_TiVme/V1.00/";
- my $zipfile = "Driver_V10.323.1.0412.100412.zip";
- my $hash = "79b597dc648698ed6820845c0c9d0d37";
- my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0);
- my $drvfile = "Driver_V10.323.1.0412.100412/Data/x86/IT9135BDA.sys";
- my $fwfile = "dvb-usb-it9137-01.fw";
-
- checkstandard();
-
- wgetfile($zipfile, $url . $zipfile);
- verify($zipfile, $hash);
- unzip($zipfile, $tmpdir);
- extract("$tmpdir/$drvfile", 69632, 5731, "$fwfile");
-
- "$fwfile"
-}
-
sub tda10071 {
my $sourcefile = "PCTV_460e_reference.zip";
my $url = "ftp://ftp.pctvsystems.com/TV/driver/PCTV%2070e%2080e%20100e%20320e%20330e%20800e/";
diff --git a/Documentation/dvb/it9137.txt b/Documentation/dvb/it9137.txt
deleted file mode 100644
index 9e6726eead90..000000000000
--- a/Documentation/dvb/it9137.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-To extract firmware for Kworld UB499-2T (id 1b80:e409) you need to copy the
-following file(s) to this directory.
-
-IT9135BDA.sys Dated Mon 22 Mar 2010 02:20:08 GMT
-
-extract using dd
-dd if=IT9135BDA.sys ibs=1 skip=69632 count=5731 of=dvb-usb-it9137-01.fw
-
-copy to default firmware location.
diff --git a/Documentation/edac.txt b/Documentation/edac.txt
index 56c7e936430f..cb4c2cefd45a 100644
--- a/Documentation/edac.txt
+++ b/Documentation/edac.txt
@@ -6,7 +6,7 @@ Written by Doug Thompson <dougthompson@xmission.com>
7 Dec 2005
17 Jul 2007 Updated
-(c) Mauro Carvalho Chehab <mchehab@redhat.com>
+(c) Mauro Carvalho Chehab
05 Aug 2009 Nehalem interface
EDAC is maintained and written by:
diff --git a/Documentation/fb/00-INDEX b/Documentation/fb/00-INDEX
index 30a70542e823..fe85e7c5907a 100644
--- a/Documentation/fb/00-INDEX
+++ b/Documentation/fb/00-INDEX
@@ -5,6 +5,8 @@ please mail me.
00-INDEX
- this file.
+api.txt
+ - The frame buffer API between applications and buffer devices.
arkfb.txt
- info on the fbdev driver for ARK Logic chips.
aty128fb.txt
@@ -51,12 +53,16 @@ sh7760fb.txt
- info on the SH7760/SH7763 integrated LCDC Framebuffer driver.
sisfb.txt
- info on the framebuffer device driver for various SiS chips.
+sm501.txt
+ - info on the framebuffer device driver for sm501 videoframebuffer.
sstfb.txt
- info on the frame buffer driver for 3dfx' Voodoo Graphics boards.
tgafb.txt
- info on the TGA (DECChip 21030) frame buffer driver.
tridentfb.txt
info on the framebuffer driver for some Trident chip based cards.
+udlfb.txt
+ - Driver for DisplayLink USB 2.0 chips.
uvesafb.txt
- info on the userspace VESA (VBE2+ compliant) frame buffer device.
vesafb.txt
diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX
index 632211cbdd56..ac28149aede4 100644
--- a/Documentation/filesystems/00-INDEX
+++ b/Documentation/filesystems/00-INDEX
@@ -2,6 +2,8 @@
- this file (info on some of the filesystems supported by linux).
Locking
- info on locking rules as they pertain to Linux VFS.
+Makefile
+ - Makefile for building the filsystems-part of DocBook.
9p.txt
- 9p (v9fs) is an implementation of the Plan 9 remote fs protocol.
adfs.txt
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 5b0c083d7c0e..f424e0e5b46b 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -47,6 +47,8 @@ prototypes:
int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t);
int (*rename) (struct inode *, struct dentry *,
struct inode *, struct dentry *);
+ int (*rename2) (struct inode *, struct dentry *,
+ struct inode *, struct dentry *, unsigned int);
int (*readlink) (struct dentry *, char __user *,int);
void * (*follow_link) (struct dentry *, struct nameidata *);
void (*put_link) (struct dentry *, struct nameidata *, void *);
@@ -78,6 +80,7 @@ mkdir: yes
unlink: yes (both)
rmdir: yes (both) (see below)
rename: yes (all) (see below)
+rename2: yes (all) (see below)
readlink: no
follow_link: no
put_link: no
@@ -96,7 +99,8 @@ tmpfile: no
Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
victim.
- cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem.
+ cross-directory ->rename() and rename2() has (per-superblock)
+->s_vfs_rename_sem.
See Documentation/filesystems/directory-locking for more detailed discussion
of the locking scheme for directory operations.
diff --git a/Documentation/filesystems/autofs4-mount-control.txt b/Documentation/filesystems/autofs4-mount-control.txt
index 4c95935cbcf4..aff22113a986 100644
--- a/Documentation/filesystems/autofs4-mount-control.txt
+++ b/Documentation/filesystems/autofs4-mount-control.txt
@@ -255,7 +255,7 @@ AUTOFS_DEV_IOCTL_OPENMOUNT and AUTOFS_DEV_IOCTL_CLOSEMOUNT
Obtain and release a file descriptor for an autofs managed mount point
path. The open call requires an initialized struct autofs_dev_ioctl with
-the the path field set and the size field adjusted appropriately as well
+the path field set and the size field adjusted appropriately as well
as the arg1 field set to the device number of the autofs mount. The
device number can be obtained from the mount options shown in
/proc/mounts. The close call requires an initialized struct
diff --git a/Documentation/filesystems/hfsplus.txt b/Documentation/filesystems/hfsplus.txt
index af1628a1061c..59f7569fc9ed 100644
--- a/Documentation/filesystems/hfsplus.txt
+++ b/Documentation/filesystems/hfsplus.txt
@@ -56,4 +56,4 @@ References
kernel source: <file:fs/hfsplus>
-Apple Technote 1150 http://developer.apple.com/technotes/tn/tn1150.html
+Apple Technote 1150 https://developer.apple.com/legacy/library/technotes/tn/tn1150.html
diff --git a/Documentation/filesystems/nfs/00-INDEX b/Documentation/filesystems/nfs/00-INDEX
index 66eb6c8c5334..53f3b596ac0d 100644
--- a/Documentation/filesystems/nfs/00-INDEX
+++ b/Documentation/filesystems/nfs/00-INDEX
@@ -12,6 +12,8 @@ nfs41-server.txt
- info on the Linux server implementation of NFSv4 minor version 1.
nfs-rdma.txt
- how to install and setup the Linux NFS/RDMA client and server software
+nfsd-admin-interfaces.txt
+ - Administrative interfaces for nfsd.
nfsroot.txt
- short guide on setting up a diskless box with NFS root filesystem.
pnfs.txt
@@ -20,5 +22,5 @@ rpc-cache.txt
- introduction to the caching mechanisms in the sunrpc layer.
idmapper.txt
- information for configuring request-keys to be used by idmapper
-knfsd-rpcgss.txt
+rpc-server-gss.txt
- Information on GSS authentication support in the NFS Server
diff --git a/Documentation/filesystems/nilfs2.txt b/Documentation/filesystems/nilfs2.txt
index 06887d46ccf2..41c3d332acc9 100644
--- a/Documentation/filesystems/nilfs2.txt
+++ b/Documentation/filesystems/nilfs2.txt
@@ -25,9 +25,8 @@ available from the following download page. At least "mkfs.nilfs2",
cleaner or garbage collector) are required. Details on the tools are
described in the man pages included in the package.
-Project web page: http://www.nilfs.org/en/
-Download page: http://www.nilfs.org/en/download.html
-Git tree web page: http://www.nilfs.org/git/
+Project web page: http://nilfs.sourceforge.net/
+Download page: http://nilfs.sourceforge.net/en/download.html
List info: http://vger.kernel.org/vger-lists.html#linux-nilfs
Caveats
@@ -111,6 +110,13 @@ Table of NILFS2 specific ioctls
nilfs_resize utilities and by nilfs_cleanerd
daemon.
+ NILFS_IOCTL_SET_SUINFO Modify segment usage info of requested
+ segments. This ioctl is used by
+ nilfs_cleanerd daemon to skip unnecessary
+ cleaning operation of segments and reduce
+ performance penalty or wear of flash device
+ due to redundant move of in-use blocks.
+
NILFS_IOCTL_GET_SUSTAT Return segment usage statistics. This ioctl
is used in lssu, nilfs_resize utilities and
by nilfs_cleanerd daemon.
diff --git a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt
index 791af8dac065..61947facfc07 100644
--- a/Documentation/filesystems/ntfs.txt
+++ b/Documentation/filesystems/ntfs.txt
@@ -455,8 +455,6 @@ not have this problem with odd numbers of sectors.
ChangeLog
=========
-Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
-
2.1.30:
- Fix writev() (it kept writing the first segment over and over again
instead of moving onto subsequent segments).
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index fe2b7ae6f962..0f3a1390bf00 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -295,9 +295,9 @@ in the beginning of ->setattr unconditionally.
->clear_inode() and ->delete_inode() are gone; ->evict_inode() should
be used instead. It gets called whenever the inode is evicted, whether it has
remaining links or not. Caller does *not* evict the pagecache or inode-associated
-metadata buffers; getting rid of those is responsibility of method, as it had
-been for ->delete_inode(). Caller makes sure async writeback cannot be running
-for the inode while (or after) ->evict_inode() is called.
+metadata buffers; the method has to use truncate_inode_pages_final() to get rid
+of those. Caller makes sure async writeback cannot be running for the inode while
+(or after) ->evict_inode() is called.
->drop_inode() returns int now; it's called on final iput() with
inode->i_lock held and it returns true if filesystems wants the inode to be
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index c53784c119c8..94eb86287bcb 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -347,6 +347,8 @@ struct inode_operations {
int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t);
int (*rename) (struct inode *, struct dentry *,
struct inode *, struct dentry *);
+ int (*rename2) (struct inode *, struct dentry *,
+ struct inode *, struct dentry *, unsigned int);
int (*readlink) (struct dentry *, char __user *,int);
void * (*follow_link) (struct dentry *, struct nameidata *);
void (*put_link) (struct dentry *, struct nameidata *, void *);
@@ -414,6 +416,20 @@ otherwise noted.
rename: called by the rename(2) system call to rename the object to
have the parent and name given by the second inode and dentry.
+ rename2: this has an additional flags argument compared to rename.
+ If no flags are supported by the filesystem then this method
+ need not be implemented. If some flags are supported then the
+ filesystem must return -EINVAL for any unsupported or unknown
+ flags. Currently the following flags are implemented:
+ (1) RENAME_NOREPLACE: this flag indicates that if the target
+ of the rename exists the rename should fail with -EEXIST
+ instead of replacing the target. The VFS already checks for
+ existence, so for local filesystems the RENAME_NOREPLACE
+ implementation is equivalent to plain rename.
+ (2) RENAME_EXCHANGE: exchange source and target. Both must
+ exist; this is checked by the VFS. Unlike plain rename,
+ source and target may be of different type.
+
readlink: called by the readlink(2) system call. Only required if
you want to support reading symbolic links
diff --git a/Documentation/fmc/fmc-write-eeprom.txt b/Documentation/fmc/fmc-write-eeprom.txt
index 44a3bc678bf0..e0a9712156aa 100644
--- a/Documentation/fmc/fmc-write-eeprom.txt
+++ b/Documentation/fmc/fmc-write-eeprom.txt
@@ -9,7 +9,12 @@ Overwriting the EEPROM is not something you should do daily, and it is
expected to only happen during manufacturing. For this reason, the
module makes it unlikely for the random user to change a working EEPROM.
-The module takes the following measures:
+However, since the EEPROM may include application-specific information
+other than the identification, later versions of this packages added
+write-support through sysfs. See *note Accessing the EEPROM::.
+
+To avoid damaging the EEPROM content, the module takes the following
+measures:
* It accepts a `file=' argument (within /lib/firmware) and if no
such argument is received, it doesn't write anything to EEPROM
@@ -70,56 +75,24 @@ first time.
[ 132.899872] fake-fmc: Product name: FmcDelay1ns4cha
-Writing to the EEPROM
+Accessing the EEPROM
=====================
-Once you have created a binary file for your EEPROM, you can write it
-to the storage medium using the fmc-write-eeprom (See *note
-fmc-write-eeprom::, while relying on a carrier driver. The procedure
-here shown here uses the SPEC driver
-(`http://www.ohwr.org/projects/spec-sw').
-
-The example assumes no driver is already loaded (actually, I unloaded
-them by hand as everything loads automatically at boot time after you
-installed the modules), and shows kernel messages together with
-commands. Here the prompt is spusa.root# and two SPEC cards are plugged
-in the system.
-
- spusa.root# insmod fmc.ko
- spusa.root# insmod spec.ko
- [13972.382818] spec 0000:02:00.0: probe for device 0002:0000
- [13972.392773] spec 0000:02:00.0: got file "fmc/spec-init.bin", 1484404 (0x16a674) bytes
- [13972.591388] spec 0000:02:00.0: FPGA programming successful
- [13972.883011] spec 0000:02:00.0: EEPROM has no FRU information
- [13972.888719] spec 0000:02:00.0: No device_id filled, using index
- [13972.894676] spec 0000:02:00.0: No mezzanine_name found
- [13972.899863] /home/rubini/wip/spec-sw/kernel/spec-gpio.c - spec_gpio_init
- [13972.906578] spec 0000:04:00.0: probe for device 0004:0000
- [13972.916509] spec 0000:04:00.0: got file "fmc/spec-init.bin", 1484404 (0x16a674) bytes
- [13973.115096] spec 0000:04:00.0: FPGA programming successful
- [13973.401798] spec 0000:04:00.0: EEPROM has no FRU information
- [13973.407474] spec 0000:04:00.0: No device_id filled, using index
- [13973.413417] spec 0000:04:00.0: No mezzanine_name found
- [13973.418600] /home/rubini/wip/spec-sw/kernel/spec-gpio.c - spec_gpio_init
- spusa.root# ls /sys/bus/fmc/devices
- fmc-0000 fmc-0001
- spusa.root# insmod fmc-write-eeprom.ko busid=0x0200 file=fdelay-eeprom.bin
- [14103.966259] spec 0000:02:00.0: Matching an generic driver (no ID)
- [14103.975519] spec 0000:02:00.0: programming 6155 bytes
- [14126.373762] spec 0000:02:00.0: write_eeprom: success
- [14126.378770] spec 0000:04:00.0: Matching an generic driver (no ID)
- [14126.384903] spec 0000:04:00.0: fmc_write_eeprom: no filename given: not programming
- [14126.392600] fmc_write_eeprom: probe of fmc-0001 failed with error -2
-
-Reading back the EEPROM
-=======================
-
-In order to read back the binary content of the EEPROM of your
-mezzanine device, the bus creates a read-only sysfs file called eeprom
-for each mezzanine it knows about:
-
- spusa.root# cd /sys/bus/fmc/devices; ls -l */eeprom
- -r--r--r-- 1 root root 8192 Apr 9 16:53 FmcDelay1ns4cha-f001/eeprom
- -r--r--r-- 1 root root 8192 Apr 9 17:19 fake-design-for-testing-f002/eeprom
- -r--r--r-- 1 root root 8192 Apr 9 17:19 fake-design-for-testing-f003/eeprom
- -r--r--r-- 1 root root 8192 Apr 9 17:19 fmc-f004/eeprom
+The bus creates a sysfs binary file called eeprom for each mezzanine it
+knows about:
+
+ spusa.root# cd /sys/bus/fmc/devices; ls -l */eeprom
+ -r--r--r-- 1 root root 8192 Feb 21 12:30 FmcAdc100m14b4cha-0800/eeprom
+ -r--r--r-- 1 root root 8192 Feb 21 12:30 FmcDelay1ns4cha-0200/eeprom
+ -r--r--r-- 1 root root 8192 Feb 21 12:30 FmcDio5cha-0400/eeprom
+
+Everybody can read the files and the superuser can also modify it, but
+the operation may on the carrier driver, if the carrier is unable to
+access the I2C bus. For example, the spec driver can access the bus
+only with its golden gateware: after a mezzanine driver reprogrammed
+the FPGA with a custom circuit, the carrier is unable to access the
+EEPROM and returns ENOTSUPP.
+
+An alternative way to write the EEPROM is the mezzanine driver
+fmc-write-eeprom (See *note fmc-write-eeprom::), but the procedure is
+more complex.
diff --git a/Documentation/futex-requeue-pi.txt b/Documentation/futex-requeue-pi.txt
index 9dc1ff4fd536..31b16610c416 100644
--- a/Documentation/futex-requeue-pi.txt
+++ b/Documentation/futex-requeue-pi.txt
@@ -67,7 +67,7 @@ pthread_cond_wait_pi(cond, mutex)
lock(cond->__data.__lock);
} while(...)
unlock(cond->__data.__lock);
- /* the kernel acquired the the mutex for us */
+ /* the kernel acquired the mutex for us */
}
pthread_cond_broadcast_pi(cond)
diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt
index e42f77d8d4ca..09854fe59307 100644
--- a/Documentation/gpio/consumer.txt
+++ b/Documentation/gpio/consumer.txt
@@ -154,6 +154,7 @@ raw line value:
void gpiod_set_raw_value(struct gpio_desc *desc, int value)
int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value)
+ int gpiod_direction_output_raw(struct gpio_desc *desc, int value)
The active-low state of a GPIO can also be queried using the following call:
diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt
index 9da0bfa74781..f73cc7b5dc85 100644
--- a/Documentation/gpio/driver.txt
+++ b/Documentation/gpio/driver.txt
@@ -62,6 +62,37 @@ Any debugfs dump method should normally ignore signals which haven't been
requested as GPIOs. They can use gpiochip_is_requested(), which returns either
NULL or the label associated with that GPIO when it was requested.
+
+GPIO drivers providing IRQs
+---------------------------
+It is custom that GPIO drivers (GPIO chips) are also providing interrupts,
+most often cascaded off a parent interrupt controller, and in some special
+cases the GPIO logic is melded with a SoC's primary interrupt controller.
+
+The IRQ portions of the GPIO block are implemented using an irqchip, using
+the header <linux/irq.h>. So basically such a driver is utilizing two sub-
+systems simultaneously: gpio and irq.
+
+It is legal for any IRQ consumer to request an IRQ from any irqchip no matter
+if that is a combined GPIO+IRQ driver. The basic premise is that gpio_chip and
+irq_chip are orthogonal, and offering their services independent of each
+other.
+
+gpiod_to_irq() is just a convenience function to figure out the IRQ for a
+certain GPIO line and should not be relied upon to have been called before
+the IRQ is used.
+
+So always prepare the hardware and make it ready for action in respective
+callbacks from the GPIO and irqchip APIs. Do not rely on gpiod_to_irq() having
+been called first.
+
+This orthogonality leads to ambiguities that we need to solve: if there is
+competition inside the subsystem which side is using the resource (a certain
+GPIO line and register for example) it needs to deny certain operations and
+keep track of usage inside of the gpiolib subsystem. This is why the API
+below exists.
+
+
Locking IRQ usage
-----------------
Input GPIOs can be used as IRQ signals. When this happens, a driver is requested
@@ -73,3 +104,7 @@ This will prevent the use of non-irq related GPIO APIs until the GPIO IRQ lock
is released:
void gpiod_unlock_as_irq(struct gpio_desc *desc)
+
+When implementing an irqchip inside a GPIO driver, these two functions should
+typically be called in the .startup() and .shutdown() callbacks from the
+irqchip.
diff --git a/Documentation/hid/hid-transport.txt b/Documentation/hid/hid-transport.txt
new file mode 100644
index 000000000000..3dcba9fd4a3a
--- /dev/null
+++ b/Documentation/hid/hid-transport.txt
@@ -0,0 +1,317 @@
+ HID I/O Transport Drivers
+ ===========================
+
+The HID subsystem is independent of the underlying transport driver. Initially,
+only USB was supported, but other specifications adopted the HID design and
+provided new transport drivers. The kernel includes at least support for USB,
+Bluetooth, I2C and user-space I/O drivers.
+
+1) HID Bus
+==========
+
+The HID subsystem is designed as a bus. Any I/O subsystem may provide HID
+devices and register them with the HID bus. HID core then loads generic device
+drivers on top of it. The transport drivers are responsible of raw data
+transport and device setup/management. HID core is responsible of
+report-parsing, report interpretation and the user-space API. Device specifics
+and quirks are handled by all layers depending on the quirk.
+
+ +-----------+ +-----------+ +-----------+ +-----------+
+ | Device #1 | | Device #i | | Device #j | | Device #k |
+ +-----------+ +-----------+ +-----------+ +-----------+
+ \\ // \\ //
+ +------------+ +------------+
+ | I/O Driver | | I/O Driver |
+ +------------+ +------------+
+ || ||
+ +------------------+ +------------------+
+ | Transport Driver | | Transport Driver |
+ +------------------+ +------------------+
+ \___ ___/
+ \ /
+ +----------------+
+ | HID Core |
+ +----------------+
+ / | | \
+ / | | \
+ ____________/ | | \_________________
+ / | | \
+ / | | \
+ +----------------+ +-----------+ +------------------+ +------------------+
+ | Generic Driver | | MT Driver | | Custom Driver #1 | | Custom Driver #2 |
+ +----------------+ +-----------+ +------------------+ +------------------+
+
+Example Drivers:
+ I/O: USB, I2C, Bluetooth-l2cap
+ Transport: USB-HID, I2C-HID, BT-HIDP
+
+Everything below "HID Core" is simplified in this graph as it is only of
+interest to HID device drivers. Transport drivers do not need to know the
+specifics.
+
+1.1) Device Setup
+-----------------
+
+I/O drivers normally provide hotplug detection or device enumeration APIs to the
+transport drivers. Transport drivers use this to find any suitable HID device.
+They allocate HID device objects and register them with HID core. Transport
+drivers are not required to register themselves with HID core. HID core is never
+aware of which transport drivers are available and is not interested in it. It
+is only interested in devices.
+
+Transport drivers attach a constant "struct hid_ll_driver" object with each
+device. Once a device is registered with HID core, the callbacks provided via
+this struct are used by HID core to communicate with the device.
+
+Transport drivers are responsible of detecting device failures and unplugging.
+HID core will operate a device as long as it is registered regardless of any
+device failures. Once transport drivers detect unplug or failure events, they
+must unregister the device from HID core and HID core will stop using the
+provided callbacks.
+
+1.2) Transport Driver Requirements
+----------------------------------
+
+The terms "asynchronous" and "synchronous" in this document describe the
+transmission behavior regarding acknowledgements. An asynchronous channel must
+not perform any synchronous operations like waiting for acknowledgements or
+verifications. Generally, HID calls operating on asynchronous channels must be
+running in atomic-context just fine.
+On the other hand, synchronous channels can be implemented by the transport
+driver in whatever way they like. They might just be the same as asynchronous
+channels, but they can also provide acknowledgement reports, automatic
+retransmission on failure, etc. in a blocking manner. If such functionality is
+required on asynchronous channels, a transport-driver must implement that via
+its own worker threads.
+
+HID core requires transport drivers to follow a given design. A Transport
+driver must provide two bi-directional I/O channels to each HID device. These
+channels must not necessarily be bi-directional in the hardware itself. A
+transport driver might just provide 4 uni-directional channels. Or it might
+multiplex all four on a single physical channel. However, in this document we
+will describe them as two bi-directional channels as they have several
+properties in common.
+
+ - Interrupt Channel (intr): The intr channel is used for asynchronous data
+ reports. No management commands or data acknowledgements are sent on this
+ channel. Any unrequested incoming or outgoing data report must be sent on
+ this channel and is never acknowledged by the remote side. Devices usually
+ send their input events on this channel. Outgoing events are normally
+ not send via intr, except if high throughput is required.
+ - Control Channel (ctrl): The ctrl channel is used for synchronous requests and
+ device management. Unrequested data input events must not be sent on this
+ channel and are normally ignored. Instead, devices only send management
+ events or answers to host requests on this channel.
+ The control-channel is used for direct blocking queries to the device
+ independent of any events on the intr-channel.
+ Outgoing reports are usually sent on the ctrl channel via synchronous
+ SET_REPORT requests.
+
+Communication between devices and HID core is mostly done via HID reports. A
+report can be of one of three types:
+
+ - INPUT Report: Input reports provide data from device to host. This
+ data may include button events, axis events, battery status or more. This
+ data is generated by the device and sent to the host with or without
+ requiring explicit requests. Devices can choose to send data continuously or
+ only on change.
+ - OUTPUT Report: Output reports change device states. They are sent from host
+ to device and may include LED requests, rumble requests or more. Output
+ reports are never sent from device to host, but a host can retrieve their
+ current state.
+ Hosts may choose to send output reports either continuously or only on
+ change.
+ - FEATURE Report: Feature reports are used for specific static device features
+ and never reported spontaneously. A host can read and/or write them to access
+ data like battery-state or device-settings.
+ Feature reports are never sent without requests. A host must explicitly set
+ or retrieve a feature report. This also means, feature reports are never sent
+ on the intr channel as this channel is asynchronous.
+
+INPUT and OUTPUT reports can be sent as pure data reports on the intr channel.
+For INPUT reports this is the usual operational mode. But for OUTPUT reports,
+this is rarely done as OUTPUT reports are normally quite scarce. But devices are
+free to make excessive use of asynchronous OUTPUT reports (for instance, custom
+HID audio speakers make great use of it).
+
+Plain reports must not be sent on the ctrl channel, though. Instead, the ctrl
+channel provides synchronous GET/SET_REPORT requests. Plain reports are only
+allowed on the intr channel and are the only means of data there.
+
+ - GET_REPORT: A GET_REPORT request has a report ID as payload and is sent
+ from host to device. The device must answer with a data report for the
+ requested report ID on the ctrl channel as a synchronous acknowledgement.
+ Only one GET_REPORT request can be pending for each device. This restriction
+ is enforced by HID core as several transport drivers don't allow multiple
+ simultaneous GET_REPORT requests.
+ Note that data reports which are sent as answer to a GET_REPORT request are
+ not handled as generic device events. That is, if a device does not operate
+ in continuous data reporting mode, an answer to GET_REPORT does not replace
+ the raw data report on the intr channel on state change.
+ GET_REPORT is only used by custom HID device drivers to query device state.
+ Normally, HID core caches any device state so this request is not necessary
+ on devices that follow the HID specs except during device initialization to
+ retrieve the current state.
+ GET_REPORT requests can be sent for any of the 3 report types and shall
+ return the current report state of the device. However, OUTPUT reports as
+ payload may be blocked by the underlying transport driver if the
+ specification does not allow them.
+ - SET_REPORT: A SET_REPORT request has a report ID plus data as payload. It is
+ sent from host to device and a device must update it's current report state
+ according to the given data. Any of the 3 report types can be used. However,
+ INPUT reports as payload might be blocked by the underlying transport driver
+ if the specification does not allow them.
+ A device must answer with a synchronous acknowledgement. However, HID core
+ does not require transport drivers to forward this acknowledgement to HID
+ core.
+ Same as for GET_REPORT, only one SET_REPORT can be pending at a time. This
+ restriction is enforced by HID core as some transport drivers do not support
+ multiple synchronous SET_REPORT requests.
+
+Other ctrl-channel requests are supported by USB-HID but are not available
+(or deprecated) in most other transport level specifications:
+
+ - GET/SET_IDLE: Only used by USB-HID and I2C-HID.
+ - GET/SET_PROTOCOL: Not used by HID core.
+ - RESET: Used by I2C-HID, not hooked up in HID core.
+ - SET_POWER: Used by I2C-HID, not hooked up in HID core.
+
+2) HID API
+==========
+
+2.1) Initialization
+-------------------
+
+Transport drivers normally use the following procedure to register a new device
+with HID core:
+
+ struct hid_device *hid;
+ int ret;
+
+ hid = hid_allocate_device();
+ if (IS_ERR(hid)) {
+ ret = PTR_ERR(hid);
+ goto err_<...>;
+ }
+
+ strlcpy(hid->name, <device-name-src>, 127);
+ strlcpy(hid->phys, <device-phys-src>, 63);
+ strlcpy(hid->uniq, <device-uniq-src>, 63);
+
+ hid->ll_driver = &custom_ll_driver;
+ hid->bus = <device-bus>;
+ hid->vendor = <device-vendor>;
+ hid->product = <device-product>;
+ hid->version = <device-version>;
+ hid->country = <device-country>;
+ hid->dev.parent = <pointer-to-parent-device>;
+ hid->driver_data = <transport-driver-data-field>;
+
+ ret = hid_add_device(hid);
+ if (ret)
+ goto err_<...>;
+
+Once hid_add_device() is entered, HID core might use the callbacks provided in
+"custom_ll_driver". Note that fields like "country" can be ignored by underlying
+transport-drivers if not supported.
+
+To unregister a device, use:
+
+ hid_destroy_device(hid);
+
+Once hid_destroy_device() returns, HID core will no longer make use of any
+driver callbacks.
+
+2.2) hid_ll_driver operations
+-----------------------------
+
+The available HID callbacks are:
+ - int (*start) (struct hid_device *hdev)
+ Called from HID device drivers once they want to use the device. Transport
+ drivers can choose to setup their device in this callback. However, normally
+ devices are already set up before transport drivers register them to HID core
+ so this is mostly only used by USB-HID.
+
+ - void (*stop) (struct hid_device *hdev)
+ Called from HID device drivers once they are done with a device. Transport
+ drivers can free any buffers and deinitialize the device. But note that
+ ->start() might be called again if another HID device driver is loaded on the
+ device.
+ Transport drivers are free to ignore it and deinitialize devices after they
+ destroyed them via hid_destroy_device().
+
+ - int (*open) (struct hid_device *hdev)
+ Called from HID device drivers once they are interested in data reports.
+ Usually, while user-space didn't open any input API/etc., device drivers are
+ not interested in device data and transport drivers can put devices asleep.
+ However, once ->open() is called, transport drivers must be ready for I/O.
+ ->open() calls are nested for each client that opens the HID device.
+
+ - void (*close) (struct hid_device *hdev)
+ Called from HID device drivers after ->open() was called but they are no
+ longer interested in device reports. (Usually if user-space closed any input
+ devices of the driver).
+ Transport drivers can put devices asleep and terminate any I/O of all
+ ->open() calls have been followed by a ->close() call. However, ->start() may
+ be called again if the device driver is interested in input reports again.
+
+ - int (*parse) (struct hid_device *hdev)
+ Called once during device setup after ->start() has been called. Transport
+ drivers must read the HID report-descriptor from the device and tell HID core
+ about it via hid_parse_report().
+
+ - int (*power) (struct hid_device *hdev, int level)
+ Called by HID core to give PM hints to transport drivers. Usually this is
+ analogical to the ->open() and ->close() hints and redundant.
+
+ - void (*request) (struct hid_device *hdev, struct hid_report *report,
+ int reqtype)
+ Send an HID request on the ctrl channel. "report" contains the report that
+ should be sent and "reqtype" the request type. Request-type can be
+ HID_REQ_SET_REPORT or HID_REQ_GET_REPORT.
+ This callback is optional. If not provided, HID core will assemble a raw
+ report following the HID specs and send it via the ->raw_request() callback.
+ The transport driver is free to implement this asynchronously.
+
+ - int (*wait) (struct hid_device *hdev)
+ Used by HID core before calling ->request() again. A transport driver can use
+ it to wait for any pending requests to complete if only one request is
+ allowed at a time.
+
+ - int (*raw_request) (struct hid_device *hdev, unsigned char reportnum,
+ __u8 *buf, size_t count, unsigned char rtype,
+ int reqtype)
+ Same as ->request() but provides the report as raw buffer. This request shall
+ be synchronous. A transport driver must not use ->wait() to complete such
+ requests. This request is mandatory and hid core will reject the device if
+ it is missing.
+
+ - int (*output_report) (struct hid_device *hdev, __u8 *buf, size_t len)
+ Send raw output report via intr channel. Used by some HID device drivers
+ which require high throughput for outgoing requests on the intr channel. This
+ must not cause SET_REPORT calls! This must be implemented as asynchronous
+ output report on the intr channel!
+
+ - int (*idle) (struct hid_device *hdev, int report, int idle, int reqtype)
+ Perform SET/GET_IDLE request. Only used by USB-HID, do not implement!
+
+2.3) Data Path
+--------------
+
+Transport drivers are responsible of reading data from I/O devices. They must
+handle any I/O-related state-tracking themselves. HID core does not implement
+protocol handshakes or other management commands which can be required by the
+given HID transport specification.
+
+Every raw data packet read from a device must be fed into HID core via
+hid_input_report(). You must specify the channel-type (intr or ctrl) and report
+type (input/output/feature). Under normal conditions, only input reports are
+provided via this API.
+
+Responses to GET_REPORT requests via ->request() must also be provided via this
+API. Responses to ->raw_request() are synchronous and must be intercepted by the
+transport driver and not passed to hid_input_report().
+Acknowledgements to SET_REPORT requests are not of interest to HID core.
+
+----------------------------------------------------
+Written 2013, David Herrmann <dh.herrmann@gmail.com>
diff --git a/Documentation/hid/uhid.txt b/Documentation/hid/uhid.txt
index dc35a2b75eee..ee6593608c8e 100644
--- a/Documentation/hid/uhid.txt
+++ b/Documentation/hid/uhid.txt
@@ -93,6 +93,11 @@ the request was handled successfully.
event to the kernel. The payload is of type struct uhid_create_req and
contains information about your device. You can start I/O now.
+ UHID_CREATE2:
+ Same as UHID_CREATE, but the HID report descriptor data (rd_data) is an array
+ inside struct uhid_create2_req, instead of a pointer to a separate array.
+ Enables use from languages that don't support pointers, e.g. Python.
+
UHID_DESTROY:
This destroys the internal HID device. No further I/O will be accepted. There
may still be pending messages that you can receive with read() but no further
@@ -105,6 +110,12 @@ the request was handled successfully.
contains a data-payload. This is the raw data that you read from your device.
The kernel will parse the HID reports and react on it.
+ UHID_INPUT2:
+ Same as UHID_INPUT, but the data array is the last field of uhid_input2_req.
+ Enables userspace to write only the required bytes to kernel (ev.type +
+ ev.u.input2.size + the part of the data array that matters), instead of
+ the entire struct uhid_input2_req.
+
UHID_FEATURE_ANSWER:
If you receive a UHID_FEATURE request you must answer with this request. You
must copy the "id" field from the request into the answer. Set the "err" field
diff --git a/Documentation/hwmon/adc128d818 b/Documentation/hwmon/adc128d818
new file mode 100644
index 000000000000..39c95004dabc
--- /dev/null
+++ b/Documentation/hwmon/adc128d818
@@ -0,0 +1,47 @@
+Kernel driver adc128d818
+========================
+
+Supported chips:
+ * Texas Instruments ADC818D818
+ Prefix: 'adc818d818'
+ Addresses scanned: I2C 0x1d, 0x1e, 0x1f, 0x2d, 0x2e, 0x2f
+ Datasheet: Publicly available at the TI website
+ http://www.ti.com/
+
+Author: Guenter Roeck
+
+Description
+-----------
+
+This driver implements support for the Texas Instruments ADC128D818.
+It is described as 'ADC System Monitor with Temperature Sensor'.
+
+The ADC128D818 implements one temperature sensor and seven voltage sensors.
+
+Temperatures are measured in degrees Celsius. There is one set of limits.
+When the HOT Temperature Limit is crossed, this will cause an alarm that will
+be reasserted until the temperature drops below the HOT Hysteresis.
+Measurements are guaranteed between -55 and +125 degrees. The temperature
+measurement has a resolution of 0.5 degrees; the limits have a resolution
+of 1 degree.
+
+Voltage sensors (also known as IN sensors) report their values in volts.
+An alarm is triggered if the voltage has crossed a programmable minimum
+or maximum limit. Note that minimum in this case always means 'closest to
+zero'; this is important for negative voltage measurements. All voltage
+inputs can measure voltages between 0 and 2.55 volts, with a resolution
+of 0.625 mV.
+
+If an alarm triggers, it will remain triggered until the hardware register
+is read at least once. This means that the cause for the alarm may
+already have disappeared by the time the alarm is read. The driver
+caches the alarm status for each sensor until it is at least reported
+once, to ensure that alarms are reported to user space.
+
+The ADC128D818 only updates its values approximately once per second;
+reading it more often will do no harm, but will return 'old' values.
+
+In addition to the scanned address list, the chip can also be configured for
+addresses 0x35 to 0x37. Those addresses are not scanned. You have to instantiate
+the driver explicitly if the chip is configured for any of those addresses in
+your system.
diff --git a/Documentation/hwmon/k10temp b/Documentation/hwmon/k10temp
index 4dfdc8f83633..ee6d30ec1522 100644
--- a/Documentation/hwmon/k10temp
+++ b/Documentation/hwmon/k10temp
@@ -11,8 +11,8 @@ Supported chips:
Socket S1G2: Athlon (X2), Sempron (X2), Turion X2 (Ultra)
* AMD Family 12h processors: "Llano" (E2/A4/A6/A8-Series)
* AMD Family 14h processors: "Brazos" (C/E/G/Z-Series)
-* AMD Family 15h processors: "Bulldozer" (FX-Series), "Trinity"
-* AMD Family 16h processors: "Kabini"
+* AMD Family 15h processors: "Bulldozer" (FX-Series), "Trinity", "Kaveri"
+* AMD Family 16h processors: "Kabini", "Mullins"
Prefix: 'k10temp'
Addresses scanned: PCI space
@@ -46,7 +46,7 @@ Description
-----------
This driver permits reading of the internal temperature sensor of AMD
-Family 10h/11h/12h/14h/15h processors.
+Family 10h/11h/12h/14h/15h/16h processors.
All these processors have a sensor, but on those for Socket F or AM2+,
the sensor may return inconsistent values (erratum 319). The driver
diff --git a/Documentation/hwmon/lm95245 b/Documentation/hwmon/lm95245
index cbd8aeab7124..77eaf2812d25 100644
--- a/Documentation/hwmon/lm95245
+++ b/Documentation/hwmon/lm95245
@@ -24,8 +24,12 @@ is given within a range of -127 to +127.875 degrees. Remote temperatures are
given within a range of -127 to +255 degrees. Resolution depends on
temperature input and range.
-Each sensor has its own critical limit, but the hysteresis is common to all
-two channels.
+Each sensor has its own critical limit. Additionally, there is a relative
+hysteresis value common to both critical limits. To make life easier to
+user-space applications, two absolute values are exported, one for each
+channel, but these values are of course linked. Only the local hysteresis
+can be set from user-space, and the same delta applies to the remote
+hysteresis.
The lm95245 driver can change its update interval to a fixed set of values.
It will round up to the next selectable interval. See the datasheet for exact
diff --git a/Documentation/hwmon/ltc2945 b/Documentation/hwmon/ltc2945
new file mode 100644
index 000000000000..f8d0f7f19adb
--- /dev/null
+++ b/Documentation/hwmon/ltc2945
@@ -0,0 +1,84 @@
+Kernel driver ltc2945
+=====================
+
+Supported chips:
+ * Linear Technology LTC2945
+ Prefix: 'ltc2945'
+ Addresses scanned: -
+ Datasheet:
+ http://cds.linear.com/docs/en/datasheet/2945fa.pdf
+
+Author: Guenter Roeck <linux@roeck-us.net>
+
+
+Description
+-----------
+
+The LTC2945 is a rail-to-rail system monitor that measures current, voltage,
+and power consumption.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for LTC2945 devices, since there is no register
+which can be safely used to identify the chip. You will have to instantiate
+the devices explicitly.
+
+Example: the following will load the driver for an LTC2945 at address 0x10
+on I2C bus #1:
+$ modprobe ltc2945
+$ echo ltc2945 0x10 > /sys/bus/i2c/devices/i2c-1/new_device
+
+
+Sysfs entries
+-------------
+
+Voltage readings provided by this driver are reported as obtained from the ADC
+registers. If a set of voltage divider resistors is installed, calculate the
+real voltage by multiplying the reported value with (R1+R2)/R2, where R1 is the
+value of the divider resistor against the measured voltage and R2 is the value
+of the divider resistor against Ground.
+
+Current reading provided by this driver is reported as obtained from the ADC
+Current Sense register. The reported value assumes that a 1 mOhm sense resistor
+is installed. If a different sense resistor is installed, calculate the real
+current by dividing the reported value by the sense resistor value in mOhm.
+
+in1_input VIN voltage (mV). Voltage is measured either at
+ SENSE+ or VDD pin depending on chip configuration.
+in1_min Undervoltage threshold
+in1_max Overvoltage threshold
+in1_lowest Lowest measured voltage
+in1_highest Highest measured voltage
+in1_reset_history Write 1 to reset in1 history
+in1_min_alarm Undervoltage alarm
+in1_max_alarm Overvoltage alarm
+
+in2_input ADIN voltage (mV)
+in2_min Undervoltage threshold
+in2_max Overvoltage threshold
+in2_lowest Lowest measured voltage
+in2_highest Highest measured voltage
+in2_reset_history Write 1 to reset in2 history
+in2_min_alarm Undervoltage alarm
+in2_max_alarm Overvoltage alarm
+
+curr1_input SENSE current (mA)
+curr1_min Undercurrent threshold
+curr1_max Overcurrent threshold
+curr1_lowest Lowest measured current
+curr1_highest Highest measured current
+curr1_reset_history Write 1 to reset curr1 history
+curr1_min_alarm Undercurrent alarm
+curr1_max_alarm Overcurrent alarm
+
+power1_input Power (in uW). Power is calculated based on SENSE+/VDD
+ voltage or ADIN voltage depending on chip configuration.
+power1_min Low lower threshold
+power1_max High power threshold
+power1_input_lowest Historical minimum power use
+power1_input_highest Historical maximum power use
+power1_reset_history Write 1 to reset power1 history
+power1_min_alarm Low power alarm
+power1_max_alarm High power alarm
diff --git a/Documentation/hwmon/ltc2978 b/Documentation/hwmon/ltc2978
index a0546fc42273..686c078bb0e0 100644
--- a/Documentation/hwmon/ltc2978
+++ b/Documentation/hwmon/ltc2978
@@ -23,6 +23,10 @@ Supported chips:
Prefix: 'ltc3883'
Addresses scanned: -
Datasheet: http://www.linear.com/product/ltc3883
+ * Linear Technology LTM4676
+ Prefix: 'ltm4676'
+ Addresses scanned: -
+ Datasheet: http://www.linear.com/product/ltm4676
Author: Guenter Roeck <linux@roeck-us.net>
@@ -33,7 +37,8 @@ Description
LTC2974 is a quad digital power supply manager. LTC2978 is an octal power supply
monitor. LTC2977 is a pin compatible replacement for LTC2978. LTC3880 is a dual
output poly-phase step-down DC/DC controller. LTC3883 is a single phase
-step-down DC/DC controller.
+step-down DC/DC controller. LTM4676 is a dual 13A or single 26A uModule
+regulator.
Usage Notes
@@ -75,7 +80,7 @@ in[N]_label "vout[1-8]".
LTC2974: N=2-5
LTC2977: N=2-9
LTC2978: N=2-9
- LTC3880: N=2-3
+ LTC3880, LTM4676: N=2-3
LTC3883: N=2
in[N]_input Measured output voltage.
in[N]_min Minimum output voltage.
@@ -95,7 +100,7 @@ temp[N]_input Measured temperature.
and temp5 reports the chip temperature.
On LTC2977 and LTC2978, only one temperature measurement
is supported and reports the chip temperature.
- On LTC3880, temp1 and temp2 report external
+ On LTC3880 and LTM4676, temp1 and temp2 report external
temperatures, and temp3 reports the chip temperature.
On LTC3883, temp1 reports an external temperature,
and temp2 reports the chip temperature.
@@ -123,11 +128,11 @@ power[N]_label "pout[1-4]".
LTC2974: N=1-4
LTC2977: Not supported
LTC2978: Not supported
- LTC3880: N=1-2
+ LTC3880, LTM4676: N=1-2
LTC3883: N=2
power[N]_input Measured output power.
-curr1_label "iin". LTC3880 and LTC3883 only.
+curr1_label "iin". LTC3880, LTC3883, and LTM4676 only.
curr1_input Measured input current.
curr1_max Maximum input current.
curr1_max_alarm Input current high alarm.
@@ -138,7 +143,7 @@ curr[N]_label "iout[1-4]".
LTC2974: N=1-4
LTC2977: not supported
LTC2978: not supported
- LTC3880: N=2-3
+ LTC3880, LTM4676: N=2-3
LTC3883: N=2
curr[N]_input Measured output current.
curr[N]_max Maximum output current.
diff --git a/Documentation/hwmon/ltc4260 b/Documentation/hwmon/ltc4260
new file mode 100644
index 000000000000..c4ff4ad998b2
--- /dev/null
+++ b/Documentation/hwmon/ltc4260
@@ -0,0 +1,56 @@
+Kernel driver ltc4260
+=====================
+
+Supported chips:
+ * Linear Technology LTC4260
+ Prefix: 'ltc4260'
+ Addresses scanned: -
+ Datasheet:
+ http://cds.linear.com/docs/en/datasheet/4260fc.pdf
+
+Author: Guenter Roeck <linux@roeck-us.net>
+
+
+Description
+-----------
+
+The LTC4260 Hot Swap controller allows a board to be safely inserted
+and removed from a live backplane.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for LTC4260 devices, since there is no register
+which can be safely used to identify the chip. You will have to instantiate
+the devices explicitly.
+
+Example: the following will load the driver for an LTC4260 at address 0x10
+on I2C bus #1:
+$ modprobe ltc4260
+$ echo ltc4260 0x10 > /sys/bus/i2c/devices/i2c-1/new_device
+
+
+Sysfs entries
+-------------
+
+Voltage readings provided by this driver are reported as obtained from the ADC
+registers. If a set of voltage divider resistors is installed, calculate the
+real voltage by multiplying the reported value with (R1+R2)/R2, where R1 is the
+value of the divider resistor against the measured voltage and R2 is the value
+of the divider resistor against Ground.
+
+Current reading provided by this driver is reported as obtained from the ADC
+Current Sense register. The reported value assumes that a 1 mOhm sense resistor
+is installed. If a different sense resistor is installed, calculate the real
+current by dividing the reported value by the sense resistor value in mOhm.
+
+in1_input SOURCE voltage (mV)
+in1_min_alarm Undervoltage alarm
+in1_max_alarm Overvoltage alarm
+
+in2_input ADIN voltage (mV)
+in2_alarm Power bad alarm
+
+curr1_input SENSE current (mA)
+curr1_alarm SENSE overcurrent alarm
diff --git a/Documentation/i2c/instantiating-devices b/Documentation/i2c/instantiating-devices
index c70e7a7638d1..0d85ac1935b7 100644
--- a/Documentation/i2c/instantiating-devices
+++ b/Documentation/i2c/instantiating-devices
@@ -8,8 +8,8 @@ reason, the kernel code must instantiate I2C devices explicitly. There are
several ways to achieve this, depending on the context and requirements.
-Method 1: Declare the I2C devices by bus number
------------------------------------------------
+Method 1a: Declare the I2C devices by bus number
+------------------------------------------------
This method is appropriate when the I2C bus is a system bus as is the case
for many embedded systems. On such systems, each I2C bus has a number
@@ -51,6 +51,43 @@ The devices will be automatically unbound and destroyed when the I2C bus
they sit on goes away (if ever.)
+Method 1b: Declare the I2C devices via devicetree
+-------------------------------------------------
+
+This method has the same implications as method 1a. The declaration of I2C
+devices is here done via devicetree as subnodes of the master controller.
+
+Example:
+
+ i2c1: i2c@400a0000 {
+ /* ... master properties skipped ... */
+ clock-frequency = <100000>;
+
+ flash@50 {
+ compatible = "atmel,24c256";
+ reg = <0x50>;
+ };
+
+ pca9532: gpio@60 {
+ compatible = "nxp,pca9532";
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x60>;
+ };
+ };
+
+Here, two devices are attached to the bus using a speed of 100kHz. For
+additional properties which might be needed to set up the device, please refer
+to its devicetree documentation in Documentation/devicetree/bindings/.
+
+
+Method 1c: Declare the I2C devices via ACPI
+-------------------------------------------
+
+ACPI can also describe I2C devices. There is special documentation for this
+which is currently located at Documentation/acpi/enumeration.txt.
+
+
Method 2: Instantiate the devices explicitly
--------------------------------------------
diff --git a/Documentation/ide/00-INDEX b/Documentation/ide/00-INDEX
index d6b778842b75..22f98ca79539 100644
--- a/Documentation/ide/00-INDEX
+++ b/Documentation/ide/00-INDEX
@@ -10,3 +10,5 @@ ide-tape.txt
- info on the IDE ATAPI streaming tape driver
ide.txt
- important info for users of ATA devices (IDE/EIDE disks and CD-ROMS).
+warm-plug-howto.txt
+ - using sysfs to remove and add IDE devices. \ No newline at end of file
diff --git a/Documentation/input/multi-touch-protocol.txt b/Documentation/input/multi-touch-protocol.txt
index de139b18184a..7b4f59c09ee2 100644
--- a/Documentation/input/multi-touch-protocol.txt
+++ b/Documentation/input/multi-touch-protocol.txt
@@ -372,7 +372,7 @@ simple scheme, which is compatible with earlier usage, is:
Rationale: We have no information about the orientation of the touching
ellipse, so approximate it with an inscribed circle instead. The tool
-ellipse should align with the the vector (T - C), so the diameter must
+ellipse should align with the vector (T - C), so the diameter must
increase with distance(T, C). Finally, assume that the touch diameter is
equal to the tool thickness, and we arrive at the formulas above.
diff --git a/Documentation/ja_JP/SubmittingPatches b/Documentation/ja_JP/SubmittingPatches
index 97f78dd0c085..5d6ae639bfa0 100644
--- a/Documentation/ja_JP/SubmittingPatches
+++ b/Documentation/ja_JP/SubmittingPatches
@@ -98,11 +98,6 @@ dontdiff ファイルには Linux カーネルのビルドプロセスの過程
Quilt:
http://savannah.nongnu.org/projects/quilt
-Andrew Morton's patch scripts:
-http://userweb.kernel.org/~akpm/stuff/patch-scripts.tar.gz
-このリンクの先のスクリプトの代わりとして、quilt がパッチマネジメント
-ツールとして推奨されています(上のリンクを見てください)。
-
2) パッチに対する説明
パッチの中の変更点に対する技術的な詳細について説明してください。
@@ -695,7 +690,7 @@ gcc においては、マクロと同じくらい軽いです。
----------------------
Andrew Morton, "The perfect patch" (tpp).
- <http://userweb.kernel.org/~akpm/stuff/tpp.txt>
+ <http://www.ozlabs.org/~akpm/stuff/tpp.txt>
Jeff Garzik, "Linux kernel patch submission format".
<http://linux.yyz.us/patch-format.html>
@@ -707,7 +702,7 @@ Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer".
<http://www.kroah.com/log/2006/01/11/>
NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!
- <http://marc.theaimsgroup.com/?l=linux-kernel&m=112112749912944&w=2>
+ <https://lkml.org/lkml/2005/7/11/336>
Kernel Documentation/CodingStyle:
<http://users.sosdg.org/~qiyong/lxr/source/Documentation/CodingStyle>
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 7116fda7077f..bc3478581f67 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -229,8 +229,24 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
use by PCI
Format: <irq>,<irq>...
+ acpi_no_auto_serialize [HW,ACPI]
+ Disable auto-serialization of AML methods
+ AML control methods that contain the opcodes to create
+ named objects will be marked as "Serialized" by the
+ auto-serialization feature.
+ This feature is enabled by default.
+ This option allows to turn off the feature.
+
acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT
+ acpica_no_return_repair [HW, ACPI]
+ Disable AML predefined validation mechanism
+ This mechanism can repair the evaluation result to make
+ the return objects more ACPI specification compliant.
+ This option is useful for developers to identify the
+ root cause of an AML interpreter issue when the issue
+ has something to do with the repair mechanism.
+
acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS
Format: To spoof as Windows 98: ="Microsoft Windows"
@@ -298,8 +314,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode
Format: { level | edge | high | low }
- acpi_serialize [HW,ACPI] force serialization of AML methods
-
acpi_skip_timer_override [HW,ACPI]
Recognize and ignore IRQ0/pin2 Interrupt Override.
For broken nForce2 BIOS resulting in XT-PIC timer.
@@ -1011,6 +1025,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
parameter will force ia64_sal_cache_flush to call
ia64_pal_cache_flush instead of SAL_CACHE_FLUSH.
+ forcepae [X86-32]
+ Forcefully enable Physical Address Extension (PAE).
+ Many Pentium M systems disable PAE but may have a
+ functionally usable PAE implementation.
+ Warning: use of this parameter will taint the kernel
+ and may cause unknown problems.
+
ftrace=[tracer]
[FTRACE] will set and start the specified tracer
as early as possible in order to facilitate early
@@ -2053,8 +2074,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
IOAPICs that may be present in the system.
nokaslr [X86]
- Disable kernel base offset ASLR (Address Space
- Layout Randomization) if built into the kernel.
+ Disable kernel and module base offset ASLR (Address
+ Space Layout Randomization) if built into the kernel.
noautogroup Disable scheduler automatic task group creation.
@@ -3409,14 +3430,24 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
of CONFIG_HIGHPTE.
vdso= [X86,SH]
- vdso=2: enable compat VDSO (default with COMPAT_VDSO)
- vdso=1: enable VDSO (default)
+ On X86_32, this is an alias for vdso32=. Otherwise:
+
+ vdso=1: enable VDSO (the default)
vdso=0: disable VDSO mapping
- vdso32= [X86]
- vdso32=2: enable compat VDSO (default with COMPAT_VDSO)
- vdso32=1: enable 32-bit VDSO (default)
- vdso32=0: disable 32-bit VDSO mapping
+ vdso32= [X86] Control the 32-bit vDSO
+ vdso32=1: enable 32-bit VDSO
+ vdso32=0 or vdso32=2: disable 32-bit VDSO
+
+ See the help text for CONFIG_COMPAT_VDSO for more
+ details. If CONFIG_COMPAT_VDSO is set, the default is
+ vdso32=0; otherwise, the default is vdso32=1.
+
+ For compatibility with older kernels, vdso32=2 is an
+ alias for vdso32=0.
+
+ Try vdso32=0 if you encounter an error that says:
+ dl_main: Assertion `(void *) ph->p_vaddr == _rtld_local._dl_sysinfo_dso' failed!
vector= [IA-64,SMP]
vector=percpu: enable percpu vector domain
diff --git a/Documentation/kernel-per-CPU-kthreads.txt b/Documentation/kernel-per-CPU-kthreads.txt
index 827104fb9364..f3cd299fcc41 100644
--- a/Documentation/kernel-per-CPU-kthreads.txt
+++ b/Documentation/kernel-per-CPU-kthreads.txt
@@ -162,7 +162,18 @@ Purpose: Execute workqueue requests
To reduce its OS jitter, do any of the following:
1. Run your workload at a real-time priority, which will allow
preempting the kworker daemons.
-2. Do any of the following needed to avoid jitter that your
+2. A given workqueue can be made visible in the sysfs filesystem
+ by passing the WQ_SYSFS to that workqueue's alloc_workqueue().
+ Such a workqueue can be confined to a given subset of the
+ CPUs using the /sys/devices/virtual/workqueue/*/cpumask sysfs
+ files. The set of WQ_SYSFS workqueues can be displayed using
+ "ls sys/devices/virtual/workqueue". That said, the workqueues
+ maintainer would like to caution people against indiscriminately
+ sprinkling WQ_SYSFS across all the workqueues. The reason for
+ caution is that it is easy to add WQ_SYSFS, but because sysfs is
+ part of the formal user/kernel API, it can be nearly impossible
+ to remove it, even if its addition was a mistake.
+3. Do any of the following needed to avoid jitter that your
application cannot tolerate:
a. Build your kernel with CONFIG_SLUB=y rather than
CONFIG_SLAB=y, thus avoiding the slab allocator's periodic
diff --git a/Documentation/kmemcheck.txt b/Documentation/kmemcheck.txt
index 9398a501fdb9..a41bdebbe87b 100644
--- a/Documentation/kmemcheck.txt
+++ b/Documentation/kmemcheck.txt
@@ -541,7 +541,7 @@ initialized. This is the beginning of the struct:
92 } _sifields;
93 } siginfo_t;
-On 64-bit, the int is 4 bytes long, so it must the the union member that has
+On 64-bit, the int is 4 bytes long, so it must the union member that has
not been initialized. We can verify this using gdb:
$ gdb vmlinux
diff --git a/Documentation/kmemleak.txt b/Documentation/kmemleak.txt
index b6e39739a36d..a7563ec4ea7b 100644
--- a/Documentation/kmemleak.txt
+++ b/Documentation/kmemleak.txt
@@ -11,9 +11,7 @@ with the difference that the orphan objects are not freed but only
reported via /sys/kernel/debug/kmemleak. A similar method is used by the
Valgrind tool (memcheck --leak-check) to detect the memory leaks in
user-space applications.
-
-Please check DEBUG_KMEMLEAK dependencies in lib/Kconfig.debug for supported
-architectures.
+Kmemleak is supported on x86, arm, powerpc, sparc, sh, microblaze, ppc, mips, s390, metag and tile.
Usage
-----
@@ -53,7 +51,8 @@ Memory scanning parameters can be modified at run-time by writing to the
(default 600, 0 to stop the automatic scanning)
scan - trigger a memory scan
clear - clear list of current memory leak suspects, done by
- marking all current reported unreferenced objects grey
+ marking all current reported unreferenced objects grey,
+ or free all kmemleak objects if kmemleak has been disabled.
dump=<addr> - dump information about the object found at <addr>
Kmemleak can also be disabled at boot-time by passing "kmemleak=off" on
@@ -68,7 +67,7 @@ Basic Algorithm
The memory allocations via kmalloc, vmalloc, kmem_cache_alloc and
friends are traced and the pointers, together with additional
-information like size and stack trace, are stored in a prio search tree.
+information like size and stack trace, are stored in a rbtree.
The corresponding freeing function calls are tracked and the pointers
removed from the kmemleak data structures.
@@ -84,7 +83,7 @@ The scanning algorithm steps:
1. mark all objects as white (remaining white objects will later be
considered orphan)
2. scan the memory starting with the data section and stacks, checking
- the values against the addresses stored in the prio search tree. If
+ the values against the addresses stored in the rbtree. If
a pointer to a white object is found, the object is added to the
gray list
3. scan the gray objects for matching addresses (some white objects
@@ -120,6 +119,18 @@ Then as usual to get your report with:
# cat /sys/kernel/debug/kmemleak
+Freeing kmemleak internal objects
+---------------------------------
+
+To allow access to previosuly found memory leaks after kmemleak has been
+disabled by the user or due to an fatal error, internal kmemleak objects
+won't be freed when kmemleak is disabled, and those objects may occupy
+a large part of physical memory.
+
+In this situation, you may reclaim memory with:
+
+ # echo clear > /sys/kernel/debug/kmemleak
+
Kmemleak API
------------
diff --git a/Documentation/laptops/00-INDEX b/Documentation/laptops/00-INDEX
index fa688538e757..d13b9a9a9e00 100644
--- a/Documentation/laptops/00-INDEX
+++ b/Documentation/laptops/00-INDEX
@@ -1,13 +1,15 @@
00-INDEX
- This file
-acer-wmi.txt
- - information on the Acer Laptop WMI Extras driver.
+Makefile
+ - Makefile for building dslm example program.
asus-laptop.txt
- information on the Asus Laptop Extras driver.
disk-shock-protection.txt
- information on hard disk shock protection.
dslm.c
- Simple Disk Sleep Monitor program
+hpfall.c
+ - (HP) laptop accelerometer program for disk protection.
laptop-mode.txt
- how to conserve battery power using laptop-mode.
sony-laptop.txt
diff --git a/Documentation/leds/00-INDEX b/Documentation/leds/00-INDEX
index 1ecd1596633e..b4ef1f34e25f 100644
--- a/Documentation/leds/00-INDEX
+++ b/Documentation/leds/00-INDEX
@@ -1,3 +1,7 @@
+00-INDEX
+ - This file
+leds-blinkm.txt
+ - Driver for BlinkM LED-devices.
leds-class.txt
- documents LED handling under Linux.
leds-lp3944.txt
@@ -12,3 +16,7 @@ leds-lp55xx.txt
- description about lp55xx common driver.
leds-lm3556.txt
- notes on how to use the leds-lm3556 driver.
+ledtrig-oneshot.txt
+ - One-shot LED trigger for both sporadic and dense events.
+ledtrig-transient.txt
+ - LED Transient Trigger, one shot timer activation.
diff --git a/Documentation/m68k/00-INDEX b/Documentation/m68k/00-INDEX
index a014e9f00765..2be8c6b00e74 100644
--- a/Documentation/m68k/00-INDEX
+++ b/Documentation/m68k/00-INDEX
@@ -1,5 +1,7 @@
00-INDEX
- this file
+README.buddha
+ - Amiga Buddha and Catweasel IDE Driver
kernel-options.txt
- command line options for Linux/m68k
diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt
index 102dc19c4119..556f951f8626 100644
--- a/Documentation/memory-barriers.txt
+++ b/Documentation/memory-barriers.txt
@@ -608,26 +608,30 @@ as follows:
b = p; /* BUG: Compiler can reorder!!! */
do_something();
-The solution is again ACCESS_ONCE(), which preserves the ordering between
-the load from variable 'a' and the store to variable 'b':
+The solution is again ACCESS_ONCE() and barrier(), which preserves the
+ordering between the load from variable 'a' and the store to variable 'b':
q = ACCESS_ONCE(a);
if (q) {
+ barrier();
ACCESS_ONCE(b) = p;
do_something();
} else {
+ barrier();
ACCESS_ONCE(b) = p;
do_something_else();
}
-You could also use barrier() to prevent the compiler from moving
-the stores to variable 'b', but barrier() would not prevent the
-compiler from proving to itself that a==1 always, so ACCESS_ONCE()
-is also needed.
+The initial ACCESS_ONCE() is required to prevent the compiler from
+proving the value of 'a', and the pair of barrier() invocations are
+required to prevent the compiler from pulling the two identical stores
+to 'b' out from the legs of the "if" statement.
It is important to note that control dependencies absolutely require a
a conditional. For example, the following "optimized" version of
-the above example breaks ordering:
+the above example breaks ordering, which is why the barrier() invocations
+are absolutely required if you have identical stores in both legs of
+the "if" statement:
q = ACCESS_ONCE(a);
ACCESS_ONCE(b) = p; /* BUG: No ordering vs. load from a!!! */
@@ -643,9 +647,11 @@ It is of course legal for the prior load to be part of the conditional,
for example, as follows:
if (ACCESS_ONCE(a) > 0) {
+ barrier();
ACCESS_ONCE(b) = q / 2;
do_something();
} else {
+ barrier();
ACCESS_ONCE(b) = q / 3;
do_something_else();
}
@@ -659,9 +665,11 @@ the needed conditional. For example:
q = ACCESS_ONCE(a);
if (q % MAX) {
+ barrier();
ACCESS_ONCE(b) = p;
do_something();
} else {
+ barrier();
ACCESS_ONCE(b) = p;
do_something_else();
}
@@ -723,8 +731,13 @@ In summary:
use smb_rmb(), smp_wmb(), or, in the case of prior stores and
later loads, smp_mb().
+ (*) If both legs of the "if" statement begin with identical stores
+ to the same variable, a barrier() statement is required at the
+ beginning of each leg of the "if" statement.
+
(*) Control dependencies require at least one run-time conditional
- between the prior load and the subsequent store. If the compiler
+ between the prior load and the subsequent store, and this
+ conditional must involve the prior load. If the compiler
is able to optimize the conditional away, it will have also
optimized away the ordering. Careful use of ACCESS_ONCE() can
help to preserve the needed conditional.
@@ -1249,6 +1262,23 @@ The ACCESS_ONCE() function can prevent any number of optimizations that,
while perfectly safe in single-threaded code, can be fatal in concurrent
code. Here are some examples of these sorts of optimizations:
+ (*) The compiler is within its rights to reorder loads and stores
+ to the same variable, and in some cases, the CPU is within its
+ rights to reorder loads to the same variable. This means that
+ the following code:
+
+ a[0] = x;
+ a[1] = x;
+
+ Might result in an older value of x stored in a[1] than in a[0].
+ Prevent both the compiler and the CPU from doing this as follows:
+
+ a[0] = ACCESS_ONCE(x);
+ a[1] = ACCESS_ONCE(x);
+
+ In short, ACCESS_ONCE() provides cache coherence for accesses from
+ multiple CPUs to a single variable.
+
(*) The compiler is within its rights to merge successive loads from
the same variable. Such merging can cause the compiler to "optimize"
the following code:
@@ -1371,7 +1401,7 @@ code. Here are some examples of these sorts of optimizations:
process_message(msg);
}
- There is nothing to prevent the the compiler from transforming
+ There is nothing to prevent the compiler from transforming
process_level() to the following, in fact, this might well be a
win for single-threaded code:
@@ -1644,12 +1674,12 @@ for each construct. These operations all imply certain barriers:
Memory operations issued after the ACQUIRE will be completed after the
ACQUIRE operation has completed.
- Memory operations issued before the ACQUIRE may be completed after the
- ACQUIRE operation has completed. An smp_mb__before_spinlock(), combined
- with a following ACQUIRE, orders prior loads against subsequent stores and
- stores and prior stores against subsequent stores. Note that this is
- weaker than smp_mb()! The smp_mb__before_spinlock() primitive is free on
- many architectures.
+ Memory operations issued before the ACQUIRE may be completed after
+ the ACQUIRE operation has completed. An smp_mb__before_spinlock(),
+ combined with a following ACQUIRE, orders prior loads against
+ subsequent loads and stores and also orders prior stores against
+ subsequent stores. Note that this is weaker than smp_mb()! The
+ smp_mb__before_spinlock() primitive is free on many architectures.
(2) RELEASE operation implication:
@@ -1694,24 +1724,21 @@ may occur as:
ACQUIRE M, STORE *B, STORE *A, RELEASE M
-This same reordering can of course occur if the lock's ACQUIRE and RELEASE are
-to the same lock variable, but only from the perspective of another CPU not
-holding that lock.
-
-In short, a RELEASE followed by an ACQUIRE may -not- be assumed to be a full
-memory barrier because it is possible for a preceding RELEASE to pass a
-later ACQUIRE from the viewpoint of the CPU, but not from the viewpoint
-of the compiler. Note that deadlocks cannot be introduced by this
-interchange because if such a deadlock threatened, the RELEASE would
-simply complete.
-
-If it is necessary for a RELEASE-ACQUIRE pair to produce a full barrier, the
-ACQUIRE can be followed by an smp_mb__after_unlock_lock() invocation. This
-will produce a full barrier if either (a) the RELEASE and the ACQUIRE are
-executed by the same CPU or task, or (b) the RELEASE and ACQUIRE act on the
-same variable. The smp_mb__after_unlock_lock() primitive is free on many
-architectures. Without smp_mb__after_unlock_lock(), the critical sections
-corresponding to the RELEASE and the ACQUIRE can cross:
+When the ACQUIRE and RELEASE are a lock acquisition and release,
+respectively, this same reordering can occur if the lock's ACQUIRE and
+RELEASE are to the same lock variable, but only from the perspective of
+another CPU not holding that lock. In short, a ACQUIRE followed by an
+RELEASE may -not- be assumed to be a full memory barrier.
+
+Similarly, the reverse case of a RELEASE followed by an ACQUIRE does not
+imply a full memory barrier. If it is necessary for a RELEASE-ACQUIRE
+pair to produce a full barrier, the ACQUIRE can be followed by an
+smp_mb__after_unlock_lock() invocation. This will produce a full barrier
+if either (a) the RELEASE and the ACQUIRE are executed by the same
+CPU or task, or (b) the RELEASE and ACQUIRE act on the same variable.
+The smp_mb__after_unlock_lock() primitive is free on many architectures.
+Without smp_mb__after_unlock_lock(), the CPU's execution of the critical
+sections corresponding to the RELEASE and the ACQUIRE can cross, so that:
*A = a;
RELEASE M
@@ -1722,7 +1749,36 @@ could occur as:
ACQUIRE N, STORE *B, STORE *A, RELEASE M
-With smp_mb__after_unlock_lock(), they cannot, so that:
+It might appear that this reordering could introduce a deadlock.
+However, this cannot happen because if such a deadlock threatened,
+the RELEASE would simply complete, thereby avoiding the deadlock.
+
+ Why does this work?
+
+ One key point is that we are only talking about the CPU doing
+ the reordering, not the compiler. If the compiler (or, for
+ that matter, the developer) switched the operations, deadlock
+ -could- occur.
+
+ But suppose the CPU reordered the operations. In this case,
+ the unlock precedes the lock in the assembly code. The CPU
+ simply elected to try executing the later lock operation first.
+ If there is a deadlock, this lock operation will simply spin (or
+ try to sleep, but more on that later). The CPU will eventually
+ execute the unlock operation (which preceded the lock operation
+ in the assembly code), which will unravel the potential deadlock,
+ allowing the lock operation to succeed.
+
+ But what if the lock is a sleeplock? In that case, the code will
+ try to enter the scheduler, where it will eventually encounter
+ a memory barrier, which will force the earlier unlock operation
+ to complete, again unraveling the deadlock. There might be
+ a sleep-unlock race, but the locking primitive needs to resolve
+ such races properly in any case.
+
+With smp_mb__after_unlock_lock(), the two critical sections cannot overlap.
+For example, with the following code, the store to *A will always be
+seen by other CPUs before the store to *B:
*A = a;
RELEASE M
@@ -1730,13 +1786,18 @@ With smp_mb__after_unlock_lock(), they cannot, so that:
smp_mb__after_unlock_lock();
*B = b;
-will always occur as either of the following:
+The operations will always occur in one of the following orders:
- STORE *A, RELEASE, ACQUIRE, STORE *B
- STORE *A, ACQUIRE, RELEASE, STORE *B
+ STORE *A, RELEASE, ACQUIRE, smp_mb__after_unlock_lock(), STORE *B
+ STORE *A, ACQUIRE, RELEASE, smp_mb__after_unlock_lock(), STORE *B
+ ACQUIRE, STORE *A, RELEASE, smp_mb__after_unlock_lock(), STORE *B
If the RELEASE and ACQUIRE were instead both operating on the same lock
-variable, only the first of these two alternatives can occur.
+variable, only the first of these alternatives can occur. In addition,
+the more strongly ordered systems may rule out some of the above orders.
+But in any case, as noted earlier, the smp_mb__after_unlock_lock()
+ensures that the store to *A will always be seen as happening before
+the store to *B.
Locks and semaphores may not provide any guarantee of ordering on UP compiled
systems, and so cannot be counted on in such a situation to actually achieve
@@ -2757,7 +2818,7 @@ in that order, but, without intervention, the sequence may have almost any
combination of elements combined or discarded, provided the program's view of
the world remains consistent. Note that ACCESS_ONCE() is -not- optional
in the above example, as there are architectures where a given CPU might
-interchange successive loads to the same location. On such architectures,
+reorder successive loads to the same location. On such architectures,
ACCESS_ONCE() does whatever is necessary to prevent this, for example, on
Itanium the volatile casts used by ACCESS_ONCE() cause GCC to emit the
special ld.acq and st.rel instructions that prevent such reordering.
diff --git a/Documentation/module-signing.txt b/Documentation/module-signing.txt
index 2b40e04d3c49..09b583e38907 100644
--- a/Documentation/module-signing.txt
+++ b/Documentation/module-signing.txt
@@ -77,11 +77,11 @@ This has a number of options available:
This presents a choice of which hash algorithm the installation phase will
sign the modules with:
- CONFIG_SIG_SHA1 "Sign modules with SHA-1"
- CONFIG_SIG_SHA224 "Sign modules with SHA-224"
- CONFIG_SIG_SHA256 "Sign modules with SHA-256"
- CONFIG_SIG_SHA384 "Sign modules with SHA-384"
- CONFIG_SIG_SHA512 "Sign modules with SHA-512"
+ CONFIG_MODULE_SIG_SHA1 "Sign modules with SHA-1"
+ CONFIG_MODULE_SIG_SHA224 "Sign modules with SHA-224"
+ CONFIG_MODULE_SIG_SHA256 "Sign modules with SHA-256"
+ CONFIG_MODULE_SIG_SHA384 "Sign modules with SHA-384"
+ CONFIG_MODULE_SIG_SHA512 "Sign modules with SHA-512"
The algorithm selected here will also be built into the kernel (rather
than being a module) so that modules signed with that algorithm can have
diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX
index f11580f8719a..557b6ef70c26 100644
--- a/Documentation/networking/00-INDEX
+++ b/Documentation/networking/00-INDEX
@@ -6,8 +6,14 @@
- information on the 3Com Etherlink III Series Ethernet cards.
6pack.txt
- info on the 6pack protocol, an alternative to KISS for AX.25
-DLINK.txt
- - info on the D-Link DE-600/DE-620 parallel port pocket adapters
+LICENSE.qla3xxx
+ - GPLv2 for QLogic Linux Networking HBA Driver
+LICENSE.qlge
+ - GPLv2 for QLogic Linux qlge NIC Driver
+LICENSE.qlcnic
+ - GPLv2 for QLogic Linux qlcnic NIC Driver
+Makefile
+ - Makefile for docsrc.
PLIP.txt
- PLIP: The Parallel Line Internet Protocol device driver
README.ipw2100
@@ -17,7 +23,7 @@ README.ipw2200
README.sb1000
- info on General Instrument/NextLevel SURFboard1000 cable modem.
alias.txt
- - info on using alias network devices
+ - info on using alias network devices.
arcnet-hardware.txt
- tons of info on ARCnet, hubs, jumper settings for ARCnet cards, etc.
arcnet.txt
@@ -80,7 +86,7 @@ framerelay.txt
- info on using Frame Relay/Data Link Connection Identifier (DLCI).
gen_stats.txt
- Generic networking statistics for netlink users.
-generic_hdlc.txt
+generic-hdlc.txt
- The generic High Level Data Link Control (HDLC) layer.
generic_netlink.txt
- info on Generic Netlink
@@ -88,6 +94,8 @@ gianfar.txt
- Gianfar Ethernet Driver.
i40e.txt
- README for the Intel Ethernet Controller XL710 Driver (i40e).
+i40evf.txt
+ - Short note on the Driver for the Intel(R) XL710 X710 Virtual Function
ieee802154.txt
- Linux IEEE 802.15.4 implementation, API and drivers
igb.txt
@@ -102,6 +110,8 @@ ipddp.txt
- AppleTalk-IP Decapsulation and AppleTalk-IP Encapsulation
iphase.txt
- Interphase PCI ATM (i)Chip IA Linux driver info.
+ipsec.txt
+ - Note on not compressing IPSec payload and resulting failed policy check.
ipv6.txt
- Options to the ipv6 kernel module.
ipvs-sysctl.txt
@@ -120,6 +130,8 @@ lapb-module.txt
- programming information of the LAPB module.
ltpc.txt
- the Apple or Farallon LocalTalk PC card driver
+mac80211-auth-assoc-deauth.txt
+ - authentication and association / deauth-disassoc with max80211
mac80211-injection.txt
- HOWTO use packet injection with mac80211
multiqueue.txt
@@ -134,6 +146,10 @@ netdevices.txt
- info on network device driver functions exported to the kernel.
netif-msg.txt
- Design of the network interface message level setting (NETIF_MSG_*).
+netlink_mmap.txt
+ - memory mapped I/O with netlink
+nf_conntrack-sysctl.txt
+ - list of netfilter-sysctl knobs.
nfc.txt
- The Linux Near Field Communication (NFS) subsystem.
openvswitch.txt
@@ -176,7 +192,7 @@ skfp.txt
- SysKonnect FDDI (SK-5xxx, Compaq Netelligent) driver info.
smc9.txt
- the driver for SMC's 9000 series of Ethernet cards
-spider-net.txt
+spider_net.txt
- README for the Spidernet Driver (as found in PS3 / Cell BE).
stmmac.txt
- README for the STMicro Synopsys Ethernet driver.
@@ -188,6 +204,8 @@ tcp.txt
- short blurb on how TCP output takes place.
tcp-thin.txt
- kernel tuning options for low rate 'thin' TCP streams.
+team.txt
+ - pointer to information for ethernet teaming devices.
tlan.txt
- ThunderLAN (Compaq Netelligent 10/100, Olicom OC-2xxx) driver info.
tproxy.txt
@@ -200,6 +218,8 @@ vortex.txt
- info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) Ethernet cards.
vxge.txt
- README for the Neterion X3100 PCIe Server Adapter.
+vxlan.txt
+ - Virtual extensible LAN overview
x25.txt
- general info on X.25 development.
x25-iface.txt
diff --git a/Documentation/networking/3c505.txt b/Documentation/networking/3c505.txt
deleted file mode 100644
index 72f38b13101d..000000000000
--- a/Documentation/networking/3c505.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-The 3Com Etherlink Plus (3c505) driver.
-
-This driver now uses DMA. There is currently no support for PIO operation.
-The default DMA channel is 6; this is _not_ autoprobed, so you must
-make sure you configure it correctly. If loading the driver as a
-module, you can do this with "modprobe 3c505 dma=n". If the driver is
-linked statically into the kernel, you must either use an "ether="
-statement on the command line, or change the definition of ELP_DMA in 3c505.h.
-
-The driver will warn you if it has to fall back on the compiled in
-default DMA channel.
-
-If no base address is given at boot time, the driver will autoprobe
-ports 0x300, 0x280 and 0x310 (in that order). If no IRQ is given, the driver
-will try to probe for it.
-
-The driver can be used as a loadable module.
-
-Theoretically, one instance of the driver can now run multiple cards,
-in the standard way (when loading a module, say "modprobe 3c505
-io=0x300,0x340 irq=10,11 dma=6,7" or whatever). I have not tested
-this, though.
-
-The driver may now support revision 2 hardware; the dependency on
-being able to read the host control register has been removed. This
-is also untested, since I don't have a suitable card.
-
-Known problems:
- I still see "DMA upload timed out" messages from time to time. These
-seem to be fairly non-fatal though.
- The card is old and slow.
-
-To do:
- Improve probe/setup code
- Test multicast and promiscuous operation
-
-Authors:
- The driver is mainly written by Craig Southeren, email
- <craigs@ineluki.apana.org.au>.
- Parts of the driver (adapting the driver to 1.1.4+ kernels,
- IRQ/address detection, some changes) and this README by
- Juha Laiho <jlaiho@ichaos.nullnet.fi>.
- DMA mode, more fixes, etc, by Philip Blundell <pjb27@cam.ac.uk>
- Multicard support, Software configurable DMA, etc., by
- Christopher Collins <ccollins@pcug.org.au>
diff --git a/Documentation/networking/altera_tse.txt b/Documentation/networking/altera_tse.txt
new file mode 100644
index 000000000000..3f24df8c6e65
--- /dev/null
+++ b/Documentation/networking/altera_tse.txt
@@ -0,0 +1,263 @@
+ Altera Triple-Speed Ethernet MAC driver
+
+Copyright (C) 2008-2014 Altera Corporation
+
+This is the driver for the Altera Triple-Speed Ethernet (TSE) controllers
+using the SGDMA and MSGDMA soft DMA IP components. The driver uses the
+platform bus to obtain component resources. The designs used to test this
+driver were built for a Cyclone(R) V SOC FPGA board, a Cyclone(R) V FPGA board,
+and tested with ARM and NIOS processor hosts seperately. The anticipated use
+cases are simple communications between an embedded system and an external peer
+for status and simple configuration of the embedded system.
+
+For more information visit www.altera.com and www.rocketboards.org. Support
+forums for the driver may be found on www.rocketboards.org, and a design used
+to test this driver may be found there as well. Support is also available from
+the maintainer of this driver, found in MAINTAINERS.
+
+The Triple-Speed Ethernet, SGDMA, and MSGDMA components are all soft IP
+components that can be assembled and built into an FPGA using the Altera
+Quartus toolchain. Quartus 13.1 and 14.0 were used to build the design that
+this driver was tested against. The sopc2dts tool is used to create the
+device tree for the driver, and may be found at rocketboards.org.
+
+The driver probe function examines the device tree and determines if the
+Triple-Speed Ethernet instance is using an SGDMA or MSGDMA component. The
+probe function then installs the appropriate set of DMA routines to
+initialize, setup transmits, receives, and interrupt handling primitives for
+the respective configurations.
+
+The SGDMA component is to be deprecated in the near future (over the next 1-2
+years as of this writing in early 2014) in favor of the MSGDMA component.
+SGDMA support is included for existing designs and reference in case a
+developer wishes to support their own soft DMA logic and driver support. Any
+new designs should not use the SGDMA.
+
+The SGDMA supports only a single transmit or receive operation at a time, and
+therefore will not perform as well compared to the MSGDMA soft IP. Please
+visit www.altera.com for known, documented SGDMA errata.
+
+Scatter-gather DMA is not supported by the SGDMA or MSGDMA at this time.
+Scatter-gather DMA will be added to a future maintenance update to this
+driver.
+
+Jumbo frames are not supported at this time.
+
+The driver limits PHY operations to 10/100Mbps, and has not yet been fully
+tested for 1Gbps. This support will be added in a future maintenance update.
+
+1) Kernel Configuration
+The kernel configuration option is ALTERA_TSE:
+ Device Drivers ---> Network device support ---> Ethernet driver support --->
+ Altera Triple-Speed Ethernet MAC support (ALTERA_TSE)
+
+2) Driver parameters list:
+ debug: message level (0: no output, 16: all);
+ dma_rx_num: Number of descriptors in the RX list (default is 64);
+ dma_tx_num: Number of descriptors in the TX list (default is 64).
+
+3) Command line options
+Driver parameters can be also passed in command line by using:
+ altera_tse=dma_rx_num:128,dma_tx_num:512
+
+4) Driver information and notes
+
+4.1) Transmit process
+When the driver's transmit routine is called by the kernel, it sets up a
+transmit descriptor by calling the underlying DMA transmit routine (SGDMA or
+MSGDMA), and initites a transmit operation. Once the transmit is complete, an
+interrupt is driven by the transmit DMA logic. The driver handles the transmit
+completion in the context of the interrupt handling chain by recycling
+resource required to send and track the requested transmit operation.
+
+4.2) Receive process
+The driver will post receive buffers to the receive DMA logic during driver
+intialization. Receive buffers may or may not be queued depending upon the
+underlying DMA logic (MSGDMA is able queue receive buffers, SGDMA is not able
+to queue receive buffers to the SGDMA receive logic). When a packet is
+received, the DMA logic generates an interrupt. The driver handles a receive
+interrupt by obtaining the DMA receive logic status, reaping receive
+completions until no more receive completions are available.
+
+4.3) Interrupt Mitigation
+The driver is able to mitigate the number of its DMA interrupts
+using NAPI for receive operations. Interrupt mitigation is not yet supported
+for transmit operations, but will be added in a future maintenance release.
+
+4.4) Ethtool support
+Ethtool is supported. Driver statistics and internal errors can be taken using:
+ethtool -S ethX command. It is possible to dump registers etc.
+
+4.5) PHY Support
+The driver is compatible with PAL to work with PHY and GPHY devices.
+
+4.7) List of source files:
+ o Kconfig
+ o Makefile
+ o altera_tse_main.c: main network device driver
+ o altera_tse_ethtool.c: ethtool support
+ o altera_tse.h: private driver structure and common definitions
+ o altera_msgdma.h: MSGDMA implementation function definitions
+ o altera_sgdma.h: SGDMA implementation function definitions
+ o altera_msgdma.c: MSGDMA implementation
+ o altera_sgdma.c: SGDMA implementation
+ o altera_sgdmahw.h: SGDMA register and descriptor definitions
+ o altera_msgdmahw.h: MSGDMA register and descriptor definitions
+ o altera_utils.c: Driver utility functions
+ o altera_utils.h: Driver utility function definitions
+
+5) Debug Information
+
+The driver exports debug information such as internal statistics,
+debug information, MAC and DMA registers etc.
+
+A user may use the ethtool support to get statistics:
+e.g. using: ethtool -S ethX (that shows the statistics counters)
+or sees the MAC registers: e.g. using: ethtool -d ethX
+
+The developer can also use the "debug" module parameter to get
+further debug information.
+
+6) Statistics Support
+
+The controller and driver support a mix of IEEE standard defined statistics,
+RFC defined statistics, and driver or Altera defined statistics. The four
+specifications containing the standard definitions for these statistics are
+as follows:
+
+ o IEEE 802.3-2012 - IEEE Standard for Ethernet.
+ o RFC 2863 found at http://www.rfc-editor.org/rfc/rfc2863.txt.
+ o RFC 2819 found at http://www.rfc-editor.org/rfc/rfc2819.txt.
+ o Altera Triple Speed Ethernet User Guide, found at http://www.altera.com
+
+The statistics supported by the TSE and the device driver are as follows:
+
+"tx_packets" is equivalent to aFramesTransmittedOK defined in IEEE 802.3-2012,
+Section 5.2.2.1.2. This statistics is the count of frames that are successfully
+transmitted.
+
+"rx_packets" is equivalent to aFramesReceivedOK defined in IEEE 802.3-2012,
+Section 5.2.2.1.5. This statistic is the count of frames that are successfully
+received. This count does not include any error packets such as CRC errors,
+length errors, or alignment errors.
+
+"rx_crc_errors" is equivalent to aFrameCheckSequenceErrors defined in IEEE
+802.3-2012, Section 5.2.2.1.6. This statistic is the count of frames that are
+an integral number of bytes in length and do not pass the CRC test as the frame
+is received.
+
+"rx_align_errors" is equivalent to aAlignmentErrors defined in IEEE 802.3-2012,
+Section 5.2.2.1.7. This statistic is the count of frames that are not an
+integral number of bytes in length and do not pass the CRC test as the frame is
+received.
+
+"tx_bytes" is equivalent to aOctetsTransmittedOK defined in IEEE 802.3-2012,
+Section 5.2.2.1.8. This statistic is the count of data and pad bytes
+successfully transmitted from the interface.
+
+"rx_bytes" is equivalent to aOctetsReceivedOK defined in IEEE 802.3-2012,
+Section 5.2.2.1.14. This statistic is the count of data and pad bytes
+successfully received by the controller.
+
+"tx_pause" is equivalent to aPAUSEMACCtrlFramesTransmitted defined in IEEE
+802.3-2012, Section 30.3.4.2. This statistic is a count of PAUSE frames
+transmitted from the network controller.
+
+"rx_pause" is equivalent to aPAUSEMACCtrlFramesReceived defined in IEEE
+802.3-2012, Section 30.3.4.3. This statistic is a count of PAUSE frames
+received by the network controller.
+
+"rx_errors" is equivalent to ifInErrors defined in RFC 2863. This statistic is
+a count of the number of packets received containing errors that prevented the
+packet from being delivered to a higher level protocol.
+
+"tx_errors" is equivalent to ifOutErrors defined in RFC 2863. This statistic
+is a count of the number of packets that could not be transmitted due to errors.
+
+"rx_unicast" is equivalent to ifInUcastPkts defined in RFC 2863. This
+statistic is a count of the number of packets received that were not addressed
+to the broadcast address or a multicast group.
+
+"rx_multicast" is equivalent to ifInMulticastPkts defined in RFC 2863. This
+statistic is a count of the number of packets received that were addressed to
+a multicast address group.
+
+"rx_broadcast" is equivalent to ifInBroadcastPkts defined in RFC 2863. This
+statistic is a count of the number of packets received that were addressed to
+the broadcast address.
+
+"tx_discards" is equivalent to ifOutDiscards defined in RFC 2863. This
+statistic is the number of outbound packets not transmitted even though an
+error was not detected. An example of a reason this might occur is to free up
+internal buffer space.
+
+"tx_unicast" is equivalent to ifOutUcastPkts defined in RFC 2863. This
+statistic counts the number of packets transmitted that were not addressed to
+a multicast group or broadcast address.
+
+"tx_multicast" is equivalent to ifOutMulticastPkts defined in RFC 2863. This
+statistic counts the number of packets transmitted that were addressed to a
+multicast group.
+
+"tx_broadcast" is equivalent to ifOutBroadcastPkts defined in RFC 2863. This
+statistic counts the number of packets transmitted that were addressed to a
+broadcast address.
+
+"ether_drops" is equivalent to etherStatsDropEvents defined in RFC 2819.
+This statistic counts the number of packets dropped due to lack of internal
+controller resources.
+
+"rx_total_bytes" is equivalent to etherStatsOctets defined in RFC 2819.
+This statistic counts the total number of bytes received by the controller,
+including error and discarded packets.
+
+"rx_total_packets" is equivalent to etherStatsPkts defined in RFC 2819.
+This statistic counts the total number of packets received by the controller,
+including error, discarded, unicast, multicast, and broadcast packets.
+
+"rx_undersize" is equivalent to etherStatsUndersizePkts defined in RFC 2819.
+This statistic counts the number of correctly formed packets received less
+than 64 bytes long.
+
+"rx_oversize" is equivalent to etherStatsOversizePkts defined in RFC 2819.
+This statistic counts the number of correctly formed packets greater than 1518
+bytes long.
+
+"rx_64_bytes" is equivalent to etherStatsPkts64Octets defined in RFC 2819.
+This statistic counts the total number of packets received that were 64 octets
+in length.
+
+"rx_65_127_bytes" is equivalent to etherStatsPkts65to127Octets defined in RFC
+2819. This statistic counts the total number of packets received that were
+between 65 and 127 octets in length inclusive.
+
+"rx_128_255_bytes" is equivalent to etherStatsPkts128to255Octets defined in
+RFC 2819. This statistic is the total number of packets received that were
+between 128 and 255 octets in length inclusive.
+
+"rx_256_511_bytes" is equivalent to etherStatsPkts256to511Octets defined in
+RFC 2819. This statistic is the total number of packets received that were
+between 256 and 511 octets in length inclusive.
+
+"rx_512_1023_bytes" is equivalent to etherStatsPkts512to1023Octets defined in
+RFC 2819. This statistic is the total number of packets received that were
+between 512 and 1023 octets in length inclusive.
+
+"rx_1024_1518_bytes" is equivalent to etherStatsPkts1024to1518Octets define
+in RFC 2819. This statistic is the total number of packets received that were
+between 1024 and 1518 octets in length inclusive.
+
+"rx_gte_1519_bytes" is a statistic defined specific to the behavior of the
+Altera TSE. This statistics counts the number of received good and errored
+frames between the length of 1519 and the maximum frame length configured
+in the frm_length register. See the Altera TSE User Guide for More details.
+
+"rx_jabbers" is equivalent to etherStatsJabbers defined in RFC 2819. This
+statistic is the total number of packets received that were longer than 1518
+octets, and had either a bad CRC with an integral number of octets (CRC Error)
+or a bad CRC with a non-integral number of octets (Alignment Error).
+
+"rx_runts" is equivalent to etherStatsFragments defined in RFC 2819. This
+statistic is the total number of packets received that were less than 64 octets
+in length and had either a bad CRC with an integral number of octets (CRC
+error) or a bad CRC with a non-integral number of octets (Alignment Error).
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index 5cdb22971d19..a383c00392d0 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -270,16 +270,15 @@ arp_ip_target
arp_validate
Specifies whether or not ARP probes and replies should be
- validated in the active-backup mode. This causes the ARP
- monitor to examine the incoming ARP requests and replies, and
- only consider a slave to be up if it is receiving the
- appropriate ARP traffic.
+ validated in any mode that supports arp monitoring, or whether
+ non-ARP traffic should be filtered (disregarded) for link
+ monitoring purposes.
Possible values are:
none or 0
- No validation is performed. This is the default.
+ No validation or filtering is performed.
active or 1
@@ -293,31 +292,68 @@ arp_validate
Validation is performed for all slaves.
- For the active slave, the validation checks ARP replies to
- confirm that they were generated by an arp_ip_target. Since
- backup slaves do not typically receive these replies, the
- validation performed for backup slaves is on the ARP request
- sent out via the active slave. It is possible that some
- switch or network configurations may result in situations
- wherein the backup slaves do not receive the ARP requests; in
- such a situation, validation of backup slaves must be
- disabled.
-
- The validation of ARP requests on backup slaves is mainly
- helping bonding to decide which slaves are more likely to
- work in case of the active slave failure, it doesn't really
- guarantee that the backup slave will work if it's selected
- as the next active slave.
-
- This option is useful in network configurations in which
- multiple bonding hosts are concurrently issuing ARPs to one or
- more targets beyond a common switch. Should the link between
- the switch and target fail (but not the switch itself), the
- probe traffic generated by the multiple bonding instances will
- fool the standard ARP monitor into considering the links as
- still up. Use of the arp_validate option can resolve this, as
- the ARP monitor will only consider ARP requests and replies
- associated with its own instance of bonding.
+ filter or 4
+
+ Filtering is applied to all slaves. No validation is
+ performed.
+
+ filter_active or 5
+
+ Filtering is applied to all slaves, validation is performed
+ only for the active slave.
+
+ filter_backup or 6
+
+ Filtering is applied to all slaves, validation is performed
+ only for backup slaves.
+
+ Validation:
+
+ Enabling validation causes the ARP monitor to examine the incoming
+ ARP requests and replies, and only consider a slave to be up if it
+ is receiving the appropriate ARP traffic.
+
+ For an active slave, the validation checks ARP replies to confirm
+ that they were generated by an arp_ip_target. Since backup slaves
+ do not typically receive these replies, the validation performed
+ for backup slaves is on the broadcast ARP request sent out via the
+ active slave. It is possible that some switch or network
+ configurations may result in situations wherein the backup slaves
+ do not receive the ARP requests; in such a situation, validation
+ of backup slaves must be disabled.
+
+ The validation of ARP requests on backup slaves is mainly helping
+ bonding to decide which slaves are more likely to work in case of
+ the active slave failure, it doesn't really guarantee that the
+ backup slave will work if it's selected as the next active slave.
+
+ Validation is useful in network configurations in which multiple
+ bonding hosts are concurrently issuing ARPs to one or more targets
+ beyond a common switch. Should the link between the switch and
+ target fail (but not the switch itself), the probe traffic
+ generated by the multiple bonding instances will fool the standard
+ ARP monitor into considering the links as still up. Use of
+ validation can resolve this, as the ARP monitor will only consider
+ ARP requests and replies associated with its own instance of
+ bonding.
+
+ Filtering:
+
+ Enabling filtering causes the ARP monitor to only use incoming ARP
+ packets for link availability purposes. Arriving packets that are
+ not ARPs are delivered normally, but do not count when determining
+ if a slave is available.
+
+ Filtering operates by only considering the reception of ARP
+ packets (any ARP packet, regardless of source or destination) when
+ determining if a slave has received traffic for link availability
+ purposes.
+
+ Filtering is useful in network configurations in which significant
+ levels of third party broadcast traffic would fool the standard
+ ARP monitor into considering the links as still up. Use of
+ filtering can resolve this, as only ARP traffic is considered for
+ link availability purposes.
This option was added in bonding version 3.1.0.
diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt
index f3089d423515..2fa44cbe81b7 100644
--- a/Documentation/networking/can.txt
+++ b/Documentation/networking/can.txt
@@ -554,12 +554,6 @@ solution for a couple of reasons:
not specified in the struct can_frame and therefore it is only valid in
CANFD_MTU sized CAN FD frames.
- As long as the payload length is <=8 the received CAN frames from CAN FD
- capable CAN devices can be received and read by legacy sockets too. When
- user-generated CAN FD frames have a payload length <=8 these can be send
- by legacy CAN network interfaces too. Sending CAN FD frames with payload
- length > 8 to a legacy CAN network interface returns an -EMSGSIZE error.
-
Implementation hint for new CAN applications:
To build a CAN FD aware application use struct canfd_frame as basic CAN
@@ -1023,7 +1017,7 @@ solution for a couple of reasons:
in case of a bus-off condition after the specified delay time
in milliseconds. By default it's off.
- "bitrate 125000 sample_point 0.875"
+ "bitrate 125000 sample-point 0.875"
Shows the real bit-rate in bits/sec and the sample-point in the
range 0.000..0.999. If the calculation of bit-timing parameters
is enabled in the kernel (CONFIG_CAN_CALC_BITTIMING=y), the
diff --git a/Documentation/networking/filter.txt b/Documentation/networking/filter.txt
index a06b48d2f5cc..81f940f4e884 100644
--- a/Documentation/networking/filter.txt
+++ b/Documentation/networking/filter.txt
@@ -546,6 +546,130 @@ ffffffffa0069c8f + <x>:
For BPF JIT developers, bpf_jit_disasm, bpf_asm and bpf_dbg provides a useful
toolchain for developing and testing the kernel's JIT compiler.
+BPF kernel internals
+--------------------
+Internally, for the kernel interpreter, a different BPF instruction set
+format with similar underlying principles from BPF described in previous
+paragraphs is being used. However, the instruction set format is modelled
+closer to the underlying architecture to mimic native instruction sets, so
+that a better performance can be achieved (more details later).
+
+It is designed to be JITed with one to one mapping, which can also open up
+the possibility for GCC/LLVM compilers to generate optimized BPF code through
+a BPF backend that performs almost as fast as natively compiled code.
+
+The new instruction set was originally designed with the possible goal in
+mind to write programs in "restricted C" and compile into BPF with a optional
+GCC/LLVM backend, so that it can just-in-time map to modern 64-bit CPUs with
+minimal performance overhead over two steps, that is, C -> BPF -> native code.
+
+Currently, the new format is being used for running user BPF programs, which
+includes seccomp BPF, classic socket filters, cls_bpf traffic classifier,
+team driver's classifier for its load-balancing mode, netfilter's xt_bpf
+extension, PTP dissector/classifier, and much more. They are all internally
+converted by the kernel into the new instruction set representation and run
+in the extended interpreter. For in-kernel handlers, this all works
+transparently by using sk_unattached_filter_create() for setting up the
+filter, resp. sk_unattached_filter_destroy() for destroying it. The macro
+SK_RUN_FILTER(filter, ctx) transparently invokes the right BPF function to
+run the filter. 'filter' is a pointer to struct sk_filter that we got from
+sk_unattached_filter_create(), and 'ctx' the given context (e.g. skb pointer).
+All constraints and restrictions from sk_chk_filter() apply before a
+conversion to the new layout is being done behind the scenes!
+
+Currently, for JITing, the user BPF format is being used and current BPF JIT
+compilers reused whenever possible. In other words, we do not (yet!) perform
+a JIT compilation in the new layout, however, future work will successively
+migrate traditional JIT compilers into the new instruction format as well, so
+that they will profit from the very same benefits. Thus, when speaking about
+JIT in the following, a JIT compiler (TBD) for the new instruction format is
+meant in this context.
+
+Some core changes of the new internal format:
+
+- Number of registers increase from 2 to 10:
+
+ The old format had two registers A and X, and a hidden frame pointer. The
+ new layout extends this to be 10 internal registers and a read-only frame
+ pointer. Since 64-bit CPUs are passing arguments to functions via registers
+ the number of args from BPF program to in-kernel function is restricted
+ to 5 and one register is used to accept return value from an in-kernel
+ function. Natively, x86_64 passes first 6 arguments in registers, aarch64/
+ sparcv9/mips64 have 7 - 8 registers for arguments; x86_64 has 6 callee saved
+ registers, and aarch64/sparcv9/mips64 have 11 or more callee saved registers.
+
+ Therefore, BPF calling convention is defined as:
+
+ * R0 - return value from in-kernel function
+ * R1 - R5 - arguments from BPF program to in-kernel function
+ * R6 - R9 - callee saved registers that in-kernel function will preserve
+ * R10 - read-only frame pointer to access stack
+
+ Thus, all BPF registers map one to one to HW registers on x86_64, aarch64,
+ etc, and BPF calling convention maps directly to ABIs used by the kernel on
+ 64-bit architectures.
+
+ On 32-bit architectures JIT may map programs that use only 32-bit arithmetic
+ and may let more complex programs to be interpreted.
+
+ R0 - R5 are scratch registers and BPF program needs spill/fill them if
+ necessary across calls. Note that there is only one BPF program (== one BPF
+ main routine) and it cannot call other BPF functions, it can only call
+ predefined in-kernel functions, though.
+
+- Register width increases from 32-bit to 64-bit:
+
+ Still, the semantics of the original 32-bit ALU operations are preserved
+ via 32-bit subregisters. All BPF registers are 64-bit with 32-bit lower
+ subregisters that zero-extend into 64-bit if they are being written to.
+ That behavior maps directly to x86_64 and arm64 subregister definition, but
+ makes other JITs more difficult.
+
+ 32-bit architectures run 64-bit internal BPF programs via interpreter.
+ Their JITs may convert BPF programs that only use 32-bit subregisters into
+ native instruction set and let the rest being interpreted.
+
+ Operation is 64-bit, because on 64-bit architectures, pointers are also
+ 64-bit wide, and we want to pass 64-bit values in/out of kernel functions,
+ so 32-bit BPF registers would otherwise require to define register-pair
+ ABI, thus, there won't be able to use a direct BPF register to HW register
+ mapping and JIT would need to do combine/split/move operations for every
+ register in and out of the function, which is complex, bug prone and slow.
+ Another reason is the use of atomic 64-bit counters.
+
+- Conditional jt/jf targets replaced with jt/fall-through:
+
+ While the original design has constructs such as "if (cond) jump_true;
+ else jump_false;", they are being replaced into alternative constructs like
+ "if (cond) jump_true; /* else fall-through */".
+
+- Introduces bpf_call insn and register passing convention for zero overhead
+ calls from/to other kernel functions:
+
+ After a kernel function call, R1 - R5 are reset to unreadable and R0 has a
+ return type of the function. Since R6 - R9 are callee saved, their state is
+ preserved across the call.
+
+Also in the new design, BPF is limited to 4096 insns, which means that any
+program will terminate quickly and will only call a fixed number of kernel
+functions. Original BPF and the new format are two operand instructions,
+which helps to do one-to-one mapping between BPF insn and x86 insn during JIT.
+
+The input context pointer for invoking the interpreter function is generic,
+its content is defined by a specific use case. For seccomp register R1 points
+to seccomp_data, for converted BPF filters R1 points to a skb.
+
+A program, that is translated internally consists of the following elements:
+
+ op:16, jt:8, jf:8, k:32 ==> op:8, a_reg:4, x_reg:4, off:16, imm:32
+
+Just like the original BPF, the new format runs within a controlled environment,
+is deterministic and the kernel can easily prove that. The safety of the program
+can be determined in two steps: first step does depth-first-search to disallow
+loops and other CFG validation; second step starts from the first insn and
+descends all possible paths. It simulates execution of every insn and observes
+the state change of registers and stack.
+
Misc
----
@@ -561,3 +685,4 @@ the underlying architecture.
Jay Schulist <jschlst@samba.org>
Daniel Borkmann <dborkman@redhat.com>
+Alexei Starovoitov <ast@plumgrid.com>
diff --git a/Documentation/networking/gianfar.txt b/Documentation/networking/gianfar.txt
index ad474ea07d07..ba1daea7f2e4 100644
--- a/Documentation/networking/gianfar.txt
+++ b/Documentation/networking/gianfar.txt
@@ -1,38 +1,8 @@
The Gianfar Ethernet Driver
-Sysfs File description
Author: Andy Fleming <afleming@freescale.com>
Updated: 2005-07-28
-SYSFS
-
-Several of the features of the gianfar driver are controlled
-through sysfs files. These are:
-
-bd_stash:
-To stash RX Buffer Descriptors in the L2, echo 'on' or '1' to
-bd_stash, echo 'off' or '0' to disable
-
-rx_stash_len:
-To stash the first n bytes of the packet in L2, echo the number
-of bytes to buf_stash_len. echo 0 to disable.
-
-WARNING: You could really screw these up if you set them too low or high!
-fifo_threshold:
-To change the number of bytes the controller needs in the
-fifo before it starts transmission, echo the number of bytes to
-fifo_thresh. Range should be 0-511.
-
-fifo_starve:
-When the FIFO has less than this many bytes during a transmit, it
-enters starve mode, and increases the priority of TX memory
-transactions. To change, echo the number of bytes to
-fifo_starve. Range should be 0-511.
-
-fifo_starve_off:
-Once in starve mode, the FIFO remains there until it has this
-many bytes. To change, echo the number of bytes to
-fifo_starve_off. Range should be 0-511.
CHECKSUM OFFLOADING
diff --git a/Documentation/networking/igb.txt b/Documentation/networking/igb.txt
index 4ebbd659256f..43d3549366a0 100644
--- a/Documentation/networking/igb.txt
+++ b/Documentation/networking/igb.txt
@@ -36,54 +36,6 @@ Default Value: 0
This parameter adds support for SR-IOV. It causes the driver to spawn up to
max_vfs worth of virtual function.
-QueuePairs
-----------
-Valid Range: 0-1
-Default Value: 1 (TX and RX will be paired onto one interrupt vector)
-
-If set to 0, when MSI-X is enabled, the TX and RX will attempt to occupy
-separate vectors.
-
-This option can be overridden to 1 if there are not sufficient interrupts
-available. This can occur if any combination of RSS, VMDQ, and max_vfs
-results in more than 4 queues being used.
-
-Node
-----
-Valid Range: 0-n
-Default Value: -1 (off)
-
- 0 - n: where n is the number of the NUMA node that should be used to
- allocate memory for this adapter port.
- -1: uses the driver default of allocating memory on whichever processor is
- running insmod/modprobe.
-
- The Node parameter will allow you to pick which NUMA node you want to have
- the adapter allocate memory from. All driver structures, in-memory queues,
- and receive buffers will be allocated on the node specified. This parameter
- is only useful when interrupt affinity is specified, otherwise some portion
- of the time the interrupt could run on a different core than the memory is
- allocated on, causing slower memory access and impacting throughput, CPU, or
- both.
-
-EEE
----
-Valid Range: 0-1
-Default Value: 1 (enabled)
-
- A link between two EEE-compliant devices will result in periodic bursts of
- data followed by long periods where in the link is in an idle state. This Low
- Power Idle (LPI) state is supported in both 1Gbps and 100Mbps link speeds.
- NOTE: EEE support requires autonegotiation.
-
-DMAC
-----
-Valid Range: 0-1
-Default Value: 1 (enabled)
- Enables or disables DMA Coalescing feature.
-
-
-
Additional Configurations
=========================
diff --git a/Documentation/networking/netlink_mmap.txt b/Documentation/networking/netlink_mmap.txt
index b26122973525..c6af4bac5aa8 100644
--- a/Documentation/networking/netlink_mmap.txt
+++ b/Documentation/networking/netlink_mmap.txt
@@ -226,9 +226,9 @@ Ring setup:
void *rx_ring, *tx_ring;
/* Configure ring parameters */
- if (setsockopt(fd, NETLINK_RX_RING, &req, sizeof(req)) < 0)
+ if (setsockopt(fd, SOL_NETLINK, NETLINK_RX_RING, &req, sizeof(req)) < 0)
exit(1);
- if (setsockopt(fd, NETLINK_TX_RING, &req, sizeof(req)) < 0)
+ if (setsockopt(fd, SOL_NETLINK, NETLINK_TX_RING, &req, sizeof(req)) < 0)
exit(1)
/* Calculate size of each individual ring */
diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt
index 1404674c0a02..6fea79efb4cb 100644
--- a/Documentation/networking/packet_mmap.txt
+++ b/Documentation/networking/packet_mmap.txt
@@ -453,7 +453,7 @@ TP_STATUS_COPY : This flag indicates that the frame (and associated
enabled previously with setsockopt() and
the PACKET_COPY_THRESH option.
- The number of frames than can be buffered to
+ The number of frames that can be buffered to
be read with recvfrom is limited like a normal socket.
See the SO_RCVBUF option in the socket (7) man page.
diff --git a/Documentation/networking/phy.txt b/Documentation/networking/phy.txt
index ebf270719402..3544c98401fd 100644
--- a/Documentation/networking/phy.txt
+++ b/Documentation/networking/phy.txt
@@ -48,7 +48,7 @@ The MDIO bus
time, so it is safe for them to block, waiting for an interrupt to signal
the operation is complete
- 2) A reset function is necessary. This is used to return the bus to an
+ 2) A reset function is optional. This is used to return the bus to an
initialized state.
3) A probe function is needed. This function should set up anything the bus
@@ -253,16 +253,25 @@ Writing a PHY driver
Each driver consists of a number of function pointers:
+ soft_reset: perform a PHY software reset
config_init: configures PHY into a sane state after a reset.
For instance, a Davicom PHY requires descrambling disabled.
probe: Allocate phy->priv, optionally refuse to bind.
PHY may not have been reset or had fixups run yet.
suspend/resume: power management
config_aneg: Changes the speed/duplex/negotiation settings
+ aneg_done: Determines the auto-negotiation result
read_status: Reads the current speed/duplex/negotiation settings
ack_interrupt: Clear a pending interrupt
+ did_interrupt: Checks if the PHY generated an interrupt
config_intr: Enable or disable interrupts
remove: Does any driver take-down
+ ts_info: Queries about the HW timestamping status
+ hwtstamp: Set the PHY HW timestamping configuration
+ rxtstamp: Requests a receive timestamp at the PHY level for a 'skb'
+ txtsamp: Requests a transmit timestamp at the PHY level for a 'skb'
+ set_wol: Enable Wake-on-LAN at the PHY level
+ get_wol: Get the Wake-on-LAN status at the PHY level
Of these, only config_aneg and read_status are required to be
assigned by the driver code. The rest are optional. Also, it is
diff --git a/Documentation/networking/pktgen.txt b/Documentation/networking/pktgen.txt
index 5a61a240a652..0e30c7845b2b 100644
--- a/Documentation/networking/pktgen.txt
+++ b/Documentation/networking/pktgen.txt
@@ -102,13 +102,18 @@ Examples:
The 'minimum' MAC is what you set with dstmac.
pgset "flag [name]" Set a flag to determine behaviour. Current flags
- are: IPSRC_RND #IP Source is random (between min/max),
- IPDST_RND, UDPSRC_RND,
- UDPDST_RND, MACSRC_RND, MACDST_RND
+ are: IPSRC_RND # IP source is random (between min/max)
+ IPDST_RND # IP destination is random
+ UDPSRC_RND, UDPDST_RND,
+ MACSRC_RND, MACDST_RND
+ TXSIZE_RND, IPV6,
MPLS_RND, VID_RND, SVID_RND
+ FLOW_SEQ,
QUEUE_MAP_RND # queue map random
QUEUE_MAP_CPU # queue map mirrors smp_processor_id()
- IPSEC # Make IPsec encapsulation for packet
+ UDPCSUM,
+ IPSEC # IPsec encapsulation (needs CONFIG_XFRM)
+ NODE_ALLOC # node specific memory allocation
pgset spi SPI_VALUE Set specific SA used to transform packet.
@@ -233,13 +238,22 @@ udp_dst_max
flag
IPSRC_RND
- TXSIZE_RND
IPDST_RND
UDPSRC_RND
UDPDST_RND
MACSRC_RND
MACDST_RND
+ TXSIZE_RND
+ IPV6
+ MPLS_RND
+ VID_RND
+ SVID_RND
+ FLOW_SEQ
+ QUEUE_MAP_RND
+ QUEUE_MAP_CPU
+ UDPCSUM
IPSEC
+ NODE_ALLOC
dst_min
dst_max
diff --git a/Documentation/networking/rxrpc.txt b/Documentation/networking/rxrpc.txt
index b89bc82eed46..16a924c486bf 100644
--- a/Documentation/networking/rxrpc.txt
+++ b/Documentation/networking/rxrpc.txt
@@ -27,6 +27,8 @@ Contents of this document:
(*) AF_RXRPC kernel interface.
+ (*) Configurable parameters.
+
========
OVERVIEW
@@ -864,3 +866,82 @@ The kernel interface functions are as follows:
This is used to allocate a null RxRPC key that can be used to indicate
anonymous security for a particular domain.
+
+
+=======================
+CONFIGURABLE PARAMETERS
+=======================
+
+The RxRPC protocol driver has a number of configurable parameters that can be
+adjusted through sysctls in /proc/net/rxrpc/:
+
+ (*) req_ack_delay
+
+ The amount of time in milliseconds after receiving a packet with the
+ request-ack flag set before we honour the flag and actually send the
+ requested ack.
+
+ Usually the other side won't stop sending packets until the advertised
+ reception window is full (to a maximum of 255 packets), so delaying the
+ ACK permits several packets to be ACK'd in one go.
+
+ (*) soft_ack_delay
+
+ The amount of time in milliseconds after receiving a new packet before we
+ generate a soft-ACK to tell the sender that it doesn't need to resend.
+
+ (*) idle_ack_delay
+
+ The amount of time in milliseconds after all the packets currently in the
+ received queue have been consumed before we generate a hard-ACK to tell
+ the sender it can free its buffers, assuming no other reason occurs that
+ we would send an ACK.
+
+ (*) resend_timeout
+
+ The amount of time in milliseconds after transmitting a packet before we
+ transmit it again, assuming no ACK is received from the receiver telling
+ us they got it.
+
+ (*) max_call_lifetime
+
+ The maximum amount of time in seconds that a call may be in progress
+ before we preemptively kill it.
+
+ (*) dead_call_expiry
+
+ The amount of time in seconds before we remove a dead call from the call
+ list. Dead calls are kept around for a little while for the purpose of
+ repeating ACK and ABORT packets.
+
+ (*) connection_expiry
+
+ The amount of time in seconds after a connection was last used before we
+ remove it from the connection list. Whilst a connection is in existence,
+ it serves as a placeholder for negotiated security; when it is deleted,
+ the security must be renegotiated.
+
+ (*) transport_expiry
+
+ The amount of time in seconds after a transport was last used before we
+ remove it from the transport list. Whilst a transport is in existence, it
+ serves to anchor the peer data and keeps the connection ID counter.
+
+ (*) rxrpc_rx_window_size
+
+ The size of the receive window in packets. This is the maximum number of
+ unconsumed received packets we're willing to hold in memory for any
+ particular call.
+
+ (*) rxrpc_rx_mtu
+
+ The maximum packet MTU size that we're willing to receive in bytes. This
+ indicates to the peer whether we're willing to accept jumbo packets.
+
+ (*) rxrpc_rx_jumbo_max
+
+ The maximum number of packets that we're willing to accept in a jumbo
+ packet. Non-terminal packets in a jumbo packet must contain a four byte
+ header plus exactly 1412 bytes of data. The terminal packet must contain
+ a four byte header plus any amount of data. In any event, a jumbo packet
+ may not exceed rxrpc_rx_mtu in size.
diff --git a/Documentation/networking/spider_net.txt b/Documentation/networking/spider_net.txt
index 4b4adb8eb14f..b0b75f8463b3 100644
--- a/Documentation/networking/spider_net.txt
+++ b/Documentation/networking/spider_net.txt
@@ -73,7 +73,7 @@ Thus, in an idle system, the GDACTDPA, tail and head pointers will
all be pointing at the same descr, which should be "empty". All of the
other descrs in the ring should be "empty" as well.
-The show_rx_chain() routine will print out the the locations of the
+The show_rx_chain() routine will print out the locations of the
GDACTDPA, tail and head pointers. It will also summarize the contents
of the ring, starting at the tail pointer, and listing the status
of the descrs that follow.
diff --git a/Documentation/networking/tcp.txt b/Documentation/networking/tcp.txt
index 7d11bb5dc30a..bdc4c0db51e1 100644
--- a/Documentation/networking/tcp.txt
+++ b/Documentation/networking/tcp.txt
@@ -30,7 +30,7 @@ A congestion control mechanism can be registered through functions in
tcp_cong.c. The functions used by the congestion control mechanism are
registered via passing a tcp_congestion_ops struct to
tcp_register_congestion_control. As a minimum name, ssthresh,
-cong_avoid, min_cwnd must be valid.
+cong_avoid must be valid.
Private data for a congestion control mechanism is stored in tp->ca_priv.
tcp_ca(tp) returns a pointer to this space. This is preallocated space - it
diff --git a/Documentation/networking/timestamping.txt b/Documentation/networking/timestamping.txt
index 661d3c316a17..bc3554124903 100644
--- a/Documentation/networking/timestamping.txt
+++ b/Documentation/networking/timestamping.txt
@@ -21,26 +21,38 @@ has such a feature).
SO_TIMESTAMPING:
-Instructs the socket layer which kind of information is wanted. The
-parameter is an integer with some of the following bits set. Setting
-other bits is an error and doesn't change the current state.
-
-SOF_TIMESTAMPING_TX_HARDWARE: try to obtain send time stamp in hardware
-SOF_TIMESTAMPING_TX_SOFTWARE: if SOF_TIMESTAMPING_TX_HARDWARE is off or
- fails, then do it in software
-SOF_TIMESTAMPING_RX_HARDWARE: return the original, unmodified time stamp
- as generated by the hardware
-SOF_TIMESTAMPING_RX_SOFTWARE: if SOF_TIMESTAMPING_RX_HARDWARE is off or
- fails, then do it in software
-SOF_TIMESTAMPING_RAW_HARDWARE: return original raw hardware time stamp
-SOF_TIMESTAMPING_SYS_HARDWARE: return hardware time stamp transformed to
- the system time base
-SOF_TIMESTAMPING_SOFTWARE: return system time stamp generated in
- software
-
-SOF_TIMESTAMPING_TX/RX determine how time stamps are generated.
-SOF_TIMESTAMPING_RAW/SYS determine how they are reported in the
-following control message:
+Instructs the socket layer which kind of information should be collected
+and/or reported. The parameter is an integer with some of the following
+bits set. Setting other bits is an error and doesn't change the current
+state.
+
+Four of the bits are requests to the stack to try to generate
+timestamps. Any combination of them is valid.
+
+SOF_TIMESTAMPING_TX_HARDWARE: try to obtain send time stamps in hardware
+SOF_TIMESTAMPING_TX_SOFTWARE: try to obtain send time stamps in software
+SOF_TIMESTAMPING_RX_HARDWARE: try to obtain receive time stamps in hardware
+SOF_TIMESTAMPING_RX_SOFTWARE: try to obtain receive time stamps in software
+
+The other three bits control which timestamps will be reported in a
+generated control message. If none of these bits are set or if none of
+the set bits correspond to data that is available, then the control
+message will not be generated:
+
+SOF_TIMESTAMPING_SOFTWARE: report systime if available
+SOF_TIMESTAMPING_SYS_HARDWARE: report hwtimetrans if available
+SOF_TIMESTAMPING_RAW_HARDWARE: report hwtimeraw if available
+
+It is worth noting that timestamps may be collected for reasons other
+than being requested by a particular socket with
+SOF_TIMESTAMPING_[TR]X_(HARD|SOFT)WARE. For example, most drivers that
+can generate hardware receive timestamps ignore
+SOF_TIMESTAMPING_RX_HARDWARE. It is still a good idea to set that flag
+in case future drivers pay attention.
+
+If timestamps are reported, they will appear in a control message with
+cmsg_level==SOL_SOCKET, cmsg_type==SO_TIMESTAMPING, and a payload like
+this:
struct scm_timestamping {
struct timespec systime;
@@ -190,6 +202,9 @@ Time stamps for outgoing packets are to be generated as follows:
and not free the skb. A driver not supporting hardware time stamping doesn't
do that. A driver must never touch sk_buff::tstamp! It is used to store
software generated time stamps by the network subsystem.
+- Driver should call skb_tx_timestamp() as close to passing sk_buff to hardware
+ as possible. skb_tx_timestamp() provides a software time stamp if requested
+ and hardware timestamping is not possible (SKBTX_IN_PROGRESS not set).
- As soon as the driver has sent the packet and/or obtained a
hardware time stamp for it, it passes the time stamp back by
calling skb_hwtstamp_tx() with the original skb, the raw
@@ -200,6 +215,3 @@ Time stamps for outgoing packets are to be generated as follows:
this would occur at a later time in the processing pipeline than other
software time stamping and therefore could lead to unexpected deltas
between time stamps.
-- If the driver did not set the SKBTX_IN_PROGRESS flag (see above), then
- dev_hard_start_xmit() checks whether software time stamping
- is wanted as fallback and potentially generates the time stamp.
diff --git a/Documentation/phy.txt b/Documentation/phy.txt
index 0103e4b15b0e..ebff6ee52441 100644
--- a/Documentation/phy.txt
+++ b/Documentation/phy.txt
@@ -75,14 +75,26 @@ Before the controller can make use of the PHY, it has to get a reference to
it. This framework provides the following APIs to get a reference to the PHY.
struct phy *phy_get(struct device *dev, const char *string);
+struct phy *phy_optional_get(struct device *dev, const char *string);
struct phy *devm_phy_get(struct device *dev, const char *string);
-
-phy_get and devm_phy_get can be used to get the PHY. In the case of dt boot,
-the string arguments should contain the phy name as given in the dt data and
-in the case of non-dt boot, it should contain the label of the PHY.
-The only difference between the two APIs is that devm_phy_get associates the
-device with the PHY using devres on successful PHY get. On driver detach,
-release function is invoked on the the devres data and devres data is freed.
+struct phy *devm_phy_optional_get(struct device *dev, const char *string);
+
+phy_get, phy_optional_get, devm_phy_get and devm_phy_optional_get can
+be used to get the PHY. In the case of dt boot, the string arguments
+should contain the phy name as given in the dt data and in the case of
+non-dt boot, it should contain the label of the PHY. The two
+devm_phy_get associates the device with the PHY using devres on
+successful PHY get. On driver detach, release function is invoked on
+the the devres data and devres data is freed. phy_optional_get and
+devm_phy_optional_get should be used when the phy is optional. These
+two functions will never return -ENODEV, but instead returns NULL when
+the phy cannot be found.
+
+It should be noted that NULL is a valid phy reference. All phy
+consumer calls on the NULL phy become NOPs. That is the release calls,
+the phy_init() and phy_exit() calls, and phy_power_on() and
+phy_power_off() calls are all NOP when applied to a NULL phy. The NULL
+phy is useful in devices for handling optional phy devices.
5. Releasing a reference to the PHY
diff --git a/Documentation/phy/samsung-usb2.txt b/Documentation/phy/samsung-usb2.txt
new file mode 100644
index 000000000000..ed12d437189d
--- /dev/null
+++ b/Documentation/phy/samsung-usb2.txt
@@ -0,0 +1,135 @@
+.------------------------------------------------------------------------------+
+| Samsung USB 2.0 PHY adaptation layer |
++-----------------------------------------------------------------------------+'
+
+| 1. Description
++----------------
+
+The architecture of the USB 2.0 PHY module in Samsung SoCs is similar
+among many SoCs. In spite of the similarities it proved difficult to
+create a one driver that would fit all these PHY controllers. Often
+the differences were minor and were found in particular bits of the
+registers of the PHY. In some rare cases the order of register writes or
+the PHY powering up process had to be altered. This adaptation layer is
+a compromise between having separate drivers and having a single driver
+with added support for many special cases.
+
+| 2. Files description
++----------------------
+
+- phy-samsung-usb2.c
+ This is the main file of the adaptation layer. This file contains
+ the probe function and provides two callbacks to the Generic PHY
+ Framework. This two callbacks are used to power on and power off the
+ phy. They carry out the common work that has to be done on all version
+ of the PHY module. Depending on which SoC was chosen they execute SoC
+ specific callbacks. The specific SoC version is selected by choosing
+ the appropriate compatible string. In addition, this file contains
+ struct of_device_id definitions for particular SoCs.
+
+- phy-samsung-usb2.h
+ This is the include file. It declares the structures used by this
+ driver. In addition it should contain extern declarations for
+ structures that describe particular SoCs.
+
+| 3. Supporting SoCs
++--------------------
+
+To support a new SoC a new file should be added to the drivers/phy
+directory. Each SoC's configuration is stored in an instance of the
+struct samsung_usb2_phy_config.
+
+struct samsung_usb2_phy_config {
+ const struct samsung_usb2_common_phy *phys;
+ int (*rate_to_clk)(unsigned long, u32 *);
+ unsigned int num_phys;
+ bool has_mode_switch;
+};
+
+The num_phys is the number of phys handled by the driver. *phys is an
+array that contains the configuration for each phy. The has_mode_switch
+property is a boolean flag that determines whether the SoC has USB host
+and device on a single pair of pins. If so, a special register has to
+be modified to change the internal routing of these pins between a USB
+device or host module.
+
+For example the configuration for Exynos 4210 is following:
+
+const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
+ .has_mode_switch = 0,
+ .num_phys = EXYNOS4210_NUM_PHYS,
+ .phys = exynos4210_phys,
+ .rate_to_clk = exynos4210_rate_to_clk,
+}
+
+- int (*rate_to_clk)(unsigned long, u32 *)
+ The rate_to_clk callback is to convert the rate of the clock
+ used as the reference clock for the PHY module to the value
+ that should be written in the hardware register.
+
+The exynos4210_phys configuration array is as follows:
+
+static const struct samsung_usb2_common_phy exynos4210_phys[] = {
+ {
+ .label = "device",
+ .id = EXYNOS4210_DEVICE,
+ .power_on = exynos4210_power_on,
+ .power_off = exynos4210_power_off,
+ },
+ {
+ .label = "host",
+ .id = EXYNOS4210_HOST,
+ .power_on = exynos4210_power_on,
+ .power_off = exynos4210_power_off,
+ },
+ {
+ .label = "hsic0",
+ .id = EXYNOS4210_HSIC0,
+ .power_on = exynos4210_power_on,
+ .power_off = exynos4210_power_off,
+ },
+ {
+ .label = "hsic1",
+ .id = EXYNOS4210_HSIC1,
+ .power_on = exynos4210_power_on,
+ .power_off = exynos4210_power_off,
+ },
+ {},
+};
+
+- int (*power_on)(struct samsung_usb2_phy_instance *);
+- int (*power_off)(struct samsung_usb2_phy_instance *);
+ These two callbacks are used to power on and power off the phy
+ by modifying appropriate registers.
+
+Final change to the driver is adding appropriate compatible value to the
+phy-samsung-usb2.c file. In case of Exynos 4210 the following lines were
+added to the struct of_device_id samsung_usb2_phy_of_match[] array:
+
+#ifdef CONFIG_PHY_EXYNOS4210_USB2
+ {
+ .compatible = "samsung,exynos4210-usb2-phy",
+ .data = &exynos4210_usb2_phy_config,
+ },
+#endif
+
+To add further flexibility to the driver the Kconfig file enables to
+include support for selected SoCs in the compiled driver. The Kconfig
+entry for Exynos 4210 is following:
+
+config PHY_EXYNOS4210_USB2
+ bool "Support for Exynos 4210"
+ depends on PHY_SAMSUNG_USB2
+ depends on CPU_EXYNOS4210
+ help
+ Enable USB PHY support for Exynos 4210. This option requires that
+ Samsung USB 2.0 PHY driver is enabled and means that support for this
+ particular SoC is compiled in the driver. In case of Exynos 4210 four
+ phys are available - device, host, HSCI0 and HSCI1.
+
+The newly created file that supports the new SoC has to be also added to the
+Makefile. In case of Exynos 4210 the added line is following:
+
+obj-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o
+
+After completing these steps the support for the new SoC should be ready.
diff --git a/Documentation/power/00-INDEX b/Documentation/power/00-INDEX
index a4d682f54231..ad04cc8097ed 100644
--- a/Documentation/power/00-INDEX
+++ b/Documentation/power/00-INDEX
@@ -4,6 +4,8 @@ apm-acpi.txt
- basic info about the APM and ACPI support.
basic-pm-debugging.txt
- Debugging suspend and resume
+charger-manager.txt
+ - Battery charger management.
devices.txt
- How drivers interact with system-wide power management
drivers-testing.txt
@@ -22,6 +24,8 @@ pm_qos_interface.txt
- info on Linux PM Quality of Service interface
power_supply_class.txt
- Tells userspace about battery, UPS, AC or DC power supply properties
+runtime_pm.txt
+ - Power management framework for I/O devices.
s2ram.txt
- How to get suspend to ram working (and debug it when it isn't)
states.txt
@@ -38,7 +42,5 @@ tricks.txt
- How to trick software suspend (to disk) into working when it isn't
userland-swsusp.txt
- Experimental implementation of software suspend in userspace
-video_extension.txt
- - ACPI video extensions
video.txt
- Video issues during resume from suspend
diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt
index a66c9821b5ce..47d46dff70f7 100644
--- a/Documentation/power/devices.txt
+++ b/Documentation/power/devices.txt
@@ -391,7 +391,7 @@ When resuming from freeze, standby or memory sleep, the phases are:
the resume methods. This generally involves undoing the actions of the
preceding suspend_late phase.
- 3 The resume methods should bring the the device back to its operating
+ 3 The resume methods should bring the device back to its operating
state, so that it can perform normal I/O. This generally involves
undoing the actions of the suspend phase.
diff --git a/Documentation/power/pm_qos_interface.txt b/Documentation/power/pm_qos_interface.txt
index 483632087788..a5da5c7e7128 100644
--- a/Documentation/power/pm_qos_interface.txt
+++ b/Documentation/power/pm_qos_interface.txt
@@ -88,17 +88,19 @@ node.
2. PM QoS per-device latency and flags framework
-For each device, there are two lists of PM QoS requests. One is maintained
-along with the aggregated target of latency value and the other is for PM QoS
-flags. Values are updated in response to changes of the request list.
+For each device, there are three lists of PM QoS requests. Two of them are
+maintained along with the aggregated targets of resume latency and active
+state latency tolerance (in microseconds) and the third one is for PM QoS flags.
+Values are updated in response to changes of the request list.
-Target latency value is simply the minimum of the request values held in the
-parameter list elements. The PM QoS flags aggregate value is a gather (bitwise
-OR) of all list elements' values. Two device PM QoS flags are defined currently:
-PM_QOS_FLAG_NO_POWER_OFF and PM_QOS_FLAG_REMOTE_WAKEUP.
+The target values of resume latency and active state latency tolerance are
+simply the minimum of the request values held in the parameter list elements.
+The PM QoS flags aggregate value is a gather (bitwise OR) of all list elements'
+values. Two device PM QoS flags are defined currently: PM_QOS_FLAG_NO_POWER_OFF
+and PM_QOS_FLAG_REMOTE_WAKEUP.
-Note: the aggregated target value is implemented as an atomic variable so that
-reading the aggregated value does not require any locking mechanism.
+Note: The aggregated target values are implemented in such a way that reading
+the aggregated value does not require any locking mechanism.
From kernel mode the use of this interface is the following:
@@ -132,19 +134,21 @@ The meaning of the return values is as follows:
PM_QOS_FLAGS_UNDEFINED: The device's PM QoS structure has not been
initialized or the list of requests is empty.
-int dev_pm_qos_add_ancestor_request(dev, handle, value)
+int dev_pm_qos_add_ancestor_request(dev, handle, type, value)
Add a PM QoS request for the first direct ancestor of the given device whose
-power.ignore_children flag is unset.
+power.ignore_children flag is unset (for DEV_PM_QOS_RESUME_LATENCY requests)
+or whose power.set_latency_tolerance callback pointer is not NULL (for
+DEV_PM_QOS_LATENCY_TOLERANCE requests).
int dev_pm_qos_expose_latency_limit(device, value)
-Add a request to the device's PM QoS list of latency constraints and create
-a sysfs attribute pm_qos_resume_latency_us under the device's power directory
-allowing user space to manipulate that request.
+Add a request to the device's PM QoS list of resume latency constraints and
+create a sysfs attribute pm_qos_resume_latency_us under the device's power
+directory allowing user space to manipulate that request.
void dev_pm_qos_hide_latency_limit(device)
Drop the request added by dev_pm_qos_expose_latency_limit() from the device's
-PM QoS list of latency constraints and remove sysfs attribute pm_qos_resume_latency_us
-from the device's power directory.
+PM QoS list of resume latency constraints and remove sysfs attribute
+pm_qos_resume_latency_us from the device's power directory.
int dev_pm_qos_expose_flags(device, value)
Add a request to the device's PM QoS list of flags and create sysfs attributes
@@ -163,7 +167,7 @@ a per-device notification tree and a global notification tree.
int dev_pm_qos_add_notifier(device, notifier):
Adds a notification callback function for the device.
The callback is called when the aggregated value of the device constraints list
-is changed.
+is changed (for resume latency device PM QoS only).
int dev_pm_qos_remove_notifier(device, notifier):
Removes the notification callback function for the device.
@@ -171,14 +175,48 @@ Removes the notification callback function for the device.
int dev_pm_qos_add_global_notifier(notifier):
Adds a notification callback function in the global notification tree of the
framework.
-The callback is called when the aggregated value for any device is changed.
+The callback is called when the aggregated value for any device is changed
+(for resume latency device PM QoS only).
int dev_pm_qos_remove_global_notifier(notifier):
Removes the notification callback function from the global notification tree
of the framework.
-From user mode:
-No API for user space access to the per-device latency constraints is provided
-yet - still under discussion.
-
+Active state latency tolerance
+
+This device PM QoS type is used to support systems in which hardware may switch
+to energy-saving operation modes on the fly. In those systems, if the operation
+mode chosen by the hardware attempts to save energy in an overly aggressive way,
+it may cause excess latencies to be visible to software, causing it to miss
+certain protocol requirements or target frame or sample rates etc.
+
+If there is a latency tolerance control mechanism for a given device available
+to software, the .set_latency_tolerance callback in that device's dev_pm_info
+structure should be populated. The routine pointed to by it is should implement
+whatever is necessary to transfer the effective requirement value to the
+hardware.
+
+Whenever the effective latency tolerance changes for the device, its
+.set_latency_tolerance() callback will be executed and the effective value will
+be passed to it. If that value is negative, which means that the list of
+latency tolerance requirements for the device is empty, the callback is expected
+to switch the underlying hardware latency tolerance control mechanism to an
+autonomous mode if available. If that value is PM_QOS_LATENCY_ANY, in turn, and
+the hardware supports a special "no requirement" setting, the callback is
+expected to use it. That allows software to prevent the hardware from
+automatically updating the device's latency tolerance in response to its power
+state changes (e.g. during transitions from D3cold to D0), which generally may
+be done in the autonomous latency tolerance control mode.
+
+If .set_latency_tolerance() is present for the device, sysfs attribute
+pm_qos_latency_tolerance_us will be present in the devivce's power directory.
+Then, user space can use that attribute to specify its latency tolerance
+requirement for the device, if any. Writing "any" to it means "no requirement,
+but do not let the hardware control latency tolerance" and writing "auto" to it
+allows the hardware to be switched to the autonomous mode if there are no other
+requirements from the kernel side in the device's list.
+
+Kernel code can use the functions described above along with the
+DEV_PM_QOS_LATENCY_TOLERANCE device PM QoS type to add, remove and update
+latency tolerance requirements for devices.
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt
index b6ce00b2be9a..5f96daf8566a 100644
--- a/Documentation/power/runtime_pm.txt
+++ b/Documentation/power/runtime_pm.txt
@@ -232,7 +232,7 @@ defined in include/linux/pm.h:
equal to zero); the initial value of it is 1 (i.e. runtime PM is
initially disabled for all devices)
- unsigned int runtime_error;
+ int runtime_error;
- if set, there was a fatal error (one of the callbacks returned error code
as described in Section 2), so the helper funtions will not work until
this flag is cleared; this is the error code returned by the failing
@@ -401,11 +401,11 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
int pm_runtime_disable(struct device *dev);
- increment the device's 'power.disable_depth' field (if the value of that
field was previously zero, this prevents subsystem-level runtime PM
- callbacks from being run for the device), make sure that all of the pending
- runtime PM operations on the device are either completed or canceled;
- returns 1 if there was a resume request pending and it was necessary to
- execute the subsystem-level resume callback for the device to satisfy that
- request, otherwise 0 is returned
+ callbacks from being run for the device), make sure that all of the
+ pending runtime PM operations on the device are either completed or
+ canceled; returns 1 if there was a resume request pending and it was
+ necessary to execute the subsystem-level resume callback for the device
+ to satisfy that request, otherwise 0 is returned
int pm_runtime_barrier(struct device *dev);
- check if there's a resume request pending for the device and resume it
@@ -667,11 +667,11 @@ driver/base/power/generic_ops.c:
int pm_generic_runtime_suspend(struct device *dev);
- invoke the ->runtime_suspend() callback provided by the driver of this
- device and return its result, or return -EINVAL if not defined
+ device and return its result, or return 0 if not defined
int pm_generic_runtime_resume(struct device *dev);
- invoke the ->runtime_resume() callback provided by the driver of this
- device and return its result, or return -EINVAL if not defined
+ device and return its result, or return 0 if not defined
int pm_generic_suspend(struct device *dev);
- if the device has not been suspended at run time, invoke the ->suspend()
@@ -727,15 +727,12 @@ driver/base/power/generic_ops.c:
int pm_generic_restore_noirq(struct device *dev);
- invoke the ->restore_noirq() callback provided by the device's driver
-These functions can be assigned to the ->runtime_idle(), ->runtime_suspend(),
+These functions are the defaults used by the PM core, if a subsystem doesn't
+provide its own callbacks for ->runtime_idle(), ->runtime_suspend(),
->runtime_resume(), ->suspend(), ->suspend_noirq(), ->resume(),
->resume_noirq(), ->freeze(), ->freeze_noirq(), ->thaw(), ->thaw_noirq(),
-->poweroff(), ->poweroff_noirq(), ->restore(), ->restore_noirq() callback
-pointers in the subsystem-level dev_pm_ops structures.
-
-If a subsystem wishes to use all of them at the same time, it can simply assign
-the GENERIC_SUBSYS_PM_OPS macro, defined in include/linux/pm.h, to its
-dev_pm_ops structure pointer.
+->poweroff(), ->poweroff_noirq(), ->restore(), ->restore_noirq() in the
+subsystem-level dev_pm_ops structure.
Device drivers that wish to use the same function as a system suspend, freeze,
poweroff and runtime suspend callback, and similarly for system resume, thaw,
@@ -873,7 +870,7 @@ Here is a schematic pseudo-code example:
foo->is_suspended = 0;
pm_runtime_mark_last_busy(&foo->dev);
if (foo->num_pending_requests > 0)
- foo_process_requests(foo);
+ foo_process_next_request(foo);
unlock(&foo->private_lock);
return 0;
}
diff --git a/Documentation/ptp/testptp.c b/Documentation/ptp/testptp.c
index a74d0a84d329..f1ac2dae999e 100644
--- a/Documentation/ptp/testptp.c
+++ b/Documentation/ptp/testptp.c
@@ -19,6 +19,7 @@
*/
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <math.h>
#include <signal.h>
#include <stdio.h>
@@ -117,13 +118,22 @@ static void usage(char *progname)
" -f val adjust the ptp clock frequency by 'val' ppb\n"
" -g get the ptp clock time\n"
" -h prints this message\n"
+ " -i val index for event/trigger\n"
" -k val measure the time offset between system and phc clock\n"
" for 'val' times (Maximum 25)\n"
+ " -l list the current pin configuration\n"
+ " -L pin,val configure pin index 'pin' with function 'val'\n"
+ " the channel index is taken from the '-i' option\n"
+ " 'val' specifies the auxiliary function:\n"
+ " 0 - none\n"
+ " 1 - external time stamp\n"
+ " 2 - periodic output\n"
" -p val enable output with a period of 'val' nanoseconds\n"
" -P val enable or disable (val=1|0) the system clock PPS\n"
" -s set the ptp clock time from the system time\n"
" -S set the system time from the ptp clock time\n"
- " -t val shift the ptp clock time by 'val' seconds\n",
+ " -t val shift the ptp clock time by 'val' seconds\n"
+ " -T val set the ptp clock time to 'val' seconds\n",
progname);
}
@@ -133,6 +143,7 @@ int main(int argc, char *argv[])
struct ptp_extts_event event;
struct ptp_extts_request extts_request;
struct ptp_perout_request perout_request;
+ struct ptp_pin_desc desc;
struct timespec ts;
struct timex tx;
@@ -154,12 +165,16 @@ int main(int argc, char *argv[])
int capabilities = 0;
int extts = 0;
int gettime = 0;
+ int index = 0;
+ int list_pins = 0;
int oneshot = 0;
int pct_offset = 0;
int n_samples = 0;
int periodic = 0;
int perout = -1;
+ int pin_index = -1, pin_func;
int pps = -1;
+ int seconds = 0;
int settime = 0;
int64_t t1, t2, tp;
@@ -167,7 +182,7 @@ int main(int argc, char *argv[])
progname = strrchr(argv[0], '/');
progname = progname ? 1+progname : argv[0];
- while (EOF != (c = getopt(argc, argv, "a:A:cd:e:f:ghk:p:P:sSt:v"))) {
+ while (EOF != (c = getopt(argc, argv, "a:A:cd:e:f:ghi:k:lL:p:P:sSt:T:v"))) {
switch (c) {
case 'a':
oneshot = atoi(optarg);
@@ -190,10 +205,23 @@ int main(int argc, char *argv[])
case 'g':
gettime = 1;
break;
+ case 'i':
+ index = atoi(optarg);
+ break;
case 'k':
pct_offset = 1;
n_samples = atoi(optarg);
break;
+ case 'l':
+ list_pins = 1;
+ break;
+ case 'L':
+ cnt = sscanf(optarg, "%d,%d", &pin_index, &pin_func);
+ if (cnt != 2) {
+ usage(progname);
+ return -1;
+ }
+ break;
case 'p':
perout = atoi(optarg);
break;
@@ -209,6 +237,10 @@ int main(int argc, char *argv[])
case 't':
adjtime = atoi(optarg);
break;
+ case 'T':
+ settime = 3;
+ seconds = atoi(optarg);
+ break;
case 'h':
usage(progname);
return 0;
@@ -240,12 +272,14 @@ int main(int argc, char *argv[])
" %d programmable alarms\n"
" %d external time stamp channels\n"
" %d programmable periodic signals\n"
- " %d pulse per second\n",
+ " %d pulse per second\n"
+ " %d programmable pins\n",
caps.max_adj,
caps.n_alarm,
caps.n_ext_ts,
caps.n_per_out,
- caps.pps);
+ caps.pps,
+ caps.n_pins);
}
}
@@ -299,9 +333,19 @@ int main(int argc, char *argv[])
}
}
+ if (settime == 3) {
+ ts.tv_sec = seconds;
+ ts.tv_nsec = 0;
+ if (clock_settime(clkid, &ts)) {
+ perror("clock_settime");
+ } else {
+ puts("set time okay");
+ }
+ }
+
if (extts) {
memset(&extts_request, 0, sizeof(extts_request));
- extts_request.index = 0;
+ extts_request.index = index;
extts_request.flags = PTP_ENABLE_FEATURE;
if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
perror("PTP_EXTTS_REQUEST");
@@ -326,6 +370,24 @@ int main(int argc, char *argv[])
}
}
+ if (list_pins) {
+ int n_pins = 0;
+ if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) {
+ perror("PTP_CLOCK_GETCAPS");
+ } else {
+ n_pins = caps.n_pins;
+ }
+ for (i = 0; i < n_pins; i++) {
+ desc.index = i;
+ if (ioctl(fd, PTP_PIN_GETFUNC, &desc)) {
+ perror("PTP_PIN_GETFUNC");
+ break;
+ }
+ printf("name %s index %u func %u chan %u\n",
+ desc.name, desc.index, desc.func, desc.chan);
+ }
+ }
+
if (oneshot) {
install_handler(SIGALRM, handle_alarm);
/* Create a timer. */
@@ -375,7 +437,7 @@ int main(int argc, char *argv[])
return -1;
}
memset(&perout_request, 0, sizeof(perout_request));
- perout_request.index = 0;
+ perout_request.index = index;
perout_request.start.sec = ts.tv_sec + 2;
perout_request.start.nsec = 0;
perout_request.period.sec = 0;
@@ -387,6 +449,18 @@ int main(int argc, char *argv[])
}
}
+ if (pin_index >= 0) {
+ memset(&desc, 0, sizeof(desc));
+ desc.index = pin_index;
+ desc.func = pin_func;
+ desc.chan = index;
+ if (ioctl(fd, PTP_PIN_SETFUNC, &desc)) {
+ perror("PTP_PIN_SETFUNC");
+ } else {
+ puts("set pin function okay");
+ }
+ }
+
if (pps != -1) {
int enable = pps ? 1 : 0;
if (ioctl(fd, PTP_ENABLE_PPS, enable)) {
@@ -423,14 +497,14 @@ int main(int argc, char *argv[])
interval = t2 - t1;
offset = (t2 + t1) / 2 - tp;
- printf("system time: %ld.%ld\n",
+ printf("system time: %" PRId64 ".%u\n",
(pct+2*i)->sec, (pct+2*i)->nsec);
- printf("phc time: %ld.%ld\n",
+ printf("phc time: %" PRId64 ".%u\n",
(pct+2*i+1)->sec, (pct+2*i+1)->nsec);
- printf("system time: %ld.%ld\n",
+ printf("system time: %" PRId64 ".%u\n",
(pct+2*i+2)->sec, (pct+2*i+2)->nsec);
- printf("system/phc clock time offset is %ld ns\n"
- "system clock time delay is %ld ns\n",
+ printf("system/phc clock time offset is %" PRId64 " ns\n"
+ "system clock time delay is %" PRId64 " ns\n",
offset, interval);
}
diff --git a/Documentation/s390/00-INDEX b/Documentation/s390/00-INDEX
index 3a2b96302ecc..10c874ebdfe5 100644
--- a/Documentation/s390/00-INDEX
+++ b/Documentation/s390/00-INDEX
@@ -16,11 +16,13 @@ Debugging390.txt
- hints for debugging on s390 systems.
driver-model.txt
- information on s390 devices and the driver model.
+kvm.txt
+ - ioctl calls to /dev/kvm on s390.
monreader.txt
- information on accessing the z/VM monitor stream from Linux.
+qeth.txt
+ - HiperSockets Bridge Port Support.
s390dbf.txt
- information on using the s390 debug feature.
-TAPE
- - information on the driver for channel-attached tapes.
-zfcpdump
+zfcpdump.txt
- information on the s390 SCSI dump tool.
diff --git a/Documentation/scheduler/00-INDEX b/Documentation/scheduler/00-INDEX
index 46702e4f89c9..eccf7ad2e7f9 100644
--- a/Documentation/scheduler/00-INDEX
+++ b/Documentation/scheduler/00-INDEX
@@ -2,6 +2,8 @@
- this file.
sched-arch.txt
- CPU Scheduler implementation hints for architecture specific code.
+sched-bwc.txt
+ - CFS bandwidth control overview.
sched-design-CFS.txt
- goals, design and implementation of the Completely Fair Scheduler.
sched-domains.txt
diff --git a/Documentation/scsi/00-INDEX b/Documentation/scsi/00-INDEX
index 2044be565d93..c4b978a72f78 100644
--- a/Documentation/scsi/00-INDEX
+++ b/Documentation/scsi/00-INDEX
@@ -36,6 +36,8 @@ NinjaSCSI.txt
- info on WorkBiT NinjaSCSI-32/32Bi driver
aacraid.txt
- Driver supporting Adaptec RAID controllers
+advansys.txt
+ - List of Advansys Host Adapters
aha152x.txt
- info on driver for Adaptec AHA152x based adapters
aic79xx.txt
@@ -44,6 +46,12 @@ aic7xxx.txt
- info on driver for Adaptec controllers
arcmsr_spec.txt
- ARECA FIRMWARE SPEC (for IOP331 adapter)
+bfa.txt
+ - Brocade FC/FCOE adapter driver.
+bnx2fc.txt
+ - FCoE hardware offload for Broadcom network interfaces.
+cxgb3i.txt
+ - Chelsio iSCSI Linux Driver
dc395x.txt
- README file for the dc395x SCSI driver
dpti.txt
@@ -52,18 +60,24 @@ dtc3x80.txt
- info on driver for DTC 2x80 based adapters
g_NCR5380.txt
- info on driver for NCR5380 and NCR53c400 based adapters
+hpsa.txt
+ - HP Smart Array Controller SCSI driver.
hptiop.txt
- HIGHPOINT ROCKETRAID 3xxx RAID DRIVER
in2000.txt
- info on in2000 driver
libsas.txt
- Serial Attached SCSI management layer.
+link_power_management_policy.txt
+ - Link power management options.
lpfc.txt
- LPFC driver release notes
megaraid.txt
- Common Management Module, shared code handling ioctls for LSI drivers
ncr53c8xx.txt
- info on driver for NCR53c8xx based adapters
+osd.txt
+ Object-Based Storage Device, command set introduction.
osst.txt
- info on driver for OnStream SC-x0 SCSI tape
ppa.txt
@@ -74,6 +88,8 @@ scsi-changer.txt
- README for the SCSI media changer driver
scsi-generic.txt
- info on the sg driver for generic (non-disk/CD/tape) SCSI devices.
+scsi-parameters.txt
+ - List of SCSI-parameters to pass to the kernel at module load-time.
scsi.txt
- short blurb on using SCSI support as a module.
scsi_mid_low_api.txt
diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas
index 6edaa65b0818..91ba58ef02d7 100644
--- a/Documentation/scsi/ChangeLog.megaraid_sas
+++ b/Documentation/scsi/ChangeLog.megaraid_sas
@@ -1,3 +1,16 @@
+Release Date : Mon. Mar 10, 2014 17:00:00 PST 2014 -
+ (emaild-id:megaraidlinux@lsi.com)
+ Adam Radford
+ Kashyap Desai
+ Sumit Saxena
+Current Version : 06.803.01.00-rc1
+Old Version : 06.700.06.00-rc1
+ 1. Load correct raid context timeout value for multipathing & clustering.
+ 2. Fix megasas_ioc_init_fusion to use local stack variable.
+ 3. Return leaked MPT frames to MPT command pool.
+ 4. Add Dell PowerEdge VRTX SR-IOV VF device support.
+ 5. Version and Changelog update.
+-------------------------------------------------------------------------------
Release Date : Sat. Aug 31, 2013 17:00:00 PST 2013 -
(emaild-id:megaraidlinux@lsi.com)
Adam Radford
diff --git a/Documentation/security/Smack.txt b/Documentation/security/Smack.txt
index 7a2d30c132e3..5ea996f21d6c 100644
--- a/Documentation/security/Smack.txt
+++ b/Documentation/security/Smack.txt
@@ -3,7 +3,7 @@
"Good for you, you've decided to clean the elevator!"
- The Elevator, from Dark Star
-Smack is the the Simplified Mandatory Access Control Kernel.
+Smack is the Simplified Mandatory Access Control Kernel.
Smack is a kernel based implementation of mandatory access
control that includes simplicity in its primary design goals.
diff --git a/Documentation/serial/00-INDEX b/Documentation/serial/00-INDEX
index 1f1b22fbd739..f9c6b5ed03e7 100644
--- a/Documentation/serial/00-INDEX
+++ b/Documentation/serial/00-INDEX
@@ -4,10 +4,12 @@ README.cycladesZ
- info on Cyclades-Z firmware loading.
digiepca.txt
- info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
-hayes-esp.txt
- - info on using the Hayes ESP serial driver.
+driver
+ - intro to the low level serial driver.
moxa-smartio
- file with info on installing/using Moxa multiport serial driver.
+n_gsm.txt
+ - GSM 0710 tty multiplexer howto.
riscom8.txt
- notes on using the RISCom/8 multi-port serial driver.
rocket.txt
diff --git a/Documentation/sgi-visws.txt b/Documentation/sgi-visws.txt
deleted file mode 100644
index 7ff0811ca2ba..000000000000
--- a/Documentation/sgi-visws.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-
-The SGI Visual Workstations (models 320 and 540) are based around
-the Cobalt, Lithium, and Arsenic ASICs. The Cobalt ASIC is the
-main system ASIC which interfaces the 1-4 IA32 cpus, the memory
-system, and the I/O system in the Lithium ASIC. The Cobalt ASIC
-also contains the 3D gfx rendering engine which renders to main
-system memory -- part of which is used as the frame buffer which
-is DMA'ed to a video connector using the Arsenic ASIC. A PIIX4
-chip and NS87307 are used to provide legacy device support (IDE,
-serial, floppy, and parallel).
-
-The Visual Workstation chipset largely conforms to the PC architecture
-with some notable exceptions such as interrupt handling.
diff --git a/Documentation/sound/oss/vwsnd b/Documentation/sound/oss/vwsnd
deleted file mode 100644
index 4c6cbdb3c548..000000000000
--- a/Documentation/sound/oss/vwsnd
+++ /dev/null
@@ -1,293 +0,0 @@
-vwsnd - Sound driver for the Silicon Graphics 320 and 540 Visual
-Workstations' onboard audio.
-
-Copyright 1999 Silicon Graphics, Inc. All rights reserved.
-
-
-At the time of this writing, March 1999, there are two models of
-Visual Workstation, the 320 and the 540. This document only describes
-those models. Future Visual Workstation models may have different
-sound capabilities, and this driver will probably not work on those
-boxes.
-
-The Visual Workstation has an Analog Devices AD1843 "SoundComm" audio
-codec chip. The AD1843 is accessed through the Cobalt I/O ASIC, also
-known as Lithium. This driver programs both chips.
-
-==============================================================================
-QUICK CONFIGURATION
-
- # insmod soundcore
- # insmod vwsnd
-
-==============================================================================
-I/O CONNECTIONS
-
-On the Visual Workstation, only three of the AD1843 inputs are hooked
-up. The analog line in jacks are connected to the AD1843's AUX1
-input. The CD audio lines are connected to the AD1843's AUX2 input.
-The microphone jack is connected to the AD1843's MIC input. The mic
-jack is mono, but the signal is delivered to both the left and right
-MIC inputs. You can record in stereo from the mic input, but you will
-get the same signal on both channels (within the limits of A/D
-accuracy). Full scale on the Line input is +/- 2.0 V. Full scale on
-the MIC input is 20 dB less, or +/- 0.2 V.
-
-The AD1843's LOUT1 outputs are connected to the Line Out jacks. The
-AD1843's HPOUT outputs are connected to the speaker/headphone jack.
-LOUT2 is not connected. Line out's maximum level is +/- 2.0 V peak to
-peak. The speaker/headphone out's maximum is +/- 4.0 V peak to peak.
-
-The AD1843's PCM input channel and one of its output channels (DAC1)
-are connected to Lithium. The other output channel (DAC2) is not
-connected.
-
-==============================================================================
-CAPABILITIES
-
-The AD1843 has PCM input and output (Pulse Code Modulation, also known
-as wavetable). PCM input and output can be mono or stereo in any of
-four formats. The formats are 16 bit signed and 8 bit unsigned,
-u-Law, and A-Law format. Any sample rate from 4 KHz to 49 KHz is
-available, in 1 Hz increments.
-
-The AD1843 includes an analog mixer that can mix all three input
-signals (line, mic and CD) into the analog outputs. The mixer has a
-separate gain control and mute switch for each input.
-
-There are two outputs, line out and speaker/headphone out. They
-always produce the same signal, and the speaker always has 3 dB more
-gain than the line out. The speaker/headphone output can be muted,
-but this driver does not export that function.
-
-The hardware can sync audio to the video clock, but this driver does
-not have a way to specify syncing to video.
-
-==============================================================================
-PROGRAMMING
-
-This section explains the API supported by the driver. Also see the
-Open Sound Programming Guide at http://www.opensound.com/pguide/ .
-This section assumes familiarity with that document.
-
-The driver has two interfaces, an I/O interface and a mixer interface.
-There is no MIDI or sequencer capability.
-
-==============================================================================
-PROGRAMMING PCM I/O
-
-The I/O interface is usually accessed as /dev/audio or /dev/dsp.
-Using the standard Open Sound System (OSS) ioctl calls, the sample
-rate, number of channels, and sample format may be set within the
-limitations described above. The driver supports triggering. It also
-supports getting the input and output pointers with one-sample
-accuracy.
-
-The SNDCTL_DSP_GETCAP ioctl returns these capabilities.
-
- DSP_CAP_DUPLEX - driver supports full duplex.
-
- DSP_CAP_TRIGGER - driver supports triggering.
-
- DSP_CAP_REALTIME - values returned by SNDCTL_DSP_GETIPTR
- and SNDCTL_DSP_GETOPTR are accurate to a few samples.
-
-Memory mapping (mmap) is not implemented.
-
-The driver permits subdivided fragment sizes from 64 to 4096 bytes.
-The number of fragments can be anything from 3 fragments to however
-many fragments fit into 124 kilobytes. It is up to the user to
-determine how few/small fragments can be used without introducing
-glitches with a given workload. Linux is not realtime, so we can't
-promise anything. (sigh...)
-
-When this driver is switched into or out of mu-Law or A-Law mode on
-output, it may produce an audible click. This is unavoidable. To
-prevent clicking, use signed 16-bit mode instead, and convert from
-mu-Law or A-Law format in software.
-
-==============================================================================
-PROGRAMMING THE MIXER INTERFACE
-
-The mixer interface is usually accessed as /dev/mixer. It is accessed
-through ioctls. The mixer allows the application to control gain or
-mute several audio signal paths, and also allows selection of the
-recording source.
-
-Each of the constants described here can be read using the
-MIXER_READ(SOUND_MIXER_xxx) ioctl. Those that are not read-only can
-also be written using the MIXER_WRITE(SOUND_MIXER_xxx) ioctl. In most
-cases, <sys/soundcard.h> defines constants SOUND_MIXER_READ_xxx and
-SOUND_MIXER_WRITE_xxx which work just as well.
-
-SOUND_MIXER_CAPS Read-only
-
-This is a mask of optional driver capabilities that are implemented.
-This driver's only capability is SOUND_CAP_EXCL_INPUT, which means
-that only one recording source can be active at a time.
-
-SOUND_MIXER_DEVMASK Read-only
-
-This is a mask of the sound channels. This driver's channels are PCM,
-LINE, MIC, CD, and RECLEV.
-
-SOUND_MIXER_STEREODEVS Read-only
-
-This is a mask of which sound channels are capable of stereo. All
-channels are capable of stereo. (But see caveat on MIC input in I/O
-CONNECTIONS section above).
-
-SOUND_MIXER_OUTMASK Read-only
-
-This is a mask of channels that route inputs through to outputs.
-Those are LINE, MIC, and CD.
-
-SOUND_MIXER_RECMASK Read-only
-
-This is a mask of channels that can be recording sources. Those are
-PCM, LINE, MIC, CD.
-
-SOUND_MIXER_PCM Default: 0x5757 (0 dB)
-
-This is the gain control for PCM output. The left and right channel
-gain are controlled independently. This gain control has 64 levels,
-which range from -82.5 dB to +12.0 dB in 1.5 dB steps. Those 64
-levels are mapped onto 100 levels at the ioctl, see below.
-
-SOUND_MIXER_LINE Default: 0x4a4a (0 dB)
-
-This is the gain control for mixing the Line In source into the
-outputs. The left and right channel gain are controlled
-independently. This gain control has 32 levels, which range from
--34.5 dB to +12.0 dB in 1.5 dB steps. Those 32 levels are mapped onto
-100 levels at the ioctl, see below.
-
-SOUND_MIXER_MIC Default: 0x4a4a (0 dB)
-
-This is the gain control for mixing the MIC source into the outputs.
-The left and right channel gain are controlled independently. This
-gain control has 32 levels, which range from -34.5 dB to +12.0 dB in
-1.5 dB steps. Those 32 levels are mapped onto 100 levels at the
-ioctl, see below.
-
-SOUND_MIXER_CD Default: 0x4a4a (0 dB)
-
-This is the gain control for mixing the CD audio source into the
-outputs. The left and right channel gain are controlled
-independently. This gain control has 32 levels, which range from
--34.5 dB to +12.0 dB in 1.5 dB steps. Those 32 levels are mapped onto
-100 levels at the ioctl, see below.
-
-SOUND_MIXER_RECLEV Default: 0 (0 dB)
-
-This is the gain control for PCM input (RECording LEVel). The left
-and right channel gain are controlled independently. This gain
-control has 16 levels, which range from 0 dB to +22.5 dB in 1.5 dB
-steps. Those 16 levels are mapped onto 100 levels at the ioctl, see
-below.
-
-SOUND_MIXER_RECSRC Default: SOUND_MASK_LINE
-
-This is a mask of currently selected PCM input sources (RECording
-SouRCes). Because the AD1843 can only have a single recording source
-at a time, only one bit at a time can be set in this mask. The
-allowable values are SOUND_MASK_PCM, SOUND_MASK_LINE, SOUND_MASK_MIC,
-or SOUND_MASK_CD. Selecting SOUND_MASK_PCM sets up internal
-resampling which is useful for loopback testing and for hardware
-sample rate conversion. But software sample rate conversion is
-probably faster, so I don't know how useful that is.
-
-SOUND_MIXER_OUTSRC DEFAULT: SOUND_MASK_LINE|SOUND_MASK_MIC|SOUND_MASK_CD
-
-This is a mask of sources that are currently passed through to the
-outputs. Those sources whose bits are not set are muted.
-
-==============================================================================
-GAIN CONTROL
-
-There are five gain controls listed above. Each has 16, 32, or 64
-steps. Each control has 1.5 dB of gain per step. Each control is
-stereo.
-
-The OSS defines the argument to a channel gain ioctl as having two
-components, left and right, each of which ranges from 0 to 100. The
-two components are packed into the same word, with the left side gain
-in the least significant byte, and the right side gain in the second
-least significant byte. In C, we would say this.
-
- #include <assert.h>
-
- ...
-
- assert(leftgain >= 0 && leftgain <= 100);
- assert(rightgain >= 0 && rightgain <= 100);
- arg = leftgain | rightgain << 8;
-
-So each OSS gain control has 101 steps. But the hardware has 16, 32,
-or 64 steps. The hardware steps are spread across the 101 OSS steps
-nearly evenly. The conversion formulas are like this, given N equals
-16, 32, or 64.
-
- int round = N/2 - 1;
- OSS_gain_steps = (hw_gain_steps * 100 + round) / (N - 1);
- hw_gain_steps = (OSS_gain_steps * (N - 1) + round) / 100;
-
-Here is a snippet of C code that will return the left and right gain
-of any channel in dB. Pass it one of the predefined gain_desc_t
-structures to access any of the five channels' gains.
-
- typedef struct gain_desc {
- float min_gain;
- float gain_step;
- int nbits;
- int chan;
- } gain_desc_t;
-
- const gain_desc_t gain_pcm = { -82.5, 1.5, 6, SOUND_MIXER_PCM };
- const gain_desc_t gain_line = { -34.5, 1.5, 5, SOUND_MIXER_LINE };
- const gain_desc_t gain_mic = { -34.5, 1.5, 5, SOUND_MIXER_MIC };
- const gain_desc_t gain_cd = { -34.5, 1.5, 5, SOUND_MIXER_CD };
- const gain_desc_t gain_reclev = { 0.0, 1.5, 4, SOUND_MIXER_RECLEV };
-
- int get_gain_dB(int fd, const gain_desc_t *gp,
- float *left, float *right)
- {
- int word;
- int lg, rg;
- int mask = (1 << gp->nbits) - 1;
-
- if (ioctl(fd, MIXER_READ(gp->chan), &word) != 0)
- return -1; /* fail */
- lg = word & 0xFF;
- rg = word >> 8 & 0xFF;
- lg = (lg * mask + mask / 2) / 100;
- rg = (rg * mask + mask / 2) / 100;
- *left = gp->min_gain + gp->gain_step * lg;
- *right = gp->min_gain + gp->gain_step * rg;
- return 0;
- }
-
-And here is the corresponding routine to set a channel's gain in dB.
-
- int set_gain_dB(int fd, const gain_desc_t *gp, float left, float right)
- {
- float max_gain =
- gp->min_gain + (1 << gp->nbits) * gp->gain_step;
- float round = gp->gain_step / 2;
- int mask = (1 << gp->nbits) - 1;
- int word;
- int lg, rg;
-
- if (left < gp->min_gain || right < gp->min_gain)
- return EINVAL;
- lg = (left - gp->min_gain + round) / gp->gain_step;
- rg = (right - gp->min_gain + round) / gp->gain_step;
- if (lg >= (1 << gp->nbits) || rg >= (1 << gp->nbits))
- return EINVAL;
- lg = (100 * lg + mask / 2) / mask;
- rg = (100 * rg + mask / 2) / mask;
- word = lg | rg << 8;
-
- return ioctl(fd, MIXER_WRITE(gp->chan), &word);
- }
-
diff --git a/Documentation/spi/00-INDEX b/Documentation/spi/00-INDEX
new file mode 100644
index 000000000000..a128fa835512
--- /dev/null
+++ b/Documentation/spi/00-INDEX
@@ -0,0 +1,22 @@
+00-INDEX
+ - this file.
+Makefile
+ - Makefile for the example sourcefiles.
+butterfly
+ - AVR Butterfly SPI driver overview and pin configuration.
+ep93xx_spi
+ - Basic EP93xx SPI driver configuration.
+pxa2xx
+ - PXA2xx SPI master controller build by spi_message fifo wq
+spidev
+ - Intro to the userspace API for spi devices
+spidev_fdx.c
+ - spidev example file
+spi-lm70llp
+ - Connecting an LM70-LLP sensor to the kernel via the SPI subsys.
+spi-sc18is602
+ - NXP SC18IS602/603 I2C-bus to SPI bridge
+spi-summary
+ - (Linux) SPI overview. If unsure about SPI or SPI in Linux, start here.
+spidev_test.c
+ - SPI testing utility.
diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary
index f72e0d1e0da8..7982bcc4d151 100644
--- a/Documentation/spi/spi-summary
+++ b/Documentation/spi/spi-summary
@@ -543,7 +543,22 @@ SPI MASTER METHODS
queuing transfers that arrive in the meantime. When the driver is
finished with this message, it must call
spi_finalize_current_message() so the subsystem can issue the next
- transfer. This may sleep.
+ message. This may sleep.
+
+ master->transfer_one(struct spi_master *master, struct spi_device *spi,
+ struct spi_transfer *transfer)
+ The subsystem calls the driver to transfer a single transfer while
+ queuing transfers that arrive in the meantime. When the driver is
+ finished with this transfer, it must call
+ spi_finalize_current_transfer() so the subsystem can issue the next
+ transfer. This may sleep. Note: transfer_one and transfer_one_message
+ are mutually exclusive; when both are set, the generic subsystem does
+ not call your transfer_one callback.
+
+ Return values:
+ negative errno: error
+ 0: transfer is finished
+ 1: transfer is still in progress
DEPRECATED METHODS
diff --git a/Documentation/spi/spidev b/Documentation/spi/spidev
index ed2da5e5b28a..3d14035b1766 100644
--- a/Documentation/spi/spidev
+++ b/Documentation/spi/spidev
@@ -85,6 +85,12 @@ settings for data transfer parameters:
SPI_MODE_0..SPI_MODE_3; or if you prefer you can combine SPI_CPOL
(clock polarity, idle high iff this is set) or SPI_CPHA (clock phase,
sample on trailing edge iff this is set) flags.
+ Note that this request is limited to SPI mode flags that fit in a
+ single byte.
+
+ SPI_IOC_RD_MODE32, SPI_IOC_WR_MODE32 ... pass a pointer to a uin32_t
+ which will return (RD) or assign (WR) the full SPI transfer mode,
+ not limited to the bits that fit in one byte.
SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST ... pass a pointer to a byte
which will return (RD) or assign (WR) the bit justification used to
diff --git a/Documentation/spi/spidev_fdx.c b/Documentation/spi/spidev_fdx.c
index 36ec0774ca0b..0ea3e51292fc 100644
--- a/Documentation/spi/spidev_fdx.c
+++ b/Documentation/spi/spidev_fdx.c
@@ -78,10 +78,10 @@ static void do_msg(int fd, int len)
static void dumpstat(const char *name, int fd)
{
- __u8 mode, lsb, bits;
- __u32 speed;
+ __u8 lsb, bits;
+ __u32 mode, speed;
- if (ioctl(fd, SPI_IOC_RD_MODE, &mode) < 0) {
+ if (ioctl(fd, SPI_IOC_RD_MODE32, &mode) < 0) {
perror("SPI rd_mode");
return;
}
@@ -98,7 +98,7 @@ static void dumpstat(const char *name, int fd)
return;
}
- printf("%s: spi mode %d, %d bits %sper word, %d Hz max\n",
+ printf("%s: spi mode 0x%x, %d bits %sper word, %d Hz max\n",
name, mode, bits, lsb ? "(lsb first) " : "", speed);
}
diff --git a/Documentation/spi/spidev_test.c b/Documentation/spi/spidev_test.c
index 16feda901469..3a2f9d59edab 100644
--- a/Documentation/spi/spidev_test.c
+++ b/Documentation/spi/spidev_test.c
@@ -30,7 +30,7 @@ static void pabort(const char *s)
}
static const char *device = "/dev/spidev1.1";
-static uint8_t mode;
+static uint32_t mode;
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;
@@ -57,6 +57,21 @@ static void transfer(int fd)
.bits_per_word = bits,
};
+ if (mode & SPI_TX_QUAD)
+ tr.tx_nbits = 4;
+ else if (mode & SPI_TX_DUAL)
+ tr.tx_nbits = 2;
+ if (mode & SPI_RX_QUAD)
+ tr.rx_nbits = 4;
+ else if (mode & SPI_RX_DUAL)
+ tr.rx_nbits = 2;
+ if (!(mode & SPI_LOOP)) {
+ if (mode & (SPI_TX_QUAD | SPI_TX_DUAL))
+ tr.rx_buf = 0;
+ else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL))
+ tr.tx_buf = 0;
+ }
+
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
pabort("can't send spi message");
@@ -81,7 +96,11 @@ static void print_usage(const char *prog)
" -O --cpol clock polarity\n"
" -L --lsb least significant bit first\n"
" -C --cs-high chip select active high\n"
- " -3 --3wire SI/SO signals shared\n");
+ " -3 --3wire SI/SO signals shared\n"
+ " -N --no-cs no chip select\n"
+ " -R --ready slave pulls low to pause\n"
+ " -2 --dual dual transfer\n"
+ " -4 --quad quad transfer\n");
exit(1);
}
@@ -101,11 +120,13 @@ static void parse_opts(int argc, char *argv[])
{ "3wire", 0, 0, '3' },
{ "no-cs", 0, 0, 'N' },
{ "ready", 0, 0, 'R' },
+ { "dual", 0, 0, '2' },
+ { "quad", 0, 0, '4' },
{ NULL, 0, 0, 0 },
};
int c;
- c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL);
+ c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24", lopts, NULL);
if (c == -1)
break;
@@ -147,11 +168,23 @@ static void parse_opts(int argc, char *argv[])
case 'R':
mode |= SPI_READY;
break;
+ case '2':
+ mode |= SPI_TX_DUAL;
+ break;
+ case '4':
+ mode |= SPI_TX_QUAD;
+ break;
default:
print_usage(argv[0]);
break;
}
}
+ if (mode & SPI_LOOP) {
+ if (mode & SPI_TX_DUAL)
+ mode |= SPI_RX_DUAL;
+ if (mode & SPI_TX_QUAD)
+ mode |= SPI_RX_QUAD;
+ }
}
int main(int argc, char *argv[])
@@ -168,11 +201,11 @@ int main(int argc, char *argv[])
/*
* spi mode
*/
- ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
+ ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
if (ret == -1)
pabort("can't set spi mode");
- ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
+ ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);
if (ret == -1)
pabort("can't get spi mode");
@@ -198,7 +231,7 @@ int main(int argc, char *argv[])
if (ret == -1)
pabort("can't get max speed hz");
- printf("spi mode: %d\n", mode);
+ printf("spi mode: 0x%x\n", mode);
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index e55124e7c40c..ec8be46bf48d 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -320,10 +320,11 @@ This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
==============================================================
-hung_task_warning:
+hung_task_warnings:
The maximum number of warnings to report. During a check interval
-When this value is reached, no more the warnings will be reported.
+if a hung task is detected, this value is decreased by 1.
+When this value reaches 0, no more warnings will be reported.
This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
-1: report an infinite number of warnings.
@@ -441,8 +442,7 @@ feature should be disabled. Otherwise, if the system overhead from the
feature is too high then the rate the kernel samples for NUMA hinting
faults may be controlled by the numa_balancing_scan_period_min_ms,
numa_balancing_scan_delay_ms, numa_balancing_scan_period_max_ms,
-numa_balancing_scan_size_mb, numa_balancing_settle_count sysctls and
-numa_balancing_migrate_deferred.
+numa_balancing_scan_size_mb, and numa_balancing_settle_count sysctls.
==============================================================
@@ -483,13 +483,6 @@ rate for each task.
numa_balancing_scan_size_mb is how many megabytes worth of pages are
scanned for a given scan.
-numa_balancing_migrate_deferred is how many page migrations get skipped
-unconditionally, after a page migration is skipped because a page is shared
-with other tasks. This reduces page migration overhead, and determines
-how much stronger the "move task near its memory" policy scheduler becomes,
-versus the "move memory near its task" memory management policy, for workloads
-with shared memory.
-
==============================================================
osrelease, ostype & version:
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index d614a9b6a280..dd9d0e33b443 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -175,18 +175,39 @@ Setting this to zero disables periodic writeback altogether.
drop_caches
-Writing to this will cause the kernel to drop clean caches, dentries and
-inodes from memory, causing that memory to become free.
+Writing to this will cause the kernel to drop clean caches, as well as
+reclaimable slab objects like dentries and inodes. Once dropped, their
+memory becomes free.
To free pagecache:
echo 1 > /proc/sys/vm/drop_caches
-To free dentries and inodes:
+To free reclaimable slab objects (includes dentries and inodes):
echo 2 > /proc/sys/vm/drop_caches
-To free pagecache, dentries and inodes:
+To free slab objects and pagecache:
echo 3 > /proc/sys/vm/drop_caches
-As this is a non-destructive operation and dirty objects are not freeable, the
-user should run `sync' first.
+This is a non-destructive operation and will not free any dirty objects.
+To increase the number of objects freed by this operation, the user may run
+`sync' prior to writing to /proc/sys/vm/drop_caches. This will minimize the
+number of dirty objects on the system and create more candidates to be
+dropped.
+
+This file is not a means to control the growth of the various kernel caches
+(inodes, dentries, pagecache, etc...) These objects are automatically
+reclaimed by the kernel when memory is needed elsewhere on the system.
+
+Use of this file can cause performance problems. Since it discards cached
+objects, it may cost a significant amount of I/O and CPU to recreate the
+dropped objects, especially if they were under heavy use. Because of this,
+use outside of a testing or debugging environment is not recommended.
+
+You may see informational messages in your kernel log when this file is
+used:
+
+ cat (1234): drop_caches: 3
+
+These are informational only. They do not mean that anything is wrong
+with your system. To disable them, echo 4 (bit 3) into drop_caches.
==============================================================
diff --git a/Documentation/timers/00-INDEX b/Documentation/timers/00-INDEX
index ef2ccbf77fa2..6d042dc1cce0 100644
--- a/Documentation/timers/00-INDEX
+++ b/Documentation/timers/00-INDEX
@@ -8,6 +8,8 @@ hpet_example.c
- sample hpet timer test program
hrtimers.txt
- subsystem for high-resolution kernel timers
+Makefile
+ - Build and link hpet_example
NO_HZ.txt
- Summary of the different methods for the scheduler clock-interrupts management.
timers-howto.txt
diff --git a/Documentation/trace/events-power.txt b/Documentation/trace/events-power.txt
index 3bd33b8dc7c4..21d514ced212 100644
--- a/Documentation/trace/events-power.txt
+++ b/Documentation/trace/events-power.txt
@@ -92,5 +92,5 @@ dev_pm_qos_remove_request "device=%s type=%s new_value=%d"
The first parameter gives the device name which tries to add/update/remove
QoS requests.
-The second parameter gives the request type (e.g. "DEV_PM_QOS_LATENCY").
+The second parameter gives the request type (e.g. "DEV_PM_QOS_RESUME_LATENCY").
The third parameter is value to be added/updated/removed.
diff --git a/Documentation/trace/ftrace-design.txt b/Documentation/trace/ftrace-design.txt
index 79fcafc7fd64..3f669b9e8852 100644
--- a/Documentation/trace/ftrace-design.txt
+++ b/Documentation/trace/ftrace-design.txt
@@ -358,11 +358,8 @@ Every arch has an init callback function. If you need to do something early on
to initialize some state, this is the time to do that. Otherwise, this simple
function below should be sufficient for most people:
-int __init ftrace_dyn_arch_init(void *data)
+int __init ftrace_dyn_arch_init(void)
{
- /* return value is done indirectly via data */
- *(unsigned long *)data = 0;
-
return 0;
}
diff --git a/Documentation/trace/ring-buffer-design.txt b/Documentation/trace/ring-buffer-design.txt
index 7d350b496585..ff747b6fa39b 100644
--- a/Documentation/trace/ring-buffer-design.txt
+++ b/Documentation/trace/ring-buffer-design.txt
@@ -683,7 +683,7 @@ against nested writers.
cmpxchg(tail_page, temp_page, next_page)
The above will update the tail page if it is still pointing to the expected
-page. If this fails, a nested write pushed it forward, the the current write
+page. If this fails, a nested write pushed it forward, the current write
does not need to push it.
diff --git a/Documentation/usb/WUSB-Design-overview.txt b/Documentation/usb/WUSB-Design-overview.txt
index 4c5e37939344..1cd07c017cf6 100644
--- a/Documentation/usb/WUSB-Design-overview.txt
+++ b/Documentation/usb/WUSB-Design-overview.txt
@@ -25,7 +25,7 @@ updated content.
* Design-overview.txt-1.8
This code implements a Ultra Wide Band stack for Linux, as well as
-drivers for the the USB based UWB radio controllers defined in the
+drivers for the USB based UWB radio controllers defined in the
Wireless USB 1.0 specification (including Wireless USB host controller
and an Intel WiNET controller).
diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv
index f14475011fea..2f6e93597ce0 100644
--- a/Documentation/video4linux/CARDLIST.bttv
+++ b/Documentation/video4linux/CARDLIST.bttv
@@ -163,3 +163,4 @@
162 -> Adlink MPG24
163 -> Bt848 Capture 14MHz
164 -> CyberVision CV06 (SV)
+165 -> Kworld V-Stream Xpert TV PVR878
diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885
index 9f056d512e35..fc009d0ee7d6 100644
--- a/Documentation/video4linux/CARDLIST.cx23885
+++ b/Documentation/video4linux/CARDLIST.cx23885
@@ -31,10 +31,13 @@
30 -> NetUP Dual DVB-T/C-CI RF [1b55:e2e4]
31 -> Leadtek Winfast PxDVR3200 H XC4000 [107d:6f39]
32 -> MPX-885
- 33 -> Mygica X8507 [14f1:8502]
+ 33 -> Mygica X8502/X8507 ISDB-T [14f1:8502]
34 -> TerraTec Cinergy T PCIe Dual [153b:117e]
35 -> TeVii S471 [d471:9022]
36 -> Hauppauge WinTV-HVR1255 [0070:2259]
37 -> Prof Revolution DVB-S2 8000 [8000:3034]
38 -> Hauppauge WinTV-HVR4400 [0070:c108,0070:c138,0070:c12a,0070:c1f8]
39 -> AVerTV Hybrid Express Slim HC81R [1461:d939]
+ 40 -> TurboSight TBS 6981 [6981:8888]
+ 41 -> TurboSight TBS 6980 [6980:8888]
+ 42 -> Leadtek Winfast PxPVR2200 [107d:6f21]
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
index e81864405102..e085b1243b45 100644
--- a/Documentation/video4linux/CARDLIST.em28xx
+++ b/Documentation/video4linux/CARDLIST.em28xx
@@ -57,6 +57,7 @@
56 -> Pinnacle Hybrid Pro (330e) (em2882) [2304:0226]
57 -> Kworld PlusTV HD Hybrid 330 (em2883) [eb1a:a316]
58 -> Compro VideoMate ForYou/Stereo (em2820/em2840) [185b:2041]
+ 59 -> Pinnacle PCTV HD Mini (em2874) [2304:023f]
60 -> Hauppauge WinTV HVR 850 (em2883) [2040:651f]
61 -> Pixelview PlayTV Box 4 USB 2.0 (em2820/em2840)
62 -> Gadmei TVR200 (em2820/em2840)
@@ -86,3 +87,8 @@
86 -> PCTV QuatroStick nano (520e) (em2884) [2013:0251]
87 -> Terratec Cinergy HTC USB XS (em2884) [0ccd:008e,0ccd:00ac]
88 -> C3 Tech Digital Duo HDTV/SDTV USB (em2884) [1b80:e755]
+ 89 -> Delock 61959 (em2874) [1b80:e1cc]
+ 90 -> KWorld USB ATSC TV Stick UB435-Q V2 (em2874) [1b80:e346]
+ 91 -> SpeedLink Vicious And Devine Laplace webcam (em2765) [1ae7:9003,1ae7:9004]
+ 92 -> PCTV DVB-S2 Stick (461e) (em28178)
+ 93 -> KWorld USB ATSC TV Stick UB435-Q V3 (em2874) [1b80:e34c]
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt
index 1e6b6531bbcc..d2ba80bb7af5 100644
--- a/Documentation/video4linux/gspca.txt
+++ b/Documentation/video4linux/gspca.txt
@@ -55,6 +55,7 @@ zc3xx 0458:700f Genius VideoCam Web V2
sonixj 0458:7025 Genius Eye 311Q
sn9c20x 0458:7029 Genius Look 320s
sonixj 0458:702e Genius Slim 310 NB
+sn9c20x 0458:7045 Genius Look 1320 V2
sn9c20x 0458:704a Genius Slim 1320
sn9c20x 0458:704c Genius i-Look 1321
sn9c20x 045e:00f4 LifeCam VX-6000 (SN9C20x + OV9650)
diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
index 6c4866b49eb5..667a43361706 100644
--- a/Documentation/video4linux/v4l2-framework.txt
+++ b/Documentation/video4linux/v4l2-framework.txt
@@ -34,6 +34,10 @@ So this framework sets up the basic building blocks that all drivers
need and this same framework should make it much easier to refactor
common code into utility functions shared by all drivers.
+A good example to look at as a reference is the v4l2-pci-skeleton.c
+source that is available in this directory. It is a skeleton driver for
+a PCI capture card, and demonstrates how to use the V4L2 driver
+framework. It can be used as a template for real PCI video capture driver.
Structure of a driver
---------------------
@@ -768,6 +772,7 @@ types exist:
VFL_TYPE_GRABBER: videoX for video input/output devices
VFL_TYPE_VBI: vbiX for vertical blank data (i.e. closed captions, teletext)
VFL_TYPE_RADIO: radioX for radio tuners
+VFL_TYPE_SDR: swradioX for Software Defined Radio tuners
The last argument gives you a certain amount of control over the device
device node number used (i.e. the X in videoX). Normally you will pass -1
diff --git a/Documentation/video4linux/v4l2-pci-skeleton.c b/Documentation/video4linux/v4l2-pci-skeleton.c
new file mode 100644
index 000000000000..3a1c0d2dafce
--- /dev/null
+++ b/Documentation/video4linux/v4l2-pci-skeleton.c
@@ -0,0 +1,913 @@
+/*
+ * This is a V4L2 PCI Skeleton Driver. It gives an initial skeleton source
+ * for use with other PCI drivers.
+ *
+ * This skeleton PCI driver assumes that the card has an S-Video connector as
+ * input 0 and an HDMI connector as input 1.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/mutex.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-dma-contig.h>
+
+MODULE_DESCRIPTION("V4L2 PCI Skeleton Driver");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(pci, skeleton_pci_tbl);
+
+/**
+ * struct skeleton - All internal data for one instance of device
+ * @pdev: PCI device
+ * @v4l2_dev: top-level v4l2 device struct
+ * @vdev: video node structure
+ * @ctrl_handler: control handler structure
+ * @lock: ioctl serialization mutex
+ * @std: current SDTV standard
+ * @timings: current HDTV timings
+ * @format: current pix format
+ * @input: current video input (0 = SDTV, 1 = HDTV)
+ * @queue: vb2 video capture queue
+ * @alloc_ctx: vb2 contiguous DMA context
+ * @qlock: spinlock controlling access to buf_list and sequence
+ * @buf_list: list of buffers queued for DMA
+ * @sequence: frame sequence counter
+ */
+struct skeleton {
+ struct pci_dev *pdev;
+ struct v4l2_device v4l2_dev;
+ struct video_device vdev;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct mutex lock;
+ v4l2_std_id std;
+ struct v4l2_dv_timings timings;
+ struct v4l2_pix_format format;
+ unsigned input;
+
+ struct vb2_queue queue;
+ struct vb2_alloc_ctx *alloc_ctx;
+
+ spinlock_t qlock;
+ struct list_head buf_list;
+ unsigned int sequence;
+};
+
+struct skel_buffer {
+ struct vb2_buffer vb;
+ struct list_head list;
+};
+
+static inline struct skel_buffer *to_skel_buffer(struct vb2_buffer *vb2)
+{
+ return container_of(vb2, struct skel_buffer, vb);
+}
+
+static const struct pci_device_id skeleton_pci_tbl[] = {
+ /* { PCI_DEVICE(PCI_VENDOR_ID_, PCI_DEVICE_ID_) }, */
+ { 0, }
+};
+
+/*
+ * HDTV: this structure has the capabilities of the HDTV receiver.
+ * It is used to constrain the huge list of possible formats based
+ * upon the hardware capabilities.
+ */
+static const struct v4l2_dv_timings_cap skel_timings_cap = {
+ .type = V4L2_DV_BT_656_1120,
+ /* keep this initialization for compatibility with GCC < 4.4.6 */
+ .reserved = { 0 },
+ V4L2_INIT_BT_TIMINGS(
+ 720, 1920, /* min/max width */
+ 480, 1080, /* min/max height */
+ 27000000, 74250000, /* min/max pixelclock*/
+ V4L2_DV_BT_STD_CEA861, /* Supported standards */
+ /* capabilities */
+ V4L2_DV_BT_CAP_INTERLACED | V4L2_DV_BT_CAP_PROGRESSIVE
+ )
+};
+
+/*
+ * Supported SDTV standards. This does the same job as skel_timings_cap, but
+ * for standard TV formats.
+ */
+#define SKEL_TVNORMS V4L2_STD_ALL
+
+/*
+ * Interrupt handler: typically interrupts happen after a new frame has been
+ * captured. It is the job of the handler to remove the new frame from the
+ * internal list and give it back to the vb2 framework, updating the sequence
+ * counter and timestamp at the same time.
+ */
+static irqreturn_t skeleton_irq(int irq, void *dev_id)
+{
+#ifdef TODO
+ struct skeleton *skel = dev_id;
+
+ /* handle interrupt */
+
+ /* Once a new frame has been captured, mark it as done like this: */
+ if (captured_new_frame) {
+ ...
+ spin_lock(&skel->qlock);
+ list_del(&new_buf->list);
+ spin_unlock(&skel->qlock);
+ new_buf->vb.v4l2_buf.sequence = skel->sequence++;
+ v4l2_get_timestamp(&new_buf->vb.v4l2_buf.timestamp);
+ vb2_buffer_done(&new_buf->vb, VB2_BUF_STATE_DONE);
+ }
+#endif
+ return IRQ_HANDLED;
+}
+
+/*
+ * Setup the constraints of the queue: besides setting the number of planes
+ * per buffer and the size and allocation context of each plane, it also
+ * checks if sufficient buffers have been allocated. Usually 3 is a good
+ * minimum number: many DMA engines need a minimum of 2 buffers in the
+ * queue and you need to have another available for userspace processing.
+ */
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct skeleton *skel = vb2_get_drv_priv(vq);
+
+ if (vq->num_buffers + *nbuffers < 3)
+ *nbuffers = 3 - vq->num_buffers;
+
+ if (fmt && fmt->fmt.pix.sizeimage < skel->format.sizeimage)
+ return -EINVAL;
+ *nplanes = 1;
+ sizes[0] = fmt ? fmt->fmt.pix.sizeimage : skel->format.sizeimage;
+ alloc_ctxs[0] = skel->alloc_ctx;
+ return 0;
+}
+
+/*
+ * Prepare the buffer for queueing to the DMA engine: check and set the
+ * payload size and fill in the field. Note: if the format's field is
+ * V4L2_FIELD_ALTERNATE, then vb->v4l2_buf.field should be set in the
+ * interrupt handler since that's usually where you know if the TOP or
+ * BOTTOM field has been captured.
+ */
+static int buffer_prepare(struct vb2_buffer *vb)
+{
+ struct skeleton *skel = vb2_get_drv_priv(vb->vb2_queue);
+ unsigned long size = skel->format.sizeimage;
+
+ if (vb2_plane_size(vb, 0) < size) {
+ dev_err(&skel->pdev->dev, "buffer too small (%lu < %lu)\n",
+ vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(vb, 0, size);
+ vb->v4l2_buf.field = skel->format.field;
+ return 0;
+}
+
+/*
+ * Queue this buffer to the DMA engine.
+ */
+static void buffer_queue(struct vb2_buffer *vb)
+{
+ struct skeleton *skel = vb2_get_drv_priv(vb->vb2_queue);
+ struct skel_buffer *buf = to_skel_buffer(vb);
+ unsigned long flags;
+
+ spin_lock_irqsave(&skel->qlock, flags);
+ list_add_tail(&buf->list, &skel->buf_list);
+
+ /* TODO: Update any DMA pointers if necessary */
+
+ spin_unlock_irqrestore(&skel->qlock, flags);
+}
+
+static void return_all_buffers(struct skeleton *skel,
+ enum vb2_buffer_state state)
+{
+ struct skel_buffer *buf, *node;
+ unsigned long flags;
+
+ spin_lock_irqsave(&skel->qlock, flags);
+ list_for_each_entry_safe(buf, node, &skel->buf_list, list) {
+ vb2_buffer_done(&buf->vb, state);
+ list_del(&buf->list);
+ }
+ spin_unlock_irqrestore(&skel->qlock, flags);
+}
+
+/*
+ * Start streaming. First check if the minimum number of buffers have been
+ * queued. If not, then return -ENOBUFS and the vb2 framework will call
+ * this function again the next time a buffer has been queued until enough
+ * buffers are available to actually start the DMA engine.
+ */
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct skeleton *skel = vb2_get_drv_priv(vq);
+ int ret = 0;
+
+ skel->sequence = 0;
+
+ /* TODO: start DMA */
+
+ if (ret) {
+ /*
+ * In case of an error, return all active buffers to the
+ * QUEUED state
+ */
+ return_all_buffers(skel, VB2_BUF_STATE_QUEUED);
+ }
+ return ret;
+}
+
+/*
+ * Stop the DMA engine. Any remaining buffers in the DMA queue are dequeued
+ * and passed on to the vb2 framework marked as STATE_ERROR.
+ */
+static int stop_streaming(struct vb2_queue *vq)
+{
+ struct skeleton *skel = vb2_get_drv_priv(vq);
+
+ /* TODO: stop DMA */
+
+ /* Release all active buffers */
+ return_all_buffers(skel, VB2_BUF_STATE_ERROR);
+ return 0;
+}
+
+/*
+ * The vb2 queue ops. Note that since q->lock is set we can use the standard
+ * vb2_ops_wait_prepare/finish helper functions. If q->lock would be NULL,
+ * then this driver would have to provide these ops.
+ */
+static struct vb2_ops skel_qops = {
+ .queue_setup = queue_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+/*
+ * Required ioctl querycap. Note that the version field is prefilled with
+ * the version of the kernel.
+ */
+static int skeleton_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct skeleton *skel = video_drvdata(file);
+
+ strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+ strlcpy(cap->card, "V4L2 PCI Skeleton", sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
+ pci_name(skel->pdev));
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+}
+
+/*
+ * Helper function to check and correct struct v4l2_pix_format. It's used
+ * not only in VIDIOC_TRY/S_FMT, but also elsewhere if changes to the SDTV
+ * standard, HDTV timings or the video input would require updating the
+ * current format.
+ */
+static void skeleton_fill_pix_format(struct skeleton *skel,
+ struct v4l2_pix_format *pix)
+{
+ pix->pixelformat = V4L2_PIX_FMT_YUYV;
+ if (skel->input == 0) {
+ /* S-Video input */
+ pix->width = 720;
+ pix->height = (skel->std & V4L2_STD_525_60) ? 480 : 576;
+ pix->field = V4L2_FIELD_INTERLACED;
+ pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ } else {
+ /* HDMI input */
+ pix->width = skel->timings.bt.width;
+ pix->height = skel->timings.bt.height;
+ if (skel->timings.bt.interlaced)
+ pix->field = V4L2_FIELD_INTERLACED;
+ else
+ pix->field = V4L2_FIELD_NONE;
+ pix->colorspace = V4L2_COLORSPACE_REC709;
+ }
+
+ /*
+ * The YUYV format is four bytes for every two pixels, so bytesperline
+ * is width * 2.
+ */
+ pix->bytesperline = pix->width * 2;
+ pix->sizeimage = pix->bytesperline * pix->height;
+ pix->priv = 0;
+}
+
+static int skeleton_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct skeleton *skel = video_drvdata(file);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ /*
+ * Due to historical reasons providing try_fmt with an unsupported
+ * pixelformat will return -EINVAL for video receivers. Webcam drivers,
+ * however, will silently correct the pixelformat. Some video capture
+ * applications rely on this behavior...
+ */
+ if (pix->pixelformat != V4L2_PIX_FMT_YUYV)
+ return -EINVAL;
+ skeleton_fill_pix_format(skel, pix);
+ return 0;
+}
+
+static int skeleton_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct skeleton *skel = video_drvdata(file);
+ int ret;
+
+ ret = skeleton_try_fmt_vid_cap(file, priv, f);
+ if (ret)
+ return ret;
+
+ /*
+ * It is not allowed to change the format while buffers for use with
+ * streaming have already been allocated.
+ */
+ if (vb2_is_busy(&skel->queue))
+ return -EBUSY;
+
+ /* TODO: change format */
+ skel->format = f->fmt.pix;
+ return 0;
+}
+
+static int skeleton_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct skeleton *skel = video_drvdata(file);
+
+ f->fmt.pix = skel->format;
+ return 0;
+}
+
+static int skeleton_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index != 0)
+ return -EINVAL;
+
+ strlcpy(f->description, "4:2:2, packed, YUYV", sizeof(f->description));
+ f->pixelformat = V4L2_PIX_FMT_YUYV;
+ f->flags = 0;
+ return 0;
+}
+
+static int skeleton_s_std(struct file *file, void *priv, v4l2_std_id std)
+{
+ struct skeleton *skel = video_drvdata(file);
+
+ /* S_STD is not supported on the HDMI input */
+ if (skel->input)
+ return -ENODATA;
+
+ /*
+ * No change, so just return. Some applications call S_STD again after
+ * the buffers for streaming have been set up, so we have to allow for
+ * this behavior.
+ */
+ if (std == skel->std)
+ return 0;
+
+ /*
+ * Changing the standard implies a format change, which is not allowed
+ * while buffers for use with streaming have already been allocated.
+ */
+ if (vb2_is_busy(&skel->queue))
+ return -EBUSY;
+
+ /* TODO: handle changing std */
+
+ skel->std = std;
+
+ /* Update the internal format */
+ skeleton_fill_pix_format(skel, &skel->format);
+ return 0;
+}
+
+static int skeleton_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct skeleton *skel = video_drvdata(file);
+
+ /* G_STD is not supported on the HDMI input */
+ if (skel->input)
+ return -ENODATA;
+
+ *std = skel->std;
+ return 0;
+}
+
+/*
+ * Query the current standard as seen by the hardware. This function shall
+ * never actually change the standard, it just detects and reports.
+ * The framework will initially set *std to tvnorms (i.e. the set of
+ * supported standards by this input), and this function should just AND
+ * this value. If there is no signal, then *std should be set to 0.
+ */
+static int skeleton_querystd(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct skeleton *skel = video_drvdata(file);
+
+ /* QUERY_STD is not supported on the HDMI input */
+ if (skel->input)
+ return -ENODATA;
+
+#ifdef TODO
+ /*
+ * Query currently seen standard. Initial value of *std is
+ * V4L2_STD_ALL. This function should look something like this:
+ */
+ get_signal_info();
+ if (no_signal) {
+ *std = 0;
+ return 0;
+ }
+ /* Use signal information to reduce the number of possible standards */
+ if (signal_has_525_lines)
+ *std &= V4L2_STD_525_60;
+ else
+ *std &= V4L2_STD_625_50;
+#endif
+ return 0;
+}
+
+static int skeleton_s_dv_timings(struct file *file, void *_fh,
+ struct v4l2_dv_timings *timings)
+{
+ struct skeleton *skel = video_drvdata(file);
+
+ /* S_DV_TIMINGS is not supported on the S-Video input */
+ if (skel->input == 0)
+ return -ENODATA;
+
+ /* Quick sanity check */
+ if (!v4l2_valid_dv_timings(timings, &skel_timings_cap, NULL, NULL))
+ return -EINVAL;
+
+ /* Check if the timings are part of the CEA-861 timings. */
+ if (!v4l2_find_dv_timings_cap(timings, &skel_timings_cap,
+ 0, NULL, NULL))
+ return -EINVAL;
+
+ /* Return 0 if the new timings are the same as the current timings. */
+ if (v4l2_match_dv_timings(timings, &skel->timings, 0))
+ return 0;
+
+ /*
+ * Changing the timings implies a format change, which is not allowed
+ * while buffers for use with streaming have already been allocated.
+ */
+ if (vb2_is_busy(&skel->queue))
+ return -EBUSY;
+
+ /* TODO: Configure new timings */
+
+ /* Save timings */
+ skel->timings = *timings;
+
+ /* Update the internal format */
+ skeleton_fill_pix_format(skel, &skel->format);
+ return 0;
+}
+
+static int skeleton_g_dv_timings(struct file *file, void *_fh,
+ struct v4l2_dv_timings *timings)
+{
+ struct skeleton *skel = video_drvdata(file);
+
+ /* G_DV_TIMINGS is not supported on the S-Video input */
+ if (skel->input == 0)
+ return -ENODATA;
+
+ *timings = skel->timings;
+ return 0;
+}
+
+static int skeleton_enum_dv_timings(struct file *file, void *_fh,
+ struct v4l2_enum_dv_timings *timings)
+{
+ struct skeleton *skel = video_drvdata(file);
+
+ /* ENUM_DV_TIMINGS is not supported on the S-Video input */
+ if (skel->input == 0)
+ return -ENODATA;
+
+ return v4l2_enum_dv_timings_cap(timings, &skel_timings_cap,
+ NULL, NULL);
+}
+
+/*
+ * Query the current timings as seen by the hardware. This function shall
+ * never actually change the timings, it just detects and reports.
+ * If no signal is detected, then return -ENOLINK. If the hardware cannot
+ * lock to the signal, then return -ENOLCK. If the signal is out of range
+ * of the capabilities of the system (e.g., it is possible that the receiver
+ * can lock but that the DMA engine it is connected to cannot handle
+ * pixelclocks above a certain frequency), then -ERANGE is returned.
+ */
+static int skeleton_query_dv_timings(struct file *file, void *_fh,
+ struct v4l2_dv_timings *timings)
+{
+ struct skeleton *skel = video_drvdata(file);
+
+ /* QUERY_DV_TIMINGS is not supported on the S-Video input */
+ if (skel->input == 0)
+ return -ENODATA;
+
+#ifdef TODO
+ /*
+ * Query currently seen timings. This function should look
+ * something like this:
+ */
+ detect_timings();
+ if (no_signal)
+ return -ENOLINK;
+ if (cannot_lock_to_signal)
+ return -ENOLCK;
+ if (signal_out_of_range_of_capabilities)
+ return -ERANGE;
+
+ /* Useful for debugging */
+ v4l2_print_dv_timings(skel->v4l2_dev.name, "query_dv_timings:",
+ timings, true);
+#endif
+ return 0;
+}
+
+static int skeleton_dv_timings_cap(struct file *file, void *fh,
+ struct v4l2_dv_timings_cap *cap)
+{
+ struct skeleton *skel = video_drvdata(file);
+
+ /* DV_TIMINGS_CAP is not supported on the S-Video input */
+ if (skel->input == 0)
+ return -ENODATA;
+ *cap = skel_timings_cap;
+ return 0;
+}
+
+static int skeleton_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ if (i->index > 1)
+ return -EINVAL;
+
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ if (i->index == 0) {
+ i->std = SKEL_TVNORMS;
+ strlcpy(i->name, "S-Video", sizeof(i->name));
+ i->capabilities = V4L2_IN_CAP_STD;
+ } else {
+ i->std = 0;
+ strlcpy(i->name, "HDMI", sizeof(i->name));
+ i->capabilities = V4L2_IN_CAP_DV_TIMINGS;
+ }
+ return 0;
+}
+
+static int skeleton_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct skeleton *skel = video_drvdata(file);
+
+ if (i > 1)
+ return -EINVAL;
+
+ /*
+ * Changing the input implies a format change, which is not allowed
+ * while buffers for use with streaming have already been allocated.
+ */
+ if (vb2_is_busy(&skel->queue))
+ return -EBUSY;
+
+ skel->input = i;
+ /*
+ * Update tvnorms. The tvnorms value is used by the core to implement
+ * VIDIOC_ENUMSTD so it has to be correct. If tvnorms == 0, then
+ * ENUMSTD will return -ENODATA.
+ */
+ skel->vdev.tvnorms = i ? 0 : SKEL_TVNORMS;
+
+ /* Update the internal format */
+ skeleton_fill_pix_format(skel, &skel->format);
+ return 0;
+}
+
+static int skeleton_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ struct skeleton *skel = video_drvdata(file);
+
+ *i = skel->input;
+ return 0;
+}
+
+/* The control handler. */
+static int skeleton_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ /*struct skeleton *skel =
+ container_of(ctrl->handler, struct skeleton, ctrl_handler);*/
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ /* TODO: set brightness to ctrl->val */
+ break;
+ case V4L2_CID_CONTRAST:
+ /* TODO: set contrast to ctrl->val */
+ break;
+ case V4L2_CID_SATURATION:
+ /* TODO: set saturation to ctrl->val */
+ break;
+ case V4L2_CID_HUE:
+ /* TODO: set hue to ctrl->val */
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* ------------------------------------------------------------------
+ File operations for the device
+ ------------------------------------------------------------------*/
+
+static const struct v4l2_ctrl_ops skel_ctrl_ops = {
+ .s_ctrl = skeleton_s_ctrl,
+};
+
+/*
+ * The set of all supported ioctls. Note that all the streaming ioctls
+ * use the vb2 helper functions that take care of all the locking and
+ * that also do ownership tracking (i.e. only the filehandle that requested
+ * the buffers can call the streaming ioctls, all other filehandles will
+ * receive -EBUSY if they attempt to call the same streaming ioctls).
+ *
+ * The last three ioctls also use standard helper functions: these implement
+ * standard behavior for drivers with controls.
+ */
+static const struct v4l2_ioctl_ops skel_ioctl_ops = {
+ .vidioc_querycap = skeleton_querycap,
+ .vidioc_try_fmt_vid_cap = skeleton_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = skeleton_s_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = skeleton_g_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap = skeleton_enum_fmt_vid_cap,
+
+ .vidioc_g_std = skeleton_g_std,
+ .vidioc_s_std = skeleton_s_std,
+ .vidioc_querystd = skeleton_querystd,
+
+ .vidioc_s_dv_timings = skeleton_s_dv_timings,
+ .vidioc_g_dv_timings = skeleton_g_dv_timings,
+ .vidioc_enum_dv_timings = skeleton_enum_dv_timings,
+ .vidioc_query_dv_timings = skeleton_query_dv_timings,
+ .vidioc_dv_timings_cap = skeleton_dv_timings_cap,
+
+ .vidioc_enum_input = skeleton_enum_input,
+ .vidioc_g_input = skeleton_g_input,
+ .vidioc_s_input = skeleton_s_input,
+
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+/*
+ * The set of file operations. Note that all these ops are standard core
+ * helper functions.
+ */
+static const struct v4l2_file_operations skel_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .unlocked_ioctl = video_ioctl2,
+ .read = vb2_fop_read,
+ .mmap = vb2_fop_mmap,
+ .poll = vb2_fop_poll,
+};
+
+/*
+ * The initial setup of this device instance. Note that the initial state of
+ * the driver should be complete. So the initial format, standard, timings
+ * and video input should all be initialized to some reasonable value.
+ */
+static int skeleton_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ /* The initial timings are chosen to be 720p60. */
+ static const struct v4l2_dv_timings timings_def =
+ V4L2_DV_BT_CEA_1280X720P60;
+ struct skeleton *skel;
+ struct video_device *vdev;
+ struct v4l2_ctrl_handler *hdl;
+ struct vb2_queue *q;
+ int ret;
+
+ /* Enable PCI */
+ ret = pci_enable_device(pdev);
+ if (ret)
+ return ret;
+ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(&pdev->dev, "no suitable DMA available.\n");
+ goto disable_pci;
+ }
+
+ /* Allocate a new instance */
+ skel = devm_kzalloc(&pdev->dev, sizeof(struct skeleton), GFP_KERNEL);
+ if (!skel)
+ return -ENOMEM;
+
+ /* Allocate the interrupt */
+ ret = devm_request_irq(&pdev->dev, pdev->irq,
+ skeleton_irq, 0, KBUILD_MODNAME, skel);
+ if (ret) {
+ dev_err(&pdev->dev, "request_irq failed\n");
+ goto disable_pci;
+ }
+ skel->pdev = pdev;
+
+ /* Fill in the initial format-related settings */
+ skel->timings = timings_def;
+ skel->std = V4L2_STD_625_50;
+ skeleton_fill_pix_format(skel, &skel->format);
+
+ /* Initialize the top-level structure */
+ ret = v4l2_device_register(&pdev->dev, &skel->v4l2_dev);
+ if (ret)
+ goto disable_pci;
+
+ mutex_init(&skel->lock);
+
+ /* Add the controls */
+ hdl = &skel->ctrl_handler;
+ v4l2_ctrl_handler_init(hdl, 4);
+ v4l2_ctrl_new_std(hdl, &skel_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
+ v4l2_ctrl_new_std(hdl, &skel_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, 16);
+ v4l2_ctrl_new_std(hdl, &skel_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 255, 1, 127);
+ v4l2_ctrl_new_std(hdl, &skel_ctrl_ops,
+ V4L2_CID_HUE, -128, 127, 1, 0);
+ if (hdl->error) {
+ ret = hdl->error;
+ goto free_hdl;
+ }
+ skel->v4l2_dev.ctrl_handler = hdl;
+
+ /* Initialize the vb2 queue */
+ q = &skel->queue;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
+ q->drv_priv = skel;
+ q->buf_struct_size = sizeof(struct skel_buffer);
+ q->ops = &skel_qops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ /*
+ * Assume that this DMA engine needs to have at least two buffers
+ * available before it can be started. The start_streaming() op
+ * won't be called until at least this many buffers are queued up.
+ */
+ q->min_buffers_needed = 2;
+ /*
+ * The serialization lock for the streaming ioctls. This is the same
+ * as the main serialization lock, but if some of the non-streaming
+ * ioctls could take a long time to execute, then you might want to
+ * have a different lock here to prevent VIDIOC_DQBUF from being
+ * blocked while waiting for another action to finish. This is
+ * generally not needed for PCI devices, but USB devices usually do
+ * want a separate lock here.
+ */
+ q->lock = &skel->lock;
+ /*
+ * Since this driver can only do 32-bit DMA we must make sure that
+ * the vb2 core will allocate the buffers in 32-bit DMA memory.
+ */
+ q->gfp_flags = GFP_DMA32;
+ ret = vb2_queue_init(q);
+ if (ret)
+ goto free_hdl;
+
+ skel->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+ if (IS_ERR(skel->alloc_ctx)) {
+ dev_err(&pdev->dev, "Can't allocate buffer context");
+ ret = PTR_ERR(skel->alloc_ctx);
+ goto free_hdl;
+ }
+ INIT_LIST_HEAD(&skel->buf_list);
+ spin_lock_init(&skel->qlock);
+
+ /* Initialize the video_device structure */
+ vdev = &skel->vdev;
+ strlcpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name));
+ /*
+ * There is nothing to clean up, so release is set to an empty release
+ * function. The release callback must be non-NULL.
+ */
+ vdev->release = video_device_release_empty;
+ vdev->fops = &skel_fops,
+ vdev->ioctl_ops = &skel_ioctl_ops,
+ /*
+ * The main serialization lock. All ioctls are serialized by this
+ * lock. Exception: if q->lock is set, then the streaming ioctls
+ * are serialized by that separate lock.
+ */
+ vdev->lock = &skel->lock;
+ vdev->queue = q;
+ vdev->v4l2_dev = &skel->v4l2_dev;
+ /* Supported SDTV standards, if any */
+ vdev->tvnorms = SKEL_TVNORMS;
+ /* If this bit is set, then the v4l2 core will provide the support
+ * for the VIDIOC_G/S_PRIORITY ioctls. This flag will eventually
+ * go away once all drivers have been converted to use struct v4l2_fh.
+ */
+ set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags);
+ video_set_drvdata(vdev, skel);
+
+ ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+ if (ret)
+ goto free_ctx;
+
+ dev_info(&pdev->dev, "V4L2 PCI Skeleton Driver loaded\n");
+ return 0;
+
+free_ctx:
+ vb2_dma_contig_cleanup_ctx(skel->alloc_ctx);
+free_hdl:
+ v4l2_ctrl_handler_free(&skel->ctrl_handler);
+ v4l2_device_unregister(&skel->v4l2_dev);
+disable_pci:
+ pci_disable_device(pdev);
+ return ret;
+}
+
+static void skeleton_remove(struct pci_dev *pdev)
+{
+ struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
+ struct skeleton *skel = container_of(v4l2_dev, struct skeleton, v4l2_dev);
+
+ video_unregister_device(&skel->vdev);
+ v4l2_ctrl_handler_free(&skel->ctrl_handler);
+ vb2_dma_contig_cleanup_ctx(skel->alloc_ctx);
+ v4l2_device_unregister(&skel->v4l2_dev);
+ pci_disable_device(skel->pdev);
+}
+
+static struct pci_driver skeleton_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = skeleton_probe,
+ .remove = skeleton_remove,
+ .id_table = skeleton_pci_tbl,
+};
+
+module_pci_driver(skeleton_driver);
diff --git a/Documentation/virtual/kvm/00-INDEX b/Documentation/virtual/kvm/00-INDEX
index 641ec9220179..fee9f2bf9c64 100644
--- a/Documentation/virtual/kvm/00-INDEX
+++ b/Documentation/virtual/kvm/00-INDEX
@@ -20,5 +20,7 @@ ppc-pv.txt
- the paravirtualization interface on PowerPC.
review-checklist.txt
- review checklist for KVM patches.
+s390-diag.txt
+ - Diagnose hypercall description (for IBM S/390)
timekeeping.txt
- timekeeping virtualization for x86-based architectures.
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 6cd63a9010fb..a9380ba54c8e 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -586,8 +586,8 @@ struct kvm_fpu {
4.24 KVM_CREATE_IRQCHIP
-Capability: KVM_CAP_IRQCHIP
-Architectures: x86, ia64, ARM, arm64
+Capability: KVM_CAP_IRQCHIP, KVM_CAP_S390_IRQCHIP (s390)
+Architectures: x86, ia64, ARM, arm64, s390
Type: vm ioctl
Parameters: none
Returns: 0 on success, -1 on error
@@ -596,7 +596,10 @@ Creates an interrupt controller model in the kernel. On x86, creates a virtual
ioapic, a virtual PIC (two PICs, nested), and sets up future vcpus to have a
local APIC. IRQ routing for GSIs 0-15 is set to both PIC and IOAPIC; GSI 16-23
only go to the IOAPIC. On ia64, a IOSAPIC is created. On ARM/arm64, a GIC is
-created.
+created. On s390, a dummy irq routing table is created.
+
+Note that on s390 the KVM_CAP_S390_IRQCHIP vm capability needs to be enabled
+before KVM_CREATE_IRQCHIP can be used.
4.25 KVM_IRQ_LINE
@@ -612,6 +615,20 @@ On some architectures it is required that an interrupt controller model has
been previously created with KVM_CREATE_IRQCHIP. Note that edge-triggered
interrupts require the level to be set to 1 and then back to 0.
+On real hardware, interrupt pins can be active-low or active-high. This
+does not matter for the level field of struct kvm_irq_level: 1 always
+means active (asserted), 0 means inactive (deasserted).
+
+x86 allows the operating system to program the interrupt polarity
+(active-low/active-high) for level-triggered interrupts, and KVM used
+to consider the polarity. However, due to bitrot in the handling of
+active-low interrupts, the above convention is now valid on x86 too.
+This is signaled by KVM_CAP_X86_IOAPIC_POLARITY_IGNORED. Userspace
+should not present interrupts to the guest as active-low unless this
+capability is present (or unless it is not using the in-kernel irqchip,
+of course).
+
+
ARM/arm64 can signal an interrupt either at the CPU level, or at the
in-kernel irqchip (GIC), and for in-kernel irqchip can tell the GIC to
use PPIs designated for specific cpus. The irq field is interpreted
@@ -628,7 +645,7 @@ The irq_type field has the following values:
(The irq_id field thus corresponds nicely to the IRQ ID in the ARM GIC specs)
-In both cases, level is used to raise/lower the line.
+In both cases, level is used to assert/deassert the line.
struct kvm_irq_level {
union {
@@ -918,9 +935,9 @@ documentation when it pops into existence).
4.37 KVM_ENABLE_CAP
-Capability: KVM_CAP_ENABLE_CAP
+Capability: KVM_CAP_ENABLE_CAP, KVM_CAP_ENABLE_CAP_VM
Architectures: ppc, s390
-Type: vcpu ioctl
+Type: vcpu ioctl, vm ioctl (with KVM_CAP_ENABLE_CAP_VM)
Parameters: struct kvm_enable_cap (in)
Returns: 0 on success; -1 on error
@@ -951,6 +968,8 @@ function properly, this is the place to put them.
__u8 pad[64];
};
+The vcpu ioctl should be used for vcpu-specific capabilities, the vm ioctl
+for vm-wide capabilities.
4.38 KVM_GET_MP_STATE
@@ -1320,7 +1339,7 @@ KVM_ASSIGN_DEV_IRQ. Partial deassignment of host or guest IRQ is allowed.
4.52 KVM_SET_GSI_ROUTING
Capability: KVM_CAP_IRQ_ROUTING
-Architectures: x86 ia64
+Architectures: x86 ia64 s390
Type: vm ioctl
Parameters: struct kvm_irq_routing (in)
Returns: 0 on success, -1 on error
@@ -1343,6 +1362,7 @@ struct kvm_irq_routing_entry {
union {
struct kvm_irq_routing_irqchip irqchip;
struct kvm_irq_routing_msi msi;
+ struct kvm_irq_routing_s390_adapter adapter;
__u32 pad[8];
} u;
};
@@ -1350,6 +1370,7 @@ struct kvm_irq_routing_entry {
/* gsi routing entry types */
#define KVM_IRQ_ROUTING_IRQCHIP 1
#define KVM_IRQ_ROUTING_MSI 2
+#define KVM_IRQ_ROUTING_S390_ADAPTER 3
No flags are specified so far, the corresponding field must be set to zero.
@@ -1365,6 +1386,14 @@ struct kvm_irq_routing_msi {
__u32 pad;
};
+struct kvm_irq_routing_s390_adapter {
+ __u64 ind_addr;
+ __u64 summary_addr;
+ __u64 ind_offset;
+ __u32 summary_offset;
+ __u32 adapter_id;
+};
+
4.53 KVM_ASSIGN_SET_MSIX_NR
@@ -1462,7 +1491,7 @@ struct kvm_lapic_state {
char regs[KVM_APIC_REG_SIZE];
};
-Copies the input argument into the the Local APIC registers. The data format
+Copies the input argument into the Local APIC registers. The data format
and layout are the same as documented in the architecture manual.
@@ -2566,6 +2595,10 @@ executed a memory-mapped I/O instruction which could not be satisfied
by kvm. The 'data' member contains the written data if 'is_write' is
true, and should be filled by application code otherwise.
+The 'data' member contains, in its first 'len' bytes, the value as it would
+appear if the VCPU performed a load or store of the appropriate width directly
+to the byte array.
+
NOTE: For KVM_EXIT_IO, KVM_EXIT_MMIO, KVM_EXIT_OSI, KVM_EXIT_DCR,
KVM_EXIT_PAPR and KVM_EXIT_EPR the corresponding
operations are complete (and guest state is consistent) only after userspace
diff --git a/Documentation/virtual/kvm/devices/s390_flic.txt b/Documentation/virtual/kvm/devices/s390_flic.txt
new file mode 100644
index 000000000000..4ceef53164b0
--- /dev/null
+++ b/Documentation/virtual/kvm/devices/s390_flic.txt
@@ -0,0 +1,91 @@
+FLIC (floating interrupt controller)
+====================================
+
+FLIC handles floating (non per-cpu) interrupts, i.e. I/O, service and some
+machine check interruptions. All interrupts are stored in a per-vm list of
+pending interrupts. FLIC performs operations on this list.
+
+Only one FLIC instance may be instantiated.
+
+FLIC provides support to
+- add interrupts (KVM_DEV_FLIC_ENQUEUE)
+- inspect currently pending interrupts (KVM_FLIC_GET_ALL_IRQS)
+- purge all pending floating interrupts (KVM_DEV_FLIC_CLEAR_IRQS)
+- enable/disable for the guest transparent async page faults
+- register and modify adapter interrupt sources (KVM_DEV_FLIC_ADAPTER_*)
+
+Groups:
+ KVM_DEV_FLIC_ENQUEUE
+ Passes a buffer and length into the kernel which are then injected into
+ the list of pending interrupts.
+ attr->addr contains the pointer to the buffer and attr->attr contains
+ the length of the buffer.
+ The format of the data structure kvm_s390_irq as it is copied from userspace
+ is defined in usr/include/linux/kvm.h.
+
+ KVM_DEV_FLIC_GET_ALL_IRQS
+ Copies all floating interrupts into a buffer provided by userspace.
+ When the buffer is too small it returns -ENOMEM, which is the indication
+ for userspace to try again with a bigger buffer.
+ All interrupts remain pending, i.e. are not deleted from the list of
+ currently pending interrupts.
+ attr->addr contains the userspace address of the buffer into which all
+ interrupt data will be copied.
+ attr->attr contains the size of the buffer in bytes.
+
+ KVM_DEV_FLIC_CLEAR_IRQS
+ Simply deletes all elements from the list of currently pending floating
+ interrupts. No interrupts are injected into the guest.
+
+ KVM_DEV_FLIC_APF_ENABLE
+ Enables async page faults for the guest. So in case of a major page fault
+ the host is allowed to handle this async and continues the guest.
+
+ KVM_DEV_FLIC_APF_DISABLE_WAIT
+ Disables async page faults for the guest and waits until already pending
+ async page faults are done. This is necessary to trigger a completion interrupt
+ for every init interrupt before migrating the interrupt list.
+
+ KVM_DEV_FLIC_ADAPTER_REGISTER
+ Register an I/O adapter interrupt source. Takes a kvm_s390_io_adapter
+ describing the adapter to register:
+
+struct kvm_s390_io_adapter {
+ __u32 id;
+ __u8 isc;
+ __u8 maskable;
+ __u8 swap;
+ __u8 pad;
+};
+
+ id contains the unique id for the adapter, isc the I/O interruption subclass
+ to use, maskable whether this adapter may be masked (interrupts turned off)
+ and swap whether the indicators need to be byte swapped.
+
+
+ KVM_DEV_FLIC_ADAPTER_MODIFY
+ Modifies attributes of an existing I/O adapter interrupt source. Takes
+ a kvm_s390_io_adapter_req specifiying the adapter and the operation:
+
+struct kvm_s390_io_adapter_req {
+ __u32 id;
+ __u8 type;
+ __u8 mask;
+ __u16 pad0;
+ __u64 addr;
+};
+
+ id specifies the adapter and type the operation. The supported operations
+ are:
+
+ KVM_S390_IO_ADAPTER_MASK
+ mask or unmask the adapter, as specified in mask
+
+ KVM_S390_IO_ADAPTER_MAP
+ perform a gmap translation for the guest address provided in addr,
+ pin a userspace page for the translated address and add it to the
+ list of mappings
+
+ KVM_S390_IO_ADAPTER_UNMAP
+ release a userspace page for the translated address specified in addr
+ from the list of mappings
diff --git a/Documentation/vm/00-INDEX b/Documentation/vm/00-INDEX
index a39d06680e1c..081c49777abb 100644
--- a/Documentation/vm/00-INDEX
+++ b/Documentation/vm/00-INDEX
@@ -16,8 +16,6 @@ hwpoison.txt
- explains what hwpoison is
ksm.txt
- how to use the Kernel Samepage Merging feature.
-locking
- - info on how locking and synchronization is done in the Linux vm code.
numa
- information about NUMA specific code in the Linux vm.
numa_memory_policy.txt
@@ -32,6 +30,8 @@ slub.txt
- a short users guide for SLUB.
soft-dirty.txt
- short explanation for soft-dirty PTEs
+split_page_table_lock
+ - Separate per-table lock to improve scalability of the old page_table_lock.
transhuge.txt
- Transparent Hugepage Support, alternative way of using hugepages.
unevictable-lru.txt
diff --git a/Documentation/vm/unevictable-lru.txt b/Documentation/vm/unevictable-lru.txt
index a68db7692ee8..744f82f86c58 100644
--- a/Documentation/vm/unevictable-lru.txt
+++ b/Documentation/vm/unevictable-lru.txt
@@ -453,7 +453,7 @@ putback_lru_page() function to add migrated pages back to the LRU.
mmap(MAP_LOCKED) SYSTEM CALL HANDLING
-------------------------------------
-In addition the the mlock()/mlockall() system calls, an application can request
+In addition the mlock()/mlockall() system calls, an application can request
that a region of memory be mlocked supplying the MAP_LOCKED flag to the mmap()
call. Furthermore, any mmap() call or brk() call that expands the heap by a
task that has previously called mlockall() with the MCL_FUTURE flag will result
diff --git a/Documentation/w1/masters/00-INDEX b/Documentation/w1/masters/00-INDEX
index d63fa024ac05..8330cf9325f0 100644
--- a/Documentation/w1/masters/00-INDEX
+++ b/Documentation/w1/masters/00-INDEX
@@ -4,7 +4,9 @@ ds2482
- The Maxim/Dallas Semiconductor DS2482 provides 1-wire busses.
ds2490
- The Maxim/Dallas Semiconductor DS2490 builds USB <-> W1 bridges.
-mxc_w1
+mxc-w1
- W1 master controller driver found on Freescale MX2/MX3 SoCs
+omap-hdq
+ - HDQ/1-wire module of TI OMAP 2430/3430.
w1-gpio
- GPIO 1-wire bus master driver.
diff --git a/Documentation/w1/masters/ds2490 b/Documentation/w1/masters/ds2490
index 28176def3d6f..3e091151dd80 100644
--- a/Documentation/w1/masters/ds2490
+++ b/Documentation/w1/masters/ds2490
@@ -21,8 +21,6 @@ Notes and limitations.
- The weak pullup current is a minimum of 0.9mA and maximum of 6.0mA.
- The 5V strong pullup is supported with a minimum of 5.9mA and a
maximum of 30.4 mA. (From DS2490.pdf)
-- While the ds2490 supports a hardware search the code doesn't take
- advantage of it (in tested case it only returned first device).
- The hardware will detect when devices are attached to the bus on the
next bus (reset?) operation, however only a message is printed as
the core w1 code doesn't make use of the information. Connecting
diff --git a/Documentation/w1/slaves/00-INDEX b/Documentation/w1/slaves/00-INDEX
index 75613c9ac4db..6e18c70c3474 100644
--- a/Documentation/w1/slaves/00-INDEX
+++ b/Documentation/w1/slaves/00-INDEX
@@ -4,3 +4,5 @@ w1_therm
- The Maxim/Dallas Semiconductor ds18*20 temperature sensor.
w1_ds2423
- The Maxim/Dallas Semiconductor ds2423 counter device.
+w1_ds28e04
+ - The Maxim/Dallas Semiconductor ds28e04 eeprom.
diff --git a/Documentation/w1/w1.netlink b/Documentation/w1/w1.netlink
index f59a31965d50..927a52cc0519 100644
--- a/Documentation/w1/w1.netlink
+++ b/Documentation/w1/w1.netlink
@@ -5,8 +5,8 @@ Message types.
=============
There are three types of messages between w1 core and userspace:
-1. Events. They are generated each time new master or slave device
- found either due to automatic or requested search.
+1. Events. They are generated each time a new master or slave device
+ is found either due to automatic or requested search.
2. Userspace commands.
3. Replies to userspace commands.
@@ -131,7 +131,7 @@ of the w1_netlink_cmd structure and cn_msg.len will be equal to the sum
of the sizeof(struct w1_netlink_msg) and sizeof(struct w1_netlink_cmd).
If reply is generated for master or root command (which do not have
w1_netlink_cmd attached), reply will contain only cn_msg and w1_netlink_msg
-structires.
+structures.
w1_netlink_msg.status field will carry positive error value
(EINVAL for example) or zero in case of success.
@@ -160,7 +160,7 @@ procedure is started to select given device.
Then all requested in w1_netlink_msg operations are performed one by one.
If command requires reply (like read command) it is sent on command completion.
-When all commands (w1_netlink_cmd) are processed muster device is unlocked
+When all commands (w1_netlink_cmd) are processed master device is unlocked
and next w1_netlink_msg header processing started.
diff --git a/Documentation/watchdog/watchdog-parameters.txt b/Documentation/watchdog/watchdog-parameters.txt
index f9492fed4104..692791cc674c 100644
--- a/Documentation/watchdog/watchdog-parameters.txt
+++ b/Documentation/watchdog/watchdog-parameters.txt
@@ -150,6 +150,8 @@ nowayout: Disable watchdog shutdown on close
-------------------------------------------------
it87_wdt:
nogameport: Forbid the activation of game port, default=0
+nocir: Forbid the use of CIR (workaround for some buggy setups); set to 1 if
+system resets despite watchdog daemon running, default=0
exclusive: Watchdog exclusive device open, default=1
timeout: Watchdog timeout in seconds, default=60
testmode: Watchdog test mode (1 = no reboot), default=0
@@ -325,6 +327,11 @@ soft_noboot: Softdog action, set to 1 to ignore reboots, 0 to reboot
stmp3xxx_wdt:
heartbeat: Watchdog heartbeat period in seconds from 1 to 4194304, default 19
-------------------------------------------------
+tegra_wdt:
+heartbeat: Watchdog heartbeats in seconds. (default = 120)
+nowayout: Watchdog cannot be stopped once started
+ (default=kernel config parameter)
+-------------------------------------------------
ts72xx_wdt:
timeout: Watchdog timeout in seconds. (1 <= timeout <= 8, default=8)
nowayout: Disable watchdog shutdown on close
diff --git a/Documentation/x86/00-INDEX b/Documentation/x86/00-INDEX
index f37b46d34861..692264456f0f 100644
--- a/Documentation/x86/00-INDEX
+++ b/Documentation/x86/00-INDEX
@@ -1,6 +1,20 @@
00-INDEX
- this file
-mtrr.txt
- - how to use x86 Memory Type Range Registers to increase performance
+boot.txt
+ - List of boot protocol versions
+early-microcode.txt
+ - How to load microcode from an initrd-CPIO archive early to fix CPU issues.
+earlyprintk.txt
+ - Using earlyprintk with a USB2 debug port key.
+entry_64.txt
+ - Describe (some of the) kernel entry points for x86.
exception-tables.txt
- why and how Linux kernel uses exception tables on x86
+mtrr.txt
+ - how to use x86 Memory Type Range Registers to increase performance
+pat.txt
+ - Page Attribute Table intro and API
+usb-legacy-support.txt
+ - how to fix/avoid quirks when using emulated PS/2 mouse/keyboard.
+zero-page.txt
+ - layout of the first page of memory.
diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt
index cb81741d3b0b..a75e3adaa39d 100644
--- a/Documentation/x86/boot.txt
+++ b/Documentation/x86/boot.txt
@@ -182,7 +182,7 @@ Offset Proto Name Meaning
0226/1 2.02+(3 ext_loader_ver Extended boot loader version
0227/1 2.02+(3 ext_loader_type Extended boot loader ID
0228/4 2.02+ cmd_line_ptr 32-bit pointer to the kernel command line
-022C/4 2.03+ ramdisk_max Highest legal initrd address
+022C/4 2.03+ initrd_addr_max Highest legal initrd address
0230/4 2.05+ kernel_alignment Physical addr alignment required for kernel
0234/1 2.05+ relocatable_kernel Whether kernel is relocatable or not
0235/1 2.10+ min_alignment Minimum alignment, as a power of two
@@ -534,7 +534,7 @@ Protocol: 2.02+
zero, the kernel will assume that your boot loader does not support
the 2.02+ protocol.
-Field name: ramdisk_max
+Field name: initrd_addr_max
Type: read
Offset/size: 0x22c/4
Protocol: 2.03+
diff --git a/Documentation/zh_CN/SubmittingPatches b/Documentation/zh_CN/SubmittingPatches
index be0bd4725062..1d3a10f8746b 100644
--- a/Documentation/zh_CN/SubmittingPatches
+++ b/Documentation/zh_CN/SubmittingPatches
@@ -82,10 +82,6 @@ Documentation/SubmittingDrivers 。
Quilt:
http://savannah.nongnu.org/projects/quilt
-Andrew Morton 的补丁脚本:
-http://userweb.kernel.org/~akpm/stuff/patch-scripts.tar.gz
-作为这些脚本的替代,quilt 是值得推荐的补丁管理工具(看上面的链接)。
-
2)描述你的改动。
描述你的改动包含的技术细节。
@@ -394,7 +390,7 @@ Static inline 函数相比宏来说,是好得多的选择。Static inline 函
----------------
Andrew Morton, "The perfect patch" (tpp).
- <http://userweb.kernel.org/~akpm/stuff/tpp.txt>
+ <http://www.ozlabs.org/~akpm/stuff/tpp.txt>
Jeff Garzik, "Linux kernel patch submission format".
<http://linux.yyz.us/patch-format.html>
@@ -406,7 +402,7 @@ Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer".
<http://www.kroah.com/log/2006/01/11/>
NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!
- <http://marc.theaimsgroup.com/?l=linux-kernel&m=112112749912944&w=2>
+ <https://lkml.org/lkml/2005/7/11/336>
Kernel Documentation/CodingStyle:
<http://sosdg.org/~coywolf/lxr/source/Documentation/CodingStyle>
diff --git a/Documentation/zh_CN/arm64/booting.txt b/Documentation/zh_CN/arm64/booting.txt
index 28fa325b7461..6f6d956ac1c9 100644
--- a/Documentation/zh_CN/arm64/booting.txt
+++ b/Documentation/zh_CN/arm64/booting.txt
@@ -7,7 +7,7 @@ help. Contact the Chinese maintainer if this translation is outdated
or if there is a problem with the translation.
Maintainer: Will Deacon <will.deacon@arm.com>
-Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
+Chinese maintainer: Fu Wei <wefu@redhat.com>
---------------------------------------------------------------------
Documentation/arm64/booting.txt 的中文翻译
@@ -16,9 +16,9 @@ Documentation/arm64/booting.txt 的中文翻译
译存在问题,请联系中文版维护者。
英文版维护者: Will Deacon <will.deacon@arm.com>
-中文版维护者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
-中文版翻译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
-中文版校译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
+中文版维护者: 傅炜 Fu Wei <wefu@redhat.com>
+中文版翻译者: 傅炜 Fu Wei <wefu@redhat.com>
+中文版校译者: 傅炜 Fu Wei <wefu@redhat.com>
以下为正文
---------------------------------------------------------------------
@@ -64,8 +64,8 @@ RAM,或可能使用对这个设备已知的 RAM 信息,还可能使用任何
必要性: 强制
-设备树数据块(dtb)大小必须不大于 2 MB,且位于从内核映像起始算起第一个
-512MB 内的 2MB 边界上。这使得内核可以通过初始页表中的单个节描述符来
+设备树数据块(dtb)必须 8 字节对齐,并位于从内核映像起始算起第一个 512MB
+内,且不得跨越 2MB 对齐边界。这使得内核可以通过初始页表中的单个节描述符来
映射此数据块。
@@ -84,13 +84,23 @@ AArch64 内核当前没有提供自解压代码,因此如果使用了压缩内
必要性: 强制
-已解压的内核映像包含一个 32 字节的头,内容如下:
+已解压的内核映像包含一个 64 字节的头,内容如下:
- u32 magic = 0x14000008; /* 跳转到 stext, 小端 */
- u32 res0 = 0; /* 保留 */
+ u32 code0; /* 可执行代码 */
+ u32 code1; /* 可执行代码 */
u64 text_offset; /* 映像装载偏移 */
+ u64 res0 = 0; /* 保留 */
u64 res1 = 0; /* 保留 */
u64 res2 = 0; /* 保留 */
+ u64 res3 = 0; /* 保留 */
+ u64 res4 = 0; /* 保留 */
+ u32 magic = 0x644d5241; /* 魔数, 小端, "ARM\x64" */
+ u32 res5 = 0; /* 保留 */
+
+
+映像头注释:
+
+- code0/code1 负责跳转到 stext.
映像必须位于系统 RAM 起始处的特定偏移(当前是 0x80000)。系统 RAM
的起始地址必须是以 2MB 对齐的。
@@ -118,9 +128,9 @@ AArch64 内核当前没有提供自解压代码,因此如果使用了压缩内
外部高速缓存(如果存在)必须配置并禁用。
- 架构计时器
- CNTFRQ 必须设定为计时器的频率。
- 如果在 EL1 模式下进入内核,则 CNTHCTL_EL2 中的 EL1PCTEN (bit 0)
- 必须置位。
+ CNTFRQ 必须设定为计时器的频率,且 CNTVOFF 必须设定为对所有 CPU
+ 都一致的值。如果在 EL1 模式下进入内核,则 CNTHCTL_EL2 中的
+ EL1PCTEN (bit 0) 必须置位。
- 一致性
通过内核启动的所有 CPU 在内核入口地址上必须处于相同的一致性域中。
@@ -131,23 +141,40 @@ AArch64 内核当前没有提供自解压代码,因此如果使用了压缩内
在进入内核映像的异常级中,所有构架中可写的系统寄存器必须通过软件
在一个更高的异常级别下初始化,以防止在 未知 状态下运行。
+以上对于 CPU 模式、高速缓存、MMU、架构计时器、一致性、系统寄存器的
+必要条件描述适用于所有 CPU。所有 CPU 必须在同一异常级别跳入内核。
+
引导装载程序必须在每个 CPU 处于以下状态时跳入内核入口:
- 主 CPU 必须直接跳入内核映像的第一条指令。通过此 CPU 传递的设备树
- 数据块必须在每个 CPU 节点中包含以下内容:
-
- 1、‘enable-method’属性。目前,此字段支持的值仅为字符串“spin-table”。
-
- 2、‘cpu-release-addr’标识一个 64-bit、初始化为零的内存位置。
+ 数据块必须在每个 CPU 节点中包含一个 ‘enable-method’ 属性,所
+ 支持的 enable-method 请见下文。
引导装载程序必须生成这些设备树属性,并在跳入内核入口之前将其插入
数据块。
-- 任何辅助 CPU 必须在内存保留区(通过设备树中的 /memreserve/ 域传递
+- enable-method 为 “spin-table” 的 CPU 必须在它们的 CPU
+ 节点中包含一个 ‘cpu-release-addr’ 属性。这个属性标识了一个
+ 64 位自然对齐且初始化为零的内存位置。
+
+ 这些 CPU 必须在内存保留区(通过设备树中的 /memreserve/ 域传递
给内核)中自旋于内核之外,轮询它们的 cpu-release-addr 位置(必须
包含在保留区中)。可通过插入 wfe 指令来降低忙循环开销,而主 CPU 将
发出 sev 指令。当对 cpu-release-addr 所指位置的读取操作返回非零值
- 时,CPU 必须直接跳入此值所指向的地址。
+ 时,CPU 必须跳入此值所指向的地址。此值为一个单独的 64 位小端值,
+ 因此 CPU 须在跳转前将所读取的值转换为其本身的端模式。
+
+- enable-method 为 “psci” 的 CPU 保持在内核外(比如,在
+ memory 节点中描述为内核空间的内存区外,或在通过设备树 /memreserve/
+ 域中描述为内核保留区的空间中)。内核将会发起在 ARM 文档(编号
+ ARM DEN 0022A:用于 ARM 上的电源状态协调接口系统软件)中描述的
+ CPU_ON 调用来将 CPU 带入内核。
+
+ *译者注:到文档翻译时,此文档已更新为 ARM DEN 0022B。
+
+ 设备树必须包含一个 ‘psci’ 节点,请参考以下文档:
+ Documentation/devicetree/bindings/arm/psci.txt
+
- 辅助 CPU 通用寄存器设置
x0 = 0 (保留,将来可能使用)
diff --git a/Documentation/zh_CN/arm64/memory.txt b/Documentation/zh_CN/arm64/memory.txt
index a5f6283829f9..a782704c1cb5 100644
--- a/Documentation/zh_CN/arm64/memory.txt
+++ b/Documentation/zh_CN/arm64/memory.txt
@@ -7,7 +7,7 @@ help. Contact the Chinese maintainer if this translation is outdated
or if there is a problem with the translation.
Maintainer: Catalin Marinas <catalin.marinas@arm.com>
-Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
+Chinese maintainer: Fu Wei <wefu@redhat.com>
---------------------------------------------------------------------
Documentation/arm64/memory.txt 的中文翻译
@@ -16,9 +16,9 @@ Documentation/arm64/memory.txt 的中文翻译
译存在问题,请联系中文版维护者。
英文版维护者: Catalin Marinas <catalin.marinas@arm.com>
-中文版维护者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
-中文版翻译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
-中文版校译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
+中文版维护者: 傅炜 Fu Wei <wefu@redhat.com>
+中文版翻译者: 傅炜 Fu Wei <wefu@redhat.com>
+中文版校译者: 傅炜 Fu Wei <wefu@redhat.com>
以下为正文
---------------------------------------------------------------------
@@ -41,7 +41,7 @@ AArch64 Linux 使用页大小为 4KB 的 3 级转换表配置,对于用户和
TTBR1 中,且从不写入 TTBR0。
-AArch64 Linux 内存布局:
+AArch64 Linux 在页大小为 4KB 时的内存布局:
起始地址 结束地址 大小 用途
-----------------------------------------------------------------------
@@ -55,15 +55,42 @@ ffffffbc00000000 ffffffbdffffffff 8GB vmemmap
ffffffbe00000000 ffffffbffbbfffff ~8GB [防护页,未来用于 vmmemap]
+ffffffbffbc00000 ffffffbffbdfffff 2MB earlyprintk 设备
+
ffffffbffbe00000 ffffffbffbe0ffff 64KB PCI I/O 空间
-ffffffbbffff0000 ffffffbcffffffff ~2MB [防护页]
+ffffffbffbe10000 ffffffbcffffffff ~2MB [防护页]
ffffffbffc000000 ffffffbfffffffff 64MB 模块
ffffffc000000000 ffffffffffffffff 256GB 内核逻辑内存映射
+AArch64 Linux 在页大小为 64KB 时的内存布局:
+
+起始地址 结束地址 大小 用途
+-----------------------------------------------------------------------
+0000000000000000 000003ffffffffff 4TB 用户空间
+
+fffffc0000000000 fffffdfbfffeffff ~2TB vmalloc
+
+fffffdfbffff0000 fffffdfbffffffff 64KB [防护页]
+
+fffffdfc00000000 fffffdfdffffffff 8GB vmemmap
+
+fffffdfe00000000 fffffdfffbbfffff ~8GB [防护页,未来用于 vmmemap]
+
+fffffdfffbc00000 fffffdfffbdfffff 2MB earlyprintk 设备
+
+fffffdfffbe00000 fffffdfffbe0ffff 64KB PCI I/O 空间
+
+fffffdfffbe10000 fffffdfffbffffff ~2MB [防护页]
+
+fffffdfffc000000 fffffdffffffffff 64MB 模块
+
+fffffe0000000000 ffffffffffffffff 2TB 内核逻辑内存映射
+
+
4KB 页大小的转换表查找:
+--------+--------+--------+--------+--------+--------+--------+--------+
@@ -91,3 +118,10 @@ ffffffc000000000 ffffffffffffffff 256GB 内核逻辑内存映射
| | +--------------------------> [41:29] L2 索引 (仅使用 38:29 )
| +-------------------------------> [47:42] L1 索引 (未使用)
+-------------------------------------------------> [63] TTBR0/1
+
+当使用 KVM 时, 管理程序(hypervisor)在 EL2 中通过相对内核虚拟地址的
+一个固定偏移来映射内核页(内核虚拟地址的高 24 位设为零):
+
+起始地址 结束地址 大小 用途
+-----------------------------------------------------------------------
+0000004000000000 0000007fffffffff 256GB 在 HYP 中映射的内核对象
diff --git a/Documentation/zh_CN/arm64/tagged-pointers.txt b/Documentation/zh_CN/arm64/tagged-pointers.txt
new file mode 100644
index 000000000000..2664d1bd5a1c
--- /dev/null
+++ b/Documentation/zh_CN/arm64/tagged-pointers.txt
@@ -0,0 +1,52 @@
+Chinese translated version of Documentation/arm64/tagged-pointers.txt
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly. However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help. Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Maintainer: Will Deacon <will.deacon@arm.com>
+Chinese maintainer: Fu Wei <wefu@redhat.com>
+---------------------------------------------------------------------
+Documentation/arm64/tagged-pointers.txt 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+
+英文版维护者: Will Deacon <will.deacon@arm.com>
+中文版维护者: 傅炜 Fu Wei <wefu@redhat.com>
+中文版翻译者: 傅炜 Fu Wei <wefu@redhat.com>
+中文版校译者: 傅炜 Fu Wei <wefu@redhat.com>
+
+以下为正文
+---------------------------------------------------------------------
+ Linux 在 AArch64 中带标记的虚拟地址
+ =================================
+
+作者: Will Deacon <will.deacon@arm.com>
+日期: 2013 年 06 月 12 日
+
+本文档简述了在 AArch64 地址转换系统中提供的带标记的虚拟地址及其在
+AArch64 Linux 中的潜在用途。
+
+内核提供的地址转换表配置使通过 TTBR0 完成的虚拟地址转换(即用户空间
+映射),其虚拟地址的最高 8 位(63:56)会被转换硬件所忽略。这种机制
+让这些位可供应用程序自由使用,其注意事项如下:
+
+ (1) 内核要求所有传递到 EL1 的用户空间地址带有 0x00 标记。
+ 这意味着任何携带用户空间虚拟地址的系统调用(syscall)
+ 参数 *必须* 在陷入内核前使它们的最高字节被清零。
+
+ (2) 非零标记在传递信号时不被保存。这意味着在应用程序中利用了
+ 标记的信号处理函数无法依赖 siginfo_t 的用户空间虚拟
+ 地址所携带的包含其内部域信息的标记。此规则的一个例外是
+ 当信号是在调试观察点的异常处理程序中产生的,此时标记的
+ 信息将被保存。
+
+ (3) 当使用带标记的指针时需特别留心,因为仅对两个虚拟地址
+ 的高字节,C 编译器很可能无法判断它们是不同的。
+
+此构架会阻止对带标记的 PC 指针的利用,因此在异常返回时,其高字节
+将被设置成一个为 “55” 的扩展符。
diff --git a/MAINTAINERS b/MAINTAINERS
index b2cf5cfb4d29..f728ac2b298a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -73,7 +73,8 @@ Descriptions of section entries:
L: Mailing list that is relevant to this area
W: Web-page with status/info
Q: Patchwork web based patch tracking system site
- T: SCM tree type and location. Type is one of: git, hg, quilt, stgit, topgit.
+ T: SCM tree type and location.
+ Type is one of: git, hg, quilt, stgit, topgit
S: Status, one of the following:
Supported: Someone is actually paid to look after this.
Maintained: Someone actually looks after it.
@@ -241,8 +242,8 @@ S: Maintained
F: drivers/platform/x86/acer-wmi.c
ACPI
-M: Len Brown <lenb@kernel.org>
M: Rafael J. Wysocki <rjw@rjwysocki.net>
+M: Len Brown <lenb@kernel.org>
L: linux-acpi@vger.kernel.org
W: https://01.org/linux-acpi
Q: https://patchwork.kernel.org/project/linux-acpi/list/
@@ -473,7 +474,7 @@ F: net/rxrpc/af_rxrpc.c
AGPGART DRIVER
M: David Airlie <airlied@linux.ie>
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git
+T: git git://people.freedesktop.org/~airlied/linux (part of drm maint)
S: Maintained
F: drivers/char/agp/
F: include/linux/agp*
@@ -535,10 +536,17 @@ S: Odd Fixes
L: linux-alpha@vger.kernel.org
F: arch/alpha/
+ALTERA TRIPLE SPEED ETHERNET DRIVER
+M: Vince Bridgers <vbridgers2013@gmail.com
+L: netdev@vger.kernel.org
+L: nios2-dev@lists.rocketboards.org (moderated for non-subscribers)
+S: Maintained
+F: drivers/net/ethernet/altera/
+
ALTERA UART/JTAG UART SERIAL DRIVERS
M: Tobias Klauser <tklauser@distanz.ch>
L: linux-serial@vger.kernel.org
-L: nios2-dev@sopc.et.ntust.edu.tw (moderated for non-subscribers)
+L: nios2-dev@lists.rocketboards.org (moderated for non-subscribers)
S: Maintained
F: drivers/tty/serial/altera_uart.c
F: drivers/tty/serial/altera_jtaguart.c
@@ -910,11 +918,11 @@ F: arch/arm/include/asm/hardware/dec21285.h
F: arch/arm/mach-footbridge/
ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
-M: Shawn Guo <shawn.guo@linaro.org>
+M: Shawn Guo <shawn.guo@freescale.com>
M: Sascha Hauer <kernel@pengutronix.de>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
-T: git git://git.linaro.org/people/shawnguo/linux-2.6.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git
F: arch/arm/mach-imx/
F: arch/arm/boot/dts/imx*
F: arch/arm/configs/imx*_defconfig
@@ -1319,6 +1327,7 @@ M: Linus Walleij <linus.walleij@linaro.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Supported
F: arch/arm/mach-u300/
+F: drivers/clocksource/timer-u300.c
F: drivers/i2c/busses/i2c-stu300.c
F: drivers/rtc/rtc-coh901331.c
F: drivers/watchdog/coh901327_wdt.c
@@ -1612,11 +1621,11 @@ S: Maintained
F: drivers/net/wireless/atmel*
ATTO EXPRESSSAS SAS/SATA RAID SCSI DRIVER
-M: Bradley Grove <linuxdrivers@attotech.com>
-L: linux-scsi@vger.kernel.org
-W: http://www.attotech.com
-S: Supported
-F: drivers/scsi/esas2r
+M: Bradley Grove <linuxdrivers@attotech.com>
+L: linux-scsi@vger.kernel.org
+W: http://www.attotech.com
+S: Supported
+F: drivers/scsi/esas2r
AUDIT SUBSYSTEM
M: Eric Paris <eparis@redhat.com>
@@ -1695,6 +1704,8 @@ F: drivers/net/wireless/b43legacy/
BACKLIGHT CLASS/SUBSYSTEM
M: Jingoo Han <jg1.han@samsung.com>
+M: Bryan Wu <cooloney@gmail.com>
+M: Lee Jones <lee.jones@linaro.org>
S: Maintained
F: drivers/video/backlight/
F: include/linux/backlight.h
@@ -1737,6 +1748,7 @@ F: include/uapi/linux/bfs_fs.h
BLACKFIN ARCHITECTURE
M: Steven Miao <realmz6@gmail.com>
L: adi-buildroot-devel@lists.sourceforge.net
+T: git git://git.code.sf.net/p/adi-linux/code
W: http://blackfin.uclinux.org
S: Supported
F: arch/blackfin/
@@ -1830,8 +1842,8 @@ F: net/bluetooth/
F: include/net/bluetooth/
BONDING DRIVER
-M: Jay Vosburgh <fubar@us.ibm.com>
-M: Veaceslav Falico <vfalico@redhat.com>
+M: Jay Vosburgh <j.vosburgh@gmail.com>
+M: Veaceslav Falico <vfalico@gmail.com>
M: Andy Gospodarek <andy@greyhouse.net>
L: netdev@vger.kernel.org
W: http://sourceforge.net/projects/bonding/
@@ -1845,6 +1857,12 @@ L: netdev@vger.kernel.org
S: Supported
F: drivers/net/ethernet/broadcom/b44.*
+BROADCOM GENET ETHERNET DRIVER
+M: Florian Fainelli <f.fainelli@gmail.com>
+L: netdev@vger.kernel.org
+S: Supported
+F: drivers/net/ethernet/broadcom/genet/
+
BROADCOM BNX2 GIGABIT ETHERNET DRIVER
M: Michael Chan <mchan@broadcom.com>
L: netdev@vger.kernel.org
@@ -1860,6 +1878,7 @@ F: drivers/net/ethernet/broadcom/bnx2x/
BROADCOM BCM281XX/BCM11XXX ARM ARCHITECTURE
M: Christian Daudt <bcm@fixthebug.org>
+M: Matt Porter <mporter@linaro.org>
L: bcm-kernel-feedback-list@broadcom.com
T: git git://git.github.com/broadcom/bcm11351
S: Maintained
@@ -1909,6 +1928,13 @@ L: linux-scsi@vger.kernel.org
S: Supported
F: drivers/scsi/bnx2i/
+BROADCOM KONA GPIO DRIVER
+M: Markus Mayer <markus.mayer@linaro.org>
+L: bcm-kernel-feedback-list@broadcom.com
+S: Supported
+F: drivers/gpio/gpio-bcm-kona.c
+F: Documentation/devicetree/bindings/gpio/gpio-bcm-kona.txt
+
BROADCOM SPECIFIC AMBA DRIVER (BCMA)
M: Rafał Miłecki <zajec5@gmail.com>
L: linux-wireless@vger.kernel.org
@@ -1917,8 +1943,8 @@ F: drivers/bcma/
F: include/linux/bcma/
BROCADE BFA FC SCSI DRIVER
-M: Anil Gurumurthy <agurumur@brocade.com>
-M: Vijaya Mohan Guvva <vmohan@brocade.com>
+M: Anil Gurumurthy <anil.gurumurthy@qlogic.com>
+M: Sudarsana Kalluru <sudarsana.kalluru@qlogic.com>
L: linux-scsi@vger.kernel.org
S: Supported
F: drivers/scsi/bfa/
@@ -2158,7 +2184,7 @@ F: Documentation/zh_CN/
CHIPIDEA USB HIGH SPEED DUAL ROLE CONTROLLER
M: Peter Chen <Peter.Chen@freescale.com>
-T: git://github.com/hzpeterchen/linux-usb.git
+T: git git://github.com/hzpeterchen/linux-usb.git
L: linux-usb@vger.kernel.org
S: Maintained
F: drivers/usb/chipidea/
@@ -2178,9 +2204,9 @@ S: Supported
F: drivers/net/ethernet/cisco/enic/
CISCO VIC LOW LATENCY NIC DRIVER
-M: Upinder Malhi <umalhi@cisco.com>
-S: Supported
-F: drivers/infiniband/hw/usnic
+M: Upinder Malhi <umalhi@cisco.com>
+S: Supported
+F: drivers/infiniband/hw/usnic
CIRRUS LOGIC EP93XX ETHERNET DRIVER
M: Hartley Sweeten <hsweeten@visionengravers.com>
@@ -2200,6 +2226,13 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Odd Fixes
F: sound/soc/codecs/cs4270*
+CIRRUS LOGIC AUDIO CODEC DRIVERS
+M: Brian Austin <brian.austin@cirrus.com>
+M: Paul Handrigan <Paul.Handrigan@cirrus.com>
+L: alsa-devel@alsa-project.org (moderated for non-subscribers)
+S: Maintained
+F: sound/soc/codecs/cs*
+
CLEANCACHE API
M: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
L: linux-kernel@vger.kernel.org
@@ -2367,7 +2400,7 @@ F: include/linux/cpufreq.h
CPU FREQUENCY DRIVERS - ARM BIG LITTLE
M: Viresh Kumar <viresh.kumar@linaro.org>
-M: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
+M: Sudeep Holla <sudeep.holla@arm.com>
L: cpufreq@vger.kernel.org
L: linux-pm@vger.kernel.org
W: http://www.arm.com/products/processors/technologies/biglittleprocessing.php
@@ -2377,20 +2410,20 @@ F: drivers/cpufreq/arm_big_little.c
F: drivers/cpufreq/arm_big_little_dt.c
CPUIDLE DRIVER - ARM BIG LITTLE
-M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
-M: Daniel Lezcano <daniel.lezcano@linaro.org>
-L: linux-pm@vger.kernel.org
-L: linux-arm-kernel@lists.infradead.org
-T: git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
-S: Maintained
-F: drivers/cpuidle/cpuidle-big_little.c
+M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+M: Daniel Lezcano <daniel.lezcano@linaro.org>
+L: linux-pm@vger.kernel.org
+L: linux-arm-kernel@lists.infradead.org
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
+S: Maintained
+F: drivers/cpuidle/cpuidle-big_little.c
CPUIDLE DRIVERS
M: Rafael J. Wysocki <rjw@rjwysocki.net>
M: Daniel Lezcano <daniel.lezcano@linaro.org>
L: linux-pm@vger.kernel.org
S: Maintained
-T: git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
F: drivers/cpuidle/*
F: include/linux/cpuidle.h
@@ -2408,8 +2441,10 @@ F: tools/power/cpupower/
CPUSETS
M: Li Zefan <lizefan@huawei.com>
+L: cgroups@vger.kernel.org
W: http://www.bullopensource.org/cpuset/
W: http://oss.sgi.com/projects/cpusets/
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
S: Maintained
F: Documentation/cgroups/cpusets.txt
F: include/linux/cpuset.h
@@ -2455,9 +2490,9 @@ S: Maintained
F: sound/pci/cs5535audio/
CW1200 WLAN driver
-M: Solomon Peachy <pizza@shaftnet.org>
-S: Maintained
-F: drivers/net/wireless/cw1200/
+M: Solomon Peachy <pizza@shaftnet.org>
+S: Maintained
+F: drivers/net/wireless/cw1200/
CX18 VIDEO4LINUX DRIVER
M: Andy Walls <awalls@md.metrocast.net>
@@ -2608,9 +2643,9 @@ DC395x SCSI driver
M: Oliver Neukum <oliver@neukum.org>
M: Ali Akcaagac <aliakc@web.de>
M: Jamie Lenehan <lenehan@twibble.org>
-W: http://twibble.org/dist/dc395x/
L: dc395x@twibble.org
-L: http://lists.twibble.org/mailman/listinfo/dc395x/
+W: http://twibble.org/dist/dc395x/
+W: http://lists.twibble.org/mailman/listinfo/dc395x/
S: Maintained
F: Documentation/scsi/dc395x.txt
F: drivers/scsi/dc395x.*
@@ -2702,6 +2737,31 @@ F: include/linux/device-mapper.h
F: include/linux/dm-*.h
F: include/uapi/linux/dm-*.h
+DIALOG SEMICONDUCTOR DRIVERS
+M: Support Opensource <support.opensource@diasemi.com>
+W: http://www.dialog-semiconductor.com/products
+S: Supported
+F: Documentation/hwmon/da90??
+F: drivers/gpio/gpio-da90??.c
+F: drivers/hwmon/da90??-hwmon.c
+F: drivers/input/misc/da90??_onkey.c
+F: drivers/input/touchscreen/da9052_tsi.c
+F: drivers/leds/leds-da90??.c
+F: drivers/mfd/da903x.c
+F: drivers/mfd/da90??-*.c
+F: drivers/power/da9052-battery.c
+F: drivers/regulator/da903x.c
+F: drivers/regulator/da9???-regulator.[ch]
+F: drivers/rtc/rtc-da90??.c
+F: drivers/video/backlight/da90??_bl.c
+F: drivers/watchdog/da90??_wdt.c
+F: include/linux/mfd/da903x.h
+F: include/linux/mfd/da9052/
+F: include/linux/mfd/da9055/
+F: include/linux/mfd/da9063/
+F: include/sound/da[79]*.h
+F: sound/soc/codecs/da[79]*.[ch]
+
DIGI NEO AND CLASSIC PCI PRODUCTS
M: Lidza Louina <lidza.louina@gmail.com>
L: driverdev-devel@linuxdriverproject.org
@@ -2796,9 +2856,9 @@ S: Supported
F: drivers/acpi/dock.c
DOCUMENTATION
-M: Rob Landley <rob@landley.net>
+M: Randy Dunlap <rdunlap@infradead.org>
L: linux-doc@vger.kernel.org
-T: TBD
+T: quilt http://www.infradead.org/~rdunlap/Doc/patches/
S: Maintained
F: Documentation/
@@ -2845,19 +2905,29 @@ F: lib/kobj*
DRM DRIVERS
M: David Airlie <airlied@linux.ie>
L: dri-devel@lists.freedesktop.org
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git
+T: git git://people.freedesktop.org/~airlied/linux
S: Maintained
F: drivers/gpu/drm/
F: include/drm/
F: include/uapi/drm/
+RADEON DRM DRIVERS
+M: Alex Deucher <alexander.deucher@amd.com>
+M: Christian König <christian.koenig@amd.com>
+L: dri-devel@lists.freedesktop.org
+T: git git://people.freedesktop.org/~agd5f/linux
+S: Supported
+F: drivers/gpu/drm/radeon/
+F: include/drm/radeon*
+F: include/uapi/drm/radeon*
+
INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
M: Daniel Vetter <daniel.vetter@ffwll.ch>
M: Jani Nikula <jani.nikula@linux.intel.com>
L: intel-gfx@lists.freedesktop.org
L: dri-devel@lists.freedesktop.org
Q: http://patchwork.freedesktop.org/project/intel-gfx/
-T: git git://people.freedesktop.org/~danvet/drm-intel
+T: git git://anongit.freedesktop.org/drm-intel
S: Supported
F: drivers/gpu/drm/i915/
F: include/drm/i915*
@@ -3082,6 +3152,8 @@ F: fs/ecryptfs/
EDAC-CORE
M: Doug Thompson <dougthompson@xmission.com>
+M: Borislav Petkov <bp@alien8.de>
+M: Mauro Carvalho Chehab <m.chehab@samsung.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Supported
@@ -3324,6 +3396,17 @@ S: Maintained
F: include/linux/netfilter_bridge/
F: net/bridge/
+ETHERNET PHY LIBRARY
+M: Florian Fainelli <f.fainelli@gmail.com>
+L: netdev@vger.kernel.org
+S: Maintained
+F: include/linux/phy.h
+F: include/linux/phy_fixed.h
+F: drivers/net/phy/
+F: Documentation/networking/phy.txt
+F: drivers/of/of_mdio.c
+F: drivers/of/of_net.c
+
EXT2 FILE SYSTEM
M: Jan Kara <jack@suse.cz>
L: linux-ext4@vger.kernel.org
@@ -3352,7 +3435,9 @@ F: Documentation/filesystems/ext4.txt
F: fs/ext4/
Extended Verification Module (EVM)
-M: Mimi Zohar <zohar@us.ibm.com>
+M: Mimi Zohar <zohar@linux.vnet.ibm.com>
+L: linux-ima-devel@lists.sourceforge.net
+L: linux-security-module@vger.kernel.org
S: Supported
F: security/integrity/evm/
@@ -3436,7 +3521,8 @@ F: include/scsi/libfcoe.h
F: include/uapi/scsi/fc/
FILE LOCKING (flock() and fcntl()/lockf())
-M: Matthew Wilcox <matthew@wil.cx>
+M: Jeff Layton <jlayton@redhat.com>
+M: J. Bruce Fields <bfields@fieldses.org>
L: linux-fsdevel@vger.kernel.org
S: Maintained
F: include/linux/fcntl.h
@@ -3629,8 +3715,8 @@ S: Maintained
F: fs/freevxfs/
FREEZER
-M: Pavel Machek <pavel@ucw.cz>
M: "Rafael J. Wysocki" <rjw@rjwysocki.net>
+M: Pavel Machek <pavel@ucw.cz>
L: linux-pm@vger.kernel.org
S: Supported
F: Documentation/power/freezing-of-tasks.txt
@@ -3994,8 +4080,8 @@ S: Maintained
F: drivers/video/hgafb.c
HIBERNATION (aka Software Suspend, aka swsusp)
-M: Pavel Machek <pavel@ucw.cz>
M: "Rafael J. Wysocki" <rjw@rjwysocki.net>
+M: Pavel Machek <pavel@ucw.cz>
L: linux-pm@vger.kernel.org
S: Supported
F: arch/x86/power/
@@ -4077,8 +4163,7 @@ F: include/linux/hpet.h
F: include/uapi/linux/hpet.h
HPET: x86
-M: "Venkatesh Pallipadi (Venki)" <venki@google.com>
-S: Maintained
+S: Orphan
F: arch/x86/kernel/hpet.c
F: arch/x86/include/asm/hpet.h
@@ -4374,8 +4459,11 @@ S: Maintained
F: drivers/ipack/
INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
-M: Mimi Zohar <zohar@us.ibm.com>
+M: Mimi Zohar <zohar@linux.vnet.ibm.com>
M: Dmitry Kasatkin <d.kasatkin@samsung.com>
+L: linux-ima-devel@lists.sourceforge.net
+L: linux-ima-user@lists.sourceforge.net
+L: linux-security-module@vger.kernel.org
S: Supported
F: security/integrity/ima/
@@ -4517,6 +4605,7 @@ M: Greg Rose <gregory.v.rose@intel.com>
M: Alex Duyck <alexander.h.duyck@intel.com>
M: John Ronciak <john.ronciak@intel.com>
M: Mitch Williams <mitch.a.williams@intel.com>
+M: Linux NICS <linux.nics@intel.com>
L: e1000-devel@lists.sourceforge.net
W: http://www.intel.com/support/feedback.htm
W: http://e1000.sourceforge.net/
@@ -4534,6 +4623,7 @@ F: Documentation/networking/ixgbevf.txt
F: Documentation/networking/i40e.txt
F: Documentation/networking/i40evf.txt
F: drivers/net/ethernet/intel/
+F: drivers/net/ethernet/intel/*/
INTEL-MID GPIO DRIVER
M: David Cohen <david.a.cohen@linux.intel.com>
@@ -4564,7 +4654,7 @@ F: arch/x86/kernel/tboot.c
INTEL WIRELESS WIMAX CONNECTION 2400
M: Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
M: linux-wimax@intel.com
-L: wimax@linuxwimax.org
+L: wimax@linuxwimax.org (subscribers-only)
S: Supported
W: http://linuxwimax.org
F: Documentation/wimax/README.i2400m
@@ -4771,22 +4861,6 @@ F: Documentation/hwmon/it87
F: drivers/hwmon/it87.c
IT913X MEDIA DRIVER
-M: Malcolm Priestley <tvboxspy@gmail.com>
-L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
-Q: http://patchwork.linuxtv.org/project/linux-media/list/
-S: Maintained
-F: drivers/media/usb/dvb-usb-v2/it913x*
-
-IT913X FE MEDIA DRIVER
-M: Malcolm Priestley <tvboxspy@gmail.com>
-L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
-Q: http://patchwork.linuxtv.org/project/linux-media/list/
-S: Maintained
-F: drivers/media/dvb-frontends/it913x-fe*
-
-IT913X MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
W: http://linuxtv.org/
@@ -4890,7 +4964,7 @@ F: drivers/staging/ktap/
KCONFIG
M: "Yann E. MORIN" <yann.morin.1998@free.fr>
L: linux-kbuild@vger.kernel.org
-T: git://gitorious.org/linux-kconfig/linux-kconfig
+T: git git://gitorious.org/linux-kconfig/linux-kconfig
S: Maintained
F: Documentation/kbuild/kconfig-language.txt
F: scripts/kconfig/
@@ -5041,8 +5115,8 @@ F: include/keys/
F: security/keys/
KEYS-TRUSTED
-M: David Safford <safford@watson.ibm.com>
-M: Mimi Zohar <zohar@us.ibm.com>
+M: David Safford <safford@us.ibm.com>
+M: Mimi Zohar <zohar@linux.vnet.ibm.com>
L: linux-security-module@vger.kernel.org
L: keyrings@linux-nfs.org
S: Supported
@@ -5052,8 +5126,8 @@ F: security/keys/trusted.c
F: security/keys/trusted.h
KEYS-ENCRYPTED
-M: Mimi Zohar <zohar@us.ibm.com>
-M: David Safford <safford@watson.ibm.com>
+M: Mimi Zohar <zohar@linux.vnet.ibm.com>
+M: David Safford <safford@us.ibm.com>
L: linux-security-module@vger.kernel.org
L: keyrings@linux-nfs.org
S: Supported
@@ -5216,11 +5290,10 @@ F: arch/powerpc/platforms/512x/
F: arch/powerpc/platforms/52xx/
LINUX FOR POWERPC EMBEDDED PPC4XX
-M: Josh Boyer <jwboyer@gmail.com>
+M: Alistair Popple <alistair@popple.id.au>
M: Matt Porter <mporter@kernel.crashing.org>
W: http://www.penguinppc.org/
L: linuxppc-dev@lists.ozlabs.org
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/jwboyer/powerpc-4xx.git
S: Maintained
F: arch/powerpc/platforms/40x/
F: arch/powerpc/platforms/44x/
@@ -5447,11 +5520,11 @@ S: Maintained
F: drivers/media/tuners/m88ts2022*
MA901 MASTERKIT USB FM RADIO DRIVER
-M: Alexey Klimov <klimov.linux@gmail.com>
-L: linux-media@vger.kernel.org
-T: git git://linuxtv.org/media_tree.git
-S: Maintained
-F: drivers/media/radio/radio-ma901.c
+M: Alexey Klimov <klimov.linux@gmail.com>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+S: Maintained
+F: drivers/media/radio/radio-ma901.c
MAC80211
M: Johannes Berg <johannes@sipsolutions.net>
@@ -5487,6 +5560,11 @@ W: http://www.kernel.org/doc/man-pages
L: linux-man@vger.kernel.org
S: Maintained
+MARVELL ARMADA DRM SUPPORT
+M: Russell King <rmk+kernel@arm.linux.org.uk>
+S: Maintained
+F: drivers/gpu/drm/armada/
+
MARVELL GIGABIT ETHERNET DRIVERS (skge/sky2)
M: Mirko Lindner <mlindner@marvell.com>
M: Stephen Hemminger <stephen@networkplumber.org>
@@ -5607,7 +5685,7 @@ F: drivers/scsi/megaraid/
MELLANOX ETHERNET DRIVER (mlx4_en)
M: Amir Vadai <amirv@mellanox.com>
-L: netdev@vger.kernel.org
+L: netdev@vger.kernel.org
S: Supported
W: http://www.mellanox.com
Q: http://patchwork.ozlabs.org/project/netdev/list/
@@ -5648,11 +5726,17 @@ F: include/linux/mtd/
F: include/uapi/mtd/
MEN A21 WATCHDOG DRIVER
-M: Johannes Thumshirn <johannes.thumshirn@men.de>
+M: Johannes Thumshirn <johannes.thumshirn@men.de>
L: linux-watchdog@vger.kernel.org
S: Supported
F: drivers/watchdog/mena21_wdt.c
+MEN CHAMELEON BUS (mcb)
+M: Johannes Thumshirn <johannes.thumshirn@men.de>
+S: Supported
+F: drivers/mcb/
+F: include/linux/mcb.h
+
METAG ARCHITECTURE
M: James Hogan <james.hogan@imgtec.com>
L: linux-metag@vger.kernel.org
@@ -5668,7 +5752,6 @@ F: fs/imgdafs/
MICROBLAZE ARCHITECTURE
M: Michal Simek <monstr@monstr.eu>
-L: microblaze-uclinux@itee.uq.edu.au (moderated for non-subscribers)
W: http://www.monstr.eu/fdt/
T: git git://git.monstr.eu/linux-2.6-microblaze.git
S: Supported
@@ -5704,20 +5787,20 @@ L: linux-rdma@vger.kernel.org
W: http://www.mellanox.com
Q: http://patchwork.ozlabs.org/project/netdev/list/
Q: http://patchwork.kernel.org/project/linux-rdma/list/
-T: git://openfabrics.org/~eli/connect-ib.git
+T: git git://openfabrics.org/~eli/connect-ib.git
S: Supported
F: drivers/net/ethernet/mellanox/mlx5/core/
F: include/linux/mlx5/
Mellanox MLX5 IB driver
-M: Eli Cohen <eli@mellanox.com>
-L: linux-rdma@vger.kernel.org
-W: http://www.mellanox.com
-Q: http://patchwork.kernel.org/project/linux-rdma/list/
-T: git://openfabrics.org/~eli/connect-ib.git
-S: Supported
-F: include/linux/mlx5/
-F: drivers/infiniband/hw/mlx5/
+M: Eli Cohen <eli@mellanox.com>
+L: linux-rdma@vger.kernel.org
+W: http://www.mellanox.com
+Q: http://patchwork.kernel.org/project/linux-rdma/list/
+T: git git://openfabrics.org/~eli/connect-ib.git
+S: Supported
+F: include/linux/mlx5/
+F: drivers/infiniband/hw/mlx5/
MODULE SUPPORT
M: Rusty Russell <rusty@rustcorp.com.au>
@@ -5757,6 +5840,26 @@ L: platform-driver-x86@vger.kernel.org
S: Supported
F: drivers/platform/x86/msi-wmi.c
+MSI001 MEDIA DRIVER
+M: Antti Palosaari <crope@iki.fi>
+L: linux-media@vger.kernel.org
+W: http://linuxtv.org/
+W: http://palosaari.fi/linux/
+Q: http://patchwork.linuxtv.org/project/linux-media/list/
+T: git git://linuxtv.org/anttip/media_tree.git
+S: Maintained
+F: drivers/staging/media/msi3101/msi001*
+
+MSI3101 MEDIA DRIVER
+M: Antti Palosaari <crope@iki.fi>
+L: linux-media@vger.kernel.org
+W: http://linuxtv.org/
+W: http://palosaari.fi/linux/
+Q: http://patchwork.linuxtv.org/project/linux-media/list/
+T: git git://linuxtv.org/anttip/media_tree.git
+S: Maintained
+F: drivers/staging/media/msi3101/sdr-msi3101*
+
MT9M032 APTINA SENSOR DRIVER
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
L: linux-media@vger.kernel.org
@@ -5969,6 +6072,9 @@ F: include/linux/netdevice.h
F: include/uapi/linux/in.h
F: include/uapi/linux/net.h
F: include/uapi/linux/netdevice.h
+F: tools/net/
+F: tools/testing/selftests/net/
+F: lib/random32.c
NETWORKING [IPv4/IPv6]
M: "David S. Miller" <davem@davemloft.net>
@@ -5992,6 +6098,7 @@ L: netdev@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next.git
S: Maintained
+F: net/core/flow.c
F: net/xfrm/
F: net/key/
F: net/ipv4/xfrm*
@@ -6067,6 +6174,7 @@ F: include/net/nfc/
F: include/uapi/linux/nfc.h
F: drivers/nfc/
F: include/linux/platform_data/pn544.h
+F: Documentation/devicetree/bindings/net/nfc/
NFS, SUNRPC, AND LOCKD CLIENTS
M: Trond Myklebust <trond.myklebust@primarydata.com>
@@ -6085,10 +6193,10 @@ F: include/uapi/linux/nfs*
F: include/uapi/linux/sunrpc/
NILFS2 FILESYSTEM
-M: KONISHI Ryusuke <konishi.ryusuke@lab.ntt.co.jp>
+M: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
L: linux-nilfs@vger.kernel.org
-W: http://www.nilfs.org/en/
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/ryusuke/nilfs2.git
+W: http://nilfs.sourceforge.net/
+T: git git://github.com/konis/nilfs2.git
S: Supported
F: Documentation/filesystems/nilfs2.txt
F: fs/nilfs2/
@@ -6142,6 +6250,12 @@ S: Supported
F: drivers/block/nvme*
F: include/linux/nvme.h
+NXP TDA998X DRM DRIVER
+M: Russell King <rmk+kernel@arm.linux.org.uk>
+S: Supported
+F: drivers/gpu/drm/i2c/tda998x_drv.c
+F: include/drm/i2c/tda998x.h
+
OMAP SUPPORT
M: Tony Lindgren <tony@atomide.com>
L: linux-omap@vger.kernel.org
@@ -7020,13 +7134,8 @@ F: Documentation/networking/LICENSE.qla3xxx
F: drivers/net/ethernet/qlogic/qla3xxx.*
QLOGIC QLCNIC (1/10)Gb ETHERNET DRIVER
-M: Himanshu Madhani <himanshu.madhani@qlogic.com>
-M: Rajesh Borundia <rajesh.borundia@qlogic.com>
M: Shahed Shaikh <shahed.shaikh@qlogic.com>
-M: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
-M: Sony Chacko <sony.chacko@qlogic.com>
-M: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
-M: linux-driver@qlogic.com
+M: Dept-HSGLinuxNICDev@qlogic.com
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/ethernet/qlogic/qlcnic/
@@ -7196,7 +7305,7 @@ S: Maintained
F: drivers/net/ethernet/rdc/r6040.c
RDS - RELIABLE DATAGRAM SOCKETS
-M: Venkat Venkatsubra <venkat.x.venkatsubra@oracle.com>
+M: Chien Yen <chien.yen@oracle.com>
L: rds-devel@oss.oracle.com (moderated for non-subscribers)
S: Supported
F: net/rds/
@@ -7318,6 +7427,16 @@ T: git git://linuxtv.org/anttip/media_tree.git
S: Maintained
F: drivers/media/dvb-frontends/rtl2832*
+RTL2832_SDR MEDIA DRIVER
+M: Antti Palosaari <crope@iki.fi>
+L: linux-media@vger.kernel.org
+W: http://linuxtv.org/
+W: http://palosaari.fi/linux/
+Q: http://patchwork.linuxtv.org/project/linux-media/list/
+T: git git://linuxtv.org/anttip/media_tree.git
+S: Maintained
+F: drivers/staging/media/rtl2832u_sdr/rtl2832_sdr*
+
RTL8180 WIRELESS DRIVER
M: "John W. Linville" <linville@tuxdriver.com>
L: linux-wireless@vger.kernel.org
@@ -7361,10 +7480,26 @@ W: http://www.ibm.com/developerworks/linux/linux390/
S: Supported
F: arch/s390/
F: drivers/s390/
-F: block/partitions/ibm.c
F: Documentation/s390/
F: Documentation/DocBook/s390*
+S390 COMMON I/O LAYER
+M: Sebastian Ott <sebott@linux.vnet.ibm.com>
+M: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+L: linux-s390@vger.kernel.org
+W: http://www.ibm.com/developerworks/linux/linux390/
+S: Supported
+F: drivers/s390/cio/
+
+S390 DASD DRIVER
+M: Stefan Weinhuber <wein@de.ibm.com>
+M: Stefan Haberland <stefan.haberland@de.ibm.com>
+L: linux-s390@vger.kernel.org
+W: http://www.ibm.com/developerworks/linux/linux390/
+S: Supported
+F: drivers/s390/block/dasd*
+F: block/partitions/ibm.c
+
S390 NETWORK DRIVERS
M: Ursula Braun <ursula.braun@de.ibm.com>
M: Frank Blaschka <blaschka@linux.vnet.ibm.com>
@@ -7374,6 +7509,15 @@ W: http://www.ibm.com/developerworks/linux/linux390/
S: Supported
F: drivers/s390/net/
+S390 PCI SUBSYSTEM
+M: Sebastian Ott <sebott@linux.vnet.ibm.com>
+M: Gerald Schaefer <gerald.schaefer@de.ibm.com>
+L: linux-s390@vger.kernel.org
+W: http://www.ibm.com/developerworks/linux/linux390/
+S: Supported
+F: arch/s390/pci/
+F: drivers/pci/hotplug/s390_pci_hpc.c
+
S390 ZCRYPT DRIVER
M: Ingo Tuchscherer <ingo.tuchscherer@de.ibm.com>
M: linux390@de.ibm.com
@@ -7497,6 +7641,15 @@ S: Supported
L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
F: drivers/clk/samsung/
+SAMSUNG SXGBE DRIVERS
+M: Byungho An <bh74.an@samsung.com>
+M: Girish K S <ks.giri@samsung.com>
+M: Siva Reddy Kallam <siva.kallam@samsung.com>
+M: Vipul Pandya <vipul.pandya@samsung.com>
+S: Supported
+L: netdev@vger.kernel.org
+F: drivers/net/ethernet/samsung/sxgbe/
+
SERIAL DRIVERS
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
L: linux-serial@vger.kernel.org
@@ -7686,11 +7839,10 @@ M: Security Officers <security@kernel.org>
S: Supported
SELINUX SECURITY MODULE
+M: Paul Moore <paul@paul-moore.com>
M: Stephen Smalley <sds@tycho.nsa.gov>
-M: James Morris <james.l.morris@oracle.com>
M: Eric Paris <eparis@parisplace.org>
-M: Paul Moore <paul@paul-moore.com>
-L: selinux@tycho.nsa.gov (subscribers-only, general discussion)
+L: selinux@tycho.nsa.gov (moderated for non-subscribers)
W: http://selinuxproject.org
T: git git://git.infradead.org/users/pcmoore/selinux
S: Supported
@@ -7757,13 +7909,6 @@ F: Documentation/ia64/serial.txt
F: drivers/tty/serial/ioc?_serial.c
F: include/linux/ioc?.h
-SGI VISUAL WORKSTATION 320 AND 540
-M: Andrey Panin <pazke@donpac.ru>
-L: linux-visws-devel@lists.sf.net
-W: http://linux-visws.sf.net
-S: Maintained for 2.6.
-F: Documentation/sgi-visws.txt
-
SGI XP/XPC/XPNET DRIVER
M: Cliff Whickman <cpw@sgi.com>
M: Robin Holt <robinmholt@gmail.com>
@@ -7824,15 +7969,13 @@ F: drivers/media/usb/siano/
F: drivers/media/mmc/siano/
SH_VEU V4L2 MEM2MEM DRIVER
-M: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
L: linux-media@vger.kernel.org
-S: Maintained
+S: Orphan
F: drivers/media/platform/sh_veu.c
SH_VOU V4L2 OUTPUT DRIVER
-M: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
L: linux-media@vger.kernel.org
-S: Odd Fixes
+S: Orphan
F: drivers/media/platform/sh_vou.c
F: include/media/sh_vou.h
@@ -8311,6 +8454,12 @@ M: Teddy Wang <teddy.wang@siliconmotion.com.cn>
S: Odd Fixes
F: drivers/staging/sm7xxfb/
+STAGING - SLICOSS
+M: Lior Dotan <liodot@gmail.com>
+M: Christopher Harrer <charrer@alacritech.com>
+S: Odd Fixes
+F: drivers/staging/slicoss/
+
STAGING - SOFTLOGIC 6x10 MPEG CODEC
M: Ismael Luceno <ismael.luceno@corp.bluecherry.net>
S: Supported
@@ -8372,20 +8521,18 @@ S: Maintained
F: drivers/net/ethernet/dlink/sundance.c
SUPERH
-M: Paul Mundt <lethal@linux-sh.org>
L: linux-sh@vger.kernel.org
W: http://www.linux-sh.org
Q: http://patchwork.kernel.org/project/linux-sh/list/
-T: git git://github.com/pmundt/linux-sh.git sh-latest
-S: Supported
+S: Orphan
F: Documentation/sh/
F: arch/sh/
F: drivers/sh/
SUSPEND TO RAM
+M: "Rafael J. Wysocki" <rjw@rjwysocki.net>
M: Len Brown <len.brown@intel.com>
M: Pavel Machek <pavel@ucw.cz>
-M: "Rafael J. Wysocki" <rjw@rjwysocki.net>
L: linux-pm@vger.kernel.org
S: Supported
F: Documentation/power/
@@ -8429,8 +8576,8 @@ TARGET SUBSYSTEM
M: Nicholas A. Bellinger <nab@linux-iscsi.org>
L: linux-scsi@vger.kernel.org
L: target-devel@vger.kernel.org
-L: http://groups.google.com/group/linux-iscsi-target-dev
W: http://www.linux-iscsi.org
+W: http://groups.google.com/group/linux-iscsi-target-dev
T: git git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git master
S: Supported
F: drivers/target/
@@ -8661,6 +8808,7 @@ M: Max Filippov <jcmvbkbc@gmail.com>
L: linux-xtensa@linux-xtensa.org
S: Maintained
F: arch/xtensa/
+F: drivers/irqchip/irq-xtensa-*
THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
@@ -8671,17 +8819,17 @@ S: Maintained
F: drivers/media/radio/radio-raremono.c
THERMAL
-M: Zhang Rui <rui.zhang@intel.com>
-M: Eduardo Valentin <eduardo.valentin@ti.com>
-L: linux-pm@vger.kernel.org
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux.git
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal.git
-Q: https://patchwork.kernel.org/project/linux-pm/list/
-S: Supported
-F: drivers/thermal/
-F: include/linux/thermal.h
-F: include/linux/cpu_cooling.h
-F: Documentation/devicetree/bindings/thermal/
+M: Zhang Rui <rui.zhang@intel.com>
+M: Eduardo Valentin <eduardo.valentin@ti.com>
+L: linux-pm@vger.kernel.org
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal.git
+Q: https://patchwork.kernel.org/project/linux-pm/list/
+S: Supported
+F: drivers/thermal/
+F: include/linux/thermal.h
+F: include/linux/cpu_cooling.h
+F: Documentation/devicetree/bindings/thermal/
THINGM BLINK(1) USB RGB LED DRIVER
M: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
@@ -8996,6 +9144,13 @@ F: drivers/cdrom/cdrom.c
F: include/linux/cdrom.h
F: include/uapi/linux/cdrom.h
+UNISYS S-PAR DRIVERS
+M: Benjamin Romer <benjamin.romer@unisys.com>
+M: David Kershner <david.kershner@unisys.com>
+L: sparmaintainer@unisys.com (Unisys internal)
+S: Supported
+F: drivers/staging/unisys/
+
UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER
M: Vinayak Holikatti <vinholikatti@gmail.com>
M: Santosh Y <santoshsy@gmail.com>
@@ -9034,8 +9189,7 @@ S: Maintained
F: drivers/net/wireless/ath/ar5523/
USB ATTACHED SCSI
-M: Matthew Wilcox <willy@linux.intel.com>
-M: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+M: Hans de Goede <hdegoede@redhat.com>
M: Gerd Hoffmann <kraxel@redhat.com>
L: linux-usb@vger.kernel.org
L: linux-scsi@vger.kernel.org
@@ -9261,7 +9415,7 @@ S: Maintained
F: drivers/net/wireless/rndis_wlan.c
USB XHCI DRIVER
-M: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+M: Mathias Nyman <mathias.nyman@intel.com>
L: linux-usb@vger.kernel.org
S: Supported
F: drivers/usb/host/xhci*
@@ -9345,7 +9499,6 @@ F: include/media/videobuf2-*
VIRTIO CONSOLE DRIVER
M: Amit Shah <amit.shah@redhat.com>
-L: virtio-dev@lists.oasis-open.org
L: virtualization@lists.linux-foundation.org
S: Maintained
F: drivers/char/virtio_console.c
@@ -9355,7 +9508,6 @@ F: include/uapi/linux/virtio_console.h
VIRTIO CORE, NET AND BLOCK DRIVERS
M: Rusty Russell <rusty@rustcorp.com.au>
M: "Michael S. Tsirkin" <mst@redhat.com>
-L: virtio-dev@lists.oasis-open.org
L: virtualization@lists.linux-foundation.org
S: Maintained
F: drivers/virtio/
@@ -9368,7 +9520,6 @@ F: include/uapi/linux/virtio_*.h
VIRTIO HOST (VHOST)
M: "Michael S. Tsirkin" <mst@redhat.com>
L: kvm@vger.kernel.org
-L: virtio-dev@lists.oasis-open.org
L: virtualization@lists.linux-foundation.org
L: netdev@vger.kernel.org
S: Maintained
@@ -9549,7 +9700,7 @@ F: drivers/media/rc/winbond-cir.c
WIMAX STACK
M: Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
M: linux-wimax@intel.com
-L: wimax@linuxwimax.org
+L: wimax@linuxwimax.org (subscribers-only)
S: Supported
W: http://linuxwimax.org
F: Documentation/wimax/README.wimax
@@ -9715,7 +9866,6 @@ F: drivers/xen/*swiotlb*
XFS FILESYSTEM
P: Silicon Graphics Inc
M: Dave Chinner <david@fromorbit.com>
-M: Ben Myers <bpm@sgi.com>
M: xfs@oss.sgi.com
L: xfs@oss.sgi.com
W: http://oss.sgi.com/projects/xfs
@@ -9740,6 +9890,12 @@ L: linux-serial@vger.kernel.org
S: Maintained
F: drivers/tty/serial/uartlite.c
+XTENSA XTFPGA PLATFORM SUPPORT
+M: Max Filippov <jcmvbkbc@gmail.com>
+L: linux-xtensa@linux-xtensa.org
+S: Maintained
+F: drivers/spi/spi-xtensa-xtfpga.c
+
YAM DRIVER FOR AX.25
M: Jean-Paul Roubelat <jpr@f6fbb.org>
L: linux-hams@vger.kernel.org
@@ -9784,7 +9940,7 @@ ZR36067 VIDEO FOR LINUX DRIVER
L: mjpeg-users@lists.sourceforge.net
L: linux-media@vger.kernel.org
W: http://mjpeg.sourceforge.net/driver-zoran/
-T: Mercurial http://linuxtv.org/hg/v4l-dvb
+T: hg http://linuxtv.org/hg/v4l-dvb
S: Odd Fixes
F: drivers/media/pci/zoran/
diff --git a/Makefile b/Makefile
index 933e1def6baf..00a933bb1f41 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 3
PATCHLEVEL = 14
SUBLEVEL = 0
-EXTRAVERSION = -rc2
+EXTRAVERSION =
NAME = Shuffling Zombie Juror
# *DOCUMENTATION*
@@ -605,10 +605,11 @@ endif
ifdef CONFIG_CC_STACKPROTECTOR_REGULAR
stackp-flag := -fstack-protector
ifeq ($(call cc-option, $(stackp-flag)),)
- $(warning Cannot use CONFIG_CC_STACKPROTECTOR: \
- -fstack-protector not supported by compiler))
+ $(warning Cannot use CONFIG_CC_STACKPROTECTOR_REGULAR: \
+ -fstack-protector not supported by compiler)
endif
-else ifdef CONFIG_CC_STACKPROTECTOR_STRONG
+else
+ifdef CONFIG_CC_STACKPROTECTOR_STRONG
stackp-flag := -fstack-protector-strong
ifeq ($(call cc-option, $(stackp-flag)),)
$(warning Cannot use CONFIG_CC_STACKPROTECTOR_STRONG: \
@@ -618,6 +619,7 @@ else
# Force off for distro compilers that enable stack protector by default.
stackp-flag := $(call cc-option, -fno-stack-protector)
endif
+endif
KBUILD_CFLAGS += $(stackp-flag)
# This warning generated too much noise in a regular build.
@@ -727,6 +729,13 @@ export KBUILD_IMAGE ?= vmlinux
export INSTALL_PATH ?= /boot
#
+# INSTALL_DTBS_PATH specifies a prefix for relocations required by build roots.
+# Like INSTALL_MOD_PATH, it isn't defined in the Makefile, but can be passed as
+# an argument if needed. Otherwise it defaults to the kernel install path
+#
+export INSTALL_DTBS_PATH ?= $(INSTALL_PATH)/dtbs/$(KERNELRELEASE)
+
+#
# INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory
# relocations required by build roots. This is not defined in the
# makefile but the argument can be passed to make if needed.
diff --git a/arch/alpha/include/asm/Kbuild b/arch/alpha/include/asm/Kbuild
index a73a8e208a4a..96e54bed5088 100644
--- a/arch/alpha/include/asm/Kbuild
+++ b/arch/alpha/include/asm/Kbuild
@@ -1,7 +1,9 @@
-generic-y += clkdev.h
+generic-y += clkdev.h
+generic-y += cputime.h
generic-y += exec.h
-generic-y += trace_clock.h
-generic-y += preempt.h
generic-y += hash.h
+generic-y += mcs_spinlock.h
+generic-y += preempt.h
+generic-y += trace_clock.h
diff --git a/arch/alpha/include/asm/cputime.h b/arch/alpha/include/asm/cputime.h
deleted file mode 100644
index 19577fd93230..000000000000
--- a/arch/alpha/include/asm/cputime.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ALPHA_CPUTIME_H
-#define __ALPHA_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __ALPHA_CPUTIME_H */
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index edb4e0097b75..076c35cd6cde 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -254,12 +254,6 @@ void pcibios_fixup_bus(struct pci_bus *bus)
}
}
-int
-pcibios_enable_device(struct pci_dev *dev, int mask)
-{
- return pci_enable_resources(dev, mask);
-}
-
/*
* If we set up a device for bus mastering, we need to check the latency
* timer as certain firmware forgets to set it properly, as seen
diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index 9be30c8cb0c2..75de197a2fef 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -356,7 +356,6 @@ config ARC_CURR_IN_REG
config ARC_MISALIGN_ACCESS
bool "Emulate unaligned memory access (userspace only)"
- default N
select SYSCTL_ARCH_UNALIGN_NO_WARN
select SYSCTL_ARCH_UNALIGN_ALLOW
help
diff --git a/arch/arc/include/asm/Kbuild b/arch/arc/include/asm/Kbuild
index 0d3362991c31..e76fd79f32b0 100644
--- a/arch/arc/include/asm/Kbuild
+++ b/arch/arc/include/asm/Kbuild
@@ -1,15 +1,15 @@
generic-y += auxvec.h
generic-y += barrier.h
-generic-y += bugs.h
generic-y += bitsperlong.h
+generic-y += bugs.h
generic-y += clkdev.h
generic-y += cputime.h
generic-y += device.h
generic-y += div64.h
generic-y += emergency-restart.h
generic-y += errno.h
-generic-y += fcntl.h
generic-y += fb.h
+generic-y += fcntl.h
generic-y += ftrace.h
generic-y += hardirq.h
generic-y += hash.h
@@ -22,6 +22,7 @@ generic-y += kmap_types.h
generic-y += kvm_para.h
generic-y += local.h
generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += mman.h
generic-y += msgbuf.h
generic-y += param.h
@@ -30,6 +31,7 @@ generic-y += pci.h
generic-y += percpu.h
generic-y += poll.h
generic-y += posix_types.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += sembuf.h
@@ -48,4 +50,3 @@ generic-y += ucontext.h
generic-y += user.h
generic-y += vga.h
generic-y += xor.h
-generic-y += preempt.h
diff --git a/arch/arc/mm/cache_arc700.c b/arch/arc/mm/cache_arc700.c
index 6b58c1de7577..400c663b21c2 100644
--- a/arch/arc/mm/cache_arc700.c
+++ b/arch/arc/mm/cache_arc700.c
@@ -282,7 +282,7 @@ static inline void __cache_line_loop(unsigned long paddr, unsigned long vaddr,
#else
/* if V-P const for loop, PTAG can be written once outside loop */
if (full_page_op)
- write_aux_reg(ARC_REG_DC_PTAG, paddr);
+ write_aux_reg(aux_tag, paddr);
#endif
while (num_lines-- > 0) {
@@ -296,7 +296,7 @@ static inline void __cache_line_loop(unsigned long paddr, unsigned long vaddr,
write_aux_reg(aux_cmd, vaddr);
vaddr += L1_CACHE_BYTES;
#else
- write_aux_reg(aux, paddr);
+ write_aux_reg(aux_cmd, paddr);
paddr += L1_CACHE_BYTES;
#endif
}
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index e25419817791..503da0a2a8ea 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -534,7 +534,6 @@ config ARCH_DOVE
select PINCTRL
select PINCTRL_DOVE
select PLAT_ORION_LEGACY
- select USB_ARCH_HAS_EHCI
help
Support for the Marvell Dove SoC 88AP510
@@ -633,7 +632,6 @@ config ARCH_LPC32XX
select GENERIC_CLOCKEVENTS
select HAVE_IDE
select HAVE_PWM
- select USB_ARCH_HAS_OHCI
select USE_OF
help
Support for the NXP LPC32XX family of processors
@@ -770,7 +768,6 @@ config ARCH_S3C64XX
select SAMSUNG_ATAGS
select SAMSUNG_WAKEMASK
select SAMSUNG_WDT_RESET
- select USB_ARCH_HAS_OHCI
help
Samsung S3C64XX series based systems
@@ -1578,6 +1575,7 @@ config BL_SWITCHER_DUMMY_IF
choice
prompt "Memory split"
+ depends on MMU
default VMSPLIT_3G
help
Select the desired split between kernel and user memory.
@@ -1595,6 +1593,7 @@ endchoice
config PAGE_OFFSET
hex
+ default PHYS_OFFSET if !MMU
default 0x40000000 if VMSPLIT_1G
default 0x80000000 if VMSPLIT_2G
default 0xC0000000
@@ -1903,6 +1902,7 @@ config XEN
depends on ARM && AEABI && OF
depends on CPU_V7 && !CPU_V6
depends on !GENERIC_ATOMIC64
+ depends on MMU
select ARM_PSCI
select SWIOTLB_XEN
select ARCH_DMA_ADDR_T_64BIT
@@ -1918,6 +1918,7 @@ config USE_OF
select IRQ_DOMAIN
select OF
select OF_EARLY_FLATTREE
+ select OF_RESERVED_MEM
help
Include support for flattened device tree machine descriptions.
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 08a9ef58d9c3..fddf4beaee45 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -310,9 +310,9 @@ $(INSTALL_TARGETS):
%.dtb: | scripts
$(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $(boot)/dts/$@
-PHONY += dtbs
-dtbs: scripts
- $(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) dtbs
+PHONY += dtbs dtbs_install
+dtbs dtbs_install: prepare scripts
+ $(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $@
# We use MRPROPER_FILES and CLEAN_FILES now
archclean:
@@ -331,6 +331,7 @@ define archhelp
echo ' bootpImage - Combined zImage and initial RAM disk'
echo ' (supply initrd image via make variable INITRD=<path>)'
echo '* dtbs - Build device tree blobs for enabled boards'
+ echo ' dtbs_install - Install dtbs to $(INSTALL_DTBS_PATH)'
echo ' install - Install uncompressed kernel'
echo ' zinstall - Install compressed kernel'
echo ' uinstall - Install U-Boot wrapped compressed kernel'
diff --git a/arch/arm/boot/compressed/.gitignore b/arch/arm/boot/compressed/.gitignore
index 47279aa96a6a..0714e0334e33 100644
--- a/arch/arm/boot/compressed/.gitignore
+++ b/arch/arm/boot/compressed/.gitignore
@@ -1,4 +1,5 @@
ashldi3.S
+bswapsdi2.S
font.c
lib1funcs.S
hyp-stub.S
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index b9d6a8b485e0..d3cb0126a102 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -38,6 +38,7 @@ dtb-$(CONFIG_ARCH_AT91) += at91sam9g35ek.dtb
dtb-$(CONFIG_ARCH_AT91) += at91sam9x25ek.dtb
dtb-$(CONFIG_ARCH_AT91) += at91sam9x35ek.dtb
# sama5d3
+dtb-$(CONFIG_ARCH_AT91) += at91-sama5d3_xplained.dtb
dtb-$(CONFIG_ARCH_AT91) += sama5d31ek.dtb
dtb-$(CONFIG_ARCH_AT91) += sama5d33ek.dtb
dtb-$(CONFIG_ARCH_AT91) += sama5d34ek.dtb
@@ -208,7 +209,8 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \
omap3-n900.dtb \
omap3-n9.dtb \
omap3-n950.dtb \
- omap3-tobi.dtb \
+ omap3-overo-tobi.dtb \
+ omap3-overo-storm-tobi.dtb \
omap3-gta04.dtb \
omap3-igep0020.dtb \
omap3-igep0030.dtb \
@@ -321,7 +323,7 @@ dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb \
zynq-zc706.dtb \
zynq-zed.dtb
-targets += dtbs
+targets += dtbs dtbs_install
targets += $(dtb-y)
endif
@@ -331,3 +333,5 @@ dtbs: $(addprefix $(obj)/, $(dtb-y))
$(Q)rm -f $(obj)/../*.dtb
clean-files := *.dtb
+
+dtbs_install: $(addsuffix _dtbinst_, $(dtb-y))
diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts
index 4718ec4a4dbf..486880b74831 100644
--- a/arch/arm/boot/dts/am335x-evmsk.dts
+++ b/arch/arm/boot/dts/am335x-evmsk.dts
@@ -121,7 +121,7 @@
ti,model = "AM335x-EVMSK";
ti,audio-codec = <&tlv320aic3106>;
ti,mcasp-controller = <&mcasp1>;
- ti,codec-clock-rate = <24576000>;
+ ti,codec-clock-rate = <24000000>;
ti,audio-routing =
"Headphone Jack", "HPLOUT",
"Headphone Jack", "HPROUT";
@@ -256,6 +256,12 @@
>;
};
+ mmc1_pins: pinmux_mmc1_pins {
+ pinctrl-single,pins = <
+ 0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
+ >;
+ };
+
mcasp1_pins: mcasp1_pins {
pinctrl-single,pins = <
0x10c (PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_crs.mcasp1_aclkx */
@@ -456,6 +462,9 @@
status = "okay";
vmmc-supply = <&vmmc_reg>;
bus-width = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins>;
+ cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
};
&sham {
diff --git a/arch/arm/boot/dts/armada-xp-mv78260.dtsi b/arch/arm/boot/dts/armada-xp-mv78260.dtsi
index 66609684d41b..9480cf891f8c 100644
--- a/arch/arm/boot/dts/armada-xp-mv78260.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78260.dtsi
@@ -23,6 +23,7 @@
gpio0 = &gpio0;
gpio1 = &gpio1;
gpio2 = &gpio2;
+ eth3 = &eth3;
};
cpus {
@@ -291,7 +292,7 @@
interrupts = <91>;
};
- ethernet@34000 {
+ eth3: ethernet@34000 {
compatible = "marvell,armada-370-neta";
reg = <0x34000 0x4000>;
interrupts = <14>;
diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/at91-sama5d3_xplained.dts
new file mode 100644
index 000000000000..ce1375595e5f
--- /dev/null
+++ b/arch/arm/boot/dts/at91-sama5d3_xplained.dts
@@ -0,0 +1,229 @@
+/*
+ * at91-sama5d3_xplained.dts - Device Tree file for the SAMA5D3 Xplained board
+ *
+ * Copyright (C) 2014 Atmel,
+ * 2014 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/dts-v1/;
+#include "sama5d36.dtsi"
+
+/ {
+ model = "SAMA5D3 Xplained";
+ compatible = "atmel,sama5d3-xplained", "atmel,sama5d3", "atmel,sama5";
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ };
+
+ memory {
+ reg = <0x20000000 0x10000000>;
+ };
+
+ ahb {
+ apb {
+ mmc0: mmc@f0000000 {
+ pinctrl-0 = <&pinctrl_mmc0_clk_cmd_dat0 &pinctrl_mmc0_dat1_3 &pinctrl_mmc0_dat4_7 &pinctrl_mmc0_cd>;
+ status = "okay";
+ slot@0 {
+ reg = <0>;
+ bus-width = <8>;
+ cd-gpios = <&pioE 0 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ spi0: spi@f0004000 {
+ cs-gpios = <&pioD 13 0>;
+ status = "okay";
+ };
+
+ can0: can@f000c000 {
+ status = "okay";
+ };
+
+ i2c0: i2c@f0014000 {
+ status = "okay";
+ };
+
+ i2c1: i2c@f0018000 {
+ status = "okay";
+ };
+
+ macb0: ethernet@f0028000 {
+ phy-mode = "rgmii";
+ status = "okay";
+ };
+
+ usart0: serial@f001c000 {
+ status = "okay";
+ };
+
+ usart1: serial@f0020000 {
+ pinctrl-0 = <&pinctrl_usart1 &pinctrl_usart1_rts_cts>;
+ status = "okay";
+ };
+
+ uart0: serial@f0024000 {
+ status = "okay";
+ };
+
+ mmc1: mmc@f8000000 {
+ pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3 &pinctrl_mmc1_cd>;
+ status = "okay";
+ slot@0 {
+ reg = <0>;
+ bus-width = <4>;
+ cd-gpios = <&pioE 1 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+ spi1: spi@f8008000 {
+ cs-gpios = <&pioC 25 0>, <0>, <0>, <&pioD 16 0>;
+ status = "okay";
+ };
+
+ adc0: adc@f8018000 {
+ pinctrl-0 = <
+ &pinctrl_adc0_adtrg
+ &pinctrl_adc0_ad0
+ &pinctrl_adc0_ad1
+ &pinctrl_adc0_ad2
+ &pinctrl_adc0_ad3
+ &pinctrl_adc0_ad4
+ &pinctrl_adc0_ad5
+ &pinctrl_adc0_ad6
+ &pinctrl_adc0_ad7
+ &pinctrl_adc0_ad8
+ &pinctrl_adc0_ad9
+ >;
+ status = "okay";
+ };
+
+ i2c2: i2c@f801c000 {
+ dmas = <0>, <0>; /* Do not use DMA for i2c2 */
+ status = "okay";
+ };
+
+ macb1: ethernet@f802c000 {
+ phy-mode = "rmii";
+ status = "okay";
+ };
+
+ dbgu: serial@ffffee00 {
+ status = "okay";
+ };
+
+ pinctrl@fffff200 {
+ board {
+ pinctrl_mmc0_cd: mmc0_cd {
+ atmel,pins =
+ <AT91_PIOE 0 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>;
+ };
+
+ pinctrl_mmc1_cd: mmc1_cd {
+ atmel,pins =
+ <AT91_PIOE 1 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>;
+ };
+
+ pinctrl_usba_vbus: usba_vbus {
+ atmel,pins =
+ <AT91_PIOE 9 AT91_PERIPH_GPIO AT91_PINCTRL_DEGLITCH>; /* PE9, conflicts with A9 */
+ };
+ };
+ };
+
+ pmc: pmc@fffffc00 {
+ main: mainck {
+ clock-frequency = <12000000>;
+ };
+ };
+ };
+
+ nand0: nand@60000000 {
+ nand-bus-width = <8>;
+ nand-ecc-mode = "hw";
+ atmel,has-pmecc;
+ atmel,pmecc-cap = <4>;
+ atmel,pmecc-sector-size = <512>;
+ nand-on-flash-bbt;
+ status = "okay";
+
+ at91bootstrap@0 {
+ label = "at91bootstrap";
+ reg = <0x0 0x40000>;
+ };
+
+ bootloader@40000 {
+ label = "bootloader";
+ reg = <0x40000 0x80000>;
+ };
+
+ bootloaderenv@c0000 {
+ label = "bootloader env";
+ reg = <0xc0000 0xc0000>;
+ };
+
+ dtb@180000 {
+ label = "device tree";
+ reg = <0x180000 0x80000>;
+ };
+
+ kernel@200000 {
+ label = "kernel";
+ reg = <0x200000 0x600000>;
+ };
+
+ rootfs@800000 {
+ label = "rootfs";
+ reg = <0x800000 0x0f800000>;
+ };
+ };
+
+ usb0: gadget@00500000 {
+ atmel,vbus-gpio = <&pioE 9 GPIO_ACTIVE_HIGH>; /* PE9, conflicts with A9 */
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usba_vbus>;
+ status = "okay";
+ };
+
+ usb1: ohci@00600000 {
+ num-ports = <3>;
+ atmel,vbus-gpio = <0
+ &pioE 3 GPIO_ACTIVE_LOW
+ &pioE 4 GPIO_ACTIVE_LOW
+ >;
+ status = "okay";
+ };
+
+ usb2: ehci@00700000 {
+ status = "okay";
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+
+ bp3 {
+ label = "PB_USER";
+ gpios = <&pioE 29 GPIO_ACTIVE_LOW>;
+ linux,code = <0x104>;
+ gpio-key,wakeup;
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ d2 {
+ label = "d2";
+ gpios = <&pioE 23 GPIO_ACTIVE_LOW>; /* PE23, conflicts with A23, CTS2 */
+ linux,default-trigger = "heartbeat";
+ };
+
+ d3 {
+ label = "d3";
+ gpios = <&pioE 24 GPIO_ACTIVE_HIGH>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
index 0042f73068b0..fece8665fb63 100644
--- a/arch/arm/boot/dts/at91sam9263.dtsi
+++ b/arch/arm/boot/dts/at91sam9263.dtsi
@@ -523,7 +523,7 @@
};
i2c0: i2c@fff88000 {
- compatible = "atmel,at91sam9263-i2c";
+ compatible = "atmel,at91sam9260-i2c";
reg = <0xfff88000 0x100>;
interrupts = <13 IRQ_TYPE_LEVEL_HIGH 6>;
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts
index e9487f6f0166..924a6a6ffd0f 100644
--- a/arch/arm/boot/dts/at91sam9n12ek.dts
+++ b/arch/arm/boot/dts/at91sam9n12ek.dts
@@ -124,6 +124,10 @@
nand-on-flash-bbt;
status = "okay";
};
+
+ usb0: ohci@00500000 {
+ status = "okay";
+ };
};
leds {
diff --git a/arch/arm/boot/dts/atlas6.dtsi b/arch/arm/boot/dts/atlas6.dtsi
index f8674bcc4489..0c81dc945aed 100644
--- a/arch/arm/boot/dts/atlas6.dtsi
+++ b/arch/arm/boot/dts/atlas6.dtsi
@@ -217,8 +217,8 @@
interrupts = <17>;
fifosize = <128>;
clocks = <&clks 13>;
- sirf,uart-dma-rx-channel = <21>;
- sirf,uart-dma-tx-channel = <2>;
+ dmas = <&dmac1 5>, <&dmac0 2>;
+ dma-names = "rx", "tx";
};
uart1: uart@b0060000 {
@@ -228,6 +228,7 @@
interrupts = <18>;
fifosize = <32>;
clocks = <&clks 14>;
+ dma-names = "no-rx", "no-tx";
};
uart2: uart@b0070000 {
@@ -237,8 +238,8 @@
interrupts = <19>;
fifosize = <128>;
clocks = <&clks 15>;
- sirf,uart-dma-rx-channel = <6>;
- sirf,uart-dma-tx-channel = <7>;
+ dmas = <&dmac0 6>, <&dmac0 7>;
+ dma-names = "rx", "tx";
};
usp0: usp@b0080000 {
@@ -248,8 +249,8 @@
interrupts = <20>;
fifosize = <128>;
clocks = <&clks 28>;
- sirf,usp-dma-rx-channel = <17>;
- sirf,usp-dma-tx-channel = <18>;
+ dmas = <&dmac1 1>, <&dmac1 2>;
+ dma-names = "rx", "tx";
};
usp1: usp@b0090000 {
@@ -259,8 +260,8 @@
interrupts = <21>;
fifosize = <128>;
clocks = <&clks 29>;
- sirf,usp-dma-rx-channel = <14>;
- sirf,usp-dma-tx-channel = <15>;
+ dmas = <&dmac0 14>, <&dmac0 15>;
+ dma-names = "rx", "tx";
};
dmac0: dma-controller@b00b0000 {
diff --git a/arch/arm/boot/dts/bcm11351.dtsi b/arch/arm/boot/dts/bcm11351.dtsi
index e491b82f8d67..792fde1b7f75 100644
--- a/arch/arm/boot/dts/bcm11351.dtsi
+++ b/arch/arm/boot/dts/bcm11351.dtsi
@@ -147,7 +147,7 @@
};
pinctrl@35004800 {
- compatible = "brcm,capri-pinctrl";
+ compatible = "brcm,bcm11351-pinctrl";
reg = <0x35004800 0x430>;
};
diff --git a/arch/arm/boot/dts/dove.dtsi b/arch/arm/boot/dts/dove.dtsi
index 2b76524f4aa7..187fd46b7b5e 100644
--- a/arch/arm/boot/dts/dove.dtsi
+++ b/arch/arm/boot/dts/dove.dtsi
@@ -379,15 +379,6 @@
#clock-cells = <1>;
};
- pmu_intc: pmu-interrupt-ctrl@d0050 {
- compatible = "marvell,dove-pmu-intc";
- interrupt-controller;
- #interrupt-cells = <1>;
- reg = <0xd0050 0x8>;
- interrupts = <33>;
- marvell,#interrupts = <7>;
- };
-
pinctrl: pin-ctrl@d0200 {
compatible = "marvell,dove-pinctrl";
reg = <0xd0200 0x10>;
@@ -610,8 +601,6 @@
rtc: real-time-clock@d8500 {
compatible = "marvell,orion-rtc";
reg = <0xd8500 0x20>;
- interrupt-parent = <&pmu_intc>;
- interrupts = <5>;
};
gpio2: gpio-ctrl@e8400 {
diff --git a/arch/arm/boot/dts/imx51-apf51dev.dts b/arch/arm/boot/dts/imx51-apf51dev.dts
index 5a7f552786a1..d3f98141462c 100644
--- a/arch/arm/boot/dts/imx51-apf51dev.dts
+++ b/arch/arm/boot/dts/imx51-apf51dev.dts
@@ -18,7 +18,6 @@
display@di1 {
compatible = "fsl,imx-parallel-display";
- crtcs = <&ipu 0>;
interface-pix-fmt = "bgr666";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ipu_disp1_1>;
@@ -41,6 +40,12 @@
pixelclk-active = <0>;
};
};
+
+ port {
+ display_in: endpoint {
+ remote-endpoint = <&ipu_di0_disp0>;
+ };
+ };
};
gpio-keys {
@@ -122,3 +127,7 @@
};
};
};
+
+&ipu_di0_disp0 {
+ remote-endpoint = <&display_in>;
+};
diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts
index be1407cf5abd..671927145632 100644
--- a/arch/arm/boot/dts/imx51-babbage.dts
+++ b/arch/arm/boot/dts/imx51-babbage.dts
@@ -21,9 +21,8 @@
reg = <0x90000000 0x20000000>;
};
- display@di0 {
+ display0: display@di0 {
compatible = "fsl,imx-parallel-display";
- crtcs = <&ipu 0>;
interface-pix-fmt = "rgb24";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ipu_disp1_1>;
@@ -41,11 +40,16 @@
vsync-len = <10>;
};
};
+
+ port {
+ display0_in: endpoint {
+ remote-endpoint = <&ipu_di0_disp0>;
+ };
+ };
};
- display@di1 {
+ display1: display@di1 {
compatible = "fsl,imx-parallel-display";
- crtcs = <&ipu 1>;
interface-pix-fmt = "rgb565";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ipu_disp2_1>;
@@ -68,6 +72,12 @@
pixelclk-active = <0>;
};
};
+
+ port {
+ display1_in: endpoint {
+ remote-endpoint = <&ipu_di1_disp1>;
+ };
+ };
};
gpio-keys {
@@ -258,6 +268,14 @@
};
};
+&ipu_di0_disp0 {
+ remote-endpoint = <&display0_in>;
+};
+
+&ipu_di1_disp1 {
+ remote-endpoint = <&display1_in>;
+};
+
&ssi2 {
fsl,mode = "i2s-slave";
status = "okay";
diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi
index 4bcdd3ad15e5..28c96aada80b 100644
--- a/arch/arm/boot/dts/imx51.dtsi
+++ b/arch/arm/boot/dts/imx51.dtsi
@@ -79,6 +79,11 @@
};
};
+ display-subsystem {
+ compatible = "fsl,imx-display-subsystem";
+ ports = <&ipu_di0>, <&ipu_di1>;
+ };
+
soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -92,13 +97,28 @@
};
ipu: ipu@40000000 {
- #crtc-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
compatible = "fsl,imx51-ipu";
reg = <0x40000000 0x20000000>;
interrupts = <11 10>;
clocks = <&clks 59>, <&clks 110>, <&clks 61>;
clock-names = "bus", "di0", "di1";
resets = <&src 2>;
+
+ ipu_di0: port@2 {
+ reg = <2>;
+
+ ipu_di0_disp0: endpoint {
+ };
+ };
+
+ ipu_di1: port@3 {
+ reg = <3>;
+
+ ipu_di1_disp1: endpoint {
+ };
+ };
};
aips@70000000 { /* AIPS1 */
diff --git a/arch/arm/boot/dts/imx53-m53evk.dts b/arch/arm/boot/dts/imx53-m53evk.dts
index 7d304d02ed38..0298adc73bb7 100644
--- a/arch/arm/boot/dts/imx53-m53evk.dts
+++ b/arch/arm/boot/dts/imx53-m53evk.dts
@@ -21,9 +21,8 @@
};
soc {
- display@di1 {
+ display1: display@di1 {
compatible = "fsl,imx-parallel-display";
- crtcs = <&ipu 1>;
interface-pix-fmt = "bgr666";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ipu_disp2_1>;
@@ -44,6 +43,12 @@
};
};
};
+
+ port {
+ display1_in: endpoint {
+ remote-endpoint = <&ipu_di1_disp1>;
+ };
+ };
};
backlight {
@@ -221,6 +226,10 @@
};
};
+&ipu_di1_disp1 {
+ remote-endpoint = <&display1_in>;
+};
+
&nfc {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_nand_1>;
diff --git a/arch/arm/boot/dts/imx53-mba53.dts b/arch/arm/boot/dts/imx53-mba53.dts
index a63090267941..a5b55c603591 100644
--- a/arch/arm/boot/dts/imx53-mba53.dts
+++ b/arch/arm/boot/dts/imx53-mba53.dts
@@ -38,9 +38,14 @@
compatible = "fsl,imx-parallel-display";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_disp1_1>;
- crtcs = <&ipu 1>;
interface-pix-fmt = "rgb24";
status = "disabled";
+
+ port {
+ display1_in: endpoint {
+ remote-endpoint = <&ipu_di1_disp1>;
+ };
+ };
};
reg_3p2v: 3p2v {
@@ -141,6 +146,10 @@
};
};
+&ipu_di1_disp1 {
+ remote-endpoint = <&display1_in>;
+};
+
&cspi {
status = "okay";
};
@@ -228,7 +237,7 @@
&tve {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_vga_sync_1>;
- ddc = <&i2c3>;
+ i2c-ddc-bus = <&i2c3>;
fsl,tve-mode = "vga";
fsl,hsync-pin = <4>;
fsl,vsync-pin = <6>;
diff --git a/arch/arm/boot/dts/imx53-qsb.dts b/arch/arm/boot/dts/imx53-qsb.dts
index 91a5935a4aac..8b254289344f 100644
--- a/arch/arm/boot/dts/imx53-qsb.dts
+++ b/arch/arm/boot/dts/imx53-qsb.dts
@@ -21,9 +21,8 @@
reg = <0x70000000 0x40000000>;
};
- display@di0 {
+ display0: display@di0 {
compatible = "fsl,imx-parallel-display";
- crtcs = <&ipu 0>;
interface-pix-fmt = "rgb565";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ipu_disp0_1>;
@@ -46,6 +45,12 @@
pixelclk-active = <0>;
};
};
+
+ port {
+ display0_in: endpoint {
+ remote-endpoint = <&ipu_di0_disp0>;
+ };
+ };
};
gpio-keys {
@@ -126,6 +131,10 @@
status = "okay";
};
+&ipu_di0_disp0 {
+ remote-endpoint = <&display0_in>;
+};
+
&ssi2 {
fsl,mode = "i2s-slave";
status = "okay";
diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
index 4307e80b2d2e..04d3127edfe1 100644
--- a/arch/arm/boot/dts/imx53.dtsi
+++ b/arch/arm/boot/dts/imx53.dtsi
@@ -45,6 +45,11 @@
};
};
+ display-subsystem {
+ compatible = "fsl,imx-display-subsystem";
+ ports = <&ipu_di0>, <&ipu_di1>;
+ };
+
tzic: tz-interrupt-controller@0fffc000 {
compatible = "fsl,imx53-tzic", "fsl,tzic";
interrupt-controller;
@@ -85,13 +90,49 @@
ranges;
ipu: ipu@18000000 {
- #crtc-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
compatible = "fsl,imx53-ipu";
reg = <0x18000000 0x080000000>;
interrupts = <11 10>;
clocks = <&clks 59>, <&clks 110>, <&clks 61>;
clock-names = "bus", "di0", "di1";
resets = <&src 2>;
+
+ ipu_di0: port@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+
+ ipu_di0_disp0: endpoint@0 {
+ reg = <0>;
+ };
+
+ ipu_di0_lvds0: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&lvds0_in>;
+ };
+ };
+
+ ipu_di1: port@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+
+ ipu_di1_disp1: endpoint@0 {
+ reg = <0>;
+ };
+
+ ipu_di1_lvds1: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&lvds1_in>;
+ };
+
+ ipu_di1_tve: endpoint@2 {
+ reg = <2>;
+ remote-endpoint = <&tve_in>;
+ };
+ };
};
aips@50000000 { /* AIPS1 */
@@ -838,14 +879,24 @@
lvds-channel@0 {
reg = <0>;
- crtcs = <&ipu 0>;
status = "disabled";
+
+ port {
+ lvds0_in: endpoint {
+ remote-endpoint = <&ipu_di0_lvds0>;
+ };
+ };
};
lvds-channel@1 {
reg = <1>;
- crtcs = <&ipu 1>;
status = "disabled";
+
+ port {
+ lvds1_in: endpoint {
+ remote-endpoint = <&ipu_di0_lvds0>;
+ };
+ };
};
};
@@ -1103,8 +1154,13 @@
interrupts = <92>;
clocks = <&clks 69>, <&clks 116>;
clock-names = "tve", "di_sel";
- crtcs = <&ipu 1>;
status = "disabled";
+
+ port {
+ tve_in: endpoint {
+ remote-endpoint = <&ipu_di1_tve>;
+ };
+ };
};
vpu: vpu@63ff4000 {
diff --git a/arch/arm/boot/dts/imx6dl-hummingboard.dts b/arch/arm/boot/dts/imx6dl-hummingboard.dts
index fd8fc7cd53f3..5bfae54fb780 100644
--- a/arch/arm/boot/dts/imx6dl-hummingboard.dts
+++ b/arch/arm/boot/dts/imx6dl-hummingboard.dts
@@ -52,12 +52,6 @@
};
};
- codec: spdif-transmitter {
- compatible = "linux,spdif-dit";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_hummingboard_spdif>;
- };
-
sound-spdif {
compatible = "fsl,imx-audio-spdif";
model = "imx-spdif";
@@ -111,7 +105,7 @@
};
pinctrl_hummingboard_spdif: hummingboard-spdif {
- fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x1b0b0>;
+ fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>;
};
pinctrl_hummingboard_usbh1_vbus: hummingboard-usbh1-vbus {
@@ -142,6 +136,8 @@
};
&spdif {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_hummingboard_spdif>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
index 9e8ae118fdd4..25bbdd6f214b 100644
--- a/arch/arm/boot/dts/imx6dl.dtsi
+++ b/arch/arm/boot/dts/imx6dl.dtsi
@@ -70,6 +70,15 @@
};
};
};
+
+ display-subsystem {
+ compatible = "fsl,imx-display-subsystem";
+ ports = <&ipu1_di0>, <&ipu1_di1>;
+ };
+};
+
+&hdmi {
+ compatible = "fsl,imx6dl-hdmi";
};
&ldb {
@@ -79,12 +88,4 @@
clock-names = "di0_pll", "di1_pll",
"di0_sel", "di1_sel",
"di0", "di1";
-
- lvds-channel@0 {
- crtcs = <&ipu1 0>, <&ipu1 1>;
- };
-
- lvds-channel@1 {
- crtcs = <&ipu1 0>, <&ipu1 1>;
- };
};
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index f024ef28b34b..2a8d9de666c9 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -132,13 +132,84 @@
};
ipu2: ipu@02800000 {
- #crtc-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
compatible = "fsl,imx6q-ipu";
reg = <0x02800000 0x400000>;
interrupts = <0 8 0x4 0 7 0x4>;
clocks = <&clks 133>, <&clks 134>, <&clks 137>;
clock-names = "bus", "di0", "di1";
resets = <&src 4>;
+
+ ipu2_di0: port@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+
+ ipu2_di0_disp0: endpoint@0 {
+ };
+
+ ipu2_di0_hdmi: endpoint@1 {
+ remote-endpoint = <&hdmi_mux_2>;
+ };
+
+ ipu2_di0_mipi: endpoint@2 {
+ };
+
+ ipu2_di0_lvds0: endpoint@3 {
+ remote-endpoint = <&lvds0_mux_2>;
+ };
+
+ ipu2_di0_lvds1: endpoint@4 {
+ remote-endpoint = <&lvds1_mux_2>;
+ };
+ };
+
+ ipu2_di1: port@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+
+ ipu2_di1_hdmi: endpoint@1 {
+ remote-endpoint = <&hdmi_mux_3>;
+ };
+
+ ipu2_di1_mipi: endpoint@2 {
+ };
+
+ ipu2_di1_lvds0: endpoint@3 {
+ remote-endpoint = <&lvds0_mux_3>;
+ };
+
+ ipu2_di1_lvds1: endpoint@4 {
+ remote-endpoint = <&lvds1_mux_3>;
+ };
+ };
+ };
+ };
+
+ display-subsystem {
+ compatible = "fsl,imx-display-subsystem";
+ ports = <&ipu1_di0>, <&ipu1_di1>, <&ipu2_di0>, <&ipu2_di1>;
+ };
+};
+
+&hdmi {
+ compatible = "fsl,imx6q-hdmi";
+
+ port@2 {
+ reg = <2>;
+
+ hdmi_mux_2: endpoint {
+ remote-endpoint = <&ipu2_di0_hdmi>;
+ };
+ };
+
+ port@3 {
+ reg = <3>;
+
+ hdmi_mux_3: endpoint {
+ remote-endpoint = <&ipu2_di1_hdmi>;
};
};
};
@@ -152,10 +223,56 @@
"di0", "di1";
lvds-channel@0 {
- crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
+ port@2 {
+ reg = <2>;
+
+ lvds0_mux_2: endpoint {
+ remote-endpoint = <&ipu2_di0_lvds0>;
+ };
+ };
+
+ port@3 {
+ reg = <3>;
+
+ lvds0_mux_3: endpoint {
+ remote-endpoint = <&ipu2_di1_lvds0>;
+ };
+ };
};
lvds-channel@1 {
- crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
+ port@2 {
+ reg = <2>;
+
+ lvds1_mux_2: endpoint {
+ remote-endpoint = <&ipu2_di0_lvds1>;
+ };
+ };
+
+ port@3 {
+ reg = <3>;
+
+ lvds1_mux_3: endpoint {
+ remote-endpoint = <&ipu2_di1_lvds1>;
+ };
+ };
+ };
+};
+
+&mipi_dsi {
+ port@2 {
+ reg = <2>;
+
+ mipi_mux_2: endpoint {
+ remote-endpoint = <&ipu2_di0_mipi>;
+ };
+ };
+
+ port@3 {
+ reg = <3>;
+
+ mipi_mux_3: endpoint {
+ remote-endpoint = <&ipu2_di1_mipi>;
+ };
};
};
diff --git a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
index 64daa3b311f6..c2a24888a276 100644
--- a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
@@ -46,12 +46,6 @@
};
};
- codec: spdif-transmitter {
- compatible = "linux,spdif-dit";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_cubox_i_spdif>;
- };
-
sound-spdif {
compatible = "fsl,imx-audio-spdif";
model = "imx-spdif";
@@ -89,7 +83,7 @@
};
pinctrl_cubox_i_spdif: cubox-i-spdif {
- fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x1b0b0>;
+ fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>;
};
pinctrl_cubox_i_usbh1_vbus: cubox-i-usbh1-vbus {
@@ -121,6 +115,8 @@
};
&spdif {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_cubox_i_spdif>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index fb28b2ecb1db..64a8cbe9480f 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1358,13 +1358,76 @@
status = "disabled";
lvds-channel@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
reg = <0>;
status = "disabled";
+
+ port@0 {
+ reg = <0>;
+
+ lvds0_mux_0: endpoint {
+ remote-endpoint = <&ipu1_di0_lvds0>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ lvds0_mux_1: endpoint {
+ remote-endpoint = <&ipu1_di1_lvds0>;
+ };
+ };
};
lvds-channel@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
reg = <1>;
status = "disabled";
+
+ port@0 {
+ reg = <0>;
+
+ lvds1_mux_0: endpoint {
+ remote-endpoint = <&ipu1_di0_lvds1>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ lvds1_mux_1: endpoint {
+ remote-endpoint = <&ipu1_di1_lvds1>;
+ };
+ };
+ };
+ };
+
+ hdmi: hdmi@0120000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x00120000 0x9000>;
+ interrupts = <0 115 0x04>;
+ gpr = <&gpr>;
+ clocks = <&clks 123>, <&clks 124>;
+ clock-names = "iahb", "isfr";
+ status = "disabled";
+
+ port@0 {
+ reg = <0>;
+
+ hdmi_mux_0: endpoint {
+ remote-endpoint = <&ipu1_di0_hdmi>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ hdmi_mux_1: endpoint {
+ remote-endpoint = <&ipu1_di1_hdmi>;
+ };
};
};
@@ -1579,8 +1642,27 @@
reg = <0x021dc000 0x4000>;
};
- mipi@021e0000 { /* MIPI-DSI */
+ mipi_dsi: mipi@021e0000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
reg = <0x021e0000 0x4000>;
+ status = "disabled";
+
+ port@0 {
+ reg = <0>;
+
+ mipi_mux_0: endpoint {
+ remote-endpoint = <&ipu1_di0_mipi>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ mipi_mux_1: endpoint {
+ remote-endpoint = <&ipu1_di1_mipi>;
+ };
+ };
};
vdoa@021e4000 {
@@ -1634,13 +1716,64 @@
};
ipu1: ipu@02400000 {
- #crtc-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
compatible = "fsl,imx6q-ipu";
reg = <0x02400000 0x400000>;
interrupts = <0 6 0x4 0 5 0x4>;
clocks = <&clks 130>, <&clks 131>, <&clks 132>;
clock-names = "bus", "di0", "di1";
resets = <&src 2>;
+
+ ipu1_di0: port@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+
+ ipu1_di0_disp0: endpoint@0 {
+ };
+
+ ipu1_di0_hdmi: endpoint@1 {
+ remote-endpoint = <&hdmi_mux_0>;
+ };
+
+ ipu1_di0_mipi: endpoint@2 {
+ remote-endpoint = <&mipi_mux_0>;
+ };
+
+ ipu1_di0_lvds0: endpoint@3 {
+ remote-endpoint = <&lvds0_mux_0>;
+ };
+
+ ipu1_di0_lvds1: endpoint@4 {
+ remote-endpoint = <&lvds1_mux_0>;
+ };
+ };
+
+ ipu1_di1: port@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+
+ ipu1_di0_disp1: endpoint@0 {
+ };
+
+ ipu1_di1_hdmi: endpoint@1 {
+ remote-endpoint = <&hdmi_mux_1>;
+ };
+
+ ipu1_di1_mipi: endpoint@2 {
+ remote-endpoint = <&mipi_mux_1>;
+ };
+
+ ipu1_di1_lvds0: endpoint@3 {
+ remote-endpoint = <&lvds0_mux_1>;
+ };
+
+ ipu1_di1_lvds1: endpoint@4 {
+ remote-endpoint = <&lvds1_mux_1>;
+ };
+ };
};
};
};
diff --git a/arch/arm/boot/dts/keystone-clocks.dtsi b/arch/arm/boot/dts/keystone-clocks.dtsi
index 2363593e1050..ef58d1c24313 100644
--- a/arch/arm/boot/dts/keystone-clocks.dtsi
+++ b/arch/arm/boot/dts/keystone-clocks.dtsi
@@ -612,7 +612,7 @@ clocks {
compatible = "ti,keystone,psc-clock";
clocks = <&chipclk13>;
clock-output-names = "vcp-3";
- reg = <0x0235000a8 0xb00>, <0x02350060 0x400>;
+ reg = <0x023500a8 0xb00>, <0x02350060 0x400>;
reg-names = "control", "domain";
domain-id = <24>;
};
diff --git a/arch/arm/boot/dts/omap3-gta04.dts b/arch/arm/boot/dts/omap3-gta04.dts
index b9b55c95a566..d3b253bbc885 100644
--- a/arch/arm/boot/dts/omap3-gta04.dts
+++ b/arch/arm/boot/dts/omap3-gta04.dts
@@ -13,7 +13,7 @@
/ {
model = "OMAP3 GTA04";
- compatible = "ti,omap3-gta04", "ti,omap3";
+ compatible = "ti,omap3-gta04", "ti,omap36xx", "ti,omap3";
cpus {
cpu@0 {
@@ -32,7 +32,7 @@
aux-button {
label = "aux";
linux,code = <169>;
- gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
+ gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
gpio-key,wakeup;
};
};
@@ -92,6 +92,8 @@
bmp085@77 {
compatible = "bosch,bmp085";
reg = <0x77>;
+ interrupt-parent = <&gpio4>;
+ interrupts = <17 IRQ_TYPE_EDGE_RISING>;
};
/* leds */
@@ -141,8 +143,8 @@
pinctrl-names = "default";
pinctrl-0 = <&mmc1_pins>;
vmmc-supply = <&vmmc1>;
- vmmc_aux-supply = <&vsim>;
bus-width = <4>;
+ ti,non-removable;
};
&mmc2 {
diff --git a/arch/arm/boot/dts/omap3-igep0020.dts b/arch/arm/boot/dts/omap3-igep0020.dts
index 25a2b5f652fd..f2779ac75872 100644
--- a/arch/arm/boot/dts/omap3-igep0020.dts
+++ b/arch/arm/boot/dts/omap3-igep0020.dts
@@ -14,7 +14,7 @@
/ {
model = "IGEPv2 (TI OMAP AM/DM37x)";
- compatible = "isee,omap3-igep0020", "ti,omap3";
+ compatible = "isee,omap3-igep0020", "ti,omap36xx", "ti,omap3";
leds {
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/omap3-igep0030.dts b/arch/arm/boot/dts/omap3-igep0030.dts
index 145c58cfc8ac..2793749eb1ba 100644
--- a/arch/arm/boot/dts/omap3-igep0030.dts
+++ b/arch/arm/boot/dts/omap3-igep0030.dts
@@ -13,7 +13,7 @@
/ {
model = "IGEP COM MODULE (TI OMAP AM/DM37x)";
- compatible = "isee,omap3-igep0030", "ti,omap3";
+ compatible = "isee,omap3-igep0030", "ti,omap36xx", "ti,omap3";
leds {
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/omap3-n9.dts b/arch/arm/boot/dts/omap3-n9.dts
index 39828ce464ee..9938b5dc1909 100644
--- a/arch/arm/boot/dts/omap3-n9.dts
+++ b/arch/arm/boot/dts/omap3-n9.dts
@@ -14,5 +14,5 @@
/ {
model = "Nokia N9";
- compatible = "nokia,omap3-n9", "ti,omap3";
+ compatible = "nokia,omap3-n9", "ti,omap36xx", "ti,omap3";
};
diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts
index 6fc85f963530..0bf40c90faba 100644
--- a/arch/arm/boot/dts/omap3-n900.dts
+++ b/arch/arm/boot/dts/omap3-n900.dts
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2013 Pavel Machek <pavel@ucw.cz>
- * Copyright 2013 Aaro Koskinen <aaro.koskinen@iki.fi>
+ * Copyright (C) 2013-2014 Aaro Koskinen <aaro.koskinen@iki.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 (or later) as
@@ -13,7 +13,7 @@
/ {
model = "Nokia N900";
- compatible = "nokia,omap3-n900", "ti,omap3";
+ compatible = "nokia,omap3-n900", "ti,omap3430", "ti,omap3";
cpus {
cpu@0 {
diff --git a/arch/arm/boot/dts/omap3-n950.dts b/arch/arm/boot/dts/omap3-n950.dts
index b076a526b999..261c5589bfa3 100644
--- a/arch/arm/boot/dts/omap3-n950.dts
+++ b/arch/arm/boot/dts/omap3-n950.dts
@@ -14,5 +14,5 @@
/ {
model = "Nokia N950";
- compatible = "nokia,omap3-n950", "ti,omap3";
+ compatible = "nokia,omap3-n950", "ti,omap36xx", "ti,omap3";
};
diff --git a/arch/arm/boot/dts/omap3-overo-storm-tobi.dts b/arch/arm/boot/dts/omap3-overo-storm-tobi.dts
new file mode 100644
index 000000000000..966b5c9cd96a
--- /dev/null
+++ b/arch/arm/boot/dts/omap3-overo-storm-tobi.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 Florian Vaussard, EPFL Mobots group
+ *
+ * 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.
+ */
+
+/*
+ * Tobi expansion board is manufactured by Gumstix Inc.
+ */
+
+/dts-v1/;
+
+#include "omap36xx.dtsi"
+#include "omap3-overo-tobi-common.dtsi"
+
+/ {
+ model = "OMAP36xx/AM37xx/DM37xx Gumstix Overo on Tobi";
+ compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap36xx", "ti,omap3";
+};
+
diff --git a/arch/arm/boot/dts/omap3-tobi.dts b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi
index 7e4ad2aec37a..4edc013a91c1 100644
--- a/arch/arm/boot/dts/omap3-tobi.dts
+++ b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi
@@ -13,9 +13,6 @@
#include "omap3-overo.dtsi"
/ {
- model = "TI OMAP3 Gumstix Overo on Tobi";
- compatible = "ti,omap3-tobi", "ti,omap3-overo", "ti,omap3";
-
leds {
compatible = "gpio-leds";
heartbeat {
diff --git a/arch/arm/boot/dts/omap3-overo-tobi.dts b/arch/arm/boot/dts/omap3-overo-tobi.dts
new file mode 100644
index 000000000000..de5653e1b5ca
--- /dev/null
+++ b/arch/arm/boot/dts/omap3-overo-tobi.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 Florian Vaussard, EPFL Mobots group
+ *
+ * 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.
+ */
+
+/*
+ * Tobi expansion board is manufactured by Gumstix Inc.
+ */
+
+/dts-v1/;
+
+#include "omap34xx.dtsi"
+#include "omap3-overo-tobi-common.dtsi"
+
+/ {
+ model = "OMAP35xx Gumstix Overo on Tobi";
+ compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap3430", "ti,omap3";
+};
+
diff --git a/arch/arm/boot/dts/omap3-overo.dtsi b/arch/arm/boot/dts/omap3-overo.dtsi
index a461d2fd1fb0..597099907f8e 100644
--- a/arch/arm/boot/dts/omap3-overo.dtsi
+++ b/arch/arm/boot/dts/omap3-overo.dtsi
@@ -9,9 +9,6 @@
/*
* The Gumstix Overo must be combined with an expansion board.
*/
-/dts-v1/;
-
-#include "omap34xx.dtsi"
/ {
pwmleds {
diff --git a/arch/arm/boot/dts/prima2.dtsi b/arch/arm/boot/dts/prima2.dtsi
index 0e219932d7cc..8582ae41a583 100644
--- a/arch/arm/boot/dts/prima2.dtsi
+++ b/arch/arm/boot/dts/prima2.dtsi
@@ -223,8 +223,8 @@
interrupts = <17>;
fifosize = <128>;
clocks = <&clks 13>;
- sirf,uart-dma-rx-channel = <21>;
- sirf,uart-dma-tx-channel = <2>;
+ dmas = <&dmac1 5>, <&dmac0 2>;
+ dma-names = "rx", "tx";
};
uart1: uart@b0060000 {
@@ -243,8 +243,8 @@
interrupts = <19>;
fifosize = <128>;
clocks = <&clks 15>;
- sirf,uart-dma-rx-channel = <6>;
- sirf,uart-dma-tx-channel = <7>;
+ dmas = <&dmac0 6>, <&dmac0 7>;
+ dma-names = "rx", "tx";
};
usp0: usp@b0080000 {
@@ -254,8 +254,8 @@
interrupts = <20>;
fifosize = <128>;
clocks = <&clks 28>;
- sirf,usp-dma-rx-channel = <17>;
- sirf,usp-dma-tx-channel = <18>;
+ dmas = <&dmac1 1>, <&dmac1 2>;
+ dma-names = "rx", "tx";
};
usp1: usp@b0090000 {
@@ -265,8 +265,8 @@
interrupts = <21>;
fifosize = <128>;
clocks = <&clks 29>;
- sirf,usp-dma-rx-channel = <14>;
- sirf,usp-dma-tx-channel = <15>;
+ dmas = <&dmac0 14>, <&dmac0 15>;
+ dma-names = "rx", "tx";
};
usp2: usp@b00a0000 {
@@ -276,8 +276,8 @@
interrupts = <22>;
fifosize = <128>;
clocks = <&clks 30>;
- sirf,usp-dma-rx-channel = <10>;
- sirf,usp-dma-tx-channel = <11>;
+ dmas = <&dmac0 10>, <&dmac0 11>;
+ dma-names = "rx", "tx";
};
dmac0: dma-controller@b00b0000 {
diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi
index 19c65509a22d..3b075dd19b51 100644
--- a/arch/arm/boot/dts/r8a7791.dtsi
+++ b/arch/arm/boot/dts/r8a7791.dtsi
@@ -429,7 +429,7 @@
R8A7791_CLK_MSIOF1 R8A7791_CLK_SCIFB2
>;
clock-output-names =
- "scifa2", "scifa1", "scifa0", "misof2", "scifb0",
+ "scifa2", "scifa1", "scifa0", "msiof2", "scifb0",
"scifb1", "msiof1", "scifb2";
};
mstp3_clks: mstp3_clks@e615013c {
diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi
index 52447c17537a..3d5faf85f51b 100644
--- a/arch/arm/boot/dts/sama5d3.dtsi
+++ b/arch/arm/boot/dts/sama5d3.dtsi
@@ -1228,7 +1228,7 @@
compatible = "atmel,at91rm9200-ohci", "usb-ohci";
reg = <0x00600000 0x100000>;
interrupts = <32 IRQ_TYPE_LEVEL_HIGH 2>;
- clocks = <&usb>, <&uhphs_clk>, <&udphs_clk>,
+ clocks = <&usb>, <&uhphs_clk>, <&uhphs_clk>,
<&uhpck>;
clock-names = "usb_clk", "ohci_clk", "hclk", "uhpck";
status = "disabled";
diff --git a/arch/arm/boot/dts/sama5d36.dtsi b/arch/arm/boot/dts/sama5d36.dtsi
index 6c31c26e6cc0..db58cad6acd3 100644
--- a/arch/arm/boot/dts/sama5d36.dtsi
+++ b/arch/arm/boot/dts/sama5d36.dtsi
@@ -8,8 +8,8 @@
*/
#include "sama5d3.dtsi"
#include "sama5d3_can.dtsi"
-#include "sama5d3_emac.dtsi"
#include "sama5d3_gmac.dtsi"
+#include "sama5d3_emac.dtsi"
#include "sama5d3_lcd.dtsi"
#include "sama5d3_mci2.dtsi"
#include "sama5d3_tcb1.dtsi"
diff --git a/arch/arm/boot/dts/ste-href.dtsi b/arch/arm/boot/dts/ste-href.dtsi
index 0c1e8d871ed1..6cb9b68e2188 100644
--- a/arch/arm/boot/dts/ste-href.dtsi
+++ b/arch/arm/boot/dts/ste-href.dtsi
@@ -188,7 +188,6 @@
msp2: msp@80117000 {
pinctrl-names = "default";
pinctrl-0 = <&msp2_default_mode>;
- status = "okay";
};
msp3: msp@80125000 {
diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index 040bb0eba152..9321681cc45a 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -315,7 +315,7 @@
ranges;
emac: ethernet@01c0b000 {
- compatible = "allwinner,sun4i-emac";
+ compatible = "allwinner,sun4i-a10-emac";
reg = <0x01c0b000 0x1000>;
interrupts = <55>;
clocks = <&ahb_gates 17>;
@@ -323,7 +323,7 @@
};
mdio@01c0b080 {
- compatible = "allwinner,sun4i-mdio";
+ compatible = "allwinner,sun4i-a10-mdio";
reg = <0x01c0b080 0x14>;
status = "disabled";
#address-cells = <1>;
@@ -331,7 +331,7 @@
};
intc: interrupt-controller@01c20400 {
- compatible = "allwinner,sun4i-ic";
+ compatible = "allwinner,sun4i-a10-ic";
reg = <0x01c20400 0x400>;
interrupt-controller;
#interrupt-cells = <1>;
@@ -403,7 +403,7 @@
};
timer@01c20c00 {
- compatible = "allwinner,sun4i-timer";
+ compatible = "allwinner,sun4i-a10-timer";
reg = <0x01c20c00 0x90>;
interrupts = <22>;
clocks = <&osc24M>;
@@ -415,18 +415,18 @@
};
rtc: rtc@01c20d00 {
- compatible = "allwinner,sun4i-rtc";
+ compatible = "allwinner,sun4i-a10-rtc";
reg = <0x01c20d00 0x20>;
interrupts = <24>;
};
sid: eeprom@01c23800 {
- compatible = "allwinner,sun4i-sid";
+ compatible = "allwinner,sun4i-a10-sid";
reg = <0x01c23800 0x10>;
};
rtp: rtp@01c25000 {
- compatible = "allwinner,sun4i-ts";
+ compatible = "allwinner,sun4i-a10-ts";
reg = <0x01c25000 0x100>;
interrupts = <29>;
};
diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
index ea16054857a4..ee17b1c379e3 100644
--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
+++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
@@ -278,7 +278,7 @@
ranges;
emac: ethernet@01c0b000 {
- compatible = "allwinner,sun4i-emac";
+ compatible = "allwinner,sun4i-a10-emac";
reg = <0x01c0b000 0x1000>;
interrupts = <55>;
clocks = <&ahb_gates 17>;
@@ -286,7 +286,7 @@
};
mdio@01c0b080 {
- compatible = "allwinner,sun4i-mdio";
+ compatible = "allwinner,sun4i-a10-mdio";
reg = <0x01c0b080 0x14>;
status = "disabled";
#address-cells = <1>;
@@ -294,7 +294,7 @@
};
intc: interrupt-controller@01c20400 {
- compatible = "allwinner,sun4i-ic";
+ compatible = "allwinner,sun4i-a10-ic";
reg = <0x01c20400 0x400>;
interrupt-controller;
#interrupt-cells = <1>;
@@ -366,7 +366,7 @@
};
timer@01c20c00 {
- compatible = "allwinner,sun4i-timer";
+ compatible = "allwinner,sun4i-a10-timer";
reg = <0x01c20c00 0x90>;
interrupts = <22>;
clocks = <&osc24M>;
@@ -378,12 +378,12 @@
};
sid: eeprom@01c23800 {
- compatible = "allwinner,sun4i-sid";
+ compatible = "allwinner,sun4i-a10-sid";
reg = <0x01c23800 0x10>;
};
rtp: rtp@01c25000 {
- compatible = "allwinner,sun4i-ts";
+ compatible = "allwinner,sun4i-a10-ts";
reg = <0x01c25000 0x100>;
interrupts = <29>;
};
diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
index 320335abfccd..3490ef9ec603 100644
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -275,7 +275,7 @@
ranges;
intc: interrupt-controller@01c20400 {
- compatible = "allwinner,sun4i-ic";
+ compatible = "allwinner,sun4i-a10-ic";
reg = <0x01c20400 0x400>;
interrupt-controller;
#interrupt-cells = <1>;
@@ -329,7 +329,7 @@
};
timer@01c20c00 {
- compatible = "allwinner,sun4i-timer";
+ compatible = "allwinner,sun4i-a10-timer";
reg = <0x01c20c00 0x90>;
interrupts = <22>;
clocks = <&osc24M>;
@@ -341,12 +341,12 @@
};
sid: eeprom@01c23800 {
- compatible = "allwinner,sun4i-sid";
+ compatible = "allwinner,sun4i-a10-sid";
reg = <0x01c23800 0x10>;
};
rtp: rtp@01c25000 {
- compatible = "allwinner,sun4i-ts";
+ compatible = "allwinner,sun4i-a10-ts";
reg = <0x01c25000 0x100>;
interrupts = <29>;
};
diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index 5256ad9be52c..38d43febda4c 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -190,6 +190,14 @@
#size-cells = <1>;
ranges;
+ nmi_intc: interrupt-controller@01f00c0c {
+ compatible = "allwinner,sun6i-a31-sc-nmi";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x01f00c0c 0x38>;
+ interrupts = <0 32 4>;
+ };
+
pio: pinctrl@01c20800 {
compatible = "allwinner,sun6i-a31-pinctrl";
reg = <0x01c20800 0x400>;
@@ -231,7 +239,7 @@
};
timer@01c20c00 {
- compatible = "allwinner,sun4i-timer";
+ compatible = "allwinner,sun4i-a10-timer";
reg = <0x01c20c00 0xa0>;
interrupts = <0 18 4>,
<0 19 4>,
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index 119f066f0d98..cadcf2f9881d 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -339,8 +339,16 @@
#size-cells = <1>;
ranges;
+ nmi_intc: interrupt-controller@01c00030 {
+ compatible = "allwinner,sun7i-a20-sc-nmi";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x01c00030 0x0c>;
+ interrupts = <0 0 4>;
+ };
+
emac: ethernet@01c0b000 {
- compatible = "allwinner,sun4i-emac";
+ compatible = "allwinner,sun4i-a10-emac";
reg = <0x01c0b000 0x1000>;
interrupts = <0 55 4>;
clocks = <&ahb_gates 17>;
@@ -348,7 +356,7 @@
};
mdio@01c0b080 {
- compatible = "allwinner,sun4i-mdio";
+ compatible = "allwinner,sun4i-a10-mdio";
reg = <0x01c0b080 0x14>;
status = "disabled";
#address-cells = <1>;
@@ -435,7 +443,7 @@
};
timer@01c20c00 {
- compatible = "allwinner,sun4i-timer";
+ compatible = "allwinner,sun4i-a10-timer";
reg = <0x01c20c00 0x90>;
interrupts = <0 22 4>,
<0 23 4>,
@@ -454,7 +462,7 @@
rtc: rtc@01c20d00 {
compatible = "allwinner,sun7i-a20-rtc";
reg = <0x01c20d00 0x20>;
- interrupts = <0 24 1>;
+ interrupts = <0 24 4>;
};
sid: eeprom@01c23800 {
@@ -463,7 +471,7 @@
};
rtp: rtp@01c25000 {
- compatible = "allwinner,sun4i-ts";
+ compatible = "allwinner,sun4i-a10-ts";
reg = <0x01c25000 0x100>;
interrupts = <0 29 4>;
};
@@ -596,10 +604,10 @@
hstimer@01c60000 {
compatible = "allwinner,sun7i-a20-hstimer";
reg = <0x01c60000 0x1000>;
- interrupts = <0 81 1>,
- <0 82 1>,
- <0 83 1>,
- <0 84 1>;
+ interrupts = <0 81 4>,
+ <0 82 4>,
+ <0 83 4>,
+ <0 84 4>;
clocks = <&ahb_gates 28>;
};
diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi
index 389e987ec281..44ec401ec366 100644
--- a/arch/arm/boot/dts/tegra114.dtsi
+++ b/arch/arm/boot/dts/tegra114.dtsi
@@ -57,6 +57,8 @@
resets = <&tegra_car 27>;
reset-names = "dc";
+ nvidia,head = <0>;
+
rgb {
status = "disabled";
};
@@ -72,6 +74,8 @@
resets = <&tegra_car 26>;
reset-names = "dc";
+ nvidia,head = <1>;
+
rgb {
status = "disabled";
};
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index 480ecda3416b..48d2a7f4d0c0 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -94,6 +94,8 @@
resets = <&tegra_car 27>;
reset-names = "dc";
+ nvidia,head = <0>;
+
rgb {
status = "disabled";
};
@@ -109,6 +111,8 @@
resets = <&tegra_car 26>;
reset-names = "dc";
+ nvidia,head = <1>;
+
rgb {
status = "disabled";
};
diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi
index 9104224124ee..1e156d9d0506 100644
--- a/arch/arm/boot/dts/tegra30-cardhu.dtsi
+++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi
@@ -28,7 +28,7 @@
compatible = "nvidia,cardhu", "nvidia,tegra30";
aliases {
- rtc0 = "/i2c@7000d000/tps6586x@34";
+ rtc0 = "/i2c@7000d000/tps65911@2d";
rtc1 = "/rtc@7000e000";
};
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index ed8e7700b46d..19a84e933f4e 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -170,6 +170,8 @@
resets = <&tegra_car 27>;
reset-names = "dc";
+ nvidia,head = <0>;
+
rgb {
status = "disabled";
};
@@ -185,6 +187,8 @@
resets = <&tegra_car 26>;
reset-names = "dc";
+ nvidia,head = <1>;
+
rgb {
status = "disabled";
};
diff --git a/arch/arm/boot/dts/testcases/tests.dtsi b/arch/arm/boot/dts/testcases/tests.dtsi
deleted file mode 100644
index 3f123ecc9dd7..000000000000
--- a/arch/arm/boot/dts/testcases/tests.dtsi
+++ /dev/null
@@ -1,2 +0,0 @@
-/include/ "tests-phandle.dtsi"
-/include/ "tests-interrupts.dtsi"
diff --git a/arch/arm/boot/dts/versatile-pb.dts b/arch/arm/boot/dts/versatile-pb.dts
index f43907c40c93..65f657711323 100644
--- a/arch/arm/boot/dts/versatile-pb.dts
+++ b/arch/arm/boot/dts/versatile-pb.dts
@@ -1,4 +1,4 @@
-/include/ "versatile-ab.dts"
+#include <versatile-ab.dts>
/ {
model = "ARM Versatile PB";
@@ -47,4 +47,4 @@
};
};
-/include/ "testcases/tests.dtsi"
+#include <testcases.dtsi>
diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi
index 8b67b19392ec..789d0bacc110 100644
--- a/arch/arm/boot/dts/zynq-7000.dtsi
+++ b/arch/arm/boot/dts/zynq-7000.dtsi
@@ -24,6 +24,12 @@
device_type = "cpu";
reg = <0>;
clocks = <&clkc 3>;
+ operating-points = <
+ /* kHz uV */
+ 666667 1000000
+ 333334 1000000
+ 222223 1000000
+ >;
};
cpu@1 {
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index 845bc745706b..ee6982976d66 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -29,6 +29,7 @@ CONFIG_ARCH_OMAP3=y
CONFIG_ARCH_OMAP4=y
CONFIG_SOC_OMAP5=y
CONFIG_SOC_AM33XX=y
+CONFIG_SOC_DRA7XX=y
CONFIG_SOC_AM43XX=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_ARCH_SOCFPGA=y
diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
index 00fe9e9710fd..27d69b558c5d 100644
--- a/arch/arm/configs/tegra_defconfig
+++ b/arch/arm/configs/tegra_defconfig
@@ -204,7 +204,10 @@ CONFIG_MMC_BLOCK_MINORS=16
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_TEGRA=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_LEDS_TRIGGER_ONESHOT=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
diff --git a/arch/arm/include/asm/Kbuild b/arch/arm/include/asm/Kbuild
index 3278afe2c3ab..23e728ecf8ab 100644
--- a/arch/arm/include/asm/Kbuild
+++ b/arch/arm/include/asm/Kbuild
@@ -7,16 +7,19 @@ generic-y += current.h
generic-y += emergency-restart.h
generic-y += errno.h
generic-y += exec.h
+generic-y += hash.h
generic-y += ioctl.h
generic-y += ipcbuf.h
generic-y += irq_regs.h
generic-y += kdebug.h
generic-y += local.h
generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += msgbuf.h
generic-y += param.h
generic-y += parport.h
generic-y += poll.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += sections.h
generic-y += segment.h
@@ -33,5 +36,3 @@ generic-y += termios.h
generic-y += timex.h
generic-y += trace_clock.h
generic-y += unaligned.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index e9a49fe0284e..8b8b61685a34 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -212,6 +212,7 @@ extern void copy_to_user_page(struct vm_area_struct *, struct page *,
static inline void __flush_icache_all(void)
{
__flush_icache_preferred();
+ dsb();
}
/*
diff --git a/arch/arm/include/asm/dma-iommu.h b/arch/arm/include/asm/dma-iommu.h
index a8c56acc8c98..eec0a12c5c1d 100644
--- a/arch/arm/include/asm/dma-iommu.h
+++ b/arch/arm/include/asm/dma-iommu.h
@@ -13,9 +13,12 @@ struct dma_iommu_mapping {
/* iommu specific data */
struct iommu_domain *domain;
- void *bitmap;
- size_t bits;
- unsigned int order;
+ unsigned long **bitmaps; /* array of bitmaps */
+ unsigned int nr_bitmaps; /* nr of elements in array */
+ unsigned int extensions;
+ size_t bitmap_size; /* size of a single bitmap */
+ size_t bits; /* per bitmap */
+ unsigned int size; /* per bitmap */
dma_addr_t base;
spinlock_t lock;
@@ -23,8 +26,7 @@ struct dma_iommu_mapping {
};
struct dma_iommu_mapping *
-arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size,
- int order);
+arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size);
void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping);
diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h
index 1d3153c7eb41..816db0bf2dd8 100644
--- a/arch/arm/include/asm/kvm_arm.h
+++ b/arch/arm/include/asm/kvm_arm.h
@@ -55,6 +55,7 @@
* The bits we set in HCR:
* TAC: Trap ACTLR
* TSC: Trap SMC
+ * TVM: Trap VM ops (until MMU and caches are on)
* TSW: Trap cache operations by set/way
* TWI: Trap WFI
* TWE: Trap WFE
@@ -68,8 +69,7 @@
*/
#define HCR_GUEST_MASK (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | \
HCR_FB | HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | \
- HCR_TWE | HCR_SWIO | HCR_TIDCP)
-#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
+ HCR_TVM | HCR_TWE | HCR_SWIO | HCR_TIDCP)
/* System Control Register (SCTLR) bits */
#define SCTLR_TE (1 << 30)
diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
index 661da11f76f4..53b3c4a50d5c 100644
--- a/arch/arm/include/asm/kvm_asm.h
+++ b/arch/arm/include/asm/kvm_asm.h
@@ -48,7 +48,9 @@
#define c13_TID_URO 26 /* Thread ID, User R/O */
#define c13_TID_PRIV 27 /* Thread ID, Privileged */
#define c14_CNTKCTL 28 /* Timer Control Register (PL1) */
-#define NR_CP15_REGS 29 /* Number of regs (incl. invalid) */
+#define c10_AMAIR0 29 /* Auxilary Memory Attribute Indirection Reg0 */
+#define c10_AMAIR1 30 /* Auxilary Memory Attribute Indirection Reg1 */
+#define NR_CP15_REGS 31 /* Number of regs (incl. invalid) */
#define ARM_EXCEPTION_RESET 0
#define ARM_EXCEPTION_UNDEFINED 1
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 098f7dd6d564..09af14999c9b 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -101,6 +101,12 @@ struct kvm_vcpu_arch {
/* The CPU type we expose to the VM */
u32 midr;
+ /* HYP trapping configuration */
+ u32 hcr;
+
+ /* Interrupt related fields */
+ u32 irq_lines; /* IRQ and FIQ levels */
+
/* Exception Information */
struct kvm_vcpu_fault_info fault;
@@ -128,9 +134,6 @@ struct kvm_vcpu_arch {
/* IO related fields */
struct kvm_decode mmio_decode;
- /* Interrupt related fields */
- u32 irq_lines; /* IRQ and FIQ levels */
-
/* Cache some mmu pages needed inside spinlock regions */
struct kvm_mmu_memory_cache mmu_page_cache;
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index 2d122adcdb22..5c7aa3c1519f 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -114,11 +114,34 @@ static inline void kvm_set_s2pmd_writable(pmd_t *pmd)
pmd_val(*pmd) |= L_PMD_S2_RDWR;
}
+/* Open coded p*d_addr_end that can deal with 64bit addresses */
+#define kvm_pgd_addr_end(addr, end) \
+({ u64 __boundary = ((addr) + PGDIR_SIZE) & PGDIR_MASK; \
+ (__boundary - 1 < (end) - 1)? __boundary: (end); \
+})
+
+#define kvm_pud_addr_end(addr,end) (end)
+
+#define kvm_pmd_addr_end(addr, end) \
+({ u64 __boundary = ((addr) + PMD_SIZE) & PMD_MASK; \
+ (__boundary - 1 < (end) - 1)? __boundary: (end); \
+})
+
struct kvm;
-static inline void coherent_icache_guest_page(struct kvm *kvm, hva_t hva,
- unsigned long size)
+#define kvm_flush_dcache_to_poc(a,l) __cpuc_flush_dcache_area((a), (l))
+
+static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
{
+ return (vcpu->arch.cp15[c1_SCTLR] & 0b101) == 0b101;
+}
+
+static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva,
+ unsigned long size)
+{
+ if (!vcpu_has_cache_enabled(vcpu))
+ kvm_flush_dcache_to_poc((void *)hva, size);
+
/*
* If we are going to insert an instruction page and the icache is
* either VIPT or PIPT, there is a potential problem where the host
@@ -139,9 +162,10 @@ static inline void coherent_icache_guest_page(struct kvm *kvm, hva_t hva,
}
}
-#define kvm_flush_dcache_to_poc(a,l) __cpuc_flush_dcache_area((a), (l))
#define kvm_virt_to_phys(x) virt_to_idmap((unsigned long)(x))
+void stage2_flush_vm(struct kvm *kvm);
+
#endif /* !__ASSEMBLY__ */
#endif /* __ARM_KVM_MMU_H__ */
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index 8756e4bcdba0..4afb376d9c7c 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -30,14 +30,15 @@
*/
#define UL(x) _AC(x, UL)
+/* PAGE_OFFSET - the virtual address of the start of the kernel image */
+#define PAGE_OFFSET UL(CONFIG_PAGE_OFFSET)
+
#ifdef CONFIG_MMU
/*
- * PAGE_OFFSET - the virtual address of the start of the kernel image
* TASK_SIZE - the maximum size of a user space task.
* TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area
*/
-#define PAGE_OFFSET UL(CONFIG_PAGE_OFFSET)
#define TASK_SIZE (UL(CONFIG_PAGE_OFFSET) - UL(SZ_16M))
#define TASK_UNMAPPED_BASE ALIGN(TASK_SIZE / 3, SZ_16M)
@@ -104,10 +105,6 @@
#define END_MEM (UL(CONFIG_DRAM_BASE) + CONFIG_DRAM_SIZE)
#endif
-#ifndef PAGE_OFFSET
-#define PAGE_OFFSET PLAT_PHYS_OFFSET
-#endif
-
/*
* The module can be at any place in ram in nommu mode.
*/
diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h
index 03243f7eeddf..85c60adc8b60 100644
--- a/arch/arm/include/asm/pgtable-3level.h
+++ b/arch/arm/include/asm/pgtable-3level.h
@@ -120,13 +120,16 @@
/*
* 2nd stage PTE definitions for LPAE.
*/
-#define L_PTE_S2_MT_UNCACHED (_AT(pteval_t, 0x5) << 2) /* MemAttr[3:0] */
-#define L_PTE_S2_MT_WRITETHROUGH (_AT(pteval_t, 0xa) << 2) /* MemAttr[3:0] */
-#define L_PTE_S2_MT_WRITEBACK (_AT(pteval_t, 0xf) << 2) /* MemAttr[3:0] */
-#define L_PTE_S2_RDONLY (_AT(pteval_t, 1) << 6) /* HAP[1] */
-#define L_PTE_S2_RDWR (_AT(pteval_t, 3) << 6) /* HAP[2:1] */
+#define L_PTE_S2_MT_UNCACHED (_AT(pteval_t, 0x0) << 2) /* strongly ordered */
+#define L_PTE_S2_MT_WRITETHROUGH (_AT(pteval_t, 0xa) << 2) /* normal inner write-through */
+#define L_PTE_S2_MT_WRITEBACK (_AT(pteval_t, 0xf) << 2) /* normal inner write-back */
+#define L_PTE_S2_MT_DEV_SHARED (_AT(pteval_t, 0x1) << 2) /* device */
+#define L_PTE_S2_MT_MASK (_AT(pteval_t, 0xf) << 2)
-#define L_PMD_S2_RDWR (_AT(pmdval_t, 3) << 6) /* HAP[2:1] */
+#define L_PTE_S2_RDONLY (_AT(pteval_t, 1) << 6) /* HAP[1] */
+#define L_PTE_S2_RDWR (_AT(pteval_t, 3) << 6) /* HAP[2:1] */
+
+#define L_PMD_S2_RDWR (_AT(pmdval_t, 3) << 6) /* HAP[2:1] */
/*
* Hyp-mode PL2 PTE definitions for LPAE.
diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h
index ef3c6072aa45..ac4bfae26702 100644
--- a/arch/arm/include/asm/spinlock.h
+++ b/arch/arm/include/asm/spinlock.h
@@ -37,18 +37,9 @@
static inline void dsb_sev(void)
{
-#if __LINUX_ARM_ARCH__ >= 7
- __asm__ __volatile__ (
- "dsb ishst\n"
- SEV
- );
-#else
- __asm__ __volatile__ (
- "mcr p15, 0, %0, c7, c10, 4\n"
- SEV
- : : "r" (0)
- );
-#endif
+
+ dsb(ishst);
+ __asm__(SEV);
}
/*
diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h
index 58b8b84adcd2..2fe85fff5cca 100644
--- a/arch/arm/include/asm/topology.h
+++ b/arch/arm/include/asm/topology.h
@@ -20,9 +20,6 @@ extern struct cputopo_arm cpu_topology[NR_CPUS];
#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling)
#define topology_thread_cpumask(cpu) (&cpu_topology[cpu].thread_sibling)
-#define mc_capable() (cpu_topology[0].socket_id != -1)
-#define smt_capable() (cpu_topology[0].thread_id != -1)
-
void init_cpu_topology(void);
void store_cpu_topology(unsigned int cpuid);
const struct cpumask *cpu_coregroup_mask(int cpu);
diff --git a/arch/arm/include/asm/xen/page.h b/arch/arm/include/asm/xen/page.h
index e0965abacb7d..cf4f3e867395 100644
--- a/arch/arm/include/asm/xen/page.h
+++ b/arch/arm/include/asm/xen/page.h
@@ -97,16 +97,13 @@ static inline pte_t *lookup_address(unsigned long address, unsigned int *level)
return NULL;
}
-static inline int m2p_add_override(unsigned long mfn, struct page *page,
- struct gnttab_map_grant_ref *kmap_op)
-{
- return 0;
-}
+extern int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops,
+ struct gnttab_map_grant_ref *kmap_ops,
+ struct page **pages, unsigned int count);
-static inline int m2p_remove_override(struct page *page, bool clear_pte)
-{
- return 0;
-}
+extern int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops,
+ struct gnttab_map_grant_ref *kmap_ops,
+ struct page **pages, unsigned int count);
bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
bool __set_phys_to_machine_multi(unsigned long pfn, unsigned long mfn,
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index ded041711beb..85598b5d1efd 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -174,6 +174,7 @@ int main(void)
DEFINE(VCPU_FIQ_REGS, offsetof(struct kvm_vcpu, arch.regs.fiq_regs));
DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.regs.usr_regs.ARM_pc));
DEFINE(VCPU_CPSR, offsetof(struct kvm_vcpu, arch.regs.usr_regs.ARM_cpsr));
+ DEFINE(VCPU_HCR, offsetof(struct kvm_vcpu, arch.hcr));
DEFINE(VCPU_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines));
DEFINE(VCPU_HSR, offsetof(struct kvm_vcpu, arch.fault.hsr));
DEFINE(VCPU_HxFAR, offsetof(struct kvm_vcpu, arch.fault.hxfar));
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 317da88ae65b..d0d46786892c 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -19,7 +19,7 @@
static int debug_pci;
/*
- * We can't use pci_find_device() here since we are
+ * We can't use pci_get_device() here since we are
* called from interrupt context.
*/
static void pcibios_bus_report_status(struct pci_bus *bus, u_int status_mask, int warn)
@@ -57,13 +57,10 @@ static void pcibios_bus_report_status(struct pci_bus *bus, u_int status_mask, in
void pcibios_report_status(u_int status_mask, int warn)
{
- struct list_head *l;
-
- list_for_each(l, &pci_root_buses) {
- struct pci_bus *bus = pci_bus_b(l);
+ struct pci_bus *bus;
+ list_for_each_entry(bus, &pci_root_buses, node)
pcibios_bus_report_status(bus, status_mask, warn);
- }
}
/*
diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c
index 34e56647dcee..c108ddcb9ba4 100644
--- a/arch/arm/kernel/ftrace.c
+++ b/arch/arm/kernel/ftrace.c
@@ -156,10 +156,8 @@ int ftrace_make_nop(struct module *mod,
return ret;
}
-int __init ftrace_dyn_arch_init(void *data)
+int __init ftrace_dyn_arch_init(void)
{
- *(unsigned long *)data = 0;
-
return 0;
}
#endif /* CONFIG_DYNAMIC_FTRACE */
diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S
index 47cd974e57ea..c96ecacb2021 100644
--- a/arch/arm/kernel/head-common.S
+++ b/arch/arm/kernel/head-common.S
@@ -177,6 +177,18 @@ __lookup_processor_type_data:
.long __proc_info_end
.size __lookup_processor_type_data, . - __lookup_processor_type_data
+__error_lpae:
+#ifdef CONFIG_DEBUG_LL
+ adr r0, str_lpae
+ bl printascii
+ b __error
+str_lpae: .asciz "\nError: Kernel with LPAE support, but CPU does not support LPAE.\n"
+#else
+ b __error
+#endif
+ .align
+ENDPROC(__error_lpae)
+
__error_p:
#ifdef CONFIG_DEBUG_LL
adr r0, str_p1
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 914616e0bdcd..f5f381d91556 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -102,7 +102,7 @@ ENTRY(stext)
and r3, r3, #0xf @ extract VMSA support
cmp r3, #5 @ long-descriptor translation table format?
THUMB( it lo ) @ force fixup-able long branch encoding
- blo __error_p @ only classic page table format
+ blo __error_lpae @ only classic page table format
#endif
#ifndef CONFIG_XIP_KERNEL
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 92f7b15dd221..adabeababeb0 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -30,7 +30,6 @@
#include <linux/uaccess.h>
#include <linux/random.h>
#include <linux/hw_breakpoint.h>
-#include <linux/cpuidle.h>
#include <linux/leds.h>
#include <linux/reboot.h>
@@ -133,7 +132,11 @@ EXPORT_SYMBOL_GPL(arm_pm_restart);
void (*arm_pm_idle)(void);
-static void default_idle(void)
+/*
+ * Called from the core idle loop.
+ */
+
+void arch_cpu_idle(void)
{
if (arm_pm_idle)
arm_pm_idle();
@@ -168,15 +171,6 @@ void arch_cpu_idle_dead(void)
#endif
/*
- * Called from the core idle loop.
- */
-void arch_cpu_idle(void)
-{
- if (cpuidle_idle_call())
- default_idle();
-}
-
-/*
* Called by kexec, immediately prior to machine_kexec().
*
* This must completely disable all secondary CPUs; simply causing those CPUs
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index b0df9761de6d..1e8b030dbefd 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -731,7 +731,7 @@ static void __init request_standard_resources(const struct machine_desc *mdesc)
kernel_data.end = virt_to_phys(_end - 1);
for_each_memblock(memory, region) {
- res = memblock_virt_alloc_low(sizeof(*res), 0);
+ res = memblock_virt_alloc(sizeof(*res), 0);
res->name = "System RAM";
res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index b7b4c86e338b..7c4fada440f0 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -674,8 +674,7 @@ static int cpufreq_callback(struct notifier_block *nb,
}
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
- (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
- (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
+ (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
loops_per_jiffy = cpufreq_scale(global_l_p_j_ref,
global_l_p_j_ref_freq,
freq->new);
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 6591e26fc13f..dfc32130bc44 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -166,7 +166,7 @@ static int twd_cpufreq_transition(struct notifier_block *nb,
* frequency. The timer is local to a cpu, so cross-call to the
* changing cpu.
*/
- if (state == CPUFREQ_POSTCHANGE || state == CPUFREQ_RESUMECHANGE)
+ if (state == CPUFREQ_POSTCHANGE)
smp_call_function_single(freqs->cpu, twd_update_frequency,
NULL, 1);
diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c
index 3e94811690ce..702bd329d9d0 100644
--- a/arch/arm/kernel/sys_oabi-compat.c
+++ b/arch/arm/kernel/sys_oabi-compat.c
@@ -203,6 +203,9 @@ asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd,
int ret;
switch (cmd) {
+ case F_GETLKP:
+ case F_SETLKP:
+ case F_SETLKPW:
case F_GETLK64:
case F_SETLK64:
case F_SETLKW64:
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 1d8248ea5669..bd18bb8b2770 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -878,7 +878,8 @@ static int hyp_init_cpu_pm_notifier(struct notifier_block *self,
unsigned long cmd,
void *v)
{
- if (cmd == CPU_PM_EXIT) {
+ if (cmd == CPU_PM_EXIT &&
+ __hyp_get_vectors() == hyp_default_vectors) {
cpu_init_hyp_mode(NULL);
return NOTIFY_OK;
}
diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
index 78c0885d6501..c58a35116f63 100644
--- a/arch/arm/kvm/coproc.c
+++ b/arch/arm/kvm/coproc.c
@@ -23,6 +23,7 @@
#include <asm/kvm_host.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_coproc.h>
+#include <asm/kvm_mmu.h>
#include <asm/cacheflush.h>
#include <asm/cputype.h>
#include <trace/events/kvm.h>
@@ -205,6 +206,44 @@ done:
}
/*
+ * Generic accessor for VM registers. Only called as long as HCR_TVM
+ * is set.
+ */
+static bool access_vm_reg(struct kvm_vcpu *vcpu,
+ const struct coproc_params *p,
+ const struct coproc_reg *r)
+{
+ BUG_ON(!p->is_write);
+
+ vcpu->arch.cp15[r->reg] = *vcpu_reg(vcpu, p->Rt1);
+ if (p->is_64bit)
+ vcpu->arch.cp15[r->reg + 1] = *vcpu_reg(vcpu, p->Rt2);
+
+ return true;
+}
+
+/*
+ * SCTLR accessor. Only called as long as HCR_TVM is set. If the
+ * guest enables the MMU, we stop trapping the VM sys_regs and leave
+ * it in complete control of the caches.
+ *
+ * Used by the cpu-specific code.
+ */
+bool access_sctlr(struct kvm_vcpu *vcpu,
+ const struct coproc_params *p,
+ const struct coproc_reg *r)
+{
+ access_vm_reg(vcpu, p, r);
+
+ if (vcpu_has_cache_enabled(vcpu)) { /* MMU+Caches enabled? */
+ vcpu->arch.hcr &= ~HCR_TVM;
+ stage2_flush_vm(vcpu->kvm);
+ }
+
+ return true;
+}
+
+/*
* We could trap ID_DFR0 and tell the guest we don't support performance
* monitoring. Unfortunately the patch to make the kernel check ID_DFR0 was
* NAKed, so it will read the PMCR anyway.
@@ -261,33 +300,36 @@ static const struct coproc_reg cp15_regs[] = {
{ CRn( 1), CRm( 0), Op1( 0), Op2( 2), is32,
NULL, reset_val, c1_CPACR, 0x00000000 },
- /* TTBR0/TTBR1: swapped by interrupt.S. */
- { CRm64( 2), Op1( 0), is64, NULL, reset_unknown64, c2_TTBR0 },
- { CRm64( 2), Op1( 1), is64, NULL, reset_unknown64, c2_TTBR1 },
-
- /* TTBCR: swapped by interrupt.S. */
+ /* TTBR0/TTBR1/TTBCR: swapped by interrupt.S. */
+ { CRm64( 2), Op1( 0), is64, access_vm_reg, reset_unknown64, c2_TTBR0 },
+ { CRn(2), CRm( 0), Op1( 0), Op2( 0), is32,
+ access_vm_reg, reset_unknown, c2_TTBR0 },
+ { CRn(2), CRm( 0), Op1( 0), Op2( 1), is32,
+ access_vm_reg, reset_unknown, c2_TTBR1 },
{ CRn( 2), CRm( 0), Op1( 0), Op2( 2), is32,
- NULL, reset_val, c2_TTBCR, 0x00000000 },
+ access_vm_reg, reset_val, c2_TTBCR, 0x00000000 },
+ { CRm64( 2), Op1( 1), is64, access_vm_reg, reset_unknown64, c2_TTBR1 },
+
/* DACR: swapped by interrupt.S. */
{ CRn( 3), CRm( 0), Op1( 0), Op2( 0), is32,
- NULL, reset_unknown, c3_DACR },
+ access_vm_reg, reset_unknown, c3_DACR },
/* DFSR/IFSR/ADFSR/AIFSR: swapped by interrupt.S. */
{ CRn( 5), CRm( 0), Op1( 0), Op2( 0), is32,
- NULL, reset_unknown, c5_DFSR },
+ access_vm_reg, reset_unknown, c5_DFSR },
{ CRn( 5), CRm( 0), Op1( 0), Op2( 1), is32,
- NULL, reset_unknown, c5_IFSR },
+ access_vm_reg, reset_unknown, c5_IFSR },
{ CRn( 5), CRm( 1), Op1( 0), Op2( 0), is32,
- NULL, reset_unknown, c5_ADFSR },
+ access_vm_reg, reset_unknown, c5_ADFSR },
{ CRn( 5), CRm( 1), Op1( 0), Op2( 1), is32,
- NULL, reset_unknown, c5_AIFSR },
+ access_vm_reg, reset_unknown, c5_AIFSR },
/* DFAR/IFAR: swapped by interrupt.S. */
{ CRn( 6), CRm( 0), Op1( 0), Op2( 0), is32,
- NULL, reset_unknown, c6_DFAR },
+ access_vm_reg, reset_unknown, c6_DFAR },
{ CRn( 6), CRm( 0), Op1( 0), Op2( 2), is32,
- NULL, reset_unknown, c6_IFAR },
+ access_vm_reg, reset_unknown, c6_IFAR },
/* PAR swapped by interrupt.S */
{ CRm64( 7), Op1( 0), is64, NULL, reset_unknown64, c7_PAR },
@@ -324,9 +366,15 @@ static const struct coproc_reg cp15_regs[] = {
/* PRRR/NMRR (aka MAIR0/MAIR1): swapped by interrupt.S. */
{ CRn(10), CRm( 2), Op1( 0), Op2( 0), is32,
- NULL, reset_unknown, c10_PRRR},
+ access_vm_reg, reset_unknown, c10_PRRR},
{ CRn(10), CRm( 2), Op1( 0), Op2( 1), is32,
- NULL, reset_unknown, c10_NMRR},
+ access_vm_reg, reset_unknown, c10_NMRR},
+
+ /* AMAIR0/AMAIR1: swapped by interrupt.S. */
+ { CRn(10), CRm( 3), Op1( 0), Op2( 0), is32,
+ access_vm_reg, reset_unknown, c10_AMAIR0},
+ { CRn(10), CRm( 3), Op1( 0), Op2( 1), is32,
+ access_vm_reg, reset_unknown, c10_AMAIR1},
/* VBAR: swapped by interrupt.S. */
{ CRn(12), CRm( 0), Op1( 0), Op2( 0), is32,
@@ -334,7 +382,7 @@ static const struct coproc_reg cp15_regs[] = {
/* CONTEXTIDR/TPIDRURW/TPIDRURO/TPIDRPRW: swapped by interrupt.S. */
{ CRn(13), CRm( 0), Op1( 0), Op2( 1), is32,
- NULL, reset_val, c13_CID, 0x00000000 },
+ access_vm_reg, reset_val, c13_CID, 0x00000000 },
{ CRn(13), CRm( 0), Op1( 0), Op2( 2), is32,
NULL, reset_unknown, c13_TID_URW },
{ CRn(13), CRm( 0), Op1( 0), Op2( 3), is32,
@@ -443,7 +491,7 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
struct coproc_params params;
- params.CRm = (kvm_vcpu_get_hsr(vcpu) >> 1) & 0xf;
+ params.CRn = (kvm_vcpu_get_hsr(vcpu) >> 1) & 0xf;
params.Rt1 = (kvm_vcpu_get_hsr(vcpu) >> 5) & 0xf;
params.is_write = ((kvm_vcpu_get_hsr(vcpu) & 1) == 0);
params.is_64bit = true;
@@ -451,7 +499,7 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
params.Op1 = (kvm_vcpu_get_hsr(vcpu) >> 16) & 0xf;
params.Op2 = 0;
params.Rt2 = (kvm_vcpu_get_hsr(vcpu) >> 10) & 0xf;
- params.CRn = 0;
+ params.CRm = 0;
return emulate_cp15(vcpu, &params);
}
diff --git a/arch/arm/kvm/coproc.h b/arch/arm/kvm/coproc.h
index 0461d5c8d3de..1a44bbe39643 100644
--- a/arch/arm/kvm/coproc.h
+++ b/arch/arm/kvm/coproc.h
@@ -58,8 +58,8 @@ static inline void print_cp_instr(const struct coproc_params *p)
{
/* Look, we even formatted it for you to paste into the table! */
if (p->is_64bit) {
- kvm_pr_unimpl(" { CRm(%2lu), Op1(%2lu), is64, func_%s },\n",
- p->CRm, p->Op1, p->is_write ? "write" : "read");
+ kvm_pr_unimpl(" { CRm64(%2lu), Op1(%2lu), is64, func_%s },\n",
+ p->CRn, p->Op1, p->is_write ? "write" : "read");
} else {
kvm_pr_unimpl(" { CRn(%2lu), CRm(%2lu), Op1(%2lu), Op2(%2lu), is32,"
" func_%s },\n",
@@ -135,13 +135,13 @@ static inline int cmp_reg(const struct coproc_reg *i1,
return -1;
if (i1->CRn != i2->CRn)
return i1->CRn - i2->CRn;
- if (i1->is_64 != i2->is_64)
- return i2->is_64 - i1->is_64;
if (i1->CRm != i2->CRm)
return i1->CRm - i2->CRm;
if (i1->Op1 != i2->Op1)
return i1->Op1 - i2->Op1;
- return i1->Op2 - i2->Op2;
+ if (i1->Op2 != i2->Op2)
+ return i1->Op2 - i2->Op2;
+ return i2->is_64 - i1->is_64;
}
@@ -153,4 +153,8 @@ static inline int cmp_reg(const struct coproc_reg *i1,
#define is64 .is_64 = true
#define is32 .is_64 = false
+bool access_sctlr(struct kvm_vcpu *vcpu,
+ const struct coproc_params *p,
+ const struct coproc_reg *r);
+
#endif /* __ARM_KVM_COPROC_LOCAL_H__ */
diff --git a/arch/arm/kvm/coproc_a15.c b/arch/arm/kvm/coproc_a15.c
index bb0cac1410cc..e6f4ae48bda9 100644
--- a/arch/arm/kvm/coproc_a15.c
+++ b/arch/arm/kvm/coproc_a15.c
@@ -34,7 +34,7 @@
static const struct coproc_reg a15_regs[] = {
/* SCTLR: swapped by interrupt.S. */
{ CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32,
- NULL, reset_val, c1_SCTLR, 0x00C50078 },
+ access_sctlr, reset_val, c1_SCTLR, 0x00C50078 },
};
static struct kvm_coproc_target_table a15_target_table = {
diff --git a/arch/arm/kvm/coproc_a7.c b/arch/arm/kvm/coproc_a7.c
index 1df767331588..17fc7cd479d3 100644
--- a/arch/arm/kvm/coproc_a7.c
+++ b/arch/arm/kvm/coproc_a7.c
@@ -37,7 +37,7 @@
static const struct coproc_reg a7_regs[] = {
/* SCTLR: swapped by interrupt.S. */
{ CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32,
- NULL, reset_val, c1_SCTLR, 0x00C50878 },
+ access_sctlr, reset_val, c1_SCTLR, 0x00C50878 },
};
static struct kvm_coproc_target_table a7_target_table = {
diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
index 2786eae10c0d..b23a59c1c522 100644
--- a/arch/arm/kvm/guest.c
+++ b/arch/arm/kvm/guest.c
@@ -38,6 +38,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
{
+ vcpu->arch.hcr = HCR_GUEST_MASK;
return 0;
}
diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S
index ddc15539bad2..0d68d4073068 100644
--- a/arch/arm/kvm/interrupts.S
+++ b/arch/arm/kvm/interrupts.S
@@ -220,6 +220,10 @@ after_vfp_restore:
* in Hyp mode (see init_hyp_mode in arch/arm/kvm/arm.c). Return values are
* passed in r0 and r1.
*
+ * A function pointer with a value of 0xffffffff has a special meaning,
+ * and is used to implement __hyp_get_vectors in the same way as in
+ * arch/arm/kernel/hyp_stub.S.
+ *
* The calling convention follows the standard AAPCS:
* r0 - r3: caller save
* r12: caller save
@@ -363,6 +367,11 @@ hyp_hvc:
host_switch_to_hyp:
pop {r0, r1, r2}
+ /* Check for __hyp_get_vectors */
+ cmp r0, #-1
+ mrceq p15, 4, r0, c12, c0, 0 @ get HVBAR
+ beq 1f
+
push {lr}
mrs lr, SPSR
push {lr}
@@ -378,7 +387,7 @@ THUMB( orr lr, #1)
pop {lr}
msr SPSR_csxf, lr
pop {lr}
- eret
+1: eret
guest_trap:
load_vcpu @ Load VCPU pointer to r0
diff --git a/arch/arm/kvm/interrupts_head.S b/arch/arm/kvm/interrupts_head.S
index 6f18695a09cb..76af93025574 100644
--- a/arch/arm/kvm/interrupts_head.S
+++ b/arch/arm/kvm/interrupts_head.S
@@ -303,13 +303,17 @@ vcpu .req r0 @ vcpu pointer always in r0
mrc p15, 0, r2, c14, c1, 0 @ CNTKCTL
mrrc p15, 0, r4, r5, c7 @ PAR
+ mrc p15, 0, r6, c10, c3, 0 @ AMAIR0
+ mrc p15, 0, r7, c10, c3, 1 @ AMAIR1
.if \store_to_vcpu == 0
- push {r2,r4-r5}
+ push {r2,r4-r7}
.else
str r2, [vcpu, #CP15_OFFSET(c14_CNTKCTL)]
add r12, vcpu, #CP15_OFFSET(c7_PAR)
strd r4, r5, [r12]
+ str r6, [vcpu, #CP15_OFFSET(c10_AMAIR0)]
+ str r7, [vcpu, #CP15_OFFSET(c10_AMAIR1)]
.endif
.endm
@@ -322,15 +326,19 @@ vcpu .req r0 @ vcpu pointer always in r0
*/
.macro write_cp15_state read_from_vcpu
.if \read_from_vcpu == 0
- pop {r2,r4-r5}
+ pop {r2,r4-r7}
.else
ldr r2, [vcpu, #CP15_OFFSET(c14_CNTKCTL)]
add r12, vcpu, #CP15_OFFSET(c7_PAR)
ldrd r4, r5, [r12]
+ ldr r6, [vcpu, #CP15_OFFSET(c10_AMAIR0)]
+ ldr r7, [vcpu, #CP15_OFFSET(c10_AMAIR1)]
.endif
mcr p15, 0, r2, c14, c1, 0 @ CNTKCTL
mcrr p15, 0, r4, r5, c7 @ PAR
+ mcr p15, 0, r6, c10, c3, 0 @ AMAIR0
+ mcr p15, 0, r7, c10, c3, 1 @ AMAIR1
.if \read_from_vcpu == 0
pop {r2-r12}
@@ -597,17 +605,14 @@ vcpu .req r0 @ vcpu pointer always in r0
/* Enable/Disable: stage-2 trans., trap interrupts, trap wfi, trap smc */
.macro configure_hyp_role operation
- mrc p15, 4, r2, c1, c1, 0 @ HCR
- bic r2, r2, #HCR_VIRT_EXCP_MASK
- ldr r3, =HCR_GUEST_MASK
.if \operation == vmentry
- orr r2, r2, r3
+ ldr r2, [vcpu, #VCPU_HCR]
ldr r3, [vcpu, #VCPU_IRQ_LINES]
orr r2, r2, r3
.else
- bic r2, r2, r3
+ mov r2, #0
.endif
- mcr p15, 4, r2, c1, c1, 0
+ mcr p15, 4, r2, c1, c1, 0 @ HCR
.endm
.macro load_vcpu
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 7789857d1470..80bb1e6c2c29 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -144,8 +144,9 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
while (addr < end) {
pgd = pgdp + pgd_index(addr);
pud = pud_offset(pgd, addr);
+ pte = NULL;
if (pud_none(*pud)) {
- addr = pud_addr_end(addr, end);
+ addr = kvm_pud_addr_end(addr, end);
continue;
}
@@ -155,13 +156,13 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
* move on.
*/
clear_pud_entry(kvm, pud, addr);
- addr = pud_addr_end(addr, end);
+ addr = kvm_pud_addr_end(addr, end);
continue;
}
pmd = pmd_offset(pud, addr);
if (pmd_none(*pmd)) {
- addr = pmd_addr_end(addr, end);
+ addr = kvm_pmd_addr_end(addr, end);
continue;
}
@@ -174,12 +175,12 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
/*
* If the pmd entry is to be cleared, walk back up the ladder
*/
- if (kvm_pmd_huge(*pmd) || page_empty(pte)) {
+ if (kvm_pmd_huge(*pmd) || (pte && page_empty(pte))) {
clear_pmd_entry(kvm, pmd, addr);
- next = pmd_addr_end(addr, end);
+ next = kvm_pmd_addr_end(addr, end);
if (page_empty(pmd) && !page_empty(pud)) {
clear_pud_entry(kvm, pud, addr);
- next = pud_addr_end(addr, end);
+ next = kvm_pud_addr_end(addr, end);
}
}
@@ -187,6 +188,99 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
}
}
+static void stage2_flush_ptes(struct kvm *kvm, pmd_t *pmd,
+ phys_addr_t addr, phys_addr_t end)
+{
+ pte_t *pte;
+
+ pte = pte_offset_kernel(pmd, addr);
+ do {
+ if (!pte_none(*pte)) {
+ hva_t hva = gfn_to_hva(kvm, addr >> PAGE_SHIFT);
+ kvm_flush_dcache_to_poc((void*)hva, PAGE_SIZE);
+ }
+ } while (pte++, addr += PAGE_SIZE, addr != end);
+}
+
+static void stage2_flush_pmds(struct kvm *kvm, pud_t *pud,
+ phys_addr_t addr, phys_addr_t end)
+{
+ pmd_t *pmd;
+ phys_addr_t next;
+
+ pmd = pmd_offset(pud, addr);
+ do {
+ next = kvm_pmd_addr_end(addr, end);
+ if (!pmd_none(*pmd)) {
+ if (kvm_pmd_huge(*pmd)) {
+ hva_t hva = gfn_to_hva(kvm, addr >> PAGE_SHIFT);
+ kvm_flush_dcache_to_poc((void*)hva, PMD_SIZE);
+ } else {
+ stage2_flush_ptes(kvm, pmd, addr, next);
+ }
+ }
+ } while (pmd++, addr = next, addr != end);
+}
+
+static void stage2_flush_puds(struct kvm *kvm, pgd_t *pgd,
+ phys_addr_t addr, phys_addr_t end)
+{
+ pud_t *pud;
+ phys_addr_t next;
+
+ pud = pud_offset(pgd, addr);
+ do {
+ next = kvm_pud_addr_end(addr, end);
+ if (!pud_none(*pud)) {
+ if (pud_huge(*pud)) {
+ hva_t hva = gfn_to_hva(kvm, addr >> PAGE_SHIFT);
+ kvm_flush_dcache_to_poc((void*)hva, PUD_SIZE);
+ } else {
+ stage2_flush_pmds(kvm, pud, addr, next);
+ }
+ }
+ } while (pud++, addr = next, addr != end);
+}
+
+static void stage2_flush_memslot(struct kvm *kvm,
+ struct kvm_memory_slot *memslot)
+{
+ phys_addr_t addr = memslot->base_gfn << PAGE_SHIFT;
+ phys_addr_t end = addr + PAGE_SIZE * memslot->npages;
+ phys_addr_t next;
+ pgd_t *pgd;
+
+ pgd = kvm->arch.pgd + pgd_index(addr);
+ do {
+ next = kvm_pgd_addr_end(addr, end);
+ stage2_flush_puds(kvm, pgd, addr, next);
+ } while (pgd++, addr = next, addr != end);
+}
+
+/**
+ * stage2_flush_vm - Invalidate cache for pages mapped in stage 2
+ * @kvm: The struct kvm pointer
+ *
+ * Go through the stage 2 page tables and invalidate any cache lines
+ * backing memory already mapped to the VM.
+ */
+void stage2_flush_vm(struct kvm *kvm)
+{
+ struct kvm_memslots *slots;
+ struct kvm_memory_slot *memslot;
+ int idx;
+
+ idx = srcu_read_lock(&kvm->srcu);
+ spin_lock(&kvm->mmu_lock);
+
+ slots = kvm_memslots(kvm);
+ kvm_for_each_memslot(memslot, slots)
+ stage2_flush_memslot(kvm, memslot);
+
+ spin_unlock(&kvm->mmu_lock);
+ srcu_read_unlock(&kvm->srcu, idx);
+}
+
/**
* free_boot_hyp_pgd - free HYP boot page tables
*
@@ -715,7 +809,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
kvm_set_s2pmd_writable(&new_pmd);
kvm_set_pfn_dirty(pfn);
}
- coherent_icache_guest_page(kvm, hva & PMD_MASK, PMD_SIZE);
+ coherent_cache_guest_page(vcpu, hva & PMD_MASK, PMD_SIZE);
ret = stage2_set_pmd_huge(kvm, memcache, fault_ipa, &new_pmd);
} else {
pte_t new_pte = pfn_pte(pfn, PAGE_S2);
@@ -723,7 +817,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
kvm_set_s2pte_writable(&new_pte);
kvm_set_pfn_dirty(pfn);
}
- coherent_icache_guest_page(kvm, hva, PAGE_SIZE);
+ coherent_cache_guest_page(vcpu, hva, PAGE_SIZE);
ret = stage2_set_pte(kvm, memcache, fault_ipa, &new_pte, false);
}
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 2ab00434b2eb..85399c98f84a 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -472,7 +472,7 @@ static struct clk_lookup da850_clks[] = {
CLK("spi_davinci.0", NULL, &spi0_clk),
CLK("spi_davinci.1", NULL, &spi1_clk),
CLK("vpif", NULL, &vpif_clk),
- CLK("ahci", NULL, &sata_clk),
+ CLK("ahci_da850", NULL, &sata_clk),
CLK("davinci-rproc.0", NULL, &dsp_clk),
CLK("ehrpwm", "fck", &ehrpwm_clk),
CLK("ehrpwm", "tbclk", &ehrpwm_tbclk),
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index 0486cdf28c8d..56ea41d5f849 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -1020,7 +1020,6 @@ int __init da8xx_register_spi_bus(int instance, unsigned num_chipselect)
}
#ifdef CONFIG_ARCH_DAVINCI_DA850
-
static struct resource da850_sata_resources[] = {
{
.start = DA850_SATA_BASE,
@@ -1028,103 +1027,22 @@ static struct resource da850_sata_resources[] = {
.flags = IORESOURCE_MEM,
},
{
+ .start = DA8XX_SYSCFG1_BASE + DA8XX_PWRDN_REG,
+ .end = DA8XX_SYSCFG1_BASE + DA8XX_PWRDN_REG + 0x3,
+ .flags = IORESOURCE_MEM,
+ },
+ {
.start = IRQ_DA850_SATAINT,
.flags = IORESOURCE_IRQ,
},
};
-/* SATA PHY Control Register offset from AHCI base */
-#define SATA_P0PHYCR_REG 0x178
-
-#define SATA_PHY_MPY(x) ((x) << 0)
-#define SATA_PHY_LOS(x) ((x) << 6)
-#define SATA_PHY_RXCDR(x) ((x) << 10)
-#define SATA_PHY_RXEQ(x) ((x) << 13)
-#define SATA_PHY_TXSWING(x) ((x) << 19)
-#define SATA_PHY_ENPLL(x) ((x) << 31)
-
-static struct clk *da850_sata_clk;
-static unsigned long da850_sata_refclkpn;
-
-/* Supported DA850 SATA crystal frequencies */
-#define KHZ_TO_HZ(freq) ((freq) * 1000)
-static unsigned long da850_sata_xtal[] = {
- KHZ_TO_HZ(300000),
- KHZ_TO_HZ(250000),
- 0, /* Reserved */
- KHZ_TO_HZ(187500),
- KHZ_TO_HZ(150000),
- KHZ_TO_HZ(125000),
- KHZ_TO_HZ(120000),
- KHZ_TO_HZ(100000),
- KHZ_TO_HZ(75000),
- KHZ_TO_HZ(60000),
-};
-
-static int da850_sata_init(struct device *dev, void __iomem *addr)
-{
- int i, ret;
- unsigned int val;
-
- da850_sata_clk = clk_get(dev, NULL);
- if (IS_ERR(da850_sata_clk))
- return PTR_ERR(da850_sata_clk);
-
- ret = clk_prepare_enable(da850_sata_clk);
- if (ret)
- goto err0;
-
- /* Enable SATA clock receiver */
- val = __raw_readl(DA8XX_SYSCFG1_VIRT(DA8XX_PWRDN_REG));
- val &= ~BIT(0);
- __raw_writel(val, DA8XX_SYSCFG1_VIRT(DA8XX_PWRDN_REG));
-
- /* Get the multiplier needed for 1.5GHz PLL output */
- for (i = 0; i < ARRAY_SIZE(da850_sata_xtal); i++)
- if (da850_sata_xtal[i] == da850_sata_refclkpn)
- break;
-
- if (i == ARRAY_SIZE(da850_sata_xtal)) {
- ret = -EINVAL;
- goto err1;
- }
-
- val = SATA_PHY_MPY(i + 1) |
- SATA_PHY_LOS(1) |
- SATA_PHY_RXCDR(4) |
- SATA_PHY_RXEQ(1) |
- SATA_PHY_TXSWING(3) |
- SATA_PHY_ENPLL(1);
-
- __raw_writel(val, addr + SATA_P0PHYCR_REG);
-
- return 0;
-
-err1:
- clk_disable_unprepare(da850_sata_clk);
-err0:
- clk_put(da850_sata_clk);
- return ret;
-}
-
-static void da850_sata_exit(struct device *dev)
-{
- clk_disable_unprepare(da850_sata_clk);
- clk_put(da850_sata_clk);
-}
-
-static struct ahci_platform_data da850_sata_pdata = {
- .init = da850_sata_init,
- .exit = da850_sata_exit,
-};
-
static u64 da850_sata_dmamask = DMA_BIT_MASK(32);
static struct platform_device da850_sata_device = {
- .name = "ahci",
+ .name = "ahci_da850",
.id = -1,
.dev = {
- .platform_data = &da850_sata_pdata,
.dma_mask = &da850_sata_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
@@ -1134,9 +1052,8 @@ static struct platform_device da850_sata_device = {
int __init da850_register_sata(unsigned long refclkpn)
{
- da850_sata_refclkpn = refclkpn;
- if (!da850_sata_refclkpn)
- return -EINVAL;
+ /* please see comment in drivers/ata/ahci_da850.c */
+ BUG_ON(refclkpn != 100 * 1000 * 1000);
return platform_device_register(&da850_sata_device);
}
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 4c414af75ef0..8d197dcdd2c0 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -36,7 +36,6 @@ config ARCH_EXYNOS5
select HAVE_ARM_SCU if SMP
select HAVE_SMP
select PINCTRL
- select USB_ARCH_HAS_XHCI
help
Samsung EXYNOS5 (Cortex-A15) SoC based systems
diff --git a/arch/arm/mach-hisi/Kconfig b/arch/arm/mach-hisi/Kconfig
index 8f4649b301b2..1abae5f6a418 100644
--- a/arch/arm/mach-hisi/Kconfig
+++ b/arch/arm/mach-hisi/Kconfig
@@ -8,7 +8,7 @@ config ARCH_HI3xxx
select CLKSRC_OF
select GENERIC_CLOCKEVENTS
select HAVE_ARM_SCU
- select HAVE_ARM_TWD
+ select HAVE_ARM_TWD if SMP
select HAVE_SMP
select PINCTRL
select PINCTRL_SINGLE
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index befcaf5d0574..ec419649320f 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -101,11 +101,9 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o
obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o
-ifeq ($(CONFIG_PM),y)
obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o headsmp.o
# i.MX6SL reuses i.MX6Q code
obj-$(CONFIG_SOC_IMX6SL) += pm-imx6q.o headsmp.o
-endif
# i.MX5 based machines
obj-$(CONFIG_MACH_MX51_BABBAGE) += mach-mx51_babbage.o
diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c
index af2e582d2b74..4d677f442539 100644
--- a/arch/arm/mach-imx/clk-imx6q.c
+++ b/arch/arm/mach-imx/clk-imx6q.c
@@ -482,6 +482,9 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
if (IS_ENABLED(CONFIG_PCI_IMX6))
clk_set_parent(clk[lvds1_sel], clk[sata_ref]);
+ /* Set initial power mode */
+ imx6q_set_lpm(WAIT_CLOCKED);
+
np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt");
base = of_iomap(np, 0);
WARN_ON(!base);
diff --git a/arch/arm/mach-imx/clk-imx6sl.c b/arch/arm/mach-imx/clk-imx6sl.c
index 3781a1853998..4c86f3035205 100644
--- a/arch/arm/mach-imx/clk-imx6sl.c
+++ b/arch/arm/mach-imx/clk-imx6sl.c
@@ -266,6 +266,9 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
/* Audio-related clocks configuration */
clk_set_parent(clks[IMX6SL_CLK_SPDIF0_SEL], clks[IMX6SL_CLK_PLL3_PFD3]);
+ /* Set initial power mode */
+ imx6q_set_lpm(WAIT_CLOCKED);
+
np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-gpt");
base = of_iomap(np, 0);
WARN_ON(!base);
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index 59c3b9b26bb4..baf439dc22d8 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -144,13 +144,11 @@ void imx6q_set_chicken_bit(void);
void imx_cpu_die(unsigned int cpu);
int imx_cpu_kill(unsigned int cpu);
-#ifdef CONFIG_PM
void imx6q_pm_init(void);
void imx6q_pm_set_ccm_base(void __iomem *base);
+#ifdef CONFIG_PM
void imx5_pm_init(void);
#else
-static inline void imx6q_pm_init(void) {}
-static inline void imx6q_pm_set_ccm_base(void __iomem *base) {}
static inline void imx5_pm_init(void) {}
#endif
diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c
index b3738e616f19..8f45afe785f8 100644
--- a/arch/arm/mach-imx/mach-mx31moboard.c
+++ b/arch/arm/mach-imx/mach-mx31moboard.c
@@ -128,27 +128,15 @@ static struct platform_device mx31moboard_flash = {
.num_resources = 1,
};
-static int moboard_uart0_init(struct platform_device *pdev)
+static void __init moboard_uart0_init(void)
{
- int ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_CTS1), "uart0-cts-hack");
- if (ret)
- return ret;
-
- ret = gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CTS1), 0);
- if (ret)
+ if (!gpio_request(IOMUX_TO_GPIO(MX31_PIN_CTS1), "uart0-cts-hack")) {
+ gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CTS1), 0);
gpio_free(IOMUX_TO_GPIO(MX31_PIN_CTS1));
-
- return ret;
-}
-
-static void moboard_uart0_exit(struct platform_device *pdev)
-{
- gpio_free(IOMUX_TO_GPIO(MX31_PIN_CTS1));
+ }
}
static const struct imxuart_platform_data uart0_pdata __initconst = {
- .init = moboard_uart0_init,
- .exit = moboard_uart0_exit,
};
static const struct imxuart_platform_data uart4_pdata __initconst = {
@@ -543,6 +531,7 @@ static void __init mx31moboard_init(void)
imx31_add_imx2_wdt();
+ moboard_uart0_init();
imx31_add_imx_uart0(&uart0_pdata);
imx31_add_imx_uart4(&uart4_pdata);
diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c
index 9d47adc078aa..29e3fe6a6669 100644
--- a/arch/arm/mach-imx/pm-imx6q.c
+++ b/arch/arm/mach-imx/pm-imx6q.c
@@ -120,7 +120,7 @@ static void imx6q_enable_wb(bool enable)
int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
{
- struct irq_desc *iomuxc_irq_desc;
+ struct irq_data *iomuxc_irq_data = irq_get_irq_data(32);
u32 val = readl_relaxed(ccm_base + CLPCR);
val &= ~BM_CLPCR_LPM;
@@ -167,10 +167,9 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
* 3) Software should mask IRQ #32 right after CCM Low-Power mode
* is set (set bits 0-1 of CCM_CLPCR).
*/
- iomuxc_irq_desc = irq_to_desc(32);
- imx_gpc_irq_unmask(&iomuxc_irq_desc->irq_data);
+ imx_gpc_irq_unmask(iomuxc_irq_data);
writel_relaxed(val, ccm_base + CLPCR);
- imx_gpc_irq_mask(&iomuxc_irq_desc->irq_data);
+ imx_gpc_irq_mask(iomuxc_irq_data);
return 0;
}
@@ -236,8 +235,6 @@ void __init imx6q_pm_init(void)
regmap_update_bits(gpr, IOMUXC_GPR1, IMX6Q_GPR1_GINT,
IMX6Q_GPR1_GINT);
- /* Set initial power mode */
- imx6q_set_lpm(WAIT_CLOCKED);
suspend_set_ops(&imx6q_pm_ops);
}
diff --git a/arch/arm/mach-mmp/pm-mmp2.c b/arch/arm/mach-mmp/pm-mmp2.c
index 461a191a32d2..43b1a516957f 100644
--- a/arch/arm/mach-mmp/pm-mmp2.c
+++ b/arch/arm/mach-mmp/pm-mmp2.c
@@ -27,22 +27,8 @@
int mmp2_set_wake(struct irq_data *d, unsigned int on)
{
- int irq = d->irq;
- struct irq_desc *desc = irq_to_desc(irq);
unsigned long data = 0;
-
- if (unlikely(irq >= nr_irqs)) {
- pr_err("IRQ nubmers are out of boundary!\n");
- return -EINVAL;
- }
-
- if (on) {
- if (desc->action)
- desc->action->flags |= IRQF_NO_SUSPEND;
- } else {
- if (desc->action)
- desc->action->flags &= ~IRQF_NO_SUSPEND;
- }
+ int irq = d->irq;
/* enable wakeup sources */
switch (irq) {
diff --git a/arch/arm/mach-mmp/pm-pxa910.c b/arch/arm/mach-mmp/pm-pxa910.c
index 48981ca801a5..04c9daf9f8d7 100644
--- a/arch/arm/mach-mmp/pm-pxa910.c
+++ b/arch/arm/mach-mmp/pm-pxa910.c
@@ -27,22 +27,8 @@
int pxa910_set_wake(struct irq_data *data, unsigned int on)
{
- int irq = data->irq;
- struct irq_desc *desc = irq_to_desc(data->irq);
uint32_t awucrm = 0, apcr = 0;
-
- if (unlikely(irq >= nr_irqs)) {
- pr_err("IRQ nubmers are out of boundary!\n");
- return -EINVAL;
- }
-
- if (on) {
- if (desc->action)
- desc->action->flags |= IRQF_NO_SUSPEND;
- } else {
- if (desc->action)
- desc->action->flags &= ~IRQF_NO_SUSPEND;
- }
+ int irq = data->irq;
/* setting wakeup sources */
switch (irq) {
@@ -115,9 +101,11 @@ int pxa910_set_wake(struct irq_data *data, unsigned int on)
if (irq >= IRQ_GPIO_START && irq < IRQ_BOARD_START) {
awucrm = MPMU_AWUCRM_WAKEUP(2);
apcr |= MPMU_APCR_SLPWP2;
- } else
+ } else {
+ /* FIXME: This should return a proper error code ! */
printk(KERN_ERR "Error: no defined wake up source irq: %d\n",
irq);
+ }
}
if (on) {
diff --git a/arch/arm/mach-moxart/Kconfig b/arch/arm/mach-moxart/Kconfig
index ba470d64493b..3795ae28a613 100644
--- a/arch/arm/mach-moxart/Kconfig
+++ b/arch/arm/mach-moxart/Kconfig
@@ -2,7 +2,6 @@ config ARCH_MOXART
bool "MOXA ART SoC" if ARCH_MULTI_V4T
select CPU_FA526
select ARM_DMA_MEM_BUFFERABLE
- select DMA_OF
select USE_OF
select CLKSRC_OF
select CLKSRC_MMIO
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
index 5e269d7263ce..df9e7d270810 100644
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -16,6 +16,7 @@ config ARCH_MVEBU
select ARCH_REQUIRE_GPIOLIB
select MIGHT_HAVE_PCI
select PCI_QUIRKS if PCI
+ select OF_ADDRESS_PCI
if ARCH_MVEBU
diff --git a/arch/arm/mach-omap1/ams-delta-fiq.c b/arch/arm/mach-omap1/ams-delta-fiq.c
index f12a12af3523..d1f12095f315 100644
--- a/arch/arm/mach-omap1/ams-delta-fiq.c
+++ b/arch/arm/mach-omap1/ams-delta-fiq.c
@@ -44,13 +44,10 @@ static unsigned int irq_counter[16];
static irqreturn_t deferred_fiq(int irq, void *dev_id)
{
- struct irq_desc *irq_desc;
- struct irq_chip *irq_chip = NULL;
int gpio, irq_num, fiq_count;
+ struct irq_chip *irq_chip;
- irq_desc = irq_to_desc(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK));
- if (irq_desc)
- irq_chip = irq_desc->irq_data.chip;
+ irq_chip = irq_get_chip(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK));
/*
* For each handled GPIO interrupt, keep calling its interrupt handler
diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
index 91449c5cb70f..85089d821982 100644
--- a/arch/arm/mach-omap1/board-nokia770.c
+++ b/arch/arm/mach-omap1/board-nokia770.c
@@ -156,6 +156,7 @@ static struct omap_usb_config nokia770_usb_config __initdata = {
.register_dev = 1,
.hmc_mode = 16,
.pins[0] = 6,
+ .extcon = "tahvo-usb",
};
#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 653b489479e0..ac4882511749 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -21,7 +21,6 @@ config ARCH_OMAP3
select PM_OPP if PM
select PM_RUNTIME if CPU_IDLE
select SOC_HAS_OMAP2_SDRC
- select USB_ARCH_HAS_EHCI if USB_SUPPORT
config ARCH_OMAP4
bool "TI OMAP4"
@@ -42,7 +41,6 @@ config ARCH_OMAP4
select PL310_ERRATA_727915
select PM_OPP if PM
select PM_RUNTIME if CPU_IDLE
- select USB_ARCH_HAS_EHCI if USB_SUPPORT
select ARM_ERRATA_754322
select ARM_ERRATA_775420
@@ -50,11 +48,12 @@ config SOC_OMAP5
bool "TI OMAP5"
depends on ARCH_MULTI_V7
select ARCH_OMAP2PLUS
+ select ARCH_HAS_OPP
select ARM_CPU_SUSPEND if PM
select ARM_GIC
select CPU_V7
select HAVE_ARM_SCU if SMP
- select HAVE_ARM_TWD if LOCAL_TIMERS
+ select HAVE_ARM_TWD if SMP
select HAVE_SMP
select HAVE_ARM_ARCH_TIMER
select ARM_ERRATA_798181 if SMP
@@ -63,6 +62,7 @@ config SOC_AM33XX
bool "TI AM33XX"
depends on ARCH_MULTI_V7
select ARCH_OMAP2PLUS
+ select ARCH_HAS_OPP
select ARM_CPU_SUSPEND if PM
select CPU_V7
select MULTI_IRQ_HANDLER
@@ -72,6 +72,7 @@ config SOC_AM43XX
depends on ARCH_MULTI_V7
select CPU_V7
select ARCH_OMAP2PLUS
+ select ARCH_HAS_OPP
select MULTI_IRQ_HANDLER
select ARM_GIC
select MACH_OMAP_GENERIC
@@ -80,6 +81,7 @@ config SOC_DRA7XX
bool "TI DRA7XX"
depends on ARCH_MULTI_V7
select ARCH_OMAP2PLUS
+ select ARCH_HAS_OPP
select ARM_CPU_SUSPEND if PM
select ARM_GIC
select CPU_V7
@@ -100,7 +102,6 @@ config ARCH_OMAP2PLUS
select MACH_OMAP_GENERIC
select OMAP_DM_TIMER
select PINCTRL
- select PROC_DEVICETREE if PROC_FS
select SOC_BUS
select SPARSE_IRQ
select TI_PRIV_EDMA
@@ -268,9 +269,6 @@ config MACH_OMAP_3430SDP
default y
select OMAP_PACKAGE_CBB
-config MACH_NOKIA_N800
- bool
-
config MACH_NOKIA_N810
bool
@@ -281,7 +279,6 @@ config MACH_NOKIA_N8X0
bool "Nokia N800/N810"
depends on SOC_OMAP2420
default y
- select MACH_NOKIA_N800
select MACH_NOKIA_N810
select MACH_NOKIA_N810_WIMAX
select OMAP_PACKAGE_ZAC
diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
index 8dd0ec858cf1..018353d88b96 100644
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -16,6 +16,8 @@
*
*/
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
@@ -542,8 +544,22 @@ static struct isp_platform_data cm_t35_isp_pdata = {
.subdevs = cm_t35_isp_subdevs,
};
+static struct regulator_consumer_supply cm_t35_camera_supplies[] = {
+ REGULATOR_SUPPLY("vaa", "3-005d"),
+ REGULATOR_SUPPLY("vdd", "3-005d"),
+};
+
static void __init cm_t35_init_camera(void)
{
+ struct clk *clk;
+
+ clk = clk_register_fixed_rate(NULL, "mt9t001-clkin", NULL, CLK_IS_ROOT,
+ 48000000);
+ clk_register_clkdev(clk, NULL, "3-005d");
+
+ regulator_register_fixed(2, cm_t35_camera_supplies,
+ ARRAY_SIZE(cm_t35_camera_supplies));
+
if (omap3_init_camera(&cm_t35_isp_pdata) < 0)
pr_warn("CM-T3x: Failed registering camera device!\n");
}
diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c
index de1bc6bbe585..cf18340eb3bb 100644
--- a/arch/arm/mach-omap2/board-omap3pandora.c
+++ b/arch/arm/mach-omap2/board-omap3pandora.c
@@ -536,11 +536,13 @@ static struct spi_board_info omap3pandora_spi_board_info[] __initdata = {
static void __init pandora_wl1251_init(void)
{
- struct wl12xx_platform_data pandora_wl1251_pdata;
+ struct wl1251_platform_data pandora_wl1251_pdata;
int ret;
memset(&pandora_wl1251_pdata, 0, sizeof(pandora_wl1251_pdata));
+ pandora_wl1251_pdata.power_gpio = -1;
+
ret = gpio_request_one(PANDORA_WIFI_IRQ_GPIO, GPIOF_IN, "wl1251 irq");
if (ret < 0)
goto fail;
@@ -550,7 +552,7 @@ static void __init pandora_wl1251_init(void)
goto fail_irq;
pandora_wl1251_pdata.use_eeprom = true;
- ret = wl12xx_set_platform_data(&pandora_wl1251_pdata);
+ ret = wl1251_set_platform_data(&pandora_wl1251_pdata);
if (ret < 0)
goto fail_irq;
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index 8760bbe3baab..ddfc8df83c6a 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -84,7 +84,7 @@ enum {
RX51_SPI_MIPID, /* LCD panel */
};
-static struct wl12xx_platform_data wl1251_pdata;
+static struct wl1251_platform_data wl1251_pdata;
static struct tsc2005_platform_data tsc2005_pdata;
#if defined(CONFIG_SENSORS_LIS3_I2C) || defined(CONFIG_SENSORS_LIS3_I2C_MODULE)
@@ -1173,13 +1173,7 @@ static inline void board_smc91x_init(void)
#endif
-static void rx51_wl1251_set_power(bool enable)
-{
- gpio_set_value(RX51_WL1251_POWER_GPIO, enable);
-}
-
static struct gpio rx51_wl1251_gpios[] __initdata = {
- { RX51_WL1251_POWER_GPIO, GPIOF_OUT_INIT_LOW, "wl1251 power" },
{ RX51_WL1251_IRQ_GPIO, GPIOF_IN, "wl1251 irq" },
};
@@ -1196,17 +1190,16 @@ static void __init rx51_init_wl1251(void)
if (irq < 0)
goto err_irq;
- wl1251_pdata.set_power = rx51_wl1251_set_power;
+ wl1251_pdata.power_gpio = RX51_WL1251_POWER_GPIO;
rx51_peripherals_spi_board_info[RX51_SPI_WL1251].irq = irq;
return;
err_irq:
gpio_free(RX51_WL1251_IRQ_GPIO);
- gpio_free(RX51_WL1251_POWER_GPIO);
error:
printk(KERN_ERR "wl1251 board initialisation failed\n");
- wl1251_pdata.set_power = NULL;
+ wl1251_pdata.power_gpio = -1;
/*
* Now rx51_peripherals_spi_board_info[1].irq is zero and
diff --git a/arch/arm/mach-omap2/cclock3xxx_data.c b/arch/arm/mach-omap2/cclock3xxx_data.c
index 3b05aea56d1f..11ed9152e665 100644
--- a/arch/arm/mach-omap2/cclock3xxx_data.c
+++ b/arch/arm/mach-omap2/cclock3xxx_data.c
@@ -433,7 +433,9 @@ static const struct clk_ops dpll4_m5x2_ck_ops = {
.enable = &omap2_dflt_clk_enable,
.disable = &omap2_dflt_clk_disable,
.is_enabled = &omap2_dflt_clk_is_enabled,
+ .set_rate = &omap3_clkoutx2_set_rate,
.recalc_rate = &omap3_clkoutx2_recalc,
+ .round_rate = &omap3_clkoutx2_round_rate,
};
static const struct clk_ops dpll4_m5x2_ck_3630_ops = {
diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c
index 4c158c838d40..01fc710c8181 100644
--- a/arch/arm/mach-omap2/cpuidle44xx.c
+++ b/arch/arm/mach-omap2/cpuidle44xx.c
@@ -23,6 +23,8 @@
#include "prm.h"
#include "clockdomain.h"
+#define MAX_CPUS 2
+
/* Machine specific information */
struct idle_statedata {
u32 cpu_state;
@@ -48,11 +50,11 @@ static struct idle_statedata omap4_idle_data[] = {
},
};
-static struct powerdomain *mpu_pd, *cpu_pd[NR_CPUS];
-static struct clockdomain *cpu_clkdm[NR_CPUS];
+static struct powerdomain *mpu_pd, *cpu_pd[MAX_CPUS];
+static struct clockdomain *cpu_clkdm[MAX_CPUS];
static atomic_t abort_barrier;
-static bool cpu_done[NR_CPUS];
+static bool cpu_done[MAX_CPUS];
static struct idle_statedata *state_ptr = &omap4_idle_data[0];
/* Private functions */
diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c
index 3185ced807c9..3c418ea54bbe 100644
--- a/arch/arm/mach-omap2/dpll3xxx.c
+++ b/arch/arm/mach-omap2/dpll3xxx.c
@@ -623,6 +623,32 @@ void omap3_dpll_deny_idle(struct clk_hw_omap *clk)
/* Clock control for DPLL outputs */
+/* Find the parent DPLL for the given clkoutx2 clock */
+static struct clk_hw_omap *omap3_find_clkoutx2_dpll(struct clk_hw *hw)
+{
+ struct clk_hw_omap *pclk = NULL;
+ struct clk *parent;
+
+ /* Walk up the parents of clk, looking for a DPLL */
+ do {
+ do {
+ parent = __clk_get_parent(hw->clk);
+ hw = __clk_get_hw(parent);
+ } while (hw && (__clk_get_flags(hw->clk) & CLK_IS_BASIC));
+ if (!hw)
+ break;
+ pclk = to_clk_hw_omap(hw);
+ } while (pclk && !pclk->dpll_data);
+
+ /* clk does not have a DPLL as a parent? error in the clock data */
+ if (!pclk) {
+ WARN_ON(1);
+ return NULL;
+ }
+
+ return pclk;
+}
+
/**
* omap3_clkoutx2_recalc - recalculate DPLL X2 output virtual clock rate
* @clk: DPLL output struct clk
@@ -637,27 +663,14 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
unsigned long rate;
u32 v;
struct clk_hw_omap *pclk = NULL;
- struct clk *parent;
if (!parent_rate)
return 0;
- /* Walk up the parents of clk, looking for a DPLL */
- do {
- do {
- parent = __clk_get_parent(hw->clk);
- hw = __clk_get_hw(parent);
- } while (hw && (__clk_get_flags(hw->clk) & CLK_IS_BASIC));
- if (!hw)
- break;
- pclk = to_clk_hw_omap(hw);
- } while (pclk && !pclk->dpll_data);
+ pclk = omap3_find_clkoutx2_dpll(hw);
- /* clk does not have a DPLL as a parent? error in the clock data */
- if (!pclk) {
- WARN_ON(1);
+ if (!pclk)
return 0;
- }
dd = pclk->dpll_data;
@@ -672,6 +685,55 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
return rate;
}
+int omap3_clkoutx2_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ return 0;
+}
+
+long omap3_clkoutx2_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ const struct dpll_data *dd;
+ u32 v;
+ struct clk_hw_omap *pclk = NULL;
+
+ if (!*prate)
+ return 0;
+
+ pclk = omap3_find_clkoutx2_dpll(hw);
+
+ if (!pclk)
+ return 0;
+
+ dd = pclk->dpll_data;
+
+ /* TYPE J does not have a clkoutx2 */
+ if (dd->flags & DPLL_J_TYPE) {
+ *prate = __clk_round_rate(__clk_get_parent(pclk->hw.clk), rate);
+ return *prate;
+ }
+
+ WARN_ON(!dd->enable_mask);
+
+ v = omap2_clk_readl(pclk, dd->control_reg) & dd->enable_mask;
+ v >>= __ffs(dd->enable_mask);
+
+ /* If in bypass, the rate is fixed to the bypass rate*/
+ if (v != OMAP3XXX_EN_DPLL_LOCKED)
+ return *prate;
+
+ if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
+ unsigned long best_parent;
+
+ best_parent = (rate / 2);
+ *prate = __clk_round_rate(__clk_get_parent(hw->clk),
+ best_parent);
+ }
+
+ return *prate * 2;
+}
+
/* OMAP3/4 non-CORE DPLL clkops */
const struct clk_hw_omap_ops clkhwops_omap3_dpll = {
.allow_idle = omap3_dpll_allow_idle,
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index d24926e6340f..ab43755364f5 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1339,7 +1339,7 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
of_property_read_bool(np, "gpmc,time-para-granularity");
}
-#ifdef CONFIG_MTD_NAND
+#if IS_ENABLED(CONFIG_MTD_NAND)
static const char * const nand_xfer_types[] = {
[NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled",
@@ -1429,7 +1429,7 @@ static int gpmc_probe_nand_child(struct platform_device *pdev,
}
#endif
-#ifdef CONFIG_MTD_ONENAND
+#if IS_ENABLED(CONFIG_MTD_ONENAND)
static int gpmc_probe_onenand_child(struct platform_device *pdev,
struct device_node *child)
{
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index d408b15b4fbf..af432b191255 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -179,15 +179,6 @@ static struct map_desc omap34xx_io_desc[] __initdata = {
.length = L4_EMU_34XX_SIZE,
.type = MT_DEVICE
},
-#if defined(CONFIG_DEBUG_LL) && \
- (defined(CONFIG_MACH_OMAP_ZOOM2) || defined(CONFIG_MACH_OMAP_ZOOM3))
- {
- .virtual = ZOOM_UART_VIRT,
- .pfn = __phys_to_pfn(ZOOM_UART_BASE),
- .length = SZ_1M,
- .type = MT_DEVICE
- },
-#endif
};
#endif
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 42d81885c700..1f33f5db10d5 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -1947,29 +1947,31 @@ static int _ocp_softreset(struct omap_hwmod *oh)
goto dis_opt_clks;
_write_sysconfig(v, oh);
- ret = _clear_softreset(oh, &v);
- if (ret)
- goto dis_opt_clks;
-
- _write_sysconfig(v, oh);
if (oh->class->sysc->srst_udelay)
udelay(oh->class->sysc->srst_udelay);
c = _wait_softreset_complete(oh);
- if (c == MAX_MODULE_SOFTRESET_WAIT)
+ if (c == MAX_MODULE_SOFTRESET_WAIT) {
pr_warning("omap_hwmod: %s: softreset failed (waited %d usec)\n",
oh->name, MAX_MODULE_SOFTRESET_WAIT);
- else
+ ret = -ETIMEDOUT;
+ goto dis_opt_clks;
+ } else {
pr_debug("omap_hwmod: %s: softreset in %d usec\n", oh->name, c);
+ }
+
+ ret = _clear_softreset(oh, &v);
+ if (ret)
+ goto dis_opt_clks;
+
+ _write_sysconfig(v, oh);
/*
* XXX add _HWMOD_STATE_WEDGED for modules that don't come back from
* _wait_target_ready() or _reset()
*/
- ret = (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0;
-
dis_opt_clks:
if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
_disable_optional_clocks(oh);
diff --git a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
index 18f333c440db..810c205d668b 100644
--- a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
@@ -1365,11 +1365,10 @@ static struct omap_hwmod_class_sysconfig dra7xx_spinlock_sysc = {
.rev_offs = 0x0000,
.sysc_offs = 0x0010,
.syss_offs = 0x0014,
- .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
- SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
- SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
- .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
- SIDLE_SMART_WKUP),
+ .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
+ SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+ SYSS_HAS_RESET_STATUS),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
.sysc_fields = &omap_hwmod_sysc_type1,
};
diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
index 3d5b24dcd9a4..c33e07e2f0d4 100644
--- a/arch/arm/mach-omap2/pdata-quirks.c
+++ b/arch/arm/mach-omap2/pdata-quirks.c
@@ -22,6 +22,8 @@
#include "common-board-devices.h"
#include "dss-common.h"
#include "control.h"
+#include "omap-secure.h"
+#include "soc.h"
struct pdata_init {
const char *compatible;
@@ -169,6 +171,22 @@ static void __init am3517_evm_legacy_init(void)
omap_ctrl_writel(v, AM35XX_CONTROL_IP_SW_RESET);
omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET); /* OCP barrier */
}
+
+static void __init nokia_n900_legacy_init(void)
+{
+ hsmmc2_internal_input_clk();
+
+ if (omap_type() == OMAP2_DEVICE_TYPE_SEC) {
+ if (IS_ENABLED(CONFIG_ARM_ERRATA_430973)) {
+ pr_info("RX-51: Enabling ARM errata 430973 workaround\n");
+ /* set IBE to 1 */
+ rx51_secure_update_aux_cr(BIT(6), 0);
+ } else {
+ pr_warning("RX-51: Not enabling ARM errata 430973 workaround\n");
+ pr_warning("Thumb binaries may crash randomly without this workaround\n");
+ }
+ }
+}
#endif /* CONFIG_ARCH_OMAP3 */
#ifdef CONFIG_ARCH_OMAP4
@@ -239,6 +257,7 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
#endif
#ifdef CONFIG_ARCH_OMAP3
OF_DEV_AUXDATA("ti,omap3-padconf", 0x48002030, "48002030.pinmux", &pcs_pdata),
+ OF_DEV_AUXDATA("ti,omap3-padconf", 0x480025a0, "480025a0.pinmux", &pcs_pdata),
OF_DEV_AUXDATA("ti,omap3-padconf", 0x48002a00, "48002a00.pinmux", &pcs_pdata),
/* Only on am3517 */
OF_DEV_AUXDATA("ti,davinci_mdio", 0x5c030000, "davinci_mdio.0", NULL),
@@ -259,7 +278,7 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
static struct pdata_init pdata_quirks[] __initdata = {
#ifdef CONFIG_ARCH_OMAP3
{ "compulab,omap3-sbc-t3730", omap3_sbc_t3730_legacy_init, },
- { "nokia,omap3-n900", hsmmc2_internal_input_clk, },
+ { "nokia,omap3-n900", nokia_n900_legacy_init, },
{ "nokia,omap3-n9", hsmmc2_internal_input_clk, },
{ "nokia,omap3-n950", hsmmc2_internal_input_clk, },
{ "isee,omap3-igep0020", omap3_igep0020_legacy_init, },
diff --git a/arch/arm/mach-omap2/prminst44xx.c b/arch/arm/mach-omap2/prminst44xx.c
index 6334b96b4097..280f3c58abe5 100644
--- a/arch/arm/mach-omap2/prminst44xx.c
+++ b/arch/arm/mach-omap2/prminst44xx.c
@@ -183,11 +183,11 @@ void omap4_prminst_global_warm_sw_reset(void)
OMAP4_PRM_RSTCTRL_OFFSET);
v |= OMAP4430_RST_GLOBAL_WARM_SW_MASK;
omap4_prminst_write_inst_reg(v, OMAP4430_PRM_PARTITION,
- OMAP4430_PRM_DEVICE_INST,
+ dev_inst,
OMAP4_PRM_RSTCTRL_OFFSET);
/* OCP barrier */
v = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
- OMAP4430_PRM_DEVICE_INST,
+ dev_inst,
OMAP4_PRM_RSTCTRL_OFFSET);
}
diff --git a/arch/arm/mach-pxa/am300epd.c b/arch/arm/mach-pxa/am300epd.c
index c9f309ae88c5..8b90c4f2d430 100644
--- a/arch/arm/mach-pxa/am300epd.c
+++ b/arch/arm/mach-pxa/am300epd.c
@@ -30,6 +30,7 @@
#include <mach/gumstix.h>
#include <mach/mfp-pxa25x.h>
+#include <mach/irqs.h>
#include <linux/platform_data/video-pxafb.h>
#include "generic.h"
diff --git a/arch/arm/mach-pxa/include/mach/balloon3.h b/arch/arm/mach-pxa/include/mach/balloon3.h
index 954641e6c8b1..1b0825911e62 100644
--- a/arch/arm/mach-pxa/include/mach/balloon3.h
+++ b/arch/arm/mach-pxa/include/mach/balloon3.h
@@ -14,6 +14,8 @@
#ifndef ASM_ARCH_BALLOON3_H
#define ASM_ARCH_BALLOON3_H
+#include "irqs.h" /* PXA_NR_BUILTIN_GPIO */
+
enum balloon3_features {
BALLOON3_FEATURE_OHCI,
BALLOON3_FEATURE_MMC,
diff --git a/arch/arm/mach-pxa/include/mach/corgi.h b/arch/arm/mach-pxa/include/mach/corgi.h
index f3c3493b468d..c030d955bbd7 100644
--- a/arch/arm/mach-pxa/include/mach/corgi.h
+++ b/arch/arm/mach-pxa/include/mach/corgi.h
@@ -13,6 +13,7 @@
#ifndef __ASM_ARCH_CORGI_H
#define __ASM_ARCH_CORGI_H 1
+#include "irqs.h" /* PXA_NR_BUILTIN_GPIO */
/*
* Corgi (Non Standard) GPIO Definitions
diff --git a/arch/arm/mach-pxa/include/mach/csb726.h b/arch/arm/mach-pxa/include/mach/csb726.h
index 2628e7b72116..00cfbbbf73f7 100644
--- a/arch/arm/mach-pxa/include/mach/csb726.h
+++ b/arch/arm/mach-pxa/include/mach/csb726.h
@@ -11,6 +11,8 @@
#ifndef CSB726_H
#define CSB726_H
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+
#define CSB726_GPIO_IRQ_LAN 52
#define CSB726_GPIO_IRQ_SM501 53
#define CSB726_GPIO_MMC_DETECT 100
diff --git a/arch/arm/mach-pxa/include/mach/gumstix.h b/arch/arm/mach-pxa/include/mach/gumstix.h
index dba14b6503ad..f7df27bbb42e 100644
--- a/arch/arm/mach-pxa/include/mach/gumstix.h
+++ b/arch/arm/mach-pxa/include/mach/gumstix.h
@@ -6,6 +6,7 @@
* published by the Free Software Foundation.
*/
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
/* BTRESET - Reset line to Bluetooth module, active low signal. */
#define GPIO_GUMSTIX_BTRESET 7
diff --git a/arch/arm/mach-pxa/include/mach/idp.h b/arch/arm/mach-pxa/include/mach/idp.h
index 22a96f87232b..7e63f4680271 100644
--- a/arch/arm/mach-pxa/include/mach/idp.h
+++ b/arch/arm/mach-pxa/include/mach/idp.h
@@ -23,6 +23,7 @@
* IDP hardware.
*/
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
#define IDP_FLASH_PHYS (PXA_CS0_PHYS)
#define IDP_ALT_FLASH_PHYS (PXA_CS1_PHYS)
diff --git a/arch/arm/mach-pxa/include/mach/palmld.h b/arch/arm/mach-pxa/include/mach/palmld.h
index 2c4471336570..b184f296023b 100644
--- a/arch/arm/mach-pxa/include/mach/palmld.h
+++ b/arch/arm/mach-pxa/include/mach/palmld.h
@@ -13,6 +13,8 @@
#ifndef _INCLUDE_PALMLD_H_
#define _INCLUDE_PALMLD_H_
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+
/** HERE ARE GPIOs **/
/* GPIOs */
diff --git a/arch/arm/mach-pxa/include/mach/palmt5.h b/arch/arm/mach-pxa/include/mach/palmt5.h
index 0bd4f036c72f..e342c5921405 100644
--- a/arch/arm/mach-pxa/include/mach/palmt5.h
+++ b/arch/arm/mach-pxa/include/mach/palmt5.h
@@ -15,6 +15,8 @@
#ifndef _INCLUDE_PALMT5_H_
#define _INCLUDE_PALMT5_H_
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+
/** HERE ARE GPIOs **/
/* GPIOs */
diff --git a/arch/arm/mach-pxa/include/mach/palmtc.h b/arch/arm/mach-pxa/include/mach/palmtc.h
index c383a21680b6..81c727b3cfd2 100644
--- a/arch/arm/mach-pxa/include/mach/palmtc.h
+++ b/arch/arm/mach-pxa/include/mach/palmtc.h
@@ -16,6 +16,8 @@
#ifndef _INCLUDE_PALMTC_H_
#define _INCLUDE_PALMTC_H_
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+
/** HERE ARE GPIOs **/
/* GPIOs */
diff --git a/arch/arm/mach-pxa/include/mach/palmtx.h b/arch/arm/mach-pxa/include/mach/palmtx.h
index f2e530380253..92bc1f05300d 100644
--- a/arch/arm/mach-pxa/include/mach/palmtx.h
+++ b/arch/arm/mach-pxa/include/mach/palmtx.h
@@ -16,6 +16,8 @@
#ifndef _INCLUDE_PALMTX_H_
#define _INCLUDE_PALMTX_H_
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+
/** HERE ARE GPIOs **/
/* GPIOs */
diff --git a/arch/arm/mach-pxa/include/mach/pcm027.h b/arch/arm/mach-pxa/include/mach/pcm027.h
index 6bf28de228bd..86ebd7b6c960 100644
--- a/arch/arm/mach-pxa/include/mach/pcm027.h
+++ b/arch/arm/mach-pxa/include/mach/pcm027.h
@@ -23,6 +23,8 @@
* Definitions of CPU card resources only
*/
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+
/* phyCORE-PXA270 (PCM027) Interrupts */
#define PCM027_IRQ(x) (IRQ_BOARD_START + (x))
#define PCM027_BTDET_IRQ PCM027_IRQ(0)
diff --git a/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h b/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h
index 0260aaa2fc17..7e544c14967e 100644
--- a/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h
+++ b/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h
@@ -20,6 +20,7 @@
*/
#include <mach/pcm027.h>
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
/*
* definitions relevant only when the PCM-990
diff --git a/arch/arm/mach-pxa/include/mach/poodle.h b/arch/arm/mach-pxa/include/mach/poodle.h
index f32ff75dcca8..b56b19351a03 100644
--- a/arch/arm/mach-pxa/include/mach/poodle.h
+++ b/arch/arm/mach-pxa/include/mach/poodle.h
@@ -15,6 +15,8 @@
#ifndef __ASM_ARCH_POODLE_H
#define __ASM_ARCH_POODLE_H 1
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+
/*
* GPIOs
*/
diff --git a/arch/arm/mach-pxa/include/mach/spitz.h b/arch/arm/mach-pxa/include/mach/spitz.h
index 0bfe6507c95d..25c9f62e46aa 100644
--- a/arch/arm/mach-pxa/include/mach/spitz.h
+++ b/arch/arm/mach-pxa/include/mach/spitz.h
@@ -15,8 +15,8 @@
#define __ASM_ARCH_SPITZ_H 1
#endif
+#include "irqs.h" /* PXA_NR_BUILTIN_GPIO, PXA_GPIO_TO_IRQ */
#include <linux/fb.h>
-#include <linux/gpio.h>
/* Spitz/Akita GPIOs */
diff --git a/arch/arm/mach-pxa/include/mach/tosa.h b/arch/arm/mach-pxa/include/mach/tosa.h
index 2bb0e862598c..0497d95cef25 100644
--- a/arch/arm/mach-pxa/include/mach/tosa.h
+++ b/arch/arm/mach-pxa/include/mach/tosa.h
@@ -13,6 +13,8 @@
#ifndef _ASM_ARCH_TOSA_H_
#define _ASM_ARCH_TOSA_H_ 1
+#include "irqs.h" /* PXA_NR_BUILTIN_GPIO */
+
/* TOSA Chip selects */
#define TOSA_LCDC_PHYS PXA_CS4_PHYS
/* Internel Scoop */
diff --git a/arch/arm/mach-pxa/include/mach/trizeps4.h b/arch/arm/mach-pxa/include/mach/trizeps4.h
index d2ca01053f69..ae3ca013afab 100644
--- a/arch/arm/mach-pxa/include/mach/trizeps4.h
+++ b/arch/arm/mach-pxa/include/mach/trizeps4.h
@@ -10,6 +10,8 @@
#ifndef _TRIPEPS4_H_
#define _TRIPEPS4_H_
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+
/* physical memory regions */
#define TRIZEPS4_FLASH_PHYS (PXA_CS0_PHYS) /* Flash region */
#define TRIZEPS4_DISK_PHYS (PXA_CS1_PHYS) /* Disk On Chip region */
diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c
index f70583fee59f..29997bde277d 100644
--- a/arch/arm/mach-pxa/mioa701.c
+++ b/arch/arm/mach-pxa/mioa701.c
@@ -38,6 +38,7 @@
#include <linux/mtd/physmap.h>
#include <linux/usb/gpio_vbus.h>
#include <linux/reboot.h>
+#include <linux/regulator/fixed.h>
#include <linux/regulator/max1586.h>
#include <linux/slab.h>
#include <linux/i2c/pxa-i2c.h>
@@ -714,6 +715,10 @@ static struct gpio global_gpios[] = {
{ GPIO56_MT9M111_nOE, GPIOF_OUT_INIT_LOW, "Camera nOE" },
};
+static struct regulator_consumer_supply fixed_5v0_consumers[] = {
+ REGULATOR_SUPPLY("power", "pwm-backlight"),
+};
+
static void __init mioa701_machine_init(void)
{
int rc;
@@ -753,6 +758,10 @@ static void __init mioa701_machine_init(void)
pxa_set_i2c_info(&i2c_pdata);
pxa27x_set_i2c_power_info(NULL);
pxa_set_camera_info(&mioa701_pxacamera_platform_data);
+
+ regulator_register_always_on(0, "fixed-5.0V", fixed_5v0_consumers,
+ ARRAY_SIZE(fixed_5v0_consumers),
+ 5000000);
}
static void mioa701_machine_exit(void)
diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c
index 29905b127ad9..41f27f667ca8 100644
--- a/arch/arm/mach-pxa/viper.c
+++ b/arch/arm/mach-pxa/viper.c
@@ -885,9 +885,6 @@ static int viper_cpufreq_notifier(struct notifier_block *nb,
viper_set_core_cpu_voltage(freq->new, 0);
}
break;
- case CPUFREQ_RESUMECHANGE:
- viper_set_core_cpu_voltage(freq->new, 0);
- break;
default:
/* ignore */
break;
diff --git a/arch/arm/mach-sa1100/include/mach/collie.h b/arch/arm/mach-sa1100/include/mach/collie.h
index f33679d2d3ee..50e1d850ee2e 100644
--- a/arch/arm/mach-sa1100/include/mach/collie.h
+++ b/arch/arm/mach-sa1100/include/mach/collie.h
@@ -13,6 +13,8 @@
#ifndef __ASM_ARCH_COLLIE_H
#define __ASM_ARCH_COLLIE_H
+#include "hardware.h" /* Gives GPIO_MAX */
+
extern void locomolcd_power(int on);
#define COLLIE_SCOOP_GPIO_BASE (GPIO_MAX + 1)
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 338640631e08..3b8c87461d67 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -8,7 +8,7 @@ config ARCH_SHMOBILE_MULTI
select CPU_V7
select GENERIC_CLOCKEVENTS
select HAVE_ARM_SCU if SMP
- select HAVE_ARM_TWD if LOCAL_TIMERS
+ select HAVE_ARM_TWD if SMP
select HAVE_SMP
select ARM_GIC
select MIGHT_HAVE_CACHE_L2X0
@@ -24,17 +24,21 @@ comment "Renesas ARM SoCs System Type"
config ARCH_EMEV2
bool "Emma Mobile EV2"
+ select SYS_SUPPORTS_EM_STI
config ARCH_R7S72100
bool "RZ/A1H (R7S72100)"
+ select SYS_SUPPORTS_SH_MTU2
config ARCH_R8A7790
bool "R-Car H2 (R8A77900)"
select RENESAS_IRQC
+ select SYS_SUPPORTS_SH_CMT
config ARCH_R8A7791
bool "R-Car M2 (R8A77910)"
select RENESAS_IRQC
+ select SYS_SUPPORTS_SH_CMT
comment "Renesas ARM SoCs Board Type"
@@ -68,6 +72,8 @@ config ARCH_SH7372
select ARM_CPU_SUSPEND if PM || CPU_IDLE
select CPU_V7
select SH_CLK_CPG
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_TMU
config ARCH_SH73A0
bool "SH-Mobile AG5 (R8A73A00)"
@@ -77,6 +83,8 @@ config ARCH_SH73A0
select I2C
select SH_CLK_CPG
select RENESAS_INTC_IRQPIN
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_TMU
config ARCH_R8A73A4
bool "R-Mobile APE6 (R8A73A40)"
@@ -87,6 +95,8 @@ config ARCH_R8A73A4
select RENESAS_IRQC
select ARCH_HAS_CPUFREQ
select ARCH_HAS_OPP
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_TMU
config ARCH_R8A7740
bool "R-Mobile A1 (R8A77400)"
@@ -95,6 +105,8 @@ config ARCH_R8A7740
select CPU_V7
select SH_CLK_CPG
select RENESAS_INTC_IRQPIN
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_TMU
config ARCH_R8A7778
bool "R-Car M1A (R8A77781)"
@@ -102,8 +114,7 @@ config ARCH_R8A7778
select CPU_V7
select SH_CLK_CPG
select ARM_GIC
- select USB_ARCH_HAS_EHCI
- select USB_ARCH_HAS_OHCI
+ select SYS_SUPPORTS_SH_TMU
config ARCH_R8A7779
bool "R-Car H1 (R8A77790)"
@@ -111,9 +122,8 @@ config ARCH_R8A7779
select ARM_GIC
select CPU_V7
select SH_CLK_CPG
- select USB_ARCH_HAS_EHCI
- select USB_ARCH_HAS_OHCI
select RENESAS_INTC_IRQPIN
+ select SYS_SUPPORTS_SH_TMU
config ARCH_R8A7790
bool "R-Car H2 (R8A77900)"
@@ -123,6 +133,7 @@ config ARCH_R8A7790
select MIGHT_HAVE_PCI
select SH_CLK_CPG
select RENESAS_IRQC
+ select SYS_SUPPORTS_SH_CMT
config ARCH_R8A7791
bool "R-Car M2 (R8A77910)"
@@ -132,6 +143,7 @@ config ARCH_R8A7791
select MIGHT_HAVE_PCI
select SH_CLK_CPG
select RENESAS_IRQC
+ select SYS_SUPPORTS_SH_CMT
config ARCH_EMEV2
bool "Emma Mobile EV2"
@@ -141,6 +153,7 @@ config ARCH_EMEV2
select MIGHT_HAVE_PCI
select USE_OF
select AUTO_ZRELADDR
+ select SYS_SUPPORTS_EM_STI
config ARCH_R7S72100
bool "RZ/A1H (R7S72100)"
@@ -148,6 +161,7 @@ config ARCH_R7S72100
select ARM_GIC
select CPU_V7
select SH_CLK_CPG
+ select SYS_SUPPORTS_SH_MTU2
comment "Renesas ARM SoCs Board Type"
@@ -321,24 +335,6 @@ config SHMOBILE_TIMER_HZ
want to select a HZ value such as 128 that can evenly divide RCLK.
A HZ value that does not divide evenly may cause timer drift.
-config SH_TIMER_CMT
- bool "CMT timer driver"
- default y
- help
- This enables build of the CMT timer driver.
-
-config SH_TIMER_TMU
- bool "TMU timer driver"
- default y
- help
- This enables build of the TMU timer driver.
-
-config EM_TIMER_STI
- bool "STI timer driver"
- default y
- help
- This enables build of the STI timer driver.
-
endmenu
endif
diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c
index 93533e2710a8..9323854242ca 100644
--- a/arch/arm/mach-shmobile/board-armadillo800eva.c
+++ b/arch/arm/mach-shmobile/board-armadillo800eva.c
@@ -988,14 +988,12 @@ static struct asoc_simple_card_info fsi_wm8978_info = {
.card = "FSI2A-WM8978",
.codec = "wm8978.0-001a",
.platform = "sh_fsi2",
- .daifmt = SND_SOC_DAIFMT_I2S,
+ .daifmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
.cpu_dai = {
.name = "fsia-dai",
- .fmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
},
.codec_dai = {
.name = "wm8978-hifi",
- .fmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF,
.sysclk = 12288000,
},
};
diff --git a/arch/arm/mach-shmobile/board-bockw.c b/arch/arm/mach-shmobile/board-bockw.c
index c475220545f2..74c27d9d6900 100644
--- a/arch/arm/mach-shmobile/board-bockw.c
+++ b/arch/arm/mach-shmobile/board-bockw.c
@@ -429,14 +429,12 @@ static struct asoc_simple_card_info rsnd_card_info[] = {
.card = "SSI56-AK4643",
.codec = "ak4642-codec.0-0012",
.platform = "rcar_sound",
- .daifmt = SND_SOC_DAIFMT_LEFT_J,
+ .daifmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM,
.cpu_dai = {
.name = "rsnd-dai.0",
- .fmt = SND_SOC_DAIFMT_CBS_CFS,
},
.codec_dai = {
.name = "ak4642-hifi",
- .fmt = SND_SOC_DAIFMT_CBM_CFM,
.sysclk = 11289600,
},
},
@@ -446,10 +444,9 @@ static struct asoc_simple_card_info rsnd_card_info[] = {
.card = "SSI3-AK4554(playback)",
.codec = "ak4554-adc-dac.0",
.platform = "rcar_sound",
+ .daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_RIGHT_J,
.cpu_dai = {
.name = "rsnd-dai.1",
- .fmt = SND_SOC_DAIFMT_CBM_CFM |
- SND_SOC_DAIFMT_RIGHT_J,
},
.codec_dai = {
.name = "ak4554-hifi",
@@ -461,10 +458,9 @@ static struct asoc_simple_card_info rsnd_card_info[] = {
.card = "SSI4-AK4554(capture)",
.codec = "ak4554-adc-dac.0",
.platform = "rcar_sound",
+ .daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_LEFT_J,
.cpu_dai = {
.name = "rsnd-dai.2",
- .fmt = SND_SOC_DAIFMT_CBM_CFM |
- SND_SOC_DAIFMT_LEFT_J,
},
.codec_dai = {
.name = "ak4554-hifi",
@@ -476,10 +472,9 @@ static struct asoc_simple_card_info rsnd_card_info[] = {
.card = "SSI7-AK4554(playback)",
.codec = "ak4554-adc-dac.1",
.platform = "rcar_sound",
+ .daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_RIGHT_J,
.cpu_dai = {
.name = "rsnd-dai.3",
- .fmt = SND_SOC_DAIFMT_CBM_CFM |
- SND_SOC_DAIFMT_RIGHT_J,
},
.codec_dai = {
.name = "ak4554-hifi",
@@ -491,10 +486,9 @@ static struct asoc_simple_card_info rsnd_card_info[] = {
.card = "SSI8-AK4554(capture)",
.codec = "ak4554-adc-dac.1",
.platform = "rcar_sound",
+ .daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_LEFT_J,
.cpu_dai = {
.name = "rsnd-dai.4",
- .fmt = SND_SOC_DAIFMT_CBM_CFM |
- SND_SOC_DAIFMT_LEFT_J,
},
.codec_dai = {
.name = "ak4554-hifi",
diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c
index bc40b853ffd3..03dc3ac84502 100644
--- a/arch/arm/mach-shmobile/board-kzm9g.c
+++ b/arch/arm/mach-shmobile/board-kzm9g.c
@@ -589,14 +589,12 @@ static struct asoc_simple_card_info fsi2_ak4648_info = {
.card = "FSI2A-AK4648",
.codec = "ak4642-codec.0-0012",
.platform = "sh_fsi2",
- .daifmt = SND_SOC_DAIFMT_LEFT_J,
+ .daifmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM,
.cpu_dai = {
.name = "fsia-dai",
- .fmt = SND_SOC_DAIFMT_CBS_CFS,
},
.codec_dai = {
.name = "ak4642-hifi",
- .fmt = SND_SOC_DAIFMT_CBM_CFM,
.sysclk = 11289600,
},
};
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index 3aba0372f630..0ff4d8e45cf7 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -509,9 +509,9 @@ static struct asoc_simple_card_info fsi2_hdmi_info = {
.card = "FSI2B-HDMI",
.codec = "sh-mobile-hdmi",
.platform = "sh_fsi2",
+ .daifmt = SND_SOC_DAIFMT_CBS_CFS,
.cpu_dai = {
.name = "fsib-dai",
- .fmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF,
},
.codec_dai = {
.name = "sh_mobile_hdmi-hifi",
@@ -905,14 +905,12 @@ static struct asoc_simple_card_info fsi2_ak4643_info = {
.card = "FSI2A-AK4643",
.codec = "ak4642-codec.0-0013",
.platform = "sh_fsi2",
- .daifmt = SND_SOC_DAIFMT_LEFT_J,
+ .daifmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM,
.cpu_dai = {
.name = "fsia-dai",
- .fmt = SND_SOC_DAIFMT_CBS_CFS,
},
.codec_dai = {
.name = "ak4642-hifi",
- .fmt = SND_SOC_DAIFMT_CBM_CFM,
.sysclk = 11289600,
},
};
diff --git a/arch/arm/mach-spear/Kconfig b/arch/arm/mach-spear/Kconfig
index ac1710e64d9a..308d5b5b3055 100644
--- a/arch/arm/mach-spear/Kconfig
+++ b/arch/arm/mach-spear/Kconfig
@@ -92,7 +92,7 @@ config MACH_SPEAR600
depends on ARCH_SPEAR6XX
select USE_OF
help
- Supports ST SPEAr600 boards configured via the device-treesource "arch/arm/mach-spear6xx/Kconfig"
+ Supports ST SPEAr600 boards configured via the device-tree
config ARCH_SPEAR_AUTO
def_bool PLAT_SPEAR_SINGLE
diff --git a/arch/arm/mach-spear/spear1310.c b/arch/arm/mach-spear/spear1310.c
index 7ad003001ab7..824b12a56a42 100644
--- a/arch/arm/mach-spear/spear1310.c
+++ b/arch/arm/mach-spear/spear1310.c
@@ -28,6 +28,7 @@
static void __init spear1310_dt_init(void)
{
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+ platform_device_register_simple("spear-cpufreq", -1, NULL, 0);
}
static const char * const spear1310_dt_board_compat[] = {
diff --git a/arch/arm/mach-spear/spear1340.c b/arch/arm/mach-spear/spear1340.c
index 3fb683424729..7b6bff7154e1 100644
--- a/arch/arm/mach-spear/spear1340.c
+++ b/arch/arm/mach-spear/spear1340.c
@@ -143,6 +143,7 @@ static void __init spear1340_dt_init(void)
{
of_platform_populate(NULL, of_default_bus_match_table,
spear1340_auxdata_lookup, NULL);
+ platform_device_register_simple("spear-cpufreq", -1, NULL, 0);
}
static const char * const spear1340_dt_board_compat[] = {
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index b1232d8be6f5..4926bd11f190 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -19,7 +19,6 @@ config ARCH_TEGRA
select RESET_CONTROLLER
select SOC_BUS
select SPARSE_IRQ
- select USB_ARCH_HAS_EHCI if USB_SUPPORT
select USB_ULPI if USB_PHY
select USB_ULPI_VIEWPORT if USB_PHY
select USE_OF
diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c
index 4ae0286b468d..f55b05a29b55 100644
--- a/arch/arm/mach-tegra/pm.c
+++ b/arch/arm/mach-tegra/pm.c
@@ -24,6 +24,7 @@
#include <linux/cpu_pm.h>
#include <linux/suspend.h>
#include <linux/err.h>
+#include <linux/slab.h>
#include <linux/clk/tegra.h>
#include <asm/smp_plat.h>
diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index 303a285d80fd..6191603379e1 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -73,10 +73,20 @@ u32 tegra_uart_config[3] = {
static void __init tegra_init_cache(void)
{
#ifdef CONFIG_CACHE_L2X0
+ static const struct of_device_id pl310_ids[] __initconst = {
+ { .compatible = "arm,pl310-cache", },
+ {}
+ };
+
+ struct device_node *np;
int ret;
void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
u32 aux_ctrl, cache_type;
+ np = of_find_matching_node(NULL, pl310_ids);
+ if (!np)
+ return;
+
cache_type = readl(p + L2X0_CACHE_TYPE);
aux_ctrl = (cache_type & 0x700) << (17-8);
aux_ctrl |= 0x7C400001;
diff --git a/arch/arm/mach-u300/Makefile b/arch/arm/mach-u300/Makefile
index 0f362b64fb87..3ec74ac95bc1 100644
--- a/arch/arm/mach-u300/Makefile
+++ b/arch/arm/mach-u300/Makefile
@@ -2,7 +2,7 @@
# Makefile for the linux kernel, U300 machine.
#
-obj-y := core.o timer.o
+obj-y := core.o
obj-m :=
obj-n :=
obj- :=
diff --git a/arch/arm/mach-zynq/Kconfig b/arch/arm/mach-zynq/Kconfig
index 6b04260aa142..f03e75bd0b2b 100644
--- a/arch/arm/mach-zynq/Kconfig
+++ b/arch/arm/mach-zynq/Kconfig
@@ -2,6 +2,8 @@ config ARCH_ZYNQ
bool "Xilinx Zynq ARM Cortex A9 Platform" if ARCH_MULTI_V7
select ARM_AMBA
select ARM_GIC
+ select ARCH_HAS_CPUFREQ
+ select ARCH_HAS_OPP
select COMMON_CLK
select CPU_V7
select GENERIC_CLOCKEVENTS
@@ -13,6 +15,6 @@ config ARCH_ZYNQ
select HAVE_SMP
select SPARSE_IRQ
select CADENCE_TTC_TIMER
- select ARM_GLOBAL_TIMER
+ select ARM_GLOBAL_TIMER if !CPU_FREQ
help
Support for Xilinx Zynq ARM Cortex A9 Platform
diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c
index 1db2a5ca9ab8..a39be8e80856 100644
--- a/arch/arm/mach-zynq/common.c
+++ b/arch/arm/mach-zynq/common.c
@@ -25,6 +25,7 @@
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/of.h>
+#include <linux/memblock.h>
#include <linux/irqchip.h>
#include <linux/irqchip/arm-gic.h>
@@ -41,6 +42,18 @@
void __iomem *zynq_scu_base;
+/**
+ * zynq_memory_init - Initialize special memory
+ *
+ * We need to stop things allocating the low memory as DMA can't work in
+ * the 1st 512K of memory.
+ */
+static void __init zynq_memory_init(void)
+{
+ if (!__pa(PAGE_OFFSET))
+ memblock_reserve(__pa(PAGE_OFFSET), __pa(swapper_pg_dir));
+}
+
static struct platform_device zynq_cpuidle_device = {
.name = "cpuidle-zynq",
};
@@ -51,6 +64,8 @@ static struct platform_device zynq_cpuidle_device = {
*/
static void __init zynq_init_machine(void)
{
+ struct platform_device_info devinfo = { .name = "cpufreq-cpu0", };
+
/*
* 64KB way size, 8-way associativity, parity disabled
*/
@@ -59,6 +74,7 @@ static void __init zynq_init_machine(void)
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
platform_device_register(&zynq_cpuidle_device);
+ platform_device_register_full(&devinfo);
}
static void __init zynq_timer_init(void)
@@ -117,5 +133,6 @@ DT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform")
.init_machine = zynq_init_machine,
.init_time = zynq_timer_init,
.dt_compat = zynq_dt_match,
+ .reserve = zynq_memory_init,
.restart = zynq_system_reset,
MACHINE_END
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 1a77450e728a..4fe42ce720d2 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -1069,6 +1069,8 @@ fs_initcall(dma_debug_do_init);
/* IOMMU */
+static int extend_iommu_mapping(struct dma_iommu_mapping *mapping);
+
static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping,
size_t size)
{
@@ -1076,41 +1078,87 @@ static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping,
unsigned int align = 0;
unsigned int count, start;
unsigned long flags;
+ dma_addr_t iova;
+ int i;
if (order > CONFIG_ARM_DMA_IOMMU_ALIGNMENT)
order = CONFIG_ARM_DMA_IOMMU_ALIGNMENT;
- count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) +
- (1 << mapping->order) - 1) >> mapping->order;
-
- if (order > mapping->order)
- align = (1 << (order - mapping->order)) - 1;
+ count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+ align = (1 << order) - 1;
spin_lock_irqsave(&mapping->lock, flags);
- start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits, 0,
- count, align);
- if (start > mapping->bits) {
- spin_unlock_irqrestore(&mapping->lock, flags);
- return DMA_ERROR_CODE;
+ for (i = 0; i < mapping->nr_bitmaps; i++) {
+ start = bitmap_find_next_zero_area(mapping->bitmaps[i],
+ mapping->bits, 0, count, align);
+
+ if (start > mapping->bits)
+ continue;
+
+ bitmap_set(mapping->bitmaps[i], start, count);
+ break;
}
- bitmap_set(mapping->bitmap, start, count);
+ /*
+ * No unused range found. Try to extend the existing mapping
+ * and perform a second attempt to reserve an IO virtual
+ * address range of size bytes.
+ */
+ if (i == mapping->nr_bitmaps) {
+ if (extend_iommu_mapping(mapping)) {
+ spin_unlock_irqrestore(&mapping->lock, flags);
+ return DMA_ERROR_CODE;
+ }
+
+ start = bitmap_find_next_zero_area(mapping->bitmaps[i],
+ mapping->bits, 0, count, align);
+
+ if (start > mapping->bits) {
+ spin_unlock_irqrestore(&mapping->lock, flags);
+ return DMA_ERROR_CODE;
+ }
+
+ bitmap_set(mapping->bitmaps[i], start, count);
+ }
spin_unlock_irqrestore(&mapping->lock, flags);
- return mapping->base + (start << (mapping->order + PAGE_SHIFT));
+ iova = mapping->base + (mapping->size * i);
+ iova += start << PAGE_SHIFT;
+
+ return iova;
}
static inline void __free_iova(struct dma_iommu_mapping *mapping,
dma_addr_t addr, size_t size)
{
- unsigned int start = (addr - mapping->base) >>
- (mapping->order + PAGE_SHIFT);
- unsigned int count = ((size >> PAGE_SHIFT) +
- (1 << mapping->order) - 1) >> mapping->order;
+ unsigned int start, count;
unsigned long flags;
+ dma_addr_t bitmap_base;
+ u32 bitmap_index;
+
+ if (!size)
+ return;
+
+ bitmap_index = (u32) (addr - mapping->base) / (u32) mapping->size;
+ BUG_ON(addr < mapping->base || bitmap_index > mapping->extensions);
+
+ bitmap_base = mapping->base + mapping->size * bitmap_index;
+
+ start = (addr - bitmap_base) >> PAGE_SHIFT;
+
+ if (addr + size > bitmap_base + mapping->size) {
+ /*
+ * The address range to be freed reaches into the iova
+ * range of the next bitmap. This should not happen as
+ * we don't allow this in __alloc_iova (at the
+ * moment).
+ */
+ BUG();
+ } else
+ count = size >> PAGE_SHIFT;
spin_lock_irqsave(&mapping->lock, flags);
- bitmap_clear(mapping->bitmap, start, count);
+ bitmap_clear(mapping->bitmaps[bitmap_index], start, count);
spin_unlock_irqrestore(&mapping->lock, flags);
}
@@ -1358,7 +1406,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
*handle = DMA_ERROR_CODE;
size = PAGE_ALIGN(size);
- if (gfp & GFP_ATOMIC)
+ if (!(gfp & __GFP_WAIT))
return __iommu_alloc_atomic(dev, size, handle);
/*
@@ -1875,8 +1923,7 @@ struct dma_map_ops iommu_coherent_ops = {
* arm_iommu_create_mapping
* @bus: pointer to the bus holding the client device (for IOMMU calls)
* @base: start address of the valid IO address space
- * @size: size of the valid IO address space
- * @order: accuracy of the IO addresses allocations
+ * @size: maximum size of the valid IO address space
*
* Creates a mapping structure which holds information about used/unused
* IO address ranges, which is required to perform memory allocation and
@@ -1886,38 +1933,54 @@ struct dma_map_ops iommu_coherent_ops = {
* arm_iommu_attach_device function.
*/
struct dma_iommu_mapping *
-arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size,
- int order)
+arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size)
{
- unsigned int count = size >> (PAGE_SHIFT + order);
- unsigned int bitmap_size = BITS_TO_LONGS(count) * sizeof(long);
+ unsigned int bits = size >> PAGE_SHIFT;
+ unsigned int bitmap_size = BITS_TO_LONGS(bits) * sizeof(long);
struct dma_iommu_mapping *mapping;
+ int extensions = 1;
int err = -ENOMEM;
- if (!count)
+ if (!bitmap_size)
return ERR_PTR(-EINVAL);
+ if (bitmap_size > PAGE_SIZE) {
+ extensions = bitmap_size / PAGE_SIZE;
+ bitmap_size = PAGE_SIZE;
+ }
+
mapping = kzalloc(sizeof(struct dma_iommu_mapping), GFP_KERNEL);
if (!mapping)
goto err;
- mapping->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
- if (!mapping->bitmap)
+ mapping->bitmap_size = bitmap_size;
+ mapping->bitmaps = kzalloc(extensions * sizeof(unsigned long *),
+ GFP_KERNEL);
+ if (!mapping->bitmaps)
goto err2;
+ mapping->bitmaps[0] = kzalloc(bitmap_size, GFP_KERNEL);
+ if (!mapping->bitmaps[0])
+ goto err3;
+
+ mapping->nr_bitmaps = 1;
+ mapping->extensions = extensions;
mapping->base = base;
+ mapping->size = bitmap_size << PAGE_SHIFT;
mapping->bits = BITS_PER_BYTE * bitmap_size;
- mapping->order = order;
+
spin_lock_init(&mapping->lock);
mapping->domain = iommu_domain_alloc(bus);
if (!mapping->domain)
- goto err3;
+ goto err4;
kref_init(&mapping->kref);
return mapping;
+err4:
+ kfree(mapping->bitmaps[0]);
err3:
- kfree(mapping->bitmap);
+ kfree(mapping->bitmaps);
err2:
kfree(mapping);
err:
@@ -1927,14 +1990,35 @@ EXPORT_SYMBOL_GPL(arm_iommu_create_mapping);
static void release_iommu_mapping(struct kref *kref)
{
+ int i;
struct dma_iommu_mapping *mapping =
container_of(kref, struct dma_iommu_mapping, kref);
iommu_domain_free(mapping->domain);
- kfree(mapping->bitmap);
+ for (i = 0; i < mapping->nr_bitmaps; i++)
+ kfree(mapping->bitmaps[i]);
+ kfree(mapping->bitmaps);
kfree(mapping);
}
+static int extend_iommu_mapping(struct dma_iommu_mapping *mapping)
+{
+ int next_bitmap;
+
+ if (mapping->nr_bitmaps > mapping->extensions)
+ return -EINVAL;
+
+ next_bitmap = mapping->nr_bitmaps;
+ mapping->bitmaps[next_bitmap] = kzalloc(mapping->bitmap_size,
+ GFP_ATOMIC);
+ if (!mapping->bitmaps[next_bitmap])
+ return -ENOMEM;
+
+ mapping->nr_bitmaps++;
+
+ return 0;
+}
+
void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
{
if (mapping)
diff --git a/arch/arm/mm/dump.c b/arch/arm/mm/dump.c
index 2b3a56414271..ef69152f9b52 100644
--- a/arch/arm/mm/dump.c
+++ b/arch/arm/mm/dump.c
@@ -264,6 +264,9 @@ static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start)
note_page(st, addr, 3, pmd_val(*pmd));
else
walk_pte(st, pmd, addr);
+
+ if (SECTION_SIZE < PMD_SIZE && pmd_large(pmd[1]))
+ note_page(st, addr + SECTION_SIZE, 3, pmd_val(pmd[1]));
}
}
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 804d61566a53..2a77ba8796ae 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -323,6 +323,8 @@ void __init arm_memblock_init(struct meminfo *mi,
if (mdesc->reserve)
mdesc->reserve();
+ early_init_fdt_scan_reserved_mem();
+
/*
* reserve memory for DMA contigouos allocations,
* must come from DMA area inside low memory
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index d5a982d15a88..7ea641b7aa7d 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
@@ -38,6 +38,7 @@ static inline pmd_t *pmd_off_k(unsigned long virt)
struct mem_type {
pteval_t prot_pte;
+ pteval_t prot_pte_s2;
pmdval_t prot_l1;
pmdval_t prot_sect;
unsigned int domain;
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 4f08c133cc25..a623cb3ad012 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -232,12 +232,16 @@ __setup("noalign", noalign_setup);
#endif /* ifdef CONFIG_CPU_CP15 / else */
#define PROT_PTE_DEVICE L_PTE_PRESENT|L_PTE_YOUNG|L_PTE_DIRTY|L_PTE_XN
+#define PROT_PTE_S2_DEVICE PROT_PTE_DEVICE
#define PROT_SECT_DEVICE PMD_TYPE_SECT|PMD_SECT_AP_WRITE
static struct mem_type mem_types[] = {
[MT_DEVICE] = { /* Strongly ordered / ARMv6 shared device */
.prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED |
L_PTE_SHARED,
+ .prot_pte_s2 = s2_policy(PROT_PTE_S2_DEVICE) |
+ s2_policy(L_PTE_S2_MT_DEV_SHARED) |
+ L_PTE_SHARED,
.prot_l1 = PMD_TYPE_TABLE,
.prot_sect = PROT_SECT_DEVICE | PMD_SECT_S,
.domain = DOMAIN_IO,
@@ -508,7 +512,8 @@ static void __init build_mem_type_table(void)
cp = &cache_policies[cachepolicy];
vecs_pgprot = kern_pgprot = user_pgprot = cp->pte;
s2_pgprot = cp->pte_s2;
- hyp_device_pgprot = s2_device_pgprot = mem_types[MT_DEVICE].prot_pte;
+ hyp_device_pgprot = mem_types[MT_DEVICE].prot_pte;
+ s2_device_pgprot = mem_types[MT_DEVICE].prot_pte_s2;
/*
* ARMv6 and above have extended page tables.
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index 45dc29f85d56..32b3558321c4 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -208,7 +208,6 @@ __v6_setup:
mcr p15, 0, r0, c7, c14, 0 @ clean+invalidate D cache
mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
mcr p15, 0, r0, c7, c15, 0 @ clean+invalidate cache
- mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs
mcr p15, 0, r0, c2, c0, 2 @ TTB control register
@@ -218,6 +217,8 @@ __v6_setup:
ALT_UP(orr r8, r8, #TTB_FLAGS_UP)
mcr p15, 0, r8, c2, c0, 1 @ load TTB1
#endif /* CONFIG_MMU */
+ mcr p15, 0, r0, c7, c10, 4 @ drain write buffer and
+ @ complete invalidations
adr r5, v6_crval
ldmia r5, {r5, r6}
ARM_BE8(orr r6, r6, #1 << 25) @ big-endian page tables
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index bd1781979a39..74f6033e76dd 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -351,7 +351,6 @@ __v7_setup:
4: mov r10, #0
mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate
- dsb
#ifdef CONFIG_MMU
mcr p15, 0, r10, c8, c7, 0 @ invalidate I + D TLBs
v7_ttb_setup r10, r4, r8, r5 @ TTBCR, TTBRx setup
@@ -360,6 +359,7 @@ __v7_setup:
mcr p15, 0, r5, c10, c2, 0 @ write PRRR
mcr p15, 0, r6, c10, c2, 1 @ write NMRR
#endif
+ dsb @ Complete invalidations
#ifndef CONFIG_ARM_THUMBEE
mrc p15, 0, r0, c0, c1, 0 @ read ID_PFR0 for ThumbEE
and r0, r0, #(0xf << 12) @ ThumbEE enabled field
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 271b5e971568..6f879c319a9d 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -825,8 +825,8 @@ b_epilogue:
break;
case BPF_S_ANC_RXHASH:
ctx->seen |= SEEN_SKB;
- BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
- off = offsetof(struct sk_buff, rxhash);
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, hash) != 4);
+ off = offsetof(struct sk_buff, hash);
emit(ARM_LDR_I(r_A, r_skb, off), ctx);
break;
case BPF_S_ANC_VLAN_TAG:
@@ -925,6 +925,7 @@ void bpf_jit_compile(struct sk_filter *fp)
bpf_jit_dump(fp->len, alloc_size, 2, ctx.target);
fp->bpf_func = (void *)ctx.target;
+ fp->jited = 1;
out:
kfree(ctx.offsets);
return;
@@ -932,7 +933,7 @@ out:
void bpf_jit_free(struct sk_filter *fp)
{
- if (fp->bpf_func != sk_run_filter)
+ if (fp->jited)
module_free(NULL, fp->bpf_func);
kfree(fp);
}
diff --git a/arch/arm/xen/p2m.c b/arch/arm/xen/p2m.c
index b31ee1b275b0..97baf4427817 100644
--- a/arch/arm/xen/p2m.c
+++ b/arch/arm/xen/p2m.c
@@ -146,6 +146,38 @@ unsigned long __mfn_to_pfn(unsigned long mfn)
}
EXPORT_SYMBOL_GPL(__mfn_to_pfn);
+int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops,
+ struct gnttab_map_grant_ref *kmap_ops,
+ struct page **pages, unsigned int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (map_ops[i].status)
+ continue;
+ set_phys_to_machine(map_ops[i].host_addr >> PAGE_SHIFT,
+ map_ops[i].dev_bus_addr >> PAGE_SHIFT);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(set_foreign_p2m_mapping);
+
+int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops,
+ struct gnttab_map_grant_ref *kmap_ops,
+ struct page **pages, unsigned int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ set_phys_to_machine(unmap_ops[i].host_addr >> PAGE_SHIFT,
+ INVALID_P2M_ENTRY);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(clear_foreign_p2m_mapping);
+
bool __set_phys_to_machine_multi(unsigned long pfn,
unsigned long mfn, unsigned long nr_pages)
{
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 27bbcfc7202a..9711a5fd948d 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -16,6 +16,7 @@ config ARM64
select DCACHE_WORD_ACCESS
select GENERIC_CLOCKEVENTS
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
+ select GENERIC_CPU_AUTOPROBE
select GENERIC_IOMAP
select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW
@@ -26,6 +27,7 @@ config ARM64
select GENERIC_TIME_VSYSCALL
select HARDIRQS_SW_RESEND
select HAVE_ARCH_JUMP_LABEL
+ select HAVE_ARCH_KGDB
select HAVE_ARCH_TRACEHOOK
select HAVE_DEBUG_BUGVERBOSE
select HAVE_DEBUG_KMEMLEAK
@@ -38,11 +40,14 @@ config ARM64
select HAVE_MEMBLOCK
select HAVE_PATA_PLATFORM
select HAVE_PERF_EVENTS
+ select HAVE_PERF_REGS
+ select HAVE_PERF_USER_STACK_DUMP
select IRQ_DOMAIN
select MODULES_USE_ELF_RELA
select NO_BOOTMEM
select OF
select OF_EARLY_FLATTREE
+ select OF_RESERVED_MEM
select PERF_USE_VMALLOC
select POWER_RESET
select POWER_SUPPLY
@@ -73,7 +78,7 @@ config LOCKDEP_SUPPORT
config TRACE_IRQFLAGS_SUPPORT
def_bool y
-config RWSEM_GENERIC_SPINLOCK
+config RWSEM_XCHGADD_ALGORITHM
def_bool y
config GENERIC_HWEIGHT
@@ -85,7 +90,7 @@ config GENERIC_CSUM
config GENERIC_CALIBRATE_DELAY
def_bool y
-config ZONE_DMA32
+config ZONE_DMA
def_bool y
config ARCH_DMA_ADDR_T_64BIT
@@ -164,6 +169,22 @@ config SMP
If you don't know what to do here, say N.
+config SCHED_MC
+ bool "Multi-core scheduler support"
+ depends on SMP
+ help
+ Multi-core scheduler support improves the CPU scheduler's decision
+ making when dealing with multi-core CPU chips at a cost of slightly
+ increased overhead in some places. If unsure say N here.
+
+config SCHED_SMT
+ bool "SMT scheduler support"
+ depends on SMP
+ help
+ Improves the CPU scheduler's decision making when dealing with
+ MultiThreading at a cost of slightly increased overhead in some
+ places. If unsure say N here.
+
config NR_CPUS
int "Maximum number of CPUs (2-32)"
range 2 32
@@ -301,6 +322,10 @@ menu "CPU Power Management"
source "drivers/cpuidle/Kconfig"
+source "kernel/power/Kconfig"
+
+source "drivers/cpufreq/Kconfig"
+
endmenu
source "net/Kconfig"
diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm-storm.dtsi
index d37d7369e260..93f4b2dd9248 100644
--- a/arch/arm64/boot/dts/apm-storm.dtsi
+++ b/arch/arm64/boot/dts/apm-storm.dtsi
@@ -176,6 +176,87 @@
reg-names = "csr-reg";
clock-output-names = "eth8clk";
};
+
+ sataphy1clk: sataphy1clk@1f21c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x1f21c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ clock-output-names = "sataphy1clk";
+ status = "disabled";
+ csr-offset = <0x4>;
+ csr-mask = <0x00>;
+ enable-offset = <0x0>;
+ enable-mask = <0x06>;
+ };
+
+ sataphy2clk: sataphy1clk@1f22c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x1f22c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ clock-output-names = "sataphy2clk";
+ status = "ok";
+ csr-offset = <0x4>;
+ csr-mask = <0x3a>;
+ enable-offset = <0x0>;
+ enable-mask = <0x06>;
+ };
+
+ sataphy3clk: sataphy1clk@1f23c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x1f23c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ clock-output-names = "sataphy3clk";
+ status = "ok";
+ csr-offset = <0x4>;
+ csr-mask = <0x3a>;
+ enable-offset = <0x0>;
+ enable-mask = <0x06>;
+ };
+
+ sata01clk: sata01clk@1f21c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x1f21c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ clock-output-names = "sata01clk";
+ csr-offset = <0x4>;
+ csr-mask = <0x05>;
+ enable-offset = <0x0>;
+ enable-mask = <0x39>;
+ };
+
+ sata23clk: sata23clk@1f22c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x1f22c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ clock-output-names = "sata23clk";
+ csr-offset = <0x4>;
+ csr-mask = <0x05>;
+ enable-offset = <0x0>;
+ enable-mask = <0x39>;
+ };
+
+ sata45clk: sata45clk@1f23c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x1f23c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ clock-output-names = "sata45clk";
+ csr-offset = <0x4>;
+ csr-mask = <0x05>;
+ enable-offset = <0x0>;
+ enable-mask = <0x39>;
+ };
};
serial0: serial@1c020000 {
@@ -187,5 +268,76 @@
interrupt-parent = <&gic>;
interrupts = <0x0 0x4c 0x4>;
};
+
+ phy1: phy@1f21a000 {
+ compatible = "apm,xgene-phy";
+ reg = <0x0 0x1f21a000 0x0 0x100>;
+ #phy-cells = <1>;
+ clocks = <&sataphy1clk 0>;
+ status = "disabled";
+ apm,tx-boost-gain = <30 30 30 30 30 30>;
+ apm,tx-eye-tuning = <2 10 10 2 10 10>;
+ };
+
+ phy2: phy@1f22a000 {
+ compatible = "apm,xgene-phy";
+ reg = <0x0 0x1f22a000 0x0 0x100>;
+ #phy-cells = <1>;
+ clocks = <&sataphy2clk 0>;
+ status = "ok";
+ apm,tx-boost-gain = <30 30 30 30 30 30>;
+ apm,tx-eye-tuning = <1 10 10 2 10 10>;
+ };
+
+ phy3: phy@1f23a000 {
+ compatible = "apm,xgene-phy";
+ reg = <0x0 0x1f23a000 0x0 0x100>;
+ #phy-cells = <1>;
+ clocks = <&sataphy3clk 0>;
+ status = "ok";
+ apm,tx-boost-gain = <31 31 31 31 31 31>;
+ apm,tx-eye-tuning = <2 10 10 2 10 10>;
+ };
+
+ sata1: sata@1a000000 {
+ compatible = "apm,xgene-ahci";
+ reg = <0x0 0x1a000000 0x0 0x1000>,
+ <0x0 0x1f210000 0x0 0x1000>,
+ <0x0 0x1f21d000 0x0 0x1000>,
+ <0x0 0x1f21e000 0x0 0x1000>,
+ <0x0 0x1f217000 0x0 0x1000>;
+ interrupts = <0x0 0x86 0x4>;
+ status = "disabled";
+ clocks = <&sata01clk 0>;
+ phys = <&phy1 0>;
+ phy-names = "sata-phy";
+ };
+
+ sata2: sata@1a400000 {
+ compatible = "apm,xgene-ahci";
+ reg = <0x0 0x1a400000 0x0 0x1000>,
+ <0x0 0x1f220000 0x0 0x1000>,
+ <0x0 0x1f22d000 0x0 0x1000>,
+ <0x0 0x1f22e000 0x0 0x1000>,
+ <0x0 0x1f227000 0x0 0x1000>;
+ interrupts = <0x0 0x87 0x4>;
+ status = "ok";
+ clocks = <&sata23clk 0>;
+ phys = <&phy2 0>;
+ phy-names = "sata-phy";
+ };
+
+ sata3: sata@1a800000 {
+ compatible = "apm,xgene-ahci";
+ reg = <0x0 0x1a800000 0x0 0x1000>,
+ <0x0 0x1f230000 0x0 0x1000>,
+ <0x0 0x1f23d000 0x0 0x1000>,
+ <0x0 0x1f23e000 0x0 0x1000>;
+ interrupts = <0x0 0x88 0x4>;
+ status = "ok";
+ clocks = <&sata45clk 0>;
+ phys = <&phy3 0>;
+ phy-names = "sata-phy";
+ };
};
};
diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild
index 71c53ecfcc3a..4bca4923fc0b 100644
--- a/arch/arm64/include/asm/Kbuild
+++ b/arch/arm64/include/asm/Kbuild
@@ -12,6 +12,7 @@ generic-y += dma.h
generic-y += emergency-restart.h
generic-y += errno.h
generic-y += ftrace.h
+generic-y += hash.h
generic-y += hw_irq.h
generic-y += ioctl.h
generic-y += ioctls.h
@@ -22,13 +23,16 @@ generic-y += kmap_types.h
generic-y += kvm_para.h
generic-y += local.h
generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += mman.h
generic-y += msgbuf.h
generic-y += mutex.h
generic-y += pci.h
generic-y += poll.h
generic-y += posix_types.h
+generic-y += preempt.h
generic-y += resource.h
+generic-y += rwsem.h
generic-y += scatterlist.h
generic-y += sections.h
generic-y += segment.h
@@ -38,8 +42,8 @@ generic-y += shmbuf.h
generic-y += sizes.h
generic-y += socket.h
generic-y += sockios.h
-generic-y += switch_to.h
generic-y += swab.h
+generic-y += switch_to.h
generic-y += termbits.h
generic-y += termios.h
generic-y += topology.h
@@ -49,5 +53,3 @@ generic-y += unaligned.h
generic-y += user.h
generic-y += vga.h
generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
index 409ca370cfe2..66eb7648043b 100644
--- a/arch/arm64/include/asm/barrier.h
+++ b/arch/arm64/include/asm/barrier.h
@@ -25,6 +25,7 @@
#define wfi() asm volatile("wfi" : : : "memory")
#define isb() asm volatile("isb" : : : "memory")
+#define dmb(opt) asm volatile("dmb sy" : : : "memory")
#define dsb(opt) asm volatile("dsb sy" : : : "memory")
#define mb() dsb()
diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
index 889324981aa4..4c60e64a801c 100644
--- a/arch/arm64/include/asm/cacheflush.h
+++ b/arch/arm64/include/asm/cacheflush.h
@@ -85,6 +85,13 @@ static inline void flush_cache_page(struct vm_area_struct *vma,
}
/*
+ * Cache maintenance functions used by the DMA API. No to be used directly.
+ */
+extern void __dma_map_area(const void *, size_t, int);
+extern void __dma_unmap_area(const void *, size_t, int);
+extern void __dma_flush_range(const void *, const void *);
+
+/*
* Copy user data from/to a page which is mapped into a different
* processes address space. Really, we want to allow our "user
* space" model to handle this.
diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
index fda2704b3f9f..e71f81fe127a 100644
--- a/arch/arm64/include/asm/compat.h
+++ b/arch/arm64/include/asm/compat.h
@@ -228,7 +228,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr)
return (u32)(unsigned long)uptr;
}
-#define compat_user_stack_pointer() (current_pt_regs()->compat_sp)
+#define compat_user_stack_pointer() (user_stack_pointer(current_pt_regs()))
static inline void __user *arch_compat_alloc_user_space(long len)
{
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
new file mode 100644
index 000000000000..cd4ac0516488
--- /dev/null
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_CPUFEATURE_H
+#define __ASM_CPUFEATURE_H
+
+#include <asm/hwcap.h>
+
+/*
+ * In the arm64 world (as in the ARM world), elf_hwcap is used both internally
+ * in the kernel and for user space to keep track of which optional features
+ * are supported by the current system. So let's map feature 'x' to HWCAP_x.
+ * Note that HWCAP_x constants are bit fields so we need to take the log.
+ */
+
+#define MAX_CPU_FEATURES (8 * sizeof(elf_hwcap))
+#define cpu_feature(x) ilog2(HWCAP_ ## x)
+
+static inline bool cpu_have_feature(unsigned int num)
+{
+ return elf_hwcap & (1UL << num);
+}
+
+#endif
diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h
index 62314791570c..6e9b5b36921c 100644
--- a/arch/arm64/include/asm/debug-monitors.h
+++ b/arch/arm64/include/asm/debug-monitors.h
@@ -26,6 +26,53 @@
#define DBG_ESR_EVT_HWWP 0x2
#define DBG_ESR_EVT_BRK 0x6
+/*
+ * Break point instruction encoding
+ */
+#define BREAK_INSTR_SIZE 4
+
+/*
+ * ESR values expected for dynamic and compile time BRK instruction
+ */
+#define DBG_ESR_VAL_BRK(x) (0xf2000000 | ((x) & 0xfffff))
+
+/*
+ * #imm16 values used for BRK instruction generation
+ * Allowed values for kgbd are 0x400 - 0x7ff
+ * 0x400: for dynamic BRK instruction
+ * 0x401: for compile time BRK instruction
+ */
+#define KGDB_DYN_DGB_BRK_IMM 0x400
+#define KDBG_COMPILED_DBG_BRK_IMM 0x401
+
+/*
+ * BRK instruction encoding
+ * The #imm16 value should be placed at bits[20:5] within BRK ins
+ */
+#define AARCH64_BREAK_MON 0xd4200000
+
+/*
+ * Extract byte from BRK instruction
+ */
+#define KGDB_DYN_DGB_BRK_INS_BYTE(x) \
+ ((((AARCH64_BREAK_MON) & 0xffe0001f) >> (x * 8)) & 0xff)
+
+/*
+ * Extract byte from BRK #imm16
+ */
+#define KGBD_DYN_DGB_BRK_IMM_BYTE(x) \
+ (((((KGDB_DYN_DGB_BRK_IMM) & 0xffff) << 5) >> (x * 8)) & 0xff)
+
+#define KGDB_DYN_DGB_BRK_BYTE(x) \
+ (KGDB_DYN_DGB_BRK_INS_BYTE(x) | KGBD_DYN_DGB_BRK_IMM_BYTE(x))
+
+#define KGDB_DYN_BRK_INS_BYTE0 KGDB_DYN_DGB_BRK_BYTE(0)
+#define KGDB_DYN_BRK_INS_BYTE1 KGDB_DYN_DGB_BRK_BYTE(1)
+#define KGDB_DYN_BRK_INS_BYTE2 KGDB_DYN_DGB_BRK_BYTE(2)
+#define KGDB_DYN_BRK_INS_BYTE3 KGDB_DYN_DGB_BRK_BYTE(3)
+
+#define CACHE_FLUSH_IS_SAFE 1
+
enum debug_el {
DBG_ACTIVE_EL0 = 0,
DBG_ACTIVE_EL1,
@@ -43,23 +90,6 @@ enum debug_el {
#ifndef __ASSEMBLY__
struct task_struct;
-#define local_dbg_save(flags) \
- do { \
- typecheck(unsigned long, flags); \
- asm volatile( \
- "mrs %0, daif // local_dbg_save\n" \
- "msr daifset, #8" \
- : "=r" (flags) : : "memory"); \
- } while (0)
-
-#define local_dbg_restore(flags) \
- do { \
- typecheck(unsigned long, flags); \
- asm volatile( \
- "msr daif, %0 // local_dbg_restore\n" \
- : : "r" (flags) : "memory"); \
- } while (0)
-
#define DBG_ARCH_ID_RESERVED 0 /* In case of ptrace ABI updates. */
#define DBG_HOOK_HANDLED 0
diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h
index fd0c0c0e447a..3a4572ec3273 100644
--- a/arch/arm64/include/asm/dma-mapping.h
+++ b/arch/arm64/include/asm/dma-mapping.h
@@ -30,6 +30,8 @@
#define DMA_ERROR_CODE (~(dma_addr_t)0)
extern struct dma_map_ops *dma_ops;
+extern struct dma_map_ops coherent_swiotlb_dma_ops;
+extern struct dma_map_ops noncoherent_swiotlb_dma_ops;
static inline struct dma_map_ops *__generic_dma_ops(struct device *dev)
{
@@ -47,6 +49,11 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
return __generic_dma_ops(dev);
}
+static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops)
+{
+ dev->archdata.dma_ops = ops;
+}
+
#include <asm-generic/dma-mapping-common.h>
static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
index 6cddbb0c9f54..024c46183c3c 100644
--- a/arch/arm64/include/asm/hwcap.h
+++ b/arch/arm64/include/asm/hwcap.h
@@ -32,6 +32,12 @@
#define COMPAT_HWCAP_IDIV (COMPAT_HWCAP_IDIVA|COMPAT_HWCAP_IDIVT)
#define COMPAT_HWCAP_EVTSTRM (1 << 21)
+#define COMPAT_HWCAP2_AES (1 << 0)
+#define COMPAT_HWCAP2_PMULL (1 << 1)
+#define COMPAT_HWCAP2_SHA1 (1 << 2)
+#define COMPAT_HWCAP2_SHA2 (1 << 3)
+#define COMPAT_HWCAP2_CRC32 (1 << 4)
+
#ifndef __ASSEMBLY__
/*
* This yields a mask that user programs can use to figure out what
@@ -41,7 +47,8 @@
#ifdef CONFIG_COMPAT
#define COMPAT_ELF_HWCAP (compat_elf_hwcap)
-extern unsigned int compat_elf_hwcap;
+#define COMPAT_ELF_HWCAP2 (compat_elf_hwcap2)
+extern unsigned int compat_elf_hwcap, compat_elf_hwcap2;
#endif
extern unsigned long elf_hwcap;
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 4cc813eddacb..7846a6bb0833 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -121,7 +121,7 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
* I/O port access primitives.
*/
#define IO_SPACE_LIMIT 0xffff
-#define PCI_IOBASE ((void __iomem *)(MODULES_VADDR - SZ_2M))
+#define PCI_IOBASE ((void __iomem *)(MODULES_VADDR - SZ_32M))
static inline u8 inb(unsigned long addr)
{
diff --git a/arch/arm64/include/asm/irqflags.h b/arch/arm64/include/asm/irqflags.h
index b2fcfbc51ecc..11cc941bd107 100644
--- a/arch/arm64/include/asm/irqflags.h
+++ b/arch/arm64/include/asm/irqflags.h
@@ -90,5 +90,28 @@ static inline int arch_irqs_disabled_flags(unsigned long flags)
return flags & PSR_I_BIT;
}
+/*
+ * save and restore debug state
+ */
+#define local_dbg_save(flags) \
+ do { \
+ typecheck(unsigned long, flags); \
+ asm volatile( \
+ "mrs %0, daif // local_dbg_save\n" \
+ "msr daifset, #8" \
+ : "=r" (flags) : : "memory"); \
+ } while (0)
+
+#define local_dbg_restore(flags) \
+ do { \
+ typecheck(unsigned long, flags); \
+ asm volatile( \
+ "msr daif, %0 // local_dbg_restore\n" \
+ : : "r" (flags) : "memory"); \
+ } while (0)
+
+#define local_dbg_enable() asm("msr daifclr, #8" : : : "memory")
+#define local_dbg_disable() asm("msr daifset, #8" : : : "memory")
+
#endif
#endif
diff --git a/arch/arm64/include/asm/kgdb.h b/arch/arm64/include/asm/kgdb.h
new file mode 100644
index 000000000000..3c8aafc1082f
--- /dev/null
+++ b/arch/arm64/include/asm/kgdb.h
@@ -0,0 +1,84 @@
+/*
+ * AArch64 KGDB support
+ *
+ * Based on arch/arm/include/kgdb.h
+ *
+ * Copyright (C) 2013 Cavium Inc.
+ * Author: Vijaya Kumar K <vijaya.kumar@caviumnetworks.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARM_KGDB_H
+#define __ARM_KGDB_H
+
+#include <linux/ptrace.h>
+#include <asm/debug-monitors.h>
+
+#ifndef __ASSEMBLY__
+
+static inline void arch_kgdb_breakpoint(void)
+{
+ asm ("brk %0" : : "I" (KDBG_COMPILED_DBG_BRK_IMM));
+}
+
+extern void kgdb_handle_bus_error(void);
+extern int kgdb_fault_expected;
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * gdb is expecting the following registers layout.
+ *
+ * General purpose regs:
+ * r0-r30: 64 bit
+ * sp,pc : 64 bit
+ * pstate : 64 bit
+ * Total: 34
+ * FPU regs:
+ * f0-f31: 128 bit
+ * Total: 32
+ * Extra regs
+ * fpsr & fpcr: 32 bit
+ * Total: 2
+ *
+ */
+
+#define _GP_REGS 34
+#define _FP_REGS 32
+#define _EXTRA_REGS 2
+/*
+ * general purpose registers size in bytes.
+ * pstate is only 4 bytes. subtract 4 bytes
+ */
+#define GP_REG_BYTES (_GP_REGS * 8)
+#define DBG_MAX_REG_NUM (_GP_REGS + _FP_REGS + _EXTRA_REGS)
+
+/*
+ * Size of I/O buffer for gdb packet.
+ * considering to hold all register contents, size is set
+ */
+
+#define BUFMAX 2048
+
+/*
+ * Number of bytes required for gdb_regs buffer.
+ * _GP_REGS: 8 bytes, _FP_REGS: 16 bytes and _EXTRA_REGS: 4 bytes each
+ * GDB fails to connect for size beyond this with error
+ * "'g' packet reply is too long"
+ */
+
+#define NUMREGBYTES ((_GP_REGS * 8) + (_FP_REGS * 16) + \
+ (_EXTRA_REGS * 4))
+
+#endif /* __ASM_KGDB_H */
diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 0eb398655378..3d6903006a8a 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -62,6 +62,7 @@
* RW: 64bit by default, can be overriden for 32bit VMs
* TAC: Trap ACTLR
* TSC: Trap SMC
+ * TVM: Trap VM ops (until M+C set in SCTLR_EL1)
* TSW: Trap cache operations by set/way
* TWE: Trap WFE
* TWI: Trap WFI
@@ -74,7 +75,7 @@
* SWIO: Turn set/way invalidates into set/way clean+invalidate
*/
#define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \
- HCR_BSU_IS | HCR_FB | HCR_TAC | \
+ HCR_TVM | HCR_BSU_IS | HCR_FB | HCR_TAC | \
HCR_AMO | HCR_IMO | HCR_FMO | \
HCR_SWIO | HCR_TIDCP | HCR_RW)
#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
@@ -106,7 +107,6 @@
/* VTCR_EL2 Registers bits */
#define VTCR_EL2_PS_MASK (7 << 16)
-#define VTCR_EL2_PS_40B (2 << 16)
#define VTCR_EL2_TG0_MASK (1 << 14)
#define VTCR_EL2_TG0_4K (0 << 14)
#define VTCR_EL2_TG0_64K (1 << 14)
@@ -129,10 +129,9 @@
* 64kB pages (TG0 = 1)
* 2 level page tables (SL = 1)
*/
-#define VTCR_EL2_FLAGS (VTCR_EL2_PS_40B | VTCR_EL2_TG0_64K | \
- VTCR_EL2_SH0_INNER | VTCR_EL2_ORGN0_WBWA | \
- VTCR_EL2_IRGN0_WBWA | VTCR_EL2_SL0_LVL1 | \
- VTCR_EL2_T0SZ_40B)
+#define VTCR_EL2_FLAGS (VTCR_EL2_TG0_64K | VTCR_EL2_SH0_INNER | \
+ VTCR_EL2_ORGN0_WBWA | VTCR_EL2_IRGN0_WBWA | \
+ VTCR_EL2_SL0_LVL1 | VTCR_EL2_T0SZ_40B)
#define VTTBR_X (38 - VTCR_EL2_T0SZ_40B)
#else
/*
@@ -142,10 +141,9 @@
* 4kB pages (TG0 = 0)
* 3 level page tables (SL = 1)
*/
-#define VTCR_EL2_FLAGS (VTCR_EL2_PS_40B | VTCR_EL2_TG0_4K | \
- VTCR_EL2_SH0_INNER | VTCR_EL2_ORGN0_WBWA | \
- VTCR_EL2_IRGN0_WBWA | VTCR_EL2_SL0_LVL1 | \
- VTCR_EL2_T0SZ_40B)
+#define VTCR_EL2_FLAGS (VTCR_EL2_TG0_4K | VTCR_EL2_SH0_INNER | \
+ VTCR_EL2_ORGN0_WBWA | VTCR_EL2_IRGN0_WBWA | \
+ VTCR_EL2_SL0_LVL1 | VTCR_EL2_T0SZ_40B)
#define VTTBR_X (37 - VTCR_EL2_T0SZ_40B)
#endif
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index b25763bc0ec4..9fcd54b1e16d 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -79,7 +79,8 @@
#define c13_TID_URW (TPIDR_EL0 * 2) /* Thread ID, User R/W */
#define c13_TID_URO (TPIDRRO_EL0 * 2)/* Thread ID, User R/O */
#define c13_TID_PRIV (TPIDR_EL1 * 2) /* Thread ID, Privileged */
-#define c10_AMAIR (AMAIR_EL1 * 2) /* Aux Memory Attr Indirection Reg */
+#define c10_AMAIR0 (AMAIR_EL1 * 2) /* Aux Memory Attr Indirection Reg */
+#define c10_AMAIR1 (c10_AMAIR0 + 1)/* Aux Memory Attr Indirection Reg */
#define c14_CNTKCTL (CNTKCTL_EL1 * 2) /* Timer Control Register (PL1) */
#define NR_CP15_REGS (NR_SYS_REGS * 2)
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 7f1f9408ff66..7d29847a893b 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -106,7 +106,6 @@ static inline bool kvm_is_write_fault(unsigned long esr)
return true;
}
-static inline void kvm_clean_dcache_area(void *addr, size_t size) {}
static inline void kvm_clean_pgd(pgd_t *pgd) {}
static inline void kvm_clean_pmd_entry(pmd_t *pmd) {}
static inline void kvm_clean_pte(pte_t *pte) {}
@@ -122,11 +121,25 @@ static inline void kvm_set_s2pmd_writable(pmd_t *pmd)
pmd_val(*pmd) |= PMD_S2_RDWR;
}
+#define kvm_pgd_addr_end(addr, end) pgd_addr_end(addr, end)
+#define kvm_pud_addr_end(addr, end) pud_addr_end(addr, end)
+#define kvm_pmd_addr_end(addr, end) pmd_addr_end(addr, end)
+
struct kvm;
-static inline void coherent_icache_guest_page(struct kvm *kvm, hva_t hva,
- unsigned long size)
+#define kvm_flush_dcache_to_poc(a,l) __flush_dcache_area((a), (l))
+
+static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
{
+ return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
+}
+
+static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva,
+ unsigned long size)
+{
+ if (!vcpu_has_cache_enabled(vcpu))
+ kvm_flush_dcache_to_poc((void *)hva, size);
+
if (!icache_is_aliasing()) { /* PIPT */
flush_icache_range(hva, hva + size);
} else if (!icache_is_aivivt()) { /* non ASID-tagged VIVT */
@@ -135,8 +148,9 @@ static inline void coherent_icache_guest_page(struct kvm *kvm, hva_t hva,
}
}
-#define kvm_flush_dcache_to_poc(a,l) __flush_dcache_area((a), (l))
#define kvm_virt_to_phys(x) __virt_to_phys((unsigned long)(x))
+void stage2_flush_vm(struct kvm *kvm);
+
#endif /* __ASSEMBLY__ */
#endif /* __ARM64_KVM_MMU_H__ */
diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h
index 13fb0b3efc5f..453a179469a3 100644
--- a/arch/arm64/include/asm/percpu.h
+++ b/arch/arm64/include/asm/percpu.h
@@ -16,6 +16,8 @@
#ifndef __ASM_PERCPU_H
#define __ASM_PERCPU_H
+#ifdef CONFIG_SMP
+
static inline void set_my_cpu_offset(unsigned long off)
{
asm volatile("msr tpidr_el1, %0" :: "r" (off) : "memory");
@@ -36,6 +38,12 @@ static inline unsigned long __my_cpu_offset(void)
}
#define __my_cpu_offset __my_cpu_offset()
+#else /* !CONFIG_SMP */
+
+#define set_my_cpu_offset(x) do { } while (0)
+
+#endif /* CONFIG_SMP */
+
#include <asm-generic/percpu.h>
#endif /* __ASM_PERCPU_H */
diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
index b1d2e26c3c88..f7af66b54cb2 100644
--- a/arch/arm64/include/asm/pgtable-hwdef.h
+++ b/arch/arm64/include/asm/pgtable-hwdef.h
@@ -100,9 +100,9 @@
#define PTE_HYP PTE_USER
/*
- * 40-bit physical address supported.
+ * Highest possible physical address supported.
*/
-#define PHYS_MASK_SHIFT (40)
+#define PHYS_MASK_SHIFT (48)
#define PHYS_MASK ((UL(1) << PHYS_MASK_SHIFT) - 1)
/*
@@ -122,7 +122,6 @@
#define TCR_SHARED ((UL(3) << 12) | (UL(3) << 28))
#define TCR_TG0_64K (UL(1) << 14)
#define TCR_TG1_64K (UL(1) << 30)
-#define TCR_IPS_40BIT (UL(2) << 32)
#define TCR_ASID16 (UL(1) << 36)
#define TCR_TBI0 (UL(1) << 37)
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index b524dcd17243..90c811f05a2e 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -136,11 +136,11 @@ extern struct page *empty_zero_page;
/*
* The following only work if pte_present(). Undefined behaviour otherwise.
*/
-#define pte_present(pte) (pte_val(pte) & (PTE_VALID | PTE_PROT_NONE))
-#define pte_dirty(pte) (pte_val(pte) & PTE_DIRTY)
-#define pte_young(pte) (pte_val(pte) & PTE_AF)
-#define pte_special(pte) (pte_val(pte) & PTE_SPECIAL)
-#define pte_write(pte) (pte_val(pte) & PTE_WRITE)
+#define pte_present(pte) (!!(pte_val(pte) & (PTE_VALID | PTE_PROT_NONE)))
+#define pte_dirty(pte) (!!(pte_val(pte) & PTE_DIRTY))
+#define pte_young(pte) (!!(pte_val(pte) & PTE_AF))
+#define pte_special(pte) (!!(pte_val(pte) & PTE_SPECIAL))
+#define pte_write(pte) (!!(pte_val(pte) & PTE_WRITE))
#define pte_exec(pte) (!(pte_val(pte) & PTE_UXN))
#define pte_valid_user(pte) \
@@ -199,7 +199,7 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte)
{
if (pte_valid_user(pte)) {
- if (pte_exec(pte))
+ if (!pte_special(pte) && pte_exec(pte))
__sync_icache_dcache(pte, addr);
if (pte_dirty(pte) && pte_write(pte))
pte_val(pte) &= ~PTE_RDONLY;
@@ -227,36 +227,36 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
#define __HAVE_ARCH_PTE_SPECIAL
-/*
- * Software PMD bits for THP
- */
+static inline pte_t pmd_pte(pmd_t pmd)
+{
+ return __pte(pmd_val(pmd));
+}
-#define PMD_SECT_DIRTY (_AT(pmdval_t, 1) << 55)
-#define PMD_SECT_SPLITTING (_AT(pmdval_t, 1) << 57)
+static inline pmd_t pte_pmd(pte_t pte)
+{
+ return __pmd(pte_val(pte));
+}
/*
* THP definitions.
*/
-#define pmd_young(pmd) (pmd_val(pmd) & PMD_SECT_AF)
-
-#define __HAVE_ARCH_PMD_WRITE
-#define pmd_write(pmd) (!(pmd_val(pmd) & PMD_SECT_RDONLY))
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
#define pmd_trans_huge(pmd) (pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT))
-#define pmd_trans_splitting(pmd) (pmd_val(pmd) & PMD_SECT_SPLITTING)
+#define pmd_trans_splitting(pmd) pte_special(pmd_pte(pmd))
#endif
-#define PMD_BIT_FUNC(fn,op) \
-static inline pmd_t pmd_##fn(pmd_t pmd) { pmd_val(pmd) op; return pmd; }
+#define pmd_young(pmd) pte_young(pmd_pte(pmd))
+#define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd)))
+#define pmd_mksplitting(pmd) pte_pmd(pte_mkspecial(pmd_pte(pmd)))
+#define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd)))
+#define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd)))
+#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd)))
+#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd)))
+#define pmd_mknotpresent(pmd) (__pmd(pmd_val(pmd) &= ~PMD_TYPE_MASK))
-PMD_BIT_FUNC(wrprotect, |= PMD_SECT_RDONLY);
-PMD_BIT_FUNC(mkold, &= ~PMD_SECT_AF);
-PMD_BIT_FUNC(mksplitting, |= PMD_SECT_SPLITTING);
-PMD_BIT_FUNC(mkwrite, &= ~PMD_SECT_RDONLY);
-PMD_BIT_FUNC(mkdirty, |= PMD_SECT_DIRTY);
-PMD_BIT_FUNC(mkyoung, |= PMD_SECT_AF);
-PMD_BIT_FUNC(mknotpresent, &= ~PMD_TYPE_MASK);
+#define __HAVE_ARCH_PMD_WRITE
+#define pmd_write(pmd) pte_write(pmd_pte(pmd))
#define pmd_mkhuge(pmd) (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
@@ -266,15 +266,6 @@ PMD_BIT_FUNC(mknotpresent, &= ~PMD_TYPE_MASK);
#define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK))
-static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
-{
- const pmdval_t mask = PMD_SECT_USER | PMD_SECT_PXN | PMD_SECT_UXN |
- PMD_SECT_RDONLY | PMD_SECT_PROT_NONE |
- PMD_SECT_VALID;
- pmd_val(pmd) = (pmd_val(pmd) & ~mask) | (pgprot_val(newprot) & mask);
- return pmd;
-}
-
#define set_pmd_at(mm, addr, pmdp, pmd) set_pmd(pmdp, pmd)
static inline int has_transparent_hugepage(void)
@@ -286,11 +277,9 @@ static inline int has_transparent_hugepage(void)
* Mark the prot value as uncacheable and unbufferable.
*/
#define pgprot_noncached(prot) \
- __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE))
+ __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE) | PTE_PXN | PTE_UXN)
#define pgprot_writecombine(prot) \
- __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC))
-#define pgprot_dmacoherent(prot) \
- __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC))
+ __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)
#define __HAVE_PHYS_MEM_ACCESS_PROT
struct file;
extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
@@ -383,6 +372,11 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
return pte;
}
+static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
+{
+ return pte_pmd(pte_modify(pmd_pte(pmd), newprot));
+}
+
extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
diff --git a/arch/arm64/include/asm/psci.h b/arch/arm64/include/asm/psci.h
index e5312ea0ec1a..d15ab8b46336 100644
--- a/arch/arm64/include/asm/psci.h
+++ b/arch/arm64/include/asm/psci.h
@@ -14,6 +14,6 @@
#ifndef __ASM_PSCI_H
#define __ASM_PSCI_H
-int psci_init(void);
+void psci_init(void);
#endif /* __ASM_PSCI_H */
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 0e7fa4963735..c7ba261dd4b3 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -68,6 +68,7 @@
/* Architecturally defined mapping between AArch32 and AArch64 registers */
#define compat_usr(x) regs[(x)]
+#define compat_fp regs[11]
#define compat_sp regs[13]
#define compat_lr regs[14]
#define compat_sp_hyp regs[15]
@@ -132,7 +133,7 @@ struct pt_regs {
(!((regs)->pstate & PSR_F_BIT))
#define user_stack_pointer(regs) \
- ((regs)->sp)
+ (!compat_user_mode(regs)) ? ((regs)->sp) : ((regs)->compat_sp)
/*
* Are the current registers suitable for user mode? (used to maintain
@@ -164,7 +165,7 @@ static inline int valid_user_regs(struct user_pt_regs *regs)
return 0;
}
-#define instruction_pointer(regs) (regs)->pc
+#define instruction_pointer(regs) ((unsigned long)(regs)->pc)
#ifdef CONFIG_SMP
extern unsigned long profile_pc(struct pt_regs *regs);
diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h
index 717031a762c2..72cadf52ca80 100644
--- a/arch/arm64/include/asm/tlb.h
+++ b/arch/arm64/include/asm/tlb.h
@@ -19,115 +19,44 @@
#ifndef __ASM_TLB_H
#define __ASM_TLB_H
-#include <linux/pagemap.h>
-#include <linux/swap.h>
-#include <asm/pgalloc.h>
-#include <asm/tlbflush.h>
-
-#define MMU_GATHER_BUNDLE 8
-
-/*
- * TLB handling. This allows us to remove pages from the page
- * tables, and efficiently handle the TLB issues.
- */
-struct mmu_gather {
- struct mm_struct *mm;
- unsigned int fullmm;
- struct vm_area_struct *vma;
- unsigned long start, end;
- unsigned long range_start;
- unsigned long range_end;
- unsigned int nr;
- unsigned int max;
- struct page **pages;
- struct page *local[MMU_GATHER_BUNDLE];
-};
+#include <asm-generic/tlb.h>
/*
- * This is unnecessarily complex. There's three ways the TLB shootdown
- * code is used:
+ * There's three ways the TLB shootdown code is used:
* 1. Unmapping a range of vmas. See zap_page_range(), unmap_region().
* tlb->fullmm = 0, and tlb_start_vma/tlb_end_vma will be called.
- * tlb->vma will be non-NULL.
* 2. Unmapping all vmas. See exit_mmap().
* tlb->fullmm = 1, and tlb_start_vma/tlb_end_vma will be called.
- * tlb->vma will be non-NULL. Additionally, page tables will be freed.
+ * Page tables will be freed.
* 3. Unmapping argument pages. See shift_arg_pages().
* tlb->fullmm = 0, but tlb_start_vma/tlb_end_vma will not be called.
- * tlb->vma will be NULL.
*/
static inline void tlb_flush(struct mmu_gather *tlb)
{
- if (tlb->fullmm || !tlb->vma)
+ if (tlb->fullmm) {
flush_tlb_mm(tlb->mm);
- else if (tlb->range_end > 0) {
- flush_tlb_range(tlb->vma, tlb->range_start, tlb->range_end);
- tlb->range_start = TASK_SIZE;
- tlb->range_end = 0;
+ } else if (tlb->end > 0) {
+ struct vm_area_struct vma = { .vm_mm = tlb->mm, };
+ flush_tlb_range(&vma, tlb->start, tlb->end);
+ tlb->start = TASK_SIZE;
+ tlb->end = 0;
}
}
static inline void tlb_add_flush(struct mmu_gather *tlb, unsigned long addr)
{
if (!tlb->fullmm) {
- if (addr < tlb->range_start)
- tlb->range_start = addr;
- if (addr + PAGE_SIZE > tlb->range_end)
- tlb->range_end = addr + PAGE_SIZE;
- }
-}
-
-static inline void __tlb_alloc_page(struct mmu_gather *tlb)
-{
- unsigned long addr = __get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0);
-
- if (addr) {
- tlb->pages = (void *)addr;
- tlb->max = PAGE_SIZE / sizeof(struct page *);
+ tlb->start = min(tlb->start, addr);
+ tlb->end = max(tlb->end, addr + PAGE_SIZE);
}
}
-static inline void tlb_flush_mmu(struct mmu_gather *tlb)
-{
- tlb_flush(tlb);
- free_pages_and_swap_cache(tlb->pages, tlb->nr);
- tlb->nr = 0;
- if (tlb->pages == tlb->local)
- __tlb_alloc_page(tlb);
-}
-
-static inline void
-tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long start, unsigned long end)
-{
- tlb->mm = mm;
- tlb->fullmm = !(start | (end+1));
- tlb->start = start;
- tlb->end = end;
- tlb->vma = NULL;
- tlb->max = ARRAY_SIZE(tlb->local);
- tlb->pages = tlb->local;
- tlb->nr = 0;
- __tlb_alloc_page(tlb);
-}
-
-static inline void
-tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
-{
- tlb_flush_mmu(tlb);
-
- /* keep the page table cache within bounds */
- check_pgt_cache();
-
- if (tlb->pages != tlb->local)
- free_pages((unsigned long)tlb->pages, 0);
-}
-
/*
* Memorize the range for the TLB flush.
*/
-static inline void
-tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, unsigned long addr)
+static inline void __tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep,
+ unsigned long addr)
{
tlb_add_flush(tlb, addr);
}
@@ -137,38 +66,24 @@ tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, unsigned long addr)
* case where we're doing a full MM flush. When we're doing a munmap,
* the vmas are adjusted to only cover the region to be torn down.
*/
-static inline void
-tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
+static inline void tlb_start_vma(struct mmu_gather *tlb,
+ struct vm_area_struct *vma)
{
if (!tlb->fullmm) {
- tlb->vma = vma;
- tlb->range_start = TASK_SIZE;
- tlb->range_end = 0;
+ tlb->start = TASK_SIZE;
+ tlb->end = 0;
}
}
-static inline void
-tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
+static inline void tlb_end_vma(struct mmu_gather *tlb,
+ struct vm_area_struct *vma)
{
if (!tlb->fullmm)
tlb_flush(tlb);
}
-static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
-{
- tlb->pages[tlb->nr++] = page;
- VM_BUG_ON(tlb->nr > tlb->max);
- return tlb->max - tlb->nr;
-}
-
-static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
-{
- if (!__tlb_remove_page(tlb, page))
- tlb_flush_mmu(tlb);
-}
-
static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
- unsigned long addr)
+ unsigned long addr)
{
pgtable_page_dtor(pte);
tlb_add_flush(tlb, addr);
@@ -184,16 +99,5 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
}
#endif
-#define pte_free_tlb(tlb, ptep, addr) __pte_free_tlb(tlb, ptep, addr)
-#define pmd_free_tlb(tlb, pmdp, addr) __pmd_free_tlb(tlb, pmdp, addr)
-#define pud_free_tlb(tlb, pudp, addr) pud_free((tlb)->mm, pudp)
-
-#define tlb_migrate_finish(mm) do { } while (0)
-
-static inline void
-tlb_remove_pmd_tlb_entry(struct mmu_gather *tlb, pmd_t *pmdp, unsigned long addr)
-{
- tlb_add_flush(tlb, addr);
-}
#endif
diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h
new file mode 100644
index 000000000000..0172e6d76bf3
--- /dev/null
+++ b/arch/arm64/include/asm/topology.h
@@ -0,0 +1,39 @@
+#ifndef __ASM_TOPOLOGY_H
+#define __ASM_TOPOLOGY_H
+
+#ifdef CONFIG_SMP
+
+#include <linux/cpumask.h>
+
+struct cpu_topology {
+ int thread_id;
+ int core_id;
+ int cluster_id;
+ cpumask_t thread_sibling;
+ cpumask_t core_sibling;
+};
+
+extern struct cpu_topology cpu_topology[NR_CPUS];
+
+#define topology_physical_package_id(cpu) (cpu_topology[cpu].cluster_id)
+#define topology_core_id(cpu) (cpu_topology[cpu].core_id)
+#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling)
+#define topology_thread_cpumask(cpu) (&cpu_topology[cpu].thread_sibling)
+
+#define mc_capable() (cpu_topology[0].cluster_id != -1)
+#define smt_capable() (cpu_topology[0].thread_id != -1)
+
+void init_cpu_topology(void);
+void store_cpu_topology(unsigned int cpuid);
+const struct cpumask *cpu_coregroup_mask(int cpu);
+
+#else
+
+static inline void init_cpu_topology(void) { }
+static inline void store_cpu_topology(unsigned int cpuid) { }
+
+#endif
+
+#include <asm-generic/topology.h>
+
+#endif /* _ASM_ARM_TOPOLOGY_H */
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 6c0f684aca81..3bf8f4e99a51 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -83,7 +83,7 @@ static inline void set_fs(mm_segment_t fs)
* Returns 1 if the range is valid, 0 otherwise.
*
* This is equivalent to the following test:
- * (u65)addr + (u65)size < (u65)current->addr_limit
+ * (u65)addr + (u65)size <= current->addr_limit
*
* This needs 65-bit arithmetic.
*/
@@ -91,7 +91,7 @@ static inline void set_fs(mm_segment_t fs)
({ \
unsigned long flag, roksum; \
__chk_user_ptr(addr); \
- asm("adds %1, %1, %3; ccmp %1, %4, #2, cc; cset %0, cc" \
+ asm("adds %1, %1, %3; ccmp %1, %4, #2, cc; cset %0, ls" \
: "=&r" (flag), "=&r" (roksum) \
: "1" (addr), "Ir" (size), \
"r" (current_thread_info()->addr_limit) \
diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
index 82ce217e94cf..a4654c656a1e 100644
--- a/arch/arm64/include/asm/unistd.h
+++ b/arch/arm64/include/asm/unistd.h
@@ -14,6 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef CONFIG_COMPAT
+#define __ARCH_WANT_COMPAT_SYS_GETDENTS64
#define __ARCH_WANT_COMPAT_STAT64
#define __ARCH_WANT_SYS_GETHOSTNAME
#define __ARCH_WANT_SYS_PAUSE
diff --git a/arch/arm64/include/uapi/asm/Kbuild b/arch/arm64/include/uapi/asm/Kbuild
index e4b78bdca19e..942376d37d22 100644
--- a/arch/arm64/include/uapi/asm/Kbuild
+++ b/arch/arm64/include/uapi/asm/Kbuild
@@ -9,6 +9,7 @@ header-y += byteorder.h
header-y += fcntl.h
header-y += hwcap.h
header-y += kvm_para.h
+header-y += perf_regs.h
header-y += param.h
header-y += ptrace.h
header-y += setup.h
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 495ab6f84a61..eaf54a30bedc 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -148,6 +148,15 @@ struct kvm_arch_memory_slot {
#define KVM_REG_ARM_TIMER_CNT ARM64_SYS_REG(3, 3, 14, 3, 2)
#define KVM_REG_ARM_TIMER_CVAL ARM64_SYS_REG(3, 3, 14, 0, 2)
+/* Device Control API: ARM VGIC */
+#define KVM_DEV_ARM_VGIC_GRP_ADDR 0
+#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1
+#define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2
+#define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32
+#define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
+#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0
+#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
+
/* KVM_IRQ_LINE irq field index values */
#define KVM_ARM_IRQ_TYPE_SHIFT 24
#define KVM_ARM_IRQ_TYPE_MASK 0xff
diff --git a/arch/arm64/include/uapi/asm/perf_regs.h b/arch/arm64/include/uapi/asm/perf_regs.h
new file mode 100644
index 000000000000..172b8317ee49
--- /dev/null
+++ b/arch/arm64/include/uapi/asm/perf_regs.h
@@ -0,0 +1,40 @@
+#ifndef _ASM_ARM64_PERF_REGS_H
+#define _ASM_ARM64_PERF_REGS_H
+
+enum perf_event_arm_regs {
+ PERF_REG_ARM64_X0,
+ PERF_REG_ARM64_X1,
+ PERF_REG_ARM64_X2,
+ PERF_REG_ARM64_X3,
+ PERF_REG_ARM64_X4,
+ PERF_REG_ARM64_X5,
+ PERF_REG_ARM64_X6,
+ PERF_REG_ARM64_X7,
+ PERF_REG_ARM64_X8,
+ PERF_REG_ARM64_X9,
+ PERF_REG_ARM64_X10,
+ PERF_REG_ARM64_X11,
+ PERF_REG_ARM64_X12,
+ PERF_REG_ARM64_X13,
+ PERF_REG_ARM64_X14,
+ PERF_REG_ARM64_X15,
+ PERF_REG_ARM64_X16,
+ PERF_REG_ARM64_X17,
+ PERF_REG_ARM64_X18,
+ PERF_REG_ARM64_X19,
+ PERF_REG_ARM64_X20,
+ PERF_REG_ARM64_X21,
+ PERF_REG_ARM64_X22,
+ PERF_REG_ARM64_X23,
+ PERF_REG_ARM64_X24,
+ PERF_REG_ARM64_X25,
+ PERF_REG_ARM64_X26,
+ PERF_REG_ARM64_X27,
+ PERF_REG_ARM64_X28,
+ PERF_REG_ARM64_X29,
+ PERF_REG_ARM64_LR,
+ PERF_REG_ARM64_SP,
+ PERF_REG_ARM64_PC,
+ PERF_REG_ARM64_MAX,
+};
+#endif /* _ASM_ARM64_PERF_REGS_H */
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 2d4554b13410..7d811d9522bc 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -14,12 +14,14 @@ arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \
arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
sys_compat.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
-arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o
+arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o topology.o
+arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
-arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o
+arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o
arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
+arm64-obj-$(CONFIG_KGDB) += kgdb.o
obj-y += $(arm64-obj-y) vdso/
obj-m += $(arm64-obj-m)
diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
index 636ba8b6240b..14ba23c61153 100644
--- a/arch/arm64/kernel/debug-monitors.c
+++ b/arch/arm64/kernel/debug-monitors.c
@@ -137,7 +137,6 @@ void disable_debug_monitors(enum debug_el el)
static void clear_os_lock(void *unused)
{
asm volatile("msr oslar_el1, %0" : : "r" (0));
- isb();
}
static int os_lock_notify(struct notifier_block *self,
@@ -156,8 +155,9 @@ static struct notifier_block os_lock_nb = {
static int debug_monitors_init(void)
{
/* Clear the OS lock. */
- smp_call_function(clear_os_lock, NULL, 1);
- clear_os_lock(NULL);
+ on_each_cpu(clear_os_lock, NULL, 1);
+ isb();
+ local_dbg_enable();
/* Register hotplug handler. */
register_cpu_notifier(&os_lock_nb);
@@ -189,7 +189,7 @@ static void clear_regs_spsr_ss(struct pt_regs *regs)
/* EL1 Single Step Handler hooks */
static LIST_HEAD(step_hook);
-DEFINE_RWLOCK(step_hook_lock);
+static DEFINE_RWLOCK(step_hook_lock);
void register_step_hook(struct step_hook *hook)
{
@@ -276,7 +276,7 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
* Use reader/writer locks instead of plain spinlock.
*/
static LIST_HEAD(break_hook);
-DEFINE_RWLOCK(break_hook_lock);
+static DEFINE_RWLOCK(break_hook_lock);
void register_break_hook(struct break_hook *hook)
{
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 0b281fffda51..61035d6814cb 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -384,26 +384,18 @@ ENDPROC(__calc_phys_offset)
* Preserves: tbl, flags
* Corrupts: phys, start, end, pstate
*/
- .macro create_block_map, tbl, flags, phys, start, end, idmap=0
+ .macro create_block_map, tbl, flags, phys, start, end
lsr \phys, \phys, #BLOCK_SHIFT
- .if \idmap
- and \start, \phys, #PTRS_PER_PTE - 1 // table index
- .else
lsr \start, \start, #BLOCK_SHIFT
and \start, \start, #PTRS_PER_PTE - 1 // table index
- .endif
orr \phys, \flags, \phys, lsl #BLOCK_SHIFT // table entry
- .ifnc \start,\end
lsr \end, \end, #BLOCK_SHIFT
and \end, \end, #PTRS_PER_PTE - 1 // table end index
- .endif
9999: str \phys, [\tbl, \start, lsl #3] // store the entry
- .ifnc \start,\end
add \start, \start, #1 // next entry
add \phys, \phys, #BLOCK_SIZE // next block
cmp \start, \end
b.ls 9999b
- .endif
.endm
/*
@@ -435,9 +427,13 @@ __create_page_tables:
* Create the identity mapping.
*/
add x0, x25, #PAGE_SIZE // section table address
- adr x3, __turn_mmu_on // virtual/physical address
+ ldr x3, =KERNEL_START
+ add x3, x3, x28 // __pa(KERNEL_START)
create_pgd_entry x25, x0, x3, x5, x6
- create_block_map x0, x7, x3, x5, x5, idmap=1
+ ldr x6, =KERNEL_END
+ mov x5, x3 // __pa(KERNEL_START)
+ add x6, x6, x28 // __pa(KERNEL_END)
+ create_block_map x0, x7, x3, x5, x6
/*
* Map the kernel image (starting with PHYS_OFFSET).
@@ -445,7 +441,7 @@ __create_page_tables:
add x0, x26, #PAGE_SIZE // section table address
mov x5, #PAGE_OFFSET
create_pgd_entry x26, x0, x5, x3, x6
- ldr x6, =KERNEL_END - 1
+ ldr x6, =KERNEL_END
mov x3, x24 // phys offset
create_block_map x0, x7, x3, x5, x6
diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c
new file mode 100644
index 000000000000..75c9cf1aafee
--- /dev/null
+++ b/arch/arm64/kernel/kgdb.c
@@ -0,0 +1,336 @@
+/*
+ * AArch64 KGDB support
+ *
+ * Based on arch/arm/kernel/kgdb.c
+ *
+ * Copyright (C) 2013 Cavium Inc.
+ * Author: Vijaya Kumar K <vijaya.kumar@caviumnetworks.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/irq.h>
+#include <linux/kdebug.h>
+#include <linux/kgdb.h>
+#include <asm/traps.h>
+
+struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
+ { "x0", 8, offsetof(struct pt_regs, regs[0])},
+ { "x1", 8, offsetof(struct pt_regs, regs[1])},
+ { "x2", 8, offsetof(struct pt_regs, regs[2])},
+ { "x3", 8, offsetof(struct pt_regs, regs[3])},
+ { "x4", 8, offsetof(struct pt_regs, regs[4])},
+ { "x5", 8, offsetof(struct pt_regs, regs[5])},
+ { "x6", 8, offsetof(struct pt_regs, regs[6])},
+ { "x7", 8, offsetof(struct pt_regs, regs[7])},
+ { "x8", 8, offsetof(struct pt_regs, regs[8])},
+ { "x9", 8, offsetof(struct pt_regs, regs[9])},
+ { "x10", 8, offsetof(struct pt_regs, regs[10])},
+ { "x11", 8, offsetof(struct pt_regs, regs[11])},
+ { "x12", 8, offsetof(struct pt_regs, regs[12])},
+ { "x13", 8, offsetof(struct pt_regs, regs[13])},
+ { "x14", 8, offsetof(struct pt_regs, regs[14])},
+ { "x15", 8, offsetof(struct pt_regs, regs[15])},
+ { "x16", 8, offsetof(struct pt_regs, regs[16])},
+ { "x17", 8, offsetof(struct pt_regs, regs[17])},
+ { "x18", 8, offsetof(struct pt_regs, regs[18])},
+ { "x19", 8, offsetof(struct pt_regs, regs[19])},
+ { "x20", 8, offsetof(struct pt_regs, regs[20])},
+ { "x21", 8, offsetof(struct pt_regs, regs[21])},
+ { "x22", 8, offsetof(struct pt_regs, regs[22])},
+ { "x23", 8, offsetof(struct pt_regs, regs[23])},
+ { "x24", 8, offsetof(struct pt_regs, regs[24])},
+ { "x25", 8, offsetof(struct pt_regs, regs[25])},
+ { "x26", 8, offsetof(struct pt_regs, regs[26])},
+ { "x27", 8, offsetof(struct pt_regs, regs[27])},
+ { "x28", 8, offsetof(struct pt_regs, regs[28])},
+ { "x29", 8, offsetof(struct pt_regs, regs[29])},
+ { "x30", 8, offsetof(struct pt_regs, regs[30])},
+ { "sp", 8, offsetof(struct pt_regs, sp)},
+ { "pc", 8, offsetof(struct pt_regs, pc)},
+ { "pstate", 8, offsetof(struct pt_regs, pstate)},
+ { "v0", 16, -1 },
+ { "v1", 16, -1 },
+ { "v2", 16, -1 },
+ { "v3", 16, -1 },
+ { "v4", 16, -1 },
+ { "v5", 16, -1 },
+ { "v6", 16, -1 },
+ { "v7", 16, -1 },
+ { "v8", 16, -1 },
+ { "v9", 16, -1 },
+ { "v10", 16, -1 },
+ { "v11", 16, -1 },
+ { "v12", 16, -1 },
+ { "v13", 16, -1 },
+ { "v14", 16, -1 },
+ { "v15", 16, -1 },
+ { "v16", 16, -1 },
+ { "v17", 16, -1 },
+ { "v18", 16, -1 },
+ { "v19", 16, -1 },
+ { "v20", 16, -1 },
+ { "v21", 16, -1 },
+ { "v22", 16, -1 },
+ { "v23", 16, -1 },
+ { "v24", 16, -1 },
+ { "v25", 16, -1 },
+ { "v26", 16, -1 },
+ { "v27", 16, -1 },
+ { "v28", 16, -1 },
+ { "v29", 16, -1 },
+ { "v30", 16, -1 },
+ { "v31", 16, -1 },
+ { "fpsr", 4, -1 },
+ { "fpcr", 4, -1 },
+};
+
+char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
+{
+ if (regno >= DBG_MAX_REG_NUM || regno < 0)
+ return NULL;
+
+ if (dbg_reg_def[regno].offset != -1)
+ memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
+ dbg_reg_def[regno].size);
+ else
+ memset(mem, 0, dbg_reg_def[regno].size);
+ return dbg_reg_def[regno].name;
+}
+
+int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
+{
+ if (regno >= DBG_MAX_REG_NUM || regno < 0)
+ return -EINVAL;
+
+ if (dbg_reg_def[regno].offset != -1)
+ memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
+ dbg_reg_def[regno].size);
+ return 0;
+}
+
+void
+sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
+{
+ struct pt_regs *thread_regs;
+
+ /* Initialize to zero */
+ memset((char *)gdb_regs, 0, NUMREGBYTES);
+ thread_regs = task_pt_regs(task);
+ memcpy((void *)gdb_regs, (void *)thread_regs->regs, GP_REG_BYTES);
+}
+
+void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
+{
+ regs->pc = pc;
+}
+
+static int compiled_break;
+
+static void kgdb_arch_update_addr(struct pt_regs *regs,
+ char *remcom_in_buffer)
+{
+ unsigned long addr;
+ char *ptr;
+
+ ptr = &remcom_in_buffer[1];
+ if (kgdb_hex2long(&ptr, &addr))
+ kgdb_arch_set_pc(regs, addr);
+ else if (compiled_break == 1)
+ kgdb_arch_set_pc(regs, regs->pc + 4);
+
+ compiled_break = 0;
+}
+
+int kgdb_arch_handle_exception(int exception_vector, int signo,
+ int err_code, char *remcom_in_buffer,
+ char *remcom_out_buffer,
+ struct pt_regs *linux_regs)
+{
+ int err;
+
+ switch (remcom_in_buffer[0]) {
+ case 'D':
+ case 'k':
+ /*
+ * Packet D (Detach), k (kill). No special handling
+ * is required here. Handle same as c packet.
+ */
+ case 'c':
+ /*
+ * Packet c (Continue) to continue executing.
+ * Set pc to required address.
+ * Try to read optional parameter and set pc.
+ * If this was a compiled breakpoint, we need to move
+ * to the next instruction else we will just breakpoint
+ * over and over again.
+ */
+ kgdb_arch_update_addr(linux_regs, remcom_in_buffer);
+ atomic_set(&kgdb_cpu_doing_single_step, -1);
+ kgdb_single_step = 0;
+
+ /*
+ * Received continue command, disable single step
+ */
+ if (kernel_active_single_step())
+ kernel_disable_single_step();
+
+ err = 0;
+ break;
+ case 's':
+ /*
+ * Update step address value with address passed
+ * with step packet.
+ * On debug exception return PC is copied to ELR
+ * So just update PC.
+ * If no step address is passed, resume from the address
+ * pointed by PC. Do not update PC
+ */
+ kgdb_arch_update_addr(linux_regs, remcom_in_buffer);
+ atomic_set(&kgdb_cpu_doing_single_step, raw_smp_processor_id());
+ kgdb_single_step = 1;
+
+ /*
+ * Enable single step handling
+ */
+ if (!kernel_active_single_step())
+ kernel_enable_single_step(linux_regs);
+ err = 0;
+ break;
+ default:
+ err = -1;
+ }
+ return err;
+}
+
+static int kgdb_brk_fn(struct pt_regs *regs, unsigned int esr)
+{
+ kgdb_handle_exception(1, SIGTRAP, 0, regs);
+ return 0;
+}
+
+static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int esr)
+{
+ compiled_break = 1;
+ kgdb_handle_exception(1, SIGTRAP, 0, regs);
+
+ return 0;
+}
+
+static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned int esr)
+{
+ kgdb_handle_exception(1, SIGTRAP, 0, regs);
+ return 0;
+}
+
+static struct break_hook kgdb_brkpt_hook = {
+ .esr_mask = 0xffffffff,
+ .esr_val = DBG_ESR_VAL_BRK(KGDB_DYN_DGB_BRK_IMM),
+ .fn = kgdb_brk_fn
+};
+
+static struct break_hook kgdb_compiled_brkpt_hook = {
+ .esr_mask = 0xffffffff,
+ .esr_val = DBG_ESR_VAL_BRK(KDBG_COMPILED_DBG_BRK_IMM),
+ .fn = kgdb_compiled_brk_fn
+};
+
+static struct step_hook kgdb_step_hook = {
+ .fn = kgdb_step_brk_fn
+};
+
+static void kgdb_call_nmi_hook(void *ignored)
+{
+ kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
+}
+
+void kgdb_roundup_cpus(unsigned long flags)
+{
+ local_irq_enable();
+ smp_call_function(kgdb_call_nmi_hook, NULL, 0);
+ local_irq_disable();
+}
+
+static int __kgdb_notify(struct die_args *args, unsigned long cmd)
+{
+ struct pt_regs *regs = args->regs;
+
+ if (kgdb_handle_exception(1, args->signr, cmd, regs))
+ return NOTIFY_DONE;
+ return NOTIFY_STOP;
+}
+
+static int
+kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
+{
+ unsigned long flags;
+ int ret;
+
+ local_irq_save(flags);
+ ret = __kgdb_notify(ptr, cmd);
+ local_irq_restore(flags);
+
+ return ret;
+}
+
+static struct notifier_block kgdb_notifier = {
+ .notifier_call = kgdb_notify,
+ /*
+ * Want to be lowest priority
+ */
+ .priority = -INT_MAX,
+};
+
+/*
+ * kgdb_arch_init - Perform any architecture specific initalization.
+ * This function will handle the initalization of any architecture
+ * specific callbacks.
+ */
+int kgdb_arch_init(void)
+{
+ int ret = register_die_notifier(&kgdb_notifier);
+
+ if (ret != 0)
+ return ret;
+
+ register_break_hook(&kgdb_brkpt_hook);
+ register_break_hook(&kgdb_compiled_brkpt_hook);
+ register_step_hook(&kgdb_step_hook);
+ return 0;
+}
+
+/*
+ * kgdb_arch_exit - Perform any architecture specific uninitalization.
+ * This function will handle the uninitalization of any architecture
+ * specific callbacks, for dynamic registration and unregistration.
+ */
+void kgdb_arch_exit(void)
+{
+ unregister_break_hook(&kgdb_brkpt_hook);
+ unregister_break_hook(&kgdb_compiled_brkpt_hook);
+ unregister_step_hook(&kgdb_step_hook);
+ unregister_die_notifier(&kgdb_notifier);
+}
+
+/*
+ * ARM instructions are always in LE.
+ * Break instruction is encoded in LE format
+ */
+struct kgdb_arch arch_kgdb_ops = {
+ .gdb_bpt_instr = {
+ KGDB_DYN_BRK_INS_BYTE0,
+ KGDB_DYN_BRK_INS_BYTE1,
+ KGDB_DYN_BRK_INS_BYTE2,
+ KGDB_DYN_BRK_INS_BYTE3,
+ }
+};
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 5b1cd792274a..e868c72a7938 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -1348,8 +1348,8 @@ early_initcall(init_hw_perf_events);
* Callchain handling code.
*/
struct frame_tail {
- struct frame_tail __user *fp;
- unsigned long lr;
+ struct frame_tail __user *fp;
+ unsigned long lr;
} __attribute__((packed));
/*
@@ -1386,22 +1386,80 @@ user_backtrace(struct frame_tail __user *tail,
return buftail.fp;
}
+/*
+ * The registers we're interested in are at the end of the variable
+ * length saved register structure. The fp points at the end of this
+ * structure so the address of this struct is:
+ * (struct compat_frame_tail *)(xxx->fp)-1
+ *
+ * This code has been adapted from the ARM OProfile support.
+ */
+struct compat_frame_tail {
+ compat_uptr_t fp; /* a (struct compat_frame_tail *) in compat mode */
+ u32 sp;
+ u32 lr;
+} __attribute__((packed));
+
+static struct compat_frame_tail __user *
+compat_user_backtrace(struct compat_frame_tail __user *tail,
+ struct perf_callchain_entry *entry)
+{
+ struct compat_frame_tail buftail;
+ unsigned long err;
+
+ /* Also check accessibility of one struct frame_tail beyond */
+ if (!access_ok(VERIFY_READ, tail, sizeof(buftail)))
+ return NULL;
+
+ pagefault_disable();
+ err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail));
+ pagefault_enable();
+
+ if (err)
+ return NULL;
+
+ perf_callchain_store(entry, buftail.lr);
+
+ /*
+ * Frame pointers should strictly progress back up the stack
+ * (towards higher addresses).
+ */
+ if (tail + 1 >= (struct compat_frame_tail __user *)
+ compat_ptr(buftail.fp))
+ return NULL;
+
+ return (struct compat_frame_tail __user *)compat_ptr(buftail.fp) - 1;
+}
+
void perf_callchain_user(struct perf_callchain_entry *entry,
struct pt_regs *regs)
{
- struct frame_tail __user *tail;
-
if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
/* We don't support guest os callchain now */
return;
}
perf_callchain_store(entry, regs->pc);
- tail = (struct frame_tail __user *)regs->regs[29];
- while (entry->nr < PERF_MAX_STACK_DEPTH &&
- tail && !((unsigned long)tail & 0xf))
- tail = user_backtrace(tail, entry);
+ if (!compat_user_mode(regs)) {
+ /* AARCH64 mode */
+ struct frame_tail __user *tail;
+
+ tail = (struct frame_tail __user *)regs->regs[29];
+
+ while (entry->nr < PERF_MAX_STACK_DEPTH &&
+ tail && !((unsigned long)tail & 0xf))
+ tail = user_backtrace(tail, entry);
+ } else {
+ /* AARCH32 compat mode */
+ struct compat_frame_tail __user *tail;
+
+ tail = (struct compat_frame_tail __user *)regs->compat_fp - 1;
+
+ while ((entry->nr < PERF_MAX_STACK_DEPTH) &&
+ tail && !((unsigned long)tail & 0x3))
+ tail = compat_user_backtrace(tail, entry);
+ }
}
/*
@@ -1429,6 +1487,7 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry,
frame.fp = regs->regs[29];
frame.sp = regs->sp;
frame.pc = regs->pc;
+
walk_stackframe(&frame, callchain_trace, entry);
}
diff --git a/arch/arm64/kernel/perf_regs.c b/arch/arm64/kernel/perf_regs.c
new file mode 100644
index 000000000000..f2d6f0a36d63
--- /dev/null
+++ b/arch/arm64/kernel/perf_regs.c
@@ -0,0 +1,44 @@
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/bug.h>
+#include <asm/perf_regs.h>
+#include <asm/ptrace.h>
+
+u64 perf_reg_value(struct pt_regs *regs, int idx)
+{
+ if (WARN_ON_ONCE((u32)idx >= PERF_REG_ARM64_MAX))
+ return 0;
+
+ /*
+ * Compat (i.e. 32 bit) mode:
+ * - PC has been set in the pt_regs struct in kernel_entry,
+ * - Handle SP and LR here.
+ */
+ if (compat_user_mode(regs)) {
+ if ((u32)idx == PERF_REG_ARM64_SP)
+ return regs->compat_sp;
+ if ((u32)idx == PERF_REG_ARM64_LR)
+ return regs->compat_lr;
+ }
+
+ return regs->regs[idx];
+}
+
+#define REG_RESERVED (~((1ULL << PERF_REG_ARM64_MAX) - 1))
+
+int perf_reg_validate(u64 mask)
+{
+ if (!mask || mask & REG_RESERVED)
+ return -EINVAL;
+
+ return 0;
+}
+
+u64 perf_reg_abi(struct task_struct *task)
+{
+ if (is_compat_thread(task_thread_info(task)))
+ return PERF_SAMPLE_REGS_ABI_32;
+ else
+ return PERF_SAMPLE_REGS_ABI_64;
+}
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 1c0a9be2ffa8..6391485f342d 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -33,7 +33,6 @@
#include <linux/kallsyms.h>
#include <linux/init.h>
#include <linux/cpu.h>
-#include <linux/cpuidle.h>
#include <linux/elfcore.h>
#include <linux/pm.h>
#include <linux/tick.h>
@@ -72,8 +71,17 @@ static void setup_restart(void)
void soft_restart(unsigned long addr)
{
+ typedef void (*phys_reset_t)(unsigned long);
+ phys_reset_t phys_reset;
+
setup_restart();
- cpu_reset(addr);
+
+ /* Switch to the identity mapping */
+ phys_reset = (phys_reset_t)virt_to_phys(cpu_reset);
+ phys_reset(addr);
+
+ /* Should never get here */
+ BUG();
}
/*
@@ -94,10 +102,8 @@ void arch_cpu_idle(void)
* This should do all the clock switching and wait for interrupt
* tricks
*/
- if (cpuidle_idle_call()) {
- cpu_do_idle();
- local_irq_enable();
- }
+ cpu_do_idle();
+ local_irq_enable();
}
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
index 4f97db3d7363..ea4828a4aa96 100644
--- a/arch/arm64/kernel/psci.c
+++ b/arch/arm64/kernel/psci.c
@@ -176,22 +176,20 @@ static const struct of_device_id psci_of_match[] __initconst = {
{},
};
-int __init psci_init(void)
+void __init psci_init(void)
{
struct device_node *np;
const char *method;
u32 id;
- int err = 0;
np = of_find_matching_node(NULL, psci_of_match);
if (!np)
- return -ENODEV;
+ return;
pr_info("probing function IDs from device-tree\n");
if (of_property_read_string(np, "method", &method)) {
pr_warning("missing \"method\" property\n");
- err = -ENXIO;
goto out_put_node;
}
@@ -201,7 +199,6 @@ int __init psci_init(void)
invoke_psci_fn = __invoke_psci_fn_smc;
} else {
pr_warning("invalid \"method\" property: %s\n", method);
- err = -EINVAL;
goto out_put_node;
}
@@ -227,7 +224,7 @@ int __init psci_init(void)
out_put_node:
of_node_put(np);
- return err;
+ return;
}
#ifdef CONFIG_SMP
@@ -251,7 +248,7 @@ static int cpu_psci_cpu_boot(unsigned int cpu)
{
int err = psci_ops.cpu_on(cpu_logical_map(cpu), __pa(secondary_entry));
if (err)
- pr_err("psci: failed to boot CPU%d (%d)\n", cpu, err);
+ pr_err("failed to boot CPU%d (%d)\n", cpu, err);
return err;
}
@@ -278,7 +275,7 @@ static void cpu_psci_cpu_die(unsigned int cpu)
ret = psci_ops.cpu_off(state);
- pr_crit("psci: unable to power off CPU%u (%d)\n", cpu, ret);
+ pr_crit("unable to power off CPU%u (%d)\n", cpu, ret);
}
#endif
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index c8e9effe52e1..67da30741a1b 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -69,6 +69,7 @@ EXPORT_SYMBOL_GPL(elf_hwcap);
COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\
COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV)
unsigned int compat_elf_hwcap __read_mostly = COMPAT_ELF_HWCAP_DEFAULT;
+unsigned int compat_elf_hwcap2 __read_mostly;
#endif
static const char *cpu_name;
@@ -242,6 +243,38 @@ static void __init setup_processor(void)
block = (features >> 16) & 0xf;
if (block && !(block & 0x8))
elf_hwcap |= HWCAP_CRC32;
+
+#ifdef CONFIG_COMPAT
+ /*
+ * ID_ISAR5_EL1 carries similar information as above, but pertaining to
+ * the Aarch32 32-bit execution state.
+ */
+ features = read_cpuid(ID_ISAR5_EL1);
+ block = (features >> 4) & 0xf;
+ if (!(block & 0x8)) {
+ switch (block) {
+ default:
+ case 2:
+ compat_elf_hwcap2 |= COMPAT_HWCAP2_PMULL;
+ case 1:
+ compat_elf_hwcap2 |= COMPAT_HWCAP2_AES;
+ case 0:
+ break;
+ }
+ }
+
+ block = (features >> 8) & 0xf;
+ if (block && !(block & 0x8))
+ compat_elf_hwcap2 |= COMPAT_HWCAP2_SHA1;
+
+ block = (features >> 12) & 0xf;
+ if (block && !(block & 0x8))
+ compat_elf_hwcap2 |= COMPAT_HWCAP2_SHA2;
+
+ block = (features >> 16) & 0xf;
+ if (block && !(block & 0x8))
+ compat_elf_hwcap2 |= COMPAT_HWCAP2_CRC32;
+#endif
}
static void __init setup_machine_fdt(phys_addr_t dt_phys)
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 7cfb92a4ab66..f0a141dd5655 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -114,6 +114,11 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
return ret;
}
+static void smp_store_cpu_info(unsigned int cpuid)
+{
+ store_cpu_topology(cpuid);
+}
+
/*
* This is the secondary CPU boot entry. We're using this CPUs
* idle thread stack, but a set of temporary page tables.
@@ -152,6 +157,8 @@ asmlinkage void secondary_start_kernel(void)
*/
notify_cpu_starting(cpu);
+ smp_store_cpu_info(cpu);
+
/*
* OK, now it's safe to let the boot CPU continue. Wait for
* the CPU migration code to notice that the CPU is online
@@ -160,6 +167,7 @@ asmlinkage void secondary_start_kernel(void)
set_cpu_online(cpu, true);
complete(&cpu_running);
+ local_dbg_enable();
local_irq_enable();
local_async_enable();
@@ -390,6 +398,10 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
int err;
unsigned int cpu, ncores = num_possible_cpus();
+ init_cpu_topology();
+
+ smp_store_cpu_info(smp_processor_id());
+
/*
* are we trying to boot more cores than exist?
*/
diff --git a/arch/arm64/kernel/smp_spin_table.c b/arch/arm64/kernel/smp_spin_table.c
index 44c22805d2e2..7a530d2cc807 100644
--- a/arch/arm64/kernel/smp_spin_table.c
+++ b/arch/arm64/kernel/smp_spin_table.c
@@ -128,7 +128,7 @@ static int smp_spin_table_cpu_boot(unsigned int cpu)
return secondary_holding_pen_release != INVALID_HWID ? -ENOSYS : 0;
}
-void smp_spin_table_cpu_postboot(void)
+static void smp_spin_table_cpu_postboot(void)
{
/*
* Let the primary processor know we're out of the pen.
diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
index c3b6c63ea5fb..38f0558f0c0a 100644
--- a/arch/arm64/kernel/stacktrace.c
+++ b/arch/arm64/kernel/stacktrace.c
@@ -48,7 +48,11 @@ int unwind_frame(struct stackframe *frame)
frame->sp = fp + 0x10;
frame->fp = *(unsigned long *)(fp);
- frame->pc = *(unsigned long *)(fp + 8);
+ /*
+ * -4 here because we care about the PC at time of bl,
+ * not where the return will go.
+ */
+ frame->pc = *(unsigned long *)(fp + 8) - 4;
return 0;
}
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
new file mode 100644
index 000000000000..3e06b0be4ec8
--- /dev/null
+++ b/arch/arm64/kernel/topology.c
@@ -0,0 +1,95 @@
+/*
+ * arch/arm64/kernel/topology.c
+ *
+ * Copyright (C) 2011,2013,2014 Linaro Limited.
+ *
+ * Based on the arm32 version written by Vincent Guittot in turn based on
+ * arch/sh/kernel/topology.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/init.h>
+#include <linux/percpu.h>
+#include <linux/node.h>
+#include <linux/nodemask.h>
+#include <linux/sched.h>
+
+#include <asm/topology.h>
+
+/*
+ * cpu topology table
+ */
+struct cpu_topology cpu_topology[NR_CPUS];
+EXPORT_SYMBOL_GPL(cpu_topology);
+
+const struct cpumask *cpu_coregroup_mask(int cpu)
+{
+ return &cpu_topology[cpu].core_sibling;
+}
+
+static void update_siblings_masks(unsigned int cpuid)
+{
+ struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
+ int cpu;
+
+ if (cpuid_topo->cluster_id == -1) {
+ /*
+ * DT does not contain topology information for this cpu
+ * reset it to default behaviour
+ */
+ pr_debug("CPU%u: No topology information configured\n", cpuid);
+ cpuid_topo->core_id = 0;
+ cpumask_set_cpu(cpuid, &cpuid_topo->core_sibling);
+ cpumask_set_cpu(cpuid, &cpuid_topo->thread_sibling);
+ return;
+ }
+
+ /* update core and thread sibling masks */
+ for_each_possible_cpu(cpu) {
+ cpu_topo = &cpu_topology[cpu];
+
+ if (cpuid_topo->cluster_id != cpu_topo->cluster_id)
+ continue;
+
+ cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
+ if (cpu != cpuid)
+ cpumask_set_cpu(cpu, &cpuid_topo->core_sibling);
+
+ if (cpuid_topo->core_id != cpu_topo->core_id)
+ continue;
+
+ cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling);
+ if (cpu != cpuid)
+ cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling);
+ }
+}
+
+void store_cpu_topology(unsigned int cpuid)
+{
+ update_siblings_masks(cpuid);
+}
+
+/*
+ * init_cpu_topology is called at boot when only one cpu is running
+ * which prevent simultaneous write access to cpu_topology array
+ */
+void __init init_cpu_topology(void)
+{
+ unsigned int cpu;
+
+ /* init core mask and power*/
+ for_each_possible_cpu(cpu) {
+ struct cpu_topology *cpu_topo = &cpu_topology[cpu];
+
+ cpu_topo->thread_id = -1;
+ cpu_topo->core_id = -1;
+ cpu_topo->cluster_id = -1;
+ cpumask_clear(&cpu_topo->core_sibling);
+ cpumask_clear(&cpu_topo->thread_sibling);
+ }
+}
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index a7149cae1615..50384fec56c4 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -106,49 +106,31 @@ int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp)
static int __init vdso_init(void)
{
- struct page *pg;
- char *vbase;
- int i, ret = 0;
+ int i;
+
+ if (memcmp(&vdso_start, "\177ELF", 4)) {
+ pr_err("vDSO is not a valid ELF object!\n");
+ return -EINVAL;
+ }
vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
pr_info("vdso: %ld pages (%ld code, %ld data) at base %p\n",
vdso_pages + 1, vdso_pages, 1L, &vdso_start);
/* Allocate the vDSO pagelist, plus a page for the data. */
- vdso_pagelist = kzalloc(sizeof(struct page *) * (vdso_pages + 1),
+ vdso_pagelist = kcalloc(vdso_pages + 1, sizeof(struct page *),
GFP_KERNEL);
- if (vdso_pagelist == NULL) {
- pr_err("Failed to allocate vDSO pagelist!\n");
+ if (vdso_pagelist == NULL)
return -ENOMEM;
- }
/* Grab the vDSO code pages. */
- for (i = 0; i < vdso_pages; i++) {
- pg = virt_to_page(&vdso_start + i*PAGE_SIZE);
- ClearPageReserved(pg);
- get_page(pg);
- vdso_pagelist[i] = pg;
- }
-
- /* Sanity check the shared object header. */
- vbase = vmap(vdso_pagelist, 1, 0, PAGE_KERNEL);
- if (vbase == NULL) {
- pr_err("Failed to map vDSO pagelist!\n");
- return -ENOMEM;
- } else if (memcmp(vbase, "\177ELF", 4)) {
- pr_err("vDSO is not a valid ELF object!\n");
- ret = -EINVAL;
- goto unmap;
- }
+ for (i = 0; i < vdso_pages; i++)
+ vdso_pagelist[i] = virt_to_page(&vdso_start + i * PAGE_SIZE);
/* Grab the vDSO data page. */
- pg = virt_to_page(vdso_data);
- get_page(pg);
- vdso_pagelist[i] = pg;
+ vdso_pagelist[i] = virt_to_page(vdso_data);
-unmap:
- vunmap(vbase);
- return ret;
+ return 0;
}
arch_initcall(vdso_init);
diff --git a/arch/arm64/kvm/hyp-init.S b/arch/arm64/kvm/hyp-init.S
index 2b0244d65c16..d968796f4b2d 100644
--- a/arch/arm64/kvm/hyp-init.S
+++ b/arch/arm64/kvm/hyp-init.S
@@ -68,6 +68,12 @@ __do_hyp_init:
msr tcr_el2, x4
ldr x4, =VTCR_EL2_FLAGS
+ /*
+ * Read the PARange bits from ID_AA64MMFR0_EL1 and set the PS bits in
+ * VTCR_EL2.
+ */
+ mrs x5, ID_AA64MMFR0_EL1
+ bfi x4, x5, #16, #3
msr vtcr_el2, x4
mrs x4, mair_el1
diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S
index 3b47c36e10ff..2c56012cb2d2 100644
--- a/arch/arm64/kvm/hyp.S
+++ b/arch/arm64/kvm/hyp.S
@@ -694,6 +694,24 @@ __hyp_panic_str:
.align 2
+/*
+ * u64 kvm_call_hyp(void *hypfn, ...);
+ *
+ * This is not really a variadic function in the classic C-way and care must
+ * be taken when calling this to ensure parameters are passed in registers
+ * only, since the stack will change between the caller and the callee.
+ *
+ * Call the function with the first argument containing a pointer to the
+ * function you wish to call in Hyp mode, and subsequent arguments will be
+ * passed as x0, x1, and x2 (a maximum of 3 arguments in addition to the
+ * function pointer can be passed). The function being called must be mapped
+ * in Hyp mode (see init_hyp_mode in arch/arm/kvm/arm.c). Return values are
+ * passed in r0 and r1.
+ *
+ * A function pointer with a value of 0 has a special meaning, and is
+ * used to implement __hyp_get_vectors in the same way as in
+ * arch/arm64/kernel/hyp_stub.S.
+ */
ENTRY(kvm_call_hyp)
hvc #0
ret
@@ -737,7 +755,12 @@ el1_sync: // Guest trapped into EL2
pop x2, x3
pop x0, x1
- push lr, xzr
+ /* Check for __hyp_get_vectors */
+ cbnz x0, 1f
+ mrs x0, vbar_el2
+ b 2f
+
+1: push lr, xzr
/*
* Compute the function address in EL2, and shuffle the parameters.
@@ -750,7 +773,7 @@ el1_sync: // Guest trapped into EL2
blr lr
pop lr, xzr
- eret
+2: eret
el1_trap:
/*
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 02e9d09e1d80..03244582bc55 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -27,6 +27,7 @@
#include <asm/kvm_host.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_coproc.h>
+#include <asm/kvm_mmu.h>
#include <asm/cacheflush.h>
#include <asm/cputype.h>
#include <trace/events/kvm.h>
@@ -121,6 +122,48 @@ done:
}
/*
+ * Generic accessor for VM registers. Only called as long as HCR_TVM
+ * is set.
+ */
+static bool access_vm_reg(struct kvm_vcpu *vcpu,
+ const struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ unsigned long val;
+
+ BUG_ON(!p->is_write);
+
+ val = *vcpu_reg(vcpu, p->Rt);
+ if (!p->is_aarch32) {
+ vcpu_sys_reg(vcpu, r->reg) = val;
+ } else {
+ vcpu_cp15(vcpu, r->reg) = val & 0xffffffffUL;
+ if (!p->is_32bit)
+ vcpu_cp15(vcpu, r->reg + 1) = val >> 32;
+ }
+ return true;
+}
+
+/*
+ * SCTLR_EL1 accessor. Only called as long as HCR_TVM is set. If the
+ * guest enables the MMU, we stop trapping the VM sys_regs and leave
+ * it in complete control of the caches.
+ */
+static bool access_sctlr(struct kvm_vcpu *vcpu,
+ const struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ access_vm_reg(vcpu, p, r);
+
+ if (vcpu_has_cache_enabled(vcpu)) { /* MMU+Caches enabled? */
+ vcpu->arch.hcr_el2 &= ~HCR_TVM;
+ stage2_flush_vm(vcpu->kvm);
+ }
+
+ return true;
+}
+
+/*
* We could trap ID_DFR0 and tell the guest we don't support performance
* monitoring. Unfortunately the patch to make the kernel check ID_DFR0 was
* NAKed, so it will read the PMCR anyway.
@@ -185,32 +228,32 @@ static const struct sys_reg_desc sys_reg_descs[] = {
NULL, reset_mpidr, MPIDR_EL1 },
/* SCTLR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b000),
- NULL, reset_val, SCTLR_EL1, 0x00C50078 },
+ access_sctlr, reset_val, SCTLR_EL1, 0x00C50078 },
/* CPACR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b010),
NULL, reset_val, CPACR_EL1, 0 },
/* TTBR0_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b000),
- NULL, reset_unknown, TTBR0_EL1 },
+ access_vm_reg, reset_unknown, TTBR0_EL1 },
/* TTBR1_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b001),
- NULL, reset_unknown, TTBR1_EL1 },
+ access_vm_reg, reset_unknown, TTBR1_EL1 },
/* TCR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b010),
- NULL, reset_val, TCR_EL1, 0 },
+ access_vm_reg, reset_val, TCR_EL1, 0 },
/* AFSR0_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0001), Op2(0b000),
- NULL, reset_unknown, AFSR0_EL1 },
+ access_vm_reg, reset_unknown, AFSR0_EL1 },
/* AFSR1_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0001), Op2(0b001),
- NULL, reset_unknown, AFSR1_EL1 },
+ access_vm_reg, reset_unknown, AFSR1_EL1 },
/* ESR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0010), Op2(0b000),
- NULL, reset_unknown, ESR_EL1 },
+ access_vm_reg, reset_unknown, ESR_EL1 },
/* FAR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0110), CRm(0b0000), Op2(0b000),
- NULL, reset_unknown, FAR_EL1 },
+ access_vm_reg, reset_unknown, FAR_EL1 },
/* PAR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0111), CRm(0b0100), Op2(0b000),
NULL, reset_unknown, PAR_EL1 },
@@ -224,17 +267,17 @@ static const struct sys_reg_desc sys_reg_descs[] = {
/* MAIR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0010), Op2(0b000),
- NULL, reset_unknown, MAIR_EL1 },
+ access_vm_reg, reset_unknown, MAIR_EL1 },
/* AMAIR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0011), Op2(0b000),
- NULL, reset_amair_el1, AMAIR_EL1 },
+ access_vm_reg, reset_amair_el1, AMAIR_EL1 },
/* VBAR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b0000), Op2(0b000),
NULL, reset_val, VBAR_EL1, 0 },
/* CONTEXTIDR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b001),
- NULL, reset_val, CONTEXTIDR_EL1, 0 },
+ access_vm_reg, reset_val, CONTEXTIDR_EL1, 0 },
/* TPIDR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b100),
NULL, reset_unknown, TPIDR_EL1 },
@@ -305,14 +348,32 @@ static const struct sys_reg_desc sys_reg_descs[] = {
NULL, reset_val, FPEXC32_EL2, 0x70 },
};
-/* Trapped cp15 registers */
+/*
+ * Trapped cp15 registers. TTBR0/TTBR1 get a double encoding,
+ * depending on the way they are accessed (as a 32bit or a 64bit
+ * register).
+ */
static const struct sys_reg_desc cp15_regs[] = {
+ { Op1( 0), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR0 },
+ { Op1( 0), CRn( 1), CRm( 0), Op2( 0), access_sctlr, NULL, c1_SCTLR },
+ { Op1( 0), CRn( 2), CRm( 0), Op2( 0), access_vm_reg, NULL, c2_TTBR0 },
+ { Op1( 0), CRn( 2), CRm( 0), Op2( 1), access_vm_reg, NULL, c2_TTBR1 },
+ { Op1( 0), CRn( 2), CRm( 0), Op2( 2), access_vm_reg, NULL, c2_TTBCR },
+ { Op1( 0), CRn( 3), CRm( 0), Op2( 0), access_vm_reg, NULL, c3_DACR },
+ { Op1( 0), CRn( 5), CRm( 0), Op2( 0), access_vm_reg, NULL, c5_DFSR },
+ { Op1( 0), CRn( 5), CRm( 0), Op2( 1), access_vm_reg, NULL, c5_IFSR },
+ { Op1( 0), CRn( 5), CRm( 1), Op2( 0), access_vm_reg, NULL, c5_ADFSR },
+ { Op1( 0), CRn( 5), CRm( 1), Op2( 1), access_vm_reg, NULL, c5_AIFSR },
+ { Op1( 0), CRn( 6), CRm( 0), Op2( 0), access_vm_reg, NULL, c6_DFAR },
+ { Op1( 0), CRn( 6), CRm( 0), Op2( 2), access_vm_reg, NULL, c6_IFAR },
+
/*
* DC{C,I,CI}SW operations:
*/
{ Op1( 0), CRn( 7), CRm( 6), Op2( 2), access_dcsw },
{ Op1( 0), CRn( 7), CRm(10), Op2( 2), access_dcsw },
{ Op1( 0), CRn( 7), CRm(14), Op2( 2), access_dcsw },
+
{ Op1( 0), CRn( 9), CRm(12), Op2( 0), pm_fake },
{ Op1( 0), CRn( 9), CRm(12), Op2( 1), pm_fake },
{ Op1( 0), CRn( 9), CRm(12), Op2( 2), pm_fake },
@@ -326,6 +387,14 @@ static const struct sys_reg_desc cp15_regs[] = {
{ Op1( 0), CRn( 9), CRm(14), Op2( 0), pm_fake },
{ Op1( 0), CRn( 9), CRm(14), Op2( 1), pm_fake },
{ Op1( 0), CRn( 9), CRm(14), Op2( 2), pm_fake },
+
+ { Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
+ { Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
+ { Op1( 0), CRn(10), CRm( 3), Op2( 0), access_vm_reg, NULL, c10_AMAIR0 },
+ { Op1( 0), CRn(10), CRm( 3), Op2( 1), access_vm_reg, NULL, c10_AMAIR1 },
+ { Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, c13_CID },
+
+ { Op1( 1), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR1 },
};
/* Target specific emulation tables */
@@ -437,6 +506,8 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
u32 hsr = kvm_vcpu_get_hsr(vcpu);
int Rt2 = (hsr >> 10) & 0xf;
+ params.is_aarch32 = true;
+ params.is_32bit = false;
params.CRm = (hsr >> 1) & 0xf;
params.Rt = (hsr >> 5) & 0xf;
params.is_write = ((hsr & 1) == 0);
@@ -480,6 +551,8 @@ int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
struct sys_reg_params params;
u32 hsr = kvm_vcpu_get_hsr(vcpu);
+ params.is_aarch32 = true;
+ params.is_32bit = true;
params.CRm = (hsr >> 1) & 0xf;
params.Rt = (hsr >> 5) & 0xf;
params.is_write = ((hsr & 1) == 0);
@@ -549,6 +622,8 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run)
struct sys_reg_params params;
unsigned long esr = kvm_vcpu_get_hsr(vcpu);
+ params.is_aarch32 = false;
+ params.is_32bit = false;
params.Op0 = (esr >> 20) & 3;
params.Op1 = (esr >> 14) & 0x7;
params.CRn = (esr >> 10) & 0xf;
diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
index d50d3722998e..d411e251412c 100644
--- a/arch/arm64/kvm/sys_regs.h
+++ b/arch/arm64/kvm/sys_regs.h
@@ -30,6 +30,8 @@ struct sys_reg_params {
u8 Op2;
u8 Rt;
bool is_write;
+ bool is_aarch32;
+ bool is_32bit; /* Only valid if is_aarch32 is true */
};
struct sys_reg_desc {
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
index 1ea9f26d1b70..c46f48b33c14 100644
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -30,7 +30,7 @@
*
* Corrupted registers: x0-x7, x9-x11
*/
-ENTRY(__flush_dcache_all)
+__flush_dcache_all:
dsb sy // ensure ordering with previous memory accesses
mrs x0, clidr_el1 // read clidr
and x3, x0, #0x7000000 // extract loc from clidr
@@ -166,3 +166,81 @@ ENTRY(__flush_dcache_area)
dsb sy
ret
ENDPROC(__flush_dcache_area)
+
+/*
+ * __dma_inv_range(start, end)
+ * - start - virtual start address of region
+ * - end - virtual end address of region
+ */
+__dma_inv_range:
+ dcache_line_size x2, x3
+ sub x3, x2, #1
+ bic x0, x0, x3
+ bic x1, x1, x3
+1: dc ivac, x0 // invalidate D / U line
+ add x0, x0, x2
+ cmp x0, x1
+ b.lo 1b
+ dsb sy
+ ret
+ENDPROC(__dma_inv_range)
+
+/*
+ * __dma_clean_range(start, end)
+ * - start - virtual start address of region
+ * - end - virtual end address of region
+ */
+__dma_clean_range:
+ dcache_line_size x2, x3
+ sub x3, x2, #1
+ bic x0, x0, x3
+1: dc cvac, x0 // clean D / U line
+ add x0, x0, x2
+ cmp x0, x1
+ b.lo 1b
+ dsb sy
+ ret
+ENDPROC(__dma_clean_range)
+
+/*
+ * __dma_flush_range(start, end)
+ * - start - virtual start address of region
+ * - end - virtual end address of region
+ */
+ENTRY(__dma_flush_range)
+ dcache_line_size x2, x3
+ sub x3, x2, #1
+ bic x0, x0, x3
+1: dc civac, x0 // clean & invalidate D / U line
+ add x0, x0, x2
+ cmp x0, x1
+ b.lo 1b
+ dsb sy
+ ret
+ENDPROC(__dma_flush_range)
+
+/*
+ * __dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(__dma_map_area)
+ add x1, x1, x0
+ cmp w2, #DMA_FROM_DEVICE
+ b.eq __dma_inv_range
+ b __dma_clean_range
+ENDPROC(__dma_map_area)
+
+/*
+ * __dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(__dma_unmap_area)
+ add x1, x1, x0
+ cmp w2, #DMA_TO_DEVICE
+ b.ne __dma_inv_range
+ ret
+ENDPROC(__dma_unmap_area)
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index fbd76785c5db..0ba347e59f06 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -30,18 +30,26 @@
struct dma_map_ops *dma_ops;
EXPORT_SYMBOL(dma_ops);
-static void *arm64_swiotlb_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flags,
- struct dma_attrs *attrs)
+static pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot,
+ bool coherent)
+{
+ if (!coherent || dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs))
+ return pgprot_writecombine(prot);
+ return prot;
+}
+
+static void *__dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flags,
+ struct dma_attrs *attrs)
{
if (dev == NULL) {
WARN_ONCE(1, "Use an actual device structure for DMA allocation\n");
return NULL;
}
- if (IS_ENABLED(CONFIG_ZONE_DMA32) &&
+ if (IS_ENABLED(CONFIG_ZONE_DMA) &&
dev->coherent_dma_mask <= DMA_BIT_MASK(32))
- flags |= GFP_DMA32;
+ flags |= GFP_DMA;
if (IS_ENABLED(CONFIG_DMA_CMA)) {
struct page *page;
@@ -58,9 +66,9 @@ static void *arm64_swiotlb_alloc_coherent(struct device *dev, size_t size,
}
}
-static void arm64_swiotlb_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle,
- struct dma_attrs *attrs)
+static void __dma_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
{
if (dev == NULL) {
WARN_ONCE(1, "Use an actual device structure for DMA allocation\n");
@@ -78,9 +86,212 @@ static void arm64_swiotlb_free_coherent(struct device *dev, size_t size,
}
}
-static struct dma_map_ops arm64_swiotlb_dma_ops = {
- .alloc = arm64_swiotlb_alloc_coherent,
- .free = arm64_swiotlb_free_coherent,
+static void *__dma_alloc_noncoherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flags,
+ struct dma_attrs *attrs)
+{
+ struct page *page, **map;
+ void *ptr, *coherent_ptr;
+ int order, i;
+
+ size = PAGE_ALIGN(size);
+ order = get_order(size);
+
+ ptr = __dma_alloc_coherent(dev, size, dma_handle, flags, attrs);
+ if (!ptr)
+ goto no_mem;
+ map = kmalloc(sizeof(struct page *) << order, flags & ~GFP_DMA);
+ if (!map)
+ goto no_map;
+
+ /* remove any dirty cache lines on the kernel alias */
+ __dma_flush_range(ptr, ptr + size);
+
+ /* create a coherent mapping */
+ page = virt_to_page(ptr);
+ for (i = 0; i < (size >> PAGE_SHIFT); i++)
+ map[i] = page + i;
+ coherent_ptr = vmap(map, size >> PAGE_SHIFT, VM_MAP,
+ __get_dma_pgprot(attrs, pgprot_default, false));
+ kfree(map);
+ if (!coherent_ptr)
+ goto no_map;
+
+ return coherent_ptr;
+
+no_map:
+ __dma_free_coherent(dev, size, ptr, *dma_handle, attrs);
+no_mem:
+ *dma_handle = ~0;
+ return NULL;
+}
+
+static void __dma_free_noncoherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
+{
+ void *swiotlb_addr = phys_to_virt(dma_to_phys(dev, dma_handle));
+
+ vunmap(vaddr);
+ __dma_free_coherent(dev, size, swiotlb_addr, dma_handle, attrs);
+}
+
+static dma_addr_t __swiotlb_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ dma_addr_t dev_addr;
+
+ dev_addr = swiotlb_map_page(dev, page, offset, size, dir, attrs);
+ __dma_map_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir);
+
+ return dev_addr;
+}
+
+
+static void __swiotlb_unmap_page(struct device *dev, dma_addr_t dev_addr,
+ size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir);
+ swiotlb_unmap_page(dev, dev_addr, size, dir, attrs);
+}
+
+static int __swiotlb_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
+ int nelems, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct scatterlist *sg;
+ int i, ret;
+
+ ret = swiotlb_map_sg_attrs(dev, sgl, nelems, dir, attrs);
+ for_each_sg(sgl, sg, ret, i)
+ __dma_map_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)),
+ sg->length, dir);
+
+ return ret;
+}
+
+static void __swiotlb_unmap_sg_attrs(struct device *dev,
+ struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct scatterlist *sg;
+ int i;
+
+ for_each_sg(sgl, sg, nelems, i)
+ __dma_unmap_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)),
+ sg->length, dir);
+ swiotlb_unmap_sg_attrs(dev, sgl, nelems, dir, attrs);
+}
+
+static void __swiotlb_sync_single_for_cpu(struct device *dev,
+ dma_addr_t dev_addr, size_t size,
+ enum dma_data_direction dir)
+{
+ __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir);
+ swiotlb_sync_single_for_cpu(dev, dev_addr, size, dir);
+}
+
+static void __swiotlb_sync_single_for_device(struct device *dev,
+ dma_addr_t dev_addr, size_t size,
+ enum dma_data_direction dir)
+{
+ swiotlb_sync_single_for_device(dev, dev_addr, size, dir);
+ __dma_map_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir);
+}
+
+static void __swiotlb_sync_sg_for_cpu(struct device *dev,
+ struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir)
+{
+ struct scatterlist *sg;
+ int i;
+
+ for_each_sg(sgl, sg, nelems, i)
+ __dma_unmap_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)),
+ sg->length, dir);
+ swiotlb_sync_sg_for_cpu(dev, sgl, nelems, dir);
+}
+
+static void __swiotlb_sync_sg_for_device(struct device *dev,
+ struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir)
+{
+ struct scatterlist *sg;
+ int i;
+
+ swiotlb_sync_sg_for_device(dev, sgl, nelems, dir);
+ for_each_sg(sgl, sg, nelems, i)
+ __dma_map_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)),
+ sg->length, dir);
+}
+
+/* vma->vm_page_prot must be set appropriately before calling this function */
+static int __dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+ int ret = -ENXIO;
+ unsigned long nr_vma_pages = (vma->vm_end - vma->vm_start) >>
+ PAGE_SHIFT;
+ unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
+ unsigned long pfn = dma_to_phys(dev, dma_addr) >> PAGE_SHIFT;
+ unsigned long off = vma->vm_pgoff;
+
+ if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
+ return ret;
+
+ if (off < nr_pages && nr_vma_pages <= (nr_pages - off)) {
+ ret = remap_pfn_range(vma, vma->vm_start,
+ pfn + off,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
+ }
+
+ return ret;
+}
+
+static int __swiotlb_mmap_noncoherent(struct device *dev,
+ struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ struct dma_attrs *attrs)
+{
+ vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot, false);
+ return __dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
+}
+
+static int __swiotlb_mmap_coherent(struct device *dev,
+ struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ struct dma_attrs *attrs)
+{
+ /* Just use whatever page_prot attributes were specified */
+ return __dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
+}
+
+struct dma_map_ops noncoherent_swiotlb_dma_ops = {
+ .alloc = __dma_alloc_noncoherent,
+ .free = __dma_free_noncoherent,
+ .mmap = __swiotlb_mmap_noncoherent,
+ .map_page = __swiotlb_map_page,
+ .unmap_page = __swiotlb_unmap_page,
+ .map_sg = __swiotlb_map_sg_attrs,
+ .unmap_sg = __swiotlb_unmap_sg_attrs,
+ .sync_single_for_cpu = __swiotlb_sync_single_for_cpu,
+ .sync_single_for_device = __swiotlb_sync_single_for_device,
+ .sync_sg_for_cpu = __swiotlb_sync_sg_for_cpu,
+ .sync_sg_for_device = __swiotlb_sync_sg_for_device,
+ .dma_supported = swiotlb_dma_supported,
+ .mapping_error = swiotlb_dma_mapping_error,
+};
+EXPORT_SYMBOL(noncoherent_swiotlb_dma_ops);
+
+struct dma_map_ops coherent_swiotlb_dma_ops = {
+ .alloc = __dma_alloc_coherent,
+ .free = __dma_free_coherent,
+ .mmap = __swiotlb_mmap_coherent,
.map_page = swiotlb_map_page,
.unmap_page = swiotlb_unmap_page,
.map_sg = swiotlb_map_sg_attrs,
@@ -92,12 +303,19 @@ static struct dma_map_ops arm64_swiotlb_dma_ops = {
.dma_supported = swiotlb_dma_supported,
.mapping_error = swiotlb_dma_mapping_error,
};
+EXPORT_SYMBOL(coherent_swiotlb_dma_ops);
+
+extern int swiotlb_late_init_with_default_size(size_t default_size);
-void __init arm64_swiotlb_init(void)
+static int __init swiotlb_late_init(void)
{
- dma_ops = &arm64_swiotlb_dma_ops;
- swiotlb_init(1);
+ size_t swiotlb_size = min(SZ_64M, MAX_ORDER_NR_PAGES << PAGE_SHIFT);
+
+ dma_ops = &coherent_swiotlb_dma_ops;
+
+ return swiotlb_late_init_with_default_size(swiotlb_size);
}
+subsys_initcall(swiotlb_late_init);
#define PREALLOC_DMA_DEBUG_ENTRIES 4096
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index d0b4c2efda90..51d5352e6ad5 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -30,6 +30,7 @@
#include <linux/memblock.h>
#include <linux/sort.h>
#include <linux/of_fdt.h>
+#include <linux/dma-mapping.h>
#include <linux/dma-contiguous.h>
#include <asm/sections.h>
@@ -59,22 +60,22 @@ static int __init early_initrd(char *p)
early_param("initrd", early_initrd);
#endif
-#define MAX_DMA32_PFN ((4UL * 1024 * 1024 * 1024) >> PAGE_SHIFT)
-
static void __init zone_sizes_init(unsigned long min, unsigned long max)
{
struct memblock_region *reg;
unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES];
- unsigned long max_dma32 = min;
+ unsigned long max_dma = min;
memset(zone_size, 0, sizeof(zone_size));
-#ifdef CONFIG_ZONE_DMA32
/* 4GB maximum for 32-bit only capable devices */
- max_dma32 = max(min, min(max, MAX_DMA32_PFN));
- zone_size[ZONE_DMA32] = max_dma32 - min;
-#endif
- zone_size[ZONE_NORMAL] = max - max_dma32;
+ if (IS_ENABLED(CONFIG_ZONE_DMA)) {
+ unsigned long max_dma_phys =
+ (unsigned long)dma_to_phys(NULL, DMA_BIT_MASK(32) + 1);
+ max_dma = max(min, min(max, max_dma_phys >> PAGE_SHIFT));
+ zone_size[ZONE_DMA] = max_dma - min;
+ }
+ zone_size[ZONE_NORMAL] = max - max_dma;
memcpy(zhole_size, zone_size, sizeof(zhole_size));
@@ -84,15 +85,15 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
if (start >= max)
continue;
-#ifdef CONFIG_ZONE_DMA32
- if (start < max_dma32) {
- unsigned long dma_end = min(end, max_dma32);
- zhole_size[ZONE_DMA32] -= dma_end - start;
+
+ if (IS_ENABLED(CONFIG_ZONE_DMA) && start < max_dma) {
+ unsigned long dma_end = min(end, max_dma);
+ zhole_size[ZONE_DMA] -= dma_end - start;
}
-#endif
- if (end > max_dma32) {
+
+ if (end > max_dma) {
unsigned long normal_end = min(end, max);
- unsigned long normal_start = max(start, max_dma32);
+ unsigned long normal_start = max(start, max_dma);
zhole_size[ZONE_NORMAL] -= normal_end - normal_start;
}
}
@@ -160,6 +161,7 @@ void __init arm64_memblock_init(void)
memblock_reserve(base, size);
}
+ early_init_fdt_scan_reserved_mem();
dma_contiguous_reserve(0);
memblock_allow_resize();
@@ -261,8 +263,6 @@ static void __init free_unused_memmap(void)
*/
void __init mem_init(void)
{
- arm64_swiotlb_init();
-
max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
#ifndef CONFIG_SPARSEMEM_VMEMMAP
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index 1333e6f9a8e5..e085ee6ef4e2 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -173,12 +173,6 @@ ENDPROC(cpu_do_switch_mm)
* value of the SCTLR_EL1 register.
*/
ENTRY(__cpu_setup)
- /*
- * Preserve the link register across the function call.
- */
- mov x28, lr
- bl __flush_dcache_all
- mov lr, x28
ic iallu // I+BTB cache invalidate
tlbi vmalle1is // invalidate I + D TLBs
dsb sy
@@ -215,8 +209,14 @@ ENTRY(__cpu_setup)
* Set/prepare TCR and TTBR. We use 512GB (39-bit) address range for
* both user and kernel.
*/
- ldr x10, =TCR_TxSZ(VA_BITS) | TCR_FLAGS | TCR_IPS_40BIT | \
+ ldr x10, =TCR_TxSZ(VA_BITS) | TCR_FLAGS | \
TCR_ASID16 | TCR_TBI0 | (1 << 31)
+ /*
+ * Read the PARange bits from ID_AA64MMFR0_EL1 and set the IPS bits in
+ * TCR_EL1.
+ */
+ mrs x9, ID_AA64MMFR0_EL1
+ bfi x10, x9, #32, #3
#ifdef CONFIG_ARM64_64K_PAGES
orr x10, x10, TCR_TG0_64K
orr x10, x10, TCR_TG1_64K
diff --git a/arch/avr32/Makefile b/arch/avr32/Makefile
index 22fb66590dcd..dba48a5d5bb9 100644
--- a/arch/avr32/Makefile
+++ b/arch/avr32/Makefile
@@ -11,7 +11,7 @@ all: uImage vmlinux.elf
KBUILD_DEFCONFIG := atstk1002_defconfig
-KBUILD_CFLAGS += -pipe -fno-builtin -mno-pic
+KBUILD_CFLAGS += -pipe -fno-builtin -mno-pic -D__linux__
KBUILD_AFLAGS += -mrelax -mno-pic
KBUILD_CFLAGS_MODULE += -mno-relax
LDFLAGS_vmlinux += --relax
diff --git a/arch/avr32/boards/mimc200/Makefile b/arch/avr32/boards/mimc200/Makefile
index 79c076e168a8..c740aa116755 100644
--- a/arch/avr32/boards/mimc200/Makefile
+++ b/arch/avr32/boards/mimc200/Makefile
@@ -1 +1 @@
-obj-y += setup.o flash.o fram.o
+obj-y += setup.o flash.o
diff --git a/arch/avr32/boards/mimc200/fram.c b/arch/avr32/boards/mimc200/fram.c
deleted file mode 100644
index 9764a1a1073e..000000000000
--- a/arch/avr32/boards/mimc200/fram.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * FRAM driver for MIMC200 board
- *
- * Copyright 2008 Mark Jackson <mpfj@mimc.co.uk>
- *
- * This module adds *very* simply support for the system's FRAM device.
- * At the moment, this is hard-coded to the MIMC200 platform, and only
- * supports mmap().
- */
-
-#define FRAM_VERSION "1.0"
-
-#include <linux/miscdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/mm.h>
-#include <linux/io.h>
-
-#define FRAM_BASE 0xac000000
-#define FRAM_SIZE 0x20000
-
-/*
- * The are the file operation function for user access to /dev/fram
- */
-
-static int fram_mmap(struct file *filp, struct vm_area_struct *vma)
-{
- int ret;
-
- ret = remap_pfn_range(vma,
- vma->vm_start,
- virt_to_phys((void *)((unsigned long)FRAM_BASE)) >> PAGE_SHIFT,
- vma->vm_end-vma->vm_start,
- PAGE_SHARED);
-
- if (ret != 0)
- return -EAGAIN;
-
- return 0;
-}
-
-static const struct file_operations fram_fops = {
- .owner = THIS_MODULE,
- .mmap = fram_mmap,
- .llseek = noop_llseek,
-};
-
-#define FRAM_MINOR 0
-
-static struct miscdevice fram_dev = {
- FRAM_MINOR,
- "fram",
- &fram_fops
-};
-
-static int __init
-fram_init(void)
-{
- int ret;
-
- ret = misc_register(&fram_dev);
- if (ret) {
- printk(KERN_ERR "fram: can't misc_register on minor=%d\n",
- FRAM_MINOR);
- return ret;
- }
- printk(KERN_INFO "FRAM memory driver v" FRAM_VERSION "\n");
- return 0;
-}
-
-static void __exit
-fram_cleanup_module(void)
-{
- misc_deregister(&fram_dev);
-}
-
-module_init(fram_init);
-module_exit(fram_cleanup_module);
-
-MODULE_LICENSE("GPL");
-
-MODULE_ALIAS_MISCDEV(FRAM_MINOR);
diff --git a/arch/avr32/include/asm/Kbuild b/arch/avr32/include/asm/Kbuild
index cfb9fe1b8df9..00a0f3ccd6eb 100644
--- a/arch/avr32/include/asm/Kbuild
+++ b/arch/avr32/include/asm/Kbuild
@@ -1,21 +1,23 @@
-generic-y += clkdev.h
-generic-y += cputime.h
-generic-y += delay.h
-generic-y += device.h
-generic-y += div64.h
-generic-y += emergency-restart.h
-generic-y += exec.h
-generic-y += futex.h
-generic-y += preempt.h
-generic-y += irq_regs.h
-generic-y += param.h
-generic-y += local.h
-generic-y += local64.h
-generic-y += percpu.h
-generic-y += scatterlist.h
-generic-y += sections.h
-generic-y += topology.h
-generic-y += trace_clock.h
-generic-y += xor.h
-generic-y += hash.h
+generic-y += clkdev.h
+generic-y += cputime.h
+generic-y += delay.h
+generic-y += device.h
+generic-y += div64.h
+generic-y += emergency-restart.h
+generic-y += exec.h
+generic-y += futex.h
+generic-y += hash.h
+generic-y += irq_regs.h
+generic-y += local.h
+generic-y += local64.h
+generic-y += mcs_spinlock.h
+generic-y += param.h
+generic-y += percpu.h
+generic-y += preempt.h
+generic-y += scatterlist.h
+generic-y += sections.h
+generic-y += topology.h
+generic-y += trace_clock.h
+generic-y += vga.h
+generic-y += xor.h
diff --git a/arch/avr32/include/asm/bugs.h b/arch/avr32/include/asm/bugs.h
index 7635e770622e..278661bbd1b0 100644
--- a/arch/avr32/include/asm/bugs.h
+++ b/arch/avr32/include/asm/bugs.h
@@ -9,7 +9,7 @@
static void __init check_bugs(void)
{
- cpu_data->loops_per_jiffy = loops_per_jiffy;
+ boot_cpu_data.loops_per_jiffy = loops_per_jiffy;
}
#endif /* __ASM_AVR32_BUGS_H */
diff --git a/arch/avr32/include/asm/io.h b/arch/avr32/include/asm/io.h
index fc6483f83ccc..4f5ec2bb7172 100644
--- a/arch/avr32/include/asm/io.h
+++ b/arch/avr32/include/asm/io.h
@@ -295,6 +295,8 @@ extern void __iounmap(void __iomem *addr);
#define iounmap(addr) \
__iounmap(addr)
+#define ioremap_wc ioremap_nocache
+
#define cached(addr) P1SEGADDR(addr)
#define uncached(addr) P2SEGADDR(addr)
diff --git a/arch/avr32/include/asm/processor.h b/arch/avr32/include/asm/processor.h
index 48d71c5c898a..972adcc1e8f4 100644
--- a/arch/avr32/include/asm/processor.h
+++ b/arch/avr32/include/asm/processor.h
@@ -83,13 +83,8 @@ static inline unsigned int avr32_get_chip_revision(struct avr32_cpuinfo *cpu)
extern struct avr32_cpuinfo boot_cpu_data;
-#ifdef CONFIG_SMP
-extern struct avr32_cpuinfo cpu_data[];
-#define current_cpu_data cpu_data[smp_processor_id()]
-#else
-#define cpu_data (&boot_cpu_data)
+/* No SMP support so far */
#define current_cpu_data boot_cpu_data
-#endif
/* This decides where the kernel will search for a free chunk of vm
* space during mmap's
diff --git a/arch/avr32/kernel/cpu.c b/arch/avr32/kernel/cpu.c
index 2233be71e2e8..0341ae27c9ec 100644
--- a/arch/avr32/kernel/cpu.c
+++ b/arch/avr32/kernel/cpu.c
@@ -39,10 +39,12 @@ static ssize_t store_pc0event(struct device *dev,
size_t count)
{
unsigned long val;
- char *endp;
+ int ret;
- val = simple_strtoul(buf, &endp, 0);
- if (endp == buf || val > 0x3f)
+ ret = kstrtoul(buf, 0, &val);
+ if (ret)
+ return ret;
+ if (val > 0x3f)
return -EINVAL;
val = (val << 12) | (sysreg_read(PCCR) & 0xfffc0fff);
sysreg_write(PCCR, val);
@@ -61,11 +63,11 @@ static ssize_t store_pc0count(struct device *dev,
const char *buf, size_t count)
{
unsigned long val;
- char *endp;
+ int ret;
- val = simple_strtoul(buf, &endp, 0);
- if (endp == buf)
- return -EINVAL;
+ ret = kstrtoul(buf, 0, &val);
+ if (ret)
+ return ret;
sysreg_write(PCNT0, val);
return count;
@@ -84,10 +86,12 @@ static ssize_t store_pc1event(struct device *dev,
size_t count)
{
unsigned long val;
- char *endp;
+ int ret;
- val = simple_strtoul(buf, &endp, 0);
- if (endp == buf || val > 0x3f)
+ ret = kstrtoul(buf, 0, &val);
+ if (ret)
+ return ret;
+ if (val > 0x3f)
return -EINVAL;
val = (val << 18) | (sysreg_read(PCCR) & 0xff03ffff);
sysreg_write(PCCR, val);
@@ -106,11 +110,11 @@ static ssize_t store_pc1count(struct device *dev,
size_t count)
{
unsigned long val;
- char *endp;
+ int ret;
- val = simple_strtoul(buf, &endp, 0);
- if (endp == buf)
- return -EINVAL;
+ ret = kstrtoul(buf, 0, &val);
+ if (ret)
+ return ret;
sysreg_write(PCNT1, val);
return count;
@@ -129,11 +133,11 @@ static ssize_t store_pccycles(struct device *dev,
size_t count)
{
unsigned long val;
- char *endp;
+ int ret;
- val = simple_strtoul(buf, &endp, 0);
- if (endp == buf)
- return -EINVAL;
+ ret = kstrtoul(buf, 0, &val);
+ if (ret)
+ return ret;
sysreg_write(PCCNT, val);
return count;
@@ -152,11 +156,11 @@ static ssize_t store_pcenable(struct device *dev,
size_t count)
{
unsigned long pccr, val;
- char *endp;
+ int ret;
- val = simple_strtoul(buf, &endp, 0);
- if (endp == buf)
- return -EINVAL;
+ ret = kstrtoul(buf, 0, &val);
+ if (ret)
+ return ret;
if (val)
val = 1;
diff --git a/arch/avr32/mm/cache.c b/arch/avr32/mm/cache.c
index 6a46ecd56cfd..85d635cd7b28 100644
--- a/arch/avr32/mm/cache.c
+++ b/arch/avr32/mm/cache.c
@@ -111,6 +111,7 @@ void flush_icache_range(unsigned long start, unsigned long end)
__flush_icache_range(start & ~(linesz - 1),
(end + linesz - 1) & ~(linesz - 1));
}
+EXPORT_SYMBOL(flush_icache_range);
/*
* This one is called from __do_fault() and do_swap_page().
diff --git a/arch/blackfin/include/asm/Kbuild b/arch/blackfin/include/asm/Kbuild
index 359d36fdc247..0d93b9a79ca9 100644
--- a/arch/blackfin/include/asm/Kbuild
+++ b/arch/blackfin/include/asm/Kbuild
@@ -10,6 +10,7 @@ generic-y += emergency-restart.h
generic-y += errno.h
generic-y += fb.h
generic-y += futex.h
+generic-y += hash.h
generic-y += hw_irq.h
generic-y += ioctl.h
generic-y += ipcbuf.h
@@ -17,14 +18,16 @@ generic-y += irq_regs.h
generic-y += kdebug.h
generic-y += kmap_types.h
generic-y += kvm_para.h
-generic-y += local64.h
generic-y += local.h
+generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += mman.h
generic-y += msgbuf.h
generic-y += mutex.h
generic-y += param.h
generic-y += percpu.h
generic-y += pgalloc.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += sembuf.h
@@ -44,5 +47,3 @@ generic-y += ucontext.h
generic-y += unaligned.h
generic-y += user.h
generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/blackfin/include/asm/irq.h b/arch/blackfin/include/asm/irq.h
index 2fd04f10cc26..89de539ed010 100644
--- a/arch/blackfin/include/asm/irq.h
+++ b/arch/blackfin/include/asm/irq.h
@@ -20,15 +20,6 @@
/* SYS_IRQS and NR_IRQS are defined in <mach-bf5xx/irq.h> */
#include <mach/irq.h>
-/*
- * pm save bfin pint registers
- */
-struct adi_pm_pint_save {
- u32 assign;
- u32 edge_set;
- u32 invert_set;
-};
-
#if ANOMALY_05000244 && defined(CONFIG_BFIN_ICACHE)
# define NOP_PAD_ANOMALY_05000244 "nop; nop;"
#else
diff --git a/arch/blackfin/kernel/ftrace.c b/arch/blackfin/kernel/ftrace.c
index 9277905b82cf..095de0fa044d 100644
--- a/arch/blackfin/kernel/ftrace.c
+++ b/arch/blackfin/kernel/ftrace.c
@@ -65,11 +65,8 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
return ftrace_modify_code(ip, call, sizeof(call));
}
-int __init ftrace_dyn_arch_init(void *data)
+int __init ftrace_dyn_arch_init(void)
{
- /* return value is done indirectly via data */
- *(unsigned long *)data = 0;
-
return 0;
}
diff --git a/arch/c6x/include/asm/Kbuild b/arch/c6x/include/asm/Kbuild
index d73bb85ccdd3..8dbdce8421b0 100644
--- a/arch/c6x/include/asm/Kbuild
+++ b/arch/c6x/include/asm/Kbuild
@@ -15,6 +15,7 @@ generic-y += exec.h
generic-y += fb.h
generic-y += fcntl.h
generic-y += futex.h
+generic-y += hash.h
generic-y += hw_irq.h
generic-y += io.h
generic-y += ioctl.h
@@ -24,6 +25,7 @@ generic-y += irq_regs.h
generic-y += kdebug.h
generic-y += kmap_types.h
generic-y += local.h
+generic-y += mcs_spinlock.h
generic-y += mman.h
generic-y += mmu.h
generic-y += mmu_context.h
@@ -34,6 +36,7 @@ generic-y += percpu.h
generic-y += pgalloc.h
generic-y += poll.h
generic-y += posix_types.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += segment.h
@@ -56,5 +59,3 @@ generic-y += ucontext.h
generic-y += user.h
generic-y += vga.h
generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/c6x/include/asm/cache.h b/arch/c6x/include/asm/cache.h
index 09c5a0f5f4d1..86648c083bb4 100644
--- a/arch/c6x/include/asm/cache.h
+++ b/arch/c6x/include/asm/cache.h
@@ -12,6 +12,7 @@
#define _ASM_C6X_CACHE_H
#include <linux/irqflags.h>
+#include <linux/init.h>
/*
* Cache line size
diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig
index 6792503aaf79..15a9ed1d579c 100644
--- a/arch/cris/arch-v32/drivers/Kconfig
+++ b/arch/cris/arch-v32/drivers/Kconfig
@@ -11,7 +11,6 @@ config ETRAX_ETHERNET
config ETRAX_NO_PHY
bool "PHY not present"
depends on ETRAX_ETHERNET
- default N
help
This option disables all MDIO communication with an ethernet
transceiver connected to the MII interface. This option shall
@@ -116,7 +115,6 @@ config ETRAX_AXISFLASHMAP
config ETRAX_AXISFLASHMAP_MTD0WHOLE
bool "MTD0 is whole boot flash device"
depends on ETRAX_AXISFLASHMAP
- default N
help
When this option is not set, mtd0 refers to the first partition
on the boot flash device. When set, mtd0 refers to the whole
diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild
index f3fd8768f095..afff5105909d 100644
--- a/arch/cris/include/asm/Kbuild
+++ b/arch/cris/include/asm/Kbuild
@@ -5,12 +5,14 @@ header-y += arch-v32/
generic-y += barrier.h
generic-y += clkdev.h
+generic-y += cputime.h
generic-y += exec.h
generic-y += hash.h
generic-y += kvm_para.h
generic-y += linkage.h
+generic-y += mcs_spinlock.h
generic-y += module.h
+generic-y += preempt.h
generic-y += trace_clock.h
generic-y += vga.h
generic-y += xor.h
-generic-y += preempt.h
diff --git a/arch/cris/include/asm/bitops.h b/arch/cris/include/asm/bitops.h
index 184066ceb1f6..053c17b36559 100644
--- a/arch/cris/include/asm/bitops.h
+++ b/arch/cris/include/asm/bitops.h
@@ -144,7 +144,7 @@ static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
* definition, which doesn't have the same semantics. We don't want to
* use -fno-builtin, so just hide the name ffs.
*/
-#define ffs kernel_ffs
+#define ffs(x) kernel_ffs(x)
#include <asm-generic/bitops/fls.h>
#include <asm-generic/bitops/__fls.h>
diff --git a/arch/cris/include/asm/cputime.h b/arch/cris/include/asm/cputime.h
deleted file mode 100644
index 4446a65656fa..000000000000
--- a/arch/cris/include/asm/cputime.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __CRIS_CPUTIME_H
-#define __CRIS_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __CRIS_CPUTIME_H */
diff --git a/arch/frv/include/asm/Kbuild b/arch/frv/include/asm/Kbuild
index bc42f14c9c2e..87b95eb8aee5 100644
--- a/arch/frv/include/asm/Kbuild
+++ b/arch/frv/include/asm/Kbuild
@@ -1,6 +1,8 @@
generic-y += clkdev.h
+generic-y += cputime.h
generic-y += exec.h
-generic-y += trace_clock.h
-generic-y += preempt.h
generic-y += hash.h
+generic-y += mcs_spinlock.h
+generic-y += preempt.h
+generic-y += trace_clock.h
diff --git a/arch/frv/include/asm/cputime.h b/arch/frv/include/asm/cputime.h
deleted file mode 100644
index f6c373ad2b80..000000000000
--- a/arch/frv/include/asm/cputime.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_CPUTIME_H
-#define _ASM_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* _ASM_CPUTIME_H */
diff --git a/arch/frv/mb93090-mb00/pci-frv.c b/arch/frv/mb93090-mb00/pci-frv.c
index c28121765448..67b1d1685759 100644
--- a/arch/frv/mb93090-mb00/pci-frv.c
+++ b/arch/frv/mb93090-mb00/pci-frv.c
@@ -88,7 +88,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
/* Depth-First Search on bus tree */
for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
- bus = pci_bus_b(ln);
+ bus = list_entry(ln, struct pci_bus, node);
if ((dev = bus->self)) {
for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
r = &dev->resource[idx];
diff --git a/arch/hexagon/include/asm/Kbuild b/arch/hexagon/include/asm/Kbuild
index 38ca45d3df1e..eadcc118f950 100644
--- a/arch/hexagon/include/asm/Kbuild
+++ b/arch/hexagon/include/asm/Kbuild
@@ -25,14 +25,16 @@ generic-y += ipcbuf.h
generic-y += irq_regs.h
generic-y += kdebug.h
generic-y += kmap_types.h
-generic-y += local64.h
generic-y += local.h
+generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += mman.h
generic-y += msgbuf.h
generic-y += pci.h
generic-y += percpu.h
generic-y += poll.h
generic-y += posix_types.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += rwsem.h
generic-y += scatterlist.h
@@ -45,8 +47,8 @@ generic-y += siginfo.h
generic-y += sizes.h
generic-y += socket.h
generic-y += sockios.h
-generic-y += statfs.h
generic-y += stat.h
+generic-y += statfs.h
generic-y += termbits.h
generic-y += termios.h
generic-y += topology.h
@@ -55,4 +57,3 @@ generic-y += types.h
generic-y += ucontext.h
generic-y += unaligned.h
generic-y += xor.h
-generic-y += preempt.h
diff --git a/arch/ia64/configs/generic_defconfig b/arch/ia64/configs/generic_defconfig
index efbd2929aeb7..b4efaf2bc13e 100644
--- a/arch/ia64/configs/generic_defconfig
+++ b/arch/ia64/configs/generic_defconfig
@@ -25,14 +25,13 @@ CONFIG_KEXEC=y
CONFIG_CRASH_DUMP=y
CONFIG_EFI_VARS=y
CONFIG_BINFMT_MISC=m
-CONFIG_ACPI_PROCFS=y
CONFIG_ACPI_BUTTON=m
CONFIG_ACPI_FAN=m
CONFIG_ACPI_DOCK=y
CONFIG_ACPI_PROCESSOR=m
-CONFIG_ACPI_CONTAINER=m
+CONFIG_ACPI_CONTAINER=y
CONFIG_HOTPLUG_PCI=y
-CONFIG_HOTPLUG_PCI_ACPI=m
+CONFIG_HOTPLUG_PCI_ACPI=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_INET=y
diff --git a/arch/ia64/configs/tiger_defconfig b/arch/ia64/configs/tiger_defconfig
index 0f4e9e41f130..0fed9ae5a42a 100644
--- a/arch/ia64/configs/tiger_defconfig
+++ b/arch/ia64/configs/tiger_defconfig
@@ -26,7 +26,6 @@ CONFIG_IA64_PALINFO=y
CONFIG_KEXEC=y
CONFIG_EFI_VARS=y
CONFIG_BINFMT_MISC=m
-CONFIG_ACPI_PROCFS=y
CONFIG_ACPI_BUTTON=m
CONFIG_ACPI_FAN=m
CONFIG_ACPI_PROCESSOR=m
diff --git a/arch/ia64/configs/zx1_defconfig b/arch/ia64/configs/zx1_defconfig
index fc7aba07c2b4..54bc72eda30d 100644
--- a/arch/ia64/configs/zx1_defconfig
+++ b/arch/ia64/configs/zx1_defconfig
@@ -16,7 +16,6 @@ CONFIG_IA64_PALINFO=y
CONFIG_CRASH_DUMP=y
CONFIG_EFI_VARS=y
CONFIG_BINFMT_MISC=y
-CONFIG_ACPI_PROCFS=y
CONFIG_HOTPLUG_PCI=y
CONFIG_HOTPLUG_PCI_ACPI=y
CONFIG_PACKET=y
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
index 8e858b593e4f..1a871b78e570 100644
--- a/arch/ia64/hp/common/sba_iommu.c
+++ b/arch/ia64/hp/common/sba_iommu.c
@@ -1140,11 +1140,13 @@ sba_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
#ifdef CONFIG_NUMA
{
+ int node = ioc->node;
struct page *page;
- page = alloc_pages_exact_node(ioc->node == MAX_NUMNODES ?
- numa_node_id() : ioc->node, flags,
- get_order(size));
+ if (node == NUMA_NO_NODE)
+ node = numa_node_id();
+
+ page = alloc_pages_exact_node(node, flags, get_order(size));
if (unlikely(!page))
return NULL;
@@ -1596,7 +1598,7 @@ static void sba_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist,
*
***************************************************************/
-static void __init
+static void
ioc_iova_init(struct ioc *ioc)
{
int tcnfg;
@@ -1807,7 +1809,7 @@ static struct ioc_iommu ioc_iommu_info[] __initdata = {
{ SX2000_IOC_ID, "sx2000", NULL },
};
-static struct ioc * __init
+static struct ioc *
ioc_init(unsigned long hpa, void *handle)
{
struct ioc *ioc;
@@ -1914,7 +1916,7 @@ ioc_show(struct seq_file *s, void *v)
seq_printf(s, "Hewlett Packard %s IOC rev %d.%d\n",
ioc->name, ((ioc->rev >> 4) & 0xF), (ioc->rev & 0xF));
#ifdef CONFIG_NUMA
- if (ioc->node != MAX_NUMNODES)
+ if (ioc->node != NUMA_NO_NODE)
seq_printf(s, "NUMA node : %d\n", ioc->node);
#endif
seq_printf(s, "IOVA size : %ld MB\n", ((ioc->pdir_size >> 3) * iovp_size)/(1024*1024));
@@ -2015,33 +2017,21 @@ sba_connect_bus(struct pci_bus *bus)
printk(KERN_WARNING "No IOC for PCI Bus %04x:%02x in ACPI\n", pci_domain_nr(bus), bus->number);
}
-#ifdef CONFIG_NUMA
static void __init
sba_map_ioc_to_node(struct ioc *ioc, acpi_handle handle)
{
+#ifdef CONFIG_NUMA
unsigned int node;
- int pxm;
-
- ioc->node = MAX_NUMNODES;
-
- pxm = acpi_get_pxm(handle);
-
- if (pxm < 0)
- return;
-
- node = pxm_to_node(pxm);
- if (node >= MAX_NUMNODES || !node_online(node))
- return;
+ node = acpi_get_node(handle);
+ if (node != NUMA_NO_NODE && !node_online(node))
+ node = NUMA_NO_NODE;
ioc->node = node;
- return;
-}
-#else
-#define sba_map_ioc_to_node(ioc, handle)
#endif
+}
-static int __init
+static int
acpi_sba_ioc_add(struct acpi_device *device,
const struct acpi_device_id *not_used)
{
diff --git a/arch/ia64/include/asm/Kbuild b/arch/ia64/include/asm/Kbuild
index 283a83154b5e..0da4aa2602ae 100644
--- a/arch/ia64/include/asm/Kbuild
+++ b/arch/ia64/include/asm/Kbuild
@@ -1,8 +1,9 @@
generic-y += clkdev.h
generic-y += exec.h
+generic-y += hash.h
generic-y += kvm_para.h
-generic-y += trace_clock.h
+generic-y += mcs_spinlock.h
generic-y += preempt.h
+generic-y += trace_clock.h
generic-y += vtime.h
-generic-y += hash.h
diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h
index 71fbaaa495cc..7d41cc089822 100644
--- a/arch/ia64/include/asm/pci.h
+++ b/arch/ia64/include/asm/pci.h
@@ -98,7 +98,7 @@ struct pci_controller {
struct acpi_device *companion;
void *iommu;
int segment;
- int node; /* nearest node with memory or -1 for global allocation */
+ int node; /* nearest node with memory or NUMA_NO_NODE for global allocation */
void *platform_data;
};
diff --git a/arch/ia64/include/asm/topology.h b/arch/ia64/include/asm/topology.h
index a2496e449b75..5cb55a1e606b 100644
--- a/arch/ia64/include/asm/topology.h
+++ b/arch/ia64/include/asm/topology.h
@@ -77,7 +77,6 @@ void build_cpu_to_node_map(void);
#define topology_core_id(cpu) (cpu_data(cpu)->core_id)
#define topology_core_cpumask(cpu) (&cpu_core_map[cpu])
#define topology_thread_cpumask(cpu) (&per_cpu(cpu_sibling_map, cpu))
-#define smt_capable() (smp_num_siblings > 1)
#endif
extern void arch_fix_phys_package_id(int num, u32 slot);
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index 07d209c9507f..0d407b300762 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -54,10 +54,6 @@
#include <asm/sal.h>
#include <asm/cyclone.h>
-#define BAD_MADT_ENTRY(entry, end) ( \
- (!entry) || (unsigned long)entry + sizeof(*entry) > end || \
- ((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
-
#define PREFIX "ACPI: "
unsigned int acpi_cpei_override;
@@ -803,14 +799,9 @@ int acpi_isa_irq_to_gsi(unsigned isa_irq, u32 *gsi)
* ACPI based hotplug CPU support
*/
#ifdef CONFIG_ACPI_HOTPLUG_CPU
-static
-int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
+static int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
{
#ifdef CONFIG_ACPI_NUMA
- int pxm_id;
- int nid;
-
- pxm_id = acpi_get_pxm(handle);
/*
* We don't have cpu-only-node hotadd. But if the system equips
* SRAT table, pxm is already found and node is ready.
@@ -818,11 +809,10 @@ int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
* This code here is for the system which doesn't have full SRAT
* table for possible cpus.
*/
- nid = acpi_map_pxm_to_node(pxm_id);
node_cpuid[cpu].phys_id = physid;
- node_cpuid[cpu].nid = nid;
+ node_cpuid[cpu].nid = acpi_get_node(handle);
#endif
- return (0);
+ return 0;
}
int additional_cpus __initdata = -1;
@@ -929,7 +919,7 @@ static acpi_status acpi_map_iosapic(acpi_handle handle, u32 depth,
union acpi_object *obj;
struct acpi_madt_io_sapic *iosapic;
unsigned int gsi_base;
- int pxm, node;
+ int node;
/* Only care about objects w/ a method that returns the MADT */
if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
@@ -956,17 +946,9 @@ static acpi_status acpi_map_iosapic(acpi_handle handle, u32 depth,
kfree(buffer.pointer);
- /*
- * OK, it's an IOSAPIC MADT entry, look for a _PXM value to tell
- * us which node to associate this with.
- */
- pxm = acpi_get_pxm(handle);
- if (pxm < 0)
- return AE_OK;
-
- node = pxm_to_node(pxm);
-
- if (node >= MAX_NUMNODES || !node_online(node) ||
+ /* OK, it's an IOSAPIC MADT entry; associate it with a node */
+ node = acpi_get_node(handle);
+ if (node == NUMA_NO_NODE || !node_online(node) ||
cpumask_empty(cpumask_of_node(node)))
return AE_OK;
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index da5b462e6de6..741b99c1a0b1 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -477,6 +477,9 @@ efi_init (void)
char *cp, vendor[100] = "unknown";
int i;
+ set_bit(EFI_BOOT, &efi.flags);
+ set_bit(EFI_64BIT, &efi.flags);
+
/*
* It's too early to be able to use the standard kernel command line
* support...
@@ -529,6 +532,8 @@ efi_init (void)
efi.systab->hdr.revision >> 16,
efi.systab->hdr.revision & 0xffff, vendor);
+ set_bit(EFI_SYSTEM_TABLES, &efi.flags);
+
palo_phys = EFI_INVALID_TABLE_ADDR;
if (efi_config_init(arch_tables) != 0)
@@ -657,6 +662,8 @@ efi_enter_virtual_mode (void)
return;
}
+ set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+
/*
* Now that EFI is in virtual mode, we call the EFI functions more
* efficiently:
diff --git a/arch/ia64/kernel/ftrace.c b/arch/ia64/kernel/ftrace.c
index 7fc8c961b1f7..3b0c2aa07857 100644
--- a/arch/ia64/kernel/ftrace.c
+++ b/arch/ia64/kernel/ftrace.c
@@ -198,9 +198,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
}
/* run from kstop_machine */
-int __init ftrace_dyn_arch_init(void *data)
+int __init ftrace_dyn_arch_init(void)
{
- *(unsigned long *)data = 0;
-
return 0;
}
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
index 1034884b77da..0884f5ecbcc3 100644
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -364,7 +364,6 @@ static irqreturn_t smp_irq_move_cleanup_interrupt(int irq, void *dev_id)
static struct irqaction irq_move_irqaction = {
.handler = smp_irq_move_cleanup_interrupt,
- .flags = IRQF_DISABLED,
.name = "irq_move"
};
@@ -489,14 +488,13 @@ ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
ia64_srlz_d();
while (vector != IA64_SPURIOUS_INT_VECTOR) {
int irq = local_vector_to_irq(vector);
- struct irq_desc *desc = irq_to_desc(irq);
if (unlikely(IS_LOCAL_TLB_FLUSH(vector))) {
smp_local_flush_tlb();
- kstat_incr_irqs_this_cpu(irq, desc);
+ kstat_incr_irq_this_cpu(irq);
} else if (unlikely(IS_RESCHEDULE(vector))) {
scheduler_ipi();
- kstat_incr_irqs_this_cpu(irq, desc);
+ kstat_incr_irq_this_cpu(irq);
} else {
ia64_setreg(_IA64_REG_CR_TPR, vector);
ia64_srlz_d();
@@ -549,13 +547,12 @@ void ia64_process_pending_intr(void)
*/
while (vector != IA64_SPURIOUS_INT_VECTOR) {
int irq = local_vector_to_irq(vector);
- struct irq_desc *desc = irq_to_desc(irq);
if (unlikely(IS_LOCAL_TLB_FLUSH(vector))) {
smp_local_flush_tlb();
- kstat_incr_irqs_this_cpu(irq, desc);
+ kstat_incr_irq_this_cpu(irq);
} else if (unlikely(IS_RESCHEDULE(vector))) {
- kstat_incr_irqs_this_cpu(irq, desc);
+ kstat_incr_irq_this_cpu(irq);
} else {
struct pt_regs *old_regs = set_irq_regs(NULL);
@@ -602,7 +599,6 @@ static irqreturn_t dummy_handler (int irq, void *dev_id)
static struct irqaction ipi_irqaction = {
.handler = handle_IPI,
- .flags = IRQF_DISABLED,
.name = "IPI"
};
@@ -611,13 +607,11 @@ static struct irqaction ipi_irqaction = {
*/
static struct irqaction resched_irqaction = {
.handler = dummy_handler,
- .flags = IRQF_DISABLED,
.name = "resched"
};
static struct irqaction tlb_irqaction = {
.handler = dummy_handler,
- .flags = IRQF_DISABLED,
.name = "tlb_flush"
};
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index b8edfa75a83f..db7b36bb068b 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -217,7 +217,7 @@ void ia64_mca_printk(const char *fmt, ...)
/* Copy the output into mlogbuf */
if (oops_in_progress) {
/* mlogbuf was abandoned, use printk directly instead. */
- printk(temp_buf);
+ printk("%s", temp_buf);
} else {
spin_lock(&mlogbuf_wlock);
for (p = temp_buf; *p; p++) {
@@ -268,7 +268,7 @@ void ia64_mlogbuf_dump(void)
}
*p = '\0';
if (temp_buf[0])
- printk(temp_buf);
+ printk("%s", temp_buf);
mlogbuf_start = index;
mlogbuf_timestamp = 0;
@@ -1772,38 +1772,32 @@ __setup("disable_cpe_poll", ia64_mca_disable_cpe_polling);
static struct irqaction cmci_irqaction = {
.handler = ia64_mca_cmc_int_handler,
- .flags = IRQF_DISABLED,
.name = "cmc_hndlr"
};
static struct irqaction cmcp_irqaction = {
.handler = ia64_mca_cmc_int_caller,
- .flags = IRQF_DISABLED,
.name = "cmc_poll"
};
static struct irqaction mca_rdzv_irqaction = {
.handler = ia64_mca_rendez_int_handler,
- .flags = IRQF_DISABLED,
.name = "mca_rdzv"
};
static struct irqaction mca_wkup_irqaction = {
.handler = ia64_mca_wakeup_int_handler,
- .flags = IRQF_DISABLED,
.name = "mca_wkup"
};
#ifdef CONFIG_ACPI
static struct irqaction mca_cpe_irqaction = {
.handler = ia64_mca_cpe_int_handler,
- .flags = IRQF_DISABLED,
.name = "cpe_hndlr"
};
static struct irqaction mca_cpep_irqaction = {
.handler = ia64_mca_cpe_int_caller,
- .flags = IRQF_DISABLED,
.name = "cpe_poll"
};
#endif /* CONFIG_ACPI */
diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c
index fb2f1e622877..c430f9198d1b 100644
--- a/arch/ia64/kernel/msi_ia64.c
+++ b/arch/ia64/kernel/msi_ia64.c
@@ -17,12 +17,9 @@ static int ia64_set_msi_irq_affinity(struct irq_data *idata,
{
struct msi_msg msg;
u32 addr, data;
- int cpu = first_cpu(*cpu_mask);
+ int cpu = cpumask_first_and(cpu_mask, cpu_online_mask);
unsigned int irq = idata->irq;
- if (!cpu_online(cpu))
- return -1;
-
if (irq_prepare_move(irq, cpu))
return -1;
@@ -139,10 +136,7 @@ static int dmar_msi_set_affinity(struct irq_data *data,
unsigned int irq = data->irq;
struct irq_cfg *cfg = irq_cfg + irq;
struct msi_msg msg;
- int cpu = cpumask_first(mask);
-
- if (!cpu_online(cpu))
- return -1;
+ int cpu = cpumask_first_and(mask, cpu_online_mask);
if (irq_prepare_move(irq, cpu))
return -1;
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index cb592773c78b..d841c4bd6864 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -6387,7 +6387,6 @@ pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx)
static struct irqaction perfmon_irqaction = {
.handler = pfm_interrupt_handler,
- .flags = IRQF_DISABLED,
.name = "perfmon"
};
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index fbaac1afb844..71c52bc7c28d 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -380,7 +380,7 @@ static cycle_t itc_get_cycles(struct clocksource *cs)
static struct irqaction timer_irqaction = {
.handler = timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_IRQPOLL,
+ .flags = IRQF_IRQPOLL,
.name = "timer"
};
diff --git a/arch/ia64/kernel/uncached.c b/arch/ia64/kernel/uncached.c
index a96bcf83a735..20e8a9b21d75 100644
--- a/arch/ia64/kernel/uncached.c
+++ b/arch/ia64/kernel/uncached.c
@@ -98,7 +98,7 @@ static int uncached_add_chunk(struct uncached_pool *uc_pool, int nid)
/* attempt to allocate a granule's worth of cached memory pages */
page = alloc_pages_exact_node(nid,
- GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+ GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
IA64_GRANULE_SHIFT-PAGE_SHIFT);
if (!page) {
mutex_unlock(&uc_pool->add_chunk_mutex);
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 53f44bee9ebb..6a4309bb821a 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -199,6 +199,7 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_IRQCHIP:
case KVM_CAP_MP_STATE:
case KVM_CAP_IRQ_INJECT_STATUS:
+ case KVM_CAP_IOAPIC_POLARITY_IGNORED:
r = 1;
break;
case KVM_CAP_COALESCED_MMIO:
diff --git a/arch/ia64/pci/fixup.c b/arch/ia64/pci/fixup.c
index 5dc969dd4ac0..eee069a0b539 100644
--- a/arch/ia64/pci/fixup.c
+++ b/arch/ia64/pci/fixup.c
@@ -5,6 +5,7 @@
#include <linux/pci.h>
#include <linux/init.h>
+#include <linux/vgaarb.h>
#include <asm/machvec.h>
@@ -19,9 +20,10 @@
* IORESOURCE_ROM_SHADOW is used to associate the boot video
* card with this copy. On laptops this copy has to be used since
* the main ROM may be compressed or combined with another image.
- * See pci_map_rom() for use of this flag. IORESOURCE_ROM_SHADOW
- * is marked here since the boot video device will be the only enabled
- * video device at this point.
+ * See pci_map_rom() for use of this flag. Before marking the device
+ * with IORESOURCE_ROM_SHADOW check if a vga_default_device is already set
+ * by either arch cde or vga-arbitration, if so only apply the fixup to this
+ * already determined primary video card.
*/
static void pci_fixup_video(struct pci_dev *pdev)
@@ -35,9 +37,6 @@ static void pci_fixup_video(struct pci_dev *pdev)
return;
/* Maybe, this machine supports legacy memory map. */
- if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
- return;
-
/* Is VGA routed to us? */
bus = pdev->bus;
while (bus) {
@@ -60,10 +59,14 @@ static void pci_fixup_video(struct pci_dev *pdev)
}
bus = bus->parent;
}
- pci_read_config_word(pdev, PCI_COMMAND, &config);
- if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
- pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
- dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n");
+ if (!vga_default_device() || pdev == vga_default_device()) {
+ pci_read_config_word(pdev, PCI_COMMAND, &config);
+ if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
+ pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
+ dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n");
+ vga_set_default_device(pdev);
+ }
}
}
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_video);
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 9e4938d8ca4d..291a582777cf 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -126,7 +126,6 @@ static struct pci_controller *alloc_pci_controller(int seg)
return NULL;
controller->segment = seg;
- controller->node = -1;
return controller;
}
@@ -430,19 +429,14 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
struct pci_root_info *info = NULL;
int busnum = root->secondary.start;
struct pci_bus *pbus;
- int pxm, ret;
+ int ret;
controller = alloc_pci_controller(domain);
if (!controller)
return NULL;
controller->companion = device;
-
- pxm = acpi_get_pxm(device->handle);
-#ifdef CONFIG_NUMA
- if (pxm >= 0)
- controller->node = pxm_to_node(pxm);
-#endif
+ controller->node = acpi_get_node(device->handle);
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) {
diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c
index 62cf4dde6a04..85d095154902 100644
--- a/arch/ia64/sn/kernel/irq.c
+++ b/arch/ia64/sn/kernel/irq.c
@@ -209,8 +209,8 @@ static int sn_set_affinity_irq(struct irq_data *data,
nasid_t nasid;
int slice;
- nasid = cpuid_to_nasid(cpumask_first(mask));
- slice = cpuid_to_slice(cpumask_first(mask));
+ nasid = cpuid_to_nasid(cpumask_first_and(mask, cpu_online_mask));
+ slice = cpuid_to_slice(cpumask_first_and(mask, cpu_online_mask));
list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe,
sn_irq_lh[irq], list)
diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c
index 2b98b9e088de..afc58d2799ad 100644
--- a/arch/ia64/sn/kernel/msi_sn.c
+++ b/arch/ia64/sn/kernel/msi_sn.c
@@ -166,7 +166,7 @@ static int sn_set_msi_irq_affinity(struct irq_data *data,
struct sn_pcibus_provider *provider;
unsigned int cpu, irq = data->irq;
- cpu = cpumask_first(cpu_mask);
+ cpu = cpumask_first_and(cpu_mask, cpu_online_mask);
sn_irq_info = sn_msi_info[irq].sn_irq_info;
if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
return -1;
diff --git a/arch/m32r/include/asm/Kbuild b/arch/m32r/include/asm/Kbuild
index 932435ac4e5c..67779a74b62d 100644
--- a/arch/m32r/include/asm/Kbuild
+++ b/arch/m32r/include/asm/Kbuild
@@ -1,7 +1,9 @@
generic-y += clkdev.h
+generic-y += cputime.h
generic-y += exec.h
+generic-y += hash.h
+generic-y += mcs_spinlock.h
generic-y += module.h
-generic-y += trace_clock.h
generic-y += preempt.h
-generic-y += hash.h
+generic-y += trace_clock.h
diff --git a/arch/m32r/include/asm/cputime.h b/arch/m32r/include/asm/cputime.h
deleted file mode 100644
index 0a47550df2b7..000000000000
--- a/arch/m32r/include/asm/cputime.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __M32R_CPUTIME_H
-#define __M32R_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __M32R_CPUTIME_H */
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index dbdd2231c75d..b2e322939256 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -17,6 +17,7 @@ config M68K
select FPU if MMU
select ARCH_WANT_IPC_PARSE_VERSION
select ARCH_USES_GETTIMEOFFSET if MMU && !COLDFIRE
+ select HAVE_FUTEX_CMPXCHG if MMU && FUTEX
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_REL
select MODULES_USE_ELF_RELA
diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c
index 18c0e29976e3..2081b8cd5591 100644
--- a/arch/m68k/amiga/cia.c
+++ b/arch/m68k/amiga/cia.c
@@ -18,6 +18,7 @@
#include <linux/init.h>
#include <linux/seq_file.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <asm/irq.h>
#include <asm/amigahw.h>
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c
index 3e73a63c066f..3d2b63bedf05 100644
--- a/arch/m68k/atari/ataints.c
+++ b/arch/m68k/atari/ataints.c
@@ -41,6 +41,7 @@
#include <linux/init.h>
#include <linux/seq_file.h>
#include <linux/module.h>
+#include <linux/irq.h>
#include <asm/traps.h>
diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig
index 559ff3af8ff7..96da4963d14b 100644
--- a/arch/m68k/configs/amiga_defconfig
+++ b/arch/m68k/configs/amiga_defconfig
@@ -24,6 +24,8 @@ CONFIG_SUN_PARTITION=y
# CONFIG_EFI_PARTITION is not set
CONFIG_SYSV68_PARTITION=y
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_M68020=y
CONFIG_M68030=y
CONFIG_M68040=y
@@ -85,6 +87,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -94,6 +97,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -126,6 +131,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -163,8 +169,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -190,7 +194,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -512,7 +515,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig
index cb1f55df69b6..1b8739f50cbf 100644
--- a/arch/m68k/configs/apollo_defconfig
+++ b/arch/m68k/configs/apollo_defconfig
@@ -25,6 +25,8 @@ CONFIG_SUN_PARTITION=y
# CONFIG_EFI_PARTITION is not set
CONFIG_SYSV68_PARTITION=y
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_M68020=y
CONFIG_M68030=y
CONFIG_M68040=y
@@ -83,6 +85,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -92,6 +95,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -124,6 +129,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -161,8 +167,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -188,7 +192,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -470,7 +473,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig
index e880cfbb62d9..6ea4e91f0caa 100644
--- a/arch/m68k/configs/atari_defconfig
+++ b/arch/m68k/configs/atari_defconfig
@@ -24,6 +24,8 @@ CONFIG_SUN_PARTITION=y
# CONFIG_EFI_PARTITION is not set
CONFIG_SYSV68_PARTITION=y
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_M68020=y
CONFIG_M68030=y
CONFIG_M68040=y
@@ -82,6 +84,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -91,6 +94,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -123,6 +128,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -160,8 +166,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -187,7 +191,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -487,7 +490,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig
index 4aa4f45e52a8..e5a12739ff2d 100644
--- a/arch/m68k/configs/bvme6000_defconfig
+++ b/arch/m68k/configs/bvme6000_defconfig
@@ -24,6 +24,8 @@ CONFIG_UNIXWARE_DISKLABEL=y
CONFIG_SUN_PARTITION=y
# CONFIG_EFI_PARTITION is not set
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_M68040=y
CONFIG_M68060=y
CONFIG_VME=y
@@ -81,6 +83,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -90,6 +93,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -122,6 +127,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -159,8 +165,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -186,7 +190,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -463,7 +466,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig
index 7cd9d9f456fb..8936d7fb0f0f 100644
--- a/arch/m68k/configs/hp300_defconfig
+++ b/arch/m68k/configs/hp300_defconfig
@@ -25,6 +25,8 @@ CONFIG_SUN_PARTITION=y
# CONFIG_EFI_PARTITION is not set
CONFIG_SYSV68_PARTITION=y
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_M68020=y
CONFIG_M68030=y
CONFIG_M68040=y
@@ -83,6 +85,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -92,6 +95,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -124,6 +129,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -161,8 +167,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -188,7 +192,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -472,7 +475,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig
index 31f5bd061d14..be5342cca25b 100644
--- a/arch/m68k/configs/mac_defconfig
+++ b/arch/m68k/configs/mac_defconfig
@@ -24,6 +24,8 @@ CONFIG_SUN_PARTITION=y
# CONFIG_EFI_PARTITION is not set
CONFIG_SYSV68_PARTITION=y
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_M68020=y
CONFIG_M68030=y
CONFIG_M68040=y
@@ -82,6 +84,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -91,6 +94,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -123,6 +128,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -160,8 +166,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -187,7 +191,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -495,7 +498,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig
index 4e5adff326ee..f27194ade167 100644
--- a/arch/m68k/configs/multi_defconfig
+++ b/arch/m68k/configs/multi_defconfig
@@ -20,6 +20,8 @@ CONFIG_SOLARIS_X86_PARTITION=y
CONFIG_UNIXWARE_DISKLABEL=y
# CONFIG_EFI_PARTITION is not set
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_M68020=y
CONFIG_M68040=y
CONFIG_M68060=y
@@ -91,6 +93,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -100,6 +103,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -132,6 +137,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -169,8 +175,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -196,7 +200,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -571,7 +574,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig
index 02cdbac5565e..c3887603c1db 100644
--- a/arch/m68k/configs/mvme147_defconfig
+++ b/arch/m68k/configs/mvme147_defconfig
@@ -24,6 +24,8 @@ CONFIG_UNIXWARE_DISKLABEL=y
CONFIG_SUN_PARTITION=y
# CONFIG_EFI_PARTITION is not set
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_M68030=y
CONFIG_VME=y
CONFIG_MVME147=y
@@ -80,6 +82,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -89,6 +92,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -121,6 +126,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -158,8 +164,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -185,7 +189,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -463,7 +466,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig
index 05a990a9dbd4..f7ff784d05ac 100644
--- a/arch/m68k/configs/mvme16x_defconfig
+++ b/arch/m68k/configs/mvme16x_defconfig
@@ -24,6 +24,8 @@ CONFIG_UNIXWARE_DISKLABEL=y
CONFIG_SUN_PARTITION=y
# CONFIG_EFI_PARTITION is not set
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_M68040=y
CONFIG_M68060=y
CONFIG_VME=y
@@ -81,6 +83,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -90,6 +93,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -122,6 +127,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -159,8 +165,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -186,7 +190,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -464,7 +467,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig
index 568e2a98f976..f0c72ab037be 100644
--- a/arch/m68k/configs/q40_defconfig
+++ b/arch/m68k/configs/q40_defconfig
@@ -25,6 +25,8 @@ CONFIG_SUN_PARTITION=y
# CONFIG_EFI_PARTITION is not set
CONFIG_SYSV68_PARTITION=y
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_M68040=y
CONFIG_M68060=y
CONFIG_Q40=y
@@ -81,6 +83,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -90,6 +93,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -122,6 +127,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -159,8 +165,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -186,7 +190,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -485,7 +488,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig
index 60b0aeac5742..7bca0f464521 100644
--- a/arch/m68k/configs/sun3_defconfig
+++ b/arch/m68k/configs/sun3_defconfig
@@ -24,6 +24,8 @@ CONFIG_UNIXWARE_DISKLABEL=y
# CONFIG_EFI_PARTITION is not set
CONFIG_SYSV68_PARTITION=y
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_SUN3=y
# CONFIG_COMPACTION is not set
CONFIG_CLEANCACHE=y
@@ -78,6 +80,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -87,6 +90,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -119,6 +124,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -156,8 +162,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -183,7 +187,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -464,7 +467,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig
index 21bda331eebb..317f3e1fec95 100644
--- a/arch/m68k/configs/sun3x_defconfig
+++ b/arch/m68k/configs/sun3x_defconfig
@@ -24,6 +24,8 @@ CONFIG_UNIXWARE_DISKLABEL=y
# CONFIG_EFI_PARTITION is not set
CONFIG_SYSV68_PARTITION=y
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_SUN3X=y
# CONFIG_COMPACTION is not set
CONFIG_CLEANCACHE=y
@@ -78,6 +80,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -87,6 +90,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -119,6 +124,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -156,8 +162,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -183,7 +187,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -464,7 +467,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/include/asm/Kbuild b/arch/m68k/include/asm/Kbuild
index 7cc8c364924d..c67c94a2d672 100644
--- a/arch/m68k/include/asm/Kbuild
+++ b/arch/m68k/include/asm/Kbuild
@@ -1,4 +1,4 @@
-
+generic-y += barrier.h
generic-y += bitsperlong.h
generic-y += clkdev.h
generic-y += cputime.h
@@ -6,6 +6,7 @@ generic-y += device.h
generic-y += emergency-restart.h
generic-y += errno.h
generic-y += exec.h
+generic-y += hash.h
generic-y += hw_irq.h
generic-y += ioctl.h
generic-y += ipcbuf.h
@@ -13,11 +14,13 @@ generic-y += irq_regs.h
generic-y += kdebug.h
generic-y += kmap_types.h
generic-y += kvm_para.h
-generic-y += local64.h
generic-y += local.h
+generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += mman.h
generic-y += mutex.h
generic-y += percpu.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += sections.h
@@ -31,5 +34,3 @@ generic-y += trace_clock.h
generic-y += types.h
generic-y += word-at-a-time.h
generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/m68k/include/asm/barrier.h b/arch/m68k/include/asm/barrier.h
deleted file mode 100644
index 15c5f77c1614..000000000000
--- a/arch/m68k/include/asm/barrier.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _M68K_BARRIER_H
-#define _M68K_BARRIER_H
-
-#define nop() do { asm volatile ("nop"); barrier(); } while (0)
-
-#include <asm-generic/barrier.h>
-
-#endif /* _M68K_BARRIER_H */
diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h
index 014f288fc813..9d38b73989eb 100644
--- a/arch/m68k/include/asm/unistd.h
+++ b/arch/m68k/include/asm/unistd.h
@@ -4,7 +4,7 @@
#include <uapi/asm/unistd.h>
-#define NR_syscalls 349
+#define NR_syscalls 351
#define __ARCH_WANT_OLD_READDIR
#define __ARCH_WANT_OLD_STAT
diff --git a/arch/m68k/include/uapi/asm/unistd.h b/arch/m68k/include/uapi/asm/unistd.h
index 625f321001dc..b932dd470041 100644
--- a/arch/m68k/include/uapi/asm/unistd.h
+++ b/arch/m68k/include/uapi/asm/unistd.h
@@ -354,5 +354,7 @@
#define __NR_process_vm_writev 346
#define __NR_kcmp 347
#define __NR_finit_module 348
+#define __NR_sched_setattr 349
+#define __NR_sched_getattr 350
#endif /* _UAPI_ASM_M68K_UNISTD_H_ */
diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S
index 4c99bab7e664..3ab329b88521 100644
--- a/arch/m68k/kernel/head.S
+++ b/arch/m68k/kernel/head.S
@@ -275,7 +275,6 @@
#ifdef CONFIG_FRAMEBUFFER_CONSOLE
#define CONSOLE
-#define CONSOLE_PENGUIN
#endif
#ifdef CONFIG_EARLY_PRINTK
@@ -658,27 +657,6 @@ ENTRY(__start)
movel %a0@,%a1@
#endif
-#if 0
- /*
- * Clear the screen
- */
- lea %pc@(L(mac_videobase)),%a0
- movel %a0@,%a1
- lea %pc@(L(mac_dimensions)),%a0
- movel %a0@,%d1
- swap %d1 /* #rows is high bytes */
- andl #0xFFFF,%d1 /* rows */
- subl #10,%d1
- lea %pc@(L(mac_rowbytes)),%a0
-loopy2:
- movel %a0@,%d0
- subql #1,%d0
-loopx2:
- moveb #0x55, %a1@+
- dbra %d0,loopx2
- dbra %d1,loopy2
-#endif
-
L(test_notmac):
#endif /* CONFIG_MAC */
@@ -907,15 +885,15 @@ L(nothp):
*/
#ifdef CONFIG_MAC
is_not_mac(L(nocon))
-#ifdef CONSOLE
+# ifdef CONSOLE
console_init
-#ifdef CONSOLE_PENGUIN
+# ifdef CONFIG_LOGO
console_put_penguin
-#endif /* CONSOLE_PENGUIN */
+# endif /* CONFIG_LOGO */
console_put_stats
-#endif /* CONSOLE */
+# endif /* CONSOLE */
L(nocon):
-#endif /* CONFIG_MAC */
+#endif /* CONFIG_MAC */
putc '\n'
@@ -3324,14 +3302,13 @@ func_return set_leds
#define Lconsole_struct_num_columns 8
#define Lconsole_struct_num_rows 12
#define Lconsole_struct_left_edge 16
-#define Lconsole_struct_penguin_putc 20
func_start console_init,%a0-%a4/%d0-%d7
/*
* Some of the register usage that follows
* a0 = pointer to boot_info
* a1 = pointer to screen
- * a2 = pointer to Lconsole_globals
+ * a2 = pointer to console_globals
* d3 = pixel width of screen
* d4 = pixel height of screen
* (d3,d4) ~= (x,y) of a point just below
@@ -3456,7 +3433,7 @@ func_start console_put_stats,%a0/%d7
func_return console_put_stats
-#ifdef CONSOLE_PENGUIN
+#ifdef CONFIG_LOGO
func_start console_put_penguin,%a0-%a1/%d0-%d7
/*
* Get 'that_penguin' onto the screen in the upper right corner
@@ -3799,38 +3776,6 @@ L(console_plot_pixel_exit):
func_return console_plot_pixel
#endif /* CONSOLE */
-#if 0
-/*
- * This is some old code lying around. I don't believe
- * it's used or important anymore. My guess is it contributed
- * to getting to this point, but it's done for now.
- * It was still in the 2.1.77 head.S, so it's still here.
- * (And still not used!)
- */
-L(showtest):
- moveml %a0/%d7,%sp@-
- puts "A="
- putn %a1
-
- .long 0xf0119f15 | ptestr #5,%a1@,#7,%a0
-
- puts "DA="
- putn %a0
-
- puts "D="
- putn %a0@
-
- puts "S="
- lea %pc@(L(mmu)),%a0
- .long 0xf0106200 | pmove %psr,%a0@
- clrl %d7
- movew %a0@,%d7
- putn %d7
-
- putc '\n'
- moveml %sp@+,%a0/%d7
- rts
-#endif /* 0 */
__INITDATA
.align 4
@@ -3849,7 +3794,6 @@ L(console_globals):
.long 0 /* max num columns */
.long 0 /* max num rows */
.long 0 /* left edge */
- .long 0 /* mac putc */
L(console_font):
.long 0 /* pointer to console font (struct font_desc) */
L(console_font_data):
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c
index 077d3a70fed1..5b8d66fbf383 100644
--- a/arch/m68k/kernel/ints.c
+++ b/arch/m68k/kernel/ints.c
@@ -10,9 +10,9 @@
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/irq.h>
#include <asm/setup.h>
#include <asm/irq.h>
diff --git a/arch/m68k/kernel/syscalltable.S b/arch/m68k/kernel/syscalltable.S
index 3f04ea0ab802..b6223dc41d82 100644
--- a/arch/m68k/kernel/syscalltable.S
+++ b/arch/m68k/kernel/syscalltable.S
@@ -369,4 +369,6 @@ ENTRY(sys_call_table)
.long sys_process_vm_writev
.long sys_kcmp
.long sys_finit_module
+ .long sys_sched_setattr
+ .long sys_sched_getattr /* 350 */
diff --git a/arch/metag/Kconfig b/arch/metag/Kconfig
index e56abd2c1b4f..b1d3c9c0eff8 100644
--- a/arch/metag/Kconfig
+++ b/arch/metag/Kconfig
@@ -9,6 +9,7 @@ config METAG
select HAVE_ARCH_TRACEHOOK
select HAVE_C_RECORDMCOUNT
select HAVE_DEBUG_KMEMLEAK
+ select HAVE_DEBUG_STACKOVERFLOW
select HAVE_DYNAMIC_FTRACE
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_FUNCTION_TRACER
@@ -29,7 +30,6 @@ config METAG
select OF
select OF_EARLY_FLATTREE
select SPARSE_IRQ
- select HAVE_DEBUG_STACKOVERFLOW
config STACKTRACE_SUPPORT
def_bool y
diff --git a/arch/metag/include/asm/Kbuild b/arch/metag/include/asm/Kbuild
index b716d807c2ec..c29ead89a317 100644
--- a/arch/metag/include/asm/Kbuild
+++ b/arch/metag/include/asm/Kbuild
@@ -13,6 +13,7 @@ generic-y += fb.h
generic-y += fcntl.h
generic-y += futex.h
generic-y += hardirq.h
+generic-y += hash.h
generic-y += hw_irq.h
generic-y += ioctl.h
generic-y += ioctls.h
@@ -23,6 +24,7 @@ generic-y += kmap_types.h
generic-y += kvm_para.h
generic-y += local.h
generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += msgbuf.h
generic-y += mutex.h
generic-y += param.h
@@ -30,6 +32,7 @@ generic-y += pci.h
generic-y += percpu.h
generic-y += poll.h
generic-y += posix_types.h
+generic-y += preempt.h
generic-y += scatterlist.h
generic-y += sections.h
generic-y += sembuf.h
@@ -52,5 +55,3 @@ generic-y += unaligned.h
generic-y += user.h
generic-y += vga.h
generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/metag/include/asm/topology.h b/arch/metag/include/asm/topology.h
index 8e9c0b3b9691..e95f874ded1b 100644
--- a/arch/metag/include/asm/topology.h
+++ b/arch/metag/include/asm/topology.h
@@ -3,33 +3,6 @@
#ifdef CONFIG_NUMA
-/* sched_domains SD_NODE_INIT for Meta machines */
-#define SD_NODE_INIT (struct sched_domain) { \
- .parent = NULL, \
- .child = NULL, \
- .groups = NULL, \
- .min_interval = 8, \
- .max_interval = 32, \
- .busy_factor = 32, \
- .imbalance_pct = 125, \
- .cache_nice_tries = 2, \
- .busy_idx = 3, \
- .idle_idx = 2, \
- .newidle_idx = 0, \
- .wake_idx = 0, \
- .forkexec_idx = 0, \
- .flags = SD_LOAD_BALANCE \
- | SD_BALANCE_FORK \
- | SD_BALANCE_EXEC \
- | SD_BALANCE_NEWIDLE \
- | SD_SERIALIZE, \
- .last_balance = jiffies, \
- .balance_interval = 1, \
- .nr_balance_failed = 0, \
- .max_newidle_lb_cost = 0, \
- .next_decay_max_lb_cost = jiffies, \
-}
-
#define cpu_to_node(cpu) ((void)(cpu), 0)
#define parent_node(node) ((void)(node), 0)
diff --git a/arch/metag/kernel/ftrace.c b/arch/metag/kernel/ftrace.c
index a774f321643f..ed1d685157c2 100644
--- a/arch/metag/kernel/ftrace.c
+++ b/arch/metag/kernel/ftrace.c
@@ -117,10 +117,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
}
/* run from kstop_machine */
-int __init ftrace_dyn_arch_init(void *data)
+int __init ftrace_dyn_arch_init(void)
{
- /* The return code is returned via data */
- writel(0, data);
-
return 0;
}
diff --git a/arch/metag/kernel/irq.c b/arch/metag/kernel/irq.c
index 3b4b7f6c0950..5385dd1216b7 100644
--- a/arch/metag/kernel/irq.c
+++ b/arch/metag/kernel/irq.c
@@ -261,18 +261,6 @@ int __init arch_probe_nr_irqs(void)
}
#ifdef CONFIG_HOTPLUG_CPU
-static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
-{
- struct irq_desc *desc = irq_to_desc(irq);
- struct irq_chip *chip = irq_data_get_irq_chip(data);
- unsigned long flags;
-
- raw_spin_lock_irqsave(&desc->lock, flags);
- if (chip->irq_set_affinity)
- chip->irq_set_affinity(data, cpumask_of(cpu), false);
- raw_spin_unlock_irqrestore(&desc->lock, flags);
-}
-
/*
* The CPU has been marked offline. Migrate IRQs off this CPU. If
* the affinity settings do not allow other CPUs, force them onto any
@@ -281,10 +269,9 @@ static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
void migrate_irqs(void)
{
unsigned int i, cpu = smp_processor_id();
- struct irq_desc *desc;
- for_each_irq_desc(i, desc) {
- struct irq_data *data = irq_desc_get_irq_data(desc);
+ for_each_active_irq(i) {
+ struct irq_data *data = irq_get_irq_data(i);
unsigned int newcpu;
if (irqd_is_per_cpu(data))
@@ -300,11 +287,8 @@ void migrate_irqs(void)
i, cpu);
cpumask_setall(data->affinity);
- newcpu = cpumask_any_and(data->affinity,
- cpu_online_mask);
}
-
- route_irq(data, i, newcpu);
+ irq_set_affinity(i, data->affinity);
}
}
#endif /* CONFIG_HOTPLUG_CPU */
diff --git a/arch/metag/kernel/signal.c b/arch/metag/kernel/signal.c
index 3be61cf0b147..b9e4a82d2bd4 100644
--- a/arch/metag/kernel/signal.c
+++ b/arch/metag/kernel/signal.c
@@ -152,18 +152,18 @@ static void __user *get_sigframe(struct k_sigaction *ka, unsigned long sp,
return (void __user *)sp;
}
-static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
- sigset_t *set, struct pt_regs *regs)
+static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
+ struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
- int err = -EFAULT;
+ int err;
unsigned long code;
- frame = get_sigframe(ka, regs->REG_SP, sizeof(*frame));
+ frame = get_sigframe(&ksig->ka, regs->REG_SP, sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto out;
+ return -EFAULT;
- err = copy_siginfo_to_user(&frame->info, info);
+ err = copy_siginfo_to_user(&frame->info, &ksig->info);
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
@@ -174,7 +174,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
- goto out;
+ return -EFAULT;
/* Set up to return from userspace. */
@@ -187,15 +187,15 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __put_user(code, (unsigned long __user *)(&frame->retcode[1]));
if (err)
- goto out;
+ return -EFAULT;
/* Set up registers for signal handler */
regs->REG_RTP = (unsigned long) frame->retcode;
regs->REG_SP = (unsigned long) frame + sizeof(*frame);
- regs->REG_ARG1 = sig;
+ regs->REG_ARG1 = ksig->sig;
regs->REG_ARG2 = (unsigned long) &frame->info;
regs->REG_ARG3 = (unsigned long) &frame->uc;
- regs->REG_PC = (unsigned long) ka->sa.sa_handler;
+ regs->REG_PC = (unsigned long) ksig->ka.sa.sa_handler;
pr_debug("SIG deliver (%s:%d): sp=%p pc=%08x pr=%08x\n",
current->comm, current->pid, frame, regs->REG_PC,
@@ -205,24 +205,19 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
* effective cache flush - directed rather than 'full flush'.
*/
flush_cache_sigtramp(regs->REG_RTP, sizeof(frame->retcode));
-out:
- if (err) {
- force_sigsegv(sig, current);
- return -EFAULT;
- }
+
return 0;
}
-static void handle_signal(unsigned long sig, siginfo_t *info,
- struct k_sigaction *ka, struct pt_regs *regs)
+static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
{
sigset_t *oldset = sigmask_to_save();
+ int ret;
/* Set up the stack frame */
- if (setup_rt_frame(sig, ka, info, oldset, regs))
- return;
+ ret = setup_rt_frame(ksig, oldset, regs);
- signal_delivered(sig, info, ka, regs, test_thread_flag(TIF_SINGLESTEP));
+ signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP));
}
/*
@@ -235,10 +230,8 @@ static void handle_signal(unsigned long sig, siginfo_t *info,
static int do_signal(struct pt_regs *regs, int syscall)
{
unsigned int retval = 0, continue_addr = 0, restart_addr = 0;
- struct k_sigaction ka;
- siginfo_t info;
- int signr;
int restart = 0;
+ struct ksignal ksig;
/*
* By the end of rt_sigreturn the context describes the point that the
@@ -275,7 +268,8 @@ static int do_signal(struct pt_regs *regs, int syscall)
* Get the signal to deliver. When running under ptrace, at this point
* the debugger may change all our registers ...
*/
- signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+ get_signal(&ksig);
+
/*
* Depending on the signal settings we may need to revert the decision
* to restart the system call. But skip this if a debugger has chosen to
@@ -283,19 +277,19 @@ static int do_signal(struct pt_regs *regs, int syscall)
*/
if (regs->REG_PC != restart_addr)
restart = 0;
- if (signr > 0) {
+ if (ksig.sig > 0) {
if (unlikely(restart)) {
if (retval == -ERESTARTNOHAND
|| retval == -ERESTART_RESTARTBLOCK
|| (retval == -ERESTARTSYS
- && !(ka.sa.sa_flags & SA_RESTART))) {
+ && !(ksig.ka.sa.sa_flags & SA_RESTART))) {
regs->REG_RETVAL = -EINTR;
regs->REG_PC = continue_addr;
}
}
/* Whee! Actually deliver the signal. */
- handle_signal(signr, &info, &ka, regs);
+ handle_signal(&ksig, regs);
return 0;
}
diff --git a/arch/microblaze/include/asm/Kbuild b/arch/microblaze/include/asm/Kbuild
index 2b98bc73642a..c98ed95c0541 100644
--- a/arch/microblaze/include/asm/Kbuild
+++ b/arch/microblaze/include/asm/Kbuild
@@ -1,8 +1,10 @@
generic-y += barrier.h
generic-y += clkdev.h
+generic-y += cputime.h
generic-y += exec.h
generic-y += hash.h
-generic-y += trace_clock.h
-generic-y += syscalls.h
+generic-y += mcs_spinlock.h
generic-y += preempt.h
+generic-y += syscalls.h
+generic-y += trace_clock.h
diff --git a/arch/microblaze/include/asm/cputime.h b/arch/microblaze/include/asm/cputime.h
deleted file mode 100644
index 6d68ad7e0ea3..000000000000
--- a/arch/microblaze/include/asm/cputime.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/cputime.h>
diff --git a/arch/microblaze/include/asm/delay.h b/arch/microblaze/include/asm/delay.h
index 05b7d39e4391..66fc24c24238 100644
--- a/arch/microblaze/include/asm/delay.h
+++ b/arch/microblaze/include/asm/delay.h
@@ -13,6 +13,8 @@
#ifndef _ASM_MICROBLAZE_DELAY_H
#define _ASM_MICROBLAZE_DELAY_H
+#include <linux/param.h>
+
extern inline void __delay(unsigned long loops)
{
asm volatile ("# __delay \n\t" \
diff --git a/arch/microblaze/include/asm/io.h b/arch/microblaze/include/asm/io.h
index a2cea7206077..3fbb7f1db3bc 100644
--- a/arch/microblaze/include/asm/io.h
+++ b/arch/microblaze/include/asm/io.h
@@ -89,6 +89,11 @@ static inline unsigned int readl(const volatile void __iomem *addr)
{
return le32_to_cpu(*(volatile unsigned int __force *)addr);
}
+#define readq readq
+static inline u64 readq(const volatile void __iomem *addr)
+{
+ return le64_to_cpu(__raw_readq(addr));
+}
static inline void writeb(unsigned char v, volatile void __iomem *addr)
{
*(volatile unsigned char __force *)addr = v;
@@ -101,6 +106,7 @@ static inline void writel(unsigned int v, volatile void __iomem *addr)
{
*(volatile unsigned int __force *)addr = cpu_to_le32(v);
}
+#define writeq(b, addr) __raw_writeq(cpu_to_le64(b), addr)
/* ioread and iowrite variants. thease are for now same as __raw_
* variants of accessors. we might check for endianess in the feature
diff --git a/arch/microblaze/kernel/ftrace.c b/arch/microblaze/kernel/ftrace.c
index e8a5e9cf4ed1..bbcd2533766c 100644
--- a/arch/microblaze/kernel/ftrace.c
+++ b/arch/microblaze/kernel/ftrace.c
@@ -171,11 +171,8 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
return ret;
}
-int __init ftrace_dyn_arch_init(void *data)
+int __init ftrace_dyn_arch_init(void)
{
- /* The return code is retured via data */
- *(unsigned long *)data = 0;
-
return 0;
}
diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S
index b7fb0438458c..17645b2e2f07 100644
--- a/arch/microblaze/kernel/head.S
+++ b/arch/microblaze/kernel/head.S
@@ -66,7 +66,7 @@ real_start:
mts rmsr, r0
/* Disable stack protection from bootloader */
mts rslr, r0
- addi r8, r0, 0xFFFFFFF
+ addi r8, r0, 0xFFFFFFFF
mts rshr, r8
/*
* According to Xilinx, msrclr instruction behaves like 'mfs rX,rpc'
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index 66804adcacf0..70996cc66aa2 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -1294,11 +1294,6 @@ void pcibios_finish_adding_to_bus(struct pci_bus *bus)
}
EXPORT_SYMBOL_GPL(pcibios_finish_adding_to_bus);
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
- return pci_enable_resources(dev, mask);
-}
-
static void pcibios_setup_phb_resources(struct pci_controller *hose,
struct list_head *resources)
{
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index dcae3a7035db..16d5ab1615b1 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -10,6 +10,7 @@ config MIPS
select HAVE_PERF_EVENTS
select PERF_USE_VMALLOC
select HAVE_ARCH_KGDB
+ select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_TRACEHOOK
select ARCH_HAVE_CUSTOM_GPIO_H
select HAVE_FUNCTION_TRACER
@@ -62,13 +63,12 @@ config MIPS_ALCHEMY
select CEVT_R4K
select CSRC_R4K
select IRQ_CPU
+ select DMA_MAYBE_COHERENT # Au1000,1500,1100 aren't, rest is
select SYS_HAS_CPU_MIPS32_R1
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_APM_EMULATION
select ARCH_REQUIRE_GPIOLIB
select SYS_SUPPORTS_ZBOOT
- select USB_ARCH_HAS_OHCI
- select USB_ARCH_HAS_EHCI
config AR7
bool "Texas Instruments AR7"
@@ -123,7 +123,7 @@ config BCM47XX
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_HAS_EARLY_PRINTK
- select EARLY_PRINTK_8250 if EARLY_PRINTK
+ select USE_GENERIC_EARLY_PRINTK_8250
help
Support for BCM47XX based boards
@@ -150,7 +150,6 @@ config MIPS_COBALT
select CSRC_R4K
select CEVT_GT641XX
select DMA_NONCOHERENT
- select EARLY_PRINTK_8250 if EARLY_PRINTK
select HW_HAS_PCI
select I8253
select I8259
@@ -163,6 +162,7 @@ config MIPS_COBALT
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_64BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
+ select USE_GENERIC_EARLY_PRINTK_8250
config MACH_DECSTATION
bool "DECstations"
@@ -235,7 +235,6 @@ config MACH_JZ4740
select IRQ_CPU
select ARCH_REQUIRE_GPIOLIB
select SYS_HAS_EARLY_PRINTK
- select HAVE_PWM
select HAVE_CLK
select GENERIC_IRQ_CHIP
@@ -320,6 +319,7 @@ config MIPS_MALTA
select SWAP_IO_SPACE
select SYS_HAS_CPU_MIPS32_R1
select SYS_HAS_CPU_MIPS32_R2
+ select SYS_HAS_CPU_MIPS32_R3_5
select SYS_HAS_CPU_MIPS64_R1
select SYS_HAS_CPU_MIPS64_R2
select SYS_HAS_CPU_NEVADA
@@ -329,6 +329,7 @@ config MIPS_MALTA
select SYS_SUPPORTS_BIG_ENDIAN
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_SUPPORTS_MIPS_CMP
+ select SYS_SUPPORTS_MIPS_CPS
select SYS_SUPPORTS_MULTITHREADING
select SYS_SUPPORTS_SMARTMIPS
select SYS_SUPPORTS_ZBOOT
@@ -360,7 +361,6 @@ config MIPS_SEAD3
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_SUPPORTS_SMARTMIPS
select SYS_SUPPORTS_MICROMIPS
- select USB_ARCH_HAS_EHCI
select USB_EHCI_BIG_ENDIAN_DESC
select USB_EHCI_BIG_ENDIAN_MMIO
select USE_OF
@@ -674,6 +674,7 @@ config SNI_RM
select SYS_SUPPORTS_BIG_ENDIAN
select SYS_SUPPORTS_HIGHMEM
select SYS_SUPPORTS_LITTLE_ENDIAN
+ select USE_GENERIC_EARLY_PRINTK_8250
help
The SNI RM200/300/400 are MIPS-based machines manufactured by
Siemens Nixdorf Informationssysteme (SNI), parent company of Pyramid
@@ -718,8 +719,6 @@ config CAVIUM_OCTEON_SOC
select SWAP_IO_SPACE
select HW_HAS_PCI
select ZONE_DMA32
- select USB_ARCH_HAS_OHCI
- select USB_ARCH_HAS_EHCI
select HOLES_IN_ZONE
select ARCH_REQUIRE_GPIOLIB
help
@@ -756,8 +755,6 @@ config NLM_XLR_BOARD
select ZONE_DMA32 if 64BIT
select SYNC_R4K
select SYS_HAS_EARLY_PRINTK
- select USB_ARCH_HAS_OHCI if USB_SUPPORT
- select USB_ARCH_HAS_EHCI if USB_SUPPORT
select SYS_SUPPORTS_ZBOOT
select SYS_SUPPORTS_ZBOOT_UART16550
help
@@ -782,7 +779,6 @@ config NLM_XLP_BOARD
select CEVT_R4K
select CSRC_R4K
select IRQ_CPU
- select ARCH_SUPPORTS_MSI
select ZONE_DMA32 if 64BIT
select SYNC_R4K
select SYS_HAS_EARLY_PRINTK
@@ -868,6 +864,7 @@ config CEVT_R4K
bool
config CEVT_GIC
+ select MIPS_CM
bool
config CEVT_SB1250
@@ -886,6 +883,7 @@ config CSRC_R4K
bool
config CSRC_GIC
+ select MIPS_CM
bool
config CSRC_SB1250
@@ -1030,6 +1028,7 @@ config IRQ_GT641XX
bool
config IRQ_GIC
+ select MIPS_CM
bool
config PCI_GT64XXX_PCI0
@@ -1148,6 +1147,18 @@ choice
prompt "CPU type"
default CPU_R4X00
+config CPU_LOONGSON3
+ bool "Loongson 3 CPU"
+ depends on SYS_HAS_CPU_LOONGSON3
+ select CPU_SUPPORTS_64BIT_KERNEL
+ select CPU_SUPPORTS_HIGHMEM
+ select CPU_SUPPORTS_HUGEPAGES
+ select WEAK_ORDERING
+ select WEAK_REORDERING_BEYOND_LLSC
+ help
+ The Loongson 3 processor implements the MIPS64R2 instruction
+ set with many extensions.
+
config CPU_LOONGSON2E
bool "Loongson 2E"
depends on SYS_HAS_CPU_LOONGSON2E
@@ -1203,6 +1214,7 @@ config CPU_MIPS32_R2
select CPU_HAS_PREFETCH
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
+ select CPU_SUPPORTS_MSA
select HAVE_KVM
help
Choose this option to build a kernel for release 2 or later of the
@@ -1238,6 +1250,7 @@ config CPU_MIPS64_R2
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
select CPU_SUPPORTS_HUGEPAGES
+ select CPU_SUPPORTS_MSA
help
Choose this option to build a kernel for release 2 or later of the
MIPS64 architecture. Many modern embedded systems with a 64-bit
@@ -1396,7 +1409,6 @@ config CPU_CAVIUM_OCTEON
select LIBFDT
select USE_OF
select USB_EHCI_BIG_ENDIAN_MMIO
- select SYS_HAS_DMA_OPS
select MIPS_L1_CACHE_SHIFT_7
help
The Cavium Octeon processor is a highly integrated chip containing
@@ -1448,6 +1460,26 @@ config CPU_XLP
Netlogic Microsystems XLP processors.
endchoice
+config CPU_MIPS32_3_5_FEATURES
+ bool "MIPS32 Release 3.5 Features"
+ depends on SYS_HAS_CPU_MIPS32_R3_5
+ depends on CPU_MIPS32_R2
+ help
+ Choose this option to build a kernel for release 2 or later of the
+ MIPS32 architecture including features from the 3.5 release such as
+ support for Enhanced Virtual Addressing (EVA).
+
+config CPU_MIPS32_3_5_EVA
+ bool "Enhanced Virtual Addressing (EVA)"
+ depends on CPU_MIPS32_3_5_FEATURES
+ select EVA
+ default y
+ help
+ Choose this option if you want to enable the Enhanced Virtual
+ Addressing (EVA) on your MIPS32 core (such as proAptiv).
+ One of its primary benefits is an increase in the maximum size
+ of lowmem (up to 3GB). If unsure, say 'N' here.
+
if CPU_LOONGSON2F
config CPU_NOP_WORKAROUNDS
bool
@@ -1523,6 +1555,10 @@ config CPU_BMIPS5000
select SYS_SUPPORTS_SMP
select SYS_SUPPORTS_HOTPLUG_CPU
+config SYS_HAS_CPU_LOONGSON3
+ bool
+ select CPU_SUPPORTS_CPUFREQ
+
config SYS_HAS_CPU_LOONGSON2E
bool
@@ -1541,6 +1577,9 @@ config SYS_HAS_CPU_MIPS32_R1
config SYS_HAS_CPU_MIPS32_R2
bool
+config SYS_HAS_CPU_MIPS32_R3_5
+ bool
+
config SYS_HAS_CPU_MIPS64_R1
bool
@@ -1657,6 +1696,9 @@ config CPU_MIPSR2
bool
default y if CPU_MIPS32_R2 || CPU_MIPS64_R2 || CPU_CAVIUM_OCTEON
+config EVA
+ bool
+
config SYS_SUPPORTS_32BIT_KERNEL
bool
config SYS_SUPPORTS_64BIT_KERNEL
@@ -1729,7 +1771,7 @@ choice
config PAGE_SIZE_4KB
bool "4kB"
- depends on !CPU_LOONGSON2
+ depends on !CPU_LOONGSON2 && !CPU_LOONGSON3
help
This option select the standard 4kB Linux page size. On some
R3000-family processors this is the only available page size. Using
@@ -1776,12 +1818,12 @@ endchoice
config FORCE_MAX_ZONEORDER
int "Maximum zone order"
- range 14 64 if HUGETLB_PAGE && PAGE_SIZE_64KB
- default "14" if HUGETLB_PAGE && PAGE_SIZE_64KB
- range 13 64 if HUGETLB_PAGE && PAGE_SIZE_32KB
- default "13" if HUGETLB_PAGE && PAGE_SIZE_32KB
- range 12 64 if HUGETLB_PAGE && PAGE_SIZE_16KB
- default "12" if HUGETLB_PAGE && PAGE_SIZE_16KB
+ range 14 64 if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_64KB
+ default "14" if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_64KB
+ range 13 64 if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_32KB
+ default "13" if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_32KB
+ range 12 64 if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_16KB
+ default "12" if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_16KB
range 11 64
default "11"
help
@@ -1870,6 +1912,7 @@ config MIPS_MT_SMP
select CPU_MIPSR2_IRQ_VI
select CPU_MIPSR2_IRQ_EI
select SYNC_R4K
+ select MIPS_GIC_IPI
select MIPS_MT
select SMP
select SMP_UP
@@ -1887,6 +1930,7 @@ config MIPS_MT_SMTC
bool "Use all TCs on all VPEs for SMP (DEPRECATED)"
depends on CPU_MIPS32_R2
depends on SYS_SUPPORTS_MULTITHREADING
+ depends on !MIPS_CPS
select CPU_MIPSR2_IRQ_VI
select CPU_MIPSR2_IRQ_EI
select MIPS_MT
@@ -1994,13 +2038,45 @@ config MIPS_VPE_APSP_API_MT
depends on MIPS_VPE_APSP_API && !MIPS_CMP
config MIPS_CMP
- bool "MIPS CMP support"
- depends on SYS_SUPPORTS_MIPS_CMP && MIPS_MT_SMP
+ bool "MIPS CMP framework support (DEPRECATED)"
+ depends on SYS_SUPPORTS_MIPS_CMP && !MIPS_MT_SMTC
+ select MIPS_GIC_IPI
select SYNC_R4K
select WEAK_ORDERING
default n
help
- Enable Coherency Manager processor (CMP) support.
+ Select this if you are using a bootloader which implements the "CMP
+ framework" protocol (ie. YAMON) and want your kernel to make use of
+ its ability to start secondary CPUs.
+
+ Unless you have a specific need, you should use CONFIG_MIPS_CPS
+ instead of this.
+
+config MIPS_CPS
+ bool "MIPS Coherent Processing System support"
+ depends on SYS_SUPPORTS_MIPS_CPS
+ select MIPS_CM
+ select MIPS_CPC
+ select MIPS_GIC_IPI
+ select SMP
+ select SYNC_R4K if (CEVT_R4K || CSRC_R4K)
+ select SYS_SUPPORTS_SMP
+ select WEAK_ORDERING
+ help
+ Select this if you wish to run an SMP kernel across multiple cores
+ within a MIPS Coherent Processing System. When this option is
+ enabled the kernel will probe for other cores and boot them with
+ no external assistance. It is safe to enable this when hardware
+ support is unavailable.
+
+config MIPS_GIC_IPI
+ bool
+
+config MIPS_CM
+ bool
+
+config MIPS_CPC
+ bool
config SB1_PASS_1_WORKAROUNDS
bool
@@ -2043,6 +2119,21 @@ config CPU_MICROMIPS
When this option is enabled the kernel will be built using the
microMIPS ISA
+config CPU_HAS_MSA
+ bool "Support for the MIPS SIMD Architecture"
+ depends on CPU_SUPPORTS_MSA
+ default y
+ help
+ MIPS SIMD Architecture (MSA) introduces 128 bit wide vector registers
+ and a set of SIMD instructions to operate on them. When this option
+ is enabled the kernel will support allocating & switching MSA
+ vector register contexts. If you know that your kernel will only be
+ running on CPUs which do not support MSA or that your userland will
+ not be making use of it then you may wish to say N here to reduce
+ the size & complexity of your kernel.
+
+ If unsure, say Y.
+
config CPU_HAS_WB
bool
@@ -2094,7 +2185,7 @@ config CPU_R4400_WORKAROUNDS
#
config HIGHMEM
bool "High Memory Support"
- depends on 32BIT && CPU_SUPPORTS_HIGHMEM && SYS_SUPPORTS_HIGHMEM
+ depends on 32BIT && CPU_SUPPORTS_HIGHMEM && SYS_SUPPORTS_HIGHMEM && !CPU_MIPS32_3_5_EVA
config CPU_SUPPORTS_HIGHMEM
bool
@@ -2108,6 +2199,9 @@ config SYS_SUPPORTS_SMARTMIPS
config SYS_SUPPORTS_MICROMIPS
bool
+config CPU_SUPPORTS_MSA
+ bool
+
config ARCH_FLATMEM_ENABLE
def_bool y
depends on !NUMA && !CPU_LOONGSON2
@@ -2181,6 +2275,9 @@ config SMP_UP
config SYS_SUPPORTS_MIPS_CMP
bool
+config SYS_SUPPORTS_MIPS_CPS
+ bool
+
config SYS_SUPPORTS_SMP
bool
@@ -2353,9 +2450,8 @@ config SECCOMP
If unsure, say Y. Only embedded should say N here.
config MIPS_O32_FP64_SUPPORT
- bool "Support for O32 binaries using 64-bit FP"
+ bool "Support for O32 binaries using 64-bit FP (EXPERIMENTAL)"
depends on 32BIT || MIPS32_O32
- default y
help
When this is enabled, the kernel will support use of 64-bit floating
point registers with binaries using the O32 ABI along with the
@@ -2367,7 +2463,14 @@ config MIPS_O32_FP64_SUPPORT
of your kernel & potentially improve FP emulation performance by
saying N here.
- If unsure, say Y.
+ Although binutils currently supports use of this flag the details
+ concerning its effect upon the O32 ABI in userland are still being
+ worked on. In order to avoid userland becoming dependant upon current
+ behaviour before the details have been finalised, this option should
+ be considered experimental and only enabled by those working upon
+ said details.
+
+ If unsure, say N.
config USE_OF
bool
@@ -2407,6 +2510,17 @@ config PCI
your box. Other bus systems are ISA, EISA, or VESA. If you have PCI,
say Y, otherwise N.
+config HT_PCI
+ bool "Support for HT-linked PCI"
+ default y
+ depends on CPU_LOONGSON3
+ select PCI
+ select PCI_DOMAINS
+ help
+ Loongson family machines use Hyper-Transport bus for inter-core
+ connection and device connection. The PCI bus is a subordinate
+ linked at HT. Choose Y for Loongson-3 based machines.
+
config PCI_DOMAINS
bool
diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug
index b147e7038ff0..25de29211d76 100644
--- a/arch/mips/Kconfig.debug
+++ b/arch/mips/Kconfig.debug
@@ -21,13 +21,17 @@ config EARLY_PRINTK
unless you want to debug such a crash.
config EARLY_PRINTK_8250
- bool "8250/16550 and compatible serial early printk driver"
- depends on EARLY_PRINTK
- default n
+ bool
+ depends on EARLY_PRINTK && USE_GENERIC_EARLY_PRINTK_8250
+ default y
help
+ "8250/16550 and compatible serial early printk driver"
If you say Y here, it will be possible to use a 8250/16550 serial
port as the boot console.
+config USE_GENERIC_EARLY_PRINTK_8250
+ bool
+
config CMDLINE_BOOL
bool "Built-in kernel command line"
default n
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 9b8556de9993..1a5b4032cb66 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -119,6 +119,11 @@ cflags-$(CONFIG_CPU_MICROMIPS) += $(call cc-option,-mmicromips)
cflags-$(CONFIG_SB1XXX_CORELIS) += $(call cc-option,-mno-sched-prolog) \
-fno-omit-frame-pointer
+ifeq ($(CONFIG_CPU_HAS_MSA),y)
+toolchain-msa := $(call cc-option-yn,-mhard-float -mfp64 -mmsa)
+cflags-$(toolchain-msa) += -DTOOLCHAIN_SUPPORTS_MSA
+endif
+
#
# CPU-dependent compiler/assembler options for optimization.
#
diff --git a/arch/mips/alchemy/Kconfig b/arch/mips/alchemy/Kconfig
index 7032ac7ecd1b..b9628983d620 100644
--- a/arch/mips/alchemy/Kconfig
+++ b/arch/mips/alchemy/Kconfig
@@ -16,36 +16,29 @@ config ALCHEMY_GPIO_INDIRECT
choice
prompt "Machine type"
depends on MIPS_ALCHEMY
- default MIPS_DB1000
+ default MIPS_DB1XXX
config MIPS_MTX1
bool "4G Systems MTX-1 board"
- select DMA_NONCOHERENT
select HW_HAS_PCI
select ALCHEMY_GPIOINT_AU1000
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_HAS_EARLY_PRINTK
-config MIPS_DB1000
- bool "Alchemy DB1000/DB1500/DB1100 PB1500/1100 boards"
- select ALCHEMY_GPIOINT_AU1000
- select DMA_NONCOHERENT
- select HW_HAS_PCI
- select SYS_SUPPORTS_BIG_ENDIAN
- select SYS_SUPPORTS_LITTLE_ENDIAN
- select SYS_HAS_EARLY_PRINTK
-
-config MIPS_DB1235
- bool "Alchemy DB1200/PB1200/DB1300/DB1550/PB1550 boards"
+config MIPS_DB1XXX
+ bool "Alchemy DB1XXX / PB1XXX boards"
select ARCH_REQUIRE_GPIOLIB
select HW_HAS_PCI
- select DMA_COHERENT
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_HAS_EARLY_PRINTK
+ help
+ Select this option if you have one of the following Alchemy
+ development boards: DB1000 DB1500 DB1100 DB1550 DB1200 DB1300
+ PB1500 PB1100 PB1550 PB1200
+ Board type is autodetected during boot.
config MIPS_XXS1500
bool "MyCable XXS1500 board"
- select DMA_NONCOHERENT
select ALCHEMY_GPIOINT_AU1000
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_HAS_EARLY_PRINTK
@@ -54,7 +47,6 @@ config MIPS_GPR
bool "Trapeze ITS GPR board"
select ALCHEMY_GPIOINT_AU1000
select HW_HAS_PCI
- select DMA_NONCOHERENT
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_HAS_EARLY_PRINTK
diff --git a/arch/mips/alchemy/Platform b/arch/mips/alchemy/Platform
index b3afcdd8d77a..33c9da3b077b 100644
--- a/arch/mips/alchemy/Platform
+++ b/arch/mips/alchemy/Platform
@@ -5,18 +5,12 @@ platform-$(CONFIG_MIPS_ALCHEMY) += alchemy/common/
#
-# AMD Alchemy Db1000/Db1500/Pb1500/Db1100/Pb1100 eval boards
+# AMD Alchemy Db1000/Db1500/Pb1500/Db1100/Pb1100
+# Db1550/Pb1550/Db1200/Pb1200/Db1300
#
-platform-$(CONFIG_MIPS_DB1000) += alchemy/devboards/
-cflags-$(CONFIG_MIPS_DB1000) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_DB1000) += 0xffffffff80100000
-
-#
-# AMD Alchemy Db1200/Pb1200/Db1550/Pb1550/Db1300 eval boards
-#
-platform-$(CONFIG_MIPS_DB1235) += alchemy/devboards/
-cflags-$(CONFIG_MIPS_DB1235) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_DB1235) += 0xffffffff80100000
+platform-$(CONFIG_MIPS_DB1XXX) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_DB1XXX) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
+load-$(CONFIG_MIPS_DB1XXX) += 0xffffffff80100000
#
# 4G-Systems MTX-1 "MeshCube" wireless router
diff --git a/arch/mips/alchemy/board-gpr.c b/arch/mips/alchemy/board-gpr.c
index 9edc35ff8cf1..acf9a2a37f5a 100644
--- a/arch/mips/alchemy/board-gpr.c
+++ b/arch/mips/alchemy/board-gpr.c
@@ -53,10 +53,8 @@ void __init prom_init(void)
prom_init_cmdline();
memsize_str = prom_getenv("memsize");
- if (!memsize_str)
+ if (!memsize_str || kstrtoul(memsize_str, 0, &memsize))
memsize = 0x04000000;
- else
- strict_strtoul(memsize_str, 0, &memsize);
add_memory_region(0, memsize, BOOT_MEM_RAM);
}
diff --git a/arch/mips/alchemy/board-mtx1.c b/arch/mips/alchemy/board-mtx1.c
index 9969dbab19e3..25a59a23547e 100644
--- a/arch/mips/alchemy/board-mtx1.c
+++ b/arch/mips/alchemy/board-mtx1.c
@@ -52,10 +52,8 @@ void __init prom_init(void)
prom_init_cmdline();
memsize_str = prom_getenv("memsize");
- if (!memsize_str)
+ if (!memsize_str || kstrtoul(memsize_str, 0, &memsize))
memsize = 0x04000000;
- else
- strict_strtoul(memsize_str, 0, &memsize);
add_memory_region(0, memsize, BOOT_MEM_RAM);
}
diff --git a/arch/mips/alchemy/common/setup.c b/arch/mips/alchemy/common/setup.c
index 62b4e7bbeab9..566a1743f685 100644
--- a/arch/mips/alchemy/common/setup.c
+++ b/arch/mips/alchemy/common/setup.c
@@ -30,6 +30,7 @@
#include <linux/jiffies.h>
#include <linux/module.h>
+#include <asm/dma-coherence.h>
#include <asm/mipsregs.h>
#include <asm/time.h>
@@ -59,6 +60,15 @@ void __init plat_mem_setup(void)
/* Clear to obtain best system bus performance */
clear_c0_config(1 << 19); /* Clear Config[OD] */
+ hw_coherentio = 0;
+ coherentio = 1;
+ switch (alchemy_get_cputype()) {
+ case ALCHEMY_CPU_AU1000:
+ case ALCHEMY_CPU_AU1500:
+ case ALCHEMY_CPU_AU1100:
+ coherentio = 0;
+ }
+
board_setup(); /* board specific setup */
/* IO/MEM resources. */
diff --git a/arch/mips/alchemy/common/sleeper.S b/arch/mips/alchemy/common/sleeper.S
index 706d933e0085..c73d81270b42 100644
--- a/arch/mips/alchemy/common/sleeper.S
+++ b/arch/mips/alchemy/common/sleeper.S
@@ -95,7 +95,7 @@ LEAF(alchemy_sleep_au1000)
/* cache following instructions, as memory gets put to sleep */
la t0, 1f
- .set mips3
+ .set arch=r4000
cache 0x14, 0(t0)
cache 0x14, 32(t0)
cache 0x14, 64(t0)
@@ -121,7 +121,7 @@ LEAF(alchemy_sleep_au1550)
/* cache following instructions, as memory gets put to sleep */
la t0, 1f
- .set mips3
+ .set arch=r4000
cache 0x14, 0(t0)
cache 0x14, 32(t0)
cache 0x14, 64(t0)
@@ -163,7 +163,7 @@ LEAF(alchemy_sleep_au1300)
la t1, 4f
subu t2, t1, t0
- .set mips3
+ .set arch=r4000
1: cache 0x14, 0(t0)
subu t2, t2, 32
diff --git a/arch/mips/alchemy/devboards/Makefile b/arch/mips/alchemy/devboards/Makefile
index 15bf7306648b..9da3659a9d1c 100644
--- a/arch/mips/alchemy/devboards/Makefile
+++ b/arch/mips/alchemy/devboards/Makefile
@@ -2,7 +2,5 @@
# Alchemy Develboards
#
-obj-y += bcsr.o platform.o
+obj-y += bcsr.o platform.o db1000.o db1200.o db1300.o db1550.o db1xxx.o
obj-$(CONFIG_PM) += pm.o
-obj-$(CONFIG_MIPS_DB1000) += db1000.o
-obj-$(CONFIG_MIPS_DB1235) += db1235.o db1200.o db1300.o db1550.o
diff --git a/arch/mips/alchemy/devboards/db1000.c b/arch/mips/alchemy/devboards/db1000.c
index 5483906e0f86..92dd929d4057 100644
--- a/arch/mips/alchemy/devboards/db1000.c
+++ b/arch/mips/alchemy/devboards/db1000.c
@@ -41,42 +41,27 @@
#define F_SWAPPED (bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT)
-struct pci_dev;
+const char *get_system_type(void);
-static const char *board_type_str(void)
+int __init db1000_board_setup(void)
{
+ /* initialize board register space */
+ bcsr_init(DB1000_BCSR_PHYS_ADDR,
+ DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS);
+
switch (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI))) {
case BCSR_WHOAMI_DB1000:
- return "DB1000";
case BCSR_WHOAMI_DB1500:
- return "DB1500";
case BCSR_WHOAMI_DB1100:
- return "DB1100";
case BCSR_WHOAMI_PB1500:
case BCSR_WHOAMI_PB1500R2:
- return "PB1500";
case BCSR_WHOAMI_PB1100:
- return "PB1100";
- default:
- return "(unknown)";
+ pr_info("AMD Alchemy %s Board\n", get_system_type());
+ return 0;
}
+ return -ENODEV;
}
-const char *get_system_type(void)
-{
- return board_type_str();
-}
-
-void __init board_setup(void)
-{
- /* initialize board register space */
- bcsr_init(DB1000_BCSR_PHYS_ADDR,
- DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS);
-
- printk(KERN_INFO "AMD Alchemy %s Board\n", board_type_str());
-}
-
-
static int db1500_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin)
{
if ((slot < 12) || (slot > 13) || pin == 0)
@@ -114,17 +99,10 @@ static struct platform_device db1500_pci_host_dev = {
.resource = alchemy_pci_host_res,
};
-static int __init db1500_pci_init(void)
+int __init db1500_pci_setup(void)
{
- int id = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
- if ((id == BCSR_WHOAMI_DB1500) || (id == BCSR_WHOAMI_PB1500) ||
- (id == BCSR_WHOAMI_PB1500R2))
- return platform_device_register(&db1500_pci_host_dev);
- return 0;
+ return platform_device_register(&db1500_pci_host_dev);
}
-/* must be arch_initcall; MIPS PCI scans busses in a subsys_initcall */
-arch_initcall(db1500_pci_init);
-
static struct resource au1100_lcd_resources[] = {
[0] = {
@@ -513,7 +491,7 @@ static struct platform_device *db1100_devs[] = {
&db1000_irda_dev,
};
-static int __init db1000_dev_init(void)
+int __init db1000_dev_setup(void)
{
int board = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
int c0, c1, d0, d1, s0, s1, flashsize = 32, twosocks = 1;
@@ -623,4 +601,3 @@ static int __init db1000_dev_init(void)
db1x_register_norflash(flashsize << 20, 4 /* 32bit */, F_SWAPPED);
return 0;
}
-device_initcall(db1000_dev_init);
diff --git a/arch/mips/alchemy/devboards/db1200.c b/arch/mips/alchemy/devboards/db1200.c
index a84d98b8f96e..9e46667f2597 100644
--- a/arch/mips/alchemy/devboards/db1200.c
+++ b/arch/mips/alchemy/devboards/db1200.c
@@ -35,16 +35,63 @@
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
#include <linux/smc91x.h>
+#include <linux/ata_platform.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1100_mmc.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
+#include <asm/mach-au1x00/au1xxx_psc.h>
#include <asm/mach-au1x00/au1200fb.h>
#include <asm/mach-au1x00/au1550_spi.h>
#include <asm/mach-db1x00/bcsr.h>
-#include <asm/mach-db1x00/db1200.h>
#include "platform.h"
+#define BCSR_INT_IDE 0x0001
+#define BCSR_INT_ETH 0x0002
+#define BCSR_INT_PC0 0x0004
+#define BCSR_INT_PC0STSCHG 0x0008
+#define BCSR_INT_PC1 0x0010
+#define BCSR_INT_PC1STSCHG 0x0020
+#define BCSR_INT_DC 0x0040
+#define BCSR_INT_FLASHBUSY 0x0080
+#define BCSR_INT_PC0INSERT 0x0100
+#define BCSR_INT_PC0EJECT 0x0200
+#define BCSR_INT_PC1INSERT 0x0400
+#define BCSR_INT_PC1EJECT 0x0800
+#define BCSR_INT_SD0INSERT 0x1000
+#define BCSR_INT_SD0EJECT 0x2000
+#define BCSR_INT_SD1INSERT 0x4000
+#define BCSR_INT_SD1EJECT 0x8000
+
+#define DB1200_IDE_PHYS_ADDR 0x18800000
+#define DB1200_IDE_REG_SHIFT 5
+#define DB1200_IDE_PHYS_LEN (16 << DB1200_IDE_REG_SHIFT)
+#define DB1200_ETH_PHYS_ADDR 0x19000300
+#define DB1200_NAND_PHYS_ADDR 0x20000000
+
+#define PB1200_IDE_PHYS_ADDR 0x0C800000
+#define PB1200_ETH_PHYS_ADDR 0x0D000300
+#define PB1200_NAND_PHYS_ADDR 0x1C000000
+
+#define DB1200_INT_BEGIN (AU1000_MAX_INTR + 1)
+#define DB1200_IDE_INT (DB1200_INT_BEGIN + 0)
+#define DB1200_ETH_INT (DB1200_INT_BEGIN + 1)
+#define DB1200_PC0_INT (DB1200_INT_BEGIN + 2)
+#define DB1200_PC0_STSCHG_INT (DB1200_INT_BEGIN + 3)
+#define DB1200_PC1_INT (DB1200_INT_BEGIN + 4)
+#define DB1200_PC1_STSCHG_INT (DB1200_INT_BEGIN + 5)
+#define DB1200_DC_INT (DB1200_INT_BEGIN + 6)
+#define DB1200_FLASHBUSY_INT (DB1200_INT_BEGIN + 7)
+#define DB1200_PC0_INSERT_INT (DB1200_INT_BEGIN + 8)
+#define DB1200_PC0_EJECT_INT (DB1200_INT_BEGIN + 9)
+#define DB1200_PC1_INSERT_INT (DB1200_INT_BEGIN + 10)
+#define DB1200_PC1_EJECT_INT (DB1200_INT_BEGIN + 11)
+#define DB1200_SD0_INSERT_INT (DB1200_INT_BEGIN + 12)
+#define DB1200_SD0_EJECT_INT (DB1200_INT_BEGIN + 13)
+#define PB1200_SD1_INSERT_INT (DB1200_INT_BEGIN + 14)
+#define PB1200_SD1_EJECT_INT (DB1200_INT_BEGIN + 15)
+#define DB1200_INT_END (DB1200_INT_BEGIN + 15)
+
const char *get_system_type(void);
static int __init db1200_detect_board(void)
@@ -89,6 +136,15 @@ int __init db1200_board_setup(void)
return -ENODEV;
whoami = bcsr_read(BCSR_WHOAMI);
+ switch (BCSR_WHOAMI_BOARD(whoami)) {
+ case BCSR_WHOAMI_PB1200_DDR1:
+ case BCSR_WHOAMI_PB1200_DDR2:
+ case BCSR_WHOAMI_DB1200:
+ break;
+ default:
+ return -ENODEV;
+ }
+
printk(KERN_INFO "Alchemy/AMD/RMI %s Board, CPLD Rev %d"
" Board-ID %d Daughtercard ID %d\n", get_system_type(),
(whoami >> 4) & 0xf, (whoami >> 8) & 0xf, whoami & 0xf);
@@ -275,32 +331,38 @@ static struct platform_device db1200_eth_dev = {
/**********************************************************************/
+static struct pata_platform_info db1200_ide_info = {
+ .ioport_shift = DB1200_IDE_REG_SHIFT,
+};
+
+#define IDE_ALT_START (14 << DB1200_IDE_REG_SHIFT)
static struct resource db1200_ide_res[] = {
[0] = {
.start = DB1200_IDE_PHYS_ADDR,
- .end = DB1200_IDE_PHYS_ADDR + DB1200_IDE_PHYS_LEN - 1,
+ .end = DB1200_IDE_PHYS_ADDR + IDE_ALT_START - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
+ .start = DB1200_IDE_PHYS_ADDR + IDE_ALT_START,
+ .end = DB1200_IDE_PHYS_ADDR + DB1200_IDE_PHYS_LEN - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
.start = DB1200_IDE_INT,
.end = DB1200_IDE_INT,
.flags = IORESOURCE_IRQ,
},
- [2] = {
- .start = AU1200_DSCR_CMD0_DMA_REQ1,
- .end = AU1200_DSCR_CMD0_DMA_REQ1,
- .flags = IORESOURCE_DMA,
- },
};
static u64 au1200_ide_dmamask = DMA_BIT_MASK(32);
static struct platform_device db1200_ide_dev = {
- .name = "au1200-ide",
+ .name = "pata_platform",
.id = 0,
.dev = {
.dma_mask = &au1200_ide_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &db1200_ide_info,
},
.num_resources = ARRAY_SIZE(db1200_ide_res),
.resource = db1200_ide_res,
diff --git a/arch/mips/alchemy/devboards/db1300.c b/arch/mips/alchemy/devboards/db1300.c
index 6167e73eef9c..1aed6be4de10 100644
--- a/arch/mips/alchemy/devboards/db1300.c
+++ b/arch/mips/alchemy/devboards/db1300.c
@@ -26,12 +26,44 @@
#include <asm/mach-au1x00/au1200fb.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
#include <asm/mach-au1x00/au1xxx_psc.h>
-#include <asm/mach-db1x00/db1300.h>
#include <asm/mach-db1x00/bcsr.h>
#include <asm/mach-au1x00/prom.h>
#include "platform.h"
+/* FPGA (external mux) interrupt sources */
+#define DB1300_FIRST_INT (ALCHEMY_GPIC_INT_LAST + 1)
+#define DB1300_IDE_INT (DB1300_FIRST_INT + 0)
+#define DB1300_ETH_INT (DB1300_FIRST_INT + 1)
+#define DB1300_CF_INT (DB1300_FIRST_INT + 2)
+#define DB1300_VIDEO_INT (DB1300_FIRST_INT + 4)
+#define DB1300_HDMI_INT (DB1300_FIRST_INT + 5)
+#define DB1300_DC_INT (DB1300_FIRST_INT + 6)
+#define DB1300_FLASH_INT (DB1300_FIRST_INT + 7)
+#define DB1300_CF_INSERT_INT (DB1300_FIRST_INT + 8)
+#define DB1300_CF_EJECT_INT (DB1300_FIRST_INT + 9)
+#define DB1300_AC97_INT (DB1300_FIRST_INT + 10)
+#define DB1300_AC97_PEN_INT (DB1300_FIRST_INT + 11)
+#define DB1300_SD1_INSERT_INT (DB1300_FIRST_INT + 12)
+#define DB1300_SD1_EJECT_INT (DB1300_FIRST_INT + 13)
+#define DB1300_OTG_VBUS_OC_INT (DB1300_FIRST_INT + 14)
+#define DB1300_HOST_VBUS_OC_INT (DB1300_FIRST_INT + 15)
+#define DB1300_LAST_INT (DB1300_FIRST_INT + 15)
+
+/* SMSC9210 CS */
+#define DB1300_ETH_PHYS_ADDR 0x19000000
+#define DB1300_ETH_PHYS_END 0x197fffff
+
+/* ATA CS */
+#define DB1300_IDE_PHYS_ADDR 0x18800000
+#define DB1300_IDE_REG_SHIFT 5
+#define DB1300_IDE_PHYS_LEN (16 << DB1300_IDE_REG_SHIFT)
+
+/* NAND CS */
+#define DB1300_NAND_PHYS_ADDR 0x20000000
+#define DB1300_NAND_PHYS_END 0x20000fff
+
+
static struct i2c_board_info db1300_i2c_devs[] __initdata = {
{ I2C_BOARD_INFO("wm8731", 0x1b), }, /* I2S audio codec */
{ I2C_BOARD_INFO("ne1619", 0x2d), }, /* adm1025-compat hwmon */
@@ -759,11 +791,15 @@ int __init db1300_board_setup(void)
{
unsigned short whoami;
- db1300_gpio_config();
bcsr_init(DB1300_BCSR_PHYS_ADDR,
DB1300_BCSR_PHYS_ADDR + DB1300_BCSR_HEXLED_OFS);
whoami = bcsr_read(BCSR_WHOAMI);
+ if (BCSR_WHOAMI_BOARD(whoami) != BCSR_WHOAMI_DB1300)
+ return -ENODEV;
+
+ db1300_gpio_config();
+
printk(KERN_INFO "NetLogic DBAu1300 Development Platform.\n\t"
"BoardID %d CPLD Rev %d DaughtercardID %d\n",
BCSR_WHOAMI_BOARD(whoami), BCSR_WHOAMI_CPLD(whoami),
diff --git a/arch/mips/alchemy/devboards/db1550.c b/arch/mips/alchemy/devboards/db1550.c
index 016cddacd7ea..bbd8d9884702 100644
--- a/arch/mips/alchemy/devboards/db1550.c
+++ b/arch/mips/alchemy/devboards/db1550.c
@@ -62,10 +62,16 @@ int __init db1550_board_setup(void)
DB1550_BCSR_PHYS_ADDR + DB1550_BCSR_HEXLED_OFS);
whoami = bcsr_read(BCSR_WHOAMI); /* PB1550 hexled offset differs */
- if ((BCSR_WHOAMI_BOARD(whoami) == BCSR_WHOAMI_PB1550_SDR) ||
- (BCSR_WHOAMI_BOARD(whoami) == BCSR_WHOAMI_PB1550_DDR))
+ switch (BCSR_WHOAMI_BOARD(whoami)) {
+ case BCSR_WHOAMI_PB1550_SDR:
+ case BCSR_WHOAMI_PB1550_DDR:
bcsr_init(PB1550_BCSR_PHYS_ADDR,
PB1550_BCSR_PHYS_ADDR + PB1550_BCSR_HEXLED_OFS);
+ case BCSR_WHOAMI_DB1550:
+ break;
+ default:
+ return -ENODEV;
+ }
pr_info("Alchemy/AMD %s Board, CPLD Rev %d Board-ID %d " \
"Daughtercard ID %d\n", get_system_type(),
diff --git a/arch/mips/alchemy/devboards/db1235.c b/arch/mips/alchemy/devboards/db1xxx.c
index bac19dc43d1d..2d47f951121a 100644
--- a/arch/mips/alchemy/devboards/db1235.c
+++ b/arch/mips/alchemy/devboards/db1xxx.c
@@ -1,12 +1,13 @@
/*
- * DB1200/PB1200 / DB1550 / DB1300 board support.
- *
- * These 4 boards can reliably be supported in a single kernel image.
+ * Alchemy DB/PB1xxx board support.
*/
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-db1x00/bcsr.h>
+int __init db1000_board_setup(void);
+int __init db1000_dev_setup(void);
+int __init db1500_pci_setup(void);
int __init db1200_board_setup(void);
int __init db1200_dev_setup(void);
int __init db1300_board_setup(void);
@@ -18,6 +19,17 @@ int __init db1550_pci_setup(int);
static const char *board_type_str(void)
{
switch (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI))) {
+ case BCSR_WHOAMI_DB1000:
+ return "DB1000";
+ case BCSR_WHOAMI_DB1500:
+ return "DB1500";
+ case BCSR_WHOAMI_DB1100:
+ return "DB1100";
+ case BCSR_WHOAMI_PB1500:
+ case BCSR_WHOAMI_PB1500R2:
+ return "PB1500";
+ case BCSR_WHOAMI_PB1100:
+ return "PB1100";
case BCSR_WHOAMI_PB1200_DDR1:
case BCSR_WHOAMI_PB1200_DDR2:
return "PB1200";
@@ -45,6 +57,11 @@ void __init board_setup(void)
int ret;
switch (alchemy_get_cputype()) {
+ case ALCHEMY_CPU_AU1000:
+ case ALCHEMY_CPU_AU1500:
+ case ALCHEMY_CPU_AU1100:
+ ret = db1000_board_setup();
+ break;
case ALCHEMY_CPU_AU1550:
ret = db1550_board_setup();
break;
@@ -62,7 +79,7 @@ void __init board_setup(void)
panic("cannot initialize board support");
}
-int __init db1235_arch_init(void)
+static int __init db1xxx_arch_init(void)
{
int id = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
if (id == BCSR_WHOAMI_DB1550)
@@ -70,14 +87,24 @@ int __init db1235_arch_init(void)
else if ((id == BCSR_WHOAMI_PB1550_SDR) ||
(id == BCSR_WHOAMI_PB1550_DDR))
return db1550_pci_setup(1);
+ else if ((id == BCSR_WHOAMI_DB1500) || (id == BCSR_WHOAMI_PB1500) ||
+ (id == BCSR_WHOAMI_PB1500R2))
+ return db1500_pci_setup();
return 0;
}
-arch_initcall(db1235_arch_init);
+arch_initcall(db1xxx_arch_init);
-int __init db1235_dev_init(void)
+static int __init db1xxx_dev_init(void)
{
switch (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI))) {
+ case BCSR_WHOAMI_DB1000:
+ case BCSR_WHOAMI_DB1500:
+ case BCSR_WHOAMI_DB1100:
+ case BCSR_WHOAMI_PB1500:
+ case BCSR_WHOAMI_PB1500R2:
+ case BCSR_WHOAMI_PB1100:
+ return db1000_dev_setup();
case BCSR_WHOAMI_PB1200_DDR1:
case BCSR_WHOAMI_PB1200_DDR2:
case BCSR_WHOAMI_DB1200:
@@ -91,4 +118,4 @@ int __init db1235_dev_init(void)
}
return 0;
}
-device_initcall(db1235_dev_init);
+device_initcall(db1xxx_dev_init);
diff --git a/arch/mips/ar7/time.c b/arch/mips/ar7/time.c
index 1dc6c3b37f91..22c93213b233 100644
--- a/arch/mips/ar7/time.c
+++ b/arch/mips/ar7/time.c
@@ -18,6 +18,7 @@
* Setting up the clock on the MIPS boards.
*/
+#include <linux/init.h>
#include <linux/time.h>
#include <linux/err.h>
#include <linux/clk.h>
diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig
index 3995e31a73e2..dfc60209dc63 100644
--- a/arch/mips/ath79/Kconfig
+++ b/arch/mips/ath79/Kconfig
@@ -74,34 +74,26 @@ config ATH79_MACH_UBNT_XM
endmenu
config SOC_AR71XX
- select USB_ARCH_HAS_EHCI
- select USB_ARCH_HAS_OHCI
select HW_HAS_PCI
def_bool n
config SOC_AR724X
- select USB_ARCH_HAS_EHCI
- select USB_ARCH_HAS_OHCI
select HW_HAS_PCI
select PCI_AR724X if PCI
def_bool n
config SOC_AR913X
- select USB_ARCH_HAS_EHCI
def_bool n
config SOC_AR933X
- select USB_ARCH_HAS_EHCI
def_bool n
config SOC_AR934X
- select USB_ARCH_HAS_EHCI
select HW_HAS_PCI
select PCI_AR724X if PCI
def_bool n
config SOC_QCA955X
- select USB_ARCH_HAS_EHCI
select HW_HAS_PCI
select PCI_AR724X if PCI
def_bool n
diff --git a/arch/mips/bcm47xx/Makefile b/arch/mips/bcm47xx/Makefile
index 4688b6a6211b..d58c51b5e501 100644
--- a/arch/mips/bcm47xx/Makefile
+++ b/arch/mips/bcm47xx/Makefile
@@ -4,4 +4,4 @@
#
obj-y += irq.o nvram.o prom.o serial.o setup.o time.o sprom.o
-obj-y += board.o buttons.o leds.o
+obj-y += board.o buttons.o leds.o workarounds.o
diff --git a/arch/mips/bcm47xx/bcm47xx_private.h b/arch/mips/bcm47xx/bcm47xx_private.h
index 5c94acebf76a..0194c3b9a729 100644
--- a/arch/mips/bcm47xx/bcm47xx_private.h
+++ b/arch/mips/bcm47xx/bcm47xx_private.h
@@ -9,4 +9,7 @@ int __init bcm47xx_buttons_register(void);
/* leds.c */
void __init bcm47xx_leds_register(void);
+/* workarounds.c */
+void __init bcm47xx_workarounds(void);
+
#endif
diff --git a/arch/mips/bcm47xx/board.c b/arch/mips/bcm47xx/board.c
index 6d612e2b949b..44ab1be68c3c 100644
--- a/arch/mips/bcm47xx/board.c
+++ b/arch/mips/bcm47xx/board.c
@@ -1,3 +1,4 @@
+#include <linux/errno.h>
#include <linux/export.h>
#include <linux/string.h>
#include <bcm47xx_board.h>
@@ -71,7 +72,11 @@ struct bcm47xx_board_type_list1 bcm47xx_board_list_hardware_version[] __initcons
{{BCM47XX_BOARD_ASUS_WL500W, "Asus WL500W"}, "WL500gW-"},
{{BCM47XX_BOARD_ASUS_WL520GC, "Asus WL520GC"}, "WL520GC-"},
{{BCM47XX_BOARD_ASUS_WL520GU, "Asus WL520GU"}, "WL520GU-"},
+ {{BCM47XX_BOARD_BELKIN_F7D3301, "Belkin F7D3301"}, "F7D3301"},
+ {{BCM47XX_BOARD_BELKIN_F7D3302, "Belkin F7D3302"}, "F7D3302"},
{{BCM47XX_BOARD_BELKIN_F7D4301, "Belkin F7D4301"}, "F7D4301"},
+ {{BCM47XX_BOARD_BELKIN_F7D4302, "Belkin F7D4302"}, "F7D4302"},
+ {{BCM47XX_BOARD_BELKIN_F7D4401, "Belkin F7D4401"}, "F7D4401"},
{ {0}, NULL},
};
@@ -175,7 +180,16 @@ struct bcm47xx_board_type_list3 bcm47xx_board_list_board[] __initconst = {
{{BCM47XX_BOARD_PHICOMM_M1, "Phicomm M1"}, "0x0590", "80", "0x1104"},
{{BCM47XX_BOARD_ZTE_H218N, "ZTE H218N"}, "0x053d", "1234", "0x1305"},
{{BCM47XX_BOARD_NETGEAR_WNR3500L, "Netgear WNR3500L"}, "0x04CF", "3500", "02"},
- {{BCM47XX_BOARD_LINKSYS_WRT54GSV1, "Linksys WRT54GS V1"}, "0x0101", "42", "0x10"},
+ {{BCM47XX_BOARD_LINKSYS_WRT54G, "Linksys WRT54G/GS/GL"}, "0x0101", "42", "0x10"},
+ {{BCM47XX_BOARD_LINKSYS_WRT54G, "Linksys WRT54G/GS/GL"}, "0x0467", "42", "0x10"},
+ {{BCM47XX_BOARD_LINKSYS_WRT54G, "Linksys WRT54G/GS/GL"}, "0x0708", "42", "0x10"},
+ { {0}, NULL},
+};
+
+/* boardtype, boardrev */
+static const
+struct bcm47xx_board_type_list2 bcm47xx_board_list_board_type_rev[] __initconst = {
+ {{BCM47XX_BOARD_SIEMENS_SE505V2, "Siemens SE505 V2"}, "0x0101", "0x10"},
{ {0}, NULL},
};
@@ -272,6 +286,16 @@ static __init const struct bcm47xx_board_type *bcm47xx_board_get_nvram(void)
return &e3->board;
}
}
+
+ if (bcm47xx_nvram_getenv("boardtype", buf1, sizeof(buf1)) >= 0 &&
+ bcm47xx_nvram_getenv("boardrev", buf2, sizeof(buf2)) >= 0 &&
+ bcm47xx_nvram_getenv("boardnum", buf3, sizeof(buf3)) == -ENOENT) {
+ for (e2 = bcm47xx_board_list_board_type_rev; e2->value1; e2++) {
+ if (!strcmp(buf1, e2->value1) &&
+ !strcmp(buf2, e2->value2))
+ return &e2->board;
+ }
+ }
return bcm47xx_board_unknown;
}
diff --git a/arch/mips/bcm47xx/buttons.c b/arch/mips/bcm47xx/buttons.c
index 872c62e93e0e..49a1ce06844b 100644
--- a/arch/mips/bcm47xx/buttons.c
+++ b/arch/mips/bcm47xx/buttons.c
@@ -259,6 +259,18 @@ bcm47xx_buttons_linksys_wrt310nv1[] __initconst = {
};
static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt54g3gv2[] __initconst = {
+ BCM47XX_GPIO_KEY(5, KEY_WIMAX),
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt54gsv1[] __initconst = {
+ BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
bcm47xx_buttons_linksys_wrt610nv1[] __initconst = {
BCM47XX_GPIO_KEY(6, KEY_RESTART),
BCM47XX_GPIO_KEY(8, KEY_WPS_BUTTON),
@@ -270,6 +282,12 @@ bcm47xx_buttons_linksys_wrt610nv2[] __initconst = {
BCM47XX_GPIO_KEY(6, KEY_RESTART),
};
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrtsl54gs[] __initconst = {
+ BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
/* Motorola */
static const struct gpio_keys_button
@@ -402,7 +420,11 @@ int __init bcm47xx_buttons_register(void)
err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wlhdd);
break;
+ case BCM47XX_BOARD_BELKIN_F7D3301:
+ case BCM47XX_BOARD_BELKIN_F7D3302:
case BCM47XX_BOARD_BELKIN_F7D4301:
+ case BCM47XX_BOARD_BELKIN_F7D4302:
+ case BCM47XX_BOARD_BELKIN_F7D4401:
err = bcm47xx_copy_bdata(bcm47xx_buttons_belkin_f7d4301);
break;
@@ -479,12 +501,21 @@ int __init bcm47xx_buttons_register(void)
case BCM47XX_BOARD_LINKSYS_WRT310NV1:
err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt310nv1);
break;
+ case BCM47XX_BOARD_LINKSYS_WRT54G:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt54gsv1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT54G3GV2:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt54g3gv2);
+ break;
case BCM47XX_BOARD_LINKSYS_WRT610NV1:
err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt610nv1);
break;
case BCM47XX_BOARD_LINKSYS_WRT610NV2:
err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt610nv2);
break;
+ case BCM47XX_BOARD_LINKSYS_WRTSL54GS:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrtsl54gs);
+ break;
case BCM47XX_BOARD_MOTOROLA_WE800G:
err = bcm47xx_copy_bdata(bcm47xx_buttons_motorola_we800g);
diff --git a/arch/mips/bcm47xx/leds.c b/arch/mips/bcm47xx/leds.c
index 647d15527066..adcb547a91c3 100644
--- a/arch/mips/bcm47xx/leds.c
+++ b/arch/mips/bcm47xx/leds.c
@@ -292,6 +292,21 @@ bcm47xx_leds_linksys_wrt310nv1[] __initconst = {
};
static const struct gpio_led
+bcm47xx_leds_linksys_wrt54gsv1[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "dmz", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(5, "white", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(7, "orange", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrt54g3gv2[] __initconst = {
+ BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(2, "green", "3g", 0, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(3, "blue", "3g", 0, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
bcm47xx_leds_linksys_wrt610nv1[] __initconst = {
BCM47XX_GPIO_LED(0, "unk", "usb", 1, LEDS_GPIO_DEFSTATE_OFF),
BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_OFF),
@@ -308,6 +323,15 @@ bcm47xx_leds_linksys_wrt610nv2[] __initconst = {
BCM47XX_GPIO_LED(7, "unk", "usb", 0, LEDS_GPIO_DEFSTATE_OFF),
};
+static const struct gpio_led
+bcm47xx_leds_linksys_wrtsl54gs[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(2, "white", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(3, "orange", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(7, "unk", "dmz", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
/* Motorola */
static const struct gpio_led
@@ -359,6 +383,14 @@ bcm47xx_leds_netgear_wnr834bv2[] __initconst = {
BCM47XX_GPIO_LED(7, "unk", "connected", 0, LEDS_GPIO_DEFSTATE_OFF),
};
+/* Siemens */
+static const struct gpio_led
+bcm47xx_leds_siemens_se505v2[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "dmz", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(3, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(5, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+};
+
/* SimpleTech */
static const struct gpio_led
@@ -425,7 +457,11 @@ void __init bcm47xx_leds_register(void)
bcm47xx_set_pdata(bcm47xx_leds_asus_wlhdd);
break;
+ case BCM47XX_BOARD_BELKIN_F7D3301:
+ case BCM47XX_BOARD_BELKIN_F7D3302:
case BCM47XX_BOARD_BELKIN_F7D4301:
+ case BCM47XX_BOARD_BELKIN_F7D4302:
+ case BCM47XX_BOARD_BELKIN_F7D4401:
bcm47xx_set_pdata(bcm47xx_leds_belkin_f7d4301);
break;
@@ -502,12 +538,21 @@ void __init bcm47xx_leds_register(void)
case BCM47XX_BOARD_LINKSYS_WRT310NV1:
bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt310nv1);
break;
+ case BCM47XX_BOARD_LINKSYS_WRT54G:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt54gsv1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT54G3GV2:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt54g3gv2);
+ break;
case BCM47XX_BOARD_LINKSYS_WRT610NV1:
bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt610nv1);
break;
case BCM47XX_BOARD_LINKSYS_WRT610NV2:
bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt610nv2);
break;
+ case BCM47XX_BOARD_LINKSYS_WRTSL54GS:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_wrtsl54gs);
+ break;
case BCM47XX_BOARD_MOTOROLA_WE800G:
bcm47xx_set_pdata(bcm47xx_leds_motorola_we800g);
@@ -529,6 +574,10 @@ void __init bcm47xx_leds_register(void)
bcm47xx_set_pdata(bcm47xx_leds_netgear_wnr834bv2);
break;
+ case BCM47XX_BOARD_SIEMENS_SE505V2:
+ bcm47xx_set_pdata(bcm47xx_leds_siemens_se505v2);
+ break;
+
case BCM47XX_BOARD_SIMPLETECH_SIMPLESHARE:
bcm47xx_set_pdata(bcm47xx_leds_simpletech_simpleshare);
break;
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index 6decb27cf48b..2bed73a684ae 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -196,7 +196,7 @@ int bcm47xx_nvram_gpio_pin(const char *name)
char nvram_var[10];
char buf[30];
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < 32; i++) {
err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
if (err <= 0)
continue;
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index 025be218ea15..63a4b0e915dc 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -212,7 +212,7 @@ void __init plat_mem_setup(void)
{
struct cpuinfo_mips *c = &current_cpu_data;
- if (c->cputype == CPU_74K) {
+ if ((c->cputype == CPU_74K) || (c->cputype == CPU_1074K)) {
printk(KERN_INFO "bcm47xx: using bcma bus\n");
#ifdef CONFIG_BCM47XX_BCMA
bcm47xx_bus_type = BCM47XX_BUS_TYPE_BCMA;
@@ -282,6 +282,7 @@ static int __init bcm47xx_register_bus_complete(void)
}
bcm47xx_buttons_register();
bcm47xx_leds_register();
+ bcm47xx_workarounds();
fixed_phy_add(PHY_POLL, 0, &bcm47xx_fixed_phy_status);
return 0;
diff --git a/arch/mips/bcm47xx/workarounds.c b/arch/mips/bcm47xx/workarounds.c
new file mode 100644
index 000000000000..e81ce4623070
--- /dev/null
+++ b/arch/mips/bcm47xx/workarounds.c
@@ -0,0 +1,31 @@
+#include "bcm47xx_private.h"
+
+#include <linux/gpio.h>
+#include <bcm47xx_board.h>
+#include <bcm47xx.h>
+
+static void __init bcm47xx_workarounds_netgear_wnr3500l(void)
+{
+ const int usb_power = 12;
+ int err;
+
+ err = gpio_request_one(usb_power, GPIOF_OUT_INIT_HIGH, "usb_power");
+ if (err)
+ pr_err("Failed to request USB power gpio: %d\n", err);
+ else
+ gpio_free(usb_power);
+}
+
+void __init bcm47xx_workarounds(void)
+{
+ enum bcm47xx_board board = bcm47xx_board_get();
+
+ switch (board) {
+ case BCM47XX_BOARD_NETGEAR_WNR3500L:
+ bcm47xx_workarounds_netgear_wnr3500l();
+ break;
+ default:
+ /* No workaround(s) needed */
+ break;
+ }
+}
diff --git a/arch/mips/bcm63xx/cpu.c b/arch/mips/bcm63xx/cpu.c
index 1b1b8a89959b..fd4e76c00a42 100644
--- a/arch/mips/bcm63xx/cpu.c
+++ b/arch/mips/bcm63xx/cpu.c
@@ -299,14 +299,13 @@ static unsigned int detect_memory_size(void)
void __init bcm63xx_cpu_init(void)
{
unsigned int tmp;
- struct cpuinfo_mips *c = &current_cpu_data;
unsigned int cpu = smp_processor_id();
u32 chipid_reg;
/* soc registers location depends on cpu type */
chipid_reg = 0;
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_BMIPS3300:
if ((read_c0_prid() & PRID_IMP_MASK) != PRID_IMP_BMIPS3300_ALT)
__cpu_name[cpu] = "Broadcom BCM6338";
diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c
index 25fbfae06c1f..c2bb4f896ce7 100644
--- a/arch/mips/cavium-octeon/octeon-irq.c
+++ b/arch/mips/cavium-octeon/octeon-irq.c
@@ -975,10 +975,6 @@ static int octeon_irq_ciu_xlat(struct irq_domain *d,
if (ciu > 1 || bit > 63)
return -EINVAL;
- /* These are the GPIO lines */
- if (ciu == 0 && bit >= 16 && bit < 32)
- return -EINVAL;
-
*out_hwirq = (ciu << 6) | bit;
*out_type = 0;
@@ -1007,6 +1003,10 @@ static int octeon_irq_ciu_map(struct irq_domain *d,
if (!octeon_irq_virq_in_range(virq))
return -EINVAL;
+ /* Don't map irq if it is reserved for GPIO. */
+ if (line == 0 && bit >= 16 && bit <32)
+ return 0;
+
if (line > 1 || octeon_irq_ciu_to_irq[line][bit] != 0)
return -EINVAL;
@@ -1525,10 +1525,6 @@ static int octeon_irq_ciu2_xlat(struct irq_domain *d,
ciu = intspec[0];
bit = intspec[1];
- /* Line 7 are the GPIO lines */
- if (ciu > 6 || bit > 63)
- return -EINVAL;
-
*out_hwirq = (ciu << 6) | bit;
*out_type = 0;
@@ -1570,8 +1566,14 @@ static int octeon_irq_ciu2_map(struct irq_domain *d,
if (!octeon_irq_virq_in_range(virq))
return -EINVAL;
- /* Line 7 are the GPIO lines */
- if (line > 6 || octeon_irq_ciu_to_irq[line][bit] != 0)
+ /*
+ * Don't map irq if it is reserved for GPIO.
+ * (Line 7 are the GPIO lines.)
+ */
+ if (line == 7)
+ return 0;
+
+ if (line > 7 || octeon_irq_ciu_to_irq[line][bit] != 0)
return -EINVAL;
if (octeon_irq_ciu2_is_edge(line, bit))
diff --git a/arch/mips/configs/db1000_defconfig b/arch/mips/configs/db1000_defconfig
deleted file mode 100644
index bac26b971c5e..000000000000
--- a/arch/mips/configs/db1000_defconfig
+++ /dev/null
@@ -1,359 +0,0 @@
-CONFIG_MIPS=y
-CONFIG_MIPS_ALCHEMY=y
-CONFIG_MIPS_DB1000=y
-CONFIG_SCHED_OMIT_FRAME_POINTER=y
-CONFIG_TICK_ONESHOT=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_HZ_100=y
-CONFIG_HZ=100
-CONFIG_PREEMPT_NONE=y
-CONFIG_EXPERIMENTAL=y
-CONFIG_BROKEN_ON_SMP=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-CONFIG_CROSS_COMPILE=""
-CONFIG_LOCALVERSION="-db1x00"
-CONFIG_LOCALVERSION_AUTO=y
-CONFIG_KERNEL_LZMA=y
-CONFIG_DEFAULT_HOSTNAME="db1x00"
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-CONFIG_SYSVIPC_SYSCTL=y
-CONFIG_FHANDLE=y
-CONFIG_AUDIT=y
-CONFIG_TINY_RCU=y
-CONFIG_LOG_BUF_SHIFT=18
-CONFIG_NAMESPACES=y
-CONFIG_UTS_NS=y
-CONFIG_IPC_NS=y
-CONFIG_USER_NS=y
-CONFIG_PID_NS=y
-CONFIG_NET_NS=y
-CONFIG_SYSCTL=y
-CONFIG_EXPERT=y
-CONFIG_KALLSYMS=y
-CONFIG_KALLSYMS_ALL=y
-CONFIG_HOTPLUG=y
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-CONFIG_ELF_CORE=y
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
-CONFIG_SHMEM=y
-CONFIG_AIO=y
-CONFIG_EMBEDDED=y
-CONFIG_HAVE_PERF_EVENTS=y
-CONFIG_PERF_USE_VMALLOC=y
-CONFIG_PCI_QUIRKS=y
-CONFIG_SLAB=y
-CONFIG_SLABINFO=y
-CONFIG_BLOCK=y
-CONFIG_LBDAF=y
-CONFIG_BLK_DEV_BSG=y
-CONFIG_BLK_DEV_BSGLIB=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_DEFAULT_NOOP=y
-CONFIG_DEFAULT_IOSCHED="noop"
-CONFIG_FREEZER=y
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_PCCARD=y
-CONFIG_PCMCIA=y
-CONFIG_PCMCIA_LOAD_CIS=y
-CONFIG_PCMCIA_ALCHEMY_DEVBOARD=y
-CONFIG_BINFMT_ELF=y
-CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
-CONFIG_SUSPEND=y
-CONFIG_SUSPEND_FREEZER=y
-CONFIG_PM_SLEEP=y
-CONFIG_PM_RUNTIME=y
-CONFIG_PM=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_XFRM=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-CONFIG_NET_IPIP=y
-CONFIG_INET_TUNNEL=y
-CONFIG_INET_LRO=y
-CONFIG_TCP_CONG_CUBIC=y
-CONFIG_DEFAULT_TCP_CONG="cubic"
-CONFIG_IPV6=y
-CONFIG_INET6_XFRM_MODE_TRANSPORT=y
-CONFIG_INET6_XFRM_MODE_TUNNEL=y
-CONFIG_INET6_XFRM_MODE_BEET=y
-CONFIG_IPV6_SIT=y
-CONFIG_IPV6_NDISC_NODETYPE=y
-CONFIG_STP=y
-CONFIG_GARP=y
-CONFIG_BRIDGE=y
-CONFIG_BRIDGE_IGMP_SNOOPING=y
-CONFIG_VLAN_8021Q=y
-CONFIG_VLAN_8021Q_GVRP=y
-CONFIG_LLC=y
-CONFIG_LLC2=y
-CONFIG_DNS_RESOLVER=y
-CONFIG_BT=y
-CONFIG_BT_L2CAP=y
-CONFIG_BT_SCO=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=y
-CONFIG_BT_HCIBTUSB=y
-CONFIG_UEVENT_HELPER_PATH=""
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=y
-CONFIG_MTD=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLKDEVS=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_GEN_PROBE=y
-CONFIG_MTD_CFI_ADV_OPTIONS=y
-CONFIG_MTD_CFI_NOSWAP=y
-CONFIG_MTD_CFI_GEOMETRY=y
-CONFIG_MTD_MAP_BANK_WIDTH_1=y
-CONFIG_MTD_MAP_BANK_WIDTH_2=y
-CONFIG_MTD_MAP_BANK_WIDTH_4=y
-CONFIG_MTD_CFI_I1=y
-CONFIG_MTD_CFI_I2=y
-CONFIG_MTD_CFI_I4=y
-CONFIG_MTD_CFI_I8=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_CFI_UTIL=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_SCSI_MOD=y
-CONFIG_SCSI=y
-CONFIG_SCSI_DMA=y
-CONFIG_SCSI_PROC_FS=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_ATA=y
-CONFIG_ATA_VERBOSE_ERROR=y
-CONFIG_ATA_SFF=y
-CONFIG_ATA_BMDMA=y
-CONFIG_PATA_HPT37X=y
-CONFIG_PATA_PCMCIA=y
-CONFIG_MD=y
-CONFIG_BLK_DEV_DM=y
-CONFIG_FIREWIRE=y
-CONFIG_FIREWIRE_OHCI=y
-CONFIG_FIREWIRE_OHCI_DEBUG=y
-CONFIG_FIREWIRE_NET=y
-CONFIG_NETDEVICES=y
-CONFIG_MII=y
-CONFIG_PHYLIB=y
-CONFIG_NET_ETHERNET=y
-CONFIG_MIPS_AU1X00_ENET=y
-CONFIG_NET_PCMCIA=y
-CONFIG_PCMCIA_3C589=y
-CONFIG_PCMCIA_PCNET=y
-CONFIG_PPP=y
-CONFIG_PPP_MULTILINK=y
-CONFIG_PPP_FILTER=y
-CONFIG_PPP_ASYNC=y
-CONFIG_PPP_SYNC_TTY=y
-CONFIG_PPP_DEFLATE=y
-CONFIG_PPP_BSDCOMP=y
-CONFIG_PPP_MPPE=y
-CONFIG_PPPOE=y
-CONFIG_INPUT=y
-CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_UINPUT=y
-CONFIG_VT=y
-CONFIG_CONSOLE_TRANSLATIONS=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
-CONFIG_DEVKMEM=y
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=4
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_TTY_PRINTK=y
-CONFIG_DEVPORT=y
-CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-CONFIG_FB=y
-CONFIG_FB_CFB_FILLRECT=y
-CONFIG_FB_CFB_COPYAREA=y
-CONFIG_FB_CFB_IMAGEBLIT=y
-CONFIG_FB_AU1100=y
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
-CONFIG_FONTS=y
-CONFIG_FONT_8x16=y
-CONFIG_SOUND=y
-CONFIG_SND=y
-CONFIG_SND_TIMER=y
-CONFIG_SND_PCM=y
-CONFIG_SND_JACK=y
-CONFIG_SND_SEQUENCER=y
-CONFIG_SND_HRTIMER=y
-CONFIG_SND_SEQ_HRTIMER_DEFAULT=y
-CONFIG_SND_DYNAMIC_MINORS=y
-CONFIG_SND_VMASTER=y
-CONFIG_SND_AC97_CODEC=y
-CONFIG_SND_SOC=y
-CONFIG_SND_SOC_AC97_BUS=y
-CONFIG_SND_SOC_AU1XAUDIO=y
-CONFIG_SND_SOC_AU1XAC97C=y
-CONFIG_SND_SOC_DB1000=y
-CONFIG_SND_SOC_AC97_CODEC=y
-CONFIG_AC97_BUS=y
-CONFIG_HID_SUPPORT=y
-CONFIG_HID=y
-CONFIG_HIDRAW=y
-CONFIG_USB_HID=y
-CONFIG_USB_SUPPORT=y
-CONFIG_USB=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_ROOT_HUB_TT=y
-CONFIG_USB_EHCI_TT_NEWSCHED=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_OHCI_HCD_PLATFORM=y
-CONFIG_USB_UHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_RTC_LIB=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_HCTOSYS=y
-CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
-CONFIG_RTC_INTF_SYSFS=y
-CONFIG_RTC_INTF_PROC=y
-CONFIG_RTC_INTF_DEV=y
-CONFIG_RTC_DRV_AU1XXX=y
-CONFIG_EXT4_FS=y
-CONFIG_EXT4_USE_FOR_EXT23=y
-CONFIG_EXT4_FS_XATTR=y
-CONFIG_EXT4_FS_POSIX_ACL=y
-CONFIG_EXT4_FS_SECURITY=y
-CONFIG_JBD2=y
-CONFIG_FS_MBCACHE=y
-CONFIG_FS_POSIX_ACL=y
-CONFIG_EXPORTFS=y
-CONFIG_FILE_LOCKING=y
-CONFIG_FSNOTIFY=y
-CONFIG_DNOTIFY=y
-CONFIG_INOTIFY_USER=y
-CONFIG_GENERIC_ACL=y
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_PROC_SYSCTL=y
-CONFIG_SYSFS=y
-CONFIG_TMPFS=y
-CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_TMPFS_XATTR=y
-CONFIG_MISC_FILESYSTEMS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_FS_DEBUG=0
-CONFIG_JFFS2_FS_WRITEBUFFER=y
-CONFIG_JFFS2_SUMMARY=y
-CONFIG_JFFS2_FS_XATTR=y
-CONFIG_JFFS2_FS_POSIX_ACL=y
-CONFIG_JFFS2_FS_SECURITY=y
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_JFFS2_ZLIB=y
-CONFIG_JFFS2_LZO=y
-CONFIG_JFFS2_RTIME=y
-CONFIG_JFFS2_RUBIN=y
-CONFIG_JFFS2_CMODE_PRIORITY=y
-CONFIG_SQUASHFS=y
-CONFIG_SQUASHFS_ZLIB=y
-CONFIG_SQUASHFS_LZO=y
-CONFIG_SQUASHFS_XZ=y
-CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
-CONFIG_NETWORK_FILESYSTEMS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V4=y
-CONFIG_NFS_V4_1=y
-CONFIG_PNFS_FILE_LAYOUT=y
-CONFIG_PNFS_BLOCK=y
-CONFIG_ROOT_NFS=y
-CONFIG_NFS_USE_KERNEL_DNS=y
-CONFIG_NFS_USE_NEW_IDMAPPER=y
-CONFIG_NFSD=y
-CONFIG_NFSD_V2_ACL=y
-CONFIG_NFSD_V3=y
-CONFIG_NFSD_V3_ACL=y
-CONFIG_NFSD_V4=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_NFS_ACL_SUPPORT=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=y
-CONFIG_SUNRPC_GSS=y
-CONFIG_SUNRPC_BACKCHANNEL=y
-CONFIG_MSDOS_PARTITION=y
-CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="iso8859-1"
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_CODEPAGE_850=y
-CONFIG_NLS_CODEPAGE_1250=y
-CONFIG_NLS_ASCII=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_NLS_ISO8859_15=y
-CONFIG_NLS_UTF8=y
-CONFIG_HAVE_ARCH_KGDB=y
-CONFIG_EARLY_PRINTK=y
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="noirqdebug rootwait root=/dev/sda1 rootfstype=ext4 console=ttyS0,115200 video=au1100fb:panel:CRT_800x600_16"
-CONFIG_DEBUG_ZBOOT=y
-CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
-CONFIG_SECURITYFS=y
-CONFIG_DEFAULT_SECURITY_DAC=y
-CONFIG_DEFAULT_SECURITY=""
-CONFIG_CRYPTO=y
-CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_ALGAPI2=y
-CONFIG_CRYPTO_AEAD2=y
-CONFIG_CRYPTO_BLKCIPHER=y
-CONFIG_CRYPTO_BLKCIPHER2=y
-CONFIG_CRYPTO_HASH=y
-CONFIG_CRYPTO_HASH2=y
-CONFIG_CRYPTO_RNG=y
-CONFIG_CRYPTO_RNG2=y
-CONFIG_CRYPTO_PCOMP2=y
-CONFIG_CRYPTO_MANAGER=y
-CONFIG_CRYPTO_MANAGER2=y
-CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
-CONFIG_CRYPTO_WORKQUEUE=y
-CONFIG_CRYPTO_ECB=y
-CONFIG_CRYPTO_SHA1=y
-CONFIG_CRYPTO_AES=y
-CONFIG_CRYPTO_ANSI_CPRNG=y
-CONFIG_BITREVERSE=y
-CONFIG_CRC_CCITT=y
-CONFIG_CRC16=y
-CONFIG_CRC_ITU_T=y
-CONFIG_CRC32=y
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=y
-CONFIG_LZO_COMPRESS=y
-CONFIG_LZO_DECOMPRESS=y
-CONFIG_XZ_DEC=y
diff --git a/arch/mips/configs/db1235_defconfig b/arch/mips/configs/db1235_defconfig
deleted file mode 100644
index 28e49f226dc0..000000000000
--- a/arch/mips/configs/db1235_defconfig
+++ /dev/null
@@ -1,434 +0,0 @@
-CONFIG_MIPS_ALCHEMY=y
-CONFIG_MIPS_DB1235=y
-CONFIG_COMPACTION=y
-CONFIG_KSM=y
-CONFIG_HZ_100=y
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOCALVERSION="-db1235"
-CONFIG_KERNEL_LZMA=y
-CONFIG_DEFAULT_HOSTNAME="db1235"
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_BSD_PROCESS_ACCT_V3=y
-CONFIG_FHANDLE=y
-CONFIG_TASKSTATS=y
-CONFIG_TASK_DELAY_ACCT=y
-CONFIG_AUDIT=y
-CONFIG_AUDIT_LOGINUID_IMMUTABLE=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_LOG_BUF_SHIFT=16
-CONFIG_NAMESPACES=y
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-CONFIG_JUMP_LABEL=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_LDM_PARTITION=y
-CONFIG_EFI_PARTITION=y
-CONFIG_PCI=y
-CONFIG_PCCARD=y
-CONFIG_PCMCIA_ALCHEMY_DEVBOARD=y
-CONFIG_PM_RUNTIME=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_UNIX_DIAG=y
-CONFIG_XFRM_USER=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_MULTIPLE_TABLES=y
-CONFIG_IP_ROUTE_MULTIPATH=y
-CONFIG_IP_ROUTE_VERBOSE=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-CONFIG_NET_IPIP=y
-CONFIG_NET_IPGRE_DEMUX=y
-CONFIG_NET_IPGRE=y
-CONFIG_NET_IPGRE_BROADCAST=y
-CONFIG_IP_MROUTE=y
-CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
-CONFIG_IP_PIMSM_V1=y
-CONFIG_IP_PIMSM_V2=y
-CONFIG_ARPD=y
-CONFIG_SYN_COOKIES=y
-CONFIG_NET_IPVTI=y
-CONFIG_INET_AH=y
-CONFIG_INET_ESP=y
-CONFIG_INET_IPCOMP=y
-CONFIG_INET_UDP_DIAG=y
-CONFIG_TCP_CONG_ADVANCED=y
-CONFIG_TCP_CONG_HSTCP=y
-CONFIG_TCP_CONG_HYBLA=y
-CONFIG_TCP_CONG_SCALABLE=y
-CONFIG_TCP_CONG_LP=y
-CONFIG_TCP_CONG_VENO=y
-CONFIG_TCP_CONG_YEAH=y
-CONFIG_TCP_CONG_ILLINOIS=y
-CONFIG_DEFAULT_HYBLA=y
-CONFIG_TCP_MD5SIG=y
-CONFIG_IPV6_PRIVACY=y
-CONFIG_IPV6_ROUTER_PREF=y
-CONFIG_IPV6_ROUTE_INFO=y
-CONFIG_IPV6_OPTIMISTIC_DAD=y
-CONFIG_INET6_AH=y
-CONFIG_INET6_ESP=y
-CONFIG_INET6_IPCOMP=y
-CONFIG_IPV6_MIP6=y
-CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=y
-CONFIG_IPV6_SIT_6RD=y
-CONFIG_IPV6_TUNNEL=y
-CONFIG_IPV6_MULTIPLE_TABLES=y
-CONFIG_IPV6_SUBTREES=y
-CONFIG_IPV6_MROUTE=y
-CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
-CONFIG_IPV6_PIMSM_V2=y
-CONFIG_NETFILTER=y
-CONFIG_NF_CONNTRACK=y
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CONNTRACK_TIMEOUT=y
-CONFIG_NF_CONNTRACK_TIMESTAMP=y
-CONFIG_NF_CT_PROTO_DCCP=y
-CONFIG_NF_CT_PROTO_SCTP=y
-CONFIG_NF_CT_PROTO_UDPLITE=y
-CONFIG_NF_CONNTRACK_AMANDA=y
-CONFIG_NF_CONNTRACK_FTP=y
-CONFIG_NF_CONNTRACK_H323=y
-CONFIG_NF_CONNTRACK_IRC=y
-CONFIG_NF_CONNTRACK_NETBIOS_NS=y
-CONFIG_NF_CONNTRACK_SNMP=y
-CONFIG_NF_CONNTRACK_PPTP=y
-CONFIG_NF_CONNTRACK_SANE=y
-CONFIG_NF_CONNTRACK_SIP=y
-CONFIG_NF_CONNTRACK_TFTP=y
-CONFIG_NF_CT_NETLINK=y
-CONFIG_NF_CT_NETLINK_TIMEOUT=y
-CONFIG_NF_CT_NETLINK_HELPER=y
-CONFIG_NETFILTER_NETLINK_QUEUE_CT=y
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
-CONFIG_NETFILTER_XT_TARGET_HMARK=y
-CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
-CONFIG_NETFILTER_XT_TARGET_LED=y
-CONFIG_NETFILTER_XT_TARGET_LOG=y
-CONFIG_NETFILTER_XT_TARGET_MARK=y
-CONFIG_NETFILTER_XT_TARGET_NFLOG=y
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
-CONFIG_NETFILTER_XT_TARGET_TEE=y
-CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
-CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
-CONFIG_NETFILTER_XT_MATCH_CLUSTER=y
-CONFIG_NETFILTER_XT_MATCH_COMMENT=y
-CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
-CONFIG_NETFILTER_XT_MATCH_CPU=y
-CONFIG_NETFILTER_XT_MATCH_DCCP=y
-CONFIG_NETFILTER_XT_MATCH_DEVGROUP=y
-CONFIG_NETFILTER_XT_MATCH_DSCP=y
-CONFIG_NETFILTER_XT_MATCH_ESP=y
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
-CONFIG_NETFILTER_XT_MATCH_HELPER=y
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
-CONFIG_NETFILTER_XT_MATCH_LENGTH=y
-CONFIG_NETFILTER_XT_MATCH_LIMIT=y
-CONFIG_NETFILTER_XT_MATCH_MAC=y
-CONFIG_NETFILTER_XT_MATCH_MARK=y
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
-CONFIG_NETFILTER_XT_MATCH_NFACCT=y
-CONFIG_NETFILTER_XT_MATCH_OSF=y
-CONFIG_NETFILTER_XT_MATCH_OWNER=y
-CONFIG_NETFILTER_XT_MATCH_POLICY=y
-CONFIG_NETFILTER_XT_MATCH_PHYSDEV=y
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA=y
-CONFIG_NETFILTER_XT_MATCH_RATEEST=y
-CONFIG_NETFILTER_XT_MATCH_REALM=y
-CONFIG_NETFILTER_XT_MATCH_RECENT=y
-CONFIG_NETFILTER_XT_MATCH_SCTP=y
-CONFIG_NETFILTER_XT_MATCH_STATE=y
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
-CONFIG_NETFILTER_XT_MATCH_STRING=y
-CONFIG_NETFILTER_XT_MATCH_TCPMSS=y
-CONFIG_NETFILTER_XT_MATCH_TIME=y
-CONFIG_NETFILTER_XT_MATCH_U32=y
-CONFIG_NF_CONNTRACK_IPV4=y
-CONFIG_IP_NF_IPTABLES=y
-CONFIG_IP_NF_MATCH_AH=y
-CONFIG_IP_NF_MATCH_ECN=y
-CONFIG_IP_NF_MATCH_RPFILTER=y
-CONFIG_IP_NF_MATCH_TTL=y
-CONFIG_IP_NF_FILTER=y
-CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_IP_NF_TARGET_ULOG=y
-CONFIG_NF_NAT=y
-CONFIG_IP_NF_TARGET_MASQUERADE=y
-CONFIG_IP_NF_TARGET_NETMAP=y
-CONFIG_IP_NF_TARGET_REDIRECT=y
-CONFIG_IP_NF_MANGLE=y
-CONFIG_IP_NF_TARGET_CLUSTERIP=y
-CONFIG_IP_NF_TARGET_ECN=y
-CONFIG_IP_NF_TARGET_TTL=y
-CONFIG_IP_NF_RAW=y
-CONFIG_IP_NF_ARPTABLES=y
-CONFIG_IP_NF_ARPFILTER=y
-CONFIG_IP_NF_ARP_MANGLE=y
-CONFIG_NF_CONNTRACK_IPV6=y
-CONFIG_IP6_NF_IPTABLES=y
-CONFIG_IP6_NF_MATCH_AH=y
-CONFIG_IP6_NF_MATCH_EUI64=y
-CONFIG_IP6_NF_MATCH_FRAG=y
-CONFIG_IP6_NF_MATCH_OPTS=y
-CONFIG_IP6_NF_MATCH_HL=y
-CONFIG_IP6_NF_MATCH_IPV6HEADER=y
-CONFIG_IP6_NF_MATCH_MH=y
-CONFIG_IP6_NF_MATCH_RPFILTER=y
-CONFIG_IP6_NF_MATCH_RT=y
-CONFIG_IP6_NF_TARGET_HL=y
-CONFIG_IP6_NF_FILTER=y
-CONFIG_IP6_NF_TARGET_REJECT=y
-CONFIG_IP6_NF_MANGLE=y
-CONFIG_IP6_NF_RAW=y
-CONFIG_BRIDGE_NF_EBTABLES=y
-CONFIG_BRIDGE_EBT_BROUTE=y
-CONFIG_BRIDGE_EBT_T_FILTER=y
-CONFIG_BRIDGE_EBT_T_NAT=y
-CONFIG_BRIDGE_EBT_802_3=y
-CONFIG_BRIDGE_EBT_AMONG=y
-CONFIG_BRIDGE_EBT_ARP=y
-CONFIG_BRIDGE_EBT_IP=y
-CONFIG_BRIDGE_EBT_IP6=y
-CONFIG_BRIDGE_EBT_LIMIT=y
-CONFIG_BRIDGE_EBT_MARK=y
-CONFIG_BRIDGE_EBT_PKTTYPE=y
-CONFIG_BRIDGE_EBT_STP=y
-CONFIG_BRIDGE_EBT_VLAN=y
-CONFIG_BRIDGE_EBT_ARPREPLY=y
-CONFIG_BRIDGE_EBT_DNAT=y
-CONFIG_BRIDGE_EBT_MARK_T=y
-CONFIG_BRIDGE_EBT_REDIRECT=y
-CONFIG_BRIDGE_EBT_SNAT=y
-CONFIG_BRIDGE_EBT_LOG=y
-CONFIG_BRIDGE_EBT_NFLOG=y
-CONFIG_L2TP=y
-CONFIG_L2TP_V3=y
-CONFIG_L2TP_IP=y
-CONFIG_L2TP_ETH=y
-CONFIG_BRIDGE=y
-CONFIG_VLAN_8021Q=y
-CONFIG_VLAN_8021Q_GVRP=y
-CONFIG_LLC2=y
-CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_CBQ=y
-CONFIG_NET_SCH_HTB=y
-CONFIG_NET_SCH_HFSC=y
-CONFIG_NET_SCH_PRIO=y
-CONFIG_NET_SCH_MULTIQ=y
-CONFIG_NET_SCH_RED=y
-CONFIG_NET_SCH_SFB=y
-CONFIG_NET_SCH_SFQ=y
-CONFIG_NET_SCH_TEQL=y
-CONFIG_NET_SCH_TBF=y
-CONFIG_NET_SCH_GRED=y
-CONFIG_NET_SCH_DSMARK=y
-CONFIG_NET_SCH_NETEM=y
-CONFIG_NET_SCH_DRR=y
-CONFIG_NET_SCH_MQPRIO=y
-CONFIG_NET_SCH_CHOKE=y
-CONFIG_NET_SCH_QFQ=y
-CONFIG_NET_SCH_CODEL=y
-CONFIG_NET_SCH_FQ_CODEL=y
-CONFIG_NET_SCH_INGRESS=y
-CONFIG_NET_SCH_PLUG=y
-CONFIG_NET_CLS_BASIC=y
-CONFIG_NET_CLS_TCINDEX=y
-CONFIG_NET_CLS_ROUTE4=y
-CONFIG_NET_CLS_FW=y
-CONFIG_NET_CLS_U32=y
-CONFIG_CLS_U32_PERF=y
-CONFIG_CLS_U32_MARK=y
-CONFIG_NET_CLS_RSVP=y
-CONFIG_NET_CLS_RSVP6=y
-CONFIG_NET_CLS_FLOW=y
-CONFIG_NET_EMATCH=y
-CONFIG_NET_EMATCH_CMP=y
-CONFIG_NET_EMATCH_NBYTE=y
-CONFIG_NET_EMATCH_U32=y
-CONFIG_NET_EMATCH_META=y
-CONFIG_NET_EMATCH_TEXT=y
-CONFIG_NET_CLS_ACT=y
-CONFIG_NET_ACT_POLICE=y
-CONFIG_NET_ACT_GACT=y
-CONFIG_GACT_PROB=y
-CONFIG_NET_ACT_MIRRED=y
-CONFIG_NET_ACT_NAT=y
-CONFIG_NET_ACT_PEDIT=y
-CONFIG_NET_ACT_SIMP=y
-CONFIG_NET_ACT_SKBEDIT=y
-CONFIG_NET_ACT_CSUM=y
-CONFIG_NET_CLS_IND=y
-CONFIG_BT=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=y
-CONFIG_BT_HCIBTUSB=y
-CONFIG_CFG80211=y
-CONFIG_CFG80211_CERTIFICATION_ONUS=y
-CONFIG_CFG80211_WEXT=y
-CONFIG_MAC80211=y
-CONFIG_MAC80211_LEDS=y
-CONFIG_RFKILL=y
-CONFIG_RFKILL_INPUT=y
-CONFIG_DEVTMPFS=y
-CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_M25P80=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_PLATFORM=y
-CONFIG_EEPROM_AT24=y
-CONFIG_EEPROM_AT25=y
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE_AU1XXX=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_ATA=y
-CONFIG_PATA_HPT37X=y
-CONFIG_PATA_PCMCIA=y
-CONFIG_PATA_PLATFORM=y
-CONFIG_NETDEVICES=y
-CONFIG_MIPS_AU1X00_ENET=y
-CONFIG_SMC91X=y
-CONFIG_SMSC911X=y
-CONFIG_AMD_PHY=y
-CONFIG_SMSC_PHY=y
-CONFIG_RT2X00=y
-CONFIG_RT73USB=y
-CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_WM97XX=y
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_UINPUT=y
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_TTY_PRINTK=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_AU1550=y
-CONFIG_SPI=y
-CONFIG_SPI_AU1550=y
-CONFIG_GPIO_SYSFS=y
-CONFIG_SENSORS_ADM1025=y
-CONFIG_SENSORS_LM70=y
-CONFIG_SOUND=y
-CONFIG_SND=y
-CONFIG_SND_HRTIMER=y
-CONFIG_SND_DYNAMIC_MINORS=y
-CONFIG_SND_SOC=y
-CONFIG_SND_SOC_AU1XPSC=y
-CONFIG_SND_SOC_DB1200=y
-CONFIG_HIDRAW=y
-CONFIG_UHID=y
-CONFIG_USB_HIDDEV=y
-CONFIG_USB=y
-CONFIG_USB_DYNAMIC_MINORS=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_HCD_PLATFORM=y
-CONFIG_USB_EHCI_ROOT_HUB_TT=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_OHCI_HCD_PLATFORM=y
-CONFIG_USB_STORAGE=y
-CONFIG_MMC=y
-CONFIG_MMC_AU1X=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_AU1XXX=y
-CONFIG_EXT4_FS=y
-CONFIG_EXT4_FS_POSIX_ACL=y
-CONFIG_EXT4_FS_SECURITY=y
-CONFIG_XFS_FS=y
-CONFIG_XFS_POSIX_ACL=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_CONFIGFS_FS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_SUMMARY=y
-CONFIG_JFFS2_FS_XATTR=y
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_JFFS2_LZO=y
-CONFIG_JFFS2_CMODE_FAVOURLZO=y
-CONFIG_SQUASHFS=y
-CONFIG_SQUASHFS_LZO=y
-CONFIG_SQUASHFS_XZ=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_NFS_V4_1=y
-CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org"
-CONFIG_ROOT_NFS=y
-CONFIG_NFSD=y
-CONFIG_NFSD_V3_ACL=y
-CONFIG_NFSD_V4=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_CODEPAGE_850=y
-CONFIG_NLS_CODEPAGE_852=y
-CONFIG_NLS_CODEPAGE_1250=y
-CONFIG_NLS_ASCII=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_NLS_ISO8859_2=y
-CONFIG_NLS_ISO8859_15=y
-CONFIG_NLS_UTF8=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_STRIP_ASM_SYMS=y
-CONFIG_SECURITYFS=y
-CONFIG_CRYPTO_USER=y
-CONFIG_CRYPTO_NULL=y
-CONFIG_CRYPTO_CRYPTD=y
-CONFIG_CRYPTO_CCM=y
-CONFIG_CRYPTO_GCM=y
-CONFIG_CRYPTO_CTS=y
-CONFIG_CRYPTO_LRW=y
-CONFIG_CRYPTO_PCBC=y
-CONFIG_CRYPTO_XTS=y
-CONFIG_CRYPTO_XCBC=y
-CONFIG_CRYPTO_VMAC=y
-CONFIG_CRYPTO_MD4=y
-CONFIG_CRYPTO_MICHAEL_MIC=y
-CONFIG_CRYPTO_RMD128=y
-CONFIG_CRYPTO_RMD160=y
-CONFIG_CRYPTO_RMD256=y
-CONFIG_CRYPTO_RMD320=y
-CONFIG_CRYPTO_SHA256=y
-CONFIG_CRYPTO_SHA512=y
-CONFIG_CRYPTO_TGR192=y
-CONFIG_CRYPTO_WP512=y
-CONFIG_CRYPTO_ANUBIS=y
-CONFIG_CRYPTO_BLOWFISH=y
-CONFIG_CRYPTO_CAMELLIA=y
-CONFIG_CRYPTO_CAST5=y
-CONFIG_CRYPTO_CAST6=y
-CONFIG_CRYPTO_FCRYPT=y
-CONFIG_CRYPTO_KHAZAD=y
-CONFIG_CRYPTO_SALSA20=y
-CONFIG_CRYPTO_SEED=y
-CONFIG_CRYPTO_SERPENT=y
-CONFIG_CRYPTO_TEA=y
-CONFIG_CRYPTO_TWOFISH=y
-CONFIG_CRYPTO_ZLIB=y
-CONFIG_CRYPTO_LZO=y
-CONFIG_CRYPTO_USER_API_HASH=y
-CONFIG_CRYPTO_USER_API_SKCIPHER=y
diff --git a/arch/mips/configs/db1xxx_defconfig b/arch/mips/configs/db1xxx_defconfig
new file mode 100644
index 000000000000..c99b6eeda90b
--- /dev/null
+++ b/arch/mips/configs/db1xxx_defconfig
@@ -0,0 +1,245 @@
+CONFIG_MIPS_ALCHEMY=y
+CONFIG_MIPS_DB1XXX=y
+CONFIG_CMA=y
+CONFIG_CMA_DEBUG=y
+CONFIG_HZ_100=y
+CONFIG_LOCALVERSION="-db1xxx"
+CONFIG_KERNEL_XZ=y
+CONFIG_DEFAULT_HOSTNAME="db1xxx"
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_FHANDLE=y
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
+CONFIG_MEMCG_KMEM=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_CGROUP=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+CONFIG_BLK_DEV_BSGLIB=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_DEFAULT_NOOP=y
+CONFIG_PCI=y
+CONFIG_PCI_REALLOC_ENABLE_AUTO=y
+CONFIG_PCCARD=y
+CONFIG_PCMCIA_ALCHEMY_DEVBOARD=y
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_PACKET_DIAG=y
+CONFIG_UNIX=y
+CONFIG_UNIX_DIAG=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_XFRM_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_FIB_TRIE_STATS=y
+CONFIG_NET_IPIP=y
+CONFIG_NET_IPGRE_DEMUX=y
+CONFIG_NET_IPGRE=y
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_UDP_DIAG=y
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_VENO=y
+CONFIG_DEFAULT_VENO=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=y
+CONFIG_IPV6_VTI=y
+CONFIG_IPV6_SIT_6RD=y
+CONFIG_IPV6_GRE=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_BRIDGE=y
+CONFIG_NETLINK_MMAP=y
+CONFIG_NETLINK_DIAG=y
+CONFIG_IRDA=y
+CONFIG_IRLAN=y
+CONFIG_IRCOMM=y
+CONFIG_IRDA_ULTRA=y
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_AU1000_FIR=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIBTUSB=y
+CONFIG_CFG80211=y
+CONFIG_CFG80211_WEXT=y
+CONFIG_MAC80211=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_M25P80=y
+CONFIG_MTD_SST25L=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_ECC_BCH=y
+CONFIG_MTD_NAND_AU1550=y
+CONFIG_MTD_NAND_PLATFORM=y
+CONFIG_EEPROM_AT24=y
+CONFIG_EEPROM_AT25=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_ATA=y
+CONFIG_PATA_HPT37X=y
+CONFIG_PATA_HPT3X2N=y
+CONFIG_PATA_PCMCIA=y
+CONFIG_PATA_PLATFORM=y
+CONFIG_NETDEVICES=y
+CONFIG_NLMON=y
+CONFIG_PCMCIA_3C589=y
+CONFIG_MIPS_AU1X00_ENET=y
+CONFIG_SMC91X=y
+CONFIG_SMSC911X=y
+CONFIG_AMD_PHY=y
+CONFIG_SMSC_PHY=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+CONFIG_TOUCHSCREEN_WM97XX=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_TTY_PRINTK=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_AU1550=y
+CONFIG_SPI=y
+CONFIG_SPI_AU1550=y
+CONFIG_SPI_GPIO=y
+CONFIG_SENSORS_ADM1025=y
+CONFIG_SENSORS_LM70=y
+CONFIG_FB=y
+CONFIG_FB_AU1100=y
+CONFIG_FB_AU1200=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SEQUENCER=y
+CONFIG_SND_HRTIMER=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_AC97_POWER_SAVE=y
+CONFIG_SND_AC97_POWER_SAVE_DEFAULT=1
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_AU1XPSC=y
+CONFIG_SND_SOC_AU1XAUDIO=y
+CONFIG_SND_SOC_DB1000=y
+CONFIG_SND_SOC_DB1200=y
+CONFIG_HIDRAW=y
+CONFIG_UHID=y
+CONFIG_HID_LOGITECH=y
+CONFIG_HID_LOGITECH_DJ=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB=y
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_OTG=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_STORAGE=y
+CONFIG_MMC=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_SDIO_UART=y
+CONFIG_MMC_AU1X=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_AU1XXX=y
+CONFIG_FIRMWARE_MEMMAP=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_XFS_FS=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_FANOTIFY=y
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RUBIN=y
+CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_FILE_DIRECT=y
+CONFIG_SQUASHFS_XATTR=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_F2FS_FS=y
+CONFIG_F2FS_FS_SECURITY=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_V4_2=y
+CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="local"
+CONFIG_NFS_V4_1_MIGRATION=y
+CONFIG_NFSD=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=y
+CONFIG_NLS_CODEPAGE_1250=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_UTF8=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_SECURITYFS=y
+CONFIG_CRYPTO_USER=y
+CONFIG_CRYPTO_CRYPTD=y
+CONFIG_CRYPTO_USER_API_HASH=y
+CONFIG_CRYPTO_USER_API_SKCIPHER=y
+CONFIG_CRC32_SLICEBY4=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
diff --git a/arch/mips/configs/loongson3_defconfig b/arch/mips/configs/loongson3_defconfig
new file mode 100644
index 000000000000..ea1761f0f917
--- /dev/null
+++ b/arch/mips/configs/loongson3_defconfig
@@ -0,0 +1,362 @@
+CONFIG_MACH_LOONGSON=y
+CONFIG_SWIOTLB=y
+CONFIG_LEMOTE_MACH3A=y
+CONFIG_CPU_LOONGSON3=y
+CONFIG_64BIT=y
+CONFIG_PAGE_SIZE_16KB=y
+CONFIG_KSM=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_HZ_256=y
+CONFIG_PREEMPT=y
+CONFIG_KEXEC=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_LZMA=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_CPUSETS=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
+CONFIG_BLK_CGROUP=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_EMBEDDED=y
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_BLK_DEV_INTEGRITY=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_IOSCHED_DEADLINE=m
+CONFIG_CFQ_GROUP_IOSCHED=y
+CONFIG_PCI=y
+CONFIG_HT_PCI=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_HOTPLUG_PCI_PCIE=y
+# CONFIG_PCIEAER is not set
+CONFIG_PCIEASPM_PERFORMANCE=y
+CONFIG_HOTPLUG_PCI=y
+CONFIG_HOTPLUG_PCI_SHPC=m
+CONFIG_BINFMT_MISC=m
+CONFIG_MIPS32_COMPAT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
+CONFIG_PM_RUNTIME=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_IP_VS=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_IP_SCTP=m
+CONFIG_L2TP=m
+CONFIG_BRIDGE=m
+CONFIG_CFG80211=m
+CONFIG_CFG80211_WEXT=y
+CONFIG_MAC80211=m
+CONFIG_RFKILL=m
+CONFIG_RFKILL_INPUT=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_MTD=m
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=m
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_ISCSI_TCP=m
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_MEGARAID_MM=y
+CONFIG_MEGARAID_MAILBOX=y
+CONFIG_MEGARAID_LEGACY=y
+CONFIG_MEGARAID_SAS=y
+CONFIG_ATA=y
+CONFIG_SATA_AHCI=y
+CONFIG_PATA_ATIIXP=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID456=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_TARGET_CORE=m
+CONFIG_TCM_IBLOCK=m
+CONFIG_TCM_FILEIO=m
+CONFIG_TCM_PSCSI=m
+CONFIG_LOOPBACK_TARGET=m
+CONFIG_ISCSI_TARGET=m
+CONFIG_NETDEVICES=y
+CONFIG_TUN=m
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+# CONFIG_NET_VENDOR_ALTEON is not set
+# CONFIG_NET_VENDOR_AMD is not set
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_VENDOR_ATHEROS is not set
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+# CONFIG_NET_VENDOR_DEC is not set
+# CONFIG_NET_VENDOR_DLINK is not set
+# CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_EXAR is not set
+# CONFIG_NET_VENDOR_HP is not set
+CONFIG_E1000=y
+CONFIG_E1000E=y
+CONFIG_IGB=y
+CONFIG_IXGB=y
+CONFIG_IXGBE=y
+# CONFIG_NET_VENDOR_I825XX is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MELLANOX is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NVIDIA is not set
+# CONFIG_NET_VENDOR_OKI is not set
+# CONFIG_NET_PACKET_ENGINE is not set
+# CONFIG_NET_VENDOR_QLOGIC is not set
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+CONFIG_R8169=y
+# CONFIG_NET_VENDOR_RDC is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SILAN is not set
+# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_SUN is not set
+# CONFIG_NET_VENDOR_TEHUTI is not set
+# CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_TOSHIBA is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=m
+CONFIG_PPPOL2TP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_ATH_CARDS=m
+CONFIG_ATH9K=m
+CONFIG_HOSTAP=m
+CONFIG_INPUT_POLLDEV=m
+CONFIG_INPUT_SPARSEKMAP=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_XTKBD=m
+CONFIG_MOUSE_PS2_SENTELIC=y
+CONFIG_MOUSE_SERIAL=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_RAW=m
+CONFIG_LEGACY_PTY_COUNT=16
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=16
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_HW_RANDOM=y
+CONFIG_RAW_DRIVER=m
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_PIIX4=y
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM93=m
+CONFIG_SENSORS_W83627HF=m
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_USB_SUPPORT=y
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_DRM=y
+CONFIG_DRM_RADEON=y
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB_RADEON=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_PLATFORM=m
+CONFIG_BACKLIGHT_GENERIC=m
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+# CONFIG_SND_ISA is not set
+CONFIG_SND_HDA_INTEL=m
+CONFIG_SND_HDA_PATCH_LOADER=y
+CONFIG_SND_HDA_CODEC_REALTEK=m
+CONFIG_SND_HDA_CODEC_CONEXANT=m
+# CONFIG_SND_USB is not set
+CONFIG_HID_A4TECH=m
+CONFIG_HID_SUNPLUS=m
+CONFIG_USB=y
+CONFIG_USB_MON=y
+CONFIG_USB_XHCI_HCD=m
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_UHCI_HCD=m
+CONFIG_USB_STORAGE=m
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_CMOS=y
+CONFIG_DMADEVICES=y
+CONFIG_PM_DEVFREQ=y
+CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y
+CONFIG_DEVFREQ_GOV_PERFORMANCE=y
+CONFIG_DEVFREQ_GOV_POWERSAVE=y
+CONFIG_DEVFREQ_GOV_USERSPACE=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_QUOTA=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=m
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=936
+CONFIG_FAT_DEFAULT_IOCHARSET="gb2312"
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_CRAMFS=m
+CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_XATTR=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=m
+CONFIG_NFSD=m
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_CIFS=m
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_936=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_UTF8=y
+CONFIG_PRINTK_TIME=y
+CONFIG_FRAME_WARN=1024
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_RCU_CPU_STALL_VERBOSE is not set
+# CONFIG_FTRACE is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITYFS=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_PATH=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_DEFLATE=m
diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig
index ce1d3eeeb737..b745b6a9f322 100644
--- a/arch/mips/configs/malta_defconfig
+++ b/arch/mips/configs/malta_defconfig
@@ -1,7 +1,9 @@
CONFIG_MIPS_MALTA=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32_R2=y
+CONFIG_PAGE_SIZE_16KB=y
CONFIG_MIPS_MT_SMP=y
+CONFIG_NR_CPUS=8
CONFIG_HZ_100=y
CONFIG_SYSVIPC=y
CONFIG_NO_HZ=y
@@ -42,7 +44,6 @@ CONFIG_INET_IPCOMP=m
CONFIG_INET_XFRM_MODE_TRANSPORT=m
CONFIG_INET_XFRM_MODE_TUNNEL=m
CONFIG_TCP_MD5SIG=y
-CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IPV6_OPTIMISTIC_DAD=y
@@ -68,7 +69,6 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_TPROXY=m
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
CONFIG_NETFILTER_XT_TARGET_MARK=m
@@ -125,7 +125,6 @@ CONFIG_IP_VS_SH=m
CONFIG_IP_VS_SED=m
CONFIG_IP_VS_NQ=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_QUEUE=m
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
@@ -185,7 +184,6 @@ CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
-CONFIG_IPDDP_DECAP=y
CONFIG_PHONET=m
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_CBQ=m
@@ -226,9 +224,9 @@ CONFIG_MAC80211_RC_DEFAULT_PID=y
CONFIG_MAC80211_MESH=y
CONFIG_RFKILL=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
CONFIG_CONNECTOR=m
CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_OOPS=m
CONFIG_MTD_CFI=y
@@ -328,7 +326,6 @@ CONFIG_LIBERTAS=m
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO_I8042 is not set
-CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_HWMON is not set
diff --git a/arch/mips/configs/malta_kvm_defconfig b/arch/mips/configs/malta_kvm_defconfig
index 341bb47204d6..4f7d952d8517 100644
--- a/arch/mips/configs/malta_kvm_defconfig
+++ b/arch/mips/configs/malta_kvm_defconfig
@@ -3,6 +3,7 @@ CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32_R2=y
CONFIG_PAGE_SIZE_16KB=y
CONFIG_MIPS_MT_SMP=y
+CONFIG_NR_CPUS=8
CONFIG_HZ_100=y
CONFIG_SYSVIPC=y
CONFIG_NO_HZ=y
@@ -44,7 +45,6 @@ CONFIG_INET_IPCOMP=m
CONFIG_INET_XFRM_MODE_TRANSPORT=m
CONFIG_INET_XFRM_MODE_TUNNEL=m
CONFIG_TCP_MD5SIG=y
-CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IPV6_OPTIMISTIC_DAD=y
@@ -70,7 +70,6 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_TPROXY=m
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
CONFIG_NETFILTER_XT_TARGET_MARK=m
@@ -127,7 +126,6 @@ CONFIG_IP_VS_SH=m
CONFIG_IP_VS_SED=m
CONFIG_IP_VS_NQ=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_QUEUE=m
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
@@ -187,7 +185,6 @@ CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
-CONFIG_IPDDP_DECAP=y
CONFIG_PHONET=m
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_CBQ=m
@@ -228,9 +225,9 @@ CONFIG_MAC80211_RC_DEFAULT_PID=y
CONFIG_MAC80211_MESH=y
CONFIG_RFKILL=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
CONFIG_CONNECTOR=m
CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_OOPS=m
CONFIG_MTD_CFI=y
@@ -300,6 +297,7 @@ CONFIG_IFB=m
CONFIG_MACVLAN=m
CONFIG_TUN=m
CONFIG_VETH=m
+CONFIG_VHOST_NET=m
CONFIG_PCNET32=y
CONFIG_CHELSIO_T3=m
CONFIG_AX88796=m
@@ -329,7 +327,6 @@ CONFIG_LIBERTAS=m
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO_I8042 is not set
-CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_HWMON is not set
@@ -453,4 +450,3 @@ CONFIG_VIRTUALIZATION=y
CONFIG_KVM=m
CONFIG_KVM_MIPS_DYN_TRANS=y
CONFIG_KVM_MIPS_DEBUG_COP0_COUNTERS=y
-CONFIG_VHOST_NET=m
diff --git a/arch/mips/configs/malta_kvm_guest_defconfig b/arch/mips/configs/malta_kvm_guest_defconfig
index 2b8558b71080..e36681c24ddc 100644
--- a/arch/mips/configs/malta_kvm_guest_defconfig
+++ b/arch/mips/configs/malta_kvm_guest_defconfig
@@ -44,7 +44,6 @@ CONFIG_INET_IPCOMP=m
CONFIG_INET_XFRM_MODE_TRANSPORT=m
CONFIG_INET_XFRM_MODE_TUNNEL=m
CONFIG_TCP_MD5SIG=y
-CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IPV6_OPTIMISTIC_DAD=y
@@ -70,7 +69,6 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_TPROXY=m
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
CONFIG_NETFILTER_XT_TARGET_MARK=m
@@ -127,7 +125,6 @@ CONFIG_IP_VS_SH=m
CONFIG_IP_VS_SED=m
CONFIG_IP_VS_NQ=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_QUEUE=m
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
@@ -187,7 +184,6 @@ CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
-CONFIG_IPDDP_DECAP=y
CONFIG_PHONET=m
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_CBQ=m
@@ -228,9 +224,9 @@ CONFIG_MAC80211_RC_DEFAULT_PID=y
CONFIG_MAC80211_MESH=y
CONFIG_RFKILL=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
CONFIG_CONNECTOR=m
CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_OOPS=m
CONFIG_MTD_CFI=y
@@ -331,7 +327,6 @@ CONFIG_LIBERTAS=m
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO_I8042 is not set
-CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_HWMON is not set
diff --git a/arch/mips/configs/maltaaprp_defconfig b/arch/mips/configs/maltaaprp_defconfig
index 93057a760dfa..fb042ce86b4b 100644
--- a/arch/mips/configs/maltaaprp_defconfig
+++ b/arch/mips/configs/maltaaprp_defconfig
@@ -44,7 +44,6 @@ CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_INET_LRO is not set
-CONFIG_IPV6_PRIVACY=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
@@ -55,7 +54,6 @@ CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
-CONFIG_IPDDP_DECAP=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_CBQ=m
CONFIG_NET_SCH_HTB=m
@@ -80,6 +78,7 @@ CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=y
CONFIG_NET_CLS_IND=y
# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_IDE=y
diff --git a/arch/mips/configs/maltasmtc_defconfig b/arch/mips/configs/maltasmtc_defconfig
index 4e54b75d89be..eb316447588c 100644
--- a/arch/mips/configs/maltasmtc_defconfig
+++ b/arch/mips/configs/maltasmtc_defconfig
@@ -1,6 +1,7 @@
CONFIG_MIPS_MALTA=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32_R2=y
+CONFIG_PAGE_SIZE_16KB=y
CONFIG_MIPS_MT_SMTC=y
# CONFIG_MIPS_MT_FPAFF is not set
CONFIG_NR_CPUS=9
@@ -45,7 +46,6 @@ CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_INET_LRO is not set
-CONFIG_IPV6_PRIVACY=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
@@ -56,7 +56,6 @@ CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
-CONFIG_IPDDP_DECAP=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_CBQ=m
CONFIG_NET_SCH_HTB=m
@@ -81,6 +80,7 @@ CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=y
CONFIG_NET_CLS_IND=y
# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_IDE=y
diff --git a/arch/mips/configs/maltasmvp_defconfig b/arch/mips/configs/maltasmvp_defconfig
index d75931850392..10ef3bed5f43 100644
--- a/arch/mips/configs/maltasmvp_defconfig
+++ b/arch/mips/configs/maltasmvp_defconfig
@@ -1,10 +1,11 @@
CONFIG_MIPS_MALTA=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32_R2=y
+CONFIG_PAGE_SIZE_16KB=y
CONFIG_MIPS_MT_SMP=y
CONFIG_SCHED_SMT=y
CONFIG_MIPS_CMP=y
-CONFIG_NR_CPUS=2
+CONFIG_NR_CPUS=8
CONFIG_HZ_100=y
CONFIG_LOCALVERSION="cmp"
CONFIG_SYSVIPC=y
@@ -47,7 +48,6 @@ CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_INET_LRO is not set
-CONFIG_IPV6_PRIVACY=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
@@ -82,6 +82,7 @@ CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=y
CONFIG_NET_CLS_IND=y
# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_IDE=y
diff --git a/arch/mips/configs/maltasmvp_eva_defconfig b/arch/mips/configs/maltasmvp_eva_defconfig
new file mode 100644
index 000000000000..2d3002cba102
--- /dev/null
+++ b/arch/mips/configs/maltasmvp_eva_defconfig
@@ -0,0 +1,200 @@
+CONFIG_MIPS_MALTA=y
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_CPU_MIPS32_R2=y
+CONFIG_CPU_MIPS32_3_5_FEATURES=y
+CONFIG_PAGE_SIZE_16KB=y
+CONFIG_MIPS_MT_SMP=y
+CONFIG_SCHED_SMT=y
+CONFIG_MIPS_CMP=y
+CONFIG_NR_CPUS=8
+CONFIG_HZ_100=y
+CONFIG_LOCALVERSION="cmp"
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=15
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PCI=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=m
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_NET_IPIP=m
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+# CONFIG_INET_LRO is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=m
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+CONFIG_NET_CLS_IND=y
+# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_IDE=y
+# CONFIG_IDE_PROC_FS is not set
+# CONFIG_IDEPCI_PCIBUS_ORDER is not set
+CONFIG_BLK_DEV_GENERIC=y
+CONFIG_BLK_DEV_PIIX=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+# CONFIG_NET_VENDOR_ALTEON is not set
+CONFIG_PCNET32=y
+# CONFIG_NET_VENDOR_ATHEROS is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+# CONFIG_NET_VENDOR_DEC is not set
+# CONFIG_NET_VENDOR_DLINK is not set
+# CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_EXAR is not set
+# CONFIG_NET_VENDOR_HP is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MELLANOX is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NVIDIA is not set
+# CONFIG_NET_VENDOR_OKI is not set
+# CONFIG_NET_PACKET_ENGINE is not set
+# CONFIG_NET_VENDOR_QLOGIC is not set
+# CONFIG_NET_VENDOR_REALTEK is not set
+# CONFIG_NET_VENDOR_RDC is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SILAN is not set
+# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_SUN is not set
+# CONFIG_NET_VENDOR_TEHUTI is not set
+# CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_TOSHIBA is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+# CONFIG_WLAN is not set
+# CONFIG_VT is not set
+CONFIG_LEGACY_PTY_COUNT=4
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_HW_RANDOM=y
+# CONFIG_HWMON is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_G=y
+CONFIG_USB=y
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_UHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_IDE_DISK=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_CMOS=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_XFS_FS=y
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V2=y
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_CIFS=m
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_FTRACE is not set
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
diff --git a/arch/mips/configs/maltaup_defconfig b/arch/mips/configs/maltaup_defconfig
index 9868fc9c1133..62344648eb7a 100644
--- a/arch/mips/configs/maltaup_defconfig
+++ b/arch/mips/configs/maltaup_defconfig
@@ -43,7 +43,6 @@ CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_INET_LRO is not set
-CONFIG_IPV6_PRIVACY=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
@@ -54,7 +53,6 @@ CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
-CONFIG_IPDDP_DECAP=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_CBQ=m
CONFIG_NET_SCH_HTB=m
@@ -79,6 +77,7 @@ CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=y
CONFIG_NET_CLS_IND=y
# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_IDE=y
diff --git a/arch/mips/include/asm/Kbuild b/arch/mips/include/asm/Kbuild
index 2d7f65052c1f..05439187891d 100644
--- a/arch/mips/include/asm/Kbuild
+++ b/arch/mips/include/asm/Kbuild
@@ -2,16 +2,17 @@
generic-y += cputime.h
generic-y += current.h
generic-y += emergency-restart.h
+generic-y += hash.h
generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += mutex.h
generic-y += parport.h
generic-y += percpu.h
+generic-y += preempt.h
generic-y += scatterlist.h
generic-y += sections.h
generic-y += segment.h
generic-y += serial.h
generic-y += trace_clock.h
-generic-y += preempt.h
generic-y += ucontext.h
generic-y += xor.h
-generic-y += hash.h
diff --git a/arch/mips/include/asm/asm-eva.h b/arch/mips/include/asm/asm-eva.h
new file mode 100644
index 000000000000..e41c56e375b1
--- /dev/null
+++ b/arch/mips/include/asm/asm-eva.h
@@ -0,0 +1,135 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2014 Imagination Technologies Ltd.
+ *
+ */
+
+#ifndef __ASM_ASM_EVA_H
+#define __ASM_ASM_EVA_H
+
+#ifndef __ASSEMBLY__
+#ifdef CONFIG_EVA
+
+#define __BUILD_EVA_INSN(insn, reg, addr) \
+ " .set push\n" \
+ " .set mips0\n" \
+ " .set eva\n" \
+ " "insn" "reg", "addr "\n" \
+ " .set pop\n"
+
+#define user_cache(op, base) __BUILD_EVA_INSN("cachee", op, base)
+#define user_ll(reg, addr) __BUILD_EVA_INSN("lle", reg, addr)
+#define user_sc(reg, addr) __BUILD_EVA_INSN("sce", reg, addr)
+#define user_lw(reg, addr) __BUILD_EVA_INSN("lwe", reg, addr)
+#define user_lwl(reg, addr) __BUILD_EVA_INSN("lwle", reg, addr)
+#define user_lwr(reg, addr) __BUILD_EVA_INSN("lwre", reg, addr)
+#define user_lh(reg, addr) __BUILD_EVA_INSN("lhe", reg, addr)
+#define user_lb(reg, addr) __BUILD_EVA_INSN("lbe", reg, addr)
+#define user_lbu(reg, addr) __BUILD_EVA_INSN("lbue", reg, addr)
+/* No 64-bit EVA instruction for loading double words */
+#define user_ld(reg, addr) user_lw(reg, addr)
+#define user_sw(reg, addr) __BUILD_EVA_INSN("swe", reg, addr)
+#define user_swl(reg, addr) __BUILD_EVA_INSN("swle", reg, addr)
+#define user_swr(reg, addr) __BUILD_EVA_INSN("swre", reg, addr)
+#define user_sh(reg, addr) __BUILD_EVA_INSN("she", reg, addr)
+#define user_sb(reg, addr) __BUILD_EVA_INSN("sbe", reg, addr)
+/* No 64-bit EVA instruction for storing double words */
+#define user_sd(reg, addr) user_sw(reg, addr)
+
+#else
+
+#define user_cache(op, base) "cache " op ", " base "\n"
+#define user_ll(reg, addr) "ll " reg ", " addr "\n"
+#define user_sc(reg, addr) "sc " reg ", " addr "\n"
+#define user_lw(reg, addr) "lw " reg ", " addr "\n"
+#define user_lwl(reg, addr) "lwl " reg ", " addr "\n"
+#define user_lwr(reg, addr) "lwr " reg ", " addr "\n"
+#define user_lh(reg, addr) "lh " reg ", " addr "\n"
+#define user_lb(reg, addr) "lb " reg ", " addr "\n"
+#define user_lbu(reg, addr) "lbu " reg ", " addr "\n"
+#define user_sw(reg, addr) "sw " reg ", " addr "\n"
+#define user_swl(reg, addr) "swl " reg ", " addr "\n"
+#define user_swr(reg, addr) "swr " reg ", " addr "\n"
+#define user_sh(reg, addr) "sh " reg ", " addr "\n"
+#define user_sb(reg, addr) "sb " reg ", " addr "\n"
+
+#ifdef CONFIG_32BIT
+/*
+ * No 'sd' or 'ld' instructions in 32-bit but the code will
+ * do the correct thing
+ */
+#define user_sd(reg, addr) user_sw(reg, addr)
+#define user_ld(reg, addr) user_lw(reg, addr)
+#else
+#define user_sd(reg, addr) "sd " reg", " addr "\n"
+#define user_ld(reg, addr) "ld " reg", " addr "\n"
+#endif /* CONFIG_32BIT */
+
+#endif /* CONFIG_EVA */
+
+#else /* __ASSEMBLY__ */
+
+#ifdef CONFIG_EVA
+
+#define __BUILD_EVA_INSN(insn, reg, addr) \
+ .set push; \
+ .set mips0; \
+ .set eva; \
+ insn reg, addr; \
+ .set pop;
+
+#define user_cache(op, base) __BUILD_EVA_INSN(cachee, op, base)
+#define user_ll(reg, addr) __BUILD_EVA_INSN(lle, reg, addr)
+#define user_sc(reg, addr) __BUILD_EVA_INSN(sce, reg, addr)
+#define user_lw(reg, addr) __BUILD_EVA_INSN(lwe, reg, addr)
+#define user_lwl(reg, addr) __BUILD_EVA_INSN(lwle, reg, addr)
+#define user_lwr(reg, addr) __BUILD_EVA_INSN(lwre, reg, addr)
+#define user_lh(reg, addr) __BUILD_EVA_INSN(lhe, reg, addr)
+#define user_lb(reg, addr) __BUILD_EVA_INSN(lbe, reg, addr)
+#define user_lbu(reg, addr) __BUILD_EVA_INSN(lbue, reg, addr)
+/* No 64-bit EVA instruction for loading double words */
+#define user_ld(reg, addr) user_lw(reg, addr)
+#define user_sw(reg, addr) __BUILD_EVA_INSN(swe, reg, addr)
+#define user_swl(reg, addr) __BUILD_EVA_INSN(swle, reg, addr)
+#define user_swr(reg, addr) __BUILD_EVA_INSN(swre, reg, addr)
+#define user_sh(reg, addr) __BUILD_EVA_INSN(she, reg, addr)
+#define user_sb(reg, addr) __BUILD_EVA_INSN(sbe, reg, addr)
+/* No 64-bit EVA instruction for loading double words */
+#define user_sd(reg, addr) user_sw(reg, addr)
+#else
+
+#define user_cache(op, base) cache op, base
+#define user_ll(reg, addr) ll reg, addr
+#define user_sc(reg, addr) sc reg, addr
+#define user_lw(reg, addr) lw reg, addr
+#define user_lwl(reg, addr) lwl reg, addr
+#define user_lwr(reg, addr) lwr reg, addr
+#define user_lh(reg, addr) lh reg, addr
+#define user_lb(reg, addr) lb reg, addr
+#define user_lbu(reg, addr) lbu reg, addr
+#define user_sw(reg, addr) sw reg, addr
+#define user_swl(reg, addr) swl reg, addr
+#define user_swr(reg, addr) swr reg, addr
+#define user_sh(reg, addr) sh reg, addr
+#define user_sb(reg, addr) sb reg, addr
+
+#ifdef CONFIG_32BIT
+/*
+ * No 'sd' or 'ld' instructions in 32-bit but the code will
+ * do the correct thing
+ */
+#define user_sd(reg, addr) user_sw(reg, addr)
+#define user_ld(reg, addr) user_lw(reg, addr)
+#else
+#define user_sd(reg, addr) sd reg, addr
+#define user_ld(reg, addr) ld reg, addr
+#endif /* CONFIG_32BIT */
+
+#endif /* CONFIG_EVA */
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_ASM_EVA_H */
diff --git a/arch/mips/include/asm/asm.h b/arch/mips/include/asm/asm.h
index 879691d194af..7c26b28bf252 100644
--- a/arch/mips/include/asm/asm.h
+++ b/arch/mips/include/asm/asm.h
@@ -18,6 +18,7 @@
#define __ASM_ASM_H
#include <asm/sgidefs.h>
+#include <asm/asm-eva.h>
#ifndef CAT
#ifdef __STDC__
@@ -145,19 +146,27 @@ symbol = value
#define PREF(hint,addr) \
.set push; \
- .set mips4; \
+ .set arch=r5000; \
pref hint, addr; \
.set pop
+#define PREFE(hint, addr) \
+ .set push; \
+ .set mips0; \
+ .set eva; \
+ prefe hint, addr; \
+ .set pop
+
#define PREFX(hint,addr) \
.set push; \
- .set mips4; \
+ .set arch=r5000; \
prefx hint, addr; \
.set pop
#else /* !CONFIG_CPU_HAS_PREFETCH */
#define PREF(hint, addr)
+#define PREFE(hint, addr)
#define PREFX(hint, addr)
#endif /* !CONFIG_CPU_HAS_PREFETCH */
diff --git a/arch/mips/include/asm/asmmacro-32.h b/arch/mips/include/asm/asmmacro-32.h
index 70e1f176f123..e38c2811d4e2 100644
--- a/arch/mips/include/asm/asmmacro-32.h
+++ b/arch/mips/include/asm/asmmacro-32.h
@@ -14,75 +14,75 @@
.macro fpu_save_single thread tmp=t0
cfc1 \tmp, fcr31
- swc1 $f0, THREAD_FPR0(\thread)
- swc1 $f1, THREAD_FPR1(\thread)
- swc1 $f2, THREAD_FPR2(\thread)
- swc1 $f3, THREAD_FPR3(\thread)
- swc1 $f4, THREAD_FPR4(\thread)
- swc1 $f5, THREAD_FPR5(\thread)
- swc1 $f6, THREAD_FPR6(\thread)
- swc1 $f7, THREAD_FPR7(\thread)
- swc1 $f8, THREAD_FPR8(\thread)
- swc1 $f9, THREAD_FPR9(\thread)
- swc1 $f10, THREAD_FPR10(\thread)
- swc1 $f11, THREAD_FPR11(\thread)
- swc1 $f12, THREAD_FPR12(\thread)
- swc1 $f13, THREAD_FPR13(\thread)
- swc1 $f14, THREAD_FPR14(\thread)
- swc1 $f15, THREAD_FPR15(\thread)
- swc1 $f16, THREAD_FPR16(\thread)
- swc1 $f17, THREAD_FPR17(\thread)
- swc1 $f18, THREAD_FPR18(\thread)
- swc1 $f19, THREAD_FPR19(\thread)
- swc1 $f20, THREAD_FPR20(\thread)
- swc1 $f21, THREAD_FPR21(\thread)
- swc1 $f22, THREAD_FPR22(\thread)
- swc1 $f23, THREAD_FPR23(\thread)
- swc1 $f24, THREAD_FPR24(\thread)
- swc1 $f25, THREAD_FPR25(\thread)
- swc1 $f26, THREAD_FPR26(\thread)
- swc1 $f27, THREAD_FPR27(\thread)
- swc1 $f28, THREAD_FPR28(\thread)
- swc1 $f29, THREAD_FPR29(\thread)
- swc1 $f30, THREAD_FPR30(\thread)
- swc1 $f31, THREAD_FPR31(\thread)
+ swc1 $f0, THREAD_FPR0_LS64(\thread)
+ swc1 $f1, THREAD_FPR1_LS64(\thread)
+ swc1 $f2, THREAD_FPR2_LS64(\thread)
+ swc1 $f3, THREAD_FPR3_LS64(\thread)
+ swc1 $f4, THREAD_FPR4_LS64(\thread)
+ swc1 $f5, THREAD_FPR5_LS64(\thread)
+ swc1 $f6, THREAD_FPR6_LS64(\thread)
+ swc1 $f7, THREAD_FPR7_LS64(\thread)
+ swc1 $f8, THREAD_FPR8_LS64(\thread)
+ swc1 $f9, THREAD_FPR9_LS64(\thread)
+ swc1 $f10, THREAD_FPR10_LS64(\thread)
+ swc1 $f11, THREAD_FPR11_LS64(\thread)
+ swc1 $f12, THREAD_FPR12_LS64(\thread)
+ swc1 $f13, THREAD_FPR13_LS64(\thread)
+ swc1 $f14, THREAD_FPR14_LS64(\thread)
+ swc1 $f15, THREAD_FPR15_LS64(\thread)
+ swc1 $f16, THREAD_FPR16_LS64(\thread)
+ swc1 $f17, THREAD_FPR17_LS64(\thread)
+ swc1 $f18, THREAD_FPR18_LS64(\thread)
+ swc1 $f19, THREAD_FPR19_LS64(\thread)
+ swc1 $f20, THREAD_FPR20_LS64(\thread)
+ swc1 $f21, THREAD_FPR21_LS64(\thread)
+ swc1 $f22, THREAD_FPR22_LS64(\thread)
+ swc1 $f23, THREAD_FPR23_LS64(\thread)
+ swc1 $f24, THREAD_FPR24_LS64(\thread)
+ swc1 $f25, THREAD_FPR25_LS64(\thread)
+ swc1 $f26, THREAD_FPR26_LS64(\thread)
+ swc1 $f27, THREAD_FPR27_LS64(\thread)
+ swc1 $f28, THREAD_FPR28_LS64(\thread)
+ swc1 $f29, THREAD_FPR29_LS64(\thread)
+ swc1 $f30, THREAD_FPR30_LS64(\thread)
+ swc1 $f31, THREAD_FPR31_LS64(\thread)
sw \tmp, THREAD_FCR31(\thread)
.endm
.macro fpu_restore_single thread tmp=t0
lw \tmp, THREAD_FCR31(\thread)
- lwc1 $f0, THREAD_FPR0(\thread)
- lwc1 $f1, THREAD_FPR1(\thread)
- lwc1 $f2, THREAD_FPR2(\thread)
- lwc1 $f3, THREAD_FPR3(\thread)
- lwc1 $f4, THREAD_FPR4(\thread)
- lwc1 $f5, THREAD_FPR5(\thread)
- lwc1 $f6, THREAD_FPR6(\thread)
- lwc1 $f7, THREAD_FPR7(\thread)
- lwc1 $f8, THREAD_FPR8(\thread)
- lwc1 $f9, THREAD_FPR9(\thread)
- lwc1 $f10, THREAD_FPR10(\thread)
- lwc1 $f11, THREAD_FPR11(\thread)
- lwc1 $f12, THREAD_FPR12(\thread)
- lwc1 $f13, THREAD_FPR13(\thread)
- lwc1 $f14, THREAD_FPR14(\thread)
- lwc1 $f15, THREAD_FPR15(\thread)
- lwc1 $f16, THREAD_FPR16(\thread)
- lwc1 $f17, THREAD_FPR17(\thread)
- lwc1 $f18, THREAD_FPR18(\thread)
- lwc1 $f19, THREAD_FPR19(\thread)
- lwc1 $f20, THREAD_FPR20(\thread)
- lwc1 $f21, THREAD_FPR21(\thread)
- lwc1 $f22, THREAD_FPR22(\thread)
- lwc1 $f23, THREAD_FPR23(\thread)
- lwc1 $f24, THREAD_FPR24(\thread)
- lwc1 $f25, THREAD_FPR25(\thread)
- lwc1 $f26, THREAD_FPR26(\thread)
- lwc1 $f27, THREAD_FPR27(\thread)
- lwc1 $f28, THREAD_FPR28(\thread)
- lwc1 $f29, THREAD_FPR29(\thread)
- lwc1 $f30, THREAD_FPR30(\thread)
- lwc1 $f31, THREAD_FPR31(\thread)
+ lwc1 $f0, THREAD_FPR0_LS64(\thread)
+ lwc1 $f1, THREAD_FPR1_LS64(\thread)
+ lwc1 $f2, THREAD_FPR2_LS64(\thread)
+ lwc1 $f3, THREAD_FPR3_LS64(\thread)
+ lwc1 $f4, THREAD_FPR4_LS64(\thread)
+ lwc1 $f5, THREAD_FPR5_LS64(\thread)
+ lwc1 $f6, THREAD_FPR6_LS64(\thread)
+ lwc1 $f7, THREAD_FPR7_LS64(\thread)
+ lwc1 $f8, THREAD_FPR8_LS64(\thread)
+ lwc1 $f9, THREAD_FPR9_LS64(\thread)
+ lwc1 $f10, THREAD_FPR10_LS64(\thread)
+ lwc1 $f11, THREAD_FPR11_LS64(\thread)
+ lwc1 $f12, THREAD_FPR12_LS64(\thread)
+ lwc1 $f13, THREAD_FPR13_LS64(\thread)
+ lwc1 $f14, THREAD_FPR14_LS64(\thread)
+ lwc1 $f15, THREAD_FPR15_LS64(\thread)
+ lwc1 $f16, THREAD_FPR16_LS64(\thread)
+ lwc1 $f17, THREAD_FPR17_LS64(\thread)
+ lwc1 $f18, THREAD_FPR18_LS64(\thread)
+ lwc1 $f19, THREAD_FPR19_LS64(\thread)
+ lwc1 $f20, THREAD_FPR20_LS64(\thread)
+ lwc1 $f21, THREAD_FPR21_LS64(\thread)
+ lwc1 $f22, THREAD_FPR22_LS64(\thread)
+ lwc1 $f23, THREAD_FPR23_LS64(\thread)
+ lwc1 $f24, THREAD_FPR24_LS64(\thread)
+ lwc1 $f25, THREAD_FPR25_LS64(\thread)
+ lwc1 $f26, THREAD_FPR26_LS64(\thread)
+ lwc1 $f27, THREAD_FPR27_LS64(\thread)
+ lwc1 $f28, THREAD_FPR28_LS64(\thread)
+ lwc1 $f29, THREAD_FPR29_LS64(\thread)
+ lwc1 $f30, THREAD_FPR30_LS64(\thread)
+ lwc1 $f31, THREAD_FPR31_LS64(\thread)
ctc1 \tmp, fcr31
.endm
diff --git a/arch/mips/include/asm/asmmacro.h b/arch/mips/include/asm/asmmacro.h
index 3220c93ea981..b464b8b1147a 100644
--- a/arch/mips/include/asm/asmmacro.h
+++ b/arch/mips/include/asm/asmmacro.h
@@ -9,6 +9,7 @@
#define _ASM_ASMMACRO_H
#include <asm/hazards.h>
+#include <asm/asm-offsets.h>
#ifdef CONFIG_32BIT
#include <asm/asmmacro-32.h>
@@ -54,59 +55,69 @@
.endm
.macro local_irq_disable reg=t0
+#ifdef CONFIG_PREEMPT
+ lw \reg, TI_PRE_COUNT($28)
+ addi \reg, \reg, 1
+ sw \reg, TI_PRE_COUNT($28)
+#endif
mfc0 \reg, CP0_STATUS
ori \reg, \reg, 1
xori \reg, \reg, 1
mtc0 \reg, CP0_STATUS
irq_disable_hazard
+#ifdef CONFIG_PREEMPT
+ lw \reg, TI_PRE_COUNT($28)
+ addi \reg, \reg, -1
+ sw \reg, TI_PRE_COUNT($28)
+#endif
.endm
#endif /* CONFIG_MIPS_MT_SMTC */
.macro fpu_save_16even thread tmp=t0
cfc1 \tmp, fcr31
- sdc1 $f0, THREAD_FPR0(\thread)
- sdc1 $f2, THREAD_FPR2(\thread)
- sdc1 $f4, THREAD_FPR4(\thread)
- sdc1 $f6, THREAD_FPR6(\thread)
- sdc1 $f8, THREAD_FPR8(\thread)
- sdc1 $f10, THREAD_FPR10(\thread)
- sdc1 $f12, THREAD_FPR12(\thread)
- sdc1 $f14, THREAD_FPR14(\thread)
- sdc1 $f16, THREAD_FPR16(\thread)
- sdc1 $f18, THREAD_FPR18(\thread)
- sdc1 $f20, THREAD_FPR20(\thread)
- sdc1 $f22, THREAD_FPR22(\thread)
- sdc1 $f24, THREAD_FPR24(\thread)
- sdc1 $f26, THREAD_FPR26(\thread)
- sdc1 $f28, THREAD_FPR28(\thread)
- sdc1 $f30, THREAD_FPR30(\thread)
+ sdc1 $f0, THREAD_FPR0_LS64(\thread)
+ sdc1 $f2, THREAD_FPR2_LS64(\thread)
+ sdc1 $f4, THREAD_FPR4_LS64(\thread)
+ sdc1 $f6, THREAD_FPR6_LS64(\thread)
+ sdc1 $f8, THREAD_FPR8_LS64(\thread)
+ sdc1 $f10, THREAD_FPR10_LS64(\thread)
+ sdc1 $f12, THREAD_FPR12_LS64(\thread)
+ sdc1 $f14, THREAD_FPR14_LS64(\thread)
+ sdc1 $f16, THREAD_FPR16_LS64(\thread)
+ sdc1 $f18, THREAD_FPR18_LS64(\thread)
+ sdc1 $f20, THREAD_FPR20_LS64(\thread)
+ sdc1 $f22, THREAD_FPR22_LS64(\thread)
+ sdc1 $f24, THREAD_FPR24_LS64(\thread)
+ sdc1 $f26, THREAD_FPR26_LS64(\thread)
+ sdc1 $f28, THREAD_FPR28_LS64(\thread)
+ sdc1 $f30, THREAD_FPR30_LS64(\thread)
sw \tmp, THREAD_FCR31(\thread)
.endm
.macro fpu_save_16odd thread
.set push
.set mips64r2
- sdc1 $f1, THREAD_FPR1(\thread)
- sdc1 $f3, THREAD_FPR3(\thread)
- sdc1 $f5, THREAD_FPR5(\thread)
- sdc1 $f7, THREAD_FPR7(\thread)
- sdc1 $f9, THREAD_FPR9(\thread)
- sdc1 $f11, THREAD_FPR11(\thread)
- sdc1 $f13, THREAD_FPR13(\thread)
- sdc1 $f15, THREAD_FPR15(\thread)
- sdc1 $f17, THREAD_FPR17(\thread)
- sdc1 $f19, THREAD_FPR19(\thread)
- sdc1 $f21, THREAD_FPR21(\thread)
- sdc1 $f23, THREAD_FPR23(\thread)
- sdc1 $f25, THREAD_FPR25(\thread)
- sdc1 $f27, THREAD_FPR27(\thread)
- sdc1 $f29, THREAD_FPR29(\thread)
- sdc1 $f31, THREAD_FPR31(\thread)
+ sdc1 $f1, THREAD_FPR1_LS64(\thread)
+ sdc1 $f3, THREAD_FPR3_LS64(\thread)
+ sdc1 $f5, THREAD_FPR5_LS64(\thread)
+ sdc1 $f7, THREAD_FPR7_LS64(\thread)
+ sdc1 $f9, THREAD_FPR9_LS64(\thread)
+ sdc1 $f11, THREAD_FPR11_LS64(\thread)
+ sdc1 $f13, THREAD_FPR13_LS64(\thread)
+ sdc1 $f15, THREAD_FPR15_LS64(\thread)
+ sdc1 $f17, THREAD_FPR17_LS64(\thread)
+ sdc1 $f19, THREAD_FPR19_LS64(\thread)
+ sdc1 $f21, THREAD_FPR21_LS64(\thread)
+ sdc1 $f23, THREAD_FPR23_LS64(\thread)
+ sdc1 $f25, THREAD_FPR25_LS64(\thread)
+ sdc1 $f27, THREAD_FPR27_LS64(\thread)
+ sdc1 $f29, THREAD_FPR29_LS64(\thread)
+ sdc1 $f31, THREAD_FPR31_LS64(\thread)
.set pop
.endm
.macro fpu_save_double thread status tmp
-#if defined(CONFIG_MIPS64) || defined(CONFIG_CPU_MIPS32_R2)
+#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
sll \tmp, \status, 5
bgez \tmp, 10f
fpu_save_16odd \thread
@@ -117,49 +128,49 @@
.macro fpu_restore_16even thread tmp=t0
lw \tmp, THREAD_FCR31(\thread)
- ldc1 $f0, THREAD_FPR0(\thread)
- ldc1 $f2, THREAD_FPR2(\thread)
- ldc1 $f4, THREAD_FPR4(\thread)
- ldc1 $f6, THREAD_FPR6(\thread)
- ldc1 $f8, THREAD_FPR8(\thread)
- ldc1 $f10, THREAD_FPR10(\thread)
- ldc1 $f12, THREAD_FPR12(\thread)
- ldc1 $f14, THREAD_FPR14(\thread)
- ldc1 $f16, THREAD_FPR16(\thread)
- ldc1 $f18, THREAD_FPR18(\thread)
- ldc1 $f20, THREAD_FPR20(\thread)
- ldc1 $f22, THREAD_FPR22(\thread)
- ldc1 $f24, THREAD_FPR24(\thread)
- ldc1 $f26, THREAD_FPR26(\thread)
- ldc1 $f28, THREAD_FPR28(\thread)
- ldc1 $f30, THREAD_FPR30(\thread)
+ ldc1 $f0, THREAD_FPR0_LS64(\thread)
+ ldc1 $f2, THREAD_FPR2_LS64(\thread)
+ ldc1 $f4, THREAD_FPR4_LS64(\thread)
+ ldc1 $f6, THREAD_FPR6_LS64(\thread)
+ ldc1 $f8, THREAD_FPR8_LS64(\thread)
+ ldc1 $f10, THREAD_FPR10_LS64(\thread)
+ ldc1 $f12, THREAD_FPR12_LS64(\thread)
+ ldc1 $f14, THREAD_FPR14_LS64(\thread)
+ ldc1 $f16, THREAD_FPR16_LS64(\thread)
+ ldc1 $f18, THREAD_FPR18_LS64(\thread)
+ ldc1 $f20, THREAD_FPR20_LS64(\thread)
+ ldc1 $f22, THREAD_FPR22_LS64(\thread)
+ ldc1 $f24, THREAD_FPR24_LS64(\thread)
+ ldc1 $f26, THREAD_FPR26_LS64(\thread)
+ ldc1 $f28, THREAD_FPR28_LS64(\thread)
+ ldc1 $f30, THREAD_FPR30_LS64(\thread)
ctc1 \tmp, fcr31
.endm
.macro fpu_restore_16odd thread
.set push
.set mips64r2
- ldc1 $f1, THREAD_FPR1(\thread)
- ldc1 $f3, THREAD_FPR3(\thread)
- ldc1 $f5, THREAD_FPR5(\thread)
- ldc1 $f7, THREAD_FPR7(\thread)
- ldc1 $f9, THREAD_FPR9(\thread)
- ldc1 $f11, THREAD_FPR11(\thread)
- ldc1 $f13, THREAD_FPR13(\thread)
- ldc1 $f15, THREAD_FPR15(\thread)
- ldc1 $f17, THREAD_FPR17(\thread)
- ldc1 $f19, THREAD_FPR19(\thread)
- ldc1 $f21, THREAD_FPR21(\thread)
- ldc1 $f23, THREAD_FPR23(\thread)
- ldc1 $f25, THREAD_FPR25(\thread)
- ldc1 $f27, THREAD_FPR27(\thread)
- ldc1 $f29, THREAD_FPR29(\thread)
- ldc1 $f31, THREAD_FPR31(\thread)
+ ldc1 $f1, THREAD_FPR1_LS64(\thread)
+ ldc1 $f3, THREAD_FPR3_LS64(\thread)
+ ldc1 $f5, THREAD_FPR5_LS64(\thread)
+ ldc1 $f7, THREAD_FPR7_LS64(\thread)
+ ldc1 $f9, THREAD_FPR9_LS64(\thread)
+ ldc1 $f11, THREAD_FPR11_LS64(\thread)
+ ldc1 $f13, THREAD_FPR13_LS64(\thread)
+ ldc1 $f15, THREAD_FPR15_LS64(\thread)
+ ldc1 $f17, THREAD_FPR17_LS64(\thread)
+ ldc1 $f19, THREAD_FPR19_LS64(\thread)
+ ldc1 $f21, THREAD_FPR21_LS64(\thread)
+ ldc1 $f23, THREAD_FPR23_LS64(\thread)
+ ldc1 $f25, THREAD_FPR25_LS64(\thread)
+ ldc1 $f27, THREAD_FPR27_LS64(\thread)
+ ldc1 $f29, THREAD_FPR29_LS64(\thread)
+ ldc1 $f31, THREAD_FPR31_LS64(\thread)
.set pop
.endm
.macro fpu_restore_double thread status tmp
-#if defined(CONFIG_MIPS64) || defined(CONFIG_CPU_MIPS32_R2)
+#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
sll \tmp, \status, 5
bgez \tmp, 10f # 16 register mode?
@@ -169,6 +180,17 @@
fpu_restore_16even \thread \tmp
.endm
+#ifdef CONFIG_CPU_MIPSR2
+ .macro _EXT rd, rs, p, s
+ ext \rd, \rs, \p, \s
+ .endm
+#else /* !CONFIG_CPU_MIPSR2 */
+ .macro _EXT rd, rs, p, s
+ srl \rd, \rs, \p
+ andi \rd, \rd, (1 << \s) - 1
+ .endm
+#endif /* !CONFIG_CPU_MIPSR2 */
+
/*
* Temporary until all gas have MT ASE support
*/
@@ -196,4 +218,195 @@
.word 0x41800000 | (\rt << 16) | (\rd << 11) | (\u << 5) | (\sel)
.endm
+#ifdef TOOLCHAIN_SUPPORTS_MSA
+ .macro ld_d wd, off, base
+ .set push
+ .set mips32r2
+ .set msa
+ ld.d $w\wd, \off(\base)
+ .set pop
+ .endm
+
+ .macro st_d wd, off, base
+ .set push
+ .set mips32r2
+ .set msa
+ st.d $w\wd, \off(\base)
+ .set pop
+ .endm
+
+ .macro copy_u_w rd, ws, n
+ .set push
+ .set mips32r2
+ .set msa
+ copy_u.w \rd, $w\ws[\n]
+ .set pop
+ .endm
+
+ .macro copy_u_d rd, ws, n
+ .set push
+ .set mips64r2
+ .set msa
+ copy_u.d \rd, $w\ws[\n]
+ .set pop
+ .endm
+
+ .macro insert_w wd, n, rs
+ .set push
+ .set mips32r2
+ .set msa
+ insert.w $w\wd[\n], \rs
+ .set pop
+ .endm
+
+ .macro insert_d wd, n, rs
+ .set push
+ .set mips64r2
+ .set msa
+ insert.d $w\wd[\n], \rs
+ .set pop
+ .endm
+#else
+ /*
+ * Temporary until all toolchains in use include MSA support.
+ */
+ .macro cfcmsa rd, cs
+ .set push
+ .set noat
+ .word 0x787e0059 | (\cs << 11)
+ move \rd, $1
+ .set pop
+ .endm
+
+ .macro ctcmsa cd, rs
+ .set push
+ .set noat
+ move $1, \rs
+ .word 0x783e0819 | (\cd << 6)
+ .set pop
+ .endm
+
+ .macro ld_d wd, off, base
+ .set push
+ .set noat
+ add $1, \base, \off
+ .word 0x78000823 | (\wd << 6)
+ .set pop
+ .endm
+
+ .macro st_d wd, off, base
+ .set push
+ .set noat
+ add $1, \base, \off
+ .word 0x78000827 | (\wd << 6)
+ .set pop
+ .endm
+
+ .macro copy_u_w rd, ws, n
+ .set push
+ .set noat
+ .word 0x78f00059 | (\n << 16) | (\ws << 11)
+ /* move triggers an assembler bug... */
+ or \rd, $1, zero
+ .set pop
+ .endm
+
+ .macro copy_u_d rd, ws, n
+ .set push
+ .set noat
+ .word 0x78f80059 | (\n << 16) | (\ws << 11)
+ /* move triggers an assembler bug... */
+ or \rd, $1, zero
+ .set pop
+ .endm
+
+ .macro insert_w wd, n, rs
+ .set push
+ .set noat
+ /* move triggers an assembler bug... */
+ or $1, \rs, zero
+ .word 0x79300819 | (\n << 16) | (\wd << 6)
+ .set pop
+ .endm
+
+ .macro insert_d wd, n, rs
+ .set push
+ .set noat
+ /* move triggers an assembler bug... */
+ or $1, \rs, zero
+ .word 0x79380819 | (\n << 16) | (\wd << 6)
+ .set pop
+ .endm
+#endif
+
+ .macro msa_save_all thread
+ st_d 0, THREAD_FPR0, \thread
+ st_d 1, THREAD_FPR1, \thread
+ st_d 2, THREAD_FPR2, \thread
+ st_d 3, THREAD_FPR3, \thread
+ st_d 4, THREAD_FPR4, \thread
+ st_d 5, THREAD_FPR5, \thread
+ st_d 6, THREAD_FPR6, \thread
+ st_d 7, THREAD_FPR7, \thread
+ st_d 8, THREAD_FPR8, \thread
+ st_d 9, THREAD_FPR9, \thread
+ st_d 10, THREAD_FPR10, \thread
+ st_d 11, THREAD_FPR11, \thread
+ st_d 12, THREAD_FPR12, \thread
+ st_d 13, THREAD_FPR13, \thread
+ st_d 14, THREAD_FPR14, \thread
+ st_d 15, THREAD_FPR15, \thread
+ st_d 16, THREAD_FPR16, \thread
+ st_d 17, THREAD_FPR17, \thread
+ st_d 18, THREAD_FPR18, \thread
+ st_d 19, THREAD_FPR19, \thread
+ st_d 20, THREAD_FPR20, \thread
+ st_d 21, THREAD_FPR21, \thread
+ st_d 22, THREAD_FPR22, \thread
+ st_d 23, THREAD_FPR23, \thread
+ st_d 24, THREAD_FPR24, \thread
+ st_d 25, THREAD_FPR25, \thread
+ st_d 26, THREAD_FPR26, \thread
+ st_d 27, THREAD_FPR27, \thread
+ st_d 28, THREAD_FPR28, \thread
+ st_d 29, THREAD_FPR29, \thread
+ st_d 30, THREAD_FPR30, \thread
+ st_d 31, THREAD_FPR31, \thread
+ .endm
+
+ .macro msa_restore_all thread
+ ld_d 0, THREAD_FPR0, \thread
+ ld_d 1, THREAD_FPR1, \thread
+ ld_d 2, THREAD_FPR2, \thread
+ ld_d 3, THREAD_FPR3, \thread
+ ld_d 4, THREAD_FPR4, \thread
+ ld_d 5, THREAD_FPR5, \thread
+ ld_d 6, THREAD_FPR6, \thread
+ ld_d 7, THREAD_FPR7, \thread
+ ld_d 8, THREAD_FPR8, \thread
+ ld_d 9, THREAD_FPR9, \thread
+ ld_d 10, THREAD_FPR10, \thread
+ ld_d 11, THREAD_FPR11, \thread
+ ld_d 12, THREAD_FPR12, \thread
+ ld_d 13, THREAD_FPR13, \thread
+ ld_d 14, THREAD_FPR14, \thread
+ ld_d 15, THREAD_FPR15, \thread
+ ld_d 16, THREAD_FPR16, \thread
+ ld_d 17, THREAD_FPR17, \thread
+ ld_d 18, THREAD_FPR18, \thread
+ ld_d 19, THREAD_FPR19, \thread
+ ld_d 20, THREAD_FPR20, \thread
+ ld_d 21, THREAD_FPR21, \thread
+ ld_d 22, THREAD_FPR22, \thread
+ ld_d 23, THREAD_FPR23, \thread
+ ld_d 24, THREAD_FPR24, \thread
+ ld_d 25, THREAD_FPR25, \thread
+ ld_d 26, THREAD_FPR26, \thread
+ ld_d 27, THREAD_FPR27, \thread
+ ld_d 28, THREAD_FPR28, \thread
+ ld_d 29, THREAD_FPR29, \thread
+ ld_d 30, THREAD_FPR30, \thread
+ ld_d 31, THREAD_FPR31, \thread
+ .endm
+
#endif /* _ASM_ASMMACRO_H */
diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h
index 7eed2f261710..e8eb3d53a241 100644
--- a/arch/mips/include/asm/atomic.h
+++ b/arch/mips/include/asm/atomic.h
@@ -53,7 +53,7 @@ static __inline__ void atomic_add(int i, atomic_t * v)
int temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %0, %1 # atomic_add \n"
" addu %0, %2 \n"
" sc %0, %1 \n"
@@ -66,7 +66,7 @@ static __inline__ void atomic_add(int i, atomic_t * v)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" ll %0, %1 # atomic_add \n"
" addu %0, %2 \n"
" sc %0, %1 \n"
@@ -96,7 +96,7 @@ static __inline__ void atomic_sub(int i, atomic_t * v)
int temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %0, %1 # atomic_sub \n"
" subu %0, %2 \n"
" sc %0, %1 \n"
@@ -109,7 +109,7 @@ static __inline__ void atomic_sub(int i, atomic_t * v)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" ll %0, %1 # atomic_sub \n"
" subu %0, %2 \n"
" sc %0, %1 \n"
@@ -139,7 +139,7 @@ static __inline__ int atomic_add_return(int i, atomic_t * v)
int temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %1, %2 # atomic_add_return \n"
" addu %0, %1, %3 \n"
" sc %0, %2 \n"
@@ -153,7 +153,7 @@ static __inline__ int atomic_add_return(int i, atomic_t * v)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" ll %1, %2 # atomic_add_return \n"
" addu %0, %1, %3 \n"
" sc %0, %2 \n"
@@ -188,7 +188,7 @@ static __inline__ int atomic_sub_return(int i, atomic_t * v)
int temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %1, %2 # atomic_sub_return \n"
" subu %0, %1, %3 \n"
" sc %0, %2 \n"
@@ -205,7 +205,7 @@ static __inline__ int atomic_sub_return(int i, atomic_t * v)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" ll %1, %2 # atomic_sub_return \n"
" subu %0, %1, %3 \n"
" sc %0, %2 \n"
@@ -248,7 +248,7 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
int temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %1, %2 # atomic_sub_if_positive\n"
" subu %0, %1, %3 \n"
" bltz %0, 1f \n"
@@ -266,7 +266,7 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
int temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %1, %2 # atomic_sub_if_positive\n"
" subu %0, %1, %3 \n"
" bltz %0, 1f \n"
@@ -420,7 +420,7 @@ static __inline__ void atomic64_add(long i, atomic64_t * v)
long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: lld %0, %1 # atomic64_add \n"
" daddu %0, %2 \n"
" scd %0, %1 \n"
@@ -433,7 +433,7 @@ static __inline__ void atomic64_add(long i, atomic64_t * v)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" lld %0, %1 # atomic64_add \n"
" daddu %0, %2 \n"
" scd %0, %1 \n"
@@ -463,7 +463,7 @@ static __inline__ void atomic64_sub(long i, atomic64_t * v)
long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: lld %0, %1 # atomic64_sub \n"
" dsubu %0, %2 \n"
" scd %0, %1 \n"
@@ -476,7 +476,7 @@ static __inline__ void atomic64_sub(long i, atomic64_t * v)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" lld %0, %1 # atomic64_sub \n"
" dsubu %0, %2 \n"
" scd %0, %1 \n"
@@ -506,7 +506,7 @@ static __inline__ long atomic64_add_return(long i, atomic64_t * v)
long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: lld %1, %2 # atomic64_add_return \n"
" daddu %0, %1, %3 \n"
" scd %0, %2 \n"
@@ -520,7 +520,7 @@ static __inline__ long atomic64_add_return(long i, atomic64_t * v)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" lld %1, %2 # atomic64_add_return \n"
" daddu %0, %1, %3 \n"
" scd %0, %2 \n"
@@ -556,7 +556,7 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: lld %1, %2 # atomic64_sub_return \n"
" dsubu %0, %1, %3 \n"
" scd %0, %2 \n"
@@ -571,7 +571,7 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" lld %1, %2 # atomic64_sub_return \n"
" dsubu %0, %1, %3 \n"
" scd %0, %2 \n"
@@ -615,7 +615,7 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: lld %1, %2 # atomic64_sub_if_positive\n"
" dsubu %0, %1, %3 \n"
" bltz %0, 1f \n"
@@ -633,7 +633,7 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: lld %1, %2 # atomic64_sub_if_positive\n"
" dsubu %0, %1, %3 \n"
" bltz %0, 1f \n"
diff --git a/arch/mips/include/asm/bitops.h b/arch/mips/include/asm/bitops.h
index 71305a8b3d78..6a65d49e2c0d 100644
--- a/arch/mips/include/asm/bitops.h
+++ b/arch/mips/include/asm/bitops.h
@@ -79,7 +79,7 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
if (kernel_uses_llsc && R10000_LLSC_WAR) {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: " __LL "%0, %1 # set_bit \n"
" or %0, %2 \n"
" " __SC "%0, %1 \n"
@@ -101,7 +101,7 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
} else if (kernel_uses_llsc) {
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" " __LL "%0, %1 # set_bit \n"
" or %0, %2 \n"
" " __SC "%0, %1 \n"
@@ -131,7 +131,7 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
if (kernel_uses_llsc && R10000_LLSC_WAR) {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: " __LL "%0, %1 # clear_bit \n"
" and %0, %2 \n"
" " __SC "%0, %1 \n"
@@ -153,7 +153,7 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
} else if (kernel_uses_llsc) {
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" " __LL "%0, %1 # clear_bit \n"
" and %0, %2 \n"
" " __SC "%0, %1 \n"
@@ -197,7 +197,7 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
unsigned long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: " __LL "%0, %1 # change_bit \n"
" xor %0, %2 \n"
" " __SC "%0, %1 \n"
@@ -211,7 +211,7 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" " __LL "%0, %1 # change_bit \n"
" xor %0, %2 \n"
" " __SC "%0, %1 \n"
@@ -244,7 +244,7 @@ static inline int test_and_set_bit(unsigned long nr,
unsigned long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: " __LL "%0, %1 # test_and_set_bit \n"
" or %2, %0, %3 \n"
" " __SC "%2, %1 \n"
@@ -260,7 +260,7 @@ static inline int test_and_set_bit(unsigned long nr,
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" " __LL "%0, %1 # test_and_set_bit \n"
" or %2, %0, %3 \n"
" " __SC "%2, %1 \n"
@@ -298,7 +298,7 @@ static inline int test_and_set_bit_lock(unsigned long nr,
unsigned long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: " __LL "%0, %1 # test_and_set_bit \n"
" or %2, %0, %3 \n"
" " __SC "%2, %1 \n"
@@ -314,7 +314,7 @@ static inline int test_and_set_bit_lock(unsigned long nr,
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" " __LL "%0, %1 # test_and_set_bit \n"
" or %2, %0, %3 \n"
" " __SC "%2, %1 \n"
@@ -353,7 +353,7 @@ static inline int test_and_clear_bit(unsigned long nr,
unsigned long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: " __LL "%0, %1 # test_and_clear_bit \n"
" or %2, %0, %3 \n"
" xor %2, %3 \n"
@@ -386,7 +386,7 @@ static inline int test_and_clear_bit(unsigned long nr,
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" " __LL "%0, %1 # test_and_clear_bit \n"
" or %2, %0, %3 \n"
" xor %2, %3 \n"
@@ -427,7 +427,7 @@ static inline int test_and_change_bit(unsigned long nr,
unsigned long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: " __LL "%0, %1 # test_and_change_bit \n"
" xor %2, %0, %3 \n"
" " __SC "%2, %1 \n"
@@ -443,7 +443,7 @@ static inline int test_and_change_bit(unsigned long nr,
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" " __LL "%0, %1 # test_and_change_bit \n"
" xor %2, %0, %3 \n"
" " __SC "\t%2, %1 \n"
diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h
index 4d2cdea5aa37..1f7ca8b00404 100644
--- a/arch/mips/include/asm/bootinfo.h
+++ b/arch/mips/include/asm/bootinfo.h
@@ -61,15 +61,21 @@
/*
* Valid machtype for Loongson family
*/
-#define MACH_LOONGSON_UNKNOWN 0
-#define MACH_LEMOTE_FL2E 1
-#define MACH_LEMOTE_FL2F 2
-#define MACH_LEMOTE_ML2F7 3
-#define MACH_LEMOTE_YL2F89 4
-#define MACH_DEXXON_GDIUM2F10 5
-#define MACH_LEMOTE_NAS 6
-#define MACH_LEMOTE_LL2F 7
-#define MACH_LOONGSON_END 8
+enum loongson_machine_type {
+ MACH_LOONGSON_UNKNOWN,
+ MACH_LEMOTE_FL2E,
+ MACH_LEMOTE_FL2F,
+ MACH_LEMOTE_ML2F7,
+ MACH_LEMOTE_YL2F89,
+ MACH_DEXXON_GDIUM2F10,
+ MACH_LEMOTE_NAS,
+ MACH_LEMOTE_LL2F,
+ MACH_LEMOTE_A1004,
+ MACH_LEMOTE_A1101,
+ MACH_LEMOTE_A1201,
+ MACH_LEMOTE_A1205,
+ MACH_LOONGSON_END
+};
/*
* Valid machtype for group INGENIC
@@ -112,6 +118,8 @@ extern void prom_free_prom_memory(void);
extern void free_init_pages(const char *what,
unsigned long begin, unsigned long end);
+extern void (*free_init_pages_eva)(void *begin, void *end);
+
/*
* Initial kernel command line, usually setup by prom_init()
*/
diff --git a/arch/mips/include/asm/checksum.h b/arch/mips/include/asm/checksum.h
index ac3d2b8a20d4..3418c51e1151 100644
--- a/arch/mips/include/asm/checksum.h
+++ b/arch/mips/include/asm/checksum.h
@@ -7,6 +7,7 @@
* Copyright (C) 1999 Silicon Graphics, Inc.
* Copyright (C) 2001 Thiemo Seufer.
* Copyright (C) 2002 Maciej W. Rozycki
+ * Copyright (C) 2014 Imagination Technologies Ltd.
*/
#ifndef _ASM_CHECKSUM_H
#define _ASM_CHECKSUM_H
@@ -29,9 +30,13 @@
*/
__wsum csum_partial(const void *buff, int len, __wsum sum);
-__wsum __csum_partial_copy_user(const void *src, void *dst,
- int len, __wsum sum, int *err_ptr);
+__wsum __csum_partial_copy_kernel(const void *src, void *dst,
+ int len, __wsum sum, int *err_ptr);
+__wsum __csum_partial_copy_from_user(const void *src, void *dst,
+ int len, __wsum sum, int *err_ptr);
+__wsum __csum_partial_copy_to_user(const void *src, void *dst,
+ int len, __wsum sum, int *err_ptr);
/*
* this is a new version of the above that records errors it finds in *errp,
* but continues and zeros the rest of the buffer.
@@ -41,8 +46,26 @@ __wsum csum_partial_copy_from_user(const void __user *src, void *dst, int len,
__wsum sum, int *err_ptr)
{
might_fault();
- return __csum_partial_copy_user((__force void *)src, dst,
- len, sum, err_ptr);
+ if (segment_eq(get_fs(), get_ds()))
+ return __csum_partial_copy_kernel((__force void *)src, dst,
+ len, sum, err_ptr);
+ else
+ return __csum_partial_copy_from_user((__force void *)src, dst,
+ len, sum, err_ptr);
+}
+
+#define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
+static inline
+__wsum csum_and_copy_from_user(const void __user *src, void *dst,
+ int len, __wsum sum, int *err_ptr)
+{
+ if (access_ok(VERIFY_READ, src, len))
+ return csum_partial_copy_from_user(src, dst, len, sum,
+ err_ptr);
+ if (len)
+ *err_ptr = -EFAULT;
+
+ return sum;
}
/*
@@ -54,9 +77,16 @@ __wsum csum_and_copy_to_user(const void *src, void __user *dst, int len,
__wsum sum, int *err_ptr)
{
might_fault();
- if (access_ok(VERIFY_WRITE, dst, len))
- return __csum_partial_copy_user(src, (__force void *)dst,
- len, sum, err_ptr);
+ if (access_ok(VERIFY_WRITE, dst, len)) {
+ if (segment_eq(get_fs(), get_ds()))
+ return __csum_partial_copy_kernel(src,
+ (__force void *)dst,
+ len, sum, err_ptr);
+ else
+ return __csum_partial_copy_to_user(src,
+ (__force void *)dst,
+ len, sum, err_ptr);
+ }
if (len)
*err_ptr = -EFAULT;
diff --git a/arch/mips/include/asm/cmpxchg.h b/arch/mips/include/asm/cmpxchg.h
index 466069bd8465..eefcaa363a87 100644
--- a/arch/mips/include/asm/cmpxchg.h
+++ b/arch/mips/include/asm/cmpxchg.h
@@ -22,11 +22,11 @@ static inline unsigned long __xchg_u32(volatile int * m, unsigned int val)
unsigned long dummy;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %0, %3 # xchg_u32 \n"
" .set mips0 \n"
" move %2, %z4 \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" sc %2, %1 \n"
" beqzl %2, 1b \n"
" .set mips0 \n"
@@ -38,11 +38,11 @@ static inline unsigned long __xchg_u32(volatile int * m, unsigned int val)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" ll %0, %3 # xchg_u32 \n"
" .set mips0 \n"
" move %2, %z4 \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" sc %2, %1 \n"
" .set mips0 \n"
: "=&r" (retval), "=m" (*m), "=&r" (dummy)
@@ -74,7 +74,7 @@ static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val)
unsigned long dummy;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: lld %0, %3 # xchg_u64 \n"
" move %2, %z4 \n"
" scd %2, %1 \n"
@@ -88,7 +88,7 @@ static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" lld %0, %3 # xchg_u64 \n"
" move %2, %z4 \n"
" scd %2, %1 \n"
@@ -145,12 +145,12 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
__asm__ __volatile__( \
" .set push \n" \
" .set noat \n" \
- " .set mips3 \n" \
+ " .set arch=r4000 \n" \
"1: " ld " %0, %2 # __cmpxchg_asm \n" \
" bne %0, %z3, 2f \n" \
" .set mips0 \n" \
" move $1, %z4 \n" \
- " .set mips3 \n" \
+ " .set arch=r4000 \n" \
" " st " $1, %1 \n" \
" beqzl $1, 1b \n" \
"2: \n" \
@@ -162,12 +162,12 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
__asm__ __volatile__( \
" .set push \n" \
" .set noat \n" \
- " .set mips3 \n" \
+ " .set arch=r4000 \n" \
"1: " ld " %0, %2 # __cmpxchg_asm \n" \
" bne %0, %z3, 2f \n" \
" .set mips0 \n" \
" move $1, %z4 \n" \
- " .set mips3 \n" \
+ " .set arch=r4000 \n" \
" " st " $1, %1 \n" \
" beqz $1, 1b \n" \
" .set pop \n" \
diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h
index 6e70b03b6aab..f56cc975b92f 100644
--- a/arch/mips/include/asm/cpu-features.h
+++ b/arch/mips/include/asm/cpu-features.h
@@ -26,7 +26,9 @@
#ifndef cpu_has_segments
#define cpu_has_segments (cpu_data[0].options & MIPS_CPU_SEGMENTS)
#endif
-
+#ifndef cpu_has_eva
+#define cpu_has_eva (cpu_data[0].options & MIPS_CPU_EVA)
+#endif
/*
* For the moment we don't consider R6000 and R8000 so we can assume that
@@ -299,4 +301,10 @@
#define cpu_has_vz (cpu_data[0].ases & MIPS_ASE_VZ)
#endif
+#if defined(CONFIG_CPU_HAS_MSA) && !defined(cpu_has_msa)
+# define cpu_has_msa (cpu_data[0].ases & MIPS_ASE_MSA)
+#elif !defined(cpu_has_msa)
+# define cpu_has_msa 0
+#endif
+
#endif /* __ASM_CPU_FEATURES_H */
diff --git a/arch/mips/include/asm/cpu-info.h b/arch/mips/include/asm/cpu-info.h
index 8f7adf0ac1e3..dc2135be2a3a 100644
--- a/arch/mips/include/asm/cpu-info.h
+++ b/arch/mips/include/asm/cpu-info.h
@@ -49,6 +49,7 @@ struct cpuinfo_mips {
unsigned long ases;
unsigned int processor_id;
unsigned int fpu_id;
+ unsigned int msa_id;
unsigned int cputype;
int isa_level;
int tlbsize;
@@ -95,4 +96,31 @@ extern void cpu_report(void);
extern const char *__cpu_name[];
#define cpu_name_string() __cpu_name[smp_processor_id()]
+struct seq_file;
+struct notifier_block;
+
+extern int register_proc_cpuinfo_notifier(struct notifier_block *nb);
+extern int proc_cpuinfo_notifier_call_chain(unsigned long val, void *v);
+
+#define proc_cpuinfo_notifier(fn, pri) \
+({ \
+ static struct notifier_block fn##_nb = { \
+ .notifier_call = fn, \
+ .priority = pri \
+ }; \
+ \
+ register_proc_cpuinfo_notifier(&fn##_nb); \
+})
+
+struct proc_cpuinfo_notifier_args {
+ struct seq_file *m;
+ unsigned long n;
+};
+
+#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC)
+# define cpu_vpe_id(cpuinfo) ((cpuinfo)->vpe_id)
+#else
+# define cpu_vpe_id(cpuinfo) 0
+#endif
+
#endif /* __ASM_CPU_INFO_H */
diff --git a/arch/mips/include/asm/cpu-type.h b/arch/mips/include/asm/cpu-type.h
index 02f591bd95ca..721906130a57 100644
--- a/arch/mips/include/asm/cpu-type.h
+++ b/arch/mips/include/asm/cpu-type.h
@@ -20,6 +20,10 @@ static inline int __pure __get_cpu_type(const int cpu_type)
case CPU_LOONGSON2:
#endif
+#ifdef CONFIG_SYS_HAS_CPU_LOONGSON3
+ case CPU_LOONGSON3:
+#endif
+
#ifdef CONFIG_SYS_HAS_CPU_LOONGSON1B
case CPU_LOONGSON1:
#endif
@@ -46,6 +50,8 @@ static inline int __pure __get_cpu_type(const int cpu_type)
case CPU_M14KEC:
case CPU_INTERAPTIV:
case CPU_PROAPTIV:
+ case CPU_P5600:
+ case CPU_M5150:
#endif
#ifdef CONFIG_SYS_HAS_CPU_MIPS64_R1
diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h
index 76411df3d971..530eb8b3a68e 100644
--- a/arch/mips/include/asm/cpu.h
+++ b/arch/mips/include/asm/cpu.h
@@ -82,10 +82,10 @@
#define PRID_IMP_RM7000 0x2700
#define PRID_IMP_NEVADA 0x2800 /* RM5260 ??? */
#define PRID_IMP_RM9000 0x3400
-#define PRID_IMP_LOONGSON1 0x4200
+#define PRID_IMP_LOONGSON_32 0x4200 /* Loongson-1 */
#define PRID_IMP_R5432 0x5400
#define PRID_IMP_R5500 0x5500
-#define PRID_IMP_LOONGSON2 0x6300
+#define PRID_IMP_LOONGSON_64 0x6300 /* Loongson-2/3 */
#define PRID_IMP_UNKNOWN 0xff00
@@ -115,6 +115,8 @@
#define PRID_IMP_INTERAPTIV_MP 0xa100
#define PRID_IMP_PROAPTIV_UP 0xa200
#define PRID_IMP_PROAPTIV_MP 0xa300
+#define PRID_IMP_M5150 0xa700
+#define PRID_IMP_P5600 0xa800
/*
* These are the PRID's for when 23:16 == PRID_COMP_SIBYTE
@@ -229,6 +231,7 @@
#define PRID_REV_LOONGSON1B 0x0020
#define PRID_REV_LOONGSON2E 0x0002
#define PRID_REV_LOONGSON2F 0x0003
+#define PRID_REV_LOONGSON3A 0x0005
/*
* Older processors used to encode processor version and revision in two
@@ -296,14 +299,14 @@ enum cpu_type_enum {
CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_1004K, CPU_74K,
CPU_ALCHEMY, CPU_PR4450, CPU_BMIPS32, CPU_BMIPS3300, CPU_BMIPS4350,
CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC, CPU_LOONGSON1, CPU_M14KC,
- CPU_M14KEC, CPU_INTERAPTIV, CPU_PROAPTIV,
+ CPU_M14KEC, CPU_INTERAPTIV, CPU_P5600, CPU_PROAPTIV, CPU_1074K, CPU_M5150,
/*
* MIPS64 class processors
*/
CPU_5KC, CPU_5KE, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2,
- CPU_CAVIUM_OCTEON, CPU_CAVIUM_OCTEON_PLUS, CPU_CAVIUM_OCTEON2,
- CPU_CAVIUM_OCTEON3, CPU_XLR, CPU_XLP,
+ CPU_LOONGSON3, CPU_CAVIUM_OCTEON, CPU_CAVIUM_OCTEON_PLUS,
+ CPU_CAVIUM_OCTEON2, CPU_CAVIUM_OCTEON3, CPU_XLR, CPU_XLP,
CPU_LAST
};
@@ -358,6 +361,7 @@ enum cpu_type_enum {
#define MIPS_CPU_MICROMIPS 0x01000000 /* CPU has microMIPS capability */
#define MIPS_CPU_TLBINV 0x02000000 /* CPU supports TLBINV/F */
#define MIPS_CPU_SEGMENTS 0x04000000 /* CPU supports Segmentation Control registers */
+#define MIPS_CPU_EVA 0x80000000 /* CPU supports Enhanced Virtual Addressing */
/*
* CPU ASE encodings
@@ -370,5 +374,6 @@ enum cpu_type_enum {
#define MIPS_ASE_MIPSMT 0x00000020 /* CPU supports MIPS MT */
#define MIPS_ASE_DSP2P 0x00000040 /* Signal Processing ASE Rev 2 */
#define MIPS_ASE_VZ 0x00000080 /* Virtualization ASE */
+#define MIPS_ASE_MSA 0x00000100 /* MIPS SIMD Architecture */
#endif /* _ASM_CPU_H */
diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h
index 84238c574d5e..06412aa9e3fb 100644
--- a/arch/mips/include/asm/dma-mapping.h
+++ b/arch/mips/include/asm/dma-mapping.h
@@ -49,9 +49,14 @@ static inline int dma_mapping_error(struct device *dev, u64 mask)
static inline int
dma_set_mask(struct device *dev, u64 mask)
{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+
if(!dev->dma_mask || !dma_supported(dev, mask))
return -EIO;
+ if (ops->set_dma_mask)
+ return ops->set_dma_mask(dev, mask);
+
*dev->dma_mask = mask;
return 0;
diff --git a/arch/mips/include/asm/fpu.h b/arch/mips/include/asm/fpu.h
index 6b9749540edf..4d86b72750c7 100644
--- a/arch/mips/include/asm/fpu.h
+++ b/arch/mips/include/asm/fpu.h
@@ -57,7 +57,7 @@ static inline int __enable_fpu(enum fpu_mode mode)
return 0;
case FPU_64BIT:
-#if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_MIPS64))
+#if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_64BIT))
/* we only have a 32-bit FPU */
return SIGFPE;
#endif
@@ -180,7 +180,7 @@ static inline void restore_fp(struct task_struct *tsk)
_restore_fp(tsk);
}
-static inline fpureg_t *get_fpu_regs(struct task_struct *tsk)
+static inline union fpureg *get_fpu_regs(struct task_struct *tsk)
{
if (tsk == current) {
preempt_disable();
diff --git a/arch/mips/include/asm/ftrace.h b/arch/mips/include/asm/ftrace.h
index ce35c9af0c28..992aaba603b5 100644
--- a/arch/mips/include/asm/ftrace.h
+++ b/arch/mips/include/asm/ftrace.h
@@ -22,12 +22,12 @@ extern void _mcount(void);
#define safe_load(load, src, dst, error) \
do { \
asm volatile ( \
- "1: " load " %[" STR(dst) "], 0(%[" STR(src) "])\n"\
- " li %[" STR(error) "], 0\n" \
+ "1: " load " %[tmp_dst], 0(%[tmp_src])\n" \
+ " li %[tmp_err], 0\n" \
"2:\n" \
\
".section .fixup, \"ax\"\n" \
- "3: li %[" STR(error) "], 1\n" \
+ "3: li %[tmp_err], 1\n" \
" j 2b\n" \
".previous\n" \
\
@@ -35,8 +35,8 @@ do { \
STR(PTR) "\t1b, 3b\n\t" \
".previous\n" \
\
- : [dst] "=&r" (dst), [error] "=r" (error)\
- : [src] "r" (src) \
+ : [tmp_dst] "=&r" (dst), [tmp_err] "=r" (error)\
+ : [tmp_src] "r" (src) \
: "memory" \
); \
} while (0)
@@ -44,12 +44,12 @@ do { \
#define safe_store(store, src, dst, error) \
do { \
asm volatile ( \
- "1: " store " %[" STR(src) "], 0(%[" STR(dst) "])\n"\
- " li %[" STR(error) "], 0\n" \
+ "1: " store " %[tmp_src], 0(%[tmp_dst])\n"\
+ " li %[tmp_err], 0\n" \
"2:\n" \
\
".section .fixup, \"ax\"\n" \
- "3: li %[" STR(error) "], 1\n" \
+ "3: li %[tmp_err], 1\n" \
" j 2b\n" \
".previous\n" \
\
@@ -57,8 +57,8 @@ do { \
STR(PTR) "\t1b, 3b\n\t" \
".previous\n" \
\
- : [error] "=r" (error) \
- : [dst] "r" (dst), [src] "r" (src)\
+ : [tmp_err] "=r" (error) \
+ : [tmp_dst] "r" (dst), [tmp_src] "r" (src)\
: "memory" \
); \
} while (0)
diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h
index 6ea15815d3ee..194cda0396a3 100644
--- a/arch/mips/include/asm/futex.h
+++ b/arch/mips/include/asm/futex.h
@@ -12,6 +12,7 @@
#include <linux/futex.h>
#include <linux/uaccess.h>
+#include <asm/asm-eva.h>
#include <asm/barrier.h>
#include <asm/errno.h>
#include <asm/war.h>
@@ -22,11 +23,11 @@
__asm__ __volatile__( \
" .set push \n" \
" .set noat \n" \
- " .set mips3 \n" \
+ " .set arch=r4000 \n" \
"1: ll %1, %4 # __futex_atomic_op \n" \
" .set mips0 \n" \
" " insn " \n" \
- " .set mips3 \n" \
+ " .set arch=r4000 \n" \
"2: sc $1, %2 \n" \
" beqzl $1, 1b \n" \
__WEAK_LLSC_MB \
@@ -48,12 +49,12 @@
__asm__ __volatile__( \
" .set push \n" \
" .set noat \n" \
- " .set mips3 \n" \
- "1: ll %1, %4 # __futex_atomic_op \n" \
+ " .set arch=r4000 \n" \
+ "1: "user_ll("%1", "%4")" # __futex_atomic_op\n" \
" .set mips0 \n" \
" " insn " \n" \
- " .set mips3 \n" \
- "2: sc $1, %2 \n" \
+ " .set arch=r4000 \n" \
+ "2: "user_sc("$1", "%2")" \n" \
" beqz $1, 1b \n" \
__WEAK_LLSC_MB \
"3: \n" \
@@ -146,12 +147,12 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
"# futex_atomic_cmpxchg_inatomic \n"
" .set push \n"
" .set noat \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %1, %3 \n"
" bne %1, %z4, 3f \n"
" .set mips0 \n"
" move $1, %z5 \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"2: sc $1, %2 \n"
" beqzl $1, 1b \n"
__WEAK_LLSC_MB
@@ -173,13 +174,13 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
"# futex_atomic_cmpxchg_inatomic \n"
" .set push \n"
" .set noat \n"
- " .set mips3 \n"
- "1: ll %1, %3 \n"
+ " .set arch=r4000 \n"
+ "1: "user_ll("%1", "%3")" \n"
" bne %1, %z4, 3f \n"
" .set mips0 \n"
" move $1, %z5 \n"
- " .set mips3 \n"
- "2: sc $1, %2 \n"
+ " .set arch=r4000 \n"
+ "2: "user_sc("$1", "%2")" \n"
" beqz $1, 1b \n"
__WEAK_LLSC_MB
"3: \n"
diff --git a/arch/mips/include/asm/fw/fw.h b/arch/mips/include/asm/fw/fw.h
index d6c50a7e9ede..f3e6978aad70 100644
--- a/arch/mips/include/asm/fw/fw.h
+++ b/arch/mips/include/asm/fw/fw.h
@@ -38,7 +38,7 @@ extern int *_fw_envp;
extern void fw_init_cmdline(void);
extern char *fw_getcmdline(void);
-extern fw_memblock_t *fw_getmdesc(void);
+extern fw_memblock_t *fw_getmdesc(int);
extern void fw_meminit(void);
extern char *fw_getenv(char *name);
extern unsigned long fw_getenvl(char *name);
diff --git a/arch/mips/include/asm/gcmpregs.h b/arch/mips/include/asm/gcmpregs.h
deleted file mode 100644
index a7359f77a48e..000000000000
--- a/arch/mips/include/asm/gcmpregs.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000, 07 MIPS Technologies, Inc.
- *
- * Multiprocessor Subsystem Register Definitions
- *
- */
-#ifndef _ASM_GCMPREGS_H
-#define _ASM_GCMPREGS_H
-
-
-/* Offsets to major blocks within GCMP from GCMP base */
-#define GCMP_GCB_OFS 0x0000 /* Global Control Block */
-#define GCMP_CLCB_OFS 0x2000 /* Core Local Control Block */
-#define GCMP_COCB_OFS 0x4000 /* Core Other Control Block */
-#define GCMP_GDB_OFS 0x8000 /* Global Debug Block */
-
-/* Offsets to individual GCMP registers from GCMP base */
-#define GCMPOFS(block, tag, reg) \
- (GCMP_##block##_OFS + GCMP_##tag##_##reg##_OFS)
-#define GCMPOFSn(block, tag, reg, n) \
- (GCMP_##block##_OFS + GCMP_##tag##_##reg##_OFS(n))
-
-#define GCMPGCBOFS(reg) GCMPOFS(GCB, GCB, reg)
-#define GCMPGCBOFSn(reg, n) GCMPOFSn(GCB, GCB, reg, n)
-#define GCMPCLCBOFS(reg) GCMPOFS(CLCB, CCB, reg)
-#define GCMPCOCBOFS(reg) GCMPOFS(COCB, CCB, reg)
-#define GCMPGDBOFS(reg) GCMPOFS(GDB, GDB, reg)
-
-/* GCMP register access */
-#define GCMPGCB(reg) REGP(_gcmp_base, GCMPGCBOFS(reg))
-#define GCMPGCBn(reg, n) REGP(_gcmp_base, GCMPGCBOFSn(reg, n))
-#define GCMPCLCB(reg) REGP(_gcmp_base, GCMPCLCBOFS(reg))
-#define GCMPCOCB(reg) REGP(_gcmp_base, GCMPCOCBOFS(reg))
-#define GCMPGDB(reg) REGP(_gcmp_base, GCMPGDBOFS(reg))
-
-/* Mask generation */
-#define GCMPMSK(block, reg, bits) (MSK(bits)<<GCMP_##block##_##reg##_SHF)
-#define GCMPGCBMSK(reg, bits) GCMPMSK(GCB, reg, bits)
-#define GCMPCCBMSK(reg, bits) GCMPMSK(CCB, reg, bits)
-#define GCMPGDBMSK(reg, bits) GCMPMSK(GDB, reg, bits)
-
-/* GCB registers */
-#define GCMP_GCB_GC_OFS 0x0000 /* Global Config Register */
-#define GCMP_GCB_GC_NUMIOCU_SHF 8
-#define GCMP_GCB_GC_NUMIOCU_MSK GCMPGCBMSK(GC_NUMIOCU, 4)
-#define GCMP_GCB_GC_NUMCORES_SHF 0
-#define GCMP_GCB_GC_NUMCORES_MSK GCMPGCBMSK(GC_NUMCORES, 8)
-#define GCMP_GCB_GCMPB_OFS 0x0008 /* Global GCMP Base */
-#define GCMP_GCB_GCMPB_GCMPBASE_SHF 15
-#define GCMP_GCB_GCMPB_GCMPBASE_MSK GCMPGCBMSK(GCMPB_GCMPBASE, 17)
-#define GCMP_GCB_GCMPB_CMDEFTGT_SHF 0
-#define GCMP_GCB_GCMPB_CMDEFTGT_MSK GCMPGCBMSK(GCMPB_CMDEFTGT, 2)
-#define GCMP_GCB_GCMPB_CMDEFTGT_DISABLED 0
-#define GCMP_GCB_GCMPB_CMDEFTGT_MEM 1
-#define GCMP_GCB_GCMPB_CMDEFTGT_IOCU1 2
-#define GCMP_GCB_GCMPB_CMDEFTGT_IOCU2 3
-#define GCMP_GCB_CCMC_OFS 0x0010 /* Global CM Control */
-#define GCMP_GCB_GCSRAP_OFS 0x0020 /* Global CSR Access Privilege */
-#define GCMP_GCB_GCSRAP_CMACCESS_SHF 0
-#define GCMP_GCB_GCSRAP_CMACCESS_MSK GCMPGCBMSK(GCSRAP_CMACCESS, 8)
-#define GCMP_GCB_GCMPREV_OFS 0x0030 /* GCMP Revision Register */
-#define GCMP_GCB_GCMEM_OFS 0x0040 /* Global CM Error Mask */
-#define GCMP_GCB_GCMEC_OFS 0x0048 /* Global CM Error Cause */
-#define GCMP_GCB_GMEC_ERROR_TYPE_SHF 27
-#define GCMP_GCB_GMEC_ERROR_TYPE_MSK GCMPGCBMSK(GMEC_ERROR_TYPE, 5)
-#define GCMP_GCB_GMEC_ERROR_INFO_SHF 0
-#define GCMP_GCB_GMEC_ERROR_INFO_MSK GCMPGCBMSK(GMEC_ERROR_INFO, 27)
-#define GCMP_GCB_GCMEA_OFS 0x0050 /* Global CM Error Address */
-#define GCMP_GCB_GCMEO_OFS 0x0058 /* Global CM Error Multiple */
-#define GCMP_GCB_GMEO_ERROR_2ND_SHF 0
-#define GCMP_GCB_GMEO_ERROR_2ND_MSK GCMPGCBMSK(GMEO_ERROR_2ND, 5)
-#define GCMP_GCB_GICBA_OFS 0x0080 /* Global Interrupt Controller Base Address */
-#define GCMP_GCB_GICBA_BASE_SHF 17
-#define GCMP_GCB_GICBA_BASE_MSK GCMPGCBMSK(GICBA_BASE, 15)
-#define GCMP_GCB_GICBA_EN_SHF 0
-#define GCMP_GCB_GICBA_EN_MSK GCMPGCBMSK(GICBA_EN, 1)
-
-/* GCB Regions */
-#define GCMP_GCB_CMxBASE_OFS(n) (0x0090+16*(n)) /* Global Region[0-3] Base Address */
-#define GCMP_GCB_CMxBASE_BASE_SHF 16
-#define GCMP_GCB_CMxBASE_BASE_MSK GCMPGCBMSK(CMxBASE_BASE, 16)
-#define GCMP_GCB_CMxMASK_OFS(n) (0x0098+16*(n)) /* Global Region[0-3] Address Mask */
-#define GCMP_GCB_CMxMASK_MASK_SHF 16
-#define GCMP_GCB_CMxMASK_MASK_MSK GCMPGCBMSK(CMxMASK_MASK, 16)
-#define GCMP_GCB_CMxMASK_CMREGTGT_SHF 0
-#define GCMP_GCB_CMxMASK_CMREGTGT_MSK GCMPGCBMSK(CMxMASK_CMREGTGT, 2)
-#define GCMP_GCB_CMxMASK_CMREGTGT_MEM 0
-#define GCMP_GCB_CMxMASK_CMREGTGT_MEM1 1
-#define GCMP_GCB_CMxMASK_CMREGTGT_IOCU1 2
-#define GCMP_GCB_CMxMASK_CMREGTGT_IOCU2 3
-
-
-/* Core local/Core other control block registers */
-#define GCMP_CCB_RESETR_OFS 0x0000 /* Reset Release */
-#define GCMP_CCB_RESETR_INRESET_SHF 0
-#define GCMP_CCB_RESETR_INRESET_MSK GCMPCCBMSK(RESETR_INRESET, 16)
-#define GCMP_CCB_COHCTL_OFS 0x0008 /* Coherence Control */
-#define GCMP_CCB_COHCTL_DOMAIN_SHF 0
-#define GCMP_CCB_COHCTL_DOMAIN_MSK GCMPCCBMSK(COHCTL_DOMAIN, 8)
-#define GCMP_CCB_CFG_OFS 0x0010 /* Config */
-#define GCMP_CCB_CFG_IOCUTYPE_SHF 10
-#define GCMP_CCB_CFG_IOCUTYPE_MSK GCMPCCBMSK(CFG_IOCUTYPE, 2)
-#define GCMP_CCB_CFG_IOCUTYPE_CPU 0
-#define GCMP_CCB_CFG_IOCUTYPE_NCIOCU 1
-#define GCMP_CCB_CFG_IOCUTYPE_CIOCU 2
-#define GCMP_CCB_CFG_NUMVPE_SHF 0
-#define GCMP_CCB_CFG_NUMVPE_MSK GCMPCCBMSK(CFG_NUMVPE, 10)
-#define GCMP_CCB_OTHER_OFS 0x0018 /* Other Address */
-#define GCMP_CCB_OTHER_CORENUM_SHF 16
-#define GCMP_CCB_OTHER_CORENUM_MSK GCMPCCBMSK(OTHER_CORENUM, 16)
-#define GCMP_CCB_RESETBASE_OFS 0x0020 /* Reset Exception Base */
-#define GCMP_CCB_RESETBASE_BEV_SHF 12
-#define GCMP_CCB_RESETBASE_BEV_MSK GCMPCCBMSK(RESETBASE_BEV, 20)
-#define GCMP_CCB_ID_OFS 0x0028 /* Identification */
-#define GCMP_CCB_DINTGROUP_OFS 0x0030 /* DINT Group Participate */
-#define GCMP_CCB_DBGGROUP_OFS 0x0100 /* DebugBreak Group */
-
-extern int __init gcmp_probe(unsigned long, unsigned long);
-extern int __init gcmp_niocu(void);
-extern void __init gcmp_setregion(int, unsigned long, unsigned long, int);
-#endif /* _ASM_GCMPREGS_H */
diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
index b2e3e93dd7d8..082716690589 100644
--- a/arch/mips/include/asm/gic.h
+++ b/arch/mips/include/asm/gic.h
@@ -11,6 +11,9 @@
#ifndef _ASM_GICREGS_H
#define _ASM_GICREGS_H
+#include <linux/bitmap.h>
+#include <linux/threads.h>
+
#undef GICISBYTELITTLEENDIAN
/* Constants */
diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h
index 3321dd5a8872..933b50e125a0 100644
--- a/arch/mips/include/asm/io.h
+++ b/arch/mips/include/asm/io.h
@@ -331,7 +331,7 @@ static inline void pfx##write##bwlq(type val, \
if (irq) \
local_irq_save(__flags); \
__asm__ __volatile__( \
- ".set mips3" "\t\t# __writeq""\n\t" \
+ ".set arch=r4000" "\t\t# __writeq""\n\t" \
"dsll32 %L0, %L0, 0" "\n\t" \
"dsrl32 %L0, %L0, 0" "\n\t" \
"dsll32 %M0, %M0, 0" "\n\t" \
@@ -361,7 +361,7 @@ static inline type pfx##read##bwlq(const volatile void __iomem *mem) \
if (irq) \
local_irq_save(__flags); \
__asm__ __volatile__( \
- ".set mips3" "\t\t# __readq" "\n\t" \
+ ".set arch=r4000" "\t\t# __readq" "\n\t" \
"ld %L0, %1" "\n\t" \
"dsra32 %M0, %L0, 0" "\n\t" \
"sll %L0, %L0, 0" "\n\t" \
@@ -584,7 +584,7 @@ static inline void memcpy_toio(volatile void __iomem *dst, const void *src, int
*
* This API used to be exported; it now is for arch code internal use only.
*/
-#ifdef CONFIG_DMA_NONCOHERENT
+#if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_DMA_MAYBE_COHERENT)
extern void (*_dma_cache_wback_inv)(unsigned long start, unsigned long size);
extern void (*_dma_cache_wback)(unsigned long start, unsigned long size);
@@ -603,7 +603,7 @@ extern void (*_dma_cache_inv)(unsigned long start, unsigned long size);
#define dma_cache_inv(start,size) \
do { (void) (start); (void) (size); } while (0)
-#endif /* CONFIG_DMA_NONCOHERENT */
+#endif /* CONFIG_DMA_NONCOHERENT || CONFIG_DMA_MAYBE_COHERENT */
/*
* Read a 32-bit register that requires a 64-bit read cycle on the bus.
diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h
index a995fce87791..060aaa6348d7 100644
--- a/arch/mips/include/asm/kvm_host.h
+++ b/arch/mips/include/asm/kvm_host.h
@@ -30,16 +30,16 @@
/* Special address that contains the comm page, used for reducing # of traps */
-#define KVM_GUEST_COMMPAGE_ADDR 0x0
+#define KVM_GUEST_COMMPAGE_ADDR 0x0
#define KVM_GUEST_KERNEL_MODE(vcpu) ((kvm_read_c0_guest_status(vcpu->arch.cop0) & (ST0_EXL | ST0_ERL)) || \
((kvm_read_c0_guest_status(vcpu->arch.cop0) & KSU_USER) == 0))
-#define KVM_GUEST_KUSEG 0x00000000UL
-#define KVM_GUEST_KSEG0 0x40000000UL
-#define KVM_GUEST_KSEG23 0x60000000UL
-#define KVM_GUEST_KSEGX(a) ((_ACAST32_(a)) & 0x60000000)
-#define KVM_GUEST_CPHYSADDR(a) ((_ACAST32_(a)) & 0x1fffffff)
+#define KVM_GUEST_KUSEG 0x00000000UL
+#define KVM_GUEST_KSEG0 0x40000000UL
+#define KVM_GUEST_KSEG23 0x60000000UL
+#define KVM_GUEST_KSEGX(a) ((_ACAST32_(a)) & 0x60000000)
+#define KVM_GUEST_CPHYSADDR(a) ((_ACAST32_(a)) & 0x1fffffff)
#define KVM_GUEST_CKSEG0ADDR(a) (KVM_GUEST_CPHYSADDR(a) | KVM_GUEST_KSEG0)
#define KVM_GUEST_CKSEG1ADDR(a) (KVM_GUEST_CPHYSADDR(a) | KVM_GUEST_KSEG1)
@@ -52,17 +52,17 @@
#define KVM_GUEST_KSEG1ADDR(a) (KVM_GUEST_CPHYSADDR(a) | KVM_GUEST_KSEG1)
#define KVM_GUEST_KSEG23ADDR(a) (KVM_GUEST_CPHYSADDR(a) | KVM_GUEST_KSEG23)
-#define KVM_INVALID_PAGE 0xdeadbeef
-#define KVM_INVALID_INST 0xdeadbeef
-#define KVM_INVALID_ADDR 0xdeadbeef
+#define KVM_INVALID_PAGE 0xdeadbeef
+#define KVM_INVALID_INST 0xdeadbeef
+#define KVM_INVALID_ADDR 0xdeadbeef
-#define KVM_MALTA_GUEST_RTC_ADDR 0xb8000070UL
+#define KVM_MALTA_GUEST_RTC_ADDR 0xb8000070UL
-#define GUEST_TICKS_PER_JIFFY (40000000/HZ)
-#define MS_TO_NS(x) (x * 1E6L)
+#define GUEST_TICKS_PER_JIFFY (40000000/HZ)
+#define MS_TO_NS(x) (x * 1E6L)
-#define CAUSEB_DC 27
-#define CAUSEF_DC (_ULCAST_(1) << 27)
+#define CAUSEB_DC 27
+#define CAUSEF_DC (_ULCAST_(1) << 27)
struct kvm;
struct kvm_run;
@@ -126,8 +126,8 @@ struct kvm_arch {
int commpage_tlb;
};
-#define N_MIPS_COPROC_REGS 32
-#define N_MIPS_COPROC_SEL 8
+#define N_MIPS_COPROC_REGS 32
+#define N_MIPS_COPROC_SEL 8
struct mips_coproc {
unsigned long reg[N_MIPS_COPROC_REGS][N_MIPS_COPROC_SEL];
@@ -139,124 +139,124 @@ struct mips_coproc {
/*
* Coprocessor 0 register names
*/
-#define MIPS_CP0_TLB_INDEX 0
-#define MIPS_CP0_TLB_RANDOM 1
-#define MIPS_CP0_TLB_LOW 2
-#define MIPS_CP0_TLB_LO0 2
-#define MIPS_CP0_TLB_LO1 3
-#define MIPS_CP0_TLB_CONTEXT 4
-#define MIPS_CP0_TLB_PG_MASK 5
-#define MIPS_CP0_TLB_WIRED 6
-#define MIPS_CP0_HWRENA 7
-#define MIPS_CP0_BAD_VADDR 8
-#define MIPS_CP0_COUNT 9
-#define MIPS_CP0_TLB_HI 10
-#define MIPS_CP0_COMPARE 11
-#define MIPS_CP0_STATUS 12
-#define MIPS_CP0_CAUSE 13
-#define MIPS_CP0_EXC_PC 14
-#define MIPS_CP0_PRID 15
-#define MIPS_CP0_CONFIG 16
-#define MIPS_CP0_LLADDR 17
-#define MIPS_CP0_WATCH_LO 18
-#define MIPS_CP0_WATCH_HI 19
-#define MIPS_CP0_TLB_XCONTEXT 20
-#define MIPS_CP0_ECC 26
-#define MIPS_CP0_CACHE_ERR 27
-#define MIPS_CP0_TAG_LO 28
-#define MIPS_CP0_TAG_HI 29
-#define MIPS_CP0_ERROR_PC 30
-#define MIPS_CP0_DEBUG 23
-#define MIPS_CP0_DEPC 24
-#define MIPS_CP0_PERFCNT 25
-#define MIPS_CP0_ERRCTL 26
-#define MIPS_CP0_DATA_LO 28
-#define MIPS_CP0_DATA_HI 29
-#define MIPS_CP0_DESAVE 31
-
-#define MIPS_CP0_CONFIG_SEL 0
-#define MIPS_CP0_CONFIG1_SEL 1
-#define MIPS_CP0_CONFIG2_SEL 2
-#define MIPS_CP0_CONFIG3_SEL 3
+#define MIPS_CP0_TLB_INDEX 0
+#define MIPS_CP0_TLB_RANDOM 1
+#define MIPS_CP0_TLB_LOW 2
+#define MIPS_CP0_TLB_LO0 2
+#define MIPS_CP0_TLB_LO1 3
+#define MIPS_CP0_TLB_CONTEXT 4
+#define MIPS_CP0_TLB_PG_MASK 5
+#define MIPS_CP0_TLB_WIRED 6
+#define MIPS_CP0_HWRENA 7
+#define MIPS_CP0_BAD_VADDR 8
+#define MIPS_CP0_COUNT 9
+#define MIPS_CP0_TLB_HI 10
+#define MIPS_CP0_COMPARE 11
+#define MIPS_CP0_STATUS 12
+#define MIPS_CP0_CAUSE 13
+#define MIPS_CP0_EXC_PC 14
+#define MIPS_CP0_PRID 15
+#define MIPS_CP0_CONFIG 16
+#define MIPS_CP0_LLADDR 17
+#define MIPS_CP0_WATCH_LO 18
+#define MIPS_CP0_WATCH_HI 19
+#define MIPS_CP0_TLB_XCONTEXT 20
+#define MIPS_CP0_ECC 26
+#define MIPS_CP0_CACHE_ERR 27
+#define MIPS_CP0_TAG_LO 28
+#define MIPS_CP0_TAG_HI 29
+#define MIPS_CP0_ERROR_PC 30
+#define MIPS_CP0_DEBUG 23
+#define MIPS_CP0_DEPC 24
+#define MIPS_CP0_PERFCNT 25
+#define MIPS_CP0_ERRCTL 26
+#define MIPS_CP0_DATA_LO 28
+#define MIPS_CP0_DATA_HI 29
+#define MIPS_CP0_DESAVE 31
+
+#define MIPS_CP0_CONFIG_SEL 0
+#define MIPS_CP0_CONFIG1_SEL 1
+#define MIPS_CP0_CONFIG2_SEL 2
+#define MIPS_CP0_CONFIG3_SEL 3
/* Config0 register bits */
-#define CP0C0_M 31
-#define CP0C0_K23 28
-#define CP0C0_KU 25
-#define CP0C0_MDU 20
-#define CP0C0_MM 17
-#define CP0C0_BM 16
-#define CP0C0_BE 15
-#define CP0C0_AT 13
-#define CP0C0_AR 10
-#define CP0C0_MT 7
-#define CP0C0_VI 3
-#define CP0C0_K0 0
+#define CP0C0_M 31
+#define CP0C0_K23 28
+#define CP0C0_KU 25
+#define CP0C0_MDU 20
+#define CP0C0_MM 17
+#define CP0C0_BM 16
+#define CP0C0_BE 15
+#define CP0C0_AT 13
+#define CP0C0_AR 10
+#define CP0C0_MT 7
+#define CP0C0_VI 3
+#define CP0C0_K0 0
/* Config1 register bits */
-#define CP0C1_M 31
-#define CP0C1_MMU 25
-#define CP0C1_IS 22
-#define CP0C1_IL 19
-#define CP0C1_IA 16
-#define CP0C1_DS 13
-#define CP0C1_DL 10
-#define CP0C1_DA 7
-#define CP0C1_C2 6
-#define CP0C1_MD 5
-#define CP0C1_PC 4
-#define CP0C1_WR 3
-#define CP0C1_CA 2
-#define CP0C1_EP 1
-#define CP0C1_FP 0
+#define CP0C1_M 31
+#define CP0C1_MMU 25
+#define CP0C1_IS 22
+#define CP0C1_IL 19
+#define CP0C1_IA 16
+#define CP0C1_DS 13
+#define CP0C1_DL 10
+#define CP0C1_DA 7
+#define CP0C1_C2 6
+#define CP0C1_MD 5
+#define CP0C1_PC 4
+#define CP0C1_WR 3
+#define CP0C1_CA 2
+#define CP0C1_EP 1
+#define CP0C1_FP 0
/* Config2 Register bits */
-#define CP0C2_M 31
-#define CP0C2_TU 28
-#define CP0C2_TS 24
-#define CP0C2_TL 20
-#define CP0C2_TA 16
-#define CP0C2_SU 12
-#define CP0C2_SS 8
-#define CP0C2_SL 4
-#define CP0C2_SA 0
+#define CP0C2_M 31
+#define CP0C2_TU 28
+#define CP0C2_TS 24
+#define CP0C2_TL 20
+#define CP0C2_TA 16
+#define CP0C2_SU 12
+#define CP0C2_SS 8
+#define CP0C2_SL 4
+#define CP0C2_SA 0
/* Config3 Register bits */
-#define CP0C3_M 31
-#define CP0C3_ISA_ON_EXC 16
-#define CP0C3_ULRI 13
-#define CP0C3_DSPP 10
-#define CP0C3_LPA 7
-#define CP0C3_VEIC 6
-#define CP0C3_VInt 5
-#define CP0C3_SP 4
-#define CP0C3_MT 2
-#define CP0C3_SM 1
-#define CP0C3_TL 0
+#define CP0C3_M 31
+#define CP0C3_ISA_ON_EXC 16
+#define CP0C3_ULRI 13
+#define CP0C3_DSPP 10
+#define CP0C3_LPA 7
+#define CP0C3_VEIC 6
+#define CP0C3_VInt 5
+#define CP0C3_SP 4
+#define CP0C3_MT 2
+#define CP0C3_SM 1
+#define CP0C3_TL 0
/* Have config1, Cacheable, noncoherent, write-back, write allocate*/
-#define MIPS_CONFIG0 \
+#define MIPS_CONFIG0 \
((1 << CP0C0_M) | (0x3 << CP0C0_K0))
/* Have config2, no coprocessor2 attached, no MDMX support attached,
no performance counters, watch registers present,
no code compression, EJTAG present, no FPU, no watch registers */
-#define MIPS_CONFIG1 \
-((1 << CP0C1_M) | \
- (0 << CP0C1_C2) | (0 << CP0C1_MD) | (0 << CP0C1_PC) | \
- (0 << CP0C1_WR) | (0 << CP0C1_CA) | (1 << CP0C1_EP) | \
+#define MIPS_CONFIG1 \
+((1 << CP0C1_M) | \
+ (0 << CP0C1_C2) | (0 << CP0C1_MD) | (0 << CP0C1_PC) | \
+ (0 << CP0C1_WR) | (0 << CP0C1_CA) | (1 << CP0C1_EP) | \
(0 << CP0C1_FP))
/* Have config3, no tertiary/secondary caches implemented */
-#define MIPS_CONFIG2 \
+#define MIPS_CONFIG2 \
((1 << CP0C2_M))
/* No config4, no DSP ASE, no large physaddr (PABITS),
no external interrupt controller, no vectored interrupts,
no 1kb pages, no SmartMIPS ASE, no trace logic */
-#define MIPS_CONFIG3 \
-((0 << CP0C3_M) | (0 << CP0C3_DSPP) | (0 << CP0C3_LPA) | \
- (0 << CP0C3_VEIC) | (0 << CP0C3_VInt) | (0 << CP0C3_SP) | \
+#define MIPS_CONFIG3 \
+((0 << CP0C3_M) | (0 << CP0C3_DSPP) | (0 << CP0C3_LPA) | \
+ (0 << CP0C3_VEIC) | (0 << CP0C3_VInt) | (0 << CP0C3_SP) | \
(0 << CP0C3_SM) | (0 << CP0C3_TL))
/* MMU types, the first four entries have the same layout as the
@@ -274,36 +274,36 @@ enum mips_mmu_types {
/*
* Trap codes
*/
-#define T_INT 0 /* Interrupt pending */
-#define T_TLB_MOD 1 /* TLB modified fault */
-#define T_TLB_LD_MISS 2 /* TLB miss on load or ifetch */
-#define T_TLB_ST_MISS 3 /* TLB miss on a store */
-#define T_ADDR_ERR_LD 4 /* Address error on a load or ifetch */
-#define T_ADDR_ERR_ST 5 /* Address error on a store */
-#define T_BUS_ERR_IFETCH 6 /* Bus error on an ifetch */
-#define T_BUS_ERR_LD_ST 7 /* Bus error on a load or store */
-#define T_SYSCALL 8 /* System call */
-#define T_BREAK 9 /* Breakpoint */
-#define T_RES_INST 10 /* Reserved instruction exception */
-#define T_COP_UNUSABLE 11 /* Coprocessor unusable */
-#define T_OVFLOW 12 /* Arithmetic overflow */
+#define T_INT 0 /* Interrupt pending */
+#define T_TLB_MOD 1 /* TLB modified fault */
+#define T_TLB_LD_MISS 2 /* TLB miss on load or ifetch */
+#define T_TLB_ST_MISS 3 /* TLB miss on a store */
+#define T_ADDR_ERR_LD 4 /* Address error on a load or ifetch */
+#define T_ADDR_ERR_ST 5 /* Address error on a store */
+#define T_BUS_ERR_IFETCH 6 /* Bus error on an ifetch */
+#define T_BUS_ERR_LD_ST 7 /* Bus error on a load or store */
+#define T_SYSCALL 8 /* System call */
+#define T_BREAK 9 /* Breakpoint */
+#define T_RES_INST 10 /* Reserved instruction exception */
+#define T_COP_UNUSABLE 11 /* Coprocessor unusable */
+#define T_OVFLOW 12 /* Arithmetic overflow */
/*
* Trap definitions added for r4000 port.
*/
-#define T_TRAP 13 /* Trap instruction */
-#define T_VCEI 14 /* Virtual coherency exception */
-#define T_FPE 15 /* Floating point exception */
-#define T_WATCH 23 /* Watch address reference */
-#define T_VCED 31 /* Virtual coherency data */
+#define T_TRAP 13 /* Trap instruction */
+#define T_VCEI 14 /* Virtual coherency exception */
+#define T_FPE 15 /* Floating point exception */
+#define T_WATCH 23 /* Watch address reference */
+#define T_VCED 31 /* Virtual coherency data */
/* Resume Flags */
-#define RESUME_FLAG_DR (1<<0) /* Reload guest nonvolatile state? */
-#define RESUME_FLAG_HOST (1<<1) /* Resume host? */
+#define RESUME_FLAG_DR (1<<0) /* Reload guest nonvolatile state? */
+#define RESUME_FLAG_HOST (1<<1) /* Resume host? */
-#define RESUME_GUEST 0
-#define RESUME_GUEST_DR RESUME_FLAG_DR
-#define RESUME_HOST RESUME_FLAG_HOST
+#define RESUME_GUEST 0
+#define RESUME_GUEST_DR RESUME_FLAG_DR
+#define RESUME_HOST RESUME_FLAG_HOST
enum emulation_result {
EMULATE_DONE, /* no further processing */
@@ -313,24 +313,27 @@ enum emulation_result {
EMULATE_PRIV_FAIL,
};
-#define MIPS3_PG_G 0x00000001 /* Global; ignore ASID if in lo0 & lo1 */
-#define MIPS3_PG_V 0x00000002 /* Valid */
-#define MIPS3_PG_NV 0x00000000
-#define MIPS3_PG_D 0x00000004 /* Dirty */
+#define MIPS3_PG_G 0x00000001 /* Global; ignore ASID if in lo0 & lo1 */
+#define MIPS3_PG_V 0x00000002 /* Valid */
+#define MIPS3_PG_NV 0x00000000
+#define MIPS3_PG_D 0x00000004 /* Dirty */
#define mips3_paddr_to_tlbpfn(x) \
- (((unsigned long)(x) >> MIPS3_PG_SHIFT) & MIPS3_PG_FRAME)
+ (((unsigned long)(x) >> MIPS3_PG_SHIFT) & MIPS3_PG_FRAME)
#define mips3_tlbpfn_to_paddr(x) \
- ((unsigned long)((x) & MIPS3_PG_FRAME) << MIPS3_PG_SHIFT)
+ ((unsigned long)((x) & MIPS3_PG_FRAME) << MIPS3_PG_SHIFT)
-#define MIPS3_PG_SHIFT 6
-#define MIPS3_PG_FRAME 0x3fffffc0
+#define MIPS3_PG_SHIFT 6
+#define MIPS3_PG_FRAME 0x3fffffc0
-#define VPN2_MASK 0xffffe000
-#define TLB_IS_GLOBAL(x) (((x).tlb_lo0 & MIPS3_PG_G) && ((x).tlb_lo1 & MIPS3_PG_G))
-#define TLB_VPN2(x) ((x).tlb_hi & VPN2_MASK)
-#define TLB_ASID(x) ((x).tlb_hi & ASID_MASK)
-#define TLB_IS_VALID(x, va) (((va) & (1 << PAGE_SHIFT)) ? ((x).tlb_lo1 & MIPS3_PG_V) : ((x).tlb_lo0 & MIPS3_PG_V))
+#define VPN2_MASK 0xffffe000
+#define TLB_IS_GLOBAL(x) (((x).tlb_lo0 & MIPS3_PG_G) && \
+ ((x).tlb_lo1 & MIPS3_PG_G))
+#define TLB_VPN2(x) ((x).tlb_hi & VPN2_MASK)
+#define TLB_ASID(x) ((x).tlb_hi & ASID_MASK)
+#define TLB_IS_VALID(x, va) (((va) & (1 << PAGE_SHIFT)) \
+ ? ((x).tlb_lo1 & MIPS3_PG_V) \
+ : ((x).tlb_lo0 & MIPS3_PG_V))
struct kvm_mips_tlb {
long tlb_mask;
@@ -339,7 +342,7 @@ struct kvm_mips_tlb {
long tlb_lo1;
};
-#define KVM_MIPS_GUEST_TLB_SIZE 64
+#define KVM_MIPS_GUEST_TLB_SIZE 64
struct kvm_vcpu_arch {
void *host_ebase, *guest_ebase;
unsigned long host_stack;
@@ -400,65 +403,67 @@ struct kvm_vcpu_arch {
};
-#define kvm_read_c0_guest_index(cop0) (cop0->reg[MIPS_CP0_TLB_INDEX][0])
-#define kvm_write_c0_guest_index(cop0, val) (cop0->reg[MIPS_CP0_TLB_INDEX][0] = val)
-#define kvm_read_c0_guest_entrylo0(cop0) (cop0->reg[MIPS_CP0_TLB_LO0][0])
-#define kvm_read_c0_guest_entrylo1(cop0) (cop0->reg[MIPS_CP0_TLB_LO1][0])
-#define kvm_read_c0_guest_context(cop0) (cop0->reg[MIPS_CP0_TLB_CONTEXT][0])
-#define kvm_write_c0_guest_context(cop0, val) (cop0->reg[MIPS_CP0_TLB_CONTEXT][0] = (val))
-#define kvm_read_c0_guest_userlocal(cop0) (cop0->reg[MIPS_CP0_TLB_CONTEXT][2])
-#define kvm_read_c0_guest_pagemask(cop0) (cop0->reg[MIPS_CP0_TLB_PG_MASK][0])
-#define kvm_write_c0_guest_pagemask(cop0, val) (cop0->reg[MIPS_CP0_TLB_PG_MASK][0] = (val))
-#define kvm_read_c0_guest_wired(cop0) (cop0->reg[MIPS_CP0_TLB_WIRED][0])
-#define kvm_write_c0_guest_wired(cop0, val) (cop0->reg[MIPS_CP0_TLB_WIRED][0] = (val))
-#define kvm_read_c0_guest_badvaddr(cop0) (cop0->reg[MIPS_CP0_BAD_VADDR][0])
-#define kvm_write_c0_guest_badvaddr(cop0, val) (cop0->reg[MIPS_CP0_BAD_VADDR][0] = (val))
-#define kvm_read_c0_guest_count(cop0) (cop0->reg[MIPS_CP0_COUNT][0])
-#define kvm_write_c0_guest_count(cop0, val) (cop0->reg[MIPS_CP0_COUNT][0] = (val))
-#define kvm_read_c0_guest_entryhi(cop0) (cop0->reg[MIPS_CP0_TLB_HI][0])
-#define kvm_write_c0_guest_entryhi(cop0, val) (cop0->reg[MIPS_CP0_TLB_HI][0] = (val))
-#define kvm_read_c0_guest_compare(cop0) (cop0->reg[MIPS_CP0_COMPARE][0])
-#define kvm_write_c0_guest_compare(cop0, val) (cop0->reg[MIPS_CP0_COMPARE][0] = (val))
-#define kvm_read_c0_guest_status(cop0) (cop0->reg[MIPS_CP0_STATUS][0])
-#define kvm_write_c0_guest_status(cop0, val) (cop0->reg[MIPS_CP0_STATUS][0] = (val))
-#define kvm_read_c0_guest_intctl(cop0) (cop0->reg[MIPS_CP0_STATUS][1])
-#define kvm_write_c0_guest_intctl(cop0, val) (cop0->reg[MIPS_CP0_STATUS][1] = (val))
-#define kvm_read_c0_guest_cause(cop0) (cop0->reg[MIPS_CP0_CAUSE][0])
-#define kvm_write_c0_guest_cause(cop0, val) (cop0->reg[MIPS_CP0_CAUSE][0] = (val))
-#define kvm_read_c0_guest_epc(cop0) (cop0->reg[MIPS_CP0_EXC_PC][0])
-#define kvm_write_c0_guest_epc(cop0, val) (cop0->reg[MIPS_CP0_EXC_PC][0] = (val))
-#define kvm_read_c0_guest_prid(cop0) (cop0->reg[MIPS_CP0_PRID][0])
-#define kvm_write_c0_guest_prid(cop0, val) (cop0->reg[MIPS_CP0_PRID][0] = (val))
-#define kvm_read_c0_guest_ebase(cop0) (cop0->reg[MIPS_CP0_PRID][1])
-#define kvm_write_c0_guest_ebase(cop0, val) (cop0->reg[MIPS_CP0_PRID][1] = (val))
-#define kvm_read_c0_guest_config(cop0) (cop0->reg[MIPS_CP0_CONFIG][0])
-#define kvm_read_c0_guest_config1(cop0) (cop0->reg[MIPS_CP0_CONFIG][1])
-#define kvm_read_c0_guest_config2(cop0) (cop0->reg[MIPS_CP0_CONFIG][2])
-#define kvm_read_c0_guest_config3(cop0) (cop0->reg[MIPS_CP0_CONFIG][3])
-#define kvm_read_c0_guest_config7(cop0) (cop0->reg[MIPS_CP0_CONFIG][7])
-#define kvm_write_c0_guest_config(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][0] = (val))
-#define kvm_write_c0_guest_config1(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][1] = (val))
-#define kvm_write_c0_guest_config2(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][2] = (val))
-#define kvm_write_c0_guest_config3(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][3] = (val))
-#define kvm_write_c0_guest_config7(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][7] = (val))
-#define kvm_read_c0_guest_errorepc(cop0) (cop0->reg[MIPS_CP0_ERROR_PC][0])
-#define kvm_write_c0_guest_errorepc(cop0, val) (cop0->reg[MIPS_CP0_ERROR_PC][0] = (val))
-
-#define kvm_set_c0_guest_status(cop0, val) (cop0->reg[MIPS_CP0_STATUS][0] |= (val))
-#define kvm_clear_c0_guest_status(cop0, val) (cop0->reg[MIPS_CP0_STATUS][0] &= ~(val))
-#define kvm_set_c0_guest_cause(cop0, val) (cop0->reg[MIPS_CP0_CAUSE][0] |= (val))
-#define kvm_clear_c0_guest_cause(cop0, val) (cop0->reg[MIPS_CP0_CAUSE][0] &= ~(val))
-#define kvm_change_c0_guest_cause(cop0, change, val) \
-{ \
- kvm_clear_c0_guest_cause(cop0, change); \
- kvm_set_c0_guest_cause(cop0, ((val) & (change))); \
+#define kvm_read_c0_guest_index(cop0) (cop0->reg[MIPS_CP0_TLB_INDEX][0])
+#define kvm_write_c0_guest_index(cop0, val) (cop0->reg[MIPS_CP0_TLB_INDEX][0] = val)
+#define kvm_read_c0_guest_entrylo0(cop0) (cop0->reg[MIPS_CP0_TLB_LO0][0])
+#define kvm_read_c0_guest_entrylo1(cop0) (cop0->reg[MIPS_CP0_TLB_LO1][0])
+#define kvm_read_c0_guest_context(cop0) (cop0->reg[MIPS_CP0_TLB_CONTEXT][0])
+#define kvm_write_c0_guest_context(cop0, val) (cop0->reg[MIPS_CP0_TLB_CONTEXT][0] = (val))
+#define kvm_read_c0_guest_userlocal(cop0) (cop0->reg[MIPS_CP0_TLB_CONTEXT][2])
+#define kvm_read_c0_guest_pagemask(cop0) (cop0->reg[MIPS_CP0_TLB_PG_MASK][0])
+#define kvm_write_c0_guest_pagemask(cop0, val) (cop0->reg[MIPS_CP0_TLB_PG_MASK][0] = (val))
+#define kvm_read_c0_guest_wired(cop0) (cop0->reg[MIPS_CP0_TLB_WIRED][0])
+#define kvm_write_c0_guest_wired(cop0, val) (cop0->reg[MIPS_CP0_TLB_WIRED][0] = (val))
+#define kvm_read_c0_guest_hwrena(cop0) (cop0->reg[MIPS_CP0_HWRENA][0])
+#define kvm_write_c0_guest_hwrena(cop0, val) (cop0->reg[MIPS_CP0_HWRENA][0] = (val))
+#define kvm_read_c0_guest_badvaddr(cop0) (cop0->reg[MIPS_CP0_BAD_VADDR][0])
+#define kvm_write_c0_guest_badvaddr(cop0, val) (cop0->reg[MIPS_CP0_BAD_VADDR][0] = (val))
+#define kvm_read_c0_guest_count(cop0) (cop0->reg[MIPS_CP0_COUNT][0])
+#define kvm_write_c0_guest_count(cop0, val) (cop0->reg[MIPS_CP0_COUNT][0] = (val))
+#define kvm_read_c0_guest_entryhi(cop0) (cop0->reg[MIPS_CP0_TLB_HI][0])
+#define kvm_write_c0_guest_entryhi(cop0, val) (cop0->reg[MIPS_CP0_TLB_HI][0] = (val))
+#define kvm_read_c0_guest_compare(cop0) (cop0->reg[MIPS_CP0_COMPARE][0])
+#define kvm_write_c0_guest_compare(cop0, val) (cop0->reg[MIPS_CP0_COMPARE][0] = (val))
+#define kvm_read_c0_guest_status(cop0) (cop0->reg[MIPS_CP0_STATUS][0])
+#define kvm_write_c0_guest_status(cop0, val) (cop0->reg[MIPS_CP0_STATUS][0] = (val))
+#define kvm_read_c0_guest_intctl(cop0) (cop0->reg[MIPS_CP0_STATUS][1])
+#define kvm_write_c0_guest_intctl(cop0, val) (cop0->reg[MIPS_CP0_STATUS][1] = (val))
+#define kvm_read_c0_guest_cause(cop0) (cop0->reg[MIPS_CP0_CAUSE][0])
+#define kvm_write_c0_guest_cause(cop0, val) (cop0->reg[MIPS_CP0_CAUSE][0] = (val))
+#define kvm_read_c0_guest_epc(cop0) (cop0->reg[MIPS_CP0_EXC_PC][0])
+#define kvm_write_c0_guest_epc(cop0, val) (cop0->reg[MIPS_CP0_EXC_PC][0] = (val))
+#define kvm_read_c0_guest_prid(cop0) (cop0->reg[MIPS_CP0_PRID][0])
+#define kvm_write_c0_guest_prid(cop0, val) (cop0->reg[MIPS_CP0_PRID][0] = (val))
+#define kvm_read_c0_guest_ebase(cop0) (cop0->reg[MIPS_CP0_PRID][1])
+#define kvm_write_c0_guest_ebase(cop0, val) (cop0->reg[MIPS_CP0_PRID][1] = (val))
+#define kvm_read_c0_guest_config(cop0) (cop0->reg[MIPS_CP0_CONFIG][0])
+#define kvm_read_c0_guest_config1(cop0) (cop0->reg[MIPS_CP0_CONFIG][1])
+#define kvm_read_c0_guest_config2(cop0) (cop0->reg[MIPS_CP0_CONFIG][2])
+#define kvm_read_c0_guest_config3(cop0) (cop0->reg[MIPS_CP0_CONFIG][3])
+#define kvm_read_c0_guest_config7(cop0) (cop0->reg[MIPS_CP0_CONFIG][7])
+#define kvm_write_c0_guest_config(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][0] = (val))
+#define kvm_write_c0_guest_config1(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][1] = (val))
+#define kvm_write_c0_guest_config2(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][2] = (val))
+#define kvm_write_c0_guest_config3(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][3] = (val))
+#define kvm_write_c0_guest_config7(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][7] = (val))
+#define kvm_read_c0_guest_errorepc(cop0) (cop0->reg[MIPS_CP0_ERROR_PC][0])
+#define kvm_write_c0_guest_errorepc(cop0, val) (cop0->reg[MIPS_CP0_ERROR_PC][0] = (val))
+
+#define kvm_set_c0_guest_status(cop0, val) (cop0->reg[MIPS_CP0_STATUS][0] |= (val))
+#define kvm_clear_c0_guest_status(cop0, val) (cop0->reg[MIPS_CP0_STATUS][0] &= ~(val))
+#define kvm_set_c0_guest_cause(cop0, val) (cop0->reg[MIPS_CP0_CAUSE][0] |= (val))
+#define kvm_clear_c0_guest_cause(cop0, val) (cop0->reg[MIPS_CP0_CAUSE][0] &= ~(val))
+#define kvm_change_c0_guest_cause(cop0, change, val) \
+{ \
+ kvm_clear_c0_guest_cause(cop0, change); \
+ kvm_set_c0_guest_cause(cop0, ((val) & (change))); \
}
-#define kvm_set_c0_guest_ebase(cop0, val) (cop0->reg[MIPS_CP0_PRID][1] |= (val))
-#define kvm_clear_c0_guest_ebase(cop0, val) (cop0->reg[MIPS_CP0_PRID][1] &= ~(val))
-#define kvm_change_c0_guest_ebase(cop0, change, val) \
-{ \
- kvm_clear_c0_guest_ebase(cop0, change); \
- kvm_set_c0_guest_ebase(cop0, ((val) & (change))); \
+#define kvm_set_c0_guest_ebase(cop0, val) (cop0->reg[MIPS_CP0_PRID][1] |= (val))
+#define kvm_clear_c0_guest_ebase(cop0, val) (cop0->reg[MIPS_CP0_PRID][1] &= ~(val))
+#define kvm_change_c0_guest_ebase(cop0, change, val) \
+{ \
+ kvm_clear_c0_guest_ebase(cop0, change); \
+ kvm_set_c0_guest_ebase(cop0, ((val) & (change))); \
}
diff --git a/arch/mips/include/asm/local.h b/arch/mips/include/asm/local.h
index d44622cd74be..46dfc3c1fd49 100644
--- a/arch/mips/include/asm/local.h
+++ b/arch/mips/include/asm/local.h
@@ -33,7 +33,7 @@ static __inline__ long local_add_return(long i, local_t * l)
unsigned long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1:" __LL "%1, %2 # local_add_return \n"
" addu %0, %1, %3 \n"
__SC "%0, %2 \n"
@@ -47,7 +47,7 @@ static __inline__ long local_add_return(long i, local_t * l)
unsigned long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1:" __LL "%1, %2 # local_add_return \n"
" addu %0, %1, %3 \n"
__SC "%0, %2 \n"
@@ -78,7 +78,7 @@ static __inline__ long local_sub_return(long i, local_t * l)
unsigned long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1:" __LL "%1, %2 # local_sub_return \n"
" subu %0, %1, %3 \n"
__SC "%0, %2 \n"
@@ -92,7 +92,7 @@ static __inline__ long local_sub_return(long i, local_t * l)
unsigned long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1:" __LL "%1, %2 # local_sub_return \n"
" subu %0, %1, %3 \n"
__SC "%0, %2 \n"
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index 54f9e84db8ac..b4c3ecb17d48 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -1161,18 +1161,6 @@ enum soc_au1200_ints {
#define MAC_RX_BUFF3_STATUS 0x30
#define MAC_RX_BUFF3_ADDR 0x34
-#define UART_RX 0 /* Receive buffer */
-#define UART_TX 4 /* Transmit buffer */
-#define UART_IER 8 /* Interrupt Enable Register */
-#define UART_IIR 0xC /* Interrupt ID Register */
-#define UART_FCR 0x10 /* FIFO Control Register */
-#define UART_LCR 0x14 /* Line Control Register */
-#define UART_MCR 0x18 /* Modem Control Register */
-#define UART_LSR 0x1C /* Line Status Register */
-#define UART_MSR 0x20 /* Modem Status Register */
-#define UART_CLK 0x28 /* Baud Rate Clock Divider */
-#define UART_MOD_CNTRL 0x100 /* Module Control */
-
/* SSIO */
#define SSI0_STATUS 0xB1600000
# define SSI_STATUS_BF (1 << 4)
diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h
index 40005fb39618..bba7399a49a3 100644
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h
+++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h
@@ -27,7 +27,11 @@ enum bcm47xx_board {
BCM47XX_BOARD_ASUS_WL700GE,
BCM47XX_BOARD_ASUS_WLHDD,
+ BCM47XX_BOARD_BELKIN_F7D3301,
+ BCM47XX_BOARD_BELKIN_F7D3302,
BCM47XX_BOARD_BELKIN_F7D4301,
+ BCM47XX_BOARD_BELKIN_F7D4302,
+ BCM47XX_BOARD_BELKIN_F7D4401,
BCM47XX_BOARD_BUFFALO_WBR2_G54,
BCM47XX_BOARD_BUFFALO_WHR2_A54G54,
@@ -66,7 +70,7 @@ enum bcm47xx_board {
BCM47XX_BOARD_LINKSYS_WRT310NV1,
BCM47XX_BOARD_LINKSYS_WRT310NV2,
BCM47XX_BOARD_LINKSYS_WRT54G3GV2,
- BCM47XX_BOARD_LINKSYS_WRT54GSV1,
+ BCM47XX_BOARD_LINKSYS_WRT54G,
BCM47XX_BOARD_LINKSYS_WRT610NV1,
BCM47XX_BOARD_LINKSYS_WRT610NV2,
BCM47XX_BOARD_LINKSYS_WRTSL54GS,
@@ -94,6 +98,8 @@ enum bcm47xx_board {
BCM47XX_BOARD_PHICOMM_M1,
+ BCM47XX_BOARD_SIEMENS_SE505V2,
+
BCM47XX_BOARD_SIMPLETECH_SIMPLESHARE,
BCM47XX_BOARD_ZTE_H218N,
diff --git a/arch/mips/include/asm/mach-db1x00/db1200.h b/arch/mips/include/asm/mach-db1x00/db1200.h
deleted file mode 100644
index d3cce7326dd4..000000000000
--- a/arch/mips/include/asm/mach-db1x00/db1200.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * AMD Alchemy DBAu1200 Reference Board
- * Board register defines.
- *
- * ########################################################################
- *
- * This program is free software; you can distribute 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 it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * ########################################################################
- *
- *
- */
-#ifndef __ASM_DB1200_H
-#define __ASM_DB1200_H
-
-#include <linux/types.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-au1x00/au1xxx_psc.h>
-
-/* Bit positions for the different interrupt sources */
-#define BCSR_INT_IDE 0x0001
-#define BCSR_INT_ETH 0x0002
-#define BCSR_INT_PC0 0x0004
-#define BCSR_INT_PC0STSCHG 0x0008
-#define BCSR_INT_PC1 0x0010
-#define BCSR_INT_PC1STSCHG 0x0020
-#define BCSR_INT_DC 0x0040
-#define BCSR_INT_FLASHBUSY 0x0080
-#define BCSR_INT_PC0INSERT 0x0100
-#define BCSR_INT_PC0EJECT 0x0200
-#define BCSR_INT_PC1INSERT 0x0400
-#define BCSR_INT_PC1EJECT 0x0800
-#define BCSR_INT_SD0INSERT 0x1000
-#define BCSR_INT_SD0EJECT 0x2000
-#define BCSR_INT_SD1INSERT 0x4000
-#define BCSR_INT_SD1EJECT 0x8000
-
-#define IDE_REG_SHIFT 5
-
-#define DB1200_IDE_PHYS_ADDR 0x18800000
-#define DB1200_IDE_PHYS_LEN (16 << IDE_REG_SHIFT)
-#define DB1200_ETH_PHYS_ADDR 0x19000300
-#define DB1200_NAND_PHYS_ADDR 0x20000000
-
-#define PB1200_IDE_PHYS_ADDR 0x0C800000
-#define PB1200_ETH_PHYS_ADDR 0x0D000300
-#define PB1200_NAND_PHYS_ADDR 0x1C000000
-
-/*
- * External Interrupts for DBAu1200 as of 8/6/2004.
- * Bit positions in the CPLD registers can be calculated by taking
- * the interrupt define and subtracting the DB1200_INT_BEGIN value.
- *
- * Example: IDE bis pos is = 64 - 64
- * ETH bit pos is = 65 - 64
- */
-enum external_db1200_ints {
- DB1200_INT_BEGIN = AU1000_MAX_INTR + 1,
-
- DB1200_IDE_INT = DB1200_INT_BEGIN,
- DB1200_ETH_INT,
- DB1200_PC0_INT,
- DB1200_PC0_STSCHG_INT,
- DB1200_PC1_INT,
- DB1200_PC1_STSCHG_INT,
- DB1200_DC_INT,
- DB1200_FLASHBUSY_INT,
- DB1200_PC0_INSERT_INT,
- DB1200_PC0_EJECT_INT,
- DB1200_PC1_INSERT_INT,
- DB1200_PC1_EJECT_INT,
- DB1200_SD0_INSERT_INT,
- DB1200_SD0_EJECT_INT,
- PB1200_SD1_INSERT_INT,
- PB1200_SD1_EJECT_INT,
-
- DB1200_INT_END = DB1200_INT_BEGIN + 15,
-};
-
-#endif /* __ASM_DB1200_H */
diff --git a/arch/mips/include/asm/mach-db1x00/db1300.h b/arch/mips/include/asm/mach-db1x00/db1300.h
deleted file mode 100644
index 3d1ede46f059..000000000000
--- a/arch/mips/include/asm/mach-db1x00/db1300.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * NetLogic DB1300 board constants
- */
-
-#ifndef _DB1300_H_
-#define _DB1300_H_
-
-/* FPGA (external mux) interrupt sources */
-#define DB1300_FIRST_INT (ALCHEMY_GPIC_INT_LAST + 1)
-#define DB1300_IDE_INT (DB1300_FIRST_INT + 0)
-#define DB1300_ETH_INT (DB1300_FIRST_INT + 1)
-#define DB1300_CF_INT (DB1300_FIRST_INT + 2)
-#define DB1300_VIDEO_INT (DB1300_FIRST_INT + 4)
-#define DB1300_HDMI_INT (DB1300_FIRST_INT + 5)
-#define DB1300_DC_INT (DB1300_FIRST_INT + 6)
-#define DB1300_FLASH_INT (DB1300_FIRST_INT + 7)
-#define DB1300_CF_INSERT_INT (DB1300_FIRST_INT + 8)
-#define DB1300_CF_EJECT_INT (DB1300_FIRST_INT + 9)
-#define DB1300_AC97_INT (DB1300_FIRST_INT + 10)
-#define DB1300_AC97_PEN_INT (DB1300_FIRST_INT + 11)
-#define DB1300_SD1_INSERT_INT (DB1300_FIRST_INT + 12)
-#define DB1300_SD1_EJECT_INT (DB1300_FIRST_INT + 13)
-#define DB1300_OTG_VBUS_OC_INT (DB1300_FIRST_INT + 14)
-#define DB1300_HOST_VBUS_OC_INT (DB1300_FIRST_INT + 15)
-#define DB1300_LAST_INT (DB1300_FIRST_INT + 15)
-
-/* SMSC9210 CS */
-#define DB1300_ETH_PHYS_ADDR 0x19000000
-#define DB1300_ETH_PHYS_END 0x197fffff
-
-/* ATA CS */
-#define DB1300_IDE_PHYS_ADDR 0x18800000
-#define DB1300_IDE_REG_SHIFT 5
-#define DB1300_IDE_PHYS_LEN (16 << DB1300_IDE_REG_SHIFT)
-
-/* NAND CS */
-#define DB1300_NAND_PHYS_ADDR 0x20000000
-#define DB1300_NAND_PHYS_END 0x20000fff
-
-#endif /* _DB1300_H_ */
diff --git a/arch/mips/include/asm/mach-loongson/boot_param.h b/arch/mips/include/asm/mach-loongson/boot_param.h
new file mode 100644
index 000000000000..829a7ec185fb
--- /dev/null
+++ b/arch/mips/include/asm/mach-loongson/boot_param.h
@@ -0,0 +1,163 @@
+#ifndef __ASM_MACH_LOONGSON_BOOT_PARAM_H_
+#define __ASM_MACH_LOONGSON_BOOT_PARAM_H_
+
+#define SYSTEM_RAM_LOW 1
+#define SYSTEM_RAM_HIGH 2
+#define MEM_RESERVED 3
+#define PCI_IO 4
+#define PCI_MEM 5
+#define LOONGSON_CFG_REG 6
+#define VIDEO_ROM 7
+#define ADAPTER_ROM 8
+#define ACPI_TABLE 9
+#define MAX_MEMORY_TYPE 10
+
+#define LOONGSON3_BOOT_MEM_MAP_MAX 128
+struct efi_memory_map_loongson {
+ u16 vers; /* version of efi_memory_map */
+ u32 nr_map; /* number of memory_maps */
+ u32 mem_freq; /* memory frequence */
+ struct mem_map {
+ u32 node_id; /* node_id which memory attached to */
+ u32 mem_type; /* system memory, pci memory, pci io, etc. */
+ u64 mem_start; /* memory map start address */
+ u32 mem_size; /* each memory_map size, not the total size */
+ } map[LOONGSON3_BOOT_MEM_MAP_MAX];
+} __packed;
+
+enum loongson_cpu_type {
+ Loongson_2E = 0,
+ Loongson_2F = 1,
+ Loongson_3A = 2,
+ Loongson_3B = 3,
+ Loongson_1A = 4,
+ Loongson_1B = 5
+};
+
+/*
+ * Capability and feature descriptor structure for MIPS CPU
+ */
+struct efi_cpuinfo_loongson {
+ u16 vers; /* version of efi_cpuinfo_loongson */
+ u32 processor_id; /* PRID, e.g. 6305, 6306 */
+ u32 cputype; /* Loongson_3A/3B, etc. */
+ u32 total_node; /* num of total numa nodes */
+ u32 cpu_startup_core_id; /* Core id */
+ u32 cpu_clock_freq; /* cpu_clock */
+ u32 nr_cpus;
+} __packed;
+
+struct system_loongson {
+ u16 vers; /* version of system_loongson */
+ u32 ccnuma_smp; /* 0: no numa; 1: has numa */
+ u32 sing_double_channel; /* 1:single; 2:double */
+} __packed;
+
+struct irq_source_routing_table {
+ u16 vers;
+ u16 size;
+ u16 rtr_bus;
+ u16 rtr_devfn;
+ u32 vendor;
+ u32 device;
+ u32 PIC_type; /* conform use HT or PCI to route to CPU-PIC */
+ u64 ht_int_bit; /* 3A: 1<<24; 3B: 1<<16 */
+ u64 ht_enable; /* irqs used in this PIC */
+ u32 node_id; /* node id: 0x0-0; 0x1-1; 0x10-2; 0x11-3 */
+ u64 pci_mem_start_addr;
+ u64 pci_mem_end_addr;
+ u64 pci_io_start_addr;
+ u64 pci_io_end_addr;
+ u64 pci_config_addr;
+ u32 dma_mask_bits;
+} __packed;
+
+struct interface_info {
+ u16 vers; /* version of the specificition */
+ u16 size;
+ u8 flag;
+ char description[64];
+} __packed;
+
+#define MAX_RESOURCE_NUMBER 128
+struct resource_loongson {
+ u64 start; /* resource start address */
+ u64 end; /* resource end address */
+ char name[64];
+ u32 flags;
+};
+
+struct archdev_data {}; /* arch specific additions */
+
+struct board_devices {
+ char name[64]; /* hold the device name */
+ u32 num_resources; /* number of device_resource */
+ /* for each device's resource */
+ struct resource_loongson resource[MAX_RESOURCE_NUMBER];
+ /* arch specific additions */
+ struct archdev_data archdata;
+};
+
+struct loongson_special_attribute {
+ u16 vers; /* version of this special */
+ char special_name[64]; /* special_atribute_name */
+ u32 loongson_special_type; /* type of special device */
+ /* for each device's resource */
+ struct resource_loongson resource[MAX_RESOURCE_NUMBER];
+};
+
+struct loongson_params {
+ u64 memory_offset; /* efi_memory_map_loongson struct offset */
+ u64 cpu_offset; /* efi_cpuinfo_loongson struct offset */
+ u64 system_offset; /* system_loongson struct offset */
+ u64 irq_offset; /* irq_source_routing_table struct offset */
+ u64 interface_offset; /* interface_info struct offset */
+ u64 special_offset; /* loongson_special_attribute struct offset */
+ u64 boarddev_table_offset; /* board_devices offset */
+};
+
+struct smbios_tables {
+ u16 vers; /* version of smbios */
+ u64 vga_bios; /* vga_bios address */
+ struct loongson_params lp;
+};
+
+struct efi_reset_system_t {
+ u64 ResetCold;
+ u64 ResetWarm;
+ u64 ResetType;
+ u64 Shutdown;
+ u64 DoSuspend; /* NULL if not support */
+};
+
+struct efi_loongson {
+ u64 mps; /* MPS table */
+ u64 acpi; /* ACPI table (IA64 ext 0.71) */
+ u64 acpi20; /* ACPI table (ACPI 2.0) */
+ struct smbios_tables smbios; /* SM BIOS table */
+ u64 sal_systab; /* SAL system table */
+ u64 boot_info; /* boot info table */
+};
+
+struct boot_params {
+ struct efi_loongson efi;
+ struct efi_reset_system_t reset_system;
+};
+
+struct loongson_system_configuration {
+ u32 nr_cpus;
+ enum loongson_cpu_type cputype;
+ u64 ht_control_base;
+ u64 pci_mem_start_addr;
+ u64 pci_mem_end_addr;
+ u64 pci_io_base;
+ u64 restart_addr;
+ u64 poweroff_addr;
+ u64 suspend_addr;
+ u64 vgabios_addr;
+ u32 dma_mask_bits;
+};
+
+extern struct efi_memory_map_loongson *loongson_memmap;
+extern struct loongson_system_configuration loongson_sysconf;
+#endif
diff --git a/arch/mips/include/asm/mach-loongson/dma-coherence.h b/arch/mips/include/asm/mach-loongson/dma-coherence.h
index aeb2c05d6145..6a902751cc7f 100644
--- a/arch/mips/include/asm/mach-loongson/dma-coherence.h
+++ b/arch/mips/include/asm/mach-loongson/dma-coherence.h
@@ -11,24 +11,40 @@
#ifndef __ASM_MACH_LOONGSON_DMA_COHERENCE_H
#define __ASM_MACH_LOONGSON_DMA_COHERENCE_H
+#ifdef CONFIG_SWIOTLB
+#include <linux/swiotlb.h>
+#endif
+
struct device;
+extern dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr);
+extern phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr);
static inline dma_addr_t plat_map_dma_mem(struct device *dev, void *addr,
size_t size)
{
+#ifdef CONFIG_CPU_LOONGSON3
+ return virt_to_phys(addr);
+#else
return virt_to_phys(addr) | 0x80000000;
+#endif
}
static inline dma_addr_t plat_map_dma_mem_page(struct device *dev,
struct page *page)
{
+#ifdef CONFIG_CPU_LOONGSON3
+ return page_to_phys(page);
+#else
return page_to_phys(page) | 0x80000000;
+#endif
}
static inline unsigned long plat_dma_addr_to_phys(struct device *dev,
dma_addr_t dma_addr)
{
-#if defined(CONFIG_CPU_LOONGSON2F) && defined(CONFIG_64BIT)
+#if defined(CONFIG_CPU_LOONGSON3) && defined(CONFIG_64BIT)
+ return dma_addr;
+#elif defined(CONFIG_CPU_LOONGSON2F) && defined(CONFIG_64BIT)
return (dma_addr > 0x8fffffff) ? dma_addr : (dma_addr & 0x0fffffff);
#else
return dma_addr & 0x7fffffff;
@@ -55,7 +71,11 @@ static inline int plat_dma_supported(struct device *dev, u64 mask)
static inline int plat_device_is_coherent(struct device *dev)
{
+#ifdef CONFIG_DMA_NONCOHERENT
return 0;
+#else
+ return 1;
+#endif /* CONFIG_DMA_NONCOHERENT */
}
#endif /* __ASM_MACH_LOONGSON_DMA_COHERENCE_H */
diff --git a/arch/mips/include/asm/mach-loongson/irq.h b/arch/mips/include/asm/mach-loongson/irq.h
new file mode 100644
index 000000000000..34560bda6626
--- /dev/null
+++ b/arch/mips/include/asm/mach-loongson/irq.h
@@ -0,0 +1,44 @@
+#ifndef __ASM_MACH_LOONGSON_IRQ_H_
+#define __ASM_MACH_LOONGSON_IRQ_H_
+
+#include <boot_param.h>
+
+#ifdef CONFIG_CPU_LOONGSON3
+
+/* cpu core interrupt numbers */
+#define MIPS_CPU_IRQ_BASE 56
+
+#define LOONGSON_UART_IRQ (MIPS_CPU_IRQ_BASE + 2) /* UART */
+#define LOONGSON_HT1_IRQ (MIPS_CPU_IRQ_BASE + 3) /* HT1 */
+#define LOONGSON_TIMER_IRQ (MIPS_CPU_IRQ_BASE + 7) /* CPU Timer */
+
+#define LOONGSON_HT1_CFG_BASE loongson_sysconf.ht_control_base
+#define LOONGSON_HT1_INT_VECTOR_BASE (LOONGSON_HT1_CFG_BASE + 0x80)
+#define LOONGSON_HT1_INT_EN_BASE (LOONGSON_HT1_CFG_BASE + 0xa0)
+#define LOONGSON_HT1_INT_VECTOR(n) \
+ LOONGSON3_REG32(LOONGSON_HT1_INT_VECTOR_BASE, 4 * (n))
+#define LOONGSON_HT1_INTN_EN(n) \
+ LOONGSON3_REG32(LOONGSON_HT1_INT_EN_BASE, 4 * (n))
+
+#define LOONGSON_INT_ROUTER_OFFSET 0x1400
+#define LOONGSON_INT_ROUTER_INTEN \
+ LOONGSON3_REG32(LOONGSON3_REG_BASE, LOONGSON_INT_ROUTER_OFFSET + 0x24)
+#define LOONGSON_INT_ROUTER_INTENSET \
+ LOONGSON3_REG32(LOONGSON3_REG_BASE, LOONGSON_INT_ROUTER_OFFSET + 0x28)
+#define LOONGSON_INT_ROUTER_INTENCLR \
+ LOONGSON3_REG32(LOONGSON3_REG_BASE, LOONGSON_INT_ROUTER_OFFSET + 0x2c)
+#define LOONGSON_INT_ROUTER_ENTRY(n) \
+ LOONGSON3_REG8(LOONGSON3_REG_BASE, LOONGSON_INT_ROUTER_OFFSET + n)
+#define LOONGSON_INT_ROUTER_LPC LOONGSON_INT_ROUTER_ENTRY(0x0a)
+#define LOONGSON_INT_ROUTER_HT1(n) LOONGSON_INT_ROUTER_ENTRY(n + 0x18)
+
+#define LOONGSON_INT_CORE0_INT0 0x11 /* route to int 0 of core 0 */
+#define LOONGSON_INT_CORE0_INT1 0x21 /* route to int 1 of core 0 */
+
+#endif
+
+extern void fixup_irqs(void);
+extern void loongson3_ipi_interrupt(struct pt_regs *regs);
+
+#include_next <irq.h>
+#endif /* __ASM_MACH_LOONGSON_IRQ_H_ */
diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h
index b286534fef08..f3fd1eb8e3dd 100644
--- a/arch/mips/include/asm/mach-loongson/loongson.h
+++ b/arch/mips/include/asm/mach-loongson/loongson.h
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/kconfig.h>
+#include <boot_param.h>
/* loongson internal northbridge initialization */
extern void bonito_irq_init(void);
@@ -24,8 +25,9 @@ extern void mach_prepare_reboot(void);
extern void mach_prepare_shutdown(void);
/* environment arguments from bootloader */
-extern unsigned long cpu_clock_freq;
-extern unsigned long memsize, highmemsize;
+extern u32 cpu_clock_freq;
+extern u32 memsize, highmemsize;
+extern struct plat_smp_ops loongson3_smp_ops;
/* loongson-specific command line, env and memory initialization */
extern void __init prom_init_memory(void);
@@ -61,6 +63,12 @@ extern int mach_i8259_irq(void);
#define LOONGSON_REG(x) \
(*(volatile u32 *)((char *)CKSEG1ADDR(LOONGSON_REG_BASE) + (x)))
+#define LOONGSON3_REG8(base, x) \
+ (*(volatile u8 *)((char *)TO_UNCAC(base) + (x)))
+
+#define LOONGSON3_REG32(base, x) \
+ (*(volatile u32 *)((char *)TO_UNCAC(base) + (x)))
+
#define LOONGSON_IRQ_BASE 32
#define LOONGSON2_PERFCNT_IRQ (MIPS_CPU_IRQ_BASE + 6) /* cpu perf counter */
@@ -86,6 +94,10 @@ static inline void do_perfcnt_IRQ(void)
#define LOONGSON_REG_BASE 0x1fe00000
#define LOONGSON_REG_SIZE 0x00100000 /* 256Bytes + 256Bytes + ??? */
#define LOONGSON_REG_TOP (LOONGSON_REG_BASE+LOONGSON_REG_SIZE-1)
+/* Loongson-3 specific registers */
+#define LOONGSON3_REG_BASE 0x3ff00000
+#define LOONGSON3_REG_SIZE 0x00100000 /* 256Bytes + 256Bytes + ??? */
+#define LOONGSON3_REG_TOP (LOONGSON3_REG_BASE+LOONGSON3_REG_SIZE-1)
#define LOONGSON_LIO1_BASE 0x1ff00000
#define LOONGSON_LIO1_SIZE 0x00100000 /* 1M */
@@ -101,7 +113,13 @@ static inline void do_perfcnt_IRQ(void)
#define LOONGSON_PCICFG_BASE 0x1fe80000
#define LOONGSON_PCICFG_SIZE 0x00000800 /* 2K */
#define LOONGSON_PCICFG_TOP (LOONGSON_PCICFG_BASE+LOONGSON_PCICFG_SIZE-1)
+
+#if defined(CONFIG_HT_PCI)
+#define LOONGSON_PCIIO_BASE loongson_sysconf.pci_io_base
+#else
#define LOONGSON_PCIIO_BASE 0x1fd00000
+#endif
+
#define LOONGSON_PCIIO_SIZE 0x00100000 /* 1M */
#define LOONGSON_PCIIO_TOP (LOONGSON_PCIIO_BASE+LOONGSON_PCIIO_SIZE-1)
@@ -231,6 +249,9 @@ static inline void do_perfcnt_IRQ(void)
#define LOONGSON_PXARB_CFG LOONGSON_REG(LOONGSON_REGBASE + 0x68)
#define LOONGSON_PXARB_STATUS LOONGSON_REG(LOONGSON_REGBASE + 0x6c)
+/* Chip Config */
+#define LOONGSON_CHIPCFG0 LOONGSON_REG(LOONGSON_REGBASE + 0x80)
+
/* pcimap */
#define LOONGSON_PCIMAP_PCIMAP_LO0 0x0000003f
@@ -246,9 +267,6 @@ static inline void do_perfcnt_IRQ(void)
#ifdef CONFIG_CPU_SUPPORTS_CPUFREQ
#include <linux/cpufreq.h>
extern struct cpufreq_frequency_table loongson2_clockmod_table[];
-
-/* Chip Config */
-#define LOONGSON_CHIPCFG0 LOONGSON_REG(LOONGSON_REGBASE + 0x80)
#endif
/*
diff --git a/arch/mips/include/asm/mach-loongson/machine.h b/arch/mips/include/asm/mach-loongson/machine.h
index 3810d5ca84ac..1b1f592fa2be 100644
--- a/arch/mips/include/asm/mach-loongson/machine.h
+++ b/arch/mips/include/asm/mach-loongson/machine.h
@@ -24,4 +24,10 @@
#endif
+#ifdef CONFIG_LEMOTE_MACH3A
+
+#define LOONGSON_MACHTYPE MACH_LEMOTE_A1101
+
+#endif /* CONFIG_LEMOTE_MACH3A */
+
#endif /* __ASM_MACH_LOONGSON_MACHINE_H */
diff --git a/arch/mips/include/asm/mach-loongson/pci.h b/arch/mips/include/asm/mach-loongson/pci.h
index bc99dab4ef63..1212774f66ef 100644
--- a/arch/mips/include/asm/mach-loongson/pci.h
+++ b/arch/mips/include/asm/mach-loongson/pci.h
@@ -40,8 +40,13 @@ extern struct pci_ops loongson_pci_ops;
#else /* loongson2f/32bit & loongson2e */
/* this pci memory space is mapped by pcimap in pci.c */
+#ifdef CONFIG_CPU_LOONGSON3
+#define LOONGSON_PCI_MEM_START 0x40000000UL
+#define LOONGSON_PCI_MEM_END 0x7effffffUL
+#else
#define LOONGSON_PCI_MEM_START LOONGSON_PCILO1_BASE
#define LOONGSON_PCI_MEM_END (LOONGSON_PCILO1_BASE + 0x04000000 * 2)
+#endif
/* this is an offset from mips_io_port_base */
#define LOONGSON_PCI_IO_START 0x00004000UL
diff --git a/arch/mips/include/asm/mach-loongson/spaces.h b/arch/mips/include/asm/mach-loongson/spaces.h
new file mode 100644
index 000000000000..e2506ee90044
--- /dev/null
+++ b/arch/mips/include/asm/mach-loongson/spaces.h
@@ -0,0 +1,9 @@
+#ifndef __ASM_MACH_LOONGSON_SPACES_H_
+#define __ASM_MACH_LOONGSON_SPACES_H_
+
+#if defined(CONFIG_64BIT)
+#define CAC_BASE _AC(0x9800000000000000, UL)
+#endif /* CONFIG_64BIT */
+
+#include <asm/mach-generic/spaces.h>
+#endif
diff --git a/arch/mips/include/asm/mach-malta/kernel-entry-init.h b/arch/mips/include/asm/mach-malta/kernel-entry-init.h
index 0b793e7bf67e..7c5e17a17849 100644
--- a/arch/mips/include/asm/mach-malta/kernel-entry-init.h
+++ b/arch/mips/include/asm/mach-malta/kernel-entry-init.h
@@ -5,10 +5,80 @@
*
* Chris Dearman (chris@mips.com)
* Copyright (C) 2007 Mips Technologies, Inc.
+ * Copyright (C) 2014 Imagination Technologies Ltd.
*/
#ifndef __ASM_MACH_MIPS_KERNEL_ENTRY_INIT_H
#define __ASM_MACH_MIPS_KERNEL_ENTRY_INIT_H
+ /*
+ * Prepare segments for EVA boot:
+ *
+ * This is in case the processor boots in legacy configuration
+ * (SI_EVAReset is de-asserted and CONFIG5.K == 0)
+ *
+ * On entry, t1 is loaded with CP0_CONFIG
+ *
+ * ========================= Mappings =============================
+ * Virtual memory Physical memory Mapping
+ * 0x00000000 - 0x7fffffff 0x80000000 - 0xfffffffff MUSUK (kuseg)
+ * Flat 2GB physical memory
+ *
+ * 0x80000000 - 0x9fffffff 0x00000000 - 0x1ffffffff MUSUK (kseg0)
+ * 0xa0000000 - 0xbf000000 0x00000000 - 0x1ffffffff MUSUK (kseg1)
+ * 0xc0000000 - 0xdfffffff - MK (kseg2)
+ * 0xe0000000 - 0xffffffff - MK (kseg3)
+ *
+ *
+ * Lowmem is expanded to 2GB
+ */
+ .macro eva_entry
+ /*
+ * Get Config.K0 value and use it to program
+ * the segmentation registers
+ */
+ andi t1, 0x7 /* CCA */
+ move t2, t1
+ ins t2, t1, 16, 3
+ /* SegCtl0 */
+ li t0, ((MIPS_SEGCFG_MK << MIPS_SEGCFG_AM_SHIFT) | \
+ (0 << MIPS_SEGCFG_PA_SHIFT) | \
+ (1 << MIPS_SEGCFG_EU_SHIFT)) | \
+ (((MIPS_SEGCFG_MK << MIPS_SEGCFG_AM_SHIFT) | \
+ (0 << MIPS_SEGCFG_PA_SHIFT) | \
+ (1 << MIPS_SEGCFG_EU_SHIFT)) << 16)
+ or t0, t2
+ mtc0 t0, $5, 2
+
+ /* SegCtl1 */
+ li t0, ((MIPS_SEGCFG_MUSUK << MIPS_SEGCFG_AM_SHIFT) | \
+ (0 << MIPS_SEGCFG_PA_SHIFT) | \
+ (2 << MIPS_SEGCFG_C_SHIFT) | \
+ (1 << MIPS_SEGCFG_EU_SHIFT)) | \
+ (((MIPS_SEGCFG_MUSUK << MIPS_SEGCFG_AM_SHIFT) | \
+ (0 << MIPS_SEGCFG_PA_SHIFT) | \
+ (1 << MIPS_SEGCFG_EU_SHIFT)) << 16)
+ ins t0, t1, 16, 3
+ mtc0 t0, $5, 3
+
+ /* SegCtl2 */
+ li t0, ((MIPS_SEGCFG_MUSUK << MIPS_SEGCFG_AM_SHIFT) | \
+ (6 << MIPS_SEGCFG_PA_SHIFT) | \
+ (1 << MIPS_SEGCFG_EU_SHIFT)) | \
+ (((MIPS_SEGCFG_MUSUK << MIPS_SEGCFG_AM_SHIFT) | \
+ (4 << MIPS_SEGCFG_PA_SHIFT) | \
+ (1 << MIPS_SEGCFG_EU_SHIFT)) << 16)
+ or t0, t2
+ mtc0 t0, $5, 4
+
+ jal mips_ihb
+ mfc0 t0, $16, 5
+ li t2, 0x40000000 /* K bit */
+ or t0, t0, t2
+ mtc0 t0, $16, 5
+ sync
+ jal mips_ihb
+ .endm
+
.macro kernel_entry_setup
#ifdef CONFIG_MIPS_MT_SMTC
mfc0 t0, CP0_CONFIG
@@ -39,14 +109,57 @@
nonmt_processor:
.asciz "SMTC kernel requires the MT ASE to run\n"
__FINIT
-0:
#endif
+
+#ifdef CONFIG_EVA
+ sync
+ ehb
+
+ mfc0 t1, CP0_CONFIG
+ bgez t1, 9f
+ mfc0 t0, CP0_CONFIG, 1
+ bgez t0, 9f
+ mfc0 t0, CP0_CONFIG, 2
+ bgez t0, 9f
+ mfc0 t0, CP0_CONFIG, 3
+ sll t0, t0, 6 /* SC bit */
+ bgez t0, 9f
+
+ eva_entry
+ b 0f
+9:
+ /* Assume we came from YAMON... */
+ PTR_LA v0, 0x9fc00534 /* YAMON print */
+ lw v0, (v0)
+ move a0, zero
+ PTR_LA a1, nonsc_processor
+ jal v0
+
+ PTR_LA v0, 0x9fc00520 /* YAMON exit */
+ lw v0, (v0)
+ li a0, 1
+ jal v0
+
+1: b 1b
+ nop
+ __INITDATA
+nonsc_processor:
+ .asciz "EVA kernel requires a MIPS core with Segment Control implemented\n"
+ __FINIT
+#endif /* CONFIG_EVA */
+0:
.endm
/*
* Do SMP slave processor setup necessary before we can safely execute C code.
*/
.macro smp_slave_setup
+#ifdef CONFIG_EVA
+ sync
+ ehb
+ mfc0 t1, CP0_CONFIG
+ eva_entry
+#endif
.endm
#endif /* __ASM_MACH_MIPS_KERNEL_ENTRY_INIT_H */
diff --git a/arch/mips/include/asm/mach-malta/spaces.h b/arch/mips/include/asm/mach-malta/spaces.h
new file mode 100644
index 000000000000..d7e54971ec66
--- /dev/null
+++ b/arch/mips/include/asm/mach-malta/spaces.h
@@ -0,0 +1,46 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2014 Imagination Technologies Ltd.
+ */
+
+#ifndef _ASM_MALTA_SPACES_H
+#define _ASM_MALTA_SPACES_H
+
+#ifdef CONFIG_EVA
+
+/*
+ * Traditional Malta Board Memory Map for EVA
+ *
+ * 0x00000000 - 0x0fffffff: 1st RAM region, 256MB
+ * 0x10000000 - 0x1bffffff: GIC and CPC Control Registers
+ * 0x1c000000 - 0x1fffffff: I/O And Flash
+ * 0x20000000 - 0x7fffffff: 2nd RAM region, 1.5GB
+ * 0x80000000 - 0xffffffff: Physical memory aliases to 0x0 (2GB)
+ *
+ * The kernel is still located in 0x80000000(kseg0). However,
+ * the physical mask has been shifted to 0x80000000 which exploits the alias
+ * on the Malta board. As a result of which, we override the __pa_symbol
+ * to peform direct mapping from virtual to physical addresses. In other
+ * words, the 0x80000000 virtual address maps to 0x80000000 physical address
+ * which in turn aliases to 0x0. We do this in order to be able to use a flat
+ * 2GB of memory (0x80000000 - 0xffffffff) so we can avoid the I/O hole in
+ * 0x10000000 - 0x1fffffff.
+ * The last 64KB of physical memory are reserved for correct HIGHMEM
+ * macros arithmetics.
+ *
+ */
+
+#define PAGE_OFFSET _AC(0x0, UL)
+#define PHYS_OFFSET _AC(0x80000000, UL)
+#define HIGHMEM_START _AC(0xffff0000, UL)
+
+#define __pa_symbol(x) (RELOC_HIDE((unsigned long)(x), 0))
+
+#endif /* CONFIG_EVA */
+
+#include <asm/mach-generic/spaces.h>
+
+#endif /* _ASM_MALTA_SPACES_H */
diff --git a/arch/mips/include/asm/mach-pmcs-msp71xx/msp_regops.h b/arch/mips/include/asm/mach-pmcs-msp71xx/msp_regops.h
index 2dbc7a8cec1a..fc946c835995 100644
--- a/arch/mips/include/asm/mach-pmcs-msp71xx/msp_regops.h
+++ b/arch/mips/include/asm/mach-pmcs-msp71xx/msp_regops.h
@@ -76,7 +76,7 @@ static inline void set_value_reg32(volatile u32 *const addr,
__asm__ __volatile__(
" .set push \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %0, %1 # set_value_reg32 \n"
" and %0, %2 \n"
" or %0, %3 \n"
@@ -98,7 +98,7 @@ static inline void set_reg32(volatile u32 *const addr,
__asm__ __volatile__(
" .set push \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %0, %1 # set_reg32 \n"
" or %0, %2 \n"
" sc %0, %1 \n"
@@ -119,7 +119,7 @@ static inline void clear_reg32(volatile u32 *const addr,
__asm__ __volatile__(
" .set push \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %0, %1 # clear_reg32 \n"
" and %0, %2 \n"
" sc %0, %1 \n"
@@ -140,7 +140,7 @@ static inline void toggle_reg32(volatile u32 *const addr,
__asm__ __volatile__(
" .set push \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %0, %1 # toggle_reg32 \n"
" xor %0, %2 \n"
" sc %0, %1 \n"
@@ -216,7 +216,7 @@ static inline u32 blocking_read_reg32(volatile u32 *const addr)
#define custom_read_reg32(address, tmp) \
__asm__ __volatile__( \
" .set push \n" \
- " .set mips3 \n" \
+ " .set arch=r4000 \n" \
"1: ll %0, %1 #custom_read_reg32 \n" \
" .set pop \n" \
: "=r" (tmp), "=m" (*address) \
@@ -225,7 +225,7 @@ static inline u32 blocking_read_reg32(volatile u32 *const addr)
#define custom_write_reg32(address, tmp) \
__asm__ __volatile__( \
" .set push \n" \
- " .set mips3 \n" \
+ " .set arch=r4000 \n" \
" sc %0, %1 #custom_write_reg32 \n" \
" "__beqz"%0, 1b \n" \
" nop \n" \
diff --git a/arch/mips/include/asm/mips-boards/malta.h b/arch/mips/include/asm/mips-boards/malta.h
index 722bc889eab5..fd9774269a5e 100644
--- a/arch/mips/include/asm/mips-boards/malta.h
+++ b/arch/mips/include/asm/mips-boards/malta.h
@@ -64,6 +64,11 @@ static inline unsigned long get_msc_port_base(unsigned long reg)
#define GIC_ADDRSPACE_SZ (128 * 1024)
/*
+ * CPC Specific definitions
+ */
+#define CPC_BASE_ADDR 0x1bde0000
+
+/*
* MSC01 BIU Specific definitions
* FIXME : These should be elsewhere ?
*/
diff --git a/arch/mips/include/asm/mips-boards/piix4.h b/arch/mips/include/asm/mips-boards/piix4.h
index 836e2ede24de..9cf54041d416 100644
--- a/arch/mips/include/asm/mips-boards/piix4.h
+++ b/arch/mips/include/asm/mips-boards/piix4.h
@@ -50,4 +50,9 @@
#define PIIX4_FUNC1_IDETIM_SECONDARY_HI 0x43
#define PIIX4_FUNC1_IDETIM_SECONDARY_HI_IDE_DECODE_EN (1 << 7)
+/* Power Management Configuration Space */
+#define PIIX4_FUNC3_PMBA 0x40
+#define PIIX4_FUNC3_PMREGMISC 0x80
+#define PIIX4_FUNC3_PMREGMISC_EN (1 << 0)
+
#endif /* __ASM_MIPS_BOARDS_PIIX4_H */
diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h
new file mode 100644
index 000000000000..6a9d2dd005ca
--- /dev/null
+++ b/arch/mips/include/asm/mips-cm.h
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.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.
+ */
+
+#ifndef __MIPS_ASM_MIPS_CM_H__
+#define __MIPS_ASM_MIPS_CM_H__
+
+#include <linux/io.h>
+#include <linux/types.h>
+
+/* The base address of the CM GCR block */
+extern void __iomem *mips_cm_base;
+
+/* The base address of the CM L2-only sync region */
+extern void __iomem *mips_cm_l2sync_base;
+
+/**
+ * __mips_cm_phys_base - retrieve the physical base address of the CM
+ *
+ * This function returns the physical base address of the Coherence Manager
+ * global control block, or 0 if no Coherence Manager is present. It provides
+ * a default implementation which reads the CMGCRBase register where available,
+ * and may be overriden by platforms which determine this address in a
+ * different way by defining a function with the same prototype except for the
+ * name mips_cm_phys_base (without underscores).
+ */
+extern phys_t __mips_cm_phys_base(void);
+
+/**
+ * mips_cm_probe - probe for a Coherence Manager
+ *
+ * Attempt to detect the presence of a Coherence Manager. Returns 0 if a CM
+ * is successfully detected, else -errno.
+ */
+#ifdef CONFIG_MIPS_CM
+extern int mips_cm_probe(void);
+#else
+static inline int mips_cm_probe(void)
+{
+ return -ENODEV;
+}
+#endif
+
+/**
+ * mips_cm_present - determine whether a Coherence Manager is present
+ *
+ * Returns true if a CM is present in the system, else false.
+ */
+static inline bool mips_cm_present(void)
+{
+#ifdef CONFIG_MIPS_CM
+ return mips_cm_base != NULL;
+#else
+ return false;
+#endif
+}
+
+/**
+ * mips_cm_has_l2sync - determine whether an L2-only sync region is present
+ *
+ * Returns true if the system implements an L2-only sync region, else false.
+ */
+static inline bool mips_cm_has_l2sync(void)
+{
+#ifdef CONFIG_MIPS_CM
+ return mips_cm_l2sync_base != NULL;
+#else
+ return false;
+#endif
+}
+
+/* Offsets to register blocks from the CM base address */
+#define MIPS_CM_GCB_OFS 0x0000 /* Global Control Block */
+#define MIPS_CM_CLCB_OFS 0x2000 /* Core Local Control Block */
+#define MIPS_CM_COCB_OFS 0x4000 /* Core Other Control Block */
+#define MIPS_CM_GDB_OFS 0x6000 /* Global Debug Block */
+
+/* Total size of the CM memory mapped registers */
+#define MIPS_CM_GCR_SIZE 0x8000
+
+/* Size of the L2-only sync region */
+#define MIPS_CM_L2SYNC_SIZE 0x1000
+
+/* Macros to ease the creation of register access functions */
+#define BUILD_CM_R_(name, off) \
+static inline u32 *addr_gcr_##name(void) \
+{ \
+ return (u32 *)(mips_cm_base + (off)); \
+} \
+ \
+static inline u32 read_gcr_##name(void) \
+{ \
+ return __raw_readl(addr_gcr_##name()); \
+}
+
+#define BUILD_CM__W(name, off) \
+static inline void write_gcr_##name(u32 value) \
+{ \
+ __raw_writel(value, addr_gcr_##name()); \
+}
+
+#define BUILD_CM_RW(name, off) \
+ BUILD_CM_R_(name, off) \
+ BUILD_CM__W(name, off)
+
+#define BUILD_CM_Cx_R_(name, off) \
+ BUILD_CM_R_(cl_##name, MIPS_CM_CLCB_OFS + (off)) \
+ BUILD_CM_R_(co_##name, MIPS_CM_COCB_OFS + (off))
+
+#define BUILD_CM_Cx__W(name, off) \
+ BUILD_CM__W(cl_##name, MIPS_CM_CLCB_OFS + (off)) \
+ BUILD_CM__W(co_##name, MIPS_CM_COCB_OFS + (off))
+
+#define BUILD_CM_Cx_RW(name, off) \
+ BUILD_CM_Cx_R_(name, off) \
+ BUILD_CM_Cx__W(name, off)
+
+/* GCB register accessor functions */
+BUILD_CM_R_(config, MIPS_CM_GCB_OFS + 0x00)
+BUILD_CM_RW(base, MIPS_CM_GCB_OFS + 0x08)
+BUILD_CM_RW(access, MIPS_CM_GCB_OFS + 0x20)
+BUILD_CM_R_(rev, MIPS_CM_GCB_OFS + 0x30)
+BUILD_CM_RW(error_mask, MIPS_CM_GCB_OFS + 0x40)
+BUILD_CM_RW(error_cause, MIPS_CM_GCB_OFS + 0x48)
+BUILD_CM_RW(error_addr, MIPS_CM_GCB_OFS + 0x50)
+BUILD_CM_RW(error_mult, MIPS_CM_GCB_OFS + 0x58)
+BUILD_CM_RW(l2_only_sync_base, MIPS_CM_GCB_OFS + 0x70)
+BUILD_CM_RW(gic_base, MIPS_CM_GCB_OFS + 0x80)
+BUILD_CM_RW(cpc_base, MIPS_CM_GCB_OFS + 0x88)
+BUILD_CM_RW(reg0_base, MIPS_CM_GCB_OFS + 0x90)
+BUILD_CM_RW(reg0_mask, MIPS_CM_GCB_OFS + 0x98)
+BUILD_CM_RW(reg1_base, MIPS_CM_GCB_OFS + 0xa0)
+BUILD_CM_RW(reg1_mask, MIPS_CM_GCB_OFS + 0xa8)
+BUILD_CM_RW(reg2_base, MIPS_CM_GCB_OFS + 0xb0)
+BUILD_CM_RW(reg2_mask, MIPS_CM_GCB_OFS + 0xb8)
+BUILD_CM_RW(reg3_base, MIPS_CM_GCB_OFS + 0xc0)
+BUILD_CM_RW(reg3_mask, MIPS_CM_GCB_OFS + 0xc8)
+BUILD_CM_R_(gic_status, MIPS_CM_GCB_OFS + 0xd0)
+BUILD_CM_R_(cpc_status, MIPS_CM_GCB_OFS + 0xf0)
+
+/* Core Local & Core Other register accessor functions */
+BUILD_CM_Cx_RW(reset_release, 0x00)
+BUILD_CM_Cx_RW(coherence, 0x08)
+BUILD_CM_Cx_R_(config, 0x10)
+BUILD_CM_Cx_RW(other, 0x18)
+BUILD_CM_Cx_RW(reset_base, 0x20)
+BUILD_CM_Cx_R_(id, 0x28)
+BUILD_CM_Cx_RW(reset_ext_base, 0x30)
+BUILD_CM_Cx_R_(tcid_0_priority, 0x40)
+BUILD_CM_Cx_R_(tcid_1_priority, 0x48)
+BUILD_CM_Cx_R_(tcid_2_priority, 0x50)
+BUILD_CM_Cx_R_(tcid_3_priority, 0x58)
+BUILD_CM_Cx_R_(tcid_4_priority, 0x60)
+BUILD_CM_Cx_R_(tcid_5_priority, 0x68)
+BUILD_CM_Cx_R_(tcid_6_priority, 0x70)
+BUILD_CM_Cx_R_(tcid_7_priority, 0x78)
+BUILD_CM_Cx_R_(tcid_8_priority, 0x80)
+
+/* GCR_CONFIG register fields */
+#define CM_GCR_CONFIG_NUMIOCU_SHF 8
+#define CM_GCR_CONFIG_NUMIOCU_MSK (_ULCAST_(0xf) << 8)
+#define CM_GCR_CONFIG_PCORES_SHF 0
+#define CM_GCR_CONFIG_PCORES_MSK (_ULCAST_(0xff) << 0)
+
+/* GCR_BASE register fields */
+#define CM_GCR_BASE_GCRBASE_SHF 15
+#define CM_GCR_BASE_GCRBASE_MSK (_ULCAST_(0x1ffff) << 15)
+#define CM_GCR_BASE_CMDEFTGT_SHF 0
+#define CM_GCR_BASE_CMDEFTGT_MSK (_ULCAST_(0x3) << 0)
+#define CM_GCR_BASE_CMDEFTGT_DISABLED 0
+#define CM_GCR_BASE_CMDEFTGT_MEM 1
+#define CM_GCR_BASE_CMDEFTGT_IOCU0 2
+#define CM_GCR_BASE_CMDEFTGT_IOCU1 3
+
+/* GCR_ACCESS register fields */
+#define CM_GCR_ACCESS_ACCESSEN_SHF 0
+#define CM_GCR_ACCESS_ACCESSEN_MSK (_ULCAST_(0xff) << 0)
+
+/* GCR_REV register fields */
+#define CM_GCR_REV_MAJOR_SHF 8
+#define CM_GCR_REV_MAJOR_MSK (_ULCAST_(0xff) << 8)
+#define CM_GCR_REV_MINOR_SHF 0
+#define CM_GCR_REV_MINOR_MSK (_ULCAST_(0xff) << 0)
+
+/* GCR_ERROR_CAUSE register fields */
+#define CM_GCR_ERROR_CAUSE_ERRTYPE_SHF 27
+#define CM_GCR_ERROR_CAUSE_ERRTYPE_MSK (_ULCAST_(0x1f) << 27)
+#define CM_GCR_ERROR_CAUSE_ERRINFO_SHF 0
+#define CM_GCR_ERROR_CAUSE_ERRINGO_MSK (_ULCAST_(0x7ffffff) << 0)
+
+/* GCR_ERROR_MULT register fields */
+#define CM_GCR_ERROR_MULT_ERR2ND_SHF 0
+#define CM_GCR_ERROR_MULT_ERR2ND_MSK (_ULCAST_(0x1f) << 0)
+
+/* GCR_L2_ONLY_SYNC_BASE register fields */
+#define CM_GCR_L2_ONLY_SYNC_BASE_SYNCBASE_SHF 12
+#define CM_GCR_L2_ONLY_SYNC_BASE_SYNCBASE_MSK (_ULCAST_(0xfffff) << 12)
+#define CM_GCR_L2_ONLY_SYNC_BASE_SYNCEN_SHF 0
+#define CM_GCR_L2_ONLY_SYNC_BASE_SYNCEN_MSK (_ULCAST_(0x1) << 0)
+
+/* GCR_GIC_BASE register fields */
+#define CM_GCR_GIC_BASE_GICBASE_SHF 17
+#define CM_GCR_GIC_BASE_GICBASE_MSK (_ULCAST_(0x7fff) << 17)
+#define CM_GCR_GIC_BASE_GICEN_SHF 0
+#define CM_GCR_GIC_BASE_GICEN_MSK (_ULCAST_(0x1) << 0)
+
+/* GCR_CPC_BASE register fields */
+#define CM_GCR_CPC_BASE_CPCBASE_SHF 17
+#define CM_GCR_CPC_BASE_CPCBASE_MSK (_ULCAST_(0x7fff) << 17)
+#define CM_GCR_CPC_BASE_CPCEN_SHF 0
+#define CM_GCR_CPC_BASE_CPCEN_MSK (_ULCAST_(0x1) << 0)
+
+/* GCR_REGn_BASE register fields */
+#define CM_GCR_REGn_BASE_BASEADDR_SHF 16
+#define CM_GCR_REGn_BASE_BASEADDR_MSK (_ULCAST_(0xffff) << 16)
+
+/* GCR_REGn_MASK register fields */
+#define CM_GCR_REGn_MASK_ADDRMASK_SHF 16
+#define CM_GCR_REGn_MASK_ADDRMASK_MSK (_ULCAST_(0xffff) << 16)
+#define CM_GCR_REGn_MASK_CCAOVR_SHF 5
+#define CM_GCR_REGn_MASK_CCAOVR_MSK (_ULCAST_(0x3) << 5)
+#define CM_GCR_REGn_MASK_CCAOVREN_SHF 4
+#define CM_GCR_REGn_MASK_CCAOVREN_MSK (_ULCAST_(0x1) << 4)
+#define CM_GCR_REGn_MASK_DROPL2_SHF 2
+#define CM_GCR_REGn_MASK_DROPL2_MSK (_ULCAST_(0x1) << 2)
+#define CM_GCR_REGn_MASK_CMTGT_SHF 0
+#define CM_GCR_REGn_MASK_CMTGT_MSK (_ULCAST_(0x3) << 0)
+#define CM_GCR_REGn_MASK_CMTGT_DISABLED (_ULCAST_(0x0) << 0)
+#define CM_GCR_REGn_MASK_CMTGT_MEM (_ULCAST_(0x1) << 0)
+#define CM_GCR_REGn_MASK_CMTGT_IOCU0 (_ULCAST_(0x2) << 0)
+#define CM_GCR_REGn_MASK_CMTGT_IOCU1 (_ULCAST_(0x3) << 0)
+
+/* GCR_GIC_STATUS register fields */
+#define CM_GCR_GIC_STATUS_EX_SHF 0
+#define CM_GCR_GIC_STATUS_EX_MSK (_ULCAST_(0x1) << 0)
+
+/* GCR_CPC_STATUS register fields */
+#define CM_GCR_CPC_STATUS_EX_SHF 0
+#define CM_GCR_CPC_STATUS_EX_MSK (_ULCAST_(0x1) << 0)
+
+/* GCR_Cx_COHERENCE register fields */
+#define CM_GCR_Cx_COHERENCE_COHDOMAINEN_SHF 0
+#define CM_GCR_Cx_COHERENCE_COHDOMAINEN_MSK (_ULCAST_(0xff) << 0)
+
+/* GCR_Cx_CONFIG register fields */
+#define CM_GCR_Cx_CONFIG_IOCUTYPE_SHF 10
+#define CM_GCR_Cx_CONFIG_IOCUTYPE_MSK (_ULCAST_(0x3) << 10)
+#define CM_GCR_Cx_CONFIG_PVPE_SHF 0
+#define CM_GCR_Cx_CONFIG_PVPE_MSK (_ULCAST_(0x1ff) << 0)
+
+/* GCR_Cx_OTHER register fields */
+#define CM_GCR_Cx_OTHER_CORENUM_SHF 16
+#define CM_GCR_Cx_OTHER_CORENUM_MSK (_ULCAST_(0xffff) << 16)
+
+/* GCR_Cx_RESET_BASE register fields */
+#define CM_GCR_Cx_RESET_BASE_BEVEXCBASE_SHF 12
+#define CM_GCR_Cx_RESET_BASE_BEVEXCBASE_MSK (_ULCAST_(0xfffff) << 12)
+
+/* GCR_Cx_RESET_EXT_BASE register fields */
+#define CM_GCR_Cx_RESET_EXT_BASE_EVARESET_SHF 31
+#define CM_GCR_Cx_RESET_EXT_BASE_EVARESET_MSK (_ULCAST_(0x1) << 31)
+#define CM_GCR_Cx_RESET_EXT_BASE_UEB_SHF 30
+#define CM_GCR_Cx_RESET_EXT_BASE_UEB_MSK (_ULCAST_(0x1) << 30)
+#define CM_GCR_Cx_RESET_EXT_BASE_BEVEXCMASK_SHF 20
+#define CM_GCR_Cx_RESET_EXT_BASE_BEVEXCMASK_MSK (_ULCAST_(0xff) << 20)
+#define CM_GCR_Cx_RESET_EXT_BASE_BEVEXCPA_SHF 1
+#define CM_GCR_Cx_RESET_EXT_BASE_BEVEXCPA_MSK (_ULCAST_(0x7f) << 1)
+#define CM_GCR_Cx_RESET_EXT_BASE_PRESENT_SHF 0
+#define CM_GCR_Cx_RESET_EXT_BASE_PRESENT_MSK (_ULCAST_(0x1) << 0)
+
+/**
+ * mips_cm_numcores - return the number of cores present in the system
+ *
+ * Returns the value of the PCORES field of the GCR_CONFIG register plus 1, or
+ * zero if no Coherence Manager is present.
+ */
+static inline unsigned mips_cm_numcores(void)
+{
+ if (!mips_cm_present())
+ return 0;
+
+ return ((read_gcr_config() & CM_GCR_CONFIG_PCORES_MSK)
+ >> CM_GCR_CONFIG_PCORES_SHF) + 1;
+}
+
+/**
+ * mips_cm_numiocu - return the number of IOCUs present in the system
+ *
+ * Returns the value of the NUMIOCU field of the GCR_CONFIG register, or zero
+ * if no Coherence Manager is present.
+ */
+static inline unsigned mips_cm_numiocu(void)
+{
+ if (!mips_cm_present())
+ return 0;
+
+ return (read_gcr_config() & CM_GCR_CONFIG_NUMIOCU_MSK)
+ >> CM_GCR_CONFIG_NUMIOCU_SHF;
+}
+
+/**
+ * mips_cm_l2sync - perform an L2-only sync operation
+ *
+ * If an L2-only sync region is present in the system then this function
+ * performs and L2-only sync and returns zero. Otherwise it returns -ENODEV.
+ */
+static inline int mips_cm_l2sync(void)
+{
+ if (!mips_cm_has_l2sync())
+ return -ENODEV;
+
+ writel(0, mips_cm_l2sync_base);
+ return 0;
+}
+
+#endif /* __MIPS_ASM_MIPS_CM_H__ */
diff --git a/arch/mips/include/asm/mips-cpc.h b/arch/mips/include/asm/mips-cpc.h
new file mode 100644
index 000000000000..988507e46d42
--- /dev/null
+++ b/arch/mips/include/asm/mips-cpc.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.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.
+ */
+
+#ifndef __MIPS_ASM_MIPS_CPC_H__
+#define __MIPS_ASM_MIPS_CPC_H__
+
+#include <linux/io.h>
+#include <linux/types.h>
+
+/* The base address of the CPC registers */
+extern void __iomem *mips_cpc_base;
+
+/**
+ * mips_cpc_default_phys_base - retrieve the default physical base address of
+ * the CPC
+ *
+ * Returns the default physical base address of the Cluster Power Controller
+ * memory mapped registers. This is platform dependant & must therefore be
+ * implemented per-platform.
+ */
+extern phys_t mips_cpc_default_phys_base(void);
+
+/**
+ * mips_cpc_phys_base - retrieve the physical base address of the CPC
+ *
+ * This function returns the physical base address of the Cluster Power
+ * Controller memory mapped registers, or 0 if no Cluster Power Controller
+ * is present. It may be overriden by individual platforms which determine
+ * this address in a different way.
+ */
+extern phys_t __weak mips_cpc_phys_base(void);
+
+/**
+ * mips_cpc_probe - probe for a Cluster Power Controller
+ *
+ * Attempt to detect the presence of a Cluster Power Controller. Returns 0 if
+ * a CPC is successfully detected, else -errno.
+ */
+#ifdef CONFIG_MIPS_CPC
+extern int mips_cpc_probe(void);
+#else
+static inline int mips_cpc_probe(void)
+{
+ return -ENODEV;
+}
+#endif
+
+/**
+ * mips_cpc_present - determine whether a Cluster Power Controller is present
+ *
+ * Returns true if a CPC is present in the system, else false.
+ */
+static inline bool mips_cpc_present(void)
+{
+#ifdef CONFIG_MIPS_CPC
+ return mips_cpc_base != NULL;
+#else
+ return false;
+#endif
+}
+
+/* Offsets from the CPC base address to various control blocks */
+#define MIPS_CPC_GCB_OFS 0x0000
+#define MIPS_CPC_CLCB_OFS 0x2000
+#define MIPS_CPC_COCB_OFS 0x4000
+
+/* Macros to ease the creation of register access functions */
+#define BUILD_CPC_R_(name, off) \
+static inline u32 read_cpc_##name(void) \
+{ \
+ return __raw_readl(mips_cpc_base + (off)); \
+}
+
+#define BUILD_CPC__W(name, off) \
+static inline void write_cpc_##name(u32 value) \
+{ \
+ __raw_writel(value, mips_cpc_base + (off)); \
+}
+
+#define BUILD_CPC_RW(name, off) \
+ BUILD_CPC_R_(name, off) \
+ BUILD_CPC__W(name, off)
+
+#define BUILD_CPC_Cx_R_(name, off) \
+ BUILD_CPC_R_(cl_##name, MIPS_CPC_CLCB_OFS + (off)) \
+ BUILD_CPC_R_(co_##name, MIPS_CPC_COCB_OFS + (off))
+
+#define BUILD_CPC_Cx__W(name, off) \
+ BUILD_CPC__W(cl_##name, MIPS_CPC_CLCB_OFS + (off)) \
+ BUILD_CPC__W(co_##name, MIPS_CPC_COCB_OFS + (off))
+
+#define BUILD_CPC_Cx_RW(name, off) \
+ BUILD_CPC_Cx_R_(name, off) \
+ BUILD_CPC_Cx__W(name, off)
+
+/* GCB register accessor functions */
+BUILD_CPC_RW(access, MIPS_CPC_GCB_OFS + 0x00)
+BUILD_CPC_RW(seqdel, MIPS_CPC_GCB_OFS + 0x08)
+BUILD_CPC_RW(rail, MIPS_CPC_GCB_OFS + 0x10)
+BUILD_CPC_RW(resetlen, MIPS_CPC_GCB_OFS + 0x18)
+BUILD_CPC_R_(revision, MIPS_CPC_GCB_OFS + 0x20)
+
+/* Core Local & Core Other accessor functions */
+BUILD_CPC_Cx_RW(cmd, 0x00)
+BUILD_CPC_Cx_RW(stat_conf, 0x08)
+BUILD_CPC_Cx_RW(other, 0x10)
+
+/* CPC_Cx_CMD register fields */
+#define CPC_Cx_CMD_SHF 0
+#define CPC_Cx_CMD_MSK (_ULCAST_(0xf) << 0)
+#define CPC_Cx_CMD_CLOCKOFF (_ULCAST_(0x1) << 0)
+#define CPC_Cx_CMD_PWRDOWN (_ULCAST_(0x2) << 0)
+#define CPC_Cx_CMD_PWRUP (_ULCAST_(0x3) << 0)
+#define CPC_Cx_CMD_RESET (_ULCAST_(0x4) << 0)
+
+/* CPC_Cx_STAT_CONF register fields */
+#define CPC_Cx_STAT_CONF_PWRUPE_SHF 23
+#define CPC_Cx_STAT_CONF_PWRUPE_MSK (_ULCAST_(0x1) << 23)
+#define CPC_Cx_STAT_CONF_SEQSTATE_SHF 19
+#define CPC_Cx_STAT_CONF_SEQSTATE_MSK (_ULCAST_(0xf) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_D0 (_ULCAST_(0x0) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_U0 (_ULCAST_(0x1) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_U1 (_ULCAST_(0x2) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_U2 (_ULCAST_(0x3) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_U3 (_ULCAST_(0x4) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_U4 (_ULCAST_(0x5) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_U5 (_ULCAST_(0x6) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_U6 (_ULCAST_(0x7) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_D1 (_ULCAST_(0x8) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_D3 (_ULCAST_(0x9) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_D2 (_ULCAST_(0xa) << 19)
+#define CPC_Cx_STAT_CONF_CLKGAT_IMPL_SHF 17
+#define CPC_Cx_STAT_CONF_CLKGAT_IMPL_MSK (_ULCAST_(0x1) << 17)
+#define CPC_Cx_STAT_CONF_PWRDN_IMPL_SHF 16
+#define CPC_Cx_STAT_CONF_PWRDN_IMPL_MSK (_ULCAST_(0x1) << 16)
+#define CPC_Cx_STAT_CONF_EJTAG_PROBE_SHF 15
+#define CPC_Cx_STAT_CONF_EJTAG_PROBE_MSK (_ULCAST_(0x1) << 15)
+
+/* CPC_Cx_OTHER register fields */
+#define CPC_Cx_OTHER_CORENUM_SHF 16
+#define CPC_Cx_OTHER_CORENUM_MSK (_ULCAST_(0xff) << 16)
+
+#endif /* __MIPS_ASM_MIPS_CPC_H__ */
diff --git a/arch/mips/include/asm/mips_mt.h b/arch/mips/include/asm/mips_mt.h
index ac7935203f89..a3df0c3faa0e 100644
--- a/arch/mips/include/asm/mips_mt.h
+++ b/arch/mips/include/asm/mips_mt.h
@@ -18,7 +18,12 @@ extern cpumask_t mt_fpu_cpumask;
extern unsigned long mt_fpemul_threshold;
extern void mips_mt_regdump(unsigned long previous_mvpcontrol_value);
+
+#ifdef CONFIG_MIPS_MT
extern void mips_mt_set_cpuoptions(void);
+#else
+static inline void mips_mt_set_cpuoptions(void) { }
+#endif
struct class;
extern struct class *mt_class;
diff --git a/arch/mips/include/asm/mipsmtregs.h b/arch/mips/include/asm/mipsmtregs.h
index 38b7704ee376..6efa79a27b6a 100644
--- a/arch/mips/include/asm/mipsmtregs.h
+++ b/arch/mips/include/asm/mipsmtregs.h
@@ -176,6 +176,17 @@
#ifndef __ASSEMBLY__
+static inline unsigned core_nvpes(void)
+{
+ unsigned conf0;
+
+ if (!cpu_has_mipsmt)
+ return 1;
+
+ conf0 = read_c0_mvpconf0();
+ return ((conf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
+}
+
static inline unsigned int dvpe(void)
{
int res = 0;
diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h
index bbc3dd4294bc..3e025b5311db 100644
--- a/arch/mips/include/asm/mipsregs.h
+++ b/arch/mips/include/asm/mipsregs.h
@@ -568,11 +568,23 @@
#define MIPS_CONF1_PC (_ULCAST_(1) << 4)
#define MIPS_CONF1_MD (_ULCAST_(1) << 5)
#define MIPS_CONF1_C2 (_ULCAST_(1) << 6)
+#define MIPS_CONF1_DA_SHF 7
+#define MIPS_CONF1_DA_SZ 3
#define MIPS_CONF1_DA (_ULCAST_(7) << 7)
+#define MIPS_CONF1_DL_SHF 10
+#define MIPS_CONF1_DL_SZ 3
#define MIPS_CONF1_DL (_ULCAST_(7) << 10)
+#define MIPS_CONF1_DS_SHF 13
+#define MIPS_CONF1_DS_SZ 3
#define MIPS_CONF1_DS (_ULCAST_(7) << 13)
+#define MIPS_CONF1_IA_SHF 16
+#define MIPS_CONF1_IA_SZ 3
#define MIPS_CONF1_IA (_ULCAST_(7) << 16)
+#define MIPS_CONF1_IL_SHF 19
+#define MIPS_CONF1_IL_SZ 3
#define MIPS_CONF1_IL (_ULCAST_(7) << 19)
+#define MIPS_CONF1_IS_SHF 22
+#define MIPS_CONF1_IS_SZ 3
#define MIPS_CONF1_IS (_ULCAST_(7) << 22)
#define MIPS_CONF1_TLBS_SHIFT (25)
#define MIPS_CONF1_TLBS_SIZE (6)
@@ -653,9 +665,16 @@
#define MIPS_CONF7_RPS (_ULCAST_(1) << 2)
+#define MIPS_CONF7_IAR (_ULCAST_(1) << 10)
+#define MIPS_CONF7_AR (_ULCAST_(1) << 16)
+
/* EntryHI bit definition */
#define MIPS_ENTRYHI_EHINV (_ULCAST_(1) << 10)
+/* CMGCRBase bit definitions */
+#define MIPS_CMGCRB_BASE 11
+#define MIPS_CMGCRF_BASE (~_ULCAST_((1 << MIPS_CMGCRB_BASE) - 1))
+
/*
* Bits in the MIPS32/64 coprocessor 1 (FPU) revision register.
*/
@@ -1010,6 +1029,8 @@ do { \
#define read_c0_prid() __read_32bit_c0_register($15, 0)
+#define read_c0_cmgcrbase() __read_ulong_c0_register($15, 3)
+
#define read_c0_config() __read_32bit_c0_register($16, 0)
#define read_c0_config1() __read_32bit_c0_register($16, 1)
#define read_c0_config2() __read_32bit_c0_register($16, 2)
@@ -1883,6 +1904,7 @@ change_c0_##name(unsigned int change, unsigned int newbits) \
__BUILD_SET_C0(status)
__BUILD_SET_C0(cause)
__BUILD_SET_C0(config)
+__BUILD_SET_C0(config5)
__BUILD_SET_C0(intcontrol)
__BUILD_SET_C0(intctl)
__BUILD_SET_C0(srsmap)
diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h
index 44b705d08262..c2edae382d5d 100644
--- a/arch/mips/include/asm/module.h
+++ b/arch/mips/include/asm/module.h
@@ -126,6 +126,8 @@ search_module_dbetables(unsigned long addr)
#define MODULE_PROC_FAMILY "LOONGSON1 "
#elif defined CONFIG_CPU_LOONGSON2
#define MODULE_PROC_FAMILY "LOONGSON2 "
+#elif defined CONFIG_CPU_LOONGSON3
+#define MODULE_PROC_FAMILY "LOONGSON3 "
#elif defined CONFIG_CPU_CAVIUM_OCTEON
#define MODULE_PROC_FAMILY "OCTEON "
#elif defined CONFIG_CPU_XLR
diff --git a/arch/mips/include/asm/msa.h b/arch/mips/include/asm/msa.h
new file mode 100644
index 000000000000..a2aba6c3ec05
--- /dev/null
+++ b/arch/mips/include/asm/msa.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.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.
+ */
+#ifndef _ASM_MSA_H
+#define _ASM_MSA_H
+
+#include <asm/mipsregs.h>
+
+extern void _save_msa(struct task_struct *);
+extern void _restore_msa(struct task_struct *);
+
+static inline void enable_msa(void)
+{
+ if (cpu_has_msa) {
+ set_c0_config5(MIPS_CONF5_MSAEN);
+ enable_fpu_hazard();
+ }
+}
+
+static inline void disable_msa(void)
+{
+ if (cpu_has_msa) {
+ clear_c0_config5(MIPS_CONF5_MSAEN);
+ disable_fpu_hazard();
+ }
+}
+
+static inline int is_msa_enabled(void)
+{
+ if (!cpu_has_msa)
+ return 0;
+
+ return read_c0_config5() & MIPS_CONF5_MSAEN;
+}
+
+static inline int thread_msa_context_live(void)
+{
+ /*
+ * Check cpu_has_msa only if it's a constant. This will allow the
+ * compiler to optimise out code for CPUs without MSA without adding
+ * an extra redundant check for CPUs with MSA.
+ */
+ if (__builtin_constant_p(cpu_has_msa) && !cpu_has_msa)
+ return 0;
+
+ return test_thread_flag(TIF_MSA_CTX_LIVE);
+}
+
+static inline void save_msa(struct task_struct *t)
+{
+ if (cpu_has_msa)
+ _save_msa(t);
+}
+
+static inline void restore_msa(struct task_struct *t)
+{
+ if (cpu_has_msa)
+ _restore_msa(t);
+}
+
+#ifdef TOOLCHAIN_SUPPORTS_MSA
+
+#define __BUILD_MSA_CTL_REG(name, cs) \
+static inline unsigned int read_msa_##name(void) \
+{ \
+ unsigned int reg; \
+ __asm__ __volatile__( \
+ " .set push\n" \
+ " .set msa\n" \
+ " cfcmsa %0, $" #cs "\n" \
+ " .set pop\n" \
+ : "=r"(reg)); \
+ return reg; \
+} \
+ \
+static inline void write_msa_##name(unsigned int val) \
+{ \
+ __asm__ __volatile__( \
+ " .set push\n" \
+ " .set msa\n" \
+ " cfcmsa $" #cs ", %0\n" \
+ " .set pop\n" \
+ : : "r"(val)); \
+}
+
+#else /* !TOOLCHAIN_SUPPORTS_MSA */
+
+/*
+ * Define functions using .word for the c[ft]cmsa instructions in order to
+ * allow compilation with toolchains that do not support MSA. Once all
+ * toolchains in use support MSA these can be removed.
+ */
+
+#define __BUILD_MSA_CTL_REG(name, cs) \
+static inline unsigned int read_msa_##name(void) \
+{ \
+ unsigned int reg; \
+ __asm__ __volatile__( \
+ " .set push\n" \
+ " .set noat\n" \
+ " .word 0x787e0059 | (" #cs " << 11)\n" \
+ " move %0, $1\n" \
+ " .set pop\n" \
+ : "=r"(reg)); \
+ return reg; \
+} \
+ \
+static inline void write_msa_##name(unsigned int val) \
+{ \
+ __asm__ __volatile__( \
+ " .set push\n" \
+ " .set noat\n" \
+ " move $1, %0\n" \
+ " .word 0x783e0819 | (" #cs " << 6)\n" \
+ " .set pop\n" \
+ : : "r"(val)); \
+}
+
+#endif /* !TOOLCHAIN_SUPPORTS_MSA */
+
+#define MSA_IR 0
+#define MSA_CSR 1
+#define MSA_ACCESS 2
+#define MSA_SAVE 3
+#define MSA_MODIFY 4
+#define MSA_REQUEST 5
+#define MSA_MAP 6
+#define MSA_UNMAP 7
+
+__BUILD_MSA_CTL_REG(ir, 0)
+__BUILD_MSA_CTL_REG(csr, 1)
+__BUILD_MSA_CTL_REG(access, 2)
+__BUILD_MSA_CTL_REG(save, 3)
+__BUILD_MSA_CTL_REG(modify, 4)
+__BUILD_MSA_CTL_REG(request, 5)
+__BUILD_MSA_CTL_REG(map, 6)
+__BUILD_MSA_CTL_REG(unmap, 7)
+
+/* MSA Implementation Register (MSAIR) */
+#define MSA_IR_REVB 0
+#define MSA_IR_REVF (_ULCAST_(0xff) << MSA_IR_REVB)
+#define MSA_IR_PROCB 8
+#define MSA_IR_PROCF (_ULCAST_(0xff) << MSA_IR_PROCB)
+#define MSA_IR_WRPB 16
+#define MSA_IR_WRPF (_ULCAST_(0x1) << MSA_IR_WRPB)
+
+/* MSA Control & Status Register (MSACSR) */
+#define MSA_CSR_RMB 0
+#define MSA_CSR_RMF (_ULCAST_(0x3) << MSA_CSR_RMB)
+#define MSA_CSR_RM_NEAREST 0
+#define MSA_CSR_RM_TO_ZERO 1
+#define MSA_CSR_RM_TO_POS 2
+#define MSA_CSR_RM_TO_NEG 3
+#define MSA_CSR_FLAGSB 2
+#define MSA_CSR_FLAGSF (_ULCAST_(0x1f) << MSA_CSR_FLAGSB)
+#define MSA_CSR_FLAGS_IB 2
+#define MSA_CSR_FLAGS_IF (_ULCAST_(0x1) << MSA_CSR_FLAGS_IB)
+#define MSA_CSR_FLAGS_UB 3
+#define MSA_CSR_FLAGS_UF (_ULCAST_(0x1) << MSA_CSR_FLAGS_UB)
+#define MSA_CSR_FLAGS_OB 4
+#define MSA_CSR_FLAGS_OF (_ULCAST_(0x1) << MSA_CSR_FLAGS_OB)
+#define MSA_CSR_FLAGS_ZB 5
+#define MSA_CSR_FLAGS_ZF (_ULCAST_(0x1) << MSA_CSR_FLAGS_ZB)
+#define MSA_CSR_FLAGS_VB 6
+#define MSA_CSR_FLAGS_VF (_ULCAST_(0x1) << MSA_CSR_FLAGS_VB)
+#define MSA_CSR_ENABLESB 7
+#define MSA_CSR_ENABLESF (_ULCAST_(0x1f) << MSA_CSR_ENABLESB)
+#define MSA_CSR_ENABLES_IB 7
+#define MSA_CSR_ENABLES_IF (_ULCAST_(0x1) << MSA_CSR_ENABLES_IB)
+#define MSA_CSR_ENABLES_UB 8
+#define MSA_CSR_ENABLES_UF (_ULCAST_(0x1) << MSA_CSR_ENABLES_UB)
+#define MSA_CSR_ENABLES_OB 9
+#define MSA_CSR_ENABLES_OF (_ULCAST_(0x1) << MSA_CSR_ENABLES_OB)
+#define MSA_CSR_ENABLES_ZB 10
+#define MSA_CSR_ENABLES_ZF (_ULCAST_(0x1) << MSA_CSR_ENABLES_ZB)
+#define MSA_CSR_ENABLES_VB 11
+#define MSA_CSR_ENABLES_VF (_ULCAST_(0x1) << MSA_CSR_ENABLES_VB)
+#define MSA_CSR_CAUSEB 12
+#define MSA_CSR_CAUSEF (_ULCAST_(0x3f) << MSA_CSR_CAUSEB)
+#define MSA_CSR_CAUSE_IB 12
+#define MSA_CSR_CAUSE_IF (_ULCAST_(0x1) << MSA_CSR_CAUSE_IB)
+#define MSA_CSR_CAUSE_UB 13
+#define MSA_CSR_CAUSE_UF (_ULCAST_(0x1) << MSA_CSR_CAUSE_UB)
+#define MSA_CSR_CAUSE_OB 14
+#define MSA_CSR_CAUSE_OF (_ULCAST_(0x1) << MSA_CSR_CAUSE_OB)
+#define MSA_CSR_CAUSE_ZB 15
+#define MSA_CSR_CAUSE_ZF (_ULCAST_(0x1) << MSA_CSR_CAUSE_ZB)
+#define MSA_CSR_CAUSE_VB 16
+#define MSA_CSR_CAUSE_VF (_ULCAST_(0x1) << MSA_CSR_CAUSE_VB)
+#define MSA_CSR_CAUSE_EB 17
+#define MSA_CSR_CAUSE_EF (_ULCAST_(0x1) << MSA_CSR_CAUSE_EB)
+#define MSA_CSR_NXB 18
+#define MSA_CSR_NXF (_ULCAST_(0x1) << MSA_CSR_NXB)
+#define MSA_CSR_FSB 24
+#define MSA_CSR_FSF (_ULCAST_(0x1) << MSA_CSR_FSB)
+
+#endif /* _ASM_MSA_H */
diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
index 5e08bcc74897..5699ec3a71af 100644
--- a/arch/mips/include/asm/page.h
+++ b/arch/mips/include/asm/page.h
@@ -190,7 +190,9 @@ typedef struct { unsigned long pgprot; } pgprot_t;
* https://patchwork.linux-mips.org/patch/1541/
*/
+#ifndef __pa_symbol
#define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x), 0))
+#endif
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
diff --git a/arch/mips/include/asm/pgtable-bits.h b/arch/mips/include/asm/pgtable-bits.h
index 32aea4852fb0..e592f3687d6f 100644
--- a/arch/mips/include/asm/pgtable-bits.h
+++ b/arch/mips/include/asm/pgtable-bits.h
@@ -235,6 +235,15 @@ static inline uint64_t pte_to_entrylo(unsigned long pte_val)
#define _CACHE_CACHABLE_NONCOHERENT (5<<_CACHE_SHIFT)
#define _CACHE_UNCACHED_ACCELERATED (7<<_CACHE_SHIFT)
+#elif defined(CONFIG_CPU_LOONGSON3)
+
+/* Using COHERENT flag for NONCOHERENT doesn't hurt. */
+
+#define _CACHE_UNCACHED (2<<_CACHE_SHIFT) /* LOONGSON */
+#define _CACHE_CACHABLE_NONCOHERENT (3<<_CACHE_SHIFT) /* LOONGSON */
+#define _CACHE_CACHABLE_COHERENT (3<<_CACHE_SHIFT) /* LOONGSON-3 */
+#define _CACHE_UNCACHED_ACCELERATED (7<<_CACHE_SHIFT) /* LOONGSON */
+
#else
#define _CACHE_CACHABLE_NO_WA (0<<_CACHE_SHIFT) /* R4600 only */
diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h
index 3605b844ad87..ad70cba8daff 100644
--- a/arch/mips/include/asm/processor.h
+++ b/arch/mips/include/asm/processor.h
@@ -97,18 +97,48 @@ extern unsigned int vced_count, vcei_count;
#define NUM_FPU_REGS 32
-typedef __u64 fpureg_t;
+#ifdef CONFIG_CPU_HAS_MSA
+# define FPU_REG_WIDTH 128
+#else
+# define FPU_REG_WIDTH 64
+#endif
+
+union fpureg {
+ __u32 val32[FPU_REG_WIDTH / 32];
+ __u64 val64[FPU_REG_WIDTH / 64];
+};
+
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+# define FPR_IDX(width, idx) (idx)
+#else
+# define FPR_IDX(width, idx) ((FPU_REG_WIDTH / (width)) - 1 - (idx))
+#endif
+
+#define BUILD_FPR_ACCESS(width) \
+static inline u##width get_fpr##width(union fpureg *fpr, unsigned idx) \
+{ \
+ return fpr->val##width[FPR_IDX(width, idx)]; \
+} \
+ \
+static inline void set_fpr##width(union fpureg *fpr, unsigned idx, \
+ u##width val) \
+{ \
+ fpr->val##width[FPR_IDX(width, idx)] = val; \
+}
+
+BUILD_FPR_ACCESS(32)
+BUILD_FPR_ACCESS(64)
/*
- * It would be nice to add some more fields for emulator statistics, but there
- * are a number of fixed offsets in offset.h and elsewhere that would have to
- * be recalculated by hand. So the additional information will be private to
- * the FPU emulator for now. See asm-mips/fpu_emulator.h.
+ * It would be nice to add some more fields for emulator statistics,
+ * the additional information is private to the FPU emulator for now.
+ * See arch/mips/include/asm/fpu_emulator.h.
*/
struct mips_fpu_struct {
- fpureg_t fpr[NUM_FPU_REGS];
+ union fpureg fpr[NUM_FPU_REGS];
unsigned int fcr31;
+ unsigned int msacsr;
};
#define NUM_DSP_REGS 6
@@ -284,8 +314,9 @@ struct thread_struct {
* Saved FPU/FPU emulator stuff \
*/ \
.fpu = { \
- .fpr = {0,}, \
+ .fpr = {{{0,},},}, \
.fcr31 = 0, \
+ .msacsr = 0, \
}, \
/* \
* FPU affinity state (null if not FPAFF) \
diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h
index 7bba9da110af..bf1ac8d35783 100644
--- a/arch/mips/include/asm/ptrace.h
+++ b/arch/mips/include/asm/ptrace.h
@@ -82,7 +82,7 @@ static inline long regs_return_value(struct pt_regs *regs)
#define instruction_pointer(regs) ((regs)->cp0_epc)
#define profile_pc(regs) instruction_pointer(regs)
-extern asmlinkage void syscall_trace_enter(struct pt_regs *regs);
+extern asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall);
extern asmlinkage void syscall_trace_leave(struct pt_regs *regs);
extern void die(const char *, struct pt_regs *) __noreturn;
diff --git a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h
index c84caddb8bde..ca64cbe44493 100644
--- a/arch/mips/include/asm/r4kcache.h
+++ b/arch/mips/include/asm/r4kcache.h
@@ -17,6 +17,7 @@
#include <asm/cpu-features.h>
#include <asm/cpu-type.h>
#include <asm/mipsmtregs.h>
+#include <asm/uaccess.h> /* for segment_eq() */
/*
* This macro return a properly sign-extended address suitable as base address
@@ -35,7 +36,7 @@
__asm__ __volatile__( \
" .set push \n" \
" .set noreorder \n" \
- " .set mips3\n\t \n" \
+ " .set arch=r4000 \n" \
" cache %0, %1 \n" \
" .set pop \n" \
: \
@@ -203,7 +204,7 @@ static inline void flush_scache_line(unsigned long addr)
__asm__ __volatile__( \
" .set push \n" \
" .set noreorder \n" \
- " .set mips3 \n" \
+ " .set arch=r4000 \n" \
"1: cache %0, (%1) \n" \
"2: .set pop \n" \
" .section __ex_table,\"a\" \n" \
@@ -212,6 +213,20 @@ static inline void flush_scache_line(unsigned long addr)
: \
: "i" (op), "r" (addr))
+#define protected_cachee_op(op,addr) \
+ __asm__ __volatile__( \
+ " .set push \n" \
+ " .set noreorder \n" \
+ " .set mips0 \n" \
+ " .set eva \n" \
+ "1: cachee %0, (%1) \n" \
+ "2: .set pop \n" \
+ " .section __ex_table,\"a\" \n" \
+ " "STR(PTR)" 1b, 2b \n" \
+ " .previous" \
+ : \
+ : "i" (op), "r" (addr))
+
/*
* The next two are for badland addresses like signal trampolines.
*/
@@ -223,7 +238,11 @@ static inline void protected_flush_icache_line(unsigned long addr)
break;
default:
+#ifdef CONFIG_EVA
+ protected_cachee_op(Hit_Invalidate_I, addr);
+#else
protected_cache_op(Hit_Invalidate_I, addr);
+#endif
break;
}
}
@@ -356,6 +375,91 @@ static inline void invalidate_tcache_page(unsigned long addr)
: "r" (base), \
"i" (op));
+/*
+ * Perform the cache operation specified by op using a user mode virtual
+ * address while in kernel mode.
+ */
+#define cache16_unroll32_user(base,op) \
+ __asm__ __volatile__( \
+ " .set push \n" \
+ " .set noreorder \n" \
+ " .set mips0 \n" \
+ " .set eva \n" \
+ " cachee %1, 0x000(%0); cachee %1, 0x010(%0) \n" \
+ " cachee %1, 0x020(%0); cachee %1, 0x030(%0) \n" \
+ " cachee %1, 0x040(%0); cachee %1, 0x050(%0) \n" \
+ " cachee %1, 0x060(%0); cachee %1, 0x070(%0) \n" \
+ " cachee %1, 0x080(%0); cachee %1, 0x090(%0) \n" \
+ " cachee %1, 0x0a0(%0); cachee %1, 0x0b0(%0) \n" \
+ " cachee %1, 0x0c0(%0); cachee %1, 0x0d0(%0) \n" \
+ " cachee %1, 0x0e0(%0); cachee %1, 0x0f0(%0) \n" \
+ " cachee %1, 0x100(%0); cachee %1, 0x110(%0) \n" \
+ " cachee %1, 0x120(%0); cachee %1, 0x130(%0) \n" \
+ " cachee %1, 0x140(%0); cachee %1, 0x150(%0) \n" \
+ " cachee %1, 0x160(%0); cachee %1, 0x170(%0) \n" \
+ " cachee %1, 0x180(%0); cachee %1, 0x190(%0) \n" \
+ " cachee %1, 0x1a0(%0); cachee %1, 0x1b0(%0) \n" \
+ " cachee %1, 0x1c0(%0); cachee %1, 0x1d0(%0) \n" \
+ " cachee %1, 0x1e0(%0); cachee %1, 0x1f0(%0) \n" \
+ " .set pop \n" \
+ : \
+ : "r" (base), \
+ "i" (op));
+
+#define cache32_unroll32_user(base, op) \
+ __asm__ __volatile__( \
+ " .set push \n" \
+ " .set noreorder \n" \
+ " .set mips0 \n" \
+ " .set eva \n" \
+ " cachee %1, 0x000(%0); cachee %1, 0x020(%0) \n" \
+ " cachee %1, 0x040(%0); cachee %1, 0x060(%0) \n" \
+ " cachee %1, 0x080(%0); cachee %1, 0x0a0(%0) \n" \
+ " cachee %1, 0x0c0(%0); cachee %1, 0x0e0(%0) \n" \
+ " cachee %1, 0x100(%0); cachee %1, 0x120(%0) \n" \
+ " cachee %1, 0x140(%0); cachee %1, 0x160(%0) \n" \
+ " cachee %1, 0x180(%0); cachee %1, 0x1a0(%0) \n" \
+ " cachee %1, 0x1c0(%0); cachee %1, 0x1e0(%0) \n" \
+ " cachee %1, 0x200(%0); cachee %1, 0x220(%0) \n" \
+ " cachee %1, 0x240(%0); cachee %1, 0x260(%0) \n" \
+ " cachee %1, 0x280(%0); cachee %1, 0x2a0(%0) \n" \
+ " cachee %1, 0x2c0(%0); cachee %1, 0x2e0(%0) \n" \
+ " cachee %1, 0x300(%0); cachee %1, 0x320(%0) \n" \
+ " cachee %1, 0x340(%0); cachee %1, 0x360(%0) \n" \
+ " cachee %1, 0x380(%0); cachee %1, 0x3a0(%0) \n" \
+ " cachee %1, 0x3c0(%0); cachee %1, 0x3e0(%0) \n" \
+ " .set pop \n" \
+ : \
+ : "r" (base), \
+ "i" (op));
+
+#define cache64_unroll32_user(base, op) \
+ __asm__ __volatile__( \
+ " .set push \n" \
+ " .set noreorder \n" \
+ " .set mips0 \n" \
+ " .set eva \n" \
+ " cachee %1, 0x000(%0); cachee %1, 0x040(%0) \n" \
+ " cachee %1, 0x080(%0); cachee %1, 0x0c0(%0) \n" \
+ " cachee %1, 0x100(%0); cachee %1, 0x140(%0) \n" \
+ " cachee %1, 0x180(%0); cachee %1, 0x1c0(%0) \n" \
+ " cachee %1, 0x200(%0); cachee %1, 0x240(%0) \n" \
+ " cachee %1, 0x280(%0); cachee %1, 0x2c0(%0) \n" \
+ " cachee %1, 0x300(%0); cachee %1, 0x340(%0) \n" \
+ " cachee %1, 0x380(%0); cachee %1, 0x3c0(%0) \n" \
+ " cachee %1, 0x400(%0); cachee %1, 0x440(%0) \n" \
+ " cachee %1, 0x480(%0); cachee %1, 0x4c0(%0) \n" \
+ " cachee %1, 0x500(%0); cachee %1, 0x540(%0) \n" \
+ " cachee %1, 0x580(%0); cachee %1, 0x5c0(%0) \n" \
+ " cachee %1, 0x600(%0); cachee %1, 0x640(%0) \n" \
+ " cachee %1, 0x680(%0); cachee %1, 0x6c0(%0) \n" \
+ " cachee %1, 0x700(%0); cachee %1, 0x740(%0) \n" \
+ " cachee %1, 0x780(%0); cachee %1, 0x7c0(%0) \n" \
+ " .set pop \n" \
+ : \
+ : "r" (base), \
+ "i" (op));
+
/* build blast_xxx, blast_xxx_page, blast_xxx_page_indexed */
#define __BUILD_BLAST_CACHE(pfx, desc, indexop, hitop, lsize, extra) \
static inline void extra##blast_##pfx##cache##lsize(void) \
@@ -429,6 +533,32 @@ __BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 32
__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 64, )
__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 128, )
+#define __BUILD_BLAST_USER_CACHE(pfx, desc, indexop, hitop, lsize) \
+static inline void blast_##pfx##cache##lsize##_user_page(unsigned long page) \
+{ \
+ unsigned long start = page; \
+ unsigned long end = page + PAGE_SIZE; \
+ \
+ __##pfx##flush_prologue \
+ \
+ do { \
+ cache##lsize##_unroll32_user(start, hitop); \
+ start += lsize * 32; \
+ } while (start < end); \
+ \
+ __##pfx##flush_epilogue \
+}
+
+__BUILD_BLAST_USER_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D,
+ 16)
+__BUILD_BLAST_USER_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16)
+__BUILD_BLAST_USER_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D,
+ 32)
+__BUILD_BLAST_USER_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32)
+__BUILD_BLAST_USER_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D,
+ 64)
+__BUILD_BLAST_USER_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64)
+
/* build blast_xxx_range, protected_blast_xxx_range */
#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot, extra) \
static inline void prot##extra##blast_##pfx##cache##_range(unsigned long start, \
@@ -450,12 +580,51 @@ static inline void prot##extra##blast_##pfx##cache##_range(unsigned long start,
__##pfx##flush_epilogue \
}
+#ifndef CONFIG_EVA
+
__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_, )
-__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_, )
__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_, )
+
+#else
+
+#define __BUILD_PROT_BLAST_CACHE_RANGE(pfx, desc, hitop) \
+static inline void protected_blast_##pfx##cache##_range(unsigned long start,\
+ unsigned long end) \
+{ \
+ unsigned long lsize = cpu_##desc##_line_size(); \
+ unsigned long addr = start & ~(lsize - 1); \
+ unsigned long aend = (end - 1) & ~(lsize - 1); \
+ \
+ __##pfx##flush_prologue \
+ \
+ if (segment_eq(get_fs(), USER_DS)) { \
+ while (1) { \
+ protected_cachee_op(hitop, addr); \
+ if (addr == aend) \
+ break; \
+ addr += lsize; \
+ } \
+ } else { \
+ while (1) { \
+ protected_cache_op(hitop, addr); \
+ if (addr == aend) \
+ break; \
+ addr += lsize; \
+ } \
+ \
+ } \
+ __##pfx##flush_epilogue \
+}
+
+__BUILD_PROT_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D)
+__BUILD_PROT_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I)
+
+#endif
+__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_, )
__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I_Loongson2, \
protected_, loongson2_)
__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, , )
+__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, , )
__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, , )
/* blast_inv_dcache_range */
__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, , )
diff --git a/arch/mips/include/asm/sigcontext.h b/arch/mips/include/asm/sigcontext.h
index eeeb0f48c767..f54bdbe85c0d 100644
--- a/arch/mips/include/asm/sigcontext.h
+++ b/arch/mips/include/asm/sigcontext.h
@@ -32,6 +32,8 @@ struct sigcontext32 {
__u32 sc_lo2;
__u32 sc_hi3;
__u32 sc_lo3;
+ __u64 sc_msaregs[32]; /* Most significant 64 bits */
+ __u32 sc_msa_csr;
};
#endif /* _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32 */
#endif /* _ASM_SIGCONTEXT_H */
diff --git a/arch/mips/include/asm/smp-cps.h b/arch/mips/include/asm/smp-cps.h
new file mode 100644
index 000000000000..d60d1a2180d1
--- /dev/null
+++ b/arch/mips/include/asm/smp-cps.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.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.
+ */
+
+#ifndef __MIPS_ASM_SMP_CPS_H__
+#define __MIPS_ASM_SMP_CPS_H__
+
+#ifndef __ASSEMBLY__
+
+struct boot_config {
+ unsigned int core;
+ unsigned int vpe;
+ unsigned long pc;
+ unsigned long sp;
+ unsigned long gp;
+};
+
+extern struct boot_config mips_cps_bootcfg;
+
+extern void mips_cps_core_entry(void);
+
+#else /* __ASSEMBLY__ */
+
+.extern mips_cps_bootcfg;
+
+#endif /* __ASSEMBLY__ */
+#endif /* __MIPS_ASM_SMP_CPS_H__ */
diff --git a/arch/mips/include/asm/smp-ops.h b/arch/mips/include/asm/smp-ops.h
index ef2a8041e78b..73d35b18fb64 100644
--- a/arch/mips/include/asm/smp-ops.h
+++ b/arch/mips/include/asm/smp-ops.h
@@ -13,6 +13,8 @@
#include <linux/errno.h>
+#include <asm/mips-cm.h>
+
#ifdef CONFIG_SMP
#include <linux/cpumask.h>
@@ -43,6 +45,9 @@ static inline void plat_smp_setup(void)
mp_ops->smp_setup();
}
+extern void gic_send_ipi_single(int cpu, unsigned int action);
+extern void gic_send_ipi_mask(const struct cpumask *mask, unsigned int action);
+
#else /* !CONFIG_SMP */
struct plat_smp_ops;
@@ -76,6 +81,9 @@ static inline int register_cmp_smp_ops(void)
#ifdef CONFIG_MIPS_CMP
extern struct plat_smp_ops cmp_smp_ops;
+ if (!mips_cm_present())
+ return -ENODEV;
+
register_smp_ops(&cmp_smp_ops);
return 0;
@@ -97,4 +105,13 @@ static inline int register_vsmp_smp_ops(void)
#endif
}
+#ifdef CONFIG_MIPS_CPS
+extern int register_cps_smp_ops(void);
+#else
+static inline int register_cps_smp_ops(void)
+{
+ return -ENODEV;
+}
+#endif
+
#endif /* __ASM_SMP_OPS_H */
diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h
index eb6008758484..efa02acd3dd5 100644
--- a/arch/mips/include/asm/smp.h
+++ b/arch/mips/include/asm/smp.h
@@ -42,6 +42,7 @@ extern int __cpu_logical_map[NR_CPUS];
#define SMP_ICACHE_FLUSH 0x4
/* Used by kexec crashdump to save all cpu's state */
#define SMP_DUMP 0x8
+#define SMP_ASK_C0COUNT 0x10
extern volatile cpumask_t cpu_callin_map;
diff --git a/arch/mips/include/asm/stackframe.h b/arch/mips/include/asm/stackframe.h
index 4857e2c8df5a..d301e108d5b8 100644
--- a/arch/mips/include/asm/stackframe.h
+++ b/arch/mips/include/asm/stackframe.h
@@ -435,7 +435,7 @@
.macro RESTORE_SP_AND_RET
LONG_L sp, PT_R29(sp)
- .set mips3
+ .set arch=r4000
eret
.set mips0
.endm
diff --git a/arch/mips/include/asm/switch_to.h b/arch/mips/include/asm/switch_to.h
index 278d45a09728..495c1041a2cc 100644
--- a/arch/mips/include/asm/switch_to.h
+++ b/arch/mips/include/asm/switch_to.h
@@ -16,22 +16,29 @@
#include <asm/watch.h>
#include <asm/dsp.h>
#include <asm/cop2.h>
+#include <asm/msa.h>
struct task_struct;
+enum {
+ FP_SAVE_NONE = 0,
+ FP_SAVE_VECTOR = -1,
+ FP_SAVE_SCALAR = 1,
+};
+
/**
* resume - resume execution of a task
* @prev: The task previously executed.
* @next: The task to begin executing.
* @next_ti: task_thread_info(next).
- * @usedfpu: Non-zero if prev's FP context should be saved.
+ * @fp_save: Which, if any, FP context to save for prev.
*
* This function is used whilst scheduling to save the context of prev & load
* the context of next. Returns prev.
*/
extern asmlinkage struct task_struct *resume(struct task_struct *prev,
struct task_struct *next, struct thread_info *next_ti,
- u32 usedfpu);
+ s32 fp_save);
extern unsigned int ll_bit;
extern struct task_struct *ll_task;
@@ -75,7 +82,8 @@ do { \
#define switch_to(prev, next, last) \
do { \
- u32 __usedfpu, __c0_stat; \
+ u32 __c0_stat; \
+ s32 __fpsave = FP_SAVE_NONE; \
__mips_mt_fpaff_switch_to(prev); \
if (cpu_has_dsp) \
__save_dsp(prev); \
@@ -88,8 +96,12 @@ do { \
write_c0_status(__c0_stat & ~ST0_CU2); \
} \
__clear_software_ll_bit(); \
- __usedfpu = test_and_clear_tsk_thread_flag(prev, TIF_USEDFPU); \
- (last) = resume(prev, next, task_thread_info(next), __usedfpu); \
+ if (test_and_clear_tsk_thread_flag(prev, TIF_USEDFPU)) \
+ __fpsave = FP_SAVE_SCALAR; \
+ if (test_and_clear_tsk_thread_flag(prev, TIF_USEDMSA)) \
+ __fpsave = FP_SAVE_VECTOR; \
+ (last) = resume(prev, next, task_thread_info(next), __fpsave); \
+ disable_msa(); \
} while (0)
#define finish_arch_switch(prev) \
diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h
index 33e8dbfc1b63..6c488c85d791 100644
--- a/arch/mips/include/asm/syscall.h
+++ b/arch/mips/include/asm/syscall.h
@@ -13,17 +13,29 @@
#ifndef __ASM_MIPS_SYSCALL_H
#define __ASM_MIPS_SYSCALL_H
+#include <linux/compiler.h>
#include <linux/audit.h>
#include <linux/elf-em.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <asm/ptrace.h>
+#include <asm/unistd.h>
+
+#ifndef __NR_syscall /* Only defined if _MIPS_SIM == _MIPS_SIM_ABI32 */
+#define __NR_syscall 4000
+#endif
static inline long syscall_get_nr(struct task_struct *task,
struct pt_regs *regs)
{
- return regs->regs[2];
+ /* O32 ABI syscall() - Either 64-bit with O32 or 32-bit */
+ if ((config_enabled(CONFIG_32BIT) ||
+ test_tsk_thread_flag(task, TIF_32BIT_REGS)) &&
+ (regs->regs[2] == __NR_syscall))
+ return regs->regs[4];
+ else
+ return regs->regs[2];
}
static inline unsigned long mips_get_syscall_arg(unsigned long *arg,
@@ -39,14 +51,14 @@ static inline unsigned long mips_get_syscall_arg(unsigned long *arg,
#ifdef CONFIG_32BIT
case 4: case 5: case 6: case 7:
- return get_user(*arg, (int *)usp + 4 * n);
+ return get_user(*arg, (int *)usp + n);
#endif
#ifdef CONFIG_64BIT
case 4: case 5: case 6: case 7:
#ifdef CONFIG_MIPS32_O32
if (test_thread_flag(TIF_32BIT_REGS))
- return get_user(*arg, (int *)usp + 4 * n);
+ return get_user(*arg, (int *)usp + n);
else
#endif
*arg = regs->regs[4 + n];
@@ -57,6 +69,8 @@ static inline unsigned long mips_get_syscall_arg(unsigned long *arg,
default:
BUG();
}
+
+ unreachable();
}
static inline long syscall_get_return_value(struct task_struct *task,
@@ -65,6 +79,12 @@ static inline long syscall_get_return_value(struct task_struct *task,
return regs->regs[2];
}
+static inline void syscall_rollback(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ /* Do nothing */
+}
+
static inline void syscall_set_return_value(struct task_struct *task,
struct pt_regs *regs,
int error, long val)
@@ -83,11 +103,17 @@ static inline void syscall_get_arguments(struct task_struct *task,
unsigned int i, unsigned int n,
unsigned long *args)
{
- unsigned long arg;
int ret;
+ /* O32 ABI syscall() - Either 64-bit with O32 or 32-bit */
+ if ((config_enabled(CONFIG_32BIT) ||
+ test_tsk_thread_flag(task, TIF_32BIT_REGS)) &&
+ (regs->regs[2] == __NR_syscall)) {
+ i++;
+ n++;
+ }
while (n--)
- ret |= mips_get_syscall_arg(&arg, task, regs, i++);
+ ret |= mips_get_syscall_arg(args++, task, regs, i++);
/*
* No way to communicate an error because this is a void function.
@@ -101,11 +127,13 @@ extern const unsigned long sys_call_table[];
extern const unsigned long sys32_call_table[];
extern const unsigned long sysn32_call_table[];
-static inline int __syscall_get_arch(void)
+static inline int syscall_get_arch(struct task_struct *task,
+ struct pt_regs *regs)
{
int arch = EM_MIPS;
#ifdef CONFIG_64BIT
- arch |= __AUDIT_ARCH_64BIT;
+ if (!test_tsk_thread_flag(task, TIF_32BIT_REGS))
+ arch |= __AUDIT_ARCH_64BIT;
#endif
#if defined(__LITTLE_ENDIAN)
arch |= __AUDIT_ARCH_LE;
diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h
index 24846f9053fe..d2d961d6cb86 100644
--- a/arch/mips/include/asm/thread_info.h
+++ b/arch/mips/include/asm/thread_info.h
@@ -116,6 +116,8 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_LOAD_WATCH 25 /* If set, load watch registers */
#define TIF_SYSCALL_TRACEPOINT 26 /* syscall tracepoint instrumentation */
#define TIF_32BIT_FPREGS 27 /* 32-bit floating point registers */
+#define TIF_USEDMSA 29 /* MSA has been used this quantum */
+#define TIF_MSA_CTX_LIVE 30 /* MSA context must be preserved */
#define TIF_SYSCALL_TRACE 31 /* syscall trace active */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
@@ -133,10 +135,13 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_FPUBOUND (1<<TIF_FPUBOUND)
#define _TIF_LOAD_WATCH (1<<TIF_LOAD_WATCH)
#define _TIF_32BIT_FPREGS (1<<TIF_32BIT_FPREGS)
+#define _TIF_USEDMSA (1<<TIF_USEDMSA)
+#define _TIF_MSA_CTX_LIVE (1<<TIF_MSA_CTX_LIVE)
#define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT)
#define _TIF_WORK_SYSCALL_ENTRY (_TIF_NOHZ | _TIF_SYSCALL_TRACE | \
- _TIF_SYSCALL_AUDIT | _TIF_SYSCALL_TRACEPOINT)
+ _TIF_SYSCALL_AUDIT | \
+ _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP)
/* work to do in syscall_trace_leave() */
#define _TIF_WORK_SYSCALL_EXIT (_TIF_NOHZ | _TIF_SYSCALL_TRACE | \
diff --git a/arch/mips/include/asm/topology.h b/arch/mips/include/asm/topology.h
index 12609a17dc8b..20ea4859c822 100644
--- a/arch/mips/include/asm/topology.h
+++ b/arch/mips/include/asm/topology.h
@@ -10,8 +10,4 @@
#include <topology.h>
-#ifdef CONFIG_SMP
-#define smt_capable() (smp_num_siblings > 1)
-#endif
-
#endif /* __ASM_TOPOLOGY_H */
diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h
index f3fa3750f577..a10951090234 100644
--- a/arch/mips/include/asm/uaccess.h
+++ b/arch/mips/include/asm/uaccess.h
@@ -6,6 +6,7 @@
* Copyright (C) 1996, 1997, 1998, 1999, 2000, 03, 04 by Ralf Baechle
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
* Copyright (C) 2007 Maciej W. Rozycki
+ * Copyright (C) 2014, Imagination Technologies Ltd.
*/
#ifndef _ASM_UACCESS_H
#define _ASM_UACCESS_H
@@ -13,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/thread_info.h>
+#include <asm/asm-eva.h>
/*
* The fs value determines whether argument validity checking should be
@@ -222,11 +224,44 @@ struct __large_struct { unsigned long buf[100]; };
* Yuck. We need two variants, one for 64bit operation and one
* for 32 bit mode and old iron.
*/
+#ifndef CONFIG_EVA
+#define __get_kernel_common(val, size, ptr) __get_user_common(val, size, ptr)
+#else
+/*
+ * Kernel specific functions for EVA. We need to use normal load instructions
+ * to read data from kernel when operating in EVA mode. We use these macros to
+ * avoid redefining __get_user_asm for EVA.
+ */
+#undef _loadd
+#undef _loadw
+#undef _loadh
+#undef _loadb
#ifdef CONFIG_32BIT
-#define __GET_USER_DW(val, ptr) __get_user_asm_ll32(val, ptr)
+#define _loadd _loadw
+#else
+#define _loadd(reg, addr) "ld " reg ", " addr
+#endif
+#define _loadw(reg, addr) "lw " reg ", " addr
+#define _loadh(reg, addr) "lh " reg ", " addr
+#define _loadb(reg, addr) "lb " reg ", " addr
+
+#define __get_kernel_common(val, size, ptr) \
+do { \
+ switch (size) { \
+ case 1: __get_data_asm(val, _loadb, ptr); break; \
+ case 2: __get_data_asm(val, _loadh, ptr); break; \
+ case 4: __get_data_asm(val, _loadw, ptr); break; \
+ case 8: __GET_DW(val, _loadd, ptr); break; \
+ default: __get_user_unknown(); break; \
+ } \
+} while (0)
+#endif
+
+#ifdef CONFIG_32BIT
+#define __GET_DW(val, insn, ptr) __get_data_asm_ll32(val, insn, ptr)
#endif
#ifdef CONFIG_64BIT
-#define __GET_USER_DW(val, ptr) __get_user_asm(val, "ld", ptr)
+#define __GET_DW(val, insn, ptr) __get_data_asm(val, insn, ptr)
#endif
extern void __get_user_unknown(void);
@@ -234,10 +269,10 @@ extern void __get_user_unknown(void);
#define __get_user_common(val, size, ptr) \
do { \
switch (size) { \
- case 1: __get_user_asm(val, "lb", ptr); break; \
- case 2: __get_user_asm(val, "lh", ptr); break; \
- case 4: __get_user_asm(val, "lw", ptr); break; \
- case 8: __GET_USER_DW(val, ptr); break; \
+ case 1: __get_data_asm(val, user_lb, ptr); break; \
+ case 2: __get_data_asm(val, user_lh, ptr); break; \
+ case 4: __get_data_asm(val, user_lw, ptr); break; \
+ case 8: __GET_DW(val, user_ld, ptr); break; \
default: __get_user_unknown(); break; \
} \
} while (0)
@@ -246,8 +281,12 @@ do { \
({ \
int __gu_err; \
\
- __chk_user_ptr(ptr); \
- __get_user_common((x), size, ptr); \
+ if (segment_eq(get_fs(), get_ds())) { \
+ __get_kernel_common((x), size, ptr); \
+ } else { \
+ __chk_user_ptr(ptr); \
+ __get_user_common((x), size, ptr); \
+ } \
__gu_err; \
})
@@ -257,18 +296,22 @@ do { \
const __typeof__(*(ptr)) __user * __gu_ptr = (ptr); \
\
might_fault(); \
- if (likely(access_ok(VERIFY_READ, __gu_ptr, size))) \
- __get_user_common((x), size, __gu_ptr); \
+ if (likely(access_ok(VERIFY_READ, __gu_ptr, size))) { \
+ if (segment_eq(get_fs(), get_ds())) \
+ __get_kernel_common((x), size, __gu_ptr); \
+ else \
+ __get_user_common((x), size, __gu_ptr); \
+ } \
\
__gu_err; \
})
-#define __get_user_asm(val, insn, addr) \
+#define __get_data_asm(val, insn, addr) \
{ \
long __gu_tmp; \
\
__asm__ __volatile__( \
- "1: " insn " %1, %3 \n" \
+ "1: "insn("%1", "%3")" \n" \
"2: \n" \
" .insn \n" \
" .section .fixup,\"ax\" \n" \
@@ -287,7 +330,7 @@ do { \
/*
* Get a long long 64 using 32 bit registers.
*/
-#define __get_user_asm_ll32(val, addr) \
+#define __get_data_asm_ll32(val, insn, addr) \
{ \
union { \
unsigned long long l; \
@@ -295,8 +338,8 @@ do { \
} __gu_tmp; \
\
__asm__ __volatile__( \
- "1: lw %1, (%3) \n" \
- "2: lw %D1, 4(%3) \n" \
+ "1: " insn("%1", "(%3)")" \n" \
+ "2: " insn("%D1", "4(%3)")" \n" \
"3: \n" \
" .insn \n" \
" .section .fixup,\"ax\" \n" \
@@ -315,30 +358,73 @@ do { \
(val) = __gu_tmp.t; \
}
+#ifndef CONFIG_EVA
+#define __put_kernel_common(ptr, size) __put_user_common(ptr, size)
+#else
+/*
+ * Kernel specific functions for EVA. We need to use normal load instructions
+ * to read data from kernel when operating in EVA mode. We use these macros to
+ * avoid redefining __get_data_asm for EVA.
+ */
+#undef _stored
+#undef _storew
+#undef _storeh
+#undef _storeb
+#ifdef CONFIG_32BIT
+#define _stored _storew
+#else
+#define _stored(reg, addr) "ld " reg ", " addr
+#endif
+
+#define _storew(reg, addr) "sw " reg ", " addr
+#define _storeh(reg, addr) "sh " reg ", " addr
+#define _storeb(reg, addr) "sb " reg ", " addr
+
+#define __put_kernel_common(ptr, size) \
+do { \
+ switch (size) { \
+ case 1: __put_data_asm(_storeb, ptr); break; \
+ case 2: __put_data_asm(_storeh, ptr); break; \
+ case 4: __put_data_asm(_storew, ptr); break; \
+ case 8: __PUT_DW(_stored, ptr); break; \
+ default: __put_user_unknown(); break; \
+ } \
+} while(0)
+#endif
+
/*
* Yuck. We need two variants, one for 64bit operation and one
* for 32 bit mode and old iron.
*/
#ifdef CONFIG_32BIT
-#define __PUT_USER_DW(ptr) __put_user_asm_ll32(ptr)
+#define __PUT_DW(insn, ptr) __put_data_asm_ll32(insn, ptr)
#endif
#ifdef CONFIG_64BIT
-#define __PUT_USER_DW(ptr) __put_user_asm("sd", ptr)
+#define __PUT_DW(insn, ptr) __put_data_asm(insn, ptr)
#endif
+#define __put_user_common(ptr, size) \
+do { \
+ switch (size) { \
+ case 1: __put_data_asm(user_sb, ptr); break; \
+ case 2: __put_data_asm(user_sh, ptr); break; \
+ case 4: __put_data_asm(user_sw, ptr); break; \
+ case 8: __PUT_DW(user_sd, ptr); break; \
+ default: __put_user_unknown(); break; \
+ } \
+} while (0)
+
#define __put_user_nocheck(x, ptr, size) \
({ \
__typeof__(*(ptr)) __pu_val; \
int __pu_err = 0; \
\
- __chk_user_ptr(ptr); \
__pu_val = (x); \
- switch (size) { \
- case 1: __put_user_asm("sb", ptr); break; \
- case 2: __put_user_asm("sh", ptr); break; \
- case 4: __put_user_asm("sw", ptr); break; \
- case 8: __PUT_USER_DW(ptr); break; \
- default: __put_user_unknown(); break; \
+ if (segment_eq(get_fs(), get_ds())) { \
+ __put_kernel_common(ptr, size); \
+ } else { \
+ __chk_user_ptr(ptr); \
+ __put_user_common(ptr, size); \
} \
__pu_err; \
})
@@ -351,21 +437,19 @@ do { \
\
might_fault(); \
if (likely(access_ok(VERIFY_WRITE, __pu_addr, size))) { \
- switch (size) { \
- case 1: __put_user_asm("sb", __pu_addr); break; \
- case 2: __put_user_asm("sh", __pu_addr); break; \
- case 4: __put_user_asm("sw", __pu_addr); break; \
- case 8: __PUT_USER_DW(__pu_addr); break; \
- default: __put_user_unknown(); break; \
- } \
+ if (segment_eq(get_fs(), get_ds())) \
+ __put_kernel_common(__pu_addr, size); \
+ else \
+ __put_user_common(__pu_addr, size); \
} \
+ \
__pu_err; \
})
-#define __put_user_asm(insn, ptr) \
+#define __put_data_asm(insn, ptr) \
{ \
__asm__ __volatile__( \
- "1: " insn " %z2, %3 # __put_user_asm\n" \
+ "1: "insn("%z2", "%3")" # __put_data_asm \n" \
"2: \n" \
" .insn \n" \
" .section .fixup,\"ax\" \n" \
@@ -380,11 +464,11 @@ do { \
"i" (-EFAULT)); \
}
-#define __put_user_asm_ll32(ptr) \
+#define __put_data_asm_ll32(insn, ptr) \
{ \
__asm__ __volatile__( \
- "1: sw %2, (%3) # __put_user_asm_ll32 \n" \
- "2: sw %D2, 4(%3) \n" \
+ "1: "insn("%2", "(%3)")" # __put_data_asm_ll32 \n" \
+ "2: "insn("%D2", "4(%3)")" \n" \
"3: \n" \
" .insn \n" \
" .section .fixup,\"ax\" \n" \
@@ -403,6 +487,11 @@ do { \
extern void __put_user_unknown(void);
/*
+ * ul{b,h,w} are macros and there are no equivalent macros for EVA.
+ * EVA unaligned access is handled in the ADE exception handler.
+ */
+#ifndef CONFIG_EVA
+/*
* put_user_unaligned: - Write a simple value into user space.
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
@@ -504,7 +593,7 @@ extern void __get_user_unaligned_unknown(void);
#define __get_user_unaligned_common(val, size, ptr) \
do { \
switch (size) { \
- case 1: __get_user_asm(val, "lb", ptr); break; \
+ case 1: __get_data_asm(val, "lb", ptr); break; \
case 2: __get_user_unaligned_asm(val, "ulh", ptr); break; \
case 4: __get_user_unaligned_asm(val, "ulw", ptr); break; \
case 8: __GET_USER_UNALIGNED_DW(val, ptr); break; \
@@ -531,7 +620,7 @@ do { \
__gu_err; \
})
-#define __get_user_unaligned_asm(val, insn, addr) \
+#define __get_data_unaligned_asm(val, insn, addr) \
{ \
long __gu_tmp; \
\
@@ -594,19 +683,23 @@ do { \
#define __PUT_USER_UNALIGNED_DW(ptr) __put_user_unaligned_asm("usd", ptr)
#endif
+#define __put_user_unaligned_common(ptr, size) \
+do { \
+ switch (size) { \
+ case 1: __put_data_asm("sb", ptr); break; \
+ case 2: __put_user_unaligned_asm("ush", ptr); break; \
+ case 4: __put_user_unaligned_asm("usw", ptr); break; \
+ case 8: __PUT_USER_UNALIGNED_DW(ptr); break; \
+ default: __put_user_unaligned_unknown(); break; \
+} while (0)
+
#define __put_user_unaligned_nocheck(x,ptr,size) \
({ \
__typeof__(*(ptr)) __pu_val; \
int __pu_err = 0; \
\
__pu_val = (x); \
- switch (size) { \
- case 1: __put_user_asm("sb", ptr); break; \
- case 2: __put_user_unaligned_asm("ush", ptr); break; \
- case 4: __put_user_unaligned_asm("usw", ptr); break; \
- case 8: __PUT_USER_UNALIGNED_DW(ptr); break; \
- default: __put_user_unaligned_unknown(); break; \
- } \
+ __put_user_unaligned_common(ptr, size); \
__pu_err; \
})
@@ -616,15 +709,9 @@ do { \
__typeof__(*(ptr)) __pu_val = (x); \
int __pu_err = -EFAULT; \
\
- if (likely(access_ok(VERIFY_WRITE, __pu_addr, size))) { \
- switch (size) { \
- case 1: __put_user_asm("sb", __pu_addr); break; \
- case 2: __put_user_unaligned_asm("ush", __pu_addr); break; \
- case 4: __put_user_unaligned_asm("usw", __pu_addr); break; \
- case 8: __PUT_USER_UNALGINED_DW(__pu_addr); break; \
- default: __put_user_unaligned_unknown(); break; \
- } \
- } \
+ if (likely(access_ok(VERIFY_WRITE, __pu_addr, size))) \
+ __put_user_unaligned_common(__pu_addr, size); \
+ \
__pu_err; \
})
@@ -669,6 +756,7 @@ do { \
}
extern void __put_user_unaligned_unknown(void);
+#endif
/*
* We're generating jump to subroutines which will be outside the range of
@@ -693,6 +781,7 @@ extern void __put_user_unaligned_unknown(void);
extern size_t __copy_user(void *__to, const void *__from, size_t __n);
+#ifndef CONFIG_EVA
#define __invoke_copy_to_user(to, from, n) \
({ \
register void __user *__cu_to_r __asm__("$4"); \
@@ -711,6 +800,11 @@ extern size_t __copy_user(void *__to, const void *__from, size_t __n);
__cu_len_r; \
})
+#define __invoke_copy_to_kernel(to, from, n) \
+ __invoke_copy_to_user(to, from, n)
+
+#endif
+
/*
* __copy_to_user: - Copy a block of data into user space, with less checking.
* @to: Destination address, in user space.
@@ -735,7 +829,12 @@ extern size_t __copy_user(void *__to, const void *__from, size_t __n);
__cu_from = (from); \
__cu_len = (n); \
might_fault(); \
- __cu_len = __invoke_copy_to_user(__cu_to, __cu_from, __cu_len); \
+ if (segment_eq(get_fs(), get_ds())) \
+ __cu_len = __invoke_copy_to_kernel(__cu_to, __cu_from, \
+ __cu_len); \
+ else \
+ __cu_len = __invoke_copy_to_user(__cu_to, __cu_from, \
+ __cu_len); \
__cu_len; \
})
@@ -750,7 +849,12 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
__cu_to = (to); \
__cu_from = (from); \
__cu_len = (n); \
- __cu_len = __invoke_copy_to_user(__cu_to, __cu_from, __cu_len); \
+ if (segment_eq(get_fs(), get_ds())) \
+ __cu_len = __invoke_copy_to_kernel(__cu_to, __cu_from, \
+ __cu_len); \
+ else \
+ __cu_len = __invoke_copy_to_user(__cu_to, __cu_from, \
+ __cu_len); \
__cu_len; \
})
@@ -763,8 +867,14 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
__cu_to = (to); \
__cu_from = (from); \
__cu_len = (n); \
- __cu_len = __invoke_copy_from_user_inatomic(__cu_to, __cu_from, \
- __cu_len); \
+ if (segment_eq(get_fs(), get_ds())) \
+ __cu_len = __invoke_copy_from_kernel_inatomic(__cu_to, \
+ __cu_from,\
+ __cu_len);\
+ else \
+ __cu_len = __invoke_copy_from_user_inatomic(__cu_to, \
+ __cu_from, \
+ __cu_len); \
__cu_len; \
})
@@ -790,14 +900,23 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
__cu_to = (to); \
__cu_from = (from); \
__cu_len = (n); \
- if (access_ok(VERIFY_WRITE, __cu_to, __cu_len)) { \
- might_fault(); \
- __cu_len = __invoke_copy_to_user(__cu_to, __cu_from, \
- __cu_len); \
+ if (segment_eq(get_fs(), get_ds())) { \
+ __cu_len = __invoke_copy_to_kernel(__cu_to, \
+ __cu_from, \
+ __cu_len); \
+ } else { \
+ if (access_ok(VERIFY_WRITE, __cu_to, __cu_len)) { \
+ might_fault(); \
+ __cu_len = __invoke_copy_to_user(__cu_to, \
+ __cu_from, \
+ __cu_len); \
+ } \
} \
__cu_len; \
})
+#ifndef CONFIG_EVA
+
#define __invoke_copy_from_user(to, from, n) \
({ \
register void *__cu_to_r __asm__("$4"); \
@@ -821,6 +940,17 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
__cu_len_r; \
})
+#define __invoke_copy_from_kernel(to, from, n) \
+ __invoke_copy_from_user(to, from, n)
+
+/* For userland <-> userland operations */
+#define ___invoke_copy_in_user(to, from, n) \
+ __invoke_copy_from_user(to, from, n)
+
+/* For kernel <-> kernel operations */
+#define ___invoke_copy_in_kernel(to, from, n) \
+ __invoke_copy_from_user(to, from, n)
+
#define __invoke_copy_from_user_inatomic(to, from, n) \
({ \
register void *__cu_to_r __asm__("$4"); \
@@ -844,6 +974,97 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
__cu_len_r; \
})
+#define __invoke_copy_from_kernel_inatomic(to, from, n) \
+ __invoke_copy_from_user_inatomic(to, from, n) \
+
+#else
+
+/* EVA specific functions */
+
+extern size_t __copy_user_inatomic_eva(void *__to, const void *__from,
+ size_t __n);
+extern size_t __copy_from_user_eva(void *__to, const void *__from,
+ size_t __n);
+extern size_t __copy_to_user_eva(void *__to, const void *__from,
+ size_t __n);
+extern size_t __copy_in_user_eva(void *__to, const void *__from, size_t __n);
+
+#define __invoke_copy_from_user_eva_generic(to, from, n, func_ptr) \
+({ \
+ register void *__cu_to_r __asm__("$4"); \
+ register const void __user *__cu_from_r __asm__("$5"); \
+ register long __cu_len_r __asm__("$6"); \
+ \
+ __cu_to_r = (to); \
+ __cu_from_r = (from); \
+ __cu_len_r = (n); \
+ __asm__ __volatile__( \
+ ".set\tnoreorder\n\t" \
+ __MODULE_JAL(func_ptr) \
+ ".set\tnoat\n\t" \
+ __UA_ADDU "\t$1, %1, %2\n\t" \
+ ".set\tat\n\t" \
+ ".set\treorder" \
+ : "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r) \
+ : \
+ : "$8", "$9", "$10", "$11", "$12", "$14", "$15", "$24", "$31", \
+ DADDI_SCRATCH, "memory"); \
+ __cu_len_r; \
+})
+
+#define __invoke_copy_to_user_eva_generic(to, from, n, func_ptr) \
+({ \
+ register void *__cu_to_r __asm__("$4"); \
+ register const void __user *__cu_from_r __asm__("$5"); \
+ register long __cu_len_r __asm__("$6"); \
+ \
+ __cu_to_r = (to); \
+ __cu_from_r = (from); \
+ __cu_len_r = (n); \
+ __asm__ __volatile__( \
+ __MODULE_JAL(func_ptr) \
+ : "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r) \
+ : \
+ : "$8", "$9", "$10", "$11", "$12", "$14", "$15", "$24", "$31", \
+ DADDI_SCRATCH, "memory"); \
+ __cu_len_r; \
+})
+
+/*
+ * Source or destination address is in userland. We need to go through
+ * the TLB
+ */
+#define __invoke_copy_from_user(to, from, n) \
+ __invoke_copy_from_user_eva_generic(to, from, n, __copy_from_user_eva)
+
+#define __invoke_copy_from_user_inatomic(to, from, n) \
+ __invoke_copy_from_user_eva_generic(to, from, n, \
+ __copy_user_inatomic_eva)
+
+#define __invoke_copy_to_user(to, from, n) \
+ __invoke_copy_to_user_eva_generic(to, from, n, __copy_to_user_eva)
+
+#define ___invoke_copy_in_user(to, from, n) \
+ __invoke_copy_from_user_eva_generic(to, from, n, __copy_in_user_eva)
+
+/*
+ * Source or destination address in the kernel. We are not going through
+ * the TLB
+ */
+#define __invoke_copy_from_kernel(to, from, n) \
+ __invoke_copy_from_user_eva_generic(to, from, n, __copy_user)
+
+#define __invoke_copy_from_kernel_inatomic(to, from, n) \
+ __invoke_copy_from_user_eva_generic(to, from, n, __copy_user_inatomic)
+
+#define __invoke_copy_to_kernel(to, from, n) \
+ __invoke_copy_to_user_eva_generic(to, from, n, __copy_user)
+
+#define ___invoke_copy_in_kernel(to, from, n) \
+ __invoke_copy_from_user_eva_generic(to, from, n, __copy_user)
+
+#endif /* CONFIG_EVA */
+
/*
* __copy_from_user: - Copy a block of data from user space, with less checking.
* @to: Destination address, in kernel space.
@@ -901,10 +1122,17 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
__cu_to = (to); \
__cu_from = (from); \
__cu_len = (n); \
- if (access_ok(VERIFY_READ, __cu_from, __cu_len)) { \
- might_fault(); \
- __cu_len = __invoke_copy_from_user(__cu_to, __cu_from, \
- __cu_len); \
+ if (segment_eq(get_fs(), get_ds())) { \
+ __cu_len = __invoke_copy_from_kernel(__cu_to, \
+ __cu_from, \
+ __cu_len); \
+ } else { \
+ if (access_ok(VERIFY_READ, __cu_from, __cu_len)) { \
+ might_fault(); \
+ __cu_len = __invoke_copy_from_user(__cu_to, \
+ __cu_from, \
+ __cu_len); \
+ } \
} \
__cu_len; \
})
@@ -918,9 +1146,14 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
__cu_to = (to); \
__cu_from = (from); \
__cu_len = (n); \
- might_fault(); \
- __cu_len = __invoke_copy_from_user(__cu_to, __cu_from, \
- __cu_len); \
+ if (segment_eq(get_fs(), get_ds())) { \
+ __cu_len = ___invoke_copy_in_kernel(__cu_to, __cu_from, \
+ __cu_len); \
+ } else { \
+ might_fault(); \
+ __cu_len = ___invoke_copy_in_user(__cu_to, __cu_from, \
+ __cu_len); \
+ } \
__cu_len; \
})
@@ -933,11 +1166,17 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
__cu_to = (to); \
__cu_from = (from); \
__cu_len = (n); \
- if (likely(access_ok(VERIFY_READ, __cu_from, __cu_len) && \
- access_ok(VERIFY_WRITE, __cu_to, __cu_len))) { \
- might_fault(); \
- __cu_len = __invoke_copy_from_user(__cu_to, __cu_from, \
- __cu_len); \
+ if (segment_eq(get_fs(), get_ds())) { \
+ __cu_len = ___invoke_copy_in_kernel(__cu_to,__cu_from, \
+ __cu_len); \
+ } else { \
+ if (likely(access_ok(VERIFY_READ, __cu_from, __cu_len) &&\
+ access_ok(VERIFY_WRITE, __cu_to, __cu_len))) {\
+ might_fault(); \
+ __cu_len = ___invoke_copy_in_user(__cu_to, \
+ __cu_from, \
+ __cu_len); \
+ } \
} \
__cu_len; \
})
@@ -1007,16 +1246,28 @@ __strncpy_from_user(char *__to, const char __user *__from, long __len)
{
long res;
- might_fault();
- __asm__ __volatile__(
- "move\t$4, %1\n\t"
- "move\t$5, %2\n\t"
- "move\t$6, %3\n\t"
- __MODULE_JAL(__strncpy_from_user_nocheck_asm)
- "move\t%0, $2"
- : "=r" (res)
- : "r" (__to), "r" (__from), "r" (__len)
- : "$2", "$3", "$4", "$5", "$6", __UA_t0, "$31", "memory");
+ if (segment_eq(get_fs(), get_ds())) {
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, %2\n\t"
+ "move\t$6, %3\n\t"
+ __MODULE_JAL(__strncpy_from_kernel_nocheck_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (__to), "r" (__from), "r" (__len)
+ : "$2", "$3", "$4", "$5", "$6", __UA_t0, "$31", "memory");
+ } else {
+ might_fault();
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, %2\n\t"
+ "move\t$6, %3\n\t"
+ __MODULE_JAL(__strncpy_from_user_nocheck_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (__to), "r" (__from), "r" (__len)
+ : "$2", "$3", "$4", "$5", "$6", __UA_t0, "$31", "memory");
+ }
return res;
}
@@ -1044,16 +1295,28 @@ strncpy_from_user(char *__to, const char __user *__from, long __len)
{
long res;
- might_fault();
- __asm__ __volatile__(
- "move\t$4, %1\n\t"
- "move\t$5, %2\n\t"
- "move\t$6, %3\n\t"
- __MODULE_JAL(__strncpy_from_user_asm)
- "move\t%0, $2"
- : "=r" (res)
- : "r" (__to), "r" (__from), "r" (__len)
- : "$2", "$3", "$4", "$5", "$6", __UA_t0, "$31", "memory");
+ if (segment_eq(get_fs(), get_ds())) {
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, %2\n\t"
+ "move\t$6, %3\n\t"
+ __MODULE_JAL(__strncpy_from_kernel_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (__to), "r" (__from), "r" (__len)
+ : "$2", "$3", "$4", "$5", "$6", __UA_t0, "$31", "memory");
+ } else {
+ might_fault();
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, %2\n\t"
+ "move\t$6, %3\n\t"
+ __MODULE_JAL(__strncpy_from_user_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (__to), "r" (__from), "r" (__len)
+ : "$2", "$3", "$4", "$5", "$6", __UA_t0, "$31", "memory");
+ }
return res;
}
@@ -1063,14 +1326,24 @@ static inline long __strlen_user(const char __user *s)
{
long res;
- might_fault();
- __asm__ __volatile__(
- "move\t$4, %1\n\t"
- __MODULE_JAL(__strlen_user_nocheck_asm)
- "move\t%0, $2"
- : "=r" (res)
- : "r" (s)
- : "$2", "$4", __UA_t0, "$31");
+ if (segment_eq(get_fs(), get_ds())) {
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ __MODULE_JAL(__strlen_kernel_nocheck_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (s)
+ : "$2", "$4", __UA_t0, "$31");
+ } else {
+ might_fault();
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ __MODULE_JAL(__strlen_user_nocheck_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (s)
+ : "$2", "$4", __UA_t0, "$31");
+ }
return res;
}
@@ -1093,14 +1366,24 @@ static inline long strlen_user(const char __user *s)
{
long res;
- might_fault();
- __asm__ __volatile__(
- "move\t$4, %1\n\t"
- __MODULE_JAL(__strlen_user_asm)
- "move\t%0, $2"
- : "=r" (res)
- : "r" (s)
- : "$2", "$4", __UA_t0, "$31");
+ if (segment_eq(get_fs(), get_ds())) {
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ __MODULE_JAL(__strlen_kernel_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (s)
+ : "$2", "$4", __UA_t0, "$31");
+ } else {
+ might_fault();
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ __MODULE_JAL(__strlen_kernel_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (s)
+ : "$2", "$4", __UA_t0, "$31");
+ }
return res;
}
@@ -1110,15 +1393,26 @@ static inline long __strnlen_user(const char __user *s, long n)
{
long res;
- might_fault();
- __asm__ __volatile__(
- "move\t$4, %1\n\t"
- "move\t$5, %2\n\t"
- __MODULE_JAL(__strnlen_user_nocheck_asm)
- "move\t%0, $2"
- : "=r" (res)
- : "r" (s), "r" (n)
- : "$2", "$4", "$5", __UA_t0, "$31");
+ if (segment_eq(get_fs(), get_ds())) {
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, %2\n\t"
+ __MODULE_JAL(__strnlen_kernel_nocheck_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (s), "r" (n)
+ : "$2", "$4", "$5", __UA_t0, "$31");
+ } else {
+ might_fault();
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, %2\n\t"
+ __MODULE_JAL(__strnlen_user_nocheck_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (s), "r" (n)
+ : "$2", "$4", "$5", __UA_t0, "$31");
+ }
return res;
}
@@ -1142,14 +1436,25 @@ static inline long strnlen_user(const char __user *s, long n)
long res;
might_fault();
- __asm__ __volatile__(
- "move\t$4, %1\n\t"
- "move\t$5, %2\n\t"
- __MODULE_JAL(__strnlen_user_asm)
- "move\t%0, $2"
- : "=r" (res)
- : "r" (s), "r" (n)
- : "$2", "$4", "$5", __UA_t0, "$31");
+ if (segment_eq(get_fs(), get_ds())) {
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, %2\n\t"
+ __MODULE_JAL(__strnlen_kernel_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (s), "r" (n)
+ : "$2", "$4", "$5", __UA_t0, "$31");
+ } else {
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, %2\n\t"
+ __MODULE_JAL(__strnlen_user_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (s), "r" (n)
+ : "$2", "$4", "$5", __UA_t0, "$31");
+ }
return res;
}
diff --git a/arch/mips/include/asm/unistd.h b/arch/mips/include/asm/unistd.h
index 4d3b92886665..413d6c612bec 100644
--- a/arch/mips/include/asm/unistd.h
+++ b/arch/mips/include/asm/unistd.h
@@ -24,7 +24,6 @@
#ifndef __ASSEMBLY__
-#define __ARCH_OMIT_COMPAT_SYS_GETDENTS64
#define __ARCH_WANT_OLD_READDIR
#define __ARCH_WANT_SYS_ALARM
#define __ARCH_WANT_SYS_GETHOSTNAME
diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h
index b39ba25b41cc..df6e775f3fef 100644
--- a/arch/mips/include/uapi/asm/inst.h
+++ b/arch/mips/include/uapi/asm/inst.h
@@ -8,6 +8,7 @@
* Copyright (C) 1996, 2000 by Ralf Baechle
* Copyright (C) 2006 by Thiemo Seufer
* Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
+ * Copyright (C) 2014 Imagination Technologies Ltd.
*/
#ifndef _UAPI_ASM_INST_H
#define _UAPI_ASM_INST_H
@@ -73,10 +74,16 @@ enum spec2_op {
enum spec3_op {
ext_op, dextm_op, dextu_op, dext_op,
ins_op, dinsm_op, dinsu_op, dins_op,
- lx_op = 0x0a,
- bshfl_op = 0x20,
- dbshfl_op = 0x24,
- rdhwr_op = 0x3b
+ lx_op = 0x0a, lwle_op = 0x19,
+ lwre_op = 0x1a, cachee_op = 0x1b,
+ sbe_op = 0x1c, she_op = 0x1d,
+ sce_op = 0x1e, swe_op = 0x1f,
+ bshfl_op = 0x20, swle_op = 0x21,
+ swre_op = 0x22, prefe_op = 0x23,
+ dbshfl_op = 0x24, lbue_op = 0x28,
+ lhue_op = 0x29, lbe_op = 0x2c,
+ lhe_op = 0x2d, lle_op = 0x2e,
+ lwe_op = 0x2f, rdhwr_op = 0x3b
};
/*
@@ -163,8 +170,8 @@ enum cop1_sdw_func {
*/
enum cop1x_func {
lwxc1_op = 0x00, ldxc1_op = 0x01,
- pfetch_op = 0x07, swxc1_op = 0x08,
- sdxc1_op = 0x09, madd_s_op = 0x20,
+ swxc1_op = 0x08, sdxc1_op = 0x09,
+ pfetch_op = 0x0f, madd_s_op = 0x20,
madd_d_op = 0x21, madd_e_op = 0x22,
msub_s_op = 0x28, msub_d_op = 0x29,
msub_e_op = 0x2a, nmadd_s_op = 0x30,
@@ -592,6 +599,15 @@ struct v_format { /* MDMX vector format */
;)))))))
};
+struct spec3_format { /* SPEC3 */
+ BITFIELD_FIELD(unsigned int opcode:6,
+ BITFIELD_FIELD(unsigned int rs:5,
+ BITFIELD_FIELD(unsigned int rt:5,
+ BITFIELD_FIELD(signed int simmediate:9,
+ BITFIELD_FIELD(unsigned int func:7,
+ ;)))))
+};
+
/*
* microMIPS instruction formats (32-bit length)
*
@@ -863,6 +879,7 @@ union mips_instruction {
struct b_format b_format;
struct ps_format ps_format;
struct v_format v_format;
+ struct spec3_format spec3_format;
struct fb_format fb_format;
struct fp0_format fp0_format;
struct mm_fp0_format mm_fp0_format;
diff --git a/arch/mips/include/uapi/asm/sigcontext.h b/arch/mips/include/uapi/asm/sigcontext.h
index 6c9906f59c6e..681c17603a48 100644
--- a/arch/mips/include/uapi/asm/sigcontext.h
+++ b/arch/mips/include/uapi/asm/sigcontext.h
@@ -12,6 +12,10 @@
#include <linux/types.h>
#include <asm/sgidefs.h>
+/* Bits which may be set in sc_used_math */
+#define USEDMATH_FP (1 << 0)
+#define USEDMATH_MSA (1 << 1)
+
#if _MIPS_SIM == _MIPS_SIM_ABI32
/*
@@ -37,6 +41,8 @@ struct sigcontext {
unsigned long sc_lo2;
unsigned long sc_hi3;
unsigned long sc_lo3;
+ unsigned long long sc_msaregs[32]; /* Most significant 64 bits */
+ unsigned long sc_msa_csr;
};
#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
@@ -70,6 +76,8 @@ struct sigcontext {
__u32 sc_used_math;
__u32 sc_dsp;
__u32 sc_reserved;
+ __u64 sc_msaregs[32];
+ __u32 sc_msa_csr;
};
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 26c6175e1379..277dab301cea 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -53,6 +53,8 @@ obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o
obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o
obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o
obj-$(CONFIG_MIPS_CMP) += smp-cmp.o
+obj-$(CONFIG_MIPS_CPS) += smp-cps.o cps-vec.o
+obj-$(CONFIG_MIPS_GIC_IPI) += smp-gic.o
obj-$(CONFIG_CPU_MIPSR2) += spram.o
obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o
@@ -102,6 +104,9 @@ obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_mipsxx.o
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
+obj-$(CONFIG_MIPS_CM) += mips-cm.o
+obj-$(CONFIG_MIPS_CPC) += mips-cpc.o
+
#
# DSP ASE supported for MIPS32 or MIPS64 Release 2 cores only. It is not
# safe to unconditionnaly use the assembler -mdsp / -mdspr2 switches
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index 0c2e853c3db4..0ea75c244b48 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -16,6 +16,7 @@
#include <linux/suspend.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
+#include <asm/smp-cps.h>
#include <linux/kvm_host.h>
@@ -168,6 +169,72 @@ void output_thread_fpu_defines(void)
OFFSET(THREAD_FPR30, task_struct, thread.fpu.fpr[30]);
OFFSET(THREAD_FPR31, task_struct, thread.fpu.fpr[31]);
+ /* the least significant 64 bits of each FP register */
+ OFFSET(THREAD_FPR0_LS64, task_struct,
+ thread.fpu.fpr[0].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR1_LS64, task_struct,
+ thread.fpu.fpr[1].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR2_LS64, task_struct,
+ thread.fpu.fpr[2].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR3_LS64, task_struct,
+ thread.fpu.fpr[3].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR4_LS64, task_struct,
+ thread.fpu.fpr[4].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR5_LS64, task_struct,
+ thread.fpu.fpr[5].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR6_LS64, task_struct,
+ thread.fpu.fpr[6].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR7_LS64, task_struct,
+ thread.fpu.fpr[7].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR8_LS64, task_struct,
+ thread.fpu.fpr[8].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR9_LS64, task_struct,
+ thread.fpu.fpr[9].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR10_LS64, task_struct,
+ thread.fpu.fpr[10].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR11_LS64, task_struct,
+ thread.fpu.fpr[11].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR12_LS64, task_struct,
+ thread.fpu.fpr[12].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR13_LS64, task_struct,
+ thread.fpu.fpr[13].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR14_LS64, task_struct,
+ thread.fpu.fpr[14].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR15_LS64, task_struct,
+ thread.fpu.fpr[15].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR16_LS64, task_struct,
+ thread.fpu.fpr[16].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR17_LS64, task_struct,
+ thread.fpu.fpr[17].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR18_LS64, task_struct,
+ thread.fpu.fpr[18].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR19_LS64, task_struct,
+ thread.fpu.fpr[19].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR20_LS64, task_struct,
+ thread.fpu.fpr[20].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR21_LS64, task_struct,
+ thread.fpu.fpr[21].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR22_LS64, task_struct,
+ thread.fpu.fpr[22].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR23_LS64, task_struct,
+ thread.fpu.fpr[23].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR24_LS64, task_struct,
+ thread.fpu.fpr[24].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR25_LS64, task_struct,
+ thread.fpu.fpr[25].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR26_LS64, task_struct,
+ thread.fpu.fpr[26].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR27_LS64, task_struct,
+ thread.fpu.fpr[27].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR28_LS64, task_struct,
+ thread.fpu.fpr[28].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR29_LS64, task_struct,
+ thread.fpu.fpr[29].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR30_LS64, task_struct,
+ thread.fpu.fpr[30].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR31_LS64, task_struct,
+ thread.fpu.fpr[31].val64[FPR_IDX(64, 0)]);
+
OFFSET(THREAD_FCR31, task_struct, thread.fpu.fcr31);
BLANK();
}
@@ -228,6 +295,7 @@ void output_sc_defines(void)
OFFSET(SC_LO2, sigcontext, sc_lo2);
OFFSET(SC_HI3, sigcontext, sc_hi3);
OFFSET(SC_LO3, sigcontext, sc_lo3);
+ OFFSET(SC_MSAREGS, sigcontext, sc_msaregs);
BLANK();
}
#endif
@@ -242,6 +310,7 @@ void output_sc_defines(void)
OFFSET(SC_MDLO, sigcontext, sc_mdlo);
OFFSET(SC_PC, sigcontext, sc_pc);
OFFSET(SC_FPC_CSR, sigcontext, sc_fpc_csr);
+ OFFSET(SC_MSAREGS, sigcontext, sc_msaregs);
BLANK();
}
#endif
@@ -253,6 +322,7 @@ void output_sc32_defines(void)
OFFSET(SC32_FPREGS, sigcontext32, sc_fpregs);
OFFSET(SC32_FPC_CSR, sigcontext32, sc_fpc_csr);
OFFSET(SC32_FPC_EIR, sigcontext32, sc_fpc_eir);
+ OFFSET(SC32_MSAREGS, sigcontext32, sc_msaregs);
BLANK();
}
#endif
@@ -397,3 +467,15 @@ void output_kvm_defines(void)
OFFSET(COP0_STATUS, mips_coproc, reg[MIPS_CP0_STATUS][0]);
BLANK();
}
+
+#ifdef CONFIG_MIPS_CPS
+void output_cps_defines(void)
+{
+ COMMENT(" MIPS CPS offsets. ");
+ OFFSET(BOOTCFG_CORE, boot_config, core);
+ OFFSET(BOOTCFG_VPE, boot_config, vpe);
+ OFFSET(BOOTCFG_PC, boot_config, pc);
+ OFFSET(BOOTCFG_SP, boot_config, sp);
+ OFFSET(BOOTCFG_GP, boot_config, gp);
+}
+#endif
diff --git a/arch/mips/kernel/bmips_vec.S b/arch/mips/kernel/bmips_vec.S
index a5bf73d22fcc..290c23b51678 100644
--- a/arch/mips/kernel/bmips_vec.S
+++ b/arch/mips/kernel/bmips_vec.S
@@ -122,7 +122,7 @@ NESTED(bmips_reset_nmi_vec, PT_SIZE, sp)
jr k0
RESTORE_ALL
- .set mips3
+ .set arch=r4000
eret
/***********************************************************************
diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S
new file mode 100644
index 000000000000..f7a46db4b161
--- /dev/null
+++ b/arch/mips/kernel/cps-vec.S
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.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 <asm/addrspace.h>
+#include <asm/asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/asmmacro.h>
+#include <asm/cacheops.h>
+#include <asm/mipsregs.h>
+
+#define GCR_CL_COHERENCE_OFS 0x2008
+
+.section .text.cps-vec
+.balign 0x1000
+.set noreorder
+
+LEAF(mips_cps_core_entry)
+ /*
+ * These first 8 bytes will be patched by cps_smp_setup to load the
+ * base address of the CM GCRs into register v1.
+ */
+ .quad 0
+
+ /* Check whether we're here due to an NMI */
+ mfc0 k0, CP0_STATUS
+ and k0, k0, ST0_NMI
+ beqz k0, not_nmi
+ nop
+
+ /* This is an NMI */
+ la k0, nmi_handler
+ jr k0
+ nop
+
+not_nmi:
+ /* Setup Cause */
+ li t0, CAUSEF_IV
+ mtc0 t0, CP0_CAUSE
+
+ /* Setup Status */
+ li t0, ST0_CU1 | ST0_CU0
+ mtc0 t0, CP0_STATUS
+
+ /*
+ * Clear the bits used to index the caches. Note that the architecture
+ * dictates that writing to any of TagLo or TagHi selects 0 or 2 should
+ * be valid for all MIPS32 CPUs, even those for which said writes are
+ * unnecessary.
+ */
+ mtc0 zero, CP0_TAGLO, 0
+ mtc0 zero, CP0_TAGHI, 0
+ mtc0 zero, CP0_TAGLO, 2
+ mtc0 zero, CP0_TAGHI, 2
+ ehb
+
+ /* Primary cache configuration is indicated by Config1 */
+ mfc0 v0, CP0_CONFIG, 1
+
+ /* Detect I-cache line size */
+ _EXT t0, v0, MIPS_CONF1_IL_SHF, MIPS_CONF1_IL_SZ
+ beqz t0, icache_done
+ li t1, 2
+ sllv t0, t1, t0
+
+ /* Detect I-cache size */
+ _EXT t1, v0, MIPS_CONF1_IS_SHF, MIPS_CONF1_IS_SZ
+ xori t2, t1, 0x7
+ beqz t2, 1f
+ li t3, 32
+ addi t1, t1, 1
+ sllv t1, t3, t1
+1: /* At this point t1 == I-cache sets per way */
+ _EXT t2, v0, MIPS_CONF1_IA_SHF, MIPS_CONF1_IA_SZ
+ addi t2, t2, 1
+ mul t1, t1, t0
+ mul t1, t1, t2
+
+ li a0, KSEG0
+ add a1, a0, t1
+1: cache Index_Store_Tag_I, 0(a0)
+ add a0, a0, t0
+ bne a0, a1, 1b
+ nop
+icache_done:
+
+ /* Detect D-cache line size */
+ _EXT t0, v0, MIPS_CONF1_DL_SHF, MIPS_CONF1_DL_SZ
+ beqz t0, dcache_done
+ li t1, 2
+ sllv t0, t1, t0
+
+ /* Detect D-cache size */
+ _EXT t1, v0, MIPS_CONF1_DS_SHF, MIPS_CONF1_DS_SZ
+ xori t2, t1, 0x7
+ beqz t2, 1f
+ li t3, 32
+ addi t1, t1, 1
+ sllv t1, t3, t1
+1: /* At this point t1 == D-cache sets per way */
+ _EXT t2, v0, MIPS_CONF1_DA_SHF, MIPS_CONF1_DA_SZ
+ addi t2, t2, 1
+ mul t1, t1, t0
+ mul t1, t1, t2
+
+ li a0, KSEG0
+ addu a1, a0, t1
+ subu a1, a1, t0
+1: cache Index_Store_Tag_D, 0(a0)
+ bne a0, a1, 1b
+ add a0, a0, t0
+dcache_done:
+
+ /* Set Kseg0 cacheable, coherent, write-back, write-allocate */
+ mfc0 t0, CP0_CONFIG
+ ori t0, 0x7
+ xori t0, 0x2
+ mtc0 t0, CP0_CONFIG
+ ehb
+
+ /* Enter the coherent domain */
+ li t0, 0xff
+ sw t0, GCR_CL_COHERENCE_OFS(v1)
+ ehb
+
+ /* Jump to kseg0 */
+ la t0, 1f
+ jr t0
+ nop
+
+1: /* We're up, cached & coherent */
+
+ /*
+ * TODO: We should check the VPE number we intended to boot here, and
+ * if non-zero we should start that VPE and stop this one. For
+ * the moment this doesn't matter since CPUs are brought up
+ * sequentially and in order, but once hotplug is implemented
+ * this will need revisiting.
+ */
+
+ /* Off we go! */
+ la t0, mips_cps_bootcfg
+ lw t1, BOOTCFG_PC(t0)
+ lw gp, BOOTCFG_GP(t0)
+ lw sp, BOOTCFG_SP(t0)
+ jr t1
+ nop
+ END(mips_cps_core_entry)
+
+.org 0x200
+LEAF(excep_tlbfill)
+ b .
+ nop
+ END(excep_tlbfill)
+
+.org 0x280
+LEAF(excep_xtlbfill)
+ b .
+ nop
+ END(excep_xtlbfill)
+
+.org 0x300
+LEAF(excep_cache)
+ b .
+ nop
+ END(excep_cache)
+
+.org 0x380
+LEAF(excep_genex)
+ b .
+ nop
+ END(excep_genex)
+
+.org 0x400
+LEAF(excep_intex)
+ b .
+ nop
+ END(excep_intex)
+
+.org 0x480
+LEAF(excep_ejtag)
+ la k0, ejtag_debug_handler
+ jr k0
+ nop
+ END(excep_ejtag)
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 530f832de02c..6e8fb85ce7c3 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -23,6 +23,8 @@
#include <asm/cpu-type.h>
#include <asm/fpu.h>
#include <asm/mipsregs.h>
+#include <asm/mipsmtregs.h>
+#include <asm/msa.h>
#include <asm/watch.h>
#include <asm/elf.h>
#include <asm/spram.h>
@@ -126,6 +128,20 @@ static inline int __cpu_has_fpu(void)
return ((cpu_get_fpu_id() & FPIR_IMP_MASK) != FPIR_IMP_NONE);
}
+static inline unsigned long cpu_get_msa_id(void)
+{
+ unsigned long status, conf5, msa_id;
+
+ status = read_c0_status();
+ __enable_fpu(FPU_64BIT);
+ conf5 = read_c0_config5();
+ enable_msa();
+ msa_id = read_msa_ir();
+ write_c0_config5(conf5);
+ write_c0_status(status);
+ return msa_id;
+}
+
static inline void cpu_probe_vmbits(struct cpuinfo_mips *c)
{
#ifdef __NEED_VMBITS_PROBE
@@ -166,11 +182,12 @@ static char unknown_isa[] = KERN_ERR \
static void set_ftlb_enable(struct cpuinfo_mips *c, int enable)
{
unsigned int config6;
- /*
- * Config6 is implementation dependent and it's currently only
- * used by proAptiv
- */
- if (c->cputype == CPU_PROAPTIV) {
+
+ /* It's implementation dependent how the FTLB can be enabled */
+ switch (c->cputype) {
+ case CPU_PROAPTIV:
+ case CPU_P5600:
+ /* proAptiv & related cores use Config6 to enable the FTLB */
config6 = read_c0_config6();
if (enable)
/* Enable FTLB */
@@ -179,6 +196,7 @@ static void set_ftlb_enable(struct cpuinfo_mips *c, int enable)
/* Disable FTLB */
write_c0_config6(config6 & ~MIPS_CONF6_FTLBEN);
back_to_back_c0_hazard();
+ break;
}
}
@@ -301,6 +319,8 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)
c->ases |= MIPS_ASE_VZ;
if (config3 & MIPS_CONF3_SC)
c->options |= MIPS_CPU_SEGMENTS;
+ if (config3 & MIPS_CONF3_MSA)
+ c->ases |= MIPS_ASE_MSA;
return config3 & MIPS_CONF_M;
}
@@ -367,6 +387,9 @@ static inline unsigned int decode_config5(struct cpuinfo_mips *c)
config5 &= ~MIPS_CONF5_UFR;
write_c0_config5(config5);
+ if (config5 & MIPS_CONF5_EVA)
+ c->options |= MIPS_CPU_EVA;
+
return config5 & MIPS_CONF_M;
}
@@ -398,8 +421,13 @@ static void decode_configs(struct cpuinfo_mips *c)
mips_probe_watch_registers(c);
- if (cpu_has_mips_r2)
+#ifndef CONFIG_MIPS_CPS
+ if (cpu_has_mips_r2) {
c->core = read_c0_ebase() & 0x3ff;
+ if (cpu_has_mipsmt)
+ c->core >>= fls(core_nvpes()) - 1;
+ }
+#endif
}
#define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE \
@@ -710,17 +738,23 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
MIPS_CPU_LLSC;
c->tlbsize = 64;
break;
- case PRID_IMP_LOONGSON2:
- c->cputype = CPU_LOONGSON2;
- __cpu_name[cpu] = "ICT Loongson-2";
-
+ case PRID_IMP_LOONGSON_64: /* Loongson-2/3 */
switch (c->processor_id & PRID_REV_MASK) {
case PRID_REV_LOONGSON2E:
+ c->cputype = CPU_LOONGSON2;
+ __cpu_name[cpu] = "ICT Loongson-2";
set_elf_platform(cpu, "loongson2e");
break;
case PRID_REV_LOONGSON2F:
+ c->cputype = CPU_LOONGSON2;
+ __cpu_name[cpu] = "ICT Loongson-2";
set_elf_platform(cpu, "loongson2f");
break;
+ case PRID_REV_LOONGSON3A:
+ c->cputype = CPU_LOONGSON3;
+ __cpu_name[cpu] = "ICT Loongson-3";
+ set_elf_platform(cpu, "loongson3a");
+ break;
}
set_isa(c, MIPS_CPU_ISA_III);
@@ -729,7 +763,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
MIPS_CPU_32FPR;
c->tlbsize = 64;
break;
- case PRID_IMP_LOONGSON1:
+ case PRID_IMP_LOONGSON_32: /* Loongson-1 */
decode_configs(c);
c->cputype = CPU_LOONGSON1;
@@ -806,7 +840,7 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
__cpu_name[cpu] = "MIPS 1004Kc";
break;
case PRID_IMP_1074K:
- c->cputype = CPU_74K;
+ c->cputype = CPU_1074K;
__cpu_name[cpu] = "MIPS 1074Kc";
break;
case PRID_IMP_INTERAPTIV_UP:
@@ -825,6 +859,14 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
c->cputype = CPU_PROAPTIV;
__cpu_name[cpu] = "MIPS proAptiv (multi)";
break;
+ case PRID_IMP_P5600:
+ c->cputype = CPU_P5600;
+ __cpu_name[cpu] = "MIPS P5600";
+ break;
+ case PRID_IMP_M5150:
+ c->cputype = CPU_M5150;
+ __cpu_name[cpu] = "MIPS M5150";
+ break;
}
decode_configs(c);
@@ -1176,6 +1218,12 @@ void cpu_probe(void)
else
c->srsets = 1;
+ if (cpu_has_msa) {
+ c->msa_id = cpu_get_msa_id();
+ WARN(c->msa_id & MSA_IR_WRPF,
+ "Vector register partitioning unimplemented!");
+ }
+
cpu_probe_vmbits(c);
#ifdef CONFIG_64BIT
@@ -1192,4 +1240,6 @@ void cpu_report(void)
smp_processor_id(), c->processor_id, cpu_name_string());
if (c->options & MIPS_CPU_FPU)
printk(KERN_INFO "FPU revision is: %08x\n", c->fpu_id);
+ if (cpu_has_msa)
+ pr_info("MSA revision is: %08x\n", c->msa_id);
}
diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c
index 185ba258361b..60e7e5e45af1 100644
--- a/arch/mips/kernel/ftrace.c
+++ b/arch/mips/kernel/ftrace.c
@@ -90,6 +90,7 @@ static inline void ftrace_dyn_arch_init_insns(void)
static int ftrace_modify_code(unsigned long ip, unsigned int new_code)
{
int faulted;
+ mm_segment_t old_fs;
/* *(unsigned int *)ip = new_code; */
safe_store_code(new_code, ip, faulted);
@@ -97,7 +98,10 @@ static int ftrace_modify_code(unsigned long ip, unsigned int new_code)
if (unlikely(faulted))
return -EFAULT;
+ old_fs = get_fs();
+ set_fs(get_ds());
flush_icache_range(ip, ip + 8);
+ set_fs(old_fs);
return 0;
}
@@ -111,11 +115,10 @@ static int ftrace_modify_code_2(unsigned long ip, unsigned int new_code1,
safe_store_code(new_code1, ip, faulted);
if (unlikely(faulted))
return -EFAULT;
- ip += 4;
- safe_store_code(new_code2, ip, faulted);
+ safe_store_code(new_code2, ip + 4, faulted);
if (unlikely(faulted))
return -EFAULT;
- flush_icache_range(ip, ip + 8); /* original ip + 12 */
+ flush_icache_range(ip, ip + 8);
return 0;
}
#endif
@@ -198,7 +201,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
return ftrace_modify_code(FTRACE_CALL_IP, new);
}
-int __init ftrace_dyn_arch_init(void *data)
+int __init ftrace_dyn_arch_init(void)
{
/* Encode the instructions when booting */
ftrace_dyn_arch_init_insns();
@@ -206,9 +209,6 @@ int __init ftrace_dyn_arch_init(void *data)
/* Remove "b ftrace_stub" to ensure ftrace_caller() is executed */
ftrace_modify_code(MCOUNT_ADDR, INSN_NOP);
- /* The return code is retured via data */
- *(unsigned long *)data = 0;
-
return 0;
}
#endif /* CONFIG_DYNAMIC_FTRACE */
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
index d84f6a509502..a9ce3408be25 100644
--- a/arch/mips/kernel/genex.S
+++ b/arch/mips/kernel/genex.S
@@ -67,7 +67,7 @@ NESTED(except_vec3_generic, 0, sp)
*/
NESTED(except_vec3_r4000, 0, sp)
.set push
- .set mips3
+ .set arch=r4000
.set noat
mfc0 k1, CP0_CAUSE
li k0, 31<<2
@@ -139,7 +139,7 @@ LEAF(__r4k_wait)
nop
nop
#endif
- .set mips3
+ .set arch=r4000
wait
/* end of rollback region (the region size must be power of two) */
1:
@@ -475,8 +475,10 @@ NESTED(nmi_handler, PT_SIZE, sp)
BUILD_HANDLER cpu cpu sti silent /* #11 */
BUILD_HANDLER ov ov sti silent /* #12 */
BUILD_HANDLER tr tr sti silent /* #13 */
+ BUILD_HANDLER msa_fpe msa_fpe sti silent /* #14 */
BUILD_HANDLER fpe fpe fpe silent /* #15 */
BUILD_HANDLER ftlb ftlb none silent /* #16 */
+ BUILD_HANDLER msa msa sti silent /* #21 */
BUILD_HANDLER mdmx mdmx sti silent /* #22 */
#ifdef CONFIG_HARDWARE_WATCHPOINTS
/*
@@ -575,7 +577,7 @@ isrdhwr:
ori k1, _THREAD_MASK
xori k1, _THREAD_MASK
LONG_L v1, TI_TP_VALUE(k1)
- .set mips3
+ .set arch=r4000
eret
.set mips0
#endif
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
index 7b6a5b3e3acf..e712dcf18b2d 100644
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -175,8 +175,8 @@ NESTED(smp_bootstrap, 16, sp)
DMT 10 # dmt t2 /* t0, t1 are used by CLI and setup_c0_status() */
jal mips_ihb
#endif /* CONFIG_MIPS_MT_SMTC */
- setup_c0_status_sec
smp_slave_setup
+ setup_c0_status_sec
#ifdef CONFIG_MIPS_MT_SMTC
andi t2, t2, VPECONTROL_TE
beqz t2, 2f
diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c
index 3553243bf9d6..837ff27950bc 100644
--- a/arch/mips/kernel/idle.c
+++ b/arch/mips/kernel/idle.c
@@ -64,7 +64,7 @@ void r4k_wait_irqoff(void)
if (!need_resched())
__asm__(
" .set push \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" wait \n"
" .set pop \n");
local_irq_enable();
@@ -82,7 +82,7 @@ static void rm7k_wait_irqoff(void)
if (!need_resched())
__asm__(
" .set push \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" .set noat \n"
" mfc0 $1, $12 \n"
" sync \n"
@@ -103,7 +103,7 @@ static void au1k_wait(void)
unsigned long c0status = read_c0_status() | 1; /* irqs on */
__asm__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" cache 0x14, 0(%0) \n"
" cache 0x14, 32(%0) \n"
" sync \n"
@@ -184,8 +184,11 @@ void __init check_wait(void)
case CPU_24K:
case CPU_34K:
case CPU_1004K:
+ case CPU_1074K:
case CPU_INTERAPTIV:
case CPU_PROAPTIV:
+ case CPU_P5600:
+ case CPU_M5150:
cpu_wait = r4k_wait;
if (read_c0_config7() & MIPS_CONF7_WII)
cpu_wait = r4k_wait_irqoff;
diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c
index 5b5ddb231f26..8520dad6d4e3 100644
--- a/arch/mips/kernel/irq-gic.c
+++ b/arch/mips/kernel/irq-gic.c
@@ -16,7 +16,6 @@
#include <asm/gic.h>
#include <asm/setup.h>
#include <asm/traps.h>
-#include <asm/gcmpregs.h>
#include <linux/hardirq.h>
#include <asm-generic/bitops/find.h>
diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c
index fcaac2f132f0..7afcc2f22c0d 100644
--- a/arch/mips/kernel/kgdb.c
+++ b/arch/mips/kernel/kgdb.c
@@ -32,6 +32,7 @@
#include <asm/cacheflush.h>
#include <asm/processor.h>
#include <asm/sigcontext.h>
+#include <asm/uaccess.h>
static struct hard_trap_info {
unsigned char tt; /* Trap type code for MIPS R3xxx and R4xxx */
@@ -208,7 +209,14 @@ void arch_kgdb_breakpoint(void)
static void kgdb_call_nmi_hook(void *ignored)
{
+ mm_segment_t old_fs;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+
kgdb_nmicallback(raw_smp_processor_id(), NULL);
+
+ set_fs(old_fs);
}
void kgdb_roundup_cpus(unsigned long flags)
@@ -282,6 +290,7 @@ static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd,
struct die_args *args = (struct die_args *)ptr;
struct pt_regs *regs = args->regs;
int trap = (regs->cp0_cause & 0x7c) >> 2;
+ mm_segment_t old_fs;
#ifdef CONFIG_KPROBES
/*
@@ -296,11 +305,17 @@ static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd,
if (user_mode(regs))
return NOTIFY_DONE;
+ /* Kernel mode. Set correct address limit */
+ old_fs = get_fs();
+ set_fs(get_ds());
+
if (atomic_read(&kgdb_active) != -1)
kgdb_nmicallback(smp_processor_id(), regs);
- if (kgdb_handle_exception(trap, compute_signal(trap), cmd, regs))
+ if (kgdb_handle_exception(trap, compute_signal(trap), cmd, regs)) {
+ set_fs(old_fs);
return NOTIFY_DONE;
+ }
if (atomic_read(&kgdb_setting_breakpoint))
if ((trap == 9) && (regs->cp0_epc == (unsigned long)breakinst))
@@ -310,6 +325,7 @@ static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd,
local_irq_enable();
__flush_cache_all();
+ set_fs(old_fs);
return NOTIFY_STOP;
}
diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c
new file mode 100644
index 000000000000..f76f7a08412d
--- /dev/null
+++ b/arch/mips/kernel/mips-cm.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.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/errno.h>
+
+#include <asm/mips-cm.h>
+#include <asm/mipsregs.h>
+
+void __iomem *mips_cm_base;
+void __iomem *mips_cm_l2sync_base;
+
+phys_t __mips_cm_phys_base(void)
+{
+ u32 config3 = read_c0_config3();
+ u32 cmgcr;
+
+ /* Check the CMGCRBase register is implemented */
+ if (!(config3 & MIPS_CONF3_CMGCR))
+ return 0;
+
+ /* Read the address from CMGCRBase */
+ cmgcr = read_c0_cmgcrbase();
+ return (cmgcr & MIPS_CMGCRF_BASE) << (36 - 32);
+}
+
+phys_t mips_cm_phys_base(void)
+ __attribute__((weak, alias("__mips_cm_phys_base")));
+
+phys_t __mips_cm_l2sync_phys_base(void)
+{
+ u32 base_reg;
+
+ /*
+ * If the L2-only sync region is already enabled then leave it at it's
+ * current location.
+ */
+ base_reg = read_gcr_l2_only_sync_base();
+ if (base_reg & CM_GCR_L2_ONLY_SYNC_BASE_SYNCEN_MSK)
+ return base_reg & CM_GCR_L2_ONLY_SYNC_BASE_SYNCBASE_MSK;
+
+ /* Default to following the CM */
+ return mips_cm_phys_base() + MIPS_CM_GCR_SIZE;
+}
+
+phys_t mips_cm_l2sync_phys_base(void)
+ __attribute__((weak, alias("__mips_cm_l2sync_phys_base")));
+
+static void mips_cm_probe_l2sync(void)
+{
+ unsigned major_rev;
+ phys_t addr;
+
+ /* L2-only sync was introduced with CM major revision 6 */
+ major_rev = (read_gcr_rev() & CM_GCR_REV_MAJOR_MSK) >>
+ CM_GCR_REV_MAJOR_SHF;
+ if (major_rev < 6)
+ return;
+
+ /* Find a location for the L2 sync region */
+ addr = mips_cm_l2sync_phys_base();
+ BUG_ON((addr & CM_GCR_L2_ONLY_SYNC_BASE_SYNCBASE_MSK) != addr);
+ if (!addr)
+ return;
+
+ /* Set the region base address & enable it */
+ write_gcr_l2_only_sync_base(addr | CM_GCR_L2_ONLY_SYNC_BASE_SYNCEN_MSK);
+
+ /* Map the region */
+ mips_cm_l2sync_base = ioremap_nocache(addr, MIPS_CM_L2SYNC_SIZE);
+}
+
+int mips_cm_probe(void)
+{
+ phys_t addr;
+ u32 base_reg;
+
+ addr = mips_cm_phys_base();
+ BUG_ON((addr & CM_GCR_BASE_GCRBASE_MSK) != addr);
+ if (!addr)
+ return -ENODEV;
+
+ mips_cm_base = ioremap_nocache(addr, MIPS_CM_GCR_SIZE);
+ if (!mips_cm_base)
+ return -ENXIO;
+
+ /* sanity check that we're looking at a CM */
+ base_reg = read_gcr_base();
+ if ((base_reg & CM_GCR_BASE_GCRBASE_MSK) != addr) {
+ pr_err("GCRs appear to have been moved (expected them at 0x%08lx)!\n",
+ (unsigned long)addr);
+ mips_cm_base = NULL;
+ return -ENODEV;
+ }
+
+ /* set default target to memory */
+ base_reg &= ~CM_GCR_BASE_CMDEFTGT_MSK;
+ base_reg |= CM_GCR_BASE_CMDEFTGT_MEM;
+ write_gcr_base(base_reg);
+
+ /* disable CM regions */
+ write_gcr_reg0_base(CM_GCR_REGn_BASE_BASEADDR_MSK);
+ write_gcr_reg0_mask(CM_GCR_REGn_MASK_ADDRMASK_MSK);
+ write_gcr_reg1_base(CM_GCR_REGn_BASE_BASEADDR_MSK);
+ write_gcr_reg1_mask(CM_GCR_REGn_MASK_ADDRMASK_MSK);
+ write_gcr_reg2_base(CM_GCR_REGn_BASE_BASEADDR_MSK);
+ write_gcr_reg2_mask(CM_GCR_REGn_MASK_ADDRMASK_MSK);
+ write_gcr_reg3_base(CM_GCR_REGn_BASE_BASEADDR_MSK);
+ write_gcr_reg3_mask(CM_GCR_REGn_MASK_ADDRMASK_MSK);
+
+ /* probe for an L2-only sync region */
+ mips_cm_probe_l2sync();
+
+ return 0;
+}
diff --git a/arch/mips/kernel/mips-cpc.c b/arch/mips/kernel/mips-cpc.c
new file mode 100644
index 000000000000..c9dc67402969
--- /dev/null
+++ b/arch/mips/kernel/mips-cpc.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.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/errno.h>
+
+#include <asm/mips-cm.h>
+#include <asm/mips-cpc.h>
+
+void __iomem *mips_cpc_base;
+
+phys_t __weak mips_cpc_phys_base(void)
+{
+ u32 cpc_base;
+
+ if (!mips_cm_present())
+ return 0;
+
+ if (!(read_gcr_cpc_status() & CM_GCR_CPC_STATUS_EX_MSK))
+ return 0;
+
+ /* If the CPC is already enabled, leave it so */
+ cpc_base = read_gcr_cpc_base();
+ if (cpc_base & CM_GCR_CPC_BASE_CPCEN_MSK)
+ return cpc_base & CM_GCR_CPC_BASE_CPCBASE_MSK;
+
+ /* Otherwise, give it the default address & enable it */
+ cpc_base = mips_cpc_default_phys_base();
+ write_gcr_cpc_base(cpc_base | CM_GCR_CPC_BASE_CPCEN_MSK);
+ return cpc_base;
+}
+
+int mips_cpc_probe(void)
+{
+ phys_t addr;
+
+ addr = mips_cpc_phys_base();
+ if (!addr)
+ return -ENODEV;
+
+ mips_cpc_base = ioremap_nocache(addr, 0x8000);
+ if (!mips_cpc_base)
+ return -ENXIO;
+
+ return 0;
+}
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c
index 6e58e97fcd39..2607c3a4ff7e 100644
--- a/arch/mips/kernel/mips_ksyms.c
+++ b/arch/mips/kernel/mips_ksyms.c
@@ -16,12 +16,20 @@
#include <asm/ftrace.h>
extern void *__bzero(void *__s, size_t __count);
+extern long __strncpy_from_kernel_nocheck_asm(char *__to,
+ const char *__from, long __len);
+extern long __strncpy_from_kernel_asm(char *__to, const char *__from,
+ long __len);
extern long __strncpy_from_user_nocheck_asm(char *__to,
const char *__from, long __len);
extern long __strncpy_from_user_asm(char *__to, const char *__from,
long __len);
+extern long __strlen_kernel_nocheck_asm(const char *s);
+extern long __strlen_kernel_asm(const char *s);
extern long __strlen_user_nocheck_asm(const char *s);
extern long __strlen_user_asm(const char *s);
+extern long __strnlen_kernel_nocheck_asm(const char *s);
+extern long __strnlen_kernel_asm(const char *s);
extern long __strnlen_user_nocheck_asm(const char *s);
extern long __strnlen_user_asm(const char *s);
@@ -43,17 +51,31 @@ EXPORT_SYMBOL(copy_page);
*/
EXPORT_SYMBOL(__copy_user);
EXPORT_SYMBOL(__copy_user_inatomic);
+#ifdef CONFIG_EVA
+EXPORT_SYMBOL(__copy_from_user_eva);
+EXPORT_SYMBOL(__copy_in_user_eva);
+EXPORT_SYMBOL(__copy_to_user_eva);
+EXPORT_SYMBOL(__copy_user_inatomic_eva);
+#endif
EXPORT_SYMBOL(__bzero);
+EXPORT_SYMBOL(__strncpy_from_kernel_nocheck_asm);
+EXPORT_SYMBOL(__strncpy_from_kernel_asm);
EXPORT_SYMBOL(__strncpy_from_user_nocheck_asm);
EXPORT_SYMBOL(__strncpy_from_user_asm);
+EXPORT_SYMBOL(__strlen_kernel_nocheck_asm);
+EXPORT_SYMBOL(__strlen_kernel_asm);
EXPORT_SYMBOL(__strlen_user_nocheck_asm);
EXPORT_SYMBOL(__strlen_user_asm);
+EXPORT_SYMBOL(__strnlen_kernel_nocheck_asm);
+EXPORT_SYMBOL(__strnlen_kernel_asm);
EXPORT_SYMBOL(__strnlen_user_nocheck_asm);
EXPORT_SYMBOL(__strnlen_user_asm);
EXPORT_SYMBOL(csum_partial);
EXPORT_SYMBOL(csum_partial_copy_nocheck);
-EXPORT_SYMBOL(__csum_partial_copy_user);
+EXPORT_SYMBOL(__csum_partial_copy_kernel);
+EXPORT_SYMBOL(__csum_partial_copy_to_user);
+EXPORT_SYMBOL(__csum_partial_copy_from_user);
EXPORT_SYMBOL(invalid_pte_table);
#ifdef CONFIG_FUNCTION_TRACER
diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c
index 24cdf64789c3..4f2d9dece7ab 100644
--- a/arch/mips/kernel/perf_event_mipsxx.c
+++ b/arch/mips/kernel/perf_event_mipsxx.c
@@ -805,7 +805,7 @@ static void reset_counters(void *arg)
}
}
-/* 24K/34K/1004K cores can share the same event map. */
+/* 24K/34K/1004K/interAptiv/loongson1 cores share the same event map. */
static const struct mips_perf_event mipsxxcore_event_map
[PERF_COUNT_HW_MAX] = {
[PERF_COUNT_HW_CPU_CYCLES] = { 0x00, CNTR_EVEN | CNTR_ODD, P },
@@ -814,8 +814,8 @@ static const struct mips_perf_event mipsxxcore_event_map
[PERF_COUNT_HW_BRANCH_MISSES] = { 0x02, CNTR_ODD, T },
};
-/* 74K core has different branch event code. */
-static const struct mips_perf_event mipsxx74Kcore_event_map
+/* 74K/proAptiv core has different branch event code. */
+static const struct mips_perf_event mipsxxcore_event_map2
[PERF_COUNT_HW_MAX] = {
[PERF_COUNT_HW_CPU_CYCLES] = { 0x00, CNTR_EVEN | CNTR_ODD, P },
[PERF_COUNT_HW_INSTRUCTIONS] = { 0x01, CNTR_EVEN | CNTR_ODD, T },
@@ -849,7 +849,7 @@ static const struct mips_perf_event xlp_event_map[PERF_COUNT_HW_MAX] = {
[PERF_COUNT_HW_BRANCH_MISSES] = { 0x1c, CNTR_ALL }, /* PAPI_BR_MSP */
};
-/* 24K/34K/1004K cores can share the same cache event map. */
+/* 24K/34K/1004K/interAptiv/loongson1 cores share the same cache event map. */
static const struct mips_perf_event mipsxxcore_cache_map
[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
@@ -930,8 +930,8 @@ static const struct mips_perf_event mipsxxcore_cache_map
},
};
-/* 74K core has completely different cache event map. */
-static const struct mips_perf_event mipsxx74Kcore_cache_map
+/* 74K/proAptiv core has completely different cache event map. */
+static const struct mips_perf_event mipsxxcore_cache_map2
[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
@@ -978,6 +978,11 @@ static const struct mips_perf_event mipsxx74Kcore_cache_map
[C(RESULT_MISS)] = { 0x1d, CNTR_EVEN, P },
},
},
+/*
+ * 74K core does not have specific DTLB events. proAptiv core has
+ * "speculative" DTLB events which are numbered 0x63 (even/odd) and
+ * not included here. One can use raw events if really needed.
+ */
[C(ITLB)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = { 0x04, CNTR_EVEN, T },
@@ -1378,6 +1383,10 @@ static irqreturn_t mipsxx_pmu_handle_irq(int irq, void *dev)
#define IS_BOTH_COUNTERS_74K_EVENT(b) \
((b) == 0 || (b) == 1)
+/* proAptiv */
+#define IS_BOTH_COUNTERS_PROAPTIV_EVENT(b) \
+ ((b) == 0 || (b) == 1)
+
/* 1004K */
#define IS_BOTH_COUNTERS_1004K_EVENT(b) \
((b) == 0 || (b) == 1 || (b) == 11)
@@ -1391,6 +1400,20 @@ static irqreturn_t mipsxx_pmu_handle_irq(int irq, void *dev)
#define IS_RANGE_V_1004K_EVENT(r) ((r) == 47)
#endif
+/* interAptiv */
+#define IS_BOTH_COUNTERS_INTERAPTIV_EVENT(b) \
+ ((b) == 0 || (b) == 1 || (b) == 11)
+#ifdef CONFIG_MIPS_MT_SMP
+/* The P/V/T info is not provided for "(b) == 38" in SUM, assume P. */
+#define IS_RANGE_P_INTERAPTIV_EVENT(r, b) \
+ ((b) == 0 || (r) == 18 || (b) == 21 || (b) == 22 || \
+ (b) == 25 || (b) == 36 || (b) == 38 || (b) == 39 || \
+ (r) == 44 || (r) == 174 || (r) == 176 || ((b) >= 50 && \
+ (b) <= 59) || (r) == 188 || (b) == 61 || (b) == 62 || \
+ ((b) >= 64 && (b) <= 67))
+#define IS_RANGE_V_INTERAPTIV_EVENT(r) ((r) == 47 || (r) == 175)
+#endif
+
/* BMIPS5000 */
#define IS_BOTH_COUNTERS_BMIPS5000_EVENT(b) \
((b) == 0 || (b) == 1)
@@ -1442,6 +1465,7 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config)
#endif
break;
case CPU_74K:
+ case CPU_1074K:
if (IS_BOTH_COUNTERS_74K_EVENT(base_id))
raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
else
@@ -1451,6 +1475,16 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config)
raw_event.range = P;
#endif
break;
+ case CPU_PROAPTIV:
+ if (IS_BOTH_COUNTERS_PROAPTIV_EVENT(base_id))
+ raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
+ else
+ raw_event.cntr_mask =
+ raw_id > 127 ? CNTR_ODD : CNTR_EVEN;
+#ifdef CONFIG_MIPS_MT_SMP
+ raw_event.range = P;
+#endif
+ break;
case CPU_1004K:
if (IS_BOTH_COUNTERS_1004K_EVENT(base_id))
raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
@@ -1466,6 +1500,21 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config)
raw_event.range = T;
#endif
break;
+ case CPU_INTERAPTIV:
+ if (IS_BOTH_COUNTERS_INTERAPTIV_EVENT(base_id))
+ raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
+ else
+ raw_event.cntr_mask =
+ raw_id > 127 ? CNTR_ODD : CNTR_EVEN;
+#ifdef CONFIG_MIPS_MT_SMP
+ if (IS_RANGE_P_INTERAPTIV_EVENT(raw_id, base_id))
+ raw_event.range = P;
+ else if (unlikely(IS_RANGE_V_INTERAPTIV_EVENT(raw_id)))
+ raw_event.range = V;
+ else
+ raw_event.range = T;
+#endif
+ break;
case CPU_BMIPS5000:
if (IS_BOTH_COUNTERS_BMIPS5000_EVENT(base_id))
raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
@@ -1576,14 +1625,29 @@ init_hw_perf_events(void)
break;
case CPU_74K:
mipspmu.name = "mips/74K";
- mipspmu.general_event_map = &mipsxx74Kcore_event_map;
- mipspmu.cache_event_map = &mipsxx74Kcore_cache_map;
+ mipspmu.general_event_map = &mipsxxcore_event_map2;
+ mipspmu.cache_event_map = &mipsxxcore_cache_map2;
+ break;
+ case CPU_PROAPTIV:
+ mipspmu.name = "mips/proAptiv";
+ mipspmu.general_event_map = &mipsxxcore_event_map2;
+ mipspmu.cache_event_map = &mipsxxcore_cache_map2;
break;
case CPU_1004K:
mipspmu.name = "mips/1004K";
mipspmu.general_event_map = &mipsxxcore_event_map;
mipspmu.cache_event_map = &mipsxxcore_cache_map;
break;
+ case CPU_1074K:
+ mipspmu.name = "mips/1074K";
+ mipspmu.general_event_map = &mipsxxcore_event_map;
+ mipspmu.cache_event_map = &mipsxxcore_cache_map;
+ break;
+ case CPU_INTERAPTIV:
+ mipspmu.name = "mips/interAptiv";
+ mipspmu.general_event_map = &mipsxxcore_event_map;
+ mipspmu.cache_event_map = &mipsxxcore_cache_map;
+ break;
case CPU_LOONGSON1:
mipspmu.name = "mips/loongson1";
mipspmu.general_event_map = &mipsxxcore_event_map;
diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c
index 00d20974b3e7..e40971b51d2f 100644
--- a/arch/mips/kernel/proc.c
+++ b/arch/mips/kernel/proc.c
@@ -17,8 +17,24 @@
unsigned int vced_count, vcei_count;
+/*
+ * * No lock; only written during early bootup by CPU 0.
+ * */
+static RAW_NOTIFIER_HEAD(proc_cpuinfo_chain);
+
+int __ref register_proc_cpuinfo_notifier(struct notifier_block *nb)
+{
+ return raw_notifier_chain_register(&proc_cpuinfo_chain, nb);
+}
+
+int proc_cpuinfo_notifier_call_chain(unsigned long val, void *v)
+{
+ return raw_notifier_call_chain(&proc_cpuinfo_chain, val, v);
+}
+
static int show_cpuinfo(struct seq_file *m, void *v)
{
+ struct proc_cpuinfo_notifier_args proc_cpuinfo_notifier_args;
unsigned long n = (unsigned long) v - 1;
unsigned int version = cpu_data[n].processor_id;
unsigned int fp_vers = cpu_data[n].fpu_id;
@@ -95,6 +111,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
if (cpu_has_mipsmt) seq_printf(m, "%s", " mt");
if (cpu_has_mmips) seq_printf(m, "%s", " micromips");
if (cpu_has_vz) seq_printf(m, "%s", " vz");
+ if (cpu_has_msa) seq_printf(m, "%s", " msa");
+ if (cpu_has_eva) seq_printf(m, "%s", " eva");
seq_printf(m, "\n");
if (cpu_has_mmips) {
@@ -118,6 +136,13 @@ static int show_cpuinfo(struct seq_file *m, void *v)
cpu_has_vce ? "%u" : "not available");
seq_printf(m, fmt, 'D', vced_count);
seq_printf(m, fmt, 'I', vcei_count);
+
+ proc_cpuinfo_notifier_args.m = m;
+ proc_cpuinfo_notifier_args.n = n;
+
+ raw_notifier_call_chain(&proc_cpuinfo_chain, 0,
+ &proc_cpuinfo_notifier_args);
+
seq_printf(m, "\n");
return 0;
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 6ae540e133b2..60e39dc7f1eb 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -32,6 +32,7 @@
#include <asm/cpu.h>
#include <asm/dsp.h>
#include <asm/fpu.h>
+#include <asm/msa.h>
#include <asm/pgtable.h>
#include <asm/mipsregs.h>
#include <asm/processor.h>
@@ -65,6 +66,8 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
clear_used_math();
clear_fpu_owner();
init_dsp();
+ clear_thread_flag(TIF_MSA_CTX_LIVE);
+ disable_msa();
regs->cp0_epc = pc;
regs->regs[29] = sp;
}
@@ -89,7 +92,9 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
preempt_disable();
- if (is_fpu_owner())
+ if (is_msa_enabled())
+ save_msa(p);
+ else if (is_fpu_owner())
save_fp(p);
if (cpu_has_dsp)
@@ -157,7 +162,13 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
/* Fill in the fpu structure for a core dump.. */
int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r)
{
- memcpy(r, &current->thread.fpu, sizeof(current->thread.fpu));
+ int i;
+
+ for (i = 0; i < NUM_FPU_REGS; i++)
+ memcpy(&r[i], &current->thread.fpu.fpr[i], sizeof(*r));
+
+ memcpy(&r[NUM_FPU_REGS], &current->thread.fpu.fcr31,
+ sizeof(current->thread.fpu.fcr31));
return 1;
}
@@ -192,7 +203,13 @@ int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
int dump_task_fpu(struct task_struct *t, elf_fpregset_t *fpr)
{
- memcpy(fpr, &t->thread.fpu, sizeof(current->thread.fpu));
+ int i;
+
+ for (i = 0; i < NUM_FPU_REGS; i++)
+ memcpy(&fpr[i], &t->thread.fpu.fpr[i], sizeof(*fpr));
+
+ memcpy(&fpr[NUM_FPU_REGS], &t->thread.fpu.fcr31,
+ sizeof(t->thread.fpu.fcr31));
return 1;
}
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 7da9b76db4d9..7271e5a83081 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -114,51 +114,30 @@ int ptrace_setregs(struct task_struct *child, __s64 __user *data)
int ptrace_getfpregs(struct task_struct *child, __u32 __user *data)
{
int i;
- unsigned int tmp;
if (!access_ok(VERIFY_WRITE, data, 33 * 8))
return -EIO;
if (tsk_used_math(child)) {
- fpureg_t *fregs = get_fpu_regs(child);
+ union fpureg *fregs = get_fpu_regs(child);
for (i = 0; i < 32; i++)
- __put_user(fregs[i], i + (__u64 __user *) data);
+ __put_user(get_fpr64(&fregs[i], 0),
+ i + (__u64 __user *)data);
} else {
for (i = 0; i < 32; i++)
__put_user((__u64) -1, i + (__u64 __user *) data);
}
__put_user(child->thread.fpu.fcr31, data + 64);
-
- preempt_disable();
- if (cpu_has_fpu) {
- unsigned int flags;
-
- if (cpu_has_mipsmt) {
- unsigned int vpflags = dvpe();
- flags = read_c0_status();
- __enable_fpu(FPU_AS_IS);
- __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
- write_c0_status(flags);
- evpe(vpflags);
- } else {
- flags = read_c0_status();
- __enable_fpu(FPU_AS_IS);
- __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
- write_c0_status(flags);
- }
- } else {
- tmp = 0;
- }
- preempt_enable();
- __put_user(tmp, data + 65);
+ __put_user(current_cpu_data.fpu_id, data + 65);
return 0;
}
int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
{
- fpureg_t *fregs;
+ union fpureg *fregs;
+ u64 fpr_val;
int i;
if (!access_ok(VERIFY_READ, data, 33 * 8))
@@ -166,8 +145,10 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
fregs = get_fpu_regs(child);
- for (i = 0; i < 32; i++)
- __get_user(fregs[i], i + (__u64 __user *) data);
+ for (i = 0; i < 32; i++) {
+ __get_user(fpr_val, i + (__u64 __user *)data);
+ set_fpr64(&fregs[i], 0, fpr_val);
+ }
__get_user(child->thread.fpu.fcr31, data + 64);
@@ -300,10 +281,27 @@ static int fpr_get(struct task_struct *target,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{
- return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
- &target->thread.fpu,
- 0, sizeof(elf_fpregset_t));
+ unsigned i;
+ int err;
+ u64 fpr_val;
+
/* XXX fcr31 */
+
+ if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t))
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.fpu,
+ 0, sizeof(elf_fpregset_t));
+
+ for (i = 0; i < NUM_FPU_REGS; i++) {
+ fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0);
+ err = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &fpr_val, i * sizeof(elf_fpreg_t),
+ (i + 1) * sizeof(elf_fpreg_t));
+ if (err)
+ return err;
+ }
+
+ return 0;
}
static int fpr_set(struct task_struct *target,
@@ -311,10 +309,27 @@ static int fpr_set(struct task_struct *target,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
- return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- &target->thread.fpu,
- 0, sizeof(elf_fpregset_t));
+ unsigned i;
+ int err;
+ u64 fpr_val;
+
/* XXX fcr31 */
+
+ if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t))
+ return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.fpu,
+ 0, sizeof(elf_fpregset_t));
+
+ for (i = 0; i < NUM_FPU_REGS; i++) {
+ err = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &fpr_val, i * sizeof(elf_fpreg_t),
+ (i + 1) * sizeof(elf_fpreg_t));
+ if (err)
+ return err;
+ set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val);
+ }
+
+ return 0;
}
enum mips_regset {
@@ -408,7 +423,7 @@ long arch_ptrace(struct task_struct *child, long request,
/* Read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
struct pt_regs *regs;
- fpureg_t *fregs;
+ union fpureg *fregs;
unsigned long tmp = 0;
regs = task_pt_regs(child);
@@ -433,14 +448,12 @@ long arch_ptrace(struct task_struct *child, long request,
* order bits of the values stored in the even
* registers - unless we're using r2k_switch.S.
*/
- if (addr & 1)
- tmp = fregs[(addr & ~1) - 32] >> 32;
- else
- tmp = fregs[addr - 32];
+ tmp = get_fpr32(&fregs[(addr & ~1) - FPR_BASE],
+ addr & 1);
break;
}
#endif
- tmp = fregs[addr - FPR_BASE];
+ tmp = get_fpr32(&fregs[addr - FPR_BASE], 0);
break;
case PC:
tmp = regs->cp0_epc;
@@ -465,44 +478,10 @@ long arch_ptrace(struct task_struct *child, long request,
case FPC_CSR:
tmp = child->thread.fpu.fcr31;
break;
- case FPC_EIR: { /* implementation / version register */
- unsigned int flags;
-#ifdef CONFIG_MIPS_MT_SMTC
- unsigned long irqflags;
- unsigned int mtflags;
-#endif /* CONFIG_MIPS_MT_SMTC */
-
- preempt_disable();
- if (!cpu_has_fpu) {
- preempt_enable();
- break;
- }
-
-#ifdef CONFIG_MIPS_MT_SMTC
- /* Read-modify-write of Status must be atomic */
- local_irq_save(irqflags);
- mtflags = dmt();
-#endif /* CONFIG_MIPS_MT_SMTC */
- if (cpu_has_mipsmt) {
- unsigned int vpflags = dvpe();
- flags = read_c0_status();
- __enable_fpu(FPU_AS_IS);
- __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
- write_c0_status(flags);
- evpe(vpflags);
- } else {
- flags = read_c0_status();
- __enable_fpu(FPU_AS_IS);
- __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
- write_c0_status(flags);
- }
-#ifdef CONFIG_MIPS_MT_SMTC
- emt(mtflags);
- local_irq_restore(irqflags);
-#endif /* CONFIG_MIPS_MT_SMTC */
- preempt_enable();
+ case FPC_EIR:
+ /* implementation / version register */
+ tmp = current_cpu_data.fpu_id;
break;
- }
case DSP_BASE ... DSP_BASE + 5: {
dspreg_t *dregs;
@@ -548,7 +527,7 @@ long arch_ptrace(struct task_struct *child, long request,
regs->regs[addr] = data;
break;
case FPR_BASE ... FPR_BASE + 31: {
- fpureg_t *fregs = get_fpu_regs(child);
+ union fpureg *fregs = get_fpu_regs(child);
if (!tsk_used_math(child)) {
/* FP not yet used */
@@ -563,19 +542,12 @@ long arch_ptrace(struct task_struct *child, long request,
* order bits of the values stored in the even
* registers - unless we're using r2k_switch.S.
*/
- if (addr & 1) {
- fregs[(addr & ~1) - FPR_BASE] &=
- 0xffffffff;
- fregs[(addr & ~1) - FPR_BASE] |=
- ((u64)data) << 32;
- } else {
- fregs[addr - FPR_BASE] &= ~0xffffffffLL;
- fregs[addr - FPR_BASE] |= data;
- }
+ set_fpr32(&fregs[(addr & ~1) - FPR_BASE],
+ addr & 1, data);
break;
}
#endif
- fregs[addr - FPR_BASE] = data;
+ set_fpr64(&fregs[addr - FPR_BASE], 0, data);
break;
}
case PC:
@@ -662,13 +634,13 @@ long arch_ptrace(struct task_struct *child, long request,
* Notification of system call entry/exit
* - triggered by current->work.syscall_trace
*/
-asmlinkage void syscall_trace_enter(struct pt_regs *regs)
+asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall)
{
long ret = 0;
user_exit();
- /* do the secure computing check first */
- secure_computing_strict(regs->regs[2]);
+ if (secure_computing(syscall) == -1)
+ return -1;
if (test_thread_flag(TIF_SYSCALL_TRACE) &&
tracehook_report_syscall_entry(regs))
@@ -677,10 +649,11 @@ asmlinkage void syscall_trace_enter(struct pt_regs *regs)
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_enter(regs, regs->regs[2]);
- audit_syscall_entry(__syscall_get_arch(),
- regs->regs[2],
+ audit_syscall_entry(syscall_get_arch(current, regs),
+ syscall,
regs->regs[4], regs->regs[5],
regs->regs[6], regs->regs[7]);
+ return syscall;
}
/*
diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c
index b8aa2dd5b00b..b40c3ca60ee5 100644
--- a/arch/mips/kernel/ptrace32.c
+++ b/arch/mips/kernel/ptrace32.c
@@ -80,7 +80,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
/* Read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
struct pt_regs *regs;
- fpureg_t *fregs;
+ union fpureg *fregs;
unsigned int tmp;
regs = task_pt_regs(child);
@@ -103,13 +103,11 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
* order bits of the values stored in the even
* registers - unless we're using r2k_switch.S.
*/
- if (addr & 1)
- tmp = fregs[(addr & ~1) - 32] >> 32;
- else
- tmp = fregs[addr - 32];
+ tmp = get_fpr32(&fregs[(addr & ~1) - FPR_BASE],
+ addr & 1);
break;
}
- tmp = fregs[addr - FPR_BASE];
+ tmp = get_fpr32(&fregs[addr - FPR_BASE], 0);
break;
case PC:
tmp = regs->cp0_epc;
@@ -129,46 +127,10 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
case FPC_CSR:
tmp = child->thread.fpu.fcr31;
break;
- case FPC_EIR: { /* implementation / version register */
- unsigned int flags;
-#ifdef CONFIG_MIPS_MT_SMTC
- unsigned int irqflags;
- unsigned int mtflags;
-#endif /* CONFIG_MIPS_MT_SMTC */
-
- preempt_disable();
- if (!cpu_has_fpu) {
- preempt_enable();
- tmp = 0;
- break;
- }
-
-#ifdef CONFIG_MIPS_MT_SMTC
- /* Read-modify-write of Status must be atomic */
- local_irq_save(irqflags);
- mtflags = dmt();
-#endif /* CONFIG_MIPS_MT_SMTC */
-
- if (cpu_has_mipsmt) {
- unsigned int vpflags = dvpe();
- flags = read_c0_status();
- __enable_fpu(FPU_AS_IS);
- __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
- write_c0_status(flags);
- evpe(vpflags);
- } else {
- flags = read_c0_status();
- __enable_fpu(FPU_AS_IS);
- __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
- write_c0_status(flags);
- }
-#ifdef CONFIG_MIPS_MT_SMTC
- emt(mtflags);
- local_irq_restore(irqflags);
-#endif /* CONFIG_MIPS_MT_SMTC */
- preempt_enable();
+ case FPC_EIR:
+ /* implementation / version register */
+ tmp = current_cpu_data.fpu_id;
break;
- }
case DSP_BASE ... DSP_BASE + 5: {
dspreg_t *dregs;
@@ -233,7 +195,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
regs->regs[addr] = data;
break;
case FPR_BASE ... FPR_BASE + 31: {
- fpureg_t *fregs = get_fpu_regs(child);
+ union fpureg *fregs = get_fpu_regs(child);
if (!tsk_used_math(child)) {
/* FP not yet used */
@@ -247,18 +209,11 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
* order bits of the values stored in the even
* registers - unless we're using r2k_switch.S.
*/
- if (addr & 1) {
- fregs[(addr & ~1) - FPR_BASE] &=
- 0xffffffff;
- fregs[(addr & ~1) - FPR_BASE] |=
- ((u64)data) << 32;
- } else {
- fregs[addr - FPR_BASE] &= ~0xffffffffLL;
- fregs[addr - FPR_BASE] |= data;
- }
+ set_fpr32(&fregs[(addr & ~1) - FPR_BASE],
+ addr & 1, data);
break;
}
- fregs[addr - FPR_BASE] = data;
+ set_fpr64(&fregs[addr - FPR_BASE], 0, data);
break;
}
case PC:
diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S
index 253b2fb52026..71814272d148 100644
--- a/arch/mips/kernel/r4k_fpu.S
+++ b/arch/mips/kernel/r4k_fpu.S
@@ -13,6 +13,7 @@
* Copyright (C) 1999, 2001 Silicon Graphics, Inc.
*/
#include <asm/asm.h>
+#include <asm/asmmacro.h>
#include <asm/errno.h>
#include <asm/fpregdef.h>
#include <asm/mipsregs.h>
@@ -30,14 +31,14 @@
.endm
.set noreorder
- .set mips3
+ .set arch=r4000
LEAF(_save_fp_context)
cfc1 t1, fcr31
-#if defined(CONFIG_64BIT) || defined(CONFIG_MIPS32_R2)
+#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
.set push
-#ifdef CONFIG_MIPS32_R2
+#ifdef CONFIG_CPU_MIPS32_R2
.set mips64r2
mfc0 t0, CP0_STATUS
sll t0, t0, 5
@@ -146,11 +147,11 @@ LEAF(_save_fp_context32)
* - cp1 status/control register
*/
LEAF(_restore_fp_context)
- EX lw t0, SC_FPC_CSR(a0)
+ EX lw t1, SC_FPC_CSR(a0)
-#if defined(CONFIG_64BIT) || defined(CONFIG_MIPS32_R2)
+#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
.set push
-#ifdef CONFIG_MIPS32_R2
+#ifdef CONFIG_CPU_MIPS32_R2
.set mips64r2
mfc0 t0, CP0_STATUS
sll t0, t0, 5
@@ -191,7 +192,7 @@ LEAF(_restore_fp_context)
EX ldc1 $f26, SC_FPREGS+208(a0)
EX ldc1 $f28, SC_FPREGS+224(a0)
EX ldc1 $f30, SC_FPREGS+240(a0)
- ctc1 t0, fcr31
+ ctc1 t1, fcr31
jr ra
li v0, 0 # success
END(_restore_fp_context)
@@ -199,7 +200,7 @@ LEAF(_restore_fp_context)
#ifdef CONFIG_MIPS32_COMPAT
LEAF(_restore_fp_context32)
/* Restore an o32 sigcontext. */
- EX lw t0, SC32_FPC_CSR(a0)
+ EX lw t1, SC32_FPC_CSR(a0)
mfc0 t0, CP0_STATUS
sll t0, t0, 5
@@ -239,12 +240,224 @@ LEAF(_restore_fp_context32)
EX ldc1 $f26, SC32_FPREGS+208(a0)
EX ldc1 $f28, SC32_FPREGS+224(a0)
EX ldc1 $f30, SC32_FPREGS+240(a0)
- ctc1 t0, fcr31
+ ctc1 t1, fcr31
jr ra
li v0, 0 # success
END(_restore_fp_context32)
#endif
+#ifdef CONFIG_CPU_HAS_MSA
+
+ .macro save_sc_msareg wr, off, sc, tmp
+#ifdef CONFIG_64BIT
+ copy_u_d \tmp, \wr, 1
+ EX sd \tmp, (\off+(\wr*8))(\sc)
+#elif defined(CONFIG_CPU_LITTLE_ENDIAN)
+ copy_u_w \tmp, \wr, 2
+ EX sw \tmp, (\off+(\wr*8)+0)(\sc)
+ copy_u_w \tmp, \wr, 3
+ EX sw \tmp, (\off+(\wr*8)+4)(\sc)
+#else /* CONFIG_CPU_BIG_ENDIAN */
+ copy_u_w \tmp, \wr, 2
+ EX sw \tmp, (\off+(\wr*8)+4)(\sc)
+ copy_u_w \tmp, \wr, 3
+ EX sw \tmp, (\off+(\wr*8)+0)(\sc)
+#endif
+ .endm
+
+/*
+ * int _save_msa_context(struct sigcontext *sc)
+ *
+ * Save the upper 64 bits of each vector register along with the MSA_CSR
+ * register into sc. Returns zero on success, else non-zero.
+ */
+LEAF(_save_msa_context)
+ save_sc_msareg 0, SC_MSAREGS, a0, t0
+ save_sc_msareg 1, SC_MSAREGS, a0, t0
+ save_sc_msareg 2, SC_MSAREGS, a0, t0
+ save_sc_msareg 3, SC_MSAREGS, a0, t0
+ save_sc_msareg 4, SC_MSAREGS, a0, t0
+ save_sc_msareg 5, SC_MSAREGS, a0, t0
+ save_sc_msareg 6, SC_MSAREGS, a0, t0
+ save_sc_msareg 7, SC_MSAREGS, a0, t0
+ save_sc_msareg 8, SC_MSAREGS, a0, t0
+ save_sc_msareg 9, SC_MSAREGS, a0, t0
+ save_sc_msareg 10, SC_MSAREGS, a0, t0
+ save_sc_msareg 11, SC_MSAREGS, a0, t0
+ save_sc_msareg 12, SC_MSAREGS, a0, t0
+ save_sc_msareg 13, SC_MSAREGS, a0, t0
+ save_sc_msareg 14, SC_MSAREGS, a0, t0
+ save_sc_msareg 15, SC_MSAREGS, a0, t0
+ save_sc_msareg 16, SC_MSAREGS, a0, t0
+ save_sc_msareg 17, SC_MSAREGS, a0, t0
+ save_sc_msareg 18, SC_MSAREGS, a0, t0
+ save_sc_msareg 19, SC_MSAREGS, a0, t0
+ save_sc_msareg 20, SC_MSAREGS, a0, t0
+ save_sc_msareg 21, SC_MSAREGS, a0, t0
+ save_sc_msareg 22, SC_MSAREGS, a0, t0
+ save_sc_msareg 23, SC_MSAREGS, a0, t0
+ save_sc_msareg 24, SC_MSAREGS, a0, t0
+ save_sc_msareg 25, SC_MSAREGS, a0, t0
+ save_sc_msareg 26, SC_MSAREGS, a0, t0
+ save_sc_msareg 27, SC_MSAREGS, a0, t0
+ save_sc_msareg 28, SC_MSAREGS, a0, t0
+ save_sc_msareg 29, SC_MSAREGS, a0, t0
+ save_sc_msareg 30, SC_MSAREGS, a0, t0
+ save_sc_msareg 31, SC_MSAREGS, a0, t0
+ jr ra
+ li v0, 0
+ END(_save_msa_context)
+
+#ifdef CONFIG_MIPS32_COMPAT
+
+/*
+ * int _save_msa_context32(struct sigcontext32 *sc)
+ *
+ * Save the upper 64 bits of each vector register along with the MSA_CSR
+ * register into sc. Returns zero on success, else non-zero.
+ */
+LEAF(_save_msa_context32)
+ save_sc_msareg 0, SC32_MSAREGS, a0, t0
+ save_sc_msareg 1, SC32_MSAREGS, a0, t0
+ save_sc_msareg 2, SC32_MSAREGS, a0, t0
+ save_sc_msareg 3, SC32_MSAREGS, a0, t0
+ save_sc_msareg 4, SC32_MSAREGS, a0, t0
+ save_sc_msareg 5, SC32_MSAREGS, a0, t0
+ save_sc_msareg 6, SC32_MSAREGS, a0, t0
+ save_sc_msareg 7, SC32_MSAREGS, a0, t0
+ save_sc_msareg 8, SC32_MSAREGS, a0, t0
+ save_sc_msareg 9, SC32_MSAREGS, a0, t0
+ save_sc_msareg 10, SC32_MSAREGS, a0, t0
+ save_sc_msareg 11, SC32_MSAREGS, a0, t0
+ save_sc_msareg 12, SC32_MSAREGS, a0, t0
+ save_sc_msareg 13, SC32_MSAREGS, a0, t0
+ save_sc_msareg 14, SC32_MSAREGS, a0, t0
+ save_sc_msareg 15, SC32_MSAREGS, a0, t0
+ save_sc_msareg 16, SC32_MSAREGS, a0, t0
+ save_sc_msareg 17, SC32_MSAREGS, a0, t0
+ save_sc_msareg 18, SC32_MSAREGS, a0, t0
+ save_sc_msareg 19, SC32_MSAREGS, a0, t0
+ save_sc_msareg 20, SC32_MSAREGS, a0, t0
+ save_sc_msareg 21, SC32_MSAREGS, a0, t0
+ save_sc_msareg 22, SC32_MSAREGS, a0, t0
+ save_sc_msareg 23, SC32_MSAREGS, a0, t0
+ save_sc_msareg 24, SC32_MSAREGS, a0, t0
+ save_sc_msareg 25, SC32_MSAREGS, a0, t0
+ save_sc_msareg 26, SC32_MSAREGS, a0, t0
+ save_sc_msareg 27, SC32_MSAREGS, a0, t0
+ save_sc_msareg 28, SC32_MSAREGS, a0, t0
+ save_sc_msareg 29, SC32_MSAREGS, a0, t0
+ save_sc_msareg 30, SC32_MSAREGS, a0, t0
+ save_sc_msareg 31, SC32_MSAREGS, a0, t0
+ jr ra
+ li v0, 0
+ END(_save_msa_context32)
+
+#endif /* CONFIG_MIPS32_COMPAT */
+
+ .macro restore_sc_msareg wr, off, sc, tmp
+#ifdef CONFIG_64BIT
+ EX ld \tmp, (\off+(\wr*8))(\sc)
+ insert_d \wr, 1, \tmp
+#elif defined(CONFIG_CPU_LITTLE_ENDIAN)
+ EX lw \tmp, (\off+(\wr*8)+0)(\sc)
+ insert_w \wr, 2, \tmp
+ EX lw \tmp, (\off+(\wr*8)+4)(\sc)
+ insert_w \wr, 3, \tmp
+#else /* CONFIG_CPU_BIG_ENDIAN */
+ EX lw \tmp, (\off+(\wr*8)+4)(\sc)
+ insert_w \wr, 2, \tmp
+ EX lw \tmp, (\off+(\wr*8)+0)(\sc)
+ insert_w \wr, 3, \tmp
+#endif
+ .endm
+
+/*
+ * int _restore_msa_context(struct sigcontext *sc)
+ */
+LEAF(_restore_msa_context)
+ restore_sc_msareg 0, SC_MSAREGS, a0, t0
+ restore_sc_msareg 1, SC_MSAREGS, a0, t0
+ restore_sc_msareg 2, SC_MSAREGS, a0, t0
+ restore_sc_msareg 3, SC_MSAREGS, a0, t0
+ restore_sc_msareg 4, SC_MSAREGS, a0, t0
+ restore_sc_msareg 5, SC_MSAREGS, a0, t0
+ restore_sc_msareg 6, SC_MSAREGS, a0, t0
+ restore_sc_msareg 7, SC_MSAREGS, a0, t0
+ restore_sc_msareg 8, SC_MSAREGS, a0, t0
+ restore_sc_msareg 9, SC_MSAREGS, a0, t0
+ restore_sc_msareg 10, SC_MSAREGS, a0, t0
+ restore_sc_msareg 11, SC_MSAREGS, a0, t0
+ restore_sc_msareg 12, SC_MSAREGS, a0, t0
+ restore_sc_msareg 13, SC_MSAREGS, a0, t0
+ restore_sc_msareg 14, SC_MSAREGS, a0, t0
+ restore_sc_msareg 15, SC_MSAREGS, a0, t0
+ restore_sc_msareg 16, SC_MSAREGS, a0, t0
+ restore_sc_msareg 17, SC_MSAREGS, a0, t0
+ restore_sc_msareg 18, SC_MSAREGS, a0, t0
+ restore_sc_msareg 19, SC_MSAREGS, a0, t0
+ restore_sc_msareg 20, SC_MSAREGS, a0, t0
+ restore_sc_msareg 21, SC_MSAREGS, a0, t0
+ restore_sc_msareg 22, SC_MSAREGS, a0, t0
+ restore_sc_msareg 23, SC_MSAREGS, a0, t0
+ restore_sc_msareg 24, SC_MSAREGS, a0, t0
+ restore_sc_msareg 25, SC_MSAREGS, a0, t0
+ restore_sc_msareg 26, SC_MSAREGS, a0, t0
+ restore_sc_msareg 27, SC_MSAREGS, a0, t0
+ restore_sc_msareg 28, SC_MSAREGS, a0, t0
+ restore_sc_msareg 29, SC_MSAREGS, a0, t0
+ restore_sc_msareg 30, SC_MSAREGS, a0, t0
+ restore_sc_msareg 31, SC_MSAREGS, a0, t0
+ jr ra
+ li v0, 0
+ END(_restore_msa_context)
+
+#ifdef CONFIG_MIPS32_COMPAT
+
+/*
+ * int _restore_msa_context32(struct sigcontext32 *sc)
+ */
+LEAF(_restore_msa_context32)
+ restore_sc_msareg 0, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 1, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 2, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 3, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 4, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 5, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 6, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 7, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 8, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 9, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 10, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 11, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 12, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 13, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 14, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 15, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 16, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 17, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 18, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 19, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 20, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 21, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 22, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 23, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 24, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 25, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 26, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 27, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 28, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 29, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 30, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 31, SC32_MSAREGS, a0, t0
+ jr ra
+ li v0, 0
+ END(_restore_msa_context32)
+
+#endif /* CONFIG_MIPS32_COMPAT */
+
+#endif /* CONFIG_CPU_HAS_MSA */
+
.set reorder
.type fault@function
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
index cc78dd9a17c7..abacac7c33ef 100644
--- a/arch/mips/kernel/r4k_switch.S
+++ b/arch/mips/kernel/r4k_switch.S
@@ -29,18 +29,8 @@
#define ST_OFF (_THREAD_SIZE - 32 - PT_SIZE + PT_STATUS)
/*
- * FPU context is saved iff the process has used it's FPU in the current
- * time slice as indicated by _TIF_USEDFPU. In any case, the CU1 bit for user
- * space STATUS register should be 0, so that a process *always* starts its
- * userland with FPU disabled after each context switch.
- *
- * FPU will be enabled as soon as the process accesses FPU again, through
- * do_cpu() trap.
- */
-
-/*
* task_struct *resume(task_struct *prev, task_struct *next,
- * struct thread_info *next_ti, int usedfpu)
+ * struct thread_info *next_ti, s32 fp_save)
*/
.align 5
LEAF(resume)
@@ -50,23 +40,37 @@
LONG_S ra, THREAD_REG31(a0)
/*
- * check if we need to save FPU registers
+ * Check whether we need to save any FP context. FP context is saved
+ * iff the process has used the context with the scalar FPU or the MSA
+ * ASE in the current time slice, as indicated by _TIF_USEDFPU and
+ * _TIF_USEDMSA respectively. switch_to will have set fp_save
+ * accordingly to an FP_SAVE_ enum value.
*/
+ beqz a3, 2f
- beqz a3, 1f
-
- PTR_L t3, TASK_THREAD_INFO(a0)
/*
- * clear saved user stack CU1 bit
+ * We do. Clear the saved CU1 bit for prev, such that next time it is
+ * scheduled it will start in userland with the FPU disabled. If the
+ * task uses the FPU then it will be enabled again via the do_cpu trap.
+ * This allows us to lazily restore the FP context.
*/
+ PTR_L t3, TASK_THREAD_INFO(a0)
LONG_L t0, ST_OFF(t3)
li t1, ~ST0_CU1
and t0, t0, t1
LONG_S t0, ST_OFF(t3)
+ /* Check whether we're saving scalar or vector context. */
+ bgtz a3, 1f
+
+ /* Save 128b MSA vector context. */
+ msa_save_all a0
+ b 2f
+
+1: /* Save 32b/64b scalar FP context. */
fpu_save_double a0 t0 t1 # c0_status passed in t0
# clobbers t1
-1:
+2:
#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
PTR_LA t8, __stack_chk_guard
@@ -141,6 +145,26 @@ LEAF(_restore_fp)
jr ra
END(_restore_fp)
+#ifdef CONFIG_CPU_HAS_MSA
+
+/*
+ * Save a thread's MSA vector context.
+ */
+LEAF(_save_msa)
+ msa_save_all a0
+ jr ra
+ END(_save_msa)
+
+/*
+ * Restore a thread's MSA vector context.
+ */
+LEAF(_restore_msa)
+ msa_restore_all a0
+ jr ra
+ END(_restore_msa)
+
+#endif
+
/*
* Load the FPU with signalling NANS. This bit pattern we're using has
* the property that no matter whether considered as single or as double
@@ -270,7 +294,7 @@ LEAF(_init_fpu)
1: .set pop
#endif /* CONFIG_CPU_MIPS32_R2 */
#else
- .set mips3
+ .set arch=r4000
dmtc1 t1, $f0
dmtc1 t1, $f2
dmtc1 t1, $f4
diff --git a/arch/mips/kernel/rtlx-cmp.c b/arch/mips/kernel/rtlx-cmp.c
index 56dc69635153..758fb3cd2326 100644
--- a/arch/mips/kernel/rtlx-cmp.c
+++ b/arch/mips/kernel/rtlx-cmp.c
@@ -112,5 +112,8 @@ void __exit rtlx_module_exit(void)
for (i = 0; i < RTLX_CHANNELS; i++)
device_destroy(mt_class, MKDEV(major, i));
+
unregister_chrdev(major, RTLX_MODULE_NAME);
+
+ aprp_hook = NULL;
}
diff --git a/arch/mips/kernel/rtlx-mt.c b/arch/mips/kernel/rtlx-mt.c
index 91d61ba422b4..9c1aca00fd54 100644
--- a/arch/mips/kernel/rtlx-mt.c
+++ b/arch/mips/kernel/rtlx-mt.c
@@ -144,5 +144,8 @@ void __exit rtlx_module_exit(void)
for (i = 0; i < RTLX_CHANNELS; i++)
device_destroy(mt_class, MKDEV(major, i));
+
unregister_chrdev(major, RTLX_MODULE_NAME);
+
+ aprp_hook = NULL;
}
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index a5b14f48e1af..fdc70b400442 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -6,6 +6,7 @@
* Copyright (C) 1995-99, 2000- 02, 06 Ralf Baechle <ralf@linux-mips.org>
* Copyright (C) 2001 MIPS Technologies, Inc.
* Copyright (C) 2004 Thiemo Seufer
+ * Copyright (C) 2014 Imagination Technologies Ltd.
*/
#include <linux/errno.h>
#include <asm/asm.h>
@@ -74,10 +75,10 @@ NESTED(handle_sys, PT_SIZE, sp)
.set noreorder
.set nomacro
-1: lw t5, 16(t0) # argument #5 from usp
-4: lw t6, 20(t0) # argument #6 from usp
-3: lw t7, 24(t0) # argument #7 from usp
-2: lw t8, 28(t0) # argument #8 from usp
+1: user_lw(t5, 16(t0)) # argument #5 from usp
+4: user_lw(t6, 20(t0)) # argument #6 from usp
+3: user_lw(t7, 24(t0)) # argument #7 from usp
+2: user_lw(t8, 28(t0)) # argument #8 from usp
sw t5, 16(sp) # argument #5 to ksp
sw t6, 20(sp) # argument #6 to ksp
@@ -118,7 +119,18 @@ syscall_trace_entry:
SAVE_STATIC
move s0, t2
move a0, sp
- jal syscall_trace_enter
+
+ /*
+ * syscall number is in v0 unless we called syscall(__NR_###)
+ * where the real syscall number is in a0
+ */
+ addiu a1, v0, __NR_O32_Linux
+ bnez v0, 1f /* __NR_syscall at offset 0 */
+ lw a1, PT_R4(sp)
+
+1: jal syscall_trace_enter
+
+ bltz v0, 2f # seccomp failed? Skip syscall
move t0, s0
RESTORE_STATIC
@@ -138,7 +150,7 @@ syscall_trace_entry:
sw t1, PT_R0(sp) # save it for syscall restarting
1: sw v0, PT_R2(sp) # result
- j syscall_exit
+2: j syscall_exit
/* ------------------------------------------------------------------------ */
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index b56e254beb15..dd99c3285aea 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -80,8 +80,11 @@ syscall_trace_entry:
SAVE_STATIC
move s0, t2
move a0, sp
+ daddiu a1, v0, __NR_64_Linux
jal syscall_trace_enter
+ bltz v0, 2f # seccomp failed? Skip syscall
+
move t0, s0
RESTORE_STATIC
ld a0, PT_R4(sp) # Restore argument registers
@@ -102,7 +105,7 @@ syscall_trace_entry:
sd t1, PT_R0(sp) # save it for syscall restarting
1: sd v0, PT_R2(sp) # result
- j syscall_exit
+2: j syscall_exit
illegal_syscall:
/* This also isn't a 64-bit syscall, throw an error. */
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index f7e5b72cf481..f68d2f4f0090 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -72,8 +72,11 @@ n32_syscall_trace_entry:
SAVE_STATIC
move s0, t2
move a0, sp
+ daddiu a1, v0, __NR_N32_Linux
jal syscall_trace_enter
+ bltz v0, 2f # seccomp failed? Skip syscall
+
move t0, s0
RESTORE_STATIC
ld a0, PT_R4(sp) # Restore argument registers
@@ -94,7 +97,7 @@ n32_syscall_trace_entry:
sd t1, PT_R0(sp) # save it for syscall restarting
1: sd v0, PT_R2(sp) # result
- j syscall_exit
+2: j syscall_exit
not_n32_scall:
/* This is not an n32 compatibility syscall, pass it on to
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 6788727d91af..70f6acecd928 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -112,7 +112,20 @@ trace_a_syscall:
move s0, t2 # Save syscall pointer
move a0, sp
- jal syscall_trace_enter
+ /*
+ * syscall number is in v0 unless we called syscall(__NR_###)
+ * where the real syscall number is in a0
+ * note: NR_syscall is the first O32 syscall but the macro is
+ * only defined when compiling with -mabi=32 (CONFIG_32BIT)
+ * therefore __NR_O32_Linux is used (4000)
+ */
+ addiu a1, v0, __NR_O32_Linux
+ bnez v0, 1f /* __NR_syscall at offset 0 */
+ lw a1, PT_R4(sp)
+
+1: jal syscall_trace_enter
+
+ bltz v0, 2f # seccomp failed? Skip syscall
move t0, s0
RESTORE_STATIC
@@ -136,7 +149,7 @@ trace_a_syscall:
sd t1, PT_R0(sp) # save it for syscall restarting
1: sd v0, PT_R2(sp) # result
- j syscall_exit
+2: j syscall_exit
/* ------------------------------------------------------------------------ */
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 5199563c4403..33133d3df3e5 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -6,6 +6,7 @@
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1994 - 2000 Ralf Baechle
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2014, Imagination Technologies Ltd.
*/
#include <linux/cache.h>
#include <linux/context_tracking.h>
@@ -30,6 +31,7 @@
#include <linux/bitops.h>
#include <asm/cacheflush.h>
#include <asm/fpu.h>
+#include <asm/msa.h>
#include <asm/sim.h>
#include <asm/ucontext.h>
#include <asm/cpu-features.h>
@@ -46,8 +48,8 @@ static int (*restore_fp_context)(struct sigcontext __user *sc);
extern asmlinkage int _save_fp_context(struct sigcontext __user *sc);
extern asmlinkage int _restore_fp_context(struct sigcontext __user *sc);
-extern asmlinkage int fpu_emulator_save_context(struct sigcontext __user *sc);
-extern asmlinkage int fpu_emulator_restore_context(struct sigcontext __user *sc);
+extern asmlinkage int _save_msa_context(struct sigcontext __user *sc);
+extern asmlinkage int _restore_msa_context(struct sigcontext __user *sc);
struct sigframe {
u32 sf_ass[4]; /* argument save space for o32 */
@@ -64,17 +66,95 @@ struct rt_sigframe {
};
/*
+ * Thread saved context copy to/from a signal context presumed to be on the
+ * user stack, and therefore accessed with appropriate macros from uaccess.h.
+ */
+static int copy_fp_to_sigcontext(struct sigcontext __user *sc)
+{
+ int i;
+ int err = 0;
+
+ for (i = 0; i < NUM_FPU_REGS; i++) {
+ err |=
+ __put_user(get_fpr64(&current->thread.fpu.fpr[i], 0),
+ &sc->sc_fpregs[i]);
+ }
+ err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
+
+ return err;
+}
+
+static int copy_fp_from_sigcontext(struct sigcontext __user *sc)
+{
+ int i;
+ int err = 0;
+ u64 fpr_val;
+
+ for (i = 0; i < NUM_FPU_REGS; i++) {
+ err |= __get_user(fpr_val, &sc->sc_fpregs[i]);
+ set_fpr64(&current->thread.fpu.fpr[i], 0, fpr_val);
+ }
+ err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
+
+ return err;
+}
+
+/*
+ * These functions will save only the upper 64 bits of the vector registers,
+ * since the lower 64 bits have already been saved as the scalar FP context.
+ */
+static int copy_msa_to_sigcontext(struct sigcontext __user *sc)
+{
+ int i;
+ int err = 0;
+
+ for (i = 0; i < NUM_FPU_REGS; i++) {
+ err |=
+ __put_user(get_fpr64(&current->thread.fpu.fpr[i], 1),
+ &sc->sc_msaregs[i]);
+ }
+ err |= __put_user(current->thread.fpu.msacsr, &sc->sc_msa_csr);
+
+ return err;
+}
+
+static int copy_msa_from_sigcontext(struct sigcontext __user *sc)
+{
+ int i;
+ int err = 0;
+ u64 val;
+
+ for (i = 0; i < NUM_FPU_REGS; i++) {
+ err |= __get_user(val, &sc->sc_msaregs[i]);
+ set_fpr64(&current->thread.fpu.fpr[i], 1, val);
+ }
+ err |= __get_user(current->thread.fpu.msacsr, &sc->sc_msa_csr);
+
+ return err;
+}
+
+/*
* Helper routines
*/
-static int protected_save_fp_context(struct sigcontext __user *sc)
+static int protected_save_fp_context(struct sigcontext __user *sc,
+ unsigned used_math)
{
int err;
+ bool save_msa = cpu_has_msa && (used_math & USEDMATH_MSA);
+#ifndef CONFIG_EVA
while (1) {
lock_fpu_owner();
- err = own_fpu_inatomic(1);
- if (!err)
- err = save_fp_context(sc); /* this might fail */
- unlock_fpu_owner();
+ if (is_fpu_owner()) {
+ err = save_fp_context(sc);
+ if (save_msa && !err)
+ err = _save_msa_context(sc);
+ unlock_fpu_owner();
+ } else {
+ unlock_fpu_owner();
+ err = copy_fp_to_sigcontext(sc);
+ if (save_msa && !err)
+ err = copy_msa_to_sigcontext(sc);
+ }
if (likely(!err))
break;
/* touch the sigcontext and try again */
@@ -84,18 +164,44 @@ static int protected_save_fp_context(struct sigcontext __user *sc)
if (err)
break; /* really bad sigcontext */
}
+#else
+ /*
+ * EVA does not have FPU EVA instructions so saving fpu context directly
+ * does not work.
+ */
+ disable_msa();
+ lose_fpu(1);
+ err = save_fp_context(sc); /* this might fail */
+ if (save_msa && !err)
+ err = copy_msa_to_sigcontext(sc);
+#endif
return err;
}
-static int protected_restore_fp_context(struct sigcontext __user *sc)
+static int protected_restore_fp_context(struct sigcontext __user *sc,
+ unsigned used_math)
{
int err, tmp __maybe_unused;
+ bool restore_msa = cpu_has_msa && (used_math & USEDMATH_MSA);
+#ifndef CONFIG_EVA
while (1) {
lock_fpu_owner();
- err = own_fpu_inatomic(0);
- if (!err)
- err = restore_fp_context(sc); /* this might fail */
- unlock_fpu_owner();
+ if (is_fpu_owner()) {
+ err = restore_fp_context(sc);
+ if (restore_msa && !err) {
+ enable_msa();
+ err = _restore_msa_context(sc);
+ } else {
+ /* signal handler may have used MSA */
+ disable_msa();
+ }
+ unlock_fpu_owner();
+ } else {
+ unlock_fpu_owner();
+ err = copy_fp_from_sigcontext(sc);
+ if (!err && (used_math & USEDMATH_MSA))
+ err = copy_msa_from_sigcontext(sc);
+ }
if (likely(!err))
break;
/* touch the sigcontext and try again */
@@ -105,6 +211,17 @@ static int protected_restore_fp_context(struct sigcontext __user *sc)
if (err)
break; /* really bad sigcontext */
}
+#else
+ /*
+ * EVA does not have FPU EVA instructions so restoring fpu context
+ * directly does not work.
+ */
+ enable_msa();
+ lose_fpu(0);
+ err = restore_fp_context(sc); /* this might fail */
+ if (restore_msa && !err)
+ err = copy_msa_from_sigcontext(sc);
+#endif
return err;
}
@@ -135,7 +252,8 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
}
- used_math = !!used_math();
+ used_math = used_math() ? USEDMATH_FP : 0;
+ used_math |= thread_msa_context_live() ? USEDMATH_MSA : 0;
err |= __put_user(used_math, &sc->sc_used_math);
if (used_math) {
@@ -143,7 +261,7 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
* Save FPU state to signal context. Signal handler
* will "inherit" current FPU state.
*/
- err |= protected_save_fp_context(sc);
+ err |= protected_save_fp_context(sc, used_math);
}
return err;
}
@@ -168,14 +286,14 @@ int fpcsr_pending(unsigned int __user *fpcsr)
}
static int
-check_and_restore_fp_context(struct sigcontext __user *sc)
+check_and_restore_fp_context(struct sigcontext __user *sc, unsigned used_math)
{
int err, sig;
err = sig = fpcsr_pending(&sc->sc_fpc_csr);
if (err > 0)
err = 0;
- err |= protected_restore_fp_context(sc);
+ err |= protected_restore_fp_context(sc, used_math);
return err ?: sig;
}
@@ -215,9 +333,10 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
if (used_math) {
/* restore fpu context if we have used it before */
if (!err)
- err = check_and_restore_fp_context(sc);
+ err = check_and_restore_fp_context(sc, used_math);
} else {
- /* signal handler may have used FPU. Give it up. */
+ /* signal handler may have used FPU or MSA. Disable them. */
+ disable_msa();
lose_fpu(0);
}
@@ -591,23 +710,26 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
}
#ifdef CONFIG_SMP
+#ifndef CONFIG_EVA
static int smp_save_fp_context(struct sigcontext __user *sc)
{
return raw_cpu_has_fpu
? _save_fp_context(sc)
- : fpu_emulator_save_context(sc);
+ : copy_fp_to_sigcontext(sc);
}
static int smp_restore_fp_context(struct sigcontext __user *sc)
{
return raw_cpu_has_fpu
? _restore_fp_context(sc)
- : fpu_emulator_restore_context(sc);
+ : copy_fp_from_sigcontext(sc);
}
+#endif /* CONFIG_EVA */
#endif
static int signal_setup(void)
{
+#ifndef CONFIG_EVA
#ifdef CONFIG_SMP
/* For now just do the cpu_has_fpu check when the functions are invoked */
save_fp_context = smp_save_fp_context;
@@ -617,9 +739,13 @@ static int signal_setup(void)
save_fp_context = _save_fp_context;
restore_fp_context = _restore_fp_context;
} else {
- save_fp_context = fpu_emulator_save_context;
- restore_fp_context = fpu_emulator_restore_context;
+ save_fp_context = copy_fp_from_sigcontext;
+ restore_fp_context = copy_fp_to_sigcontext;
}
+#endif /* CONFIG_SMP */
+#else
+ save_fp_context = copy_fp_from_sigcontext;;
+ restore_fp_context = copy_fp_to_sigcontext;
#endif
return 0;
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index 3d60f7750fa8..299f956e4db3 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -30,6 +30,7 @@
#include <asm/sim.h>
#include <asm/ucontext.h>
#include <asm/fpu.h>
+#include <asm/msa.h>
#include <asm/war.h>
#include <asm/vdso.h>
#include <asm/dsp.h>
@@ -42,8 +43,8 @@ static int (*restore_fp_context32)(struct sigcontext32 __user *sc);
extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc);
extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc);
-extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 __user *sc);
-extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 __user *sc);
+extern asmlinkage int _save_msa_context32(struct sigcontext32 __user *sc);
+extern asmlinkage int _restore_msa_context32(struct sigcontext32 __user *sc);
/*
* Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
@@ -78,17 +79,96 @@ struct rt_sigframe32 {
};
/*
+ * Thread saved context copy to/from a signal context presumed to be on the
+ * user stack, and therefore accessed with appropriate macros from uaccess.h.
+ */
+static int copy_fp_to_sigcontext32(struct sigcontext32 __user *sc)
+{
+ int i;
+ int err = 0;
+ int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
+
+ for (i = 0; i < NUM_FPU_REGS; i += inc) {
+ err |=
+ __put_user(get_fpr64(&current->thread.fpu.fpr[i], 0),
+ &sc->sc_fpregs[i]);
+ }
+ err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
+
+ return err;
+}
+
+static int copy_fp_from_sigcontext32(struct sigcontext32 __user *sc)
+{
+ int i;
+ int err = 0;
+ int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
+ u64 fpr_val;
+
+ for (i = 0; i < NUM_FPU_REGS; i += inc) {
+ err |= __get_user(fpr_val, &sc->sc_fpregs[i]);
+ set_fpr64(&current->thread.fpu.fpr[i], 0, fpr_val);
+ }
+ err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
+
+ return err;
+}
+
+/*
+ * These functions will save only the upper 64 bits of the vector registers,
+ * since the lower 64 bits have already been saved as the scalar FP context.
+ */
+static int copy_msa_to_sigcontext32(struct sigcontext32 __user *sc)
+{
+ int i;
+ int err = 0;
+
+ for (i = 0; i < NUM_FPU_REGS; i++) {
+ err |=
+ __put_user(get_fpr64(&current->thread.fpu.fpr[i], 1),
+ &sc->sc_msaregs[i]);
+ }
+ err |= __put_user(current->thread.fpu.msacsr, &sc->sc_msa_csr);
+
+ return err;
+}
+
+static int copy_msa_from_sigcontext32(struct sigcontext32 __user *sc)
+{
+ int i;
+ int err = 0;
+ u64 val;
+
+ for (i = 0; i < NUM_FPU_REGS; i++) {
+ err |= __get_user(val, &sc->sc_msaregs[i]);
+ set_fpr64(&current->thread.fpu.fpr[i], 1, val);
+ }
+ err |= __get_user(current->thread.fpu.msacsr, &sc->sc_msa_csr);
+
+ return err;
+}
+
+/*
* sigcontext handlers
*/
-static int protected_save_fp_context32(struct sigcontext32 __user *sc)
+static int protected_save_fp_context32(struct sigcontext32 __user *sc,
+ unsigned used_math)
{
int err;
+ bool save_msa = cpu_has_msa && (used_math & USEDMATH_MSA);
while (1) {
lock_fpu_owner();
- err = own_fpu_inatomic(1);
- if (!err)
- err = save_fp_context32(sc); /* this might fail */
- unlock_fpu_owner();
+ if (is_fpu_owner()) {
+ err = save_fp_context32(sc);
+ if (save_msa && !err)
+ err = _save_msa_context32(sc);
+ unlock_fpu_owner();
+ } else {
+ unlock_fpu_owner();
+ err = copy_fp_to_sigcontext32(sc);
+ if (save_msa && !err)
+ err = copy_msa_to_sigcontext32(sc);
+ }
if (likely(!err))
break;
/* touch the sigcontext and try again */
@@ -101,15 +181,29 @@ static int protected_save_fp_context32(struct sigcontext32 __user *sc)
return err;
}
-static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
+static int protected_restore_fp_context32(struct sigcontext32 __user *sc,
+ unsigned used_math)
{
int err, tmp __maybe_unused;
+ bool restore_msa = cpu_has_msa && (used_math & USEDMATH_MSA);
while (1) {
lock_fpu_owner();
- err = own_fpu_inatomic(0);
- if (!err)
- err = restore_fp_context32(sc); /* this might fail */
- unlock_fpu_owner();
+ if (is_fpu_owner()) {
+ err = restore_fp_context32(sc);
+ if (restore_msa && !err) {
+ enable_msa();
+ err = _restore_msa_context32(sc);
+ } else {
+ /* signal handler may have used MSA */
+ disable_msa();
+ }
+ unlock_fpu_owner();
+ } else {
+ unlock_fpu_owner();
+ err = copy_fp_from_sigcontext32(sc);
+ if (restore_msa && !err)
+ err = copy_msa_from_sigcontext32(sc);
+ }
if (likely(!err))
break;
/* touch the sigcontext and try again */
@@ -147,7 +241,8 @@ static int setup_sigcontext32(struct pt_regs *regs,
err |= __put_user(mflo3(), &sc->sc_lo3);
}
- used_math = !!used_math();
+ used_math = used_math() ? USEDMATH_FP : 0;
+ used_math |= thread_msa_context_live() ? USEDMATH_MSA : 0;
err |= __put_user(used_math, &sc->sc_used_math);
if (used_math) {
@@ -155,20 +250,21 @@ static int setup_sigcontext32(struct pt_regs *regs,
* Save FPU state to signal context. Signal handler
* will "inherit" current FPU state.
*/
- err |= protected_save_fp_context32(sc);
+ err |= protected_save_fp_context32(sc, used_math);
}
return err;
}
static int
-check_and_restore_fp_context32(struct sigcontext32 __user *sc)
+check_and_restore_fp_context32(struct sigcontext32 __user *sc,
+ unsigned used_math)
{
int err, sig;
err = sig = fpcsr_pending(&sc->sc_fpc_csr);
if (err > 0)
err = 0;
- err |= protected_restore_fp_context32(sc);
+ err |= protected_restore_fp_context32(sc, used_math);
return err ?: sig;
}
@@ -205,9 +301,10 @@ static int restore_sigcontext32(struct pt_regs *regs,
if (used_math) {
/* restore fpu context if we have used it before */
if (!err)
- err = check_and_restore_fp_context32(sc);
+ err = check_and_restore_fp_context32(sc, used_math);
} else {
- /* signal handler may have used FPU. Give it up. */
+ /* signal handler may have used FPU or MSA. Disable them. */
+ disable_msa();
lose_fpu(0);
}
@@ -566,8 +663,8 @@ static int signal32_init(void)
save_fp_context32 = _save_fp_context32;
restore_fp_context32 = _restore_fp_context32;
} else {
- save_fp_context32 = fpu_emulator_save_context32;
- restore_fp_context32 = fpu_emulator_restore_context32;
+ save_fp_context32 = copy_fp_to_sigcontext32;
+ restore_fp_context32 = copy_fp_from_sigcontext32;
}
return 0;
diff --git a/arch/mips/kernel/smp-cmp.c b/arch/mips/kernel/smp-cmp.c
index 1b925d8a610c..3ef55fb7ac03 100644
--- a/arch/mips/kernel/smp-cmp.c
+++ b/arch/mips/kernel/smp-cmp.c
@@ -39,57 +39,9 @@
#include <asm/amon.h>
#include <asm/gic.h>
-static void ipi_call_function(unsigned int cpu)
-{
- pr_debug("CPU%d: %s cpu %d status %08x\n",
- smp_processor_id(), __func__, cpu, read_c0_status());
-
- gic_send_ipi(plat_ipi_call_int_xlate(cpu));
-}
-
-
-static void ipi_resched(unsigned int cpu)
-{
- pr_debug("CPU%d: %s cpu %d status %08x\n",
- smp_processor_id(), __func__, cpu, read_c0_status());
-
- gic_send_ipi(plat_ipi_resched_int_xlate(cpu));
-}
-
-/*
- * FIXME: This isn't restricted to CMP
- * The SMVP kernel could use GIC interrupts if available
- */
-void cmp_send_ipi_single(int cpu, unsigned int action)
-{
- unsigned long flags;
-
- local_irq_save(flags);
-
- switch (action) {
- case SMP_CALL_FUNCTION:
- ipi_call_function(cpu);
- break;
-
- case SMP_RESCHEDULE_YOURSELF:
- ipi_resched(cpu);
- break;
- }
-
- local_irq_restore(flags);
-}
-
-static void cmp_send_ipi_mask(const struct cpumask *mask, unsigned int action)
-{
- unsigned int i;
-
- for_each_cpu(i, mask)
- cmp_send_ipi_single(i, action);
-}
-
static void cmp_init_secondary(void)
{
- struct cpuinfo_mips *c = &current_cpu_data;
+ struct cpuinfo_mips *c __maybe_unused = &current_cpu_data;
/* Assume GIC is present */
change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP6 |
@@ -97,7 +49,6 @@ static void cmp_init_secondary(void)
/* Enable per-cpu interrupts: platform specific */
- c->core = (read_c0_ebase() >> 1) & 0x1ff;
#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC)
if (cpu_has_mipsmt)
c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) &
@@ -210,8 +161,8 @@ void __init cmp_prepare_cpus(unsigned int max_cpus)
}
struct plat_smp_ops cmp_smp_ops = {
- .send_ipi_single = cmp_send_ipi_single,
- .send_ipi_mask = cmp_send_ipi_mask,
+ .send_ipi_single = gic_send_ipi_single,
+ .send_ipi_mask = gic_send_ipi_mask,
.init_secondary = cmp_init_secondary,
.smp_finish = cmp_smp_finish,
.cpus_done = cmp_cpus_done,
diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c
new file mode 100644
index 000000000000..536eec0d21b6
--- /dev/null
+++ b/arch/mips/kernel/smp-cps.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.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/io.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/types.h>
+
+#include <asm/cacheflush.h>
+#include <asm/gic.h>
+#include <asm/mips-cm.h>
+#include <asm/mips-cpc.h>
+#include <asm/mips_mt.h>
+#include <asm/mipsregs.h>
+#include <asm/smp-cps.h>
+#include <asm/time.h>
+#include <asm/uasm.h>
+
+static DECLARE_BITMAP(core_power, NR_CPUS);
+
+struct boot_config mips_cps_bootcfg;
+
+static void init_core(void)
+{
+ unsigned int nvpes, t;
+ u32 mvpconf0, vpeconf0, vpecontrol, tcstatus, tcbind, status;
+
+ if (!cpu_has_mipsmt)
+ return;
+
+ /* Enter VPE configuration state */
+ dvpe();
+ set_c0_mvpcontrol(MVPCONTROL_VPC);
+
+ /* Retrieve the count of VPEs in this core */
+ mvpconf0 = read_c0_mvpconf0();
+ nvpes = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
+ smp_num_siblings = nvpes;
+
+ for (t = 1; t < nvpes; t++) {
+ /* Use a 1:1 mapping of TC index to VPE index */
+ settc(t);
+
+ /* Bind 1 TC to this VPE */
+ tcbind = read_tc_c0_tcbind();
+ tcbind &= ~TCBIND_CURVPE;
+ tcbind |= t << TCBIND_CURVPE_SHIFT;
+ write_tc_c0_tcbind(tcbind);
+
+ /* Set exclusive TC, non-active, master */
+ vpeconf0 = read_vpe_c0_vpeconf0();
+ vpeconf0 &= ~(VPECONF0_XTC | VPECONF0_VPA);
+ vpeconf0 |= t << VPECONF0_XTC_SHIFT;
+ vpeconf0 |= VPECONF0_MVP;
+ write_vpe_c0_vpeconf0(vpeconf0);
+
+ /* Declare TC non-active, non-allocatable & interrupt exempt */
+ tcstatus = read_tc_c0_tcstatus();
+ tcstatus &= ~(TCSTATUS_A | TCSTATUS_DA);
+ tcstatus |= TCSTATUS_IXMT;
+ write_tc_c0_tcstatus(tcstatus);
+
+ /* Halt the TC */
+ write_tc_c0_tchalt(TCHALT_H);
+
+ /* Allow only 1 TC to execute */
+ vpecontrol = read_vpe_c0_vpecontrol();
+ vpecontrol &= ~VPECONTROL_TE;
+ write_vpe_c0_vpecontrol(vpecontrol);
+
+ /* Copy (most of) Status from VPE 0 */
+ status = read_c0_status();
+ status &= ~(ST0_IM | ST0_IE | ST0_KSU);
+ status |= ST0_CU0;
+ write_vpe_c0_status(status);
+
+ /* Copy Config from VPE 0 */
+ write_vpe_c0_config(read_c0_config());
+ write_vpe_c0_config7(read_c0_config7());
+
+ /* Ensure no software interrupts are pending */
+ write_vpe_c0_cause(0);
+
+ /* Sync Count */
+ write_vpe_c0_count(read_c0_count());
+ }
+
+ /* Leave VPE configuration state */
+ clear_c0_mvpcontrol(MVPCONTROL_VPC);
+}
+
+static void __init cps_smp_setup(void)
+{
+ unsigned int ncores, nvpes, core_vpes;
+ int c, v;
+ u32 core_cfg, *entry_code;
+
+ /* Detect & record VPE topology */
+ ncores = mips_cm_numcores();
+ pr_info("VPE topology ");
+ for (c = nvpes = 0; c < ncores; c++) {
+ if (cpu_has_mipsmt && config_enabled(CONFIG_MIPS_MT_SMP)) {
+ write_gcr_cl_other(c << CM_GCR_Cx_OTHER_CORENUM_SHF);
+ core_cfg = read_gcr_co_config();
+ core_vpes = ((core_cfg & CM_GCR_Cx_CONFIG_PVPE_MSK) >>
+ CM_GCR_Cx_CONFIG_PVPE_SHF) + 1;
+ } else {
+ core_vpes = 1;
+ }
+
+ pr_cont("%c%u", c ? ',' : '{', core_vpes);
+
+ for (v = 0; v < min_t(int, core_vpes, NR_CPUS - nvpes); v++) {
+ cpu_data[nvpes + v].core = c;
+#ifdef CONFIG_MIPS_MT_SMP
+ cpu_data[nvpes + v].vpe_id = v;
+#endif
+ }
+
+ nvpes += core_vpes;
+ }
+ pr_cont("} total %u\n", nvpes);
+
+ /* Indicate present CPUs (CPU being synonymous with VPE) */
+ for (v = 0; v < min_t(unsigned, nvpes, NR_CPUS); v++) {
+ set_cpu_possible(v, true);
+ set_cpu_present(v, true);
+ __cpu_number_map[v] = v;
+ __cpu_logical_map[v] = v;
+ }
+
+ /* Core 0 is powered up (we're running on it) */
+ bitmap_set(core_power, 0, 1);
+
+ /* Disable MT - we only want to run 1 TC per VPE */
+ if (cpu_has_mipsmt)
+ dmt();
+
+ /* Initialise core 0 */
+ init_core();
+
+ /* Patch the start of mips_cps_core_entry to provide the CM base */
+ entry_code = (u32 *)&mips_cps_core_entry;
+ UASM_i_LA(&entry_code, 3, (long)mips_cm_base);
+
+ /* Make core 0 coherent with everything */
+ write_gcr_cl_coherence(0xff);
+}
+
+static void __init cps_prepare_cpus(unsigned int max_cpus)
+{
+ mips_mt_set_cpuoptions();
+}
+
+static void boot_core(struct boot_config *cfg)
+{
+ u32 access;
+
+ /* Select the appropriate core */
+ write_gcr_cl_other(cfg->core << CM_GCR_Cx_OTHER_CORENUM_SHF);
+
+ /* Set its reset vector */
+ write_gcr_co_reset_base(CKSEG1ADDR((unsigned long)mips_cps_core_entry));
+
+ /* Ensure its coherency is disabled */
+ write_gcr_co_coherence(0);
+
+ /* Ensure the core can access the GCRs */
+ access = read_gcr_access();
+ access |= 1 << (CM_GCR_ACCESS_ACCESSEN_SHF + cfg->core);
+ write_gcr_access(access);
+
+ /* Copy cfg */
+ mips_cps_bootcfg = *cfg;
+
+ if (mips_cpc_present()) {
+ /* Select the appropriate core */
+ write_cpc_cl_other(cfg->core << CPC_Cx_OTHER_CORENUM_SHF);
+
+ /* Reset the core */
+ write_cpc_co_cmd(CPC_Cx_CMD_RESET);
+ } else {
+ /* Take the core out of reset */
+ write_gcr_co_reset_release(0);
+ }
+
+ /* The core is now powered up */
+ bitmap_set(core_power, cfg->core, 1);
+}
+
+static void boot_vpe(void *info)
+{
+ struct boot_config *cfg = info;
+ u32 tcstatus, vpeconf0;
+
+ /* Enter VPE configuration state */
+ dvpe();
+ set_c0_mvpcontrol(MVPCONTROL_VPC);
+
+ settc(cfg->vpe);
+
+ /* Set the TC restart PC */
+ write_tc_c0_tcrestart((unsigned long)&smp_bootstrap);
+
+ /* Activate the TC, allow interrupts */
+ tcstatus = read_tc_c0_tcstatus();
+ tcstatus &= ~TCSTATUS_IXMT;
+ tcstatus |= TCSTATUS_A;
+ write_tc_c0_tcstatus(tcstatus);
+
+ /* Clear the TC halt bit */
+ write_tc_c0_tchalt(0);
+
+ /* Activate the VPE */
+ vpeconf0 = read_vpe_c0_vpeconf0();
+ vpeconf0 |= VPECONF0_VPA;
+ write_vpe_c0_vpeconf0(vpeconf0);
+
+ /* Set the stack & global pointer registers */
+ write_tc_gpr_sp(cfg->sp);
+ write_tc_gpr_gp(cfg->gp);
+
+ /* Leave VPE configuration state */
+ clear_c0_mvpcontrol(MVPCONTROL_VPC);
+
+ /* Enable other VPEs to execute */
+ evpe(EVPE_ENABLE);
+}
+
+static void cps_boot_secondary(int cpu, struct task_struct *idle)
+{
+ struct boot_config cfg;
+ unsigned int remote;
+ int err;
+
+ cfg.core = cpu_data[cpu].core;
+ cfg.vpe = cpu_vpe_id(&cpu_data[cpu]);
+ cfg.pc = (unsigned long)&smp_bootstrap;
+ cfg.sp = __KSTK_TOS(idle);
+ cfg.gp = (unsigned long)task_thread_info(idle);
+
+ if (!test_bit(cfg.core, core_power)) {
+ /* Boot a VPE on a powered down core */
+ boot_core(&cfg);
+ return;
+ }
+
+ if (cfg.core != current_cpu_data.core) {
+ /* Boot a VPE on another powered up core */
+ for (remote = 0; remote < NR_CPUS; remote++) {
+ if (cpu_data[remote].core != cfg.core)
+ continue;
+ if (cpu_online(remote))
+ break;
+ }
+ BUG_ON(remote >= NR_CPUS);
+
+ err = smp_call_function_single(remote, boot_vpe, &cfg, 1);
+ if (err)
+ panic("Failed to call remote CPU\n");
+ return;
+ }
+
+ BUG_ON(!cpu_has_mipsmt);
+
+ /* Boot a VPE on this core */
+ boot_vpe(&cfg);
+}
+
+static void cps_init_secondary(void)
+{
+ /* Disable MT - we only want to run 1 TC per VPE */
+ if (cpu_has_mipsmt)
+ dmt();
+
+ /* TODO: revisit this assumption once hotplug is implemented */
+ if (cpu_vpe_id(&current_cpu_data) == 0)
+ init_core();
+
+ change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 |
+ STATUSF_IP6 | STATUSF_IP7);
+}
+
+static void cps_smp_finish(void)
+{
+ write_c0_compare(read_c0_count() + (8 * mips_hpt_frequency / HZ));
+
+#ifdef CONFIG_MIPS_MT_FPAFF
+ /* If we have an FPU, enroll ourselves in the FPU-full mask */
+ if (cpu_has_fpu)
+ cpu_set(smp_processor_id(), mt_fpu_cpumask);
+#endif /* CONFIG_MIPS_MT_FPAFF */
+
+ local_irq_enable();
+}
+
+static void cps_cpus_done(void)
+{
+}
+
+static struct plat_smp_ops cps_smp_ops = {
+ .smp_setup = cps_smp_setup,
+ .prepare_cpus = cps_prepare_cpus,
+ .boot_secondary = cps_boot_secondary,
+ .init_secondary = cps_init_secondary,
+ .smp_finish = cps_smp_finish,
+ .send_ipi_single = gic_send_ipi_single,
+ .send_ipi_mask = gic_send_ipi_mask,
+ .cpus_done = cps_cpus_done,
+};
+
+int register_cps_smp_ops(void)
+{
+ if (!mips_cm_present()) {
+ pr_warn("MIPS CPS SMP unable to proceed without a CM\n");
+ return -ENODEV;
+ }
+
+ /* check we have a GIC - we need one for IPIs */
+ if (!(read_gcr_gic_status() & CM_GCR_GIC_STATUS_EX_MSK)) {
+ pr_warn("MIPS CPS SMP unable to proceed without a GIC\n");
+ return -ENODEV;
+ }
+
+ register_smp_ops(&cps_smp_ops);
+ return 0;
+}
diff --git a/arch/mips/kernel/smp-gic.c b/arch/mips/kernel/smp-gic.c
new file mode 100644
index 000000000000..3bb1f92ab525
--- /dev/null
+++ b/arch/mips/kernel/smp-gic.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * Based on smp-cmp.c:
+ * Copyright (C) 2007 MIPS Technologies, Inc.
+ * Author: Chris Dearman (chris@mips.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/printk.h>
+
+#include <asm/gic.h>
+#include <asm/smp-ops.h>
+
+void gic_send_ipi_single(int cpu, unsigned int action)
+{
+ unsigned long flags;
+ unsigned int intr;
+
+ pr_debug("CPU%d: %s cpu %d action %u status %08x\n",
+ smp_processor_id(), __func__, cpu, action, read_c0_status());
+
+ local_irq_save(flags);
+
+ switch (action) {
+ case SMP_CALL_FUNCTION:
+ intr = plat_ipi_call_int_xlate(cpu);
+ break;
+
+ case SMP_RESCHEDULE_YOURSELF:
+ intr = plat_ipi_resched_int_xlate(cpu);
+ break;
+
+ default:
+ BUG();
+ }
+
+ gic_send_ipi(intr);
+ local_irq_restore(flags);
+}
+
+void gic_send_ipi_mask(const struct cpumask *mask, unsigned int action)
+{
+ unsigned int i;
+
+ for_each_cpu(i, mask)
+ gic_send_ipi_single(i, action);
+}
diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c
index 0fb8cefc9114..f8e13149604d 100644
--- a/arch/mips/kernel/smp-mt.c
+++ b/arch/mips/kernel/smp-mt.c
@@ -113,27 +113,6 @@ static void __init smvp_tc_init(unsigned int tc, unsigned int mvpconf0)
write_tc_c0_tchalt(TCHALT_H);
}
-#ifdef CONFIG_IRQ_GIC
-static void mp_send_ipi_single(int cpu, unsigned int action)
-{
- unsigned long flags;
-
- local_irq_save(flags);
-
- switch (action) {
- case SMP_CALL_FUNCTION:
- gic_send_ipi(plat_ipi_call_int_xlate(cpu));
- break;
-
- case SMP_RESCHEDULE_YOURSELF:
- gic_send_ipi(plat_ipi_resched_int_xlate(cpu));
- break;
- }
-
- local_irq_restore(flags);
-}
-#endif
-
static void vsmp_send_ipi_single(int cpu, unsigned int action)
{
int i;
@@ -142,7 +121,7 @@ static void vsmp_send_ipi_single(int cpu, unsigned int action)
#ifdef CONFIG_IRQ_GIC
if (gic_present) {
- mp_send_ipi_single(cpu, action);
+ gic_send_ipi_single(cpu, action);
return;
}
#endif
@@ -313,3 +292,25 @@ struct plat_smp_ops vsmp_smp_ops = {
.smp_setup = vsmp_smp_setup,
.prepare_cpus = vsmp_prepare_cpus,
};
+
+static int proc_cpuinfo_chain_call(struct notifier_block *nfb,
+ unsigned long action_unused, void *data)
+{
+ struct proc_cpuinfo_notifier_args *pcn = data;
+ struct seq_file *m = pcn->m;
+ unsigned long n = pcn->n;
+
+ if (!cpu_has_mipsmt)
+ return NOTIFY_OK;
+
+ seq_printf(m, "VPE\t\t\t: %d\n", cpu_data[n].vpe_id);
+
+ return NOTIFY_OK;
+}
+
+static int __init proc_cpuinfo_notifier_init(void)
+{
+ return proc_cpuinfo_notifier(proc_cpuinfo_chain_call, 0);
+}
+
+subsys_initcall(proc_cpuinfo_notifier_init);
diff --git a/arch/mips/kernel/smtc-proc.c b/arch/mips/kernel/smtc-proc.c
index c10aa84c9fa9..38635a996cbf 100644
--- a/arch/mips/kernel/smtc-proc.c
+++ b/arch/mips/kernel/smtc-proc.c
@@ -77,3 +77,26 @@ void init_smtc_stats(void)
proc_create("smtc", 0444, NULL, &smtc_proc_fops);
}
+
+static int proc_cpuinfo_chain_call(struct notifier_block *nfb,
+ unsigned long action_unused, void *data)
+{
+ struct proc_cpuinfo_notifier_args *pcn = data;
+ struct seq_file *m = pcn->m;
+ unsigned long n = pcn->n;
+
+ if (!cpu_has_mipsmt)
+ return NOTIFY_OK;
+
+ seq_printf(m, "VPE\t\t\t: %d\n", cpu_data[n].vpe_id);
+ seq_printf(m, "TC\t\t\t: %d\n", cpu_data[n].tc_id);
+
+ return NOTIFY_OK;
+}
+
+static int __init proc_cpuinfo_notifier_init(void)
+{
+ return proc_cpuinfo_notifier(proc_cpuinfo_chain_call, 0);
+}
+
+subsys_initcall(proc_cpuinfo_notifier_init);
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index dfc1b911be04..c1681d65dd5c 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -1007,7 +1007,7 @@ static void __irq_entry smtc_clock_tick_interrupt(void)
int irq = MIPS_CPU_IRQ_BASE + 1;
irq_enter();
- kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+ kstat_incr_irq_this_cpu(irq);
cd = &per_cpu(mips_clockevent_device, cpu);
cd->event_handler(cd);
irq_exit();
diff --git a/arch/mips/kernel/spram.c b/arch/mips/kernel/spram.c
index b242e2c10ea0..67f2495def1c 100644
--- a/arch/mips/kernel/spram.c
+++ b/arch/mips/kernel/spram.c
@@ -197,16 +197,17 @@ static void probe_spram(char *type,
}
void spram_config(void)
{
- struct cpuinfo_mips *c = &current_cpu_data;
unsigned int config0;
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_24K:
case CPU_34K:
case CPU_74K:
case CPU_1004K:
+ case CPU_1074K:
case CPU_INTERAPTIV:
case CPU_PROAPTIV:
+ case CPU_P5600:
config0 = read_c0_config();
/* FIXME: addresses are Malta specific */
if (config0 & (1<<24)) {
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index b79d13f95bf0..4a4f9dda5658 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -110,7 +110,7 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new)
if (cpu_has_llsc && R10000_LLSC_WAR) {
__asm__ __volatile__ (
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" li %[err], 0 \n"
"1: ll %[old], (%[addr]) \n"
" move %[tmp], %[new] \n"
@@ -135,7 +135,7 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new)
: "memory");
} else if (cpu_has_llsc) {
__asm__ __volatile__ (
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" li %[err], 0 \n"
"1: ll %[old], (%[addr]) \n"
" move %[tmp], %[new] \n"
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index e0b499694d18..074e857ced28 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -10,6 +10,7 @@
* Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2002, 2003, 2004, 2005, 2007 Maciej W. Rozycki
* Copyright (C) 2000, 2001, 2012 MIPS Technologies, Inc. All rights reserved.
+ * Copyright (C) 2014, Imagination Technologies Ltd.
*/
#include <linux/bug.h>
#include <linux/compiler.h>
@@ -47,6 +48,7 @@
#include <asm/mipsregs.h>
#include <asm/mipsmtregs.h>
#include <asm/module.h>
+#include <asm/msa.h>
#include <asm/pgtable.h>
#include <asm/ptrace.h>
#include <asm/sections.h>
@@ -77,8 +79,10 @@ extern asmlinkage void handle_ri_rdhwr(void);
extern asmlinkage void handle_cpu(void);
extern asmlinkage void handle_ov(void);
extern asmlinkage void handle_tr(void);
+extern asmlinkage void handle_msa_fpe(void);
extern asmlinkage void handle_fpe(void);
extern asmlinkage void handle_ftlb(void);
+extern asmlinkage void handle_msa(void);
extern asmlinkage void handle_mdmx(void);
extern asmlinkage void handle_watch(void);
extern asmlinkage void handle_mt(void);
@@ -861,6 +865,11 @@ asmlinkage void do_bp(struct pt_regs *regs)
enum ctx_state prev_state;
unsigned long epc;
u16 instr[2];
+ mm_segment_t seg;
+
+ seg = get_fs();
+ if (!user_mode(regs))
+ set_fs(KERNEL_DS);
prev_state = exception_enter();
if (get_isa16_mode(regs->cp0_epc)) {
@@ -870,17 +879,19 @@ asmlinkage void do_bp(struct pt_regs *regs)
if ((__get_user(instr[0], (u16 __user *)msk_isa16_mode(epc)) ||
(__get_user(instr[1], (u16 __user *)msk_isa16_mode(epc + 2)))))
goto out_sigsegv;
- opcode = (instr[0] << 16) | instr[1];
+ opcode = (instr[0] << 16) | instr[1];
} else {
- /* MIPS16e mode */
- if (__get_user(instr[0], (u16 __user *)msk_isa16_mode(epc)))
+ /* MIPS16e mode */
+ if (__get_user(instr[0],
+ (u16 __user *)msk_isa16_mode(epc)))
goto out_sigsegv;
- bcode = (instr[0] >> 6) & 0x3f;
- do_trap_or_bp(regs, bcode, "Break");
- goto out;
+ bcode = (instr[0] >> 6) & 0x3f;
+ do_trap_or_bp(regs, bcode, "Break");
+ goto out;
}
} else {
- if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
+ if (__get_user(opcode,
+ (unsigned int __user *) exception_epc(regs)))
goto out_sigsegv;
}
@@ -918,6 +929,7 @@ asmlinkage void do_bp(struct pt_regs *regs)
do_trap_or_bp(regs, bcode, "Break");
out:
+ set_fs(seg);
exception_exit(prev_state);
return;
@@ -931,8 +943,13 @@ asmlinkage void do_tr(struct pt_regs *regs)
u32 opcode, tcode = 0;
enum ctx_state prev_state;
u16 instr[2];
+ mm_segment_t seg;
unsigned long epc = msk_isa16_mode(exception_epc(regs));
+ seg = get_fs();
+ if (!user_mode(regs))
+ set_fs(get_ds());
+
prev_state = exception_enter();
if (get_isa16_mode(regs->cp0_epc)) {
if (__get_user(instr[0], (u16 __user *)(epc + 0)) ||
@@ -953,6 +970,7 @@ asmlinkage void do_tr(struct pt_regs *regs)
do_trap_or_bp(regs, tcode, "Trap");
out:
+ set_fs(seg);
exception_exit(prev_state);
return;
@@ -1074,6 +1092,76 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action,
return NOTIFY_OK;
}
+static int enable_restore_fp_context(int msa)
+{
+ int err, was_fpu_owner;
+
+ if (!used_math()) {
+ /* First time FP context user. */
+ err = init_fpu();
+ if (msa && !err)
+ enable_msa();
+ if (!err)
+ set_used_math();
+ return err;
+ }
+
+ /*
+ * This task has formerly used the FP context.
+ *
+ * If this thread has no live MSA vector context then we can simply
+ * restore the scalar FP context. If it has live MSA vector context
+ * (that is, it has or may have used MSA since last performing a
+ * function call) then we'll need to restore the vector context. This
+ * applies even if we're currently only executing a scalar FP
+ * instruction. This is because if we were to later execute an MSA
+ * instruction then we'd either have to:
+ *
+ * - Restore the vector context & clobber any registers modified by
+ * scalar FP instructions between now & then.
+ *
+ * or
+ *
+ * - Not restore the vector context & lose the most significant bits
+ * of all vector registers.
+ *
+ * Neither of those options is acceptable. We cannot restore the least
+ * significant bits of the registers now & only restore the most
+ * significant bits later because the most significant bits of any
+ * vector registers whose aliased FP register is modified now will have
+ * been zeroed. We'd have no way to know that when restoring the vector
+ * context & thus may load an outdated value for the most significant
+ * bits of a vector register.
+ */
+ if (!msa && !thread_msa_context_live())
+ return own_fpu(1);
+
+ /*
+ * This task is using or has previously used MSA. Thus we require
+ * that Status.FR == 1.
+ */
+ was_fpu_owner = is_fpu_owner();
+ err = own_fpu(0);
+ if (err)
+ return err;
+
+ enable_msa();
+ write_msa_csr(current->thread.fpu.msacsr);
+ set_thread_flag(TIF_USEDMSA);
+
+ /*
+ * If this is the first time that the task is using MSA and it has
+ * previously used scalar FP in this time slice then we already nave
+ * FP context which we shouldn't clobber.
+ */
+ if (!test_and_set_thread_flag(TIF_MSA_CTX_LIVE) && was_fpu_owner)
+ return 0;
+
+ /* We need to restore the vector context. */
+ restore_msa(current);
+ return 0;
+}
+
asmlinkage void do_cpu(struct pt_regs *regs)
{
enum ctx_state prev_state;
@@ -1153,12 +1241,7 @@ asmlinkage void do_cpu(struct pt_regs *regs)
/* Fall through. */
case 1:
- if (used_math()) /* Using the FPU again. */
- err = own_fpu(1);
- else { /* First time FPU user. */
- err = init_fpu();
- set_used_math();
- }
+ err = enable_restore_fp_context(0);
if (!raw_cpu_has_fpu || err) {
int sig;
@@ -1183,6 +1266,37 @@ out:
exception_exit(prev_state);
}
+asmlinkage void do_msa_fpe(struct pt_regs *regs)
+{
+ enum ctx_state prev_state;
+
+ prev_state = exception_enter();
+ die_if_kernel("do_msa_fpe invoked from kernel context!", regs);
+ force_sig(SIGFPE, current);
+ exception_exit(prev_state);
+}
+
+asmlinkage void do_msa(struct pt_regs *regs)
+{
+ enum ctx_state prev_state;
+ int err;
+
+ prev_state = exception_enter();
+
+ if (!cpu_has_msa || test_thread_flag(TIF_32BIT_FPREGS)) {
+ force_sig(SIGILL, current);
+ goto out;
+ }
+
+ die_if_kernel("do_msa invoked from kernel context!", regs);
+
+ err = enable_restore_fp_context(1);
+ if (err)
+ force_sig(SIGILL, current);
+out:
+ exception_exit(prev_state);
+}
+
asmlinkage void do_mdmx(struct pt_regs *regs)
{
enum ctx_state prev_state;
@@ -1337,8 +1451,10 @@ static inline void parity_protection_init(void)
case CPU_34K:
case CPU_74K:
case CPU_1004K:
+ case CPU_1074K:
case CPU_INTERAPTIV:
case CPU_PROAPTIV:
+ case CPU_P5600:
{
#define ERRCTL_PE 0x80000000
#define ERRCTL_L2P 0x00800000
@@ -2017,6 +2133,7 @@ void __init trap_init(void)
set_except_vector(11, handle_cpu);
set_except_vector(12, handle_ov);
set_except_vector(13, handle_tr);
+ set_except_vector(14, handle_msa_fpe);
if (current_cpu_type() == CPU_R6000 ||
current_cpu_type() == CPU_R6000A) {
@@ -2040,6 +2157,7 @@ void __init trap_init(void)
set_except_vector(15, handle_fpe);
set_except_vector(16, handle_ftlb);
+ set_except_vector(21, handle_msa);
set_except_vector(22, handle_mdmx);
if (cpu_has_mcheck)
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
index c369a5d35527..2b3517214d6d 100644
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -7,6 +7,7 @@
*
* Copyright (C) 1996, 1998, 1999, 2002 by Ralf Baechle
* Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) 2014 Imagination Technologies Ltd.
*
* This file contains exception handler for address error exception with the
* special capability to execute faulting instructions in software. The
@@ -110,8 +111,8 @@ extern void show_registers(struct pt_regs *regs);
#ifdef __BIG_ENDIAN
#define LoadHW(addr, value, res) \
__asm__ __volatile__ (".set\tnoat\n" \
- "1:\tlb\t%0, 0(%2)\n" \
- "2:\tlbu\t$1, 1(%2)\n\t" \
+ "1:\t"user_lb("%0", "0(%2)")"\n" \
+ "2:\t"user_lbu("$1", "1(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
@@ -130,8 +131,8 @@ extern void show_registers(struct pt_regs *regs);
#define LoadW(addr, value, res) \
__asm__ __volatile__ ( \
- "1:\tlwl\t%0, (%2)\n" \
- "2:\tlwr\t%0, 3(%2)\n\t" \
+ "1:\t"user_lwl("%0", "(%2)")"\n" \
+ "2:\t"user_lwr("%0", "3(%2)")"\n\t" \
"li\t%1, 0\n" \
"3:\n\t" \
".insn\n\t" \
@@ -149,8 +150,8 @@ extern void show_registers(struct pt_regs *regs);
#define LoadHWU(addr, value, res) \
__asm__ __volatile__ ( \
".set\tnoat\n" \
- "1:\tlbu\t%0, 0(%2)\n" \
- "2:\tlbu\t$1, 1(%2)\n\t" \
+ "1:\t"user_lbu("%0", "0(%2)")"\n" \
+ "2:\t"user_lbu("$1", "1(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
@@ -170,8 +171,8 @@ extern void show_registers(struct pt_regs *regs);
#define LoadWU(addr, value, res) \
__asm__ __volatile__ ( \
- "1:\tlwl\t%0, (%2)\n" \
- "2:\tlwr\t%0, 3(%2)\n\t" \
+ "1:\t"user_lwl("%0", "(%2)")"\n" \
+ "2:\t"user_lwr("%0", "3(%2)")"\n\t" \
"dsll\t%0, %0, 32\n\t" \
"dsrl\t%0, %0, 32\n\t" \
"li\t%1, 0\n" \
@@ -209,9 +210,9 @@ extern void show_registers(struct pt_regs *regs);
#define StoreHW(addr, value, res) \
__asm__ __volatile__ ( \
".set\tnoat\n" \
- "1:\tsb\t%1, 1(%2)\n\t" \
+ "1:\t"user_sb("%1", "1(%2)")"\n" \
"srl\t$1, %1, 0x8\n" \
- "2:\tsb\t$1, 0(%2)\n\t" \
+ "2:\t"user_sb("$1", "0(%2)")"\n" \
".set\tat\n\t" \
"li\t%0, 0\n" \
"3:\n\t" \
@@ -229,8 +230,8 @@ extern void show_registers(struct pt_regs *regs);
#define StoreW(addr, value, res) \
__asm__ __volatile__ ( \
- "1:\tswl\t%1,(%2)\n" \
- "2:\tswr\t%1, 3(%2)\n\t" \
+ "1:\t"user_swl("%1", "(%2)")"\n" \
+ "2:\t"user_swr("%1", "3(%2)")"\n\t" \
"li\t%0, 0\n" \
"3:\n\t" \
".insn\n\t" \
@@ -267,8 +268,8 @@ extern void show_registers(struct pt_regs *regs);
#ifdef __LITTLE_ENDIAN
#define LoadHW(addr, value, res) \
__asm__ __volatile__ (".set\tnoat\n" \
- "1:\tlb\t%0, 1(%2)\n" \
- "2:\tlbu\t$1, 0(%2)\n\t" \
+ "1:\t"user_lb("%0", "1(%2)")"\n" \
+ "2:\t"user_lbu("$1", "0(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
@@ -287,8 +288,8 @@ extern void show_registers(struct pt_regs *regs);
#define LoadW(addr, value, res) \
__asm__ __volatile__ ( \
- "1:\tlwl\t%0, 3(%2)\n" \
- "2:\tlwr\t%0, (%2)\n\t" \
+ "1:\t"user_lwl("%0", "3(%2)")"\n" \
+ "2:\t"user_lwr("%0", "(%2)")"\n\t" \
"li\t%1, 0\n" \
"3:\n\t" \
".insn\n\t" \
@@ -306,8 +307,8 @@ extern void show_registers(struct pt_regs *regs);
#define LoadHWU(addr, value, res) \
__asm__ __volatile__ ( \
".set\tnoat\n" \
- "1:\tlbu\t%0, 1(%2)\n" \
- "2:\tlbu\t$1, 0(%2)\n\t" \
+ "1:\t"user_lbu("%0", "1(%2)")"\n" \
+ "2:\t"user_lbu("$1", "0(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
@@ -327,8 +328,8 @@ extern void show_registers(struct pt_regs *regs);
#define LoadWU(addr, value, res) \
__asm__ __volatile__ ( \
- "1:\tlwl\t%0, 3(%2)\n" \
- "2:\tlwr\t%0, (%2)\n\t" \
+ "1:\t"user_lwl("%0", "3(%2)")"\n" \
+ "2:\t"user_lwr("%0", "(%2)")"\n\t" \
"dsll\t%0, %0, 32\n\t" \
"dsrl\t%0, %0, 32\n\t" \
"li\t%1, 0\n" \
@@ -366,9 +367,9 @@ extern void show_registers(struct pt_regs *regs);
#define StoreHW(addr, value, res) \
__asm__ __volatile__ ( \
".set\tnoat\n" \
- "1:\tsb\t%1, 0(%2)\n\t" \
+ "1:\t"user_sb("%1", "0(%2)")"\n" \
"srl\t$1,%1, 0x8\n" \
- "2:\tsb\t$1, 1(%2)\n\t" \
+ "2:\t"user_sb("$1", "1(%2)")"\n" \
".set\tat\n\t" \
"li\t%0, 0\n" \
"3:\n\t" \
@@ -386,8 +387,8 @@ extern void show_registers(struct pt_regs *regs);
#define StoreW(addr, value, res) \
__asm__ __volatile__ ( \
- "1:\tswl\t%1, 3(%2)\n" \
- "2:\tswr\t%1, (%2)\n\t" \
+ "1:\t"user_swl("%1", "3(%2)")"\n" \
+ "2:\t"user_swr("%1", "(%2)")"\n\t" \
"li\t%0, 0\n" \
"3:\n\t" \
".insn\n\t" \
@@ -430,7 +431,9 @@ static void emulate_load_store_insn(struct pt_regs *regs,
unsigned long origpc;
unsigned long orig31;
void __user *fault_addr = NULL;
-
+#ifdef CONFIG_EVA
+ mm_segment_t seg;
+#endif
origpc = (unsigned long)pc;
orig31 = regs->regs[31];
@@ -475,6 +478,88 @@ static void emulate_load_store_insn(struct pt_regs *regs,
* The remaining opcodes are the ones that are really of
* interest.
*/
+#ifdef CONFIG_EVA
+ case spec3_op:
+ /*
+ * we can land here only from kernel accessing user memory,
+ * so we need to "switch" the address limit to user space, so
+ * address check can work properly.
+ */
+ seg = get_fs();
+ set_fs(USER_DS);
+ switch (insn.spec3_format.func) {
+ case lhe_op:
+ if (!access_ok(VERIFY_READ, addr, 2)) {
+ set_fs(seg);
+ goto sigbus;
+ }
+ LoadHW(addr, value, res);
+ if (res) {
+ set_fs(seg);
+ goto fault;
+ }
+ compute_return_epc(regs);
+ regs->regs[insn.spec3_format.rt] = value;
+ break;
+ case lwe_op:
+ if (!access_ok(VERIFY_READ, addr, 4)) {
+ set_fs(seg);
+ goto sigbus;
+ }
+ LoadW(addr, value, res);
+ if (res) {
+ set_fs(seg);
+ goto fault;
+ }
+ compute_return_epc(regs);
+ regs->regs[insn.spec3_format.rt] = value;
+ break;
+ case lhue_op:
+ if (!access_ok(VERIFY_READ, addr, 2)) {
+ set_fs(seg);
+ goto sigbus;
+ }
+ LoadHWU(addr, value, res);
+ if (res) {
+ set_fs(seg);
+ goto fault;
+ }
+ compute_return_epc(regs);
+ regs->regs[insn.spec3_format.rt] = value;
+ break;
+ case she_op:
+ if (!access_ok(VERIFY_WRITE, addr, 2)) {
+ set_fs(seg);
+ goto sigbus;
+ }
+ compute_return_epc(regs);
+ value = regs->regs[insn.spec3_format.rt];
+ StoreHW(addr, value, res);
+ if (res) {
+ set_fs(seg);
+ goto fault;
+ }
+ break;
+ case swe_op:
+ if (!access_ok(VERIFY_WRITE, addr, 4)) {
+ set_fs(seg);
+ goto sigbus;
+ }
+ compute_return_epc(regs);
+ value = regs->regs[insn.spec3_format.rt];
+ StoreW(addr, value, res);
+ if (res) {
+ set_fs(seg);
+ goto fault;
+ }
+ break;
+ default:
+ set_fs(seg);
+ goto sigill;
+ }
+ set_fs(seg);
+ break;
+#endif
case lh_op:
if (!access_ok(VERIFY_READ, addr, 2))
goto sigbus;
diff --git a/arch/mips/kvm/kvm_mips_emul.c b/arch/mips/kvm/kvm_mips_emul.c
index 4b6274b47f33..e3fec99941a7 100644
--- a/arch/mips/kvm/kvm_mips_emul.c
+++ b/arch/mips/kvm/kvm_mips_emul.c
@@ -436,13 +436,6 @@ kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc, uint32_t cause,
sel = inst & 0x7;
co_bit = (inst >> 25) & 1;
- /* Verify that the register is valid */
- if (rd > MIPS_CP0_DESAVE) {
- printk("Invalid rd: %d\n", rd);
- er = EMULATE_FAIL;
- goto done;
- }
-
if (co_bit) {
op = (inst) & 0xff;
@@ -1542,8 +1535,15 @@ kvm_mips_handle_ri(unsigned long cause, uint32_t *opc,
}
if ((inst & OPCODE) == SPEC3 && (inst & FUNC) == RDHWR) {
+ int usermode = !KVM_GUEST_KERNEL_MODE(vcpu);
int rd = (inst & RD) >> 11;
int rt = (inst & RT) >> 16;
+ /* If usermode, check RDHWR rd is allowed by guest HWREna */
+ if (usermode && !(kvm_read_c0_guest_hwrena(cop0) & BIT(rd))) {
+ kvm_debug("RDHWR %#x disallowed by HWREna @ %p\n",
+ rd, opc);
+ goto emulate_ri;
+ }
switch (rd) {
case 0: /* CPU number */
arch->gprs[rt] = 0;
@@ -1567,31 +1567,27 @@ kvm_mips_handle_ri(unsigned long cause, uint32_t *opc,
}
break;
case 29:
-#if 1
arch->gprs[rt] = kvm_read_c0_guest_userlocal(cop0);
-#else
- /* UserLocal not implemented */
- er = kvm_mips_emulate_ri_exc(cause, opc, run, vcpu);
-#endif
break;
default:
- printk("RDHWR not supported\n");
- er = EMULATE_FAIL;
- break;
+ kvm_debug("RDHWR %#x not supported @ %p\n", rd, opc);
+ goto emulate_ri;
}
} else {
- printk("Emulate RI not supported @ %p: %#x\n", opc, inst);
- er = EMULATE_FAIL;
+ kvm_debug("Emulate RI not supported @ %p: %#x\n", opc, inst);
+ goto emulate_ri;
}
+ return EMULATE_DONE;
+
+emulate_ri:
/*
- * Rollback PC only if emulation was unsuccessful
+ * Rollback PC (if in branch delay slot then the PC already points to
+ * branch target), and pass the RI exception to the guest OS.
*/
- if (er == EMULATE_FAIL) {
- vcpu->arch.pc = curr_pc;
- }
- return er;
+ vcpu->arch.pc = curr_pc;
+ return kvm_mips_emulate_ri_exc(cause, opc, run, vcpu);
}
enum emulation_result
diff --git a/arch/mips/lasat/picvue_proc.c b/arch/mips/lasat/picvue_proc.c
index 638c5db122c9..2bcd8391bc93 100644
--- a/arch/mips/lasat/picvue_proc.c
+++ b/arch/mips/lasat/picvue_proc.c
@@ -175,7 +175,7 @@ static void pvc_proc_cleanup(void)
remove_proc_entry("scroll", pvc_display_dir);
remove_proc_entry(DISPLAY_DIR_NAME, NULL);
- del_timer(&timer);
+ del_timer_sync(&timer);
}
static int __init pvc_proc_init(void)
diff --git a/arch/mips/lib/csum_partial.S b/arch/mips/lib/csum_partial.S
index a6adffbb4e5f..2e4825e48388 100644
--- a/arch/mips/lib/csum_partial.S
+++ b/arch/mips/lib/csum_partial.S
@@ -8,6 +8,7 @@
* Copyright (C) 1998, 1999 Ralf Baechle
* Copyright (C) 1999 Silicon Graphics, Inc.
* Copyright (C) 2007 Maciej W. Rozycki
+ * Copyright (C) 2014 Imagination Technologies Ltd.
*/
#include <linux/errno.h>
#include <asm/asm.h>
@@ -296,7 +297,7 @@ LEAF(csum_partial)
* checksum and copy routines based on memcpy.S
*
* csum_partial_copy_nocheck(src, dst, len, sum)
- * __csum_partial_copy_user(src, dst, len, sum, errp)
+ * __csum_partial_copy_kernel(src, dst, len, sum, errp)
*
* See "Spec" in memcpy.S for details. Unlike __copy_user, all
* function in this file use the standard calling convention.
@@ -327,20 +328,58 @@ LEAF(csum_partial)
* These handlers do not need to overwrite any data.
*/
-#define EXC(inst_reg,addr,handler) \
-9: inst_reg, addr; \
- .section __ex_table,"a"; \
- PTR 9b, handler; \
- .previous
+/* Instruction type */
+#define LD_INSN 1
+#define ST_INSN 2
+#define LEGACY_MODE 1
+#define EVA_MODE 2
+#define USEROP 1
+#define KERNELOP 2
+
+/*
+ * Wrapper to add an entry in the exception table
+ * in case the insn causes a memory exception.
+ * Arguments:
+ * insn : Load/store instruction
+ * type : Instruction type
+ * reg : Register
+ * addr : Address
+ * handler : Exception handler
+ */
+#define EXC(insn, type, reg, addr, handler) \
+ .if \mode == LEGACY_MODE; \
+9: insn reg, addr; \
+ .section __ex_table,"a"; \
+ PTR 9b, handler; \
+ .previous; \
+ /* This is enabled in EVA mode */ \
+ .else; \
+ /* If loading from user or storing to user */ \
+ .if ((\from == USEROP) && (type == LD_INSN)) || \
+ ((\to == USEROP) && (type == ST_INSN)); \
+9: __BUILD_EVA_INSN(insn##e, reg, addr); \
+ .section __ex_table,"a"; \
+ PTR 9b, handler; \
+ .previous; \
+ .else; \
+ /* EVA without exception */ \
+ insn reg, addr; \
+ .endif; \
+ .endif
+
+#undef LOAD
#ifdef USE_DOUBLE
-#define LOAD ld
-#define LOADL ldl
-#define LOADR ldr
-#define STOREL sdl
-#define STORER sdr
-#define STORE sd
+#define LOADK ld /* No exception */
+#define LOAD(reg, addr, handler) EXC(ld, LD_INSN, reg, addr, handler)
+#define LOADBU(reg, addr, handler) EXC(lbu, LD_INSN, reg, addr, handler)
+#define LOADL(reg, addr, handler) EXC(ldl, LD_INSN, reg, addr, handler)
+#define LOADR(reg, addr, handler) EXC(ldr, LD_INSN, reg, addr, handler)
+#define STOREB(reg, addr, handler) EXC(sb, ST_INSN, reg, addr, handler)
+#define STOREL(reg, addr, handler) EXC(sdl, ST_INSN, reg, addr, handler)
+#define STORER(reg, addr, handler) EXC(sdr, ST_INSN, reg, addr, handler)
+#define STORE(reg, addr, handler) EXC(sd, ST_INSN, reg, addr, handler)
#define ADD daddu
#define SUB dsubu
#define SRL dsrl
@@ -352,12 +391,15 @@ LEAF(csum_partial)
#else
-#define LOAD lw
-#define LOADL lwl
-#define LOADR lwr
-#define STOREL swl
-#define STORER swr
-#define STORE sw
+#define LOADK lw /* No exception */
+#define LOAD(reg, addr, handler) EXC(lw, LD_INSN, reg, addr, handler)
+#define LOADBU(reg, addr, handler) EXC(lbu, LD_INSN, reg, addr, handler)
+#define LOADL(reg, addr, handler) EXC(lwl, LD_INSN, reg, addr, handler)
+#define LOADR(reg, addr, handler) EXC(lwr, LD_INSN, reg, addr, handler)
+#define STOREB(reg, addr, handler) EXC(sb, ST_INSN, reg, addr, handler)
+#define STOREL(reg, addr, handler) EXC(swl, ST_INSN, reg, addr, handler)
+#define STORER(reg, addr, handler) EXC(swr, ST_INSN, reg, addr, handler)
+#define STORE(reg, addr, handler) EXC(sw, ST_INSN, reg, addr, handler)
#define ADD addu
#define SUB subu
#define SRL srl
@@ -396,14 +438,20 @@ LEAF(csum_partial)
.set at=v1
#endif
-LEAF(__csum_partial_copy_user)
+ .macro __BUILD_CSUM_PARTIAL_COPY_USER mode, from, to, __nocheck
+
PTR_ADDU AT, src, len /* See (1) above. */
+ /* initialize __nocheck if this the first time we execute this
+ * macro
+ */
#ifdef CONFIG_64BIT
move errptr, a4
#else
lw errptr, 16(sp)
#endif
-FEXPORT(csum_partial_copy_nocheck)
+ .if \__nocheck == 1
+ FEXPORT(csum_partial_copy_nocheck)
+ .endif
move sum, zero
move odd, zero
/*
@@ -419,48 +467,48 @@ FEXPORT(csum_partial_copy_nocheck)
*/
sltu t2, len, NBYTES
and t1, dst, ADDRMASK
- bnez t2, .Lcopy_bytes_checklen
+ bnez t2, .Lcopy_bytes_checklen\@
and t0, src, ADDRMASK
andi odd, dst, 0x1 /* odd buffer? */
- bnez t1, .Ldst_unaligned
+ bnez t1, .Ldst_unaligned\@
nop
- bnez t0, .Lsrc_unaligned_dst_aligned
+ bnez t0, .Lsrc_unaligned_dst_aligned\@
/*
* use delay slot for fall-through
* src and dst are aligned; need to compute rem
*/
-.Lboth_aligned:
+.Lboth_aligned\@:
SRL t0, len, LOG_NBYTES+3 # +3 for 8 units/iter
- beqz t0, .Lcleanup_both_aligned # len < 8*NBYTES
+ beqz t0, .Lcleanup_both_aligned\@ # len < 8*NBYTES
nop
SUB len, 8*NBYTES # subtract here for bgez loop
.align 4
1:
-EXC( LOAD t0, UNIT(0)(src), .Ll_exc)
-EXC( LOAD t1, UNIT(1)(src), .Ll_exc_copy)
-EXC( LOAD t2, UNIT(2)(src), .Ll_exc_copy)
-EXC( LOAD t3, UNIT(3)(src), .Ll_exc_copy)
-EXC( LOAD t4, UNIT(4)(src), .Ll_exc_copy)
-EXC( LOAD t5, UNIT(5)(src), .Ll_exc_copy)
-EXC( LOAD t6, UNIT(6)(src), .Ll_exc_copy)
-EXC( LOAD t7, UNIT(7)(src), .Ll_exc_copy)
+ LOAD(t0, UNIT(0)(src), .Ll_exc\@)
+ LOAD(t1, UNIT(1)(src), .Ll_exc_copy\@)
+ LOAD(t2, UNIT(2)(src), .Ll_exc_copy\@)
+ LOAD(t3, UNIT(3)(src), .Ll_exc_copy\@)
+ LOAD(t4, UNIT(4)(src), .Ll_exc_copy\@)
+ LOAD(t5, UNIT(5)(src), .Ll_exc_copy\@)
+ LOAD(t6, UNIT(6)(src), .Ll_exc_copy\@)
+ LOAD(t7, UNIT(7)(src), .Ll_exc_copy\@)
SUB len, len, 8*NBYTES
ADD src, src, 8*NBYTES
-EXC( STORE t0, UNIT(0)(dst), .Ls_exc)
+ STORE(t0, UNIT(0)(dst), .Ls_exc\@)
ADDC(sum, t0)
-EXC( STORE t1, UNIT(1)(dst), .Ls_exc)
+ STORE(t1, UNIT(1)(dst), .Ls_exc\@)
ADDC(sum, t1)
-EXC( STORE t2, UNIT(2)(dst), .Ls_exc)
+ STORE(t2, UNIT(2)(dst), .Ls_exc\@)
ADDC(sum, t2)
-EXC( STORE t3, UNIT(3)(dst), .Ls_exc)
+ STORE(t3, UNIT(3)(dst), .Ls_exc\@)
ADDC(sum, t3)
-EXC( STORE t4, UNIT(4)(dst), .Ls_exc)
+ STORE(t4, UNIT(4)(dst), .Ls_exc\@)
ADDC(sum, t4)
-EXC( STORE t5, UNIT(5)(dst), .Ls_exc)
+ STORE(t5, UNIT(5)(dst), .Ls_exc\@)
ADDC(sum, t5)
-EXC( STORE t6, UNIT(6)(dst), .Ls_exc)
+ STORE(t6, UNIT(6)(dst), .Ls_exc\@)
ADDC(sum, t6)
-EXC( STORE t7, UNIT(7)(dst), .Ls_exc)
+ STORE(t7, UNIT(7)(dst), .Ls_exc\@)
ADDC(sum, t7)
.set reorder /* DADDI_WAR */
ADD dst, dst, 8*NBYTES
@@ -471,44 +519,44 @@ EXC( STORE t7, UNIT(7)(dst), .Ls_exc)
/*
* len == the number of bytes left to copy < 8*NBYTES
*/
-.Lcleanup_both_aligned:
+.Lcleanup_both_aligned\@:
#define rem t7
- beqz len, .Ldone
+ beqz len, .Ldone\@
sltu t0, len, 4*NBYTES
- bnez t0, .Lless_than_4units
+ bnez t0, .Lless_than_4units\@
and rem, len, (NBYTES-1) # rem = len % NBYTES
/*
* len >= 4*NBYTES
*/
-EXC( LOAD t0, UNIT(0)(src), .Ll_exc)
-EXC( LOAD t1, UNIT(1)(src), .Ll_exc_copy)
-EXC( LOAD t2, UNIT(2)(src), .Ll_exc_copy)
-EXC( LOAD t3, UNIT(3)(src), .Ll_exc_copy)
+ LOAD(t0, UNIT(0)(src), .Ll_exc\@)
+ LOAD(t1, UNIT(1)(src), .Ll_exc_copy\@)
+ LOAD(t2, UNIT(2)(src), .Ll_exc_copy\@)
+ LOAD(t3, UNIT(3)(src), .Ll_exc_copy\@)
SUB len, len, 4*NBYTES
ADD src, src, 4*NBYTES
-EXC( STORE t0, UNIT(0)(dst), .Ls_exc)
+ STORE(t0, UNIT(0)(dst), .Ls_exc\@)
ADDC(sum, t0)
-EXC( STORE t1, UNIT(1)(dst), .Ls_exc)
+ STORE(t1, UNIT(1)(dst), .Ls_exc\@)
ADDC(sum, t1)
-EXC( STORE t2, UNIT(2)(dst), .Ls_exc)
+ STORE(t2, UNIT(2)(dst), .Ls_exc\@)
ADDC(sum, t2)
-EXC( STORE t3, UNIT(3)(dst), .Ls_exc)
+ STORE(t3, UNIT(3)(dst), .Ls_exc\@)
ADDC(sum, t3)
.set reorder /* DADDI_WAR */
ADD dst, dst, 4*NBYTES
- beqz len, .Ldone
+ beqz len, .Ldone\@
.set noreorder
-.Lless_than_4units:
+.Lless_than_4units\@:
/*
* rem = len % NBYTES
*/
- beq rem, len, .Lcopy_bytes
+ beq rem, len, .Lcopy_bytes\@
nop
1:
-EXC( LOAD t0, 0(src), .Ll_exc)
+ LOAD(t0, 0(src), .Ll_exc\@)
ADD src, src, NBYTES
SUB len, len, NBYTES
-EXC( STORE t0, 0(dst), .Ls_exc)
+ STORE(t0, 0(dst), .Ls_exc\@)
ADDC(sum, t0)
.set reorder /* DADDI_WAR */
ADD dst, dst, NBYTES
@@ -527,20 +575,20 @@ EXC( STORE t0, 0(dst), .Ls_exc)
* more instruction-level parallelism.
*/
#define bits t2
- beqz len, .Ldone
+ beqz len, .Ldone\@
ADD t1, dst, len # t1 is just past last byte of dst
li bits, 8*NBYTES
SLL rem, len, 3 # rem = number of bits to keep
-EXC( LOAD t0, 0(src), .Ll_exc)
+ LOAD(t0, 0(src), .Ll_exc\@)
SUB bits, bits, rem # bits = number of bits to discard
SHIFT_DISCARD t0, t0, bits
-EXC( STREST t0, -1(t1), .Ls_exc)
+ STREST(t0, -1(t1), .Ls_exc\@)
SHIFT_DISCARD_REVERT t0, t0, bits
.set reorder
ADDC(sum, t0)
- b .Ldone
+ b .Ldone\@
.set noreorder
-.Ldst_unaligned:
+.Ldst_unaligned\@:
/*
* dst is unaligned
* t0 = src & ADDRMASK
@@ -551,25 +599,25 @@ EXC( STREST t0, -1(t1), .Ls_exc)
* Set match = (src and dst have same alignment)
*/
#define match rem
-EXC( LDFIRST t3, FIRST(0)(src), .Ll_exc)
+ LDFIRST(t3, FIRST(0)(src), .Ll_exc\@)
ADD t2, zero, NBYTES
-EXC( LDREST t3, REST(0)(src), .Ll_exc_copy)
+ LDREST(t3, REST(0)(src), .Ll_exc_copy\@)
SUB t2, t2, t1 # t2 = number of bytes copied
xor match, t0, t1
-EXC( STFIRST t3, FIRST(0)(dst), .Ls_exc)
+ STFIRST(t3, FIRST(0)(dst), .Ls_exc\@)
SLL t4, t1, 3 # t4 = number of bits to discard
SHIFT_DISCARD t3, t3, t4
/* no SHIFT_DISCARD_REVERT to handle odd buffer properly */
ADDC(sum, t3)
- beq len, t2, .Ldone
+ beq len, t2, .Ldone\@
SUB len, len, t2
ADD dst, dst, t2
- beqz match, .Lboth_aligned
+ beqz match, .Lboth_aligned\@
ADD src, src, t2
-.Lsrc_unaligned_dst_aligned:
+.Lsrc_unaligned_dst_aligned\@:
SRL t0, len, LOG_NBYTES+2 # +2 for 4 units/iter
- beqz t0, .Lcleanup_src_unaligned
+ beqz t0, .Lcleanup_src_unaligned\@
and rem, len, (4*NBYTES-1) # rem = len % 4*NBYTES
1:
/*
@@ -578,53 +626,53 @@ EXC( STFIRST t3, FIRST(0)(dst), .Ls_exc)
* It's OK to load FIRST(N+1) before REST(N) because the two addresses
* are to the same unit (unless src is aligned, but it's not).
*/
-EXC( LDFIRST t0, FIRST(0)(src), .Ll_exc)
-EXC( LDFIRST t1, FIRST(1)(src), .Ll_exc_copy)
+ LDFIRST(t0, FIRST(0)(src), .Ll_exc\@)
+ LDFIRST(t1, FIRST(1)(src), .Ll_exc_copy\@)
SUB len, len, 4*NBYTES
-EXC( LDREST t0, REST(0)(src), .Ll_exc_copy)
-EXC( LDREST t1, REST(1)(src), .Ll_exc_copy)
-EXC( LDFIRST t2, FIRST(2)(src), .Ll_exc_copy)
-EXC( LDFIRST t3, FIRST(3)(src), .Ll_exc_copy)
-EXC( LDREST t2, REST(2)(src), .Ll_exc_copy)
-EXC( LDREST t3, REST(3)(src), .Ll_exc_copy)
+ LDREST(t0, REST(0)(src), .Ll_exc_copy\@)
+ LDREST(t1, REST(1)(src), .Ll_exc_copy\@)
+ LDFIRST(t2, FIRST(2)(src), .Ll_exc_copy\@)
+ LDFIRST(t3, FIRST(3)(src), .Ll_exc_copy\@)
+ LDREST(t2, REST(2)(src), .Ll_exc_copy\@)
+ LDREST(t3, REST(3)(src), .Ll_exc_copy\@)
ADD src, src, 4*NBYTES
#ifdef CONFIG_CPU_SB1
nop # improves slotting
#endif
-EXC( STORE t0, UNIT(0)(dst), .Ls_exc)
+ STORE(t0, UNIT(0)(dst), .Ls_exc\@)
ADDC(sum, t0)
-EXC( STORE t1, UNIT(1)(dst), .Ls_exc)
+ STORE(t1, UNIT(1)(dst), .Ls_exc\@)
ADDC(sum, t1)
-EXC( STORE t2, UNIT(2)(dst), .Ls_exc)
+ STORE(t2, UNIT(2)(dst), .Ls_exc\@)
ADDC(sum, t2)
-EXC( STORE t3, UNIT(3)(dst), .Ls_exc)
+ STORE(t3, UNIT(3)(dst), .Ls_exc\@)
ADDC(sum, t3)
.set reorder /* DADDI_WAR */
ADD dst, dst, 4*NBYTES
bne len, rem, 1b
.set noreorder
-.Lcleanup_src_unaligned:
- beqz len, .Ldone
+.Lcleanup_src_unaligned\@:
+ beqz len, .Ldone\@
and rem, len, NBYTES-1 # rem = len % NBYTES
- beq rem, len, .Lcopy_bytes
+ beq rem, len, .Lcopy_bytes\@
nop
1:
-EXC( LDFIRST t0, FIRST(0)(src), .Ll_exc)
-EXC( LDREST t0, REST(0)(src), .Ll_exc_copy)
+ LDFIRST(t0, FIRST(0)(src), .Ll_exc\@)
+ LDREST(t0, REST(0)(src), .Ll_exc_copy\@)
ADD src, src, NBYTES
SUB len, len, NBYTES
-EXC( STORE t0, 0(dst), .Ls_exc)
+ STORE(t0, 0(dst), .Ls_exc\@)
ADDC(sum, t0)
.set reorder /* DADDI_WAR */
ADD dst, dst, NBYTES
bne len, rem, 1b
.set noreorder
-.Lcopy_bytes_checklen:
- beqz len, .Ldone
+.Lcopy_bytes_checklen\@:
+ beqz len, .Ldone\@
nop
-.Lcopy_bytes:
+.Lcopy_bytes\@:
/* 0 < len < NBYTES */
#ifdef CONFIG_CPU_LITTLE_ENDIAN
#define SHIFT_START 0
@@ -637,12 +685,12 @@ EXC( STORE t0, 0(dst), .Ls_exc)
li t3, SHIFT_START # shift
/* use .Ll_exc_copy here to return correct sum on fault */
#define COPY_BYTE(N) \
-EXC( lbu t0, N(src), .Ll_exc_copy); \
+ LOADBU(t0, N(src), .Ll_exc_copy\@); \
SUB len, len, 1; \
-EXC( sb t0, N(dst), .Ls_exc); \
+ STOREB(t0, N(dst), .Ls_exc\@); \
SLLV t0, t0, t3; \
addu t3, SHIFT_INC; \
- beqz len, .Lcopy_bytes_done; \
+ beqz len, .Lcopy_bytes_done\@; \
or t2, t0
COPY_BYTE(0)
@@ -653,14 +701,14 @@ EXC( sb t0, N(dst), .Ls_exc); \
COPY_BYTE(4)
COPY_BYTE(5)
#endif
-EXC( lbu t0, NBYTES-2(src), .Ll_exc_copy)
+ LOADBU(t0, NBYTES-2(src), .Ll_exc_copy\@)
SUB len, len, 1
-EXC( sb t0, NBYTES-2(dst), .Ls_exc)
+ STOREB(t0, NBYTES-2(dst), .Ls_exc\@)
SLLV t0, t0, t3
or t2, t0
-.Lcopy_bytes_done:
+.Lcopy_bytes_done\@:
ADDC(sum, t2)
-.Ldone:
+.Ldone\@:
/* fold checksum */
#ifdef USE_DOUBLE
dsll32 v1, sum, 0
@@ -689,7 +737,7 @@ EXC( sb t0, NBYTES-2(dst), .Ls_exc)
jr ra
.set noreorder
-.Ll_exc_copy:
+.Ll_exc_copy\@:
/*
* Copy bytes from src until faulting load address (or until a
* lb faults)
@@ -700,11 +748,11 @@ EXC( sb t0, NBYTES-2(dst), .Ls_exc)
*
* Assumes src < THREAD_BUADDR($28)
*/
- LOAD t0, TI_TASK($28)
+ LOADK t0, TI_TASK($28)
li t2, SHIFT_START
- LOAD t0, THREAD_BUADDR(t0)
+ LOADK t0, THREAD_BUADDR(t0)
1:
-EXC( lbu t1, 0(src), .Ll_exc)
+ LOADBU(t1, 0(src), .Ll_exc\@)
ADD src, src, 1
sb t1, 0(dst) # can't fault -- we're copy_from_user
SLLV t1, t1, t2
@@ -714,10 +762,10 @@ EXC( lbu t1, 0(src), .Ll_exc)
ADD dst, dst, 1
bne src, t0, 1b
.set noreorder
-.Ll_exc:
- LOAD t0, TI_TASK($28)
+.Ll_exc\@:
+ LOADK t0, TI_TASK($28)
nop
- LOAD t0, THREAD_BUADDR(t0) # t0 is just past last good address
+ LOADK t0, THREAD_BUADDR(t0) # t0 is just past last good address
nop
SUB len, AT, t0 # len number of uncopied bytes
/*
@@ -733,7 +781,7 @@ EXC( lbu t1, 0(src), .Ll_exc)
*/
.set reorder /* DADDI_WAR */
SUB src, len, 1
- beqz len, .Ldone
+ beqz len, .Ldone\@
.set noreorder
1: sb zero, 0(dst)
ADD dst, dst, 1
@@ -748,13 +796,31 @@ EXC( lbu t1, 0(src), .Ll_exc)
SUB src, src, v1
#endif
li v1, -EFAULT
- b .Ldone
+ b .Ldone\@
sw v1, (errptr)
-.Ls_exc:
+.Ls_exc\@:
li v0, -1 /* invalid checksum */
li v1, -EFAULT
jr ra
sw v1, (errptr)
.set pop
- END(__csum_partial_copy_user)
+ .endm
+
+LEAF(__csum_partial_copy_kernel)
+#ifndef CONFIG_EVA
+FEXPORT(__csum_partial_copy_to_user)
+FEXPORT(__csum_partial_copy_from_user)
+#endif
+__BUILD_CSUM_PARTIAL_COPY_USER LEGACY_MODE USEROP USEROP 1
+END(__csum_partial_copy_kernel)
+
+#ifdef CONFIG_EVA
+LEAF(__csum_partial_copy_to_user)
+__BUILD_CSUM_PARTIAL_COPY_USER EVA_MODE KERNELOP USEROP 0
+END(__csum_partial_copy_to_user)
+
+LEAF(__csum_partial_copy_from_user)
+__BUILD_CSUM_PARTIAL_COPY_USER EVA_MODE USEROP KERNELOP 0
+END(__csum_partial_copy_from_user)
+#endif
diff --git a/arch/mips/lib/memcpy.S b/arch/mips/lib/memcpy.S
index c5c40dad0bbf..c17ef80cf65a 100644
--- a/arch/mips/lib/memcpy.S
+++ b/arch/mips/lib/memcpy.S
@@ -10,6 +10,7 @@
* Copyright (C) 2002 Broadcom, Inc.
* memcpy/copy_user author: Mark Vandevoorde
* Copyright (C) 2007 Maciej W. Rozycki
+ * Copyright (C) 2014 Imagination Technologies Ltd.
*
* Mnemonic names for arguments to memcpy/__copy_user
*/
@@ -85,11 +86,51 @@
* they're not protected.
*/
-#define EXC(inst_reg,addr,handler) \
-9: inst_reg, addr; \
- .section __ex_table,"a"; \
- PTR 9b, handler; \
- .previous
+/* Instruction type */
+#define LD_INSN 1
+#define ST_INSN 2
+/* Pretech type */
+#define SRC_PREFETCH 1
+#define DST_PREFETCH 2
+#define LEGACY_MODE 1
+#define EVA_MODE 2
+#define USEROP 1
+#define KERNELOP 2
+
+/*
+ * Wrapper to add an entry in the exception table
+ * in case the insn causes a memory exception.
+ * Arguments:
+ * insn : Load/store instruction
+ * type : Instruction type
+ * reg : Register
+ * addr : Address
+ * handler : Exception handler
+ */
+
+#define EXC(insn, type, reg, addr, handler) \
+ .if \mode == LEGACY_MODE; \
+9: insn reg, addr; \
+ .section __ex_table,"a"; \
+ PTR 9b, handler; \
+ .previous; \
+ /* This is assembled in EVA mode */ \
+ .else; \
+ /* If loading from user or storing to user */ \
+ .if ((\from == USEROP) && (type == LD_INSN)) || \
+ ((\to == USEROP) && (type == ST_INSN)); \
+9: __BUILD_EVA_INSN(insn##e, reg, addr); \
+ .section __ex_table,"a"; \
+ PTR 9b, handler; \
+ .previous; \
+ .else; \
+ /* \
+ * Still in EVA, but no need for \
+ * exception handler or EVA insn \
+ */ \
+ insn reg, addr; \
+ .endif; \
+ .endif
/*
* Only on the 64-bit kernel we can made use of 64-bit registers.
@@ -100,12 +141,13 @@
#ifdef USE_DOUBLE
-#define LOAD ld
-#define LOADL ldl
-#define LOADR ldr
-#define STOREL sdl
-#define STORER sdr
-#define STORE sd
+#define LOADK ld /* No exception */
+#define LOAD(reg, addr, handler) EXC(ld, LD_INSN, reg, addr, handler)
+#define LOADL(reg, addr, handler) EXC(ldl, LD_INSN, reg, addr, handler)
+#define LOADR(reg, addr, handler) EXC(ldr, LD_INSN, reg, addr, handler)
+#define STOREL(reg, addr, handler) EXC(sdl, ST_INSN, reg, addr, handler)
+#define STORER(reg, addr, handler) EXC(sdr, ST_INSN, reg, addr, handler)
+#define STORE(reg, addr, handler) EXC(sd, ST_INSN, reg, addr, handler)
#define ADD daddu
#define SUB dsubu
#define SRL dsrl
@@ -136,12 +178,13 @@
#else
-#define LOAD lw
-#define LOADL lwl
-#define LOADR lwr
-#define STOREL swl
-#define STORER swr
-#define STORE sw
+#define LOADK lw /* No exception */
+#define LOAD(reg, addr, handler) EXC(lw, LD_INSN, reg, addr, handler)
+#define LOADL(reg, addr, handler) EXC(lwl, LD_INSN, reg, addr, handler)
+#define LOADR(reg, addr, handler) EXC(lwr, LD_INSN, reg, addr, handler)
+#define STOREL(reg, addr, handler) EXC(swl, ST_INSN, reg, addr, handler)
+#define STORER(reg, addr, handler) EXC(swr, ST_INSN, reg, addr, handler)
+#define STORE(reg, addr, handler) EXC(sw, ST_INSN, reg, addr, handler)
#define ADD addu
#define SUB subu
#define SRL srl
@@ -154,6 +197,33 @@
#endif /* USE_DOUBLE */
+#define LOADB(reg, addr, handler) EXC(lb, LD_INSN, reg, addr, handler)
+#define STOREB(reg, addr, handler) EXC(sb, ST_INSN, reg, addr, handler)
+
+#define _PREF(hint, addr, type) \
+ .if \mode == LEGACY_MODE; \
+ PREF(hint, addr); \
+ .else; \
+ .if ((\from == USEROP) && (type == SRC_PREFETCH)) || \
+ ((\to == USEROP) && (type == DST_PREFETCH)); \
+ /* \
+ * PREFE has only 9 bits for the offset \
+ * compared to PREF which has 16, so it may \
+ * need to use the $at register but this \
+ * register should remain intact because it's \
+ * used later on. Therefore use $v1. \
+ */ \
+ .set at=v1; \
+ PREFE(hint, addr); \
+ .set noat; \
+ .else; \
+ PREF(hint, addr); \
+ .endif; \
+ .endif
+
+#define PREFS(hint, addr) _PREF(hint, addr, SRC_PREFETCH)
+#define PREFD(hint, addr) _PREF(hint, addr, DST_PREFETCH)
+
#ifdef CONFIG_CPU_LITTLE_ENDIAN
#define LDFIRST LOADR
#define LDREST LOADL
@@ -182,27 +252,23 @@
.set at=v1
#endif
-/*
- * t6 is used as a flag to note inatomic mode.
- */
-LEAF(__copy_user_inatomic)
- b __copy_user_common
- li t6, 1
- END(__copy_user_inatomic)
-
-/*
- * A combined memcpy/__copy_user
- * __copy_user sets len to 0 for success; else to an upper bound of
- * the number of uncopied bytes.
- * memcpy sets v0 to dst.
- */
.align 5
-LEAF(memcpy) /* a0=dst a1=src a2=len */
- move v0, dst /* return value */
-.L__memcpy:
-FEXPORT(__copy_user)
- li t6, 0 /* not inatomic */
-__copy_user_common:
+
+ /*
+ * Macro to build the __copy_user common code
+ * Arguements:
+ * mode : LEGACY_MODE or EVA_MODE
+ * from : Source operand. USEROP or KERNELOP
+ * to : Destination operand. USEROP or KERNELOP
+ */
+ .macro __BUILD_COPY_USER mode, from, to
+
+ /* initialize __memcpy if this the first time we execute this macro */
+ .ifnotdef __memcpy
+ .set __memcpy, 1
+ .hidden __memcpy /* make sure it does not leak */
+ .endif
+
/*
* Note: dst & src may be unaligned, len may be 0
* Temps
@@ -217,94 +283,94 @@ __copy_user_common:
*
* If len < NBYTES use byte operations.
*/
- PREF( 0, 0(src) )
- PREF( 1, 0(dst) )
+ PREFS( 0, 0(src) )
+ PREFD( 1, 0(dst) )
sltu t2, len, NBYTES
and t1, dst, ADDRMASK
- PREF( 0, 1*32(src) )
- PREF( 1, 1*32(dst) )
- bnez t2, .Lcopy_bytes_checklen
+ PREFS( 0, 1*32(src) )
+ PREFD( 1, 1*32(dst) )
+ bnez t2, .Lcopy_bytes_checklen\@
and t0, src, ADDRMASK
- PREF( 0, 2*32(src) )
- PREF( 1, 2*32(dst) )
- bnez t1, .Ldst_unaligned
+ PREFS( 0, 2*32(src) )
+ PREFD( 1, 2*32(dst) )
+ bnez t1, .Ldst_unaligned\@
nop
- bnez t0, .Lsrc_unaligned_dst_aligned
+ bnez t0, .Lsrc_unaligned_dst_aligned\@
/*
* use delay slot for fall-through
* src and dst are aligned; need to compute rem
*/
-.Lboth_aligned:
+.Lboth_aligned\@:
SRL t0, len, LOG_NBYTES+3 # +3 for 8 units/iter
- beqz t0, .Lcleanup_both_aligned # len < 8*NBYTES
+ beqz t0, .Lcleanup_both_aligned\@ # len < 8*NBYTES
and rem, len, (8*NBYTES-1) # rem = len % (8*NBYTES)
- PREF( 0, 3*32(src) )
- PREF( 1, 3*32(dst) )
+ PREFS( 0, 3*32(src) )
+ PREFD( 1, 3*32(dst) )
.align 4
1:
R10KCBARRIER(0(ra))
-EXC( LOAD t0, UNIT(0)(src), .Ll_exc)
-EXC( LOAD t1, UNIT(1)(src), .Ll_exc_copy)
-EXC( LOAD t2, UNIT(2)(src), .Ll_exc_copy)
-EXC( LOAD t3, UNIT(3)(src), .Ll_exc_copy)
+ LOAD(t0, UNIT(0)(src), .Ll_exc\@)
+ LOAD(t1, UNIT(1)(src), .Ll_exc_copy\@)
+ LOAD(t2, UNIT(2)(src), .Ll_exc_copy\@)
+ LOAD(t3, UNIT(3)(src), .Ll_exc_copy\@)
SUB len, len, 8*NBYTES
-EXC( LOAD t4, UNIT(4)(src), .Ll_exc_copy)
-EXC( LOAD t7, UNIT(5)(src), .Ll_exc_copy)
-EXC( STORE t0, UNIT(0)(dst), .Ls_exc_p8u)
-EXC( STORE t1, UNIT(1)(dst), .Ls_exc_p7u)
-EXC( LOAD t0, UNIT(6)(src), .Ll_exc_copy)
-EXC( LOAD t1, UNIT(7)(src), .Ll_exc_copy)
+ LOAD(t4, UNIT(4)(src), .Ll_exc_copy\@)
+ LOAD(t7, UNIT(5)(src), .Ll_exc_copy\@)
+ STORE(t0, UNIT(0)(dst), .Ls_exc_p8u\@)
+ STORE(t1, UNIT(1)(dst), .Ls_exc_p7u\@)
+ LOAD(t0, UNIT(6)(src), .Ll_exc_copy\@)
+ LOAD(t1, UNIT(7)(src), .Ll_exc_copy\@)
ADD src, src, 8*NBYTES
ADD dst, dst, 8*NBYTES
-EXC( STORE t2, UNIT(-6)(dst), .Ls_exc_p6u)
-EXC( STORE t3, UNIT(-5)(dst), .Ls_exc_p5u)
-EXC( STORE t4, UNIT(-4)(dst), .Ls_exc_p4u)
-EXC( STORE t7, UNIT(-3)(dst), .Ls_exc_p3u)
-EXC( STORE t0, UNIT(-2)(dst), .Ls_exc_p2u)
-EXC( STORE t1, UNIT(-1)(dst), .Ls_exc_p1u)
- PREF( 0, 8*32(src) )
- PREF( 1, 8*32(dst) )
+ STORE(t2, UNIT(-6)(dst), .Ls_exc_p6u\@)
+ STORE(t3, UNIT(-5)(dst), .Ls_exc_p5u\@)
+ STORE(t4, UNIT(-4)(dst), .Ls_exc_p4u\@)
+ STORE(t7, UNIT(-3)(dst), .Ls_exc_p3u\@)
+ STORE(t0, UNIT(-2)(dst), .Ls_exc_p2u\@)
+ STORE(t1, UNIT(-1)(dst), .Ls_exc_p1u\@)
+ PREFS( 0, 8*32(src) )
+ PREFD( 1, 8*32(dst) )
bne len, rem, 1b
nop
/*
* len == rem == the number of bytes left to copy < 8*NBYTES
*/
-.Lcleanup_both_aligned:
- beqz len, .Ldone
+.Lcleanup_both_aligned\@:
+ beqz len, .Ldone\@
sltu t0, len, 4*NBYTES
- bnez t0, .Lless_than_4units
+ bnez t0, .Lless_than_4units\@
and rem, len, (NBYTES-1) # rem = len % NBYTES
/*
* len >= 4*NBYTES
*/
-EXC( LOAD t0, UNIT(0)(src), .Ll_exc)
-EXC( LOAD t1, UNIT(1)(src), .Ll_exc_copy)
-EXC( LOAD t2, UNIT(2)(src), .Ll_exc_copy)
-EXC( LOAD t3, UNIT(3)(src), .Ll_exc_copy)
+ LOAD( t0, UNIT(0)(src), .Ll_exc\@)
+ LOAD( t1, UNIT(1)(src), .Ll_exc_copy\@)
+ LOAD( t2, UNIT(2)(src), .Ll_exc_copy\@)
+ LOAD( t3, UNIT(3)(src), .Ll_exc_copy\@)
SUB len, len, 4*NBYTES
ADD src, src, 4*NBYTES
R10KCBARRIER(0(ra))
-EXC( STORE t0, UNIT(0)(dst), .Ls_exc_p4u)
-EXC( STORE t1, UNIT(1)(dst), .Ls_exc_p3u)
-EXC( STORE t2, UNIT(2)(dst), .Ls_exc_p2u)
-EXC( STORE t3, UNIT(3)(dst), .Ls_exc_p1u)
+ STORE(t0, UNIT(0)(dst), .Ls_exc_p4u\@)
+ STORE(t1, UNIT(1)(dst), .Ls_exc_p3u\@)
+ STORE(t2, UNIT(2)(dst), .Ls_exc_p2u\@)
+ STORE(t3, UNIT(3)(dst), .Ls_exc_p1u\@)
.set reorder /* DADDI_WAR */
ADD dst, dst, 4*NBYTES
- beqz len, .Ldone
+ beqz len, .Ldone\@
.set noreorder
-.Lless_than_4units:
+.Lless_than_4units\@:
/*
* rem = len % NBYTES
*/
- beq rem, len, .Lcopy_bytes
+ beq rem, len, .Lcopy_bytes\@
nop
1:
R10KCBARRIER(0(ra))
-EXC( LOAD t0, 0(src), .Ll_exc)
+ LOAD(t0, 0(src), .Ll_exc\@)
ADD src, src, NBYTES
SUB len, len, NBYTES
-EXC( STORE t0, 0(dst), .Ls_exc_p1u)
+ STORE(t0, 0(dst), .Ls_exc_p1u\@)
.set reorder /* DADDI_WAR */
ADD dst, dst, NBYTES
bne rem, len, 1b
@@ -322,17 +388,17 @@ EXC( STORE t0, 0(dst), .Ls_exc_p1u)
* more instruction-level parallelism.
*/
#define bits t2
- beqz len, .Ldone
+ beqz len, .Ldone\@
ADD t1, dst, len # t1 is just past last byte of dst
li bits, 8*NBYTES
SLL rem, len, 3 # rem = number of bits to keep
-EXC( LOAD t0, 0(src), .Ll_exc)
+ LOAD(t0, 0(src), .Ll_exc\@)
SUB bits, bits, rem # bits = number of bits to discard
SHIFT_DISCARD t0, t0, bits
-EXC( STREST t0, -1(t1), .Ls_exc)
+ STREST(t0, -1(t1), .Ls_exc\@)
jr ra
move len, zero
-.Ldst_unaligned:
+.Ldst_unaligned\@:
/*
* dst is unaligned
* t0 = src & ADDRMASK
@@ -343,25 +409,25 @@ EXC( STREST t0, -1(t1), .Ls_exc)
* Set match = (src and dst have same alignment)
*/
#define match rem
-EXC( LDFIRST t3, FIRST(0)(src), .Ll_exc)
+ LDFIRST(t3, FIRST(0)(src), .Ll_exc\@)
ADD t2, zero, NBYTES
-EXC( LDREST t3, REST(0)(src), .Ll_exc_copy)
+ LDREST(t3, REST(0)(src), .Ll_exc_copy\@)
SUB t2, t2, t1 # t2 = number of bytes copied
xor match, t0, t1
R10KCBARRIER(0(ra))
-EXC( STFIRST t3, FIRST(0)(dst), .Ls_exc)
- beq len, t2, .Ldone
+ STFIRST(t3, FIRST(0)(dst), .Ls_exc\@)
+ beq len, t2, .Ldone\@
SUB len, len, t2
ADD dst, dst, t2
- beqz match, .Lboth_aligned
+ beqz match, .Lboth_aligned\@
ADD src, src, t2
-.Lsrc_unaligned_dst_aligned:
+.Lsrc_unaligned_dst_aligned\@:
SRL t0, len, LOG_NBYTES+2 # +2 for 4 units/iter
- PREF( 0, 3*32(src) )
- beqz t0, .Lcleanup_src_unaligned
+ PREFS( 0, 3*32(src) )
+ beqz t0, .Lcleanup_src_unaligned\@
and rem, len, (4*NBYTES-1) # rem = len % 4*NBYTES
- PREF( 1, 3*32(dst) )
+ PREFD( 1, 3*32(dst) )
1:
/*
* Avoid consecutive LD*'s to the same register since some mips
@@ -370,58 +436,58 @@ EXC( STFIRST t3, FIRST(0)(dst), .Ls_exc)
* are to the same unit (unless src is aligned, but it's not).
*/
R10KCBARRIER(0(ra))
-EXC( LDFIRST t0, FIRST(0)(src), .Ll_exc)
-EXC( LDFIRST t1, FIRST(1)(src), .Ll_exc_copy)
+ LDFIRST(t0, FIRST(0)(src), .Ll_exc\@)
+ LDFIRST(t1, FIRST(1)(src), .Ll_exc_copy\@)
SUB len, len, 4*NBYTES
-EXC( LDREST t0, REST(0)(src), .Ll_exc_copy)
-EXC( LDREST t1, REST(1)(src), .Ll_exc_copy)
-EXC( LDFIRST t2, FIRST(2)(src), .Ll_exc_copy)
-EXC( LDFIRST t3, FIRST(3)(src), .Ll_exc_copy)
-EXC( LDREST t2, REST(2)(src), .Ll_exc_copy)
-EXC( LDREST t3, REST(3)(src), .Ll_exc_copy)
- PREF( 0, 9*32(src) ) # 0 is PREF_LOAD (not streamed)
+ LDREST(t0, REST(0)(src), .Ll_exc_copy\@)
+ LDREST(t1, REST(1)(src), .Ll_exc_copy\@)
+ LDFIRST(t2, FIRST(2)(src), .Ll_exc_copy\@)
+ LDFIRST(t3, FIRST(3)(src), .Ll_exc_copy\@)
+ LDREST(t2, REST(2)(src), .Ll_exc_copy\@)
+ LDREST(t3, REST(3)(src), .Ll_exc_copy\@)
+ PREFS( 0, 9*32(src) ) # 0 is PREF_LOAD (not streamed)
ADD src, src, 4*NBYTES
#ifdef CONFIG_CPU_SB1
nop # improves slotting
#endif
-EXC( STORE t0, UNIT(0)(dst), .Ls_exc_p4u)
-EXC( STORE t1, UNIT(1)(dst), .Ls_exc_p3u)
-EXC( STORE t2, UNIT(2)(dst), .Ls_exc_p2u)
-EXC( STORE t3, UNIT(3)(dst), .Ls_exc_p1u)
- PREF( 1, 9*32(dst) ) # 1 is PREF_STORE (not streamed)
+ STORE(t0, UNIT(0)(dst), .Ls_exc_p4u\@)
+ STORE(t1, UNIT(1)(dst), .Ls_exc_p3u\@)
+ STORE(t2, UNIT(2)(dst), .Ls_exc_p2u\@)
+ STORE(t3, UNIT(3)(dst), .Ls_exc_p1u\@)
+ PREFD( 1, 9*32(dst) ) # 1 is PREF_STORE (not streamed)
.set reorder /* DADDI_WAR */
ADD dst, dst, 4*NBYTES
bne len, rem, 1b
.set noreorder
-.Lcleanup_src_unaligned:
- beqz len, .Ldone
+.Lcleanup_src_unaligned\@:
+ beqz len, .Ldone\@
and rem, len, NBYTES-1 # rem = len % NBYTES
- beq rem, len, .Lcopy_bytes
+ beq rem, len, .Lcopy_bytes\@
nop
1:
R10KCBARRIER(0(ra))
-EXC( LDFIRST t0, FIRST(0)(src), .Ll_exc)
-EXC( LDREST t0, REST(0)(src), .Ll_exc_copy)
+ LDFIRST(t0, FIRST(0)(src), .Ll_exc\@)
+ LDREST(t0, REST(0)(src), .Ll_exc_copy\@)
ADD src, src, NBYTES
SUB len, len, NBYTES
-EXC( STORE t0, 0(dst), .Ls_exc_p1u)
+ STORE(t0, 0(dst), .Ls_exc_p1u\@)
.set reorder /* DADDI_WAR */
ADD dst, dst, NBYTES
bne len, rem, 1b
.set noreorder
-.Lcopy_bytes_checklen:
- beqz len, .Ldone
+.Lcopy_bytes_checklen\@:
+ beqz len, .Ldone\@
nop
-.Lcopy_bytes:
+.Lcopy_bytes\@:
/* 0 < len < NBYTES */
R10KCBARRIER(0(ra))
#define COPY_BYTE(N) \
-EXC( lb t0, N(src), .Ll_exc); \
+ LOADB(t0, N(src), .Ll_exc\@); \
SUB len, len, 1; \
- beqz len, .Ldone; \
-EXC( sb t0, N(dst), .Ls_exc_p1)
+ beqz len, .Ldone\@; \
+ STOREB(t0, N(dst), .Ls_exc_p1\@)
COPY_BYTE(0)
COPY_BYTE(1)
@@ -431,16 +497,19 @@ EXC( sb t0, N(dst), .Ls_exc_p1)
COPY_BYTE(4)
COPY_BYTE(5)
#endif
-EXC( lb t0, NBYTES-2(src), .Ll_exc)
+ LOADB(t0, NBYTES-2(src), .Ll_exc\@)
SUB len, len, 1
jr ra
-EXC( sb t0, NBYTES-2(dst), .Ls_exc_p1)
-.Ldone:
+ STOREB(t0, NBYTES-2(dst), .Ls_exc_p1\@)
+.Ldone\@:
jr ra
- nop
+ .if __memcpy == 1
END(memcpy)
+ .set __memcpy, 0
+ .hidden __memcpy
+ .endif
-.Ll_exc_copy:
+.Ll_exc_copy\@:
/*
* Copy bytes from src until faulting load address (or until a
* lb faults)
@@ -451,24 +520,24 @@ EXC( sb t0, NBYTES-2(dst), .Ls_exc_p1)
*
* Assumes src < THREAD_BUADDR($28)
*/
- LOAD t0, TI_TASK($28)
+ LOADK t0, TI_TASK($28)
nop
- LOAD t0, THREAD_BUADDR(t0)
+ LOADK t0, THREAD_BUADDR(t0)
1:
-EXC( lb t1, 0(src), .Ll_exc)
+ LOADB(t1, 0(src), .Ll_exc\@)
ADD src, src, 1
sb t1, 0(dst) # can't fault -- we're copy_from_user
.set reorder /* DADDI_WAR */
ADD dst, dst, 1
bne src, t0, 1b
.set noreorder
-.Ll_exc:
- LOAD t0, TI_TASK($28)
+.Ll_exc\@:
+ LOADK t0, TI_TASK($28)
nop
- LOAD t0, THREAD_BUADDR(t0) # t0 is just past last good address
+ LOADK t0, THREAD_BUADDR(t0) # t0 is just past last good address
nop
SUB len, AT, t0 # len number of uncopied bytes
- bnez t6, .Ldone /* Skip the zeroing part if inatomic */
+ bnez t6, .Ldone\@ /* Skip the zeroing part if inatomic */
/*
* Here's where we rely on src and dst being incremented in tandem,
* See (3) above.
@@ -482,7 +551,7 @@ EXC( lb t1, 0(src), .Ll_exc)
*/
.set reorder /* DADDI_WAR */
SUB src, len, 1
- beqz len, .Ldone
+ beqz len, .Ldone\@
.set noreorder
1: sb zero, 0(dst)
ADD dst, dst, 1
@@ -503,7 +572,7 @@ EXC( lb t1, 0(src), .Ll_exc)
#define SEXC(n) \
.set reorder; /* DADDI_WAR */ \
-.Ls_exc_p ## n ## u: \
+.Ls_exc_p ## n ## u\@: \
ADD len, len, n*NBYTES; \
jr ra; \
.set noreorder
@@ -517,14 +586,15 @@ SEXC(3)
SEXC(2)
SEXC(1)
-.Ls_exc_p1:
+.Ls_exc_p1\@:
.set reorder /* DADDI_WAR */
ADD len, len, 1
jr ra
.set noreorder
-.Ls_exc:
+.Ls_exc\@:
jr ra
nop
+ .endm
.align 5
LEAF(memmove)
@@ -575,3 +645,71 @@ LEAF(__rmemcpy) /* a0=dst a1=src a2=len */
jr ra
move a2, zero
END(__rmemcpy)
+
+/*
+ * t6 is used as a flag to note inatomic mode.
+ */
+LEAF(__copy_user_inatomic)
+ b __copy_user_common
+ li t6, 1
+ END(__copy_user_inatomic)
+
+/*
+ * A combined memcpy/__copy_user
+ * __copy_user sets len to 0 for success; else to an upper bound of
+ * the number of uncopied bytes.
+ * memcpy sets v0 to dst.
+ */
+ .align 5
+LEAF(memcpy) /* a0=dst a1=src a2=len */
+ move v0, dst /* return value */
+.L__memcpy:
+FEXPORT(__copy_user)
+ li t6, 0 /* not inatomic */
+__copy_user_common:
+ /* Legacy Mode, user <-> user */
+ __BUILD_COPY_USER LEGACY_MODE USEROP USEROP
+
+#ifdef CONFIG_EVA
+
+/*
+ * For EVA we need distinct symbols for reading and writing to user space.
+ * This is because we need to use specific EVA instructions to perform the
+ * virtual <-> physical translation when a virtual address is actually in user
+ * space
+ */
+
+LEAF(__copy_user_inatomic_eva)
+ b __copy_from_user_common
+ li t6, 1
+ END(__copy_user_inatomic_eva)
+
+/*
+ * __copy_from_user (EVA)
+ */
+
+LEAF(__copy_from_user_eva)
+ li t6, 0 /* not inatomic */
+__copy_from_user_common:
+ __BUILD_COPY_USER EVA_MODE USEROP KERNELOP
+END(__copy_from_user_eva)
+
+
+
+/*
+ * __copy_to_user (EVA)
+ */
+
+LEAF(__copy_to_user_eva)
+__BUILD_COPY_USER EVA_MODE KERNELOP USEROP
+END(__copy_to_user_eva)
+
+/*
+ * __copy_in_user (EVA)
+ */
+
+LEAF(__copy_in_user_eva)
+__BUILD_COPY_USER EVA_MODE USEROP USEROP
+END(__copy_in_user_eva)
+
+#endif
diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S
index 0580194e7402..7b0e5462ca51 100644
--- a/arch/mips/lib/memset.S
+++ b/arch/mips/lib/memset.S
@@ -34,13 +34,27 @@
#define FILLPTRG t0
#endif
+#define LEGACY_MODE 1
+#define EVA_MODE 2
+
+/*
+ * No need to protect it with EVA #ifdefery. The generated block of code
+ * will never be assembled if EVA is not enabled.
+ */
+#define __EVAFY(insn, reg, addr) __BUILD_EVA_INSN(insn##e, reg, addr)
+#define ___BUILD_EVA_INSN(insn, reg, addr) __EVAFY(insn, reg, addr)
+
#define EX(insn,reg,addr,handler) \
-9: insn reg, addr; \
+ .if \mode == LEGACY_MODE; \
+9: insn reg, addr; \
+ .else; \
+9: ___BUILD_EVA_INSN(insn, reg, addr); \
+ .endif; \
.section __ex_table,"a"; \
PTR 9b, handler; \
.previous
- .macro f_fill64 dst, offset, val, fixup
+ .macro f_fill64 dst, offset, val, fixup, mode
EX(LONG_S, \val, (\offset + 0 * STORSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 1 * STORSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 2 * STORSIZE)(\dst), \fixup)
@@ -63,34 +77,24 @@
#endif
.endm
-/*
- * memset(void *s, int c, size_t n)
- *
- * a0: start of area to clear
- * a1: char to fill with
- * a2: size of area to clear
- */
.set noreorder
.align 5
-LEAF(memset)
- beqz a1, 1f
- move v0, a0 /* result */
- andi a1, 0xff /* spread fillword */
- LONG_SLL t1, a1, 8
- or a1, t1
- LONG_SLL t1, a1, 16
-#if LONGSIZE == 8
- or a1, t1
- LONG_SLL t1, a1, 32
-#endif
- or a1, t1
-1:
+ /*
+ * Macro to generate the __bzero{,_user} symbol
+ * Arguments:
+ * mode: LEGACY_MODE or EVA_MODE
+ */
+ .macro __BUILD_BZERO mode
+ /* Initialize __memset if this is the first time we call this macro */
+ .ifnotdef __memset
+ .set __memset, 1
+ .hidden __memset /* Make sure it does not leak */
+ .endif
-FEXPORT(__bzero)
sltiu t0, a2, STORSIZE /* very small region? */
- bnez t0, .Lsmall_memset
- andi t0, a0, STORMASK /* aligned? */
+ bnez t0, .Lsmall_memset\@
+ andi t0, a0, STORMASK /* aligned? */
#ifdef CONFIG_CPU_MICROMIPS
move t8, a1 /* used by 'swp' instruction */
@@ -98,39 +102,39 @@ FEXPORT(__bzero)
#endif
#ifndef CONFIG_CPU_DADDI_WORKAROUNDS
beqz t0, 1f
- PTR_SUBU t0, STORSIZE /* alignment in bytes */
+ PTR_SUBU t0, STORSIZE /* alignment in bytes */
#else
.set noat
li AT, STORSIZE
beqz t0, 1f
- PTR_SUBU t0, AT /* alignment in bytes */
+ PTR_SUBU t0, AT /* alignment in bytes */
.set at
#endif
R10KCBARRIER(0(ra))
#ifdef __MIPSEB__
- EX(LONG_S_L, a1, (a0), .Lfirst_fixup) /* make word/dword aligned */
+ EX(LONG_S_L, a1, (a0), .Lfirst_fixup\@) /* make word/dword aligned */
#endif
#ifdef __MIPSEL__
- EX(LONG_S_R, a1, (a0), .Lfirst_fixup) /* make word/dword aligned */
+ EX(LONG_S_R, a1, (a0), .Lfirst_fixup\@) /* make word/dword aligned */
#endif
PTR_SUBU a0, t0 /* long align ptr */
PTR_ADDU a2, t0 /* correct size */
1: ori t1, a2, 0x3f /* # of full blocks */
xori t1, 0x3f
- beqz t1, .Lmemset_partial /* no block to fill */
- andi t0, a2, 0x40-STORSIZE
+ beqz t1, .Lmemset_partial\@ /* no block to fill */
+ andi t0, a2, 0x40-STORSIZE
PTR_ADDU t1, a0 /* end address */
.set reorder
1: PTR_ADDIU a0, 64
R10KCBARRIER(0(ra))
- f_fill64 a0, -64, FILL64RG, .Lfwd_fixup
+ f_fill64 a0, -64, FILL64RG, .Lfwd_fixup\@, \mode
bne t1, a0, 1b
.set noreorder
-.Lmemset_partial:
+.Lmemset_partial\@:
R10KCBARRIER(0(ra))
PTR_LA t1, 2f /* where to start */
#ifdef CONFIG_CPU_MICROMIPS
@@ -145,60 +149,100 @@ FEXPORT(__bzero)
.set at
#endif
jr t1
- PTR_ADDU a0, t0 /* dest ptr */
+ PTR_ADDU a0, t0 /* dest ptr */
.set push
.set noreorder
.set nomacro
- f_fill64 a0, -64, FILL64RG, .Lpartial_fixup /* ... but first do longs ... */
+ /* ... but first do longs ... */
+ f_fill64 a0, -64, FILL64RG, .Lpartial_fixup\@, \mode
2: .set pop
andi a2, STORMASK /* At most one long to go */
beqz a2, 1f
- PTR_ADDU a0, a2 /* What's left */
+ PTR_ADDU a0, a2 /* What's left */
R10KCBARRIER(0(ra))
#ifdef __MIPSEB__
- EX(LONG_S_R, a1, -1(a0), .Llast_fixup)
+ EX(LONG_S_R, a1, -1(a0), .Llast_fixup\@)
#endif
#ifdef __MIPSEL__
- EX(LONG_S_L, a1, -1(a0), .Llast_fixup)
+ EX(LONG_S_L, a1, -1(a0), .Llast_fixup\@)
#endif
1: jr ra
- move a2, zero
+ move a2, zero
-.Lsmall_memset:
+.Lsmall_memset\@:
beqz a2, 2f
- PTR_ADDU t1, a0, a2
+ PTR_ADDU t1, a0, a2
1: PTR_ADDIU a0, 1 /* fill bytewise */
R10KCBARRIER(0(ra))
bne t1, a0, 1b
- sb a1, -1(a0)
+ sb a1, -1(a0)
2: jr ra /* done */
- move a2, zero
+ move a2, zero
+ .if __memset == 1
END(memset)
+ .set __memset, 0
+ .hidden __memset
+ .endif
-.Lfirst_fixup:
+.Lfirst_fixup\@:
jr ra
- nop
+ nop
-.Lfwd_fixup:
+.Lfwd_fixup\@:
PTR_L t0, TI_TASK($28)
andi a2, 0x3f
LONG_L t0, THREAD_BUADDR(t0)
LONG_ADDU a2, t1
jr ra
- LONG_SUBU a2, t0
+ LONG_SUBU a2, t0
-.Lpartial_fixup:
+.Lpartial_fixup\@:
PTR_L t0, TI_TASK($28)
andi a2, STORMASK
LONG_L t0, THREAD_BUADDR(t0)
LONG_ADDU a2, t1
jr ra
- LONG_SUBU a2, t0
+ LONG_SUBU a2, t0
-.Llast_fixup:
+.Llast_fixup\@:
jr ra
- andi v1, a2, STORMASK
+ andi v1, a2, STORMASK
+
+ .endm
+
+/*
+ * memset(void *s, int c, size_t n)
+ *
+ * a0: start of area to clear
+ * a1: char to fill with
+ * a2: size of area to clear
+ */
+
+LEAF(memset)
+ beqz a1, 1f
+ move v0, a0 /* result */
+
+ andi a1, 0xff /* spread fillword */
+ LONG_SLL t1, a1, 8
+ or a1, t1
+ LONG_SLL t1, a1, 16
+#if LONGSIZE == 8
+ or a1, t1
+ LONG_SLL t1, a1, 32
+#endif
+ or a1, t1
+1:
+#ifndef CONFIG_EVA
+FEXPORT(__bzero)
+#endif
+ __BUILD_BZERO LEGACY_MODE
+
+#ifdef CONFIG_EVA
+LEAF(__bzero)
+ __BUILD_BZERO EVA_MODE
+END(__bzero)
+#endif
diff --git a/arch/mips/lib/strlen_user.S b/arch/mips/lib/strlen_user.S
index e362dcdc69d1..bef65c98df59 100644
--- a/arch/mips/lib/strlen_user.S
+++ b/arch/mips/lib/strlen_user.S
@@ -22,19 +22,43 @@
*
* Return 0 for error
*/
-LEAF(__strlen_user_asm)
+ .macro __BUILD_STRLEN_ASM func
+LEAF(__strlen_\func\()_asm)
LONG_L v0, TI_ADDR_LIMIT($28) # pointer ok?
and v0, a0
- bnez v0, .Lfault
+ bnez v0, .Lfault\@
-FEXPORT(__strlen_user_nocheck_asm)
+FEXPORT(__strlen_\func\()_nocheck_asm)
move v0, a0
-1: EX(lbu, v1, (v0), .Lfault)
+.ifeqs "\func", "kernel"
+1: EX(lbu, v1, (v0), .Lfault\@)
+.else
+1: EX(lbue, v1, (v0), .Lfault\@)
+.endif
PTR_ADDIU v0, 1
bnez v1, 1b
PTR_SUBU v0, a0
jr ra
- END(__strlen_user_asm)
+ END(__strlen_\func\()_asm)
-.Lfault: move v0, zero
+.Lfault\@: move v0, zero
jr ra
+ .endm
+
+#ifndef CONFIG_EVA
+ /* Set aliases */
+ .global __strlen_user_asm
+ .global __strlen_user_nocheck_asm
+ .set __strlen_user_asm, __strlen_kernel_asm
+ .set __strlen_user_nocheck_asm, __strlen_kernel_nocheck_asm
+#endif
+
+__BUILD_STRLEN_ASM kernel
+
+#ifdef CONFIG_EVA
+
+ .set push
+ .set eva
+__BUILD_STRLEN_ASM user
+ .set pop
+#endif
diff --git a/arch/mips/lib/strncpy_user.S b/arch/mips/lib/strncpy_user.S
index 92870b6b53ea..d3301cd1e9a5 100644
--- a/arch/mips/lib/strncpy_user.S
+++ b/arch/mips/lib/strncpy_user.S
@@ -28,16 +28,21 @@
* it happens at most some bytes of the exceptions handlers will be copied.
*/
-LEAF(__strncpy_from_user_asm)
+ .macro __BUILD_STRNCPY_ASM func
+LEAF(__strncpy_from_\func\()_asm)
LONG_L v0, TI_ADDR_LIMIT($28) # pointer ok?
and v0, a1
- bnez v0, .Lfault
+ bnez v0, .Lfault\@
-FEXPORT(__strncpy_from_user_nocheck_asm)
+FEXPORT(__strncpy_from_\func\()_nocheck_asm)
.set noreorder
move t0, zero
move v1, a1
-1: EX(lbu, v0, (v1), .Lfault)
+.ifeqs "\func","kernel"
+1: EX(lbu, v0, (v1), .Lfault\@)
+.else
+1: EX(lbue, v0, (v1), .Lfault\@)
+.endif
PTR_ADDIU v1, 1
R10KCBARRIER(0(ra))
beqz v0, 2f
@@ -47,15 +52,34 @@ FEXPORT(__strncpy_from_user_nocheck_asm)
PTR_ADDIU a0, 1
2: PTR_ADDU v0, a1, t0
xor v0, a1
- bltz v0, .Lfault
+ bltz v0, .Lfault\@
nop
jr ra # return n
move v0, t0
- END(__strncpy_from_user_asm)
+ END(__strncpy_from_\func\()_asm)
-.Lfault: jr ra
+.Lfault\@: jr ra
li v0, -EFAULT
.section __ex_table,"a"
- PTR 1b, .Lfault
+ PTR 1b, .Lfault\@
.previous
+
+ .endm
+
+#ifndef CONFIG_EVA
+ /* Set aliases */
+ .global __strncpy_from_user_asm
+ .global __strncpy_from_user_nocheck_asm
+ .set __strncpy_from_user_asm, __strncpy_from_kernel_asm
+ .set __strncpy_from_user_nocheck_asm, __strncpy_from_kernel_nocheck_asm
+#endif
+
+__BUILD_STRNCPY_ASM kernel
+
+#ifdef CONFIG_EVA
+ .set push
+ .set eva
+__BUILD_STRNCPY_ASM user
+ .set pop
+#endif
diff --git a/arch/mips/lib/strnlen_user.S b/arch/mips/lib/strnlen_user.S
index fcacea5e61f1..f3af6995e2a6 100644
--- a/arch/mips/lib/strnlen_user.S
+++ b/arch/mips/lib/strnlen_user.S
@@ -25,22 +25,46 @@
* bytes. There's nothing secret there. On 64-bit accessing beyond
* the maximum is a tad hairier ...
*/
-LEAF(__strnlen_user_asm)
+ .macro __BUILD_STRNLEN_ASM func
+LEAF(__strnlen_\func\()_asm)
LONG_L v0, TI_ADDR_LIMIT($28) # pointer ok?
and v0, a0
- bnez v0, .Lfault
+ bnez v0, .Lfault\@
-FEXPORT(__strnlen_user_nocheck_asm)
+FEXPORT(__strnlen_\func\()_nocheck_asm)
move v0, a0
PTR_ADDU a1, a0 # stop pointer
1: beq v0, a1, 1f # limit reached?
- EX(lb, t0, (v0), .Lfault)
+.ifeqs "\func", "kernel"
+ EX(lb, t0, (v0), .Lfault\@)
+.else
+ EX(lbe, t0, (v0), .Lfault\@)
+.endif
PTR_ADDIU v0, 1
bnez t0, 1b
1: PTR_SUBU v0, a0
jr ra
- END(__strnlen_user_asm)
+ END(__strnlen_\func\()_asm)
-.Lfault:
+.Lfault\@:
move v0, zero
jr ra
+ .endm
+
+#ifndef CONFIG_EVA
+ /* Set aliases */
+ .global __strnlen_user_asm
+ .global __strnlen_user_nocheck_asm
+ .set __strnlen_user_asm, __strnlen_kernel_asm
+ .set __strnlen_user_nocheck_asm, __strnlen_kernel_nocheck_asm
+#endif
+
+__BUILD_STRNLEN_ASM kernel
+
+#ifdef CONFIG_EVA
+
+ .set push
+ .set eva
+__BUILD_STRNLEN_ASM user
+ .set pop
+#endif
diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig
index 263beb9322a8..7397be226a06 100644
--- a/arch/mips/loongson/Kconfig
+++ b/arch/mips/loongson/Kconfig
@@ -59,6 +59,36 @@ config LEMOTE_MACH2F
These family machines include fuloong2f mini PC, yeeloong2f notebook,
LingLoong allinone PC and so forth.
+
+config LEMOTE_MACH3A
+ bool "Lemote Loongson 3A family machines"
+ select ARCH_SPARSEMEM_ENABLE
+ select GENERIC_ISA_DMA_SUPPORT_BROKEN
+ select GENERIC_HARDIRQS_NO__DO_IRQ
+ select BOOT_ELF32
+ select BOARD_SCACHE
+ select CSRC_R4K
+ select CEVT_R4K
+ select CPU_HAS_WB
+ select HW_HAS_PCI
+ select ISA
+ select HT_PCI
+ select I8259
+ select IRQ_CPU
+ select NR_CPUS_DEFAULT_4
+ select SYS_HAS_CPU_LOONGSON3
+ select SYS_HAS_EARLY_PRINTK
+ select SYS_SUPPORTS_SMP
+ select SYS_SUPPORTS_HOTPLUG_CPU
+ select SYS_SUPPORTS_64BIT_KERNEL
+ select SYS_SUPPORTS_HIGHMEM
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select LOONGSON_MC146818
+ select ZONE_DMA32
+ select LEFI_FIRMWARE_INTERFACE
+ help
+ Lemote Loongson 3A family machines utilize the 3A revision of
+ Loongson processor and RS780/SBX00 chipset.
endchoice
config CS5536
@@ -86,8 +116,25 @@ config LOONGSON_UART_BASE
default y
depends on EARLY_PRINTK || SERIAL_8250
+config IOMMU_HELPER
+ bool
+
+config NEED_SG_DMA_LENGTH
+ bool
+
+config SWIOTLB
+ bool "Soft IOMMU Support for All-Memory DMA"
+ default y
+ depends on CPU_LOONGSON3
+ select IOMMU_HELPER
+ select NEED_SG_DMA_LENGTH
+ select NEED_DMA_MAP_STATE
+
config LOONGSON_MC146818
bool
default n
+config LEFI_FIRMWARE_INTERFACE
+ bool
+
endif # MACH_LOONGSON
diff --git a/arch/mips/loongson/Makefile b/arch/mips/loongson/Makefile
index 0dc0055754cd..7429994e7604 100644
--- a/arch/mips/loongson/Makefile
+++ b/arch/mips/loongson/Makefile
@@ -15,3 +15,9 @@ obj-$(CONFIG_LEMOTE_FULOONG2E) += fuloong-2e/
#
obj-$(CONFIG_LEMOTE_MACH2F) += lemote-2f/
+
+#
+# All Loongson-3 family machines
+#
+
+obj-$(CONFIG_CPU_LOONGSON3) += loongson-3/
diff --git a/arch/mips/loongson/Platform b/arch/mips/loongson/Platform
index 29692e5433b1..6205372b6c2d 100644
--- a/arch/mips/loongson/Platform
+++ b/arch/mips/loongson/Platform
@@ -30,3 +30,4 @@ platform-$(CONFIG_MACH_LOONGSON) += loongson/
cflags-$(CONFIG_MACH_LOONGSON) += -I$(srctree)/arch/mips/include/asm/mach-loongson -mno-branch-likely
load-$(CONFIG_LEMOTE_FULOONG2E) += 0xffffffff80100000
load-$(CONFIG_LEMOTE_MACH2F) += 0xffffffff80200000
+load-$(CONFIG_CPU_LOONGSON3) += 0xffffffff80200000
diff --git a/arch/mips/loongson/common/Makefile b/arch/mips/loongson/common/Makefile
index 9e4484ccbb03..0bb9cc9dc621 100644
--- a/arch/mips/loongson/common/Makefile
+++ b/arch/mips/loongson/common/Makefile
@@ -26,3 +26,8 @@ obj-$(CONFIG_CS5536) += cs5536/
#
obj-$(CONFIG_LOONGSON_SUSPEND) += pm.o
+
+#
+# Big Memory (SWIOTLB) Support
+#
+obj-$(CONFIG_SWIOTLB) += dma-swiotlb.o
diff --git a/arch/mips/loongson/common/dma-swiotlb.c b/arch/mips/loongson/common/dma-swiotlb.c
new file mode 100644
index 000000000000..c2be01f91575
--- /dev/null
+++ b/arch/mips/loongson/common/dma-swiotlb.c
@@ -0,0 +1,136 @@
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/swiotlb.h>
+#include <linux/bootmem.h>
+
+#include <asm/bootinfo.h>
+#include <boot_param.h>
+#include <dma-coherence.h>
+
+static void *loongson_dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp, struct dma_attrs *attrs)
+{
+ void *ret;
+
+ if (dma_alloc_from_coherent(dev, size, dma_handle, &ret))
+ return ret;
+
+ /* ignore region specifiers */
+ gfp &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM);
+
+#ifdef CONFIG_ISA
+ if (dev == NULL)
+ gfp |= __GFP_DMA;
+ else
+#endif
+#ifdef CONFIG_ZONE_DMA
+ if (dev->coherent_dma_mask < DMA_BIT_MASK(32))
+ gfp |= __GFP_DMA;
+ else
+#endif
+#ifdef CONFIG_ZONE_DMA32
+ if (dev->coherent_dma_mask < DMA_BIT_MASK(40))
+ gfp |= __GFP_DMA32;
+ else
+#endif
+ ;
+ gfp |= __GFP_NORETRY;
+
+ ret = swiotlb_alloc_coherent(dev, size, dma_handle, gfp);
+ mb();
+ return ret;
+}
+
+static void loongson_dma_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle, struct dma_attrs *attrs)
+{
+ int order = get_order(size);
+
+ if (dma_release_from_coherent(dev, order, vaddr))
+ return;
+
+ swiotlb_free_coherent(dev, size, vaddr, dma_handle);
+}
+
+static dma_addr_t loongson_dma_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ dma_addr_t daddr = swiotlb_map_page(dev, page, offset, size,
+ dir, attrs);
+ mb();
+ return daddr;
+}
+
+static int loongson_dma_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ int r = swiotlb_map_sg_attrs(dev, sg, nents, dir, NULL);
+ mb();
+
+ return r;
+}
+
+static void loongson_dma_sync_single_for_device(struct device *dev,
+ dma_addr_t dma_handle, size_t size,
+ enum dma_data_direction dir)
+{
+ swiotlb_sync_single_for_device(dev, dma_handle, size, dir);
+ mb();
+}
+
+static void loongson_dma_sync_sg_for_device(struct device *dev,
+ struct scatterlist *sg, int nents,
+ enum dma_data_direction dir)
+{
+ swiotlb_sync_sg_for_device(dev, sg, nents, dir);
+ mb();
+}
+
+static int loongson_dma_set_mask(struct device *dev, u64 mask)
+{
+ if (mask > DMA_BIT_MASK(loongson_sysconf.dma_mask_bits)) {
+ *dev->dma_mask = DMA_BIT_MASK(loongson_sysconf.dma_mask_bits);
+ return -EIO;
+ }
+
+ *dev->dma_mask = mask;
+
+ return 0;
+}
+
+dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+ return paddr;
+}
+
+phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
+{
+ return daddr;
+}
+
+static struct dma_map_ops loongson_dma_map_ops = {
+ .alloc = loongson_dma_alloc_coherent,
+ .free = loongson_dma_free_coherent,
+ .map_page = loongson_dma_map_page,
+ .unmap_page = swiotlb_unmap_page,
+ .map_sg = loongson_dma_map_sg,
+ .unmap_sg = swiotlb_unmap_sg_attrs,
+ .sync_single_for_cpu = swiotlb_sync_single_for_cpu,
+ .sync_single_for_device = loongson_dma_sync_single_for_device,
+ .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
+ .sync_sg_for_device = loongson_dma_sync_sg_for_device,
+ .mapping_error = swiotlb_dma_mapping_error,
+ .dma_supported = swiotlb_dma_supported,
+ .set_dma_mask = loongson_dma_set_mask
+};
+
+void __init plat_swiotlb_setup(void)
+{
+ swiotlb_init(1);
+ mips_dma_map_ops = &loongson_dma_map_ops;
+}
diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c
index 0a18fcf2d372..0c543eae49bf 100644
--- a/arch/mips/loongson/common/env.c
+++ b/arch/mips/loongson/common/env.c
@@ -18,29 +18,30 @@
* option) any later version.
*/
#include <linux/module.h>
-
#include <asm/bootinfo.h>
-
#include <loongson.h>
+#include <boot_param.h>
-unsigned long cpu_clock_freq;
+u32 cpu_clock_freq;
EXPORT_SYMBOL(cpu_clock_freq);
-unsigned long memsize, highmemsize;
+struct efi_memory_map_loongson *loongson_memmap;
+struct loongson_system_configuration loongson_sysconf;
#define parse_even_earlier(res, option, p) \
do { \
unsigned int tmp __maybe_unused; \
\
if (strncmp(option, (char *)p, strlen(option)) == 0) \
- tmp = strict_strtol((char *)p + strlen(option"="), 10, &res); \
+ tmp = kstrtou32((char *)p + strlen(option"="), 10, &res); \
} while (0)
void __init prom_init_env(void)
{
/* pmon passes arguments in 32bit pointers */
- int *_prom_envp;
- unsigned long bus_clock;
unsigned int processor_id;
+
+#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE
+ int *_prom_envp;
long l;
/* firmware arguments are initialized in head.S */
@@ -48,7 +49,6 @@ void __init prom_init_env(void)
l = (long)*_prom_envp;
while (l != 0) {
- parse_even_earlier(bus_clock, "busclock", l);
parse_even_earlier(cpu_clock_freq, "cpuclock", l);
parse_even_earlier(memsize, "memsize", l);
parse_even_earlier(highmemsize, "highmemsize", l);
@@ -57,8 +57,48 @@ void __init prom_init_env(void)
}
if (memsize == 0)
memsize = 256;
- if (bus_clock == 0)
- bus_clock = 66000000;
+ pr_info("memsize=%u, highmemsize=%u\n", memsize, highmemsize);
+#else
+ struct boot_params *boot_p;
+ struct loongson_params *loongson_p;
+ struct efi_cpuinfo_loongson *ecpu;
+ struct irq_source_routing_table *eirq_source;
+
+ /* firmware arguments are initialized in head.S */
+ boot_p = (struct boot_params *)fw_arg2;
+ loongson_p = &(boot_p->efi.smbios.lp);
+
+ ecpu = (struct efi_cpuinfo_loongson *)
+ ((u64)loongson_p + loongson_p->cpu_offset);
+ eirq_source = (struct irq_source_routing_table *)
+ ((u64)loongson_p + loongson_p->irq_offset);
+ loongson_memmap = (struct efi_memory_map_loongson *)
+ ((u64)loongson_p + loongson_p->memory_offset);
+
+ cpu_clock_freq = ecpu->cpu_clock_freq;
+ loongson_sysconf.cputype = ecpu->cputype;
+ loongson_sysconf.nr_cpus = ecpu->nr_cpus;
+ if (ecpu->nr_cpus > NR_CPUS || ecpu->nr_cpus == 0)
+ loongson_sysconf.nr_cpus = NR_CPUS;
+
+ loongson_sysconf.pci_mem_start_addr = eirq_source->pci_mem_start_addr;
+ loongson_sysconf.pci_mem_end_addr = eirq_source->pci_mem_end_addr;
+ loongson_sysconf.pci_io_base = eirq_source->pci_io_start_addr;
+ loongson_sysconf.dma_mask_bits = eirq_source->dma_mask_bits;
+ if (loongson_sysconf.dma_mask_bits < 32 ||
+ loongson_sysconf.dma_mask_bits > 64)
+ loongson_sysconf.dma_mask_bits = 32;
+
+ loongson_sysconf.restart_addr = boot_p->reset_system.ResetWarm;
+ loongson_sysconf.poweroff_addr = boot_p->reset_system.Shutdown;
+ loongson_sysconf.suspend_addr = boot_p->reset_system.DoSuspend;
+
+ loongson_sysconf.ht_control_base = 0x90000EFDFB000000;
+ loongson_sysconf.vgabios_addr = boot_p->efi.smbios.vga_bios;
+ pr_debug("Shutdown Addr: %llx, Restart Addr: %llx, VBIOS Addr: %llx\n",
+ loongson_sysconf.poweroff_addr, loongson_sysconf.restart_addr,
+ loongson_sysconf.vgabios_addr);
+#endif
if (cpu_clock_freq == 0) {
processor_id = (&current_cpu_data)->processor_id;
switch (processor_id & PRID_REV_MASK) {
@@ -68,12 +108,13 @@ void __init prom_init_env(void)
case PRID_REV_LOONGSON2F:
cpu_clock_freq = 797000000;
break;
+ case PRID_REV_LOONGSON3A:
+ cpu_clock_freq = 900000000;
+ break;
default:
cpu_clock_freq = 100000000;
break;
}
}
-
- pr_info("busclock=%ld, cpuclock=%ld, memsize=%ld, highmemsize=%ld\n",
- bus_clock, cpu_clock_freq, memsize, highmemsize);
+ pr_info("CpuClock = %u\n", cpu_clock_freq);
}
diff --git a/arch/mips/loongson/common/init.c b/arch/mips/loongson/common/init.c
index ae7af1fd5d59..f37fe5413b73 100644
--- a/arch/mips/loongson/common/init.c
+++ b/arch/mips/loongson/common/init.c
@@ -9,6 +9,7 @@
*/
#include <linux/bootmem.h>
+#include <asm/smp-ops.h>
#include <loongson.h>
@@ -17,10 +18,6 @@ unsigned long __maybe_unused _loongson_addrwincfg_base;
void __init prom_init(void)
{
- /* init base address of io space */
- set_io_port_base((unsigned long)
- ioremap(LOONGSON_PCIIO_BASE, LOONGSON_PCIIO_SIZE));
-
#ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG
_loongson_addrwincfg_base = (unsigned long)
ioremap(LOONGSON_ADDRWINCFG_BASE, LOONGSON_ADDRWINCFG_SIZE);
@@ -28,10 +25,16 @@ void __init prom_init(void)
prom_init_cmdline();
prom_init_env();
+
+ /* init base address of io space */
+ set_io_port_base((unsigned long)
+ ioremap(LOONGSON_PCIIO_BASE, LOONGSON_PCIIO_SIZE));
+
prom_init_memory();
/*init the uart base address */
prom_init_uart_base();
+ register_smp_ops(&loongson3_smp_ops);
}
void __init prom_free_prom_memory(void)
diff --git a/arch/mips/loongson/common/machtype.c b/arch/mips/loongson/common/machtype.c
index 4becd4f9ef2e..1a4797984b8d 100644
--- a/arch/mips/loongson/common/machtype.c
+++ b/arch/mips/loongson/common/machtype.c
@@ -27,6 +27,10 @@ static const char *system_types[] = {
[MACH_DEXXON_GDIUM2F10] "dexxon-gdium-2f",
[MACH_LEMOTE_NAS] "lemote-nas-2f",
[MACH_LEMOTE_LL2F] "lemote-lynloong-2f",
+ [MACH_LEMOTE_A1004] "lemote-3a-notebook-a1004",
+ [MACH_LEMOTE_A1101] "lemote-3a-itx-a1101",
+ [MACH_LEMOTE_A1201] "lemote-2gq-notebook-a1201",
+ [MACH_LEMOTE_A1205] "lemote-2gq-aio-a1205",
[MACH_LOONGSON_END] NULL,
};
diff --git a/arch/mips/loongson/common/mem.c b/arch/mips/loongson/common/mem.c
index 8626a42f5b94..b01d52473da8 100644
--- a/arch/mips/loongson/common/mem.c
+++ b/arch/mips/loongson/common/mem.c
@@ -11,9 +11,14 @@
#include <asm/bootinfo.h>
#include <loongson.h>
+#include <boot_param.h>
#include <mem.h>
#include <pci.h>
+#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE
+
+u32 memsize, highmemsize;
+
void __init prom_init_memory(void)
{
add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM);
@@ -49,6 +54,43 @@ void __init prom_init_memory(void)
#endif /* !CONFIG_64BIT */
}
+#else /* CONFIG_LEFI_FIRMWARE_INTERFACE */
+
+void __init prom_init_memory(void)
+{
+ int i;
+ u32 node_id;
+ u32 mem_type;
+
+ /* parse memory information */
+ for (i = 0; i < loongson_memmap->nr_map; i++) {
+ node_id = loongson_memmap->map[i].node_id;
+ mem_type = loongson_memmap->map[i].mem_type;
+
+ if (node_id == 0) {
+ switch (mem_type) {
+ case SYSTEM_RAM_LOW:
+ add_memory_region(loongson_memmap->map[i].mem_start,
+ (u64)loongson_memmap->map[i].mem_size << 20,
+ BOOT_MEM_RAM);
+ break;
+ case SYSTEM_RAM_HIGH:
+ add_memory_region(loongson_memmap->map[i].mem_start,
+ (u64)loongson_memmap->map[i].mem_size << 20,
+ BOOT_MEM_RAM);
+ break;
+ case MEM_RESERVED:
+ add_memory_region(loongson_memmap->map[i].mem_start,
+ (u64)loongson_memmap->map[i].mem_size << 20,
+ BOOT_MEM_RESERVED);
+ break;
+ }
+ }
+ }
+}
+
+#endif /* CONFIG_LEFI_FIRMWARE_INTERFACE */
+
/* override of arch/mips/mm/cache.c: __uncached_access */
int __uncached_access(struct file *file, unsigned long addr)
{
diff --git a/arch/mips/loongson/common/pci.c b/arch/mips/loongson/common/pci.c
index fa7784459721..003ab4e618b3 100644
--- a/arch/mips/loongson/common/pci.c
+++ b/arch/mips/loongson/common/pci.c
@@ -11,6 +11,7 @@
#include <pci.h>
#include <loongson.h>
+#include <boot_param.h>
static struct resource loongson_pci_mem_resource = {
.name = "pci memory space",
@@ -82,7 +83,10 @@ static int __init pcibios_init(void)
setup_pcimap();
loongson_pci_controller.io_map_base = mips_io_port_base;
-
+#ifdef CONFIG_LEFI_FIRMWARE_INTERFACE
+ loongson_pci_mem_resource.start = loongson_sysconf.pci_mem_start_addr;
+ loongson_pci_mem_resource.end = loongson_sysconf.pci_mem_end_addr;
+#endif
register_pci_controller(&loongson_pci_controller);
return 0;
diff --git a/arch/mips/loongson/common/reset.c b/arch/mips/loongson/common/reset.c
index 65bfbb5d06f4..a60715e11306 100644
--- a/arch/mips/loongson/common/reset.c
+++ b/arch/mips/loongson/common/reset.c
@@ -16,6 +16,7 @@
#include <asm/reboot.h>
#include <loongson.h>
+#include <boot_param.h>
static inline void loongson_reboot(void)
{
@@ -37,17 +38,37 @@ static inline void loongson_reboot(void)
static void loongson_restart(char *command)
{
+#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE
/* do preparation for reboot */
mach_prepare_reboot();
/* reboot via jumping to boot base address */
loongson_reboot();
+#else
+ void (*fw_restart)(void) = (void *)loongson_sysconf.restart_addr;
+
+ fw_restart();
+ while (1) {
+ if (cpu_wait)
+ cpu_wait();
+ }
+#endif
}
static void loongson_poweroff(void)
{
+#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE
mach_prepare_shutdown();
unreachable();
+#else
+ void (*fw_poweroff)(void) = (void *)loongson_sysconf.poweroff_addr;
+
+ fw_poweroff();
+ while (1) {
+ if (cpu_wait)
+ cpu_wait();
+ }
+#endif
}
static void loongson_halt(void)
diff --git a/arch/mips/loongson/common/serial.c b/arch/mips/loongson/common/serial.c
index 5f2b78ae97cc..bd2b7095b6dc 100644
--- a/arch/mips/loongson/common/serial.c
+++ b/arch/mips/loongson/common/serial.c
@@ -19,19 +19,19 @@
#include <loongson.h>
#include <machine.h>
-#define PORT(int) \
+#define PORT(int, clk) \
{ \
.irq = int, \
- .uartclk = 1843200, \
+ .uartclk = clk, \
.iotype = UPIO_PORT, \
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \
.regshift = 0, \
}
-#define PORT_M(int) \
+#define PORT_M(int, clk) \
{ \
.irq = MIPS_CPU_IRQ_BASE + (int), \
- .uartclk = 3686400, \
+ .uartclk = clk, \
.iotype = UPIO_MEM, \
.membase = (void __iomem *)NULL, \
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \
@@ -40,13 +40,17 @@
static struct plat_serial8250_port uart8250_data[][2] = {
[MACH_LOONGSON_UNKNOWN] {},
- [MACH_LEMOTE_FL2E] {PORT(4), {} },
- [MACH_LEMOTE_FL2F] {PORT(3), {} },
- [MACH_LEMOTE_ML2F7] {PORT_M(3), {} },
- [MACH_LEMOTE_YL2F89] {PORT_M(3), {} },
- [MACH_DEXXON_GDIUM2F10] {PORT_M(3), {} },
- [MACH_LEMOTE_NAS] {PORT_M(3), {} },
- [MACH_LEMOTE_LL2F] {PORT(3), {} },
+ [MACH_LEMOTE_FL2E] {PORT(4, 1843200), {} },
+ [MACH_LEMOTE_FL2F] {PORT(3, 1843200), {} },
+ [MACH_LEMOTE_ML2F7] {PORT_M(3, 3686400), {} },
+ [MACH_LEMOTE_YL2F89] {PORT_M(3, 3686400), {} },
+ [MACH_DEXXON_GDIUM2F10] {PORT_M(3, 3686400), {} },
+ [MACH_LEMOTE_NAS] {PORT_M(3, 3686400), {} },
+ [MACH_LEMOTE_LL2F] {PORT(3, 1843200), {} },
+ [MACH_LEMOTE_A1004] {PORT_M(2, 33177600), {} },
+ [MACH_LEMOTE_A1101] {PORT_M(2, 25000000), {} },
+ [MACH_LEMOTE_A1201] {PORT_M(2, 25000000), {} },
+ [MACH_LEMOTE_A1205] {PORT_M(2, 25000000), {} },
[MACH_LOONGSON_END] {},
};
diff --git a/arch/mips/loongson/common/setup.c b/arch/mips/loongson/common/setup.c
index 8223f8acfd59..bb4ac922e47a 100644
--- a/arch/mips/loongson/common/setup.c
+++ b/arch/mips/loongson/common/setup.c
@@ -18,9 +18,6 @@
#include <linux/screen_info.h>
#endif
-void (*__wbflush)(void);
-EXPORT_SYMBOL(__wbflush);
-
static void wbflush_loongson(void)
{
asm(".set\tpush\n\t"
@@ -32,10 +29,11 @@ static void wbflush_loongson(void)
".set mips0\n\t");
}
+void (*__wbflush)(void) = wbflush_loongson;
+EXPORT_SYMBOL(__wbflush);
+
void __init plat_mem_setup(void)
{
- __wbflush = wbflush_loongson;
-
#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
conswitchp = &vga_con;
diff --git a/arch/mips/loongson/common/uart_base.c b/arch/mips/loongson/common/uart_base.c
index e192ad021edc..1e1eeea73fde 100644
--- a/arch/mips/loongson/common/uart_base.c
+++ b/arch/mips/loongson/common/uart_base.c
@@ -35,9 +35,16 @@ void prom_init_loongson_uart_base(void)
case MACH_DEXXON_GDIUM2F10:
case MACH_LEMOTE_NAS:
default:
- /* The CPU provided serial port */
+ /* The CPU provided serial port (LPC) */
loongson_uart_base = LOONGSON_LIO1_BASE + 0x3f8;
break;
+ case MACH_LEMOTE_A1004:
+ case MACH_LEMOTE_A1101:
+ case MACH_LEMOTE_A1201:
+ case MACH_LEMOTE_A1205:
+ /* The CPU provided serial port (CPU) */
+ loongson_uart_base = LOONGSON_REG_BASE + 0x1e0;
+ break;
}
_loongson_uart_base =
diff --git a/arch/mips/loongson/loongson-3/Makefile b/arch/mips/loongson/loongson-3/Makefile
new file mode 100644
index 000000000000..70152b252ddc
--- /dev/null
+++ b/arch/mips/loongson/loongson-3/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for Loongson-3 family machines
+#
+obj-y += irq.o
+
+obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/mips/loongson/loongson-3/irq.c b/arch/mips/loongson/loongson-3/irq.c
new file mode 100644
index 000000000000..f240828181ff
--- /dev/null
+++ b/arch/mips/loongson/loongson-3/irq.c
@@ -0,0 +1,126 @@
+#include <loongson.h>
+#include <irq.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+
+#include <asm/irq_cpu.h>
+#include <asm/i8259.h>
+#include <asm/mipsregs.h>
+
+unsigned int ht_irq[] = {1, 3, 4, 5, 6, 7, 8, 12, 14, 15};
+
+static void ht_irqdispatch(void)
+{
+ unsigned int i, irq;
+
+ irq = LOONGSON_HT1_INT_VECTOR(0);
+ LOONGSON_HT1_INT_VECTOR(0) = irq; /* Acknowledge the IRQs */
+
+ for (i = 0; i < ARRAY_SIZE(ht_irq); i++) {
+ if (irq & (0x1 << ht_irq[i]))
+ do_IRQ(ht_irq[i]);
+ }
+}
+
+void mach_irq_dispatch(unsigned int pending)
+{
+ if (pending & CAUSEF_IP7)
+ do_IRQ(LOONGSON_TIMER_IRQ);
+#if defined(CONFIG_SMP)
+ else if (pending & CAUSEF_IP6)
+ loongson3_ipi_interrupt(NULL);
+#endif
+ else if (pending & CAUSEF_IP3)
+ ht_irqdispatch();
+ else if (pending & CAUSEF_IP2)
+ do_IRQ(LOONGSON_UART_IRQ);
+ else {
+ pr_err("%s : spurious interrupt\n", __func__);
+ spurious_interrupt();
+ }
+}
+
+static struct irqaction cascade_irqaction = {
+ .handler = no_action,
+ .name = "cascade",
+};
+
+static inline void mask_loongson_irq(struct irq_data *d)
+{
+ clear_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE));
+ irq_disable_hazard();
+
+ /* Workaround: UART IRQ may deliver to any core */
+ if (d->irq == LOONGSON_UART_IRQ) {
+ int cpu = smp_processor_id();
+
+ LOONGSON_INT_ROUTER_INTENCLR = 1 << 10;
+ LOONGSON_INT_ROUTER_LPC = 0x10 + (1<<cpu);
+ }
+}
+
+static inline void unmask_loongson_irq(struct irq_data *d)
+{
+ /* Workaround: UART IRQ may deliver to any core */
+ if (d->irq == LOONGSON_UART_IRQ) {
+ int cpu = smp_processor_id();
+
+ LOONGSON_INT_ROUTER_INTENSET = 1 << 10;
+ LOONGSON_INT_ROUTER_LPC = 0x10 + (1<<cpu);
+ }
+
+ set_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE));
+ irq_enable_hazard();
+}
+
+ /* For MIPS IRQs which shared by all cores */
+static struct irq_chip loongson_irq_chip = {
+ .name = "Loongson",
+ .irq_ack = mask_loongson_irq,
+ .irq_mask = mask_loongson_irq,
+ .irq_mask_ack = mask_loongson_irq,
+ .irq_unmask = unmask_loongson_irq,
+ .irq_eoi = unmask_loongson_irq,
+};
+
+void irq_router_init(void)
+{
+ int i;
+
+ /* route LPC int to cpu core0 int 0 */
+ LOONGSON_INT_ROUTER_LPC = LOONGSON_INT_CORE0_INT0;
+ /* route HT1 int0 ~ int7 to cpu core0 INT1*/
+ for (i = 0; i < 8; i++)
+ LOONGSON_INT_ROUTER_HT1(i) = LOONGSON_INT_CORE0_INT1;
+ /* enable HT1 interrupt */
+ LOONGSON_HT1_INTN_EN(0) = 0xffffffff;
+ /* enable router interrupt intenset */
+ LOONGSON_INT_ROUTER_INTENSET =
+ LOONGSON_INT_ROUTER_INTEN | (0xffff << 16) | 0x1 << 10;
+}
+
+void __init mach_init_irq(void)
+{
+ clear_c0_status(ST0_IM | ST0_BEV);
+
+ irq_router_init();
+ mips_cpu_irq_init();
+ init_i8259_irqs();
+ irq_set_chip_and_handler(LOONGSON_UART_IRQ,
+ &loongson_irq_chip, handle_level_irq);
+
+ /* setup HT1 irq */
+ setup_irq(LOONGSON_HT1_IRQ, &cascade_irqaction);
+
+ set_c0_status(STATUSF_IP2 | STATUSF_IP6);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+void fixup_irqs(void)
+{
+ irq_cpu_offline();
+ clear_c0_status(ST0_IM);
+}
+
+#endif
diff --git a/arch/mips/loongson/loongson-3/smp.c b/arch/mips/loongson/loongson-3/smp.c
new file mode 100644
index 000000000000..c665fe16d4c9
--- /dev/null
+++ b/arch/mips/loongson/loongson-3/smp.c
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2010, 2011, 2012, Lemote, Inc.
+ * Author: Chen Huacai, chenhc@lemote.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/cpu.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/cpufreq.h>
+#include <asm/processor.h>
+#include <asm/time.h>
+#include <asm/clock.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
+#include <loongson.h>
+
+#include "smp.h"
+
+DEFINE_PER_CPU(int, cpu_state);
+DEFINE_PER_CPU(uint32_t, core0_c0count);
+
+/* read a 32bit value from ipi register */
+#define loongson3_ipi_read32(addr) readl(addr)
+/* read a 64bit value from ipi register */
+#define loongson3_ipi_read64(addr) readq(addr)
+/* write a 32bit value to ipi register */
+#define loongson3_ipi_write32(action, addr) \
+ do { \
+ writel(action, addr); \
+ __wbflush(); \
+ } while (0)
+/* write a 64bit value to ipi register */
+#define loongson3_ipi_write64(action, addr) \
+ do { \
+ writeq(action, addr); \
+ __wbflush(); \
+ } while (0)
+
+static void *ipi_set0_regs[] = {
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + SET0),
+};
+
+static void *ipi_clear0_regs[] = {
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + CLEAR0),
+};
+
+static void *ipi_status0_regs[] = {
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + STATUS0),
+};
+
+static void *ipi_en0_regs[] = {
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + EN0),
+};
+
+static void *ipi_mailbox_buf[] = {
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + BUF),
+};
+
+/*
+ * Simple enough, just poke the appropriate ipi register
+ */
+static void loongson3_send_ipi_single(int cpu, unsigned int action)
+{
+ loongson3_ipi_write32((u32)action, ipi_set0_regs[cpu]);
+}
+
+static void
+loongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action)
+{
+ unsigned int i;
+
+ for_each_cpu(i, mask)
+ loongson3_ipi_write32((u32)action, ipi_set0_regs[i]);
+}
+
+void loongson3_ipi_interrupt(struct pt_regs *regs)
+{
+ int i, cpu = smp_processor_id();
+ unsigned int action, c0count;
+
+ /* Load the ipi register to figure out what we're supposed to do */
+ action = loongson3_ipi_read32(ipi_status0_regs[cpu]);
+
+ /* Clear the ipi register to clear the interrupt */
+ loongson3_ipi_write32((u32)action, ipi_clear0_regs[cpu]);
+
+ if (action & SMP_RESCHEDULE_YOURSELF)
+ scheduler_ipi();
+
+ if (action & SMP_CALL_FUNCTION)
+ smp_call_function_interrupt();
+
+ if (action & SMP_ASK_C0COUNT) {
+ BUG_ON(cpu != 0);
+ c0count = read_c0_count();
+ for (i = 1; i < loongson_sysconf.nr_cpus; i++)
+ per_cpu(core0_c0count, i) = c0count;
+ }
+}
+
+#define MAX_LOOPS 1111
+/*
+ * SMP init and finish on secondary CPUs
+ */
+static void loongson3_init_secondary(void)
+{
+ int i;
+ uint32_t initcount;
+ unsigned int cpu = smp_processor_id();
+ unsigned int imask = STATUSF_IP7 | STATUSF_IP6 |
+ STATUSF_IP3 | STATUSF_IP2;
+
+ /* Set interrupt mask, but don't enable */
+ change_c0_status(ST0_IM, imask);
+
+ for (i = 0; i < loongson_sysconf.nr_cpus; i++)
+ loongson3_ipi_write32(0xffffffff, ipi_en0_regs[i]);
+
+ per_cpu(cpu_state, cpu) = CPU_ONLINE;
+
+ i = 0;
+ __get_cpu_var(core0_c0count) = 0;
+ loongson3_send_ipi_single(0, SMP_ASK_C0COUNT);
+ while (!__get_cpu_var(core0_c0count)) {
+ i++;
+ cpu_relax();
+ }
+
+ if (i > MAX_LOOPS)
+ i = MAX_LOOPS;
+ initcount = __get_cpu_var(core0_c0count) + i;
+ write_c0_count(initcount);
+}
+
+static void loongson3_smp_finish(void)
+{
+ write_c0_compare(read_c0_count() + mips_hpt_frequency/HZ);
+ local_irq_enable();
+ loongson3_ipi_write64(0,
+ (void *)(ipi_mailbox_buf[smp_processor_id()]+0x0));
+ pr_info("CPU#%d finished, CP0_ST=%x\n",
+ smp_processor_id(), read_c0_status());
+}
+
+static void __init loongson3_smp_setup(void)
+{
+ int i, num;
+
+ init_cpu_possible(cpu_none_mask);
+ set_cpu_possible(0, true);
+
+ __cpu_number_map[0] = 0;
+ __cpu_logical_map[0] = 0;
+
+ /* For unified kernel, NR_CPUS is the maximum possible value,
+ * loongson_sysconf.nr_cpus is the really present value */
+ for (i = 1, num = 0; i < loongson_sysconf.nr_cpus; i++) {
+ set_cpu_possible(i, true);
+ __cpu_number_map[i] = ++num;
+ __cpu_logical_map[num] = i;
+ }
+ pr_info("Detected %i available secondary CPU(s)\n", num);
+}
+
+static void __init loongson3_prepare_cpus(unsigned int max_cpus)
+{
+ init_cpu_present(cpu_possible_mask);
+ per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
+}
+
+/*
+ * Setup the PC, SP, and GP of a secondary processor and start it runing!
+ */
+static void loongson3_boot_secondary(int cpu, struct task_struct *idle)
+{
+ unsigned long startargs[4];
+
+ pr_info("Booting CPU#%d...\n", cpu);
+
+ /* startargs[] are initial PC, SP and GP for secondary CPU */
+ startargs[0] = (unsigned long)&smp_bootstrap;
+ startargs[1] = (unsigned long)__KSTK_TOS(idle);
+ startargs[2] = (unsigned long)task_thread_info(idle);
+ startargs[3] = 0;
+
+ pr_debug("CPU#%d, func_pc=%lx, sp=%lx, gp=%lx\n",
+ cpu, startargs[0], startargs[1], startargs[2]);
+
+ loongson3_ipi_write64(startargs[3], (void *)(ipi_mailbox_buf[cpu]+0x18));
+ loongson3_ipi_write64(startargs[2], (void *)(ipi_mailbox_buf[cpu]+0x10));
+ loongson3_ipi_write64(startargs[1], (void *)(ipi_mailbox_buf[cpu]+0x8));
+ loongson3_ipi_write64(startargs[0], (void *)(ipi_mailbox_buf[cpu]+0x0));
+}
+
+/*
+ * Final cleanup after all secondaries booted
+ */
+static void __init loongson3_cpus_done(void)
+{
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+static int loongson3_cpu_disable(void)
+{
+ unsigned long flags;
+ unsigned int cpu = smp_processor_id();
+
+ if (cpu == 0)
+ return -EBUSY;
+
+ set_cpu_online(cpu, false);
+ cpu_clear(cpu, cpu_callin_map);
+ local_irq_save(flags);
+ fixup_irqs();
+ local_irq_restore(flags);
+ flush_cache_all();
+ local_flush_tlb_all();
+
+ return 0;
+}
+
+
+static void loongson3_cpu_die(unsigned int cpu)
+{
+ while (per_cpu(cpu_state, cpu) != CPU_DEAD)
+ cpu_relax();
+
+ mb();
+}
+
+/* To shutdown a core in Loongson 3, the target core should go to CKSEG1 and
+ * flush all L1 entries at first. Then, another core (usually Core 0) can
+ * safely disable the clock of the target core. loongson3_play_dead() is
+ * called via CKSEG1 (uncached and unmmaped) */
+static void loongson3_play_dead(int *state_addr)
+{
+ register int val;
+ register long cpuid, core, node, count;
+ register void *addr, *base, *initfunc;
+
+ __asm__ __volatile__(
+ " .set push \n"
+ " .set noreorder \n"
+ " li %[addr], 0x80000000 \n" /* KSEG0 */
+ "1: cache 0, 0(%[addr]) \n" /* flush L1 ICache */
+ " cache 0, 1(%[addr]) \n"
+ " cache 0, 2(%[addr]) \n"
+ " cache 0, 3(%[addr]) \n"
+ " cache 1, 0(%[addr]) \n" /* flush L1 DCache */
+ " cache 1, 1(%[addr]) \n"
+ " cache 1, 2(%[addr]) \n"
+ " cache 1, 3(%[addr]) \n"
+ " addiu %[sets], %[sets], -1 \n"
+ " bnez %[sets], 1b \n"
+ " addiu %[addr], %[addr], 0x20 \n"
+ " li %[val], 0x7 \n" /* *state_addr = CPU_DEAD; */
+ " sw %[val], (%[state_addr]) \n"
+ " sync \n"
+ " cache 21, (%[state_addr]) \n" /* flush entry of *state_addr */
+ " .set pop \n"
+ : [addr] "=&r" (addr), [val] "=&r" (val)
+ : [state_addr] "r" (state_addr),
+ [sets] "r" (cpu_data[smp_processor_id()].dcache.sets));
+
+ __asm__ __volatile__(
+ " .set push \n"
+ " .set noreorder \n"
+ " .set mips64 \n"
+ " mfc0 %[cpuid], $15, 1 \n"
+ " andi %[cpuid], 0x3ff \n"
+ " dli %[base], 0x900000003ff01000 \n"
+ " andi %[core], %[cpuid], 0x3 \n"
+ " sll %[core], 8 \n" /* get core id */
+ " or %[base], %[base], %[core] \n"
+ " andi %[node], %[cpuid], 0xc \n"
+ " dsll %[node], 42 \n" /* get node id */
+ " or %[base], %[base], %[node] \n"
+ "1: li %[count], 0x100 \n" /* wait for init loop */
+ "2: bnez %[count], 2b \n" /* limit mailbox access */
+ " addiu %[count], -1 \n"
+ " ld %[initfunc], 0x20(%[base]) \n" /* get PC via mailbox */
+ " beqz %[initfunc], 1b \n"
+ " nop \n"
+ " ld $sp, 0x28(%[base]) \n" /* get SP via mailbox */
+ " ld $gp, 0x30(%[base]) \n" /* get GP via mailbox */
+ " ld $a1, 0x38(%[base]) \n"
+ " jr %[initfunc] \n" /* jump to initial PC */
+ " nop \n"
+ " .set pop \n"
+ : [core] "=&r" (core), [node] "=&r" (node),
+ [base] "=&r" (base), [cpuid] "=&r" (cpuid),
+ [count] "=&r" (count), [initfunc] "=&r" (initfunc)
+ : /* No Input */
+ : "a1");
+}
+
+void play_dead(void)
+{
+ int *state_addr;
+ unsigned int cpu = smp_processor_id();
+ void (*play_dead_at_ckseg1)(int *);
+
+ idle_task_exit();
+ play_dead_at_ckseg1 =
+ (void *)CKSEG1ADDR((unsigned long)loongson3_play_dead);
+ state_addr = &per_cpu(cpu_state, cpu);
+ mb();
+ play_dead_at_ckseg1(state_addr);
+}
+
+#define CPU_POST_DEAD_FROZEN (CPU_POST_DEAD | CPU_TASKS_FROZEN)
+static int loongson3_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+
+ switch (action) {
+ case CPU_POST_DEAD:
+ case CPU_POST_DEAD_FROZEN:
+ pr_info("Disable clock for CPU#%d\n", cpu);
+ LOONGSON_CHIPCFG0 &= ~(1 << (12 + cpu));
+ break;
+ case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
+ pr_info("Enable clock for CPU#%d\n", cpu);
+ LOONGSON_CHIPCFG0 |= 1 << (12 + cpu);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static int register_loongson3_notifier(void)
+{
+ hotcpu_notifier(loongson3_cpu_callback, 0);
+ return 0;
+}
+early_initcall(register_loongson3_notifier);
+
+#endif
+
+struct plat_smp_ops loongson3_smp_ops = {
+ .send_ipi_single = loongson3_send_ipi_single,
+ .send_ipi_mask = loongson3_send_ipi_mask,
+ .init_secondary = loongson3_init_secondary,
+ .smp_finish = loongson3_smp_finish,
+ .cpus_done = loongson3_cpus_done,
+ .boot_secondary = loongson3_boot_secondary,
+ .smp_setup = loongson3_smp_setup,
+ .prepare_cpus = loongson3_prepare_cpus,
+#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_disable = loongson3_cpu_disable,
+ .cpu_die = loongson3_cpu_die,
+#endif
+};
diff --git a/arch/mips/loongson/loongson-3/smp.h b/arch/mips/loongson/loongson-3/smp.h
new file mode 100644
index 000000000000..3453e8c4f2f0
--- /dev/null
+++ b/arch/mips/loongson/loongson-3/smp.h
@@ -0,0 +1,29 @@
+#ifndef __LOONGSON_SMP_H_
+#define __LOONGSON_SMP_H_
+
+/* for Loongson-3A smp support */
+
+/* 4 groups(nodes) in maximum in numa case */
+#define SMP_CORE_GROUP0_BASE 0x900000003ff01000
+#define SMP_CORE_GROUP1_BASE 0x900010003ff01000
+#define SMP_CORE_GROUP2_BASE 0x900020003ff01000
+#define SMP_CORE_GROUP3_BASE 0x900030003ff01000
+
+/* 4 cores in each group(node) */
+#define SMP_CORE0_OFFSET 0x000
+#define SMP_CORE1_OFFSET 0x100
+#define SMP_CORE2_OFFSET 0x200
+#define SMP_CORE3_OFFSET 0x300
+
+/* ipi registers offsets */
+#define STATUS0 0x00
+#define EN0 0x04
+#define SET0 0x08
+#define CLEAR0 0x0c
+#define STATUS1 0x10
+#define MASK1 0x14
+#define SET1 0x18
+#define CLEAR1 0x1c
+#define BUF 0x20
+
+#endif
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index 506925b2c3f3..7b3c9acae689 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -876,20 +876,43 @@ static inline int cop1_64bit(struct pt_regs *xcp)
#endif
}
-#define SIFROMREG(si, x) ((si) = cop1_64bit(xcp) || !(x & 1) ? \
- (int)ctx->fpr[x] : (int)(ctx->fpr[x & ~1] >> 32))
-
-#define SITOREG(si, x) (ctx->fpr[x & ~(cop1_64bit(xcp) == 0)] = \
- cop1_64bit(xcp) || !(x & 1) ? \
- ctx->fpr[x & ~1] >> 32 << 32 | (u32)(si) : \
- ctx->fpr[x & ~1] << 32 >> 32 | (u64)(si) << 32)
-
-#define SIFROMHREG(si, x) ((si) = (int)(ctx->fpr[x] >> 32))
-#define SITOHREG(si, x) (ctx->fpr[x] = \
- ctx->fpr[x] << 32 >> 32 | (u64)(si) << 32)
-
-#define DIFROMREG(di, x) ((di) = ctx->fpr[x & ~(cop1_64bit(xcp) == 0)])
-#define DITOREG(di, x) (ctx->fpr[x & ~(cop1_64bit(xcp) == 0)] = (di))
+#define SIFROMREG(si, x) do { \
+ if (cop1_64bit(xcp)) \
+ (si) = get_fpr32(&ctx->fpr[x], 0); \
+ else \
+ (si) = get_fpr32(&ctx->fpr[(x) & ~1], (x) & 1); \
+} while (0)
+
+#define SITOREG(si, x) do { \
+ if (cop1_64bit(xcp)) { \
+ unsigned i; \
+ set_fpr32(&ctx->fpr[x], 0, si); \
+ for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \
+ set_fpr32(&ctx->fpr[x], i, 0); \
+ } else { \
+ set_fpr32(&ctx->fpr[(x) & ~1], (x) & 1, si); \
+ } \
+} while (0)
+
+#define SIFROMHREG(si, x) ((si) = get_fpr32(&ctx->fpr[x], 1))
+
+#define SITOHREG(si, x) do { \
+ unsigned i; \
+ set_fpr32(&ctx->fpr[x], 1, si); \
+ for (i = 2; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \
+ set_fpr32(&ctx->fpr[x], i, 0); \
+} while (0)
+
+#define DIFROMREG(di, x) \
+ ((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) == 0)], 0))
+
+#define DITOREG(di, x) do { \
+ unsigned fpr, i; \
+ fpr = (x) & ~(cop1_64bit(xcp) == 0); \
+ set_fpr64(&ctx->fpr[fpr], 0, di); \
+ for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val64); i++) \
+ set_fpr64(&ctx->fpr[fpr], i, 0); \
+} while (0)
#define SPFROMREG(sp, x) SIFROMREG((sp).bits, x)
#define SPTOREG(sp, x) SITOREG((sp).bits, x)
@@ -1538,10 +1561,10 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
break;
}
- case 0x7: /* 7 */
- if (MIPSInst_FUNC(ir) != pfetch_op) {
+ case 0x3:
+ if (MIPSInst_FUNC(ir) != pfetch_op)
return SIGILL;
- }
+
/* ignore prefx operation */
break;
@@ -1960,15 +1983,18 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
#if defined(__mips64)
case l_fmt:{
+ u64 bits;
+ DIFROMREG(bits, MIPSInst_FS(ir));
+
switch (MIPSInst_FUNC(ir)) {
case fcvts_op:
/* convert long to single precision real */
- rv.s = ieee754sp_flong(ctx->fpr[MIPSInst_FS(ir)]);
+ rv.s = ieee754sp_flong(bits);
rfmt = s_fmt;
goto copcsr;
case fcvtd_op:
/* convert long to double precision real */
- rv.d = ieee754dp_flong(ctx->fpr[MIPSInst_FS(ir)]);
+ rv.d = ieee754dp_flong(bits);
rfmt = d_fmt;
goto copcsr;
default:
diff --git a/arch/mips/math-emu/kernel_linkage.c b/arch/mips/math-emu/kernel_linkage.c
index 3aeae07ed5b8..eb58a85b3157 100644
--- a/arch/mips/math-emu/kernel_linkage.c
+++ b/arch/mips/math-emu/kernel_linkage.c
@@ -40,78 +40,6 @@ void fpu_emulator_init_fpu(void)
}
current->thread.fpu.fcr31 = 0;
- for (i = 0; i < 32; i++) {
- current->thread.fpu.fpr[i] = SIGNALLING_NAN;
- }
-}
-
-
-/*
- * Emulator context save/restore to/from a signal context
- * presumed to be on the user stack, and therefore accessed
- * with appropriate macros from uaccess.h
- */
-
-int fpu_emulator_save_context(struct sigcontext __user *sc)
-{
- int i;
- int err = 0;
-
- for (i = 0; i < 32; i++) {
- err |=
- __put_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]);
- }
- err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
-
- return err;
-}
-
-int fpu_emulator_restore_context(struct sigcontext __user *sc)
-{
- int i;
- int err = 0;
-
- for (i = 0; i < 32; i++) {
- err |=
- __get_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]);
- }
- err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
-
- return err;
-}
-
-#ifdef CONFIG_64BIT
-/*
- * This is the o32 version
- */
-
-int fpu_emulator_save_context32(struct sigcontext32 __user *sc)
-{
- int i;
- int err = 0;
- int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
-
- for (i = 0; i < 32; i += inc) {
- err |=
- __put_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]);
- }
- err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
-
- return err;
-}
-
-int fpu_emulator_restore_context32(struct sigcontext32 __user *sc)
-{
- int i;
- int err = 0;
- int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
-
- for (i = 0; i < 32; i += inc) {
- err |=
- __get_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]);
- }
- err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
-
- return err;
+ for (i = 0; i < 32; i++)
+ set_fpr64(&current->thread.fpu.fpr[i], 0, SIGNALLING_NAN);
}
-#endif
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index c14259edd53f..1c74a6ad072a 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -57,7 +57,7 @@ static inline void r4k_on_each_cpu(void (*func) (void *info), void *info)
preempt_enable();
}
-#if defined(CONFIG_MIPS_CMP)
+#if defined(CONFIG_MIPS_CMP) || defined(CONFIG_MIPS_CPS)
#define cpu_has_safe_index_cacheops 0
#else
#define cpu_has_safe_index_cacheops 1
@@ -123,6 +123,28 @@ static void r4k_blast_dcache_page_setup(void)
r4k_blast_dcache_page = r4k_blast_dcache_page_dc64;
}
+#ifndef CONFIG_EVA
+#define r4k_blast_dcache_user_page r4k_blast_dcache_page
+#else
+
+static void (*r4k_blast_dcache_user_page)(unsigned long addr);
+
+static void r4k_blast_dcache_user_page_setup(void)
+{
+ unsigned long dc_lsize = cpu_dcache_line_size();
+
+ if (dc_lsize == 0)
+ r4k_blast_dcache_user_page = (void *)cache_noop;
+ else if (dc_lsize == 16)
+ r4k_blast_dcache_user_page = blast_dcache16_user_page;
+ else if (dc_lsize == 32)
+ r4k_blast_dcache_user_page = blast_dcache32_user_page;
+ else if (dc_lsize == 64)
+ r4k_blast_dcache_user_page = blast_dcache64_user_page;
+}
+
+#endif
+
static void (* r4k_blast_dcache_page_indexed)(unsigned long addr);
static void r4k_blast_dcache_page_indexed_setup(void)
@@ -245,6 +267,27 @@ static void r4k_blast_icache_page_setup(void)
r4k_blast_icache_page = blast_icache64_page;
}
+#ifndef CONFIG_EVA
+#define r4k_blast_icache_user_page r4k_blast_icache_page
+#else
+
+static void (*r4k_blast_icache_user_page)(unsigned long addr);
+
+static void __cpuinit r4k_blast_icache_user_page_setup(void)
+{
+ unsigned long ic_lsize = cpu_icache_line_size();
+
+ if (ic_lsize == 0)
+ r4k_blast_icache_user_page = (void *)cache_noop;
+ else if (ic_lsize == 16)
+ r4k_blast_icache_user_page = blast_icache16_user_page;
+ else if (ic_lsize == 32)
+ r4k_blast_icache_user_page = blast_icache32_user_page;
+ else if (ic_lsize == 64)
+ r4k_blast_icache_user_page = blast_icache64_user_page;
+}
+
+#endif
static void (* r4k_blast_icache_page_indexed)(unsigned long addr);
@@ -355,6 +398,7 @@ static inline void local_r4k___flush_cache_all(void * args)
{
switch (current_cpu_type()) {
case CPU_LOONGSON2:
+ case CPU_LOONGSON3:
case CPU_R4000SC:
case CPU_R4000MC:
case CPU_R4400SC:
@@ -519,7 +563,8 @@ static inline void local_r4k_flush_cache_page(void *args)
}
if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) {
- r4k_blast_dcache_page(addr);
+ vaddr ? r4k_blast_dcache_page(addr) :
+ r4k_blast_dcache_user_page(addr);
if (exec && !cpu_icache_snoops_remote_store)
r4k_blast_scache_page(addr);
}
@@ -530,7 +575,8 @@ static inline void local_r4k_flush_cache_page(void *args)
if (cpu_context(cpu, mm) != 0)
drop_mmu_context(mm, cpu);
} else
- r4k_blast_icache_page(addr);
+ vaddr ? r4k_blast_icache_page(addr) :
+ r4k_blast_icache_user_page(addr);
}
if (vaddr) {
@@ -595,6 +641,17 @@ static inline void local_r4k_flush_icache_range(unsigned long start, unsigned lo
break;
}
}
+#ifdef CONFIG_EVA
+ /*
+ * Due to all possible segment mappings, there might cache aliases
+ * caused by the bootloader being in non-EVA mode, and the CPU switching
+ * to EVA during early kernel init. It's best to flush the scache
+ * to avoid having secondary cores fetching stale data and lead to
+ * kernel crashes.
+ */
+ bc_wback_inv(start, (end - start));
+ __sync();
+#endif
}
static inline void local_r4k_flush_icache_range_ipi(void *args)
@@ -617,7 +674,7 @@ static void r4k_flush_icache_range(unsigned long start, unsigned long end)
instruction_hazard();
}
-#ifdef CONFIG_DMA_NONCOHERENT
+#if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_DMA_MAYBE_COHERENT)
static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
{
@@ -688,7 +745,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
bc_inv(addr, size);
__sync();
}
-#endif /* CONFIG_DMA_NONCOHERENT */
+#endif /* CONFIG_DMA_NONCOHERENT || CONFIG_DMA_MAYBE_COHERENT */
/*
* While we're protected against bad userland addresses we don't care
@@ -1010,6 +1067,33 @@ static void probe_pcache(void)
c->dcache.waybit = 0;
break;
+ case CPU_LOONGSON3:
+ config1 = read_c0_config1();
+ lsize = (config1 >> 19) & 7;
+ if (lsize)
+ c->icache.linesz = 2 << lsize;
+ else
+ c->icache.linesz = 0;
+ c->icache.sets = 64 << ((config1 >> 22) & 7);
+ c->icache.ways = 1 + ((config1 >> 16) & 7);
+ icache_size = c->icache.sets *
+ c->icache.ways *
+ c->icache.linesz;
+ c->icache.waybit = 0;
+
+ lsize = (config1 >> 10) & 7;
+ if (lsize)
+ c->dcache.linesz = 2 << lsize;
+ else
+ c->dcache.linesz = 0;
+ c->dcache.sets = 64 << ((config1 >> 13) & 7);
+ c->dcache.ways = 1 + ((config1 >> 7) & 7);
+ dcache_size = c->dcache.sets *
+ c->dcache.ways *
+ c->dcache.linesz;
+ c->dcache.waybit = 0;
+ break;
+
default:
if (!(config & MIPS_CONF_M))
panic("Don't know how to probe P-caches on this cpu.");
@@ -1113,13 +1197,21 @@ static void probe_pcache(void)
case CPU_34K:
case CPU_74K:
case CPU_1004K:
+ case CPU_1074K:
case CPU_INTERAPTIV:
+ case CPU_P5600:
case CPU_PROAPTIV:
- if (current_cpu_type() == CPU_74K)
+ case CPU_M5150:
+ if ((c->cputype == CPU_74K) || (c->cputype == CPU_1074K))
alias_74k_erratum(c);
- if ((read_c0_config7() & (1 << 16))) {
- /* effectively physically indexed dcache,
- thus no virtual aliases. */
+ if (!(read_c0_config7() & MIPS_CONF7_IAR) &&
+ (c->icache.waysize > PAGE_SIZE))
+ c->icache.flags |= MIPS_CACHE_ALIASES;
+ if (read_c0_config7() & MIPS_CONF7_AR) {
+ /*
+ * Effectively physically indexed dcache,
+ * thus no virtual aliases.
+ */
c->dcache.flags |= MIPS_CACHE_PINDEX;
break;
}
@@ -1239,6 +1331,33 @@ static void __init loongson2_sc_init(void)
c->options |= MIPS_CPU_INCLUSIVE_CACHES;
}
+static void __init loongson3_sc_init(void)
+{
+ struct cpuinfo_mips *c = &current_cpu_data;
+ unsigned int config2, lsize;
+
+ config2 = read_c0_config2();
+ lsize = (config2 >> 4) & 15;
+ if (lsize)
+ c->scache.linesz = 2 << lsize;
+ else
+ c->scache.linesz = 0;
+ c->scache.sets = 64 << ((config2 >> 8) & 15);
+ c->scache.ways = 1 + (config2 & 15);
+
+ scache_size = c->scache.sets *
+ c->scache.ways *
+ c->scache.linesz;
+ /* Loongson-3 has 4 cores, 1MB scache for each. scaches are shared */
+ scache_size *= 4;
+ c->scache.waybit = 0;
+ pr_info("Unified secondary cache %ldkB %s, linesize %d bytes.\n",
+ scache_size >> 10, way_string[c->scache.ways], c->scache.linesz);
+ if (scache_size)
+ c->options |= MIPS_CPU_INCLUSIVE_CACHES;
+ return;
+}
+
extern int r5k_sc_init(void);
extern int rm7k_sc_init(void);
extern int mips_sc_init(void);
@@ -1291,6 +1410,10 @@ static void setup_scache(void)
loongson2_sc_init();
return;
+ case CPU_LOONGSON3:
+ loongson3_sc_init();
+ return;
+
case CPU_XLP:
/* don't need to worry about L2, fully coherent */
return;
@@ -1461,6 +1584,10 @@ void r4k_cache_init(void)
r4k_blast_scache_page_setup();
r4k_blast_scache_page_indexed_setup();
r4k_blast_scache_setup();
+#ifdef CONFIG_EVA
+ r4k_blast_dcache_user_page_setup();
+ r4k_blast_icache_user_page_setup();
+#endif
/*
* Some MIPS32 and MIPS64 processors have physically indexed caches.
@@ -1492,7 +1619,7 @@ void r4k_cache_init(void)
flush_icache_range = r4k_flush_icache_range;
local_flush_icache_range = local_r4k_flush_icache_range;
-#if defined(CONFIG_DMA_NONCOHERENT)
+#if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_DMA_MAYBE_COHERENT)
if (coherentio) {
_dma_cache_wback_inv = (void *)cache_noop;
_dma_cache_wback = (void *)cache_noop;
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c
index fde7e56d13fe..e422b38d3113 100644
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -49,7 +49,7 @@ EXPORT_SYMBOL_GPL(local_flush_data_cache_page);
EXPORT_SYMBOL(flush_data_cache_page);
EXPORT_SYMBOL(flush_icache_all);
-#ifdef CONFIG_DMA_NONCOHERENT
+#if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_DMA_MAYBE_COHERENT)
/* DMA cache operations. */
void (*_dma_cache_wback_inv)(unsigned long start, unsigned long size);
@@ -58,7 +58,7 @@ void (*_dma_cache_inv)(unsigned long start, unsigned long size);
EXPORT_SYMBOL(_dma_cache_wback_inv);
-#endif /* CONFIG_DMA_NONCOHERENT */
+#endif /* CONFIG_DMA_NONCOHERENT || CONFIG_DMA_MAYBE_COHERENT */
/*
* We could optimize the case where the cache argument is not BCACHE but
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 6b59617760c1..4fc74c78265a 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -422,10 +422,20 @@ void free_initrd_mem(unsigned long start, unsigned long end)
}
#endif
+void (*free_init_pages_eva)(void *begin, void *end) = NULL;
+
void __init_refok free_initmem(void)
{
prom_free_prom_memory();
- free_initmem_default(POISON_FREE_INITMEM);
+ /*
+ * Let the platform define a specific function to free the
+ * init section since EVA may have used any possible mapping
+ * between virtual and physical addresses.
+ */
+ if (free_init_pages_eva)
+ free_init_pages_eva((void *)&__init_begin, (void *)&__init_end);
+ else
+ free_initmem_default(POISON_FREE_INITMEM);
}
#ifndef CONFIG_MIPS_PGD_C0_CONTEXT
diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c
index 7a56aee5fce7..99eb8fabab60 100644
--- a/arch/mips/mm/sc-mips.c
+++ b/arch/mips/mm/sc-mips.c
@@ -76,8 +76,10 @@ static inline int mips_sc_is_activated(struct cpuinfo_mips *c)
case CPU_34K:
case CPU_74K:
case CPU_1004K:
+ case CPU_1074K:
case CPU_INTERAPTIV:
case CPU_PROAPTIV:
+ case CPU_P5600:
case CPU_BMIPS5000:
if (config2 & (1 << 12))
return 0;
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index ae4ca2450707..eeaf50f5df2b 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -48,13 +48,14 @@ extern void build_tlb_refill_handler(void);
#endif /* CONFIG_MIPS_MT_SMTC */
/*
- * LOONGSON2 has a 4 entry itlb which is a subset of dtlb,
- * unfortrunately, itlb is not totally transparent to software.
+ * LOONGSON2/3 has a 4 entry itlb which is a subset of dtlb,
+ * unfortunately, itlb is not totally transparent to software.
*/
static inline void flush_itlb(void)
{
switch (current_cpu_type()) {
case CPU_LOONGSON2:
+ case CPU_LOONGSON3:
write_c0_diag(4);
break;
default:
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index b234b1b5ccad..ee88367ab3ad 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -509,7 +509,10 @@ static void build_tlb_write_entry(u32 **p, struct uasm_label **l,
switch (current_cpu_type()) {
case CPU_M14KC:
case CPU_74K:
+ case CPU_1074K:
case CPU_PROAPTIV:
+ case CPU_P5600:
+ case CPU_M5150:
break;
default:
@@ -579,6 +582,7 @@ static void build_tlb_write_entry(u32 **p, struct uasm_label **l,
case CPU_BMIPS4380:
case CPU_BMIPS5000:
case CPU_LOONGSON2:
+ case CPU_LOONGSON3:
case CPU_R5500:
if (m4kc_tlbp_war())
uasm_i_nop(p);
@@ -621,7 +625,7 @@ static void build_tlb_write_entry(u32 **p, struct uasm_label **l,
default:
panic("No TLB refill handler yet (CPU type: %d)",
- current_cpu_data.cputype);
+ current_cpu_type());
break;
}
}
diff --git a/arch/mips/mti-malta/malta-amon.c b/arch/mips/mti-malta/malta-amon.c
index 592ac0427426..84ac523b0ce0 100644
--- a/arch/mips/mti-malta/malta-amon.c
+++ b/arch/mips/mti-malta/malta-amon.c
@@ -72,7 +72,7 @@ int amon_cpu_start(int cpu,
return 0;
}
-#ifdef CONFIG_MIPS_VPE_LOADER
+#ifdef CONFIG_MIPS_VPE_LOADER_CMP
int vpe_run(struct vpe *v)
{
struct vpe_notifications *n;
diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c
index fcebfced26d0..4f9e44d358b7 100644
--- a/arch/mips/mti-malta/malta-init.c
+++ b/arch/mips/mti-malta/malta-init.c
@@ -20,7 +20,8 @@
#include <asm/smp-ops.h>
#include <asm/traps.h>
#include <asm/fw/fw.h>
-#include <asm/gcmpregs.h>
+#include <asm/mips-cm.h>
+#include <asm/mips-cpc.h>
#include <asm/mips-boards/generic.h>
#include <asm/mips-boards/malta.h>
@@ -110,6 +111,11 @@ static void __init mips_ejtag_setup(void)
flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
}
+phys_t mips_cpc_default_phys_base(void)
+{
+ return CPC_BASE_ADDR;
+}
+
extern struct plat_smp_ops msmtc_smp_ops;
void __init prom_init(void)
@@ -238,10 +244,23 @@ mips_pci_controller:
MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_MEM_SHF |
MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_BAR0_SHF);
#endif
+#ifndef CONFIG_EVA
/* Fix up target memory mapping. */
MSC_READ(MSC01_PCI_BAR0, mask);
MSC_WRITE(MSC01_PCI_P2SCMSKL, mask & MSC01_PCI_BAR0_SIZE_MSK);
+#else
+ /*
+ * Setup the Malta max (2GB) memory for PCI DMA in host bridge
+ * in transparent addressing mode, starting from 0x80000000.
+ */
+ mask = PHYS_OFFSET | (1<<3);
+ MSC_WRITE(MSC01_PCI_BAR0, mask);
+ mask = PHYS_OFFSET;
+ MSC_WRITE(MSC01_PCI_HEAD4, mask);
+ MSC_WRITE(MSC01_PCI_P2SCMSKL, mask);
+ MSC_WRITE(MSC01_PCI_P2SCMAPL, mask);
+#endif
/* Don't handle target retries indefinitely. */
if ((data & MSC01_PCI_CFG_MAXRTRY_MSK) ==
MSC01_PCI_CFG_MAXRTRY_MSK)
@@ -276,10 +295,13 @@ mips_pci_controller:
console_config();
#endif
/* Early detection of CMP support */
- if (gcmp_probe(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ))
- if (!register_cmp_smp_ops())
- return;
+ mips_cm_probe();
+ mips_cpc_probe();
+ if (!register_cps_smp_ops())
+ return;
+ if (!register_cmp_smp_ops())
+ return;
if (!register_vsmp_smp_ops())
return;
diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
index ca3e3a46a42f..b71ee809191a 100644
--- a/arch/mips/mti-malta/malta-int.c
+++ b/arch/mips/mti-malta/malta-int.c
@@ -26,6 +26,7 @@
#include <asm/i8259.h>
#include <asm/irq_cpu.h>
#include <asm/irq_regs.h>
+#include <asm/mips-cm.h>
#include <asm/mips-boards/malta.h>
#include <asm/mips-boards/maltaint.h>
#include <asm/gt64120.h>
@@ -33,13 +34,10 @@
#include <asm/mips-boards/msc01_pci.h>
#include <asm/msc01_ic.h>
#include <asm/gic.h>
-#include <asm/gcmpregs.h>
#include <asm/setup.h>
#include <asm/rtlx.h>
-int gcmp_present = -1;
static unsigned long _msc01_biu_base;
-static unsigned long _gcmp_base;
static unsigned int ipi_map[NR_CPUS];
static DEFINE_RAW_SPINLOCK(mips_irq_lock);
@@ -119,7 +117,7 @@ static void malta_hw0_irqdispatch(void)
do_IRQ(MALTA_INT_BASE + irq);
-#ifdef MIPS_VPE_APSP_API
+#ifdef CONFIG_MIPS_VPE_APSP_API_MT
if (aprp_hook)
aprp_hook();
#endif
@@ -288,10 +286,6 @@ asmlinkage void plat_irq_dispatch(void)
#ifdef CONFIG_MIPS_MT_SMP
-
-#define GIC_MIPS_CPU_IPI_RESCHED_IRQ 3
-#define GIC_MIPS_CPU_IPI_CALL_IRQ 4
-
#define MIPS_CPU_IPI_RESCHED_IRQ 0 /* SW int 0 for resched */
#define C_RESCHED C_SW0
#define MIPS_CPU_IPI_CALL_IRQ 1 /* SW int 1 for resched */
@@ -308,9 +302,16 @@ static void ipi_call_dispatch(void)
do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ);
}
+#endif /* CONFIG_MIPS_MT_SMP */
+
+#ifdef CONFIG_MIPS_GIC_IPI
+
+#define GIC_MIPS_CPU_IPI_RESCHED_IRQ 3
+#define GIC_MIPS_CPU_IPI_CALL_IRQ 4
+
static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
{
-#ifdef MIPS_VPE_APSP_API
+#ifdef CONFIG_MIPS_VPE_APSP_API_CMP
if (aprp_hook)
aprp_hook();
#endif
@@ -338,7 +339,7 @@ static struct irqaction irq_call = {
.flags = IRQF_PERCPU,
.name = "IPI_call"
};
-#endif /* CONFIG_MIPS_MT_SMP */
+#endif /* CONFIG_MIPS_GIC_IPI */
static int gic_resched_int_base;
static int gic_call_int_base;
@@ -418,49 +419,7 @@ static struct gic_intr_map gic_intr_map[GIC_NUM_INTRS] = {
};
#undef X
-/*
- * GCMP needs to be detected before any SMP initialisation
- */
-int __init gcmp_probe(unsigned long addr, unsigned long size)
-{
- if ((mips_revision_sconid != MIPS_REVISION_SCON_ROCIT) &&
- (mips_revision_sconid != MIPS_REVISION_SCON_GT64120)) {
- gcmp_present = 0;
- pr_debug("GCMP NOT present\n");
- return gcmp_present;
- }
-
- if (gcmp_present >= 0)
- return gcmp_present;
-
- _gcmp_base = (unsigned long) ioremap_nocache(GCMP_BASE_ADDR,
- GCMP_ADDRSPACE_SZ);
- _msc01_biu_base = (unsigned long) ioremap_nocache(MSC01_BIU_REG_BASE,
- MSC01_BIU_ADDRSPACE_SZ);
- gcmp_present = ((GCMPGCB(GCMPB) & GCMP_GCB_GCMPB_GCMPBASE_MSK) ==
- GCMP_BASE_ADDR);
-
- if (gcmp_present)
- pr_debug("GCMP present\n");
- return gcmp_present;
-}
-
-/* Return the number of IOCU's present */
-int __init gcmp_niocu(void)
-{
- return gcmp_present ? ((GCMPGCB(GC) & GCMP_GCB_GC_NUMIOCU_MSK) >>
- GCMP_GCB_GC_NUMIOCU_SHF) : 0;
-}
-
-/* Set GCMP region attributes */
-void __init gcmp_setregion(int region, unsigned long base,
- unsigned long mask, int type)
-{
- GCMPGCBn(CMxBASE, region) = base;
- GCMPGCBn(CMxMASK, region) = mask | type;
-}
-
-#if defined(CONFIG_MIPS_MT_SMP)
+#ifdef CONFIG_MIPS_GIC_IPI
static void __init fill_ipi_map1(int baseintr, int cpu, int cpupin)
{
int intr = baseintr + cpu;
@@ -496,8 +455,8 @@ void __init arch_init_irq(void)
if (!cpu_has_veic)
mips_cpu_irq_init();
- if (gcmp_present) {
- GCMPGCB(GICBA) = GIC_BASE_ADDR | GCMP_GCB_GICBA_EN_MSK;
+ if (mips_cm_present()) {
+ write_gcr_gic_base(GIC_BASE_ADDR | CM_GCR_GIC_BASE_GICEN_MSK);
gic_present = 1;
} else {
if (mips_revision_sconid == MIPS_REVISION_SCON_ROCIT) {
@@ -576,7 +535,7 @@ void __init arch_init_irq(void)
if (gic_present) {
/* FIXME */
int i;
-#if defined(CONFIG_MIPS_MT_SMP)
+#if defined(CONFIG_MIPS_GIC_IPI)
gic_call_int_base = GIC_NUM_INTRS -
(NR_CPUS - nr_cpu_ids) * 2 - nr_cpu_ids;
gic_resched_int_base = gic_call_int_base - nr_cpu_ids;
@@ -584,14 +543,14 @@ void __init arch_init_irq(void)
#endif
gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map,
ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE);
- if (!gcmp_present) {
+ if (!mips_cm_present()) {
/* Enable the GIC */
i = REG(_msc01_biu_base, MSC01_SC_CFG);
REG(_msc01_biu_base, MSC01_SC_CFG) =
(i | (0x1 << MSC01_SC_CFG_GICENA_SHF));
pr_debug("GIC Enabled\n");
}
-#if defined(CONFIG_MIPS_MT_SMP)
+#if defined(CONFIG_MIPS_GIC_IPI)
/* set up ipi interrupts */
if (cpu_has_vint) {
set_vi_handler(MIPSCPU_INT_IPI0, malta_ipi_irqdispatch);
@@ -708,16 +667,16 @@ int malta_be_handler(struct pt_regs *regs, int is_fixup)
/* This duplicates the handling in do_be which seems wrong */
int retval = is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL;
- if (gcmp_present) {
- unsigned long cm_error = GCMPGCB(GCMEC);
- unsigned long cm_addr = GCMPGCB(GCMEA);
- unsigned long cm_other = GCMPGCB(GCMEO);
+ if (mips_cm_present()) {
+ unsigned long cm_error = read_gcr_error_cause();
+ unsigned long cm_addr = read_gcr_error_addr();
+ unsigned long cm_other = read_gcr_error_mult();
unsigned long cause, ocause;
char buf[256];
- cause = (cm_error & GCMP_GCB_GMEC_ERROR_TYPE_MSK);
+ cause = cm_error & CM_GCR_ERROR_CAUSE_ERRTYPE_MSK;
if (cause != 0) {
- cause >>= GCMP_GCB_GMEC_ERROR_TYPE_SHF;
+ cause >>= CM_GCR_ERROR_CAUSE_ERRTYPE_SHF;
if (cause < 16) {
unsigned long cca_bits = (cm_error >> 15) & 7;
unsigned long tr_bits = (cm_error >> 12) & 7;
@@ -748,8 +707,8 @@ int malta_be_handler(struct pt_regs *regs, int is_fixup)
mcmd[cmd_bits], sport_bits);
}
- ocause = (cm_other & GCMP_GCB_GMEO_ERROR_2ND_MSK) >>
- GCMP_GCB_GMEO_ERROR_2ND_SHF;
+ ocause = (cm_other & CM_GCR_ERROR_MULT_ERR2ND_MSK) >>
+ CM_GCR_ERROR_MULT_ERR2ND_SHF;
pr_err("CM_ERROR=%08lx %s <%s>\n", cm_error,
causes[cause], buf);
@@ -757,7 +716,7 @@ int malta_be_handler(struct pt_regs *regs, int is_fixup)
pr_err("CM_OTHER=%08lx %s\n", cm_other, causes[ocause]);
/* reprime cause register */
- GCMPGCB(GCMEC) = 0;
+ write_gcr_error_cause(0);
}
}
diff --git a/arch/mips/mti-malta/malta-memory.c b/arch/mips/mti-malta/malta-memory.c
index 1f73d63e92a7..6d0f4ab3632d 100644
--- a/arch/mips/mti-malta/malta-memory.c
+++ b/arch/mips/mti-malta/malta-memory.c
@@ -24,22 +24,30 @@ static fw_memblock_t mdesc[FW_MAX_MEMBLOCKS];
/* determined physical memory size, not overridden by command line args */
unsigned long physical_memsize = 0L;
-fw_memblock_t * __init fw_getmdesc(void)
+fw_memblock_t * __init fw_getmdesc(int eva)
{
- char *memsize_str, *ptr;
- unsigned int memsize;
+ char *memsize_str, *ememsize_str __maybe_unused = NULL, *ptr;
+ unsigned long memsize, ememsize __maybe_unused = 0;
static char cmdline[COMMAND_LINE_SIZE] __initdata;
- long val;
int tmp;
/* otherwise look in the environment */
+
memsize_str = fw_getenv("memsize");
- if (!memsize_str) {
+ if (memsize_str)
+ tmp = kstrtol(memsize_str, 0, &memsize);
+ if (eva) {
+ /* Look for ememsize for EVA */
+ ememsize_str = fw_getenv("ememsize");
+ if (ememsize_str)
+ tmp = kstrtol(ememsize_str, 0, &ememsize);
+ }
+ if (!memsize && !ememsize) {
pr_warn("memsize not set in YAMON, set to default (32Mb)\n");
physical_memsize = 0x02000000;
} else {
- tmp = kstrtol(memsize_str, 0, &val);
- physical_memsize = (unsigned long)val;
+ /* If ememsize is set, then set physical_memsize to that */
+ physical_memsize = ememsize ? : memsize;
}
#ifdef CONFIG_CPU_BIG_ENDIAN
@@ -54,20 +62,30 @@ fw_memblock_t * __init fw_getmdesc(void)
ptr = strstr(cmdline, "memsize=");
if (ptr && (ptr != cmdline) && (*(ptr - 1) != ' '))
ptr = strstr(ptr, " memsize=");
+ /* And now look for ememsize */
+ if (eva) {
+ ptr = strstr(cmdline, "ememsize=");
+ if (ptr && (ptr != cmdline) && (*(ptr - 1) != ' '))
+ ptr = strstr(ptr, " ememsize=");
+ }
if (ptr)
- memsize = memparse(ptr + 8, &ptr);
+ memsize = memparse(ptr + 8 + (eva ? 1 : 0), &ptr);
else
memsize = physical_memsize;
+ /* Last 64K for HIGHMEM arithmetics */
+ if (memsize > 0x7fff0000)
+ memsize = 0x7fff0000;
+
memset(mdesc, 0, sizeof(mdesc));
mdesc[0].type = fw_dontuse;
- mdesc[0].base = 0x00000000;
+ mdesc[0].base = PHYS_OFFSET;
mdesc[0].size = 0x00001000;
mdesc[1].type = fw_code;
- mdesc[1].base = 0x00001000;
+ mdesc[1].base = mdesc[0].base + 0x00001000UL;
mdesc[1].size = 0x000ef000;
/*
@@ -78,21 +96,27 @@ fw_memblock_t * __init fw_getmdesc(void)
* devices.
*/
mdesc[2].type = fw_dontuse;
- mdesc[2].base = 0x000f0000;
+ mdesc[2].base = mdesc[0].base + 0x000f0000UL;
mdesc[2].size = 0x00010000;
mdesc[3].type = fw_dontuse;
- mdesc[3].base = 0x00100000;
+ mdesc[3].base = mdesc[0].base + 0x00100000UL;
mdesc[3].size = CPHYSADDR(PFN_ALIGN((unsigned long)&_end)) -
- mdesc[3].base;
+ 0x00100000UL;
mdesc[4].type = fw_free;
- mdesc[4].base = CPHYSADDR(PFN_ALIGN(&_end));
- mdesc[4].size = memsize - mdesc[4].base;
+ mdesc[4].base = mdesc[0].base + CPHYSADDR(PFN_ALIGN(&_end));
+ mdesc[4].size = memsize - CPHYSADDR(mdesc[4].base);
return &mdesc[0];
}
+static void free_init_pages_eva_malta(void *begin, void *end)
+{
+ free_init_pages("unused kernel", __pa_symbol((unsigned long *)begin),
+ __pa_symbol((unsigned long *)end));
+}
+
static int __init fw_memtype_classify(unsigned int type)
{
switch (type) {
@@ -109,7 +133,9 @@ void __init fw_meminit(void)
{
fw_memblock_t *p;
- p = fw_getmdesc();
+ p = fw_getmdesc(config_enabled(CONFIG_EVA));
+ free_init_pages_eva = (config_enabled(CONFIG_EVA) ?
+ free_init_pages_eva_malta : NULL);
while (p->size) {
long type;
diff --git a/arch/mips/mti-malta/malta-setup.c b/arch/mips/mti-malta/malta-setup.c
index c72a06936781..bf621516afff 100644
--- a/arch/mips/mti-malta/malta-setup.c
+++ b/arch/mips/mti-malta/malta-setup.c
@@ -26,12 +26,12 @@
#include <linux/time.h>
#include <asm/fw/fw.h>
+#include <asm/mips-cm.h>
#include <asm/mips-boards/generic.h>
#include <asm/mips-boards/malta.h>
#include <asm/mips-boards/maltaint.h>
#include <asm/dma.h>
#include <asm/traps.h>
-#include <asm/gcmpregs.h>
#ifdef CONFIG_VT
#include <linux/console.h>
#endif
@@ -127,7 +127,7 @@ static int __init plat_enable_iocoherency(void)
BONITO_PCIMEMBASECFG_MEMBASE1_CACHED);
pr_info("Enabled Bonito IOBC coherency\n");
}
- } else if (gcmp_niocu() != 0) {
+ } else if (mips_cm_numiocu() != 0) {
/* Nothing special needs to be done to enable coherency */
pr_info("CMP IOCU detected\n");
if ((*(unsigned int *)0xbf403000 & 0x81) != 0x81) {
@@ -165,7 +165,6 @@ static void __init plat_setup_iocoherency(void)
#endif
}
-#ifdef CONFIG_BLK_DEV_IDE
static void __init pci_clock_check(void)
{
unsigned int __iomem *jmpr_p =
@@ -175,18 +174,25 @@ static void __init pci_clock_check(void)
33, 20, 25, 30, 12, 16, 37, 10
};
int pciclock = pciclocks[jmpr];
- char *argptr = fw_getcmdline();
+ char *optptr, *argptr = fw_getcmdline();
- if (pciclock != 33 && !strstr(argptr, "idebus=")) {
- pr_warn("WARNING: PCI clock is %dMHz, setting idebus\n",
+ /*
+ * If user passed a pci_clock= option, don't tack on another one
+ */
+ optptr = strstr(argptr, "pci_clock=");
+ if (optptr && (optptr == argptr || optptr[-1] == ' '))
+ return;
+
+ if (pciclock != 33) {
+ pr_warn("WARNING: PCI clock is %dMHz, setting pci_clock\n",
pciclock);
argptr += strlen(argptr);
- sprintf(argptr, " idebus=%d", pciclock);
+ sprintf(argptr, " pci_clock=%d", pciclock);
if (pciclock < 20 || pciclock > 66)
- pr_warn("WARNING: IDE timing calculations will be incorrect\n");
+ pr_warn("WARNING: IDE timing calculations will be "
+ "incorrect\n");
}
}
-#endif
#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
static void __init screen_info_setup(void)
@@ -247,6 +253,10 @@ void __init plat_mem_setup(void)
{
unsigned int i;
+ if (config_enabled(CONFIG_EVA))
+ /* EVA has already been configured in mach-malta/kernel-init.h */
+ pr_info("Enhanced Virtual Addressing (EVA) activated\n");
+
mips_pcibios_init();
/* Request I/O space for devices used on the Malta board. */
@@ -268,9 +278,7 @@ void __init plat_mem_setup(void)
plat_setup_iocoherency();
-#ifdef CONFIG_BLK_DEV_IDE
pci_clock_check();
-#endif
#ifdef CONFIG_BLK_DEV_FD
fd_activate();
diff --git a/arch/mips/mti-sead3/sead3-mtd.c b/arch/mips/mti-sead3/sead3-mtd.c
index ffa35f509789..f9c890d72677 100644
--- a/arch/mips/mti-sead3/sead3-mtd.c
+++ b/arch/mips/mti-sead3/sead3-mtd.c
@@ -50,5 +50,4 @@ static int __init sead3_mtd_init(void)
return 0;
}
-
-module_init(sead3_mtd_init)
+device_initcall(sead3_mtd_init);
diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c
index 2a86e38872a7..e74732449478 100644
--- a/arch/mips/oprofile/common.c
+++ b/arch/mips/oprofile/common.c
@@ -86,8 +86,11 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
case CPU_34K:
case CPU_1004K:
case CPU_74K:
+ case CPU_1074K:
case CPU_INTERAPTIV:
case CPU_PROAPTIV:
+ case CPU_P5600:
+ case CPU_M5150:
case CPU_LOONGSON1:
case CPU_SB1:
case CPU_SB1A:
diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c
index 4d94d75ec6f9..42821ae2d77e 100644
--- a/arch/mips/oprofile/op_model_mipsxx.c
+++ b/arch/mips/oprofile/op_model_mipsxx.c
@@ -372,6 +372,7 @@ static int __init mipsxx_init(void)
op_model_mipsxx_ops.cpu_type = "mips/34K";
break;
+ case CPU_1074K:
case CPU_74K:
op_model_mipsxx_ops.cpu_type = "mips/74K";
break;
@@ -384,6 +385,14 @@ static int __init mipsxx_init(void)
op_model_mipsxx_ops.cpu_type = "mips/proAptiv";
break;
+ case CPU_P5600:
+ op_model_mipsxx_ops.cpu_type = "mips/P5600";
+ break;
+
+ case CPU_M5150:
+ op_model_mipsxx_ops.cpu_type = "mips/M5150";
+ break;
+
case CPU_5KC:
op_model_mipsxx_ops.cpu_type = "mips/5K";
break;
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index 137f2a6feb25..d61138a177cc 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_LASAT) += pci-lasat.o
obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o
obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-loongson2.o
obj-$(CONFIG_LEMOTE_MACH2F) += fixup-lemote2f.o ops-loongson2.o
+obj-$(CONFIG_LEMOTE_MACH3A) += fixup-loongson3.o ops-loongson3.o
obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o pci-malta.o
obj-$(CONFIG_PMC_MSP7120_GW) += fixup-pmcmsp.o ops-pmcmsp.o
obj-$(CONFIG_PMC_MSP7120_EVAL) += fixup-pmcmsp.o ops-pmcmsp.o
diff --git a/arch/mips/pci/fixup-loongson3.c b/arch/mips/pci/fixup-loongson3.c
new file mode 100644
index 000000000000..d708ae46d325
--- /dev/null
+++ b/arch/mips/pci/fixup-loongson3.c
@@ -0,0 +1,66 @@
+/*
+ * fixup-loongson3.c
+ *
+ * Copyright (C) 2012 Lemote, Inc.
+ * Author: Xiang Yu, xiangy@lemote.com
+ * Chen Huacai, chenhc@lemote.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 SOFTWARE IS PROVIDED ``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 AUTHOR 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.
+ *
+ */
+
+#include <linux/pci.h>
+#include <boot_param.h>
+
+static void print_fixup_info(const struct pci_dev *pdev)
+{
+ dev_info(&pdev->dev, "Device %x:%x, irq %d\n",
+ pdev->vendor, pdev->device, pdev->irq);
+}
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ print_fixup_info(dev);
+ return dev->irq;
+}
+
+static void pci_fixup_radeon(struct pci_dev *pdev)
+{
+ if (pdev->resource[PCI_ROM_RESOURCE].start)
+ return;
+
+ if (!loongson_sysconf.vgabios_addr)
+ return;
+
+ pdev->resource[PCI_ROM_RESOURCE].start =
+ loongson_sysconf.vgabios_addr;
+ pdev->resource[PCI_ROM_RESOURCE].end =
+ loongson_sysconf.vgabios_addr + 256*1024 - 1;
+ pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_COPY;
+
+ dev_info(&pdev->dev, "BAR %d: assigned %pR for Radeon ROM\n",
+ PCI_ROM_RESOURCE, &pdev->resource[PCI_ROM_RESOURCE]);
+}
+
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_ATI, PCI_ANY_ID,
+ PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_radeon);
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
diff --git a/arch/mips/pci/fixup-malta.c b/arch/mips/pci/fixup-malta.c
index 7a0eda782e35..2f9e52a1a750 100644
--- a/arch/mips/pci/fixup-malta.c
+++ b/arch/mips/pci/fixup-malta.c
@@ -51,6 +51,19 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
return 0;
}
+static void malta_piix_func3_base_fixup(struct pci_dev *dev)
+{
+ /* Set a sane PM I/O base address */
+ pci_write_config_word(dev, PIIX4_FUNC3_PMBA, 0x1000);
+
+ /* Enable access to the PM I/O region */
+ pci_write_config_byte(dev, PIIX4_FUNC3_PMREGMISC,
+ PIIX4_FUNC3_PMREGMISC_EN);
+}
+
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
+ malta_piix_func3_base_fixup);
+
static void malta_piix_func0_fixup(struct pci_dev *pdev)
{
unsigned char reg_val;
diff --git a/arch/mips/pci/msi-octeon.c b/arch/mips/pci/msi-octeon.c
index d37be36dc659..2b91b0e61566 100644
--- a/arch/mips/pci/msi-octeon.c
+++ b/arch/mips/pci/msi-octeon.c
@@ -150,6 +150,7 @@ msi_irq_allocated:
msg.address_lo =
((128ul << 20) + CVMX_PCI_MSI_RCV) & 0xffffffff;
msg.address_hi = ((128ul << 20) + CVMX_PCI_MSI_RCV) >> 32;
+ break;
case OCTEON_DMA_BAR_TYPE_BIG:
/* When using big bar, Bar 0 is based at 0 */
msg.address_lo = (0 + CVMX_PCI_MSI_RCV) & 0xffffffff;
diff --git a/arch/mips/pci/ops-loongson3.c b/arch/mips/pci/ops-loongson3.c
new file mode 100644
index 000000000000..46ed541a3ec7
--- /dev/null
+++ b/arch/mips/pci/ops-loongson3.c
@@ -0,0 +1,101 @@
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+
+#include <asm/mips-boards/bonito64.h>
+
+#include <loongson.h>
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+#define HT1LO_PCICFG_BASE 0x1a000000
+#define HT1LO_PCICFG_BASE_TP1 0x1b000000
+
+static int loongson3_pci_config_access(unsigned char access_type,
+ struct pci_bus *bus, unsigned int devfn,
+ int where, u32 *data)
+{
+ unsigned char busnum = bus->number;
+ u_int64_t addr, type;
+ void *addrp;
+ int device = PCI_SLOT(devfn);
+ int function = PCI_FUNC(devfn);
+ int reg = where & ~3;
+
+ addr = (busnum << 16) | (device << 11) | (function << 8) | reg;
+ if (busnum == 0) {
+ if (device > 31)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ addrp = (void *)(TO_UNCAC(HT1LO_PCICFG_BASE) | (addr & 0xffff));
+ type = 0;
+
+ } else {
+ addrp = (void *)(TO_UNCAC(HT1LO_PCICFG_BASE_TP1) | (addr));
+ type = 0x10000;
+ }
+
+ if (access_type == PCI_ACCESS_WRITE)
+ writel(*data, addrp);
+ else {
+ *data = readl(addrp);
+ if (*data == 0xffffffff) {
+ *data = -1;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int loongson3_pci_pcibios_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ u32 data = 0;
+ int ret = loongson3_pci_config_access(PCI_ACCESS_READ,
+ bus, devfn, where, &data);
+
+ if (ret != PCIBIOS_SUCCESSFUL)
+ return ret;
+
+ if (size == 1)
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+ else if (size == 2)
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+ else
+ *val = data;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int loongson3_pci_pcibios_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ u32 data = 0;
+ int ret;
+
+ if (size == 4)
+ data = val;
+ else {
+ ret = loongson3_pci_config_access(PCI_ACCESS_READ,
+ bus, devfn, where, &data);
+ if (ret != PCIBIOS_SUCCESSFUL)
+ return ret;
+
+ if (size == 1)
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ else if (size == 2)
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ }
+
+ ret = loongson3_pci_config_access(PCI_ACCESS_WRITE,
+ bus, devfn, where, &data);
+
+ return ret;
+}
+
+struct pci_ops loongson_pci_ops = {
+ .read = loongson3_pci_pcibios_read,
+ .write = loongson3_pci_pcibios_write
+};
diff --git a/arch/mips/pci/pci-alchemy.c b/arch/mips/pci/pci-alchemy.c
index d1faece21b6a..563d1f61d6ee 100644
--- a/arch/mips/pci/pci-alchemy.c
+++ b/arch/mips/pci/pci-alchemy.c
@@ -16,6 +16,7 @@
#include <linux/syscore_ops.h>
#include <linux/vmalloc.h>
+#include <asm/dma-coherence.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/tlbmisc.h>
@@ -411,17 +412,15 @@ static int alchemy_pci_probe(struct platform_device *pdev)
}
ctx->alchemy_pci_ctrl.io_map_base = (unsigned long)virt_io;
-#ifdef CONFIG_DMA_NONCOHERENT
/* Au1500 revisions older than AD have borked coherent PCI */
if ((alchemy_get_cputype() == ALCHEMY_CPU_AU1500) &&
- (read_c0_prid() < 0x01030202)) {
+ (read_c0_prid() < 0x01030202) && !coherentio) {
val = __raw_readl(ctx->regs + PCI_REG_CONFIG);
val |= PCI_CONFIG_NC;
__raw_writel(val, ctx->regs + PCI_REG_CONFIG);
wmb();
dev_info(&pdev->dev, "non-coherent PCI on Au1500 AA/AB/AC\n");
}
-#endif
if (pd->board_map_irq)
ctx->board_map_irq = pd->board_map_irq;
diff --git a/arch/mips/pci/pci-malta.c b/arch/mips/pci/pci-malta.c
index f1a73890dd4f..cfbbc3e3e914 100644
--- a/arch/mips/pci/pci-malta.c
+++ b/arch/mips/pci/pci-malta.c
@@ -27,7 +27,7 @@
#include <linux/init.h>
#include <asm/gt64120.h>
-#include <asm/gcmpregs.h>
+#include <asm/mips-cm.h>
#include <asm/mips-boards/generic.h>
#include <asm/mips-boards/bonito64.h>
#include <asm/mips-boards/msc01_pci.h>
@@ -201,11 +201,11 @@ void __init mips_pcibios_init(void)
msc_mem_resource.start = start & mask;
msc_mem_resource.end = (start & mask) | ~mask;
msc_controller.mem_offset = (start & mask) - (map & mask);
-#ifdef CONFIG_MIPS_CMP
- if (gcmp_niocu())
- gcmp_setregion(0, start, mask,
- GCMP_GCB_GCMPB_CMDEFTGT_IOCU1);
-#endif
+ if (mips_cm_numiocu()) {
+ write_gcr_reg0_base(start);
+ write_gcr_reg0_mask(mask |
+ CM_GCR_REGn_MASK_CMTGT_IOCU0);
+ }
MSC_READ(MSC01_PCI_SC2PIOBASL, start);
MSC_READ(MSC01_PCI_SC2PIOMSKL, mask);
MSC_READ(MSC01_PCI_SC2PIOMAPL, map);
@@ -213,11 +213,11 @@ void __init mips_pcibios_init(void)
msc_io_resource.end = (map & mask) | ~mask;
msc_controller.io_offset = 0;
ioport_resource.end = ~mask;
-#ifdef CONFIG_MIPS_CMP
- if (gcmp_niocu())
- gcmp_setregion(1, start, mask,
- GCMP_GCB_GCMPB_CMDEFTGT_IOCU1);
-#endif
+ if (mips_cm_numiocu()) {
+ write_gcr_reg1_base(start);
+ write_gcr_reg1_mask(mask |
+ CM_GCR_REGn_MASK_CMTGT_IOCU0);
+ }
/* If ranges overlap I/O takes precedence. */
start = start & mask;
end = start | ~mask;
diff --git a/arch/mips/pmcs-msp71xx/msp_setup.c b/arch/mips/pmcs-msp71xx/msp_setup.c
index 396b2967ad85..7e980767679c 100644
--- a/arch/mips/pmcs-msp71xx/msp_setup.c
+++ b/arch/mips/pmcs-msp71xx/msp_setup.c
@@ -49,7 +49,7 @@ void msp7120_reset(void)
/* Cache the reset code of this function */
__asm__ __volatile__ (
" .set push \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" la %0,startpoint \n"
" la %1,endpoint \n"
" .set pop \n"
diff --git a/arch/mips/power/hibernate.S b/arch/mips/power/hibernate.S
index 7e0277a1048f..32a7c828f073 100644
--- a/arch/mips/power/hibernate.S
+++ b/arch/mips/power/hibernate.S
@@ -43,6 +43,7 @@ LEAF(swsusp_arch_resume)
bne t1, t3, 1b
PTR_L t0, PBE_NEXT(t0)
bnez t0, 0b
+ jal local_flush_tlb_all /* Avoid TLB mismatch after kernel resume */
PTR_LA t0, saved_regs
PTR_L ra, PT_R31(t0)
PTR_L sp, PT_R29(t0)
diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig
index 1bfd1c17b3c2..4a296655f446 100644
--- a/arch/mips/ralink/Kconfig
+++ b/arch/mips/ralink/Kconfig
@@ -20,19 +20,13 @@ choice
config SOC_RT305X
bool "RT305x"
select USB_ARCH_HAS_HCD
- select USB_ARCH_HAS_OHCI
- select USB_ARCH_HAS_EHCI
config SOC_RT3883
bool "RT3883"
- select USB_ARCH_HAS_OHCI
- select USB_ARCH_HAS_EHCI
select HW_HAS_PCI
config SOC_MT7620
bool "MT7620"
- select USB_ARCH_HAS_OHCI
- select USB_ARCH_HAS_EHCI
endchoice
diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c
index 3db64d51798d..58b40ae59335 100644
--- a/arch/mips/sgi-ip22/ip22-int.c
+++ b/arch/mips/sgi-ip22/ip22-int.c
@@ -148,7 +148,7 @@ static void __irq_entry indy_buserror_irq(void)
int irq = SGI_BUSERR_IRQ;
irq_enter();
- kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+ kstat_incr_irq_this_cpu(irq);
ip22_be_interrupt(irq);
irq_exit();
}
diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c
index 607192449335..045aa89f28d8 100644
--- a/arch/mips/sgi-ip22/ip22-time.c
+++ b/arch/mips/sgi-ip22/ip22-time.c
@@ -123,7 +123,7 @@ void __irq_entry indy_8254timer_irq(void)
char c;
irq_enter();
- kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+ kstat_incr_irq_this_cpu(irq);
printk(KERN_ALERT "Oops, got 8254 interrupt.\n");
ArcRead(0, &c, 1, &cnt);
ArcEnterInteractiveMode();
diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c
index 09d6e16a70f1..59cfe2659771 100644
--- a/arch/mips/sibyte/bcm1480/irq.c
+++ b/arch/mips/sibyte/bcm1480/irq.c
@@ -95,7 +95,7 @@ static int bcm1480_set_affinity(struct irq_data *d, const struct cpumask *mask,
u64 cur_ints;
unsigned long flags;
- i = cpumask_first(mask);
+ i = cpumask_first_and(mask, cpu_online_mask);
/* Convert logical CPU to physical CPU */
cpu = cpu_logical_map(i);
diff --git a/arch/mips/sibyte/bcm1480/smp.c b/arch/mips/sibyte/bcm1480/smp.c
index 54e2c4de15c1..70d9182b26f1 100644
--- a/arch/mips/sibyte/bcm1480/smp.c
+++ b/arch/mips/sibyte/bcm1480/smp.c
@@ -182,7 +182,7 @@ void bcm1480_mailbox_interrupt(void)
int irq = K_BCM1480_INT_MBOX_0_0;
unsigned int action;
- kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+ kstat_incr_irq_this_cpu(irq);
/* Load the mailbox register to figure out what we're supposed to do */
action = (__raw_readq(mailbox_0_regs[cpu]) >> 48) & 0xffff;
diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c
index fca0cdb99509..6d8dba5cf348 100644
--- a/arch/mips/sibyte/sb1250/irq.c
+++ b/arch/mips/sibyte/sb1250/irq.c
@@ -88,7 +88,7 @@ static int sb1250_set_affinity(struct irq_data *d, const struct cpumask *mask,
u64 cur_ints;
unsigned long flags;
- i = cpumask_first(mask);
+ i = cpumask_first_and(mask, cpu_online_mask);
/* Convert logical CPU to physical CPU */
cpu = cpu_logical_map(i);
diff --git a/arch/mips/sibyte/sb1250/smp.c b/arch/mips/sibyte/sb1250/smp.c
index d7b942db0ea5..db976117dd4d 100644
--- a/arch/mips/sibyte/sb1250/smp.c
+++ b/arch/mips/sibyte/sb1250/smp.c
@@ -170,7 +170,7 @@ void sb1250_mailbox_interrupt(void)
int irq = K_INT_MBOX_0;
unsigned int action;
- kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+ kstat_incr_irq_this_cpu(irq);
/* Load the mailbox register to figure out what we're supposed to do */
action = (____raw_readq(mailbox_regs[cpu]) >> 48) & 0xffff;
diff --git a/arch/mn10300/include/asm/Kbuild b/arch/mn10300/include/asm/Kbuild
index 992e989ab785..654d5ba6e310 100644
--- a/arch/mn10300/include/asm/Kbuild
+++ b/arch/mn10300/include/asm/Kbuild
@@ -1,7 +1,9 @@
generic-y += barrier.h
generic-y += clkdev.h
+generic-y += cputime.h
generic-y += exec.h
generic-y += hash.h
-generic-y += trace_clock.h
+generic-y += mcs_spinlock.h
generic-y += preempt.h
+generic-y += trace_clock.h
diff --git a/arch/mn10300/include/asm/cputime.h b/arch/mn10300/include/asm/cputime.h
deleted file mode 100644
index 6d68ad7e0ea3..000000000000
--- a/arch/mn10300/include/asm/cputime.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/cputime.h>
diff --git a/arch/mn10300/kernel/cevt-mn10300.c b/arch/mn10300/kernel/cevt-mn10300.c
index ccce35e3e179..60f64ca1752a 100644
--- a/arch/mn10300/kernel/cevt-mn10300.c
+++ b/arch/mn10300/kernel/cevt-mn10300.c
@@ -113,7 +113,7 @@ int __init init_clockevents(void)
cd->set_next_event = next_event;
iact = &per_cpu(timer_irq, cpu);
- iact->flags = IRQF_DISABLED | IRQF_SHARED | IRQF_TIMER;
+ iact->flags = IRQF_SHARED | IRQF_TIMER;
iact->handler = timer_interrupt;
clockevents_register_device(cd);
diff --git a/arch/mn10300/kernel/mn10300-serial.c b/arch/mn10300/kernel/mn10300-serial.c
index bf6e949a2f87..7ecf69879e2d 100644
--- a/arch/mn10300/kernel/mn10300-serial.c
+++ b/arch/mn10300/kernel/mn10300-serial.c
@@ -985,17 +985,17 @@ static int mn10300_serial_startup(struct uart_port *_port)
irq_set_chip(port->tm_irq, &mn10300_serial_pic);
if (request_irq(port->rx_irq, mn10300_serial_interrupt,
- IRQF_DISABLED | IRQF_NOBALANCING,
+ IRQF_NOBALANCING,
port->rx_name, port) < 0)
goto error;
if (request_irq(port->tx_irq, mn10300_serial_interrupt,
- IRQF_DISABLED | IRQF_NOBALANCING,
+ IRQF_NOBALANCING,
port->tx_name, port) < 0)
goto error2;
if (request_irq(port->tm_irq, mn10300_serial_interrupt,
- IRQF_DISABLED | IRQF_NOBALANCING,
+ IRQF_NOBALANCING,
port->tm_name, port) < 0)
goto error3;
mn10300_serial_mask_ack(port->tm_irq);
diff --git a/arch/mn10300/kernel/mn10300-watchdog.c b/arch/mn10300/kernel/mn10300-watchdog.c
index db64a7166c09..a2d8e6938d67 100644
--- a/arch/mn10300/kernel/mn10300-watchdog.c
+++ b/arch/mn10300/kernel/mn10300-watchdog.c
@@ -142,7 +142,7 @@ void watchdog_interrupt(struct pt_regs *regs, enum exception_code excep)
NMICR = NMICR_WDIF;
nmi_count(smp_processor_id())++;
- kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+ kstat_incr_irq_this_cpu(irq);
for_each_online_cpu(cpu) {
diff --git a/arch/mn10300/kernel/smp.c b/arch/mn10300/kernel/smp.c
index a17f9c9c14c9..f984193718b1 100644
--- a/arch/mn10300/kernel/smp.c
+++ b/arch/mn10300/kernel/smp.c
@@ -143,7 +143,7 @@ static struct irqaction call_function_ipi = {
static irqreturn_t smp_ipi_timer_interrupt(int irq, void *dev_id);
static struct irqaction local_timer_ipi = {
.handler = smp_ipi_timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_NOBALANCING,
+ .flags = IRQF_NOBALANCING,
.name = "smp local timer IPI"
};
#endif
diff --git a/arch/mn10300/unit-asb2364/irq-fpga.c b/arch/mn10300/unit-asb2364/irq-fpga.c
index e16c216f31dc..073e2ccc4a44 100644
--- a/arch/mn10300/unit-asb2364/irq-fpga.c
+++ b/arch/mn10300/unit-asb2364/irq-fpga.c
@@ -76,7 +76,7 @@ static irqreturn_t fpga_interrupt(int irq, void *_mask)
static struct irqaction fpga_irq[] = {
[0] = {
.handler = fpga_interrupt,
- .flags = IRQF_DISABLED | IRQF_SHARED,
+ .flags = IRQF_SHARED,
.name = "fpga",
},
};
diff --git a/arch/openrisc/include/asm/Kbuild b/arch/openrisc/include/asm/Kbuild
index 2e40f1ca8667..480af0d9c2f5 100644
--- a/arch/openrisc/include/asm/Kbuild
+++ b/arch/openrisc/include/asm/Kbuild
@@ -10,8 +10,8 @@ generic-y += bugs.h
generic-y += cacheflush.h
generic-y += checksum.h
generic-y += clkdev.h
-generic-y += cmpxchg.h
generic-y += cmpxchg-local.h
+generic-y += cmpxchg.h
generic-y += cputime.h
generic-y += current.h
generic-y += device.h
@@ -25,6 +25,7 @@ generic-y += fcntl.h
generic-y += ftrace.h
generic-y += futex.h
generic-y += hardirq.h
+generic-y += hash.h
generic-y += hw_irq.h
generic-y += ioctl.h
generic-y += ioctls.h
@@ -34,6 +35,7 @@ generic-y += kdebug.h
generic-y += kmap_types.h
generic-y += kvm_para.h
generic-y += local.h
+generic-y += mcs_spinlock.h
generic-y += mman.h
generic-y += module.h
generic-y += msgbuf.h
@@ -41,6 +43,7 @@ generic-y += pci.h
generic-y += percpu.h
generic-y += poll.h
generic-y += posix_types.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += sections.h
@@ -53,11 +56,11 @@ generic-y += siginfo.h
generic-y += signal.h
generic-y += socket.h
generic-y += sockios.h
-generic-y += statfs.h
generic-y += stat.h
+generic-y += statfs.h
generic-y += string.h
-generic-y += switch_to.h
generic-y += swab.h
+generic-y += switch_to.h
generic-y += termbits.h
generic-y += termios.h
generic-y += topology.h
@@ -68,5 +71,3 @@ generic-y += user.h
generic-y += vga.h
generic-y += word-at-a-time.h
generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/parisc/include/asm/Kbuild b/arch/parisc/include/asm/Kbuild
index 752c981bc3c7..ecf25e6678ad 100644
--- a/arch/parisc/include/asm/Kbuild
+++ b/arch/parisc/include/asm/Kbuild
@@ -1,9 +1,29 @@
+generic-y += auxvec.h
generic-y += barrier.h
-generic-y += word-at-a-time.h auxvec.h user.h cputime.h emergency-restart.h \
- segment.h topology.h vga.h device.h percpu.h hw_irq.h mutex.h \
- div64.h irq_regs.h kdebug.h kvm_para.h local64.h local.h param.h \
- poll.h xor.h clkdev.h exec.h
-generic-y += trace_clock.h
-generic-y += preempt.h
+generic-y += clkdev.h
+generic-y += cputime.h
+generic-y += device.h
+generic-y += div64.h
+generic-y += emergency-restart.h
+generic-y += exec.h
generic-y += hash.h
+generic-y += hw_irq.h
+generic-y += irq_regs.h
+generic-y += kdebug.h
+generic-y += kvm_para.h
+generic-y += local.h
+generic-y += local64.h
+generic-y += mcs_spinlock.h
+generic-y += mutex.h
+generic-y += param.h
+generic-y += percpu.h
+generic-y += poll.h
+generic-y += preempt.h
+generic-y += segment.h
+generic-y += topology.h
+generic-y += trace_clock.h
+generic-y += user.h
+generic-y += vga.h
+generic-y += word-at-a-time.h
+generic-y += xor.h
diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h
index 637fe031aa84..60d5d174dfe4 100644
--- a/arch/parisc/include/asm/page.h
+++ b/arch/parisc/include/asm/page.h
@@ -32,17 +32,6 @@ void copy_page_asm(void *to, void *from);
void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
struct page *pg);
-/* #define CONFIG_PARISC_TMPALIAS */
-
-#ifdef CONFIG_PARISC_TMPALIAS
-void clear_user_highpage(struct page *page, unsigned long vaddr);
-#define clear_user_highpage clear_user_highpage
-struct vm_area_struct;
-void copy_user_highpage(struct page *to, struct page *from,
- unsigned long vaddr, struct vm_area_struct *vma);
-#define __HAVE_ARCH_COPY_USER_HIGHPAGE
-#endif
-
/*
* These are used to make use of C type-checking..
*/
diff --git a/arch/parisc/include/asm/spinlock.h b/arch/parisc/include/asm/spinlock.h
index 3516e0b27044..64f2992e439f 100644
--- a/arch/parisc/include/asm/spinlock.h
+++ b/arch/parisc/include/asm/spinlock.h
@@ -191,8 +191,4 @@ static __inline__ int arch_write_can_lock(arch_rwlock_t *rw)
#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-#define arch_spin_relax(lock) cpu_relax()
-#define arch_read_relax(lock) cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
-
#endif /* __ASM_SPINLOCK_H */
diff --git a/arch/parisc/include/uapi/asm/unistd.h b/arch/parisc/include/uapi/asm/unistd.h
index 42706794a36f..265ae5190b0a 100644
--- a/arch/parisc/include/uapi/asm/unistd.h
+++ b/arch/parisc/include/uapi/asm/unistd.h
@@ -828,13 +828,13 @@
#define __NR_finit_module (__NR_Linux + 333)
#define __NR_sched_setattr (__NR_Linux + 334)
#define __NR_sched_getattr (__NR_Linux + 335)
+#define __NR_utimes (__NR_Linux + 336)
-#define __NR_Linux_syscalls (__NR_sched_getattr + 1)
+#define __NR_Linux_syscalls (__NR_utimes + 1)
#define __IGNORE_select /* newselect */
#define __IGNORE_fadvise64 /* fadvise64_64 */
-#define __IGNORE_utimes /* utime */
#define HPUX_GATEWAY_ADDR 0xC0000004
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index ac87a40502e6..a6ffc775a9f8 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -581,67 +581,3 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long
__flush_cache_page(vma, vmaddr, PFN_PHYS(pfn));
}
}
-
-#ifdef CONFIG_PARISC_TMPALIAS
-
-void clear_user_highpage(struct page *page, unsigned long vaddr)
-{
- void *vto;
- unsigned long flags;
-
- /* Clear using TMPALIAS region. The page doesn't need to
- be flushed but the kernel mapping needs to be purged. */
-
- vto = kmap_atomic(page);
-
- /* The PA-RISC 2.0 Architecture book states on page F-6:
- "Before a write-capable translation is enabled, *all*
- non-equivalently-aliased translations must be removed
- from the page table and purged from the TLB. (Note
- that the caches are not required to be flushed at this
- time.) Before any non-equivalent aliased translation
- is re-enabled, the virtual address range for the writeable
- page (the entire page) must be flushed from the cache,
- and the write-capable translation removed from the page
- table and purged from the TLB." */
-
- purge_kernel_dcache_page_asm((unsigned long)vto);
- purge_tlb_start(flags);
- pdtlb_kernel(vto);
- purge_tlb_end(flags);
- preempt_disable();
- clear_user_page_asm(vto, vaddr);
- preempt_enable();
-
- pagefault_enable(); /* kunmap_atomic(addr, KM_USER0); */
-}
-
-void copy_user_highpage(struct page *to, struct page *from,
- unsigned long vaddr, struct vm_area_struct *vma)
-{
- void *vfrom, *vto;
- unsigned long flags;
-
- /* Copy using TMPALIAS region. This has the advantage
- that the `from' page doesn't need to be flushed. However,
- the `to' page must be flushed in copy_user_page_asm since
- it can be used to bring in executable code. */
-
- vfrom = kmap_atomic(from);
- vto = kmap_atomic(to);
-
- purge_kernel_dcache_page_asm((unsigned long)vto);
- purge_tlb_start(flags);
- pdtlb_kernel(vto);
- pdtlb_kernel(vfrom);
- purge_tlb_end(flags);
- preempt_disable();
- copy_user_page_asm(vto, vfrom, vaddr);
- flush_dcache_page_asm(__pa(vto), vaddr);
- preempt_enable();
-
- pagefault_enable(); /* kunmap_atomic(addr, KM_USER1); */
- pagefault_enable(); /* kunmap_atomic(addr, KM_USER0); */
-}
-
-#endif /* CONFIG_PARISC_TMPALIAS */
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
index 8ceac4785609..cfe056fe7f5c 100644
--- a/arch/parisc/kernel/irq.c
+++ b/arch/parisc/kernel/irq.c
@@ -117,7 +117,7 @@ int cpu_check_affinity(struct irq_data *d, const struct cpumask *dest)
return -EINVAL;
/* whatever mask they set, we just allow one CPU */
- cpu_dest = first_cpu(*dest);
+ cpu_dest = cpumask_first_and(dest, cpu_online_mask);
return cpu_dest;
}
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
index 8fa3fbb3e4d3..80e5dd248934 100644
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -431,6 +431,7 @@
ENTRY_SAME(finit_module)
ENTRY_SAME(sched_setattr)
ENTRY_SAME(sched_getattr) /* 335 */
+ ENTRY_COMP(utimes)
/* Nothing yet */
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 957bf344c0f5..6c03a94991ad 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -90,6 +90,7 @@ config PPC
select BINFMT_ELF
select OF
select OF_EARLY_FLATTREE
+ select OF_RESERVED_MEM
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_DYNAMIC_FTRACE
select HAVE_FUNCTION_TRACER
@@ -130,6 +131,8 @@ config PPC
select GENERIC_CMOS_UPDATE
select GENERIC_TIME_VSYSCALL_OLD
select GENERIC_CLOCKEVENTS
+ select GENERIC_CLOCKEVENTS_BROADCAST if SMP
+ select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
select HAVE_MOD_ARCH_SPECIFIC
@@ -618,6 +621,15 @@ config CMDLINE
some command-line options at build time by entering them here. In
most cases you will need to specify the root device here.
+config CMDLINE_FORCE
+ bool "Always use the default kernel command string"
+ depends on CMDLINE_BOOL
+ help
+ Always use the default kernel command string, even if the boot
+ loader passes other arguments to the kernel.
+ This is useful if you cannot or don't want to change the
+ command-line options your boot loader passes to the kernel.
+
config EXTRA_TARGETS
string "Additional default image types"
help
@@ -736,10 +748,6 @@ config FSL_LBC
controller. Also contains some common code used by
drivers for specific local bus peripherals.
-config FSL_IFC
- bool
- depends on FSL_SOC
-
config FSL_GTM
bool
depends on PPC_83xx || QUICC_ENGINE || CPM2
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 90e9d9548660..a1f8c7f1ec60 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -54,7 +54,7 @@ zlib := inffast.c inflate.c inftrees.c
zlibheader := inffast.h inffixed.h inflate.h inftrees.h infutil.h
zliblinuxheader := zlib.h zconf.h zutil.h
-$(addprefix $(obj)/,$(zlib) cuboot-c2k.o gunzip_util.o main.o prpmc2800.o): \
+$(addprefix $(obj)/,$(zlib) cuboot-c2k.o gunzip_util.o main.o): \
$(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
libfdt := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
@@ -95,7 +95,7 @@ src-plat-$(CONFIG_FSL_SOC_BOOKE) += cuboot-85xx.c cuboot-85xx-cpm2.c
src-plat-$(CONFIG_EMBEDDED6xx) += cuboot-pq2.c cuboot-mpc7448hpc2.c \
cuboot-c2k.c gamecube-head.S \
gamecube.c wii-head.S wii.c holly.c \
- prpmc2800.c fixed-head.S mvme5100.c
+ fixed-head.S mvme5100.c
src-plat-$(CONFIG_AMIGAONE) += cuboot-amigaone.c
src-plat-$(CONFIG_PPC_PS3) += ps3-head.S ps3-hvcall.S ps3.c
src-plat-$(CONFIG_EPAPR_BOOT) += epapr.c epapr-wrapper.c
@@ -204,7 +204,6 @@ image-$(CONFIG_PPC_CHRP) += zImage.chrp
image-$(CONFIG_PPC_EFIKA) += zImage.chrp
image-$(CONFIG_PPC_PMAC) += zImage.pmac
image-$(CONFIG_PPC_HOLLY) += dtbImage.holly
-image-$(CONFIG_PPC_PRPMC2800) += dtbImage.prpmc2800
image-$(CONFIG_DEFAULT_UIMAGE) += uImage
image-$(CONFIG_EPAPR_BOOT) += zImage.epapr
diff --git a/arch/powerpc/boot/dts/fsl/b4420si-post.dtsi b/arch/powerpc/boot/dts/fsl/b4420si-post.dtsi
index 5a6615d0ade2..60566f9927be 100644
--- a/arch/powerpc/boot/dts/fsl/b4420si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/b4420si-post.dtsi
@@ -86,6 +86,42 @@
clockgen: global-utilities@e1000 {
compatible = "fsl,b4420-clockgen", "fsl,qoriq-clockgen-2.0";
+ ranges = <0x0 0xe1000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sysclk: sysclk {
+ #clock-cells = <0>;
+ compatible = "fsl,qoriq-sysclk-2.0";
+ clock-output-names = "sysclk";
+ };
+
+ pll0: pll0@800 {
+ #clock-cells = <1>;
+ reg = <0x800 0x4>;
+ compatible = "fsl,qoriq-core-pll-2.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll0", "pll0-div2", "pll0-div4";
+ };
+
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820 0x4>;
+ compatible = "fsl,qoriq-core-pll-2.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll1", "pll1-div2", "pll1-div4";
+ };
+
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0 0x4>;
+ compatible = "fsl,qoriq-core-mux-2.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+ <&pll1 0>, <&pll1 1>, <&pll1 2>;
+ clock-names = "pll0", "pll0-div2", "pll0-div4",
+ "pll1", "pll1-div2", "pll1-div4";
+ clock-output-names = "cmux0";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/b4420si-pre.dtsi b/arch/powerpc/boot/dts/fsl/b4420si-pre.dtsi
index c6e451affb05..2419731c2c54 100644
--- a/arch/powerpc/boot/dts/fsl/b4420si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/b4420si-pre.dtsi
@@ -64,11 +64,13 @@
cpu0: PowerPC,e6500@0 {
device_type = "cpu";
reg = <0 1>;
+ clocks = <&mux0>;
next-level-cache = <&L2>;
};
cpu1: PowerPC,e6500@2 {
device_type = "cpu";
reg = <2 3>;
+ clocks = <&mux0>;
next-level-cache = <&L2>;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/b4860si-post.dtsi b/arch/powerpc/boot/dts/fsl/b4860si-post.dtsi
index 981397518fc6..cbc354b05117 100644
--- a/arch/powerpc/boot/dts/fsl/b4860si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/b4860si-post.dtsi
@@ -130,6 +130,42 @@
clockgen: global-utilities@e1000 {
compatible = "fsl,b4860-clockgen", "fsl,qoriq-clockgen-2.0";
+ ranges = <0x0 0xe1000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sysclk: sysclk {
+ #clock-cells = <0>;
+ compatible = "fsl,qoriq-sysclk-2.0";
+ clock-output-names = "sysclk";
+ };
+
+ pll0: pll0@800 {
+ #clock-cells = <1>;
+ reg = <0x800 0x4>;
+ compatible = "fsl,qoriq-core-pll-2.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll0", "pll0-div2", "pll0-div4";
+ };
+
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820 0x4>;
+ compatible = "fsl,qoriq-core-pll-2.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll1", "pll1-div2", "pll1-div4";
+ };
+
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0 0x4>;
+ compatible = "fsl,qoriq-core-mux-2.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+ <&pll1 0>, <&pll1 1>, <&pll1 2>;
+ clock-names = "pll0", "pll0-div2", "pll0-div4",
+ "pll1", "pll1-div2", "pll1-div4";
+ clock-output-names = "cmux0";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/b4860si-pre.dtsi b/arch/powerpc/boot/dts/fsl/b4860si-pre.dtsi
index 9bc26b147900..142ac862cacf 100644
--- a/arch/powerpc/boot/dts/fsl/b4860si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/b4860si-pre.dtsi
@@ -64,21 +64,25 @@
cpu0: PowerPC,e6500@0 {
device_type = "cpu";
reg = <0 1>;
+ clocks = <&mux0>;
next-level-cache = <&L2>;
};
cpu1: PowerPC,e6500@2 {
device_type = "cpu";
reg = <2 3>;
+ clocks = <&mux0>;
next-level-cache = <&L2>;
};
cpu2: PowerPC,e6500@4 {
device_type = "cpu";
reg = <4 5>;
+ clocks = <&mux0>;
next-level-cache = <&L2>;
};
cpu3: PowerPC,e6500@6 {
device_type = "cpu";
reg = <6 7>;
+ clocks = <&mux0>;
next-level-cache = <&L2>;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
index dc6cc5afd189..e2987a33083c 100644
--- a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
@@ -306,8 +306,68 @@
clockgen: global-utilities@e1000 {
compatible = "fsl,p2041-clockgen", "fsl,qoriq-clockgen-1.0";
+ ranges = <0x0 0xe1000 0x1000>;
reg = <0xe1000 0x1000>;
clock-frequency = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sysclk: sysclk {
+ #clock-cells = <0>;
+ compatible = "fsl,qoriq-sysclk-1.0";
+ clock-output-names = "sysclk";
+ };
+
+ pll0: pll0@800 {
+ #clock-cells = <1>;
+ reg = <0x800 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll0", "pll0-div2";
+ };
+
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll1", "pll1-div2";
+ };
+
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux0";
+ };
+
+ mux1: mux1@20 {
+ #clock-cells = <0>;
+ reg = <0x20 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux1";
+ };
+
+ mux2: mux2@40 {
+ #clock-cells = <0>;
+ reg = <0x40 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ };
+
+ mux3: mux3@60 {
+ #clock-cells = <0>;
+ reg = <0x60 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux3";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi
index 7a2697d04549..22f3b14517de 100644
--- a/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi
@@ -81,6 +81,7 @@
cpu0: PowerPC,e500mc@0 {
device_type = "cpu";
reg = <0>;
+ clocks = <&mux0>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
next-level-cache = <&cpc>;
@@ -89,6 +90,7 @@
cpu1: PowerPC,e500mc@1 {
device_type = "cpu";
reg = <1>;
+ clocks = <&mux1>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
next-level-cache = <&cpc>;
@@ -97,6 +99,7 @@
cpu2: PowerPC,e500mc@2 {
device_type = "cpu";
reg = <2>;
+ clocks = <&mux2>;
next-level-cache = <&L2_2>;
L2_2: l2-cache {
next-level-cache = <&cpc>;
@@ -105,6 +108,7 @@
cpu3: PowerPC,e500mc@3 {
device_type = "cpu";
reg = <3>;
+ clocks = <&mux3>;
next-level-cache = <&L2_3>;
L2_3: l2-cache {
next-level-cache = <&cpc>;
diff --git a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
index 3fa1e22d544a..7af6d45fd998 100644
--- a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
@@ -333,8 +333,69 @@
clockgen: global-utilities@e1000 {
compatible = "fsl,p3041-clockgen", "fsl,qoriq-clockgen-1.0";
+ ranges = <0x0 0xe1000 0x1000>;
reg = <0xe1000 0x1000>;
clock-frequency = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sysclk: sysclk {
+ #clock-cells = <0>;
+ compatible = "fsl,qoriq-sysclk-1.0";
+ clock-output-names = "sysclk";
+ };
+
+ pll0: pll0@800 {
+ #clock-cells = <1>;
+ reg = <0x800 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll0", "pll0-div2";
+ };
+
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll1", "pll1-div2";
+ };
+
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux0";
+ };
+
+ mux1: mux1@20 {
+ #clock-cells = <0>;
+ reg = <0x20 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux1";
+ };
+
+ mux2: mux2@40 {
+ #clock-cells = <0>;
+ reg = <0x40 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux2";
+ };
+
+ mux3: mux3@60 {
+ #clock-cells = <0>;
+ reg = <0x60 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux3";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi
index c9ca2c305cfe..468e8be8ac6f 100644
--- a/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi
@@ -82,6 +82,7 @@
cpu0: PowerPC,e500mc@0 {
device_type = "cpu";
reg = <0>;
+ clocks = <&mux0>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
next-level-cache = <&cpc>;
@@ -90,6 +91,7 @@
cpu1: PowerPC,e500mc@1 {
device_type = "cpu";
reg = <1>;
+ clocks = <&mux1>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
next-level-cache = <&cpc>;
@@ -98,6 +100,7 @@
cpu2: PowerPC,e500mc@2 {
device_type = "cpu";
reg = <2>;
+ clocks = <&mux2>;
next-level-cache = <&L2_2>;
L2_2: l2-cache {
next-level-cache = <&cpc>;
@@ -106,6 +109,7 @@
cpu3: PowerPC,e500mc@3 {
device_type = "cpu";
reg = <3>;
+ clocks = <&mux3>;
next-level-cache = <&L2_3>;
L2_3: l2-cache {
next-level-cache = <&cpc>;
diff --git a/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi b/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
index 34769a7eafea..2415e1f1d3fa 100644
--- a/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
@@ -353,8 +353,121 @@
clockgen: global-utilities@e1000 {
compatible = "fsl,p4080-clockgen", "fsl,qoriq-clockgen-1.0";
+ ranges = <0x0 0xe1000 0x1000>;
reg = <0xe1000 0x1000>;
clock-frequency = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sysclk: sysclk {
+ #clock-cells = <0>;
+ compatible = "fsl,qoriq-sysclk-1.0";
+ clock-output-names = "sysclk";
+ };
+
+ pll0: pll0@800 {
+ #clock-cells = <1>;
+ reg = <0x800 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll0", "pll0-div2";
+ };
+
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll1", "pll1-div2";
+ };
+
+ pll2: pll2@840 {
+ #clock-cells = <1>;
+ reg = <0x840 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll2", "pll2-div2";
+ };
+
+ pll3: pll3@860 {
+ #clock-cells = <1>;
+ reg = <0x860 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll3", "pll3-div2";
+ };
+
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux0";
+ };
+
+ mux1: mux1@20 {
+ #clock-cells = <0>;
+ reg = <0x20 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux1";
+ };
+
+ mux2: mux2@40 {
+ #clock-cells = <0>;
+ reg = <0x40 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux2";
+ };
+
+ mux3: mux3@60 {
+ #clock-cells = <0>;
+ reg = <0x60 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux3";
+ };
+
+ mux4: mux4@80 {
+ #clock-cells = <0>;
+ reg = <0x80 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll2 0>, <&pll2 1>, <&pll3 0>, <&pll3 1>;
+ clock-names = "pll2", "pll2-div2", "pll3", "pll3-div2";
+ clock-output-names = "cmux4";
+ };
+
+ mux5: mux5@a0 {
+ #clock-cells = <0>;
+ reg = <0xa0 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll2 0>, <&pll2 1>, <&pll3 0>, <&pll3 1>;
+ clock-names = "pll2", "pll2-div2", "pll3", "pll3-div2";
+ clock-output-names = "cmux5";
+ };
+
+ mux6: mux6@c0 {
+ #clock-cells = <0>;
+ reg = <0xc0 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll2 0>, <&pll2 1>, <&pll3 0>, <&pll3 1>;
+ clock-names = "pll2", "pll2-div2", "pll3", "pll3-div2";
+ clock-output-names = "cmux6";
+ };
+
+ mux7: mux7@e0 {
+ #clock-cells = <0>;
+ reg = <0xe0 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll2 0>, <&pll2 1>, <&pll3 0>, <&pll3 1>;
+ clock-names = "pll2", "pll2-div2", "pll3", "pll3-div2";
+ clock-output-names = "cmux7";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi
index 493d9a056b5c..0040b5a5379e 100644
--- a/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi
@@ -81,6 +81,7 @@
cpu0: PowerPC,e500mc@0 {
device_type = "cpu";
reg = <0>;
+ clocks = <&mux0>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
next-level-cache = <&cpc>;
@@ -89,6 +90,7 @@
cpu1: PowerPC,e500mc@1 {
device_type = "cpu";
reg = <1>;
+ clocks = <&mux1>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
next-level-cache = <&cpc>;
@@ -97,6 +99,7 @@
cpu2: PowerPC,e500mc@2 {
device_type = "cpu";
reg = <2>;
+ clocks = <&mux2>;
next-level-cache = <&L2_2>;
L2_2: l2-cache {
next-level-cache = <&cpc>;
@@ -105,6 +108,7 @@
cpu3: PowerPC,e500mc@3 {
device_type = "cpu";
reg = <3>;
+ clocks = <&mux3>;
next-level-cache = <&L2_3>;
L2_3: l2-cache {
next-level-cache = <&cpc>;
@@ -113,6 +117,7 @@
cpu4: PowerPC,e500mc@4 {
device_type = "cpu";
reg = <4>;
+ clocks = <&mux4>;
next-level-cache = <&L2_4>;
L2_4: l2-cache {
next-level-cache = <&cpc>;
@@ -121,6 +126,7 @@
cpu5: PowerPC,e500mc@5 {
device_type = "cpu";
reg = <5>;
+ clocks = <&mux5>;
next-level-cache = <&L2_5>;
L2_5: l2-cache {
next-level-cache = <&cpc>;
@@ -129,6 +135,7 @@
cpu6: PowerPC,e500mc@6 {
device_type = "cpu";
reg = <6>;
+ clocks = <&mux6>;
next-level-cache = <&L2_6>;
L2_6: l2-cache {
next-level-cache = <&cpc>;
@@ -137,6 +144,7 @@
cpu7: PowerPC,e500mc@7 {
device_type = "cpu";
reg = <7>;
+ clocks = <&mux7>;
next-level-cache = <&L2_7>;
L2_7: l2-cache {
next-level-cache = <&cpc>;
diff --git a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
index bc3ae5a2252f..2985de4ad6be 100644
--- a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
@@ -338,8 +338,51 @@
clockgen: global-utilities@e1000 {
compatible = "fsl,p5020-clockgen", "fsl,qoriq-clockgen-1.0";
+ ranges = <0x0 0xe1000 0x1000>;
reg = <0xe1000 0x1000>;
clock-frequency = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sysclk: sysclk {
+ #clock-cells = <0>;
+ compatible = "fsl,qoriq-sysclk-1.0";
+ clock-output-names = "sysclk";
+ };
+
+ pll0: pll0@800 {
+ #clock-cells = <1>;
+ reg = <0x800 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll0", "pll0-div2";
+ };
+
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll1", "pll1-div2";
+ };
+
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux0";
+ };
+
+ mux1: mux1@20 {
+ #clock-cells = <0>;
+ reg = <0x20 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux1";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi
index 8df47fc45ab5..fe1a2e6613b4 100644
--- a/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi
@@ -88,6 +88,7 @@
cpu0: PowerPC,e5500@0 {
device_type = "cpu";
reg = <0>;
+ clocks = <&mux0>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
next-level-cache = <&cpc>;
@@ -96,6 +97,7 @@
cpu1: PowerPC,e5500@1 {
device_type = "cpu";
reg = <1>;
+ clocks = <&mux1>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
next-level-cache = <&cpc>;
diff --git a/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
index a91897f6af09..546a899efe20 100644
--- a/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
@@ -298,8 +298,69 @@
clockgen: global-utilities@e1000 {
compatible = "fsl,p5040-clockgen", "fsl,qoriq-clockgen-1.0";
+ ranges = <0x0 0xe1000 0x1000>;
reg = <0xe1000 0x1000>;
clock-frequency = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sysclk: sysclk {
+ #clock-cells = <0>;
+ compatible = "fsl,qoriq-sysclk-1.0";
+ clock-output-names = "sysclk";
+ };
+
+ pll0: pll0@800 {
+ #clock-cells = <1>;
+ reg = <0x800 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll0", "pll0-div2";
+ };
+
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll1", "pll1-div2";
+ };
+
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux0";
+ };
+
+ mux1: mux1@20 {
+ #clock-cells = <0>;
+ reg = <0x20 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux1";
+ };
+
+ mux2: mux2@40 {
+ #clock-cells = <0>;
+ reg = <0x40 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux2";
+ };
+
+ mux3: mux3@60 {
+ #clock-cells = <0>;
+ reg = <0x60 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux3";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi
index 40ca943f5d1c..3674686687cb 100644
--- a/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi
@@ -81,6 +81,7 @@
cpu0: PowerPC,e5500@0 {
device_type = "cpu";
reg = <0>;
+ clocks = <&mux0>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
next-level-cache = <&cpc>;
@@ -89,6 +90,7 @@
cpu1: PowerPC,e5500@1 {
device_type = "cpu";
reg = <1>;
+ clocks = <&mux1>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
next-level-cache = <&cpc>;
@@ -97,6 +99,7 @@
cpu2: PowerPC,e5500@2 {
device_type = "cpu";
reg = <2>;
+ clocks = <&mux2>;
next-level-cache = <&L2_2>;
L2_2: l2-cache {
next-level-cache = <&cpc>;
@@ -105,6 +108,7 @@
cpu3: PowerPC,e5500@3 {
device_type = "cpu";
reg = <3>;
+ clocks = <&mux3>;
next-level-cache = <&L2_3>;
L2_3: l2-cache {
next-level-cache = <&cpc>;
diff --git a/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi b/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi
index 4143a9733cd0..f99d74ff11b4 100644
--- a/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi
@@ -369,7 +369,93 @@
clockgen: global-utilities@e1000 {
compatible = "fsl,t4240-clockgen", "fsl,qoriq-clockgen-2.0";
+ ranges = <0x0 0xe1000 0x1000>;
reg = <0xe1000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sysclk: sysclk {
+ #clock-cells = <0>;
+ compatible = "fsl,qoriq-sysclk-2.0";
+ clock-output-names = "sysclk";
+ };
+
+ pll0: pll0@800 {
+ #clock-cells = <1>;
+ reg = <0x800 0x4>;
+ compatible = "fsl,qoriq-core-pll-2.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll0", "pll0-div2", "pll0-div4";
+ };
+
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820 0x4>;
+ compatible = "fsl,qoriq-core-pll-2.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll1", "pll1-div2", "pll1-div4";
+ };
+
+ pll2: pll2@840 {
+ #clock-cells = <1>;
+ reg = <0x840 0x4>;
+ compatible = "fsl,qoriq-core-pll-2.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll2", "pll2-div2", "pll2-div4";
+ };
+
+ pll3: pll3@860 {
+ #clock-cells = <1>;
+ reg = <0x860 0x4>;
+ compatible = "fsl,qoriq-core-pll-2.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll3", "pll3-div2", "pll3-div4";
+ };
+
+ pll4: pll4@880 {
+ #clock-cells = <1>;
+ reg = <0x880 0x4>;
+ compatible = "fsl,qoriq-core-pll-2.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll4", "pll4-div2", "pll4-div4";
+ };
+
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0 0x4>;
+ compatible = "fsl,qoriq-core-mux-2.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+ <&pll1 0>, <&pll1 1>, <&pll1 2>,
+ <&pll2 0>, <&pll2 1>, <&pll2 2>;
+ clock-names = "pll0", "pll0-div2", "pll0-div4",
+ "pll1", "pll1-div2", "pll1-div4",
+ "pll2", "pll2-div2", "pll2-div4";
+ clock-output-names = "cmux0";
+ };
+
+ mux1: mux1@20 {
+ #clock-cells = <0>;
+ reg = <0x20 0x4>;
+ compatible = "fsl,qoriq-core-mux-2.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+ <&pll1 0>, <&pll1 1>, <&pll1 2>,
+ <&pll2 0>, <&pll2 1>, <&pll2 2>;
+ clock-names = "pll0", "pll0-div2", "pll0-div4",
+ "pll1", "pll1-div2", "pll1-div4",
+ "pll2", "pll2-div2", "pll2-div4";
+ clock-output-names = "cmux1";
+ };
+
+ mux2: mux2@40 {
+ #clock-cells = <0>;
+ reg = <0x40 0x4>;
+ compatible = "fsl,qoriq-core-mux-2.0";
+ clocks = <&pll3 0>, <&pll3 1>, <&pll3 2>,
+ <&pll4 0>, <&pll4 1>, <&pll4 2>;
+ clock-names = "pll3", "pll3-div2", "pll3-div4",
+ "pll4", "pll4-div2", "pll4-div4";
+ clock-output-names = "cmux2";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/t4240si-pre.dtsi b/arch/powerpc/boot/dts/fsl/t4240si-pre.dtsi
index a93c55a88560..0b8ccc5b4a46 100644
--- a/arch/powerpc/boot/dts/fsl/t4240si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t4240si-pre.dtsi
@@ -67,61 +67,73 @@
cpu0: PowerPC,e6500@0 {
device_type = "cpu";
reg = <0 1>;
+ clocks = <&mux0>;
next-level-cache = <&L2_1>;
};
cpu1: PowerPC,e6500@2 {
device_type = "cpu";
reg = <2 3>;
+ clocks = <&mux0>;
next-level-cache = <&L2_1>;
};
cpu2: PowerPC,e6500@4 {
device_type = "cpu";
reg = <4 5>;
+ clocks = <&mux0>;
next-level-cache = <&L2_1>;
};
cpu3: PowerPC,e6500@6 {
device_type = "cpu";
reg = <6 7>;
+ clocks = <&mux0>;
next-level-cache = <&L2_1>;
};
cpu4: PowerPC,e6500@8 {
device_type = "cpu";
reg = <8 9>;
+ clocks = <&mux1>;
next-level-cache = <&L2_2>;
};
cpu5: PowerPC,e6500@10 {
device_type = "cpu";
reg = <10 11>;
+ clocks = <&mux1>;
next-level-cache = <&L2_2>;
};
cpu6: PowerPC,e6500@12 {
device_type = "cpu";
reg = <12 13>;
+ clocks = <&mux1>;
next-level-cache = <&L2_2>;
};
cpu7: PowerPC,e6500@14 {
device_type = "cpu";
reg = <14 15>;
+ clocks = <&mux1>;
next-level-cache = <&L2_2>;
};
cpu8: PowerPC,e6500@16 {
device_type = "cpu";
reg = <16 17>;
+ clocks = <&mux2>;
next-level-cache = <&L2_3>;
};
cpu9: PowerPC,e6500@18 {
device_type = "cpu";
reg = <18 19>;
+ clocks = <&mux2>;
next-level-cache = <&L2_3>;
};
cpu10: PowerPC,e6500@20 {
device_type = "cpu";
reg = <20 21>;
+ clocks = <&mux2>;
next-level-cache = <&L2_3>;
};
cpu11: PowerPC,e6500@22 {
device_type = "cpu";
reg = <22 23>;
+ clocks = <&mux2>;
next-level-cache = <&L2_3>;
};
};
diff --git a/arch/powerpc/boot/dts/t4240qds.dts b/arch/powerpc/boot/dts/t4240qds.dts
index 63e81b010804..97683f6a2936 100644
--- a/arch/powerpc/boot/dts/t4240qds.dts
+++ b/arch/powerpc/boot/dts/t4240qds.dts
@@ -159,6 +159,48 @@
interrupts = <0x1 0x1 0 0>;
};
};
+
+ i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x2>;
+
+ ina220@40 {
+ compatible = "ti,ina220";
+ reg = <0x40>;
+ shunt-resistor = <1000>;
+ };
+
+ ina220@41 {
+ compatible = "ti,ina220";
+ reg = <0x41>;
+ shunt-resistor = <1000>;
+ };
+
+ ina220@44 {
+ compatible = "ti,ina220";
+ reg = <0x44>;
+ shunt-resistor = <1000>;
+ };
+
+ ina220@45 {
+ compatible = "ti,ina220";
+ reg = <0x45>;
+ shunt-resistor = <1000>;
+ };
+
+ ina220@46 {
+ compatible = "ti,ina220";
+ reg = <0x46>;
+ shunt-resistor = <1000>;
+ };
+
+ ina220@47 {
+ compatible = "ti,ina220";
+ reg = <0x47>;
+ shunt-resistor = <1000>;
+ };
+ };
};
};
diff --git a/arch/powerpc/configs/40x/acadia_defconfig b/arch/powerpc/configs/40x/acadia_defconfig
index ed3bab72a834..69e06eeae6a6 100644
--- a/arch/powerpc/configs/40x/acadia_defconfig
+++ b/arch/powerpc/configs/40x/acadia_defconfig
@@ -30,7 +30,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/40x/ep405_defconfig b/arch/powerpc/configs/40x/ep405_defconfig
index 17582a3420fb..cf06d42f2c03 100644
--- a/arch/powerpc/configs/40x/ep405_defconfig
+++ b/arch/powerpc/configs/40x/ep405_defconfig
@@ -29,7 +29,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/40x/kilauea_defconfig b/arch/powerpc/configs/40x/kilauea_defconfig
index f2d4be936e08..5ff338f6443f 100644
--- a/arch/powerpc/configs/40x/kilauea_defconfig
+++ b/arch/powerpc/configs/40x/kilauea_defconfig
@@ -32,7 +32,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/40x/makalu_defconfig b/arch/powerpc/configs/40x/makalu_defconfig
index 42b979355f9b..84505e3aa0fb 100644
--- a/arch/powerpc/configs/40x/makalu_defconfig
+++ b/arch/powerpc/configs/40x/makalu_defconfig
@@ -29,7 +29,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/40x/walnut_defconfig b/arch/powerpc/configs/40x/walnut_defconfig
index aa1a4cac3708..0a19f4386ee9 100644
--- a/arch/powerpc/configs/40x/walnut_defconfig
+++ b/arch/powerpc/configs/40x/walnut_defconfig
@@ -27,7 +27,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/44x/arches_defconfig b/arch/powerpc/configs/44x/arches_defconfig
index 329f9a3b892e..44355c53cd30 100644
--- a/arch/powerpc/configs/44x/arches_defconfig
+++ b/arch/powerpc/configs/44x/arches_defconfig
@@ -31,7 +31,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/44x/bluestone_defconfig b/arch/powerpc/configs/44x/bluestone_defconfig
index 20c8d26d7fc0..ca7f1f32f2b2 100644
--- a/arch/powerpc/configs/44x/bluestone_defconfig
+++ b/arch/powerpc/configs/44x/bluestone_defconfig
@@ -26,7 +26,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/44x/canyonlands_defconfig b/arch/powerpc/configs/44x/canyonlands_defconfig
index d5be93e6e92d..7b8abd1b88b0 100644
--- a/arch/powerpc/configs/44x/canyonlands_defconfig
+++ b/arch/powerpc/configs/44x/canyonlands_defconfig
@@ -31,7 +31,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/44x/ebony_defconfig b/arch/powerpc/configs/44x/ebony_defconfig
index f9269fc4ffcc..31b58b0d52e2 100644
--- a/arch/powerpc/configs/44x/ebony_defconfig
+++ b/arch/powerpc/configs/44x/ebony_defconfig
@@ -28,7 +28,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/44x/eiger_defconfig b/arch/powerpc/configs/44x/eiger_defconfig
index 9be089038fd7..faccaf65f394 100644
--- a/arch/powerpc/configs/44x/eiger_defconfig
+++ b/arch/powerpc/configs/44x/eiger_defconfig
@@ -34,7 +34,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/44x/icon_defconfig b/arch/powerpc/configs/44x/icon_defconfig
index 82f73035a7ce..05782c145141 100644
--- a/arch/powerpc/configs/44x/icon_defconfig
+++ b/arch/powerpc/configs/44x/icon_defconfig
@@ -33,7 +33,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/44x/iss476-smp_defconfig b/arch/powerpc/configs/44x/iss476-smp_defconfig
index ca00cf750d3e..49a1518a4e69 100644
--- a/arch/powerpc/configs/44x/iss476-smp_defconfig
+++ b/arch/powerpc/configs/44x/iss476-smp_defconfig
@@ -42,7 +42,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/44x/katmai_defconfig b/arch/powerpc/configs/44x/katmai_defconfig
index 109562c3c6be..f1137972ed41 100644
--- a/arch/powerpc/configs/44x/katmai_defconfig
+++ b/arch/powerpc/configs/44x/katmai_defconfig
@@ -29,7 +29,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/44x/rainier_defconfig b/arch/powerpc/configs/44x/rainier_defconfig
index 21c33faf61a2..4b91a44c4c32 100644
--- a/arch/powerpc/configs/44x/rainier_defconfig
+++ b/arch/powerpc/configs/44x/rainier_defconfig
@@ -30,7 +30,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/44x/redwood_defconfig b/arch/powerpc/configs/44x/redwood_defconfig
index 48802811da76..b7113e114a14 100644
--- a/arch/powerpc/configs/44x/redwood_defconfig
+++ b/arch/powerpc/configs/44x/redwood_defconfig
@@ -34,7 +34,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/44x/sequoia_defconfig b/arch/powerpc/configs/44x/sequoia_defconfig
index b7a653b626db..9642d99b47f1 100644
--- a/arch/powerpc/configs/44x/sequoia_defconfig
+++ b/arch/powerpc/configs/44x/sequoia_defconfig
@@ -31,7 +31,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/44x/taishan_defconfig b/arch/powerpc/configs/44x/taishan_defconfig
index 30de97f158a4..09e3075030bf 100644
--- a/arch/powerpc/configs/44x/taishan_defconfig
+++ b/arch/powerpc/configs/44x/taishan_defconfig
@@ -29,7 +29,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_CFI=y
diff --git a/arch/powerpc/configs/44x/warp_defconfig b/arch/powerpc/configs/44x/warp_defconfig
index 105bc56f4b2b..551e50a0be5e 100644
--- a/arch/powerpc/configs/44x/warp_defconfig
+++ b/arch/powerpc/configs/44x/warp_defconfig
@@ -34,7 +34,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_STANDALONE is not set
# CONFIG_FIRMWARE_IN_KERNEL is not set
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/52xx/cm5200_defconfig b/arch/powerpc/configs/52xx/cm5200_defconfig
index 0b88c7b30bb9..4f84a0b2fbf3 100644
--- a/arch/powerpc/configs/52xx/cm5200_defconfig
+++ b/arch/powerpc/configs/52xx/cm5200_defconfig
@@ -30,7 +30,6 @@ CONFIG_SYN_COOKIES=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/52xx/motionpro_defconfig b/arch/powerpc/configs/52xx/motionpro_defconfig
index 0d13ad7e4478..c05310a913be 100644
--- a/arch/powerpc/configs/52xx/motionpro_defconfig
+++ b/arch/powerpc/configs/52xx/motionpro_defconfig
@@ -31,7 +31,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/52xx/pcm030_defconfig b/arch/powerpc/configs/52xx/pcm030_defconfig
index 430aa182fa1c..2401e2554329 100644
--- a/arch/powerpc/configs/52xx/pcm030_defconfig
+++ b/arch/powerpc/configs/52xx/pcm030_defconfig
@@ -44,7 +44,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/52xx/tqm5200_defconfig b/arch/powerpc/configs/52xx/tqm5200_defconfig
index 7af4c5bb7c63..21c841e0f482 100644
--- a/arch/powerpc/configs/52xx/tqm5200_defconfig
+++ b/arch/powerpc/configs/52xx/tqm5200_defconfig
@@ -35,7 +35,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/83xx/asp8347_defconfig b/arch/powerpc/configs/83xx/asp8347_defconfig
index d2762d9dcb8e..985f95c7280a 100644
--- a/arch/powerpc/configs/83xx/asp8347_defconfig
+++ b/arch/powerpc/configs/83xx/asp8347_defconfig
@@ -32,7 +32,6 @@ CONFIG_SYN_COOKIES=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_REDBOOT_PARTS=y
CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
CONFIG_MTD_OF_PARTS=y
diff --git a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
index e4ad2e27551a..0b73b7f9d112 100644
--- a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
+++ b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
@@ -30,7 +30,6 @@ CONFIG_SYN_COOKIES=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
index 34ff5686be08..97ac3b993cb6 100644
--- a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
+++ b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
@@ -30,7 +30,6 @@ CONFIG_SYN_COOKIES=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
diff --git a/arch/powerpc/configs/83xx/mpc836x_mds_defconfig b/arch/powerpc/configs/83xx/mpc836x_mds_defconfig
index 10b5c4cd0e72..05710bbfd2ef 100644
--- a/arch/powerpc/configs/83xx/mpc836x_mds_defconfig
+++ b/arch/powerpc/configs/83xx/mpc836x_mds_defconfig
@@ -31,7 +31,6 @@ CONFIG_SYN_COOKIES=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig b/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig
index 45925d701d2a..0540d673a052 100644
--- a/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig
+++ b/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig
@@ -29,7 +29,6 @@ CONFIG_SYN_COOKIES=y
# CONFIG_IPV6 is not set
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/83xx/sbc834x_defconfig b/arch/powerpc/configs/83xx/sbc834x_defconfig
index 6d6463fe06fc..a3bcda67d2d9 100644
--- a/arch/powerpc/configs/83xx/sbc834x_defconfig
+++ b/arch/powerpc/configs/83xx/sbc834x_defconfig
@@ -31,7 +31,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/85xx/ksi8560_defconfig b/arch/powerpc/configs/85xx/ksi8560_defconfig
index 8f7c1061891a..aee0d17a9551 100644
--- a/arch/powerpc/configs/85xx/ksi8560_defconfig
+++ b/arch/powerpc/configs/85xx/ksi8560_defconfig
@@ -28,7 +28,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
diff --git a/arch/powerpc/configs/85xx/ppa8548_defconfig b/arch/powerpc/configs/85xx/ppa8548_defconfig
index a11337de8aa2..e80bb9b21eac 100644
--- a/arch/powerpc/configs/85xx/ppa8548_defconfig
+++ b/arch/powerpc/configs/85xx/ppa8548_defconfig
@@ -44,7 +44,6 @@ CONFIG_MTD_CFI_INTELEXT=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_PHYSMAP_OF=y
CONFIG_I2C=y
diff --git a/arch/powerpc/configs/85xx/socrates_defconfig b/arch/powerpc/configs/85xx/socrates_defconfig
index 77506b5d5a41..e5147488c000 100644
--- a/arch/powerpc/configs/85xx/socrates_defconfig
+++ b/arch/powerpc/configs/85xx/socrates_defconfig
@@ -32,7 +32,6 @@ CONFIG_CAN_RAW=y
CONFIG_CAN_BCM=y
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/85xx/tqm8540_defconfig b/arch/powerpc/configs/85xx/tqm8540_defconfig
index ddcb9f37fa1f..5a800e6e38e3 100644
--- a/arch/powerpc/configs/85xx/tqm8540_defconfig
+++ b/arch/powerpc/configs/85xx/tqm8540_defconfig
@@ -26,7 +26,6 @@ CONFIG_SYN_COOKIES=y
# CONFIG_IPV6 is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/85xx/tqm8541_defconfig b/arch/powerpc/configs/85xx/tqm8541_defconfig
index 981abd6d4b57..2d936697d69e 100644
--- a/arch/powerpc/configs/85xx/tqm8541_defconfig
+++ b/arch/powerpc/configs/85xx/tqm8541_defconfig
@@ -26,7 +26,6 @@ CONFIG_SYN_COOKIES=y
# CONFIG_IPV6 is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/85xx/tqm8548_defconfig b/arch/powerpc/configs/85xx/tqm8548_defconfig
index 37b3d7227cdd..ce8a67e89473 100644
--- a/arch/powerpc/configs/85xx/tqm8548_defconfig
+++ b/arch/powerpc/configs/85xx/tqm8548_defconfig
@@ -34,7 +34,6 @@ CONFIG_SYN_COOKIES=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLKDEVS=y
diff --git a/arch/powerpc/configs/85xx/tqm8555_defconfig b/arch/powerpc/configs/85xx/tqm8555_defconfig
index 3593b320c97c..a4e12971ccac 100644
--- a/arch/powerpc/configs/85xx/tqm8555_defconfig
+++ b/arch/powerpc/configs/85xx/tqm8555_defconfig
@@ -26,7 +26,6 @@ CONFIG_SYN_COOKIES=y
# CONFIG_IPV6 is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/85xx/tqm8560_defconfig b/arch/powerpc/configs/85xx/tqm8560_defconfig
index de413acc34d6..341abe18a74d 100644
--- a/arch/powerpc/configs/85xx/tqm8560_defconfig
+++ b/arch/powerpc/configs/85xx/tqm8560_defconfig
@@ -26,7 +26,6 @@ CONFIG_SYN_COOKIES=y
# CONFIG_IPV6 is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
index 1cd6fcb368e9..07bb81df27e0 100644
--- a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
+++ b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
@@ -65,7 +65,6 @@ CONFIG_ARPD=y
CONFIG_IPV6=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_REDBOOT_PARTS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
diff --git a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig
index f2f6734d5f76..e5a648115ada 100644
--- a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig
+++ b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig
@@ -70,7 +70,6 @@ CONFIG_NET_PKTGEN=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/86xx/gef_sbc310_defconfig b/arch/powerpc/configs/86xx/gef_sbc310_defconfig
index be73219212b7..8317b6010ba6 100644
--- a/arch/powerpc/configs/86xx/gef_sbc310_defconfig
+++ b/arch/powerpc/configs/86xx/gef_sbc310_defconfig
@@ -70,7 +70,6 @@ CONFIG_NET_PKTGEN=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/86xx/gef_sbc610_defconfig b/arch/powerpc/configs/86xx/gef_sbc610_defconfig
index b3e2b1058f27..124d66f0282c 100644
--- a/arch/powerpc/configs/86xx/gef_sbc610_defconfig
+++ b/arch/powerpc/configs/86xx/gef_sbc610_defconfig
@@ -123,7 +123,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig b/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
index c09598b31de1..bcbe74716689 100644
--- a/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
+++ b/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
@@ -41,7 +41,6 @@ CONFIG_IP_PNP_RARP=y
CONFIG_IPV6=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/86xx/sbc8641d_defconfig b/arch/powerpc/configs/86xx/sbc8641d_defconfig
index 1a62baf855e9..1e151594c691 100644
--- a/arch/powerpc/configs/86xx/sbc8641d_defconfig
+++ b/arch/powerpc/configs/86xx/sbc8641d_defconfig
@@ -120,7 +120,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
diff --git a/arch/powerpc/configs/c2k_defconfig b/arch/powerpc/configs/c2k_defconfig
index 671a8f960afa..c69f61620908 100644
--- a/arch/powerpc/configs/c2k_defconfig
+++ b/arch/powerpc/configs/c2k_defconfig
@@ -149,7 +149,6 @@ CONFIG_BT_HCIVHCI=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
CONFIG_MTD_CONCAT=m
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=m
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/corenet64_smp_defconfig b/arch/powerpc/configs/corenet64_smp_defconfig
index 63508ddee11c..5c7fa19ae4ef 100644
--- a/arch/powerpc/configs/corenet64_smp_defconfig
+++ b/arch/powerpc/configs/corenet64_smp_defconfig
@@ -26,7 +26,6 @@ CONFIG_CORENET_GENERIC=y
CONFIG_BINFMT_MISC=m
CONFIG_MATH_EMULATION=y
CONFIG_MATH_EMULATION_HW_UNIMPLEMENTED=y
-CONFIG_FSL_IFC=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCI_MSI=y
CONFIG_RAPIDIO=y
@@ -60,7 +59,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/linkstation_defconfig b/arch/powerpc/configs/linkstation_defconfig
index 8a874b999867..353435256f4c 100644
--- a/arch/powerpc/configs/linkstation_defconfig
+++ b/arch/powerpc/configs/linkstation_defconfig
@@ -59,7 +59,6 @@ CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig
index 83d3550fdb54..19f0fbe5ba4b 100644
--- a/arch/powerpc/configs/mpc85xx_defconfig
+++ b/arch/powerpc/configs/mpc85xx_defconfig
@@ -49,7 +49,6 @@ CONFIG_HIGHMEM=y
CONFIG_BINFMT_MISC=m
CONFIG_MATH_EMULATION=y
CONFIG_FORCE_MAX_ZONEORDER=12
-CONFIG_FSL_IFC=y
CONFIG_PCI=y
CONFIG_PCI_MSI=y
CONFIG_RAPIDIO=y
@@ -82,7 +81,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig
index 4b686294feb4..062312e1fe1a 100644
--- a/arch/powerpc/configs/mpc85xx_smp_defconfig
+++ b/arch/powerpc/configs/mpc85xx_smp_defconfig
@@ -52,7 +52,6 @@ CONFIG_HIGHMEM=y
CONFIG_BINFMT_MISC=m
CONFIG_MATH_EMULATION=y
CONFIG_FORCE_MAX_ZONEORDER=12
-CONFIG_FSL_IFC=y
CONFIG_PCI=y
CONFIG_PCI_MSI=y
CONFIG_RAPIDIO=y
@@ -85,7 +84,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/ppc40x_defconfig b/arch/powerpc/configs/ppc40x_defconfig
index 1eb19ac45d09..52908c7897d9 100644
--- a/arch/powerpc/configs/ppc40x_defconfig
+++ b/arch/powerpc/configs/ppc40x_defconfig
@@ -33,7 +33,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/ppc44x_defconfig b/arch/powerpc/configs/ppc44x_defconfig
index 3b98d7354341..ccf66b9060a6 100644
--- a/arch/powerpc/configs/ppc44x_defconfig
+++ b/arch/powerpc/configs/ppc44x_defconfig
@@ -44,7 +44,6 @@ CONFIG_BRIDGE=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
index e015896b7e5c..f26b267eb71f 100644
--- a/arch/powerpc/configs/ppc64_defconfig
+++ b/arch/powerpc/configs/ppc64_defconfig
@@ -73,74 +73,8 @@ CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_IPV6 is not set
CONFIG_NETFILTER=y
-CONFIG_NF_CONNTRACK=m
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_SCTP=m
-CONFIG_NF_CONNTRACK_AMANDA=m
-CONFIG_NF_CONNTRACK_FTP=m
-CONFIG_NF_CONNTRACK_H323=m
-CONFIG_NF_CONNTRACK_IRC=m
-CONFIG_NF_CONNTRACK_NETBIOS_NS=m
-CONFIG_NF_CONNTRACK_PPTP=m
-CONFIG_NF_CONNTRACK_SIP=m
-CONFIG_NF_CONNTRACK_TFTP=m
-CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
-CONFIG_NETFILTER_XT_TARGET_DSCP=m
-CONFIG_NETFILTER_XT_TARGET_MARK=m
-CONFIG_NETFILTER_XT_TARGET_NFLOG=m
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-CONFIG_NETFILTER_XT_TARGET_TPROXY=m
-CONFIG_NETFILTER_XT_TARGET_TRACE=m
-CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
-CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
-CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-CONFIG_NETFILTER_XT_MATCH_DCCP=m
-CONFIG_NETFILTER_XT_MATCH_DSCP=m
-CONFIG_NETFILTER_XT_MATCH_ESP=m
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_HELPER=m
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
-CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-CONFIG_NETFILTER_XT_MATCH_MAC=m
-CONFIG_NETFILTER_XT_MATCH_MARK=m
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
-CONFIG_NETFILTER_XT_MATCH_OWNER=m
-CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-CONFIG_NETFILTER_XT_MATCH_QUOTA=m
-CONFIG_NETFILTER_XT_MATCH_RATEEST=m
-CONFIG_NETFILTER_XT_MATCH_REALM=m
-CONFIG_NETFILTER_XT_MATCH_RECENT=m
-CONFIG_NETFILTER_XT_MATCH_SCTP=m
-CONFIG_NETFILTER_XT_MATCH_SOCKET=m
-CONFIG_NETFILTER_XT_MATCH_STATE=m
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
-CONFIG_NETFILTER_XT_MATCH_STRING=m
-CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_U32=m
-CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_AH=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_MANGLE=m
-CONFIG_IP_NF_TARGET_CLUSTERIP=m
-CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
+# CONFIG_NETFILTER_ADVANCED is not set
+CONFIG_BRIDGE=m
CONFIG_BPF_JIT=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
diff --git a/arch/powerpc/configs/ppc64e_defconfig b/arch/powerpc/configs/ppc64e_defconfig
index f627fda08953..438e813dc9cb 100644
--- a/arch/powerpc/configs/ppc64e_defconfig
+++ b/arch/powerpc/configs/ppc64e_defconfig
@@ -48,74 +48,8 @@ CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_IPV6 is not set
CONFIG_NETFILTER=y
-CONFIG_NF_CONNTRACK=m
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_SCTP=m
-CONFIG_NF_CONNTRACK_AMANDA=m
-CONFIG_NF_CONNTRACK_FTP=m
-CONFIG_NF_CONNTRACK_H323=m
-CONFIG_NF_CONNTRACK_IRC=m
-CONFIG_NF_CONNTRACK_NETBIOS_NS=m
-CONFIG_NF_CONNTRACK_PPTP=m
-CONFIG_NF_CONNTRACK_SIP=m
-CONFIG_NF_CONNTRACK_TFTP=m
-CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
-CONFIG_NETFILTER_XT_TARGET_DSCP=m
-CONFIG_NETFILTER_XT_TARGET_MARK=m
-CONFIG_NETFILTER_XT_TARGET_NFLOG=m
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-CONFIG_NETFILTER_XT_TARGET_TPROXY=m
-CONFIG_NETFILTER_XT_TARGET_TRACE=m
-CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
-CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
-CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-CONFIG_NETFILTER_XT_MATCH_DCCP=m
-CONFIG_NETFILTER_XT_MATCH_DSCP=m
-CONFIG_NETFILTER_XT_MATCH_ESP=m
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_HELPER=m
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
-CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-CONFIG_NETFILTER_XT_MATCH_MAC=m
-CONFIG_NETFILTER_XT_MATCH_MARK=m
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
-CONFIG_NETFILTER_XT_MATCH_OWNER=m
-CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-CONFIG_NETFILTER_XT_MATCH_QUOTA=m
-CONFIG_NETFILTER_XT_MATCH_RATEEST=m
-CONFIG_NETFILTER_XT_MATCH_REALM=m
-CONFIG_NETFILTER_XT_MATCH_RECENT=m
-CONFIG_NETFILTER_XT_MATCH_SCTP=m
-CONFIG_NETFILTER_XT_MATCH_SOCKET=m
-CONFIG_NETFILTER_XT_MATCH_STATE=m
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
-CONFIG_NETFILTER_XT_MATCH_STRING=m
-CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_U32=m
-CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_AH=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_MANGLE=m
-CONFIG_IP_NF_TARGET_CLUSTERIP=m
-CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
+# CONFIG_NETFILTER_ADVANCED is not set
+CONFIG_BRIDGE=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
diff --git a/arch/powerpc/configs/prpmc2800_defconfig b/arch/powerpc/configs/prpmc2800_defconfig
deleted file mode 100644
index cd80fb615d34..000000000000
--- a/arch/powerpc/configs/prpmc2800_defconfig
+++ /dev/null
@@ -1,108 +0,0 @@
-CONFIG_ALTIVEC=y
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-# CONFIG_PPC_CHRP is not set
-# CONFIG_PPC_PMAC is not set
-CONFIG_EMBEDDED6xx=y
-CONFIG_PPC_PRPMC2800=y
-CONFIG_HIGHMEM=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_BINFMT_MISC=y
-CONFIG_SPARSE_IRQ=y
-# CONFIG_SECCOMP is not set
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_XFRM_USER=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_SYN_COOKIES=y
-# CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_MTD=y
-CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_JEDECPROBE=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_PHYSMAP_OF=y
-CONFIG_PROC_DEVICETREE=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=131072
-CONFIG_IDE=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_PDC202XX_NEW=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_ATA=y
-CONFIG_SATA_MV=y
-CONFIG_MACINTOSH_DRIVERS=y
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_NET_PCI=y
-CONFIG_E100=y
-CONFIG_8139TOO=y
-# CONFIG_8139TOO_PIO is not set
-CONFIG_E1000=y
-CONFIG_MV643XX_ETH=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_MPSC=y
-CONFIG_SERIAL_MPSC_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_MV64XXX=y
-CONFIG_VIDEO_OUTPUT_CONTROL=y
-CONFIG_HID_DRAGONRISE=y
-CONFIG_HID_GYRATION=y
-CONFIG_HID_TWINHAN=y
-CONFIG_HID_NTRIG=y
-CONFIG_HID_ORTEK=y
-CONFIG_HID_PANTHERLORD=y
-CONFIG_HID_PETALYNX=y
-CONFIG_HID_SAMSUNG=y
-CONFIG_HID_SONY=y
-CONFIG_HID_SUNPLUS=y
-CONFIG_HID_GREENASIA=y
-CONFIG_HID_SMARTJOYPLUS=y
-CONFIG_HID_TOPSEED=y
-CONFIG_HID_THRUSTMASTER=y
-CONFIG_THRUSTMASTER_FF=y
-CONFIG_HID_ZEROPLUS=y
-CONFIG_ZEROPLUS_FF=y
-CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_DEVICE_CLASS is not set
-CONFIG_USB_MON=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_MAX6900=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_INOTIFY=y
-CONFIG_PROC_KCORE=y
-CONFIG_TMPFS=y
-CONFIG_NFS_FS=y
-CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_CRC_T10DIF=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig
index e9a8b4e0a0f6..9ea8342bd219 100644
--- a/arch/powerpc/configs/pseries_defconfig
+++ b/arch/powerpc/configs/pseries_defconfig
@@ -65,57 +65,8 @@ CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_IPV6 is not set
CONFIG_NETFILTER=y
-CONFIG_NF_CONNTRACK=m
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_UDPLITE=m
-CONFIG_NF_CONNTRACK_FTP=m
-CONFIG_NF_CONNTRACK_IRC=m
-CONFIG_NF_CONNTRACK_TFTP=m
-CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
-CONFIG_NETFILTER_XT_TARGET_MARK=m
-CONFIG_NETFILTER_XT_TARGET_NFLOG=m
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-CONFIG_NETFILTER_XT_MATCH_DCCP=m
-CONFIG_NETFILTER_XT_MATCH_DSCP=m
-CONFIG_NETFILTER_XT_MATCH_ESP=m
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_HELPER=m
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
-CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-CONFIG_NETFILTER_XT_MATCH_MAC=m
-CONFIG_NETFILTER_XT_MATCH_MARK=m
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
-CONFIG_NETFILTER_XT_MATCH_OWNER=m
-CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-CONFIG_NETFILTER_XT_MATCH_QUOTA=m
-CONFIG_NETFILTER_XT_MATCH_RATEEST=m
-CONFIG_NETFILTER_XT_MATCH_REALM=m
-CONFIG_NETFILTER_XT_MATCH_RECENT=m
-CONFIG_NETFILTER_XT_MATCH_SCTP=m
-CONFIG_NETFILTER_XT_MATCH_STATE=m
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
-CONFIG_NETFILTER_XT_MATCH_STRING=m
-CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_TIME=m
-CONFIG_NETFILTER_XT_MATCH_U32=m
-CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_AH=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_ULOG=m
+# CONFIG_NETFILTER_ADVANCED is not set
+CONFIG_BRIDGE=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
@@ -353,3 +304,5 @@ CONFIG_CRYPTO_DEV_NX_ENCRYPT=m
CONFIG_VIRTUALIZATION=y
CONFIG_KVM_BOOK3S_64=m
CONFIG_KVM_BOOK3S_64_HV=y
+CONFIG_TRANSPARENT_HUGEPAGE=y
+CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
diff --git a/arch/powerpc/configs/pseries_le_defconfig b/arch/powerpc/configs/pseries_le_defconfig
index 62771e0adb7c..3c84f9d87980 100644
--- a/arch/powerpc/configs/pseries_le_defconfig
+++ b/arch/powerpc/configs/pseries_le_defconfig
@@ -67,57 +67,8 @@ CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_IPV6 is not set
CONFIG_NETFILTER=y
-CONFIG_NF_CONNTRACK=m
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_UDPLITE=m
-CONFIG_NF_CONNTRACK_FTP=m
-CONFIG_NF_CONNTRACK_IRC=m
-CONFIG_NF_CONNTRACK_TFTP=m
-CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
-CONFIG_NETFILTER_XT_TARGET_MARK=m
-CONFIG_NETFILTER_XT_TARGET_NFLOG=m
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-CONFIG_NETFILTER_XT_MATCH_DCCP=m
-CONFIG_NETFILTER_XT_MATCH_DSCP=m
-CONFIG_NETFILTER_XT_MATCH_ESP=m
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_HELPER=m
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
-CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-CONFIG_NETFILTER_XT_MATCH_MAC=m
-CONFIG_NETFILTER_XT_MATCH_MARK=m
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
-CONFIG_NETFILTER_XT_MATCH_OWNER=m
-CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-CONFIG_NETFILTER_XT_MATCH_QUOTA=m
-CONFIG_NETFILTER_XT_MATCH_RATEEST=m
-CONFIG_NETFILTER_XT_MATCH_REALM=m
-CONFIG_NETFILTER_XT_MATCH_RECENT=m
-CONFIG_NETFILTER_XT_MATCH_SCTP=m
-CONFIG_NETFILTER_XT_MATCH_STATE=m
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
-CONFIG_NETFILTER_XT_MATCH_STRING=m
-CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_TIME=m
-CONFIG_NETFILTER_XT_MATCH_U32=m
-CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_AH=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_ULOG=m
+# CONFIG_NETFILTER_ADVANCED is not set
+CONFIG_BRIDGE=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
diff --git a/arch/powerpc/configs/storcenter_defconfig b/arch/powerpc/configs/storcenter_defconfig
index ebb2a66c99d3..ba39c785445d 100644
--- a/arch/powerpc/configs/storcenter_defconfig
+++ b/arch/powerpc/configs/storcenter_defconfig
@@ -31,7 +31,6 @@ CONFIG_IP_PNP_DHCP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/tqm8xx_defconfig b/arch/powerpc/configs/tqm8xx_defconfig
index 4b6f8bf104e0..7fe277a7b422 100644
--- a/arch/powerpc/configs/tqm8xx_defconfig
+++ b/arch/powerpc/configs/tqm8xx_defconfig
@@ -41,7 +41,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/include/asm/Kbuild b/arch/powerpc/include/asm/Kbuild
index 6c0a955a1b06..3fb1bc432f4f 100644
--- a/arch/powerpc/include/asm/Kbuild
+++ b/arch/powerpc/include/asm/Kbuild
@@ -1,7 +1,8 @@
generic-y += clkdev.h
+generic-y += hash.h
+generic-y += mcs_spinlock.h
+generic-y += preempt.h
generic-y += rwsem.h
generic-y += trace_clock.h
-generic-y += preempt.h
generic-y += vtime.h
-generic-y += hash.h
diff --git a/arch/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h
index 84fdf6857c31..b142b8e0ed9e 100644
--- a/arch/powerpc/include/asm/compat.h
+++ b/arch/powerpc/include/asm/compat.h
@@ -8,7 +8,11 @@
#include <linux/sched.h>
#define COMPAT_USER_HZ 100
+#ifdef __BIG_ENDIAN__
#define COMPAT_UTS_MACHINE "ppc\0\0"
+#else
+#define COMPAT_UTS_MACHINE "ppcle\0\0"
+#endif
typedef u32 compat_size_t;
typedef s32 compat_ssize_t;
@@ -200,10 +204,11 @@ static inline void __user *arch_compat_alloc_user_space(long len)
/*
* We can't access below the stack pointer in the 32bit ABI and
- * can access 288 bytes in the 64bit ABI
+ * can access 288 bytes in the 64bit big-endian ABI,
+ * or 512 bytes with the new ELFv2 little-endian ABI.
*/
if (!is_32bit_task())
- usp -= 288;
+ usp -= USER_REDZONE_SIZE;
return (void __user *) (usp - len);
}
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index 617cc767c076..bc2347774f0a 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -189,6 +189,7 @@ extern const char *powerpc_base_platform;
#define CPU_FTR_HAS_PPR LONG_ASM_CONST(0x0200000000000000)
#define CPU_FTR_DAWR LONG_ASM_CONST(0x0400000000000000)
#define CPU_FTR_DABRX LONG_ASM_CONST(0x0800000000000000)
+#define CPU_FTR_PMAO_BUG LONG_ASM_CONST(0x1000000000000000)
#ifndef __ASSEMBLY__
@@ -445,6 +446,7 @@ extern const char *powerpc_base_platform;
CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY | \
CPU_FTR_DBELL | CPU_FTR_HAS_PPR | CPU_FTR_DAWR | \
CPU_FTR_ARCH_207S | CPU_FTR_TM_COMP)
+#define CPU_FTRS_POWER8E (CPU_FTRS_POWER8 | CPU_FTR_PMAO_BUG)
#define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
@@ -466,8 +468,8 @@ extern const char *powerpc_base_platform;
#define CPU_FTRS_POSSIBLE \
(CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | \
CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_POWER6 | \
- CPU_FTRS_POWER7 | CPU_FTRS_POWER8 | CPU_FTRS_CELL | \
- CPU_FTRS_PA6T | CPU_FTR_VSX)
+ CPU_FTRS_POWER7 | CPU_FTRS_POWER8E | CPU_FTRS_POWER8 | \
+ CPU_FTRS_CELL | CPU_FTRS_PA6T | CPU_FTR_VSX)
#endif
#else
enum {
diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h
index e27e9ad6818e..150866b2a3fe 100644
--- a/arch/powerpc/include/asm/dma-mapping.h
+++ b/arch/powerpc/include/asm/dma-mapping.h
@@ -134,6 +134,7 @@ static inline int dma_supported(struct device *dev, u64 mask)
}
extern int dma_set_mask(struct device *dev, u64 dma_mask);
+extern int __dma_set_mask(struct device *dev, u64 dma_mask);
#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL)
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index 9e39ceb1d19f..d4dd41fb951b 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -172,10 +172,20 @@ struct eeh_ops {
};
extern struct eeh_ops *eeh_ops;
-extern int eeh_subsystem_enabled;
+extern bool eeh_subsystem_enabled;
extern raw_spinlock_t confirm_error_lock;
extern int eeh_probe_mode;
+static inline bool eeh_enabled(void)
+{
+ return eeh_subsystem_enabled;
+}
+
+static inline void eeh_set_enable(bool mode)
+{
+ eeh_subsystem_enabled = mode;
+}
+
#define EEH_PROBE_MODE_DEV (1<<0) /* From PCI device */
#define EEH_PROBE_MODE_DEVTREE (1<<1) /* From device tree */
@@ -246,7 +256,7 @@ void eeh_remove_device(struct pci_dev *);
* If this macro yields TRUE, the caller relays to eeh_check_failure()
* which does further tests out of line.
*/
-#define EEH_POSSIBLE_ERROR(val, type) ((val) == (type)~0 && eeh_subsystem_enabled)
+#define EEH_POSSIBLE_ERROR(val, type) ((val) == (type)~0 && eeh_enabled())
/*
* Reads from a device which has been isolated by EEH will return
@@ -257,6 +267,13 @@ void eeh_remove_device(struct pci_dev *);
#else /* !CONFIG_EEH */
+static inline bool eeh_enabled(void)
+{
+ return false;
+}
+
+static inline void eeh_set_enable(bool mode) { }
+
static inline int eeh_init(void)
{
return 0;
diff --git a/arch/powerpc/include/asm/exception-64e.h b/arch/powerpc/include/asm/exception-64e.h
index 51fa43e536b9..a563d9afd179 100644
--- a/arch/powerpc/include/asm/exception-64e.h
+++ b/arch/powerpc/include/asm/exception-64e.h
@@ -46,9 +46,8 @@
#define EX_CR (1 * 8)
#define EX_R10 (2 * 8)
#define EX_R11 (3 * 8)
-#define EX_R13 (4 * 8)
-#define EX_R14 (5 * 8)
-#define EX_R15 (6 * 8)
+#define EX_R14 (4 * 8)
+#define EX_R15 (5 * 8)
/*
* The TLB miss exception uses different slots.
@@ -173,16 +172,6 @@ exc_##label##_book3e:
ld r9,EX_TLB_R9(r12); \
ld r8,EX_TLB_R8(r12); \
mtlr r16;
-#define TLB_MISS_PROLOG_STATS_BOLTED \
- mflr r10; \
- std r8,PACA_EXTLB+EX_TLB_R8(r13); \
- std r9,PACA_EXTLB+EX_TLB_R9(r13); \
- std r10,PACA_EXTLB+EX_TLB_LR(r13);
-#define TLB_MISS_RESTORE_STATS_BOLTED \
- ld r16,PACA_EXTLB+EX_TLB_LR(r13); \
- ld r9,PACA_EXTLB+EX_TLB_R9(r13); \
- ld r8,PACA_EXTLB+EX_TLB_R8(r13); \
- mtlr r16;
#define TLB_MISS_STATS_D(name) \
addi r9,r13,MMSTAT_DSTATS+name; \
bl .tlb_stat_inc;
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
index 66830618cc19..aeaa56cd9b54 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -147,6 +147,14 @@ BEGIN_FTR_SECTION_NESTED(943) \
END_FTR_SECTION_NESTED(ftr,ftr,943)
/*
+ * Set an SPR from a register if the CPU has the given feature
+ */
+#define OPT_SET_SPR(ra, spr, ftr) \
+BEGIN_FTR_SECTION_NESTED(943) \
+ mtspr spr,ra; \
+END_FTR_SECTION_NESTED(ftr,ftr,943)
+
+/*
* Save a register to the PACA if the CPU has the given feature
*/
#define OPT_SAVE_REG_TO_PACA(offset, ra, ftr) \
diff --git a/arch/powerpc/include/asm/hugetlb.h b/arch/powerpc/include/asm/hugetlb.h
index d750336b171d..623f2971ce0e 100644
--- a/arch/powerpc/include/asm/hugetlb.h
+++ b/arch/powerpc/include/asm/hugetlb.h
@@ -127,7 +127,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
unsigned long addr, pte_t *ptep)
{
#ifdef CONFIG_PPC64
- return __pte(pte_update(mm, addr, ptep, ~0UL, 1));
+ return __pte(pte_update(mm, addr, ptep, ~0UL, 0, 1));
#else
return __pte(pte_update(ptep, ~0UL, 0));
#endif
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index d8b600b3f058..5dbbb29f5c3e 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -274,6 +274,11 @@
/* Platform specific hcalls, used by KVM */
#define H_RTAS 0xf000
+/* "Platform specific hcalls", provided by PHYP */
+#define H_GET_24X7_CATALOG_PAGE 0xF078
+#define H_GET_24X7_DATA 0xF07C
+#define H_GET_PERF_COUNTER_INFO 0xF080
+
#ifndef __ASSEMBLY__
/**
diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h
index f7a8036579b5..42632c7a2a4e 100644
--- a/arch/powerpc/include/asm/iommu.h
+++ b/arch/powerpc/include/asm/iommu.h
@@ -77,6 +77,7 @@ struct iommu_table {
#ifdef CONFIG_IOMMU_API
struct iommu_group *it_group;
#endif
+ void (*set_bypass)(struct iommu_table *tbl, bool enable);
};
/* Pure 2^n version of get_order */
diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
index 83851aabfdc8..bb1e38a23ac7 100644
--- a/arch/powerpc/include/asm/kvm_book3s.h
+++ b/arch/powerpc/include/asm/kvm_book3s.h
@@ -304,6 +304,11 @@ static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
return vcpu->arch.fault_dar;
}
+static inline bool is_kvmppc_resume_guest(int r)
+{
+ return (r == RESUME_GUEST || r == RESUME_GUEST_NV);
+}
+
/* Magic register values loaded into r3 and r4 before the 'sc' assembly
* instruction for the OSI hypercalls */
#define OSI_SC_MAGIC_R3 0x113724FA
diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h
index bf0fa8b0a883..51388befeddb 100644
--- a/arch/powerpc/include/asm/kvm_book3s_64.h
+++ b/arch/powerpc/include/asm/kvm_book3s_64.h
@@ -289,6 +289,18 @@ static inline void note_hpte_modification(struct kvm *kvm,
if (atomic_read(&kvm->arch.hpte_mod_interest))
rev->guest_rpte |= HPTE_GR_MODIFIED;
}
+
+/*
+ * Like kvm_memslots(), but for use in real mode when we can't do
+ * any RCU stuff (since the secondary threads are offline from the
+ * kernel's point of view), and we can't print anything.
+ * Thus we use rcu_dereference_raw() rather than rcu_dereference_check().
+ */
+static inline struct kvm_memslots *kvm_memslots_raw(struct kvm *kvm)
+{
+ return rcu_dereference_raw_notrace(kvm->memslots);
+}
+
#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
#endif /* __ASM_KVM_BOOK3S_64_H__ */
diff --git a/arch/powerpc/include/asm/kvm_book3s_asm.h b/arch/powerpc/include/asm/kvm_book3s_asm.h
index f3a91dc02c98..821725c1bf46 100644
--- a/arch/powerpc/include/asm/kvm_book3s_asm.h
+++ b/arch/powerpc/include/asm/kvm_book3s_asm.h
@@ -94,7 +94,7 @@ struct kvmppc_host_state {
unsigned long xics_phys;
u32 saved_xirr;
u64 dabr;
- u64 host_mmcr[3];
+ u64 host_mmcr[7]; /* MMCR 0,1,A, SIAR, SDAR, MMCR2, SIER */
u32 host_pmc[8];
u64 host_purr;
u64 host_spurr;
diff --git a/arch/powerpc/include/asm/kvm_booke_hv_asm.h b/arch/powerpc/include/asm/kvm_booke_hv_asm.h
index 3a79f5325712..e5f048bbcb7c 100644
--- a/arch/powerpc/include/asm/kvm_booke_hv_asm.h
+++ b/arch/powerpc/include/asm/kvm_booke_hv_asm.h
@@ -36,26 +36,21 @@
* *(r8 + GPR11) = saved r11
*
* 64-bit host
- * Expected inputs (GEN/GDBELL/DBG/MC exception types):
+ * Expected inputs (GEN/GDBELL/DBG/CRIT/MC exception types):
* r10 = saved CR
* r13 = PACA_POINTER
* *(r13 + PACA_EX##type + EX_R10) = saved r10
* *(r13 + PACA_EX##type + EX_R11) = saved r11
* SPRN_SPRG_##type##_SCRATCH = saved r13
*
- * Expected inputs (CRIT exception type):
- * r10 = saved CR
- * r13 = PACA_POINTER
- * *(r13 + PACA_EX##type + EX_R10) = saved r10
- * *(r13 + PACA_EX##type + EX_R11) = saved r11
- * *(r13 + PACA_EX##type + EX_R13) = saved r13
- *
* Expected inputs (TLB exception type):
* r10 = saved CR
+ * r12 = extlb pointer
* r13 = PACA_POINTER
- * *(r13 + PACA_EX##type + EX_TLB_R10) = saved r10
- * *(r13 + PACA_EX##type + EX_TLB_R11) = saved r11
- * SPRN_SPRG_GEN_SCRATCH = saved r13
+ * *(r12 + EX_TLB_R10) = saved r10
+ * *(r12 + EX_TLB_R11) = saved r11
+ * *(r12 + EX_TLB_R13) = saved r13
+ * SPRN_SPRG_GEN_SCRATCH = saved r12
*
* Only the bolted version of TLB miss exception handlers is supported now.
*/
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index fcd53f0d34ba..4096f16502a9 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -129,6 +129,8 @@ extern long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
struct kvm_create_spapr_tce *args);
extern long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
unsigned long ioba, unsigned long tce);
+extern long kvmppc_h_get_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
+ unsigned long ioba);
extern struct kvm_rma_info *kvm_alloc_rma(void);
extern void kvm_release_rma(struct kvm_rma_info *ri);
extern struct page *kvm_alloc_hpt(unsigned long nr_pages);
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index ad3025d0880b..5b6c03f1058f 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -170,6 +170,9 @@ struct machdep_calls {
int (*system_reset_exception)(struct pt_regs *regs);
int (*machine_check_exception)(struct pt_regs *regs);
+ /* Called during machine check exception to retrive fixup address. */
+ bool (*mce_check_early_recovery)(struct pt_regs *regs);
+
/* Motherboard/chipset features. This is a kind of general purpose
* hook used to control some machine specific features (like reset
* lines, chip power control, etc...).
@@ -279,6 +282,10 @@ struct machdep_calls {
#ifdef CONFIG_ARCH_RANDOM
int (*get_random_long)(unsigned long *v);
#endif
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+ int (*remove_memory)(u64, u64);
+#endif
};
extern void e500_idle(void);
diff --git a/arch/powerpc/include/asm/mce.h b/arch/powerpc/include/asm/mce.h
index 8e99edf6d966..f97d8cb6bdf6 100644
--- a/arch/powerpc/include/asm/mce.h
+++ b/arch/powerpc/include/asm/mce.h
@@ -187,7 +187,8 @@ struct mce_error_info {
#define MCE_EVENT_DONTRELEASE false
extern void save_mce_event(struct pt_regs *regs, long handled,
- struct mce_error_info *mce_err, uint64_t addr);
+ struct mce_error_info *mce_err, uint64_t nip,
+ uint64_t addr);
extern int get_mce_event(struct machine_check_event *mce, bool release);
extern void release_mce_event(void);
extern void machine_check_queue_event(void);
diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h
index 89b785d16846..901dac6b6cb7 100644
--- a/arch/powerpc/include/asm/mmu-book3e.h
+++ b/arch/powerpc/include/asm/mmu-book3e.h
@@ -287,11 +287,14 @@ extern int mmu_linear_psize;
extern int mmu_vmemmap_psize;
struct tlb_core_data {
+ /*
+ * Per-core spinlock for e6500 TLB handlers (no tlbsrx.)
+ * Must be the first struct element.
+ */
+ u8 lock;
+
/* For software way selection, as on Freescale TLB1 */
u8 esel_next, esel_max, esel_first;
-
- /* Per-core spinlock for e6500 TLB handlers (no tlbsrx.) */
- u8 lock;
};
#ifdef CONFIG_PPC64
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 40157e2ca691..fe2aa0b48d2b 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -83,6 +83,8 @@ extern int opal_enter_rtas(struct rtas_args *args,
#define OPAL_INTERNAL_ERROR -11
#define OPAL_BUSY_EVENT -12
#define OPAL_HARDWARE_FROZEN -13
+#define OPAL_WRONG_STATE -14
+#define OPAL_ASYNC_COMPLETION -15
/* API Tokens (in r0) */
#define OPAL_CONSOLE_WRITE 1
@@ -151,12 +153,27 @@ extern int opal_enter_rtas(struct rtas_args *args,
#define OPAL_LPC_READ 67
#define OPAL_LPC_WRITE 68
#define OPAL_RETURN_CPU 69
+#define OPAL_ELOG_READ 71
+#define OPAL_ELOG_WRITE 72
+#define OPAL_ELOG_ACK 73
+#define OPAL_ELOG_RESEND 74
+#define OPAL_ELOG_SIZE 75
#define OPAL_FLASH_VALIDATE 76
#define OPAL_FLASH_MANAGE 77
#define OPAL_FLASH_UPDATE 78
+#define OPAL_RESYNC_TIMEBASE 79
+#define OPAL_DUMP_INIT 81
+#define OPAL_DUMP_INFO 82
+#define OPAL_DUMP_READ 83
+#define OPAL_DUMP_ACK 84
#define OPAL_GET_MSG 85
#define OPAL_CHECK_ASYNC_COMPLETION 86
#define OPAL_SYNC_HOST_REBOOT 87
+#define OPAL_SENSOR_READ 88
+#define OPAL_GET_PARAM 89
+#define OPAL_SET_PARAM 90
+#define OPAL_DUMP_RESEND 91
+#define OPAL_DUMP_INFO2 94
#ifndef __ASSEMBLY__
@@ -237,11 +254,14 @@ enum OpalPendingState {
OPAL_EVENT_EPOW = 0x80,
OPAL_EVENT_LED_STATUS = 0x100,
OPAL_EVENT_PCI_ERROR = 0x200,
+ OPAL_EVENT_DUMP_AVAIL = 0x400,
OPAL_EVENT_MSG_PENDING = 0x800,
};
enum OpalMessageType {
- OPAL_MSG_ASYNC_COMP = 0,
+ OPAL_MSG_ASYNC_COMP = 0, /* params[0] = token, params[1] = rc,
+ * additional params function-specific
+ */
OPAL_MSG_MEM_ERR,
OPAL_MSG_EPOW,
OPAL_MSG_SHUTDOWN,
@@ -394,6 +414,13 @@ enum OpalLPCAddressType {
OPAL_LPC_FW = 2,
};
+/* System parameter permission */
+enum OpalSysparamPerm {
+ OPAL_SYSPARAM_READ = 0x1,
+ OPAL_SYSPARAM_WRITE = 0x2,
+ OPAL_SYSPARAM_RW = (OPAL_SYSPARAM_READ | OPAL_SYSPARAM_WRITE),
+};
+
struct opal_msg {
uint32_t msg_type;
uint32_t reserved;
@@ -816,23 +843,44 @@ int64_t opal_pci_next_error(uint64_t phb_id, uint64_t *first_frozen_pe,
int64_t opal_pci_poll(uint64_t phb_id);
int64_t opal_return_cpu(void);
-int64_t opal_xscom_read(uint32_t gcid, uint32_t pcb_addr, __be64 *val);
-int64_t opal_xscom_write(uint32_t gcid, uint32_t pcb_addr, uint64_t val);
+int64_t opal_xscom_read(uint32_t gcid, uint64_t pcb_addr, __be64 *val);
+int64_t opal_xscom_write(uint32_t gcid, uint64_t pcb_addr, uint64_t val);
int64_t opal_lpc_write(uint32_t chip_id, enum OpalLPCAddressType addr_type,
uint32_t addr, uint32_t data, uint32_t sz);
int64_t opal_lpc_read(uint32_t chip_id, enum OpalLPCAddressType addr_type,
uint32_t addr, __be32 *data, uint32_t sz);
+
+int64_t opal_read_elog(uint64_t buffer, size_t size, uint64_t log_id);
+int64_t opal_get_elog_size(uint64_t *log_id, size_t *size, uint64_t *elog_type);
+int64_t opal_write_elog(uint64_t buffer, uint64_t size, uint64_t offset);
+int64_t opal_send_ack_elog(uint64_t log_id);
+void opal_resend_pending_logs(void);
+
int64_t opal_validate_flash(uint64_t buffer, uint32_t *size, uint32_t *result);
int64_t opal_manage_flash(uint8_t op);
int64_t opal_update_flash(uint64_t blk_list);
+int64_t opal_dump_init(uint8_t dump_type);
+int64_t opal_dump_info(uint32_t *dump_id, uint32_t *dump_size);
+int64_t opal_dump_info2(uint32_t *dump_id, uint32_t *dump_size, uint32_t *dump_type);
+int64_t opal_dump_read(uint32_t dump_id, uint64_t buffer);
+int64_t opal_dump_ack(uint32_t dump_id);
+int64_t opal_dump_resend_notification(void);
int64_t opal_get_msg(uint64_t buffer, size_t size);
int64_t opal_check_completion(uint64_t buffer, size_t size, uint64_t token);
int64_t opal_sync_host_reboot(void);
+int64_t opal_get_param(uint64_t token, uint32_t param_id, uint64_t buffer,
+ size_t length);
+int64_t opal_set_param(uint64_t token, uint32_t param_id, uint64_t buffer,
+ size_t length);
+int64_t opal_sensor_read(uint32_t sensor_hndl, int token,
+ uint32_t *sensor_data);
/* Internal functions */
extern int early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data);
+extern int early_init_dt_scan_recoverable_ranges(unsigned long node,
+ const char *uname, int depth, void *data);
extern int opal_get_chars(uint32_t vtermno, char *buf, int count);
extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len);
@@ -853,6 +901,13 @@ extern void opal_notifier_update_evt(uint64_t evt_mask, uint64_t evt_val);
extern int opal_get_chars(uint32_t vtermno, char *buf, int count);
extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len);
+extern int __opal_async_get_token(void);
+extern int opal_async_get_token_interruptible(void);
+extern int __opal_async_release_token(int token);
+extern int opal_async_release_token(int token);
+extern int opal_async_wait_response(uint64_t token, struct opal_msg *msg);
+extern int opal_get_sensor_data(u32 sensor_hndl, u32 *sensor_data);
+
extern void hvc_opal_init_early(void);
struct rtc_time;
@@ -861,10 +916,15 @@ extern void opal_get_rtc_time(struct rtc_time *tm);
extern unsigned long opal_get_boot_time(void);
extern void opal_nvram_init(void);
extern void opal_flash_init(void);
+extern int opal_elog_init(void);
+extern void opal_platform_dump_init(void);
+extern void opal_sys_param_init(void);
extern int opal_machine_check(struct pt_regs *regs);
+extern bool opal_mce_check_early_recovery(struct pt_regs *regs);
extern void opal_shutdown(void);
+extern int opal_resync_timebase(void);
extern void opal_lpc_init(void);
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index 9c5dbc3833fb..8e956a0b6e85 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -116,8 +116,11 @@ struct paca_struct {
/* Shared by all threads of a core -- points to tcd of first thread */
struct tlb_core_data *tcd_ptr;
- /* We can have up to 3 levels of reentrancy in the TLB miss handler */
- u64 extlb[3][EX_TLB_SIZE / sizeof(u64)];
+ /*
+ * We can have up to 3 levels of reentrancy in the TLB miss handler,
+ * in each of four exception levels (normal, crit, mcheck, debug).
+ */
+ u64 extlb[12][EX_TLB_SIZE / sizeof(u64)];
u64 exmc[8]; /* used for machine checks */
u64 excrit[8]; /* used for crit interrupts */
u64 exdbg[8]; /* used for debug interrupts */
@@ -146,7 +149,7 @@ struct paca_struct {
u8 io_sync; /* writel() needs spin_unlock sync */
u8 irq_work_pending; /* IRQ_WORK interrupt while soft-disable */
u8 nap_state_lost; /* NV GPR values lost in power7_idle */
- u64 sprg3; /* Saved user-visible sprg */
+ u64 sprg_vdso; /* Saved user-visible sprg */
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
u64 tm_scratch; /* TM scratch area for reclaim */
#endif
diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h
index 3fd2f1b6f906..9ed737146dbb 100644
--- a/arch/powerpc/include/asm/perf_event_server.h
+++ b/arch/powerpc/include/asm/perf_event_server.h
@@ -14,6 +14,7 @@
#include <linux/device.h>
#include <uapi/asm/perf_event.h>
+/* Update perf_event_print_debug() if this changes */
#define MAX_HWEVENTS 8
#define MAX_EVENT_ALTERNATIVES 8
#define MAX_LIMITED_HWCOUNTERS 2
diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h
index bc141c950b1e..eb9261024f51 100644
--- a/arch/powerpc/include/asm/pgtable-ppc64.h
+++ b/arch/powerpc/include/asm/pgtable-ppc64.h
@@ -195,6 +195,7 @@ extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
static inline unsigned long pte_update(struct mm_struct *mm,
unsigned long addr,
pte_t *ptep, unsigned long clr,
+ unsigned long set,
int huge)
{
#ifdef PTE_ATOMIC_UPDATES
@@ -205,14 +206,15 @@ static inline unsigned long pte_update(struct mm_struct *mm,
andi. %1,%0,%6\n\
bne- 1b \n\
andc %1,%0,%4 \n\
+ or %1,%1,%7\n\
stdcx. %1,0,%3 \n\
bne- 1b"
: "=&r" (old), "=&r" (tmp), "=m" (*ptep)
- : "r" (ptep), "r" (clr), "m" (*ptep), "i" (_PAGE_BUSY)
+ : "r" (ptep), "r" (clr), "m" (*ptep), "i" (_PAGE_BUSY), "r" (set)
: "cc" );
#else
unsigned long old = pte_val(*ptep);
- *ptep = __pte(old & ~clr);
+ *ptep = __pte((old & ~clr) | set);
#endif
/* huge pages use the old page table lock */
if (!huge)
@@ -231,9 +233,9 @@ static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
{
unsigned long old;
- if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
+ if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
return 0;
- old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0);
+ old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0, 0);
return (old & _PAGE_ACCESSED) != 0;
}
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
@@ -252,7 +254,7 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
if ((pte_val(*ptep) & _PAGE_RW) == 0)
return;
- pte_update(mm, addr, ptep, _PAGE_RW, 0);
+ pte_update(mm, addr, ptep, _PAGE_RW, 0, 0);
}
static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
@@ -261,7 +263,7 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
if ((pte_val(*ptep) & _PAGE_RW) == 0)
return;
- pte_update(mm, addr, ptep, _PAGE_RW, 1);
+ pte_update(mm, addr, ptep, _PAGE_RW, 0, 1);
}
/*
@@ -284,14 +286,14 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
unsigned long addr, pte_t *ptep)
{
- unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0);
+ unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0, 0);
return __pte(old);
}
static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
pte_t * ptep)
{
- pte_update(mm, addr, ptep, ~0UL, 0);
+ pte_update(mm, addr, ptep, ~0UL, 0, 0);
}
@@ -506,7 +508,9 @@ extern int pmdp_set_access_flags(struct vm_area_struct *vma,
extern unsigned long pmd_hugepage_update(struct mm_struct *mm,
unsigned long addr,
- pmd_t *pmdp, unsigned long clr);
+ pmd_t *pmdp,
+ unsigned long clr,
+ unsigned long set);
static inline int __pmdp_test_and_clear_young(struct mm_struct *mm,
unsigned long addr, pmd_t *pmdp)
@@ -515,7 +519,7 @@ static inline int __pmdp_test_and_clear_young(struct mm_struct *mm,
if ((pmd_val(*pmdp) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
return 0;
- old = pmd_hugepage_update(mm, addr, pmdp, _PAGE_ACCESSED);
+ old = pmd_hugepage_update(mm, addr, pmdp, _PAGE_ACCESSED, 0);
return ((old & _PAGE_ACCESSED) != 0);
}
@@ -542,7 +546,7 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm, unsigned long addr,
if ((pmd_val(*pmdp) & _PAGE_RW) == 0)
return;
- pmd_hugepage_update(mm, addr, pmdp, _PAGE_RW);
+ pmd_hugepage_update(mm, addr, pmdp, _PAGE_RW, 0);
}
#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h
index f83b6f3e1b39..3ebb188c3ff5 100644
--- a/arch/powerpc/include/asm/pgtable.h
+++ b/arch/powerpc/include/asm/pgtable.h
@@ -75,12 +75,34 @@ static inline pte_t pte_mknuma(pte_t pte)
return pte;
}
+#define ptep_set_numa ptep_set_numa
+static inline void ptep_set_numa(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
+{
+ if ((pte_val(*ptep) & _PAGE_PRESENT) == 0)
+ VM_BUG_ON(1);
+
+ pte_update(mm, addr, ptep, _PAGE_PRESENT, _PAGE_NUMA, 0);
+ return;
+}
+
#define pmd_numa pmd_numa
static inline int pmd_numa(pmd_t pmd)
{
return pte_numa(pmd_pte(pmd));
}
+#define pmdp_set_numa pmdp_set_numa
+static inline void pmdp_set_numa(struct mm_struct *mm, unsigned long addr,
+ pmd_t *pmdp)
+{
+ if ((pmd_val(*pmdp) & _PAGE_PRESENT) == 0)
+ VM_BUG_ON(1);
+
+ pmd_hugepage_update(mm, addr, pmdp, _PAGE_PRESENT, _PAGE_NUMA);
+ return;
+}
+
#define pmd_mknonnuma pmd_mknonnuma
static inline pmd_t pmd_mknonnuma(pmd_t pmd)
{
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index b62de43ae5f3..d660dc36831a 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -450,6 +450,7 @@ enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_POWERSAVE_OFF};
extern int powersave_nap; /* set if nap mode can be used in idle loop */
extern void power7_nap(void);
+extern void power7_sleep(void);
extern void flush_instruction_cache(void);
extern void hard_reset_now(void);
extern void poweroff_now(void);
diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h
index becc08e6a65c..279b80f3bb29 100644
--- a/arch/powerpc/include/asm/ptrace.h
+++ b/arch/powerpc/include/asm/ptrace.h
@@ -28,11 +28,23 @@
#ifdef __powerpc64__
+/*
+ * Size of redzone that userspace is allowed to use below the stack
+ * pointer. This is 288 in the 64-bit big-endian ELF ABI, and 512 in
+ * the new ELFv2 little-endian ABI, so we allow the larger amount.
+ *
+ * For kernel code we allow a 288-byte redzone, in order to conserve
+ * kernel stack space; gcc currently only uses 288 bytes, and will
+ * hopefully allow explicit control of the redzone size in future.
+ */
+#define USER_REDZONE_SIZE 512
+#define KERNEL_REDZONE_SIZE 288
+
#define STACK_FRAME_OVERHEAD 112 /* size of minimum stack frame */
#define STACK_FRAME_LR_SAVE 2 /* Location of LR in stack frame */
#define STACK_FRAME_REGS_MARKER ASM_CONST(0x7265677368657265)
#define STACK_INT_FRAME_SIZE (sizeof(struct pt_regs) + \
- STACK_FRAME_OVERHEAD + 288)
+ STACK_FRAME_OVERHEAD + KERNEL_REDZONE_SIZE)
#define STACK_FRAME_MARKER 12
/* Size of dummy stack frame allocated when calling signal handler. */
@@ -41,6 +53,8 @@
#else /* __powerpc64__ */
+#define USER_REDZONE_SIZE 0
+#define KERNEL_REDZONE_SIZE 0
#define STACK_FRAME_OVERHEAD 16 /* size of minimum stack frame */
#define STACK_FRAME_LR_SAVE 1 /* Location of LR in stack frame */
#define STACK_FRAME_REGS_MARKER ASM_CONST(0x72656773)
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 90c06ec6eff5..0dcc48af25a3 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -213,6 +213,7 @@
#define SPRN_ACOP 0x1F /* Available Coprocessor Register */
#define SPRN_TFIAR 0x81 /* Transaction Failure Inst Addr */
#define SPRN_TEXASR 0x82 /* Transaction EXception & Summary */
+#define TEXASR_FS __MASK(63-36) /* Transaction Failure Summary */
#define SPRN_TEXASRU 0x83 /* '' '' '' Upper 32 */
#define SPRN_TFHAR 0x80 /* Transaction Failure Handler Addr */
#define SPRN_CTRLF 0x088
@@ -577,9 +578,13 @@
#define SPRN_SPRG3 0x113 /* Special Purpose Register General 3 */
#define SPRN_USPRG3 0x103 /* SPRG3 userspace read */
#define SPRN_SPRG4 0x114 /* Special Purpose Register General 4 */
+#define SPRN_USPRG4 0x104 /* SPRG4 userspace read */
#define SPRN_SPRG5 0x115 /* Special Purpose Register General 5 */
+#define SPRN_USPRG5 0x105 /* SPRG5 userspace read */
#define SPRN_SPRG6 0x116 /* Special Purpose Register General 6 */
+#define SPRN_USPRG6 0x106 /* SPRG6 userspace read */
#define SPRN_SPRG7 0x117 /* Special Purpose Register General 7 */
+#define SPRN_USPRG7 0x107 /* SPRG7 userspace read */
#define SPRN_SRR0 0x01A /* Save/Restore Register 0 */
#define SPRN_SRR1 0x01B /* Save/Restore Register 1 */
#define SRR1_ISI_NOPT 0x40000000 /* ISI: Not found in hash */
@@ -664,12 +669,14 @@
#define MMCR0_PMXE 0x04000000UL /* performance monitor exception enable */
#define MMCR0_FCECE 0x02000000UL /* freeze ctrs on enabled cond or event */
#define MMCR0_TBEE 0x00400000UL /* time base exception enable */
+#define MMCR0_BHRBA 0x00200000UL /* BHRB Access allowed in userspace */
#define MMCR0_EBE 0x00100000UL /* Event based branch enable */
#define MMCR0_PMCC 0x000c0000UL /* PMC control */
#define MMCR0_PMCC_U6 0x00080000UL /* PMC1-6 are R/W by user (PR) */
#define MMCR0_PMC1CE 0x00008000UL /* PMC1 count enable*/
#define MMCR0_PMCjCE 0x00004000UL /* PMCj count enable*/
#define MMCR0_TRIGGER 0x00002000UL /* TRIGGER enable */
+#define MMCR0_PMAO_SYNC 0x00000800UL /* PMU interrupt is synchronous */
#define MMCR0_PMAO 0x00000080UL /* performance monitor alert has occurred, set to 0 after handling exception */
#define MMCR0_SHRFC 0x00000040UL /* SHRre freeze conditions between threads */
#define MMCR0_FC56 0x00000010UL /* freeze counters 5 and 6 */
@@ -703,6 +710,7 @@
#define SPRN_EBBHR 804 /* Event based branch handler register */
#define SPRN_EBBRR 805 /* Event based branch return register */
#define SPRN_BESCR 806 /* Branch event status and control register */
+#define BESCR_GE 0x8000000000000000ULL /* Global Enable */
#define SPRN_WORT 895 /* Workload optimization register - thread */
#define SPRN_PMC1 787
@@ -879,11 +887,10 @@
* 64-bit embedded
* - SPRG0 generic exception scratch
* - SPRG2 TLB exception stack
- * - SPRG3 critical exception scratch and
- * CPU and NUMA node for VDSO getcpu (user visible)
+ * - SPRG3 critical exception scratch (user visible, sorry!)
* - SPRG4 unused (user visible)
* - SPRG6 TLB miss scratch (user visible, sorry !)
- * - SPRG7 critical exception scratch
+ * - SPRG7 CPU and NUMA node for VDSO getcpu (user visible)
* - SPRG8 machine check exception scratch
* - SPRG9 debug exception scratch
*
@@ -940,6 +947,8 @@
#define SPRN_SPRG_SCRATCH0 SPRN_SPRG2
#define SPRN_SPRG_HPACA SPRN_HSPRG0
#define SPRN_SPRG_HSCRATCH0 SPRN_HSPRG1
+#define SPRN_SPRG_VDSO_READ SPRN_USPRG3
+#define SPRN_SPRG_VDSO_WRITE SPRN_SPRG3
#define GET_PACA(rX) \
BEGIN_FTR_SECTION_NESTED(66); \
@@ -983,6 +992,8 @@
#define SPRN_SPRG_TLB_SCRATCH SPRN_SPRG6
#define SPRN_SPRG_GEN_SCRATCH SPRN_SPRG0
#define SPRN_SPRG_GDBELL_SCRATCH SPRN_SPRG_GEN_SCRATCH
+#define SPRN_SPRG_VDSO_READ SPRN_USPRG7
+#define SPRN_SPRG_VDSO_WRITE SPRN_SPRG7
#define SET_PACA(rX) mtspr SPRN_SPRG_PACA,rX
#define GET_PACA(rX) mfspr rX,SPRN_SPRG_PACA
@@ -1102,6 +1113,8 @@
#define PVR_8560 0x80200000
#define PVR_VER_E500V1 0x8020
#define PVR_VER_E500V2 0x8021
+#define PVR_VER_E500MC 0x8023
+#define PVR_VER_E5500 0x8024
#define PVR_VER_E6500 0x8040
/*
diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
index 9bd52c65e66f..a0e1add01ef5 100644
--- a/arch/powerpc/include/asm/rtas.h
+++ b/arch/powerpc/include/asm/rtas.h
@@ -283,6 +283,7 @@ extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal);
#ifdef CONFIG_PPC_PSERIES
extern int pseries_devicetree_update(s32 scope);
+extern void post_mobility_fixup(void);
#endif
#ifdef CONFIG_PPC_RTAS_DAEMON
diff --git a/arch/powerpc/include/asm/sections.h b/arch/powerpc/include/asm/sections.h
index 4ee06fe15de4..d0e784e0ff48 100644
--- a/arch/powerpc/include/asm/sections.h
+++ b/arch/powerpc/include/asm/sections.h
@@ -8,6 +8,7 @@
#ifdef __powerpc64__
+extern char __start_interrupts[];
extern char __end_interrupts[];
extern char __prom_init_toc_start[];
@@ -21,6 +22,17 @@ static inline int in_kernel_text(unsigned long addr)
return 0;
}
+static inline int overlaps_interrupt_vector_text(unsigned long start,
+ unsigned long end)
+{
+ unsigned long real_start, real_end;
+ real_start = __start_interrupts - _stext;
+ real_end = __end_interrupts - _stext;
+
+ return start < (unsigned long)__va(real_end) &&
+ (unsigned long)__va(real_start) < end;
+}
+
static inline int overlaps_kernel_text(unsigned long start, unsigned long end)
{
return start < (unsigned long)__init_end &&
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index 084e0807db98..ff51046b6466 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -120,7 +120,7 @@ extern int cpu_to_core_id(int cpu);
* in /proc/interrupts will be wrong!!! --Troy */
#define PPC_MSG_CALL_FUNCTION 0
#define PPC_MSG_RESCHEDULE 1
-#define PPC_MSG_CALL_FUNC_SINGLE 2
+#define PPC_MSG_TICK_BROADCAST 2
#define PPC_MSG_DEBUGGER_BREAK 3
/* for irq controllers that have dedicated ipis per message (4) */
diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h
index c1f267694acb..1d428e6007ca 100644
--- a/arch/powerpc/include/asm/time.h
+++ b/arch/powerpc/include/asm/time.h
@@ -28,6 +28,7 @@ extern struct clock_event_device decrementer_clockevent;
struct rtc_time;
extern void to_tm(int tim, struct rtc_time * tm);
extern void GregorianDay(struct rtc_time *tm);
+extern void tick_broadcast_ipi_handler(void);
extern void generic_calibrate_decr(void);
diff --git a/arch/powerpc/include/asm/tm.h b/arch/powerpc/include/asm/tm.h
index 0c9f8b74dd97..c22d704b6d41 100644
--- a/arch/powerpc/include/asm/tm.h
+++ b/arch/powerpc/include/asm/tm.h
@@ -7,6 +7,8 @@
#include <uapi/asm/tm.h>
+#ifndef __ASSEMBLY__
+
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
extern void do_load_up_transact_fpu(struct thread_struct *thread);
extern void do_load_up_transact_altivec(struct thread_struct *thread);
@@ -21,3 +23,5 @@ extern void tm_recheckpoint(struct thread_struct *thread,
extern void tm_abort(uint8_t cause);
extern void tm_save_sprs(struct thread_struct *thread);
extern void tm_restore_sprs(struct thread_struct *thread);
+
+#endif /* __ASSEMBLY__ */
diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index d0b5fca6b077..c9202151079f 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -99,7 +99,6 @@ static inline int prrn_is_enabled(void)
#ifdef CONFIG_SMP
#include <asm/cputable.h>
-#define smt_capable() (cpu_has_feature(CPU_FTR_SMT))
#ifdef CONFIG_PPC64
#include <asm/smp.h>
diff --git a/arch/powerpc/include/asm/vdso.h b/arch/powerpc/include/asm/vdso.h
index 0d9cecddf8a4..c53f5f6d1761 100644
--- a/arch/powerpc/include/asm/vdso.h
+++ b/arch/powerpc/include/asm/vdso.h
@@ -4,11 +4,11 @@
#ifdef __KERNEL__
/* Default link addresses for the vDSOs */
-#define VDSO32_LBASE 0x100000
-#define VDSO64_LBASE 0x100000
+#define VDSO32_LBASE 0x0
+#define VDSO64_LBASE 0x0
/* Default map addresses for 32bit vDSO */
-#define VDSO32_MBASE VDSO32_LBASE
+#define VDSO32_MBASE 0x100000
#define VDSO_VERSION_STRING LINUX_2.6.15
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index b5aacf72ae6f..dba8140ebc20 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -253,7 +253,7 @@ int main(void)
DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time));
DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save));
DEFINE(PACA_NAPSTATELOST, offsetof(struct paca_struct, nap_state_lost));
- DEFINE(PACA_SPRG3, offsetof(struct paca_struct, sprg3));
+ DEFINE(PACA_SPRG_VDSO, offsetof(struct paca_struct, sprg_vdso));
#endif /* CONFIG_PPC64 */
/* RTAS */
diff --git a/arch/powerpc/kernel/cacheinfo.c b/arch/powerpc/kernel/cacheinfo.c
index 2912b8787aa4..40198d50b4c2 100644
--- a/arch/powerpc/kernel/cacheinfo.c
+++ b/arch/powerpc/kernel/cacheinfo.c
@@ -756,7 +756,10 @@ void cacheinfo_cpu_online(unsigned int cpu_id)
cacheinfo_sysfs_populate(cpu_id, cache);
}
-#ifdef CONFIG_HOTPLUG_CPU /* functions needed for cpu offline */
+/* functions needed to remove cache entry for cpu offline or suspend/resume */
+
+#if (defined(CONFIG_PPC_PSERIES) && defined(CONFIG_SUSPEND)) || \
+ defined(CONFIG_HOTPLUG_CPU)
static struct cache *cache_lookup_by_cpu(unsigned int cpu_id)
{
@@ -843,4 +846,4 @@ void cacheinfo_cpu_offline(unsigned int cpu_id)
if (cache)
cache_cpu_clear(cache, cpu_id);
}
-#endif /* CONFIG_HOTPLUG_CPU */
+#endif /* (CONFIG_PPC_PSERIES && CONFIG_SUSPEND) || CONFIG_HOTPLUG_CPU */
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 6c8dd5da4de5..c1faade6506d 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -510,7 +510,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.pvr_mask = 0xffff0000,
.pvr_value = 0x004b0000,
.cpu_name = "POWER8E (raw)",
- .cpu_features = CPU_FTRS_POWER8,
+ .cpu_features = CPU_FTRS_POWER8E,
.cpu_user_features = COMMON_USER_POWER8,
.cpu_user_features2 = COMMON_USER2_POWER8,
.mmu_features = MMU_FTRS_POWER8,
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c
index 11c1d069d920..7a13f378ca2c 100644
--- a/arch/powerpc/kernel/crash_dump.c
+++ b/arch/powerpc/kernel/crash_dump.c
@@ -98,17 +98,19 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
size_t csize, unsigned long offset, int userbuf)
{
void *vaddr;
+ phys_addr_t paddr;
if (!csize)
return 0;
csize = min_t(size_t, csize, PAGE_SIZE);
+ paddr = pfn << PAGE_SHIFT;
- if ((min_low_pfn < pfn) && (pfn < max_pfn)) {
- vaddr = __va(pfn << PAGE_SHIFT);
+ if (memblock_is_region_memory(paddr, csize)) {
+ vaddr = __va(paddr);
csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf);
} else {
- vaddr = __ioremap(pfn << PAGE_SHIFT, PAGE_SIZE, 0);
+ vaddr = __ioremap(paddr, PAGE_SIZE, 0);
csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf);
iounmap(vaddr);
}
diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c
index 8032b97ccdcb..ee78f6e49d64 100644
--- a/arch/powerpc/kernel/dma.c
+++ b/arch/powerpc/kernel/dma.c
@@ -191,12 +191,10 @@ EXPORT_SYMBOL(dma_direct_ops);
#define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)
-int dma_set_mask(struct device *dev, u64 dma_mask)
+int __dma_set_mask(struct device *dev, u64 dma_mask)
{
struct dma_map_ops *dma_ops = get_dma_ops(dev);
- if (ppc_md.dma_set_mask)
- return ppc_md.dma_set_mask(dev, dma_mask);
if ((dma_ops != NULL) && (dma_ops->set_dma_mask != NULL))
return dma_ops->set_dma_mask(dev, dma_mask);
if (!dev->dma_mask || !dma_supported(dev, dma_mask))
@@ -204,6 +202,12 @@ int dma_set_mask(struct device *dev, u64 dma_mask)
*dev->dma_mask = dma_mask;
return 0;
}
+int dma_set_mask(struct device *dev, u64 dma_mask)
+{
+ if (ppc_md.dma_set_mask)
+ return ppc_md.dma_set_mask(dev, dma_mask);
+ return __dma_set_mask(dev, dma_mask);
+}
EXPORT_SYMBOL(dma_set_mask);
u64 dma_get_required_mask(struct device *dev)
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index 148db72a8c43..e7b76a6bf150 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -28,6 +28,7 @@
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/rbtree.h>
+#include <linux/reboot.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/export.h>
@@ -89,7 +90,7 @@
/* Platform dependent EEH operations */
struct eeh_ops *eeh_ops = NULL;
-int eeh_subsystem_enabled;
+bool eeh_subsystem_enabled = false;
EXPORT_SYMBOL(eeh_subsystem_enabled);
/*
@@ -364,7 +365,7 @@ int eeh_dev_check_failure(struct eeh_dev *edev)
eeh_stats.total_mmio_ffs++;
- if (!eeh_subsystem_enabled)
+ if (!eeh_enabled())
return 0;
if (!edev) {
@@ -747,6 +748,17 @@ int __exit eeh_ops_unregister(const char *name)
return -EEXIST;
}
+static int eeh_reboot_notifier(struct notifier_block *nb,
+ unsigned long action, void *unused)
+{
+ eeh_set_enable(false);
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block eeh_reboot_nb = {
+ .notifier_call = eeh_reboot_notifier,
+};
+
/**
* eeh_init - EEH initialization
*
@@ -778,6 +790,14 @@ int eeh_init(void)
if (machine_is(powernv) && cnt++ <= 0)
return ret;
+ /* Register reboot notifier */
+ ret = register_reboot_notifier(&eeh_reboot_nb);
+ if (ret) {
+ pr_warn("%s: Failed to register notifier (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
/* call platform initialization function */
if (!eeh_ops) {
pr_warning("%s: Platform EEH operation not found\n",
@@ -822,7 +842,7 @@ int eeh_init(void)
return ret;
}
- if (eeh_subsystem_enabled)
+ if (eeh_enabled())
pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n");
else
pr_warning("EEH: No capable adapters found\n");
@@ -897,7 +917,7 @@ void eeh_add_device_late(struct pci_dev *dev)
struct device_node *dn;
struct eeh_dev *edev;
- if (!dev || !eeh_subsystem_enabled)
+ if (!dev || !eeh_enabled())
return;
pr_debug("EEH: Adding device %s\n", pci_name(dev));
@@ -1005,7 +1025,7 @@ void eeh_remove_device(struct pci_dev *dev)
{
struct eeh_dev *edev;
- if (!dev || !eeh_subsystem_enabled)
+ if (!dev || !eeh_enabled())
return;
edev = pci_dev_to_eeh_dev(dev);
@@ -1045,7 +1065,7 @@ void eeh_remove_device(struct pci_dev *dev)
static int proc_eeh_show(struct seq_file *m, void *v)
{
- if (0 == eeh_subsystem_enabled) {
+ if (!eeh_enabled()) {
seq_printf(m, "EEH Subsystem is globally disabled\n");
seq_printf(m, "eeh_total_mmio_ffs=%llu\n", eeh_stats.total_mmio_ffs);
} else {
diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
index 7bb30dca4e19..bb61ca58ca6d 100644
--- a/arch/powerpc/kernel/eeh_driver.c
+++ b/arch/powerpc/kernel/eeh_driver.c
@@ -143,13 +143,30 @@ static void eeh_disable_irq(struct pci_dev *dev)
static void eeh_enable_irq(struct pci_dev *dev)
{
struct eeh_dev *edev = pci_dev_to_eeh_dev(dev);
- struct irq_desc *desc;
if ((edev->mode) & EEH_DEV_IRQ_DISABLED) {
edev->mode &= ~EEH_DEV_IRQ_DISABLED;
-
- desc = irq_to_desc(dev->irq);
- if (desc && desc->depth > 0)
+ /*
+ * FIXME !!!!!
+ *
+ * This is just ass backwards. This maze has
+ * unbalanced irq_enable/disable calls. So instead of
+ * finding the root cause it works around the warning
+ * in the irq_enable code by conditionally calling
+ * into it.
+ *
+ * That's just wrong.The warning in the core code is
+ * there to tell people to fix their assymetries in
+ * their own code, not by abusing the core information
+ * to avoid it.
+ *
+ * I so wish that the assymetry would be the other way
+ * round and a few more irq_disable calls render that
+ * shit unusable forever.
+ *
+ * tglx
+ */
+ if (irqd_irq_disabled(irq_get_irq_data(dev->irq)))
enable_irq(dev->irq);
}
}
@@ -362,9 +379,13 @@ static void *eeh_rmv_device(void *data, void *userdata)
*/
if (!dev || (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE))
return NULL;
+
driver = eeh_pcid_get(dev);
- if (driver && driver->err_handler)
- return NULL;
+ if (driver) {
+ eeh_pcid_put(dev);
+ if (driver->err_handler)
+ return NULL;
+ }
/* Remove it from PCI subsystem */
pr_debug("EEH: Removing %s without EEH sensitive driver\n",
diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S
index 063b65dd4f27..c1bee3ce9d1f 100644
--- a/arch/powerpc/kernel/exceptions-64e.S
+++ b/arch/powerpc/kernel/exceptions-64e.S
@@ -34,7 +34,250 @@
* special interrupts from within a non-standard level will probably
* blow you up
*/
-#define SPECIAL_EXC_FRAME_SIZE INT_FRAME_SIZE
+#define SPECIAL_EXC_SRR0 0
+#define SPECIAL_EXC_SRR1 1
+#define SPECIAL_EXC_SPRG_GEN 2
+#define SPECIAL_EXC_SPRG_TLB 3
+#define SPECIAL_EXC_MAS0 4
+#define SPECIAL_EXC_MAS1 5
+#define SPECIAL_EXC_MAS2 6
+#define SPECIAL_EXC_MAS3 7
+#define SPECIAL_EXC_MAS6 8
+#define SPECIAL_EXC_MAS7 9
+#define SPECIAL_EXC_MAS5 10 /* E.HV only */
+#define SPECIAL_EXC_MAS8 11 /* E.HV only */
+#define SPECIAL_EXC_IRQHAPPENED 12
+#define SPECIAL_EXC_DEAR 13
+#define SPECIAL_EXC_ESR 14
+#define SPECIAL_EXC_SOFTE 15
+#define SPECIAL_EXC_CSRR0 16
+#define SPECIAL_EXC_CSRR1 17
+/* must be even to keep 16-byte stack alignment */
+#define SPECIAL_EXC_END 18
+
+#define SPECIAL_EXC_FRAME_SIZE (INT_FRAME_SIZE + SPECIAL_EXC_END * 8)
+#define SPECIAL_EXC_FRAME_OFFS (INT_FRAME_SIZE - 288)
+
+#define SPECIAL_EXC_STORE(reg, name) \
+ std reg, (SPECIAL_EXC_##name * 8 + SPECIAL_EXC_FRAME_OFFS)(r1)
+
+#define SPECIAL_EXC_LOAD(reg, name) \
+ ld reg, (SPECIAL_EXC_##name * 8 + SPECIAL_EXC_FRAME_OFFS)(r1)
+
+special_reg_save:
+ lbz r9,PACAIRQHAPPENED(r13)
+ RECONCILE_IRQ_STATE(r3,r4)
+
+ /*
+ * We only need (or have stack space) to save this stuff if
+ * we interrupted the kernel.
+ */
+ ld r3,_MSR(r1)
+ andi. r3,r3,MSR_PR
+ bnelr
+
+ /* Copy info into temporary exception thread info */
+ ld r11,PACAKSAVE(r13)
+ CURRENT_THREAD_INFO(r11, r11)
+ CURRENT_THREAD_INFO(r12, r1)
+ ld r10,TI_FLAGS(r11)
+ std r10,TI_FLAGS(r12)
+ ld r10,TI_PREEMPT(r11)
+ std r10,TI_PREEMPT(r12)
+ ld r10,TI_TASK(r11)
+ std r10,TI_TASK(r12)
+
+ /*
+ * Advance to the next TLB exception frame for handler
+ * types that don't do it automatically.
+ */
+ LOAD_REG_ADDR(r11,extlb_level_exc)
+ lwz r12,0(r11)
+ mfspr r10,SPRN_SPRG_TLB_EXFRAME
+ add r10,r10,r12
+ mtspr SPRN_SPRG_TLB_EXFRAME,r10
+
+ /*
+ * Save registers needed to allow nesting of certain exceptions
+ * (such as TLB misses) inside special exception levels
+ */
+ mfspr r10,SPRN_SRR0
+ SPECIAL_EXC_STORE(r10,SRR0)
+ mfspr r10,SPRN_SRR1
+ SPECIAL_EXC_STORE(r10,SRR1)
+ mfspr r10,SPRN_SPRG_GEN_SCRATCH
+ SPECIAL_EXC_STORE(r10,SPRG_GEN)
+ mfspr r10,SPRN_SPRG_TLB_SCRATCH
+ SPECIAL_EXC_STORE(r10,SPRG_TLB)
+ mfspr r10,SPRN_MAS0
+ SPECIAL_EXC_STORE(r10,MAS0)
+ mfspr r10,SPRN_MAS1
+ SPECIAL_EXC_STORE(r10,MAS1)
+ mfspr r10,SPRN_MAS2
+ SPECIAL_EXC_STORE(r10,MAS2)
+ mfspr r10,SPRN_MAS3
+ SPECIAL_EXC_STORE(r10,MAS3)
+ mfspr r10,SPRN_MAS6
+ SPECIAL_EXC_STORE(r10,MAS6)
+ mfspr r10,SPRN_MAS7
+ SPECIAL_EXC_STORE(r10,MAS7)
+BEGIN_FTR_SECTION
+ mfspr r10,SPRN_MAS5
+ SPECIAL_EXC_STORE(r10,MAS5)
+ mfspr r10,SPRN_MAS8
+ SPECIAL_EXC_STORE(r10,MAS8)
+
+ /* MAS5/8 could have inappropriate values if we interrupted KVM code */
+ li r10,0
+ mtspr SPRN_MAS5,r10
+ mtspr SPRN_MAS8,r10
+END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV)
+ SPECIAL_EXC_STORE(r9,IRQHAPPENED)
+
+ mfspr r10,SPRN_DEAR
+ SPECIAL_EXC_STORE(r10,DEAR)
+ mfspr r10,SPRN_ESR
+ SPECIAL_EXC_STORE(r10,ESR)
+
+ lbz r10,PACASOFTIRQEN(r13)
+ SPECIAL_EXC_STORE(r10,SOFTE)
+ ld r10,_NIP(r1)
+ SPECIAL_EXC_STORE(r10,CSRR0)
+ ld r10,_MSR(r1)
+ SPECIAL_EXC_STORE(r10,CSRR1)
+
+ blr
+
+ret_from_level_except:
+ ld r3,_MSR(r1)
+ andi. r3,r3,MSR_PR
+ beq 1f
+ b ret_from_except
+1:
+
+ LOAD_REG_ADDR(r11,extlb_level_exc)
+ lwz r12,0(r11)
+ mfspr r10,SPRN_SPRG_TLB_EXFRAME
+ sub r10,r10,r12
+ mtspr SPRN_SPRG_TLB_EXFRAME,r10
+
+ /*
+ * It's possible that the special level exception interrupted a
+ * TLB miss handler, and inserted the same entry that the
+ * interrupted handler was about to insert. On CPUs without TLB
+ * write conditional, this can result in a duplicate TLB entry.
+ * Wipe all non-bolted entries to be safe.
+ *
+ * Note that this doesn't protect against any TLB misses
+ * we may take accessing the stack from here to the end of
+ * the special level exception. It's not clear how we can
+ * reasonably protect against that, but only CPUs with
+ * neither TLB write conditional nor bolted kernel memory
+ * are affected. Do any such CPUs even exist?
+ */
+ PPC_TLBILX_ALL(0,R0)
+
+ REST_NVGPRS(r1)
+
+ SPECIAL_EXC_LOAD(r10,SRR0)
+ mtspr SPRN_SRR0,r10
+ SPECIAL_EXC_LOAD(r10,SRR1)
+ mtspr SPRN_SRR1,r10
+ SPECIAL_EXC_LOAD(r10,SPRG_GEN)
+ mtspr SPRN_SPRG_GEN_SCRATCH,r10
+ SPECIAL_EXC_LOAD(r10,SPRG_TLB)
+ mtspr SPRN_SPRG_TLB_SCRATCH,r10
+ SPECIAL_EXC_LOAD(r10,MAS0)
+ mtspr SPRN_MAS0,r10
+ SPECIAL_EXC_LOAD(r10,MAS1)
+ mtspr SPRN_MAS1,r10
+ SPECIAL_EXC_LOAD(r10,MAS2)
+ mtspr SPRN_MAS2,r10
+ SPECIAL_EXC_LOAD(r10,MAS3)
+ mtspr SPRN_MAS3,r10
+ SPECIAL_EXC_LOAD(r10,MAS6)
+ mtspr SPRN_MAS6,r10
+ SPECIAL_EXC_LOAD(r10,MAS7)
+ mtspr SPRN_MAS7,r10
+BEGIN_FTR_SECTION
+ SPECIAL_EXC_LOAD(r10,MAS5)
+ mtspr SPRN_MAS5,r10
+ SPECIAL_EXC_LOAD(r10,MAS8)
+ mtspr SPRN_MAS8,r10
+END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV)
+
+ lbz r6,PACASOFTIRQEN(r13)
+ ld r5,SOFTE(r1)
+
+ /* Interrupts had better not already be enabled... */
+ twnei r6,0
+
+ cmpwi cr0,r5,0
+ beq 1f
+
+ TRACE_ENABLE_INTS
+ stb r5,PACASOFTIRQEN(r13)
+1:
+ /*
+ * Restore PACAIRQHAPPENED rather than setting it based on
+ * the return MSR[EE], since we could have interrupted
+ * __check_irq_replay() or other inconsistent transitory
+ * states that must remain that way.
+ */
+ SPECIAL_EXC_LOAD(r10,IRQHAPPENED)
+ stb r10,PACAIRQHAPPENED(r13)
+
+ SPECIAL_EXC_LOAD(r10,DEAR)
+ mtspr SPRN_DEAR,r10
+ SPECIAL_EXC_LOAD(r10,ESR)
+ mtspr SPRN_ESR,r10
+
+ stdcx. r0,0,r1 /* to clear the reservation */
+
+ REST_4GPRS(2, r1)
+ REST_4GPRS(6, r1)
+
+ ld r10,_CTR(r1)
+ ld r11,_XER(r1)
+ mtctr r10
+ mtxer r11
+
+ blr
+
+.macro ret_from_level srr0 srr1 paca_ex scratch
+ bl ret_from_level_except
+
+ ld r10,_LINK(r1)
+ ld r11,_CCR(r1)
+ ld r0,GPR13(r1)
+ mtlr r10
+ mtcr r11
+
+ ld r10,GPR10(r1)
+ ld r11,GPR11(r1)
+ ld r12,GPR12(r1)
+ mtspr \scratch,r0
+
+ std r10,\paca_ex+EX_R10(r13);
+ std r11,\paca_ex+EX_R11(r13);
+ ld r10,_NIP(r1)
+ ld r11,_MSR(r1)
+ ld r0,GPR0(r1)
+ ld r1,GPR1(r1)
+ mtspr \srr0,r10
+ mtspr \srr1,r11
+ ld r10,\paca_ex+EX_R10(r13)
+ ld r11,\paca_ex+EX_R11(r13)
+ mfspr r13,\scratch
+.endm
+
+ret_from_crit_except:
+ ret_from_level SPRN_CSRR0 SPRN_CSRR1 PACA_EXCRIT SPRN_SPRG_CRIT_SCRATCH
+ rfci
+
+ret_from_mc_except:
+ ret_from_level SPRN_MCSRR0 SPRN_MCSRR1 PACA_EXMC SPRN_SPRG_MC_SCRATCH
+ rfmci
/* Exception prolog code for all exceptions */
#define EXCEPTION_PROLOG(n, intnum, type, addition) \
@@ -42,7 +285,6 @@
mfspr r13,SPRN_SPRG_PACA; /* get PACA */ \
std r10,PACA_EX##type+EX_R10(r13); \
std r11,PACA_EX##type+EX_R11(r13); \
- PROLOG_STORE_RESTORE_SCRATCH_##type; \
mfcr r10; /* save CR */ \
mfspr r11,SPRN_##type##_SRR1;/* what are we coming from */ \
DO_KVM intnum,SPRN_##type##_SRR1; /* KVM hook */ \
@@ -69,19 +311,19 @@
#define CRIT_SET_KSTACK \
ld r1,PACA_CRIT_STACK(r13); \
- subi r1,r1,SPECIAL_EXC_FRAME_SIZE;
+ subi r1,r1,SPECIAL_EXC_FRAME_SIZE
#define SPRN_CRIT_SRR0 SPRN_CSRR0
#define SPRN_CRIT_SRR1 SPRN_CSRR1
#define DBG_SET_KSTACK \
ld r1,PACA_DBG_STACK(r13); \
- subi r1,r1,SPECIAL_EXC_FRAME_SIZE;
+ subi r1,r1,SPECIAL_EXC_FRAME_SIZE
#define SPRN_DBG_SRR0 SPRN_DSRR0
#define SPRN_DBG_SRR1 SPRN_DSRR1
#define MC_SET_KSTACK \
ld r1,PACA_MC_STACK(r13); \
- subi r1,r1,SPECIAL_EXC_FRAME_SIZE;
+ subi r1,r1,SPECIAL_EXC_FRAME_SIZE
#define SPRN_MC_SRR0 SPRN_MCSRR0
#define SPRN_MC_SRR1 SPRN_MCSRR1
@@ -100,20 +342,6 @@
#define GDBELL_EXCEPTION_PROLOG(n, intnum, addition) \
EXCEPTION_PROLOG(n, intnum, GDBELL, addition##_GDBELL(n))
-/*
- * Store user-visible scratch in PACA exception slots and restore proper value
- */
-#define PROLOG_STORE_RESTORE_SCRATCH_GEN
-#define PROLOG_STORE_RESTORE_SCRATCH_GDBELL
-#define PROLOG_STORE_RESTORE_SCRATCH_DBG
-#define PROLOG_STORE_RESTORE_SCRATCH_MC
-
-#define PROLOG_STORE_RESTORE_SCRATCH_CRIT \
- mfspr r10,SPRN_SPRG_CRIT_SCRATCH; /* get r13 */ \
- std r10,PACA_EXCRIT+EX_R13(r13); \
- ld r11,PACA_SPRG3(r13); \
- mtspr SPRN_SPRG_CRIT_SCRATCH,r11;
-
/* Variants of the "addition" argument for the prolog
*/
#define PROLOG_ADDITION_NONE_GEN(n)
@@ -147,10 +375,8 @@
std r15,PACA_EXMC+EX_R15(r13)
-/* Core exception code for all exceptions except TLB misses.
- * XXX: Needs to make SPRN_SPRG_GEN depend on exception type
- */
-#define EXCEPTION_COMMON(n, excf, ints) \
+/* Core exception code for all exceptions except TLB misses. */
+#define EXCEPTION_COMMON_LVL(n, scratch, excf) \
exc_##n##_common: \
std r0,GPR0(r1); /* save r0 in stackframe */ \
std r2,GPR2(r1); /* save r2 in stackframe */ \
@@ -163,7 +389,7 @@ exc_##n##_common: \
ACCOUNT_CPU_USER_ENTRY(r10,r11);/* accounting (uses cr0+eq) */ \
2: ld r3,excf+EX_R10(r13); /* get back r10 */ \
ld r4,excf+EX_R11(r13); /* get back r11 */ \
- mfspr r5,SPRN_SPRG_GEN_SCRATCH;/* get back r13 */ \
+ mfspr r5,scratch; /* get back r13 */ \
std r12,GPR12(r1); /* save r12 in stackframe */ \
ld r2,PACATOC(r13); /* get kernel TOC into r2 */ \
mflr r6; /* save LR in stackframe */ \
@@ -187,24 +413,29 @@ exc_##n##_common: \
std r11,SOFTE(r1); /* and save it to stackframe */ \
std r12,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame */ \
std r3,_TRAP(r1); /* set trap number */ \
- std r0,RESULT(r1); /* clear regs->result */ \
- ints;
+ std r0,RESULT(r1); /* clear regs->result */
-/* Variants for the "ints" argument. This one does nothing when we want
- * to keep interrupts in their original state
- */
-#define INTS_KEEP
+#define EXCEPTION_COMMON(n) \
+ EXCEPTION_COMMON_LVL(n, SPRN_SPRG_GEN_SCRATCH, PACA_EXGEN)
+#define EXCEPTION_COMMON_CRIT(n) \
+ EXCEPTION_COMMON_LVL(n, SPRN_SPRG_CRIT_SCRATCH, PACA_EXCRIT)
+#define EXCEPTION_COMMON_MC(n) \
+ EXCEPTION_COMMON_LVL(n, SPRN_SPRG_MC_SCRATCH, PACA_EXMC)
+#define EXCEPTION_COMMON_DBG(n) \
+ EXCEPTION_COMMON_LVL(n, SPRN_SPRG_DBG_SCRATCH, PACA_EXDBG)
-/* This second version is meant for exceptions that don't immediately
- * hard-enable. We set a bit in paca->irq_happened to ensure that
- * a subsequent call to arch_local_irq_restore() will properly
- * hard-enable and avoid the fast-path, and then reconcile irq state.
+/*
+ * This is meant for exceptions that don't immediately hard-enable. We
+ * set a bit in paca->irq_happened to ensure that a subsequent call to
+ * arch_local_irq_restore() will properly hard-enable and avoid the
+ * fast-path, and then reconcile irq state.
*/
#define INTS_DISABLE RECONCILE_IRQ_STATE(r3,r4)
-/* This is called by exceptions that used INTS_KEEP (that did not touch
- * irq indicators in the PACA). This will restore MSR:EE to it's previous
- * value
+/*
+ * This is called by exceptions that don't use INTS_DISABLE (that did not
+ * touch irq indicators in the PACA). This will restore MSR:EE to it's
+ * previous value
*
* XXX In the long run, we may want to open-code it in order to separate the
* load from the wrtee, thus limiting the latency caused by the dependency
@@ -262,7 +493,8 @@ exc_##n##_bad_stack: \
#define MASKABLE_EXCEPTION(trapnum, intnum, label, hdlr, ack) \
START_EXCEPTION(label); \
NORMAL_EXCEPTION_PROLOG(trapnum, intnum, PROLOG_ADDITION_MASKABLE)\
- EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE) \
+ EXCEPTION_COMMON(trapnum) \
+ INTS_DISABLE; \
ack(r8); \
CHECK_NAPPING(); \
addi r3,r1,STACK_FRAME_OVERHEAD; \
@@ -283,8 +515,8 @@ exception_marker:
.balign 0x1000
.globl interrupt_base_book3e
interrupt_base_book3e: /* fake trap */
- EXCEPTION_STUB(0x000, machine_check) /* 0x0200 */
- EXCEPTION_STUB(0x020, critical_input) /* 0x0580 */
+ EXCEPTION_STUB(0x000, machine_check)
+ EXCEPTION_STUB(0x020, critical_input) /* 0x0100 */
EXCEPTION_STUB(0x040, debug_crit) /* 0x0d00 */
EXCEPTION_STUB(0x060, data_storage) /* 0x0300 */
EXCEPTION_STUB(0x080, instruction_storage) /* 0x0400 */
@@ -299,8 +531,8 @@ interrupt_base_book3e: /* fake trap */
EXCEPTION_STUB(0x1a0, watchdog) /* 0x09f0 */
EXCEPTION_STUB(0x1c0, data_tlb_miss)
EXCEPTION_STUB(0x1e0, instruction_tlb_miss)
- EXCEPTION_STUB(0x200, altivec_unavailable) /* 0x0f20 */
- EXCEPTION_STUB(0x220, altivec_assist) /* 0x1700 */
+ EXCEPTION_STUB(0x200, altivec_unavailable)
+ EXCEPTION_STUB(0x220, altivec_assist)
EXCEPTION_STUB(0x260, perfmon)
EXCEPTION_STUB(0x280, doorbell)
EXCEPTION_STUB(0x2a0, doorbell_crit)
@@ -317,25 +549,25 @@ interrupt_end_book3e:
START_EXCEPTION(critical_input);
CRIT_EXCEPTION_PROLOG(0x100, BOOKE_INTERRUPT_CRITICAL,
PROLOG_ADDITION_NONE)
-// EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE)
-// bl special_reg_save_crit
-// CHECK_NAPPING();
-// addi r3,r1,STACK_FRAME_OVERHEAD
-// bl .critical_exception
-// b ret_from_crit_except
- b .
+ EXCEPTION_COMMON_CRIT(0x100)
+ bl .save_nvgprs
+ bl special_reg_save
+ CHECK_NAPPING();
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .unknown_exception
+ b ret_from_crit_except
/* Machine Check Interrupt */
START_EXCEPTION(machine_check);
- MC_EXCEPTION_PROLOG(0x200, BOOKE_INTERRUPT_MACHINE_CHECK,
+ MC_EXCEPTION_PROLOG(0x000, BOOKE_INTERRUPT_MACHINE_CHECK,
PROLOG_ADDITION_NONE)
-// EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE)
-// bl special_reg_save_mc
-// addi r3,r1,STACK_FRAME_OVERHEAD
-// CHECK_NAPPING();
-// bl .machine_check_exception
-// b ret_from_mc_except
- b .
+ EXCEPTION_COMMON_MC(0x000)
+ bl .save_nvgprs
+ bl special_reg_save
+ CHECK_NAPPING();
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .machine_check_exception
+ b ret_from_mc_except
/* Data Storage Interrupt */
START_EXCEPTION(data_storage)
@@ -343,7 +575,8 @@ interrupt_end_book3e:
PROLOG_ADDITION_2REGS)
mfspr r14,SPRN_DEAR
mfspr r15,SPRN_ESR
- EXCEPTION_COMMON(0x300, PACA_EXGEN, INTS_DISABLE)
+ EXCEPTION_COMMON(0x300)
+ INTS_DISABLE
b storage_fault_common
/* Instruction Storage Interrupt */
@@ -352,7 +585,8 @@ interrupt_end_book3e:
PROLOG_ADDITION_2REGS)
li r15,0
mr r14,r10
- EXCEPTION_COMMON(0x400, PACA_EXGEN, INTS_DISABLE)
+ EXCEPTION_COMMON(0x400)
+ INTS_DISABLE
b storage_fault_common
/* External Input Interrupt */
@@ -365,7 +599,7 @@ interrupt_end_book3e:
PROLOG_ADDITION_2REGS)
mfspr r14,SPRN_DEAR
mfspr r15,SPRN_ESR
- EXCEPTION_COMMON(0x600, PACA_EXGEN, INTS_KEEP)
+ EXCEPTION_COMMON(0x600)
b alignment_more /* no room, go out of line */
/* Program Interrupt */
@@ -373,7 +607,8 @@ interrupt_end_book3e:
NORMAL_EXCEPTION_PROLOG(0x700, BOOKE_INTERRUPT_PROGRAM,
PROLOG_ADDITION_1REG)
mfspr r14,SPRN_ESR
- EXCEPTION_COMMON(0x700, PACA_EXGEN, INTS_DISABLE)
+ EXCEPTION_COMMON(0x700)
+ INTS_DISABLE
std r14,_DSISR(r1)
addi r3,r1,STACK_FRAME_OVERHEAD
ld r14,PACA_EXGEN+EX_R14(r13)
@@ -386,7 +621,7 @@ interrupt_end_book3e:
NORMAL_EXCEPTION_PROLOG(0x800, BOOKE_INTERRUPT_FP_UNAVAIL,
PROLOG_ADDITION_NONE)
/* we can probably do a shorter exception entry for that one... */
- EXCEPTION_COMMON(0x800, PACA_EXGEN, INTS_KEEP)
+ EXCEPTION_COMMON(0x800)
ld r12,_MSR(r1)
andi. r0,r12,MSR_PR;
beq- 1f
@@ -403,7 +638,7 @@ interrupt_end_book3e:
NORMAL_EXCEPTION_PROLOG(0x200, BOOKE_INTERRUPT_SPE_ALTIVEC_UNAVAIL,
PROLOG_ADDITION_NONE)
/* we can probably do a shorter exception entry for that one... */
- EXCEPTION_COMMON(0x200, PACA_EXGEN, INTS_KEEP)
+ EXCEPTION_COMMON(0x200)
#ifdef CONFIG_ALTIVEC
BEGIN_FTR_SECTION
ld r12,_MSR(r1)
@@ -425,7 +660,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
NORMAL_EXCEPTION_PROLOG(0x220,
BOOKE_INTERRUPT_SPE_FP_DATA_ALTIVEC_ASSIST,
PROLOG_ADDITION_NONE)
- EXCEPTION_COMMON(0x220, PACA_EXGEN, INTS_DISABLE)
+ EXCEPTION_COMMON(0x220)
+ INTS_DISABLE
bl .save_nvgprs
addi r3,r1,STACK_FRAME_OVERHEAD
#ifdef CONFIG_ALTIVEC
@@ -450,13 +686,17 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
START_EXCEPTION(watchdog);
CRIT_EXCEPTION_PROLOG(0x9f0, BOOKE_INTERRUPT_WATCHDOG,
PROLOG_ADDITION_NONE)
-// EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE)
-// bl special_reg_save_crit
-// CHECK_NAPPING();
-// addi r3,r1,STACK_FRAME_OVERHEAD
-// bl .unknown_exception
-// b ret_from_crit_except
- b .
+ EXCEPTION_COMMON_CRIT(0x9f0)
+ bl .save_nvgprs
+ bl special_reg_save
+ CHECK_NAPPING();
+ addi r3,r1,STACK_FRAME_OVERHEAD
+#ifdef CONFIG_BOOKE_WDT
+ bl .WatchdogException
+#else
+ bl .unknown_exception
+#endif
+ b ret_from_crit_except
/* System Call Interrupt */
START_EXCEPTION(system_call)
@@ -470,7 +710,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
START_EXCEPTION(ap_unavailable);
NORMAL_EXCEPTION_PROLOG(0xf20, BOOKE_INTERRUPT_AP_UNAVAIL,
PROLOG_ADDITION_NONE)
- EXCEPTION_COMMON(0xf20, PACA_EXGEN, INTS_DISABLE)
+ EXCEPTION_COMMON(0xf20)
+ INTS_DISABLE
bl .save_nvgprs
addi r3,r1,STACK_FRAME_OVERHEAD
bl .unknown_exception
@@ -513,7 +754,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
mtcr r10
ld r10,PACA_EXCRIT+EX_R10(r13) /* restore registers */
ld r11,PACA_EXCRIT+EX_R11(r13)
- ld r13,PACA_EXCRIT+EX_R13(r13)
+ mfspr r13,SPRN_SPRG_CRIT_SCRATCH
rfci
/* Normal debug exception */
@@ -526,10 +767,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
/* Now we mash up things to make it look like we are coming on a
* normal exception
*/
- ld r15,PACA_EXCRIT+EX_R13(r13)
- mtspr SPRN_SPRG_GEN_SCRATCH,r15
mfspr r14,SPRN_DBSR
- EXCEPTION_COMMON(0xd00, PACA_EXCRIT, INTS_DISABLE)
+ EXCEPTION_COMMON_CRIT(0xd00)
std r14,_DSISR(r1)
addi r3,r1,STACK_FRAME_OVERHEAD
mr r4,r14
@@ -592,10 +831,9 @@ kernel_dbg_exc:
/* Now we mash up things to make it look like we are coming on a
* normal exception
*/
- mfspr r15,SPRN_SPRG_DBG_SCRATCH
- mtspr SPRN_SPRG_GEN_SCRATCH,r15
mfspr r14,SPRN_DBSR
- EXCEPTION_COMMON(0xd08, PACA_EXDBG, INTS_DISABLE)
+ EXCEPTION_COMMON_DBG(0xd08)
+ INTS_DISABLE
std r14,_DSISR(r1)
addi r3,r1,STACK_FRAME_OVERHEAD
mr r4,r14
@@ -608,7 +846,8 @@ kernel_dbg_exc:
START_EXCEPTION(perfmon);
NORMAL_EXCEPTION_PROLOG(0x260, BOOKE_INTERRUPT_PERFORMANCE_MONITOR,
PROLOG_ADDITION_NONE)
- EXCEPTION_COMMON(0x260, PACA_EXGEN, INTS_DISABLE)
+ EXCEPTION_COMMON(0x260)
+ INTS_DISABLE
CHECK_NAPPING()
addi r3,r1,STACK_FRAME_OVERHEAD
bl .performance_monitor_exception
@@ -622,13 +861,13 @@ kernel_dbg_exc:
START_EXCEPTION(doorbell_crit);
CRIT_EXCEPTION_PROLOG(0x2a0, BOOKE_INTERRUPT_DOORBELL_CRITICAL,
PROLOG_ADDITION_NONE)
-// EXCEPTION_COMMON(0x2a0, PACA_EXCRIT, INTS_DISABLE)
-// bl special_reg_save_crit
-// CHECK_NAPPING();
-// addi r3,r1,STACK_FRAME_OVERHEAD
-// bl .doorbell_critical_exception
-// b ret_from_crit_except
- b .
+ EXCEPTION_COMMON_CRIT(0x2a0)
+ bl .save_nvgprs
+ bl special_reg_save
+ CHECK_NAPPING();
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .unknown_exception
+ b ret_from_crit_except
/*
* Guest doorbell interrupt
@@ -637,7 +876,7 @@ kernel_dbg_exc:
START_EXCEPTION(guest_doorbell);
GDBELL_EXCEPTION_PROLOG(0x2c0, BOOKE_INTERRUPT_GUEST_DBELL,
PROLOG_ADDITION_NONE)
- EXCEPTION_COMMON(0x2c0, PACA_EXGEN, INTS_KEEP)
+ EXCEPTION_COMMON(0x2c0)
addi r3,r1,STACK_FRAME_OVERHEAD
bl .save_nvgprs
INTS_RESTORE_HARD
@@ -648,19 +887,19 @@ kernel_dbg_exc:
START_EXCEPTION(guest_doorbell_crit);
CRIT_EXCEPTION_PROLOG(0x2e0, BOOKE_INTERRUPT_GUEST_DBELL_CRIT,
PROLOG_ADDITION_NONE)
-// EXCEPTION_COMMON(0x2e0, PACA_EXCRIT, INTS_DISABLE)
-// bl special_reg_save_crit
-// CHECK_NAPPING();
-// addi r3,r1,STACK_FRAME_OVERHEAD
-// bl .guest_doorbell_critical_exception
-// b ret_from_crit_except
- b .
+ EXCEPTION_COMMON_CRIT(0x2e0)
+ bl .save_nvgprs
+ bl special_reg_save
+ CHECK_NAPPING();
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .unknown_exception
+ b ret_from_crit_except
/* Hypervisor call */
START_EXCEPTION(hypercall);
NORMAL_EXCEPTION_PROLOG(0x310, BOOKE_INTERRUPT_HV_SYSCALL,
PROLOG_ADDITION_NONE)
- EXCEPTION_COMMON(0x310, PACA_EXGEN, INTS_KEEP)
+ EXCEPTION_COMMON(0x310)
addi r3,r1,STACK_FRAME_OVERHEAD
bl .save_nvgprs
INTS_RESTORE_HARD
@@ -671,7 +910,7 @@ kernel_dbg_exc:
START_EXCEPTION(ehpriv);
NORMAL_EXCEPTION_PROLOG(0x320, BOOKE_INTERRUPT_HV_PRIV,
PROLOG_ADDITION_NONE)
- EXCEPTION_COMMON(0x320, PACA_EXGEN, INTS_KEEP)
+ EXCEPTION_COMMON(0x320)
addi r3,r1,STACK_FRAME_OVERHEAD
bl .save_nvgprs
INTS_RESTORE_HARD
@@ -682,7 +921,7 @@ kernel_dbg_exc:
START_EXCEPTION(lrat_error);
NORMAL_EXCEPTION_PROLOG(0x340, BOOKE_INTERRUPT_LRAT_ERROR,
PROLOG_ADDITION_NONE)
- EXCEPTION_COMMON(0x340, PACA_EXGEN, INTS_KEEP)
+ EXCEPTION_COMMON(0x340)
addi r3,r1,STACK_FRAME_OVERHEAD
bl .save_nvgprs
INTS_RESTORE_HARD
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 38d507306a11..d9c650ec7dac 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -121,9 +121,10 @@ BEGIN_FTR_SECTION
cmpwi cr1,r13,2
/* Total loss of HV state is fatal, we could try to use the
* PIR to locate a PACA, then use an emergency stack etc...
- * but for now, let's just stay stuck here
+ * OPAL v3 based powernv platforms have new idle states
+ * which fall in this catagory.
*/
- bgt cr1,.
+ bgt cr1,8f
GET_PACA(r13)
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
@@ -141,6 +142,11 @@ BEGIN_FTR_SECTION
beq cr1,2f
b .power7_wakeup_noloss
2: b .power7_wakeup_loss
+
+ /* Fast Sleep wakeup on PowerNV */
+8: GET_PACA(r13)
+ b .power7_wakeup_tb_loss
+
9:
END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
#endif /* CONFIG_PPC_P7_NAP */
@@ -164,13 +170,18 @@ BEGIN_FTR_SECTION
*/
mfspr r13,SPRN_SRR1
rlwinm. r13,r13,47-31,30,31
+ OPT_GET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR)
beq 9f
+ mfspr r13,SPRN_SRR1
+ rlwinm. r13,r13,47-31,30,31
/* waking up from powersave (nap) state */
cmpwi cr1,r13,2
/* Total loss of HV state is fatal. let's just stay stuck here */
+ OPT_GET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR)
bgt cr1,.
9:
+ OPT_SET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR)
END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
#endif /* CONFIG_PPC_P7_NAP */
EXCEPTION_PROLOG_0(PACA_EXMC)
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c
index 9b27b293a922..6a014c763cc7 100644
--- a/arch/powerpc/kernel/ftrace.c
+++ b/arch/powerpc/kernel/ftrace.c
@@ -74,6 +74,7 @@ ftrace_modify_code(unsigned long ip, unsigned int old, unsigned int new)
*/
static int test_24bit_addr(unsigned long ip, unsigned long addr)
{
+ addr = ppc_function_entry((void *)addr);
/* use the create_branch to verify that this offset can be branched */
return create_branch((unsigned int *)ip, addr, 0);
@@ -531,13 +532,8 @@ void arch_ftrace_update_code(int command)
ftrace_disable_ftrace_graph_caller();
}
-int __init ftrace_dyn_arch_init(void *data)
+int __init ftrace_dyn_arch_init(void)
{
- /* caller expects data to be zero */
- unsigned long *p = data;
-
- *p = 0;
-
return 0;
}
#endif /* CONFIG_DYNAMIC_FTRACE */
diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S
index 3fdef0f0c67f..c3ab86975614 100644
--- a/arch/powerpc/kernel/idle_power7.S
+++ b/arch/powerpc/kernel/idle_power7.S
@@ -17,20 +17,31 @@
#include <asm/ppc-opcode.h>
#include <asm/hw_irq.h>
#include <asm/kvm_book3s_asm.h>
+#include <asm/opal.h>
#undef DEBUG
- .text
+/* Idle state entry routines */
-_GLOBAL(power7_idle)
- /* Now check if user or arch enabled NAP mode */
- LOAD_REG_ADDRBASE(r3,powersave_nap)
- lwz r4,ADDROFF(powersave_nap)(r3)
- cmpwi 0,r4,0
- beqlr
- /* fall through */
+#define IDLE_STATE_ENTER_SEQ(IDLE_INST) \
+ /* Magic NAP/SLEEP/WINKLE mode enter sequence */ \
+ std r0,0(r1); \
+ ptesync; \
+ ld r0,0(r1); \
+1: cmp cr0,r0,r0; \
+ bne 1b; \
+ IDLE_INST; \
+ b .
-_GLOBAL(power7_nap)
+ .text
+
+/*
+ * Pass requested state in r3:
+ * 0 - nap
+ * 1 - sleep
+ */
+_GLOBAL(power7_powersave_common)
+ /* Use r3 to pass state nap/sleep/winkle */
/* NAP is a state loss, we create a regs frame on the
* stack, fill it up with the state we care about and
* stick a pointer to it in PACAR1. We really only
@@ -79,8 +90,8 @@ _GLOBAL(power7_nap)
/* Continue saving state */
SAVE_GPR(2, r1)
SAVE_NVGPRS(r1)
- mfcr r3
- std r3,_CCR(r1)
+ mfcr r4
+ std r4,_CCR(r1)
std r9,_MSR(r1)
std r1,PACAR1(r13)
@@ -90,15 +101,56 @@ _GLOBAL(power7_enter_nap_mode)
li r4,KVM_HWTHREAD_IN_NAP
stb r4,HSTATE_HWTHREAD_STATE(r13)
#endif
+ cmpwi cr0,r3,1
+ beq 2f
+ IDLE_STATE_ENTER_SEQ(PPC_NAP)
+ /* No return */
+2: IDLE_STATE_ENTER_SEQ(PPC_SLEEP)
+ /* No return */
- /* Magic NAP mode enter sequence */
- std r0,0(r1)
- ptesync
- ld r0,0(r1)
-1: cmp cr0,r0,r0
- bne 1b
- PPC_NAP
- b .
+_GLOBAL(power7_idle)
+ /* Now check if user or arch enabled NAP mode */
+ LOAD_REG_ADDRBASE(r3,powersave_nap)
+ lwz r4,ADDROFF(powersave_nap)(r3)
+ cmpwi 0,r4,0
+ beqlr
+ /* fall through */
+
+_GLOBAL(power7_nap)
+ li r3,0
+ b power7_powersave_common
+ /* No return */
+
+_GLOBAL(power7_sleep)
+ li r3,1
+ b power7_powersave_common
+ /* No return */
+
+_GLOBAL(power7_wakeup_tb_loss)
+ ld r2,PACATOC(r13);
+ ld r1,PACAR1(r13)
+
+ /* Time base re-sync */
+ li r0,OPAL_RESYNC_TIMEBASE
+ LOAD_REG_ADDR(r11,opal);
+ ld r12,8(r11);
+ ld r2,0(r11);
+ mtctr r12
+ bctrl
+
+ /* TODO: Check r3 for failure */
+
+ REST_NVGPRS(r1)
+ REST_GPR(2, r1)
+ ld r3,_CCR(r1)
+ ld r4,_MSR(r1)
+ ld r5,_NIP(r1)
+ addi r1,r1,INT_FRAME_SIZE
+ mtcr r3
+ mfspr r3,SPRN_SRR1 /* Return SRR1 */
+ mtspr SPRN_SRR1,r4
+ mtspr SPRN_SRR0,r5
+ rfid
_GLOBAL(power7_wakeup_loss)
ld r1,PACAR1(r13)
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index d773dd440a45..88e3ec6e1d96 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -1088,6 +1088,14 @@ int iommu_take_ownership(struct iommu_table *tbl)
memset(tbl->it_map, 0xff, sz);
iommu_clear_tces_and_put_pages(tbl, tbl->it_offset, tbl->it_size);
+ /*
+ * Disable iommu bypass, otherwise the user can DMA to all of
+ * our physical memory via the bypass window instead of just
+ * the pages that has been explicitly mapped into the iommu
+ */
+ if (tbl->set_bypass)
+ tbl->set_bypass(tbl, false);
+
return 0;
}
EXPORT_SYMBOL_GPL(iommu_take_ownership);
@@ -1102,6 +1110,10 @@ void iommu_release_ownership(struct iommu_table *tbl)
/* Restore bit#0 set by iommu_init_table() */
if (tbl->it_offset == 0)
set_bit(0, tbl->it_map);
+
+ /* The kernel owns the device now, we can restore the iommu bypass */
+ if (tbl->set_bypass)
+ tbl->set_bypass(tbl, true);
}
EXPORT_SYMBOL_GPL(iommu_release_ownership);
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 9729b23bfb0a..ca1cd7459c4a 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -465,7 +465,6 @@ static inline void check_stack_overflow(void)
void __do_irq(struct pt_regs *regs)
{
- struct irq_desc *desc;
unsigned int irq;
irq_enter();
@@ -487,11 +486,8 @@ void __do_irq(struct pt_regs *regs)
/* And finally process it */
if (unlikely(irq == NO_IRQ))
__get_cpu_var(irq_stat).spurious_irqs++;
- else {
- desc = irq_to_desc(irq);
- if (likely(desc))
- desc->handle_irq(irq, desc);
- }
+ else
+ generic_handle_irq(irq);
trace_irq_exit(regs);
@@ -559,8 +555,13 @@ void exc_lvl_ctx_init(void)
#ifdef CONFIG_PPC64
cpu_nr = i;
#else
+#ifdef CONFIG_SMP
cpu_nr = get_hard_smp_processor_id(i);
+#else
+ cpu_nr = 0;
+#endif
#endif
+
memset((void *)critirq_ctx[cpu_nr], 0, THREAD_SIZE);
tp = critirq_ctx[cpu_nr];
tp->cpu = cpu_nr;
diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c
index 75d4f7340da8..015ae55c1868 100644
--- a/arch/powerpc/kernel/machine_kexec.c
+++ b/arch/powerpc/kernel/machine_kexec.c
@@ -196,7 +196,9 @@ int overlaps_crashkernel(unsigned long start, unsigned long size)
/* Values we need to export to the second kernel via the device tree. */
static phys_addr_t kernel_end;
+static phys_addr_t crashk_base;
static phys_addr_t crashk_size;
+static unsigned long long mem_limit;
static struct property kernel_end_prop = {
.name = "linux,kernel-end",
@@ -207,7 +209,7 @@ static struct property kernel_end_prop = {
static struct property crashk_base_prop = {
.name = "linux,crashkernel-base",
.length = sizeof(phys_addr_t),
- .value = &crashk_res.start,
+ .value = &crashk_base
};
static struct property crashk_size_prop = {
@@ -219,9 +221,11 @@ static struct property crashk_size_prop = {
static struct property memory_limit_prop = {
.name = "linux,memory-limit",
.length = sizeof(unsigned long long),
- .value = &memory_limit,
+ .value = &mem_limit,
};
+#define cpu_to_be_ulong __PASTE(cpu_to_be, BITS_PER_LONG)
+
static void __init export_crashk_values(struct device_node *node)
{
struct property *prop;
@@ -237,8 +241,9 @@ static void __init export_crashk_values(struct device_node *node)
of_remove_property(node, prop);
if (crashk_res.start != 0) {
+ crashk_base = cpu_to_be_ulong(crashk_res.start),
of_add_property(node, &crashk_base_prop);
- crashk_size = resource_size(&crashk_res);
+ crashk_size = cpu_to_be_ulong(resource_size(&crashk_res));
of_add_property(node, &crashk_size_prop);
}
@@ -246,6 +251,7 @@ static void __init export_crashk_values(struct device_node *node)
* memory_limit is required by the kexec-tools to limit the
* crash regions to the actual memory used.
*/
+ mem_limit = cpu_to_be_ulong(memory_limit);
of_update_property(node, &memory_limit_prop);
}
@@ -264,7 +270,7 @@ static int __init kexec_setup(void)
of_remove_property(node, prop);
/* information needed by userspace when using default_machine_kexec */
- kernel_end = __pa(_end);
+ kernel_end = cpu_to_be_ulong(__pa(_end));
of_add_property(node, &kernel_end_prop);
export_crashk_values(node);
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index be4e6d648f60..59d229a2a3e0 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -369,6 +369,7 @@ void default_machine_kexec(struct kimage *image)
/* Values we need to export to the second kernel via the device tree. */
static unsigned long htab_base;
+static unsigned long htab_size;
static struct property htab_base_prop = {
.name = "linux,htab-base",
@@ -379,7 +380,7 @@ static struct property htab_base_prop = {
static struct property htab_size_prop = {
.name = "linux,htab-size",
.length = sizeof(unsigned long),
- .value = &htab_size_bytes,
+ .value = &htab_size,
};
static int __init export_htab_values(void)
@@ -403,8 +404,9 @@ static int __init export_htab_values(void)
if (prop)
of_remove_property(node, prop);
- htab_base = __pa(htab_address);
+ htab_base = cpu_to_be64(__pa(htab_address));
of_add_property(node, &htab_base_prop);
+ htab_size = cpu_to_be64(htab_size_bytes);
of_add_property(node, &htab_size_prop);
of_node_put(node);
diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c
index cadef7e64e42..a7fd4cb78b78 100644
--- a/arch/powerpc/kernel/mce.c
+++ b/arch/powerpc/kernel/mce.c
@@ -70,7 +70,7 @@ static void mce_set_error_info(struct machine_check_event *mce,
*/
void save_mce_event(struct pt_regs *regs, long handled,
struct mce_error_info *mce_err,
- uint64_t addr)
+ uint64_t nip, uint64_t addr)
{
uint64_t srr1;
int index = __get_cpu_var(mce_nest_count)++;
@@ -86,7 +86,7 @@ void save_mce_event(struct pt_regs *regs, long handled,
/* Populate generic machine check info */
mce->version = MCE_V1;
- mce->srr0 = regs->nip;
+ mce->srr0 = nip;
mce->srr1 = regs->msr;
mce->gpr3 = regs->gpr[3];
mce->in_use = 1;
diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c
index 27c93f41166f..aa9aff3d6ad3 100644
--- a/arch/powerpc/kernel/mce_power.c
+++ b/arch/powerpc/kernel/mce_power.c
@@ -26,6 +26,7 @@
#include <linux/ptrace.h>
#include <asm/mmu.h>
#include <asm/mce.h>
+#include <asm/machdep.h>
/* flush SLBs and reload */
static void flush_and_reload_slb(void)
@@ -197,13 +198,32 @@ static void mce_get_derror_p7(struct mce_error_info *mce_err, uint64_t dsisr)
}
}
+static long mce_handle_ue_error(struct pt_regs *regs)
+{
+ long handled = 0;
+
+ /*
+ * On specific SCOM read via MMIO we may get a machine check
+ * exception with SRR0 pointing inside opal. If that is the
+ * case OPAL may have recovery address to re-read SCOM data in
+ * different way and hence we can recover from this MC.
+ */
+
+ if (ppc_md.mce_check_early_recovery) {
+ if (ppc_md.mce_check_early_recovery(regs))
+ handled = 1;
+ }
+ return handled;
+}
+
long __machine_check_early_realmode_p7(struct pt_regs *regs)
{
- uint64_t srr1, addr;
+ uint64_t srr1, nip, addr;
long handled = 1;
struct mce_error_info mce_error_info = { 0 };
srr1 = regs->msr;
+ nip = regs->nip;
/*
* Handle memory errors depending whether this was a load/store or
@@ -221,7 +241,11 @@ long __machine_check_early_realmode_p7(struct pt_regs *regs)
addr = regs->nip;
}
- save_mce_event(regs, handled, &mce_error_info, addr);
+ /* Handle UE error. */
+ if (mce_error_info.error_type == MCE_ERROR_TYPE_UE)
+ handled = mce_handle_ue_error(regs);
+
+ save_mce_event(regs, handled, &mce_error_info, nip, addr);
return handled;
}
@@ -263,11 +287,12 @@ static long mce_handle_derror_p8(uint64_t dsisr)
long __machine_check_early_realmode_p8(struct pt_regs *regs)
{
- uint64_t srr1, addr;
+ uint64_t srr1, nip, addr;
long handled = 1;
struct mce_error_info mce_error_info = { 0 };
srr1 = regs->msr;
+ nip = regs->nip;
if (P7_SRR1_MC_LOADSTORE(srr1)) {
handled = mce_handle_derror_p8(regs->dsisr);
@@ -279,6 +304,10 @@ long __machine_check_early_realmode_p8(struct pt_regs *regs)
addr = regs->nip;
}
- save_mce_event(regs, handled, &mce_error_info, addr);
+ /* Handle UE error. */
+ if (mce_error_info.error_type == MCE_ERROR_TYPE_UE)
+ handled = mce_handle_ue_error(regs);
+
+ save_mce_event(regs, handled, &mce_error_info, nip, addr);
return handled;
}
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 879f09620f83..7c6bb4b17b49 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -57,11 +57,14 @@ _GLOBAL(call_do_softirq)
mtlr r0
blr
+/*
+ * void call_do_irq(struct pt_regs *regs, struct thread_info *irqtp);
+ */
_GLOBAL(call_do_irq)
mflr r0
stw r0,4(r1)
lwz r10,THREAD+KSP_LIMIT(r2)
- addi r11,r3,THREAD_INFO_GAP
+ addi r11,r4,THREAD_INFO_GAP
stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4)
mr r1,r4
stw r10,8(r1)
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index a9e311f7a9dd..2a4779091a58 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -208,7 +208,6 @@ long sys_pciconfig_iobase(long which, unsigned long in_bus,
unsigned long in_devfn)
{
struct pci_controller* hose;
- struct list_head *ln;
struct pci_bus *bus = NULL;
struct device_node *hose_node;
@@ -230,8 +229,7 @@ long sys_pciconfig_iobase(long which, unsigned long in_bus,
* used on pre-domains setup. We return the first match
*/
- for (ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) {
- bus = pci_bus_b(ln);
+ list_for_each_entry(bus, &pci_root_buses, node) {
if (in_bus >= bus->number && in_bus <= bus->busn_res.end)
break;
bus = NULL;
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 8d4c247f1738..af064d28b365 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1048,6 +1048,15 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
flush_altivec_to_thread(src);
flush_vsx_to_thread(src);
flush_spe_to_thread(src);
+ /*
+ * Flush TM state out so we can copy it. __switch_to_tm() does this
+ * flush but it removes the checkpointed state from the current CPU and
+ * transitions the CPU out of TM mode. Hence we need to call
+ * tm_recheckpoint_new_task() (on the same task) to restore the
+ * checkpointed state back and the TM mode.
+ */
+ __switch_to_tm(src);
+ tm_recheckpoint_new_task(src);
*dst = *src;
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index f58c0d3aaeb4..dd72bebd708a 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -33,6 +33,7 @@
#include <linux/irq.h>
#include <linux/memblock.h>
#include <linux/of.h>
+#include <linux/of_fdt.h>
#include <asm/prom.h>
#include <asm/rtas.h>
@@ -588,6 +589,8 @@ static void __init early_reserve_mem_dt(void)
memblock_reserve(base, size);
}
}
+
+ early_init_fdt_scan_reserved_mem();
}
static void __init early_reserve_mem(void)
@@ -752,6 +755,11 @@ void __init early_init_devtree(void *params)
spinning_secondaries = boot_cpu_count - 1;
#endif
+#ifdef CONFIG_PPC_POWERNV
+ /* Scan and build the list of machine check recoverable ranges */
+ of_scan_flat_dt(early_init_dt_scan_recoverable_ranges, NULL);
+#endif
+
DBG(" <- early_init_devtree()\n");
}
diff --git a/arch/powerpc/kernel/reloc_64.S b/arch/powerpc/kernel/reloc_64.S
index b47a0e1ab001..d88736fbece6 100644
--- a/arch/powerpc/kernel/reloc_64.S
+++ b/arch/powerpc/kernel/reloc_64.S
@@ -69,8 +69,8 @@ _GLOBAL(relocate)
* R_PPC64_RELATIVE ones.
*/
mtctr r8
-5: lwz r0,12(9) /* ELF64_R_TYPE(reloc->r_info) */
- cmpwi r0,R_PPC64_RELATIVE
+5: ld r0,8(9) /* ELF64_R_TYPE(reloc->r_info) */
+ cmpdi r0,R_PPC64_RELATIVE
bne 6f
ld r6,0(r9) /* reloc->r_offset */
ld r0,16(r9) /* reloc->r_addend */
@@ -81,6 +81,7 @@ _GLOBAL(relocate)
6: blr
+.balign 8
p_dyn: .llong __dynamic_start - 0b
p_rela: .llong __rela_dyn_start - 0b
p_st: .llong _stext - 0b
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 4cf674d7d5ae..f386296ff378 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -1013,12 +1013,13 @@ struct pseries_errorlog *get_pseries_errorlog(struct rtas_error_log *log,
return NULL;
}
+/* We assume to be passed big endian arguments */
asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
{
struct rtas_args args;
unsigned long flags;
char *buff_copy, *errbuf = NULL;
- int nargs;
+ int nargs, nret, token;
int rc;
if (!capable(CAP_SYS_ADMIN))
@@ -1027,10 +1028,13 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
if (copy_from_user(&args, uargs, 3 * sizeof(u32)) != 0)
return -EFAULT;
- nargs = args.nargs;
+ nargs = be32_to_cpu(args.nargs);
+ nret = be32_to_cpu(args.nret);
+ token = be32_to_cpu(args.token);
+
if (nargs > ARRAY_SIZE(args.args)
- || args.nret > ARRAY_SIZE(args.args)
- || nargs + args.nret > ARRAY_SIZE(args.args))
+ || nret > ARRAY_SIZE(args.args)
+ || nargs + nret > ARRAY_SIZE(args.args))
return -EINVAL;
/* Copy in args. */
@@ -1038,14 +1042,14 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
nargs * sizeof(rtas_arg_t)) != 0)
return -EFAULT;
- if (args.token == RTAS_UNKNOWN_SERVICE)
+ if (token == RTAS_UNKNOWN_SERVICE)
return -EINVAL;
args.rets = &args.args[nargs];
- memset(args.rets, 0, args.nret * sizeof(rtas_arg_t));
+ memset(args.rets, 0, nret * sizeof(rtas_arg_t));
/* Need to handle ibm,suspend_me call specially */
- if (args.token == ibm_suspend_me_token) {
+ if (token == ibm_suspend_me_token) {
rc = rtas_ibm_suspend_me(&args);
if (rc)
return rc;
@@ -1062,7 +1066,7 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
/* A -1 return code indicates that the last command couldn't
be completed due to a hardware error. */
- if (args.rets[0] == -1)
+ if (be32_to_cpu(args.rets[0]) == -1)
errbuf = __fetch_rtas_last_error(buff_copy);
unlock_rtas(flags);
@@ -1077,7 +1081,7 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
/* Copy out args. */
if (copy_to_user(uargs->args + nargs,
args.args + nargs,
- args.nret * sizeof(rtas_arg_t)) != 0)
+ nret * sizeof(rtas_arg_t)) != 0)
return -EFAULT;
return 0;
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 2b0da27eaee4..04cc4fcca78b 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -247,7 +247,12 @@ static void __init exc_lvl_early_init(void)
/* interrupt stacks must be in lowmem, we get that for free on ppc32
* as the memblock is limited to lowmem by MEMBLOCK_REAL_LIMIT */
for_each_possible_cpu(i) {
+#ifdef CONFIG_SMP
hw_cpu = get_hard_smp_processor_id(i);
+#else
+ hw_cpu = 0;
+#endif
+
critirq_ctx[hw_cpu] = (struct thread_info *)
__va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
#ifdef CONFIG_BOOKE
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index f5f11a7d30e5..4933909cc5c0 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -102,6 +102,8 @@ static void setup_tlb_core_data(void)
{
int cpu;
+ BUILD_BUG_ON(offsetof(struct tlb_core_data, lock) != 0);
+
for_each_possible_cpu(cpu) {
int first = cpu_first_thread_sibling(cpu);
@@ -552,14 +554,20 @@ static void __init irqstack_early_init(void)
static void __init exc_lvl_early_init(void)
{
unsigned int i;
+ unsigned long sp;
for_each_possible_cpu(i) {
- critirq_ctx[i] = (struct thread_info *)
- __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
- dbgirq_ctx[i] = (struct thread_info *)
- __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
- mcheckirq_ctx[i] = (struct thread_info *)
- __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
+ sp = memblock_alloc(THREAD_SIZE, THREAD_SIZE);
+ critirq_ctx[i] = (struct thread_info *)__va(sp);
+ paca[i].crit_kstack = __va(sp + THREAD_SIZE);
+
+ sp = memblock_alloc(THREAD_SIZE, THREAD_SIZE);
+ dbgirq_ctx[i] = (struct thread_info *)__va(sp);
+ paca[i].dbg_kstack = __va(sp + THREAD_SIZE);
+
+ sp = memblock_alloc(THREAD_SIZE, THREAD_SIZE);
+ mcheckirq_ctx[i] = (struct thread_info *)__va(sp);
+ paca[i].mc_kstack = __va(sp + THREAD_SIZE);
}
if (cpu_has_feature(CPU_FTR_DEBUG_LVL_EXC))
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index e35bf773df7a..8d253c29649b 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -65,8 +65,8 @@ struct rt_sigframe {
struct siginfo __user *pinfo;
void __user *puc;
struct siginfo info;
- /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
- char abigap[288];
+ /* New 64 bit little-endian ABI allows redzone of 512 bytes below sp */
+ char abigap[USER_REDZONE_SIZE];
} __attribute__ ((aligned (16)));
static const char fmt32[] = KERN_INFO \
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index ac2621af3154..e2a4232c5871 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -35,6 +35,7 @@
#include <asm/ptrace.h>
#include <linux/atomic.h>
#include <asm/irq.h>
+#include <asm/hw_irq.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/prom.h>
@@ -145,9 +146,9 @@ static irqreturn_t reschedule_action(int irq, void *data)
return IRQ_HANDLED;
}
-static irqreturn_t call_function_single_action(int irq, void *data)
+static irqreturn_t tick_broadcast_ipi_action(int irq, void *data)
{
- generic_smp_call_function_single_interrupt();
+ tick_broadcast_ipi_handler();
return IRQ_HANDLED;
}
@@ -168,14 +169,14 @@ static irqreturn_t debug_ipi_action(int irq, void *data)
static irq_handler_t smp_ipi_action[] = {
[PPC_MSG_CALL_FUNCTION] = call_function_action,
[PPC_MSG_RESCHEDULE] = reschedule_action,
- [PPC_MSG_CALL_FUNC_SINGLE] = call_function_single_action,
+ [PPC_MSG_TICK_BROADCAST] = tick_broadcast_ipi_action,
[PPC_MSG_DEBUGGER_BREAK] = debug_ipi_action,
};
const char *smp_ipi_name[] = {
[PPC_MSG_CALL_FUNCTION] = "ipi call function",
[PPC_MSG_RESCHEDULE] = "ipi reschedule",
- [PPC_MSG_CALL_FUNC_SINGLE] = "ipi call function single",
+ [PPC_MSG_TICK_BROADCAST] = "ipi tick-broadcast",
[PPC_MSG_DEBUGGER_BREAK] = "ipi debugger",
};
@@ -251,8 +252,8 @@ irqreturn_t smp_ipi_demux(void)
generic_smp_call_function_interrupt();
if (all & IPI_MESSAGE(PPC_MSG_RESCHEDULE))
scheduler_ipi();
- if (all & IPI_MESSAGE(PPC_MSG_CALL_FUNC_SINGLE))
- generic_smp_call_function_single_interrupt();
+ if (all & IPI_MESSAGE(PPC_MSG_TICK_BROADCAST))
+ tick_broadcast_ipi_handler();
if (all & IPI_MESSAGE(PPC_MSG_DEBUGGER_BREAK))
debug_ipi_action(0, NULL);
} while (info->messages);
@@ -280,7 +281,7 @@ EXPORT_SYMBOL_GPL(smp_send_reschedule);
void arch_send_call_function_single_ipi(int cpu)
{
- do_message_pass(cpu, PPC_MSG_CALL_FUNC_SINGLE);
+ do_message_pass(cpu, PPC_MSG_CALL_FUNCTION);
}
void arch_send_call_function_ipi_mask(const struct cpumask *mask)
@@ -291,6 +292,16 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask)
do_message_pass(cpu, PPC_MSG_CALL_FUNCTION);
}
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+void tick_broadcast(const struct cpumask *mask)
+{
+ unsigned int cpu;
+
+ for_each_cpu(cpu, mask)
+ do_message_pass(cpu, PPC_MSG_TICK_BROADCAST);
+}
+#endif
+
#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
void smp_send_debugger_break(void)
{
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index b3dab20acf34..122a580f7322 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -42,6 +42,7 @@
#include <linux/timex.h>
#include <linux/kernel_stat.h>
#include <linux/time.h>
+#include <linux/clockchips.h>
#include <linux/init.h>
#include <linux/profile.h>
#include <linux/cpu.h>
@@ -106,7 +107,7 @@ struct clock_event_device decrementer_clockevent = {
.irq = 0,
.set_next_event = decrementer_set_next_event,
.set_mode = decrementer_set_mode,
- .features = CLOCK_EVT_FEAT_ONESHOT,
+ .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP,
};
EXPORT_SYMBOL(decrementer_clockevent);
@@ -478,6 +479,47 @@ void arch_irq_work_raise(void)
#endif /* CONFIG_IRQ_WORK */
+void __timer_interrupt(void)
+{
+ struct pt_regs *regs = get_irq_regs();
+ u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
+ struct clock_event_device *evt = &__get_cpu_var(decrementers);
+ u64 now;
+
+ trace_timer_interrupt_entry(regs);
+
+ if (test_irq_work_pending()) {
+ clear_irq_work_pending();
+ irq_work_run();
+ }
+
+ now = get_tb_or_rtc();
+ if (now >= *next_tb) {
+ *next_tb = ~(u64)0;
+ if (evt->event_handler)
+ evt->event_handler(evt);
+ __get_cpu_var(irq_stat).timer_irqs_event++;
+ } else {
+ now = *next_tb - now;
+ if (now <= DECREMENTER_MAX)
+ set_dec((int)now);
+ /* We may have raced with new irq work */
+ if (test_irq_work_pending())
+ set_dec(1);
+ __get_cpu_var(irq_stat).timer_irqs_others++;
+ }
+
+#ifdef CONFIG_PPC64
+ /* collect purr register values often, for accurate calculations */
+ if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
+ struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array);
+ cu->current_tb = mfspr(SPRN_PURR);
+ }
+#endif
+
+ trace_timer_interrupt_exit(regs);
+}
+
/*
* timer_interrupt - gets called when the decrementer overflows,
* with interrupts disabled.
@@ -486,8 +528,6 @@ void timer_interrupt(struct pt_regs * regs)
{
struct pt_regs *old_regs;
u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
- struct clock_event_device *evt = &__get_cpu_var(decrementers);
- u64 now;
/* Ensure a positive value is written to the decrementer, or else
* some CPUs will continue to take decrementer exceptions.
@@ -519,39 +559,7 @@ void timer_interrupt(struct pt_regs * regs)
old_regs = set_irq_regs(regs);
irq_enter();
- trace_timer_interrupt_entry(regs);
-
- if (test_irq_work_pending()) {
- clear_irq_work_pending();
- irq_work_run();
- }
-
- now = get_tb_or_rtc();
- if (now >= *next_tb) {
- *next_tb = ~(u64)0;
- if (evt->event_handler)
- evt->event_handler(evt);
- __get_cpu_var(irq_stat).timer_irqs_event++;
- } else {
- now = *next_tb - now;
- if (now <= DECREMENTER_MAX)
- set_dec((int)now);
- /* We may have raced with new irq work */
- if (test_irq_work_pending())
- set_dec(1);
- __get_cpu_var(irq_stat).timer_irqs_others++;
- }
-
-#ifdef CONFIG_PPC64
- /* collect purr register values often, for accurate calculations */
- if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
- struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array);
- cu->current_tb = mfspr(SPRN_PURR);
- }
-#endif
-
- trace_timer_interrupt_exit(regs);
-
+ __timer_interrupt();
irq_exit();
set_irq_regs(old_regs);
}
@@ -825,6 +833,15 @@ static void decrementer_set_mode(enum clock_event_mode mode,
decrementer_set_next_event(DECREMENTER_MAX, dev);
}
+/* Interrupt handler for the timer broadcast IPI */
+void tick_broadcast_ipi_handler(void)
+{
+ u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
+
+ *next_tb = get_tb_or_rtc();
+ __timer_interrupt();
+}
+
static void register_decrementer_clockevent(int cpu)
{
struct clock_event_device *dec = &per_cpu(decrementers, cpu);
@@ -928,6 +945,7 @@ void __init time_init(void)
clocksource_init();
init_decrementer_clockevent();
+ tick_setup_hrtimer_broadcast();
}
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 33cd7a0b8e73..df86f0ce2d36 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -1379,8 +1379,9 @@ void facility_unavailable_exception(struct pt_regs *regs)
if (!arch_irq_disabled_regs(regs))
local_irq_enable();
- pr_err("%sFacility '%s' unavailable, exception at 0x%lx, MSR=%lx\n",
- hv ? "Hypervisor " : "", facility, regs->nip, regs->msr);
+ pr_err_ratelimited(
+ "%sFacility '%s' unavailable, exception at 0x%lx, MSR=%lx\n",
+ hv ? "Hypervisor " : "", facility, regs->nip, regs->msr);
if (user_mode(regs)) {
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index 094e45c16a17..ce74c335a6a4 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -715,8 +715,8 @@ int vdso_getcpu_init(void)
unsigned long cpu, node, val;
/*
- * SPRG3 contains the CPU in the bottom 16 bits and the NUMA node in
- * the next 16 bits. The VDSO uses this to implement getcpu().
+ * SPRG_VDSO contains the CPU in the bottom 16 bits and the NUMA node
+ * in the next 16 bits. The VDSO uses this to implement getcpu().
*/
cpu = get_cpu();
WARN_ON_ONCE(cpu > 0xffff);
@@ -725,8 +725,8 @@ int vdso_getcpu_init(void)
WARN_ON_ONCE(node > 0xffff);
val = (cpu & 0xfff) | ((node & 0xffff) << 16);
- mtspr(SPRN_SPRG3, val);
- get_paca()->sprg3 = val;
+ mtspr(SPRN_SPRG_VDSO_WRITE, val);
+ get_paca()->sprg_vdso = val;
put_cpu();
diff --git a/arch/powerpc/kernel/vdso32/getcpu.S b/arch/powerpc/kernel/vdso32/getcpu.S
index 47afd08c90f7..23eb9a9441bd 100644
--- a/arch/powerpc/kernel/vdso32/getcpu.S
+++ b/arch/powerpc/kernel/vdso32/getcpu.S
@@ -29,7 +29,7 @@
*/
V_FUNCTION_BEGIN(__kernel_getcpu)
.cfi_startproc
- mfspr r5,SPRN_USPRG3
+ mfspr r5,SPRN_SPRG_VDSO_READ
cmpdi cr0,r3,0
cmpdi cr1,r4,0
clrlwi r6,r5,16
diff --git a/arch/powerpc/kernel/vdso32/vdso32_wrapper.S b/arch/powerpc/kernel/vdso32/vdso32_wrapper.S
index 79683d0393f5..6ac107ac402a 100644
--- a/arch/powerpc/kernel/vdso32/vdso32_wrapper.S
+++ b/arch/powerpc/kernel/vdso32/vdso32_wrapper.S
@@ -6,7 +6,7 @@
.globl vdso32_start, vdso32_end
.balign PAGE_SIZE
vdso32_start:
- .incbin "arch/powerpc/kernel/vdso32/vdso32.so"
+ .incbin "arch/powerpc/kernel/vdso32/vdso32.so.dbg"
.balign PAGE_SIZE
vdso32_end:
diff --git a/arch/powerpc/kernel/vdso64/getcpu.S b/arch/powerpc/kernel/vdso64/getcpu.S
index 47afd08c90f7..23eb9a9441bd 100644
--- a/arch/powerpc/kernel/vdso64/getcpu.S
+++ b/arch/powerpc/kernel/vdso64/getcpu.S
@@ -29,7 +29,7 @@
*/
V_FUNCTION_BEGIN(__kernel_getcpu)
.cfi_startproc
- mfspr r5,SPRN_USPRG3
+ mfspr r5,SPRN_SPRG_VDSO_READ
cmpdi cr0,r3,0
cmpdi cr1,r4,0
clrlwi r6,r5,16
diff --git a/arch/powerpc/kernel/vdso64/vdso64_wrapper.S b/arch/powerpc/kernel/vdso64/vdso64_wrapper.S
index 8df9e2463007..df60fca6a13d 100644
--- a/arch/powerpc/kernel/vdso64/vdso64_wrapper.S
+++ b/arch/powerpc/kernel/vdso64/vdso64_wrapper.S
@@ -6,7 +6,7 @@
.globl vdso64_start, vdso64_end
.balign PAGE_SIZE
vdso64_start:
- .incbin "arch/powerpc/kernel/vdso64/vdso64.so"
+ .incbin "arch/powerpc/kernel/vdso64/vdso64.so.dbg"
.balign PAGE_SIZE
vdso64_end:
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index 826d8bd9e522..904c66128fae 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -1432,7 +1432,8 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node)
/* needed to ensure proper operation of coherent allocations
* later, in case driver doesn't set it explicitly */
- dma_coerce_mask_and_coherent(&viodev->dev, DMA_BIT_MASK(64));
+ viodev->dev.coherent_dma_mask = DMA_BIT_MASK(64);
+ viodev->dev.dma_mask = &viodev->dev.coherent_dma_mask;
}
/* register with generic device framework */
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index 303ece75b8e4..fb25ebc0af0c 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -262,7 +262,14 @@ int kvmppc_mmu_hv_init(void)
static void kvmppc_mmu_book3s_64_hv_reset_msr(struct kvm_vcpu *vcpu)
{
- kvmppc_set_msr(vcpu, vcpu->arch.intr_msr);
+ unsigned long msr = vcpu->arch.intr_msr;
+
+ /* If transactional, change to suspend mode on IRQ delivery */
+ if (MSR_TM_TRANSACTIONAL(vcpu->arch.shregs.msr))
+ msr |= MSR_TS_S;
+ else
+ msr |= vcpu->arch.shregs.msr & MSR_TS_MASK;
+ kvmppc_set_msr(vcpu, msr);
}
/*
diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c
index 2c25f5412bdb..89e96b3e0039 100644
--- a/arch/powerpc/kvm/book3s_64_vio_hv.c
+++ b/arch/powerpc/kvm/book3s_64_vio_hv.c
@@ -75,3 +75,31 @@ long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
return H_TOO_HARD;
}
EXPORT_SYMBOL_GPL(kvmppc_h_put_tce);
+
+long kvmppc_h_get_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
+ unsigned long ioba)
+{
+ struct kvm *kvm = vcpu->kvm;
+ struct kvmppc_spapr_tce_table *stt;
+
+ list_for_each_entry(stt, &kvm->arch.spapr_tce_tables, list) {
+ if (stt->liobn == liobn) {
+ unsigned long idx = ioba >> SPAPR_TCE_SHIFT;
+ struct page *page;
+ u64 *tbl;
+
+ if (ioba >= stt->window_size)
+ return H_PARAMETER;
+
+ page = stt->pages[idx / TCES_PER_PAGE];
+ tbl = (u64 *)page_address(page);
+
+ vcpu->arch.gpr[4] = tbl[idx % TCES_PER_PAGE];
+ return H_SUCCESS;
+ }
+ }
+
+ /* Didn't find the liobn, punt it to userspace */
+ return H_TOO_HARD;
+}
+EXPORT_SYMBOL_GPL(kvmppc_h_get_tce);
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 17fc9496b6ac..8227dba5af0f 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -86,7 +86,7 @@ static void kvmppc_fast_vcpu_kick_hv(struct kvm_vcpu *vcpu)
/* CPU points to the first thread of the core */
if (cpu != me && cpu >= 0 && cpu < nr_cpu_ids) {
-#ifdef CONFIG_KVM_XICS
+#ifdef CONFIG_PPC_ICP_NATIVE
int real_cpu = cpu + vcpu->arch.ptid;
if (paca[real_cpu].kvm_hstate.xics_phys)
xics_wake_cpu(real_cpu);
@@ -879,17 +879,6 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
case KVM_REG_PPC_IAMR:
*val = get_reg_val(id, vcpu->arch.iamr);
break;
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- case KVM_REG_PPC_TFHAR:
- *val = get_reg_val(id, vcpu->arch.tfhar);
- break;
- case KVM_REG_PPC_TFIAR:
- *val = get_reg_val(id, vcpu->arch.tfiar);
- break;
- case KVM_REG_PPC_TEXASR:
- *val = get_reg_val(id, vcpu->arch.texasr);
- break;
-#endif
case KVM_REG_PPC_FSCR:
*val = get_reg_val(id, vcpu->arch.fscr);
break;
@@ -970,6 +959,69 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
case KVM_REG_PPC_PPR:
*val = get_reg_val(id, vcpu->arch.ppr);
break;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ case KVM_REG_PPC_TFHAR:
+ *val = get_reg_val(id, vcpu->arch.tfhar);
+ break;
+ case KVM_REG_PPC_TFIAR:
+ *val = get_reg_val(id, vcpu->arch.tfiar);
+ break;
+ case KVM_REG_PPC_TEXASR:
+ *val = get_reg_val(id, vcpu->arch.texasr);
+ break;
+ case KVM_REG_PPC_TM_GPR0 ... KVM_REG_PPC_TM_GPR31:
+ i = id - KVM_REG_PPC_TM_GPR0;
+ *val = get_reg_val(id, vcpu->arch.gpr_tm[i]);
+ break;
+ case KVM_REG_PPC_TM_VSR0 ... KVM_REG_PPC_TM_VSR63:
+ {
+ int j;
+ i = id - KVM_REG_PPC_TM_VSR0;
+ if (i < 32)
+ for (j = 0; j < TS_FPRWIDTH; j++)
+ val->vsxval[j] = vcpu->arch.fp_tm.fpr[i][j];
+ else {
+ if (cpu_has_feature(CPU_FTR_ALTIVEC))
+ val->vval = vcpu->arch.vr_tm.vr[i-32];
+ else
+ r = -ENXIO;
+ }
+ break;
+ }
+ case KVM_REG_PPC_TM_CR:
+ *val = get_reg_val(id, vcpu->arch.cr_tm);
+ break;
+ case KVM_REG_PPC_TM_LR:
+ *val = get_reg_val(id, vcpu->arch.lr_tm);
+ break;
+ case KVM_REG_PPC_TM_CTR:
+ *val = get_reg_val(id, vcpu->arch.ctr_tm);
+ break;
+ case KVM_REG_PPC_TM_FPSCR:
+ *val = get_reg_val(id, vcpu->arch.fp_tm.fpscr);
+ break;
+ case KVM_REG_PPC_TM_AMR:
+ *val = get_reg_val(id, vcpu->arch.amr_tm);
+ break;
+ case KVM_REG_PPC_TM_PPR:
+ *val = get_reg_val(id, vcpu->arch.ppr_tm);
+ break;
+ case KVM_REG_PPC_TM_VRSAVE:
+ *val = get_reg_val(id, vcpu->arch.vrsave_tm);
+ break;
+ case KVM_REG_PPC_TM_VSCR:
+ if (cpu_has_feature(CPU_FTR_ALTIVEC))
+ *val = get_reg_val(id, vcpu->arch.vr_tm.vscr.u[3]);
+ else
+ r = -ENXIO;
+ break;
+ case KVM_REG_PPC_TM_DSCR:
+ *val = get_reg_val(id, vcpu->arch.dscr_tm);
+ break;
+ case KVM_REG_PPC_TM_TAR:
+ *val = get_reg_val(id, vcpu->arch.tar_tm);
+ break;
+#endif
case KVM_REG_PPC_ARCH_COMPAT:
*val = get_reg_val(id, vcpu->arch.vcore->arch_compat);
break;
@@ -1039,17 +1091,6 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
case KVM_REG_PPC_IAMR:
vcpu->arch.iamr = set_reg_val(id, *val);
break;
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- case KVM_REG_PPC_TFHAR:
- vcpu->arch.tfhar = set_reg_val(id, *val);
- break;
- case KVM_REG_PPC_TFIAR:
- vcpu->arch.tfiar = set_reg_val(id, *val);
- break;
- case KVM_REG_PPC_TEXASR:
- vcpu->arch.texasr = set_reg_val(id, *val);
- break;
-#endif
case KVM_REG_PPC_FSCR:
vcpu->arch.fscr = set_reg_val(id, *val);
break;
@@ -1144,6 +1185,68 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
case KVM_REG_PPC_PPR:
vcpu->arch.ppr = set_reg_val(id, *val);
break;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ case KVM_REG_PPC_TFHAR:
+ vcpu->arch.tfhar = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TFIAR:
+ vcpu->arch.tfiar = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TEXASR:
+ vcpu->arch.texasr = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TM_GPR0 ... KVM_REG_PPC_TM_GPR31:
+ i = id - KVM_REG_PPC_TM_GPR0;
+ vcpu->arch.gpr_tm[i] = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TM_VSR0 ... KVM_REG_PPC_TM_VSR63:
+ {
+ int j;
+ i = id - KVM_REG_PPC_TM_VSR0;
+ if (i < 32)
+ for (j = 0; j < TS_FPRWIDTH; j++)
+ vcpu->arch.fp_tm.fpr[i][j] = val->vsxval[j];
+ else
+ if (cpu_has_feature(CPU_FTR_ALTIVEC))
+ vcpu->arch.vr_tm.vr[i-32] = val->vval;
+ else
+ r = -ENXIO;
+ break;
+ }
+ case KVM_REG_PPC_TM_CR:
+ vcpu->arch.cr_tm = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TM_LR:
+ vcpu->arch.lr_tm = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TM_CTR:
+ vcpu->arch.ctr_tm = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TM_FPSCR:
+ vcpu->arch.fp_tm.fpscr = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TM_AMR:
+ vcpu->arch.amr_tm = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TM_PPR:
+ vcpu->arch.ppr_tm = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TM_VRSAVE:
+ vcpu->arch.vrsave_tm = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TM_VSCR:
+ if (cpu_has_feature(CPU_FTR_ALTIVEC))
+ vcpu->arch.vr.vscr.u[3] = set_reg_val(id, *val);
+ else
+ r = - ENXIO;
+ break;
+ case KVM_REG_PPC_TM_DSCR:
+ vcpu->arch.dscr_tm = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TM_TAR:
+ vcpu->arch.tar_tm = set_reg_val(id, *val);
+ break;
+#endif
case KVM_REG_PPC_ARCH_COMPAT:
r = kvmppc_set_arch_compat(vcpu, set_reg_val(id, *val));
break;
@@ -1360,9 +1463,7 @@ static void kvmppc_start_thread(struct kvm_vcpu *vcpu)
smp_wmb();
#if defined(CONFIG_PPC_ICP_NATIVE) && defined(CONFIG_SMP)
if (cpu != smp_processor_id()) {
-#ifdef CONFIG_KVM_XICS
xics_wake_cpu(cpu);
-#endif
if (vcpu->arch.ptid)
++vc->n_woken;
}
@@ -1530,7 +1631,7 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
vcpu->arch.trap = 0;
if (vcpu->arch.ceded) {
- if (ret != RESUME_GUEST)
+ if (!is_kvmppc_resume_guest(ret))
kvmppc_end_cede(vcpu);
else
kvmppc_set_timer(vcpu);
@@ -1541,7 +1642,7 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
vc->vcore_state = VCORE_INACTIVE;
list_for_each_entry_safe(vcpu, vnext, &vc->runnable_threads,
arch.run_list) {
- if (vcpu->arch.ret != RESUME_GUEST) {
+ if (!is_kvmppc_resume_guest(vcpu->arch.ret)) {
kvmppc_remove_runnable(vc, vcpu);
wake_up(&vcpu->arch.cpu_run);
}
@@ -1731,7 +1832,7 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu)
vcpu->arch.fault_dar, vcpu->arch.fault_dsisr);
srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx);
}
- } while (r == RESUME_GUEST);
+ } while (is_kvmppc_resume_guest(r));
out:
vcpu->arch.state = KVMPPC_VCPU_NOTREADY;
@@ -2366,7 +2467,7 @@ static int kvmppc_book3s_init_hv(void)
*/
r = kvmppc_core_check_processor_compat_hv();
if (r < 0)
- return r;
+ return -ENODEV;
kvm_ops_hv.owner = THIS_MODULE;
kvmppc_hv_ops = &kvm_ops_hv;
diff --git a/arch/powerpc/kvm/book3s_hv_interrupts.S b/arch/powerpc/kvm/book3s_hv_interrupts.S
index e873796b1a29..e18e3cfc32de 100644
--- a/arch/powerpc/kvm/book3s_hv_interrupts.S
+++ b/arch/powerpc/kvm/book3s_hv_interrupts.S
@@ -71,6 +71,14 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
mtmsrd r10,1
/* Save host PMU registers */
+BEGIN_FTR_SECTION
+ /* Work around P8 PMAE bug */
+ li r3, -1
+ clrrdi r3, r3, 10
+ mfspr r8, SPRN_MMCR2
+ mtspr SPRN_MMCR2, r3 /* freeze all counters using MMCR2 */
+ isync
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
li r3, 1
sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */
mfspr r7, SPRN_MMCR0 /* save MMCR0 */
@@ -87,9 +95,18 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
cmpwi r5, 0
beq 31f /* skip if not */
mfspr r5, SPRN_MMCR1
+ mfspr r9, SPRN_SIAR
+ mfspr r10, SPRN_SDAR
std r7, HSTATE_MMCR(r13)
std r5, HSTATE_MMCR + 8(r13)
std r6, HSTATE_MMCR + 16(r13)
+ std r9, HSTATE_MMCR + 24(r13)
+ std r10, HSTATE_MMCR + 32(r13)
+BEGIN_FTR_SECTION
+ mfspr r9, SPRN_SIER
+ std r8, HSTATE_MMCR + 40(r13)
+ std r9, HSTATE_MMCR + 48(r13)
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
mfspr r3, SPRN_PMC1
mfspr r5, SPRN_PMC2
mfspr r6, SPRN_PMC3
@@ -110,6 +127,11 @@ BEGIN_FTR_SECTION
stw r10, HSTATE_PMC + 24(r13)
stw r11, HSTATE_PMC + 28(r13)
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
+BEGIN_FTR_SECTION
+ mfspr r9, SPRN_SIER
+ std r8, HSTATE_MMCR + 40(r13)
+ std r9, HSTATE_MMCR + 48(r13)
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
31:
/*
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
index 37fb3caa4c80..1d6c56ad5b60 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -111,7 +111,7 @@ static void remove_revmap_chain(struct kvm *kvm, long pte_index,
rcbits = hpte_r & (HPTE_R_R | HPTE_R_C);
ptel = rev->guest_rpte |= rcbits;
gfn = hpte_rpn(ptel, hpte_page_size(hpte_v, ptel));
- memslot = __gfn_to_memslot(kvm_memslots(kvm), gfn);
+ memslot = __gfn_to_memslot(kvm_memslots_raw(kvm), gfn);
if (!memslot)
return;
@@ -192,7 +192,7 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
/* Find the memslot (if any) for this address */
gpa = (ptel & HPTE_R_RPN) & ~(psize - 1);
gfn = gpa >> PAGE_SHIFT;
- memslot = __gfn_to_memslot(kvm_memslots(kvm), gfn);
+ memslot = __gfn_to_memslot(kvm_memslots_raw(kvm), gfn);
pa = 0;
is_io = ~0ul;
rmap = NULL;
@@ -670,7 +670,7 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
psize = hpte_page_size(v, r);
gfn = ((r & HPTE_R_RPN) & ~(psize - 1)) >> PAGE_SHIFT;
- memslot = __gfn_to_memslot(kvm_memslots(kvm), gfn);
+ memslot = __gfn_to_memslot(kvm_memslots_raw(kvm), gfn);
if (memslot) {
hva = __gfn_to_hva_memslot(memslot, gfn);
pte = lookup_linux_pte_and_update(pgdir, hva,
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index e66d4ec04d95..ffbb871c2bd8 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -28,6 +28,9 @@
#include <asm/exception-64s.h>
#include <asm/kvm_book3s_asm.h>
#include <asm/mmu-hash64.h>
+#include <asm/tm.h>
+
+#define VCPU_GPRS_TM(reg) (((reg) * ULONG_SIZE) + VCPU_GPR_TM)
#ifdef __LITTLE_ENDIAN__
#error Need to fix lppaca and SLB shadow accesses in little endian mode
@@ -75,8 +78,8 @@ BEGIN_FTR_SECTION
END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
/* Restore SPRG3 */
- ld r3,PACA_SPRG3(r13)
- mtspr SPRN_SPRG3,r3
+ ld r3,PACA_SPRG_VDSO(r13)
+ mtspr SPRN_SPRG_VDSO_WRITE,r3
/* Reload the host's PMU registers */
ld r3, PACALPPACAPTR(r13) /* is the host using the PMU? */
@@ -106,8 +109,18 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
ld r3, HSTATE_MMCR(r13)
ld r4, HSTATE_MMCR + 8(r13)
ld r5, HSTATE_MMCR + 16(r13)
+ ld r6, HSTATE_MMCR + 24(r13)
+ ld r7, HSTATE_MMCR + 32(r13)
mtspr SPRN_MMCR1, r4
mtspr SPRN_MMCRA, r5
+ mtspr SPRN_SIAR, r6
+ mtspr SPRN_SDAR, r7
+BEGIN_FTR_SECTION
+ ld r8, HSTATE_MMCR + 40(r13)
+ ld r9, HSTATE_MMCR + 48(r13)
+ mtspr SPRN_MMCR2, r8
+ mtspr SPRN_SIER, r9
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
mtspr SPRN_MMCR0, r3
isync
23:
@@ -597,6 +610,116 @@ BEGIN_FTR_SECTION
END_FTR_SECTION_NESTED(CPU_FTR_ARCH_206, CPU_FTR_ARCH_206, 89)
END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+BEGIN_FTR_SECTION
+ b skip_tm
+END_FTR_SECTION_IFCLR(CPU_FTR_TM)
+
+ /* Turn on TM/FP/VSX/VMX so we can restore them. */
+ mfmsr r5
+ li r6, MSR_TM >> 32
+ sldi r6, r6, 32
+ or r5, r5, r6
+ ori r5, r5, MSR_FP
+ oris r5, r5, (MSR_VEC | MSR_VSX)@h
+ mtmsrd r5
+
+ /*
+ * The user may change these outside of a transaction, so they must
+ * always be context switched.
+ */
+ ld r5, VCPU_TFHAR(r4)
+ ld r6, VCPU_TFIAR(r4)
+ ld r7, VCPU_TEXASR(r4)
+ mtspr SPRN_TFHAR, r5
+ mtspr SPRN_TFIAR, r6
+ mtspr SPRN_TEXASR, r7
+
+ ld r5, VCPU_MSR(r4)
+ rldicl. r5, r5, 64 - MSR_TS_S_LG, 62
+ beq skip_tm /* TM not active in guest */
+
+ /* Make sure the failure summary is set, otherwise we'll program check
+ * when we trechkpt. It's possible that this might have been not set
+ * on a kvmppc_set_one_reg() call but we shouldn't let this crash the
+ * host.
+ */
+ oris r7, r7, (TEXASR_FS)@h
+ mtspr SPRN_TEXASR, r7
+
+ /*
+ * We need to load up the checkpointed state for the guest.
+ * We need to do this early as it will blow away any GPRs, VSRs and
+ * some SPRs.
+ */
+
+ mr r31, r4
+ addi r3, r31, VCPU_FPRS_TM
+ bl .load_fp_state
+ addi r3, r31, VCPU_VRS_TM
+ bl .load_vr_state
+ mr r4, r31
+ lwz r7, VCPU_VRSAVE_TM(r4)
+ mtspr SPRN_VRSAVE, r7
+
+ ld r5, VCPU_LR_TM(r4)
+ lwz r6, VCPU_CR_TM(r4)
+ ld r7, VCPU_CTR_TM(r4)
+ ld r8, VCPU_AMR_TM(r4)
+ ld r9, VCPU_TAR_TM(r4)
+ mtlr r5
+ mtcr r6
+ mtctr r7
+ mtspr SPRN_AMR, r8
+ mtspr SPRN_TAR, r9
+
+ /*
+ * Load up PPR and DSCR values but don't put them in the actual SPRs
+ * till the last moment to avoid running with userspace PPR and DSCR for
+ * too long.
+ */
+ ld r29, VCPU_DSCR_TM(r4)
+ ld r30, VCPU_PPR_TM(r4)
+
+ std r2, PACATMSCRATCH(r13) /* Save TOC */
+
+ /* Clear the MSR RI since r1, r13 are all going to be foobar. */
+ li r5, 0
+ mtmsrd r5, 1
+
+ /* Load GPRs r0-r28 */
+ reg = 0
+ .rept 29
+ ld reg, VCPU_GPRS_TM(reg)(r31)
+ reg = reg + 1
+ .endr
+
+ mtspr SPRN_DSCR, r29
+ mtspr SPRN_PPR, r30
+
+ /* Load final GPRs */
+ ld 29, VCPU_GPRS_TM(29)(r31)
+ ld 30, VCPU_GPRS_TM(30)(r31)
+ ld 31, VCPU_GPRS_TM(31)(r31)
+
+ /* TM checkpointed state is now setup. All GPRs are now volatile. */
+ TRECHKPT
+
+ /* Now let's get back the state we need. */
+ HMT_MEDIUM
+ GET_PACA(r13)
+ ld r29, HSTATE_DSCR(r13)
+ mtspr SPRN_DSCR, r29
+ ld r4, HSTATE_KVM_VCPU(r13)
+ ld r1, HSTATE_HOST_R1(r13)
+ ld r2, PACATMSCRATCH(r13)
+
+ /* Set the MSR RI since we have our registers back. */
+ li r5, MSR_RI
+ mtmsrd r5, 1
+skip_tm:
+#endif
+
/* Load guest PMU registers */
/* R4 is live here (vcpu pointer) */
li r3, 1
@@ -704,14 +827,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
ld r6, VCPU_VTB(r4)
mtspr SPRN_IC, r5
mtspr SPRN_VTB, r6
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- ld r5, VCPU_TFHAR(r4)
- ld r6, VCPU_TFIAR(r4)
- ld r7, VCPU_TEXASR(r4)
- mtspr SPRN_TFHAR, r5
- mtspr SPRN_TFIAR, r6
- mtspr SPRN_TEXASR, r7
-#endif
ld r8, VCPU_EBBHR(r4)
mtspr SPRN_EBBHR, r8
ld r5, VCPU_EBBRR(r4)
@@ -736,6 +851,10 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
* Set the decrementer to the guest decrementer.
*/
ld r8,VCPU_DEC_EXPIRES(r4)
+ /* r8 is a host timebase value here, convert to guest TB */
+ ld r5,HSTATE_KVM_VCORE(r13)
+ ld r6,VCORE_TB_OFFSET(r5)
+ add r8,r8,r6
mftb r7
subf r3,r7,r8
mtspr SPRN_DEC,r3
@@ -817,7 +936,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
12: mtspr SPRN_SRR0, r10
mr r10,r0
mtspr SPRN_SRR1, r11
- ld r11, VCPU_INTR_MSR(r4)
+ mr r9, r4
+ bl kvmppc_msr_interrupt
5:
/*
@@ -1098,17 +1218,15 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_201)
mftb r6
extsw r5,r5
add r5,r5,r6
+ /* r5 is a guest timebase value here, convert to host TB */
+ ld r3,HSTATE_KVM_VCORE(r13)
+ ld r4,VCORE_TB_OFFSET(r3)
+ subf r5,r4,r5
std r5,VCPU_DEC_EXPIRES(r9)
BEGIN_FTR_SECTION
b 8f
END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
- /* Turn on TM so we can access TFHAR/TFIAR/TEXASR */
- mfmsr r8
- li r0, 1
- rldimi r8, r0, MSR_TM_LG, 63-MSR_TM_LG
- mtmsrd r8
-
/* Save POWER8-specific registers */
mfspr r5, SPRN_IAMR
mfspr r6, SPRN_PSPB
@@ -1122,14 +1240,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
std r5, VCPU_IC(r9)
std r6, VCPU_VTB(r9)
std r7, VCPU_TAR(r9)
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- mfspr r5, SPRN_TFHAR
- mfspr r6, SPRN_TFIAR
- mfspr r7, SPRN_TEXASR
- std r5, VCPU_TFHAR(r9)
- std r6, VCPU_TFIAR(r9)
- std r7, VCPU_TEXASR(r9)
-#endif
mfspr r8, SPRN_EBBHR
std r8, VCPU_EBBHR(r9)
mfspr r5, SPRN_EBBRR
@@ -1387,7 +1497,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
ld r8,VCORE_TB_OFFSET(r5)
cmpdi r8,0
beq 17f
- mftb r6 /* current host timebase */
+ mftb r6 /* current guest timebase */
subf r8,r8,r6
mtspr SPRN_TBU40,r8 /* update upper 40 bits */
mftb r7 /* check if lower 24 bits overflowed */
@@ -1504,73 +1614,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
1: addi r8,r8,16
.endr
- /* Save DEC */
- mfspr r5,SPRN_DEC
- mftb r6
- extsw r5,r5
- add r5,r5,r6
- std r5,VCPU_DEC_EXPIRES(r9)
-
-BEGIN_FTR_SECTION
- b 8f
-END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
- /* Turn on TM so we can access TFHAR/TFIAR/TEXASR */
- mfmsr r8
- li r0, 1
- rldimi r8, r0, MSR_TM_LG, 63-MSR_TM_LG
- mtmsrd r8
-
- /* Save POWER8-specific registers */
- mfspr r5, SPRN_IAMR
- mfspr r6, SPRN_PSPB
- mfspr r7, SPRN_FSCR
- std r5, VCPU_IAMR(r9)
- stw r6, VCPU_PSPB(r9)
- std r7, VCPU_FSCR(r9)
- mfspr r5, SPRN_IC
- mfspr r6, SPRN_VTB
- mfspr r7, SPRN_TAR
- std r5, VCPU_IC(r9)
- std r6, VCPU_VTB(r9)
- std r7, VCPU_TAR(r9)
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- mfspr r5, SPRN_TFHAR
- mfspr r6, SPRN_TFIAR
- mfspr r7, SPRN_TEXASR
- std r5, VCPU_TFHAR(r9)
- std r6, VCPU_TFIAR(r9)
- std r7, VCPU_TEXASR(r9)
-#endif
- mfspr r8, SPRN_EBBHR
- std r8, VCPU_EBBHR(r9)
- mfspr r5, SPRN_EBBRR
- mfspr r6, SPRN_BESCR
- mfspr r7, SPRN_CSIGR
- mfspr r8, SPRN_TACR
- std r5, VCPU_EBBRR(r9)
- std r6, VCPU_BESCR(r9)
- std r7, VCPU_CSIGR(r9)
- std r8, VCPU_TACR(r9)
- mfspr r5, SPRN_TCSCR
- mfspr r6, SPRN_ACOP
- mfspr r7, SPRN_PID
- mfspr r8, SPRN_WORT
- std r5, VCPU_TCSCR(r9)
- std r6, VCPU_ACOP(r9)
- stw r7, VCPU_GUEST_PID(r9)
- std r8, VCPU_WORT(r9)
-8:
-
- /* Save and reset AMR and UAMOR before turning on the MMU */
-BEGIN_FTR_SECTION
- mfspr r5,SPRN_AMR
- mfspr r6,SPRN_UAMOR
- std r5,VCPU_AMR(r9)
- std r6,VCPU_UAMOR(r9)
- li r6,0
- mtspr SPRN_AMR,r6
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
-
/* Unset guest mode */
li r0, KVM_GUEST_MODE_NONE
stb r0, HSTATE_IN_GUEST(r13)
@@ -1624,7 +1667,7 @@ kvmppc_hdsi:
mtspr SPRN_SRR0, r10
mtspr SPRN_SRR1, r11
li r10, BOOK3S_INTERRUPT_DATA_STORAGE
- ld r11, VCPU_INTR_MSR(r9)
+ bl kvmppc_msr_interrupt
fast_interrupt_c_return:
6: ld r7, VCPU_CTR(r9)
lwz r8, VCPU_XER(r9)
@@ -1693,7 +1736,7 @@ kvmppc_hisi:
1: mtspr SPRN_SRR0, r10
mtspr SPRN_SRR1, r11
li r10, BOOK3S_INTERRUPT_INST_STORAGE
- ld r11, VCPU_INTR_MSR(r9)
+ bl kvmppc_msr_interrupt
b fast_interrupt_c_return
3: ld r6, VCPU_KVM(r9) /* not relocated, use VRMA */
@@ -1736,7 +1779,7 @@ sc_1_fast_return:
mtspr SPRN_SRR0,r10
mtspr SPRN_SRR1,r11
li r10, BOOK3S_INTERRUPT_SYSCALL
- ld r11, VCPU_INTR_MSR(r9)
+ bl kvmppc_msr_interrupt
mr r4,r9
b fast_guest_return
@@ -1758,7 +1801,7 @@ hcall_real_table:
.long 0 /* 0x10 - H_CLEAR_MOD */
.long 0 /* 0x14 - H_CLEAR_REF */
.long .kvmppc_h_protect - hcall_real_table
- .long 0 /* 0x1c - H_GET_TCE */
+ .long .kvmppc_h_get_tce - hcall_real_table
.long .kvmppc_h_put_tce - hcall_real_table
.long 0 /* 0x24 - H_SET_SPRG0 */
.long .kvmppc_h_set_dabr - hcall_real_table
@@ -2064,7 +2107,7 @@ machine_check_realmode:
beq mc_cont
/* If not, deliver a machine check. SRR0/1 are already set */
li r10, BOOK3S_INTERRUPT_MACHINE_CHECK
- ld r11, VCPU_INTR_MSR(r9)
+ bl kvmppc_msr_interrupt
b fast_interrupt_c_return
/*
@@ -2203,10 +2246,8 @@ BEGIN_FTR_SECTION
END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
#endif
mfspr r6,SPRN_VRSAVE
- stw r6,VCPU_VRSAVE(r3)
+ stw r6,VCPU_VRSAVE(r31)
mtlr r30
- mtmsrd r5
- isync
blr
/*
@@ -2240,7 +2281,7 @@ BEGIN_FTR_SECTION
bl .load_vr_state
END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
#endif
- lwz r7,VCPU_VRSAVE(r4)
+ lwz r7,VCPU_VRSAVE(r31)
mtspr SPRN_VRSAVE,r7
mtlr r30
mr r4,r31
@@ -2253,3 +2294,20 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
*/
kvmppc_bad_host_intr:
b .
+
+/*
+ * This mimics the MSR transition on IRQ delivery. The new guest MSR is taken
+ * from VCPU_INTR_MSR and is modified based on the required TM state changes.
+ * r11 has the guest MSR value (in/out)
+ * r9 has a vcpu pointer (in)
+ * r0 is used as a scratch register
+ */
+kvmppc_msr_interrupt:
+ rldicl r0, r11, 64 - MSR_TS_S_LG, 62
+ cmpwi r0, 2 /* Check if we are in transactional state.. */
+ ld r11, VCPU_INTR_MSR(r9)
+ bne 1f
+ /* ... if transactional, change to suspended */
+ li r0, 1
+1: rldimi r11, r0, MSR_TS_S_LG, 63 - MSR_TS_T_LG
+ blr
diff --git a/arch/powerpc/kvm/book3s_interrupts.S b/arch/powerpc/kvm/book3s_interrupts.S
index f779450cb07c..3533c999194a 100644
--- a/arch/powerpc/kvm/book3s_interrupts.S
+++ b/arch/powerpc/kvm/book3s_interrupts.S
@@ -153,8 +153,8 @@ kvm_start_lightweight:
* Reload kernel SPRG3 value.
* No need to save guest value as usermode can't modify SPRG3.
*/
- ld r3, PACA_SPRG3(r13)
- mtspr SPRN_SPRG3, r3
+ ld r3, PACA_SPRG_VDSO(r13)
+ mtspr SPRN_SPRG_VDSO_WRITE, r3
#endif /* CONFIG_PPC_BOOK3S_64 */
/* R7 = vcpu */
diff --git a/arch/powerpc/kvm/book3s_rtas.c b/arch/powerpc/kvm/book3s_rtas.c
index cf95cdef73c9..7a053157483b 100644
--- a/arch/powerpc/kvm/book3s_rtas.c
+++ b/arch/powerpc/kvm/book3s_rtas.c
@@ -213,8 +213,11 @@ int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)
gpa_t args_phys;
int rc;
- /* r4 contains the guest physical address of the RTAS args */
- args_phys = kvmppc_get_gpr(vcpu, 4);
+ /*
+ * r4 contains the guest physical address of the RTAS args
+ * Mask off the top 4 bits since this is a guest real address
+ */
+ args_phys = kvmppc_get_gpr(vcpu, 4) & KVM_PAM;
rc = kvm_read_guest(vcpu->kvm, args_phys, &args, sizeof(args));
if (rc)
diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S
index e4185f6b3309..a1712b818a5f 100644
--- a/arch/powerpc/kvm/bookehv_interrupts.S
+++ b/arch/powerpc/kvm/bookehv_interrupts.S
@@ -229,17 +229,20 @@
stw r10, VCPU_CR(r4)
PPC_STL r11, VCPU_GPR(R4)(r4)
PPC_STL r5, VCPU_GPR(R5)(r4)
- .if \type == EX_CRIT
- PPC_LL r5, (\paca_ex + EX_R13)(r13)
- .else
- mfspr r5, \scratch
- .endif
PPC_STL r6, VCPU_GPR(R6)(r4)
PPC_STL r8, VCPU_GPR(R8)(r4)
PPC_STL r9, VCPU_GPR(R9)(r4)
- PPC_STL r5, VCPU_GPR(R13)(r4)
+ .if \type == EX_TLB
+ PPC_LL r5, EX_TLB_R13(r12)
+ PPC_LL r6, EX_TLB_R10(r12)
+ PPC_LL r8, EX_TLB_R11(r12)
+ mfspr r12, \scratch
+ .else
+ mfspr r5, \scratch
PPC_LL r6, (\paca_ex + \ex_r10)(r13)
PPC_LL r8, (\paca_ex + \ex_r11)(r13)
+ .endif
+ PPC_STL r5, VCPU_GPR(R13)(r4)
PPC_STL r3, VCPU_GPR(R3)(r4)
PPC_STL r7, VCPU_GPR(R7)(r4)
PPC_STL r12, VCPU_GPR(R12)(r4)
@@ -435,10 +438,16 @@ _GLOBAL(kvmppc_resume_host)
PPC_STL r5, VCPU_LR(r4)
mfspr r7, SPRN_SPRG5
stw r3, VCPU_VRSAVE(r4)
+#ifdef CONFIG_64BIT
+ PPC_LL r3, PACA_SPRG_VDSO(r13)
+#endif
PPC_STD(r6, VCPU_SHARED_SPRG4, r11)
mfspr r8, SPRN_SPRG6
PPC_STD(r7, VCPU_SHARED_SPRG5, r11)
mfspr r9, SPRN_SPRG7
+#ifdef CONFIG_64BIT
+ mtspr SPRN_SPRG_VDSO_WRITE, r3
+#endif
PPC_STD(r8, VCPU_SHARED_SPRG6, r11)
mfxer r3
PPC_STD(r9, VCPU_SHARED_SPRG7, r11)
diff --git a/arch/powerpc/lib/memcpy_64.S b/arch/powerpc/lib/memcpy_64.S
index d2bbbc8d7dc0..72ad055168a3 100644
--- a/arch/powerpc/lib/memcpy_64.S
+++ b/arch/powerpc/lib/memcpy_64.S
@@ -14,7 +14,9 @@ _GLOBAL(memcpy)
BEGIN_FTR_SECTION
std r3,48(r1) /* save destination pointer for return value */
FTR_SECTION_ELSE
+#ifndef SELFTEST
b memcpy_power7
+#endif
ALT_FTR_SECTION_END_IFCLR(CPU_FTR_VMX_COPY)
PPC_MTOCRF(0x01,r5)
cmpldi cr1,r5,16
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index de6881259aef..d766d6ee33fe 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -207,6 +207,20 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
if (overlaps_kernel_text(vaddr, vaddr + step))
tprot &= ~HPTE_R_N;
+ /*
+ * If relocatable, check if it overlaps interrupt vectors that
+ * are copied down to real 0. For relocatable kernel
+ * (e.g. kdump case) we copy interrupt vectors down to real
+ * address 0. Mark that region as executable. This is
+ * because on p8 system with relocation on exception feature
+ * enabled, exceptions are raised with MMU (IR=DR=1) ON. Hence
+ * in order to execute the interrupt handlers in virtual
+ * mode the vector region need to be marked as executable.
+ */
+ if ((PHYSICAL_START > MEMORY_START) &&
+ overlaps_interrupt_vector_text(vaddr, vaddr + step))
+ tprot &= ~HPTE_R_N;
+
hash = hpt_hash(vpn, shift, ssize);
hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 4b5cd5c2594d..2c8e90f5789e 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -139,9 +139,14 @@ int arch_remove_memory(u64 start, u64 size)
unsigned long start_pfn = start >> PAGE_SHIFT;
unsigned long nr_pages = size >> PAGE_SHIFT;
struct zone *zone;
+ int ret;
zone = page_zone(pfn_to_page(start_pfn));
- return __remove_pages(zone, start_pfn, nr_pages);
+ ret = __remove_pages(zone, start_pfn, nr_pages);
+ if (!ret && (ppc_md.remove_memory))
+ ret = ppc_md.remove_memory(start, size);
+
+ return ret;
}
#endif
#endif /* CONFIG_MEMORY_HOTPLUG */
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index 65b7b65e8708..f6ce1f111f5b 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -510,7 +510,8 @@ int pmdp_set_access_flags(struct vm_area_struct *vma, unsigned long address,
}
unsigned long pmd_hugepage_update(struct mm_struct *mm, unsigned long addr,
- pmd_t *pmdp, unsigned long clr)
+ pmd_t *pmdp, unsigned long clr,
+ unsigned long set)
{
unsigned long old, tmp;
@@ -526,14 +527,15 @@ unsigned long pmd_hugepage_update(struct mm_struct *mm, unsigned long addr,
andi. %1,%0,%6\n\
bne- 1b \n\
andc %1,%0,%4 \n\
+ or %1,%1,%7\n\
stdcx. %1,0,%3 \n\
bne- 1b"
: "=&r" (old), "=&r" (tmp), "=m" (*pmdp)
- : "r" (pmdp), "r" (clr), "m" (*pmdp), "i" (_PAGE_BUSY)
+ : "r" (pmdp), "r" (clr), "m" (*pmdp), "i" (_PAGE_BUSY), "r" (set)
: "cc" );
#else
old = pmd_val(*pmdp);
- *pmdp = __pmd(old & ~clr);
+ *pmdp = __pmd((old & ~clr) | set);
#endif
if (old & _PAGE_HASHPTE)
hpte_do_hugepage_flush(mm, addr, pmdp);
@@ -645,6 +647,11 @@ void pmdp_splitting_flush(struct vm_area_struct *vma,
if (old & _PAGE_HASHPTE)
hpte_do_hugepage_flush(vma->vm_mm, address, pmdp);
}
+ /*
+ * This ensures that generic code that rely on IRQ disabling
+ * to prevent a parallel THP split work as expected.
+ */
+ kick_all_cpus_sync();
}
/*
@@ -708,7 +715,7 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,
void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
pmd_t *pmdp)
{
- pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT);
+ pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT, 0);
}
/*
@@ -835,7 +842,7 @@ pmd_t pmdp_get_and_clear(struct mm_struct *mm,
unsigned long old;
pgtable_t *pgtable_slot;
- old = pmd_hugepage_update(mm, addr, pmdp, ~0UL);
+ old = pmd_hugepage_update(mm, addr, pmdp, ~0UL, 0);
old_pmd = __pmd(old);
/*
* We have pmd == none and we are holding page_table_lock.
diff --git a/arch/powerpc/mm/subpage-prot.c b/arch/powerpc/mm/subpage-prot.c
index a770df2dae70..6c0b1f5f8d2c 100644
--- a/arch/powerpc/mm/subpage-prot.c
+++ b/arch/powerpc/mm/subpage-prot.c
@@ -78,7 +78,7 @@ static void hpte_flush_range(struct mm_struct *mm, unsigned long addr,
pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
arch_enter_lazy_mmu_mode();
for (; npages > 0; --npages) {
- pte_update(mm, addr, pte, 0, 0);
+ pte_update(mm, addr, pte, 0, 0, 0);
addr += PAGE_SIZE;
++pte;
}
diff --git a/arch/powerpc/mm/tlb_low_64e.S b/arch/powerpc/mm/tlb_low_64e.S
index c95eb323e9ae..356e8b41fb09 100644
--- a/arch/powerpc/mm/tlb_low_64e.S
+++ b/arch/powerpc/mm/tlb_low_64e.S
@@ -39,37 +39,49 @@
* *
**********************************************************************/
+/*
+ * Note that, unlike non-bolted handlers, TLB_EXFRAME is not
+ * modified by the TLB miss handlers themselves, since the TLB miss
+ * handler code will not itself cause a recursive TLB miss.
+ *
+ * TLB_EXFRAME will be modified when crit/mc/debug exceptions are
+ * entered/exited.
+ */
.macro tlb_prolog_bolted intnum addr
- mtspr SPRN_SPRG_GEN_SCRATCH,r13
+ mtspr SPRN_SPRG_GEN_SCRATCH,r12
+ mfspr r12,SPRN_SPRG_TLB_EXFRAME
+ std r13,EX_TLB_R13(r12)
+ std r10,EX_TLB_R10(r12)
mfspr r13,SPRN_SPRG_PACA
- std r10,PACA_EXTLB+EX_TLB_R10(r13)
+
mfcr r10
- std r11,PACA_EXTLB+EX_TLB_R11(r13)
+ std r11,EX_TLB_R11(r12)
#ifdef CONFIG_KVM_BOOKE_HV
BEGIN_FTR_SECTION
mfspr r11, SPRN_SRR1
END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV)
#endif
DO_KVM \intnum, SPRN_SRR1
- std r16,PACA_EXTLB+EX_TLB_R16(r13)
+ std r16,EX_TLB_R16(r12)
mfspr r16,\addr /* get faulting address */
- std r14,PACA_EXTLB+EX_TLB_R14(r13)
+ std r14,EX_TLB_R14(r12)
ld r14,PACAPGD(r13)
- std r15,PACA_EXTLB+EX_TLB_R15(r13)
- std r10,PACA_EXTLB+EX_TLB_CR(r13)
- TLB_MISS_PROLOG_STATS_BOLTED
+ std r15,EX_TLB_R15(r12)
+ std r10,EX_TLB_CR(r12)
+ TLB_MISS_PROLOG_STATS
.endm
.macro tlb_epilog_bolted
- ld r14,PACA_EXTLB+EX_TLB_CR(r13)
- ld r10,PACA_EXTLB+EX_TLB_R10(r13)
- ld r11,PACA_EXTLB+EX_TLB_R11(r13)
+ ld r14,EX_TLB_CR(r12)
+ ld r10,EX_TLB_R10(r12)
+ ld r11,EX_TLB_R11(r12)
+ ld r13,EX_TLB_R13(r12)
mtcr r14
- ld r14,PACA_EXTLB+EX_TLB_R14(r13)
- ld r15,PACA_EXTLB+EX_TLB_R15(r13)
- TLB_MISS_RESTORE_STATS_BOLTED
- ld r16,PACA_EXTLB+EX_TLB_R16(r13)
- mfspr r13,SPRN_SPRG_GEN_SCRATCH
+ ld r14,EX_TLB_R14(r12)
+ ld r15,EX_TLB_R15(r12)
+ TLB_MISS_RESTORE_STATS
+ ld r16,EX_TLB_R16(r12)
+ mfspr r12,SPRN_SPRG_GEN_SCRATCH
.endm
/* Data TLB miss */
@@ -284,7 +296,7 @@ itlb_miss_fault_bolted:
* r14 = page table base
* r13 = PACA
* r11 = tlb_per_core ptr
- * r10 = crap (free to use)
+ * r10 = cpu number
*/
tlb_miss_common_e6500:
/*
@@ -293,15 +305,18 @@ tlb_miss_common_e6500:
*
* MAS6:IND should be already set based on MAS4
*/
- addi r10,r11,TCD_LOCK
-1: lbarx r15,0,r10
+1: lbarx r15,0,r11
+ lhz r10,PACAPACAINDEX(r13)
cmpdi r15,0
+ cmpdi cr1,r15,1 /* set cr1.eq = 0 for non-recursive */
bne 2f
- li r15,1
- stbcx. r15,0,r10
+ stbcx. r10,0,r11
bne 1b
+3:
.subsection 1
-2: lbz r15,0(r10)
+2: cmpd cr1,r15,r10 /* recursive lock due to mcheck/crit/etc? */
+ beq cr1,3b /* unlock will happen if cr1.eq = 0 */
+ lbz r15,0(r11)
cmpdi r15,0
bne 2b
b 1b
@@ -379,9 +394,11 @@ tlb_miss_common_e6500:
tlb_miss_done_e6500:
.macro tlb_unlock_e6500
+ beq cr1,1f /* no unlock if lock was recursively grabbed */
li r15,0
isync
- stb r15,TCD_LOCK(r11)
+ stb r15,0(r11)
+1:
.endm
tlb_unlock_e6500
@@ -1091,7 +1108,8 @@ tlb_load_linear:
ld r11,PACATOC(r13)
ld r11,linear_map_top@got(r11)
ld r10,0(r11)
- cmpld cr0,r10,r16
+ tovirt(10,10)
+ cmpld cr0,r16,r10
bge tlb_load_linear_fault
/* MAS1 need whole new setup. */
diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c
index b37a58e1c92d..ae3d5b799b90 100644
--- a/arch/powerpc/mm/tlb_nohash.c
+++ b/arch/powerpc/mm/tlb_nohash.c
@@ -144,6 +144,15 @@ int mmu_vmemmap_psize; /* Page size used for the virtual mem map */
int book3e_htw_mode; /* HW tablewalk? Value is PPC_HTW_* */
unsigned long linear_map_top; /* Top of linear mapping */
+
+/*
+ * Number of bytes to add to SPRN_SPRG_TLB_EXFRAME on crit/mcheck/debug
+ * exceptions. This is used for bolted and e6500 TLB miss handlers which
+ * do not modify this SPRG in the TLB miss code; for other TLB miss handlers,
+ * this is set to zero.
+ */
+int extlb_level_exc;
+
#endif /* CONFIG_PPC64 */
#ifdef CONFIG_PPC_FSL_BOOK3E
@@ -559,6 +568,7 @@ static void setup_mmu_htw(void)
break;
#ifdef CONFIG_PPC_FSL_BOOK3E
case PPC_HTW_E6500:
+ extlb_level_exc = EX_TLB_SIZE;
patch_exception(0x1c0, exc_data_tlb_miss_e6500_book3e);
patch_exception(0x1e0, exc_instruction_tlb_miss_e6500_book3e);
break;
@@ -652,6 +662,7 @@ static void __early_init_mmu(int boot_cpu)
memblock_enforce_memory_limit(linear_map_top);
if (book3e_htw_mode == PPC_HTW_NONE) {
+ extlb_level_exc = EX_TLB_SIZE;
patch_exception(0x1c0, exc_data_tlb_miss_bolted_book3e);
patch_exception(0x1e0,
exc_instruction_tlb_miss_bolted_book3e);
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index 555034f8505e..808ce1cae21a 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -390,9 +390,9 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
mark));
break;
case BPF_S_ANC_RXHASH:
- BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, hash) != 4);
PPC_LWZ_OFFS(r_A, r_skb, offsetof(struct sk_buff,
- rxhash));
+ hash));
break;
case BPF_S_ANC_VLAN_TAG:
case BPF_S_ANC_VLAN_TAG_PRESENT:
@@ -689,6 +689,7 @@ void bpf_jit_compile(struct sk_filter *fp)
((u64 *)image)[0] = (u64)code_base;
((u64 *)image)[1] = local_paca->kernel_toc;
fp->bpf_func = (void *)image;
+ fp->jited = 1;
}
out:
kfree(addrs);
@@ -697,7 +698,7 @@ out:
void bpf_jit_free(struct sk_filter *fp)
{
- if (fp->bpf_func != sk_run_filter)
+ if (fp->jited)
module_free(NULL, fp->bpf_func);
kfree(fp);
}
diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c
index 1f0ebdeea5f7..863d89386f60 100644
--- a/arch/powerpc/oprofile/op_model_cell.c
+++ b/arch/powerpc/oprofile/op_model_cell.c
@@ -1121,8 +1121,7 @@ oprof_cpufreq_notify(struct notifier_block *nb, unsigned long val, void *data)
int ret = 0;
struct cpufreq_freqs *frq = data;
if ((val == CPUFREQ_PRECHANGE && frq->old < frq->new) ||
- (val == CPUFREQ_POSTCHANGE && frq->old > frq->new) ||
- (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE))
+ (val == CPUFREQ_POSTCHANGE && frq->old > frq->new))
set_spu_profiling_frequency(frq->new, spu_cycle_reset);
return ret;
}
diff --git a/arch/powerpc/perf/Makefile b/arch/powerpc/perf/Makefile
index 60d71eea919c..f9c083a5652a 100644
--- a/arch/powerpc/perf/Makefile
+++ b/arch/powerpc/perf/Makefile
@@ -11,5 +11,7 @@ obj32-$(CONFIG_PPC_PERF_CTRS) += mpc7450-pmu.o
obj-$(CONFIG_FSL_EMB_PERF_EVENT) += core-fsl-emb.o
obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o e6500-pmu.o
+obj-$(CONFIG_HV_PERF_CTRS) += hv-24x7.o hv-gpci.o hv-common.o
+
obj-$(CONFIG_PPC64) += $(obj64-y)
obj-$(CONFIG_PPC32) += $(obj32-y)
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 29b89e863d7c..4520c9356b54 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -78,6 +78,7 @@ static unsigned int freeze_events_kernel = MMCR0_FCS;
#define MMCR0_FC56 0
#define MMCR0_PMAO 0
#define MMCR0_EBE 0
+#define MMCR0_BHRBA 0
#define MMCR0_PMCC 0
#define MMCR0_PMCC_U6 0
@@ -120,6 +121,7 @@ static inline void power_pmu_bhrb_enable(struct perf_event *event) {}
static inline void power_pmu_bhrb_disable(struct perf_event *event) {}
void power_pmu_flush_branch_stack(void) {}
static inline void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) {}
+static void pmao_restore_workaround(bool ebb) { }
#endif /* CONFIG_PPC32 */
static bool regs_use_siar(struct pt_regs *regs)
@@ -502,8 +504,11 @@ static int ebb_event_check(struct perf_event *event)
if (!leader->attr.pinned || !leader->attr.exclusive)
return -EINVAL;
- if (event->attr.inherit || event->attr.sample_period ||
- event->attr.enable_on_exec || event->attr.freq)
+ if (event->attr.freq ||
+ event->attr.inherit ||
+ event->attr.sample_type ||
+ event->attr.sample_period ||
+ event->attr.enable_on_exec)
return -EINVAL;
}
@@ -542,13 +547,21 @@ static unsigned long ebb_switch_in(bool ebb, unsigned long mmcr0)
if (!ebb)
goto out;
- /* Enable EBB and read/write to all 6 PMCs for userspace */
- mmcr0 |= MMCR0_EBE | MMCR0_PMCC_U6;
+ /* Enable EBB and read/write to all 6 PMCs and BHRB for userspace */
+ mmcr0 |= MMCR0_EBE | MMCR0_BHRBA | MMCR0_PMCC_U6;
- /* Add any bits from the user reg, FC or PMAO */
+ /*
+ * Add any bits from the user MMCR0, FC or PMAO. This is compatible
+ * with pmao_restore_workaround() because we may add PMAO but we never
+ * clear it here.
+ */
mmcr0 |= current->thread.mmcr0;
- /* Be careful not to set PMXE if userspace had it cleared */
+ /*
+ * Be careful not to set PMXE if userspace had it cleared. This is also
+ * compatible with pmao_restore_workaround() because it has already
+ * cleared PMXE and we leave PMAO alone.
+ */
if (!(current->thread.mmcr0 & MMCR0_PMXE))
mmcr0 &= ~MMCR0_PMXE;
@@ -559,13 +572,94 @@ static unsigned long ebb_switch_in(bool ebb, unsigned long mmcr0)
out:
return mmcr0;
}
-#endif /* CONFIG_PPC64 */
-static void perf_event_interrupt(struct pt_regs *regs);
-
-void perf_event_print_debug(void)
+static void pmao_restore_workaround(bool ebb)
{
+ unsigned pmcs[6];
+
+ if (!cpu_has_feature(CPU_FTR_PMAO_BUG))
+ return;
+
+ /*
+ * On POWER8E there is a hardware defect which affects the PMU context
+ * switch logic, ie. power_pmu_disable/enable().
+ *
+ * When a counter overflows PMXE is cleared and FC/PMAO is set in MMCR0
+ * by the hardware. Sometime later the actual PMU exception is
+ * delivered.
+ *
+ * If we context switch, or simply disable/enable, the PMU prior to the
+ * exception arriving, the exception will be lost when we clear PMAO.
+ *
+ * When we reenable the PMU, we will write the saved MMCR0 with PMAO
+ * set, and this _should_ generate an exception. However because of the
+ * defect no exception is generated when we write PMAO, and we get
+ * stuck with no counters counting but no exception delivered.
+ *
+ * The workaround is to detect this case and tweak the hardware to
+ * create another pending PMU exception.
+ *
+ * We do that by setting up PMC6 (cycles) for an imminent overflow and
+ * enabling the PMU. That causes a new exception to be generated in the
+ * chip, but we don't take it yet because we have interrupts hard
+ * disabled. We then write back the PMU state as we want it to be seen
+ * by the exception handler. When we reenable interrupts the exception
+ * handler will be called and see the correct state.
+ *
+ * The logic is the same for EBB, except that the exception is gated by
+ * us having interrupts hard disabled as well as the fact that we are
+ * not in userspace. The exception is finally delivered when we return
+ * to userspace.
+ */
+
+ /* Only if PMAO is set and PMAO_SYNC is clear */
+ if ((current->thread.mmcr0 & (MMCR0_PMAO | MMCR0_PMAO_SYNC)) != MMCR0_PMAO)
+ return;
+
+ /* If we're doing EBB, only if BESCR[GE] is set */
+ if (ebb && !(current->thread.bescr & BESCR_GE))
+ return;
+
+ /*
+ * We are already soft-disabled in power_pmu_enable(). We need to hard
+ * enable to actually prevent the PMU exception from firing.
+ */
+ hard_irq_disable();
+
+ /*
+ * This is a bit gross, but we know we're on POWER8E and have 6 PMCs.
+ * Using read/write_pmc() in a for loop adds 12 function calls and
+ * almost doubles our code size.
+ */
+ pmcs[0] = mfspr(SPRN_PMC1);
+ pmcs[1] = mfspr(SPRN_PMC2);
+ pmcs[2] = mfspr(SPRN_PMC3);
+ pmcs[3] = mfspr(SPRN_PMC4);
+ pmcs[4] = mfspr(SPRN_PMC5);
+ pmcs[5] = mfspr(SPRN_PMC6);
+
+ /* Ensure all freeze bits are unset */
+ mtspr(SPRN_MMCR2, 0);
+
+ /* Set up PMC6 to overflow in one cycle */
+ mtspr(SPRN_PMC6, 0x7FFFFFFE);
+
+ /* Enable exceptions and unfreeze PMC6 */
+ mtspr(SPRN_MMCR0, MMCR0_PMXE | MMCR0_PMCjCE | MMCR0_PMAO);
+
+ /* Now we need to refreeze and restore the PMCs */
+ mtspr(SPRN_MMCR0, MMCR0_FC | MMCR0_PMAO);
+
+ mtspr(SPRN_PMC1, pmcs[0]);
+ mtspr(SPRN_PMC2, pmcs[1]);
+ mtspr(SPRN_PMC3, pmcs[2]);
+ mtspr(SPRN_PMC4, pmcs[3]);
+ mtspr(SPRN_PMC5, pmcs[4]);
+ mtspr(SPRN_PMC6, pmcs[5]);
}
+#endif /* CONFIG_PPC64 */
+
+static void perf_event_interrupt(struct pt_regs *regs);
/*
* Read one performance monitor counter (PMC).
@@ -645,6 +739,57 @@ static void write_pmc(int idx, unsigned long val)
}
}
+/* Called from sysrq_handle_showregs() */
+void perf_event_print_debug(void)
+{
+ unsigned long sdar, sier, flags;
+ u32 pmcs[MAX_HWEVENTS];
+ int i;
+
+ if (!ppmu->n_counter)
+ return;
+
+ local_irq_save(flags);
+
+ pr_info("CPU: %d PMU registers, ppmu = %s n_counters = %d",
+ smp_processor_id(), ppmu->name, ppmu->n_counter);
+
+ for (i = 0; i < ppmu->n_counter; i++)
+ pmcs[i] = read_pmc(i + 1);
+
+ for (; i < MAX_HWEVENTS; i++)
+ pmcs[i] = 0xdeadbeef;
+
+ pr_info("PMC1: %08x PMC2: %08x PMC3: %08x PMC4: %08x\n",
+ pmcs[0], pmcs[1], pmcs[2], pmcs[3]);
+
+ if (ppmu->n_counter > 4)
+ pr_info("PMC5: %08x PMC6: %08x PMC7: %08x PMC8: %08x\n",
+ pmcs[4], pmcs[5], pmcs[6], pmcs[7]);
+
+ pr_info("MMCR0: %016lx MMCR1: %016lx MMCRA: %016lx\n",
+ mfspr(SPRN_MMCR0), mfspr(SPRN_MMCR1), mfspr(SPRN_MMCRA));
+
+ sdar = sier = 0;
+#ifdef CONFIG_PPC64
+ sdar = mfspr(SPRN_SDAR);
+
+ if (ppmu->flags & PPMU_HAS_SIER)
+ sier = mfspr(SPRN_SIER);
+
+ if (ppmu->flags & PPMU_EBB) {
+ pr_info("MMCR2: %016lx EBBHR: %016lx\n",
+ mfspr(SPRN_MMCR2), mfspr(SPRN_EBBHR));
+ pr_info("EBBRR: %016lx BESCR: %016lx\n",
+ mfspr(SPRN_EBBRR), mfspr(SPRN_BESCR));
+ }
+#endif
+ pr_info("SIAR: %016lx SDAR: %016lx SIER: %016lx\n",
+ mfspr(SPRN_SIAR), sdar, sier);
+
+ local_irq_restore(flags);
+}
+
/*
* Check if a set of events can all go on the PMU at once.
* If they can't, this will look at alternative codes for the events
@@ -973,11 +1118,12 @@ static void power_pmu_disable(struct pmu *pmu)
}
/*
- * Set the 'freeze counters' bit, clear EBE/PMCC/PMAO/FC56.
+ * Set the 'freeze counters' bit, clear EBE/BHRBA/PMCC/PMAO/FC56
*/
val = mmcr0 = mfspr(SPRN_MMCR0);
val |= MMCR0_FC;
- val &= ~(MMCR0_EBE | MMCR0_PMCC | MMCR0_PMAO | MMCR0_FC56);
+ val &= ~(MMCR0_EBE | MMCR0_BHRBA | MMCR0_PMCC | MMCR0_PMAO |
+ MMCR0_FC56);
/*
* The barrier is to make sure the mtspr has been
@@ -1144,9 +1290,14 @@ static void power_pmu_enable(struct pmu *pmu)
cpuhw->mmcr[0] |= MMCR0_PMXE | MMCR0_FCECE;
out_enable:
+ pmao_restore_workaround(ebb);
+
mmcr0 = ebb_switch_in(ebb, cpuhw->mmcr[0]);
mb();
+ if (cpuhw->bhrb_users)
+ ppmu->config_bhrb(cpuhw->bhrb_filter);
+
write_mmcr0(cpuhw, mmcr0);
/*
@@ -1158,8 +1309,6 @@ static void power_pmu_enable(struct pmu *pmu)
}
out:
- if (cpuhw->bhrb_users)
- ppmu->config_bhrb(cpuhw->bhrb_filter);
local_irq_restore(flags);
}
diff --git a/arch/powerpc/perf/hv-24x7-catalog.h b/arch/powerpc/perf/hv-24x7-catalog.h
new file mode 100644
index 000000000000..21b19dd86d9c
--- /dev/null
+++ b/arch/powerpc/perf/hv-24x7-catalog.h
@@ -0,0 +1,33 @@
+#ifndef LINUX_POWERPC_PERF_HV_24X7_CATALOG_H_
+#define LINUX_POWERPC_PERF_HV_24X7_CATALOG_H_
+
+#include <linux/types.h>
+
+/* From document "24x7 Event and Group Catalog Formats Proposal" v0.15 */
+
+struct hv_24x7_catalog_page_0 {
+#define HV_24X7_CATALOG_MAGIC 0x32347837 /* "24x7" in ASCII */
+ __be32 magic;
+ __be32 length; /* In 4096 byte pages */
+ __be64 version; /* XXX: arbitrary? what's the meaning/useage/purpose? */
+ __u8 build_time_stamp[16]; /* "YYYYMMDDHHMMSS\0\0" */
+ __u8 reserved2[32];
+ __be16 schema_data_offs; /* in 4096 byte pages */
+ __be16 schema_data_len; /* in 4096 byte pages */
+ __be16 schema_entry_count;
+ __u8 reserved3[2];
+ __be16 event_data_offs;
+ __be16 event_data_len;
+ __be16 event_entry_count;
+ __u8 reserved4[2];
+ __be16 group_data_offs; /* in 4096 byte pages */
+ __be16 group_data_len; /* in 4096 byte pages */
+ __be16 group_entry_count;
+ __u8 reserved5[2];
+ __be16 formula_data_offs; /* in 4096 byte pages */
+ __be16 formula_data_len; /* in 4096 byte pages */
+ __be16 formula_entry_count;
+ __u8 reserved6[2];
+} __packed;
+
+#endif
diff --git a/arch/powerpc/perf/hv-24x7.c b/arch/powerpc/perf/hv-24x7.c
new file mode 100644
index 000000000000..297c91051413
--- /dev/null
+++ b/arch/powerpc/perf/hv-24x7.c
@@ -0,0 +1,510 @@
+/*
+ * Hypervisor supplied "24x7" performance counter support
+ *
+ * Author: Cody P Schafer <cody@linux.vnet.ibm.com>
+ * Copyright 2014 IBM 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 the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) "hv-24x7: " fmt
+
+#include <linux/perf_event.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/firmware.h>
+#include <asm/hvcall.h>
+#include <asm/io.h>
+
+#include "hv-24x7.h"
+#include "hv-24x7-catalog.h"
+#include "hv-common.h"
+
+/*
+ * TODO: Merging events:
+ * - Think of the hcall as an interface to a 4d array of counters:
+ * - x = domains
+ * - y = indexes in the domain (core, chip, vcpu, node, etc)
+ * - z = offset into the counter space
+ * - w = lpars (guest vms, "logical partitions")
+ * - A single request is: x,y,y_last,z,z_last,w,w_last
+ * - this means we can retrieve a rectangle of counters in y,z for a single x.
+ *
+ * - Things to consider (ignoring w):
+ * - input cost_per_request = 16
+ * - output cost_per_result(ys,zs) = 8 + 8 * ys + ys * zs
+ * - limited number of requests per hcall (must fit into 4K bytes)
+ * - 4k = 16 [buffer header] - 16 [request size] * request_count
+ * - 255 requests per hcall
+ * - sometimes it will be more efficient to read extra data and discard
+ */
+
+/*
+ * Example usage:
+ * perf stat -e 'hv_24x7/domain=2,offset=8,starting_index=0,lpar=0xffffffff/'
+ */
+
+/* u3 0-6, one of HV_24X7_PERF_DOMAIN */
+EVENT_DEFINE_RANGE_FORMAT(domain, config, 0, 3);
+/* u16 */
+EVENT_DEFINE_RANGE_FORMAT(starting_index, config, 16, 31);
+/* u32, see "data_offset" */
+EVENT_DEFINE_RANGE_FORMAT(offset, config, 32, 63);
+/* u16 */
+EVENT_DEFINE_RANGE_FORMAT(lpar, config1, 0, 15);
+
+EVENT_DEFINE_RANGE(reserved1, config, 4, 15);
+EVENT_DEFINE_RANGE(reserved2, config1, 16, 63);
+EVENT_DEFINE_RANGE(reserved3, config2, 0, 63);
+
+static struct attribute *format_attrs[] = {
+ &format_attr_domain.attr,
+ &format_attr_offset.attr,
+ &format_attr_starting_index.attr,
+ &format_attr_lpar.attr,
+ NULL,
+};
+
+static struct attribute_group format_group = {
+ .name = "format",
+ .attrs = format_attrs,
+};
+
+static struct kmem_cache *hv_page_cache;
+
+/*
+ * read_offset_data - copy data from one buffer to another while treating the
+ * source buffer as a small view on the total avaliable
+ * source data.
+ *
+ * @dest: buffer to copy into
+ * @dest_len: length of @dest in bytes
+ * @requested_offset: the offset within the source data we want. Must be > 0
+ * @src: buffer to copy data from
+ * @src_len: length of @src in bytes
+ * @source_offset: the offset in the sorce data that (src,src_len) refers to.
+ * Must be > 0
+ *
+ * returns the number of bytes copied.
+ *
+ * The following ascii art shows the various buffer possitioning we need to
+ * handle, assigns some arbitrary varibles to points on the buffer, and then
+ * shows how we fiddle with those values to get things we care about (copy
+ * start in src and copy len)
+ *
+ * s = @src buffer
+ * d = @dest buffer
+ * '.' areas in d are written to.
+ *
+ * u
+ * x w v z
+ * d |.........|
+ * s |----------------------|
+ *
+ * u
+ * x w z v
+ * d |........------|
+ * s |------------------|
+ *
+ * x w u,z,v
+ * d |........|
+ * s |------------------|
+ *
+ * x,w u,v,z
+ * d |..................|
+ * s |------------------|
+ *
+ * x u
+ * w v z
+ * d |........|
+ * s |------------------|
+ *
+ * x z w v
+ * d |------|
+ * s |------|
+ *
+ * x = source_offset
+ * w = requested_offset
+ * z = source_offset + src_len
+ * v = requested_offset + dest_len
+ *
+ * w_offset_in_s = w - x = requested_offset - source_offset
+ * z_offset_in_s = z - x = src_len
+ * v_offset_in_s = v - x = request_offset + dest_len - src_len
+ */
+static ssize_t read_offset_data(void *dest, size_t dest_len,
+ loff_t requested_offset, void *src,
+ size_t src_len, loff_t source_offset)
+{
+ size_t w_offset_in_s = requested_offset - source_offset;
+ size_t z_offset_in_s = src_len;
+ size_t v_offset_in_s = requested_offset + dest_len - src_len;
+ size_t u_offset_in_s = min(z_offset_in_s, v_offset_in_s);
+ size_t copy_len = u_offset_in_s - w_offset_in_s;
+
+ if (requested_offset < 0 || source_offset < 0)
+ return -EINVAL;
+
+ if (z_offset_in_s <= w_offset_in_s)
+ return 0;
+
+ memcpy(dest, src + w_offset_in_s, copy_len);
+ return copy_len;
+}
+
+static unsigned long h_get_24x7_catalog_page(char page[static 4096],
+ u32 version, u32 index)
+{
+ WARN_ON(!IS_ALIGNED((unsigned long)page, 4096));
+ return plpar_hcall_norets(H_GET_24X7_CATALOG_PAGE,
+ virt_to_phys(page),
+ version,
+ index);
+}
+
+static ssize_t catalog_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t offset, size_t count)
+{
+ unsigned long hret;
+ ssize_t ret = 0;
+ size_t catalog_len = 0, catalog_page_len = 0, page_count = 0;
+ loff_t page_offset = 0;
+ uint32_t catalog_version_num = 0;
+ void *page = kmem_cache_alloc(hv_page_cache, GFP_USER);
+ struct hv_24x7_catalog_page_0 *page_0 = page;
+ if (!page)
+ return -ENOMEM;
+
+ hret = h_get_24x7_catalog_page(page, 0, 0);
+ if (hret) {
+ ret = -EIO;
+ goto e_free;
+ }
+
+ catalog_version_num = be32_to_cpu(page_0->version);
+ catalog_page_len = be32_to_cpu(page_0->length);
+ catalog_len = catalog_page_len * 4096;
+
+ page_offset = offset / 4096;
+ page_count = count / 4096;
+
+ if (page_offset >= catalog_page_len)
+ goto e_free;
+
+ if (page_offset != 0) {
+ hret = h_get_24x7_catalog_page(page, catalog_version_num,
+ page_offset);
+ if (hret) {
+ ret = -EIO;
+ goto e_free;
+ }
+ }
+
+ ret = read_offset_data(buf, count, offset,
+ page, 4096, page_offset * 4096);
+e_free:
+ if (hret)
+ pr_err("h_get_24x7_catalog_page(ver=%d, page=%lld) failed: rc=%ld\n",
+ catalog_version_num, page_offset, hret);
+ kfree(page);
+
+ pr_devel("catalog_read: offset=%lld(%lld) count=%zu(%zu) catalog_len=%zu(%zu) => %zd\n",
+ offset, page_offset, count, page_count, catalog_len,
+ catalog_page_len, ret);
+
+ return ret;
+}
+
+#define PAGE_0_ATTR(_name, _fmt, _expr) \
+static ssize_t _name##_show(struct device *dev, \
+ struct device_attribute *dev_attr, \
+ char *buf) \
+{ \
+ unsigned long hret; \
+ ssize_t ret = 0; \
+ void *page = kmem_cache_alloc(hv_page_cache, GFP_USER); \
+ struct hv_24x7_catalog_page_0 *page_0 = page; \
+ if (!page) \
+ return -ENOMEM; \
+ hret = h_get_24x7_catalog_page(page, 0, 0); \
+ if (hret) { \
+ ret = -EIO; \
+ goto e_free; \
+ } \
+ ret = sprintf(buf, _fmt, _expr); \
+e_free: \
+ kfree(page); \
+ return ret; \
+} \
+static DEVICE_ATTR_RO(_name)
+
+PAGE_0_ATTR(catalog_version, "%lld\n",
+ (unsigned long long)be32_to_cpu(page_0->version));
+PAGE_0_ATTR(catalog_len, "%lld\n",
+ (unsigned long long)be32_to_cpu(page_0->length) * 4096);
+static BIN_ATTR_RO(catalog, 0/* real length varies */);
+
+static struct bin_attribute *if_bin_attrs[] = {
+ &bin_attr_catalog,
+ NULL,
+};
+
+static struct attribute *if_attrs[] = {
+ &dev_attr_catalog_len.attr,
+ &dev_attr_catalog_version.attr,
+ NULL,
+};
+
+static struct attribute_group if_group = {
+ .name = "interface",
+ .bin_attrs = if_bin_attrs,
+ .attrs = if_attrs,
+};
+
+static const struct attribute_group *attr_groups[] = {
+ &format_group,
+ &if_group,
+ NULL,
+};
+
+static bool is_physical_domain(int domain)
+{
+ return domain == HV_24X7_PERF_DOMAIN_PHYSICAL_CHIP ||
+ domain == HV_24X7_PERF_DOMAIN_PHYSICAL_CORE;
+}
+
+static unsigned long single_24x7_request(u8 domain, u32 offset, u16 ix,
+ u16 lpar, u64 *res,
+ bool success_expected)
+{
+ unsigned long ret;
+
+ /*
+ * request_buffer and result_buffer are not required to be 4k aligned,
+ * but are not allowed to cross any 4k boundary. Aligning them to 4k is
+ * the simplest way to ensure that.
+ */
+ struct reqb {
+ struct hv_24x7_request_buffer buf;
+ struct hv_24x7_request req;
+ } __packed __aligned(4096) request_buffer = {
+ .buf = {
+ .interface_version = HV_24X7_IF_VERSION_CURRENT,
+ .num_requests = 1,
+ },
+ .req = {
+ .performance_domain = domain,
+ .data_size = cpu_to_be16(8),
+ .data_offset = cpu_to_be32(offset),
+ .starting_lpar_ix = cpu_to_be16(lpar),
+ .max_num_lpars = cpu_to_be16(1),
+ .starting_ix = cpu_to_be16(ix),
+ .max_ix = cpu_to_be16(1),
+ }
+ };
+
+ struct resb {
+ struct hv_24x7_data_result_buffer buf;
+ struct hv_24x7_result res;
+ struct hv_24x7_result_element elem;
+ __be64 result;
+ } __packed __aligned(4096) result_buffer = {};
+
+ ret = plpar_hcall_norets(H_GET_24X7_DATA,
+ virt_to_phys(&request_buffer), sizeof(request_buffer),
+ virt_to_phys(&result_buffer), sizeof(result_buffer));
+
+ if (ret) {
+ if (success_expected)
+ pr_err_ratelimited("hcall failed: %d %#x %#x %d => 0x%lx (%ld) detail=0x%x failing ix=%x\n",
+ domain, offset, ix, lpar,
+ ret, ret,
+ result_buffer.buf.detailed_rc,
+ result_buffer.buf.failing_request_ix);
+ return ret;
+ }
+
+ *res = be64_to_cpu(result_buffer.result);
+ return ret;
+}
+
+static unsigned long event_24x7_request(struct perf_event *event, u64 *res,
+ bool success_expected)
+{
+ return single_24x7_request(event_get_domain(event),
+ event_get_offset(event),
+ event_get_starting_index(event),
+ event_get_lpar(event),
+ res,
+ success_expected);
+}
+
+static int h_24x7_event_init(struct perf_event *event)
+{
+ struct hv_perf_caps caps;
+ unsigned domain;
+ unsigned long hret;
+ u64 ct;
+
+ /* Not our event */
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+
+ /* Unused areas must be 0 */
+ if (event_get_reserved1(event) ||
+ event_get_reserved2(event) ||
+ event_get_reserved3(event)) {
+ pr_devel("reserved set when forbidden 0x%llx(0x%llx) 0x%llx(0x%llx) 0x%llx(0x%llx)\n",
+ event->attr.config,
+ event_get_reserved1(event),
+ event->attr.config1,
+ event_get_reserved2(event),
+ event->attr.config2,
+ event_get_reserved3(event));
+ return -EINVAL;
+ }
+
+ /* unsupported modes and filters */
+ if (event->attr.exclude_user ||
+ event->attr.exclude_kernel ||
+ event->attr.exclude_hv ||
+ event->attr.exclude_idle ||
+ event->attr.exclude_host ||
+ event->attr.exclude_guest ||
+ is_sampling_event(event)) /* no sampling */
+ return -EINVAL;
+
+ /* no branch sampling */
+ if (has_branch_stack(event))
+ return -EOPNOTSUPP;
+
+ /* offset must be 8 byte aligned */
+ if (event_get_offset(event) % 8) {
+ pr_devel("bad alignment\n");
+ return -EINVAL;
+ }
+
+ /* Domains above 6 are invalid */
+ domain = event_get_domain(event);
+ if (domain > 6) {
+ pr_devel("invalid domain %d\n", domain);
+ return -EINVAL;
+ }
+
+ hret = hv_perf_caps_get(&caps);
+ if (hret) {
+ pr_devel("could not get capabilities: rc=%ld\n", hret);
+ return -EIO;
+ }
+
+ /* PHYSICAL domains & other lpars require extra capabilities */
+ if (!caps.collect_privileged && (is_physical_domain(domain) ||
+ (event_get_lpar(event) != event_get_lpar_max()))) {
+ pr_devel("hv permisions disallow: is_physical_domain:%d, lpar=0x%llx\n",
+ is_physical_domain(domain),
+ event_get_lpar(event));
+ return -EACCES;
+ }
+
+ /* see if the event complains */
+ if (event_24x7_request(event, &ct, false)) {
+ pr_devel("test hcall failed\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static u64 h_24x7_get_value(struct perf_event *event)
+{
+ unsigned long ret;
+ u64 ct;
+ ret = event_24x7_request(event, &ct, true);
+ if (ret)
+ /* We checked this in event init, shouldn't fail here... */
+ return 0;
+
+ return ct;
+}
+
+static void h_24x7_event_update(struct perf_event *event)
+{
+ s64 prev;
+ u64 now;
+ now = h_24x7_get_value(event);
+ prev = local64_xchg(&event->hw.prev_count, now);
+ local64_add(now - prev, &event->count);
+}
+
+static void h_24x7_event_start(struct perf_event *event, int flags)
+{
+ if (flags & PERF_EF_RELOAD)
+ local64_set(&event->hw.prev_count, h_24x7_get_value(event));
+}
+
+static void h_24x7_event_stop(struct perf_event *event, int flags)
+{
+ h_24x7_event_update(event);
+}
+
+static int h_24x7_event_add(struct perf_event *event, int flags)
+{
+ if (flags & PERF_EF_START)
+ h_24x7_event_start(event, flags);
+
+ return 0;
+}
+
+static int h_24x7_event_idx(struct perf_event *event)
+{
+ return 0;
+}
+
+static struct pmu h_24x7_pmu = {
+ .task_ctx_nr = perf_invalid_context,
+
+ .name = "hv_24x7",
+ .attr_groups = attr_groups,
+ .event_init = h_24x7_event_init,
+ .add = h_24x7_event_add,
+ .del = h_24x7_event_stop,
+ .start = h_24x7_event_start,
+ .stop = h_24x7_event_stop,
+ .read = h_24x7_event_update,
+ .event_idx = h_24x7_event_idx,
+};
+
+static int hv_24x7_init(void)
+{
+ int r;
+ unsigned long hret;
+ struct hv_perf_caps caps;
+
+ if (!firmware_has_feature(FW_FEATURE_LPAR)) {
+ pr_info("not a virtualized system, not enabling\n");
+ return -ENODEV;
+ }
+
+ hret = hv_perf_caps_get(&caps);
+ if (hret) {
+ pr_info("could not obtain capabilities, error 0x%80lx, not enabling\n",
+ hret);
+ return -ENODEV;
+ }
+
+ hv_page_cache = kmem_cache_create("hv-page-4096", 4096, 4096, 0, NULL);
+ if (!hv_page_cache)
+ return -ENOMEM;
+
+ r = perf_pmu_register(&h_24x7_pmu, h_24x7_pmu.name, -1);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+device_initcall(hv_24x7_init);
diff --git a/arch/powerpc/perf/hv-24x7.h b/arch/powerpc/perf/hv-24x7.h
new file mode 100644
index 000000000000..720ebce4b435
--- /dev/null
+++ b/arch/powerpc/perf/hv-24x7.h
@@ -0,0 +1,109 @@
+#ifndef LINUX_POWERPC_PERF_HV_24X7_H_
+#define LINUX_POWERPC_PERF_HV_24X7_H_
+
+#include <linux/types.h>
+
+struct hv_24x7_request {
+ /* PHYSICAL domains require enabling via phyp/hmc. */
+#define HV_24X7_PERF_DOMAIN_PHYSICAL_CHIP 0x01
+#define HV_24X7_PERF_DOMAIN_PHYSICAL_CORE 0x02
+#define HV_24X7_PERF_DOMAIN_VIRTUAL_PROCESSOR_HOME_CORE 0x03
+#define HV_24X7_PERF_DOMAIN_VIRTUAL_PROCESSOR_HOME_CHIP 0x04
+#define HV_24X7_PERF_DOMAIN_VIRTUAL_PROCESSOR_HOME_NODE 0x05
+#define HV_24X7_PERF_DOMAIN_VIRTUAL_PROCESSOR_REMOTE_NODE 0x06
+ __u8 performance_domain;
+ __u8 reserved[0x1];
+
+ /* bytes to read starting at @data_offset. must be a multiple of 8 */
+ __be16 data_size;
+
+ /*
+ * byte offset within the perf domain to read from. must be 8 byte
+ * aligned
+ */
+ __be32 data_offset;
+
+ /*
+ * only valid for VIRTUAL_PROCESSOR domains, ignored for others.
+ * -1 means "current partition only"
+ * Enabling via phyp/hmc required for non-"-1" values. 0 forbidden
+ * unless requestor is 0.
+ */
+ __be16 starting_lpar_ix;
+
+ /*
+ * Ignored when @starting_lpar_ix == -1
+ * Ignored when @performance_domain is not VIRTUAL_PROCESSOR_*
+ * -1 means "infinite" or all
+ */
+ __be16 max_num_lpars;
+
+ /* chip, core, or virtual processor based on @performance_domain */
+ __be16 starting_ix;
+ __be16 max_ix;
+} __packed;
+
+struct hv_24x7_request_buffer {
+ /* 0 - ? */
+ /* 1 - ? */
+#define HV_24X7_IF_VERSION_CURRENT 0x01
+ __u8 interface_version;
+ __u8 num_requests;
+ __u8 reserved[0xE];
+ struct hv_24x7_request requests[];
+} __packed;
+
+struct hv_24x7_result_element {
+ __be16 lpar_ix;
+
+ /*
+ * represents the core, chip, or virtual processor based on the
+ * request's @performance_domain
+ */
+ __be16 domain_ix;
+
+ /* -1 if @performance_domain does not refer to a virtual processor */
+ __be32 lpar_cfg_instance_id;
+
+ /* size = @result_element_data_size of cointaining result. */
+ __u8 element_data[];
+} __packed;
+
+struct hv_24x7_result {
+ __u8 result_ix;
+
+ /*
+ * 0 = not all result elements fit into the buffer, additional requests
+ * required
+ * 1 = all result elements were returned
+ */
+ __u8 results_complete;
+ __be16 num_elements_returned;
+
+ /* This is a copy of @data_size from the coresponding hv_24x7_request */
+ __be16 result_element_data_size;
+ __u8 reserved[0x2];
+
+ /* WARNING: only valid for first result element due to variable sizes
+ * of result elements */
+ /* struct hv_24x7_result_element[@num_elements_returned] */
+ struct hv_24x7_result_element elements[];
+} __packed;
+
+struct hv_24x7_data_result_buffer {
+ /* See versioning for request buffer */
+ __u8 interface_version;
+
+ __u8 num_results;
+ __u8 reserved[0x1];
+ __u8 failing_request_ix;
+ __be32 detailed_rc;
+ __be64 cec_cfg_instance_id;
+ __be64 catalog_version_num;
+ __u8 reserved2[0x8];
+ /* WARNING: only valid for the first result due to variable sizes of
+ * results */
+ struct hv_24x7_result results[]; /* [@num_results] */
+} __packed;
+
+#endif
diff --git a/arch/powerpc/perf/hv-common.c b/arch/powerpc/perf/hv-common.c
new file mode 100644
index 000000000000..47e02b366f58
--- /dev/null
+++ b/arch/powerpc/perf/hv-common.c
@@ -0,0 +1,39 @@
+#include <asm/io.h>
+#include <asm/hvcall.h>
+
+#include "hv-gpci.h"
+#include "hv-common.h"
+
+unsigned long hv_perf_caps_get(struct hv_perf_caps *caps)
+{
+ unsigned long r;
+ struct p {
+ struct hv_get_perf_counter_info_params params;
+ struct cv_system_performance_capabilities caps;
+ } __packed __aligned(sizeof(uint64_t));
+
+ struct p arg = {
+ .params = {
+ .counter_request = cpu_to_be32(
+ CIR_SYSTEM_PERFORMANCE_CAPABILITIES),
+ .starting_index = cpu_to_be32(-1),
+ .counter_info_version_in = 0,
+ }
+ };
+
+ r = plpar_hcall_norets(H_GET_PERF_COUNTER_INFO,
+ virt_to_phys(&arg), sizeof(arg));
+
+ if (r)
+ return r;
+
+ pr_devel("capability_mask: 0x%x\n", arg.caps.capability_mask);
+
+ caps->version = arg.params.counter_info_version_out;
+ caps->collect_privileged = !!arg.caps.perf_collect_privileged;
+ caps->ga = !!(arg.caps.capability_mask & CV_CM_GA);
+ caps->expanded = !!(arg.caps.capability_mask & CV_CM_EXPANDED);
+ caps->lab = !!(arg.caps.capability_mask & CV_CM_LAB);
+
+ return r;
+}
diff --git a/arch/powerpc/perf/hv-common.h b/arch/powerpc/perf/hv-common.h
new file mode 100644
index 000000000000..5d79cecbd73d
--- /dev/null
+++ b/arch/powerpc/perf/hv-common.h
@@ -0,0 +1,36 @@
+#ifndef LINUX_POWERPC_PERF_HV_COMMON_H_
+#define LINUX_POWERPC_PERF_HV_COMMON_H_
+
+#include <linux/perf_event.h>
+#include <linux/types.h>
+
+struct hv_perf_caps {
+ u16 version;
+ u16 collect_privileged:1,
+ ga:1,
+ expanded:1,
+ lab:1,
+ unused:12;
+};
+
+unsigned long hv_perf_caps_get(struct hv_perf_caps *caps);
+
+
+#define EVENT_DEFINE_RANGE_FORMAT(name, attr_var, bit_start, bit_end) \
+PMU_FORMAT_ATTR(name, #attr_var ":" #bit_start "-" #bit_end); \
+EVENT_DEFINE_RANGE(name, attr_var, bit_start, bit_end)
+
+#define EVENT_DEFINE_RANGE(name, attr_var, bit_start, bit_end) \
+static u64 event_get_##name##_max(void) \
+{ \
+ BUILD_BUG_ON((bit_start > bit_end) \
+ || (bit_end >= (sizeof(1ull) * 8))); \
+ return (((1ull << (bit_end - bit_start)) - 1) << 1) + 1; \
+} \
+static u64 event_get_##name(struct perf_event *event) \
+{ \
+ return (event->attr.attr_var >> (bit_start)) & \
+ event_get_##name##_max(); \
+}
+
+#endif
diff --git a/arch/powerpc/perf/hv-gpci.c b/arch/powerpc/perf/hv-gpci.c
new file mode 100644
index 000000000000..278ba7b9c2b5
--- /dev/null
+++ b/arch/powerpc/perf/hv-gpci.c
@@ -0,0 +1,294 @@
+/*
+ * Hypervisor supplied "gpci" ("get performance counter info") performance
+ * counter support
+ *
+ * Author: Cody P Schafer <cody@linux.vnet.ibm.com>
+ * Copyright 2014 IBM 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 the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) "hv-gpci: " fmt
+
+#include <linux/init.h>
+#include <linux/perf_event.h>
+#include <asm/firmware.h>
+#include <asm/hvcall.h>
+#include <asm/io.h>
+
+#include "hv-gpci.h"
+#include "hv-common.h"
+
+/*
+ * Example usage:
+ * perf stat -e 'hv_gpci/counter_info_version=3,offset=0,length=8,
+ * secondary_index=0,starting_index=0xffffffff,request=0x10/' ...
+ */
+
+/* u32 */
+EVENT_DEFINE_RANGE_FORMAT(request, config, 0, 31);
+/* u32 */
+EVENT_DEFINE_RANGE_FORMAT(starting_index, config, 32, 63);
+/* u16 */
+EVENT_DEFINE_RANGE_FORMAT(secondary_index, config1, 0, 15);
+/* u8 */
+EVENT_DEFINE_RANGE_FORMAT(counter_info_version, config1, 16, 23);
+/* u8, bytes of data (1-8) */
+EVENT_DEFINE_RANGE_FORMAT(length, config1, 24, 31);
+/* u32, byte offset */
+EVENT_DEFINE_RANGE_FORMAT(offset, config1, 32, 63);
+
+static struct attribute *format_attrs[] = {
+ &format_attr_request.attr,
+ &format_attr_starting_index.attr,
+ &format_attr_secondary_index.attr,
+ &format_attr_counter_info_version.attr,
+
+ &format_attr_offset.attr,
+ &format_attr_length.attr,
+ NULL,
+};
+
+static struct attribute_group format_group = {
+ .name = "format",
+ .attrs = format_attrs,
+};
+
+#define HV_CAPS_ATTR(_name, _format) \
+static ssize_t _name##_show(struct device *dev, \
+ struct device_attribute *attr, \
+ char *page) \
+{ \
+ struct hv_perf_caps caps; \
+ unsigned long hret = hv_perf_caps_get(&caps); \
+ if (hret) \
+ return -EIO; \
+ \
+ return sprintf(page, _format, caps._name); \
+} \
+static struct device_attribute hv_caps_attr_##_name = __ATTR_RO(_name)
+
+static ssize_t kernel_version_show(struct device *dev,
+ struct device_attribute *attr,
+ char *page)
+{
+ return sprintf(page, "0x%x\n", COUNTER_INFO_VERSION_CURRENT);
+}
+
+DEVICE_ATTR_RO(kernel_version);
+HV_CAPS_ATTR(version, "0x%x\n");
+HV_CAPS_ATTR(ga, "%d\n");
+HV_CAPS_ATTR(expanded, "%d\n");
+HV_CAPS_ATTR(lab, "%d\n");
+HV_CAPS_ATTR(collect_privileged, "%d\n");
+
+static struct attribute *interface_attrs[] = {
+ &dev_attr_kernel_version.attr,
+ &hv_caps_attr_version.attr,
+ &hv_caps_attr_ga.attr,
+ &hv_caps_attr_expanded.attr,
+ &hv_caps_attr_lab.attr,
+ &hv_caps_attr_collect_privileged.attr,
+ NULL,
+};
+
+static struct attribute_group interface_group = {
+ .name = "interface",
+ .attrs = interface_attrs,
+};
+
+static const struct attribute_group *attr_groups[] = {
+ &format_group,
+ &interface_group,
+ NULL,
+};
+
+#define GPCI_MAX_DATA_BYTES \
+ (1024 - sizeof(struct hv_get_perf_counter_info_params))
+
+static unsigned long single_gpci_request(u32 req, u32 starting_index,
+ u16 secondary_index, u8 version_in, u32 offset, u8 length,
+ u64 *value)
+{
+ unsigned long ret;
+ size_t i;
+ u64 count;
+
+ struct {
+ struct hv_get_perf_counter_info_params params;
+ uint8_t bytes[GPCI_MAX_DATA_BYTES];
+ } __packed __aligned(sizeof(uint64_t)) arg = {
+ .params = {
+ .counter_request = cpu_to_be32(req),
+ .starting_index = cpu_to_be32(starting_index),
+ .secondary_index = cpu_to_be16(secondary_index),
+ .counter_info_version_in = version_in,
+ }
+ };
+
+ ret = plpar_hcall_norets(H_GET_PERF_COUNTER_INFO,
+ virt_to_phys(&arg), sizeof(arg));
+ if (ret) {
+ pr_devel("hcall failed: 0x%lx\n", ret);
+ return ret;
+ }
+
+ /*
+ * we verify offset and length are within the zeroed buffer at event
+ * init.
+ */
+ count = 0;
+ for (i = offset; i < offset + length; i++)
+ count |= arg.bytes[i] << (i - offset);
+
+ *value = count;
+ return ret;
+}
+
+static u64 h_gpci_get_value(struct perf_event *event)
+{
+ u64 count;
+ unsigned long ret = single_gpci_request(event_get_request(event),
+ event_get_starting_index(event),
+ event_get_secondary_index(event),
+ event_get_counter_info_version(event),
+ event_get_offset(event),
+ event_get_length(event),
+ &count);
+ if (ret)
+ return 0;
+ return count;
+}
+
+static void h_gpci_event_update(struct perf_event *event)
+{
+ s64 prev;
+ u64 now = h_gpci_get_value(event);
+ prev = local64_xchg(&event->hw.prev_count, now);
+ local64_add(now - prev, &event->count);
+}
+
+static void h_gpci_event_start(struct perf_event *event, int flags)
+{
+ local64_set(&event->hw.prev_count, h_gpci_get_value(event));
+}
+
+static void h_gpci_event_stop(struct perf_event *event, int flags)
+{
+ h_gpci_event_update(event);
+}
+
+static int h_gpci_event_add(struct perf_event *event, int flags)
+{
+ if (flags & PERF_EF_START)
+ h_gpci_event_start(event, flags);
+
+ return 0;
+}
+
+static int h_gpci_event_init(struct perf_event *event)
+{
+ u64 count;
+ u8 length;
+
+ /* Not our event */
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+
+ /* config2 is unused */
+ if (event->attr.config2) {
+ pr_devel("config2 set when reserved\n");
+ return -EINVAL;
+ }
+
+ /* unsupported modes and filters */
+ if (event->attr.exclude_user ||
+ event->attr.exclude_kernel ||
+ event->attr.exclude_hv ||
+ event->attr.exclude_idle ||
+ event->attr.exclude_host ||
+ event->attr.exclude_guest ||
+ is_sampling_event(event)) /* no sampling */
+ return -EINVAL;
+
+ /* no branch sampling */
+ if (has_branch_stack(event))
+ return -EOPNOTSUPP;
+
+ length = event_get_length(event);
+ if (length < 1 || length > 8) {
+ pr_devel("length invalid\n");
+ return -EINVAL;
+ }
+
+ /* last byte within the buffer? */
+ if ((event_get_offset(event) + length) > GPCI_MAX_DATA_BYTES) {
+ pr_devel("request outside of buffer: %zu > %zu\n",
+ (size_t)event_get_offset(event) + length,
+ GPCI_MAX_DATA_BYTES);
+ return -EINVAL;
+ }
+
+ /* check if the request works... */
+ if (single_gpci_request(event_get_request(event),
+ event_get_starting_index(event),
+ event_get_secondary_index(event),
+ event_get_counter_info_version(event),
+ event_get_offset(event),
+ length,
+ &count)) {
+ pr_devel("gpci hcall failed\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int h_gpci_event_idx(struct perf_event *event)
+{
+ return 0;
+}
+
+static struct pmu h_gpci_pmu = {
+ .task_ctx_nr = perf_invalid_context,
+
+ .name = "hv_gpci",
+ .attr_groups = attr_groups,
+ .event_init = h_gpci_event_init,
+ .add = h_gpci_event_add,
+ .del = h_gpci_event_stop,
+ .start = h_gpci_event_start,
+ .stop = h_gpci_event_stop,
+ .read = h_gpci_event_update,
+ .event_idx = h_gpci_event_idx,
+};
+
+static int hv_gpci_init(void)
+{
+ int r;
+ unsigned long hret;
+ struct hv_perf_caps caps;
+
+ if (!firmware_has_feature(FW_FEATURE_LPAR)) {
+ pr_info("not a virtualized system, not enabling\n");
+ return -ENODEV;
+ }
+
+ hret = hv_perf_caps_get(&caps);
+ if (hret) {
+ pr_info("could not obtain capabilities, error 0x%80lx, not enabling\n",
+ hret);
+ return -ENODEV;
+ }
+
+ r = perf_pmu_register(&h_gpci_pmu, h_gpci_pmu.name, -1);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+device_initcall(hv_gpci_init);
diff --git a/arch/powerpc/perf/hv-gpci.h b/arch/powerpc/perf/hv-gpci.h
new file mode 100644
index 000000000000..b25f460c9cce
--- /dev/null
+++ b/arch/powerpc/perf/hv-gpci.h
@@ -0,0 +1,73 @@
+#ifndef LINUX_POWERPC_PERF_HV_GPCI_H_
+#define LINUX_POWERPC_PERF_HV_GPCI_H_
+
+#include <linux/types.h>
+
+/* From the document "H_GetPerformanceCounterInfo Interface" v1.07 */
+
+/* H_GET_PERF_COUNTER_INFO argument */
+struct hv_get_perf_counter_info_params {
+ __be32 counter_request; /* I */
+ __be32 starting_index; /* IO */
+ __be16 secondary_index; /* IO */
+ __be16 returned_values; /* O */
+ __be32 detail_rc; /* O, only needed when called via *_norets() */
+
+ /*
+ * O, size each of counter_value element in bytes, only set for version
+ * >= 0x3
+ */
+ __be16 cv_element_size;
+
+ /* I, 0 (zero) for versions < 0x3 */
+ __u8 counter_info_version_in;
+
+ /* O, 0 (zero) if version < 0x3. Must be set to 0 when making hcall */
+ __u8 counter_info_version_out;
+ __u8 reserved[0xC];
+ __u8 counter_value[];
+} __packed;
+
+/*
+ * counter info version => fw version/reference (spec version)
+ *
+ * 8 => power8 (1.07)
+ * [7 is skipped by spec 1.07]
+ * 6 => TLBIE (1.07)
+ * 5 => v7r7m0.phyp (1.05)
+ * [4 skipped]
+ * 3 => v7r6m0.phyp (?)
+ * [1,2 skipped]
+ * 0 => v7r{2,3,4}m0.phyp (?)
+ */
+#define COUNTER_INFO_VERSION_CURRENT 0x8
+
+/*
+ * These determine the counter_value[] layout and the meaning of starting_index
+ * and secondary_index.
+ *
+ * Unless otherwise noted, @secondary_index is unused and ignored.
+ */
+enum counter_info_requests {
+
+ /* GENERAL */
+
+ /* @starting_index: must be -1 (to refer to the current partition)
+ */
+ CIR_SYSTEM_PERFORMANCE_CAPABILITIES = 0X40,
+};
+
+struct cv_system_performance_capabilities {
+ /* If != 0, allowed to collect data from other partitions */
+ __u8 perf_collect_privileged;
+
+ /* These following are only valid if counter_info_version >= 0x3 */
+#define CV_CM_GA (1 << 7)
+#define CV_CM_EXPANDED (1 << 6)
+#define CV_CM_LAB (1 << 5)
+ /* remaining bits are reserved */
+ __u8 capability_mask;
+ __u8 reserved[0xE];
+} __packed;
+
+#endif
diff --git a/arch/powerpc/perf/power7-events-list.h b/arch/powerpc/perf/power7-events-list.h
index 687790a2c0b8..64f13d9260a6 100644
--- a/arch/powerpc/perf/power7-events-list.h
+++ b/arch/powerpc/perf/power7-events-list.h
@@ -546,3 +546,13 @@ EVENT(PM_MRK_DATA_FROM_RL2L3_SHR, 0x1d04c)
EVENT(PM_DTLB_MISS_16M, 0x4c05e)
EVENT(PM_LSU1_LMQ_LHR_MERGE, 0x0d09a)
EVENT(PM_IFU_FIN, 0x40066)
+EVENT(PM_1THRD_CON_RUN_INSTR, 0x30062)
+EVENT(PM_CMPLU_STALL_COUNT, 0x4000B)
+EVENT(PM_MEM0_PB_RD_CL, 0x30083)
+EVENT(PM_THRD_1_RUN_CYC, 0x10060)
+EVENT(PM_THRD_2_CONC_RUN_INSTR, 0x40062)
+EVENT(PM_THRD_2_RUN_CYC, 0x20060)
+EVENT(PM_THRD_3_CONC_RUN_INST, 0x10062)
+EVENT(PM_THRD_3_RUN_CYC, 0x30060)
+EVENT(PM_THRD_4_CONC_RUN_INST, 0x20062)
+EVENT(PM_THRD_4_RUN_CYC, 0x40060)
diff --git a/arch/powerpc/perf/power8-pmu.c b/arch/powerpc/perf/power8-pmu.c
index a3f7abd2f13f..fe2763b6e039 100644
--- a/arch/powerpc/perf/power8-pmu.c
+++ b/arch/powerpc/perf/power8-pmu.c
@@ -10,6 +10,8 @@
* 2 of the License, or (at your option) any later version.
*/
+#define pr_fmt(fmt) "power8-pmu: " fmt
+
#include <linux/kernel.h>
#include <linux/perf_event.h>
#include <asm/firmware.h>
@@ -25,15 +27,48 @@
#define PM_BRU_FIN 0x10068
#define PM_BR_MPRED_CMPL 0x400f6
+/* All L1 D cache load references counted at finish, gated by reject */
+#define PM_LD_REF_L1 0x100ee
+/* Load Missed L1 */
+#define PM_LD_MISS_L1 0x3e054
+/* Store Missed L1 */
+#define PM_ST_MISS_L1 0x300f0
+/* L1 cache data prefetches */
+#define PM_L1_PREF 0x0d8b8
+/* Instruction fetches from L1 */
+#define PM_INST_FROM_L1 0x04080
+/* Demand iCache Miss */
+#define PM_L1_ICACHE_MISS 0x200fd
+/* Instruction Demand sectors wriittent into IL1 */
+#define PM_L1_DEMAND_WRITE 0x0408c
+/* Instruction prefetch written into IL1 */
+#define PM_IC_PREF_WRITE 0x0408e
+/* The data cache was reloaded from local core's L3 due to a demand load */
+#define PM_DATA_FROM_L3 0x4c042
+/* Demand LD - L3 Miss (not L2 hit and not L3 hit) */
+#define PM_DATA_FROM_L3MISS 0x300fe
+/* All successful D-side store dispatches for this thread */
+#define PM_L2_ST 0x17080
+/* All successful D-side store dispatches for this thread that were L2 Miss */
+#define PM_L2_ST_MISS 0x17082
+/* Total HW L3 prefetches(Load+store) */
+#define PM_L3_PREF_ALL 0x4e052
+/* Data PTEG reload */
+#define PM_DTLB_MISS 0x300fc
+/* ITLB Reloaded */
+#define PM_ITLB_MISS 0x400fc
+
/*
* Raw event encoding for POWER8:
*
* 60 56 52 48 44 40 36 32
* | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - |
- * | [ thresh_cmp ] [ thresh_ctl ]
- * | |
- * *- EBB (Linux) thresh start/stop OR FAB match -*
+ * | | [ ] [ thresh_cmp ] [ thresh_ctl ]
+ * | | | |
+ * | | *- IFM (Linux) thresh start/stop OR FAB match -*
+ * | *- BHRB (Linux)
+ * *- EBB (Linux)
*
* 28 24 20 16 12 8 4 0
* | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - |
@@ -83,9 +118,18 @@
* MMCRA[57:59] = sample[0:2] (RAND_SAMP_ELIG)
 * MMCRA[61:62] = sample[3:4] (RAND_SAMP_MODE)
*
+ * if EBB and BHRB:
+ * MMCRA[32:33] = IFM
+ *
*/
#define EVENT_EBB_MASK 1ull
+#define EVENT_EBB_SHIFT PERF_EVENT_CONFIG_EBB_SHIFT
+#define EVENT_BHRB_MASK 1ull
+#define EVENT_BHRB_SHIFT 62
+#define EVENT_WANTS_BHRB (EVENT_BHRB_MASK << EVENT_BHRB_SHIFT)
+#define EVENT_IFM_MASK 3ull
+#define EVENT_IFM_SHIFT 60
#define EVENT_THR_CMP_SHIFT 40 /* Threshold CMP value */
#define EVENT_THR_CMP_MASK 0x3ff
#define EVENT_THR_CTL_SHIFT 32 /* Threshold control value (start/stop) */
@@ -110,6 +154,12 @@
#define EVENT_IS_MARKED (EVENT_MARKED_MASK << EVENT_MARKED_SHIFT)
#define EVENT_PSEL_MASK 0xff /* PMCxSEL value */
+/* Bits defined by Linux */
+#define EVENT_LINUX_MASK \
+ ((EVENT_EBB_MASK << EVENT_EBB_SHIFT) | \
+ (EVENT_BHRB_MASK << EVENT_BHRB_SHIFT) | \
+ (EVENT_IFM_MASK << EVENT_IFM_SHIFT))
+
#define EVENT_VALID_MASK \
((EVENT_THRESH_MASK << EVENT_THRESH_SHIFT) | \
(EVENT_SAMPLE_MASK << EVENT_SAMPLE_SHIFT) | \
@@ -118,7 +168,7 @@
(EVENT_UNIT_MASK << EVENT_UNIT_SHIFT) | \
(EVENT_COMBINE_MASK << EVENT_COMBINE_SHIFT) | \
(EVENT_MARKED_MASK << EVENT_MARKED_SHIFT) | \
- (EVENT_EBB_MASK << PERF_EVENT_CONFIG_EBB_SHIFT) | \
+ EVENT_LINUX_MASK | \
EVENT_PSEL_MASK)
/* MMCRA IFM bits - POWER8 */
@@ -142,10 +192,11 @@
*
* 28 24 20 16 12 8 4 0
* | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - |
- * | [ ] [ sample ] [ ] [6] [5] [4] [3] [2] [1]
- * EBB -* | |
- * | | Count of events for each PMC.
- * L1 I/D qualifier -* | p1, p2, p3, p4, p5, p6.
+ * [ ] | [ ] [ sample ] [ ] [6] [5] [4] [3] [2] [1]
+ * | | | |
+ * BHRB IFM -* | | | Count of events for each PMC.
+ * EBB -* | | p1, p2, p3, p4, p5, p6.
+ * L1 I/D qualifier -* |
* nc - number of counters -*
*
* The PMC fields P1..P6, and NC, are adder fields. As we accumulate constraints
@@ -164,6 +215,9 @@
#define CNST_EBB_VAL(v) (((v) & EVENT_EBB_MASK) << 24)
#define CNST_EBB_MASK CNST_EBB_VAL(EVENT_EBB_MASK)
+#define CNST_IFM_VAL(v) (((v) & EVENT_IFM_MASK) << 25)
+#define CNST_IFM_MASK CNST_IFM_VAL(EVENT_IFM_MASK)
+
#define CNST_L1_QUAL_VAL(v) (((v) & 3) << 22)
#define CNST_L1_QUAL_MASK CNST_L1_QUAL_VAL(3)
@@ -210,6 +264,7 @@
#define MMCRA_THR_SEL_SHIFT 16
#define MMCRA_THR_CMP_SHIFT 32
#define MMCRA_SDAR_MODE_TLB (1ull << 42)
+#define MMCRA_IFM_SHIFT 30
static inline bool event_is_fab_match(u64 event)
@@ -234,20 +289,22 @@ static int power8_get_constraint(u64 event, unsigned long *maskp, unsigned long
pmc = (event >> EVENT_PMC_SHIFT) & EVENT_PMC_MASK;
unit = (event >> EVENT_UNIT_SHIFT) & EVENT_UNIT_MASK;
cache = (event >> EVENT_CACHE_SEL_SHIFT) & EVENT_CACHE_SEL_MASK;
- ebb = (event >> PERF_EVENT_CONFIG_EBB_SHIFT) & EVENT_EBB_MASK;
-
- /* Clear the EBB bit in the event, so event checks work below */
- event &= ~(EVENT_EBB_MASK << PERF_EVENT_CONFIG_EBB_SHIFT);
+ ebb = (event >> EVENT_EBB_SHIFT) & EVENT_EBB_MASK;
if (pmc) {
+ u64 base_event;
+
if (pmc > 6)
return -1;
- mask |= CNST_PMC_MASK(pmc);
- value |= CNST_PMC_VAL(pmc);
+ /* Ignore Linux defined bits when checking event below */
+ base_event = event & ~EVENT_LINUX_MASK;
- if (pmc >= 5 && event != 0x500fa && event != 0x600f4)
+ if (pmc >= 5 && base_event != 0x500fa && base_event != 0x600f4)
return -1;
+
+ mask |= CNST_PMC_MASK(pmc);
+ value |= CNST_PMC_VAL(pmc);
}
if (pmc <= 4) {
@@ -268,9 +325,10 @@ static int power8_get_constraint(u64 event, unsigned long *maskp, unsigned long
* HV writable, and there is no API for guest kernels to modify
* it. The solution is for the hypervisor to initialise the
* field to zeroes, and for us to only ever allow events that
- * have a cache selector of zero.
+ * have a cache selector of zero. The bank selector (bit 3) is
+ * irrelevant, as long as the rest of the value is 0.
*/
- if (cache)
+ if (cache & 0x7)
return -1;
} else if (event & EVENT_IS_L1) {
@@ -311,6 +369,15 @@ static int power8_get_constraint(u64 event, unsigned long *maskp, unsigned long
/* EBB events must specify the PMC */
return -1;
+ if (event & EVENT_WANTS_BHRB) {
+ if (!ebb)
+ /* Only EBB events can request BHRB */
+ return -1;
+
+ mask |= CNST_IFM_MASK;
+ value |= CNST_IFM_VAL(event >> EVENT_IFM_SHIFT);
+ }
+
/*
* All events must agree on EBB, either all request it or none.
* EBB events are pinned & exclusive, so this should never actually
@@ -400,6 +467,11 @@ static int power8_compute_mmcr(u64 event[], int n_ev,
mmcra |= val << MMCRA_THR_CMP_SHIFT;
}
+ if (event[i] & EVENT_WANTS_BHRB) {
+ val = (event[i] >> EVENT_IFM_SHIFT) & EVENT_IFM_MASK;
+ mmcra |= val << MMCRA_IFM_SHIFT;
+ }
+
hwc[i] = pmc - 1;
}
@@ -557,6 +629,8 @@ static int power8_generic_events[] = {
[PERF_COUNT_HW_INSTRUCTIONS] = PM_INST_CMPL,
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = PM_BRU_FIN,
[PERF_COUNT_HW_BRANCH_MISSES] = PM_BR_MPRED_CMPL,
+ [PERF_COUNT_HW_CACHE_REFERENCES] = PM_LD_REF_L1,
+ [PERF_COUNT_HW_CACHE_MISSES] = PM_LD_MISS_L1,
};
static u64 power8_bhrb_filter_map(u64 branch_sample_type)
@@ -596,6 +670,116 @@ static void power8_config_bhrb(u64 pmu_bhrb_filter)
mtspr(SPRN_MMCRA, (mfspr(SPRN_MMCRA) | pmu_bhrb_filter));
}
+#define C(x) PERF_COUNT_HW_CACHE_##x
+
+/*
+ * Table of generalized cache-related events.
+ * 0 means not supported, -1 means nonsensical, other values
+ * are event codes.
+ */
+static int power8_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
+ [ C(L1D) ] = {
+ [ C(OP_READ) ] = {
+ [ C(RESULT_ACCESS) ] = PM_LD_REF_L1,
+ [ C(RESULT_MISS) ] = PM_LD_MISS_L1,
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = 0,
+ [ C(RESULT_MISS) ] = PM_ST_MISS_L1,
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = PM_L1_PREF,
+ [ C(RESULT_MISS) ] = 0,
+ },
+ },
+ [ C(L1I) ] = {
+ [ C(OP_READ) ] = {
+ [ C(RESULT_ACCESS) ] = PM_INST_FROM_L1,
+ [ C(RESULT_MISS) ] = PM_L1_ICACHE_MISS,
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = PM_L1_DEMAND_WRITE,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = PM_IC_PREF_WRITE,
+ [ C(RESULT_MISS) ] = 0,
+ },
+ },
+ [ C(LL) ] = {
+ [ C(OP_READ) ] = {
+ [ C(RESULT_ACCESS) ] = PM_DATA_FROM_L3,
+ [ C(RESULT_MISS) ] = PM_DATA_FROM_L3MISS,
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = PM_L2_ST,
+ [ C(RESULT_MISS) ] = PM_L2_ST_MISS,
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = PM_L3_PREF_ALL,
+ [ C(RESULT_MISS) ] = 0,
+ },
+ },
+ [ C(DTLB) ] = {
+ [ C(OP_READ) ] = {
+ [ C(RESULT_ACCESS) ] = 0,
+ [ C(RESULT_MISS) ] = PM_DTLB_MISS,
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ },
+ [ C(ITLB) ] = {
+ [ C(OP_READ) ] = {
+ [ C(RESULT_ACCESS) ] = 0,
+ [ C(RESULT_MISS) ] = PM_ITLB_MISS,
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ },
+ [ C(BPU) ] = {
+ [ C(OP_READ) ] = {
+ [ C(RESULT_ACCESS) ] = PM_BRU_FIN,
+ [ C(RESULT_MISS) ] = PM_BR_MPRED_CMPL,
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ },
+ [ C(NODE) ] = {
+ [ C(OP_READ) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = -1,
+ [ C(RESULT_MISS) ] = -1,
+ },
+ },
+};
+
+#undef C
+
static struct power_pmu power8_pmu = {
.name = "POWER8",
.n_counter = 6,
@@ -611,6 +795,7 @@ static struct power_pmu power8_pmu = {
.flags = PPMU_HAS_SSLOT | PPMU_HAS_SIER | PPMU_BHRB | PPMU_EBB,
.n_generic = ARRAY_SIZE(power8_generic_events),
.generic_events = power8_generic_events,
+ .cache_events = &power8_cache_events,
.attr_groups = power8_pmu_attr_groups,
.bhrb_nr = 32,
};
@@ -630,6 +815,9 @@ static int __init init_power8_pmu(void)
/* Tell userspace that EBB is supported */
cur_cpu_spec->cpu_user_features2 |= PPC_FEATURE2_EBB;
+ if (cpu_has_feature(CPU_FTR_PMAO_BUG))
+ pr_info("PMAO restore workaround active.\n");
+
return 0;
}
early_initcall(init_power8_pmu);
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index d6c7506ec7d9..dc1a264ec6e6 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -265,7 +265,6 @@ config 440EP
select PPC_FPU
select IBM440EP_ERR42
select IBM_EMAC_ZMII
- select USB_ARCH_HAS_OHCI
config 440EPX
bool
diff --git a/arch/powerpc/platforms/85xx/c293pcie.c b/arch/powerpc/platforms/85xx/c293pcie.c
index 213d5b815827..84476b646005 100644
--- a/arch/powerpc/platforms/85xx/c293pcie.c
+++ b/arch/powerpc/platforms/85xx/c293pcie.c
@@ -68,6 +68,7 @@ define_machine(c293_pcie) {
.init_IRQ = c293_pcie_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/85xx/common.c b/arch/powerpc/platforms/85xx/common.c
index 3b085c7ee539..b564b5e23f7c 100644
--- a/arch/powerpc/platforms/85xx/common.c
+++ b/arch/powerpc/platforms/85xx/common.c
@@ -107,6 +107,12 @@ void __init mpc85xx_qe_init(void)
qe_reset();
of_node_put(np);
+}
+
+void __init mpc85xx_qe_par_io_init(void)
+{
+ struct device_node *np;
+
np = of_find_node_by_name(NULL, "par_io");
if (np) {
struct device_node *ucc;
diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c
index fbd871e69754..8e4b1e1a4911 100644
--- a/arch/powerpc/platforms/85xx/corenet_generic.c
+++ b/arch/powerpc/platforms/85xx/corenet_generic.c
@@ -26,11 +26,13 @@
#include <asm/udbg.h>
#include <asm/mpic.h>
#include <asm/ehv_pic.h>
+#include <asm/qe_ic.h>
#include <linux/of_platform.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
#include "smp.h"
+#include "mpc85xx.h"
void __init corenet_gen_pic_init(void)
{
@@ -38,6 +40,8 @@ void __init corenet_gen_pic_init(void)
unsigned int flags = MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU |
MPIC_NO_RESET;
+ struct device_node *np;
+
if (ppc_md.get_irq == mpic_get_coreint_irq)
flags |= MPIC_ENABLE_COREINT;
@@ -45,6 +49,13 @@ void __init corenet_gen_pic_init(void)
BUG_ON(mpic == NULL);
mpic_init(mpic);
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
+ if (np) {
+ qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
+ qe_ic_cascade_high_mpic);
+ of_node_put(np);
+ }
}
/*
@@ -57,6 +68,8 @@ void __init corenet_gen_setup_arch(void)
swiotlb_detect_4g();
pr_info("%s board from Freescale Semiconductor\n", ppc_md.name);
+
+ mpc85xx_qe_init();
}
static const struct of_device_id of_device_ids[] = {
@@ -81,6 +94,9 @@ static const struct of_device_id of_device_ids[] = {
{
.compatible = "fsl,qoriq-pcie-v3.0",
},
+ {
+ .compatible = "fsl,qe",
+ },
/* The following two are for the Freescale hypervisor */
{
.name = "hypervisor",
@@ -163,6 +179,7 @@ define_machine(corenet_generic) {
.init_IRQ = corenet_gen_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_coreint_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/85xx/ge_imp3a.c b/arch/powerpc/platforms/85xx/ge_imp3a.c
index e6285ae6f423..11790e074c8a 100644
--- a/arch/powerpc/platforms/85xx/ge_imp3a.c
+++ b/arch/powerpc/platforms/85xx/ge_imp3a.c
@@ -215,6 +215,7 @@ define_machine(ge_imp3a) {
.show_cpuinfo = ge_imp3a_show_cpuinfo,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/85xx/mpc8536_ds.c b/arch/powerpc/platforms/85xx/mpc8536_ds.c
index 15ce4b55f117..a378ba3519e9 100644
--- a/arch/powerpc/platforms/85xx/mpc8536_ds.c
+++ b/arch/powerpc/platforms/85xx/mpc8536_ds.c
@@ -76,6 +76,7 @@ define_machine(mpc8536_ds) {
.init_IRQ = mpc8536_ds_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/85xx/mpc85xx.h b/arch/powerpc/platforms/85xx/mpc85xx.h
index fc51dd4092e5..39056f6befeb 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx.h
+++ b/arch/powerpc/platforms/85xx/mpc85xx.h
@@ -10,8 +10,10 @@ static inline void __init mpc85xx_cpm2_pic_init(void) {}
#ifdef CONFIG_QUICC_ENGINE
extern void mpc85xx_qe_init(void);
+extern void mpc85xx_qe_par_io_init(void);
#else
static inline void __init mpc85xx_qe_init(void) {}
+static inline void __init mpc85xx_qe_par_io_init(void) {}
#endif
#endif
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
index 7a31a0e1df29..b0753e222086 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
@@ -385,6 +385,7 @@ define_machine(mpc85xx_cds) {
#ifdef CONFIG_PCI
.restart = mpc85xx_cds_restart,
.pcibios_fixup_bus = mpc85xx_cds_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#else
.restart = fsl_rstcr_restart,
#endif
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
index 9ebb91ed96a3..ffdf02121a7c 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
@@ -209,6 +209,7 @@ define_machine(mpc8544_ds) {
.init_IRQ = mpc85xx_ds_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -223,6 +224,7 @@ define_machine(mpc8572_ds) {
.init_IRQ = mpc85xx_ds_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -237,6 +239,7 @@ define_machine(p2020_ds) {
.init_IRQ = mpc85xx_ds_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index 34f3c5eb3bee..a392e94a07fa 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -239,6 +239,7 @@ static void __init mpc85xx_mds_qe_init(void)
struct device_node *np;
mpc85xx_qe_init();
+ mpc85xx_qe_par_io_init();
mpc85xx_mds_reset_ucc_phys();
if (machine_is(p1021_mds)) {
@@ -391,6 +392,7 @@ define_machine(mpc8568_mds) {
.progress = udbg_progress,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
};
@@ -412,6 +414,7 @@ define_machine(mpc8569_mds) {
.progress = udbg_progress,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
};
@@ -434,6 +437,7 @@ define_machine(p1021_mds) {
.progress = udbg_progress,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
};
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
index e15bdd18fdb2..e358bed66d01 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
@@ -86,10 +86,6 @@ void __init mpc85xx_rdb_pic_init(void)
*/
static void __init mpc85xx_rdb_setup_arch(void)
{
-#ifdef CONFIG_QUICC_ENGINE
- struct device_node *np;
-#endif
-
if (ppc_md.progress)
ppc_md.progress("mpc85xx_rdb_setup_arch()", 0);
@@ -99,8 +95,10 @@ static void __init mpc85xx_rdb_setup_arch(void)
#ifdef CONFIG_QUICC_ENGINE
mpc85xx_qe_init();
+ mpc85xx_qe_par_io_init();
#if defined(CONFIG_UCC_GETH) || defined(CONFIG_SERIAL_QE)
if (machine_is(p1025_rdb)) {
+ struct device_node *np;
struct ccsr_guts __iomem *guts;
@@ -233,6 +231,7 @@ define_machine(p2020_rdb) {
.init_IRQ = mpc85xx_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -247,6 +246,7 @@ define_machine(p1020_rdb) {
.init_IRQ = mpc85xx_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -261,6 +261,7 @@ define_machine(p1021_rdb_pc) {
.init_IRQ = mpc85xx_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -275,6 +276,7 @@ define_machine(p2020_rdb_pc) {
.init_IRQ = mpc85xx_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -289,6 +291,7 @@ define_machine(p1025_rdb) {
.init_IRQ = mpc85xx_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -303,6 +306,7 @@ define_machine(p1020_mbg_pc) {
.init_IRQ = mpc85xx_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -317,6 +321,7 @@ define_machine(p1020_utm_pc) {
.init_IRQ = mpc85xx_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -331,6 +336,7 @@ define_machine(p1020_rdb_pc) {
.init_IRQ = mpc85xx_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -345,6 +351,7 @@ define_machine(p1020_rdb_pd) {
.init_IRQ = mpc85xx_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -359,6 +366,7 @@ define_machine(p1024_rdb) {
.init_IRQ = mpc85xx_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/85xx/p1010rdb.c b/arch/powerpc/platforms/85xx/p1010rdb.c
index d6a3dd311494..ad1a3d438a9e 100644
--- a/arch/powerpc/platforms/85xx/p1010rdb.c
+++ b/arch/powerpc/platforms/85xx/p1010rdb.c
@@ -78,6 +78,7 @@ define_machine(p1010_rdb) {
.init_IRQ = p1010_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c
index e611e79f23ce..6ac986d3f8a3 100644
--- a/arch/powerpc/platforms/85xx/p1022_ds.c
+++ b/arch/powerpc/platforms/85xx/p1022_ds.c
@@ -567,6 +567,7 @@ define_machine(p1022_ds) {
.init_IRQ = p1022_ds_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/85xx/p1022_rdk.c b/arch/powerpc/platforms/85xx/p1022_rdk.c
index 8c9297112b30..7a180f0308d5 100644
--- a/arch/powerpc/platforms/85xx/p1022_rdk.c
+++ b/arch/powerpc/platforms/85xx/p1022_rdk.c
@@ -147,6 +147,7 @@ define_machine(p1022_rdk) {
.init_IRQ = p1022_rdk_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/85xx/p1023_rds.c b/arch/powerpc/platforms/85xx/p1023_rds.c
index 2ae9d490c3d9..0e614007acfb 100644
--- a/arch/powerpc/platforms/85xx/p1023_rds.c
+++ b/arch/powerpc/platforms/85xx/p1023_rds.c
@@ -126,6 +126,7 @@ define_machine(p1023_rds) {
.progress = udbg_progress,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
};
@@ -140,5 +141,6 @@ define_machine(p1023_rdb) {
.progress = udbg_progress,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
};
diff --git a/arch/powerpc/platforms/85xx/qemu_e500.c b/arch/powerpc/platforms/85xx/qemu_e500.c
index 5cefc5a9a144..7f2673293549 100644
--- a/arch/powerpc/platforms/85xx/qemu_e500.c
+++ b/arch/powerpc/platforms/85xx/qemu_e500.c
@@ -66,6 +66,7 @@ define_machine(qemu_e500) {
.init_IRQ = qemu_e500_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_coreint_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/85xx/sbc8548.c b/arch/powerpc/platforms/85xx/sbc8548.c
index f62121825914..b07214666d65 100644
--- a/arch/powerpc/platforms/85xx/sbc8548.c
+++ b/arch/powerpc/platforms/85xx/sbc8548.c
@@ -135,6 +135,7 @@ define_machine(sbc8548) {
.restart = fsl_rstcr_restart,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.calibrate_decr = generic_calibrate_decr,
.progress = udbg_progress,
diff --git a/arch/powerpc/platforms/85xx/twr_p102x.c b/arch/powerpc/platforms/85xx/twr_p102x.c
index c25ff10f05ee..1eadb6d0dc64 100644
--- a/arch/powerpc/platforms/85xx/twr_p102x.c
+++ b/arch/powerpc/platforms/85xx/twr_p102x.c
@@ -77,6 +77,7 @@ static void __init twr_p1025_setup_arch(void)
#ifdef CONFIG_QUICC_ENGINE
mpc85xx_qe_init();
+ mpc85xx_qe_par_io_init();
#if defined(CONFIG_UCC_GETH) || defined(CONFIG_SERIAL_QE)
if (machine_is(twr_p1025)) {
diff --git a/arch/powerpc/platforms/85xx/xes_mpc85xx.c b/arch/powerpc/platforms/85xx/xes_mpc85xx.c
index dcbf7e42dce7..1a9c1085855f 100644
--- a/arch/powerpc/platforms/85xx/xes_mpc85xx.c
+++ b/arch/powerpc/platforms/85xx/xes_mpc85xx.c
@@ -170,6 +170,7 @@ define_machine(xes_mpc8572) {
.init_IRQ = xes_mpc85xx_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -184,6 +185,7 @@ define_machine(xes_mpc8548) {
.init_IRQ = xes_mpc85xx_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -198,6 +200,7 @@ define_machine(xes_mpc8540) {
.init_IRQ = xes_mpc85xx_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 2d42f3bb66d6..8a106b4172e0 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -215,7 +215,7 @@ void iic_request_IPIs(void)
{
iic_request_ipi(PPC_MSG_CALL_FUNCTION);
iic_request_ipi(PPC_MSG_RESCHEDULE);
- iic_request_ipi(PPC_MSG_CALL_FUNC_SINGLE);
+ iic_request_ipi(PPC_MSG_TICK_BROADCAST);
iic_request_ipi(PPC_MSG_DEBUGGER_BREAK);
}
diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c
index 5ec1e47a0d77..e865d748179b 100644
--- a/arch/powerpc/platforms/cell/ras.c
+++ b/arch/powerpc/platforms/cell/ras.c
@@ -123,7 +123,8 @@ static int __init cbe_ptcal_enable_on_node(int nid, int order)
area->nid = nid;
area->order = order;
- area->pages = alloc_pages_exact_node(area->nid, GFP_KERNEL|GFP_THISNODE,
+ area->pages = alloc_pages_exact_node(area->nid,
+ GFP_KERNEL|__GFP_THISNODE,
area->order);
if (!area->pages) {
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 49318385d4fa..4a0a64fe25df 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -83,7 +83,6 @@ static struct timer_list spuloadavg_timer;
#define MIN_SPU_TIMESLICE max(5 * HZ / (1000 * SPUSCHED_TICK), 1)
#define DEF_SPU_TIMESLICE (100 * HZ / (1000 * SPUSCHED_TICK))
-#define MAX_USER_PRIO (MAX_PRIO - MAX_RT_PRIO)
#define SCALE_PRIO(x, prio) \
max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_SPU_TIMESLICE)
diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig
index 6d3c7a9fd047..2a7024d8d8b1 100644
--- a/arch/powerpc/platforms/embedded6xx/Kconfig
+++ b/arch/powerpc/platforms/embedded6xx/Kconfig
@@ -34,7 +34,6 @@ config MPC7448HPC2
select TSI108_BRIDGE
select DEFAULT_UIMAGE
select PPC_UDBG_16550
- select TSI108_BRIDGE
help
Select MPC7448HPC2 if configuring for Freescale MPC7448HPC2 (Taiga)
platform
@@ -44,19 +43,10 @@ config PPC_HOLLY
depends on EMBEDDED6xx
select TSI108_BRIDGE
select PPC_UDBG_16550
- select TSI108_BRIDGE
help
Select PPC_HOLLY if configuring for an IBM 750GX/CL Eval
Board with TSI108/9 bridge (Hickory/Holly)
-config PPC_PRPMC2800
- bool "Motorola-PrPMC2800"
- depends on EMBEDDED6xx
- select MV64X60
- select NOT_COHERENT_CACHE
- help
- This option enables support for the Motorola PrPMC2800 board
-
config PPC_C2K
bool "SBS/GEFanuc C2K board"
depends on EMBEDDED6xx
diff --git a/arch/powerpc/platforms/embedded6xx/Makefile b/arch/powerpc/platforms/embedded6xx/Makefile
index cdd48d402b93..f126a2a09981 100644
--- a/arch/powerpc/platforms/embedded6xx/Makefile
+++ b/arch/powerpc/platforms/embedded6xx/Makefile
@@ -5,7 +5,6 @@ obj-$(CONFIG_MPC7448HPC2) += mpc7448_hpc2.o
obj-$(CONFIG_LINKSTATION) += linkstation.o ls_uart.o
obj-$(CONFIG_STORCENTER) += storcenter.o
obj-$(CONFIG_PPC_HOLLY) += holly.o
-obj-$(CONFIG_PPC_PRPMC2800) += prpmc2800.o
obj-$(CONFIG_PPC_C2K) += c2k.o
obj-$(CONFIG_USBGECKO_UDBG) += usbgecko_udbg.o
obj-$(CONFIG_GAMECUBE_COMMON) += flipper-pic.o
diff --git a/arch/powerpc/platforms/embedded6xx/prpmc2800.c b/arch/powerpc/platforms/embedded6xx/prpmc2800.c
deleted file mode 100644
index d455f08bea53..000000000000
--- a/arch/powerpc/platforms/embedded6xx/prpmc2800.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Board setup routines for the Motorola PrPMC2800
- *
- * Author: Dale Farnsworth <dale@farnsworth.org>
- *
- * 2007 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/seq_file.h>
-
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/time.h>
-
-#include <mm/mmu_decl.h>
-
-#include <sysdev/mv64x60.h>
-
-#define MV64x60_MPP_CNTL_0 0x0000
-#define MV64x60_MPP_CNTL_2 0x0008
-
-#define MV64x60_GPP_IO_CNTL 0x0000
-#define MV64x60_GPP_LEVEL_CNTL 0x0010
-#define MV64x60_GPP_VALUE_SET 0x0018
-
-#define PLATFORM_NAME_MAX 32
-
-static char prpmc2800_platform_name[PLATFORM_NAME_MAX];
-
-static void __iomem *mv64x60_mpp_reg_base;
-static void __iomem *mv64x60_gpp_reg_base;
-
-static void __init prpmc2800_setup_arch(void)
-{
- struct device_node *np;
- phys_addr_t paddr;
- const unsigned int *reg;
-
- /*
- * ioremap mpp and gpp registers in case they are later
- * needed by prpmc2800_reset_board().
- */
- np = of_find_compatible_node(NULL, NULL, "marvell,mv64360-mpp");
- reg = of_get_property(np, "reg", NULL);
- paddr = of_translate_address(np, reg);
- of_node_put(np);
- mv64x60_mpp_reg_base = ioremap(paddr, reg[1]);
-
- np = of_find_compatible_node(NULL, NULL, "marvell,mv64360-gpp");
- reg = of_get_property(np, "reg", NULL);
- paddr = of_translate_address(np, reg);
- of_node_put(np);
- mv64x60_gpp_reg_base = ioremap(paddr, reg[1]);
-
-#ifdef CONFIG_PCI
- mv64x60_pci_init();
-#endif
-
- printk("Motorola %s\n", prpmc2800_platform_name);
-}
-
-static void prpmc2800_reset_board(void)
-{
- u32 temp;
-
- local_irq_disable();
-
- temp = in_le32(mv64x60_mpp_reg_base + MV64x60_MPP_CNTL_0);
- temp &= 0xFFFF0FFF;
- out_le32(mv64x60_mpp_reg_base + MV64x60_MPP_CNTL_0, temp);
-
- temp = in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_LEVEL_CNTL);
- temp |= 0x00000004;
- out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_LEVEL_CNTL, temp);
-
- temp = in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_IO_CNTL);
- temp |= 0x00000004;
- out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_IO_CNTL, temp);
-
- temp = in_le32(mv64x60_mpp_reg_base + MV64x60_MPP_CNTL_2);
- temp &= 0xFFFF0FFF;
- out_le32(mv64x60_mpp_reg_base + MV64x60_MPP_CNTL_2, temp);
-
- temp = in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_LEVEL_CNTL);
- temp |= 0x00080000;
- out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_LEVEL_CNTL, temp);
-
- temp = in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_IO_CNTL);
- temp |= 0x00080000;
- out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_IO_CNTL, temp);
-
- out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_VALUE_SET, 0x00080004);
-}
-
-static void prpmc2800_restart(char *cmd)
-{
- volatile ulong i = 10000000;
-
- prpmc2800_reset_board();
-
- while (i-- > 0);
- panic("restart failed\n");
-}
-
-#ifdef CONFIG_NOT_COHERENT_CACHE
-#define PPRPM2800_COHERENCY_SETTING "off"
-#else
-#define PPRPM2800_COHERENCY_SETTING "on"
-#endif
-
-void prpmc2800_show_cpuinfo(struct seq_file *m)
-{
- seq_printf(m, "Vendor\t\t: Motorola\n");
- seq_printf(m, "coherency\t: %s\n", PPRPM2800_COHERENCY_SETTING);
-}
-
-/*
- * Called very early, device-tree isn't unflattened
- */
-static int __init prpmc2800_probe(void)
-{
- unsigned long root = of_get_flat_dt_root();
- unsigned long len = PLATFORM_NAME_MAX;
- void *m;
-
- if (!of_flat_dt_is_compatible(root, "motorola,PrPMC2800"))
- return 0;
-
- /* Update ppc_md.name with name from dt */
- m = of_get_flat_dt_prop(root, "model", &len);
- if (m)
- strncpy(prpmc2800_platform_name, m,
- min((int)len, PLATFORM_NAME_MAX - 1));
-
- _set_L2CR(_get_L2CR() | L2CR_L2E);
- return 1;
-}
-
-define_machine(prpmc2800){
- .name = prpmc2800_platform_name,
- .probe = prpmc2800_probe,
- .setup_arch = prpmc2800_setup_arch,
- .init_early = mv64x60_init_early,
- .show_cpuinfo = prpmc2800_show_cpuinfo,
- .init_IRQ = mv64x60_init_irq,
- .get_irq = mv64x60_get_irq,
- .restart = prpmc2800_restart,
- .calibrate_decr = generic_calibrate_decr,
-};
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index 8d767fde5a6a..f324ea099503 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -1,6 +1,6 @@
-obj-y += setup.o opal-takeover.o opal-wrappers.o opal.o
+obj-y += setup.o opal-takeover.o opal-wrappers.o opal.o opal-async.o
obj-y += opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
-obj-y += rng.o
+obj-y += rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o
diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c
index e1e71618b70c..253fefe3d1a0 100644
--- a/arch/powerpc/platforms/powernv/eeh-ioda.c
+++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
@@ -44,7 +44,8 @@ static int ioda_eeh_event(struct notifier_block *nb,
/* We simply send special EEH event */
if ((changed_evts & OPAL_EVENT_PCI_ERROR) &&
- (events & OPAL_EVENT_PCI_ERROR))
+ (events & OPAL_EVENT_PCI_ERROR) &&
+ eeh_enabled())
eeh_send_failure_event(NULL);
return 0;
@@ -113,6 +114,7 @@ DEFINE_SIMPLE_ATTRIBUTE(ioda_eeh_inbB_dbgfs_ops, ioda_eeh_inbB_dbgfs_get,
ioda_eeh_inbB_dbgfs_set, "0x%llx\n");
#endif /* CONFIG_DEBUG_FS */
+
/**
* ioda_eeh_post_init - Chip dependent post initialization
* @hose: PCI controller
@@ -220,6 +222,22 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
return ret;
}
+static void ioda_eeh_phb_diag(struct pci_controller *hose)
+{
+ struct pnv_phb *phb = hose->private_data;
+ long rc;
+
+ rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob,
+ PNV_PCI_DIAG_BUF_SIZE);
+ if (rc != OPAL_SUCCESS) {
+ pr_warning("%s: Failed to get diag-data for PHB#%x (%ld)\n",
+ __func__, hose->global_number, rc);
+ return;
+ }
+
+ pnv_pci_dump_phb_diag_data(hose, phb->diag.blob);
+}
+
/**
* ioda_eeh_get_state - Retrieve the state of PE
* @pe: EEH PE
@@ -271,6 +289,9 @@ static int ioda_eeh_get_state(struct eeh_pe *pe)
result |= EEH_STATE_DMA_ACTIVE;
result |= EEH_STATE_MMIO_ENABLED;
result |= EEH_STATE_DMA_ENABLED;
+ } else if (!(pe->state & EEH_PE_ISOLATED)) {
+ eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
+ ioda_eeh_phb_diag(hose);
}
return result;
@@ -314,6 +335,15 @@ static int ioda_eeh_get_state(struct eeh_pe *pe)
__func__, fstate, hose->global_number, pe_no);
}
+ /* Dump PHB diag-data for frozen PE */
+ if (result != EEH_STATE_NOT_SUPPORT &&
+ (result & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) !=
+ (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE) &&
+ !(pe->state & EEH_PE_ISOLATED)) {
+ eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
+ ioda_eeh_phb_diag(hose);
+ }
+
return result;
}
@@ -489,8 +519,7 @@ static int ioda_eeh_bridge_reset(struct pci_controller *hose,
static int ioda_eeh_reset(struct eeh_pe *pe, int option)
{
struct pci_controller *hose = pe->phb;
- struct eeh_dev *edev;
- struct pci_dev *dev;
+ struct pci_bus *bus;
int ret;
/*
@@ -519,73 +548,17 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option)
if (pe->type & EEH_PE_PHB) {
ret = ioda_eeh_phb_reset(hose, option);
} else {
- if (pe->type & EEH_PE_DEVICE) {
- /*
- * If it's device PE, we didn't refer to the parent
- * PCI bus yet. So we have to figure it out indirectly.
- */
- edev = list_first_entry(&pe->edevs,
- struct eeh_dev, list);
- dev = eeh_dev_to_pci_dev(edev);
- dev = dev->bus->self;
- } else {
- /*
- * If it's bus PE, the parent PCI bus is already there
- * and just pick it up.
- */
- dev = pe->bus->self;
- }
-
- /*
- * Do reset based on the fact that the direct upstream bridge
- * is root bridge (port) or not.
- */
- if (dev->bus->number == 0)
+ bus = eeh_pe_bus_get(pe);
+ if (pci_is_root_bus(bus))
ret = ioda_eeh_root_reset(hose, option);
else
- ret = ioda_eeh_bridge_reset(hose, dev, option);
+ ret = ioda_eeh_bridge_reset(hose, bus->self, option);
}
return ret;
}
/**
- * ioda_eeh_get_log - Retrieve error log
- * @pe: EEH PE
- * @severity: Severity level of the log
- * @drv_log: buffer to store the log
- * @len: space of the log buffer
- *
- * The function is used to retrieve error log from P7IOC.
- */
-static int ioda_eeh_get_log(struct eeh_pe *pe, int severity,
- char *drv_log, unsigned long len)
-{
- s64 ret;
- unsigned long flags;
- struct pci_controller *hose = pe->phb;
- struct pnv_phb *phb = hose->private_data;
-
- spin_lock_irqsave(&phb->lock, flags);
-
- ret = opal_pci_get_phb_diag_data2(phb->opal_id,
- phb->diag.blob, PNV_PCI_DIAG_BUF_SIZE);
- if (ret) {
- spin_unlock_irqrestore(&phb->lock, flags);
- pr_warning("%s: Can't get log for PHB#%x-PE#%x (%lld)\n",
- __func__, hose->global_number, pe->addr, ret);
- return -EIO;
- }
-
- /* The PHB diag-data is always indicative */
- pnv_pci_dump_phb_diag_data(hose, phb->diag.blob);
-
- spin_unlock_irqrestore(&phb->lock, flags);
-
- return 0;
-}
-
-/**
* ioda_eeh_configure_bridge - Configure the PCI bridges for the indicated PE
* @pe: EEH PE
*
@@ -666,22 +639,6 @@ static void ioda_eeh_hub_diag(struct pci_controller *hose)
}
}
-static void ioda_eeh_phb_diag(struct pci_controller *hose)
-{
- struct pnv_phb *phb = hose->private_data;
- long rc;
-
- rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob,
- PNV_PCI_DIAG_BUF_SIZE);
- if (rc != OPAL_SUCCESS) {
- pr_warning("%s: Failed to get diag-data for PHB#%x (%ld)\n",
- __func__, hose->global_number, rc);
- return;
- }
-
- pnv_pci_dump_phb_diag_data(hose, phb->diag.blob);
-}
-
static int ioda_eeh_get_phb_pe(struct pci_controller *hose,
struct eeh_pe **pe)
{
@@ -855,6 +812,20 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
}
/*
+ * EEH core will try recover from fenced PHB or
+ * frozen PE. In the time for frozen PE, EEH core
+ * enable IO path for that before collecting logs,
+ * but it ruins the site. So we have to dump the
+ * log in advance here.
+ */
+ if ((ret == EEH_NEXT_ERR_FROZEN_PE ||
+ ret == EEH_NEXT_ERR_FENCED_PHB) &&
+ !((*pe)->state & EEH_PE_ISOLATED)) {
+ eeh_pe_state_mark(*pe, EEH_PE_ISOLATED);
+ ioda_eeh_phb_diag(hose);
+ }
+
+ /*
* If we have no errors on the specific PHB or only
* informative error there, we continue poking it.
* Otherwise, we need actions to be taken by upper
@@ -872,7 +843,6 @@ struct pnv_eeh_ops ioda_eeh_ops = {
.set_option = ioda_eeh_set_option,
.get_state = ioda_eeh_get_state,
.reset = ioda_eeh_reset,
- .get_log = ioda_eeh_get_log,
.configure_bridge = ioda_eeh_configure_bridge,
.next_error = ioda_eeh_next_error
};
diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c
index a79fddc5e74e..a59788e83b8b 100644
--- a/arch/powerpc/platforms/powernv/eeh-powernv.c
+++ b/arch/powerpc/platforms/powernv/eeh-powernv.c
@@ -145,7 +145,7 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag)
* Enable EEH explicitly so that we will do EEH check
* while accessing I/O stuff
*/
- eeh_subsystem_enabled = 1;
+ eeh_set_enable(true);
/* Save memory bars */
eeh_save_bars(edev);
diff --git a/arch/powerpc/platforms/powernv/opal-async.c b/arch/powerpc/platforms/powernv/opal-async.c
new file mode 100644
index 000000000000..cd0c1354d404
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-async.c
@@ -0,0 +1,203 @@
+/*
+ * PowerNV OPAL asynchronous completion interfaces
+ *
+ * Copyright 2013 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/gfp.h>
+#include <linux/of.h>
+#include <asm/opal.h>
+
+#define N_ASYNC_COMPLETIONS 64
+
+static DECLARE_BITMAP(opal_async_complete_map, N_ASYNC_COMPLETIONS) = {~0UL};
+static DECLARE_BITMAP(opal_async_token_map, N_ASYNC_COMPLETIONS);
+static DECLARE_WAIT_QUEUE_HEAD(opal_async_wait);
+static DEFINE_SPINLOCK(opal_async_comp_lock);
+static struct semaphore opal_async_sem;
+static struct opal_msg *opal_async_responses;
+static unsigned int opal_max_async_tokens;
+
+int __opal_async_get_token(void)
+{
+ unsigned long flags;
+ int token;
+
+ spin_lock_irqsave(&opal_async_comp_lock, flags);
+ token = find_first_bit(opal_async_complete_map, opal_max_async_tokens);
+ if (token >= opal_max_async_tokens) {
+ token = -EBUSY;
+ goto out;
+ }
+
+ if (__test_and_set_bit(token, opal_async_token_map)) {
+ token = -EBUSY;
+ goto out;
+ }
+
+ __clear_bit(token, opal_async_complete_map);
+
+out:
+ spin_unlock_irqrestore(&opal_async_comp_lock, flags);
+ return token;
+}
+
+int opal_async_get_token_interruptible(void)
+{
+ int token;
+
+ /* Wait until a token is available */
+ if (down_interruptible(&opal_async_sem))
+ return -ERESTARTSYS;
+
+ token = __opal_async_get_token();
+ if (token < 0)
+ up(&opal_async_sem);
+
+ return token;
+}
+
+int __opal_async_release_token(int token)
+{
+ unsigned long flags;
+
+ if (token < 0 || token >= opal_max_async_tokens) {
+ pr_err("%s: Passed token is out of range, token %d\n",
+ __func__, token);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&opal_async_comp_lock, flags);
+ __set_bit(token, opal_async_complete_map);
+ __clear_bit(token, opal_async_token_map);
+ spin_unlock_irqrestore(&opal_async_comp_lock, flags);
+
+ return 0;
+}
+
+int opal_async_release_token(int token)
+{
+ int ret;
+
+ ret = __opal_async_release_token(token);
+ if (ret)
+ return ret;
+
+ up(&opal_async_sem);
+
+ return 0;
+}
+
+int opal_async_wait_response(uint64_t token, struct opal_msg *msg)
+{
+ if (token >= opal_max_async_tokens) {
+ pr_err("%s: Invalid token passed\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!msg) {
+ pr_err("%s: Invalid message pointer passed\n", __func__);
+ return -EINVAL;
+ }
+
+ wait_event(opal_async_wait, test_bit(token, opal_async_complete_map));
+ memcpy(msg, &opal_async_responses[token], sizeof(*msg));
+
+ return 0;
+}
+
+static int opal_async_comp_event(struct notifier_block *nb,
+ unsigned long msg_type, void *msg)
+{
+ struct opal_msg *comp_msg = msg;
+ unsigned long flags;
+
+ if (msg_type != OPAL_MSG_ASYNC_COMP)
+ return 0;
+
+ memcpy(&opal_async_responses[comp_msg->params[0]], comp_msg,
+ sizeof(*comp_msg));
+ spin_lock_irqsave(&opal_async_comp_lock, flags);
+ __set_bit(comp_msg->params[0], opal_async_complete_map);
+ spin_unlock_irqrestore(&opal_async_comp_lock, flags);
+
+ wake_up(&opal_async_wait);
+
+ return 0;
+}
+
+static struct notifier_block opal_async_comp_nb = {
+ .notifier_call = opal_async_comp_event,
+ .next = NULL,
+ .priority = 0,
+};
+
+static int __init opal_async_comp_init(void)
+{
+ struct device_node *opal_node;
+ const __be32 *async;
+ int err;
+
+ opal_node = of_find_node_by_path("/ibm,opal");
+ if (!opal_node) {
+ pr_err("%s: Opal node not found\n", __func__);
+ err = -ENOENT;
+ goto out;
+ }
+
+ async = of_get_property(opal_node, "opal-msg-async-num", NULL);
+ if (!async) {
+ pr_err("%s: %s has no opal-msg-async-num\n",
+ __func__, opal_node->full_name);
+ err = -ENOENT;
+ goto out_opal_node;
+ }
+
+ opal_max_async_tokens = be32_to_cpup(async);
+ if (opal_max_async_tokens > N_ASYNC_COMPLETIONS)
+ opal_max_async_tokens = N_ASYNC_COMPLETIONS;
+
+ err = opal_message_notifier_register(OPAL_MSG_ASYNC_COMP,
+ &opal_async_comp_nb);
+ if (err) {
+ pr_err("%s: Can't register OPAL event notifier (%d)\n",
+ __func__, err);
+ goto out_opal_node;
+ }
+
+ opal_async_responses = kzalloc(
+ sizeof(*opal_async_responses) * opal_max_async_tokens,
+ GFP_KERNEL);
+ if (!opal_async_responses) {
+ pr_err("%s: Out of memory, failed to do asynchronous "
+ "completion init\n", __func__);
+ err = -ENOMEM;
+ goto out_opal_node;
+ }
+
+ /* Initialize to 1 less than the maximum tokens available, as we may
+ * require to pop one during emergency through synchronous call to
+ * __opal_async_get_token()
+ */
+ sema_init(&opal_async_sem, opal_max_async_tokens - 1);
+
+out_opal_node:
+ of_node_put(opal_node);
+out:
+ return err;
+}
+subsys_initcall(opal_async_comp_init);
diff --git a/arch/powerpc/platforms/powernv/opal-dump.c b/arch/powerpc/platforms/powernv/opal-dump.c
new file mode 100644
index 000000000000..0c767c561dc9
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-dump.c
@@ -0,0 +1,525 @@
+/*
+ * PowerNV OPAL Dump Interface
+ *
+ * Copyright 2013,2014 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kobject.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/delay.h>
+
+#include <asm/opal.h>
+
+#define DUMP_TYPE_FSP 0x01
+
+struct dump_obj {
+ struct kobject kobj;
+ struct bin_attribute dump_attr;
+ uint32_t id; /* becomes object name */
+ uint32_t type;
+ uint32_t size;
+ char *buffer;
+};
+#define to_dump_obj(x) container_of(x, struct dump_obj, kobj)
+
+struct dump_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct dump_obj *dump, struct dump_attribute *attr,
+ char *buf);
+ ssize_t (*store)(struct dump_obj *dump, struct dump_attribute *attr,
+ const char *buf, size_t count);
+};
+#define to_dump_attr(x) container_of(x, struct dump_attribute, attr)
+
+static ssize_t dump_id_show(struct dump_obj *dump_obj,
+ struct dump_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "0x%x\n", dump_obj->id);
+}
+
+static const char* dump_type_to_string(uint32_t type)
+{
+ switch (type) {
+ case 0x01: return "SP Dump";
+ case 0x02: return "System/Platform Dump";
+ case 0x03: return "SMA Dump";
+ default: return "unknown";
+ }
+}
+
+static ssize_t dump_type_show(struct dump_obj *dump_obj,
+ struct dump_attribute *attr,
+ char *buf)
+{
+
+ return sprintf(buf, "0x%x %s\n", dump_obj->type,
+ dump_type_to_string(dump_obj->type));
+}
+
+static ssize_t dump_ack_show(struct dump_obj *dump_obj,
+ struct dump_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "ack - acknowledge dump\n");
+}
+
+/*
+ * Send acknowledgement to OPAL
+ */
+static int64_t dump_send_ack(uint32_t dump_id)
+{
+ int rc;
+
+ rc = opal_dump_ack(dump_id);
+ if (rc)
+ pr_warn("%s: Failed to send ack to Dump ID 0x%x (%d)\n",
+ __func__, dump_id, rc);
+ return rc;
+}
+
+static void delay_release_kobj(void *kobj)
+{
+ kobject_put((struct kobject *)kobj);
+}
+
+static ssize_t dump_ack_store(struct dump_obj *dump_obj,
+ struct dump_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ dump_send_ack(dump_obj->id);
+ sysfs_schedule_callback(&dump_obj->kobj, delay_release_kobj,
+ &dump_obj->kobj, THIS_MODULE);
+ return count;
+}
+
+/* Attributes of a dump
+ * The binary attribute of the dump itself is dynamic
+ * due to the dynamic size of the dump
+ */
+static struct dump_attribute id_attribute =
+ __ATTR(id, 0666, dump_id_show, NULL);
+static struct dump_attribute type_attribute =
+ __ATTR(type, 0666, dump_type_show, NULL);
+static struct dump_attribute ack_attribute =
+ __ATTR(acknowledge, 0660, dump_ack_show, dump_ack_store);
+
+static ssize_t init_dump_show(struct dump_obj *dump_obj,
+ struct dump_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "1 - initiate dump\n");
+}
+
+static int64_t dump_fips_init(uint8_t type)
+{
+ int rc;
+
+ rc = opal_dump_init(type);
+ if (rc)
+ pr_warn("%s: Failed to initiate FipS dump (%d)\n",
+ __func__, rc);
+ return rc;
+}
+
+static ssize_t init_dump_store(struct dump_obj *dump_obj,
+ struct dump_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ dump_fips_init(DUMP_TYPE_FSP);
+ pr_info("%s: Initiated FSP dump\n", __func__);
+ return count;
+}
+
+static struct dump_attribute initiate_attribute =
+ __ATTR(initiate_dump, 0600, init_dump_show, init_dump_store);
+
+static struct attribute *initiate_attrs[] = {
+ &initiate_attribute.attr,
+ NULL,
+};
+
+static struct attribute_group initiate_attr_group = {
+ .attrs = initiate_attrs,
+};
+
+static struct kset *dump_kset;
+
+static ssize_t dump_attr_show(struct kobject *kobj,
+ struct attribute *attr,
+ char *buf)
+{
+ struct dump_attribute *attribute;
+ struct dump_obj *dump;
+
+ attribute = to_dump_attr(attr);
+ dump = to_dump_obj(kobj);
+
+ if (!attribute->show)
+ return -EIO;
+
+ return attribute->show(dump, attribute, buf);
+}
+
+static ssize_t dump_attr_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buf, size_t len)
+{
+ struct dump_attribute *attribute;
+ struct dump_obj *dump;
+
+ attribute = to_dump_attr(attr);
+ dump = to_dump_obj(kobj);
+
+ if (!attribute->store)
+ return -EIO;
+
+ return attribute->store(dump, attribute, buf, len);
+}
+
+static const struct sysfs_ops dump_sysfs_ops = {
+ .show = dump_attr_show,
+ .store = dump_attr_store,
+};
+
+static void dump_release(struct kobject *kobj)
+{
+ struct dump_obj *dump;
+
+ dump = to_dump_obj(kobj);
+ vfree(dump->buffer);
+ kfree(dump);
+}
+
+static struct attribute *dump_default_attrs[] = {
+ &id_attribute.attr,
+ &type_attribute.attr,
+ &ack_attribute.attr,
+ NULL,
+};
+
+static struct kobj_type dump_ktype = {
+ .sysfs_ops = &dump_sysfs_ops,
+ .release = &dump_release,
+ .default_attrs = dump_default_attrs,
+};
+
+static void free_dump_sg_list(struct opal_sg_list *list)
+{
+ struct opal_sg_list *sg1;
+ while (list) {
+ sg1 = list->next;
+ kfree(list);
+ list = sg1;
+ }
+ list = NULL;
+}
+
+static struct opal_sg_list *dump_data_to_sglist(struct dump_obj *dump)
+{
+ struct opal_sg_list *sg1, *list = NULL;
+ void *addr;
+ int64_t size;
+
+ addr = dump->buffer;
+ size = dump->size;
+
+ sg1 = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!sg1)
+ goto nomem;
+
+ list = sg1;
+ sg1->num_entries = 0;
+ while (size > 0) {
+ /* Translate virtual address to physical address */
+ sg1->entry[sg1->num_entries].data =
+ (void *)(vmalloc_to_pfn(addr) << PAGE_SHIFT);
+
+ if (size > PAGE_SIZE)
+ sg1->entry[sg1->num_entries].length = PAGE_SIZE;
+ else
+ sg1->entry[sg1->num_entries].length = size;
+
+ sg1->num_entries++;
+ if (sg1->num_entries >= SG_ENTRIES_PER_NODE) {
+ sg1->next = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!sg1->next)
+ goto nomem;
+
+ sg1 = sg1->next;
+ sg1->num_entries = 0;
+ }
+ addr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ return list;
+
+nomem:
+ pr_err("%s : Failed to allocate memory\n", __func__);
+ free_dump_sg_list(list);
+ return NULL;
+}
+
+static void sglist_to_phy_addr(struct opal_sg_list *list)
+{
+ struct opal_sg_list *sg, *next;
+
+ for (sg = list; sg; sg = next) {
+ next = sg->next;
+ /* Don't translate NULL pointer for last entry */
+ if (sg->next)
+ sg->next = (struct opal_sg_list *)__pa(sg->next);
+ else
+ sg->next = NULL;
+
+ /* Convert num_entries to length */
+ sg->num_entries =
+ sg->num_entries * sizeof(struct opal_sg_entry) + 16;
+ }
+}
+
+static int64_t dump_read_info(uint32_t *id, uint32_t *size, uint32_t *type)
+{
+ int rc;
+ *type = 0xffffffff;
+
+ rc = opal_dump_info2(id, size, type);
+
+ if (rc == OPAL_PARAMETER)
+ rc = opal_dump_info(id, size);
+
+ if (rc)
+ pr_warn("%s: Failed to get dump info (%d)\n",
+ __func__, rc);
+ return rc;
+}
+
+static int64_t dump_read_data(struct dump_obj *dump)
+{
+ struct opal_sg_list *list;
+ uint64_t addr;
+ int64_t rc;
+
+ /* Allocate memory */
+ dump->buffer = vzalloc(PAGE_ALIGN(dump->size));
+ if (!dump->buffer) {
+ pr_err("%s : Failed to allocate memory\n", __func__);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ /* Generate SG list */
+ list = dump_data_to_sglist(dump);
+ if (!list) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ /* Translate sg list addr to real address */
+ sglist_to_phy_addr(list);
+
+ /* First entry address */
+ addr = __pa(list);
+
+ /* Fetch data */
+ rc = OPAL_BUSY_EVENT;
+ while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
+ rc = opal_dump_read(dump->id, addr);
+ if (rc == OPAL_BUSY_EVENT) {
+ opal_poll_events(NULL);
+ msleep(20);
+ }
+ }
+
+ if (rc != OPAL_SUCCESS && rc != OPAL_PARTIAL)
+ pr_warn("%s: Extract dump failed for ID 0x%x\n",
+ __func__, dump->id);
+
+ /* Free SG list */
+ free_dump_sg_list(list);
+
+out:
+ return rc;
+}
+
+static ssize_t dump_attr_read(struct file *filep, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t pos, size_t count)
+{
+ ssize_t rc;
+
+ struct dump_obj *dump = to_dump_obj(kobj);
+
+ if (!dump->buffer) {
+ rc = dump_read_data(dump);
+
+ if (rc != OPAL_SUCCESS && rc != OPAL_PARTIAL) {
+ vfree(dump->buffer);
+ dump->buffer = NULL;
+
+ return -EIO;
+ }
+ if (rc == OPAL_PARTIAL) {
+ /* On a partial read, we just return EIO
+ * and rely on userspace to ask us to try
+ * again.
+ */
+ pr_info("%s: Platform dump partially read.ID = 0x%x\n",
+ __func__, dump->id);
+ return -EIO;
+ }
+ }
+
+ memcpy(buffer, dump->buffer + pos, count);
+
+ /* You may think we could free the dump buffer now and retrieve
+ * it again later if needed, but due to current firmware limitation,
+ * that's not the case. So, once read into userspace once,
+ * we keep the dump around until it's acknowledged by userspace.
+ */
+
+ return count;
+}
+
+static struct dump_obj *create_dump_obj(uint32_t id, size_t size,
+ uint32_t type)
+{
+ struct dump_obj *dump;
+ int rc;
+
+ dump = kzalloc(sizeof(*dump), GFP_KERNEL);
+ if (!dump)
+ return NULL;
+
+ dump->kobj.kset = dump_kset;
+
+ kobject_init(&dump->kobj, &dump_ktype);
+
+ sysfs_bin_attr_init(&dump->dump_attr);
+
+ dump->dump_attr.attr.name = "dump";
+ dump->dump_attr.attr.mode = 0400;
+ dump->dump_attr.size = size;
+ dump->dump_attr.read = dump_attr_read;
+
+ dump->id = id;
+ dump->size = size;
+ dump->type = type;
+
+ rc = kobject_add(&dump->kobj, NULL, "0x%x-0x%x", type, id);
+ if (rc) {
+ kobject_put(&dump->kobj);
+ return NULL;
+ }
+
+ rc = sysfs_create_bin_file(&dump->kobj, &dump->dump_attr);
+ if (rc) {
+ kobject_put(&dump->kobj);
+ return NULL;
+ }
+
+ pr_info("%s: New platform dump. ID = 0x%x Size %u\n",
+ __func__, dump->id, dump->size);
+
+ kobject_uevent(&dump->kobj, KOBJ_ADD);
+
+ return dump;
+}
+
+static int process_dump(void)
+{
+ int rc;
+ uint32_t dump_id, dump_size, dump_type;
+ struct dump_obj *dump;
+ char name[22];
+
+ rc = dump_read_info(&dump_id, &dump_size, &dump_type);
+ if (rc != OPAL_SUCCESS)
+ return rc;
+
+ sprintf(name, "0x%x-0x%x", dump_type, dump_id);
+
+ /* we may get notified twice, let's handle
+ * that gracefully and not create two conflicting
+ * entries.
+ */
+ if (kset_find_obj(dump_kset, name))
+ return 0;
+
+ dump = create_dump_obj(dump_id, dump_size, dump_type);
+ if (!dump)
+ return -1;
+
+ return 0;
+}
+
+static void dump_work_fn(struct work_struct *work)
+{
+ process_dump();
+}
+
+static DECLARE_WORK(dump_work, dump_work_fn);
+
+static void schedule_process_dump(void)
+{
+ schedule_work(&dump_work);
+}
+
+/*
+ * New dump available notification
+ *
+ * Once we get notification, we add sysfs entries for it.
+ * We only fetch the dump on demand, and create sysfs asynchronously.
+ */
+static int dump_event(struct notifier_block *nb,
+ unsigned long events, void *change)
+{
+ if (events & OPAL_EVENT_DUMP_AVAIL)
+ schedule_process_dump();
+
+ return 0;
+}
+
+static struct notifier_block dump_nb = {
+ .notifier_call = dump_event,
+ .next = NULL,
+ .priority = 0
+};
+
+void __init opal_platform_dump_init(void)
+{
+ int rc;
+
+ dump_kset = kset_create_and_add("dump", NULL, opal_kobj);
+ if (!dump_kset) {
+ pr_warn("%s: Failed to create dump kset\n", __func__);
+ return;
+ }
+
+ rc = sysfs_create_group(&dump_kset->kobj, &initiate_attr_group);
+ if (rc) {
+ pr_warn("%s: Failed to create initiate dump attr group\n",
+ __func__);
+ kobject_put(&dump_kset->kobj);
+ return;
+ }
+
+ rc = opal_notifier_register(&dump_nb);
+ if (rc) {
+ pr_warn("%s: Can't register OPAL event notifier (%d)\n",
+ __func__, rc);
+ return;
+ }
+
+ opal_dump_resend_notification();
+}
diff --git a/arch/powerpc/platforms/powernv/opal-elog.c b/arch/powerpc/platforms/powernv/opal-elog.c
new file mode 100644
index 000000000000..1d7355bc9db0
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-elog.c
@@ -0,0 +1,313 @@
+/*
+ * Error log support on PowerNV.
+ *
+ * Copyright 2013,2014 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/fcntl.h>
+#include <linux/kobject.h>
+#include <asm/uaccess.h>
+#include <asm/opal.h>
+
+struct elog_obj {
+ struct kobject kobj;
+ struct bin_attribute raw_attr;
+ uint64_t id;
+ uint64_t type;
+ size_t size;
+ char *buffer;
+};
+#define to_elog_obj(x) container_of(x, struct elog_obj, kobj)
+
+struct elog_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct elog_obj *elog, struct elog_attribute *attr,
+ char *buf);
+ ssize_t (*store)(struct elog_obj *elog, struct elog_attribute *attr,
+ const char *buf, size_t count);
+};
+#define to_elog_attr(x) container_of(x, struct elog_attribute, attr)
+
+static ssize_t elog_id_show(struct elog_obj *elog_obj,
+ struct elog_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "0x%llx\n", elog_obj->id);
+}
+
+static const char *elog_type_to_string(uint64_t type)
+{
+ switch (type) {
+ case 0: return "PEL";
+ default: return "unknown";
+ }
+}
+
+static ssize_t elog_type_show(struct elog_obj *elog_obj,
+ struct elog_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "0x%llx %s\n",
+ elog_obj->type,
+ elog_type_to_string(elog_obj->type));
+}
+
+static ssize_t elog_ack_show(struct elog_obj *elog_obj,
+ struct elog_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "ack - acknowledge log message\n");
+}
+
+static void delay_release_kobj(void *kobj)
+{
+ kobject_put((struct kobject *)kobj);
+}
+
+static ssize_t elog_ack_store(struct elog_obj *elog_obj,
+ struct elog_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ opal_send_ack_elog(elog_obj->id);
+ sysfs_schedule_callback(&elog_obj->kobj, delay_release_kobj,
+ &elog_obj->kobj, THIS_MODULE);
+ return count;
+}
+
+static struct elog_attribute id_attribute =
+ __ATTR(id, 0666, elog_id_show, NULL);
+static struct elog_attribute type_attribute =
+ __ATTR(type, 0666, elog_type_show, NULL);
+static struct elog_attribute ack_attribute =
+ __ATTR(acknowledge, 0660, elog_ack_show, elog_ack_store);
+
+static struct kset *elog_kset;
+
+static ssize_t elog_attr_show(struct kobject *kobj,
+ struct attribute *attr,
+ char *buf)
+{
+ struct elog_attribute *attribute;
+ struct elog_obj *elog;
+
+ attribute = to_elog_attr(attr);
+ elog = to_elog_obj(kobj);
+
+ if (!attribute->show)
+ return -EIO;
+
+ return attribute->show(elog, attribute, buf);
+}
+
+static ssize_t elog_attr_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buf, size_t len)
+{
+ struct elog_attribute *attribute;
+ struct elog_obj *elog;
+
+ attribute = to_elog_attr(attr);
+ elog = to_elog_obj(kobj);
+
+ if (!attribute->store)
+ return -EIO;
+
+ return attribute->store(elog, attribute, buf, len);
+}
+
+static const struct sysfs_ops elog_sysfs_ops = {
+ .show = elog_attr_show,
+ .store = elog_attr_store,
+};
+
+static void elog_release(struct kobject *kobj)
+{
+ struct elog_obj *elog;
+
+ elog = to_elog_obj(kobj);
+ kfree(elog->buffer);
+ kfree(elog);
+}
+
+static struct attribute *elog_default_attrs[] = {
+ &id_attribute.attr,
+ &type_attribute.attr,
+ &ack_attribute.attr,
+ NULL,
+};
+
+static struct kobj_type elog_ktype = {
+ .sysfs_ops = &elog_sysfs_ops,
+ .release = &elog_release,
+ .default_attrs = elog_default_attrs,
+};
+
+/* Maximum size of a single log on FSP is 16KB */
+#define OPAL_MAX_ERRLOG_SIZE 16384
+
+static ssize_t raw_attr_read(struct file *filep, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t pos, size_t count)
+{
+ int opal_rc;
+
+ struct elog_obj *elog = to_elog_obj(kobj);
+
+ /* We may have had an error reading before, so let's retry */
+ if (!elog->buffer) {
+ elog->buffer = kzalloc(elog->size, GFP_KERNEL);
+ if (!elog->buffer)
+ return -EIO;
+
+ opal_rc = opal_read_elog(__pa(elog->buffer),
+ elog->size, elog->id);
+ if (opal_rc != OPAL_SUCCESS) {
+ pr_err("ELOG: log read failed for log-id=%llx\n",
+ elog->id);
+ kfree(elog->buffer);
+ elog->buffer = NULL;
+ return -EIO;
+ }
+ }
+
+ memcpy(buffer, elog->buffer + pos, count);
+
+ return count;
+}
+
+static struct elog_obj *create_elog_obj(uint64_t id, size_t size, uint64_t type)
+{
+ struct elog_obj *elog;
+ int rc;
+
+ elog = kzalloc(sizeof(*elog), GFP_KERNEL);
+ if (!elog)
+ return NULL;
+
+ elog->kobj.kset = elog_kset;
+
+ kobject_init(&elog->kobj, &elog_ktype);
+
+ sysfs_bin_attr_init(&elog->raw_attr);
+
+ elog->raw_attr.attr.name = "raw";
+ elog->raw_attr.attr.mode = 0400;
+ elog->raw_attr.size = size;
+ elog->raw_attr.read = raw_attr_read;
+
+ elog->id = id;
+ elog->size = size;
+ elog->type = type;
+
+ elog->buffer = kzalloc(elog->size, GFP_KERNEL);
+
+ if (elog->buffer) {
+ rc = opal_read_elog(__pa(elog->buffer),
+ elog->size, elog->id);
+ if (rc != OPAL_SUCCESS) {
+ pr_err("ELOG: log read failed for log-id=%llx\n",
+ elog->id);
+ kfree(elog->buffer);
+ elog->buffer = NULL;
+ }
+ }
+
+ rc = kobject_add(&elog->kobj, NULL, "0x%llx", id);
+ if (rc) {
+ kobject_put(&elog->kobj);
+ return NULL;
+ }
+
+ rc = sysfs_create_bin_file(&elog->kobj, &elog->raw_attr);
+ if (rc) {
+ kobject_put(&elog->kobj);
+ return NULL;
+ }
+
+ kobject_uevent(&elog->kobj, KOBJ_ADD);
+
+ return elog;
+}
+
+static void elog_work_fn(struct work_struct *work)
+{
+ size_t elog_size;
+ uint64_t log_id;
+ uint64_t elog_type;
+ int rc;
+ char name[2+16+1];
+
+ rc = opal_get_elog_size(&log_id, &elog_size, &elog_type);
+ if (rc != OPAL_SUCCESS) {
+ pr_err("ELOG: Opal log read failed\n");
+ return;
+ }
+
+ BUG_ON(elog_size > OPAL_MAX_ERRLOG_SIZE);
+
+ if (elog_size >= OPAL_MAX_ERRLOG_SIZE)
+ elog_size = OPAL_MAX_ERRLOG_SIZE;
+
+ sprintf(name, "0x%llx", log_id);
+
+ /* we may get notified twice, let's handle
+ * that gracefully and not create two conflicting
+ * entries.
+ */
+ if (kset_find_obj(elog_kset, name))
+ return;
+
+ create_elog_obj(log_id, elog_size, elog_type);
+}
+
+static DECLARE_WORK(elog_work, elog_work_fn);
+
+static int elog_event(struct notifier_block *nb,
+ unsigned long events, void *change)
+{
+ /* check for error log event */
+ if (events & OPAL_EVENT_ERROR_LOG_AVAIL)
+ schedule_work(&elog_work);
+ return 0;
+}
+
+static struct notifier_block elog_nb = {
+ .notifier_call = elog_event,
+ .next = NULL,
+ .priority = 0
+};
+
+int __init opal_elog_init(void)
+{
+ int rc = 0;
+
+ elog_kset = kset_create_and_add("elog", NULL, opal_kobj);
+ if (!elog_kset) {
+ pr_warn("%s: failed to create elog kset\n", __func__);
+ return -1;
+ }
+
+ rc = opal_notifier_register(&elog_nb);
+ if (rc) {
+ pr_err("%s: Can't register OPAL event notifier (%d)\n",
+ __func__, rc);
+ return rc;
+ }
+
+ /* We are now ready to pull error logs from opal. */
+ opal_resend_pending_logs();
+
+ return 0;
+}
diff --git a/arch/powerpc/platforms/powernv/opal-sensor.c b/arch/powerpc/platforms/powernv/opal-sensor.c
new file mode 100644
index 000000000000..663cc9c65613
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-sensor.c
@@ -0,0 +1,64 @@
+/*
+ * PowerNV sensor code
+ *
+ * Copyright (C) 2013 IBM
+ *
+ * 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/delay.h>
+#include <linux/mutex.h>
+#include <asm/opal.h>
+
+static DEFINE_MUTEX(opal_sensor_mutex);
+
+/*
+ * This will return sensor information to driver based on the requested sensor
+ * handle. A handle is an opaque id for the powernv, read by the driver from the
+ * device tree..
+ */
+int opal_get_sensor_data(u32 sensor_hndl, u32 *sensor_data)
+{
+ int ret, token;
+ struct opal_msg msg;
+
+ token = opal_async_get_token_interruptible();
+ if (token < 0) {
+ pr_err("%s: Couldn't get the token, returning\n", __func__);
+ ret = token;
+ goto out;
+ }
+
+ mutex_lock(&opal_sensor_mutex);
+ ret = opal_sensor_read(sensor_hndl, token, sensor_data);
+ if (ret != OPAL_ASYNC_COMPLETION)
+ goto out_token;
+
+ ret = opal_async_wait_response(token, &msg);
+ if (ret) {
+ pr_err("%s: Failed to wait for the async response, %d\n",
+ __func__, ret);
+ goto out_token;
+ }
+
+ ret = msg.params[1];
+
+out_token:
+ mutex_unlock(&opal_sensor_mutex);
+ opal_async_release_token(token);
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(opal_get_sensor_data);
diff --git a/arch/powerpc/platforms/powernv/opal-sysparam.c b/arch/powerpc/platforms/powernv/opal-sysparam.c
new file mode 100644
index 000000000000..0bd249a26f30
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-sysparam.c
@@ -0,0 +1,290 @@
+/*
+ * PowerNV system parameter code
+ *
+ * Copyright (C) 2013 IBM
+ *
+ * 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/kobject.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/gfp.h>
+#include <linux/stat.h>
+#include <asm/opal.h>
+
+#define MAX_PARAM_DATA_LEN 64
+
+static DEFINE_MUTEX(opal_sysparam_mutex);
+static struct kobject *sysparam_kobj;
+static void *param_data_buf;
+
+struct param_attr {
+ struct list_head list;
+ u32 param_id;
+ u32 param_size;
+ struct kobj_attribute kobj_attr;
+};
+
+static int opal_get_sys_param(u32 param_id, u32 length, void *buffer)
+{
+ struct opal_msg msg;
+ int ret, token;
+
+ token = opal_async_get_token_interruptible();
+ if (token < 0) {
+ if (token != -ERESTARTSYS)
+ pr_err("%s: Couldn't get the token, returning\n",
+ __func__);
+ ret = token;
+ goto out;
+ }
+
+ ret = opal_get_param(token, param_id, (u64)buffer, length);
+ if (ret != OPAL_ASYNC_COMPLETION)
+ goto out_token;
+
+ ret = opal_async_wait_response(token, &msg);
+ if (ret) {
+ pr_err("%s: Failed to wait for the async response, %d\n",
+ __func__, ret);
+ goto out_token;
+ }
+
+ ret = msg.params[1];
+
+out_token:
+ opal_async_release_token(token);
+out:
+ return ret;
+}
+
+static int opal_set_sys_param(u32 param_id, u32 length, void *buffer)
+{
+ struct opal_msg msg;
+ int ret, token;
+
+ token = opal_async_get_token_interruptible();
+ if (token < 0) {
+ if (token != -ERESTARTSYS)
+ pr_err("%s: Couldn't get the token, returning\n",
+ __func__);
+ ret = token;
+ goto out;
+ }
+
+ ret = opal_set_param(token, param_id, (u64)buffer, length);
+
+ if (ret != OPAL_ASYNC_COMPLETION)
+ goto out_token;
+
+ ret = opal_async_wait_response(token, &msg);
+ if (ret) {
+ pr_err("%s: Failed to wait for the async response, %d\n",
+ __func__, ret);
+ goto out_token;
+ }
+
+ ret = msg.params[1];
+
+out_token:
+ opal_async_release_token(token);
+out:
+ return ret;
+}
+
+static ssize_t sys_param_show(struct kobject *kobj,
+ struct kobj_attribute *kobj_attr, char *buf)
+{
+ struct param_attr *attr = container_of(kobj_attr, struct param_attr,
+ kobj_attr);
+ int ret;
+
+ mutex_lock(&opal_sysparam_mutex);
+ ret = opal_get_sys_param(attr->param_id, attr->param_size,
+ param_data_buf);
+ if (ret)
+ goto out;
+
+ memcpy(buf, param_data_buf, attr->param_size);
+
+out:
+ mutex_unlock(&opal_sysparam_mutex);
+ return ret ? ret : attr->param_size;
+}
+
+static ssize_t sys_param_store(struct kobject *kobj,
+ struct kobj_attribute *kobj_attr, const char *buf, size_t count)
+{
+ struct param_attr *attr = container_of(kobj_attr, struct param_attr,
+ kobj_attr);
+ int ret;
+
+ mutex_lock(&opal_sysparam_mutex);
+ memcpy(param_data_buf, buf, count);
+ ret = opal_set_sys_param(attr->param_id, attr->param_size,
+ param_data_buf);
+ mutex_unlock(&opal_sysparam_mutex);
+ return ret ? ret : count;
+}
+
+void __init opal_sys_param_init(void)
+{
+ struct device_node *sysparam;
+ struct param_attr *attr;
+ u32 *id, *size;
+ int count, i;
+ u8 *perm;
+
+ if (!opal_kobj) {
+ pr_warn("SYSPARAM: opal kobject is not available\n");
+ goto out;
+ }
+
+ sysparam_kobj = kobject_create_and_add("sysparams", opal_kobj);
+ if (!sysparam_kobj) {
+ pr_err("SYSPARAM: Failed to create sysparam kobject\n");
+ goto out;
+ }
+
+ /* Allocate big enough buffer for any get/set transactions */
+ param_data_buf = kzalloc(MAX_PARAM_DATA_LEN, GFP_KERNEL);
+ if (!param_data_buf) {
+ pr_err("SYSPARAM: Failed to allocate memory for param data "
+ "buf\n");
+ goto out_kobj_put;
+ }
+
+ sysparam = of_find_node_by_path("/ibm,opal/sysparams");
+ if (!sysparam) {
+ pr_err("SYSPARAM: Opal sysparam node not found\n");
+ goto out_param_buf;
+ }
+
+ if (!of_device_is_compatible(sysparam, "ibm,opal-sysparams")) {
+ pr_err("SYSPARAM: Opal sysparam node not compatible\n");
+ goto out_node_put;
+ }
+
+ /* Number of parameters exposed through DT */
+ count = of_property_count_strings(sysparam, "param-name");
+ if (count < 0) {
+ pr_err("SYSPARAM: No string found of property param-name in "
+ "the node %s\n", sysparam->name);
+ goto out_node_put;
+ }
+
+ id = kzalloc(sizeof(*id) * count, GFP_KERNEL);
+ if (!id) {
+ pr_err("SYSPARAM: Failed to allocate memory to read parameter "
+ "id\n");
+ goto out_node_put;
+ }
+
+ size = kzalloc(sizeof(*size) * count, GFP_KERNEL);
+ if (!size) {
+ pr_err("SYSPARAM: Failed to allocate memory to read parameter "
+ "size\n");
+ goto out_free_id;
+ }
+
+ perm = kzalloc(sizeof(*perm) * count, GFP_KERNEL);
+ if (!perm) {
+ pr_err("SYSPARAM: Failed to allocate memory to read supported "
+ "action on the parameter");
+ goto out_free_size;
+ }
+
+ if (of_property_read_u32_array(sysparam, "param-id", id, count)) {
+ pr_err("SYSPARAM: Missing property param-id in the DT\n");
+ goto out_free_perm;
+ }
+
+ if (of_property_read_u32_array(sysparam, "param-len", size, count)) {
+ pr_err("SYSPARAM: Missing propery param-len in the DT\n");
+ goto out_free_perm;
+ }
+
+
+ if (of_property_read_u8_array(sysparam, "param-perm", perm, count)) {
+ pr_err("SYSPARAM: Missing propery param-perm in the DT\n");
+ goto out_free_perm;
+ }
+
+ attr = kzalloc(sizeof(*attr) * count, GFP_KERNEL);
+ if (!attr) {
+ pr_err("SYSPARAM: Failed to allocate memory for parameter "
+ "attributes\n");
+ goto out_free_perm;
+ }
+
+ /* For each of the parameters, populate the parameter attributes */
+ for (i = 0; i < count; i++) {
+ sysfs_attr_init(&attr[i].kobj_attr.attr);
+ attr[i].param_id = id[i];
+ attr[i].param_size = size[i];
+ if (of_property_read_string_index(sysparam, "param-name", i,
+ &attr[i].kobj_attr.attr.name))
+ continue;
+
+ /* If the parameter is read-only or read-write */
+ switch (perm[i] & 3) {
+ case OPAL_SYSPARAM_READ:
+ attr[i].kobj_attr.attr.mode = S_IRUGO;
+ break;
+ case OPAL_SYSPARAM_WRITE:
+ attr[i].kobj_attr.attr.mode = S_IWUGO;
+ break;
+ case OPAL_SYSPARAM_RW:
+ attr[i].kobj_attr.attr.mode = S_IRUGO | S_IWUGO;
+ break;
+ default:
+ break;
+ }
+
+ attr[i].kobj_attr.show = sys_param_show;
+ attr[i].kobj_attr.store = sys_param_store;
+
+ if (sysfs_create_file(sysparam_kobj, &attr[i].kobj_attr.attr)) {
+ pr_err("SYSPARAM: Failed to create sysfs file %s\n",
+ attr[i].kobj_attr.attr.name);
+ goto out_free_attr;
+ }
+ }
+
+ kfree(perm);
+ kfree(size);
+ kfree(id);
+ of_node_put(sysparam);
+ return;
+
+out_free_attr:
+ kfree(attr);
+out_free_perm:
+ kfree(perm);
+out_free_size:
+ kfree(size);
+out_free_id:
+ kfree(id);
+out_node_put:
+ of_node_put(sysparam);
+out_param_buf:
+ kfree(param_data_buf);
+out_kobj_put:
+ kobject_put(sysparam_kobj);
+out:
+ return;
+}
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 3e8829c40fbb..bb90f9a4e027 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -123,9 +123,24 @@ OPAL_CALL(opal_xscom_write, OPAL_XSCOM_WRITE);
OPAL_CALL(opal_lpc_read, OPAL_LPC_READ);
OPAL_CALL(opal_lpc_write, OPAL_LPC_WRITE);
OPAL_CALL(opal_return_cpu, OPAL_RETURN_CPU);
+OPAL_CALL(opal_read_elog, OPAL_ELOG_READ);
+OPAL_CALL(opal_send_ack_elog, OPAL_ELOG_ACK);
+OPAL_CALL(opal_get_elog_size, OPAL_ELOG_SIZE);
+OPAL_CALL(opal_resend_pending_logs, OPAL_ELOG_RESEND);
+OPAL_CALL(opal_write_elog, OPAL_ELOG_WRITE);
OPAL_CALL(opal_validate_flash, OPAL_FLASH_VALIDATE);
OPAL_CALL(opal_manage_flash, OPAL_FLASH_MANAGE);
OPAL_CALL(opal_update_flash, OPAL_FLASH_UPDATE);
+OPAL_CALL(opal_resync_timebase, OPAL_RESYNC_TIMEBASE);
+OPAL_CALL(opal_dump_init, OPAL_DUMP_INIT);
+OPAL_CALL(opal_dump_info, OPAL_DUMP_INFO);
+OPAL_CALL(opal_dump_info2, OPAL_DUMP_INFO2);
+OPAL_CALL(opal_dump_read, OPAL_DUMP_READ);
+OPAL_CALL(opal_dump_ack, OPAL_DUMP_ACK);
OPAL_CALL(opal_get_msg, OPAL_GET_MSG);
OPAL_CALL(opal_check_completion, OPAL_CHECK_ASYNC_COMPLETION);
+OPAL_CALL(opal_dump_resend_notification, OPAL_DUMP_RESEND);
OPAL_CALL(opal_sync_host_reboot, OPAL_SYNC_HOST_REBOOT);
+OPAL_CALL(opal_sensor_read, OPAL_SENSOR_READ);
+OPAL_CALL(opal_get_param, OPAL_GET_PARAM);
+OPAL_CALL(opal_set_param, OPAL_SET_PARAM);
diff --git a/arch/powerpc/platforms/powernv/opal-xscom.c b/arch/powerpc/platforms/powernv/opal-xscom.c
index 4fbf276ac99e..4cd2ea6c0dbe 100644
--- a/arch/powerpc/platforms/powernv/opal-xscom.c
+++ b/arch/powerpc/platforms/powernv/opal-xscom.c
@@ -71,11 +71,11 @@ static int opal_xscom_err_xlate(int64_t rc)
}
}
-static u64 opal_scom_unmangle(u64 reg)
+static u64 opal_scom_unmangle(u64 addr)
{
/*
* XSCOM indirect addresses have the top bit set. Additionally
- * the reset of the top 3 nibbles is always 0.
+ * the rest of the top 3 nibbles is always 0.
*
* Because the debugfs interface uses signed offsets and shifts
* the address left by 3, we basically cannot use the top 4 bits
@@ -86,10 +86,13 @@ static u64 opal_scom_unmangle(u64 reg)
* conversion here. To leave room for further xscom address
* expansion, we only clear out the top byte
*
+ * For in-kernel use, we also support the real indirect bit, so
+ * we test for any of the top 5 bits
+ *
*/
- if (reg & (1ull << 59))
- reg = (reg & ~(0xffull << 56)) | (1ull << 63);
- return reg;
+ if (addr & (0x1full << 59))
+ addr = (addr & ~(0xffull << 56)) | (1ull << 63);
+ return addr;
}
static int opal_scom_read(scom_map_t map, u64 reg, u64 *value)
@@ -98,8 +101,8 @@ static int opal_scom_read(scom_map_t map, u64 reg, u64 *value)
int64_t rc;
__be64 v;
- reg = opal_scom_unmangle(reg);
- rc = opal_xscom_read(m->chip, m->addr + reg, (__be64 *)__pa(&v));
+ reg = opal_scom_unmangle(m->addr + reg);
+ rc = opal_xscom_read(m->chip, reg, (__be64 *)__pa(&v));
*value = be64_to_cpu(v);
return opal_xscom_err_xlate(rc);
}
@@ -109,8 +112,8 @@ static int opal_scom_write(scom_map_t map, u64 reg, u64 value)
struct opal_scom_map *m = map;
int64_t rc;
- reg = opal_scom_unmangle(reg);
- rc = opal_xscom_write(m->chip, m->addr + reg, value);
+ reg = opal_scom_unmangle(m->addr + reg);
+ rc = opal_xscom_write(m->chip, reg, value);
return opal_xscom_err_xlate(rc);
}
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 65499adaecff..e92f2f67640f 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -21,6 +21,7 @@
#include <linux/sched.h>
#include <linux/kobject.h>
#include <linux/delay.h>
+#include <linux/memblock.h>
#include <asm/opal.h>
#include <asm/firmware.h>
#include <asm/mce.h>
@@ -33,8 +34,18 @@ struct kobject *opal_kobj;
struct opal {
u64 base;
u64 entry;
+ u64 size;
} opal;
+struct mcheck_recoverable_range {
+ u64 start_addr;
+ u64 end_addr;
+ u64 recover_addr;
+};
+
+static struct mcheck_recoverable_range *mc_recoverable_range;
+static int mc_recoverable_range_len;
+
static struct device_node *opal_node;
static DEFINE_SPINLOCK(opal_write_lock);
extern u64 opal_mc_secondary_handler[];
@@ -49,25 +60,29 @@ static atomic_t opal_notifier_hold = ATOMIC_INIT(0);
int __init early_init_dt_scan_opal(unsigned long node,
const char *uname, int depth, void *data)
{
- const void *basep, *entryp;
- unsigned long basesz, entrysz;
+ const void *basep, *entryp, *sizep;
+ unsigned long basesz, entrysz, runtimesz;
if (depth != 1 || strcmp(uname, "ibm,opal") != 0)
return 0;
basep = of_get_flat_dt_prop(node, "opal-base-address", &basesz);
entryp = of_get_flat_dt_prop(node, "opal-entry-address", &entrysz);
+ sizep = of_get_flat_dt_prop(node, "opal-runtime-size", &runtimesz);
- if (!basep || !entryp)
+ if (!basep || !entryp || !sizep)
return 1;
opal.base = of_read_number(basep, basesz/4);
opal.entry = of_read_number(entryp, entrysz/4);
+ opal.size = of_read_number(sizep, runtimesz/4);
pr_debug("OPAL Base = 0x%llx (basep=%p basesz=%ld)\n",
opal.base, basep, basesz);
pr_debug("OPAL Entry = 0x%llx (entryp=%p basesz=%ld)\n",
opal.entry, entryp, entrysz);
+ pr_debug("OPAL Entry = 0x%llx (sizep=%p runtimesz=%ld)\n",
+ opal.size, sizep, runtimesz);
powerpc_firmware_features |= FW_FEATURE_OPAL;
if (of_flat_dt_is_compatible(node, "ibm,opal-v3")) {
@@ -84,6 +99,53 @@ int __init early_init_dt_scan_opal(unsigned long node,
return 1;
}
+int __init early_init_dt_scan_recoverable_ranges(unsigned long node,
+ const char *uname, int depth, void *data)
+{
+ unsigned long i, size;
+ const __be32 *prop;
+
+ if (depth != 1 || strcmp(uname, "ibm,opal") != 0)
+ return 0;
+
+ prop = of_get_flat_dt_prop(node, "mcheck-recoverable-ranges", &size);
+
+ if (!prop)
+ return 1;
+
+ pr_debug("Found machine check recoverable ranges.\n");
+
+ /*
+ * Allocate a buffer to hold the MC recoverable ranges. We would be
+ * accessing them in real mode, hence it needs to be within
+ * RMO region.
+ */
+ mc_recoverable_range =__va(memblock_alloc_base(size, __alignof__(u64),
+ ppc64_rma_size));
+ memset(mc_recoverable_range, 0, size);
+
+ /*
+ * Each recoverable address entry is an (start address,len,
+ * recover address) pair, * 2 cells each, totalling 4 cells per entry.
+ */
+ for (i = 0; i < size / (sizeof(*prop) * 5); i++) {
+ mc_recoverable_range[i].start_addr =
+ of_read_number(prop + (i * 5) + 0, 2);
+ mc_recoverable_range[i].end_addr =
+ mc_recoverable_range[i].start_addr +
+ of_read_number(prop + (i * 5) + 2, 1);
+ mc_recoverable_range[i].recover_addr =
+ of_read_number(prop + (i * 5) + 3, 2);
+
+ pr_debug("Machine check recoverable range: %llx..%llx: %llx\n",
+ mc_recoverable_range[i].start_addr,
+ mc_recoverable_range[i].end_addr,
+ mc_recoverable_range[i].recover_addr);
+ }
+ mc_recoverable_range_len = i;
+ return 1;
+}
+
static int __init opal_register_exception_handlers(void)
{
#ifdef __BIG_ENDIAN__
@@ -401,6 +463,38 @@ int opal_machine_check(struct pt_regs *regs)
return 0;
}
+static uint64_t find_recovery_address(uint64_t nip)
+{
+ int i;
+
+ for (i = 0; i < mc_recoverable_range_len; i++)
+ if ((nip >= mc_recoverable_range[i].start_addr) &&
+ (nip < mc_recoverable_range[i].end_addr))
+ return mc_recoverable_range[i].recover_addr;
+ return 0;
+}
+
+bool opal_mce_check_early_recovery(struct pt_regs *regs)
+{
+ uint64_t recover_addr = 0;
+
+ if (!opal.base || !opal.size)
+ goto out;
+
+ if ((regs->nip >= opal.base) &&
+ (regs->nip <= (opal.base + opal.size)))
+ recover_addr = find_recovery_address(regs->nip);
+
+ /*
+ * Setup regs->nip to rfi into fixup address.
+ */
+ if (recover_addr)
+ regs->nip = recover_addr;
+
+out:
+ return !!recover_addr;
+}
+
static irqreturn_t opal_interrupt(int irq, void *data)
{
__be64 events;
@@ -472,8 +566,14 @@ static int __init opal_init(void)
/* Create "opal" kobject under /sys/firmware */
rc = opal_sysfs_init();
if (rc == 0) {
+ /* Setup error log interface */
+ rc = opal_elog_init();
/* Setup code update interface */
opal_flash_init();
+ /* Setup platform dump extract interface */
+ opal_platform_dump_init();
+ /* Setup system parameters interface */
+ opal_sys_param_init();
}
return 0;
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 7d6dcc6d5fa9..3b2b4fb3585b 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -21,6 +21,7 @@
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/msi.h>
+#include <linux/memblock.h>
#include <asm/sections.h>
#include <asm/io.h>
@@ -460,9 +461,39 @@ static void pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev
return;
pe = &phb->ioda.pe_array[pdn->pe_number];
+ WARN_ON(get_dma_ops(&pdev->dev) != &dma_iommu_ops);
set_iommu_table_base_and_group(&pdev->dev, &pe->tce32_table);
}
+static int pnv_pci_ioda_dma_set_mask(struct pnv_phb *phb,
+ struct pci_dev *pdev, u64 dma_mask)
+{
+ struct pci_dn *pdn = pci_get_pdn(pdev);
+ struct pnv_ioda_pe *pe;
+ uint64_t top;
+ bool bypass = false;
+
+ if (WARN_ON(!pdn || pdn->pe_number == IODA_INVALID_PE))
+ return -ENODEV;;
+
+ pe = &phb->ioda.pe_array[pdn->pe_number];
+ if (pe->tce_bypass_enabled) {
+ top = pe->tce_bypass_base + memblock_end_of_DRAM() - 1;
+ bypass = (dma_mask >= top);
+ }
+
+ if (bypass) {
+ dev_info(&pdev->dev, "Using 64-bit DMA iommu bypass\n");
+ set_dma_ops(&pdev->dev, &dma_direct_ops);
+ set_dma_offset(&pdev->dev, pe->tce_bypass_base);
+ } else {
+ dev_info(&pdev->dev, "Using 32-bit DMA via iommu\n");
+ set_dma_ops(&pdev->dev, &dma_iommu_ops);
+ set_iommu_table_base(&pdev->dev, &pe->tce32_table);
+ }
+ return 0;
+}
+
static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus)
{
struct pci_dev *dev;
@@ -657,6 +688,56 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
__free_pages(tce_mem, get_order(TCE32_TABLE_SIZE * segs));
}
+static void pnv_pci_ioda2_set_bypass(struct iommu_table *tbl, bool enable)
+{
+ struct pnv_ioda_pe *pe = container_of(tbl, struct pnv_ioda_pe,
+ tce32_table);
+ uint16_t window_id = (pe->pe_number << 1 ) + 1;
+ int64_t rc;
+
+ pe_info(pe, "%sabling 64-bit DMA bypass\n", enable ? "En" : "Dis");
+ if (enable) {
+ phys_addr_t top = memblock_end_of_DRAM();
+
+ top = roundup_pow_of_two(top);
+ rc = opal_pci_map_pe_dma_window_real(pe->phb->opal_id,
+ pe->pe_number,
+ window_id,
+ pe->tce_bypass_base,
+ top);
+ } else {
+ rc = opal_pci_map_pe_dma_window_real(pe->phb->opal_id,
+ pe->pe_number,
+ window_id,
+ pe->tce_bypass_base,
+ 0);
+
+ /*
+ * We might want to reset the DMA ops of all devices on
+ * this PE. However in theory, that shouldn't be necessary
+ * as this is used for VFIO/KVM pass-through and the device
+ * hasn't yet been returned to its kernel driver
+ */
+ }
+ if (rc)
+ pe_err(pe, "OPAL error %lld configuring bypass window\n", rc);
+ else
+ pe->tce_bypass_enabled = enable;
+}
+
+static void pnv_pci_ioda2_setup_bypass_pe(struct pnv_phb *phb,
+ struct pnv_ioda_pe *pe)
+{
+ /* TVE #1 is selected by PCI address bit 59 */
+ pe->tce_bypass_base = 1ull << 59;
+
+ /* Install set_bypass callback for VFIO */
+ pe->tce32_table.set_bypass = pnv_pci_ioda2_set_bypass;
+
+ /* Enable bypass by default */
+ pnv_pci_ioda2_set_bypass(&pe->tce32_table, true);
+}
+
static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
struct pnv_ioda_pe *pe)
{
@@ -727,6 +808,8 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
else
pnv_ioda_setup_bus_dma(pe, pe->pbus);
+ /* Also create a bypass window */
+ pnv_pci_ioda2_setup_bypass_pe(phb, pe);
return;
fail:
if (pe->tce32_seg >= 0)
@@ -1286,6 +1369,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
/* Setup TCEs */
phb->dma_dev_setup = pnv_pci_ioda_dma_dev_setup;
+ phb->dma_set_mask = pnv_pci_ioda_dma_set_mask;
/* Setup shutdown function for kexec */
phb->shutdown = pnv_pci_ioda_shutdown;
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index b555ebc57ef5..8518817dcdfd 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -134,57 +134,72 @@ static void pnv_pci_dump_p7ioc_diag_data(struct pci_controller *hose,
pr_info("P7IOC PHB#%d Diag-data (Version: %d)\n\n",
hose->global_number, common->version);
- pr_info(" brdgCtl: %08x\n", data->brdgCtl);
-
- pr_info(" portStatusReg: %08x\n", data->portStatusReg);
- pr_info(" rootCmplxStatus: %08x\n", data->rootCmplxStatus);
- pr_info(" busAgentStatus: %08x\n", data->busAgentStatus);
-
- pr_info(" deviceStatus: %08x\n", data->deviceStatus);
- pr_info(" slotStatus: %08x\n", data->slotStatus);
- pr_info(" linkStatus: %08x\n", data->linkStatus);
- pr_info(" devCmdStatus: %08x\n", data->devCmdStatus);
- pr_info(" devSecStatus: %08x\n", data->devSecStatus);
-
- pr_info(" rootErrorStatus: %08x\n", data->rootErrorStatus);
- pr_info(" uncorrErrorStatus: %08x\n", data->uncorrErrorStatus);
- pr_info(" corrErrorStatus: %08x\n", data->corrErrorStatus);
- pr_info(" tlpHdr1: %08x\n", data->tlpHdr1);
- pr_info(" tlpHdr2: %08x\n", data->tlpHdr2);
- pr_info(" tlpHdr3: %08x\n", data->tlpHdr3);
- pr_info(" tlpHdr4: %08x\n", data->tlpHdr4);
- pr_info(" sourceId: %08x\n", data->sourceId);
- pr_info(" errorClass: %016llx\n", data->errorClass);
- pr_info(" correlator: %016llx\n", data->correlator);
- pr_info(" p7iocPlssr: %016llx\n", data->p7iocPlssr);
- pr_info(" p7iocCsr: %016llx\n", data->p7iocCsr);
- pr_info(" lemFir: %016llx\n", data->lemFir);
- pr_info(" lemErrorMask: %016llx\n", data->lemErrorMask);
- pr_info(" lemWOF: %016llx\n", data->lemWOF);
- pr_info(" phbErrorStatus: %016llx\n", data->phbErrorStatus);
- pr_info(" phbFirstErrorStatus: %016llx\n", data->phbFirstErrorStatus);
- pr_info(" phbErrorLog0: %016llx\n", data->phbErrorLog0);
- pr_info(" phbErrorLog1: %016llx\n", data->phbErrorLog1);
- pr_info(" mmioErrorStatus: %016llx\n", data->mmioErrorStatus);
- pr_info(" mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus);
- pr_info(" mmioErrorLog0: %016llx\n", data->mmioErrorLog0);
- pr_info(" mmioErrorLog1: %016llx\n", data->mmioErrorLog1);
- pr_info(" dma0ErrorStatus: %016llx\n", data->dma0ErrorStatus);
- pr_info(" dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus);
- pr_info(" dma0ErrorLog0: %016llx\n", data->dma0ErrorLog0);
- pr_info(" dma0ErrorLog1: %016llx\n", data->dma0ErrorLog1);
- pr_info(" dma1ErrorStatus: %016llx\n", data->dma1ErrorStatus);
- pr_info(" dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus);
- pr_info(" dma1ErrorLog0: %016llx\n", data->dma1ErrorLog0);
- pr_info(" dma1ErrorLog1: %016llx\n", data->dma1ErrorLog1);
+ if (data->brdgCtl)
+ pr_info(" brdgCtl: %08x\n",
+ data->brdgCtl);
+ if (data->portStatusReg || data->rootCmplxStatus ||
+ data->busAgentStatus)
+ pr_info(" UtlSts: %08x %08x %08x\n",
+ data->portStatusReg, data->rootCmplxStatus,
+ data->busAgentStatus);
+ if (data->deviceStatus || data->slotStatus ||
+ data->linkStatus || data->devCmdStatus ||
+ data->devSecStatus)
+ pr_info(" RootSts: %08x %08x %08x %08x %08x\n",
+ data->deviceStatus, data->slotStatus,
+ data->linkStatus, data->devCmdStatus,
+ data->devSecStatus);
+ if (data->rootErrorStatus || data->uncorrErrorStatus ||
+ data->corrErrorStatus)
+ pr_info(" RootErrSts: %08x %08x %08x\n",
+ data->rootErrorStatus, data->uncorrErrorStatus,
+ data->corrErrorStatus);
+ if (data->tlpHdr1 || data->tlpHdr2 ||
+ data->tlpHdr3 || data->tlpHdr4)
+ pr_info(" RootErrLog: %08x %08x %08x %08x\n",
+ data->tlpHdr1, data->tlpHdr2,
+ data->tlpHdr3, data->tlpHdr4);
+ if (data->sourceId || data->errorClass ||
+ data->correlator)
+ pr_info(" RootErrLog1: %08x %016llx %016llx\n",
+ data->sourceId, data->errorClass,
+ data->correlator);
+ if (data->p7iocPlssr || data->p7iocCsr)
+ pr_info(" PhbSts: %016llx %016llx\n",
+ data->p7iocPlssr, data->p7iocCsr);
+ if (data->lemFir || data->lemErrorMask ||
+ data->lemWOF)
+ pr_info(" Lem: %016llx %016llx %016llx\n",
+ data->lemFir, data->lemErrorMask,
+ data->lemWOF);
+ if (data->phbErrorStatus || data->phbFirstErrorStatus ||
+ data->phbErrorLog0 || data->phbErrorLog1)
+ pr_info(" PhbErr: %016llx %016llx %016llx %016llx\n",
+ data->phbErrorStatus, data->phbFirstErrorStatus,
+ data->phbErrorLog0, data->phbErrorLog1);
+ if (data->mmioErrorStatus || data->mmioFirstErrorStatus ||
+ data->mmioErrorLog0 || data->mmioErrorLog1)
+ pr_info(" OutErr: %016llx %016llx %016llx %016llx\n",
+ data->mmioErrorStatus, data->mmioFirstErrorStatus,
+ data->mmioErrorLog0, data->mmioErrorLog1);
+ if (data->dma0ErrorStatus || data->dma0FirstErrorStatus ||
+ data->dma0ErrorLog0 || data->dma0ErrorLog1)
+ pr_info(" InAErr: %016llx %016llx %016llx %016llx\n",
+ data->dma0ErrorStatus, data->dma0FirstErrorStatus,
+ data->dma0ErrorLog0, data->dma0ErrorLog1);
+ if (data->dma1ErrorStatus || data->dma1FirstErrorStatus ||
+ data->dma1ErrorLog0 || data->dma1ErrorLog1)
+ pr_info(" InBErr: %016llx %016llx %016llx %016llx\n",
+ data->dma1ErrorStatus, data->dma1FirstErrorStatus,
+ data->dma1ErrorLog0, data->dma1ErrorLog1);
for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) {
if ((data->pestA[i] >> 63) == 0 &&
(data->pestB[i] >> 63) == 0)
continue;
- pr_info(" PE[%3d] PESTA: %016llx\n", i, data->pestA[i]);
- pr_info(" PESTB: %016llx\n", data->pestB[i]);
+ pr_info(" PE[%3d] A/B: %016llx %016llx\n",
+ i, data->pestA[i], data->pestB[i]);
}
}
@@ -197,62 +212,77 @@ static void pnv_pci_dump_phb3_diag_data(struct pci_controller *hose,
data = (struct OpalIoPhb3ErrorData*)common;
pr_info("PHB3 PHB#%d Diag-data (Version: %d)\n\n",
hose->global_number, common->version);
-
- pr_info(" brdgCtl: %08x\n", data->brdgCtl);
-
- pr_info(" portStatusReg: %08x\n", data->portStatusReg);
- pr_info(" rootCmplxStatus: %08x\n", data->rootCmplxStatus);
- pr_info(" busAgentStatus: %08x\n", data->busAgentStatus);
-
- pr_info(" deviceStatus: %08x\n", data->deviceStatus);
- pr_info(" slotStatus: %08x\n", data->slotStatus);
- pr_info(" linkStatus: %08x\n", data->linkStatus);
- pr_info(" devCmdStatus: %08x\n", data->devCmdStatus);
- pr_info(" devSecStatus: %08x\n", data->devSecStatus);
-
- pr_info(" rootErrorStatus: %08x\n", data->rootErrorStatus);
- pr_info(" uncorrErrorStatus: %08x\n", data->uncorrErrorStatus);
- pr_info(" corrErrorStatus: %08x\n", data->corrErrorStatus);
- pr_info(" tlpHdr1: %08x\n", data->tlpHdr1);
- pr_info(" tlpHdr2: %08x\n", data->tlpHdr2);
- pr_info(" tlpHdr3: %08x\n", data->tlpHdr3);
- pr_info(" tlpHdr4: %08x\n", data->tlpHdr4);
- pr_info(" sourceId: %08x\n", data->sourceId);
- pr_info(" errorClass: %016llx\n", data->errorClass);
- pr_info(" correlator: %016llx\n", data->correlator);
-
- pr_info(" nFir: %016llx\n", data->nFir);
- pr_info(" nFirMask: %016llx\n", data->nFirMask);
- pr_info(" nFirWOF: %016llx\n", data->nFirWOF);
- pr_info(" PhbPlssr: %016llx\n", data->phbPlssr);
- pr_info(" PhbCsr: %016llx\n", data->phbCsr);
- pr_info(" lemFir: %016llx\n", data->lemFir);
- pr_info(" lemErrorMask: %016llx\n", data->lemErrorMask);
- pr_info(" lemWOF: %016llx\n", data->lemWOF);
- pr_info(" phbErrorStatus: %016llx\n", data->phbErrorStatus);
- pr_info(" phbFirstErrorStatus: %016llx\n", data->phbFirstErrorStatus);
- pr_info(" phbErrorLog0: %016llx\n", data->phbErrorLog0);
- pr_info(" phbErrorLog1: %016llx\n", data->phbErrorLog1);
- pr_info(" mmioErrorStatus: %016llx\n", data->mmioErrorStatus);
- pr_info(" mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus);
- pr_info(" mmioErrorLog0: %016llx\n", data->mmioErrorLog0);
- pr_info(" mmioErrorLog1: %016llx\n", data->mmioErrorLog1);
- pr_info(" dma0ErrorStatus: %016llx\n", data->dma0ErrorStatus);
- pr_info(" dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus);
- pr_info(" dma0ErrorLog0: %016llx\n", data->dma0ErrorLog0);
- pr_info(" dma0ErrorLog1: %016llx\n", data->dma0ErrorLog1);
- pr_info(" dma1ErrorStatus: %016llx\n", data->dma1ErrorStatus);
- pr_info(" dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus);
- pr_info(" dma1ErrorLog0: %016llx\n", data->dma1ErrorLog0);
- pr_info(" dma1ErrorLog1: %016llx\n", data->dma1ErrorLog1);
+ if (data->brdgCtl)
+ pr_info(" brdgCtl: %08x\n",
+ data->brdgCtl);
+ if (data->portStatusReg || data->rootCmplxStatus ||
+ data->busAgentStatus)
+ pr_info(" UtlSts: %08x %08x %08x\n",
+ data->portStatusReg, data->rootCmplxStatus,
+ data->busAgentStatus);
+ if (data->deviceStatus || data->slotStatus ||
+ data->linkStatus || data->devCmdStatus ||
+ data->devSecStatus)
+ pr_info(" RootSts: %08x %08x %08x %08x %08x\n",
+ data->deviceStatus, data->slotStatus,
+ data->linkStatus, data->devCmdStatus,
+ data->devSecStatus);
+ if (data->rootErrorStatus || data->uncorrErrorStatus ||
+ data->corrErrorStatus)
+ pr_info(" RootErrSts: %08x %08x %08x\n",
+ data->rootErrorStatus, data->uncorrErrorStatus,
+ data->corrErrorStatus);
+ if (data->tlpHdr1 || data->tlpHdr2 ||
+ data->tlpHdr3 || data->tlpHdr4)
+ pr_info(" RootErrLog: %08x %08x %08x %08x\n",
+ data->tlpHdr1, data->tlpHdr2,
+ data->tlpHdr3, data->tlpHdr4);
+ if (data->sourceId || data->errorClass ||
+ data->correlator)
+ pr_info(" RootErrLog1: %08x %016llx %016llx\n",
+ data->sourceId, data->errorClass,
+ data->correlator);
+ if (data->nFir || data->nFirMask ||
+ data->nFirWOF)
+ pr_info(" nFir: %016llx %016llx %016llx\n",
+ data->nFir, data->nFirMask,
+ data->nFirWOF);
+ if (data->phbPlssr || data->phbCsr)
+ pr_info(" PhbSts: %016llx %016llx\n",
+ data->phbPlssr, data->phbCsr);
+ if (data->lemFir || data->lemErrorMask ||
+ data->lemWOF)
+ pr_info(" Lem: %016llx %016llx %016llx\n",
+ data->lemFir, data->lemErrorMask,
+ data->lemWOF);
+ if (data->phbErrorStatus || data->phbFirstErrorStatus ||
+ data->phbErrorLog0 || data->phbErrorLog1)
+ pr_info(" PhbErr: %016llx %016llx %016llx %016llx\n",
+ data->phbErrorStatus, data->phbFirstErrorStatus,
+ data->phbErrorLog0, data->phbErrorLog1);
+ if (data->mmioErrorStatus || data->mmioFirstErrorStatus ||
+ data->mmioErrorLog0 || data->mmioErrorLog1)
+ pr_info(" OutErr: %016llx %016llx %016llx %016llx\n",
+ data->mmioErrorStatus, data->mmioFirstErrorStatus,
+ data->mmioErrorLog0, data->mmioErrorLog1);
+ if (data->dma0ErrorStatus || data->dma0FirstErrorStatus ||
+ data->dma0ErrorLog0 || data->dma0ErrorLog1)
+ pr_info(" InAErr: %016llx %016llx %016llx %016llx\n",
+ data->dma0ErrorStatus, data->dma0FirstErrorStatus,
+ data->dma0ErrorLog0, data->dma0ErrorLog1);
+ if (data->dma1ErrorStatus || data->dma1FirstErrorStatus ||
+ data->dma1ErrorLog0 || data->dma1ErrorLog1)
+ pr_info(" InBErr: %016llx %016llx %016llx %016llx\n",
+ data->dma1ErrorStatus, data->dma1FirstErrorStatus,
+ data->dma1ErrorLog0, data->dma1ErrorLog1);
for (i = 0; i < OPAL_PHB3_NUM_PEST_REGS; i++) {
if ((data->pestA[i] >> 63) == 0 &&
(data->pestB[i] >> 63) == 0)
continue;
- pr_info(" PE[%3d] PESTA: %016llx\n", i, data->pestA[i]);
- pr_info(" PESTB: %016llx\n", data->pestB[i]);
+ pr_info(" PE[%3d] A/B: %016llx %016llx\n",
+ i, data->pestA[i], data->pestB[i]);
}
}
@@ -634,6 +664,16 @@ static void pnv_pci_dma_dev_setup(struct pci_dev *pdev)
pnv_pci_dma_fallback_setup(hose, pdev);
}
+int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask)
+{
+ struct pci_controller *hose = pci_bus_to_host(pdev->bus);
+ struct pnv_phb *phb = hose->private_data;
+
+ if (phb && phb->dma_set_mask)
+ return phb->dma_set_mask(phb, pdev, dma_mask);
+ return __dma_set_mask(&pdev->dev, dma_mask);
+}
+
void pnv_pci_shutdown(void)
{
struct pci_controller *hose;
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
index 13f1942a9a5f..cde169442775 100644
--- a/arch/powerpc/platforms/powernv/pci.h
+++ b/arch/powerpc/platforms/powernv/pci.h
@@ -54,7 +54,9 @@ struct pnv_ioda_pe {
struct iommu_table tce32_table;
phys_addr_t tce_inval_reg_phys;
- /* XXX TODO: Add support for additional 64-bit iommus */
+ /* 64-bit TCE bypass region */
+ bool tce_bypass_enabled;
+ uint64_t tce_bypass_base;
/* MSIs. MVE index is identical for for 32 and 64 bit MSI
* and -1 if not supported. (It's actually identical to the
@@ -113,6 +115,8 @@ struct pnv_phb {
unsigned int hwirq, unsigned int virq,
unsigned int is_64, struct msi_msg *msg);
void (*dma_dev_setup)(struct pnv_phb *phb, struct pci_dev *pdev);
+ int (*dma_set_mask)(struct pnv_phb *phb, struct pci_dev *pdev,
+ u64 dma_mask);
void (*fixup_phb)(struct pci_controller *hose);
u32 (*bdfn_to_pe)(struct pnv_phb *phb, struct pci_bus *bus, u32 devfn);
void (*shutdown)(struct pnv_phb *phb);
diff --git a/arch/powerpc/platforms/powernv/powernv.h b/arch/powerpc/platforms/powernv/powernv.h
index de6819be1f95..0051e108ef0f 100644
--- a/arch/powerpc/platforms/powernv/powernv.h
+++ b/arch/powerpc/platforms/powernv/powernv.h
@@ -7,12 +7,20 @@ extern void pnv_smp_init(void);
static inline void pnv_smp_init(void) { }
#endif
+struct pci_dev;
+
#ifdef CONFIG_PCI
extern void pnv_pci_init(void);
extern void pnv_pci_shutdown(void);
+extern int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask);
#else
static inline void pnv_pci_init(void) { }
static inline void pnv_pci_shutdown(void) { }
+
+static inline int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask)
+{
+ return -ENODEV;
+}
#endif
extern void pnv_lpc_init(void);
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
index 21166f65c97c..61cf8fa9c61b 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -26,7 +26,7 @@
#include <linux/of_fdt.h>
#include <linux/interrupt.h>
#include <linux/bug.h>
-#include <linux/cpuidle.h>
+#include <linux/pci.h>
#include <asm/machdep.h>
#include <asm/firmware.h>
@@ -141,6 +141,13 @@ static void pnv_progress(char *s, unsigned short hex)
{
}
+static int pnv_dma_set_mask(struct device *dev, u64 dma_mask)
+{
+ if (dev_is_pci(dev))
+ return pnv_pci_dma_set_mask(to_pci_dev(dev), dma_mask);
+ return __dma_set_mask(dev, dma_mask);
+}
+
static void pnv_shutdown(void)
{
/* Let the PCI code clear up IODA tables */
@@ -180,6 +187,7 @@ static void __init pnv_setup_machdep_opal(void)
ppc_md.power_off = pnv_power_off;
ppc_md.halt = pnv_halt;
ppc_md.machine_check_exception = opal_machine_check;
+ ppc_md.mce_check_early_recovery = opal_mce_check_early_recovery;
}
#ifdef CONFIG_PPC_POWERNV_RTAS
@@ -217,16 +225,6 @@ static int __init pnv_probe(void)
return 1;
}
-void powernv_idle(void)
-{
- /* Hook to cpuidle framework if available, else
- * call on default platform idle code
- */
- if (cpuidle_idle_call()) {
- power7_idle();
- }
-}
-
define_machine(powernv) {
.name = "PowerNV",
.probe = pnv_probe,
@@ -236,8 +234,9 @@ define_machine(powernv) {
.show_cpuinfo = pnv_show_cpuinfo,
.progress = pnv_progress,
.machine_shutdown = pnv_shutdown,
- .power_save = powernv_idle,
+ .power_save = power7_idle,
.calibrate_decr = generic_calibrate_decr,
+ .dma_set_mask = pnv_dma_set_mask,
#ifdef CONFIG_KEXEC
.kexec_cpu_down = pnv_kexec_cpu_down,
#endif
diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig
index e87c19473973..56f274064d6c 100644
--- a/arch/powerpc/platforms/ps3/Kconfig
+++ b/arch/powerpc/platforms/ps3/Kconfig
@@ -2,10 +2,8 @@ config PPC_PS3
bool "Sony PS3"
depends on PPC64 && PPC_BOOK3S
select PPC_CELL
- select USB_ARCH_HAS_OHCI
select USB_OHCI_LITTLE_ENDIAN
select USB_OHCI_BIG_ENDIAN_MMIO
- select USB_ARCH_HAS_EHCI
select USB_EHCI_BIG_ENDIAN_MMIO
select PPC_PCI_CHOICE
help
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c
index 4b35166229fe..b358bec6c8cb 100644
--- a/arch/powerpc/platforms/ps3/smp.c
+++ b/arch/powerpc/platforms/ps3/smp.c
@@ -76,7 +76,7 @@ static int __init ps3_smp_probe(void)
BUILD_BUG_ON(PPC_MSG_CALL_FUNCTION != 0);
BUILD_BUG_ON(PPC_MSG_RESCHEDULE != 1);
- BUILD_BUG_ON(PPC_MSG_CALL_FUNC_SINGLE != 2);
+ BUILD_BUG_ON(PPC_MSG_TICK_BROADCAST != 2);
BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3);
for (i = 0; i < MSG_COUNT; i++) {
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index 37300f6ee244..2cb8b776c84a 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -20,6 +20,7 @@ config PPC_PSERIES
select PPC_DOORBELL
select HAVE_CONTEXT_TRACKING
select HOTPLUG_CPU if SMP
+ select ARCH_RANDOM
default y
config PPC_SPLPAR
@@ -110,6 +111,18 @@ config CMM
will be reused for other LPARs. The interface allows firmware to
balance memory across many LPARs.
+config HV_PERF_CTRS
+ bool "Hypervisor supplied PMU events (24x7 & GPCI)"
+ default y
+ depends on PERF_EVENTS && PPC_PSERIES
+ help
+ Enable access to hypervisor supplied counters in perf. Currently,
+ this enables code that uses the hcall GetPerfCounterInfo and 24x7
+ interfaces to retrieve counters. GPCI exists on Power 6 and later
+ systems. 24x7 is available on Power 8 systems.
+
+ If unsure, select Y.
+
config DTL
bool "Dispatch Trace Log"
depends on PPC_SPLPAR && DEBUG_FS
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index a8fe5aa3d34f..022b38e6a80b 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -11,7 +11,6 @@
*/
#include <linux/kernel.h>
-#include <linux/kref.h>
#include <linux/notifier.h>
#include <linux/spinlock.h>
#include <linux/cpu.h>
@@ -87,7 +86,6 @@ static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa,
}
of_node_set_flag(dn, OF_DYNAMIC);
- kref_init(&dn->kref);
return dn;
}
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
index 9ef3cc8ebc11..8a8f0472d98f 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -265,7 +265,7 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag)
enable = 1;
if (enable) {
- eeh_subsystem_enabled = 1;
+ eeh_set_enable(true);
eeh_add_to_parent_pe(edev);
pr_debug("%s: EEH enabled on %s PHB#%d-PE#%x, config addr#%x\n",
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index 82789e79e539..9b8e05078a63 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -35,12 +35,7 @@
#include "offline_states.h"
/* This version can't take the spinlock, because it never returns */
-static struct rtas_args rtas_stop_self_args = {
- .token = RTAS_UNKNOWN_SERVICE,
- .nargs = 0,
- .nret = 1,
- .rets = &rtas_stop_self_args.args[0],
-};
+static int rtas_stop_self_token = RTAS_UNKNOWN_SERVICE;
static DEFINE_PER_CPU(enum cpu_state_vals, preferred_offline_state) =
CPU_STATE_OFFLINE;
@@ -93,15 +88,20 @@ void set_default_offline_state(int cpu)
static void rtas_stop_self(void)
{
- struct rtas_args *args = &rtas_stop_self_args;
+ struct rtas_args args = {
+ .token = cpu_to_be32(rtas_stop_self_token),
+ .nargs = 0,
+ .nret = 1,
+ .rets = &args.args[0],
+ };
local_irq_disable();
- BUG_ON(args->token == RTAS_UNKNOWN_SERVICE);
+ BUG_ON(rtas_stop_self_token == RTAS_UNKNOWN_SERVICE);
printk("cpu %u (hwid %u) Ready to die...\n",
smp_processor_id(), hard_smp_processor_id());
- enter_rtas(__pa(args));
+ enter_rtas(__pa(&args));
panic("Alas, I survived.\n");
}
@@ -392,10 +392,10 @@ static int __init pseries_cpu_hotplug_init(void)
}
}
- rtas_stop_self_args.token = rtas_token("stop-self");
+ rtas_stop_self_token = rtas_token("stop-self");
qcss_tok = rtas_token("query-cpu-stopped-state");
- if (rtas_stop_self_args.token == RTAS_UNKNOWN_SERVICE ||
+ if (rtas_stop_self_token == RTAS_UNKNOWN_SERVICE ||
qcss_tok == RTAS_UNKNOWN_SERVICE) {
printk(KERN_INFO "CPU Hotplug not supported by firmware "
"- disabling.\n");
@@ -420,4 +420,4 @@ static int __init pseries_cpu_hotplug_init(void)
return 0;
}
-arch_initcall(pseries_cpu_hotplug_init);
+machine_arch_initcall(pseries, pseries_cpu_hotplug_init);
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index 9590dbb756f2..573b488fc48b 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -14,6 +14,7 @@
#include <linux/memblock.h>
#include <linux/vmalloc.h>
#include <linux/memory.h>
+#include <linux/memory_hotplug.h>
#include <asm/firmware.h>
#include <asm/machdep.h>
@@ -75,13 +76,27 @@ unsigned long memory_block_size_bytes(void)
}
#ifdef CONFIG_MEMORY_HOTREMOVE
-static int pseries_remove_memblock(unsigned long base, unsigned int memblock_size)
+static int pseries_remove_memory(u64 start, u64 size)
{
- unsigned long start, start_pfn;
- struct zone *zone;
int ret;
- unsigned long section;
- unsigned long sections_to_remove;
+
+ /* Remove htab bolted mappings for this section of memory */
+ start = (unsigned long)__va(start);
+ ret = remove_section_mapping(start, start + size);
+
+ /* Ensure all vmalloc mappings are flushed in case they also
+ * hit that section of memory
+ */
+ vm_unmap_aliases();
+
+ return ret;
+}
+
+static int pseries_remove_memblock(unsigned long base, unsigned int memblock_size)
+{
+ unsigned long block_sz, start_pfn;
+ int sections_per_block;
+ int i, nid;
start_pfn = base >> PAGE_SHIFT;
@@ -90,45 +105,21 @@ static int pseries_remove_memblock(unsigned long base, unsigned int memblock_siz
return 0;
}
- zone = page_zone(pfn_to_page(start_pfn));
+ block_sz = memory_block_size_bytes();
+ sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
+ nid = memory_add_physaddr_to_nid(base);
- /*
- * Remove section mappings and sysfs entries for the
- * section of the memory we are removing.
- *
- * NOTE: Ideally, this should be done in generic code like
- * remove_memory(). But remove_memory() gets called by writing
- * to sysfs "state" file and we can't remove sysfs entries
- * while writing to it. So we have to defer it to here.
- */
- sections_to_remove = (memblock_size >> PAGE_SHIFT) / PAGES_PER_SECTION;
- for (section = 0; section < sections_to_remove; section++) {
- unsigned long pfn = start_pfn + section * PAGES_PER_SECTION;
- ret = __remove_pages(zone, pfn, PAGES_PER_SECTION);
- if (ret)
- return ret;
+ for (i = 0; i < sections_per_block; i++) {
+ remove_memory(nid, base, MIN_MEMORY_BLOCK_SIZE);
+ base += MIN_MEMORY_BLOCK_SIZE;
}
- /*
- * Update memory regions for memory remove
- */
+ /* Update memory regions for memory remove */
memblock_remove(base, memblock_size);
-
- /*
- * Remove htab bolted mappings for this section of memory
- */
- start = (unsigned long)__va(base);
- ret = remove_section_mapping(start, start + memblock_size);
-
- /* Ensure all vmalloc mappings are flushed in case they also
- * hit that section of memory
- */
- vm_unmap_aliases();
-
- return ret;
+ return 0;
}
-static int pseries_remove_memory(struct device_node *np)
+static int pseries_remove_mem_node(struct device_node *np)
{
const char *type;
const unsigned int *regs;
@@ -153,8 +144,8 @@ static int pseries_remove_memory(struct device_node *np)
base = *(unsigned long *)regs;
lmb_size = regs[3];
- ret = pseries_remove_memblock(base, lmb_size);
- return ret;
+ pseries_remove_memblock(base, lmb_size);
+ return 0;
}
#else
static inline int pseries_remove_memblock(unsigned long base,
@@ -162,13 +153,13 @@ static inline int pseries_remove_memblock(unsigned long base,
{
return -EOPNOTSUPP;
}
-static inline int pseries_remove_memory(struct device_node *np)
+static inline int pseries_remove_mem_node(struct device_node *np)
{
return -EOPNOTSUPP;
}
#endif /* CONFIG_MEMORY_HOTREMOVE */
-static int pseries_add_memory(struct device_node *np)
+static int pseries_add_mem_node(struct device_node *np)
{
const char *type;
const unsigned int *regs;
@@ -254,10 +245,10 @@ static int pseries_memory_notifier(struct notifier_block *nb,
switch (action) {
case OF_RECONFIG_ATTACH_NODE:
- err = pseries_add_memory(node);
+ err = pseries_add_mem_node(node);
break;
case OF_RECONFIG_DETACH_NODE:
- err = pseries_remove_memory(node);
+ err = pseries_remove_mem_node(node);
break;
case OF_RECONFIG_UPDATE_PROPERTY:
pr = (struct of_prop_reconfig *)node;
@@ -277,6 +268,10 @@ static int __init pseries_memory_hotplug_init(void)
if (firmware_has_feature(FW_FEATURE_LPAR))
of_reconfig_notifier_register(&pseries_mem_nb);
+#ifdef CONFIG_MEMORY_HOTREMOVE
+ ppc_md.remove_memory = pseries_remove_memory;
+#endif
+
return 0;
}
machine_device_initcall(pseries, pseries_memory_hotplug_init);
diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c
index cde4e0a095ae..bde7ebad3949 100644
--- a/arch/powerpc/platforms/pseries/mobility.c
+++ b/arch/powerpc/platforms/pseries/mobility.c
@@ -290,13 +290,6 @@ void post_mobility_fixup(void)
int rc;
int activate_fw_token;
- rc = pseries_devicetree_update(MIGRATION_SCOPE);
- if (rc) {
- printk(KERN_ERR "Initial post-mobility device tree update "
- "failed: %d\n", rc);
- return;
- }
-
activate_fw_token = rtas_token("ibm,activate-firmware");
if (activate_fw_token == RTAS_UNKNOWN_SERVICE) {
printk(KERN_ERR "Could not make post-mobility "
@@ -304,16 +297,17 @@ void post_mobility_fixup(void)
return;
}
- rc = rtas_call(activate_fw_token, 0, 1, NULL);
- if (!rc) {
- rc = pseries_devicetree_update(MIGRATION_SCOPE);
- if (rc)
- printk(KERN_ERR "Secondary post-mobility device tree "
- "update failed: %d\n", rc);
- } else {
+ do {
+ rc = rtas_call(activate_fw_token, 0, 1, NULL);
+ } while (rtas_busy_delay(rc));
+
+ if (rc)
printk(KERN_ERR "Post-mobility activate-fw failed: %d\n", rc);
- return;
- }
+
+ rc = pseries_devicetree_update(MIGRATION_SCOPE);
+ if (rc)
+ printk(KERN_ERR "Post-mobility device tree update "
+ "failed: %d\n", rc);
return;
}
diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c
index 70670a2d9cf2..c413ec158ff5 100644
--- a/arch/powerpc/platforms/pseries/pci.c
+++ b/arch/powerpc/platforms/pseries/pci.c
@@ -113,7 +113,8 @@ int pseries_root_bridge_prepare(struct pci_host_bridge *bridge)
{
struct device_node *dn, *pdn;
struct pci_bus *bus;
- const __be32 *pcie_link_speed_stats;
+ u32 pcie_link_speed_stats[2];
+ int rc;
bus = bridge->bus;
@@ -122,38 +123,45 @@ int pseries_root_bridge_prepare(struct pci_host_bridge *bridge)
return 0;
for (pdn = dn; pdn != NULL; pdn = of_get_next_parent(pdn)) {
- pcie_link_speed_stats = of_get_property(pdn,
- "ibm,pcie-link-speed-stats", NULL);
- if (pcie_link_speed_stats)
+ rc = of_property_read_u32_array(pdn,
+ "ibm,pcie-link-speed-stats",
+ &pcie_link_speed_stats[0], 2);
+ if (!rc)
break;
}
of_node_put(pdn);
- if (!pcie_link_speed_stats) {
+ if (rc) {
pr_err("no ibm,pcie-link-speed-stats property\n");
return 0;
}
- switch (be32_to_cpup(pcie_link_speed_stats)) {
+ switch (pcie_link_speed_stats[0]) {
case 0x01:
bus->max_bus_speed = PCIE_SPEED_2_5GT;
break;
case 0x02:
bus->max_bus_speed = PCIE_SPEED_5_0GT;
break;
+ case 0x04:
+ bus->max_bus_speed = PCIE_SPEED_8_0GT;
+ break;
default:
bus->max_bus_speed = PCI_SPEED_UNKNOWN;
break;
}
- switch (be32_to_cpup(pcie_link_speed_stats)) {
+ switch (pcie_link_speed_stats[1]) {
case 0x01:
bus->cur_bus_speed = PCIE_SPEED_2_5GT;
break;
case 0x02:
bus->cur_bus_speed = PCIE_SPEED_5_0GT;
break;
+ case 0x04:
+ bus->cur_bus_speed = PCIE_SPEED_8_0GT;
+ break;
default:
bus->cur_bus_speed = PCI_SPEED_UNKNOWN;
break;
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c
index efe61374f6ea..203cbf0dc101 100644
--- a/arch/powerpc/platforms/pseries/pci_dlpar.c
+++ b/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -37,15 +37,15 @@ find_bus_among_children(struct pci_bus *bus,
struct device_node *dn)
{
struct pci_bus *child = NULL;
- struct list_head *tmp;
+ struct pci_bus *tmp;
struct device_node *busdn;
busdn = pci_bus_to_OF_node(bus);
if (busdn == dn)
return bus;
- list_for_each(tmp, &bus->children) {
- child = find_bus_among_children(pci_bus_b(tmp), dn);
+ list_for_each_entry(tmp, &bus->children, node) {
+ child = find_bus_among_children(tmp, dn);
if (child)
break;
};
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
index f93cdf55628c..0435bb65d0aa 100644
--- a/arch/powerpc/platforms/pseries/reconfig.c
+++ b/arch/powerpc/platforms/pseries/reconfig.c
@@ -12,7 +12,6 @@
*/
#include <linux/kernel.h>
-#include <linux/kref.h>
#include <linux/notifier.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
@@ -70,7 +69,6 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist
np->properties = proplist;
of_node_set_flag(np, OF_DYNAMIC);
- kref_init(&np->kref);
np->parent = derive_parent(path);
if (IS_ERR(np->parent)) {
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 8e639d7cbda7..2db8cc691bf4 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -39,7 +39,6 @@
#include <linux/irq.h>
#include <linux/seq_file.h>
#include <linux/root_dev.h>
-#include <linux/cpuidle.h>
#include <linux/of.h>
#include <linux/kexec.h>
@@ -356,29 +355,24 @@ early_initcall(alloc_dispatch_log_kmem_cache);
static void pseries_lpar_idle(void)
{
- /* This would call on the cpuidle framework, and the back-end pseries
- * driver to go to idle states
+ /*
+ * Default handler to go into low thread priority and possibly
+ * low power mode by cedeing processor to hypervisor
*/
- if (cpuidle_idle_call()) {
- /* On error, execute default handler
- * to go into low thread priority and possibly
- * low power mode by cedeing processor to hypervisor
- */
- /* Indicate to hypervisor that we are idle. */
- get_lppaca()->idle = 1;
+ /* Indicate to hypervisor that we are idle. */
+ get_lppaca()->idle = 1;
- /*
- * Yield the processor to the hypervisor. We return if
- * an external interrupt occurs (which are driven prior
- * to returning here) or if a prod occurs from another
- * processor. When returning here, external interrupts
- * are enabled.
- */
- cede_processor();
+ /*
+ * Yield the processor to the hypervisor. We return if
+ * an external interrupt occurs (which are driven prior
+ * to returning here) or if a prod occurs from another
+ * processor. When returning here, external interrupts
+ * are enabled.
+ */
+ cede_processor();
- get_lppaca()->idle = 0;
- }
+ get_lppaca()->idle = 0;
}
/*
@@ -430,8 +424,7 @@ static void pSeries_machine_kexec(struct kimage *image)
{
long rc;
- if (firmware_has_feature(FW_FEATURE_SET_MODE) &&
- (image->type != KEXEC_TYPE_CRASH)) {
+ if (firmware_has_feature(FW_FEATURE_SET_MODE)) {
rc = pSeries_disable_reloc_on_exc();
if (rc != H_SUCCESS)
pr_warning("Warning: Failed to disable relocation on "
diff --git a/arch/powerpc/platforms/pseries/suspend.c b/arch/powerpc/platforms/pseries/suspend.c
index 16a255255d30..b87b97849d4c 100644
--- a/arch/powerpc/platforms/pseries/suspend.c
+++ b/arch/powerpc/platforms/pseries/suspend.c
@@ -26,6 +26,7 @@
#include <asm/mmu.h>
#include <asm/rtas.h>
#include <asm/topology.h>
+#include "../../kernel/cacheinfo.h"
static u64 stream_id;
static struct device suspend_dev;
@@ -79,6 +80,23 @@ static int pseries_suspend_cpu(void)
}
/**
+ * pseries_suspend_enable_irqs
+ *
+ * Post suspend configuration updates
+ *
+ **/
+static void pseries_suspend_enable_irqs(void)
+{
+ /*
+ * Update configuration which can be modified based on device tree
+ * changes during resume.
+ */
+ cacheinfo_cpu_offline(smp_processor_id());
+ post_mobility_fixup();
+ cacheinfo_cpu_online(smp_processor_id());
+}
+
+/**
* pseries_suspend_enter - Final phase of hibernation
*
* Return value:
@@ -174,7 +192,30 @@ out:
return rc;
}
-static DEVICE_ATTR(hibernate, S_IWUSR, NULL, store_hibernate);
+#define USER_DT_UPDATE 0
+#define KERN_DT_UPDATE 1
+
+/**
+ * show_hibernate - Report device tree update responsibilty
+ * @dev: subsys root device
+ * @attr: device attribute struct
+ * @buf: buffer
+ *
+ * Report whether a device tree update is performed by the kernel after a
+ * resume, or if drmgr must coordinate the update from user space.
+ *
+ * Return value:
+ * 0 if drmgr is to initiate update, and 1 otherwise
+ **/
+static ssize_t show_hibernate(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", KERN_DT_UPDATE);
+}
+
+static DEVICE_ATTR(hibernate, S_IWUSR | S_IRUGO,
+ show_hibernate, store_hibernate);
static struct bus_type suspend_subsys = {
.name = "power",
@@ -235,6 +276,7 @@ static int __init pseries_suspend_init(void)
return rc;
ppc_md.suspend_disable_cpu = pseries_suspend_cpu;
+ ppc_md.suspend_enable_irqs = pseries_suspend_enable_irqs;
suspend_set_ops(&pseries_suspend_ops);
return 0;
}
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index f67ac900d870..afbcc37aa094 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -21,7 +21,6 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o fsl_mpic_err.o
obj-$(CONFIG_FSL_PCI) += fsl_pci.o $(fsl-msi-obj-y)
obj-$(CONFIG_FSL_PMC) += fsl_pmc.o
obj-$(CONFIG_FSL_LBC) += fsl_lbc.o
-obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
obj-$(CONFIG_FSL_GTM) += fsl_gtm.o
obj-$(CONFIG_FSL_85XX_CACHE_SRAM) += fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o
obj-$(CONFIG_SIMPLE_GPIO) += simple_gpio.o
diff --git a/arch/powerpc/sysdev/ehv_pic.c b/arch/powerpc/sysdev/ehv_pic.c
index b74085cea1af..2d20f10a4203 100644
--- a/arch/powerpc/sysdev/ehv_pic.c
+++ b/arch/powerpc/sysdev/ehv_pic.c
@@ -28,8 +28,6 @@
#include <asm/ehv_pic.h>
#include <asm/fsl_hcalls.h>
-#include "../../../kernel/irq/settings.h"
-
static struct ehv_pic *global_ehv_pic;
static DEFINE_SPINLOCK(ehv_pic_lock);
@@ -113,17 +111,13 @@ static unsigned int ehv_pic_type_to_vecpri(unsigned int type)
int ehv_pic_set_irq_type(struct irq_data *d, unsigned int flow_type)
{
unsigned int src = virq_to_hw(d->irq);
- struct irq_desc *desc = irq_to_desc(d->irq);
unsigned int vecpri, vold, vnew, prio, cpu_dest;
unsigned long flags;
if (flow_type == IRQ_TYPE_NONE)
flow_type = IRQ_TYPE_LEVEL_LOW;
- irq_settings_clr_level(desc);
- irq_settings_set_trigger_mask(desc, flow_type);
- if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
- irq_settings_set_level(desc);
+ irqd_set_trigger_type(d, flow_type);
vecpri = ehv_pic_type_to_vecpri(flow_type);
@@ -144,7 +138,7 @@ int ehv_pic_set_irq_type(struct irq_data *d, unsigned int flow_type)
ev_int_set_config(src, vecpri, prio, cpu_dest);
spin_unlock_irqrestore(&ehv_pic_lock, flags);
- return 0;
+ return IRQ_SET_MASK_OK_NOCOPY;
}
static struct irq_chip ehv_pic_irq_chip = {
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index a625dcf26b2b..3f415e252ea5 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -22,10 +22,13 @@
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/bootmem.h>
#include <linux/memblock.h>
#include <linux/log2.h>
#include <linux/slab.h>
+#include <linux/suspend.h>
+#include <linux/syscore_ops.h>
#include <linux/uaccess.h>
#include <asm/io.h>
@@ -868,6 +871,14 @@ u64 fsl_pci_immrbar_base(struct pci_controller *hose)
pci_bus_read_config_dword(hose->bus,
PCI_DEVFN(0, 0), PCI_BASE_ADDRESS_0, &base);
+
+ /*
+ * For PEXCSRBAR, bit 3-0 indicate prefetchable and
+ * address type. So when getting base address, these
+ * bits should be masked
+ */
+ base &= PCI_BASE_ADDRESS_MEM_MASK;
+
return base;
}
#endif
@@ -1086,55 +1097,171 @@ void fsl_pci_assign_primary(void)
}
}
-static int fsl_pci_probe(struct platform_device *pdev)
+#ifdef CONFIG_PM_SLEEP
+static irqreturn_t fsl_pci_pme_handle(int irq, void *dev_id)
{
- int ret;
- struct device_node *node;
+ struct pci_controller *hose = dev_id;
+ struct ccsr_pci __iomem *pci = hose->private_data;
+ u32 dr;
- node = pdev->dev.of_node;
- ret = fsl_add_bridge(pdev, fsl_pci_primary == node);
+ dr = in_be32(&pci->pex_pme_mes_dr);
+ if (!dr)
+ return IRQ_NONE;
- mpc85xx_pci_err_probe(pdev);
+ out_be32(&pci->pex_pme_mes_dr, dr);
- return 0;
+ return IRQ_HANDLED;
}
-#ifdef CONFIG_PM
-static int fsl_pci_resume(struct device *dev)
+static int fsl_pci_pme_probe(struct pci_controller *hose)
{
- struct pci_controller *hose;
- struct resource pci_rsrc;
+ struct ccsr_pci __iomem *pci;
+ struct pci_dev *dev;
+ int pme_irq;
+ int res;
+ u16 pms;
- hose = pci_find_hose_for_OF_device(dev->of_node);
- if (!hose)
- return -ENODEV;
+ /* Get hose's pci_dev */
+ dev = list_first_entry(&hose->bus->devices, typeof(*dev), bus_list);
+
+ /* PME Disable */
+ pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pms);
+ pms &= ~PCI_PM_CTRL_PME_ENABLE;
+ pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pms);
+
+ pme_irq = irq_of_parse_and_map(hose->dn, 0);
+ if (!pme_irq) {
+ dev_err(&dev->dev, "Failed to map PME interrupt.\n");
+
+ return -ENXIO;
+ }
+
+ res = devm_request_irq(hose->parent, pme_irq,
+ fsl_pci_pme_handle,
+ IRQF_SHARED,
+ "[PCI] PME", hose);
+ if (res < 0) {
+ dev_err(&dev->dev, "Unable to requiest irq %d for PME\n", pme_irq);
+ irq_dispose_mapping(pme_irq);
- if (of_address_to_resource(dev->of_node, 0, &pci_rsrc)) {
- dev_err(dev, "Get pci register base failed.");
return -ENODEV;
}
- setup_pci_atmu(hose);
+ pci = hose->private_data;
+
+ /* Enable PTOD, ENL23D & EXL23D */
+ out_be32(&pci->pex_pme_mes_disr, 0);
+ setbits32(&pci->pex_pme_mes_disr,
+ PME_DISR_EN_PTOD | PME_DISR_EN_ENL23D | PME_DISR_EN_EXL23D);
+
+ out_be32(&pci->pex_pme_mes_ier, 0);
+ setbits32(&pci->pex_pme_mes_ier,
+ PME_DISR_EN_PTOD | PME_DISR_EN_ENL23D | PME_DISR_EN_EXL23D);
+
+ /* PME Enable */
+ pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pms);
+ pms |= PCI_PM_CTRL_PME_ENABLE;
+ pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pms);
return 0;
}
-static const struct dev_pm_ops pci_pm_ops = {
- .resume = fsl_pci_resume,
-};
+static void send_pme_turnoff_message(struct pci_controller *hose)
+{
+ struct ccsr_pci __iomem *pci = hose->private_data;
+ u32 dr;
+ int i;
-#define PCI_PM_OPS (&pci_pm_ops)
+ /* Send PME_Turn_Off Message Request */
+ setbits32(&pci->pex_pmcr, PEX_PMCR_PTOMR);
-#else
+ /* Wait trun off done */
+ for (i = 0; i < 150; i++) {
+ dr = in_be32(&pci->pex_pme_mes_dr);
+ if (dr) {
+ out_be32(&pci->pex_pme_mes_dr, dr);
+ break;
+ }
+
+ udelay(1000);
+ }
+}
+
+static void fsl_pci_syscore_do_suspend(struct pci_controller *hose)
+{
+ send_pme_turnoff_message(hose);
+}
+
+static int fsl_pci_syscore_suspend(void)
+{
+ struct pci_controller *hose, *tmp;
-#define PCI_PM_OPS NULL
+ list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
+ fsl_pci_syscore_do_suspend(hose);
+ return 0;
+}
+
+static void fsl_pci_syscore_do_resume(struct pci_controller *hose)
+{
+ struct ccsr_pci __iomem *pci = hose->private_data;
+ u32 dr;
+ int i;
+
+ /* Send Exit L2 State Message */
+ setbits32(&pci->pex_pmcr, PEX_PMCR_EXL2S);
+
+ /* Wait exit done */
+ for (i = 0; i < 150; i++) {
+ dr = in_be32(&pci->pex_pme_mes_dr);
+ if (dr) {
+ out_be32(&pci->pex_pme_mes_dr, dr);
+ break;
+ }
+
+ udelay(1000);
+ }
+
+ setup_pci_atmu(hose);
+}
+
+static void fsl_pci_syscore_resume(void)
+{
+ struct pci_controller *hose, *tmp;
+
+ list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
+ fsl_pci_syscore_do_resume(hose);
+}
+
+static struct syscore_ops pci_syscore_pm_ops = {
+ .suspend = fsl_pci_syscore_suspend,
+ .resume = fsl_pci_syscore_resume,
+};
#endif
+void fsl_pcibios_fixup_phb(struct pci_controller *phb)
+{
+#ifdef CONFIG_PM_SLEEP
+ fsl_pci_pme_probe(phb);
+#endif
+}
+
+static int fsl_pci_probe(struct platform_device *pdev)
+{
+ struct device_node *node;
+ int ret;
+
+ node = pdev->dev.of_node;
+ ret = fsl_add_bridge(pdev, fsl_pci_primary == node);
+
+ mpc85xx_pci_err_probe(pdev);
+
+ return 0;
+}
+
static struct platform_driver fsl_pci_driver = {
.driver = {
.name = "fsl-pci",
- .pm = PCI_PM_OPS,
.of_match_table = pci_ids,
},
.probe = fsl_pci_probe,
@@ -1142,6 +1269,9 @@ static struct platform_driver fsl_pci_driver = {
static int __init fsl_pci_init(void)
{
+#ifdef CONFIG_PM_SLEEP
+ register_syscore_ops(&pci_syscore_pm_ops);
+#endif
return platform_driver_register(&fsl_pci_driver);
}
arch_initcall(fsl_pci_init);
diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h
index 8d455df58471..c1cec771d5ea 100644
--- a/arch/powerpc/sysdev/fsl_pci.h
+++ b/arch/powerpc/sysdev/fsl_pci.h
@@ -32,6 +32,13 @@ struct platform_device;
#define PIWAR_WRITE_SNOOP 0x00005000
#define PIWAR_SZ_MASK 0x0000003f
+#define PEX_PMCR_PTOMR 0x1
+#define PEX_PMCR_EXL2S 0x2
+
+#define PME_DISR_EN_PTOD 0x00008000
+#define PME_DISR_EN_ENL23D 0x00002000
+#define PME_DISR_EN_EXL23D 0x00001000
+
/* PCI/PCI Express outbound window reg */
struct pci_outbound_window_regs {
__be32 potar; /* 0x.0 - Outbound translation address register */
@@ -111,6 +118,7 @@ struct ccsr_pci {
extern int fsl_add_bridge(struct platform_device *pdev, int is_primary);
extern void fsl_pcibios_fixup_bus(struct pci_bus *bus);
+extern void fsl_pcibios_fixup_phb(struct pci_controller *phb);
extern int mpc83xx_add_bridge(struct device_node *dev);
u64 fsl_pci_immrbar_base(struct pci_controller *hose);
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 0e166ed4cd16..8209744b2829 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -886,25 +886,25 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type)
/* Default: read HW settings */
if (flow_type == IRQ_TYPE_DEFAULT) {
- switch(vold & (MPIC_INFO(VECPRI_POLARITY_MASK) |
- MPIC_INFO(VECPRI_SENSE_MASK))) {
- case MPIC_INFO(VECPRI_SENSE_EDGE) |
- MPIC_INFO(VECPRI_POLARITY_POSITIVE):
- flow_type = IRQ_TYPE_EDGE_RISING;
- break;
- case MPIC_INFO(VECPRI_SENSE_EDGE) |
- MPIC_INFO(VECPRI_POLARITY_NEGATIVE):
- flow_type = IRQ_TYPE_EDGE_FALLING;
- break;
- case MPIC_INFO(VECPRI_SENSE_LEVEL) |
- MPIC_INFO(VECPRI_POLARITY_POSITIVE):
- flow_type = IRQ_TYPE_LEVEL_HIGH;
- break;
- case MPIC_INFO(VECPRI_SENSE_LEVEL) |
- MPIC_INFO(VECPRI_POLARITY_NEGATIVE):
- flow_type = IRQ_TYPE_LEVEL_LOW;
- break;
- }
+ int vold_ps;
+
+ vold_ps = vold & (MPIC_INFO(VECPRI_POLARITY_MASK) |
+ MPIC_INFO(VECPRI_SENSE_MASK));
+
+ if (vold_ps == (MPIC_INFO(VECPRI_SENSE_EDGE) |
+ MPIC_INFO(VECPRI_POLARITY_POSITIVE)))
+ flow_type = IRQ_TYPE_EDGE_RISING;
+ else if (vold_ps == (MPIC_INFO(VECPRI_SENSE_EDGE) |
+ MPIC_INFO(VECPRI_POLARITY_NEGATIVE)))
+ flow_type = IRQ_TYPE_EDGE_FALLING;
+ else if (vold_ps == (MPIC_INFO(VECPRI_SENSE_LEVEL) |
+ MPIC_INFO(VECPRI_POLARITY_POSITIVE)))
+ flow_type = IRQ_TYPE_LEVEL_HIGH;
+ else if (vold_ps == (MPIC_INFO(VECPRI_SENSE_LEVEL) |
+ MPIC_INFO(VECPRI_POLARITY_NEGATIVE)))
+ flow_type = IRQ_TYPE_LEVEL_LOW;
+ else
+ WARN_ONCE(1, "mpic: unknown IRQ type %d\n", vold);
}
/* Apply to irq desc */
diff --git a/arch/powerpc/sysdev/msi_bitmap.c b/arch/powerpc/sysdev/msi_bitmap.c
index 0968b66b4cf9..8ba60424be95 100644
--- a/arch/powerpc/sysdev/msi_bitmap.c
+++ b/arch/powerpc/sysdev/msi_bitmap.c
@@ -202,7 +202,7 @@ void __init test_of_node(void)
/* There should really be a struct device_node allocator */
memset(&of_node, 0, sizeof(of_node));
- kref_init(&of_node.kref);
+ kref_init(&of_node.kobj.kref);
of_node.full_name = node_name;
check(0 == msi_bitmap_alloc(&bmp, size, &of_node));
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index a90731b3d44a..08504e75b2c7 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -171,7 +171,11 @@ extern void xmon_leave(void);
#define REG "%.8lx"
#endif
+#ifdef __LITTLE_ENDIAN__
+#define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
+#else
#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
+#endif
#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
|| ('a' <= (c) && (c) <= 'f') \
@@ -309,16 +313,23 @@ static void get_output_lock(void)
if (xmon_speaker == me)
return;
+
for (;;) {
- if (xmon_speaker == 0) {
- last_speaker = cmpxchg(&xmon_speaker, 0, me);
- if (last_speaker == 0)
- return;
- }
- timeout = 10000000;
+ last_speaker = cmpxchg(&xmon_speaker, 0, me);
+ if (last_speaker == 0)
+ return;
+
+ /*
+ * Wait a full second for the lock, we might be on a slow
+ * console, but check every 100us.
+ */
+ timeout = 10000;
while (xmon_speaker == last_speaker) {
- if (--timeout > 0)
+ if (--timeout > 0) {
+ udelay(100);
continue;
+ }
+
/* hostile takeover */
prev = cmpxchg(&xmon_speaker, last_speaker, me);
if (prev == last_speaker)
@@ -397,7 +408,6 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
}
xmon_fault_jmp[cpu] = recurse_jmp;
- cpumask_set_cpu(cpu, &cpus_in_xmon);
bp = NULL;
if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
@@ -419,6 +429,8 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
release_output_lock();
}
+ cpumask_set_cpu(cpu, &cpus_in_xmon);
+
waiting:
secondary = 1;
while (secondary && !xmon_gate) {
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 65a07750f4f9..953f17c8d17c 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -117,6 +117,7 @@ config S390
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
+ select HAVE_FUTEX_CMPXCHG if FUTEX
select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_LZ4
@@ -140,6 +141,7 @@ config S390
select OLD_SIGACTION
select OLD_SIGSUSPEND3
select SYSCTL_EXCEPTION_TRACE
+ select TTY
select VIRT_CPU_ACCOUNTING
select VIRT_TO_BUS
@@ -415,6 +417,10 @@ config ARCH_ENABLE_MEMORY_HOTPLUG
config ARCH_ENABLE_MEMORY_HOTREMOVE
def_bool y
+config ARCH_ENABLE_SPLIT_PMD_PTLOCK
+ def_bool y
+ depends on 64BIT
+
config FORCE_MAX_ZONEORDER
int
default "9"
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
index 4c4a1cef5208..47c8630c93cd 100644
--- a/arch/s390/appldata/appldata_base.c
+++ b/arch/s390/appldata/appldata_base.c
@@ -529,6 +529,7 @@ static int __init appldata_init(void)
{
int rc;
+ init_virt_timer(&appldata_timer);
appldata_timer.function = appldata_timer_function;
appldata_timer.data = (unsigned long) &appldata_work;
diff --git a/arch/s390/appldata/appldata_os.c b/arch/s390/appldata/appldata_os.c
index de8e2b3b0180..69b23b25ac34 100644
--- a/arch/s390/appldata/appldata_os.c
+++ b/arch/s390/appldata/appldata_os.c
@@ -171,7 +171,7 @@ static int __init appldata_os_init(void)
int rc, max_size;
max_size = sizeof(struct appldata_os_data) +
- (NR_CPUS * sizeof(struct appldata_os_per_cpu));
+ (num_possible_cpus() * sizeof(struct appldata_os_per_cpu));
if (max_size > APPLDATA_MAX_REC_SIZE) {
pr_err("Maximum OS record size %i exceeds the maximum "
"record size %i\n", max_size, APPLDATA_MAX_REC_SIZE);
diff --git a/arch/s390/configs/default_defconfig b/arch/s390/configs/default_defconfig
index e0af2ee58751..ddaae2f5c913 100644
--- a/arch/s390/configs/default_defconfig
+++ b/arch/s390/configs/default_defconfig
@@ -46,6 +46,7 @@ CONFIG_UNIXWARE_DISKLABEL=y
CONFIG_CFQ_GROUP_IOSCHED=y
CONFIG_DEFAULT_DEADLINE=y
CONFIG_MARCH_Z9_109=y
+CONFIG_NR_CPUS=256
CONFIG_PREEMPT=y
CONFIG_HZ_100=y
CONFIG_MEMORY_HOTPLUG=y
@@ -58,7 +59,6 @@ CONFIG_HOTPLUG_PCI=y
CONFIG_HOTPLUG_PCI_S390=y
CONFIG_CHSC_SCH=y
CONFIG_CRASH_DUMP=y
-CONFIG_ZFCPDUMP=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_BINFMT_MISC=m
CONFIG_HIBERNATION=y
@@ -101,7 +101,6 @@ CONFIG_TCP_CONG_VENO=m
CONFIG_TCP_CONG_YEAH=m
CONFIG_TCP_CONG_ILLINOIS=m
CONFIG_IPV6=y
-CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
@@ -111,6 +110,7 @@ CONFIG_INET6_XFRM_MODE_TRANSPORT=m
CONFIG_INET6_XFRM_MODE_TUNNEL=m
CONFIG_INET6_XFRM_MODE_BEET=m
CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_VTI=m
CONFIG_IPV6_SIT=m
CONFIG_IPV6_GRE=m
CONFIG_IPV6_MULTIPLE_TABLES=y
@@ -135,7 +135,17 @@ CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_CT_NETLINK=m
CONFIG_NF_CT_NETLINK_TIMEOUT=m
-CONFIG_NETFILTER_TPROXY=m
+CONFIG_NF_TABLES=m
+CONFIG_NFT_EXTHDR=m
+CONFIG_NFT_META=m
+CONFIG_NFT_CT=m
+CONFIG_NFT_RBTREE=m
+CONFIG_NFT_HASH=m
+CONFIG_NFT_COUNTER=m
+CONFIG_NFT_LOG=m
+CONFIG_NFT_LIMIT=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_AUDIT=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -204,7 +214,9 @@ CONFIG_IP_SET_HASH_IP=m
CONFIG_IP_SET_HASH_IPPORT=m
CONFIG_IP_SET_HASH_IPPORTIP=m
CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_NETPORTNET=m
CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETNET=m
CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
@@ -227,6 +239,11 @@ CONFIG_IP_VS_FTP=m
CONFIG_IP_VS_PE_SIP=m
CONFIG_NF_CONNTRACK_IPV4=m
# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
+CONFIG_NF_TABLES_IPV4=m
+CONFIG_NFT_REJECT_IPV4=m
+CONFIG_NFT_CHAIN_ROUTE_IPV4=m
+CONFIG_NFT_CHAIN_NAT_IPV4=m
+CONFIG_NF_TABLES_ARP=m
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
@@ -249,6 +266,9 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_NF_TABLES_IPV6=m
+CONFIG_NFT_CHAIN_ROUTE_IPV6=m
+CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
CONFIG_IP6_NF_MATCH_AH=m
CONFIG_IP6_NF_MATCH_EUI64=m
@@ -268,6 +288,7 @@ CONFIG_IP6_NF_SECURITY=m
CONFIG_NF_NAT_IPV6=m
CONFIG_IP6_NF_TARGET_MASQUERADE=m
CONFIG_IP6_NF_TARGET_NPT=m
+CONFIG_NF_TABLES_BRIDGE=m
CONFIG_NET_SCTPPROBE=m
CONFIG_RDS=m
CONFIG_RDS_RDMA=m
@@ -314,6 +335,7 @@ CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
CONFIG_NET_CLS_FLOW=m
CONFIG_NET_CLS_CGROUP=y
+CONFIG_NET_CLS_BPF=m
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=m
CONFIG_NET_ACT_GACT=m
@@ -381,8 +403,8 @@ CONFIG_BLK_DEV_DM=m
CONFIG_DM_CRYPT=m
CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
-CONFIG_DM_RAID=m
CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_RAID=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_MULTIPATH_QL=m
@@ -434,7 +456,6 @@ CONFIG_TN3270_FS=y
CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_NOWAYOUT=y
CONFIG_SOFT_WATCHDOG=m
-CONFIG_ZVM_WATCHDOG=m
# CONFIG_HID is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_INFINIBAND=m
@@ -534,13 +555,23 @@ CONFIG_UNUSED_SYMBOLS=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_SELFTEST=y
+CONFIG_DEBUG_OBJECTS_FREE=y
+CONFIG_DEBUG_OBJECTS_TIMERS=y
+CONFIG_DEBUG_OBJECTS_WORK=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
CONFIG_SLUB_DEBUG_ON=y
CONFIG_SLUB_STATS=y
+CONFIG_DEBUG_KMEMLEAK=y
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUG_VM=y
CONFIG_DEBUG_VM_RB=y
CONFIG_MEMORY_NOTIFIER_ERROR_INJECT=m
CONFIG_DEBUG_PER_CPU_MAPS=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_DETECT_HUNG_TASK=y
CONFIG_TIMER_STATS=y
CONFIG_DEBUG_RT_MUTEXES=y
CONFIG_RT_MUTEX_TESTER=y
@@ -573,9 +604,11 @@ CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y
CONFIG_BLK_DEV_IO_TRACE=y
# CONFIG_KPROBE_EVENT is not set
CONFIG_LKDTM=m
+CONFIG_TEST_LIST_SORT=y
CONFIG_KPROBES_SANITY_TEST=y
-CONFIG_RBTREE_TEST=m
+CONFIG_RBTREE_TEST=y
CONFIG_INTERVAL_TREE_TEST=m
+CONFIG_PERCPU_TEST=m
CONFIG_ATOMIC64_SELFTEST=y
CONFIG_DMA_API_DEBUG=y
# CONFIG_STRICT_DEVMEM is not set
@@ -638,7 +671,6 @@ CONFIG_CRYPTO_AES_S390=m
CONFIG_CRYPTO_GHASH_S390=m
CONFIG_ASYMMETRIC_KEY_TYPE=m
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=m
-CONFIG_PUBLIC_KEY_ALGO_RSA=m
CONFIG_X509_CERTIFICATE_PARSER=m
CONFIG_CRC7=m
CONFIG_CRC8=m
diff --git a/arch/s390/configs/gcov_defconfig b/arch/s390/configs/gcov_defconfig
index b9f6b4cab927..c81a74e3e25a 100644
--- a/arch/s390/configs/gcov_defconfig
+++ b/arch/s390/configs/gcov_defconfig
@@ -46,6 +46,7 @@ CONFIG_UNIXWARE_DISKLABEL=y
CONFIG_CFQ_GROUP_IOSCHED=y
CONFIG_DEFAULT_DEADLINE=y
CONFIG_MARCH_Z9_109=y
+CONFIG_NR_CPUS=256
CONFIG_HZ_100=y
CONFIG_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTREMOVE=y
@@ -56,7 +57,6 @@ CONFIG_HOTPLUG_PCI=y
CONFIG_HOTPLUG_PCI_S390=y
CONFIG_CHSC_SCH=y
CONFIG_CRASH_DUMP=y
-CONFIG_ZFCPDUMP=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_BINFMT_MISC=m
CONFIG_HIBERNATION=y
@@ -99,7 +99,6 @@ CONFIG_TCP_CONG_VENO=m
CONFIG_TCP_CONG_YEAH=m
CONFIG_TCP_CONG_ILLINOIS=m
CONFIG_IPV6=y
-CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
@@ -109,6 +108,7 @@ CONFIG_INET6_XFRM_MODE_TRANSPORT=m
CONFIG_INET6_XFRM_MODE_TUNNEL=m
CONFIG_INET6_XFRM_MODE_BEET=m
CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_VTI=m
CONFIG_IPV6_SIT=m
CONFIG_IPV6_GRE=m
CONFIG_IPV6_MULTIPLE_TABLES=y
@@ -133,7 +133,17 @@ CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_CT_NETLINK=m
CONFIG_NF_CT_NETLINK_TIMEOUT=m
-CONFIG_NETFILTER_TPROXY=m
+CONFIG_NF_TABLES=m
+CONFIG_NFT_EXTHDR=m
+CONFIG_NFT_META=m
+CONFIG_NFT_CT=m
+CONFIG_NFT_RBTREE=m
+CONFIG_NFT_HASH=m
+CONFIG_NFT_COUNTER=m
+CONFIG_NFT_LOG=m
+CONFIG_NFT_LIMIT=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_AUDIT=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -202,7 +212,9 @@ CONFIG_IP_SET_HASH_IP=m
CONFIG_IP_SET_HASH_IPPORT=m
CONFIG_IP_SET_HASH_IPPORTIP=m
CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_NETPORTNET=m
CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETNET=m
CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
@@ -225,6 +237,11 @@ CONFIG_IP_VS_FTP=m
CONFIG_IP_VS_PE_SIP=m
CONFIG_NF_CONNTRACK_IPV4=m
# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
+CONFIG_NF_TABLES_IPV4=m
+CONFIG_NFT_REJECT_IPV4=m
+CONFIG_NFT_CHAIN_ROUTE_IPV4=m
+CONFIG_NFT_CHAIN_NAT_IPV4=m
+CONFIG_NF_TABLES_ARP=m
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
@@ -247,6 +264,9 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_NF_TABLES_IPV6=m
+CONFIG_NFT_CHAIN_ROUTE_IPV6=m
+CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
CONFIG_IP6_NF_MATCH_AH=m
CONFIG_IP6_NF_MATCH_EUI64=m
@@ -266,6 +286,7 @@ CONFIG_IP6_NF_SECURITY=m
CONFIG_NF_NAT_IPV6=m
CONFIG_IP6_NF_TARGET_MASQUERADE=m
CONFIG_IP6_NF_TARGET_NPT=m
+CONFIG_NF_TABLES_BRIDGE=m
CONFIG_NET_SCTPPROBE=m
CONFIG_RDS=m
CONFIG_RDS_RDMA=m
@@ -311,6 +332,7 @@ CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
CONFIG_NET_CLS_FLOW=m
CONFIG_NET_CLS_CGROUP=y
+CONFIG_NET_CLS_BPF=m
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=m
CONFIG_NET_ACT_GACT=m
@@ -378,8 +400,8 @@ CONFIG_BLK_DEV_DM=m
CONFIG_DM_CRYPT=m
CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
-CONFIG_DM_RAID=m
CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_RAID=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_MULTIPATH_QL=m
@@ -431,7 +453,6 @@ CONFIG_TN3270_FS=y
CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_NOWAYOUT=y
CONFIG_SOFT_WATCHDOG=m
-CONFIG_ZVM_WATCHDOG=m
# CONFIG_HID is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_INFINIBAND=m
@@ -540,6 +561,7 @@ CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_LKDTM=m
CONFIG_RBTREE_TEST=m
CONFIG_INTERVAL_TREE_TEST=m
+CONFIG_PERCPU_TEST=m
CONFIG_ATOMIC64_SELFTEST=y
# CONFIG_STRICT_DEVMEM is not set
CONFIG_S390_PTDUMP=y
@@ -601,7 +623,6 @@ CONFIG_CRYPTO_AES_S390=m
CONFIG_CRYPTO_GHASH_S390=m
CONFIG_ASYMMETRIC_KEY_TYPE=m
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=m
-CONFIG_PUBLIC_KEY_ALGO_RSA=m
CONFIG_X509_CERTIFICATE_PARSER=m
CONFIG_CRC7=m
CONFIG_CRC8=m
diff --git a/arch/s390/configs/performance_defconfig b/arch/s390/configs/performance_defconfig
index 91087b43e8fa..b5ba8fe1cc64 100644
--- a/arch/s390/configs/performance_defconfig
+++ b/arch/s390/configs/performance_defconfig
@@ -44,6 +44,7 @@ CONFIG_UNIXWARE_DISKLABEL=y
CONFIG_CFQ_GROUP_IOSCHED=y
CONFIG_DEFAULT_DEADLINE=y
CONFIG_MARCH_Z9_109=y
+CONFIG_NR_CPUS=256
CONFIG_HZ_100=y
CONFIG_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTREMOVE=y
@@ -54,7 +55,6 @@ CONFIG_HOTPLUG_PCI=y
CONFIG_HOTPLUG_PCI_S390=y
CONFIG_CHSC_SCH=y
CONFIG_CRASH_DUMP=y
-CONFIG_ZFCPDUMP=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_BINFMT_MISC=m
CONFIG_HIBERNATION=y
@@ -97,7 +97,6 @@ CONFIG_TCP_CONG_VENO=m
CONFIG_TCP_CONG_YEAH=m
CONFIG_TCP_CONG_ILLINOIS=m
CONFIG_IPV6=y
-CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
@@ -107,6 +106,7 @@ CONFIG_INET6_XFRM_MODE_TRANSPORT=m
CONFIG_INET6_XFRM_MODE_TUNNEL=m
CONFIG_INET6_XFRM_MODE_BEET=m
CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_VTI=m
CONFIG_IPV6_SIT=m
CONFIG_IPV6_GRE=m
CONFIG_IPV6_MULTIPLE_TABLES=y
@@ -131,7 +131,17 @@ CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_CT_NETLINK=m
CONFIG_NF_CT_NETLINK_TIMEOUT=m
-CONFIG_NETFILTER_TPROXY=m
+CONFIG_NF_TABLES=m
+CONFIG_NFT_EXTHDR=m
+CONFIG_NFT_META=m
+CONFIG_NFT_CT=m
+CONFIG_NFT_RBTREE=m
+CONFIG_NFT_HASH=m
+CONFIG_NFT_COUNTER=m
+CONFIG_NFT_LOG=m
+CONFIG_NFT_LIMIT=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_AUDIT=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -200,7 +210,9 @@ CONFIG_IP_SET_HASH_IP=m
CONFIG_IP_SET_HASH_IPPORT=m
CONFIG_IP_SET_HASH_IPPORTIP=m
CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_NETPORTNET=m
CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETNET=m
CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
@@ -223,6 +235,11 @@ CONFIG_IP_VS_FTP=m
CONFIG_IP_VS_PE_SIP=m
CONFIG_NF_CONNTRACK_IPV4=m
# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
+CONFIG_NF_TABLES_IPV4=m
+CONFIG_NFT_REJECT_IPV4=m
+CONFIG_NFT_CHAIN_ROUTE_IPV4=m
+CONFIG_NFT_CHAIN_NAT_IPV4=m
+CONFIG_NF_TABLES_ARP=m
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
@@ -245,6 +262,9 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_NF_TABLES_IPV6=m
+CONFIG_NFT_CHAIN_ROUTE_IPV6=m
+CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
CONFIG_IP6_NF_MATCH_AH=m
CONFIG_IP6_NF_MATCH_EUI64=m
@@ -264,6 +284,7 @@ CONFIG_IP6_NF_SECURITY=m
CONFIG_NF_NAT_IPV6=m
CONFIG_IP6_NF_TARGET_MASQUERADE=m
CONFIG_IP6_NF_TARGET_NPT=m
+CONFIG_NF_TABLES_BRIDGE=m
CONFIG_NET_SCTPPROBE=m
CONFIG_RDS=m
CONFIG_RDS_RDMA=m
@@ -309,6 +330,7 @@ CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
CONFIG_NET_CLS_FLOW=m
CONFIG_NET_CLS_CGROUP=y
+CONFIG_NET_CLS_BPF=m
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=m
CONFIG_NET_ACT_GACT=m
@@ -376,8 +398,8 @@ CONFIG_BLK_DEV_DM=m
CONFIG_DM_CRYPT=m
CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
-CONFIG_DM_RAID=m
CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_RAID=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_MULTIPATH_QL=m
@@ -429,7 +451,6 @@ CONFIG_TN3270_FS=y
CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_NOWAYOUT=y
CONFIG_SOFT_WATCHDOG=m
-CONFIG_ZVM_WATCHDOG=m
# CONFIG_HID is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_INFINIBAND=m
@@ -532,6 +553,7 @@ CONFIG_LATENCYTOP=y
CONFIG_BLK_DEV_IO_TRACE=y
# CONFIG_KPROBE_EVENT is not set
CONFIG_LKDTM=m
+CONFIG_PERCPU_TEST=m
CONFIG_ATOMIC64_SELFTEST=y
# CONFIG_STRICT_DEVMEM is not set
CONFIG_S390_PTDUMP=y
@@ -593,7 +615,6 @@ CONFIG_CRYPTO_AES_S390=m
CONFIG_CRYPTO_GHASH_S390=m
CONFIG_ASYMMETRIC_KEY_TYPE=m
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=m
-CONFIG_PUBLIC_KEY_ALGO_RSA=m
CONFIG_X509_CERTIFICATE_PARSER=m
CONFIG_CRC7=m
CONFIG_CRC8=m
diff --git a/arch/s390/configs/zfcpdump_defconfig b/arch/s390/configs/zfcpdump_defconfig
index d725c4d956e4..cef073ca1f07 100644
--- a/arch/s390/configs/zfcpdump_defconfig
+++ b/arch/s390/configs/zfcpdump_defconfig
@@ -19,7 +19,6 @@ CONFIG_HZ_100=y
# CONFIG_CHSC_SCH is not set
# CONFIG_SCM_BUS is not set
CONFIG_CRASH_DUMP=y
-CONFIG_ZFCPDUMP=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
# CONFIG_SECCOMP is not set
# CONFIG_IUCV is not set
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index 33f57514f424..4557cb7ffddf 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -40,6 +40,7 @@ CONFIG_PARTITION_ADVANCED=y
CONFIG_IBM_PARTITION=y
CONFIG_DEFAULT_DEADLINE=y
CONFIG_MARCH_Z196=y
+CONFIG_NR_CPUS=256
CONFIG_HZ_100=y
CONFIG_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTREMOVE=y
@@ -122,22 +123,31 @@ CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_HUGETLBFS=y
# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_SECTION_MISMATCH=y
CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_DETECT_HUNG_TASK=y
CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_RT_MUTEXES=y
CONFIG_PROVE_LOCKING=y
CONFIG_LOCK_STAT=y
CONFIG_DEBUG_LOCKDEP=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_WRITECOUNT=y
CONFIG_DEBUG_LIST=y
+CONFIG_DEBUG_SG=y
CONFIG_DEBUG_NOTIFIERS=y
CONFIG_PROVE_RCU=y
CONFIG_RCU_CPU_STALL_TIMEOUT=60
CONFIG_RCU_TRACE=y
CONFIG_LATENCYTOP=y
+CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_KPROBES_SANITY_TEST=y
# CONFIG_STRICT_DEVMEM is not set
+CONFIG_S390_PTDUMP=y
CONFIG_CRYPTO_CRYPTD=m
CONFIG_CRYPTO_AUTHENC=m
CONFIG_CRYPTO_TEST=m
diff --git a/arch/s390/hypfs/hypfs_vm.c b/arch/s390/hypfs/hypfs_vm.c
index 24908ce149f1..32040ace00ea 100644
--- a/arch/s390/hypfs/hypfs_vm.c
+++ b/arch/s390/hypfs/hypfs_vm.c
@@ -32,7 +32,7 @@ struct diag2fc_data {
__u32 pcpus;
__u32 lcpus;
__u32 vcpus;
- __u32 cpu_min;
+ __u32 ocpus;
__u32 cpu_max;
__u32 cpu_shares;
__u32 cpu_use_samp;
@@ -142,7 +142,12 @@ static int hpyfs_vm_create_guest(struct dentry *systems_dir,
ATTRIBUTE(cpus_dir, "capped", capped_value);
ATTRIBUTE(cpus_dir, "dedicated", dedicated_flag);
ATTRIBUTE(cpus_dir, "count", data->vcpus);
- ATTRIBUTE(cpus_dir, "weight_min", data->cpu_min);
+ /*
+ * Note: The "weight_min" attribute got the wrong name.
+ * The value represents the number of non-stopped (operating)
+ * CPUS.
+ */
+ ATTRIBUTE(cpus_dir, "weight_min", data->ocpus);
ATTRIBUTE(cpus_dir, "weight_max", data->cpu_max);
ATTRIBUTE(cpus_dir, "weight_cur", data->cpu_shares);
diff --git a/arch/s390/include/asm/Kbuild b/arch/s390/include/asm/Kbuild
index 8386a4a1f19a..57892a8a9055 100644
--- a/arch/s390/include/asm/Kbuild
+++ b/arch/s390/include/asm/Kbuild
@@ -1,6 +1,7 @@
generic-y += clkdev.h
-generic-y += trace_clock.h
-generic-y += preempt.h
generic-y += hash.h
+generic-y += mcs_spinlock.h
+generic-y += preempt.h
+generic-y += trace_clock.h
diff --git a/arch/s390/include/asm/airq.h b/arch/s390/include/asm/airq.h
index 4bbb5957ed1b..bd93ff6661b8 100644
--- a/arch/s390/include/asm/airq.h
+++ b/arch/s390/include/asm/airq.h
@@ -44,11 +44,21 @@ struct airq_iv {
struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags);
void airq_iv_release(struct airq_iv *iv);
-unsigned long airq_iv_alloc_bit(struct airq_iv *iv);
-void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit);
+unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num);
+void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num);
unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start,
unsigned long end);
+static inline unsigned long airq_iv_alloc_bit(struct airq_iv *iv)
+{
+ return airq_iv_alloc(iv, 1);
+}
+
+static inline void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit)
+{
+ airq_iv_free(iv, bit, 1);
+}
+
static inline unsigned long airq_iv_end(struct airq_iv *iv)
{
return iv->end;
diff --git a/arch/s390/include/asm/bitops.h b/arch/s390/include/asm/bitops.h
index 6e6ad0680829..ec5ef891db6b 100644
--- a/arch/s390/include/asm/bitops.h
+++ b/arch/s390/include/asm/bitops.h
@@ -13,9 +13,9 @@
*
* The bitop functions are defined to work on unsigned longs, so for an
* s390x system the bits end up numbered:
- * |63..............0|127............64|191...........128|255...........196|
+ * |63..............0|127............64|191...........128|255...........192|
* and on s390:
- * |31.....0|63....31|95....64|127...96|159..128|191..160|223..192|255..224|
+ * |31.....0|63....32|95....64|127...96|159..128|191..160|223..192|255..224|
*
* There are a few little-endian macros used mostly for filesystem
* bitmaps, these work on similar bit arrays layouts, but
@@ -30,7 +30,7 @@
* on an s390x system the bits are numbered:
* |0..............63|64............127|128...........191|192...........255|
* and on s390:
- * |0.....31|31....63|64....95|96...127|128..159|160..191|192..223|224..255|
+ * |0.....31|32....63|64....95|96...127|128..159|160..191|192..223|224..255|
*
* The main difference is that bit 0-63 (64b) or 0-31 (32b) in the bit
* number field needs to be reversed compared to the LSB0 encoded bit
@@ -304,7 +304,7 @@ static inline int test_bit(unsigned long nr, const volatile unsigned long *ptr)
* On an s390x system the bits are numbered:
* |0..............63|64............127|128...........191|192...........255|
* and on s390:
- * |0.....31|31....63|64....95|96...127|128..159|160..191|192..223|224..255|
+ * |0.....31|32....63|64....95|96...127|128..159|160..191|192..223|224..255|
*/
unsigned long find_first_bit_inv(const unsigned long *addr, unsigned long size);
unsigned long find_next_bit_inv(const unsigned long *addr, unsigned long size,
diff --git a/arch/s390/include/asm/ccwdev.h b/arch/s390/include/asm/ccwdev.h
index f201af8be580..a9c2c0686177 100644
--- a/arch/s390/include/asm/ccwdev.h
+++ b/arch/s390/include/asm/ccwdev.h
@@ -219,7 +219,9 @@ extern void ccw_device_get_id(struct ccw_device *, struct ccw_dev_id *);
#define to_ccwdev(n) container_of(n, struct ccw_device, dev)
#define to_ccwdrv(n) container_of(n, struct ccw_driver, driver)
-extern struct ccw_device *ccw_device_probe_console(void);
+extern struct ccw_device *ccw_device_create_console(struct ccw_driver *);
+extern void ccw_device_destroy_console(struct ccw_device *);
+extern int ccw_device_enable_console(struct ccw_device *);
extern void ccw_device_wait_idle(struct ccw_device *);
extern int ccw_device_force_console(struct ccw_device *);
diff --git a/arch/s390/include/asm/ccwgroup.h b/arch/s390/include/asm/ccwgroup.h
index 23723ce5ca7a..6e670f88d125 100644
--- a/arch/s390/include/asm/ccwgroup.h
+++ b/arch/s390/include/asm/ccwgroup.h
@@ -23,6 +23,7 @@ struct ccwgroup_device {
unsigned int count;
struct device dev;
struct ccw_device *cdev[0];
+ struct work_struct ungroup_work;
};
/**
diff --git a/arch/s390/include/asm/checksum.h b/arch/s390/include/asm/checksum.h
index 4f57a4f3909a..740364856355 100644
--- a/arch/s390/include/asm/checksum.h
+++ b/arch/s390/include/asm/checksum.h
@@ -44,22 +44,15 @@ csum_partial(const void *buff, int len, __wsum sum)
* here even more important to align src and dst on a 32-bit (or even
* better 64-bit) boundary
*
- * Copy from userspace and compute checksum. If we catch an exception
- * then zero the rest of the buffer.
+ * Copy from userspace and compute checksum.
*/
static inline __wsum
csum_partial_copy_from_user(const void __user *src, void *dst,
int len, __wsum sum,
int *err_ptr)
{
- int missing;
-
- missing = copy_from_user(dst, src, len);
- if (missing) {
- memset(dst + len - missing, 0, missing);
+ if (unlikely(copy_from_user(dst, src, len)))
*err_ptr = -EFAULT;
- }
-
return csum_partial(dst, len, sum);
}
diff --git a/arch/s390/include/asm/cio.h b/arch/s390/include/asm/cio.h
index d42625053c37..096339207764 100644
--- a/arch/s390/include/asm/cio.h
+++ b/arch/s390/include/asm/cio.h
@@ -199,7 +199,7 @@ struct esw_eadm {
/**
* struct irb - interruption response block
* @scsw: subchannel status word
- * @esw: extened status word
+ * @esw: extended status word
* @ecw: extended control word
*
* The irb that is handed to the device driver when an interrupt occurs. For
diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h
index 5d7e8cf83bd6..d350ed9d0fbb 100644
--- a/arch/s390/include/asm/compat.h
+++ b/arch/s390/include/asm/compat.h
@@ -8,7 +8,11 @@
#include <linux/thread_info.h>
#define __TYPE_IS_PTR(t) (!__builtin_types_compatible_p(typeof(0?(t)0:0ULL), u64))
-#define __SC_DELOUSE(t,v) (t)(__TYPE_IS_PTR(t) ? ((v) & 0x7fffffff) : (v))
+
+#define __SC_DELOUSE(t,v) ({ \
+ BUILD_BUG_ON(sizeof(t) > 4 && !__TYPE_IS_PTR(t)); \
+ (t)(__TYPE_IS_PTR(t) ? ((v) & 0x7fffffff) : (v)); \
+})
#define PSW32_MASK_PER 0x40000000UL
#define PSW32_MASK_DAT 0x04000000UL
diff --git a/arch/s390/include/asm/futex.h b/arch/s390/include/asm/futex.h
index 51bcaa0fdeef..fda46bd38c99 100644
--- a/arch/s390/include/asm/futex.h
+++ b/arch/s390/include/asm/futex.h
@@ -5,7 +5,10 @@
#include <linux/uaccess.h>
#include <asm/errno.h>
-static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
+int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval);
+int __futex_atomic_op_inuser(int op, u32 __user *uaddr, int oparg, int *old);
+
+static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -17,7 +20,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
oparg = 1 << oparg;
pagefault_disable();
- ret = uaccess.futex_atomic_op(op, uaddr, oparg, &oldval);
+ ret = __futex_atomic_op_inuser(op, uaddr, oparg, &oldval);
pagefault_enable();
if (!ret) {
@@ -34,10 +37,4 @@ static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
return ret;
}
-static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
- u32 oldval, u32 newval)
-{
- return uaccess.futex_atomic_cmpxchg(uval, uaddr, oldval, newval);
-}
-
#endif /* _ASM_S390_FUTEX_H */
diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h
index 5f8bcc5fe423..35f0faab5361 100644
--- a/arch/s390/include/asm/irq.h
+++ b/arch/s390/include/asm/irq.h
@@ -53,6 +53,7 @@ enum interruption_class {
IRQIO_PCI,
IRQIO_MSI,
IRQIO_VIR,
+ IRQIO_VAI,
NMI_NMI,
CPU_RST,
NR_ARCH_IRQS
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index eef3dd3fd9a9..154b60089be9 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -16,12 +16,22 @@
#include <linux/hrtimer.h>
#include <linux/interrupt.h>
#include <linux/kvm_host.h>
+#include <linux/kvm.h>
#include <asm/debug.h>
#include <asm/cpu.h>
+#include <asm/isc.h>
#define KVM_MAX_VCPUS 64
#define KVM_USER_MEM_SLOTS 32
+/*
+ * These seem to be used for allocating ->chip in the routing table,
+ * which we don't use. 4096 is an out-of-thin-air value. If we need
+ * to look at ->chip later on, we'll need to revisit this.
+ */
+#define KVM_NR_IRQCHIPS 1
+#define KVM_IRQCHIP_NUM_PINS 4096
+
struct sca_entry {
atomic_t scn;
__u32 reserved;
@@ -106,7 +116,11 @@ struct kvm_s390_sie_block {
__u64 gbea; /* 0x0180 */
__u8 reserved188[24]; /* 0x0188 */
__u32 fac; /* 0x01a0 */
- __u8 reserved1a4[68]; /* 0x01a4 */
+ __u8 reserved1a4[20]; /* 0x01a4 */
+ __u64 cbrlo; /* 0x01b8 */
+ __u8 reserved1c0[30]; /* 0x01c0 */
+ __u64 pp; /* 0x01de */
+ __u8 reserved1e6[2]; /* 0x01e6 */
__u64 itdba; /* 0x01e8 */
__u8 reserved1f0[16]; /* 0x01f0 */
} __attribute__((packed));
@@ -155,6 +169,7 @@ struct kvm_vcpu_stat {
u32 instruction_stsi;
u32 instruction_stfl;
u32 instruction_tprot;
+ u32 instruction_essa;
u32 instruction_sigp_sense;
u32 instruction_sigp_sense_running;
u32 instruction_sigp_external_call;
@@ -168,18 +183,6 @@ struct kvm_vcpu_stat {
u32 diagnose_9c;
};
-struct kvm_s390_io_info {
- __u16 subchannel_id; /* 0x0b8 */
- __u16 subchannel_nr; /* 0x0ba */
- __u32 io_int_parm; /* 0x0bc */
- __u32 io_int_word; /* 0x0c0 */
-};
-
-struct kvm_s390_ext_info {
- __u32 ext_params;
- __u64 ext_params2;
-};
-
#define PGM_OPERATION 0x01
#define PGM_PRIVILEGED_OP 0x02
#define PGM_EXECUTE 0x03
@@ -188,27 +191,6 @@ struct kvm_s390_ext_info {
#define PGM_SPECIFICATION 0x06
#define PGM_DATA 0x07
-struct kvm_s390_pgm_info {
- __u16 code;
-};
-
-struct kvm_s390_prefix_info {
- __u32 address;
-};
-
-struct kvm_s390_extcall_info {
- __u16 code;
-};
-
-struct kvm_s390_emerg_info {
- __u16 code;
-};
-
-struct kvm_s390_mchk_info {
- __u64 cr14;
- __u64 mcic;
-};
-
struct kvm_s390_interrupt_info {
struct list_head list;
u64 type;
@@ -243,9 +225,8 @@ struct kvm_s390_float_interrupt {
struct list_head list;
atomic_t active;
int next_rr_cpu;
- unsigned long idle_mask[(KVM_MAX_VCPUS + sizeof(long) - 1)
- / sizeof(long)];
- struct kvm_s390_local_interrupt *local_int[KVM_MAX_VCPUS];
+ unsigned long idle_mask[BITS_TO_LONGS(KVM_MAX_VCPUS)];
+ unsigned int irq_count;
};
@@ -262,6 +243,10 @@ struct kvm_vcpu_arch {
u64 stidp_data;
};
struct gmap *gmap;
+#define KVM_S390_PFAULT_TOKEN_INVALID (-1UL)
+ unsigned long pfault_token;
+ unsigned long pfault_select;
+ unsigned long pfault_compare;
};
struct kvm_vm_stat {
@@ -271,12 +256,36 @@ struct kvm_vm_stat {
struct kvm_arch_memory_slot {
};
+struct s390_map_info {
+ struct list_head list;
+ __u64 guest_addr;
+ __u64 addr;
+ struct page *page;
+};
+
+struct s390_io_adapter {
+ unsigned int id;
+ int isc;
+ bool maskable;
+ bool masked;
+ bool swap;
+ struct rw_semaphore maps_lock;
+ struct list_head maps;
+ atomic_t nr_maps;
+};
+
+#define MAX_S390_IO_ADAPTERS ((MAX_ISC + 1) * 8)
+#define MAX_S390_ADAPTER_MAPS 256
+
struct kvm_arch{
struct sca_block *sca;
debug_info_t *dbf;
struct kvm_s390_float_interrupt float_int;
+ struct kvm_device *flic;
struct gmap *gmap;
int css_support;
+ int use_irqchip;
+ struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS];
};
#define KVM_HVA_ERR_BAD (-1UL)
@@ -287,6 +296,24 @@ static inline bool kvm_is_error_hva(unsigned long addr)
return IS_ERR_VALUE(addr);
}
+#define ASYNC_PF_PER_VCPU 64
+struct kvm_vcpu;
+struct kvm_async_pf;
+struct kvm_arch_async_pf {
+ unsigned long pfault_token;
+};
+
+bool kvm_arch_can_inject_async_page_present(struct kvm_vcpu *vcpu);
+
+void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work);
+
+void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work);
+
+void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work);
+
extern int sie64a(struct kvm_s390_sie_block *, u64 *);
extern char sie_exit;
#endif
diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h
index 5d1f950704dc..38149b63dc44 100644
--- a/arch/s390/include/asm/mmu_context.h
+++ b/arch/s390/include/asm/mmu_context.h
@@ -48,13 +48,42 @@ static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk)
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk)
{
- cpumask_set_cpu(smp_processor_id(), mm_cpumask(next));
- update_mm(next, tsk);
+ int cpu = smp_processor_id();
+
+ if (prev == next)
+ return;
+ if (atomic_inc_return(&next->context.attach_count) >> 16) {
+ /* Delay update_mm until all TLB flushes are done. */
+ set_tsk_thread_flag(tsk, TIF_TLB_WAIT);
+ } else {
+ cpumask_set_cpu(cpu, mm_cpumask(next));
+ update_mm(next, tsk);
+ if (next->context.flush_mm)
+ /* Flush pending TLBs */
+ __tlb_flush_mm(next);
+ }
atomic_dec(&prev->context.attach_count);
WARN_ON(atomic_read(&prev->context.attach_count) < 0);
- atomic_inc(&next->context.attach_count);
- /* Check for TLBs not flushed yet */
- __tlb_flush_mm_lazy(next);
+}
+
+#define finish_arch_post_lock_switch finish_arch_post_lock_switch
+static inline void finish_arch_post_lock_switch(void)
+{
+ struct task_struct *tsk = current;
+ struct mm_struct *mm = tsk->mm;
+
+ if (!test_tsk_thread_flag(tsk, TIF_TLB_WAIT))
+ return;
+ preempt_disable();
+ clear_tsk_thread_flag(tsk, TIF_TLB_WAIT);
+ while (atomic_read(&mm->context.attach_count) >> 16)
+ cpu_relax();
+
+ cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
+ update_mm(mm, tsk);
+ if (mm->context.flush_mm)
+ __tlb_flush_mm(mm);
+ preempt_enable();
}
#define enter_lazy_tlb(mm,tsk) do { } while (0)
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h
index e1408ddb94f8..884017cbfa9f 100644
--- a/arch/s390/include/asm/pgalloc.h
+++ b/arch/s390/include/asm/pgalloc.h
@@ -22,6 +22,7 @@ unsigned long *page_table_alloc(struct mm_struct *, unsigned long);
void page_table_free(struct mm_struct *, unsigned long *);
void page_table_free_rcu(struct mmu_gather *, unsigned long *);
+void page_table_reset_pgste(struct mm_struct *, unsigned long, unsigned long);
int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
unsigned long key, bool nq);
@@ -91,11 +92,22 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address)
static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
{
unsigned long *table = crst_table_alloc(mm);
- if (table)
- crst_table_init(table, _SEGMENT_ENTRY_EMPTY);
+
+ if (!table)
+ return NULL;
+ crst_table_init(table, _SEGMENT_ENTRY_EMPTY);
+ if (!pgtable_pmd_page_ctor(virt_to_page(table))) {
+ crst_table_free(mm, table);
+ return NULL;
+ }
return (pmd_t *) table;
}
-#define pmd_free(mm, pmd) crst_table_free(mm, (unsigned long *) pmd)
+
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
+{
+ pgtable_pmd_page_dtor(virt_to_page(pmd));
+ crst_table_free(mm, (unsigned long *) pmd);
+}
static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
{
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 2204400d0bd5..50a75d96f939 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -229,6 +229,7 @@ extern unsigned long MODULES_END;
#define _PAGE_READ 0x010 /* SW pte read bit */
#define _PAGE_WRITE 0x020 /* SW pte write bit */
#define _PAGE_SPECIAL 0x040 /* SW associated with special page */
+#define _PAGE_UNUSED 0x080 /* SW bit for pgste usage state */
#define __HAVE_ARCH_PTE_SPECIAL
/* Set of bits not changed in pte_modify */
@@ -394,6 +395,12 @@ extern unsigned long MODULES_END;
#endif /* CONFIG_64BIT */
+/* Guest Page State used for virtualization */
+#define _PGSTE_GPS_ZERO 0x0000000080000000UL
+#define _PGSTE_GPS_USAGE_MASK 0x0000000003000000UL
+#define _PGSTE_GPS_USAGE_STABLE 0x0000000000000000UL
+#define _PGSTE_GPS_USAGE_UNUSED 0x0000000001000000UL
+
/*
* A user page table pointer has the space-switch-event bit, the
* private-space-control bit and the storage-alteration-event-control
@@ -617,6 +624,14 @@ static inline int pte_none(pte_t pte)
return pte_val(pte) == _PAGE_INVALID;
}
+static inline int pte_swap(pte_t pte)
+{
+ /* Bit pattern: (pte & 0x603) == 0x402 */
+ return (pte_val(pte) & (_PAGE_INVALID | _PAGE_PROTECT |
+ _PAGE_TYPE | _PAGE_PRESENT))
+ == (_PAGE_INVALID | _PAGE_TYPE);
+}
+
static inline int pte_file(pte_t pte)
{
/* Bit pattern: (pte & 0x601) == 0x600 */
@@ -767,6 +782,7 @@ static inline void pgste_set_pte(pte_t *ptep, pte_t entry)
* @table: pointer to the page directory
* @asce: address space control element for gmap page table
* @crst_list: list of all crst tables used in the guest address space
+ * @pfault_enabled: defines if pfaults are applicable for the guest
*/
struct gmap {
struct list_head list;
@@ -775,6 +791,7 @@ struct gmap {
unsigned long asce;
void *private;
struct list_head crst_list;
+ bool pfault_enabled;
};
/**
@@ -821,20 +838,20 @@ unsigned long gmap_translate(unsigned long address, struct gmap *);
unsigned long __gmap_fault(unsigned long address, struct gmap *);
unsigned long gmap_fault(unsigned long address, struct gmap *);
void gmap_discard(unsigned long from, unsigned long to, struct gmap *);
+void __gmap_zap(unsigned long address, struct gmap *);
void gmap_register_ipte_notifier(struct gmap_notifier *);
void gmap_unregister_ipte_notifier(struct gmap_notifier *);
int gmap_ipte_notify(struct gmap *, unsigned long start, unsigned long len);
-void gmap_do_ipte_notify(struct mm_struct *, unsigned long addr, pte_t *);
+void gmap_do_ipte_notify(struct mm_struct *, pte_t *);
static inline pgste_t pgste_ipte_notify(struct mm_struct *mm,
- unsigned long addr,
pte_t *ptep, pgste_t pgste)
{
#ifdef CONFIG_PGSTE
if (pgste_val(pgste) & PGSTE_IN_BIT) {
pgste_val(pgste) &= ~PGSTE_IN_BIT;
- gmap_do_ipte_notify(mm, addr, ptep);
+ gmap_do_ipte_notify(mm, ptep);
}
#endif
return pgste;
@@ -852,6 +869,7 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
if (mm_has_pgste(mm)) {
pgste = pgste_get_lock(ptep);
+ pgste_val(pgste) &= ~_PGSTE_GPS_ZERO;
pgste_set_key(ptep, pgste, entry);
pgste_set_pte(ptep, entry);
pgste_set_unlock(ptep, pgste);
@@ -881,6 +899,12 @@ static inline int pte_young(pte_t pte)
return (pte_val(pte) & _PAGE_YOUNG) != 0;
}
+#define __HAVE_ARCH_PTE_UNUSED
+static inline int pte_unused(pte_t pte)
+{
+ return pte_val(pte) & _PAGE_UNUSED;
+}
+
/*
* pgd/pmd/pte modification functions
*/
@@ -1034,30 +1058,41 @@ static inline int ptep_test_and_clear_user_young(struct mm_struct *mm,
static inline void __ptep_ipte(unsigned long address, pte_t *ptep)
{
- if (!(pte_val(*ptep) & _PAGE_INVALID)) {
+ unsigned long pto = (unsigned long) ptep;
+
#ifndef CONFIG_64BIT
- /* pto must point to the start of the segment table */
- pte_t *pto = (pte_t *) (((unsigned long) ptep) & 0x7ffffc00);
-#else
- /* ipte in zarch mode can do the math */
- pte_t *pto = ptep;
+ /* pto in ESA mode must point to the start of the segment table */
+ pto &= 0x7ffffc00;
#endif
- asm volatile(
- " ipte %2,%3"
- : "=m" (*ptep) : "m" (*ptep),
- "a" (pto), "a" (address));
- }
+ /* Invalidation + global TLB flush for the pte */
+ asm volatile(
+ " ipte %2,%3"
+ : "=m" (*ptep) : "m" (*ptep), "a" (pto), "a" (address));
+}
+
+static inline void ptep_flush_direct(struct mm_struct *mm,
+ unsigned long address, pte_t *ptep)
+{
+ if (pte_val(*ptep) & _PAGE_INVALID)
+ return;
+ __ptep_ipte(address, ptep);
}
static inline void ptep_flush_lazy(struct mm_struct *mm,
unsigned long address, pte_t *ptep)
{
- int active = (mm == current->active_mm) ? 1 : 0;
+ int active, count;
- if (atomic_read(&mm->context.attach_count) > active)
- __ptep_ipte(address, ptep);
- else
+ if (pte_val(*ptep) & _PAGE_INVALID)
+ return;
+ active = (mm == current->active_mm) ? 1 : 0;
+ count = atomic_add_return(0x10000, &mm->context.attach_count);
+ if ((count & 0xffff) <= active) {
+ pte_val(*ptep) |= _PAGE_INVALID;
mm->context.flush_mm = 1;
+ } else
+ __ptep_ipte(address, ptep);
+ atomic_sub(0x10000, &mm->context.attach_count);
}
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
@@ -1070,11 +1105,11 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
if (mm_has_pgste(vma->vm_mm)) {
pgste = pgste_get_lock(ptep);
- pgste = pgste_ipte_notify(vma->vm_mm, addr, ptep, pgste);
+ pgste = pgste_ipte_notify(vma->vm_mm, ptep, pgste);
}
pte = *ptep;
- __ptep_ipte(addr, ptep);
+ ptep_flush_direct(vma->vm_mm, addr, ptep);
young = pte_young(pte);
pte = pte_mkold(pte);
@@ -1116,7 +1151,7 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
if (mm_has_pgste(mm)) {
pgste = pgste_get_lock(ptep);
- pgste = pgste_ipte_notify(mm, address, ptep, pgste);
+ pgste = pgste_ipte_notify(mm, ptep, pgste);
}
pte = *ptep;
@@ -1140,12 +1175,11 @@ static inline pte_t ptep_modify_prot_start(struct mm_struct *mm,
if (mm_has_pgste(mm)) {
pgste = pgste_get_lock(ptep);
- pgste_ipte_notify(mm, address, ptep, pgste);
+ pgste_ipte_notify(mm, ptep, pgste);
}
pte = *ptep;
ptep_flush_lazy(mm, address, ptep);
- pte_val(*ptep) |= _PAGE_INVALID;
if (mm_has_pgste(mm)) {
pgste = pgste_update_all(&pte, pgste);
@@ -1178,14 +1212,17 @@ static inline pte_t ptep_clear_flush(struct vm_area_struct *vma,
if (mm_has_pgste(vma->vm_mm)) {
pgste = pgste_get_lock(ptep);
- pgste = pgste_ipte_notify(vma->vm_mm, address, ptep, pgste);
+ pgste = pgste_ipte_notify(vma->vm_mm, ptep, pgste);
}
pte = *ptep;
- __ptep_ipte(address, ptep);
+ ptep_flush_direct(vma->vm_mm, address, ptep);
pte_val(*ptep) = _PAGE_INVALID;
if (mm_has_pgste(vma->vm_mm)) {
+ if ((pgste_val(pgste) & _PGSTE_GPS_USAGE_MASK) ==
+ _PGSTE_GPS_USAGE_UNUSED)
+ pte_val(pte) |= _PAGE_UNUSED;
pgste = pgste_update_all(&pte, pgste);
pgste_set_unlock(ptep, pgste);
}
@@ -1209,7 +1246,7 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm,
if (!full && mm_has_pgste(mm)) {
pgste = pgste_get_lock(ptep);
- pgste = pgste_ipte_notify(mm, address, ptep, pgste);
+ pgste = pgste_ipte_notify(mm, ptep, pgste);
}
pte = *ptep;
@@ -1234,7 +1271,7 @@ static inline pte_t ptep_set_wrprotect(struct mm_struct *mm,
if (pte_write(pte)) {
if (mm_has_pgste(mm)) {
pgste = pgste_get_lock(ptep);
- pgste = pgste_ipte_notify(mm, address, ptep, pgste);
+ pgste = pgste_ipte_notify(mm, ptep, pgste);
}
ptep_flush_lazy(mm, address, ptep);
@@ -1260,10 +1297,10 @@ static inline int ptep_set_access_flags(struct vm_area_struct *vma,
return 0;
if (mm_has_pgste(vma->vm_mm)) {
pgste = pgste_get_lock(ptep);
- pgste = pgste_ipte_notify(vma->vm_mm, address, ptep, pgste);
+ pgste = pgste_ipte_notify(vma->vm_mm, ptep, pgste);
}
- __ptep_ipte(address, ptep);
+ ptep_flush_direct(vma->vm_mm, address, ptep);
if (mm_has_pgste(vma->vm_mm)) {
pgste_set_pte(ptep, entry);
@@ -1447,12 +1484,16 @@ static inline pmd_t pmd_mkwrite(pmd_t pmd)
static inline void pmdp_flush_lazy(struct mm_struct *mm,
unsigned long address, pmd_t *pmdp)
{
- int active = (mm == current->active_mm) ? 1 : 0;
+ int active, count;
- if ((atomic_read(&mm->context.attach_count) & 0xffff) > active)
- __pmd_idte(address, pmdp);
- else
+ active = (mm == current->active_mm) ? 1 : 0;
+ count = atomic_add_return(0x10000, &mm->context.attach_count);
+ if ((count & 0xffff) <= active) {
+ pmd_val(*pmdp) |= _SEGMENT_ENTRY_INVALID;
mm->context.flush_mm = 1;
+ } else
+ __pmd_idte(address, pmdp);
+ atomic_sub(0x10000, &mm->context.attach_count);
}
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index 0a876bc543d3..dc5fc4f90e52 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -79,6 +79,7 @@ struct thread_struct {
unsigned long ksp; /* kernel stack pointer */
mm_segment_t mm_segment;
unsigned long gmap_addr; /* address of last gmap fault. */
+ unsigned int gmap_pfault; /* signal of a pending guest pfault */
struct per_regs per_user; /* User specified PER registers */
struct per_event per_event; /* Cause of the last PER trap */
unsigned long per_flags; /* Flags to control debug behavior */
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index 9c82cebddabd..f4783c0b7b43 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -83,6 +83,7 @@ struct per_struct_kernel {
* These are defined as per linux/ptrace.h, which see.
*/
#define arch_has_single_step() (1)
+#define arch_has_block_step() (1)
#define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
#define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN)
diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h
index abaca2275c7a..2f5e9932b4de 100644
--- a/arch/s390/include/asm/sclp.h
+++ b/arch/s390/include/asm/sclp.h
@@ -46,6 +46,7 @@ int sclp_cpu_configure(u8 cpu);
int sclp_cpu_deconfigure(u8 cpu);
unsigned long long sclp_get_rnmax(void);
unsigned long long sclp_get_rzm(void);
+unsigned int sclp_get_max_cpu(void);
int sclp_sdias_blk_count(void);
int sclp_sdias_copy(void *dest, int blk_num, int nr_blks);
int sclp_chp_configure(struct chp_id chpid);
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h
index 94cfbe442f12..406f3a1e63ef 100644
--- a/arch/s390/include/asm/setup.h
+++ b/arch/s390/include/asm/setup.h
@@ -59,7 +59,6 @@ void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr,
#define MACHINE_FLAG_DIAG44 (1UL << 4)
#define MACHINE_FLAG_IDTE (1UL << 5)
#define MACHINE_FLAG_DIAG9C (1UL << 6)
-#define MACHINE_FLAG_MVCOS (1UL << 7)
#define MACHINE_FLAG_KVM (1UL << 8)
#define MACHINE_FLAG_ESOP (1UL << 9)
#define MACHINE_FLAG_EDAT1 (1UL << 10)
@@ -85,7 +84,6 @@ void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr,
#define MACHINE_HAS_IDTE (0)
#define MACHINE_HAS_DIAG44 (1)
#define MACHINE_HAS_MVPG (S390_lowcore.machine_flags & MACHINE_FLAG_MVPG)
-#define MACHINE_HAS_MVCOS (0)
#define MACHINE_HAS_EDAT1 (0)
#define MACHINE_HAS_EDAT2 (0)
#define MACHINE_HAS_LPP (0)
@@ -98,7 +96,6 @@ void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr,
#define MACHINE_HAS_IDTE (S390_lowcore.machine_flags & MACHINE_FLAG_IDTE)
#define MACHINE_HAS_DIAG44 (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG44)
#define MACHINE_HAS_MVPG (1)
-#define MACHINE_HAS_MVCOS (S390_lowcore.machine_flags & MACHINE_FLAG_MVCOS)
#define MACHINE_HAS_EDAT1 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT1)
#define MACHINE_HAS_EDAT2 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT2)
#define MACHINE_HAS_LPP (S390_lowcore.machine_flags & MACHINE_FLAG_LPP)
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h
index 10e0fcd3633d..3ccd71b90345 100644
--- a/arch/s390/include/asm/thread_info.h
+++ b/arch/s390/include/asm/thread_info.h
@@ -81,6 +81,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_NOTIFY_RESUME 1 /* callback before returning to user */
#define TIF_SIGPENDING 2 /* signal pending */
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
+#define TIF_TLB_WAIT 4 /* wait for TLB flush completion */
#define TIF_PER_TRAP 6 /* deliver sigtrap on return to user */
#define TIF_MCCK_PENDING 7 /* machine check handling is pending */
#define TIF_SYSCALL_TRACE 8 /* syscall trace active */
@@ -91,11 +92,13 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_MEMDIE 18 /* is terminating due to OOM killer */
#define TIF_RESTORE_SIGMASK 19 /* restore signal mask in do_signal() */
#define TIF_SINGLE_STEP 20 /* This task is single stepped */
+#define TIF_BLOCK_STEP 21 /* This task is block stepped */
#define _TIF_SYSCALL (1<<TIF_SYSCALL)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
+#define _TIF_TLB_WAIT (1<<TIF_TLB_WAIT)
#define _TIF_PER_TRAP (1<<TIF_PER_TRAP)
#define _TIF_MCCK_PENDING (1<<TIF_MCCK_PENDING)
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
index 79330af9a5f8..4133b3f72fb0 100644
--- a/arch/s390/include/asm/uaccess.h
+++ b/arch/s390/include/asm/uaccess.h
@@ -92,33 +92,58 @@ static inline unsigned long extable_fixup(const struct exception_table_entry *x)
#define ARCH_HAS_SORT_EXTABLE
#define ARCH_HAS_SEARCH_EXTABLE
-struct uaccess_ops {
- size_t (*copy_from_user)(size_t, const void __user *, void *);
- size_t (*copy_to_user)(size_t, void __user *, const void *);
- size_t (*copy_in_user)(size_t, void __user *, const void __user *);
- size_t (*clear_user)(size_t, void __user *);
- size_t (*strnlen_user)(size_t, const char __user *);
- size_t (*strncpy_from_user)(size_t, const char __user *, char *);
- int (*futex_atomic_op)(int op, u32 __user *, int oparg, int *old);
- int (*futex_atomic_cmpxchg)(u32 *, u32 __user *, u32 old, u32 new);
-};
+int __handle_fault(unsigned long, unsigned long, int);
-extern struct uaccess_ops uaccess;
-extern struct uaccess_ops uaccess_mvcos;
-extern struct uaccess_ops uaccess_pt;
+/**
+ * __copy_from_user: - Copy a block of data from user space, with less checking.
+ * @to: Destination address, in kernel space.
+ * @from: Source address, in user space.
+ * @n: Number of bytes to copy.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * Copy data from user space to kernel space. Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ *
+ * If some data could not be copied, this function will pad the copied
+ * data to the requested size using zero bytes.
+ */
+unsigned long __must_check __copy_from_user(void *to, const void __user *from,
+ unsigned long n);
+
+/**
+ * __copy_to_user: - Copy a block of data into user space, with less checking.
+ * @to: Destination address, in user space.
+ * @from: Source address, in kernel space.
+ * @n: Number of bytes to copy.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * Copy data from kernel space to user space. Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ */
+unsigned long __must_check __copy_to_user(void __user *to, const void *from,
+ unsigned long n);
-extern int __handle_fault(unsigned long, unsigned long, int);
+#define __copy_to_user_inatomic __copy_to_user
+#define __copy_from_user_inatomic __copy_from_user
-static inline int __put_user_fn(size_t size, void __user *ptr, void *x)
+static inline int __put_user_fn(void *x, void __user *ptr, unsigned long size)
{
- size = uaccess.copy_to_user(size, ptr, x);
- return size ? -EFAULT : size;
+ size = __copy_to_user(ptr, x, size);
+ return size ? -EFAULT : 0;
}
-static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)
+static inline int __get_user_fn(void *x, const void __user *ptr, unsigned long size)
{
- size = uaccess.copy_from_user(size, ptr, x);
- return size ? -EFAULT : size;
+ size = __copy_from_user(x, ptr, size);
+ return size ? -EFAULT : 0;
}
/*
@@ -135,8 +160,8 @@ static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)
case 2: \
case 4: \
case 8: \
- __pu_err = __put_user_fn(sizeof (*(ptr)), \
- ptr, &__x); \
+ __pu_err = __put_user_fn(&__x, ptr, \
+ sizeof(*(ptr))); \
break; \
default: \
__put_user_bad(); \
@@ -152,7 +177,7 @@ static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)
})
-extern int __put_user_bad(void) __attribute__((noreturn));
+int __put_user_bad(void) __attribute__((noreturn));
#define __get_user(x, ptr) \
({ \
@@ -161,29 +186,29 @@ extern int __put_user_bad(void) __attribute__((noreturn));
switch (sizeof(*(ptr))) { \
case 1: { \
unsigned char __x; \
- __gu_err = __get_user_fn(sizeof (*(ptr)), \
- ptr, &__x); \
+ __gu_err = __get_user_fn(&__x, ptr, \
+ sizeof(*(ptr))); \
(x) = *(__force __typeof__(*(ptr)) *) &__x; \
break; \
}; \
case 2: { \
unsigned short __x; \
- __gu_err = __get_user_fn(sizeof (*(ptr)), \
- ptr, &__x); \
+ __gu_err = __get_user_fn(&__x, ptr, \
+ sizeof(*(ptr))); \
(x) = *(__force __typeof__(*(ptr)) *) &__x; \
break; \
}; \
case 4: { \
unsigned int __x; \
- __gu_err = __get_user_fn(sizeof (*(ptr)), \
- ptr, &__x); \
+ __gu_err = __get_user_fn(&__x, ptr, \
+ sizeof(*(ptr))); \
(x) = *(__force __typeof__(*(ptr)) *) &__x; \
break; \
}; \
case 8: { \
unsigned long long __x; \
- __gu_err = __get_user_fn(sizeof (*(ptr)), \
- ptr, &__x); \
+ __gu_err = __get_user_fn(&__x, ptr, \
+ sizeof(*(ptr))); \
(x) = *(__force __typeof__(*(ptr)) *) &__x; \
break; \
}; \
@@ -200,35 +225,12 @@ extern int __put_user_bad(void) __attribute__((noreturn));
__get_user(x, ptr); \
})
-extern int __get_user_bad(void) __attribute__((noreturn));
+int __get_user_bad(void) __attribute__((noreturn));
#define __put_user_unaligned __put_user
#define __get_user_unaligned __get_user
/**
- * __copy_to_user: - Copy a block of data into user space, with less checking.
- * @to: Destination address, in user space.
- * @from: Source address, in kernel space.
- * @n: Number of bytes to copy.
- *
- * Context: User context only. This function may sleep.
- *
- * Copy data from kernel space to user space. Caller must check
- * the specified block with access_ok() before calling this function.
- *
- * Returns number of bytes that could not be copied.
- * On success, this will be zero.
- */
-static inline unsigned long __must_check
-__copy_to_user(void __user *to, const void *from, unsigned long n)
-{
- return uaccess.copy_to_user(n, to, from);
-}
-
-#define __copy_to_user_inatomic __copy_to_user
-#define __copy_from_user_inatomic __copy_from_user
-
-/**
* copy_to_user: - Copy a block of data into user space.
* @to: Destination address, in user space.
* @from: Source address, in kernel space.
@@ -248,30 +250,7 @@ copy_to_user(void __user *to, const void *from, unsigned long n)
return __copy_to_user(to, from, n);
}
-/**
- * __copy_from_user: - Copy a block of data from user space, with less checking.
- * @to: Destination address, in kernel space.
- * @from: Source address, in user space.
- * @n: Number of bytes to copy.
- *
- * Context: User context only. This function may sleep.
- *
- * Copy data from user space to kernel space. Caller must check
- * the specified block with access_ok() before calling this function.
- *
- * Returns number of bytes that could not be copied.
- * On success, this will be zero.
- *
- * If some data could not be copied, this function will pad the copied
- * data to the requested size using zero bytes.
- */
-static inline unsigned long __must_check
-__copy_from_user(void *to, const void __user *from, unsigned long n)
-{
- return uaccess.copy_from_user(n, from, to);
-}
-
-extern void copy_from_user_overflow(void)
+void copy_from_user_overflow(void)
#ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS
__compiletime_warning("copy_from_user() buffer size is not provably correct")
#endif
@@ -306,11 +285,8 @@ copy_from_user(void *to, const void __user *from, unsigned long n)
return __copy_from_user(to, from, n);
}
-static inline unsigned long __must_check
-__copy_in_user(void __user *to, const void __user *from, unsigned long n)
-{
- return uaccess.copy_in_user(n, to, from);
-}
+unsigned long __must_check
+__copy_in_user(void __user *to, const void __user *from, unsigned long n);
static inline unsigned long __must_check
copy_in_user(void __user *to, const void __user *from, unsigned long n)
@@ -322,18 +298,22 @@ copy_in_user(void __user *to, const void __user *from, unsigned long n)
/*
* Copy a null terminated string from userspace.
*/
+
+long __strncpy_from_user(char *dst, const char __user *src, long count);
+
static inline long __must_check
strncpy_from_user(char *dst, const char __user *src, long count)
{
might_fault();
- return uaccess.strncpy_from_user(count, src, dst);
+ return __strncpy_from_user(dst, src, count);
}
-static inline unsigned long
-strnlen_user(const char __user * src, unsigned long n)
+unsigned long __must_check __strnlen_user(const char __user *src, unsigned long count);
+
+static inline unsigned long strnlen_user(const char __user *src, unsigned long n)
{
might_fault();
- return uaccess.strnlen_user(n, src);
+ return __strnlen_user(src, n);
}
/**
@@ -355,21 +335,14 @@ strnlen_user(const char __user * src, unsigned long n)
/*
* Zero Userspace
*/
+unsigned long __must_check __clear_user(void __user *to, unsigned long size);
-static inline unsigned long __must_check
-__clear_user(void __user *to, unsigned long n)
-{
- return uaccess.clear_user(n, to);
-}
-
-static inline unsigned long __must_check
-clear_user(void __user *to, unsigned long n)
+static inline unsigned long __must_check clear_user(void __user *to, unsigned long n)
{
might_fault();
- return uaccess.clear_user(n, to);
+ return __clear_user(to, n);
}
-extern int copy_to_user_real(void __user *dest, void *src, size_t count);
-extern int copy_from_user_real(void *dest, void __user *src, size_t count);
+int copy_to_user_real(void __user *dest, void *src, unsigned long count);
#endif /* __S390_UACCESS_H */
diff --git a/arch/s390/include/uapi/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h
index d25da598ec62..c003c6a73b1e 100644
--- a/arch/s390/include/uapi/asm/kvm.h
+++ b/arch/s390/include/uapi/asm/kvm.h
@@ -16,6 +16,44 @@
#define __KVM_S390
+/* Device control API: s390-specific devices */
+#define KVM_DEV_FLIC_GET_ALL_IRQS 1
+#define KVM_DEV_FLIC_ENQUEUE 2
+#define KVM_DEV_FLIC_CLEAR_IRQS 3
+#define KVM_DEV_FLIC_APF_ENABLE 4
+#define KVM_DEV_FLIC_APF_DISABLE_WAIT 5
+#define KVM_DEV_FLIC_ADAPTER_REGISTER 6
+#define KVM_DEV_FLIC_ADAPTER_MODIFY 7
+/*
+ * We can have up to 4*64k pending subchannels + 8 adapter interrupts,
+ * as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts.
+ * There are also sclp and machine checks. This gives us
+ * sizeof(kvm_s390_irq)*(4*65536+8+64*64+1+1) = 72 * 266250 = 19170000
+ * Lets round up to 8192 pages.
+ */
+#define KVM_S390_MAX_FLOAT_IRQS 266250
+#define KVM_S390_FLIC_MAX_BUFFER 0x2000000
+
+struct kvm_s390_io_adapter {
+ __u32 id;
+ __u8 isc;
+ __u8 maskable;
+ __u8 swap;
+ __u8 pad;
+};
+
+#define KVM_S390_IO_ADAPTER_MASK 1
+#define KVM_S390_IO_ADAPTER_MAP 2
+#define KVM_S390_IO_ADAPTER_UNMAP 3
+
+struct kvm_s390_io_adapter_req {
+ __u32 id;
+ __u8 type;
+ __u8 mask;
+ __u16 pad0;
+ __u64 addr;
+};
+
/* for KVM_GET_REGS and KVM_SET_REGS */
struct kvm_regs {
/* general purpose regs for s390 */
@@ -57,4 +95,9 @@ struct kvm_sync_regs {
#define KVM_REG_S390_EPOCHDIFF (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x2)
#define KVM_REG_S390_CPU_TIMER (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x3)
#define KVM_REG_S390_CLOCK_COMP (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x4)
+#define KVM_REG_S390_PFTOKEN (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x5)
+#define KVM_REG_S390_PFCOMPARE (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x6)
+#define KVM_REG_S390_PFSELECT (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x7)
+#define KVM_REG_S390_PP (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x8)
+#define KVM_REG_S390_GBEA (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x9)
#endif
diff --git a/arch/s390/include/uapi/asm/ptrace.h b/arch/s390/include/uapi/asm/ptrace.h
index 7e0b498a2c2b..a150f4fabe43 100644
--- a/arch/s390/include/uapi/asm/ptrace.h
+++ b/arch/s390/include/uapi/asm/ptrace.h
@@ -403,6 +403,12 @@ typedef struct
#define PTRACE_TE_ABORT_RAND 0x5011
/*
+ * The numbers chosen here are somewhat arbitrary but absolutely MUST
+ * not overlap with any of the number assigned in <linux/ptrace.h>.
+ */
+#define PTRACE_SINGLEBLOCK 12 /* resume execution until next branch */
+
+/*
* PT_PROT definition is loosely based on hppa bsd definition in
* gdb/hppab-nat.c
*/
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index 1b3ac09c11b6..a95c4ca99617 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -47,9 +47,8 @@ obj-$(CONFIG_SCHED_BOOK) += topology.o
obj-$(CONFIG_HIBERNATION) += suspend.o swsusp_asm64.o
obj-$(CONFIG_AUDIT) += audit.o
compat-obj-$(CONFIG_AUDIT) += compat_audit.o
-obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o \
- compat_wrapper.o compat_exec_domain.o \
- $(compat-obj-y)
+obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o
+obj-$(CONFIG_COMPAT) += compat_wrapper.o $(compat-obj-y)
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_KPROBES) += kprobes.o
diff --git a/arch/s390/kernel/compat_exec_domain.c b/arch/s390/kernel/compat_exec_domain.c
deleted file mode 100644
index 765fabdada9f..000000000000
--- a/arch/s390/kernel/compat_exec_domain.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Support for 32-bit Linux for S390 personality.
- *
- * Copyright IBM Corp. 2000
- * Author(s): Gerhard Tonn (ton@de.ibm.com)
- *
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/personality.h>
-#include <linux/sched.h>
-
-static struct exec_domain s390_exec_domain;
-
-static int __init s390_init (void)
-{
- s390_exec_domain.name = "Linux/s390";
- s390_exec_domain.handler = NULL;
- s390_exec_domain.pers_low = PER_LINUX32;
- s390_exec_domain.pers_high = PER_LINUX32;
- s390_exec_domain.signal_map = default_exec_domain.signal_map;
- s390_exec_domain.signal_invmap = default_exec_domain.signal_invmap;
- register_exec_domain(&s390_exec_domain);
- return 0;
-}
-
-__initcall(s390_init);
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index db02052bd137..ca38139423ae 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -86,48 +86,51 @@
#define SET_STAT_UID(stat, uid) (stat).st_uid = high2lowuid(uid)
#define SET_STAT_GID(stat, gid) (stat).st_gid = high2lowgid(gid)
-asmlinkage long sys32_chown16(const char __user * filename, u16 user, u16 group)
+COMPAT_SYSCALL_DEFINE3(s390_chown16, const char __user *, filename,
+ u16, user, u16, group)
{
return sys_chown(filename, low2highuid(user), low2highgid(group));
}
-asmlinkage long sys32_lchown16(const char __user * filename, u16 user, u16 group)
+COMPAT_SYSCALL_DEFINE3(s390_lchown16, const char __user *,
+ filename, u16, user, u16, group)
{
return sys_lchown(filename, low2highuid(user), low2highgid(group));
}
-asmlinkage long sys32_fchown16(unsigned int fd, u16 user, u16 group)
+COMPAT_SYSCALL_DEFINE3(s390_fchown16, unsigned int, fd, u16, user, u16, group)
{
return sys_fchown(fd, low2highuid(user), low2highgid(group));
}
-asmlinkage long sys32_setregid16(u16 rgid, u16 egid)
+COMPAT_SYSCALL_DEFINE2(s390_setregid16, u16, rgid, u16, egid)
{
return sys_setregid(low2highgid(rgid), low2highgid(egid));
}
-asmlinkage long sys32_setgid16(u16 gid)
+COMPAT_SYSCALL_DEFINE1(s390_setgid16, u16, gid)
{
return sys_setgid((gid_t)gid);
}
-asmlinkage long sys32_setreuid16(u16 ruid, u16 euid)
+COMPAT_SYSCALL_DEFINE2(s390_setreuid16, u16, ruid, u16, euid)
{
return sys_setreuid(low2highuid(ruid), low2highuid(euid));
}
-asmlinkage long sys32_setuid16(u16 uid)
+COMPAT_SYSCALL_DEFINE1(s390_setuid16, u16, uid)
{
return sys_setuid((uid_t)uid);
}
-asmlinkage long sys32_setresuid16(u16 ruid, u16 euid, u16 suid)
+COMPAT_SYSCALL_DEFINE3(s390_setresuid16, u16, ruid, u16, euid, u16, suid)
{
return sys_setresuid(low2highuid(ruid), low2highuid(euid),
- low2highuid(suid));
+ low2highuid(suid));
}
-asmlinkage long sys32_getresuid16(u16 __user *ruidp, u16 __user *euidp, u16 __user *suidp)
+COMPAT_SYSCALL_DEFINE3(s390_getresuid16, u16 __user *, ruidp,
+ u16 __user *, euidp, u16 __user *, suidp)
{
const struct cred *cred = current_cred();
int retval;
@@ -144,13 +147,14 @@ asmlinkage long sys32_getresuid16(u16 __user *ruidp, u16 __user *euidp, u16 __us
return retval;
}
-asmlinkage long sys32_setresgid16(u16 rgid, u16 egid, u16 sgid)
+COMPAT_SYSCALL_DEFINE3(s390_setresgid16, u16, rgid, u16, egid, u16, sgid)
{
return sys_setresgid(low2highgid(rgid), low2highgid(egid),
- low2highgid(sgid));
+ low2highgid(sgid));
}
-asmlinkage long sys32_getresgid16(u16 __user *rgidp, u16 __user *egidp, u16 __user *sgidp)
+COMPAT_SYSCALL_DEFINE3(s390_getresgid16, u16 __user *, rgidp,
+ u16 __user *, egidp, u16 __user *, sgidp)
{
const struct cred *cred = current_cred();
int retval;
@@ -167,12 +171,12 @@ asmlinkage long sys32_getresgid16(u16 __user *rgidp, u16 __user *egidp, u16 __us
return retval;
}
-asmlinkage long sys32_setfsuid16(u16 uid)
+COMPAT_SYSCALL_DEFINE1(s390_setfsuid16, u16, uid)
{
return sys_setfsuid((uid_t)uid);
}
-asmlinkage long sys32_setfsgid16(u16 gid)
+COMPAT_SYSCALL_DEFINE1(s390_setfsgid16, u16, gid)
{
return sys_setfsgid((gid_t)gid);
}
@@ -215,7 +219,7 @@ static int groups16_from_user(struct group_info *group_info, u16 __user *groupli
return 0;
}
-asmlinkage long sys32_getgroups16(int gidsetsize, u16 __user *grouplist)
+COMPAT_SYSCALL_DEFINE2(s390_getgroups16, int, gidsetsize, u16 __user *, grouplist)
{
const struct cred *cred = current_cred();
int i;
@@ -240,7 +244,7 @@ out:
return i;
}
-asmlinkage long sys32_setgroups16(int gidsetsize, u16 __user *grouplist)
+COMPAT_SYSCALL_DEFINE2(s390_setgroups16, int, gidsetsize, u16 __user *, grouplist)
{
struct group_info *group_info;
int retval;
@@ -265,22 +269,22 @@ asmlinkage long sys32_setgroups16(int gidsetsize, u16 __user *grouplist)
return retval;
}
-asmlinkage long sys32_getuid16(void)
+COMPAT_SYSCALL_DEFINE0(s390_getuid16)
{
return high2lowuid(from_kuid_munged(current_user_ns(), current_uid()));
}
-asmlinkage long sys32_geteuid16(void)
+COMPAT_SYSCALL_DEFINE0(s390_geteuid16)
{
return high2lowuid(from_kuid_munged(current_user_ns(), current_euid()));
}
-asmlinkage long sys32_getgid16(void)
+COMPAT_SYSCALL_DEFINE0(s390_getgid16)
{
return high2lowgid(from_kgid_munged(current_user_ns(), current_gid()));
}
-asmlinkage long sys32_getegid16(void)
+COMPAT_SYSCALL_DEFINE0(s390_getegid16)
{
return high2lowgid(from_kgid_munged(current_user_ns(), current_egid()));
}
@@ -295,41 +299,35 @@ COMPAT_SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, compat_ulong_t, second,
}
#endif
-asmlinkage long sys32_truncate64(const char __user * path, unsigned long high, unsigned long low)
+COMPAT_SYSCALL_DEFINE3(s390_truncate64, const char __user *, path, u32, high, u32, low)
{
- if ((int)high < 0)
- return -EINVAL;
- else
- return sys_truncate(path, (high << 32) | low);
+ return sys_truncate(path, (unsigned long)high << 32 | low);
}
-asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low)
+COMPAT_SYSCALL_DEFINE3(s390_ftruncate64, unsigned int, fd, u32, high, u32, low)
{
- if ((int)high < 0)
- return -EINVAL;
- else
- return sys_ftruncate(fd, (high << 32) | low);
+ return sys_ftruncate(fd, (unsigned long)high << 32 | low);
}
-asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf,
- size_t count, u32 poshi, u32 poslo)
+COMPAT_SYSCALL_DEFINE5(s390_pread64, unsigned int, fd, char __user *, ubuf,
+ compat_size_t, count, u32, high, u32, low)
{
if ((compat_ssize_t) count < 0)
return -EINVAL;
- return sys_pread64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
+ return sys_pread64(fd, ubuf, count, (unsigned long)high << 32 | low);
}
-asmlinkage long sys32_pwrite64(unsigned int fd, const char __user *ubuf,
- size_t count, u32 poshi, u32 poslo)
+COMPAT_SYSCALL_DEFINE5(s390_pwrite64, unsigned int, fd, const char __user *, ubuf,
+ compat_size_t, count, u32, high, u32, low)
{
if ((compat_ssize_t) count < 0)
return -EINVAL;
- return sys_pwrite64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
+ return sys_pwrite64(fd, ubuf, count, (unsigned long)high << 32 | low);
}
-asmlinkage compat_ssize_t sys32_readahead(int fd, u32 offhi, u32 offlo, s32 count)
+COMPAT_SYSCALL_DEFINE4(s390_readahead, int, fd, u32, high, u32, low, s32, count)
{
- return sys_readahead(fd, ((loff_t)AA(offhi) << 32) | AA(offlo), count);
+ return sys_readahead(fd, (unsigned long)high << 32 | low, count);
}
struct stat64_emu31 {
@@ -381,7 +379,7 @@ static int cp_stat64(struct stat64_emu31 __user *ubuf, struct kstat *stat)
return copy_to_user(ubuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
}
-asmlinkage long sys32_stat64(const char __user * filename, struct stat64_emu31 __user * statbuf)
+COMPAT_SYSCALL_DEFINE2(s390_stat64, const char __user *, filename, struct stat64_emu31 __user *, statbuf)
{
struct kstat stat;
int ret = vfs_stat(filename, &stat);
@@ -390,7 +388,7 @@ asmlinkage long sys32_stat64(const char __user * filename, struct stat64_emu31 _
return ret;
}
-asmlinkage long sys32_lstat64(const char __user * filename, struct stat64_emu31 __user * statbuf)
+COMPAT_SYSCALL_DEFINE2(s390_lstat64, const char __user *, filename, struct stat64_emu31 __user *, statbuf)
{
struct kstat stat;
int ret = vfs_lstat(filename, &stat);
@@ -399,7 +397,7 @@ asmlinkage long sys32_lstat64(const char __user * filename, struct stat64_emu31
return ret;
}
-asmlinkage long sys32_fstat64(unsigned long fd, struct stat64_emu31 __user * statbuf)
+COMPAT_SYSCALL_DEFINE2(s390_fstat64, unsigned int, fd, struct stat64_emu31 __user *, statbuf)
{
struct kstat stat;
int ret = vfs_fstat(fd, &stat);
@@ -408,8 +406,8 @@ asmlinkage long sys32_fstat64(unsigned long fd, struct stat64_emu31 __user * sta
return ret;
}
-asmlinkage long sys32_fstatat64(unsigned int dfd, const char __user *filename,
- struct stat64_emu31 __user* statbuf, int flag)
+COMPAT_SYSCALL_DEFINE4(s390_fstatat64, unsigned int, dfd, const char __user *, filename,
+ struct stat64_emu31 __user *, statbuf, int, flag)
{
struct kstat stat;
int error;
@@ -435,7 +433,7 @@ struct mmap_arg_struct_emu31 {
compat_ulong_t offset;
};
-asmlinkage unsigned long old32_mmap(struct mmap_arg_struct_emu31 __user *arg)
+COMPAT_SYSCALL_DEFINE1(s390_old_mmap, struct mmap_arg_struct_emu31 __user *, arg)
{
struct mmap_arg_struct_emu31 a;
@@ -447,7 +445,7 @@ asmlinkage unsigned long old32_mmap(struct mmap_arg_struct_emu31 __user *arg)
a.offset >> PAGE_SHIFT);
}
-asmlinkage long sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg)
+COMPAT_SYSCALL_DEFINE1(s390_mmap2, struct mmap_arg_struct_emu31 __user *, arg)
{
struct mmap_arg_struct_emu31 a;
@@ -456,7 +454,7 @@ asmlinkage long sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg)
return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
}
-asmlinkage long sys32_read(unsigned int fd, char __user * buf, size_t count)
+COMPAT_SYSCALL_DEFINE3(s390_read, unsigned int, fd, char __user *, buf, compat_size_t, count)
{
if ((compat_ssize_t) count < 0)
return -EINVAL;
@@ -464,7 +462,7 @@ asmlinkage long sys32_read(unsigned int fd, char __user * buf, size_t count)
return sys_read(fd, buf, count);
}
-asmlinkage long sys32_write(unsigned int fd, const char __user * buf, size_t count)
+COMPAT_SYSCALL_DEFINE3(s390_write, unsigned int, fd, const char __user *, buf, compat_size_t, count)
{
if ((compat_ssize_t) count < 0)
return -EINVAL;
@@ -478,14 +476,13 @@ asmlinkage long sys32_write(unsigned int fd, const char __user * buf, size_t cou
* because the 31 bit values differ from the 64 bit values.
*/
-asmlinkage long
-sys32_fadvise64(int fd, loff_t offset, size_t len, int advise)
+COMPAT_SYSCALL_DEFINE5(s390_fadvise64, int, fd, u32, high, u32, low, compat_size_t, len, int, advise)
{
if (advise == 4)
advise = POSIX_FADV_DONTNEED;
else if (advise == 5)
advise = POSIX_FADV_NOREUSE;
- return sys_fadvise64(fd, offset, len, advise);
+ return sys_fadvise64(fd, (unsigned long)high << 32 | low, len, advise);
}
struct fadvise64_64_args {
@@ -495,8 +492,7 @@ struct fadvise64_64_args {
int advice;
};
-asmlinkage long
-sys32_fadvise64_64(struct fadvise64_64_args __user *args)
+COMPAT_SYSCALL_DEFINE1(s390_fadvise64_64, struct fadvise64_64_args __user *, args)
{
struct fadvise64_64_args a;
@@ -508,3 +504,17 @@ sys32_fadvise64_64(struct fadvise64_64_args __user *args)
a.advice = POSIX_FADV_NOREUSE;
return sys_fadvise64_64(a.fd, a.offset, a.len, a.advice);
}
+
+COMPAT_SYSCALL_DEFINE6(s390_sync_file_range, int, fd, u32, offhigh, u32, offlow,
+ u32, nhigh, u32, nlow, unsigned int, flags)
+{
+ return sys_sync_file_range(fd, ((loff_t)offhigh << 32) + offlow,
+ ((u64)nhigh << 32) + nlow, flags);
+}
+
+COMPAT_SYSCALL_DEFINE6(s390_fallocate, int, fd, int, mode, u32, offhigh, u32, offlow,
+ u32, lenhigh, u32, lenlow)
+{
+ return sys_fallocate(fd, mode, ((loff_t)offhigh << 32) + offlow,
+ ((u64)lenhigh << 32) + lenlow);
+}
diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h
index 1bfda3eca379..39ddfdb40ae8 100644
--- a/arch/s390/kernel/compat_linux.h
+++ b/arch/s390/kernel/compat_linux.h
@@ -76,46 +76,43 @@ struct stat64_emu31;
struct mmap_arg_struct_emu31;
struct fadvise64_64_args;
-long sys32_chown16(const char __user * filename, u16 user, u16 group);
-long sys32_lchown16(const char __user * filename, u16 user, u16 group);
-long sys32_fchown16(unsigned int fd, u16 user, u16 group);
-long sys32_setregid16(u16 rgid, u16 egid);
-long sys32_setgid16(u16 gid);
-long sys32_setreuid16(u16 ruid, u16 euid);
-long sys32_setuid16(u16 uid);
-long sys32_setresuid16(u16 ruid, u16 euid, u16 suid);
-long sys32_getresuid16(u16 __user *ruid, u16 __user *euid, u16 __user *suid);
-long sys32_setresgid16(u16 rgid, u16 egid, u16 sgid);
-long sys32_getresgid16(u16 __user *rgid, u16 __user *egid, u16 __user *sgid);
-long sys32_setfsuid16(u16 uid);
-long sys32_setfsgid16(u16 gid);
-long sys32_getgroups16(int gidsetsize, u16 __user *grouplist);
-long sys32_setgroups16(int gidsetsize, u16 __user *grouplist);
-long sys32_getuid16(void);
-long sys32_geteuid16(void);
-long sys32_getgid16(void);
-long sys32_getegid16(void);
-long sys32_truncate64(const char __user * path, unsigned long high,
- unsigned long low);
-long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low);
-long sys32_init_module(void __user *umod, unsigned long len,
- const char __user *uargs);
-long sys32_delete_module(const char __user *name_user, unsigned int flags);
-long sys32_pread64(unsigned int fd, char __user *ubuf, size_t count,
- u32 poshi, u32 poslo);
-long sys32_pwrite64(unsigned int fd, const char __user *ubuf,
- size_t count, u32 poshi, u32 poslo);
-compat_ssize_t sys32_readahead(int fd, u32 offhi, u32 offlo, s32 count);
-long sys32_stat64(const char __user * filename, struct stat64_emu31 __user * statbuf);
-long sys32_lstat64(const char __user * filename,
- struct stat64_emu31 __user * statbuf);
-long sys32_fstat64(unsigned long fd, struct stat64_emu31 __user * statbuf);
-long sys32_fstatat64(unsigned int dfd, const char __user *filename,
- struct stat64_emu31 __user* statbuf, int flag);
-unsigned long old32_mmap(struct mmap_arg_struct_emu31 __user *arg);
-long sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg);
-long sys32_read(unsigned int fd, char __user * buf, size_t count);
-long sys32_write(unsigned int fd, const char __user * buf, size_t count);
-long sys32_fadvise64(int fd, loff_t offset, size_t len, int advise);
-long sys32_fadvise64_64(struct fadvise64_64_args __user *args);
+long compat_sys_s390_chown16(const char __user *filename, u16 user, u16 group);
+long compat_sys_s390_lchown16(const char __user *filename, u16 user, u16 group);
+long compat_sys_s390_fchown16(unsigned int fd, u16 user, u16 group);
+long compat_sys_s390_setregid16(u16 rgid, u16 egid);
+long compat_sys_s390_setgid16(u16 gid);
+long compat_sys_s390_setreuid16(u16 ruid, u16 euid);
+long compat_sys_s390_setuid16(u16 uid);
+long compat_sys_s390_setresuid16(u16 ruid, u16 euid, u16 suid);
+long compat_sys_s390_getresuid16(u16 __user *ruid, u16 __user *euid, u16 __user *suid);
+long compat_sys_s390_setresgid16(u16 rgid, u16 egid, u16 sgid);
+long compat_sys_s390_getresgid16(u16 __user *rgid, u16 __user *egid, u16 __user *sgid);
+long compat_sys_s390_setfsuid16(u16 uid);
+long compat_sys_s390_setfsgid16(u16 gid);
+long compat_sys_s390_getgroups16(int gidsetsize, u16 __user *grouplist);
+long compat_sys_s390_setgroups16(int gidsetsize, u16 __user *grouplist);
+long compat_sys_s390_getuid16(void);
+long compat_sys_s390_geteuid16(void);
+long compat_sys_s390_getgid16(void);
+long compat_sys_s390_getegid16(void);
+long compat_sys_s390_truncate64(const char __user *path, u32 high, u32 low);
+long compat_sys_s390_ftruncate64(unsigned int fd, u32 high, u32 low);
+long compat_sys_s390_pread64(unsigned int fd, char __user *ubuf, compat_size_t count, u32 high, u32 low);
+long compat_sys_s390_pwrite64(unsigned int fd, const char __user *ubuf, compat_size_t count, u32 high, u32 low);
+long compat_sys_s390_readahead(int fd, u32 high, u32 low, s32 count);
+long compat_sys_s390_stat64(const char __user *filename, struct stat64_emu31 __user *statbuf);
+long compat_sys_s390_lstat64(const char __user *filename, struct stat64_emu31 __user *statbuf);
+long compat_sys_s390_fstat64(unsigned int fd, struct stat64_emu31 __user *statbuf);
+long compat_sys_s390_fstatat64(unsigned int dfd, const char __user *filename, struct stat64_emu31 __user *statbuf, int flag);
+long compat_sys_s390_old_mmap(struct mmap_arg_struct_emu31 __user *arg);
+long compat_sys_s390_mmap2(struct mmap_arg_struct_emu31 __user *arg);
+long compat_sys_s390_read(unsigned int fd, char __user * buf, compat_size_t count);
+long compat_sys_s390_write(unsigned int fd, const char __user * buf, compat_size_t count);
+long compat_sys_s390_fadvise64(int fd, u32 high, u32 low, compat_size_t len, int advise);
+long compat_sys_s390_fadvise64_64(struct fadvise64_64_args __user *args);
+long compat_sys_s390_sync_file_range(int fd, u32 offhigh, u32 offlow, u32 nhigh, u32 nlow, unsigned int flags);
+long compat_sys_s390_fallocate(int fd, int mode, u32 offhigh, u32 offlow, u32 lenhigh, u32 lenlow);
+long compat_sys_sigreturn(void);
+long compat_sys_rt_sigreturn(void);
+
#endif /* _ASM_S390X_S390_H */
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index 8b84bc373e94..7df5ed9f44d7 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -241,7 +241,7 @@ static int restore_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)
return 0;
}
-asmlinkage long sys32_sigreturn(void)
+COMPAT_SYSCALL_DEFINE0(sigreturn)
{
struct pt_regs *regs = task_pt_regs(current);
sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15];
@@ -260,7 +260,7 @@ badframe:
return 0;
}
-asmlinkage long sys32_rt_sigreturn(void)
+COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
{
struct pt_regs *regs = task_pt_regs(current);
rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15];
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
deleted file mode 100644
index 59c8efce1b99..000000000000
--- a/arch/s390/kernel/compat_wrapper.S
+++ /dev/null
@@ -1,1425 +0,0 @@
-/*
-* wrapper for 31 bit compatible system calls.
-*
-* Copyright IBM Corp. 2000, 2006
-* Author(s): Gerhard Tonn (ton@de.ibm.com),
-* Thomas Spatzier (tspat@de.ibm.com)
-*/
-
-#include <linux/linkage.h>
-
-ENTRY(sys32_exit_wrapper)
- lgfr %r2,%r2 # int
- jg sys_exit # branch to sys_exit
-
-ENTRY(sys32_read_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # char *
- llgfr %r4,%r4 # size_t
- jg sys32_read # branch to sys_read
-
-ENTRY(sys32_write_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # const char *
- llgfr %r4,%r4 # size_t
- jg sys32_write # branch to system call
-
-ENTRY(sys32_close_wrapper)
- llgfr %r2,%r2 # unsigned int
- jg sys_close # branch to system call
-
-ENTRY(sys32_creat_wrapper)
- llgtr %r2,%r2 # const char *
- lgfr %r3,%r3 # int
- jg sys_creat # branch to system call
-
-ENTRY(sys32_link_wrapper)
- llgtr %r2,%r2 # const char *
- llgtr %r3,%r3 # const char *
- jg sys_link # branch to system call
-
-ENTRY(sys32_unlink_wrapper)
- llgtr %r2,%r2 # const char *
- jg sys_unlink # branch to system call
-
-ENTRY(sys32_chdir_wrapper)
- llgtr %r2,%r2 # const char *
- jg sys_chdir # branch to system call
-
-ENTRY(sys32_time_wrapper)
- llgtr %r2,%r2 # int *
- jg compat_sys_time # branch to system call
-
-ENTRY(sys32_mknod_wrapper)
- llgtr %r2,%r2 # const char *
- lgfr %r3,%r3 # int
- llgfr %r4,%r4 # dev
- jg sys_mknod # branch to system call
-
-ENTRY(sys32_chmod_wrapper)
- llgtr %r2,%r2 # const char *
- llgfr %r3,%r3 # mode_t
- jg sys_chmod # branch to system call
-
-ENTRY(sys32_lchown16_wrapper)
- llgtr %r2,%r2 # const char *
- llgfr %r3,%r3 # __kernel_old_uid_emu31_t
- llgfr %r4,%r4 # __kernel_old_uid_emu31_t
- jg sys32_lchown16 # branch to system call
-
-#sys32_getpid_wrapper # void
-
-ENTRY(sys32_mount_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # char *
- llgtr %r4,%r4 # char *
- llgfr %r5,%r5 # unsigned long
- llgtr %r6,%r6 # void *
- jg compat_sys_mount # branch to system call
-
-ENTRY(sys32_oldumount_wrapper)
- llgtr %r2,%r2 # char *
- jg sys_oldumount # branch to system call
-
-ENTRY(sys32_setuid16_wrapper)
- llgfr %r2,%r2 # __kernel_old_uid_emu31_t
- jg sys32_setuid16 # branch to system call
-
-#sys32_getuid16_wrapper # void
-
-ENTRY(sys32_ptrace_wrapper)
- lgfr %r2,%r2 # long
- lgfr %r3,%r3 # long
- llgtr %r4,%r4 # long
- llgfr %r5,%r5 # long
- jg compat_sys_ptrace # branch to system call
-
-ENTRY(sys32_alarm_wrapper)
- llgfr %r2,%r2 # unsigned int
- jg sys_alarm # branch to system call
-
-ENTRY(compat_sys_utime_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # struct compat_utimbuf *
- jg compat_sys_utime # branch to system call
-
-ENTRY(sys32_access_wrapper)
- llgtr %r2,%r2 # const char *
- lgfr %r3,%r3 # int
- jg sys_access # branch to system call
-
-ENTRY(sys32_nice_wrapper)
- lgfr %r2,%r2 # int
- jg sys_nice # branch to system call
-
-#sys32_sync_wrapper # void
-
-ENTRY(sys32_kill_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- jg sys_kill # branch to system call
-
-ENTRY(sys32_rename_wrapper)
- llgtr %r2,%r2 # const char *
- llgtr %r3,%r3 # const char *
- jg sys_rename # branch to system call
-
-ENTRY(sys32_mkdir_wrapper)
- llgtr %r2,%r2 # const char *
- lgfr %r3,%r3 # int
- jg sys_mkdir # branch to system call
-
-ENTRY(sys32_rmdir_wrapper)
- llgtr %r2,%r2 # const char *
- jg sys_rmdir # branch to system call
-
-ENTRY(sys32_dup_wrapper)
- llgfr %r2,%r2 # unsigned int
- jg sys_dup # branch to system call
-
-ENTRY(sys32_pipe_wrapper)
- llgtr %r2,%r2 # u32 *
- jg sys_pipe # branch to system call
-
-ENTRY(compat_sys_times_wrapper)
- llgtr %r2,%r2 # struct compat_tms *
- jg compat_sys_times # branch to system call
-
-ENTRY(sys32_brk_wrapper)
- llgtr %r2,%r2 # unsigned long
- jg sys_brk # branch to system call
-
-ENTRY(sys32_setgid16_wrapper)
- llgfr %r2,%r2 # __kernel_old_gid_emu31_t
- jg sys32_setgid16 # branch to system call
-
-#sys32_getgid16_wrapper # void
-
-ENTRY(sys32_signal_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # __sighandler_t
- jg sys_signal
-
-#sys32_geteuid16_wrapper # void
-
-#sys32_getegid16_wrapper # void
-
-ENTRY(sys32_acct_wrapper)
- llgtr %r2,%r2 # char *
- jg sys_acct # branch to system call
-
-ENTRY(sys32_umount_wrapper)
- llgtr %r2,%r2 # char *
- lgfr %r3,%r3 # int
- jg sys_umount # branch to system call
-
-ENTRY(compat_sys_ioctl_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # unsigned int
- llgfr %r4,%r4 # unsigned int
- jg compat_sys_ioctl # branch to system call
-
-ENTRY(compat_sys_fcntl_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # unsigned int
- llgfr %r4,%r4 # unsigned long
- jg compat_sys_fcntl # branch to system call
-
-ENTRY(sys32_setpgid_wrapper)
- lgfr %r2,%r2 # pid_t
- lgfr %r3,%r3 # pid_t
- jg sys_setpgid # branch to system call
-
-ENTRY(sys32_umask_wrapper)
- lgfr %r2,%r2 # int
- jg sys_umask # branch to system call
-
-ENTRY(sys32_chroot_wrapper)
- llgtr %r2,%r2 # char *
- jg sys_chroot # branch to system call
-
-ENTRY(sys32_ustat_wrapper)
- llgfr %r2,%r2 # dev_t
- llgtr %r3,%r3 # struct ustat *
- jg compat_sys_ustat
-
-ENTRY(sys32_dup2_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # unsigned int
- jg sys_dup2 # branch to system call
-
-#sys32_getppid_wrapper # void
-
-#sys32_getpgrp_wrapper # void
-
-#sys32_setsid_wrapper # void
-
-ENTRY(sys32_setreuid16_wrapper)
- llgfr %r2,%r2 # __kernel_old_uid_emu31_t
- llgfr %r3,%r3 # __kernel_old_uid_emu31_t
- jg sys32_setreuid16 # branch to system call
-
-ENTRY(sys32_setregid16_wrapper)
- llgfr %r2,%r2 # __kernel_old_gid_emu31_t
- llgfr %r3,%r3 # __kernel_old_gid_emu31_t
- jg sys32_setregid16 # branch to system call
-
-ENTRY(sys_sigsuspend_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- llgfr %r4,%r4 # old_sigset_t
- jg sys_sigsuspend
-
-ENTRY(compat_sys_sigpending_wrapper)
- llgtr %r2,%r2 # compat_old_sigset_t *
- jg compat_sys_sigpending # branch to system call
-
-ENTRY(sys32_sethostname_wrapper)
- llgtr %r2,%r2 # char *
- lgfr %r3,%r3 # int
- jg sys_sethostname # branch to system call
-
-ENTRY(compat_sys_setrlimit_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # struct rlimit_emu31 *
- jg compat_sys_setrlimit # branch to system call
-
-ENTRY(compat_sys_old_getrlimit_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # struct rlimit_emu31 *
- jg compat_sys_old_getrlimit # branch to system call
-
-ENTRY(compat_sys_getrlimit_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # struct rlimit_emu31 *
- jg compat_sys_getrlimit # branch to system call
-
-ENTRY(sys32_mmap2_wrapper)
- llgtr %r2,%r2 # struct mmap_arg_struct_emu31 *
- jg sys32_mmap2 # branch to system call
-
-ENTRY(compat_sys_gettimeofday_wrapper)
- llgtr %r2,%r2 # struct timeval_emu31 *
- llgtr %r3,%r3 # struct timezone *
- jg compat_sys_gettimeofday # branch to system call
-
-ENTRY(compat_sys_settimeofday_wrapper)
- llgtr %r2,%r2 # struct timeval_emu31 *
- llgtr %r3,%r3 # struct timezone *
- jg compat_sys_settimeofday # branch to system call
-
-ENTRY(sys32_getgroups16_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
- jg sys32_getgroups16 # branch to system call
-
-ENTRY(sys32_setgroups16_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
- jg sys32_setgroups16 # branch to system call
-
-ENTRY(sys32_symlink_wrapper)
- llgtr %r2,%r2 # const char *
- llgtr %r3,%r3 # const char *
- jg sys_symlink # branch to system call
-
-ENTRY(sys32_readlink_wrapper)
- llgtr %r2,%r2 # const char *
- llgtr %r3,%r3 # char *
- lgfr %r4,%r4 # int
- jg sys_readlink # branch to system call
-
-ENTRY(sys32_uselib_wrapper)
- llgtr %r2,%r2 # const char *
- jg sys_uselib # branch to system call
-
-ENTRY(sys32_swapon_wrapper)
- llgtr %r2,%r2 # const char *
- lgfr %r3,%r3 # int
- jg sys_swapon # branch to system call
-
-ENTRY(sys32_reboot_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- llgfr %r4,%r4 # unsigned int
- llgtr %r5,%r5 # void *
- jg sys_reboot # branch to system call
-
-ENTRY(old32_readdir_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # void *
- llgfr %r4,%r4 # unsigned int
- jg compat_sys_old_readdir # branch to system call
-
-ENTRY(old32_mmap_wrapper)
- llgtr %r2,%r2 # struct mmap_arg_struct_emu31 *
- jg old32_mmap # branch to system call
-
-ENTRY(sys32_munmap_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # size_t
- jg sys_munmap # branch to system call
-
-ENTRY(sys32_fchmod_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # mode_t
- jg sys_fchmod # branch to system call
-
-ENTRY(sys32_fchown16_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # compat_uid_t
- llgfr %r4,%r4 # compat_uid_t
- jg sys32_fchown16 # branch to system call
-
-ENTRY(sys32_getpriority_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- jg sys_getpriority # branch to system call
-
-ENTRY(sys32_setpriority_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- lgfr %r4,%r4 # int
- jg sys_setpriority # branch to system call
-
-ENTRY(compat_sys_statfs_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # struct compat_statfs *
- jg compat_sys_statfs # branch to system call
-
-ENTRY(compat_sys_fstatfs_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # struct compat_statfs *
- jg compat_sys_fstatfs # branch to system call
-
-ENTRY(compat_sys_socketcall_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # u32 *
- jg compat_sys_socketcall # branch to system call
-
-ENTRY(sys32_syslog_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # char *
- lgfr %r4,%r4 # int
- jg sys_syslog # branch to system call
-
-ENTRY(compat_sys_newstat_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # struct stat_emu31 *
- jg compat_sys_newstat # branch to system call
-
-ENTRY(compat_sys_newlstat_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # struct stat_emu31 *
- jg compat_sys_newlstat # branch to system call
-
-ENTRY(compat_sys_newfstat_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # struct stat_emu31 *
- jg compat_sys_newfstat # branch to system call
-
-#sys32_vhangup_wrapper # void
-
-ENTRY(sys32_swapoff_wrapper)
- llgtr %r2,%r2 # const char *
- jg sys_swapoff # branch to system call
-
-ENTRY(compat_sys_sysinfo_wrapper)
- llgtr %r2,%r2 # struct sysinfo_emu31 *
- jg compat_sys_sysinfo # branch to system call
-
-ENTRY(sys32_fsync_wrapper)
- llgfr %r2,%r2 # unsigned int
- jg sys_fsync # branch to system call
-
-#sys32_sigreturn_wrapper # done in sigreturn_glue
-
-#sys32_clone_wrapper # done in clone_glue
-
-ENTRY(sys32_setdomainname_wrapper)
- llgtr %r2,%r2 # char *
- lgfr %r3,%r3 # int
- jg sys_setdomainname # branch to system call
-
-ENTRY(sys32_newuname_wrapper)
- llgtr %r2,%r2 # struct new_utsname *
- jg sys_newuname # branch to system call
-
-ENTRY(compat_sys_adjtimex_wrapper)
- llgtr %r2,%r2 # struct compat_timex *
- jg compat_sys_adjtimex # branch to system call
-
-ENTRY(sys32_mprotect_wrapper)
- llgtr %r2,%r2 # unsigned long (actually pointer
- llgfr %r3,%r3 # size_t
- llgfr %r4,%r4 # unsigned long
- jg sys_mprotect # branch to system call
-
-ENTRY(sys_init_module_wrapper)
- llgtr %r2,%r2 # void *
- llgfr %r3,%r3 # unsigned long
- llgtr %r4,%r4 # char *
- jg sys_init_module # branch to system call
-
-ENTRY(sys_delete_module_wrapper)
- llgtr %r2,%r2 # const char *
- llgfr %r3,%r3 # unsigned int
- jg sys_delete_module # branch to system call
-
-ENTRY(sys32_quotactl_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # const char *
- llgfr %r4,%r4 # qid_t
- llgtr %r5,%r5 # caddr_t
- jg sys_quotactl # branch to system call
-
-ENTRY(sys32_getpgid_wrapper)
- lgfr %r2,%r2 # pid_t
- jg sys_getpgid # branch to system call
-
-ENTRY(sys32_fchdir_wrapper)
- llgfr %r2,%r2 # unsigned int
- jg sys_fchdir # branch to system call
-
-ENTRY(sys32_bdflush_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # long
- jg sys_bdflush # branch to system call
-
-ENTRY(sys32_sysfs_wrapper)
- lgfr %r2,%r2 # int
- llgfr %r3,%r3 # unsigned long
- llgfr %r4,%r4 # unsigned long
- jg sys_sysfs # branch to system call
-
-ENTRY(sys32_personality_wrapper)
- llgfr %r2,%r2 # unsigned int
- jg sys_s390_personality # branch to system call
-
-ENTRY(sys32_setfsuid16_wrapper)
- llgfr %r2,%r2 # __kernel_old_uid_emu31_t
- jg sys32_setfsuid16 # branch to system call
-
-ENTRY(sys32_setfsgid16_wrapper)
- llgfr %r2,%r2 # __kernel_old_gid_emu31_t
- jg sys32_setfsgid16 # branch to system call
-
-ENTRY(sys32_llseek_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # unsigned long
- llgfr %r4,%r4 # unsigned long
- llgtr %r5,%r5 # loff_t *
- llgfr %r6,%r6 # unsigned int
- jg sys_llseek # branch to system call
-
-ENTRY(sys32_getdents_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # void *
- llgfr %r4,%r4 # unsigned int
- jg compat_sys_getdents # branch to system call
-
-ENTRY(compat_sys_select_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # compat_fd_set *
- llgtr %r4,%r4 # compat_fd_set *
- llgtr %r5,%r5 # compat_fd_set *
- llgtr %r6,%r6 # struct compat_timeval *
- jg compat_sys_select # branch to system call
-
-ENTRY(sys32_flock_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # unsigned int
- jg sys_flock # branch to system call
-
-ENTRY(sys32_msync_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # size_t
- lgfr %r4,%r4 # int
- jg sys_msync # branch to system call
-
-ENTRY(compat_sys_readv_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const struct compat_iovec *
- llgfr %r4,%r4 # unsigned long
- jg compat_sys_readv # branch to system call
-
-ENTRY(compat_sys_writev_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const struct compat_iovec *
- llgfr %r4,%r4 # unsigned long
- jg compat_sys_writev # branch to system call
-
-ENTRY(sys32_getsid_wrapper)
- lgfr %r2,%r2 # pid_t
- jg sys_getsid # branch to system call
-
-ENTRY(sys32_fdatasync_wrapper)
- llgfr %r2,%r2 # unsigned int
- jg sys_fdatasync # branch to system call
-
-ENTRY(sys32_mlock_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # size_t
- jg sys_mlock # branch to system call
-
-ENTRY(sys32_munlock_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # size_t
- jg sys_munlock # branch to system call
-
-ENTRY(sys32_mlockall_wrapper)
- lgfr %r2,%r2 # int
- jg sys_mlockall # branch to system call
-
-#sys32_munlockall_wrapper # void
-
-ENTRY(sys32_sched_setparam_wrapper)
- lgfr %r2,%r2 # pid_t
- llgtr %r3,%r3 # struct sched_param *
- jg sys_sched_setparam # branch to system call
-
-ENTRY(sys32_sched_getparam_wrapper)
- lgfr %r2,%r2 # pid_t
- llgtr %r3,%r3 # struct sched_param *
- jg sys_sched_getparam # branch to system call
-
-ENTRY(sys32_sched_setscheduler_wrapper)
- lgfr %r2,%r2 # pid_t
- lgfr %r3,%r3 # int
- llgtr %r4,%r4 # struct sched_param *
- jg sys_sched_setscheduler # branch to system call
-
-ENTRY(sys32_sched_getscheduler_wrapper)
- lgfr %r2,%r2 # pid_t
- jg sys_sched_getscheduler # branch to system call
-
-#sys32_sched_yield_wrapper # void
-
-ENTRY(sys32_sched_get_priority_max_wrapper)
- lgfr %r2,%r2 # int
- jg sys_sched_get_priority_max # branch to system call
-
-ENTRY(sys32_sched_get_priority_min_wrapper)
- lgfr %r2,%r2 # int
- jg sys_sched_get_priority_min # branch to system call
-
-ENTRY(compat_sys_nanosleep_wrapper)
- llgtr %r2,%r2 # struct compat_timespec *
- llgtr %r3,%r3 # struct compat_timespec *
- jg compat_sys_nanosleep # branch to system call
-
-ENTRY(sys32_mremap_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # unsigned long
- llgfr %r4,%r4 # unsigned long
- llgfr %r5,%r5 # unsigned long
- llgfr %r6,%r6 # unsigned long
- jg sys_mremap # branch to system call
-
-ENTRY(sys32_setresuid16_wrapper)
- llgfr %r2,%r2 # __kernel_old_uid_emu31_t
- llgfr %r3,%r3 # __kernel_old_uid_emu31_t
- llgfr %r4,%r4 # __kernel_old_uid_emu31_t
- jg sys32_setresuid16 # branch to system call
-
-ENTRY(sys32_getresuid16_wrapper)
- llgtr %r2,%r2 # __kernel_old_uid_emu31_t *
- llgtr %r3,%r3 # __kernel_old_uid_emu31_t *
- llgtr %r4,%r4 # __kernel_old_uid_emu31_t *
- jg sys32_getresuid16 # branch to system call
-
-ENTRY(sys32_poll_wrapper)
- llgtr %r2,%r2 # struct pollfd *
- llgfr %r3,%r3 # unsigned int
- lgfr %r4,%r4 # int
- jg sys_poll # branch to system call
-
-ENTRY(sys32_setresgid16_wrapper)
- llgfr %r2,%r2 # __kernel_old_gid_emu31_t
- llgfr %r3,%r3 # __kernel_old_gid_emu31_t
- llgfr %r4,%r4 # __kernel_old_gid_emu31_t
- jg sys32_setresgid16 # branch to system call
-
-ENTRY(sys32_getresgid16_wrapper)
- llgtr %r2,%r2 # __kernel_old_gid_emu31_t *
- llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
- llgtr %r4,%r4 # __kernel_old_gid_emu31_t *
- jg sys32_getresgid16 # branch to system call
-
-ENTRY(sys32_prctl_wrapper)
- lgfr %r2,%r2 # int
- llgfr %r3,%r3 # unsigned long
- llgfr %r4,%r4 # unsigned long
- llgfr %r5,%r5 # unsigned long
- llgfr %r6,%r6 # unsigned long
- jg sys_prctl # branch to system call
-
-#sys32_rt_sigreturn_wrapper # done in rt_sigreturn_glue
-
-ENTRY(sys32_pread64_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # char *
- llgfr %r4,%r4 # size_t
- llgfr %r5,%r5 # u32
- llgfr %r6,%r6 # u32
- jg sys32_pread64 # branch to system call
-
-ENTRY(sys32_pwrite64_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # const char *
- llgfr %r4,%r4 # size_t
- llgfr %r5,%r5 # u32
- llgfr %r6,%r6 # u32
- jg sys32_pwrite64 # branch to system call
-
-ENTRY(sys32_chown16_wrapper)
- llgtr %r2,%r2 # const char *
- llgfr %r3,%r3 # __kernel_old_uid_emu31_t
- llgfr %r4,%r4 # __kernel_old_gid_emu31_t
- jg sys32_chown16 # branch to system call
-
-ENTRY(sys32_getcwd_wrapper)
- llgtr %r2,%r2 # char *
- llgfr %r3,%r3 # unsigned long
- jg sys_getcwd # branch to system call
-
-ENTRY(sys32_capget_wrapper)
- llgtr %r2,%r2 # cap_user_header_t
- llgtr %r3,%r3 # cap_user_data_t
- jg sys_capget # branch to system call
-
-ENTRY(sys32_capset_wrapper)
- llgtr %r2,%r2 # cap_user_header_t
- llgtr %r3,%r3 # const cap_user_data_t
- jg sys_capset # branch to system call
-
-#sys32_vfork_wrapper # done in vfork_glue
-
-ENTRY(sys32_truncate64_wrapper)
- llgtr %r2,%r2 # const char *
- llgfr %r3,%r3 # unsigned long
- llgfr %r4,%r4 # unsigned long
- jg sys32_truncate64 # branch to system call
-
-ENTRY(sys32_ftruncate64_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # unsigned long
- llgfr %r4,%r4 # unsigned long
- jg sys32_ftruncate64 # branch to system call
-
-ENTRY(sys32_lchown_wrapper)
- llgtr %r2,%r2 # const char *
- llgfr %r3,%r3 # uid_t
- llgfr %r4,%r4 # gid_t
- jg sys_lchown # branch to system call
-
-#sys32_getuid_wrapper # void
-#sys32_getgid_wrapper # void
-#sys32_geteuid_wrapper # void
-#sys32_getegid_wrapper # void
-
-ENTRY(sys32_setreuid_wrapper)
- llgfr %r2,%r2 # uid_t
- llgfr %r3,%r3 # uid_t
- jg sys_setreuid # branch to system call
-
-ENTRY(sys32_setregid_wrapper)
- llgfr %r2,%r2 # gid_t
- llgfr %r3,%r3 # gid_t
- jg sys_setregid # branch to system call
-
-ENTRY(sys32_getgroups_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # gid_t *
- jg sys_getgroups # branch to system call
-
-ENTRY(sys32_setgroups_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # gid_t *
- jg sys_setgroups # branch to system call
-
-ENTRY(sys32_fchown_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # uid_t
- llgfr %r4,%r4 # gid_t
- jg sys_fchown # branch to system call
-
-ENTRY(sys32_setresuid_wrapper)
- llgfr %r2,%r2 # uid_t
- llgfr %r3,%r3 # uid_t
- llgfr %r4,%r4 # uid_t
- jg sys_setresuid # branch to system call
-
-ENTRY(sys32_getresuid_wrapper)
- llgtr %r2,%r2 # uid_t *
- llgtr %r3,%r3 # uid_t *
- llgtr %r4,%r4 # uid_t *
- jg sys_getresuid # branch to system call
-
-ENTRY(sys32_setresgid_wrapper)
- llgfr %r2,%r2 # gid_t
- llgfr %r3,%r3 # gid_t
- llgfr %r4,%r4 # gid_t
- jg sys_setresgid # branch to system call
-
-ENTRY(sys32_getresgid_wrapper)
- llgtr %r2,%r2 # gid_t *
- llgtr %r3,%r3 # gid_t *
- llgtr %r4,%r4 # gid_t *
- jg sys_getresgid # branch to system call
-
-ENTRY(sys32_chown_wrapper)
- llgtr %r2,%r2 # const char *
- llgfr %r3,%r3 # uid_t
- llgfr %r4,%r4 # gid_t
- jg sys_chown # branch to system call
-
-ENTRY(sys32_setuid_wrapper)
- llgfr %r2,%r2 # uid_t
- jg sys_setuid # branch to system call
-
-ENTRY(sys32_setgid_wrapper)
- llgfr %r2,%r2 # gid_t
- jg sys_setgid # branch to system call
-
-ENTRY(sys32_setfsuid_wrapper)
- llgfr %r2,%r2 # uid_t
- jg sys_setfsuid # branch to system call
-
-ENTRY(sys32_setfsgid_wrapper)
- llgfr %r2,%r2 # gid_t
- jg sys_setfsgid # branch to system call
-
-ENTRY(sys32_pivot_root_wrapper)
- llgtr %r2,%r2 # const char *
- llgtr %r3,%r3 # const char *
- jg sys_pivot_root # branch to system call
-
-ENTRY(sys32_mincore_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # size_t
- llgtr %r4,%r4 # unsigned char *
- jg sys_mincore # branch to system call
-
-ENTRY(sys32_madvise_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # size_t
- lgfr %r4,%r4 # int
- jg sys_madvise # branch to system call
-
-ENTRY(sys32_getdents64_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # void *
- llgfr %r4,%r4 # unsigned int
- jg sys_getdents64 # branch to system call
-
-ENTRY(compat_sys_fcntl64_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # unsigned int
- llgfr %r4,%r4 # unsigned long
- jg compat_sys_fcntl64 # branch to system call
-
-ENTRY(sys32_stat64_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # struct stat64 *
- jg sys32_stat64 # branch to system call
-
-ENTRY(sys32_lstat64_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # struct stat64 *
- jg sys32_lstat64 # branch to system call
-
-ENTRY(sys32_stime_wrapper)
- llgtr %r2,%r2 # long *
- jg compat_sys_stime # branch to system call
-
-ENTRY(sys32_fstat64_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgtr %r3,%r3 # struct stat64 *
- jg sys32_fstat64 # branch to system call
-
-ENTRY(sys32_setxattr_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # char *
- llgtr %r4,%r4 # void *
- llgfr %r5,%r5 # size_t
- lgfr %r6,%r6 # int
- jg sys_setxattr
-
-ENTRY(sys32_lsetxattr_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # char *
- llgtr %r4,%r4 # void *
- llgfr %r5,%r5 # size_t
- lgfr %r6,%r6 # int
- jg sys_lsetxattr
-
-ENTRY(sys32_fsetxattr_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # char *
- llgtr %r4,%r4 # void *
- llgfr %r5,%r5 # size_t
- lgfr %r6,%r6 # int
- jg sys_fsetxattr
-
-ENTRY(sys32_getxattr_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # char *
- llgtr %r4,%r4 # void *
- llgfr %r5,%r5 # size_t
- jg sys_getxattr
-
-ENTRY(sys32_lgetxattr_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # char *
- llgtr %r4,%r4 # void *
- llgfr %r5,%r5 # size_t
- jg sys_lgetxattr
-
-ENTRY(sys32_fgetxattr_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # char *
- llgtr %r4,%r4 # void *
- llgfr %r5,%r5 # size_t
- jg sys_fgetxattr
-
-ENTRY(sys32_listxattr_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # char *
- llgfr %r4,%r4 # size_t
- jg sys_listxattr
-
-ENTRY(sys32_llistxattr_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # char *
- llgfr %r4,%r4 # size_t
- jg sys_llistxattr
-
-ENTRY(sys32_flistxattr_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # char *
- llgfr %r4,%r4 # size_t
- jg sys_flistxattr
-
-ENTRY(sys32_removexattr_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # char *
- jg sys_removexattr
-
-ENTRY(sys32_lremovexattr_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # char *
- jg sys_lremovexattr
-
-ENTRY(sys32_fremovexattr_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # char *
- jg sys_fremovexattr
-
-ENTRY(sys32_sched_setaffinity_wrapper)
- lgfr %r2,%r2 # int
- llgfr %r3,%r3 # unsigned int
- llgtr %r4,%r4 # unsigned long *
- jg compat_sys_sched_setaffinity
-
-ENTRY(sys32_sched_getaffinity_wrapper)
- lgfr %r2,%r2 # int
- llgfr %r3,%r3 # unsigned int
- llgtr %r4,%r4 # unsigned long *
- jg compat_sys_sched_getaffinity
-
-ENTRY(sys32_exit_group_wrapper)
- lgfr %r2,%r2 # int
- jg sys_exit_group # branch to system call
-
-ENTRY(sys32_set_tid_address_wrapper)
- llgtr %r2,%r2 # int *
- jg sys_set_tid_address # branch to system call
-
-ENTRY(sys_epoll_create_wrapper)
- lgfr %r2,%r2 # int
- jg sys_epoll_create # branch to system call
-
-ENTRY(sys_epoll_ctl_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- lgfr %r4,%r4 # int
- llgtr %r5,%r5 # struct epoll_event *
- jg sys_epoll_ctl # branch to system call
-
-ENTRY(sys_epoll_wait_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # struct epoll_event *
- lgfr %r4,%r4 # int
- lgfr %r5,%r5 # int
- jg sys_epoll_wait # branch to system call
-
-ENTRY(sys32_fadvise64_wrapper)
- lgfr %r2,%r2 # int
- sllg %r3,%r3,32 # get high word of 64bit loff_t
- or %r3,%r4 # get low word of 64bit loff_t
- llgfr %r4,%r5 # size_t (unsigned long)
- lgfr %r5,%r6 # int
- jg sys32_fadvise64
-
-ENTRY(sys32_fadvise64_64_wrapper)
- llgtr %r2,%r2 # struct fadvise64_64_args *
- jg sys32_fadvise64_64
-
-ENTRY(sys32_clock_settime_wrapper)
- lgfr %r2,%r2 # clockid_t (int)
- llgtr %r3,%r3 # struct compat_timespec *
- jg compat_sys_clock_settime
-
-ENTRY(sys32_clock_gettime_wrapper)
- lgfr %r2,%r2 # clockid_t (int)
- llgtr %r3,%r3 # struct compat_timespec *
- jg compat_sys_clock_gettime
-
-ENTRY(sys32_clock_getres_wrapper)
- lgfr %r2,%r2 # clockid_t (int)
- llgtr %r3,%r3 # struct compat_timespec *
- jg compat_sys_clock_getres
-
-ENTRY(sys32_clock_nanosleep_wrapper)
- lgfr %r2,%r2 # clockid_t (int)
- lgfr %r3,%r3 # int
- llgtr %r4,%r4 # struct compat_timespec *
- llgtr %r5,%r5 # struct compat_timespec *
- jg compat_sys_clock_nanosleep
-
-ENTRY(sys32_timer_create_wrapper)
- lgfr %r2,%r2 # timer_t (int)
- llgtr %r3,%r3 # struct compat_sigevent *
- llgtr %r4,%r4 # timer_t *
- jg compat_sys_timer_create
-
-ENTRY(sys32_timer_settime_wrapper)
- lgfr %r2,%r2 # timer_t (int)
- lgfr %r3,%r3 # int
- llgtr %r4,%r4 # struct compat_itimerspec *
- llgtr %r5,%r5 # struct compat_itimerspec *
- jg compat_sys_timer_settime
-
-ENTRY(sys32_timer_gettime_wrapper)
- lgfr %r2,%r2 # timer_t (int)
- llgtr %r3,%r3 # struct compat_itimerspec *
- jg compat_sys_timer_gettime
-
-ENTRY(sys32_timer_getoverrun_wrapper)
- lgfr %r2,%r2 # timer_t (int)
- jg sys_timer_getoverrun
-
-ENTRY(sys32_timer_delete_wrapper)
- lgfr %r2,%r2 # timer_t (int)
- jg sys_timer_delete
-
-ENTRY(sys32_io_setup_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # u32 *
- jg compat_sys_io_setup
-
-ENTRY(sys32_io_destroy_wrapper)
- llgfr %r2,%r2 # (aio_context_t) u32
- jg sys_io_destroy
-
-ENTRY(sys32_io_getevents_wrapper)
- llgfr %r2,%r2 # (aio_context_t) u32
- lgfr %r3,%r3 # long
- lgfr %r4,%r4 # long
- llgtr %r5,%r5 # struct io_event *
- llgtr %r6,%r6 # struct compat_timespec *
- jg compat_sys_io_getevents
-
-ENTRY(sys32_io_submit_wrapper)
- llgfr %r2,%r2 # (aio_context_t) u32
- lgfr %r3,%r3 # long
- llgtr %r4,%r4 # struct iocb **
- jg compat_sys_io_submit
-
-ENTRY(sys32_io_cancel_wrapper)
- llgfr %r2,%r2 # (aio_context_t) u32
- llgtr %r3,%r3 # struct iocb *
- llgtr %r4,%r4 # struct io_event *
- jg sys_io_cancel
-
-ENTRY(compat_sys_statfs64_wrapper)
- llgtr %r2,%r2 # const char *
- llgfr %r3,%r3 # compat_size_t
- llgtr %r4,%r4 # struct compat_statfs64 *
- jg compat_sys_statfs64
-
-ENTRY(compat_sys_fstatfs64_wrapper)
- llgfr %r2,%r2 # unsigned int fd
- llgfr %r3,%r3 # compat_size_t
- llgtr %r4,%r4 # struct compat_statfs64 *
- jg compat_sys_fstatfs64
-
-ENTRY(compat_sys_mq_open_wrapper)
- llgtr %r2,%r2 # const char *
- lgfr %r3,%r3 # int
- llgfr %r4,%r4 # mode_t
- llgtr %r5,%r5 # struct compat_mq_attr *
- jg compat_sys_mq_open
-
-ENTRY(sys32_mq_unlink_wrapper)
- llgtr %r2,%r2 # const char *
- jg sys_mq_unlink
-
-ENTRY(compat_sys_mq_timedsend_wrapper)
- lgfr %r2,%r2 # mqd_t
- llgtr %r3,%r3 # const char *
- llgfr %r4,%r4 # size_t
- llgfr %r5,%r5 # unsigned int
- llgtr %r6,%r6 # const struct compat_timespec *
- jg compat_sys_mq_timedsend
-
-ENTRY(compat_sys_mq_timedreceive_wrapper)
- lgfr %r2,%r2 # mqd_t
- llgtr %r3,%r3 # char *
- llgfr %r4,%r4 # size_t
- llgtr %r5,%r5 # unsigned int *
- llgtr %r6,%r6 # const struct compat_timespec *
- jg compat_sys_mq_timedreceive
-
-ENTRY(compat_sys_mq_notify_wrapper)
- lgfr %r2,%r2 # mqd_t
- llgtr %r3,%r3 # struct compat_sigevent *
- jg compat_sys_mq_notify
-
-ENTRY(compat_sys_mq_getsetattr_wrapper)
- lgfr %r2,%r2 # mqd_t
- llgtr %r3,%r3 # struct compat_mq_attr *
- llgtr %r4,%r4 # struct compat_mq_attr *
- jg compat_sys_mq_getsetattr
-
-ENTRY(compat_sys_add_key_wrapper)
- llgtr %r2,%r2 # const char *
- llgtr %r3,%r3 # const char *
- llgtr %r4,%r4 # const void *
- llgfr %r5,%r5 # size_t
- llgfr %r6,%r6 # (key_serial_t) u32
- jg sys_add_key
-
-ENTRY(compat_sys_request_key_wrapper)
- llgtr %r2,%r2 # const char *
- llgtr %r3,%r3 # const char *
- llgtr %r4,%r4 # const void *
- llgfr %r5,%r5 # (key_serial_t) u32
- jg sys_request_key
-
-ENTRY(sys32_remap_file_pages_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # unsigned long
- llgfr %r4,%r4 # unsigned long
- llgfr %r5,%r5 # unsigned long
- llgfr %r6,%r6 # unsigned long
- jg sys_remap_file_pages
-
-ENTRY(compat_sys_kexec_load_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # unsigned long
- llgtr %r4,%r4 # struct kexec_segment *
- llgfr %r5,%r5 # unsigned long
- jg compat_sys_kexec_load
-
-ENTRY(sys_ioprio_set_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- lgfr %r4,%r4 # int
- jg sys_ioprio_set
-
-ENTRY(sys_ioprio_get_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- jg sys_ioprio_get
-
-ENTRY(sys_inotify_add_watch_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char *
- llgfr %r4,%r4 # u32
- jg sys_inotify_add_watch
-
-ENTRY(sys_inotify_rm_watch_wrapper)
- lgfr %r2,%r2 # int
- llgfr %r3,%r3 # u32
- jg sys_inotify_rm_watch
-
-ENTRY(sys_mkdirat_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char *
- lgfr %r4,%r4 # int
- jg sys_mkdirat
-
-ENTRY(sys_mknodat_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char *
- lgfr %r4,%r4 # int
- llgfr %r5,%r5 # unsigned int
- jg sys_mknodat
-
-ENTRY(sys_fchownat_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char *
- llgfr %r4,%r4 # uid_t
- llgfr %r5,%r5 # gid_t
- lgfr %r6,%r6 # int
- jg sys_fchownat
-
-ENTRY(compat_sys_futimesat_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # char *
- llgtr %r4,%r4 # struct timeval *
- jg compat_sys_futimesat
-
-ENTRY(sys32_fstatat64_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # char *
- llgtr %r4,%r4 # struct stat64 *
- lgfr %r5,%r5 # int
- jg sys32_fstatat64
-
-ENTRY(sys_unlinkat_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char *
- lgfr %r4,%r4 # int
- jg sys_unlinkat
-
-ENTRY(sys_renameat_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char *
- lgfr %r4,%r4 # int
- llgtr %r5,%r5 # const char *
- jg sys_renameat
-
-ENTRY(sys_linkat_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char *
- lgfr %r4,%r4 # int
- llgtr %r5,%r5 # const char *
- lgfr %r6,%r6 # int
- jg sys_linkat
-
-ENTRY(sys_symlinkat_wrapper)
- llgtr %r2,%r2 # const char *
- lgfr %r3,%r3 # int
- llgtr %r4,%r4 # const char *
- jg sys_symlinkat
-
-ENTRY(sys_readlinkat_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char *
- llgtr %r4,%r4 # char *
- lgfr %r5,%r5 # int
- jg sys_readlinkat
-
-ENTRY(sys_fchmodat_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char *
- llgfr %r4,%r4 # mode_t
- jg sys_fchmodat
-
-ENTRY(sys_faccessat_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char *
- lgfr %r4,%r4 # int
- jg sys_faccessat
-
-ENTRY(compat_sys_pselect6_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # fd_set *
- llgtr %r4,%r4 # fd_set *
- llgtr %r5,%r5 # fd_set *
- llgtr %r6,%r6 # struct timespec *
- llgt %r0,164(%r15) # void *
- stg %r0,160(%r15)
- jg compat_sys_pselect6
-
-ENTRY(compat_sys_ppoll_wrapper)
- llgtr %r2,%r2 # struct pollfd *
- llgfr %r3,%r3 # unsigned int
- llgtr %r4,%r4 # struct timespec *
- llgtr %r5,%r5 # const sigset_t *
- llgfr %r6,%r6 # size_t
- jg compat_sys_ppoll
-
-ENTRY(sys_unshare_wrapper)
- llgfr %r2,%r2 # unsigned long
- jg sys_unshare
-
-ENTRY(sys_splice_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # loff_t *
- lgfr %r4,%r4 # int
- llgtr %r5,%r5 # loff_t *
- llgfr %r6,%r6 # size_t
- llgf %r0,164(%r15) # unsigned int
- stg %r0,160(%r15)
- jg sys_splice
-
-ENTRY(sys_sync_file_range_wrapper)
- lgfr %r2,%r2 # int
- sllg %r3,%r3,32 # get high word of 64bit loff_t
- or %r3,%r4 # get low word of 64bit loff_t
- sllg %r4,%r5,32 # get high word of 64bit loff_t
- or %r4,%r6 # get low word of 64bit loff_t
- llgf %r5,164(%r15) # unsigned int
- jg sys_sync_file_range
-
-ENTRY(sys_tee_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- llgfr %r4,%r4 # size_t
- llgfr %r5,%r5 # unsigned int
- jg sys_tee
-
-ENTRY(sys_getcpu_wrapper)
- llgtr %r2,%r2 # unsigned *
- llgtr %r3,%r3 # unsigned *
- llgtr %r4,%r4 # struct getcpu_cache *
- jg sys_getcpu
-
-ENTRY(compat_sys_utimes_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # struct compat_timeval *
- jg compat_sys_utimes
-
-ENTRY(compat_sys_utimensat_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # char *
- llgtr %r4,%r4 # struct compat_timespec *
- lgfr %r5,%r5 # int
- jg compat_sys_utimensat
-
-ENTRY(sys_eventfd_wrapper)
- llgfr %r2,%r2 # unsigned int
- jg sys_eventfd
-
-ENTRY(sys_fallocate_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- sllg %r4,%r4,32 # get high word of 64bit loff_t
- lr %r4,%r5 # get low word of 64bit loff_t
- sllg %r5,%r6,32 # get high word of 64bit loff_t
- l %r5,164(%r15) # get low word of 64bit loff_t
- jg sys_fallocate
-
-ENTRY(sys_timerfd_create_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- jg sys_timerfd_create
-
-ENTRY(sys_eventfd2_wrapper)
- llgfr %r2,%r2 # unsigned int
- lgfr %r3,%r3 # int
- jg sys_eventfd2
-
-ENTRY(sys_inotify_init1_wrapper)
- lgfr %r2,%r2 # int
- jg sys_inotify_init1
-
-ENTRY(sys_pipe2_wrapper)
- llgtr %r2,%r2 # u32 *
- lgfr %r3,%r3 # int
- jg sys_pipe2 # branch to system call
-
-ENTRY(sys_dup3_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # unsigned int
- lgfr %r4,%r4 # int
- jg sys_dup3 # branch to system call
-
-ENTRY(sys_epoll_create1_wrapper)
- lgfr %r2,%r2 # int
- jg sys_epoll_create1 # branch to system call
-
-ENTRY(sys32_readahead_wrapper)
- lgfr %r2,%r2 # int
- llgfr %r3,%r3 # u32
- llgfr %r4,%r4 # u32
- lgfr %r5,%r5 # s32
- jg sys32_readahead # branch to system call
-
-ENTRY(sys_tkill_wrapper)
- lgfr %r2,%r2 # pid_t
- lgfr %r3,%r3 # int
- jg sys_tkill # branch to system call
-
-ENTRY(sys_tgkill_wrapper)
- lgfr %r2,%r2 # pid_t
- lgfr %r3,%r3 # pid_t
- lgfr %r4,%r4 # int
- jg sys_tgkill # branch to system call
-
-ENTRY(compat_sys_keyctl_wrapper)
- llgfr %r2,%r2 # u32
- llgfr %r3,%r3 # u32
- llgfr %r4,%r4 # u32
- llgfr %r5,%r5 # u32
- llgfr %r6,%r6 # u32
- jg compat_sys_keyctl # branch to system call
-
-ENTRY(sys_perf_event_open_wrapper)
- llgtr %r2,%r2 # const struct perf_event_attr *
- lgfr %r3,%r3 # pid_t
- lgfr %r4,%r4 # int
- lgfr %r5,%r5 # int
- llgfr %r6,%r6 # unsigned long
- jg sys_perf_event_open # branch to system call
-
-ENTRY(sys_clone_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # unsigned long
- llgtr %r4,%r4 # int *
- llgtr %r5,%r5 # int *
- jg sys_clone # branch to system call
-
-ENTRY(sys32_execve_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # compat_uptr_t *
- llgtr %r4,%r4 # compat_uptr_t *
- jg compat_sys_execve # branch to system call
-
-ENTRY(sys_fanotify_init_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # unsigned int
- jg sys_fanotify_init # branch to system call
-
-ENTRY(sys_prlimit64_wrapper)
- lgfr %r2,%r2 # pid_t
- llgfr %r3,%r3 # unsigned int
- llgtr %r4,%r4 # const struct rlimit64 __user *
- llgtr %r5,%r5 # struct rlimit64 __user *
- jg sys_prlimit64 # branch to system call
-
-ENTRY(sys_name_to_handle_at_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char __user *
- llgtr %r4,%r4 # struct file_handle __user *
- llgtr %r5,%r5 # int __user *
- lgfr %r6,%r6 # int
- jg sys_name_to_handle_at
-
-ENTRY(compat_sys_clock_adjtime_wrapper)
- lgfr %r2,%r2 # clockid_t (int)
- llgtr %r3,%r3 # struct compat_timex __user *
- jg compat_sys_clock_adjtime
-
-ENTRY(sys_syncfs_wrapper)
- lgfr %r2,%r2 # int
- jg sys_syncfs
-
-ENTRY(sys_setns_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- jg sys_setns
-
-ENTRY(compat_sys_process_vm_readv_wrapper)
- lgfr %r2,%r2 # compat_pid_t
- llgtr %r3,%r3 # struct compat_iovec __user *
- llgfr %r4,%r4 # unsigned long
- llgtr %r5,%r5 # struct compat_iovec __user *
- llgfr %r6,%r6 # unsigned long
- llgf %r0,164(%r15) # unsigned long
- stg %r0,160(%r15)
- jg compat_sys_process_vm_readv
-
-ENTRY(compat_sys_process_vm_writev_wrapper)
- lgfr %r2,%r2 # compat_pid_t
- llgtr %r3,%r3 # struct compat_iovec __user *
- llgfr %r4,%r4 # unsigned long
- llgtr %r5,%r5 # struct compat_iovec __user *
- llgfr %r6,%r6 # unsigned long
- llgf %r0,164(%r15) # unsigned long
- stg %r0,160(%r15)
- jg compat_sys_process_vm_writev
-
-ENTRY(sys_s390_runtime_instr_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- jg sys_s390_runtime_instr
-
-ENTRY(sys_kcmp_wrapper)
- lgfr %r2,%r2 # pid_t
- lgfr %r3,%r3 # pid_t
- lgfr %r4,%r4 # int
- llgfr %r5,%r5 # unsigned long
- llgfr %r6,%r6 # unsigned long
- jg sys_kcmp
-
-ENTRY(sys_finit_module_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char __user *
- lgfr %r4,%r4 # int
- jg sys_finit_module
-
-ENTRY(sys_sched_setattr_wrapper)
- lgfr %r2,%r2 # pid_t
- llgtr %r3,%r3 # struct sched_attr __user *
- jg sys_sched_setattr
-
-ENTRY(sys_sched_getattr_wrapper)
- lgfr %r2,%r2 # pid_t
- llgtr %r3,%r3 # const char __user *
- llgfr %r3,%r3 # unsigned int
- jg sys_sched_getattr
diff --git a/arch/s390/kernel/compat_wrapper.c b/arch/s390/kernel/compat_wrapper.c
new file mode 100644
index 000000000000..824c39dfddfc
--- /dev/null
+++ b/arch/s390/kernel/compat_wrapper.c
@@ -0,0 +1,215 @@
+/*
+ * Compat sytem call wrappers.
+ *
+ * Copyright IBM Corp. 2014
+ */
+
+#include <linux/syscalls.h>
+#include <linux/compat.h>
+#include "entry.h"
+
+#define COMPAT_SYSCALL_WRAP1(name, ...) \
+ COMPAT_SYSCALL_WRAPx(1, _##name, __VA_ARGS__)
+#define COMPAT_SYSCALL_WRAP2(name, ...) \
+ COMPAT_SYSCALL_WRAPx(2, _##name, __VA_ARGS__)
+#define COMPAT_SYSCALL_WRAP3(name, ...) \
+ COMPAT_SYSCALL_WRAPx(3, _##name, __VA_ARGS__)
+#define COMPAT_SYSCALL_WRAP4(name, ...) \
+ COMPAT_SYSCALL_WRAPx(4, _##name, __VA_ARGS__)
+#define COMPAT_SYSCALL_WRAP5(name, ...) \
+ COMPAT_SYSCALL_WRAPx(5, _##name, __VA_ARGS__)
+#define COMPAT_SYSCALL_WRAP6(name, ...) \
+ COMPAT_SYSCALL_WRAPx(6, _##name, __VA_ARGS__)
+
+#define __SC_COMPAT_TYPE(t, a) \
+ __typeof(__builtin_choose_expr(sizeof(t) > 4, 0L, (t)0)) a
+
+#define __SC_COMPAT_CAST(t, a) \
+({ \
+ long __ReS = a; \
+ \
+ BUILD_BUG_ON((sizeof(t) > 4) && !__TYPE_IS_L(t) && \
+ !__TYPE_IS_UL(t) && !__TYPE_IS_PTR(t)); \
+ if (__TYPE_IS_L(t)) \
+ __ReS = (s32)a; \
+ if (__TYPE_IS_UL(t)) \
+ __ReS = (u32)a; \
+ if (__TYPE_IS_PTR(t)) \
+ __ReS = a & 0x7fffffff; \
+ (t)__ReS; \
+})
+
+/*
+ * The COMPAT_SYSCALL_WRAP macro generates system call wrappers to be used by
+ * compat tasks. These wrappers will only be used for system calls where only
+ * the system call arguments need sign or zero extension or zeroing of the upper
+ * 33 bits of pointers.
+ * Note: since the wrapper function will afterwards call a system call which
+ * again performs zero and sign extension for all system call arguments with
+ * a size of less than eight bytes, these compat wrappers only touch those
+ * system call arguments with a size of eight bytes ((unsigned) long and
+ * pointers). Zero and sign extension for e.g. int parameters will be done by
+ * the regular system call wrappers.
+ */
+#define COMPAT_SYSCALL_WRAPx(x, name, ...) \
+ asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \
+ asmlinkage long compat_sys##name(__MAP(x,__SC_COMPAT_TYPE,__VA_ARGS__));\
+ asmlinkage long compat_sys##name(__MAP(x,__SC_COMPAT_TYPE,__VA_ARGS__)) \
+ { \
+ return sys##name(__MAP(x,__SC_COMPAT_CAST,__VA_ARGS__)); \
+ }
+
+COMPAT_SYSCALL_WRAP1(exit, int, error_code);
+COMPAT_SYSCALL_WRAP1(close, unsigned int, fd);
+COMPAT_SYSCALL_WRAP2(creat, const char __user *, pathname, umode_t, mode);
+COMPAT_SYSCALL_WRAP2(link, const char __user *, oldname, const char __user *, newname);
+COMPAT_SYSCALL_WRAP1(unlink, const char __user *, pathname);
+COMPAT_SYSCALL_WRAP1(chdir, const char __user *, filename);
+COMPAT_SYSCALL_WRAP3(mknod, const char __user *, filename, umode_t, mode, unsigned, dev);
+COMPAT_SYSCALL_WRAP2(chmod, const char __user *, filename, umode_t, mode);
+COMPAT_SYSCALL_WRAP1(oldumount, char __user *, name);
+COMPAT_SYSCALL_WRAP1(alarm, unsigned int, seconds);
+COMPAT_SYSCALL_WRAP2(access, const char __user *, filename, int, mode);
+COMPAT_SYSCALL_WRAP1(nice, int, increment);
+COMPAT_SYSCALL_WRAP2(kill, int, pid, int, sig);
+COMPAT_SYSCALL_WRAP2(rename, const char __user *, oldname, const char __user *, newname);
+COMPAT_SYSCALL_WRAP2(mkdir, const char __user *, pathname, umode_t, mode);
+COMPAT_SYSCALL_WRAP1(rmdir, const char __user *, pathname);
+COMPAT_SYSCALL_WRAP1(dup, unsigned int, fildes);
+COMPAT_SYSCALL_WRAP1(pipe, int __user *, fildes);
+COMPAT_SYSCALL_WRAP1(brk, unsigned long, brk);
+COMPAT_SYSCALL_WRAP2(signal, int, sig, __sighandler_t, handler);
+COMPAT_SYSCALL_WRAP1(acct, const char __user *, name);
+COMPAT_SYSCALL_WRAP2(umount, char __user *, name, int, flags);
+COMPAT_SYSCALL_WRAP2(setpgid, pid_t, pid, pid_t, pgid);
+COMPAT_SYSCALL_WRAP1(umask, int, mask);
+COMPAT_SYSCALL_WRAP1(chroot, const char __user *, filename);
+COMPAT_SYSCALL_WRAP2(dup2, unsigned int, oldfd, unsigned int, newfd);
+COMPAT_SYSCALL_WRAP3(sigsuspend, int, unused1, int, unused2, old_sigset_t, mask);
+COMPAT_SYSCALL_WRAP2(sethostname, char __user *, name, int, len);
+COMPAT_SYSCALL_WRAP2(symlink, const char __user *, old, const char __user *, new);
+COMPAT_SYSCALL_WRAP3(readlink, const char __user *, path, char __user *, buf, int, bufsiz);
+COMPAT_SYSCALL_WRAP1(uselib, const char __user *, library);
+COMPAT_SYSCALL_WRAP2(swapon, const char __user *, specialfile, int, swap_flags);
+COMPAT_SYSCALL_WRAP4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg);
+COMPAT_SYSCALL_WRAP2(munmap, unsigned long, addr, size_t, len);
+COMPAT_SYSCALL_WRAP2(fchmod, unsigned int, fd, umode_t, mode);
+COMPAT_SYSCALL_WRAP2(getpriority, int, which, int, who);
+COMPAT_SYSCALL_WRAP3(setpriority, int, which, int, who, int, niceval);
+COMPAT_SYSCALL_WRAP3(syslog, int, type, char __user *, buf, int, len);
+COMPAT_SYSCALL_WRAP1(swapoff, const char __user *, specialfile);
+COMPAT_SYSCALL_WRAP1(fsync, unsigned int, fd);
+COMPAT_SYSCALL_WRAP2(setdomainname, char __user *, name, int, len);
+COMPAT_SYSCALL_WRAP1(newuname, struct new_utsname __user *, name);
+COMPAT_SYSCALL_WRAP3(mprotect, unsigned long, start, size_t, len, unsigned long, prot);
+COMPAT_SYSCALL_WRAP3(init_module, void __user *, umod, unsigned long, len, const char __user *, uargs);
+COMPAT_SYSCALL_WRAP2(delete_module, const char __user *, name_user, unsigned int, flags);
+COMPAT_SYSCALL_WRAP4(quotactl, unsigned int, cmd, const char __user *, special, qid_t, id, void __user *, addr);
+COMPAT_SYSCALL_WRAP1(getpgid, pid_t, pid);
+COMPAT_SYSCALL_WRAP1(fchdir, unsigned int, fd);
+COMPAT_SYSCALL_WRAP2(bdflush, int, func, long, data);
+COMPAT_SYSCALL_WRAP3(sysfs, int, option, unsigned long, arg1, unsigned long, arg2);
+COMPAT_SYSCALL_WRAP1(s390_personality, unsigned int, personality);
+COMPAT_SYSCALL_WRAP5(llseek, unsigned int, fd, unsigned long, high, unsigned long, low, loff_t __user *, result, unsigned int, whence);
+COMPAT_SYSCALL_WRAP2(flock, unsigned int, fd, unsigned int, cmd);
+COMPAT_SYSCALL_WRAP3(msync, unsigned long, start, size_t, len, int, flags);
+COMPAT_SYSCALL_WRAP1(getsid, pid_t, pid);
+COMPAT_SYSCALL_WRAP1(fdatasync, unsigned int, fd);
+COMPAT_SYSCALL_WRAP2(mlock, unsigned long, start, size_t, len);
+COMPAT_SYSCALL_WRAP2(munlock, unsigned long, start, size_t, len);
+COMPAT_SYSCALL_WRAP1(mlockall, int, flags);
+COMPAT_SYSCALL_WRAP2(sched_setparam, pid_t, pid, struct sched_param __user *, param);
+COMPAT_SYSCALL_WRAP2(sched_getparam, pid_t, pid, struct sched_param __user *, param);
+COMPAT_SYSCALL_WRAP3(sched_setscheduler, pid_t, pid, int, policy, struct sched_param __user *, param);
+COMPAT_SYSCALL_WRAP1(sched_getscheduler, pid_t, pid);
+COMPAT_SYSCALL_WRAP1(sched_get_priority_max, int, policy);
+COMPAT_SYSCALL_WRAP1(sched_get_priority_min, int, policy);
+COMPAT_SYSCALL_WRAP5(mremap, unsigned long, addr, unsigned long, old_len, unsigned long, new_len, unsigned long, flags, unsigned long, new_addr);
+COMPAT_SYSCALL_WRAP3(poll, struct pollfd __user *, ufds, unsigned int, nfds, int, timeout);
+COMPAT_SYSCALL_WRAP5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, unsigned long, arg4, unsigned long, arg5);
+COMPAT_SYSCALL_WRAP2(getcwd, char __user *, buf, unsigned long, size);
+COMPAT_SYSCALL_WRAP2(capget, cap_user_header_t, header, cap_user_data_t, dataptr);
+COMPAT_SYSCALL_WRAP2(capset, cap_user_header_t, header, const cap_user_data_t, data);
+COMPAT_SYSCALL_WRAP3(lchown, const char __user *, filename, uid_t, user, gid_t, group);
+COMPAT_SYSCALL_WRAP2(setreuid, uid_t, ruid, uid_t, euid);
+COMPAT_SYSCALL_WRAP2(setregid, gid_t, rgid, gid_t, egid);
+COMPAT_SYSCALL_WRAP2(getgroups, int, gidsetsize, gid_t __user *, grouplist);
+COMPAT_SYSCALL_WRAP2(setgroups, int, gidsetsize, gid_t __user *, grouplist);
+COMPAT_SYSCALL_WRAP3(fchown, unsigned int, fd, uid_t, user, gid_t, group);
+COMPAT_SYSCALL_WRAP3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid);
+COMPAT_SYSCALL_WRAP3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __user *, suid);
+COMPAT_SYSCALL_WRAP3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid);
+COMPAT_SYSCALL_WRAP3(getresgid, gid_t __user *, rgid, gid_t __user *, egid, gid_t __user *, sgid);
+COMPAT_SYSCALL_WRAP3(chown, const char __user *, filename, uid_t, user, gid_t, group);
+COMPAT_SYSCALL_WRAP1(setuid, uid_t, uid);
+COMPAT_SYSCALL_WRAP1(setgid, gid_t, gid);
+COMPAT_SYSCALL_WRAP1(setfsuid, uid_t, uid);
+COMPAT_SYSCALL_WRAP1(setfsgid, gid_t, gid);
+COMPAT_SYSCALL_WRAP2(pivot_root, const char __user *, new_root, const char __user *, put_old);
+COMPAT_SYSCALL_WRAP3(mincore, unsigned long, start, size_t, len, unsigned char __user *, vec);
+COMPAT_SYSCALL_WRAP3(madvise, unsigned long, start, size_t, len, int, behavior);
+COMPAT_SYSCALL_WRAP5(setxattr, const char __user *, path, const char __user *, name, const void __user *, value, size_t, size, int, flags);
+COMPAT_SYSCALL_WRAP5(lsetxattr, const char __user *, path, const char __user *, name, const void __user *, value, size_t, size, int, flags);
+COMPAT_SYSCALL_WRAP5(fsetxattr, int, fd, const char __user *, name, const void __user *, value, size_t, size, int, flags);
+COMPAT_SYSCALL_WRAP3(getdents64, unsigned int, fd, struct linux_dirent64 __user *, dirent, unsigned int, count);
+COMPAT_SYSCALL_WRAP4(getxattr, const char __user *, path, const char __user *, name, void __user *, value, size_t, size);
+COMPAT_SYSCALL_WRAP4(lgetxattr, const char __user *, path, const char __user *, name, void __user *, value, size_t, size);
+COMPAT_SYSCALL_WRAP4(fgetxattr, int, fd, const char __user *, name, void __user *, value, size_t, size);
+COMPAT_SYSCALL_WRAP3(listxattr, const char __user *, path, char __user *, list, size_t, size);
+COMPAT_SYSCALL_WRAP3(llistxattr, const char __user *, path, char __user *, list, size_t, size);
+COMPAT_SYSCALL_WRAP3(flistxattr, int, fd, char __user *, list, size_t, size);
+COMPAT_SYSCALL_WRAP2(removexattr, const char __user *, path, const char __user *, name);
+COMPAT_SYSCALL_WRAP2(lremovexattr, const char __user *, path, const char __user *, name);
+COMPAT_SYSCALL_WRAP2(fremovexattr, int, fd, const char __user *, name);
+COMPAT_SYSCALL_WRAP1(exit_group, int, error_code);
+COMPAT_SYSCALL_WRAP1(set_tid_address, int __user *, tidptr);
+COMPAT_SYSCALL_WRAP1(epoll_create, int, size);
+COMPAT_SYSCALL_WRAP4(epoll_ctl, int, epfd, int, op, int, fd, struct epoll_event __user *, event);
+COMPAT_SYSCALL_WRAP4(epoll_wait, int, epfd, struct epoll_event __user *, events, int, maxevents, int, timeout);
+COMPAT_SYSCALL_WRAP1(timer_getoverrun, timer_t, timer_id);
+COMPAT_SYSCALL_WRAP1(timer_delete, compat_timer_t, compat_timer_id);
+COMPAT_SYSCALL_WRAP1(io_destroy, aio_context_t, ctx);
+COMPAT_SYSCALL_WRAP3(io_cancel, aio_context_t, ctx_id, struct iocb __user *, iocb, struct io_event __user *, result);
+COMPAT_SYSCALL_WRAP1(mq_unlink, const char __user *, name);
+COMPAT_SYSCALL_WRAP5(add_key, const char __user *, tp, const char __user *, dsc, const void __user *, pld, size_t, len, key_serial_t, id);
+COMPAT_SYSCALL_WRAP4(request_key, const char __user *, tp, const char __user *, dsc, const char __user *, info, key_serial_t, id);
+COMPAT_SYSCALL_WRAP5(remap_file_pages, unsigned long, start, unsigned long, size, unsigned long, prot, unsigned long, pgoff, unsigned long, flags);
+COMPAT_SYSCALL_WRAP3(ioprio_set, int, which, int, who, int, ioprio);
+COMPAT_SYSCALL_WRAP2(ioprio_get, int, which, int, who);
+COMPAT_SYSCALL_WRAP3(inotify_add_watch, int, fd, const char __user *, path, u32, mask);
+COMPAT_SYSCALL_WRAP2(inotify_rm_watch, int, fd, __s32, wd);
+COMPAT_SYSCALL_WRAP3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode);
+COMPAT_SYSCALL_WRAP4(mknodat, int, dfd, const char __user *, filename, umode_t, mode, unsigned, dev);
+COMPAT_SYSCALL_WRAP5(fchownat, int, dfd, const char __user *, filename, uid_t, user, gid_t, group, int, flag);
+COMPAT_SYSCALL_WRAP3(unlinkat, int, dfd, const char __user *, pathname, int, flag);
+COMPAT_SYSCALL_WRAP4(renameat, int, olddfd, const char __user *, oldname, int, newdfd, const char __user *, newname);
+COMPAT_SYSCALL_WRAP5(linkat, int, olddfd, const char __user *, oldname, int, newdfd, const char __user *, newname, int, flags);
+COMPAT_SYSCALL_WRAP3(symlinkat, const char __user *, oldname, int, newdfd, const char __user *, newname);
+COMPAT_SYSCALL_WRAP4(readlinkat, int, dfd, const char __user *, path, char __user *, buf, int, bufsiz);
+COMPAT_SYSCALL_WRAP3(fchmodat, int, dfd, const char __user *, filename, umode_t, mode);
+COMPAT_SYSCALL_WRAP3(faccessat, int, dfd, const char __user *, filename, int, mode);
+COMPAT_SYSCALL_WRAP1(unshare, unsigned long, unshare_flags);
+COMPAT_SYSCALL_WRAP6(splice, int, fd_in, loff_t __user *, off_in, int, fd_out, loff_t __user *, off_out, size_t, len, unsigned int, flags);
+COMPAT_SYSCALL_WRAP4(tee, int, fdin, int, fdout, size_t, len, unsigned int, flags);
+COMPAT_SYSCALL_WRAP3(getcpu, unsigned __user *, cpu, unsigned __user *, node, struct getcpu_cache __user *, cache);
+COMPAT_SYSCALL_WRAP1(eventfd, unsigned int, count);
+COMPAT_SYSCALL_WRAP2(timerfd_create, int, clockid, int, flags);
+COMPAT_SYSCALL_WRAP2(eventfd2, unsigned int, count, int, flags);
+COMPAT_SYSCALL_WRAP1(inotify_init1, int, flags);
+COMPAT_SYSCALL_WRAP2(pipe2, int __user *, fildes, int, flags);
+COMPAT_SYSCALL_WRAP3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags);
+COMPAT_SYSCALL_WRAP1(epoll_create1, int, flags);
+COMPAT_SYSCALL_WRAP2(tkill, int, pid, int, sig);
+COMPAT_SYSCALL_WRAP3(tgkill, int, tgid, int, pid, int, sig);
+COMPAT_SYSCALL_WRAP5(perf_event_open, struct perf_event_attr __user *, attr_uptr, pid_t, pid, int, cpu, int, group_fd, unsigned long, flags);
+COMPAT_SYSCALL_WRAP5(clone, unsigned long, newsp, unsigned long, clone_flags, int __user *, parent_tidptr, int __user *, child_tidptr, int, tls_val);
+COMPAT_SYSCALL_WRAP2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags);
+COMPAT_SYSCALL_WRAP4(prlimit64, pid_t, pid, unsigned int, resource, const struct rlimit64 __user *, new_rlim, struct rlimit64 __user *, old_rlim);
+COMPAT_SYSCALL_WRAP5(name_to_handle_at, int, dfd, const char __user *, name, struct file_handle __user *, handle, int __user *, mnt_id, int, flag);
+COMPAT_SYSCALL_WRAP1(syncfs, int, fd);
+COMPAT_SYSCALL_WRAP2(setns, int, fd, int, nstype);
+COMPAT_SYSCALL_WRAP2(s390_runtime_instr, int, command, int, signum);
+COMPAT_SYSCALL_WRAP5(kcmp, pid_t, pid1, pid_t, pid2, int, type, unsigned long, idx1, unsigned long, idx2);
+COMPAT_SYSCALL_WRAP3(finit_module, int, fd, const char __user *, uargs, int, flags);
+COMPAT_SYSCALL_WRAP3(sched_setattr, pid_t, pid, struct sched_attr __user *, attr, unsigned int, flags);
+COMPAT_SYSCALL_WRAP4(sched_getattr, pid_t, pid, struct sched_attr __user *, attr, unsigned int, size, unsigned int, flags);
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index fca20b5fe79e..6b594439cca5 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -380,8 +380,6 @@ static __init void detect_machine_facilities(void)
S390_lowcore.machine_flags |= MACHINE_FLAG_EDAT2;
if (test_facility(3))
S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE;
- if (test_facility(27))
- S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS;
if (test_facility(40))
S390_lowcore.machine_flags |= MACHINE_FLAG_LPP;
if (test_facility(50) && test_facility(73))
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 0dc2b6d0a1ec..526d3735ed29 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -43,6 +43,7 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
_TIF_MCCK_PENDING)
_TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
_TIF_SYSCALL_TRACEPOINT)
+_TIF_TRANSFER = (_TIF_MCCK_PENDING | _TIF_TLB_WAIT)
STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
STACK_SIZE = 1 << STACK_SHIFT
@@ -159,10 +160,12 @@ ENTRY(__switch_to)
lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
mvc __LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next
l %r15,__THREAD_ksp(%r3) # load kernel stack of next
- tm __TI_flags+3(%r4),_TIF_MCCK_PENDING # machine check pending?
+ lhi %r6,_TIF_TRANSFER # transfer TIF bits
+ n %r6,__TI_flags(%r4) # isolate TIF bits
jz 0f
- ni __TI_flags+3(%r4),255-_TIF_MCCK_PENDING # clear flag in prev
- oi __TI_flags+3(%r5),_TIF_MCCK_PENDING # set it in next
+ o %r6,__TI_flags(%r5) # set TIF bits of next
+ st %r6,__TI_flags(%r5)
+ ni __TI_flags+3(%r4),255-_TIF_TRANSFER # clear TIF bits of prev
0: lm %r6,%r15,__SF_GPRS(%r15) # load gprs of next task
br %r14
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h
index cb533f78c09e..6ac78192455f 100644
--- a/arch/s390/kernel/entry.h
+++ b/arch/s390/kernel/entry.h
@@ -67,9 +67,7 @@ struct s390_mmap_arg_struct;
struct fadvise64_64_args;
struct old_sigaction;
-long sys_sigreturn(void);
-long sys_rt_sigreturn(void);
-long sys32_sigreturn(void);
-long sys32_rt_sigreturn(void);
+long sys_s390_personality(unsigned int personality);
+long sys_s390_runtime_instr(int command, int signum);
#endif /* _ENTRY_H */
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 384e609b4711..e09dbe5f2901 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -48,6 +48,7 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
_TIF_MCCK_PENDING)
_TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
_TIF_SYSCALL_TRACEPOINT)
+_TIF_TRANSFER = (_TIF_MCCK_PENDING | _TIF_TLB_WAIT)
#define BASED(name) name-system_call(%r13)
@@ -189,10 +190,12 @@ ENTRY(__switch_to)
lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
mvc __LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next
lg %r15,__THREAD_ksp(%r3) # load kernel stack of next
- tm __TI_flags+7(%r4),_TIF_MCCK_PENDING # machine check pending?
+ llill %r6,_TIF_TRANSFER # transfer TIF bits
+ ng %r6,__TI_flags(%r4) # isolate TIF bits
jz 0f
- ni __TI_flags+7(%r4),255-_TIF_MCCK_PENDING # clear flag in prev
- oi __TI_flags+7(%r5),_TIF_MCCK_PENDING # set it in next
+ og %r6,__TI_flags(%r5) # set TIF bits of next
+ stg %r6,__TI_flags(%r5)
+ ni __TI_flags+7(%r4),255-_TIF_TRANSFER # clear TIF bits of prev
0: lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task
br %r14
diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c
index 224db03e9518..54d6493c4a56 100644
--- a/arch/s390/kernel/ftrace.c
+++ b/arch/s390/kernel/ftrace.c
@@ -130,9 +130,8 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
return 0;
}
-int __init ftrace_dyn_arch_init(void *data)
+int __init ftrace_dyn_arch_init(void)
{
- *(unsigned long *) data = 0;
return 0;
}
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
index b9e25ae2579c..d7c00507568a 100644
--- a/arch/s390/kernel/head64.S
+++ b/arch/s390/kernel/head64.S
@@ -59,7 +59,7 @@ ENTRY(startup_continue)
.quad 0 # cr12: tracing off
.quad 0 # cr13: home space segment table
.quad 0xc0000000 # cr14: machine check handling off
- .quad 0 # cr15: linkage stack operations
+ .quad .Llinkage_stack # cr15: linkage stack operations
.Lpcmsk:.quad 0x0000000180000000
.L4malign:.quad 0xffffffffffc00000
.Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8
@@ -67,12 +67,15 @@ ENTRY(startup_continue)
.Lparmaddr:
.quad PARMAREA
.align 64
-.Lduct: .long 0,0,0,0,.Lduald,0,0,0
+.Lduct: .long 0,.Laste,.Laste,0,.Lduald,0,0,0
.long 0,0,0,0,0,0,0,0
+.Laste: .quad 0,0xffffffffffffffff,0,0,0,0,0,0
.align 128
.Lduald:.rept 8
.long 0x80000000,0,0,0 # invalid access-list entries
.endr
+.Llinkage_stack:
+ .long 0,0,0x89000000,0,0,0,0x8a000000,0
ENTRY(_ehead)
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
index bb27a262c44a..d42b14cc72a4 100644
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -18,6 +18,7 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/cpu.h>
+#include <linux/irq.h>
#include <asm/irq_regs.h>
#include <asm/cputime.h>
#include <asm/lowcore.h>
@@ -84,6 +85,7 @@ static const struct irq_class irqclass_sub_desc[NR_ARCH_IRQS] = {
[IRQIO_PCI] = {.name = "PCI", .desc = "[I/O] PCI Interrupt" },
[IRQIO_MSI] = {.name = "MSI", .desc = "[I/O] MSI Interrupt" },
[IRQIO_VIR] = {.name = "VIR", .desc = "[I/O] Virtual I/O Devices"},
+ [IRQIO_VAI] = {.name = "VAI", .desc = "[I/O] Virtual I/O Devices AI"},
[NMI_NMI] = {.name = "NMI", .desc = "[NMI] Machine Check"},
[CPU_RST] = {.name = "RST", .desc = "[CPU] CPU Restart"},
};
diff --git a/arch/s390/kernel/perf_event.c b/arch/s390/kernel/perf_event.c
index 5d2dfa31c4ef..61595c1f0a0f 100644
--- a/arch/s390/kernel/perf_event.c
+++ b/arch/s390/kernel/perf_event.c
@@ -121,7 +121,7 @@ unsigned long perf_misc_flags(struct pt_regs *regs)
: PERF_RECORD_MISC_KERNEL;
}
-void print_debug_cf(void)
+static void print_debug_cf(void)
{
struct cpumf_ctr_info cf_info;
int cpu = smp_processor_id();
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index f6be6087a0e9..4ac8fafec95f 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -85,7 +85,10 @@ void update_cr_regs(struct task_struct *task)
/* merge TIF_SINGLE_STEP into user specified PER registers. */
if (test_tsk_thread_flag(task, TIF_SINGLE_STEP)) {
- new.control |= PER_EVENT_IFETCH;
+ if (test_tsk_thread_flag(task, TIF_BLOCK_STEP))
+ new.control |= PER_EVENT_BRANCH;
+ else
+ new.control |= PER_EVENT_IFETCH;
#ifdef CONFIG_64BIT
new.control |= PER_CONTROL_SUSPENSION;
new.control |= PER_EVENT_TRANSACTION_END;
@@ -107,14 +110,22 @@ void update_cr_regs(struct task_struct *task)
void user_enable_single_step(struct task_struct *task)
{
+ clear_tsk_thread_flag(task, TIF_BLOCK_STEP);
set_tsk_thread_flag(task, TIF_SINGLE_STEP);
}
void user_disable_single_step(struct task_struct *task)
{
+ clear_tsk_thread_flag(task, TIF_BLOCK_STEP);
clear_tsk_thread_flag(task, TIF_SINGLE_STEP);
}
+void user_enable_block_step(struct task_struct *task)
+{
+ set_tsk_thread_flag(task, TIF_SINGLE_STEP);
+ set_tsk_thread_flag(task, TIF_BLOCK_STEP);
+}
+
/*
* Called by kernel/ptrace.c when detaching..
*
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 09e2f468f48b..f70f2489fa5f 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -47,7 +47,6 @@
#include <linux/compat.h>
#include <asm/ipl.h>
-#include <asm/uaccess.h>
#include <asm/facility.h>
#include <asm/smp.h>
#include <asm/mmu_context.h>
@@ -65,12 +64,6 @@
#include "entry.h"
/*
- * User copy operations.
- */
-struct uaccess_ops uaccess;
-EXPORT_SYMBOL(uaccess);
-
-/*
* Machine setup..
*/
unsigned int console_mode = 0;
@@ -294,14 +287,6 @@ static int __init parse_vmalloc(char *arg)
}
early_param("vmalloc", parse_vmalloc);
-static int __init early_parse_user_mode(char *p)
-{
- if (!p || strcmp(p, "primary") == 0)
- return 0;
- return 1;
-}
-early_param("user_mode", early_parse_user_mode);
-
void *restart_stack __attribute__((__section__(".data")));
static void __init setup_lowcore(void)
@@ -1009,8 +994,6 @@ void __init setup_arch(char **cmdline_p)
init_mm.end_data = (unsigned long) &_edata;
init_mm.brk = (unsigned long) &_end;
- uaccess = MACHINE_HAS_MVCOS ? uaccess_mvcos : uaccess_pt;
-
parse_early_param();
detect_memory_layout(memory_chunk, memory_end);
os_info_init();
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index a7125b62a9a6..8827883310dd 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -773,11 +773,11 @@ void __noreturn cpu_die(void)
void __init smp_fill_possible_mask(void)
{
- unsigned int possible, cpu;
+ unsigned int possible, sclp, cpu;
- possible = setup_possible_cpus;
- if (!possible)
- possible = MACHINE_IS_VM ? 64 : nr_cpu_ids;
+ sclp = sclp_get_max_cpu() ?: nr_cpu_ids;
+ possible = setup_possible_cpus ?: nr_cpu_ids;
+ possible = min(possible, sclp);
for (cpu = 0; cpu < possible && cpu < nr_cpu_ids; cpu++)
set_cpu_possible(cpu, true);
}
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index 143992152ec9..542ef488bac1 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -9,349 +9,349 @@
#define NI_SYSCALL SYSCALL(sys_ni_syscall,sys_ni_syscall,sys_ni_syscall)
NI_SYSCALL /* 0 */
-SYSCALL(sys_exit,sys_exit,sys32_exit_wrapper)
+SYSCALL(sys_exit,sys_exit,compat_sys_exit)
SYSCALL(sys_fork,sys_fork,sys_fork)
-SYSCALL(sys_read,sys_read,sys32_read_wrapper)
-SYSCALL(sys_write,sys_write,sys32_write_wrapper)
+SYSCALL(sys_read,sys_read,compat_sys_s390_read)
+SYSCALL(sys_write,sys_write,compat_sys_s390_write)
SYSCALL(sys_open,sys_open,compat_sys_open) /* 5 */
-SYSCALL(sys_close,sys_close,sys32_close_wrapper)
+SYSCALL(sys_close,sys_close,compat_sys_close)
SYSCALL(sys_restart_syscall,sys_restart_syscall,sys_restart_syscall)
-SYSCALL(sys_creat,sys_creat,sys32_creat_wrapper)
-SYSCALL(sys_link,sys_link,sys32_link_wrapper)
-SYSCALL(sys_unlink,sys_unlink,sys32_unlink_wrapper) /* 10 */
-SYSCALL(sys_execve,sys_execve,sys32_execve_wrapper)
-SYSCALL(sys_chdir,sys_chdir,sys32_chdir_wrapper)
-SYSCALL(sys_time,sys_ni_syscall,sys32_time_wrapper) /* old time syscall */
-SYSCALL(sys_mknod,sys_mknod,sys32_mknod_wrapper)
-SYSCALL(sys_chmod,sys_chmod,sys32_chmod_wrapper) /* 15 */
-SYSCALL(sys_lchown16,sys_ni_syscall,sys32_lchown16_wrapper) /* old lchown16 syscall*/
+SYSCALL(sys_creat,sys_creat,compat_sys_creat)
+SYSCALL(sys_link,sys_link,compat_sys_link)
+SYSCALL(sys_unlink,sys_unlink,compat_sys_unlink) /* 10 */
+SYSCALL(sys_execve,sys_execve,compat_sys_execve)
+SYSCALL(sys_chdir,sys_chdir,compat_sys_chdir)
+SYSCALL(sys_time,sys_ni_syscall,compat_sys_time) /* old time syscall */
+SYSCALL(sys_mknod,sys_mknod,compat_sys_mknod)
+SYSCALL(sys_chmod,sys_chmod,compat_sys_chmod) /* 15 */
+SYSCALL(sys_lchown16,sys_ni_syscall,compat_sys_s390_lchown16) /* old lchown16 syscall*/
NI_SYSCALL /* old break syscall holder */
NI_SYSCALL /* old stat syscall holder */
SYSCALL(sys_lseek,sys_lseek,compat_sys_lseek)
SYSCALL(sys_getpid,sys_getpid,sys_getpid) /* 20 */
-SYSCALL(sys_mount,sys_mount,sys32_mount_wrapper)
-SYSCALL(sys_oldumount,sys_oldumount,sys32_oldumount_wrapper)
-SYSCALL(sys_setuid16,sys_ni_syscall,sys32_setuid16_wrapper) /* old setuid16 syscall*/
-SYSCALL(sys_getuid16,sys_ni_syscall,sys32_getuid16) /* old getuid16 syscall*/
-SYSCALL(sys_stime,sys_ni_syscall,sys32_stime_wrapper) /* 25 old stime syscall */
-SYSCALL(sys_ptrace,sys_ptrace,sys32_ptrace_wrapper)
-SYSCALL(sys_alarm,sys_alarm,sys32_alarm_wrapper)
+SYSCALL(sys_mount,sys_mount,compat_sys_mount)
+SYSCALL(sys_oldumount,sys_oldumount,compat_sys_oldumount)
+SYSCALL(sys_setuid16,sys_ni_syscall,compat_sys_s390_setuid16) /* old setuid16 syscall*/
+SYSCALL(sys_getuid16,sys_ni_syscall,compat_sys_s390_getuid16) /* old getuid16 syscall*/
+SYSCALL(sys_stime,sys_ni_syscall,compat_sys_stime) /* 25 old stime syscall */
+SYSCALL(sys_ptrace,sys_ptrace,compat_sys_ptrace)
+SYSCALL(sys_alarm,sys_alarm,compat_sys_alarm)
NI_SYSCALL /* old fstat syscall */
SYSCALL(sys_pause,sys_pause,sys_pause)
-SYSCALL(sys_utime,sys_utime,compat_sys_utime_wrapper) /* 30 */
+SYSCALL(sys_utime,sys_utime,compat_sys_utime) /* 30 */
NI_SYSCALL /* old stty syscall */
NI_SYSCALL /* old gtty syscall */
-SYSCALL(sys_access,sys_access,sys32_access_wrapper)
-SYSCALL(sys_nice,sys_nice,sys32_nice_wrapper)
+SYSCALL(sys_access,sys_access,compat_sys_access)
+SYSCALL(sys_nice,sys_nice,compat_sys_nice)
NI_SYSCALL /* 35 old ftime syscall */
SYSCALL(sys_sync,sys_sync,sys_sync)
-SYSCALL(sys_kill,sys_kill,sys32_kill_wrapper)
-SYSCALL(sys_rename,sys_rename,sys32_rename_wrapper)
-SYSCALL(sys_mkdir,sys_mkdir,sys32_mkdir_wrapper)
-SYSCALL(sys_rmdir,sys_rmdir,sys32_rmdir_wrapper) /* 40 */
-SYSCALL(sys_dup,sys_dup,sys32_dup_wrapper)
-SYSCALL(sys_pipe,sys_pipe,sys32_pipe_wrapper)
-SYSCALL(sys_times,sys_times,compat_sys_times_wrapper)
+SYSCALL(sys_kill,sys_kill,compat_sys_kill)
+SYSCALL(sys_rename,sys_rename,compat_sys_rename)
+SYSCALL(sys_mkdir,sys_mkdir,compat_sys_mkdir)
+SYSCALL(sys_rmdir,sys_rmdir,compat_sys_rmdir) /* 40 */
+SYSCALL(sys_dup,sys_dup,compat_sys_dup)
+SYSCALL(sys_pipe,sys_pipe,compat_sys_pipe)
+SYSCALL(sys_times,sys_times,compat_sys_times)
NI_SYSCALL /* old prof syscall */
-SYSCALL(sys_brk,sys_brk,sys32_brk_wrapper) /* 45 */
-SYSCALL(sys_setgid16,sys_ni_syscall,sys32_setgid16_wrapper) /* old setgid16 syscall*/
-SYSCALL(sys_getgid16,sys_ni_syscall,sys32_getgid16) /* old getgid16 syscall*/
-SYSCALL(sys_signal,sys_signal,sys32_signal_wrapper)
-SYSCALL(sys_geteuid16,sys_ni_syscall,sys32_geteuid16) /* old geteuid16 syscall */
-SYSCALL(sys_getegid16,sys_ni_syscall,sys32_getegid16) /* 50 old getegid16 syscall */
-SYSCALL(sys_acct,sys_acct,sys32_acct_wrapper)
-SYSCALL(sys_umount,sys_umount,sys32_umount_wrapper)
+SYSCALL(sys_brk,sys_brk,compat_sys_brk) /* 45 */
+SYSCALL(sys_setgid16,sys_ni_syscall,compat_sys_s390_setgid16) /* old setgid16 syscall*/
+SYSCALL(sys_getgid16,sys_ni_syscall,compat_sys_s390_getgid16) /* old getgid16 syscall*/
+SYSCALL(sys_signal,sys_signal,compat_sys_signal)
+SYSCALL(sys_geteuid16,sys_ni_syscall,compat_sys_s390_geteuid16) /* old geteuid16 syscall */
+SYSCALL(sys_getegid16,sys_ni_syscall,compat_sys_s390_getegid16) /* 50 old getegid16 syscall */
+SYSCALL(sys_acct,sys_acct,compat_sys_acct)
+SYSCALL(sys_umount,sys_umount,compat_sys_umount)
NI_SYSCALL /* old lock syscall */
-SYSCALL(sys_ioctl,sys_ioctl,compat_sys_ioctl_wrapper)
-SYSCALL(sys_fcntl,sys_fcntl,compat_sys_fcntl_wrapper) /* 55 */
+SYSCALL(sys_ioctl,sys_ioctl,compat_sys_ioctl)
+SYSCALL(sys_fcntl,sys_fcntl,compat_sys_fcntl) /* 55 */
NI_SYSCALL /* intel mpx syscall */
-SYSCALL(sys_setpgid,sys_setpgid,sys32_setpgid_wrapper)
+SYSCALL(sys_setpgid,sys_setpgid,compat_sys_setpgid)
NI_SYSCALL /* old ulimit syscall */
NI_SYSCALL /* old uname syscall */
-SYSCALL(sys_umask,sys_umask,sys32_umask_wrapper) /* 60 */
-SYSCALL(sys_chroot,sys_chroot,sys32_chroot_wrapper)
-SYSCALL(sys_ustat,sys_ustat,sys32_ustat_wrapper)
-SYSCALL(sys_dup2,sys_dup2,sys32_dup2_wrapper)
+SYSCALL(sys_umask,sys_umask,compat_sys_umask) /* 60 */
+SYSCALL(sys_chroot,sys_chroot,compat_sys_chroot)
+SYSCALL(sys_ustat,sys_ustat,compat_sys_ustat)
+SYSCALL(sys_dup2,sys_dup2,compat_sys_dup2)
SYSCALL(sys_getppid,sys_getppid,sys_getppid)
SYSCALL(sys_getpgrp,sys_getpgrp,sys_getpgrp) /* 65 */
SYSCALL(sys_setsid,sys_setsid,sys_setsid)
SYSCALL(sys_sigaction,sys_sigaction,compat_sys_sigaction)
NI_SYSCALL /* old sgetmask syscall*/
NI_SYSCALL /* old ssetmask syscall*/
-SYSCALL(sys_setreuid16,sys_ni_syscall,sys32_setreuid16_wrapper) /* old setreuid16 syscall */
-SYSCALL(sys_setregid16,sys_ni_syscall,sys32_setregid16_wrapper) /* old setregid16 syscall */
-SYSCALL(sys_sigsuspend,sys_sigsuspend,sys_sigsuspend_wrapper)
-SYSCALL(sys_sigpending,sys_sigpending,compat_sys_sigpending_wrapper)
-SYSCALL(sys_sethostname,sys_sethostname,sys32_sethostname_wrapper)
-SYSCALL(sys_setrlimit,sys_setrlimit,compat_sys_setrlimit_wrapper) /* 75 */
-SYSCALL(sys_old_getrlimit,sys_getrlimit,compat_sys_old_getrlimit_wrapper)
+SYSCALL(sys_setreuid16,sys_ni_syscall,compat_sys_s390_setreuid16) /* old setreuid16 syscall */
+SYSCALL(sys_setregid16,sys_ni_syscall,compat_sys_s390_setregid16) /* old setregid16 syscall */
+SYSCALL(sys_sigsuspend,sys_sigsuspend,compat_sys_sigsuspend)
+SYSCALL(sys_sigpending,sys_sigpending,compat_sys_sigpending)
+SYSCALL(sys_sethostname,sys_sethostname,compat_sys_sethostname)
+SYSCALL(sys_setrlimit,sys_setrlimit,compat_sys_setrlimit) /* 75 */
+SYSCALL(sys_old_getrlimit,sys_getrlimit,compat_sys_old_getrlimit)
SYSCALL(sys_getrusage,sys_getrusage,compat_sys_getrusage)
-SYSCALL(sys_gettimeofday,sys_gettimeofday,compat_sys_gettimeofday_wrapper)
-SYSCALL(sys_settimeofday,sys_settimeofday,compat_sys_settimeofday_wrapper)
-SYSCALL(sys_getgroups16,sys_ni_syscall,sys32_getgroups16_wrapper) /* 80 old getgroups16 syscall */
-SYSCALL(sys_setgroups16,sys_ni_syscall,sys32_setgroups16_wrapper) /* old setgroups16 syscall */
+SYSCALL(sys_gettimeofday,sys_gettimeofday,compat_sys_gettimeofday)
+SYSCALL(sys_settimeofday,sys_settimeofday,compat_sys_settimeofday)
+SYSCALL(sys_getgroups16,sys_ni_syscall,compat_sys_s390_getgroups16) /* 80 old getgroups16 syscall */
+SYSCALL(sys_setgroups16,sys_ni_syscall,compat_sys_s390_setgroups16) /* old setgroups16 syscall */
NI_SYSCALL /* old select syscall */
-SYSCALL(sys_symlink,sys_symlink,sys32_symlink_wrapper)
+SYSCALL(sys_symlink,sys_symlink,compat_sys_symlink)
NI_SYSCALL /* old lstat syscall */
-SYSCALL(sys_readlink,sys_readlink,sys32_readlink_wrapper) /* 85 */
-SYSCALL(sys_uselib,sys_uselib,sys32_uselib_wrapper)
-SYSCALL(sys_swapon,sys_swapon,sys32_swapon_wrapper)
-SYSCALL(sys_reboot,sys_reboot,sys32_reboot_wrapper)
-SYSCALL(sys_ni_syscall,sys_ni_syscall,old32_readdir_wrapper) /* old readdir syscall */
-SYSCALL(sys_old_mmap,sys_old_mmap,old32_mmap_wrapper) /* 90 */
-SYSCALL(sys_munmap,sys_munmap,sys32_munmap_wrapper)
+SYSCALL(sys_readlink,sys_readlink,compat_sys_readlink) /* 85 */
+SYSCALL(sys_uselib,sys_uselib,compat_sys_uselib)
+SYSCALL(sys_swapon,sys_swapon,compat_sys_swapon)
+SYSCALL(sys_reboot,sys_reboot,compat_sys_reboot)
+SYSCALL(sys_ni_syscall,sys_ni_syscall,compat_sys_old_readdir) /* old readdir syscall */
+SYSCALL(sys_old_mmap,sys_old_mmap,compat_sys_s390_old_mmap) /* 90 */
+SYSCALL(sys_munmap,sys_munmap,compat_sys_munmap)
SYSCALL(sys_truncate,sys_truncate,compat_sys_truncate)
SYSCALL(sys_ftruncate,sys_ftruncate,compat_sys_ftruncate)
-SYSCALL(sys_fchmod,sys_fchmod,sys32_fchmod_wrapper)
-SYSCALL(sys_fchown16,sys_ni_syscall,sys32_fchown16_wrapper) /* 95 old fchown16 syscall*/
-SYSCALL(sys_getpriority,sys_getpriority,sys32_getpriority_wrapper)
-SYSCALL(sys_setpriority,sys_setpriority,sys32_setpriority_wrapper)
+SYSCALL(sys_fchmod,sys_fchmod,compat_sys_fchmod)
+SYSCALL(sys_fchown16,sys_ni_syscall,compat_sys_s390_fchown16) /* 95 old fchown16 syscall*/
+SYSCALL(sys_getpriority,sys_getpriority,compat_sys_getpriority)
+SYSCALL(sys_setpriority,sys_setpriority,compat_sys_setpriority)
NI_SYSCALL /* old profil syscall */
-SYSCALL(sys_statfs,sys_statfs,compat_sys_statfs_wrapper)
-SYSCALL(sys_fstatfs,sys_fstatfs,compat_sys_fstatfs_wrapper) /* 100 */
+SYSCALL(sys_statfs,sys_statfs,compat_sys_statfs)
+SYSCALL(sys_fstatfs,sys_fstatfs,compat_sys_fstatfs) /* 100 */
NI_SYSCALL /* ioperm for i386 */
-SYSCALL(sys_socketcall,sys_socketcall,compat_sys_socketcall_wrapper)
-SYSCALL(sys_syslog,sys_syslog,sys32_syslog_wrapper)
+SYSCALL(sys_socketcall,sys_socketcall,compat_sys_socketcall)
+SYSCALL(sys_syslog,sys_syslog,compat_sys_syslog)
SYSCALL(sys_setitimer,sys_setitimer,compat_sys_setitimer)
SYSCALL(sys_getitimer,sys_getitimer,compat_sys_getitimer) /* 105 */
-SYSCALL(sys_newstat,sys_newstat,compat_sys_newstat_wrapper)
-SYSCALL(sys_newlstat,sys_newlstat,compat_sys_newlstat_wrapper)
-SYSCALL(sys_newfstat,sys_newfstat,compat_sys_newfstat_wrapper)
+SYSCALL(sys_newstat,sys_newstat,compat_sys_newstat)
+SYSCALL(sys_newlstat,sys_newlstat,compat_sys_newlstat)
+SYSCALL(sys_newfstat,sys_newfstat,compat_sys_newfstat)
NI_SYSCALL /* old uname syscall */
SYSCALL(sys_lookup_dcookie,sys_lookup_dcookie,compat_sys_lookup_dcookie) /* 110 */
SYSCALL(sys_vhangup,sys_vhangup,sys_vhangup)
NI_SYSCALL /* old "idle" system call */
NI_SYSCALL /* vm86old for i386 */
SYSCALL(sys_wait4,sys_wait4,compat_sys_wait4)
-SYSCALL(sys_swapoff,sys_swapoff,sys32_swapoff_wrapper) /* 115 */
-SYSCALL(sys_sysinfo,sys_sysinfo,compat_sys_sysinfo_wrapper)
+SYSCALL(sys_swapoff,sys_swapoff,compat_sys_swapoff) /* 115 */
+SYSCALL(sys_sysinfo,sys_sysinfo,compat_sys_sysinfo)
SYSCALL(sys_s390_ipc,sys_s390_ipc,compat_sys_s390_ipc)
-SYSCALL(sys_fsync,sys_fsync,sys32_fsync_wrapper)
-SYSCALL(sys_sigreturn,sys_sigreturn,sys32_sigreturn)
-SYSCALL(sys_clone,sys_clone,sys_clone_wrapper) /* 120 */
-SYSCALL(sys_setdomainname,sys_setdomainname,sys32_setdomainname_wrapper)
-SYSCALL(sys_newuname,sys_newuname,sys32_newuname_wrapper)
+SYSCALL(sys_fsync,sys_fsync,compat_sys_fsync)
+SYSCALL(sys_sigreturn,sys_sigreturn,compat_sys_sigreturn)
+SYSCALL(sys_clone,sys_clone,compat_sys_clone) /* 120 */
+SYSCALL(sys_setdomainname,sys_setdomainname,compat_sys_setdomainname)
+SYSCALL(sys_newuname,sys_newuname,compat_sys_newuname)
NI_SYSCALL /* modify_ldt for i386 */
-SYSCALL(sys_adjtimex,sys_adjtimex,compat_sys_adjtimex_wrapper)
-SYSCALL(sys_mprotect,sys_mprotect,sys32_mprotect_wrapper) /* 125 */
+SYSCALL(sys_adjtimex,sys_adjtimex,compat_sys_adjtimex)
+SYSCALL(sys_mprotect,sys_mprotect,compat_sys_mprotect) /* 125 */
SYSCALL(sys_sigprocmask,sys_sigprocmask,compat_sys_sigprocmask)
NI_SYSCALL /* old "create module" */
-SYSCALL(sys_init_module,sys_init_module,sys_init_module_wrapper)
-SYSCALL(sys_delete_module,sys_delete_module,sys_delete_module_wrapper)
+SYSCALL(sys_init_module,sys_init_module,compat_sys_init_module)
+SYSCALL(sys_delete_module,sys_delete_module,compat_sys_delete_module)
NI_SYSCALL /* 130: old get_kernel_syms */
-SYSCALL(sys_quotactl,sys_quotactl,sys32_quotactl_wrapper)
-SYSCALL(sys_getpgid,sys_getpgid,sys32_getpgid_wrapper)
-SYSCALL(sys_fchdir,sys_fchdir,sys32_fchdir_wrapper)
-SYSCALL(sys_bdflush,sys_bdflush,sys32_bdflush_wrapper)
-SYSCALL(sys_sysfs,sys_sysfs,sys32_sysfs_wrapper) /* 135 */
-SYSCALL(sys_personality,sys_s390_personality,sys32_personality_wrapper)
+SYSCALL(sys_quotactl,sys_quotactl,compat_sys_quotactl)
+SYSCALL(sys_getpgid,sys_getpgid,compat_sys_getpgid)
+SYSCALL(sys_fchdir,sys_fchdir,compat_sys_fchdir)
+SYSCALL(sys_bdflush,sys_bdflush,compat_sys_bdflush)
+SYSCALL(sys_sysfs,sys_sysfs,compat_sys_sysfs) /* 135 */
+SYSCALL(sys_personality,sys_s390_personality,compat_sys_s390_personality)
NI_SYSCALL /* for afs_syscall */
-SYSCALL(sys_setfsuid16,sys_ni_syscall,sys32_setfsuid16_wrapper) /* old setfsuid16 syscall */
-SYSCALL(sys_setfsgid16,sys_ni_syscall,sys32_setfsgid16_wrapper) /* old setfsgid16 syscall */
-SYSCALL(sys_llseek,sys_llseek,sys32_llseek_wrapper) /* 140 */
-SYSCALL(sys_getdents,sys_getdents,sys32_getdents_wrapper)
-SYSCALL(sys_select,sys_select,compat_sys_select_wrapper)
-SYSCALL(sys_flock,sys_flock,sys32_flock_wrapper)
-SYSCALL(sys_msync,sys_msync,sys32_msync_wrapper)
-SYSCALL(sys_readv,sys_readv,compat_sys_readv_wrapper) /* 145 */
-SYSCALL(sys_writev,sys_writev,compat_sys_writev_wrapper)
-SYSCALL(sys_getsid,sys_getsid,sys32_getsid_wrapper)
-SYSCALL(sys_fdatasync,sys_fdatasync,sys32_fdatasync_wrapper)
+SYSCALL(sys_setfsuid16,sys_ni_syscall,compat_sys_s390_setfsuid16) /* old setfsuid16 syscall */
+SYSCALL(sys_setfsgid16,sys_ni_syscall,compat_sys_s390_setfsgid16) /* old setfsgid16 syscall */
+SYSCALL(sys_llseek,sys_llseek,compat_sys_llseek) /* 140 */
+SYSCALL(sys_getdents,sys_getdents,compat_sys_getdents)
+SYSCALL(sys_select,sys_select,compat_sys_select)
+SYSCALL(sys_flock,sys_flock,compat_sys_flock)
+SYSCALL(sys_msync,sys_msync,compat_sys_msync)
+SYSCALL(sys_readv,sys_readv,compat_sys_readv) /* 145 */
+SYSCALL(sys_writev,sys_writev,compat_sys_writev)
+SYSCALL(sys_getsid,sys_getsid,compat_sys_getsid)
+SYSCALL(sys_fdatasync,sys_fdatasync,compat_sys_fdatasync)
SYSCALL(sys_sysctl,sys_sysctl,compat_sys_sysctl)
-SYSCALL(sys_mlock,sys_mlock,sys32_mlock_wrapper) /* 150 */
-SYSCALL(sys_munlock,sys_munlock,sys32_munlock_wrapper)
-SYSCALL(sys_mlockall,sys_mlockall,sys32_mlockall_wrapper)
+SYSCALL(sys_mlock,sys_mlock,compat_sys_mlock) /* 150 */
+SYSCALL(sys_munlock,sys_munlock,compat_sys_munlock)
+SYSCALL(sys_mlockall,sys_mlockall,compat_sys_mlockall)
SYSCALL(sys_munlockall,sys_munlockall,sys_munlockall)
-SYSCALL(sys_sched_setparam,sys_sched_setparam,sys32_sched_setparam_wrapper)
-SYSCALL(sys_sched_getparam,sys_sched_getparam,sys32_sched_getparam_wrapper) /* 155 */
-SYSCALL(sys_sched_setscheduler,sys_sched_setscheduler,sys32_sched_setscheduler_wrapper)
-SYSCALL(sys_sched_getscheduler,sys_sched_getscheduler,sys32_sched_getscheduler_wrapper)
+SYSCALL(sys_sched_setparam,sys_sched_setparam,compat_sys_sched_setparam)
+SYSCALL(sys_sched_getparam,sys_sched_getparam,compat_sys_sched_getparam) /* 155 */
+SYSCALL(sys_sched_setscheduler,sys_sched_setscheduler,compat_sys_sched_setscheduler)
+SYSCALL(sys_sched_getscheduler,sys_sched_getscheduler,compat_sys_sched_getscheduler)
SYSCALL(sys_sched_yield,sys_sched_yield,sys_sched_yield)
-SYSCALL(sys_sched_get_priority_max,sys_sched_get_priority_max,sys32_sched_get_priority_max_wrapper)
-SYSCALL(sys_sched_get_priority_min,sys_sched_get_priority_min,sys32_sched_get_priority_min_wrapper) /* 160 */
+SYSCALL(sys_sched_get_priority_max,sys_sched_get_priority_max,compat_sys_sched_get_priority_max)
+SYSCALL(sys_sched_get_priority_min,sys_sched_get_priority_min,compat_sys_sched_get_priority_min) /* 160 */
SYSCALL(sys_sched_rr_get_interval,sys_sched_rr_get_interval,compat_sys_sched_rr_get_interval)
-SYSCALL(sys_nanosleep,sys_nanosleep,compat_sys_nanosleep_wrapper)
-SYSCALL(sys_mremap,sys_mremap,sys32_mremap_wrapper)
-SYSCALL(sys_setresuid16,sys_ni_syscall,sys32_setresuid16_wrapper) /* old setresuid16 syscall */
-SYSCALL(sys_getresuid16,sys_ni_syscall,sys32_getresuid16_wrapper) /* 165 old getresuid16 syscall */
+SYSCALL(sys_nanosleep,sys_nanosleep,compat_sys_nanosleep)
+SYSCALL(sys_mremap,sys_mremap,compat_sys_mremap)
+SYSCALL(sys_setresuid16,sys_ni_syscall,compat_sys_s390_setresuid16) /* old setresuid16 syscall */
+SYSCALL(sys_getresuid16,sys_ni_syscall,compat_sys_s390_getresuid16) /* 165 old getresuid16 syscall */
NI_SYSCALL /* for vm86 */
NI_SYSCALL /* old sys_query_module */
-SYSCALL(sys_poll,sys_poll,sys32_poll_wrapper)
+SYSCALL(sys_poll,sys_poll,compat_sys_poll)
NI_SYSCALL /* old nfsservctl */
-SYSCALL(sys_setresgid16,sys_ni_syscall,sys32_setresgid16_wrapper) /* 170 old setresgid16 syscall */
-SYSCALL(sys_getresgid16,sys_ni_syscall,sys32_getresgid16_wrapper) /* old getresgid16 syscall */
-SYSCALL(sys_prctl,sys_prctl,sys32_prctl_wrapper)
-SYSCALL(sys_rt_sigreturn,sys_rt_sigreturn,sys32_rt_sigreturn)
+SYSCALL(sys_setresgid16,sys_ni_syscall,compat_sys_s390_setresgid16) /* 170 old setresgid16 syscall */
+SYSCALL(sys_getresgid16,sys_ni_syscall,compat_sys_s390_getresgid16) /* old getresgid16 syscall */
+SYSCALL(sys_prctl,sys_prctl,compat_sys_prctl)
+SYSCALL(sys_rt_sigreturn,sys_rt_sigreturn,compat_sys_rt_sigreturn)
SYSCALL(sys_rt_sigaction,sys_rt_sigaction,compat_sys_rt_sigaction)
SYSCALL(sys_rt_sigprocmask,sys_rt_sigprocmask,compat_sys_rt_sigprocmask) /* 175 */
SYSCALL(sys_rt_sigpending,sys_rt_sigpending,compat_sys_rt_sigpending)
SYSCALL(sys_rt_sigtimedwait,sys_rt_sigtimedwait,compat_sys_rt_sigtimedwait)
SYSCALL(sys_rt_sigqueueinfo,sys_rt_sigqueueinfo,compat_sys_rt_sigqueueinfo)
SYSCALL(sys_rt_sigsuspend,sys_rt_sigsuspend,compat_sys_rt_sigsuspend)
-SYSCALL(sys_pread64,sys_pread64,sys32_pread64_wrapper) /* 180 */
-SYSCALL(sys_pwrite64,sys_pwrite64,sys32_pwrite64_wrapper)
-SYSCALL(sys_chown16,sys_ni_syscall,sys32_chown16_wrapper) /* old chown16 syscall */
-SYSCALL(sys_getcwd,sys_getcwd,sys32_getcwd_wrapper)
-SYSCALL(sys_capget,sys_capget,sys32_capget_wrapper)
-SYSCALL(sys_capset,sys_capset,sys32_capset_wrapper) /* 185 */
+SYSCALL(sys_pread64,sys_pread64,compat_sys_s390_pread64) /* 180 */
+SYSCALL(sys_pwrite64,sys_pwrite64,compat_sys_s390_pwrite64)
+SYSCALL(sys_chown16,sys_ni_syscall,compat_sys_s390_chown16) /* old chown16 syscall */
+SYSCALL(sys_getcwd,sys_getcwd,compat_sys_getcwd)
+SYSCALL(sys_capget,sys_capget,compat_sys_capget)
+SYSCALL(sys_capset,sys_capset,compat_sys_capset) /* 185 */
SYSCALL(sys_sigaltstack,sys_sigaltstack,compat_sys_sigaltstack)
SYSCALL(sys_sendfile,sys_sendfile64,compat_sys_sendfile)
NI_SYSCALL /* streams1 */
NI_SYSCALL /* streams2 */
SYSCALL(sys_vfork,sys_vfork,sys_vfork) /* 190 */
-SYSCALL(sys_getrlimit,sys_getrlimit,compat_sys_getrlimit_wrapper)
-SYSCALL(sys_mmap2,sys_mmap2,sys32_mmap2_wrapper)
-SYSCALL(sys_truncate64,sys_ni_syscall,sys32_truncate64_wrapper)
-SYSCALL(sys_ftruncate64,sys_ni_syscall,sys32_ftruncate64_wrapper)
-SYSCALL(sys_stat64,sys_ni_syscall,sys32_stat64_wrapper) /* 195 */
-SYSCALL(sys_lstat64,sys_ni_syscall,sys32_lstat64_wrapper)
-SYSCALL(sys_fstat64,sys_ni_syscall,sys32_fstat64_wrapper)
-SYSCALL(sys_lchown,sys_lchown,sys32_lchown_wrapper)
+SYSCALL(sys_getrlimit,sys_getrlimit,compat_sys_getrlimit)
+SYSCALL(sys_mmap2,sys_mmap2,compat_sys_s390_mmap2)
+SYSCALL(sys_truncate64,sys_ni_syscall,compat_sys_s390_truncate64)
+SYSCALL(sys_ftruncate64,sys_ni_syscall,compat_sys_s390_ftruncate64)
+SYSCALL(sys_stat64,sys_ni_syscall,compat_sys_s390_stat64) /* 195 */
+SYSCALL(sys_lstat64,sys_ni_syscall,compat_sys_s390_lstat64)
+SYSCALL(sys_fstat64,sys_ni_syscall,compat_sys_s390_fstat64)
+SYSCALL(sys_lchown,sys_lchown,compat_sys_lchown)
SYSCALL(sys_getuid,sys_getuid,sys_getuid)
SYSCALL(sys_getgid,sys_getgid,sys_getgid) /* 200 */
SYSCALL(sys_geteuid,sys_geteuid,sys_geteuid)
SYSCALL(sys_getegid,sys_getegid,sys_getegid)
-SYSCALL(sys_setreuid,sys_setreuid,sys32_setreuid_wrapper)
-SYSCALL(sys_setregid,sys_setregid,sys32_setregid_wrapper)
-SYSCALL(sys_getgroups,sys_getgroups,sys32_getgroups_wrapper) /* 205 */
-SYSCALL(sys_setgroups,sys_setgroups,sys32_setgroups_wrapper)
-SYSCALL(sys_fchown,sys_fchown,sys32_fchown_wrapper)
-SYSCALL(sys_setresuid,sys_setresuid,sys32_setresuid_wrapper)
-SYSCALL(sys_getresuid,sys_getresuid,sys32_getresuid_wrapper)
-SYSCALL(sys_setresgid,sys_setresgid,sys32_setresgid_wrapper) /* 210 */
-SYSCALL(sys_getresgid,sys_getresgid,sys32_getresgid_wrapper)
-SYSCALL(sys_chown,sys_chown,sys32_chown_wrapper)
-SYSCALL(sys_setuid,sys_setuid,sys32_setuid_wrapper)
-SYSCALL(sys_setgid,sys_setgid,sys32_setgid_wrapper)
-SYSCALL(sys_setfsuid,sys_setfsuid,sys32_setfsuid_wrapper) /* 215 */
-SYSCALL(sys_setfsgid,sys_setfsgid,sys32_setfsgid_wrapper)
-SYSCALL(sys_pivot_root,sys_pivot_root,sys32_pivot_root_wrapper)
-SYSCALL(sys_mincore,sys_mincore,sys32_mincore_wrapper)
-SYSCALL(sys_madvise,sys_madvise,sys32_madvise_wrapper)
-SYSCALL(sys_getdents64,sys_getdents64,sys32_getdents64_wrapper) /* 220 */
-SYSCALL(sys_fcntl64,sys_ni_syscall,compat_sys_fcntl64_wrapper)
-SYSCALL(sys_readahead,sys_readahead,sys32_readahead_wrapper)
+SYSCALL(sys_setreuid,sys_setreuid,compat_sys_setreuid)
+SYSCALL(sys_setregid,sys_setregid,compat_sys_setregid)
+SYSCALL(sys_getgroups,sys_getgroups,compat_sys_getgroups) /* 205 */
+SYSCALL(sys_setgroups,sys_setgroups,compat_sys_setgroups)
+SYSCALL(sys_fchown,sys_fchown,compat_sys_fchown)
+SYSCALL(sys_setresuid,sys_setresuid,compat_sys_setresuid)
+SYSCALL(sys_getresuid,sys_getresuid,compat_sys_getresuid)
+SYSCALL(sys_setresgid,sys_setresgid,compat_sys_setresgid) /* 210 */
+SYSCALL(sys_getresgid,sys_getresgid,compat_sys_getresgid)
+SYSCALL(sys_chown,sys_chown,compat_sys_chown)
+SYSCALL(sys_setuid,sys_setuid,compat_sys_setuid)
+SYSCALL(sys_setgid,sys_setgid,compat_sys_setgid)
+SYSCALL(sys_setfsuid,sys_setfsuid,compat_sys_setfsuid) /* 215 */
+SYSCALL(sys_setfsgid,sys_setfsgid,compat_sys_setfsgid)
+SYSCALL(sys_pivot_root,sys_pivot_root,compat_sys_pivot_root)
+SYSCALL(sys_mincore,sys_mincore,compat_sys_mincore)
+SYSCALL(sys_madvise,sys_madvise,compat_sys_madvise)
+SYSCALL(sys_getdents64,sys_getdents64,compat_sys_getdents64) /* 220 */
+SYSCALL(sys_fcntl64,sys_ni_syscall,compat_sys_fcntl64)
+SYSCALL(sys_readahead,sys_readahead,compat_sys_s390_readahead)
SYSCALL(sys_sendfile64,sys_ni_syscall,compat_sys_sendfile64)
-SYSCALL(sys_setxattr,sys_setxattr,sys32_setxattr_wrapper)
-SYSCALL(sys_lsetxattr,sys_lsetxattr,sys32_lsetxattr_wrapper) /* 225 */
-SYSCALL(sys_fsetxattr,sys_fsetxattr,sys32_fsetxattr_wrapper)
-SYSCALL(sys_getxattr,sys_getxattr,sys32_getxattr_wrapper)
-SYSCALL(sys_lgetxattr,sys_lgetxattr,sys32_lgetxattr_wrapper)
-SYSCALL(sys_fgetxattr,sys_fgetxattr,sys32_fgetxattr_wrapper)
-SYSCALL(sys_listxattr,sys_listxattr,sys32_listxattr_wrapper) /* 230 */
-SYSCALL(sys_llistxattr,sys_llistxattr,sys32_llistxattr_wrapper)
-SYSCALL(sys_flistxattr,sys_flistxattr,sys32_flistxattr_wrapper)
-SYSCALL(sys_removexattr,sys_removexattr,sys32_removexattr_wrapper)
-SYSCALL(sys_lremovexattr,sys_lremovexattr,sys32_lremovexattr_wrapper)
-SYSCALL(sys_fremovexattr,sys_fremovexattr,sys32_fremovexattr_wrapper) /* 235 */
+SYSCALL(sys_setxattr,sys_setxattr,compat_sys_setxattr)
+SYSCALL(sys_lsetxattr,sys_lsetxattr,compat_sys_lsetxattr) /* 225 */
+SYSCALL(sys_fsetxattr,sys_fsetxattr,compat_sys_fsetxattr)
+SYSCALL(sys_getxattr,sys_getxattr,compat_sys_getxattr)
+SYSCALL(sys_lgetxattr,sys_lgetxattr,compat_sys_lgetxattr)
+SYSCALL(sys_fgetxattr,sys_fgetxattr,compat_sys_fgetxattr)
+SYSCALL(sys_listxattr,sys_listxattr,compat_sys_listxattr) /* 230 */
+SYSCALL(sys_llistxattr,sys_llistxattr,compat_sys_llistxattr)
+SYSCALL(sys_flistxattr,sys_flistxattr,compat_sys_flistxattr)
+SYSCALL(sys_removexattr,sys_removexattr,compat_sys_removexattr)
+SYSCALL(sys_lremovexattr,sys_lremovexattr,compat_sys_lremovexattr)
+SYSCALL(sys_fremovexattr,sys_fremovexattr,compat_sys_fremovexattr) /* 235 */
SYSCALL(sys_gettid,sys_gettid,sys_gettid)
-SYSCALL(sys_tkill,sys_tkill,sys_tkill_wrapper)
+SYSCALL(sys_tkill,sys_tkill,compat_sys_tkill)
SYSCALL(sys_futex,sys_futex,compat_sys_futex)
-SYSCALL(sys_sched_setaffinity,sys_sched_setaffinity,sys32_sched_setaffinity_wrapper)
-SYSCALL(sys_sched_getaffinity,sys_sched_getaffinity,sys32_sched_getaffinity_wrapper) /* 240 */
-SYSCALL(sys_tgkill,sys_tgkill,sys_tgkill_wrapper)
+SYSCALL(sys_sched_setaffinity,sys_sched_setaffinity,compat_sys_sched_setaffinity)
+SYSCALL(sys_sched_getaffinity,sys_sched_getaffinity,compat_sys_sched_getaffinity) /* 240 */
+SYSCALL(sys_tgkill,sys_tgkill,compat_sys_tgkill)
NI_SYSCALL /* reserved for TUX */
-SYSCALL(sys_io_setup,sys_io_setup,sys32_io_setup_wrapper)
-SYSCALL(sys_io_destroy,sys_io_destroy,sys32_io_destroy_wrapper)
-SYSCALL(sys_io_getevents,sys_io_getevents,sys32_io_getevents_wrapper) /* 245 */
-SYSCALL(sys_io_submit,sys_io_submit,sys32_io_submit_wrapper)
-SYSCALL(sys_io_cancel,sys_io_cancel,sys32_io_cancel_wrapper)
-SYSCALL(sys_exit_group,sys_exit_group,sys32_exit_group_wrapper)
-SYSCALL(sys_epoll_create,sys_epoll_create,sys_epoll_create_wrapper)
-SYSCALL(sys_epoll_ctl,sys_epoll_ctl,sys_epoll_ctl_wrapper) /* 250 */
-SYSCALL(sys_epoll_wait,sys_epoll_wait,sys_epoll_wait_wrapper)
-SYSCALL(sys_set_tid_address,sys_set_tid_address,sys32_set_tid_address_wrapper)
-SYSCALL(sys_s390_fadvise64,sys_fadvise64_64,sys32_fadvise64_wrapper)
-SYSCALL(sys_timer_create,sys_timer_create,sys32_timer_create_wrapper)
-SYSCALL(sys_timer_settime,sys_timer_settime,sys32_timer_settime_wrapper) /* 255 */
-SYSCALL(sys_timer_gettime,sys_timer_gettime,sys32_timer_gettime_wrapper)
-SYSCALL(sys_timer_getoverrun,sys_timer_getoverrun,sys32_timer_getoverrun_wrapper)
-SYSCALL(sys_timer_delete,sys_timer_delete,sys32_timer_delete_wrapper)
-SYSCALL(sys_clock_settime,sys_clock_settime,sys32_clock_settime_wrapper)
-SYSCALL(sys_clock_gettime,sys_clock_gettime,sys32_clock_gettime_wrapper) /* 260 */
-SYSCALL(sys_clock_getres,sys_clock_getres,sys32_clock_getres_wrapper)
-SYSCALL(sys_clock_nanosleep,sys_clock_nanosleep,sys32_clock_nanosleep_wrapper)
+SYSCALL(sys_io_setup,sys_io_setup,compat_sys_io_setup)
+SYSCALL(sys_io_destroy,sys_io_destroy,compat_sys_io_destroy)
+SYSCALL(sys_io_getevents,sys_io_getevents,compat_sys_io_getevents) /* 245 */
+SYSCALL(sys_io_submit,sys_io_submit,compat_sys_io_submit)
+SYSCALL(sys_io_cancel,sys_io_cancel,compat_sys_io_cancel)
+SYSCALL(sys_exit_group,sys_exit_group,compat_sys_exit_group)
+SYSCALL(sys_epoll_create,sys_epoll_create,compat_sys_epoll_create)
+SYSCALL(sys_epoll_ctl,sys_epoll_ctl,compat_sys_epoll_ctl) /* 250 */
+SYSCALL(sys_epoll_wait,sys_epoll_wait,compat_sys_epoll_wait)
+SYSCALL(sys_set_tid_address,sys_set_tid_address,compat_sys_set_tid_address)
+SYSCALL(sys_s390_fadvise64,sys_fadvise64_64,compat_sys_s390_fadvise64)
+SYSCALL(sys_timer_create,sys_timer_create,compat_sys_timer_create)
+SYSCALL(sys_timer_settime,sys_timer_settime,compat_sys_timer_settime) /* 255 */
+SYSCALL(sys_timer_gettime,sys_timer_gettime,compat_sys_timer_gettime)
+SYSCALL(sys_timer_getoverrun,sys_timer_getoverrun,compat_sys_timer_getoverrun)
+SYSCALL(sys_timer_delete,sys_timer_delete,compat_sys_timer_delete)
+SYSCALL(sys_clock_settime,sys_clock_settime,compat_sys_clock_settime)
+SYSCALL(sys_clock_gettime,sys_clock_gettime,compat_sys_clock_gettime) /* 260 */
+SYSCALL(sys_clock_getres,sys_clock_getres,compat_sys_clock_getres)
+SYSCALL(sys_clock_nanosleep,sys_clock_nanosleep,compat_sys_clock_nanosleep)
NI_SYSCALL /* reserved for vserver */
-SYSCALL(sys_s390_fadvise64_64,sys_ni_syscall,sys32_fadvise64_64_wrapper)
-SYSCALL(sys_statfs64,sys_statfs64,compat_sys_statfs64_wrapper)
-SYSCALL(sys_fstatfs64,sys_fstatfs64,compat_sys_fstatfs64_wrapper)
-SYSCALL(sys_remap_file_pages,sys_remap_file_pages,sys32_remap_file_pages_wrapper)
+SYSCALL(sys_s390_fadvise64_64,sys_ni_syscall,compat_sys_s390_fadvise64_64)
+SYSCALL(sys_statfs64,sys_statfs64,compat_sys_statfs64)
+SYSCALL(sys_fstatfs64,sys_fstatfs64,compat_sys_fstatfs64)
+SYSCALL(sys_remap_file_pages,sys_remap_file_pages,compat_sys_remap_file_pages)
NI_SYSCALL /* 268 sys_mbind */
NI_SYSCALL /* 269 sys_get_mempolicy */
NI_SYSCALL /* 270 sys_set_mempolicy */
-SYSCALL(sys_mq_open,sys_mq_open,compat_sys_mq_open_wrapper)
-SYSCALL(sys_mq_unlink,sys_mq_unlink,sys32_mq_unlink_wrapper)
-SYSCALL(sys_mq_timedsend,sys_mq_timedsend,compat_sys_mq_timedsend_wrapper)
-SYSCALL(sys_mq_timedreceive,sys_mq_timedreceive,compat_sys_mq_timedreceive_wrapper)
-SYSCALL(sys_mq_notify,sys_mq_notify,compat_sys_mq_notify_wrapper) /* 275 */
-SYSCALL(sys_mq_getsetattr,sys_mq_getsetattr,compat_sys_mq_getsetattr_wrapper)
-SYSCALL(sys_kexec_load,sys_kexec_load,compat_sys_kexec_load_wrapper)
-SYSCALL(sys_add_key,sys_add_key,compat_sys_add_key_wrapper)
-SYSCALL(sys_request_key,sys_request_key,compat_sys_request_key_wrapper)
-SYSCALL(sys_keyctl,sys_keyctl,compat_sys_keyctl_wrapper) /* 280 */
+SYSCALL(sys_mq_open,sys_mq_open,compat_sys_mq_open)
+SYSCALL(sys_mq_unlink,sys_mq_unlink,compat_sys_mq_unlink)
+SYSCALL(sys_mq_timedsend,sys_mq_timedsend,compat_sys_mq_timedsend)
+SYSCALL(sys_mq_timedreceive,sys_mq_timedreceive,compat_sys_mq_timedreceive)
+SYSCALL(sys_mq_notify,sys_mq_notify,compat_sys_mq_notify) /* 275 */
+SYSCALL(sys_mq_getsetattr,sys_mq_getsetattr,compat_sys_mq_getsetattr)
+SYSCALL(sys_kexec_load,sys_kexec_load,compat_sys_kexec_load)
+SYSCALL(sys_add_key,sys_add_key,compat_sys_add_key)
+SYSCALL(sys_request_key,sys_request_key,compat_sys_request_key)
+SYSCALL(sys_keyctl,sys_keyctl,compat_sys_keyctl) /* 280 */
SYSCALL(sys_waitid,sys_waitid,compat_sys_waitid)
-SYSCALL(sys_ioprio_set,sys_ioprio_set,sys_ioprio_set_wrapper)
-SYSCALL(sys_ioprio_get,sys_ioprio_get,sys_ioprio_get_wrapper)
+SYSCALL(sys_ioprio_set,sys_ioprio_set,compat_sys_ioprio_set)
+SYSCALL(sys_ioprio_get,sys_ioprio_get,compat_sys_ioprio_get)
SYSCALL(sys_inotify_init,sys_inotify_init,sys_inotify_init)
-SYSCALL(sys_inotify_add_watch,sys_inotify_add_watch,sys_inotify_add_watch_wrapper) /* 285 */
-SYSCALL(sys_inotify_rm_watch,sys_inotify_rm_watch,sys_inotify_rm_watch_wrapper)
+SYSCALL(sys_inotify_add_watch,sys_inotify_add_watch,compat_sys_inotify_add_watch) /* 285 */
+SYSCALL(sys_inotify_rm_watch,sys_inotify_rm_watch,compat_sys_inotify_rm_watch)
NI_SYSCALL /* 287 sys_migrate_pages */
SYSCALL(sys_openat,sys_openat,compat_sys_openat)
-SYSCALL(sys_mkdirat,sys_mkdirat,sys_mkdirat_wrapper)
-SYSCALL(sys_mknodat,sys_mknodat,sys_mknodat_wrapper) /* 290 */
-SYSCALL(sys_fchownat,sys_fchownat,sys_fchownat_wrapper)
-SYSCALL(sys_futimesat,sys_futimesat,compat_sys_futimesat_wrapper)
-SYSCALL(sys_fstatat64,sys_newfstatat,sys32_fstatat64_wrapper)
-SYSCALL(sys_unlinkat,sys_unlinkat,sys_unlinkat_wrapper)
-SYSCALL(sys_renameat,sys_renameat,sys_renameat_wrapper) /* 295 */
-SYSCALL(sys_linkat,sys_linkat,sys_linkat_wrapper)
-SYSCALL(sys_symlinkat,sys_symlinkat,sys_symlinkat_wrapper)
-SYSCALL(sys_readlinkat,sys_readlinkat,sys_readlinkat_wrapper)
-SYSCALL(sys_fchmodat,sys_fchmodat,sys_fchmodat_wrapper)
-SYSCALL(sys_faccessat,sys_faccessat,sys_faccessat_wrapper) /* 300 */
-SYSCALL(sys_pselect6,sys_pselect6,compat_sys_pselect6_wrapper)
-SYSCALL(sys_ppoll,sys_ppoll,compat_sys_ppoll_wrapper)
-SYSCALL(sys_unshare,sys_unshare,sys_unshare_wrapper)
+SYSCALL(sys_mkdirat,sys_mkdirat,compat_sys_mkdirat)
+SYSCALL(sys_mknodat,sys_mknodat,compat_sys_mknodat) /* 290 */
+SYSCALL(sys_fchownat,sys_fchownat,compat_sys_fchownat)
+SYSCALL(sys_futimesat,sys_futimesat,compat_sys_futimesat)
+SYSCALL(sys_fstatat64,sys_newfstatat,compat_sys_s390_fstatat64)
+SYSCALL(sys_unlinkat,sys_unlinkat,compat_sys_unlinkat)
+SYSCALL(sys_renameat,sys_renameat,compat_sys_renameat) /* 295 */
+SYSCALL(sys_linkat,sys_linkat,compat_sys_linkat)
+SYSCALL(sys_symlinkat,sys_symlinkat,compat_sys_symlinkat)
+SYSCALL(sys_readlinkat,sys_readlinkat,compat_sys_readlinkat)
+SYSCALL(sys_fchmodat,sys_fchmodat,compat_sys_fchmodat)
+SYSCALL(sys_faccessat,sys_faccessat,compat_sys_faccessat) /* 300 */
+SYSCALL(sys_pselect6,sys_pselect6,compat_sys_pselect6)
+SYSCALL(sys_ppoll,sys_ppoll,compat_sys_ppoll)
+SYSCALL(sys_unshare,sys_unshare,compat_sys_unshare)
SYSCALL(sys_set_robust_list,sys_set_robust_list,compat_sys_set_robust_list)
SYSCALL(sys_get_robust_list,sys_get_robust_list,compat_sys_get_robust_list)
-SYSCALL(sys_splice,sys_splice,sys_splice_wrapper)
-SYSCALL(sys_sync_file_range,sys_sync_file_range,sys_sync_file_range_wrapper)
-SYSCALL(sys_tee,sys_tee,sys_tee_wrapper)
+SYSCALL(sys_splice,sys_splice,compat_sys_splice)
+SYSCALL(sys_sync_file_range,sys_sync_file_range,compat_sys_s390_sync_file_range)
+SYSCALL(sys_tee,sys_tee,compat_sys_tee)
SYSCALL(sys_vmsplice,sys_vmsplice,compat_sys_vmsplice)
NI_SYSCALL /* 310 sys_move_pages */
-SYSCALL(sys_getcpu,sys_getcpu,sys_getcpu_wrapper)
+SYSCALL(sys_getcpu,sys_getcpu,compat_sys_getcpu)
SYSCALL(sys_epoll_pwait,sys_epoll_pwait,compat_sys_epoll_pwait)
-SYSCALL(sys_utimes,sys_utimes,compat_sys_utimes_wrapper)
-SYSCALL(sys_s390_fallocate,sys_fallocate,sys_fallocate_wrapper)
-SYSCALL(sys_utimensat,sys_utimensat,compat_sys_utimensat_wrapper) /* 315 */
+SYSCALL(sys_utimes,sys_utimes,compat_sys_utimes)
+SYSCALL(sys_s390_fallocate,sys_fallocate,compat_sys_s390_fallocate)
+SYSCALL(sys_utimensat,sys_utimensat,compat_sys_utimensat) /* 315 */
SYSCALL(sys_signalfd,sys_signalfd,compat_sys_signalfd)
NI_SYSCALL /* 317 old sys_timer_fd */
-SYSCALL(sys_eventfd,sys_eventfd,sys_eventfd_wrapper)
-SYSCALL(sys_timerfd_create,sys_timerfd_create,sys_timerfd_create_wrapper)
+SYSCALL(sys_eventfd,sys_eventfd,compat_sys_eventfd)
+SYSCALL(sys_timerfd_create,sys_timerfd_create,compat_sys_timerfd_create)
SYSCALL(sys_timerfd_settime,sys_timerfd_settime,compat_sys_timerfd_settime) /* 320 */
SYSCALL(sys_timerfd_gettime,sys_timerfd_gettime,compat_sys_timerfd_gettime)
SYSCALL(sys_signalfd4,sys_signalfd4,compat_sys_signalfd4)
-SYSCALL(sys_eventfd2,sys_eventfd2,sys_eventfd2_wrapper)
-SYSCALL(sys_inotify_init1,sys_inotify_init1,sys_inotify_init1_wrapper)
-SYSCALL(sys_pipe2,sys_pipe2,sys_pipe2_wrapper) /* 325 */
-SYSCALL(sys_dup3,sys_dup3,sys_dup3_wrapper)
-SYSCALL(sys_epoll_create1,sys_epoll_create1,sys_epoll_create1_wrapper)
+SYSCALL(sys_eventfd2,sys_eventfd2,compat_sys_eventfd2)
+SYSCALL(sys_inotify_init1,sys_inotify_init1,compat_sys_inotify_init1)
+SYSCALL(sys_pipe2,sys_pipe2,compat_sys_pipe2) /* 325 */
+SYSCALL(sys_dup3,sys_dup3,compat_sys_dup3)
+SYSCALL(sys_epoll_create1,sys_epoll_create1,compat_sys_epoll_create1)
SYSCALL(sys_preadv,sys_preadv,compat_sys_preadv)
SYSCALL(sys_pwritev,sys_pwritev,compat_sys_pwritev)
SYSCALL(sys_rt_tgsigqueueinfo,sys_rt_tgsigqueueinfo,compat_sys_rt_tgsigqueueinfo) /* 330 */
-SYSCALL(sys_perf_event_open,sys_perf_event_open,sys_perf_event_open_wrapper)
-SYSCALL(sys_fanotify_init,sys_fanotify_init,sys_fanotify_init_wrapper)
+SYSCALL(sys_perf_event_open,sys_perf_event_open,compat_sys_perf_event_open)
+SYSCALL(sys_fanotify_init,sys_fanotify_init,compat_sys_fanotify_init)
SYSCALL(sys_fanotify_mark,sys_fanotify_mark,compat_sys_fanotify_mark)
-SYSCALL(sys_prlimit64,sys_prlimit64,sys_prlimit64_wrapper)
-SYSCALL(sys_name_to_handle_at,sys_name_to_handle_at,sys_name_to_handle_at_wrapper) /* 335 */
+SYSCALL(sys_prlimit64,sys_prlimit64,compat_sys_prlimit64)
+SYSCALL(sys_name_to_handle_at,sys_name_to_handle_at,compat_sys_name_to_handle_at) /* 335 */
SYSCALL(sys_open_by_handle_at,sys_open_by_handle_at,compat_sys_open_by_handle_at)
-SYSCALL(sys_clock_adjtime,sys_clock_adjtime,compat_sys_clock_adjtime_wrapper)
-SYSCALL(sys_syncfs,sys_syncfs,sys_syncfs_wrapper)
-SYSCALL(sys_setns,sys_setns,sys_setns_wrapper)
-SYSCALL(sys_process_vm_readv,sys_process_vm_readv,compat_sys_process_vm_readv_wrapper) /* 340 */
-SYSCALL(sys_process_vm_writev,sys_process_vm_writev,compat_sys_process_vm_writev_wrapper)
-SYSCALL(sys_ni_syscall,sys_s390_runtime_instr,sys_s390_runtime_instr_wrapper)
-SYSCALL(sys_kcmp,sys_kcmp,sys_kcmp_wrapper)
-SYSCALL(sys_finit_module,sys_finit_module,sys_finit_module_wrapper)
-SYSCALL(sys_sched_setattr,sys_sched_setattr,sys_sched_setattr_wrapper) /* 345 */
-SYSCALL(sys_sched_getattr,sys_sched_getattr,sys_sched_getattr_wrapper)
+SYSCALL(sys_clock_adjtime,sys_clock_adjtime,compat_sys_clock_adjtime)
+SYSCALL(sys_syncfs,sys_syncfs,compat_sys_syncfs)
+SYSCALL(sys_setns,sys_setns,compat_sys_setns)
+SYSCALL(sys_process_vm_readv,sys_process_vm_readv,compat_sys_process_vm_readv) /* 340 */
+SYSCALL(sys_process_vm_writev,sys_process_vm_writev,compat_sys_process_vm_writev)
+SYSCALL(sys_ni_syscall,sys_s390_runtime_instr,compat_sys_s390_runtime_instr)
+SYSCALL(sys_kcmp,sys_kcmp,compat_sys_kcmp)
+SYSCALL(sys_finit_module,sys_finit_module,compat_sys_finit_module)
+SYSCALL(sys_sched_setattr,sys_sched_setattr,compat_sys_sched_setattr) /* 345 */
+SYSCALL(sys_sched_getattr,sys_sched_getattr,compat_sys_sched_getattr)
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c
index 4b2e3e317004..6298fed11ced 100644
--- a/arch/s390/kernel/topology.c
+++ b/arch/s390/kernel/topology.c
@@ -451,7 +451,6 @@ static int __init topology_init(void)
}
set_topology_timer();
out:
- update_cpu_masks();
return device_create_file(cpu_subsys.dev_root, &dev_attr_dispatching);
}
device_initcall(topology_init);
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig
index 70b46eacf8e1..10d529ac9821 100644
--- a/arch/s390/kvm/Kconfig
+++ b/arch/s390/kvm/Kconfig
@@ -23,6 +23,10 @@ config KVM
select ANON_INODES
select HAVE_KVM_CPU_RELAX_INTERCEPT
select HAVE_KVM_EVENTFD
+ select KVM_ASYNC_PF
+ select KVM_ASYNC_PF_SYNC
+ select HAVE_KVM_IRQCHIP
+ select HAVE_KVM_IRQ_ROUTING
---help---
Support hosting paravirtualized guest machines using the SIE
virtualization capability on the mainframe. This should work
diff --git a/arch/s390/kvm/Makefile b/arch/s390/kvm/Makefile
index 40b4c6470f88..d3adb37e93a4 100644
--- a/arch/s390/kvm/Makefile
+++ b/arch/s390/kvm/Makefile
@@ -7,7 +7,7 @@
# as published by the Free Software Foundation.
KVM := ../../../virt/kvm
-common-objs = $(KVM)/kvm_main.o $(KVM)/eventfd.o
+common-objs = $(KVM)/kvm_main.o $(KVM)/eventfd.o $(KVM)/async_pf.o $(KVM)/irqchip.o
ccflags-y := -Ivirt/kvm -Iarch/s390/kvm
diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c
index 8216c0e0b2e2..03a05ffb662f 100644
--- a/arch/s390/kvm/diag.c
+++ b/arch/s390/kvm/diag.c
@@ -13,10 +13,12 @@
#include <linux/kvm.h>
#include <linux/kvm_host.h>
+#include <asm/pgalloc.h>
#include <asm/virtio-ccw.h>
#include "kvm-s390.h"
#include "trace.h"
#include "trace-s390.h"
+#include "gaccess.h"
static int diag_release_pages(struct kvm_vcpu *vcpu)
{
@@ -46,6 +48,87 @@ static int diag_release_pages(struct kvm_vcpu *vcpu)
return 0;
}
+static int __diag_page_ref_service(struct kvm_vcpu *vcpu)
+{
+ struct prs_parm {
+ u16 code;
+ u16 subcode;
+ u16 parm_len;
+ u16 parm_version;
+ u64 token_addr;
+ u64 select_mask;
+ u64 compare_mask;
+ u64 zarch;
+ };
+ struct prs_parm parm;
+ int rc;
+ u16 rx = (vcpu->arch.sie_block->ipa & 0xf0) >> 4;
+ u16 ry = (vcpu->arch.sie_block->ipa & 0x0f);
+ unsigned long hva_token = KVM_HVA_ERR_BAD;
+
+ if (vcpu->run->s.regs.gprs[rx] & 7)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+ if (copy_from_guest(vcpu, &parm, vcpu->run->s.regs.gprs[rx], sizeof(parm)))
+ return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+ if (parm.parm_version != 2 || parm.parm_len < 5 || parm.code != 0x258)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+ switch (parm.subcode) {
+ case 0: /* TOKEN */
+ if (vcpu->arch.pfault_token != KVM_S390_PFAULT_TOKEN_INVALID) {
+ /*
+ * If the pagefault handshake is already activated,
+ * the token must not be changed. We have to return
+ * decimal 8 instead, as mandated in SC24-6084.
+ */
+ vcpu->run->s.regs.gprs[ry] = 8;
+ return 0;
+ }
+
+ if ((parm.compare_mask & parm.select_mask) != parm.compare_mask ||
+ parm.token_addr & 7 || parm.zarch != 0x8000000000000000ULL)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+ hva_token = gfn_to_hva(vcpu->kvm, gpa_to_gfn(parm.token_addr));
+ if (kvm_is_error_hva(hva_token))
+ return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+
+ vcpu->arch.pfault_token = parm.token_addr;
+ vcpu->arch.pfault_select = parm.select_mask;
+ vcpu->arch.pfault_compare = parm.compare_mask;
+ vcpu->run->s.regs.gprs[ry] = 0;
+ rc = 0;
+ break;
+ case 1: /*
+ * CANCEL
+ * Specification allows to let already pending tokens survive
+ * the cancel, therefore to reduce code complexity, we assume
+ * all outstanding tokens are already pending.
+ */
+ if (parm.token_addr || parm.select_mask ||
+ parm.compare_mask || parm.zarch)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+ vcpu->run->s.regs.gprs[ry] = 0;
+ /*
+ * If the pfault handling was not established or is already
+ * canceled SC24-6084 requests to return decimal 4.
+ */
+ if (vcpu->arch.pfault_token == KVM_S390_PFAULT_TOKEN_INVALID)
+ vcpu->run->s.regs.gprs[ry] = 4;
+ else
+ vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
+
+ rc = 0;
+ break;
+ default:
+ rc = -EOPNOTSUPP;
+ break;
+ }
+
+ return rc;
+}
+
static int __diag_time_slice_end(struct kvm_vcpu *vcpu)
{
VCPU_EVENT(vcpu, 5, "%s", "diag time slice end");
@@ -86,9 +169,11 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu)
switch (subcode) {
case 3:
vcpu->run->s390_reset_flags = KVM_S390_RESET_CLEAR;
+ page_table_reset_pgste(current->mm, 0, TASK_SIZE);
break;
case 4:
vcpu->run->s390_reset_flags = 0;
+ page_table_reset_pgste(current->mm, 0, TASK_SIZE);
break;
default:
return -EOPNOTSUPP;
@@ -150,6 +235,8 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu)
return __diag_time_slice_end(vcpu);
case 0x9c:
return __diag_time_slice_end_directed(vcpu);
+ case 0x258:
+ return __diag_page_ref_service(vcpu);
case 0x308:
return __diag_ipl_functions(vcpu);
case 0x500:
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 5f79d2d79ca7..200a8f9390b6 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -1,7 +1,7 @@
/*
* handling kvm guest interrupts
*
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008,2014
*
* 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)
@@ -13,6 +13,7 @@
#include <linux/interrupt.h>
#include <linux/kvm_host.h>
#include <linux/hrtimer.h>
+#include <linux/mmu_context.h>
#include <linux/signal.h>
#include <linux/slab.h>
#include <asm/asm-offsets.h>
@@ -31,7 +32,7 @@ static int is_ioint(u64 type)
return ((type & 0xfffe0000u) != 0xfffe0000u);
}
-static int psw_extint_disabled(struct kvm_vcpu *vcpu)
+int psw_extint_disabled(struct kvm_vcpu *vcpu)
{
return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT);
}
@@ -78,11 +79,8 @@ static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu,
return 1;
return 0;
case KVM_S390_INT_SERVICE:
- if (psw_extint_disabled(vcpu))
- return 0;
- if (vcpu->arch.sie_block->gcr[0] & 0x200ul)
- return 1;
- return 0;
+ case KVM_S390_INT_PFAULT_INIT:
+ case KVM_S390_INT_PFAULT_DONE:
case KVM_S390_INT_VIRTIO:
if (psw_extint_disabled(vcpu))
return 0;
@@ -117,14 +115,12 @@ static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu,
static void __set_cpu_idle(struct kvm_vcpu *vcpu)
{
- BUG_ON(vcpu->vcpu_id > KVM_MAX_VCPUS - 1);
atomic_set_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags);
set_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask);
}
static void __unset_cpu_idle(struct kvm_vcpu *vcpu)
{
- BUG_ON(vcpu->vcpu_id > KVM_MAX_VCPUS - 1);
atomic_clear_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags);
clear_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask);
}
@@ -150,6 +146,8 @@ static void __set_intercept_indicator(struct kvm_vcpu *vcpu,
case KVM_S390_INT_EXTERNAL_CALL:
case KVM_S390_INT_EMERGENCY:
case KVM_S390_INT_SERVICE:
+ case KVM_S390_INT_PFAULT_INIT:
+ case KVM_S390_INT_PFAULT_DONE:
case KVM_S390_INT_VIRTIO:
if (psw_extint_disabled(vcpu))
__set_cpuflag(vcpu, CPUSTAT_EXT_INT);
@@ -223,6 +221,30 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
rc |= put_guest(vcpu, inti->ext.ext_params,
(u32 __user *)__LC_EXT_PARAMS);
break;
+ case KVM_S390_INT_PFAULT_INIT:
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, 0,
+ inti->ext.ext_params2);
+ rc = put_guest(vcpu, 0x2603, (u16 __user *) __LC_EXT_INT_CODE);
+ rc |= put_guest(vcpu, 0x0600, (u16 __user *) __LC_EXT_CPU_ADDR);
+ rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
+ __LC_EXT_NEW_PSW, sizeof(psw_t));
+ rc |= put_guest(vcpu, inti->ext.ext_params2,
+ (u64 __user *) __LC_EXT_PARAMS2);
+ break;
+ case KVM_S390_INT_PFAULT_DONE:
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, 0,
+ inti->ext.ext_params2);
+ rc = put_guest(vcpu, 0x2603, (u16 __user *) __LC_EXT_INT_CODE);
+ rc |= put_guest(vcpu, 0x0680, (u16 __user *) __LC_EXT_CPU_ADDR);
+ rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
+ __LC_EXT_NEW_PSW, sizeof(psw_t));
+ rc |= put_guest(vcpu, inti->ext.ext_params2,
+ (u64 __user *) __LC_EXT_PARAMS2);
+ break;
case KVM_S390_INT_VIRTIO:
VCPU_EVENT(vcpu, 4, "interrupt: virtio parm:%x,parm64:%llx",
inti->ext.ext_params, inti->ext.ext_params2);
@@ -357,7 +379,7 @@ static int __try_deliver_ckc_interrupt(struct kvm_vcpu *vcpu)
return 1;
}
-static int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
+int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
struct kvm_s390_float_interrupt *fi = vcpu->arch.local_int.float_int;
@@ -482,11 +504,26 @@ enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer)
struct kvm_vcpu *vcpu;
vcpu = container_of(timer, struct kvm_vcpu, arch.ckc_timer);
+ vcpu->preempted = true;
tasklet_schedule(&vcpu->arch.tasklet);
return HRTIMER_NORESTART;
}
+void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu)
+{
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+ struct kvm_s390_interrupt_info *n, *inti = NULL;
+
+ spin_lock_bh(&li->lock);
+ list_for_each_entry_safe(inti, n, &li->list, list) {
+ list_del(&inti->list);
+ kfree(inti);
+ }
+ atomic_set(&li->active, 0);
+ spin_unlock_bh(&li->lock);
+}
+
void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
@@ -528,6 +565,7 @@ void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
list_for_each_entry_safe(inti, n, &fi->list, list) {
if (__interrupt_is_deliverable(vcpu, inti)) {
list_del(&inti->list);
+ fi->irq_count--;
deliver = 1;
break;
}
@@ -583,6 +621,7 @@ void kvm_s390_deliver_pending_machine_checks(struct kvm_vcpu *vcpu)
if ((inti->type == KVM_S390_MCHK) &&
__interrupt_is_deliverable(vcpu, inti)) {
list_del(&inti->list);
+ fi->irq_count--;
deliver = 1;
break;
}
@@ -650,8 +689,10 @@ struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
inti = iter;
break;
}
- if (inti)
+ if (inti) {
list_del_init(&inti->list);
+ fi->irq_count--;
+ }
if (list_empty(&fi->list))
atomic_set(&fi->active, 0);
spin_unlock(&fi->lock);
@@ -659,53 +700,101 @@ struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
return inti;
}
-int kvm_s390_inject_vm(struct kvm *kvm,
- struct kvm_s390_interrupt *s390int)
+static int __inject_vm(struct kvm *kvm, struct kvm_s390_interrupt_info *inti)
{
struct kvm_s390_local_interrupt *li;
struct kvm_s390_float_interrupt *fi;
- struct kvm_s390_interrupt_info *inti, *iter;
+ struct kvm_s390_interrupt_info *iter;
+ struct kvm_vcpu *dst_vcpu = NULL;
int sigcpu;
+ int rc = 0;
+
+ mutex_lock(&kvm->lock);
+ fi = &kvm->arch.float_int;
+ spin_lock(&fi->lock);
+ if (fi->irq_count >= KVM_S390_MAX_FLOAT_IRQS) {
+ rc = -EINVAL;
+ goto unlock_fi;
+ }
+ fi->irq_count++;
+ if (!is_ioint(inti->type)) {
+ list_add_tail(&inti->list, &fi->list);
+ } else {
+ u64 isc_bits = int_word_to_isc_bits(inti->io.io_int_word);
+
+ /* Keep I/O interrupts sorted in isc order. */
+ list_for_each_entry(iter, &fi->list, list) {
+ if (!is_ioint(iter->type))
+ continue;
+ if (int_word_to_isc_bits(iter->io.io_int_word)
+ <= isc_bits)
+ continue;
+ break;
+ }
+ list_add_tail(&inti->list, &iter->list);
+ }
+ atomic_set(&fi->active, 1);
+ sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS);
+ if (sigcpu == KVM_MAX_VCPUS) {
+ do {
+ sigcpu = fi->next_rr_cpu++;
+ if (sigcpu == KVM_MAX_VCPUS)
+ sigcpu = fi->next_rr_cpu = 0;
+ } while (kvm_get_vcpu(kvm, sigcpu) == NULL);
+ }
+ dst_vcpu = kvm_get_vcpu(kvm, sigcpu);
+ li = &dst_vcpu->arch.local_int;
+ spin_lock_bh(&li->lock);
+ atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
+ if (waitqueue_active(li->wq))
+ wake_up_interruptible(li->wq);
+ kvm_get_vcpu(kvm, sigcpu)->preempted = true;
+ spin_unlock_bh(&li->lock);
+unlock_fi:
+ spin_unlock(&fi->lock);
+ mutex_unlock(&kvm->lock);
+ return rc;
+}
+
+int kvm_s390_inject_vm(struct kvm *kvm,
+ struct kvm_s390_interrupt *s390int)
+{
+ struct kvm_s390_interrupt_info *inti;
inti = kzalloc(sizeof(*inti), GFP_KERNEL);
if (!inti)
return -ENOMEM;
- switch (s390int->type) {
+ inti->type = s390int->type;
+ switch (inti->type) {
case KVM_S390_INT_VIRTIO:
VM_EVENT(kvm, 5, "inject: virtio parm:%x,parm64:%llx",
s390int->parm, s390int->parm64);
- inti->type = s390int->type;
inti->ext.ext_params = s390int->parm;
inti->ext.ext_params2 = s390int->parm64;
break;
case KVM_S390_INT_SERVICE:
VM_EVENT(kvm, 5, "inject: sclp parm:%x", s390int->parm);
- inti->type = s390int->type;
inti->ext.ext_params = s390int->parm;
break;
- case KVM_S390_PROGRAM_INT:
- case KVM_S390_SIGP_STOP:
- case KVM_S390_INT_EXTERNAL_CALL:
- case KVM_S390_INT_EMERGENCY:
- kfree(inti);
- return -EINVAL;
+ case KVM_S390_INT_PFAULT_DONE:
+ inti->type = s390int->type;
+ inti->ext.ext_params2 = s390int->parm64;
+ break;
case KVM_S390_MCHK:
VM_EVENT(kvm, 5, "inject: machine check parm64:%llx",
s390int->parm64);
- inti->type = s390int->type;
inti->mchk.cr14 = s390int->parm; /* upper bits are not used */
inti->mchk.mcic = s390int->parm64;
break;
case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
- if (s390int->type & IOINT_AI_MASK)
+ if (inti->type & IOINT_AI_MASK)
VM_EVENT(kvm, 5, "%s", "inject: I/O (AI)");
else
VM_EVENT(kvm, 5, "inject: I/O css %x ss %x schid %04x",
s390int->type & IOINT_CSSID_MASK,
s390int->type & IOINT_SSID_MASK,
s390int->type & IOINT_SCHID_MASK);
- inti->type = s390int->type;
inti->io.subchannel_id = s390int->parm >> 16;
inti->io.subchannel_nr = s390int->parm & 0x0000ffffu;
inti->io.io_int_parm = s390int->parm64 >> 32;
@@ -718,43 +807,7 @@ int kvm_s390_inject_vm(struct kvm *kvm,
trace_kvm_s390_inject_vm(s390int->type, s390int->parm, s390int->parm64,
2);
- mutex_lock(&kvm->lock);
- fi = &kvm->arch.float_int;
- spin_lock(&fi->lock);
- if (!is_ioint(inti->type))
- list_add_tail(&inti->list, &fi->list);
- else {
- u64 isc_bits = int_word_to_isc_bits(inti->io.io_int_word);
-
- /* Keep I/O interrupts sorted in isc order. */
- list_for_each_entry(iter, &fi->list, list) {
- if (!is_ioint(iter->type))
- continue;
- if (int_word_to_isc_bits(iter->io.io_int_word)
- <= isc_bits)
- continue;
- break;
- }
- list_add_tail(&inti->list, &iter->list);
- }
- atomic_set(&fi->active, 1);
- sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS);
- if (sigcpu == KVM_MAX_VCPUS) {
- do {
- sigcpu = fi->next_rr_cpu++;
- if (sigcpu == KVM_MAX_VCPUS)
- sigcpu = fi->next_rr_cpu = 0;
- } while (fi->local_int[sigcpu] == NULL);
- }
- li = fi->local_int[sigcpu];
- spin_lock_bh(&li->lock);
- atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
- if (waitqueue_active(li->wq))
- wake_up_interruptible(li->wq);
- spin_unlock_bh(&li->lock);
- spin_unlock(&fi->lock);
- mutex_unlock(&kvm->lock);
- return 0;
+ return __inject_vm(kvm, inti);
}
int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
@@ -814,6 +867,10 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
inti->type = s390int->type;
inti->mchk.mcic = s390int->parm64;
break;
+ case KVM_S390_INT_PFAULT_INIT:
+ inti->type = s390int->type;
+ inti->ext.ext_params2 = s390int->parm64;
+ break;
case KVM_S390_INT_VIRTIO:
case KVM_S390_INT_SERVICE:
case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
@@ -837,7 +894,528 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
if (waitqueue_active(&vcpu->wq))
wake_up_interruptible(&vcpu->wq);
+ vcpu->preempted = true;
spin_unlock_bh(&li->lock);
mutex_unlock(&vcpu->kvm->lock);
return 0;
}
+
+static void clear_floating_interrupts(struct kvm *kvm)
+{
+ struct kvm_s390_float_interrupt *fi;
+ struct kvm_s390_interrupt_info *n, *inti = NULL;
+
+ mutex_lock(&kvm->lock);
+ fi = &kvm->arch.float_int;
+ spin_lock(&fi->lock);
+ list_for_each_entry_safe(inti, n, &fi->list, list) {
+ list_del(&inti->list);
+ kfree(inti);
+ }
+ fi->irq_count = 0;
+ atomic_set(&fi->active, 0);
+ spin_unlock(&fi->lock);
+ mutex_unlock(&kvm->lock);
+}
+
+static inline int copy_irq_to_user(struct kvm_s390_interrupt_info *inti,
+ u8 *addr)
+{
+ struct kvm_s390_irq __user *uptr = (struct kvm_s390_irq __user *) addr;
+ struct kvm_s390_irq irq = {0};
+
+ irq.type = inti->type;
+ switch (inti->type) {
+ case KVM_S390_INT_PFAULT_INIT:
+ case KVM_S390_INT_PFAULT_DONE:
+ case KVM_S390_INT_VIRTIO:
+ case KVM_S390_INT_SERVICE:
+ irq.u.ext = inti->ext;
+ break;
+ case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
+ irq.u.io = inti->io;
+ break;
+ case KVM_S390_MCHK:
+ irq.u.mchk = inti->mchk;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (copy_to_user(uptr, &irq, sizeof(irq)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int get_all_floating_irqs(struct kvm *kvm, __u8 *buf, __u64 len)
+{
+ struct kvm_s390_interrupt_info *inti;
+ struct kvm_s390_float_interrupt *fi;
+ int ret = 0;
+ int n = 0;
+
+ mutex_lock(&kvm->lock);
+ fi = &kvm->arch.float_int;
+ spin_lock(&fi->lock);
+
+ list_for_each_entry(inti, &fi->list, list) {
+ if (len < sizeof(struct kvm_s390_irq)) {
+ /* signal userspace to try again */
+ ret = -ENOMEM;
+ break;
+ }
+ ret = copy_irq_to_user(inti, buf);
+ if (ret)
+ break;
+ buf += sizeof(struct kvm_s390_irq);
+ len -= sizeof(struct kvm_s390_irq);
+ n++;
+ }
+
+ spin_unlock(&fi->lock);
+ mutex_unlock(&kvm->lock);
+
+ return ret < 0 ? ret : n;
+}
+
+static int flic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
+{
+ int r;
+
+ switch (attr->group) {
+ case KVM_DEV_FLIC_GET_ALL_IRQS:
+ r = get_all_floating_irqs(dev->kvm, (u8 *) attr->addr,
+ attr->attr);
+ break;
+ default:
+ r = -EINVAL;
+ }
+
+ return r;
+}
+
+static inline int copy_irq_from_user(struct kvm_s390_interrupt_info *inti,
+ u64 addr)
+{
+ struct kvm_s390_irq __user *uptr = (struct kvm_s390_irq __user *) addr;
+ void *target = NULL;
+ void __user *source;
+ u64 size;
+
+ if (get_user(inti->type, (u64 __user *)addr))
+ return -EFAULT;
+
+ switch (inti->type) {
+ case KVM_S390_INT_PFAULT_INIT:
+ case KVM_S390_INT_PFAULT_DONE:
+ case KVM_S390_INT_VIRTIO:
+ case KVM_S390_INT_SERVICE:
+ target = (void *) &inti->ext;
+ source = &uptr->u.ext;
+ size = sizeof(inti->ext);
+ break;
+ case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
+ target = (void *) &inti->io;
+ source = &uptr->u.io;
+ size = sizeof(inti->io);
+ break;
+ case KVM_S390_MCHK:
+ target = (void *) &inti->mchk;
+ source = &uptr->u.mchk;
+ size = sizeof(inti->mchk);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (copy_from_user(target, source, size))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int enqueue_floating_irq(struct kvm_device *dev,
+ struct kvm_device_attr *attr)
+{
+ struct kvm_s390_interrupt_info *inti = NULL;
+ int r = 0;
+ int len = attr->attr;
+
+ if (len % sizeof(struct kvm_s390_irq) != 0)
+ return -EINVAL;
+ else if (len > KVM_S390_FLIC_MAX_BUFFER)
+ return -EINVAL;
+
+ while (len >= sizeof(struct kvm_s390_irq)) {
+ inti = kzalloc(sizeof(*inti), GFP_KERNEL);
+ if (!inti)
+ return -ENOMEM;
+
+ r = copy_irq_from_user(inti, attr->addr);
+ if (r) {
+ kfree(inti);
+ return r;
+ }
+ r = __inject_vm(dev->kvm, inti);
+ if (r) {
+ kfree(inti);
+ return r;
+ }
+ len -= sizeof(struct kvm_s390_irq);
+ attr->addr += sizeof(struct kvm_s390_irq);
+ }
+
+ return r;
+}
+
+static struct s390_io_adapter *get_io_adapter(struct kvm *kvm, unsigned int id)
+{
+ if (id >= MAX_S390_IO_ADAPTERS)
+ return NULL;
+ return kvm->arch.adapters[id];
+}
+
+static int register_io_adapter(struct kvm_device *dev,
+ struct kvm_device_attr *attr)
+{
+ struct s390_io_adapter *adapter;
+ struct kvm_s390_io_adapter adapter_info;
+
+ if (copy_from_user(&adapter_info,
+ (void __user *)attr->addr, sizeof(adapter_info)))
+ return -EFAULT;
+
+ if ((adapter_info.id >= MAX_S390_IO_ADAPTERS) ||
+ (dev->kvm->arch.adapters[adapter_info.id] != NULL))
+ return -EINVAL;
+
+ adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
+ if (!adapter)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&adapter->maps);
+ init_rwsem(&adapter->maps_lock);
+ atomic_set(&adapter->nr_maps, 0);
+ adapter->id = adapter_info.id;
+ adapter->isc = adapter_info.isc;
+ adapter->maskable = adapter_info.maskable;
+ adapter->masked = false;
+ adapter->swap = adapter_info.swap;
+ dev->kvm->arch.adapters[adapter->id] = adapter;
+
+ return 0;
+}
+
+int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked)
+{
+ int ret;
+ struct s390_io_adapter *adapter = get_io_adapter(kvm, id);
+
+ if (!adapter || !adapter->maskable)
+ return -EINVAL;
+ ret = adapter->masked;
+ adapter->masked = masked;
+ return ret;
+}
+
+static int kvm_s390_adapter_map(struct kvm *kvm, unsigned int id, __u64 addr)
+{
+ struct s390_io_adapter *adapter = get_io_adapter(kvm, id);
+ struct s390_map_info *map;
+ int ret;
+
+ if (!adapter || !addr)
+ return -EINVAL;
+
+ map = kzalloc(sizeof(*map), GFP_KERNEL);
+ if (!map) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ INIT_LIST_HEAD(&map->list);
+ map->guest_addr = addr;
+ map->addr = gmap_translate(addr, kvm->arch.gmap);
+ if (map->addr == -EFAULT) {
+ ret = -EFAULT;
+ goto out;
+ }
+ ret = get_user_pages_fast(map->addr, 1, 1, &map->page);
+ if (ret < 0)
+ goto out;
+ BUG_ON(ret != 1);
+ down_write(&adapter->maps_lock);
+ if (atomic_inc_return(&adapter->nr_maps) < MAX_S390_ADAPTER_MAPS) {
+ list_add_tail(&map->list, &adapter->maps);
+ ret = 0;
+ } else {
+ put_page(map->page);
+ ret = -EINVAL;
+ }
+ up_write(&adapter->maps_lock);
+out:
+ if (ret)
+ kfree(map);
+ return ret;
+}
+
+static int kvm_s390_adapter_unmap(struct kvm *kvm, unsigned int id, __u64 addr)
+{
+ struct s390_io_adapter *adapter = get_io_adapter(kvm, id);
+ struct s390_map_info *map, *tmp;
+ int found = 0;
+
+ if (!adapter || !addr)
+ return -EINVAL;
+
+ down_write(&adapter->maps_lock);
+ list_for_each_entry_safe(map, tmp, &adapter->maps, list) {
+ if (map->guest_addr == addr) {
+ found = 1;
+ atomic_dec(&adapter->nr_maps);
+ list_del(&map->list);
+ put_page(map->page);
+ kfree(map);
+ break;
+ }
+ }
+ up_write(&adapter->maps_lock);
+
+ return found ? 0 : -EINVAL;
+}
+
+void kvm_s390_destroy_adapters(struct kvm *kvm)
+{
+ int i;
+ struct s390_map_info *map, *tmp;
+
+ for (i = 0; i < MAX_S390_IO_ADAPTERS; i++) {
+ if (!kvm->arch.adapters[i])
+ continue;
+ list_for_each_entry_safe(map, tmp,
+ &kvm->arch.adapters[i]->maps, list) {
+ list_del(&map->list);
+ put_page(map->page);
+ kfree(map);
+ }
+ kfree(kvm->arch.adapters[i]);
+ }
+}
+
+static int modify_io_adapter(struct kvm_device *dev,
+ struct kvm_device_attr *attr)
+{
+ struct kvm_s390_io_adapter_req req;
+ struct s390_io_adapter *adapter;
+ int ret;
+
+ if (copy_from_user(&req, (void __user *)attr->addr, sizeof(req)))
+ return -EFAULT;
+
+ adapter = get_io_adapter(dev->kvm, req.id);
+ if (!adapter)
+ return -EINVAL;
+ switch (req.type) {
+ case KVM_S390_IO_ADAPTER_MASK:
+ ret = kvm_s390_mask_adapter(dev->kvm, req.id, req.mask);
+ if (ret > 0)
+ ret = 0;
+ break;
+ case KVM_S390_IO_ADAPTER_MAP:
+ ret = kvm_s390_adapter_map(dev->kvm, req.id, req.addr);
+ break;
+ case KVM_S390_IO_ADAPTER_UNMAP:
+ ret = kvm_s390_adapter_unmap(dev->kvm, req.id, req.addr);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
+{
+ int r = 0;
+ unsigned int i;
+ struct kvm_vcpu *vcpu;
+
+ switch (attr->group) {
+ case KVM_DEV_FLIC_ENQUEUE:
+ r = enqueue_floating_irq(dev, attr);
+ break;
+ case KVM_DEV_FLIC_CLEAR_IRQS:
+ r = 0;
+ clear_floating_interrupts(dev->kvm);
+ break;
+ case KVM_DEV_FLIC_APF_ENABLE:
+ dev->kvm->arch.gmap->pfault_enabled = 1;
+ break;
+ case KVM_DEV_FLIC_APF_DISABLE_WAIT:
+ dev->kvm->arch.gmap->pfault_enabled = 0;
+ /*
+ * Make sure no async faults are in transition when
+ * clearing the queues. So we don't need to worry
+ * about late coming workers.
+ */
+ synchronize_srcu(&dev->kvm->srcu);
+ kvm_for_each_vcpu(i, vcpu, dev->kvm)
+ kvm_clear_async_pf_completion_queue(vcpu);
+ break;
+ case KVM_DEV_FLIC_ADAPTER_REGISTER:
+ r = register_io_adapter(dev, attr);
+ break;
+ case KVM_DEV_FLIC_ADAPTER_MODIFY:
+ r = modify_io_adapter(dev, attr);
+ break;
+ default:
+ r = -EINVAL;
+ }
+
+ return r;
+}
+
+static int flic_create(struct kvm_device *dev, u32 type)
+{
+ if (!dev)
+ return -EINVAL;
+ if (dev->kvm->arch.flic)
+ return -EINVAL;
+ dev->kvm->arch.flic = dev;
+ return 0;
+}
+
+static void flic_destroy(struct kvm_device *dev)
+{
+ dev->kvm->arch.flic = NULL;
+ kfree(dev);
+}
+
+/* s390 floating irq controller (flic) */
+struct kvm_device_ops kvm_flic_ops = {
+ .name = "kvm-flic",
+ .get_attr = flic_get_attr,
+ .set_attr = flic_set_attr,
+ .create = flic_create,
+ .destroy = flic_destroy,
+};
+
+static unsigned long get_ind_bit(__u64 addr, unsigned long bit_nr, bool swap)
+{
+ unsigned long bit;
+
+ bit = bit_nr + (addr % PAGE_SIZE) * 8;
+
+ return swap ? (bit ^ (BITS_PER_LONG - 1)) : bit;
+}
+
+static struct s390_map_info *get_map_info(struct s390_io_adapter *adapter,
+ u64 addr)
+{
+ struct s390_map_info *map;
+
+ if (!adapter)
+ return NULL;
+
+ list_for_each_entry(map, &adapter->maps, list) {
+ if (map->guest_addr == addr)
+ return map;
+ }
+ return NULL;
+}
+
+static int adapter_indicators_set(struct kvm *kvm,
+ struct s390_io_adapter *adapter,
+ struct kvm_s390_adapter_int *adapter_int)
+{
+ unsigned long bit;
+ int summary_set, idx;
+ struct s390_map_info *info;
+ void *map;
+
+ info = get_map_info(adapter, adapter_int->ind_addr);
+ if (!info)
+ return -1;
+ map = page_address(info->page);
+ bit = get_ind_bit(info->addr, adapter_int->ind_offset, adapter->swap);
+ set_bit(bit, map);
+ idx = srcu_read_lock(&kvm->srcu);
+ mark_page_dirty(kvm, info->guest_addr >> PAGE_SHIFT);
+ set_page_dirty_lock(info->page);
+ info = get_map_info(adapter, adapter_int->summary_addr);
+ if (!info) {
+ srcu_read_unlock(&kvm->srcu, idx);
+ return -1;
+ }
+ map = page_address(info->page);
+ bit = get_ind_bit(info->addr, adapter_int->summary_offset,
+ adapter->swap);
+ summary_set = test_and_set_bit(bit, map);
+ mark_page_dirty(kvm, info->guest_addr >> PAGE_SHIFT);
+ set_page_dirty_lock(info->page);
+ srcu_read_unlock(&kvm->srcu, idx);
+ return summary_set ? 0 : 1;
+}
+
+/*
+ * < 0 - not injected due to error
+ * = 0 - coalesced, summary indicator already active
+ * > 0 - injected interrupt
+ */
+static int set_adapter_int(struct kvm_kernel_irq_routing_entry *e,
+ struct kvm *kvm, int irq_source_id, int level,
+ bool line_status)
+{
+ int ret;
+ struct s390_io_adapter *adapter;
+
+ /* We're only interested in the 0->1 transition. */
+ if (!level)
+ return 0;
+ adapter = get_io_adapter(kvm, e->adapter.adapter_id);
+ if (!adapter)
+ return -1;
+ down_read(&adapter->maps_lock);
+ ret = adapter_indicators_set(kvm, adapter, &e->adapter);
+ up_read(&adapter->maps_lock);
+ if ((ret > 0) && !adapter->masked) {
+ struct kvm_s390_interrupt s390int = {
+ .type = KVM_S390_INT_IO(1, 0, 0, 0),
+ .parm = 0,
+ .parm64 = (adapter->isc << 27) | 0x80000000,
+ };
+ ret = kvm_s390_inject_vm(kvm, &s390int);
+ if (ret == 0)
+ ret = 1;
+ }
+ return ret;
+}
+
+int kvm_set_routing_entry(struct kvm_irq_routing_table *rt,
+ struct kvm_kernel_irq_routing_entry *e,
+ const struct kvm_irq_routing_entry *ue)
+{
+ int ret;
+
+ switch (ue->type) {
+ case KVM_IRQ_ROUTING_S390_ADAPTER:
+ e->set = set_adapter_int;
+ e->adapter.summary_addr = ue->u.adapter.summary_addr;
+ e->adapter.ind_addr = ue->u.adapter.ind_addr;
+ e->adapter.summary_offset = ue->u.adapter.summary_offset;
+ e->adapter.ind_offset = ue->u.adapter.ind_offset;
+ e->adapter.adapter_id = ue->u.adapter.adapter_id;
+ ret = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm,
+ int irq_source_id, int level, bool line_status)
+{
+ return -EINVAL;
+}
diff --git a/arch/s390/kvm/irq.h b/arch/s390/kvm/irq.h
new file mode 100644
index 000000000000..d98e4159643d
--- /dev/null
+++ b/arch/s390/kvm/irq.h
@@ -0,0 +1,22 @@
+/*
+ * s390 irqchip routines
+ *
+ * Copyright IBM Corp. 2014
+ *
+ * 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.
+ *
+ * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
+ */
+#ifndef __KVM_IRQ_H
+#define __KVM_IRQ_H
+
+#include <linux/kvm_host.h>
+
+static inline int irqchip_in_kernel(struct kvm *kvm)
+{
+ return 1;
+}
+
+#endif
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index e0676f390d57..b3ecb8f5b6ce 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -68,6 +68,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
{ "instruction_storage_key", VCPU_STAT(instruction_storage_key) },
{ "instruction_stsch", VCPU_STAT(instruction_stsch) },
{ "instruction_chsc", VCPU_STAT(instruction_chsc) },
+ { "instruction_essa", VCPU_STAT(instruction_essa) },
{ "instruction_stsi", VCPU_STAT(instruction_stsi) },
{ "instruction_stfl", VCPU_STAT(instruction_stfl) },
{ "instruction_tprot", VCPU_STAT(instruction_tprot) },
@@ -152,11 +153,14 @@ int kvm_dev_ioctl_check_extension(long ext)
#ifdef CONFIG_KVM_S390_UCONTROL
case KVM_CAP_S390_UCONTROL:
#endif
+ case KVM_CAP_ASYNC_PF:
case KVM_CAP_SYNC_REGS:
case KVM_CAP_ONE_REG:
case KVM_CAP_ENABLE_CAP:
case KVM_CAP_S390_CSS_SUPPORT:
case KVM_CAP_IOEVENTFD:
+ case KVM_CAP_DEVICE_CTRL:
+ case KVM_CAP_ENABLE_CAP_VM:
r = 1;
break;
case KVM_CAP_NR_VCPUS:
@@ -185,6 +189,25 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
return 0;
}
+static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
+{
+ int r;
+
+ if (cap->flags)
+ return -EINVAL;
+
+ switch (cap->cap) {
+ case KVM_CAP_S390_IRQCHIP:
+ kvm->arch.use_irqchip = 1;
+ r = 0;
+ break;
+ default:
+ r = -EINVAL;
+ break;
+ }
+ return r;
+}
+
long kvm_arch_vm_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
@@ -202,6 +225,26 @@ long kvm_arch_vm_ioctl(struct file *filp,
r = kvm_s390_inject_vm(kvm, &s390int);
break;
}
+ case KVM_ENABLE_CAP: {
+ struct kvm_enable_cap cap;
+ r = -EFAULT;
+ if (copy_from_user(&cap, argp, sizeof(cap)))
+ break;
+ r = kvm_vm_ioctl_enable_cap(kvm, &cap);
+ break;
+ }
+ case KVM_CREATE_IRQCHIP: {
+ struct kvm_irq_routing_entry routing;
+
+ r = -EINVAL;
+ if (kvm->arch.use_irqchip) {
+ /* Set up dummy routing. */
+ memset(&routing, 0, sizeof(routing));
+ kvm_set_irq_routing(kvm, &routing, 0, 0);
+ r = 0;
+ }
+ break;
+ }
default:
r = -ENOTTY;
}
@@ -213,6 +256,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
{
int rc;
char debug_name[16];
+ static unsigned long sca_offset;
rc = -EINVAL;
#ifdef CONFIG_KVM_S390_UCONTROL
@@ -234,6 +278,10 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
kvm->arch.sca = (struct sca_block *) get_zeroed_page(GFP_KERNEL);
if (!kvm->arch.sca)
goto out_err;
+ spin_lock(&kvm_lock);
+ sca_offset = (sca_offset + 16) & 0x7f0;
+ kvm->arch.sca = (struct sca_block *) ((char *) kvm->arch.sca + sca_offset);
+ spin_unlock(&kvm_lock);
sprintf(debug_name, "kvm-%u", current->pid);
@@ -254,9 +302,11 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
if (!kvm->arch.gmap)
goto out_nogmap;
kvm->arch.gmap->private = kvm;
+ kvm->arch.gmap->pfault_enabled = 0;
}
kvm->arch.css_support = 0;
+ kvm->arch.use_irqchip = 0;
return 0;
out_nogmap:
@@ -271,6 +321,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
{
VCPU_EVENT(vcpu, 3, "%s", "free cpu");
trace_kvm_s390_destroy_vcpu(vcpu->vcpu_id);
+ kvm_clear_async_pf_completion_queue(vcpu);
if (!kvm_is_ucontrol(vcpu->kvm)) {
clear_bit(63 - vcpu->vcpu_id,
(unsigned long *) &vcpu->kvm->arch.sca->mcn);
@@ -283,7 +334,11 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
if (kvm_is_ucontrol(vcpu->kvm))
gmap_free(vcpu->arch.gmap);
+ if (vcpu->arch.sie_block->cbrlo)
+ __free_page(__pfn_to_page(
+ vcpu->arch.sie_block->cbrlo >> PAGE_SHIFT));
free_page((unsigned long)(vcpu->arch.sie_block));
+
kvm_vcpu_uninit(vcpu);
kmem_cache_free(kvm_vcpu_cache, vcpu);
}
@@ -315,11 +370,14 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
debug_unregister(kvm->arch.dbf);
if (!kvm_is_ucontrol(kvm))
gmap_free(kvm->arch.gmap);
+ kvm_s390_destroy_adapters(kvm);
}
/* Section: vcpu related */
int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
{
+ vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
+ kvm_clear_async_pf_completion_queue(vcpu);
if (kvm_is_ucontrol(vcpu->kvm)) {
vcpu->arch.gmap = gmap_alloc(current->mm);
if (!vcpu->arch.gmap)
@@ -380,7 +438,11 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
vcpu->arch.guest_fpregs.fpc = 0;
asm volatile("lfpc %0" : : "Q" (vcpu->arch.guest_fpregs.fpc));
vcpu->arch.sie_block->gbea = 1;
+ vcpu->arch.sie_block->pp = 0;
+ vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
+ kvm_clear_async_pf_completion_queue(vcpu);
atomic_set_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags);
+ kvm_s390_clear_local_irqs(vcpu);
}
int kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
@@ -390,6 +452,8 @@ int kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
{
+ struct page *cbrl;
+
atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH |
CPUSTAT_SM |
CPUSTAT_STOPPED |
@@ -401,6 +465,14 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
vcpu->arch.sie_block->ecb2 = 8;
vcpu->arch.sie_block->eca = 0xC1002001U;
vcpu->arch.sie_block->fac = (int) (long) vfacilities;
+ if (kvm_enabled_cmma()) {
+ cbrl = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (cbrl) {
+ vcpu->arch.sie_block->ecb2 |= 0x80;
+ vcpu->arch.sie_block->ecb2 &= ~0x08;
+ vcpu->arch.sie_block->cbrlo = page_to_phys(cbrl);
+ }
+ }
hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
tasklet_init(&vcpu->arch.tasklet, kvm_s390_tasklet,
(unsigned long) vcpu);
@@ -451,11 +523,8 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
spin_lock_init(&vcpu->arch.local_int.lock);
INIT_LIST_HEAD(&vcpu->arch.local_int.list);
vcpu->arch.local_int.float_int = &kvm->arch.float_int;
- spin_lock(&kvm->arch.float_int.lock);
- kvm->arch.float_int.local_int[id] = &vcpu->arch.local_int;
vcpu->arch.local_int.wq = &vcpu->wq;
vcpu->arch.local_int.cpuflags = &vcpu->arch.sie_block->cpuflags;
- spin_unlock(&kvm->arch.float_int.lock);
rc = kvm_vcpu_init(vcpu, kvm, id);
if (rc)
@@ -475,9 +544,7 @@ out:
int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
{
- /* kvm common code refers to this, but never calls it */
- BUG();
- return 0;
+ return kvm_cpu_has_interrupt(vcpu);
}
void s390_vcpu_block(struct kvm_vcpu *vcpu)
@@ -553,6 +620,26 @@ static int kvm_arch_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu,
r = put_user(vcpu->arch.sie_block->ckc,
(u64 __user *)reg->addr);
break;
+ case KVM_REG_S390_PFTOKEN:
+ r = put_user(vcpu->arch.pfault_token,
+ (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_S390_PFCOMPARE:
+ r = put_user(vcpu->arch.pfault_compare,
+ (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_S390_PFSELECT:
+ r = put_user(vcpu->arch.pfault_select,
+ (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_S390_PP:
+ r = put_user(vcpu->arch.sie_block->pp,
+ (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_S390_GBEA:
+ r = put_user(vcpu->arch.sie_block->gbea,
+ (u64 __user *)reg->addr);
+ break;
default:
break;
}
@@ -582,6 +669,26 @@ static int kvm_arch_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu,
r = get_user(vcpu->arch.sie_block->ckc,
(u64 __user *)reg->addr);
break;
+ case KVM_REG_S390_PFTOKEN:
+ r = get_user(vcpu->arch.pfault_token,
+ (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_S390_PFCOMPARE:
+ r = get_user(vcpu->arch.pfault_compare,
+ (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_S390_PFSELECT:
+ r = get_user(vcpu->arch.pfault_select,
+ (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_S390_PP:
+ r = get_user(vcpu->arch.sie_block->pp,
+ (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_S390_GBEA:
+ r = get_user(vcpu->arch.sie_block->gbea,
+ (u64 __user *)reg->addr);
+ break;
default:
break;
}
@@ -700,10 +807,100 @@ static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
return 0;
}
+static long kvm_arch_fault_in_sync(struct kvm_vcpu *vcpu)
+{
+ long rc;
+ hva_t fault = gmap_fault(current->thread.gmap_addr, vcpu->arch.gmap);
+ struct mm_struct *mm = current->mm;
+ down_read(&mm->mmap_sem);
+ rc = get_user_pages(current, mm, fault, 1, 1, 0, NULL, NULL);
+ up_read(&mm->mmap_sem);
+ return rc;
+}
+
+static void __kvm_inject_pfault_token(struct kvm_vcpu *vcpu, bool start_token,
+ unsigned long token)
+{
+ struct kvm_s390_interrupt inti;
+ inti.parm64 = token;
+
+ if (start_token) {
+ inti.type = KVM_S390_INT_PFAULT_INIT;
+ WARN_ON_ONCE(kvm_s390_inject_vcpu(vcpu, &inti));
+ } else {
+ inti.type = KVM_S390_INT_PFAULT_DONE;
+ WARN_ON_ONCE(kvm_s390_inject_vm(vcpu->kvm, &inti));
+ }
+}
+
+void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work)
+{
+ trace_kvm_s390_pfault_init(vcpu, work->arch.pfault_token);
+ __kvm_inject_pfault_token(vcpu, true, work->arch.pfault_token);
+}
+
+void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work)
+{
+ trace_kvm_s390_pfault_done(vcpu, work->arch.pfault_token);
+ __kvm_inject_pfault_token(vcpu, false, work->arch.pfault_token);
+}
+
+void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work)
+{
+ /* s390 will always inject the page directly */
+}
+
+bool kvm_arch_can_inject_async_page_present(struct kvm_vcpu *vcpu)
+{
+ /*
+ * s390 will always inject the page directly,
+ * but we still want check_async_completion to cleanup
+ */
+ return true;
+}
+
+static int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu)
+{
+ hva_t hva;
+ struct kvm_arch_async_pf arch;
+ int rc;
+
+ if (vcpu->arch.pfault_token == KVM_S390_PFAULT_TOKEN_INVALID)
+ return 0;
+ if ((vcpu->arch.sie_block->gpsw.mask & vcpu->arch.pfault_select) !=
+ vcpu->arch.pfault_compare)
+ return 0;
+ if (psw_extint_disabled(vcpu))
+ return 0;
+ if (kvm_cpu_has_interrupt(vcpu))
+ return 0;
+ if (!(vcpu->arch.sie_block->gcr[0] & 0x200ul))
+ return 0;
+ if (!vcpu->arch.gmap->pfault_enabled)
+ return 0;
+
+ hva = gmap_fault(current->thread.gmap_addr, vcpu->arch.gmap);
+ if (copy_from_guest(vcpu, &arch.pfault_token, vcpu->arch.pfault_token, 8))
+ return 0;
+
+ rc = kvm_setup_async_pf(vcpu, current->thread.gmap_addr, hva, &arch);
+ return rc;
+}
+
static int vcpu_pre_run(struct kvm_vcpu *vcpu)
{
int rc, cpuflags;
+ /*
+ * On s390 notifications for arriving pages will be delivered directly
+ * to the guest but the house keeping for completed pfaults is
+ * handled outside the worker.
+ */
+ kvm_check_async_pf_completion(vcpu);
+
memcpy(&vcpu->arch.sie_block->gg14, &vcpu->run->s.regs.gprs[14], 16);
if (need_resched())
@@ -729,7 +926,7 @@ static int vcpu_pre_run(struct kvm_vcpu *vcpu)
static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
{
- int rc;
+ int rc = -1;
VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
vcpu->arch.sie_block->icptcode);
@@ -743,7 +940,16 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
current->thread.gmap_addr;
vcpu->run->s390_ucontrol.pgm_code = 0x10;
rc = -EREMOTE;
- } else {
+
+ } else if (current->thread.gmap_pfault) {
+ trace_kvm_s390_major_guest_pfault(vcpu);
+ current->thread.gmap_pfault = 0;
+ if (kvm_arch_setup_async_pf(vcpu) ||
+ (kvm_arch_fault_in_sync(vcpu) >= 0))
+ rc = 0;
+ }
+
+ if (rc == -1) {
VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction");
trace_kvm_s390_sie_fault(vcpu);
rc = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
@@ -753,7 +959,8 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
if (rc == 0) {
if (kvm_is_ucontrol(vcpu->kvm))
- rc = -EOPNOTSUPP;
+ /* Don't exit for host interrupts. */
+ rc = vcpu->arch.sie_block->icptcode ? -EOPNOTSUPP : 0;
else
rc = kvm_handle_sie_intercept(vcpu);
}
@@ -761,6 +968,16 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
return rc;
}
+bool kvm_enabled_cmma(void)
+{
+ if (!MACHINE_IS_LPAR)
+ return false;
+ /* only enable for z10 and later */
+ if (!MACHINE_HAS_EDAT1)
+ return false;
+ return true;
+}
+
static int __vcpu_run(struct kvm_vcpu *vcpu)
{
int rc, exit_reason;
@@ -806,8 +1023,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
atomic_clear_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags);
- BUG_ON(vcpu->kvm->arch.float_int.local_int[vcpu->vcpu_id] == NULL);
-
switch (kvm_run->exit_reason) {
case KVM_EXIT_S390_SIEIC:
case KVM_EXIT_UNKNOWN:
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index f9559b0bd620..3c1e2274d9ea 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -129,6 +129,7 @@ enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer);
void kvm_s390_tasklet(unsigned long parm);
void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu);
void kvm_s390_deliver_pending_machine_checks(struct kvm_vcpu *vcpu);
+void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu);
int __must_check kvm_s390_inject_vm(struct kvm *kvm,
struct kvm_s390_interrupt *s390int);
int __must_check kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
@@ -136,6 +137,7 @@ int __must_check kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
int __must_check kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code);
struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
u64 cr6, u64 schid);
+int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked);
/* implemented in priv.c */
int kvm_s390_handle_b2(struct kvm_vcpu *vcpu);
@@ -156,7 +158,14 @@ void s390_vcpu_block(struct kvm_vcpu *vcpu);
void s390_vcpu_unblock(struct kvm_vcpu *vcpu);
void exit_sie(struct kvm_vcpu *vcpu);
void exit_sie_sync(struct kvm_vcpu *vcpu);
+/* are we going to support cmma? */
+bool kvm_enabled_cmma(void);
/* implemented in diag.c */
int kvm_s390_handle_diag(struct kvm_vcpu *vcpu);
+/* implemented in interrupt.c */
+int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu);
+int psw_extint_disabled(struct kvm_vcpu *vcpu);
+void kvm_s390_destroy_adapters(struct kvm *kvm);
+
#endif
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 75beea632a10..476e9e218f43 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -396,15 +396,10 @@ static int handle_stidp(struct kvm_vcpu *vcpu)
static void handle_stsi_3_2_2(struct kvm_vcpu *vcpu, struct sysinfo_3_2_2 *mem)
{
- struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
int cpus = 0;
int n;
- spin_lock(&fi->lock);
- for (n = 0; n < KVM_MAX_VCPUS; n++)
- if (fi->local_int[n])
- cpus++;
- spin_unlock(&fi->lock);
+ cpus = atomic_read(&vcpu->kvm->online_vcpus);
/* deal with other level 3 hypervisors */
if (stsi(mem, 3, 2, 2))
@@ -636,8 +631,49 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
return 0;
}
+static int handle_essa(struct kvm_vcpu *vcpu)
+{
+ /* entries expected to be 1FF */
+ int entries = (vcpu->arch.sie_block->cbrlo & ~PAGE_MASK) >> 3;
+ unsigned long *cbrlo, cbrle;
+ struct gmap *gmap;
+ int i;
+
+ VCPU_EVENT(vcpu, 5, "cmma release %d pages", entries);
+ gmap = vcpu->arch.gmap;
+ vcpu->stat.instruction_essa++;
+ if (!kvm_enabled_cmma() || !vcpu->arch.sie_block->cbrlo)
+ return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
+
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
+ if (((vcpu->arch.sie_block->ipb & 0xf0000000) >> 28) > 6)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+ /* Rewind PSW to repeat the ESSA instruction */
+ vcpu->arch.sie_block->gpsw.addr =
+ __rewind_psw(vcpu->arch.sie_block->gpsw, 4);
+ vcpu->arch.sie_block->cbrlo &= PAGE_MASK; /* reset nceo */
+ cbrlo = phys_to_virt(vcpu->arch.sie_block->cbrlo);
+ down_read(&gmap->mm->mmap_sem);
+ for (i = 0; i < entries; ++i) {
+ cbrle = cbrlo[i];
+ if (unlikely(cbrle & ~PAGE_MASK || cbrle < 2 * PAGE_SIZE))
+ /* invalid entry */
+ break;
+ /* try to free backing */
+ __gmap_zap(cbrle, gmap);
+ }
+ up_read(&gmap->mm->mmap_sem);
+ if (i < entries)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+ return 0;
+}
+
static const intercept_handler_t b9_handlers[256] = {
[0x8d] = handle_epsw,
+ [0xab] = handle_essa,
[0xaf] = handle_pfmf,
};
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c
index 87c2b3a3bd3e..26caeb530a78 100644
--- a/arch/s390/kvm/sigp.c
+++ b/arch/s390/kvm/sigp.c
@@ -23,29 +23,30 @@
static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
u64 *reg)
{
- struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
+ struct kvm_s390_local_interrupt *li;
+ struct kvm_vcpu *dst_vcpu = NULL;
+ int cpuflags;
int rc;
if (cpu_addr >= KVM_MAX_VCPUS)
return SIGP_CC_NOT_OPERATIONAL;
- spin_lock(&fi->lock);
- if (fi->local_int[cpu_addr] == NULL)
- rc = SIGP_CC_NOT_OPERATIONAL;
- else if (!(atomic_read(fi->local_int[cpu_addr]->cpuflags)
- & (CPUSTAT_ECALL_PEND | CPUSTAT_STOPPED)))
+ dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
+ if (!dst_vcpu)
+ return SIGP_CC_NOT_OPERATIONAL;
+ li = &dst_vcpu->arch.local_int;
+
+ cpuflags = atomic_read(li->cpuflags);
+ if (!(cpuflags & (CPUSTAT_ECALL_PEND | CPUSTAT_STOPPED)))
rc = SIGP_CC_ORDER_CODE_ACCEPTED;
else {
*reg &= 0xffffffff00000000UL;
- if (atomic_read(fi->local_int[cpu_addr]->cpuflags)
- & CPUSTAT_ECALL_PEND)
+ if (cpuflags & CPUSTAT_ECALL_PEND)
*reg |= SIGP_STATUS_EXT_CALL_PENDING;
- if (atomic_read(fi->local_int[cpu_addr]->cpuflags)
- & CPUSTAT_STOPPED)
+ if (cpuflags & CPUSTAT_STOPPED)
*reg |= SIGP_STATUS_STOPPED;
rc = SIGP_CC_STATUS_STORED;
}
- spin_unlock(&fi->lock);
VCPU_EVENT(vcpu, 4, "sensed status of cpu %x rc %x", cpu_addr, rc);
return rc;
@@ -53,12 +54,13 @@ static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr)
{
- struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
struct kvm_s390_local_interrupt *li;
struct kvm_s390_interrupt_info *inti;
- int rc;
+ struct kvm_vcpu *dst_vcpu = NULL;
- if (cpu_addr >= KVM_MAX_VCPUS)
+ if (cpu_addr < KVM_MAX_VCPUS)
+ dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
+ if (!dst_vcpu)
return SIGP_CC_NOT_OPERATIONAL;
inti = kzalloc(sizeof(*inti), GFP_KERNEL);
@@ -68,13 +70,7 @@ static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr)
inti->type = KVM_S390_INT_EMERGENCY;
inti->emerg.code = vcpu->vcpu_id;
- spin_lock(&fi->lock);
- li = fi->local_int[cpu_addr];
- if (li == NULL) {
- rc = SIGP_CC_NOT_OPERATIONAL;
- kfree(inti);
- goto unlock;
- }
+ li = &dst_vcpu->arch.local_int;
spin_lock_bh(&li->lock);
list_add_tail(&inti->list, &li->list);
atomic_set(&li->active, 1);
@@ -82,11 +78,9 @@ static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr)
if (waitqueue_active(li->wq))
wake_up_interruptible(li->wq);
spin_unlock_bh(&li->lock);
- rc = SIGP_CC_ORDER_CODE_ACCEPTED;
VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr);
-unlock:
- spin_unlock(&fi->lock);
- return rc;
+
+ return SIGP_CC_ORDER_CODE_ACCEPTED;
}
static int __sigp_conditional_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr,
@@ -122,12 +116,13 @@ static int __sigp_conditional_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr,
static int __sigp_external_call(struct kvm_vcpu *vcpu, u16 cpu_addr)
{
- struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
struct kvm_s390_local_interrupt *li;
struct kvm_s390_interrupt_info *inti;
- int rc;
+ struct kvm_vcpu *dst_vcpu = NULL;
- if (cpu_addr >= KVM_MAX_VCPUS)
+ if (cpu_addr < KVM_MAX_VCPUS)
+ dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
+ if (!dst_vcpu)
return SIGP_CC_NOT_OPERATIONAL;
inti = kzalloc(sizeof(*inti), GFP_KERNEL);
@@ -137,13 +132,7 @@ static int __sigp_external_call(struct kvm_vcpu *vcpu, u16 cpu_addr)
inti->type = KVM_S390_INT_EXTERNAL_CALL;
inti->extcall.code = vcpu->vcpu_id;
- spin_lock(&fi->lock);
- li = fi->local_int[cpu_addr];
- if (li == NULL) {
- rc = SIGP_CC_NOT_OPERATIONAL;
- kfree(inti);
- goto unlock;
- }
+ li = &dst_vcpu->arch.local_int;
spin_lock_bh(&li->lock);
list_add_tail(&inti->list, &li->list);
atomic_set(&li->active, 1);
@@ -151,11 +140,9 @@ static int __sigp_external_call(struct kvm_vcpu *vcpu, u16 cpu_addr)
if (waitqueue_active(li->wq))
wake_up_interruptible(li->wq);
spin_unlock_bh(&li->lock);
- rc = SIGP_CC_ORDER_CODE_ACCEPTED;
VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x", cpu_addr);
-unlock:
- spin_unlock(&fi->lock);
- return rc;
+
+ return SIGP_CC_ORDER_CODE_ACCEPTED;
}
static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, int action)
@@ -189,31 +176,26 @@ out:
static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int action)
{
- struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
struct kvm_s390_local_interrupt *li;
+ struct kvm_vcpu *dst_vcpu = NULL;
int rc;
if (cpu_addr >= KVM_MAX_VCPUS)
return SIGP_CC_NOT_OPERATIONAL;
- spin_lock(&fi->lock);
- li = fi->local_int[cpu_addr];
- if (li == NULL) {
- rc = SIGP_CC_NOT_OPERATIONAL;
- goto unlock;
- }
+ dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
+ if (!dst_vcpu)
+ return SIGP_CC_NOT_OPERATIONAL;
+ li = &dst_vcpu->arch.local_int;
rc = __inject_sigp_stop(li, action);
-unlock:
- spin_unlock(&fi->lock);
VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", cpu_addr);
if ((action & ACTION_STORE_ON_STOP) != 0 && rc == -ESHUTDOWN) {
/* If the CPU has already been stopped, we still have
* to save the status when doing stop-and-store. This
* has to be done after unlocking all spinlocks. */
- struct kvm_vcpu *dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
rc = kvm_s390_store_status_unloaded(dst_vcpu,
KVM_S390_STORE_STATUS_NOADDR);
}
@@ -224,6 +206,8 @@ unlock:
static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter)
{
int rc;
+ unsigned int i;
+ struct kvm_vcpu *v;
switch (parameter & 0xff) {
case 0:
@@ -231,6 +215,11 @@ static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter)
break;
case 1:
case 2:
+ kvm_for_each_vcpu(i, v, vcpu->kvm) {
+ v->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
+ kvm_clear_async_pf_completion_queue(v);
+ }
+
rc = SIGP_CC_ORDER_CODE_ACCEPTED;
break;
default:
@@ -242,12 +231,18 @@ static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter)
static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
u64 *reg)
{
- struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
- struct kvm_s390_local_interrupt *li = NULL;
+ struct kvm_s390_local_interrupt *li;
+ struct kvm_vcpu *dst_vcpu = NULL;
struct kvm_s390_interrupt_info *inti;
int rc;
u8 tmp;
+ if (cpu_addr < KVM_MAX_VCPUS)
+ dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
+ if (!dst_vcpu)
+ return SIGP_CC_NOT_OPERATIONAL;
+ li = &dst_vcpu->arch.local_int;
+
/* make sure that the new value is valid memory */
address = address & 0x7fffe000u;
if (copy_from_guest_absolute(vcpu, &tmp, address, 1) ||
@@ -261,18 +256,6 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
if (!inti)
return SIGP_CC_BUSY;
- spin_lock(&fi->lock);
- if (cpu_addr < KVM_MAX_VCPUS)
- li = fi->local_int[cpu_addr];
-
- if (li == NULL) {
- *reg &= 0xffffffff00000000UL;
- *reg |= SIGP_STATUS_INCORRECT_STATE;
- rc = SIGP_CC_STATUS_STORED;
- kfree(inti);
- goto out_fi;
- }
-
spin_lock_bh(&li->lock);
/* cpu must be in stopped state */
if (!(atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) {
@@ -295,8 +278,6 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
VCPU_EVENT(vcpu, 4, "set prefix of cpu %02x to %x", cpu_addr, address);
out_li:
spin_unlock_bh(&li->lock);
-out_fi:
- spin_unlock(&fi->lock);
return rc;
}
@@ -334,28 +315,26 @@ static int __sigp_store_status_at_addr(struct kvm_vcpu *vcpu, u16 cpu_id,
static int __sigp_sense_running(struct kvm_vcpu *vcpu, u16 cpu_addr,
u64 *reg)
{
+ struct kvm_s390_local_interrupt *li;
+ struct kvm_vcpu *dst_vcpu = NULL;
int rc;
- struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
if (cpu_addr >= KVM_MAX_VCPUS)
return SIGP_CC_NOT_OPERATIONAL;
- spin_lock(&fi->lock);
- if (fi->local_int[cpu_addr] == NULL)
- rc = SIGP_CC_NOT_OPERATIONAL;
- else {
- if (atomic_read(fi->local_int[cpu_addr]->cpuflags)
- & CPUSTAT_RUNNING) {
- /* running */
- rc = SIGP_CC_ORDER_CODE_ACCEPTED;
- } else {
- /* not running */
- *reg &= 0xffffffff00000000UL;
- *reg |= SIGP_STATUS_NOT_RUNNING;
- rc = SIGP_CC_STATUS_STORED;
- }
+ dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
+ if (!dst_vcpu)
+ return SIGP_CC_NOT_OPERATIONAL;
+ li = &dst_vcpu->arch.local_int;
+ if (atomic_read(li->cpuflags) & CPUSTAT_RUNNING) {
+ /* running */
+ rc = SIGP_CC_ORDER_CODE_ACCEPTED;
+ } else {
+ /* not running */
+ *reg &= 0xffffffff00000000UL;
+ *reg |= SIGP_STATUS_NOT_RUNNING;
+ rc = SIGP_CC_STATUS_STORED;
}
- spin_unlock(&fi->lock);
VCPU_EVENT(vcpu, 4, "sensed running status of cpu %x rc %x", cpu_addr,
rc);
@@ -366,26 +345,22 @@ static int __sigp_sense_running(struct kvm_vcpu *vcpu, u16 cpu_addr,
/* Test whether the destination CPU is available and not busy */
static int sigp_check_callable(struct kvm_vcpu *vcpu, u16 cpu_addr)
{
- struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
struct kvm_s390_local_interrupt *li;
int rc = SIGP_CC_ORDER_CODE_ACCEPTED;
+ struct kvm_vcpu *dst_vcpu = NULL;
if (cpu_addr >= KVM_MAX_VCPUS)
return SIGP_CC_NOT_OPERATIONAL;
- spin_lock(&fi->lock);
- li = fi->local_int[cpu_addr];
- if (li == NULL) {
- rc = SIGP_CC_NOT_OPERATIONAL;
- goto out;
- }
-
+ dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
+ if (!dst_vcpu)
+ return SIGP_CC_NOT_OPERATIONAL;
+ li = &dst_vcpu->arch.local_int;
spin_lock_bh(&li->lock);
if (li->action_bits & ACTION_STOP_ON_STOP)
rc = SIGP_CC_BUSY;
spin_unlock_bh(&li->lock);
-out:
- spin_unlock(&fi->lock);
+
return rc;
}
diff --git a/arch/s390/kvm/trace.h b/arch/s390/kvm/trace.h
index 3db76b2daed7..e8e7213d4cc5 100644
--- a/arch/s390/kvm/trace.h
+++ b/arch/s390/kvm/trace.h
@@ -30,6 +30,52 @@
TP_printk("%02d[%016lx-%016lx]: " p_str, __entry->id, \
__entry->pswmask, __entry->pswaddr, p_args)
+TRACE_EVENT(kvm_s390_major_guest_pfault,
+ TP_PROTO(VCPU_PROTO_COMMON),
+ TP_ARGS(VCPU_ARGS_COMMON),
+
+ TP_STRUCT__entry(
+ VCPU_FIELD_COMMON
+ ),
+
+ TP_fast_assign(
+ VCPU_ASSIGN_COMMON
+ ),
+ VCPU_TP_PRINTK("%s", "major fault, maybe applicable for pfault")
+ );
+
+TRACE_EVENT(kvm_s390_pfault_init,
+ TP_PROTO(VCPU_PROTO_COMMON, long pfault_token),
+ TP_ARGS(VCPU_ARGS_COMMON, pfault_token),
+
+ TP_STRUCT__entry(
+ VCPU_FIELD_COMMON
+ __field(long, pfault_token)
+ ),
+
+ TP_fast_assign(
+ VCPU_ASSIGN_COMMON
+ __entry->pfault_token = pfault_token;
+ ),
+ VCPU_TP_PRINTK("init pfault token %ld", __entry->pfault_token)
+ );
+
+TRACE_EVENT(kvm_s390_pfault_done,
+ TP_PROTO(VCPU_PROTO_COMMON, long pfault_token),
+ TP_ARGS(VCPU_ARGS_COMMON, pfault_token),
+
+ TP_STRUCT__entry(
+ VCPU_FIELD_COMMON
+ __field(long, pfault_token)
+ ),
+
+ TP_fast_assign(
+ VCPU_ASSIGN_COMMON
+ __entry->pfault_token = pfault_token;
+ ),
+ VCPU_TP_PRINTK("done pfault token %ld", __entry->pfault_token)
+ );
+
/*
* Tracepoints for SIE entry and exit.
*/
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile
index b068729e50ac..e3fffe1dff51 100644
--- a/arch/s390/lib/Makefile
+++ b/arch/s390/lib/Makefile
@@ -2,8 +2,7 @@
# Makefile for s390-specific library files..
#
-lib-y += delay.o string.o uaccess_pt.o find.o
+lib-y += delay.o string.o uaccess_pt.o uaccess_mvcos.o find.o
obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o mem32.o
obj-$(CONFIG_64BIT) += mem64.o
-lib-$(CONFIG_64BIT) += uaccess_mvcos.o
lib-$(CONFIG_SMP) += spinlock.o
diff --git a/arch/s390/lib/find.c b/arch/s390/lib/find.c
index 620d34d6487e..922003c1b90d 100644
--- a/arch/s390/lib/find.c
+++ b/arch/s390/lib/find.c
@@ -4,7 +4,7 @@
* On s390x the bits are numbered:
* |0..............63|64............127|128...........191|192...........255|
* and on s390:
- * |0.....31|31....63|64....95|96...127|128..159|160..191|192..223|224..255|
+ * |0.....31|32....63|64....95|96...127|128..159|160..191|192..223|224..255|
*
* The reason for this bit numbering is the fact that the hardware sets bits
* in a bitmap starting at bit 0 (MSB) and we don't want to scan the bitmap
diff --git a/arch/s390/lib/uaccess.h b/arch/s390/lib/uaccess.h
index b1a22173d027..c7e0e81f4b4e 100644
--- a/arch/s390/lib/uaccess.h
+++ b/arch/s390/lib/uaccess.h
@@ -6,7 +6,11 @@
#ifndef __ARCH_S390_LIB_UACCESS_H
#define __ARCH_S390_LIB_UACCESS_H
-extern int futex_atomic_op_pt(int, u32 __user *, int, int *);
-extern int futex_atomic_cmpxchg_pt(u32 *, u32 __user *, u32, u32);
+unsigned long copy_from_user_pt(void *to, const void __user *from, unsigned long n);
+unsigned long copy_to_user_pt(void __user *to, const void *from, unsigned long n);
+unsigned long copy_in_user_pt(void __user *to, const void __user *from, unsigned long n);
+unsigned long clear_user_pt(void __user *to, unsigned long n);
+unsigned long strnlen_user_pt(const char __user *src, unsigned long count);
+long strncpy_from_user_pt(char *dst, const char __user *src, long count);
#endif /* __ARCH_S390_LIB_UACCESS_H */
diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c
index 4b7993bf69b9..ae97b8df11aa 100644
--- a/arch/s390/lib/uaccess_mvcos.c
+++ b/arch/s390/lib/uaccess_mvcos.c
@@ -6,8 +6,11 @@
* Gerald Schaefer (gerald.schaefer@de.ibm.com)
*/
+#include <linux/jump_label.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/mm.h>
+#include <asm/facility.h>
#include <asm/uaccess.h>
#include <asm/futex.h>
#include "uaccess.h"
@@ -26,7 +29,10 @@
#define SLR "slgr"
#endif
-static size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
+static struct static_key have_mvcos = STATIC_KEY_INIT_TRUE;
+
+static inline unsigned long copy_from_user_mvcos(void *x, const void __user *ptr,
+ unsigned long size)
{
register unsigned long reg0 asm("0") = 0x81UL;
unsigned long tmp1, tmp2;
@@ -65,7 +71,16 @@ static size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
return size;
}
-static size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
+unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+ if (static_key_true(&have_mvcos))
+ return copy_from_user_mvcos(to, from, n);
+ return copy_from_user_pt(to, from, n);
+}
+EXPORT_SYMBOL(__copy_from_user);
+
+static inline unsigned long copy_to_user_mvcos(void __user *ptr, const void *x,
+ unsigned long size)
{
register unsigned long reg0 asm("0") = 0x810000UL;
unsigned long tmp1, tmp2;
@@ -94,8 +109,16 @@ static size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
return size;
}
-static size_t copy_in_user_mvcos(size_t size, void __user *to,
- const void __user *from)
+unsigned long __copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+ if (static_key_true(&have_mvcos))
+ return copy_to_user_mvcos(to, from, n);
+ return copy_to_user_pt(to, from, n);
+}
+EXPORT_SYMBOL(__copy_to_user);
+
+static inline unsigned long copy_in_user_mvcos(void __user *to, const void __user *from,
+ unsigned long size)
{
register unsigned long reg0 asm("0") = 0x810081UL;
unsigned long tmp1, tmp2;
@@ -117,7 +140,15 @@ static size_t copy_in_user_mvcos(size_t size, void __user *to,
return size;
}
-static size_t clear_user_mvcos(size_t size, void __user *to)
+unsigned long __copy_in_user(void __user *to, const void __user *from, unsigned long n)
+{
+ if (static_key_true(&have_mvcos))
+ return copy_in_user_mvcos(to, from, n);
+ return copy_in_user_pt(to, from, n);
+}
+EXPORT_SYMBOL(__copy_in_user);
+
+static inline unsigned long clear_user_mvcos(void __user *to, unsigned long size)
{
register unsigned long reg0 asm("0") = 0x810000UL;
unsigned long tmp1, tmp2;
@@ -145,17 +176,26 @@ static size_t clear_user_mvcos(size_t size, void __user *to)
return size;
}
-static size_t strnlen_user_mvcos(size_t count, const char __user *src)
+unsigned long __clear_user(void __user *to, unsigned long size)
{
- size_t done, len, offset, len_str;
+ if (static_key_true(&have_mvcos))
+ return clear_user_mvcos(to, size);
+ return clear_user_pt(to, size);
+}
+EXPORT_SYMBOL(__clear_user);
+
+static inline unsigned long strnlen_user_mvcos(const char __user *src,
+ unsigned long count)
+{
+ unsigned long done, len, offset, len_str;
char buf[256];
done = 0;
do {
- offset = (size_t)src & ~PAGE_MASK;
+ offset = (unsigned long)src & ~PAGE_MASK;
len = min(256UL, PAGE_SIZE - offset);
len = min(count - done, len);
- if (copy_from_user_mvcos(len, src, buf))
+ if (copy_from_user_mvcos(buf, src, len))
return 0;
len_str = strnlen(buf, len);
done += len_str;
@@ -164,18 +204,26 @@ static size_t strnlen_user_mvcos(size_t count, const char __user *src)
return done + 1;
}
-static size_t strncpy_from_user_mvcos(size_t count, const char __user *src,
- char *dst)
+unsigned long __strnlen_user(const char __user *src, unsigned long count)
{
- size_t done, len, offset, len_str;
+ if (static_key_true(&have_mvcos))
+ return strnlen_user_mvcos(src, count);
+ return strnlen_user_pt(src, count);
+}
+EXPORT_SYMBOL(__strnlen_user);
- if (unlikely(!count))
+static inline long strncpy_from_user_mvcos(char *dst, const char __user *src,
+ long count)
+{
+ unsigned long done, len, offset, len_str;
+
+ if (unlikely(count <= 0))
return 0;
done = 0;
do {
- offset = (size_t)src & ~PAGE_MASK;
+ offset = (unsigned long)src & ~PAGE_MASK;
len = min(count - done, PAGE_SIZE - offset);
- if (copy_from_user_mvcos(len, src, dst))
+ if (copy_from_user_mvcos(dst, src, len))
return -EFAULT;
len_str = strnlen(dst, len);
done += len_str;
@@ -185,13 +233,31 @@ static size_t strncpy_from_user_mvcos(size_t count, const char __user *src,
return done;
}
-struct uaccess_ops uaccess_mvcos = {
- .copy_from_user = copy_from_user_mvcos,
- .copy_to_user = copy_to_user_mvcos,
- .copy_in_user = copy_in_user_mvcos,
- .clear_user = clear_user_mvcos,
- .strnlen_user = strnlen_user_mvcos,
- .strncpy_from_user = strncpy_from_user_mvcos,
- .futex_atomic_op = futex_atomic_op_pt,
- .futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt,
-};
+long __strncpy_from_user(char *dst, const char __user *src, long count)
+{
+ if (static_key_true(&have_mvcos))
+ return strncpy_from_user_mvcos(dst, src, count);
+ return strncpy_from_user_pt(dst, src, count);
+}
+EXPORT_SYMBOL(__strncpy_from_user);
+
+/*
+ * The uaccess page tabe walk variant can be enforced with the "uaccesspt"
+ * kernel parameter. This is mainly for debugging purposes.
+ */
+static int force_uaccess_pt __initdata;
+
+static int __init parse_uaccess_pt(char *__unused)
+{
+ force_uaccess_pt = 1;
+ return 0;
+}
+early_param("uaccesspt", parse_uaccess_pt);
+
+static int __init uaccess_init(void)
+{
+ if (IS_ENABLED(CONFIG_32BIT) || force_uaccess_pt || !test_facility(27))
+ static_key_slow_dec(&have_mvcos);
+ return 0;
+}
+early_initcall(uaccess_init);
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index 61ebcc9ccb34..8d39760bae68 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -22,7 +22,7 @@
#define SLR "slgr"
#endif
-static size_t strnlen_kernel(size_t count, const char __user *src)
+static unsigned long strnlen_kernel(const char __user *src, unsigned long count)
{
register unsigned long reg0 asm("0") = 0UL;
unsigned long tmp1, tmp2;
@@ -42,8 +42,8 @@ static size_t strnlen_kernel(size_t count, const char __user *src)
return count;
}
-static size_t copy_in_kernel(size_t count, void __user *to,
- const void __user *from)
+static unsigned long copy_in_kernel(void __user *to, const void __user *from,
+ unsigned long count)
{
unsigned long tmp1;
@@ -146,8 +146,8 @@ static unsigned long follow_table(struct mm_struct *mm,
#endif /* CONFIG_64BIT */
-static __always_inline size_t __user_copy_pt(unsigned long uaddr, void *kptr,
- size_t n, int write_user)
+static inline unsigned long __user_copy_pt(unsigned long uaddr, void *kptr,
+ unsigned long n, int write_user)
{
struct mm_struct *mm = current->mm;
unsigned long offset, done, size, kaddr;
@@ -189,8 +189,7 @@ fault:
* Do DAT for user address by page table walk, return kernel address.
* This function needs to be called with current->mm->page_table_lock held.
*/
-static __always_inline unsigned long __dat_user_addr(unsigned long uaddr,
- int write)
+static inline unsigned long __dat_user_addr(unsigned long uaddr, int write)
{
struct mm_struct *mm = current->mm;
unsigned long kaddr;
@@ -211,29 +210,29 @@ fault:
return 0;
}
-static size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
+unsigned long copy_from_user_pt(void *to, const void __user *from, unsigned long n)
{
- size_t rc;
+ unsigned long rc;
if (segment_eq(get_fs(), KERNEL_DS))
- return copy_in_kernel(n, (void __user *) to, from);
+ return copy_in_kernel((void __user *) to, from, n);
rc = __user_copy_pt((unsigned long) from, to, n, 0);
if (unlikely(rc))
memset(to + n - rc, 0, rc);
return rc;
}
-static size_t copy_to_user_pt(size_t n, void __user *to, const void *from)
+unsigned long copy_to_user_pt(void __user *to, const void *from, unsigned long n)
{
if (segment_eq(get_fs(), KERNEL_DS))
- return copy_in_kernel(n, to, (void __user *) from);
+ return copy_in_kernel(to, (void __user *) from, n);
return __user_copy_pt((unsigned long) to, (void *) from, n, 1);
}
-static size_t clear_user_pt(size_t n, void __user *to)
+unsigned long clear_user_pt(void __user *to, unsigned long n)
{
void *zpage = (void *) empty_zero_page;
- long done, size, ret;
+ unsigned long done, size, ret;
done = 0;
do {
@@ -242,7 +241,7 @@ static size_t clear_user_pt(size_t n, void __user *to)
else
size = n - done;
if (segment_eq(get_fs(), KERNEL_DS))
- ret = copy_in_kernel(n, to, (void __user *) zpage);
+ ret = copy_in_kernel(to, (void __user *) zpage, n);
else
ret = __user_copy_pt((unsigned long) to, zpage, size, 1);
done += size;
@@ -253,17 +252,17 @@ static size_t clear_user_pt(size_t n, void __user *to)
return 0;
}
-static size_t strnlen_user_pt(size_t count, const char __user *src)
+unsigned long strnlen_user_pt(const char __user *src, unsigned long count)
{
unsigned long uaddr = (unsigned long) src;
struct mm_struct *mm = current->mm;
unsigned long offset, done, len, kaddr;
- size_t len_str;
+ unsigned long len_str;
if (unlikely(!count))
return 0;
if (segment_eq(get_fs(), KERNEL_DS))
- return strnlen_kernel(count, src);
+ return strnlen_kernel(src, count);
if (!mm)
return 0;
done = 0;
@@ -289,19 +288,18 @@ fault:
goto retry;
}
-static size_t strncpy_from_user_pt(size_t count, const char __user *src,
- char *dst)
+long strncpy_from_user_pt(char *dst, const char __user *src, long count)
{
- size_t done, len, offset, len_str;
+ unsigned long done, len, offset, len_str;
- if (unlikely(!count))
+ if (unlikely(count <= 0))
return 0;
done = 0;
do {
- offset = (size_t)src & ~PAGE_MASK;
+ offset = (unsigned long)src & ~PAGE_MASK;
len = min(count - done, PAGE_SIZE - offset);
if (segment_eq(get_fs(), KERNEL_DS)) {
- if (copy_in_kernel(len, (void __user *) dst, src))
+ if (copy_in_kernel((void __user *) dst, src, len))
return -EFAULT;
} else {
if (__user_copy_pt((unsigned long) src, dst, len, 0))
@@ -315,8 +313,8 @@ static size_t strncpy_from_user_pt(size_t count, const char __user *src,
return done;
}
-static size_t copy_in_user_pt(size_t n, void __user *to,
- const void __user *from)
+unsigned long copy_in_user_pt(void __user *to, const void __user *from,
+ unsigned long n)
{
struct mm_struct *mm = current->mm;
unsigned long offset_max, uaddr, done, size, error_code;
@@ -326,7 +324,7 @@ static size_t copy_in_user_pt(size_t n, void __user *to,
int write_user;
if (segment_eq(get_fs(), KERNEL_DS))
- return copy_in_kernel(n, to, from);
+ return copy_in_kernel(to, from, n);
if (!mm)
return n;
done = 0;
@@ -411,7 +409,7 @@ static int __futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
return ret;
}
-int futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
+int __futex_atomic_op_inuser(int op, u32 __user *uaddr, int oparg, int *old)
{
int ret;
@@ -449,8 +447,8 @@ static int __futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
return ret;
}
-int futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
- u32 oldval, u32 newval)
+int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
int ret;
@@ -471,14 +469,3 @@ int futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
put_page(virt_to_page(uaddr));
return ret;
}
-
-struct uaccess_ops uaccess_pt = {
- .copy_from_user = copy_from_user_pt,
- .copy_to_user = copy_to_user_pt,
- .copy_in_user = copy_in_user_pt,
- .clear_user = clear_user_pt,
- .strnlen_user = strnlen_user_pt,
- .strncpy_from_user = strncpy_from_user_pt,
- .futex_atomic_op = futex_atomic_op_pt,
- .futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt,
-};
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index d95265b2719f..88cef505453b 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -50,6 +50,7 @@
#define VM_FAULT_BADMAP 0x020000
#define VM_FAULT_BADACCESS 0x040000
#define VM_FAULT_SIGNAL 0x080000
+#define VM_FAULT_PFAULT 0x100000
static unsigned long store_indication __read_mostly;
@@ -227,6 +228,7 @@ static noinline void do_fault_error(struct pt_regs *regs, int fault)
return;
}
case VM_FAULT_BADCONTEXT:
+ case VM_FAULT_PFAULT:
do_no_context(regs);
break;
case VM_FAULT_SIGNAL:
@@ -264,6 +266,9 @@ static noinline void do_fault_error(struct pt_regs *regs, int fault)
*/
static inline int do_exception(struct pt_regs *regs, int access)
{
+#ifdef CONFIG_PGSTE
+ struct gmap *gmap;
+#endif
struct task_struct *tsk;
struct mm_struct *mm;
struct vm_area_struct *vma;
@@ -304,9 +309,10 @@ static inline int do_exception(struct pt_regs *regs, int access)
down_read(&mm->mmap_sem);
#ifdef CONFIG_PGSTE
- if ((current->flags & PF_VCPU) && S390_lowcore.gmap) {
- address = __gmap_fault(address,
- (struct gmap *) S390_lowcore.gmap);
+ gmap = (struct gmap *)
+ ((current->flags & PF_VCPU) ? S390_lowcore.gmap : 0);
+ if (gmap) {
+ address = __gmap_fault(address, gmap);
if (address == -EFAULT) {
fault = VM_FAULT_BADMAP;
goto out_up;
@@ -315,6 +321,8 @@ static inline int do_exception(struct pt_regs *regs, int access)
fault = VM_FAULT_OOM;
goto out_up;
}
+ if (gmap->pfault_enabled)
+ flags |= FAULT_FLAG_RETRY_NOWAIT;
}
#endif
@@ -371,9 +379,19 @@ retry:
regs, address);
}
if (fault & VM_FAULT_RETRY) {
+#ifdef CONFIG_PGSTE
+ if (gmap && (flags & FAULT_FLAG_RETRY_NOWAIT)) {
+ /* FAULT_FLAG_RETRY_NOWAIT has been set,
+ * mmap_sem has not been released */
+ current->thread.gmap_pfault = 1;
+ fault = VM_FAULT_PFAULT;
+ goto out_up;
+ }
+#endif
/* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
* of starvation. */
- flags &= ~FAULT_FLAG_ALLOW_RETRY;
+ flags &= ~(FAULT_FLAG_ALLOW_RETRY |
+ FAULT_FLAG_RETRY_NOWAIT);
flags |= FAULT_FLAG_TRIED;
down_read(&mm->mmap_sem);
goto retry;
diff --git a/arch/s390/mm/maccess.c b/arch/s390/mm/maccess.c
index d1e0e0c7a7e2..2a2e35416d2f 100644
--- a/arch/s390/mm/maccess.c
+++ b/arch/s390/mm/maccess.c
@@ -128,7 +128,7 @@ void memcpy_absolute(void *dest, void *src, size_t count)
/*
* Copy memory from kernel (real) to user (virtual)
*/
-int copy_to_user_real(void __user *dest, void *src, size_t count)
+int copy_to_user_real(void __user *dest, void *src, unsigned long count)
{
int offs = 0, size, rc;
char *buf;
@@ -152,32 +152,6 @@ out:
}
/*
- * Copy memory from user (virtual) to kernel (real)
- */
-int copy_from_user_real(void *dest, void __user *src, size_t count)
-{
- int offs = 0, size, rc;
- char *buf;
-
- buf = (char *) __get_free_page(GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- rc = -EFAULT;
- while (offs < count) {
- size = min(PAGE_SIZE, count - offs);
- if (copy_from_user(buf, src + offs, size))
- goto out;
- if (memcpy_real(dest + offs, buf, size))
- goto out;
- offs += size;
- }
- rc = 0;
-out:
- free_page((unsigned long) buf);
- return rc;
-}
-
-/*
* Check if physical address is within prefix or zero page
*/
static int is_swapped(unsigned long addr)
diff --git a/arch/s390/mm/page-states.c b/arch/s390/mm/page-states.c
index a90d45e9dfb0..27c50f4d90cb 100644
--- a/arch/s390/mm/page-states.c
+++ b/arch/s390/mm/page-states.c
@@ -12,6 +12,8 @@
#include <linux/mm.h>
#include <linux/gfp.h>
#include <linux/init.h>
+#include <asm/setup.h>
+#include <asm/ipl.h>
#define ESSA_SET_STABLE 1
#define ESSA_SET_UNUSED 2
@@ -41,6 +43,14 @@ void __init cmma_init(void)
if (!cmma_flag)
return;
+ /*
+ * Disable CMM for dump, otherwise the tprot based memory
+ * detection can fail because of unstable pages.
+ */
+ if (OLDMEM_BASE || ipl_info.type == IPL_TYPE_FCP_DUMP) {
+ cmma_flag = 0;
+ return;
+ }
asm volatile(
" .insn rrf,0xb9ab0000,%1,%1,0,0\n"
"0: la %0,0\n"
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index 3584ed9b20a1..796c9320c709 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -17,6 +17,7 @@
#include <linux/quicklist.h>
#include <linux/rcupdate.h>
#include <linux/slab.h>
+#include <linux/swapops.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -594,6 +595,82 @@ unsigned long gmap_fault(unsigned long address, struct gmap *gmap)
}
EXPORT_SYMBOL_GPL(gmap_fault);
+static void gmap_zap_swap_entry(swp_entry_t entry, struct mm_struct *mm)
+{
+ if (!non_swap_entry(entry))
+ dec_mm_counter(mm, MM_SWAPENTS);
+ else if (is_migration_entry(entry)) {
+ struct page *page = migration_entry_to_page(entry);
+
+ if (PageAnon(page))
+ dec_mm_counter(mm, MM_ANONPAGES);
+ else
+ dec_mm_counter(mm, MM_FILEPAGES);
+ }
+ free_swap_and_cache(entry);
+}
+
+/**
+ * The mm->mmap_sem lock must be held
+ */
+static void gmap_zap_unused(struct mm_struct *mm, unsigned long address)
+{
+ unsigned long ptev, pgstev;
+ spinlock_t *ptl;
+ pgste_t pgste;
+ pte_t *ptep, pte;
+
+ ptep = get_locked_pte(mm, address, &ptl);
+ if (unlikely(!ptep))
+ return;
+ pte = *ptep;
+ if (!pte_swap(pte))
+ goto out_pte;
+ /* Zap unused and logically-zero pages */
+ pgste = pgste_get_lock(ptep);
+ pgstev = pgste_val(pgste);
+ ptev = pte_val(pte);
+ if (((pgstev & _PGSTE_GPS_USAGE_MASK) == _PGSTE_GPS_USAGE_UNUSED) ||
+ ((pgstev & _PGSTE_GPS_ZERO) && (ptev & _PAGE_INVALID))) {
+ gmap_zap_swap_entry(pte_to_swp_entry(pte), mm);
+ pte_clear(mm, address, ptep);
+ }
+ pgste_set_unlock(ptep, pgste);
+out_pte:
+ pte_unmap_unlock(*ptep, ptl);
+}
+
+/*
+ * this function is assumed to be called with mmap_sem held
+ */
+void __gmap_zap(unsigned long address, struct gmap *gmap)
+{
+ unsigned long *table, *segment_ptr;
+ unsigned long segment, pgstev, ptev;
+ struct gmap_pgtable *mp;
+ struct page *page;
+
+ segment_ptr = gmap_table_walk(address, gmap);
+ if (IS_ERR(segment_ptr))
+ return;
+ segment = *segment_ptr;
+ if (segment & _SEGMENT_ENTRY_INVALID)
+ return;
+ page = pfn_to_page(segment >> PAGE_SHIFT);
+ mp = (struct gmap_pgtable *) page->index;
+ address = mp->vmaddr | (address & ~PMD_MASK);
+ /* Page table is present */
+ table = (unsigned long *)(segment & _SEGMENT_ENTRY_ORIGIN);
+ table = table + ((address >> 12) & 0xff);
+ pgstev = table[PTRS_PER_PTE];
+ ptev = table[0];
+ /* quick check, checked again with locks held */
+ if (((pgstev & _PGSTE_GPS_USAGE_MASK) == _PGSTE_GPS_USAGE_UNUSED) ||
+ ((pgstev & _PGSTE_GPS_ZERO) && (ptev & _PAGE_INVALID)))
+ gmap_zap_unused(gmap->mm, address);
+}
+EXPORT_SYMBOL_GPL(__gmap_zap);
+
void gmap_discard(unsigned long from, unsigned long to, struct gmap *gmap)
{
@@ -671,7 +748,7 @@ EXPORT_SYMBOL_GPL(gmap_unregister_ipte_notifier);
/**
* gmap_ipte_notify - mark a range of ptes for invalidation notification
* @gmap: pointer to guest mapping meta data structure
- * @address: virtual address in the guest address space
+ * @start: virtual address in the guest address space
* @len: size of area
*
* Returns 0 if for each page in the given range a gmap mapping exists and
@@ -725,13 +802,12 @@ EXPORT_SYMBOL_GPL(gmap_ipte_notify);
/**
* gmap_do_ipte_notify - call all invalidation callbacks for a specific pte.
* @mm: pointer to the process mm_struct
- * @addr: virtual address in the process address space
* @pte: pointer to the page table entry
*
* This function is assumed to be called with the page table lock held
* for the pte to notify.
*/
-void gmap_do_ipte_notify(struct mm_struct *mm, unsigned long addr, pte_t *pte)
+void gmap_do_ipte_notify(struct mm_struct *mm, pte_t *pte)
{
unsigned long segment_offset;
struct gmap_notifier *nb;
@@ -802,6 +878,78 @@ static inline void page_table_free_pgste(unsigned long *table)
__free_page(page);
}
+static inline unsigned long page_table_reset_pte(struct mm_struct *mm,
+ pmd_t *pmd, unsigned long addr, unsigned long end)
+{
+ pte_t *start_pte, *pte;
+ spinlock_t *ptl;
+ pgste_t pgste;
+
+ start_pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+ pte = start_pte;
+ do {
+ pgste = pgste_get_lock(pte);
+ pgste_val(pgste) &= ~_PGSTE_GPS_USAGE_MASK;
+ pgste_set_unlock(pte, pgste);
+ } while (pte++, addr += PAGE_SIZE, addr != end);
+ pte_unmap_unlock(start_pte, ptl);
+
+ return addr;
+}
+
+static inline unsigned long page_table_reset_pmd(struct mm_struct *mm,
+ pud_t *pud, unsigned long addr, unsigned long end)
+{
+ unsigned long next;
+ pmd_t *pmd;
+
+ pmd = pmd_offset(pud, addr);
+ do {
+ next = pmd_addr_end(addr, end);
+ if (pmd_none_or_clear_bad(pmd))
+ continue;
+ next = page_table_reset_pte(mm, pmd, addr, next);
+ } while (pmd++, addr = next, addr != end);
+
+ return addr;
+}
+
+static inline unsigned long page_table_reset_pud(struct mm_struct *mm,
+ pgd_t *pgd, unsigned long addr, unsigned long end)
+{
+ unsigned long next;
+ pud_t *pud;
+
+ pud = pud_offset(pgd, addr);
+ do {
+ next = pud_addr_end(addr, end);
+ if (pud_none_or_clear_bad(pud))
+ continue;
+ next = page_table_reset_pmd(mm, pud, addr, next);
+ } while (pud++, addr = next, addr != end);
+
+ return addr;
+}
+
+void page_table_reset_pgste(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+{
+ unsigned long addr, next;
+ pgd_t *pgd;
+
+ addr = start;
+ down_read(&mm->mmap_sem);
+ pgd = pgd_offset(mm, addr);
+ do {
+ next = pgd_addr_end(addr, end);
+ if (pgd_none_or_clear_bad(pgd))
+ continue;
+ next = page_table_reset_pud(mm, pgd, addr, next);
+ } while (pgd++, addr = next, addr != end);
+ up_read(&mm->mmap_sem);
+}
+EXPORT_SYMBOL(page_table_reset_pgste);
+
int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
unsigned long key, bool nq)
{
@@ -1248,7 +1396,7 @@ void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
{
struct list_head *lh = (struct list_head *) pgtable;
- assert_spin_locked(&mm->page_table_lock);
+ assert_spin_locked(pmd_lockptr(mm, pmdp));
/* FIFO */
if (!pmd_huge_pte(mm, pmdp))
@@ -1264,7 +1412,7 @@ pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp)
pgtable_t pgtable;
pte_t *ptep;
- assert_spin_locked(&mm->page_table_lock);
+ assert_spin_locked(pmd_lockptr(mm, pmdp));
/* FIFO */
pgtable = pmd_huge_pte(mm, pmdp);
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
index 708d60e40066..9c36dc398f90 100644
--- a/arch/s390/net/bpf_jit_comp.c
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -737,10 +737,10 @@ call_fn: /* lg %r1,<d(function)>(%r13) */
/* icm %r5,3,<d(type)>(%r1) */
EMIT4_DISP(0xbf531000, offsetof(struct net_device, type));
break;
- case BPF_S_ANC_RXHASH: /* A = skb->rxhash */
- BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
- /* l %r5,<d(rxhash)>(%r2) */
- EMIT4_DISP(0x58502000, offsetof(struct sk_buff, rxhash));
+ case BPF_S_ANC_RXHASH: /* A = skb->hash */
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, hash) != 4);
+ /* l %r5,<d(hash)>(%r2) */
+ EMIT4_DISP(0x58502000, offsetof(struct sk_buff, hash));
break;
case BPF_S_ANC_VLAN_TAG:
case BPF_S_ANC_VLAN_TAG_PRESENT:
@@ -877,6 +877,7 @@ void bpf_jit_compile(struct sk_filter *fp)
if (jit.start) {
set_memory_ro((unsigned long)header, header->pages);
fp->bpf_func = (void *) jit.start;
+ fp->jited = 1;
}
out:
kfree(addrs);
@@ -887,10 +888,12 @@ void bpf_jit_free(struct sk_filter *fp)
unsigned long addr = (unsigned long)fp->bpf_func & PAGE_MASK;
struct bpf_binary_header *header = (void *)addr;
- if (fp->bpf_func == sk_run_filter)
+ if (!fp->jited)
goto free_filter;
+
set_memory_rw(addr, header->pages);
module_free(NULL, header);
+
free_filter:
kfree(fp);
}
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index 66670ff262a0..1df1d29ac81d 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -686,27 +686,13 @@ int pcibios_add_device(struct pci_dev *pdev)
int pcibios_enable_device(struct pci_dev *pdev, int mask)
{
struct zpci_dev *zdev = get_zdev(pdev);
- struct resource *res;
- u16 cmd;
- int i;
zdev->pdev = pdev;
zpci_debug_init_device(zdev);
zpci_fmb_enable_device(zdev);
zpci_map_resources(zdev);
- pci_read_config_word(pdev, PCI_COMMAND, &cmd);
- for (i = 0; i < PCI_BAR_COUNT; i++) {
- res = &pdev->resource[i];
-
- if (res->flags & IORESOURCE_IO)
- return -EINVAL;
-
- if (res->flags & IORESOURCE_MEM)
- cmd |= PCI_COMMAND_MEMORY;
- }
- pci_write_config_word(pdev, PCI_COMMAND, cmd);
- return 0;
+ return pci_enable_resources(pdev, mask);
}
void pcibios_disable_device(struct pci_dev *pdev)
diff --git a/arch/s390/pci/pci_debug.c b/arch/s390/pci/pci_debug.c
index 75c69b402e05..c5c66840ac00 100644
--- a/arch/s390/pci/pci_debug.c
+++ b/arch/s390/pci/pci_debug.c
@@ -139,7 +139,7 @@ void zpci_debug_exit_device(struct zpci_dev *zdev)
int __init zpci_debug_init(void)
{
/* event trace buffer */
- pci_debug_msg_id = debug_register("pci_msg", 16, 1, 16 * sizeof(long));
+ pci_debug_msg_id = debug_register("pci_msg", 8, 1, 8 * sizeof(long));
if (!pci_debug_msg_id)
return -EINVAL;
debug_register_view(pci_debug_msg_id, &debug_sprintf_view);
diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c
index 60c11a629d96..f91c03119804 100644
--- a/arch/s390/pci/pci_dma.c
+++ b/arch/s390/pci/pci_dma.c
@@ -206,11 +206,13 @@ static void dma_cleanup_tables(struct zpci_dev *zdev)
zdev->dma_table = NULL;
}
-static unsigned long __dma_alloc_iommu(struct zpci_dev *zdev, unsigned long start,
- int size)
+static unsigned long __dma_alloc_iommu(struct zpci_dev *zdev,
+ unsigned long start, int size)
{
- unsigned long boundary_size = 0x1000000;
+ unsigned long boundary_size;
+ boundary_size = ALIGN(dma_get_seg_boundary(&zdev->pdev->dev) + 1,
+ PAGE_SIZE) >> PAGE_SHIFT;
return iommu_area_alloc(zdev->iommu_bitmap, zdev->iommu_pages,
start, size, 0, boundary_size, 0);
}
diff --git a/arch/s390/pci/pci_sysfs.c b/arch/s390/pci/pci_sysfs.c
index cf8a12ff733b..ab4a91393005 100644
--- a/arch/s390/pci/pci_sysfs.c
+++ b/arch/s390/pci/pci_sysfs.c
@@ -48,29 +48,27 @@ static ssize_t show_pfgid(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR(pfgid, S_IRUGO, show_pfgid, NULL);
-static void recover_callback(struct device *dev)
+static ssize_t store_recover(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct zpci_dev *zdev = get_zdev(pdev);
int ret;
+ if (!device_remove_file_self(dev, attr))
+ return count;
+
pci_stop_and_remove_bus_device(pdev);
ret = zpci_disable_device(zdev);
if (ret)
- return;
+ return ret;
ret = zpci_enable_device(zdev);
if (ret)
- return;
+ return ret;
pci_rescan_bus(zdev->bus);
-}
-
-static ssize_t store_recover(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- int rc = device_schedule_callback(dev, recover_callback);
- return rc ? rc : count;
+ return count;
}
static DEVICE_ATTR(recover, S_IWUSR, NULL, store_recover);
diff --git a/arch/score/Kconfig b/arch/score/Kconfig
index c75d06aa27c3..4ac8cae5727c 100644
--- a/arch/score/Kconfig
+++ b/arch/score/Kconfig
@@ -22,27 +22,21 @@ choice
config ARCH_SCORE7
bool "SCORE7 processor"
select SYS_SUPPORTS_32BIT_KERNEL
- select CPU_SCORE7
select GENERIC_HAS_IOMAP
config MACH_SPCT6600
bool "SPCT6600 series based machines"
select SYS_SUPPORTS_32BIT_KERNEL
- select CPU_SCORE7
select GENERIC_HAS_IOMAP
config SCORE_SIM
bool "Score simulator"
select SYS_SUPPORTS_32BIT_KERNEL
- select CPU_SCORE7
select GENERIC_HAS_IOMAP
endchoice
endmenu
-config CPU_SCORE7
- bool
-
config NO_DMA
bool
default y
diff --git a/arch/score/include/asm/Kbuild b/arch/score/include/asm/Kbuild
index 146b9d5e89f8..2f947aba4bd4 100644
--- a/arch/score/include/asm/Kbuild
+++ b/arch/score/include/asm/Kbuild
@@ -1,10 +1,12 @@
header-y +=
+
generic-y += barrier.h
generic-y += clkdev.h
+generic-y += cputime.h
generic-y += hash.h
+generic-y += mcs_spinlock.h
+generic-y += preempt.h
generic-y += trace_clock.h
generic-y += xor.h
-generic-y += preempt.h
-
diff --git a/arch/score/include/asm/cputime.h b/arch/score/include/asm/cputime.h
deleted file mode 100644
index 1fced99f0d67..000000000000
--- a/arch/score/include/asm/cputime.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_SCORE_CPUTIME_H
-#define _ASM_SCORE_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* _ASM_SCORE_CPUTIME_H */
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 6357710753d5..1399383315a3 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -123,15 +123,6 @@ config SYS_SUPPORTS_NUMA
config SYS_SUPPORTS_PCI
bool
-config SYS_SUPPORTS_CMT
- bool
-
-config SYS_SUPPORTS_MTU2
- bool
-
-config SYS_SUPPORTS_TMU
- bool
-
config STACKTRACE_SUPPORT
def_bool y
@@ -191,14 +182,14 @@ config CPU_SH3
bool
select CPU_HAS_INTEVT
select CPU_HAS_SR_RB
- select SYS_SUPPORTS_TMU
+ select SYS_SUPPORTS_SH_TMU
config CPU_SH4
bool
select CPU_HAS_INTEVT
select CPU_HAS_SR_RB
select CPU_HAS_FPU if !CPU_SH4AL_DSP
- select SYS_SUPPORTS_TMU
+ select SYS_SUPPORTS_SH_TMU
select SYS_SUPPORTS_HUGETLBFS if MMU
config CPU_SH4A
@@ -213,7 +204,7 @@ config CPU_SH4AL_DSP
config CPU_SH5
bool
select CPU_HAS_FPU
- select SYS_SUPPORTS_TMU
+ select SYS_SUPPORTS_SH_TMU
select SYS_SUPPORTS_HUGETLBFS if MMU
config CPU_SHX2
@@ -250,7 +241,7 @@ choice
config CPU_SUBTYPE_SH7619
bool "Support SH7619 processor"
select CPU_SH2
- select SYS_SUPPORTS_CMT
+ select SYS_SUPPORTS_SH_CMT
# SH-2A Processor Support
@@ -258,50 +249,50 @@ config CPU_SUBTYPE_SH7201
bool "Support SH7201 processor"
select CPU_SH2A
select CPU_HAS_FPU
- select SYS_SUPPORTS_MTU2
+ select SYS_SUPPORTS_SH_MTU2
config CPU_SUBTYPE_SH7203
bool "Support SH7203 processor"
select CPU_SH2A
select CPU_HAS_FPU
- select SYS_SUPPORTS_CMT
- select SYS_SUPPORTS_MTU2
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_MTU2
select ARCH_WANT_OPTIONAL_GPIOLIB
select PINCTRL
config CPU_SUBTYPE_SH7206
bool "Support SH7206 processor"
select CPU_SH2A
- select SYS_SUPPORTS_CMT
- select SYS_SUPPORTS_MTU2
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_MTU2
config CPU_SUBTYPE_SH7263
bool "Support SH7263 processor"
select CPU_SH2A
select CPU_HAS_FPU
- select SYS_SUPPORTS_CMT
- select SYS_SUPPORTS_MTU2
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_MTU2
config CPU_SUBTYPE_SH7264
bool "Support SH7264 processor"
select CPU_SH2A
select CPU_HAS_FPU
- select SYS_SUPPORTS_CMT
- select SYS_SUPPORTS_MTU2
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_MTU2
select PINCTRL
config CPU_SUBTYPE_SH7269
bool "Support SH7269 processor"
select CPU_SH2A
select CPU_HAS_FPU
- select SYS_SUPPORTS_CMT
- select SYS_SUPPORTS_MTU2
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_MTU2
select PINCTRL
config CPU_SUBTYPE_MXG
bool "Support MX-G processor"
select CPU_SH2A
- select SYS_SUPPORTS_MTU2
+ select SYS_SUPPORTS_SH_MTU2
help
Select MX-G if running on an R8A03022BG part.
@@ -354,9 +345,8 @@ config CPU_SUBTYPE_SH7720
bool "Support SH7720 processor"
select CPU_SH3
select CPU_HAS_DSP
- select SYS_SUPPORTS_CMT
+ select SYS_SUPPORTS_SH_CMT
select ARCH_WANT_OPTIONAL_GPIOLIB
- select USB_ARCH_HAS_OHCI
select USB_OHCI_SH if USB_OHCI_HCD
select PINCTRL
help
@@ -366,8 +356,7 @@ config CPU_SUBTYPE_SH7721
bool "Support SH7721 processor"
select CPU_SH3
select CPU_HAS_DSP
- select SYS_SUPPORTS_CMT
- select USB_ARCH_HAS_OHCI
+ select SYS_SUPPORTS_SH_CMT
select USB_OHCI_SH if USB_OHCI_HCD
help
Select SH7721 if you have a SH3-DSP SH7721 CPU.
@@ -422,7 +411,7 @@ config CPU_SUBTYPE_SH7723
select CPU_SHX2
select ARCH_SHMOBILE
select ARCH_SPARSEMEM_ENABLE
- select SYS_SUPPORTS_CMT
+ select SYS_SUPPORTS_SH_CMT
select ARCH_WANT_OPTIONAL_GPIOLIB
select PINCTRL
help
@@ -434,7 +423,7 @@ config CPU_SUBTYPE_SH7724
select CPU_SHX2
select ARCH_SHMOBILE
select ARCH_SPARSEMEM_ENABLE
- select SYS_SUPPORTS_CMT
+ select SYS_SUPPORTS_SH_CMT
select ARCH_WANT_OPTIONAL_GPIOLIB
select PINCTRL
help
@@ -445,8 +434,6 @@ config CPU_SUBTYPE_SH7734
select CPU_SH4A
select CPU_SHX2
select ARCH_WANT_OPTIONAL_GPIOLIB
- select USB_ARCH_HAS_OHCI
- select USB_ARCH_HAS_EHCI
select PINCTRL
help
Select SH7734 if you have a SH4A SH7734 CPU.
@@ -456,8 +443,6 @@ config CPU_SUBTYPE_SH7757
select CPU_SH4A
select CPU_SHX2
select ARCH_WANT_OPTIONAL_GPIOLIB
- select USB_ARCH_HAS_OHCI
- select USB_ARCH_HAS_EHCI
select PINCTRL
help
Select SH7757 if you have a SH4A SH7757 CPU.
@@ -465,7 +450,6 @@ config CPU_SUBTYPE_SH7757
config CPU_SUBTYPE_SH7763
bool "Support SH7763 processor"
select CPU_SH4A
- select USB_ARCH_HAS_OHCI
select USB_OHCI_SH if USB_OHCI_HCD
help
Select SH7763 if you have a SH4A SH7763(R5S77631) CPU.
@@ -494,9 +478,7 @@ config CPU_SUBTYPE_SH7786
select CPU_HAS_PTEAEX
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
select ARCH_WANT_OPTIONAL_GPIOLIB
- select USB_ARCH_HAS_OHCI
select USB_OHCI_SH if USB_OHCI_HCD
- select USB_ARCH_HAS_EHCI
select USB_EHCI_SH if USB_EHCI_HCD
select PINCTRL
@@ -514,7 +496,7 @@ config CPU_SUBTYPE_SH7343
bool "Support SH7343 processor"
select CPU_SH4AL_DSP
select ARCH_SHMOBILE
- select SYS_SUPPORTS_CMT
+ select SYS_SUPPORTS_SH_CMT
config CPU_SUBTYPE_SH7722
bool "Support SH7722 processor"
@@ -523,7 +505,7 @@ config CPU_SUBTYPE_SH7722
select ARCH_SHMOBILE
select ARCH_SPARSEMEM_ENABLE
select SYS_SUPPORTS_NUMA
- select SYS_SUPPORTS_CMT
+ select SYS_SUPPORTS_SH_CMT
select ARCH_WANT_OPTIONAL_GPIOLIB
select PINCTRL
@@ -534,7 +516,7 @@ config CPU_SUBTYPE_SH7366
select ARCH_SHMOBILE
select ARCH_SPARSEMEM_ENABLE
select SYS_SUPPORTS_NUMA
- select SYS_SUPPORTS_CMT
+ select SYS_SUPPORTS_SH_CMT
endchoice
@@ -567,27 +549,6 @@ source "arch/sh/boards/Kconfig"
menu "Timer and clock configuration"
-config SH_TIMER_TMU
- bool "TMU timer driver"
- depends on SYS_SUPPORTS_TMU
- default y
- help
- This enables the build of the TMU timer driver.
-
-config SH_TIMER_CMT
- bool "CMT timer driver"
- depends on SYS_SUPPORTS_CMT
- default y
- help
- This enables build of the CMT timer driver.
-
-config SH_TIMER_MTU2
- bool "MTU2 timer driver"
- depends on SYS_SUPPORTS_MTU2
- default y
- help
- This enables build of the MTU2 timer driver.
-
config SH_PCLK_FREQ
int "Peripheral clock frequency (in Hz)"
depends on SH_CLK_CPG_LEGACY
diff --git a/arch/sh/boards/board-sh7757lcr.c b/arch/sh/boards/board-sh7757lcr.c
index 25c5a932f9fe..669df51a82e3 100644
--- a/arch/sh/boards/board-sh7757lcr.c
+++ b/arch/sh/boards/board-sh7757lcr.c
@@ -252,7 +252,7 @@ static struct sh_mobile_sdhi_info sdhi_info = {
static struct resource sdhi_resources[] = {
[0] = {
.start = 0xffe50000,
- .end = 0xffe501ff,
+ .end = 0xffe500ff,
.flags = IORESOURCE_MEM,
},
[1] = {
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 5bc3a15465c7..85d5255d259f 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -861,14 +861,12 @@ static struct asoc_simple_card_info fsi_da7210_info = {
.card = "FSIB-DA7210",
.codec = "da7210.0-001a",
.platform = "sh_fsi.0",
- .daifmt = SND_SOC_DAIFMT_I2S,
+ .daifmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
.cpu_dai = {
.name = "fsib-dai",
- .fmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
},
.codec_dai = {
.name = "da7210-hifi",
- .fmt = SND_SOC_DAIFMT_CBM_CFM,
},
};
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index 21e4230659a5..1162bc6945a3 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -304,14 +304,12 @@ static struct asoc_simple_card_info fsi_ak4642_info = {
.card = "FSIA-AK4642",
.codec = "ak4642-codec.0-0012",
.platform = "sh_fsi.0",
- .daifmt = SND_SOC_DAIFMT_LEFT_J,
+ .daifmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM,
.cpu_dai = {
.name = "fsia-dai",
- .fmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
},
.codec_dai = {
.name = "ak4642-hifi",
- .fmt = SND_SOC_DAIFMT_CBM_CFM,
.sysclk = 11289600,
},
};
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index 60ed3e1c4b75..1bc09ee7948f 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -186,11 +186,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
return start;
}
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
- return pci_enable_resources(dev, mask);
-}
-
static void __init
pcibios_bus_report_status_early(struct pci_channel *hose,
int top_bus, int current_bus,
diff --git a/arch/sh/drivers/pci/pcie-sh7786.h b/arch/sh/drivers/pci/pcie-sh7786.h
index 1ee054e47eae..4a6ff55f759b 100644
--- a/arch/sh/drivers/pci/pcie-sh7786.h
+++ b/arch/sh/drivers/pci/pcie-sh7786.h
@@ -145,9 +145,6 @@
/* PCIERMSGIER */
#define SH4A_PCIERMSGIER (0x004040) /* R/W - 0x0000 0000 32 */
-/* PCIEPHYCTLR */
-#define SH4A_PCIEPHYCTLR (0x010000) /* R/W - 0x0000 0000 32 */
-
/* PCIEPHYADRR */
#define SH4A_PCIEPHYADRR (0x010004) /* R/W - 0x0000 0000 32 */
#define BITS_ACK (24) // Rev1.171
diff --git a/arch/sh/include/asm/Kbuild b/arch/sh/include/asm/Kbuild
index 0cd7198a4524..c19e47dacb31 100644
--- a/arch/sh/include/asm/Kbuild
+++ b/arch/sh/include/asm/Kbuild
@@ -8,18 +8,21 @@ generic-y += emergency-restart.h
generic-y += errno.h
generic-y += exec.h
generic-y += fcntl.h
+generic-y += hash.h
generic-y += ioctl.h
generic-y += ipcbuf.h
generic-y += irq_regs.h
generic-y += kvm_para.h
generic-y += local.h
generic-y += local64.h
+generic-y += mcs_spinlock.h
+generic-y += mman.h
+generic-y += msgbuf.h
generic-y += param.h
generic-y += parport.h
generic-y += percpu.h
generic-y += poll.h
-generic-y += mman.h
-generic-y += msgbuf.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += sembuf.h
@@ -34,5 +37,3 @@ generic-y += termios.h
generic-y += trace_clock.h
generic-y += ucontext.h
generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/sh/include/asm/syscalls_32.h b/arch/sh/include/asm/syscalls_32.h
index 4f97df87d7d5..4f643aa718e3 100644
--- a/arch/sh/include/asm/syscalls_32.h
+++ b/arch/sh/include/asm/syscalls_32.h
@@ -9,15 +9,9 @@
struct pt_regs;
-asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs);
-asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs);
-asmlinkage int sys_sh_pipe(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs);
+asmlinkage int sys_sigreturn(void);
+asmlinkage int sys_rt_sigreturn(void);
+asmlinkage int sys_sh_pipe(void);
asmlinkage ssize_t sys_pread_wrapper(unsigned int fd, char __user *buf,
size_t count, long dummy, loff_t pos);
asmlinkage ssize_t sys_pwrite_wrapper(unsigned int fd, const char __user *buf,
diff --git a/arch/sh/include/asm/traps_32.h b/arch/sh/include/asm/traps_32.h
index cfd55ff9dff2..17e129fe459c 100644
--- a/arch/sh/include/asm/traps_32.h
+++ b/arch/sh/include/asm/traps_32.h
@@ -42,18 +42,10 @@ static inline void trigger_address_error(void)
asmlinkage void do_address_error(struct pt_regs *regs,
unsigned long writeaccess,
unsigned long address);
-asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs);
-asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs);
-asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs);
-asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs);
+asmlinkage void do_divide_error(unsigned long r4);
+asmlinkage void do_reserved_inst(void);
+asmlinkage void do_illegal_slot_inst(void);
+asmlinkage void do_exception_error(void);
#define BUILD_TRAP_HANDLER(name) \
asmlinkage void name##_trap_handler(unsigned long r4, unsigned long r5, \
diff --git a/arch/sh/include/cpu-sh2/cpu/cache.h b/arch/sh/include/cpu-sh2/cpu/cache.h
index 673515bc4135..aa1b2b9088a7 100644
--- a/arch/sh/include/cpu-sh2/cpu/cache.h
+++ b/arch/sh/include/cpu-sh2/cpu/cache.h
@@ -18,7 +18,7 @@
#define SH_CACHE_ASSOC 8
#if defined(CONFIG_CPU_SUBTYPE_SH7619)
-#define CCR 0xffffffec
+#define SH_CCR 0xffffffec
#define CCR_CACHE_CE 0x01 /* Cache enable */
#define CCR_CACHE_WT 0x02 /* CCR[bit1=1,bit2=1] */
diff --git a/arch/sh/include/cpu-sh2a/cpu/cache.h b/arch/sh/include/cpu-sh2a/cpu/cache.h
index defb0baa5a06..b27ce92cb600 100644
--- a/arch/sh/include/cpu-sh2a/cpu/cache.h
+++ b/arch/sh/include/cpu-sh2a/cpu/cache.h
@@ -17,8 +17,8 @@
#define SH_CACHE_COMBINED 4
#define SH_CACHE_ASSOC 8
-#define CCR 0xfffc1000 /* CCR1 */
-#define CCR2 0xfffc1004
+#define SH_CCR 0xfffc1000 /* CCR1 */
+#define SH_CCR2 0xfffc1004
/*
* Most of the SH-2A CCR1 definitions resemble the SH-4 ones. All others not
diff --git a/arch/sh/include/cpu-sh3/cpu/cache.h b/arch/sh/include/cpu-sh3/cpu/cache.h
index bee2d81c56bf..29700fd88c75 100644
--- a/arch/sh/include/cpu-sh3/cpu/cache.h
+++ b/arch/sh/include/cpu-sh3/cpu/cache.h
@@ -17,7 +17,7 @@
#define SH_CACHE_COMBINED 4
#define SH_CACHE_ASSOC 8
-#define CCR 0xffffffec /* Address of Cache Control Register */
+#define SH_CCR 0xffffffec /* Address of Cache Control Register */
#define CCR_CACHE_CE 0x01 /* Cache Enable */
#define CCR_CACHE_WT 0x02 /* Write-Through (for P0,U0,P3) (else writeback) */
diff --git a/arch/sh/include/cpu-sh4/cpu/cache.h b/arch/sh/include/cpu-sh4/cpu/cache.h
index 7bfb9e8b069c..92c4cd119b66 100644
--- a/arch/sh/include/cpu-sh4/cpu/cache.h
+++ b/arch/sh/include/cpu-sh4/cpu/cache.h
@@ -17,7 +17,7 @@
#define SH_CACHE_COMBINED 4
#define SH_CACHE_ASSOC 8
-#define CCR 0xff00001c /* Address of Cache Control Register */
+#define SH_CCR 0xff00001c /* Address of Cache Control Register */
#define CCR_CACHE_OCE 0x0001 /* Operand Cache Enable */
#define CCR_CACHE_WT 0x0002 /* Write-Through (for P0,U0,P3) (else writeback)*/
#define CCR_CACHE_CB 0x0004 /* Copy-Back (for P1) (else writethrough) */
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index ecf83cd158dc..0d7360d549c1 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -112,7 +112,7 @@ static void cache_init(void)
unsigned long ccr, flags;
jump_to_uncached();
- ccr = __raw_readl(CCR);
+ ccr = __raw_readl(SH_CCR);
/*
* At this point we don't know whether the cache is enabled or not - a
@@ -189,7 +189,7 @@ static void cache_init(void)
l2_cache_init();
- __raw_writel(flags, CCR);
+ __raw_writel(flags, SH_CCR);
back_to_cached();
}
#else
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
index e84a43229b9c..5c0e3c335161 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
@@ -132,7 +132,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("usb_fck", &mstp_clks[MSTP103]),
CLKDEV_DEV_ID("renesas_usbhs.0", &mstp_clks[MSTP102]),
CLKDEV_CON_ID("mmc0", &mstp_clks[MSTP220]),
- CLKDEV_CON_ID("rspi2", &mstp_clks[MSTP127]),
+ CLKDEV_DEV_ID("rspi.2", &mstp_clks[MSTP127]),
};
int __init arch_clk_init(void)
diff --git a/arch/sh/kernel/dumpstack.c b/arch/sh/kernel/dumpstack.c
index b959f5592604..8dfe645bcc4b 100644
--- a/arch/sh/kernel/dumpstack.c
+++ b/arch/sh/kernel/dumpstack.c
@@ -115,7 +115,7 @@ static int print_trace_stack(void *data, char *name)
*/
static void print_trace_address(void *data, unsigned long addr, int reliable)
{
- printk(data);
+ printk("%s", (char *)data);
printk_address(addr, reliable);
}
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S
index ca46834294b7..13047a4facd2 100644
--- a/arch/sh/kernel/entry-common.S
+++ b/arch/sh/kernel/entry-common.S
@@ -193,10 +193,10 @@ syscall_trace_entry:
! Reload R0-R4 from kernel stack, where the
! parent may have modified them using
! ptrace(POKEUSR). (Note that R0-R2 are
- ! used by the system call handler directly
- ! from the kernel stack anyway, so don't need
- ! to be reloaded here.) This allows the parent
- ! to rewrite system calls and args on the fly.
+ ! reloaded from the kernel stack by syscall_call
+ ! below, so don't need to be reloaded here.)
+ ! This allows the parent to rewrite system calls
+ ! and args on the fly.
mov.l @(OFF_R4,r15), r4 ! arg0
mov.l @(OFF_R5,r15), r5
mov.l @(OFF_R6,r15), r6
@@ -357,8 +357,15 @@ syscall_call:
mov.l 3f, r8 ! Load the address of sys_call_table
add r8, r3
mov.l @r3, r8
+ mov.l @(OFF_R2,r15), r2
+ mov.l @(OFF_R1,r15), r1
+ mov.l @(OFF_R0,r15), r0
+ mov.l r2, @-r15
+ mov.l r1, @-r15
+ mov.l r0, @-r15
jsr @r8 ! jump to specific syscall handler
nop
+ add #12, r15
mov.l @(OFF_R0,r15), r12 ! save r0
mov.l r0, @(OFF_R0,r15) ! save the return value
!
diff --git a/arch/sh/kernel/ftrace.c b/arch/sh/kernel/ftrace.c
index 30e13196d35b..3c74f53db6db 100644
--- a/arch/sh/kernel/ftrace.c
+++ b/arch/sh/kernel/ftrace.c
@@ -272,11 +272,8 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
return ftrace_modify_code(rec->ip, old, new);
}
-int __init ftrace_dyn_arch_init(void *data)
+int __init ftrace_dyn_arch_init(void)
{
- /* The return code is retured via data */
- __raw_writel(0, (unsigned long)data);
-
return 0;
}
#endif /* CONFIG_DYNAMIC_FTRACE */
diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c
index 2ea4483fd722..be616ee0cf87 100644
--- a/arch/sh/kernel/idle.c
+++ b/arch/sh/kernel/idle.c
@@ -16,7 +16,6 @@
#include <linux/thread_info.h>
#include <linux/irqflags.h>
#include <linux/smp.h>
-#include <linux/cpuidle.h>
#include <linux/atomic.h>
#include <asm/pgalloc.h>
#include <asm/smp.h>
@@ -40,8 +39,7 @@ void arch_cpu_idle_dead(void)
void arch_cpu_idle(void)
{
- if (cpuidle_idle_call())
- sh_idle();
+ sh_idle();
}
void __init select_idle_routine(void)
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index 0833736afa32..65a1ecd77f96 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -217,19 +217,6 @@ void __init init_IRQ(void)
}
#ifdef CONFIG_HOTPLUG_CPU
-static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
-{
- struct irq_desc *desc = irq_to_desc(irq);
- struct irq_chip *chip = irq_data_get_irq_chip(data);
-
- printk(KERN_INFO "IRQ%u: moving from cpu%u to cpu%u\n",
- irq, data->node, cpu);
-
- raw_spin_lock_irq(&desc->lock);
- chip->irq_set_affinity(data, cpumask_of(cpu), false);
- raw_spin_unlock_irq(&desc->lock);
-}
-
/*
* The CPU has been marked offline. Migrate IRQs off this CPU. If
* the affinity settings do not allow other CPUs, force them onto any
@@ -250,11 +237,8 @@ void migrate_irqs(void)
irq, cpu);
cpumask_setall(data->affinity);
- newcpu = cpumask_any_and(data->affinity,
- cpu_online_mask);
}
-
- route_irq(data, irq, newcpu);
+ irq_set_affinity(irq, data->affinity);
}
}
}
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c
index 6af6e7c5cac8..594cd371aa28 100644
--- a/arch/sh/kernel/signal_32.c
+++ b/arch/sh/kernel/signal_32.c
@@ -148,11 +148,9 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *r0_p
return err;
}
-asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
+asmlinkage int sys_sigreturn(void)
{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+ struct pt_regs *regs = current_pt_regs();
struct sigframe __user *frame = (struct sigframe __user *)regs->regs[15];
sigset_t set;
int r0;
@@ -180,11 +178,9 @@ badframe:
return 0;
}
-asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
+asmlinkage int sys_rt_sigreturn(void)
{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+ struct pt_regs *regs = current_pt_regs();
struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs->regs[15];
sigset_t set;
int r0;
diff --git a/arch/sh/kernel/sys_sh32.c b/arch/sh/kernel/sys_sh32.c
index 497bab3a0401..b66d1c62eb19 100644
--- a/arch/sh/kernel/sys_sh32.c
+++ b/arch/sh/kernel/sys_sh32.c
@@ -21,17 +21,14 @@
* sys_pipe() is the normal C calling standard for creating
* a pipe. It's not the way Unix traditionally does this, though.
*/
-asmlinkage int sys_sh_pipe(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
+asmlinkage int sys_sh_pipe(void)
{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
int fd[2];
int error;
error = do_pipe_flags(fd, 0);
if (!error) {
- regs->regs[1] = fd[1];
+ current_pt_regs()->regs[1] = fd[1];
return fd[0];
}
return error;
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index 68e99f09171d..ff639342a8be 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -594,9 +594,7 @@ int is_dsp_inst(struct pt_regs *regs)
#endif /* CONFIG_SH_DSP */
#ifdef CONFIG_CPU_SH2A
-asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
+asmlinkage void do_divide_error(unsigned long r4)
{
siginfo_t info;
@@ -613,11 +611,9 @@ asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
}
#endif
-asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
+asmlinkage void do_reserved_inst(void)
{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+ struct pt_regs *regs = current_pt_regs();
unsigned long error_code;
struct task_struct *tsk = current;
@@ -701,11 +697,9 @@ static int emulate_branch(unsigned short inst, struct pt_regs *regs)
}
#endif
-asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
+asmlinkage void do_illegal_slot_inst(void)
{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+ struct pt_regs *regs = current_pt_regs();
unsigned long inst;
struct task_struct *tsk = current;
@@ -730,15 +724,12 @@ asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
die_if_no_fixup("illegal slot instruction", regs, inst);
}
-asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
+asmlinkage void do_exception_error(void)
{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
long ex;
ex = lookup_exception_vector();
- die_if_kernel("exception", regs, ex);
+ die_if_kernel("exception", current_pt_regs(), ex);
}
void per_cpu_trap_init(void)
diff --git a/arch/sh/math-emu/math.c b/arch/sh/math-emu/math.c
index b876780c1e1c..04aa55fa8c75 100644
--- a/arch/sh/math-emu/math.c
+++ b/arch/sh/math-emu/math.c
@@ -574,24 +574,6 @@ static int ieee_fpe_handler(struct pt_regs *regs)
return 0;
}
-asmlinkage void do_fpu_error(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs regs)
-{
- struct task_struct *tsk = current;
- siginfo_t info;
-
- if (ieee_fpe_handler (&regs))
- return;
-
- regs.pc += 2;
- info.si_signo = SIGFPE;
- info.si_errno = 0;
- info.si_code = FPE_FLTINV;
- info.si_addr = (void __user *)regs.pc;
- force_sig_info(SIGFPE, &info, tsk);
-}
-
/**
* fpu_init - Initialize FPU registers
* @fpu: Pointer to software emulated FPU registers.
diff --git a/arch/sh/mm/cache-debugfs.c b/arch/sh/mm/cache-debugfs.c
index 115725198038..777e50f33c00 100644
--- a/arch/sh/mm/cache-debugfs.c
+++ b/arch/sh/mm/cache-debugfs.c
@@ -36,7 +36,7 @@ static int cache_seq_show(struct seq_file *file, void *iter)
*/
jump_to_uncached();
- ccr = __raw_readl(CCR);
+ ccr = __raw_readl(SH_CCR);
if ((ccr & CCR_CACHE_ENABLE) == 0) {
back_to_cached();
diff --git a/arch/sh/mm/cache-sh2.c b/arch/sh/mm/cache-sh2.c
index defcf719f2e8..a74259f2f981 100644
--- a/arch/sh/mm/cache-sh2.c
+++ b/arch/sh/mm/cache-sh2.c
@@ -63,9 +63,9 @@ static void sh2__flush_invalidate_region(void *start, int size)
local_irq_save(flags);
jump_to_uncached();
- ccr = __raw_readl(CCR);
+ ccr = __raw_readl(SH_CCR);
ccr |= CCR_CACHE_INVALIDATE;
- __raw_writel(ccr, CCR);
+ __raw_writel(ccr, SH_CCR);
back_to_cached();
local_irq_restore(flags);
diff --git a/arch/sh/mm/cache-sh2a.c b/arch/sh/mm/cache-sh2a.c
index 949e2d3138a0..ee87d081259b 100644
--- a/arch/sh/mm/cache-sh2a.c
+++ b/arch/sh/mm/cache-sh2a.c
@@ -134,7 +134,8 @@ static void sh2a__flush_invalidate_region(void *start, int size)
/* If there are too many pages then just blow the cache */
if (((end - begin) >> PAGE_SHIFT) >= MAX_OCACHE_PAGES) {
- __raw_writel(__raw_readl(CCR) | CCR_OCACHE_INVALIDATE, CCR);
+ __raw_writel(__raw_readl(SH_CCR) | CCR_OCACHE_INVALIDATE,
+ SH_CCR);
} else {
for (v = begin; v < end; v += L1_CACHE_BYTES)
sh2a_invalidate_line(CACHE_OC_ADDRESS_ARRAY, v);
@@ -167,7 +168,8 @@ static void sh2a_flush_icache_range(void *args)
/* I-Cache invalidate */
/* If there are too many pages then just blow the cache */
if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) {
- __raw_writel(__raw_readl(CCR) | CCR_ICACHE_INVALIDATE, CCR);
+ __raw_writel(__raw_readl(SH_CCR) | CCR_ICACHE_INVALIDATE,
+ SH_CCR);
} else {
for (v = start; v < end; v += L1_CACHE_BYTES)
sh2a_invalidate_line(CACHE_IC_ADDRESS_ARRAY, v);
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c
index 0e529285b28d..51d8f7f31d1d 100644
--- a/arch/sh/mm/cache-sh4.c
+++ b/arch/sh/mm/cache-sh4.c
@@ -133,9 +133,9 @@ static void flush_icache_all(void)
jump_to_uncached();
/* Flush I-cache */
- ccr = __raw_readl(CCR);
+ ccr = __raw_readl(SH_CCR);
ccr |= CCR_CACHE_ICI;
- __raw_writel(ccr, CCR);
+ __raw_writel(ccr, SH_CCR);
/*
* back_to_cached() will take care of the barrier for us, don't add
diff --git a/arch/sh/mm/cache-shx3.c b/arch/sh/mm/cache-shx3.c
index c0adbee97b5f..24c58b7dc022 100644
--- a/arch/sh/mm/cache-shx3.c
+++ b/arch/sh/mm/cache-shx3.c
@@ -19,7 +19,7 @@ void __init shx3_cache_init(void)
{
unsigned int ccr;
- ccr = __raw_readl(CCR);
+ ccr = __raw_readl(SH_CCR);
/*
* If we've got cache aliases, resolve them in hardware.
@@ -40,5 +40,5 @@ void __init shx3_cache_init(void)
ccr |= CCR_CACHE_IBE;
#endif
- writel_uncached(ccr, CCR);
+ writel_uncached(ccr, SH_CCR);
}
diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c
index 616966a96cba..097c2cdd117f 100644
--- a/arch/sh/mm/cache.c
+++ b/arch/sh/mm/cache.c
@@ -285,8 +285,8 @@ void __init cpu_cache_init(void)
{
unsigned int cache_disabled = 0;
-#ifdef CCR
- cache_disabled = !(__raw_readl(CCR) & CCR_CACHE_ENABLE);
+#ifdef SH_CCR
+ cache_disabled = !(__raw_readl(SH_CCR) & CCR_CACHE_ENABLE);
#endif
compute_alias(&boot_cpu_data.icache);
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index c51efdcd07a2..7d8b7e94b93b 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -27,7 +27,7 @@ config SPARC
select RTC_DRV_M48T59
select HAVE_DMA_ATTRS
select HAVE_DMA_API_DEBUG
- select HAVE_ARCH_JUMP_LABEL
+ select HAVE_ARCH_JUMP_LABEL if SPARC64
select GENERIC_IRQ_SHOW
select ARCH_WANT_IPC_PARSE_VERSION
select GENERIC_PCI_IOMAP
diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild
index 4b60a0c325ec..a45821818003 100644
--- a/arch/sparc/include/asm/Kbuild
+++ b/arch/sparc/include/asm/Kbuild
@@ -6,15 +6,16 @@ generic-y += cputime.h
generic-y += div64.h
generic-y += emergency-restart.h
generic-y += exec.h
-generic-y += linkage.h
-generic-y += local64.h
-generic-y += mutex.h
+generic-y += hash.h
generic-y += irq_regs.h
+generic-y += linkage.h
generic-y += local.h
+generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += module.h
+generic-y += mutex.h
+generic-y += preempt.h
generic-y += serial.h
generic-y += trace_clock.h
generic-y += types.h
generic-y += word-at-a-time.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/sparc/include/asm/smp_64.h b/arch/sparc/include/asm/smp_64.h
index dd3bef4b9896..05710393959f 100644
--- a/arch/sparc/include/asm/smp_64.h
+++ b/arch/sparc/include/asm/smp_64.h
@@ -32,7 +32,6 @@
DECLARE_PER_CPU(cpumask_t, cpu_sibling_map);
extern cpumask_t cpu_core_map[NR_CPUS];
-extern int sparc64_multi_core;
extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
diff --git a/arch/sparc/include/asm/topology_64.h b/arch/sparc/include/asm/topology_64.h
index 1754390a426f..a2d10fc64faf 100644
--- a/arch/sparc/include/asm/topology_64.h
+++ b/arch/sparc/include/asm/topology_64.h
@@ -42,8 +42,6 @@ static inline int pcibus_to_node(struct pci_bus *pbus)
#define topology_core_id(cpu) (cpu_data(cpu).core_id)
#define topology_core_cpumask(cpu) (&cpu_core_map[cpu])
#define topology_thread_cpumask(cpu) (&per_cpu(cpu_sibling_map, cpu))
-#define mc_capable() (sparc64_multi_core)
-#define smt_capable() (sparc64_multi_core)
#endif /* CONFIG_SMP */
extern cpumask_t cpu_core_map[NR_CPUS];
diff --git a/arch/sparc/kernel/ftrace.c b/arch/sparc/kernel/ftrace.c
index 03ab022e51c5..0a2d2ddff543 100644
--- a/arch/sparc/kernel/ftrace.c
+++ b/arch/sparc/kernel/ftrace.c
@@ -82,12 +82,8 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
return ftrace_modify_code(ip, old, new);
}
-int __init ftrace_dyn_arch_init(void *data)
+int __init ftrace_dyn_arch_init(void)
{
- unsigned long *p = data;
-
- *p = 0;
-
return 0;
}
#endif
diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c
index 88aaaa57bb64..e16c4157e1ae 100644
--- a/arch/sparc/kernel/leon_pci.c
+++ b/arch/sparc/kernel/leon_pci.c
@@ -99,11 +99,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
return res->start;
}
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
- return pci_enable_resources(dev, mask);
-}
-
/* in/out routines taken from pcic.c
*
* This probably belongs here rather than ioport.c because
diff --git a/arch/sparc/kernel/leon_pci_grpci2.c b/arch/sparc/kernel/leon_pci_grpci2.c
index 5f0402aab7fb..24d6a4446349 100644
--- a/arch/sparc/kernel/leon_pci_grpci2.c
+++ b/arch/sparc/kernel/leon_pci_grpci2.c
@@ -8,6 +8,7 @@
#include <linux/of_device.h>
#include <linux/kernel.h>
#include <linux/pci.h>
+#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/export.h>
#include <asm/io.h>
diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c
index b90bf23e3aab..a1a4400d4025 100644
--- a/arch/sparc/kernel/mdesc.c
+++ b/arch/sparc/kernel/mdesc.c
@@ -896,10 +896,6 @@ void mdesc_fill_in_cpu_data(cpumask_t *mask)
mdesc_iterate_over_cpus(fill_in_one_cpu, NULL, mask);
-#ifdef CONFIG_SMP
- sparc64_multi_core = 1;
-#endif
-
hp = mdesc_grab();
set_core_ids(hp);
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c
index 32a280ec38c1..d7b4967f8fa6 100644
--- a/arch/sparc/kernel/process_64.c
+++ b/arch/sparc/kernel/process_64.c
@@ -58,9 +58,12 @@ void arch_cpu_idle(void)
{
if (tlb_type != hypervisor) {
touch_nmi_watchdog();
+ local_irq_enable();
} else {
unsigned long pstate;
+ local_irq_enable();
+
/* The sun4v sleeping code requires that we have PSTATE.IE cleared over
* the cpu sleep hypervisor call.
*/
@@ -82,7 +85,6 @@ void arch_cpu_idle(void)
: "=&r" (pstate)
: "i" (PSTATE_IE));
}
- local_irq_enable();
}
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/sparc/kernel/prom_64.c b/arch/sparc/kernel/prom_64.c
index 6b39125eb927..9a690d39c01b 100644
--- a/arch/sparc/kernel/prom_64.c
+++ b/arch/sparc/kernel/prom_64.c
@@ -555,9 +555,6 @@ static void *fill_in_one_cpu(struct device_node *dp, int cpuid, int arg)
cpu_data(cpuid).core_id = portid + 1;
cpu_data(cpuid).proc_id = portid;
-#ifdef CONFIG_SMP
- sparc64_multi_core = 1;
-#endif
} else {
cpu_data(cpuid).dcache_size =
of_getintprop_default(dp, "dcache-size", 16 * 1024);
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c
index b085311dcd0e..9781048161ab 100644
--- a/arch/sparc/kernel/smp_64.c
+++ b/arch/sparc/kernel/smp_64.c
@@ -53,8 +53,6 @@
#include "cpumap.h"
-int sparc64_multi_core __read_mostly;
-
DEFINE_PER_CPU(cpumask_t, cpu_sibling_map) = CPU_MASK_NONE;
cpumask_t cpu_core_map[NR_CPUS] __read_mostly =
{ [0 ... NR_CPUS-1] = CPU_MASK_NONE };
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
index c5ade9d27a1d..8bb3b3fddea7 100644
--- a/arch/sparc/kernel/sun4m_irq.c
+++ b/arch/sparc/kernel/sun4m_irq.c
@@ -9,6 +9,8 @@
* Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
*/
+#include <linux/slab.h>
+
#include <asm/timer.h>
#include <asm/traps.h>
#include <asm/pgalloc.h>
diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S
index 87729fff13b9..33a17e7b3ccd 100644
--- a/arch/sparc/kernel/syscalls.S
+++ b/arch/sparc/kernel/syscalls.S
@@ -189,7 +189,8 @@ linux_sparc_syscall32:
mov %i0, %l5 ! IEU1
5: call %l7 ! CTI Group brk forced
srl %i5, 0, %o5 ! IEU1
- ba,a,pt %xcc, 3f
+ ba,pt %xcc, 3f
+ sra %o0, 0, %o0
/* Linux native system calls enter here... */
.align 32
@@ -217,7 +218,6 @@ linux_sparc_syscall:
3: stx %o0, [%sp + PTREGS_OFF + PT_V9_I0]
ret_sys_call:
ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %g3
- sra %o0, 0, %o0
mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
sllx %g2, 32, %g2
diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c
index c3d82b5f54ca..3fddf64c7fc6 100644
--- a/arch/sparc/kernel/time_64.c
+++ b/arch/sparc/kernel/time_64.c
@@ -659,8 +659,7 @@ static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val
ft->clock_tick_ref = cpu_data(cpu).clock_tick;
}
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
- (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
- (val == CPUFREQ_RESUMECHANGE)) {
+ (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
cpu_data(cpu).clock_tick =
cpufreq_scale(ft->clock_tick_ref,
ft->ref_freq,
@@ -733,7 +732,7 @@ void __irq_entry timer_interrupt(int irq, struct pt_regs *regs)
irq_enter();
local_cpu_data().irq0_irqs++;
- kstat_incr_irqs_this_cpu(0, irq_to_desc(0));
+ kstat_incr_irq_this_cpu(0);
if (unlikely(!evt->event_handler)) {
printk(KERN_WARNING
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index 869023abe5a4..cfbe53c17b0d 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -14,6 +14,7 @@
#include <linux/pagemap.h>
#include <linux/vmalloc.h>
#include <linux/kdebug.h>
+#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/log2.h>
@@ -62,6 +63,7 @@ extern unsigned long last_valid_pfn;
static pgd_t *srmmu_swapper_pg_dir;
const struct sparc32_cachetlb_ops *sparc32_cachetlb_ops;
+EXPORT_SYMBOL(sparc32_cachetlb_ops);
#ifdef CONFIG_SMP
const struct sparc32_cachetlb_ops *local_ops;
diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c
index 3b3a360b429a..f5d506fdddad 100644
--- a/arch/sparc/mm/tsb.c
+++ b/arch/sparc/mm/tsb.c
@@ -273,7 +273,7 @@ void __init pgtable_cache_init(void)
prom_halt();
}
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < ARRAY_SIZE(tsb_cache_names); i++) {
unsigned long size = 8192 << i;
const char *name = tsb_cache_names[i];
diff --git a/arch/sparc/net/bpf_jit_comp.c b/arch/sparc/net/bpf_jit_comp.c
index 01fe9946d388..a82c6b2a9780 100644
--- a/arch/sparc/net/bpf_jit_comp.c
+++ b/arch/sparc/net/bpf_jit_comp.c
@@ -618,7 +618,7 @@ void bpf_jit_compile(struct sk_filter *fp)
emit_load16(r_A, struct net_device, type, r_A);
break;
case BPF_S_ANC_RXHASH:
- emit_skb_load32(rxhash, r_A);
+ emit_skb_load32(hash, r_A);
break;
case BPF_S_ANC_VLAN_TAG:
case BPF_S_ANC_VLAN_TAG_PRESENT:
@@ -809,6 +809,7 @@ cond_branch: f_offset = addrs[i + filter[i].jf];
if (image) {
bpf_flush_icache(image, image + proglen);
fp->bpf_func = (void *)image;
+ fp->jited = 1;
}
out:
kfree(addrs);
@@ -817,7 +818,7 @@ out:
void bpf_jit_free(struct sk_filter *fp)
{
- if (fp->bpf_func != sk_run_filter)
+ if (fp->jited)
module_free(NULL, fp->bpf_func);
kfree(fp);
}
diff --git a/arch/tile/include/asm/Kbuild b/arch/tile/include/asm/Kbuild
index 3793c75e45d9..0aa5675e7025 100644
--- a/arch/tile/include/asm/Kbuild
+++ b/arch/tile/include/asm/Kbuild
@@ -11,6 +11,7 @@ generic-y += errno.h
generic-y += exec.h
generic-y += fb.h
generic-y += fcntl.h
+generic-y += hash.h
generic-y += hw_irq.h
generic-y += ioctl.h
generic-y += ioctls.h
@@ -18,12 +19,14 @@ generic-y += ipcbuf.h
generic-y += irq_regs.h
generic-y += local.h
generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += msgbuf.h
generic-y += mutex.h
generic-y += param.h
generic-y += parport.h
generic-y += poll.h
generic-y += posix_types.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += sembuf.h
@@ -38,5 +41,3 @@ generic-y += termios.h
generic-y += trace_clock.h
generic-y += types.h
generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/tile/kernel/ftrace.c b/arch/tile/kernel/ftrace.c
index f1c452092eeb..8d52d83cc516 100644
--- a/arch/tile/kernel/ftrace.c
+++ b/arch/tile/kernel/ftrace.c
@@ -167,10 +167,8 @@ int ftrace_make_nop(struct module *mod,
return ret;
}
-int __init ftrace_dyn_arch_init(void *data)
+int __init ftrace_dyn_arch_init(void)
{
- *(unsigned long *)data = 0;
-
return 0;
}
#endif /* CONFIG_DYNAMIC_FTRACE */
diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c
index a97a6452b812..077b7bc437e5 100644
--- a/arch/tile/kernel/pci_gx.c
+++ b/arch/tile/kernel/pci_gx.c
@@ -1065,18 +1065,6 @@ char *__init pcibios_setup(char *str)
}
/*
- * Enable memory address decoding, as appropriate, for the
- * device described by the 'dev' struct.
- *
- * This is called from the generic PCI layer, and can be called
- * for bridges or endpoints.
- */
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
- return pci_enable_resources(dev, mask);
-}
-
-/*
* Called for each device after PCI setup is done.
* We initialize the PCI device capabilities conservatively, assuming that
* all devices can only address the 32-bit DMA space. The exception here is
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 39f186252e02..7d26d9c0b2fb 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -240,7 +240,7 @@ static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&lp->lock, flags);
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
return NETDEV_TX_OK;
}
diff --git a/arch/um/include/asm/Kbuild b/arch/um/include/asm/Kbuild
index 88a330dcdede..a5e4b6068213 100644
--- a/arch/um/include/asm/Kbuild
+++ b/arch/um/include/asm/Kbuild
@@ -1,8 +1,28 @@
-generic-y += bug.h cputime.h device.h emergency-restart.h futex.h hardirq.h
-generic-y += hw_irq.h irq_regs.h kdebug.h percpu.h sections.h topology.h xor.h
-generic-y += ftrace.h pci.h io.h param.h delay.h mutex.h current.h exec.h
-generic-y += switch_to.h clkdev.h
-generic-y += trace_clock.h
-generic-y += preempt.h
-generic-y += hash.h
generic-y += barrier.h
+generic-y += bug.h
+generic-y += clkdev.h
+generic-y += cputime.h
+generic-y += current.h
+generic-y += delay.h
+generic-y += device.h
+generic-y += emergency-restart.h
+generic-y += exec.h
+generic-y += ftrace.h
+generic-y += futex.h
+generic-y += hardirq.h
+generic-y += hash.h
+generic-y += hw_irq.h
+generic-y += io.h
+generic-y += irq_regs.h
+generic-y += kdebug.h
+generic-y += mcs_spinlock.h
+generic-y += mutex.h
+generic-y += param.h
+generic-y += pci.h
+generic-y += percpu.h
+generic-y += preempt.h
+generic-y += sections.h
+generic-y += switch_to.h
+generic-y += topology.h
+generic-y += trace_clock.h
+generic-y += xor.h
diff --git a/arch/unicore32/include/asm/Kbuild b/arch/unicore32/include/asm/Kbuild
index 3ef4f9d9bf5d..1e5fb872a4aa 100644
--- a/arch/unicore32/include/asm/Kbuild
+++ b/arch/unicore32/include/asm/Kbuild
@@ -16,6 +16,7 @@ generic-y += fcntl.h
generic-y += ftrace.h
generic-y += futex.h
generic-y += hardirq.h
+generic-y += hash.h
generic-y += hw_irq.h
generic-y += ioctl.h
generic-y += ioctls.h
@@ -24,6 +25,7 @@ generic-y += irq_regs.h
generic-y += kdebug.h
generic-y += kmap_types.h
generic-y += local.h
+generic-y += mcs_spinlock.h
generic-y += mman.h
generic-y += module.h
generic-y += msgbuf.h
@@ -32,6 +34,7 @@ generic-y += parport.h
generic-y += percpu.h
generic-y += poll.h
generic-y += posix_types.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += sections.h
@@ -60,5 +63,3 @@ generic-y += unaligned.h
generic-y += user.h
generic-y += vga.h
generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 0af5250d914f..f73071742975 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -107,9 +107,9 @@ config X86
select HAVE_ARCH_SOFT_DIRTY
select CLOCKSOURCE_WATCHDOG
select GENERIC_CLOCKEVENTS
- select ARCH_CLOCKSOURCE_DATA if X86_64
+ select ARCH_CLOCKSOURCE_DATA
select GENERIC_CLOCKEVENTS_BROADCAST if X86_64 || (X86_32 && X86_LOCAL_APIC)
- select GENERIC_TIME_VSYSCALL if X86_64
+ select GENERIC_TIME_VSYSCALL
select KTIME_SCALAR if X86_32
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
@@ -127,6 +127,7 @@ config X86
select HAVE_DEBUG_STACKOVERFLOW
select HAVE_IRQ_EXIT_ON_IRQ_STACK if X86_64
select HAVE_CC_STACKPROTECTOR
+ select GENERIC_CPU_AUTOPROBE
config INSTRUCTION_DECODER
def_bool y
@@ -195,9 +196,6 @@ config ARCH_HAS_CPU_RELAX
config ARCH_HAS_CACHE_LINE_SIZE
def_bool y
-config ARCH_HAS_CPU_AUTOPROBE
- def_bool y
-
config HAVE_SETUP_PER_CPU_AREA
def_bool y
@@ -346,12 +344,9 @@ config X86_EXTENDED_PLATFORM
for the following (non-PC) 32 bit x86 platforms:
Goldfish (Android emulator)
AMD Elan
- NUMAQ (IBM/Sequent)
RDC R-321x SoC
SGI 320/540 (Visual Workstation)
STA2X11-based (e.g. Northville)
- Summit/EXA (IBM x440)
- Unisys ES7000 IA32 series
Moorestown MID devices
If you have one of these systems, or if you want to build a
@@ -489,49 +484,22 @@ config X86_32_NON_STANDARD
depends on X86_32 && SMP
depends on X86_EXTENDED_PLATFORM
---help---
- This option compiles in the NUMAQ, Summit, bigsmp, ES7000,
- STA2X11, default subarchitectures. It is intended for a generic
- binary kernel. If you select them all, kernel will probe it
- one by one and will fallback to default.
+ This option compiles in the bigsmp and STA2X11 default
+ subarchitectures. It is intended for a generic binary
+ kernel. If you select them all, kernel will probe it one by
+ one and will fallback to default.
# Alphabetically sorted list of Non standard 32 bit platforms
-config X86_NUMAQ
- bool "NUMAQ (IBM/Sequent)"
- depends on X86_32_NON_STANDARD
- depends on PCI
- select NUMA
- select X86_MPPARSE
- ---help---
- This option is used for getting Linux to run on a NUMAQ (IBM/Sequent)
- NUMA multiquad box. This changes the way that processors are
- bootstrapped, and uses Clustered Logical APIC addressing mode instead
- of Flat Logical. You will need a new lynxer.elf file to flash your
- firmware with - send email to <Martin.Bligh@us.ibm.com>.
-
config X86_SUPPORTS_MEMORY_FAILURE
def_bool y
# MCE code calls memory_failure():
depends on X86_MCE
# On 32-bit this adds too big of NODES_SHIFT and we run out of page flags:
- depends on !X86_NUMAQ
# On 32-bit SPARSEMEM adds too big of SECTIONS_WIDTH:
depends on X86_64 || !SPARSEMEM
select ARCH_SUPPORTS_MEMORY_FAILURE
-config X86_VISWS
- bool "SGI 320/540 (Visual Workstation)"
- depends on X86_32 && PCI && X86_MPPARSE && PCI_GODIRECT
- depends on X86_32_NON_STANDARD
- ---help---
- The SGI Visual Workstation series is an IA32-based workstation
- based on SGI systems chips with some legacy PC hardware attached.
-
- Say Y here to create a kernel to run on the SGI 320 or 540.
-
- A kernel compiled for the Visual Workstation will run on general
- PCs as well. See <file:Documentation/sgi-visws.txt> for details.
-
config STA2X11
bool "STA2X11 Companion Chip Support"
depends on X86_32_NON_STANDARD && PCI
@@ -548,20 +516,6 @@ config STA2X11
option is selected the kernel will still be able to boot on
standard PC machines.
-config X86_SUMMIT
- bool "Summit/EXA (IBM x440)"
- depends on X86_32_NON_STANDARD
- ---help---
- This option is needed for IBM systems that use the Summit/EXA chipset.
- In particular, it is needed for the x440.
-
-config X86_ES7000
- bool "Unisys ES7000 IA32 series"
- depends on X86_32_NON_STANDARD && X86_BIGSMP
- ---help---
- Support for Unisys ES7000 systems. Say 'Y' here if this kernel is
- supposed to run on an IA32-based Unisys ES7000 system.
-
config X86_32_IRIS
tristate "Eurobraille/Iris poweroff module"
depends on X86_32
@@ -684,14 +638,6 @@ config MEMTEST
memtest=4, mean do 4 test patterns.
If you are unsure how to answer this question, answer N.
-config X86_SUMMIT_NUMA
- def_bool y
- depends on X86_32 && NUMA && X86_32_NON_STANDARD
-
-config X86_CYCLONE_TIMER
- def_bool y
- depends on X86_SUMMIT
-
source "arch/x86/Kconfig.cpu"
config HPET_TIMER
@@ -820,7 +766,7 @@ config NR_CPUS
range 2 8192 if SMP && !MAXSMP && CPUMASK_OFFSTACK && X86_64
default "1" if !SMP
default "8192" if MAXSMP
- default "32" if SMP && (X86_NUMAQ || X86_SUMMIT || X86_BIGSMP || X86_ES7000)
+ default "32" if SMP && X86_BIGSMP
default "8" if SMP
---help---
This allows you to specify the maximum number of CPUs which this
@@ -884,10 +830,6 @@ config X86_IO_APIC
def_bool y
depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_IOAPIC || PCI_MSI
-config X86_VISWS_APIC
- def_bool y
- depends on X86_32 && X86_VISWS
-
config X86_REROUTE_FOR_BROKEN_BOOT_IRQS
bool "Reroute for broken boot IRQs"
depends on X86_IO_APIC
@@ -1105,13 +1047,11 @@ config X86_CPUID
choice
prompt "High Memory Support"
- default HIGHMEM64G if X86_NUMAQ
default HIGHMEM4G
depends on X86_32
config NOHIGHMEM
bool "off"
- depends on !X86_NUMAQ
---help---
Linux can use up to 64 Gigabytes of physical memory on x86 systems.
However, the address space of 32-bit x86 processors is only 4
@@ -1148,7 +1088,6 @@ config NOHIGHMEM
config HIGHMEM4G
bool "4GB"
- depends on !X86_NUMAQ
---help---
Select this if you have a 32-bit processor and between 1 and 4
gigabytes of physical RAM.
@@ -1240,8 +1179,8 @@ config DIRECT_GBPAGES
config NUMA
bool "Numa Memory Allocation and Scheduler Support"
depends on SMP
- depends on X86_64 || (X86_32 && HIGHMEM64G && (X86_NUMAQ || X86_BIGSMP || X86_SUMMIT && ACPI))
- default y if (X86_NUMAQ || X86_SUMMIT || X86_BIGSMP)
+ depends on X86_64 || (X86_32 && HIGHMEM64G && X86_BIGSMP)
+ default y if X86_BIGSMP
---help---
Enable NUMA (Non Uniform Memory Access) support.
@@ -1252,15 +1191,11 @@ config NUMA
For 64-bit this is recommended if the system is Intel Core i7
(or later), AMD Opteron, or EM64T NUMA.
- For 32-bit this is only needed on (rare) 32-bit-only platforms
- that support NUMA topologies, such as NUMAQ / Summit, or if you
- boot a 32-bit kernel on a 64-bit NUMA platform.
+ For 32-bit this is only needed if you boot a 32-bit
+ kernel on a 64-bit NUMA platform.
Otherwise, you should say N.
-comment "NUMA (Summit) requires SMP, 64GB highmem support, ACPI"
- depends on X86_32 && X86_SUMMIT && (!HIGHMEM64G || !ACPI)
-
config AMD_NUMA
def_bool y
prompt "Old style AMD Opteron NUMA detection"
@@ -1302,7 +1237,6 @@ config NODES_SHIFT
range 1 10
default "10" if MAXSMP
default "6" if X86_64
- default "4" if X86_NUMAQ
default "3"
depends on NEED_MULTIPLE_NODES
---help---
@@ -1585,6 +1519,20 @@ config EFI_STUB
See Documentation/efi-stub.txt for more information.
+config EFI_MIXED
+ bool "EFI mixed-mode support"
+ depends on EFI_STUB && X86_64
+ ---help---
+ Enabling this feature allows a 64-bit kernel to be booted
+ on a 32-bit firmware, provided that your CPU supports 64-bit
+ mode.
+
+ Note that it is not possible to boot a mixed-mode enabled
+ kernel via the EFI boot stub - a bootloader that supports
+ the EFI handover protocol must be used.
+
+ If unsure, say N.
+
config SECCOMP
def_bool y
prompt "Enable seccomp to safely compute untrusted bytecode"
@@ -1836,17 +1784,29 @@ config DEBUG_HOTPLUG_CPU0
If unsure, say N.
config COMPAT_VDSO
- def_bool y
- prompt "Compat VDSO support"
+ def_bool n
+ prompt "Disable the 32-bit vDSO (needed for glibc 2.3.3)"
depends on X86_32 || IA32_EMULATION
---help---
- Map the 32-bit VDSO to the predictable old-style address too.
+ Certain buggy versions of glibc will crash if they are
+ presented with a 32-bit vDSO that is not mapped at the address
+ indicated in its segment table.
- Say N here if you are running a sufficiently recent glibc
- version (2.3.3 or later), to remove the high-mapped
- VDSO mapping and to exclusively use the randomized VDSO.
+ The bug was introduced by f866314b89d56845f55e6f365e18b31ec978ec3a
+ and fixed by 3b3ddb4f7db98ec9e912ccdf54d35df4aa30e04a and
+ 49ad572a70b8aeb91e57483a11dd1b77e31c4468. Glibc 2.3.3 is
+ the only released version with the bug, but OpenSUSE 9
+ contains a buggy "glibc 2.3.2".
- If unsure, say Y.
+ The symptom of the bug is that everything crashes on startup, saying:
+ dl_main: Assertion `(void *) ph->p_vaddr == _rtld_local._dl_sysinfo_dso' failed!
+
+ Saying Y here changes the default value of the vdso32 boot
+ option from 1 to 0, which turns off the 32-bit vDSO entirely.
+ This works around the glibc bug but hurts performance.
+
+ If unsure, say N: if you are compiling your own kernel, you
+ are unlikely to be using a buggy version of glibc.
config CMDLINE_BOOL
bool "Built-in kernel command line"
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
index c026cca5602c..6983314c8b37 100644
--- a/arch/x86/Kconfig.cpu
+++ b/arch/x86/Kconfig.cpu
@@ -341,10 +341,6 @@ config X86_USE_3DNOW
def_bool y
depends on (MCYRIXIII || MK7 || MGEODE_LX) && !UML
-config X86_OOSTORE
- def_bool y
- depends on (MWINCHIP3D || MWINCHIPC6) && MTRR
-
#
# P6_NOPs are a relatively minor optimization that require a family >=
# 6 processor, except that it is broken on certain VIA chips.
@@ -363,7 +359,7 @@ config X86_P6_NOP
config X86_TSC
def_bool y
- depends on ((MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MATOM) && !X86_NUMAQ) || X86_64
+ depends on (MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MATOM) || X86_64
config X86_CMPXCHG64
def_bool y
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 321a52ccf63a..61bd2ad94281 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -81,6 +81,15 @@ config X86_PTDUMP
kernel.
If in doubt, say "N"
+config EFI_PGT_DUMP
+ bool "Dump the EFI pagetable"
+ depends on EFI && X86_PTDUMP
+ ---help---
+ Enable this if you want to dump the EFI page table before
+ enabling virtual mode. This can be used to debug miscellaneous
+ issues with the mapping of the EFI runtime regions into that
+ table.
+
config DEBUG_RODATA
bool "Write protect kernel read-only data structures"
default y
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index eeda43abed6e..3b9348a0c1a4 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -82,8 +82,8 @@ else
KBUILD_AFLAGS += -m64
KBUILD_CFLAGS += -m64
- # Don't autogenerate MMX or SSE instructions
- KBUILD_CFLAGS += -mno-mmx -mno-sse
+ # Don't autogenerate traditional x87, MMX or SSE instructions
+ KBUILD_CFLAGS += -mno-mmx -mno-sse -mno-80387 -mno-fp-ret-in-387
# Use -mpreferred-stack-boundary=3 if supported.
KBUILD_CFLAGS += $(call cc-option,-mpreferred-stack-boundary=3)
@@ -152,6 +152,7 @@ cfi-sections := $(call as-instr,.cfi_sections .debug_frame,-DCONFIG_AS_CFI_SECTI
# does binutils support specific instructions?
asinstr := $(call as-instr,fxsaveq (%rax),-DCONFIG_AS_FXSAVEQ=1)
+asinstr += $(call as-instr,crc32l %eax$(comma)%eax,-DCONFIG_AS_CRC32=1)
avx_instr := $(call as-instr,vxorps %ymm0$(comma)%ymm1$(comma)%ymm2,-DCONFIG_AS_AVX=1)
avx2_instr :=$(call as-instr,vpbroadcastb %xmm0$(comma)%ymm1,-DCONFIG_AS_AVX2=1)
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
index 878df7e88cd4..abb9eba61b50 100644
--- a/arch/x86/boot/Makefile
+++ b/arch/x86/boot/Makefile
@@ -80,7 +80,7 @@ targets += voffset.h
$(obj)/voffset.h: vmlinux FORCE
$(call if_changed,voffset)
-sed-zoffset := -e 's/^\([0-9a-fA-F]*\) . \(startup_32\|startup_64\|efi_pe_entry\|efi_stub_entry\|input_data\|_end\|z_.*\)$$/\#define ZO_\2 0x\1/p'
+sed-zoffset := -e 's/^\([0-9a-fA-F]*\) . \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|input_data\|_end\|z_.*\)$$/\#define ZO_\2 0x\1/p'
quiet_cmd_zoffset = ZOFFSET $@
cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@
diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
index 50f8c5e0f37e..bd49ec61255c 100644
--- a/arch/x86/boot/boot.h
+++ b/arch/x86/boot/boot.h
@@ -177,14 +177,6 @@ static inline void wrgs32(u32 v, addr_t addr)
}
/* Note: these only return true/false, not a signed return value! */
-static inline int memcmp(const void *s1, const void *s2, size_t len)
-{
- u8 diff;
- asm("repe; cmpsb; setnz %0"
- : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len));
- return diff;
-}
-
static inline int memcmp_fs(const void *s1, addr_t s2, size_t len)
{
u8 diff;
@@ -228,11 +220,6 @@ void copy_to_fs(addr_t dst, void *src, size_t len);
void *copy_from_fs(void *dst, addr_t src, size_t len);
void copy_to_gs(addr_t dst, void *src, size_t len);
void *copy_from_gs(void *dst, addr_t src, size_t len);
-void *memcpy(void *dst, void *src, size_t len);
-void *memset(void *dst, int c, size_t len);
-
-#define memcpy(d,s,l) __builtin_memcpy(d,s,l)
-#define memset(d,c,l) __builtin_memset(d,c,l)
/* a20.c */
int enable_a20(void);
diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c
index 90a21f430117..4dbf967da50d 100644
--- a/arch/x86/boot/compressed/aslr.c
+++ b/arch/x86/boot/compressed/aslr.c
@@ -111,7 +111,7 @@ struct mem_vector {
};
#define MEM_AVOID_MAX 5
-struct mem_vector mem_avoid[MEM_AVOID_MAX];
+static struct mem_vector mem_avoid[MEM_AVOID_MAX];
static bool mem_contains(struct mem_vector *region, struct mem_vector *item)
{
@@ -180,7 +180,7 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
}
/* Does this memory vector overlap a known avoided area? */
-bool mem_avoid_overlap(struct mem_vector *img)
+static bool mem_avoid_overlap(struct mem_vector *img)
{
int i;
@@ -192,8 +192,9 @@ bool mem_avoid_overlap(struct mem_vector *img)
return false;
}
-unsigned long slots[CONFIG_RANDOMIZE_BASE_MAX_OFFSET / CONFIG_PHYSICAL_ALIGN];
-unsigned long slot_max = 0;
+static unsigned long slots[CONFIG_RANDOMIZE_BASE_MAX_OFFSET /
+ CONFIG_PHYSICAL_ALIGN];
+static unsigned long slot_max;
static void slots_append(unsigned long addr)
{
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index a7677babf946..1e6146137f8e 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -19,10 +19,272 @@
static efi_system_table_t *sys_table;
+static struct efi_config *efi_early;
+
+#define efi_call_early(f, ...) \
+ efi_early->call(efi_early->f, __VA_ARGS__);
+
+#define BOOT_SERVICES(bits) \
+static void setup_boot_services##bits(struct efi_config *c) \
+{ \
+ efi_system_table_##bits##_t *table; \
+ efi_boot_services_##bits##_t *bt; \
+ \
+ table = (typeof(table))sys_table; \
+ \
+ c->text_output = table->con_out; \
+ \
+ bt = (typeof(bt))(unsigned long)(table->boottime); \
+ \
+ c->allocate_pool = bt->allocate_pool; \
+ c->allocate_pages = bt->allocate_pages; \
+ c->get_memory_map = bt->get_memory_map; \
+ c->free_pool = bt->free_pool; \
+ c->free_pages = bt->free_pages; \
+ c->locate_handle = bt->locate_handle; \
+ c->handle_protocol = bt->handle_protocol; \
+ c->exit_boot_services = bt->exit_boot_services; \
+}
+BOOT_SERVICES(32);
+BOOT_SERVICES(64);
-#include "../../../../drivers/firmware/efi/efi-stub-helper.c"
+static void efi_printk(efi_system_table_t *, char *);
+static void efi_char16_printk(efi_system_table_t *, efi_char16_t *);
+
+static efi_status_t
+__file_size32(void *__fh, efi_char16_t *filename_16,
+ void **handle, u64 *file_sz)
+{
+ efi_file_handle_32_t *h, *fh = __fh;
+ efi_file_info_t *info;
+ efi_status_t status;
+ efi_guid_t info_guid = EFI_FILE_INFO_ID;
+ u32 info_sz;
+
+ status = efi_early->call((unsigned long)fh->open, fh, &h, filename_16,
+ EFI_FILE_MODE_READ, (u64)0);
+ if (status != EFI_SUCCESS) {
+ efi_printk(sys_table, "Failed to open file: ");
+ efi_char16_printk(sys_table, filename_16);
+ efi_printk(sys_table, "\n");
+ return status;
+ }
+
+ *handle = h;
+
+ info_sz = 0;
+ status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
+ &info_sz, NULL);
+ if (status != EFI_BUFFER_TOO_SMALL) {
+ efi_printk(sys_table, "Failed to get file info size\n");
+ return status;
+ }
+
+grow:
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+ info_sz, (void **)&info);
+ if (status != EFI_SUCCESS) {
+ efi_printk(sys_table, "Failed to alloc mem for file info\n");
+ return status;
+ }
+
+ status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
+ &info_sz, info);
+ if (status == EFI_BUFFER_TOO_SMALL) {
+ efi_call_early(free_pool, info);
+ goto grow;
+ }
+
+ *file_sz = info->file_size;
+ efi_call_early(free_pool, info);
+
+ if (status != EFI_SUCCESS)
+ efi_printk(sys_table, "Failed to get initrd info\n");
+
+ return status;
+}
+
+static efi_status_t
+__file_size64(void *__fh, efi_char16_t *filename_16,
+ void **handle, u64 *file_sz)
+{
+ efi_file_handle_64_t *h, *fh = __fh;
+ efi_file_info_t *info;
+ efi_status_t status;
+ efi_guid_t info_guid = EFI_FILE_INFO_ID;
+ u32 info_sz;
+ status = efi_early->call((unsigned long)fh->open, fh, &h, filename_16,
+ EFI_FILE_MODE_READ, (u64)0);
+ if (status != EFI_SUCCESS) {
+ efi_printk(sys_table, "Failed to open file: ");
+ efi_char16_printk(sys_table, filename_16);
+ efi_printk(sys_table, "\n");
+ return status;
+ }
+ *handle = h;
+
+ info_sz = 0;
+ status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
+ &info_sz, NULL);
+ if (status != EFI_BUFFER_TOO_SMALL) {
+ efi_printk(sys_table, "Failed to get file info size\n");
+ return status;
+ }
+
+grow:
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+ info_sz, (void **)&info);
+ if (status != EFI_SUCCESS) {
+ efi_printk(sys_table, "Failed to alloc mem for file info\n");
+ return status;
+ }
+
+ status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
+ &info_sz, info);
+ if (status == EFI_BUFFER_TOO_SMALL) {
+ efi_call_early(free_pool, info);
+ goto grow;
+ }
+
+ *file_sz = info->file_size;
+ efi_call_early(free_pool, info);
+
+ if (status != EFI_SUCCESS)
+ efi_printk(sys_table, "Failed to get initrd info\n");
+
+ return status;
+}
+static efi_status_t
+efi_file_size(efi_system_table_t *sys_table, void *__fh,
+ efi_char16_t *filename_16, void **handle, u64 *file_sz)
+{
+ if (efi_early->is64)
+ return __file_size64(__fh, filename_16, handle, file_sz);
+
+ return __file_size32(__fh, filename_16, handle, file_sz);
+}
+
+static inline efi_status_t
+efi_file_read(void *__fh, void *handle, unsigned long *size, void *addr)
+{
+ unsigned long func;
+
+ if (efi_early->is64) {
+ efi_file_handle_64_t *fh = __fh;
+
+ func = (unsigned long)fh->read;
+ return efi_early->call(func, handle, size, addr);
+ } else {
+ efi_file_handle_32_t *fh = __fh;
+
+ func = (unsigned long)fh->read;
+ return efi_early->call(func, handle, size, addr);
+ }
+}
+
+static inline efi_status_t efi_file_close(void *__fh, void *handle)
+{
+ if (efi_early->is64) {
+ efi_file_handle_64_t *fh = __fh;
+
+ return efi_early->call((unsigned long)fh->close, handle);
+ } else {
+ efi_file_handle_32_t *fh = __fh;
+
+ return efi_early->call((unsigned long)fh->close, handle);
+ }
+}
+
+static inline efi_status_t __open_volume32(void *__image, void **__fh)
+{
+ efi_file_io_interface_t *io;
+ efi_loaded_image_32_t *image = __image;
+ efi_file_handle_32_t *fh;
+ efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
+ efi_status_t status;
+ void *handle = (void *)(unsigned long)image->device_handle;
+ unsigned long func;
+
+ status = efi_call_early(handle_protocol, handle,
+ &fs_proto, (void **)&io);
+ if (status != EFI_SUCCESS) {
+ efi_printk(sys_table, "Failed to handle fs_proto\n");
+ return status;
+ }
+
+ func = (unsigned long)io->open_volume;
+ status = efi_early->call(func, io, &fh);
+ if (status != EFI_SUCCESS)
+ efi_printk(sys_table, "Failed to open volume\n");
+
+ *__fh = fh;
+ return status;
+}
+
+static inline efi_status_t __open_volume64(void *__image, void **__fh)
+{
+ efi_file_io_interface_t *io;
+ efi_loaded_image_64_t *image = __image;
+ efi_file_handle_64_t *fh;
+ efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
+ efi_status_t status;
+ void *handle = (void *)(unsigned long)image->device_handle;
+ unsigned long func;
+
+ status = efi_call_early(handle_protocol, handle,
+ &fs_proto, (void **)&io);
+ if (status != EFI_SUCCESS) {
+ efi_printk(sys_table, "Failed to handle fs_proto\n");
+ return status;
+ }
+
+ func = (unsigned long)io->open_volume;
+ status = efi_early->call(func, io, &fh);
+ if (status != EFI_SUCCESS)
+ efi_printk(sys_table, "Failed to open volume\n");
+
+ *__fh = fh;
+ return status;
+}
+
+static inline efi_status_t
+efi_open_volume(efi_system_table_t *sys_table, void *__image, void **__fh)
+{
+ if (efi_early->is64)
+ return __open_volume64(__image, __fh);
+
+ return __open_volume32(__image, __fh);
+}
+
+static void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str)
+{
+ unsigned long output_string;
+ size_t offset;
+
+ if (efi_early->is64) {
+ struct efi_simple_text_output_protocol_64 *out;
+ u64 *func;
+
+ offset = offsetof(typeof(*out), output_string);
+ output_string = efi_early->text_output + offset;
+ func = (u64 *)output_string;
+
+ efi_early->call(*func, efi_early->text_output, str);
+ } else {
+ struct efi_simple_text_output_protocol_32 *out;
+ u32 *func;
+
+ offset = offsetof(typeof(*out), output_string);
+ output_string = efi_early->text_output + offset;
+ func = (u32 *)output_string;
+
+ efi_early->call(*func, efi_early->text_output, str);
+ }
+}
+
+#include "../../../../drivers/firmware/efi/efi-stub-helper.c"
static void find_bits(unsigned long mask, u8 *pos, u8 *size)
{
@@ -47,105 +309,97 @@ static void find_bits(unsigned long mask, u8 *pos, u8 *size)
*size = len;
}
-static efi_status_t setup_efi_pci(struct boot_params *params)
+static efi_status_t
+__setup_efi_pci32(efi_pci_io_protocol_32 *pci, struct pci_setup_rom **__rom)
{
- efi_pci_io_protocol *pci;
+ struct pci_setup_rom *rom = NULL;
efi_status_t status;
- void **pci_handle;
- efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
- unsigned long nr_pci, size = 0;
- int i;
- struct setup_data *data;
+ unsigned long size;
+ uint64_t attributes;
- data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
+ status = efi_early->call(pci->attributes, pci,
+ EfiPciIoAttributeOperationGet, 0, 0,
+ &attributes);
+ if (status != EFI_SUCCESS)
+ return status;
- while (data && data->next)
- data = (struct setup_data *)(unsigned long)data->next;
+ if (!pci->romimage || !pci->romsize)
+ return EFI_INVALID_PARAMETER;
- status = efi_call_phys5(sys_table->boottime->locate_handle,
- EFI_LOCATE_BY_PROTOCOL, &pci_proto,
- NULL, &size, pci_handle);
+ size = pci->romsize + sizeof(*rom);
- if (status == EFI_BUFFER_TOO_SMALL) {
- status = efi_call_phys3(sys_table->boottime->allocate_pool,
- EFI_LOADER_DATA, size, &pci_handle);
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom);
+ if (status != EFI_SUCCESS)
+ return status;
- if (status != EFI_SUCCESS)
- return status;
+ memset(rom, 0, sizeof(*rom));
- status = efi_call_phys5(sys_table->boottime->locate_handle,
- EFI_LOCATE_BY_PROTOCOL, &pci_proto,
- NULL, &size, pci_handle);
- }
+ rom->data.type = SETUP_PCI;
+ rom->data.len = size - sizeof(struct setup_data);
+ rom->data.next = 0;
+ rom->pcilen = pci->romsize;
+ *__rom = rom;
- if (status != EFI_SUCCESS)
- goto free_handle;
-
- nr_pci = size / sizeof(void *);
- for (i = 0; i < nr_pci; i++) {
- void *h = pci_handle[i];
- uint64_t attributes;
- struct pci_setup_rom *rom;
+ status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
+ PCI_VENDOR_ID, 1, &(rom->vendor));
- status = efi_call_phys3(sys_table->boottime->handle_protocol,
- h, &pci_proto, &pci);
+ if (status != EFI_SUCCESS)
+ goto free_struct;
- if (status != EFI_SUCCESS)
- continue;
+ status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
+ PCI_DEVICE_ID, 1, &(rom->devid));
- if (!pci)
- continue;
+ if (status != EFI_SUCCESS)
+ goto free_struct;
-#ifdef CONFIG_X86_64
- status = efi_call_phys4(pci->attributes, pci,
- EfiPciIoAttributeOperationGet, 0,
- &attributes);
-#else
- status = efi_call_phys5(pci->attributes, pci,
- EfiPciIoAttributeOperationGet, 0, 0,
- &attributes);
-#endif
- if (status != EFI_SUCCESS)
- continue;
+ status = efi_early->call(pci->get_location, pci, &(rom->segment),
+ &(rom->bus), &(rom->device), &(rom->function));
- if (!pci->romimage || !pci->romsize)
- continue;
+ if (status != EFI_SUCCESS)
+ goto free_struct;
- size = pci->romsize + sizeof(*rom);
+ memcpy(rom->romdata, pci->romimage, pci->romsize);
+ return status;
- status = efi_call_phys3(sys_table->boottime->allocate_pool,
- EFI_LOADER_DATA, size, &rom);
+free_struct:
+ efi_call_early(free_pool, rom);
+ return status;
+}
- if (status != EFI_SUCCESS)
- continue;
+static efi_status_t
+setup_efi_pci32(struct boot_params *params, void **pci_handle,
+ unsigned long size)
+{
+ efi_pci_io_protocol_32 *pci = NULL;
+ efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
+ u32 *handles = (u32 *)(unsigned long)pci_handle;
+ efi_status_t status;
+ unsigned long nr_pci;
+ struct setup_data *data;
+ int i;
- rom->data.type = SETUP_PCI;
- rom->data.len = size - sizeof(struct setup_data);
- rom->data.next = 0;
- rom->pcilen = pci->romsize;
+ data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
- status = efi_call_phys5(pci->pci.read, pci,
- EfiPciIoWidthUint16, PCI_VENDOR_ID,
- 1, &(rom->vendor));
+ while (data && data->next)
+ data = (struct setup_data *)(unsigned long)data->next;
- if (status != EFI_SUCCESS)
- goto free_struct;
+ nr_pci = size / sizeof(u32);
+ for (i = 0; i < nr_pci; i++) {
+ struct pci_setup_rom *rom = NULL;
+ u32 h = handles[i];
- status = efi_call_phys5(pci->pci.read, pci,
- EfiPciIoWidthUint16, PCI_DEVICE_ID,
- 1, &(rom->devid));
+ status = efi_call_early(handle_protocol, h,
+ &pci_proto, (void **)&pci);
if (status != EFI_SUCCESS)
- goto free_struct;
+ continue;
- status = efi_call_phys5(pci->get_location, pci,
- &(rom->segment), &(rom->bus),
- &(rom->device), &(rom->function));
+ if (!pci)
+ continue;
+ status = __setup_efi_pci32(pci, &rom);
if (status != EFI_SUCCESS)
- goto free_struct;
-
- memcpy(rom->romdata, pci->romimage, pci->romsize);
+ continue;
if (data)
data->next = (unsigned long)rom;
@@ -154,105 +408,155 @@ static efi_status_t setup_efi_pci(struct boot_params *params)
data = (struct setup_data *)rom;
- continue;
- free_struct:
- efi_call_phys1(sys_table->boottime->free_pool, rom);
}
-free_handle:
- efi_call_phys1(sys_table->boottime->free_pool, pci_handle);
return status;
}
-/*
- * See if we have Graphics Output Protocol
- */
-static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
- unsigned long size)
+static efi_status_t
+__setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom)
{
- struct efi_graphics_output_protocol *gop, *first_gop;
- struct efi_pixel_bitmask pixel_info;
- unsigned long nr_gops;
+ struct pci_setup_rom *rom;
efi_status_t status;
- void **gop_handle;
- u16 width, height;
- u32 fb_base, fb_size;
- u32 pixels_per_scan_line;
- int pixel_format;
- int i;
+ unsigned long size;
+ uint64_t attributes;
- status = efi_call_phys3(sys_table->boottime->allocate_pool,
- EFI_LOADER_DATA, size, &gop_handle);
+ status = efi_early->call(pci->attributes, pci,
+ EfiPciIoAttributeOperationGet, 0,
+ &attributes);
if (status != EFI_SUCCESS)
return status;
- status = efi_call_phys5(sys_table->boottime->locate_handle,
- EFI_LOCATE_BY_PROTOCOL, proto,
- NULL, &size, gop_handle);
+ if (!pci->romimage || !pci->romsize)
+ return EFI_INVALID_PARAMETER;
+
+ size = pci->romsize + sizeof(*rom);
+
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom);
if (status != EFI_SUCCESS)
- goto free_handle;
+ return status;
- first_gop = NULL;
+ rom->data.type = SETUP_PCI;
+ rom->data.len = size - sizeof(struct setup_data);
+ rom->data.next = 0;
+ rom->pcilen = pci->romsize;
+ *__rom = rom;
- nr_gops = size / sizeof(void *);
- for (i = 0; i < nr_gops; i++) {
- struct efi_graphics_output_mode_info *info;
- efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
- bool conout_found = false;
- void *dummy;
- void *h = gop_handle[i];
+ status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
+ PCI_VENDOR_ID, 1, &(rom->vendor));
+
+ if (status != EFI_SUCCESS)
+ goto free_struct;
+
+ status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
+ PCI_DEVICE_ID, 1, &(rom->devid));
+
+ if (status != EFI_SUCCESS)
+ goto free_struct;
+
+ status = efi_early->call(pci->get_location, pci, &(rom->segment),
+ &(rom->bus), &(rom->device), &(rom->function));
+
+ if (status != EFI_SUCCESS)
+ goto free_struct;
+
+ memcpy(rom->romdata, pci->romimage, pci->romsize);
+ return status;
+
+free_struct:
+ efi_call_early(free_pool, rom);
+ return status;
+
+}
+
+static efi_status_t
+setup_efi_pci64(struct boot_params *params, void **pci_handle,
+ unsigned long size)
+{
+ efi_pci_io_protocol_64 *pci = NULL;
+ efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
+ u64 *handles = (u64 *)(unsigned long)pci_handle;
+ efi_status_t status;
+ unsigned long nr_pci;
+ struct setup_data *data;
+ int i;
+
+ data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
+
+ while (data && data->next)
+ data = (struct setup_data *)(unsigned long)data->next;
+
+ nr_pci = size / sizeof(u64);
+ for (i = 0; i < nr_pci; i++) {
+ struct pci_setup_rom *rom = NULL;
+ u64 h = handles[i];
+
+ status = efi_call_early(handle_protocol, h,
+ &pci_proto, (void **)&pci);
- status = efi_call_phys3(sys_table->boottime->handle_protocol,
- h, proto, &gop);
if (status != EFI_SUCCESS)
continue;
- status = efi_call_phys3(sys_table->boottime->handle_protocol,
- h, &conout_proto, &dummy);
+ if (!pci)
+ continue;
- if (status == EFI_SUCCESS)
- conout_found = true;
+ status = __setup_efi_pci64(pci, &rom);
+ if (status != EFI_SUCCESS)
+ continue;
- status = efi_call_phys4(gop->query_mode, gop,
- gop->mode->mode, &size, &info);
- if (status == EFI_SUCCESS && (!first_gop || conout_found)) {
- /*
- * Systems that use the UEFI Console Splitter may
- * provide multiple GOP devices, not all of which are
- * backed by real hardware. The workaround is to search
- * for a GOP implementing the ConOut protocol, and if
- * one isn't found, to just fall back to the first GOP.
- */
- width = info->horizontal_resolution;
- height = info->vertical_resolution;
- fb_base = gop->mode->frame_buffer_base;
- fb_size = gop->mode->frame_buffer_size;
- pixel_format = info->pixel_format;
- pixel_info = info->pixel_information;
- pixels_per_scan_line = info->pixels_per_scan_line;
+ if (data)
+ data->next = (unsigned long)rom;
+ else
+ params->hdr.setup_data = (unsigned long)rom;
+
+ data = (struct setup_data *)rom;
- /*
- * Once we've found a GOP supporting ConOut,
- * don't bother looking any further.
- */
- first_gop = gop;
- if (conout_found)
- break;
- }
}
- /* Did we find any GOPs? */
- if (!first_gop)
+ return status;
+}
+
+static efi_status_t setup_efi_pci(struct boot_params *params)
+{
+ efi_status_t status;
+ void **pci_handle = NULL;
+ efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
+ unsigned long size = 0;
+
+ status = efi_call_early(locate_handle,
+ EFI_LOCATE_BY_PROTOCOL,
+ &pci_proto, NULL, &size, pci_handle);
+
+ if (status == EFI_BUFFER_TOO_SMALL) {
+ status = efi_call_early(allocate_pool,
+ EFI_LOADER_DATA,
+ size, (void **)&pci_handle);
+
+ if (status != EFI_SUCCESS)
+ return status;
+
+ status = efi_call_early(locate_handle,
+ EFI_LOCATE_BY_PROTOCOL, &pci_proto,
+ NULL, &size, pci_handle);
+ }
+
+ if (status != EFI_SUCCESS)
goto free_handle;
- /* EFI framebuffer */
- si->orig_video_isVGA = VIDEO_TYPE_EFI;
+ if (efi_early->is64)
+ status = setup_efi_pci64(params, pci_handle, size);
+ else
+ status = setup_efi_pci32(params, pci_handle, size);
- si->lfb_width = width;
- si->lfb_height = height;
- si->lfb_base = fb_base;
- si->pages = 1;
+free_handle:
+ efi_call_early(free_pool, pci_handle);
+ return status;
+}
+static void
+setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line,
+ struct efi_pixel_bitmask pixel_info, int pixel_format)
+{
if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) {
si->lfb_depth = 32;
si->lfb_linelength = pixels_per_scan_line * 4;
@@ -297,62 +601,319 @@ static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
si->rsvd_size = 0;
si->rsvd_pos = 0;
}
+}
+
+static efi_status_t
+__gop_query32(struct efi_graphics_output_protocol_32 *gop32,
+ struct efi_graphics_output_mode_info **info,
+ unsigned long *size, u32 *fb_base)
+{
+ struct efi_graphics_output_protocol_mode_32 *mode;
+ efi_status_t status;
+ unsigned long m;
+
+ m = gop32->mode;
+ mode = (struct efi_graphics_output_protocol_mode_32 *)m;
+
+ status = efi_early->call(gop32->query_mode, gop32,
+ mode->mode, size, info);
+ if (status != EFI_SUCCESS)
+ return status;
+
+ *fb_base = mode->frame_buffer_base;
+ return status;
+}
+
+static efi_status_t
+setup_gop32(struct screen_info *si, efi_guid_t *proto,
+ unsigned long size, void **gop_handle)
+{
+ struct efi_graphics_output_protocol_32 *gop32, *first_gop;
+ unsigned long nr_gops;
+ u16 width, height;
+ u32 pixels_per_scan_line;
+ u32 fb_base;
+ struct efi_pixel_bitmask pixel_info;
+ int pixel_format;
+ efi_status_t status;
+ u32 *handles = (u32 *)(unsigned long)gop_handle;
+ int i;
+
+ first_gop = NULL;
+ gop32 = NULL;
+
+ nr_gops = size / sizeof(u32);
+ for (i = 0; i < nr_gops; i++) {
+ struct efi_graphics_output_mode_info *info = NULL;
+ efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
+ bool conout_found = false;
+ void *dummy = NULL;
+ u32 h = handles[i];
+
+ status = efi_call_early(handle_protocol, h,
+ proto, (void **)&gop32);
+ if (status != EFI_SUCCESS)
+ continue;
+
+ status = efi_call_early(handle_protocol, h,
+ &conout_proto, &dummy);
+ if (status == EFI_SUCCESS)
+ conout_found = true;
+
+ status = __gop_query32(gop32, &info, &size, &fb_base);
+ if (status == EFI_SUCCESS && (!first_gop || conout_found)) {
+ /*
+ * Systems that use the UEFI Console Splitter may
+ * provide multiple GOP devices, not all of which are
+ * backed by real hardware. The workaround is to search
+ * for a GOP implementing the ConOut protocol, and if
+ * one isn't found, to just fall back to the first GOP.
+ */
+ width = info->horizontal_resolution;
+ height = info->vertical_resolution;
+ pixel_format = info->pixel_format;
+ pixel_info = info->pixel_information;
+ pixels_per_scan_line = info->pixels_per_scan_line;
+
+ /*
+ * Once we've found a GOP supporting ConOut,
+ * don't bother looking any further.
+ */
+ first_gop = gop32;
+ if (conout_found)
+ break;
+ }
+ }
+
+ /* Did we find any GOPs? */
+ if (!first_gop)
+ goto out;
+
+ /* EFI framebuffer */
+ si->orig_video_isVGA = VIDEO_TYPE_EFI;
+
+ si->lfb_width = width;
+ si->lfb_height = height;
+ si->lfb_base = fb_base;
+ si->pages = 1;
+
+ setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
si->lfb_size = si->lfb_linelength * si->lfb_height;
si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
+out:
+ return status;
+}
-free_handle:
- efi_call_phys1(sys_table->boottime->free_pool, gop_handle);
+static efi_status_t
+__gop_query64(struct efi_graphics_output_protocol_64 *gop64,
+ struct efi_graphics_output_mode_info **info,
+ unsigned long *size, u32 *fb_base)
+{
+ struct efi_graphics_output_protocol_mode_64 *mode;
+ efi_status_t status;
+ unsigned long m;
+
+ m = gop64->mode;
+ mode = (struct efi_graphics_output_protocol_mode_64 *)m;
+
+ status = efi_early->call(gop64->query_mode, gop64,
+ mode->mode, size, info);
+ if (status != EFI_SUCCESS)
+ return status;
+
+ *fb_base = mode->frame_buffer_base;
+ return status;
+}
+
+static efi_status_t
+setup_gop64(struct screen_info *si, efi_guid_t *proto,
+ unsigned long size, void **gop_handle)
+{
+ struct efi_graphics_output_protocol_64 *gop64, *first_gop;
+ unsigned long nr_gops;
+ u16 width, height;
+ u32 pixels_per_scan_line;
+ u32 fb_base;
+ struct efi_pixel_bitmask pixel_info;
+ int pixel_format;
+ efi_status_t status;
+ u64 *handles = (u64 *)(unsigned long)gop_handle;
+ int i;
+
+ first_gop = NULL;
+ gop64 = NULL;
+
+ nr_gops = size / sizeof(u64);
+ for (i = 0; i < nr_gops; i++) {
+ struct efi_graphics_output_mode_info *info = NULL;
+ efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
+ bool conout_found = false;
+ void *dummy = NULL;
+ u64 h = handles[i];
+
+ status = efi_call_early(handle_protocol, h,
+ proto, (void **)&gop64);
+ if (status != EFI_SUCCESS)
+ continue;
+
+ status = efi_call_early(handle_protocol, h,
+ &conout_proto, &dummy);
+ if (status == EFI_SUCCESS)
+ conout_found = true;
+
+ status = __gop_query64(gop64, &info, &size, &fb_base);
+ if (status == EFI_SUCCESS && (!first_gop || conout_found)) {
+ /*
+ * Systems that use the UEFI Console Splitter may
+ * provide multiple GOP devices, not all of which are
+ * backed by real hardware. The workaround is to search
+ * for a GOP implementing the ConOut protocol, and if
+ * one isn't found, to just fall back to the first GOP.
+ */
+ width = info->horizontal_resolution;
+ height = info->vertical_resolution;
+ pixel_format = info->pixel_format;
+ pixel_info = info->pixel_information;
+ pixels_per_scan_line = info->pixels_per_scan_line;
+
+ /*
+ * Once we've found a GOP supporting ConOut,
+ * don't bother looking any further.
+ */
+ first_gop = gop64;
+ if (conout_found)
+ break;
+ }
+ }
+
+ /* Did we find any GOPs? */
+ if (!first_gop)
+ goto out;
+
+ /* EFI framebuffer */
+ si->orig_video_isVGA = VIDEO_TYPE_EFI;
+
+ si->lfb_width = width;
+ si->lfb_height = height;
+ si->lfb_base = fb_base;
+ si->pages = 1;
+
+ setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
+
+ si->lfb_size = si->lfb_linelength * si->lfb_height;
+
+ si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
+out:
return status;
}
/*
- * See if we have Universal Graphics Adapter (UGA) protocol
+ * See if we have Graphics Output Protocol
*/
-static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
+static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
unsigned long size)
{
- struct efi_uga_draw_protocol *uga, *first_uga;
- unsigned long nr_ugas;
efi_status_t status;
- u32 width, height;
- void **uga_handle = NULL;
- int i;
+ void **gop_handle = NULL;
- status = efi_call_phys3(sys_table->boottime->allocate_pool,
- EFI_LOADER_DATA, size, &uga_handle);
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+ size, (void **)&gop_handle);
if (status != EFI_SUCCESS)
return status;
- status = efi_call_phys5(sys_table->boottime->locate_handle,
- EFI_LOCATE_BY_PROTOCOL, uga_proto,
- NULL, &size, uga_handle);
+ status = efi_call_early(locate_handle,
+ EFI_LOCATE_BY_PROTOCOL,
+ proto, NULL, &size, gop_handle);
if (status != EFI_SUCCESS)
goto free_handle;
+ if (efi_early->is64)
+ status = setup_gop64(si, proto, size, gop_handle);
+ else
+ status = setup_gop32(si, proto, size, gop_handle);
+
+free_handle:
+ efi_call_early(free_pool, gop_handle);
+ return status;
+}
+
+static efi_status_t
+setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height)
+{
+ struct efi_uga_draw_protocol *uga = NULL, *first_uga;
+ efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
+ unsigned long nr_ugas;
+ u32 *handles = (u32 *)uga_handle;;
+ efi_status_t status;
+ int i;
+
first_uga = NULL;
+ nr_ugas = size / sizeof(u32);
+ for (i = 0; i < nr_ugas; i++) {
+ efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
+ u32 w, h, depth, refresh;
+ void *pciio;
+ u32 handle = handles[i];
+
+ status = efi_call_early(handle_protocol, handle,
+ &uga_proto, (void **)&uga);
+ if (status != EFI_SUCCESS)
+ continue;
+
+ efi_call_early(handle_protocol, handle, &pciio_proto, &pciio);
+
+ status = efi_early->call((unsigned long)uga->get_mode, uga,
+ &w, &h, &depth, &refresh);
+ if (status == EFI_SUCCESS && (!first_uga || pciio)) {
+ *width = w;
+ *height = h;
+
+ /*
+ * Once we've found a UGA supporting PCIIO,
+ * don't bother looking any further.
+ */
+ if (pciio)
+ break;
- nr_ugas = size / sizeof(void *);
+ first_uga = uga;
+ }
+ }
+
+ return status;
+}
+
+static efi_status_t
+setup_uga64(void **uga_handle, unsigned long size, u32 *width, u32 *height)
+{
+ struct efi_uga_draw_protocol *uga = NULL, *first_uga;
+ efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
+ unsigned long nr_ugas;
+ u64 *handles = (u64 *)uga_handle;;
+ efi_status_t status;
+ int i;
+
+ first_uga = NULL;
+ nr_ugas = size / sizeof(u64);
for (i = 0; i < nr_ugas; i++) {
efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
- void *handle = uga_handle[i];
u32 w, h, depth, refresh;
void *pciio;
+ u64 handle = handles[i];
- status = efi_call_phys3(sys_table->boottime->handle_protocol,
- handle, uga_proto, &uga);
+ status = efi_call_early(handle_protocol, handle,
+ &uga_proto, (void **)&uga);
if (status != EFI_SUCCESS)
continue;
- efi_call_phys3(sys_table->boottime->handle_protocol,
- handle, &pciio_proto, &pciio);
+ efi_call_early(handle_protocol, handle, &pciio_proto, &pciio);
- status = efi_call_phys5(uga->get_mode, uga, &w, &h,
- &depth, &refresh);
+ status = efi_early->call((unsigned long)uga->get_mode, uga,
+ &w, &h, &depth, &refresh);
if (status == EFI_SUCCESS && (!first_uga || pciio)) {
- width = w;
- height = h;
+ *width = w;
+ *height = h;
/*
* Once we've found a UGA supporting PCIIO,
@@ -365,7 +926,39 @@ static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
}
}
- if (!first_uga)
+ return status;
+}
+
+/*
+ * See if we have Universal Graphics Adapter (UGA) protocol
+ */
+static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
+ unsigned long size)
+{
+ efi_status_t status;
+ u32 width, height;
+ void **uga_handle = NULL;
+
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+ size, (void **)&uga_handle);
+ if (status != EFI_SUCCESS)
+ return status;
+
+ status = efi_call_early(locate_handle,
+ EFI_LOCATE_BY_PROTOCOL,
+ uga_proto, NULL, &size, uga_handle);
+ if (status != EFI_SUCCESS)
+ goto free_handle;
+
+ height = 0;
+ width = 0;
+
+ if (efi_early->is64)
+ status = setup_uga64(uga_handle, size, &width, &height);
+ else
+ status = setup_uga32(uga_handle, size, &width, &height);
+
+ if (!width && !height)
goto free_handle;
/* EFI framebuffer */
@@ -384,9 +977,8 @@ static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
si->rsvd_size = 8;
si->rsvd_pos = 24;
-
free_handle:
- efi_call_phys1(sys_table->boottime->free_pool, uga_handle);
+ efi_call_early(free_pool, uga_handle);
return status;
}
@@ -404,29 +996,28 @@ void setup_graphics(struct boot_params *boot_params)
memset(si, 0, sizeof(*si));
size = 0;
- status = efi_call_phys5(sys_table->boottime->locate_handle,
- EFI_LOCATE_BY_PROTOCOL, &graphics_proto,
- NULL, &size, gop_handle);
+ status = efi_call_early(locate_handle,
+ EFI_LOCATE_BY_PROTOCOL,
+ &graphics_proto, NULL, &size, gop_handle);
if (status == EFI_BUFFER_TOO_SMALL)
status = setup_gop(si, &graphics_proto, size);
if (status != EFI_SUCCESS) {
size = 0;
- status = efi_call_phys5(sys_table->boottime->locate_handle,
- EFI_LOCATE_BY_PROTOCOL, &uga_proto,
- NULL, &size, uga_handle);
+ status = efi_call_early(locate_handle,
+ EFI_LOCATE_BY_PROTOCOL,
+ &uga_proto, NULL, &size, uga_handle);
if (status == EFI_BUFFER_TOO_SMALL)
setup_uga(si, &uga_proto, size);
}
}
-
/*
* Because the x86 boot code expects to be passed a boot_params we
* need to create one ourselves (usually the bootloader would create
* one for us).
*/
-struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
+struct boot_params *make_boot_params(struct efi_config *c)
{
struct boot_params *boot_params;
struct sys_desc_table *sdt;
@@ -434,7 +1025,7 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
struct setup_header *hdr;
struct efi_info *efi;
efi_loaded_image_t *image;
- void *options;
+ void *options, *handle;
efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
int options_size = 0;
efi_status_t status;
@@ -445,14 +1036,21 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
unsigned long ramdisk_addr;
unsigned long ramdisk_size;
- sys_table = _table;
+ efi_early = c;
+ sys_table = (efi_system_table_t *)(unsigned long)efi_early->table;
+ handle = (void *)(unsigned long)efi_early->image_handle;
/* Check if we were booted by the EFI firmware */
if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
return NULL;
- status = efi_call_phys3(sys_table->boottime->handle_protocol,
- handle, &proto, (void *)&image);
+ if (efi_early->is64)
+ setup_boot_services64(efi_early);
+ else
+ setup_boot_services32(efi_early);
+
+ status = efi_call_early(handle_protocol, handle,
+ &proto, (void *)&image);
if (status != EFI_SUCCESS) {
efi_printk(sys_table, "Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
return NULL;
@@ -641,14 +1239,13 @@ static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
sizeof(struct e820entry) * nr_desc;
if (*e820ext) {
- efi_call_phys1(sys_table->boottime->free_pool, *e820ext);
+ efi_call_early(free_pool, *e820ext);
*e820ext = NULL;
*e820ext_size = 0;
}
- status = efi_call_phys3(sys_table->boottime->allocate_pool,
- EFI_LOADER_DATA, size, e820ext);
-
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+ size, (void **)e820ext);
if (status == EFI_SUCCESS)
*e820ext_size = size;
@@ -656,12 +1253,13 @@ static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
}
static efi_status_t exit_boot(struct boot_params *boot_params,
- void *handle)
+ void *handle, bool is64)
{
struct efi_info *efi = &boot_params->efi_info;
unsigned long map_sz, key, desc_size;
efi_memory_desc_t *mem_map;
struct setup_data *e820ext;
+ const char *signature;
__u32 e820ext_size;
__u32 nr_desc, prev_nr_desc;
efi_status_t status;
@@ -691,11 +1289,13 @@ get_map:
if (status != EFI_SUCCESS)
goto free_mem_map;
- efi_call_phys1(sys_table->boottime->free_pool, mem_map);
+ efi_call_early(free_pool, mem_map);
goto get_map; /* Allocated memory, get map again */
}
- memcpy(&efi->efi_loader_signature, EFI_LOADER_SIGNATURE, sizeof(__u32));
+ signature = is64 ? EFI64_LOADER_SIGNATURE : EFI32_LOADER_SIGNATURE;
+ memcpy(&efi->efi_loader_signature, signature, sizeof(__u32));
+
efi->efi_systab = (unsigned long)sys_table;
efi->efi_memdesc_size = desc_size;
efi->efi_memdesc_version = desc_version;
@@ -708,8 +1308,7 @@ get_map:
#endif
/* Might as well exit boot services now */
- status = efi_call_phys2(sys_table->boottime->exit_boot_services,
- handle, key);
+ status = efi_call_early(exit_boot_services, handle, key);
if (status != EFI_SUCCESS) {
/*
* ExitBootServices() will fail if any of the event
@@ -722,7 +1321,7 @@ get_map:
goto free_mem_map;
called_exit = true;
- efi_call_phys1(sys_table->boottime->free_pool, mem_map);
+ efi_call_early(free_pool, mem_map);
goto get_map;
}
@@ -736,23 +1335,31 @@ get_map:
return EFI_SUCCESS;
free_mem_map:
- efi_call_phys1(sys_table->boottime->free_pool, mem_map);
+ efi_call_early(free_pool, mem_map);
return status;
}
-
/*
* On success we return a pointer to a boot_params structure, and NULL
* on failure.
*/
-struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
+struct boot_params *efi_main(struct efi_config *c,
struct boot_params *boot_params)
{
- struct desc_ptr *gdt;
+ struct desc_ptr *gdt = NULL;
efi_loaded_image_t *image;
struct setup_header *hdr = &boot_params->hdr;
efi_status_t status;
struct desc_struct *desc;
+ void *handle;
+ efi_system_table_t *_table;
+ bool is64;
+
+ efi_early = c;
+
+ _table = (efi_system_table_t *)(unsigned long)efi_early->table;
+ handle = (void *)(unsigned long)efi_early->image_handle;
+ is64 = efi_early->is64;
sys_table = _table;
@@ -760,13 +1367,17 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
goto fail;
+ if (is64)
+ setup_boot_services64(efi_early);
+ else
+ setup_boot_services32(efi_early);
+
setup_graphics(boot_params);
setup_efi_pci(boot_params);
- status = efi_call_phys3(sys_table->boottime->allocate_pool,
- EFI_LOADER_DATA, sizeof(*gdt),
- (void **)&gdt);
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+ sizeof(*gdt), (void **)&gdt);
if (status != EFI_SUCCESS) {
efi_printk(sys_table, "Failed to alloc mem for gdt structure\n");
goto fail;
@@ -797,7 +1408,7 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
hdr->code32_start = bzimage_addr;
}
- status = exit_boot(boot_params, handle);
+ status = exit_boot(boot_params, handle, is64);
if (status != EFI_SUCCESS)
goto fail;
diff --git a/arch/x86/boot/compressed/eboot.h b/arch/x86/boot/compressed/eboot.h
index 81b6b652b46a..c88c31ecad12 100644
--- a/arch/x86/boot/compressed/eboot.h
+++ b/arch/x86/boot/compressed/eboot.h
@@ -37,6 +37,24 @@ struct efi_graphics_output_mode_info {
u32 pixels_per_scan_line;
} __packed;
+struct efi_graphics_output_protocol_mode_32 {
+ u32 max_mode;
+ u32 mode;
+ u32 info;
+ u32 size_of_info;
+ u64 frame_buffer_base;
+ u32 frame_buffer_size;
+} __packed;
+
+struct efi_graphics_output_protocol_mode_64 {
+ u32 max_mode;
+ u32 mode;
+ u64 info;
+ u64 size_of_info;
+ u64 frame_buffer_base;
+ u64 frame_buffer_size;
+} __packed;
+
struct efi_graphics_output_protocol_mode {
u32 max_mode;
u32 mode;
@@ -46,6 +64,20 @@ struct efi_graphics_output_protocol_mode {
unsigned long frame_buffer_size;
} __packed;
+struct efi_graphics_output_protocol_32 {
+ u32 query_mode;
+ u32 set_mode;
+ u32 blt;
+ u32 mode;
+};
+
+struct efi_graphics_output_protocol_64 {
+ u64 query_mode;
+ u64 set_mode;
+ u64 blt;
+ u64 mode;
+};
+
struct efi_graphics_output_protocol {
void *query_mode;
unsigned long set_mode;
@@ -53,10 +85,38 @@ struct efi_graphics_output_protocol {
struct efi_graphics_output_protocol_mode *mode;
};
+struct efi_uga_draw_protocol_32 {
+ u32 get_mode;
+ u32 set_mode;
+ u32 blt;
+};
+
+struct efi_uga_draw_protocol_64 {
+ u64 get_mode;
+ u64 set_mode;
+ u64 blt;
+};
+
struct efi_uga_draw_protocol {
void *get_mode;
void *set_mode;
void *blt;
};
+struct efi_config {
+ u64 image_handle;
+ u64 table;
+ u64 allocate_pool;
+ u64 allocate_pages;
+ u64 get_memory_map;
+ u64 free_pool;
+ u64 free_pages;
+ u64 locate_handle;
+ u64 handle_protocol;
+ u64 exit_boot_services;
+ u64 text_output;
+ efi_status_t (*call)(unsigned long, ...);
+ bool is64;
+} __packed;
+
#endif /* BOOT_COMPRESSED_EBOOT_H */
diff --git a/arch/x86/boot/compressed/efi_stub_64.S b/arch/x86/boot/compressed/efi_stub_64.S
index cedc60de86eb..7ff3632806b1 100644
--- a/arch/x86/boot/compressed/efi_stub_64.S
+++ b/arch/x86/boot/compressed/efi_stub_64.S
@@ -1 +1,30 @@
+#include <asm/segment.h>
+#include <asm/msr.h>
+#include <asm/processor-flags.h>
+
#include "../../platform/efi/efi_stub_64.S"
+
+#ifdef CONFIG_EFI_MIXED
+ .code64
+ .text
+ENTRY(efi64_thunk)
+ push %rbp
+ push %rbx
+
+ subq $16, %rsp
+ leaq efi_exit32(%rip), %rax
+ movl %eax, 8(%rsp)
+ leaq efi_gdt64(%rip), %rax
+ movl %eax, 4(%rsp)
+ movl %eax, 2(%rax) /* Fixup the gdt base address */
+ leaq efi32_boot_gdt(%rip), %rax
+ movl %eax, (%rsp)
+
+ call __efi64_thunk
+
+ addq $16, %rsp
+ pop %rbx
+ pop %rbp
+ ret
+ENDPROC(efi64_thunk)
+#endif /* CONFIG_EFI_MIXED */
diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S
index 9116aac232c7..de9d4200d305 100644
--- a/arch/x86/boot/compressed/head_32.S
+++ b/arch/x86/boot/compressed/head_32.S
@@ -42,26 +42,53 @@ ENTRY(startup_32)
ENTRY(efi_pe_entry)
add $0x4, %esp
+ call 1f
+1: popl %esi
+ subl $1b, %esi
+
+ popl %ecx
+ movl %ecx, efi32_config(%esi) /* Handle */
+ popl %ecx
+ movl %ecx, efi32_config+8(%esi) /* EFI System table pointer */
+
+ /* Relocate efi_config->call() */
+ leal efi32_config(%esi), %eax
+ add %esi, 88(%eax)
+ pushl %eax
+
call make_boot_params
cmpl $0, %eax
- je 1f
- movl 0x4(%esp), %esi
- movl (%esp), %ecx
+ je fail
+ popl %ecx
pushl %eax
- pushl %esi
pushl %ecx
- sub $0x4, %esp
+ jmp 2f /* Skip efi_config initialization */
-ENTRY(efi_stub_entry)
+ENTRY(efi32_stub_entry)
add $0x4, %esp
+ popl %ecx
+ popl %edx
+
+ call 1f
+1: popl %esi
+ subl $1b, %esi
+
+ movl %ecx, efi32_config(%esi) /* Handle */
+ movl %edx, efi32_config+8(%esi) /* EFI System table pointer */
+
+ /* Relocate efi_config->call() */
+ leal efi32_config(%esi), %eax
+ add %esi, 88(%eax)
+ pushl %eax
+2:
call efi_main
cmpl $0, %eax
movl %eax, %esi
jne 2f
-1:
+fail:
/* EFI init failed, so hang. */
hlt
- jmp 1b
+ jmp fail
2:
call 3f
3:
@@ -202,6 +229,15 @@ relocated:
xorl %ebx, %ebx
jmp *%eax
+#ifdef CONFIG_EFI_STUB
+ .data
+efi32_config:
+ .fill 11,8,0
+ .long efi_call_phys
+ .long 0
+ .byte 0
+#endif
+
/*
* Stack and heap for uncompression
*/
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index c5c1ae0997e7..57e58a5fa210 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -113,7 +113,8 @@ ENTRY(startup_32)
lgdt gdt(%ebp)
/* Enable PAE mode */
- movl $(X86_CR4_PAE), %eax
+ movl %cr4, %eax
+ orl $X86_CR4_PAE, %eax
movl %eax, %cr4
/*
@@ -178,6 +179,13 @@ ENTRY(startup_32)
*/
pushl $__KERNEL_CS
leal startup_64(%ebp), %eax
+#ifdef CONFIG_EFI_MIXED
+ movl efi32_config(%ebp), %ebx
+ cmp $0, %ebx
+ jz 1f
+ leal handover_entry(%ebp), %eax
+1:
+#endif
pushl %eax
/* Enter paged protected Mode, activating Long Mode */
@@ -188,6 +196,30 @@ ENTRY(startup_32)
lret
ENDPROC(startup_32)
+#ifdef CONFIG_EFI_MIXED
+ .org 0x190
+ENTRY(efi32_stub_entry)
+ add $0x4, %esp /* Discard return address */
+ popl %ecx
+ popl %edx
+ popl %esi
+
+ leal (BP_scratch+4)(%esi), %esp
+ call 1f
+1: pop %ebp
+ subl $1b, %ebp
+
+ movl %ecx, efi32_config(%ebp)
+ movl %edx, efi32_config+8(%ebp)
+ sgdtl efi32_boot_gdt(%ebp)
+
+ leal efi32_config(%ebp), %eax
+ movl %eax, efi_config(%ebp)
+
+ jmp startup_32
+ENDPROC(efi32_stub_entry)
+#endif
+
.code64
.org 0x200
ENTRY(startup_64)
@@ -209,26 +241,48 @@ ENTRY(startup_64)
jmp preferred_addr
ENTRY(efi_pe_entry)
- mov %rcx, %rdi
- mov %rdx, %rsi
- pushq %rdi
- pushq %rsi
+ movq %rcx, efi64_config(%rip) /* Handle */
+ movq %rdx, efi64_config+8(%rip) /* EFI System table pointer */
+
+ leaq efi64_config(%rip), %rax
+ movq %rax, efi_config(%rip)
+
+ call 1f
+1: popq %rbp
+ subq $1b, %rbp
+
+ /*
+ * Relocate efi_config->call().
+ */
+ addq %rbp, efi64_config+88(%rip)
+
+ movq %rax, %rdi
call make_boot_params
cmpq $0,%rax
- je 1f
- mov %rax, %rdx
- popq %rsi
- popq %rdi
+ je fail
+ mov %rax, %rsi
+ jmp 2f /* Skip the relocation */
-ENTRY(efi_stub_entry)
+handover_entry:
+ call 1f
+1: popq %rbp
+ subq $1b, %rbp
+
+ /*
+ * Relocate efi_config->call().
+ */
+ movq efi_config(%rip), %rax
+ addq %rbp, 88(%rax)
+2:
+ movq efi_config(%rip), %rdi
call efi_main
movq %rax,%rsi
cmpq $0,%rax
jne 2f
-1:
+fail:
/* EFI init failed, so hang. */
hlt
- jmp 1b
+ jmp fail
2:
call 3f
3:
@@ -307,6 +361,20 @@ preferred_addr:
leaq relocated(%rbx), %rax
jmp *%rax
+#ifdef CONFIG_EFI_STUB
+ .org 0x390
+ENTRY(efi64_stub_entry)
+ movq %rdi, efi64_config(%rip) /* Handle */
+ movq %rsi, efi64_config+8(%rip) /* EFI System table pointer */
+
+ leaq efi64_config(%rip), %rax
+ movq %rax, efi_config(%rip)
+
+ movq %rdx, %rsi
+ jmp handover_entry
+ENDPROC(efi64_stub_entry)
+#endif
+
.text
relocated:
@@ -372,6 +440,25 @@ gdt:
.quad 0x0000000000000000 /* TS continued */
gdt_end:
+#ifdef CONFIG_EFI_STUB
+efi_config:
+ .quad 0
+
+#ifdef CONFIG_EFI_MIXED
+ .global efi32_config
+efi32_config:
+ .fill 11,8,0
+ .quad efi64_thunk
+ .byte 0
+#endif
+
+ .global efi64_config
+efi64_config:
+ .fill 11,8,0
+ .quad efi_call6
+ .byte 1
+#endif /* CONFIG_EFI_STUB */
+
/*
* Stack and heap for uncompression
*/
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index 196eaf373a06..17684615374b 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -10,6 +10,7 @@
*/
#include "misc.h"
+#include "../string.h"
/* WARNING!!
* This code is compiled with -fPIC and it is relocated dynamically
@@ -97,8 +98,14 @@
*/
#define STATIC static
-#undef memset
#undef memcpy
+
+/*
+ * Use a normal definition of memset() from string.c. There are already
+ * included header files which expect a definition of memset() and by
+ * the time we define memset macro, it is too late.
+ */
+#undef memset
#define memzero(s, n) memset((s), 0, (n))
@@ -109,9 +116,6 @@ static void error(char *m);
*/
struct boot_params *real_mode; /* Pointer to real-mode data */
-void *memset(void *s, int c, size_t n);
-void *memcpy(void *dest, const void *src, size_t n);
-
memptr free_mem_ptr;
memptr free_mem_end_ptr;
@@ -216,45 +220,6 @@ void __putstr(const char *s)
outb(0xff & (pos >> 1), vidport+1);
}
-void *memset(void *s, int c, size_t n)
-{
- int i;
- char *ss = s;
-
- for (i = 0; i < n; i++)
- ss[i] = c;
- return s;
-}
-#ifdef CONFIG_X86_32
-void *memcpy(void *dest, const void *src, size_t n)
-{
- int d0, d1, d2;
- asm volatile(
- "rep ; movsl\n\t"
- "movl %4,%%ecx\n\t"
- "rep ; movsb\n\t"
- : "=&c" (d0), "=&D" (d1), "=&S" (d2)
- : "0" (n >> 2), "g" (n & 3), "1" (dest), "2" (src)
- : "memory");
-
- return dest;
-}
-#else
-void *memcpy(void *dest, const void *src, size_t n)
-{
- long d0, d1, d2;
- asm volatile(
- "rep ; movsq\n\t"
- "movq %4,%%rcx\n\t"
- "rep ; movsb\n\t"
- : "=&c" (d0), "=&D" (d1), "=&S" (d2)
- : "0" (n >> 3), "g" (n & 7), "1" (dest), "2" (src)
- : "memory");
-
- return dest;
-}
-#endif
-
static void error(char *x)
{
error_putstr("\n\n");
diff --git a/arch/x86/boot/compressed/string.c b/arch/x86/boot/compressed/string.c
index ffb9c5c9d748..f3c57e341402 100644
--- a/arch/x86/boot/compressed/string.c
+++ b/arch/x86/boot/compressed/string.c
@@ -1,11 +1,45 @@
#include "misc.h"
+#include "../string.c"
+
+/* misc.h might pull in string_32.h which has a macro for memcpy. undef that */
+#undef memcpy
-int memcmp(const void *s1, const void *s2, size_t len)
+#ifdef CONFIG_X86_32
+void *memcpy(void *dest, const void *src, size_t n)
{
- u8 diff;
- asm("repe; cmpsb; setnz %0"
- : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len));
- return diff;
+ int d0, d1, d2;
+ asm volatile(
+ "rep ; movsl\n\t"
+ "movl %4,%%ecx\n\t"
+ "rep ; movsb\n\t"
+ : "=&c" (d0), "=&D" (d1), "=&S" (d2)
+ : "0" (n >> 2), "g" (n & 3), "1" (dest), "2" (src)
+ : "memory");
+
+ return dest;
}
+#else
+void *memcpy(void *dest, const void *src, size_t n)
+{
+ long d0, d1, d2;
+ asm volatile(
+ "rep ; movsq\n\t"
+ "movq %4,%%rcx\n\t"
+ "rep ; movsb\n\t"
+ : "=&c" (d0), "=&D" (d1), "=&S" (d2)
+ : "0" (n >> 3), "g" (n & 7), "1" (dest), "2" (src)
+ : "memory");
-#include "../string.c"
+ return dest;
+}
+#endif
+
+void *memset(void *s, int c, size_t n)
+{
+ int i;
+ char *ss = s;
+
+ for (i = 0; i < n; i++)
+ ss[i] = c;
+ return s;
+}
diff --git a/arch/x86/boot/cpucheck.c b/arch/x86/boot/cpucheck.c
index 100a9a10076a..1fd7d575092e 100644
--- a/arch/x86/boot/cpucheck.c
+++ b/arch/x86/boot/cpucheck.c
@@ -27,6 +27,7 @@
#include <asm/processor-flags.h>
#include <asm/required-features.h>
#include <asm/msr-index.h>
+#include "string.h"
static u32 err_flags[NCAPINTS];
@@ -67,6 +68,13 @@ static int is_transmeta(void)
cpu_vendor[2] == A32('M', 'x', '8', '6');
}
+static int is_intel(void)
+{
+ return cpu_vendor[0] == A32('G', 'e', 'n', 'u') &&
+ cpu_vendor[1] == A32('i', 'n', 'e', 'I') &&
+ cpu_vendor[2] == A32('n', 't', 'e', 'l');
+}
+
/* Returns a bitmask of which words we have error bits in */
static int check_cpuflags(void)
{
@@ -153,6 +161,19 @@ int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr)
asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx));
err = check_cpuflags();
+ } else if (err == 0x01 &&
+ !(err_flags[0] & ~(1 << X86_FEATURE_PAE)) &&
+ is_intel() && cpu.level == 6 &&
+ (cpu.model == 9 || cpu.model == 13)) {
+ /* PAE is disabled on this Pentium M but can be forced */
+ if (cmdline_find_option_bool("forcepae")) {
+ puts("WARNING: Forcing PAE in CPU flags\n");
+ set_bit(X86_FEATURE_PAE, cpu.flags);
+ err = check_cpuflags();
+ }
+ else {
+ puts("WARNING: PAE disabled. Use parameter 'forcepae' to enable at your own risk!\n");
+ }
}
if (err_flags_ptr)
diff --git a/arch/x86/boot/edd.c b/arch/x86/boot/edd.c
index c501a5b466f8..223e42527077 100644
--- a/arch/x86/boot/edd.c
+++ b/arch/x86/boot/edd.c
@@ -15,6 +15,7 @@
#include "boot.h"
#include <linux/edd.h>
+#include "string.h"
#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index ec3b8ba68096..0ca9a5c362bc 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -283,7 +283,7 @@ _start:
# Part 2 of the header, from the old setup.S
.ascii "HdrS" # header signature
- .word 0x020c # header version number (>= 0x0105)
+ .word 0x020d # header version number (>= 0x0105)
# or else old loadlin-1.5 will fail)
.globl realmode_swtch
realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
@@ -350,7 +350,7 @@ cmd_line_ptr: .long 0 # (Header version 0x0202 or later)
# can be located anywhere in
# low memory 0x10000 or higher.
-ramdisk_max: .long 0x7fffffff
+initrd_addr_max: .long 0x7fffffff
# (Header version 0x0203 or later)
# The highest safe address for
# the contents of an initrd
@@ -375,7 +375,8 @@ xloadflags:
# define XLF0 0
#endif
-#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_X86_64)
+#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_X86_64) && \
+ !defined(CONFIG_EFI_MIXED)
/* kernel/boot_param/ramdisk could be loaded above 4g */
# define XLF1 XLF_CAN_BE_LOADED_ABOVE_4G
#else
@@ -383,10 +384,14 @@ xloadflags:
#endif
#ifdef CONFIG_EFI_STUB
-# ifdef CONFIG_X86_64
-# define XLF23 XLF_EFI_HANDOVER_64 /* 64-bit EFI handover ok */
+# ifdef CONFIG_EFI_MIXED
+# define XLF23 (XLF_EFI_HANDOVER_32|XLF_EFI_HANDOVER_64)
# else
-# define XLF23 XLF_EFI_HANDOVER_32 /* 32-bit EFI handover ok */
+# ifdef CONFIG_X86_64
+# define XLF23 XLF_EFI_HANDOVER_64 /* 64-bit EFI handover ok */
+# else
+# define XLF23 XLF_EFI_HANDOVER_32 /* 32-bit EFI handover ok */
+# endif
# endif
#else
# define XLF23 0
@@ -426,13 +431,7 @@ pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr
#define INIT_SIZE VO_INIT_SIZE
#endif
init_size: .long INIT_SIZE # kernel initialization size
-handover_offset:
-#ifdef CONFIG_EFI_STUB
- .long 0x30 # offset to the handover
- # protocol entry point
-#else
- .long 0
-#endif
+handover_offset: .long 0 # Filled in by build.c
# End of setup header #####################################################
diff --git a/arch/x86/boot/main.c b/arch/x86/boot/main.c
index cf6083d444f4..fd6c9f236996 100644
--- a/arch/x86/boot/main.c
+++ b/arch/x86/boot/main.c
@@ -14,6 +14,7 @@
*/
#include "boot.h"
+#include "string.h"
struct boot_params boot_params __attribute__((aligned(16)));
diff --git a/arch/x86/boot/regs.c b/arch/x86/boot/regs.c
index 958019b1cfa5..c0fb356a3092 100644
--- a/arch/x86/boot/regs.c
+++ b/arch/x86/boot/regs.c
@@ -17,6 +17,7 @@
*/
#include "boot.h"
+#include "string.h"
void initregs(struct biosregs *reg)
{
diff --git a/arch/x86/boot/string.c b/arch/x86/boot/string.c
index 574dedfe2890..5339040ef86e 100644
--- a/arch/x86/boot/string.c
+++ b/arch/x86/boot/string.c
@@ -14,6 +14,20 @@
#include "boot.h"
+/*
+ * This file gets included in compressed/string.c which might pull in
+ * string_32.h and which in turn maps memcmp to __builtin_memcmp(). Undo
+ * that first.
+ */
+#undef memcmp
+int memcmp(const void *s1, const void *s2, size_t len)
+{
+ u8 diff;
+ asm("repe; cmpsb; setnz %0"
+ : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len));
+ return diff;
+}
+
int strcmp(const char *str1, const char *str2)
{
const unsigned char *s1 = (const unsigned char *)str1;
diff --git a/arch/x86/boot/string.h b/arch/x86/boot/string.h
new file mode 100644
index 000000000000..725e820602b1
--- /dev/null
+++ b/arch/x86/boot/string.h
@@ -0,0 +1,21 @@
+#ifndef BOOT_STRING_H
+#define BOOT_STRING_H
+
+/* Undef any of these macros coming from string_32.h. */
+#undef memcpy
+#undef memset
+#undef memcmp
+
+void *memcpy(void *dst, const void *src, size_t len);
+void *memset(void *dst, int c, size_t len);
+int memcmp(const void *s1, const void *s2, size_t len);
+
+/*
+ * Access builtin version by default. If one needs to use optimized version,
+ * do "undef memcpy" in .c file and link against right string.c
+ */
+#define memcpy(d,s,l) __builtin_memcpy(d,s,l)
+#define memset(d,c,l) __builtin_memset(d,c,l)
+#define memcmp __builtin_memcmp
+
+#endif /* BOOT_STRING_H */
diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c
index 8e15b22391fc..1a2f2121cada 100644
--- a/arch/x86/boot/tools/build.c
+++ b/arch/x86/boot/tools/build.c
@@ -53,7 +53,8 @@ int is_big_kernel;
#define PECOFF_RELOC_RESERVE 0x20
-unsigned long efi_stub_entry;
+unsigned long efi32_stub_entry;
+unsigned long efi64_stub_entry;
unsigned long efi_pe_entry;
unsigned long startup_64;
@@ -219,6 +220,52 @@ static void update_pecoff_text(unsigned int text_start, unsigned int file_sz)
update_pecoff_section_header(".text", text_start, text_sz);
}
+static int reserve_pecoff_reloc_section(int c)
+{
+ /* Reserve 0x20 bytes for .reloc section */
+ memset(buf+c, 0, PECOFF_RELOC_RESERVE);
+ return PECOFF_RELOC_RESERVE;
+}
+
+static void efi_stub_defaults(void)
+{
+ /* Defaults for old kernel */
+#ifdef CONFIG_X86_32
+ efi_pe_entry = 0x10;
+#else
+ efi_pe_entry = 0x210;
+ startup_64 = 0x200;
+#endif
+}
+
+static void efi_stub_entry_update(void)
+{
+ unsigned long addr = efi32_stub_entry;
+
+#ifdef CONFIG_X86_64
+ /* Yes, this is really how we defined it :( */
+ addr = efi64_stub_entry - 0x200;
+#endif
+
+#ifdef CONFIG_EFI_MIXED
+ if (efi32_stub_entry != addr)
+ die("32-bit and 64-bit EFI entry points do not match\n");
+#endif
+ put_unaligned_le32(addr, &buf[0x264]);
+}
+
+#else
+
+static inline void update_pecoff_setup_and_reloc(unsigned int size) {}
+static inline void update_pecoff_text(unsigned int text_start,
+ unsigned int file_sz) {}
+static inline void efi_stub_defaults(void) {}
+static inline void efi_stub_entry_update(void) {}
+
+static inline int reserve_pecoff_reloc_section(int c)
+{
+ return 0;
+}
#endif /* CONFIG_EFI_STUB */
@@ -250,7 +297,8 @@ static void parse_zoffset(char *fname)
p = (char *)buf;
while (p && *p) {
- PARSE_ZOFS(p, efi_stub_entry);
+ PARSE_ZOFS(p, efi32_stub_entry);
+ PARSE_ZOFS(p, efi64_stub_entry);
PARSE_ZOFS(p, efi_pe_entry);
PARSE_ZOFS(p, startup_64);
@@ -271,15 +319,7 @@ int main(int argc, char ** argv)
void *kernel;
u32 crc = 0xffffffffUL;
- /* Defaults for old kernel */
-#ifdef CONFIG_X86_32
- efi_pe_entry = 0x10;
- efi_stub_entry = 0x30;
-#else
- efi_pe_entry = 0x210;
- efi_stub_entry = 0x230;
- startup_64 = 0x200;
-#endif
+ efi_stub_defaults();
if (argc != 5)
usage();
@@ -302,11 +342,7 @@ int main(int argc, char ** argv)
die("Boot block hasn't got boot flag (0xAA55)");
fclose(file);
-#ifdef CONFIG_EFI_STUB
- /* Reserve 0x20 bytes for .reloc section */
- memset(buf+c, 0, PECOFF_RELOC_RESERVE);
- c += PECOFF_RELOC_RESERVE;
-#endif
+ c += reserve_pecoff_reloc_section(c);
/* Pad unused space with zeros */
setup_sectors = (c + 511) / 512;
@@ -315,9 +351,7 @@ int main(int argc, char ** argv)
i = setup_sectors*512;
memset(buf+c, 0, i-c);
-#ifdef CONFIG_EFI_STUB
update_pecoff_setup_and_reloc(i);
-#endif
/* Set the default root device */
put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]);
@@ -342,14 +376,9 @@ int main(int argc, char ** argv)
buf[0x1f1] = setup_sectors-1;
put_unaligned_le32(sys_size, &buf[0x1f4]);
-#ifdef CONFIG_EFI_STUB
update_pecoff_text(setup_sectors * 512, sz + i + ((sys_size * 16) - sz));
-#ifdef CONFIG_X86_64 /* Yes, this is really how we defined it :( */
- efi_stub_entry -= 0x200;
-#endif
- put_unaligned_le32(efi_stub_entry, &buf[0x264]);
-#endif
+ efi_stub_entry_update();
crc = partial_crc32(buf, i, crc);
if (fwrite(buf, 1, i, dest) != i)
diff --git a/arch/x86/boot/video-vesa.c b/arch/x86/boot/video-vesa.c
index 11e8c6eb80a1..ba3e100654db 100644
--- a/arch/x86/boot/video-vesa.c
+++ b/arch/x86/boot/video-vesa.c
@@ -16,6 +16,7 @@
#include "boot.h"
#include "video.h"
#include "vesa.h"
+#include "string.h"
/* VESA information */
static struct vesa_general_info vginfo;
diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig
index a7fef2621cc9..619e7f7426c6 100644
--- a/arch/x86/configs/i386_defconfig
+++ b/arch/x86/configs/i386_defconfig
@@ -60,7 +60,6 @@ CONFIG_CRASH_DUMP=y
CONFIG_HIBERNATION=y
CONFIG_PM_DEBUG=y
CONFIG_PM_TRACE_RTC=y
-CONFIG_ACPI_PROCFS=y
CONFIG_ACPI_DOCK=y
CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_STAT is not set
diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig
index c1119d4c1281..6181c69b786b 100644
--- a/arch/x86/configs/x86_64_defconfig
+++ b/arch/x86/configs/x86_64_defconfig
@@ -58,7 +58,6 @@ CONFIG_CRASH_DUMP=y
CONFIG_HIBERNATION=y
CONFIG_PM_DEBUG=y
CONFIG_PM_TRACE_RTC=y
-CONFIG_ACPI_PROCFS=y
CONFIG_ACPI_DOCK=y
CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_STAT is not set
diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile
index 6ba54d640383..61d6e281898b 100644
--- a/arch/x86/crypto/Makefile
+++ b/arch/x86/crypto/Makefile
@@ -79,6 +79,9 @@ aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o fpu.o
aesni-intel-$(CONFIG_64BIT) += aesni-intel_avx-x86_64.o
ghash-clmulni-intel-y := ghash-clmulni-intel_asm.o ghash-clmulni-intel_glue.o
sha1-ssse3-y := sha1_ssse3_asm.o sha1_ssse3_glue.o
+ifeq ($(avx2_supported),yes)
+sha1-ssse3-y += sha1_avx2_x86_64_asm.o
+endif
crc32c-intel-y := crc32c-intel_glue.o
crc32c-intel-$(CONFIG_64BIT) += crc32c-pcl-intel-asm_64.o
crc32-pclmul-y := crc32-pclmul_asm.o crc32-pclmul_glue.o
diff --git a/arch/x86/crypto/blowfish_glue.c b/arch/x86/crypto/blowfish_glue.c
index 50ec333b70e6..8af519ed73d1 100644
--- a/arch/x86/crypto/blowfish_glue.c
+++ b/arch/x86/crypto/blowfish_glue.c
@@ -223,9 +223,6 @@ static unsigned int __cbc_decrypt(struct blkcipher_desc *desc,
src -= 1;
dst -= 1;
} while (nbytes >= bsize * 4);
-
- if (nbytes < bsize)
- goto done;
}
/* Handle leftovers */
diff --git a/arch/x86/crypto/cast5_avx_glue.c b/arch/x86/crypto/cast5_avx_glue.c
index e6a3700489b9..e57e20ab5e0b 100644
--- a/arch/x86/crypto/cast5_avx_glue.c
+++ b/arch/x86/crypto/cast5_avx_glue.c
@@ -203,9 +203,6 @@ static unsigned int __cbc_decrypt(struct blkcipher_desc *desc,
src -= 1;
dst -= 1;
} while (nbytes >= bsize * CAST5_PARALLEL_BLOCKS);
-
- if (nbytes < bsize)
- goto done;
}
/* Handle leftovers */
diff --git a/arch/x86/crypto/ghash-clmulni-intel_asm.S b/arch/x86/crypto/ghash-clmulni-intel_asm.S
index 586f41aac361..185fad49d86f 100644
--- a/arch/x86/crypto/ghash-clmulni-intel_asm.S
+++ b/arch/x86/crypto/ghash-clmulni-intel_asm.S
@@ -24,10 +24,6 @@
.align 16
.Lbswap_mask:
.octa 0x000102030405060708090a0b0c0d0e0f
-.Lpoly:
- .octa 0xc2000000000000000000000000000001
-.Ltwo_one:
- .octa 0x00000001000000000000000000000001
#define DATA %xmm0
#define SHASH %xmm1
@@ -134,28 +130,3 @@ ENTRY(clmul_ghash_update)
.Lupdate_just_ret:
ret
ENDPROC(clmul_ghash_update)
-
-/*
- * void clmul_ghash_setkey(be128 *shash, const u8 *key);
- *
- * Calculate hash_key << 1 mod poly
- */
-ENTRY(clmul_ghash_setkey)
- movaps .Lbswap_mask, BSWAP
- movups (%rsi), %xmm0
- PSHUFB_XMM BSWAP %xmm0
- movaps %xmm0, %xmm1
- psllq $1, %xmm0
- psrlq $63, %xmm1
- movaps %xmm1, %xmm2
- pslldq $8, %xmm1
- psrldq $8, %xmm2
- por %xmm1, %xmm0
- # reduction
- pshufd $0b00100100, %xmm2, %xmm1
- pcmpeqd .Ltwo_one, %xmm1
- pand .Lpoly, %xmm1
- pxor %xmm1, %xmm0
- movups %xmm0, (%rdi)
- ret
-ENDPROC(clmul_ghash_setkey)
diff --git a/arch/x86/crypto/ghash-clmulni-intel_glue.c b/arch/x86/crypto/ghash-clmulni-intel_glue.c
index 6759dd1135be..d785cf2c529c 100644
--- a/arch/x86/crypto/ghash-clmulni-intel_glue.c
+++ b/arch/x86/crypto/ghash-clmulni-intel_glue.c
@@ -30,8 +30,6 @@ void clmul_ghash_mul(char *dst, const be128 *shash);
void clmul_ghash_update(char *dst, const char *src, unsigned int srclen,
const be128 *shash);
-void clmul_ghash_setkey(be128 *shash, const u8 *key);
-
struct ghash_async_ctx {
struct cryptd_ahash *cryptd_tfm;
};
@@ -58,13 +56,23 @@ static int ghash_setkey(struct crypto_shash *tfm,
const u8 *key, unsigned int keylen)
{
struct ghash_ctx *ctx = crypto_shash_ctx(tfm);
+ be128 *x = (be128 *)key;
+ u64 a, b;
if (keylen != GHASH_BLOCK_SIZE) {
crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
return -EINVAL;
}
- clmul_ghash_setkey(&ctx->shash, key);
+ /* perform multiplication by 'x' in GF(2^128) */
+ a = be64_to_cpu(x->a);
+ b = be64_to_cpu(x->b);
+
+ ctx->shash.a = (__be64)((b << 1) | (a >> 63));
+ ctx->shash.b = (__be64)((a << 1) | (b >> 63));
+
+ if (a >> 63)
+ ctx->shash.b ^= cpu_to_be64(0xc2);
return 0;
}
diff --git a/arch/x86/crypto/sha1_avx2_x86_64_asm.S b/arch/x86/crypto/sha1_avx2_x86_64_asm.S
new file mode 100644
index 000000000000..1cd792db15ef
--- /dev/null
+++ b/arch/x86/crypto/sha1_avx2_x86_64_asm.S
@@ -0,0 +1,708 @@
+/*
+ * Implement fast SHA-1 with AVX2 instructions. (x86_64)
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * 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.
+ *
+ * Contact Information:
+ * Ilya Albrekht <ilya.albrekht@intel.com>
+ * Maxim Locktyukhin <maxim.locktyukhin@intel.com>
+ * Ronen Zohar <ronen.zohar@intel.com>
+ * Chandramouli Narayanan <mouli@linux.intel.com>
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * SHA-1 implementation with Intel(R) AVX2 instruction set extensions.
+ *
+ *This implementation is based on the previous SSSE3 release:
+ *Visit http://software.intel.com/en-us/articles/
+ *and refer to improving-the-performance-of-the-secure-hash-algorithm-1/
+ *
+ *Updates 20-byte SHA-1 record in 'hash' for even number of
+ *'num_blocks' consecutive 64-byte blocks
+ *
+ *extern "C" void sha1_transform_avx2(
+ * int *hash, const char* input, size_t num_blocks );
+ */
+
+#include <linux/linkage.h>
+
+#define CTX %rdi /* arg1 */
+#define BUF %rsi /* arg2 */
+#define CNT %rdx /* arg3 */
+
+#define REG_A %ecx
+#define REG_B %esi
+#define REG_C %edi
+#define REG_D %eax
+#define REG_E %edx
+#define REG_TB %ebx
+#define REG_TA %r12d
+#define REG_RA %rcx
+#define REG_RB %rsi
+#define REG_RC %rdi
+#define REG_RD %rax
+#define REG_RE %rdx
+#define REG_RTA %r12
+#define REG_RTB %rbx
+#define REG_T1 %ebp
+#define xmm_mov vmovups
+#define avx2_zeroupper vzeroupper
+#define RND_F1 1
+#define RND_F2 2
+#define RND_F3 3
+
+.macro REGALLOC
+ .set A, REG_A
+ .set B, REG_B
+ .set C, REG_C
+ .set D, REG_D
+ .set E, REG_E
+ .set TB, REG_TB
+ .set TA, REG_TA
+
+ .set RA, REG_RA
+ .set RB, REG_RB
+ .set RC, REG_RC
+ .set RD, REG_RD
+ .set RE, REG_RE
+
+ .set RTA, REG_RTA
+ .set RTB, REG_RTB
+
+ .set T1, REG_T1
+.endm
+
+#define K_BASE %r8
+#define HASH_PTR %r9
+#define BUFFER_PTR %r10
+#define BUFFER_PTR2 %r13
+#define BUFFER_END %r11
+
+#define PRECALC_BUF %r14
+#define WK_BUF %r15
+
+#define W_TMP %xmm0
+#define WY_TMP %ymm0
+#define WY_TMP2 %ymm9
+
+# AVX2 variables
+#define WY0 %ymm3
+#define WY4 %ymm5
+#define WY08 %ymm7
+#define WY12 %ymm8
+#define WY16 %ymm12
+#define WY20 %ymm13
+#define WY24 %ymm14
+#define WY28 %ymm15
+
+#define YMM_SHUFB_BSWAP %ymm10
+
+/*
+ * Keep 2 iterations precalculated at a time:
+ * - 80 DWORDs per iteration * 2
+ */
+#define W_SIZE (80*2*2 +16)
+
+#define WK(t) ((((t) % 80) / 4)*32 + ( (t) % 4)*4 + ((t)/80)*16 )(WK_BUF)
+#define PRECALC_WK(t) ((t)*2*2)(PRECALC_BUF)
+
+
+.macro UPDATE_HASH hash, val
+ add \hash, \val
+ mov \val, \hash
+.endm
+
+.macro PRECALC_RESET_WY
+ .set WY_00, WY0
+ .set WY_04, WY4
+ .set WY_08, WY08
+ .set WY_12, WY12
+ .set WY_16, WY16
+ .set WY_20, WY20
+ .set WY_24, WY24
+ .set WY_28, WY28
+ .set WY_32, WY_00
+.endm
+
+.macro PRECALC_ROTATE_WY
+ /* Rotate macros */
+ .set WY_32, WY_28
+ .set WY_28, WY_24
+ .set WY_24, WY_20
+ .set WY_20, WY_16
+ .set WY_16, WY_12
+ .set WY_12, WY_08
+ .set WY_08, WY_04
+ .set WY_04, WY_00
+ .set WY_00, WY_32
+
+ /* Define register aliases */
+ .set WY, WY_00
+ .set WY_minus_04, WY_04
+ .set WY_minus_08, WY_08
+ .set WY_minus_12, WY_12
+ .set WY_minus_16, WY_16
+ .set WY_minus_20, WY_20
+ .set WY_minus_24, WY_24
+ .set WY_minus_28, WY_28
+ .set WY_minus_32, WY
+.endm
+
+.macro PRECALC_00_15
+ .if (i == 0) # Initialize and rotate registers
+ PRECALC_RESET_WY
+ PRECALC_ROTATE_WY
+ .endif
+
+ /* message scheduling pre-compute for rounds 0-15 */
+ .if ((i & 7) == 0)
+ /*
+ * blended AVX2 and ALU instruction scheduling
+ * 1 vector iteration per 8 rounds
+ */
+ vmovdqu ((i * 2) + PRECALC_OFFSET)(BUFFER_PTR), W_TMP
+ .elseif ((i & 7) == 1)
+ vinsertf128 $1, (((i-1) * 2)+PRECALC_OFFSET)(BUFFER_PTR2),\
+ WY_TMP, WY_TMP
+ .elseif ((i & 7) == 2)
+ vpshufb YMM_SHUFB_BSWAP, WY_TMP, WY
+ .elseif ((i & 7) == 4)
+ vpaddd K_XMM(K_BASE), WY, WY_TMP
+ .elseif ((i & 7) == 7)
+ vmovdqu WY_TMP, PRECALC_WK(i&~7)
+
+ PRECALC_ROTATE_WY
+ .endif
+.endm
+
+.macro PRECALC_16_31
+ /*
+ * message scheduling pre-compute for rounds 16-31
+ * calculating last 32 w[i] values in 8 XMM registers
+ * pre-calculate K+w[i] values and store to mem
+ * for later load by ALU add instruction
+ *
+ * "brute force" vectorization for rounds 16-31 only
+ * due to w[i]->w[i-3] dependency
+ */
+ .if ((i & 7) == 0)
+ /*
+ * blended AVX2 and ALU instruction scheduling
+ * 1 vector iteration per 8 rounds
+ */
+ /* w[i-14] */
+ vpalignr $8, WY_minus_16, WY_minus_12, WY
+ vpsrldq $4, WY_minus_04, WY_TMP /* w[i-3] */
+ .elseif ((i & 7) == 1)
+ vpxor WY_minus_08, WY, WY
+ vpxor WY_minus_16, WY_TMP, WY_TMP
+ .elseif ((i & 7) == 2)
+ vpxor WY_TMP, WY, WY
+ vpslldq $12, WY, WY_TMP2
+ .elseif ((i & 7) == 3)
+ vpslld $1, WY, WY_TMP
+ vpsrld $31, WY, WY
+ .elseif ((i & 7) == 4)
+ vpor WY, WY_TMP, WY_TMP
+ vpslld $2, WY_TMP2, WY
+ .elseif ((i & 7) == 5)
+ vpsrld $30, WY_TMP2, WY_TMP2
+ vpxor WY, WY_TMP, WY_TMP
+ .elseif ((i & 7) == 7)
+ vpxor WY_TMP2, WY_TMP, WY
+ vpaddd K_XMM(K_BASE), WY, WY_TMP
+ vmovdqu WY_TMP, PRECALC_WK(i&~7)
+
+ PRECALC_ROTATE_WY
+ .endif
+.endm
+
+.macro PRECALC_32_79
+ /*
+ * in SHA-1 specification:
+ * w[i] = (w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]) rol 1
+ * instead we do equal:
+ * w[i] = (w[i-6] ^ w[i-16] ^ w[i-28] ^ w[i-32]) rol 2
+ * allows more efficient vectorization
+ * since w[i]=>w[i-3] dependency is broken
+ */
+
+ .if ((i & 7) == 0)
+ /*
+ * blended AVX2 and ALU instruction scheduling
+ * 1 vector iteration per 8 rounds
+ */
+ vpalignr $8, WY_minus_08, WY_minus_04, WY_TMP
+ .elseif ((i & 7) == 1)
+ /* W is W_minus_32 before xor */
+ vpxor WY_minus_28, WY, WY
+ .elseif ((i & 7) == 2)
+ vpxor WY_minus_16, WY_TMP, WY_TMP
+ .elseif ((i & 7) == 3)
+ vpxor WY_TMP, WY, WY
+ .elseif ((i & 7) == 4)
+ vpslld $2, WY, WY_TMP
+ .elseif ((i & 7) == 5)
+ vpsrld $30, WY, WY
+ vpor WY, WY_TMP, WY
+ .elseif ((i & 7) == 7)
+ vpaddd K_XMM(K_BASE), WY, WY_TMP
+ vmovdqu WY_TMP, PRECALC_WK(i&~7)
+
+ PRECALC_ROTATE_WY
+ .endif
+.endm
+
+.macro PRECALC r, s
+ .set i, \r
+
+ .if (i < 40)
+ .set K_XMM, 32*0
+ .elseif (i < 80)
+ .set K_XMM, 32*1
+ .elseif (i < 120)
+ .set K_XMM, 32*2
+ .else
+ .set K_XMM, 32*3
+ .endif
+
+ .if (i<32)
+ PRECALC_00_15 \s
+ .elseif (i<64)
+ PRECALC_16_31 \s
+ .elseif (i < 160)
+ PRECALC_32_79 \s
+ .endif
+.endm
+
+.macro ROTATE_STATE
+ .set T_REG, E
+ .set E, D
+ .set D, C
+ .set C, B
+ .set B, TB
+ .set TB, A
+ .set A, T_REG
+
+ .set T_REG, RE
+ .set RE, RD
+ .set RD, RC
+ .set RC, RB
+ .set RB, RTB
+ .set RTB, RA
+ .set RA, T_REG
+.endm
+
+/* Macro relies on saved ROUND_Fx */
+
+.macro RND_FUN f, r
+ .if (\f == RND_F1)
+ ROUND_F1 \r
+ .elseif (\f == RND_F2)
+ ROUND_F2 \r
+ .elseif (\f == RND_F3)
+ ROUND_F3 \r
+ .endif
+.endm
+
+.macro RR r
+ .set round_id, (\r % 80)
+
+ .if (round_id == 0) /* Precalculate F for first round */
+ .set ROUND_FUNC, RND_F1
+ mov B, TB
+
+ rorx $(32-30), B, B /* b>>>2 */
+ andn D, TB, T1
+ and C, TB
+ xor T1, TB
+ .endif
+
+ RND_FUN ROUND_FUNC, \r
+ ROTATE_STATE
+
+ .if (round_id == 18)
+ .set ROUND_FUNC, RND_F2
+ .elseif (round_id == 38)
+ .set ROUND_FUNC, RND_F3
+ .elseif (round_id == 58)
+ .set ROUND_FUNC, RND_F2
+ .endif
+
+ .set round_id, ( (\r+1) % 80)
+
+ RND_FUN ROUND_FUNC, (\r+1)
+ ROTATE_STATE
+.endm
+
+.macro ROUND_F1 r
+ add WK(\r), E
+
+ andn C, A, T1 /* ~b&d */
+ lea (RE,RTB), E /* Add F from the previous round */
+
+ rorx $(32-5), A, TA /* T2 = A >>> 5 */
+ rorx $(32-30),A, TB /* b>>>2 for next round */
+
+ PRECALC (\r) /* msg scheduling for next 2 blocks */
+
+ /*
+ * Calculate F for the next round
+ * (b & c) ^ andn[b, d]
+ */
+ and B, A /* b&c */
+ xor T1, A /* F1 = (b&c) ^ (~b&d) */
+
+ lea (RE,RTA), E /* E += A >>> 5 */
+.endm
+
+.macro ROUND_F2 r
+ add WK(\r), E
+ lea (RE,RTB), E /* Add F from the previous round */
+
+ /* Calculate F for the next round */
+ rorx $(32-5), A, TA /* T2 = A >>> 5 */
+ .if ((round_id) < 79)
+ rorx $(32-30), A, TB /* b>>>2 for next round */
+ .endif
+ PRECALC (\r) /* msg scheduling for next 2 blocks */
+
+ .if ((round_id) < 79)
+ xor B, A
+ .endif
+
+ add TA, E /* E += A >>> 5 */
+
+ .if ((round_id) < 79)
+ xor C, A
+ .endif
+.endm
+
+.macro ROUND_F3 r
+ add WK(\r), E
+ PRECALC (\r) /* msg scheduling for next 2 blocks */
+
+ lea (RE,RTB), E /* Add F from the previous round */
+
+ mov B, T1
+ or A, T1
+
+ rorx $(32-5), A, TA /* T2 = A >>> 5 */
+ rorx $(32-30), A, TB /* b>>>2 for next round */
+
+ /* Calculate F for the next round
+ * (b and c) or (d and (b or c))
+ */
+ and C, T1
+ and B, A
+ or T1, A
+
+ add TA, E /* E += A >>> 5 */
+
+.endm
+
+/*
+ * macro implements 80 rounds of SHA-1, for multiple blocks with s/w pipelining
+ */
+.macro SHA1_PIPELINED_MAIN_BODY
+
+ REGALLOC
+
+ mov (HASH_PTR), A
+ mov 4(HASH_PTR), B
+ mov 8(HASH_PTR), C
+ mov 12(HASH_PTR), D
+ mov 16(HASH_PTR), E
+
+ mov %rsp, PRECALC_BUF
+ lea (2*4*80+32)(%rsp), WK_BUF
+
+ # Precalc WK for first 2 blocks
+ PRECALC_OFFSET = 0
+ .set i, 0
+ .rept 160
+ PRECALC i
+ .set i, i + 1
+ .endr
+ PRECALC_OFFSET = 128
+ xchg WK_BUF, PRECALC_BUF
+
+ .align 32
+_loop:
+ /*
+ * code loops through more than one block
+ * we use K_BASE value as a signal of a last block,
+ * it is set below by: cmovae BUFFER_PTR, K_BASE
+ */
+ cmp K_BASE, BUFFER_PTR
+ jne _begin
+ .align 32
+ jmp _end
+ .align 32
+_begin:
+
+ /*
+ * Do first block
+ * rounds: 0,2,4,6,8
+ */
+ .set j, 0
+ .rept 5
+ RR j
+ .set j, j+2
+ .endr
+
+ jmp _loop0
+_loop0:
+
+ /*
+ * rounds:
+ * 10,12,14,16,18
+ * 20,22,24,26,28
+ * 30,32,34,36,38
+ * 40,42,44,46,48
+ * 50,52,54,56,58
+ */
+ .rept 25
+ RR j
+ .set j, j+2
+ .endr
+
+ add $(2*64), BUFFER_PTR /* move to next odd-64-byte block */
+ cmp BUFFER_END, BUFFER_PTR /* is current block the last one? */
+ cmovae K_BASE, BUFFER_PTR /* signal the last iteration smartly */
+
+ /*
+ * rounds
+ * 60,62,64,66,68
+ * 70,72,74,76,78
+ */
+ .rept 10
+ RR j
+ .set j, j+2
+ .endr
+
+ UPDATE_HASH (HASH_PTR), A
+ UPDATE_HASH 4(HASH_PTR), TB
+ UPDATE_HASH 8(HASH_PTR), C
+ UPDATE_HASH 12(HASH_PTR), D
+ UPDATE_HASH 16(HASH_PTR), E
+
+ cmp K_BASE, BUFFER_PTR /* is current block the last one? */
+ je _loop
+
+ mov TB, B
+
+ /* Process second block */
+ /*
+ * rounds
+ * 0+80, 2+80, 4+80, 6+80, 8+80
+ * 10+80,12+80,14+80,16+80,18+80
+ */
+
+ .set j, 0
+ .rept 10
+ RR j+80
+ .set j, j+2
+ .endr
+
+ jmp _loop1
+_loop1:
+ /*
+ * rounds
+ * 20+80,22+80,24+80,26+80,28+80
+ * 30+80,32+80,34+80,36+80,38+80
+ */
+ .rept 10
+ RR j+80
+ .set j, j+2
+ .endr
+
+ jmp _loop2
+_loop2:
+
+ /*
+ * rounds
+ * 40+80,42+80,44+80,46+80,48+80
+ * 50+80,52+80,54+80,56+80,58+80
+ */
+ .rept 10
+ RR j+80
+ .set j, j+2
+ .endr
+
+ add $(2*64), BUFFER_PTR2 /* move to next even-64-byte block */
+
+ cmp BUFFER_END, BUFFER_PTR2 /* is current block the last one */
+ cmovae K_BASE, BUFFER_PTR /* signal the last iteration smartly */
+
+ jmp _loop3
+_loop3:
+
+ /*
+ * rounds
+ * 60+80,62+80,64+80,66+80,68+80
+ * 70+80,72+80,74+80,76+80,78+80
+ */
+ .rept 10
+ RR j+80
+ .set j, j+2
+ .endr
+
+ UPDATE_HASH (HASH_PTR), A
+ UPDATE_HASH 4(HASH_PTR), TB
+ UPDATE_HASH 8(HASH_PTR), C
+ UPDATE_HASH 12(HASH_PTR), D
+ UPDATE_HASH 16(HASH_PTR), E
+
+ /* Reset state for AVX2 reg permutation */
+ mov A, TA
+ mov TB, A
+ mov C, TB
+ mov E, C
+ mov D, B
+ mov TA, D
+
+ REGALLOC
+
+ xchg WK_BUF, PRECALC_BUF
+
+ jmp _loop
+
+ .align 32
+ _end:
+
+.endm
+/*
+ * macro implements SHA-1 function's body for several 64-byte blocks
+ * param: function's name
+ */
+.macro SHA1_VECTOR_ASM name
+ ENTRY(\name)
+
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+
+ RESERVE_STACK = (W_SIZE*4 + 8+24)
+
+ /* Align stack */
+ mov %rsp, %rbx
+ and $~(0x20-1), %rsp
+ push %rbx
+ sub $RESERVE_STACK, %rsp
+
+ avx2_zeroupper
+
+ lea K_XMM_AR(%rip), K_BASE
+
+ mov CTX, HASH_PTR
+ mov BUF, BUFFER_PTR
+ lea 64(BUF), BUFFER_PTR2
+
+ shl $6, CNT /* mul by 64 */
+ add BUF, CNT
+ add $64, CNT
+ mov CNT, BUFFER_END
+
+ cmp BUFFER_END, BUFFER_PTR2
+ cmovae K_BASE, BUFFER_PTR2
+
+ xmm_mov BSWAP_SHUFB_CTL(%rip), YMM_SHUFB_BSWAP
+
+ SHA1_PIPELINED_MAIN_BODY
+
+ avx2_zeroupper
+
+ add $RESERVE_STACK, %rsp
+ pop %rsp
+
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+
+ ret
+
+ ENDPROC(\name)
+.endm
+
+.section .rodata
+
+#define K1 0x5a827999
+#define K2 0x6ed9eba1
+#define K3 0x8f1bbcdc
+#define K4 0xca62c1d6
+
+.align 128
+K_XMM_AR:
+ .long K1, K1, K1, K1
+ .long K1, K1, K1, K1
+ .long K2, K2, K2, K2
+ .long K2, K2, K2, K2
+ .long K3, K3, K3, K3
+ .long K3, K3, K3, K3
+ .long K4, K4, K4, K4
+ .long K4, K4, K4, K4
+
+BSWAP_SHUFB_CTL:
+ .long 0x00010203
+ .long 0x04050607
+ .long 0x08090a0b
+ .long 0x0c0d0e0f
+ .long 0x00010203
+ .long 0x04050607
+ .long 0x08090a0b
+ .long 0x0c0d0e0f
+.text
+
+SHA1_VECTOR_ASM sha1_transform_avx2
diff --git a/arch/x86/crypto/sha1_ssse3_glue.c b/arch/x86/crypto/sha1_ssse3_glue.c
index 4a11a9d72451..74d16ef707c7 100644
--- a/arch/x86/crypto/sha1_ssse3_glue.c
+++ b/arch/x86/crypto/sha1_ssse3_glue.c
@@ -10,6 +10,7 @@
* Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
* Copyright (c) Jean-Francois Dive <jef@linuxbe.org>
* Copyright (c) Mathias Krause <minipli@googlemail.com>
+ * Copyright (c) Chandramouli Narayanan <mouli@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -39,6 +40,12 @@ asmlinkage void sha1_transform_ssse3(u32 *digest, const char *data,
asmlinkage void sha1_transform_avx(u32 *digest, const char *data,
unsigned int rounds);
#endif
+#ifdef CONFIG_AS_AVX2
+#define SHA1_AVX2_BLOCK_OPTSIZE 4 /* optimal 4*64 bytes of SHA1 blocks */
+
+asmlinkage void sha1_transform_avx2(u32 *digest, const char *data,
+ unsigned int rounds);
+#endif
static asmlinkage void (*sha1_transform_asm)(u32 *, const char *, unsigned int);
@@ -165,6 +172,18 @@ static int sha1_ssse3_import(struct shash_desc *desc, const void *in)
return 0;
}
+#ifdef CONFIG_AS_AVX2
+static void sha1_apply_transform_avx2(u32 *digest, const char *data,
+ unsigned int rounds)
+{
+ /* Select the optimal transform based on data block size */
+ if (rounds >= SHA1_AVX2_BLOCK_OPTSIZE)
+ sha1_transform_avx2(digest, data, rounds);
+ else
+ sha1_transform_avx(digest, data, rounds);
+}
+#endif
+
static struct shash_alg alg = {
.digestsize = SHA1_DIGEST_SIZE,
.init = sha1_ssse3_init,
@@ -201,27 +220,49 @@ static bool __init avx_usable(void)
return true;
}
+
+#ifdef CONFIG_AS_AVX2
+static bool __init avx2_usable(void)
+{
+ if (avx_usable() && cpu_has_avx2 && boot_cpu_has(X86_FEATURE_BMI1) &&
+ boot_cpu_has(X86_FEATURE_BMI2))
+ return true;
+
+ return false;
+}
+#endif
#endif
static int __init sha1_ssse3_mod_init(void)
{
+ char *algo_name;
+
/* test for SSSE3 first */
- if (cpu_has_ssse3)
+ if (cpu_has_ssse3) {
sha1_transform_asm = sha1_transform_ssse3;
+ algo_name = "SSSE3";
+ }
#ifdef CONFIG_AS_AVX
/* allow AVX to override SSSE3, it's a little faster */
- if (avx_usable())
+ if (avx_usable()) {
sha1_transform_asm = sha1_transform_avx;
+ algo_name = "AVX";
+#ifdef CONFIG_AS_AVX2
+ /* allow AVX2 to override AVX, it's a little faster */
+ if (avx2_usable()) {
+ sha1_transform_asm = sha1_apply_transform_avx2;
+ algo_name = "AVX2";
+ }
+#endif
+ }
#endif
if (sha1_transform_asm) {
- pr_info("Using %s optimized SHA-1 implementation\n",
- sha1_transform_asm == sha1_transform_ssse3 ? "SSSE3"
- : "AVX");
+ pr_info("Using %s optimized SHA-1 implementation\n", algo_name);
return crypto_register_shash(&alg);
}
- pr_info("Neither AVX nor SSSE3 is available/usable.\n");
+ pr_info("Neither AVX nor AVX2 nor SSSE3 is available/usable.\n");
return -ENODEV;
}
diff --git a/arch/x86/include/asm/Kbuild b/arch/x86/include/asm/Kbuild
index 7f669853317a..4acddc43ee0c 100644
--- a/arch/x86/include/asm/Kbuild
+++ b/arch/x86/include/asm/Kbuild
@@ -5,3 +5,5 @@ genhdr-y += unistd_64.h
genhdr-y += unistd_x32.h
generic-y += clkdev.h
+generic-y += cputime.h
+generic-y += mcs_spinlock.h
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 1d2091a226bc..19b0ebafcd3e 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -93,9 +93,6 @@ static inline int is_vsmp_box(void)
return 0;
}
#endif
-extern void xapic_wait_icr_idle(void);
-extern u32 safe_xapic_wait_icr_idle(void);
-extern void xapic_icr_write(u32, u32);
extern int setup_profiling_timer(unsigned int);
static inline void native_apic_mem_write(u32 reg, u32 v)
@@ -184,7 +181,6 @@ extern int x2apic_phys;
extern int x2apic_preenabled;
extern void check_x2apic(void);
extern void enable_x2apic(void);
-extern void x2apic_icr_write(u32 low, u32 id);
static inline int x2apic_enabled(void)
{
u64 msr;
@@ -221,7 +217,6 @@ static inline void x2apic_force_phys(void)
{
}
-#define nox2apic 0
#define x2apic_preenabled 0
#define x2apic_supported() 0
#endif
@@ -351,7 +346,7 @@ struct apic {
int trampoline_phys_low;
int trampoline_phys_high;
- void (*wait_for_init_deassert)(atomic_t *deassert);
+ bool wait_for_init_deassert;
void (*smp_callin_clear_local_apic)(void);
void (*inquire_remote_apic)(int apicid);
@@ -517,13 +512,6 @@ extern int default_cpu_present_to_apicid(int mps_cpu);
extern int default_check_phys_apicid_present(int phys_apicid);
#endif
-static inline void default_wait_for_init_deassert(atomic_t *deassert)
-{
- while (!atomic_read(deassert))
- cpu_relax();
- return;
-}
-
extern void generic_bigsmp_probe(void);
diff --git a/arch/x86/include/asm/barrier.h b/arch/x86/include/asm/barrier.h
index 04a48903b2eb..69bbb4845020 100644
--- a/arch/x86/include/asm/barrier.h
+++ b/arch/x86/include/asm/barrier.h
@@ -85,11 +85,7 @@
#else
# define smp_rmb() barrier()
#endif
-#ifdef CONFIG_X86_OOSTORE
-# define smp_wmb() wmb()
-#else
-# define smp_wmb() barrier()
-#endif
+#define smp_wmb() barrier()
#define smp_read_barrier_depends() read_barrier_depends()
#define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
#else /* !SMP */
@@ -100,7 +96,7 @@
#define set_mb(var, value) do { var = value; barrier(); } while (0)
#endif /* SMP */
-#if defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE)
+#if defined(CONFIG_X86_PPRO_FENCE)
/*
* For either of these options x86 doesn't have a strong TSO memory
diff --git a/arch/x86/include/asm/clocksource.h b/arch/x86/include/asm/clocksource.h
index 16a57f4ed64d..eda81dc0f4ae 100644
--- a/arch/x86/include/asm/clocksource.h
+++ b/arch/x86/include/asm/clocksource.h
@@ -3,8 +3,6 @@
#ifndef _ASM_X86_CLOCKSOURCE_H
#define _ASM_X86_CLOCKSOURCE_H
-#ifdef CONFIG_X86_64
-
#define VCLOCK_NONE 0 /* No vDSO clock available. */
#define VCLOCK_TSC 1 /* vDSO should use vread_tsc. */
#define VCLOCK_HPET 2 /* vDSO should use vread_hpet. */
@@ -14,6 +12,4 @@ struct arch_clocksource_data {
int vclock_mode;
};
-#endif /* CONFIG_X86_64 */
-
#endif /* _ASM_X86_CLOCKSOURCE_H */
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index e099f9502ace..e265ff95d16d 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -37,7 +37,7 @@
#define X86_FEATURE_PAT (0*32+16) /* Page Attribute Table */
#define X86_FEATURE_PSE36 (0*32+17) /* 36-bit PSEs */
#define X86_FEATURE_PN (0*32+18) /* Processor serial number */
-#define X86_FEATURE_CLFLSH (0*32+19) /* "clflush" CLFLUSH instruction */
+#define X86_FEATURE_CLFLUSH (0*32+19) /* CLFLUSH instruction */
#define X86_FEATURE_DS (0*32+21) /* "dts" Debug Store */
#define X86_FEATURE_ACPI (0*32+22) /* ACPI via MSR */
#define X86_FEATURE_MMX (0*32+23) /* Multimedia Extensions */
@@ -217,9 +217,14 @@
#define X86_FEATURE_INVPCID (9*32+10) /* Invalidate Processor Context ID */
#define X86_FEATURE_RTM (9*32+11) /* Restricted Transactional Memory */
#define X86_FEATURE_MPX (9*32+14) /* Memory Protection Extension */
+#define X86_FEATURE_AVX512F (9*32+16) /* AVX-512 Foundation */
#define X86_FEATURE_RDSEED (9*32+18) /* The RDSEED instruction */
#define X86_FEATURE_ADX (9*32+19) /* The ADCX and ADOX instructions */
#define X86_FEATURE_SMAP (9*32+20) /* Supervisor Mode Access Prevention */
+#define X86_FEATURE_CLFLUSHOPT (9*32+23) /* CLFLUSHOPT instruction */
+#define X86_FEATURE_AVX512PF (9*32+26) /* AVX-512 Prefetch */
+#define X86_FEATURE_AVX512ER (9*32+27) /* AVX-512 Exponential and Reciprocal */
+#define X86_FEATURE_AVX512CD (9*32+28) /* AVX-512 Conflict Detection */
/*
* BUG word(s)
@@ -313,7 +318,7 @@ extern const char * const x86_power_flags[32];
#define cpu_has_pmm_enabled boot_cpu_has(X86_FEATURE_PMM_EN)
#define cpu_has_ds boot_cpu_has(X86_FEATURE_DS)
#define cpu_has_pebs boot_cpu_has(X86_FEATURE_PEBS)
-#define cpu_has_clflush boot_cpu_has(X86_FEATURE_CLFLSH)
+#define cpu_has_clflush boot_cpu_has(X86_FEATURE_CLFLUSH)
#define cpu_has_bts boot_cpu_has(X86_FEATURE_BTS)
#define cpu_has_gbpages boot_cpu_has(X86_FEATURE_GBPAGES)
#define cpu_has_arch_perfmon boot_cpu_has(X86_FEATURE_ARCH_PERFMON)
@@ -541,6 +546,13 @@ static __always_inline __pure bool _static_cpu_has_safe(u16 bit)
#define static_cpu_has_bug(bit) static_cpu_has((bit))
#define boot_cpu_has_bug(bit) cpu_has_bug(&boot_cpu_data, (bit))
+#define MAX_CPU_FEATURES (NCAPINTS * 32)
+#define cpu_have_feature boot_cpu_has
+
+#define CPU_FEATURE_TYPEFMT "x86,ven%04Xfam%04Xmod%04X"
+#define CPU_FEATURE_TYPEVAL boot_cpu_data.x86_vendor, boot_cpu_data.x86, \
+ boot_cpu_data.x86_model
+
#endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */
#endif /* _ASM_X86_CPUFEATURE_H */
diff --git a/arch/x86/include/asm/cputime.h b/arch/x86/include/asm/cputime.h
deleted file mode 100644
index 6d68ad7e0ea3..000000000000
--- a/arch/x86/include/asm/cputime.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/cputime.h>
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 3b978c472d08..0869434eaf72 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -19,9 +19,11 @@
*/
#define EFI_OLD_MEMMAP EFI_ARCH_1
+#define EFI32_LOADER_SIGNATURE "EL32"
+#define EFI64_LOADER_SIGNATURE "EL64"
+
#ifdef CONFIG_X86_32
-#define EFI_LOADER_SIGNATURE "EL32"
extern unsigned long asmlinkage efi_call_phys(void *, ...);
@@ -57,8 +59,6 @@ extern unsigned long asmlinkage efi_call_phys(void *, ...);
#else /* !CONFIG_X86_32 */
-#define EFI_LOADER_SIGNATURE "EL64"
-
extern u64 efi_call0(void *fp);
extern u64 efi_call1(void *fp, u64 arg1);
extern u64 efi_call2(void *fp, u64 arg1, u64 arg2);
@@ -119,7 +119,6 @@ extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size,
#endif /* CONFIG_X86_32 */
extern int add_efi_memmap;
-extern unsigned long x86_efi_facility;
extern struct efi_scratch efi_scratch;
extern void efi_set_executable(efi_memory_desc_t *md, bool executable);
extern int efi_memblock_x86_reserve_range(void);
@@ -130,8 +129,13 @@ extern void efi_memory_uc(u64 addr, unsigned long size);
extern void __init efi_map_region(efi_memory_desc_t *md);
extern void __init efi_map_region_fixed(efi_memory_desc_t *md);
extern void efi_sync_low_kernel_mappings(void);
-extern void efi_setup_page_tables(void);
+extern int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages);
+extern void efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages);
extern void __init old_map_region(efi_memory_desc_t *md);
+extern void __init runtime_code_page_mkexec(void);
+extern void __init efi_runtime_mkexec(void);
+extern void __init efi_dump_pagetable(void);
+extern void __init efi_apply_memmap_quirks(void);
struct efi_setup_data {
u64 fw_vendor;
@@ -150,8 +154,40 @@ static inline bool efi_is_native(void)
return IS_ENABLED(CONFIG_X86_64) == efi_enabled(EFI_64BIT);
}
+static inline bool efi_runtime_supported(void)
+{
+ if (efi_is_native())
+ return true;
+
+ if (IS_ENABLED(CONFIG_EFI_MIXED) && !efi_enabled(EFI_OLD_MEMMAP))
+ return true;
+
+ return false;
+}
+
extern struct console early_efi_console;
extern void parse_efi_setup(u64 phys_addr, u32 data_len);
+
+#ifdef CONFIG_EFI_MIXED
+extern void efi_thunk_runtime_setup(void);
+extern efi_status_t efi_thunk_set_virtual_address_map(
+ void *phys_set_virtual_address_map,
+ unsigned long memory_map_size,
+ unsigned long descriptor_size,
+ u32 descriptor_version,
+ efi_memory_desc_t *virtual_map);
+#else
+static inline void efi_thunk_runtime_setup(void) {}
+static inline efi_status_t efi_thunk_set_virtual_address_map(
+ void *phys_set_virtual_address_map,
+ unsigned long memory_map_size,
+ unsigned long descriptor_size,
+ u32 descriptor_version,
+ efi_memory_desc_t *virtual_map)
+{
+ return EFI_SUCCESS;
+}
+#endif /* CONFIG_EFI_MIXED */
#else
/*
* IF EFI is not configured, have the EFI calls return -ENOSYS.
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index 9c999c1674fa..2c71182d30ef 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -281,16 +281,12 @@ do { \
#define STACK_RND_MASK (0x7ff)
-#define VDSO_HIGH_BASE (__fix_to_virt(FIX_VDSO))
-
#define ARCH_DLINFO ARCH_DLINFO_IA32(vdso_enabled)
/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
#else /* CONFIG_X86_32 */
-#define VDSO_HIGH_BASE 0xffffe000U /* CONFIG_COMPAT_VDSO address */
-
/* 1GB for 64bit, 8MB for 32bit */
#define STACK_RND_MASK (test_thread_flag(TIF_ADDR32) ? 0x7ff : 0x3fffff)
diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h
index 7252cd339175..8dcd35c4c787 100644
--- a/arch/x86/include/asm/fixmap.h
+++ b/arch/x86/include/asm/fixmap.h
@@ -40,15 +40,8 @@
*/
extern unsigned long __FIXADDR_TOP;
#define FIXADDR_TOP ((unsigned long)__FIXADDR_TOP)
-
-#define FIXADDR_USER_START __fix_to_virt(FIX_VDSO)
-#define FIXADDR_USER_END __fix_to_virt(FIX_VDSO - 1)
#else
#define FIXADDR_TOP (VSYSCALL_END-PAGE_SIZE)
-
-/* Only covers 32bit vsyscalls currently. Need another set for 64bit. */
-#define FIXADDR_USER_START ((unsigned long)VSYSCALL32_VSYSCALL)
-#define FIXADDR_USER_END (FIXADDR_USER_START + PAGE_SIZE)
#endif
@@ -74,7 +67,6 @@ extern unsigned long __FIXADDR_TOP;
enum fixed_addresses {
#ifdef CONFIG_X86_32
FIX_HOLE,
- FIX_VDSO,
#else
VSYSCALL_LAST_PAGE,
VSYSCALL_FIRST_PAGE = VSYSCALL_LAST_PAGE
@@ -98,12 +90,6 @@ enum fixed_addresses {
FIX_IO_APIC_BASE_0,
FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS - 1,
#endif
-#ifdef CONFIG_X86_VISWS_APIC
- FIX_CO_CPU, /* Cobalt timer */
- FIX_CO_APIC, /* Cobalt APIC Redirection Table */
- FIX_LI_PCIA, /* Lithium PCI Bridge A */
- FIX_LI_PCIB, /* Lithium PCI Bridge B */
-#endif
FIX_RO_IDT, /* Virtual mapping for read-only IDT */
#ifdef CONFIG_X86_32
FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
diff --git a/arch/x86/include/asm/floppy.h b/arch/x86/include/asm/floppy.h
index d3d74698dce9..1c7eefe32502 100644
--- a/arch/x86/include/asm/floppy.h
+++ b/arch/x86/include/asm/floppy.h
@@ -145,10 +145,10 @@ static int fd_request_irq(void)
{
if (can_use_virtual_dma)
return request_irq(FLOPPY_IRQ, floppy_hardint,
- IRQF_DISABLED, "floppy", NULL);
+ 0, "floppy", NULL);
else
return request_irq(FLOPPY_IRQ, floppy_interrupt,
- IRQF_DISABLED, "floppy", NULL);
+ 0, "floppy", NULL);
}
static unsigned long dma_mem_alloc(unsigned long size)
diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h
index ab0ae1aa6d0a..230853da4ec0 100644
--- a/arch/x86/include/asm/hardirq.h
+++ b/arch/x86/include/asm/hardirq.h
@@ -33,6 +33,9 @@ typedef struct {
#ifdef CONFIG_X86_MCE_THRESHOLD
unsigned int irq_threshold_count;
#endif
+#if IS_ENABLED(CONFIG_HYPERV) || defined(CONFIG_XEN)
+ unsigned int irq_hv_callback_count;
+#endif
} ____cacheline_aligned irq_cpustat_t;
DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
index 67d69b8e2d20..a307b7530e54 100644
--- a/arch/x86/include/asm/hw_irq.h
+++ b/arch/x86/include/asm/hw_irq.h
@@ -98,7 +98,6 @@ extern void trace_call_function_single_interrupt(void);
#define IO_APIC_IRQ(x) (((x) >= NR_IRQS_LEGACY) || ((1<<(x)) & io_apic_irqs))
extern unsigned long io_apic_irqs;
-extern void init_VISWS_APIC_irqs(void);
extern void setup_IO_APIC(void);
extern void disable_IO_APIC(void);
diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h
index 34f69cb9350a..91d9c69a629e 100644
--- a/arch/x86/include/asm/io.h
+++ b/arch/x86/include/asm/io.h
@@ -237,7 +237,7 @@ memcpy_toio(volatile void __iomem *dst, const void *src, size_t count)
static inline void flush_write_buffers(void)
{
-#if defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE)
+#if defined(CONFIG_X86_PPRO_FENCE)
asm volatile("lock; addl $0,0(%%esp)": : :"memory");
#endif
}
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index fdf83afbb7d9..fcaf9c961265 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -337,6 +337,11 @@ struct kvm_pmu {
u64 reprogram_pmi;
};
+enum {
+ KVM_DEBUGREG_BP_ENABLED = 1,
+ KVM_DEBUGREG_WONT_EXIT = 2,
+};
+
struct kvm_vcpu_arch {
/*
* rip and regs accesses must go through
@@ -444,7 +449,6 @@ struct kvm_vcpu_arch {
} st;
u64 last_guest_tsc;
- u64 last_kernel_ns;
u64 last_host_tsc;
u64 tsc_offset_adjustment;
u64 this_tsc_nsec;
@@ -464,7 +468,7 @@ struct kvm_vcpu_arch {
struct mtrr_state_type mtrr_state;
u32 pat;
- int switch_db_regs;
+ unsigned switch_db_regs;
unsigned long db[KVM_NR_DB_REGS];
unsigned long dr6;
unsigned long dr7;
@@ -599,6 +603,8 @@ struct kvm_arch {
bool use_master_clock;
u64 master_kernel_ns;
cycle_t master_cycle_now;
+ struct delayed_work kvmclock_update_work;
+ struct delayed_work kvmclock_sync_work;
struct kvm_xen_hvm_config xen_hvm_config;
@@ -702,6 +708,7 @@ struct kvm_x86_ops {
void (*set_gdt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt);
u64 (*get_dr6)(struct kvm_vcpu *vcpu);
void (*set_dr6)(struct kvm_vcpu *vcpu, unsigned long value);
+ void (*sync_dirty_debug_regs)(struct kvm_vcpu *vcpu);
void (*set_dr7)(struct kvm_vcpu *vcpu, unsigned long value);
void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg);
unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);
@@ -728,8 +735,8 @@ struct kvm_x86_ops {
int (*nmi_allowed)(struct kvm_vcpu *vcpu);
bool (*get_nmi_mask)(struct kvm_vcpu *vcpu);
void (*set_nmi_mask)(struct kvm_vcpu *vcpu, bool masked);
- int (*enable_nmi_window)(struct kvm_vcpu *vcpu);
- int (*enable_irq_window)(struct kvm_vcpu *vcpu);
+ void (*enable_nmi_window)(struct kvm_vcpu *vcpu);
+ void (*enable_irq_window)(struct kvm_vcpu *vcpu);
void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr);
int (*vm_has_apicv)(struct kvm *kvm);
void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr);
@@ -765,6 +772,9 @@ struct kvm_x86_ops {
struct x86_instruction_info *info,
enum x86_intercept_stage stage);
void (*handle_external_intr)(struct kvm_vcpu *vcpu);
+ bool (*mpx_supported)(void);
+
+ int (*check_nested_events)(struct kvm_vcpu *vcpu, bool external_intr);
};
struct kvm_arch_async_pf {
diff --git a/arch/x86/include/asm/mmzone_32.h b/arch/x86/include/asm/mmzone_32.h
index 8a9b3e288cb4..1ec990bd7dc0 100644
--- a/arch/x86/include/asm/mmzone_32.h
+++ b/arch/x86/include/asm/mmzone_32.h
@@ -11,9 +11,6 @@
#ifdef CONFIG_NUMA
extern struct pglist_data *node_data[];
#define NODE_DATA(nid) (node_data[nid])
-
-#include <asm/numaq.h>
-
#endif /* CONFIG_NUMA */
#ifdef CONFIG_DISCONTIGMEM
diff --git a/arch/x86/include/asm/mpspec.h b/arch/x86/include/asm/mpspec.h
index 3e6b4920ef5d..f5a617956735 100644
--- a/arch/x86/include/asm/mpspec.h
+++ b/arch/x86/include/asm/mpspec.h
@@ -25,12 +25,6 @@ extern int pic_mode;
extern unsigned int def_to_bigsmp;
-#ifdef CONFIG_X86_NUMAQ
-extern int mp_bus_id_to_node[MAX_MP_BUSSES];
-extern int mp_bus_id_to_local[MAX_MP_BUSSES];
-extern int quad_local_to_mp_bus_id [NR_CPUS/4][4];
-#endif
-
#else /* CONFIG_X86_64: */
#define MAX_MP_BUSSES 256
diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h
index cd9c41938b8a..c163215abb9a 100644
--- a/arch/x86/include/asm/mshyperv.h
+++ b/arch/x86/include/asm/mshyperv.h
@@ -2,6 +2,7 @@
#define _ASM_X86_MSHYPER_H
#include <linux/types.h>
+#include <linux/interrupt.h>
#include <asm/hyperv.h>
struct ms_hyperv_info {
@@ -16,6 +17,7 @@ void hyperv_callback_vector(void);
#define trace_hyperv_callback_vector hyperv_callback_vector
#endif
void hyperv_vector_handler(struct pt_regs *regs);
-void hv_register_vmbus_handler(int irq, irq_handler_t handler);
+void hv_setup_vmbus_irq(void (*handler)(void));
+void hv_remove_vmbus_irq(void);
#endif
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index e139b13f2a33..de36f22eb0b9 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -214,6 +214,8 @@ do { \
struct msr *msrs_alloc(void);
void msrs_free(struct msr *msrs);
+int msr_set_bit(u32 msr, u8 bit);
+int msr_clear_bit(u32 msr, u8 bit);
#ifdef CONFIG_SMP
int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
diff --git a/arch/x86/include/asm/nmi.h b/arch/x86/include/asm/nmi.h
index 86f9301903c8..5f2fc4441b11 100644
--- a/arch/x86/include/asm/nmi.h
+++ b/arch/x86/include/asm/nmi.h
@@ -1,6 +1,7 @@
#ifndef _ASM_X86_NMI_H
#define _ASM_X86_NMI_H
+#include <linux/irq_work.h>
#include <linux/pm.h>
#include <asm/irq.h>
#include <asm/io.h>
@@ -38,6 +39,8 @@ typedef int (*nmi_handler_t)(unsigned int, struct pt_regs *);
struct nmiaction {
struct list_head list;
nmi_handler_t handler;
+ u64 max_duration;
+ struct irq_work irq_work;
unsigned long flags;
const char *name;
};
diff --git a/arch/x86/include/asm/numaq.h b/arch/x86/include/asm/numaq.h
deleted file mode 100644
index c3b3c322fd87..000000000000
--- a/arch/x86/include/asm/numaq.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Written by: Patricia Gaughen, IBM Corporation
- *
- * Copyright (C) 2002, IBM Corp.
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT. 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.
- *
- * Send feedback to <gone@us.ibm.com>
- */
-
-#ifndef _ASM_X86_NUMAQ_H
-#define _ASM_X86_NUMAQ_H
-
-#ifdef CONFIG_X86_NUMAQ
-
-extern int found_numaq;
-extern int numaq_numa_init(void);
-extern int pci_numaq_init(void);
-
-extern void *xquad_portio;
-
-#define XQUAD_PORTIO_BASE 0xfe400000
-#define XQUAD_PORTIO_QUAD 0x40000 /* 256k per quad. */
-#define XQUAD_PORT_ADDR(port, quad) (xquad_portio + (XQUAD_PORTIO_QUAD*quad) + port)
-
-/*
- * SYS_CFG_DATA_PRIV_ADDR, struct eachquadmem, and struct sys_cfg_data are the
- */
-#define SYS_CFG_DATA_PRIV_ADDR 0x0009d000 /* place for scd in private
- quad space */
-
-/*
- * Communication area for each processor on lynxer-processor tests.
- *
- * NOTE: If you change the size of this eachproc structure you need
- * to change the definition for EACH_QUAD_SIZE.
- */
-struct eachquadmem {
- unsigned int priv_mem_start; /* Starting address of this */
- /* quad's private memory. */
- /* This is always 0. */
- /* In MB. */
- unsigned int priv_mem_size; /* Size of this quad's */
- /* private memory. */
- /* In MB. */
- unsigned int low_shrd_mem_strp_start;/* Starting address of this */
- /* quad's low shared block */
- /* (untranslated). */
- /* In MB. */
- unsigned int low_shrd_mem_start; /* Starting address of this */
- /* quad's low shared memory */
- /* (untranslated). */
- /* In MB. */
- unsigned int low_shrd_mem_size; /* Size of this quad's low */
- /* shared memory. */
- /* In MB. */
- unsigned int lmmio_copb_start; /* Starting address of this */
- /* quad's local memory */
- /* mapped I/O in the */
- /* compatibility OPB. */
- /* In MB. */
- unsigned int lmmio_copb_size; /* Size of this quad's local */
- /* memory mapped I/O in the */
- /* compatibility OPB. */
- /* In MB. */
- unsigned int lmmio_nopb_start; /* Starting address of this */
- /* quad's local memory */
- /* mapped I/O in the */
- /* non-compatibility OPB. */
- /* In MB. */
- unsigned int lmmio_nopb_size; /* Size of this quad's local */
- /* memory mapped I/O in the */
- /* non-compatibility OPB. */
- /* In MB. */
- unsigned int io_apic_0_start; /* Starting address of I/O */
- /* APIC 0. */
- unsigned int io_apic_0_sz; /* Size I/O APIC 0. */
- unsigned int io_apic_1_start; /* Starting address of I/O */
- /* APIC 1. */
- unsigned int io_apic_1_sz; /* Size I/O APIC 1. */
- unsigned int hi_shrd_mem_start; /* Starting address of this */
- /* quad's high shared memory.*/
- /* In MB. */
- unsigned int hi_shrd_mem_size; /* Size of this quad's high */
- /* shared memory. */
- /* In MB. */
- unsigned int mps_table_addr; /* Address of this quad's */
- /* MPS tables from BIOS, */
- /* in system space.*/
- unsigned int lcl_MDC_pio_addr; /* Port-I/O address for */
- /* local access of MDC. */
- unsigned int rmt_MDC_mmpio_addr; /* MM-Port-I/O address for */
- /* remote access of MDC. */
- unsigned int mm_port_io_start; /* Starting address of this */
- /* quad's memory mapped Port */
- /* I/O space. */
- unsigned int mm_port_io_size; /* Size of this quad's memory*/
- /* mapped Port I/O space. */
- unsigned int mm_rmt_io_apic_start; /* Starting address of this */
- /* quad's memory mapped */
- /* remote I/O APIC space. */
- unsigned int mm_rmt_io_apic_size; /* Size of this quad's memory*/
- /* mapped remote I/O APIC */
- /* space. */
- unsigned int mm_isa_start; /* Starting address of this */
- /* quad's memory mapped ISA */
- /* space (contains MDC */
- /* memory space). */
- unsigned int mm_isa_size; /* Size of this quad's memory*/
- /* mapped ISA space (contains*/
- /* MDC memory space). */
- unsigned int rmt_qmi_addr; /* Remote addr to access QMI.*/
- unsigned int lcl_qmi_addr; /* Local addr to access QMI. */
-};
-
-/*
- * Note: This structure must be NOT be changed unless the multiproc and
- * OS are changed to reflect the new structure.
- */
-struct sys_cfg_data {
- unsigned int quad_id;
- unsigned int bsp_proc_id; /* Boot Strap Processor in this quad. */
- unsigned int scd_version; /* Version number of this table. */
- unsigned int first_quad_id;
- unsigned int quads_present31_0; /* 1 bit for each quad */
- unsigned int quads_present63_32; /* 1 bit for each quad */
- unsigned int config_flags;
- unsigned int boot_flags;
- unsigned int csr_start_addr; /* Absolute value (not in MB) */
- unsigned int csr_size; /* Absolute value (not in MB) */
- unsigned int lcl_apic_start_addr; /* Absolute value (not in MB) */
- unsigned int lcl_apic_size; /* Absolute value (not in MB) */
- unsigned int low_shrd_mem_base; /* 0 or 512MB or 1GB */
- unsigned int low_shrd_mem_quad_offset; /* 0,128M,256M,512M,1G */
- /* may not be totally populated */
- unsigned int split_mem_enbl; /* 0 for no low shared memory */
- unsigned int mmio_sz; /* Size of total system memory mapped I/O */
- /* (in MB). */
- unsigned int quad_spin_lock; /* Spare location used for quad */
- /* bringup. */
- unsigned int nonzero55; /* For checksumming. */
- unsigned int nonzeroaa; /* For checksumming. */
- unsigned int scd_magic_number;
- unsigned int system_type;
- unsigned int checksum;
- /*
- * memory configuration area for each quad
- */
- struct eachquadmem eq[MAX_NUMNODES]; /* indexed by quad id */
-};
-
-void numaq_tsc_disable(void);
-
-#endif /* CONFIG_X86_NUMAQ */
-#endif /* _ASM_X86_NUMAQ_H */
-
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index 1ac6114c9ea5..96ae4f4040bb 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -26,11 +26,6 @@ extern int pci_routeirq;
extern int noioapicquirk;
extern int noioapicreroute;
-/* scan a bus after allocating a pci_sysdata for it */
-extern struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops,
- int node);
-extern struct pci_bus *pci_scan_bus_with_sysdata(int busno);
-
#ifdef CONFIG_PCI
#ifdef CONFIG_PCI_DOMAINS
@@ -70,7 +65,7 @@ extern unsigned long pci_mem_start;
extern int pcibios_enabled;
void pcibios_config_init(void);
-struct pci_bus *pcibios_scan_root(int bus);
+void pcibios_scan_root(int bus);
void pcibios_set_master(struct pci_dev *dev);
void pcibios_penalize_isa_irq(int irq, int active);
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index bbc8b12fa443..b459ddf27d64 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -15,9 +15,10 @@
: (prot))
#ifndef __ASSEMBLY__
-
#include <asm/x86_init.h>
+void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd);
+
/*
* ZERO_PAGE is a global shared page that is always zero: used
* for zero-mapped memory areas etc..
diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h
index 1aa9ccd43223..eb3d44945133 100644
--- a/arch/x86/include/asm/pgtable_types.h
+++ b/arch/x86/include/asm/pgtable_types.h
@@ -214,13 +214,8 @@
#ifdef CONFIG_X86_64
#define __PAGE_KERNEL_IDENT_LARGE_EXEC __PAGE_KERNEL_LARGE_EXEC
#else
-/*
- * For PDE_IDENT_ATTR include USER bit. As the PDE and PTE protection
- * bits are combined, this will alow user to access the high address mapped
- * VDSO in the presence of CONFIG_COMPAT_VDSO
- */
#define PTE_IDENT_ATTR 0x003 /* PRESENT+RW */
-#define PDE_IDENT_ATTR 0x067 /* PRESENT+RW+USER+DIRTY+ACCESSED */
+#define PDE_IDENT_ATTR 0x063 /* PRESENT+RW+DIRTY+ACCESSED */
#define PGD_IDENT_ATTR 0x001 /* PRESENT (no other attributes) */
#endif
@@ -382,9 +377,13 @@ static inline void update_page_count(int level, unsigned long pages) { }
* as a pte too.
*/
extern pte_t *lookup_address(unsigned long address, unsigned int *level);
+extern pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
+ unsigned int *level);
extern phys_addr_t slow_virt_to_phys(void *__address);
extern int kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address,
unsigned numpages, unsigned long page_flags);
+void kernel_unmap_pages_in_pgd(pgd_t *root, unsigned long address,
+ unsigned numpages);
#endif /* !__ASSEMBLY__ */
#endif /* _ASM_X86_PGTABLE_DEFS_H */
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index fdedd38fd0fc..a4ea02351f4d 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -449,6 +449,15 @@ struct stack_canary {
};
DECLARE_PER_CPU_ALIGNED(struct stack_canary, stack_canary);
#endif
+/*
+ * per-CPU IRQ handling stacks
+ */
+struct irq_stack {
+ u32 stack[THREAD_SIZE/sizeof(u32)];
+} __aligned(THREAD_SIZE);
+
+DECLARE_PER_CPU(struct irq_stack *, hardirq_stack);
+DECLARE_PER_CPU(struct irq_stack *, softirq_stack);
#endif /* X86_64 */
extern unsigned int xstate_size;
diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h
index d62c9f809bc5..9264f04a4c55 100644
--- a/arch/x86/include/asm/setup.h
+++ b/arch/x86/include/asm/setup.h
@@ -39,12 +39,6 @@ static inline void vsmp_init(void) { }
void setup_bios_corruption_check(void);
-#ifdef CONFIG_X86_VISWS
-extern void visws_early_detect(void);
-#else
-static inline void visws_early_detect(void) { }
-#endif
-
extern unsigned long saved_video_mode;
extern void reserve_standard_io_resources(void);
diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h
index 645cad2c95ff..e820c080a4e9 100644
--- a/arch/x86/include/asm/special_insns.h
+++ b/arch/x86/include/asm/special_insns.h
@@ -191,6 +191,14 @@ static inline void clflush(volatile void *__p)
asm volatile("clflush %0" : "+m" (*(volatile char __force *)__p));
}
+static inline void clflushopt(volatile void *__p)
+{
+ alternative_io(".byte " __stringify(NOP_DS_PREFIX) "; clflush %P0",
+ ".byte 0x66; clflush %P0",
+ X86_FEATURE_CLFLUSHOPT,
+ "+m" (*(volatile char __force *)__p));
+}
+
#define nop() asm volatile ("nop")
diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h
index bf156ded74b5..0f62f5482d91 100644
--- a/arch/x86/include/asm/spinlock.h
+++ b/arch/x86/include/asm/spinlock.h
@@ -26,10 +26,9 @@
# define LOCK_PTR_REG "D"
#endif
-#if defined(CONFIG_X86_32) && \
- (defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE))
+#if defined(CONFIG_X86_32) && (defined(CONFIG_X86_PPRO_FENCE))
/*
- * On PPro SMP or if we are using OOSTORE, we use a locked operation to unlock
+ * On PPro SMP, we use a locked operation to unlock
* (PPro errata 66, 92)
*/
# define UNLOCK_LOCK_PREFIX LOCK_PREFIX
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index e1940c06ed02..47e5de25ba79 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -9,6 +9,7 @@
#include <linux/compiler.h>
#include <asm/page.h>
+#include <asm/percpu.h>
#include <asm/types.h>
/*
@@ -32,12 +33,6 @@ struct thread_info {
mm_segment_t addr_limit;
struct restart_block restart_block;
void __user *sysenter_return;
-#ifdef CONFIG_X86_32
- unsigned long previous_esp; /* ESP of the previous stack in
- case of nested (IRQ) stacks
- */
- __u8 supervisor_stack[0];
-#endif
unsigned int sig_on_uaccess_error:1;
unsigned int uaccess_err:1; /* uaccess failed */
};
@@ -153,9 +148,9 @@ struct thread_info {
#define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW|_TIF_USER_RETURN_NOTIFY)
#define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW)
-#ifdef CONFIG_X86_32
+#define STACK_WARN (THREAD_SIZE/8)
+#define KERNEL_STACK_OFFSET (5*(BITS_PER_LONG/8))
-#define STACK_WARN (THREAD_SIZE/8)
/*
* macros/functions for gaining access to the thread information structure
*
@@ -163,42 +158,6 @@ struct thread_info {
*/
#ifndef __ASSEMBLY__
-#define current_stack_pointer ({ \
- unsigned long sp; \
- asm("mov %%esp,%0" : "=g" (sp)); \
- sp; \
-})
-
-/* how to get the thread information struct from C */
-static inline struct thread_info *current_thread_info(void)
-{
- return (struct thread_info *)
- (current_stack_pointer & ~(THREAD_SIZE - 1));
-}
-
-#else /* !__ASSEMBLY__ */
-
-/* how to get the thread information struct from ASM */
-#define GET_THREAD_INFO(reg) \
- movl $-THREAD_SIZE, reg; \
- andl %esp, reg
-
-/* use this one if reg already contains %esp */
-#define GET_THREAD_INFO_WITH_ESP(reg) \
- andl $-THREAD_SIZE, reg
-
-#endif
-
-#else /* X86_32 */
-
-#include <asm/percpu.h>
-#define KERNEL_STACK_OFFSET (5*8)
-
-/*
- * macros/functions for gaining access to the thread information structure
- * preempt_count needs to be 1 initially, until the scheduler is functional.
- */
-#ifndef __ASSEMBLY__
DECLARE_PER_CPU(unsigned long, kernel_stack);
static inline struct thread_info *current_thread_info(void)
@@ -213,8 +172,8 @@ static inline struct thread_info *current_thread_info(void)
/* how to get the thread information struct from ASM */
#define GET_THREAD_INFO(reg) \
- movq PER_CPU_VAR(kernel_stack),reg ; \
- subq $(THREAD_SIZE-KERNEL_STACK_OFFSET),reg
+ _ASM_MOV PER_CPU_VAR(kernel_stack),reg ; \
+ _ASM_SUB $(THREAD_SIZE-KERNEL_STACK_OFFSET),reg ;
/*
* Same if PER_CPU_VAR(kernel_stack) is, perhaps with some offset, already in
@@ -224,8 +183,6 @@ static inline struct thread_info *current_thread_info(void)
#endif
-#endif /* !X86_32 */
-
/*
* Thread-synchronous status.
*
diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h
index d35f24e231cd..0e8f04f2c26f 100644
--- a/arch/x86/include/asm/topology.h
+++ b/arch/x86/include/asm/topology.h
@@ -119,9 +119,10 @@ static inline void setup_node_to_cpumask_map(void) { }
extern const struct cpumask *cpu_coregroup_mask(int cpu);
-#ifdef ENABLE_TOPO_DEFINES
#define topology_physical_package_id(cpu) (cpu_data(cpu).phys_proc_id)
#define topology_core_id(cpu) (cpu_data(cpu).cpu_core_id)
+
+#ifdef ENABLE_TOPO_DEFINES
#define topology_core_cpumask(cpu) (per_cpu(cpu_core_map, cpu))
#define topology_thread_cpumask(cpu) (per_cpu(cpu_sibling_map, cpu))
#endif
@@ -131,25 +132,7 @@ static inline void arch_fix_phys_package_id(int num, u32 slot)
}
struct pci_bus;
+int x86_pci_root_bus_node(int bus);
void x86_pci_root_bus_resources(int bus, struct list_head *resources);
-#ifdef CONFIG_SMP
-#define mc_capable() ((boot_cpu_data.x86_max_cores > 1) && \
- (cpumask_weight(cpu_core_mask(0)) != nr_cpu_ids))
-#define smt_capable() (smp_num_siblings > 1)
-#endif
-
-#ifdef CONFIG_NUMA
-extern int get_mp_bus_to_node(int busnum);
-extern void set_mp_bus_to_node(int busnum, int node);
-#else
-static inline int get_mp_bus_to_node(int busnum)
-{
- return 0;
-}
-static inline void set_mp_bus_to_node(int busnum, int node)
-{
-}
-#endif
-
#endif /* _ASM_X86_TOPOLOGY_H */
diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h
index 57ae63cd6ee2..94605c0e9cee 100644
--- a/arch/x86/include/asm/tsc.h
+++ b/arch/x86/include/asm/tsc.h
@@ -66,6 +66,6 @@ extern void tsc_save_sched_clock_state(void);
extern void tsc_restore_sched_clock_state(void);
/* MSR based TSC calibration for Intel Atom SoC platforms */
-int try_msr_calibrate_tsc(unsigned long *fast_calibrate);
+unsigned long try_msr_calibrate_tsc(void);
#endif /* _ASM_X86_TSC_H */
diff --git a/arch/x86/include/asm/unistd.h b/arch/x86/include/asm/unistd.h
index c2a48139c340..3f556c6a0157 100644
--- a/arch/x86/include/asm/unistd.h
+++ b/arch/x86/include/asm/unistd.h
@@ -23,6 +23,9 @@
# include <asm/unistd_64.h>
# include <asm/unistd_64_x32.h>
# define __ARCH_WANT_COMPAT_SYS_TIME
+# define __ARCH_WANT_COMPAT_SYS_GETDENTS64
+# define __ARCH_WANT_COMPAT_SYS_PREADV64
+# define __ARCH_WANT_COMPAT_SYS_PWRITEV64
# endif
diff --git a/arch/x86/include/asm/vdso.h b/arch/x86/include/asm/vdso.h
index fddb53d63915..d1dc55404ff1 100644
--- a/arch/x86/include/asm/vdso.h
+++ b/arch/x86/include/asm/vdso.h
@@ -1,8 +1,45 @@
#ifndef _ASM_X86_VDSO_H
#define _ASM_X86_VDSO_H
+#include <asm/page_types.h>
+#include <linux/linkage.h>
+
+#ifdef __ASSEMBLER__
+
+#define DEFINE_VDSO_IMAGE(symname, filename) \
+__PAGE_ALIGNED_DATA ; \
+ .globl symname##_start, symname##_end ; \
+ .align PAGE_SIZE ; \
+ symname##_start: ; \
+ .incbin filename ; \
+ symname##_end: ; \
+ .align PAGE_SIZE /* extra data here leaks to userspace. */ ; \
+ \
+.previous ; \
+ \
+ .globl symname##_pages ; \
+ .bss ; \
+ .align 8 ; \
+ .type symname##_pages, @object ; \
+ symname##_pages: ; \
+ .zero (symname##_end - symname##_start + PAGE_SIZE - 1) / PAGE_SIZE * (BITS_PER_LONG / 8) ; \
+ .size symname##_pages, .-symname##_pages
+
+#else
+
+#define DECLARE_VDSO_IMAGE(symname) \
+ extern char symname##_start[], symname##_end[]; \
+ extern struct page *symname##_pages[]
+
#if defined CONFIG_X86_32 || defined CONFIG_COMPAT
-extern const char VDSO32_PRELINK[];
+
+#include <asm/vdso32.h>
+
+DECLARE_VDSO_IMAGE(vdso32_int80);
+#ifdef CONFIG_COMPAT
+DECLARE_VDSO_IMAGE(vdso32_syscall);
+#endif
+DECLARE_VDSO_IMAGE(vdso32_sysenter);
/*
* Given a pointer to the vDSO image, find the pointer to VDSO32_name
@@ -11,8 +48,7 @@ extern const char VDSO32_PRELINK[];
#define VDSO32_SYMBOL(base, name) \
({ \
extern const char VDSO32_##name[]; \
- (void __user *)(VDSO32_##name - VDSO32_PRELINK + \
- (unsigned long)(base)); \
+ (void __user *)(VDSO32_##name + (unsigned long)(base)); \
})
#endif
@@ -23,12 +59,8 @@ extern const char VDSO32_PRELINK[];
extern void __user __kernel_sigreturn;
extern void __user __kernel_rt_sigreturn;
-/*
- * These symbols are defined by vdso32.S to mark the bounds
- * of the ELF DSO images included therein.
- */
-extern const char vdso32_int80_start, vdso32_int80_end;
-extern const char vdso32_syscall_start, vdso32_syscall_end;
-extern const char vdso32_sysenter_start, vdso32_sysenter_end;
+void __init patch_vdso32(void *vdso, size_t len);
+
+#endif /* __ASSEMBLER__ */
#endif /* _ASM_X86_VDSO_H */
diff --git a/arch/x86/include/asm/vdso32.h b/arch/x86/include/asm/vdso32.h
new file mode 100644
index 000000000000..7efb7018406e
--- /dev/null
+++ b/arch/x86/include/asm/vdso32.h
@@ -0,0 +1,11 @@
+#ifndef _ASM_X86_VDSO32_H
+#define _ASM_X86_VDSO32_H
+
+#define VDSO_BASE_PAGE 0
+#define VDSO_VVAR_PAGE 1
+#define VDSO_HPET_PAGE 2
+#define VDSO_PAGES 3
+#define VDSO_PREV_PAGES 2
+#define VDSO_OFFSET(x) ((x) * PAGE_SIZE)
+
+#endif
diff --git a/arch/x86/include/asm/vgtod.h b/arch/x86/include/asm/vgtod.h
index 46e24d36b7da..3c3366c2e37f 100644
--- a/arch/x86/include/asm/vgtod.h
+++ b/arch/x86/include/asm/vgtod.h
@@ -1,30 +1,73 @@
#ifndef _ASM_X86_VGTOD_H
#define _ASM_X86_VGTOD_H
-#include <asm/vsyscall.h>
+#include <linux/compiler.h>
#include <linux/clocksource.h>
+#ifdef BUILD_VDSO32_64
+typedef u64 gtod_long_t;
+#else
+typedef unsigned long gtod_long_t;
+#endif
+/*
+ * vsyscall_gtod_data will be accessed by 32 and 64 bit code at the same time
+ * so be carefull by modifying this structure.
+ */
struct vsyscall_gtod_data {
- seqcount_t seq;
+ unsigned seq;
- struct { /* extract of a clocksource struct */
- int vclock_mode;
- cycle_t cycle_last;
- cycle_t mask;
- u32 mult;
- u32 shift;
- } clock;
+ int vclock_mode;
+ cycle_t cycle_last;
+ cycle_t mask;
+ u32 mult;
+ u32 shift;
/* open coded 'struct timespec' */
- time_t wall_time_sec;
u64 wall_time_snsec;
+ gtod_long_t wall_time_sec;
+ gtod_long_t monotonic_time_sec;
u64 monotonic_time_snsec;
- time_t monotonic_time_sec;
+ gtod_long_t wall_time_coarse_sec;
+ gtod_long_t wall_time_coarse_nsec;
+ gtod_long_t monotonic_time_coarse_sec;
+ gtod_long_t monotonic_time_coarse_nsec;
- struct timezone sys_tz;
- struct timespec wall_time_coarse;
- struct timespec monotonic_time_coarse;
+ int tz_minuteswest;
+ int tz_dsttime;
};
extern struct vsyscall_gtod_data vsyscall_gtod_data;
+static inline unsigned gtod_read_begin(const struct vsyscall_gtod_data *s)
+{
+ unsigned ret;
+
+repeat:
+ ret = ACCESS_ONCE(s->seq);
+ if (unlikely(ret & 1)) {
+ cpu_relax();
+ goto repeat;
+ }
+ smp_rmb();
+ return ret;
+}
+
+static inline int gtod_read_retry(const struct vsyscall_gtod_data *s,
+ unsigned start)
+{
+ smp_rmb();
+ return unlikely(s->seq != start);
+}
+
+static inline void gtod_write_begin(struct vsyscall_gtod_data *s)
+{
+ ++s->seq;
+ smp_wmb();
+}
+
+static inline void gtod_write_end(struct vsyscall_gtod_data *s)
+{
+ smp_wmb();
+ ++s->seq;
+}
+
#endif /* _ASM_X86_VGTOD_H */
diff --git a/arch/x86/include/asm/visws/cobalt.h b/arch/x86/include/asm/visws/cobalt.h
deleted file mode 100644
index 2edb37637ead..000000000000
--- a/arch/x86/include/asm/visws/cobalt.h
+++ /dev/null
@@ -1,127 +0,0 @@
-#ifndef _ASM_X86_VISWS_COBALT_H
-#define _ASM_X86_VISWS_COBALT_H
-
-#include <asm/fixmap.h>
-
-/*
- * Cobalt SGI Visual Workstation system ASIC
- */
-
-#define CO_CPU_NUM_PHYS 0x1e00
-#define CO_CPU_TAB_PHYS (CO_CPU_NUM_PHYS + 2)
-
-#define CO_CPU_MAX 4
-
-#define CO_CPU_PHYS 0xc2000000
-#define CO_APIC_PHYS 0xc4000000
-
-/* see set_fixmap() and asm/fixmap.h */
-#define CO_CPU_VADDR (fix_to_virt(FIX_CO_CPU))
-#define CO_APIC_VADDR (fix_to_virt(FIX_CO_APIC))
-
-/* Cobalt CPU registers -- relative to CO_CPU_VADDR, use co_cpu_*() */
-#define CO_CPU_REV 0x08
-#define CO_CPU_CTRL 0x10
-#define CO_CPU_STAT 0x20
-#define CO_CPU_TIMEVAL 0x30
-
-/* CO_CPU_CTRL bits */
-#define CO_CTRL_TIMERUN 0x04 /* 0 == disabled */
-#define CO_CTRL_TIMEMASK 0x08 /* 0 == unmasked */
-
-/* CO_CPU_STATUS bits */
-#define CO_STAT_TIMEINTR 0x02 /* (r) 1 == int pend, (w) 0 == clear */
-
-/* CO_CPU_TIMEVAL value */
-#define CO_TIME_HZ 100000000 /* Cobalt core rate */
-
-/* Cobalt APIC registers -- relative to CO_APIC_VADDR, use co_apic_*() */
-#define CO_APIC_HI(n) (((n) * 0x10) + 4)
-#define CO_APIC_LO(n) ((n) * 0x10)
-#define CO_APIC_ID 0x0ffc
-
-/* CO_APIC_ID bits */
-#define CO_APIC_ENABLE 0x00000100
-
-/* CO_APIC_LO bits */
-#define CO_APIC_MASK 0x00010000 /* 0 = enabled */
-#define CO_APIC_LEVEL 0x00008000 /* 0 = edge */
-
-/*
- * Where things are physically wired to Cobalt
- * #defines with no board _<type>_<rev>_ are common to all (thus far)
- */
-#define CO_APIC_IDE0 4
-#define CO_APIC_IDE1 2 /* Only on 320 */
-
-#define CO_APIC_8259 12 /* serial, floppy, par-l-l */
-
-/* Lithium PCI Bridge A -- "the one with 82557 Ethernet" */
-#define CO_APIC_PCIA_BASE0 0 /* and 1 */ /* slot 0, line 0 */
-#define CO_APIC_PCIA_BASE123 5 /* and 6 */ /* slot 0, line 1 */
-
-#define CO_APIC_PIIX4_USB 7 /* this one is weird */
-
-/* Lithium PCI Bridge B -- "the one with PIIX4" */
-#define CO_APIC_PCIB_BASE0 8 /* and 9-12 *//* slot 0, line 0 */
-#define CO_APIC_PCIB_BASE123 13 /* 14.15 */ /* slot 0, line 1 */
-
-#define CO_APIC_VIDOUT0 16
-#define CO_APIC_VIDOUT1 17
-#define CO_APIC_VIDIN0 18
-#define CO_APIC_VIDIN1 19
-
-#define CO_APIC_LI_AUDIO 22
-
-#define CO_APIC_AS 24
-#define CO_APIC_RE 25
-
-#define CO_APIC_CPU 28 /* Timer and Cache interrupt */
-#define CO_APIC_NMI 29
-#define CO_APIC_LAST CO_APIC_NMI
-
-/*
- * This is how irqs are assigned on the Visual Workstation.
- * Legacy devices get irq's 1-15 (system clock is 0 and is CO_APIC_CPU).
- * All other devices (including PCI) go to Cobalt and are irq's 16 on up.
- */
-#define CO_IRQ_APIC0 16 /* irq of apic entry 0 */
-#define IS_CO_APIC(irq) ((irq) >= CO_IRQ_APIC0)
-#define CO_IRQ(apic) (CO_IRQ_APIC0 + (apic)) /* apic ent to irq */
-#define CO_APIC(irq) ((irq) - CO_IRQ_APIC0) /* irq to apic ent */
-#define CO_IRQ_IDE0 14 /* knowledge of... */
-#define CO_IRQ_IDE1 15 /* ... ide driver defaults! */
-#define CO_IRQ_8259 CO_IRQ(CO_APIC_8259)
-
-#ifdef CONFIG_X86_VISWS_APIC
-static inline void co_cpu_write(unsigned long reg, unsigned long v)
-{
- *((volatile unsigned long *)(CO_CPU_VADDR+reg))=v;
-}
-
-static inline unsigned long co_cpu_read(unsigned long reg)
-{
- return *((volatile unsigned long *)(CO_CPU_VADDR+reg));
-}
-
-static inline void co_apic_write(unsigned long reg, unsigned long v)
-{
- *((volatile unsigned long *)(CO_APIC_VADDR+reg))=v;
-}
-
-static inline unsigned long co_apic_read(unsigned long reg)
-{
- return *((volatile unsigned long *)(CO_APIC_VADDR+reg));
-}
-#endif
-
-extern char visws_board_type;
-
-#define VISWS_320 0
-#define VISWS_540 1
-
-extern char visws_board_rev;
-
-extern int pci_visws_init(void);
-
-#endif /* _ASM_X86_VISWS_COBALT_H */
diff --git a/arch/x86/include/asm/visws/lithium.h b/arch/x86/include/asm/visws/lithium.h
deleted file mode 100644
index a10d89bc1270..000000000000
--- a/arch/x86/include/asm/visws/lithium.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef _ASM_X86_VISWS_LITHIUM_H
-#define _ASM_X86_VISWS_LITHIUM_H
-
-#include <asm/fixmap.h>
-
-/*
- * Lithium is the SGI Visual Workstation I/O ASIC
- */
-
-#define LI_PCI_A_PHYS 0xfc000000 /* Enet is dev 3 */
-#define LI_PCI_B_PHYS 0xfd000000 /* PIIX4 is here */
-
-/* see set_fixmap() and asm/fixmap.h */
-#define LI_PCIA_VADDR (fix_to_virt(FIX_LI_PCIA))
-#define LI_PCIB_VADDR (fix_to_virt(FIX_LI_PCIB))
-
-/* Not a standard PCI? (not in linux/pci.h) */
-#define LI_PCI_BUSNUM 0x44 /* lo8: primary, hi8: sub */
-#define LI_PCI_INTEN 0x46
-
-/* LI_PCI_INTENT bits */
-#define LI_INTA_0 0x0001
-#define LI_INTA_1 0x0002
-#define LI_INTA_2 0x0004
-#define LI_INTA_3 0x0008
-#define LI_INTA_4 0x0010
-#define LI_INTB 0x0020
-#define LI_INTC 0x0040
-#define LI_INTD 0x0080
-
-/* More special purpose macros... */
-static inline void li_pcia_write16(unsigned long reg, unsigned short v)
-{
- *((volatile unsigned short *)(LI_PCIA_VADDR+reg))=v;
-}
-
-static inline unsigned short li_pcia_read16(unsigned long reg)
-{
- return *((volatile unsigned short *)(LI_PCIA_VADDR+reg));
-}
-
-static inline void li_pcib_write16(unsigned long reg, unsigned short v)
-{
- *((volatile unsigned short *)(LI_PCIB_VADDR+reg))=v;
-}
-
-static inline unsigned short li_pcib_read16(unsigned long reg)
-{
- return *((volatile unsigned short *)(LI_PCIB_VADDR+reg));
-}
-
-#endif /* _ASM_X86_VISWS_LITHIUM_H */
-
diff --git a/arch/x86/include/asm/visws/piix4.h b/arch/x86/include/asm/visws/piix4.h
deleted file mode 100644
index d0af4d338e7f..000000000000
--- a/arch/x86/include/asm/visws/piix4.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef _ASM_X86_VISWS_PIIX4_H
-#define _ASM_X86_VISWS_PIIX4_H
-
-/*
- * PIIX4 as used on SGI Visual Workstations
- */
-
-#define PIIX_PM_START 0x0F80
-
-#define SIO_GPIO_START 0x0FC0
-
-#define SIO_PM_START 0x0FC8
-
-#define PMBASE PIIX_PM_START
-#define GPIREG0 (PMBASE+0x30)
-#define GPIREG(x) (GPIREG0+((x)/8))
-#define GPIBIT(x) (1 << ((x)%8))
-
-#define PIIX_GPI_BD_ID1 18
-#define PIIX_GPI_BD_ID2 19
-#define PIIX_GPI_BD_ID3 20
-#define PIIX_GPI_BD_ID4 21
-#define PIIX_GPI_BD_REG GPIREG(PIIX_GPI_BD_ID1)
-#define PIIX_GPI_BD_MASK (GPIBIT(PIIX_GPI_BD_ID1) | \
- GPIBIT(PIIX_GPI_BD_ID2) | \
- GPIBIT(PIIX_GPI_BD_ID3) | \
- GPIBIT(PIIX_GPI_BD_ID4) )
-
-#define PIIX_GPI_BD_SHIFT (PIIX_GPI_BD_ID1 % 8)
-
-#define SIO_INDEX 0x2e
-#define SIO_DATA 0x2f
-
-#define SIO_DEV_SEL 0x7
-#define SIO_DEV_ENB 0x30
-#define SIO_DEV_MSB 0x60
-#define SIO_DEV_LSB 0x61
-
-#define SIO_GP_DEV 0x7
-
-#define SIO_GP_BASE SIO_GPIO_START
-#define SIO_GP_MSB (SIO_GP_BASE>>8)
-#define SIO_GP_LSB (SIO_GP_BASE&0xff)
-
-#define SIO_GP_DATA1 (SIO_GP_BASE+0)
-
-#define SIO_PM_DEV 0x8
-
-#define SIO_PM_BASE SIO_PM_START
-#define SIO_PM_MSB (SIO_PM_BASE>>8)
-#define SIO_PM_LSB (SIO_PM_BASE&0xff)
-#define SIO_PM_INDEX (SIO_PM_BASE+0)
-#define SIO_PM_DATA (SIO_PM_BASE+1)
-
-#define SIO_PM_FER2 0x1
-
-#define SIO_PM_GP_EN 0x80
-
-
-
-/*
- * This is the dev/reg where generating a config cycle will
- * result in a PCI special cycle.
- */
-#define SPECIAL_DEV 0xff
-#define SPECIAL_REG 0x00
-
-/*
- * PIIX4 needs to see a special cycle with the following data
- * to be convinced the processor has gone into the stop grant
- * state. PIIX4 insists on seeing this before it will power
- * down a system.
- */
-#define PIIX_SPECIAL_STOP 0x00120002
-
-#define PIIX4_RESET_PORT 0xcf9
-#define PIIX4_RESET_VAL 0x6
-
-#define PMSTS_PORT 0xf80 // 2 bytes PM Status
-#define PMEN_PORT 0xf82 // 2 bytes PM Enable
-#define PMCNTRL_PORT 0xf84 // 2 bytes PM Control
-
-#define PM_SUSPEND_ENABLE 0x2000 // start sequence to suspend state
-
-/*
- * PMSTS and PMEN I/O bit definitions.
- * (Bits are the same in both registers)
- */
-#define PM_STS_RSM (1<<15) // Resume Status
-#define PM_STS_PWRBTNOR (1<<11) // Power Button Override
-#define PM_STS_RTC (1<<10) // RTC status
-#define PM_STS_PWRBTN (1<<8) // Power Button Pressed?
-#define PM_STS_GBL (1<<5) // Global Status
-#define PM_STS_BM (1<<4) // Bus Master Status
-#define PM_STS_TMROF (1<<0) // Timer Overflow Status.
-
-/*
- * Stop clock GPI register
- */
-#define PIIX_GPIREG0 (0xf80 + 0x30)
-
-/*
- * Stop clock GPI bit in GPIREG0
- */
-#define PIIX_GPI_STPCLK 0x4 // STPCLK signal routed back in
-
-#endif /* _ASM_X86_VISWS_PIIX4_H */
diff --git a/arch/x86/include/asm/visws/sgivw.h b/arch/x86/include/asm/visws/sgivw.h
deleted file mode 100644
index 5fbf63e1003c..000000000000
--- a/arch/x86/include/asm/visws/sgivw.h
+++ /dev/null
@@ -1,5 +0,0 @@
-/*
- * Frame buffer position and size:
- */
-extern unsigned long sgivwfb_mem_phys;
-extern unsigned long sgivwfb_mem_size;
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index 2067264fb7f5..7004d21e6219 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -85,6 +85,7 @@
#define VM_EXIT_SAVE_IA32_EFER 0x00100000
#define VM_EXIT_LOAD_IA32_EFER 0x00200000
#define VM_EXIT_SAVE_VMX_PREEMPTION_TIMER 0x00400000
+#define VM_EXIT_CLEAR_BNDCFGS 0x00800000
#define VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR 0x00036dff
@@ -95,6 +96,7 @@
#define VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL 0x00002000
#define VM_ENTRY_LOAD_IA32_PAT 0x00004000
#define VM_ENTRY_LOAD_IA32_EFER 0x00008000
+#define VM_ENTRY_LOAD_BNDCFGS 0x00010000
#define VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR 0x000011ff
@@ -174,6 +176,8 @@ enum vmcs_field {
GUEST_PDPTR2_HIGH = 0x0000280f,
GUEST_PDPTR3 = 0x00002810,
GUEST_PDPTR3_HIGH = 0x00002811,
+ GUEST_BNDCFGS = 0x00002812,
+ GUEST_BNDCFGS_HIGH = 0x00002813,
HOST_IA32_PAT = 0x00002c00,
HOST_IA32_PAT_HIGH = 0x00002c01,
HOST_IA32_EFER = 0x00002c02,
diff --git a/arch/x86/include/asm/vvar.h b/arch/x86/include/asm/vvar.h
index d76ac40da206..081d909bc495 100644
--- a/arch/x86/include/asm/vvar.h
+++ b/arch/x86/include/asm/vvar.h
@@ -16,8 +16,8 @@
* you mess up, the linker will catch it.)
*/
-/* Base address of vvars. This is not ABI. */
-#define VVAR_ADDRESS (-10*1024*1024 - 4096)
+#ifndef _ASM_X86_VVAR_H
+#define _ASM_X86_VVAR_H
#if defined(__VVAR_KERNEL_LDS)
@@ -29,16 +29,35 @@
#else
+#ifdef BUILD_VDSO32
+
+#define DECLARE_VVAR(offset, type, name) \
+ extern type vvar_ ## name __attribute__((visibility("hidden")));
+
+#define VVAR(name) (vvar_ ## name)
+
+#else
+
+extern char __vvar_page;
+
+/* Base address of vvars. This is not ABI. */
+#ifdef CONFIG_X86_64
+#define VVAR_ADDRESS (-10*1024*1024 - 4096)
+#else
+#define VVAR_ADDRESS (&__vvar_page)
+#endif
+
#define DECLARE_VVAR(offset, type, name) \
static type const * const vvaraddr_ ## name = \
(void *)(VVAR_ADDRESS + (offset));
+#define VVAR(name) (*vvaraddr_ ## name)
+#endif
+
#define DEFINE_VVAR(type, name) \
type name \
__attribute__((section(".vvar_" #name), aligned(16))) __visible
-#define VVAR(name) (*vvaraddr_ ## name)
-
#endif
/* DECLARE_VVAR(offset, type, name) */
@@ -48,3 +67,5 @@ DECLARE_VVAR(16, int, vgetcpu_mode)
DECLARE_VVAR(128, struct vsyscall_gtod_data, vsyscall_gtod_data)
#undef DECLARE_VVAR
+
+#endif
diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
index 3e276eb23d1b..c949923a5668 100644
--- a/arch/x86/include/asm/xen/page.h
+++ b/arch/x86/include/asm/xen/page.h
@@ -49,10 +49,17 @@ extern bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
extern unsigned long set_phys_range_identity(unsigned long pfn_s,
unsigned long pfn_e);
+extern int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops,
+ struct gnttab_map_grant_ref *kmap_ops,
+ struct page **pages, unsigned int count);
extern int m2p_add_override(unsigned long mfn, struct page *page,
struct gnttab_map_grant_ref *kmap_op);
+extern int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops,
+ struct gnttab_map_grant_ref *kmap_ops,
+ struct page **pages, unsigned int count);
extern int m2p_remove_override(struct page *page,
- struct gnttab_map_grant_ref *kmap_op);
+ struct gnttab_map_grant_ref *kmap_op,
+ unsigned long mfn);
extern struct page *m2p_find_override(unsigned long mfn);
extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn);
@@ -121,7 +128,7 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn)
pfn = m2p_find_override_pfn(mfn, ~0);
}
- /*
+ /*
* pfn is ~0 if there are no entries in the m2p for mfn or if the
* entry doesn't map back to the mfn and m2p_override doesn't have a
* valid entry for it.
diff --git a/arch/x86/include/asm/xsave.h b/arch/x86/include/asm/xsave.h
index 554738963b28..d949ef28c48b 100644
--- a/arch/x86/include/asm/xsave.h
+++ b/arch/x86/include/asm/xsave.h
@@ -6,13 +6,18 @@
#define XSTATE_CPUID 0x0000000d
-#define XSTATE_FP 0x1
-#define XSTATE_SSE 0x2
-#define XSTATE_YMM 0x4
-#define XSTATE_BNDREGS 0x8
-#define XSTATE_BNDCSR 0x10
+#define XSTATE_FP 0x1
+#define XSTATE_SSE 0x2
+#define XSTATE_YMM 0x4
+#define XSTATE_BNDREGS 0x8
+#define XSTATE_BNDCSR 0x10
+#define XSTATE_OPMASK 0x20
+#define XSTATE_ZMM_Hi256 0x40
+#define XSTATE_Hi16_ZMM 0x80
#define XSTATE_FPSSE (XSTATE_FP | XSTATE_SSE)
+/* Bit 63 of XCR0 is reserved for future expansion */
+#define XSTATE_EXTEND_MASK (~(XSTATE_FPSSE | (1ULL << 63)))
#define FXSAVE_SIZE 512
@@ -23,7 +28,8 @@
#define XSAVE_YMM_OFFSET (XSAVE_HDR_SIZE + XSAVE_HDR_OFFSET)
/* Supported features which support lazy state saving */
-#define XSTATE_LAZY (XSTATE_FP | XSTATE_SSE | XSTATE_YMM)
+#define XSTATE_LAZY (XSTATE_FP | XSTATE_SSE | XSTATE_YMM \
+ | XSTATE_OPMASK | XSTATE_ZMM_Hi256 | XSTATE_Hi16_ZMM)
/* Supported features which require eager state saving */
#define XSTATE_EAGER (XSTATE_BNDREGS | XSTATE_BNDCSR)
diff --git a/arch/x86/include/uapi/asm/msr-index.h b/arch/x86/include/uapi/asm/msr-index.h
index c19fc60ff062..c827ace3121b 100644
--- a/arch/x86/include/uapi/asm/msr-index.h
+++ b/arch/x86/include/uapi/asm/msr-index.h
@@ -295,6 +295,7 @@
#define MSR_SMI_COUNT 0x00000034
#define MSR_IA32_FEATURE_CONTROL 0x0000003a
#define MSR_IA32_TSC_ADJUST 0x0000003b
+#define MSR_IA32_BNDCFGS 0x00000d90
#define FEATURE_CONTROL_LOCKED (1<<0)
#define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX (1<<1)
@@ -368,33 +369,58 @@
#define THERM_LOG_THRESHOLD1 (1 << 9)
/* MISC_ENABLE bits: architectural */
-#define MSR_IA32_MISC_ENABLE_FAST_STRING (1ULL << 0)
-#define MSR_IA32_MISC_ENABLE_TCC (1ULL << 1)
-#define MSR_IA32_MISC_ENABLE_EMON (1ULL << 7)
-#define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL (1ULL << 11)
-#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL (1ULL << 12)
-#define MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP (1ULL << 16)
-#define MSR_IA32_MISC_ENABLE_MWAIT (1ULL << 18)
-#define MSR_IA32_MISC_ENABLE_LIMIT_CPUID (1ULL << 22)
-#define MSR_IA32_MISC_ENABLE_XTPR_DISABLE (1ULL << 23)
-#define MSR_IA32_MISC_ENABLE_XD_DISABLE (1ULL << 34)
+#define MSR_IA32_MISC_ENABLE_FAST_STRING_BIT 0
+#define MSR_IA32_MISC_ENABLE_FAST_STRING (1ULL << MSR_IA32_MISC_ENABLE_FAST_STRING_BIT)
+#define MSR_IA32_MISC_ENABLE_TCC_BIT 1
+#define MSR_IA32_MISC_ENABLE_TCC (1ULL << MSR_IA32_MISC_ENABLE_TCC_BIT)
+#define MSR_IA32_MISC_ENABLE_EMON_BIT 7
+#define MSR_IA32_MISC_ENABLE_EMON (1ULL << MSR_IA32_MISC_ENABLE_EMON_BIT)
+#define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL_BIT 11
+#define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL (1ULL << MSR_IA32_MISC_ENABLE_BTS_UNAVAIL_BIT)
+#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL_BIT 12
+#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL (1ULL << MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL_BIT)
+#define MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP_BIT 16
+#define MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP (1ULL << MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP_BIT)
+#define MSR_IA32_MISC_ENABLE_MWAIT_BIT 18
+#define MSR_IA32_MISC_ENABLE_MWAIT (1ULL << MSR_IA32_MISC_ENABLE_MWAIT_BIT)
+#define MSR_IA32_MISC_ENABLE_LIMIT_CPUID_BIT 22
+#define MSR_IA32_MISC_ENABLE_LIMIT_CPUID (1ULL << MSR_IA32_MISC_ENABLE_LIMIT_CPUID_BIT);
+#define MSR_IA32_MISC_ENABLE_XTPR_DISABLE_BIT 23
+#define MSR_IA32_MISC_ENABLE_XTPR_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_XTPR_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_XD_DISABLE_BIT 34
+#define MSR_IA32_MISC_ENABLE_XD_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_XD_DISABLE_BIT)
/* MISC_ENABLE bits: model-specific, meaning may vary from core to core */
-#define MSR_IA32_MISC_ENABLE_X87_COMPAT (1ULL << 2)
-#define MSR_IA32_MISC_ENABLE_TM1 (1ULL << 3)
-#define MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE (1ULL << 4)
-#define MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE (1ULL << 6)
-#define MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK (1ULL << 8)
-#define MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE (1ULL << 9)
-#define MSR_IA32_MISC_ENABLE_FERR (1ULL << 10)
-#define MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX (1ULL << 10)
-#define MSR_IA32_MISC_ENABLE_TM2 (1ULL << 13)
-#define MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE (1ULL << 19)
-#define MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK (1ULL << 20)
-#define MSR_IA32_MISC_ENABLE_L1D_CONTEXT (1ULL << 24)
-#define MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE (1ULL << 37)
-#define MSR_IA32_MISC_ENABLE_TURBO_DISABLE (1ULL << 38)
-#define MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE (1ULL << 39)
+#define MSR_IA32_MISC_ENABLE_X87_COMPAT_BIT 2
+#define MSR_IA32_MISC_ENABLE_X87_COMPAT (1ULL << MSR_IA32_MISC_ENABLE_X87_COMPAT_BIT)
+#define MSR_IA32_MISC_ENABLE_TM1_BIT 3
+#define MSR_IA32_MISC_ENABLE_TM1 (1ULL << MSR_IA32_MISC_ENABLE_TM1_BIT)
+#define MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE_BIT 4
+#define MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE_BIT 6
+#define MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK_BIT 8
+#define MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK (1ULL << MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK_BIT)
+#define MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE_BIT 9
+#define MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_FERR_BIT 10
+#define MSR_IA32_MISC_ENABLE_FERR (1ULL << MSR_IA32_MISC_ENABLE_FERR_BIT)
+#define MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX_BIT 10
+#define MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX (1ULL << MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX_BIT)
+#define MSR_IA32_MISC_ENABLE_TM2_BIT 13
+#define MSR_IA32_MISC_ENABLE_TM2 (1ULL << MSR_IA32_MISC_ENABLE_TM2_BIT)
+#define MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE_BIT 19
+#define MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK_BIT 20
+#define MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK (1ULL << MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK_BIT)
+#define MSR_IA32_MISC_ENABLE_L1D_CONTEXT_BIT 24
+#define MSR_IA32_MISC_ENABLE_L1D_CONTEXT (1ULL << MSR_IA32_MISC_ENABLE_L1D_CONTEXT_BIT)
+#define MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE_BIT 37
+#define MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_TURBO_DISABLE_BIT 38
+#define MSR_IA32_MISC_ENABLE_TURBO_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_TURBO_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE_BIT 39
+#define MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE_BIT)
#define MSR_IA32_TSC_DEADLINE 0x000006E0
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index cb648c84b327..f4d96000d33a 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -26,7 +26,7 @@ obj-$(CONFIG_IRQ_WORK) += irq_work.o
obj-y += probe_roms.o
obj-$(CONFIG_X86_32) += i386_ksyms_32.o
obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o
-obj-y += syscall_$(BITS).o
+obj-y += syscall_$(BITS).o vsyscall_gtod.o
obj-$(CONFIG_X86_64) += vsyscall_64.o
obj-$(CONFIG_X86_64) += vsyscall_emu_64.o
obj-$(CONFIG_SYSFS) += ksysfs.o
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 1dac94265b59..86281ffb96d6 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -53,10 +53,6 @@ EXPORT_SYMBOL(acpi_disabled);
# include <asm/proto.h>
#endif /* X86 */
-#define BAD_MADT_ENTRY(entry, end) ( \
- (!entry) || (unsigned long)entry + sizeof(*entry) > end || \
- ((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
-
#define PREFIX "ACPI: "
int acpi_noirq; /* skip ACPI IRQ initialization */
@@ -613,10 +609,10 @@ static void acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
int nid;
nid = acpi_get_node(handle);
- if (nid == -1 || !node_online(nid))
- return;
- set_apicid_to_node(physid, nid);
- numa_set_node(cpu, nid);
+ if (nid != -1) {
+ set_apicid_to_node(physid, nid);
+ numa_set_node(cpu, nid);
+ }
#endif
}
@@ -907,10 +903,6 @@ static int __init acpi_parse_madt_lapic_entries(void)
#ifdef CONFIG_X86_IO_APIC
#define MP_ISA_BUS 0
-#ifdef CONFIG_X86_ES7000
-extern int es7000_plat;
-#endif
-
void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi)
{
int ioapic;
@@ -960,14 +952,6 @@ void __init mp_config_acpi_legacy_irqs(void)
set_bit(MP_ISA_BUS, mp_bus_not_pci);
pr_debug("Bus #%d is ISA\n", MP_ISA_BUS);
-#ifdef CONFIG_X86_ES7000
- /*
- * Older generations of ES7000 have no legacy identity mappings
- */
- if (es7000_plat == 1)
- return;
-#endif
-
/*
* Use the default configuration for the IRQs 0-15. Unless
* overridden by (MADT) interrupt source override entries.
diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c
index dec8de4e1663..f04dbb3069b8 100644
--- a/arch/x86/kernel/amd_nb.c
+++ b/arch/x86/kernel/amd_nb.c
@@ -22,6 +22,7 @@ const struct pci_device_id amd_nb_misc_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
{}
};
EXPORT_SYMBOL(amd_nb_misc_ids);
@@ -30,6 +31,7 @@ static const struct pci_device_id amd_nb_link_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F4) },
{}
};
diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c
index fd972a3e4cbb..9fa8aa051f54 100644
--- a/arch/x86/kernel/aperture_64.c
+++ b/arch/x86/kernel/aperture_64.c
@@ -18,7 +18,6 @@
#include <linux/pci_ids.h>
#include <linux/pci.h>
#include <linux/bitops.h>
-#include <linux/ioport.h>
#include <linux/suspend.h>
#include <asm/e820.h>
#include <asm/io.h>
@@ -54,18 +53,6 @@ int fallback_aper_force __initdata;
int fix_aperture __initdata = 1;
-static struct resource gart_resource = {
- .name = "GART",
- .flags = IORESOURCE_MEM,
-};
-
-static void __init insert_aperture_resource(u32 aper_base, u32 aper_size)
-{
- gart_resource.start = aper_base;
- gart_resource.end = aper_base + aper_size - 1;
- insert_resource(&iomem_resource, &gart_resource);
-}
-
/* This code runs before the PCI subsystem is initialized, so just
access the northbridge directly. */
@@ -96,7 +83,6 @@ static u32 __init allocate_aperture(void)
memblock_reserve(addr, aper_size);
printk(KERN_INFO "Mapping aperture over %d KB of RAM @ %lx\n",
aper_size >> 10, addr);
- insert_aperture_resource((u32)addr, aper_size);
register_nosave_region(addr >> PAGE_SHIFT,
(addr+aper_size) >> PAGE_SHIFT);
@@ -444,12 +430,8 @@ int __init gart_iommu_hole_init(void)
out:
if (!fix && !fallback_aper_force) {
- if (last_aper_base) {
- unsigned long n = (32 * 1024 * 1024) << last_aper_order;
-
- insert_aperture_resource((u32)last_aper_base, n);
+ if (last_aper_base)
return 1;
- }
return 0;
}
diff --git a/arch/x86/kernel/apic/Makefile b/arch/x86/kernel/apic/Makefile
index 0ae0323b1f9c..dcb5b15401ce 100644
--- a/arch/x86/kernel/apic/Makefile
+++ b/arch/x86/kernel/apic/Makefile
@@ -18,10 +18,7 @@ obj-y += apic_flat_64.o
endif
# APIC probe will depend on the listing order here
-obj-$(CONFIG_X86_NUMAQ) += numaq_32.o
-obj-$(CONFIG_X86_SUMMIT) += summit_32.o
obj-$(CONFIG_X86_BIGSMP) += bigsmp_32.o
-obj-$(CONFIG_X86_ES7000) += es7000_32.o
# For 32bit, probe_32 need to be listed last
obj-$(CONFIG_X86_LOCAL_APIC) += probe_$(BITS).o
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 7f26c9a70a9e..481ae38f6a44 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -133,6 +133,10 @@ static inline void imcr_apic_to_pic(void)
* +1=force-enable
*/
static int force_enable_local_apic __initdata;
+
+/* Control whether x2APIC mode is enabled or not */
+static bool nox2apic __initdata;
+
/*
* APIC command line parameters
*/
@@ -162,8 +166,7 @@ int x2apic_mode;
/* x2apic enabled before OS handover */
int x2apic_preenabled;
static int x2apic_disabled;
-static int nox2apic;
-static __init int setup_nox2apic(char *str)
+static int __init setup_nox2apic(char *str)
{
if (x2apic_enabled()) {
int apicid = native_apic_msr_read(APIC_ID);
@@ -178,7 +181,7 @@ static __init int setup_nox2apic(char *str)
} else
setup_clear_cpu_cap(X86_FEATURE_X2APIC);
- nox2apic = 1;
+ nox2apic = true;
return 0;
}
@@ -283,8 +286,12 @@ u32 native_safe_apic_wait_icr_idle(void)
void native_apic_icr_write(u32 low, u32 id)
{
+ unsigned long flags;
+
+ local_irq_save(flags);
apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(id));
apic_write(APIC_ICR, low);
+ local_irq_restore(flags);
}
u64 native_apic_icr_read(void)
@@ -2129,7 +2136,6 @@ int generic_processor_info(int apicid, int version)
*
* - arch/x86/kernel/mpparse.c: MP_processor_info()
* - arch/x86/mm/amdtopology.c: amd_numa_init()
- * - arch/x86/platform/visws/visws_quirks.c: MP_processor_info()
*
* This function is executed with the modified
* boot_cpu_physical_apicid. So, disabled_cpu_apicid kernel
diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c
index 2c621a6b901a..7c1b29479513 100644
--- a/arch/x86/kernel/apic/apic_flat_64.c
+++ b/arch/x86/kernel/apic/apic_flat_64.c
@@ -198,7 +198,7 @@ static struct apic apic_flat = {
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
- .wait_for_init_deassert = NULL,
+ .wait_for_init_deassert = false,
.smp_callin_clear_local_apic = NULL,
.inquire_remote_apic = default_inquire_remote_apic,
@@ -314,7 +314,7 @@ static struct apic apic_physflat = {
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
- .wait_for_init_deassert = NULL,
+ .wait_for_init_deassert = false,
.smp_callin_clear_local_apic = NULL,
.inquire_remote_apic = default_inquire_remote_apic,
diff --git a/arch/x86/kernel/apic/apic_noop.c b/arch/x86/kernel/apic/apic_noop.c
index 191ce75c0e54..8c7c98249c20 100644
--- a/arch/x86/kernel/apic/apic_noop.c
+++ b/arch/x86/kernel/apic/apic_noop.c
@@ -172,8 +172,7 @@ struct apic apic_noop = {
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
- .wait_for_init_deassert = NULL,
-
+ .wait_for_init_deassert = false,
.smp_callin_clear_local_apic = NULL,
.inquire_remote_apic = NULL,
diff --git a/arch/x86/kernel/apic/apic_numachip.c b/arch/x86/kernel/apic/apic_numachip.c
index 3e67f9e3d7ef..a5b45df8bc88 100644
--- a/arch/x86/kernel/apic/apic_numachip.c
+++ b/arch/x86/kernel/apic/apic_numachip.c
@@ -248,7 +248,7 @@ static const struct apic apic_numachip __refconst = {
.wakeup_secondary_cpu = numachip_wakeup_secondary,
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
- .wait_for_init_deassert = NULL,
+ .wait_for_init_deassert = false,
.smp_callin_clear_local_apic = NULL,
.inquire_remote_apic = NULL, /* REMRD not supported */
diff --git a/arch/x86/kernel/apic/bigsmp_32.c b/arch/x86/kernel/apic/bigsmp_32.c
index d50e3640d5ae..e4840aa7a255 100644
--- a/arch/x86/kernel/apic/bigsmp_32.c
+++ b/arch/x86/kernel/apic/bigsmp_32.c
@@ -199,8 +199,7 @@ static struct apic apic_bigsmp = {
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
- .wait_for_init_deassert = default_wait_for_init_deassert,
-
+ .wait_for_init_deassert = true,
.smp_callin_clear_local_apic = NULL,
.inquire_remote_apic = default_inquire_remote_apic,
diff --git a/arch/x86/kernel/apic/es7000_32.c b/arch/x86/kernel/apic/es7000_32.c
deleted file mode 100644
index c55224731b2d..000000000000
--- a/arch/x86/kernel/apic/es7000_32.c
+++ /dev/null
@@ -1,746 +0,0 @@
-/*
- * Written by: Garry Forsgren, Unisys Corporation
- * Natalie Protasevich, Unisys Corporation
- *
- * This file contains the code to configure and interface
- * with Unisys ES7000 series hardware system manager.
- *
- * Copyright (c) 2003 Unisys Corporation.
- * Copyright (C) 2009, Red Hat, Inc., Ingo Molnar
- *
- * 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 would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Unisys Corporation, Township Line & Union Meeting
- * Roads-A, Unisys Way, Blue Bell, Pennsylvania, 19424, or:
- *
- * http://www.unisys.com
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/notifier.h>
-#include <linux/spinlock.h>
-#include <linux/cpumask.h>
-#include <linux/threads.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/reboot.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/acpi.h>
-#include <linux/init.h>
-#include <linux/gfp.h>
-#include <linux/nmi.h>
-#include <linux/smp.h>
-#include <linux/io.h>
-
-#include <asm/apicdef.h>
-#include <linux/atomic.h>
-#include <asm/fixmap.h>
-#include <asm/mpspec.h>
-#include <asm/setup.h>
-#include <asm/apic.h>
-#include <asm/ipi.h>
-
-/*
- * ES7000 chipsets
- */
-
-#define NON_UNISYS 0
-#define ES7000_CLASSIC 1
-#define ES7000_ZORRO 2
-
-#define MIP_REG 1
-#define MIP_PSAI_REG 4
-
-#define MIP_BUSY 1
-#define MIP_SPIN 0xf0000
-#define MIP_VALID 0x0100000000000000ULL
-#define MIP_SW_APIC 0x1020b
-
-#define MIP_PORT(val) ((val >> 32) & 0xffff)
-
-#define MIP_RD_LO(val) (val & 0xffffffff)
-
-struct mip_reg {
- unsigned long long off_0x00;
- unsigned long long off_0x08;
- unsigned long long off_0x10;
- unsigned long long off_0x18;
- unsigned long long off_0x20;
- unsigned long long off_0x28;
- unsigned long long off_0x30;
- unsigned long long off_0x38;
-};
-
-struct mip_reg_info {
- unsigned long long mip_info;
- unsigned long long delivery_info;
- unsigned long long host_reg;
- unsigned long long mip_reg;
-};
-
-struct psai {
- unsigned long long entry_type;
- unsigned long long addr;
- unsigned long long bep_addr;
-};
-
-#ifdef CONFIG_ACPI
-
-struct es7000_oem_table {
- struct acpi_table_header Header;
- u32 OEMTableAddr;
- u32 OEMTableSize;
-};
-
-static unsigned long oem_addrX;
-static unsigned long oem_size;
-
-#endif
-
-/*
- * ES7000 Globals
- */
-
-static volatile unsigned long *psai;
-static struct mip_reg *mip_reg;
-static struct mip_reg *host_reg;
-static int mip_port;
-static unsigned long mip_addr;
-static unsigned long host_addr;
-
-int es7000_plat;
-
-/*
- * GSI override for ES7000 platforms.
- */
-
-
-static int wakeup_secondary_cpu_via_mip(int cpu, unsigned long eip)
-{
- unsigned long vect = 0, psaival = 0;
-
- if (psai == NULL)
- return -1;
-
- vect = ((unsigned long)__pa(eip)/0x1000) << 16;
- psaival = (0x1000000 | vect | cpu);
-
- while (*psai & 0x1000000)
- ;
-
- *psai = psaival;
-
- return 0;
-}
-
-static int es7000_apic_is_cluster(void)
-{
- /* MPENTIUMIII */
- if (boot_cpu_data.x86 == 6 &&
- (boot_cpu_data.x86_model >= 7 && boot_cpu_data.x86_model <= 11))
- return 1;
-
- return 0;
-}
-
-static void setup_unisys(void)
-{
- /*
- * Determine the generation of the ES7000 currently running.
- *
- * es7000_plat = 1 if the machine is a 5xx ES7000 box
- * es7000_plat = 2 if the machine is a x86_64 ES7000 box
- *
- */
- if (!(boot_cpu_data.x86 <= 15 && boot_cpu_data.x86_model <= 2))
- es7000_plat = ES7000_ZORRO;
- else
- es7000_plat = ES7000_CLASSIC;
-}
-
-/*
- * Parse the OEM Table:
- */
-static int parse_unisys_oem(char *oemptr)
-{
- int i;
- int success = 0;
- unsigned char type, size;
- unsigned long val;
- char *tp = NULL;
- struct psai *psaip = NULL;
- struct mip_reg_info *mi;
- struct mip_reg *host, *mip;
-
- tp = oemptr;
-
- tp += 8;
-
- for (i = 0; i <= 6; i++) {
- type = *tp++;
- size = *tp++;
- tp -= 2;
- switch (type) {
- case MIP_REG:
- mi = (struct mip_reg_info *)tp;
- val = MIP_RD_LO(mi->host_reg);
- host_addr = val;
- host = (struct mip_reg *)val;
- host_reg = __va(host);
- val = MIP_RD_LO(mi->mip_reg);
- mip_port = MIP_PORT(mi->mip_info);
- mip_addr = val;
- mip = (struct mip_reg *)val;
- mip_reg = __va(mip);
- pr_debug("host_reg = 0x%lx\n",
- (unsigned long)host_reg);
- pr_debug("mip_reg = 0x%lx\n",
- (unsigned long)mip_reg);
- success++;
- break;
- case MIP_PSAI_REG:
- psaip = (struct psai *)tp;
- if (tp != NULL) {
- if (psaip->addr)
- psai = __va(psaip->addr);
- else
- psai = NULL;
- success++;
- }
- break;
- default:
- break;
- }
- tp += size;
- }
-
- if (success < 2)
- es7000_plat = NON_UNISYS;
- else
- setup_unisys();
-
- return es7000_plat;
-}
-
-#ifdef CONFIG_ACPI
-static int __init find_unisys_acpi_oem_table(unsigned long *oem_addr)
-{
- struct acpi_table_header *header = NULL;
- struct es7000_oem_table *table;
- acpi_size tbl_size;
- acpi_status ret;
- int i = 0;
-
- for (;;) {
- ret = acpi_get_table_with_size("OEM1", i++, &header, &tbl_size);
- if (!ACPI_SUCCESS(ret))
- return -1;
-
- if (!memcmp((char *) &header->oem_id, "UNISYS", 6))
- break;
-
- early_acpi_os_unmap_memory(header, tbl_size);
- }
-
- table = (void *)header;
-
- oem_addrX = table->OEMTableAddr;
- oem_size = table->OEMTableSize;
-
- early_acpi_os_unmap_memory(header, tbl_size);
-
- *oem_addr = (unsigned long)__acpi_map_table(oem_addrX, oem_size);
-
- return 0;
-}
-
-static void __init unmap_unisys_acpi_oem_table(unsigned long oem_addr)
-{
- if (!oem_addr)
- return;
-
- __acpi_unmap_table((char *)oem_addr, oem_size);
-}
-
-static int es7000_check_dsdt(void)
-{
- struct acpi_table_header header;
-
- if (ACPI_SUCCESS(acpi_get_table_header(ACPI_SIG_DSDT, 0, &header)) &&
- !strncmp(header.oem_id, "UNISYS", 6))
- return 1;
- return 0;
-}
-
-static int es7000_acpi_ret;
-
-/* Hook from generic ACPI tables.c */
-static int __init es7000_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
-{
- unsigned long oem_addr = 0;
- int check_dsdt;
- int ret = 0;
-
- /* check dsdt at first to avoid clear fix_map for oem_addr */
- check_dsdt = es7000_check_dsdt();
-
- if (!find_unisys_acpi_oem_table(&oem_addr)) {
- if (check_dsdt) {
- ret = parse_unisys_oem((char *)oem_addr);
- } else {
- setup_unisys();
- ret = 1;
- }
- /*
- * we need to unmap it
- */
- unmap_unisys_acpi_oem_table(oem_addr);
- }
-
- es7000_acpi_ret = ret;
-
- return ret && !es7000_apic_is_cluster();
-}
-
-static int es7000_acpi_madt_oem_check_cluster(char *oem_id, char *oem_table_id)
-{
- int ret = es7000_acpi_ret;
-
- return ret && es7000_apic_is_cluster();
-}
-
-#else /* !CONFIG_ACPI: */
-static int es7000_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
-{
- return 0;
-}
-
-static int es7000_acpi_madt_oem_check_cluster(char *oem_id, char *oem_table_id)
-{
- return 0;
-}
-#endif /* !CONFIG_ACPI */
-
-static void es7000_spin(int n)
-{
- int i = 0;
-
- while (i++ < n)
- rep_nop();
-}
-
-static int es7000_mip_write(struct mip_reg *mip_reg)
-{
- int status = 0;
- int spin;
-
- spin = MIP_SPIN;
- while ((host_reg->off_0x38 & MIP_VALID) != 0) {
- if (--spin <= 0) {
- WARN(1, "Timeout waiting for Host Valid Flag\n");
- return -1;
- }
- es7000_spin(MIP_SPIN);
- }
-
- memcpy(host_reg, mip_reg, sizeof(struct mip_reg));
- outb(1, mip_port);
-
- spin = MIP_SPIN;
-
- while ((mip_reg->off_0x38 & MIP_VALID) == 0) {
- if (--spin <= 0) {
- WARN(1, "Timeout waiting for MIP Valid Flag\n");
- return -1;
- }
- es7000_spin(MIP_SPIN);
- }
-
- status = (mip_reg->off_0x00 & 0xffff0000000000ULL) >> 48;
- mip_reg->off_0x38 &= ~MIP_VALID;
-
- return status;
-}
-
-static void es7000_enable_apic_mode(void)
-{
- struct mip_reg es7000_mip_reg;
- int mip_status;
-
- if (!es7000_plat)
- return;
-
- pr_info("Enabling APIC mode.\n");
- memset(&es7000_mip_reg, 0, sizeof(struct mip_reg));
- es7000_mip_reg.off_0x00 = MIP_SW_APIC;
- es7000_mip_reg.off_0x38 = MIP_VALID;
-
- while ((mip_status = es7000_mip_write(&es7000_mip_reg)) != 0)
- WARN(1, "Command failed, status = %x\n", mip_status);
-}
-
-static void es7000_wait_for_init_deassert(atomic_t *deassert)
-{
- while (!atomic_read(deassert))
- cpu_relax();
-}
-
-static unsigned int es7000_get_apic_id(unsigned long x)
-{
- return (x >> 24) & 0xFF;
-}
-
-static void es7000_send_IPI_mask(const struct cpumask *mask, int vector)
-{
- default_send_IPI_mask_sequence_phys(mask, vector);
-}
-
-static void es7000_send_IPI_allbutself(int vector)
-{
- default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector);
-}
-
-static void es7000_send_IPI_all(int vector)
-{
- es7000_send_IPI_mask(cpu_online_mask, vector);
-}
-
-static int es7000_apic_id_registered(void)
-{
- return 1;
-}
-
-static const struct cpumask *target_cpus_cluster(void)
-{
- return cpu_all_mask;
-}
-
-static const struct cpumask *es7000_target_cpus(void)
-{
- return cpumask_of(smp_processor_id());
-}
-
-static unsigned long es7000_check_apicid_used(physid_mask_t *map, int apicid)
-{
- return 0;
-}
-
-static unsigned long es7000_check_apicid_present(int bit)
-{
- return physid_isset(bit, phys_cpu_present_map);
-}
-
-static int es7000_early_logical_apicid(int cpu)
-{
- /* on es7000, logical apicid is the same as physical */
- return early_per_cpu(x86_bios_cpu_apicid, cpu);
-}
-
-static unsigned long calculate_ldr(int cpu)
-{
- unsigned long id = per_cpu(x86_bios_cpu_apicid, cpu);
-
- return SET_APIC_LOGICAL_ID(id);
-}
-
-/*
- * Set up the logical destination ID.
- *
- * Intel recommends to set DFR, LdR and TPR before enabling
- * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
- * document number 292116). So here it goes...
- */
-static void es7000_init_apic_ldr_cluster(void)
-{
- unsigned long val;
- int cpu = smp_processor_id();
-
- apic_write(APIC_DFR, APIC_DFR_CLUSTER);
- val = calculate_ldr(cpu);
- apic_write(APIC_LDR, val);
-}
-
-static void es7000_init_apic_ldr(void)
-{
- unsigned long val;
- int cpu = smp_processor_id();
-
- apic_write(APIC_DFR, APIC_DFR_FLAT);
- val = calculate_ldr(cpu);
- apic_write(APIC_LDR, val);
-}
-
-static void es7000_setup_apic_routing(void)
-{
- int apic = per_cpu(x86_bios_cpu_apicid, smp_processor_id());
-
- pr_info("Enabling APIC mode: %s. Using %d I/O APICs, target cpus %lx\n",
- (apic_version[apic] == 0x14) ?
- "Physical Cluster" : "Logical Cluster",
- nr_ioapics, cpumask_bits(es7000_target_cpus())[0]);
-}
-
-static int es7000_cpu_present_to_apicid(int mps_cpu)
-{
- if (!mps_cpu)
- return boot_cpu_physical_apicid;
- else if (mps_cpu < nr_cpu_ids)
- return per_cpu(x86_bios_cpu_apicid, mps_cpu);
- else
- return BAD_APICID;
-}
-
-static int cpu_id;
-
-static void es7000_apicid_to_cpu_present(int phys_apicid, physid_mask_t *retmap)
-{
- physid_set_mask_of_physid(cpu_id, retmap);
- ++cpu_id;
-}
-
-static void es7000_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
-{
- /* For clustered we don't have a good way to do this yet - hack */
- physids_promote(0xFFL, retmap);
-}
-
-static int es7000_check_phys_apicid_present(int cpu_physical_apicid)
-{
- boot_cpu_physical_apicid = read_apic_id();
- return 1;
-}
-
-static inline int
-es7000_cpu_mask_to_apicid(const struct cpumask *cpumask, unsigned int *dest_id)
-{
- unsigned int round = 0;
- unsigned int cpu, uninitialized_var(apicid);
-
- /*
- * The cpus in the mask must all be on the apic cluster.
- */
- for_each_cpu_and(cpu, cpumask, cpu_online_mask) {
- int new_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
-
- if (round && APIC_CLUSTER(apicid) != APIC_CLUSTER(new_apicid)) {
- WARN(1, "Not a valid mask!");
-
- return -EINVAL;
- }
- apicid |= new_apicid;
- round++;
- }
- if (!round)
- return -EINVAL;
- *dest_id = apicid;
- return 0;
-}
-
-static int
-es7000_cpu_mask_to_apicid_and(const struct cpumask *inmask,
- const struct cpumask *andmask,
- unsigned int *apicid)
-{
- cpumask_var_t cpumask;
- *apicid = early_per_cpu(x86_cpu_to_logical_apicid, 0);
-
- if (!alloc_cpumask_var(&cpumask, GFP_ATOMIC))
- return 0;
-
- cpumask_and(cpumask, inmask, andmask);
- es7000_cpu_mask_to_apicid(cpumask, apicid);
-
- free_cpumask_var(cpumask);
-
- return 0;
-}
-
-static int es7000_phys_pkg_id(int cpuid_apic, int index_msb)
-{
- return cpuid_apic >> index_msb;
-}
-
-static int probe_es7000(void)
-{
- /* probed later in mptable/ACPI hooks */
- return 0;
-}
-
-static int es7000_mps_ret;
-static int es7000_mps_oem_check(struct mpc_table *mpc, char *oem,
- char *productid)
-{
- int ret = 0;
-
- if (mpc->oemptr) {
- struct mpc_oemtable *oem_table =
- (struct mpc_oemtable *)mpc->oemptr;
-
- if (!strncmp(oem, "UNISYS", 6))
- ret = parse_unisys_oem((char *)oem_table);
- }
-
- es7000_mps_ret = ret;
-
- return ret && !es7000_apic_is_cluster();
-}
-
-static int es7000_mps_oem_check_cluster(struct mpc_table *mpc, char *oem,
- char *productid)
-{
- int ret = es7000_mps_ret;
-
- return ret && es7000_apic_is_cluster();
-}
-
-/* We've been warned by a false positive warning.Use __refdata to keep calm. */
-static struct apic __refdata apic_es7000_cluster = {
-
- .name = "es7000",
- .probe = probe_es7000,
- .acpi_madt_oem_check = es7000_acpi_madt_oem_check_cluster,
- .apic_id_valid = default_apic_id_valid,
- .apic_id_registered = es7000_apic_id_registered,
-
- .irq_delivery_mode = dest_LowestPrio,
- /* logical delivery broadcast to all procs: */
- .irq_dest_mode = 1,
-
- .target_cpus = target_cpus_cluster,
- .disable_esr = 1,
- .dest_logical = 0,
- .check_apicid_used = es7000_check_apicid_used,
- .check_apicid_present = es7000_check_apicid_present,
-
- .vector_allocation_domain = flat_vector_allocation_domain,
- .init_apic_ldr = es7000_init_apic_ldr_cluster,
-
- .ioapic_phys_id_map = es7000_ioapic_phys_id_map,
- .setup_apic_routing = es7000_setup_apic_routing,
- .multi_timer_check = NULL,
- .cpu_present_to_apicid = es7000_cpu_present_to_apicid,
- .apicid_to_cpu_present = es7000_apicid_to_cpu_present,
- .setup_portio_remap = NULL,
- .check_phys_apicid_present = es7000_check_phys_apicid_present,
- .enable_apic_mode = es7000_enable_apic_mode,
- .phys_pkg_id = es7000_phys_pkg_id,
- .mps_oem_check = es7000_mps_oem_check_cluster,
-
- .get_apic_id = es7000_get_apic_id,
- .set_apic_id = NULL,
- .apic_id_mask = 0xFF << 24,
-
- .cpu_mask_to_apicid_and = es7000_cpu_mask_to_apicid_and,
-
- .send_IPI_mask = es7000_send_IPI_mask,
- .send_IPI_mask_allbutself = NULL,
- .send_IPI_allbutself = es7000_send_IPI_allbutself,
- .send_IPI_all = es7000_send_IPI_all,
- .send_IPI_self = default_send_IPI_self,
-
- .wakeup_secondary_cpu = wakeup_secondary_cpu_via_mip,
-
- .trampoline_phys_low = 0x467,
- .trampoline_phys_high = 0x469,
-
- .wait_for_init_deassert = NULL,
-
- /* Nothing to do for most platforms, since cleared by the INIT cycle: */
- .smp_callin_clear_local_apic = NULL,
- .inquire_remote_apic = default_inquire_remote_apic,
-
- .read = native_apic_mem_read,
- .write = native_apic_mem_write,
- .eoi_write = native_apic_mem_write,
- .icr_read = native_apic_icr_read,
- .icr_write = native_apic_icr_write,
- .wait_icr_idle = native_apic_wait_icr_idle,
- .safe_wait_icr_idle = native_safe_apic_wait_icr_idle,
-
- .x86_32_early_logical_apicid = es7000_early_logical_apicid,
-};
-
-static struct apic __refdata apic_es7000 = {
-
- .name = "es7000",
- .probe = probe_es7000,
- .acpi_madt_oem_check = es7000_acpi_madt_oem_check,
- .apic_id_valid = default_apic_id_valid,
- .apic_id_registered = es7000_apic_id_registered,
-
- .irq_delivery_mode = dest_Fixed,
- /* phys delivery to target CPUs: */
- .irq_dest_mode = 0,
-
- .target_cpus = es7000_target_cpus,
- .disable_esr = 1,
- .dest_logical = 0,
- .check_apicid_used = es7000_check_apicid_used,
- .check_apicid_present = es7000_check_apicid_present,
-
- .vector_allocation_domain = flat_vector_allocation_domain,
- .init_apic_ldr = es7000_init_apic_ldr,
-
- .ioapic_phys_id_map = es7000_ioapic_phys_id_map,
- .setup_apic_routing = es7000_setup_apic_routing,
- .multi_timer_check = NULL,
- .cpu_present_to_apicid = es7000_cpu_present_to_apicid,
- .apicid_to_cpu_present = es7000_apicid_to_cpu_present,
- .setup_portio_remap = NULL,
- .check_phys_apicid_present = es7000_check_phys_apicid_present,
- .enable_apic_mode = es7000_enable_apic_mode,
- .phys_pkg_id = es7000_phys_pkg_id,
- .mps_oem_check = es7000_mps_oem_check,
-
- .get_apic_id = es7000_get_apic_id,
- .set_apic_id = NULL,
- .apic_id_mask = 0xFF << 24,
-
- .cpu_mask_to_apicid_and = es7000_cpu_mask_to_apicid_and,
-
- .send_IPI_mask = es7000_send_IPI_mask,
- .send_IPI_mask_allbutself = NULL,
- .send_IPI_allbutself = es7000_send_IPI_allbutself,
- .send_IPI_all = es7000_send_IPI_all,
- .send_IPI_self = default_send_IPI_self,
-
- .trampoline_phys_low = 0x467,
- .trampoline_phys_high = 0x469,
-
- .wait_for_init_deassert = es7000_wait_for_init_deassert,
-
- /* Nothing to do for most platforms, since cleared by the INIT cycle: */
- .smp_callin_clear_local_apic = NULL,
- .inquire_remote_apic = default_inquire_remote_apic,
-
- .read = native_apic_mem_read,
- .write = native_apic_mem_write,
- .eoi_write = native_apic_mem_write,
- .icr_read = native_apic_icr_read,
- .icr_write = native_apic_icr_write,
- .wait_icr_idle = native_apic_wait_icr_idle,
- .safe_wait_icr_idle = native_safe_apic_wait_icr_idle,
-
- .x86_32_early_logical_apicid = es7000_early_logical_apicid,
-};
-
-/*
- * Need to check for es7000 followed by es7000_cluster, so this order
- * in apic_drivers is important.
- */
-apic_drivers(apic_es7000, apic_es7000_cluster);
diff --git a/arch/x86/kernel/apic/numaq_32.c b/arch/x86/kernel/apic/numaq_32.c
deleted file mode 100644
index 1e42e8f305ee..000000000000
--- a/arch/x86/kernel/apic/numaq_32.c
+++ /dev/null
@@ -1,525 +0,0 @@
-/*
- * Written by: Patricia Gaughen, IBM Corporation
- *
- * Copyright (C) 2002, IBM Corp.
- * Copyright (C) 2009, Red Hat, Inc., Ingo Molnar
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT. 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.
- *
- * Send feedback to <gone@us.ibm.com>
- */
-#include <linux/nodemask.h>
-#include <linux/topology.h>
-#include <linux/bootmem.h>
-#include <linux/memblock.h>
-#include <linux/threads.h>
-#include <linux/cpumask.h>
-#include <linux/kernel.h>
-#include <linux/mmzone.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/numa.h>
-#include <linux/smp.h>
-#include <linux/io.h>
-#include <linux/mm.h>
-
-#include <asm/processor.h>
-#include <asm/fixmap.h>
-#include <asm/mpspec.h>
-#include <asm/numaq.h>
-#include <asm/setup.h>
-#include <asm/apic.h>
-#include <asm/e820.h>
-#include <asm/ipi.h>
-
-int found_numaq;
-
-/*
- * Have to match translation table entries to main table entries by counter
- * hence the mpc_record variable .... can't see a less disgusting way of
- * doing this ....
- */
-struct mpc_trans {
- unsigned char mpc_type;
- unsigned char trans_len;
- unsigned char trans_type;
- unsigned char trans_quad;
- unsigned char trans_global;
- unsigned char trans_local;
- unsigned short trans_reserved;
-};
-
-static int mpc_record;
-
-static struct mpc_trans *translation_table[MAX_MPC_ENTRY];
-
-int mp_bus_id_to_node[MAX_MP_BUSSES];
-int mp_bus_id_to_local[MAX_MP_BUSSES];
-int quad_local_to_mp_bus_id[NR_CPUS/4][4];
-
-
-static inline void numaq_register_node(int node, struct sys_cfg_data *scd)
-{
- struct eachquadmem *eq = scd->eq + node;
- u64 start = (u64)(eq->hi_shrd_mem_start - eq->priv_mem_size) << 20;
- u64 end = (u64)(eq->hi_shrd_mem_start + eq->hi_shrd_mem_size) << 20;
- int ret;
-
- node_set(node, numa_nodes_parsed);
- ret = numa_add_memblk(node, start, end);
- BUG_ON(ret < 0);
-}
-
-/*
- * Function: smp_dump_qct()
- *
- * Description: gets memory layout from the quad config table. This
- * function also updates numa_nodes_parsed with the nodes (quads) present.
- */
-static void __init smp_dump_qct(void)
-{
- struct sys_cfg_data *scd;
- int node;
-
- scd = (void *)__va(SYS_CFG_DATA_PRIV_ADDR);
-
- for_each_node(node) {
- if (scd->quads_present31_0 & (1 << node))
- numaq_register_node(node, scd);
- }
-}
-
-void numaq_tsc_disable(void)
-{
- if (!found_numaq)
- return;
-
- if (num_online_nodes() > 1) {
- printk(KERN_DEBUG "NUMAQ: disabling TSC\n");
- setup_clear_cpu_cap(X86_FEATURE_TSC);
- }
-}
-
-static void __init numaq_tsc_init(void)
-{
- numaq_tsc_disable();
-}
-
-static inline int generate_logical_apicid(int quad, int phys_apicid)
-{
- return (quad << 4) + (phys_apicid ? phys_apicid << 1 : 1);
-}
-
-/* x86_quirks member */
-static int mpc_apic_id(struct mpc_cpu *m)
-{
- int quad = translation_table[mpc_record]->trans_quad;
- int logical_apicid = generate_logical_apicid(quad, m->apicid);
-
- printk(KERN_DEBUG
- "Processor #%d %u:%u APIC version %d (quad %d, apic %d)\n",
- m->apicid, (m->cpufeature & CPU_FAMILY_MASK) >> 8,
- (m->cpufeature & CPU_MODEL_MASK) >> 4,
- m->apicver, quad, logical_apicid);
-
- return logical_apicid;
-}
-
-/* x86_quirks member */
-static void mpc_oem_bus_info(struct mpc_bus *m, char *name)
-{
- int quad = translation_table[mpc_record]->trans_quad;
- int local = translation_table[mpc_record]->trans_local;
-
- mp_bus_id_to_node[m->busid] = quad;
- mp_bus_id_to_local[m->busid] = local;
-
- printk(KERN_INFO "Bus #%d is %s (node %d)\n", m->busid, name, quad);
-}
-
-/* x86_quirks member */
-static void mpc_oem_pci_bus(struct mpc_bus *m)
-{
- int quad = translation_table[mpc_record]->trans_quad;
- int local = translation_table[mpc_record]->trans_local;
-
- quad_local_to_mp_bus_id[quad][local] = m->busid;
-}
-
-/*
- * Called from mpparse code.
- * mode = 0: prescan
- * mode = 1: one mpc entry scanned
- */
-static void numaq_mpc_record(unsigned int mode)
-{
- if (!mode)
- mpc_record = 0;
- else
- mpc_record++;
-}
-
-static void __init MP_translation_info(struct mpc_trans *m)
-{
- printk(KERN_INFO
- "Translation: record %d, type %d, quad %d, global %d, local %d\n",
- mpc_record, m->trans_type, m->trans_quad, m->trans_global,
- m->trans_local);
-
- if (mpc_record >= MAX_MPC_ENTRY)
- printk(KERN_ERR "MAX_MPC_ENTRY exceeded!\n");
- else
- translation_table[mpc_record] = m; /* stash this for later */
-
- if (m->trans_quad < MAX_NUMNODES && !node_online(m->trans_quad))
- node_set_online(m->trans_quad);
-}
-
-static int __init mpf_checksum(unsigned char *mp, int len)
-{
- int sum = 0;
-
- while (len--)
- sum += *mp++;
-
- return sum & 0xFF;
-}
-
-/*
- * Read/parse the MPC oem tables
- */
-static void __init smp_read_mpc_oem(struct mpc_table *mpc)
-{
- struct mpc_oemtable *oemtable = (void *)(long)mpc->oemptr;
- int count = sizeof(*oemtable); /* the header size */
- unsigned char *oemptr = ((unsigned char *)oemtable) + count;
-
- mpc_record = 0;
- printk(KERN_INFO
- "Found an OEM MPC table at %8p - parsing it...\n", oemtable);
-
- if (memcmp(oemtable->signature, MPC_OEM_SIGNATURE, 4)) {
- printk(KERN_WARNING
- "SMP mpc oemtable: bad signature [%c%c%c%c]!\n",
- oemtable->signature[0], oemtable->signature[1],
- oemtable->signature[2], oemtable->signature[3]);
- return;
- }
-
- if (mpf_checksum((unsigned char *)oemtable, oemtable->length)) {
- printk(KERN_WARNING "SMP oem mptable: checksum error!\n");
- return;
- }
-
- while (count < oemtable->length) {
- switch (*oemptr) {
- case MP_TRANSLATION:
- {
- struct mpc_trans *m = (void *)oemptr;
-
- MP_translation_info(m);
- oemptr += sizeof(*m);
- count += sizeof(*m);
- ++mpc_record;
- break;
- }
- default:
- printk(KERN_WARNING
- "Unrecognised OEM table entry type! - %d\n",
- (int)*oemptr);
- return;
- }
- }
-}
-
-static __init void early_check_numaq(void)
-{
- /*
- * get boot-time SMP configuration:
- */
- if (smp_found_config)
- early_get_smp_config();
-
- if (found_numaq) {
- x86_init.mpparse.mpc_record = numaq_mpc_record;
- x86_init.mpparse.setup_ioapic_ids = x86_init_noop;
- x86_init.mpparse.mpc_apic_id = mpc_apic_id;
- x86_init.mpparse.smp_read_mpc_oem = smp_read_mpc_oem;
- x86_init.mpparse.mpc_oem_pci_bus = mpc_oem_pci_bus;
- x86_init.mpparse.mpc_oem_bus_info = mpc_oem_bus_info;
- x86_init.timers.tsc_pre_init = numaq_tsc_init;
- x86_init.pci.init = pci_numaq_init;
- }
-}
-
-int __init numaq_numa_init(void)
-{
- early_check_numaq();
- if (!found_numaq)
- return -ENOENT;
- smp_dump_qct();
-
- return 0;
-}
-
-#define NUMAQ_APIC_DFR_VALUE (APIC_DFR_CLUSTER)
-
-static inline unsigned int numaq_get_apic_id(unsigned long x)
-{
- return (x >> 24) & 0x0F;
-}
-
-static inline void numaq_send_IPI_mask(const struct cpumask *mask, int vector)
-{
- default_send_IPI_mask_sequence_logical(mask, vector);
-}
-
-static inline void numaq_send_IPI_allbutself(int vector)
-{
- default_send_IPI_mask_allbutself_logical(cpu_online_mask, vector);
-}
-
-static inline void numaq_send_IPI_all(int vector)
-{
- numaq_send_IPI_mask(cpu_online_mask, vector);
-}
-
-#define NUMAQ_TRAMPOLINE_PHYS_LOW (0x8)
-#define NUMAQ_TRAMPOLINE_PHYS_HIGH (0xa)
-
-/*
- * Because we use NMIs rather than the INIT-STARTUP sequence to
- * bootstrap the CPUs, the APIC may be in a weird state. Kick it:
- */
-static inline void numaq_smp_callin_clear_local_apic(void)
-{
- clear_local_APIC();
-}
-
-static inline const struct cpumask *numaq_target_cpus(void)
-{
- return cpu_all_mask;
-}
-
-static unsigned long numaq_check_apicid_used(physid_mask_t *map, int apicid)
-{
- return physid_isset(apicid, *map);
-}
-
-static inline unsigned long numaq_check_apicid_present(int bit)
-{
- return physid_isset(bit, phys_cpu_present_map);
-}
-
-static inline int numaq_apic_id_registered(void)
-{
- return 1;
-}
-
-static inline void numaq_init_apic_ldr(void)
-{
- /* Already done in NUMA-Q firmware */
-}
-
-static inline void numaq_setup_apic_routing(void)
-{
- printk(KERN_INFO
- "Enabling APIC mode: NUMA-Q. Using %d I/O APICs\n",
- nr_ioapics);
-}
-
-/*
- * Skip adding the timer int on secondary nodes, which causes
- * a small but painful rift in the time-space continuum.
- */
-static inline int numaq_multi_timer_check(int apic, int irq)
-{
- return apic != 0 && irq == 0;
-}
-
-static inline void numaq_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
-{
- /* We don't have a good way to do this yet - hack */
- return physids_promote(0xFUL, retmap);
-}
-
-/*
- * Supporting over 60 cpus on NUMA-Q requires a locality-dependent
- * cpu to APIC ID relation to properly interact with the intelligent
- * mode of the cluster controller.
- */
-static inline int numaq_cpu_present_to_apicid(int mps_cpu)
-{
- if (mps_cpu < 60)
- return ((mps_cpu >> 2) << 4) | (1 << (mps_cpu & 0x3));
- else
- return BAD_APICID;
-}
-
-static inline int numaq_apicid_to_node(int logical_apicid)
-{
- return logical_apicid >> 4;
-}
-
-static int numaq_numa_cpu_node(int cpu)
-{
- int logical_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
-
- if (logical_apicid != BAD_APICID)
- return numaq_apicid_to_node(logical_apicid);
- return NUMA_NO_NODE;
-}
-
-static void numaq_apicid_to_cpu_present(int logical_apicid, physid_mask_t *retmap)
-{
- int node = numaq_apicid_to_node(logical_apicid);
- int cpu = __ffs(logical_apicid & 0xf);
-
- physid_set_mask_of_physid(cpu + 4*node, retmap);
-}
-
-/* Where the IO area was mapped on multiquad, always 0 otherwise */
-void *xquad_portio;
-
-static inline int numaq_check_phys_apicid_present(int phys_apicid)
-{
- return 1;
-}
-
-/*
- * We use physical apicids here, not logical, so just return the default
- * physical broadcast to stop people from breaking us
- */
-static int
-numaq_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
- const struct cpumask *andmask,
- unsigned int *apicid)
-{
- *apicid = 0x0F;
- return 0;
-}
-
-/* No NUMA-Q box has a HT CPU, but it can't hurt to use the default code. */
-static inline int numaq_phys_pkg_id(int cpuid_apic, int index_msb)
-{
- return cpuid_apic >> index_msb;
-}
-
-static int
-numaq_mps_oem_check(struct mpc_table *mpc, char *oem, char *productid)
-{
- if (strncmp(oem, "IBM NUMA", 8))
- printk(KERN_ERR "Warning! Not a NUMA-Q system!\n");
- else
- found_numaq = 1;
-
- return found_numaq;
-}
-
-static int probe_numaq(void)
-{
- /* already know from get_memcfg_numaq() */
- return found_numaq;
-}
-
-static void numaq_setup_portio_remap(void)
-{
- int num_quads = num_online_nodes();
-
- if (num_quads <= 1)
- return;
-
- printk(KERN_INFO
- "Remapping cross-quad port I/O for %d quads\n", num_quads);
-
- xquad_portio = ioremap(XQUAD_PORTIO_BASE, num_quads*XQUAD_PORTIO_QUAD);
-
- printk(KERN_INFO
- "xquad_portio vaddr 0x%08lx, len %08lx\n",
- (u_long) xquad_portio, (u_long) num_quads*XQUAD_PORTIO_QUAD);
-}
-
-/* Use __refdata to keep false positive warning calm. */
-static struct apic __refdata apic_numaq = {
-
- .name = "NUMAQ",
- .probe = probe_numaq,
- .acpi_madt_oem_check = NULL,
- .apic_id_valid = default_apic_id_valid,
- .apic_id_registered = numaq_apic_id_registered,
-
- .irq_delivery_mode = dest_LowestPrio,
- /* physical delivery on LOCAL quad: */
- .irq_dest_mode = 0,
-
- .target_cpus = numaq_target_cpus,
- .disable_esr = 1,
- .dest_logical = APIC_DEST_LOGICAL,
- .check_apicid_used = numaq_check_apicid_used,
- .check_apicid_present = numaq_check_apicid_present,
-
- .vector_allocation_domain = flat_vector_allocation_domain,
- .init_apic_ldr = numaq_init_apic_ldr,
-
- .ioapic_phys_id_map = numaq_ioapic_phys_id_map,
- .setup_apic_routing = numaq_setup_apic_routing,
- .multi_timer_check = numaq_multi_timer_check,
- .cpu_present_to_apicid = numaq_cpu_present_to_apicid,
- .apicid_to_cpu_present = numaq_apicid_to_cpu_present,
- .setup_portio_remap = numaq_setup_portio_remap,
- .check_phys_apicid_present = numaq_check_phys_apicid_present,
- .enable_apic_mode = NULL,
- .phys_pkg_id = numaq_phys_pkg_id,
- .mps_oem_check = numaq_mps_oem_check,
-
- .get_apic_id = numaq_get_apic_id,
- .set_apic_id = NULL,
- .apic_id_mask = 0x0F << 24,
-
- .cpu_mask_to_apicid_and = numaq_cpu_mask_to_apicid_and,
-
- .send_IPI_mask = numaq_send_IPI_mask,
- .send_IPI_mask_allbutself = NULL,
- .send_IPI_allbutself = numaq_send_IPI_allbutself,
- .send_IPI_all = numaq_send_IPI_all,
- .send_IPI_self = default_send_IPI_self,
-
- .wakeup_secondary_cpu = wakeup_secondary_cpu_via_nmi,
- .trampoline_phys_low = NUMAQ_TRAMPOLINE_PHYS_LOW,
- .trampoline_phys_high = NUMAQ_TRAMPOLINE_PHYS_HIGH,
-
- /* We don't do anything here because we use NMI's to boot instead */
- .wait_for_init_deassert = NULL,
-
- .smp_callin_clear_local_apic = numaq_smp_callin_clear_local_apic,
- .inquire_remote_apic = NULL,
-
- .read = native_apic_mem_read,
- .write = native_apic_mem_write,
- .eoi_write = native_apic_mem_write,
- .icr_read = native_apic_icr_read,
- .icr_write = native_apic_icr_write,
- .wait_icr_idle = native_apic_wait_icr_idle,
- .safe_wait_icr_idle = native_safe_apic_wait_icr_idle,
-
- .x86_32_early_logical_apicid = noop_x86_32_early_logical_apicid,
- .x86_32_numa_cpu_node = numaq_numa_cpu_node,
-};
-
-apic_driver(apic_numaq);
diff --git a/arch/x86/kernel/apic/probe_32.c b/arch/x86/kernel/apic/probe_32.c
index eb35ef9ee63f..cceb352c968c 100644
--- a/arch/x86/kernel/apic/probe_32.c
+++ b/arch/x86/kernel/apic/probe_32.c
@@ -119,8 +119,7 @@ static struct apic apic_default = {
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
- .wait_for_init_deassert = default_wait_for_init_deassert,
-
+ .wait_for_init_deassert = true,
.smp_callin_clear_local_apic = NULL,
.inquire_remote_apic = default_inquire_remote_apic,
diff --git a/arch/x86/kernel/apic/summit_32.c b/arch/x86/kernel/apic/summit_32.c
deleted file mode 100644
index 00146f9b0254..000000000000
--- a/arch/x86/kernel/apic/summit_32.c
+++ /dev/null
@@ -1,551 +0,0 @@
-/*
- * IBM Summit-Specific Code
- *
- * Written By: Matthew Dobson, IBM Corporation
- *
- * Copyright (c) 2003 IBM Corp.
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT. 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.
- *
- * Send feedback to <colpatch@us.ibm.com>
- *
- */
-
-#define pr_fmt(fmt) "summit: %s: " fmt, __func__
-
-#include <linux/mm.h>
-#include <asm/io.h>
-#include <asm/bios_ebda.h>
-
-/*
- * APIC driver for the IBM "Summit" chipset.
- */
-#include <linux/threads.h>
-#include <linux/cpumask.h>
-#include <asm/mpspec.h>
-#include <asm/apic.h>
-#include <asm/smp.h>
-#include <asm/fixmap.h>
-#include <asm/apicdef.h>
-#include <asm/ipi.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/gfp.h>
-#include <linux/smp.h>
-
-static unsigned summit_get_apic_id(unsigned long x)
-{
- return (x >> 24) & 0xFF;
-}
-
-static inline void summit_send_IPI_mask(const struct cpumask *mask, int vector)
-{
- default_send_IPI_mask_sequence_logical(mask, vector);
-}
-
-static void summit_send_IPI_allbutself(int vector)
-{
- default_send_IPI_mask_allbutself_logical(cpu_online_mask, vector);
-}
-
-static void summit_send_IPI_all(int vector)
-{
- summit_send_IPI_mask(cpu_online_mask, vector);
-}
-
-#include <asm/tsc.h>
-
-extern int use_cyclone;
-
-#ifdef CONFIG_X86_SUMMIT_NUMA
-static void setup_summit(void);
-#else
-static inline void setup_summit(void) {}
-#endif
-
-static int summit_mps_oem_check(struct mpc_table *mpc, char *oem,
- char *productid)
-{
- if (!strncmp(oem, "IBM ENSW", 8) &&
- (!strncmp(productid, "VIGIL SMP", 9)
- || !strncmp(productid, "EXA", 3)
- || !strncmp(productid, "RUTHLESS SMP", 12))){
- mark_tsc_unstable("Summit based system");
- use_cyclone = 1; /*enable cyclone-timer*/
- setup_summit();
- return 1;
- }
- return 0;
-}
-
-/* Hook from generic ACPI tables.c */
-static int summit_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
-{
- if (!strncmp(oem_id, "IBM", 3) &&
- (!strncmp(oem_table_id, "SERVIGIL", 8)
- || !strncmp(oem_table_id, "EXA", 3))){
- mark_tsc_unstable("Summit based system");
- use_cyclone = 1; /*enable cyclone-timer*/
- setup_summit();
- return 1;
- }
- return 0;
-}
-
-struct rio_table_hdr {
- unsigned char version; /* Version number of this data structure */
- /* Version 3 adds chassis_num & WP_index */
- unsigned char num_scal_dev; /* # of Scalability devices (Twisters for Vigil) */
- unsigned char num_rio_dev; /* # of RIO I/O devices (Cyclones and Winnipegs) */
-} __attribute__((packed));
-
-struct scal_detail {
- unsigned char node_id; /* Scalability Node ID */
- unsigned long CBAR; /* Address of 1MB register space */
- unsigned char port0node; /* Node ID port connected to: 0xFF=None */
- unsigned char port0port; /* Port num port connected to: 0,1,2, or 0xFF=None */
- unsigned char port1node; /* Node ID port connected to: 0xFF = None */
- unsigned char port1port; /* Port num port connected to: 0,1,2, or 0xFF=None */
- unsigned char port2node; /* Node ID port connected to: 0xFF = None */
- unsigned char port2port; /* Port num port connected to: 0,1,2, or 0xFF=None */
- unsigned char chassis_num; /* 1 based Chassis number (1 = boot node) */
-} __attribute__((packed));
-
-struct rio_detail {
- unsigned char node_id; /* RIO Node ID */
- unsigned long BBAR; /* Address of 1MB register space */
- unsigned char type; /* Type of device */
- unsigned char owner_id; /* For WPEG: Node ID of Cyclone that owns this WPEG*/
- /* For CYC: Node ID of Twister that owns this CYC */
- unsigned char port0node; /* Node ID port connected to: 0xFF=None */
- unsigned char port0port; /* Port num port connected to: 0,1,2, or 0xFF=None */
- unsigned char port1node; /* Node ID port connected to: 0xFF=None */
- unsigned char port1port; /* Port num port connected to: 0,1,2, or 0xFF=None */
- unsigned char first_slot; /* For WPEG: Lowest slot number below this WPEG */
- /* For CYC: 0 */
- unsigned char status; /* For WPEG: Bit 0 = 1 : the XAPIC is used */
- /* = 0 : the XAPIC is not used, ie:*/
- /* ints fwded to another XAPIC */
- /* Bits1:7 Reserved */
- /* For CYC: Bits0:7 Reserved */
- unsigned char WP_index; /* For WPEG: WPEG instance index - lower ones have */
- /* lower slot numbers/PCI bus numbers */
- /* For CYC: No meaning */
- unsigned char chassis_num; /* 1 based Chassis number */
- /* For LookOut WPEGs this field indicates the */
- /* Expansion Chassis #, enumerated from Boot */
- /* Node WPEG external port, then Boot Node CYC */
- /* external port, then Next Vigil chassis WPEG */
- /* external port, etc. */
- /* Shared Lookouts have only 1 chassis number (the */
- /* first one assigned) */
-} __attribute__((packed));
-
-
-typedef enum {
- CompatTwister = 0, /* Compatibility Twister */
- AltTwister = 1, /* Alternate Twister of internal 8-way */
- CompatCyclone = 2, /* Compatibility Cyclone */
- AltCyclone = 3, /* Alternate Cyclone of internal 8-way */
- CompatWPEG = 4, /* Compatibility WPEG */
- AltWPEG = 5, /* Second Planar WPEG */
- LookOutAWPEG = 6, /* LookOut WPEG */
- LookOutBWPEG = 7, /* LookOut WPEG */
-} node_type;
-
-static inline int is_WPEG(struct rio_detail *rio){
- return (rio->type == CompatWPEG || rio->type == AltWPEG ||
- rio->type == LookOutAWPEG || rio->type == LookOutBWPEG);
-}
-
-#define SUMMIT_APIC_DFR_VALUE (APIC_DFR_CLUSTER)
-
-static const struct cpumask *summit_target_cpus(void)
-{
- /* CPU_MASK_ALL (0xff) has undefined behaviour with
- * dest_LowestPrio mode logical clustered apic interrupt routing
- * Just start on cpu 0. IRQ balancing will spread load
- */
- return cpumask_of(0);
-}
-
-static unsigned long summit_check_apicid_used(physid_mask_t *map, int apicid)
-{
- return 0;
-}
-
-/* we don't use the phys_cpu_present_map to indicate apicid presence */
-static unsigned long summit_check_apicid_present(int bit)
-{
- return 1;
-}
-
-static int summit_early_logical_apicid(int cpu)
-{
- int count = 0;
- u8 my_id = early_per_cpu(x86_cpu_to_apicid, cpu);
- u8 my_cluster = APIC_CLUSTER(my_id);
-#ifdef CONFIG_SMP
- u8 lid;
- int i;
-
- /* Create logical APIC IDs by counting CPUs already in cluster. */
- for (count = 0, i = nr_cpu_ids; --i >= 0; ) {
- lid = early_per_cpu(x86_cpu_to_logical_apicid, i);
- if (lid != BAD_APICID && APIC_CLUSTER(lid) == my_cluster)
- ++count;
- }
-#endif
- /* We only have a 4 wide bitmap in cluster mode. If a deranged
- * BIOS puts 5 CPUs in one APIC cluster, we're hosed. */
- BUG_ON(count >= XAPIC_DEST_CPUS_SHIFT);
- return my_cluster | (1UL << count);
-}
-
-static void summit_init_apic_ldr(void)
-{
- int cpu = smp_processor_id();
- unsigned long id = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
- unsigned long val;
-
- apic_write(APIC_DFR, SUMMIT_APIC_DFR_VALUE);
- val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
- val |= SET_APIC_LOGICAL_ID(id);
- apic_write(APIC_LDR, val);
-}
-
-static int summit_apic_id_registered(void)
-{
- return 1;
-}
-
-static void summit_setup_apic_routing(void)
-{
- pr_info("Enabling APIC mode: Summit. Using %d I/O APICs\n",
- nr_ioapics);
-}
-
-static int summit_cpu_present_to_apicid(int mps_cpu)
-{
- if (mps_cpu < nr_cpu_ids)
- return (int)per_cpu(x86_bios_cpu_apicid, mps_cpu);
- else
- return BAD_APICID;
-}
-
-static void summit_ioapic_phys_id_map(physid_mask_t *phys_id_map, physid_mask_t *retmap)
-{
- /* For clustered we don't have a good way to do this yet - hack */
- physids_promote(0x0FL, retmap);
-}
-
-static void summit_apicid_to_cpu_present(int apicid, physid_mask_t *retmap)
-{
- physid_set_mask_of_physid(0, retmap);
-}
-
-static int summit_check_phys_apicid_present(int physical_apicid)
-{
- return 1;
-}
-
-static inline int
-summit_cpu_mask_to_apicid(const struct cpumask *cpumask, unsigned int *dest_id)
-{
- unsigned int round = 0;
- unsigned int cpu, apicid = 0;
-
- /*
- * The cpus in the mask must all be on the apic cluster.
- */
- for_each_cpu_and(cpu, cpumask, cpu_online_mask) {
- int new_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
-
- if (round && APIC_CLUSTER(apicid) != APIC_CLUSTER(new_apicid)) {
- pr_err("Not a valid mask!\n");
- return -EINVAL;
- }
- apicid |= new_apicid;
- round++;
- }
- if (!round)
- return -EINVAL;
- *dest_id = apicid;
- return 0;
-}
-
-static int
-summit_cpu_mask_to_apicid_and(const struct cpumask *inmask,
- const struct cpumask *andmask,
- unsigned int *apicid)
-{
- cpumask_var_t cpumask;
- *apicid = early_per_cpu(x86_cpu_to_logical_apicid, 0);
-
- if (!alloc_cpumask_var(&cpumask, GFP_ATOMIC))
- return 0;
-
- cpumask_and(cpumask, inmask, andmask);
- summit_cpu_mask_to_apicid(cpumask, apicid);
-
- free_cpumask_var(cpumask);
-
- return 0;
-}
-
-/*
- * cpuid returns the value latched in the HW at reset, not the APIC ID
- * register's value. For any box whose BIOS changes APIC IDs, like
- * clustered APIC systems, we must use hard_smp_processor_id.
- *
- * See Intel's IA-32 SW Dev's Manual Vol2 under CPUID.
- */
-static int summit_phys_pkg_id(int cpuid_apic, int index_msb)
-{
- return hard_smp_processor_id() >> index_msb;
-}
-
-static int probe_summit(void)
-{
- /* probed later in mptable/ACPI hooks */
- return 0;
-}
-
-#ifdef CONFIG_X86_SUMMIT_NUMA
-static struct rio_table_hdr *rio_table_hdr;
-static struct scal_detail *scal_devs[MAX_NUMNODES];
-static struct rio_detail *rio_devs[MAX_NUMNODES*4];
-
-#ifndef CONFIG_X86_NUMAQ
-static int mp_bus_id_to_node[MAX_MP_BUSSES];
-#endif
-
-static int setup_pci_node_map_for_wpeg(int wpeg_num, int last_bus)
-{
- int twister = 0, node = 0;
- int i, bus, num_buses;
-
- for (i = 0; i < rio_table_hdr->num_rio_dev; i++) {
- if (rio_devs[i]->node_id == rio_devs[wpeg_num]->owner_id) {
- twister = rio_devs[i]->owner_id;
- break;
- }
- }
- if (i == rio_table_hdr->num_rio_dev) {
- pr_err("Couldn't find owner Cyclone for Winnipeg!\n");
- return last_bus;
- }
-
- for (i = 0; i < rio_table_hdr->num_scal_dev; i++) {
- if (scal_devs[i]->node_id == twister) {
- node = scal_devs[i]->node_id;
- break;
- }
- }
- if (i == rio_table_hdr->num_scal_dev) {
- pr_err("Couldn't find owner Twister for Cyclone!\n");
- return last_bus;
- }
-
- switch (rio_devs[wpeg_num]->type) {
- case CompatWPEG:
- /*
- * The Compatibility Winnipeg controls the 2 legacy buses,
- * the 66MHz PCI bus [2 slots] and the 2 "extra" buses in case
- * a PCI-PCI bridge card is used in either slot: total 5 buses.
- */
- num_buses = 5;
- break;
- case AltWPEG:
- /*
- * The Alternate Winnipeg controls the 2 133MHz buses [1 slot
- * each], their 2 "extra" buses, the 100MHz bus [2 slots] and
- * the "extra" buses for each of those slots: total 7 buses.
- */
- num_buses = 7;
- break;
- case LookOutAWPEG:
- case LookOutBWPEG:
- /*
- * A Lookout Winnipeg controls 3 100MHz buses [2 slots each]
- * & the "extra" buses for each of those slots: total 9 buses.
- */
- num_buses = 9;
- break;
- default:
- pr_info("Unsupported Winnipeg type!\n");
- return last_bus;
- }
-
- for (bus = last_bus; bus < last_bus + num_buses; bus++)
- mp_bus_id_to_node[bus] = node;
- return bus;
-}
-
-static int build_detail_arrays(void)
-{
- unsigned long ptr;
- int i, scal_detail_size, rio_detail_size;
-
- if (rio_table_hdr->num_scal_dev > MAX_NUMNODES) {
- pr_warn("MAX_NUMNODES too low! Defined as %d, but system has %d nodes\n",
- MAX_NUMNODES, rio_table_hdr->num_scal_dev);
- return 0;
- }
-
- switch (rio_table_hdr->version) {
- default:
- pr_warn("Invalid Rio Grande Table Version: %d\n",
- rio_table_hdr->version);
- return 0;
- case 2:
- scal_detail_size = 11;
- rio_detail_size = 13;
- break;
- case 3:
- scal_detail_size = 12;
- rio_detail_size = 15;
- break;
- }
-
- ptr = (unsigned long)rio_table_hdr + 3;
- for (i = 0; i < rio_table_hdr->num_scal_dev; i++, ptr += scal_detail_size)
- scal_devs[i] = (struct scal_detail *)ptr;
-
- for (i = 0; i < rio_table_hdr->num_rio_dev; i++, ptr += rio_detail_size)
- rio_devs[i] = (struct rio_detail *)ptr;
-
- return 1;
-}
-
-void setup_summit(void)
-{
- unsigned long ptr;
- unsigned short offset;
- int i, next_wpeg, next_bus = 0;
-
- /* The pointer to the EBDA is stored in the word @ phys 0x40E(40:0E) */
- ptr = get_bios_ebda();
- ptr = (unsigned long)phys_to_virt(ptr);
-
- rio_table_hdr = NULL;
- offset = 0x180;
- while (offset) {
- /* The block id is stored in the 2nd word */
- if (*((unsigned short *)(ptr + offset + 2)) == 0x4752) {
- /* set the pointer past the offset & block id */
- rio_table_hdr = (struct rio_table_hdr *)(ptr + offset + 4);
- break;
- }
- /* The next offset is stored in the 1st word. 0 means no more */
- offset = *((unsigned short *)(ptr + offset));
- }
- if (!rio_table_hdr) {
- pr_err("Unable to locate Rio Grande Table in EBDA - bailing!\n");
- return;
- }
-
- if (!build_detail_arrays())
- return;
-
- /* The first Winnipeg we're looking for has an index of 0 */
- next_wpeg = 0;
- do {
- for (i = 0; i < rio_table_hdr->num_rio_dev; i++) {
- if (is_WPEG(rio_devs[i]) && rio_devs[i]->WP_index == next_wpeg) {
- /* It's the Winnipeg we're looking for! */
- next_bus = setup_pci_node_map_for_wpeg(i, next_bus);
- next_wpeg++;
- break;
- }
- }
- /*
- * If we go through all Rio devices and don't find one with
- * the next index, it means we've found all the Winnipegs,
- * and thus all the PCI buses.
- */
- if (i == rio_table_hdr->num_rio_dev)
- next_wpeg = 0;
- } while (next_wpeg != 0);
-}
-#endif
-
-static struct apic apic_summit = {
-
- .name = "summit",
- .probe = probe_summit,
- .acpi_madt_oem_check = summit_acpi_madt_oem_check,
- .apic_id_valid = default_apic_id_valid,
- .apic_id_registered = summit_apic_id_registered,
-
- .irq_delivery_mode = dest_LowestPrio,
- /* logical delivery broadcast to all CPUs: */
- .irq_dest_mode = 1,
-
- .target_cpus = summit_target_cpus,
- .disable_esr = 1,
- .dest_logical = APIC_DEST_LOGICAL,
- .check_apicid_used = summit_check_apicid_used,
- .check_apicid_present = summit_check_apicid_present,
-
- .vector_allocation_domain = flat_vector_allocation_domain,
- .init_apic_ldr = summit_init_apic_ldr,
-
- .ioapic_phys_id_map = summit_ioapic_phys_id_map,
- .setup_apic_routing = summit_setup_apic_routing,
- .multi_timer_check = NULL,
- .cpu_present_to_apicid = summit_cpu_present_to_apicid,
- .apicid_to_cpu_present = summit_apicid_to_cpu_present,
- .setup_portio_remap = NULL,
- .check_phys_apicid_present = summit_check_phys_apicid_present,
- .enable_apic_mode = NULL,
- .phys_pkg_id = summit_phys_pkg_id,
- .mps_oem_check = summit_mps_oem_check,
-
- .get_apic_id = summit_get_apic_id,
- .set_apic_id = NULL,
- .apic_id_mask = 0xFF << 24,
-
- .cpu_mask_to_apicid_and = summit_cpu_mask_to_apicid_and,
-
- .send_IPI_mask = summit_send_IPI_mask,
- .send_IPI_mask_allbutself = NULL,
- .send_IPI_allbutself = summit_send_IPI_allbutself,
- .send_IPI_all = summit_send_IPI_all,
- .send_IPI_self = default_send_IPI_self,
-
- .trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
- .trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
-
- .wait_for_init_deassert = default_wait_for_init_deassert,
-
- .smp_callin_clear_local_apic = NULL,
- .inquire_remote_apic = default_inquire_remote_apic,
-
- .read = native_apic_mem_read,
- .write = native_apic_mem_write,
- .eoi_write = native_apic_mem_write,
- .icr_read = native_apic_icr_read,
- .icr_write = native_apic_icr_write,
- .wait_icr_idle = native_apic_wait_icr_idle,
- .safe_wait_icr_idle = native_safe_apic_wait_icr_idle,
-
- .x86_32_early_logical_apicid = summit_early_logical_apicid,
-};
-
-apic_driver(apic_summit);
diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c
index cac85ee6913f..e66766bf1641 100644
--- a/arch/x86/kernel/apic/x2apic_cluster.c
+++ b/arch/x86/kernel/apic/x2apic_cluster.c
@@ -279,7 +279,7 @@ static struct apic apic_x2apic_cluster = {
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
- .wait_for_init_deassert = NULL,
+ .wait_for_init_deassert = false,
.smp_callin_clear_local_apic = NULL,
.inquire_remote_apic = NULL,
diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c
index de231e328cae..6d600ebf6c12 100644
--- a/arch/x86/kernel/apic/x2apic_phys.c
+++ b/arch/x86/kernel/apic/x2apic_phys.c
@@ -133,7 +133,7 @@ static struct apic apic_x2apic_phys = {
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
- .wait_for_init_deassert = NULL,
+ .wait_for_init_deassert = false,
.smp_callin_clear_local_apic = NULL,
.inquire_remote_apic = NULL,
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index d263b1307de1..7834389ba5be 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -396,7 +396,7 @@ static struct apic __refdata apic_x2apic_uv_x = {
.wakeup_secondary_cpu = uv_wakeup_secondary,
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
- .wait_for_init_deassert = NULL,
+ .wait_for_init_deassert = false,
.smp_callin_clear_local_apic = NULL,
.inquire_remote_apic = NULL,
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index c67ffa686064..ce8b8ff0e0ef 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -218,7 +218,7 @@ static void amd_k7_smp_check(struct cpuinfo_x86 *c)
*/
WARN_ONCE(1, "WARNING: This combination of AMD"
" processors is not suitable for SMP.\n");
- add_taint(TAINT_UNSAFE_SMP, LOCKDEP_NOW_UNRELIABLE);
+ add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_NOW_UNRELIABLE);
}
static void init_amd_k7(struct cpuinfo_x86 *c)
@@ -233,9 +233,7 @@ static void init_amd_k7(struct cpuinfo_x86 *c)
if (c->x86_model >= 6 && c->x86_model <= 10) {
if (!cpu_has(c, X86_FEATURE_XMM)) {
printk(KERN_INFO "Enabling disabled K7/SSE Support.\n");
- rdmsr(MSR_K7_HWCR, l, h);
- l &= ~0x00008000;
- wrmsr(MSR_K7_HWCR, l, h);
+ msr_clear_bit(MSR_K7_HWCR, 15);
set_cpu_cap(c, X86_FEATURE_XMM);
}
}
@@ -509,14 +507,8 @@ static void early_init_amd(struct cpuinfo_x86 *c)
#endif
/* F16h erratum 793, CVE-2013-6885 */
- if (c->x86 == 0x16 && c->x86_model <= 0xf) {
- u64 val;
-
- rdmsrl(MSR_AMD64_LS_CFG, val);
- if (!(val & BIT(15)))
- wrmsrl(MSR_AMD64_LS_CFG, val | BIT(15));
- }
-
+ if (c->x86 == 0x16 && c->x86_model <= 0xf)
+ msr_set_bit(MSR_AMD64_LS_CFG, 15);
}
static const int amd_erratum_383[];
@@ -536,11 +528,8 @@ static void init_amd(struct cpuinfo_x86 *c)
* Errata 63 for SH-B3 steppings
* Errata 122 for all steppings (F+ have it disabled by default)
*/
- if (c->x86 == 0xf) {
- rdmsrl(MSR_K7_HWCR, value);
- value |= 1 << 6;
- wrmsrl(MSR_K7_HWCR, value);
- }
+ if (c->x86 == 0xf)
+ msr_set_bit(MSR_K7_HWCR, 6);
#endif
early_init_amd(c);
@@ -623,14 +612,11 @@ static void init_amd(struct cpuinfo_x86 *c)
(c->x86_model >= 0x10) && (c->x86_model <= 0x1f) &&
!cpu_has(c, X86_FEATURE_TOPOEXT)) {
- if (!rdmsrl_safe(0xc0011005, &value)) {
- value |= 1ULL << 54;
- wrmsrl_safe(0xc0011005, value);
+ if (msr_set_bit(0xc0011005, 54) > 0) {
rdmsrl(0xc0011005, value);
- if (value & (1ULL << 54)) {
+ if (value & BIT_64(54)) {
set_cpu_cap(c, X86_FEATURE_TOPOEXT);
- printk(KERN_INFO FW_INFO "CPU: Re-enabling "
- "disabled Topology Extensions Support\n");
+ pr_info(FW_INFO "CPU: Re-enabling disabled Topology Extensions Support.\n");
}
}
}
@@ -709,19 +695,12 @@ static void init_amd(struct cpuinfo_x86 *c)
* Disable GART TLB Walk Errors on Fam10h. We do this here
* because this is always needed when GART is enabled, even in a
* kernel which has no MCE support built in.
- * BIOS should disable GartTlbWlk Errors themself. If
- * it doesn't do it here as suggested by the BKDG.
+ * BIOS should disable GartTlbWlk Errors already. If
+ * it doesn't, do it here as suggested by the BKDG.
*
* Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=33012
*/
- u64 mask;
- int err;
-
- err = rdmsrl_safe(MSR_AMD64_MCx_MASK(4), &mask);
- if (err == 0) {
- mask |= (1 << 10);
- wrmsrl_safe(MSR_AMD64_MCx_MASK(4), mask);
- }
+ msr_set_bit(MSR_AMD64_MCx_MASK(4), 10);
/*
* On family 10h BIOS may not have properly enabled WC+ support,
@@ -733,10 +712,7 @@ static void init_amd(struct cpuinfo_x86 *c)
* NOTE: we want to use the _safe accessors so as not to #GP kvm
* guests on older kvm hosts.
*/
-
- rdmsrl_safe(MSR_AMD64_BU_CFG2, &value);
- value &= ~(1ULL << 24);
- wrmsrl_safe(MSR_AMD64_BU_CFG2, value);
+ msr_clear_bit(MSR_AMD64_BU_CFG2, 24);
if (cpu_has_amd_erratum(c, amd_erratum_383))
set_cpu_bug(c, X86_BUG_AMD_TLB_MMATCH);
diff --git a/arch/x86/kernel/cpu/centaur.c b/arch/x86/kernel/cpu/centaur.c
index 8779edab684e..d8fba5c15fbd 100644
--- a/arch/x86/kernel/cpu/centaur.c
+++ b/arch/x86/kernel/cpu/centaur.c
@@ -8,236 +8,6 @@
#include "cpu.h"
-#ifdef CONFIG_X86_OOSTORE
-
-static u32 power2(u32 x)
-{
- u32 s = 1;
-
- while (s <= x)
- s <<= 1;
-
- return s >>= 1;
-}
-
-
-/*
- * Set up an actual MCR
- */
-static void centaur_mcr_insert(int reg, u32 base, u32 size, int key)
-{
- u32 lo, hi;
-
- hi = base & ~0xFFF;
- lo = ~(size-1); /* Size is a power of 2 so this makes a mask */
- lo &= ~0xFFF; /* Remove the ctrl value bits */
- lo |= key; /* Attribute we wish to set */
- wrmsr(reg+MSR_IDT_MCR0, lo, hi);
- mtrr_centaur_report_mcr(reg, lo, hi); /* Tell the mtrr driver */
-}
-
-/*
- * Figure what we can cover with MCR's
- *
- * Shortcut: We know you can't put 4Gig of RAM on a winchip
- */
-static u32 ramtop(void)
-{
- u32 clip = 0xFFFFFFFFUL;
- u32 top = 0;
- int i;
-
- for (i = 0; i < e820.nr_map; i++) {
- unsigned long start, end;
-
- if (e820.map[i].addr > 0xFFFFFFFFUL)
- continue;
- /*
- * Don't MCR over reserved space. Ignore the ISA hole
- * we frob around that catastrophe already
- */
- if (e820.map[i].type == E820_RESERVED) {
- if (e820.map[i].addr >= 0x100000UL &&
- e820.map[i].addr < clip)
- clip = e820.map[i].addr;
- continue;
- }
- start = e820.map[i].addr;
- end = e820.map[i].addr + e820.map[i].size;
- if (start >= end)
- continue;
- if (end > top)
- top = end;
- }
- /*
- * Everything below 'top' should be RAM except for the ISA hole.
- * Because of the limited MCR's we want to map NV/ACPI into our
- * MCR range for gunk in RAM
- *
- * Clip might cause us to MCR insufficient RAM but that is an
- * acceptable failure mode and should only bite obscure boxes with
- * a VESA hole at 15Mb
- *
- * The second case Clip sometimes kicks in is when the EBDA is marked
- * as reserved. Again we fail safe with reasonable results
- */
- if (top > clip)
- top = clip;
-
- return top;
-}
-
-/*
- * Compute a set of MCR's to give maximum coverage
- */
-static int centaur_mcr_compute(int nr, int key)
-{
- u32 mem = ramtop();
- u32 root = power2(mem);
- u32 base = root;
- u32 top = root;
- u32 floor = 0;
- int ct = 0;
-
- while (ct < nr) {
- u32 fspace = 0;
- u32 high;
- u32 low;
-
- /*
- * Find the largest block we will fill going upwards
- */
- high = power2(mem-top);
-
- /*
- * Find the largest block we will fill going downwards
- */
- low = base/2;
-
- /*
- * Don't fill below 1Mb going downwards as there
- * is an ISA hole in the way.
- */
- if (base <= 1024*1024)
- low = 0;
-
- /*
- * See how much space we could cover by filling below
- * the ISA hole
- */
-
- if (floor == 0)
- fspace = 512*1024;
- else if (floor == 512*1024)
- fspace = 128*1024;
-
- /* And forget ROM space */
-
- /*
- * Now install the largest coverage we get
- */
- if (fspace > high && fspace > low) {
- centaur_mcr_insert(ct, floor, fspace, key);
- floor += fspace;
- } else if (high > low) {
- centaur_mcr_insert(ct, top, high, key);
- top += high;
- } else if (low > 0) {
- base -= low;
- centaur_mcr_insert(ct, base, low, key);
- } else
- break;
- ct++;
- }
- /*
- * We loaded ct values. We now need to set the mask. The caller
- * must do this bit.
- */
- return ct;
-}
-
-static void centaur_create_optimal_mcr(void)
-{
- int used;
- int i;
-
- /*
- * Allocate up to 6 mcrs to mark as much of ram as possible
- * as write combining and weak write ordered.
- *
- * To experiment with: Linux never uses stack operations for
- * mmio spaces so we could globally enable stack operation wc
- *
- * Load the registers with type 31 - full write combining, all
- * writes weakly ordered.
- */
- used = centaur_mcr_compute(6, 31);
-
- /*
- * Wipe unused MCRs
- */
- for (i = used; i < 8; i++)
- wrmsr(MSR_IDT_MCR0+i, 0, 0);
-}
-
-static void winchip2_create_optimal_mcr(void)
-{
- u32 lo, hi;
- int used;
- int i;
-
- /*
- * Allocate up to 6 mcrs to mark as much of ram as possible
- * as write combining, weak store ordered.
- *
- * Load the registers with type 25
- * 8 - weak write ordering
- * 16 - weak read ordering
- * 1 - write combining
- */
- used = centaur_mcr_compute(6, 25);
-
- /*
- * Mark the registers we are using.
- */
- rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
- for (i = 0; i < used; i++)
- lo |= 1<<(9+i);
- wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-
- /*
- * Wipe unused MCRs
- */
-
- for (i = used; i < 8; i++)
- wrmsr(MSR_IDT_MCR0+i, 0, 0);
-}
-
-/*
- * Handle the MCR key on the Winchip 2.
- */
-static void winchip2_unprotect_mcr(void)
-{
- u32 lo, hi;
- u32 key;
-
- rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
- lo &= ~0x1C0; /* blank bits 8-6 */
- key = (lo>>17) & 7;
- lo |= key<<6; /* replace with unlock key */
- wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-}
-
-static void winchip2_protect_mcr(void)
-{
- u32 lo, hi;
-
- rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
- lo &= ~0x1C0; /* blank bits 8-6 */
- wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-}
-#endif /* CONFIG_X86_OOSTORE */
-
#define ACE_PRESENT (1 << 6)
#define ACE_ENABLED (1 << 7)
#define ACE_FCR (1 << 28) /* MSR_VIA_FCR */
@@ -362,20 +132,6 @@ static void init_centaur(struct cpuinfo_x86 *c)
fcr_clr = DPDC;
printk(KERN_NOTICE "Disabling bugged TSC.\n");
clear_cpu_cap(c, X86_FEATURE_TSC);
-#ifdef CONFIG_X86_OOSTORE
- centaur_create_optimal_mcr();
- /*
- * Enable:
- * write combining on non-stack, non-string
- * write combining on string, all types
- * weak write ordering
- *
- * The C6 original lacks weak read order
- *
- * Note 0x120 is write only on Winchip 1
- */
- wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0);
-#endif
break;
case 8:
switch (c->x86_mask) {
@@ -392,40 +148,12 @@ static void init_centaur(struct cpuinfo_x86 *c)
fcr_set = ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|
E2MMX|EAMD3D;
fcr_clr = DPDC;
-#ifdef CONFIG_X86_OOSTORE
- winchip2_unprotect_mcr();
- winchip2_create_optimal_mcr();
- rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
- /*
- * Enable:
- * write combining on non-stack, non-string
- * write combining on string, all types
- * weak write ordering
- */
- lo |= 31;
- wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
- winchip2_protect_mcr();
-#endif
break;
case 9:
name = "3";
fcr_set = ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|
E2MMX|EAMD3D;
fcr_clr = DPDC;
-#ifdef CONFIG_X86_OOSTORE
- winchip2_unprotect_mcr();
- winchip2_create_optimal_mcr();
- rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
- /*
- * Enable:
- * write combining on non-stack, non-string
- * write combining on string, all types
- * weak write ordering
- */
- lo |= 31;
- wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
- winchip2_protect_mcr();
-#endif
break;
default:
name = "??";
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 24b6fd10625a..a135239badb7 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -284,8 +284,13 @@ static __always_inline void setup_smap(struct cpuinfo_x86 *c)
raw_local_save_flags(eflags);
BUG_ON(eflags & X86_EFLAGS_AC);
- if (cpu_has(c, X86_FEATURE_SMAP))
+ if (cpu_has(c, X86_FEATURE_SMAP)) {
+#ifdef CONFIG_X86_SMAP
set_in_cr4(X86_CR4_SMAP);
+#else
+ clear_in_cr4(X86_CR4_SMAP);
+#endif
+ }
}
/*
@@ -1020,7 +1025,8 @@ __setup("show_msr=", setup_show_msr);
static __init int setup_noclflush(char *arg)
{
- setup_clear_cpu_cap(X86_FEATURE_CLFLSH);
+ setup_clear_cpu_cap(X86_FEATURE_CLFLUSH);
+ setup_clear_cpu_cap(X86_FEATURE_CLFLUSHOPT);
return 1;
}
__setup("noclflush", setup_noclflush);
@@ -1073,6 +1079,10 @@ static __init int setup_disablecpuid(char *arg)
}
__setup("clearcpuid=", setup_disablecpuid);
+DEFINE_PER_CPU(unsigned long, kernel_stack) =
+ (unsigned long)&init_thread_union - KERNEL_STACK_OFFSET + THREAD_SIZE;
+EXPORT_PER_CPU_SYMBOL(kernel_stack);
+
#ifdef CONFIG_X86_64
struct desc_ptr idt_descr = { NR_VECTORS * 16 - 1, (unsigned long) idt_table };
struct desc_ptr debug_idt_descr = { NR_VECTORS * 16 - 1,
@@ -1089,10 +1099,6 @@ DEFINE_PER_CPU(struct task_struct *, current_task) ____cacheline_aligned =
&init_task;
EXPORT_PER_CPU_SYMBOL(current_task);
-DEFINE_PER_CPU(unsigned long, kernel_stack) =
- (unsigned long)&init_thread_union - KERNEL_STACK_OFFSET + THREAD_SIZE;
-EXPORT_PER_CPU_SYMBOL(kernel_stack);
-
DEFINE_PER_CPU(char *, irq_stack_ptr) =
init_per_cpu_var(irq_stack_union.irq_stack) + IRQ_STACK_SIZE - 64;
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index 5cd9bfabd645..a80029035bf2 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -31,11 +31,8 @@ static void early_init_intel(struct cpuinfo_x86 *c)
/* Unmask CPUID levels if masked: */
if (c->x86 > 6 || (c->x86 == 6 && c->x86_model >= 0xd)) {
- rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
-
- if (misc_enable & MSR_IA32_MISC_ENABLE_LIMIT_CPUID) {
- misc_enable &= ~MSR_IA32_MISC_ENABLE_LIMIT_CPUID;
- wrmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
+ if (msr_clear_bit(MSR_IA32_MISC_ENABLE,
+ MSR_IA32_MISC_ENABLE_LIMIT_CPUID_BIT) > 0) {
c->cpuid_level = cpuid_eax(0);
get_cpu_cap(c);
}
@@ -129,16 +126,10 @@ static void early_init_intel(struct cpuinfo_x86 *c)
* Ingo Molnar reported a Pentium D (model 6) and a Xeon
* (model 2) with the same problem.
*/
- if (c->x86 == 15) {
- rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
-
- if (misc_enable & MSR_IA32_MISC_ENABLE_FAST_STRING) {
- printk(KERN_INFO "kmemcheck: Disabling fast string operations\n");
-
- misc_enable &= ~MSR_IA32_MISC_ENABLE_FAST_STRING;
- wrmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
- }
- }
+ if (c->x86 == 15)
+ if (msr_clear_bit(MSR_IA32_MISC_ENABLE,
+ MSR_IA32_MISC_ENABLE_FAST_STRING_BIT) > 0)
+ pr_info("kmemcheck: Disabling fast string operations\n");
#endif
/*
@@ -195,10 +186,16 @@ static void intel_smp_check(struct cpuinfo_x86 *c)
}
}
-static void intel_workarounds(struct cpuinfo_x86 *c)
+static int forcepae;
+static int __init forcepae_setup(char *__unused)
{
- unsigned long lo, hi;
+ forcepae = 1;
+ return 1;
+}
+__setup("forcepae", forcepae_setup);
+static void intel_workarounds(struct cpuinfo_x86 *c)
+{
#ifdef CONFIG_X86_F00F_BUG
/*
* All current models of Pentium and Pentium with MMX technology CPUs
@@ -225,16 +222,26 @@ static void intel_workarounds(struct cpuinfo_x86 *c)
clear_cpu_cap(c, X86_FEATURE_SEP);
/*
+ * PAE CPUID issue: many Pentium M report no PAE but may have a
+ * functionally usable PAE implementation.
+ * Forcefully enable PAE if kernel parameter "forcepae" is present.
+ */
+ if (forcepae) {
+ printk(KERN_WARNING "PAE forced!\n");
+ set_cpu_cap(c, X86_FEATURE_PAE);
+ add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_NOW_UNRELIABLE);
+ }
+
+ /*
* P4 Xeon errata 037 workaround.
* Hardware prefetcher may cause stale data to be loaded into the cache.
*/
if ((c->x86 == 15) && (c->x86_model == 1) && (c->x86_mask == 1)) {
- rdmsr(MSR_IA32_MISC_ENABLE, lo, hi);
- if ((lo & MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE) == 0) {
- printk (KERN_INFO "CPU: C0 stepping P4 Xeon detected.\n");
- printk (KERN_INFO "CPU: Disabling hardware prefetching (Errata 037)\n");
- lo |= MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE;
- wrmsr(MSR_IA32_MISC_ENABLE, lo, hi);
+ if (msr_set_bit(MSR_IA32_MISC_ENABLE,
+ MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE_BIT)
+ > 0) {
+ pr_info("CPU: C0 stepping P4 Xeon detected.\n");
+ pr_info("CPU: Disabling hardware prefetching (Errata 037)\n");
}
}
@@ -267,10 +274,6 @@ static void intel_workarounds(struct cpuinfo_x86 *c)
}
#endif
-#ifdef CONFIG_X86_NUMAQ
- numaq_tsc_disable();
-#endif
-
intel_smp_check(c);
}
#else
diff --git a/arch/x86/kernel/cpu/match.c b/arch/x86/kernel/cpu/match.c
index 36565373af87..afa9f0d487ea 100644
--- a/arch/x86/kernel/cpu/match.c
+++ b/arch/x86/kernel/cpu/match.c
@@ -47,45 +47,3 @@ const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match)
return NULL;
}
EXPORT_SYMBOL(x86_match_cpu);
-
-ssize_t arch_print_cpu_modalias(struct device *dev,
- struct device_attribute *attr,
- char *bufptr)
-{
- int size = PAGE_SIZE;
- int i, n;
- char *buf = bufptr;
-
- n = snprintf(buf, size, "x86cpu:vendor:%04X:family:%04X:"
- "model:%04X:feature:",
- boot_cpu_data.x86_vendor,
- boot_cpu_data.x86,
- boot_cpu_data.x86_model);
- size -= n;
- buf += n;
- size -= 1;
- for (i = 0; i < NCAPINTS*32; i++) {
- if (boot_cpu_has(i)) {
- n = snprintf(buf, size, ",%04X", i);
- if (n >= size) {
- WARN(1, "x86 features overflow page\n");
- break;
- }
- size -= n;
- buf += n;
- }
- }
- *buf++ = '\n';
- return buf - bufptr;
-}
-
-int arch_cpu_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
- char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
- if (buf) {
- arch_print_cpu_modalias(NULL, NULL, buf);
- add_uevent_var(env, "MODALIAS=%s", buf);
- kfree(buf);
- }
- return 0;
-}
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
index 9f7ca266864a..76f98fe5b35c 100644
--- a/arch/x86/kernel/cpu/mshyperv.c
+++ b/arch/x86/kernel/cpu/mshyperv.c
@@ -17,6 +17,7 @@
#include <linux/hardirq.h>
#include <linux/efi.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <asm/processor.h>
#include <asm/hypervisor.h>
#include <asm/hyperv.h>
@@ -26,10 +27,50 @@
#include <asm/irq_regs.h>
#include <asm/i8259.h>
#include <asm/apic.h>
+#include <asm/timer.h>
struct ms_hyperv_info ms_hyperv;
EXPORT_SYMBOL_GPL(ms_hyperv);
+#if IS_ENABLED(CONFIG_HYPERV)
+static void (*vmbus_handler)(void);
+
+void hyperv_vector_handler(struct pt_regs *regs)
+{
+ struct pt_regs *old_regs = set_irq_regs(regs);
+
+ irq_enter();
+ exit_idle();
+
+ inc_irq_stat(irq_hv_callback_count);
+ if (vmbus_handler)
+ vmbus_handler();
+
+ irq_exit();
+ set_irq_regs(old_regs);
+}
+
+void hv_setup_vmbus_irq(void (*handler)(void))
+{
+ vmbus_handler = handler;
+ /*
+ * Setup the IDT for hypervisor callback. Prevent reallocation
+ * at module reload.
+ */
+ if (!test_bit(HYPERVISOR_CALLBACK_VECTOR, used_vectors))
+ alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR,
+ hyperv_callback_vector);
+}
+
+void hv_remove_vmbus_irq(void)
+{
+ /* We have no way to deallocate the interrupt gate */
+ vmbus_handler = NULL;
+}
+EXPORT_SYMBOL_GPL(hv_setup_vmbus_irq);
+EXPORT_SYMBOL_GPL(hv_remove_vmbus_irq);
+#endif
+
static uint32_t __init ms_hyperv_platform(void)
{
u32 eax;
@@ -105,6 +146,11 @@ static void __init ms_hyperv_init_platform(void)
if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)
clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100);
+
+#ifdef CONFIG_X86_IO_APIC
+ no_timer_check = 1;
+#endif
+
}
const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
@@ -113,41 +159,3 @@ const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
.init_platform = ms_hyperv_init_platform,
};
EXPORT_SYMBOL(x86_hyper_ms_hyperv);
-
-#if IS_ENABLED(CONFIG_HYPERV)
-static int vmbus_irq = -1;
-static irq_handler_t vmbus_isr;
-
-void hv_register_vmbus_handler(int irq, irq_handler_t handler)
-{
- /*
- * Setup the IDT for hypervisor callback.
- */
- alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector);
-
- vmbus_irq = irq;
- vmbus_isr = handler;
-}
-
-void hyperv_vector_handler(struct pt_regs *regs)
-{
- struct pt_regs *old_regs = set_irq_regs(regs);
- struct irq_desc *desc;
-
- irq_enter();
- exit_idle();
-
- desc = irq_to_desc(vmbus_irq);
-
- if (desc)
- generic_handle_irq_desc(vmbus_irq, desc);
-
- irq_exit();
- set_irq_regs(old_regs);
-}
-#else
-void hv_register_vmbus_handler(int irq, irq_handler_t handler)
-{
-}
-#endif
-EXPORT_SYMBOL_GPL(hv_register_vmbus_handler);
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index b88645191fe5..ae407f7226c8 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -892,7 +892,6 @@ static void x86_pmu_enable(struct pmu *pmu)
* hw_perf_group_sched_in() or x86_pmu_enable()
*
* step1: save events moving to new counters
- * step2: reprogram moved events into new counters
*/
for (i = 0; i < n_running; i++) {
event = cpuc->event_list[i];
@@ -918,6 +917,9 @@ static void x86_pmu_enable(struct pmu *pmu)
x86_pmu_stop(event, PERF_EF_UPDATE);
}
+ /*
+ * step2: reprogram moved events into new counters
+ */
for (i = 0; i < cpuc->n_events; i++) {
event = cpuc->event_list[i];
hwc = &event->hw;
@@ -1043,7 +1045,7 @@ static int x86_pmu_add(struct perf_event *event, int flags)
/*
* If group events scheduling transaction was started,
* skip the schedulability test here, it will be performed
- * at commit time (->commit_txn) as a whole
+ * at commit time (->commit_txn) as a whole.
*/
if (cpuc->group_flag & PERF_EVENT_TXN)
goto done_collect;
@@ -1058,6 +1060,10 @@ static int x86_pmu_add(struct perf_event *event, int flags)
memcpy(cpuc->assign, assign, n*sizeof(int));
done_collect:
+ /*
+ * Commit the collect_events() state. See x86_pmu_del() and
+ * x86_pmu_*_txn().
+ */
cpuc->n_events = n;
cpuc->n_added += n - n0;
cpuc->n_txn += n - n0;
@@ -1183,25 +1189,38 @@ static void x86_pmu_del(struct perf_event *event, int flags)
* If we're called during a txn, we don't need to do anything.
* The events never got scheduled and ->cancel_txn will truncate
* the event_list.
+ *
+ * XXX assumes any ->del() called during a TXN will only be on
+ * an event added during that same TXN.
*/
if (cpuc->group_flag & PERF_EVENT_TXN)
return;
+ /*
+ * Not a TXN, therefore cleanup properly.
+ */
x86_pmu_stop(event, PERF_EF_UPDATE);
for (i = 0; i < cpuc->n_events; i++) {
- if (event == cpuc->event_list[i]) {
+ if (event == cpuc->event_list[i])
+ break;
+ }
- if (x86_pmu.put_event_constraints)
- x86_pmu.put_event_constraints(cpuc, event);
+ if (WARN_ON_ONCE(i == cpuc->n_events)) /* called ->del() without ->add() ? */
+ return;
- while (++i < cpuc->n_events)
- cpuc->event_list[i-1] = cpuc->event_list[i];
+ /* If we have a newly added event; make sure to decrease n_added. */
+ if (i >= cpuc->n_events - cpuc->n_added)
+ --cpuc->n_added;
+
+ if (x86_pmu.put_event_constraints)
+ x86_pmu.put_event_constraints(cpuc, event);
+
+ /* Delete the array entry. */
+ while (++i < cpuc->n_events)
+ cpuc->event_list[i-1] = cpuc->event_list[i];
+ --cpuc->n_events;
- --cpuc->n_events;
- break;
- }
- }
perf_event_update_userpage(event);
}
@@ -1521,6 +1540,8 @@ static int __init init_hw_perf_events(void)
pr_cont("%s PMU driver.\n", x86_pmu.name);
+ x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */
+
for (quirk = x86_pmu.quirks; quirk; quirk = quirk->next)
quirk->func();
@@ -1534,7 +1555,6 @@ static int __init init_hw_perf_events(void)
__EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_counters) - 1,
0, x86_pmu.num_counters, 0, 0);
- x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */
x86_pmu_format_group.attrs = x86_pmu.format_attrs;
if (x86_pmu.event_attrs)
@@ -1594,7 +1614,8 @@ static void x86_pmu_cancel_txn(struct pmu *pmu)
{
__this_cpu_and(cpu_hw_events.group_flag, ~PERF_EVENT_TXN);
/*
- * Truncate the collected events.
+ * Truncate collected array by the number of events added in this
+ * transaction. See x86_pmu_add() and x86_pmu_*_txn().
*/
__this_cpu_sub(cpu_hw_events.n_added, __this_cpu_read(cpu_hw_events.n_txn));
__this_cpu_sub(cpu_hw_events.n_events, __this_cpu_read(cpu_hw_events.n_txn));
@@ -1605,6 +1626,8 @@ static void x86_pmu_cancel_txn(struct pmu *pmu)
* Commit group events scheduling transaction
* Perform the group schedulability test as a whole
* Return 0 if success
+ *
+ * Does not cancel the transaction on failure; expects the caller to do this.
*/
static int x86_pmu_commit_txn(struct pmu *pmu)
{
@@ -1820,9 +1843,12 @@ static ssize_t set_attr_rdpmc(struct device *cdev,
if (ret)
return ret;
+ if (x86_pmu.attr_rdpmc_broken)
+ return -ENOTSUPP;
+
if (!!val != !!x86_pmu.attr_rdpmc) {
x86_pmu.attr_rdpmc = !!val;
- smp_call_function(change_rdpmc, (void *)val, 1);
+ on_each_cpu(change_rdpmc, (void *)val, 1);
}
return count;
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index c1a861829d81..3b2f9bdd974b 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -130,9 +130,11 @@ struct cpu_hw_events {
unsigned long running[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
int enabled;
- int n_events;
- int n_added;
- int n_txn;
+ int n_events; /* the # of events in the below arrays */
+ int n_added; /* the # last events in the below arrays;
+ they've never been enabled yet */
+ int n_txn; /* the # last events in the below arrays;
+ added in the current transaction */
int assign[X86_PMC_IDX_MAX]; /* event to counter assignment */
u64 tags[X86_PMC_IDX_MAX];
struct perf_event *event_list[X86_PMC_IDX_MAX]; /* in enabled order */
@@ -409,6 +411,7 @@ struct x86_pmu {
/*
* sysfs attrs
*/
+ int attr_rdpmc_broken;
int attr_rdpmc;
struct attribute **format_attrs;
struct attribute **event_attrs;
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index 0fa4f242f050..aa333d966886 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -1361,10 +1361,8 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)
intel_pmu_disable_all();
handled = intel_pmu_drain_bts_buffer();
status = intel_pmu_get_status();
- if (!status) {
- intel_pmu_enable_all(0);
- return handled;
- }
+ if (!status)
+ goto done;
loops = 0;
again:
@@ -2310,10 +2308,7 @@ __init int intel_pmu_init(void)
if (version > 1)
x86_pmu.num_counters_fixed = max((int)edx.split.num_counters_fixed, 3);
- /*
- * v2 and above have a perf capabilities MSR
- */
- if (version > 1) {
+ if (boot_cpu_has(X86_FEATURE_PDCM)) {
u64 capabilities;
rdmsrl(MSR_IA32_PERF_CAPABILITIES, capabilities);
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
index 29c248799ced..bd2253d40cff 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
@@ -66,6 +66,47 @@ DEFINE_UNCORE_FORMAT_ATTR(mask_vnw, mask_vnw, "config2:3-4");
DEFINE_UNCORE_FORMAT_ATTR(mask0, mask0, "config2:0-31");
DEFINE_UNCORE_FORMAT_ATTR(mask1, mask1, "config2:32-63");
+static void uncore_pmu_start_hrtimer(struct intel_uncore_box *box);
+static void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box);
+static void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *event);
+static void uncore_pmu_event_read(struct perf_event *event);
+
+static struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event)
+{
+ return container_of(event->pmu, struct intel_uncore_pmu, pmu);
+}
+
+static struct intel_uncore_box *
+uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
+{
+ struct intel_uncore_box *box;
+
+ box = *per_cpu_ptr(pmu->box, cpu);
+ if (box)
+ return box;
+
+ raw_spin_lock(&uncore_box_lock);
+ list_for_each_entry(box, &pmu->box_list, list) {
+ if (box->phys_id == topology_physical_package_id(cpu)) {
+ atomic_inc(&box->refcnt);
+ *per_cpu_ptr(pmu->box, cpu) = box;
+ break;
+ }
+ }
+ raw_spin_unlock(&uncore_box_lock);
+
+ return *per_cpu_ptr(pmu->box, cpu);
+}
+
+static struct intel_uncore_box *uncore_event_to_box(struct perf_event *event)
+{
+ /*
+ * perf core schedules event on the basis of cpu, uncore events are
+ * collected by one of the cpus inside a physical package.
+ */
+ return uncore_pmu_to_box(uncore_event_to_pmu(event), smp_processor_id());
+}
+
static u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event)
{
u64 count;
@@ -501,8 +542,11 @@ static struct extra_reg snbep_uncore_cbox_extra_regs[] = {
SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0x6),
SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0x6),
SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0x6),
SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0x6),
SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x8),
SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x8),
@@ -1178,10 +1222,15 @@ static struct extra_reg ivt_uncore_cbox_extra_regs[] = {
SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
SNBEP_CBO_EVENT_EXTRA_REG(0x1031, 0x10ff, 0x2),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x1134, 0xffff, 0x4),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0xc),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x5134, 0xffff, 0xc),
SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0xc),
SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0xc),
SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
- SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0xc),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0xc),
SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x10),
SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x10),
SNBEP_CBO_EVENT_EXTRA_REG(0x2135, 0xffff, 0x10),
@@ -1631,6 +1680,349 @@ static struct intel_uncore_type *snb_msr_uncores[] = {
&snb_uncore_cbox,
NULL,
};
+
+enum {
+ SNB_PCI_UNCORE_IMC,
+};
+
+static struct uncore_event_desc snb_uncore_imc_events[] = {
+ INTEL_UNCORE_EVENT_DESC(data_reads, "event=0x01"),
+ INTEL_UNCORE_EVENT_DESC(data_reads.scale, "6.103515625e-5"),
+ INTEL_UNCORE_EVENT_DESC(data_reads.unit, "MiB"),
+
+ INTEL_UNCORE_EVENT_DESC(data_writes, "event=0x02"),
+ INTEL_UNCORE_EVENT_DESC(data_writes.scale, "6.103515625e-5"),
+ INTEL_UNCORE_EVENT_DESC(data_writes.unit, "MiB"),
+
+ { /* end: all zeroes */ },
+};
+
+#define SNB_UNCORE_PCI_IMC_EVENT_MASK 0xff
+#define SNB_UNCORE_PCI_IMC_BAR_OFFSET 0x48
+
+/* page size multiple covering all config regs */
+#define SNB_UNCORE_PCI_IMC_MAP_SIZE 0x6000
+
+#define SNB_UNCORE_PCI_IMC_DATA_READS 0x1
+#define SNB_UNCORE_PCI_IMC_DATA_READS_BASE 0x5050
+#define SNB_UNCORE_PCI_IMC_DATA_WRITES 0x2
+#define SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE 0x5054
+#define SNB_UNCORE_PCI_IMC_CTR_BASE SNB_UNCORE_PCI_IMC_DATA_READS_BASE
+
+static struct attribute *snb_uncore_imc_formats_attr[] = {
+ &format_attr_event.attr,
+ NULL,
+};
+
+static struct attribute_group snb_uncore_imc_format_group = {
+ .name = "format",
+ .attrs = snb_uncore_imc_formats_attr,
+};
+
+static void snb_uncore_imc_init_box(struct intel_uncore_box *box)
+{
+ struct pci_dev *pdev = box->pci_dev;
+ int where = SNB_UNCORE_PCI_IMC_BAR_OFFSET;
+ resource_size_t addr;
+ u32 pci_dword;
+
+ pci_read_config_dword(pdev, where, &pci_dword);
+ addr = pci_dword;
+
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+ pci_read_config_dword(pdev, where + 4, &pci_dword);
+ addr |= ((resource_size_t)pci_dword << 32);
+#endif
+
+ addr &= ~(PAGE_SIZE - 1);
+
+ box->io_addr = ioremap(addr, SNB_UNCORE_PCI_IMC_MAP_SIZE);
+ box->hrtimer_duration = UNCORE_SNB_IMC_HRTIMER_INTERVAL;
+}
+
+static void snb_uncore_imc_enable_box(struct intel_uncore_box *box)
+{}
+
+static void snb_uncore_imc_disable_box(struct intel_uncore_box *box)
+{}
+
+static void snb_uncore_imc_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{}
+
+static void snb_uncore_imc_disable_event(struct intel_uncore_box *box, struct perf_event *event)
+{}
+
+static u64 snb_uncore_imc_read_counter(struct intel_uncore_box *box, struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+
+ return (u64)*(unsigned int *)(box->io_addr + hwc->event_base);
+}
+
+/*
+ * custom event_init() function because we define our own fixed, free
+ * running counters, so we do not want to conflict with generic uncore
+ * logic. Also simplifies processing
+ */
+static int snb_uncore_imc_event_init(struct perf_event *event)
+{
+ struct intel_uncore_pmu *pmu;
+ struct intel_uncore_box *box;
+ struct hw_perf_event *hwc = &event->hw;
+ u64 cfg = event->attr.config & SNB_UNCORE_PCI_IMC_EVENT_MASK;
+ int idx, base;
+
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+
+ pmu = uncore_event_to_pmu(event);
+ /* no device found for this pmu */
+ if (pmu->func_id < 0)
+ return -ENOENT;
+
+ /* Sampling not supported yet */
+ if (hwc->sample_period)
+ return -EINVAL;
+
+ /* unsupported modes and filters */
+ if (event->attr.exclude_user ||
+ event->attr.exclude_kernel ||
+ event->attr.exclude_hv ||
+ event->attr.exclude_idle ||
+ event->attr.exclude_host ||
+ event->attr.exclude_guest ||
+ event->attr.sample_period) /* no sampling */
+ return -EINVAL;
+
+ /*
+ * Place all uncore events for a particular physical package
+ * onto a single cpu
+ */
+ if (event->cpu < 0)
+ return -EINVAL;
+
+ /* check only supported bits are set */
+ if (event->attr.config & ~SNB_UNCORE_PCI_IMC_EVENT_MASK)
+ return -EINVAL;
+
+ box = uncore_pmu_to_box(pmu, event->cpu);
+ if (!box || box->cpu < 0)
+ return -EINVAL;
+
+ event->cpu = box->cpu;
+
+ event->hw.idx = -1;
+ event->hw.last_tag = ~0ULL;
+ event->hw.extra_reg.idx = EXTRA_REG_NONE;
+ event->hw.branch_reg.idx = EXTRA_REG_NONE;
+ /*
+ * check event is known (whitelist, determines counter)
+ */
+ switch (cfg) {
+ case SNB_UNCORE_PCI_IMC_DATA_READS:
+ base = SNB_UNCORE_PCI_IMC_DATA_READS_BASE;
+ idx = UNCORE_PMC_IDX_FIXED;
+ break;
+ case SNB_UNCORE_PCI_IMC_DATA_WRITES:
+ base = SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE;
+ idx = UNCORE_PMC_IDX_FIXED + 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* must be done before validate_group */
+ event->hw.event_base = base;
+ event->hw.config = cfg;
+ event->hw.idx = idx;
+
+ /* no group validation needed, we have free running counters */
+
+ return 0;
+}
+
+static int snb_uncore_imc_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+ return 0;
+}
+
+static void snb_uncore_imc_event_start(struct perf_event *event, int flags)
+{
+ struct intel_uncore_box *box = uncore_event_to_box(event);
+ u64 count;
+
+ if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
+ return;
+
+ event->hw.state = 0;
+ box->n_active++;
+
+ list_add_tail(&event->active_entry, &box->active_list);
+
+ count = snb_uncore_imc_read_counter(box, event);
+ local64_set(&event->hw.prev_count, count);
+
+ if (box->n_active == 1)
+ uncore_pmu_start_hrtimer(box);
+}
+
+static void snb_uncore_imc_event_stop(struct perf_event *event, int flags)
+{
+ struct intel_uncore_box *box = uncore_event_to_box(event);
+ struct hw_perf_event *hwc = &event->hw;
+
+ if (!(hwc->state & PERF_HES_STOPPED)) {
+ box->n_active--;
+
+ WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+ hwc->state |= PERF_HES_STOPPED;
+
+ list_del(&event->active_entry);
+
+ if (box->n_active == 0)
+ uncore_pmu_cancel_hrtimer(box);
+ }
+
+ if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+ /*
+ * Drain the remaining delta count out of a event
+ * that we are disabling:
+ */
+ uncore_perf_event_update(box, event);
+ hwc->state |= PERF_HES_UPTODATE;
+ }
+}
+
+static int snb_uncore_imc_event_add(struct perf_event *event, int flags)
+{
+ struct intel_uncore_box *box = uncore_event_to_box(event);
+ struct hw_perf_event *hwc = &event->hw;
+
+ if (!box)
+ return -ENODEV;
+
+ hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+ if (!(flags & PERF_EF_START))
+ hwc->state |= PERF_HES_ARCH;
+
+ snb_uncore_imc_event_start(event, 0);
+
+ box->n_events++;
+
+ return 0;
+}
+
+static void snb_uncore_imc_event_del(struct perf_event *event, int flags)
+{
+ struct intel_uncore_box *box = uncore_event_to_box(event);
+ int i;
+
+ snb_uncore_imc_event_stop(event, PERF_EF_UPDATE);
+
+ for (i = 0; i < box->n_events; i++) {
+ if (event == box->event_list[i]) {
+ --box->n_events;
+ break;
+ }
+ }
+}
+
+static int snb_pci2phy_map_init(int devid)
+{
+ struct pci_dev *dev = NULL;
+ int bus;
+
+ dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, dev);
+ if (!dev)
+ return -ENOTTY;
+
+ bus = dev->bus->number;
+
+ pcibus_to_physid[bus] = 0;
+
+ pci_dev_put(dev);
+
+ return 0;
+}
+
+static struct pmu snb_uncore_imc_pmu = {
+ .task_ctx_nr = perf_invalid_context,
+ .event_init = snb_uncore_imc_event_init,
+ .add = snb_uncore_imc_event_add,
+ .del = snb_uncore_imc_event_del,
+ .start = snb_uncore_imc_event_start,
+ .stop = snb_uncore_imc_event_stop,
+ .read = uncore_pmu_event_read,
+};
+
+static struct intel_uncore_ops snb_uncore_imc_ops = {
+ .init_box = snb_uncore_imc_init_box,
+ .enable_box = snb_uncore_imc_enable_box,
+ .disable_box = snb_uncore_imc_disable_box,
+ .disable_event = snb_uncore_imc_disable_event,
+ .enable_event = snb_uncore_imc_enable_event,
+ .hw_config = snb_uncore_imc_hw_config,
+ .read_counter = snb_uncore_imc_read_counter,
+};
+
+static struct intel_uncore_type snb_uncore_imc = {
+ .name = "imc",
+ .num_counters = 2,
+ .num_boxes = 1,
+ .fixed_ctr_bits = 32,
+ .fixed_ctr = SNB_UNCORE_PCI_IMC_CTR_BASE,
+ .event_descs = snb_uncore_imc_events,
+ .format_group = &snb_uncore_imc_format_group,
+ .perf_ctr = SNB_UNCORE_PCI_IMC_DATA_READS_BASE,
+ .event_mask = SNB_UNCORE_PCI_IMC_EVENT_MASK,
+ .ops = &snb_uncore_imc_ops,
+ .pmu = &snb_uncore_imc_pmu,
+};
+
+static struct intel_uncore_type *snb_pci_uncores[] = {
+ [SNB_PCI_UNCORE_IMC] = &snb_uncore_imc,
+ NULL,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(snb_uncore_pci_ids) = {
+ { /* IMC */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SNB_IMC),
+ .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+ },
+ { /* end: all zeroes */ },
+};
+
+static DEFINE_PCI_DEVICE_TABLE(ivb_uncore_pci_ids) = {
+ { /* IMC */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_IMC),
+ .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+ },
+ { /* end: all zeroes */ },
+};
+
+static DEFINE_PCI_DEVICE_TABLE(hsw_uncore_pci_ids) = {
+ { /* IMC */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_IMC),
+ .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+ },
+ { /* end: all zeroes */ },
+};
+
+static struct pci_driver snb_uncore_pci_driver = {
+ .name = "snb_uncore",
+ .id_table = snb_uncore_pci_ids,
+};
+
+static struct pci_driver ivb_uncore_pci_driver = {
+ .name = "ivb_uncore",
+ .id_table = ivb_uncore_pci_ids,
+};
+
+static struct pci_driver hsw_uncore_pci_driver = {
+ .name = "hsw_uncore",
+ .id_table = hsw_uncore_pci_ids,
+};
+
/* end of Sandy Bridge uncore support */
/* Nehalem uncore support */
@@ -2781,6 +3173,7 @@ again:
static enum hrtimer_restart uncore_pmu_hrtimer(struct hrtimer *hrtimer)
{
struct intel_uncore_box *box;
+ struct perf_event *event;
unsigned long flags;
int bit;
@@ -2793,19 +3186,27 @@ static enum hrtimer_restart uncore_pmu_hrtimer(struct hrtimer *hrtimer)
*/
local_irq_save(flags);
+ /*
+ * handle boxes with an active event list as opposed to active
+ * counters
+ */
+ list_for_each_entry(event, &box->active_list, active_entry) {
+ uncore_perf_event_update(box, event);
+ }
+
for_each_set_bit(bit, box->active_mask, UNCORE_PMC_IDX_MAX)
uncore_perf_event_update(box, box->events[bit]);
local_irq_restore(flags);
- hrtimer_forward_now(hrtimer, ns_to_ktime(UNCORE_PMU_HRTIMER_INTERVAL));
+ hrtimer_forward_now(hrtimer, ns_to_ktime(box->hrtimer_duration));
return HRTIMER_RESTART;
}
static void uncore_pmu_start_hrtimer(struct intel_uncore_box *box)
{
__hrtimer_start_range_ns(&box->hrtimer,
- ns_to_ktime(UNCORE_PMU_HRTIMER_INTERVAL), 0,
+ ns_to_ktime(box->hrtimer_duration), 0,
HRTIMER_MODE_REL_PINNED, 0);
}
@@ -2839,43 +3240,12 @@ static struct intel_uncore_box *uncore_alloc_box(struct intel_uncore_type *type,
box->cpu = -1;
box->phys_id = -1;
- return box;
-}
-
-static struct intel_uncore_box *
-uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
-{
- struct intel_uncore_box *box;
-
- box = *per_cpu_ptr(pmu->box, cpu);
- if (box)
- return box;
+ /* set default hrtimer timeout */
+ box->hrtimer_duration = UNCORE_PMU_HRTIMER_INTERVAL;
- raw_spin_lock(&uncore_box_lock);
- list_for_each_entry(box, &pmu->box_list, list) {
- if (box->phys_id == topology_physical_package_id(cpu)) {
- atomic_inc(&box->refcnt);
- *per_cpu_ptr(pmu->box, cpu) = box;
- break;
- }
- }
- raw_spin_unlock(&uncore_box_lock);
+ INIT_LIST_HEAD(&box->active_list);
- return *per_cpu_ptr(pmu->box, cpu);
-}
-
-static struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event)
-{
- return container_of(event->pmu, struct intel_uncore_pmu, pmu);
-}
-
-static struct intel_uncore_box *uncore_event_to_box(struct perf_event *event)
-{
- /*
- * perf core schedules event on the basis of cpu, uncore events are
- * collected by one of the cpus inside a physical package.
- */
- return uncore_pmu_to_box(uncore_event_to_pmu(event), smp_processor_id());
+ return box;
}
static int
@@ -3271,16 +3641,21 @@ static int __init uncore_pmu_register(struct intel_uncore_pmu *pmu)
{
int ret;
- pmu->pmu = (struct pmu) {
- .attr_groups = pmu->type->attr_groups,
- .task_ctx_nr = perf_invalid_context,
- .event_init = uncore_pmu_event_init,
- .add = uncore_pmu_event_add,
- .del = uncore_pmu_event_del,
- .start = uncore_pmu_event_start,
- .stop = uncore_pmu_event_stop,
- .read = uncore_pmu_event_read,
- };
+ if (!pmu->type->pmu) {
+ pmu->pmu = (struct pmu) {
+ .attr_groups = pmu->type->attr_groups,
+ .task_ctx_nr = perf_invalid_context,
+ .event_init = uncore_pmu_event_init,
+ .add = uncore_pmu_event_add,
+ .del = uncore_pmu_event_del,
+ .start = uncore_pmu_event_start,
+ .stop = uncore_pmu_event_stop,
+ .read = uncore_pmu_event_read,
+ };
+ } else {
+ pmu->pmu = *pmu->type->pmu;
+ pmu->pmu.attr_groups = pmu->type->attr_groups;
+ }
if (pmu->type->num_boxes == 1) {
if (strlen(pmu->type->name) > 0)
@@ -3326,6 +3701,8 @@ static int __init uncore_type_init(struct intel_uncore_type *type)
if (!pmus)
return -ENOMEM;
+ type->pmus = pmus;
+
type->unconstrainted = (struct event_constraint)
__EVENT_CONSTRAINT(0, (1ULL << type->num_counters) - 1,
0, type->num_counters, 0, 0);
@@ -3361,7 +3738,6 @@ static int __init uncore_type_init(struct intel_uncore_type *type)
}
type->pmu_group = &uncore_pmu_attr_group;
- type->pmus = pmus;
return 0;
fail:
uncore_type_exit(type);
@@ -3493,6 +3869,28 @@ static int __init uncore_pci_init(void)
pci_uncores = ivt_pci_uncores;
uncore_pci_driver = &ivt_uncore_pci_driver;
break;
+ case 42: /* Sandy Bridge */
+ ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_SNB_IMC);
+ if (ret)
+ return ret;
+ pci_uncores = snb_pci_uncores;
+ uncore_pci_driver = &snb_uncore_pci_driver;
+ break;
+ case 58: /* Ivy Bridge */
+ ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_IVB_IMC);
+ if (ret)
+ return ret;
+ pci_uncores = snb_pci_uncores;
+ uncore_pci_driver = &ivb_uncore_pci_driver;
+ break;
+ case 60: /* Haswell */
+ case 69: /* Haswell Celeron */
+ ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_HSW_IMC);
+ if (ret)
+ return ret;
+ pci_uncores = snb_pci_uncores;
+ uncore_pci_driver = &hsw_uncore_pci_driver;
+ break;
default:
return 0;
}
@@ -3764,7 +4162,7 @@ static void __init uncore_cpu_setup(void *dummy)
static int __init uncore_cpu_init(void)
{
- int ret, cpu, max_cores;
+ int ret, max_cores;
max_cores = boot_cpu_data.x86_max_cores;
switch (boot_cpu_data.x86_model) {
@@ -3808,29 +4206,6 @@ static int __init uncore_cpu_init(void)
if (ret)
return ret;
- get_online_cpus();
-
- for_each_online_cpu(cpu) {
- int i, phys_id = topology_physical_package_id(cpu);
-
- for_each_cpu(i, &uncore_cpu_mask) {
- if (phys_id == topology_physical_package_id(i)) {
- phys_id = -1;
- break;
- }
- }
- if (phys_id < 0)
- continue;
-
- uncore_cpu_prepare(cpu, phys_id);
- uncore_event_init_cpu(cpu);
- }
- on_each_cpu(uncore_cpu_setup, NULL, 1);
-
- register_cpu_notifier(&uncore_cpu_nb);
-
- put_online_cpus();
-
return 0;
}
@@ -3859,6 +4234,41 @@ static int __init uncore_pmus_register(void)
return 0;
}
+static void __init uncore_cpumask_init(void)
+{
+ int cpu;
+
+ /*
+ * ony invoke once from msr or pci init code
+ */
+ if (!cpumask_empty(&uncore_cpu_mask))
+ return;
+
+ get_online_cpus();
+
+ for_each_online_cpu(cpu) {
+ int i, phys_id = topology_physical_package_id(cpu);
+
+ for_each_cpu(i, &uncore_cpu_mask) {
+ if (phys_id == topology_physical_package_id(i)) {
+ phys_id = -1;
+ break;
+ }
+ }
+ if (phys_id < 0)
+ continue;
+
+ uncore_cpu_prepare(cpu, phys_id);
+ uncore_event_init_cpu(cpu);
+ }
+ on_each_cpu(uncore_cpu_setup, NULL, 1);
+
+ register_cpu_notifier(&uncore_cpu_nb);
+
+ put_online_cpus();
+}
+
+
static int __init intel_uncore_init(void)
{
int ret;
@@ -3877,6 +4287,7 @@ static int __init intel_uncore_init(void)
uncore_pci_exit();
goto fail;
}
+ uncore_cpumask_init();
uncore_pmus_register();
return 0;
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
index a80ab71a883d..90236f0c94a9 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
@@ -6,6 +6,7 @@
#define UNCORE_PMU_NAME_LEN 32
#define UNCORE_PMU_HRTIMER_INTERVAL (60LL * NSEC_PER_SEC)
+#define UNCORE_SNB_IMC_HRTIMER_INTERVAL (5ULL * NSEC_PER_SEC)
#define UNCORE_FIXED_EVENT 0xff
#define UNCORE_PMC_IDX_MAX_GENERIC 8
@@ -440,6 +441,7 @@ struct intel_uncore_type {
struct intel_uncore_ops *ops;
struct uncore_event_desc *event_descs;
const struct attribute_group *attr_groups[4];
+ struct pmu *pmu; /* for custom pmu ops */
};
#define pmu_group attr_groups[0]
@@ -488,8 +490,11 @@ struct intel_uncore_box {
u64 tags[UNCORE_PMC_IDX_MAX];
struct pci_dev *pci_dev;
struct intel_uncore_pmu *pmu;
+ u64 hrtimer_duration; /* hrtimer timeout for this box */
struct hrtimer hrtimer;
struct list_head list;
+ struct list_head active_list;
+ void *io_addr;
struct intel_uncore_extra_reg shared_regs[0];
};
diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c
index 3486e6660357..5d466b7d8609 100644
--- a/arch/x86/kernel/cpu/perf_event_p4.c
+++ b/arch/x86/kernel/cpu/perf_event_p4.c
@@ -1257,7 +1257,24 @@ again:
pass++;
goto again;
}
-
+ /*
+ * Perf does test runs to see if a whole group can be assigned
+ * together succesfully. There can be multiple rounds of this.
+ * Unfortunately, p4_pmu_swap_config_ts touches the hwc->config
+ * bits, such that the next round of group assignments will
+ * cause the above p4_should_swap_ts to pass instead of fail.
+ * This leads to counters exclusive to thread0 being used by
+ * thread1.
+ *
+ * Solve this with a cheap hack, reset the idx back to -1 to
+ * force a new lookup (p4_next_cntr) to get the right counter
+ * for the right thread.
+ *
+ * This probably doesn't comply with the general spirit of how
+ * perf wants to work, but P4 is special. :-(
+ */
+ if (p4_should_swap_ts(hwc->config, cpu))
+ hwc->idx = -1;
p4_pmu_swap_config_ts(hwc, cpu);
if (assign)
assign[i] = cntr_idx;
@@ -1322,6 +1339,7 @@ static __initconst const struct x86_pmu p4_pmu = {
__init int p4_pmu_init(void)
{
unsigned int low, high;
+ int i, reg;
/* If we get stripped -- indexing fails */
BUILD_BUG_ON(ARCH_P4_MAX_CCCR > INTEL_PMC_MAX_GENERIC);
@@ -1340,5 +1358,19 @@ __init int p4_pmu_init(void)
x86_pmu = p4_pmu;
+ /*
+ * Even though the counters are configured to interrupt a particular
+ * logical processor when an overflow happens, testing has shown that
+ * on kdump kernels (which uses a single cpu), thread1's counter
+ * continues to run and will report an NMI on thread0. Due to the
+ * overflow bug, this leads to a stream of unknown NMIs.
+ *
+ * Solve this by zero'ing out the registers to mimic a reset.
+ */
+ for (i = 0; i < x86_pmu.num_counters; i++) {
+ reg = x86_pmu_config_addr(i);
+ wrmsrl_safe(reg, 0ULL);
+ }
+
return 0;
}
diff --git a/arch/x86/kernel/cpu/perf_event_p6.c b/arch/x86/kernel/cpu/perf_event_p6.c
index b1e2fe115323..7c1a0c07b607 100644
--- a/arch/x86/kernel/cpu/perf_event_p6.c
+++ b/arch/x86/kernel/cpu/perf_event_p6.c
@@ -231,31 +231,49 @@ static __initconst const struct x86_pmu p6_pmu = {
};
+static __init void p6_pmu_rdpmc_quirk(void)
+{
+ if (boot_cpu_data.x86_mask < 9) {
+ /*
+ * PPro erratum 26; fixed in stepping 9 and above.
+ */
+ pr_warn("Userspace RDPMC support disabled due to a CPU erratum\n");
+ x86_pmu.attr_rdpmc_broken = 1;
+ x86_pmu.attr_rdpmc = 0;
+ }
+}
+
__init int p6_pmu_init(void)
{
+ x86_pmu = p6_pmu;
+
switch (boot_cpu_data.x86_model) {
- case 1:
- case 3: /* Pentium Pro */
- case 5:
- case 6: /* Pentium II */
- case 7:
- case 8:
- case 11: /* Pentium III */
- case 9:
- case 13:
- /* Pentium M */
+ case 1: /* Pentium Pro */
+ x86_add_quirk(p6_pmu_rdpmc_quirk);
+ break;
+
+ case 3: /* Pentium II - Klamath */
+ case 5: /* Pentium II - Deschutes */
+ case 6: /* Pentium II - Mendocino */
break;
+
+ case 7: /* Pentium III - Katmai */
+ case 8: /* Pentium III - Coppermine */
+ case 10: /* Pentium III Xeon */
+ case 11: /* Pentium III - Tualatin */
+ break;
+
+ case 9: /* Pentium M - Banias */
+ case 13: /* Pentium M - Dothan */
+ break;
+
default:
- pr_cont("unsupported p6 CPU model %d ",
- boot_cpu_data.x86_model);
+ pr_cont("unsupported p6 CPU model %d ", boot_cpu_data.x86_model);
return -ENODEV;
}
- x86_pmu = p6_pmu;
-
memcpy(hw_cache_event_ids, p6_hw_cache_event_ids,
sizeof(hw_cache_event_ids));
-
return 0;
}
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index a57902efe2d5..507de8066594 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -57,9 +57,7 @@ static void kdump_nmi_callback(int cpu, struct pt_regs *regs)
{
#ifdef CONFIG_X86_32
struct pt_regs fixed_regs;
-#endif
-#ifdef CONFIG_X86_32
if (!user_mode_vm(regs)) {
crash_fixup_ss_esp(&fixed_regs, regs);
regs = &fixed_regs;
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
index f2a1770ca176..5abd4cd4230c 100644
--- a/arch/x86/kernel/dumpstack_32.c
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -16,12 +16,35 @@
#include <asm/stacktrace.h>
+static void *is_irq_stack(void *p, void *irq)
+{
+ if (p < irq || p >= (irq + THREAD_SIZE))
+ return NULL;
+ return irq + THREAD_SIZE;
+}
+
+
+static void *is_hardirq_stack(unsigned long *stack, int cpu)
+{
+ void *irq = per_cpu(hardirq_stack, cpu);
+
+ return is_irq_stack(stack, irq);
+}
+
+static void *is_softirq_stack(unsigned long *stack, int cpu)
+{
+ void *irq = per_cpu(softirq_stack, cpu);
+
+ return is_irq_stack(stack, irq);
+}
void dump_trace(struct task_struct *task, struct pt_regs *regs,
unsigned long *stack, unsigned long bp,
const struct stacktrace_ops *ops, void *data)
{
+ const unsigned cpu = get_cpu();
int graph = 0;
+ u32 *prev_esp;
if (!task)
task = current;
@@ -30,7 +53,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
unsigned long dummy;
stack = &dummy;
- if (task && task != current)
+ if (task != current)
stack = (unsigned long *)task->thread.sp;
}
@@ -39,18 +62,31 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
for (;;) {
struct thread_info *context;
+ void *end_stack;
+
+ end_stack = is_hardirq_stack(stack, cpu);
+ if (!end_stack)
+ end_stack = is_softirq_stack(stack, cpu);
- context = (struct thread_info *)
- ((unsigned long)stack & (~(THREAD_SIZE - 1)));
- bp = ops->walk_stack(context, stack, bp, ops, data, NULL, &graph);
+ context = task_thread_info(task);
+ bp = ops->walk_stack(context, stack, bp, ops, data,
+ end_stack, &graph);
- stack = (unsigned long *)context->previous_esp;
+ /* Stop if not on irq stack */
+ if (!end_stack)
+ break;
+
+ /* The previous esp is saved on the bottom of the stack */
+ prev_esp = (u32 *)(end_stack - THREAD_SIZE);
+ stack = (unsigned long *)*prev_esp;
if (!stack)
break;
+
if (ops->stack(data, "IRQ") < 0)
break;
touch_nmi_watchdog();
}
+ put_cpu();
}
EXPORT_SYMBOL(dump_trace);
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index addb207dab92..1abcb50b48ae 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -104,6 +104,44 @@ in_irq_stack(unsigned long *stack, unsigned long *irq_stack,
return (stack >= irq_stack && stack < irq_stack_end);
}
+static const unsigned long irq_stack_size =
+ (IRQ_STACK_SIZE - 64) / sizeof(unsigned long);
+
+enum stack_type {
+ STACK_IS_UNKNOWN,
+ STACK_IS_NORMAL,
+ STACK_IS_EXCEPTION,
+ STACK_IS_IRQ,
+};
+
+static enum stack_type
+analyze_stack(int cpu, struct task_struct *task, unsigned long *stack,
+ unsigned long **stack_end, unsigned long *irq_stack,
+ unsigned *used, char **id)
+{
+ unsigned long addr;
+
+ addr = ((unsigned long)stack & (~(THREAD_SIZE - 1)));
+ if ((unsigned long)task_stack_page(task) == addr)
+ return STACK_IS_NORMAL;
+
+ *stack_end = in_exception_stack(cpu, (unsigned long)stack,
+ used, id);
+ if (*stack_end)
+ return STACK_IS_EXCEPTION;
+
+ if (!irq_stack)
+ return STACK_IS_NORMAL;
+
+ *stack_end = irq_stack;
+ irq_stack = irq_stack - irq_stack_size;
+
+ if (in_irq_stack(stack, irq_stack, *stack_end))
+ return STACK_IS_IRQ;
+
+ return STACK_IS_UNKNOWN;
+}
+
/*
* x86-64 can have up to three kernel stacks:
* process stack
@@ -116,12 +154,12 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
const struct stacktrace_ops *ops, void *data)
{
const unsigned cpu = get_cpu();
- unsigned long *irq_stack_end =
- (unsigned long *)per_cpu(irq_stack_ptr, cpu);
- unsigned used = 0;
struct thread_info *tinfo;
- int graph = 0;
+ unsigned long *irq_stack = (unsigned long *)per_cpu(irq_stack_ptr, cpu);
unsigned long dummy;
+ unsigned used = 0;
+ int graph = 0;
+ int done = 0;
if (!task)
task = current;
@@ -143,49 +181,61 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
* exceptions
*/
tinfo = task_thread_info(task);
- for (;;) {
+ while (!done) {
+ unsigned long *stack_end;
+ enum stack_type stype;
char *id;
- unsigned long *estack_end;
- estack_end = in_exception_stack(cpu, (unsigned long)stack,
- &used, &id);
- if (estack_end) {
+ stype = analyze_stack(cpu, task, stack, &stack_end,
+ irq_stack, &used, &id);
+
+ /* Default finish unless specified to continue */
+ done = 1;
+
+ switch (stype) {
+
+ /* Break out early if we are on the thread stack */
+ case STACK_IS_NORMAL:
+ break;
+
+ case STACK_IS_EXCEPTION:
+
if (ops->stack(data, id) < 0)
break;
bp = ops->walk_stack(tinfo, stack, bp, ops,
- data, estack_end, &graph);
+ data, stack_end, &graph);
ops->stack(data, "<EOE>");
/*
* We link to the next stack via the
* second-to-last pointer (index -2 to end) in the
* exception stack:
*/
- stack = (unsigned long *) estack_end[-2];
- continue;
- }
- if (irq_stack_end) {
- unsigned long *irq_stack;
- irq_stack = irq_stack_end -
- (IRQ_STACK_SIZE - 64) / sizeof(*irq_stack);
-
- if (in_irq_stack(stack, irq_stack, irq_stack_end)) {
- if (ops->stack(data, "IRQ") < 0)
- break;
- bp = ops->walk_stack(tinfo, stack, bp,
- ops, data, irq_stack_end, &graph);
- /*
- * We link to the next stack (which would be
- * the process stack normally) the last
- * pointer (index -1 to end) in the IRQ stack:
- */
- stack = (unsigned long *) (irq_stack_end[-1]);
- irq_stack_end = NULL;
- ops->stack(data, "EOI");
- continue;
- }
+ stack = (unsigned long *) stack_end[-2];
+ done = 0;
+ break;
+
+ case STACK_IS_IRQ:
+
+ if (ops->stack(data, "IRQ") < 0)
+ break;
+ bp = ops->walk_stack(tinfo, stack, bp,
+ ops, data, stack_end, &graph);
+ /*
+ * We link to the next stack (which would be
+ * the process stack normally) the last
+ * pointer (index -1 to end) in the IRQ stack:
+ */
+ stack = (unsigned long *) (stack_end[-1]);
+ irq_stack = NULL;
+ ops->stack(data, "EOI");
+ done = 0;
+ break;
+
+ case STACK_IS_UNKNOWN:
+ ops->stack(data, "UNK");
+ break;
}
- break;
}
/*
diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c
index bc4a088f9023..6d7d5a1260a6 100644
--- a/arch/x86/kernel/early-quirks.c
+++ b/arch/x86/kernel/early-quirks.c
@@ -203,18 +203,15 @@ static void __init intel_remapping_check(int num, int slot, int func)
revision = read_pci_config_byte(num, slot, func, PCI_REVISION_ID);
/*
- * Revision 13 of all triggering devices id in this quirk have
- * a problem draining interrupts when irq remapping is enabled,
- * and should be flagged as broken. Additionally revisions 0x12
- * and 0x22 of device id 0x3405 has this problem.
+ * Revision <= 13 of all triggering devices id in this quirk
+ * have a problem draining interrupts when irq remapping is
+ * enabled, and should be flagged as broken. Additionally
+ * revision 0x22 of device id 0x3405 has this problem.
*/
- if (revision == 0x13)
+ if (revision <= 0x13)
set_irq_remapping_broken();
- else if ((device == 0x3405) &&
- ((revision == 0x12) ||
- (revision == 0x22)))
+ else if (device == 0x3405 && revision == 0x22)
set_irq_remapping_broken();
-
}
/*
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index d4bdd253fea7..52819e816f87 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -77,8 +77,7 @@ within(unsigned long addr, unsigned long start, unsigned long end)
return addr >= start && addr < end;
}
-static int
-do_ftrace_mod_code(unsigned long ip, const void *new_code)
+static unsigned long text_ip_addr(unsigned long ip)
{
/*
* On x86_64, kernel text mappings are mapped read-only with
@@ -91,7 +90,7 @@ do_ftrace_mod_code(unsigned long ip, const void *new_code)
if (within(ip, (unsigned long)_text, (unsigned long)_etext))
ip = (unsigned long)__va(__pa_symbol(ip));
- return probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE);
+ return ip;
}
static const unsigned char *ftrace_nop_replace(void)
@@ -123,8 +122,10 @@ ftrace_modify_code_direct(unsigned long ip, unsigned const char *old_code,
if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0)
return -EINVAL;
+ ip = text_ip_addr(ip);
+
/* replace the text with the new text */
- if (do_ftrace_mod_code(ip, new_code))
+ if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE))
return -EPERM;
sync_core();
@@ -221,37 +222,51 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
return -EINVAL;
}
-int ftrace_update_ftrace_func(ftrace_func_t func)
+static unsigned long ftrace_update_func;
+
+static int update_ftrace_func(unsigned long ip, void *new)
{
- unsigned long ip = (unsigned long)(&ftrace_call);
- unsigned char old[MCOUNT_INSN_SIZE], *new;
+ unsigned char old[MCOUNT_INSN_SIZE];
int ret;
- memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE);
- new = ftrace_call_replace(ip, (unsigned long)func);
+ memcpy(old, (void *)ip, MCOUNT_INSN_SIZE);
+
+ ftrace_update_func = ip;
+ /* Make sure the breakpoints see the ftrace_update_func update */
+ smp_wmb();
/* See comment above by declaration of modifying_ftrace_code */
atomic_inc(&modifying_ftrace_code);
ret = ftrace_modify_code(ip, old, new);
+ atomic_dec(&modifying_ftrace_code);
+
+ return ret;
+}
+
+int ftrace_update_ftrace_func(ftrace_func_t func)
+{
+ unsigned long ip = (unsigned long)(&ftrace_call);
+ unsigned char *new;
+ int ret;
+
+ new = ftrace_call_replace(ip, (unsigned long)func);
+ ret = update_ftrace_func(ip, new);
+
/* Also update the regs callback function */
if (!ret) {
ip = (unsigned long)(&ftrace_regs_call);
- memcpy(old, &ftrace_regs_call, MCOUNT_INSN_SIZE);
new = ftrace_call_replace(ip, (unsigned long)func);
- ret = ftrace_modify_code(ip, old, new);
+ ret = update_ftrace_func(ip, new);
}
- atomic_dec(&modifying_ftrace_code);
-
return ret;
}
static int is_ftrace_caller(unsigned long ip)
{
- if (ip == (unsigned long)(&ftrace_call) ||
- ip == (unsigned long)(&ftrace_regs_call))
+ if (ip == ftrace_update_func)
return 1;
return 0;
@@ -293,7 +308,10 @@ static int ftrace_write(unsigned long ip, const char *val, int size)
if (within(ip, (unsigned long)_text, (unsigned long)_etext))
ip = (unsigned long)__va(__pa_symbol(ip));
- return probe_kernel_write((void *)ip, val, size);
+ if (probe_kernel_write((void *)ip, val, size))
+ return -EPERM;
+
+ return 0;
}
static int add_break(unsigned long ip, const char *old)
@@ -308,10 +326,7 @@ static int add_break(unsigned long ip, const char *old)
if (memcmp(replaced, old, MCOUNT_INSN_SIZE) != 0)
return -EINVAL;
- if (ftrace_write(ip, &brk, 1))
- return -EPERM;
-
- return 0;
+ return ftrace_write(ip, &brk, 1);
}
static int add_brk_on_call(struct dyn_ftrace *rec, unsigned long addr)
@@ -410,7 +425,7 @@ static int remove_breakpoint(struct dyn_ftrace *rec)
/* If this does not have a breakpoint, we are done */
if (ins[0] != brk)
- return -1;
+ return 0;
nop = ftrace_nop_replace();
@@ -440,7 +455,7 @@ static int remove_breakpoint(struct dyn_ftrace *rec)
}
update:
- return probe_kernel_write((void *)ip, &nop[0], 1);
+ return ftrace_write(ip, nop, 1);
}
static int add_update_code(unsigned long ip, unsigned const char *new)
@@ -448,9 +463,7 @@ static int add_update_code(unsigned long ip, unsigned const char *new)
/* skip breakpoint */
ip++;
new++;
- if (ftrace_write(ip, new, MCOUNT_INSN_SIZE - 1))
- return -EPERM;
- return 0;
+ return ftrace_write(ip, new, MCOUNT_INSN_SIZE - 1);
}
static int add_update_call(struct dyn_ftrace *rec, unsigned long addr)
@@ -505,10 +518,7 @@ static int finish_update_call(struct dyn_ftrace *rec, unsigned long addr)
new = ftrace_call_replace(ip, addr);
- if (ftrace_write(ip, new, 1))
- return -EPERM;
-
- return 0;
+ return ftrace_write(ip, new, 1);
}
static int finish_update_nop(struct dyn_ftrace *rec)
@@ -518,9 +528,7 @@ static int finish_update_nop(struct dyn_ftrace *rec)
new = ftrace_nop_replace();
- if (ftrace_write(ip, new, 1))
- return -EPERM;
- return 0;
+ return ftrace_write(ip, new, 1);
}
static int finish_update(struct dyn_ftrace *rec, int enable)
@@ -617,8 +625,14 @@ void ftrace_replace_code(int enable)
printk(KERN_WARNING "Failed on %s (%d):\n", report, count);
for_ftrace_rec_iter(iter) {
rec = ftrace_rec_iter_record(iter);
- remove_breakpoint(rec);
+ /*
+ * Breakpoints are handled only when this function is in
+ * progress. The system could not work with them.
+ */
+ if (remove_breakpoint(rec))
+ BUG();
}
+ run_sync();
}
static int
@@ -640,16 +654,19 @@ ftrace_modify_code(unsigned long ip, unsigned const char *old_code,
run_sync();
ret = ftrace_write(ip, new_code, 1);
- if (ret) {
- ret = -EPERM;
- goto out;
- }
- run_sync();
+ /*
+ * The breakpoint is handled only when this function is in progress.
+ * The system could not work if we could not remove it.
+ */
+ BUG_ON(ret);
out:
+ run_sync();
return ret;
fail_update:
- probe_kernel_write((void *)ip, &old_code[0], 1);
+ /* Also here the system could not work with the breakpoint */
+ if (ftrace_write(ip, old_code, 1))
+ BUG();
goto out;
}
@@ -663,11 +680,8 @@ void arch_ftrace_update_code(int command)
atomic_dec(&modifying_ftrace_code);
}
-int __init ftrace_dyn_arch_init(void *data)
+int __init ftrace_dyn_arch_init(void)
{
- /* The return code is retured via data */
- *(unsigned long *)data = 0;
-
return 0;
}
#endif
@@ -677,45 +691,41 @@ int __init ftrace_dyn_arch_init(void *data)
#ifdef CONFIG_DYNAMIC_FTRACE
extern void ftrace_graph_call(void);
-static int ftrace_mod_jmp(unsigned long ip,
- int old_offset, int new_offset)
+static unsigned char *ftrace_jmp_replace(unsigned long ip, unsigned long addr)
{
- unsigned char code[MCOUNT_INSN_SIZE];
+ static union ftrace_code_union calc;
- if (probe_kernel_read(code, (void *)ip, MCOUNT_INSN_SIZE))
- return -EFAULT;
+ /* Jmp not a call (ignore the .e8) */
+ calc.e8 = 0xe9;
+ calc.offset = ftrace_calc_offset(ip + MCOUNT_INSN_SIZE, addr);
- if (code[0] != 0xe9 || old_offset != *(int *)(&code[1]))
- return -EINVAL;
+ /*
+ * ftrace external locks synchronize the access to the static variable.
+ */
+ return calc.code;
+}
- *(int *)(&code[1]) = new_offset;
+static int ftrace_mod_jmp(unsigned long ip, void *func)
+{
+ unsigned char *new;
- if (do_ftrace_mod_code(ip, &code))
- return -EPERM;
+ new = ftrace_jmp_replace(ip, (unsigned long)func);
- return 0;
+ return update_ftrace_func(ip, new);
}
int ftrace_enable_ftrace_graph_caller(void)
{
unsigned long ip = (unsigned long)(&ftrace_graph_call);
- int old_offset, new_offset;
-
- old_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE);
- new_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE);
- return ftrace_mod_jmp(ip, old_offset, new_offset);
+ return ftrace_mod_jmp(ip, &ftrace_graph_caller);
}
int ftrace_disable_ftrace_graph_caller(void)
{
unsigned long ip = (unsigned long)(&ftrace_graph_call);
- int old_offset, new_offset;
-
- old_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE);
- new_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE);
- return ftrace_mod_jmp(ip, old_offset, new_offset);
+ return ftrace_mod_jmp(ip, &ftrace_stub);
}
#endif /* !CONFIG_DYNAMIC_FTRACE */
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index 81ba27679f18..f36bd42d6f0c 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -544,6 +544,10 @@ ENDPROC(early_idt_handlers)
/* This is global to keep gas from relaxing the jumps */
ENTRY(early_idt_handler)
cld
+
+ cmpl $2,(%esp) # X86_TRAP_NMI
+ je is_nmi # Ignore NMI
+
cmpl $2,%ss:early_recursion_flag
je hlt_loop
incl %ss:early_recursion_flag
@@ -594,8 +598,9 @@ ex_entry:
pop %edx
pop %ecx
pop %eax
- addl $8,%esp /* drop vector number and error code */
decl %ss:early_recursion_flag
+is_nmi:
+ addl $8,%esp /* drop vector number and error code */
iret
ENDPROC(early_idt_handler)
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index e1aabdb314c8..a468c0a65c42 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -343,6 +343,9 @@ early_idt_handlers:
ENTRY(early_idt_handler)
cld
+ cmpl $2,(%rsp) # X86_TRAP_NMI
+ je is_nmi # Ignore NMI
+
cmpl $2,early_recursion_flag(%rip)
jz 1f
incl early_recursion_flag(%rip)
@@ -405,8 +408,9 @@ ENTRY(early_idt_handler)
popq %rdx
popq %rcx
popq %rax
- addq $16,%rsp # drop vector number and error code
decl early_recursion_flag(%rip)
+is_nmi:
+ addq $16,%rsp # drop vector number and error code
INTERRUPT_RETURN
ENDPROC(early_idt_handler)
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index da85a8e830a1..93eed15a8fd4 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -521,7 +521,7 @@ static int hpet_setup_irq(struct hpet_dev *dev)
{
if (request_irq(dev->irq, hpet_interrupt_handler,
- IRQF_TIMER | IRQF_DISABLED | IRQF_NOBALANCING,
+ IRQF_TIMER | IRQF_NOBALANCING,
dev->name, dev))
return -1;
@@ -699,7 +699,7 @@ static int hpet_cpuhp_notify(struct notifier_block *n,
/* FIXME: add schedule_work_on() */
schedule_delayed_work_on(cpu, &work.work, 0);
wait_for_completion(&work.complete);
- destroy_timer_on_stack(&work.work.timer);
+ destroy_delayed_work_on_stack(&work.work);
break;
case CPU_DEAD:
if (hdev) {
@@ -752,9 +752,7 @@ static struct clocksource clocksource_hpet = {
.mask = HPET_MASK,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
.resume = hpet_resume_counter,
-#ifdef CONFIG_X86_64
.archdata = { .vclock_mode = VCLOCK_HPET },
-#endif
};
static int hpet_clocksource_register(void)
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index e8368c6dd2a2..d5dd80814419 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -86,10 +86,19 @@ EXPORT_SYMBOL(__kernel_fpu_begin);
void __kernel_fpu_end(void)
{
- if (use_eager_fpu())
- math_state_restore();
- else
+ if (use_eager_fpu()) {
+ /*
+ * For eager fpu, most the time, tsk_used_math() is true.
+ * Restore the user math as we are done with the kernel usage.
+ * At few instances during thread exit, signal handling etc,
+ * tsk_used_math() is false. Those few places will take proper
+ * actions, so we don't need to restore the math here.
+ */
+ if (likely(tsk_used_math(current)))
+ math_state_restore();
+ } else {
stts();
+ }
}
EXPORT_SYMBOL(__kernel_fpu_end);
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index d99f31d9a750..42805fac0092 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -125,6 +125,12 @@ int arch_show_interrupts(struct seq_file *p, int prec)
seq_printf(p, "%10u ", per_cpu(mce_poll_count, j));
seq_printf(p, " Machine check polls\n");
#endif
+#if defined(CONFIG_HYPERV) || defined(CONFIG_XEN)
+ seq_printf(p, "%*s: ", prec, "THR");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", irq_stats(j)->irq_hv_callback_count);
+ seq_printf(p, " Hypervisor callback interrupts\n");
+#endif
seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count));
#if defined(CONFIG_X86_IO_APIC)
seq_printf(p, "%*s: %10u\n", prec, "MIS", atomic_read(&irq_mis_count));
diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c
index d7fcbedc9c43..63ce838e5a54 100644
--- a/arch/x86/kernel/irq_32.c
+++ b/arch/x86/kernel/irq_32.c
@@ -55,16 +55,8 @@ static inline int check_stack_overflow(void) { return 0; }
static inline void print_stack_overflow(void) { }
#endif
-/*
- * per-CPU IRQ handling contexts (thread information and stack)
- */
-union irq_ctx {
- struct thread_info tinfo;
- u32 stack[THREAD_SIZE/sizeof(u32)];
-} __attribute__((aligned(THREAD_SIZE)));
-
-static DEFINE_PER_CPU(union irq_ctx *, hardirq_ctx);
-static DEFINE_PER_CPU(union irq_ctx *, softirq_ctx);
+DEFINE_PER_CPU(struct irq_stack *, hardirq_stack);
+DEFINE_PER_CPU(struct irq_stack *, softirq_stack);
static void call_on_stack(void *func, void *stack)
{
@@ -77,14 +69,26 @@ static void call_on_stack(void *func, void *stack)
: "memory", "cc", "edx", "ecx", "eax");
}
+/* how to get the current stack pointer from C */
+#define current_stack_pointer ({ \
+ unsigned long sp; \
+ asm("mov %%esp,%0" : "=g" (sp)); \
+ sp; \
+})
+
+static inline void *current_stack(void)
+{
+ return (void *)(current_stack_pointer & ~(THREAD_SIZE - 1));
+}
+
static inline int
execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
{
- union irq_ctx *curctx, *irqctx;
- u32 *isp, arg1, arg2;
+ struct irq_stack *curstk, *irqstk;
+ u32 *isp, *prev_esp, arg1, arg2;
- curctx = (union irq_ctx *) current_thread_info();
- irqctx = __this_cpu_read(hardirq_ctx);
+ curstk = (struct irq_stack *) current_stack();
+ irqstk = __this_cpu_read(hardirq_stack);
/*
* this is where we switch to the IRQ stack. However, if we are
@@ -92,13 +96,14 @@ execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
* handler) we can't do that and just have to keep using the
* current stack (which is the irq stack already after all)
*/
- if (unlikely(curctx == irqctx))
+ if (unlikely(curstk == irqstk))
return 0;
- /* build the stack frame on the IRQ stack */
- isp = (u32 *) ((char *)irqctx + sizeof(*irqctx));
- irqctx->tinfo.task = curctx->tinfo.task;
- irqctx->tinfo.previous_esp = current_stack_pointer;
+ isp = (u32 *) ((char *)irqstk + sizeof(*irqstk));
+
+ /* Save the next esp at the bottom of the stack */
+ prev_esp = (u32 *)irqstk;
+ *prev_esp = current_stack_pointer;
if (unlikely(overflow))
call_on_stack(print_stack_overflow, isp);
@@ -118,46 +123,40 @@ execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
*/
void irq_ctx_init(int cpu)
{
- union irq_ctx *irqctx;
+ struct irq_stack *irqstk;
- if (per_cpu(hardirq_ctx, cpu))
+ if (per_cpu(hardirq_stack, cpu))
return;
- irqctx = page_address(alloc_pages_node(cpu_to_node(cpu),
+ irqstk = page_address(alloc_pages_node(cpu_to_node(cpu),
THREADINFO_GFP,
THREAD_SIZE_ORDER));
- memset(&irqctx->tinfo, 0, sizeof(struct thread_info));
- irqctx->tinfo.cpu = cpu;
- irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
-
- per_cpu(hardirq_ctx, cpu) = irqctx;
+ per_cpu(hardirq_stack, cpu) = irqstk;
- irqctx = page_address(alloc_pages_node(cpu_to_node(cpu),
+ irqstk = page_address(alloc_pages_node(cpu_to_node(cpu),
THREADINFO_GFP,
THREAD_SIZE_ORDER));
- memset(&irqctx->tinfo, 0, sizeof(struct thread_info));
- irqctx->tinfo.cpu = cpu;
- irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
-
- per_cpu(softirq_ctx, cpu) = irqctx;
+ per_cpu(softirq_stack, cpu) = irqstk;
printk(KERN_DEBUG "CPU %u irqstacks, hard=%p soft=%p\n",
- cpu, per_cpu(hardirq_ctx, cpu), per_cpu(softirq_ctx, cpu));
+ cpu, per_cpu(hardirq_stack, cpu), per_cpu(softirq_stack, cpu));
}
void do_softirq_own_stack(void)
{
- struct thread_info *curctx;
- union irq_ctx *irqctx;
- u32 *isp;
+ struct thread_info *curstk;
+ struct irq_stack *irqstk;
+ u32 *isp, *prev_esp;
- curctx = current_thread_info();
- irqctx = __this_cpu_read(softirq_ctx);
- irqctx->tinfo.task = curctx->task;
- irqctx->tinfo.previous_esp = current_stack_pointer;
+ curstk = current_stack();
+ irqstk = __this_cpu_read(softirq_stack);
/* build the stack frame on the softirq stack */
- isp = (u32 *) ((char *)irqctx + sizeof(*irqctx));
+ isp = (u32 *) ((char *)irqstk + sizeof(*irqstk));
+
+ /* Push the previous esp onto the stack */
+ prev_esp = (u32 *)irqstk;
+ *prev_esp = current_stack_pointer;
call_on_stack(__do_softirq, isp);
}
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 713f1b3bad52..0331cb389d68 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -417,7 +417,6 @@ void kvm_disable_steal_time(void)
#ifdef CONFIG_SMP
static void __init kvm_smp_prepare_boot_cpu(void)
{
- WARN_ON(kvm_register_clock("primary cpu clock"));
kvm_guest_cpu_init();
native_smp_prepare_boot_cpu();
kvm_spinlock_init();
diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
index e6041094ff26..d9156ceecdff 100644
--- a/arch/x86/kernel/kvmclock.c
+++ b/arch/x86/kernel/kvmclock.c
@@ -242,7 +242,7 @@ void __init kvmclock_init(void)
hv_clock = __va(mem);
memset(hv_clock, 0, size);
- if (kvm_register_clock("boot clock")) {
+ if (kvm_register_clock("primary cpu clock")) {
hv_clock = NULL;
memblock_free(mem, size);
return;
diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c
index 4eabc160696f..679cef0791cd 100644
--- a/arch/x86/kernel/machine_kexec_64.c
+++ b/arch/x86/kernel/machine_kexec_64.c
@@ -279,5 +279,7 @@ void arch_crash_save_vmcoreinfo(void)
VMCOREINFO_SYMBOL(node_data);
VMCOREINFO_LENGTH(node_data, MAX_NUMNODES);
#endif
+ vmcoreinfo_append_str("KERNELOFFSET=%lx\n",
+ (unsigned long)&_text - __START_KERNEL);
}
diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c
index 18be189368bb..e69f9882bf95 100644
--- a/arch/x86/kernel/module.c
+++ b/arch/x86/kernel/module.c
@@ -28,6 +28,7 @@
#include <linux/mm.h>
#include <linux/gfp.h>
#include <linux/jump_label.h>
+#include <linux/random.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -43,13 +44,52 @@ do { \
} while (0)
#endif
+#ifdef CONFIG_RANDOMIZE_BASE
+static unsigned long module_load_offset;
+static int randomize_modules = 1;
+
+/* Mutex protects the module_load_offset. */
+static DEFINE_MUTEX(module_kaslr_mutex);
+
+static int __init parse_nokaslr(char *p)
+{
+ randomize_modules = 0;
+ return 0;
+}
+early_param("nokaslr", parse_nokaslr);
+
+static unsigned long int get_module_load_offset(void)
+{
+ if (randomize_modules) {
+ mutex_lock(&module_kaslr_mutex);
+ /*
+ * Calculate the module_load_offset the first time this
+ * code is called. Once calculated it stays the same until
+ * reboot.
+ */
+ if (module_load_offset == 0)
+ module_load_offset =
+ (get_random_int() % 1024 + 1) * PAGE_SIZE;
+ mutex_unlock(&module_kaslr_mutex);
+ }
+ return module_load_offset;
+}
+#else
+static unsigned long int get_module_load_offset(void)
+{
+ return 0;
+}
+#endif
+
void *module_alloc(unsigned long size)
{
if (PAGE_ALIGN(size) > MODULES_LEN)
return NULL;
- return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
- GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC,
- NUMA_NO_NODE, __builtin_return_address(0));
+ return __vmalloc_node_range(size, 1,
+ MODULES_VADDR + get_module_load_offset(),
+ MODULES_END, GFP_KERNEL | __GFP_HIGHMEM,
+ PAGE_KERNEL_EXEC, NUMA_NO_NODE,
+ __builtin_return_address(0));
}
#ifdef CONFIG_X86_32
diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c
index 6fcb49ce50a1..b4872b999a71 100644
--- a/arch/x86/kernel/nmi.c
+++ b/arch/x86/kernel/nmi.c
@@ -87,6 +87,7 @@ __setup("unknown_nmi_panic", setup_unknown_nmi_panic);
#define nmi_to_desc(type) (&nmi_desc[type])
static u64 nmi_longest_ns = 1 * NSEC_PER_MSEC;
+
static int __init nmi_warning_debugfs(void)
{
debugfs_create_u64("nmi_longest_ns", 0644,
@@ -95,6 +96,20 @@ static int __init nmi_warning_debugfs(void)
}
fs_initcall(nmi_warning_debugfs);
+static void nmi_max_handler(struct irq_work *w)
+{
+ struct nmiaction *a = container_of(w, struct nmiaction, irq_work);
+ int remainder_ns, decimal_msecs;
+ u64 whole_msecs = ACCESS_ONCE(a->max_duration);
+
+ remainder_ns = do_div(whole_msecs, (1000 * 1000));
+ decimal_msecs = remainder_ns / 1000;
+
+ printk_ratelimited(KERN_INFO
+ "INFO: NMI handler (%ps) took too long to run: %lld.%03d msecs\n",
+ a->handler, whole_msecs, decimal_msecs);
+}
+
static int __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2b)
{
struct nmi_desc *desc = nmi_to_desc(type);
@@ -110,26 +125,20 @@ static int __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2
* to handle those situations.
*/
list_for_each_entry_rcu(a, &desc->head, list) {
- u64 before, delta, whole_msecs;
- int remainder_ns, decimal_msecs, thishandled;
+ int thishandled;
+ u64 delta;
- before = sched_clock();
+ delta = sched_clock();
thishandled = a->handler(type, regs);
handled += thishandled;
- delta = sched_clock() - before;
+ delta = sched_clock() - delta;
trace_nmi_handler(a->handler, (int)delta, thishandled);
- if (delta < nmi_longest_ns)
+ if (delta < nmi_longest_ns || delta < a->max_duration)
continue;
- nmi_longest_ns = delta;
- whole_msecs = delta;
- remainder_ns = do_div(whole_msecs, (1000 * 1000));
- decimal_msecs = remainder_ns / 1000;
- printk_ratelimited(KERN_INFO
- "INFO: NMI handler (%ps) took too long to run: "
- "%lld.%03d msecs\n", a->handler, whole_msecs,
- decimal_msecs);
+ a->max_duration = delta;
+ irq_work_queue(&a->irq_work);
}
rcu_read_unlock();
@@ -146,6 +155,8 @@ int __register_nmi_handler(unsigned int type, struct nmiaction *action)
if (!action->handler)
return -EINVAL;
+ init_irq_work(&action->irq_work, nmi_max_handler);
+
spin_lock_irqsave(&desc->lock, flags);
/*
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index 872079a67e4d..f7d0672481fd 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -100,8 +100,10 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size,
flag |= __GFP_ZERO;
again:
page = NULL;
- if (!(flag & GFP_ATOMIC))
+ /* CMA can be used only in the context which permits sleeping */
+ if (flag & __GFP_WAIT)
page = dma_alloc_from_contiguous(dev, count, get_order(size));
+ /* fallback */
if (!page)
page = alloc_pages_node(dev_to_node(dev), flag, get_order(size));
if (!page)
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 3fb8d95ab8b5..4505e2a950d8 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -298,10 +298,7 @@ void arch_cpu_idle_dead(void)
*/
void arch_cpu_idle(void)
{
- if (cpuidle_idle_call())
- x86_idle();
- else
- local_irq_enable();
+ x86_idle();
}
/*
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 0de43e98ce08..7bc86bbe7485 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -314,6 +314,10 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
*/
arch_end_context_switch(next_p);
+ this_cpu_write(kernel_stack,
+ (unsigned long)task_stack_page(next_p) +
+ THREAD_SIZE - KERNEL_STACK_OFFSET);
+
/*
* Restore %gs if needed (which is common)
*/
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 7461f50d5bb1..678c0ada3b3c 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -184,14 +184,14 @@ unsigned long kernel_stack_pointer(struct pt_regs *regs)
{
unsigned long context = (unsigned long)regs & ~(THREAD_SIZE - 1);
unsigned long sp = (unsigned long)&regs->sp;
- struct thread_info *tinfo;
+ u32 *prev_esp;
if (context == (sp & ~(THREAD_SIZE - 1)))
return sp;
- tinfo = (struct thread_info *)context;
- if (tinfo->previous_esp)
- return tinfo->previous_esp;
+ prev_esp = (u32 *)(context);
+ if (prev_esp)
+ return (unsigned long)prev_esp;
return (unsigned long)regs;
}
diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c
index 7c6acd4b8995..ff898bbf579d 100644
--- a/arch/x86/kernel/quirks.c
+++ b/arch/x86/kernel/quirks.c
@@ -529,7 +529,7 @@ static void quirk_amd_nb_node(struct pci_dev *dev)
return;
pci_read_config_dword(nb_ht, 0x60, &val);
- node = val & 7;
+ node = pcibus_to_node(dev->bus) | (val & 7);
/*
* Some hardware may return an invalid node ID,
* so check it first:
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index c752cb43e52f..654b46574b91 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -464,9 +464,12 @@ void __attribute__((weak)) mach_reboot_fixups(void)
* 2) If still alive, write to the keyboard controller
* 3) If still alive, write to the ACPI reboot register again
* 4) If still alive, write to the keyboard controller again
+ * 5) If still alive, call the EFI runtime service to reboot
+ * 6) If still alive, write to the PCI IO port 0xCF9 to reboot
+ * 7) If still alive, inform BIOS to do a proper reboot
*
* If the machine is still alive at this stage, it gives up. We default to
- * following the same pattern, except that if we're still alive after (4) we'll
+ * following the same pattern, except that if we're still alive after (7) we'll
* try to force a triple fault and then cycle between hitting the keyboard
* controller and doing that
*/
@@ -502,7 +505,7 @@ static void native_machine_emergency_restart(void)
attempt = 1;
reboot_type = BOOT_ACPI;
} else {
- reboot_type = BOOT_TRIPLE;
+ reboot_type = BOOT_EFI;
}
break;
@@ -510,13 +513,15 @@ static void native_machine_emergency_restart(void)
load_idt(&no_idt);
__asm__ __volatile__("int3");
+ /* We're probably dead after this, but... */
reboot_type = BOOT_KBD;
break;
case BOOT_BIOS:
machine_real_restart(MRR_BIOS);
- reboot_type = BOOT_KBD;
+ /* We're probably dead after this, but... */
+ reboot_type = BOOT_TRIPLE;
break;
case BOOT_ACPI:
@@ -530,7 +535,7 @@ static void native_machine_emergency_restart(void)
EFI_RESET_WARM :
EFI_RESET_COLD,
EFI_SUCCESS, 0, NULL);
- reboot_type = BOOT_KBD;
+ reboot_type = BOOT_CF9_COND;
break;
case BOOT_CF9:
@@ -548,7 +553,7 @@ static void native_machine_emergency_restart(void)
outb(cf9|reboot_code, 0xcf9);
udelay(50);
}
- reboot_type = BOOT_KBD;
+ reboot_type = BOOT_BIOS;
break;
}
}
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 06853e670354..09c76d265550 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -869,7 +869,6 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_X86_32
memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
- visws_early_detect();
/*
* copy kernel address range established so far and switch
@@ -926,11 +925,11 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_EFI
if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
"EL32", 4)) {
- set_bit(EFI_BOOT, &x86_efi_facility);
+ set_bit(EFI_BOOT, &efi.flags);
} else if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
"EL64", 4)) {
- set_bit(EFI_BOOT, &x86_efi_facility);
- set_bit(EFI_64BIT, &x86_efi_facility);
+ set_bit(EFI_BOOT, &efi.flags);
+ set_bit(EFI_64BIT, &efi.flags);
}
if (efi_enabled(EFI_BOOT))
@@ -1239,14 +1238,8 @@ void __init setup_arch(char **cmdline_p)
register_refined_jiffies(CLOCK_TICK_RATE);
#ifdef CONFIG_EFI
- /* Once setup is done above, unmap the EFI memory map on
- * mismatched firmware/kernel archtectures since there is no
- * support for runtime services.
- */
- if (efi_enabled(EFI_BOOT) && !efi_is_native()) {
- pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n");
- efi_unmap_memmap();
- }
+ if (efi_enabled(EFI_BOOT))
+ efi_apply_memmap_quirks();
#endif
}
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index a32da804252e..34826934d4a7 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -122,8 +122,9 @@ static void smp_callin(void)
* Since CPU0 is not wakened up by INIT, it doesn't wait for the IPI.
*/
cpuid = smp_processor_id();
- if (apic->wait_for_init_deassert && cpuid != 0)
- apic->wait_for_init_deassert(&init_deasserted);
+ if (apic->wait_for_init_deassert && cpuid)
+ while (!atomic_read(&init_deasserted))
+ cpu_relax();
/*
* (This works even if the APIC is not enabled.)
@@ -701,11 +702,15 @@ wakeup_cpu_via_init_nmi(int cpu, unsigned long start_ip, int apicid,
int id;
int boot_error;
+ preempt_disable();
+
/*
* Wake up AP by INIT, INIT, STARTUP sequence.
*/
- if (cpu)
- return wakeup_secondary_cpu_via_init(apicid, start_ip);
+ if (cpu) {
+ boot_error = wakeup_secondary_cpu_via_init(apicid, start_ip);
+ goto out;
+ }
/*
* Wake up BSP by nmi.
@@ -725,6 +730,9 @@ wakeup_cpu_via_init_nmi(int cpu, unsigned long start_ip, int apicid,
boot_error = wakeup_secondary_cpu_via_nmi(id, start_ip);
}
+out:
+ preempt_enable();
+
return boot_error;
}
@@ -758,10 +766,10 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
#else
clear_tsk_thread_flag(idle, TIF_FORK);
initial_gs = per_cpu_offset(cpu);
+#endif
per_cpu(kernel_stack, cpu) =
(unsigned long)task_stack_page(idle) -
KERNEL_STACK_OFFSET + THREAD_SIZE;
-#endif
early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu);
initial_code = (unsigned long)start_secondary;
stack_start = idle->thread.sp;
@@ -1379,7 +1387,7 @@ static inline void mwait_play_dead(void)
if (!this_cpu_has(X86_FEATURE_MWAIT))
return;
- if (!this_cpu_has(X86_FEATURE_CLFLSH))
+ if (!this_cpu_has(X86_FEATURE_CLFLUSH))
return;
if (__this_cpu_read(cpu_info.cpuid_level) < CPUID_MWAIT_LEAF)
return;
diff --git a/arch/x86/kernel/time.c b/arch/x86/kernel/time.c
index 24d3c91e9812..bf7ef5ce29df 100644
--- a/arch/x86/kernel/time.c
+++ b/arch/x86/kernel/time.c
@@ -23,7 +23,7 @@
#include <asm/time.h>
#ifdef CONFIG_X86_64
-DEFINE_VVAR(volatile unsigned long, jiffies) = INITIAL_JIFFIES;
+__visible DEFINE_VVAR(volatile unsigned long, jiffies) = INITIAL_JIFFIES;
#endif
unsigned long profile_pc(struct pt_regs *regs)
@@ -62,7 +62,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
static struct irqaction irq0 = {
.handler = timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
+ .flags = IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
.name = "timer"
};
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 19e5adb49a27..57e5ce126d5a 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -209,7 +209,7 @@ static inline unsigned long long cycles_2_ns(unsigned long long cyc)
* dance when its actually needed.
*/
- preempt_disable();
+ preempt_disable_notrace();
data = this_cpu_read(cyc2ns.head);
tail = this_cpu_read(cyc2ns.tail);
@@ -229,7 +229,7 @@ static inline unsigned long long cycles_2_ns(unsigned long long cyc)
if (!--data->__count)
this_cpu_write(cyc2ns.tail, data);
}
- preempt_enable();
+ preempt_enable_notrace();
return ns;
}
@@ -653,13 +653,10 @@ unsigned long native_calibrate_tsc(void)
/* Calibrate TSC using MSR for Intel Atom SoCs */
local_irq_save(flags);
- i = try_msr_calibrate_tsc(&fast_calibrate);
+ fast_calibrate = try_msr_calibrate_tsc();
local_irq_restore(flags);
- if (i >= 0) {
- if (i == 0)
- pr_warn("Fast TSC calibration using MSR failed\n");
+ if (fast_calibrate)
return fast_calibrate;
- }
local_irq_save(flags);
fast_calibrate = quick_pit_calibrate();
@@ -917,8 +914,7 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
tsc_khz_ref = tsc_khz;
}
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
- (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
- (val == CPUFREQ_RESUMECHANGE)) {
+ (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
*lpj = cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
tsc_khz = cpufreq_scale(tsc_khz_ref, ref_freq, freq->new);
@@ -988,9 +984,7 @@ static struct clocksource clocksource_tsc = {
.mask = CLOCKSOURCE_MASK(64),
.flags = CLOCK_SOURCE_IS_CONTINUOUS |
CLOCK_SOURCE_MUST_VERIFY,
-#ifdef CONFIG_X86_64
.archdata = { .vclock_mode = VCLOCK_TSC },
-#endif
};
void mark_tsc_unstable(char *reason)
diff --git a/arch/x86/kernel/tsc_msr.c b/arch/x86/kernel/tsc_msr.c
index 8b5434f4389f..92ae6acac8a7 100644
--- a/arch/x86/kernel/tsc_msr.c
+++ b/arch/x86/kernel/tsc_msr.c
@@ -53,7 +53,7 @@ static struct freq_desc freq_desc_tables[] = {
/* TNG */
{ 6, 0x4a, 1, { 0, FREQ_100, FREQ_133, 0, 0, 0, 0, 0 } },
/* VLV2 */
- { 6, 0x37, 1, { 0, FREQ_100, FREQ_133, FREQ_166, 0, 0, 0, 0 } },
+ { 6, 0x37, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_166, 0, 0, 0, 0 } },
/* ANN */
{ 6, 0x5a, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_100, 0, 0, 0, 0 } },
};
@@ -77,21 +77,18 @@ static int match_cpu(u8 family, u8 model)
/*
* Do MSR calibration only for known/supported CPUs.
- * Return values:
- * -1: CPU is unknown/unsupported for MSR based calibration
- * 0: CPU is known/supported, but calibration failed
- * 1: CPU is known/supported, and calibration succeeded
+ *
+ * Returns the calibration value or 0 if MSR calibration failed.
*/
-int try_msr_calibrate_tsc(unsigned long *fast_calibrate)
+unsigned long try_msr_calibrate_tsc(void)
{
- int cpu_index;
u32 lo, hi, ratio, freq_id, freq;
+ unsigned long res;
+ int cpu_index;
cpu_index = match_cpu(boot_cpu_data.x86, boot_cpu_data.x86_model);
if (cpu_index < 0)
- return -1;
-
- *fast_calibrate = 0;
+ return 0;
if (freq_desc_tables[cpu_index].msr_plat) {
rdmsr(MSR_PLATFORM_INFO, lo, hi);
@@ -103,7 +100,7 @@ int try_msr_calibrate_tsc(unsigned long *fast_calibrate)
pr_info("Maximum core-clock to bus-clock ratio: 0x%x\n", ratio);
if (!ratio)
- return 0;
+ goto fail;
/* Get FSB FREQ ID */
rdmsr(MSR_FSB_FREQ, lo, hi);
@@ -112,16 +109,19 @@ int try_msr_calibrate_tsc(unsigned long *fast_calibrate)
pr_info("Resolved frequency ID: %u, frequency: %u KHz\n",
freq_id, freq);
if (!freq)
- return 0;
+ goto fail;
/* TSC frequency = maximum resolved freq * maximum resolved bus ratio */
- *fast_calibrate = freq * ratio;
- pr_info("TSC runs at %lu KHz\n", *fast_calibrate);
+ res = freq * ratio;
+ pr_info("TSC runs at %lu KHz\n", res);
#ifdef CONFIG_X86_LOCAL_APIC
lapic_timer_frequency = (freq * 1000) / HZ;
pr_info("lapic_timer_frequency = %d\n", lapic_timer_frequency);
#endif
+ return res;
- return 1;
+fail:
+ pr_warn("Fast TSC calibration using MSR failed\n");
+ return 0;
}
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index da6b35a98260..49edf2dd3613 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -147,7 +147,6 @@ SECTIONS
_edata = .;
} :data
-#ifdef CONFIG_X86_64
. = ALIGN(PAGE_SIZE);
__vvar_page = .;
@@ -165,12 +164,15 @@ SECTIONS
#undef __VVAR_KERNEL_LDS
#undef EMIT_VVAR
+ /*
+ * Pad the rest of the page with zeros. Otherwise the loader
+ * can leave garbage here.
+ */
+ . = __vvar_beginning_hack + PAGE_SIZE;
} :data
. = ALIGN(__vvar_page + PAGE_SIZE, PAGE_SIZE);
-#endif /* CONFIG_X86_64 */
-
/* Init code and data - will be freed after init */
. = ALIGN(PAGE_SIZE);
.init.begin : AT(ADDR(.init.begin) - LOAD_OFFSET) {
diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c
index 1f96f9347ed9..9ea287666c65 100644
--- a/arch/x86/kernel/vsyscall_64.c
+++ b/arch/x86/kernel/vsyscall_64.c
@@ -47,14 +47,12 @@
#include <asm/segment.h>
#include <asm/desc.h>
#include <asm/topology.h>
-#include <asm/vgtod.h>
#include <asm/traps.h>
#define CREATE_TRACE_POINTS
#include "vsyscall_trace.h"
DEFINE_VVAR(int, vgetcpu_mode);
-DEFINE_VVAR(struct vsyscall_gtod_data, vsyscall_gtod_data);
static enum { EMULATE, NATIVE, NONE } vsyscall_mode = EMULATE;
@@ -77,48 +75,6 @@ static int __init vsyscall_setup(char *str)
}
early_param("vsyscall", vsyscall_setup);
-void update_vsyscall_tz(void)
-{
- vsyscall_gtod_data.sys_tz = sys_tz;
-}
-
-void update_vsyscall(struct timekeeper *tk)
-{
- struct vsyscall_gtod_data *vdata = &vsyscall_gtod_data;
-
- write_seqcount_begin(&vdata->seq);
-
- /* copy vsyscall data */
- vdata->clock.vclock_mode = tk->clock->archdata.vclock_mode;
- vdata->clock.cycle_last = tk->clock->cycle_last;
- vdata->clock.mask = tk->clock->mask;
- vdata->clock.mult = tk->mult;
- vdata->clock.shift = tk->shift;
-
- vdata->wall_time_sec = tk->xtime_sec;
- vdata->wall_time_snsec = tk->xtime_nsec;
-
- vdata->monotonic_time_sec = tk->xtime_sec
- + tk->wall_to_monotonic.tv_sec;
- vdata->monotonic_time_snsec = tk->xtime_nsec
- + (tk->wall_to_monotonic.tv_nsec
- << tk->shift);
- while (vdata->monotonic_time_snsec >=
- (((u64)NSEC_PER_SEC) << tk->shift)) {
- vdata->monotonic_time_snsec -=
- ((u64)NSEC_PER_SEC) << tk->shift;
- vdata->monotonic_time_sec++;
- }
-
- vdata->wall_time_coarse.tv_sec = tk->xtime_sec;
- vdata->wall_time_coarse.tv_nsec = (long)(tk->xtime_nsec >> tk->shift);
-
- vdata->monotonic_time_coarse = timespec_add(vdata->wall_time_coarse,
- tk->wall_to_monotonic);
-
- write_seqcount_end(&vdata->seq);
-}
-
static void warn_bad_vsyscall(const char *level, struct pt_regs *regs,
const char *message)
{
@@ -374,7 +330,6 @@ void __init map_vsyscall(void)
{
extern char __vsyscall_page;
unsigned long physaddr_vsyscall = __pa_symbol(&__vsyscall_page);
- extern char __vvar_page;
unsigned long physaddr_vvar_page = __pa_symbol(&__vvar_page);
__set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_vsyscall,
diff --git a/arch/x86/kernel/vsyscall_gtod.c b/arch/x86/kernel/vsyscall_gtod.c
new file mode 100644
index 000000000000..f9c6e56e14b5
--- /dev/null
+++ b/arch/x86/kernel/vsyscall_gtod.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2001 Andrea Arcangeli <andrea@suse.de> SuSE
+ * Copyright 2003 Andi Kleen, SuSE Labs.
+ *
+ * Modified for x86 32 bit architecture by
+ * Stefani Seibold <stefani@seibold.net>
+ * sponsored by Rohde & Schwarz GmbH & Co. KG Munich/Germany
+ *
+ * Thanks to hpa@transmeta.com for some useful hint.
+ * Special thanks to Ingo Molnar for his early experience with
+ * a different vsyscall implementation for Linux/IA32 and for the name.
+ *
+ */
+
+#include <linux/timekeeper_internal.h>
+#include <asm/vgtod.h>
+#include <asm/vvar.h>
+
+DEFINE_VVAR(struct vsyscall_gtod_data, vsyscall_gtod_data);
+
+void update_vsyscall_tz(void)
+{
+ vsyscall_gtod_data.tz_minuteswest = sys_tz.tz_minuteswest;
+ vsyscall_gtod_data.tz_dsttime = sys_tz.tz_dsttime;
+}
+
+void update_vsyscall(struct timekeeper *tk)
+{
+ struct vsyscall_gtod_data *vdata = &vsyscall_gtod_data;
+
+ gtod_write_begin(vdata);
+
+ /* copy vsyscall data */
+ vdata->vclock_mode = tk->clock->archdata.vclock_mode;
+ vdata->cycle_last = tk->clock->cycle_last;
+ vdata->mask = tk->clock->mask;
+ vdata->mult = tk->mult;
+ vdata->shift = tk->shift;
+
+ vdata->wall_time_sec = tk->xtime_sec;
+ vdata->wall_time_snsec = tk->xtime_nsec;
+
+ vdata->monotonic_time_sec = tk->xtime_sec
+ + tk->wall_to_monotonic.tv_sec;
+ vdata->monotonic_time_snsec = tk->xtime_nsec
+ + (tk->wall_to_monotonic.tv_nsec
+ << tk->shift);
+ while (vdata->monotonic_time_snsec >=
+ (((u64)NSEC_PER_SEC) << tk->shift)) {
+ vdata->monotonic_time_snsec -=
+ ((u64)NSEC_PER_SEC) << tk->shift;
+ vdata->monotonic_time_sec++;
+ }
+
+ vdata->wall_time_coarse_sec = tk->xtime_sec;
+ vdata->wall_time_coarse_nsec = (long)(tk->xtime_nsec >> tk->shift);
+
+ vdata->monotonic_time_coarse_sec =
+ vdata->wall_time_coarse_sec + tk->wall_to_monotonic.tv_sec;
+ vdata->monotonic_time_coarse_nsec =
+ vdata->wall_time_coarse_nsec + tk->wall_to_monotonic.tv_nsec;
+
+ while (vdata->monotonic_time_coarse_nsec >= NSEC_PER_SEC) {
+ vdata->monotonic_time_coarse_nsec -= NSEC_PER_SEC;
+ vdata->monotonic_time_coarse_sec++;
+ }
+
+ gtod_write_end(vdata);
+}
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index c6976257eff5..bea60671ef8a 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -28,7 +28,7 @@ static u32 xstate_required_size(u64 xstate_bv)
int feature_bit = 0;
u32 ret = XSAVE_HDR_SIZE + XSAVE_HDR_OFFSET;
- xstate_bv &= ~XSTATE_FPSSE;
+ xstate_bv &= XSTATE_EXTEND_MASK;
while (xstate_bv) {
if (xstate_bv & 0x1) {
u32 eax, ebx, ecx, edx;
@@ -43,6 +43,16 @@ static u32 xstate_required_size(u64 xstate_bv)
return ret;
}
+u64 kvm_supported_xcr0(void)
+{
+ u64 xcr0 = KVM_SUPPORTED_XCR0 & host_xcr0;
+
+ if (!kvm_x86_ops->mpx_supported())
+ xcr0 &= ~(XSTATE_BNDREGS | XSTATE_BNDCSR);
+
+ return xcr0;
+}
+
void kvm_update_cpuid(struct kvm_vcpu *vcpu)
{
struct kvm_cpuid_entry2 *best;
@@ -73,9 +83,9 @@ void kvm_update_cpuid(struct kvm_vcpu *vcpu)
} else {
vcpu->arch.guest_supported_xcr0 =
(best->eax | ((u64)best->edx << 32)) &
- host_xcr0 & KVM_SUPPORTED_XCR0;
- vcpu->arch.guest_xstate_size =
- xstate_required_size(vcpu->arch.guest_supported_xcr0);
+ kvm_supported_xcr0();
+ vcpu->arch.guest_xstate_size = best->ebx =
+ xstate_required_size(vcpu->arch.xcr0);
}
kvm_pmu_cpuid_update(vcpu);
@@ -210,13 +220,6 @@ static void do_cpuid_1_ent(struct kvm_cpuid_entry2 *entry, u32 function,
entry->flags = 0;
}
-static bool supported_xcr0_bit(unsigned bit)
-{
- u64 mask = ((u64)1 << bit);
-
- return mask & KVM_SUPPORTED_XCR0 & host_xcr0;
-}
-
#define F(x) bit(X86_FEATURE_##x)
static int __do_cpuid_ent_emulated(struct kvm_cpuid_entry2 *entry,
@@ -256,6 +259,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
#endif
unsigned f_rdtscp = kvm_x86_ops->rdtscp_supported() ? F(RDTSCP) : 0;
unsigned f_invpcid = kvm_x86_ops->invpcid_supported() ? F(INVPCID) : 0;
+ unsigned f_mpx = kvm_x86_ops->mpx_supported() ? F(MPX) : 0;
/* cpuid 1.edx */
const u32 kvm_supported_word0_x86_features =
@@ -263,7 +267,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
F(TSC) | F(MSR) | F(PAE) | F(MCE) |
F(CX8) | F(APIC) | 0 /* Reserved */ | F(SEP) |
F(MTRR) | F(PGE) | F(MCA) | F(CMOV) |
- F(PAT) | F(PSE36) | 0 /* PSN */ | F(CLFLSH) |
+ F(PAT) | F(PSE36) | 0 /* PSN */ | F(CLFLUSH) |
0 /* Reserved, DS, ACPI */ | F(MMX) |
F(FXSR) | F(XMM) | F(XMM2) | F(SELFSNOOP) |
0 /* HTT, TM, Reserved, PBE */;
@@ -303,7 +307,8 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
/* cpuid 7.0.ebx */
const u32 kvm_supported_word9_x86_features =
F(FSGSBASE) | F(BMI1) | F(HLE) | F(AVX2) | F(SMEP) |
- F(BMI2) | F(ERMS) | f_invpcid | F(RTM);
+ F(BMI2) | F(ERMS) | f_invpcid | F(RTM) | f_mpx | F(RDSEED) |
+ F(ADX);
/* all calls to cpuid_count() should be made on the same cpu */
get_cpu();
@@ -436,16 +441,18 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
}
case 0xd: {
int idx, i;
+ u64 supported = kvm_supported_xcr0();
- entry->eax &= host_xcr0 & KVM_SUPPORTED_XCR0;
- entry->edx &= (host_xcr0 & KVM_SUPPORTED_XCR0) >> 32;
+ entry->eax &= supported;
+ entry->edx &= supported >> 32;
entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
for (idx = 1, i = 1; idx < 64; ++idx) {
+ u64 mask = ((u64)1 << idx);
if (*nent >= maxnent)
goto out;
do_cpuid_1_ent(&entry[i], function, idx);
- if (entry[i].eax == 0 || !supported_xcr0_bit(idx))
+ if (entry[i].eax == 0 || !(supported & mask))
continue;
entry[i].flags |=
KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 07ffca0a89e9..205b17eed93c 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -3668,6 +3668,10 @@ static const struct gprefix pfx_vmovntpx = {
I(0, em_mov), N, N, N,
};
+static const struct gprefix pfx_0f_28_0f_29 = {
+ I(Aligned, em_mov), I(Aligned, em_mov), N, N,
+};
+
static const struct escape escape_d9 = { {
N, N, N, N, N, N, N, I(DstMem, em_fnstcw),
}, {
@@ -3870,7 +3874,9 @@ static const struct opcode twobyte_table[256] = {
IIP(ModRM | SrcMem | Priv | Op3264, em_cr_write, cr_write, check_cr_write),
IIP(ModRM | SrcMem | Priv | Op3264, em_dr_write, dr_write, check_dr_write),
N, N, N, N,
- N, N, N, GP(ModRM | DstMem | SrcReg | Sse | Mov | Aligned, &pfx_vmovntpx),
+ GP(ModRM | DstReg | SrcMem | Mov | Sse, &pfx_0f_28_0f_29),
+ GP(ModRM | DstMem | SrcReg | Mov | Sse, &pfx_0f_28_0f_29),
+ N, GP(ModRM | DstMem | SrcReg | Sse | Mov | Aligned, &pfx_vmovntpx),
N, N, N, N,
/* 0x30 - 0x3F */
II(ImplicitOps | Priv, em_wrmsr, wrmsr),
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index e50425d0f5f7..f5704d9e5ddc 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -2672,6 +2672,7 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
break;
}
+ drop_large_spte(vcpu, iterator.sptep);
if (!is_shadow_present_pte(*iterator.sptep)) {
u64 base_addr = iterator.addr;
@@ -3328,7 +3329,7 @@ static int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn)
arch.direct_map = vcpu->arch.mmu.direct_map;
arch.cr3 = vcpu->arch.mmu.get_cr3(vcpu);
- return kvm_setup_async_pf(vcpu, gva, gfn, &arch);
+ return kvm_setup_async_pf(vcpu, gva, gfn_to_hva(vcpu->kvm, gfn), &arch);
}
static bool can_do_async_pf(struct kvm_vcpu *vcpu)
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index cba218a2f08d..b1e6c1bf68d3 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -913,7 +913,8 @@ static gpa_t FNAME(gva_to_gpa_nested)(struct kvm_vcpu *vcpu, gva_t vaddr,
* and kvm_mmu_notifier_invalidate_range_start detect the mapping page isn't
* used by guest then tlbs are not flushed, so guest is allowed to access the
* freed pages.
- * And we increase kvm->tlbs_dirty to delay tlbs flush in this case.
+ * We set tlbs_dirty to let the notifier know this change and delay the flush
+ * until such a case actually happens.
*/
static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
{
@@ -942,7 +943,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
return -EINVAL;
if (FNAME(prefetch_invalid_gpte)(vcpu, sp, &sp->spt[i], gpte)) {
- vcpu->kvm->tlbs_dirty++;
+ vcpu->kvm->tlbs_dirty = true;
continue;
}
@@ -957,7 +958,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
if (gfn != sp->gfns[i]) {
drop_spte(vcpu->kvm, &sp->spt[i]);
- vcpu->kvm->tlbs_dirty++;
+ vcpu->kvm->tlbs_dirty = true;
continue;
}
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index e81df8fce027..7f4f9c2badae 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -34,6 +34,7 @@
#include <asm/perf_event.h>
#include <asm/tlbflush.h>
#include <asm/desc.h>
+#include <asm/debugreg.h>
#include <asm/kvm_para.h>
#include <asm/virtext.h>
@@ -303,20 +304,35 @@ static inline bool is_cr_intercept(struct vcpu_svm *svm, int bit)
return vmcb->control.intercept_cr & (1U << bit);
}
-static inline void set_dr_intercept(struct vcpu_svm *svm, int bit)
+static inline void set_dr_intercepts(struct vcpu_svm *svm)
{
struct vmcb *vmcb = get_host_vmcb(svm);
- vmcb->control.intercept_dr |= (1U << bit);
+ vmcb->control.intercept_dr = (1 << INTERCEPT_DR0_READ)
+ | (1 << INTERCEPT_DR1_READ)
+ | (1 << INTERCEPT_DR2_READ)
+ | (1 << INTERCEPT_DR3_READ)
+ | (1 << INTERCEPT_DR4_READ)
+ | (1 << INTERCEPT_DR5_READ)
+ | (1 << INTERCEPT_DR6_READ)
+ | (1 << INTERCEPT_DR7_READ)
+ | (1 << INTERCEPT_DR0_WRITE)
+ | (1 << INTERCEPT_DR1_WRITE)
+ | (1 << INTERCEPT_DR2_WRITE)
+ | (1 << INTERCEPT_DR3_WRITE)
+ | (1 << INTERCEPT_DR4_WRITE)
+ | (1 << INTERCEPT_DR5_WRITE)
+ | (1 << INTERCEPT_DR6_WRITE)
+ | (1 << INTERCEPT_DR7_WRITE);
recalc_intercepts(svm);
}
-static inline void clr_dr_intercept(struct vcpu_svm *svm, int bit)
+static inline void clr_dr_intercepts(struct vcpu_svm *svm)
{
struct vmcb *vmcb = get_host_vmcb(svm);
- vmcb->control.intercept_dr &= ~(1U << bit);
+ vmcb->control.intercept_dr = 0;
recalc_intercepts(svm);
}
@@ -1080,23 +1096,7 @@ static void init_vmcb(struct vcpu_svm *svm)
set_cr_intercept(svm, INTERCEPT_CR4_WRITE);
set_cr_intercept(svm, INTERCEPT_CR8_WRITE);
- set_dr_intercept(svm, INTERCEPT_DR0_READ);
- set_dr_intercept(svm, INTERCEPT_DR1_READ);
- set_dr_intercept(svm, INTERCEPT_DR2_READ);
- set_dr_intercept(svm, INTERCEPT_DR3_READ);
- set_dr_intercept(svm, INTERCEPT_DR4_READ);
- set_dr_intercept(svm, INTERCEPT_DR5_READ);
- set_dr_intercept(svm, INTERCEPT_DR6_READ);
- set_dr_intercept(svm, INTERCEPT_DR7_READ);
-
- set_dr_intercept(svm, INTERCEPT_DR0_WRITE);
- set_dr_intercept(svm, INTERCEPT_DR1_WRITE);
- set_dr_intercept(svm, INTERCEPT_DR2_WRITE);
- set_dr_intercept(svm, INTERCEPT_DR3_WRITE);
- set_dr_intercept(svm, INTERCEPT_DR4_WRITE);
- set_dr_intercept(svm, INTERCEPT_DR5_WRITE);
- set_dr_intercept(svm, INTERCEPT_DR6_WRITE);
- set_dr_intercept(svm, INTERCEPT_DR7_WRITE);
+ set_dr_intercepts(svm);
set_exception_intercept(svm, PF_VECTOR);
set_exception_intercept(svm, UD_VECTOR);
@@ -1684,6 +1684,21 @@ static void svm_set_dr6(struct kvm_vcpu *vcpu, unsigned long value)
mark_dirty(svm->vmcb, VMCB_DR);
}
+static void svm_sync_dirty_debug_regs(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ get_debugreg(vcpu->arch.db[0], 0);
+ get_debugreg(vcpu->arch.db[1], 1);
+ get_debugreg(vcpu->arch.db[2], 2);
+ get_debugreg(vcpu->arch.db[3], 3);
+ vcpu->arch.dr6 = svm_get_dr6(vcpu);
+ vcpu->arch.dr7 = svm->vmcb->save.dr7;
+
+ vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_WONT_EXIT;
+ set_dr_intercepts(svm);
+}
+
static void svm_set_dr7(struct kvm_vcpu *vcpu, unsigned long value)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -2842,6 +2857,7 @@ static int iret_interception(struct vcpu_svm *svm)
clr_intercept(svm, INTERCEPT_IRET);
svm->vcpu.arch.hflags |= HF_IRET_MASK;
svm->nmi_iret_rip = kvm_rip_read(&svm->vcpu);
+ kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
return 1;
}
@@ -2974,6 +2990,17 @@ static int dr_interception(struct vcpu_svm *svm)
unsigned long val;
int err;
+ if (svm->vcpu.guest_debug == 0) {
+ /*
+ * No more DR vmexits; force a reload of the debug registers
+ * and reenter on this instruction. The next vmexit will
+ * retrieve the full state of the debug registers.
+ */
+ clr_dr_intercepts(svm);
+ svm->vcpu.arch.switch_db_regs |= KVM_DEBUGREG_WONT_EXIT;
+ return 1;
+ }
+
if (!boot_cpu_has(X86_FEATURE_DECODEASSISTS))
return emulate_on_interception(svm);
@@ -3002,10 +3029,8 @@ static int cr8_write_interception(struct vcpu_svm *svm)
u8 cr8_prev = kvm_get_cr8(&svm->vcpu);
/* instruction emulation calls kvm_set_cr8() */
r = cr_interception(svm);
- if (irqchip_in_kernel(svm->vcpu.kvm)) {
- clr_cr_intercept(svm, INTERCEPT_CR8_WRITE);
+ if (irqchip_in_kernel(svm->vcpu.kvm))
return r;
- }
if (cr8_prev <= kvm_get_cr8(&svm->vcpu))
return r;
kvm_run->exit_reason = KVM_EXIT_SET_TPR;
@@ -3567,6 +3592,8 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
if (is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK))
return;
+ clr_cr_intercept(svm, INTERCEPT_CR8_WRITE);
+
if (irr == -1)
return;
@@ -3649,7 +3676,7 @@ static int svm_interrupt_allowed(struct kvm_vcpu *vcpu)
return ret;
}
-static int enable_irq_window(struct kvm_vcpu *vcpu)
+static void enable_irq_window(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -3663,16 +3690,15 @@ static int enable_irq_window(struct kvm_vcpu *vcpu)
svm_set_vintr(svm);
svm_inject_irq(svm, 0x0);
}
- return 0;
}
-static int enable_nmi_window(struct kvm_vcpu *vcpu)
+static void enable_nmi_window(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
if ((svm->vcpu.arch.hflags & (HF_NMI_MASK | HF_IRET_MASK))
== HF_NMI_MASK)
- return 0; /* IRET will cause a vm exit */
+ return; /* IRET will cause a vm exit */
/*
* Something prevents NMI from been injected. Single step over possible
@@ -3681,7 +3707,6 @@ static int enable_nmi_window(struct kvm_vcpu *vcpu)
svm->nmi_singlestep = true;
svm->vmcb->save.rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF);
update_db_bp_intercept(vcpu);
- return 0;
}
static int svm_set_tss_addr(struct kvm *kvm, unsigned int addr)
@@ -4064,6 +4089,11 @@ static bool svm_invpcid_supported(void)
return false;
}
+static bool svm_mpx_supported(void)
+{
+ return false;
+}
+
static bool svm_has_wbinvd_exit(void)
{
return true;
@@ -4302,6 +4332,7 @@ static struct kvm_x86_ops svm_x86_ops = {
.get_dr6 = svm_get_dr6,
.set_dr6 = svm_set_dr6,
.set_dr7 = svm_set_dr7,
+ .sync_dirty_debug_regs = svm_sync_dirty_debug_regs,
.cache_reg = svm_cache_reg,
.get_rflags = svm_get_rflags,
.set_rflags = svm_set_rflags,
@@ -4345,6 +4376,7 @@ static struct kvm_x86_ops svm_x86_ops = {
.rdtscp_supported = svm_rdtscp_supported,
.invpcid_supported = svm_invpcid_supported,
+ .mpx_supported = svm_mpx_supported,
.set_supported_cpuid = svm_set_supported_cpuid,
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index a06f101ef64b..1320e0f8e611 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -31,6 +31,7 @@
#include <linux/ftrace_event.h>
#include <linux/slab.h>
#include <linux/tboot.h>
+#include <linux/hrtimer.h>
#include "kvm_cache_regs.h"
#include "x86.h"
@@ -42,6 +43,7 @@
#include <asm/i387.h>
#include <asm/xcr.h>
#include <asm/perf_event.h>
+#include <asm/debugreg.h>
#include <asm/kexec.h>
#include "trace.h"
@@ -110,6 +112,8 @@ module_param(nested, bool, S_IRUGO);
#define RMODE_GUEST_OWNED_EFLAGS_BITS (~(X86_EFLAGS_IOPL | X86_EFLAGS_VM))
+#define VMX_MISC_EMULATED_PREEMPTION_TIMER_RATE 5
+
/*
* These 2 parameters are used to config the controls for Pause-Loop Exiting:
* ple_gap: upper bound on the amount of time between two successive
@@ -202,6 +206,7 @@ struct __packed vmcs12 {
u64 guest_pdptr1;
u64 guest_pdptr2;
u64 guest_pdptr3;
+ u64 guest_bndcfgs;
u64 host_ia32_pat;
u64 host_ia32_efer;
u64 host_ia32_perf_global_ctrl;
@@ -374,6 +379,9 @@ struct nested_vmx {
*/
struct page *apic_access_page;
u64 msr_ia32_feature_control;
+
+ struct hrtimer preemption_timer;
+ bool preemption_timer_expired;
};
#define POSTED_INTR_ON 0
@@ -441,6 +449,7 @@ struct vcpu_vmx {
#endif
int gs_ldt_reload_needed;
int fs_reload_needed;
+ u64 msr_host_bndcfgs;
} host_state;
struct {
int vm86_active;
@@ -533,6 +542,7 @@ static const unsigned long shadow_read_write_fields[] = {
GUEST_CS_LIMIT,
GUEST_CS_BASE,
GUEST_ES_BASE,
+ GUEST_BNDCFGS,
CR0_GUEST_HOST_MASK,
CR0_READ_SHADOW,
CR4_READ_SHADOW,
@@ -588,6 +598,7 @@ static const unsigned short vmcs_field_to_offset_table[] = {
FIELD64(GUEST_PDPTR1, guest_pdptr1),
FIELD64(GUEST_PDPTR2, guest_pdptr2),
FIELD64(GUEST_PDPTR3, guest_pdptr3),
+ FIELD64(GUEST_BNDCFGS, guest_bndcfgs),
FIELD64(HOST_IA32_PAT, host_ia32_pat),
FIELD64(HOST_IA32_EFER, host_ia32_efer),
FIELD64(HOST_IA32_PERF_GLOBAL_CTRL, host_ia32_perf_global_ctrl),
@@ -718,6 +729,7 @@ static unsigned long nested_ept_get_cr3(struct kvm_vcpu *vcpu);
static u64 construct_eptp(unsigned long root_hpa);
static void kvm_cpu_vmxon(u64 addr);
static void kvm_cpu_vmxoff(void);
+static bool vmx_mpx_supported(void);
static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr);
static void vmx_set_segment(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg);
@@ -728,6 +740,7 @@ static u32 vmx_segment_access_rights(struct kvm_segment *var);
static void vmx_sync_pir_to_irr_dummy(struct kvm_vcpu *vcpu);
static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx);
static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx);
+static bool vmx_mpx_supported(void);
static DEFINE_PER_CPU(struct vmcs *, vmxarea);
static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
@@ -1047,6 +1060,12 @@ static inline bool nested_cpu_has_virtual_nmis(struct vmcs12 *vmcs12)
return vmcs12->pin_based_vm_exec_control & PIN_BASED_VIRTUAL_NMIS;
}
+static inline bool nested_cpu_has_preemption_timer(struct vmcs12 *vmcs12)
+{
+ return vmcs12->pin_based_vm_exec_control &
+ PIN_BASED_VMX_PREEMPTION_TIMER;
+}
+
static inline int nested_cpu_has_ept(struct vmcs12 *vmcs12)
{
return nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENABLE_EPT);
@@ -1710,6 +1729,8 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu)
if (is_long_mode(&vmx->vcpu))
wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
#endif
+ if (boot_cpu_has(X86_FEATURE_MPX))
+ rdmsrl(MSR_IA32_BNDCFGS, vmx->host_state.msr_host_bndcfgs);
for (i = 0; i < vmx->save_nmsrs; ++i)
kvm_set_shared_msr(vmx->guest_msrs[i].index,
vmx->guest_msrs[i].data,
@@ -1747,6 +1768,8 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx)
#ifdef CONFIG_X86_64
wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
#endif
+ if (vmx->host_state.msr_host_bndcfgs)
+ wrmsrl(MSR_IA32_BNDCFGS, vmx->host_state.msr_host_bndcfgs);
/*
* If the FPU is not active (through the host task or
* the guest vcpu), then restore the cr0.TS bit.
@@ -2248,9 +2271,9 @@ static __init void nested_vmx_setup_ctls_msrs(void)
*/
nested_vmx_pinbased_ctls_low |= PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR;
nested_vmx_pinbased_ctls_high &= PIN_BASED_EXT_INTR_MASK |
- PIN_BASED_NMI_EXITING | PIN_BASED_VIRTUAL_NMIS |
+ PIN_BASED_NMI_EXITING | PIN_BASED_VIRTUAL_NMIS;
+ nested_vmx_pinbased_ctls_high |= PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR |
PIN_BASED_VMX_PREEMPTION_TIMER;
- nested_vmx_pinbased_ctls_high |= PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR;
/*
* Exit controls
@@ -2265,15 +2288,12 @@ static __init void nested_vmx_setup_ctls_msrs(void)
#ifdef CONFIG_X86_64
VM_EXIT_HOST_ADDR_SPACE_SIZE |
#endif
- VM_EXIT_LOAD_IA32_PAT | VM_EXIT_SAVE_IA32_PAT |
+ VM_EXIT_LOAD_IA32_PAT | VM_EXIT_SAVE_IA32_PAT;
+ nested_vmx_exit_ctls_high |= VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR |
+ VM_EXIT_LOAD_IA32_EFER | VM_EXIT_SAVE_IA32_EFER |
VM_EXIT_SAVE_VMX_PREEMPTION_TIMER;
- if (!(nested_vmx_pinbased_ctls_high & PIN_BASED_VMX_PREEMPTION_TIMER) ||
- !(nested_vmx_exit_ctls_high & VM_EXIT_SAVE_VMX_PREEMPTION_TIMER)) {
- nested_vmx_exit_ctls_high &= ~VM_EXIT_SAVE_VMX_PREEMPTION_TIMER;
- nested_vmx_pinbased_ctls_high &= ~PIN_BASED_VMX_PREEMPTION_TIMER;
- }
- nested_vmx_exit_ctls_high |= (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR |
- VM_EXIT_LOAD_IA32_EFER | VM_EXIT_SAVE_IA32_EFER);
+ if (vmx_mpx_supported())
+ nested_vmx_exit_ctls_high |= VM_EXIT_CLEAR_BNDCFGS;
/* entry controls */
rdmsr(MSR_IA32_VMX_ENTRY_CTLS,
@@ -2287,6 +2307,8 @@ static __init void nested_vmx_setup_ctls_msrs(void)
VM_ENTRY_LOAD_IA32_PAT;
nested_vmx_entry_ctls_high |= (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR |
VM_ENTRY_LOAD_IA32_EFER);
+ if (vmx_mpx_supported())
+ nested_vmx_entry_ctls_high |= VM_ENTRY_LOAD_BNDCFGS;
/* cpu-based controls */
rdmsr(MSR_IA32_VMX_PROCBASED_CTLS,
@@ -2342,9 +2364,9 @@ static __init void nested_vmx_setup_ctls_msrs(void)
/* miscellaneous data */
rdmsr(MSR_IA32_VMX_MISC, nested_vmx_misc_low, nested_vmx_misc_high);
- nested_vmx_misc_low &= VMX_MISC_PREEMPTION_TIMER_RATE_MASK |
- VMX_MISC_SAVE_EFER_LMA;
- nested_vmx_misc_low |= VMX_MISC_ACTIVITY_HLT;
+ nested_vmx_misc_low &= VMX_MISC_SAVE_EFER_LMA;
+ nested_vmx_misc_low |= VMX_MISC_EMULATED_PREEMPTION_TIMER_RATE |
+ VMX_MISC_ACTIVITY_HLT;
nested_vmx_misc_high = 0;
}
@@ -2479,6 +2501,11 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
case MSR_IA32_SYSENTER_ESP:
data = vmcs_readl(GUEST_SYSENTER_ESP);
break;
+ case MSR_IA32_BNDCFGS:
+ if (!vmx_mpx_supported())
+ return 1;
+ data = vmcs_read64(GUEST_BNDCFGS);
+ break;
case MSR_IA32_FEATURE_CONTROL:
if (!nested_vmx_allowed(vcpu))
return 1;
@@ -2547,6 +2574,11 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
case MSR_IA32_SYSENTER_ESP:
vmcs_writel(GUEST_SYSENTER_ESP, data);
break;
+ case MSR_IA32_BNDCFGS:
+ if (!vmx_mpx_supported())
+ return 1;
+ vmcs_write64(GUEST_BNDCFGS, data);
+ break;
case MSR_IA32_TSC:
kvm_write_tsc(vcpu, msr_info);
break;
@@ -2832,12 +2864,12 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
vmx_capability.ept, vmx_capability.vpid);
}
- min = 0;
+ min = VM_EXIT_SAVE_DEBUG_CONTROLS;
#ifdef CONFIG_X86_64
min |= VM_EXIT_HOST_ADDR_SPACE_SIZE;
#endif
opt = VM_EXIT_SAVE_IA32_PAT | VM_EXIT_LOAD_IA32_PAT |
- VM_EXIT_ACK_INTR_ON_EXIT;
+ VM_EXIT_ACK_INTR_ON_EXIT | VM_EXIT_CLEAR_BNDCFGS;
if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS,
&_vmexit_control) < 0)
return -EIO;
@@ -2853,8 +2885,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
!(_vmexit_control & VM_EXIT_ACK_INTR_ON_EXIT))
_pin_based_exec_control &= ~PIN_BASED_POSTED_INTR;
- min = 0;
- opt = VM_ENTRY_LOAD_IA32_PAT;
+ min = VM_ENTRY_LOAD_DEBUG_CONTROLS;
+ opt = VM_ENTRY_LOAD_IA32_PAT | VM_ENTRY_LOAD_BNDCFGS;
if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_ENTRY_CTLS,
&_vmentry_control) < 0)
return -EIO;
@@ -4223,6 +4255,10 @@ static u32 vmx_pin_based_exec_ctrl(struct vcpu_vmx *vmx)
static u32 vmx_exec_control(struct vcpu_vmx *vmx)
{
u32 exec_control = vmcs_config.cpu_based_exec_ctrl;
+
+ if (vmx->vcpu.arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)
+ exec_control &= ~CPU_BASED_MOV_DR_EXITING;
+
if (!vm_need_tpr_shadow(vmx->vcpu.kvm)) {
exec_control &= ~CPU_BASED_TPR_SHADOW;
#ifdef CONFIG_X86_64
@@ -4496,39 +4532,28 @@ static bool nested_exit_on_nmi(struct kvm_vcpu *vcpu)
PIN_BASED_NMI_EXITING;
}
-static int enable_irq_window(struct kvm_vcpu *vcpu)
+static void enable_irq_window(struct kvm_vcpu *vcpu)
{
u32 cpu_based_vm_exec_control;
- if (is_guest_mode(vcpu) && nested_exit_on_intr(vcpu))
- /*
- * We get here if vmx_interrupt_allowed() said we can't
- * inject to L1 now because L2 must run. The caller will have
- * to make L2 exit right after entry, so we can inject to L1
- * more promptly.
- */
- return -EBUSY;
-
cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
- return 0;
}
-static int enable_nmi_window(struct kvm_vcpu *vcpu)
+static void enable_nmi_window(struct kvm_vcpu *vcpu)
{
u32 cpu_based_vm_exec_control;
- if (!cpu_has_virtual_nmis())
- return enable_irq_window(vcpu);
-
- if (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & GUEST_INTR_STATE_STI)
- return enable_irq_window(vcpu);
+ if (!cpu_has_virtual_nmis() ||
+ vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & GUEST_INTR_STATE_STI) {
+ enable_irq_window(vcpu);
+ return;
+ }
cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_NMI_PENDING;
vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
- return 0;
}
static void vmx_inject_irq(struct kvm_vcpu *vcpu)
@@ -4620,22 +4645,8 @@ static void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked)
static int vmx_nmi_allowed(struct kvm_vcpu *vcpu)
{
- if (is_guest_mode(vcpu)) {
- if (to_vmx(vcpu)->nested.nested_run_pending)
- return 0;
- if (nested_exit_on_nmi(vcpu)) {
- nested_vmx_vmexit(vcpu, EXIT_REASON_EXCEPTION_NMI,
- NMI_VECTOR | INTR_TYPE_NMI_INTR |
- INTR_INFO_VALID_MASK, 0);
- /*
- * The NMI-triggered VM exit counts as injection:
- * clear this one and block further NMIs.
- */
- vcpu->arch.nmi_pending = 0;
- vmx_set_nmi_mask(vcpu, true);
- return 0;
- }
- }
+ if (to_vmx(vcpu)->nested.nested_run_pending)
+ return 0;
if (!cpu_has_virtual_nmis() && to_vmx(vcpu)->soft_vnmi_blocked)
return 0;
@@ -4647,19 +4658,8 @@ static int vmx_nmi_allowed(struct kvm_vcpu *vcpu)
static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu)
{
- if (is_guest_mode(vcpu)) {
- if (to_vmx(vcpu)->nested.nested_run_pending)
- return 0;
- if (nested_exit_on_intr(vcpu)) {
- nested_vmx_vmexit(vcpu, EXIT_REASON_EXTERNAL_INTERRUPT,
- 0, 0);
- /*
- * fall through to normal code, but now in L1, not L2
- */
- }
- }
-
- return (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
+ return (!to_vmx(vcpu)->nested.nested_run_pending &&
+ vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
!(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) &
(GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS));
}
@@ -5102,6 +5102,22 @@ static int handle_dr(struct kvm_vcpu *vcpu)
}
}
+ if (vcpu->guest_debug == 0) {
+ u32 cpu_based_vm_exec_control;
+
+ cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+ cpu_based_vm_exec_control &= ~CPU_BASED_MOV_DR_EXITING;
+ vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
+
+ /*
+ * No more DR vmexits; force a reload of the debug registers
+ * and reenter on this instruction. The next vmexit will
+ * retrieve the full state of the debug registers.
+ */
+ vcpu->arch.switch_db_regs |= KVM_DEBUGREG_WONT_EXIT;
+ return 1;
+ }
+
exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
dr = exit_qualification & DEBUG_REG_ACCESS_NUM;
reg = DEBUG_REG_ACCESS_REG(exit_qualification);
@@ -5128,6 +5144,24 @@ static void vmx_set_dr6(struct kvm_vcpu *vcpu, unsigned long val)
{
}
+static void vmx_sync_dirty_debug_regs(struct kvm_vcpu *vcpu)
+{
+ u32 cpu_based_vm_exec_control;
+
+ get_debugreg(vcpu->arch.db[0], 0);
+ get_debugreg(vcpu->arch.db[1], 1);
+ get_debugreg(vcpu->arch.db[2], 2);
+ get_debugreg(vcpu->arch.db[3], 3);
+ get_debugreg(vcpu->arch.dr6, 6);
+ vcpu->arch.dr7 = vmcs_readl(GUEST_DR7);
+
+ vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_WONT_EXIT;
+
+ cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+ cpu_based_vm_exec_control |= CPU_BASED_MOV_DR_EXITING;
+ vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
+}
+
static void vmx_set_dr7(struct kvm_vcpu *vcpu, unsigned long val)
{
vmcs_writel(GUEST_DR7, val);
@@ -5727,6 +5761,18 @@ static void nested_vmx_failValid(struct kvm_vcpu *vcpu,
*/
}
+static enum hrtimer_restart vmx_preemption_timer_fn(struct hrtimer *timer)
+{
+ struct vcpu_vmx *vmx =
+ container_of(timer, struct vcpu_vmx, nested.preemption_timer);
+
+ vmx->nested.preemption_timer_expired = true;
+ kvm_make_request(KVM_REQ_EVENT, &vmx->vcpu);
+ kvm_vcpu_kick(&vmx->vcpu);
+
+ return HRTIMER_NORESTART;
+}
+
/*
* Emulate the VMXON instruction.
* Currently, we just remember that VMX is active, and do not save or even
@@ -5791,6 +5837,10 @@ static int handle_vmon(struct kvm_vcpu *vcpu)
INIT_LIST_HEAD(&(vmx->nested.vmcs02_pool));
vmx->nested.vmcs02_num = 0;
+ hrtimer_init(&vmx->nested.preemption_timer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ vmx->nested.preemption_timer.function = vmx_preemption_timer_fn;
+
vmx->nested.vmxon = true;
skip_emulated_instruction(vcpu);
@@ -6688,7 +6738,7 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu)
else if (is_page_fault(intr_info))
return enable_ept;
else if (is_no_device(intr_info) &&
- !(nested_read_cr0(vmcs12) & X86_CR0_TS))
+ !(vmcs12->guest_cr0 & X86_CR0_TS))
return 0;
return vmcs12->exception_bitmap &
(1u << (intr_info & INTR_INFO_VECTOR_MASK));
@@ -6767,9 +6817,6 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu)
* table is L0's fault.
*/
return 0;
- case EXIT_REASON_PREEMPTION_TIMER:
- return vmcs12->pin_based_vm_exec_control &
- PIN_BASED_VMX_PREEMPTION_TIMER;
case EXIT_REASON_WBINVD:
return nested_cpu_has2(vmcs12, SECONDARY_EXEC_WBINVD_EXITING);
case EXIT_REASON_XSETBV:
@@ -6785,27 +6832,6 @@ static void vmx_get_exit_info(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2)
*info2 = vmcs_read32(VM_EXIT_INTR_INFO);
}
-static void nested_adjust_preemption_timer(struct kvm_vcpu *vcpu)
-{
- u64 delta_tsc_l1;
- u32 preempt_val_l1, preempt_val_l2, preempt_scale;
-
- if (!(get_vmcs12(vcpu)->pin_based_vm_exec_control &
- PIN_BASED_VMX_PREEMPTION_TIMER))
- return;
- preempt_scale = native_read_msr(MSR_IA32_VMX_MISC) &
- MSR_IA32_VMX_MISC_PREEMPTION_TIMER_SCALE;
- preempt_val_l2 = vmcs_read32(VMX_PREEMPTION_TIMER_VALUE);
- delta_tsc_l1 = vmx_read_l1_tsc(vcpu, native_read_tsc())
- - vcpu->arch.last_guest_tsc;
- preempt_val_l1 = delta_tsc_l1 >> preempt_scale;
- if (preempt_val_l2 <= preempt_val_l1)
- preempt_val_l2 = 0;
- else
- preempt_val_l2 -= preempt_val_l1;
- vmcs_write32(VMX_PREEMPTION_TIMER_VALUE, preempt_val_l2);
-}
-
/*
* The guest has exited. See if we can fix it or if we need userspace
* assistance.
@@ -7052,6 +7078,12 @@ static void vmx_handle_external_intr(struct kvm_vcpu *vcpu)
local_irq_enable();
}
+static bool vmx_mpx_supported(void)
+{
+ return (vmcs_config.vmexit_ctrl & VM_EXIT_CLEAR_BNDCFGS) &&
+ (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_BNDCFGS);
+}
+
static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx)
{
u32 exit_intr_info;
@@ -7218,8 +7250,6 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
atomic_switch_perf_msrs(vmx);
debugctlmsr = get_debugctlmsr();
- if (is_guest_mode(vcpu) && !vmx->nested.nested_run_pending)
- nested_adjust_preemption_timer(vcpu);
vmx->__launched = vmx->loaded_vmcs->launched;
asm(
/* Store host registers */
@@ -7616,6 +7646,28 @@ static void vmx_inject_page_fault_nested(struct kvm_vcpu *vcpu,
kvm_inject_page_fault(vcpu, fault);
}
+static void vmx_start_preemption_timer(struct kvm_vcpu *vcpu)
+{
+ u64 preemption_timeout = get_vmcs12(vcpu)->vmx_preemption_timer_value;
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+ if (vcpu->arch.virtual_tsc_khz == 0)
+ return;
+
+ /* Make sure short timeouts reliably trigger an immediate vmexit.
+ * hrtimer_start does not guarantee this. */
+ if (preemption_timeout <= 1) {
+ vmx_preemption_timer_fn(&vmx->nested.preemption_timer);
+ return;
+ }
+
+ preemption_timeout <<= VMX_MISC_EMULATED_PREEMPTION_TIMER_RATE;
+ preemption_timeout *= 1000000;
+ do_div(preemption_timeout, vcpu->arch.virtual_tsc_khz);
+ hrtimer_start(&vmx->nested.preemption_timer,
+ ns_to_ktime(preemption_timeout), HRTIMER_MODE_REL);
+}
+
/*
* prepare_vmcs02 is called when the L1 guest hypervisor runs its nested
* L2 guest. L1 has a vmcs for L2 (vmcs12), and this function "merges" it
@@ -7629,7 +7681,6 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
u32 exec_control;
- u32 exit_control;
vmcs_write16(GUEST_ES_SELECTOR, vmcs12->guest_es_selector);
vmcs_write16(GUEST_CS_SELECTOR, vmcs12->guest_cs_selector);
@@ -7687,13 +7738,14 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
vmcs_write64(VMCS_LINK_POINTER, -1ull);
- vmcs_write32(PIN_BASED_VM_EXEC_CONTROL,
- (vmcs_config.pin_based_exec_ctrl |
- vmcs12->pin_based_vm_exec_control));
+ exec_control = vmcs12->pin_based_vm_exec_control;
+ exec_control |= vmcs_config.pin_based_exec_ctrl;
+ exec_control &= ~PIN_BASED_VMX_PREEMPTION_TIMER;
+ vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, exec_control);
- if (vmcs12->pin_based_vm_exec_control & PIN_BASED_VMX_PREEMPTION_TIMER)
- vmcs_write32(VMX_PREEMPTION_TIMER_VALUE,
- vmcs12->vmx_preemption_timer_value);
+ vmx->nested.preemption_timer_expired = false;
+ if (nested_cpu_has_preemption_timer(vmcs12))
+ vmx_start_preemption_timer(vcpu);
/*
* Whether page-faults are trapped is determined by a combination of
@@ -7721,7 +7773,7 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
enable_ept ? vmcs12->page_fault_error_code_match : 0);
if (cpu_has_secondary_exec_ctrls()) {
- u32 exec_control = vmx_secondary_exec_control(vmx);
+ exec_control = vmx_secondary_exec_control(vmx);
if (!vmx->rdtscp_enabled)
exec_control &= ~SECONDARY_EXEC_RDTSCP;
/* Take the following fields only from vmcs12 */
@@ -7808,10 +7860,7 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
* we should use its exit controls. Note that VM_EXIT_LOAD_IA32_EFER
* bits are further modified by vmx_set_efer() below.
*/
- exit_control = vmcs_config.vmexit_ctrl;
- if (vmcs12->pin_based_vm_exec_control & PIN_BASED_VMX_PREEMPTION_TIMER)
- exit_control |= VM_EXIT_SAVE_VMX_PREEMPTION_TIMER;
- vm_exit_controls_init(vmx, exit_control);
+ vmcs_write32(VM_EXIT_CONTROLS, vmcs_config.vmexit_ctrl);
/* vmcs12's VM_ENTRY_LOAD_IA32_EFER and VM_ENTRY_IA32E_MODE are
* emulated by vmx_set_efer(), below.
@@ -7830,6 +7879,9 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
set_cr4_guest_host_mask(vmx);
+ if (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS)
+ vmcs_write64(GUEST_BNDCFGS, vmcs12->guest_bndcfgs);
+
if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING)
vmcs_write64(TSC_OFFSET,
vmx->nested.vmcs01_tsc_offset + vmcs12->tsc_offset);
@@ -8155,6 +8207,58 @@ static void vmcs12_save_pending_event(struct kvm_vcpu *vcpu,
}
}
+static int vmx_check_nested_events(struct kvm_vcpu *vcpu, bool external_intr)
+{
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+ if (nested_cpu_has_preemption_timer(get_vmcs12(vcpu)) &&
+ vmx->nested.preemption_timer_expired) {
+ if (vmx->nested.nested_run_pending)
+ return -EBUSY;
+ nested_vmx_vmexit(vcpu, EXIT_REASON_PREEMPTION_TIMER, 0, 0);
+ return 0;
+ }
+
+ if (vcpu->arch.nmi_pending && nested_exit_on_nmi(vcpu)) {
+ if (vmx->nested.nested_run_pending ||
+ vcpu->arch.interrupt.pending)
+ return -EBUSY;
+ nested_vmx_vmexit(vcpu, EXIT_REASON_EXCEPTION_NMI,
+ NMI_VECTOR | INTR_TYPE_NMI_INTR |
+ INTR_INFO_VALID_MASK, 0);
+ /*
+ * The NMI-triggered VM exit counts as injection:
+ * clear this one and block further NMIs.
+ */
+ vcpu->arch.nmi_pending = 0;
+ vmx_set_nmi_mask(vcpu, true);
+ return 0;
+ }
+
+ if ((kvm_cpu_has_interrupt(vcpu) || external_intr) &&
+ nested_exit_on_intr(vcpu)) {
+ if (vmx->nested.nested_run_pending)
+ return -EBUSY;
+ nested_vmx_vmexit(vcpu, EXIT_REASON_EXTERNAL_INTERRUPT, 0, 0);
+ }
+
+ return 0;
+}
+
+static u32 vmx_get_preemption_timer_value(struct kvm_vcpu *vcpu)
+{
+ ktime_t remaining =
+ hrtimer_get_remaining(&to_vmx(vcpu)->nested.preemption_timer);
+ u64 value;
+
+ if (ktime_to_ns(remaining) <= 0)
+ return 0;
+
+ value = ktime_to_ns(remaining) * vcpu->arch.virtual_tsc_khz;
+ do_div(value, 1000000);
+ return value >> VMX_MISC_EMULATED_PREEMPTION_TIMER_RATE;
+}
+
/*
* prepare_vmcs12 is part of what we need to do when the nested L2 guest exits
* and we want to prepare to run its L1 parent. L1 keeps a vmcs for L2 (vmcs12),
@@ -8225,10 +8329,13 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
else
vmcs12->guest_activity_state = GUEST_ACTIVITY_ACTIVE;
- if ((vmcs12->pin_based_vm_exec_control & PIN_BASED_VMX_PREEMPTION_TIMER) &&
- (vmcs12->vm_exit_controls & VM_EXIT_SAVE_VMX_PREEMPTION_TIMER))
- vmcs12->vmx_preemption_timer_value =
- vmcs_read32(VMX_PREEMPTION_TIMER_VALUE);
+ if (nested_cpu_has_preemption_timer(vmcs12)) {
+ if (vmcs12->vm_exit_controls &
+ VM_EXIT_SAVE_VMX_PREEMPTION_TIMER)
+ vmcs12->vmx_preemption_timer_value =
+ vmx_get_preemption_timer_value(vcpu);
+ hrtimer_cancel(&to_vmx(vcpu)->nested.preemption_timer);
+ }
/*
* In some cases (usually, nested EPT), L2 is allowed to change its
@@ -8260,6 +8367,8 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
vmcs12->guest_sysenter_cs = vmcs_read32(GUEST_SYSENTER_CS);
vmcs12->guest_sysenter_esp = vmcs_readl(GUEST_SYSENTER_ESP);
vmcs12->guest_sysenter_eip = vmcs_readl(GUEST_SYSENTER_EIP);
+ if (vmx_mpx_supported())
+ vmcs12->guest_bndcfgs = vmcs_read64(GUEST_BNDCFGS);
/* update exit information fields: */
@@ -8369,6 +8478,10 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu,
vmcs_writel(GUEST_IDTR_BASE, vmcs12->host_idtr_base);
vmcs_writel(GUEST_GDTR_BASE, vmcs12->host_gdtr_base);
+ /* If not VM_EXIT_CLEAR_BNDCFGS, the L2 value propagates to L1. */
+ if (vmcs12->vm_exit_controls & VM_EXIT_CLEAR_BNDCFGS)
+ vmcs_write64(GUEST_BNDCFGS, 0);
+
if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_PAT) {
vmcs_write64(GUEST_IA32_PAT, vmcs12->host_ia32_pat);
vcpu->arch.pat = vmcs12->host_ia32_pat;
@@ -8495,6 +8608,9 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
nested_vmx_succeed(vcpu);
if (enable_shadow_vmcs)
vmx->nested.sync_shadow_vmcs = true;
+
+ /* in case we halted in L2 */
+ vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
}
/*
@@ -8573,6 +8689,7 @@ static struct kvm_x86_ops vmx_x86_ops = {
.get_dr6 = vmx_get_dr6,
.set_dr6 = vmx_set_dr6,
.set_dr7 = vmx_set_dr7,
+ .sync_dirty_debug_regs = vmx_sync_dirty_debug_regs,
.cache_reg = vmx_cache_reg,
.get_rflags = vmx_get_rflags,
.set_rflags = vmx_set_rflags,
@@ -8634,6 +8751,9 @@ static struct kvm_x86_ops vmx_x86_ops = {
.check_intercept = vmx_check_intercept,
.handle_external_intr = vmx_handle_external_intr,
+ .mpx_supported = vmx_mpx_supported,
+
+ .check_nested_events = vmx_check_nested_events,
};
static int __init vmx_init(void)
@@ -8721,6 +8841,8 @@ static int __init vmx_init(void)
vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_CS, false);
vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_ESP, false);
vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false);
+ vmx_disable_intercept_for_msr(MSR_IA32_BNDCFGS, true);
+
memcpy(vmx_msr_bitmap_legacy_x2apic,
vmx_msr_bitmap_legacy, PAGE_SIZE);
memcpy(vmx_msr_bitmap_longmode_x2apic,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 39c28f09dfd5..d1c55f8722c6 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -595,13 +595,13 @@ static void kvm_put_guest_xcr0(struct kvm_vcpu *vcpu)
int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)
{
- u64 xcr0;
+ u64 xcr0 = xcr;
+ u64 old_xcr0 = vcpu->arch.xcr0;
u64 valid_bits;
/* Only support XCR_XFEATURE_ENABLED_MASK(xcr0) now */
if (index != XCR_XFEATURE_ENABLED_MASK)
return 1;
- xcr0 = xcr;
if (!(xcr0 & XSTATE_FP))
return 1;
if ((xcr0 & XSTATE_YMM) && !(xcr0 & XSTATE_SSE))
@@ -616,8 +616,14 @@ int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)
if (xcr0 & ~valid_bits)
return 1;
+ if ((!(xcr0 & XSTATE_BNDREGS)) != (!(xcr0 & XSTATE_BNDCSR)))
+ return 1;
+
kvm_put_guest_xcr0(vcpu);
vcpu->arch.xcr0 = xcr0;
+
+ if ((xcr0 ^ old_xcr0) & XSTATE_EXTEND_MASK)
+ kvm_update_cpuid(vcpu);
return 0;
}
@@ -753,7 +759,9 @@ static void kvm_update_dr7(struct kvm_vcpu *vcpu)
else
dr7 = vcpu->arch.dr7;
kvm_x86_ops->set_dr7(vcpu, dr7);
- vcpu->arch.switch_db_regs = (dr7 & DR7_BP_EN_MASK);
+ vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_BP_ENABLED;
+ if (dr7 & DR7_BP_EN_MASK)
+ vcpu->arch.switch_db_regs |= KVM_DEBUGREG_BP_ENABLED;
}
static int __kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
@@ -879,7 +887,7 @@ static u32 msrs_to_save[] = {
MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
#endif
MSR_IA32_TSC, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA,
- MSR_IA32_FEATURE_CONTROL
+ MSR_IA32_FEATURE_CONTROL, MSR_IA32_BNDCFGS
};
static unsigned num_msrs_to_save;
@@ -1581,7 +1589,6 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
/* With all the info we got, fill in the values */
vcpu->hv_clock.tsc_timestamp = tsc_timestamp;
vcpu->hv_clock.system_time = kernel_ns + v->kvm->arch.kvmclock_offset;
- vcpu->last_kernel_ns = kernel_ns;
vcpu->last_guest_tsc = tsc_timestamp;
/*
@@ -1623,14 +1630,21 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
* the others.
*
* So in those cases, request a kvmclock update for all vcpus.
- * The worst case for a remote vcpu to update its kvmclock
- * is then bounded by maximum nohz sleep latency.
+ * We need to rate-limit these requests though, as they can
+ * considerably slow guests that have a large number of vcpus.
+ * The time for a remote vcpu to update its kvmclock is bound
+ * by the delay we use to rate-limit the updates.
*/
-static void kvm_gen_kvmclock_update(struct kvm_vcpu *v)
+#define KVMCLOCK_UPDATE_DELAY msecs_to_jiffies(100)
+
+static void kvmclock_update_fn(struct work_struct *work)
{
int i;
- struct kvm *kvm = v->kvm;
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct kvm_arch *ka = container_of(dwork, struct kvm_arch,
+ kvmclock_update_work);
+ struct kvm *kvm = container_of(ka, struct kvm, arch);
struct kvm_vcpu *vcpu;
kvm_for_each_vcpu(i, vcpu, kvm) {
@@ -1639,6 +1653,29 @@ static void kvm_gen_kvmclock_update(struct kvm_vcpu *v)
}
}
+static void kvm_gen_kvmclock_update(struct kvm_vcpu *v)
+{
+ struct kvm *kvm = v->kvm;
+
+ set_bit(KVM_REQ_CLOCK_UPDATE, &v->requests);
+ schedule_delayed_work(&kvm->arch.kvmclock_update_work,
+ KVMCLOCK_UPDATE_DELAY);
+}
+
+#define KVMCLOCK_SYNC_PERIOD (300 * HZ)
+
+static void kvmclock_sync_fn(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct kvm_arch *ka = container_of(dwork, struct kvm_arch,
+ kvmclock_sync_work);
+ struct kvm *kvm = container_of(ka, struct kvm, arch);
+
+ schedule_delayed_work(&kvm->arch.kvmclock_update_work, 0);
+ schedule_delayed_work(&kvm->arch.kvmclock_sync_work,
+ KVMCLOCK_SYNC_PERIOD);
+}
+
static bool msr_mtrr_valid(unsigned msr)
{
switch (msr) {
@@ -2323,9 +2360,12 @@ static int get_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
case HV_X64_MSR_VP_INDEX: {
int r;
struct kvm_vcpu *v;
- kvm_for_each_vcpu(r, v, vcpu->kvm)
- if (v == vcpu)
+ kvm_for_each_vcpu(r, v, vcpu->kvm) {
+ if (v == vcpu) {
data = r;
+ break;
+ }
+ }
break;
}
case HV_X64_MSR_EOI:
@@ -2617,6 +2657,7 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_KVMCLOCK_CTRL:
case KVM_CAP_READONLY_MEM:
case KVM_CAP_HYPERV_TIME:
+ case KVM_CAP_IOAPIC_POLARITY_IGNORED:
#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
case KVM_CAP_ASSIGN_DEV_IRQ:
case KVM_CAP_PCI_2_3:
@@ -3043,9 +3084,7 @@ static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
* CPUID leaf 0xD, index 0, EDX:EAX. This is for compatibility
* with old userspace.
*/
- if (xstate_bv & ~KVM_SUPPORTED_XCR0)
- return -EINVAL;
- if (xstate_bv & ~host_xcr0)
+ if (xstate_bv & ~kvm_supported_xcr0())
return -EINVAL;
memcpy(&vcpu->arch.guest_fpu.state->xsave,
guest_xsave->region, vcpu->arch.guest_xstate_size);
@@ -3898,6 +3937,23 @@ static void kvm_init_msr_list(void)
for (i = j = KVM_SAVE_MSRS_BEGIN; i < ARRAY_SIZE(msrs_to_save); i++) {
if (rdmsr_safe(msrs_to_save[i], &dummy[0], &dummy[1]) < 0)
continue;
+
+ /*
+ * Even MSRs that are valid in the host may not be exposed
+ * to the guests in some cases. We could work around this
+ * in VMX with the generic MSR save/load machinery, but it
+ * is not really worthwhile since it will really only
+ * happen with nested virtualization.
+ */
+ switch (msrs_to_save[i]) {
+ case MSR_IA32_BNDCFGS:
+ if (!kvm_x86_ops->mpx_supported())
+ continue;
+ break;
+ default:
+ break;
+ }
+
if (j < i)
msrs_to_save[j] = msrs_to_save[i];
j++;
@@ -4394,6 +4450,7 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt,
if (!exchanged)
return X86EMUL_CMPXCHG_FAILED;
+ mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT);
kvm_mmu_pte_write(vcpu, gpa, new, bytes);
return X86EMUL_CONTINUE;
@@ -5537,9 +5594,10 @@ int kvm_arch_init(void *opaque)
goto out_free_percpu;
kvm_set_mmio_spte_mask();
- kvm_init_msr_list();
kvm_x86_ops = ops;
+ kvm_init_msr_list();
+
kvm_mmu_set_mask_ptes(PT_USER_MASK, PT_ACCESSED_MASK,
PT_DIRTY_MASK, PT64_NX_MASK, 0);
@@ -5782,8 +5840,10 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu)
kvm_x86_ops->update_cr8_intercept(vcpu, tpr, max_irr);
}
-static void inject_pending_event(struct kvm_vcpu *vcpu)
+static int inject_pending_event(struct kvm_vcpu *vcpu, bool req_int_win)
{
+ int r;
+
/* try to reinject previous events if any */
if (vcpu->arch.exception.pending) {
trace_kvm_inj_exception(vcpu->arch.exception.nr,
@@ -5793,17 +5853,23 @@ static void inject_pending_event(struct kvm_vcpu *vcpu)
vcpu->arch.exception.has_error_code,
vcpu->arch.exception.error_code,
vcpu->arch.exception.reinject);
- return;
+ return 0;
}
if (vcpu->arch.nmi_injected) {
kvm_x86_ops->set_nmi(vcpu);
- return;
+ return 0;
}
if (vcpu->arch.interrupt.pending) {
kvm_x86_ops->set_irq(vcpu);
- return;
+ return 0;
+ }
+
+ if (is_guest_mode(vcpu) && kvm_x86_ops->check_nested_events) {
+ r = kvm_x86_ops->check_nested_events(vcpu, req_int_win);
+ if (r != 0)
+ return r;
}
/* try to inject new event if pending */
@@ -5820,6 +5886,7 @@ static void inject_pending_event(struct kvm_vcpu *vcpu)
kvm_x86_ops->set_irq(vcpu);
}
}
+ return 0;
}
static void process_nmi(struct kvm_vcpu *vcpu)
@@ -5924,15 +5991,13 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
goto out;
}
- inject_pending_event(vcpu);
-
+ if (inject_pending_event(vcpu, req_int_win) != 0)
+ req_immediate_exit = true;
/* enable NMI/IRQ window open exits if needed */
- if (vcpu->arch.nmi_pending)
- req_immediate_exit =
- kvm_x86_ops->enable_nmi_window(vcpu) != 0;
+ else if (vcpu->arch.nmi_pending)
+ kvm_x86_ops->enable_nmi_window(vcpu);
else if (kvm_cpu_has_injectable_intr(vcpu) || req_int_win)
- req_immediate_exit =
- kvm_x86_ops->enable_irq_window(vcpu) != 0;
+ kvm_x86_ops->enable_irq_window(vcpu);
if (kvm_lapic_enabled(vcpu)) {
/*
@@ -5992,12 +6057,28 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
set_debugreg(vcpu->arch.eff_db[1], 1);
set_debugreg(vcpu->arch.eff_db[2], 2);
set_debugreg(vcpu->arch.eff_db[3], 3);
+ set_debugreg(vcpu->arch.dr6, 6);
}
trace_kvm_entry(vcpu->vcpu_id);
kvm_x86_ops->run(vcpu);
/*
+ * Do this here before restoring debug registers on the host. And
+ * since we do this before handling the vmexit, a DR access vmexit
+ * can (a) read the correct value of the debug registers, (b) set
+ * KVM_DEBUGREG_WONT_EXIT again.
+ */
+ if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)) {
+ int i;
+
+ WARN_ON(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP);
+ kvm_x86_ops->sync_dirty_debug_regs(vcpu);
+ for (i = 0; i < KVM_NR_DB_REGS; i++)
+ vcpu->arch.eff_db[i] = vcpu->arch.db[i];
+ }
+
+ /*
* If the guest has used debug registers, at least dr7
* will be disabled while returning to the host.
* If we don't have active breakpoints in the host, we don't
@@ -6186,7 +6267,7 @@ static int complete_emulated_mmio(struct kvm_vcpu *vcpu)
frag->len -= len;
}
- if (vcpu->mmio_cur_fragment == vcpu->mmio_nr_fragments) {
+ if (vcpu->mmio_cur_fragment >= vcpu->mmio_nr_fragments) {
vcpu->mmio_needed = 0;
/* FIXME: return into emulator if single-stepping. */
@@ -6711,6 +6792,7 @@ int kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
{
int r;
struct msr_data msr;
+ struct kvm *kvm = vcpu->kvm;
r = vcpu_load(vcpu);
if (r)
@@ -6721,6 +6803,9 @@ int kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
kvm_write_tsc(vcpu, &msr);
vcpu_put(vcpu);
+ schedule_delayed_work(&kvm->arch.kvmclock_sync_work,
+ KVMCLOCK_SYNC_PERIOD);
+
return r;
}
@@ -7013,6 +7098,9 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
pvclock_update_vm_gtod_copy(kvm);
+ INIT_DELAYED_WORK(&kvm->arch.kvmclock_update_work, kvmclock_update_fn);
+ INIT_DELAYED_WORK(&kvm->arch.kvmclock_sync_work, kvmclock_sync_fn);
+
return 0;
}
@@ -7050,6 +7138,8 @@ static void kvm_free_vcpus(struct kvm *kvm)
void kvm_arch_sync_events(struct kvm *kvm)
{
+ cancel_delayed_work_sync(&kvm->arch.kvmclock_sync_work);
+ cancel_delayed_work_sync(&kvm->arch.kvmclock_update_work);
kvm_free_all_assigned_devices(kvm);
kvm_free_pit(kvm);
}
@@ -7248,6 +7338,9 @@ void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
{
+ if (is_guest_mode(vcpu) && kvm_x86_ops->check_nested_events)
+ kvm_x86_ops->check_nested_events(vcpu, false);
+
return (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE &&
!vcpu->arch.apf.halted)
|| !list_empty_careful(&vcpu->async_pf.done)
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index 8da5823bcde6..8c97bac9a895 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -122,9 +122,12 @@ int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt,
gva_t addr, void *val, unsigned int bytes,
struct x86_exception *exception);
-#define KVM_SUPPORTED_XCR0 (XSTATE_FP | XSTATE_SSE | XSTATE_YMM)
+#define KVM_SUPPORTED_XCR0 (XSTATE_FP | XSTATE_SSE | XSTATE_YMM \
+ | XSTATE_BNDREGS | XSTATE_BNDCSR)
extern u64 host_xcr0;
+extern u64 kvm_supported_xcr0(void);
+
extern unsigned int min_timer_period_us;
extern struct static_key kvm_no_apic_vcpu;
diff --git a/arch/x86/lib/hash.c b/arch/x86/lib/hash.c
index 3056702e81fb..ff4fa51a5b1f 100644
--- a/arch/x86/lib/hash.c
+++ b/arch/x86/lib/hash.c
@@ -32,6 +32,7 @@
*/
#include <linux/hash.h>
+#include <linux/init.h>
#include <asm/processor.h>
#include <asm/cpufeature.h>
@@ -39,7 +40,11 @@
static inline u32 crc32_u32(u32 crc, u32 val)
{
+#ifdef CONFIG_AS_CRC32
asm ("crc32l %1,%0\n" : "+r" (crc) : "rm" (val));
+#else
+ asm (".byte 0xf2, 0x0f, 0x38, 0xf1, 0xc1" : "+a" (crc) : "c" (val));
+#endif
return crc;
}
@@ -49,19 +54,18 @@ static u32 intel_crc4_2_hash(const void *data, u32 len, u32 seed)
u32 i, tmp = 0;
for (i = 0; i < len / 4; i++)
- seed = crc32_u32(*p32++, seed);
+ seed = crc32_u32(seed, *p32++);
- switch (3 - (len & 0x03)) {
- case 0:
+ switch (len & 3) {
+ case 3:
tmp |= *((const u8 *) p32 + 2) << 16;
/* fallthrough */
- case 1:
+ case 2:
tmp |= *((const u8 *) p32 + 1) << 8;
/* fallthrough */
- case 2:
+ case 1:
tmp |= *((const u8 *) p32);
- seed = crc32_u32(tmp, seed);
- default:
+ seed = crc32_u32(seed, tmp);
break;
}
@@ -74,12 +78,12 @@ static u32 intel_crc4_2_hash2(const u32 *data, u32 len, u32 seed)
u32 i;
for (i = 0; i < len; i++)
- seed = crc32_u32(*p32++, seed);
+ seed = crc32_u32(seed, *p32++);
return seed;
}
-void setup_arch_fast_hash(struct fast_hash_ops *ops)
+void __init setup_arch_fast_hash(struct fast_hash_ops *ops)
{
if (cpu_has_xmm4_2) {
ops->hash = intel_crc4_2_hash;
diff --git a/arch/x86/lib/memcpy_32.c b/arch/x86/lib/memcpy_32.c
index e78761d6b7f8..a404b4b75533 100644
--- a/arch/x86/lib/memcpy_32.c
+++ b/arch/x86/lib/memcpy_32.c
@@ -4,7 +4,7 @@
#undef memcpy
#undef memset
-void *memcpy(void *to, const void *from, size_t n)
+__visible void *memcpy(void *to, const void *from, size_t n)
{
#ifdef CONFIG_X86_USE_3DNOW
return __memcpy3d(to, from, n);
@@ -14,13 +14,13 @@ void *memcpy(void *to, const void *from, size_t n)
}
EXPORT_SYMBOL(memcpy);
-void *memset(void *s, int c, size_t count)
+__visible void *memset(void *s, int c, size_t count)
{
return __memset(s, c, count);
}
EXPORT_SYMBOL(memset);
-void *memmove(void *dest, const void *src, size_t n)
+__visible void *memmove(void *dest, const void *src, size_t n)
{
int d0,d1,d2,d3,d4,d5;
char *ret = dest;
diff --git a/arch/x86/lib/msr.c b/arch/x86/lib/msr.c
index 8f8eebdca7d4..db9db446b71a 100644
--- a/arch/x86/lib/msr.c
+++ b/arch/x86/lib/msr.c
@@ -8,7 +8,7 @@ struct msr *msrs_alloc(void)
msrs = alloc_percpu(struct msr);
if (!msrs) {
- pr_warning("%s: error allocating msrs\n", __func__);
+ pr_warn("%s: error allocating msrs\n", __func__);
return NULL;
}
@@ -21,3 +21,90 @@ void msrs_free(struct msr *msrs)
free_percpu(msrs);
}
EXPORT_SYMBOL(msrs_free);
+
+/**
+ * Read an MSR with error handling
+ *
+ * @msr: MSR to read
+ * @m: value to read into
+ *
+ * It returns read data only on success, otherwise it doesn't change the output
+ * argument @m.
+ *
+ */
+int msr_read(u32 msr, struct msr *m)
+{
+ int err;
+ u64 val;
+
+ err = rdmsrl_safe(msr, &val);
+ if (!err)
+ m->q = val;
+
+ return err;
+}
+
+/**
+ * Write an MSR with error handling
+ *
+ * @msr: MSR to write
+ * @m: value to write
+ */
+int msr_write(u32 msr, struct msr *m)
+{
+ return wrmsrl_safe(msr, m->q);
+}
+
+static inline int __flip_bit(u32 msr, u8 bit, bool set)
+{
+ struct msr m, m1;
+ int err = -EINVAL;
+
+ if (bit > 63)
+ return err;
+
+ err = msr_read(msr, &m);
+ if (err)
+ return err;
+
+ m1 = m;
+ if (set)
+ m1.q |= BIT_64(bit);
+ else
+ m1.q &= ~BIT_64(bit);
+
+ if (m1.q == m.q)
+ return 0;
+
+ err = msr_write(msr, &m);
+ if (err)
+ return err;
+
+ return 1;
+}
+
+/**
+ * Set @bit in a MSR @msr.
+ *
+ * Retval:
+ * < 0: An error was encountered.
+ * = 0: Bit was already set.
+ * > 0: Hardware accepted the MSR write.
+ */
+int msr_set_bit(u32 msr, u8 bit)
+{
+ return __flip_bit(msr, bit, true);
+}
+
+/**
+ * Clear @bit in a MSR @msr.
+ *
+ * Retval:
+ * < 0: An error was encountered.
+ * = 0: Bit was already cleared.
+ * > 0: Hardware accepted the MSR write.
+ */
+int msr_clear_bit(u32 msr, u8 bit)
+{
+ return __flip_bit(msr, bit, false);
+}
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c
index 0002a3a33081..20621d753d5f 100644
--- a/arch/x86/mm/dump_pagetables.c
+++ b/arch/x86/mm/dump_pagetables.c
@@ -30,6 +30,7 @@ struct pg_state {
unsigned long start_address;
unsigned long current_address;
const struct addr_marker *marker;
+ bool to_dmesg;
};
struct addr_marker {
@@ -88,10 +89,28 @@ static struct addr_marker address_markers[] = {
#define PUD_LEVEL_MULT (PTRS_PER_PMD * PMD_LEVEL_MULT)
#define PGD_LEVEL_MULT (PTRS_PER_PUD * PUD_LEVEL_MULT)
+#define pt_dump_seq_printf(m, to_dmesg, fmt, args...) \
+({ \
+ if (to_dmesg) \
+ printk(KERN_INFO fmt, ##args); \
+ else \
+ if (m) \
+ seq_printf(m, fmt, ##args); \
+})
+
+#define pt_dump_cont_printf(m, to_dmesg, fmt, args...) \
+({ \
+ if (to_dmesg) \
+ printk(KERN_CONT fmt, ##args); \
+ else \
+ if (m) \
+ seq_printf(m, fmt, ##args); \
+})
+
/*
* Print a readable form of a pgprot_t to the seq_file
*/
-static void printk_prot(struct seq_file *m, pgprot_t prot, int level)
+static void printk_prot(struct seq_file *m, pgprot_t prot, int level, bool dmsg)
{
pgprotval_t pr = pgprot_val(prot);
static const char * const level_name[] =
@@ -99,47 +118,47 @@ static void printk_prot(struct seq_file *m, pgprot_t prot, int level)
if (!pgprot_val(prot)) {
/* Not present */
- seq_printf(m, " ");
+ pt_dump_cont_printf(m, dmsg, " ");
} else {
if (pr & _PAGE_USER)
- seq_printf(m, "USR ");
+ pt_dump_cont_printf(m, dmsg, "USR ");
else
- seq_printf(m, " ");
+ pt_dump_cont_printf(m, dmsg, " ");
if (pr & _PAGE_RW)
- seq_printf(m, "RW ");
+ pt_dump_cont_printf(m, dmsg, "RW ");
else
- seq_printf(m, "ro ");
+ pt_dump_cont_printf(m, dmsg, "ro ");
if (pr & _PAGE_PWT)
- seq_printf(m, "PWT ");
+ pt_dump_cont_printf(m, dmsg, "PWT ");
else
- seq_printf(m, " ");
+ pt_dump_cont_printf(m, dmsg, " ");
if (pr & _PAGE_PCD)
- seq_printf(m, "PCD ");
+ pt_dump_cont_printf(m, dmsg, "PCD ");
else
- seq_printf(m, " ");
+ pt_dump_cont_printf(m, dmsg, " ");
/* Bit 9 has a different meaning on level 3 vs 4 */
if (level <= 3) {
if (pr & _PAGE_PSE)
- seq_printf(m, "PSE ");
+ pt_dump_cont_printf(m, dmsg, "PSE ");
else
- seq_printf(m, " ");
+ pt_dump_cont_printf(m, dmsg, " ");
} else {
if (pr & _PAGE_PAT)
- seq_printf(m, "pat ");
+ pt_dump_cont_printf(m, dmsg, "pat ");
else
- seq_printf(m, " ");
+ pt_dump_cont_printf(m, dmsg, " ");
}
if (pr & _PAGE_GLOBAL)
- seq_printf(m, "GLB ");
+ pt_dump_cont_printf(m, dmsg, "GLB ");
else
- seq_printf(m, " ");
+ pt_dump_cont_printf(m, dmsg, " ");
if (pr & _PAGE_NX)
- seq_printf(m, "NX ");
+ pt_dump_cont_printf(m, dmsg, "NX ");
else
- seq_printf(m, "x ");
+ pt_dump_cont_printf(m, dmsg, "x ");
}
- seq_printf(m, "%s\n", level_name[level]);
+ pt_dump_cont_printf(m, dmsg, "%s\n", level_name[level]);
}
/*
@@ -178,7 +197,8 @@ static void note_page(struct seq_file *m, struct pg_state *st,
st->current_prot = new_prot;
st->level = level;
st->marker = address_markers;
- seq_printf(m, "---[ %s ]---\n", st->marker->name);
+ pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n",
+ st->marker->name);
} else if (prot != cur || level != st->level ||
st->current_address >= st->marker[1].start_address) {
const char *unit = units;
@@ -188,17 +208,17 @@ static void note_page(struct seq_file *m, struct pg_state *st,
/*
* Now print the actual finished series
*/
- seq_printf(m, "0x%0*lx-0x%0*lx ",
- width, st->start_address,
- width, st->current_address);
+ pt_dump_seq_printf(m, st->to_dmesg, "0x%0*lx-0x%0*lx ",
+ width, st->start_address,
+ width, st->current_address);
delta = (st->current_address - st->start_address) >> 10;
while (!(delta & 1023) && unit[1]) {
delta >>= 10;
unit++;
}
- seq_printf(m, "%9lu%c ", delta, *unit);
- printk_prot(m, st->current_prot, st->level);
+ pt_dump_cont_printf(m, st->to_dmesg, "%9lu%c ", delta, *unit);
+ printk_prot(m, st->current_prot, st->level, st->to_dmesg);
/*
* We print markers for special areas of address space,
@@ -207,7 +227,8 @@ static void note_page(struct seq_file *m, struct pg_state *st,
*/
if (st->current_address >= st->marker[1].start_address) {
st->marker++;
- seq_printf(m, "---[ %s ]---\n", st->marker->name);
+ pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n",
+ st->marker->name);
}
st->start_address = st->current_address;
@@ -296,7 +317,7 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st, pgd_t addr,
#define pgd_none(a) pud_none(__pud(pgd_val(a)))
#endif
-static void walk_pgd_level(struct seq_file *m)
+void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd)
{
#ifdef CONFIG_X86_64
pgd_t *start = (pgd_t *) &init_level4_pgt;
@@ -304,9 +325,12 @@ static void walk_pgd_level(struct seq_file *m)
pgd_t *start = swapper_pg_dir;
#endif
int i;
- struct pg_state st;
+ struct pg_state st = {};
- memset(&st, 0, sizeof(st));
+ if (pgd) {
+ start = pgd;
+ st.to_dmesg = true;
+ }
for (i = 0; i < PTRS_PER_PGD; i++) {
st.current_address = normalize_addr(i * PGD_LEVEL_MULT);
@@ -331,7 +355,7 @@ static void walk_pgd_level(struct seq_file *m)
static int ptdump_show(struct seq_file *m, void *v)
{
- walk_pgd_level(m);
+ ptdump_walk_pgd_level(m, NULL);
return 0;
}
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 9d591c895803..8e5722992677 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -584,8 +584,13 @@ show_fault_oops(struct pt_regs *regs, unsigned long error_code,
if (error_code & PF_INSTR) {
unsigned int level;
+ pgd_t *pgd;
+ pte_t *pte;
- pte_t *pte = lookup_address(address, &level);
+ pgd = __va(read_cr3() & PHYSICAL_PAGE_MASK);
+ pgd += pgd_index(address);
+
+ pte = lookup_address_in_pgd(pgd, address, &level);
if (pte && pte_present(*pte) && !pte_exec(*pte))
printk(nx_warning, from_kuid(&init_user_ns, current_uid()));
@@ -1001,6 +1006,12 @@ static int fault_in_kernel_space(unsigned long address)
static inline bool smap_violation(int error_code, struct pt_regs *regs)
{
+ if (!IS_ENABLED(CONFIG_X86_SMAP))
+ return false;
+
+ if (!static_cpu_has(X86_FEATURE_SMAP))
+ return false;
+
if (error_code & PF_USER)
return false;
@@ -1014,13 +1025,17 @@ static inline bool smap_violation(int error_code, struct pt_regs *regs)
* This routine handles page faults. It determines the address,
* and the problem, and then passes it off to one of the appropriate
* routines.
+ *
+ * This function must have noinline because both callers
+ * {,trace_}do_page_fault() have notrace on. Having this an actual function
+ * guarantees there's a function trace entry.
*/
-static void __kprobes
-__do_page_fault(struct pt_regs *regs, unsigned long error_code)
+static void __kprobes noinline
+__do_page_fault(struct pt_regs *regs, unsigned long error_code,
+ unsigned long address)
{
struct vm_area_struct *vma;
struct task_struct *tsk;
- unsigned long address;
struct mm_struct *mm;
int fault;
unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
@@ -1028,9 +1043,6 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code)
tsk = current;
mm = tsk->mm;
- /* Get the faulting address: */
- address = read_cr2();
-
/*
* Detect and handle instructions that would cause a page fault for
* both a tracked kernel page and a userspace page.
@@ -1087,11 +1099,9 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code)
if (unlikely(error_code & PF_RSVD))
pgtable_bad(regs, error_code, address);
- if (static_cpu_has(X86_FEATURE_SMAP)) {
- if (unlikely(smap_violation(error_code, regs))) {
- bad_area_nosemaphore(regs, error_code, address);
- return;
- }
+ if (unlikely(smap_violation(error_code, regs))) {
+ bad_area_nosemaphore(regs, error_code, address);
+ return;
}
/*
@@ -1244,32 +1254,50 @@ good_area:
up_read(&mm->mmap_sem);
}
-dotraplinkage void __kprobes
+dotraplinkage void __kprobes notrace
do_page_fault(struct pt_regs *regs, unsigned long error_code)
{
+ unsigned long address = read_cr2(); /* Get the faulting address */
enum ctx_state prev_state;
+ /*
+ * We must have this function tagged with __kprobes, notrace and call
+ * read_cr2() before calling anything else. To avoid calling any kind
+ * of tracing machinery before we've observed the CR2 value.
+ *
+ * exception_{enter,exit}() contain all sorts of tracepoints.
+ */
+
prev_state = exception_enter();
- __do_page_fault(regs, error_code);
+ __do_page_fault(regs, error_code, address);
exception_exit(prev_state);
}
-static void trace_page_fault_entries(struct pt_regs *regs,
+#ifdef CONFIG_TRACING
+static void trace_page_fault_entries(unsigned long address, struct pt_regs *regs,
unsigned long error_code)
{
if (user_mode(regs))
- trace_page_fault_user(read_cr2(), regs, error_code);
+ trace_page_fault_user(address, regs, error_code);
else
- trace_page_fault_kernel(read_cr2(), regs, error_code);
+ trace_page_fault_kernel(address, regs, error_code);
}
-dotraplinkage void __kprobes
+dotraplinkage void __kprobes notrace
trace_do_page_fault(struct pt_regs *regs, unsigned long error_code)
{
+ /*
+ * The exception_enter and tracepoint processing could
+ * trigger another page faults (user space callchain
+ * reading) and destroy the original cr2 value, so read
+ * the faulting address now.
+ */
+ unsigned long address = read_cr2();
enum ctx_state prev_state;
prev_state = exception_enter();
- trace_page_fault_entries(regs, error_code);
- __do_page_fault(regs, error_code);
+ trace_page_fault_entries(address, regs, error_code);
+ __do_page_fault(regs, error_code, address);
exception_exit(prev_state);
}
+#endif /* CONFIG_TRACING */
diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c
index 27aa0455fab3..1d045f9c390f 100644
--- a/arch/x86/mm/numa.c
+++ b/arch/x86/mm/numa.c
@@ -687,10 +687,6 @@ static int __init dummy_numa_init(void)
void __init x86_numa_init(void)
{
if (!numa_off) {
-#ifdef CONFIG_X86_NUMAQ
- if (!numa_init(numaq_numa_init))
- return;
-#endif
#ifdef CONFIG_ACPI_NUMA
if (!numa_init(x86_acpi_numa_init))
return;
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index b3b19f46c016..ae242a7c11c7 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -126,8 +126,8 @@ within(unsigned long addr, unsigned long start, unsigned long end)
* @vaddr: virtual start address
* @size: number of bytes to flush
*
- * clflush is an unordered instruction which needs fencing with mfence
- * to avoid ordering issues.
+ * clflushopt is an unordered instruction which needs fencing with mfence or
+ * sfence to avoid ordering issues.
*/
void clflush_cache_range(void *vaddr, unsigned int size)
{
@@ -136,11 +136,11 @@ void clflush_cache_range(void *vaddr, unsigned int size)
mb();
for (; vaddr < vend; vaddr += boot_cpu_data.x86_clflush_size)
- clflush(vaddr);
+ clflushopt(vaddr);
/*
* Flush any possible final partial cacheline:
*/
- clflush(vend);
+ clflushopt(vend);
mb();
}
@@ -323,8 +323,12 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
return prot;
}
-static pte_t *__lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
- unsigned int *level)
+/*
+ * Lookup the page table entry for a virtual address in a specific pgd.
+ * Return a pointer to the entry and the level of the mapping.
+ */
+pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
+ unsigned int *level)
{
pud_t *pud;
pmd_t *pmd;
@@ -365,7 +369,7 @@ static pte_t *__lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
*/
pte_t *lookup_address(unsigned long address, unsigned int *level)
{
- return __lookup_address_in_pgd(pgd_offset_k(address), address, level);
+ return lookup_address_in_pgd(pgd_offset_k(address), address, level);
}
EXPORT_SYMBOL_GPL(lookup_address);
@@ -373,7 +377,7 @@ static pte_t *_lookup_address_cpa(struct cpa_data *cpa, unsigned long address,
unsigned int *level)
{
if (cpa->pgd)
- return __lookup_address_in_pgd(cpa->pgd + pgd_index(address),
+ return lookup_address_in_pgd(cpa->pgd + pgd_index(address),
address, level);
return lookup_address(address, level);
@@ -692,6 +696,18 @@ static bool try_to_free_pmd_page(pmd_t *pmd)
return true;
}
+static bool try_to_free_pud_page(pud_t *pud)
+{
+ int i;
+
+ for (i = 0; i < PTRS_PER_PUD; i++)
+ if (!pud_none(pud[i]))
+ return false;
+
+ free_page((unsigned long)pud);
+ return true;
+}
+
static bool unmap_pte_range(pmd_t *pmd, unsigned long start, unsigned long end)
{
pte_t *pte = pte_offset_kernel(pmd, start);
@@ -805,6 +821,16 @@ static void unmap_pud_range(pgd_t *pgd, unsigned long start, unsigned long end)
*/
}
+static void unmap_pgd_range(pgd_t *root, unsigned long addr, unsigned long end)
+{
+ pgd_t *pgd_entry = root + pgd_index(addr);
+
+ unmap_pud_range(pgd_entry, addr, end);
+
+ if (try_to_free_pud_page((pud_t *)pgd_page_vaddr(*pgd_entry)))
+ pgd_clear(pgd_entry);
+}
+
static int alloc_pte_page(pmd_t *pmd)
{
pte_t *pte = (pte_t *)get_zeroed_page(GFP_KERNEL | __GFP_NOTRACK);
@@ -999,9 +1025,8 @@ static int populate_pud(struct cpa_data *cpa, unsigned long start, pgd_t *pgd,
static int populate_pgd(struct cpa_data *cpa, unsigned long addr)
{
pgprot_t pgprot = __pgprot(_KERNPG_TABLE);
- bool allocd_pgd = false;
- pgd_t *pgd_entry;
pud_t *pud = NULL; /* shut up gcc */
+ pgd_t *pgd_entry;
int ret;
pgd_entry = cpa->pgd + pgd_index(addr);
@@ -1015,7 +1040,6 @@ static int populate_pgd(struct cpa_data *cpa, unsigned long addr)
return -1;
set_pgd(pgd_entry, __pgd(__pa(pud) | _KERNPG_TABLE));
- allocd_pgd = true;
}
pgprot_val(pgprot) &= ~pgprot_val(cpa->mask_clr);
@@ -1023,19 +1047,11 @@ static int populate_pgd(struct cpa_data *cpa, unsigned long addr)
ret = populate_pud(cpa, addr, pgd_entry, pgprot);
if (ret < 0) {
- unmap_pud_range(pgd_entry, addr,
+ unmap_pgd_range(cpa->pgd, addr,
addr + (cpa->numpages << PAGE_SHIFT));
-
- if (allocd_pgd) {
- /*
- * If I allocated this PUD page, I can just as well
- * free it in this error path.
- */
- pgd_clear(pgd_entry);
- free_page((unsigned long)pud);
- }
return ret;
}
+
cpa->numpages = ret;
return 0;
}
@@ -1377,10 +1393,10 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
cache = cache_attr(mask_set);
/*
- * On success we use clflush, when the CPU supports it to
- * avoid the wbindv. If the CPU does not support it and in the
+ * On success we use CLFLUSH, when the CPU supports it to
+ * avoid the WBINVD. If the CPU does not support it and in the
* error case we fall back to cpa_flush_all (which uses
- * wbindv):
+ * WBINVD):
*/
if (!ret && cpu_has_clflush) {
if (cpa.flags & (CPA_PAGES_ARRAY | CPA_ARRAY)) {
@@ -1861,6 +1877,12 @@ out:
return retval;
}
+void kernel_unmap_pages_in_pgd(pgd_t *root, unsigned long address,
+ unsigned numpages)
+{
+ unmap_pgd_range(root, address, address + (numpages << PAGE_SHIFT));
+}
+
/*
* The testcases use internal knowledge of the implementation that shouldn't
* be exposed to the rest of the kernel. Include these directly here.
diff --git a/arch/x86/mm/srat.c b/arch/x86/mm/srat.c
index 1953e9c9391a..66338a60aa6e 100644
--- a/arch/x86/mm/srat.c
+++ b/arch/x86/mm/srat.c
@@ -52,12 +52,18 @@ void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
int i, j;
for (i = 0; i < slit->locality_count; i++) {
- if (pxm_to_node(i) == NUMA_NO_NODE)
+ const int from_node = pxm_to_node(i);
+
+ if (from_node == NUMA_NO_NODE)
continue;
+
for (j = 0; j < slit->locality_count; j++) {
- if (pxm_to_node(j) == NUMA_NO_NODE)
+ const int to_node = pxm_to_node(j);
+
+ if (to_node == NUMA_NO_NODE)
continue;
- numa_set_distance(pxm_to_node(i), pxm_to_node(j),
+
+ numa_set_distance(from_node, to_node,
slit->entry[slit->locality_count * i + j]);
}
}
diff --git a/arch/x86/net/bpf_jit.S b/arch/x86/net/bpf_jit.S
index 877b9a1b2152..01495755701b 100644
--- a/arch/x86/net/bpf_jit.S
+++ b/arch/x86/net/bpf_jit.S
@@ -140,7 +140,7 @@ bpf_slow_path_byte_msh:
push %r9; \
push SKBDATA; \
/* rsi already has offset */ \
- mov $SIZE,%ecx; /* size */ \
+ mov $SIZE,%edx; /* size */ \
call bpf_internal_load_pointer_neg_helper; \
test %rax,%rax; \
pop SKBDATA; \
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 4ed75dd81d05..dc017735bb91 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -553,13 +553,13 @@ void bpf_jit_compile(struct sk_filter *fp)
}
break;
case BPF_S_ANC_RXHASH:
- BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
- if (is_imm8(offsetof(struct sk_buff, rxhash))) {
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, hash) != 4);
+ if (is_imm8(offsetof(struct sk_buff, hash))) {
/* mov off8(%rdi),%eax */
- EMIT3(0x8b, 0x47, offsetof(struct sk_buff, rxhash));
+ EMIT3(0x8b, 0x47, offsetof(struct sk_buff, hash));
} else {
EMIT2(0x8b, 0x87);
- EMIT(offsetof(struct sk_buff, rxhash), 4);
+ EMIT(offsetof(struct sk_buff, hash), 4);
}
break;
case BPF_S_ANC_QUEUE:
@@ -772,6 +772,7 @@ cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i];
bpf_flush_icache(header, image + proglen);
set_memory_ro((unsigned long)header, header->pages);
fp->bpf_func = (void *)image;
+ fp->jited = 1;
}
out:
kfree(addrs);
@@ -791,7 +792,7 @@ static void bpf_jit_free_deferred(struct work_struct *work)
void bpf_jit_free(struct sk_filter *fp)
{
- if (fp->bpf_func != sk_run_filter) {
+ if (fp->jited) {
INIT_WORK(&fp->work, bpf_jit_free_deferred);
schedule_work(&fp->work);
} else {
diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile
index e063eed0f912..5c6fc3577a49 100644
--- a/arch/x86/pci/Makefile
+++ b/arch/x86/pci/Makefile
@@ -13,9 +13,6 @@ obj-y += legacy.o irq.o
obj-$(CONFIG_STA2X11) += sta2x11-fixup.o
-obj-$(CONFIG_X86_VISWS) += visws.o
-
-obj-$(CONFIG_X86_NUMAQ) += numaq_32.o
obj-$(CONFIG_X86_NUMACHIP) += numachip.o
obj-$(CONFIG_X86_INTEL_MID) += intel_mid_pci.o
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 4f25ec077552..01edac6c5e18 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -218,9 +218,8 @@ static void teardown_mcfg_map(struct pci_root_info *info)
}
#endif
-static acpi_status
-resource_to_addr(struct acpi_resource *resource,
- struct acpi_resource_address64 *addr)
+static acpi_status resource_to_addr(struct acpi_resource *resource,
+ struct acpi_resource_address64 *addr)
{
acpi_status status;
struct acpi_resource_memory24 *memory24;
@@ -265,8 +264,7 @@ resource_to_addr(struct acpi_resource *resource,
return AE_ERROR;
}
-static acpi_status
-count_resource(struct acpi_resource *acpi_res, void *data)
+static acpi_status count_resource(struct acpi_resource *acpi_res, void *data)
{
struct pci_root_info *info = data;
struct acpi_resource_address64 addr;
@@ -278,8 +276,7 @@ count_resource(struct acpi_resource *acpi_res, void *data)
return AE_OK;
}
-static acpi_status
-setup_resource(struct acpi_resource *acpi_res, void *data)
+static acpi_status setup_resource(struct acpi_resource *acpi_res, void *data)
{
struct pci_root_info *info = data;
struct resource *res;
@@ -435,9 +432,9 @@ static void release_pci_root_info(struct pci_host_bridge *bridge)
__release_pci_root_info(info);
}
-static void
-probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
- int busnum, int domain)
+static void probe_pci_root_info(struct pci_root_info *info,
+ struct acpi_device *device,
+ int busnum, int domain)
{
size_t size;
@@ -473,16 +470,13 @@ probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
{
struct acpi_device *device = root->device;
- struct pci_root_info *info = NULL;
+ struct pci_root_info *info;
int domain = root->segment;
int busnum = root->secondary.start;
LIST_HEAD(resources);
- struct pci_bus *bus = NULL;
+ struct pci_bus *bus;
struct pci_sysdata *sd;
int node;
-#ifdef CONFIG_ACPI_NUMA
- int pxm;
-#endif
if (pci_ignore_seg)
domain = 0;
@@ -494,19 +488,12 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
return NULL;
}
- node = -1;
-#ifdef CONFIG_ACPI_NUMA
- pxm = acpi_get_pxm(device->handle);
- if (pxm >= 0)
- node = pxm_to_node(pxm);
- if (node != -1)
- set_mp_bus_to_node(busnum, node);
- else
-#endif
- node = get_mp_bus_to_node(busnum);
+ node = acpi_get_node(device->handle);
+ if (node == NUMA_NO_NODE)
+ node = x86_pci_root_bus_node(busnum);
- if (node != -1 && !node_online(node))
- node = -1;
+ if (node != NUMA_NO_NODE && !node_online(node))
+ node = NUMA_NO_NODE;
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) {
@@ -519,15 +506,12 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
sd->domain = domain;
sd->node = node;
sd->companion = device;
- /*
- * Maybe the desired pci bus has been already scanned. In such case
- * it is unnecessary to scan the pci bus with the given domain,busnum.
- */
+
bus = pci_find_bus(domain, busnum);
if (bus) {
/*
- * If the desired bus exits, the content of bus->sysdata will
- * be replaced by sd.
+ * If the desired bus has been scanned already, replace
+ * its bus->sysdata.
*/
memcpy(bus->sysdata, sd, sizeof(*sd));
kfree(info);
@@ -572,15 +556,8 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
pcie_bus_configure_settings(child);
}
- if (bus && node != -1) {
-#ifdef CONFIG_ACPI_NUMA
- if (pxm >= 0)
- dev_printk(KERN_DEBUG, &bus->dev,
- "on NUMA node %d (pxm %d)\n", node, pxm);
-#else
+ if (bus && node != NUMA_NO_NODE)
dev_printk(KERN_DEBUG, &bus->dev, "on NUMA node %d\n", node);
-#endif
- }
return bus;
}
diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c
index a48be98e9ded..a313a7fb6b86 100644
--- a/arch/x86/pci/amd_bus.c
+++ b/arch/x86/pci/amd_bus.c
@@ -44,15 +44,6 @@ static struct pci_root_info __init *find_pci_root_info(int node, int link)
return NULL;
}
-static void __init set_mp_bus_range_to_node(int min_bus, int max_bus, int node)
-{
-#ifdef CONFIG_NUMA
- int j;
-
- for (j = min_bus; j <= max_bus; j++)
- set_mp_bus_to_node(j, node);
-#endif
-}
/**
* early_fill_mp_bus_to_node()
* called before pcibios_scan_root and pci_scan_bus
@@ -117,7 +108,6 @@ static int __init early_fill_mp_bus_info(void)
min_bus = (reg >> 16) & 0xff;
max_bus = (reg >> 24) & 0xff;
node = (reg >> 4) & 0x07;
- set_mp_bus_range_to_node(min_bus, max_bus, node);
link = (reg >> 8) & 0x03;
info = alloc_pci_root_info(min_bus, max_bus, node, link);
diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c
index c2735feb2508..f3a2cfc14125 100644
--- a/arch/x86/pci/bus_numa.c
+++ b/arch/x86/pci/bus_numa.c
@@ -10,9 +10,6 @@ static struct pci_root_info *x86_find_pci_root_info(int bus)
{
struct pci_root_info *info;
- if (list_empty(&pci_root_infos))
- return NULL;
-
list_for_each_entry(info, &pci_root_infos, list)
if (info->busn.start == bus)
return info;
@@ -20,6 +17,16 @@ static struct pci_root_info *x86_find_pci_root_info(int bus)
return NULL;
}
+int x86_pci_root_bus_node(int bus)
+{
+ struct pci_root_info *info = x86_find_pci_root_info(bus);
+
+ if (!info)
+ return NUMA_NO_NODE;
+
+ return info->node;
+}
+
void x86_pci_root_bus_resources(int bus, struct list_head *resources)
{
struct pci_root_info *info = x86_find_pci_root_info(bus);
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 981c2dbd72cc..059a76c29739 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -456,19 +456,25 @@ void __init dmi_check_pciprobe(void)
dmi_check_system(pciprobe_dmi_table);
}
-struct pci_bus *pcibios_scan_root(int busnum)
+void pcibios_scan_root(int busnum)
{
- struct pci_bus *bus = NULL;
+ struct pci_bus *bus;
+ struct pci_sysdata *sd;
+ LIST_HEAD(resources);
- while ((bus = pci_find_next_bus(bus)) != NULL) {
- if (bus->number == busnum) {
- /* Already scanned */
- return bus;
- }
+ sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+ if (!sd) {
+ printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busnum);
+ return;
+ }
+ sd->node = x86_pci_root_bus_node(busnum);
+ x86_pci_root_bus_resources(busnum, &resources);
+ printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum);
+ bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, sd, &resources);
+ if (!bus) {
+ pci_free_resource_list(&resources);
+ kfree(sd);
}
-
- return pci_scan_bus_on_node(busnum, &pci_root_ops,
- get_mp_bus_to_node(busnum));
}
void __init pcibios_set_cache_line_size(void)
@@ -561,7 +567,6 @@ char * __init pcibios_setup(char *str)
pci_probe |= PCI_PROBE_NOEARLY;
return NULL;
}
-#ifndef CONFIG_X86_VISWS
else if (!strcmp(str, "usepirqmask")) {
pci_probe |= PCI_USE_PIRQ_MASK;
return NULL;
@@ -571,9 +576,7 @@ char * __init pcibios_setup(char *str)
} else if (!strncmp(str, "lastbus=", 8)) {
pcibios_last_bus = simple_strtol(str+8, NULL, 0);
return NULL;
- }
-#endif
- else if (!strcmp(str, "rom")) {
+ } else if (!strcmp(str, "rom")) {
pci_probe |= PCI_ASSIGN_ROMS;
return NULL;
} else if (!strcmp(str, "norom")) {
@@ -677,105 +680,3 @@ int pci_ext_cfg_avail(void)
else
return 0;
}
-
-struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node)
-{
- LIST_HEAD(resources);
- struct pci_bus *bus = NULL;
- struct pci_sysdata *sd;
-
- /*
- * Allocate per-root-bus (not per bus) arch-specific data.
- * TODO: leak; this memory is never freed.
- * It's arguable whether it's worth the trouble to care.
- */
- sd = kzalloc(sizeof(*sd), GFP_KERNEL);
- if (!sd) {
- printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busno);
- return NULL;
- }
- sd->node = node;
- x86_pci_root_bus_resources(busno, &resources);
- printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busno);
- bus = pci_scan_root_bus(NULL, busno, ops, sd, &resources);
- if (!bus) {
- pci_free_resource_list(&resources);
- kfree(sd);
- }
-
- return bus;
-}
-
-struct pci_bus *pci_scan_bus_with_sysdata(int busno)
-{
- return pci_scan_bus_on_node(busno, &pci_root_ops, -1);
-}
-
-/*
- * NUMA info for PCI busses
- *
- * Early arch code is responsible for filling in reasonable values here.
- * A node id of "-1" means "use current node". In other words, if a bus
- * has a -1 node id, it's not tightly coupled to any particular chunk
- * of memory (as is the case on some Nehalem systems).
- */
-#ifdef CONFIG_NUMA
-
-#define BUS_NR 256
-
-#ifdef CONFIG_X86_64
-
-static int mp_bus_to_node[BUS_NR] = {
- [0 ... BUS_NR - 1] = -1
-};
-
-void set_mp_bus_to_node(int busnum, int node)
-{
- if (busnum >= 0 && busnum < BUS_NR)
- mp_bus_to_node[busnum] = node;
-}
-
-int get_mp_bus_to_node(int busnum)
-{
- int node = -1;
-
- if (busnum < 0 || busnum > (BUS_NR - 1))
- return node;
-
- node = mp_bus_to_node[busnum];
-
- /*
- * let numa_node_id to decide it later in dma_alloc_pages
- * if there is no ram on that node
- */
- if (node != -1 && !node_online(node))
- node = -1;
-
- return node;
-}
-
-#else /* CONFIG_X86_32 */
-
-static int mp_bus_to_node[BUS_NR] = {
- [0 ... BUS_NR - 1] = -1
-};
-
-void set_mp_bus_to_node(int busnum, int node)
-{
- if (busnum >= 0 && busnum < BUS_NR)
- mp_bus_to_node[busnum] = (unsigned char) node;
-}
-
-int get_mp_bus_to_node(int busnum)
-{
- int node;
-
- if (busnum < 0 || busnum > (BUS_NR - 1))
- return 0;
- node = mp_bus_to_node[busnum];
- return node;
-}
-
-#endif /* CONFIG_X86_32 */
-
-#endif /* CONFIG_NUMA */
diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c
index bca9e85daaa5..94ae9ae9574f 100644
--- a/arch/x86/pci/fixup.c
+++ b/arch/x86/pci/fixup.c
@@ -25,9 +25,9 @@ static void pci_fixup_i450nx(struct pci_dev *d)
dev_dbg(&d->dev, "i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno,
suba, subb);
if (busno)
- pci_scan_bus_with_sysdata(busno); /* Bus A */
+ pcibios_scan_root(busno); /* Bus A */
if (suba < subb)
- pci_scan_bus_with_sysdata(suba+1); /* Bus B */
+ pcibios_scan_root(suba+1); /* Bus B */
}
pcibios_last_bus = -1;
}
@@ -42,7 +42,7 @@ static void pci_fixup_i450gx(struct pci_dev *d)
u8 busno;
pci_read_config_byte(d, 0x4a, &busno);
dev_info(&d->dev, "i440KX/GX host bridge; secondary bus %02x\n", busno);
- pci_scan_bus_with_sysdata(busno);
+ pcibios_scan_root(busno);
pcibios_last_bus = -1;
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx);
@@ -313,9 +313,10 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC1, pcie_r
* IORESOURCE_ROM_SHADOW is used to associate the boot video
* card with this copy. On laptops this copy has to be used since
* the main ROM may be compressed or combined with another image.
- * See pci_map_rom() for use of this flag. IORESOURCE_ROM_SHADOW
- * is marked here since the boot video device will be the only enabled
- * video device at this point.
+ * See pci_map_rom() for use of this flag. Before marking the device
+ * with IORESOURCE_ROM_SHADOW check if a vga_default_device is already set
+ * by either arch cde or vga-arbitration, if so only apply the fixup to this
+ * already determined primary video card.
*/
static void pci_fixup_video(struct pci_dev *pdev)
@@ -346,12 +347,13 @@ static void pci_fixup_video(struct pci_dev *pdev)
}
bus = bus->parent;
}
- pci_read_config_word(pdev, PCI_COMMAND, &config);
- if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
- pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
- dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n");
- if (!vga_default_device())
+ if (!vga_default_device() || pdev == vga_default_device()) {
+ pci_read_config_word(pdev, PCI_COMMAND, &config);
+ if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
+ pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
+ dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n");
vga_set_default_device(pdev);
+ }
}
}
DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index 372e9b8989b3..84112f55dd7a 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -136,13 +136,9 @@ static void __init pirq_peer_trick(void)
busmap[e->bus] = 1;
}
for (i = 1; i < 256; i++) {
- int node;
if (!busmap[i] || pci_find_bus(0, i))
continue;
- node = get_mp_bus_to_node(i);
- if (pci_scan_bus_on_node(i, &pci_root_ops, node))
- printk(KERN_INFO "PCI: Discovered primary peer "
- "bus %02x [IRQ]\n", i);
+ pcibios_scan_root(i);
}
pcibios_last_bus = -1;
}
diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c
index 4db96fb1c232..5b662c0faf8c 100644
--- a/arch/x86/pci/legacy.c
+++ b/arch/x86/pci/legacy.c
@@ -37,19 +37,17 @@ int __init pci_legacy_init(void)
void pcibios_scan_specific_bus(int busn)
{
int devfn;
- long node;
u32 l;
if (pci_find_bus(0, busn))
return;
- node = get_mp_bus_to_node(busn);
for (devfn = 0; devfn < 256; devfn += 8) {
if (!raw_pci_read(0, busn, devfn, PCI_VENDOR_ID, 2, &l) &&
l != 0x0000 && l != 0xffff) {
DBG("Found device at %02x:%02x [%04x]\n", busn, devfn, l);
printk(KERN_INFO "PCI: Discovered peer bus %02x\n", busn);
- pci_scan_bus_on_node(busn, &pci_root_ops, node);
+ pcibios_scan_root(busn);
return;
}
}
diff --git a/arch/x86/pci/numaq_32.c b/arch/x86/pci/numaq_32.c
deleted file mode 100644
index 72c229f9ebcf..000000000000
--- a/arch/x86/pci/numaq_32.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * numaq_32.c - Low-level PCI access for NUMA-Q machines
- */
-
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/nodemask.h>
-#include <asm/apic.h>
-#include <asm/mpspec.h>
-#include <asm/pci_x86.h>
-#include <asm/numaq.h>
-
-#define BUS2QUAD(global) (mp_bus_id_to_node[global])
-
-#define BUS2LOCAL(global) (mp_bus_id_to_local[global])
-
-#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local])
-
-#define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \
- (0x80000000 | (BUS2LOCAL(bus) << 16) | (devfn << 8) | (reg & ~3))
-
-static void write_cf8(unsigned bus, unsigned devfn, unsigned reg)
-{
- unsigned val = PCI_CONF1_MQ_ADDRESS(bus, devfn, reg);
- if (xquad_portio)
- writel(val, XQUAD_PORT_ADDR(0xcf8, BUS2QUAD(bus)));
- else
- outl(val, 0xCF8);
-}
-
-static int pci_conf1_mq_read(unsigned int seg, unsigned int bus,
- unsigned int devfn, int reg, int len, u32 *value)
-{
- unsigned long flags;
- void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus));
-
- WARN_ON(seg);
- if (!value || (bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
- return -EINVAL;
-
- raw_spin_lock_irqsave(&pci_config_lock, flags);
-
- write_cf8(bus, devfn, reg);
-
- switch (len) {
- case 1:
- if (xquad_portio)
- *value = readb(adr + (reg & 3));
- else
- *value = inb(0xCFC + (reg & 3));
- break;
- case 2:
- if (xquad_portio)
- *value = readw(adr + (reg & 2));
- else
- *value = inw(0xCFC + (reg & 2));
- break;
- case 4:
- if (xquad_portio)
- *value = readl(adr);
- else
- *value = inl(0xCFC);
- break;
- }
-
- raw_spin_unlock_irqrestore(&pci_config_lock, flags);
-
- return 0;
-}
-
-static int pci_conf1_mq_write(unsigned int seg, unsigned int bus,
- unsigned int devfn, int reg, int len, u32 value)
-{
- unsigned long flags;
- void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus));
-
- WARN_ON(seg);
- if ((bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
- return -EINVAL;
-
- raw_spin_lock_irqsave(&pci_config_lock, flags);
-
- write_cf8(bus, devfn, reg);
-
- switch (len) {
- case 1:
- if (xquad_portio)
- writeb(value, adr + (reg & 3));
- else
- outb((u8)value, 0xCFC + (reg & 3));
- break;
- case 2:
- if (xquad_portio)
- writew(value, adr + (reg & 2));
- else
- outw((u16)value, 0xCFC + (reg & 2));
- break;
- case 4:
- if (xquad_portio)
- writel(value, adr + reg);
- else
- outl((u32)value, 0xCFC);
- break;
- }
-
- raw_spin_unlock_irqrestore(&pci_config_lock, flags);
-
- return 0;
-}
-
-#undef PCI_CONF1_MQ_ADDRESS
-
-static const struct pci_raw_ops pci_direct_conf1_mq = {
- .read = pci_conf1_mq_read,
- .write = pci_conf1_mq_write
-};
-
-
-static void pci_fixup_i450nx(struct pci_dev *d)
-{
- /*
- * i450NX -- Find and scan all secondary buses on all PXB's.
- */
- int pxb, reg;
- u8 busno, suba, subb;
- int quad = BUS2QUAD(d->bus->number);
-
- dev_info(&d->dev, "searching for i450NX host bridges\n");
- reg = 0xd0;
- for(pxb=0; pxb<2; pxb++) {
- pci_read_config_byte(d, reg++, &busno);
- pci_read_config_byte(d, reg++, &suba);
- pci_read_config_byte(d, reg++, &subb);
- dev_dbg(&d->dev, "i450NX PXB %d: %02x/%02x/%02x\n",
- pxb, busno, suba, subb);
- if (busno) {
- /* Bus A */
- pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, busno));
- }
- if (suba < subb) {
- /* Bus B */
- pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, suba+1));
- }
- }
- pcibios_last_bus = -1;
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx);
-
-int __init pci_numaq_init(void)
-{
- int quad;
-
- raw_pci_ops = &pci_direct_conf1_mq;
-
- pcibios_scan_root(0);
- if (num_online_nodes() > 1)
- for_each_online_node(quad) {
- if (quad == 0)
- continue;
- printk("Scanning PCI bus %d for quad %d\n",
- QUADLOCAL2BUS(quad,0), quad);
- pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, 0));
- }
- return 0;
-}
diff --git a/arch/x86/pci/visws.c b/arch/x86/pci/visws.c
deleted file mode 100644
index 3e6d2a6db866..000000000000
--- a/arch/x86/pci/visws.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Low-Level PCI Support for SGI Visual Workstation
- *
- * (c) 1999--2000 Martin Mares <mj@ucw.cz>
- */
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-
-#include <asm/setup.h>
-#include <asm/pci_x86.h>
-#include <asm/visws/cobalt.h>
-#include <asm/visws/lithium.h>
-
-static int pci_visws_enable_irq(struct pci_dev *dev) { return 0; }
-static void pci_visws_disable_irq(struct pci_dev *dev) { }
-
-/* int (*pcibios_enable_irq)(struct pci_dev *dev) = &pci_visws_enable_irq; */
-/* void (*pcibios_disable_irq)(struct pci_dev *dev) = &pci_visws_disable_irq; */
-
-/* void __init pcibios_penalize_isa_irq(int irq, int active) {} */
-
-
-unsigned int pci_bus0, pci_bus1;
-
-static int __init visws_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-{
- int irq, bus = dev->bus->number;
-
- pin--;
-
- /* Nothing useful at PIIX4 pin 1 */
- if (bus == pci_bus0 && slot == 4 && pin == 0)
- return -1;
-
- /* PIIX4 USB is on Bus 0, Slot 4, Line 3 */
- if (bus == pci_bus0 && slot == 4 && pin == 3) {
- irq = CO_IRQ(CO_APIC_PIIX4_USB);
- goto out;
- }
-
- /* First pin spread down 1 APIC entry per slot */
- if (pin == 0) {
- irq = CO_IRQ((bus == pci_bus0 ? CO_APIC_PCIB_BASE0 :
- CO_APIC_PCIA_BASE0) + slot);
- goto out;
- }
-
- /* lines 1,2,3 from any slot is shared in this twirly pattern */
- if (bus == pci_bus1) {
- /* lines 1-3 from devices 0 1 rotate over 2 apic entries */
- irq = CO_IRQ(CO_APIC_PCIA_BASE123 + ((slot + (pin - 1)) % 2));
- } else { /* bus == pci_bus0 */
- /* lines 1-3 from devices 0-3 rotate over 3 apic entries */
- if (slot == 0)
- slot = 3; /* same pattern */
- irq = CO_IRQ(CO_APIC_PCIA_BASE123 + ((3 - slot) + (pin - 1) % 3));
- }
-out:
- printk(KERN_DEBUG "PCI: Bus %d Slot %d Line %d -> IRQ %d\n", bus, slot, pin, irq);
- return irq;
-}
-
-int __init pci_visws_init(void)
-{
- pcibios_enable_irq = &pci_visws_enable_irq;
- pcibios_disable_irq = &pci_visws_disable_irq;
-
- /* The VISWS supports configuration access type 1 only */
- pci_probe = (pci_probe | PCI_PROBE_CONF1) &
- ~(PCI_PROBE_BIOS | PCI_PROBE_CONF2);
-
- pci_bus0 = li_pcib_read16(LI_PCI_BUSNUM) & 0xff;
- pci_bus1 = li_pcia_read16(LI_PCI_BUSNUM) & 0xff;
-
- printk(KERN_INFO "PCI: Lithium bridge A bus: %u, "
- "bridge B (PIIX4) bus: %u\n", pci_bus1, pci_bus0);
-
- raw_pci_ops = &pci_direct_conf1;
- pci_scan_bus_with_sysdata(pci_bus0);
- pci_scan_bus_with_sysdata(pci_bus1);
- pci_fixup_irqs(pci_common_swizzle, visws_map_irq);
- pcibios_resource_survey();
- /* Request bus scan */
- return 1;
-}
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
index 103e702ec5a7..905956f16465 100644
--- a/arch/x86/pci/xen.c
+++ b/arch/x86/pci/xen.c
@@ -178,6 +178,7 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
i = 0;
list_for_each_entry(msidesc, &dev->msi_list, list) {
irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i],
+ (type == PCI_CAP_ID_MSI) ? nvec : 1,
(type == PCI_CAP_ID_MSIX) ?
"pcifront-msi-x" :
"pcifront-msi",
@@ -245,6 +246,7 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
"xen: msi already bound to pirq=%d\n", pirq);
}
irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq,
+ (type == PCI_CAP_ID_MSI) ? nvec : 1,
(type == PCI_CAP_ID_MSIX) ?
"msi-x" : "msi",
DOMID_SELF);
@@ -269,9 +271,6 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
int ret = 0;
struct msi_desc *msidesc;
- if (type == PCI_CAP_ID_MSI && nvec > 1)
- return 1;
-
list_for_each_entry(msidesc, &dev->msi_list, list) {
struct physdev_map_pirq map_irq;
domid_t domid;
@@ -291,7 +290,10 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
(pci_domain_nr(dev->bus) << 16);
map_irq.devfn = dev->devfn;
- if (type == PCI_CAP_ID_MSIX) {
+ if (type == PCI_CAP_ID_MSI && nvec > 1) {
+ map_irq.type = MAP_PIRQ_TYPE_MULTI_MSI;
+ map_irq.entry_nr = nvec;
+ } else if (type == PCI_CAP_ID_MSIX) {
int pos;
u32 table_offset, bir;
@@ -308,6 +310,16 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
if (pci_seg_supported)
ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq,
&map_irq);
+ if (type == PCI_CAP_ID_MSI && nvec > 1 && ret) {
+ /*
+ * If MAP_PIRQ_TYPE_MULTI_MSI is not available
+ * there's nothing else we can do in this case.
+ * Just set ret > 0 so driver can retry with
+ * single MSI.
+ */
+ ret = 1;
+ goto out;
+ }
if (ret == -EINVAL && !pci_domain_nr(dev->bus)) {
map_irq.type = MAP_PIRQ_TYPE_MSI;
map_irq.index = -1;
@@ -324,11 +336,10 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
goto out;
}
- ret = xen_bind_pirq_msi_to_irq(dev, msidesc,
- map_irq.pirq,
- (type == PCI_CAP_ID_MSIX) ?
- "msi-x" : "msi",
- domid);
+ ret = xen_bind_pirq_msi_to_irq(dev, msidesc, map_irq.pirq,
+ (type == PCI_CAP_ID_MSI) ? nvec : 1,
+ (type == PCI_CAP_ID_MSIX) ? "msi-x" : "msi",
+ domid);
if (ret < 0)
goto out;
}
diff --git a/arch/x86/platform/Makefile b/arch/x86/platform/Makefile
index 20342d4c82ce..85afde1fa3e5 100644
--- a/arch/x86/platform/Makefile
+++ b/arch/x86/platform/Makefile
@@ -9,5 +9,4 @@ obj-y += olpc/
obj-y += scx200/
obj-y += sfi/
obj-y += ts5500/
-obj-y += visws/
obj-y += uv/
diff --git a/arch/x86/platform/efi/Makefile b/arch/x86/platform/efi/Makefile
index b7b0b35c1981..d51045afcaaf 100644
--- a/arch/x86/platform/efi/Makefile
+++ b/arch/x86/platform/efi/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o
obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
obj-$(CONFIG_EARLY_PRINTK_EFI) += early_printk.o
+obj-$(CONFIG_EFI_MIXED) += efi_thunk_$(BITS).o
diff --git a/arch/x86/platform/efi/efi-bgrt.c b/arch/x86/platform/efi/efi-bgrt.c
index 4df9591eadad..f15103dff4b4 100644
--- a/arch/x86/platform/efi/efi-bgrt.c
+++ b/arch/x86/platform/efi/efi-bgrt.c
@@ -42,7 +42,7 @@ void __init efi_bgrt_init(void)
if (bgrt_tab->header.length < sizeof(*bgrt_tab))
return;
- if (bgrt_tab->version != 1)
+ if (bgrt_tab->version != 1 || bgrt_tab->status != 1)
return;
if (bgrt_tab->image_type != 0 || !bgrt_tab->image_address)
return;
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index d62ec87a2b26..3781dd39e8bd 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -52,6 +52,7 @@
#include <asm/tlbflush.h>
#include <asm/x86_init.h>
#include <asm/rtc.h>
+#include <asm/uv/uv.h>
#define EFI_DEBUG
@@ -67,9 +68,7 @@ struct efi_memory_map memmap;
static struct efi efi_phys __initdata;
static efi_system_table_t efi_systab __initdata;
-unsigned long x86_efi_facility;
-
-static __initdata efi_config_table_type_t arch_tables[] = {
+static efi_config_table_type_t arch_tables[] __initdata = {
#ifdef CONFIG_X86_UV
{UV_SYSTEM_TABLE_GUID, "UVsystab", &efi.uv_systab},
#endif
@@ -78,16 +77,7 @@ static __initdata efi_config_table_type_t arch_tables[] = {
u64 efi_setup; /* efi setup_data physical address */
-/*
- * Returns 1 if 'facility' is enabled, 0 otherwise.
- */
-int efi_enabled(int facility)
-{
- return test_bit(facility, &x86_efi_facility) != 0;
-}
-EXPORT_SYMBOL(efi_enabled);
-
-static bool __initdata disable_runtime = false;
+static bool disable_runtime __initdata = false;
static int __init setup_noefi(char *arg)
{
disable_runtime = true;
@@ -256,27 +246,12 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
return status;
}
-static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
- efi_time_cap_t *tc)
-{
- unsigned long flags;
- efi_status_t status;
-
- spin_lock_irqsave(&rtc_lock, flags);
- efi_call_phys_prelog();
- status = efi_call_phys2(efi_phys.get_time, virt_to_phys(tm),
- virt_to_phys(tc));
- efi_call_phys_epilog();
- spin_unlock_irqrestore(&rtc_lock, flags);
- return status;
-}
-
int efi_set_rtc_mmss(const struct timespec *now)
{
unsigned long nowtime = now->tv_sec;
- efi_status_t status;
- efi_time_t eft;
- efi_time_cap_t cap;
+ efi_status_t status;
+ efi_time_t eft;
+ efi_time_cap_t cap;
struct rtc_time tm;
status = efi.get_time(&eft, &cap);
@@ -294,9 +269,8 @@ int efi_set_rtc_mmss(const struct timespec *now)
eft.second = tm.tm_sec;
eft.nanosecond = 0;
} else {
- printk(KERN_ERR
- "%s: Invalid EFI RTC value: write of %lx to EFI RTC failed\n",
- __FUNCTION__, nowtime);
+ pr_err("%s: Invalid EFI RTC value: write of %lx to EFI RTC failed\n",
+ __func__, nowtime);
return -1;
}
@@ -412,8 +386,7 @@ static void __init print_efi_memmap(void)
p < memmap.map_end;
p += memmap.desc_size, i++) {
md = p;
- pr_info("mem%02u: type=%u, attr=0x%llx, "
- "range=[0x%016llx-0x%016llx) (%lluMB)\n",
+ pr_info("mem%02u: type=%u, attr=0x%llx, range=[0x%016llx-0x%016llx) (%lluMB)\n",
i, md->type, md->attribute, md->phys_addr,
md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT),
(md->num_pages >> (20 - EFI_PAGE_SHIFT)));
@@ -445,9 +418,8 @@ void __init efi_reserve_boot_services(void)
memblock_is_region_reserved(start, size)) {
/* Could not reserve, skip it */
md->num_pages = 0;
- memblock_dbg("Could not reserve boot range "
- "[0x%010llx-0x%010llx]\n",
- start, start+size-1);
+ memblock_dbg("Could not reserve boot range [0x%010llx-0x%010llx]\n",
+ start, start+size-1);
} else
memblock_reserve(start, size);
}
@@ -455,7 +427,7 @@ void __init efi_reserve_boot_services(void)
void __init efi_unmap_memmap(void)
{
- clear_bit(EFI_MEMMAP, &x86_efi_facility);
+ clear_bit(EFI_MEMMAP, &efi.flags);
if (memmap.map) {
early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
memmap.map = NULL;
@@ -466,9 +438,6 @@ void __init efi_free_boot_services(void)
{
void *p;
- if (!efi_is_native())
- return;
-
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
efi_memory_desc_t *md = p;
unsigned long long start = md->phys_addr;
@@ -583,45 +552,82 @@ static int __init efi_systab_init(void *phys)
return -EINVAL;
}
if ((efi.systab->hdr.revision >> 16) == 0)
- pr_err("Warning: System table version "
- "%d.%02d, expected 1.00 or greater!\n",
+ pr_err("Warning: System table version %d.%02d, expected 1.00 or greater!\n",
efi.systab->hdr.revision >> 16,
efi.systab->hdr.revision & 0xffff);
+ set_bit(EFI_SYSTEM_TABLES, &efi.flags);
+
return 0;
}
-static int __init efi_runtime_init(void)
+static int __init efi_runtime_init32(void)
{
- efi_runtime_services_t *runtime;
+ efi_runtime_services_32_t *runtime;
+
+ runtime = early_ioremap((unsigned long)efi.systab->runtime,
+ sizeof(efi_runtime_services_32_t));
+ if (!runtime) {
+ pr_err("Could not map the runtime service table!\n");
+ return -ENOMEM;
+ }
/*
- * Check out the runtime services table. We need to map
- * the runtime services table so that we can grab the physical
- * address of several of the EFI runtime functions, needed to
- * set the firmware into virtual mode.
+ * We will only need *early* access to the following two
+ * EFI runtime services before set_virtual_address_map
+ * is invoked.
*/
+ efi_phys.set_virtual_address_map =
+ (efi_set_virtual_address_map_t *)
+ (unsigned long)runtime->set_virtual_address_map;
+ early_iounmap(runtime, sizeof(efi_runtime_services_32_t));
+
+ return 0;
+}
+
+static int __init efi_runtime_init64(void)
+{
+ efi_runtime_services_64_t *runtime;
+
runtime = early_ioremap((unsigned long)efi.systab->runtime,
- sizeof(efi_runtime_services_t));
+ sizeof(efi_runtime_services_64_t));
if (!runtime) {
pr_err("Could not map the runtime service table!\n");
return -ENOMEM;
}
+
/*
- * We will only need *early* access to the following
- * two EFI runtime services before set_virtual_address_map
+ * We will only need *early* access to the following two
+ * EFI runtime services before set_virtual_address_map
* is invoked.
*/
- efi_phys.get_time = (efi_get_time_t *)runtime->get_time;
efi_phys.set_virtual_address_map =
- (efi_set_virtual_address_map_t *)
- runtime->set_virtual_address_map;
+ (efi_set_virtual_address_map_t *)
+ (unsigned long)runtime->set_virtual_address_map;
+ early_iounmap(runtime, sizeof(efi_runtime_services_64_t));
+
+ return 0;
+}
+
+static int __init efi_runtime_init(void)
+{
+ int rv;
+
/*
- * Make efi_get_time can be called before entering
- * virtual mode.
+ * Check out the runtime services table. We need to map
+ * the runtime services table so that we can grab the physical
+ * address of several of the EFI runtime functions, needed to
+ * set the firmware into virtual mode.
*/
- efi.get_time = phys_efi_get_time;
- early_iounmap(runtime, sizeof(efi_runtime_services_t));
+ if (efi_enabled(EFI_64BIT))
+ rv = efi_runtime_init64();
+ else
+ rv = efi_runtime_init32();
+
+ if (rv)
+ return rv;
+
+ set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
return 0;
}
@@ -640,6 +646,8 @@ static int __init efi_memmap_init(void)
if (add_efi_memmap)
do_add_efi_memmap();
+ set_bit(EFI_MEMMAP, &efi.flags);
+
return 0;
}
@@ -722,7 +730,7 @@ void __init efi_init(void)
if (efi_systab_init(efi_phys.systab))
return;
- set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility);
+ set_bit(EFI_SYSTEM_TABLES, &efi.flags);
efi.config_table = (unsigned long)efi.systab->tables;
efi.fw_vendor = (unsigned long)efi.systab->fw_vendor;
@@ -750,24 +758,21 @@ void __init efi_init(void)
if (efi_config_init(arch_tables))
return;
- set_bit(EFI_CONFIG_TABLES, &x86_efi_facility);
-
/*
* Note: We currently don't support runtime services on an EFI
* that doesn't match the kernel 32/64-bit mode.
*/
- if (!efi_is_native())
+ if (!efi_runtime_supported())
pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n");
else {
if (disable_runtime || efi_runtime_init())
return;
- set_bit(EFI_RUNTIME_SERVICES, &x86_efi_facility);
}
if (efi_memmap_init())
return;
- set_bit(EFI_MEMMAP, &x86_efi_facility);
+ set_bit(EFI_MEMMAP, &efi.flags);
print_efi_memmap();
}
@@ -792,7 +797,7 @@ void __init efi_set_executable(efi_memory_desc_t *md, bool executable)
set_memory_nx(addr, npages);
}
-static void __init runtime_code_page_mkexec(void)
+void __init runtime_code_page_mkexec(void)
{
efi_memory_desc_t *md;
void *p;
@@ -844,6 +849,22 @@ void __init old_map_region(efi_memory_desc_t *md)
(unsigned long long)md->phys_addr);
}
+static void native_runtime_setup(void)
+{
+ efi.get_time = virt_efi_get_time;
+ efi.set_time = virt_efi_set_time;
+ efi.get_wakeup_time = virt_efi_get_wakeup_time;
+ efi.set_wakeup_time = virt_efi_set_wakeup_time;
+ efi.get_variable = virt_efi_get_variable;
+ efi.get_next_variable = virt_efi_get_next_variable;
+ efi.set_variable = virt_efi_set_variable;
+ efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
+ efi.reset_system = virt_efi_reset_system;
+ efi.query_variable_info = virt_efi_query_variable_info;
+ efi.update_capsule = virt_efi_update_capsule;
+ efi.query_capsule_caps = virt_efi_query_capsule_caps;
+}
+
/* Merge contiguous regions of the same type and attribute */
static void __init efi_merge_regions(void)
{
@@ -891,8 +912,9 @@ static void __init get_systab_virt_addr(efi_memory_desc_t *md)
}
}
-static int __init save_runtime_map(void)
+static void __init save_runtime_map(void)
{
+#ifdef CONFIG_KEXEC
efi_memory_desc_t *md;
void *tmp, *p, *q = NULL;
int count = 0;
@@ -914,38 +936,44 @@ static int __init save_runtime_map(void)
}
efi_runtime_map_setup(q, count, memmap.desc_size);
+ return;
- return 0;
out:
kfree(q);
- return -ENOMEM;
+ pr_err("Error saving runtime map, efi runtime on kexec non-functional!!\n");
+#endif
}
-/*
- * Map efi regions which were passed via setup_data. The virt_addr is a fixed
- * addr which was used in first kernel of a kexec boot.
- */
-static void __init efi_map_regions_fixed(void)
+static void *realloc_pages(void *old_memmap, int old_shift)
{
- void *p;
- efi_memory_desc_t *md;
+ void *ret;
- for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
- md = p;
- efi_map_region_fixed(md); /* FIXME: add error handling */
- get_systab_virt_addr(md);
- }
+ ret = (void *)__get_free_pages(GFP_KERNEL, old_shift + 1);
+ if (!ret)
+ goto out;
+
+ /*
+ * A first-time allocation doesn't have anything to copy.
+ */
+ if (!old_memmap)
+ return ret;
+ memcpy(ret, old_memmap, PAGE_SIZE << old_shift);
+
+out:
+ free_pages((unsigned long)old_memmap, old_shift);
+ return ret;
}
/*
- * Map efi memory ranges for runtime serivce and update new_memmap with virtual
- * addresses.
+ * Map the efi memory ranges of the runtime services and update new_mmap with
+ * virtual addresses.
*/
-static void * __init efi_map_regions(int *count)
+static void * __init efi_map_regions(int *count, int *pg_shift)
{
+ void *p, *new_memmap = NULL;
+ unsigned long left = 0;
efi_memory_desc_t *md;
- void *p, *tmp, *new_memmap = NULL;
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
md = p;
@@ -960,20 +988,80 @@ static void * __init efi_map_regions(int *count)
efi_map_region(md);
get_systab_virt_addr(md);
- tmp = krealloc(new_memmap, (*count + 1) * memmap.desc_size,
- GFP_KERNEL);
- if (!tmp)
- goto out;
- new_memmap = tmp;
+ if (left < memmap.desc_size) {
+ new_memmap = realloc_pages(new_memmap, *pg_shift);
+ if (!new_memmap)
+ return NULL;
+
+ left += PAGE_SIZE << *pg_shift;
+ (*pg_shift)++;
+ }
+
memcpy(new_memmap + (*count * memmap.desc_size), md,
memmap.desc_size);
+
+ left -= memmap.desc_size;
(*count)++;
}
return new_memmap;
-out:
- kfree(new_memmap);
- return NULL;
+}
+
+static void __init kexec_enter_virtual_mode(void)
+{
+#ifdef CONFIG_KEXEC
+ efi_memory_desc_t *md;
+ void *p;
+
+ efi.systab = NULL;
+
+ /*
+ * We don't do virtual mode, since we don't do runtime services, on
+ * non-native EFI
+ */
+ if (!efi_is_native()) {
+ efi_unmap_memmap();
+ return;
+ }
+
+ /*
+ * Map efi regions which were passed via setup_data. The virt_addr is a
+ * fixed addr which was used in first kernel of a kexec boot.
+ */
+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+ md = p;
+ efi_map_region_fixed(md); /* FIXME: add error handling */
+ get_systab_virt_addr(md);
+ }
+
+ save_runtime_map();
+
+ BUG_ON(!efi.systab);
+
+ efi_sync_low_kernel_mappings();
+
+ /*
+ * Now that EFI is in virtual mode, update the function
+ * pointers in the runtime service table to the new virtual addresses.
+ *
+ * Call EFI services through wrapper functions.
+ */
+ efi.runtime_version = efi_systab.hdr.revision;
+
+ native_runtime_setup();
+
+ efi.set_virtual_address_map = NULL;
+
+ if (efi_enabled(EFI_OLD_MEMMAP) && (__supported_pte_mask & _PAGE_NX))
+ runtime_code_page_mkexec();
+
+ /* clean DUMMY object */
+ efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ 0, NULL);
+#endif
}
/*
@@ -995,57 +1083,53 @@ out:
*
* Specially for kexec boot, efi runtime maps in previous kernel should
* be passed in via setup_data. In that case runtime ranges will be mapped
- * to the same virtual addresses as the first kernel.
+ * to the same virtual addresses as the first kernel, see
+ * kexec_enter_virtual_mode().
*/
-void __init efi_enter_virtual_mode(void)
+static void __init __efi_enter_virtual_mode(void)
{
- efi_status_t status;
+ int count = 0, pg_shift = 0;
void *new_memmap = NULL;
- int err, count = 0;
+ efi_status_t status;
efi.systab = NULL;
- /*
- * We don't do virtual mode, since we don't do runtime services, on
- * non-native EFI
- */
- if (!efi_is_native()) {
- efi_unmap_memmap();
+ efi_merge_regions();
+ new_memmap = efi_map_regions(&count, &pg_shift);
+ if (!new_memmap) {
+ pr_err("Error reallocating memory, EFI runtime non-functional!\n");
return;
}
- if (efi_setup) {
- efi_map_regions_fixed();
- } else {
- efi_merge_regions();
- new_memmap = efi_map_regions(&count);
- if (!new_memmap) {
- pr_err("Error reallocating memory, EFI runtime non-functional!\n");
- return;
- }
- }
-
- err = save_runtime_map();
- if (err)
- pr_err("Error saving runtime map, efi runtime on kexec non-functional!!\n");
+ save_runtime_map();
BUG_ON(!efi.systab);
- efi_setup_page_tables();
+ if (efi_setup_page_tables(__pa(new_memmap), 1 << pg_shift))
+ return;
+
efi_sync_low_kernel_mappings();
+ efi_dump_pagetable();
- if (!efi_setup) {
+ if (efi_is_native()) {
status = phys_efi_set_virtual_address_map(
- memmap.desc_size * count,
- memmap.desc_size,
- memmap.desc_version,
- (efi_memory_desc_t *)__pa(new_memmap));
-
- if (status != EFI_SUCCESS) {
- pr_alert("Unable to switch EFI into virtual mode (status=%lx)!\n",
- status);
- panic("EFI call to SetVirtualAddressMap() failed!");
- }
+ memmap.desc_size * count,
+ memmap.desc_size,
+ memmap.desc_version,
+ (efi_memory_desc_t *)__pa(new_memmap));
+ } else {
+ status = efi_thunk_set_virtual_address_map(
+ efi_phys.set_virtual_address_map,
+ memmap.desc_size * count,
+ memmap.desc_size,
+ memmap.desc_version,
+ (efi_memory_desc_t *)__pa(new_memmap));
+ }
+
+ if (status != EFI_SUCCESS) {
+ pr_alert("Unable to switch EFI into virtual mode (status=%lx)!\n",
+ status);
+ panic("EFI call to SetVirtualAddressMap() failed!");
}
/*
@@ -1055,24 +1139,43 @@ void __init efi_enter_virtual_mode(void)
* Call EFI services through wrapper functions.
*/
efi.runtime_version = efi_systab.hdr.revision;
- efi.get_time = virt_efi_get_time;
- efi.set_time = virt_efi_set_time;
- efi.get_wakeup_time = virt_efi_get_wakeup_time;
- efi.set_wakeup_time = virt_efi_set_wakeup_time;
- efi.get_variable = virt_efi_get_variable;
- efi.get_next_variable = virt_efi_get_next_variable;
- efi.set_variable = virt_efi_set_variable;
- efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
- efi.reset_system = virt_efi_reset_system;
+
+ if (efi_is_native())
+ native_runtime_setup();
+ else
+ efi_thunk_runtime_setup();
+
efi.set_virtual_address_map = NULL;
- efi.query_variable_info = virt_efi_query_variable_info;
- efi.update_capsule = virt_efi_update_capsule;
- efi.query_capsule_caps = virt_efi_query_capsule_caps;
- if (efi_enabled(EFI_OLD_MEMMAP) && (__supported_pte_mask & _PAGE_NX))
- runtime_code_page_mkexec();
+ efi_runtime_mkexec();
- kfree(new_memmap);
+ /*
+ * We mapped the descriptor array into the EFI pagetable above but we're
+ * not unmapping it here. Here's why:
+ *
+ * We're copying select PGDs from the kernel page table to the EFI page
+ * table and when we do so and make changes to those PGDs like unmapping
+ * stuff from them, those changes appear in the kernel page table and we
+ * go boom.
+ *
+ * From setup_real_mode():
+ *
+ * ...
+ * trampoline_pgd[0] = init_level4_pgt[pgd_index(__PAGE_OFFSET)].pgd;
+ *
+ * In this particular case, our allocation is in PGD 0 of the EFI page
+ * table but we've copied that PGD from PGD[272] of the EFI page table:
+ *
+ * pgd_index(__PAGE_OFFSET = 0xffff880000000000) = 272
+ *
+ * where the direct memory mapping in kernel space is.
+ *
+ * new_memmap's VA comes from that direct mapping and thus clearing it,
+ * it would get cleared in the kernel page table too.
+ *
+ * efi_cleanup_page_tables(__pa(new_memmap), 1 << pg_shift);
+ */
+ free_pages((unsigned long)new_memmap, pg_shift);
/* clean DUMMY object */
efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
@@ -1082,6 +1185,14 @@ void __init efi_enter_virtual_mode(void)
0, NULL);
}
+void __init efi_enter_virtual_mode(void)
+{
+ if (efi_setup)
+ kexec_enter_virtual_mode();
+ else
+ __efi_enter_virtual_mode();
+}
+
/*
* Convenience functions to obtain memory types and attributes
*/
@@ -1119,9 +1230,8 @@ u64 efi_mem_attributes(unsigned long phys_addr)
}
/*
- * Some firmware has serious problems when using more than 50% of the EFI
- * variable store, i.e. it triggers bugs that can brick machines. Ensure that
- * we never use more than this safe limit.
+ * Some firmware implementations refuse to boot if there's insufficient space
+ * in the variable store. Ensure that we never use more than a safe limit.
*
* Return EFI_SUCCESS if it is safe to write 'size' bytes to the variable
* store.
@@ -1140,10 +1250,9 @@ efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
return status;
/*
- * Some firmware implementations refuse to boot if there's insufficient
- * space in the variable store. We account for that by refusing the
- * write if permitting it would reduce the available space to under
- * 5KB. This figure was provided by Samsung, so should be safe.
+ * We account for that by refusing the write if permitting it would
+ * reduce the available space to under 5KB. This figure was provided by
+ * Samsung, so should be safe.
*/
if ((remaining_size - size < EFI_MIN_RESERVE) &&
!efi_no_storage_paranoia) {
@@ -1206,8 +1315,27 @@ static int __init parse_efi_cmdline(char *str)
str++;
if (!strncmp(str, "old_map", 7))
- set_bit(EFI_OLD_MEMMAP, &x86_efi_facility);
+ set_bit(EFI_OLD_MEMMAP, &efi.flags);
return 0;
}
early_param("efi", parse_efi_cmdline);
+
+void __init efi_apply_memmap_quirks(void)
+{
+ /*
+ * Once setup is done earlier, unmap the EFI memory map on mismatched
+ * firmware/kernel architectures since there is no support for runtime
+ * services.
+ */
+ if (!efi_runtime_supported()) {
+ pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n");
+ efi_unmap_memmap();
+ }
+
+ /*
+ * UV doesn't support the new EFI pagetable mapping yet.
+ */
+ if (is_uv_system())
+ set_bit(EFI_OLD_MEMMAP, &efi.flags);
+}
diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c
index 249b183cf417..9ee3491e31fb 100644
--- a/arch/x86/platform/efi/efi_32.c
+++ b/arch/x86/platform/efi/efi_32.c
@@ -40,7 +40,12 @@
static unsigned long efi_rt_eflags;
void efi_sync_low_kernel_mappings(void) {}
-void efi_setup_page_tables(void) {}
+void __init efi_dump_pagetable(void) {}
+int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
+{
+ return 0;
+}
+void efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages) {}
void __init efi_map_region(efi_memory_desc_t *md)
{
@@ -77,3 +82,9 @@ void efi_call_phys_epilog(void)
local_irq_restore(efi_rt_eflags);
}
+
+void __init efi_runtime_mkexec(void)
+{
+ if (__supported_pte_mask & _PAGE_NX)
+ runtime_code_page_mkexec();
+}
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c
index 6284f158a47d..290d397e1dd9 100644
--- a/arch/x86/platform/efi/efi_64.c
+++ b/arch/x86/platform/efi/efi_64.c
@@ -39,6 +39,7 @@
#include <asm/cacheflush.h>
#include <asm/fixmap.h>
#include <asm/realmode.h>
+#include <asm/time.h>
static pgd_t *save_pgd __initdata;
static unsigned long efi_flags __initdata;
@@ -58,7 +59,8 @@ struct efi_scratch {
u64 prev_cr3;
pgd_t *efi_pgt;
bool use_pgd;
-};
+ u64 phys_stack;
+} __packed;
static void __init early_code_mapping_set_exec(int executable)
{
@@ -137,12 +139,64 @@ void efi_sync_low_kernel_mappings(void)
sizeof(pgd_t) * num_pgds);
}
-void efi_setup_page_tables(void)
+int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
{
+ unsigned long text;
+ struct page *page;
+ unsigned npages;
+ pgd_t *pgd;
+
+ if (efi_enabled(EFI_OLD_MEMMAP))
+ return 0;
+
efi_scratch.efi_pgt = (pgd_t *)(unsigned long)real_mode_header->trampoline_pgd;
+ pgd = __va(efi_scratch.efi_pgt);
- if (!efi_enabled(EFI_OLD_MEMMAP))
- efi_scratch.use_pgd = true;
+ /*
+ * It can happen that the physical address of new_memmap lands in memory
+ * which is not mapped in the EFI page table. Therefore we need to go
+ * and ident-map those pages containing the map before calling
+ * phys_efi_set_virtual_address_map().
+ */
+ if (kernel_map_pages_in_pgd(pgd, pa_memmap, pa_memmap, num_pages, _PAGE_NX)) {
+ pr_err("Error ident-mapping new memmap (0x%lx)!\n", pa_memmap);
+ return 1;
+ }
+
+ efi_scratch.use_pgd = true;
+
+ /*
+ * When making calls to the firmware everything needs to be 1:1
+ * mapped and addressable with 32-bit pointers. Map the kernel
+ * text and allocate a new stack because we can't rely on the
+ * stack pointer being < 4GB.
+ */
+ if (!IS_ENABLED(CONFIG_EFI_MIXED))
+ return 0;
+
+ page = alloc_page(GFP_KERNEL|__GFP_DMA32);
+ if (!page)
+ panic("Unable to allocate EFI runtime stack < 4GB\n");
+
+ efi_scratch.phys_stack = virt_to_phys(page_address(page));
+ efi_scratch.phys_stack += PAGE_SIZE; /* stack grows down */
+
+ npages = (_end - _text) >> PAGE_SHIFT;
+ text = __pa(_text);
+
+ if (kernel_map_pages_in_pgd(pgd, text >> PAGE_SHIFT, text, npages, 0)) {
+ pr_err("Failed to map kernel text 1:1\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+void efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages)
+{
+ pgd_t *pgd = (pgd_t *)__va(real_mode_header->trampoline_pgd);
+
+ kernel_unmap_pages_in_pgd(pgd, pa_memmap, num_pages);
}
static void __init __map_region(efi_memory_desc_t *md, u64 va)
@@ -173,6 +227,16 @@ void __init efi_map_region(efi_memory_desc_t *md)
*/
__map_region(md, md->phys_addr);
+ /*
+ * Enforce the 1:1 mapping as the default virtual address when
+ * booting in EFI mixed mode, because even though we may be
+ * running a 64-bit kernel, the firmware may only be 32-bit.
+ */
+ if (!efi_is_native () && IS_ENABLED(CONFIG_EFI_MIXED)) {
+ md->virt_addr = md->phys_addr;
+ return;
+ }
+
efi_va -= size;
/* Is PA 2M-aligned? */
@@ -233,3 +297,308 @@ void __init parse_efi_setup(u64 phys_addr, u32 data_len)
{
efi_setup = phys_addr + sizeof(struct setup_data);
}
+
+void __init efi_runtime_mkexec(void)
+{
+ if (!efi_enabled(EFI_OLD_MEMMAP))
+ return;
+
+ if (__supported_pte_mask & _PAGE_NX)
+ runtime_code_page_mkexec();
+}
+
+void __init efi_dump_pagetable(void)
+{
+#ifdef CONFIG_EFI_PGT_DUMP
+ pgd_t *pgd = (pgd_t *)__va(real_mode_header->trampoline_pgd);
+
+ ptdump_walk_pgd_level(NULL, pgd);
+#endif
+}
+
+#ifdef CONFIG_EFI_MIXED
+extern efi_status_t efi64_thunk(u32, ...);
+
+#define runtime_service32(func) \
+({ \
+ u32 table = (u32)(unsigned long)efi.systab; \
+ u32 *rt, *___f; \
+ \
+ rt = (u32 *)(table + offsetof(efi_system_table_32_t, runtime)); \
+ ___f = (u32 *)(*rt + offsetof(efi_runtime_services_32_t, func)); \
+ *___f; \
+})
+
+/*
+ * Switch to the EFI page tables early so that we can access the 1:1
+ * runtime services mappings which are not mapped in any other page
+ * tables. This function must be called before runtime_service32().
+ *
+ * Also, disable interrupts because the IDT points to 64-bit handlers,
+ * which aren't going to function correctly when we switch to 32-bit.
+ */
+#define efi_thunk(f, ...) \
+({ \
+ efi_status_t __s; \
+ unsigned long flags; \
+ u32 func; \
+ \
+ efi_sync_low_kernel_mappings(); \
+ local_irq_save(flags); \
+ \
+ efi_scratch.prev_cr3 = read_cr3(); \
+ write_cr3((unsigned long)efi_scratch.efi_pgt); \
+ __flush_tlb_all(); \
+ \
+ func = runtime_service32(f); \
+ __s = efi64_thunk(func, __VA_ARGS__); \
+ \
+ write_cr3(efi_scratch.prev_cr3); \
+ __flush_tlb_all(); \
+ local_irq_restore(flags); \
+ \
+ __s; \
+})
+
+efi_status_t efi_thunk_set_virtual_address_map(
+ void *phys_set_virtual_address_map,
+ unsigned long memory_map_size,
+ unsigned long descriptor_size,
+ u32 descriptor_version,
+ efi_memory_desc_t *virtual_map)
+{
+ efi_status_t status;
+ unsigned long flags;
+ u32 func;
+
+ efi_sync_low_kernel_mappings();
+ local_irq_save(flags);
+
+ efi_scratch.prev_cr3 = read_cr3();
+ write_cr3((unsigned long)efi_scratch.efi_pgt);
+ __flush_tlb_all();
+
+ func = (u32)(unsigned long)phys_set_virtual_address_map;
+ status = efi64_thunk(func, memory_map_size, descriptor_size,
+ descriptor_version, virtual_map);
+
+ write_cr3(efi_scratch.prev_cr3);
+ __flush_tlb_all();
+ local_irq_restore(flags);
+
+ return status;
+}
+
+static efi_status_t efi_thunk_get_time(efi_time_t *tm, efi_time_cap_t *tc)
+{
+ efi_status_t status;
+ u32 phys_tm, phys_tc;
+
+ spin_lock(&rtc_lock);
+
+ phys_tm = virt_to_phys(tm);
+ phys_tc = virt_to_phys(tc);
+
+ status = efi_thunk(get_time, phys_tm, phys_tc);
+
+ spin_unlock(&rtc_lock);
+
+ return status;
+}
+
+static efi_status_t efi_thunk_set_time(efi_time_t *tm)
+{
+ efi_status_t status;
+ u32 phys_tm;
+
+ spin_lock(&rtc_lock);
+
+ phys_tm = virt_to_phys(tm);
+
+ status = efi_thunk(set_time, phys_tm);
+
+ spin_unlock(&rtc_lock);
+
+ return status;
+}
+
+static efi_status_t
+efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending,
+ efi_time_t *tm)
+{
+ efi_status_t status;
+ u32 phys_enabled, phys_pending, phys_tm;
+
+ spin_lock(&rtc_lock);
+
+ phys_enabled = virt_to_phys(enabled);
+ phys_pending = virt_to_phys(pending);
+ phys_tm = virt_to_phys(tm);
+
+ status = efi_thunk(get_wakeup_time, phys_enabled,
+ phys_pending, phys_tm);
+
+ spin_unlock(&rtc_lock);
+
+ return status;
+}
+
+static efi_status_t
+efi_thunk_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
+{
+ efi_status_t status;
+ u32 phys_tm;
+
+ spin_lock(&rtc_lock);
+
+ phys_tm = virt_to_phys(tm);
+
+ status = efi_thunk(set_wakeup_time, enabled, phys_tm);
+
+ spin_unlock(&rtc_lock);
+
+ return status;
+}
+
+
+static efi_status_t
+efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,
+ u32 *attr, unsigned long *data_size, void *data)
+{
+ efi_status_t status;
+ u32 phys_name, phys_vendor, phys_attr;
+ u32 phys_data_size, phys_data;
+
+ phys_data_size = virt_to_phys(data_size);
+ phys_vendor = virt_to_phys(vendor);
+ phys_name = virt_to_phys(name);
+ phys_attr = virt_to_phys(attr);
+ phys_data = virt_to_phys(data);
+
+ status = efi_thunk(get_variable, phys_name, phys_vendor,
+ phys_attr, phys_data_size, phys_data);
+
+ return status;
+}
+
+static efi_status_t
+efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor,
+ u32 attr, unsigned long data_size, void *data)
+{
+ u32 phys_name, phys_vendor, phys_data;
+ efi_status_t status;
+
+ phys_name = virt_to_phys(name);
+ phys_vendor = virt_to_phys(vendor);
+ phys_data = virt_to_phys(data);
+
+ /* If data_size is > sizeof(u32) we've got problems */
+ status = efi_thunk(set_variable, phys_name, phys_vendor,
+ attr, data_size, phys_data);
+
+ return status;
+}
+
+static efi_status_t
+efi_thunk_get_next_variable(unsigned long *name_size,
+ efi_char16_t *name,
+ efi_guid_t *vendor)
+{
+ efi_status_t status;
+ u32 phys_name_size, phys_name, phys_vendor;
+
+ phys_name_size = virt_to_phys(name_size);
+ phys_vendor = virt_to_phys(vendor);
+ phys_name = virt_to_phys(name);
+
+ status = efi_thunk(get_next_variable, phys_name_size,
+ phys_name, phys_vendor);
+
+ return status;
+}
+
+static efi_status_t
+efi_thunk_get_next_high_mono_count(u32 *count)
+{
+ efi_status_t status;
+ u32 phys_count;
+
+ phys_count = virt_to_phys(count);
+ status = efi_thunk(get_next_high_mono_count, phys_count);
+
+ return status;
+}
+
+static void
+efi_thunk_reset_system(int reset_type, efi_status_t status,
+ unsigned long data_size, efi_char16_t *data)
+{
+ u32 phys_data;
+
+ phys_data = virt_to_phys(data);
+
+ efi_thunk(reset_system, reset_type, status, data_size, phys_data);
+}
+
+static efi_status_t
+efi_thunk_update_capsule(efi_capsule_header_t **capsules,
+ unsigned long count, unsigned long sg_list)
+{
+ /*
+ * To properly support this function we would need to repackage
+ * 'capsules' because the firmware doesn't understand 64-bit
+ * pointers.
+ */
+ return EFI_UNSUPPORTED;
+}
+
+static efi_status_t
+efi_thunk_query_variable_info(u32 attr, u64 *storage_space,
+ u64 *remaining_space,
+ u64 *max_variable_size)
+{
+ efi_status_t status;
+ u32 phys_storage, phys_remaining, phys_max;
+
+ if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
+ return EFI_UNSUPPORTED;
+
+ phys_storage = virt_to_phys(storage_space);
+ phys_remaining = virt_to_phys(remaining_space);
+ phys_max = virt_to_phys(max_variable_size);
+
+ status = efi_thunk(query_variable_info, attr, phys_storage,
+ phys_remaining, phys_max);
+
+ return status;
+}
+
+static efi_status_t
+efi_thunk_query_capsule_caps(efi_capsule_header_t **capsules,
+ unsigned long count, u64 *max_size,
+ int *reset_type)
+{
+ /*
+ * To properly support this function we would need to repackage
+ * 'capsules' because the firmware doesn't understand 64-bit
+ * pointers.
+ */
+ return EFI_UNSUPPORTED;
+}
+
+void efi_thunk_runtime_setup(void)
+{
+ efi.get_time = efi_thunk_get_time;
+ efi.set_time = efi_thunk_set_time;
+ efi.get_wakeup_time = efi_thunk_get_wakeup_time;
+ efi.set_wakeup_time = efi_thunk_set_wakeup_time;
+ efi.get_variable = efi_thunk_get_variable;
+ efi.get_next_variable = efi_thunk_get_next_variable;
+ efi.set_variable = efi_thunk_set_variable;
+ efi.get_next_high_mono_count = efi_thunk_get_next_high_mono_count;
+ efi.reset_system = efi_thunk_reset_system;
+ efi.query_variable_info = efi_thunk_query_variable_info;
+ efi.update_capsule = efi_thunk_update_capsule;
+ efi.query_capsule_caps = efi_thunk_query_capsule_caps;
+}
+#endif /* CONFIG_EFI_MIXED */
diff --git a/arch/x86/platform/efi/efi_stub_64.S b/arch/x86/platform/efi/efi_stub_64.S
index 88073b140298..e0984ef0374b 100644
--- a/arch/x86/platform/efi/efi_stub_64.S
+++ b/arch/x86/platform/efi/efi_stub_64.S
@@ -7,6 +7,10 @@
*/
#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/msr.h>
+#include <asm/processor-flags.h>
+#include <asm/page_types.h>
#define SAVE_XMM \
mov %rsp, %rax; \
@@ -164,7 +168,169 @@ ENTRY(efi_call6)
ret
ENDPROC(efi_call6)
+#ifdef CONFIG_EFI_MIXED
+
+/*
+ * We run this function from the 1:1 mapping.
+ *
+ * This function must be invoked with a 1:1 mapped stack.
+ */
+ENTRY(__efi64_thunk)
+ movl %ds, %eax
+ push %rax
+ movl %es, %eax
+ push %rax
+ movl %ss, %eax
+ push %rax
+
+ subq $32, %rsp
+ movl %esi, 0x0(%rsp)
+ movl %edx, 0x4(%rsp)
+ movl %ecx, 0x8(%rsp)
+ movq %r8, %rsi
+ movl %esi, 0xc(%rsp)
+ movq %r9, %rsi
+ movl %esi, 0x10(%rsp)
+
+ sgdt save_gdt(%rip)
+
+ leaq 1f(%rip), %rbx
+ movq %rbx, func_rt_ptr(%rip)
+
+ /* Switch to gdt with 32-bit segments */
+ movl 64(%rsp), %eax
+ lgdt (%rax)
+
+ leaq efi_enter32(%rip), %rax
+ pushq $__KERNEL_CS
+ pushq %rax
+ lretq
+
+1: addq $32, %rsp
+
+ lgdt save_gdt(%rip)
+
+ pop %rbx
+ movl %ebx, %ss
+ pop %rbx
+ movl %ebx, %es
+ pop %rbx
+ movl %ebx, %ds
+
+ /*
+ * Convert 32-bit status code into 64-bit.
+ */
+ test %rax, %rax
+ jz 1f
+ movl %eax, %ecx
+ andl $0x0fffffff, %ecx
+ andl $0xf0000000, %eax
+ shl $32, %rax
+ or %rcx, %rax
+1:
+ ret
+ENDPROC(__efi64_thunk)
+
+ENTRY(efi_exit32)
+ movq func_rt_ptr(%rip), %rax
+ push %rax
+ mov %rdi, %rax
+ ret
+ENDPROC(efi_exit32)
+
+ .code32
+/*
+ * EFI service pointer must be in %edi.
+ *
+ * The stack should represent the 32-bit calling convention.
+ */
+ENTRY(efi_enter32)
+ movl $__KERNEL_DS, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+
+ /* Reload pgtables */
+ movl %cr3, %eax
+ movl %eax, %cr3
+
+ /* Disable paging */
+ movl %cr0, %eax
+ btrl $X86_CR0_PG_BIT, %eax
+ movl %eax, %cr0
+
+ /* Disable long mode via EFER */
+ movl $MSR_EFER, %ecx
+ rdmsr
+ btrl $_EFER_LME, %eax
+ wrmsr
+
+ call *%edi
+
+ /* We must preserve return value */
+ movl %eax, %edi
+
+ /*
+ * Some firmware will return with interrupts enabled. Be sure to
+ * disable them before we switch GDTs.
+ */
+ cli
+
+ movl 68(%esp), %eax
+ movl %eax, 2(%eax)
+ lgdtl (%eax)
+
+ movl %cr4, %eax
+ btsl $(X86_CR4_PAE_BIT), %eax
+ movl %eax, %cr4
+
+ movl %cr3, %eax
+ movl %eax, %cr3
+
+ movl $MSR_EFER, %ecx
+ rdmsr
+ btsl $_EFER_LME, %eax
+ wrmsr
+
+ xorl %eax, %eax
+ lldt %ax
+
+ movl 72(%esp), %eax
+ pushl $__KERNEL_CS
+ pushl %eax
+
+ /* Enable paging */
+ movl %cr0, %eax
+ btsl $X86_CR0_PG_BIT, %eax
+ movl %eax, %cr0
+ lret
+ENDPROC(efi_enter32)
+
+ .data
+ .balign 8
+ .global efi32_boot_gdt
+efi32_boot_gdt: .word 0
+ .quad 0
+
+save_gdt: .word 0
+ .quad 0
+func_rt_ptr: .quad 0
+
+ .global efi_gdt64
+efi_gdt64:
+ .word efi_gdt64_end - efi_gdt64
+ .long 0 /* Filled out by user */
+ .word 0
+ .quad 0x0000000000000000 /* NULL descriptor */
+ .quad 0x00af9a000000ffff /* __KERNEL_CS */
+ .quad 0x00cf92000000ffff /* __KERNEL_DS */
+ .quad 0x0080890000000000 /* TS descriptor */
+ .quad 0x0000000000000000 /* TS continued */
+efi_gdt64_end:
+#endif /* CONFIG_EFI_MIXED */
+
.data
ENTRY(efi_scratch)
.fill 3,8,0
.byte 0
+ .quad 0
diff --git a/arch/x86/platform/efi/efi_thunk_64.S b/arch/x86/platform/efi/efi_thunk_64.S
new file mode 100644
index 000000000000..8806fa73e6e6
--- /dev/null
+++ b/arch/x86/platform/efi/efi_thunk_64.S
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 Intel Corporation; author Matt Fleming
+ */
+
+#include <linux/linkage.h>
+#include <asm/page_types.h>
+
+ .text
+ .code64
+ENTRY(efi64_thunk)
+ push %rbp
+ push %rbx
+
+ /*
+ * Switch to 1:1 mapped 32-bit stack pointer.
+ */
+ movq %rsp, efi_saved_sp(%rip)
+ movq efi_scratch+25(%rip), %rsp
+
+ /*
+ * Calculate the physical address of the kernel text.
+ */
+ movq $__START_KERNEL_map, %rax
+ subq phys_base(%rip), %rax
+
+ /*
+ * Push some physical addresses onto the stack. This is easier
+ * to do now in a code64 section while the assembler can address
+ * 64-bit values. Note that all the addresses on the stack are
+ * 32-bit.
+ */
+ subq $16, %rsp
+ leaq efi_exit32(%rip), %rbx
+ subq %rax, %rbx
+ movl %ebx, 8(%rsp)
+ leaq efi_gdt64(%rip), %rbx
+ subq %rax, %rbx
+ movl %ebx, 2(%ebx)
+ movl %ebx, 4(%rsp)
+ leaq efi_gdt32(%rip), %rbx
+ subq %rax, %rbx
+ movl %ebx, 2(%ebx)
+ movl %ebx, (%rsp)
+
+ leaq __efi64_thunk(%rip), %rbx
+ subq %rax, %rbx
+ call *%rbx
+
+ movq efi_saved_sp(%rip), %rsp
+ pop %rbx
+ pop %rbp
+ retq
+ENDPROC(efi64_thunk)
+
+ .data
+efi_gdt32:
+ .word efi_gdt32_end - efi_gdt32
+ .long 0 /* Filled out above */
+ .word 0
+ .quad 0x0000000000000000 /* NULL descriptor */
+ .quad 0x00cf9a000000ffff /* __KERNEL_CS */
+ .quad 0x00cf93000000ffff /* __KERNEL_DS */
+efi_gdt32_end:
+
+efi_saved_sp: .quad 0
diff --git a/arch/x86/platform/ts5500/ts5500.c b/arch/x86/platform/ts5500/ts5500.c
index 39febb214e8c..9471b9456f25 100644
--- a/arch/x86/platform/ts5500/ts5500.c
+++ b/arch/x86/platform/ts5500/ts5500.c
@@ -88,7 +88,7 @@ struct ts5500_sbc {
static const struct {
const char * const string;
const ssize_t offset;
-} ts5500_signatures[] __initdata = {
+} ts5500_signatures[] __initconst = {
{ "TS-5x00 AMD Elan", 0xb14 },
};
diff --git a/arch/x86/platform/visws/Makefile b/arch/x86/platform/visws/Makefile
deleted file mode 100644
index 91bc17ab2fd5..000000000000
--- a/arch/x86/platform/visws/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_X86_VISWS) += visws_quirks.o
diff --git a/arch/x86/platform/visws/visws_quirks.c b/arch/x86/platform/visws/visws_quirks.c
deleted file mode 100644
index 94d8a39332ec..000000000000
--- a/arch/x86/platform/visws/visws_quirks.c
+++ /dev/null
@@ -1,608 +0,0 @@
-/*
- * SGI Visual Workstation support and quirks, unmaintained.
- *
- * Split out from setup.c by davej@suse.de
- *
- * Copyright (C) 1999 Bent Hagemark, Ingo Molnar
- *
- * SGI Visual Workstation interrupt controller
- *
- * The Cobalt system ASIC in the Visual Workstation contains a "Cobalt" APIC
- * which serves as the main interrupt controller in the system. Non-legacy
- * hardware in the system uses this controller directly. Legacy devices
- * are connected to the PIIX4 which in turn has its 8259(s) connected to
- * a of the Cobalt APIC entry.
- *
- * 09/02/2000 - Updated for 2.4 by jbarnes@sgi.com
- *
- * 25/11/2002 - Updated for 2.5 by Andrey Panin <pazke@orbita1.ru>
- */
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-
-#include <asm/visws/cobalt.h>
-#include <asm/visws/piix4.h>
-#include <asm/io_apic.h>
-#include <asm/fixmap.h>
-#include <asm/reboot.h>
-#include <asm/setup.h>
-#include <asm/apic.h>
-#include <asm/e820.h>
-#include <asm/time.h>
-#include <asm/io.h>
-
-#include <linux/kernel_stat.h>
-
-#include <asm/i8259.h>
-#include <asm/irq_vectors.h>
-#include <asm/visws/lithium.h>
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/pci_ids.h>
-
-extern int no_broadcast;
-
-char visws_board_type = -1;
-char visws_board_rev = -1;
-
-static void __init visws_time_init(void)
-{
- printk(KERN_INFO "Starting Cobalt Timer system clock\n");
-
- /* Set the countdown value */
- co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ);
-
- /* Start the timer */
- co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN);
-
- /* Enable (unmask) the timer interrupt */
- co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK);
-
- setup_default_timer_irq();
-}
-
-/* Replaces the default init_ISA_irqs in the generic setup */
-static void __init visws_pre_intr_init(void);
-
-/* Quirk for machine specific memory setup. */
-
-#define MB (1024 * 1024)
-
-unsigned long sgivwfb_mem_phys;
-unsigned long sgivwfb_mem_size;
-EXPORT_SYMBOL(sgivwfb_mem_phys);
-EXPORT_SYMBOL(sgivwfb_mem_size);
-
-long long mem_size __initdata = 0;
-
-static char * __init visws_memory_setup(void)
-{
- long long gfx_mem_size = 8 * MB;
-
- mem_size = boot_params.alt_mem_k;
-
- if (!mem_size) {
- printk(KERN_WARNING "Bootloader didn't set memory size, upgrade it !\n");
- mem_size = 128 * MB;
- }
-
- /*
- * this hardcodes the graphics memory to 8 MB
- * it really should be sized dynamically (or at least
- * set as a boot param)
- */
- if (!sgivwfb_mem_size) {
- printk(KERN_WARNING "Defaulting to 8 MB framebuffer size\n");
- sgivwfb_mem_size = 8 * MB;
- }
-
- /*
- * Trim to nearest MB
- */
- sgivwfb_mem_size &= ~((1 << 20) - 1);
- sgivwfb_mem_phys = mem_size - gfx_mem_size;
-
- e820_add_region(0, LOWMEMSIZE(), E820_RAM);
- e820_add_region(HIGH_MEMORY, mem_size - sgivwfb_mem_size - HIGH_MEMORY, E820_RAM);
- e820_add_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED);
-
- return "PROM";
-}
-
-static void visws_machine_emergency_restart(void)
-{
- /*
- * Visual Workstations restart after this
- * register is poked on the PIIX4
- */
- outb(PIIX4_RESET_VAL, PIIX4_RESET_PORT);
-}
-
-static void visws_machine_power_off(void)
-{
- unsigned short pm_status;
-/* extern unsigned int pci_bus0; */
-
- while ((pm_status = inw(PMSTS_PORT)) & 0x100)
- outw(pm_status, PMSTS_PORT);
-
- outw(PM_SUSPEND_ENABLE, PMCNTRL_PORT);
-
- mdelay(10);
-
-#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
- (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
-
-/* outl(PCI_CONF1_ADDRESS(pci_bus0, SPECIAL_DEV, SPECIAL_REG), 0xCF8); */
- outl(PIIX_SPECIAL_STOP, 0xCFC);
-}
-
-static void __init visws_get_smp_config(unsigned int early)
-{
-}
-
-/*
- * The Visual Workstation is Intel MP compliant in the hardware
- * sense, but it doesn't have a BIOS(-configuration table).
- * No problem for Linux.
- */
-
-static void __init MP_processor_info(struct mpc_cpu *m)
-{
- int ver, logical_apicid;
- physid_mask_t apic_cpus;
-
- if (!(m->cpuflag & CPU_ENABLED))
- return;
-
- logical_apicid = m->apicid;
- printk(KERN_INFO "%sCPU #%d %u:%u APIC version %d\n",
- m->cpuflag & CPU_BOOTPROCESSOR ? "Bootup " : "",
- m->apicid, (m->cpufeature & CPU_FAMILY_MASK) >> 8,
- (m->cpufeature & CPU_MODEL_MASK) >> 4, m->apicver);
-
- if (m->cpuflag & CPU_BOOTPROCESSOR)
- boot_cpu_physical_apicid = m->apicid;
-
- ver = m->apicver;
- if ((ver >= 0x14 && m->apicid >= 0xff) || m->apicid >= 0xf) {
- printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n",
- m->apicid, MAX_LOCAL_APIC);
- return;
- }
-
- apic->apicid_to_cpu_present(m->apicid, &apic_cpus);
- physids_or(phys_cpu_present_map, phys_cpu_present_map, apic_cpus);
- /*
- * Validate version
- */
- if (ver == 0x0) {
- printk(KERN_ERR "BIOS bug, APIC version is 0 for CPU#%d! "
- "fixing up to 0x10. (tell your hw vendor)\n",
- m->apicid);
- ver = 0x10;
- }
- apic_version[m->apicid] = ver;
-}
-
-static void __init visws_find_smp_config(void)
-{
- struct mpc_cpu *mp = phys_to_virt(CO_CPU_TAB_PHYS);
- unsigned short ncpus = readw(phys_to_virt(CO_CPU_NUM_PHYS));
-
- if (ncpus > CO_CPU_MAX) {
- printk(KERN_WARNING "find_visws_smp: got cpu count of %d at %p\n",
- ncpus, mp);
-
- ncpus = CO_CPU_MAX;
- }
-
- if (ncpus > setup_max_cpus)
- ncpus = setup_max_cpus;
-
-#ifdef CONFIG_X86_LOCAL_APIC
- smp_found_config = 1;
-#endif
- while (ncpus--)
- MP_processor_info(mp++);
-
- mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
-}
-
-static void visws_trap_init(void);
-
-void __init visws_early_detect(void)
-{
- int raw;
-
- visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG)
- >> PIIX_GPI_BD_SHIFT;
-
- if (visws_board_type < 0)
- return;
-
- /*
- * Override the default platform setup functions
- */
- x86_init.resources.memory_setup = visws_memory_setup;
- x86_init.mpparse.get_smp_config = visws_get_smp_config;
- x86_init.mpparse.find_smp_config = visws_find_smp_config;
- x86_init.irqs.pre_vector_init = visws_pre_intr_init;
- x86_init.irqs.trap_init = visws_trap_init;
- x86_init.timers.timer_init = visws_time_init;
- x86_init.pci.init = pci_visws_init;
- x86_init.pci.init_irq = x86_init_noop;
-
- /*
- * Install reboot quirks:
- */
- pm_power_off = visws_machine_power_off;
- machine_ops.emergency_restart = visws_machine_emergency_restart;
-
- /*
- * Do not use broadcast IPIs:
- */
- no_broadcast = 0;
-
-#ifdef CONFIG_X86_IO_APIC
- /*
- * Turn off IO-APIC detection and initialization:
- */
- skip_ioapic_setup = 1;
-#endif
-
- /*
- * Get Board rev.
- * First, we have to initialize the 307 part to allow us access
- * to the GPIO registers. Let's map them at 0x0fc0 which is right
- * after the PIIX4 PM section.
- */
- outb_p(SIO_DEV_SEL, SIO_INDEX);
- outb_p(SIO_GP_DEV, SIO_DATA); /* Talk to GPIO regs. */
-
- outb_p(SIO_DEV_MSB, SIO_INDEX);
- outb_p(SIO_GP_MSB, SIO_DATA); /* MSB of GPIO base address */
-
- outb_p(SIO_DEV_LSB, SIO_INDEX);
- outb_p(SIO_GP_LSB, SIO_DATA); /* LSB of GPIO base address */
-
- outb_p(SIO_DEV_ENB, SIO_INDEX);
- outb_p(1, SIO_DATA); /* Enable GPIO registers. */
-
- /*
- * Now, we have to map the power management section to write
- * a bit which enables access to the GPIO registers.
- * What lunatic came up with this shit?
- */
- outb_p(SIO_DEV_SEL, SIO_INDEX);
- outb_p(SIO_PM_DEV, SIO_DATA); /* Talk to GPIO regs. */
-
- outb_p(SIO_DEV_MSB, SIO_INDEX);
- outb_p(SIO_PM_MSB, SIO_DATA); /* MSB of PM base address */
-
- outb_p(SIO_DEV_LSB, SIO_INDEX);
- outb_p(SIO_PM_LSB, SIO_DATA); /* LSB of PM base address */
-
- outb_p(SIO_DEV_ENB, SIO_INDEX);
- outb_p(1, SIO_DATA); /* Enable PM registers. */
-
- /*
- * Now, write the PM register which enables the GPIO registers.
- */
- outb_p(SIO_PM_FER2, SIO_PM_INDEX);
- outb_p(SIO_PM_GP_EN, SIO_PM_DATA);
-
- /*
- * Now, initialize the GPIO registers.
- * We want them all to be inputs which is the
- * power on default, so let's leave them alone.
- * So, let's just read the board rev!
- */
- raw = inb_p(SIO_GP_DATA1);
- raw &= 0x7f; /* 7 bits of valid board revision ID. */
-
- if (visws_board_type == VISWS_320) {
- if (raw < 0x6) {
- visws_board_rev = 4;
- } else if (raw < 0xc) {
- visws_board_rev = 5;
- } else {
- visws_board_rev = 6;
- }
- } else if (visws_board_type == VISWS_540) {
- visws_board_rev = 2;
- } else {
- visws_board_rev = raw;
- }
-
- printk(KERN_INFO "Silicon Graphics Visual Workstation %s (rev %d) detected\n",
- (visws_board_type == VISWS_320 ? "320" :
- (visws_board_type == VISWS_540 ? "540" :
- "unknown")), visws_board_rev);
-}
-
-#define A01234 (LI_INTA_0 | LI_INTA_1 | LI_INTA_2 | LI_INTA_3 | LI_INTA_4)
-#define BCD (LI_INTB | LI_INTC | LI_INTD)
-#define ALLDEVS (A01234 | BCD)
-
-static __init void lithium_init(void)
-{
- set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS);
- set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS);
-
- if ((li_pcia_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) ||
- (li_pcia_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) {
- printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'A');
-/* panic("This machine is not SGI Visual Workstation 320/540"); */
- }
-
- if ((li_pcib_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) ||
- (li_pcib_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) {
- printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'B');
-/* panic("This machine is not SGI Visual Workstation 320/540"); */
- }
-
- li_pcia_write16(LI_PCI_INTEN, ALLDEVS);
- li_pcib_write16(LI_PCI_INTEN, ALLDEVS);
-}
-
-static __init void cobalt_init(void)
-{
- /*
- * On normal SMP PC this is used only with SMP, but we have to
- * use it and set it up here to start the Cobalt clock
- */
- set_fixmap(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE);
- setup_local_APIC();
- printk(KERN_INFO "Local APIC Version %#x, ID %#x\n",
- (unsigned int)apic_read(APIC_LVR),
- (unsigned int)apic_read(APIC_ID));
-
- set_fixmap(FIX_CO_CPU, CO_CPU_PHYS);
- set_fixmap(FIX_CO_APIC, CO_APIC_PHYS);
- printk(KERN_INFO "Cobalt Revision %#lx, APIC ID %#lx\n",
- co_cpu_read(CO_CPU_REV), co_apic_read(CO_APIC_ID));
-
- /* Enable Cobalt APIC being careful to NOT change the ID! */
- co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID) | CO_APIC_ENABLE);
-
- printk(KERN_INFO "Cobalt APIC enabled: ID reg %#lx\n",
- co_apic_read(CO_APIC_ID));
-}
-
-static void __init visws_trap_init(void)
-{
- lithium_init();
- cobalt_init();
-}
-
-/*
- * IRQ controller / APIC support:
- */
-
-static DEFINE_SPINLOCK(cobalt_lock);
-
-/*
- * Set the given Cobalt APIC Redirection Table entry to point
- * to the given IDT vector/index.
- */
-static inline void co_apic_set(int entry, int irq)
-{
- co_apic_write(CO_APIC_LO(entry), CO_APIC_LEVEL | (irq + FIRST_EXTERNAL_VECTOR));
- co_apic_write(CO_APIC_HI(entry), 0);
-}
-
-/*
- * Cobalt (IO)-APIC functions to handle PCI devices.
- */
-static inline int co_apic_ide0_hack(void)
-{
- extern char visws_board_type;
- extern char visws_board_rev;
-
- if (visws_board_type == VISWS_320 && visws_board_rev == 5)
- return 5;
- return CO_APIC_IDE0;
-}
-
-static int is_co_apic(unsigned int irq)
-{
- if (IS_CO_APIC(irq))
- return CO_APIC(irq);
-
- switch (irq) {
- case 0: return CO_APIC_CPU;
- case CO_IRQ_IDE0: return co_apic_ide0_hack();
- case CO_IRQ_IDE1: return CO_APIC_IDE1;
- default: return -1;
- }
-}
-
-
-/*
- * This is the SGI Cobalt (IO-)APIC:
- */
-static void enable_cobalt_irq(struct irq_data *data)
-{
- co_apic_set(is_co_apic(data->irq), data->irq);
-}
-
-static void disable_cobalt_irq(struct irq_data *data)
-{
- int entry = is_co_apic(data->irq);
-
- co_apic_write(CO_APIC_LO(entry), CO_APIC_MASK);
- co_apic_read(CO_APIC_LO(entry));
-}
-
-static void ack_cobalt_irq(struct irq_data *data)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cobalt_lock, flags);
- disable_cobalt_irq(data);
- apic_write(APIC_EOI, APIC_EOI_ACK);
- spin_unlock_irqrestore(&cobalt_lock, flags);
-}
-
-static struct irq_chip cobalt_irq_type = {
- .name = "Cobalt-APIC",
- .irq_enable = enable_cobalt_irq,
- .irq_disable = disable_cobalt_irq,
- .irq_ack = ack_cobalt_irq,
-};
-
-
-/*
- * This is the PIIX4-based 8259 that is wired up indirectly to Cobalt
- * -- not the manner expected by the code in i8259.c.
- *
- * there is a 'master' physical interrupt source that gets sent to
- * the CPU. But in the chipset there are various 'virtual' interrupts
- * waiting to be handled. We represent this to Linux through a 'master'
- * interrupt controller type, and through a special virtual interrupt-
- * controller. Device drivers only see the virtual interrupt sources.
- */
-static unsigned int startup_piix4_master_irq(struct irq_data *data)
-{
- legacy_pic->init(0);
- enable_cobalt_irq(data);
- return 0;
-}
-
-static struct irq_chip piix4_master_irq_type = {
- .name = "PIIX4-master",
- .irq_startup = startup_piix4_master_irq,
- .irq_ack = ack_cobalt_irq,
-};
-
-static void pii4_mask(struct irq_data *data) { }
-
-static struct irq_chip piix4_virtual_irq_type = {
- .name = "PIIX4-virtual",
- .irq_mask = pii4_mask,
-};
-
-/*
- * PIIX4-8259 master/virtual functions to handle interrupt requests
- * from legacy devices: floppy, parallel, serial, rtc.
- *
- * None of these get Cobalt APIC entries, neither do they have IDT
- * entries. These interrupts are purely virtual and distributed from
- * the 'master' interrupt source: CO_IRQ_8259.
- *
- * When the 8259 interrupts its handler figures out which of these
- * devices is interrupting and dispatches to its handler.
- *
- * CAREFUL: devices see the 'virtual' interrupt only. Thus disable/
- * enable_irq gets the right irq. This 'master' irq is never directly
- * manipulated by any driver.
- */
-static irqreturn_t piix4_master_intr(int irq, void *dev_id)
-{
- unsigned long flags;
- int realirq;
-
- raw_spin_lock_irqsave(&i8259A_lock, flags);
-
- /* Find out what's interrupting in the PIIX4 master 8259 */
- outb(0x0c, 0x20); /* OCW3 Poll command */
- realirq = inb(0x20);
-
- /*
- * Bit 7 == 0 means invalid/spurious
- */
- if (unlikely(!(realirq & 0x80)))
- goto out_unlock;
-
- realirq &= 7;
-
- if (unlikely(realirq == 2)) {
- outb(0x0c, 0xa0);
- realirq = inb(0xa0);
-
- if (unlikely(!(realirq & 0x80)))
- goto out_unlock;
-
- realirq = (realirq & 7) + 8;
- }
-
- /* mask and ack interrupt */
- cached_irq_mask |= 1 << realirq;
- if (unlikely(realirq > 7)) {
- inb(0xa1);
- outb(cached_slave_mask, 0xa1);
- outb(0x60 + (realirq & 7), 0xa0);
- outb(0x60 + 2, 0x20);
- } else {
- inb(0x21);
- outb(cached_master_mask, 0x21);
- outb(0x60 + realirq, 0x20);
- }
-
- raw_spin_unlock_irqrestore(&i8259A_lock, flags);
-
- /*
- * handle this 'virtual interrupt' as a Cobalt one now.
- */
- generic_handle_irq(realirq);
-
- return IRQ_HANDLED;
-
-out_unlock:
- raw_spin_unlock_irqrestore(&i8259A_lock, flags);
- return IRQ_NONE;
-}
-
-static struct irqaction master_action = {
- .handler = piix4_master_intr,
- .name = "PIIX4-8259",
- .flags = IRQF_NO_THREAD,
-};
-
-static struct irqaction cascade_action = {
- .handler = no_action,
- .name = "cascade",
- .flags = IRQF_NO_THREAD,
-};
-
-static inline void set_piix4_virtual_irq_type(void)
-{
- piix4_virtual_irq_type.irq_enable = i8259A_chip.irq_unmask;
- piix4_virtual_irq_type.irq_disable = i8259A_chip.irq_mask;
- piix4_virtual_irq_type.irq_unmask = i8259A_chip.irq_unmask;
-}
-
-static void __init visws_pre_intr_init(void)
-{
- int i;
-
- set_piix4_virtual_irq_type();
-
- for (i = 0; i < CO_IRQ_APIC0 + CO_APIC_LAST + 1; i++) {
- struct irq_chip *chip = NULL;
-
- if (i == 0)
- chip = &cobalt_irq_type;
- else if (i == CO_IRQ_IDE0)
- chip = &cobalt_irq_type;
- else if (i == CO_IRQ_IDE1)
- chip = &cobalt_irq_type;
- else if (i == CO_IRQ_8259)
- chip = &piix4_master_irq_type;
- else if (i < CO_IRQ_APIC0)
- chip = &piix4_virtual_irq_type;
- else if (IS_CO_APIC(i))
- chip = &cobalt_irq_type;
-
- if (chip)
- irq_set_chip(i, chip);
- }
-
- setup_irq(CO_IRQ_8259, &master_action);
- setup_irq(2, &cascade_action);
-}
diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl
index a12bddc7ccea..04376ac3d9ef 100644
--- a/arch/x86/syscalls/syscall_64.tbl
+++ b/arch/x86/syscalls/syscall_64.tbl
@@ -322,6 +322,7 @@
313 common finit_module sys_finit_module
314 common sched_setattr sys_sched_setattr
315 common sched_getattr sys_sched_getattr
+316 common renameat2 sys_renameat2
#
# x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index cfbdbdb4e173..bbb1d2259ecf 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -69,8 +69,8 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
"__per_cpu_load|"
"init_per_cpu__.*|"
"__end_rodata_hpage_align|"
- "__vvar_page|"
#endif
+ "__vvar_page|"
"_end)$"
};
diff --git a/arch/x86/um/asm/barrier.h b/arch/x86/um/asm/barrier.h
index 7d01b8c56c00..cc04e67bfd05 100644
--- a/arch/x86/um/asm/barrier.h
+++ b/arch/x86/um/asm/barrier.h
@@ -40,11 +40,7 @@
#define smp_rmb() barrier()
#endif /* CONFIG_X86_PPRO_FENCE */
-#ifdef CONFIG_X86_OOSTORE
-#define smp_wmb() wmb()
-#else /* CONFIG_X86_OOSTORE */
#define smp_wmb() barrier()
-#endif /* CONFIG_X86_OOSTORE */
#define smp_read_barrier_depends() read_barrier_depends()
#define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile
index fd14be1d1472..c580d1210ffe 100644
--- a/arch/x86/vdso/Makefile
+++ b/arch/x86/vdso/Makefile
@@ -2,6 +2,8 @@
# Building vDSO images for x86.
#
+KBUILD_CFLAGS += $(DISABLE_LTO)
+
VDSO64-$(CONFIG_X86_64) := y
VDSOX32-$(CONFIG_X86_X32_ABI) := y
VDSO32-$(CONFIG_X86_32) := y
@@ -21,7 +23,8 @@ vobjs-$(VDSOX32-y) += $(vobjx32s-compat)
vobj64s := $(filter-out $(vobjx32s-compat),$(vobjs-y))
# files to link into kernel
-obj-$(VDSO64-y) += vma.o vdso.o
+obj-y += vma.o
+obj-$(VDSO64-y) += vdso.o
obj-$(VDSOX32-y) += vdsox32.o
obj-$(VDSO32-y) += vdso32.o vdso32-setup.o
@@ -35,7 +38,8 @@ export CPPFLAGS_vdso.lds += -P -C
VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \
-Wl,--no-undefined \
- -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
+ -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096 \
+ $(DISABLE_LTO)
$(obj)/vdso.o: $(src)/vdso.S $(obj)/vdso.so
@@ -127,7 +131,7 @@ vdso32.so-$(VDSO32-y) += sysenter
vdso32-images = $(vdso32.so-y:%=vdso32-%.so)
CPPFLAGS_vdso32.lds = $(CPPFLAGS_vdso.lds)
-VDSO_LDFLAGS_vdso32.lds = -m32 -Wl,-soname=linux-gate.so.1
+VDSO_LDFLAGS_vdso32.lds = -m32 -Wl,-m,elf_i386 -Wl,-soname=linux-gate.so.1
# This makes sure the $(obj) subdirectory exists even though vdso32/
# is not a kbuild sub-make subdirectory.
@@ -135,7 +139,7 @@ override obj-dirs = $(dir $(obj)) $(obj)/vdso32/
targets += vdso32/vdso32.lds
targets += $(vdso32-images) $(vdso32-images:=.dbg)
-targets += vdso32/note.o $(vdso32.so-y:%=vdso32/%.o)
+targets += vdso32/note.o vdso32/vclock_gettime.o $(vdso32.so-y:%=vdso32/%.o)
extra-y += $(vdso32-images)
@@ -145,8 +149,19 @@ KBUILD_AFLAGS_32 := $(filter-out -m64,$(KBUILD_AFLAGS))
$(vdso32-images:%=$(obj)/%.dbg): KBUILD_AFLAGS = $(KBUILD_AFLAGS_32)
$(vdso32-images:%=$(obj)/%.dbg): asflags-$(CONFIG_X86_64) += -m32
+KBUILD_CFLAGS_32 := $(filter-out -m64,$(KBUILD_CFLAGS))
+KBUILD_CFLAGS_32 := $(filter-out -mcmodel=kernel,$(KBUILD_CFLAGS_32))
+KBUILD_CFLAGS_32 := $(filter-out -fno-pic,$(KBUILD_CFLAGS_32))
+KBUILD_CFLAGS_32 := $(filter-out -mfentry,$(KBUILD_CFLAGS_32))
+KBUILD_CFLAGS_32 += -m32 -msoft-float -mregparm=0 -fpic
+KBUILD_CFLAGS_32 += $(call cc-option, -fno-stack-protector)
+KBUILD_CFLAGS_32 += $(call cc-option, -foptimize-sibling-calls)
+KBUILD_CFLAGS_32 += -fno-omit-frame-pointer
+$(vdso32-images:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_32)
+
$(vdso32-images:%=$(obj)/%.dbg): $(obj)/vdso32-%.so.dbg: FORCE \
$(obj)/vdso32/vdso32.lds \
+ $(obj)/vdso32/vclock_gettime.o \
$(obj)/vdso32/note.o \
$(obj)/vdso32/%.o
$(call if_changed,vdso)
@@ -181,7 +196,8 @@ quiet_cmd_vdso = VDSO $@
-Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) && \
sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@'
-VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
+VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) \
+ $(LTO_CFLAGS)
GCOV_PROFILE := n
#
diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c
index eb5d7a56f8d4..16d686171e9a 100644
--- a/arch/x86/vdso/vclock_gettime.c
+++ b/arch/x86/vdso/vclock_gettime.c
@@ -4,6 +4,9 @@
*
* Fast user context implementation of clock_gettime, gettimeofday, and time.
*
+ * 32 Bit compat layer by Stefani Seibold <stefani@seibold.net>
+ * sponsored by Rohde & Schwarz GmbH & Co. KG Munich/Germany
+ *
* The code should have no internal unresolved relocations.
* Check with readelf after changing.
*/
@@ -11,56 +14,55 @@
/* Disable profiling for userspace code: */
#define DISABLE_BRANCH_PROFILING
-#include <linux/kernel.h>
-#include <linux/posix-timers.h>
-#include <linux/time.h>
-#include <linux/string.h>
-#include <asm/vsyscall.h>
-#include <asm/fixmap.h>
+#include <uapi/linux/time.h>
#include <asm/vgtod.h>
-#include <asm/timex.h>
#include <asm/hpet.h>
+#include <asm/vvar.h>
#include <asm/unistd.h>
-#include <asm/io.h>
-#include <asm/pvclock.h>
+#include <asm/msr.h>
+#include <linux/math64.h>
+#include <linux/time.h>
#define gtod (&VVAR(vsyscall_gtod_data))
-notrace static cycle_t vread_tsc(void)
+extern int __vdso_clock_gettime(clockid_t clock, struct timespec *ts);
+extern int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz);
+extern time_t __vdso_time(time_t *t);
+
+#ifdef CONFIG_HPET_TIMER
+static inline u32 read_hpet_counter(const volatile void *addr)
{
- cycle_t ret;
- u64 last;
+ return *(const volatile u32 *) (addr + HPET_COUNTER);
+}
+#endif
- /*
- * Empirically, a fence (of type that depends on the CPU)
- * before rdtsc is enough to ensure that rdtsc is ordered
- * with respect to loads. The various CPU manuals are unclear
- * as to whether rdtsc can be reordered with later loads,
- * but no one has ever seen it happen.
- */
- rdtsc_barrier();
- ret = (cycle_t)vget_cycles();
+#ifndef BUILD_VDSO32
- last = VVAR(vsyscall_gtod_data).clock.cycle_last;
+#include <linux/kernel.h>
+#include <asm/vsyscall.h>
+#include <asm/fixmap.h>
+#include <asm/pvclock.h>
- if (likely(ret >= last))
- return ret;
+static notrace cycle_t vread_hpet(void)
+{
+ return read_hpet_counter((const void *)fix_to_virt(VSYSCALL_HPET));
+}
- /*
- * GCC likes to generate cmov here, but this branch is extremely
- * predictable (it's just a funciton of time and the likely is
- * very likely) and there's a data dependence, so force GCC
- * to generate a branch instead. I don't barrier() because
- * we don't actually need a barrier, and if this function
- * ever gets inlined it will generate worse code.
- */
- asm volatile ("");
- return last;
+notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
+{
+ long ret;
+ asm("syscall" : "=a" (ret) :
+ "0" (__NR_clock_gettime), "D" (clock), "S" (ts) : "memory");
+ return ret;
}
-static notrace cycle_t vread_hpet(void)
+notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz)
{
- return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + HPET_COUNTER);
+ long ret;
+
+ asm("syscall" : "=a" (ret) :
+ "0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory");
+ return ret;
}
#ifdef CONFIG_PARAVIRT_CLOCK
@@ -124,7 +126,7 @@ static notrace cycle_t vread_pvclock(int *mode)
*mode = VCLOCK_NONE;
/* refer to tsc.c read_tsc() comment for rationale */
- last = VVAR(vsyscall_gtod_data).clock.cycle_last;
+ last = gtod->cycle_last;
if (likely(ret >= last))
return ret;
@@ -133,11 +135,30 @@ static notrace cycle_t vread_pvclock(int *mode)
}
#endif
+#else
+
+extern u8 hpet_page
+ __attribute__((visibility("hidden")));
+
+#ifdef CONFIG_HPET_TIMER
+static notrace cycle_t vread_hpet(void)
+{
+ return read_hpet_counter((const void *)(&hpet_page));
+}
+#endif
+
notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
{
long ret;
- asm("syscall" : "=a" (ret) :
- "0" (__NR_clock_gettime),"D" (clock), "S" (ts) : "memory");
+
+ asm(
+ "mov %%ebx, %%edx \n"
+ "mov %2, %%ebx \n"
+ "call VDSO32_vsyscall \n"
+ "mov %%edx, %%ebx \n"
+ : "=a" (ret)
+ : "0" (__NR_clock_gettime), "g" (clock), "c" (ts)
+ : "memory", "edx");
return ret;
}
@@ -145,28 +166,79 @@ notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz)
{
long ret;
- asm("syscall" : "=a" (ret) :
- "0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory");
+ asm(
+ "mov %%ebx, %%edx \n"
+ "mov %2, %%ebx \n"
+ "call VDSO32_vsyscall \n"
+ "mov %%edx, %%ebx \n"
+ : "=a" (ret)
+ : "0" (__NR_gettimeofday), "g" (tv), "c" (tz)
+ : "memory", "edx");
return ret;
}
+#ifdef CONFIG_PARAVIRT_CLOCK
+
+static notrace cycle_t vread_pvclock(int *mode)
+{
+ *mode = VCLOCK_NONE;
+ return 0;
+}
+#endif
+
+#endif
+
+notrace static cycle_t vread_tsc(void)
+{
+ cycle_t ret;
+ u64 last;
+
+ /*
+ * Empirically, a fence (of type that depends on the CPU)
+ * before rdtsc is enough to ensure that rdtsc is ordered
+ * with respect to loads. The various CPU manuals are unclear
+ * as to whether rdtsc can be reordered with later loads,
+ * but no one has ever seen it happen.
+ */
+ rdtsc_barrier();
+ ret = (cycle_t)__native_read_tsc();
+
+ last = gtod->cycle_last;
+
+ if (likely(ret >= last))
+ return ret;
+
+ /*
+ * GCC likes to generate cmov here, but this branch is extremely
+ * predictable (it's just a funciton of time and the likely is
+ * very likely) and there's a data dependence, so force GCC
+ * to generate a branch instead. I don't barrier() because
+ * we don't actually need a barrier, and if this function
+ * ever gets inlined it will generate worse code.
+ */
+ asm volatile ("");
+ return last;
+}
notrace static inline u64 vgetsns(int *mode)
{
- long v;
+ u64 v;
cycles_t cycles;
- if (gtod->clock.vclock_mode == VCLOCK_TSC)
+
+ if (gtod->vclock_mode == VCLOCK_TSC)
cycles = vread_tsc();
- else if (gtod->clock.vclock_mode == VCLOCK_HPET)
+#ifdef CONFIG_HPET_TIMER
+ else if (gtod->vclock_mode == VCLOCK_HPET)
cycles = vread_hpet();
+#endif
#ifdef CONFIG_PARAVIRT_CLOCK
- else if (gtod->clock.vclock_mode == VCLOCK_PVCLOCK)
+ else if (gtod->vclock_mode == VCLOCK_PVCLOCK)
cycles = vread_pvclock(mode);
#endif
else
return 0;
- v = (cycles - gtod->clock.cycle_last) & gtod->clock.mask;
- return v * gtod->clock.mult;
+ v = (cycles - gtod->cycle_last) & gtod->mask;
+ return v * gtod->mult;
}
/* Code size doesn't matter (vdso is 4k anyway) and this is faster. */
@@ -176,106 +248,102 @@ notrace static int __always_inline do_realtime(struct timespec *ts)
u64 ns;
int mode;
- ts->tv_nsec = 0;
do {
- seq = raw_read_seqcount_begin(&gtod->seq);
- mode = gtod->clock.vclock_mode;
+ seq = gtod_read_begin(gtod);
+ mode = gtod->vclock_mode;
ts->tv_sec = gtod->wall_time_sec;
ns = gtod->wall_time_snsec;
ns += vgetsns(&mode);
- ns >>= gtod->clock.shift;
- } while (unlikely(read_seqcount_retry(&gtod->seq, seq)));
+ ns >>= gtod->shift;
+ } while (unlikely(gtod_read_retry(gtod, seq)));
+
+ ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
+ ts->tv_nsec = ns;
- timespec_add_ns(ts, ns);
return mode;
}
-notrace static int do_monotonic(struct timespec *ts)
+notrace static int __always_inline do_monotonic(struct timespec *ts)
{
unsigned long seq;
u64 ns;
int mode;
- ts->tv_nsec = 0;
do {
- seq = raw_read_seqcount_begin(&gtod->seq);
- mode = gtod->clock.vclock_mode;
+ seq = gtod_read_begin(gtod);
+ mode = gtod->vclock_mode;
ts->tv_sec = gtod->monotonic_time_sec;
ns = gtod->monotonic_time_snsec;
ns += vgetsns(&mode);
- ns >>= gtod->clock.shift;
- } while (unlikely(read_seqcount_retry(&gtod->seq, seq)));
- timespec_add_ns(ts, ns);
+ ns >>= gtod->shift;
+ } while (unlikely(gtod_read_retry(gtod, seq)));
+
+ ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
+ ts->tv_nsec = ns;
return mode;
}
-notrace static int do_realtime_coarse(struct timespec *ts)
+notrace static void do_realtime_coarse(struct timespec *ts)
{
unsigned long seq;
do {
- seq = raw_read_seqcount_begin(&gtod->seq);
- ts->tv_sec = gtod->wall_time_coarse.tv_sec;
- ts->tv_nsec = gtod->wall_time_coarse.tv_nsec;
- } while (unlikely(read_seqcount_retry(&gtod->seq, seq)));
- return 0;
+ seq = gtod_read_begin(gtod);
+ ts->tv_sec = gtod->wall_time_coarse_sec;
+ ts->tv_nsec = gtod->wall_time_coarse_nsec;
+ } while (unlikely(gtod_read_retry(gtod, seq)));
}
-notrace static int do_monotonic_coarse(struct timespec *ts)
+notrace static void do_monotonic_coarse(struct timespec *ts)
{
unsigned long seq;
do {
- seq = raw_read_seqcount_begin(&gtod->seq);
- ts->tv_sec = gtod->monotonic_time_coarse.tv_sec;
- ts->tv_nsec = gtod->monotonic_time_coarse.tv_nsec;
- } while (unlikely(read_seqcount_retry(&gtod->seq, seq)));
-
- return 0;
+ seq = gtod_read_begin(gtod);
+ ts->tv_sec = gtod->monotonic_time_coarse_sec;
+ ts->tv_nsec = gtod->monotonic_time_coarse_nsec;
+ } while (unlikely(gtod_read_retry(gtod, seq)));
}
notrace int __vdso_clock_gettime(clockid_t clock, struct timespec *ts)
{
- int ret = VCLOCK_NONE;
-
switch (clock) {
case CLOCK_REALTIME:
- ret = do_realtime(ts);
+ if (do_realtime(ts) == VCLOCK_NONE)
+ goto fallback;
break;
case CLOCK_MONOTONIC:
- ret = do_monotonic(ts);
+ if (do_monotonic(ts) == VCLOCK_NONE)
+ goto fallback;
break;
case CLOCK_REALTIME_COARSE:
- return do_realtime_coarse(ts);
+ do_realtime_coarse(ts);
+ break;
case CLOCK_MONOTONIC_COARSE:
- return do_monotonic_coarse(ts);
+ do_monotonic_coarse(ts);
+ break;
+ default:
+ goto fallback;
}
- if (ret == VCLOCK_NONE)
- return vdso_fallback_gettime(clock, ts);
return 0;
+fallback:
+ return vdso_fallback_gettime(clock, ts);
}
int clock_gettime(clockid_t, struct timespec *)
__attribute__((weak, alias("__vdso_clock_gettime")));
notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
{
- long ret = VCLOCK_NONE;
-
if (likely(tv != NULL)) {
- BUILD_BUG_ON(offsetof(struct timeval, tv_usec) !=
- offsetof(struct timespec, tv_nsec) ||
- sizeof(*tv) != sizeof(struct timespec));
- ret = do_realtime((struct timespec *)tv);
+ if (unlikely(do_realtime((struct timespec *)tv) == VCLOCK_NONE))
+ return vdso_fallback_gtod(tv, tz);
tv->tv_usec /= 1000;
}
if (unlikely(tz != NULL)) {
- /* Avoid memcpy. Some old compilers fail to inline it */
- tz->tz_minuteswest = gtod->sys_tz.tz_minuteswest;
- tz->tz_dsttime = gtod->sys_tz.tz_dsttime;
+ tz->tz_minuteswest = gtod->tz_minuteswest;
+ tz->tz_dsttime = gtod->tz_dsttime;
}
- if (ret == VCLOCK_NONE)
- return vdso_fallback_gtod(tv, tz);
return 0;
}
int gettimeofday(struct timeval *, struct timezone *)
@@ -287,8 +355,8 @@ int gettimeofday(struct timeval *, struct timezone *)
*/
notrace time_t __vdso_time(time_t *t)
{
- /* This is atomic on x86_64 so we don't need any locks. */
- time_t result = ACCESS_ONCE(VVAR(vsyscall_gtod_data).wall_time_sec);
+ /* This is atomic on x86 so we don't need any locks. */
+ time_t result = ACCESS_ONCE(gtod->wall_time_sec);
if (t)
*t = result;
diff --git a/arch/x86/vdso/vdso-layout.lds.S b/arch/x86/vdso/vdso-layout.lds.S
index 634a2cf62046..2e263f367b13 100644
--- a/arch/x86/vdso/vdso-layout.lds.S
+++ b/arch/x86/vdso/vdso-layout.lds.S
@@ -6,7 +6,25 @@
SECTIONS
{
- . = VDSO_PRELINK + SIZEOF_HEADERS;
+#ifdef BUILD_VDSO32
+#include <asm/vdso32.h>
+
+ .hpet_sect : {
+ hpet_page = . - VDSO_OFFSET(VDSO_HPET_PAGE);
+ } :text :hpet_sect
+
+ .vvar_sect : {
+ vvar = . - VDSO_OFFSET(VDSO_VVAR_PAGE);
+
+ /* Place all vvars at the offsets in asm/vvar.h. */
+#define EMIT_VVAR(name, offset) vvar_ ## name = vvar + offset;
+#define __VVAR_KERNEL_LDS
+#include <asm/vvar.h>
+#undef __VVAR_KERNEL_LDS
+#undef EMIT_VVAR
+ } :text :vvar_sect
+#endif
+ . = SIZEOF_HEADERS;
.hash : { *(.hash) } :text
.gnu.hash : { *(.gnu.hash) }
@@ -44,6 +62,11 @@ SECTIONS
. = ALIGN(0x100);
.text : { *(.text*) } :text =0x90909090
+
+ /DISCARD/ : {
+ *(.discard)
+ *(.discard.*)
+ }
}
/*
@@ -61,4 +84,8 @@ PHDRS
dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
note PT_NOTE FLAGS(4); /* PF_R */
eh_frame_hdr PT_GNU_EH_FRAME;
+#ifdef BUILD_VDSO32
+ vvar_sect PT_NULL FLAGS(4); /* PF_R */
+ hpet_sect PT_NULL FLAGS(4); /* PF_R */
+#endif
}
diff --git a/arch/x86/vdso/vdso.S b/arch/x86/vdso/vdso.S
index 1e13eb8c9656..be3f23b09af5 100644
--- a/arch/x86/vdso/vdso.S
+++ b/arch/x86/vdso/vdso.S
@@ -1,21 +1,3 @@
-#include <asm/page_types.h>
-#include <linux/linkage.h>
+#include <asm/vdso.h>
-__PAGE_ALIGNED_DATA
-
- .globl vdso_start, vdso_end
- .align PAGE_SIZE
-vdso_start:
- .incbin "arch/x86/vdso/vdso.so"
-vdso_end:
- .align PAGE_SIZE /* extra data here leaks to userspace. */
-
-.previous
-
- .globl vdso_pages
- .bss
- .align 8
- .type vdso_pages, @object
-vdso_pages:
- .zero (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE * 8
- .size vdso_pages, .-vdso_pages
+DEFINE_VDSO_IMAGE(vdso, "arch/x86/vdso/vdso.so")
diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c
index d6bfb876cfb0..00348980a3a6 100644
--- a/arch/x86/vdso/vdso32-setup.c
+++ b/arch/x86/vdso/vdso32-setup.c
@@ -16,6 +16,7 @@
#include <linux/mm.h>
#include <linux/err.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include <asm/cpufeature.h>
#include <asm/msr.h>
@@ -25,17 +26,14 @@
#include <asm/tlbflush.h>
#include <asm/vdso.h>
#include <asm/proto.h>
-
-enum {
- VDSO_DISABLED = 0,
- VDSO_ENABLED = 1,
- VDSO_COMPAT = 2,
-};
+#include <asm/fixmap.h>
+#include <asm/hpet.h>
+#include <asm/vvar.h>
#ifdef CONFIG_COMPAT_VDSO
-#define VDSO_DEFAULT VDSO_COMPAT
+#define VDSO_DEFAULT 0
#else
-#define VDSO_DEFAULT VDSO_ENABLED
+#define VDSO_DEFAULT 1
#endif
#ifdef CONFIG_X86_64
@@ -44,13 +42,6 @@ enum {
#endif
/*
- * This is the difference between the prelinked addresses in the vDSO images
- * and the VDSO_HIGH_BASE address where CONFIG_COMPAT_VDSO places the vDSO
- * in the user address space.
- */
-#define VDSO_ADDR_ADJUST (VDSO_HIGH_BASE - (unsigned long)VDSO32_PRELINK)
-
-/*
* Should the kernel map a VDSO page into processes and pass its
* address down to glibc upon exec()?
*/
@@ -60,6 +51,9 @@ static int __init vdso_setup(char *s)
{
vdso_enabled = simple_strtoul(s, NULL, 0);
+ if (vdso_enabled > 1)
+ pr_warn("vdso32 values other than 0 and 1 are no longer allowed; vdso disabled\n");
+
return 1;
}
@@ -76,124 +70,8 @@ __setup_param("vdso=", vdso32_setup, vdso_setup, 0);
EXPORT_SYMBOL_GPL(vdso_enabled);
#endif
-static __init void reloc_symtab(Elf32_Ehdr *ehdr,
- unsigned offset, unsigned size)
-{
- Elf32_Sym *sym = (void *)ehdr + offset;
- unsigned nsym = size / sizeof(*sym);
- unsigned i;
-
- for(i = 0; i < nsym; i++, sym++) {
- if (sym->st_shndx == SHN_UNDEF ||
- sym->st_shndx == SHN_ABS)
- continue; /* skip */
-
- if (sym->st_shndx > SHN_LORESERVE) {
- printk(KERN_INFO "VDSO: unexpected st_shndx %x\n",
- sym->st_shndx);
- continue;
- }
-
- switch(ELF_ST_TYPE(sym->st_info)) {
- case STT_OBJECT:
- case STT_FUNC:
- case STT_SECTION:
- case STT_FILE:
- sym->st_value += VDSO_ADDR_ADJUST;
- }
- }
-}
-
-static __init void reloc_dyn(Elf32_Ehdr *ehdr, unsigned offset)
-{
- Elf32_Dyn *dyn = (void *)ehdr + offset;
-
- for(; dyn->d_tag != DT_NULL; dyn++)
- switch(dyn->d_tag) {
- case DT_PLTGOT:
- case DT_HASH:
- case DT_STRTAB:
- case DT_SYMTAB:
- case DT_RELA:
- case DT_INIT:
- case DT_FINI:
- case DT_REL:
- case DT_DEBUG:
- case DT_JMPREL:
- case DT_VERSYM:
- case DT_VERDEF:
- case DT_VERNEED:
- case DT_ADDRRNGLO ... DT_ADDRRNGHI:
- /* definitely pointers needing relocation */
- dyn->d_un.d_ptr += VDSO_ADDR_ADJUST;
- break;
-
- case DT_ENCODING ... OLD_DT_LOOS-1:
- case DT_LOOS ... DT_HIOS-1:
- /* Tags above DT_ENCODING are pointers if
- they're even */
- if (dyn->d_tag >= DT_ENCODING &&
- (dyn->d_tag & 1) == 0)
- dyn->d_un.d_ptr += VDSO_ADDR_ADJUST;
- break;
-
- case DT_VERDEFNUM:
- case DT_VERNEEDNUM:
- case DT_FLAGS_1:
- case DT_RELACOUNT:
- case DT_RELCOUNT:
- case DT_VALRNGLO ... DT_VALRNGHI:
- /* definitely not pointers */
- break;
-
- case OLD_DT_LOOS ... DT_LOOS-1:
- case DT_HIOS ... DT_VALRNGLO-1:
- default:
- if (dyn->d_tag > DT_ENCODING)
- printk(KERN_INFO "VDSO: unexpected DT_tag %x\n",
- dyn->d_tag);
- break;
- }
-}
-
-static __init void relocate_vdso(Elf32_Ehdr *ehdr)
-{
- Elf32_Phdr *phdr;
- Elf32_Shdr *shdr;
- int i;
-
- BUG_ON(memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0 ||
- !elf_check_arch_ia32(ehdr) ||
- ehdr->e_type != ET_DYN);
-
- ehdr->e_entry += VDSO_ADDR_ADJUST;
-
- /* rebase phdrs */
- phdr = (void *)ehdr + ehdr->e_phoff;
- for (i = 0; i < ehdr->e_phnum; i++) {
- phdr[i].p_vaddr += VDSO_ADDR_ADJUST;
-
- /* relocate dynamic stuff */
- if (phdr[i].p_type == PT_DYNAMIC)
- reloc_dyn(ehdr, phdr[i].p_offset);
- }
-
- /* rebase sections */
- shdr = (void *)ehdr + ehdr->e_shoff;
- for(i = 0; i < ehdr->e_shnum; i++) {
- if (!(shdr[i].sh_flags & SHF_ALLOC))
- continue;
-
- shdr[i].sh_addr += VDSO_ADDR_ADJUST;
-
- if (shdr[i].sh_type == SHT_SYMTAB ||
- shdr[i].sh_type == SHT_DYNSYM)
- reloc_symtab(ehdr, shdr[i].sh_offset,
- shdr[i].sh_size);
- }
-}
-
-static struct page *vdso32_pages[1];
+static struct page **vdso32_pages;
+static unsigned vdso32_size;
#ifdef CONFIG_X86_64
@@ -212,12 +90,6 @@ void syscall32_cpu_init(void)
wrmsrl(MSR_CSTAR, ia32_cstar_target);
}
-#define compat_uses_vma 1
-
-static inline void map_compat_vdso(int map)
-{
-}
-
#else /* CONFIG_X86_32 */
#define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SEP))
@@ -241,64 +113,36 @@ void enable_sep_cpu(void)
put_cpu();
}
-static struct vm_area_struct gate_vma;
-
-static int __init gate_vma_init(void)
-{
- gate_vma.vm_mm = NULL;
- gate_vma.vm_start = FIXADDR_USER_START;
- gate_vma.vm_end = FIXADDR_USER_END;
- gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC;
- gate_vma.vm_page_prot = __P101;
-
- return 0;
-}
-
-#define compat_uses_vma 0
-
-static void map_compat_vdso(int map)
-{
- static int vdso_mapped;
-
- if (map == vdso_mapped)
- return;
-
- vdso_mapped = map;
-
- __set_fixmap(FIX_VDSO, page_to_pfn(vdso32_pages[0]) << PAGE_SHIFT,
- map ? PAGE_READONLY_EXEC : PAGE_NONE);
-
- /* flush stray tlbs */
- flush_tlb_all();
-}
-
#endif /* CONFIG_X86_64 */
int __init sysenter_setup(void)
{
- void *syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
- const void *vsyscall;
- size_t vsyscall_len;
-
- vdso32_pages[0] = virt_to_page(syscall_page);
-
-#ifdef CONFIG_X86_32
- gate_vma_init();
-#endif
+ char *vdso32_start, *vdso32_end;
+ int npages, i;
+#ifdef CONFIG_COMPAT
if (vdso32_syscall()) {
- vsyscall = &vdso32_syscall_start;
- vsyscall_len = &vdso32_syscall_end - &vdso32_syscall_start;
- } else if (vdso32_sysenter()){
- vsyscall = &vdso32_sysenter_start;
- vsyscall_len = &vdso32_sysenter_end - &vdso32_sysenter_start;
+ vdso32_start = vdso32_syscall_start;
+ vdso32_end = vdso32_syscall_end;
+ vdso32_pages = vdso32_syscall_pages;
+ } else
+#endif
+ if (vdso32_sysenter()) {
+ vdso32_start = vdso32_sysenter_start;
+ vdso32_end = vdso32_sysenter_end;
+ vdso32_pages = vdso32_sysenter_pages;
} else {
- vsyscall = &vdso32_int80_start;
- vsyscall_len = &vdso32_int80_end - &vdso32_int80_start;
+ vdso32_start = vdso32_int80_start;
+ vdso32_end = vdso32_int80_end;
+ vdso32_pages = vdso32_int80_pages;
}
- memcpy(syscall_page, vsyscall, vsyscall_len);
- relocate_vdso(syscall_page);
+ npages = ((vdso32_end - vdso32_start) + PAGE_SIZE - 1) / PAGE_SIZE;
+ vdso32_size = npages << PAGE_SHIFT;
+ for (i = 0; i < npages; i++)
+ vdso32_pages[i] = virt_to_page(vdso32_start + i*PAGE_SIZE);
+
+ patch_vdso32(vdso32_start, vdso32_size);
return 0;
}
@@ -309,48 +153,73 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
struct mm_struct *mm = current->mm;
unsigned long addr;
int ret = 0;
- bool compat;
+ struct vm_area_struct *vma;
#ifdef CONFIG_X86_X32_ABI
if (test_thread_flag(TIF_X32))
return x32_setup_additional_pages(bprm, uses_interp);
#endif
- if (vdso_enabled == VDSO_DISABLED)
+ if (vdso_enabled != 1) /* Other values all mean "disabled" */
return 0;
down_write(&mm->mmap_sem);
- /* Test compat mode once here, in case someone
- changes it via sysctl */
- compat = (vdso_enabled == VDSO_COMPAT);
+ addr = get_unmapped_area(NULL, 0, vdso32_size + VDSO_OFFSET(VDSO_PREV_PAGES), 0, 0);
+ if (IS_ERR_VALUE(addr)) {
+ ret = addr;
+ goto up_fail;
+ }
+
+ addr += VDSO_OFFSET(VDSO_PREV_PAGES);
- map_compat_vdso(compat);
+ current->mm->context.vdso = (void *)addr;
- if (compat)
- addr = VDSO_HIGH_BASE;
- else {
- addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
- if (IS_ERR_VALUE(addr)) {
- ret = addr;
- goto up_fail;
- }
+ /*
+ * MAYWRITE to allow gdb to COW and set breakpoints
+ */
+ ret = install_special_mapping(mm,
+ addr,
+ vdso32_size,
+ VM_READ|VM_EXEC|
+ VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
+ vdso32_pages);
+
+ if (ret)
+ goto up_fail;
+
+ vma = _install_special_mapping(mm,
+ addr - VDSO_OFFSET(VDSO_PREV_PAGES),
+ VDSO_OFFSET(VDSO_PREV_PAGES),
+ VM_READ,
+ NULL);
+
+ if (IS_ERR(vma)) {
+ ret = PTR_ERR(vma);
+ goto up_fail;
}
- current->mm->context.vdso = (void *)addr;
+ ret = remap_pfn_range(vma,
+ addr - VDSO_OFFSET(VDSO_VVAR_PAGE),
+ __pa_symbol(&__vvar_page) >> PAGE_SHIFT,
+ PAGE_SIZE,
+ PAGE_READONLY);
+
+ if (ret)
+ goto up_fail;
- if (compat_uses_vma || !compat) {
- /*
- * MAYWRITE to allow gdb to COW and set breakpoints
- */
- ret = install_special_mapping(mm, addr, PAGE_SIZE,
- VM_READ|VM_EXEC|
- VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
- vdso32_pages);
+#ifdef CONFIG_HPET_TIMER
+ if (hpet_address) {
+ ret = io_remap_pfn_range(vma,
+ addr - VDSO_OFFSET(VDSO_HPET_PAGE),
+ hpet_address >> PAGE_SHIFT,
+ PAGE_SIZE,
+ pgprot_noncached(PAGE_READONLY));
if (ret)
goto up_fail;
}
+#endif
current_thread_info()->sysenter_return =
VDSO32_SYMBOL(addr, SYSENTER_RETURN);
@@ -411,20 +280,12 @@ const char *arch_vma_name(struct vm_area_struct *vma)
struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
{
- /*
- * Check to see if the corresponding task was created in compat vdso
- * mode.
- */
- if (mm && mm->context.vdso == (void *)VDSO_HIGH_BASE)
- return &gate_vma;
return NULL;
}
int in_gate_area(struct mm_struct *mm, unsigned long addr)
{
- const struct vm_area_struct *vma = get_gate_vma(mm);
-
- return vma && addr >= vma->vm_start && addr < vma->vm_end;
+ return 0;
}
int in_gate_area_no_mm(unsigned long addr)
diff --git a/arch/x86/vdso/vdso32.S b/arch/x86/vdso/vdso32.S
index 2ce5f82c333b..018bcd9f97b4 100644
--- a/arch/x86/vdso/vdso32.S
+++ b/arch/x86/vdso/vdso32.S
@@ -1,22 +1,9 @@
-#include <linux/init.h>
+#include <asm/vdso.h>
-__INITDATA
+DEFINE_VDSO_IMAGE(vdso32_int80, "arch/x86/vdso/vdso32-int80.so")
- .globl vdso32_int80_start, vdso32_int80_end
-vdso32_int80_start:
- .incbin "arch/x86/vdso/vdso32-int80.so"
-vdso32_int80_end:
-
- .globl vdso32_syscall_start, vdso32_syscall_end
-vdso32_syscall_start:
#ifdef CONFIG_COMPAT
- .incbin "arch/x86/vdso/vdso32-syscall.so"
+DEFINE_VDSO_IMAGE(vdso32_syscall, "arch/x86/vdso/vdso32-syscall.so")
#endif
-vdso32_syscall_end:
-
- .globl vdso32_sysenter_start, vdso32_sysenter_end
-vdso32_sysenter_start:
- .incbin "arch/x86/vdso/vdso32-sysenter.so"
-vdso32_sysenter_end:
-__FINIT
+DEFINE_VDSO_IMAGE(vdso32_sysenter, "arch/x86/vdso/vdso32-sysenter.so")
diff --git a/arch/x86/vdso/vdso32/vclock_gettime.c b/arch/x86/vdso/vdso32/vclock_gettime.c
new file mode 100644
index 000000000000..175cc72c0f68
--- /dev/null
+++ b/arch/x86/vdso/vdso32/vclock_gettime.c
@@ -0,0 +1,30 @@
+#define BUILD_VDSO32
+
+#ifndef CONFIG_CC_OPTIMIZE_FOR_SIZE
+#undef CONFIG_OPTIMIZE_INLINING
+#endif
+
+#undef CONFIG_X86_PPRO_FENCE
+
+#ifdef CONFIG_X86_64
+
+/*
+ * in case of a 32 bit VDSO for a 64 bit kernel fake a 32 bit kernel
+ * configuration
+ */
+#undef CONFIG_64BIT
+#undef CONFIG_X86_64
+#undef CONFIG_ILLEGAL_POINTER_VALUE
+#undef CONFIG_SPARSEMEM_VMEMMAP
+#undef CONFIG_NR_CPUS
+
+#define CONFIG_X86_32 1
+#define CONFIG_PAGE_OFFSET 0
+#define CONFIG_ILLEGAL_POINTER_VALUE 0
+#define CONFIG_NR_CPUS 1
+
+#define BUILD_VDSO32_64
+
+#endif
+
+#include "../vclock_gettime.c"
diff --git a/arch/x86/vdso/vdso32/vdso32.lds.S b/arch/x86/vdso/vdso32/vdso32.lds.S
index 976124bb5f92..aadb8b9994cd 100644
--- a/arch/x86/vdso/vdso32/vdso32.lds.S
+++ b/arch/x86/vdso/vdso32/vdso32.lds.S
@@ -8,7 +8,11 @@
* values visible using the asm-x86/vdso.h macros from the kernel proper.
*/
+#include <asm/page.h>
+
+#define BUILD_VDSO32
#define VDSO_PRELINK 0
+
#include "../vdso-layout.lds.S"
/* The ELF entry point can be used to set the AT_SYSINFO value. */
@@ -19,6 +23,13 @@ ENTRY(__kernel_vsyscall);
*/
VERSION
{
+ LINUX_2.6 {
+ global:
+ __vdso_clock_gettime;
+ __vdso_gettimeofday;
+ __vdso_time;
+ };
+
LINUX_2.5 {
global:
__kernel_vsyscall;
@@ -31,7 +42,9 @@ VERSION
/*
* Symbols we define here called VDSO* get their values into vdso32-syms.h.
*/
-VDSO32_PRELINK = VDSO_PRELINK;
VDSO32_vsyscall = __kernel_vsyscall;
VDSO32_sigreturn = __kernel_sigreturn;
VDSO32_rt_sigreturn = __kernel_rt_sigreturn;
+VDSO32_clock_gettime = clock_gettime;
+VDSO32_gettimeofday = gettimeofday;
+VDSO32_time = time;
diff --git a/arch/x86/vdso/vdsox32.S b/arch/x86/vdso/vdsox32.S
index 295f1c7543d8..f4aa34e7f370 100644
--- a/arch/x86/vdso/vdsox32.S
+++ b/arch/x86/vdso/vdsox32.S
@@ -1,21 +1,3 @@
-#include <asm/page_types.h>
-#include <linux/linkage.h>
+#include <asm/vdso.h>
-__PAGE_ALIGNED_DATA
-
- .globl vdsox32_start, vdsox32_end
- .align PAGE_SIZE
-vdsox32_start:
- .incbin "arch/x86/vdso/vdsox32.so"
-vdsox32_end:
- .align PAGE_SIZE /* extra data here leaks to userspace. */
-
-.previous
-
- .globl vdsox32_pages
- .bss
- .align 8
- .type vdsox32_pages, @object
-vdsox32_pages:
- .zero (vdsox32_end - vdsox32_start + PAGE_SIZE - 1) / PAGE_SIZE * 8
- .size vdsox32_pages, .-vdsox32_pages
+DEFINE_VDSO_IMAGE(vdsox32, "arch/x86/vdso/vdsox32.so")
diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c
index 431e87544411..1ad102613127 100644
--- a/arch/x86/vdso/vma.c
+++ b/arch/x86/vdso/vma.c
@@ -16,20 +16,22 @@
#include <asm/vdso.h>
#include <asm/page.h>
+#if defined(CONFIG_X86_64)
unsigned int __read_mostly vdso_enabled = 1;
-extern char vdso_start[], vdso_end[];
+DECLARE_VDSO_IMAGE(vdso);
extern unsigned short vdso_sync_cpuid;
-
-extern struct page *vdso_pages[];
static unsigned vdso_size;
#ifdef CONFIG_X86_X32_ABI
-extern char vdsox32_start[], vdsox32_end[];
-extern struct page *vdsox32_pages[];
+DECLARE_VDSO_IMAGE(vdsox32);
static unsigned vdsox32_size;
+#endif
+#endif
-static void __init patch_vdsox32(void *vdso, size_t len)
+#if defined(CONFIG_X86_32) || defined(CONFIG_X86_X32_ABI) || \
+ defined(CONFIG_COMPAT)
+void __init patch_vdso32(void *vdso, size_t len)
{
Elf32_Ehdr *hdr = vdso;
Elf32_Shdr *sechdrs, *alt_sec = 0;
@@ -52,7 +54,7 @@ static void __init patch_vdsox32(void *vdso, size_t len)
}
/* If we get here, it's probably a bug. */
- pr_warning("patch_vdsox32: .altinstructions not found\n");
+ pr_warning("patch_vdso32: .altinstructions not found\n");
return; /* nothing to patch */
found:
@@ -61,6 +63,7 @@ found:
}
#endif
+#if defined(CONFIG_X86_64)
static void __init patch_vdso64(void *vdso, size_t len)
{
Elf64_Ehdr *hdr = vdso;
@@ -104,7 +107,7 @@ static int __init init_vdso(void)
vdso_pages[i] = virt_to_page(vdso_start + i*PAGE_SIZE);
#ifdef CONFIG_X86_X32_ABI
- patch_vdsox32(vdsox32_start, vdsox32_end - vdsox32_start);
+ patch_vdso32(vdsox32_start, vdsox32_end - vdsox32_start);
npages = (vdsox32_end - vdsox32_start + PAGE_SIZE - 1) / PAGE_SIZE;
vdsox32_size = npages << PAGE_SHIFT;
for (i = 0; i < npages; i++)
@@ -204,3 +207,4 @@ static __init int vdso_setup(char *s)
return 0;
}
__setup("vdso=", vdso_setup);
+#endif
diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig
index 01b90261fa38..e88fda867a33 100644
--- a/arch/x86/xen/Kconfig
+++ b/arch/x86/xen/Kconfig
@@ -7,7 +7,7 @@ config XEN
depends on PARAVIRT
select PARAVIRT_CLOCK
select XEN_HAVE_PVMMU
- depends on X86_64 || (X86_32 && X86_PAE && !X86_VISWS)
+ depends on X86_64 || (X86_32 && X86_PAE)
depends on X86_TSC
help
This is the Linux Xen port. Enabling this will allow the
@@ -19,11 +19,6 @@ config XEN_DOM0
depends on XEN && PCI_XEN && SWIOTLB_XEN
depends on X86_LOCAL_APIC && X86_IO_APIC && ACPI && PCI
-# Dummy symbol since people have come to rely on the PRIVILEGED_GUEST
-# name in tools.
-config XEN_PRIVILEGED_GUEST
- def_bool XEN_DOM0
-
config XEN_PVHVM
def_bool y
depends on XEN && PCI && X86_LOCAL_APIC
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 2423ef04ffea..86e02eabb640 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -2058,7 +2058,6 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
case FIX_RO_IDT:
#ifdef CONFIG_X86_32
case FIX_WP_TEST:
- case FIX_VDSO:
# ifdef CONFIG_HIGHMEM
case FIX_KMAP_BEGIN ... FIX_KMAP_END:
# endif
diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
index 696c694986d0..85e5d78c9874 100644
--- a/arch/x86/xen/p2m.c
+++ b/arch/x86/xen/p2m.c
@@ -881,6 +881,65 @@ static unsigned long mfn_hash(unsigned long mfn)
return hash_long(mfn, M2P_OVERRIDE_HASH_SHIFT);
}
+int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops,
+ struct gnttab_map_grant_ref *kmap_ops,
+ struct page **pages, unsigned int count)
+{
+ int i, ret = 0;
+ bool lazy = false;
+ pte_t *pte;
+
+ if (xen_feature(XENFEAT_auto_translated_physmap))
+ return 0;
+
+ if (kmap_ops &&
+ !in_interrupt() &&
+ paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) {
+ arch_enter_lazy_mmu_mode();
+ lazy = true;
+ }
+
+ for (i = 0; i < count; i++) {
+ unsigned long mfn, pfn;
+
+ /* Do not add to override if the map failed. */
+ if (map_ops[i].status)
+ continue;
+
+ if (map_ops[i].flags & GNTMAP_contains_pte) {
+ pte = (pte_t *) (mfn_to_virt(PFN_DOWN(map_ops[i].host_addr)) +
+ (map_ops[i].host_addr & ~PAGE_MASK));
+ mfn = pte_mfn(*pte);
+ } else {
+ mfn = PFN_DOWN(map_ops[i].dev_bus_addr);
+ }
+ pfn = page_to_pfn(pages[i]);
+
+ WARN_ON(PagePrivate(pages[i]));
+ SetPagePrivate(pages[i]);
+ set_page_private(pages[i], mfn);
+ pages[i]->index = pfn_to_mfn(pfn);
+
+ if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)))) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (kmap_ops) {
+ ret = m2p_add_override(mfn, pages[i], &kmap_ops[i]);
+ if (ret)
+ goto out;
+ }
+ }
+
+out:
+ if (lazy)
+ arch_leave_lazy_mmu_mode();
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(set_foreign_p2m_mapping);
+
/* Add an MFN override for a particular page */
int m2p_add_override(unsigned long mfn, struct page *page,
struct gnttab_map_grant_ref *kmap_op)
@@ -899,13 +958,6 @@ int m2p_add_override(unsigned long mfn, struct page *page,
"m2p_add_override: pfn %lx not mapped", pfn))
return -EINVAL;
}
- WARN_ON(PagePrivate(page));
- SetPagePrivate(page);
- set_page_private(page, mfn);
- page->index = pfn_to_mfn(pfn);
-
- if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn))))
- return -ENOMEM;
if (kmap_op != NULL) {
if (!PageHighMem(page)) {
@@ -943,20 +995,62 @@ int m2p_add_override(unsigned long mfn, struct page *page,
return 0;
}
EXPORT_SYMBOL_GPL(m2p_add_override);
+
+int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops,
+ struct gnttab_map_grant_ref *kmap_ops,
+ struct page **pages, unsigned int count)
+{
+ int i, ret = 0;
+ bool lazy = false;
+
+ if (xen_feature(XENFEAT_auto_translated_physmap))
+ return 0;
+
+ if (kmap_ops &&
+ !in_interrupt() &&
+ paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) {
+ arch_enter_lazy_mmu_mode();
+ lazy = true;
+ }
+
+ for (i = 0; i < count; i++) {
+ unsigned long mfn = get_phys_to_machine(page_to_pfn(pages[i]));
+ unsigned long pfn = page_to_pfn(pages[i]);
+
+ if (mfn == INVALID_P2M_ENTRY || !(mfn & FOREIGN_FRAME_BIT)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ set_page_private(pages[i], INVALID_P2M_ENTRY);
+ WARN_ON(!PagePrivate(pages[i]));
+ ClearPagePrivate(pages[i]);
+ set_phys_to_machine(pfn, pages[i]->index);
+
+ if (kmap_ops)
+ ret = m2p_remove_override(pages[i], &kmap_ops[i], mfn);
+ if (ret)
+ goto out;
+ }
+
+out:
+ if (lazy)
+ arch_leave_lazy_mmu_mode();
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clear_foreign_p2m_mapping);
+
int m2p_remove_override(struct page *page,
- struct gnttab_map_grant_ref *kmap_op)
+ struct gnttab_map_grant_ref *kmap_op,
+ unsigned long mfn)
{
unsigned long flags;
- unsigned long mfn;
unsigned long pfn;
unsigned long uninitialized_var(address);
unsigned level;
pte_t *ptep = NULL;
pfn = page_to_pfn(page);
- mfn = get_phys_to_machine(pfn);
- if (mfn == INVALID_P2M_ENTRY || !(mfn & FOREIGN_FRAME_BIT))
- return -EINVAL;
if (!PageHighMem(page)) {
address = (unsigned long)__va(pfn << PAGE_SHIFT);
@@ -970,10 +1064,7 @@ int m2p_remove_override(struct page *page,
spin_lock_irqsave(&m2p_override_lock, flags);
list_del(&page->lru);
spin_unlock_irqrestore(&m2p_override_lock, flags);
- WARN_ON(!PagePrivate(page));
- ClearPagePrivate(page);
- set_phys_to_machine(pfn, page->index);
if (kmap_op != NULL) {
if (!PageHighMem(page)) {
struct multicall_space mcs;
diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c
index 581521c843a5..4d3acc34a998 100644
--- a/arch/x86/xen/spinlock.c
+++ b/arch/x86/xen/spinlock.c
@@ -183,7 +183,7 @@ __visible void xen_lock_spinning(struct arch_spinlock *lock, __ticket_t want)
local_irq_save(flags);
- kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+ kstat_incr_irq_this_cpu(irq);
out:
cpumask_clear_cpu(cpu, &waiting_cpus);
w->lock = NULL;
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index ba56e11cbf77..c87ae7c6e5f9 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -20,6 +20,7 @@ config XTENSA
select HAVE_FUNCTION_TRACER
select HAVE_IRQ_TIME_ACCOUNTING
select HAVE_PERF_EVENTS
+ select COMMON_CLK
help
Xtensa processors are 32-bit RISC machines designed by Tensilica
primarily for embedded systems. These processors are both
@@ -80,7 +81,6 @@ choice
config XTENSA_VARIANT_FSF
bool "fsf - default (not generic) configuration"
select MMU
- select HAVE_XTENSA_GPIO32
config XTENSA_VARIANT_DC232B
bool "dc232b - Diamond 232L Standard Core Rev.B (LE)"
@@ -135,7 +135,6 @@ config HAVE_SMP
config SMP
bool "Enable Symmetric multi-processing support"
depends on HAVE_SMP
- select USE_GENERIC_SMP_HELPERS
select GENERIC_SMP_IDLE_THREAD
help
Enabled SMP Software; allows more than one CPU/CORE
diff --git a/arch/xtensa/boot/dts/xtfpga.dtsi b/arch/xtensa/boot/dts/xtfpga.dtsi
index 46b4f5eab421..e7370b11348e 100644
--- a/arch/xtensa/boot/dts/xtfpga.dtsi
+++ b/arch/xtensa/boot/dts/xtfpga.dtsi
@@ -35,6 +35,13 @@
interrupt-controller;
};
+ clocks {
+ osc: main-oscillator {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ };
+ };
+
serial0: serial@fd050020 {
device_type = "serial";
compatible = "ns16550a";
@@ -42,9 +49,7 @@
reg = <0xfd050020 0x20>;
reg-shift = <2>;
interrupts = <0 1>; /* external irq 0 */
- /* Filled in by platform_setup from FPGA register
- * clock-frequency = <100000000>;
- */
+ clocks = <&osc>;
};
enet0: ethoc@fd030000 {
@@ -52,5 +57,6 @@
reg = <0xfd030000 0x4000 0xfd800000 0x4000>;
interrupts = <1 1>; /* external irq 1 */
local-mac-address = [00 50 c2 13 6f 00];
+ clocks = <&osc>;
};
};
diff --git a/arch/xtensa/include/asm/Kbuild b/arch/xtensa/include/asm/Kbuild
index 0a337e4a8370..c3d20ba6eb86 100644
--- a/arch/xtensa/include/asm/Kbuild
+++ b/arch/xtensa/include/asm/Kbuild
@@ -9,6 +9,7 @@ generic-y += errno.h
generic-y += exec.h
generic-y += fcntl.h
generic-y += hardirq.h
+generic-y += hash.h
generic-y += ioctl.h
generic-y += irq_regs.h
generic-y += kdebug.h
@@ -17,7 +18,9 @@ generic-y += kvm_para.h
generic-y += linkage.h
generic-y += local.h
generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += percpu.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += sections.h
@@ -27,5 +30,3 @@ generic-y += termios.h
generic-y += topology.h
generic-y += trace_clock.h
generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/xtensa/include/asm/io.h b/arch/xtensa/include/asm/io.h
index 2a042d430c25..74944207167e 100644
--- a/arch/xtensa/include/asm/io.h
+++ b/arch/xtensa/include/asm/io.h
@@ -25,7 +25,7 @@
#ifdef CONFIG_MMU
-#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && CONFIG_OF
+#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && defined(CONFIG_OF)
extern unsigned long xtensa_kio_paddr;
static inline unsigned long xtensa_get_kio_paddr(void)
diff --git a/arch/xtensa/include/asm/traps.h b/arch/xtensa/include/asm/traps.h
index 8c194f6af45e..677bfcf4ee5d 100644
--- a/arch/xtensa/include/asm/traps.h
+++ b/arch/xtensa/include/asm/traps.h
@@ -23,25 +23,37 @@ void secondary_trap_init(void);
static inline void spill_registers(void)
{
-
+#if XCHAL_NUM_AREGS > 16
__asm__ __volatile__ (
- "movi a14, "__stringify((1 << PS_EXCM_BIT) | LOCKLEVEL)"\n\t"
- "mov a12, a0\n\t"
- "rsr a13, sar\n\t"
- "xsr a14, ps\n\t"
- "movi a0, _spill_registers\n\t"
- "rsync\n\t"
- "callx0 a0\n\t"
- "mov a0, a12\n\t"
- "wsr a13, sar\n\t"
- "wsr a14, ps\n\t"
- : :
-#if defined(CONFIG_FRAME_POINTER)
- : "a2", "a3", "a4", "a11", "a12", "a13", "a14", "a15",
+ " call12 1f\n"
+ " _j 2f\n"
+ " retw\n"
+ " .align 4\n"
+ "1:\n"
+ " _entry a1, 48\n"
+ " addi a12, a0, 3\n"
+#if XCHAL_NUM_AREGS > 32
+ " .rept (" __stringify(XCHAL_NUM_AREGS) " - 32) / 12\n"
+ " _entry a1, 48\n"
+ " mov a12, a0\n"
+ " .endr\n"
+#endif
+ " _entry a1, 48\n"
+#if XCHAL_NUM_AREGS % 12 == 0
+ " mov a8, a8\n"
+#elif XCHAL_NUM_AREGS % 12 == 4
+ " mov a12, a12\n"
+#elif XCHAL_NUM_AREGS % 12 == 8
+ " mov a4, a4\n"
+#endif
+ " retw\n"
+ "2:\n"
+ : : : "a12", "a13", "memory");
#else
- : "a2", "a3", "a4", "a7", "a11", "a12", "a13", "a14", "a15",
+ __asm__ __volatile__ (
+ " mov a12, a12\n"
+ : : : "memory");
#endif
- "memory");
}
#endif /* _XTENSA_TRAPS_H */
diff --git a/arch/xtensa/include/asm/vectors.h b/arch/xtensa/include/asm/vectors.h
index 5791b45d5a5d..f74ddfbb92ef 100644
--- a/arch/xtensa/include/asm/vectors.h
+++ b/arch/xtensa/include/asm/vectors.h
@@ -25,7 +25,7 @@
#define XCHAL_KIO_DEFAULT_PADDR 0xf0000000
#define XCHAL_KIO_SIZE 0x10000000
-#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && CONFIG_OF
+#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && defined(CONFIG_OF)
#define XCHAL_KIO_PADDR xtensa_get_kio_paddr()
#else
#define XCHAL_KIO_PADDR XCHAL_KIO_DEFAULT_PADDR
diff --git a/arch/xtensa/include/uapi/asm/unistd.h b/arch/xtensa/include/uapi/asm/unistd.h
index 51940fec6990..b9395529f02d 100644
--- a/arch/xtensa/include/uapi/asm/unistd.h
+++ b/arch/xtensa/include/uapi/asm/unistd.h
@@ -734,7 +734,12 @@ __SYSCALL(332, sys_finit_module, 3)
#define __NR_accept4 333
__SYSCALL(333, sys_accept4, 4)
-#define __NR_syscall_count 334
+#define __NR_sched_setattr 334
+__SYSCALL(334, sys_sched_setattr, 2)
+#define __NR_sched_getattr 335
+__SYSCALL(335, sys_sched_getattr, 3)
+
+#define __NR_syscall_count 336
/*
* sysxtensa syscall handler
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index 21dbe6bdb8ed..ef7f4990722b 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -1081,196 +1081,53 @@ ENTRY(fast_syscall_spill_registers)
rsr a0, sar
s32i a3, a2, PT_AREG3
- s32i a4, a2, PT_AREG4
- s32i a0, a2, PT_AREG5 # store SAR to PT_AREG5
+ s32i a0, a2, PT_SAR
- /* The spill routine might clobber a7, a11, and a15. */
+ /* The spill routine might clobber a4, a7, a8, a11, a12, and a15. */
+ s32i a4, a2, PT_AREG4
s32i a7, a2, PT_AREG7
+ s32i a8, a2, PT_AREG8
s32i a11, a2, PT_AREG11
+ s32i a12, a2, PT_AREG12
s32i a15, a2, PT_AREG15
- call0 _spill_registers # destroys a3, a4, and SAR
-
- /* Advance PC, restore registers and SAR, and return from exception. */
-
- l32i a3, a2, PT_AREG5
- l32i a4, a2, PT_AREG4
- l32i a0, a2, PT_AREG0
- wsr a3, sar
- l32i a3, a2, PT_AREG3
-
- /* Restore clobbered registers. */
-
- l32i a7, a2, PT_AREG7
- l32i a11, a2, PT_AREG11
- l32i a15, a2, PT_AREG15
-
- movi a2, 0
- rfe
-
-ENDPROC(fast_syscall_spill_registers)
-
-/* Fixup handler.
- *
- * We get here if the spill routine causes an exception, e.g. tlb miss.
- * We basically restore WINDOWBASE and WINDOWSTART to the condition when
- * we entered the spill routine and jump to the user exception handler.
- *
- * a0: value of depc, original value in depc
- * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE
- * a3: exctable, original value in excsave1
- */
-
-ENTRY(fast_syscall_spill_registers_fixup)
-
- rsr a2, windowbase # get current windowbase (a2 is saved)
- xsr a0, depc # restore depc and a0
- ssl a2 # set shift (32 - WB)
-
- /* We need to make sure the current registers (a0-a3) are preserved.
- * To do this, we simply set the bit for the current window frame
- * in WS, so that the exception handlers save them to the task stack.
- */
-
- xsr a3, excsave1 # get spill-mask
- slli a3, a3, 1 # shift left by one
-
- slli a2, a3, 32-WSBITS
- src a2, a3, a2 # a2 = xxwww1yyxxxwww1yy......
- wsr a2, windowstart # set corrected windowstart
-
- srli a3, a3, 1
- rsr a2, excsave1
- l32i a2, a2, EXC_TABLE_DOUBLE_SAVE # restore a2
- xsr a2, excsave1
- s32i a3, a2, EXC_TABLE_DOUBLE_SAVE # save a3
- l32i a3, a2, EXC_TABLE_PARAM # original WB (in user task)
- xsr a2, excsave1
-
- /* Return to the original (user task) WINDOWBASE.
- * We leave the following frame behind:
- * a0, a1, a2 same
- * a3: trashed (saved in EXC_TABLE_DOUBLE_SAVE)
- * depc: depc (we have to return to that address)
- * excsave_1: exctable
- */
-
- wsr a3, windowbase
- rsync
-
- /* We are now in the original frame when we entered _spill_registers:
- * a0: return address
- * a1: used, stack pointer
- * a2: kernel stack pointer
- * a3: available
- * depc: exception address
- * excsave: exctable
- * Note: This frame might be the same as above.
- */
-
- /* Setup stack pointer. */
-
- addi a2, a2, -PT_USER_SIZE
- s32i a0, a2, PT_AREG0
-
- /* Make sure we return to this fixup handler. */
-
- movi a3, fast_syscall_spill_registers_fixup_return
- s32i a3, a2, PT_DEPC # setup depc
-
- /* Jump to the exception handler. */
-
- rsr a3, excsave1
- rsr a0, exccause
- addx4 a0, a0, a3 # find entry in table
- l32i a0, a0, EXC_TABLE_FAST_USER # load handler
- l32i a3, a3, EXC_TABLE_DOUBLE_SAVE
- jx a0
-
-ENDPROC(fast_syscall_spill_registers_fixup)
-
-ENTRY(fast_syscall_spill_registers_fixup_return)
-
- /* When we return here, all registers have been restored (a2: DEPC) */
-
- wsr a2, depc # exception address
-
- /* Restore fixup handler. */
-
- rsr a2, excsave1
- s32i a3, a2, EXC_TABLE_DOUBLE_SAVE
- movi a3, fast_syscall_spill_registers_fixup
- s32i a3, a2, EXC_TABLE_FIXUP
- rsr a3, windowbase
- s32i a3, a2, EXC_TABLE_PARAM
- l32i a2, a2, EXC_TABLE_KSTK
-
- /* Load WB at the time the exception occurred. */
-
- rsr a3, sar # WB is still in SAR
- neg a3, a3
- wsr a3, windowbase
- rsync
-
- rsr a3, excsave1
- l32i a3, a3, EXC_TABLE_DOUBLE_SAVE
-
- rfde
-
-ENDPROC(fast_syscall_spill_registers_fixup_return)
-
-/*
- * spill all registers.
- *
- * This is not a real function. The following conditions must be met:
- *
- * - must be called with call0.
- * - uses a3, a4 and SAR.
- * - the last 'valid' register of each frame are clobbered.
- * - the caller must have registered a fixup handler
- * (or be inside a critical section)
- * - PS_EXCM must be set (PS_WOE cleared?)
- */
-
-ENTRY(_spill_registers)
-
/*
* Rotate ws so that the current windowbase is at bit 0.
* Assume ws = xxxwww1yy (www1 current window frame).
* Rotate ws right so that a4 = yyxxxwww1.
*/
- rsr a4, windowbase
+ rsr a0, windowbase
rsr a3, windowstart # a3 = xxxwww1yy
- ssr a4 # holds WB
- slli a4, a3, WSBITS
- or a3, a3, a4 # a3 = xxxwww1yyxxxwww1yy
+ ssr a0 # holds WB
+ slli a0, a3, WSBITS
+ or a3, a3, a0 # a3 = xxxwww1yyxxxwww1yy
srl a3, a3 # a3 = 00xxxwww1yyxxxwww1
/* We are done if there are no more than the current register frame. */
extui a3, a3, 1, WSBITS-1 # a3 = 0yyxxxwww
- movi a4, (1 << (WSBITS-1))
+ movi a0, (1 << (WSBITS-1))
_beqz a3, .Lnospill # only one active frame? jump
/* We want 1 at the top, so that we return to the current windowbase */
- or a3, a3, a4 # 1yyxxxwww
+ or a3, a3, a0 # 1yyxxxwww
/* Skip empty frames - get 'oldest' WINDOWSTART-bit. */
wsr a3, windowstart # save shifted windowstart
- neg a4, a3
- and a3, a4, a3 # first bit set from right: 000010000
+ neg a0, a3
+ and a3, a0, a3 # first bit set from right: 000010000
- ffs_ws a4, a3 # a4: shifts to skip empty frames
+ ffs_ws a0, a3 # a0: shifts to skip empty frames
movi a3, WSBITS
- sub a4, a3, a4 # WSBITS-a4:number of 0-bits from right
- ssr a4 # save in SAR for later.
+ sub a0, a3, a0 # WSBITS-a0:number of 0-bits from right
+ ssr a0 # save in SAR for later.
rsr a3, windowbase
- add a3, a3, a4
+ add a3, a3, a0
wsr a3, windowbase
rsync
@@ -1285,22 +1142,6 @@ ENTRY(_spill_registers)
* we have to save 4,8. or 12 registers.
*/
- _bbsi.l a3, 1, .Lc4
- _bbsi.l a3, 2, .Lc8
-
- /* Special case: we have a call12-frame starting at a4. */
-
- _bbci.l a3, 3, .Lc12 # bit 3 shouldn't be zero! (Jump to Lc12 first)
-
- s32e a4, a1, -16 # a1 is valid with an empty spill area
- l32e a4, a5, -12
- s32e a8, a4, -48
- mov a8, a4
- l32e a4, a1, -16
- j .Lc12c
-
-.Lnospill:
- ret
.Lloop: _bbsi.l a3, 1, .Lc4
_bbci.l a3, 2, .Lc12
@@ -1314,20 +1155,10 @@ ENTRY(_spill_registers)
s32e a9, a4, -28
s32e a10, a4, -24
s32e a11, a4, -20
-
srli a11, a3, 2 # shift windowbase by 2
rotw 2
_bnei a3, 1, .Lloop
-
-.Lexit: /* Done. Do the final rotation, set WS, and return. */
-
- rotw 1
- rsr a3, windowbase
- ssl a3
- movi a3, 1
- sll a3, a3
- wsr a3, windowstart
- ret
+ j .Lexit
.Lc4: s32e a4, a9, -16
s32e a5, a9, -12
@@ -1343,11 +1174,11 @@ ENTRY(_spill_registers)
/* 12-register frame (call12) */
- l32e a2, a5, -12
- s32e a8, a2, -48
- mov a8, a2
+ l32e a0, a5, -12
+ s32e a8, a0, -48
+ mov a8, a0
-.Lc12c: s32e a9, a8, -44
+ s32e a9, a8, -44
s32e a10, a8, -40
s32e a11, a8, -36
s32e a12, a8, -32
@@ -1367,30 +1198,54 @@ ENTRY(_spill_registers)
*/
rotw 1
- mov a5, a13
+ mov a4, a13
rotw -1
- s32e a4, a9, -16
- s32e a5, a9, -12
- s32e a6, a9, -8
- s32e a7, a9, -4
+ s32e a4, a8, -16
+ s32e a5, a8, -12
+ s32e a6, a8, -8
+ s32e a7, a8, -4
rotw 3
_beqi a3, 1, .Lexit
j .Lloop
-.Linvalid_mask:
+.Lexit:
- /* We get here because of an unrecoverable error in the window
- * registers. If we are in user space, we kill the application,
- * however, this condition is unrecoverable in kernel space.
- */
+ /* Done. Do the final rotation and set WS */
+
+ rotw 1
+ rsr a3, windowbase
+ ssl a3
+ movi a3, 1
+ sll a3, a3
+ wsr a3, windowstart
+.Lnospill:
+
+ /* Advance PC, restore registers and SAR, and return from exception. */
+
+ l32i a3, a2, PT_SAR
+ l32i a0, a2, PT_AREG0
+ wsr a3, sar
+ l32i a3, a2, PT_AREG3
- rsr a0, ps
- _bbci.l a0, PS_UM_BIT, 1f
+ /* Restore clobbered registers. */
- /* User space: Setup a dummy frame and kill application.
+ l32i a4, a2, PT_AREG4
+ l32i a7, a2, PT_AREG7
+ l32i a8, a2, PT_AREG8
+ l32i a11, a2, PT_AREG11
+ l32i a12, a2, PT_AREG12
+ l32i a15, a2, PT_AREG15
+
+ movi a2, 0
+ rfe
+
+.Linvalid_mask:
+
+ /* We get here because of an unrecoverable error in the window
+ * registers, so set up a dummy frame and kill the user application.
* Note: We assume EXC_TABLE_KSTK contains a valid stack pointer.
*/
@@ -1414,14 +1269,136 @@ ENTRY(_spill_registers)
movi a4, do_exit
callx4 a4
-1: /* Kernel space: PANIC! */
+ /* shouldn't return, so panic */
wsr a0, excsave1
movi a0, unrecoverable_exception
callx0 a0 # should not return
1: j 1b
-ENDPROC(_spill_registers)
+
+ENDPROC(fast_syscall_spill_registers)
+
+/* Fixup handler.
+ *
+ * We get here if the spill routine causes an exception, e.g. tlb miss.
+ * We basically restore WINDOWBASE and WINDOWSTART to the condition when
+ * we entered the spill routine and jump to the user exception handler.
+ *
+ * Note that we only need to restore the bits in windowstart that have not
+ * been spilled yet by the _spill_register routine. Luckily, a3 contains a
+ * rotated windowstart with only those bits set for frames that haven't been
+ * spilled yet. Because a3 is rotated such that bit 0 represents the register
+ * frame for the current windowbase - 1, we need to rotate a3 left by the
+ * value of the current windowbase + 1 and move it to windowstart.
+ *
+ * a0: value of depc, original value in depc
+ * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE
+ * a3: exctable, original value in excsave1
+ */
+
+ENTRY(fast_syscall_spill_registers_fixup)
+
+ rsr a2, windowbase # get current windowbase (a2 is saved)
+ xsr a0, depc # restore depc and a0
+ ssl a2 # set shift (32 - WB)
+
+ /* We need to make sure the current registers (a0-a3) are preserved.
+ * To do this, we simply set the bit for the current window frame
+ * in WS, so that the exception handlers save them to the task stack.
+ *
+ * Note: we use a3 to set the windowbase, so we take a special care
+ * of it, saving it in the original _spill_registers frame across
+ * the exception handler call.
+ */
+
+ xsr a3, excsave1 # get spill-mask
+ slli a3, a3, 1 # shift left by one
+ addi a3, a3, 1 # set the bit for the current window frame
+
+ slli a2, a3, 32-WSBITS
+ src a2, a3, a2 # a2 = xxwww1yyxxxwww1yy......
+ wsr a2, windowstart # set corrected windowstart
+
+ srli a3, a3, 1
+ rsr a2, excsave1
+ l32i a2, a2, EXC_TABLE_DOUBLE_SAVE # restore a2
+ xsr a2, excsave1
+ s32i a3, a2, EXC_TABLE_DOUBLE_SAVE # save a3
+ l32i a3, a2, EXC_TABLE_PARAM # original WB (in user task)
+ xsr a2, excsave1
+
+ /* Return to the original (user task) WINDOWBASE.
+ * We leave the following frame behind:
+ * a0, a1, a2 same
+ * a3: trashed (saved in EXC_TABLE_DOUBLE_SAVE)
+ * depc: depc (we have to return to that address)
+ * excsave_1: exctable
+ */
+
+ wsr a3, windowbase
+ rsync
+
+ /* We are now in the original frame when we entered _spill_registers:
+ * a0: return address
+ * a1: used, stack pointer
+ * a2: kernel stack pointer
+ * a3: available
+ * depc: exception address
+ * excsave: exctable
+ * Note: This frame might be the same as above.
+ */
+
+ /* Setup stack pointer. */
+
+ addi a2, a2, -PT_USER_SIZE
+ s32i a0, a2, PT_AREG0
+
+ /* Make sure we return to this fixup handler. */
+
+ movi a3, fast_syscall_spill_registers_fixup_return
+ s32i a3, a2, PT_DEPC # setup depc
+
+ /* Jump to the exception handler. */
+
+ rsr a3, excsave1
+ rsr a0, exccause
+ addx4 a0, a0, a3 # find entry in table
+ l32i a0, a0, EXC_TABLE_FAST_USER # load handler
+ l32i a3, a3, EXC_TABLE_DOUBLE_SAVE
+ jx a0
+
+ENDPROC(fast_syscall_spill_registers_fixup)
+
+ENTRY(fast_syscall_spill_registers_fixup_return)
+
+ /* When we return here, all registers have been restored (a2: DEPC) */
+
+ wsr a2, depc # exception address
+
+ /* Restore fixup handler. */
+
+ rsr a2, excsave1
+ s32i a3, a2, EXC_TABLE_DOUBLE_SAVE
+ movi a3, fast_syscall_spill_registers_fixup
+ s32i a3, a2, EXC_TABLE_FIXUP
+ rsr a3, windowbase
+ s32i a3, a2, EXC_TABLE_PARAM
+ l32i a2, a2, EXC_TABLE_KSTK
+
+ /* Load WB at the time the exception occurred. */
+
+ rsr a3, sar # WB is still in SAR
+ neg a3, a3
+ wsr a3, windowbase
+ rsync
+
+ rsr a3, excsave1
+ l32i a3, a3, EXC_TABLE_DOUBLE_SAVE
+
+ rfde
+
+ENDPROC(fast_syscall_spill_registers_fixup_return)
#ifdef CONFIG_MMU
/*
@@ -1794,6 +1771,43 @@ ENTRY(system_call)
ENDPROC(system_call)
+/*
+ * Spill live registers on the kernel stack macro.
+ *
+ * Entry condition: ps.woe is set, ps.excm is cleared
+ * Exit condition: windowstart has single bit set
+ * May clobber: a12, a13
+ */
+ .macro spill_registers_kernel
+
+#if XCHAL_NUM_AREGS > 16
+ call12 1f
+ _j 2f
+ retw
+ .align 4
+1:
+ _entry a1, 48
+ addi a12, a0, 3
+#if XCHAL_NUM_AREGS > 32
+ .rept (XCHAL_NUM_AREGS - 32) / 12
+ _entry a1, 48
+ mov a12, a0
+ .endr
+#endif
+ _entry a1, 48
+#if XCHAL_NUM_AREGS % 12 == 0
+ mov a8, a8
+#elif XCHAL_NUM_AREGS % 12 == 4
+ mov a12, a12
+#elif XCHAL_NUM_AREGS % 12 == 8
+ mov a4, a4
+#endif
+ retw
+2:
+#else
+ mov a12, a12
+#endif
+ .endm
/*
* Task switch.
@@ -1806,21 +1820,20 @@ ENTRY(_switch_to)
entry a1, 16
- mov a12, a2 # preserve 'prev' (a2)
- mov a13, a3 # and 'next' (a3)
+ mov a10, a2 # preserve 'prev' (a2)
+ mov a11, a3 # and 'next' (a3)
l32i a4, a2, TASK_THREAD_INFO
l32i a5, a3, TASK_THREAD_INFO
- save_xtregs_user a4 a6 a8 a9 a10 a11 THREAD_XTREGS_USER
+ save_xtregs_user a4 a6 a8 a9 a12 a13 THREAD_XTREGS_USER
- s32i a0, a12, THREAD_RA # save return address
- s32i a1, a12, THREAD_SP # save stack pointer
+ s32i a0, a10, THREAD_RA # save return address
+ s32i a1, a10, THREAD_SP # save stack pointer
/* Disable ints while we manipulate the stack pointer. */
- movi a14, (1 << PS_EXCM_BIT) | LOCKLEVEL
- xsr a14, ps
+ rsil a14, LOCKLEVEL
rsr a3, excsave1
rsync
s32i a3, a3, EXC_TABLE_FIXUP /* enter critical section */
@@ -1835,7 +1848,7 @@ ENTRY(_switch_to)
/* Flush register file. */
- call0 _spill_registers # destroys a3, a4, and SAR
+ spill_registers_kernel
/* Set kernel stack (and leave critical section)
* Note: It's save to set it here. The stack will not be overwritten
@@ -1851,13 +1864,13 @@ ENTRY(_switch_to)
/* restore context of the task 'next' */
- l32i a0, a13, THREAD_RA # restore return address
- l32i a1, a13, THREAD_SP # restore stack pointer
+ l32i a0, a11, THREAD_RA # restore return address
+ l32i a1, a11, THREAD_SP # restore stack pointer
- load_xtregs_user a5 a6 a8 a9 a10 a11 THREAD_XTREGS_USER
+ load_xtregs_user a5 a6 a8 a9 a12 a13 THREAD_XTREGS_USER
wsr a14, ps
- mov a2, a12 # return 'prev'
+ mov a2, a10 # return 'prev'
rsync
retw
diff --git a/arch/xtensa/kernel/irq.c b/arch/xtensa/kernel/irq.c
index 482868a2de6e..3eee94f621eb 100644
--- a/arch/xtensa/kernel/irq.c
+++ b/arch/xtensa/kernel/irq.c
@@ -155,18 +155,6 @@ void __init init_IRQ(void)
}
#ifdef CONFIG_HOTPLUG_CPU
-static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
-{
- struct irq_desc *desc = irq_to_desc(irq);
- struct irq_chip *chip = irq_data_get_irq_chip(data);
- unsigned long flags;
-
- raw_spin_lock_irqsave(&desc->lock, flags);
- if (chip->irq_set_affinity)
- chip->irq_set_affinity(data, cpumask_of(cpu), false);
- raw_spin_unlock_irqrestore(&desc->lock, flags);
-}
-
/*
* The CPU has been marked offline. Migrate IRQs off this CPU. If
* the affinity settings do not allow other CPUs, force them onto any
@@ -175,10 +163,9 @@ static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
void migrate_irqs(void)
{
unsigned int i, cpu = smp_processor_id();
- struct irq_desc *desc;
- for_each_irq_desc(i, desc) {
- struct irq_data *data = irq_desc_get_irq_data(desc);
+ for_each_active_irq(i) {
+ struct irq_data *data = irq_get_irq_data(i);
unsigned int newcpu;
if (irqd_is_per_cpu(data))
@@ -194,11 +181,8 @@ void migrate_irqs(void)
i, cpu);
cpumask_setall(data->affinity);
- newcpu = cpumask_any_and(data->affinity,
- cpu_online_mask);
}
-
- route_irq(data, i, newcpu);
+ irq_set_affinity(i, data->affinity);
}
}
#endif /* CONFIG_HOTPLUG_CPU */
diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c
index 7d12af1317f1..84fe931bb60e 100644
--- a/arch/xtensa/kernel/setup.c
+++ b/arch/xtensa/kernel/setup.c
@@ -22,6 +22,7 @@
#include <linux/bootmem.h>
#include <linux/kernel.h>
#include <linux/percpu.h>
+#include <linux/clk-provider.h>
#include <linux/cpu.h>
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
@@ -276,6 +277,7 @@ void __init early_init_devtree(void *params)
static int __init xtensa_device_probe(void)
{
+ of_clk_init(NULL);
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
return 0;
}
diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c
index 08b769d3b3a1..2a1823de69cc 100644
--- a/arch/xtensa/kernel/time.c
+++ b/arch/xtensa/kernel/time.c
@@ -30,6 +30,7 @@
#include <asm/platform.h>
unsigned long ccount_freq; /* ccount Hz */
+EXPORT_SYMBOL(ccount_freq);
static cycle_t ccount_read(struct clocksource *cs)
{
diff --git a/arch/xtensa/kernel/vectors.S b/arch/xtensa/kernel/vectors.S
index cb8fd44caabc..f9e1ec346e35 100644
--- a/arch/xtensa/kernel/vectors.S
+++ b/arch/xtensa/kernel/vectors.S
@@ -235,7 +235,7 @@ ENTRY(_DoubleExceptionVector)
/* Check for overflow/underflow exception, jump if overflow. */
- _bbci.l a0, 6, _DoubleExceptionVector_WindowOverflow
+ bbci.l a0, 6, _DoubleExceptionVector_WindowOverflow
/*
* Restart window underflow exception.
diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c
index 74a60c7e085e..80b33ed51f31 100644
--- a/arch/xtensa/kernel/xtensa_ksyms.c
+++ b/arch/xtensa/kernel/xtensa_ksyms.c
@@ -122,9 +122,7 @@ EXPORT_SYMBOL(insw);
EXPORT_SYMBOL(insl);
extern long common_exception_return;
-extern long _spill_registers;
EXPORT_SYMBOL(common_exception_return);
-EXPORT_SYMBOL(_spill_registers);
#ifdef CONFIG_FUNCTION_TRACER
EXPORT_SYMBOL(_mcount);
diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c
index 479d7537a32a..aff108df92d3 100644
--- a/arch/xtensa/mm/init.c
+++ b/arch/xtensa/mm/init.c
@@ -90,7 +90,7 @@ int __init mem_reserve(unsigned long start, unsigned long end, int must_exist)
/*
- * Initialize the bootmem system and give it all the memory we have available.
+ * Initialize the bootmem system and give it all low memory we have available.
*/
void __init bootmem_init(void)
@@ -142,9 +142,14 @@ void __init bootmem_init(void)
/* Add all remaining memory pieces into the bootmem map */
- for (i=0; i<sysmem.nr_banks; i++)
- free_bootmem(sysmem.bank[i].start,
- sysmem.bank[i].end - sysmem.bank[i].start);
+ for (i = 0; i < sysmem.nr_banks; i++) {
+ if (sysmem.bank[i].start >> PAGE_SHIFT < max_low_pfn) {
+ unsigned long end = min(max_low_pfn << PAGE_SHIFT,
+ sysmem.bank[i].end);
+ free_bootmem(sysmem.bank[i].start,
+ end - sysmem.bank[i].start);
+ }
+ }
}
diff --git a/arch/xtensa/mm/mmu.c b/arch/xtensa/mm/mmu.c
index 36ec171698b8..861203e958da 100644
--- a/arch/xtensa/mm/mmu.c
+++ b/arch/xtensa/mm/mmu.c
@@ -39,7 +39,7 @@ void init_mmu(void)
set_itlbcfg_register(0);
set_dtlbcfg_register(0);
#endif
-#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && CONFIG_OF
+#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && defined(CONFIG_OF)
/*
* Update the IO area mapping in case xtensa_kio_paddr has changed
*/
diff --git a/arch/xtensa/platforms/xtfpga/setup.c b/arch/xtensa/platforms/xtfpga/setup.c
index 800227862fe8..57fd08b36f51 100644
--- a/arch/xtensa/platforms/xtfpga/setup.c
+++ b/arch/xtensa/platforms/xtfpga/setup.c
@@ -135,11 +135,11 @@ static void __init update_local_mac(struct device_node *node)
static int __init machine_setup(void)
{
- struct device_node *serial;
+ struct device_node *clock;
struct device_node *eth = NULL;
- for_each_compatible_node(serial, NULL, "ns16550a")
- update_clock_frequency(serial);
+ for_each_node_by_name(clock, "main-oscillator")
+ update_clock_frequency(clock);
if ((eth = of_find_compatible_node(eth, NULL, "opencores,ethoc")))
update_local_mac(eth);
@@ -290,6 +290,7 @@ static int __init xtavnet_init(void)
* knows whether they set it correctly on the DIP switches.
*/
pr_info("XTFPGA: Ethernet MAC %pM\n", ethoc_pdata.hwaddr);
+ ethoc_pdata.eth_clkfreq = *(long *)XTFPGA_CLKFRQ_VADDR;
return 0;
}
diff --git a/arch/xtensa/variants/fsf/include/variant/tie.h b/arch/xtensa/variants/fsf/include/variant/tie.h
index bf4020116df5..244cdea4dee5 100644
--- a/arch/xtensa/variants/fsf/include/variant/tie.h
+++ b/arch/xtensa/variants/fsf/include/variant/tie.h
@@ -18,13 +18,6 @@
#define XCHAL_CP_MASK 0x00 /* bitmask of all CPs by ID */
#define XCHAL_CP_PORT_MASK 0x00 /* bitmask of only port CPs */
-/* Basic parameters of each coprocessor: */
-#define XCHAL_CP7_NAME "XTIOP"
-#define XCHAL_CP7_IDENT XTIOP
-#define XCHAL_CP7_SA_SIZE 0 /* size of state save area */
-#define XCHAL_CP7_SA_ALIGN 1 /* min alignment of save area */
-#define XCHAL_CP_ID_XTIOP 7 /* coprocessor ID (0..7) */
-
/* Filler info for unassigned coprocessors, to simplify arrays etc: */
#define XCHAL_NCP_SA_SIZE 0
#define XCHAL_NCP_SA_ALIGN 1
@@ -42,6 +35,8 @@
#define XCHAL_CP5_SA_ALIGN 1
#define XCHAL_CP6_SA_SIZE 0
#define XCHAL_CP6_SA_ALIGN 1
+#define XCHAL_CP7_SA_SIZE 0
+#define XCHAL_CP7_SA_ALIGN 1
/* Save area for non-coprocessor optional and custom (TIE) state: */
#define XCHAL_NCP_SA_SIZE 0
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 4e491d9b5292..e4a4145926f6 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -336,7 +336,7 @@ static void blkg_destroy(struct blkcg_gq *blkg)
* under queue_lock. If it's not pointing to @blkg now, it never
* will. Hint assignment itself can race safely.
*/
- if (rcu_dereference_raw(blkcg->blkg_hint) == blkg)
+ if (rcu_access_pointer(blkcg->blkg_hint) == blkg)
rcu_assign_pointer(blkcg->blkg_hint, NULL);
/*
@@ -894,7 +894,7 @@ static int blkcg_can_attach(struct cgroup_subsys_state *css,
int ret = 0;
/* task_lock() is needed to avoid races with exit_io_context() */
- cgroup_taskset_for_each(task, css, tset) {
+ cgroup_taskset_for_each(task, tset) {
task_lock(task);
ioc = task->io_context;
if (ioc && atomic_read(&ioc->nr_tasks) > 1)
@@ -906,17 +906,14 @@ static int blkcg_can_attach(struct cgroup_subsys_state *css,
return ret;
}
-struct cgroup_subsys blkio_subsys = {
- .name = "blkio",
+struct cgroup_subsys blkio_cgrp_subsys = {
.css_alloc = blkcg_css_alloc,
.css_offline = blkcg_css_offline,
.css_free = blkcg_css_free,
.can_attach = blkcg_can_attach,
- .subsys_id = blkio_subsys_id,
.base_cftypes = blkcg_files,
- .module = THIS_MODULE,
};
-EXPORT_SYMBOL_GPL(blkio_subsys);
+EXPORT_SYMBOL_GPL(blkio_cgrp_subsys);
/**
* blkcg_activate_policy - activate a blkcg policy on a request_queue
@@ -1106,7 +1103,7 @@ int blkcg_policy_register(struct blkcg_policy *pol)
/* everything is in place, add intf files for the new policy */
if (pol->cftypes)
- WARN_ON(cgroup_add_cftypes(&blkio_subsys, pol->cftypes));
+ WARN_ON(cgroup_add_cftypes(&blkio_cgrp_subsys, pol->cftypes));
ret = 0;
out_unlock:
mutex_unlock(&blkcg_pol_mutex);
diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h
index 86154eab9523..371fe8e92ab5 100644
--- a/block/blk-cgroup.h
+++ b/block/blk-cgroup.h
@@ -186,7 +186,7 @@ static inline struct blkcg *css_to_blkcg(struct cgroup_subsys_state *css)
static inline struct blkcg *task_blkcg(struct task_struct *tsk)
{
- return css_to_blkcg(task_css(tsk, blkio_subsys_id));
+ return css_to_blkcg(task_css(tsk, blkio_cgrp_id));
}
static inline struct blkcg *bio_blkcg(struct bio *bio)
@@ -241,12 +241,16 @@ static inline struct blkcg_gq *pd_to_blkg(struct blkg_policy_data *pd)
*/
static inline int blkg_path(struct blkcg_gq *blkg, char *buf, int buflen)
{
- int ret;
+ char *p;
- ret = cgroup_path(blkg->blkcg->css.cgroup, buf, buflen);
- if (ret)
+ p = cgroup_path(blkg->blkcg->css.cgroup, buf, buflen);
+ if (!p) {
strncpy(buf, "<unavailable>", buflen);
- return ret;
+ return -ENAMETOOLONG;
+ }
+
+ memmove(buf, p, buf + buflen - p);
+ return 0;
}
/**
@@ -435,9 +439,9 @@ static inline uint64_t blkg_stat_read(struct blkg_stat *stat)
uint64_t v;
do {
- start = u64_stats_fetch_begin_bh(&stat->syncp);
+ start = u64_stats_fetch_begin_irq(&stat->syncp);
v = stat->cnt;
- } while (u64_stats_fetch_retry_bh(&stat->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&stat->syncp, start));
return v;
}
@@ -508,9 +512,9 @@ static inline struct blkg_rwstat blkg_rwstat_read(struct blkg_rwstat *rwstat)
struct blkg_rwstat tmp;
do {
- start = u64_stats_fetch_begin_bh(&rwstat->syncp);
+ start = u64_stats_fetch_begin_irq(&rwstat->syncp);
tmp = *rwstat;
- } while (u64_stats_fetch_retry_bh(&rwstat->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&rwstat->syncp, start));
return tmp;
}
diff --git a/block/blk-core.c b/block/blk-core.c
index c00e0bdeab4a..34d7c196338b 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -708,9 +708,13 @@ blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn,
if (!q)
return NULL;
- if (blk_init_rl(&q->root_rl, q, GFP_KERNEL))
+ q->flush_rq = kzalloc(sizeof(struct request), GFP_KERNEL);
+ if (!q->flush_rq)
return NULL;
+ if (blk_init_rl(&q->root_rl, q, GFP_KERNEL))
+ goto fail;
+
q->request_fn = rfn;
q->prep_rq_fn = NULL;
q->unprep_rq_fn = NULL;
@@ -733,12 +737,16 @@ blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn,
/* init elevator */
if (elevator_init(q, NULL)) {
mutex_unlock(&q->sysfs_lock);
- return NULL;
+ goto fail;
}
mutex_unlock(&q->sysfs_lock);
return q;
+
+fail:
+ kfree(q->flush_rq);
+ return NULL;
}
EXPORT_SYMBOL(blk_init_allocated_queue);
@@ -1127,7 +1135,7 @@ static struct request *blk_old_get_request(struct request_queue *q, int rw,
struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask)
{
if (q->mq_ops)
- return blk_mq_alloc_request(q, rw, gfp_mask, false);
+ return blk_mq_alloc_request(q, rw, gfp_mask);
else
return blk_old_get_request(q, rw, gfp_mask);
}
@@ -1278,6 +1286,11 @@ void __blk_put_request(struct request_queue *q, struct request *req)
if (unlikely(!q))
return;
+ if (q->mq_ops) {
+ blk_mq_free_request(req);
+ return;
+ }
+
blk_pm_put_request(req);
elv_completed_request(q, req);
@@ -1915,7 +1928,7 @@ EXPORT_SYMBOL(submit_bio);
* in some cases below, so export this function.
* Request stacking drivers like request-based dm may change the queue
* limits while requests are in the queue (e.g. dm's table swapping).
- * Such request stacking drivers should check those requests agaist
+ * Such request stacking drivers should check those requests against
* the new queue limits again when they dispatch those requests,
* although such checkings are also done against the old queue limits
* when submitting requests.
@@ -2340,7 +2353,7 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes)
if (!req->bio)
return false;
- trace_block_rq_complete(req->q, req);
+ trace_block_rq_complete(req->q, req, nr_bytes);
/*
* For fs requests, rq is just carrier of independent bio's
diff --git a/block/blk-exec.c b/block/blk-exec.c
index bbfc072a79c2..dbf4502b1d67 100644
--- a/block/blk-exec.c
+++ b/block/blk-exec.c
@@ -65,7 +65,7 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
* be resued after dying flag is set
*/
if (q->mq_ops) {
- blk_mq_insert_request(q, rq, true);
+ blk_mq_insert_request(rq, at_head, true, false);
return;
}
diff --git a/block/blk-flush.c b/block/blk-flush.c
index 9288aaf35c21..43e6b4755e9a 100644
--- a/block/blk-flush.c
+++ b/block/blk-flush.c
@@ -130,20 +130,29 @@ static void blk_flush_restore_request(struct request *rq)
blk_clear_rq_complete(rq);
}
-static void mq_flush_data_run(struct work_struct *work)
+static void mq_flush_run(struct work_struct *work)
{
struct request *rq;
- rq = container_of(work, struct request, mq_flush_data);
+ rq = container_of(work, struct request, mq_flush_work);
memset(&rq->csd, 0, sizeof(rq->csd));
- blk_mq_run_request(rq, true, false);
+ blk_mq_insert_request(rq, false, true, false);
}
-static void blk_mq_flush_data_insert(struct request *rq)
+static bool blk_flush_queue_rq(struct request *rq, bool add_front)
{
- INIT_WORK(&rq->mq_flush_data, mq_flush_data_run);
- kblockd_schedule_work(rq->q, &rq->mq_flush_data);
+ if (rq->q->mq_ops) {
+ INIT_WORK(&rq->mq_flush_work, mq_flush_run);
+ kblockd_schedule_work(rq->q, &rq->mq_flush_work);
+ return false;
+ } else {
+ if (add_front)
+ list_add(&rq->queuelist, &rq->q->queue_head);
+ else
+ list_add_tail(&rq->queuelist, &rq->q->queue_head);
+ return true;
+ }
}
/**
@@ -187,12 +196,7 @@ static bool blk_flush_complete_seq(struct request *rq, unsigned int seq,
case REQ_FSEQ_DATA:
list_move_tail(&rq->flush.list, &q->flush_data_in_flight);
- if (q->mq_ops)
- blk_mq_flush_data_insert(rq);
- else {
- list_add(&rq->queuelist, &q->queue_head);
- queued = true;
- }
+ queued = blk_flush_queue_rq(rq, true);
break;
case REQ_FSEQ_DONE:
@@ -216,9 +220,6 @@ static bool blk_flush_complete_seq(struct request *rq, unsigned int seq,
}
kicked = blk_kick_flush(q);
- /* blk_mq_run_flush will run queue */
- if (q->mq_ops)
- return queued;
return kicked | queued;
}
@@ -230,10 +231,9 @@ static void flush_end_io(struct request *flush_rq, int error)
struct request *rq, *n;
unsigned long flags = 0;
- if (q->mq_ops) {
- blk_mq_free_request(flush_rq);
+ if (q->mq_ops)
spin_lock_irqsave(&q->mq_flush_lock, flags);
- }
+
running = &q->flush_queue[q->flush_running_idx];
BUG_ON(q->flush_pending_idx == q->flush_running_idx);
@@ -263,49 +263,14 @@ static void flush_end_io(struct request *flush_rq, int error)
* kblockd.
*/
if (queued || q->flush_queue_delayed) {
- if (!q->mq_ops)
- blk_run_queue_async(q);
- else
- /*
- * This can be optimized to only run queues with requests
- * queued if necessary.
- */
- blk_mq_run_queues(q, true);
+ WARN_ON(q->mq_ops);
+ blk_run_queue_async(q);
}
q->flush_queue_delayed = 0;
if (q->mq_ops)
spin_unlock_irqrestore(&q->mq_flush_lock, flags);
}
-static void mq_flush_work(struct work_struct *work)
-{
- struct request_queue *q;
- struct request *rq;
-
- q = container_of(work, struct request_queue, mq_flush_work);
-
- /* We don't need set REQ_FLUSH_SEQ, it's for consistency */
- rq = blk_mq_alloc_request(q, WRITE_FLUSH|REQ_FLUSH_SEQ,
- __GFP_WAIT|GFP_ATOMIC, true);
- rq->cmd_type = REQ_TYPE_FS;
- rq->end_io = flush_end_io;
-
- blk_mq_run_request(rq, true, false);
-}
-
-/*
- * We can't directly use q->flush_rq, because it doesn't have tag and is not in
- * hctx->rqs[]. so we must allocate a new request, since we can't sleep here,
- * so offload the work to workqueue.
- *
- * Note: we assume a flush request finished in any hardware queue will flush
- * the whole disk cache.
- */
-static void mq_run_flush(struct request_queue *q)
-{
- kblockd_schedule_work(q, &q->mq_flush_work);
-}
-
/**
* blk_kick_flush - consider issuing flush request
* @q: request_queue being kicked
@@ -340,19 +305,31 @@ static bool blk_kick_flush(struct request_queue *q)
* different from running_idx, which means flush is in flight.
*/
q->flush_pending_idx ^= 1;
+
if (q->mq_ops) {
- mq_run_flush(q);
- return true;
+ struct blk_mq_ctx *ctx = first_rq->mq_ctx;
+ struct blk_mq_hw_ctx *hctx = q->mq_ops->map_queue(q, ctx->cpu);
+
+ blk_mq_rq_init(hctx, q->flush_rq);
+ q->flush_rq->mq_ctx = ctx;
+
+ /*
+ * Reuse the tag value from the fist waiting request,
+ * with blk-mq the tag is generated during request
+ * allocation and drivers can rely on it being inside
+ * the range they asked for.
+ */
+ q->flush_rq->tag = first_rq->tag;
+ } else {
+ blk_rq_init(q, q->flush_rq);
}
- blk_rq_init(q, &q->flush_rq);
- q->flush_rq.cmd_type = REQ_TYPE_FS;
- q->flush_rq.cmd_flags = WRITE_FLUSH | REQ_FLUSH_SEQ;
- q->flush_rq.rq_disk = first_rq->rq_disk;
- q->flush_rq.end_io = flush_end_io;
+ q->flush_rq->cmd_type = REQ_TYPE_FS;
+ q->flush_rq->cmd_flags = WRITE_FLUSH | REQ_FLUSH_SEQ;
+ q->flush_rq->rq_disk = first_rq->rq_disk;
+ q->flush_rq->end_io = flush_end_io;
- list_add_tail(&q->flush_rq.queuelist, &q->queue_head);
- return true;
+ return blk_flush_queue_rq(q->flush_rq, false);
}
static void flush_data_end_io(struct request *rq, int error)
@@ -437,7 +414,7 @@ void blk_insert_flush(struct request *rq)
if ((policy & REQ_FSEQ_DATA) &&
!(policy & (REQ_FSEQ_PREFLUSH | REQ_FSEQ_POSTFLUSH))) {
if (q->mq_ops) {
- blk_mq_run_request(rq, false, true);
+ blk_mq_insert_request(rq, false, false, true);
} else
list_add_tail(&rq->queuelist, &q->queue_head);
return;
@@ -558,5 +535,4 @@ EXPORT_SYMBOL(blkdev_issue_flush);
void blk_mq_init_flush(struct request_queue *q)
{
spin_lock_init(&q->mq_flush_lock);
- INIT_WORK(&q->mq_flush_work, mq_flush_work);
}
diff --git a/block/blk-ioc.c b/block/blk-ioc.c
index 242df01413f6..1a27f45ec776 100644
--- a/block/blk-ioc.c
+++ b/block/blk-ioc.c
@@ -68,7 +68,7 @@ static void ioc_destroy_icq(struct io_cq *icq)
* under queue_lock. If it's not pointing to @icq now, it never
* will. Hint assignment itself can race safely.
*/
- if (rcu_dereference_raw(ioc->icq_hint) == icq)
+ if (rcu_access_pointer(ioc->icq_hint) == icq)
rcu_assign_pointer(ioc->icq_hint, NULL);
ioc_exit_icq(icq);
diff --git a/block/blk-iopoll.c b/block/blk-iopoll.c
index 1855bf51edb0..c11d24e379e2 100644
--- a/block/blk-iopoll.c
+++ b/block/blk-iopoll.c
@@ -14,9 +14,6 @@
#include "blk.h"
-int blk_iopoll_enabled = 1;
-EXPORT_SYMBOL(blk_iopoll_enabled);
-
static unsigned int blk_iopoll_budget __read_mostly = 256;
static DEFINE_PER_CPU(struct list_head, blk_cpu_iopoll);
diff --git a/block/blk-lib.c b/block/blk-lib.c
index 2da76c999ef3..97a733cf3d5f 100644
--- a/block/blk-lib.c
+++ b/block/blk-lib.c
@@ -119,6 +119,14 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
atomic_inc(&bb.done);
submit_bio(type, bio);
+
+ /*
+ * We can loop for a long time in here, if someone does
+ * full device discards (like mkfs). Be nice and allow
+ * us to schedule out to avoid softlocking if preempt
+ * is disabled.
+ */
+ cond_resched();
}
blk_finish_plug(&plug);
diff --git a/block/blk-map.c b/block/blk-map.c
index ae4ae1047fd9..cca6356d216d 100644
--- a/block/blk-map.c
+++ b/block/blk-map.c
@@ -285,7 +285,7 @@ EXPORT_SYMBOL(blk_rq_unmap_user);
*
* Description:
* Data will be mapped directly if possible. Otherwise a bounce
- * buffer is used. Can be called multple times to append multple
+ * buffer is used. Can be called multiple times to append multiple
* buffers.
*/
int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf,
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 8f8adaa95466..6c583f9c5b65 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -21,6 +21,16 @@ static unsigned int __blk_recalc_rq_segments(struct request_queue *q,
if (!bio)
return 0;
+ /*
+ * This should probably be returning 0, but blk_add_request_payload()
+ * (Christoph!!!!)
+ */
+ if (bio->bi_rw & REQ_DISCARD)
+ return 1;
+
+ if (bio->bi_rw & REQ_WRITE_SAME)
+ return 1;
+
fbio = bio;
cluster = blk_queue_cluster(q);
seg_size = 0;
@@ -161,30 +171,60 @@ new_segment:
*bvprv = *bvec;
}
-/*
- * map a request to scatterlist, return number of sg entries setup. Caller
- * must make sure sg can hold rq->nr_phys_segments entries
- */
-int blk_rq_map_sg(struct request_queue *q, struct request *rq,
- struct scatterlist *sglist)
+static int __blk_bios_map_sg(struct request_queue *q, struct bio *bio,
+ struct scatterlist *sglist,
+ struct scatterlist **sg)
{
struct bio_vec bvec, bvprv = { NULL };
- struct req_iterator iter;
- struct scatterlist *sg;
+ struct bvec_iter iter;
int nsegs, cluster;
nsegs = 0;
cluster = blk_queue_cluster(q);
- /*
- * for each bio in rq
- */
- sg = NULL;
- rq_for_each_segment(bvec, rq, iter) {
- __blk_segment_map_sg(q, &bvec, sglist, &bvprv, &sg,
- &nsegs, &cluster);
- } /* segments in rq */
+ if (bio->bi_rw & REQ_DISCARD) {
+ /*
+ * This is a hack - drivers should be neither modifying the
+ * biovec, nor relying on bi_vcnt - but because of
+ * blk_add_request_payload(), a discard bio may or may not have
+ * a payload we need to set up here (thank you Christoph) and
+ * bi_vcnt is really the only way of telling if we need to.
+ */
+
+ if (bio->bi_vcnt)
+ goto single_segment;
+
+ return 0;
+ }
+
+ if (bio->bi_rw & REQ_WRITE_SAME) {
+single_segment:
+ *sg = sglist;
+ bvec = bio_iovec(bio);
+ sg_set_page(*sg, bvec.bv_page, bvec.bv_len, bvec.bv_offset);
+ return 1;
+ }
+
+ for_each_bio(bio)
+ bio_for_each_segment(bvec, bio, iter)
+ __blk_segment_map_sg(q, &bvec, sglist, &bvprv, sg,
+ &nsegs, &cluster);
+ return nsegs;
+}
+
+/*
+ * map a request to scatterlist, return number of sg entries setup. Caller
+ * must make sure sg can hold rq->nr_phys_segments entries
+ */
+int blk_rq_map_sg(struct request_queue *q, struct request *rq,
+ struct scatterlist *sglist)
+{
+ struct scatterlist *sg = NULL;
+ int nsegs = 0;
+
+ if (rq->bio)
+ nsegs = __blk_bios_map_sg(q, rq->bio, sglist, &sg);
if (unlikely(rq->cmd_flags & REQ_COPY_USER) &&
(blk_rq_bytes(rq) & q->dma_pad_mask)) {
@@ -230,20 +270,13 @@ EXPORT_SYMBOL(blk_rq_map_sg);
int blk_bio_map_sg(struct request_queue *q, struct bio *bio,
struct scatterlist *sglist)
{
- struct bio_vec bvec, bvprv = { NULL };
- struct scatterlist *sg;
- int nsegs, cluster;
- struct bvec_iter iter;
-
- nsegs = 0;
- cluster = blk_queue_cluster(q);
-
- sg = NULL;
- bio_for_each_segment(bvec, bio, iter) {
- __blk_segment_map_sg(q, &bvec, sglist, &bvprv, &sg,
- &nsegs, &cluster);
- } /* segments in bio */
+ struct scatterlist *sg = NULL;
+ int nsegs;
+ struct bio *next = bio->bi_next;
+ bio->bi_next = NULL;
+ nsegs = __blk_bios_map_sg(q, bio, sglist, &sg);
+ bio->bi_next = next;
if (sg)
sg_mark_end(sg);
diff --git a/block/blk-mq-cpu.c b/block/blk-mq-cpu.c
index 3146befb56aa..136ef8643bba 100644
--- a/block/blk-mq-cpu.c
+++ b/block/blk-mq-cpu.c
@@ -11,7 +11,7 @@
#include "blk-mq.h"
static LIST_HEAD(blk_mq_cpu_notify_list);
-static DEFINE_SPINLOCK(blk_mq_cpu_notify_lock);
+static DEFINE_RAW_SPINLOCK(blk_mq_cpu_notify_lock);
static int blk_mq_main_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
@@ -19,12 +19,12 @@ static int blk_mq_main_cpu_notify(struct notifier_block *self,
unsigned int cpu = (unsigned long) hcpu;
struct blk_mq_cpu_notifier *notify;
- spin_lock(&blk_mq_cpu_notify_lock);
+ raw_spin_lock(&blk_mq_cpu_notify_lock);
list_for_each_entry(notify, &blk_mq_cpu_notify_list, list)
notify->notify(notify->data, action, cpu);
- spin_unlock(&blk_mq_cpu_notify_lock);
+ raw_spin_unlock(&blk_mq_cpu_notify_lock);
return NOTIFY_OK;
}
@@ -32,16 +32,16 @@ void blk_mq_register_cpu_notifier(struct blk_mq_cpu_notifier *notifier)
{
BUG_ON(!notifier->notify);
- spin_lock(&blk_mq_cpu_notify_lock);
+ raw_spin_lock(&blk_mq_cpu_notify_lock);
list_add_tail(&notifier->list, &blk_mq_cpu_notify_list);
- spin_unlock(&blk_mq_cpu_notify_lock);
+ raw_spin_unlock(&blk_mq_cpu_notify_lock);
}
void blk_mq_unregister_cpu_notifier(struct blk_mq_cpu_notifier *notifier)
{
- spin_lock(&blk_mq_cpu_notify_lock);
+ raw_spin_lock(&blk_mq_cpu_notify_lock);
list_del(&notifier->list);
- spin_unlock(&blk_mq_cpu_notify_lock);
+ raw_spin_unlock(&blk_mq_cpu_notify_lock);
}
void blk_mq_init_cpu_notifier(struct blk_mq_cpu_notifier *notifier,
diff --git a/block/blk-mq-cpumap.c b/block/blk-mq-cpumap.c
index f8721278601c..097921329619 100644
--- a/block/blk-mq-cpumap.c
+++ b/block/blk-mq-cpumap.c
@@ -9,15 +9,6 @@
#include "blk.h"
#include "blk-mq.h"
-static void show_map(unsigned int *map, unsigned int nr)
-{
- int i;
-
- pr_info("blk-mq: CPU -> queue map\n");
- for_each_online_cpu(i)
- pr_info(" CPU%2u -> Queue %u\n", i, map[i]);
-}
-
static int cpu_to_queue_index(unsigned int nr_cpus, unsigned int nr_queues,
const int cpu)
{
@@ -85,7 +76,6 @@ int blk_mq_update_queue_map(unsigned int *map, unsigned int nr_queues)
map[i] = map[first_sibling];
}
- show_map(map, nr_cpus);
free_cpumask_var(cpus);
return 0;
}
diff --git a/block/blk-mq-sysfs.c b/block/blk-mq-sysfs.c
index b91ce75bd35d..b0ba264b0522 100644
--- a/block/blk-mq-sysfs.c
+++ b/block/blk-mq-sysfs.c
@@ -244,6 +244,32 @@ static ssize_t blk_mq_hw_sysfs_tags_show(struct blk_mq_hw_ctx *hctx, char *page)
return blk_mq_tag_sysfs_show(hctx->tags, page);
}
+static ssize_t blk_mq_hw_sysfs_cpus_show(struct blk_mq_hw_ctx *hctx, char *page)
+{
+ unsigned int i, queue_num, first = 1;
+ ssize_t ret = 0;
+
+ blk_mq_disable_hotplug();
+
+ for_each_online_cpu(i) {
+ queue_num = hctx->queue->mq_map[i];
+ if (queue_num != hctx->queue_num)
+ continue;
+
+ if (first)
+ ret += sprintf(ret + page, "%u", i);
+ else
+ ret += sprintf(ret + page, ", %u", i);
+
+ first = 0;
+ }
+
+ blk_mq_enable_hotplug();
+
+ ret += sprintf(ret + page, "\n");
+ return ret;
+}
+
static struct blk_mq_ctx_sysfs_entry blk_mq_sysfs_dispatched = {
.attr = {.name = "dispatched", .mode = S_IRUGO },
.show = blk_mq_sysfs_dispatched_show,
@@ -294,6 +320,10 @@ static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_tags = {
.attr = {.name = "tags", .mode = S_IRUGO },
.show = blk_mq_hw_sysfs_tags_show,
};
+static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_cpus = {
+ .attr = {.name = "cpu_list", .mode = S_IRUGO },
+ .show = blk_mq_hw_sysfs_cpus_show,
+};
static struct attribute *default_hw_ctx_attrs[] = {
&blk_mq_hw_sysfs_queued.attr,
@@ -302,6 +332,7 @@ static struct attribute *default_hw_ctx_attrs[] = {
&blk_mq_hw_sysfs_pending.attr,
&blk_mq_hw_sysfs_ipi.attr,
&blk_mq_hw_sysfs_tags.attr,
+ &blk_mq_hw_sysfs_cpus.attr,
NULL,
};
diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c
index 5d70edc9855f..83ae96c51a27 100644
--- a/block/blk-mq-tag.c
+++ b/block/blk-mq-tag.c
@@ -184,7 +184,7 @@ void blk_mq_free_tags(struct blk_mq_tags *tags)
ssize_t blk_mq_tag_sysfs_show(struct blk_mq_tags *tags, char *page)
{
char *orig_page = page;
- int cpu;
+ unsigned int cpu;
if (!tags)
return 0;
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 57039fcd9c93..b1bcc619d0ea 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -73,8 +73,8 @@ static void blk_mq_hctx_mark_pending(struct blk_mq_hw_ctx *hctx,
set_bit(ctx->index_hw, hctx->ctx_map);
}
-static struct request *blk_mq_alloc_rq(struct blk_mq_hw_ctx *hctx, gfp_t gfp,
- bool reserved)
+static struct request *__blk_mq_alloc_request(struct blk_mq_hw_ctx *hctx,
+ gfp_t gfp, bool reserved)
{
struct request *rq;
unsigned int tag;
@@ -193,12 +193,6 @@ static void blk_mq_rq_ctx_init(struct request_queue *q, struct blk_mq_ctx *ctx,
ctx->rq_dispatched[rw_is_sync(rw_flags)]++;
}
-static struct request *__blk_mq_alloc_request(struct blk_mq_hw_ctx *hctx,
- gfp_t gfp, bool reserved)
-{
- return blk_mq_alloc_rq(hctx, gfp, reserved);
-}
-
static struct request *blk_mq_alloc_request_pinned(struct request_queue *q,
int rw, gfp_t gfp,
bool reserved)
@@ -226,15 +220,14 @@ static struct request *blk_mq_alloc_request_pinned(struct request_queue *q,
return rq;
}
-struct request *blk_mq_alloc_request(struct request_queue *q, int rw,
- gfp_t gfp, bool reserved)
+struct request *blk_mq_alloc_request(struct request_queue *q, int rw, gfp_t gfp)
{
struct request *rq;
if (blk_mq_queue_enter(q))
return NULL;
- rq = blk_mq_alloc_request_pinned(q, rw, gfp, reserved);
+ rq = blk_mq_alloc_request_pinned(q, rw, gfp, false);
if (rq)
blk_mq_put_ctx(rq->mq_ctx);
return rq;
@@ -258,7 +251,7 @@ EXPORT_SYMBOL(blk_mq_alloc_reserved_request);
/*
* Re-init and set pdu, if we have it
*/
-static void blk_mq_rq_init(struct blk_mq_hw_ctx *hctx, struct request *rq)
+void blk_mq_rq_init(struct blk_mq_hw_ctx *hctx, struct request *rq)
{
blk_rq_init(hctx->queue, rq);
@@ -290,38 +283,10 @@ void blk_mq_free_request(struct request *rq)
__blk_mq_free_request(hctx, ctx, rq);
}
-static void blk_mq_bio_endio(struct request *rq, struct bio *bio, int error)
-{
- if (error)
- clear_bit(BIO_UPTODATE, &bio->bi_flags);
- else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
- error = -EIO;
-
- if (unlikely(rq->cmd_flags & REQ_QUIET))
- set_bit(BIO_QUIET, &bio->bi_flags);
-
- /* don't actually finish bio if it's part of flush sequence */
- if (!(rq->cmd_flags & REQ_FLUSH_SEQ))
- bio_endio(bio, error);
-}
-
-void blk_mq_complete_request(struct request *rq, int error)
+bool blk_mq_end_io_partial(struct request *rq, int error, unsigned int nr_bytes)
{
- struct bio *bio = rq->bio;
- unsigned int bytes = 0;
-
- trace_block_rq_complete(rq->q, rq);
-
- while (bio) {
- struct bio *next = bio->bi_next;
-
- bio->bi_next = NULL;
- bytes += bio->bi_iter.bi_size;
- blk_mq_bio_endio(rq, bio, error);
- bio = next;
- }
-
- blk_account_io_completion(rq, bytes);
+ if (blk_update_request(rq, error, blk_rq_bytes(rq)))
+ return true;
blk_account_io_done(rq);
@@ -329,49 +294,57 @@ void blk_mq_complete_request(struct request *rq, int error)
rq->end_io(rq, error);
else
blk_mq_free_request(rq);
+ return false;
}
+EXPORT_SYMBOL(blk_mq_end_io_partial);
-void __blk_mq_end_io(struct request *rq, int error)
-{
- if (!blk_mark_rq_complete(rq))
- blk_mq_complete_request(rq, error);
-}
-
-static void blk_mq_end_io_remote(void *data)
+static void __blk_mq_complete_request_remote(void *data)
{
struct request *rq = data;
- __blk_mq_end_io(rq, rq->errors);
+ rq->q->softirq_done_fn(rq);
}
-/*
- * End IO on this request on a multiqueue enabled driver. We'll either do
- * it directly inline, or punt to a local IPI handler on the matching
- * remote CPU.
- */
-void blk_mq_end_io(struct request *rq, int error)
+void __blk_mq_complete_request(struct request *rq)
{
struct blk_mq_ctx *ctx = rq->mq_ctx;
int cpu;
- if (!ctx->ipi_redirect)
- return __blk_mq_end_io(rq, error);
+ if (!ctx->ipi_redirect) {
+ rq->q->softirq_done_fn(rq);
+ return;
+ }
cpu = get_cpu();
if (cpu != ctx->cpu && cpu_online(ctx->cpu)) {
- rq->errors = error;
- rq->csd.func = blk_mq_end_io_remote;
+ rq->csd.func = __blk_mq_complete_request_remote;
rq->csd.info = rq;
rq->csd.flags = 0;
- __smp_call_function_single(ctx->cpu, &rq->csd, 0);
+ smp_call_function_single_async(ctx->cpu, &rq->csd);
} else {
- __blk_mq_end_io(rq, error);
+ rq->q->softirq_done_fn(rq);
}
put_cpu();
}
-EXPORT_SYMBOL(blk_mq_end_io);
-static void blk_mq_start_request(struct request *rq)
+/**
+ * blk_mq_complete_request - end I/O on a request
+ * @rq: the request being processed
+ *
+ * Description:
+ * Ends all I/O on a request. It does not handle partial completions.
+ * The actual completion happens out-of-order, through a IPI handler.
+ **/
+void blk_mq_complete_request(struct request *rq)
+{
+ if (unlikely(blk_should_fake_timeout(rq->q)))
+ return;
+ if (!blk_mark_rq_complete(rq))
+ __blk_mq_complete_request(rq);
+}
+EXPORT_SYMBOL(blk_mq_complete_request);
+
+static void blk_mq_start_request(struct request *rq, bool last)
{
struct request_queue *q = rq->q;
@@ -384,6 +357,25 @@ static void blk_mq_start_request(struct request *rq)
*/
rq->deadline = jiffies + q->rq_timeout;
set_bit(REQ_ATOM_STARTED, &rq->atomic_flags);
+
+ if (q->dma_drain_size && blk_rq_bytes(rq)) {
+ /*
+ * Make sure space for the drain appears. We know we can do
+ * this because max_hw_segments has been adjusted to be one
+ * fewer than the device can handle.
+ */
+ rq->nr_phys_segments++;
+ }
+
+ /*
+ * Flag the last request in the series so that drivers know when IO
+ * should be kicked off, if they don't do it on a per-request basis.
+ *
+ * Note: the flag isn't the only condition drivers should do kick off.
+ * If drive is busy, the last request might not have the bit set.
+ */
+ if (last)
+ rq->cmd_flags |= REQ_END;
}
static void blk_mq_requeue_request(struct request *rq)
@@ -392,6 +384,11 @@ static void blk_mq_requeue_request(struct request *rq)
trace_block_rq_requeue(q, rq);
clear_bit(REQ_ATOM_STARTED, &rq->atomic_flags);
+
+ rq->cmd_flags &= ~REQ_END;
+
+ if (q->dma_drain_size && blk_rq_bytes(rq))
+ rq->nr_phys_segments--;
}
struct blk_mq_timeout_data {
@@ -517,7 +514,7 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)
LIST_HEAD(rq_list);
int bit, queued;
- if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->flags)))
+ if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->state)))
return;
hctx->run++;
@@ -559,19 +556,8 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)
rq = list_first_entry(&rq_list, struct request, queuelist);
list_del_init(&rq->queuelist);
- blk_mq_start_request(rq);
- /*
- * Last request in the series. Flag it as such, this
- * enables drivers to know when IO should be kicked off,
- * if they don't do it on a per-request basis.
- *
- * Note: the flag isn't the only condition drivers
- * should do kick off. If drive is busy, the last
- * request might not have the bit set.
- */
- if (list_empty(&rq_list))
- rq->cmd_flags |= REQ_END;
+ blk_mq_start_request(rq, list_empty(&rq_list));
ret = q->mq_ops->queue_rq(hctx, rq);
switch (ret) {
@@ -589,8 +575,8 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)
break;
default:
pr_err("blk-mq: bad return on queue: %d\n", ret);
- rq->errors = -EIO;
case BLK_MQ_RQ_QUEUE_ERROR:
+ rq->errors = -EIO;
blk_mq_end_io(rq, rq->errors);
break;
}
@@ -617,7 +603,7 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)
void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async)
{
- if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->flags)))
+ if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->state)))
return;
if (!async)
@@ -637,7 +623,7 @@ void blk_mq_run_queues(struct request_queue *q, bool async)
queue_for_each_hw_ctx(q, hctx, i) {
if ((!blk_mq_hctx_has_pending(hctx) &&
list_empty_careful(&hctx->dispatch)) ||
- test_bit(BLK_MQ_S_STOPPED, &hctx->flags))
+ test_bit(BLK_MQ_S_STOPPED, &hctx->state))
continue;
blk_mq_run_hw_queue(hctx, async);
@@ -693,13 +679,16 @@ static void blk_mq_work_fn(struct work_struct *work)
}
static void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx,
- struct request *rq)
+ struct request *rq, bool at_head)
{
struct blk_mq_ctx *ctx = rq->mq_ctx;
trace_block_rq_insert(hctx->queue, rq);
- list_add_tail(&rq->queuelist, &ctx->rq_list);
+ if (at_head)
+ list_add(&rq->queuelist, &ctx->rq_list);
+ else
+ list_add_tail(&rq->queuelist, &ctx->rq_list);
blk_mq_hctx_mark_pending(hctx, ctx);
/*
@@ -708,60 +697,27 @@ static void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx,
blk_mq_add_timer(rq);
}
-void blk_mq_insert_request(struct request_queue *q, struct request *rq,
- bool run_queue)
+void blk_mq_insert_request(struct request *rq, bool at_head, bool run_queue,
+ bool async)
{
+ struct request_queue *q = rq->q;
struct blk_mq_hw_ctx *hctx;
- struct blk_mq_ctx *ctx, *current_ctx;
+ struct blk_mq_ctx *ctx = rq->mq_ctx, *current_ctx;
+
+ current_ctx = blk_mq_get_ctx(q);
+ if (!cpu_online(ctx->cpu))
+ rq->mq_ctx = ctx = current_ctx;
- ctx = rq->mq_ctx;
hctx = q->mq_ops->map_queue(q, ctx->cpu);
- if (rq->cmd_flags & (REQ_FLUSH | REQ_FUA)) {
+ if (rq->cmd_flags & (REQ_FLUSH | REQ_FUA) &&
+ !(rq->cmd_flags & (REQ_FLUSH_SEQ))) {
blk_insert_flush(rq);
} else {
- current_ctx = blk_mq_get_ctx(q);
-
- if (!cpu_online(ctx->cpu)) {
- ctx = current_ctx;
- hctx = q->mq_ops->map_queue(q, ctx->cpu);
- rq->mq_ctx = ctx;
- }
spin_lock(&ctx->lock);
- __blk_mq_insert_request(hctx, rq);
+ __blk_mq_insert_request(hctx, rq, at_head);
spin_unlock(&ctx->lock);
-
- blk_mq_put_ctx(current_ctx);
- }
-
- if (run_queue)
- __blk_mq_run_hw_queue(hctx);
-}
-EXPORT_SYMBOL(blk_mq_insert_request);
-
-/*
- * This is a special version of blk_mq_insert_request to bypass FLUSH request
- * check. Should only be used internally.
- */
-void blk_mq_run_request(struct request *rq, bool run_queue, bool async)
-{
- struct request_queue *q = rq->q;
- struct blk_mq_hw_ctx *hctx;
- struct blk_mq_ctx *ctx, *current_ctx;
-
- current_ctx = blk_mq_get_ctx(q);
-
- ctx = rq->mq_ctx;
- if (!cpu_online(ctx->cpu)) {
- ctx = current_ctx;
- rq->mq_ctx = ctx;
}
- hctx = q->mq_ops->map_queue(q, ctx->cpu);
-
- /* ctx->cpu might be offline */
- spin_lock(&ctx->lock);
- __blk_mq_insert_request(hctx, rq);
- spin_unlock(&ctx->lock);
blk_mq_put_ctx(current_ctx);
@@ -798,7 +754,7 @@ static void blk_mq_insert_requests(struct request_queue *q,
rq = list_first_entry(list, struct request, queuelist);
list_del_init(&rq->queuelist);
rq->mq_ctx = ctx;
- __blk_mq_insert_request(hctx, rq);
+ __blk_mq_insert_request(hctx, rq, false);
}
spin_unlock(&ctx->lock);
@@ -888,6 +844,11 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
blk_queue_bounce(q, &bio);
+ if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {
+ bio_endio(bio, -EIO);
+ return;
+ }
+
if (use_plug && blk_attempt_plug_merge(q, bio, &request_count))
return;
@@ -899,6 +860,8 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
ctx = blk_mq_get_ctx(q);
hctx = q->mq_ops->map_queue(q, ctx->cpu);
+ if (is_sync)
+ rw |= REQ_SYNC;
trace_block_getrq(q, bio, rw);
rq = __blk_mq_alloc_request(hctx, GFP_ATOMIC, false);
if (likely(rq))
@@ -950,7 +913,7 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
__blk_mq_free_request(hctx, ctx, rq);
else {
blk_mq_bio_to_request(rq, bio);
- __blk_mq_insert_request(hctx, rq);
+ __blk_mq_insert_request(hctx, rq, false);
}
spin_unlock(&ctx->lock);
@@ -1031,8 +994,46 @@ static void blk_mq_hctx_notify(void *data, unsigned long action,
blk_mq_put_ctx(ctx);
}
-static void blk_mq_init_hw_commands(struct blk_mq_hw_ctx *hctx,
- void (*init)(void *, struct blk_mq_hw_ctx *,
+static int blk_mq_init_hw_commands(struct blk_mq_hw_ctx *hctx,
+ int (*init)(void *, struct blk_mq_hw_ctx *,
+ struct request *, unsigned int),
+ void *data)
+{
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; i < hctx->queue_depth; i++) {
+ struct request *rq = hctx->rqs[i];
+
+ ret = init(data, hctx, rq, i);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+int blk_mq_init_commands(struct request_queue *q,
+ int (*init)(void *, struct blk_mq_hw_ctx *,
+ struct request *, unsigned int),
+ void *data)
+{
+ struct blk_mq_hw_ctx *hctx;
+ unsigned int i;
+ int ret = 0;
+
+ queue_for_each_hw_ctx(q, hctx, i) {
+ ret = blk_mq_init_hw_commands(hctx, init, data);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(blk_mq_init_commands);
+
+static void blk_mq_free_hw_commands(struct blk_mq_hw_ctx *hctx,
+ void (*free)(void *, struct blk_mq_hw_ctx *,
struct request *, unsigned int),
void *data)
{
@@ -1041,12 +1042,12 @@ static void blk_mq_init_hw_commands(struct blk_mq_hw_ctx *hctx,
for (i = 0; i < hctx->queue_depth; i++) {
struct request *rq = hctx->rqs[i];
- init(data, hctx, rq, i);
+ free(data, hctx, rq, i);
}
}
-void blk_mq_init_commands(struct request_queue *q,
- void (*init)(void *, struct blk_mq_hw_ctx *,
+void blk_mq_free_commands(struct request_queue *q,
+ void (*free)(void *, struct blk_mq_hw_ctx *,
struct request *, unsigned int),
void *data)
{
@@ -1054,9 +1055,9 @@ void blk_mq_init_commands(struct request_queue *q,
unsigned int i;
queue_for_each_hw_ctx(q, hctx, i)
- blk_mq_init_hw_commands(hctx, init, data);
+ blk_mq_free_hw_commands(hctx, free, data);
}
-EXPORT_SYMBOL(blk_mq_init_commands);
+EXPORT_SYMBOL(blk_mq_free_commands);
static void blk_mq_free_rq_map(struct blk_mq_hw_ctx *hctx)
{
@@ -1309,15 +1310,6 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_reg *reg,
reg->queue_depth = BLK_MQ_MAX_DEPTH;
}
- /*
- * Set aside a tag for flush requests. It will only be used while
- * another flush request is in progress but outside the driver.
- *
- * TODO: only allocate if flushes are supported
- */
- reg->queue_depth++;
- reg->reserved_tags++;
-
if (reg->queue_depth < (reg->reserved_tags + BLK_MQ_TAG_MIN))
return ERR_PTR(-EINVAL);
@@ -1360,17 +1352,27 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_reg *reg,
q->mq_ops = reg->ops;
q->queue_flags |= QUEUE_FLAG_MQ_DEFAULT;
+ q->sg_reserved_size = INT_MAX;
+
blk_queue_make_request(q, blk_mq_make_request);
blk_queue_rq_timed_out(q, reg->ops->timeout);
if (reg->timeout)
blk_queue_rq_timeout(q, reg->timeout);
+ if (reg->ops->complete)
+ blk_queue_softirq_done(q, reg->ops->complete);
+
blk_mq_init_flush(q);
blk_mq_init_cpu_queues(q, reg->nr_hw_queues);
- if (blk_mq_init_hw_queues(q, reg, driver_data))
+ q->flush_rq = kzalloc(round_up(sizeof(struct request) + reg->cmd_size,
+ cache_line_size()), GFP_KERNEL);
+ if (!q->flush_rq)
goto err_hw;
+ if (blk_mq_init_hw_queues(q, reg, driver_data))
+ goto err_flush_rq;
+
blk_mq_map_swqueue(q);
mutex_lock(&all_q_mutex);
@@ -1378,6 +1380,9 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_reg *reg,
mutex_unlock(&all_q_mutex);
return q;
+
+err_flush_rq:
+ kfree(q->flush_rq);
err_hw:
kfree(q->mq_map);
err_map:
@@ -1463,6 +1468,16 @@ static int blk_mq_queue_reinit_notify(struct notifier_block *nb,
return NOTIFY_OK;
}
+void blk_mq_disable_hotplug(void)
+{
+ mutex_lock(&all_q_mutex);
+}
+
+void blk_mq_enable_hotplug(void)
+{
+ mutex_unlock(&all_q_mutex);
+}
+
static int __init blk_mq_init(void)
{
blk_mq_cpu_init();
diff --git a/block/blk-mq.h b/block/blk-mq.h
index 5c3917984b00..ebbe6bac9d61 100644
--- a/block/blk-mq.h
+++ b/block/blk-mq.h
@@ -22,13 +22,12 @@ struct blk_mq_ctx {
struct kobject kobj;
};
-void __blk_mq_end_io(struct request *rq, int error);
-void blk_mq_complete_request(struct request *rq, int error);
-void blk_mq_run_request(struct request *rq, bool run_queue, bool async);
+void __blk_mq_complete_request(struct request *rq);
void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async);
void blk_mq_init_flush(struct request_queue *q);
void blk_mq_drain_queue(struct request_queue *q);
void blk_mq_free_queue(struct request_queue *q);
+void blk_mq_rq_init(struct blk_mq_hw_ctx *hctx, struct request *rq);
/*
* CPU hotplug helpers
@@ -40,6 +39,8 @@ void blk_mq_init_cpu_notifier(struct blk_mq_cpu_notifier *notifier,
void blk_mq_register_cpu_notifier(struct blk_mq_cpu_notifier *notifier);
void blk_mq_unregister_cpu_notifier(struct blk_mq_cpu_notifier *notifier);
void blk_mq_cpu_init(void);
+void blk_mq_enable_hotplug(void);
+void blk_mq_disable_hotplug(void);
/*
* CPU -> queue mappings
diff --git a/block/blk-softirq.c b/block/blk-softirq.c
index 57790c1a97eb..ebd6b6f1bdeb 100644
--- a/block/blk-softirq.c
+++ b/block/blk-softirq.c
@@ -30,8 +30,8 @@ static void blk_done_softirq(struct softirq_action *h)
while (!list_empty(&local_list)) {
struct request *rq;
- rq = list_entry(local_list.next, struct request, csd.list);
- list_del_init(&rq->csd.list);
+ rq = list_entry(local_list.next, struct request, queuelist);
+ list_del_init(&rq->queuelist);
rq->q->softirq_done_fn(rq);
}
}
@@ -45,9 +45,14 @@ static void trigger_softirq(void *data)
local_irq_save(flags);
list = this_cpu_ptr(&blk_cpu_done);
- list_add_tail(&rq->csd.list, list);
+ /*
+ * We reuse queuelist for a list of requests to process. Since the
+ * queuelist is used by the block layer only for requests waiting to be
+ * submitted to the device it is unused now.
+ */
+ list_add_tail(&rq->queuelist, list);
- if (list->next == &rq->csd.list)
+ if (list->next == &rq->queuelist)
raise_softirq_irqoff(BLOCK_SOFTIRQ);
local_irq_restore(flags);
@@ -65,7 +70,7 @@ static int raise_blk_irq(int cpu, struct request *rq)
data->info = rq;
data->flags = 0;
- __smp_call_function_single(cpu, data, 0);
+ smp_call_function_single_async(cpu, data);
return 0;
}
@@ -136,7 +141,7 @@ void __blk_complete_request(struct request *req)
struct list_head *list;
do_local:
list = this_cpu_ptr(&blk_cpu_done);
- list_add_tail(&req->csd.list, list);
+ list_add_tail(&req->queuelist, list);
/*
* if the list only contains our just added request,
@@ -144,7 +149,7 @@ do_local:
* entries there, someone already raised the irq but it
* hasn't run yet.
*/
- if (list->next == &req->csd.list)
+ if (list->next == &req->queuelist)
raise_softirq_irqoff(BLOCK_SOFTIRQ);
} else if (raise_blk_irq(ccpu, req))
goto do_local;
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index 8095c4a21fc0..7500f876dae4 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -549,6 +549,8 @@ static void blk_release_queue(struct kobject *kobj)
if (q->mq_ops)
blk_mq_free_queue(q);
+ kfree(q->flush_rq);
+
blk_trace_shutdown(q);
bdi_destroy(&q->backing_dev_info);
diff --git a/block/blk-throttle.c b/block/blk-throttle.c
index 1474c3ab7e72..033745cd7fba 100644
--- a/block/blk-throttle.c
+++ b/block/blk-throttle.c
@@ -1408,13 +1408,13 @@ static int tg_set_conf(struct cgroup_subsys_state *css, struct cftype *cft,
}
static int tg_set_conf_u64(struct cgroup_subsys_state *css, struct cftype *cft,
- const char *buf)
+ char *buf)
{
return tg_set_conf(css, cft, buf, true);
}
static int tg_set_conf_uint(struct cgroup_subsys_state *css, struct cftype *cft,
- const char *buf)
+ char *buf)
{
return tg_set_conf(css, cft, buf, false);
}
@@ -1425,28 +1425,24 @@ static struct cftype throtl_files[] = {
.private = offsetof(struct throtl_grp, bps[READ]),
.seq_show = tg_print_conf_u64,
.write_string = tg_set_conf_u64,
- .max_write_len = 256,
},
{
.name = "throttle.write_bps_device",
.private = offsetof(struct throtl_grp, bps[WRITE]),
.seq_show = tg_print_conf_u64,
.write_string = tg_set_conf_u64,
- .max_write_len = 256,
},
{
.name = "throttle.read_iops_device",
.private = offsetof(struct throtl_grp, iops[READ]),
.seq_show = tg_print_conf_uint,
.write_string = tg_set_conf_uint,
- .max_write_len = 256,
},
{
.name = "throttle.write_iops_device",
.private = offsetof(struct throtl_grp, iops[WRITE]),
.seq_show = tg_print_conf_uint,
.write_string = tg_set_conf_uint,
- .max_write_len = 256,
},
{
.name = "throttle.io_service_bytes",
diff --git a/block/blk-timeout.c b/block/blk-timeout.c
index bba81c9348e1..d96f7061c6fd 100644
--- a/block/blk-timeout.c
+++ b/block/blk-timeout.c
@@ -91,7 +91,7 @@ static void blk_rq_timed_out(struct request *req)
case BLK_EH_HANDLED:
/* Can we use req->errors here? */
if (q->mq_ops)
- blk_mq_complete_request(req, req->errors);
+ __blk_mq_complete_request(req);
else
__blk_complete_request(req);
break;
diff --git a/block/blk.h b/block/blk.h
index c90e1d8f7a2b..d23b415b8a28 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -113,7 +113,7 @@ static inline struct request *__elv_next_request(struct request_queue *q)
q->flush_queue_delayed = 1;
return NULL;
}
- if (unlikely(blk_queue_dying(q)) ||
+ if (unlikely(blk_queue_bypass(q)) ||
!q->elevator->type->ops.elevator_dispatch_fn(q, 0))
return NULL;
}
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 744833b630c6..e0985f1955e7 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -1701,13 +1701,13 @@ static int __cfqg_set_weight_device(struct cgroup_subsys_state *css,
}
static int cfqg_set_weight_device(struct cgroup_subsys_state *css,
- struct cftype *cft, const char *buf)
+ struct cftype *cft, char *buf)
{
return __cfqg_set_weight_device(css, cft, buf, false);
}
static int cfqg_set_leaf_weight_device(struct cgroup_subsys_state *css,
- struct cftype *cft, const char *buf)
+ struct cftype *cft, char *buf)
{
return __cfqg_set_weight_device(css, cft, buf, true);
}
@@ -1838,7 +1838,6 @@ static struct cftype cfq_blkcg_files[] = {
.flags = CFTYPE_ONLY_ON_ROOT,
.seq_show = cfqg_print_leaf_weight_device,
.write_string = cfqg_set_leaf_weight_device,
- .max_write_len = 256,
},
{
.name = "weight",
@@ -1853,7 +1852,6 @@ static struct cftype cfq_blkcg_files[] = {
.flags = CFTYPE_NOT_ON_ROOT,
.seq_show = cfqg_print_weight_device,
.write_string = cfqg_set_weight_device,
- .max_write_len = 256,
},
{
.name = "weight",
@@ -1866,7 +1864,6 @@ static struct cftype cfq_blkcg_files[] = {
.name = "leaf_weight_device",
.seq_show = cfqg_print_leaf_weight_device,
.write_string = cfqg_set_leaf_weight_device,
- .max_write_len = 256,
},
{
.name = "leaf_weight",
@@ -2367,10 +2364,10 @@ cfq_merged_requests(struct request_queue *q, struct request *rq,
* reposition in fifo if next is older than rq
*/
if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist) &&
- time_before(rq_fifo_time(next), rq_fifo_time(rq)) &&
+ time_before(next->fifo_time, rq->fifo_time) &&
cfqq == RQ_CFQQ(next)) {
list_move(&rq->queuelist, &next->queuelist);
- rq_set_fifo_time(rq, rq_fifo_time(next));
+ rq->fifo_time = next->fifo_time;
}
if (cfqq->next_rq == next)
@@ -2814,7 +2811,7 @@ static struct request *cfq_check_fifo(struct cfq_queue *cfqq)
return NULL;
rq = rq_entry_fifo(cfqq->fifo.next);
- if (time_before(jiffies, rq_fifo_time(rq)))
+ if (time_before(jiffies, rq->fifo_time))
rq = NULL;
cfq_log_cfqq(cfqq->cfqd, cfqq, "fifo=%p", rq);
@@ -3927,7 +3924,7 @@ static void cfq_insert_request(struct request_queue *q, struct request *rq)
cfq_log_cfqq(cfqd, cfqq, "insert_request");
cfq_init_prio_data(cfqq, RQ_CIC(rq));
- rq_set_fifo_time(rq, jiffies + cfqd->cfq_fifo_expire[rq_is_sync(rq)]);
+ rq->fifo_time = jiffies + cfqd->cfq_fifo_expire[rq_is_sync(rq)];
list_add_tail(&rq->queuelist, &cfqq->fifo);
cfq_add_rq_rb(rq);
cfqg_stats_update_io_add(RQ_CFQG(rq), cfqd->serving_group,
diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c
index 9ef66406c625..a753df2b3fc2 100644
--- a/block/deadline-iosched.c
+++ b/block/deadline-iosched.c
@@ -106,7 +106,7 @@ deadline_add_request(struct request_queue *q, struct request *rq)
/*
* set expire time and add to fifo list
*/
- rq_set_fifo_time(rq, jiffies + dd->fifo_expire[data_dir]);
+ rq->fifo_time = jiffies + dd->fifo_expire[data_dir];
list_add_tail(&rq->queuelist, &dd->fifo_list[data_dir]);
}
@@ -174,9 +174,9 @@ deadline_merged_requests(struct request_queue *q, struct request *req,
* and move into next position (next will be deleted) in fifo
*/
if (!list_empty(&req->queuelist) && !list_empty(&next->queuelist)) {
- if (time_before(rq_fifo_time(next), rq_fifo_time(req))) {
+ if (time_before(next->fifo_time, req->fifo_time)) {
list_move(&req->queuelist, &next->queuelist);
- rq_set_fifo_time(req, rq_fifo_time(next));
+ req->fifo_time = next->fifo_time;
}
}
@@ -230,7 +230,7 @@ static inline int deadline_check_fifo(struct deadline_data *dd, int ddir)
/*
* rq is expired!
*/
- if (time_after_eq(jiffies, rq_fifo_time(rq)))
+ if (time_after_eq(jiffies, rq->fifo_time))
return 1;
return 0;
diff --git a/block/partitions/atari.h b/block/partitions/atari.h
index fe2d32a89f36..f2ec43bfeec1 100644
--- a/block/partitions/atari.h
+++ b/block/partitions/atari.h
@@ -11,6 +11,8 @@
* by Guenther Kelleter (guenther@pool.informatik.rwth-aachen.de)
*/
+#include <linux/compiler.h>
+
struct partition_info
{
u8 flg; /* bit 0: active; bit 7: bootable */
@@ -29,6 +31,6 @@ struct rootsector
u32 bsl_st; /* start of bad sector list */
u32 bsl_cnt; /* length of bad sector list */
u16 checksum; /* checksum for bootable disks */
-} __attribute__((__packed__));
+} __packed;
int atari_partition(struct parsed_partitions *state);
diff --git a/block/partitions/efi.h b/block/partitions/efi.h
index 4efcafba7e64..abd0b19288a6 100644
--- a/block/partitions/efi.h
+++ b/block/partitions/efi.h
@@ -32,6 +32,7 @@
#include <linux/major.h>
#include <linux/string.h>
#include <linux/efi.h>
+#include <linux/compiler.h>
#define MSDOS_MBR_SIGNATURE 0xaa55
#define EFI_PMBR_OSTYPE_EFI 0xEF
@@ -87,13 +88,13 @@ typedef struct _gpt_header {
*
* uint8_t reserved2[ BlockSize - 92 ];
*/
-} __attribute__ ((packed)) gpt_header;
+} __packed gpt_header;
typedef struct _gpt_entry_attributes {
u64 required_to_function:1;
u64 reserved:47;
u64 type_guid_specific:16;
-} __attribute__ ((packed)) gpt_entry_attributes;
+} __packed gpt_entry_attributes;
typedef struct _gpt_entry {
efi_guid_t partition_type_guid;
@@ -102,7 +103,7 @@ typedef struct _gpt_entry {
__le64 ending_lba;
gpt_entry_attributes attributes;
efi_char16_t partition_name[72 / sizeof (efi_char16_t)];
-} __attribute__ ((packed)) gpt_entry;
+} __packed gpt_entry;
typedef struct _gpt_mbr_record {
u8 boot_indicator; /* unused by EFI, set to 0x80 for bootable */
@@ -124,7 +125,7 @@ typedef struct _legacy_mbr {
__le16 unknown;
gpt_mbr_record partition_record[4];
__le16 signature;
-} __attribute__ ((packed)) legacy_mbr;
+} __packed legacy_mbr;
/* Functions */
extern int efi_partition(struct parsed_partitions *state);
diff --git a/block/partitions/karma.c b/block/partitions/karma.c
index 0ea19312706b..9721fa589bb1 100644
--- a/block/partitions/karma.c
+++ b/block/partitions/karma.c
@@ -8,6 +8,7 @@
#include "check.h"
#include "karma.h"
+#include <linux/compiler.h>
int karma_partition(struct parsed_partitions *state)
{
@@ -26,7 +27,7 @@ int karma_partition(struct parsed_partitions *state)
} d_partitions[2];
u8 d_blank[208];
__le16 d_magic;
- } __attribute__((packed)) *label;
+ } __packed *label;
struct d_partition *p;
data = read_part_sector(state, 0, &sect);
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 7bcb70d216e1..ce4012a58781 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -491,14 +491,14 @@ config CRYPTO_SHA1
SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
config CRYPTO_SHA1_SSSE3
- tristate "SHA1 digest algorithm (SSSE3/AVX)"
+ tristate "SHA1 digest algorithm (SSSE3/AVX/AVX2)"
depends on X86 && 64BIT
select CRYPTO_SHA1
select CRYPTO_HASH
help
SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented
using Supplemental SSE3 (SSSE3) instructions or Advanced Vector
- Extensions (AVX), when available.
+ Extensions (AVX/AVX2), when available.
config CRYPTO_SHA256_SSSE3
tristate "SHA256 digest algorithm (SSSE3/AVX/AVX2)"
diff --git a/crypto/Makefile b/crypto/Makefile
index b29402a7b9b5..38e64231dcd3 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -81,7 +81,7 @@ obj-$(CONFIG_CRYPTO_SALSA20) += salsa20_generic.o
obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
obj-$(CONFIG_CRYPTO_ZLIB) += zlib.o
obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
-obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
+obj-$(CONFIG_CRYPTO_CRC32C) += crc32c_generic.o
obj-$(CONFIG_CRYPTO_CRC32) += crc32.o
obj-$(CONFIG_CRYPTO_CRCT10DIF) += crct10dif_common.o crct10dif_generic.o
obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o
diff --git a/crypto/ahash.c b/crypto/ahash.c
index a92dc382f781..6e7223392e80 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -190,6 +190,75 @@ static inline unsigned int ahash_align_buffer_size(unsigned len,
return len + (mask & ~(crypto_tfm_ctx_alignment() - 1));
}
+static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ unsigned long alignmask = crypto_ahash_alignmask(tfm);
+ unsigned int ds = crypto_ahash_digestsize(tfm);
+ struct ahash_request_priv *priv;
+
+ priv = kmalloc(sizeof(*priv) + ahash_align_buffer_size(ds, alignmask),
+ (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+ GFP_KERNEL : GFP_ATOMIC);
+ if (!priv)
+ return -ENOMEM;
+
+ /*
+ * WARNING: Voodoo programming below!
+ *
+ * The code below is obscure and hard to understand, thus explanation
+ * is necessary. See include/crypto/hash.h and include/linux/crypto.h
+ * to understand the layout of structures used here!
+ *
+ * The code here will replace portions of the ORIGINAL request with
+ * pointers to new code and buffers so the hashing operation can store
+ * the result in aligned buffer. We will call the modified request
+ * an ADJUSTED request.
+ *
+ * The newly mangled request will look as such:
+ *
+ * req {
+ * .result = ADJUSTED[new aligned buffer]
+ * .base.complete = ADJUSTED[pointer to completion function]
+ * .base.data = ADJUSTED[*req (pointer to self)]
+ * .priv = ADJUSTED[new priv] {
+ * .result = ORIGINAL(result)
+ * .complete = ORIGINAL(base.complete)
+ * .data = ORIGINAL(base.data)
+ * }
+ */
+
+ priv->result = req->result;
+ priv->complete = req->base.complete;
+ priv->data = req->base.data;
+ /*
+ * WARNING: We do not backup req->priv here! The req->priv
+ * is for internal use of the Crypto API and the
+ * user must _NOT_ _EVER_ depend on it's content!
+ */
+
+ req->result = PTR_ALIGN((u8 *)priv->ubuf, alignmask + 1);
+ req->base.complete = cplt;
+ req->base.data = req;
+ req->priv = priv;
+
+ return 0;
+}
+
+static void ahash_restore_req(struct ahash_request *req)
+{
+ struct ahash_request_priv *priv = req->priv;
+
+ /* Restore the original crypto request. */
+ req->result = priv->result;
+ req->base.complete = priv->complete;
+ req->base.data = priv->data;
+ req->priv = NULL;
+
+ /* Free the req->priv.priv from the ADJUSTED request. */
+ kzfree(priv);
+}
+
static void ahash_op_unaligned_finish(struct ahash_request *req, int err)
{
struct ahash_request_priv *priv = req->priv;
@@ -201,47 +270,37 @@ static void ahash_op_unaligned_finish(struct ahash_request *req, int err)
memcpy(priv->result, req->result,
crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
- kzfree(priv);
+ ahash_restore_req(req);
}
static void ahash_op_unaligned_done(struct crypto_async_request *req, int err)
{
struct ahash_request *areq = req->data;
- struct ahash_request_priv *priv = areq->priv;
- crypto_completion_t complete = priv->complete;
- void *data = priv->data;
- ahash_op_unaligned_finish(areq, err);
+ /*
+ * Restore the original request, see ahash_op_unaligned() for what
+ * goes where.
+ *
+ * The "struct ahash_request *req" here is in fact the "req.base"
+ * from the ADJUSTED request from ahash_op_unaligned(), thus as it
+ * is a pointer to self, it is also the ADJUSTED "req" .
+ */
- areq->base.complete = complete;
- areq->base.data = data;
+ /* First copy req->result into req->priv.result */
+ ahash_op_unaligned_finish(areq, err);
- complete(&areq->base, err);
+ /* Complete the ORIGINAL request. */
+ areq->base.complete(&areq->base, err);
}
static int ahash_op_unaligned(struct ahash_request *req,
int (*op)(struct ahash_request *))
{
- struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
- unsigned long alignmask = crypto_ahash_alignmask(tfm);
- unsigned int ds = crypto_ahash_digestsize(tfm);
- struct ahash_request_priv *priv;
int err;
- priv = kmalloc(sizeof(*priv) + ahash_align_buffer_size(ds, alignmask),
- (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
- GFP_KERNEL : GFP_ATOMIC);
- if (!priv)
- return -ENOMEM;
-
- priv->result = req->result;
- priv->complete = req->base.complete;
- priv->data = req->base.data;
-
- req->result = PTR_ALIGN((u8 *)priv->ubuf, alignmask + 1);
- req->base.complete = ahash_op_unaligned_done;
- req->base.data = req;
- req->priv = priv;
+ err = ahash_save_req(req, ahash_op_unaligned_done);
+ if (err)
+ return err;
err = op(req);
ahash_op_unaligned_finish(req, err);
@@ -290,19 +349,16 @@ static void ahash_def_finup_finish2(struct ahash_request *req, int err)
memcpy(priv->result, req->result,
crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
- kzfree(priv);
+ ahash_restore_req(req);
}
static void ahash_def_finup_done2(struct crypto_async_request *req, int err)
{
struct ahash_request *areq = req->data;
- struct ahash_request_priv *priv = areq->priv;
- crypto_completion_t complete = priv->complete;
- void *data = priv->data;
ahash_def_finup_finish2(areq, err);
- complete(data, err);
+ areq->base.complete(&areq->base, err);
}
static int ahash_def_finup_finish1(struct ahash_request *req, int err)
@@ -322,38 +378,23 @@ out:
static void ahash_def_finup_done1(struct crypto_async_request *req, int err)
{
struct ahash_request *areq = req->data;
- struct ahash_request_priv *priv = areq->priv;
- crypto_completion_t complete = priv->complete;
- void *data = priv->data;
err = ahash_def_finup_finish1(areq, err);
- complete(data, err);
+ areq->base.complete(&areq->base, err);
}
static int ahash_def_finup(struct ahash_request *req)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
- unsigned long alignmask = crypto_ahash_alignmask(tfm);
- unsigned int ds = crypto_ahash_digestsize(tfm);
- struct ahash_request_priv *priv;
-
- priv = kmalloc(sizeof(*priv) + ahash_align_buffer_size(ds, alignmask),
- (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
- GFP_KERNEL : GFP_ATOMIC);
- if (!priv)
- return -ENOMEM;
-
- priv->result = req->result;
- priv->complete = req->base.complete;
- priv->data = req->base.data;
+ int err;
- req->result = PTR_ALIGN((u8 *)priv->ubuf, alignmask + 1);
- req->base.complete = ahash_def_finup_done1;
- req->base.data = req;
- req->priv = priv;
+ err = ahash_save_req(req, ahash_def_finup_done1);
+ if (err)
+ return err;
- return ahash_def_finup_finish1(req, tfm->update(req));
+ err = tfm->update(req);
+ return ahash_def_finup_finish1(req, err);
}
static int ahash_no_export(struct ahash_request *req, void *out)
diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c
index a79e7e9ab86e..0122bec38564 100644
--- a/crypto/blkcipher.c
+++ b/crypto/blkcipher.c
@@ -70,14 +70,12 @@ static inline u8 *blkcipher_get_spot(u8 *start, unsigned int len)
return max(start, end_page);
}
-static inline unsigned int blkcipher_done_slow(struct crypto_blkcipher *tfm,
- struct blkcipher_walk *walk,
+static inline unsigned int blkcipher_done_slow(struct blkcipher_walk *walk,
unsigned int bsize)
{
u8 *addr;
- unsigned int alignmask = crypto_blkcipher_alignmask(tfm);
- addr = (u8 *)ALIGN((unsigned long)walk->buffer, alignmask + 1);
+ addr = (u8 *)ALIGN((unsigned long)walk->buffer, walk->alignmask + 1);
addr = blkcipher_get_spot(addr, bsize);
scatterwalk_copychunks(addr, &walk->out, bsize, 1);
return bsize;
@@ -105,7 +103,6 @@ static inline unsigned int blkcipher_done_fast(struct blkcipher_walk *walk,
int blkcipher_walk_done(struct blkcipher_desc *desc,
struct blkcipher_walk *walk, int err)
{
- struct crypto_blkcipher *tfm = desc->tfm;
unsigned int nbytes = 0;
if (likely(err >= 0)) {
@@ -117,7 +114,7 @@ int blkcipher_walk_done(struct blkcipher_desc *desc,
err = -EINVAL;
goto err;
} else
- n = blkcipher_done_slow(tfm, walk, n);
+ n = blkcipher_done_slow(walk, n);
nbytes = walk->total - n;
err = 0;
@@ -136,7 +133,7 @@ err:
}
if (walk->iv != desc->info)
- memcpy(desc->info, walk->iv, crypto_blkcipher_ivsize(tfm));
+ memcpy(desc->info, walk->iv, walk->ivsize);
if (walk->buffer != walk->page)
kfree(walk->buffer);
if (walk->page)
@@ -226,22 +223,20 @@ static inline int blkcipher_next_fast(struct blkcipher_desc *desc,
static int blkcipher_walk_next(struct blkcipher_desc *desc,
struct blkcipher_walk *walk)
{
- struct crypto_blkcipher *tfm = desc->tfm;
- unsigned int alignmask = crypto_blkcipher_alignmask(tfm);
unsigned int bsize;
unsigned int n;
int err;
n = walk->total;
- if (unlikely(n < crypto_blkcipher_blocksize(tfm))) {
+ if (unlikely(n < walk->cipher_blocksize)) {
desc->flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
return blkcipher_walk_done(desc, walk, -EINVAL);
}
walk->flags &= ~(BLKCIPHER_WALK_SLOW | BLKCIPHER_WALK_COPY |
BLKCIPHER_WALK_DIFF);
- if (!scatterwalk_aligned(&walk->in, alignmask) ||
- !scatterwalk_aligned(&walk->out, alignmask)) {
+ if (!scatterwalk_aligned(&walk->in, walk->alignmask) ||
+ !scatterwalk_aligned(&walk->out, walk->alignmask)) {
walk->flags |= BLKCIPHER_WALK_COPY;
if (!walk->page) {
walk->page = (void *)__get_free_page(GFP_ATOMIC);
@@ -250,12 +245,12 @@ static int blkcipher_walk_next(struct blkcipher_desc *desc,
}
}
- bsize = min(walk->blocksize, n);
+ bsize = min(walk->walk_blocksize, n);
n = scatterwalk_clamp(&walk->in, n);
n = scatterwalk_clamp(&walk->out, n);
if (unlikely(n < bsize)) {
- err = blkcipher_next_slow(desc, walk, bsize, alignmask);
+ err = blkcipher_next_slow(desc, walk, bsize, walk->alignmask);
goto set_phys_lowmem;
}
@@ -277,28 +272,26 @@ set_phys_lowmem:
return err;
}
-static inline int blkcipher_copy_iv(struct blkcipher_walk *walk,
- struct crypto_blkcipher *tfm,
- unsigned int alignmask)
+static inline int blkcipher_copy_iv(struct blkcipher_walk *walk)
{
- unsigned bs = walk->blocksize;
- unsigned int ivsize = crypto_blkcipher_ivsize(tfm);
- unsigned aligned_bs = ALIGN(bs, alignmask + 1);
- unsigned int size = aligned_bs * 2 + ivsize + max(aligned_bs, ivsize) -
- (alignmask + 1);
+ unsigned bs = walk->walk_blocksize;
+ unsigned aligned_bs = ALIGN(bs, walk->alignmask + 1);
+ unsigned int size = aligned_bs * 2 +
+ walk->ivsize + max(aligned_bs, walk->ivsize) -
+ (walk->alignmask + 1);
u8 *iv;
- size += alignmask & ~(crypto_tfm_ctx_alignment() - 1);
+ size += walk->alignmask & ~(crypto_tfm_ctx_alignment() - 1);
walk->buffer = kmalloc(size, GFP_ATOMIC);
if (!walk->buffer)
return -ENOMEM;
- iv = (u8 *)ALIGN((unsigned long)walk->buffer, alignmask + 1);
+ iv = (u8 *)ALIGN((unsigned long)walk->buffer, walk->alignmask + 1);
iv = blkcipher_get_spot(iv, bs) + aligned_bs;
iv = blkcipher_get_spot(iv, bs) + aligned_bs;
- iv = blkcipher_get_spot(iv, ivsize);
+ iv = blkcipher_get_spot(iv, walk->ivsize);
- walk->iv = memcpy(iv, walk->iv, ivsize);
+ walk->iv = memcpy(iv, walk->iv, walk->ivsize);
return 0;
}
@@ -306,7 +299,10 @@ int blkcipher_walk_virt(struct blkcipher_desc *desc,
struct blkcipher_walk *walk)
{
walk->flags &= ~BLKCIPHER_WALK_PHYS;
- walk->blocksize = crypto_blkcipher_blocksize(desc->tfm);
+ walk->walk_blocksize = crypto_blkcipher_blocksize(desc->tfm);
+ walk->cipher_blocksize = walk->walk_blocksize;
+ walk->ivsize = crypto_blkcipher_ivsize(desc->tfm);
+ walk->alignmask = crypto_blkcipher_alignmask(desc->tfm);
return blkcipher_walk_first(desc, walk);
}
EXPORT_SYMBOL_GPL(blkcipher_walk_virt);
@@ -315,7 +311,10 @@ int blkcipher_walk_phys(struct blkcipher_desc *desc,
struct blkcipher_walk *walk)
{
walk->flags |= BLKCIPHER_WALK_PHYS;
- walk->blocksize = crypto_blkcipher_blocksize(desc->tfm);
+ walk->walk_blocksize = crypto_blkcipher_blocksize(desc->tfm);
+ walk->cipher_blocksize = walk->walk_blocksize;
+ walk->ivsize = crypto_blkcipher_ivsize(desc->tfm);
+ walk->alignmask = crypto_blkcipher_alignmask(desc->tfm);
return blkcipher_walk_first(desc, walk);
}
EXPORT_SYMBOL_GPL(blkcipher_walk_phys);
@@ -323,9 +322,6 @@ EXPORT_SYMBOL_GPL(blkcipher_walk_phys);
static int blkcipher_walk_first(struct blkcipher_desc *desc,
struct blkcipher_walk *walk)
{
- struct crypto_blkcipher *tfm = desc->tfm;
- unsigned int alignmask = crypto_blkcipher_alignmask(tfm);
-
if (WARN_ON_ONCE(in_irq()))
return -EDEADLK;
@@ -335,8 +331,8 @@ static int blkcipher_walk_first(struct blkcipher_desc *desc,
walk->buffer = NULL;
walk->iv = desc->info;
- if (unlikely(((unsigned long)walk->iv & alignmask))) {
- int err = blkcipher_copy_iv(walk, tfm, alignmask);
+ if (unlikely(((unsigned long)walk->iv & walk->alignmask))) {
+ int err = blkcipher_copy_iv(walk);
if (err)
return err;
}
@@ -353,11 +349,28 @@ int blkcipher_walk_virt_block(struct blkcipher_desc *desc,
unsigned int blocksize)
{
walk->flags &= ~BLKCIPHER_WALK_PHYS;
- walk->blocksize = blocksize;
+ walk->walk_blocksize = blocksize;
+ walk->cipher_blocksize = crypto_blkcipher_blocksize(desc->tfm);
+ walk->ivsize = crypto_blkcipher_ivsize(desc->tfm);
+ walk->alignmask = crypto_blkcipher_alignmask(desc->tfm);
return blkcipher_walk_first(desc, walk);
}
EXPORT_SYMBOL_GPL(blkcipher_walk_virt_block);
+int blkcipher_aead_walk_virt_block(struct blkcipher_desc *desc,
+ struct blkcipher_walk *walk,
+ struct crypto_aead *tfm,
+ unsigned int blocksize)
+{
+ walk->flags &= ~BLKCIPHER_WALK_PHYS;
+ walk->walk_blocksize = blocksize;
+ walk->cipher_blocksize = crypto_aead_blocksize(tfm);
+ walk->ivsize = crypto_aead_ivsize(tfm);
+ walk->alignmask = crypto_aead_alignmask(tfm);
+ return blkcipher_walk_first(desc, walk);
+}
+EXPORT_SYMBOL_GPL(blkcipher_aead_walk_virt_block);
+
static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key,
unsigned int keylen)
{
diff --git a/crypto/crc32c.c b/crypto/crc32c_generic.c
index 06f7018c9d95..d9c7beba8e50 100644
--- a/crypto/crc32c.c
+++ b/crypto/crc32c_generic.c
@@ -170,3 +170,5 @@ module_exit(crc32c_mod_fini);
MODULE_AUTHOR("Clay Haapala <chaapala@cisco.com>");
MODULE_DESCRIPTION("CRC32c (Castagnoli) calculations wrapper for lib/crc32c");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("crc32c");
+MODULE_SOFTDEP("pre: crc32c");
diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c
index fee7265cd35d..1dc54bb95a87 100644
--- a/crypto/crypto_null.c
+++ b/crypto/crypto_null.c
@@ -17,6 +17,7 @@
*
*/
+#include <crypto/null.h>
#include <crypto/internal/hash.h>
#include <crypto/internal/skcipher.h>
#include <linux/init.h>
@@ -24,11 +25,6 @@
#include <linux/mm.h>
#include <linux/string.h>
-#define NULL_KEY_SIZE 0
-#define NULL_BLOCK_SIZE 1
-#define NULL_DIGEST_SIZE 0
-#define NULL_IV_SIZE 0
-
static int null_compress(struct crypto_tfm *tfm, const u8 *src,
unsigned int slen, u8 *dst, unsigned int *dlen)
{
diff --git a/crypto/crypto_wq.c b/crypto/crypto_wq.c
index adad92a44ba2..2f1b8d12952a 100644
--- a/crypto/crypto_wq.c
+++ b/crypto/crypto_wq.c
@@ -33,7 +33,7 @@ static void __exit crypto_wq_exit(void)
destroy_workqueue(kcrypto_wq);
}
-module_init(crypto_wq_init);
+subsys_initcall(crypto_wq_init);
module_exit(crypto_wq_exit);
MODULE_LICENSE("GPL");
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index 0d9003ae8c61..870be7b4dc05 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -1511,6 +1511,14 @@ static int do_test(int m)
ret += tcrypt_test("authenc(hmac(sha1),cbc(aes))");
break;
+ case 156:
+ ret += tcrypt_test("authenc(hmac(md5),ecb(cipher_null))");
+ break;
+
+ case 157:
+ ret += tcrypt_test("authenc(hmac(sha1),ecb(cipher_null))");
+ break;
+
case 200:
test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0,
speed_template_16_24_32);
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 77955507f6f1..dc3cf3535ef0 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -1809,6 +1809,22 @@ static const struct alg_test_desc alg_test_descs[] = {
}
}
}, {
+ .alg = "authenc(hmac(md5),ecb(cipher_null))",
+ .test = alg_test_aead,
+ .fips_allowed = 1,
+ .suite = {
+ .aead = {
+ .enc = {
+ .vecs = hmac_md5_ecb_cipher_null_enc_tv_template,
+ .count = HMAC_MD5_ECB_CIPHER_NULL_ENC_TEST_VECTORS
+ },
+ .dec = {
+ .vecs = hmac_md5_ecb_cipher_null_dec_tv_template,
+ .count = HMAC_MD5_ECB_CIPHER_NULL_DEC_TEST_VECTORS
+ }
+ }
+ }
+ }, {
.alg = "authenc(hmac(sha1),cbc(aes))",
.test = alg_test_aead,
.fips_allowed = 1,
@@ -1821,6 +1837,22 @@ static const struct alg_test_desc alg_test_descs[] = {
}
}
}, {
+ .alg = "authenc(hmac(sha1),ecb(cipher_null))",
+ .test = alg_test_aead,
+ .fips_allowed = 1,
+ .suite = {
+ .aead = {
+ .enc = {
+ .vecs = hmac_sha1_ecb_cipher_null_enc_tv_template,
+ .count = HMAC_SHA1_ECB_CIPHER_NULL_ENC_TEST_VECTORS
+ },
+ .dec = {
+ .vecs = hmac_sha1_ecb_cipher_null_dec_tv_template,
+ .count = HMAC_SHA1_ECB_CIPHER_NULL_DEC_TEST_VECTORS
+ }
+ }
+ }
+ }, {
.alg = "authenc(hmac(sha256),cbc(aes))",
.test = alg_test_aead,
.fips_allowed = 1,
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 7d44aa3d6b44..3db83dbba1d9 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -12821,6 +12821,10 @@ static struct cipher_testvec cast6_xts_dec_tv_template[] = {
#define AES_DEC_TEST_VECTORS 4
#define AES_CBC_ENC_TEST_VECTORS 5
#define AES_CBC_DEC_TEST_VECTORS 5
+#define HMAC_MD5_ECB_CIPHER_NULL_ENC_TEST_VECTORS 2
+#define HMAC_MD5_ECB_CIPHER_NULL_DEC_TEST_VECTORS 2
+#define HMAC_SHA1_ECB_CIPHER_NULL_ENC_TEST_VECTORS 2
+#define HMAC_SHA1_ECB_CIPHER_NULL_DEC_TEST_VECTORS 2
#define HMAC_SHA1_AES_CBC_ENC_TEST_VECTORS 7
#define HMAC_SHA256_AES_CBC_ENC_TEST_VECTORS 7
#define HMAC_SHA512_AES_CBC_ENC_TEST_VECTORS 7
@@ -13627,6 +13631,90 @@ static struct cipher_testvec aes_cbc_dec_tv_template[] = {
},
};
+static struct aead_testvec hmac_md5_ecb_cipher_null_enc_tv_template[] = {
+ { /* Input data from RFC 2410 Case 1 */
+#ifdef __LITTLE_ENDIAN
+ .key = "\x08\x00" /* rta length */
+ "\x01\x00" /* rta type */
+#else
+ .key = "\x00\x08" /* rta length */
+ "\x00\x01" /* rta type */
+#endif
+ "\x00\x00\x00\x00" /* enc key length */
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .klen = 8 + 16 + 0,
+ .iv = "",
+ .input = "\x01\x23\x45\x67\x89\xab\xcd\xef",
+ .ilen = 8,
+ .result = "\x01\x23\x45\x67\x89\xab\xcd\xef"
+ "\xaa\x42\xfe\x43\x8d\xea\xa3\x5a"
+ "\xb9\x3d\x9f\xb1\xa3\x8e\x9b\xae",
+ .rlen = 8 + 16,
+ }, { /* Input data from RFC 2410 Case 2 */
+#ifdef __LITTLE_ENDIAN
+ .key = "\x08\x00" /* rta length */
+ "\x01\x00" /* rta type */
+#else
+ .key = "\x00\x08" /* rta length */
+ "\x00\x01" /* rta type */
+#endif
+ "\x00\x00\x00\x00" /* enc key length */
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .klen = 8 + 16 + 0,
+ .iv = "",
+ .input = "Network Security People Have A Strange Sense Of Humor",
+ .ilen = 53,
+ .result = "Network Security People Have A Strange Sense Of Humor"
+ "\x73\xa5\x3e\x1c\x08\x0e\x8a\x8a"
+ "\x8e\xb5\x5f\x90\x8e\xfe\x13\x23",
+ .rlen = 53 + 16,
+ },
+};
+
+static struct aead_testvec hmac_md5_ecb_cipher_null_dec_tv_template[] = {
+ {
+#ifdef __LITTLE_ENDIAN
+ .key = "\x08\x00" /* rta length */
+ "\x01\x00" /* rta type */
+#else
+ .key = "\x00\x08" /* rta length */
+ "\x00\x01" /* rta type */
+#endif
+ "\x00\x00\x00\x00" /* enc key length */
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .klen = 8 + 16 + 0,
+ .iv = "",
+ .input = "\x01\x23\x45\x67\x89\xab\xcd\xef"
+ "\xaa\x42\xfe\x43\x8d\xea\xa3\x5a"
+ "\xb9\x3d\x9f\xb1\xa3\x8e\x9b\xae",
+ .ilen = 8 + 16,
+ .result = "\x01\x23\x45\x67\x89\xab\xcd\xef",
+ .rlen = 8,
+ }, {
+#ifdef __LITTLE_ENDIAN
+ .key = "\x08\x00" /* rta length */
+ "\x01\x00" /* rta type */
+#else
+ .key = "\x00\x08" /* rta length */
+ "\x00\x01" /* rta type */
+#endif
+ "\x00\x00\x00\x00" /* enc key length */
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .klen = 8 + 16 + 0,
+ .iv = "",
+ .input = "Network Security People Have A Strange Sense Of Humor"
+ "\x73\xa5\x3e\x1c\x08\x0e\x8a\x8a"
+ "\x8e\xb5\x5f\x90\x8e\xfe\x13\x23",
+ .ilen = 53 + 16,
+ .result = "Network Security People Have A Strange Sense Of Humor",
+ .rlen = 53,
+ },
+};
+
static struct aead_testvec hmac_sha1_aes_cbc_enc_tv_template[] = {
{ /* RFC 3602 Case 1 */
#ifdef __LITTLE_ENDIAN
@@ -13876,6 +13964,98 @@ static struct aead_testvec hmac_sha1_aes_cbc_enc_tv_template[] = {
},
};
+static struct aead_testvec hmac_sha1_ecb_cipher_null_enc_tv_template[] = {
+ { /* Input data from RFC 2410 Case 1 */
+#ifdef __LITTLE_ENDIAN
+ .key = "\x08\x00" /* rta length */
+ "\x01\x00" /* rta type */
+#else
+ .key = "\x00\x08" /* rta length */
+ "\x00\x01" /* rta type */
+#endif
+ "\x00\x00\x00\x00" /* enc key length */
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00",
+ .klen = 8 + 20 + 0,
+ .iv = "",
+ .input = "\x01\x23\x45\x67\x89\xab\xcd\xef",
+ .ilen = 8,
+ .result = "\x01\x23\x45\x67\x89\xab\xcd\xef"
+ "\x40\xc3\x0a\xa1\xc9\xa0\x28\xab"
+ "\x99\x5e\x19\x04\xd1\x72\xef\xb8"
+ "\x8c\x5e\xe4\x08",
+ .rlen = 8 + 20,
+ }, { /* Input data from RFC 2410 Case 2 */
+#ifdef __LITTLE_ENDIAN
+ .key = "\x08\x00" /* rta length */
+ "\x01\x00" /* rta type */
+#else
+ .key = "\x00\x08" /* rta length */
+ "\x00\x01" /* rta type */
+#endif
+ "\x00\x00\x00\x00" /* enc key length */
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00",
+ .klen = 8 + 20 + 0,
+ .iv = "",
+ .input = "Network Security People Have A Strange Sense Of Humor",
+ .ilen = 53,
+ .result = "Network Security People Have A Strange Sense Of Humor"
+ "\x75\x6f\x42\x1e\xf8\x50\x21\xd2"
+ "\x65\x47\xee\x8e\x1a\xef\x16\xf6"
+ "\x91\x56\xe4\xd6",
+ .rlen = 53 + 20,
+ },
+};
+
+static struct aead_testvec hmac_sha1_ecb_cipher_null_dec_tv_template[] = {
+ {
+#ifdef __LITTLE_ENDIAN
+ .key = "\x08\x00" /* rta length */
+ "\x01\x00" /* rta type */
+#else
+ .key = "\x00\x08" /* rta length */
+ "\x00\x01" /* rta type */
+#endif
+ "\x00\x00\x00\x00" /* enc key length */
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00",
+ .klen = 8 + 20 + 0,
+ .iv = "",
+ .input = "\x01\x23\x45\x67\x89\xab\xcd\xef"
+ "\x40\xc3\x0a\xa1\xc9\xa0\x28\xab"
+ "\x99\x5e\x19\x04\xd1\x72\xef\xb8"
+ "\x8c\x5e\xe4\x08",
+ .ilen = 8 + 20,
+ .result = "\x01\x23\x45\x67\x89\xab\xcd\xef",
+ .rlen = 8,
+ }, {
+#ifdef __LITTLE_ENDIAN
+ .key = "\x08\x00" /* rta length */
+ "\x01\x00" /* rta type */
+#else
+ .key = "\x00\x08" /* rta length */
+ "\x00\x01" /* rta type */
+#endif
+ "\x00\x00\x00\x00" /* enc key length */
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00",
+ .klen = 8 + 20 + 0,
+ .iv = "",
+ .input = "Network Security People Have A Strange Sense Of Humor"
+ "\x75\x6f\x42\x1e\xf8\x50\x21\xd2"
+ "\x65\x47\xee\x8e\x1a\xef\x16\xf6"
+ "\x91\x56\xe4\xd6",
+ .ilen = 53 + 20,
+ .result = "Network Security People Have A Strange Sense Of Humor",
+ .rlen = 53,
+ },
+};
+
static struct aead_testvec hmac_sha256_aes_cbc_enc_tv_template[] = {
{ /* RFC 3602 Case 1 */
#ifdef __LITTLE_ENDIAN
diff --git a/drivers/Kconfig b/drivers/Kconfig
index b3138fbb46a4..0a0a90f52d26 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -52,6 +52,8 @@ source "drivers/i2c/Kconfig"
source "drivers/spi/Kconfig"
+source "drivers/spmi/Kconfig"
+
source "drivers/hsi/Kconfig"
source "drivers/pps/Kconfig"
@@ -170,4 +172,6 @@ source "drivers/phy/Kconfig"
source "drivers/powercap/Kconfig"
+source "drivers/mcb/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 8e3b8b06c0b2..e3ced91b1784 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_ATA) += ata/
obj-$(CONFIG_TARGET_CORE) += target/
obj-$(CONFIG_MTD) += mtd/
obj-$(CONFIG_SPI) += spi/
+obj-$(CONFIG_SPMI) += spmi/
obj-y += hsi/
obj-y += net/
obj-$(CONFIG_ATM) += atm/
@@ -155,3 +156,4 @@ obj-$(CONFIG_IPACK_BUS) += ipack/
obj-$(CONFIG_NTB) += ntb/
obj-$(CONFIG_FMC) += fmc/
obj-$(CONFIG_POWERCAP) += powercap/
+obj-$(CONFIG_MCB) += mcb/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 4770de5707b9..c205653e9644 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -43,19 +43,6 @@ config ACPI_SLEEP
depends on SUSPEND || HIBERNATION
default y
-config ACPI_PROCFS
- bool "Deprecated /proc/acpi files"
- depends on PROC_FS
- help
- For backwards compatibility, this option allows
- deprecated /proc/acpi/ files to exist, even when
- they have been replaced by functions in /sys.
-
- This option has no effect on /proc/acpi/ files
- and functions which do not yet exist in /sys.
-
- Say N to delete /proc/acpi/ files that have moved to /sys/
-
config ACPI_EC_DEBUGFS
tristate "EC read/write access through /sys/kernel/debug/ec"
default n
@@ -115,7 +102,7 @@ config ACPI_BUTTON
config ACPI_VIDEO
tristate "Video"
- depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL
+ depends on X86 && BACKLIGHT_CLASS_DEVICE
depends on INPUT
select THERMAL
help
@@ -343,6 +330,19 @@ config ACPI_BGRT
data from the firmware boot splash. It will appear under
/sys/firmware/acpi/bgrt/ .
+config ACPI_REDUCED_HARDWARE_ONLY
+ bool "Hardware-reduced ACPI support only" if EXPERT
+ def_bool n
+ depends on ACPI
+ help
+ This config item changes the way the ACPI code is built. When this
+ option is selected, the kernel will use a specialized version of
+ ACPICA that ONLY supports the ACPI "reduced hardware" mode. The
+ resulting kernel will be smaller but it will also be restricted to
+ running in ACPI reduced hardware mode ONLY.
+
+ If you are unsure what to do, do not enable this option.
+
source "drivers/acpi/apei/Kconfig"
config ACPI_EXTLOG
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index e7515aa43d6b..2c01c1da29ce 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -33,6 +33,7 @@
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/acpi.h>
+#include "battery.h"
#define PREFIX "ACPI: "
@@ -57,6 +58,7 @@ struct acpi_ac {
struct power_supply charger;
struct platform_device *pdev;
unsigned long long state;
+ struct notifier_block battery_nb;
};
#define to_acpi_ac(x) container_of(x, struct acpi_ac, charger)
@@ -152,6 +154,26 @@ static void acpi_ac_notify_handler(acpi_handle handle, u32 event, void *data)
return;
}
+static int acpi_ac_battery_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct acpi_ac *ac = container_of(nb, struct acpi_ac, battery_nb);
+ struct acpi_bus_event *event = (struct acpi_bus_event *)data;
+
+ /*
+ * On HP Pavilion dv6-6179er AC status notifications aren't triggered
+ * when adapter is plugged/unplugged. However, battery status
+ * notifcations are triggered when battery starts charging or
+ * discharging. Re-reading AC status triggers lost AC notifications,
+ * if AC status has changed.
+ */
+ if (strcmp(event->device_class, ACPI_BATTERY_CLASS) == 0 &&
+ event->type == ACPI_BATTERY_NOTIFY_STATUS)
+ acpi_ac_get_state(ac);
+
+ return NOTIFY_OK;
+}
+
static int thinkpad_e530_quirk(const struct dmi_system_id *d)
{
ac_sleep_before_get_state_ms = 1000;
@@ -215,6 +237,8 @@ static int acpi_ac_probe(struct platform_device *pdev)
acpi_device_name(adev), acpi_device_bid(adev),
ac->state ? "on-line" : "off-line");
+ ac->battery_nb.notifier_call = acpi_ac_battery_notify;
+ register_acpi_notifier(&ac->battery_nb);
end:
if (result)
kfree(ac);
@@ -243,6 +267,8 @@ static int acpi_ac_resume(struct device *dev)
kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
return 0;
}
+#else
+#define acpi_ac_resume NULL
#endif
static SIMPLE_DEV_PM_OPS(acpi_ac_pm_ops, NULL, acpi_ac_resume);
@@ -259,6 +285,7 @@ static int acpi_ac_remove(struct platform_device *pdev)
ac = platform_get_drvdata(pdev);
if (ac->charger.dev)
power_supply_unregister(&ac->charger);
+ unregister_acpi_notifier(&ac->battery_nb);
kfree(ac);
diff --git a/drivers/acpi/acpi_cmos_rtc.c b/drivers/acpi/acpi_cmos_rtc.c
index 84190ed89c04..961b45d18a5d 100644
--- a/drivers/acpi/acpi_cmos_rtc.c
+++ b/drivers/acpi/acpi_cmos_rtc.c
@@ -18,8 +18,6 @@
#include "internal.h"
-#define PREFIX "ACPI: "
-
ACPI_MODULE_NAME("cmos rtc");
static const struct acpi_device_id acpi_cmos_rtc_ids[] = {
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index 6745fe137b9e..69e29f409d4c 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -33,6 +33,13 @@ ACPI_MODULE_NAME("acpi_lpss");
#define LPSS_GENERAL_UART_RTS_OVRD BIT(3)
#define LPSS_SW_LTR 0x10
#define LPSS_AUTO_LTR 0x14
+#define LPSS_LTR_SNOOP_REQ BIT(15)
+#define LPSS_LTR_SNOOP_MASK 0x0000FFFF
+#define LPSS_LTR_SNOOP_LAT_1US 0x800
+#define LPSS_LTR_SNOOP_LAT_32US 0xC00
+#define LPSS_LTR_SNOOP_LAT_SHIFT 5
+#define LPSS_LTR_SNOOP_LAT_CUTOFF 3000
+#define LPSS_LTR_MAX_VAL 0x3FF
#define LPSS_TX_INT 0x20
#define LPSS_TX_INT_MASK BIT(1)
@@ -102,6 +109,16 @@ static struct lpss_device_desc lpt_sdio_dev_desc = {
.ltr_required = true,
};
+static struct lpss_shared_clock pwm_clock = {
+ .name = "pwm_clk",
+ .rate = 25000000,
+};
+
+static struct lpss_device_desc byt_pwm_dev_desc = {
+ .clk_required = true,
+ .shared_clock = &pwm_clock,
+};
+
static struct lpss_shared_clock uart_clock = {
.name = "uart_clk",
.rate = 44236800,
@@ -157,6 +174,7 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {
{ "INT33C7", },
/* BayTrail LPSS devices */
+ { "80860F09", (unsigned long)&byt_pwm_dev_desc },
{ "80860F0A", (unsigned long)&byt_uart_dev_desc },
{ "80860F0E", (unsigned long)&byt_spi_dev_desc },
{ "80860F14", (unsigned long)&byt_sdio_dev_desc },
@@ -315,6 +333,17 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
return ret;
}
+static u32 __lpss_reg_read(struct lpss_private_data *pdata, unsigned int reg)
+{
+ return readl(pdata->mmio_base + pdata->dev_desc->prv_offset + reg);
+}
+
+static void __lpss_reg_write(u32 val, struct lpss_private_data *pdata,
+ unsigned int reg)
+{
+ writel(val, pdata->mmio_base + pdata->dev_desc->prv_offset + reg);
+}
+
static int lpss_reg_read(struct device *dev, unsigned int reg, u32 *val)
{
struct acpi_device *adev;
@@ -336,7 +365,7 @@ static int lpss_reg_read(struct device *dev, unsigned int reg, u32 *val)
ret = -ENODEV;
goto out;
}
- *val = readl(pdata->mmio_base + pdata->dev_desc->prv_offset + reg);
+ *val = __lpss_reg_read(pdata, reg);
out:
spin_unlock_irqrestore(&dev->power.lock, flags);
@@ -389,6 +418,37 @@ static struct attribute_group lpss_attr_group = {
.name = "lpss_ltr",
};
+static void acpi_lpss_set_ltr(struct device *dev, s32 val)
+{
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ u32 ltr_mode, ltr_val;
+
+ ltr_mode = __lpss_reg_read(pdata, LPSS_GENERAL);
+ if (val < 0) {
+ if (ltr_mode & LPSS_GENERAL_LTR_MODE_SW) {
+ ltr_mode &= ~LPSS_GENERAL_LTR_MODE_SW;
+ __lpss_reg_write(ltr_mode, pdata, LPSS_GENERAL);
+ }
+ return;
+ }
+ ltr_val = __lpss_reg_read(pdata, LPSS_SW_LTR) & ~LPSS_LTR_SNOOP_MASK;
+ if (val >= LPSS_LTR_SNOOP_LAT_CUTOFF) {
+ ltr_val |= LPSS_LTR_SNOOP_LAT_32US;
+ val = LPSS_LTR_MAX_VAL;
+ } else if (val > LPSS_LTR_MAX_VAL) {
+ ltr_val |= LPSS_LTR_SNOOP_LAT_32US | LPSS_LTR_SNOOP_REQ;
+ val >>= LPSS_LTR_SNOOP_LAT_SHIFT;
+ } else {
+ ltr_val |= LPSS_LTR_SNOOP_LAT_1US | LPSS_LTR_SNOOP_REQ;
+ }
+ ltr_val |= val;
+ __lpss_reg_write(ltr_val, pdata, LPSS_SW_LTR);
+ if (!(ltr_mode & LPSS_GENERAL_LTR_MODE_SW)) {
+ ltr_mode |= LPSS_GENERAL_LTR_MODE_SW;
+ __lpss_reg_write(ltr_mode, pdata, LPSS_GENERAL);
+ }
+}
+
static int acpi_lpss_platform_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
@@ -426,9 +486,29 @@ static struct notifier_block acpi_lpss_nb = {
.notifier_call = acpi_lpss_platform_notify,
};
+static void acpi_lpss_bind(struct device *dev)
+{
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+
+ if (!pdata || !pdata->mmio_base || !pdata->dev_desc->ltr_required)
+ return;
+
+ if (pdata->mmio_size >= pdata->dev_desc->prv_offset + LPSS_LTR_SIZE)
+ dev->power.set_latency_tolerance = acpi_lpss_set_ltr;
+ else
+ dev_err(dev, "MMIO size insufficient to access LTR\n");
+}
+
+static void acpi_lpss_unbind(struct device *dev)
+{
+ dev->power.set_latency_tolerance = NULL;
+}
+
static struct acpi_scan_handler lpss_handler = {
.ids = acpi_lpss_device_ids,
.attach = acpi_lpss_create_device,
+ .bind = acpi_lpss_bind,
+ .unbind = acpi_lpss_unbind,
};
void __init acpi_lpss_init(void)
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index df96a0fe4890..37d73024b82e 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -408,28 +408,14 @@ static int acpi_pad_pur(acpi_handle handle)
return num;
}
-/* Notify firmware how many CPUs are idle */
-static void acpi_pad_ost(acpi_handle handle, int stat,
- uint32_t idle_cpus)
-{
- union acpi_object params[3] = {
- {.type = ACPI_TYPE_INTEGER,},
- {.type = ACPI_TYPE_INTEGER,},
- {.type = ACPI_TYPE_BUFFER,},
- };
- struct acpi_object_list arg_list = {3, params};
-
- params[0].integer.value = ACPI_PROCESSOR_AGGREGATOR_NOTIFY;
- params[1].integer.value = stat;
- params[2].buffer.length = 4;
- params[2].buffer.pointer = (void *)&idle_cpus;
- acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
-}
-
static void acpi_pad_handle_notify(acpi_handle handle)
{
int num_cpus;
uint32_t idle_cpus;
+ struct acpi_buffer param = {
+ .length = 4,
+ .pointer = (void *)&idle_cpus,
+ };
mutex_lock(&isolated_cpus_lock);
num_cpus = acpi_pad_pur(handle);
@@ -439,7 +425,7 @@ static void acpi_pad_handle_notify(acpi_handle handle)
}
acpi_pad_idle_cpus(num_cpus);
idle_cpus = acpi_pad_idle_cpus_num();
- acpi_pad_ost(handle, 0, idle_cpus);
+ acpi_evaluate_ost(handle, ACPI_PROCESSOR_AGGREGATOR_NOTIFY, 0, &param);
mutex_unlock(&isolated_cpus_lock);
}
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
index 438304086ff1..b7ed86a20427 100644
--- a/drivers/acpi/acpica/Makefile
+++ b/drivers/acpi/acpica/Makefile
@@ -122,6 +122,8 @@ acpi-y += \
rsaddr.o \
rscalc.o \
rscreate.o \
+ rsdump.o \
+ rsdumpinfo.o \
rsinfo.o \
rsio.o \
rsirq.o \
@@ -132,8 +134,6 @@ acpi-y += \
rsutils.o \
rsxface.o
-acpi-$(ACPI_FUTURE_USAGE) += rsdump.o rsdumpinfo.o
-
acpi-y += \
tbfadt.o \
tbfind.o \
diff --git a/drivers/acpi/acpica/accommon.h b/drivers/acpi/acpica/accommon.h
index 8a6c4a0d22db..6f1c616910ac 100644
--- a/drivers/acpi/acpica/accommon.h
+++ b/drivers/acpi/acpica/accommon.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index 2bf3ca2b8a7a..68a91eb0fa48 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -115,6 +115,8 @@ ACPI_HW_DEPENDENT_RETURN_VOID(void
char *block_arg))
ACPI_HW_DEPENDENT_RETURN_VOID(void acpi_db_generate_sci(void))
+void acpi_db_execute_test(char *type_arg);
+
/*
* dbconvert - miscellaneous conversion routines
*/
diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h
index 427db72a6302..d3e2cc395d7f 100644
--- a/drivers/acpi/acpica/acdispat.h
+++ b/drivers/acpi/acpica/acdispat.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -139,20 +139,21 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
struct acpi_walk_state *walk_state);
/*
- * dsload - Parser/Interpreter interface, pass 1 namespace load callbacks
+ * dsload - Parser/Interpreter interface
*/
acpi_status
acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number);
+/* dsload - pass 1 namespace load callbacks */
+
acpi_status
acpi_ds_load1_begin_op(struct acpi_walk_state *walk_state,
union acpi_parse_object **out_op);
acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state);
-/*
- * dsload - Parser/Interpreter interface, pass 2 namespace load callbacks
- */
+/* dsload - pass 2 namespace load callbacks */
+
acpi_status
acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
union acpi_parse_object **out_op);
@@ -200,7 +201,9 @@ void acpi_ds_method_data_init(struct acpi_walk_state *walk_state);
/*
* dsmethod - Parser/Interpreter interface - control method parsing
*/
-acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node);
+acpi_status
+acpi_ds_auto_serialize_method(struct acpi_namespace_node *node,
+ union acpi_operand_object *obj_desc);
acpi_status
acpi_ds_call_control_method(struct acpi_thread_state *thread,
diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h
index 0fb0adf435d6..68ec61fff188 100644
--- a/drivers/acpi/acpica/acevents.h
+++ b/drivers/acpi/acpica/acevents.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 4ed1aa384df2..49bbc71fad54 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -51,11 +51,19 @@
* to simplify maintenance of the code.
*/
#ifdef DEFINE_ACPI_GLOBALS
-#define ACPI_EXTERN
-#define ACPI_INIT_GLOBAL(a,b) a=b
+#define ACPI_GLOBAL(type,name) \
+ extern type name; \
+ type name
+
+#define ACPI_INIT_GLOBAL(type,name,value) \
+ type name=value
+
#else
-#define ACPI_EXTERN extern
-#define ACPI_INIT_GLOBAL(a,b) a
+#define ACPI_GLOBAL(type,name) \
+ extern type name
+
+#define ACPI_INIT_GLOBAL(type,name,value) \
+ extern type name
#endif
#ifdef DEFINE_ACPI_GLOBALS
@@ -82,33 +90,34 @@
* 5) Allow unresolved references (invalid target name) in package objects
* 6) Enable warning messages for behavior that is not ACPI spec compliant
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_interpreter_slack, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_interpreter_slack, FALSE);
/*
- * Automatically serialize ALL control methods? Default is FALSE, meaning
- * to use the Serialized/not_serialized method flags on a per method basis.
- * Only change this if the ASL code is poorly written and cannot handle
- * reentrancy even though methods are marked "NotSerialized".
+ * Automatically serialize all methods that create named objects? Default
+ * is TRUE, meaning that all non_serialized methods are scanned once at
+ * table load time to determine those that create named objects. Methods
+ * that create named objects are marked Serialized in order to prevent
+ * possible run-time problems if they are entered by more than one thread.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_all_methods_serialized, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_auto_serialize_methods, TRUE);
/*
* Create the predefined _OSI method in the namespace? Default is TRUE
* because ACPI CA is fully compatible with other ACPI implementations.
* Changing this will revert ACPI CA (and machine ASL) to pre-OSI behavior.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_create_osi_method, TRUE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_create_osi_method, TRUE);
/*
* Optionally use default values for the ACPI register widths. Set this to
* TRUE to use the defaults, if an FADT contains incorrect widths/lengths.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_use_default_register_widths, TRUE);
/*
* Optionally enable output from the AML Debug Object.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_aml_debug_object, FALSE);
/*
* Optionally copy the entire DSDT to local memory (instead of simply
@@ -116,7 +125,7 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE);
* DSDT, creating the need for this option. Default is FALSE, do not copy
* the DSDT.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_copy_dsdt_locally, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_copy_dsdt_locally, FALSE);
/*
* Optionally ignore an XSDT if present and use the RSDT instead.
@@ -124,7 +133,7 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_copy_dsdt_locally, FALSE);
* of the RSDT, the XSDT has been found to be corrupt or ill-formed on
* some machines. Default behavior is to use the XSDT if present.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_do_not_use_xsdt, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_do_not_use_xsdt, FALSE);
/*
* Optionally use 32-bit FADT addresses if and when there is a conflict
@@ -134,7 +143,7 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_do_not_use_xsdt, FALSE);
* some machines have been found to have a corrupted non-zero 64-bit
* address. Default is FALSE, do not favor the 32-bit addresses.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_use32_bit_fadt_addresses, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_use32_bit_fadt_addresses, FALSE);
/*
* Optionally truncate I/O addresses to 16 bits. Provides compatibility
@@ -142,47 +151,28 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_use32_bit_fadt_addresses, FALSE);
* this value is set to TRUE if any Windows OSI strings have been
* requested by the BIOS.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_truncate_io_addresses, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_truncate_io_addresses, FALSE);
/*
* Disable runtime checking and repair of values returned by control methods.
* Use only if the repair is causing a problem on a particular machine.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_disable_auto_repair, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_auto_repair, FALSE);
/*
* Optionally do not load any SSDTs from the RSDT/XSDT during initialization.
* This can be useful for debugging ACPI problems on some machines.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_disable_ssdt_table_load, FALSE);
+ACPI_INIT_GLOBAL(u8, 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;
-u32 acpi_current_gpe_count;
-u32 acpi_gbl_trace_flags;
-acpi_name acpi_gbl_trace_method_name;
-u8 acpi_gbl_system_awake_and_running;
-
-/*
- * ACPI 5.0 introduces the concept of a "reduced hardware platform", meaning
- * that the ACPI hardware is no longer required. A flag in the FADT indicates
- * a reduced HW machine, and that flag is duplicated here for convenience.
- */
-u8 acpi_gbl_reduced_hardware;
+ACPI_INIT_GLOBAL(u8, acpi_gbl_osi_data, 0);
#endif /* DEFINE_ACPI_GLOBALS */
-/* Do not disassemble buffers to resource descriptors */
-
-ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_no_resource_disassembly, FALSE);
-
/*****************************************************************************
*
* ACPI Table globals
@@ -190,37 +180,36 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_no_resource_disassembly, FALSE);
****************************************************************************/
/*
- * acpi_gbl_root_table_list is the master list of ACPI tables that were
- * found in the RSDT/XSDT.
+ * Master list of all ACPI tables that were found in the RSDT/XSDT.
*/
-ACPI_EXTERN struct acpi_table_list acpi_gbl_root_table_list;
+ACPI_GLOBAL(struct acpi_table_list, acpi_gbl_root_table_list);
+
+/* DSDT information. Used to check for DSDT corruption */
+
+ACPI_GLOBAL(struct acpi_table_header *, acpi_gbl_DSDT);
+ACPI_GLOBAL(struct acpi_table_header, acpi_gbl_original_dsdt_header);
#if (!ACPI_REDUCED_HARDWARE)
-ACPI_EXTERN struct acpi_table_facs *acpi_gbl_FACS;
+ACPI_GLOBAL(struct acpi_table_facs *, acpi_gbl_FACS);
#endif /* !ACPI_REDUCED_HARDWARE */
/* These addresses are calculated from the FADT Event Block addresses */
-ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_status;
-ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable;
-
-ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_status;
-ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable;
+ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1a_status);
+ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1a_enable);
-/* DSDT information. Used to check for DSDT corruption */
-
-ACPI_EXTERN struct acpi_table_header *acpi_gbl_DSDT;
-ACPI_EXTERN struct acpi_table_header acpi_gbl_original_dsdt_header;
+ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1b_status);
+ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1b_enable);
/*
- * Handle both ACPI 1.0 and ACPI 2.0 Integer widths. The integer width is
+ * Handle both ACPI 1.0 and ACPI 2.0+ Integer widths. The integer width is
* determined by the revision of the DSDT: If the DSDT revision is less than
* 2, use only the lower 32 bits of the internal 64-bit Integer.
*/
-ACPI_EXTERN u8 acpi_gbl_integer_bit_width;
-ACPI_EXTERN u8 acpi_gbl_integer_byte_width;
-ACPI_EXTERN u8 acpi_gbl_integer_nybble_width;
+ACPI_GLOBAL(u8, acpi_gbl_integer_bit_width);
+ACPI_GLOBAL(u8, acpi_gbl_integer_byte_width);
+ACPI_GLOBAL(u8, acpi_gbl_integer_nybble_width);
/*****************************************************************************
*
@@ -233,36 +222,36 @@ ACPI_EXTERN u8 acpi_gbl_integer_nybble_width;
* actual OS mutex handles, indexed by the local ACPI_MUTEX_HANDLEs.
* (The table maps local handles to the real OS handles)
*/
-ACPI_EXTERN struct acpi_mutex_info acpi_gbl_mutex_info[ACPI_NUM_MUTEX];
+ACPI_GLOBAL(struct acpi_mutex_info, acpi_gbl_mutex_info[ACPI_NUM_MUTEX]);
/*
* Global lock mutex is an actual AML mutex object
* Global lock semaphore works in conjunction with the actual global lock
* Global lock spinlock is used for "pending" handshake
*/
-ACPI_EXTERN union acpi_operand_object *acpi_gbl_global_lock_mutex;
-ACPI_EXTERN acpi_semaphore acpi_gbl_global_lock_semaphore;
-ACPI_EXTERN acpi_spinlock acpi_gbl_global_lock_pending_lock;
-ACPI_EXTERN u16 acpi_gbl_global_lock_handle;
-ACPI_EXTERN u8 acpi_gbl_global_lock_acquired;
-ACPI_EXTERN u8 acpi_gbl_global_lock_present;
-ACPI_EXTERN u8 acpi_gbl_global_lock_pending;
+ACPI_GLOBAL(union acpi_operand_object *, acpi_gbl_global_lock_mutex);
+ACPI_GLOBAL(acpi_semaphore, acpi_gbl_global_lock_semaphore);
+ACPI_GLOBAL(acpi_spinlock, acpi_gbl_global_lock_pending_lock);
+ACPI_GLOBAL(u16, acpi_gbl_global_lock_handle);
+ACPI_GLOBAL(u8, acpi_gbl_global_lock_acquired);
+ACPI_GLOBAL(u8, acpi_gbl_global_lock_present);
+ACPI_GLOBAL(u8, acpi_gbl_global_lock_pending);
/*
* Spinlocks are used for interfaces that can be possibly called at
* interrupt level
*/
-ACPI_EXTERN acpi_spinlock acpi_gbl_gpe_lock; /* For GPE data structs and registers */
-ACPI_EXTERN acpi_spinlock acpi_gbl_hardware_lock; /* For ACPI H/W except GPE registers */
-ACPI_EXTERN acpi_spinlock acpi_gbl_reference_count_lock;
+ACPI_GLOBAL(acpi_spinlock, acpi_gbl_gpe_lock); /* For GPE data structs and registers */
+ACPI_GLOBAL(acpi_spinlock, acpi_gbl_hardware_lock); /* For ACPI H/W except GPE registers */
+ACPI_GLOBAL(acpi_spinlock, acpi_gbl_reference_count_lock);
/* Mutex for _OSI support */
-ACPI_EXTERN acpi_mutex acpi_gbl_osi_mutex;
+ACPI_GLOBAL(acpi_mutex, acpi_gbl_osi_mutex);
/* Reader/Writer lock is used for namespace walk and dynamic table unload */
-ACPI_EXTERN struct acpi_rw_lock acpi_gbl_namespace_rw_lock;
+ACPI_GLOBAL(struct acpi_rw_lock, acpi_gbl_namespace_rw_lock);
/*****************************************************************************
*
@@ -272,70 +261,69 @@ ACPI_EXTERN struct acpi_rw_lock acpi_gbl_namespace_rw_lock;
/* Object caches */
-ACPI_EXTERN acpi_cache_t *acpi_gbl_namespace_cache;
-ACPI_EXTERN acpi_cache_t *acpi_gbl_state_cache;
-ACPI_EXTERN acpi_cache_t *acpi_gbl_ps_node_cache;
-ACPI_EXTERN acpi_cache_t *acpi_gbl_ps_node_ext_cache;
-ACPI_EXTERN acpi_cache_t *acpi_gbl_operand_cache;
+ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_namespace_cache);
+ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_state_cache);
+ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_ps_node_cache);
+ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_ps_node_ext_cache);
+ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_operand_cache);
+
+/* System */
+
+ACPI_INIT_GLOBAL(u32, acpi_gbl_startup_flags, 0);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_shutdown, TRUE);
/* Global handlers */
-ACPI_EXTERN struct acpi_global_notify_handler acpi_gbl_global_notify[2];
-ACPI_EXTERN acpi_exception_handler acpi_gbl_exception_handler;
-ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler;
-ACPI_EXTERN acpi_table_handler acpi_gbl_table_handler;
-ACPI_EXTERN void *acpi_gbl_table_handler_context;
-ACPI_EXTERN struct acpi_walk_state *acpi_gbl_breakpoint_walk;
-ACPI_EXTERN acpi_interface_handler acpi_gbl_interface_handler;
-ACPI_EXTERN struct acpi_sci_handler_info *acpi_gbl_sci_handler_list;
+ACPI_GLOBAL(struct acpi_global_notify_handler, acpi_gbl_global_notify[2]);
+ACPI_GLOBAL(acpi_exception_handler, acpi_gbl_exception_handler);
+ACPI_GLOBAL(acpi_init_handler, acpi_gbl_init_handler);
+ACPI_GLOBAL(acpi_table_handler, acpi_gbl_table_handler);
+ACPI_GLOBAL(void *, acpi_gbl_table_handler_context);
+ACPI_GLOBAL(struct acpi_walk_state *, acpi_gbl_breakpoint_walk);
+ACPI_GLOBAL(acpi_interface_handler, acpi_gbl_interface_handler);
+ACPI_GLOBAL(struct acpi_sci_handler_info *, acpi_gbl_sci_handler_list);
/* Owner ID support */
-ACPI_EXTERN u32 acpi_gbl_owner_id_mask[ACPI_NUM_OWNERID_MASKS];
-ACPI_EXTERN u8 acpi_gbl_last_owner_id_index;
-ACPI_EXTERN u8 acpi_gbl_next_owner_id_offset;
+ACPI_GLOBAL(u32, acpi_gbl_owner_id_mask[ACPI_NUM_OWNERID_MASKS]);
+ACPI_GLOBAL(u8, acpi_gbl_last_owner_id_index);
+ACPI_GLOBAL(u8, acpi_gbl_next_owner_id_offset);
/* Initialization sequencing */
-ACPI_EXTERN u8 acpi_gbl_reg_methods_executed;
+ACPI_GLOBAL(u8, acpi_gbl_reg_methods_executed);
/* Misc */
-ACPI_EXTERN u32 acpi_gbl_original_mode;
-ACPI_EXTERN u32 acpi_gbl_rsdp_original_location;
-ACPI_EXTERN u32 acpi_gbl_ns_lookup_count;
-ACPI_EXTERN u32 acpi_gbl_ps_find_count;
-ACPI_EXTERN u16 acpi_gbl_pm1_enable_register_save;
-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 struct acpi_interface_info *acpi_gbl_supported_interfaces;
-ACPI_EXTERN struct acpi_address_range
- *acpi_gbl_address_range_list[ACPI_ADDRESS_RANGE_MAX];
-
-#ifndef DEFINE_ACPI_GLOBALS
-
-/* Other miscellaneous */
-
-extern u8 acpi_gbl_shutdown;
-extern u32 acpi_gbl_startup_flags;
+ACPI_GLOBAL(u32, acpi_gbl_original_mode);
+ACPI_GLOBAL(u32, acpi_gbl_rsdp_original_location);
+ACPI_GLOBAL(u32, acpi_gbl_ns_lookup_count);
+ACPI_GLOBAL(u32, acpi_gbl_ps_find_count);
+ACPI_GLOBAL(u16, acpi_gbl_pm1_enable_register_save);
+ACPI_GLOBAL(u8, acpi_gbl_debugger_configuration);
+ACPI_GLOBAL(u8, acpi_gbl_step_to_next_call);
+ACPI_GLOBAL(u8, acpi_gbl_acpi_hardware_present);
+ACPI_GLOBAL(u8, acpi_gbl_events_initialized);
+ACPI_GLOBAL(struct acpi_interface_info *, acpi_gbl_supported_interfaces);
+ACPI_GLOBAL(struct acpi_address_range *,
+ acpi_gbl_address_range_list[ACPI_ADDRESS_RANGE_MAX]);
+
+/* Other miscellaneous, declared and initialized in utglobal */
+
extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT];
extern const char *acpi_gbl_lowest_dstate_names[ACPI_NUM_sx_w_METHODS];
extern const char *acpi_gbl_highest_dstate_names[ACPI_NUM_sx_d_METHODS];
-extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES];
extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS];
-
-#endif
+extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES];
#ifdef ACPI_DBG_TRACK_ALLOCATIONS
-/* Lists for tracking memory allocations */
+/* Lists for tracking memory allocations (debug only) */
-ACPI_EXTERN struct acpi_memory_list *acpi_gbl_global_list;
-ACPI_EXTERN struct acpi_memory_list *acpi_gbl_ns_node_list;
-ACPI_EXTERN u8 acpi_gbl_display_final_mem_stats;
-ACPI_EXTERN u8 acpi_gbl_disable_mem_tracking;
+ACPI_GLOBAL(struct acpi_memory_list *, acpi_gbl_global_list);
+ACPI_GLOBAL(struct acpi_memory_list *, acpi_gbl_ns_node_list);
+ACPI_GLOBAL(u8, acpi_gbl_display_final_mem_stats);
+ACPI_GLOBAL(u8, acpi_gbl_disable_mem_tracking);
#endif
/*****************************************************************************
@@ -350,22 +338,23 @@ ACPI_EXTERN u8 acpi_gbl_disable_mem_tracking;
#define NUM_PREDEFINED_NAMES 9
#endif
-ACPI_EXTERN struct acpi_namespace_node acpi_gbl_root_node_struct;
-ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_root_node;
-ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_fadt_gpe_device;
-ACPI_EXTERN union acpi_operand_object *acpi_gbl_module_code_list;
+ACPI_GLOBAL(struct acpi_namespace_node, acpi_gbl_root_node_struct);
+ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_root_node);
+ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_fadt_gpe_device);
+ACPI_GLOBAL(union acpi_operand_object *, acpi_gbl_module_code_list);
extern const u8 acpi_gbl_ns_properties[ACPI_NUM_NS_TYPES];
extern const struct acpi_predefined_names
acpi_gbl_pre_defined_names[NUM_PREDEFINED_NAMES];
#ifdef ACPI_DEBUG_OUTPUT
-ACPI_EXTERN u32 acpi_gbl_current_node_count;
-ACPI_EXTERN u32 acpi_gbl_current_node_size;
-ACPI_EXTERN u32 acpi_gbl_max_concurrent_node_count;
-ACPI_EXTERN acpi_size *acpi_gbl_entry_stack_pointer;
-ACPI_EXTERN acpi_size *acpi_gbl_lowest_stack_pointer;
-ACPI_EXTERN u32 acpi_gbl_deepest_nesting;
+ACPI_GLOBAL(u32, acpi_gbl_current_node_count);
+ACPI_GLOBAL(u32, acpi_gbl_current_node_size);
+ACPI_GLOBAL(u32, acpi_gbl_max_concurrent_node_count);
+ACPI_GLOBAL(acpi_size *, acpi_gbl_entry_stack_pointer);
+ACPI_GLOBAL(acpi_size *, acpi_gbl_lowest_stack_pointer);
+ACPI_GLOBAL(u32, acpi_gbl_deepest_nesting);
+ACPI_INIT_GLOBAL(u32, acpi_gbl_nesting_level, 0);
#endif
/*****************************************************************************
@@ -374,11 +363,11 @@ ACPI_EXTERN u32 acpi_gbl_deepest_nesting;
*
****************************************************************************/
-ACPI_EXTERN struct acpi_thread_state *acpi_gbl_current_walk_list;
+ACPI_GLOBAL(struct acpi_thread_state *, acpi_gbl_current_walk_list);
/* Control method single step flag */
-ACPI_EXTERN u8 acpi_gbl_cm_single_step;
+ACPI_GLOBAL(u8, acpi_gbl_cm_single_step);
/*****************************************************************************
*
@@ -388,8 +377,9 @@ ACPI_EXTERN u8 acpi_gbl_cm_single_step;
extern struct acpi_bit_register_info
acpi_gbl_bit_register_info[ACPI_NUM_BITREG];
-ACPI_EXTERN u8 acpi_gbl_sleep_type_a;
-ACPI_EXTERN u8 acpi_gbl_sleep_type_b;
+
+ACPI_GLOBAL(u8, acpi_gbl_sleep_type_a);
+ACPI_GLOBAL(u8, acpi_gbl_sleep_type_b);
/*****************************************************************************
*
@@ -399,14 +389,15 @@ ACPI_EXTERN u8 acpi_gbl_sleep_type_b;
#if (!ACPI_REDUCED_HARDWARE)
-ACPI_EXTERN u8 acpi_gbl_all_gpes_initialized;
-ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head;
-ACPI_EXTERN struct acpi_gpe_block_info
- *acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
-ACPI_EXTERN acpi_gbl_event_handler acpi_gbl_global_event_handler;
-ACPI_EXTERN void *acpi_gbl_global_event_handler_context;
-ACPI_EXTERN struct acpi_fixed_event_handler
- acpi_gbl_fixed_event_handlers[ACPI_NUM_FIXED_EVENTS];
+ACPI_GLOBAL(u8, acpi_gbl_all_gpes_initialized);
+ACPI_GLOBAL(struct acpi_gpe_xrupt_info *, acpi_gbl_gpe_xrupt_list_head);
+ACPI_GLOBAL(struct acpi_gpe_block_info *,
+ acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS]);
+ACPI_GLOBAL(acpi_gbl_event_handler, acpi_gbl_global_event_handler);
+ACPI_GLOBAL(void *, acpi_gbl_global_event_handler_context);
+ACPI_GLOBAL(struct acpi_fixed_event_handler,
+ acpi_gbl_fixed_event_handlers[ACPI_NUM_FIXED_EVENTS]);
+
extern struct acpi_fixed_event_info
acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS];
@@ -418,23 +409,19 @@ extern struct acpi_fixed_event_info
*
****************************************************************************/
-/* Procedure nesting level for debug output */
-
-extern u32 acpi_gbl_nesting_level;
-
/* Event counters */
-ACPI_EXTERN u32 acpi_method_count;
-ACPI_EXTERN u32 acpi_gpe_count;
-ACPI_EXTERN u32 acpi_sci_count;
-ACPI_EXTERN u32 acpi_fixed_event_count[ACPI_NUM_FIXED_EVENTS];
+ACPI_GLOBAL(u32, acpi_method_count);
+ACPI_GLOBAL(u32, acpi_gpe_count);
+ACPI_GLOBAL(u32, acpi_sci_count);
+ACPI_GLOBAL(u32, acpi_fixed_event_count[ACPI_NUM_FIXED_EVENTS]);
/* Support for dynamic control method tracing mechanism */
-ACPI_EXTERN u32 acpi_gbl_original_dbg_level;
-ACPI_EXTERN u32 acpi_gbl_original_dbg_layer;
-ACPI_EXTERN u32 acpi_gbl_trace_dbg_level;
-ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer;
+ACPI_GLOBAL(u32, acpi_gbl_original_dbg_level);
+ACPI_GLOBAL(u32, acpi_gbl_original_dbg_layer);
+ACPI_GLOBAL(u32, acpi_gbl_trace_dbg_level);
+ACPI_GLOBAL(u32, acpi_gbl_trace_dbg_layer);
/*****************************************************************************
*
@@ -442,61 +429,64 @@ ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer;
*
****************************************************************************/
-ACPI_EXTERN u8 acpi_gbl_db_output_flags;
+ACPI_GLOBAL(u8, acpi_gbl_db_output_flags);
#ifdef ACPI_DISASSEMBLER
-ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_ignore_noop_operator, FALSE);
+/* Do not disassemble buffers to resource descriptors */
+
+ACPI_INIT_GLOBAL(u8, acpi_gbl_no_resource_disassembly, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_ignore_noop_operator, FALSE);
-ACPI_EXTERN u8 acpi_gbl_db_opt_disasm;
-ACPI_EXTERN u8 acpi_gbl_db_opt_verbose;
-ACPI_EXTERN u8 acpi_gbl_num_external_methods;
-ACPI_EXTERN u32 acpi_gbl_resolved_external_methods;
-ACPI_EXTERN struct acpi_external_list *acpi_gbl_external_list;
-ACPI_EXTERN struct acpi_external_file *acpi_gbl_external_file_list;
+ACPI_GLOBAL(u8, acpi_gbl_db_opt_disasm);
+ACPI_GLOBAL(u8, acpi_gbl_db_opt_verbose);
+ACPI_GLOBAL(u8, acpi_gbl_num_external_methods);
+ACPI_GLOBAL(u32, acpi_gbl_resolved_external_methods);
+ACPI_GLOBAL(struct acpi_external_list *, acpi_gbl_external_list);
+ACPI_GLOBAL(struct acpi_external_file *, acpi_gbl_external_file_list);
#endif
#ifdef ACPI_DEBUGGER
-extern u8 acpi_gbl_method_executing;
-extern u8 acpi_gbl_abort_method;
-extern u8 acpi_gbl_db_terminate_threads;
+ACPI_INIT_GLOBAL(u8, acpi_gbl_db_terminate_threads, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_abort_method, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_method_executing, FALSE);
-ACPI_EXTERN u8 acpi_gbl_db_opt_tables;
-ACPI_EXTERN u8 acpi_gbl_db_opt_stats;
-ACPI_EXTERN u8 acpi_gbl_db_opt_ini_methods;
-ACPI_EXTERN u8 acpi_gbl_db_opt_no_region_support;
-ACPI_EXTERN u8 acpi_gbl_db_output_to_file;
-ACPI_EXTERN char *acpi_gbl_db_buffer;
-ACPI_EXTERN char *acpi_gbl_db_filename;
-ACPI_EXTERN u32 acpi_gbl_db_debug_level;
-ACPI_EXTERN u32 acpi_gbl_db_console_debug_level;
-ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_db_scope_node;
+ACPI_GLOBAL(u8, acpi_gbl_db_opt_tables);
+ACPI_GLOBAL(u8, acpi_gbl_db_opt_stats);
+ACPI_GLOBAL(u8, acpi_gbl_db_opt_ini_methods);
+ACPI_GLOBAL(u8, acpi_gbl_db_opt_no_region_support);
+ACPI_GLOBAL(u8, acpi_gbl_db_output_to_file);
+ACPI_GLOBAL(char *, acpi_gbl_db_buffer);
+ACPI_GLOBAL(char *, acpi_gbl_db_filename);
+ACPI_GLOBAL(u32, acpi_gbl_db_debug_level);
+ACPI_GLOBAL(u32, acpi_gbl_db_console_debug_level);
+ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_db_scope_node);
-ACPI_EXTERN char *acpi_gbl_db_args[ACPI_DEBUGGER_MAX_ARGS];
-ACPI_EXTERN acpi_object_type acpi_gbl_db_arg_types[ACPI_DEBUGGER_MAX_ARGS];
+ACPI_GLOBAL(char *, acpi_gbl_db_args[ACPI_DEBUGGER_MAX_ARGS]);
+ACPI_GLOBAL(acpi_object_type, acpi_gbl_db_arg_types[ACPI_DEBUGGER_MAX_ARGS]);
/* These buffers should all be the same size */
-ACPI_EXTERN char acpi_gbl_db_line_buf[ACPI_DB_LINE_BUFFER_SIZE];
-ACPI_EXTERN char acpi_gbl_db_parsed_buf[ACPI_DB_LINE_BUFFER_SIZE];
-ACPI_EXTERN char acpi_gbl_db_scope_buf[ACPI_DB_LINE_BUFFER_SIZE];
-ACPI_EXTERN char acpi_gbl_db_debug_filename[ACPI_DB_LINE_BUFFER_SIZE];
+ACPI_GLOBAL(char, acpi_gbl_db_line_buf[ACPI_DB_LINE_BUFFER_SIZE]);
+ACPI_GLOBAL(char, acpi_gbl_db_parsed_buf[ACPI_DB_LINE_BUFFER_SIZE]);
+ACPI_GLOBAL(char, acpi_gbl_db_scope_buf[ACPI_DB_LINE_BUFFER_SIZE]);
+ACPI_GLOBAL(char, acpi_gbl_db_debug_filename[ACPI_DB_LINE_BUFFER_SIZE]);
/*
* Statistic globals
*/
-ACPI_EXTERN u16 acpi_gbl_obj_type_count[ACPI_TYPE_NS_NODE_MAX + 1];
-ACPI_EXTERN u16 acpi_gbl_node_type_count[ACPI_TYPE_NS_NODE_MAX + 1];
-ACPI_EXTERN u16 acpi_gbl_obj_type_count_misc;
-ACPI_EXTERN u16 acpi_gbl_node_type_count_misc;
-ACPI_EXTERN u32 acpi_gbl_num_nodes;
-ACPI_EXTERN u32 acpi_gbl_num_objects;
-
-ACPI_EXTERN u32 acpi_gbl_size_of_parse_tree;
-ACPI_EXTERN u32 acpi_gbl_size_of_method_trees;
-ACPI_EXTERN u32 acpi_gbl_size_of_node_entries;
-ACPI_EXTERN u32 acpi_gbl_size_of_acpi_objects;
+ACPI_GLOBAL(u16, acpi_gbl_obj_type_count[ACPI_TYPE_NS_NODE_MAX + 1]);
+ACPI_GLOBAL(u16, acpi_gbl_node_type_count[ACPI_TYPE_NS_NODE_MAX + 1]);
+ACPI_GLOBAL(u16, acpi_gbl_obj_type_count_misc);
+ACPI_GLOBAL(u16, acpi_gbl_node_type_count_misc);
+ACPI_GLOBAL(u32, acpi_gbl_num_nodes);
+ACPI_GLOBAL(u32, acpi_gbl_num_objects);
+
+ACPI_GLOBAL(u32, acpi_gbl_size_of_parse_tree);
+ACPI_GLOBAL(u32, acpi_gbl_size_of_method_trees);
+ACPI_GLOBAL(u32, acpi_gbl_size_of_node_entries);
+ACPI_GLOBAL(u32, acpi_gbl_size_of_acpi_objects);
#endif /* ACPI_DEBUGGER */
@@ -508,7 +498,7 @@ ACPI_EXTERN u32 acpi_gbl_size_of_acpi_objects;
#ifdef ACPI_APPLICATION
-ACPI_FILE ACPI_INIT_GLOBAL(acpi_gbl_debug_file, NULL);
+ACPI_INIT_GLOBAL(ACPI_FILE, acpi_gbl_debug_file, NULL);
#endif /* ACPI_APPLICATION */
diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h
index 6357e932bfd9..2ad2351a9833 100644
--- a/drivers/acpi/acpica/achware.h
+++ b/drivers/acpi/acpica/achware.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h
index 8af8c9bdeb35..b01f71ce0523 100644
--- a/drivers/acpi/acpica/acinterp.h
+++ b/drivers/acpi/acpica/acinterp.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -87,6 +87,10 @@ typedef const struct acpi_exdump_info {
#define ACPI_EXD_PACKAGE 11
#define ACPI_EXD_FIELD 12
#define ACPI_EXD_REFERENCE 13
+#define ACPI_EXD_LIST 14 /* Operand object list */
+#define ACPI_EXD_HDLR_LIST 15 /* Address Handler list */
+#define ACPI_EXD_RGN_LIST 16 /* Region list */
+#define ACPI_EXD_NODE 17 /* Namespace Node */
/* restore default alignment */
@@ -454,10 +458,6 @@ void acpi_ex_enter_interpreter(void);
void acpi_ex_exit_interpreter(void);
-void acpi_ex_reacquire_interpreter(void);
-
-void acpi_ex_relinquish_interpreter(void);
-
u8 acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc);
void acpi_ex_acquire_global_lock(u32 rule);
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index d95ca5449ace..52a21dafb540 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index 2a86c65d873b..4bceb11c7380 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -63,17 +63,21 @@
#define ACPI_SET64(ptr, val) (*ACPI_CAST64 (ptr) = (u64) (val))
/*
- * printf() format helpers
+ * printf() format helpers. These macros are workarounds for the difficulties
+ * with emitting 64-bit integers and 64-bit pointers with the same code
+ * for both 32-bit and 64-bit hosts.
*/
-
-/* Split 64-bit integer into two 32-bit values. Use with %8.8X%8.8X */
-
#define ACPI_FORMAT_UINT64(i) ACPI_HIDWORD(i), ACPI_LODWORD(i)
#if ACPI_MACHINE_WIDTH == 64
#define ACPI_FORMAT_NATIVE_UINT(i) ACPI_FORMAT_UINT64(i)
+#define ACPI_FORMAT_TO_UINT(i) ACPI_FORMAT_UINT64(i)
+#define ACPI_PRINTF_UINT "0x%8.8X%8.8X"
+
#else
-#define ACPI_FORMAT_NATIVE_UINT(i) 0, (i)
+#define ACPI_FORMAT_NATIVE_UINT(i) 0, (u32) (i)
+#define ACPI_FORMAT_TO_UINT(i) (u32) (i)
+#define ACPI_PRINTF_UINT "0x%8.8X"
#endif
/*
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index e6138ac4a160..ee1c040f321c 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h
index cc7ab6dd724e..22fb6449d3d6 100644
--- a/drivers/acpi/acpica/acobject.h
+++ b/drivers/acpi/acpica/acobject.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -193,7 +193,8 @@ struct acpi_object_method {
#define ACPI_METHOD_INTERNAL_ONLY 0x02 /* Method is implemented internally (_OSI) */
#define ACPI_METHOD_SERIALIZED 0x04 /* Method is serialized */
#define ACPI_METHOD_SERIALIZED_PENDING 0x08 /* Method is to be marked serialized */
-#define ACPI_METHOD_MODIFIED_NAMESPACE 0x10 /* Method modified the namespace */
+#define ACPI_METHOD_IGNORE_SYNC_LEVEL 0x10 /* Method was auto-serialized at table load time */
+#define ACPI_METHOD_MODIFIED_NAMESPACE 0x20 /* Method modified the namespace */
/******************************************************************************
*
diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h
index 3fc9ca7e8aa3..dda0e6affcf1 100644
--- a/drivers/acpi/acpica/acopcode.h
+++ b/drivers/acpi/acpica/acopcode.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h
index aed319318835..6168b85463ed 100644
--- a/drivers/acpi/acpica/acparser.h
+++ b/drivers/acpi/acpica/acparser.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index f600aded7261..a48d713e9599 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,7 +48,7 @@
*
* Return Package types
*
- * 1) PTYPE1 packages do not contain sub-packages.
+ * 1) PTYPE1 packages do not contain subpackages.
*
* ACPI_PTYPE1_FIXED: Fixed-length length, 1 or 2 object types:
* object type
@@ -63,8 +63,8 @@
* (Used for _PRW)
*
*
- * 2) PTYPE2 packages contain a Variable-length number of sub-packages. Each
- * of the different types describe the contents of each of the sub-packages.
+ * 2) PTYPE2 packages contain a Variable-length number of subpackages. Each
+ * of the different types describe the contents of each of the subpackages.
*
* ACPI_PTYPE2: Each subpackage contains 1 or 2 object types. Zero-length
* parent package is allowed:
@@ -560,7 +560,7 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
/*
* For _HPX, a single package is returned, containing a variable-length number
- * of sub-packages. Each sub-package contains a PCI record setting.
+ * of subpackages. Each subpackage contains a PCI record setting.
* There are several different type of record settings, of different
* lengths, but all elements of all settings are Integers.
*/
@@ -698,6 +698,12 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+ {{"_PRP", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each: 1 Str, 1 Int/Str/Pkg */
+ PACKAGE_INFO(ACPI_PTYPE2, ACPI_RTYPE_STRING, 1,
+ ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING |
+ ACPI_RTYPE_PACKAGE | ACPI_RTYPE_REFERENCE, 1, 0),
+
{{"_PRS", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h
index ff97430455cb..4b008e8884a1 100644
--- a/drivers/acpi/acpica/acresrc.h
+++ b/drivers/acpi/acpica/acresrc.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h
index fc83c0a5ca70..cf7346110bd8 100644
--- a/drivers/acpi/acpica/acstruct.h
+++ b/drivers/acpi/acpica/acstruct.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -133,6 +133,9 @@ struct acpi_init_walk_info {
u32 table_index;
u32 object_count;
u32 method_count;
+ u32 serial_method_count;
+ u32 non_serial_method_count;
+ u32 serialized_method_count;
u32 device_count;
u32 op_region_count;
u32 field_count;
diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h
index c54f42c64fe2..5fa4b2027697 100644
--- a/drivers/acpi/acpica/actables.h
+++ b/drivers/acpi/acpica/actables.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index be8180c17d7e..ceeec0b7ccb1 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,7 +49,7 @@ extern const u8 acpi_gbl_resource_aml_serial_bus_sizes[];
/* Strings used by the disassembler and debugger resource dump routines */
-#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER)
+#if defined(ACPI_DEBUG_OUTPUT) || defined (ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER)
extern const char *acpi_gbl_bm_decode[];
extern const char *acpi_gbl_config_decode[];
diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h
index 48a3e331b72d..5908ccec6aea 100644
--- a/drivers/acpi/acpica/amlcode.h
+++ b/drivers/acpi/acpica/amlcode.h
@@ -7,7 +7,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h
index 87c26366d1df..f3f834408441 100644
--- a/drivers/acpi/acpica/amlresrc.h
+++ b/drivers/acpi/acpica/amlresrc.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c
index afdc6df17abf..720b1cdda711 100644
--- a/drivers/acpi/acpica/dsargs.c
+++ b/drivers/acpi/acpica/dsargs.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c
index eb56b66444b5..8daf9de82b73 100644
--- a/drivers/acpi/acpica/dscontrol.c
+++ b/drivers/acpi/acpica/dscontrol.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c
index e7a57c554e84..3661c8e90540 100644
--- a/drivers/acpi/acpica/dsfield.c
+++ b/drivers/acpi/acpica/dsfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c
index 14424200d246..aee5e45f6d35 100644
--- a/drivers/acpi/acpica/dsinit.c
+++ b/drivers/acpi/acpica/dsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -83,8 +83,8 @@ acpi_ds_init_one_object(acpi_handle obj_handle,
(struct acpi_init_walk_info *)context;
struct acpi_namespace_node *node =
(struct acpi_namespace_node *)obj_handle;
- acpi_object_type type;
acpi_status status;
+ union acpi_operand_object *obj_desc;
ACPI_FUNCTION_ENTRY();
@@ -100,9 +100,7 @@ acpi_ds_init_one_object(acpi_handle obj_handle,
/* And even then, we are only interested in a few object types */
- type = acpi_ns_get_type(obj_handle);
-
- switch (type) {
+ switch (acpi_ns_get_type(obj_handle)) {
case ACPI_TYPE_REGION:
status = acpi_ds_initialize_region(obj_handle);
@@ -117,8 +115,44 @@ acpi_ds_init_one_object(acpi_handle obj_handle,
break;
case ACPI_TYPE_METHOD:
-
+ /*
+ * Auto-serialization support. We will examine each method that is
+ * not_serialized to determine if it creates any Named objects. If
+ * it does, it will be marked serialized to prevent problems if
+ * the method is entered by two or more threads and an attempt is
+ * made to create the same named object twice -- which results in
+ * an AE_ALREADY_EXISTS exception and method abort.
+ */
info->method_count++;
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (!obj_desc) {
+ break;
+ }
+
+ /* Ignore if already serialized */
+
+ if (obj_desc->method.info_flags & ACPI_METHOD_SERIALIZED) {
+ info->serial_method_count++;
+ break;
+ }
+
+ if (acpi_gbl_auto_serialize_methods) {
+
+ /* Parse/scan method and serialize it if necessary */
+
+ acpi_ds_auto_serialize_method(node, obj_desc);
+ if (obj_desc->method.
+ info_flags & ACPI_METHOD_SERIALIZED) {
+
+ /* Method was just converted to Serialized */
+
+ info->serial_method_count++;
+ info->serialized_method_count++;
+ break;
+ }
+ }
+
+ info->non_serial_method_count++;
break;
case ACPI_TYPE_DEVICE:
@@ -170,7 +204,6 @@ acpi_ds_initialize_objects(u32 table_index,
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"**** Starting initialization of namespace objects ****\n"));
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "Parsing all Control Methods:"));
/* Set all init info to zero */
@@ -205,14 +238,16 @@ acpi_ds_initialize_objects(u32 table_index,
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
- "\nTable [%4.4s](id %4.4X) - %u Objects with %u Devices %u Methods %u Regions\n",
+ "Table [%4.4s] (id %4.4X) - %4u Objects with %3u Devices, "
+ "%3u Regions, %3u Methods (%u/%u/%u Serial/Non/Cvt)\n",
table->signature, owner_id, info.object_count,
- info.device_count, info.method_count,
- info.op_region_count));
+ info.device_count, info.op_region_count,
+ info.method_count, info.serial_method_count,
+ info.non_serial_method_count,
+ info.serialized_method_count));
- ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "%u Methods, %u Regions\n", info.method_count,
- info.op_region_count));
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "%u Methods, %u Regions\n",
+ info.method_count, info.op_region_count));
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c
index 81a78ba84311..3c7f7378b94d 100644
--- a/drivers/acpi/acpica/dsmethod.c
+++ b/drivers/acpi/acpica/dsmethod.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,16 +49,155 @@
#ifdef ACPI_DISASSEMBLER
#include "acdisasm.h"
#endif
+#include "acparser.h"
+#include "amlcode.h"
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dsmethod")
/* Local prototypes */
static acpi_status
+acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state,
+ union acpi_parse_object **out_op);
+
+static acpi_status
acpi_ds_create_method_mutex(union acpi_operand_object *method_desc);
/*******************************************************************************
*
+ * FUNCTION: acpi_ds_auto_serialize_method
+ *
+ * PARAMETERS: node - Namespace Node of the method
+ * obj_desc - Method object attached to node
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Parse a control method AML to scan for control methods that
+ * need serialization due to the creation of named objects.
+ *
+ * NOTE: It is a bit of overkill to mark all such methods serialized, since
+ * there is only a problem if the method actually blocks during execution.
+ * A blocking operation is, for example, a Sleep() operation, or any access
+ * to an operation region. However, it is probably not possible to easily
+ * detect whether a method will block or not, so we simply mark all suspicious
+ * methods as serialized.
+ *
+ * NOTE2: This code is essentially a generic routine for parsing a single
+ * control method.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_auto_serialize_method(struct acpi_namespace_node *node,
+ union acpi_operand_object *obj_desc)
+{
+ acpi_status status;
+ union acpi_parse_object *op = NULL;
+ struct acpi_walk_state *walk_state;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_auto_serialize_method, node);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+ "Method auto-serialization parse [%4.4s] %p\n",
+ acpi_ut_get_node_name(node), node));
+
+ /* Create/Init a root op for the method parse tree */
+
+ op = acpi_ps_alloc_op(AML_METHOD_OP);
+ if (!op) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ acpi_ps_set_name(op, node->name.integer);
+ op->common.node = node;
+
+ /* Create and initialize a new walk state */
+
+ walk_state =
+ acpi_ds_create_walk_state(node->owner_id, NULL, NULL, NULL);
+ if (!walk_state) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ status =
+ acpi_ds_init_aml_walk(walk_state, op, node,
+ obj_desc->method.aml_start,
+ obj_desc->method.aml_length, NULL, 0);
+ if (ACPI_FAILURE(status)) {
+ acpi_ds_delete_walk_state(walk_state);
+ return_ACPI_STATUS(status);
+ }
+
+ walk_state->descending_callback = acpi_ds_detect_named_opcodes;
+
+ /* Parse the method, scan for creation of named objects */
+
+ status = acpi_ps_parse_aml(walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ acpi_ps_delete_parse_tree(op);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_detect_named_opcodes
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk
+ * out_op - Unused, required for parser interface
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Descending callback used during the loading of ACPI tables.
+ * Currently used to detect methods that must be marked serialized
+ * in order to avoid problems with the creation of named objects.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state,
+ union acpi_parse_object **out_op)
+{
+
+ ACPI_FUNCTION_NAME(acpi_ds_detect_named_opcodes);
+
+ /* We are only interested in opcodes that create a new name */
+
+ if (!
+ (walk_state->op_info->
+ flags & (AML_NAMED | AML_CREATE | AML_FIELD))) {
+ return (AE_OK);
+ }
+
+ /*
+ * At this point, we know we have a Named object opcode.
+ * Mark the method as serialized. Later code will create a mutex for
+ * this method to enforce serialization.
+ *
+ * Note, ACPI_METHOD_IGNORE_SYNC_LEVEL flag means that we will ignore the
+ * Sync Level mechanism for this method, even though it is now serialized.
+ * Otherwise, there can be conflicts with existing ASL code that actually
+ * uses sync levels.
+ */
+ walk_state->method_desc->method.sync_level = 0;
+ walk_state->method_desc->method.info_flags |=
+ (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Method serialized [%4.4s] %p - [%s] (%4.4X)\n",
+ walk_state->method_node->name.ascii,
+ walk_state->method_node, walk_state->op_info->name,
+ walk_state->opcode));
+
+ /* Abort the parse, no need to examine this method any further */
+
+ return (AE_CTRL_TERMINATE);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ds_method_error
*
* PARAMETERS: status - Execution status
@@ -74,7 +213,7 @@ acpi_ds_create_method_mutex(union acpi_operand_object *method_desc);
******************************************************************************/
acpi_status
-acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state)
+acpi_ds_method_error(acpi_status status, struct acpi_walk_state * walk_state)
{
ACPI_FUNCTION_ENTRY();
@@ -217,13 +356,19 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
/*
* The current_sync_level (per-thread) must be less than or equal to
* the sync level of the method. This mechanism provides some
- * deadlock prevention
+ * deadlock prevention.
+ *
+ * If the method was auto-serialized, we just ignore the sync level
+ * mechanism, because auto-serialization of methods can interfere
+ * with ASL code that actually uses sync levels.
*
* Top-level method invocation has no walk state at this point
*/
if (walk_state &&
- (walk_state->thread->current_sync_level >
- obj_desc->method.mutex->mutex.sync_level)) {
+ (!(obj_desc->method.
+ info_flags & ACPI_METHOD_IGNORE_SYNC_LEVEL))
+ && (walk_state->thread->current_sync_level >
+ obj_desc->method.mutex->mutex.sync_level)) {
ACPI_ERROR((AE_INFO,
"Cannot acquire Mutex for method [%4.4s], current SyncLevel is too large (%u)",
acpi_ut_get_node_name(method_node),
@@ -668,7 +813,8 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
method_desc->method.info_flags &=
~ACPI_METHOD_SERIALIZED_PENDING;
method_desc->method.info_flags |=
- ACPI_METHOD_SERIALIZED;
+ (ACPI_METHOD_SERIALIZED |
+ ACPI_METHOD_IGNORE_SYNC_LEVEL);
method_desc->method.sync_level = 0;
}
diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c
index c4b0b3657237..b67522df01ac 100644
--- a/drivers/acpi/acpica/dsmthdat.c
+++ b/drivers/acpi/acpica/dsmthdat.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c
index b1746a68dad1..a1e7e6b6fcf7 100644
--- a/drivers/acpi/acpica/dsobject.c
+++ b/drivers/acpi/acpica/dsobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c
index 5205edcf2c01..6c0759c0db47 100644
--- a/drivers/acpi/acpica/dsopcode.c
+++ b/drivers/acpi/acpica/dsopcode.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c
index d7f53fb2979a..9f74795e2268 100644
--- a/drivers/acpi/acpica/dsutils.c
+++ b/drivers/acpi/acpica/dsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c
index 1bbb22fd6fa0..f7f5107e754d 100644
--- a/drivers/acpi/acpica/dswexec.c
+++ b/drivers/acpi/acpica/dswexec.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c
index 2dbe109727c8..15623da26200 100644
--- a/drivers/acpi/acpica/dswload.c
+++ b/drivers/acpi/acpica/dswload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -73,8 +73,20 @@ acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number)
{
switch (pass_number) {
+ case 0:
+
+ /* Parse only - caller will setup callbacks */
+
+ walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 |
+ ACPI_PARSE_DELETE_TREE | ACPI_PARSE_DISASSEMBLE;
+ walk_state->descending_callback = NULL;
+ walk_state->ascending_callback = NULL;
+ break;
+
case 1:
+ /* Load pass 1 */
+
walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 |
ACPI_PARSE_DELETE_TREE;
walk_state->descending_callback = acpi_ds_load1_begin_op;
@@ -83,6 +95,8 @@ acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number)
case 2:
+ /* Load pass 2 */
+
walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 |
ACPI_PARSE_DELETE_TREE;
walk_state->descending_callback = acpi_ds_load2_begin_op;
@@ -91,6 +105,8 @@ acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number)
case 3:
+ /* Execution pass */
+
#ifndef ACPI_NO_METHOD_EXECUTION
walk_state->parse_flags |= ACPI_PARSE_EXECUTE |
ACPI_PARSE_DELETE_TREE;
diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c
index 7f569d573027..2ac28d297305 100644
--- a/drivers/acpi/acpica/dswload2.c
+++ b/drivers/acpi/acpica/dswload2.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswscope.c b/drivers/acpi/acpica/dswscope.c
index d67891de1b54..9d6e2c1de1f8 100644
--- a/drivers/acpi/acpica/dswscope.c
+++ b/drivers/acpi/acpica/dswscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c
index ecb12e2137ff..24f7d5ea678a 100644
--- a/drivers/acpi/acpica/dswstate.c
+++ b/drivers/acpi/acpica/dswstate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c
index 83cd45f4a870..c7bffff9ed32 100644
--- a/drivers/acpi/acpica/evevent.c
+++ b/drivers/acpi/acpica/evevent.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evglock.c b/drivers/acpi/acpica/evglock.c
index 4c67193a9fa7..3393a73ca0d6 100644
--- a/drivers/acpi/acpica/evglock.c
+++ b/drivers/acpi/acpica/evglock.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index a9cb4a1a4bb8..955f83da68a5 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c
index a31e549e64cc..caaed3c673fd 100644
--- a/drivers/acpi/acpica/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c
index a3e2f38aadf6..ae779c1e871d 100644
--- a/drivers/acpi/acpica/evgpeinit.c
+++ b/drivers/acpi/acpica/evgpeinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c
index 4d764e847a08..17e4bbfdb096 100644
--- a/drivers/acpi/acpica/evgpeutil.c
+++ b/drivers/acpi/acpica/evgpeutil.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evhandler.c b/drivers/acpi/acpica/evhandler.c
index e3157313eb27..78ac29351c9e 100644
--- a/drivers/acpi/acpica/evhandler.c
+++ b/drivers/acpi/acpica/evhandler.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c
index a5687540e9a6..5d594eb2e5ec 100644
--- a/drivers/acpi/acpica/evmisc.c
+++ b/drivers/acpi/acpica/evmisc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c
index 144cbb9b73bc..9957297d1580 100644
--- a/drivers/acpi/acpica/evregion.c
+++ b/drivers/acpi/acpica/evregion.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -314,6 +314,7 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
{
union acpi_operand_object *handler_obj;
union acpi_operand_object *obj_desc;
+ union acpi_operand_object *start_desc;
union acpi_operand_object **last_obj_ptr;
acpi_adr_space_setup region_setup;
void **region_context;
@@ -341,6 +342,7 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
/* Find this region in the handler's list */
obj_desc = handler_obj->address_space.region_list;
+ start_desc = obj_desc;
last_obj_ptr = &handler_obj->address_space.region_list;
while (obj_desc) {
@@ -438,6 +440,15 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
last_obj_ptr = &obj_desc->region.next;
obj_desc = obj_desc->region.next;
+
+ /* Prevent infinite loop if list is corrupted */
+
+ if (obj_desc == start_desc) {
+ ACPI_ERROR((AE_INFO,
+ "Circular handler list in region object %p",
+ region_obj));
+ return_VOID;
+ }
}
/* If we get here, the region was not in the handler's region list */
diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c
index 8354c4f7f10c..1b148a440d67 100644
--- a/drivers/acpi/acpica/evrgnini.c
+++ b/drivers/acpi/acpica/evrgnini.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evsci.c b/drivers/acpi/acpica/evsci.c
index 9e9e3454d893..4d8a709c1fc4 100644
--- a/drivers/acpi/acpica/evsci.c
+++ b/drivers/acpi/acpica/evsci.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index 23a7fadca412..a734b27da061 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c
index 39d06af5e347..e286640ad4ff 100644
--- a/drivers/acpi/acpica/evxfevnt.c
+++ b/drivers/acpi/acpica/evxfevnt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
index 5713da77c665..20a1392ffe06 100644
--- a/drivers/acpi/acpica/evxfgpe.c
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -583,6 +583,18 @@ acpi_install_gpe_block(acpi_handle gpe_device,
goto unlock_and_exit;
}
+ /* Validate the parent device */
+
+ if (node->type != ACPI_TYPE_DEVICE) {
+ status = AE_TYPE;
+ goto unlock_and_exit;
+ }
+
+ if (node->object) {
+ status = AE_ALREADY_EXISTS;
+ goto unlock_and_exit;
+ }
+
/*
* For user-installed GPE Block Devices, the gpe_block_base_number
* is always zero
@@ -666,6 +678,13 @@ acpi_status acpi_remove_gpe_block(acpi_handle gpe_device)
goto unlock_and_exit;
}
+ /* Validate the parent device */
+
+ if (node->type != ACPI_TYPE_DEVICE) {
+ status = AE_TYPE;
+ goto unlock_and_exit;
+ }
+
/* Get the device_object attached to the node */
obj_desc = acpi_ns_get_attached_object(node);
diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c
index 02ed75ac56cd..2d6f187939c7 100644
--- a/drivers/acpi/acpica/evxfregn.c
+++ b/drivers/acpi/acpica/evxfregn.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c
index 06d216c8d43a..8ba1464efd11 100644
--- a/drivers/acpi/acpica/exconfig.c
+++ b/drivers/acpi/acpica/exconfig.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c
index 69e4a8cc9b71..c545386fee96 100644
--- a/drivers/acpi/acpica/exconvrt.c
+++ b/drivers/acpi/acpica/exconvrt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c
index 3c2e6dcdad3e..95d23dabcfbb 100644
--- a/drivers/acpi/acpica/excreate.c
+++ b/drivers/acpi/acpica/excreate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c
index 81c72a4ecd82..4cfc3d3b5c97 100644
--- a/drivers/acpi/acpica/exdebug.c
+++ b/drivers/acpi/acpica/exdebug.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c
index 4d046faac48c..973fdae00f94 100644
--- a/drivers/acpi/acpica/exdump.c
+++ b/drivers/acpi/acpica/exdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -94,12 +94,13 @@ static struct acpi_exdump_info acpi_ex_dump_buffer[5] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_buffer), NULL},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(buffer.length), "Length"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.pointer), "Pointer"},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.node), "Parent Node"},
+ {ACPI_EXD_NODE, ACPI_EXD_OFFSET(buffer.node), "Parent Node"},
{ACPI_EXD_BUFFER, 0, NULL}
};
-static struct acpi_exdump_info acpi_ex_dump_package[5] = {
+static struct acpi_exdump_info acpi_ex_dump_package[6] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_package), NULL},
+ {ACPI_EXD_NODE, ACPI_EXD_OFFSET(package.node), "Parent Node"},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(package.flags), "Flags"},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(package.count), "Elements"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(package.elements), "Element List"},
@@ -108,11 +109,11 @@ static struct acpi_exdump_info acpi_ex_dump_package[5] = {
static struct acpi_exdump_info acpi_ex_dump_device[4] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_device), NULL},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.handler), "Handler"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.notify_list[0]),
"System Notify"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.notify_list[1]),
- "Device Notify"}
+ "Device Notify"},
+ {ACPI_EXD_HDLR_LIST, ACPI_EXD_OFFSET(device.handler), "Handler"}
};
static struct acpi_exdump_info acpi_ex_dump_event[2] = {
@@ -142,17 +143,18 @@ static struct acpi_exdump_info acpi_ex_dump_mutex[5] = {
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.os_mutex), "OsMutex"}
};
-static struct acpi_exdump_info acpi_ex_dump_region[7] = {
+static struct acpi_exdump_info acpi_ex_dump_region[8] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_region), NULL},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(region.space_id), "Space Id"},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(region.flags), "Flags"},
+ {ACPI_EXD_NODE, ACPI_EXD_OFFSET(region.node), "Parent Node"},
{ACPI_EXD_ADDRESS, ACPI_EXD_OFFSET(region.address), "Address"},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(region.length), "Length"},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(region.handler), "Handler"},
+ {ACPI_EXD_HDLR_LIST, ACPI_EXD_OFFSET(region.handler), "Handler"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(region.next), "Next"}
};
-static struct acpi_exdump_info acpi_ex_dump_power[5] = {
+static struct acpi_exdump_info acpi_ex_dump_power[6] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_power), NULL},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(power_resource.system_level),
"System Level"},
@@ -161,7 +163,8 @@ static struct acpi_exdump_info acpi_ex_dump_power[5] = {
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.notify_list[0]),
"System Notify"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.notify_list[1]),
- "Device Notify"}
+ "Device Notify"},
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.handler), "Handler"}
};
static struct acpi_exdump_info acpi_ex_dump_processor[7] = {
@@ -225,7 +228,7 @@ static struct acpi_exdump_info acpi_ex_dump_reference[8] = {
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(reference.target_type), "Target Type"},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(reference.value), "Value"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.object), "Object Desc"},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.node), "Node"},
+ {ACPI_EXD_NODE, ACPI_EXD_OFFSET(reference.node), "Node"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.where), "Where"},
{ACPI_EXD_REFERENCE, 0, NULL}
};
@@ -234,16 +237,16 @@ static struct acpi_exdump_info acpi_ex_dump_address_handler[6] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_address_handler),
NULL},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(address_space.space_id), "Space Id"},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(address_space.next), "Next"},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(address_space.region_list),
+ {ACPI_EXD_HDLR_LIST, ACPI_EXD_OFFSET(address_space.next), "Next"},
+ {ACPI_EXD_RGN_LIST, ACPI_EXD_OFFSET(address_space.region_list),
"Region List"},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(address_space.node), "Node"},
+ {ACPI_EXD_NODE, ACPI_EXD_OFFSET(address_space.node), "Node"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(address_space.context), "Context"}
};
static struct acpi_exdump_info acpi_ex_dump_notify[7] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_notify), NULL},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.node), "Node"},
+ {ACPI_EXD_NODE, ACPI_EXD_OFFSET(notify.node), "Node"},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(notify.handler_type), "Handler Type"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.handler), "Handler"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.context), "Context"},
@@ -252,14 +255,31 @@ static struct acpi_exdump_info acpi_ex_dump_notify[7] = {
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.next[1]), "Next Device Notify"}
};
+static struct acpi_exdump_info acpi_ex_dump_extra[6] = {
+ {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_extra), NULL},
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(extra.method_REG), "_REG Method"},
+ {ACPI_EXD_NODE, ACPI_EXD_OFFSET(extra.scope_node), "Scope Node"},
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(extra.region_context),
+ "Region Context"},
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(extra.aml_start), "Aml Start"},
+ {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(extra.aml_length), "Aml Length"}
+};
+
+static struct acpi_exdump_info acpi_ex_dump_data[3] = {
+ {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_data), NULL},
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(data.handler), "Handler"},
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(data.pointer), "Raw Data"}
+};
+
/* Miscellaneous tables */
-static struct acpi_exdump_info acpi_ex_dump_common[4] = {
+static struct acpi_exdump_info acpi_ex_dump_common[5] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_common), NULL},
{ACPI_EXD_TYPE, 0, NULL},
{ACPI_EXD_UINT16, ACPI_EXD_OFFSET(common.reference_count),
"Reference Count"},
- {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(common.flags), "Flags"}
+ {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(common.flags), "Flags"},
+ {ACPI_EXD_LIST, ACPI_EXD_OFFSET(common.next_object), "Object List"}
};
static struct acpi_exdump_info acpi_ex_dump_field_common[7] = {
@@ -274,15 +294,17 @@ static struct acpi_exdump_info acpi_ex_dump_field_common[7] = {
"Field Bit Offset"},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(common_field.base_byte_offset),
"Base Byte Offset"},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(common_field.node), "Parent Node"}
+ {ACPI_EXD_NODE, ACPI_EXD_OFFSET(common_field.node), "Parent Node"}
};
-static struct acpi_exdump_info acpi_ex_dump_node[5] = {
+static struct acpi_exdump_info acpi_ex_dump_node[7] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_node), NULL},
{ACPI_EXD_UINT8, ACPI_EXD_NSOFFSET(flags), "Flags"},
{ACPI_EXD_UINT8, ACPI_EXD_NSOFFSET(owner_id), "Owner Id"},
- {ACPI_EXD_POINTER, ACPI_EXD_NSOFFSET(child), "Child List"},
- {ACPI_EXD_POINTER, ACPI_EXD_NSOFFSET(peer), "Next Peer"}
+ {ACPI_EXD_LIST, ACPI_EXD_NSOFFSET(object), "Object List"},
+ {ACPI_EXD_NODE, ACPI_EXD_NSOFFSET(parent), "Parent"},
+ {ACPI_EXD_NODE, ACPI_EXD_NSOFFSET(child), "Child"},
+ {ACPI_EXD_NODE, ACPI_EXD_NSOFFSET(peer), "Peer"}
};
/* Dispatch table, indexed by object type */
@@ -315,7 +337,9 @@ static struct acpi_exdump_info *acpi_ex_dump_info[] = {
acpi_ex_dump_address_handler,
NULL,
NULL,
- NULL
+ NULL,
+ acpi_ex_dump_extra,
+ acpi_ex_dump_data
};
/*******************************************************************************
@@ -340,6 +364,10 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
char *name;
const char *reference_name;
u8 count;
+ union acpi_operand_object *start;
+ union acpi_operand_object *data = NULL;
+ union acpi_operand_object *next;
+ struct acpi_namespace_node *node;
if (!info) {
acpi_os_printf
@@ -363,9 +391,9 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
case ACPI_EXD_TYPE:
- acpi_ex_out_string("Type",
- acpi_ut_get_object_type_name
- (obj_desc));
+ acpi_os_printf("%20s : %2.2X [%s]\n", "Type",
+ obj_desc->common.type,
+ acpi_ut_get_object_type_name(obj_desc));
break;
case ACPI_EXD_UINT8:
@@ -433,6 +461,121 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
acpi_ex_dump_reference_obj(obj_desc);
break;
+ case ACPI_EXD_LIST:
+
+ start = *ACPI_CAST_PTR(void *, target);
+ next = start;
+
+ acpi_os_printf("%20s : %p", name, next);
+ if (next) {
+ acpi_os_printf("(%s %2.2X)",
+ acpi_ut_get_object_type_name
+ (next), next->common.type);
+
+ while (next->common.next_object) {
+ if ((next->common.type ==
+ ACPI_TYPE_LOCAL_DATA) && !data) {
+ data = next;
+ }
+
+ next = next->common.next_object;
+ acpi_os_printf("->%p(%s %2.2X)", next,
+ acpi_ut_get_object_type_name
+ (next),
+ next->common.type);
+
+ if ((next == start) || (next == data)) {
+ acpi_os_printf
+ ("\n**** Error: Object list appears to be circular linked");
+ break;
+ }
+ }
+ }
+
+ acpi_os_printf("\n", next);
+ break;
+
+ case ACPI_EXD_HDLR_LIST:
+
+ start = *ACPI_CAST_PTR(void *, target);
+ next = start;
+
+ acpi_os_printf("%20s : %p", name, next);
+ if (next) {
+ acpi_os_printf("(%s %2.2X)",
+ acpi_ut_get_object_type_name
+ (next), next->common.type);
+
+ while (next->address_space.next) {
+ if ((next->common.type ==
+ ACPI_TYPE_LOCAL_DATA) && !data) {
+ data = next;
+ }
+
+ next = next->address_space.next;
+ acpi_os_printf("->%p(%s %2.2X)", next,
+ acpi_ut_get_object_type_name
+ (next),
+ next->common.type);
+
+ if ((next == start) || (next == data)) {
+ acpi_os_printf
+ ("\n**** Error: Handler list appears to be circular linked");
+ break;
+ }
+ }
+ }
+
+ acpi_os_printf("\n", next);
+ break;
+
+ case ACPI_EXD_RGN_LIST:
+
+ start = *ACPI_CAST_PTR(void *, target);
+ next = start;
+
+ acpi_os_printf("%20s : %p", name, next);
+ if (next) {
+ acpi_os_printf("(%s %2.2X)",
+ acpi_ut_get_object_type_name
+ (next), next->common.type);
+
+ while (next->region.next) {
+ if ((next->common.type ==
+ ACPI_TYPE_LOCAL_DATA) && !data) {
+ data = next;
+ }
+
+ next = next->region.next;
+ acpi_os_printf("->%p(%s %2.2X)", next,
+ acpi_ut_get_object_type_name
+ (next),
+ next->common.type);
+
+ if ((next == start) || (next == data)) {
+ acpi_os_printf
+ ("\n**** Error: Region list appears to be circular linked");
+ break;
+ }
+ }
+ }
+
+ acpi_os_printf("\n", next);
+ break;
+
+ case ACPI_EXD_NODE:
+
+ node =
+ *ACPI_CAST_PTR(struct acpi_namespace_node *,
+ target);
+
+ acpi_os_printf("%20s : %p", name, node);
+ if (node) {
+ acpi_os_printf(" [%4.4s]", node->name.ascii);
+ }
+ acpi_os_printf("\n");
+ break;
+
default:
acpi_os_printf("**** Invalid table opcode [%X] ****\n",
@@ -821,10 +964,8 @@ void acpi_ex_dump_namespace_node(struct acpi_namespace_node *node, u32 flags)
}
acpi_os_printf("%20s : %4.4s\n", "Name", acpi_ut_get_node_name(node));
- acpi_ex_out_string("Type", acpi_ut_get_type_name(node->type));
- acpi_ex_out_pointer("Attached Object",
- acpi_ns_get_attached_object(node));
- acpi_ex_out_pointer("Parent", node->parent);
+ acpi_os_printf("%20s : %2.2X [%s]\n", "Type",
+ node->type, acpi_ut_get_type_name(node->type));
acpi_ex_dump_object(ACPI_CAST_PTR(union acpi_operand_object, node),
acpi_ex_dump_node);
@@ -1017,22 +1158,26 @@ acpi_ex_dump_object_descriptor(union acpi_operand_object *obj_desc, u32 flags)
((struct acpi_namespace_node *)obj_desc)->
object);
- acpi_ex_dump_object_descriptor(((struct acpi_namespace_node *)
- obj_desc)->object, flags);
- return_VOID;
+ obj_desc = ((struct acpi_namespace_node *)obj_desc)->object;
+ goto dump_object;
}
if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) {
- acpi_os_printf
- ("ExDumpObjectDescriptor: %p is not an ACPI operand object: [%s]\n",
- obj_desc, acpi_ut_get_descriptor_name(obj_desc));
+ acpi_os_printf("%p is not an ACPI operand object: [%s]\n",
+ obj_desc, acpi_ut_get_descriptor_name(obj_desc));
return_VOID;
}
- if (obj_desc->common.type > ACPI_TYPE_NS_NODE_MAX) {
+ /* Validate the object type */
+
+ if (obj_desc->common.type > ACPI_TYPE_LOCAL_MAX) {
+ acpi_os_printf("Not a known object type: %2.2X\n",
+ obj_desc->common.type);
return_VOID;
}
+dump_object:
+
/* Common Fields */
acpi_ex_dump_object(obj_desc, acpi_ex_dump_common);
@@ -1040,6 +1185,22 @@ acpi_ex_dump_object_descriptor(union acpi_operand_object *obj_desc, u32 flags)
/* Object-specific fields */
acpi_ex_dump_object(obj_desc, acpi_ex_dump_info[obj_desc->common.type]);
+
+ if (obj_desc->common.type == ACPI_TYPE_REGION) {
+ obj_desc = obj_desc->common.next_object;
+ if (obj_desc->common.type > ACPI_TYPE_LOCAL_MAX) {
+ acpi_os_printf
+ ("Secondary object is not a known object type: %2.2X\n",
+ obj_desc->common.type);
+
+ return_VOID;
+ }
+
+ acpi_os_printf("\nExtra attached Object (%p):\n", obj_desc);
+ acpi_ex_dump_object(obj_desc,
+ acpi_ex_dump_info[obj_desc->common.type]);
+ }
+
return_VOID;
}
diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c
index cfd875243421..68d97441432c 100644
--- a/drivers/acpi/acpica/exfield.c
+++ b/drivers/acpi/acpica/exfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c
index 49fb742d61b9..1d1b27a96c5b 100644
--- a/drivers/acpi/acpica/exfldio.c
+++ b/drivers/acpi/acpica/exfldio.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c
index 65d93607f368..2207e624f538 100644
--- a/drivers/acpi/acpica/exmisc.c
+++ b/drivers/acpi/acpica/exmisc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c
index 7be0205ad067..b49ea2a95f4f 100644
--- a/drivers/acpi/acpica/exmutex.c
+++ b/drivers/acpi/acpica/exmutex.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c
index 14689dec4960..dbb03b544e8c 100644
--- a/drivers/acpi/acpica/exnames.c
+++ b/drivers/acpi/acpica/exnames.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c
index d74cea416ca0..1b8e94104407 100644
--- a/drivers/acpi/acpica/exoparg1.c
+++ b/drivers/acpi/acpica/exoparg1.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c
index d6fa0fce1fc9..2ede656ee26a 100644
--- a/drivers/acpi/acpica/exoparg2.c
+++ b/drivers/acpi/acpica/exoparg2.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c
index bc042adf8804..363767cf01e5 100644
--- a/drivers/acpi/acpica/exoparg3.c
+++ b/drivers/acpi/acpica/exoparg3.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c
index 4459e32c683d..29e9e99f7fe3 100644
--- a/drivers/acpi/acpica/exoparg6.c
+++ b/drivers/acpi/acpica/exoparg6.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c
index 5a588611ab48..ee3f872870bc 100644
--- a/drivers/acpi/acpica/exprep.c
+++ b/drivers/acpi/acpica/exprep.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c
index 9d28867e60dc..cd5288a257a9 100644
--- a/drivers/acpi/acpica/exregion.c
+++ b/drivers/acpi/acpica/exregion.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c
index 7ca6925a87ca..ab060261b43e 100644
--- a/drivers/acpi/acpica/exresnte.c
+++ b/drivers/acpi/acpica/exresnte.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c
index 1606524312e3..3cde553bcbe1 100644
--- a/drivers/acpi/acpica/exresolv.c
+++ b/drivers/acpi/acpica/exresolv.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c
index be3f66973ee8..3af8de3fcea4 100644
--- a/drivers/acpi/acpica/exresop.c
+++ b/drivers/acpi/acpica/exresop.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c
index f0b09bf9887d..daf49f7ea311 100644
--- a/drivers/acpi/acpica/exstore.c
+++ b/drivers/acpi/acpica/exstore.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c
index 20d809d90c5b..04bd16c08f9e 100644
--- a/drivers/acpi/acpica/exstoren.c
+++ b/drivers/acpi/acpica/exstoren.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c
index 26e371073b1a..fd11018b0168 100644
--- a/drivers/acpi/acpica/exstorob.c
+++ b/drivers/acpi/acpica/exstorob.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c
index 6578dee2e51b..f7da64123ed5 100644
--- a/drivers/acpi/acpica/exsystem.c
+++ b/drivers/acpi/acpica/exsystem.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -77,7 +77,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
/* We must wait, so unlock the interpreter */
- acpi_ex_relinquish_interpreter();
+ acpi_ex_exit_interpreter();
status = acpi_os_wait_semaphore(semaphore, 1, timeout);
@@ -87,7 +87,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
/* Reacquire the interpreter */
- acpi_ex_reacquire_interpreter();
+ acpi_ex_enter_interpreter();
}
return_ACPI_STATUS(status);
@@ -123,7 +123,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
/* We must wait, so unlock the interpreter */
- acpi_ex_relinquish_interpreter();
+ acpi_ex_exit_interpreter();
status = acpi_os_acquire_mutex(mutex, timeout);
@@ -133,7 +133,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
/* Reacquire the interpreter */
- acpi_ex_reacquire_interpreter();
+ acpi_ex_enter_interpreter();
}
return_ACPI_STATUS(status);
@@ -198,7 +198,7 @@ acpi_status acpi_ex_system_do_sleep(u64 how_long)
/* Since this thread will sleep, we must release the interpreter */
- acpi_ex_relinquish_interpreter();
+ acpi_ex_exit_interpreter();
/*
* For compatibility with other ACPI implementations and to prevent
@@ -212,7 +212,7 @@ acpi_status acpi_ex_system_do_sleep(u64 how_long)
/* And now we must get the interpreter again */
- acpi_ex_reacquire_interpreter();
+ acpi_ex_enter_interpreter();
return (AE_OK);
}
diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c
index 99dc7b287d55..d9d72dff2a76 100644
--- a/drivers/acpi/acpica/exutils.c
+++ b/drivers/acpi/acpica/exutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -100,37 +100,6 @@ void acpi_ex_enter_interpreter(void)
/*******************************************************************************
*
- * FUNCTION: acpi_ex_reacquire_interpreter
- *
- * PARAMETERS: None
- *
- * RETURN: None
- *
- * DESCRIPTION: Reacquire the interpreter execution region from within the
- * interpreter code. Failure to enter the interpreter region is a
- * fatal system error. Used in conjunction with
- * relinquish_interpreter
- *
- ******************************************************************************/
-
-void acpi_ex_reacquire_interpreter(void)
-{
- ACPI_FUNCTION_TRACE(ex_reacquire_interpreter);
-
- /*
- * If the global serialized flag is set, do not release the interpreter,
- * since it was not actually released by acpi_ex_relinquish_interpreter.
- * This forces the interpreter to be single threaded.
- */
- if (!acpi_gbl_all_methods_serialized) {
- acpi_ex_enter_interpreter();
- }
-
- return_VOID;
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ex_exit_interpreter
*
* PARAMETERS: None
@@ -139,7 +108,16 @@ void acpi_ex_reacquire_interpreter(void)
*
* DESCRIPTION: Exit the interpreter execution region. This is the top level
* routine used to exit the interpreter when all processing has
- * been completed.
+ * been completed, or when the method blocks.
+ *
+ * Cases where the interpreter is unlocked internally:
+ * 1) Method will be blocked on a Sleep() AML opcode
+ * 2) Method will be blocked on an Acquire() AML opcode
+ * 3) Method will be blocked on a Wait() AML opcode
+ * 4) Method will be blocked to acquire the global lock
+ * 5) Method will be blocked waiting to execute a serialized control
+ * method that is currently executing
+ * 6) About to invoke a user-installed opregion handler
*
******************************************************************************/
@@ -160,44 +138,6 @@ void acpi_ex_exit_interpreter(void)
/*******************************************************************************
*
- * FUNCTION: acpi_ex_relinquish_interpreter
- *
- * PARAMETERS: None
- *
- * RETURN: None
- *
- * DESCRIPTION: Exit the interpreter execution region, from within the
- * interpreter - before attempting an operation that will possibly
- * block the running thread.
- *
- * Cases where the interpreter is unlocked internally
- * 1) Method to be blocked on a Sleep() AML opcode
- * 2) Method to be blocked on an Acquire() AML opcode
- * 3) Method to be blocked on a Wait() AML opcode
- * 4) Method to be blocked to acquire the global lock
- * 5) Method to be blocked waiting to execute a serialized control method
- * that is currently executing
- * 6) About to invoke a user-installed opregion handler
- *
- ******************************************************************************/
-
-void acpi_ex_relinquish_interpreter(void)
-{
- ACPI_FUNCTION_TRACE(ex_relinquish_interpreter);
-
- /*
- * If the global serialized flag is set, do not release the interpreter.
- * This forces the interpreter to be single threaded.
- */
- if (!acpi_gbl_all_methods_serialized) {
- acpi_ex_exit_interpreter();
- }
-
- return_VOID;
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ex_truncate_for32bit_table
*
* PARAMETERS: obj_desc - Object to be truncated
diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c
index 3d36df828f52..1e66d960fc11 100644
--- a/drivers/acpi/acpica/hwacpi.c
+++ b/drivers/acpi/acpica/hwacpi.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c
index 414076818d40..858fdd6be598 100644
--- a/drivers/acpi/acpica/hwesleep.c
+++ b/drivers/acpi/acpica/hwesleep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
index 96540506058f..2e6caabba07a 100644
--- a/drivers/acpi/acpica/hwgpe.c
+++ b/drivers/acpi/acpica/hwgpe.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwpci.c b/drivers/acpi/acpica/hwpci.c
index 0889a629505f..e701d8c33dbf 100644
--- a/drivers/acpi/acpica/hwpci.c
+++ b/drivers/acpi/acpica/hwpci.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c
index 12e6cff54f78..e0fd9b4978cd 100644
--- a/drivers/acpi/acpica/hwregs.c
+++ b/drivers/acpi/acpica/hwregs.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c
index e3828cc4361b..d590693eb54e 100644
--- a/drivers/acpi/acpica/hwsleep.c
+++ b/drivers/acpi/acpica/hwsleep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c
index 3c498dc1636e..76ab5c1a814e 100644
--- a/drivers/acpi/acpica/hwtimer.c
+++ b/drivers/acpi/acpica/hwtimer.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c
index eab70d58852a..6b919127cd9d 100644
--- a/drivers/acpi/acpica/hwvalid.c
+++ b/drivers/acpi/acpica/hwvalid.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c
index b4b47db2dee2..96d007df65ec 100644
--- a/drivers/acpi/acpica/hwxface.c
+++ b/drivers/acpi/acpica/hwxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c
index 15dddc10fc9b..6921c7f3d208 100644
--- a/drivers/acpi/acpica/hwxfsleep.c
+++ b/drivers/acpi/acpica/hwxfsleep.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c
index 14f65f6345b9..f1249e3463be 100644
--- a/drivers/acpi/acpica/nsaccess.c
+++ b/drivers/acpi/acpica/nsaccess.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c
index fd1ff54cda19..607eb9e5150d 100644
--- a/drivers/acpi/acpica/nsalloc.c
+++ b/drivers/acpi/acpica/nsalloc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsarguments.c b/drivers/acpi/acpica/nsarguments.c
index 74b24c82707e..80fcfc8c9c1b 100644
--- a/drivers/acpi/acpica/nsarguments.c
+++ b/drivers/acpi/acpica/nsarguments.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsconvert.c b/drivers/acpi/acpica/nsconvert.c
index acd2964c2690..b55642c4ee58 100644
--- a/drivers/acpi/acpica/nsconvert.c
+++ b/drivers/acpi/acpica/nsconvert.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c
index 48b9c6f12643..3d88ef4a3e0d 100644
--- a/drivers/acpi/acpica/nsdump.c
+++ b/drivers/acpi/acpica/nsdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c
index 283762511b73..42d37109aa5d 100644
--- a/drivers/acpi/acpica/nsdumpdv.c
+++ b/drivers/acpi/acpica/nsdumpdv.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c
index 963ceef063f8..e634a05974db 100644
--- a/drivers/acpi/acpica/nseval.c
+++ b/drivers/acpi/acpica/nseval.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c
index 3a0423af968c..a3fb7e4c0809 100644
--- a/drivers/acpi/acpica/nsinit.c
+++ b/drivers/acpi/acpica/nsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -111,9 +111,8 @@ acpi_status acpi_ns_initialize_objects(void)
info.object_count));
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "%u Control Methods found\n", info.method_count));
- ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "%u Op Regions found\n", info.op_region_count));
+ "%u Control Methods found\n%u Op Regions found\n",
+ info.method_count, info.op_region_count));
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c
index 89ec645e7730..7c9d0181f341 100644
--- a/drivers/acpi/acpica/nsload.c
+++ b/drivers/acpi/acpica/nsload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -128,12 +128,12 @@ unlock:
* parse trees.
*/
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "**** Begin Table Method Parsing and Object Initialization\n"));
+ "**** Begin Table Object Initialization\n"));
status = acpi_ds_initialize_objects(table_index, node);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "**** Completed Table Method Parsing and Object Initialization\n"));
+ "**** Completed Table Object Initialization\n"));
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c
index 90a0380fb8a0..7eee0a6f02f6 100644
--- a/drivers/acpi/acpica/nsnames.c
+++ b/drivers/acpi/acpica/nsnames.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c
index 7a736f4d1fd8..fe54a8c73b8c 100644
--- a/drivers/acpi/acpica/nsobject.c
+++ b/drivers/acpi/acpica/nsobject.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -222,13 +222,19 @@ void acpi_ns_detach_object(struct acpi_namespace_node *node)
}
}
- /* Clear the entry in all cases */
+ /* Clear the Node entry in all cases */
node->object = NULL;
if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == ACPI_DESC_TYPE_OPERAND) {
+
+ /* Unlink object from front of possible object list */
+
node->object = obj_desc->common.next_object;
+
+ /* Handle possible 2-descriptor object */
+
if (node->object &&
- ((node->object)->common.type != ACPI_TYPE_LOCAL_DATA)) {
+ (node->object->common.type != ACPI_TYPE_LOCAL_DATA)) {
node->object = node->object->common.next_object;
}
}
diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c
index 177857340271..e83cff31754b 100644
--- a/drivers/acpi/acpica/nsparse.c
+++ b/drivers/acpi/acpica/nsparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c
index d2855d9857c4..392910ffbed9 100644
--- a/drivers/acpi/acpica/nspredef.c
+++ b/drivers/acpi/acpica/nspredef.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsprepkg.c b/drivers/acpi/acpica/nsprepkg.c
index 3d5391f9bcb5..68f725839eb6 100644
--- a/drivers/acpi/acpica/nsprepkg.c
+++ b/drivers/acpi/acpica/nsprepkg.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -132,12 +132,12 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
* Decode the type of the expected package contents
*
* PTYPE1 packages contain no subpackages
- * PTYPE2 packages contain sub-packages
+ * PTYPE2 packages contain subpackages
*/
switch (package->ret_info.type) {
case ACPI_PTYPE1_FIXED:
/*
- * The package count is fixed and there are no sub-packages
+ * The package count is fixed and there are no subpackages
*
* If package is too small, exit.
* If package is larger than expected, issue warning but continue
@@ -169,7 +169,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
case ACPI_PTYPE1_VAR:
/*
- * The package count is variable, there are no sub-packages, and all
+ * The package count is variable, there are no subpackages, and all
* elements must be of the same type
*/
for (i = 0; i < count; i++) {
@@ -185,7 +185,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
case ACPI_PTYPE1_OPTION:
/*
- * The package count is variable, there are no sub-packages. There are
+ * The package count is variable, there are no subpackages. There are
* a fixed number of required elements, and a variable number of
* optional elements.
*
@@ -242,7 +242,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
elements++;
count--;
- /* Examine the sub-packages */
+ /* Examine the subpackages */
status =
acpi_ns_check_package_list(info, package, elements, count);
@@ -250,7 +250,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
case ACPI_PTYPE2_PKG_COUNT:
- /* First element is the (Integer) count of sub-packages to follow */
+ /* First element is the (Integer) count of subpackages to follow */
status = acpi_ns_check_object_type(info, elements,
ACPI_RTYPE_INTEGER, 0);
@@ -270,7 +270,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
count = expected_count;
elements++;
- /* Examine the sub-packages */
+ /* Examine the subpackages */
status =
acpi_ns_check_package_list(info, package, elements, count);
@@ -283,9 +283,9 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
case ACPI_PTYPE2_FIX_VAR:
/*
* These types all return a single Package that consists of a
- * variable number of sub-Packages.
+ * variable number of subpackages.
*
- * First, ensure that the first element is a sub-Package. If not,
+ * First, ensure that the first element is a subpackage. If not,
* the BIOS may have incorrectly returned the object as a single
* package instead of a Package of Packages (a common error if
* there is only one entry). We may be able to repair this by
@@ -310,7 +310,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
count = 1;
}
- /* Examine the sub-packages */
+ /* Examine the subpackages */
status =
acpi_ns_check_package_list(info, package, elements, count);
@@ -370,9 +370,9 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info,
u32 j;
/*
- * Validate each sub-Package in the parent Package
+ * Validate each subpackage in the parent Package
*
- * NOTE: assumes list of sub-packages contains no NULL elements.
+ * NOTE: assumes list of subpackages contains no NULL elements.
* Any NULL elements should have been removed by earlier call
* to acpi_ns_remove_null_elements.
*/
@@ -389,7 +389,7 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info,
return (status);
}
- /* Examine the different types of expected sub-packages */
+ /* Examine the different types of expected subpackages */
info->parent_package = sub_package;
switch (package->ret_info.type) {
@@ -450,14 +450,14 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info,
case ACPI_PTYPE2_FIXED:
- /* Each sub-package has a fixed length */
+ /* Each subpackage has a fixed length */
expected_count = package->ret_info2.count;
if (sub_package->package.count < expected_count) {
goto package_too_small;
}
- /* Check the type of each sub-package element */
+ /* Check the type of each subpackage element */
for (j = 0; j < expected_count; j++) {
status =
@@ -475,14 +475,14 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info,
case ACPI_PTYPE2_MIN:
- /* Each sub-package has a variable but minimum length */
+ /* Each subpackage has a variable but minimum length */
expected_count = package->ret_info.count1;
if (sub_package->package.count < expected_count) {
goto package_too_small;
}
- /* Check the type of each sub-package element */
+ /* Check the type of each subpackage element */
status =
acpi_ns_check_package_elements(info, sub_elements,
@@ -531,7 +531,7 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info,
(*sub_elements)->integer.value = expected_count;
}
- /* Check the type of each sub-package element */
+ /* Check the type of each subpackage element */
status =
acpi_ns_check_package_elements(info,
@@ -557,10 +557,10 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info,
package_too_small:
- /* The sub-package count was smaller than required */
+ /* The subpackage count was smaller than required */
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, info->node_flags,
- "Return Sub-Package[%u] is too small - found %u elements, expected %u",
+ "Return SubPackage[%u] is too small - found %u elements, expected %u",
i, sub_package->package.count, expected_count));
return (AE_AML_OPERAND_VALUE);
diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c
index a05afff50eb9..7e417aa5c91e 100644
--- a/drivers/acpi/acpica/nsrepair.c
+++ b/drivers/acpi/acpica/nsrepair.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -207,13 +207,30 @@ acpi_ns_simple_repair(struct acpi_evaluate_info *info,
* this predefined name. Either one return value is expected, or none,
* for both methods and other objects.
*
- * Exit now if there is no return object. Warning if one was expected.
+ * Try to fix if there was no return object. Warning if failed to fix.
*/
if (!return_object) {
if (expected_btypes && (!(expected_btypes & ACPI_RTYPE_NONE))) {
- ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
- ACPI_WARN_ALWAYS,
- "Missing expected return value"));
+ if (package_index != ACPI_NOT_PACKAGE_ELEMENT) {
+ ACPI_WARN_PREDEFINED((AE_INFO,
+ info->full_pathname,
+ ACPI_WARN_ALWAYS,
+ "Found unexpected NULL package element"));
+
+ status =
+ acpi_ns_repair_null_element(info,
+ expected_btypes,
+ package_index,
+ return_object_ptr);
+ if (ACPI_SUCCESS(status)) {
+ return (AE_OK); /* Repair was successful */
+ }
+ } else {
+ ACPI_WARN_PREDEFINED((AE_INFO,
+ info->full_pathname,
+ ACPI_WARN_ALWAYS,
+ "Missing expected return value"));
+ }
return (AE_AML_NO_RETURN_VALUE);
}
@@ -448,7 +465,7 @@ acpi_ns_repair_null_element(struct acpi_evaluate_info * info,
* RETURN: None.
*
* DESCRIPTION: Remove all NULL package elements from packages that contain
- * a variable number of sub-packages. For these types of
+ * a variable number of subpackages. For these types of
* packages, NULL elements can be safely removed.
*
*****************************************************************************/
@@ -469,7 +486,7 @@ acpi_ns_remove_null_elements(struct acpi_evaluate_info *info,
/*
* We can safely remove all NULL elements from these package types:
* PTYPE1_VAR packages contain a variable number of simple data types.
- * PTYPE2 packages contain a variable number of sub-packages.
+ * PTYPE2 packages contain a variable number of subpackages.
*/
switch (package_type) {
case ACPI_PTYPE1_VAR:
diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c
index 6a25d320b169..b09e6bef72b8 100644
--- a/drivers/acpi/acpica/nsrepair2.c
+++ b/drivers/acpi/acpica/nsrepair2.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -432,8 +432,8 @@ acpi_ns_repair_CID(struct acpi_evaluate_info *info,
* DESCRIPTION: Repair for the _CST object:
* 1. Sort the list ascending by C state type
* 2. Ensure type cannot be zero
- * 3. A sub-package count of zero means _CST is meaningless
- * 4. Count must match the number of C state sub-packages
+ * 3. A subpackage count of zero means _CST is meaningless
+ * 4. Count must match the number of C state subpackages
*
*****************************************************************************/
@@ -611,6 +611,7 @@ acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
union acpi_operand_object **top_object_list;
union acpi_operand_object **sub_object_list;
union acpi_operand_object *obj_desc;
+ union acpi_operand_object *sub_package;
u32 element_count;
u32 index;
@@ -619,8 +620,17 @@ acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
top_object_list = package_object->package.elements;
element_count = package_object->package.count;
- for (index = 0; index < element_count; index++) {
- sub_object_list = (*top_object_list)->package.elements;
+ /* Examine each subpackage */
+
+ for (index = 0; index < element_count; index++, top_object_list++) {
+ sub_package = *top_object_list;
+ sub_object_list = sub_package->package.elements;
+
+ /* Check for minimum required element count */
+
+ if (sub_package->package.count < 4) {
+ continue;
+ }
/*
* If the BIOS has erroneously reversed the _PRT source_name (index 2)
@@ -634,15 +644,12 @@ acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
sub_object_list[2] = obj_desc;
info->return_flags |= ACPI_OBJECT_REPAIRED;
- ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+ ACPI_WARN_PREDEFINED((AE_INFO,
+ info->full_pathname,
info->node_flags,
"PRT[%X]: Fixed reversed SourceName and SourceIndex",
index));
}
-
- /* Point to the next union acpi_operand_object in the top level package */
-
- top_object_list++;
}
return (AE_OK);
@@ -679,7 +686,7 @@ acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
u32 i;
/*
- * Entries (sub-packages) in the _PSS Package must be sorted by power
+ * Entries (subpackages) in the _PSS Package must be sorted by power
* dissipation, in descending order. If it appears that the list is
* incorrectly sorted, sort it. We sort by cpu_frequency, since this
* should be proportional to the power.
@@ -767,9 +774,9 @@ acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
*
* PARAMETERS: info - Method execution information block
* return_object - Pointer to the top-level returned object
- * start_index - Index of the first sub-package
- * expected_count - Minimum length of each sub-package
- * sort_index - Sub-package entry to sort on
+ * start_index - Index of the first subpackage
+ * expected_count - Minimum length of each subpackage
+ * sort_index - Subpackage entry to sort on
* sort_direction - Ascending or descending
* sort_key_name - Name of the sort_index field
*
@@ -805,7 +812,7 @@ acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
}
/*
- * NOTE: assumes list of sub-packages contains no NULL elements.
+ * NOTE: assumes list of subpackages contains no NULL elements.
* Any NULL elements should have been removed by earlier call
* to acpi_ns_remove_null_elements.
*/
@@ -832,7 +839,7 @@ acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
return (AE_AML_OPERAND_TYPE);
}
- /* Each sub-package must have the minimum length */
+ /* Each subpackage must have the minimum length */
if ((*outer_elements)->package.count < expected_count) {
return (AE_AML_PACKAGE_LIMIT);
diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c
index 47420faef073..af1cc42a8aa1 100644
--- a/drivers/acpi/acpica/nssearch.c
+++ b/drivers/acpi/acpica/nssearch.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c
index 4a0665b6bcc1..4a5e3f5c0ff7 100644
--- a/drivers/acpi/acpica/nsutils.c
+++ b/drivers/acpi/acpica/nsutils.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c
index e81f15ef659a..4758a1f2ce22 100644
--- a/drivers/acpi/acpica/nswalk.c
+++ b/drivers/acpi/acpica/nswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c
index 1f0c28ba50df..4bd558bf10d2 100644
--- a/drivers/acpi/acpica/nsxfeval.c
+++ b/drivers/acpi/acpica/nsxfeval.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -923,19 +923,22 @@ ACPI_EXPORT_SYMBOL(acpi_detach_data)
/*******************************************************************************
*
- * FUNCTION: acpi_get_data
+ * FUNCTION: acpi_get_data_full
*
* PARAMETERS: obj_handle - Namespace node
* handler - Handler used in call to attach_data
* data - Where the data is returned
+ * callback - function to execute before returning
*
* RETURN: Status
*
- * DESCRIPTION: Retrieve data that was previously attached to a namespace node.
+ * DESCRIPTION: Retrieve data that was previously attached to a namespace node
+ * and execute a callback before returning.
*
******************************************************************************/
acpi_status
-acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data)
+acpi_get_data_full(acpi_handle obj_handle, acpi_object_handler handler,
+ void **data, void (*callback)(void *))
{
struct acpi_namespace_node *node;
acpi_status status;
@@ -960,10 +963,34 @@ acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data)
}
status = acpi_ns_get_attached_data(node, handler, data);
+ if (ACPI_SUCCESS(status) && callback) {
+ callback(*data);
+ }
unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
return (status);
}
+ACPI_EXPORT_SYMBOL(acpi_get_data_full)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_data
+ *
+ * PARAMETERS: obj_handle - Namespace node
+ * handler - Handler used in call to attach_data
+ * data - Where the data is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Retrieve data that was previously attached to a namespace node.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data)
+{
+ return acpi_get_data_full(obj_handle, handler, data, NULL);
+}
+
ACPI_EXPORT_SYMBOL(acpi_get_data)
diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c
index 3a4bd3ff49a3..8c6c11ce9760 100644
--- a/drivers/acpi/acpica/nsxfname.c
+++ b/drivers/acpi/acpica/nsxfname.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c
index 0e6d79e462d4..dae9401be7a2 100644
--- a/drivers/acpi/acpica/nsxfobj.c
+++ b/drivers/acpi/acpica/nsxfobj.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
index 91a5a69db80c..314d314340ae 100644
--- a/drivers/acpi/acpica/psargs.c
+++ b/drivers/acpi/acpica/psargs.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c
index 065b44ae538f..b058e2390fdd 100644
--- a/drivers/acpi/acpica/psloop.c
+++ b/drivers/acpi/acpica/psloop.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -480,6 +480,10 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
status = AE_OK;
}
+ if (status == AE_CTRL_TERMINATE) {
+ return_ACPI_STATUS(status);
+ }
+
status =
acpi_ps_complete_op(walk_state, &op,
status);
diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c
index 95dc608a66a8..a6885077d59e 100644
--- a/drivers/acpi/acpica/psobject.c
+++ b/drivers/acpi/acpica/psobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -219,7 +219,10 @@ acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
status = walk_state->descending_callback(walk_state, op);
if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "During name lookup/catalog"));
+ if (status != AE_CTRL_TERMINATE) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "During name lookup/catalog"));
+ }
return_ACPI_STATUS(status);
}
@@ -230,7 +233,7 @@ acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
status = acpi_ps_next_parse_state(walk_state, *op, status);
if (ACPI_FAILURE(status)) {
if (status == AE_CTRL_PENDING) {
- return_ACPI_STATUS(AE_CTRL_PARSE_PENDING);
+ status = AE_CTRL_PARSE_PENDING;
}
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c
index 1b659e59710a..1755d2ac5656 100644
--- a/drivers/acpi/acpica/psopcode.c
+++ b/drivers/acpi/acpica/psopcode.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psopinfo.c b/drivers/acpi/acpica/psopinfo.c
index b0c9787dbe61..0d8d37ffd04d 100644
--- a/drivers/acpi/acpica/psopinfo.c
+++ b/drivers/acpi/acpica/psopinfo.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c
index 79d9a28dedef..6d27b597394e 100644
--- a/drivers/acpi/acpica/psparse.c
+++ b/drivers/acpi/acpica/psparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psscope.c b/drivers/acpi/acpica/psscope.c
index 6a4b6fb39f32..32d250feea21 100644
--- a/drivers/acpi/acpica/psscope.c
+++ b/drivers/acpi/acpica/psscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c
index 877dc0de8df3..0b64181e7720 100644
--- a/drivers/acpi/acpica/pstree.c
+++ b/drivers/acpi/acpica/pstree.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c
index 91fa73a6e55e..3cd48802eede 100644
--- a/drivers/acpi/acpica/psutils.c
+++ b/drivers/acpi/acpica/psutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/pswalk.c b/drivers/acpi/acpica/pswalk.c
index abd65624754f..9cb07e1e76d9 100644
--- a/drivers/acpi/acpica/pswalk.c
+++ b/drivers/acpi/acpica/pswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c
index fcb7a840e996..e135acaa5e1c 100644
--- a/drivers/acpi/acpica/psxface.c
+++ b/drivers/acpi/acpica/psxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsaddr.c b/drivers/acpi/acpica/rsaddr.c
index f3a9276ac665..916fd095ff34 100644
--- a/drivers/acpi/acpica/rsaddr.c
+++ b/drivers/acpi/acpica/rsaddr.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c
index b60c9cf82862..689556744b03 100644
--- a/drivers/acpi/acpica/rscalc.c
+++ b/drivers/acpi/acpica/rscalc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -636,7 +636,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
for (index = 0; index < number_of_elements; index++) {
- /* Dereference the sub-package */
+ /* Dereference the subpackage */
package_element = *top_object_list;
diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c
index 3a2ace93e62c..75d369050657 100644
--- a/drivers/acpi/acpica/rscreate.c
+++ b/drivers/acpi/acpica/rscreate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -273,7 +273,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
*/
user_prt->length = (sizeof(struct acpi_pci_routing_table) - 4);
- /* Each sub-package must be of length 4 */
+ /* Each subpackage must be of length 4 */
if ((*top_object_list)->package.count != 4) {
ACPI_ERROR((AE_INFO,
@@ -283,7 +283,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
}
/*
- * Dereference the sub-package.
+ * Dereference the subpackage.
* The sub_object_list will now point to an array of the four IRQ
* elements: [Address, Pin, Source, source_index]
*/
@@ -292,7 +292,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
/* 1) First subobject: Dereference the PRT.Address */
obj_desc = sub_object_list[0];
- if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
+ if (!obj_desc || obj_desc->common.type != ACPI_TYPE_INTEGER) {
ACPI_ERROR((AE_INFO,
"(PRT[%u].Address) Need Integer, found %s",
index,
@@ -305,7 +305,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
/* 2) Second subobject: Dereference the PRT.Pin */
obj_desc = sub_object_list[1];
- if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
+ if (!obj_desc || obj_desc->common.type != ACPI_TYPE_INTEGER) {
ACPI_ERROR((AE_INFO,
"(PRT[%u].Pin) Need Integer, found %s",
index,
@@ -394,7 +394,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
/* 4) Fourth subobject: Dereference the PRT.source_index */
obj_desc = sub_object_list[3];
- if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
+ if (!obj_desc || obj_desc->common.type != ACPI_TYPE_INTEGER) {
ACPI_ERROR((AE_INFO,
"(PRT[%u].SourceIndex) Need Integer, found %s",
index,
diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c
index 8a2d4986b0aa..c3c56b5a9788 100644
--- a/drivers/acpi/acpica/rsdump.c
+++ b/drivers/acpi/acpica/rsdump.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -47,7 +47,8 @@
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME("rsdump")
-#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUGGER)
/* Local prototypes */
static void acpi_rs_out_string(char *title, char *value);
diff --git a/drivers/acpi/acpica/rsdumpinfo.c b/drivers/acpi/acpica/rsdumpinfo.c
index 46192bd53653..2f9332d5c973 100644
--- a/drivers/acpi/acpica/rsdumpinfo.c
+++ b/drivers/acpi/acpica/rsdumpinfo.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,7 +48,7 @@
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME("rsdumpinfo")
-#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUGGER)
#define ACPI_RSD_OFFSET(f) (u8) ACPI_OFFSET (union acpi_resource_data,f)
#define ACPI_PRT_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_pci_routing_table,f)
#define ACPI_RSD_TABLE_SIZE(name) (sizeof(name) / sizeof (struct acpi_rsdump_info))
diff --git a/drivers/acpi/acpica/rsinfo.c b/drivers/acpi/acpica/rsinfo.c
index 41fed78e0de6..9d3f8a9a24bd 100644
--- a/drivers/acpi/acpica/rsinfo.c
+++ b/drivers/acpi/acpica/rsinfo.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -132,8 +132,7 @@ struct acpi_rsconvert_info *acpi_gbl_convert_resource_serial_bus_dispatch[] = {
acpi_rs_convert_uart_serial_bus,
};
-#ifdef ACPI_FUTURE_USAGE
-#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUGGER)
/* Dispatch table for resource dump functions */
@@ -168,7 +167,6 @@ struct acpi_rsdump_info *acpi_gbl_dump_serial_bus_dispatch[] = {
};
#endif
-#endif /* ACPI_FUTURE_USAGE */
/*
* Base sizes for external AML resource descriptors, indexed by internal type.
* Includes size of the descriptor header (1 byte for small descriptors,
diff --git a/drivers/acpi/acpica/rsio.c b/drivers/acpi/acpica/rsio.c
index ca183755a6f9..19d64873290a 100644
--- a/drivers/acpi/acpica/rsio.c
+++ b/drivers/acpi/acpica/rsio.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsirq.c b/drivers/acpi/acpica/rsirq.c
index 364decc1028a..3461f7db26df 100644
--- a/drivers/acpi/acpica/rsirq.c
+++ b/drivers/acpi/acpica/rsirq.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c
index 6053aa182093..77291293af64 100644
--- a/drivers/acpi/acpica/rslist.c
+++ b/drivers/acpi/acpica/rslist.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsmemory.c b/drivers/acpi/acpica/rsmemory.c
index ebc773a1b350..eab4483ff5f8 100644
--- a/drivers/acpi/acpica/rsmemory.c
+++ b/drivers/acpi/acpica/rsmemory.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c
index c99cec9cefde..41eea4bc089c 100644
--- a/drivers/acpi/acpica/rsmisc.c
+++ b/drivers/acpi/acpica/rsmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsserial.c b/drivers/acpi/acpica/rsserial.c
index fe49fc43e10f..9e8407223d95 100644
--- a/drivers/acpi/acpica/rsserial.c
+++ b/drivers/acpi/acpica/rsserial.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c
index 14a7982c9961..897a5ceb0420 100644
--- a/drivers/acpi/acpica/rsutils.c
+++ b/drivers/acpi/acpica/rsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c
index 01e476988aae..877ab9202133 100644
--- a/drivers/acpi/acpica/rsxface.c
+++ b/drivers/acpi/acpica/rsxface.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c
index 8f89263ac47e..ec14588254d4 100644
--- a/drivers/acpi/acpica/tbfadt.c
+++ b/drivers/acpi/acpica/tbfadt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c
index e4f4f02d49e7..c12003947bd5 100644
--- a/drivers/acpi/acpica/tbfind.c
+++ b/drivers/acpi/acpica/tbfind.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c
index 634357d51fe9..e3040947e9a0 100644
--- a/drivers/acpi/acpica/tbinstal.c
+++ b/drivers/acpi/acpica/tbinstal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -292,10 +292,11 @@ struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header
new_table = acpi_os_map_memory(new_address, new_table_length);
if (!new_table) {
ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY,
- "%4.4s %p Attempted physical table override failed",
+ "%4.4s " ACPI_PRINTF_UINT
+ " Attempted physical table override failed",
table_header->signature,
- ACPI_CAST_PTR(void,
- table_desc->address)));
+ ACPI_FORMAT_TO_UINT(table_desc->
+ address)));
return (NULL);
}
@@ -308,11 +309,11 @@ struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header
finish_override:
- ACPI_INFO((AE_INFO,
- "%4.4s %p %s table override, new table: %p",
+ ACPI_INFO((AE_INFO, "%4.4s " ACPI_PRINTF_UINT
+ " %s table override, new table: " ACPI_PRINTF_UINT,
table_header->signature,
- ACPI_CAST_PTR(void, table_desc->address),
- override_type, new_table));
+ ACPI_FORMAT_TO_UINT(table_desc->address),
+ override_type, ACPI_FORMAT_TO_UINT(new_table)));
/* We can now unmap/delete the original table (if fully mapped) */
diff --git a/drivers/acpi/acpica/tbprint.c b/drivers/acpi/acpica/tbprint.c
index 6866e767ba90..df3bb20ea325 100644
--- a/drivers/acpi/acpica/tbprint.c
+++ b/drivers/acpi/acpica/tbprint.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -128,15 +128,17 @@ acpi_tb_print_table_header(acpi_physical_address address,
struct acpi_table_header local_header;
/*
- * The reason that the Address is cast to a void pointer is so that we
- * can use %p which will work properly on both 32-bit and 64-bit hosts.
+ * The reason that we use ACPI_PRINTF_UINT and ACPI_FORMAT_TO_UINT is to
+ * support both 32-bit and 64-bit hosts/addresses in a consistent manner.
+ * The %p specifier does not emit uniform output on all hosts. On some,
+ * leading zeros are not supported.
*/
if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_FACS)) {
/* FACS only has signature and length fields */
- ACPI_INFO((AE_INFO, "%4.4s %p %06X",
- header->signature, ACPI_CAST_PTR(void, address),
+ ACPI_INFO((AE_INFO, "%-4.4s " ACPI_PRINTF_UINT " %06X",
+ header->signature, ACPI_FORMAT_TO_UINT(address),
header->length));
} else if (ACPI_VALIDATE_RSDP_SIG(header->signature)) {
@@ -147,8 +149,9 @@ acpi_tb_print_table_header(acpi_physical_address address,
header)->oem_id, ACPI_OEM_ID_SIZE);
acpi_tb_fix_string(local_header.oem_id, ACPI_OEM_ID_SIZE);
- ACPI_INFO((AE_INFO, "RSDP %p %06X (v%.2d %6.6s)",
- ACPI_CAST_PTR(void, address),
+ ACPI_INFO((AE_INFO,
+ "RSDP " ACPI_PRINTF_UINT " %06X (v%.2d %-6.6s)",
+ ACPI_FORMAT_TO_UINT(address),
(ACPI_CAST_PTR(struct acpi_table_rsdp, header)->
revision >
0) ? ACPI_CAST_PTR(struct acpi_table_rsdp,
@@ -162,8 +165,9 @@ acpi_tb_print_table_header(acpi_physical_address address,
acpi_tb_cleanup_table_header(&local_header, header);
ACPI_INFO((AE_INFO,
- "%4.4s %p %06X (v%.2d %6.6s %8.8s %08X %4.4s %08X)",
- local_header.signature, ACPI_CAST_PTR(void, address),
+ "%-4.4s " ACPI_PRINTF_UINT
+ " %06X (v%.2d %-6.6s %-8.8s %08X %-4.4s %08X)",
+ local_header.signature, ACPI_FORMAT_TO_UINT(address),
local_header.length, local_header.revision,
local_header.oem_id, local_header.oem_table_id,
local_header.oem_revision,
diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 6412d3c301cb..a4702eee91a8 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c
index db826eaadd1c..a1593159d9ea 100644
--- a/drivers/acpi/acpica/tbxface.c
+++ b/drivers/acpi/acpica/tbxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c
index 60b5a871833c..0909420fc776 100644
--- a/drivers/acpi/acpica/tbxfload.c
+++ b/drivers/acpi/acpica/tbxfload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c
index e4e1468877c3..65ab8fed3d5e 100644
--- a/drivers/acpi/acpica/tbxfroot.c
+++ b/drivers/acpi/acpica/tbxfroot.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utaddress.c b/drivers/acpi/acpica/utaddress.c
index 2c2b6ae5dfc4..a1acec9d2ef3 100644
--- a/drivers/acpi/acpica/utaddress.c
+++ b/drivers/acpi/acpica/utaddress.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c
index 1851762fc5b5..efac83c606dc 100644
--- a/drivers/acpi/acpica/utalloc.c
+++ b/drivers/acpi/acpica/utalloc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utbuffer.c b/drivers/acpi/acpica/utbuffer.c
index 11fde93be120..3c1699740653 100644
--- a/drivers/acpi/acpica/utbuffer.c
+++ b/drivers/acpi/acpica/utbuffer.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c
index cacd2fd9e665..78fde0aac487 100644
--- a/drivers/acpi/acpica/utcache.c
+++ b/drivers/acpi/acpica/utcache.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c
index edff4e653d9a..270c16464dd9 100644
--- a/drivers/acpi/acpica/utcopy.c
+++ b/drivers/acpi/acpica/utcopy.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -535,10 +535,10 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
case ACPI_TYPE_LOCAL_REFERENCE:
- /* TBD: should validate incoming handle */
+ /* An incoming reference is defined to be a namespace node */
- internal_object->reference.class = ACPI_REFCLASS_NAME;
- internal_object->reference.node =
+ internal_object->reference.class = ACPI_REFCLASS_REFOF;
+ internal_object->reference.object =
external_object->reference.handle;
break;
diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c
index d971c8631263..21a20ac5b1e1 100644
--- a/drivers/acpi/acpica/utdebug.c
+++ b/drivers/acpi/acpica/utdebug.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c
index b3f31dd89a45..fbfa9eca011f 100644
--- a/drivers/acpi/acpica/utdecode.c
+++ b/drivers/acpi/acpica/utdecode.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c
index c07d2227ea42..a3516de213fa 100644
--- a/drivers/acpi/acpica/utdelete.c
+++ b/drivers/acpi/acpica/utdelete.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -75,6 +75,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
union acpi_operand_object *handler_desc;
union acpi_operand_object *second_desc;
union acpi_operand_object *next_desc;
+ union acpi_operand_object *start_desc;
union acpi_operand_object **last_obj_ptr;
ACPI_FUNCTION_TRACE_PTR(ut_delete_internal_obj, object);
@@ -235,10 +236,11 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
if (handler_desc) {
next_desc =
handler_desc->address_space.region_list;
+ start_desc = next_desc;
last_obj_ptr =
&handler_desc->address_space.region_list;
- /* Remove the region object from the handler's list */
+ /* Remove the region object from the handler list */
while (next_desc) {
if (next_desc == object) {
@@ -247,10 +249,19 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
break;
}
- /* Walk the linked list of handler */
+ /* Walk the linked list of handlers */
last_obj_ptr = &next_desc->region.next;
next_desc = next_desc->region.next;
+
+ /* Prevent infinite loop if list is corrupted */
+
+ if (next_desc == start_desc) {
+ ACPI_ERROR((AE_INFO,
+ "Circular region list in address handler object %p",
+ handler_desc));
+ return_VOID;
+ }
}
if (handler_desc->address_space.handler_flags &
diff --git a/drivers/acpi/acpica/uterror.c b/drivers/acpi/acpica/uterror.c
index 154fdcaa5830..8e544d4688cd 100644
--- a/drivers/acpi/acpica/uterror.c
+++ b/drivers/acpi/acpica/uterror.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c
index 16fb90506db7..8fed1482d228 100644
--- a/drivers/acpi/acpica/uteval.c
+++ b/drivers/acpi/acpica/uteval.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utexcep.c b/drivers/acpi/acpica/utexcep.c
index 3cf7b597edb9..0403dcaabaf2 100644
--- a/drivers/acpi/acpica/utexcep.c
+++ b/drivers/acpi/acpica/utexcep.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c
index 030cb0dc673c..f3abeae9d2f8 100644
--- a/drivers/acpi/acpica/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -55,31 +55,27 @@ ACPI_MODULE_NAME("utglobal")
* Static global variable initialization.
*
******************************************************************************/
-/*
- * We want the debug switches statically initialized so they
- * are already set when the debugger is entered.
- */
-/* Debug switch - level and trace mask */
+/* Debug output control masks */
u32 acpi_dbg_level = ACPI_DEBUG_DEFAULT;
-/* Debug switch - layer (component) mask */
-
u32 acpi_dbg_layer = 0;
-u32 acpi_gbl_nesting_level = 0;
-/* Debugger globals */
+/* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */
-u8 acpi_gbl_db_terminate_threads = FALSE;
-u8 acpi_gbl_abort_method = FALSE;
-u8 acpi_gbl_method_executing = FALSE;
+struct acpi_table_fadt acpi_gbl_FADT;
+u32 acpi_gbl_trace_flags;
+acpi_name acpi_gbl_trace_method_name;
+u8 acpi_gbl_system_awake_and_running;
+u32 acpi_current_gpe_count;
-/* System flags */
-
-u32 acpi_gbl_startup_flags = 0;
-
-/* System starts uninitialized */
+/*
+ * ACPI 5.0 introduces the concept of a "reduced hardware platform", meaning
+ * that the ACPI hardware is no longer required. A flag in the FADT indicates
+ * a reduced HW machine, and that flag is duplicated here for convenience.
+ */
+u8 acpi_gbl_reduced_hardware;
-u8 acpi_gbl_shutdown = TRUE;
+/* Various state name strings */
const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = {
"\\_S0_",
@@ -335,7 +331,6 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_DSDT = NULL;
acpi_gbl_cm_single_step = FALSE;
- acpi_gbl_db_terminate_threads = FALSE;
acpi_gbl_shutdown = FALSE;
acpi_gbl_ns_lookup_count = 0;
acpi_gbl_ps_find_count = 0;
@@ -382,6 +377,10 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_disable_mem_tracking = FALSE;
#endif
+#ifdef ACPI_DEBUGGER
+ acpi_gbl_db_terminate_threads = FALSE;
+#endif
+
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c
index bfca7b4b6731..4b12880e5b11 100644
--- a/drivers/acpi/acpica/utids.c
+++ b/drivers/acpi/acpica/utids.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c
index c5d1ac44c07d..5f56fc49021e 100644
--- a/drivers/acpi/acpica/utinit.c
+++ b/drivers/acpi/acpica/utinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utlock.c b/drivers/acpi/acpica/utlock.c
index 5c26ad420344..dc6e96547f18 100644
--- a/drivers/acpi/acpica/utlock.c
+++ b/drivers/acpi/acpica/utlock.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c
index 909fe66e1934..d44dee6ee10a 100644
--- a/drivers/acpi/acpica/utmath.c
+++ b/drivers/acpi/acpica/utmath.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c
index 02f9101b65e4..2e2bb14e1099 100644
--- a/drivers/acpi/acpica/utmisc.c
+++ b/drivers/acpi/acpica/utmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c
index 08c323245584..82717fff9ffc 100644
--- a/drivers/acpi/acpica/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c
index 517af700399d..dfa9009bfc87 100644
--- a/drivers/acpi/acpica/utobject.c
+++ b/drivers/acpi/acpica/utobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c
index 8856bd37bc76..685766fc6ca8 100644
--- a/drivers/acpi/acpica/utosi.c
+++ b/drivers/acpi/acpica/utosi.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -47,6 +47,31 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utosi")
+/******************************************************************************
+ *
+ * ACPICA policy for new _OSI strings:
+ *
+ * It is the stated policy of ACPICA that new _OSI strings will be integrated
+ * into this module as soon as possible after they are defined. It is strongly
+ * recommended that all ACPICA hosts mirror this policy and integrate any
+ * changes to this module as soon as possible. There are several historical
+ * reasons behind this policy:
+ *
+ * 1) New BIOSs tend to test only the case where the host responds TRUE to
+ * the latest version of Windows, which would respond to the latest/newest
+ * _OSI string. Not responding TRUE to the latest version of Windows will
+ * risk executing untested code paths throughout the DSDT and SSDTs.
+ *
+ * 2) If a new _OSI string is recognized only after a significant delay, this
+ * has the potential to cause problems on existing working machines because
+ * of the possibility that a new and different path through the ASL code
+ * will be executed.
+ *
+ * 3) New _OSI strings are tending to come out about once per year. A delay
+ * in recognizing a new string for a significant amount of time risks the
+ * release of another string which only compounds the initial problem.
+ *
+ *****************************************************************************/
/*
* Strings supported by the _OSI predefined control method (which is
* implemented internally within this module.)
@@ -74,6 +99,7 @@ static struct acpi_interface_info acpi_default_supported_interfaces[] = {
{"Windows 2006 SP2", NULL, 0, ACPI_OSI_WIN_VISTA_SP2}, /* Windows Vista SP2 - Added 09/2010 */
{"Windows 2009", NULL, 0, ACPI_OSI_WIN_7}, /* Windows 7 and Server 2008 R2 - Added 09/2009 */
{"Windows 2012", NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8 and Server 2012 - Added 08/2012 */
+ {"Windows 2013", NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8.1 and Server 2012 R2 - Added 01/2014 */
/* Feature Group Strings */
diff --git a/drivers/acpi/acpica/utownerid.c b/drivers/acpi/acpica/utownerid.c
index eb3aca761369..36bec57ebd23 100644
--- a/drivers/acpi/acpica/utownerid.c
+++ b/drivers/acpi/acpica/utownerid.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utpredef.c b/drivers/acpi/acpica/utpredef.c
index 2b1ce4cd3207..db30caff130a 100644
--- a/drivers/acpi/acpica/utpredef.c
+++ b/drivers/acpi/acpica/utpredef.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c
index 2c2accb9e534..14cb6c0c8be2 100644
--- a/drivers/acpi/acpica/utresrc.c
+++ b/drivers/acpi/acpica/utresrc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -47,7 +47,8 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utresrc")
-#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER)
+
+#if defined(ACPI_DEBUG_OUTPUT) || defined (ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER)
/*
* Strings used to decode resource descriptors.
* Used by both the disassembler and the debugger resource dump routines
diff --git a/drivers/acpi/acpica/utstate.c b/drivers/acpi/acpica/utstate.c
index 03c4c2febd84..1cc97a752c15 100644
--- a/drivers/acpi/acpica/utstate.c
+++ b/drivers/acpi/acpica/utstate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c
index 45c0eb26b33d..77219336c7e0 100644
--- a/drivers/acpi/acpica/utstring.c
+++ b/drivers/acpi/acpica/utstring.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c
index c0027773cccb..7d0ee969d781 100644
--- a/drivers/acpi/acpica/uttrack.c
+++ b/drivers/acpi/acpica/uttrack.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -276,7 +276,8 @@ acpi_ut_free_and_track(void *allocation,
}
acpi_os_free(debug_block);
- ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "%p freed\n", allocation));
+ ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "%p freed (block %p)\n",
+ allocation, debug_block));
return_VOID;
}
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index be322c83643a..502a8492dc83 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c
index f7edb88f6054..edd861102f1b 100644
--- a/drivers/acpi/acpica/utxferror.c
+++ b/drivers/acpi/acpica/utxferror.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c
index 246ef68681f4..13380d818462 100644
--- a/drivers/acpi/acpica/utxfinit.c
+++ b/drivers/acpi/acpica/utxfinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utxfmutex.c b/drivers/acpi/acpica/utxfmutex.c
index 312299721ba1..2a0f9e04d3a4 100644
--- a/drivers/acpi/acpica/utxfmutex.c
+++ b/drivers/acpi/acpica/utxfmutex.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig
index 3650b2183227..c4dac7150960 100644
--- a/drivers/acpi/apei/Kconfig
+++ b/drivers/acpi/apei/Kconfig
@@ -12,7 +12,7 @@ config ACPI_APEI
config ACPI_APEI_GHES
bool "APEI Generic Hardware Error Source"
- depends on ACPI_APEI && X86
+ depends on ACPI_APEI
select ACPI_HED
select IRQ_WORK
select GENERIC_ALLOCATOR
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 018a42883706..9a2c63b20050 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -39,15 +39,13 @@
#include <linux/acpi.h>
#include <linux/power_supply.h>
+#include "battery.h"
+
#define PREFIX "ACPI: "
#define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
-#define ACPI_BATTERY_CLASS "battery"
#define ACPI_BATTERY_DEVICE_NAME "Battery"
-#define ACPI_BATTERY_NOTIFY_STATUS 0x80
-#define ACPI_BATTERY_NOTIFY_INFO 0x81
-#define ACPI_BATTERY_NOTIFY_THRESHOLD 0x82
/* Battery power unit: 0 means mW, 1 means mA */
#define ACPI_BATTERY_POWER_UNIT_MA 1
@@ -736,6 +734,7 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event)
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event,
acpi_battery_present(battery));
+ acpi_notifier_call_chain(device, event, acpi_battery_present(battery));
/* acpi_battery_update could remove power_supply object */
if (old && battery->bat.dev)
power_supply_changed(&battery->bat);
@@ -841,6 +840,8 @@ static int acpi_battery_resume(struct device *dev)
acpi_battery_update(battery);
return 0;
}
+#else
+#define acpi_battery_resume NULL
#endif
static SIMPLE_DEV_PM_OPS(acpi_battery_pm, NULL, acpi_battery_resume);
diff --git a/drivers/acpi/battery.h b/drivers/acpi/battery.h
new file mode 100644
index 000000000000..6c084976987d
--- /dev/null
+++ b/drivers/acpi/battery.h
@@ -0,0 +1,10 @@
+#ifndef __ACPI_BATTERY_H
+#define __ACPI_BATTERY_H
+
+#define ACPI_BATTERY_CLASS "battery"
+
+#define ACPI_BATTERY_NOTIFY_STATUS 0x80
+#define ACPI_BATTERY_NOTIFY_INFO 0x81
+#define ACPI_BATTERY_NOTIFY_THRESHOLD 0x82
+
+#endif
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index 10e4964d051a..afec4526c48a 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -260,14 +260,6 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
},
{
.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 = "ThinkPad Edge E530",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
@@ -322,56 +314,6 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_VERSION, "2349D15"),
},
},
- {
- .callback = dmi_disable_osi_win8,
- .ident = "HP ProBook 2013 models",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook "),
- DMI_MATCH(DMI_PRODUCT_NAME, " G1"),
- },
- },
- {
- .callback = dmi_disable_osi_win8,
- .ident = "HP EliteBook 2013 models",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook "),
- DMI_MATCH(DMI_PRODUCT_NAME, " G1"),
- },
- },
- {
- .callback = dmi_disable_osi_win8,
- .ident = "HP ZBook 14",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 14"),
- },
- },
- {
- .callback = dmi_disable_osi_win8,
- .ident = "HP ZBook 15",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 15"),
- },
- },
- {
- .callback = dmi_disable_osi_win8,
- .ident = "HP ZBook 17",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 17"),
- },
- },
- {
- .callback = dmi_disable_osi_win8,
- .ident = "HP EliteBook 8780w",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8780w"),
- },
- },
/*
* BIOS invocation of _OSI(Linux) is almost always a BIOS bug.
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index fcb59c21c68d..e7e5844c87d0 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -311,9 +311,7 @@ static void acpi_bus_osc_support(void)
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PPC_OST_SUPPORT;
#endif
-#ifdef ACPI_HOTPLUG_OST
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_OST_SUPPORT;
-#endif
if (!ghes_disable)
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_APEI_SUPPORT;
@@ -340,60 +338,77 @@ static void acpi_bus_osc_support(void)
*/
static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
{
- struct acpi_device *device = NULL;
+ struct acpi_device *adev;
struct acpi_driver *driver;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n",
- type, handle));
+ acpi_status status;
+ u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
switch (type) {
-
case ACPI_NOTIFY_BUS_CHECK:
- /* TBD */
+ acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
break;
case ACPI_NOTIFY_DEVICE_CHECK:
- /* TBD */
+ acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
break;
case ACPI_NOTIFY_DEVICE_WAKE:
- /* TBD */
+ acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_WAKE event\n");
break;
case ACPI_NOTIFY_EJECT_REQUEST:
- /* TBD */
+ acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
break;
case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
+ acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK_LIGHT event\n");
/* TBD: Exactly what does 'light' mean? */
break;
case ACPI_NOTIFY_FREQUENCY_MISMATCH:
- /* TBD */
+ acpi_handle_err(handle, "Device cannot be configured due "
+ "to a frequency mismatch\n");
break;
case ACPI_NOTIFY_BUS_MODE_MISMATCH:
- /* TBD */
+ acpi_handle_err(handle, "Device cannot be configured due "
+ "to a bus mode mismatch\n");
break;
case ACPI_NOTIFY_POWER_FAULT:
- /* TBD */
+ acpi_handle_err(handle, "Device has suffered a power fault\n");
break;
default:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Received unknown/unsupported notification [%08x]\n",
- type));
- break;
+ acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
+ ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY;
+ goto err;
}
- acpi_bus_get_device(handle, &device);
- if (device) {
- driver = device->driver;
- if (driver && driver->ops.notify &&
- (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
- driver->ops.notify(device, type);
+ adev = acpi_bus_get_acpi_device(handle);
+ if (!adev)
+ goto err;
+
+ driver = adev->driver;
+ if (driver && driver->ops.notify &&
+ (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
+ driver->ops.notify(adev, type);
+
+ switch (type) {
+ case ACPI_NOTIFY_BUS_CHECK:
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ case ACPI_NOTIFY_EJECT_REQUEST:
+ status = acpi_hotplug_schedule(adev, type);
+ if (ACPI_SUCCESS(status))
+ return;
+ default:
+ break;
}
+ acpi_bus_put_acpi_device(adev);
+ return;
+
+ err:
+ acpi_evaluate_ost(handle, type, ost_code, NULL);
}
/* --------------------------------------------------------------------------
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 11c11f6b8fa1..db35594d4df7 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -80,6 +80,8 @@ static void acpi_button_notify(struct acpi_device *device, u32 event);
#ifdef CONFIG_PM_SLEEP
static int acpi_button_resume(struct device *dev);
+#else
+#define acpi_button_resume NULL
#endif
static SIMPLE_DEV_PM_OPS(acpi_button_pm, NULL, acpi_button_resume);
@@ -300,6 +302,10 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
input_sync(input);
pm_wakeup_event(&device->dev, 0);
+ acpi_bus_generate_netlink_event(
+ device->pnp.device_class,
+ dev_name(&device->dev),
+ event, ++button->pushed);
}
break;
default:
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 0b6ae6eb5c4a..63119d09b354 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -31,8 +31,6 @@
#include "internal.h"
-#define PREFIX "ACPI: "
-
#define _COMPONENT ACPI_CONTAINER_COMPONENT
ACPI_MODULE_NAME("container");
@@ -68,6 +66,9 @@ static int container_device_attach(struct acpi_device *adev,
struct device *dev;
int ret;
+ if (adev->flags.is_dock_station)
+ return 0;
+
cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
if (!cdev)
return -ENOMEM;
@@ -79,9 +80,10 @@ static int container_device_attach(struct acpi_device *adev,
ACPI_COMPANION_SET(dev, adev);
dev->release = acpi_container_release;
ret = device_register(dev);
- if (ret)
+ if (ret) {
+ put_device(dev);
return ret;
-
+ }
adev->driver_data = dev;
return 1;
}
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index c14a00d3dca6..d047739f3380 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -901,15 +901,30 @@ EXPORT_SYMBOL_GPL(acpi_dev_resume_early);
int acpi_subsys_prepare(struct device *dev)
{
/*
- * Follow PCI and resume devices suspended at run time before running
- * their system suspend callbacks.
+ * Devices having power.ignore_children set may still be necessary for
+ * suspending their children in the next phase of device suspend.
*/
- pm_runtime_resume(dev);
+ if (dev->power.ignore_children)
+ pm_runtime_resume(dev);
+
return pm_generic_prepare(dev);
}
EXPORT_SYMBOL_GPL(acpi_subsys_prepare);
/**
+ * acpi_subsys_suspend - Run the device driver's suspend callback.
+ * @dev: Device to handle.
+ *
+ * Follow PCI and resume devices suspended at run time before running their
+ * system suspend callbacks.
+ */
+int acpi_subsys_suspend(struct device *dev)
+{
+ pm_runtime_resume(dev);
+ return pm_generic_suspend(dev);
+}
+
+/**
* acpi_subsys_suspend_late - Suspend device using ACPI.
* @dev: Device to suspend.
*
@@ -937,6 +952,23 @@ int acpi_subsys_resume_early(struct device *dev)
return ret ? ret : pm_generic_resume_early(dev);
}
EXPORT_SYMBOL_GPL(acpi_subsys_resume_early);
+
+/**
+ * acpi_subsys_freeze - Run the device driver's freeze callback.
+ * @dev: Device to handle.
+ */
+int acpi_subsys_freeze(struct device *dev)
+{
+ /*
+ * This used to be done in acpi_subsys_prepare() for all devices and
+ * some drivers may depend on it, so do it here. Ideally, however,
+ * runtime-suspended devices should not be touched during freeze/thaw
+ * transitions.
+ */
+ pm_runtime_resume(dev);
+ return pm_generic_freeze(dev);
+}
+
#endif /* CONFIG_PM_SLEEP */
static struct dev_pm_domain acpi_general_pm_domain = {
@@ -947,8 +979,11 @@ static struct dev_pm_domain acpi_general_pm_domain = {
#endif
#ifdef CONFIG_PM_SLEEP
.prepare = acpi_subsys_prepare,
+ .suspend = acpi_subsys_suspend,
.suspend_late = acpi_subsys_suspend_late,
.resume_early = acpi_subsys_resume_early,
+ .freeze = acpi_subsys_freeze,
+ .poweroff = acpi_subsys_suspend,
.poweroff_late = acpi_subsys_suspend_late,
.restore_early = acpi_subsys_resume_early,
#endif
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index c431c88faaff..f0fc6260266b 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -1,7 +1,9 @@
/*
* dock.c - ACPI dock station driver
*
- * Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.com>
+ * Copyright (C) 2006, 2014, Intel Corp.
+ * Author: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
+ * Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
@@ -35,8 +37,6 @@
#include "internal.h"
-#define PREFIX "ACPI: "
-
#define ACPI_DOCK_DRIVER_DESCRIPTION "ACPI Dock Station Driver"
ACPI_MODULE_NAME("dock");
@@ -68,15 +68,10 @@ struct dock_station {
};
static LIST_HEAD(dock_stations);
static int dock_station_count;
-static DEFINE_MUTEX(hotplug_lock);
struct dock_dependent_device {
struct list_head list;
- acpi_handle handle;
- const struct acpi_dock_ops *hp_ops;
- void *hp_context;
- unsigned int hp_refcount;
- void (*hp_release)(void *);
+ struct acpi_device *adev;
};
#define DOCK_DOCKING 0x00000001
@@ -98,13 +93,13 @@ enum dock_callback_type {
*****************************************************************************/
/**
* add_dock_dependent_device - associate a device with the dock station
- * @ds: The dock station
- * @handle: handle of the dependent device
+ * @ds: Dock station.
+ * @adev: Dependent ACPI device object.
*
* Add the dependent device to the dock's dependent device list.
*/
-static int __init
-add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
+static int add_dock_dependent_device(struct dock_station *ds,
+ struct acpi_device *adev)
{
struct dock_dependent_device *dd;
@@ -112,180 +107,120 @@ add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
if (!dd)
return -ENOMEM;
- dd->handle = handle;
+ dd->adev = adev;
INIT_LIST_HEAD(&dd->list);
list_add_tail(&dd->list, &ds->dependent_devices);
return 0;
}
-static void remove_dock_dependent_devices(struct dock_station *ds)
+static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
+ enum dock_callback_type cb_type)
{
- struct dock_dependent_device *dd, *aux;
+ struct acpi_device *adev = dd->adev;
- list_for_each_entry_safe(dd, aux, &ds->dependent_devices, list) {
- list_del(&dd->list);
- kfree(dd);
- }
-}
+ acpi_lock_hp_context();
-/**
- * dock_init_hotplug - Initialize a hotplug device on a docking station.
- * @dd: Dock-dependent device.
- * @ops: Dock operations to attach to the dependent device.
- * @context: Data to pass to the @ops callbacks and @release.
- * @init: Optional initialization routine to run after setting up context.
- * @release: Optional release routine to run on removal.
- */
-static int dock_init_hotplug(struct dock_dependent_device *dd,
- const struct acpi_dock_ops *ops, void *context,
- void (*init)(void *), void (*release)(void *))
-{
- int ret = 0;
+ if (!adev->hp)
+ goto out;
- mutex_lock(&hotplug_lock);
- 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);
- }
- mutex_unlock(&hotplug_lock);
- return ret;
-}
+ if (cb_type == DOCK_CALL_FIXUP) {
+ void (*fixup)(struct acpi_device *);
-/**
- * dock_release_hotplug - Decrement hotplug reference counter of dock device.
- * @dd: Dock-dependent device.
- *
- * Decrement the reference counter of @dd and if 0, detach its hotplug
- * operations from it, reset its context pointer and run the optional release
- * routine if present.
- */
-static void dock_release_hotplug(struct dock_dependent_device *dd)
-{
- 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;
- dd->hp_context = NULL;
- dd->hp_release = NULL;
- if (release)
- release(context);
- }
- mutex_unlock(&hotplug_lock);
-}
+ fixup = adev->hp->fixup;
+ if (fixup) {
+ acpi_unlock_hp_context();
+ fixup(adev);
+ return;
+ }
+ } else if (cb_type == DOCK_CALL_UEVENT) {
+ void (*uevent)(struct acpi_device *, u32);
+
+ uevent = adev->hp->uevent;
+ if (uevent) {
+ acpi_unlock_hp_context();
+ uevent(adev, event);
+ return;
+ }
+ } else {
+ int (*notify)(struct acpi_device *, u32);
-static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
- enum dock_callback_type cb_type)
-{
- acpi_notify_handler cb = NULL;
- bool run = false;
-
- mutex_lock(&hotplug_lock);
-
- if (dd->hp_context) {
- run = true;
- dd->hp_refcount++;
- 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;
- }
+ notify = adev->hp->notify;
+ if (notify) {
+ acpi_unlock_hp_context();
+ notify(adev, event);
+ return;
}
}
- mutex_unlock(&hotplug_lock);
+ out:
+ acpi_unlock_hp_context();
+}
- if (!run)
- return;
+static struct dock_station *find_dock_station(acpi_handle handle)
+{
+ struct dock_station *ds;
- if (cb)
- cb(dd->handle, event, dd->hp_context);
+ list_for_each_entry(ds, &dock_stations, sibling)
+ if (ds->handle == handle)
+ return ds;
- dock_release_hotplug(dd);
+ return NULL;
}
/**
* find_dock_dependent_device - get a device dependent on this dock
* @ds: the dock station
- * @handle: the acpi_handle of the device we want
+ * @adev: ACPI device object to find.
*
* iterate over the dependent device list for this dock. If the
* dependent device matches the handle, return.
*/
static struct dock_dependent_device *
-find_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
+find_dock_dependent_device(struct dock_station *ds, struct acpi_device *adev)
{
struct dock_dependent_device *dd;
list_for_each_entry(dd, &ds->dependent_devices, list)
- if (handle == dd->handle)
+ if (adev == dd->adev)
return dd;
return NULL;
}
-/*****************************************************************************
- * Dock functions *
- *****************************************************************************/
-static int __init is_battery(acpi_handle handle)
+void register_dock_dependent_device(struct acpi_device *adev,
+ acpi_handle dshandle)
{
- struct acpi_device_info *info;
- int ret = 1;
+ struct dock_station *ds = find_dock_station(dshandle);
- if (!ACPI_SUCCESS(acpi_get_object_info(handle, &info)))
- return 0;
- if (!(info->valid & ACPI_VALID_HID))
- ret = 0;
- else
- ret = !strcmp("PNP0C0A", info->hardware_id.string);
-
- kfree(info);
- return ret;
+ if (ds && !find_dock_dependent_device(ds, adev))
+ add_dock_dependent_device(ds, adev);
}
-/* Check whether ACPI object is an ejectable battery or disk bay */
-static bool __init is_ejectable_bay(acpi_handle handle)
-{
- if (acpi_has_method(handle, "_EJ0") && is_battery(handle))
- return true;
-
- return acpi_bay_match(handle);
-}
+/*****************************************************************************
+ * Dock functions *
+ *****************************************************************************/
/**
* is_dock_device - see if a device is on a dock station
- * @handle: acpi handle of the device
+ * @adev: ACPI device object to check.
*
* If this device is either the dock station itself,
* or is a device dependent on the dock station, then it
* is a dock device
*/
-int is_dock_device(acpi_handle handle)
+int is_dock_device(struct acpi_device *adev)
{
struct dock_station *dock_station;
if (!dock_station_count)
return 0;
- if (acpi_dock_match(handle))
+ if (acpi_dock_match(adev->handle))
return 1;
list_for_each_entry(dock_station, &dock_stations, sibling)
- if (find_dock_dependent_device(dock_station, handle))
+ if (find_dock_dependent_device(dock_station, adev))
return 1;
return 0;
@@ -313,43 +248,6 @@ static int dock_present(struct dock_station *ds)
}
/**
- * dock_create_acpi_device - add new devices to acpi
- * @handle - handle of the device to add
- *
- * This function will create a new acpi_device for the given
- * 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.
- */
-static void dock_create_acpi_device(acpi_handle handle)
-{
- struct acpi_device *device = NULL;
- int ret;
-
- acpi_bus_get_device(handle, &device);
- if (!acpi_device_enumerated(device)) {
- ret = acpi_bus_scan(handle);
- if (ret)
- pr_debug("error adding bus, %x\n", -ret);
- }
-}
-
-/**
- * dock_remove_acpi_device - remove the acpi_device struct from acpi
- * @handle - the handle of the device to remove
- *
- * Tell acpi to remove the acpi_device. This should cause any loaded
- * driver to have it's remove routine called.
- */
-static void dock_remove_acpi_device(acpi_handle handle)
-{
- struct acpi_device *device;
-
- if (!acpi_bus_get_device(handle, &device))
- acpi_bus_trim(device);
-}
-
-/**
* hot_remove_dock_devices - Remove dock station devices.
* @ds: Dock station.
*/
@@ -366,7 +264,7 @@ static void hot_remove_dock_devices(struct dock_station *ds)
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);
+ acpi_bus_trim(dd->adev);
}
/**
@@ -392,12 +290,20 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
dock_hotplug_event(dd, event, DOCK_CALL_HANDLER);
/*
- * 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.
+ * Check if all devices have been enumerated already. If not, run
+ * acpi_bus_scan() for them and 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)
- dock_create_acpi_device(dd->handle);
+ list_for_each_entry(dd, &ds->dependent_devices, list) {
+ struct acpi_device *adev = dd->adev;
+
+ if (!acpi_device_enumerated(adev)) {
+ int ret = acpi_bus_scan(adev->handle);
+ if (ret)
+ dev_dbg(&adev->dev, "scan error %d\n", -ret);
+ }
+ }
}
static void dock_event(struct dock_station *ds, u32 event, int num)
@@ -501,71 +407,6 @@ static int dock_in_progress(struct dock_station *ds)
}
/**
- * register_hotplug_dock_device - register a hotplug function
- * @handle: the handle of the device
- * @ops: handlers to call after docking
- * @context: device specific data
- * @init: Optional initialization routine to run after registration
- * @release: Optional release routine to run on unregistration
- *
- * If a driver would like to perform a hotplug operation after a dock
- * event, they can register an acpi_notifiy_handler to be called by
- * the dock driver after _DCK is executed.
- */
-int register_hotplug_dock_device(acpi_handle handle,
- const struct acpi_dock_ops *ops, void *context,
- void (*init)(void *), void (*release)(void *))
-{
- struct dock_dependent_device *dd;
- struct dock_station *dock_station;
- int ret = -EINVAL;
-
- if (WARN_ON(!context))
- return -EINVAL;
-
- if (!dock_station_count)
- return -ENODEV;
-
- /*
- * make sure this handle is for a device dependent on the dock,
- * this would include the dock station itself
- */
- list_for_each_entry(dock_station, &dock_stations, sibling) {
- /*
- * An ATA bay can be in a dock and itself can be ejected
- * separately, so there are two 'dock stations' which need the
- * ops
- */
- dd = find_dock_dependent_device(dock_station, handle);
- if (dd && !dock_init_hotplug(dd, ops, context, init, release))
- ret = 0;
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(register_hotplug_dock_device);
-
-/**
- * unregister_hotplug_dock_device - remove yourself from the hotplug list
- * @handle: the acpi handle of the device
- */
-void unregister_hotplug_dock_device(acpi_handle handle)
-{
- struct dock_dependent_device *dd;
- struct dock_station *dock_station;
-
- if (!dock_station_count)
- return;
-
- list_for_each_entry(dock_station, &dock_stations, sibling) {
- dd = find_dock_dependent_device(dock_station, handle);
- if (dd)
- dock_release_hotplug(dd);
- }
-}
-EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
-
-/**
* handle_eject_request - handle an undock request checking for error conditions
*
* Check to make sure the dock device is still present, then undock and
@@ -598,20 +439,23 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
}
/**
- * dock_notify - act upon an acpi dock notification
- * @ds: dock station
- * @event: the acpi event
+ * dock_notify - Handle ACPI dock notification.
+ * @adev: Dock station's ACPI device object.
+ * @event: Event code.
*
* 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(struct dock_station *ds, u32 event)
+int dock_notify(struct acpi_device *adev, u32 event)
{
- acpi_handle handle = ds->handle;
- struct acpi_device *ad;
+ acpi_handle handle = adev->handle;
+ struct dock_station *ds = find_dock_station(handle);
int surprise_removal = 0;
+ if (!ds)
+ return -ENODEV;
+
/*
* According to acpi spec 3.0a, if a DEVICE_CHECK notification
* is sent and _DCK is present, it is assumed to mean an undock
@@ -632,7 +476,7 @@ static void dock_notify(struct dock_station *ds, u32 event)
switch (event) {
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
- if (!dock_in_progress(ds) && acpi_bus_get_device(handle, &ad)) {
+ if (!dock_in_progress(ds) && !acpi_device_enumerated(adev)) {
begin_dock(ds);
dock(ds);
if (!dock_present(ds)) {
@@ -661,49 +505,8 @@ static void dock_notify(struct dock_station *ds, u32 event)
else
dock_event(ds, event, UNDOCK_EVENT);
break;
- default:
- acpi_handle_err(handle, "Unknown dock event %d\n", event);
}
-}
-
-static void acpi_dock_deferred_cb(void *data, u32 event)
-{
- acpi_scan_lock_acquire();
- dock_notify(data, event);
- acpi_scan_lock_release();
-}
-
-static void dock_notify_handler(acpi_handle handle, u32 event, void *data)
-{
- if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
- && event != ACPI_NOTIFY_EJECT_REQUEST)
- return;
-
- acpi_hotplug_execute(acpi_dock_deferred_cb, data, event);
-}
-
-/**
- * find_dock_devices - find devices on the dock station
- * @handle: the handle of the device we are examining
- * @lvl: unused
- * @context: the dock station private data
- * @rv: unused
- *
- * This function is called by acpi_walk_namespace. It will
- * 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 __init find_dock_devices(acpi_handle handle, u32 lvl,
- void *context, void **rv)
-{
- struct dock_station *ds = context;
- acpi_handle ejd = NULL;
-
- acpi_bus_get_ejd(handle, &ejd);
- if (ejd == ds->handle)
- add_dock_dependent_device(ds, handle);
-
- return AE_OK;
+ return 0;
}
/*
@@ -712,13 +515,11 @@ static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl,
static ssize_t show_docked(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct acpi_device *tmp;
-
struct dock_station *dock_station = dev->platform_data;
+ struct acpi_device *adev = NULL;
- if (!acpi_bus_get_device(dock_station->handle, &tmp))
- return snprintf(buf, PAGE_SIZE, "1\n");
- return snprintf(buf, PAGE_SIZE, "0\n");
+ acpi_bus_get_device(dock_station->handle, &adev);
+ return snprintf(buf, PAGE_SIZE, "%u\n", acpi_device_enumerated(adev));
}
static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
@@ -804,23 +605,28 @@ static struct attribute_group dock_attribute_group = {
};
/**
- * dock_add - add a new dock station
- * @handle: the dock station handle
+ * acpi_dock_add - Add a new dock station
+ * @adev: Dock station ACPI device object.
*
- * allocated and initialize a new dock station device. Find all devices
- * that are on the dock station, and register for dock event notifications.
+ * allocated and initialize a new dock station device.
*/
-static int __init dock_add(acpi_handle handle)
+void acpi_dock_add(struct acpi_device *adev)
{
struct dock_station *dock_station, ds = { NULL, };
+ struct platform_device_info pdevinfo;
+ acpi_handle handle = adev->handle;
struct platform_device *dd;
- acpi_status status;
int ret;
- dd = platform_device_register_data(NULL, "dock", dock_station_count,
- &ds, sizeof(ds));
+ memset(&pdevinfo, 0, sizeof(pdevinfo));
+ pdevinfo.name = "dock";
+ pdevinfo.id = dock_station_count;
+ pdevinfo.acpi_node.companion = adev;
+ pdevinfo.data = &ds;
+ pdevinfo.size_data = sizeof(ds);
+ dd = platform_device_register_full(&pdevinfo);
if (IS_ERR(dd))
- return PTR_ERR(dd);
+ return;
dock_station = dd->dev.platform_data;
@@ -838,72 +644,29 @@ static int __init dock_add(acpi_handle handle)
dock_station->flags |= DOCK_IS_DOCK;
if (acpi_ata_match(handle))
dock_station->flags |= DOCK_IS_ATA;
- if (is_battery(handle))
+ if (acpi_device_is_battery(adev))
dock_station->flags |= DOCK_IS_BAT;
ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group);
if (ret)
goto err_unregister;
- /* Find dependent devices */
- acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX, find_dock_devices, NULL,
- dock_station, NULL);
-
/* add the dock station as a device dependent on itself */
- ret = add_dock_dependent_device(dock_station, handle);
+ ret = add_dock_dependent_device(dock_station, adev);
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;
+ adev->flags.is_dock_station = true;
+ dev_info(&adev->dev, "ACPI dock station (docks/bays count: %d)\n",
+ dock_station_count);
+ return;
err_rmgroup:
- remove_dock_dependent_devices(dock_station);
sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group);
+
err_unregister:
platform_device_unregister(dd);
acpi_handle_err(handle, "%s encountered error %d\n", __func__, ret);
- return ret;
-}
-
-/**
- * find_dock_and_bay - look for dock stations and bays
- * @handle: acpi handle of a device
- * @lvl: unused
- * @context: unused
- * @rv: unused
- *
- * This is called by acpi_walk_namespace to look for dock stations and bays.
- */
-static acpi_status __init
-find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
- if (acpi_dock_match(handle) || is_ejectable_bay(handle))
- dock_add(handle);
-
- return AE_OK;
-}
-
-void __init acpi_dock_init(void)
-{
- /* look for dock stations and bays */
- acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX, find_dock_and_bay, NULL, NULL, NULL);
-
- if (!dock_station_count) {
- pr_info(PREFIX "No dock devices found.\n");
- return;
- }
-
- 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 959d41acc108..d7d32c28829b 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -67,6 +67,8 @@ enum ec_command {
#define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
#define ACPI_EC_MSI_UDELAY 550 /* Wait 550us for MSI EC */
+#define ACPI_EC_CLEAR_MAX 100 /* Maximum number of events to query
+ * when trying to clear the EC */
enum {
EC_FLAGS_QUERY_PENDING, /* Query is pending */
@@ -116,6 +118,7 @@ EXPORT_SYMBOL(first_ec);
static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
+static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
/* --------------------------------------------------------------------------
Transaction Management
@@ -440,6 +443,29 @@ acpi_handle ec_get_handle(void)
EXPORT_SYMBOL(ec_get_handle);
+static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data);
+
+/*
+ * Clears stale _Q events that might have accumulated in the EC.
+ * Run with locked ec mutex.
+ */
+static void acpi_ec_clear(struct acpi_ec *ec)
+{
+ int i, status;
+ u8 value = 0;
+
+ for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) {
+ status = acpi_ec_query_unlocked(ec, &value);
+ if (status || !value)
+ break;
+ }
+
+ if (unlikely(i == ACPI_EC_CLEAR_MAX))
+ pr_warn("Warning: Maximum of %d stale EC events cleared\n", i);
+ else
+ pr_info("%d stale EC events cleared\n", i);
+}
+
void acpi_ec_block_transactions(void)
{
struct acpi_ec *ec = first_ec;
@@ -463,6 +489,10 @@ void acpi_ec_unblock_transactions(void)
mutex_lock(&ec->mutex);
/* Allow transactions to be carried out again */
clear_bit(EC_FLAGS_BLOCKED, &ec->flags);
+
+ if (EC_FLAGS_CLEAR_ON_RESUME)
+ acpi_ec_clear(ec);
+
mutex_unlock(&ec->mutex);
}
@@ -821,6 +851,13 @@ static int acpi_ec_add(struct acpi_device *device)
/* EC is fully operational, allow queries */
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
+
+ /* Clear stale _Q events if hardware might require that */
+ if (EC_FLAGS_CLEAR_ON_RESUME) {
+ mutex_lock(&ec->mutex);
+ acpi_ec_clear(ec);
+ mutex_unlock(&ec->mutex);
+ }
return ret;
}
@@ -922,6 +959,30 @@ static int ec_enlarge_storm_threshold(const struct dmi_system_id *id)
return 0;
}
+/*
+ * On some hardware it is necessary to clear events accumulated by the EC during
+ * sleep. These ECs stop reporting GPEs until they are manually polled, if too
+ * many events are accumulated. (e.g. Samsung Series 5/9 notebooks)
+ *
+ * https://bugzilla.kernel.org/show_bug.cgi?id=44161
+ *
+ * Ideally, the EC should also be instructed NOT to accumulate events during
+ * sleep (which Windows seems to do somehow), but the interface to control this
+ * behaviour is not known at this time.
+ *
+ * Models known to be affected are Samsung 530Uxx/535Uxx/540Uxx/550Pxx/900Xxx,
+ * however it is very likely that other Samsung models are affected.
+ *
+ * On systems which don't accumulate _Q events during sleep, this extra check
+ * should be harmless.
+ */
+static int ec_clear_on_resume(const struct dmi_system_id *id)
+{
+ pr_debug("Detected system needing EC poll on resume.\n");
+ EC_FLAGS_CLEAR_ON_RESUME = 1;
+ return 0;
+}
+
static struct dmi_system_id ec_dmi_table[] __initdata = {
{
ec_skip_dsdt_scan, "Compal JFL92", {
@@ -965,6 +1026,9 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
ec_validate_ecdt, "ASUS hardware", {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek Computer Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),}, NULL},
+ {
+ ec_clear_on_resume, "Samsung hardware", {
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
{},
};
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 1fb62900f32a..8acf53e62966 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -55,8 +55,16 @@ MODULE_DEVICE_TABLE(acpi, fan_device_ids);
#ifdef CONFIG_PM_SLEEP
static int acpi_fan_suspend(struct device *dev);
static int acpi_fan_resume(struct device *dev);
+static struct dev_pm_ops acpi_fan_pm = {
+ .resume = acpi_fan_resume,
+ .freeze = acpi_fan_suspend,
+ .thaw = acpi_fan_resume,
+ .restore = acpi_fan_resume,
+};
+#define FAN_PM_OPS_PTR (&acpi_fan_pm)
+#else
+#define FAN_PM_OPS_PTR NULL
#endif
-static SIMPLE_DEV_PM_OPS(acpi_fan_pm, acpi_fan_suspend, acpi_fan_resume);
static struct acpi_driver acpi_fan_driver = {
.name = "fan",
@@ -66,7 +74,7 @@ static struct acpi_driver acpi_fan_driver = {
.add = acpi_fan_add,
.remove = acpi_fan_remove,
},
- .drv.pm = &acpi_fan_pm,
+ .drv.pm = FAN_PM_OPS_PTR,
};
/* thermal cooling device callbacks */
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 0c789224d40d..f774c65ecb8b 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -287,6 +287,7 @@ EXPORT_SYMBOL_GPL(acpi_unbind_one);
static int acpi_platform_notify(struct device *dev)
{
struct acpi_bus_type *type = acpi_get_bus_type(dev);
+ struct acpi_device *adev;
int ret;
ret = acpi_bind_one(dev, NULL);
@@ -303,9 +304,14 @@ static int acpi_platform_notify(struct device *dev)
if (ret)
goto out;
}
+ adev = ACPI_COMPANION(dev);
+ if (!adev)
+ goto out;
if (type && type->setup)
type->setup(dev);
+ else if (adev->handler && adev->handler->bind)
+ adev->handler->bind(dev);
out:
#if ACPI_GLUE_DEBUG
@@ -324,11 +330,17 @@ static int acpi_platform_notify(struct device *dev)
static int acpi_platform_notify_remove(struct device *dev)
{
+ struct acpi_device *adev = ACPI_COMPANION(dev);
struct acpi_bus_type *type;
+ if (!adev)
+ return 0;
+
type = acpi_get_bus_type(dev);
if (type && type->cleanup)
type->cleanup(dev);
+ else if (adev->handler && adev->handler->unbind)
+ adev->handler->unbind(dev);
acpi_unbind_one(dev);
return 0;
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index dedbb2d802f1..957391306cbf 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -37,9 +37,15 @@ void acpi_container_init(void);
static inline void acpi_container_init(void) {}
#endif
#ifdef CONFIG_ACPI_DOCK
-void acpi_dock_init(void);
+void register_dock_dependent_device(struct acpi_device *adev,
+ acpi_handle dshandle);
+int dock_notify(struct acpi_device *adev, u32 event);
+void acpi_dock_add(struct acpi_device *adev);
#else
-static inline void acpi_dock_init(void) {}
+static inline void register_dock_dependent_device(struct acpi_device *adev,
+ acpi_handle dshandle) {}
+static inline int dock_notify(struct acpi_device *adev, u32 event) { return -ENODEV; }
+static inline void acpi_dock_add(struct acpi_device *adev) {}
#endif
#ifdef CONFIG_ACPI_HOTPLUG_MEMORY
void acpi_memory_hotplug_init(void);
@@ -72,7 +78,9 @@ void acpi_lpss_init(void);
static inline void acpi_lpss_init(void) {}
#endif
+acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src);
bool acpi_queue_hotplug_work(struct work_struct *work);
+void acpi_device_hotplug(struct acpi_device *adev, u32 src);
bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent);
/* --------------------------------------------------------------------------
@@ -90,6 +98,7 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
int acpi_bind_one(struct device *dev, struct acpi_device *adev);
int acpi_unbind_one(struct device *dev);
bool acpi_device_is_present(struct acpi_device *adev);
+bool acpi_device_is_battery(struct acpi_device *adev);
/* --------------------------------------------------------------------------
Power Resource
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 9e6816ef280a..24b5476449a1 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -60,7 +60,7 @@ int node_to_pxm(int node)
return node_to_pxm_map[node];
}
-void __acpi_map_pxm_to_node(int pxm, int node)
+static void __acpi_map_pxm_to_node(int pxm, int node)
{
if (pxm_to_node_map[pxm] == NUMA_NO_NODE || node < pxm_to_node_map[pxm])
pxm_to_node_map[pxm] = node;
@@ -193,7 +193,7 @@ static int __init acpi_parse_slit(struct acpi_table_header *table)
return 0;
}
-void __init __attribute__ ((weak))
+void __init __weak
acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
{
printk(KERN_WARNING PREFIX
@@ -314,7 +314,7 @@ int __init acpi_numa_init(void)
return 0;
}
-int acpi_get_pxm(acpi_handle h)
+static int acpi_get_pxm(acpi_handle h)
{
unsigned long long pxm;
acpi_status status;
@@ -331,14 +331,14 @@ int acpi_get_pxm(acpi_handle h)
return -1;
}
-int acpi_get_node(acpi_handle *handle)
+int acpi_get_node(acpi_handle handle)
{
- int pxm, node = NUMA_NO_NODE;
+ int pxm;
pxm = acpi_get_pxm(handle);
- if (pxm >= 0 && pxm < MAX_PXM_DOMAINS)
- node = acpi_map_pxm_to_node(pxm);
+ if (pxm < 0 || pxm >= MAX_PXM_DOMAINS)
+ return NUMA_NO_NODE;
- return node;
+ return acpi_map_pxm_to_node(pxm);
}
EXPORT_SYMBOL(acpi_get_node);
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index fc1aa7909690..f7fd72ac69cf 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -52,7 +52,7 @@
#define _COMPONENT ACPI_OS_SERVICES
ACPI_MODULE_NAME("osl");
-#define PREFIX "ACPI: "
+
struct acpi_os_dpc {
acpi_osd_exec_callback function;
void *context;
@@ -1168,8 +1168,7 @@ void acpi_os_wait_events_complete(void)
struct acpi_hp_work {
struct work_struct work;
- acpi_hp_callback func;
- void *data;
+ struct acpi_device *adev;
u32 src;
};
@@ -1178,25 +1177,24 @@ static void acpi_hotplug_work_fn(struct work_struct *work)
struct acpi_hp_work *hpw = container_of(work, struct acpi_hp_work, work);
acpi_os_wait_events_complete();
- hpw->func(hpw->data, hpw->src);
+ acpi_device_hotplug(hpw->adev, hpw->src);
kfree(hpw);
}
-acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src)
+acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src)
{
struct acpi_hp_work *hpw;
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Scheduling function [%p(%p, %u)] for deferred execution.\n",
- func, data, src));
+ "Scheduling hotplug event (%p, %u) for deferred execution.\n",
+ adev, src));
hpw = kmalloc(sizeof(*hpw), GFP_KERNEL);
if (!hpw)
return AE_NO_MEMORY;
INIT_WORK(&hpw->work, acpi_hotplug_work_fn);
- hpw->func = func;
- hpw->data = data;
+ hpw->adev = adev;
hpw->src = src;
/*
* We can't run hotplug code in kacpid_wq/kacpid_notify_wq etc., because
@@ -1539,17 +1537,21 @@ static int __init osi_setup(char *str)
__setup("acpi_osi=", osi_setup);
-/* enable serialization to combat AE_ALREADY_EXISTS errors */
-static int __init acpi_serialize_setup(char *str)
+/*
+ * Disable the auto-serialization of named objects creation methods.
+ *
+ * This feature is enabled by default. It marks the AML control methods
+ * that contain the opcodes to create named objects as "Serialized".
+ */
+static int __init acpi_no_auto_serialize_setup(char *str)
{
- printk(KERN_INFO PREFIX "serialize enabled\n");
-
- acpi_gbl_all_methods_serialized = TRUE;
+ acpi_gbl_auto_serialize_methods = FALSE;
+ pr_info("ACPI: auto-serialization disabled\n");
return 1;
}
-__setup("acpi_serialize", acpi_serialize_setup);
+__setup("acpi_no_auto_serialize", acpi_no_auto_serialize_setup);
/* Check of resource interference between native drivers and ACPI
* OperationRegions (SystemIO and System Memory only).
@@ -1780,6 +1782,17 @@ static int __init acpi_no_auto_ssdt_setup(char *s)
__setup("acpi_no_auto_ssdt", acpi_no_auto_ssdt_setup);
+static int __init acpi_disable_return_repair(char *s)
+{
+ printk(KERN_NOTICE PREFIX
+ "ACPI: Predefined validation mechanism disabled\n");
+ acpi_gbl_disable_auto_repair = TRUE;
+
+ return 1;
+}
+
+__setup("acpica_no_return_repair", acpi_disable_return_repair);
+
acpi_status __init acpi_os_initialize(void)
{
acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1a_event_block);
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index 52d45ea2bc4f..9c62340c2360 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -370,6 +370,30 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
return NULL;
}
+#if IS_ENABLED(CONFIG_ISA) || IS_ENABLED(CONFIG_EISA)
+static int acpi_isa_register_gsi(struct pci_dev *dev)
+{
+ u32 dev_gsi;
+
+ /* Interrupt Line values above 0xF are forbidden */
+ if (dev->irq > 0 && (dev->irq <= 0xF) &&
+ (acpi_isa_irq_to_gsi(dev->irq, &dev_gsi) == 0)) {
+ dev_warn(&dev->dev, "PCI INT %c: no GSI - using ISA IRQ %d\n",
+ pin_name(dev->pin), dev->irq);
+ acpi_register_gsi(&dev->dev, dev_gsi,
+ ACPI_LEVEL_SENSITIVE,
+ ACPI_ACTIVE_LOW);
+ return 0;
+ }
+ return -EINVAL;
+}
+#else
+static inline int acpi_isa_register_gsi(struct pci_dev *dev)
+{
+ return -ENODEV;
+}
+#endif
+
int acpi_pci_irq_enable(struct pci_dev *dev)
{
struct acpi_prt_entry *entry;
@@ -416,20 +440,11 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
* driver reported one, then use it. Exit in any case.
*/
if (gsi < 0) {
- u32 dev_gsi;
- /* Interrupt Line values above 0xF are forbidden */
- if (dev->irq > 0 && (dev->irq <= 0xF) &&
- (acpi_isa_irq_to_gsi(dev->irq, &dev_gsi) == 0)) {
- dev_warn(&dev->dev, "PCI INT %c: no GSI - using ISA IRQ %d\n",
- pin_name(pin), dev->irq);
- acpi_register_gsi(&dev->dev, dev_gsi,
- ACPI_LEVEL_SENSITIVE,
- ACPI_ACTIVE_LOW);
- } else {
+ if (acpi_isa_register_gsi(dev))
dev_warn(&dev->dev, "PCI INT %c: no GSI\n",
pin_name(pin));
- }
+ kfree(entry);
return 0;
}
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 9418c7a1f786..cfd7581cc19f 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -43,8 +43,6 @@
#include "internal.h"
-#define PREFIX "ACPI: "
-
#define _COMPONENT ACPI_PCI_COMPONENT
ACPI_MODULE_NAME("pci_link");
#define ACPI_PCI_LINK_CLASS "pci_irq_routing"
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index c1c4102e6478..d388f13d48b4 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -39,8 +39,6 @@
#include "internal.h"
-#define PREFIX "ACPI: "
-
#define _COMPONENT ACPI_PCI_COMPONENT
ACPI_MODULE_NAME("pci_root");
#define ACPI_PCI_ROOT_CLASS "pci_bridge"
@@ -51,7 +49,7 @@ static void acpi_pci_root_remove(struct acpi_device *device);
static int acpi_pci_root_scan_dependent(struct acpi_device *adev)
{
- acpiphp_check_host_bridge(adev->handle);
+ acpiphp_check_host_bridge(adev);
return 0;
}
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index ad7da686e6e6..e0bcfb642b52 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -46,8 +46,6 @@
#include "sleep.h"
#include "internal.h"
-#define PREFIX "ACPI: "
-
#define _COMPONENT ACPI_POWER_COMPONENT
ACPI_MODULE_NAME("power");
#define ACPI_POWER_CLASS "power_resource"
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index a4eea9a508d3..71e2065639a6 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -15,28 +15,9 @@
#include "internal.h"
-#define PREFIX "ACPI: "
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_core");
-static int __init set_no_mwait(const struct dmi_system_id *id)
-{
- printk(KERN_NOTICE PREFIX "%s detected - "
- "disabling mwait for CPU C-states\n", id->ident);
- boot_option_idle_override = IDLE_NOMWAIT;
- return 0;
-}
-
-static struct dmi_system_id processor_idle_dmi_table[] __initdata = {
- {
- set_no_mwait, "Extensa 5220", {
- DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
- DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
- DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL},
- {},
-};
-
static int map_lapic_id(struct acpi_subtable_header *entry,
u32 acpi_id, int *apic_id)
{
@@ -323,7 +304,7 @@ static struct acpi_object_list *acpi_processor_alloc_pdc(void)
* _PDC is required for a BIOS-OS handshake for most of the newer
* ACPI processor features.
*/
-static int
+static acpi_status
acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in)
{
acpi_status status = AE_OK;
@@ -379,16 +360,43 @@ early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK;
}
-void __init acpi_early_processor_set_pdc(void)
+#if defined(CONFIG_X86) || defined(CONFIG_IA64)
+static int __init set_no_mwait(const struct dmi_system_id *id)
+{
+ pr_notice(PREFIX "%s detected - disabling mwait for CPU C-states\n",
+ id->ident);
+ boot_option_idle_override = IDLE_NOMWAIT;
+ return 0;
+}
+
+static struct dmi_system_id processor_idle_dmi_table[] __initdata = {
+ {
+ set_no_mwait, "Extensa 5220", {
+ DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
+ DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL},
+ {},
+};
+
+static void __init processor_dmi_check(void)
{
/*
* Check whether the system is DMI table. If yes, OSPM
* should not use mwait for CPU-states.
*/
dmi_check_system(processor_idle_dmi_table);
+}
+#else
+static inline void processor_dmi_check(void) {}
+#endif
+
+void __init acpi_early_processor_set_pdc(void)
+{
+ processor_dmi_check();
acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX,
early_init_pdc, NULL, NULL, NULL);
- acpi_get_devices("ACPI0007", early_init_pdc, NULL, NULL);
+ acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, early_init_pdc, NULL, NULL);
}
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index c1c35623550f..7f70f3182d50 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -41,8 +41,6 @@
#include "internal.h"
-#define PREFIX "ACPI: "
-
#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
#define ACPI_PROCESSOR_NOTIFY_POWER 0x81
#define ACPI_PROCESSOR_NOTIFY_THROTTLING 0x82
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index ff90054f04fd..cfc8aba72f86 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -156,17 +156,9 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
*/
static void acpi_processor_ppc_ost(acpi_handle handle, int status)
{
- union acpi_object params[2] = {
- {.type = ACPI_TYPE_INTEGER,},
- {.type = ACPI_TYPE_INTEGER,},
- };
- struct acpi_object_list arg_list = {2, params};
-
- 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);
- }
+ if (acpi_has_method(handle, "_OST"))
+ acpi_evaluate_ost(handle, ACPI_PROCESSOR_NOTIFY_PERFORMANCE,
+ status, NULL);
}
int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag)
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index 28baa05b8018..84243c32e29c 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -56,6 +56,12 @@ struct throttling_tstate {
int target_state; /* target T-state */
};
+struct acpi_processor_throttling_arg {
+ struct acpi_processor *pr;
+ int target_state;
+ bool force;
+};
+
#define THROTTLING_PRECHANGE (1)
#define THROTTLING_POSTCHANGE (2)
@@ -1060,16 +1066,24 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
return 0;
}
+static long acpi_processor_throttling_fn(void *data)
+{
+ struct acpi_processor_throttling_arg *arg = data;
+ struct acpi_processor *pr = arg->pr;
+
+ return pr->throttling.acpi_processor_set_throttling(pr,
+ arg->target_state, arg->force);
+}
+
int acpi_processor_set_throttling(struct acpi_processor *pr,
int state, bool force)
{
- cpumask_var_t saved_mask;
int ret = 0;
unsigned int i;
struct acpi_processor *match_pr;
struct acpi_processor_throttling *p_throttling;
+ struct acpi_processor_throttling_arg arg;
struct throttling_tstate t_state;
- cpumask_var_t online_throttling_cpus;
if (!pr)
return -EINVAL;
@@ -1080,14 +1094,6 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
if ((state < 0) || (state > (pr->throttling.state_count - 1)))
return -EINVAL;
- if (!alloc_cpumask_var(&saved_mask, GFP_KERNEL))
- return -ENOMEM;
-
- if (!alloc_cpumask_var(&online_throttling_cpus, GFP_KERNEL)) {
- free_cpumask_var(saved_mask);
- return -ENOMEM;
- }
-
if (cpu_is_offline(pr->id)) {
/*
* the cpu pointed by pr->id is offline. Unnecessary to change
@@ -1096,17 +1102,15 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
return -ENODEV;
}
- cpumask_copy(saved_mask, &current->cpus_allowed);
t_state.target_state = state;
p_throttling = &(pr->throttling);
- cpumask_and(online_throttling_cpus, cpu_online_mask,
- p_throttling->shared_cpu_map);
+
/*
* The throttling notifier will be called for every
* affected cpu in order to get one proper T-state.
* The notifier event is THROTTLING_PRECHANGE.
*/
- for_each_cpu(i, online_throttling_cpus) {
+ for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) {
t_state.cpu = i;
acpi_processor_throttling_notifier(THROTTLING_PRECHANGE,
&t_state);
@@ -1118,21 +1122,18 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
* it can be called only for the cpu pointed by pr.
*/
if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) {
- /* FIXME: use work_on_cpu() */
- if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) {
- /* Can't migrate to the pr->id CPU. Exit */
- ret = -ENODEV;
- goto exit;
- }
- ret = p_throttling->acpi_processor_set_throttling(pr,
- t_state.target_state, force);
+ arg.pr = pr;
+ arg.target_state = state;
+ arg.force = force;
+ ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, &arg);
} else {
/*
* When the T-state coordination is SW_ALL or HW_ALL,
* it is necessary to set T-state for every affected
* cpus.
*/
- for_each_cpu(i, online_throttling_cpus) {
+ for_each_cpu_and(i, cpu_online_mask,
+ p_throttling->shared_cpu_map) {
match_pr = per_cpu(processors, i);
/*
* If the pointer is invalid, we will report the
@@ -1153,13 +1154,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
"on CPU %d\n", i));
continue;
}
- t_state.cpu = i;
- /* FIXME: use work_on_cpu() */
- if (set_cpus_allowed_ptr(current, cpumask_of(i)))
- continue;
- ret = match_pr->throttling.
- acpi_processor_set_throttling(
- match_pr, t_state.target_state, force);
+
+ arg.pr = match_pr;
+ arg.target_state = state;
+ arg.force = force;
+ ret = work_on_cpu(pr->id, acpi_processor_throttling_fn,
+ &arg);
}
}
/*
@@ -1168,17 +1168,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
* affected cpu to update the T-states.
* The notifier event is THROTTLING_POSTCHANGE
*/
- for_each_cpu(i, online_throttling_cpus) {
+ for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) {
t_state.cpu = i;
acpi_processor_throttling_notifier(THROTTLING_POSTCHANGE,
&t_state);
}
- /* restore the previous state */
- /* FIXME: use work_on_cpu() */
- set_cpus_allowed_ptr(current, saved_mask);
-exit:
- free_cpumask_var(online_throttling_cpus);
- free_cpumask_var(saved_mask);
+
return ret;
}
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index b7201fc6f1e1..0bdacc5e26a3 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -77,18 +77,24 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
switch (ares->type) {
case ACPI_RESOURCE_TYPE_MEMORY24:
memory24 = &ares->data.memory24;
+ if (!memory24->address_length)
+ return false;
acpi_dev_get_memresource(res, memory24->minimum,
memory24->address_length,
memory24->write_protect);
break;
case ACPI_RESOURCE_TYPE_MEMORY32:
memory32 = &ares->data.memory32;
+ if (!memory32->address_length)
+ return false;
acpi_dev_get_memresource(res, memory32->minimum,
memory32->address_length,
memory32->write_protect);
break;
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
fixed_memory32 = &ares->data.fixed_memory32;
+ if (!fixed_memory32->address_length)
+ return false;
acpi_dev_get_memresource(res, fixed_memory32->address,
fixed_memory32->address_length,
fixed_memory32->write_protect);
@@ -144,12 +150,16 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res)
switch (ares->type) {
case ACPI_RESOURCE_TYPE_IO:
io = &ares->data.io;
+ if (!io->address_length)
+ return false;
acpi_dev_get_ioresource(res, io->minimum,
io->address_length,
io->io_decode);
break;
case ACPI_RESOURCE_TYPE_FIXED_IO:
fixed_io = &ares->data.fixed_io;
+ if (!fixed_io->address_length)
+ return false;
acpi_dev_get_ioresource(res, fixed_io->address,
fixed_io->address_length,
ACPI_DECODE_10);
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index d465ae6cdd00..366ca40a6f70 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -37,12 +37,12 @@
#include <linux/power_supply.h>
#include "sbshc.h"
+#include "battery.h"
#define PREFIX "ACPI: "
#define ACPI_SBS_CLASS "sbs"
#define ACPI_AC_CLASS "ac_adapter"
-#define ACPI_BATTERY_CLASS "battery"
#define ACPI_SBS_DEVICE_NAME "Smart Battery System"
#define ACPI_SBS_FILE_INFO "info"
#define ACPI_SBS_FILE_STATE "state"
@@ -450,7 +450,7 @@ static ssize_t acpi_battery_alarm_store(struct device *dev,
{
unsigned long x;
struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
- if (sscanf(buf, "%ld\n", &x) == 1)
+ if (sscanf(buf, "%lu\n", &x) == 1)
battery->alarm_capacity = x /
(1000 * acpi_battery_scale(battery));
if (battery->present)
@@ -668,6 +668,8 @@ static int acpi_sbs_resume(struct device *dev)
acpi_sbs_callback(sbs);
return 0;
}
+#else
+#define acpi_sbs_resume NULL
#endif
static SIMPLE_DEV_PM_OPS(acpi_sbs_pm, NULL, acpi_sbs_resume);
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 57b053f424d1..7efe546a8c42 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -41,6 +41,7 @@ static DEFINE_MUTEX(acpi_scan_lock);
static LIST_HEAD(acpi_scan_handlers_list);
DEFINE_MUTEX(acpi_device_lock);
LIST_HEAD(acpi_wakeup_device_list);
+static DEFINE_MUTEX(acpi_hp_context_lock);
struct acpi_device_bus_id{
char bus_id[15];
@@ -60,6 +61,27 @@ void acpi_scan_lock_release(void)
}
EXPORT_SYMBOL_GPL(acpi_scan_lock_release);
+void acpi_lock_hp_context(void)
+{
+ mutex_lock(&acpi_hp_context_lock);
+}
+
+void acpi_unlock_hp_context(void)
+{
+ mutex_unlock(&acpi_hp_context_lock);
+}
+
+void acpi_initialize_hp_context(struct acpi_device *adev,
+ struct acpi_hotplug_context *hp,
+ int (*notify)(struct acpi_device *, u32),
+ void (*uevent)(struct acpi_device *, u32))
+{
+ acpi_lock_hp_context();
+ acpi_set_hp_context(adev, hp, notify, uevent, NULL);
+ acpi_unlock_hp_context();
+}
+EXPORT_SYMBOL_GPL(acpi_initialize_hp_context);
+
int acpi_scan_add_handler(struct acpi_scan_handler *handler)
{
if (!handler || !handler->attach)
@@ -439,90 +461,75 @@ static int acpi_scan_bus_check(struct acpi_device *adev)
return 0;
}
-static void acpi_device_hotplug(void *data, u32 src)
+static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type)
{
- u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
- struct acpi_device *adev = data;
- int error;
-
- lock_device_hotplug();
- mutex_lock(&acpi_scan_lock);
-
- /*
- * The device object's ACPI handle cannot become invalid as long as we
- * are holding acpi_scan_lock, but it may have become invalid before
- * that lock was acquired.
- */
- if (adev->handle == INVALID_ACPI_HANDLE)
- goto out;
-
- switch (src) {
+ switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
- error = acpi_scan_bus_check(adev);
- break;
+ return acpi_scan_bus_check(adev);
case ACPI_NOTIFY_DEVICE_CHECK:
- error = acpi_scan_device_check(adev);
- break;
+ return acpi_scan_device_check(adev);
case ACPI_NOTIFY_EJECT_REQUEST:
case ACPI_OST_EC_OSPM_EJECT:
- error = acpi_scan_hot_remove(adev);
- break;
- default:
- error = -EINVAL;
- break;
+ if (adev->handler && !adev->handler->hotplug.enabled) {
+ dev_info(&adev->dev, "Eject disabled\n");
+ return -EPERM;
+ }
+ acpi_evaluate_ost(adev->handle, ACPI_NOTIFY_EJECT_REQUEST,
+ ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+ return acpi_scan_hot_remove(adev);
}
- if (!error)
- ost_code = ACPI_OST_SC_SUCCESS;
-
- out:
- acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL);
- put_device(&adev->dev);
- mutex_unlock(&acpi_scan_lock);
- unlock_device_hotplug();
+ return -EINVAL;
}
-static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data)
+void acpi_device_hotplug(struct acpi_device *adev, u32 src)
{
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
- struct acpi_device *adev;
- acpi_status status;
+ int error = -ENODEV;
- if (acpi_bus_get_device(handle, &adev))
- goto err_out;
+ lock_device_hotplug();
+ mutex_lock(&acpi_scan_lock);
- switch (type) {
- case ACPI_NOTIFY_BUS_CHECK:
- acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
- break;
- case ACPI_NOTIFY_DEVICE_CHECK:
- acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
- break;
- case ACPI_NOTIFY_EJECT_REQUEST:
- acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
- if (!adev->handler)
- goto err_out;
+ /*
+ * The device object's ACPI handle cannot become invalid as long as we
+ * are holding acpi_scan_lock, but it might have become invalid before
+ * that lock was acquired.
+ */
+ if (adev->handle == INVALID_ACPI_HANDLE)
+ goto err_out;
- if (!adev->handler->hotplug.enabled) {
- acpi_handle_err(handle, "Eject disabled\n");
+ if (adev->flags.is_dock_station) {
+ error = dock_notify(adev, src);
+ } else if (adev->flags.hotplug_notify) {
+ error = acpi_generic_hotplug_event(adev, src);
+ if (error == -EPERM) {
ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
goto err_out;
}
- acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
- ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
- break;
- default:
- /* non-hotplug event; possibly handled by other handler */
- return;
- }
- get_device(&adev->dev);
- status = acpi_hotplug_execute(acpi_device_hotplug, adev, type);
- if (ACPI_SUCCESS(status))
- return;
+ } else {
+ int (*notify)(struct acpi_device *, u32);
- put_device(&adev->dev);
+ acpi_lock_hp_context();
+ notify = adev->hp ? adev->hp->notify : NULL;
+ acpi_unlock_hp_context();
+ /*
+ * There may be additional notify handlers for device objects
+ * without the .event() callback, so ignore them here.
+ */
+ if (notify)
+ error = notify(adev, src);
+ else
+ goto out;
+ }
+ if (!error)
+ ost_code = ACPI_OST_SC_SUCCESS;
err_out:
- acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
+ acpi_evaluate_ost(adev->handle, src, ost_code, NULL);
+
+ out:
+ acpi_bus_put_acpi_device(adev);
+ mutex_unlock(&acpi_scan_lock);
+ unlock_device_hotplug();
}
static ssize_t real_power_state_show(struct device *dev,
@@ -570,17 +577,14 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
return -ENODEV;
- acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
- ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
get_device(&acpi_device->dev);
- status = acpi_hotplug_execute(acpi_device_hotplug, acpi_device,
- ACPI_OST_EC_OSPM_EJECT);
+ status = acpi_hotplug_schedule(acpi_device, ACPI_OST_EC_OSPM_EJECT);
if (ACPI_SUCCESS(status))
return count;
put_device(&acpi_device->dev);
- acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
- ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
+ acpi_evaluate_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
+ ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
return status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
}
@@ -1114,14 +1118,16 @@ static void acpi_scan_drop_device(acpi_handle handle, void *context)
mutex_unlock(&acpi_device_del_lock);
}
-int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
+static int acpi_get_device_data(acpi_handle handle, struct acpi_device **device,
+ void (*callback)(void *))
{
acpi_status status;
if (!device)
return -EINVAL;
- status = acpi_get_data(handle, acpi_scan_drop_device, (void **)device);
+ status = acpi_get_data_full(handle, acpi_scan_drop_device,
+ (void **)device, callback);
if (ACPI_FAILURE(status) || !*device) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
handle));
@@ -1129,8 +1135,32 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
}
return 0;
}
+
+int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
+{
+ return acpi_get_device_data(handle, device, NULL);
+}
EXPORT_SYMBOL(acpi_bus_get_device);
+static void get_acpi_device(void *dev)
+{
+ if (dev)
+ get_device(&((struct acpi_device *)dev)->dev);
+}
+
+struct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle)
+{
+ struct acpi_device *adev = NULL;
+
+ acpi_get_device_data(handle, &adev, get_acpi_device);
+ return adev;
+}
+
+void acpi_bus_put_acpi_device(struct acpi_device *adev)
+{
+ put_device(&adev->dev);
+}
+
int acpi_device_add(struct acpi_device *device,
void (*release)(struct device *))
{
@@ -1641,6 +1671,27 @@ bool acpi_bay_match(acpi_handle handle)
return acpi_ata_match(phandle);
}
+bool acpi_device_is_battery(struct acpi_device *adev)
+{
+ struct acpi_hardware_id *hwid;
+
+ list_for_each_entry(hwid, &adev->pnp.ids, list)
+ if (!strcmp("PNP0C0A", hwid->id))
+ return true;
+
+ return false;
+}
+
+static bool is_ejectable_bay(struct acpi_device *adev)
+{
+ acpi_handle handle = adev->handle;
+
+ if (acpi_has_method(handle, "_EJ0") && acpi_device_is_battery(adev))
+ return true;
+
+ return acpi_bay_match(handle);
+}
+
/*
* acpi_dock_match - see if an acpi object has a _DCK method
*/
@@ -1706,6 +1757,20 @@ static bool acpi_ibm_smbus_match(acpi_handle handle)
return false;
}
+static bool acpi_object_is_system_bus(acpi_handle handle)
+{
+ acpi_handle tmp;
+
+ if (ACPI_SUCCESS(acpi_get_handle(NULL, "\\_SB", &tmp)) &&
+ tmp == handle)
+ return true;
+ if (ACPI_SUCCESS(acpi_get_handle(NULL, "\\_TZ", &tmp)) &&
+ tmp == handle)
+ return true;
+
+ return false;
+}
+
static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
int device_type)
{
@@ -1757,8 +1822,10 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
acpi_add_id(pnp, ACPI_DOCK_HID);
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 */
+ else if (list_empty(&pnp->ids) &&
+ acpi_object_is_system_bus(handle)) {
+ /* \_SB, \_TZ, LNXSYBUS */
+ acpi_add_id(pnp, ACPI_BUS_HID);
strcpy(pnp->device_name, ACPI_BUS_DEVICE_NAME);
strcpy(pnp->device_class, ACPI_BUS_CLASS);
}
@@ -1941,33 +2008,23 @@ void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val)
mutex_unlock(&acpi_scan_lock);
}
-static void acpi_scan_init_hotplug(acpi_handle handle, int type)
+static void acpi_scan_init_hotplug(struct acpi_device *adev)
{
- struct acpi_device_pnp pnp = {};
struct acpi_hardware_id *hwid;
- struct acpi_scan_handler *handler;
- INIT_LIST_HEAD(&pnp.ids);
- acpi_set_pnp_ids(handle, &pnp, type);
-
- if (!pnp.type.hardware_id)
- goto out;
+ if (acpi_dock_match(adev->handle) || is_ejectable_bay(adev)) {
+ acpi_dock_add(adev);
+ return;
+ }
+ list_for_each_entry(hwid, &adev->pnp.ids, list) {
+ struct acpi_scan_handler *handler;
- /*
- * This relies on the fact that acpi_install_notify_handler() will not
- * install the same notify handler routine twice for the same handle.
- */
- list_for_each_entry(hwid, &pnp.ids, list) {
handler = acpi_scan_match_handler(hwid->id, NULL);
if (handler) {
- acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
- acpi_hotplug_notify_cb, handler);
+ adev->flags.hotplug_notify = true;
break;
}
}
-
-out:
- acpi_free_pnp_ids(&pnp);
}
static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
@@ -1991,12 +2048,12 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
return AE_OK;
}
- acpi_scan_init_hotplug(handle, type);
-
acpi_add_single_object(&device, handle, type, sta);
if (!device)
return AE_CTRL_DEPTH;
+ acpi_scan_init_hotplug(device);
+
out:
if (!*return_value)
*return_value = device;
@@ -2015,13 +2072,14 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
handler = acpi_scan_match_handler(hwid->id, &devid);
if (handler) {
+ device->handler = handler;
ret = handler->attach(device, devid);
- if (ret > 0) {
- device->handler = handler;
+ if (ret > 0)
break;
- } else if (ret < 0) {
+
+ device->handler = NULL;
+ if (ret < 0)
break;
- }
}
}
return ret;
@@ -2030,8 +2088,12 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
static void acpi_bus_attach(struct acpi_device *device)
{
struct acpi_device *child;
+ acpi_handle ejd;
int ret;
+ if (ACPI_SUCCESS(acpi_bus_get_ejd(device->handle, &ejd)))
+ register_dock_dependent_device(device, ejd);
+
acpi_bus_get_status(device);
/* Skip devices that are not present. */
if (!acpi_device_is_present(device)) {
@@ -2184,7 +2246,6 @@ int __init acpi_scan_init(void)
acpi_cmos_rtc_init();
acpi_container_init();
acpi_memory_hotplug_init();
- acpi_dock_init();
mutex_lock(&acpi_scan_lock);
/*
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index b718806657cd..c40fb2e81bbc 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -71,6 +71,17 @@ static int acpi_sleep_prepare(u32 acpi_state)
return 0;
}
+static bool acpi_sleep_state_supported(u8 sleep_state)
+{
+ acpi_status status;
+ u8 type_a, type_b;
+
+ status = acpi_get_sleep_type_data(sleep_state, &type_a, &type_b);
+ return ACPI_SUCCESS(status) && (!acpi_gbl_reduced_hardware
+ || (acpi_gbl_FADT.sleep_control.address
+ && acpi_gbl_FADT.sleep_status.address));
+}
+
#ifdef CONFIG_ACPI_SLEEP
static u32 acpi_target_sleep_state = ACPI_STATE_S0;
@@ -604,15 +615,9 @@ static void acpi_sleep_suspend_setup(void)
{
int i;
- for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) {
- acpi_status status;
- u8 type_a, type_b;
-
- status = acpi_get_sleep_type_data(i, &type_a, &type_b);
- if (ACPI_SUCCESS(status)) {
+ for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++)
+ if (acpi_sleep_state_supported(i))
sleep_states[i] = 1;
- }
- }
suspend_set_ops(old_suspend_ordering ?
&acpi_suspend_ops_old : &acpi_suspend_ops);
@@ -740,11 +745,7 @@ static const struct platform_hibernation_ops acpi_hibernation_ops_old = {
static void acpi_sleep_hibernate_setup(void)
{
- acpi_status status;
- u8 type_a, type_b;
-
- status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
- if (ACPI_FAILURE(status))
+ if (!acpi_sleep_state_supported(ACPI_STATE_S4))
return;
hibernation_set_ops(old_suspend_ordering ?
@@ -793,8 +794,6 @@ static void acpi_power_off(void)
int __init acpi_sleep_init(void)
{
- acpi_status status;
- u8 type_a, type_b;
char supported[ACPI_S_STATE_COUNT * 3 + 1];
char *pos = supported;
int i;
@@ -806,8 +805,7 @@ int __init acpi_sleep_init(void)
acpi_sleep_suspend_setup();
acpi_sleep_hibernate_setup();
- status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
- if (ACPI_SUCCESS(status)) {
+ if (acpi_sleep_state_supported(ACPI_STATE_S5)) {
sleep_states[ACPI_STATE_S5] = 1;
pm_power_off_prepare = acpi_power_off_prepare;
pm_power_off = acpi_power_off;
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index 91a32cefb11f..38cb9782d4b8 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -12,8 +12,6 @@
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME("sysfs");
-#define PREFIX "ACPI: "
-
#ifdef CONFIG_ACPI_DEBUG
/*
* ACPI debug sysfs I/F, including:
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 5837f857ac2e..21782290df41 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -23,6 +23,8 @@
*
*/
+#define pr_fmt(fmt) "ACPI: " fmt
+
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/smp.h>
@@ -33,8 +35,6 @@
#include <linux/acpi.h>
#include <linux/bootmem.h>
-#define PREFIX "ACPI: "
-
#define ACPI_MAX_TABLES 128
static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" };
@@ -55,10 +55,9 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
struct acpi_madt_local_apic *p =
(struct acpi_madt_local_apic *)header;
- printk(KERN_INFO PREFIX
- "LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n",
- p->processor_id, p->id,
- (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
+ pr_info("LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n",
+ p->processor_id, p->id,
+ (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
}
break;
@@ -66,11 +65,9 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
struct acpi_madt_local_x2apic *p =
(struct acpi_madt_local_x2apic *)header;
- printk(KERN_INFO PREFIX
- "X2APIC (apic_id[0x%02x] uid[0x%02x] %s)\n",
- p->local_apic_id, p->uid,
- (p->lapic_flags & ACPI_MADT_ENABLED) ?
- "enabled" : "disabled");
+ pr_info("X2APIC (apic_id[0x%02x] uid[0x%02x] %s)\n",
+ p->local_apic_id, p->uid,
+ (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
}
break;
@@ -78,9 +75,8 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
struct acpi_madt_io_apic *p =
(struct acpi_madt_io_apic *)header;
- printk(KERN_INFO PREFIX
- "IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
- p->id, p->address, p->global_irq_base);
+ pr_info("IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
+ p->id, p->address, p->global_irq_base);
}
break;
@@ -88,18 +84,15 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
struct acpi_madt_interrupt_override *p =
(struct acpi_madt_interrupt_override *)header;
- printk(KERN_INFO PREFIX
- "INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n",
- p->bus, p->source_irq, p->global_irq,
- mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
- mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]);
+ pr_info("INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n",
+ p->bus, p->source_irq, p->global_irq,
+ mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+ mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]);
if (p->inti_flags &
~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK))
- printk(KERN_INFO PREFIX
- "INT_SRC_OVR unexpected reserved flags: 0x%x\n",
- p->inti_flags &
+ pr_info("INT_SRC_OVR unexpected reserved flags: 0x%x\n",
+ p->inti_flags &
~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK));
-
}
break;
@@ -107,11 +100,10 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
struct acpi_madt_nmi_source *p =
(struct acpi_madt_nmi_source *)header;
- printk(KERN_INFO PREFIX
- "NMI_SRC (%s %s global_irq %d)\n",
- mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
- mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
- p->global_irq);
+ pr_info("NMI_SRC (%s %s global_irq %d)\n",
+ mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+ mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
+ p->global_irq);
}
break;
@@ -119,12 +111,11 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
struct acpi_madt_local_apic_nmi *p =
(struct acpi_madt_local_apic_nmi *)header;
- printk(KERN_INFO PREFIX
- "LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n",
- p->processor_id,
- mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK ],
- mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
- p->lint);
+ pr_info("LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n",
+ p->processor_id,
+ mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK ],
+ mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
+ p->lint);
}
break;
@@ -137,12 +128,11 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
polarity = p->inti_flags & ACPI_MADT_POLARITY_MASK;
trigger = (p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2;
- printk(KERN_INFO PREFIX
- "X2APIC_NMI (uid[0x%02x] %s %s lint[0x%x])\n",
- p->uid,
- mps_inti_flags_polarity[polarity],
- mps_inti_flags_trigger[trigger],
- p->lint);
+ pr_info("X2APIC_NMI (uid[0x%02x] %s %s lint[0x%x])\n",
+ p->uid,
+ mps_inti_flags_polarity[polarity],
+ mps_inti_flags_trigger[trigger],
+ p->lint);
}
break;
@@ -150,9 +140,8 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
struct acpi_madt_local_apic_override *p =
(struct acpi_madt_local_apic_override *)header;
- printk(KERN_INFO PREFIX
- "LAPIC_ADDR_OVR (address[%p])\n",
- (void *)(unsigned long)p->address);
+ pr_info("LAPIC_ADDR_OVR (address[%p])\n",
+ (void *)(unsigned long)p->address);
}
break;
@@ -160,10 +149,9 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
struct acpi_madt_io_sapic *p =
(struct acpi_madt_io_sapic *)header;
- printk(KERN_INFO PREFIX
- "IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
- p->id, (void *)(unsigned long)p->address,
- p->global_irq_base);
+ pr_info("IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
+ p->id, (void *)(unsigned long)p->address,
+ p->global_irq_base);
}
break;
@@ -171,10 +159,9 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
struct acpi_madt_local_sapic *p =
(struct acpi_madt_local_sapic *)header;
- printk(KERN_INFO PREFIX
- "LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n",
- p->processor_id, p->id, p->eid,
- (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
+ pr_info("LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n",
+ p->processor_id, p->id, p->eid,
+ (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
}
break;
@@ -182,19 +169,17 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
struct acpi_madt_interrupt_source *p =
(struct acpi_madt_interrupt_source *)header;
- printk(KERN_INFO PREFIX
- "PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n",
- mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
- mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
- p->type, p->id, p->eid, p->io_sapic_vector,
- p->global_irq);
+ pr_info("PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n",
+ mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+ mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
+ p->type, p->id, p->eid, p->io_sapic_vector,
+ p->global_irq);
}
break;
default:
- printk(KERN_WARNING PREFIX
- "Found unsupported MADT entry (type = 0x%x)\n",
- header->type);
+ pr_warn("Found unsupported MADT entry (type = 0x%x)\n",
+ header->type);
break;
}
}
@@ -225,7 +210,7 @@ acpi_table_parse_entries(char *id,
acpi_get_table_with_size(id, 0, &table_header, &tbl_size);
if (!table_header) {
- printk(KERN_WARNING PREFIX "%4.4s not present\n", id);
+ pr_warn("%4.4s not present\n", id);
return -ENODEV;
}
@@ -248,7 +233,7 @@ acpi_table_parse_entries(char *id,
* infinite loop.
*/
if (entry->length == 0) {
- pr_err(PREFIX "[%4.4s:0x%02x] Invalid zero length\n", id, entry_id);
+ pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, entry_id);
goto err;
}
@@ -256,8 +241,8 @@ acpi_table_parse_entries(char *id,
((unsigned long)entry + entry->length);
}
if (max_entries && count > max_entries) {
- printk(KERN_WARNING PREFIX "[%4.4s:0x%02x] ignored %i entries of "
- "%i found\n", id, entry_id, count - max_entries, count);
+ pr_warn("[%4.4s:0x%02x] ignored %i entries of %i found\n",
+ id, entry_id, count - max_entries, count);
}
early_acpi_os_unmap_memory((char *)table_header, tbl_size);
@@ -322,13 +307,11 @@ static void __init check_multiple_madt(void)
acpi_get_table_with_size(ACPI_SIG_MADT, 2, &table, &tbl_size);
if (table) {
- printk(KERN_WARNING PREFIX
- "BIOS bug: multiple APIC/MADT found,"
- " using %d\n", acpi_apic_instance);
- printk(KERN_WARNING PREFIX
- "If \"acpi_apic_instance=%d\" works better, "
- "notify linux-acpi@vger.kernel.org\n",
- acpi_apic_instance ? 0 : 2);
+ pr_warn("BIOS bug: multiple APIC/MADT found, using %d\n",
+ acpi_apic_instance);
+ pr_warn("If \"acpi_apic_instance=%d\" works better, "
+ "notify linux-acpi@vger.kernel.org\n",
+ acpi_apic_instance ? 0 : 2);
early_acpi_os_unmap_memory(table, tbl_size);
} else
@@ -365,8 +348,7 @@ static int __init acpi_parse_apic_instance(char *str)
acpi_apic_instance = simple_strtoul(str, NULL, 0);
- printk(KERN_NOTICE PREFIX "Shall use APIC/MADT table %d\n",
- acpi_apic_instance);
+ pr_notice("Shall use APIC/MADT table %d\n", acpi_apic_instance);
return 0;
}
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 8349a555b92b..964068553334 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -43,6 +43,7 @@
#include <linux/device.h>
#include <linux/thermal.h>
#include <linux/acpi.h>
+#include <linux/workqueue.h>
#include <asm/uaccess.h>
#define PREFIX "ACPI: "
@@ -90,6 +91,8 @@ static int psv;
module_param(psv, int, 0644);
MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");
+static struct workqueue_struct *acpi_thermal_pm_queue;
+
static int acpi_thermal_add(struct acpi_device *device);
static int acpi_thermal_remove(struct acpi_device *device);
static void acpi_thermal_notify(struct acpi_device *device, u32 event);
@@ -101,9 +104,13 @@ static const struct acpi_device_id thermal_device_ids[] = {
MODULE_DEVICE_TABLE(acpi, thermal_device_ids);
#ifdef CONFIG_PM_SLEEP
+static int acpi_thermal_suspend(struct device *dev);
static int acpi_thermal_resume(struct device *dev);
+#else
+#define acpi_thermal_suspend NULL
+#define acpi_thermal_resume NULL
#endif
-static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, NULL, acpi_thermal_resume);
+static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, acpi_thermal_suspend, acpi_thermal_resume);
static struct acpi_driver acpi_thermal_driver = {
.name = "thermal",
@@ -184,6 +191,7 @@ struct acpi_thermal {
struct thermal_zone_device *thermal_zone;
int tz_enabled;
int kelvin_offset;
+ struct work_struct thermal_check_work;
};
/* --------------------------------------------------------------------------
@@ -1062,6 +1070,13 @@ static void acpi_thermal_guess_offset(struct acpi_thermal *tz)
tz->kelvin_offset = 2732;
}
+static void acpi_thermal_check_fn(struct work_struct *work)
+{
+ struct acpi_thermal *tz = container_of(work, struct acpi_thermal,
+ thermal_check_work);
+ acpi_thermal_check(tz);
+}
+
static int acpi_thermal_add(struct acpi_device *device)
{
int result = 0;
@@ -1091,6 +1106,8 @@ static int acpi_thermal_add(struct acpi_device *device)
if (result)
goto free_memory;
+ INIT_WORK(&tz->thermal_check_work, acpi_thermal_check_fn);
+
pr_info(PREFIX "%s [%s] (%ld C)\n", acpi_device_name(device),
acpi_device_bid(device), KELVIN_TO_CELSIUS(tz->temperature));
goto end;
@@ -1108,6 +1125,7 @@ static int acpi_thermal_remove(struct acpi_device *device)
if (!device || !acpi_driver_data(device))
return -EINVAL;
+ flush_workqueue(acpi_thermal_pm_queue);
tz = acpi_driver_data(device);
acpi_thermal_unregister_thermal_zone(tz);
@@ -1116,6 +1134,13 @@ static int acpi_thermal_remove(struct acpi_device *device)
}
#ifdef CONFIG_PM_SLEEP
+static int acpi_thermal_suspend(struct device *dev)
+{
+ /* Make sure the previously queued thermal check work has been done */
+ flush_workqueue(acpi_thermal_pm_queue);
+ return 0;
+}
+
static int acpi_thermal_resume(struct device *dev)
{
struct acpi_thermal *tz;
@@ -1146,7 +1171,7 @@ static int acpi_thermal_resume(struct device *dev)
tz->state.active |= tz->trips.active[i].flags.enabled;
}
- acpi_thermal_check(tz);
+ queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work);
return AE_OK;
}
@@ -1238,16 +1263,22 @@ static int __init acpi_thermal_init(void)
return -ENODEV;
}
+ acpi_thermal_pm_queue = create_workqueue("acpi_thermal_pm");
+ if (!acpi_thermal_pm_queue)
+ return -ENODEV;
+
result = acpi_bus_register_driver(&acpi_thermal_driver);
- if (result < 0)
+ if (result < 0) {
+ destroy_workqueue(acpi_thermal_pm_queue);
return -ENODEV;
+ }
return 0;
}
static void __exit acpi_thermal_exit(void)
{
-
+ destroy_workqueue(acpi_thermal_pm_queue);
acpi_bus_unregister_driver(&acpi_thermal_driver);
return;
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 85e3b612bdc0..0f5f78fa6545 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -422,7 +422,7 @@ out:
EXPORT_SYMBOL(acpi_get_physical_device_location);
/**
- * acpi_evaluate_hotplug_ost: Evaluate _OST for hotplug operations
+ * acpi_evaluate_ost: Evaluate _OST for hotplug operations
* @handle: ACPI device handle
* @source_event: source event code
* @status_code: status code
@@ -433,17 +433,15 @@ EXPORT_SYMBOL(acpi_get_physical_device_location);
* When the platform does not support _OST, this function has no effect.
*/
acpi_status
-acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event,
- u32 status_code, struct acpi_buffer *status_buf)
+acpi_evaluate_ost(acpi_handle handle, u32 source_event, u32 status_code,
+ struct acpi_buffer *status_buf)
{
-#ifdef ACPI_HOTPLUG_OST
union acpi_object params[3] = {
{.type = ACPI_TYPE_INTEGER,},
{.type = ACPI_TYPE_INTEGER,},
{.type = ACPI_TYPE_BUFFER,}
};
struct acpi_object_list arg_list = {3, params};
- acpi_status status;
params[0].integer.value = source_event;
params[1].integer.value = status_code;
@@ -455,13 +453,9 @@ acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event,
params[2].buffer.length = 0;
}
- status = acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
- return status;
-#else
- return AE_OK;
-#endif
+ return acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
}
-EXPORT_SYMBOL(acpi_evaluate_hotplug_ost);
+EXPORT_SYMBOL(acpi_evaluate_ost);
/**
* acpi_handle_printk: Print message with ACPI prefix and object path
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index b727d105046d..48c7e8af9c96 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -45,8 +45,6 @@
#include "internal.h"
-#define PREFIX "ACPI: "
-
#define ACPI_VIDEO_BUS_NAME "Video Bus"
#define ACPI_VIDEO_DEVICE_NAME "Video Device"
#define ACPI_VIDEO_NOTIFY_SWITCH 0x80
@@ -81,11 +79,12 @@ static bool allow_duplicates;
module_param(allow_duplicates, bool, 0644);
/*
- * For Windows 8 systems: if set ture and the GPU driver has
- * registered a backlight interface, skip registering ACPI video's.
+ * For Windows 8 systems: used to decide if video module
+ * should skip registering backlight interface of its own.
*/
-static bool use_native_backlight = false;
-module_param(use_native_backlight, bool, 0644);
+static int use_native_backlight_param = -1;
+module_param_named(use_native_backlight, use_native_backlight_param, int, 0444);
+static bool use_native_backlight_dmi = false;
static int register_count;
static struct mutex video_list_lock;
@@ -231,9 +230,17 @@ 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);
+static bool acpi_video_use_native_backlight(void)
+{
+ if (use_native_backlight_param != -1)
+ return use_native_backlight_param;
+ else
+ return use_native_backlight_dmi;
+}
+
static bool acpi_video_verify_backlight_support(void)
{
- if (acpi_osi_is_win8() && use_native_backlight &&
+ if (acpi_osi_is_win8() && acpi_video_use_native_backlight() &&
backlight_device_registered(BACKLIGHT_RAW))
return false;
return acpi_video_backlight_support();
@@ -398,6 +405,12 @@ static int __init video_set_bqc_offset(const struct dmi_system_id *d)
return 0;
}
+static int __init video_set_use_native_backlight(const struct dmi_system_id *d)
+{
+ use_native_backlight_dmi = true;
+ return 0;
+}
+
static struct dmi_system_id video_dmi_table[] __initdata = {
/*
* Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121
@@ -442,6 +455,120 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720"),
},
},
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "ThinkPad T430s",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T430s"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "ThinkPad X230",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X230"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "ThinkPad X1 Carbon",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X1 Carbon"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "Lenovo Yoga 13",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Yoga 13"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "Dell Inspiron 7520",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Inspiron 7520"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "Acer Aspire 5733Z",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5733Z"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "Acer Aspire V5-431",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-431"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "HP ProBook 4340s",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "HP ProBook 4340s"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "HP ProBook 2013 models",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook "),
+ DMI_MATCH(DMI_PRODUCT_NAME, " G1"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "HP EliteBook 2013 models",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook "),
+ DMI_MATCH(DMI_PRODUCT_NAME, " G1"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "HP ZBook 14",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 14"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "HP ZBook 15",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 15"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "HP ZBook 17",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 17"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "HP EliteBook 8780w",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8780w"),
+ },
+ },
{}
};
@@ -685,6 +812,7 @@ acpi_video_init_brightness(struct acpi_video_device *device)
union acpi_object *o;
struct acpi_video_device_brightness *br = NULL;
int result = -EINVAL;
+ u32 value;
if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available "
@@ -715,7 +843,12 @@ acpi_video_init_brightness(struct acpi_video_device *device)
printk(KERN_ERR PREFIX "Invalid data\n");
continue;
}
- br->levels[count] = (u32) o->integer.value;
+ value = (u32) o->integer.value;
+ /* Skip duplicate entries */
+ if (count > 2 && br->levels[count - 1] == value)
+ continue;
+
+ br->levels[count] = value;
if (br->levels[count] > max_level)
max_level = br->levels[count];
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index a697b77b8865..33e3db548a29 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -40,8 +40,6 @@
#include "internal.h"
-#define PREFIX "ACPI: "
-
ACPI_MODULE_NAME("video");
#define _COMPONENT ACPI_VIDEO_COMPONENT
@@ -168,22 +166,6 @@ static struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"),
},
},
- {
- .callback = video_detect_force_vendor,
- .ident = "HP EliteBook Revolve 810",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook Revolve 810 G1"),
- },
- },
- {
- .callback = video_detect_force_vendor,
- .ident = "Lenovo Yoga 13",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Yoga 13"),
- },
- },
{ },
};
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 4e737728aee2..20e03a7eb8b4 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -11,13 +11,13 @@ config HAVE_PATA_PLATFORM
to update the PATA_PLATFORM entry.
menuconfig ATA
- tristate "Serial ATA and Parallel ATA drivers"
+ tristate "Serial ATA and Parallel ATA drivers (libata)"
depends on HAS_IOMEM
depends on BLOCK
depends on !(M32R || M68K || S390) || BROKEN
select SCSI
---help---
- If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or
+ If you want to use an ATA hard disk, ATA tape drive, ATA CD-ROM or
any other ATA device under Linux, say Y and make sure that you know
the name of your ATA host adapter (the card inside your computer
that "speaks" the ATA protocol, also called ATA controller),
@@ -60,7 +60,7 @@ config ATA_ACPI
config SATA_ZPODD
bool "SATA Zero Power Optical Disc Drive (ZPODD) support"
- depends on ATA_ACPI
+ depends on ATA_ACPI && PM_RUNTIME
default n
help
This option adds support for SATA Zero Power Optical Disc
@@ -97,15 +97,48 @@ config SATA_AHCI_PLATFORM
If unsure, say N.
+config AHCI_DA850
+ tristate "DaVinci DA850 AHCI SATA support"
+ depends on ARCH_DAVINCI_DA850
+ help
+ This option enables support for the DaVinci DA850 SoC's
+ onboard AHCI SATA.
+
+ If unsure, say N.
+
+config AHCI_ST
+ tristate "ST AHCI SATA support"
+ depends on ARCH_STI
+ help
+ This option enables support for ST AHCI SATA controller.
+
+ If unsure, say N.
+
config AHCI_IMX
tristate "Freescale i.MX AHCI SATA support"
- depends on SATA_AHCI_PLATFORM && MFD_SYSCON
+ depends on MFD_SYSCON
help
This option enables support for the Freescale i.MX SoC's
onboard AHCI SATA.
If unsure, say N.
+config AHCI_SUNXI
+ tristate "Allwinner sunxi AHCI SATA support"
+ depends on ARCH_SUNXI
+ help
+ This option enables support for the Allwinner sunxi SoC's
+ onboard AHCI SATA.
+
+ If unsure, say N.
+
+config AHCI_XGENE
+ tristate "APM X-Gene 6.0Gbps AHCI SATA host controller support"
+ depends on ARM64 || COMPILE_TEST
+ select PHY_XGENE
+ help
+ This option enables support for APM X-Gene SoC SATA host controller.
+
config SATA_FSL
tristate "Freescale 3.0Gbps SATA support"
depends on FSL_SOC
@@ -239,6 +272,7 @@ config SATA_DWC_VDEBUG
config SATA_HIGHBANK
tristate "Calxeda Highbank SATA support"
+ depends on ARCH_HIGHBANK || COMPILE_TEST
help
This option enables support for the Calxeda Highbank SoC's
onboard SATA.
@@ -247,6 +281,9 @@ config SATA_HIGHBANK
config SATA_MV
tristate "Marvell SATA support"
+ depends on PCI || ARCH_DOVE || ARCH_KIRKWOOD || ARCH_MV78XX0 || \
+ ARCH_MVEBU || ARCH_ORION5X || COMPILE_TEST
+ select GENERIC_PHY
help
This option enables support for the Marvell Serial ATA family.
Currently supports 88SX[56]0[48][01] PCI(-X) chips,
@@ -272,6 +309,7 @@ config SATA_PROMISE
config SATA_RCAR
tristate "Renesas R-Car SATA support"
+ depends on ARCH_SHMOBILE || COMPILE_TEST
help
This option enables support for Renesas R-Car Serial ATA.
@@ -351,6 +389,7 @@ config PATA_AMD
config PATA_ARASAN_CF
tristate "ARASAN CompactFlash PATA Controller Support"
+ depends on ARCH_SPEAR13XX || COMPILE_TEST
depends on DMADEVICES
select DMA_ENGINE
help
@@ -402,7 +441,7 @@ config PATA_CMD64X
config PATA_CS5520
tristate "CS5510/5520 PATA support"
- depends on PCI
+ depends on PCI && (X86_32 || COMPILE_TEST)
help
This option enables support for the Cyrix 5510/5520
companion chip used with the MediaGX/Geode processor family.
@@ -411,7 +450,7 @@ config PATA_CS5520
config PATA_CS5530
tristate "CS5530 PATA support"
- depends on PCI
+ depends on PCI && (X86_32 || COMPILE_TEST)
help
This option enables support for the Cyrix/NatSemi/AMD CS5530
companion chip used with the MediaGX/Geode processor family.
@@ -420,7 +459,7 @@ config PATA_CS5530
config PATA_CS5535
tristate "CS5535 PATA support (Experimental)"
- depends on PCI && X86 && !X86_64
+ depends on PCI && X86_32
help
This option enables support for the NatSemi/AMD CS5535
companion chip used with the Geode processor family.
@@ -429,7 +468,7 @@ config PATA_CS5535
config PATA_CS5536
tristate "CS5536 PATA support"
- depends on PCI
+ depends on PCI && (X86_32 || MIPS || COMPILE_TEST)
help
This option enables support for the AMD CS5536
companion chip used with the Geode LX processor family.
@@ -665,7 +704,7 @@ config PATA_RDC
config PATA_SC1200
tristate "SC1200 PATA support"
- depends on PCI
+ depends on PCI && (X86_32 || COMPILE_TEST)
help
This option enables support for the NatSemi/AMD SC1200 SoC
companion chip used with the Geode processor family.
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 46518c622460..44c8016e565c 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -4,13 +4,17 @@ obj-$(CONFIG_ATA) += libata.o
# non-SFF interface
obj-$(CONFIG_SATA_AHCI) += ahci.o libahci.o
obj-$(CONFIG_SATA_ACARD_AHCI) += acard-ahci.o libahci.o
-obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o
+obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o libahci_platform.o
obj-$(CONFIG_SATA_FSL) += sata_fsl.o
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
+obj-$(CONFIG_AHCI_DA850) += ahci_da850.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_SUNXI) += ahci_sunxi.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_ST) += ahci_st.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_XGENE) += ahci_xgene.o libahci.o libahci_platform.o
# SFF w/ custom DMA
obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c
index fd665d919df2..b51605ac5974 100644
--- a/drivers/ata/acard-ahci.c
+++ b/drivers/ata/acard-ahci.c
@@ -36,7 +36,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index dc2756fb6f33..5a0bf8ed649b 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -35,7 +35,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -61,6 +60,7 @@ enum board_ids {
/* board IDs by feature in alphabetical order */
board_ahci,
board_ahci_ign_iferr,
+ board_ahci_noncq,
board_ahci_nosntf,
board_ahci_yes_fbs,
@@ -121,6 +121,13 @@ static const struct ata_port_info ahci_port_info[] = {
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
+ [board_ahci_noncq] = {
+ AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ),
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_ops,
+ },
[board_ahci_nosntf] = {
AHCI_HFLAGS (AHCI_HFLAG_NO_SNTF),
.flags = AHCI_FLAG_COMMON,
@@ -452,6 +459,12 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */
{ PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */
+ /*
+ * Samsung SSDs found on some macbooks. NCQ times out.
+ * https://bugzilla.kernel.org/show_bug.cgi?id=60731
+ */
+ { PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_noncq },
+
/* Enmotus */
{ PCI_DEVICE(0x1c44, 0x8000), board_ahci },
@@ -564,6 +577,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
struct ata_port *ap = link->ap;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
bool online;
int rc;
@@ -574,7 +588,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
deadline, &online, NULL);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
@@ -589,6 +603,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
{
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
bool online;
@@ -604,7 +619,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
deadline, &online, NULL);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
/* The pseudo configuration device on SIMG4726 attached to
* ASUS P5W-DH Deluxe doesn't send signature FIS after
@@ -1151,13 +1166,13 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
struct ahci_host_priv *hpriv)
{
- int rc, nvec;
+ int nvec;
if (hpriv->flags & AHCI_HFLAG_NO_MSI)
goto intx;
- rc = pci_msi_vec_count(pdev);
- if (rc < 0)
+ nvec = pci_msi_vec_count(pdev);
+ if (nvec < 0)
goto intx;
/*
@@ -1165,19 +1180,19 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
* Message mode could be enforced. In this case assume that advantage
* of multipe MSIs is negated and use single MSI mode instead.
*/
- if (rc < n_ports)
+ if (nvec < n_ports)
goto single_msi;
- nvec = rc;
- rc = pci_enable_msi_block(pdev, nvec);
- if (rc)
+ nvec = pci_enable_msi_range(pdev, nvec, nvec);
+ if (nvec == -ENOSPC)
+ goto single_msi;
+ else if (nvec < 0)
goto intx;
return nvec;
single_msi:
- rc = pci_enable_msi(pdev);
- if (rc)
+ if (pci_enable_msi(pdev))
goto intx;
return 1;
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 2289efdf8203..51af275b3388 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -37,6 +37,8 @@
#include <linux/clk.h>
#include <linux/libata.h>
+#include <linux/phy/phy.h>
+#include <linux/regulator/consumer.h>
/* Enclosure Management Control */
#define EM_CTRL_MSG_TYPE 0x000f0000
@@ -51,6 +53,7 @@
enum {
AHCI_MAX_PORTS = 32,
+ AHCI_MAX_CLKS = 3,
AHCI_MAX_SG = 168, /* hardware max is 64K */
AHCI_DMA_BOUNDARY = 0xffffffff,
AHCI_MAX_CMDS = 32,
@@ -321,8 +324,17 @@ struct ahci_host_priv {
u32 em_loc; /* enclosure management location */
u32 em_buf_sz; /* EM buffer size in byte */
u32 em_msg_type; /* EM message type */
- struct clk *clk; /* Only for platforms supporting clk */
+ bool got_runtime_pm; /* Did we do pm_runtime_get? */
+ struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
+ struct regulator *target_pwr; /* Optional */
+ struct phy *phy; /* If platform uses phy */
void *plat_data; /* Other platform data */
+ /*
+ * Optional ahci_start_engine override, if not set this gets set to the
+ * default ahci_start_engine during ahci_save_initial_config, this can
+ * be overridden anytime before the host is activated.
+ */
+ void (*start_engine)(struct ata_port *ap);
};
extern int ahci_ignore_sss;
diff --git a/drivers/ata/ahci_da850.c b/drivers/ata/ahci_da850.c
new file mode 100644
index 000000000000..2c83613ce2db
--- /dev/null
+++ b/drivers/ata/ahci_da850.c
@@ -0,0 +1,114 @@
+/*
+ * DaVinci DA850 AHCI SATA platform 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, or (at your option)
+ * any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/libata.h>
+#include <linux/ahci_platform.h>
+#include "ahci.h"
+
+/* SATA PHY Control Register offset from AHCI base */
+#define SATA_P0PHYCR_REG 0x178
+
+#define SATA_PHY_MPY(x) ((x) << 0)
+#define SATA_PHY_LOS(x) ((x) << 6)
+#define SATA_PHY_RXCDR(x) ((x) << 10)
+#define SATA_PHY_RXEQ(x) ((x) << 13)
+#define SATA_PHY_TXSWING(x) ((x) << 19)
+#define SATA_PHY_ENPLL(x) ((x) << 31)
+
+/*
+ * The multiplier needed for 1.5GHz PLL output.
+ *
+ * NOTE: This is currently hardcoded to be suitable for 100MHz crystal
+ * frequency (which is used by DA850 EVM board) and may need to be changed
+ * if you would like to use this driver on some other board.
+ */
+#define DA850_SATA_CLK_MULTIPLIER 7
+
+static void da850_sata_init(struct device *dev, void __iomem *pwrdn_reg,
+ void __iomem *ahci_base)
+{
+ unsigned int val;
+
+ /* Enable SATA clock receiver */
+ val = readl(pwrdn_reg);
+ val &= ~BIT(0);
+ writel(val, pwrdn_reg);
+
+ val = SATA_PHY_MPY(DA850_SATA_CLK_MULTIPLIER + 1) | SATA_PHY_LOS(1) |
+ SATA_PHY_RXCDR(4) | SATA_PHY_RXEQ(1) | SATA_PHY_TXSWING(3) |
+ SATA_PHY_ENPLL(1);
+
+ writel(val, ahci_base + SATA_P0PHYCR_REG);
+}
+
+static const struct ata_port_info ahci_da850_port_info = {
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_platform_ops,
+};
+
+static int ahci_da850_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ahci_host_priv *hpriv;
+ struct resource *res;
+ void __iomem *pwrdn_reg;
+ int rc;
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ return rc;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res)
+ goto disable_resources;
+
+ pwrdn_reg = devm_ioremap(dev, res->start, resource_size(res));
+ if (!pwrdn_reg)
+ goto disable_resources;
+
+ da850_sata_init(dev, pwrdn_reg, hpriv->mmio);
+
+ rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info, 0, 0);
+ if (rc)
+ goto disable_resources;
+
+ return 0;
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+ return rc;
+}
+
+static SIMPLE_DEV_PM_OPS(ahci_da850_pm_ops, ahci_platform_suspend,
+ ahci_platform_resume);
+
+static struct platform_driver ahci_da850_driver = {
+ .probe = ahci_da850_probe,
+ .remove = ata_platform_remove_one,
+ .driver = {
+ .name = "ahci_da850",
+ .owner = THIS_MODULE,
+ .pm = &ahci_da850_pm_ops,
+ },
+};
+module_platform_driver(ahci_da850_driver);
+
+MODULE_DESCRIPTION("DaVinci DA850 AHCI SATA platform driver");
+MODULE_AUTHOR("Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index dd4d6f74d7bd..497c7abe1c7d 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -42,13 +42,7 @@ enum ahci_imx_type {
struct imx_ahci_priv {
struct platform_device *ahci_pdev;
enum ahci_imx_type type;
-
- /* i.MX53 clock */
- struct clk *sata_gate_clk;
- /* Common clock */
- struct clk *sata_ref_clk;
struct clk *ahb_clk;
-
struct regmap *gpr;
bool no_device;
bool first_time;
@@ -58,28 +52,52 @@ static int ahci_imx_hotplug;
module_param_named(hotplug, ahci_imx_hotplug, int, 0644);
MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support)");
-static int imx_sata_clock_enable(struct device *dev)
+static void ahci_imx_host_stop(struct ata_host *host);
+
+static int imx_sata_enable(struct ahci_host_priv *hpriv)
{
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
int ret;
- if (imxpriv->type == AHCI_IMX53) {
- ret = clk_prepare_enable(imxpriv->sata_gate_clk);
- if (ret < 0) {
- dev_err(dev, "prepare-enable sata_gate clock err:%d\n",
- ret);
+ if (imxpriv->no_device)
+ return 0;
+
+ if (hpriv->target_pwr) {
+ ret = regulator_enable(hpriv->target_pwr);
+ if (ret)
return ret;
- }
}
- ret = clk_prepare_enable(imxpriv->sata_ref_clk);
- if (ret < 0) {
- dev_err(dev, "prepare-enable sata_ref clock err:%d\n",
- ret);
- goto clk_err;
- }
+ ret = ahci_platform_enable_clks(hpriv);
+ if (ret < 0)
+ goto disable_regulator;
if (imxpriv->type == AHCI_IMX6Q) {
+ /*
+ * set PHY Paremeters, two steps to configure the GPR13,
+ * one write for rest of parameters, mask of first write
+ * is 0x07ffffff, and the other one write for setting
+ * the mpll_clk_en.
+ */
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
+ 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_MPLL_CLK_EN |
+ 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, IOMUXC_GPR13,
IMX6Q_GPR13_SATA_MPLL_CLK_EN,
IMX6Q_GPR13_SATA_MPLL_CLK_EN);
@@ -89,15 +107,19 @@ static int imx_sata_clock_enable(struct device *dev)
return 0;
-clk_err:
- if (imxpriv->type == AHCI_IMX53)
- clk_disable_unprepare(imxpriv->sata_gate_clk);
+disable_regulator:
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+
return ret;
}
-static void imx_sata_clock_disable(struct device *dev)
+static void imx_sata_disable(struct ahci_host_priv *hpriv)
{
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
+
+ if (imxpriv->no_device)
+ return;
if (imxpriv->type == AHCI_IMX6Q) {
regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
@@ -105,10 +127,10 @@ static void imx_sata_clock_disable(struct device *dev)
!IMX6Q_GPR13_SATA_MPLL_CLK_EN);
}
- clk_disable_unprepare(imxpriv->sata_ref_clk);
+ ahci_platform_disable_clks(hpriv);
- if (imxpriv->type == AHCI_IMX53)
- clk_disable_unprepare(imxpriv->sata_gate_clk);
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
}
static void ahci_imx_error_handler(struct ata_port *ap)
@@ -118,7 +140,7 @@ static void ahci_imx_error_handler(struct ata_port *ap)
struct ata_host *host = dev_get_drvdata(ap->dev);
struct ahci_host_priv *hpriv = host->private_data;
void __iomem *mmio = hpriv->mmio;
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent);
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
ahci_error_handler(ap);
@@ -136,7 +158,7 @@ static void ahci_imx_error_handler(struct ata_port *ap)
*/
reg_val = readl(mmio + PORT_PHY_CTL);
writel(reg_val | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL);
- imx_sata_clock_disable(ap->dev);
+ imx_sata_disable(hpriv);
imxpriv->no_device = true;
}
@@ -144,7 +166,9 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
struct ata_port *ap = link->ap;
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent);
+ struct ata_host *host = dev_get_drvdata(ap->dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
int ret = -EIO;
if (imxpriv->type == AHCI_IMX53)
@@ -156,7 +180,8 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
}
static struct ata_port_operations ahci_imx_ops = {
- .inherits = &ahci_platform_ops,
+ .inherits = &ahci_ops,
+ .host_stop = ahci_imx_host_stop,
.error_handler = ahci_imx_error_handler,
.softreset = ahci_imx_softreset,
};
@@ -168,79 +193,6 @@ static const struct ata_port_info ahci_imx_port_info = {
.port_ops = &ahci_imx_ops,
};
-static int imx_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);
-
- ret = imx_sata_clock_enable(dev);
- if (ret < 0)
- return ret;
-
- /*
- * 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 imx_sata_exit(struct device *dev)
-{
- imx_sata_clock_disable(dev);
-}
-
-static int imx_ahci_suspend(struct device *dev)
-{
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
-
- /*
- * If no_device is set, The CLKs had been gated off in the
- * initialization so don't do it again here.
- */
- if (!imxpriv->no_device)
- imx_sata_clock_disable(dev);
-
- return 0;
-}
-
-static int imx_ahci_resume(struct device *dev)
-{
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
- int ret = 0;
-
- if (!imxpriv->no_device)
- ret = imx_sata_clock_enable(dev);
-
- return ret;
-}
-
-static struct ahci_platform_data imx_sata_pdata = {
- .init = imx_sata_init,
- .exit = imx_sata_exit,
- .ata_port_info = &ahci_imx_port_info,
- .suspend = imx_ahci_suspend,
- .resume = imx_ahci_resume,
-
-};
-
static const struct of_device_id imx_ahci_of_match[] = {
{ .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 },
{ .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q },
@@ -251,151 +203,124 @@ 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;
- enum ahci_imx_type type;
- const struct ahci_platform_data *pdata = NULL;
+ struct ahci_host_priv *hpriv;
struct imx_ahci_priv *imxpriv;
- struct device *ahci_dev;
- struct platform_device *ahci_pdev;
+ unsigned int reg_val;
int ret;
of_id = of_match_device(imx_ahci_of_match, dev);
if (!of_id)
return -EINVAL;
- type = (enum ahci_imx_type)of_id->data;
- pdata = &imx_sata_pdata;
-
imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL);
- if (!imxpriv) {
- dev_err(dev, "can't alloc ahci_host_priv\n");
+ if (!imxpriv)
return -ENOMEM;
- }
-
- ahci_pdev = platform_device_alloc("ahci", -1);
- if (!ahci_pdev)
- return -ENODEV;
-
- ahci_dev = &ahci_pdev->dev;
- ahci_dev->parent = dev;
imxpriv->no_device = false;
imxpriv->first_time = true;
- imxpriv->type = type;
-
+ imxpriv->type = (enum ahci_imx_type)of_id->data;
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;
+ return PTR_ERR(imxpriv->ahb_clk);
}
- if (type == AHCI_IMX53) {
- imxpriv->sata_gate_clk = devm_clk_get(dev, "sata_gate");
- if (IS_ERR(imxpriv->sata_gate_clk)) {
- dev_err(dev, "can't get sata_gate clock.\n");
- ret = PTR_ERR(imxpriv->sata_gate_clk);
- goto err_out;
+ if (imxpriv->type == AHCI_IMX6Q) {
+ 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);
}
}
- 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;
- }
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ hpriv->plat_data = imxpriv;
- imxpriv->ahci_pdev = ahci_pdev;
- platform_set_drvdata(pdev, imxpriv);
+ ret = imx_sata_enable(hpriv);
+ if (ret)
+ return ret;
- 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;
+ /*
+ * 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(hpriv->mmio + HOST_CAP);
+ if (!(reg_val & HOST_CAP_SSS)) {
+ reg_val |= HOST_CAP_SSS;
+ writel(reg_val, hpriv->mmio + HOST_CAP);
+ }
+ reg_val = readl(hpriv->mmio + HOST_PORTS_IMPL);
+ if (!(reg_val & 0x1)) {
+ reg_val |= 0x1;
+ writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL);
}
- res[0] = *mem;
- res[1] = *irq;
+ reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
+ writel(reg_val, hpriv->mmio + HOST_TIMER1MS);
- 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 = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, 0, 0);
+ if (ret)
+ imx_sata_disable(hpriv);
- if (type == AHCI_IMX6Q) {
- 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");
- ret = PTR_ERR(imxpriv->gpr);
- goto err_out;
- }
+ return ret;
+}
- /*
- * Set PHY Paremeters, two steps to configure the GPR13,
- * one write for rest of parameters, mask of first write
- * is 0x07fffffe, and the other one write for setting
- * the mpll_clk_en happens in imx_sata_clock_enable().
- */
- regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
- 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_MPLL_CLK_EN |
- 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);
- }
+static void ahci_imx_host_stop(struct ata_host *host)
+{
+ struct ahci_host_priv *hpriv = host->private_data;
- ret = platform_device_add_resources(ahci_pdev, res, 2);
- if (ret)
- goto err_out;
+ imx_sata_disable(hpriv);
+}
- ret = platform_device_add_data(ahci_pdev, pdata, sizeof(*pdata));
- if (ret)
- goto err_out;
+#ifdef CONFIG_PM_SLEEP
+static int imx_ahci_suspend(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ int ret;
- ret = platform_device_add(ahci_pdev);
- if (ret) {
-err_out:
- platform_device_put(ahci_pdev);
+ ret = ahci_platform_suspend_host(dev);
+ if (ret)
return ret;
- }
+
+ imx_sata_disable(hpriv);
return 0;
}
-static int imx_ahci_remove(struct platform_device *pdev)
+static int imx_ahci_resume(struct device *dev)
{
- struct imx_ahci_priv *imxpriv = platform_get_drvdata(pdev);
- struct platform_device *ahci_pdev = imxpriv->ahci_pdev;
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ int ret;
- platform_device_unregister(ahci_pdev);
- return 0;
+ ret = imx_sata_enable(hpriv);
+ if (ret)
+ return ret;
+
+ return ahci_platform_resume_host(dev);
}
+#endif
+
+static SIMPLE_DEV_PM_OPS(ahci_imx_pm_ops, imx_ahci_suspend, imx_ahci_resume);
static struct platform_driver imx_ahci_driver = {
.probe = imx_ahci_probe,
- .remove = imx_ahci_remove,
+ .remove = ata_platform_remove_one,
.driver = {
.name = "ahci-imx",
.owner = THIS_MODULE,
.of_match_table = imx_ahci_of_match,
+ .pm = &ahci_imx_pm_ops,
},
};
module_platform_driver(imx_ahci_driver);
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 4b231baceb09..ef67e79944f9 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -12,135 +12,36 @@
* any later version.
*/
-#include <linux/clk.h>
#include <linux/kernel.h>
-#include <linux/gfp.h>
#include <linux/module.h>
#include <linux/pm.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/libata.h>
#include <linux/ahci_platform.h>
#include "ahci.h"
-static void ahci_host_stop(struct ata_host *host);
-
-enum ahci_type {
- AHCI, /* standard platform ahci */
- IMX53_AHCI, /* ahci on i.mx53 */
- STRICT_AHCI, /* delayed DMA engine start */
-};
-
-static struct platform_device_id ahci_devtype[] = {
- {
- .name = "ahci",
- .driver_data = AHCI,
- }, {
- .name = "imx53-ahci",
- .driver_data = IMX53_AHCI,
- }, {
- .name = "strict-ahci",
- .driver_data = STRICT_AHCI,
- }, {
- /* sentinel */
- }
-};
-MODULE_DEVICE_TABLE(platform, ahci_devtype);
-
-struct ata_port_operations ahci_platform_ops = {
- .inherits = &ahci_ops,
- .host_stop = ahci_host_stop,
-};
-EXPORT_SYMBOL_GPL(ahci_platform_ops);
-
-static struct ata_port_operations ahci_platform_retry_srst_ops = {
- .inherits = &ahci_pmp_retry_srst_ops,
- .host_stop = ahci_host_stop,
-};
-
-static const struct ata_port_info ahci_port_info[] = {
- /* by features */
- [AHCI] = {
- .flags = AHCI_FLAG_COMMON,
- .pio_mask = ATA_PIO4,
- .udma_mask = ATA_UDMA6,
- .port_ops = &ahci_platform_ops,
- },
- [IMX53_AHCI] = {
- .flags = AHCI_FLAG_COMMON,
- .pio_mask = ATA_PIO4,
- .udma_mask = ATA_UDMA6,
- .port_ops = &ahci_platform_retry_srst_ops,
- },
- [STRICT_AHCI] = {
- AHCI_HFLAGS (AHCI_HFLAG_DELAY_ENGINE),
- .flags = AHCI_FLAG_COMMON,
- .pio_mask = ATA_PIO4,
- .udma_mask = ATA_UDMA6,
- .port_ops = &ahci_platform_ops,
- },
-};
-
-static struct scsi_host_template ahci_platform_sht = {
- AHCI_SHT("ahci_platform"),
+static const struct ata_port_info ahci_port_info = {
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_platform_ops,
};
static int ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ahci_platform_data *pdata = dev_get_platdata(dev);
- const struct platform_device_id *id = platform_get_device_id(pdev);
- struct ata_port_info pi = ahci_port_info[id ? id->driver_data : 0];
- const struct ata_port_info *ppi[] = { &pi, NULL };
struct ahci_host_priv *hpriv;
- struct ata_host *host;
- struct resource *mem;
- int irq;
- int n_ports;
- int i;
int rc;
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(dev, "no mmio space\n");
- return -EINVAL;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq <= 0) {
- dev_err(dev, "no irq\n");
- return -EINVAL;
- }
-
- if (pdata && pdata->ata_port_info)
- pi = *pdata->ata_port_info;
-
- hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv) {
- dev_err(dev, "can't alloc ahci_host_priv\n");
- return -ENOMEM;
- }
-
- hpriv->flags |= (unsigned long)pi.private_data;
-
- hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
- if (!hpriv->mmio) {
- dev_err(dev, "can't map %pR\n", mem);
- return -ENOMEM;
- }
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
- hpriv->clk = clk_get(dev, NULL);
- if (IS_ERR(hpriv->clk)) {
- dev_err(dev, "can't get clock\n");
- } else {
- rc = clk_prepare_enable(hpriv->clk);
- if (rc) {
- dev_err(dev, "clock prepare enable failed");
- goto free_clk;
- }
- }
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ return rc;
/*
* Some platforms might need to prepare for mmio region access,
@@ -151,69 +52,10 @@ static int ahci_probe(struct platform_device *pdev)
if (pdata && pdata->init) {
rc = pdata->init(dev, hpriv->mmio);
if (rc)
- goto disable_unprepare_clk;
- }
-
- ahci_save_initial_config(dev, hpriv,
- pdata ? pdata->force_port_map : 0,
- pdata ? pdata->mask_port_map : 0);
-
- /* prepare host */
- if (hpriv->cap & HOST_CAP_NCQ)
- pi.flags |= ATA_FLAG_NCQ;
-
- if (hpriv->cap & HOST_CAP_PMP)
- pi.flags |= ATA_FLAG_PMP;
-
- ahci_set_em_messages(hpriv, &pi);
-
- /* CAP.NP sometimes indicate the index of the last enabled
- * port, at other times, that of the last possible port, so
- * determining the maximum port number requires looking at
- * both CAP.NP and port_map.
- */
- n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
-
- host = ata_host_alloc_pinfo(dev, ppi, n_ports);
- if (!host) {
- rc = -ENOMEM;
- goto pdata_exit;
- }
-
- host->private_data = hpriv;
-
- if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
- host->flags |= ATA_HOST_PARALLEL_SCAN;
- else
- dev_info(dev, "SSS flag set, parallel bus scan disabled\n");
-
- if (pi.flags & ATA_FLAG_EM)
- ahci_reset_em(host);
-
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap = host->ports[i];
-
- ata_port_desc(ap, "mmio %pR", mem);
- ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
-
- /* set enclosure management message type */
- if (ap->flags & ATA_FLAG_EM)
- ap->em_message_type = hpriv->em_msg_type;
-
- /* disabled/not-implemented port */
- if (!(hpriv->port_map & (1 << i)))
- ap->ops = &ata_dummy_port_ops;
+ goto disable_resources;
}
- rc = ahci_reset_controller(host);
- if (rc)
- goto pdata_exit;
-
- ahci_init_controller(host);
- ahci_print_info(host, "platform");
-
- rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
- &ahci_platform_sht);
+ rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info, 0, 0);
if (rc)
goto pdata_exit;
@@ -221,115 +63,19 @@ static int ahci_probe(struct platform_device *pdev)
pdata_exit:
if (pdata && pdata->exit)
pdata->exit(dev);
-disable_unprepare_clk:
- if (!IS_ERR(hpriv->clk))
- clk_disable_unprepare(hpriv->clk);
-free_clk:
- if (!IS_ERR(hpriv->clk))
- clk_put(hpriv->clk);
- return rc;
-}
-
-static void ahci_host_stop(struct ata_host *host)
-{
- struct device *dev = host->dev;
- struct ahci_platform_data *pdata = dev_get_platdata(dev);
- struct ahci_host_priv *hpriv = host->private_data;
-
- if (pdata && pdata->exit)
- pdata->exit(dev);
-
- if (!IS_ERR(hpriv->clk)) {
- clk_disable_unprepare(hpriv->clk);
- clk_put(hpriv->clk);
- }
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int ahci_suspend(struct device *dev)
-{
- struct ahci_platform_data *pdata = dev_get_platdata(dev);
- struct ata_host *host = dev_get_drvdata(dev);
- struct ahci_host_priv *hpriv = host->private_data;
- void __iomem *mmio = hpriv->mmio;
- u32 ctl;
- int rc;
-
- if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
- dev_err(dev, "firmware update required for suspend/resume\n");
- return -EIO;
- }
-
- /*
- * AHCI spec rev1.1 section 8.3.3:
- * Software must disable interrupts prior to requesting a
- * transition of the HBA to D3 state.
- */
- ctl = readl(mmio + HOST_CTL);
- ctl &= ~HOST_IRQ_EN;
- writel(ctl, mmio + HOST_CTL);
- readl(mmio + HOST_CTL); /* flush */
-
- rc = ata_host_suspend(host, PMSG_SUSPEND);
- if (rc)
- return rc;
-
- if (pdata && pdata->suspend)
- return pdata->suspend(dev);
-
- if (!IS_ERR(hpriv->clk))
- clk_disable_unprepare(hpriv->clk);
-
- return 0;
-}
-
-static int ahci_resume(struct device *dev)
-{
- struct ahci_platform_data *pdata = dev_get_platdata(dev);
- struct ata_host *host = dev_get_drvdata(dev);
- struct ahci_host_priv *hpriv = host->private_data;
- int rc;
-
- if (!IS_ERR(hpriv->clk)) {
- rc = clk_prepare_enable(hpriv->clk);
- if (rc) {
- dev_err(dev, "clock prepare enable failed");
- return rc;
- }
- }
-
- if (pdata && pdata->resume) {
- rc = pdata->resume(dev);
- if (rc)
- goto disable_unprepare_clk;
- }
-
- if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
- rc = ahci_reset_controller(host);
- if (rc)
- goto disable_unprepare_clk;
-
- ahci_init_controller(host);
- }
-
- ata_host_resume(host);
-
- return 0;
-
-disable_unprepare_clk:
- if (!IS_ERR(hpriv->clk))
- clk_disable_unprepare(hpriv->clk);
-
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
return rc;
}
-#endif
-static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume);
+static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
+ ahci_platform_resume);
static const struct of_device_id ahci_of_match[] = {
{ .compatible = "snps,spear-ahci", },
{ .compatible = "snps,exynos5440-ahci", },
{ .compatible = "ibm,476gtr-ahci", },
+ { .compatible = "snps,dwc-ahci", },
{},
};
MODULE_DEVICE_TABLE(of, ahci_of_match);
@@ -343,7 +89,6 @@ static struct platform_driver ahci_driver = {
.of_match_table = ahci_of_match,
.pm = &ahci_pm_ops,
},
- .id_table = ahci_devtype,
};
module_platform_driver(ahci_driver);
diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c
new file mode 100644
index 000000000000..633222226c19
--- /dev/null
+++ b/drivers/ata/ahci_st.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2012 STMicroelectronics Limited
+ *
+ * Authors: Francesco Virlinzi <francesco.virlinzi@st.com>
+ * Alexandre Torgue <alexandre.torgue@st.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/ahci_platform.h>
+#include <linux/libata.h>
+#include <linux/reset.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+
+#include "ahci.h"
+
+#define ST_AHCI_OOBR 0xbc
+#define ST_AHCI_OOBR_WE BIT(31)
+#define ST_AHCI_OOBR_CWMIN_SHIFT 24
+#define ST_AHCI_OOBR_CWMAX_SHIFT 16
+#define ST_AHCI_OOBR_CIMIN_SHIFT 8
+#define ST_AHCI_OOBR_CIMAX_SHIFT 0
+
+struct st_ahci_drv_data {
+ struct platform_device *ahci;
+ struct reset_control *pwr;
+ struct reset_control *sw_rst;
+ struct reset_control *pwr_rst;
+ struct ahci_host_priv *hpriv;
+};
+
+static void st_ahci_configure_oob(void __iomem *mmio)
+{
+ unsigned long old_val, new_val;
+
+ new_val = (0x02 << ST_AHCI_OOBR_CWMIN_SHIFT) |
+ (0x04 << ST_AHCI_OOBR_CWMAX_SHIFT) |
+ (0x08 << ST_AHCI_OOBR_CIMIN_SHIFT) |
+ (0x0C << ST_AHCI_OOBR_CIMAX_SHIFT);
+
+ old_val = readl(mmio + ST_AHCI_OOBR);
+ writel(old_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR);
+ writel(new_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR);
+ writel(new_val, mmio + ST_AHCI_OOBR);
+}
+
+static int st_ahci_deassert_resets(struct device *dev)
+{
+ struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+ int err;
+
+ if (drv_data->pwr) {
+ err = reset_control_deassert(drv_data->pwr);
+ if (err) {
+ dev_err(dev, "unable to bring out of pwrdwn\n");
+ return err;
+ }
+ }
+
+ st_ahci_configure_oob(drv_data->hpriv->mmio);
+
+ if (drv_data->sw_rst) {
+ err = reset_control_deassert(drv_data->sw_rst);
+ if (err) {
+ dev_err(dev, "unable to bring out of sw-rst\n");
+ return err;
+ }
+ }
+
+ if (drv_data->pwr_rst) {
+ err = reset_control_deassert(drv_data->pwr_rst);
+ if (err) {
+ dev_err(dev, "unable to bring out of pwr-rst\n");
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static void st_ahci_host_stop(struct ata_host *host)
+{
+ struct ahci_host_priv *hpriv = host->private_data;
+ struct device *dev = host->dev;
+ struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+ int err;
+
+ if (drv_data->pwr) {
+ err = reset_control_assert(drv_data->pwr);
+ if (err)
+ dev_err(dev, "unable to pwrdwn\n");
+ }
+
+ ahci_platform_disable_resources(hpriv);
+}
+
+static int st_ahci_probe_resets(struct platform_device *pdev)
+{
+ struct st_ahci_drv_data *drv_data = platform_get_drvdata(pdev);
+
+ drv_data->pwr = devm_reset_control_get(&pdev->dev, "pwr-dwn");
+ if (IS_ERR(drv_data->pwr)) {
+ dev_info(&pdev->dev, "power reset control not defined\n");
+ drv_data->pwr = NULL;
+ }
+
+ drv_data->sw_rst = devm_reset_control_get(&pdev->dev, "sw-rst");
+ if (IS_ERR(drv_data->sw_rst)) {
+ dev_info(&pdev->dev, "soft reset control not defined\n");
+ drv_data->sw_rst = NULL;
+ }
+
+ drv_data->pwr_rst = devm_reset_control_get(&pdev->dev, "pwr-rst");
+ if (IS_ERR(drv_data->pwr_rst)) {
+ dev_dbg(&pdev->dev, "power soft reset control not defined\n");
+ drv_data->pwr_rst = NULL;
+ }
+
+ return st_ahci_deassert_resets(&pdev->dev);
+}
+
+static struct ata_port_operations st_ahci_port_ops = {
+ .inherits = &ahci_platform_ops,
+ .host_stop = st_ahci_host_stop,
+};
+
+static const struct ata_port_info st_ahci_port_info = {
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &st_ahci_port_ops,
+};
+
+static int st_ahci_probe(struct platform_device *pdev)
+{
+ struct st_ahci_drv_data *drv_data;
+ struct ahci_host_priv *hpriv;
+ int err;
+
+ drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL);
+ if (!drv_data)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, drv_data);
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ drv_data->hpriv = hpriv;
+
+ err = st_ahci_probe_resets(pdev);
+ if (err)
+ return err;
+
+ err = ahci_platform_enable_resources(hpriv);
+ if (err)
+ return err;
+
+ err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info, 0, 0);
+ if (err) {
+ ahci_platform_disable_resources(hpriv);
+ return err;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int st_ahci_suspend(struct device *dev)
+{
+ struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = drv_data->hpriv;
+ int err;
+
+ err = ahci_platform_suspend_host(dev);
+ if (err)
+ return err;
+
+ if (drv_data->pwr) {
+ err = reset_control_assert(drv_data->pwr);
+ if (err) {
+ dev_err(dev, "unable to pwrdwn");
+ return err;
+ }
+ }
+
+ ahci_platform_disable_resources(hpriv);
+
+ return 0;
+}
+
+static int st_ahci_resume(struct device *dev)
+{
+ struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = drv_data->hpriv;
+ int err;
+
+ err = ahci_platform_enable_resources(hpriv);
+ if (err)
+ return err;
+
+ err = st_ahci_deassert_resets(dev);
+ if (err) {
+ ahci_platform_disable_resources(hpriv);
+ return err;
+ }
+
+ return ahci_platform_resume_host(dev);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(st_ahci_pm_ops, st_ahci_suspend, st_ahci_resume);
+
+static struct of_device_id st_ahci_match[] = {
+ { .compatible = "st,ahci", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, st_ahci_match);
+
+static struct platform_driver st_ahci_driver = {
+ .driver = {
+ .name = "st_ahci",
+ .owner = THIS_MODULE,
+ .pm = &st_ahci_pm_ops,
+ .of_match_table = of_match_ptr(st_ahci_match),
+ },
+ .probe = st_ahci_probe,
+ .remove = ata_platform_remove_one,
+};
+module_platform_driver(st_ahci_driver);
+
+MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@st.com>");
+MODULE_AUTHOR("Francesco Virlinzi <francesco.virlinzi@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics SATA AHCI Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c
new file mode 100644
index 000000000000..42d3f64e74b3
--- /dev/null
+++ b/drivers/ata/ahci_sunxi.c
@@ -0,0 +1,249 @@
+/*
+ * Allwinner sunxi AHCI SATA platform driver
+ * Copyright 2013 Olliver Schinagl <oliver@schinagl.nl>
+ * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
+ * Based on code from Allwinner Technology Co., Ltd. <www.allwinnertech.com>,
+ * Daniel Wang <danielwang@allwinnertech.com>
+ *
+ * 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.
+ */
+
+#include <linux/ahci_platform.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include "ahci.h"
+
+#define AHCI_BISTAFR 0x00a0
+#define AHCI_BISTCR 0x00a4
+#define AHCI_BISTFCTR 0x00a8
+#define AHCI_BISTSR 0x00ac
+#define AHCI_BISTDECR 0x00b0
+#define AHCI_DIAGNR0 0x00b4
+#define AHCI_DIAGNR1 0x00b8
+#define AHCI_OOBR 0x00bc
+#define AHCI_PHYCS0R 0x00c0
+#define AHCI_PHYCS1R 0x00c4
+#define AHCI_PHYCS2R 0x00c8
+#define AHCI_TIMER1MS 0x00e0
+#define AHCI_GPARAM1R 0x00e8
+#define AHCI_GPARAM2R 0x00ec
+#define AHCI_PPARAMR 0x00f0
+#define AHCI_TESTR 0x00f4
+#define AHCI_VERSIONR 0x00f8
+#define AHCI_IDR 0x00fc
+#define AHCI_RWCR 0x00fc
+#define AHCI_P0DMACR 0x0170
+#define AHCI_P0PHYCR 0x0178
+#define AHCI_P0PHYSR 0x017c
+
+static void sunxi_clrbits(void __iomem *reg, u32 clr_val)
+{
+ u32 reg_val;
+
+ reg_val = readl(reg);
+ reg_val &= ~(clr_val);
+ writel(reg_val, reg);
+}
+
+static void sunxi_setbits(void __iomem *reg, u32 set_val)
+{
+ u32 reg_val;
+
+ reg_val = readl(reg);
+ reg_val |= set_val;
+ writel(reg_val, reg);
+}
+
+static void sunxi_clrsetbits(void __iomem *reg, u32 clr_val, u32 set_val)
+{
+ u32 reg_val;
+
+ reg_val = readl(reg);
+ reg_val &= ~(clr_val);
+ reg_val |= set_val;
+ writel(reg_val, reg);
+}
+
+static u32 sunxi_getbits(void __iomem *reg, u8 mask, u8 shift)
+{
+ return (readl(reg) >> shift) & mask;
+}
+
+static int ahci_sunxi_phy_init(struct device *dev, void __iomem *reg_base)
+{
+ u32 reg_val;
+ int timeout;
+
+ /* This magic is from the original code */
+ writel(0, reg_base + AHCI_RWCR);
+ msleep(5);
+
+ sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(19));
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS0R,
+ (0x7 << 24),
+ (0x5 << 24) | BIT(23) | BIT(18));
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS1R,
+ (0x3 << 16) | (0x1f << 8) | (0x3 << 6),
+ (0x2 << 16) | (0x6 << 8) | (0x2 << 6));
+ sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(28) | BIT(15));
+ sunxi_clrbits(reg_base + AHCI_PHYCS1R, BIT(19));
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS0R,
+ (0x7 << 20), (0x3 << 20));
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS2R,
+ (0x1f << 5), (0x19 << 5));
+ msleep(5);
+
+ sunxi_setbits(reg_base + AHCI_PHYCS0R, (0x1 << 19));
+
+ timeout = 250; /* Power up takes aprox 50 us */
+ do {
+ reg_val = sunxi_getbits(reg_base + AHCI_PHYCS0R, 0x7, 28);
+ if (reg_val == 0x02)
+ break;
+
+ if (--timeout == 0) {
+ dev_err(dev, "PHY power up failed.\n");
+ return -EIO;
+ }
+ udelay(1);
+ } while (1);
+
+ sunxi_setbits(reg_base + AHCI_PHYCS2R, (0x1 << 24));
+
+ timeout = 100; /* Calibration takes aprox 10 us */
+ do {
+ reg_val = sunxi_getbits(reg_base + AHCI_PHYCS2R, 0x1, 24);
+ if (reg_val == 0x00)
+ break;
+
+ if (--timeout == 0) {
+ dev_err(dev, "PHY calibration failed.\n");
+ return -EIO;
+ }
+ udelay(1);
+ } while (1);
+
+ msleep(15);
+
+ writel(0x7, reg_base + AHCI_RWCR);
+
+ return 0;
+}
+
+static void ahci_sunxi_start_engine(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+
+ /* Setup DMA before DMA start */
+ sunxi_clrsetbits(hpriv->mmio + AHCI_P0DMACR, 0x0000ff00, 0x00004400);
+
+ /* Start DMA */
+ sunxi_setbits(port_mmio + PORT_CMD, PORT_CMD_START);
+}
+
+static const struct ata_port_info ahci_sunxi_port_info = {
+ AHCI_HFLAGS(AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
+ AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ),
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_platform_ops,
+};
+
+static int ahci_sunxi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ahci_host_priv *hpriv;
+ int rc;
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ hpriv->start_engine = ahci_sunxi_start_engine;
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ return rc;
+
+ rc = ahci_sunxi_phy_init(dev, hpriv->mmio);
+ if (rc)
+ goto disable_resources;
+
+ rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info, 0, 0);
+ if (rc)
+ goto disable_resources;
+
+ return 0;
+
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+ return rc;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ahci_sunxi_resume(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ int rc;
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ return rc;
+
+ rc = ahci_sunxi_phy_init(dev, hpriv->mmio);
+ if (rc)
+ goto disable_resources;
+
+ rc = ahci_platform_resume_host(dev);
+ if (rc)
+ goto disable_resources;
+
+ return 0;
+
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+ return rc;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(ahci_sunxi_pm_ops, ahci_platform_suspend,
+ ahci_sunxi_resume);
+
+static const struct of_device_id ahci_sunxi_of_match[] = {
+ { .compatible = "allwinner,sun4i-a10-ahci", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ahci_sunxi_of_match);
+
+static struct platform_driver ahci_sunxi_driver = {
+ .probe = ahci_sunxi_probe,
+ .remove = ata_platform_remove_one,
+ .driver = {
+ .name = "ahci-sunxi",
+ .owner = THIS_MODULE,
+ .of_match_table = ahci_sunxi_of_match,
+ .pm = &ahci_sunxi_pm_ops,
+ },
+};
+module_platform_driver(ahci_sunxi_driver);
+
+MODULE_DESCRIPTION("Allwinner sunxi AHCI SATA driver");
+MODULE_AUTHOR("Olliver Schinagl <oliver@schinagl.nl>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c
new file mode 100644
index 000000000000..77c89bf171f1
--- /dev/null
+++ b/drivers/ata/ahci_xgene.c
@@ -0,0 +1,486 @@
+/*
+ * AppliedMicro X-Gene SoC SATA Host Controller Driver
+ *
+ * Copyright (c) 2014, Applied Micro Circuits Corporation
+ * Author: Loc Ho <lho@apm.com>
+ * Tuan Phan <tphan@apm.com>
+ * Suman Tripathi <stripathi@apm.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, see <http://www.gnu.org/licenses/>.
+ *
+ * NOTE: PM support is not currently available.
+ *
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/ahci_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/phy/phy.h>
+#include "ahci.h"
+
+/* Max # of disk per a controller */
+#define MAX_AHCI_CHN_PERCTR 2
+
+/* MUX CSR */
+#define SATA_ENET_CONFIG_REG 0x00000000
+#define CFG_SATA_ENET_SELECT_MASK 0x00000001
+
+/* SATA core host controller CSR */
+#define SLVRDERRATTRIBUTES 0x00000000
+#define SLVWRERRATTRIBUTES 0x00000004
+#define MSTRDERRATTRIBUTES 0x00000008
+#define MSTWRERRATTRIBUTES 0x0000000c
+#define BUSCTLREG 0x00000014
+#define IOFMSTRWAUX 0x00000018
+#define INTSTATUSMASK 0x0000002c
+#define ERRINTSTATUS 0x00000030
+#define ERRINTSTATUSMASK 0x00000034
+
+/* SATA host AHCI CSR */
+#define PORTCFG 0x000000a4
+#define PORTADDR_SET(dst, src) \
+ (((dst) & ~0x0000003f) | (((u32)(src)) & 0x0000003f))
+#define PORTPHY1CFG 0x000000a8
+#define PORTPHY1CFG_FRCPHYRDY_SET(dst, src) \
+ (((dst) & ~0x00100000) | (((u32)(src) << 0x14) & 0x00100000))
+#define PORTPHY2CFG 0x000000ac
+#define PORTPHY3CFG 0x000000b0
+#define PORTPHY4CFG 0x000000b4
+#define PORTPHY5CFG 0x000000b8
+#define SCTL0 0x0000012C
+#define PORTPHY5CFG_RTCHG_SET(dst, src) \
+ (((dst) & ~0xfff00000) | (((u32)(src) << 0x14) & 0xfff00000))
+#define PORTAXICFG_EN_CONTEXT_SET(dst, src) \
+ (((dst) & ~0x01000000) | (((u32)(src) << 0x18) & 0x01000000))
+#define PORTAXICFG 0x000000bc
+#define PORTAXICFG_OUTTRANS_SET(dst, src) \
+ (((dst) & ~0x00f00000) | (((u32)(src) << 0x14) & 0x00f00000))
+
+/* SATA host controller AXI CSR */
+#define INT_SLV_TMOMASK 0x00000010
+
+/* SATA diagnostic CSR */
+#define CFG_MEM_RAM_SHUTDOWN 0x00000070
+#define BLOCK_MEM_RDY 0x00000074
+
+struct xgene_ahci_context {
+ struct ahci_host_priv *hpriv;
+ struct device *dev;
+ void __iomem *csr_core; /* Core CSR address of IP */
+ void __iomem *csr_diag; /* Diag CSR address of IP */
+ void __iomem *csr_axi; /* AXI CSR address of IP */
+ void __iomem *csr_mux; /* MUX CSR address of IP */
+};
+
+static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx)
+{
+ dev_dbg(ctx->dev, "Release memory from shutdown\n");
+ writel(0x0, ctx->csr_diag + CFG_MEM_RAM_SHUTDOWN);
+ readl(ctx->csr_diag + CFG_MEM_RAM_SHUTDOWN); /* Force a barrier */
+ msleep(1); /* reset may take up to 1ms */
+ if (readl(ctx->csr_diag + BLOCK_MEM_RDY) != 0xFFFFFFFF) {
+ dev_err(ctx->dev, "failed to release memory from shutdown\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+/**
+ * xgene_ahci_read_id - Read ID data from the specified device
+ * @dev: device
+ * @tf: proposed taskfile
+ * @id: data buffer
+ *
+ * This custom read ID function is required due to the fact that the HW
+ * does not support DEVSLP and the controller state machine may get stuck
+ * after processing the ID query command.
+ */
+static unsigned int xgene_ahci_read_id(struct ata_device *dev,
+ struct ata_taskfile *tf, u16 *id)
+{
+ u32 err_mask;
+ void __iomem *port_mmio = ahci_port_base(dev->link->ap);
+
+ err_mask = ata_do_dev_read_id(dev, tf, id);
+ if (err_mask)
+ return err_mask;
+
+ /*
+ * Mask reserved area. Word78 spec of Link Power Management
+ * bit15-8: reserved
+ * bit7: NCQ autosence
+ * bit6: Software settings preservation supported
+ * bit5: reserved
+ * bit4: In-order sata delivery supported
+ * bit3: DIPM requests supported
+ * bit2: DMA Setup FIS Auto-Activate optimization supported
+ * bit1: DMA Setup FIX non-Zero buffer offsets supported
+ * bit0: Reserved
+ *
+ * Clear reserved bit 8 (DEVSLP bit) as we don't support DEVSLP
+ */
+ id[ATA_ID_FEATURE_SUPP] &= ~(1 << 8);
+
+ /*
+ * Due to HW errata, restart the port if no other command active.
+ * Otherwise the controller may get stuck.
+ */
+ if (!readl(port_mmio + PORT_CMD_ISSUE)) {
+ writel(PORT_CMD_FIS_RX, port_mmio + PORT_CMD);
+ readl(port_mmio + PORT_CMD); /* Force a barrier */
+ writel(PORT_CMD_FIS_RX | PORT_CMD_START, port_mmio + PORT_CMD);
+ readl(port_mmio + PORT_CMD); /* Force a barrier */
+ }
+ return 0;
+}
+
+static void xgene_ahci_set_phy_cfg(struct xgene_ahci_context *ctx, int channel)
+{
+ void __iomem *mmio = ctx->hpriv->mmio;
+ u32 val;
+
+ dev_dbg(ctx->dev, "port configure mmio 0x%p channel %d\n",
+ mmio, channel);
+ val = readl(mmio + PORTCFG);
+ val = PORTADDR_SET(val, channel == 0 ? 2 : 3);
+ writel(val, mmio + PORTCFG);
+ readl(mmio + PORTCFG); /* Force a barrier */
+ /* Disable fix rate */
+ writel(0x0001fffe, mmio + PORTPHY1CFG);
+ readl(mmio + PORTPHY1CFG); /* Force a barrier */
+ writel(0x5018461c, mmio + PORTPHY2CFG);
+ readl(mmio + PORTPHY2CFG); /* Force a barrier */
+ writel(0x1c081907, mmio + PORTPHY3CFG);
+ readl(mmio + PORTPHY3CFG); /* Force a barrier */
+ writel(0x1c080815, mmio + PORTPHY4CFG);
+ readl(mmio + PORTPHY4CFG); /* Force a barrier */
+ /* Set window negotiation */
+ val = readl(mmio + PORTPHY5CFG);
+ val = PORTPHY5CFG_RTCHG_SET(val, 0x300);
+ writel(val, mmio + PORTPHY5CFG);
+ readl(mmio + PORTPHY5CFG); /* Force a barrier */
+ val = readl(mmio + PORTAXICFG);
+ val = PORTAXICFG_EN_CONTEXT_SET(val, 0x1); /* Enable context mgmt */
+ val = PORTAXICFG_OUTTRANS_SET(val, 0xe); /* Set outstanding */
+ writel(val, mmio + PORTAXICFG);
+ readl(mmio + PORTAXICFG); /* Force a barrier */
+}
+
+/**
+ * xgene_ahci_do_hardreset - Issue the actual COMRESET
+ * @link: link to reset
+ * @deadline: deadline jiffies for the operation
+ * @online: Return value to indicate if device online
+ *
+ * Due to the limitation of the hardware PHY, a difference set of setting is
+ * required for each supported disk speed - Gen3 (6.0Gbps), Gen2 (3.0Gbps),
+ * and Gen1 (1.5Gbps). Otherwise during long IO stress test, the PHY will
+ * report disparity error and etc. In addition, during COMRESET, there can
+ * be error reported in the register PORT_SCR_ERR. For SERR_DISPARITY and
+ * SERR_10B_8B_ERR, the PHY receiver line must be reseted. The following
+ * algorithm is followed to proper configure the hardware PHY during COMRESET:
+ *
+ * Alg Part 1:
+ * 1. Start the PHY at Gen3 speed (default setting)
+ * 2. Issue the COMRESET
+ * 3. If no link, go to Alg Part 3
+ * 4. If link up, determine if the negotiated speed matches the PHY
+ * configured speed
+ * 5. If they matched, go to Alg Part 2
+ * 6. If they do not matched and first time, configure the PHY for the linked
+ * up disk speed and repeat step 2
+ * 7. Go to Alg Part 2
+ *
+ * Alg Part 2:
+ * 1. On link up, if there are any SERR_DISPARITY and SERR_10B_8B_ERR error
+ * reported in the register PORT_SCR_ERR, then reset the PHY receiver line
+ * 2. Go to Alg Part 3
+ *
+ * Alg Part 3:
+ * 1. Clear any pending from register PORT_SCR_ERR.
+ *
+ * NOTE: For the initial version, we will NOT support Gen1/Gen2. In addition
+ * and until the underlying PHY supports an method to reset the receiver
+ * line, on detection of SERR_DISPARITY or SERR_10B_8B_ERR errors,
+ * an warning message will be printed.
+ */
+static int xgene_ahci_do_hardreset(struct ata_link *link,
+ unsigned long deadline, bool *online)
+{
+ const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+ struct ata_port *ap = link->ap;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct xgene_ahci_context *ctx = hpriv->plat_data;
+ struct ahci_port_priv *pp = ap->private_data;
+ u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ata_taskfile tf;
+ int rc;
+ u32 val;
+
+ /* clear D2H reception area to properly wait for D2H FIS */
+ ata_tf_init(link->device, &tf);
+ tf.command = ATA_BUSY;
+ ata_tf_to_fis(&tf, 0, 0, d2h_fis);
+ rc = sata_link_hardreset(link, timing, deadline, online,
+ ahci_check_ready);
+
+ val = readl(port_mmio + PORT_SCR_ERR);
+ if (val & (SERR_DISPARITY | SERR_10B_8B_ERR))
+ dev_warn(ctx->dev, "link has error\n");
+
+ /* clear all errors if any pending */
+ val = readl(port_mmio + PORT_SCR_ERR);
+ writel(val, port_mmio + PORT_SCR_ERR);
+
+ return rc;
+}
+
+static int xgene_ahci_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ bool online;
+ int rc;
+ u32 portcmd_saved;
+ u32 portclb_saved;
+ u32 portclbhi_saved;
+ u32 portrxfis_saved;
+ u32 portrxfishi_saved;
+
+ /* As hardreset resets these CSR, save it to restore later */
+ portcmd_saved = readl(port_mmio + PORT_CMD);
+ portclb_saved = readl(port_mmio + PORT_LST_ADDR);
+ portclbhi_saved = readl(port_mmio + PORT_LST_ADDR_HI);
+ portrxfis_saved = readl(port_mmio + PORT_FIS_ADDR);
+ portrxfishi_saved = readl(port_mmio + PORT_FIS_ADDR_HI);
+
+ ahci_stop_engine(ap);
+
+ rc = xgene_ahci_do_hardreset(link, deadline, &online);
+
+ /* As controller hardreset clears them, restore them */
+ writel(portcmd_saved, port_mmio + PORT_CMD);
+ writel(portclb_saved, port_mmio + PORT_LST_ADDR);
+ writel(portclbhi_saved, port_mmio + PORT_LST_ADDR_HI);
+ writel(portrxfis_saved, port_mmio + PORT_FIS_ADDR);
+ writel(portrxfishi_saved, port_mmio + PORT_FIS_ADDR_HI);
+
+ hpriv->start_engine(ap);
+
+ if (online)
+ *class = ahci_dev_classify(ap);
+
+ return rc;
+}
+
+static void xgene_ahci_host_stop(struct ata_host *host)
+{
+ struct ahci_host_priv *hpriv = host->private_data;
+
+ ahci_platform_disable_resources(hpriv);
+}
+
+static struct ata_port_operations xgene_ahci_ops = {
+ .inherits = &ahci_ops,
+ .host_stop = xgene_ahci_host_stop,
+ .hardreset = xgene_ahci_hardreset,
+ .read_id = xgene_ahci_read_id,
+};
+
+static const struct ata_port_info xgene_ahci_port_info = {
+ AHCI_HFLAGS(AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ),
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &xgene_ahci_ops,
+};
+
+static int xgene_ahci_hw_init(struct ahci_host_priv *hpriv)
+{
+ struct xgene_ahci_context *ctx = hpriv->plat_data;
+ int i;
+ int rc;
+ u32 val;
+
+ /* Remove IP RAM out of shutdown */
+ rc = xgene_ahci_init_memram(ctx);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < MAX_AHCI_CHN_PERCTR; i++)
+ xgene_ahci_set_phy_cfg(ctx, i);
+
+ /* AXI disable Mask */
+ writel(0xffffffff, hpriv->mmio + HOST_IRQ_STAT);
+ readl(hpriv->mmio + HOST_IRQ_STAT); /* Force a barrier */
+ writel(0, ctx->csr_core + INTSTATUSMASK);
+ val = readl(ctx->csr_core + INTSTATUSMASK); /* Force a barrier */
+ dev_dbg(ctx->dev, "top level interrupt mask 0x%X value 0x%08X\n",
+ INTSTATUSMASK, val);
+
+ writel(0x0, ctx->csr_core + ERRINTSTATUSMASK);
+ readl(ctx->csr_core + ERRINTSTATUSMASK); /* Force a barrier */
+ writel(0x0, ctx->csr_axi + INT_SLV_TMOMASK);
+ readl(ctx->csr_axi + INT_SLV_TMOMASK);
+
+ /* Enable AXI Interrupt */
+ writel(0xffffffff, ctx->csr_core + SLVRDERRATTRIBUTES);
+ writel(0xffffffff, ctx->csr_core + SLVWRERRATTRIBUTES);
+ writel(0xffffffff, ctx->csr_core + MSTRDERRATTRIBUTES);
+ writel(0xffffffff, ctx->csr_core + MSTWRERRATTRIBUTES);
+
+ /* Enable coherency */
+ val = readl(ctx->csr_core + BUSCTLREG);
+ val &= ~0x00000002; /* Enable write coherency */
+ val &= ~0x00000001; /* Enable read coherency */
+ writel(val, ctx->csr_core + BUSCTLREG);
+
+ val = readl(ctx->csr_core + IOFMSTRWAUX);
+ val |= (1 << 3); /* Enable read coherency */
+ val |= (1 << 9); /* Enable write coherency */
+ writel(val, ctx->csr_core + IOFMSTRWAUX);
+ val = readl(ctx->csr_core + IOFMSTRWAUX);
+ dev_dbg(ctx->dev, "coherency 0x%X value 0x%08X\n",
+ IOFMSTRWAUX, val);
+
+ return rc;
+}
+
+static int xgene_ahci_mux_select(struct xgene_ahci_context *ctx)
+{
+ u32 val;
+
+ /* Check for optional MUX resource */
+ if (IS_ERR(ctx->csr_mux))
+ return 0;
+
+ val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG);
+ val &= ~CFG_SATA_ENET_SELECT_MASK;
+ writel(val, ctx->csr_mux + SATA_ENET_CONFIG_REG);
+ val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG);
+ return val & CFG_SATA_ENET_SELECT_MASK ? -1 : 0;
+}
+
+static int xgene_ahci_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ahci_host_priv *hpriv;
+ struct xgene_ahci_context *ctx;
+ struct resource *res;
+ int rc;
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ hpriv->plat_data = ctx;
+ ctx->hpriv = hpriv;
+ ctx->dev = dev;
+
+ /* Retrieve the IP core resource */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ ctx->csr_core = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ctx->csr_core))
+ return PTR_ERR(ctx->csr_core);
+
+ /* Retrieve the IP diagnostic resource */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ ctx->csr_diag = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ctx->csr_diag))
+ return PTR_ERR(ctx->csr_diag);
+
+ /* Retrieve the IP AXI resource */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+ ctx->csr_axi = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ctx->csr_axi))
+ return PTR_ERR(ctx->csr_axi);
+
+ /* Retrieve the optional IP mux resource */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
+ ctx->csr_mux = devm_ioremap_resource(dev, res);
+
+ dev_dbg(dev, "VAddr 0x%p Mmio VAddr 0x%p\n", ctx->csr_core,
+ hpriv->mmio);
+
+ /* Select ATA */
+ if ((rc = xgene_ahci_mux_select(ctx))) {
+ dev_err(dev, "SATA mux selection failed error %d\n", rc);
+ return -ENODEV;
+ }
+
+ /* Due to errata, HW requires full toggle transition */
+ rc = ahci_platform_enable_clks(hpriv);
+ if (rc)
+ goto disable_resources;
+ ahci_platform_disable_clks(hpriv);
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ goto disable_resources;
+
+ /* Configure the host controller */
+ xgene_ahci_hw_init(hpriv);
+
+ /*
+ * Setup DMA mask. This is preliminary until the DMA range is sorted
+ * out.
+ */
+ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
+ if (rc) {
+ dev_err(dev, "Unable to set dma mask\n");
+ goto disable_resources;
+ }
+
+ rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info, 0, 0);
+ if (rc)
+ goto disable_resources;
+
+ dev_dbg(dev, "X-Gene SATA host controller initialized\n");
+ return 0;
+
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+ return rc;
+}
+
+static const struct of_device_id xgene_ahci_of_match[] = {
+ {.compatible = "apm,xgene-ahci"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, xgene_ahci_of_match);
+
+static struct platform_driver xgene_ahci_driver = {
+ .probe = xgene_ahci_probe,
+ .remove = ata_platform_remove_one,
+ .driver = {
+ .name = "xgene-ahci",
+ .owner = THIS_MODULE,
+ .of_match_table = xgene_ahci_of_match,
+ },
+};
+
+module_platform_driver(xgene_ahci_driver);
+
+MODULE_DESCRIPTION("APM X-Gene AHCI SATA driver");
+MODULE_AUTHOR("Loc Ho <lho@apm.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.4");
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index 7d196656adb5..9498a7d3846f 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 36605abe5a67..6bd4f660b4e1 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -35,7 +35,6 @@
#include <linux/kernel.h>
#include <linux/gfp.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -394,6 +393,9 @@ static ssize_t ahci_show_em_supported(struct device *dev,
*
* If inconsistent, config values are fixed up by this function.
*
+ * If it is not set already this function sets hpriv->start_engine to
+ * ahci_start_engine.
+ *
* LOCKING:
* None.
*/
@@ -500,6 +502,9 @@ void ahci_save_initial_config(struct device *dev,
hpriv->cap = cap;
hpriv->cap2 = cap2;
hpriv->port_map = port_map;
+
+ if (!hpriv->start_engine)
+ hpriv->start_engine = ahci_start_engine;
}
EXPORT_SYMBOL_GPL(ahci_save_initial_config);
@@ -766,7 +771,7 @@ static void ahci_start_port(struct ata_port *ap)
/* enable DMA */
if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE))
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
/* turn on LEDs */
if (ap->flags & ATA_FLAG_EM) {
@@ -1032,12 +1037,13 @@ static ssize_t ahci_led_show(struct ata_port *ap, char *buf)
static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
size_t size)
{
- int state;
+ unsigned int state;
int pmp;
struct ahci_port_priv *pp = ap->private_data;
struct ahci_em_priv *emp;
- state = simple_strtoul(buf, NULL, 0);
+ if (kstrtouint(buf, 0, &state) < 0)
+ return -EINVAL;
/* get the slot number from the message */
pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
@@ -1234,7 +1240,7 @@ int ahci_kick_engine(struct ata_port *ap)
/* restart engine */
out_restart:
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
return rc;
}
EXPORT_SYMBOL_GPL(ahci_kick_engine);
@@ -1387,8 +1393,8 @@ static int ahci_bad_pmp_check_ready(struct ata_link *link)
return ata_check_ready(status);
}
-int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class,
- unsigned long deadline)
+static int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
{
struct ata_port *ap = link->ap;
void __iomem *port_mmio = ahci_port_base(ap);
@@ -1426,6 +1432,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
bool online;
@@ -1443,7 +1450,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
rc = sata_link_hardreset(link, timing, deadline, &online,
ahci_check_ready);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
if (online)
*class = ahci_dev_classify(ap);
@@ -1629,7 +1636,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
}
if (irq_stat & PORT_IRQ_UNK_FIS) {
- u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
+ u32 *unk = pp->rx_fis + RX_FIS_UNK;
active_ehi->err_mask |= AC_ERR_HSM;
active_ehi->action |= ATA_EH_RESET;
@@ -2007,10 +2014,12 @@ static void ahci_thaw(struct ata_port *ap)
void ahci_error_handler(struct ata_port *ap)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
/* restart engine */
ahci_stop_engine(ap);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
}
sata_pmp_error_handler(ap);
@@ -2031,6 +2040,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
struct ata_device *dev = ap->link.device;
u32 devslp, dm, dito, mdat, deto;
@@ -2094,7 +2104,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
PORT_DEVSLP_ADSE);
writel(devslp, port_mmio + PORT_DEVSLP);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
/* enable device sleep feature for the drive */
err_mask = ata_dev_set_feature(dev,
@@ -2106,6 +2116,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
static void ahci_enable_fbs(struct ata_port *ap)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
u32 fbs;
@@ -2134,11 +2145,12 @@ static void ahci_enable_fbs(struct ata_port *ap)
} else
dev_err(ap->host->dev, "Failed to enable FBS\n");
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
}
static void ahci_disable_fbs(struct ata_port *ap)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
u32 fbs;
@@ -2166,7 +2178,7 @@ static void ahci_disable_fbs(struct ata_port *ap)
pp->fbs_enabled = false;
}
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
}
static void ahci_pmp_attach(struct ata_port *ap)
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
new file mode 100644
index 000000000000..7cb3a85719c0
--- /dev/null
+++ b/drivers/ata/libahci_platform.c
@@ -0,0 +1,541 @@
+/*
+ * AHCI SATA platform library
+ *
+ * Copyright 2004-2005 Red Hat, Inc.
+ * Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2010 MontaVista Software, LLC.
+ * Anton Vorontsov <avorontsov@ru.mvista.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.
+ */
+
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/libata.h>
+#include <linux/ahci_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/pm_runtime.h>
+#include "ahci.h"
+
+static void ahci_host_stop(struct ata_host *host);
+
+struct ata_port_operations ahci_platform_ops = {
+ .inherits = &ahci_ops,
+ .host_stop = ahci_host_stop,
+};
+EXPORT_SYMBOL_GPL(ahci_platform_ops);
+
+static struct scsi_host_template ahci_platform_sht = {
+ AHCI_SHT("ahci_platform"),
+};
+
+/**
+ * ahci_platform_enable_clks - Enable platform clocks
+ * @hpriv: host private area to store config values
+ *
+ * This function enables all the clks found in hpriv->clks, starting at
+ * index 0. If any clk fails to enable it disables all the clks already
+ * enabled in reverse order, and then returns an error.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
+{
+ int c, rc;
+
+ for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
+ rc = clk_prepare_enable(hpriv->clks[c]);
+ if (rc)
+ goto disable_unprepare_clk;
+ }
+ return 0;
+
+disable_unprepare_clk:
+ while (--c >= 0)
+ clk_disable_unprepare(hpriv->clks[c]);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
+
+/**
+ * ahci_platform_disable_clks - Disable platform clocks
+ * @hpriv: host private area to store config values
+ *
+ * This function disables all the clks found in hpriv->clks, in reverse
+ * order of ahci_platform_enable_clks (starting at the end of the array).
+ */
+void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
+{
+ int c;
+
+ for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
+ if (hpriv->clks[c])
+ clk_disable_unprepare(hpriv->clks[c]);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
+
+/**
+ * ahci_platform_enable_resources - Enable platform resources
+ * @hpriv: host private area to store config values
+ *
+ * This function enables all ahci_platform managed resources in the
+ * following order:
+ * 1) Regulator
+ * 2) Clocks (through ahci_platform_enable_clks)
+ * 3) Phy
+ *
+ * If resource enabling fails at any point the previous enabled resources
+ * are disabled in reverse order.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
+{
+ int rc;
+
+ if (hpriv->target_pwr) {
+ rc = regulator_enable(hpriv->target_pwr);
+ if (rc)
+ return rc;
+ }
+
+ rc = ahci_platform_enable_clks(hpriv);
+ if (rc)
+ goto disable_regulator;
+
+ if (hpriv->phy) {
+ rc = phy_init(hpriv->phy);
+ if (rc)
+ goto disable_clks;
+
+ rc = phy_power_on(hpriv->phy);
+ if (rc) {
+ phy_exit(hpriv->phy);
+ goto disable_clks;
+ }
+ }
+
+ return 0;
+
+disable_clks:
+ ahci_platform_disable_clks(hpriv);
+
+disable_regulator:
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
+
+/**
+ * ahci_platform_disable_resources - Disable platform resources
+ * @hpriv: host private area to store config values
+ *
+ * This function disables all ahci_platform managed resources in the
+ * following order:
+ * 1) Phy
+ * 2) Clocks (through ahci_platform_disable_clks)
+ * 3) Regulator
+ */
+void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
+{
+ if (hpriv->phy) {
+ phy_power_off(hpriv->phy);
+ phy_exit(hpriv->phy);
+ }
+
+ ahci_platform_disable_clks(hpriv);
+
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
+
+static void ahci_platform_put_resources(struct device *dev, void *res)
+{
+ struct ahci_host_priv *hpriv = res;
+ int c;
+
+ if (hpriv->got_runtime_pm) {
+ pm_runtime_put_sync(dev);
+ pm_runtime_disable(dev);
+ }
+
+ for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
+ clk_put(hpriv->clks[c]);
+}
+
+/**
+ * ahci_platform_get_resources - Get platform resources
+ * @pdev: platform device to get resources for
+ *
+ * This function allocates an ahci_host_priv struct, and gets the following
+ * resources, storing a reference to them inside the returned struct:
+ *
+ * 1) mmio registers (IORESOURCE_MEM 0, mandatory)
+ * 2) regulator for controlling the targets power (optional)
+ * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
+ * or for non devicetree enabled platforms a single clock
+ * 4) phy (optional)
+ *
+ * RETURNS:
+ * The allocated ahci_host_priv on success, otherwise an ERR_PTR value
+ */
+struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ahci_host_priv *hpriv;
+ struct clk *clk;
+ int i, rc = -ENOMEM;
+
+ if (!devres_open_group(dev, NULL, GFP_KERNEL))
+ return ERR_PTR(-ENOMEM);
+
+ hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
+ GFP_KERNEL);
+ if (!hpriv)
+ goto err_out;
+
+ devres_add(dev, hpriv);
+
+ hpriv->mmio = devm_ioremap_resource(dev,
+ platform_get_resource(pdev, IORESOURCE_MEM, 0));
+ if (IS_ERR(hpriv->mmio)) {
+ dev_err(dev, "no mmio space\n");
+ rc = PTR_ERR(hpriv->mmio);
+ goto err_out;
+ }
+
+ hpriv->target_pwr = devm_regulator_get_optional(dev, "target");
+ if (IS_ERR(hpriv->target_pwr)) {
+ rc = PTR_ERR(hpriv->target_pwr);
+ if (rc == -EPROBE_DEFER)
+ goto err_out;
+ hpriv->target_pwr = NULL;
+ }
+
+ for (i = 0; i < AHCI_MAX_CLKS; i++) {
+ /*
+ * For now we must use clk_get(dev, NULL) for the first clock,
+ * because some platforms (da850, spear13xx) are not yet
+ * converted to use devicetree for clocks. For new platforms
+ * this is equivalent to of_clk_get(dev->of_node, 0).
+ */
+ if (i == 0)
+ clk = clk_get(dev, NULL);
+ else
+ clk = of_clk_get(dev->of_node, i);
+
+ if (IS_ERR(clk)) {
+ rc = PTR_ERR(clk);
+ if (rc == -EPROBE_DEFER)
+ goto err_out;
+ break;
+ }
+ hpriv->clks[i] = clk;
+ }
+
+ hpriv->phy = devm_phy_get(dev, "sata-phy");
+ if (IS_ERR(hpriv->phy)) {
+ rc = PTR_ERR(hpriv->phy);
+ switch (rc) {
+ case -ENODEV:
+ case -ENOSYS:
+ /* continue normally */
+ hpriv->phy = NULL;
+ break;
+
+ case -EPROBE_DEFER:
+ goto err_out;
+
+ default:
+ dev_err(dev, "couldn't get sata-phy\n");
+ goto err_out;
+ }
+ }
+
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+ hpriv->got_runtime_pm = true;
+
+ devres_remove_group(dev, NULL);
+ return hpriv;
+
+err_out:
+ devres_release_group(dev, NULL);
+ return ERR_PTR(rc);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
+
+/**
+ * ahci_platform_init_host - Bring up an ahci-platform host
+ * @pdev: platform device pointer for the host
+ * @hpriv: ahci-host private data for the host
+ * @pi_template: template for the ata_port_info to use
+ * @force_port_map: param passed to ahci_save_initial_config
+ * @mask_port_map: param passed to ahci_save_initial_config
+ *
+ * This function does all the usual steps needed to bring up an
+ * ahci-platform host, note any necessary resources (ie clks, phy, etc.)
+ * must be initialized / enabled before calling this.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_init_host(struct platform_device *pdev,
+ struct ahci_host_priv *hpriv,
+ const struct ata_port_info *pi_template,
+ unsigned int force_port_map,
+ unsigned int mask_port_map)
+{
+ struct device *dev = &pdev->dev;
+ struct ata_port_info pi = *pi_template;
+ const struct ata_port_info *ppi[] = { &pi, NULL };
+ struct ata_host *host;
+ int i, irq, n_ports, rc;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(dev, "no irq\n");
+ return -EINVAL;
+ }
+
+ /* prepare host */
+ hpriv->flags |= (unsigned long)pi.private_data;
+
+ ahci_save_initial_config(dev, hpriv, force_port_map, mask_port_map);
+
+ if (hpriv->cap & HOST_CAP_NCQ)
+ pi.flags |= ATA_FLAG_NCQ;
+
+ if (hpriv->cap & HOST_CAP_PMP)
+ pi.flags |= ATA_FLAG_PMP;
+
+ ahci_set_em_messages(hpriv, &pi);
+
+ /* CAP.NP sometimes indicate the index of the last enabled
+ * port, at other times, that of the last possible port, so
+ * determining the maximum port number requires looking at
+ * both CAP.NP and port_map.
+ */
+ n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
+
+ host = ata_host_alloc_pinfo(dev, ppi, n_ports);
+ if (!host)
+ return -ENOMEM;
+
+ host->private_data = hpriv;
+
+ if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
+ host->flags |= ATA_HOST_PARALLEL_SCAN;
+ else
+ dev_info(dev, "SSS flag set, parallel bus scan disabled\n");
+
+ if (pi.flags & ATA_FLAG_EM)
+ ahci_reset_em(host);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ ata_port_desc(ap, "mmio %pR",
+ platform_get_resource(pdev, IORESOURCE_MEM, 0));
+ ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
+
+ /* set enclosure management message type */
+ if (ap->flags & ATA_FLAG_EM)
+ ap->em_message_type = hpriv->em_msg_type;
+
+ /* disabled/not-implemented port */
+ if (!(hpriv->port_map & (1 << i)))
+ ap->ops = &ata_dummy_port_ops;
+ }
+
+ rc = ahci_reset_controller(host);
+ if (rc)
+ return rc;
+
+ ahci_init_controller(host);
+ ahci_print_info(host, "platform");
+
+ return ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
+ &ahci_platform_sht);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_init_host);
+
+static void ahci_host_stop(struct ata_host *host)
+{
+ struct device *dev = host->dev;
+ struct ahci_platform_data *pdata = dev_get_platdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+
+ if (pdata && pdata->exit)
+ pdata->exit(dev);
+
+ ahci_platform_disable_resources(hpriv);
+}
+
+#ifdef CONFIG_PM_SLEEP
+/**
+ * ahci_platform_suspend_host - Suspend an ahci-platform host
+ * @dev: device pointer for the host
+ *
+ * This function does all the usual steps needed to suspend an
+ * ahci-platform host, note any necessary resources (ie clks, phy, etc.)
+ * must be disabled after calling this.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_suspend_host(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+ u32 ctl;
+
+ if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
+ dev_err(dev, "firmware update required for suspend/resume\n");
+ return -EIO;
+ }
+
+ /*
+ * AHCI spec rev1.1 section 8.3.3:
+ * Software must disable interrupts prior to requesting a
+ * transition of the HBA to D3 state.
+ */
+ ctl = readl(mmio + HOST_CTL);
+ ctl &= ~HOST_IRQ_EN;
+ writel(ctl, mmio + HOST_CTL);
+ readl(mmio + HOST_CTL); /* flush */
+
+ return ata_host_suspend(host, PMSG_SUSPEND);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_suspend_host);
+
+/**
+ * ahci_platform_resume_host - Resume an ahci-platform host
+ * @dev: device pointer for the host
+ *
+ * This function does all the usual steps needed to resume an ahci-platform
+ * host, note any necessary resources (ie clks, phy, etc.) must be
+ * initialized / enabled before calling this.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_resume_host(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ int rc;
+
+ if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
+ rc = ahci_reset_controller(host);
+ if (rc)
+ return rc;
+
+ ahci_init_controller(host);
+ }
+
+ ata_host_resume(host);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_resume_host);
+
+/**
+ * ahci_platform_suspend - Suspend an ahci-platform device
+ * @dev: the platform device to suspend
+ *
+ * This function suspends the host associated with the device, followed by
+ * disabling all the resources of the device.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_suspend(struct device *dev)
+{
+ struct ahci_platform_data *pdata = dev_get_platdata(dev);
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ int rc;
+
+ rc = ahci_platform_suspend_host(dev);
+ if (rc)
+ return rc;
+
+ if (pdata && pdata->suspend) {
+ rc = pdata->suspend(dev);
+ if (rc)
+ goto resume_host;
+ }
+
+ ahci_platform_disable_resources(hpriv);
+
+ return 0;
+
+resume_host:
+ ahci_platform_resume_host(dev);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_suspend);
+
+/**
+ * ahci_platform_resume - Resume an ahci-platform device
+ * @dev: the platform device to resume
+ *
+ * This function enables all the resources of the device followed by
+ * resuming the host associated with the device.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_resume(struct device *dev)
+{
+ struct ahci_platform_data *pdata = dev_get_platdata(dev);
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ int rc;
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ return rc;
+
+ if (pdata && pdata->resume) {
+ rc = pdata->resume(dev);
+ if (rc)
+ goto disable_resources;
+ }
+
+ rc = ahci_platform_resume_host(dev);
+ if (rc)
+ goto disable_resources;
+
+ /* We resumed so update PM runtime state */
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ return 0;
+
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_resume);
+#endif
+
+MODULE_DESCRIPTION("AHCI SATA platform library");
+MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 9e69a5308693..97a14fe47de1 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -38,6 +38,16 @@ static void ata_acpi_clear_gtf(struct ata_device *dev)
dev->gtf_cache = NULL;
}
+struct ata_acpi_hotplug_context {
+ struct acpi_hotplug_context hp;
+ union {
+ struct ata_port *ap;
+ struct ata_device *dev;
+ } data;
+};
+
+#define ata_hotplug_data(context) (container_of((context), struct ata_acpi_hotplug_context, hp)->data)
+
/**
* ata_dev_acpi_handle - provide the acpi_handle for an ata_device
* @dev: the acpi_handle returned will correspond to this device
@@ -121,18 +131,17 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
ata_port_wait_eh(ap);
}
-static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
+static int ata_acpi_dev_notify_dock(struct acpi_device *adev, u32 event)
{
- struct ata_device *dev = data;
-
+ struct ata_device *dev = ata_hotplug_data(adev->hp).dev;
ata_acpi_handle_hotplug(dev->link->ap, dev, event);
+ return 0;
}
-static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
+static int ata_acpi_ap_notify_dock(struct acpi_device *adev, u32 event)
{
- struct ata_port *ap = data;
-
- ata_acpi_handle_hotplug(ap, NULL, event);
+ ata_acpi_handle_hotplug(ata_hotplug_data(adev->hp).ap, NULL, event);
+ return 0;
}
static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
@@ -154,31 +163,23 @@ static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
}
}
-static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data)
+static void ata_acpi_ap_uevent(struct acpi_device *adev, u32 event)
{
- ata_acpi_uevent(data, NULL, event);
+ ata_acpi_uevent(ata_hotplug_data(adev->hp).ap, NULL, event);
}
-static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data)
+static void ata_acpi_dev_uevent(struct acpi_device *adev, u32 event)
{
- struct ata_device *dev = data;
+ struct ata_device *dev = ata_hotplug_data(adev->hp).dev;
ata_acpi_uevent(dev->link->ap, dev, event);
}
-static const struct acpi_dock_ops ata_acpi_dev_dock_ops = {
- .handler = ata_acpi_dev_notify_dock,
- .uevent = ata_acpi_dev_uevent,
-};
-
-static const struct acpi_dock_ops ata_acpi_ap_dock_ops = {
- .handler = ata_acpi_ap_notify_dock,
- .uevent = ata_acpi_ap_uevent,
-};
-
/* bind acpi handle to pata port */
void ata_acpi_bind_port(struct ata_port *ap)
{
struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
+ struct acpi_device *adev;
+ struct ata_acpi_hotplug_context *context;
if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion)
return;
@@ -188,9 +189,17 @@ void ata_acpi_bind_port(struct ata_port *ap)
if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0)
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
- /* we might be on a docking station */
- register_hotplug_dock_device(ACPI_HANDLE(&ap->tdev),
- &ata_acpi_ap_dock_ops, ap, NULL, NULL);
+ adev = ACPI_COMPANION(&ap->tdev);
+ if (!adev || adev->hp)
+ return;
+
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return;
+
+ context->data.ap = ap;
+ acpi_initialize_hp_context(adev, &context->hp, ata_acpi_ap_notify_dock,
+ ata_acpi_ap_uevent);
}
void ata_acpi_bind_dev(struct ata_device *dev)
@@ -198,7 +207,8 @@ void ata_acpi_bind_dev(struct ata_device *dev)
struct ata_port *ap = dev->link->ap;
struct acpi_device *port_companion = ACPI_COMPANION(&ap->tdev);
struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
- struct acpi_device *parent;
+ struct acpi_device *parent, *adev;
+ struct ata_acpi_hotplug_context *context;
u64 adr;
/*
@@ -221,9 +231,17 @@ void ata_acpi_bind_dev(struct ata_device *dev)
}
acpi_preset_companion(&dev->tdev, parent, adr);
+ adev = ACPI_COMPANION(&dev->tdev);
+ if (!adev || adev->hp)
+ return;
+
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return;
- register_hotplug_dock_device(ata_dev_acpi_handle(dev),
- &ata_acpi_dev_dock_ops, dev, NULL, NULL);
+ context->data.dev = dev;
+ acpi_initialize_hp_context(adev, &context->hp, ata_acpi_dev_notify_dock,
+ ata_acpi_dev_uevent);
}
/**
@@ -835,6 +853,7 @@ void ata_acpi_on_resume(struct ata_port *ap)
ata_for_each_dev(dev, &ap->link, ALL) {
ata_acpi_clear_gtf(dev);
if (ata_dev_enabled(dev) &&
+ ata_dev_acpi_handle(dev) &&
ata_dev_get_GTF(dev, NULL) >= 0)
dev->flags |= ATA_DFLAG_ACPI_PENDING;
}
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 1a3dbd1b196e..c19734d96d7e 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1524,7 +1524,7 @@ static void ata_qc_complete_internal(struct ata_queued_cmd *qc)
* @dev: Device to which the command is sent
* @tf: Taskfile registers for the command and the result
* @cdb: CDB for packet command
- * @dma_dir: Data tranfer direction of the command
+ * @dma_dir: Data transfer direction of the command
* @sgl: sg list for the data buffer of the command
* @n_elem: Number of sg entries
* @timeout: Timeout in msecs (0 for default)
@@ -1712,7 +1712,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
* @dev: Device to which the command is sent
* @tf: Taskfile registers for the command and the result
* @cdb: CDB for packet command
- * @dma_dir: Data tranfer direction of the command
+ * @dma_dir: Data transfer direction of the command
* @buf: Data buffer of the command
* @buflen: Length of data buffer
* @timeout: Timeout in msecs (0 for default)
@@ -4175,6 +4175,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* Seagate Momentus SpinPoint M8 seem to have FPMDA_AA issues */
{ "ST1000LM024 HN-M101MBB", "2AR10001", ATA_HORKAGE_BROKEN_FPDMA_AA },
+ { "ST1000LM024 HN-M101MBB", "2BA30001", ATA_HORKAGE_BROKEN_FPDMA_AA },
/* Blacklist entries taken from Silicon Image 3124/3132
Windows driver .inf file - also several Linux problem reports */
@@ -4224,7 +4225,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* devices that don't properly handle queued TRIM commands */
{ "Micron_M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, },
- { "Crucial_CT???M500SSD1", NULL, ATA_HORKAGE_NO_NCQ_TRIM, },
+ { "Crucial_CT???M500SSD*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, },
/*
* Some WD SATA-I drives spin up and down erratically when the link
@@ -5351,22 +5352,17 @@ bool ata_link_offline(struct ata_link *link)
}
#ifdef CONFIG_PM
-static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
- unsigned int action, unsigned int ehi_flags,
- int *async)
+static void ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
+ unsigned int action, unsigned int ehi_flags,
+ bool async)
{
struct ata_link *link;
unsigned long flags;
- int rc = 0;
/* Previous resume operation might still be in
* progress. Wait for PM_PENDING to clear.
*/
if (ap->pflags & ATA_PFLAG_PM_PENDING) {
- if (async) {
- *async = -EAGAIN;
- return 0;
- }
ata_port_wait_eh(ap);
WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
}
@@ -5375,11 +5371,6 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
spin_lock_irqsave(ap->lock, flags);
ap->pm_mesg = mesg;
- if (async)
- ap->pm_result = async;
- else
- ap->pm_result = &rc;
-
ap->pflags |= ATA_PFLAG_PM_PENDING;
ata_for_each_link(link, ap, HOST_FIRST) {
link->eh_info.action |= action;
@@ -5390,87 +5381,81 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
spin_unlock_irqrestore(ap->lock, flags);
- /* wait and check result */
if (!async) {
ata_port_wait_eh(ap);
WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
}
-
- return rc;
}
-static int __ata_port_suspend_common(struct ata_port *ap, pm_message_t mesg, int *async)
+/*
+ * On some hardware, device fails to respond after spun down for suspend. As
+ * the device won't be used before being resumed, we don't need to touch the
+ * device. Ask EH to skip the usual stuff and proceed directly to suspend.
+ *
+ * http://thread.gmane.org/gmane.linux.ide/46764
+ */
+static const unsigned int ata_port_suspend_ehi = ATA_EHI_QUIET
+ | ATA_EHI_NO_AUTOPSY
+ | ATA_EHI_NO_RECOVERY;
+
+static void ata_port_suspend(struct ata_port *ap, pm_message_t mesg)
{
- /*
- * On some hardware, device fails to respond after spun down
- * for suspend. As the device won't be used before being
- * resumed, we don't need to touch the device. Ask EH to skip
- * the usual stuff and proceed directly to suspend.
- *
- * http://thread.gmane.org/gmane.linux.ide/46764
- */
- unsigned int ehi_flags = ATA_EHI_QUIET | ATA_EHI_NO_AUTOPSY |
- ATA_EHI_NO_RECOVERY;
- return ata_port_request_pm(ap, mesg, 0, ehi_flags, async);
+ ata_port_request_pm(ap, mesg, 0, ata_port_suspend_ehi, false);
}
-static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
+static void ata_port_suspend_async(struct ata_port *ap, pm_message_t mesg)
{
- struct ata_port *ap = to_ata_port(dev);
-
- return __ata_port_suspend_common(ap, mesg, NULL);
+ ata_port_request_pm(ap, mesg, 0, ata_port_suspend_ehi, true);
}
-static int ata_port_suspend(struct device *dev)
+static int ata_port_pm_suspend(struct device *dev)
{
+ struct ata_port *ap = to_ata_port(dev);
+
if (pm_runtime_suspended(dev))
return 0;
- return ata_port_suspend_common(dev, PMSG_SUSPEND);
+ ata_port_suspend(ap, PMSG_SUSPEND);
+ return 0;
}
-static int ata_port_do_freeze(struct device *dev)
+static int ata_port_pm_freeze(struct device *dev)
{
+ struct ata_port *ap = to_ata_port(dev);
+
if (pm_runtime_suspended(dev))
return 0;
- return ata_port_suspend_common(dev, PMSG_FREEZE);
+ ata_port_suspend(ap, PMSG_FREEZE);
+ return 0;
}
-static int ata_port_poweroff(struct device *dev)
+static int ata_port_pm_poweroff(struct device *dev)
{
- return ata_port_suspend_common(dev, PMSG_HIBERNATE);
+ ata_port_suspend(to_ata_port(dev), PMSG_HIBERNATE);
+ return 0;
}
-static int __ata_port_resume_common(struct ata_port *ap, pm_message_t mesg,
- int *async)
-{
- int rc;
+static const unsigned int ata_port_resume_ehi = ATA_EHI_NO_AUTOPSY
+ | ATA_EHI_QUIET;
- rc = ata_port_request_pm(ap, mesg, ATA_EH_RESET,
- ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, async);
- return rc;
+static void ata_port_resume(struct ata_port *ap, pm_message_t mesg)
+{
+ ata_port_request_pm(ap, mesg, ATA_EH_RESET, ata_port_resume_ehi, false);
}
-static int ata_port_resume_common(struct device *dev, pm_message_t mesg)
+static void ata_port_resume_async(struct ata_port *ap, pm_message_t mesg)
{
- struct ata_port *ap = to_ata_port(dev);
-
- return __ata_port_resume_common(ap, mesg, NULL);
+ ata_port_request_pm(ap, mesg, ATA_EH_RESET, ata_port_resume_ehi, true);
}
-static int ata_port_resume(struct device *dev)
+static int ata_port_pm_resume(struct device *dev)
{
- int rc;
-
- rc = ata_port_resume_common(dev, PMSG_RESUME);
- if (!rc) {
- pm_runtime_disable(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
- }
-
- return rc;
+ ata_port_resume_async(to_ata_port(dev), PMSG_RESUME);
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ return 0;
}
/*
@@ -5499,21 +5484,23 @@ static int ata_port_runtime_idle(struct device *dev)
static int ata_port_runtime_suspend(struct device *dev)
{
- return ata_port_suspend_common(dev, PMSG_AUTO_SUSPEND);
+ ata_port_suspend(to_ata_port(dev), PMSG_AUTO_SUSPEND);
+ return 0;
}
static int ata_port_runtime_resume(struct device *dev)
{
- return ata_port_resume_common(dev, PMSG_AUTO_RESUME);
+ ata_port_resume(to_ata_port(dev), PMSG_AUTO_RESUME);
+ return 0;
}
static const struct dev_pm_ops ata_port_pm_ops = {
- .suspend = ata_port_suspend,
- .resume = ata_port_resume,
- .freeze = ata_port_do_freeze,
- .thaw = ata_port_resume,
- .poweroff = ata_port_poweroff,
- .restore = ata_port_resume,
+ .suspend = ata_port_pm_suspend,
+ .resume = ata_port_pm_resume,
+ .freeze = ata_port_pm_freeze,
+ .thaw = ata_port_pm_resume,
+ .poweroff = ata_port_pm_poweroff,
+ .restore = ata_port_pm_resume,
.runtime_suspend = ata_port_runtime_suspend,
.runtime_resume = ata_port_runtime_resume,
@@ -5525,18 +5512,17 @@ static const struct dev_pm_ops ata_port_pm_ops = {
* level. sas suspend/resume is async to allow parallel port recovery
* since sas has multiple ata_port instances per Scsi_Host.
*/
-int ata_sas_port_async_suspend(struct ata_port *ap, int *async)
+void ata_sas_port_suspend(struct ata_port *ap)
{
- return __ata_port_suspend_common(ap, PMSG_SUSPEND, async);
+ ata_port_suspend_async(ap, PMSG_SUSPEND);
}
-EXPORT_SYMBOL_GPL(ata_sas_port_async_suspend);
+EXPORT_SYMBOL_GPL(ata_sas_port_suspend);
-int ata_sas_port_async_resume(struct ata_port *ap, int *async)
+void ata_sas_port_resume(struct ata_port *ap)
{
- return __ata_port_resume_common(ap, PMSG_RESUME, async);
+ ata_port_resume_async(ap, PMSG_RESUME);
}
-EXPORT_SYMBOL_GPL(ata_sas_port_async_resume);
-
+EXPORT_SYMBOL_GPL(ata_sas_port_resume);
/**
* ata_host_suspend - suspend host
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 6d8757008318..6760fc4e85b8 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -95,12 +95,13 @@ enum {
* represents timeout for that try. The first try can be soft or
* hardreset. All others are hardreset if available. In most cases
* the first reset w/ 10sec timeout should succeed. Following entries
- * are mostly for error handling, hotplug and retarded devices.
+ * are mostly for error handling, hotplug and those outlier devices that
+ * take an exceptionally long time to recover from reset.
*/
static const unsigned long ata_eh_reset_timeouts[] = {
10000, /* most drives spin up by 10sec */
10000, /* > 99% working drives spin up before 20sec */
- 35000, /* give > 30 secs of idleness for retarded devices */
+ 35000, /* give > 30 secs of idleness for outlier devices */
5000, /* and sweet one last chance */
ULONG_MAX, /* > 1 min has elapsed, give up */
};
@@ -4069,7 +4070,7 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
ata_acpi_set_state(ap, ap->pm_mesg);
out:
- /* report result */
+ /* update the flags */
spin_lock_irqsave(ap->lock, flags);
ap->pflags &= ~ATA_PFLAG_PM_PENDING;
@@ -4078,11 +4079,6 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
else if (ap->pflags & ATA_PFLAG_FROZEN)
ata_port_schedule_eh(ap);
- if (ap->pm_result) {
- *ap->pm_result = rc;
- ap->pm_result = NULL;
- }
-
spin_unlock_irqrestore(ap->lock, flags);
return;
@@ -4134,13 +4130,9 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
/* tell ACPI that we're resuming */
ata_acpi_on_resume(ap);
- /* report result */
+ /* update the flags */
spin_lock_irqsave(ap->lock, flags);
ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED);
- if (ap->pm_result) {
- *ap->pm_result = rc;
- ap->pm_result = NULL;
- }
spin_unlock_irqrestore(ap->lock, flags);
}
#endif /* CONFIG_PM */
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
index 20fd337a5731..7ccc084bf1df 100644
--- a/drivers/ata/libata-pmp.c
+++ b/drivers/ata/libata-pmp.c
@@ -447,8 +447,11 @@ static void sata_pmp_quirks(struct ata_port *ap)
* otherwise. Don't try hard to recover it.
*/
ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY;
- } else if (vendor == 0x197b && devid == 0x2352) {
- /* chip found in Thermaltake BlackX Duet, jmicron JMB350? */
+ } else if (vendor == 0x197b && (devid == 0x2352 || devid == 0x0325)) {
+ /*
+ * 0x2352: found in Thermaltake BlackX Duet, jmicron JMB350?
+ * 0x0325: jmicron JMB394.
+ */
ata_for_each_link(link, ap, EDGE) {
/* SRST breaks detection and disks get misclassified
* LPM disabled to avoid potential problems
diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c
index 88949c6d55dd..f3a65a3140d3 100644
--- a/drivers/ata/libata-zpodd.c
+++ b/drivers/ata/libata-zpodd.c
@@ -85,21 +85,6 @@ static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev)
return ODD_MECH_TYPE_UNSUPPORTED;
}
-static bool odd_can_poweroff(struct ata_device *ata_dev)
-{
- acpi_handle handle;
- struct acpi_device *acpi_dev;
-
- handle = ata_dev_acpi_handle(ata_dev);
- if (!handle)
- return false;
-
- if (acpi_bus_get_device(handle, &acpi_dev))
- return false;
-
- return acpi_device_can_poweroff(acpi_dev);
-}
-
/* Test if ODD is zero power ready by sense code */
static bool zpready(struct ata_device *dev)
{
@@ -267,13 +252,11 @@ static void ata_acpi_remove_pm_notifier(struct ata_device *dev)
void zpodd_init(struct ata_device *dev)
{
+ struct acpi_device *adev = ACPI_COMPANION(&dev->tdev);
enum odd_mech_type mech_type;
struct zpodd *zpodd;
- if (dev->zpodd)
- return;
-
- if (!odd_can_poweroff(dev))
+ if (dev->zpodd || !adev || !acpi_device_can_poweroff(adev))
return;
mech_type = zpodd_get_mech_type(dev);
diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c
index 62c9ac80c6e9..5108b8744dce 100644
--- a/drivers/ata/pata_acpi.c
+++ b/drivers/ata/pata_acpi.c
@@ -7,7 +7,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index d23e2b3ca0b6..1206fa6b62ca 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -17,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c
index 73492dd4a4bc..6fac524c2f50 100644
--- a/drivers/ata/pata_arasan_cf.c
+++ b/drivers/ata/pata_arasan_cf.c
@@ -356,7 +356,7 @@ static void cf_exit(struct arasan_cf_dev *acdev)
static void dma_callback(void *dev)
{
- struct arasan_cf_dev *acdev = (struct arasan_cf_dev *) dev;
+ struct arasan_cf_dev *acdev = dev;
complete(&acdev->dma_completion);
}
diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c
index 1581dee2967a..3aa4e655e3c6 100644
--- a/drivers/ata/pata_artop.c
+++ b/drivers/ata/pata_artop.c
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c
index d63ee8f41a4f..e9c87274a781 100644
--- a/drivers/ata/pata_at91.c
+++ b/drivers/ata/pata_at91.c
@@ -18,7 +18,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/gfp.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 24e51056ac26..30fa4ca4cef6 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_atp867x.c b/drivers/ata/pata_atp867x.c
index 2ca5026f2c15..7e73a0f1e323 100644
--- a/drivers/ata/pata_atp867x.c
+++ b/drivers/ata/pata_atp867x.c
@@ -29,7 +29,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c
index 8fb69e5ca1b7..57f1be64dbf2 100644
--- a/drivers/ata/pata_cmd640.c
+++ b/drivers/ata/pata_cmd640.c
@@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/gfp.h>
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index 1275a8d4dedc..6bca3505b9e9 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -26,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index f10baabbf5db..bcde4b786807 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -34,7 +34,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index f07f2296acdc..8afe854a5a50 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -26,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
index 997e16a3a63f..2c0986fa4bb2 100644
--- a/drivers/ata/pata_cs5535.c
+++ b/drivers/ata/pata_cs5535.c
@@ -31,7 +31,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c
index 0448860a2077..32ddcae5a360 100644
--- a/drivers/ata/pata_cs5536.c
+++ b/drivers/ata/pata_cs5536.c
@@ -33,7 +33,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/libata.h>
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
index 810bc9964dde..3435bd6a5cc9 100644
--- a/drivers/ata/pata_cypress.c
+++ b/drivers/ata/pata_cypress.c
@@ -11,7 +11,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
index 3c12fd7acd41..f440892225f4 100644
--- a/drivers/ata/pata_efar.c
+++ b/drivers/ata/pata_efar.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c
index 980b88e109fc..cad9d45749c4 100644
--- a/drivers/ata/pata_ep93xx.c
+++ b/drivers/ata/pata_ep93xx.c
@@ -34,7 +34,6 @@
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <scsi/scsi_host.h>
#include <linux/ata.h>
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index 35b521348d31..8e76f79689d3 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
index a9d74eff5fc4..3ba843f5cdc0 100644
--- a/drivers/ata/pata_hpt37x.c
+++ b/drivers/ata/pata_hpt37x.c
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
index 4be0398c153d..b93c0f0729e7 100644
--- a/drivers/ata/pata_hpt3x2n.c
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -20,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
index 85cf2861e0b7..255c5aaff3a8 100644
--- a/drivers/ata/pata_hpt3x3.c
+++ b/drivers/ata/pata_hpt3x3.c
@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c
index 26386f0b89a8..e0872db913d6 100644
--- a/drivers/ata/pata_imx.c
+++ b/drivers/ata/pata_imx.c
@@ -15,7 +15,6 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <scsi/scsi_host.h>
#include <linux/ata.h>
@@ -100,13 +99,9 @@ static int pata_imx_probe(struct platform_device *pdev)
struct resource *io_res;
int ret;
- io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (io_res == NULL)
- return -EINVAL;
-
irq = platform_get_irq(pdev, 0);
- if (irq <= 0)
- return -EINVAL;
+ if (irq < 0)
+ return irq;
priv = devm_kzalloc(&pdev->dev,
sizeof(struct pata_imx_priv), GFP_KERNEL);
@@ -119,7 +114,9 @@ static int pata_imx_probe(struct platform_device *pdev)
return PTR_ERR(priv->clk);
}
- clk_prepare_enable(priv->clk);
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
host = ata_host_alloc(&pdev->dev, 1);
if (!host) {
@@ -134,11 +131,10 @@ static int pata_imx_probe(struct platform_device *pdev)
ap->pio_mask = ATA_PIO0;
ap->flags |= ATA_FLAG_SLAVE_POSS;
- priv->host_regs = devm_ioremap(&pdev->dev, io_res->start,
- resource_size(io_res));
- if (!priv->host_regs) {
- dev_err(&pdev->dev, "failed to map IO/CTL base\n");
- ret = -EBUSY;
+ io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->host_regs = devm_ioremap_resource(&pdev->dev, io_res);
+ if (IS_ERR(priv->host_regs)) {
+ ret = PTR_ERR(priv->host_regs);
goto err;
}
@@ -212,7 +208,9 @@ static int pata_imx_resume(struct device *dev)
struct ata_host *host = dev_get_drvdata(dev);
struct pata_imx_priv *priv = host->private_data;
- clk_prepare_enable(priv->clk);
+ int ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
__raw_writel(priv->ata_ctl, priv->host_regs + PATA_IMX_ATA_CONTROL);
diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c
index 2a8dd9527ecc..81369d187a5c 100644
--- a/drivers/ata/pata_it8213.c
+++ b/drivers/ata/pata_it8213.c
@@ -10,7 +10,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index 581e04d80367..dc3d7877f29d 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -72,7 +72,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/slab.h>
diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c
index 76e739b031b6..b1cfa0258fd3 100644
--- a/drivers/ata/pata_jmicron.c
+++ b/drivers/ata/pata_jmicron.c
@@ -10,7 +10,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index be816428b430..bce2a8ca4678 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -916,7 +916,6 @@ static __init int probe_chip_type(struct legacy_probe *probe)
local_irq_restore(flags);
return BIOS;
}
- local_irq_restore(flags);
}
if (ht6560a & mask)
diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c
index a4f5e781c8c2..6bad3df3a13c 100644
--- a/drivers/ata/pata_marvell.c
+++ b/drivers/ata/pata_marvell.c
@@ -11,7 +11,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c
index 1f5f28bb0bb8..f39a5379e816 100644
--- a/drivers/ata/pata_mpiix.c
+++ b/drivers/ata/pata_mpiix.c
@@ -28,7 +28,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c
index ad1a0febd620..e3b97093ef9a 100644
--- a/drivers/ata/pata_netcell.c
+++ b/drivers/ata/pata_netcell.c
@@ -7,7 +7,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_ninja32.c b/drivers/ata/pata_ninja32.c
index 9513e071040d..56201a69af12 100644
--- a/drivers/ata/pata_ninja32.c
+++ b/drivers/ata/pata_ninja32.c
@@ -37,7 +37,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
index 0c424dae56e7..6154c3ee11a5 100644
--- a/drivers/ata/pata_ns87410.c
+++ b/drivers/ata/pata_ns87410.c
@@ -20,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c
index 16dc3a63a23d..d44df7ccfe43 100644
--- a/drivers/ata/pata_ns87415.c
+++ b/drivers/ata/pata_ns87415.c
@@ -25,7 +25,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c
index d77b2e1054ef..319b64491b7b 100644
--- a/drivers/ata/pata_oldpiix.c
+++ b/drivers/ata/pata_oldpiix.c
@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c
index 4ea70cd22aee..fb042e0519d0 100644
--- a/drivers/ata/pata_opti.c
+++ b/drivers/ata/pata_opti.c
@@ -26,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c
index 78ede3fd1875..bb71ea214b99 100644
--- a/drivers/ata/pata_optidma.c
+++ b/drivers/ata/pata_optidma.c
@@ -25,7 +25,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 40254f4df584..bcc4b968c049 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -26,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/slab.h>
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index 9d874c85d64d..1151f23177bb 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -25,7 +25,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
index c34fc50070a6..defa050e1784 100644
--- a/drivers/ata/pata_pdc202xx_old.c
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_piccolo.c b/drivers/ata/pata_piccolo.c
index 2beb6b5045f8..0b46be117051 100644
--- a/drivers/ata/pata_piccolo.c
+++ b/drivers/ata/pata_piccolo.c
@@ -18,7 +18,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 02794885de10..a5579b55e332 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -13,7 +13,6 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <scsi/scsi_host.h>
#include <linux/ata.h>
diff --git a/drivers/ata/pata_pxa.c b/drivers/ata/pata_pxa.c
index a6f05acad61e..73259bfda1e3 100644
--- a/drivers/ata/pata_pxa.c
+++ b/drivers/ata/pata_pxa.c
@@ -20,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/ata.h>
#include <linux/libata.h>
diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c
index f582ba180a7d..be3f10240dca 100644
--- a/drivers/ata/pata_radisys.c
+++ b/drivers/ata/pata_radisys.c
@@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_rdc.c b/drivers/ata/pata_rdc.c
index 79a970f05a2e..521b2137ea3e 100644
--- a/drivers/ata/pata_rdc.c
+++ b/drivers/ata/pata_rdc.c
@@ -24,7 +24,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
index 040b093617a4..caedc90855b2 100644
--- a/drivers/ata/pata_rz1000.c
+++ b/drivers/ata/pata_rz1000.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
index ce2f828c17b3..96a232fffae6 100644
--- a/drivers/ata/pata_sc1200.c
+++ b/drivers/ata/pata_sc1200.c
@@ -32,7 +32,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index f35f15f4d83e..f1f5b5ae3382 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -35,7 +35,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_sch.c b/drivers/ata/pata_sch.c
index d3830c45a369..5a1cde0ea360 100644
--- a/drivers/ata/pata_sch.c
+++ b/drivers/ata/pata_sch.c
@@ -27,7 +27,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index 96c6a79ef606..e27f31fe1b67 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -34,7 +34,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index c4b0b073ba8e..73fe362d9716 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -25,7 +25,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index 1e8363640bf5..78d913aa93c8 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -26,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index 6816911ac422..900f0e4a1faf 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
index 94473da68c02..7bc78e264f9e 100644
--- a/drivers/ata/pata_triflex.c
+++ b/drivers/ata/pata_triflex.c
@@ -36,7 +36,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index c3ab9a6c3965..f6c9632bdff6 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -55,7 +55,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/gfp.h>
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
index 8ea6e6afd041..f10631beffa8 100644
--- a/drivers/ata/pdc_adma.c
+++ b/drivers/ata/pdc_adma.c
@@ -36,7 +36,6 @@
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c
index 523524b68022..0bb2cabd2197 100644
--- a/drivers/ata/sata_dwc_460ex.c
+++ b/drivers/ata/sata_dwc_460ex.c
@@ -29,7 +29,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/device.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -462,8 +461,7 @@ static irqreturn_t dma_dwc_interrupt(int irq, void *hsdev_instance)
int chan;
u32 tfr_reg, err_reg;
unsigned long flags;
- struct sata_dwc_device *hsdev =
- (struct sata_dwc_device *)hsdev_instance;
+ struct sata_dwc_device *hsdev = hsdev_instance;
struct ata_host *host = (struct ata_host *)hsdev->host;
struct ata_port *ap;
struct sata_dwc_device_port *hsdevp;
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
index 870b11eadc6d..65965cf5af06 100644
--- a/drivers/ata/sata_highbank.c
+++ b/drivers/ata/sata_highbank.c
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/gfp.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/types.h>
#include <linux/err.h>
#include <linux/io.h>
@@ -142,7 +141,7 @@ static ssize_t ecx_transmit_led_message(struct ata_port *ap, u32 state,
ssize_t size)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
- struct ecx_plat_data *pdata = (struct ecx_plat_data *) hpriv->plat_data;
+ struct ecx_plat_data *pdata = hpriv->plat_data;
struct ahci_port_priv *pp = ap->private_data;
unsigned long flags;
int pmp, i;
@@ -403,6 +402,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
static const unsigned long timing[] = { 5, 100, 500};
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
bool online;
@@ -431,7 +431,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
break;
} while (!online && retry--);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
if (online)
*class = ahci_dev_classify(ap);
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 20a7517bd339..05c8a44adf8e 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -4104,7 +4104,6 @@ static int mv_platform_probe(struct platform_device *pdev)
if (!hpriv->port_phys)
return -ENOMEM;
host->private_data = hpriv;
- hpriv->n_ports = n_ports;
hpriv->board_idx = chip_soc;
host->iomap = NULL;
@@ -4126,17 +4125,24 @@ static int mv_platform_probe(struct platform_device *pdev)
clk_prepare_enable(hpriv->port_clks[port]);
sprintf(port_number, "port%d", port);
- hpriv->port_phys[port] = devm_phy_get(&pdev->dev, port_number);
+ hpriv->port_phys[port] = devm_phy_optional_get(&pdev->dev,
+ port_number);
if (IS_ERR(hpriv->port_phys[port])) {
rc = PTR_ERR(hpriv->port_phys[port]);
hpriv->port_phys[port] = NULL;
- if ((rc != -EPROBE_DEFER) && (rc != -ENODEV))
- dev_warn(&pdev->dev, "error getting phy");
+ if (rc != -EPROBE_DEFER)
+ dev_warn(&pdev->dev, "error getting phy %d", rc);
+
+ /* Cleanup only the initialized ports */
+ hpriv->n_ports = port;
goto err;
} else
phy_power_on(hpriv->port_phys[port]);
}
+ /* All the ports have been initialized */
+ hpriv->n_ports = n_ports;
+
/*
* (Re-)program MBUS remapping windows if we are asked to.
*/
@@ -4174,7 +4180,7 @@ err:
clk_disable_unprepare(hpriv->clk);
clk_put(hpriv->clk);
}
- for (port = 0; port < n_ports; port++) {
+ for (port = 0; port < hpriv->n_ports; port++) {
if (!IS_ERR(hpriv->port_clks[port])) {
clk_disable_unprepare(hpriv->port_clks[port]);
clk_put(hpriv->port_clks[port]);
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index d74def823d3e..ba5f27120332 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -40,7 +40,6 @@
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index 97f4acb54ad6..3638887476f6 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -35,7 +35,6 @@
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 3b0dd57984e1..9a6bd4cd29a0 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -31,7 +31,6 @@
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index d67fc351343c..3062f8605b29 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -37,7 +37,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -157,6 +156,7 @@ static const struct sil_drivelist {
{ "ST380011ASL", SIL_QUIRK_MOD15WRITE },
{ "ST3120022ASL", SIL_QUIRK_MOD15WRITE },
{ "ST3160021ASL", SIL_QUIRK_MOD15WRITE },
+ { "TOSHIBA MK2561GSYN", SIL_QUIRK_MOD15WRITE },
{ "Maxtor 4D060H3", SIL_QUIRK_UDMA5MAX },
{ }
};
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index 1ad2f62d34b9..b513428171b3 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -33,7 +33,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index dc4f70179e7d..c630fa812624 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -39,7 +39,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index 9947010afc0f..39b5de60a1f9 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -82,7 +82,6 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -1021,8 +1020,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
idx++;
dist = ((long) (window_size - (offset + size))) >= 0 ? size :
(long) (window_size - offset);
- memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4),
- dist);
+ memcpy_fromio(psource, dimm_mmio + offset / 4, dist);
psource += dist;
size -= dist;
@@ -1031,8 +1029,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
readl(mmio + PDC_GENERAL_CTLR);
writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
readl(mmio + PDC_DIMM_WINDOW_CTLR);
- memcpy_fromio((char *) psource, (char *) (dimm_mmio),
- window_size / 4);
+ memcpy_fromio(psource, dimm_mmio, window_size / 4);
psource += window_size;
size -= window_size;
idx++;
@@ -1043,8 +1040,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
readl(mmio + PDC_GENERAL_CTLR);
writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
readl(mmio + PDC_DIMM_WINDOW_CTLR);
- memcpy_fromio((char *) psource, (char *) (dimm_mmio),
- size / 4);
+ memcpy_fromio(psource, dimm_mmio, size / 4);
}
}
#endif
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index 6d6489118873..08f98c3ed5c8 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -28,7 +28,6 @@
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index 87f056e54a9d..f72e84228c5c 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -36,7 +36,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index 44f304b3de63..29e847aac34b 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -37,7 +37,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index 62a76076b548..f1a9198dfe5a 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -1925,7 +1925,7 @@ static int ucode_init(loader_block *lb, amb_dev *dev)
const struct firmware *fw;
unsigned long start_address;
const struct ihex_binrec *rec;
- const char *errmsg = 0;
+ const char *errmsg = NULL;
int res;
res = request_ihex_firmware(&fw, "atmsar11.fw", &dev->pci_dev->dev);
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
index b41c9481b67b..82f2ae0d7cc4 100644
--- a/drivers/atm/firestream.c
+++ b/drivers/atm/firestream.c
@@ -736,8 +736,8 @@ static void process_txdone_queue (struct fs_dev *dev, struct queue *q)
skb = td->skb;
if (skb == FS_VCC (ATM_SKB(skb)->vcc)->last_skb) {
- wake_up_interruptible (& FS_VCC (ATM_SKB(skb)->vcc)->close_wait);
FS_VCC (ATM_SKB(skb)->vcc)->last_skb = NULL;
+ wake_up_interruptible (& FS_VCC (ATM_SKB(skb)->vcc)->close_wait);
}
td->dev->ntxpckts--;
@@ -1123,7 +1123,7 @@ static void fs_close(struct atm_vcc *atm_vcc)
this sleep_on, we'll lose any reference to these packets. Memory leak!
On the other hand, it's awfully convenient that we can abort a "close" that
is taking too long. Maybe just use non-interruptible sleep on? -- REW */
- interruptible_sleep_on (& vcc->close_wait);
+ wait_event_interruptible(vcc->close_wait, !vcc->last_skb);
}
txtp = &atm_vcc->qos.txtp;
@@ -2000,7 +2000,7 @@ static void firestream_remove_one(struct pci_dev *pdev)
fs_dprintk (FS_DEBUG_CLEANUP, "Freeing irq%d.\n", dev->irq);
free_irq (dev->irq, dev);
- del_timer (&dev->timer);
+ del_timer_sync (&dev->timer);
atm_dev_deregister(dev->atm_dev);
free_queue (dev, &dev->hp_txq);
diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c
index 45d506363aba..909c95bd7be2 100644
--- a/drivers/atm/idt77105.c
+++ b/drivers/atm/idt77105.c
@@ -368,9 +368,9 @@ EXPORT_SYMBOL(idt77105_init);
static void __exit idt77105_exit(void)
{
- /* turn off timers */
- del_timer(&stats_timer);
- del_timer(&restart_timer);
+ /* turn off timers */
+ del_timer_sync(&stats_timer);
+ del_timer_sync(&restart_timer);
}
module_exit(idt77105_exit);
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index 9587e959ce1a..9988ac98b6d8 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -639,9 +639,9 @@ static int ns_init_card(int i, struct pci_dev *pcidev)
card->hbnr.init = NUM_HB;
card->hbnr.max = MAX_HB;
- card->sm_handle = 0x00000000;
+ card->sm_handle = NULL;
card->sm_addr = 0x00000000;
- card->lg_handle = 0x00000000;
+ card->lg_handle = NULL;
card->lg_addr = 0x00000000;
card->efbie = 1; /* To prevent push_rxbufs from enabling the interrupt */
@@ -979,7 +979,7 @@ static void push_rxbufs(ns_dev * card, struct sk_buff *skb)
addr2 = card->sm_addr;
handle2 = card->sm_handle;
card->sm_addr = 0x00000000;
- card->sm_handle = 0x00000000;
+ card->sm_handle = NULL;
} else { /* (!sm_addr) */
card->sm_addr = addr1;
@@ -993,7 +993,7 @@ static void push_rxbufs(ns_dev * card, struct sk_buff *skb)
addr2 = card->lg_addr;
handle2 = card->lg_handle;
card->lg_addr = 0x00000000;
- card->lg_handle = 0x00000000;
+ card->lg_handle = NULL;
} else { /* (!lg_addr) */
card->lg_addr = addr1;
@@ -1739,10 +1739,10 @@ static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd,
}
scq->full = 1;
- spin_unlock_irqrestore(&scq->lock, flags);
- interruptible_sleep_on_timeout(&scq->scqfull_waitq,
- SCQFULL_TIMEOUT);
- spin_lock_irqsave(&scq->lock, flags);
+ wait_event_interruptible_lock_irq_timeout(scq->scqfull_waitq,
+ scq->tail != scq->next,
+ scq->lock,
+ SCQFULL_TIMEOUT);
if (scq->full) {
spin_unlock_irqrestore(&scq->lock, flags);
@@ -1789,10 +1789,10 @@ static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd,
scq->full = 1;
if (has_run++)
break;
- spin_unlock_irqrestore(&scq->lock, flags);
- interruptible_sleep_on_timeout(&scq->scqfull_waitq,
- SCQFULL_TIMEOUT);
- spin_lock_irqsave(&scq->lock, flags);
+ wait_event_interruptible_lock_irq_timeout(scq->scqfull_waitq,
+ scq->tail != scq->next,
+ scq->lock,
+ SCQFULL_TIMEOUT);
}
if (!scq->full) {
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index e3fb496c7163..943cf0d6abaf 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -760,7 +760,7 @@ static irqreturn_t solos_irq(int irq, void *dev_id)
return IRQ_RETVAL(handled);
}
-void solos_bh(unsigned long card_arg)
+static void solos_bh(unsigned long card_arg)
{
struct solos_card *card = (void *)card_arg;
uint32_t card_flags;
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index ec36e7772e57..8fa8deab6449 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -185,6 +185,9 @@ config GENERIC_CPU_DEVICES
bool
default n
+config GENERIC_CPU_AUTOPROBE
+ bool
+
config SOC_BUS
bool
diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c
index ecc1929d7f6a..b84ca8f13f9e 100644
--- a/drivers/base/attribute_container.c
+++ b/drivers/base/attribute_container.c
@@ -12,7 +12,6 @@
*/
#include <linux/attribute_container.h>
-#include <linux/init.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 59dc8086e4fa..83e910a57563 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -1218,7 +1218,7 @@ err_dev:
* with the name of the subsystem. The root device can carry subsystem-
* wide attributes. All registered devices are below this single root
* device and are named after the subsystem with a simple enumeration
- * number appended. The registered devices are not explicitely named;
+ * number appended. The registered devices are not explicitly named;
* only 'id' in the device needs to be set.
*
* Do not use this interface for anything new, it exists for compatibility
diff --git a/drivers/base/component.c b/drivers/base/component.c
index c53efe6c6d8e..c4778995cd72 100644
--- a/drivers/base/component.c
+++ b/drivers/base/component.c
@@ -133,9 +133,16 @@ static int try_to_bring_up_master(struct master *master,
goto out;
}
+ if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
/* Found all components */
ret = master->ops->bind(master->dev);
if (ret < 0) {
+ devres_release_group(master->dev, NULL);
+ dev_info(master->dev, "master bind failed: %d\n", ret);
master_remove_components(master);
goto out;
}
@@ -166,6 +173,7 @@ static void take_down_master(struct master *master)
{
if (master->bound) {
master->ops->unbind(master->dev);
+ devres_release_group(master->dev, NULL);
master->bound = false;
}
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 2b567177ef78..0dd65281cc65 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -23,7 +23,6 @@
#include <linux/genhd.h>
#include <linux/kallsyms.h>
#include <linux/mutex.h>
-#include <linux/async.h>
#include <linux/pm_runtime.h>
#include <linux/netdevice.h>
#include <linux/sysfs.h>
@@ -571,6 +570,23 @@ void device_remove_file(struct device *dev,
EXPORT_SYMBOL_GPL(device_remove_file);
/**
+ * device_remove_file_self - remove sysfs attribute file from its own method.
+ * @dev: device.
+ * @attr: device attribute descriptor.
+ *
+ * See kernfs_remove_self() for details.
+ */
+bool device_remove_file_self(struct device *dev,
+ const struct device_attribute *attr)
+{
+ if (dev)
+ return sysfs_remove_file_self(&dev->kobj, &attr->attr);
+ else
+ return false;
+}
+EXPORT_SYMBOL_GPL(device_remove_file_self);
+
+/**
* device_create_bin_file - create sysfs binary attribute file for device.
* @dev: device.
* @attr: device binary attribute descriptor.
@@ -2003,7 +2019,6 @@ void device_shutdown(void)
spin_lock(&devices_kset->list_lock);
}
spin_unlock(&devices_kset->list_lock);
- async_synchronize_full();
}
/*
@@ -2058,7 +2073,6 @@ create_syslog_header(const struct device *dev, char *hdr, size_t hdrlen)
return pos;
}
-EXPORT_SYMBOL(create_syslog_header);
int dev_vprintk_emit(int level, const struct device *dev,
const char *fmt, va_list args)
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index f48370dfc908..006b1bc5297d 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -15,6 +15,7 @@
#include <linux/percpu.h>
#include <linux/acpi.h>
#include <linux/of.h>
+#include <linux/cpufeature.h>
#include "base.h"
@@ -286,6 +287,41 @@ static void cpu_device_release(struct device *dev)
*/
}
+#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
+static ssize_t print_cpu_modalias(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ ssize_t n;
+ u32 i;
+
+ n = sprintf(buf, "cpu:type:" CPU_FEATURE_TYPEFMT ":feature:",
+ CPU_FEATURE_TYPEVAL);
+
+ for (i = 0; i < MAX_CPU_FEATURES; i++)
+ if (cpu_have_feature(i)) {
+ if (PAGE_SIZE < n + sizeof(",XXXX\n")) {
+ WARN(1, "CPU features overflow page\n");
+ break;
+ }
+ n += sprintf(&buf[n], ",%04X", i);
+ }
+ buf[n++] = '\n';
+ return n;
+}
+
+static int cpu_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (buf) {
+ print_cpu_modalias(NULL, NULL, buf);
+ add_uevent_var(env, "MODALIAS=%s", buf);
+ kfree(buf);
+ }
+ return 0;
+}
+#endif
+
/*
* register_cpu - Setup a sysfs device for a CPU.
* @cpu - cpu->hotpluggable field set to 1 will generate a control file in
@@ -306,8 +342,8 @@ int register_cpu(struct cpu *cpu, int num)
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;
+#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
+ cpu->dev.bus->uevent = cpu_uevent;
#endif
cpu->dev.groups = common_cpu_attr_groups;
if (cpu->hotpluggable)
@@ -330,8 +366,8 @@ struct device *get_cpu_device(unsigned cpu)
}
EXPORT_SYMBOL_GPL(get_cpu_device);
-#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
-static DEVICE_ATTR(modalias, 0444, arch_print_cpu_modalias, NULL);
+#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
+static DEVICE_ATTR(modalias, 0444, print_cpu_modalias, NULL);
#endif
static struct attribute *cpu_root_attrs[] = {
@@ -344,7 +380,7 @@ static struct attribute *cpu_root_attrs[] = {
&cpu_attrs[2].attr.attr,
&dev_attr_kernel_max.attr,
&dev_attr_offline.attr,
-#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
+#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
&dev_attr_modalias.attr,
#endif
NULL
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index 545c4de412c3..db4e264eecb6 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -791,6 +791,32 @@ void * devm_kmalloc(struct device *dev, size_t size, gfp_t gfp)
EXPORT_SYMBOL_GPL(devm_kmalloc);
/**
+ * devm_kstrdup - Allocate resource managed space and
+ * copy an existing string into that.
+ * @dev: Device to allocate memory for
+ * @s: the string to duplicate
+ * @gfp: the GFP mask used in the devm_kmalloc() call when
+ * allocating memory
+ * RETURNS:
+ * Pointer to allocated string on success, NULL on failure.
+ */
+char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp)
+{
+ size_t size;
+ char *buf;
+
+ if (!s)
+ return NULL;
+
+ size = strlen(s) + 1;
+ buf = devm_kmalloc(dev, size, gfp);
+ if (buf)
+ memcpy(buf, s, size);
+ return buf;
+}
+EXPORT_SYMBOL_GPL(devm_kstrdup);
+
+/**
* devm_kfree - Resource-managed kfree
* @dev: Device this memory belongs to
* @p: Memory to free
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index 1e16cbd61da2..ea77701deda4 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -251,9 +251,8 @@ EXPORT_SYMBOL_GPL(dma_buf_put);
* @dmabuf: [in] buffer to attach device to.
* @dev: [in] device to be attached.
*
- * Returns struct dma_buf_attachment * for this attachment; may return negative
- * error codes.
- *
+ * Returns struct dma_buf_attachment * for this attachment; returns ERR_PTR on
+ * error.
*/
struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
struct device *dev)
@@ -319,9 +318,8 @@ EXPORT_SYMBOL_GPL(dma_buf_detach);
* @attach: [in] attachment whose scatterlist is to be returned
* @direction: [in] direction of DMA transfer
*
- * Returns sg_table containing the scatterlist to be returned; may return NULL
- * or ERR_PTR.
- *
+ * Returns sg_table containing the scatterlist to be returned; returns ERR_PTR
+ * on error.
*/
struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach,
enum dma_data_direction direction)
@@ -334,6 +332,8 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach,
return ERR_PTR(-EINVAL);
sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction);
+ if (!sg_table)
+ sg_table = ERR_PTR(-ENOMEM);
return sg_table;
}
@@ -544,6 +544,8 @@ EXPORT_SYMBOL_GPL(dma_buf_mmap);
* These calls are optional in drivers. The intended use for them
* is for mapping objects linear in kernel space for high use objects.
* Please attempt to use kmap/kunmap before thinking about these interfaces.
+ *
+ * Returns NULL on error.
*/
void *dma_buf_vmap(struct dma_buf *dmabuf)
{
@@ -566,7 +568,9 @@ void *dma_buf_vmap(struct dma_buf *dmabuf)
BUG_ON(dmabuf->vmap_ptr);
ptr = dmabuf->ops->vmap(dmabuf);
- if (IS_ERR_OR_NULL(ptr))
+ if (WARN_ON_ONCE(IS_ERR(ptr)))
+ ptr = NULL;
+ if (!ptr)
goto out_unlock;
dmabuf->vmap_ptr = ptr;
@@ -616,36 +620,35 @@ static int dma_buf_describe(struct seq_file *s)
if (ret)
return ret;
- seq_printf(s, "\nDma-buf Objects:\n");
- seq_printf(s, "\texp_name\tsize\tflags\tmode\tcount\n");
+ seq_puts(s, "\nDma-buf Objects:\n");
+ seq_puts(s, "size\tflags\tmode\tcount\texp_name\n");
list_for_each_entry(buf_obj, &db_list.head, list_node) {
ret = mutex_lock_interruptible(&buf_obj->lock);
if (ret) {
- seq_printf(s,
- "\tERROR locking buffer object: skipping\n");
+ seq_puts(s,
+ "\tERROR locking buffer object: skipping\n");
continue;
}
- seq_printf(s, "\t");
-
- seq_printf(s, "\t%s\t%08zu\t%08x\t%08x\t%08ld\n",
- buf_obj->exp_name, buf_obj->size,
+ seq_printf(s, "%08zu\t%08x\t%08x\t%08ld\t%s\n",
+ buf_obj->size,
buf_obj->file->f_flags, buf_obj->file->f_mode,
- (long)(buf_obj->file->f_count.counter));
+ (long)(buf_obj->file->f_count.counter),
+ buf_obj->exp_name);
- seq_printf(s, "\t\tAttached Devices:\n");
+ seq_puts(s, "\tAttached Devices:\n");
attach_count = 0;
list_for_each_entry(attach_obj, &buf_obj->attachments, node) {
- seq_printf(s, "\t\t");
+ seq_puts(s, "\t");
- seq_printf(s, "%s\n", attach_obj->dev->init_name);
+ seq_printf(s, "%s\n", dev_name(attach_obj->dev));
attach_count++;
}
- seq_printf(s, "\n\t\tTotal %d devices attached\n",
+ seq_printf(s, "Total %d devices attached\n\n",
attach_count);
count++;
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 8a97ddfa6122..d276e33880be 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -649,7 +649,9 @@ static ssize_t firmware_loading_store(struct device *dev,
* see the mapped 'buf->data' once the loading
* is completed.
* */
- fw_map_pages_buf(fw_buf);
+ if (fw_map_pages_buf(fw_buf))
+ dev_err(dev, "%s: map pages failed\n",
+ __func__);
list_del_init(&fw_buf->pending_list);
complete_all(&fw_buf->completion);
break;
@@ -900,7 +902,8 @@ static int _request_firmware_load(struct firmware_priv *fw_priv,
dev_set_uevent_suppress(f_dev, false);
dev_dbg(f_dev, "firmware: requesting %s\n", buf->fw_id);
if (timeout != MAX_SCHEDULE_TIMEOUT)
- schedule_delayed_work(&fw_priv->timeout_work, timeout);
+ queue_delayed_work(system_power_efficient_wq,
+ &fw_priv->timeout_work, timeout);
kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
}
@@ -908,6 +911,8 @@ static int _request_firmware_load(struct firmware_priv *fw_priv,
wait_for_completion(&buf->completion);
cancel_delayed_work_sync(&fw_priv->timeout_work);
+ if (!buf->data)
+ retval = -ENOMEM;
device_remove_file(f_dev, &dev_attr_loading);
err_del_bin_attr:
@@ -1570,8 +1575,8 @@ static void device_uncache_fw_images_work(struct work_struct *work)
*/
static void device_uncache_fw_images_delay(unsigned long delay)
{
- schedule_delayed_work(&fw_cache.work,
- msecs_to_jiffies(delay));
+ queue_delayed_work(system_power_efficient_wq, &fw_cache.work,
+ msecs_to_jiffies(delay));
}
static int fw_pm_notify(struct notifier_block *notify_block,
@@ -1580,6 +1585,7 @@ static int fw_pm_notify(struct notifier_block *notify_block,
switch (mode) {
case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
+ case PM_RESTORE_PREPARE:
kill_requests_without_uevent();
device_cache_fw_images();
break;
diff --git a/drivers/base/node.c b/drivers/base/node.c
index bc9f43bf7e29..8f7ed9933a7c 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -599,7 +599,11 @@ int register_one_node(int nid)
void unregister_one_node(int nid)
{
+ if (!node_devices[nid])
+ return;
+
unregister_node(node_devices[nid]);
+ kfree(node_devices[nid]);
node_devices[nid] = NULL;
}
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index bc78848dd59a..e714709704e4 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -481,11 +481,10 @@ static int platform_drv_probe(struct device *_dev)
struct platform_device *dev = to_platform_device(_dev);
int ret;
- if (ACPI_HANDLE(_dev))
- acpi_dev_pm_attach(_dev, true);
+ acpi_dev_pm_attach(_dev, true);
ret = drv->probe(dev);
- if (ret && ACPI_HANDLE(_dev))
+ if (ret)
acpi_dev_pm_detach(_dev, true);
if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {
@@ -508,8 +507,7 @@ static int platform_drv_remove(struct device *_dev)
int ret;
ret = drv->remove(dev);
- if (ACPI_HANDLE(_dev))
- acpi_dev_pm_detach(_dev, true);
+ acpi_dev_pm_detach(_dev, true);
return ret;
}
@@ -520,8 +518,7 @@ static void platform_drv_shutdown(struct device *_dev)
struct platform_device *dev = to_platform_device(_dev);
drv->shutdown(dev);
- if (ACPI_HANDLE(_dev))
- acpi_dev_pm_detach(_dev, true);
+ acpi_dev_pm_detach(_dev, true);
}
/**
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 2e58ebb1f6c0..1cb8544598d5 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,6 +1,5 @@
-obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o
+obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o
obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o
-obj-$(CONFIG_PM_RUNTIME) += runtime.o
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
obj-$(CONFIG_PM_OPP) += opp.o
obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c
index e870bbe9ec4e..b99e6c06ee67 100644
--- a/drivers/base/power/clock_ops.c
+++ b/drivers/base/power/clock_ops.c
@@ -6,7 +6,6 @@
* This file is released under the GPLv2.
*/
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/io.h>
diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c
index 5da914041305..df2e5eeaeb05 100644
--- a/drivers/base/power/common.c
+++ b/drivers/base/power/common.c
@@ -6,7 +6,6 @@
* This file is released under the GPLv2.
*/
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/export.h>
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index bfb8955c406c..6f54962aae1d 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -6,7 +6,6 @@
* This file is released under the GPLv2.
*/
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/pm_runtime.h>
@@ -42,7 +41,7 @@
struct gpd_timing_data *__td = &dev_gpd_data(dev)->td; \
if (!__retval && __elapsed > __td->field) { \
__td->field = __elapsed; \
- dev_warn(dev, name " latency exceeded, new value %lld ns\n", \
+ dev_dbg(dev, name " latency exceeded, new value %lld ns\n", \
__elapsed); \
genpd->max_off_time_changed = true; \
__td->constraint_changed = true; \
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index 28dee3053f1f..a089e3bcdfbc 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -6,7 +6,6 @@
* This file is released under the GPLv2.
*/
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pm_domain.h>
#include <linux/pm_qos.h>
diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c
index a2e55bfdf572..96a92db83cad 100644
--- a/drivers/base/power/generic_ops.c
+++ b/drivers/base/power/generic_ops.c
@@ -285,7 +285,7 @@ int pm_generic_restore(struct device *dev)
EXPORT_SYMBOL_GPL(pm_generic_restore);
/**
- * pm_generic_complete - Generic routine competing a device power transition.
+ * pm_generic_complete - Generic routine completing a device power transition.
* @dev: Device to handle.
*
* Complete a device power transition during a system-wide power transition.
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 1b41fca3d65a..86d5e4fb5b98 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -29,6 +29,7 @@
#include <linux/async.h>
#include <linux/suspend.h>
#include <trace/events/power.h>
+#include <linux/cpufreq.h>
#include <linux/cpuidle.h>
#include <linux/timer.h>
@@ -91,6 +92,8 @@ void device_pm_sleep_init(struct device *dev)
{
dev->power.is_prepared = false;
dev->power.is_suspended = false;
+ dev->power.is_noirq_suspended = false;
+ dev->power.is_late_suspended = false;
init_completion(&dev->power.completion);
complete_all(&dev->power.completion);
dev->power.wakeup = NULL;
@@ -467,7 +470,7 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd)
* The driver of @dev will not receive interrupts while this function is being
* executed.
*/
-static int device_resume_noirq(struct device *dev, pm_message_t state)
+static int device_resume_noirq(struct device *dev, pm_message_t state, bool async)
{
pm_callback_t callback = NULL;
char *info = NULL;
@@ -479,6 +482,11 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
if (dev->power.syscore)
goto Out;
+ if (!dev->power.is_noirq_suspended)
+ goto Out;
+
+ dpm_wait(dev->parent, async);
+
if (dev->pm_domain) {
info = "noirq power domain ";
callback = pm_noirq_op(&dev->pm_domain->ops, state);
@@ -499,12 +507,32 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
}
error = dpm_run_callback(callback, dev, state, info);
+ dev->power.is_noirq_suspended = false;
Out:
+ complete_all(&dev->power.completion);
TRACE_RESUME(error);
return error;
}
+static bool is_async(struct device *dev)
+{
+ return dev->power.async_suspend && pm_async_enabled
+ && !pm_trace_is_enabled();
+}
+
+static void async_resume_noirq(void *data, async_cookie_t cookie)
+{
+ struct device *dev = (struct device *)data;
+ int error;
+
+ error = device_resume_noirq(dev, pm_transition, true);
+ if (error)
+ pm_dev_err(dev, pm_transition, " async", error);
+
+ put_device(dev);
+}
+
/**
* dpm_resume_noirq - Execute "noirq resume" callbacks for all devices.
* @state: PM transition of the system being carried out.
@@ -514,29 +542,48 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
*/
static void dpm_resume_noirq(pm_message_t state)
{
+ struct device *dev;
ktime_t starttime = ktime_get();
mutex_lock(&dpm_list_mtx);
- while (!list_empty(&dpm_noirq_list)) {
- struct device *dev = to_device(dpm_noirq_list.next);
- int error;
+ pm_transition = state;
+ /*
+ * Advanced the async threads upfront,
+ * in case the starting of async threads is
+ * delayed by non-async resuming devices.
+ */
+ list_for_each_entry(dev, &dpm_noirq_list, power.entry) {
+ reinit_completion(&dev->power.completion);
+ if (is_async(dev)) {
+ get_device(dev);
+ async_schedule(async_resume_noirq, dev);
+ }
+ }
+
+ while (!list_empty(&dpm_noirq_list)) {
+ dev = to_device(dpm_noirq_list.next);
get_device(dev);
list_move_tail(&dev->power.entry, &dpm_late_early_list);
mutex_unlock(&dpm_list_mtx);
- error = device_resume_noirq(dev, state);
- if (error) {
- suspend_stats.failed_resume_noirq++;
- dpm_save_failed_step(SUSPEND_RESUME_NOIRQ);
- dpm_save_failed_dev(dev_name(dev));
- pm_dev_err(dev, state, " noirq", error);
+ if (!is_async(dev)) {
+ int error;
+
+ error = device_resume_noirq(dev, state, false);
+ if (error) {
+ suspend_stats.failed_resume_noirq++;
+ dpm_save_failed_step(SUSPEND_RESUME_NOIRQ);
+ dpm_save_failed_dev(dev_name(dev));
+ pm_dev_err(dev, state, " noirq", error);
+ }
}
mutex_lock(&dpm_list_mtx);
put_device(dev);
}
mutex_unlock(&dpm_list_mtx);
+ async_synchronize_full();
dpm_show_time(starttime, state, "noirq");
resume_device_irqs();
cpuidle_resume();
@@ -549,7 +596,7 @@ static void dpm_resume_noirq(pm_message_t state)
*
* Runtime PM is disabled for @dev while this function is being executed.
*/
-static int device_resume_early(struct device *dev, pm_message_t state)
+static int device_resume_early(struct device *dev, pm_message_t state, bool async)
{
pm_callback_t callback = NULL;
char *info = NULL;
@@ -561,6 +608,11 @@ static int device_resume_early(struct device *dev, pm_message_t state)
if (dev->power.syscore)
goto Out;
+ if (!dev->power.is_late_suspended)
+ goto Out;
+
+ dpm_wait(dev->parent, async);
+
if (dev->pm_domain) {
info = "early power domain ";
callback = pm_late_early_op(&dev->pm_domain->ops, state);
@@ -581,43 +633,75 @@ static int device_resume_early(struct device *dev, pm_message_t state)
}
error = dpm_run_callback(callback, dev, state, info);
+ dev->power.is_late_suspended = false;
Out:
TRACE_RESUME(error);
pm_runtime_enable(dev);
+ complete_all(&dev->power.completion);
return error;
}
+static void async_resume_early(void *data, async_cookie_t cookie)
+{
+ struct device *dev = (struct device *)data;
+ int error;
+
+ error = device_resume_early(dev, pm_transition, true);
+ if (error)
+ pm_dev_err(dev, pm_transition, " async", error);
+
+ put_device(dev);
+}
+
/**
* dpm_resume_early - Execute "early resume" callbacks for all devices.
* @state: PM transition of the system being carried out.
*/
static void dpm_resume_early(pm_message_t state)
{
+ struct device *dev;
ktime_t starttime = ktime_get();
mutex_lock(&dpm_list_mtx);
- while (!list_empty(&dpm_late_early_list)) {
- struct device *dev = to_device(dpm_late_early_list.next);
- int error;
+ pm_transition = state;
+ /*
+ * Advanced the async threads upfront,
+ * in case the starting of async threads is
+ * delayed by non-async resuming devices.
+ */
+ list_for_each_entry(dev, &dpm_late_early_list, power.entry) {
+ reinit_completion(&dev->power.completion);
+ if (is_async(dev)) {
+ get_device(dev);
+ async_schedule(async_resume_early, dev);
+ }
+ }
+
+ while (!list_empty(&dpm_late_early_list)) {
+ dev = to_device(dpm_late_early_list.next);
get_device(dev);
list_move_tail(&dev->power.entry, &dpm_suspended_list);
mutex_unlock(&dpm_list_mtx);
- error = device_resume_early(dev, state);
- if (error) {
- suspend_stats.failed_resume_early++;
- dpm_save_failed_step(SUSPEND_RESUME_EARLY);
- dpm_save_failed_dev(dev_name(dev));
- pm_dev_err(dev, state, " early", error);
- }
+ if (!is_async(dev)) {
+ int error;
+ error = device_resume_early(dev, state, false);
+ if (error) {
+ suspend_stats.failed_resume_early++;
+ dpm_save_failed_step(SUSPEND_RESUME_EARLY);
+ dpm_save_failed_dev(dev_name(dev));
+ pm_dev_err(dev, state, " early", error);
+ }
+ }
mutex_lock(&dpm_list_mtx);
put_device(dev);
}
mutex_unlock(&dpm_list_mtx);
+ async_synchronize_full();
dpm_show_time(starttime, state, "early");
}
@@ -732,12 +816,6 @@ static void async_resume(void *data, async_cookie_t cookie)
put_device(dev);
}
-static bool is_async(struct device *dev)
-{
- return dev->power.async_suspend && pm_async_enabled
- && !pm_trace_is_enabled();
-}
-
/**
* dpm_resume - Execute "resume" callbacks for non-sysdev devices.
* @state: PM transition of the system being carried out.
@@ -789,6 +867,8 @@ void dpm_resume(pm_message_t state)
mutex_unlock(&dpm_list_mtx);
async_synchronize_full();
dpm_show_time(starttime, state, NULL);
+
+ cpufreq_resume();
}
/**
@@ -913,13 +993,24 @@ static pm_message_t resume_event(pm_message_t sleep_state)
* The driver of @dev will not receive interrupts while this function is being
* executed.
*/
-static int device_suspend_noirq(struct device *dev, pm_message_t state)
+static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool async)
{
pm_callback_t callback = NULL;
char *info = NULL;
+ int error = 0;
+
+ if (async_error)
+ goto Complete;
+
+ if (pm_wakeup_pending()) {
+ async_error = -EBUSY;
+ goto Complete;
+ }
if (dev->power.syscore)
- return 0;
+ goto Complete;
+
+ dpm_wait_for_children(dev, async);
if (dev->pm_domain) {
info = "noirq power domain ";
@@ -940,7 +1031,41 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
callback = pm_noirq_op(dev->driver->pm, state);
}
- return dpm_run_callback(callback, dev, state, info);
+ error = dpm_run_callback(callback, dev, state, info);
+ if (!error)
+ dev->power.is_noirq_suspended = true;
+ else
+ async_error = error;
+
+Complete:
+ complete_all(&dev->power.completion);
+ return error;
+}
+
+static void async_suspend_noirq(void *data, async_cookie_t cookie)
+{
+ struct device *dev = (struct device *)data;
+ int error;
+
+ error = __device_suspend_noirq(dev, pm_transition, true);
+ if (error) {
+ dpm_save_failed_dev(dev_name(dev));
+ pm_dev_err(dev, pm_transition, " async", error);
+ }
+
+ put_device(dev);
+}
+
+static int device_suspend_noirq(struct device *dev)
+{
+ reinit_completion(&dev->power.completion);
+
+ if (pm_async_enabled && dev->power.async_suspend) {
+ get_device(dev);
+ async_schedule(async_suspend_noirq, dev);
+ return 0;
+ }
+ return __device_suspend_noirq(dev, pm_transition, false);
}
/**
@@ -958,19 +1083,20 @@ static int dpm_suspend_noirq(pm_message_t state)
cpuidle_pause();
suspend_device_irqs();
mutex_lock(&dpm_list_mtx);
+ pm_transition = state;
+ async_error = 0;
+
while (!list_empty(&dpm_late_early_list)) {
struct device *dev = to_device(dpm_late_early_list.prev);
get_device(dev);
mutex_unlock(&dpm_list_mtx);
- error = device_suspend_noirq(dev, state);
+ error = device_suspend_noirq(dev);
mutex_lock(&dpm_list_mtx);
if (error) {
pm_dev_err(dev, state, " noirq", error);
- suspend_stats.failed_suspend_noirq++;
- dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ);
dpm_save_failed_dev(dev_name(dev));
put_device(dev);
break;
@@ -979,16 +1105,21 @@ static int dpm_suspend_noirq(pm_message_t state)
list_move(&dev->power.entry, &dpm_noirq_list);
put_device(dev);
- if (pm_wakeup_pending()) {
- error = -EBUSY;
+ if (async_error)
break;
- }
}
mutex_unlock(&dpm_list_mtx);
- if (error)
+ async_synchronize_full();
+ if (!error)
+ error = async_error;
+
+ if (error) {
+ suspend_stats.failed_suspend_noirq++;
+ dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ);
dpm_resume_noirq(resume_event(state));
- else
+ } else {
dpm_show_time(starttime, state, "noirq");
+ }
return error;
}
@@ -999,15 +1130,26 @@ static int dpm_suspend_noirq(pm_message_t state)
*
* Runtime PM is disabled for @dev while this function is being executed.
*/
-static int device_suspend_late(struct device *dev, pm_message_t state)
+static int __device_suspend_late(struct device *dev, pm_message_t state, bool async)
{
pm_callback_t callback = NULL;
char *info = NULL;
+ int error = 0;
__pm_runtime_disable(dev, false);
+ if (async_error)
+ goto Complete;
+
+ if (pm_wakeup_pending()) {
+ async_error = -EBUSY;
+ goto Complete;
+ }
+
if (dev->power.syscore)
- return 0;
+ goto Complete;
+
+ dpm_wait_for_children(dev, async);
if (dev->pm_domain) {
info = "late power domain ";
@@ -1028,7 +1170,41 @@ static int device_suspend_late(struct device *dev, pm_message_t state)
callback = pm_late_early_op(dev->driver->pm, state);
}
- return dpm_run_callback(callback, dev, state, info);
+ error = dpm_run_callback(callback, dev, state, info);
+ if (!error)
+ dev->power.is_late_suspended = true;
+ else
+ async_error = error;
+
+Complete:
+ complete_all(&dev->power.completion);
+ return error;
+}
+
+static void async_suspend_late(void *data, async_cookie_t cookie)
+{
+ struct device *dev = (struct device *)data;
+ int error;
+
+ error = __device_suspend_late(dev, pm_transition, true);
+ if (error) {
+ dpm_save_failed_dev(dev_name(dev));
+ pm_dev_err(dev, pm_transition, " async", error);
+ }
+ put_device(dev);
+}
+
+static int device_suspend_late(struct device *dev)
+{
+ reinit_completion(&dev->power.completion);
+
+ if (pm_async_enabled && dev->power.async_suspend) {
+ get_device(dev);
+ async_schedule(async_suspend_late, dev);
+ return 0;
+ }
+
+ return __device_suspend_late(dev, pm_transition, false);
}
/**
@@ -1041,19 +1217,20 @@ static int dpm_suspend_late(pm_message_t state)
int error = 0;
mutex_lock(&dpm_list_mtx);
+ pm_transition = state;
+ async_error = 0;
+
while (!list_empty(&dpm_suspended_list)) {
struct device *dev = to_device(dpm_suspended_list.prev);
get_device(dev);
mutex_unlock(&dpm_list_mtx);
- error = device_suspend_late(dev, state);
+ error = device_suspend_late(dev);
mutex_lock(&dpm_list_mtx);
if (error) {
pm_dev_err(dev, state, " late", error);
- suspend_stats.failed_suspend_late++;
- dpm_save_failed_step(SUSPEND_SUSPEND_LATE);
dpm_save_failed_dev(dev_name(dev));
put_device(dev);
break;
@@ -1062,17 +1239,18 @@ static int dpm_suspend_late(pm_message_t state)
list_move(&dev->power.entry, &dpm_late_early_list);
put_device(dev);
- if (pm_wakeup_pending()) {
- error = -EBUSY;
+ if (async_error)
break;
- }
}
mutex_unlock(&dpm_list_mtx);
- if (error)
+ async_synchronize_full();
+ if (error) {
+ suspend_stats.failed_suspend_late++;
+ dpm_save_failed_step(SUSPEND_SUSPEND_LATE);
dpm_resume_early(resume_event(state));
- else
+ } else {
dpm_show_time(starttime, state, "late");
-
+ }
return error;
}
@@ -1259,6 +1437,8 @@ int dpm_suspend(pm_message_t state)
might_sleep();
+ cpufreq_suspend();
+
mutex_lock(&dpm_list_mtx);
pm_transition = state;
async_error = 0;
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index fa4187418440..25538675d59e 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/err.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/cpufreq.h>
#include <linux/device.h>
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index cfc3226ec492..a21223d95926 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -89,8 +89,8 @@ extern void dpm_sysfs_remove(struct device *dev);
extern void rpm_sysfs_remove(struct device *dev);
extern int wakeup_sysfs_add(struct device *dev);
extern void wakeup_sysfs_remove(struct device *dev);
-extern int pm_qos_sysfs_add_latency(struct device *dev);
-extern void pm_qos_sysfs_remove_latency(struct device *dev);
+extern int pm_qos_sysfs_add_resume_latency(struct device *dev);
+extern void pm_qos_sysfs_remove_resume_latency(struct device *dev);
extern int pm_qos_sysfs_add_flags(struct device *dev);
extern void pm_qos_sysfs_remove_flags(struct device *dev);
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 5c1361a9e5dd..36b9eb4862cb 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -105,7 +105,7 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_flags);
s32 __dev_pm_qos_read_value(struct device *dev)
{
return IS_ERR_OR_NULL(dev->power.qos) ?
- 0 : pm_qos_read_value(&dev->power.qos->latency);
+ 0 : pm_qos_read_value(&dev->power.qos->resume_latency);
}
/**
@@ -141,16 +141,24 @@ static int apply_constraint(struct dev_pm_qos_request *req,
int ret;
switch(req->type) {
- case DEV_PM_QOS_LATENCY:
- ret = pm_qos_update_target(&qos->latency, &req->data.pnode,
- action, value);
+ case DEV_PM_QOS_RESUME_LATENCY:
+ ret = pm_qos_update_target(&qos->resume_latency,
+ &req->data.pnode, action, value);
if (ret) {
- value = pm_qos_read_value(&qos->latency);
+ value = pm_qos_read_value(&qos->resume_latency);
blocking_notifier_call_chain(&dev_pm_notifiers,
(unsigned long)value,
req);
}
break;
+ case DEV_PM_QOS_LATENCY_TOLERANCE:
+ ret = pm_qos_update_target(&qos->latency_tolerance,
+ &req->data.pnode, action, value);
+ if (ret) {
+ value = pm_qos_read_value(&qos->latency_tolerance);
+ req->dev->power.set_latency_tolerance(req->dev, value);
+ }
+ break;
case DEV_PM_QOS_FLAGS:
ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
action, value);
@@ -186,13 +194,21 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
}
BLOCKING_INIT_NOTIFIER_HEAD(n);
- c = &qos->latency;
+ c = &qos->resume_latency;
plist_head_init(&c->list);
- c->target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
- c->default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
+ c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
+ c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
+ c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
c->type = PM_QOS_MIN;
c->notifiers = n;
+ c = &qos->latency_tolerance;
+ plist_head_init(&c->list);
+ c->target_value = PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE;
+ c->default_value = PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE;
+ c->no_constraint_value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
+ c->type = PM_QOS_MIN;
+
INIT_LIST_HEAD(&qos->flags.list);
spin_lock_irq(&dev->power.lock);
@@ -224,7 +240,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
* If the device's PM QoS resume latency limit or PM QoS flags have been
* exposed to user space, they have to be hidden at this point.
*/
- pm_qos_sysfs_remove_latency(dev);
+ pm_qos_sysfs_remove_resume_latency(dev);
pm_qos_sysfs_remove_flags(dev);
mutex_lock(&dev_pm_qos_mtx);
@@ -237,7 +253,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
goto out;
/* Flush the constraints lists for the device. */
- c = &qos->latency;
+ c = &qos->resume_latency;
plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
/*
* Update constraints list and call the notification
@@ -246,6 +262,11 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
memset(req, 0, sizeof(*req));
}
+ c = &qos->latency_tolerance;
+ plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
+ apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
+ memset(req, 0, sizeof(*req));
+ }
f = &qos->flags;
list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) {
apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
@@ -265,6 +286,40 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
mutex_unlock(&dev_pm_qos_sysfs_mtx);
}
+static bool dev_pm_qos_invalid_request(struct device *dev,
+ struct dev_pm_qos_request *req)
+{
+ return !req || (req->type == DEV_PM_QOS_LATENCY_TOLERANCE
+ && !dev->power.set_latency_tolerance);
+}
+
+static int __dev_pm_qos_add_request(struct device *dev,
+ struct dev_pm_qos_request *req,
+ enum dev_pm_qos_req_type type, s32 value)
+{
+ int ret = 0;
+
+ if (!dev || dev_pm_qos_invalid_request(dev, req))
+ return -EINVAL;
+
+ if (WARN(dev_pm_qos_request_active(req),
+ "%s() called for already added request\n", __func__))
+ return -EINVAL;
+
+ if (IS_ERR(dev->power.qos))
+ ret = -ENODEV;
+ else if (!dev->power.qos)
+ ret = dev_pm_qos_constraints_allocate(dev);
+
+ trace_dev_pm_qos_add_request(dev_name(dev), type, value);
+ if (!ret) {
+ req->dev = dev;
+ req->type = type;
+ ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
+ }
+ return ret;
+}
+
/**
* dev_pm_qos_add_request - inserts new qos request into the list
* @dev: target device for the constraint
@@ -290,31 +345,11 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
enum dev_pm_qos_req_type type, s32 value)
{
- int ret = 0;
-
- if (!dev || !req) /*guard against callers passing in null */
- return -EINVAL;
-
- if (WARN(dev_pm_qos_request_active(req),
- "%s() called for already added request\n", __func__))
- return -EINVAL;
+ int ret;
mutex_lock(&dev_pm_qos_mtx);
-
- if (IS_ERR(dev->power.qos))
- ret = -ENODEV;
- else if (!dev->power.qos)
- ret = dev_pm_qos_constraints_allocate(dev);
-
- trace_dev_pm_qos_add_request(dev_name(dev), type, value);
- if (!ret) {
- req->dev = dev;
- req->type = type;
- ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
- }
-
+ ret = __dev_pm_qos_add_request(dev, req, type, value);
mutex_unlock(&dev_pm_qos_mtx);
-
return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
@@ -341,7 +376,8 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
return -ENODEV;
switch(req->type) {
- case DEV_PM_QOS_LATENCY:
+ case DEV_PM_QOS_RESUME_LATENCY:
+ case DEV_PM_QOS_LATENCY_TOLERANCE:
curr_value = req->data.pnode.prio;
break;
case DEV_PM_QOS_FLAGS:
@@ -460,8 +496,8 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
ret = dev_pm_qos_constraints_allocate(dev);
if (!ret)
- ret = blocking_notifier_chain_register(
- dev->power.qos->latency.notifiers, notifier);
+ ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers,
+ notifier);
mutex_unlock(&dev_pm_qos_mtx);
return ret;
@@ -487,9 +523,8 @@ int dev_pm_qos_remove_notifier(struct device *dev,
/* Silently return if the constraints object is not present. */
if (!IS_ERR_OR_NULL(dev->power.qos))
- retval = blocking_notifier_chain_unregister(
- dev->power.qos->latency.notifiers,
- notifier);
+ retval = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers,
+ notifier);
mutex_unlock(&dev_pm_qos_mtx);
return retval;
@@ -530,20 +565,32 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_remove_global_notifier);
* dev_pm_qos_add_ancestor_request - Add PM QoS request for device's ancestor.
* @dev: Device whose ancestor to add the request for.
* @req: Pointer to the preallocated handle.
+ * @type: Type of the request.
* @value: Constraint latency value.
*/
int dev_pm_qos_add_ancestor_request(struct device *dev,
- struct dev_pm_qos_request *req, s32 value)
+ struct dev_pm_qos_request *req,
+ enum dev_pm_qos_req_type type, s32 value)
{
struct device *ancestor = dev->parent;
int ret = -ENODEV;
- while (ancestor && !ancestor->power.ignore_children)
- ancestor = ancestor->parent;
+ switch (type) {
+ case DEV_PM_QOS_RESUME_LATENCY:
+ while (ancestor && !ancestor->power.ignore_children)
+ ancestor = ancestor->parent;
+ break;
+ case DEV_PM_QOS_LATENCY_TOLERANCE:
+ while (ancestor && !ancestor->power.set_latency_tolerance)
+ ancestor = ancestor->parent;
+
+ break;
+ default:
+ ancestor = NULL;
+ }
if (ancestor)
- ret = dev_pm_qos_add_request(ancestor, req,
- DEV_PM_QOS_LATENCY, value);
+ ret = dev_pm_qos_add_request(ancestor, req, type, value);
if (ret < 0)
req->dev = NULL;
@@ -559,9 +606,13 @@ static void __dev_pm_qos_drop_user_request(struct device *dev,
struct dev_pm_qos_request *req = NULL;
switch(type) {
- case DEV_PM_QOS_LATENCY:
- req = dev->power.qos->latency_req;
- dev->power.qos->latency_req = NULL;
+ case DEV_PM_QOS_RESUME_LATENCY:
+ req = dev->power.qos->resume_latency_req;
+ dev->power.qos->resume_latency_req = NULL;
+ break;
+ case DEV_PM_QOS_LATENCY_TOLERANCE:
+ req = dev->power.qos->latency_tolerance_req;
+ dev->power.qos->latency_tolerance_req = NULL;
break;
case DEV_PM_QOS_FLAGS:
req = dev->power.qos->flags_req;
@@ -597,7 +648,7 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
if (!req)
return -ENOMEM;
- ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_LATENCY, value);
+ ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_RESUME_LATENCY, value);
if (ret < 0) {
kfree(req);
return ret;
@@ -609,7 +660,7 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
if (IS_ERR_OR_NULL(dev->power.qos))
ret = -ENODEV;
- else if (dev->power.qos->latency_req)
+ else if (dev->power.qos->resume_latency_req)
ret = -EEXIST;
if (ret < 0) {
@@ -618,13 +669,13 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
mutex_unlock(&dev_pm_qos_mtx);
goto out;
}
- dev->power.qos->latency_req = req;
+ dev->power.qos->resume_latency_req = req;
mutex_unlock(&dev_pm_qos_mtx);
- ret = pm_qos_sysfs_add_latency(dev);
+ ret = pm_qos_sysfs_add_resume_latency(dev);
if (ret)
- dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);
+ dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_RESUME_LATENCY);
out:
mutex_unlock(&dev_pm_qos_sysfs_mtx);
@@ -634,8 +685,8 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit);
static void __dev_pm_qos_hide_latency_limit(struct device *dev)
{
- if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->latency_req)
- __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);
+ if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->resume_latency_req)
+ __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_RESUME_LATENCY);
}
/**
@@ -646,7 +697,7 @@ void dev_pm_qos_hide_latency_limit(struct device *dev)
{
mutex_lock(&dev_pm_qos_sysfs_mtx);
- pm_qos_sysfs_remove_latency(dev);
+ pm_qos_sysfs_remove_resume_latency(dev);
mutex_lock(&dev_pm_qos_mtx);
__dev_pm_qos_hide_latency_limit(dev);
@@ -768,6 +819,67 @@ int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set)
pm_runtime_put(dev);
return ret;
}
+
+/**
+ * dev_pm_qos_get_user_latency_tolerance - Get user space latency tolerance.
+ * @dev: Device to obtain the user space latency tolerance for.
+ */
+s32 dev_pm_qos_get_user_latency_tolerance(struct device *dev)
+{
+ s32 ret;
+
+ mutex_lock(&dev_pm_qos_mtx);
+ ret = IS_ERR_OR_NULL(dev->power.qos)
+ || !dev->power.qos->latency_tolerance_req ?
+ PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT :
+ dev->power.qos->latency_tolerance_req->data.pnode.prio;
+ mutex_unlock(&dev_pm_qos_mtx);
+ return ret;
+}
+
+/**
+ * dev_pm_qos_update_user_latency_tolerance - Update user space latency tolerance.
+ * @dev: Device to update the user space latency tolerance for.
+ * @val: New user space latency tolerance for @dev (negative values disable).
+ */
+int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val)
+{
+ int ret;
+
+ mutex_lock(&dev_pm_qos_mtx);
+
+ if (IS_ERR_OR_NULL(dev->power.qos)
+ || !dev->power.qos->latency_tolerance_req) {
+ struct dev_pm_qos_request *req;
+
+ if (val < 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ ret = __dev_pm_qos_add_request(dev, req, DEV_PM_QOS_LATENCY_TOLERANCE, val);
+ if (ret < 0) {
+ kfree(req);
+ goto out;
+ }
+ dev->power.qos->latency_tolerance_req = req;
+ } else {
+ if (val < 0) {
+ __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY_TOLERANCE);
+ ret = 0;
+ } else {
+ ret = __dev_pm_qos_update_request(dev->power.qos->latency_tolerance_req, val);
+ }
+ }
+
+ out:
+ mutex_unlock(&dev_pm_qos_mtx);
+ return ret;
+}
#else /* !CONFIG_PM_RUNTIME */
static void __dev_pm_qos_hide_latency_limit(struct device *dev) {}
static void __dev_pm_qos_hide_flags(struct device *dev) {}
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 72e00e66ecc5..67c7938e430b 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -13,6 +13,43 @@
#include <trace/events/rpm.h>
#include "power.h"
+#define RPM_GET_CALLBACK(dev, cb) \
+({ \
+ int (*__rpm_cb)(struct device *__d); \
+ \
+ if (dev->pm_domain) \
+ __rpm_cb = dev->pm_domain->ops.cb; \
+ else if (dev->type && dev->type->pm) \
+ __rpm_cb = dev->type->pm->cb; \
+ else if (dev->class && dev->class->pm) \
+ __rpm_cb = dev->class->pm->cb; \
+ else if (dev->bus && dev->bus->pm) \
+ __rpm_cb = dev->bus->pm->cb; \
+ else \
+ __rpm_cb = NULL; \
+ \
+ if (!__rpm_cb && dev->driver && dev->driver->pm) \
+ __rpm_cb = dev->driver->pm->cb; \
+ \
+ __rpm_cb; \
+})
+
+static int (*rpm_get_suspend_cb(struct device *dev))(struct device *)
+{
+ return RPM_GET_CALLBACK(dev, runtime_suspend);
+}
+
+static int (*rpm_get_resume_cb(struct device *dev))(struct device *)
+{
+ return RPM_GET_CALLBACK(dev, runtime_resume);
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int (*rpm_get_idle_cb(struct device *dev))(struct device *)
+{
+ return RPM_GET_CALLBACK(dev, runtime_idle);
+}
+
static int rpm_resume(struct device *dev, int rpmflags);
static int rpm_suspend(struct device *dev, int rpmflags);
@@ -310,19 +347,7 @@ static int rpm_idle(struct device *dev, int rpmflags)
dev->power.idle_notification = true;
- if (dev->pm_domain)
- callback = dev->pm_domain->ops.runtime_idle;
- else if (dev->type && dev->type->pm)
- callback = dev->type->pm->runtime_idle;
- else if (dev->class && dev->class->pm)
- callback = dev->class->pm->runtime_idle;
- else if (dev->bus && dev->bus->pm)
- callback = dev->bus->pm->runtime_idle;
- else
- callback = NULL;
-
- if (!callback && dev->driver && dev->driver->pm)
- callback = dev->driver->pm->runtime_idle;
+ callback = rpm_get_idle_cb(dev);
if (callback)
retval = __rpm_callback(callback, dev);
@@ -492,19 +517,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
__update_runtime_status(dev, RPM_SUSPENDING);
- if (dev->pm_domain)
- callback = dev->pm_domain->ops.runtime_suspend;
- else if (dev->type && dev->type->pm)
- callback = dev->type->pm->runtime_suspend;
- else if (dev->class && dev->class->pm)
- callback = dev->class->pm->runtime_suspend;
- else if (dev->bus && dev->bus->pm)
- callback = dev->bus->pm->runtime_suspend;
- else
- callback = NULL;
-
- if (!callback && dev->driver && dev->driver->pm)
- callback = dev->driver->pm->runtime_suspend;
+ callback = rpm_get_suspend_cb(dev);
retval = rpm_callback(callback, dev);
if (retval)
@@ -724,19 +737,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
__update_runtime_status(dev, RPM_RESUMING);
- if (dev->pm_domain)
- callback = dev->pm_domain->ops.runtime_resume;
- else if (dev->type && dev->type->pm)
- callback = dev->type->pm->runtime_resume;
- else if (dev->class && dev->class->pm)
- callback = dev->class->pm->runtime_resume;
- else if (dev->bus && dev->bus->pm)
- callback = dev->bus->pm->runtime_resume;
- else
- callback = NULL;
-
- if (!callback && dev->driver && dev->driver->pm)
- callback = dev->driver->pm->runtime_resume;
+ callback = rpm_get_resume_cb(dev);
retval = rpm_callback(callback, dev);
if (retval) {
@@ -1130,7 +1131,7 @@ EXPORT_SYMBOL_GPL(pm_runtime_barrier);
* @dev: Device to handle.
* @check_resume: If set, check if there's a resume request for the device.
*
- * Increment power.disable_depth for the device and if was zero previously,
+ * Increment power.disable_depth for the device and if it was zero previously,
* cancel all pending runtime PM requests for the device and wait for all
* operations in progress to complete. The device can be either active or
* suspended after its runtime PM has been disabled.
@@ -1401,3 +1402,86 @@ void pm_runtime_remove(struct device *dev)
if (dev->power.irq_safe && dev->parent)
pm_runtime_put(dev->parent);
}
+#endif
+
+/**
+ * pm_runtime_force_suspend - Force a device into suspend state if needed.
+ * @dev: Device to suspend.
+ *
+ * Disable runtime PM so we safely can check the device's runtime PM status and
+ * if it is active, invoke it's .runtime_suspend callback to bring it into
+ * suspend state. Keep runtime PM disabled to preserve the state unless we
+ * encounter errors.
+ *
+ * Typically this function may be invoked from a system suspend callback to make
+ * sure the device is put into low power state.
+ */
+int pm_runtime_force_suspend(struct device *dev)
+{
+ int (*callback)(struct device *);
+ int ret = 0;
+
+ pm_runtime_disable(dev);
+
+ /*
+ * Note that pm_runtime_status_suspended() returns false while
+ * !CONFIG_PM_RUNTIME, which means the device will be put into low
+ * power state.
+ */
+ if (pm_runtime_status_suspended(dev))
+ return 0;
+
+ callback = rpm_get_suspend_cb(dev);
+
+ if (!callback) {
+ ret = -ENOSYS;
+ goto err;
+ }
+
+ ret = callback(dev);
+ if (ret)
+ goto err;
+
+ pm_runtime_set_suspended(dev);
+ return 0;
+err:
+ pm_runtime_enable(dev);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pm_runtime_force_suspend);
+
+/**
+ * pm_runtime_force_resume - Force a device into resume state.
+ * @dev: Device to resume.
+ *
+ * Prior invoking this function we expect the user to have brought the device
+ * into low power state by a call to pm_runtime_force_suspend(). Here we reverse
+ * those actions and brings the device into full power. We update the runtime PM
+ * status and re-enables runtime PM.
+ *
+ * Typically this function may be invoked from a system resume callback to make
+ * sure the device is put into full power state.
+ */
+int pm_runtime_force_resume(struct device *dev)
+{
+ int (*callback)(struct device *);
+ int ret = 0;
+
+ callback = rpm_get_resume_cb(dev);
+
+ if (!callback) {
+ ret = -ENOSYS;
+ goto out;
+ }
+
+ ret = callback(dev);
+ if (ret)
+ goto out;
+
+ pm_runtime_set_active(dev);
+ pm_runtime_mark_last_busy(dev);
+out:
+ pm_runtime_enable(dev);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pm_runtime_force_resume);
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 03e089ade5ce..95b181d1ca6d 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -218,15 +218,16 @@ static ssize_t autosuspend_delay_ms_store(struct device *dev,
static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show,
autosuspend_delay_ms_store);
-static ssize_t pm_qos_latency_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t pm_qos_resume_latency_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
- return sprintf(buf, "%d\n", dev_pm_qos_requested_latency(dev));
+ return sprintf(buf, "%d\n", dev_pm_qos_requested_resume_latency(dev));
}
-static ssize_t pm_qos_latency_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t n)
+static ssize_t pm_qos_resume_latency_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t n)
{
s32 value;
int ret;
@@ -237,12 +238,47 @@ static ssize_t pm_qos_latency_store(struct device *dev,
if (value < 0)
return -EINVAL;
- ret = dev_pm_qos_update_request(dev->power.qos->latency_req, value);
+ ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req,
+ value);
return ret < 0 ? ret : n;
}
static DEVICE_ATTR(pm_qos_resume_latency_us, 0644,
- pm_qos_latency_show, pm_qos_latency_store);
+ pm_qos_resume_latency_show, pm_qos_resume_latency_store);
+
+static ssize_t pm_qos_latency_tolerance_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ s32 value = dev_pm_qos_get_user_latency_tolerance(dev);
+
+ if (value < 0)
+ return sprintf(buf, "auto\n");
+ else if (value == PM_QOS_LATENCY_ANY)
+ return sprintf(buf, "any\n");
+
+ return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t pm_qos_latency_tolerance_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t n)
+{
+ s32 value;
+ int ret;
+
+ if (kstrtos32(buf, 0, &value)) {
+ if (!strcmp(buf, "auto") || !strcmp(buf, "auto\n"))
+ value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
+ else if (!strcmp(buf, "any") || !strcmp(buf, "any\n"))
+ value = PM_QOS_LATENCY_ANY;
+ }
+ ret = dev_pm_qos_update_user_latency_tolerance(dev, value);
+ return ret < 0 ? ret : n;
+}
+
+static DEVICE_ATTR(pm_qos_latency_tolerance_us, 0644,
+ pm_qos_latency_tolerance_show, pm_qos_latency_tolerance_store);
static ssize_t pm_qos_no_power_off_show(struct device *dev,
struct device_attribute *attr,
@@ -618,15 +654,26 @@ static struct attribute_group pm_runtime_attr_group = {
.attrs = runtime_attrs,
};
-static struct attribute *pm_qos_latency_attrs[] = {
+static struct attribute *pm_qos_resume_latency_attrs[] = {
#ifdef CONFIG_PM_RUNTIME
&dev_attr_pm_qos_resume_latency_us.attr,
#endif /* CONFIG_PM_RUNTIME */
NULL,
};
-static struct attribute_group pm_qos_latency_attr_group = {
+static struct attribute_group pm_qos_resume_latency_attr_group = {
+ .name = power_group_name,
+ .attrs = pm_qos_resume_latency_attrs,
+};
+
+static struct attribute *pm_qos_latency_tolerance_attrs[] = {
+#ifdef CONFIG_PM_RUNTIME
+ &dev_attr_pm_qos_latency_tolerance_us.attr,
+#endif /* CONFIG_PM_RUNTIME */
+ NULL,
+};
+static struct attribute_group pm_qos_latency_tolerance_attr_group = {
.name = power_group_name,
- .attrs = pm_qos_latency_attrs,
+ .attrs = pm_qos_latency_tolerance_attrs,
};
static struct attribute *pm_qos_flags_attrs[] = {
@@ -654,18 +701,23 @@ int dpm_sysfs_add(struct device *dev)
if (rc)
goto err_out;
}
-
if (device_can_wakeup(dev)) {
rc = sysfs_merge_group(&dev->kobj, &pm_wakeup_attr_group);
- if (rc) {
- if (pm_runtime_callbacks_present(dev))
- sysfs_unmerge_group(&dev->kobj,
- &pm_runtime_attr_group);
- goto err_out;
- }
+ if (rc)
+ goto err_runtime;
+ }
+ if (dev->power.set_latency_tolerance) {
+ rc = sysfs_merge_group(&dev->kobj,
+ &pm_qos_latency_tolerance_attr_group);
+ if (rc)
+ goto err_wakeup;
}
return 0;
+ err_wakeup:
+ sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
+ err_runtime:
+ sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group);
err_out:
sysfs_remove_group(&dev->kobj, &pm_attr_group);
return rc;
@@ -681,14 +733,14 @@ void wakeup_sysfs_remove(struct device *dev)
sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
}
-int pm_qos_sysfs_add_latency(struct device *dev)
+int pm_qos_sysfs_add_resume_latency(struct device *dev)
{
- return sysfs_merge_group(&dev->kobj, &pm_qos_latency_attr_group);
+ return sysfs_merge_group(&dev->kobj, &pm_qos_resume_latency_attr_group);
}
-void pm_qos_sysfs_remove_latency(struct device *dev)
+void pm_qos_sysfs_remove_resume_latency(struct device *dev)
{
- sysfs_unmerge_group(&dev->kobj, &pm_qos_latency_attr_group);
+ sysfs_unmerge_group(&dev->kobj, &pm_qos_resume_latency_attr_group);
}
int pm_qos_sysfs_add_flags(struct device *dev)
@@ -708,6 +760,7 @@ void rpm_sysfs_remove(struct device *dev)
void dpm_sysfs_remove(struct device *dev)
{
+ sysfs_unmerge_group(&dev->kobj, &pm_qos_latency_tolerance_attr_group);
dev_pm_qos_constraints_destroy(dev);
rpm_sysfs_remove(dev);
sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 33414b1de201..7d1326985bee 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -134,6 +134,8 @@ struct regmap {
/* if set, converts bulk rw to single rw */
bool use_single_rw;
+ /* if set, the device supports multi write mode */
+ bool can_multi_write;
struct rb_root range_tree;
void *selector_work_buf; /* Scratch buffer used for selector */
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index d4dd77134814..29b4128da0b0 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -249,11 +249,12 @@ static int regcache_default_sync(struct regmap *map, unsigned int min,
{
unsigned int reg;
- for (reg = min; reg <= max; reg++) {
+ for (reg = min; reg <= max; reg += map->reg_stride) {
unsigned int val;
int ret;
- if (regmap_volatile(map, reg))
+ if (regmap_volatile(map, reg) ||
+ !regmap_writeable(map, reg))
continue;
ret = regcache_read(map, reg, &val);
@@ -312,10 +313,6 @@ int regcache_sync(struct regmap *map)
/* Apply any patch first */
map->cache_bypass = 1;
for (i = 0; i < map->patch_regs; i++) {
- if (map->patch[i].reg % map->reg_stride) {
- ret = -EINVAL;
- goto out;
- }
ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def);
if (ret != 0) {
dev_err(map->dev, "Failed to write %x = %x: %d\n",
@@ -636,10 +633,10 @@ static int regcache_sync_block_raw_flush(struct regmap *map, const void **data,
if (*data == NULL)
return 0;
- count = cur - base;
+ count = (cur - base) / map->reg_stride;
dev_dbg(map->dev, "Writing %zu bytes for %d registers from 0x%x-0x%x\n",
- count * val_bytes, count, base, cur - 1);
+ count * val_bytes, count, base, cur - map->reg_stride);
map->cache_bypass = 1;
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index c5471cd6ebb7..45d812c0ea77 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -511,7 +511,7 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
debugfs_create_file("range", 0400, map->debugfs,
map, &regmap_reg_ranges_fops);
- if (map->max_register) {
+ if (map->max_register || regmap_readable(map, 0)) {
debugfs_create_file("registers", 0400, map->debugfs,
map, &regmap_map_fops);
debugfs_create_file("access", 0400, map->debugfs,
diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c
index fa6bf5279d28..ebd189529760 100644
--- a/drivers/base/regmap/regmap-i2c.c
+++ b/drivers/base/regmap/regmap-i2c.c
@@ -13,7 +13,6 @@
#include <linux/regmap.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/init.h>
static int regmap_i2c_write(void *context, const void *data, size_t count)
{
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index 82692068d3cb..edf88f20cbce 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -368,8 +368,6 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
if (!d)
return -ENOMEM;
- *data = d;
-
d->status_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
GFP_KERNEL);
if (!d->status_buf)
@@ -506,6 +504,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
goto err_domain;
}
+ *data = d;
+
return 0;
err_domain:
@@ -533,7 +533,7 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
return;
free_irq(irq, d);
- /* We should unmap the domain but... */
+ irq_domain_remove(d->domain);
kfree(d->wake_buf);
kfree(d->mask_buf_def);
kfree(d->mask_buf);
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
index 81f977510775..1e03e7f8bacb 100644
--- a/drivers/base/regmap/regmap-mmio.c
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -18,7 +18,6 @@
#include <linux/clk.h>
#include <linux/err.h>
-#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/regmap.h>
@@ -26,10 +25,47 @@
struct regmap_mmio_context {
void __iomem *regs;
+ unsigned reg_bytes;
unsigned val_bytes;
+ unsigned pad_bytes;
struct clk *clk;
};
+static inline void regmap_mmio_regsize_check(size_t reg_size)
+{
+ switch (reg_size) {
+ case 1:
+ case 2:
+ case 4:
+#ifdef CONFIG_64BIT
+ case 8:
+#endif
+ break;
+ default:
+ BUG();
+ }
+}
+
+static int regmap_mmio_regbits_check(size_t reg_bits)
+{
+ switch (reg_bits) {
+ case 8:
+ case 16:
+ case 32:
+#ifdef CONFIG_64BIT
+ case 64:
+#endif
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static inline void regmap_mmio_count_check(size_t count)
+{
+ BUG_ON(count % 2 != 0);
+}
+
static int regmap_mmio_gather_write(void *context,
const void *reg, size_t reg_size,
const void *val, size_t val_size)
@@ -38,7 +74,7 @@ static int regmap_mmio_gather_write(void *context,
u32 offset;
int ret;
- BUG_ON(reg_size != 4);
+ regmap_mmio_regsize_check(reg_size);
if (!IS_ERR(ctx->clk)) {
ret = clk_enable(ctx->clk);
@@ -81,9 +117,13 @@ static int regmap_mmio_gather_write(void *context,
static int regmap_mmio_write(void *context, const void *data, size_t count)
{
- BUG_ON(count < 4);
+ struct regmap_mmio_context *ctx = context;
+ u32 offset = ctx->reg_bytes + ctx->pad_bytes;
+
+ regmap_mmio_count_check(count);
- return regmap_mmio_gather_write(context, data, 4, data + 4, count - 4);
+ return regmap_mmio_gather_write(context, data, ctx->reg_bytes,
+ data + offset, count - offset);
}
static int regmap_mmio_read(void *context,
@@ -94,7 +134,7 @@ static int regmap_mmio_read(void *context,
u32 offset;
int ret;
- BUG_ON(reg_size != 4);
+ regmap_mmio_regsize_check(reg_size);
if (!IS_ERR(ctx->clk)) {
ret = clk_enable(ctx->clk);
@@ -165,8 +205,9 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
int min_stride;
int ret;
- if (config->reg_bits != 32)
- return ERR_PTR(-EINVAL);
+ ret = regmap_mmio_regbits_check(config->reg_bits);
+ if (ret)
+ return ERR_PTR(ret);
if (config->pad_bits)
return ERR_PTR(-EINVAL);
@@ -209,6 +250,8 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
ctx->regs = regs;
ctx->val_bytes = config->val_bits / 8;
+ ctx->reg_bytes = config->reg_bits / 8;
+ ctx->pad_bytes = config->pad_bits / 8;
ctx->clk = ERR_PTR(-ENODEV);
if (clk_id == NULL)
diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c
index 37f12ae7aada..0eb3097c0d76 100644
--- a/drivers/base/regmap/regmap-spi.c
+++ b/drivers/base/regmap/regmap-spi.c
@@ -12,7 +12,6 @@
#include <linux/regmap.h>
#include <linux/spi/spi.h>
-#include <linux/init.h>
#include <linux/module.h>
#include "internal.h"
diff --git a/drivers/base/regmap/regmap-spmi.c b/drivers/base/regmap/regmap-spmi.c
index ac2391013db1..d7026dc33388 100644
--- a/drivers/base/regmap/regmap-spmi.c
+++ b/drivers/base/regmap/regmap-spmi.c
@@ -22,69 +22,235 @@
#include <linux/module.h>
#include <linux/init.h>
-static int regmap_spmi_read(void *context,
- const void *reg, size_t reg_size,
- void *val, size_t val_size)
+static int regmap_spmi_base_read(void *context,
+ const void *reg, size_t reg_size,
+ void *val, size_t val_size)
{
+ u8 addr = *(u8 *)reg;
+ int err = 0;
+
+ BUG_ON(reg_size != 1);
+
+ while (val_size-- && !err)
+ err = spmi_register_read(context, addr++, val++);
+
+ return err;
+}
+
+static int regmap_spmi_base_gather_write(void *context,
+ const void *reg, size_t reg_size,
+ const void *val, size_t val_size)
+{
+ const u8 *data = val;
+ u8 addr = *(u8 *)reg;
+ int err = 0;
+
+ BUG_ON(reg_size != 1);
+
+ /*
+ * SPMI defines a more bandwidth-efficient 'Register 0 Write' sequence,
+ * use it when possible.
+ */
+ if (addr == 0 && val_size) {
+ err = spmi_register_zero_write(context, *data);
+ if (err)
+ goto err_out;
+
+ data++;
+ addr++;
+ val_size--;
+ }
+
+ while (val_size) {
+ err = spmi_register_write(context, addr, *data);
+ if (err)
+ goto err_out;
+
+ data++;
+ addr++;
+ val_size--;
+ }
+
+err_out:
+ return err;
+}
+
+static int regmap_spmi_base_write(void *context, const void *data,
+ size_t count)
+{
+ BUG_ON(count < 1);
+ return regmap_spmi_base_gather_write(context, data, 1, data + 1,
+ count - 1);
+}
+
+static struct regmap_bus regmap_spmi_base = {
+ .read = regmap_spmi_base_read,
+ .write = regmap_spmi_base_write,
+ .gather_write = regmap_spmi_base_gather_write,
+ .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+ .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
+/**
+ * regmap_init_spmi_base(): Create regmap for the Base register space
+ * @sdev: SPMI device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer to
+ * a struct regmap.
+ */
+struct regmap *regmap_init_spmi_base(struct spmi_device *sdev,
+ const struct regmap_config *config)
+{
+ return regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config);
+}
+EXPORT_SYMBOL_GPL(regmap_init_spmi_base);
+
+/**
+ * devm_regmap_init_spmi_base(): Create managed regmap for Base register space
+ * @sdev: SPMI device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap. The regmap will be automatically freed by the
+ * device management code.
+ */
+struct regmap *devm_regmap_init_spmi_base(struct spmi_device *sdev,
+ const struct regmap_config *config)
+{
+ return devm_regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config);
+}
+EXPORT_SYMBOL_GPL(devm_regmap_init_spmi_base);
+
+static int regmap_spmi_ext_read(void *context,
+ const void *reg, size_t reg_size,
+ void *val, size_t val_size)
+{
+ int err = 0;
+ size_t len;
+ u16 addr;
+
BUG_ON(reg_size != 2);
- return spmi_ext_register_readl(context, *(u16 *)reg,
- val, val_size);
+
+ addr = *(u16 *)reg;
+
+ /*
+ * Split accesses into two to take advantage of the more
+ * bandwidth-efficient 'Extended Register Read' command when possible
+ */
+ while (addr <= 0xFF && val_size) {
+ len = min_t(size_t, val_size, 16);
+
+ err = spmi_ext_register_read(context, addr, val, len);
+ if (err)
+ goto err_out;
+
+ addr += len;
+ val += len;
+ val_size -= len;
+ }
+
+ while (val_size) {
+ len = min_t(size_t, val_size, 8);
+
+ err = spmi_ext_register_readl(context, addr, val, val_size);
+ if (err)
+ goto err_out;
+
+ addr += len;
+ val += len;
+ val_size -= len;
+ }
+
+err_out:
+ return err;
}
-static int regmap_spmi_gather_write(void *context,
- const void *reg, size_t reg_size,
- const void *val, size_t val_size)
+static int regmap_spmi_ext_gather_write(void *context,
+ const void *reg, size_t reg_size,
+ const void *val, size_t val_size)
{
+ int err = 0;
+ size_t len;
+ u16 addr;
+
BUG_ON(reg_size != 2);
- return spmi_ext_register_writel(context, *(u16 *)reg, val, val_size);
+
+ addr = *(u16 *)reg;
+
+ while (addr <= 0xFF && val_size) {
+ len = min_t(size_t, val_size, 16);
+
+ err = spmi_ext_register_write(context, addr, val, len);
+ if (err)
+ goto err_out;
+
+ addr += len;
+ val += len;
+ val_size -= len;
+ }
+
+ while (val_size) {
+ len = min_t(size_t, val_size, 8);
+
+ err = spmi_ext_register_writel(context, addr, val, len);
+ if (err)
+ goto err_out;
+
+ addr += len;
+ val += len;
+ val_size -= len;
+ }
+
+err_out:
+ return err;
}
-static int regmap_spmi_write(void *context, const void *data,
- size_t count)
+static int regmap_spmi_ext_write(void *context, const void *data,
+ size_t count)
{
BUG_ON(count < 2);
- return regmap_spmi_gather_write(context, data, 2, data + 2, count - 2);
+ return regmap_spmi_ext_gather_write(context, data, 2, data + 2,
+ count - 2);
}
-static struct regmap_bus regmap_spmi = {
- .read = regmap_spmi_read,
- .write = regmap_spmi_write,
- .gather_write = regmap_spmi_gather_write,
+static struct regmap_bus regmap_spmi_ext = {
+ .read = regmap_spmi_ext_read,
+ .write = regmap_spmi_ext_write,
+ .gather_write = regmap_spmi_ext_gather_write,
.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
};
/**
- * regmap_init_spmi(): Initialize register map
- *
- * @sdev: Device that will be interacted with
- * @config: Configuration for register map
+ * regmap_init_spmi_ext(): Create regmap for Ext register space
+ * @sdev: Device that will be interacted with
+ * @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap.
*/
-struct regmap *regmap_init_spmi(struct spmi_device *sdev,
- const struct regmap_config *config)
+struct regmap *regmap_init_spmi_ext(struct spmi_device *sdev,
+ const struct regmap_config *config)
{
- return regmap_init(&sdev->dev, &regmap_spmi, sdev, config);
+ return regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config);
}
-EXPORT_SYMBOL_GPL(regmap_init_spmi);
+EXPORT_SYMBOL_GPL(regmap_init_spmi_ext);
/**
- * devm_regmap_init_spmi(): Initialise managed register map
- *
- * @sdev: Device that will be interacted with
- * @config: Configuration for register map
+ * devm_regmap_init_spmi_ext(): Create managed regmap for Ext register space
+ * @sdev: SPMI device that will be interacted with
+ * @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap. The regmap will be automatically freed by the
* device management code.
*/
-struct regmap *devm_regmap_init_spmi(struct spmi_device *sdev,
+struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *sdev,
const struct regmap_config *config)
{
- return devm_regmap_init(&sdev->dev, &regmap_spmi, sdev, config);
+ return devm_regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config);
}
-EXPORT_SYMBOL_GPL(devm_regmap_init_spmi);
+EXPORT_SYMBOL_GPL(devm_regmap_init_spmi_ext);
MODULE_LICENSE("GPL");
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 6a19515f8a45..d0a072463a04 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -380,6 +380,28 @@ static void regmap_range_exit(struct regmap *map)
kfree(map->selector_work_buf);
}
+int regmap_attach_dev(struct device *dev, struct regmap *map,
+ const struct regmap_config *config)
+{
+ struct regmap **m;
+
+ map->dev = dev;
+
+ regmap_debugfs_init(map, config->name);
+
+ /* Add a devres resource for dev_get_regmap() */
+ m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
+ if (!m) {
+ regmap_debugfs_exit(map);
+ return -ENOMEM;
+ }
+ *m = map;
+ devres_add(dev, m);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(regmap_attach_dev);
+
/**
* regmap_init(): Initialise register map
*
@@ -397,7 +419,7 @@ struct regmap *regmap_init(struct device *dev,
void *bus_context,
const struct regmap_config *config)
{
- struct regmap *map, **m;
+ struct regmap *map;
int ret = -EINVAL;
enum regmap_endian reg_endian, val_endian;
int i, j;
@@ -439,6 +461,7 @@ struct regmap *regmap_init(struct device *dev,
else
map->reg_stride = 1;
map->use_single_rw = config->use_single_rw;
+ map->can_multi_write = config->can_multi_write;
map->dev = dev;
map->bus = bus;
map->bus_context = bus_context;
@@ -718,7 +741,7 @@ skip_format_initialization:
new->window_start = range_cfg->window_start;
new->window_len = range_cfg->window_len;
- if (_regmap_range_add(map, new) == false) {
+ if (!_regmap_range_add(map, new)) {
dev_err(map->dev, "Failed to add range %d\n", i);
kfree(new);
goto err_range;
@@ -734,25 +757,18 @@ skip_format_initialization:
}
}
- regmap_debugfs_init(map, config->name);
-
ret = regcache_init(map, config);
if (ret != 0)
goto err_range;
- /* Add a devres resource for dev_get_regmap() */
- m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
- if (!m) {
- ret = -ENOMEM;
- goto err_debugfs;
- }
- *m = map;
- devres_add(dev, m);
+ if (dev)
+ ret = regmap_attach_dev(dev, map, config);
+ if (ret != 0)
+ goto err_regcache;
return map;
-err_debugfs:
- regmap_debugfs_exit(map);
+err_regcache:
regcache_exit(map);
err_range:
regmap_range_exit(map);
@@ -1520,12 +1536,12 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
if (reg % map->reg_stride)
return -EINVAL;
- map->lock(map->lock_arg);
/*
* Some devices don't support bulk write, for
* them we have a series of single write operations.
*/
if (!map->bus || map->use_single_rw) {
+ map->lock(map->lock_arg);
for (i = 0; i < val_count; i++) {
unsigned int ival;
@@ -1554,31 +1570,239 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
if (ret != 0)
goto out;
}
+out:
+ map->unlock(map->lock_arg);
} else {
void *wval;
wval = kmemdup(val, val_count * val_bytes, GFP_KERNEL);
if (!wval) {
- ret = -ENOMEM;
dev_err(map->dev, "Error in memory allocation\n");
- goto out;
+ return -ENOMEM;
}
for (i = 0; i < val_count * val_bytes; i += val_bytes)
map->format.parse_inplace(wval + i);
+ map->lock(map->lock_arg);
ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count);
+ map->unlock(map->lock_arg);
kfree(wval);
}
-out:
- map->unlock(map->lock_arg);
return ret;
}
EXPORT_SYMBOL_GPL(regmap_bulk_write);
/*
+ * _regmap_raw_multi_reg_write()
+ *
+ * the (register,newvalue) pairs in regs have not been formatted, but
+ * they are all in the same page and have been changed to being page
+ * relative. The page register has been written if that was neccessary.
+ */
+static int _regmap_raw_multi_reg_write(struct regmap *map,
+ const struct reg_default *regs,
+ size_t num_regs)
+{
+ int ret;
+ void *buf;
+ int i;
+ u8 *u8;
+ size_t val_bytes = map->format.val_bytes;
+ size_t reg_bytes = map->format.reg_bytes;
+ size_t pad_bytes = map->format.pad_bytes;
+ size_t pair_size = reg_bytes + pad_bytes + val_bytes;
+ size_t len = pair_size * num_regs;
+
+ buf = kzalloc(len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ /* We have to linearise by hand. */
+
+ u8 = buf;
+
+ for (i = 0; i < num_regs; i++) {
+ int reg = regs[i].reg;
+ int val = regs[i].def;
+ trace_regmap_hw_write_start(map->dev, reg, 1);
+ map->format.format_reg(u8, reg, map->reg_shift);
+ u8 += reg_bytes + pad_bytes;
+ map->format.format_val(u8, val, 0);
+ u8 += val_bytes;
+ }
+ u8 = buf;
+ *u8 |= map->write_flag_mask;
+
+ ret = map->bus->write(map->bus_context, buf, len);
+
+ kfree(buf);
+
+ for (i = 0; i < num_regs; i++) {
+ int reg = regs[i].reg;
+ trace_regmap_hw_write_done(map->dev, reg, 1);
+ }
+ return ret;
+}
+
+static unsigned int _regmap_register_page(struct regmap *map,
+ unsigned int reg,
+ struct regmap_range_node *range)
+{
+ unsigned int win_page = (reg - range->range_min) / range->window_len;
+
+ return win_page;
+}
+
+static int _regmap_range_multi_paged_reg_write(struct regmap *map,
+ struct reg_default *regs,
+ size_t num_regs)
+{
+ int ret;
+ int i, n;
+ struct reg_default *base;
+ unsigned int this_page;
+ /*
+ * the set of registers are not neccessarily in order, but
+ * since the order of write must be preserved this algorithm
+ * chops the set each time the page changes
+ */
+ base = regs;
+ for (i = 0, n = 0; i < num_regs; i++, n++) {
+ unsigned int reg = regs[i].reg;
+ struct regmap_range_node *range;
+
+ range = _regmap_range_lookup(map, reg);
+ if (range) {
+ unsigned int win_page = _regmap_register_page(map, reg,
+ range);
+
+ if (i == 0)
+ this_page = win_page;
+ if (win_page != this_page) {
+ this_page = win_page;
+ ret = _regmap_raw_multi_reg_write(map, base, n);
+ if (ret != 0)
+ return ret;
+ base += n;
+ n = 0;
+ }
+ ret = _regmap_select_page(map, &base[n].reg, range, 1);
+ if (ret != 0)
+ return ret;
+ }
+ }
+ if (n > 0)
+ return _regmap_raw_multi_reg_write(map, base, n);
+ return 0;
+}
+
+static int _regmap_multi_reg_write(struct regmap *map,
+ const struct reg_default *regs,
+ size_t num_regs)
+{
+ int i;
+ int ret;
+
+ if (!map->can_multi_write) {
+ for (i = 0; i < num_regs; i++) {
+ ret = _regmap_write(map, regs[i].reg, regs[i].def);
+ if (ret != 0)
+ return ret;
+ }
+ return 0;
+ }
+
+ if (!map->format.parse_inplace)
+ return -EINVAL;
+
+ if (map->writeable_reg)
+ for (i = 0; i < num_regs; i++) {
+ int reg = regs[i].reg;
+ if (!map->writeable_reg(map->dev, reg))
+ return -EINVAL;
+ if (reg % map->reg_stride)
+ return -EINVAL;
+ }
+
+ if (!map->cache_bypass) {
+ for (i = 0; i < num_regs; i++) {
+ unsigned int val = regs[i].def;
+ unsigned int reg = regs[i].reg;
+ ret = regcache_write(map, reg, val);
+ if (ret) {
+ dev_err(map->dev,
+ "Error in caching of register: %x ret: %d\n",
+ reg, ret);
+ return ret;
+ }
+ }
+ if (map->cache_only) {
+ map->cache_dirty = true;
+ return 0;
+ }
+ }
+
+ WARN_ON(!map->bus);
+
+ for (i = 0; i < num_regs; i++) {
+ unsigned int reg = regs[i].reg;
+ struct regmap_range_node *range;
+ range = _regmap_range_lookup(map, reg);
+ if (range) {
+ size_t len = sizeof(struct reg_default)*num_regs;
+ struct reg_default *base = kmemdup(regs, len,
+ GFP_KERNEL);
+ if (!base)
+ return -ENOMEM;
+ ret = _regmap_range_multi_paged_reg_write(map, base,
+ num_regs);
+ kfree(base);
+
+ return ret;
+ }
+ }
+ return _regmap_raw_multi_reg_write(map, regs, num_regs);
+}
+
+/*
* regmap_multi_reg_write(): Write multiple registers to the device
*
+ * where the set of register,value pairs are supplied in any order,
+ * possibly not all in a single range.
+ *
+ * @map: Register map to write to
+ * @regs: Array of structures containing register,value to be written
+ * @num_regs: Number of registers to write
+ *
+ * The 'normal' block write mode will send ultimately send data on the
+ * target bus as R,V1,V2,V3,..,Vn where successively higer registers are
+ * addressed. However, this alternative block multi write mode will send
+ * the data as R1,V1,R2,V2,..,Rn,Vn on the target bus. The target device
+ * must of course support the mode.
+ *
+ * A value of zero will be returned on success, a negative errno will be
+ * returned in error cases.
+ */
+int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs,
+ int num_regs)
+{
+ int ret;
+
+ map->lock(map->lock_arg);
+
+ ret = _regmap_multi_reg_write(map, regs, num_regs);
+
+ map->unlock(map->lock_arg);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_multi_reg_write);
+
+/*
+ * regmap_multi_reg_write_bypassed(): Write multiple registers to the
+ * device but not the cache
+ *
* where the set of register are supplied in any order
*
* @map: Register map to write to
@@ -1592,30 +1816,27 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write);
* A value of zero will be returned on success, a negative errno will
* be returned in error cases.
*/
-int regmap_multi_reg_write(struct regmap *map, struct reg_default *regs,
- int num_regs)
+int regmap_multi_reg_write_bypassed(struct regmap *map,
+ const struct reg_default *regs,
+ int num_regs)
{
- int ret = 0, i;
-
- for (i = 0; i < num_regs; i++) {
- int reg = regs[i].reg;
- if (reg % map->reg_stride)
- return -EINVAL;
- }
+ int ret;
+ bool bypass;
map->lock(map->lock_arg);
- for (i = 0; i < num_regs; i++) {
- ret = _regmap_write(map, regs[i].reg, regs[i].def);
- if (ret != 0)
- goto out;
- }
-out:
+ bypass = map->cache_bypass;
+ map->cache_bypass = true;
+
+ ret = _regmap_multi_reg_write(map, regs, num_regs);
+
+ map->cache_bypass = bypass;
+
map->unlock(map->lock_arg);
return ret;
}
-EXPORT_SYMBOL_GPL(regmap_multi_reg_write);
+EXPORT_SYMBOL_GPL(regmap_multi_reg_write_bypassed);
/**
* regmap_raw_write_async(): Write raw values to one or more registers
@@ -1736,6 +1957,9 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
if (map->cache_only)
return -EBUSY;
+ if (!regmap_readable(map, reg))
+ return -EIO;
+
ret = map->reg_read(context, reg, val);
if (ret == 0) {
#ifdef LOG_DEVICE
@@ -1966,9 +2190,11 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
if (tmp != orig) {
ret = _regmap_write(map, reg, tmp);
- *change = true;
+ if (change)
+ *change = true;
} else {
- *change = false;
+ if (change)
+ *change = false;
}
return ret;
@@ -1987,11 +2213,10 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
int regmap_update_bits(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val)
{
- bool change;
int ret;
map->lock(map->lock_arg);
- ret = _regmap_update_bits(map, reg, mask, val, &change);
+ ret = _regmap_update_bits(map, reg, mask, val, NULL);
map->unlock(map->lock_arg);
return ret;
@@ -2016,14 +2241,13 @@ EXPORT_SYMBOL_GPL(regmap_update_bits);
int regmap_update_bits_async(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val)
{
- bool change;
int ret;
map->lock(map->lock_arg);
map->async = true;
- ret = _regmap_update_bits(map, reg, mask, val, &change);
+ ret = _regmap_update_bits(map, reg, mask, val, NULL);
map->async = false;
@@ -2173,35 +2397,21 @@ EXPORT_SYMBOL_GPL(regmap_async_complete);
* apply them immediately. Typically this is used to apply
* corrections to be applied to the device defaults on startup, such
* as the updates some vendors provide to undocumented registers.
+ *
+ * The caller must ensure that this function cannot be called
+ * concurrently with either itself or regcache_sync().
*/
int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
int num_regs)
{
struct reg_default *p;
- int i, ret;
+ int ret;
bool bypass;
if (WARN_ONCE(num_regs <= 0, "invalid registers number (%d)\n",
num_regs))
return 0;
- map->lock(map->lock_arg);
-
- bypass = map->cache_bypass;
-
- map->cache_bypass = true;
- map->async = true;
-
- /* Write out first; it's useful to apply even if we fail later. */
- for (i = 0; i < num_regs; i++) {
- ret = _regmap_write(map, regs[i].reg, regs[i].def);
- if (ret != 0) {
- dev_err(map->dev, "Failed to write %x = %x: %d\n",
- regs[i].reg, regs[i].def, ret);
- goto out;
- }
- }
-
p = krealloc(map->patch,
sizeof(struct reg_default) * (map->patch_regs + num_regs),
GFP_KERNEL);
@@ -2210,9 +2420,20 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
map->patch = p;
map->patch_regs += num_regs;
} else {
- ret = -ENOMEM;
+ return -ENOMEM;
}
+ map->lock(map->lock_arg);
+
+ bypass = map->cache_bypass;
+
+ map->cache_bypass = true;
+ map->async = true;
+
+ ret = _regmap_multi_reg_write(map, regs, num_regs);
+ if (ret != 0)
+ goto out;
+
out:
map->async = false;
map->cache_bypass = bypass;
@@ -2240,6 +2461,18 @@ int regmap_get_val_bytes(struct regmap *map)
}
EXPORT_SYMBOL_GPL(regmap_get_val_bytes);
+int regmap_parse_val(struct regmap *map, const void *buf,
+ unsigned int *val)
+{
+ if (!map->format.parse_val)
+ return -EINVAL;
+
+ *val = map->format.parse_val(buf);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(regmap_parse_val);
+
static int __init regmap_initcall(void)
{
regmap_debugfs_initcall();
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index 94ffee378f10..ad9d17762664 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -23,7 +23,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
-#include <linux/init.h>
#include <linux/mm.h>
#include <linux/cpu.h>
#include <linux/module.h>
diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c
index 25f9887a35d0..d7f81ad56b8a 100644
--- a/drivers/bcma/driver_gpio.c
+++ b/drivers/bcma/driver_gpio.c
@@ -218,7 +218,14 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
#if IS_BUILTIN(CONFIG_BCMA_HOST_SOC)
chip->to_irq = bcma_gpio_to_irq;
#endif
- chip->ngpio = 16;
+ switch (cc->core->bus->chipinfo.id) {
+ case BCMA_CHIP_ID_BCM5357:
+ chip->ngpio = 32;
+ break;
+ default:
+ chip->ngpio = 16;
+ }
+
/* There is just one SoC in one device and its GPIO addresses should be
* deterministic to address them more easily. The other buses could get
* a random base number. */
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index eb3950113e42..125d84505738 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -6411,12 +6411,12 @@ static bool DAC960_V2_ExecuteUserCommand(DAC960_Controller_T *Controller,
.ScatterGatherSegments[0]
.SegmentByteCount =
CommandMailbox->ControllerInfo.DataTransferSize;
- DAC960_ExecuteCommand(Command);
- while (Controller->V2.NewControllerInformation->PhysicalScanActive)
- {
- DAC960_ExecuteCommand(Command);
- sleep_on_timeout(&Controller->CommandWaitQueue, HZ);
- }
+ while (1) {
+ DAC960_ExecuteCommand(Command);
+ if (!Controller->V2.NewControllerInformation->PhysicalScanActive)
+ break;
+ msleep(1000);
+ }
DAC960_UserCritical("Discovery Completed\n", Controller);
}
}
@@ -7035,18 +7035,16 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request,
ErrorCode = -EFAULT;
break;
}
- while (Controller->V2.HealthStatusBuffer->StatusChangeCounter
- == HealthStatusBuffer.StatusChangeCounter &&
- Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
- == HealthStatusBuffer.NextEventSequenceNumber)
- {
- interruptible_sleep_on_timeout(&Controller->HealthStatusWaitQueue,
- DAC960_MonitoringTimerInterval);
- if (signal_pending(current)) {
- ErrorCode = -EINTR;
- break;
- }
- }
+ ErrorCode = wait_event_interruptible_timeout(Controller->HealthStatusWaitQueue,
+ !(Controller->V2.HealthStatusBuffer->StatusChangeCounter
+ == HealthStatusBuffer.StatusChangeCounter &&
+ Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
+ == HealthStatusBuffer.NextEventSequenceNumber),
+ DAC960_MonitoringTimerInterval);
+ if (ErrorCode == -ERESTARTSYS) {
+ ErrorCode = -EINTR;
+ break;
+ }
if (copy_to_user(GetHealthStatus.HealthStatusBuffer,
Controller->V2.HealthStatusBuffer,
sizeof(DAC960_V2_HealthStatusBuffer_T)))
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 8184451b57c0..422b7d84f686 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -874,7 +874,7 @@ bio_pageinc(struct bio *bio)
/* Non-zero page count for non-head members of
* compound pages is no longer allowed by the kernel.
*/
- page = compound_trans_head(bv.bv_page);
+ page = compound_head(bv.bv_page);
atomic_inc(&page->_count);
}
}
@@ -887,7 +887,7 @@ bio_pagedec(struct bio *bio)
struct bvec_iter iter;
bio_for_each_segment(bv, bio, iter) {
- page = compound_trans_head(bv.bv_page);
+ page = compound_head(bv.bv_page);
atomic_dec(&page->_count);
}
}
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 0e30c6e5492a..96b629e1f0c9 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -68,6 +68,8 @@
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/wait.h>
#include <asm/atafd.h>
#include <asm/atafdreg.h>
@@ -301,7 +303,7 @@ module_param_array(UserSteprate, int, NULL, 0);
/* Synchronization of FDC access. */
static volatile int fdc_busy = 0;
static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
-static DECLARE_WAIT_QUEUE_HEAD(format_wait);
+static DECLARE_COMPLETION(format_wait);
static unsigned long changed_floppies = 0xff, fake_change = 0;
#define CHECK_CHANGE_DELAY HZ/2
@@ -608,7 +610,7 @@ static void fd_error( void )
if (IsFormatting) {
IsFormatting = 0;
FormatError = 1;
- wake_up( &format_wait );
+ complete(&format_wait);
return;
}
@@ -650,9 +652,8 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
DPRINT(("do_format( dr=%d tr=%d he=%d offs=%d )\n",
drive, desc->track, desc->head, desc->sect_offset ));
+ wait_event(fdc_wait, cmpxchg(&fdc_busy, 0, 1) == 0);
local_irq_save(flags);
- while( fdc_busy ) sleep_on( &fdc_wait );
- fdc_busy = 1;
stdma_lock(floppy_irq, NULL);
atari_turnon_irq( IRQ_MFP_FDC ); /* should be already, just to be sure */
local_irq_restore(flags);
@@ -706,7 +707,7 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
ReqSide = desc->head;
do_fd_action( drive );
- sleep_on( &format_wait );
+ wait_for_completion(&format_wait);
redo_fd_request();
return( FormatError ? -EIO : 0 );
@@ -1229,7 +1230,7 @@ static void fd_writetrack_done( int status )
goto err_end;
}
- wake_up( &format_wait );
+ complete(&format_wait);
return;
err_end:
@@ -1497,8 +1498,7 @@ repeat:
void do_fd_request(struct request_queue * q)
{
DPRINT(("do_fd_request for pid %d\n",current->pid));
- while( fdc_busy ) sleep_on( &fdc_wait );
- fdc_busy = 1;
+ wait_event(fdc_wait, cmpxchg(&fdc_busy, 0, 1) == 0);
stdma_lock(floppy_irq, NULL);
atari_disable_irq( IRQ_MFP_FDC );
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 036e8ab86c71..73894ca33956 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -4092,11 +4092,9 @@ static void cciss_interrupt_mode(ctlr_info_t *h)
if (err > 0) {
dev_warn(&h->pdev->dev,
"only %d MSI-X vectors available\n", err);
- goto default_int_mode;
} else {
dev_warn(&h->pdev->dev,
"MSI-X init failed %d\n", err);
- goto default_int_mode;
}
}
if (pci_find_capability(h->pdev, PCI_CAP_ID_MSI)) {
diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c
index a9b13f2cc420..90ae4ba8f9ee 100644
--- a/drivers/block/drbd/drbd_actlog.c
+++ b/drivers/block/drbd/drbd_actlog.c
@@ -95,34 +95,36 @@ struct __packed al_transaction_on_disk {
struct update_odbm_work {
struct drbd_work w;
+ struct drbd_device *device;
unsigned int enr;
};
struct update_al_work {
struct drbd_work w;
+ struct drbd_device *device;
struct completion event;
int err;
};
-void *drbd_md_get_buffer(struct drbd_conf *mdev)
+void *drbd_md_get_buffer(struct drbd_device *device)
{
int r;
- wait_event(mdev->misc_wait,
- (r = atomic_cmpxchg(&mdev->md_io_in_use, 0, 1)) == 0 ||
- mdev->state.disk <= D_FAILED);
+ wait_event(device->misc_wait,
+ (r = atomic_cmpxchg(&device->md_io_in_use, 0, 1)) == 0 ||
+ device->state.disk <= D_FAILED);
- return r ? NULL : page_address(mdev->md_io_page);
+ return r ? NULL : page_address(device->md_io_page);
}
-void drbd_md_put_buffer(struct drbd_conf *mdev)
+void drbd_md_put_buffer(struct drbd_device *device)
{
- if (atomic_dec_and_test(&mdev->md_io_in_use))
- wake_up(&mdev->misc_wait);
+ if (atomic_dec_and_test(&device->md_io_in_use))
+ wake_up(&device->misc_wait);
}
-void wait_until_done_or_force_detached(struct drbd_conf *mdev, struct drbd_backing_dev *bdev,
+void wait_until_done_or_force_detached(struct drbd_device *device, struct drbd_backing_dev *bdev,
unsigned int *done)
{
long dt;
@@ -134,15 +136,15 @@ void wait_until_done_or_force_detached(struct drbd_conf *mdev, struct drbd_backi
if (dt == 0)
dt = MAX_SCHEDULE_TIMEOUT;
- dt = wait_event_timeout(mdev->misc_wait,
- *done || test_bit(FORCE_DETACH, &mdev->flags), dt);
+ dt = wait_event_timeout(device->misc_wait,
+ *done || test_bit(FORCE_DETACH, &device->flags), dt);
if (dt == 0) {
- dev_err(DEV, "meta-data IO operation timed out\n");
- drbd_chk_io_error(mdev, 1, DRBD_FORCE_DETACH);
+ drbd_err(device, "meta-data IO operation timed out\n");
+ drbd_chk_io_error(device, 1, DRBD_FORCE_DETACH);
}
}
-static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
+static int _drbd_md_sync_page_io(struct drbd_device *device,
struct drbd_backing_dev *bdev,
struct page *page, sector_t sector,
int rw, int size)
@@ -150,10 +152,10 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
struct bio *bio;
int err;
- mdev->md_io.done = 0;
- mdev->md_io.error = -ENODEV;
+ device->md_io.done = 0;
+ device->md_io.error = -ENODEV;
- if ((rw & WRITE) && !test_bit(MD_NO_FUA, &mdev->flags))
+ if ((rw & WRITE) && !test_bit(MD_NO_FUA, &device->flags))
rw |= REQ_FUA | REQ_FLUSH;
rw |= REQ_SYNC;
@@ -163,69 +165,69 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
err = -EIO;
if (bio_add_page(bio, page, size, 0) != size)
goto out;
- bio->bi_private = &mdev->md_io;
+ bio->bi_private = &device->md_io;
bio->bi_end_io = drbd_md_io_complete;
bio->bi_rw = rw;
- if (!(rw & WRITE) && mdev->state.disk == D_DISKLESS && mdev->ldev == NULL)
+ if (!(rw & WRITE) && device->state.disk == D_DISKLESS && device->ldev == NULL)
/* special case, drbd_md_read() during drbd_adm_attach(): no get_ldev */
;
- else if (!get_ldev_if_state(mdev, D_ATTACHING)) {
+ else if (!get_ldev_if_state(device, D_ATTACHING)) {
/* Corresponding put_ldev in drbd_md_io_complete() */
- dev_err(DEV, "ASSERT FAILED: get_ldev_if_state() == 1 in _drbd_md_sync_page_io()\n");
+ drbd_err(device, "ASSERT FAILED: get_ldev_if_state() == 1 in _drbd_md_sync_page_io()\n");
err = -ENODEV;
goto out;
}
bio_get(bio); /* one bio_put() is in the completion handler */
- atomic_inc(&mdev->md_io_in_use); /* drbd_md_put_buffer() is in the completion handler */
- if (drbd_insert_fault(mdev, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD))
+ atomic_inc(&device->md_io_in_use); /* drbd_md_put_buffer() is in the completion handler */
+ if (drbd_insert_fault(device, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD))
bio_endio(bio, -EIO);
else
submit_bio(rw, bio);
- wait_until_done_or_force_detached(mdev, bdev, &mdev->md_io.done);
+ wait_until_done_or_force_detached(device, bdev, &device->md_io.done);
if (bio_flagged(bio, BIO_UPTODATE))
- err = mdev->md_io.error;
+ err = device->md_io.error;
out:
bio_put(bio);
return err;
}
-int drbd_md_sync_page_io(struct drbd_conf *mdev, struct drbd_backing_dev *bdev,
+int drbd_md_sync_page_io(struct drbd_device *device, struct drbd_backing_dev *bdev,
sector_t sector, int rw)
{
int err;
- struct page *iop = mdev->md_io_page;
+ struct page *iop = device->md_io_page;
- D_ASSERT(atomic_read(&mdev->md_io_in_use) == 1);
+ D_ASSERT(device, atomic_read(&device->md_io_in_use) == 1);
BUG_ON(!bdev->md_bdev);
- dev_dbg(DEV, "meta_data io: %s [%d]:%s(,%llus,%s) %pS\n",
+ drbd_dbg(device, "meta_data io: %s [%d]:%s(,%llus,%s) %pS\n",
current->comm, current->pid, __func__,
(unsigned long long)sector, (rw & WRITE) ? "WRITE" : "READ",
(void*)_RET_IP_ );
if (sector < drbd_md_first_sector(bdev) ||
sector + 7 > drbd_md_last_sector(bdev))
- dev_alert(DEV, "%s [%d]:%s(,%llus,%s) out of range md access!\n",
+ drbd_alert(device, "%s [%d]:%s(,%llus,%s) out of range md access!\n",
current->comm, current->pid, __func__,
(unsigned long long)sector, (rw & WRITE) ? "WRITE" : "READ");
/* we do all our meta data IO in aligned 4k blocks. */
- err = _drbd_md_sync_page_io(mdev, bdev, iop, sector, rw, 4096);
+ err = _drbd_md_sync_page_io(device, bdev, iop, sector, rw, 4096);
if (err) {
- dev_err(DEV, "drbd_md_sync_page_io(,%llus,%s) failed with error %d\n",
+ drbd_err(device, "drbd_md_sync_page_io(,%llus,%s) failed with error %d\n",
(unsigned long long)sector, (rw & WRITE) ? "WRITE" : "READ", err);
}
return err;
}
-static struct bm_extent *find_active_resync_extent(struct drbd_conf *mdev, unsigned int enr)
+static struct bm_extent *find_active_resync_extent(struct drbd_device *device, unsigned int enr)
{
struct lc_element *tmp;
- tmp = lc_find(mdev->resync, enr/AL_EXT_PER_BM_SECT);
+ tmp = lc_find(device->resync, enr/AL_EXT_PER_BM_SECT);
if (unlikely(tmp != NULL)) {
struct bm_extent *bm_ext = lc_entry(tmp, struct bm_extent, lce);
if (test_bit(BME_NO_WRITES, &bm_ext->flags))
@@ -234,47 +236,48 @@ static struct bm_extent *find_active_resync_extent(struct drbd_conf *mdev, unsig
return NULL;
}
-static struct lc_element *_al_get(struct drbd_conf *mdev, unsigned int enr, bool nonblock)
+static struct lc_element *_al_get(struct drbd_device *device, unsigned int enr, bool nonblock)
{
struct lc_element *al_ext;
struct bm_extent *bm_ext;
int wake;
- spin_lock_irq(&mdev->al_lock);
- bm_ext = find_active_resync_extent(mdev, enr);
+ spin_lock_irq(&device->al_lock);
+ bm_ext = find_active_resync_extent(device, enr);
if (bm_ext) {
wake = !test_and_set_bit(BME_PRIORITY, &bm_ext->flags);
- spin_unlock_irq(&mdev->al_lock);
+ spin_unlock_irq(&device->al_lock);
if (wake)
- wake_up(&mdev->al_wait);
+ wake_up(&device->al_wait);
return NULL;
}
if (nonblock)
- al_ext = lc_try_get(mdev->act_log, enr);
+ al_ext = lc_try_get(device->act_log, enr);
else
- al_ext = lc_get(mdev->act_log, enr);
- spin_unlock_irq(&mdev->al_lock);
+ al_ext = lc_get(device->act_log, enr);
+ spin_unlock_irq(&device->al_lock);
return al_ext;
}
-bool drbd_al_begin_io_fastpath(struct drbd_conf *mdev, struct drbd_interval *i)
+bool drbd_al_begin_io_fastpath(struct drbd_device *device, struct drbd_interval *i)
{
/* for bios crossing activity log extent boundaries,
* we may need to activate two extents in one go */
unsigned first = i->sector >> (AL_EXTENT_SHIFT-9);
unsigned last = i->size == 0 ? first : (i->sector + (i->size >> 9) - 1) >> (AL_EXTENT_SHIFT-9);
- D_ASSERT((unsigned)(last - first) <= 1);
- D_ASSERT(atomic_read(&mdev->local_cnt) > 0);
+ D_ASSERT(device, (unsigned)(last - first) <= 1);
+ D_ASSERT(device, atomic_read(&device->local_cnt) > 0);
/* FIXME figure out a fast path for bios crossing AL extent boundaries */
if (first != last)
return false;
- return _al_get(mdev, first, true);
+ return _al_get(device, first, true);
}
-bool drbd_al_begin_io_prepare(struct drbd_conf *mdev, struct drbd_interval *i)
+static
+bool drbd_al_begin_io_prepare(struct drbd_device *device, struct drbd_interval *i)
{
/* for bios crossing activity log extent boundaries,
* we may need to activate two extents in one go */
@@ -283,20 +286,20 @@ bool drbd_al_begin_io_prepare(struct drbd_conf *mdev, struct drbd_interval *i)
unsigned enr;
bool need_transaction = false;
- D_ASSERT(first <= last);
- D_ASSERT(atomic_read(&mdev->local_cnt) > 0);
+ D_ASSERT(device, first <= last);
+ D_ASSERT(device, atomic_read(&device->local_cnt) > 0);
for (enr = first; enr <= last; enr++) {
struct lc_element *al_ext;
- wait_event(mdev->al_wait,
- (al_ext = _al_get(mdev, enr, false)) != NULL);
+ wait_event(device->al_wait,
+ (al_ext = _al_get(device, enr, false)) != NULL);
if (al_ext->lc_number != enr)
need_transaction = true;
}
return need_transaction;
}
-static int al_write_transaction(struct drbd_conf *mdev, bool delegate);
+static int al_write_transaction(struct drbd_device *device, bool delegate);
/* When called through generic_make_request(), we must delegate
* activity log I/O to the worker thread: a further request
@@ -310,58 +313,58 @@ static int al_write_transaction(struct drbd_conf *mdev, bool delegate);
/*
* @delegate: delegate activity log I/O to the worker thread
*/
-void drbd_al_begin_io_commit(struct drbd_conf *mdev, bool delegate)
+void drbd_al_begin_io_commit(struct drbd_device *device, bool delegate)
{
bool locked = false;
- BUG_ON(delegate && current == mdev->tconn->worker.task);
+ BUG_ON(delegate && current == first_peer_device(device)->connection->worker.task);
/* Serialize multiple transactions.
* This uses test_and_set_bit, memory barrier is implicit.
*/
- wait_event(mdev->al_wait,
- mdev->act_log->pending_changes == 0 ||
- (locked = lc_try_lock_for_transaction(mdev->act_log)));
+ wait_event(device->al_wait,
+ device->act_log->pending_changes == 0 ||
+ (locked = lc_try_lock_for_transaction(device->act_log)));
if (locked) {
/* Double check: it may have been committed by someone else,
* while we have been waiting for the lock. */
- if (mdev->act_log->pending_changes) {
+ if (device->act_log->pending_changes) {
bool write_al_updates;
rcu_read_lock();
- write_al_updates = rcu_dereference(mdev->ldev->disk_conf)->al_updates;
+ write_al_updates = rcu_dereference(device->ldev->disk_conf)->al_updates;
rcu_read_unlock();
if (write_al_updates)
- al_write_transaction(mdev, delegate);
- spin_lock_irq(&mdev->al_lock);
+ al_write_transaction(device, delegate);
+ spin_lock_irq(&device->al_lock);
/* FIXME
if (err)
we need an "lc_cancel" here;
*/
- lc_committed(mdev->act_log);
- spin_unlock_irq(&mdev->al_lock);
+ lc_committed(device->act_log);
+ spin_unlock_irq(&device->al_lock);
}
- lc_unlock(mdev->act_log);
- wake_up(&mdev->al_wait);
+ lc_unlock(device->act_log);
+ wake_up(&device->al_wait);
}
}
/*
* @delegate: delegate activity log I/O to the worker thread
*/
-void drbd_al_begin_io(struct drbd_conf *mdev, struct drbd_interval *i, bool delegate)
+void drbd_al_begin_io(struct drbd_device *device, struct drbd_interval *i, bool delegate)
{
- BUG_ON(delegate && current == mdev->tconn->worker.task);
+ BUG_ON(delegate && current == first_peer_device(device)->connection->worker.task);
- if (drbd_al_begin_io_prepare(mdev, i))
- drbd_al_begin_io_commit(mdev, delegate);
+ if (drbd_al_begin_io_prepare(device, i))
+ drbd_al_begin_io_commit(device, delegate);
}
-int drbd_al_begin_io_nonblock(struct drbd_conf *mdev, struct drbd_interval *i)
+int drbd_al_begin_io_nonblock(struct drbd_device *device, struct drbd_interval *i)
{
- struct lru_cache *al = mdev->act_log;
+ struct lru_cache *al = device->act_log;
/* for bios crossing activity log extent boundaries,
* we may need to activate two extents in one go */
unsigned first = i->sector >> (AL_EXTENT_SHIFT-9);
@@ -370,7 +373,7 @@ int drbd_al_begin_io_nonblock(struct drbd_conf *mdev, struct drbd_interval *i)
unsigned available_update_slots;
unsigned enr;
- D_ASSERT(first <= last);
+ D_ASSERT(device, first <= last);
nr_al_extents = 1 + last - first; /* worst case: all touched extends are cold. */
available_update_slots = min(al->nr_elements - al->used,
@@ -385,7 +388,7 @@ int drbd_al_begin_io_nonblock(struct drbd_conf *mdev, struct drbd_interval *i)
/* Is resync active in this area? */
for (enr = first; enr <= last; enr++) {
struct lc_element *tmp;
- tmp = lc_find(mdev->resync, enr/AL_EXT_PER_BM_SECT);
+ tmp = lc_find(device->resync, enr/AL_EXT_PER_BM_SECT);
if (unlikely(tmp != NULL)) {
struct bm_extent *bm_ext = lc_entry(tmp, struct bm_extent, lce);
if (test_bit(BME_NO_WRITES, &bm_ext->flags)) {
@@ -401,14 +404,14 @@ int drbd_al_begin_io_nonblock(struct drbd_conf *mdev, struct drbd_interval *i)
* this has to be successful. */
for (enr = first; enr <= last; enr++) {
struct lc_element *al_ext;
- al_ext = lc_get_cumulative(mdev->act_log, enr);
+ al_ext = lc_get_cumulative(device->act_log, enr);
if (!al_ext)
- dev_info(DEV, "LOGIC BUG for enr=%u\n", enr);
+ drbd_info(device, "LOGIC BUG for enr=%u\n", enr);
}
return 0;
}
-void drbd_al_complete_io(struct drbd_conf *mdev, struct drbd_interval *i)
+void drbd_al_complete_io(struct drbd_device *device, struct drbd_interval *i)
{
/* for bios crossing activity log extent boundaries,
* we may need to activate two extents in one go */
@@ -418,19 +421,19 @@ void drbd_al_complete_io(struct drbd_conf *mdev, struct drbd_interval *i)
struct lc_element *extent;
unsigned long flags;
- D_ASSERT(first <= last);
- spin_lock_irqsave(&mdev->al_lock, flags);
+ D_ASSERT(device, first <= last);
+ spin_lock_irqsave(&device->al_lock, flags);
for (enr = first; enr <= last; enr++) {
- extent = lc_find(mdev->act_log, enr);
+ extent = lc_find(device->act_log, enr);
if (!extent) {
- dev_err(DEV, "al_complete_io() called on inactive extent %u\n", enr);
+ drbd_err(device, "al_complete_io() called on inactive extent %u\n", enr);
continue;
}
- lc_put(mdev->act_log, extent);
+ lc_put(device->act_log, extent);
}
- spin_unlock_irqrestore(&mdev->al_lock, flags);
- wake_up(&mdev->al_wait);
+ spin_unlock_irqrestore(&device->al_lock, flags);
+ wake_up(&device->al_wait);
}
#if (PAGE_SHIFT + 3) < (AL_EXTENT_SHIFT - BM_BLOCK_SHIFT)
@@ -460,13 +463,13 @@ static unsigned int rs_extent_to_bm_page(unsigned int rs_enr)
(BM_EXT_SHIFT - BM_BLOCK_SHIFT));
}
-static sector_t al_tr_number_to_on_disk_sector(struct drbd_conf *mdev)
+static sector_t al_tr_number_to_on_disk_sector(struct drbd_device *device)
{
- const unsigned int stripes = mdev->ldev->md.al_stripes;
- const unsigned int stripe_size_4kB = mdev->ldev->md.al_stripe_size_4k;
+ const unsigned int stripes = device->ldev->md.al_stripes;
+ const unsigned int stripe_size_4kB = device->ldev->md.al_stripe_size_4k;
/* transaction number, modulo on-disk ring buffer wrap around */
- unsigned int t = mdev->al_tr_number % (mdev->ldev->md.al_size_4k);
+ unsigned int t = device->al_tr_number % (device->ldev->md.al_size_4k);
/* ... to aligned 4k on disk block */
t = ((t % stripes) * stripe_size_4kB) + t/stripes;
@@ -475,11 +478,11 @@ static sector_t al_tr_number_to_on_disk_sector(struct drbd_conf *mdev)
t *= 8;
/* ... plus offset to the on disk position */
- return mdev->ldev->md.md_offset + mdev->ldev->md.al_offset + t;
+ return device->ldev->md.md_offset + device->ldev->md.al_offset + t;
}
static int
-_al_write_transaction(struct drbd_conf *mdev)
+_al_write_transaction(struct drbd_device *device)
{
struct al_transaction_on_disk *buffer;
struct lc_element *e;
@@ -489,31 +492,31 @@ _al_write_transaction(struct drbd_conf *mdev)
unsigned crc = 0;
int err = 0;
- if (!get_ldev(mdev)) {
- dev_err(DEV, "disk is %s, cannot start al transaction\n",
- drbd_disk_str(mdev->state.disk));
+ if (!get_ldev(device)) {
+ drbd_err(device, "disk is %s, cannot start al transaction\n",
+ drbd_disk_str(device->state.disk));
return -EIO;
}
/* The bitmap write may have failed, causing a state change. */
- if (mdev->state.disk < D_INCONSISTENT) {
- dev_err(DEV,
+ if (device->state.disk < D_INCONSISTENT) {
+ drbd_err(device,
"disk is %s, cannot write al transaction\n",
- drbd_disk_str(mdev->state.disk));
- put_ldev(mdev);
+ drbd_disk_str(device->state.disk));
+ put_ldev(device);
return -EIO;
}
- buffer = drbd_md_get_buffer(mdev); /* protects md_io_buffer, al_tr_cycle, ... */
+ buffer = drbd_md_get_buffer(device); /* protects md_io_buffer, al_tr_cycle, ... */
if (!buffer) {
- dev_err(DEV, "disk failed while waiting for md_io buffer\n");
- put_ldev(mdev);
+ drbd_err(device, "disk failed while waiting for md_io buffer\n");
+ put_ldev(device);
return -ENODEV;
}
memset(buffer, 0, sizeof(*buffer));
buffer->magic = cpu_to_be32(DRBD_AL_MAGIC);
- buffer->tr_number = cpu_to_be32(mdev->al_tr_number);
+ buffer->tr_number = cpu_to_be32(device->al_tr_number);
i = 0;
@@ -521,8 +524,8 @@ _al_write_transaction(struct drbd_conf *mdev)
* once we set the LC_LOCKED -- from drbd_al_begin_io(),
* lc_try_lock_for_transaction() --, someone may still
* be in the process of changing it. */
- spin_lock_irq(&mdev->al_lock);
- list_for_each_entry(e, &mdev->act_log->to_be_changed, list) {
+ spin_lock_irq(&device->al_lock);
+ list_for_each_entry(e, &device->act_log->to_be_changed, list) {
if (i == AL_UPDATES_PER_TRANSACTION) {
i++;
break;
@@ -530,11 +533,11 @@ _al_write_transaction(struct drbd_conf *mdev)
buffer->update_slot_nr[i] = cpu_to_be16(e->lc_index);
buffer->update_extent_nr[i] = cpu_to_be32(e->lc_new_number);
if (e->lc_number != LC_FREE)
- drbd_bm_mark_for_writeout(mdev,
+ drbd_bm_mark_for_writeout(device,
al_extent_to_bm_page(e->lc_number));
i++;
}
- spin_unlock_irq(&mdev->al_lock);
+ spin_unlock_irq(&device->al_lock);
BUG_ON(i > AL_UPDATES_PER_TRANSACTION);
buffer->n_updates = cpu_to_be16(i);
@@ -543,48 +546,48 @@ _al_write_transaction(struct drbd_conf *mdev)
buffer->update_extent_nr[i] = cpu_to_be32(LC_FREE);
}
- buffer->context_size = cpu_to_be16(mdev->act_log->nr_elements);
- buffer->context_start_slot_nr = cpu_to_be16(mdev->al_tr_cycle);
+ buffer->context_size = cpu_to_be16(device->act_log->nr_elements);
+ buffer->context_start_slot_nr = cpu_to_be16(device->al_tr_cycle);
mx = min_t(int, AL_CONTEXT_PER_TRANSACTION,
- mdev->act_log->nr_elements - mdev->al_tr_cycle);
+ device->act_log->nr_elements - device->al_tr_cycle);
for (i = 0; i < mx; i++) {
- unsigned idx = mdev->al_tr_cycle + i;
- extent_nr = lc_element_by_index(mdev->act_log, idx)->lc_number;
+ unsigned idx = device->al_tr_cycle + i;
+ extent_nr = lc_element_by_index(device->act_log, idx)->lc_number;
buffer->context[i] = cpu_to_be32(extent_nr);
}
for (; i < AL_CONTEXT_PER_TRANSACTION; i++)
buffer->context[i] = cpu_to_be32(LC_FREE);
- mdev->al_tr_cycle += AL_CONTEXT_PER_TRANSACTION;
- if (mdev->al_tr_cycle >= mdev->act_log->nr_elements)
- mdev->al_tr_cycle = 0;
+ device->al_tr_cycle += AL_CONTEXT_PER_TRANSACTION;
+ if (device->al_tr_cycle >= device->act_log->nr_elements)
+ device->al_tr_cycle = 0;
- sector = al_tr_number_to_on_disk_sector(mdev);
+ sector = al_tr_number_to_on_disk_sector(device);
crc = crc32c(0, buffer, 4096);
buffer->crc32c = cpu_to_be32(crc);
- if (drbd_bm_write_hinted(mdev))
+ if (drbd_bm_write_hinted(device))
err = -EIO;
else {
bool write_al_updates;
rcu_read_lock();
- write_al_updates = rcu_dereference(mdev->ldev->disk_conf)->al_updates;
+ write_al_updates = rcu_dereference(device->ldev->disk_conf)->al_updates;
rcu_read_unlock();
if (write_al_updates) {
- if (drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) {
+ if (drbd_md_sync_page_io(device, device->ldev, sector, WRITE)) {
err = -EIO;
- drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
+ drbd_chk_io_error(device, 1, DRBD_META_IO_ERROR);
} else {
- mdev->al_tr_number++;
- mdev->al_writ_cnt++;
+ device->al_tr_number++;
+ device->al_writ_cnt++;
}
}
}
- drbd_md_put_buffer(mdev);
- put_ldev(mdev);
+ drbd_md_put_buffer(device);
+ put_ldev(device);
return err;
}
@@ -593,10 +596,10 @@ _al_write_transaction(struct drbd_conf *mdev)
static int w_al_write_transaction(struct drbd_work *w, int unused)
{
struct update_al_work *aw = container_of(w, struct update_al_work, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_device *device = aw->device;
int err;
- err = _al_write_transaction(mdev);
+ err = _al_write_transaction(device);
aw->err = err;
complete(&aw->event);
@@ -606,63 +609,64 @@ static int w_al_write_transaction(struct drbd_work *w, int unused)
/* Calls from worker context (see w_restart_disk_io()) need to write the
transaction directly. Others came through generic_make_request(),
those need to delegate it to the worker. */
-static int al_write_transaction(struct drbd_conf *mdev, bool delegate)
+static int al_write_transaction(struct drbd_device *device, bool delegate)
{
if (delegate) {
struct update_al_work al_work;
init_completion(&al_work.event);
al_work.w.cb = w_al_write_transaction;
- al_work.w.mdev = mdev;
- drbd_queue_work_front(&mdev->tconn->sender_work, &al_work.w);
+ al_work.device = device;
+ drbd_queue_work_front(&first_peer_device(device)->connection->sender_work,
+ &al_work.w);
wait_for_completion(&al_work.event);
return al_work.err;
} else
- return _al_write_transaction(mdev);
+ return _al_write_transaction(device);
}
-static int _try_lc_del(struct drbd_conf *mdev, struct lc_element *al_ext)
+static int _try_lc_del(struct drbd_device *device, struct lc_element *al_ext)
{
int rv;
- spin_lock_irq(&mdev->al_lock);
+ spin_lock_irq(&device->al_lock);
rv = (al_ext->refcnt == 0);
if (likely(rv))
- lc_del(mdev->act_log, al_ext);
- spin_unlock_irq(&mdev->al_lock);
+ lc_del(device->act_log, al_ext);
+ spin_unlock_irq(&device->al_lock);
return rv;
}
/**
* drbd_al_shrink() - Removes all active extents form the activity log
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Removes all active extents form the activity log, waiting until
* the reference count of each entry dropped to 0 first, of course.
*
- * You need to lock mdev->act_log with lc_try_lock() / lc_unlock()
+ * You need to lock device->act_log with lc_try_lock() / lc_unlock()
*/
-void drbd_al_shrink(struct drbd_conf *mdev)
+void drbd_al_shrink(struct drbd_device *device)
{
struct lc_element *al_ext;
int i;
- D_ASSERT(test_bit(__LC_LOCKED, &mdev->act_log->flags));
+ D_ASSERT(device, test_bit(__LC_LOCKED, &device->act_log->flags));
- for (i = 0; i < mdev->act_log->nr_elements; i++) {
- al_ext = lc_element_by_index(mdev->act_log, i);
+ for (i = 0; i < device->act_log->nr_elements; i++) {
+ al_ext = lc_element_by_index(device->act_log, i);
if (al_ext->lc_number == LC_FREE)
continue;
- wait_event(mdev->al_wait, _try_lc_del(mdev, al_ext));
+ wait_event(device->al_wait, _try_lc_del(device, al_ext));
}
- wake_up(&mdev->al_wait);
+ wake_up(&device->al_wait);
}
-int drbd_initialize_al(struct drbd_conf *mdev, void *buffer)
+int drbd_initialize_al(struct drbd_device *device, void *buffer)
{
struct al_transaction_on_disk *al = buffer;
- struct drbd_md *md = &mdev->ldev->md;
+ struct drbd_md *md = &device->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;
@@ -673,7 +677,7 @@ int drbd_initialize_al(struct drbd_conf *mdev, void *buffer)
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);
+ int err = drbd_md_sync_page_io(device, device->ldev, al_base + i * 8, WRITE);
if (err)
return err;
}
@@ -683,32 +687,32 @@ int drbd_initialize_al(struct drbd_conf *mdev, void *buffer)
static int w_update_odbm(struct drbd_work *w, int unused)
{
struct update_odbm_work *udw = container_of(w, struct update_odbm_work, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_device *device = udw->device;
struct sib_info sib = { .sib_reason = SIB_SYNC_PROGRESS, };
- if (!get_ldev(mdev)) {
+ if (!get_ldev(device)) {
if (__ratelimit(&drbd_ratelimit_state))
- dev_warn(DEV, "Can not update on disk bitmap, local IO disabled.\n");
+ drbd_warn(device, "Can not update on disk bitmap, local IO disabled.\n");
kfree(udw);
return 0;
}
- drbd_bm_write_page(mdev, rs_extent_to_bm_page(udw->enr));
- put_ldev(mdev);
+ drbd_bm_write_page(device, rs_extent_to_bm_page(udw->enr));
+ put_ldev(device);
kfree(udw);
- if (drbd_bm_total_weight(mdev) <= mdev->rs_failed) {
- switch (mdev->state.conn) {
+ if (drbd_bm_total_weight(device) <= device->rs_failed) {
+ switch (device->state.conn) {
case C_SYNC_SOURCE: case C_SYNC_TARGET:
case C_PAUSED_SYNC_S: case C_PAUSED_SYNC_T:
- drbd_resync_finished(mdev);
+ drbd_resync_finished(device);
default:
/* nothing to do */
break;
}
}
- drbd_bcast_event(mdev, &sib);
+ drbd_bcast_event(device, &sib);
return 0;
}
@@ -720,7 +724,7 @@ static int w_update_odbm(struct drbd_work *w, int unused)
*
* TODO will be obsoleted once we have a caching lru of the on disk bitmap
*/
-static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector,
+static void drbd_try_clear_on_disk_bm(struct drbd_device *device, sector_t sector,
int count, int success)
{
struct lc_element *e;
@@ -728,13 +732,13 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector,
unsigned int enr;
- D_ASSERT(atomic_read(&mdev->local_cnt));
+ D_ASSERT(device, atomic_read(&device->local_cnt));
/* I simply assume that a sector/size pair never crosses
* a 16 MB extent border. (Currently this is true...) */
enr = BM_SECT_TO_EXT(sector);
- e = lc_get(mdev->resync, enr);
+ e = lc_get(device->resync, enr);
if (e) {
struct bm_extent *ext = lc_entry(e, struct bm_extent, lce);
if (ext->lce.lc_number == enr) {
@@ -743,12 +747,12 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector,
else
ext->rs_failed += count;
if (ext->rs_left < ext->rs_failed) {
- dev_warn(DEV, "BAD! sector=%llus enr=%u rs_left=%d "
+ drbd_warn(device, "BAD! sector=%llus enr=%u rs_left=%d "
"rs_failed=%d count=%d cstate=%s\n",
(unsigned long long)sector,
ext->lce.lc_number, ext->rs_left,
ext->rs_failed, count,
- drbd_conn_str(mdev->state.conn));
+ drbd_conn_str(device->state.conn));
/* We don't expect to be able to clear more bits
* than have been set when we originally counted
@@ -756,7 +760,7 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector,
* Whatever the reason (disconnect during resync,
* delayed local completion of an application write),
* try to fix it up by recounting here. */
- ext->rs_left = drbd_bm_e_weight(mdev, enr);
+ ext->rs_left = drbd_bm_e_weight(device, enr);
}
} else {
/* Normally this element should be in the cache,
@@ -765,16 +769,16 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector,
* But maybe an application write finished, and we set
* something outside the resync lru_cache in sync.
*/
- int rs_left = drbd_bm_e_weight(mdev, enr);
+ int rs_left = drbd_bm_e_weight(device, enr);
if (ext->flags != 0) {
- dev_warn(DEV, "changing resync lce: %d[%u;%02lx]"
+ drbd_warn(device, "changing resync lce: %d[%u;%02lx]"
" -> %d[%u;00]\n",
ext->lce.lc_number, ext->rs_left,
ext->flags, enr, rs_left);
ext->flags = 0;
}
if (ext->rs_failed) {
- dev_warn(DEV, "Kicking resync_lru element enr=%u "
+ drbd_warn(device, "Kicking resync_lru element enr=%u "
"out with rs_failed=%d\n",
ext->lce.lc_number, ext->rs_failed);
}
@@ -782,9 +786,9 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector,
ext->rs_failed = success ? 0 : count;
/* we don't keep a persistent log of the resync lru,
* we can commit any change right away. */
- lc_committed(mdev->resync);
+ lc_committed(device->resync);
}
- lc_put(mdev->resync, &ext->lce);
+ lc_put(device->resync, &ext->lce);
/* no race, we are within the al_lock! */
if (ext->rs_left == ext->rs_failed) {
@@ -794,32 +798,33 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector,
if (udw) {
udw->enr = ext->lce.lc_number;
udw->w.cb = w_update_odbm;
- udw->w.mdev = mdev;
- drbd_queue_work_front(&mdev->tconn->sender_work, &udw->w);
+ udw->device = device;
+ drbd_queue_work_front(&first_peer_device(device)->connection->sender_work,
+ &udw->w);
} else {
- dev_warn(DEV, "Could not kmalloc an udw\n");
+ drbd_warn(device, "Could not kmalloc an udw\n");
}
}
} else {
- dev_err(DEV, "lc_get() failed! locked=%d/%d flags=%lu\n",
- mdev->resync_locked,
- mdev->resync->nr_elements,
- mdev->resync->flags);
+ drbd_err(device, "lc_get() failed! locked=%d/%d flags=%lu\n",
+ device->resync_locked,
+ device->resync->nr_elements,
+ device->resync->flags);
}
}
-void drbd_advance_rs_marks(struct drbd_conf *mdev, unsigned long still_to_go)
+void drbd_advance_rs_marks(struct drbd_device *device, unsigned long still_to_go)
{
unsigned long now = jiffies;
- unsigned long last = mdev->rs_mark_time[mdev->rs_last_mark];
- int next = (mdev->rs_last_mark + 1) % DRBD_SYNC_MARKS;
+ unsigned long last = device->rs_mark_time[device->rs_last_mark];
+ int next = (device->rs_last_mark + 1) % DRBD_SYNC_MARKS;
if (time_after_eq(now, last + DRBD_SYNC_MARK_STEP)) {
- if (mdev->rs_mark_left[mdev->rs_last_mark] != still_to_go &&
- mdev->state.conn != C_PAUSED_SYNC_T &&
- mdev->state.conn != C_PAUSED_SYNC_S) {
- mdev->rs_mark_time[next] = now;
- mdev->rs_mark_left[next] = still_to_go;
- mdev->rs_last_mark = next;
+ if (device->rs_mark_left[device->rs_last_mark] != still_to_go &&
+ device->state.conn != C_PAUSED_SYNC_T &&
+ device->state.conn != C_PAUSED_SYNC_S) {
+ device->rs_mark_time[next] = now;
+ device->rs_mark_left[next] = still_to_go;
+ device->rs_last_mark = next;
}
}
}
@@ -831,7 +836,7 @@ void drbd_advance_rs_marks(struct drbd_conf *mdev, unsigned long still_to_go)
* called by worker on C_SYNC_TARGET and receiver on SyncSource.
*
*/
-void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size,
+void __drbd_set_in_sync(struct drbd_device *device, sector_t sector, int size,
const char *file, const unsigned int line)
{
/* Is called from worker and receiver context _only_ */
@@ -842,15 +847,15 @@ void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size,
unsigned long flags;
if (size <= 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_BIO_SIZE) {
- dev_err(DEV, "drbd_set_in_sync: sector=%llus size=%d nonsense!\n",
+ drbd_err(device, "drbd_set_in_sync: sector=%llus size=%d nonsense!\n",
(unsigned long long)sector, size);
return;
}
- if (!get_ldev(mdev))
+ if (!get_ldev(device))
return; /* no disk, no metadata, no bitmap to clear bits in */
- nr_sectors = drbd_get_capacity(mdev->this_bdev);
+ nr_sectors = drbd_get_capacity(device->this_bdev);
esector = sector + (size >> 9) - 1;
if (!expect(sector < nr_sectors))
@@ -878,21 +883,21 @@ void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size,
* ok, (capacity & 7) != 0 sometimes, but who cares...
* we count rs_{total,left} in bits, not sectors.
*/
- count = drbd_bm_clear_bits(mdev, sbnr, ebnr);
+ count = drbd_bm_clear_bits(device, sbnr, ebnr);
if (count) {
- drbd_advance_rs_marks(mdev, drbd_bm_total_weight(mdev));
- spin_lock_irqsave(&mdev->al_lock, flags);
- drbd_try_clear_on_disk_bm(mdev, sector, count, true);
- spin_unlock_irqrestore(&mdev->al_lock, flags);
+ drbd_advance_rs_marks(device, drbd_bm_total_weight(device));
+ spin_lock_irqsave(&device->al_lock, flags);
+ drbd_try_clear_on_disk_bm(device, sector, count, true);
+ spin_unlock_irqrestore(&device->al_lock, flags);
/* just wake_up unconditional now, various lc_chaged(),
* lc_put() in drbd_try_clear_on_disk_bm(). */
wake_up = 1;
}
out:
- put_ldev(mdev);
+ put_ldev(device);
if (wake_up)
- wake_up(&mdev->al_wait);
+ wake_up(&device->al_wait);
}
/*
@@ -903,7 +908,7 @@ out:
* called by tl_clear and drbd_send_dblock (==drbd_make_request).
* so this can be _any_ process.
*/
-int __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, int size,
+int __drbd_set_out_of_sync(struct drbd_device *device, sector_t sector, int size,
const char *file, const unsigned int line)
{
unsigned long sbnr, ebnr, flags;
@@ -916,15 +921,15 @@ int __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, int size,
return 0;
if (size < 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_BIO_SIZE) {
- dev_err(DEV, "sector: %llus, size: %d\n",
+ drbd_err(device, "sector: %llus, size: %d\n",
(unsigned long long)sector, size);
return 0;
}
- if (!get_ldev(mdev))
+ if (!get_ldev(device))
return 0; /* no disk, no metadata, no bitmap to set bits in */
- nr_sectors = drbd_get_capacity(mdev->this_bdev);
+ nr_sectors = drbd_get_capacity(device->this_bdev);
esector = sector + (size >> 9) - 1;
if (!expect(sector < nr_sectors))
@@ -939,55 +944,55 @@ int __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, int size,
/* ok, (capacity & 7) != 0 sometimes, but who cares...
* we count rs_{total,left} in bits, not sectors. */
- spin_lock_irqsave(&mdev->al_lock, flags);
- count = drbd_bm_set_bits(mdev, sbnr, ebnr);
+ spin_lock_irqsave(&device->al_lock, flags);
+ count = drbd_bm_set_bits(device, sbnr, ebnr);
enr = BM_SECT_TO_EXT(sector);
- e = lc_find(mdev->resync, enr);
+ e = lc_find(device->resync, enr);
if (e)
lc_entry(e, struct bm_extent, lce)->rs_left += count;
- spin_unlock_irqrestore(&mdev->al_lock, flags);
+ spin_unlock_irqrestore(&device->al_lock, flags);
out:
- put_ldev(mdev);
+ put_ldev(device);
return count;
}
static
-struct bm_extent *_bme_get(struct drbd_conf *mdev, unsigned int enr)
+struct bm_extent *_bme_get(struct drbd_device *device, unsigned int enr)
{
struct lc_element *e;
struct bm_extent *bm_ext;
int wakeup = 0;
unsigned long rs_flags;
- spin_lock_irq(&mdev->al_lock);
- if (mdev->resync_locked > mdev->resync->nr_elements/2) {
- spin_unlock_irq(&mdev->al_lock);
+ spin_lock_irq(&device->al_lock);
+ if (device->resync_locked > device->resync->nr_elements/2) {
+ spin_unlock_irq(&device->al_lock);
return NULL;
}
- e = lc_get(mdev->resync, enr);
+ e = lc_get(device->resync, enr);
bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
if (bm_ext) {
if (bm_ext->lce.lc_number != enr) {
- bm_ext->rs_left = drbd_bm_e_weight(mdev, enr);
+ bm_ext->rs_left = drbd_bm_e_weight(device, enr);
bm_ext->rs_failed = 0;
- lc_committed(mdev->resync);
+ lc_committed(device->resync);
wakeup = 1;
}
if (bm_ext->lce.refcnt == 1)
- mdev->resync_locked++;
+ device->resync_locked++;
set_bit(BME_NO_WRITES, &bm_ext->flags);
}
- rs_flags = mdev->resync->flags;
- spin_unlock_irq(&mdev->al_lock);
+ rs_flags = device->resync->flags;
+ spin_unlock_irq(&device->al_lock);
if (wakeup)
- wake_up(&mdev->al_wait);
+ wake_up(&device->al_wait);
if (!bm_ext) {
if (rs_flags & LC_STARVING)
- dev_warn(DEV, "Have to wait for element"
+ drbd_warn(device, "Have to wait for element"
" (resync LRU too small?)\n");
BUG_ON(rs_flags & LC_LOCKED);
}
@@ -995,25 +1000,25 @@ struct bm_extent *_bme_get(struct drbd_conf *mdev, unsigned int enr)
return bm_ext;
}
-static int _is_in_al(struct drbd_conf *mdev, unsigned int enr)
+static int _is_in_al(struct drbd_device *device, unsigned int enr)
{
int rv;
- spin_lock_irq(&mdev->al_lock);
- rv = lc_is_used(mdev->act_log, enr);
- spin_unlock_irq(&mdev->al_lock);
+ spin_lock_irq(&device->al_lock);
+ rv = lc_is_used(device->act_log, enr);
+ spin_unlock_irq(&device->al_lock);
return rv;
}
/**
* drbd_rs_begin_io() - Gets an extent in the resync LRU cache and sets it to BME_LOCKED
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @sector: The sector number.
*
* This functions sleeps on al_wait. Returns 0 on success, -EINTR if interrupted.
*/
-int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector)
+int drbd_rs_begin_io(struct drbd_device *device, sector_t sector)
{
unsigned int enr = BM_SECT_TO_EXT(sector);
struct bm_extent *bm_ext;
@@ -1022,8 +1027,8 @@ int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector)
200 times -> 20 seconds. */
retry:
- sig = wait_event_interruptible(mdev->al_wait,
- (bm_ext = _bme_get(mdev, enr)));
+ sig = wait_event_interruptible(device->al_wait,
+ (bm_ext = _bme_get(device, enr)));
if (sig)
return -EINTR;
@@ -1031,24 +1036,24 @@ retry:
return 0;
for (i = 0; i < AL_EXT_PER_BM_SECT; i++) {
- sig = wait_event_interruptible(mdev->al_wait,
- !_is_in_al(mdev, enr * AL_EXT_PER_BM_SECT + i) ||
+ sig = wait_event_interruptible(device->al_wait,
+ !_is_in_al(device, enr * AL_EXT_PER_BM_SECT + i) ||
test_bit(BME_PRIORITY, &bm_ext->flags));
if (sig || (test_bit(BME_PRIORITY, &bm_ext->flags) && sa)) {
- spin_lock_irq(&mdev->al_lock);
- if (lc_put(mdev->resync, &bm_ext->lce) == 0) {
+ spin_lock_irq(&device->al_lock);
+ if (lc_put(device->resync, &bm_ext->lce) == 0) {
bm_ext->flags = 0; /* clears BME_NO_WRITES and eventually BME_PRIORITY */
- mdev->resync_locked--;
- wake_up(&mdev->al_wait);
+ device->resync_locked--;
+ wake_up(&device->al_wait);
}
- spin_unlock_irq(&mdev->al_lock);
+ spin_unlock_irq(&device->al_lock);
if (sig)
return -EINTR;
if (schedule_timeout_interruptible(HZ/10))
return -EINTR;
if (sa && --sa == 0)
- dev_warn(DEV,"drbd_rs_begin_io() stepped aside for 20sec."
+ drbd_warn(device, "drbd_rs_begin_io() stepped aside for 20sec."
"Resync stalled?\n");
goto retry;
}
@@ -1059,14 +1064,14 @@ retry:
/**
* drbd_try_rs_begin_io() - Gets an extent in the resync LRU cache, does not sleep
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @sector: The sector number.
*
* Gets an extent in the resync LRU cache, sets it to BME_NO_WRITES, then
* tries to set it to BME_LOCKED. Returns 0 upon success, and -EAGAIN
* if there is still application IO going on in this area.
*/
-int drbd_try_rs_begin_io(struct drbd_conf *mdev, sector_t sector)
+int drbd_try_rs_begin_io(struct drbd_device *device, sector_t sector)
{
unsigned int enr = BM_SECT_TO_EXT(sector);
const unsigned int al_enr = enr*AL_EXT_PER_BM_SECT;
@@ -1074,8 +1079,8 @@ int drbd_try_rs_begin_io(struct drbd_conf *mdev, sector_t sector)
struct bm_extent *bm_ext;
int i;
- spin_lock_irq(&mdev->al_lock);
- if (mdev->resync_wenr != LC_FREE && mdev->resync_wenr != enr) {
+ spin_lock_irq(&device->al_lock);
+ if (device->resync_wenr != LC_FREE && device->resync_wenr != enr) {
/* in case you have very heavy scattered io, it may
* stall the syncer undefined if we give up the ref count
* when we try again and requeue.
@@ -1089,193 +1094,193 @@ int drbd_try_rs_begin_io(struct drbd_conf *mdev, sector_t sector)
* the lc_put here...
* we also have to wake_up
*/
- e = lc_find(mdev->resync, mdev->resync_wenr);
+ e = lc_find(device->resync, device->resync_wenr);
bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
if (bm_ext) {
- D_ASSERT(!test_bit(BME_LOCKED, &bm_ext->flags));
- D_ASSERT(test_bit(BME_NO_WRITES, &bm_ext->flags));
+ D_ASSERT(device, !test_bit(BME_LOCKED, &bm_ext->flags));
+ D_ASSERT(device, test_bit(BME_NO_WRITES, &bm_ext->flags));
clear_bit(BME_NO_WRITES, &bm_ext->flags);
- mdev->resync_wenr = LC_FREE;
- if (lc_put(mdev->resync, &bm_ext->lce) == 0)
- mdev->resync_locked--;
- wake_up(&mdev->al_wait);
+ device->resync_wenr = LC_FREE;
+ if (lc_put(device->resync, &bm_ext->lce) == 0)
+ device->resync_locked--;
+ wake_up(&device->al_wait);
} else {
- dev_alert(DEV, "LOGIC BUG\n");
+ drbd_alert(device, "LOGIC BUG\n");
}
}
/* TRY. */
- e = lc_try_get(mdev->resync, enr);
+ e = lc_try_get(device->resync, enr);
bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
if (bm_ext) {
if (test_bit(BME_LOCKED, &bm_ext->flags))
goto proceed;
if (!test_and_set_bit(BME_NO_WRITES, &bm_ext->flags)) {
- mdev->resync_locked++;
+ device->resync_locked++;
} else {
/* we did set the BME_NO_WRITES,
* but then could not set BME_LOCKED,
* so we tried again.
* drop the extra reference. */
bm_ext->lce.refcnt--;
- D_ASSERT(bm_ext->lce.refcnt > 0);
+ D_ASSERT(device, bm_ext->lce.refcnt > 0);
}
goto check_al;
} else {
/* do we rather want to try later? */
- if (mdev->resync_locked > mdev->resync->nr_elements-3)
+ if (device->resync_locked > device->resync->nr_elements-3)
goto try_again;
/* Do or do not. There is no try. -- Yoda */
- e = lc_get(mdev->resync, enr);
+ e = lc_get(device->resync, enr);
bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
if (!bm_ext) {
- const unsigned long rs_flags = mdev->resync->flags;
+ const unsigned long rs_flags = device->resync->flags;
if (rs_flags & LC_STARVING)
- dev_warn(DEV, "Have to wait for element"
+ drbd_warn(device, "Have to wait for element"
" (resync LRU too small?)\n");
BUG_ON(rs_flags & LC_LOCKED);
goto try_again;
}
if (bm_ext->lce.lc_number != enr) {
- bm_ext->rs_left = drbd_bm_e_weight(mdev, enr);
+ bm_ext->rs_left = drbd_bm_e_weight(device, enr);
bm_ext->rs_failed = 0;
- lc_committed(mdev->resync);
- wake_up(&mdev->al_wait);
- D_ASSERT(test_bit(BME_LOCKED, &bm_ext->flags) == 0);
+ lc_committed(device->resync);
+ wake_up(&device->al_wait);
+ D_ASSERT(device, test_bit(BME_LOCKED, &bm_ext->flags) == 0);
}
set_bit(BME_NO_WRITES, &bm_ext->flags);
- D_ASSERT(bm_ext->lce.refcnt == 1);
- mdev->resync_locked++;
+ D_ASSERT(device, bm_ext->lce.refcnt == 1);
+ device->resync_locked++;
goto check_al;
}
check_al:
for (i = 0; i < AL_EXT_PER_BM_SECT; i++) {
- if (lc_is_used(mdev->act_log, al_enr+i))
+ if (lc_is_used(device->act_log, al_enr+i))
goto try_again;
}
set_bit(BME_LOCKED, &bm_ext->flags);
proceed:
- mdev->resync_wenr = LC_FREE;
- spin_unlock_irq(&mdev->al_lock);
+ device->resync_wenr = LC_FREE;
+ spin_unlock_irq(&device->al_lock);
return 0;
try_again:
if (bm_ext)
- mdev->resync_wenr = enr;
- spin_unlock_irq(&mdev->al_lock);
+ device->resync_wenr = enr;
+ spin_unlock_irq(&device->al_lock);
return -EAGAIN;
}
-void drbd_rs_complete_io(struct drbd_conf *mdev, sector_t sector)
+void drbd_rs_complete_io(struct drbd_device *device, sector_t sector)
{
unsigned int enr = BM_SECT_TO_EXT(sector);
struct lc_element *e;
struct bm_extent *bm_ext;
unsigned long flags;
- spin_lock_irqsave(&mdev->al_lock, flags);
- e = lc_find(mdev->resync, enr);
+ spin_lock_irqsave(&device->al_lock, flags);
+ e = lc_find(device->resync, enr);
bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
if (!bm_ext) {
- spin_unlock_irqrestore(&mdev->al_lock, flags);
+ spin_unlock_irqrestore(&device->al_lock, flags);
if (__ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "drbd_rs_complete_io() called, but extent not found\n");
+ drbd_err(device, "drbd_rs_complete_io() called, but extent not found\n");
return;
}
if (bm_ext->lce.refcnt == 0) {
- spin_unlock_irqrestore(&mdev->al_lock, flags);
- dev_err(DEV, "drbd_rs_complete_io(,%llu [=%u]) called, "
+ spin_unlock_irqrestore(&device->al_lock, flags);
+ drbd_err(device, "drbd_rs_complete_io(,%llu [=%u]) called, "
"but refcnt is 0!?\n",
(unsigned long long)sector, enr);
return;
}
- if (lc_put(mdev->resync, &bm_ext->lce) == 0) {
+ if (lc_put(device->resync, &bm_ext->lce) == 0) {
bm_ext->flags = 0; /* clear BME_LOCKED, BME_NO_WRITES and BME_PRIORITY */
- mdev->resync_locked--;
- wake_up(&mdev->al_wait);
+ device->resync_locked--;
+ wake_up(&device->al_wait);
}
- spin_unlock_irqrestore(&mdev->al_lock, flags);
+ spin_unlock_irqrestore(&device->al_lock, flags);
}
/**
* drbd_rs_cancel_all() - Removes all extents from the resync LRU (even BME_LOCKED)
- * @mdev: DRBD device.
+ * @device: DRBD device.
*/
-void drbd_rs_cancel_all(struct drbd_conf *mdev)
+void drbd_rs_cancel_all(struct drbd_device *device)
{
- spin_lock_irq(&mdev->al_lock);
+ spin_lock_irq(&device->al_lock);
- if (get_ldev_if_state(mdev, D_FAILED)) { /* Makes sure ->resync is there. */
- lc_reset(mdev->resync);
- put_ldev(mdev);
+ if (get_ldev_if_state(device, D_FAILED)) { /* Makes sure ->resync is there. */
+ lc_reset(device->resync);
+ put_ldev(device);
}
- mdev->resync_locked = 0;
- mdev->resync_wenr = LC_FREE;
- spin_unlock_irq(&mdev->al_lock);
- wake_up(&mdev->al_wait);
+ device->resync_locked = 0;
+ device->resync_wenr = LC_FREE;
+ spin_unlock_irq(&device->al_lock);
+ wake_up(&device->al_wait);
}
/**
* drbd_rs_del_all() - Gracefully remove all extents from the resync LRU
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Returns 0 upon success, -EAGAIN if at least one reference count was
* not zero.
*/
-int drbd_rs_del_all(struct drbd_conf *mdev)
+int drbd_rs_del_all(struct drbd_device *device)
{
struct lc_element *e;
struct bm_extent *bm_ext;
int i;
- spin_lock_irq(&mdev->al_lock);
+ spin_lock_irq(&device->al_lock);
- if (get_ldev_if_state(mdev, D_FAILED)) {
+ if (get_ldev_if_state(device, D_FAILED)) {
/* ok, ->resync is there. */
- for (i = 0; i < mdev->resync->nr_elements; i++) {
- e = lc_element_by_index(mdev->resync, i);
+ for (i = 0; i < device->resync->nr_elements; i++) {
+ e = lc_element_by_index(device->resync, i);
bm_ext = lc_entry(e, struct bm_extent, lce);
if (bm_ext->lce.lc_number == LC_FREE)
continue;
- if (bm_ext->lce.lc_number == mdev->resync_wenr) {
- dev_info(DEV, "dropping %u in drbd_rs_del_all, apparently"
+ if (bm_ext->lce.lc_number == device->resync_wenr) {
+ drbd_info(device, "dropping %u in drbd_rs_del_all, apparently"
" got 'synced' by application io\n",
- mdev->resync_wenr);
- D_ASSERT(!test_bit(BME_LOCKED, &bm_ext->flags));
- D_ASSERT(test_bit(BME_NO_WRITES, &bm_ext->flags));
+ device->resync_wenr);
+ D_ASSERT(device, !test_bit(BME_LOCKED, &bm_ext->flags));
+ D_ASSERT(device, test_bit(BME_NO_WRITES, &bm_ext->flags));
clear_bit(BME_NO_WRITES, &bm_ext->flags);
- mdev->resync_wenr = LC_FREE;
- lc_put(mdev->resync, &bm_ext->lce);
+ device->resync_wenr = LC_FREE;
+ lc_put(device->resync, &bm_ext->lce);
}
if (bm_ext->lce.refcnt != 0) {
- dev_info(DEV, "Retrying drbd_rs_del_all() later. "
+ drbd_info(device, "Retrying drbd_rs_del_all() later. "
"refcnt=%d\n", bm_ext->lce.refcnt);
- put_ldev(mdev);
- spin_unlock_irq(&mdev->al_lock);
+ put_ldev(device);
+ spin_unlock_irq(&device->al_lock);
return -EAGAIN;
}
- D_ASSERT(!test_bit(BME_LOCKED, &bm_ext->flags));
- D_ASSERT(!test_bit(BME_NO_WRITES, &bm_ext->flags));
- lc_del(mdev->resync, &bm_ext->lce);
+ D_ASSERT(device, !test_bit(BME_LOCKED, &bm_ext->flags));
+ D_ASSERT(device, !test_bit(BME_NO_WRITES, &bm_ext->flags));
+ lc_del(device->resync, &bm_ext->lce);
}
- D_ASSERT(mdev->resync->used == 0);
- put_ldev(mdev);
+ D_ASSERT(device, device->resync->used == 0);
+ put_ldev(device);
}
- spin_unlock_irq(&mdev->al_lock);
- wake_up(&mdev->al_wait);
+ spin_unlock_irq(&device->al_lock);
+ wake_up(&device->al_wait);
return 0;
}
/**
* drbd_rs_failed_io() - Record information on a failure to resync the specified blocks
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @sector: The sector number.
* @size: Size of failed IO operation, in byte.
*/
-void drbd_rs_failed_io(struct drbd_conf *mdev, sector_t sector, int size)
+void drbd_rs_failed_io(struct drbd_device *device, sector_t sector, int size)
{
/* Is called from worker and receiver context _only_ */
unsigned long sbnr, ebnr, lbnr;
@@ -1284,11 +1289,11 @@ void drbd_rs_failed_io(struct drbd_conf *mdev, sector_t sector, int size)
int wake_up = 0;
if (size <= 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_BIO_SIZE) {
- dev_err(DEV, "drbd_rs_failed_io: sector=%llus size=%d nonsense!\n",
+ drbd_err(device, "drbd_rs_failed_io: sector=%llus size=%d nonsense!\n",
(unsigned long long)sector, size);
return;
}
- nr_sectors = drbd_get_capacity(mdev->this_bdev);
+ nr_sectors = drbd_get_capacity(device->this_bdev);
esector = sector + (size >> 9) - 1;
if (!expect(sector < nr_sectors))
@@ -1316,21 +1321,21 @@ void drbd_rs_failed_io(struct drbd_conf *mdev, sector_t sector, int size)
* ok, (capacity & 7) != 0 sometimes, but who cares...
* we count rs_{total,left} in bits, not sectors.
*/
- spin_lock_irq(&mdev->al_lock);
- count = drbd_bm_count_bits(mdev, sbnr, ebnr);
+ spin_lock_irq(&device->al_lock);
+ count = drbd_bm_count_bits(device, sbnr, ebnr);
if (count) {
- mdev->rs_failed += count;
+ device->rs_failed += count;
- if (get_ldev(mdev)) {
- drbd_try_clear_on_disk_bm(mdev, sector, count, false);
- put_ldev(mdev);
+ if (get_ldev(device)) {
+ drbd_try_clear_on_disk_bm(device, sector, count, false);
+ put_ldev(device);
}
/* just wake_up unconditional now, various lc_chaged(),
* lc_put() in drbd_try_clear_on_disk_bm(). */
wake_up = 1;
}
- spin_unlock_irq(&mdev->al_lock);
+ spin_unlock_irq(&device->al_lock);
if (wake_up)
- wake_up(&mdev->al_wait);
+ wake_up(&device->al_wait);
}
diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c
index 597f111df67b..1aa29f8fdfe1 100644
--- a/drivers/block/drbd/drbd_bitmap.c
+++ b/drivers/block/drbd/drbd_bitmap.c
@@ -113,54 +113,54 @@ struct drbd_bitmap {
};
#define bm_print_lock_info(m) __bm_print_lock_info(m, __func__)
-static void __bm_print_lock_info(struct drbd_conf *mdev, const char *func)
+static void __bm_print_lock_info(struct drbd_device *device, const char *func)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
if (!__ratelimit(&drbd_ratelimit_state))
return;
- dev_err(DEV, "FIXME %s in %s, bitmap locked for '%s' by %s\n",
- drbd_task_to_thread_name(mdev->tconn, current),
- func, b->bm_why ?: "?",
- drbd_task_to_thread_name(mdev->tconn, b->bm_task));
+ drbd_err(device, "FIXME %s[%d] in %s, bitmap locked for '%s' by %s[%d]\n",
+ current->comm, task_pid_nr(current),
+ func, b->bm_why ?: "?",
+ b->bm_task->comm, task_pid_nr(b->bm_task));
}
-void drbd_bm_lock(struct drbd_conf *mdev, char *why, enum bm_flag flags)
+void drbd_bm_lock(struct drbd_device *device, char *why, enum bm_flag flags)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
int trylock_failed;
if (!b) {
- dev_err(DEV, "FIXME no bitmap in drbd_bm_lock!?\n");
+ drbd_err(device, "FIXME no bitmap in drbd_bm_lock!?\n");
return;
}
trylock_failed = !mutex_trylock(&b->bm_change);
if (trylock_failed) {
- dev_warn(DEV, "%s going to '%s' but bitmap already locked for '%s' by %s\n",
- drbd_task_to_thread_name(mdev->tconn, current),
- why, b->bm_why ?: "?",
- drbd_task_to_thread_name(mdev->tconn, b->bm_task));
+ drbd_warn(device, "%s[%d] going to '%s' but bitmap already locked for '%s' by %s[%d]\n",
+ current->comm, task_pid_nr(current),
+ why, b->bm_why ?: "?",
+ b->bm_task->comm, task_pid_nr(b->bm_task));
mutex_lock(&b->bm_change);
}
if (BM_LOCKED_MASK & b->bm_flags)
- dev_err(DEV, "FIXME bitmap already locked in bm_lock\n");
+ drbd_err(device, "FIXME bitmap already locked in bm_lock\n");
b->bm_flags |= flags & BM_LOCKED_MASK;
b->bm_why = why;
b->bm_task = current;
}
-void drbd_bm_unlock(struct drbd_conf *mdev)
+void drbd_bm_unlock(struct drbd_device *device)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
if (!b) {
- dev_err(DEV, "FIXME no bitmap in drbd_bm_unlock!?\n");
+ drbd_err(device, "FIXME no bitmap in drbd_bm_unlock!?\n");
return;
}
- if (!(BM_LOCKED_MASK & mdev->bitmap->bm_flags))
- dev_err(DEV, "FIXME bitmap not locked in bm_unlock\n");
+ if (!(BM_LOCKED_MASK & device->bitmap->bm_flags))
+ drbd_err(device, "FIXME bitmap not locked in bm_unlock\n");
b->bm_flags &= ~BM_LOCKED_MASK;
b->bm_why = NULL;
@@ -211,19 +211,19 @@ static unsigned long bm_page_to_idx(struct page *page)
/* As is very unlikely that the same page is under IO from more than one
* context, we can get away with a bit per page and one wait queue per bitmap.
*/
-static void bm_page_lock_io(struct drbd_conf *mdev, int page_nr)
+static void bm_page_lock_io(struct drbd_device *device, int page_nr)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
void *addr = &page_private(b->bm_pages[page_nr]);
wait_event(b->bm_io_wait, !test_and_set_bit(BM_PAGE_IO_LOCK, addr));
}
-static void bm_page_unlock_io(struct drbd_conf *mdev, int page_nr)
+static void bm_page_unlock_io(struct drbd_device *device, int page_nr)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
void *addr = &page_private(b->bm_pages[page_nr]);
clear_bit_unlock(BM_PAGE_IO_LOCK, addr);
- wake_up(&mdev->bitmap->bm_io_wait);
+ wake_up(&device->bitmap->bm_io_wait);
}
/* set _before_ submit_io, so it may be reset due to being changed
@@ -242,22 +242,22 @@ static void bm_set_page_need_writeout(struct page *page)
/**
* drbd_bm_mark_for_writeout() - mark a page with a "hint" to be considered for writeout
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @page_nr: the bitmap page to mark with the "hint" flag
*
* From within an activity log transaction, we mark a few pages with these
* hints, then call drbd_bm_write_hinted(), which will only write out changed
* pages which are flagged with this mark.
*/
-void drbd_bm_mark_for_writeout(struct drbd_conf *mdev, int page_nr)
+void drbd_bm_mark_for_writeout(struct drbd_device *device, int page_nr)
{
struct page *page;
- if (page_nr >= mdev->bitmap->bm_number_of_pages) {
- dev_warn(DEV, "BAD: page_nr: %u, number_of_pages: %u\n",
- page_nr, (int)mdev->bitmap->bm_number_of_pages);
+ if (page_nr >= device->bitmap->bm_number_of_pages) {
+ drbd_warn(device, "BAD: page_nr: %u, number_of_pages: %u\n",
+ page_nr, (int)device->bitmap->bm_number_of_pages);
return;
}
- page = mdev->bitmap->bm_pages[page_nr];
+ page = device->bitmap->bm_pages[page_nr];
set_bit(BM_PAGE_HINT_WRITEOUT, &page_private(page));
}
@@ -340,7 +340,7 @@ static void bm_unmap(unsigned long *p_addr)
/*
* actually most functions herein should take a struct drbd_bitmap*, not a
- * struct drbd_conf*, but for the debug macros I like to have the mdev around
+ * struct drbd_device*, but for the debug macros I like to have the device around
* to be able to report device specific.
*/
@@ -436,11 +436,11 @@ static struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want)
/*
* called on driver init only. TODO call when a device is created.
- * allocates the drbd_bitmap, and stores it in mdev->bitmap.
+ * allocates the drbd_bitmap, and stores it in device->bitmap.
*/
-int drbd_bm_init(struct drbd_conf *mdev)
+int drbd_bm_init(struct drbd_device *device)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
WARN_ON(b != NULL);
b = kzalloc(sizeof(struct drbd_bitmap), GFP_KERNEL);
if (!b)
@@ -449,28 +449,28 @@ int drbd_bm_init(struct drbd_conf *mdev)
mutex_init(&b->bm_change);
init_waitqueue_head(&b->bm_io_wait);
- mdev->bitmap = b;
+ device->bitmap = b;
return 0;
}
-sector_t drbd_bm_capacity(struct drbd_conf *mdev)
+sector_t drbd_bm_capacity(struct drbd_device *device)
{
- if (!expect(mdev->bitmap))
+ if (!expect(device->bitmap))
return 0;
- return mdev->bitmap->bm_dev_capacity;
+ return device->bitmap->bm_dev_capacity;
}
/* called on driver unload. TODO: call when a device is destroyed.
*/
-void drbd_bm_cleanup(struct drbd_conf *mdev)
+void drbd_bm_cleanup(struct drbd_device *device)
{
- if (!expect(mdev->bitmap))
+ if (!expect(device->bitmap))
return;
- bm_free_pages(mdev->bitmap->bm_pages, mdev->bitmap->bm_number_of_pages);
- bm_vk_free(mdev->bitmap->bm_pages, (BM_P_VMALLOCED & mdev->bitmap->bm_flags));
- kfree(mdev->bitmap);
- mdev->bitmap = NULL;
+ bm_free_pages(device->bitmap->bm_pages, device->bitmap->bm_number_of_pages);
+ bm_vk_free(device->bitmap->bm_pages, (BM_P_VMALLOCED & device->bitmap->bm_flags));
+ kfree(device->bitmap);
+ device->bitmap = NULL;
}
/*
@@ -631,9 +631,9 @@ static u64 drbd_md_on_disk_bits(struct drbd_backing_dev *ldev)
* In case this is actually a resize, we copy the old bitmap into the new one.
* Otherwise, the bitmap is initialized to all bits set.
*/
-int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits)
+int drbd_bm_resize(struct drbd_device *device, sector_t capacity, int set_new_bits)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
unsigned long bits, words, owords, obits;
unsigned long want, have, onpages; /* number of pages */
struct page **npages, **opages = NULL;
@@ -643,9 +643,9 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits)
if (!expect(b))
return -ENOMEM;
- drbd_bm_lock(mdev, "resize", BM_LOCKED_MASK);
+ drbd_bm_lock(device, "resize", BM_LOCKED_MASK);
- dev_info(DEV, "drbd_bm_resize called with capacity == %llu\n",
+ drbd_info(device, "drbd_bm_resize called with capacity == %llu\n",
(unsigned long long)capacity);
if (capacity == b->bm_dev_capacity)
@@ -678,12 +678,12 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits)
*/
words = ALIGN(bits, 64) >> LN2_BPL;
- if (get_ldev(mdev)) {
- u64 bits_on_disk = drbd_md_on_disk_bits(mdev->ldev);
- put_ldev(mdev);
+ if (get_ldev(device)) {
+ u64 bits_on_disk = drbd_md_on_disk_bits(device->ldev);
+ put_ldev(device);
if (bits > bits_on_disk) {
- dev_info(DEV, "bits = %lu\n", bits);
- dev_info(DEV, "bits_on_disk = %llu\n", bits_on_disk);
+ drbd_info(device, "bits = %lu\n", bits);
+ drbd_info(device, "bits_on_disk = %llu\n", bits_on_disk);
err = -ENOSPC;
goto out;
}
@@ -692,10 +692,10 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits)
want = ALIGN(words*sizeof(long), PAGE_SIZE) >> PAGE_SHIFT;
have = b->bm_number_of_pages;
if (want == have) {
- D_ASSERT(b->bm_pages != NULL);
+ D_ASSERT(device, b->bm_pages != NULL);
npages = b->bm_pages;
} else {
- if (drbd_insert_fault(mdev, DRBD_FAULT_BM_ALLOC))
+ if (drbd_insert_fault(device, DRBD_FAULT_BM_ALLOC))
npages = NULL;
else
npages = bm_realloc_pages(b, want);
@@ -742,10 +742,10 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits)
bm_vk_free(opages, opages_vmalloced);
if (!growing)
b->bm_set = bm_count_bits(b);
- dev_info(DEV, "resync bitmap: bits=%lu words=%lu pages=%lu\n", bits, words, want);
+ drbd_info(device, "resync bitmap: bits=%lu words=%lu pages=%lu\n", bits, words, want);
out:
- drbd_bm_unlock(mdev);
+ drbd_bm_unlock(device);
return err;
}
@@ -757,9 +757,9 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits)
*
* maybe bm_set should be atomic_t ?
*/
-unsigned long _drbd_bm_total_weight(struct drbd_conf *mdev)
+unsigned long _drbd_bm_total_weight(struct drbd_device *device)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
unsigned long s;
unsigned long flags;
@@ -775,20 +775,20 @@ unsigned long _drbd_bm_total_weight(struct drbd_conf *mdev)
return s;
}
-unsigned long drbd_bm_total_weight(struct drbd_conf *mdev)
+unsigned long drbd_bm_total_weight(struct drbd_device *device)
{
unsigned long s;
/* if I don't have a disk, I don't know about out-of-sync status */
- if (!get_ldev_if_state(mdev, D_NEGOTIATING))
+ if (!get_ldev_if_state(device, D_NEGOTIATING))
return 0;
- s = _drbd_bm_total_weight(mdev);
- put_ldev(mdev);
+ s = _drbd_bm_total_weight(device);
+ put_ldev(device);
return s;
}
-size_t drbd_bm_words(struct drbd_conf *mdev)
+size_t drbd_bm_words(struct drbd_device *device)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
if (!expect(b))
return 0;
if (!expect(b->bm_pages))
@@ -797,9 +797,9 @@ size_t drbd_bm_words(struct drbd_conf *mdev)
return b->bm_words;
}
-unsigned long drbd_bm_bits(struct drbd_conf *mdev)
+unsigned long drbd_bm_bits(struct drbd_device *device)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
if (!expect(b))
return 0;
@@ -811,10 +811,10 @@ unsigned long drbd_bm_bits(struct drbd_conf *mdev)
* bitmap must be locked by drbd_bm_lock.
* currently only used from receive_bitmap.
*/
-void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset, size_t number,
+void drbd_bm_merge_lel(struct drbd_device *device, size_t offset, size_t number,
unsigned long *buffer)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
unsigned long *p_addr, *bm;
unsigned long word, bits;
unsigned int idx;
@@ -860,10 +860,10 @@ void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset, size_t number,
/* copy number words from the bitmap starting at offset into the buffer.
* buffer[i] will be little endian unsigned long.
*/
-void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset, size_t number,
+void drbd_bm_get_lel(struct drbd_device *device, size_t offset, size_t number,
unsigned long *buffer)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
unsigned long *p_addr, *bm;
size_t end, do_now;
@@ -878,7 +878,7 @@ void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset, size_t number,
if ((offset >= b->bm_words) ||
(end > b->bm_words) ||
(number <= 0))
- dev_err(DEV, "offset=%lu number=%lu bm_words=%lu\n",
+ drbd_err(device, "offset=%lu number=%lu bm_words=%lu\n",
(unsigned long) offset,
(unsigned long) number,
(unsigned long) b->bm_words);
@@ -897,9 +897,9 @@ void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset, size_t number,
}
/* set all bits in the bitmap */
-void drbd_bm_set_all(struct drbd_conf *mdev)
+void drbd_bm_set_all(struct drbd_device *device)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
if (!expect(b))
return;
if (!expect(b->bm_pages))
@@ -913,9 +913,9 @@ void drbd_bm_set_all(struct drbd_conf *mdev)
}
/* clear all bits in the bitmap */
-void drbd_bm_clear_all(struct drbd_conf *mdev)
+void drbd_bm_clear_all(struct drbd_device *device)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
if (!expect(b))
return;
if (!expect(b->bm_pages))
@@ -928,7 +928,7 @@ void drbd_bm_clear_all(struct drbd_conf *mdev)
}
struct bm_aio_ctx {
- struct drbd_conf *mdev;
+ struct drbd_device *device;
atomic_t in_flight;
unsigned int done;
unsigned flags;
@@ -943,7 +943,7 @@ static void bm_aio_ctx_destroy(struct kref *kref)
{
struct bm_aio_ctx *ctx = container_of(kref, struct bm_aio_ctx, kref);
- put_ldev(ctx->mdev);
+ put_ldev(ctx->device);
kfree(ctx);
}
@@ -951,8 +951,8 @@ static void bm_aio_ctx_destroy(struct kref *kref)
static void bm_async_io_complete(struct bio *bio, int error)
{
struct bm_aio_ctx *ctx = bio->bi_private;
- struct drbd_conf *mdev = ctx->mdev;
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_device *device = ctx->device;
+ struct drbd_bitmap *b = device->bitmap;
unsigned int idx = bm_page_to_idx(bio->bi_io_vec[0].bv_page);
int uptodate = bio_flagged(bio, BIO_UPTODATE);
@@ -966,7 +966,7 @@ static void bm_async_io_complete(struct bio *bio, int error)
if ((ctx->flags & BM_AIO_COPY_PAGES) == 0 &&
!bm_test_page_unchanged(b->bm_pages[idx]))
- dev_warn(DEV, "bitmap page idx %u changed during IO!\n", idx);
+ drbd_warn(device, "bitmap page idx %u changed during IO!\n", idx);
if (error) {
/* ctx error will hold the completed-last non-zero error code,
@@ -976,14 +976,14 @@ static void bm_async_io_complete(struct bio *bio, int error)
/* Not identical to on disk version of it.
* Is BM_PAGE_IO_ERROR enough? */
if (__ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "IO ERROR %d on bitmap page idx %u\n",
+ drbd_err(device, "IO ERROR %d on bitmap page idx %u\n",
error, idx);
} else {
bm_clear_page_io_err(b->bm_pages[idx]);
- dynamic_dev_dbg(DEV, "bitmap page idx %u completed\n", idx);
+ dynamic_drbd_dbg(device, "bitmap page idx %u completed\n", idx);
}
- bm_page_unlock_io(mdev, idx);
+ bm_page_unlock_io(device, idx);
if (ctx->flags & BM_AIO_COPY_PAGES)
mempool_free(bio->bi_io_vec[0].bv_page, drbd_md_io_page_pool);
@@ -992,7 +992,7 @@ static void bm_async_io_complete(struct bio *bio, int error)
if (atomic_dec_and_test(&ctx->in_flight)) {
ctx->done = 1;
- wake_up(&mdev->misc_wait);
+ wake_up(&device->misc_wait);
kref_put(&ctx->kref, &bm_aio_ctx_destroy);
}
}
@@ -1000,23 +1000,23 @@ static void bm_async_io_complete(struct bio *bio, int error)
static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must_hold(local)
{
struct bio *bio = bio_alloc_drbd(GFP_NOIO);
- struct drbd_conf *mdev = ctx->mdev;
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_device *device = ctx->device;
+ struct drbd_bitmap *b = device->bitmap;
struct page *page;
unsigned int len;
sector_t on_disk_sector =
- mdev->ldev->md.md_offset + mdev->ldev->md.bm_offset;
+ device->ldev->md.md_offset + device->ldev->md.bm_offset;
on_disk_sector += ((sector_t)page_nr) << (PAGE_SHIFT-9);
/* this might happen with very small
* flexible external meta data device,
* or with PAGE_SIZE > 4k */
len = min_t(unsigned int, PAGE_SIZE,
- (drbd_md_last_sector(mdev->ldev) - on_disk_sector + 1)<<9);
+ (drbd_md_last_sector(device->ldev) - on_disk_sector + 1)<<9);
/* serialize IO on this page */
- bm_page_lock_io(mdev, page_nr);
+ bm_page_lock_io(device, page_nr);
/* before memcpy and submit,
* so it can be redirtied any time */
bm_set_page_unchanged(b->bm_pages[page_nr]);
@@ -1027,7 +1027,7 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must
bm_store_page_idx(page, page_nr);
} else
page = b->bm_pages[page_nr];
- bio->bi_bdev = mdev->ldev->md_bdev;
+ bio->bi_bdev = device->ldev->md_bdev;
bio->bi_iter.bi_sector = on_disk_sector;
/* bio_add_page of a single page to an empty bio will always succeed,
* according to api. Do we want to assert that? */
@@ -1035,24 +1035,24 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must
bio->bi_private = ctx;
bio->bi_end_io = bm_async_io_complete;
- if (drbd_insert_fault(mdev, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) {
+ if (drbd_insert_fault(device, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) {
bio->bi_rw |= rw;
bio_endio(bio, -EIO);
} else {
submit_bio(rw, bio);
/* this should not count as user activity and cause the
* resync to throttle -- see drbd_rs_should_slow_down(). */
- atomic_add(len >> 9, &mdev->rs_sect_ev);
+ atomic_add(len >> 9, &device->rs_sect_ev);
}
}
/*
* bm_rw: read/write the whole bitmap from/to its on disk location.
*/
-static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_writeout_upper_idx) __must_hold(local)
+static int bm_rw(struct drbd_device *device, int rw, unsigned flags, unsigned lazy_writeout_upper_idx) __must_hold(local)
{
struct bm_aio_ctx *ctx;
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
int num_pages, i, count = 0;
unsigned long now;
char ppb[10];
@@ -1072,7 +1072,7 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w
return -ENOMEM;
*ctx = (struct bm_aio_ctx) {
- .mdev = mdev,
+ .device = device,
.in_flight = ATOMIC_INIT(1),
.done = 0,
.flags = flags,
@@ -1080,8 +1080,8 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w
.kref = { ATOMIC_INIT(2) },
};
- if (!get_ldev_if_state(mdev, D_ATTACHING)) { /* put is in bm_aio_ctx_destroy() */
- dev_err(DEV, "ASSERT FAILED: get_ldev_if_state() == 1 in bm_rw()\n");
+ if (!get_ldev_if_state(device, D_ATTACHING)) { /* put is in bm_aio_ctx_destroy() */
+ drbd_err(device, "ASSERT FAILED: get_ldev_if_state() == 1 in bm_rw()\n");
kfree(ctx);
return -ENODEV;
}
@@ -1106,14 +1106,14 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w
if (!(flags & BM_WRITE_ALL_PAGES) &&
bm_test_page_unchanged(b->bm_pages[i])) {
- dynamic_dev_dbg(DEV, "skipped bm write for idx %u\n", i);
+ dynamic_drbd_dbg(device, "skipped bm write for idx %u\n", i);
continue;
}
/* during lazy writeout,
* ignore those pages not marked for lazy writeout. */
if (lazy_writeout_upper_idx &&
!bm_test_page_lazy_writeout(b->bm_pages[i])) {
- dynamic_dev_dbg(DEV, "skipped bm lazy write for idx %u\n", i);
+ dynamic_drbd_dbg(device, "skipped bm lazy write for idx %u\n", i);
continue;
}
}
@@ -1132,19 +1132,19 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w
* "in_flight reached zero, all done" event.
*/
if (!atomic_dec_and_test(&ctx->in_flight))
- wait_until_done_or_force_detached(mdev, mdev->ldev, &ctx->done);
+ wait_until_done_or_force_detached(device, device->ldev, &ctx->done);
else
kref_put(&ctx->kref, &bm_aio_ctx_destroy);
/* summary for global bitmap IO */
if (flags == 0)
- dev_info(DEV, "bitmap %s of %u pages took %lu jiffies\n",
+ drbd_info(device, "bitmap %s of %u pages took %lu jiffies\n",
rw == WRITE ? "WRITE" : "READ",
count, jiffies - now);
if (ctx->error) {
- dev_alert(DEV, "we had at least one MD IO ERROR during bitmap IO\n");
- drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
+ drbd_alert(device, "we had at least one MD IO ERROR during bitmap IO\n");
+ drbd_chk_io_error(device, 1, DRBD_META_IO_ERROR);
err = -EIO; /* ctx->error ? */
}
@@ -1153,16 +1153,16 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w
now = jiffies;
if (rw == WRITE) {
- drbd_md_flush(mdev);
+ drbd_md_flush(device);
} else /* rw == READ */ {
b->bm_set = bm_count_bits(b);
- dev_info(DEV, "recounting of set bits took additional %lu jiffies\n",
+ drbd_info(device, "recounting of set bits took additional %lu jiffies\n",
jiffies - now);
}
now = b->bm_set;
if (flags == 0)
- dev_info(DEV, "%s (%lu bits) marked out-of-sync by on disk bit-map.\n",
+ drbd_info(device, "%s (%lu bits) marked out-of-sync by on disk bit-map.\n",
ppsize(ppb, now << (BM_BLOCK_SHIFT-10)), now);
kref_put(&ctx->kref, &bm_aio_ctx_destroy);
@@ -1171,48 +1171,38 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w
/**
* drbd_bm_read() - Read the whole bitmap from its on disk location.
- * @mdev: DRBD device.
+ * @device: DRBD device.
*/
-int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local)
+int drbd_bm_read(struct drbd_device *device) __must_hold(local)
{
- return bm_rw(mdev, READ, 0, 0);
+ return bm_rw(device, READ, 0, 0);
}
/**
* drbd_bm_write() - Write the whole bitmap to its on disk location.
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Will only write pages that have changed since last IO.
*/
-int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local)
+int drbd_bm_write(struct drbd_device *device) __must_hold(local)
{
- return bm_rw(mdev, WRITE, 0, 0);
+ return bm_rw(device, WRITE, 0, 0);
}
/**
* drbd_bm_write_all() - Write the whole bitmap to its on disk location.
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Will write all pages.
*/
-int drbd_bm_write_all(struct drbd_conf *mdev) __must_hold(local)
+int drbd_bm_write_all(struct drbd_device *device) __must_hold(local)
{
- return bm_rw(mdev, WRITE, BM_WRITE_ALL_PAGES, 0);
-}
-
-/**
- * drbd_bm_lazy_write_out() - Write bitmap pages 0 to @upper_idx-1, if they have changed.
- * @mdev: DRBD device.
- * @upper_idx: 0: write all changed pages; +ve: page index to stop scanning for changed pages
- */
-int drbd_bm_write_lazy(struct drbd_conf *mdev, unsigned upper_idx) __must_hold(local)
-{
- return bm_rw(mdev, WRITE, BM_AIO_COPY_PAGES, upper_idx);
+ return bm_rw(device, WRITE, BM_WRITE_ALL_PAGES, 0);
}
/**
* drbd_bm_write_copy_pages() - Write the whole bitmap to its on disk location.
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Will only write pages that have changed since last IO.
* In contrast to drbd_bm_write(), this will copy the bitmap pages
@@ -1221,23 +1211,23 @@ int drbd_bm_write_lazy(struct drbd_conf *mdev, unsigned upper_idx) __must_hold(l
* verify is aborted due to a failed peer disk, while local IO continues, or
* pending resync acks are still being processed.
*/
-int drbd_bm_write_copy_pages(struct drbd_conf *mdev) __must_hold(local)
+int drbd_bm_write_copy_pages(struct drbd_device *device) __must_hold(local)
{
- return bm_rw(mdev, WRITE, BM_AIO_COPY_PAGES, 0);
+ return bm_rw(device, WRITE, BM_AIO_COPY_PAGES, 0);
}
/**
* drbd_bm_write_hinted() - Write bitmap pages with "hint" marks, if they have changed.
- * @mdev: DRBD device.
+ * @device: DRBD device.
*/
-int drbd_bm_write_hinted(struct drbd_conf *mdev) __must_hold(local)
+int drbd_bm_write_hinted(struct drbd_device *device) __must_hold(local)
{
- return bm_rw(mdev, WRITE, BM_AIO_WRITE_HINTED | BM_AIO_COPY_PAGES, 0);
+ return bm_rw(device, WRITE, BM_AIO_WRITE_HINTED | BM_AIO_COPY_PAGES, 0);
}
/**
* drbd_bm_write_page() - Writes a PAGE_SIZE aligned piece of bitmap
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @idx: bitmap page index
*
* We don't want to special case on logical_block_size of the backend device,
@@ -1247,13 +1237,13 @@ int drbd_bm_write_hinted(struct drbd_conf *mdev) __must_hold(local)
* In case this becomes an issue on systems with larger PAGE_SIZE,
* we may want to change this again to write 4k aligned 4k pieces.
*/
-int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(local)
+int drbd_bm_write_page(struct drbd_device *device, unsigned int idx) __must_hold(local)
{
struct bm_aio_ctx *ctx;
int err;
- if (bm_test_page_unchanged(mdev->bitmap->bm_pages[idx])) {
- dynamic_dev_dbg(DEV, "skipped bm page write for idx %u\n", idx);
+ if (bm_test_page_unchanged(device->bitmap->bm_pages[idx])) {
+ dynamic_drbd_dbg(device, "skipped bm page write for idx %u\n", idx);
return 0;
}
@@ -1262,7 +1252,7 @@ int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(loc
return -ENOMEM;
*ctx = (struct bm_aio_ctx) {
- .mdev = mdev,
+ .device = device,
.in_flight = ATOMIC_INIT(1),
.done = 0,
.flags = BM_AIO_COPY_PAGES,
@@ -1270,21 +1260,21 @@ int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(loc
.kref = { ATOMIC_INIT(2) },
};
- if (!get_ldev_if_state(mdev, D_ATTACHING)) { /* put is in bm_aio_ctx_destroy() */
- dev_err(DEV, "ASSERT FAILED: get_ldev_if_state() == 1 in drbd_bm_write_page()\n");
+ if (!get_ldev_if_state(device, D_ATTACHING)) { /* put is in bm_aio_ctx_destroy() */
+ drbd_err(device, "ASSERT FAILED: get_ldev_if_state() == 1 in drbd_bm_write_page()\n");
kfree(ctx);
return -ENODEV;
}
bm_page_io_async(ctx, idx, WRITE_SYNC);
- wait_until_done_or_force_detached(mdev, mdev->ldev, &ctx->done);
+ wait_until_done_or_force_detached(device, device->ldev, &ctx->done);
if (ctx->error)
- drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
+ drbd_chk_io_error(device, 1, DRBD_META_IO_ERROR);
/* that causes us to detach, so the in memory bitmap will be
* gone in a moment as well. */
- mdev->bm_writ_cnt++;
+ device->bm_writ_cnt++;
err = atomic_read(&ctx->in_flight) ? -EIO : ctx->error;
kref_put(&ctx->kref, &bm_aio_ctx_destroy);
return err;
@@ -1298,17 +1288,17 @@ int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(loc
*
* this returns a bit number, NOT a sector!
*/
-static unsigned long __bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo,
+static unsigned long __bm_find_next(struct drbd_device *device, unsigned long bm_fo,
const int find_zero_bit)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
unsigned long *p_addr;
unsigned long bit_offset;
unsigned i;
if (bm_fo > b->bm_bits) {
- dev_err(DEV, "bm_fo=%lu bm_bits=%lu\n", bm_fo, b->bm_bits);
+ drbd_err(device, "bm_fo=%lu bm_bits=%lu\n", bm_fo, b->bm_bits);
bm_fo = DRBD_END_OF_BITMAP;
} else {
while (bm_fo < b->bm_bits) {
@@ -1338,10 +1328,10 @@ static unsigned long __bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo,
return bm_fo;
}
-static unsigned long bm_find_next(struct drbd_conf *mdev,
+static unsigned long bm_find_next(struct drbd_device *device,
unsigned long bm_fo, const int find_zero_bit)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
unsigned long i = DRBD_END_OF_BITMAP;
if (!expect(b))
@@ -1351,39 +1341,39 @@ static unsigned long bm_find_next(struct drbd_conf *mdev,
spin_lock_irq(&b->bm_lock);
if (BM_DONT_TEST & b->bm_flags)
- bm_print_lock_info(mdev);
+ bm_print_lock_info(device);
- i = __bm_find_next(mdev, bm_fo, find_zero_bit);
+ i = __bm_find_next(device, bm_fo, find_zero_bit);
spin_unlock_irq(&b->bm_lock);
return i;
}
-unsigned long drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo)
+unsigned long drbd_bm_find_next(struct drbd_device *device, unsigned long bm_fo)
{
- return bm_find_next(mdev, bm_fo, 0);
+ return bm_find_next(device, bm_fo, 0);
}
#if 0
/* not yet needed for anything. */
-unsigned long drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo)
+unsigned long drbd_bm_find_next_zero(struct drbd_device *device, unsigned long bm_fo)
{
- return bm_find_next(mdev, bm_fo, 1);
+ return bm_find_next(device, bm_fo, 1);
}
#endif
/* does not spin_lock_irqsave.
* you must take drbd_bm_lock() first */
-unsigned long _drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo)
+unsigned long _drbd_bm_find_next(struct drbd_device *device, unsigned long bm_fo)
{
- /* WARN_ON(!(BM_DONT_SET & mdev->b->bm_flags)); */
- return __bm_find_next(mdev, bm_fo, 0);
+ /* WARN_ON(!(BM_DONT_SET & device->b->bm_flags)); */
+ return __bm_find_next(device, bm_fo, 0);
}
-unsigned long _drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo)
+unsigned long _drbd_bm_find_next_zero(struct drbd_device *device, unsigned long bm_fo)
{
- /* WARN_ON(!(BM_DONT_SET & mdev->b->bm_flags)); */
- return __bm_find_next(mdev, bm_fo, 1);
+ /* WARN_ON(!(BM_DONT_SET & device->b->bm_flags)); */
+ return __bm_find_next(device, bm_fo, 1);
}
/* returns number of bits actually changed.
@@ -1392,10 +1382,10 @@ unsigned long _drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_f
* wants bitnr, not sector.
* expected to be called for only a few bits (e - s about BITS_PER_LONG).
* Must hold bitmap lock already. */
-static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
+static int __bm_change_bits_to(struct drbd_device *device, const unsigned long s,
unsigned long e, int val)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
unsigned long *p_addr = NULL;
unsigned long bitnr;
unsigned int last_page_nr = -1U;
@@ -1403,7 +1393,7 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
int changed_total = 0;
if (e >= b->bm_bits) {
- dev_err(DEV, "ASSERT FAILED: bit_s=%lu bit_e=%lu bm_bits=%lu\n",
+ drbd_err(device, "ASSERT FAILED: bit_s=%lu bit_e=%lu bm_bits=%lu\n",
s, e, b->bm_bits);
e = b->bm_bits ? b->bm_bits -1 : 0;
}
@@ -1441,11 +1431,11 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
* for val != 0, we change 0 -> 1, return code positive
* for val == 0, we change 1 -> 0, return code negative
* wants bitnr, not sector */
-static int bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
+static int bm_change_bits_to(struct drbd_device *device, const unsigned long s,
const unsigned long e, int val)
{
unsigned long flags;
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
int c = 0;
if (!expect(b))
@@ -1455,24 +1445,24 @@ static int bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
spin_lock_irqsave(&b->bm_lock, flags);
if ((val ? BM_DONT_SET : BM_DONT_CLEAR) & b->bm_flags)
- bm_print_lock_info(mdev);
+ bm_print_lock_info(device);
- c = __bm_change_bits_to(mdev, s, e, val);
+ c = __bm_change_bits_to(device, s, e, val);
spin_unlock_irqrestore(&b->bm_lock, flags);
return c;
}
/* returns number of bits changed 0 -> 1 */
-int drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e)
+int drbd_bm_set_bits(struct drbd_device *device, const unsigned long s, const unsigned long e)
{
- return bm_change_bits_to(mdev, s, e, 1);
+ return bm_change_bits_to(device, s, e, 1);
}
/* returns number of bits changed 1 -> 0 */
-int drbd_bm_clear_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e)
+int drbd_bm_clear_bits(struct drbd_device *device, const unsigned long s, const unsigned long e)
{
- return -bm_change_bits_to(mdev, s, e, 0);
+ return -bm_change_bits_to(device, s, e, 0);
}
/* sets all bits in full words,
@@ -1504,7 +1494,7 @@ static inline void bm_set_full_words_within_one_page(struct drbd_bitmap *b,
* You must first drbd_bm_lock().
* Can be called to set the whole bitmap in one go.
* Sets bits from s to e _inclusive_. */
-void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e)
+void _drbd_bm_set_bits(struct drbd_device *device, const unsigned long s, const unsigned long e)
{
/* First set_bit from the first bit (s)
* up to the next long boundary (sl),
@@ -1514,7 +1504,7 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
* Do not use memset, because we must account for changes,
* so we need to loop over the words with hweight() anyways.
*/
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
unsigned long sl = ALIGN(s,BITS_PER_LONG);
unsigned long el = (e+1) & ~((unsigned long)BITS_PER_LONG-1);
int first_page;
@@ -1526,7 +1516,7 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
if (e - s <= 3*BITS_PER_LONG) {
/* don't bother; el and sl may even be wrong. */
spin_lock_irq(&b->bm_lock);
- __bm_change_bits_to(mdev, s, e, 1);
+ __bm_change_bits_to(device, s, e, 1);
spin_unlock_irq(&b->bm_lock);
return;
}
@@ -1537,7 +1527,7 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
/* bits filling the current long */
if (sl)
- __bm_change_bits_to(mdev, s, sl-1, 1);
+ __bm_change_bits_to(device, s, sl-1, 1);
first_page = sl >> (3 + PAGE_SHIFT);
last_page = el >> (3 + PAGE_SHIFT);
@@ -1549,7 +1539,7 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
/* first and full pages, unless first page == last page */
for (page_nr = first_page; page_nr < last_page; page_nr++) {
- bm_set_full_words_within_one_page(mdev->bitmap, page_nr, first_word, last_word);
+ bm_set_full_words_within_one_page(device->bitmap, page_nr, first_word, last_word);
spin_unlock_irq(&b->bm_lock);
cond_resched();
first_word = 0;
@@ -1565,7 +1555,7 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
* as we did not allocate it, it is not present in bitmap->bm_pages.
*/
if (last_word)
- bm_set_full_words_within_one_page(mdev->bitmap, last_page, first_word, last_word);
+ bm_set_full_words_within_one_page(device->bitmap, last_page, first_word, last_word);
/* possibly trailing bits.
* example: (e & 63) == 63, el will be e+1.
@@ -1573,7 +1563,7 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
* it would trigger an assert in __bm_change_bits_to()
*/
if (el <= e)
- __bm_change_bits_to(mdev, el, e, 1);
+ __bm_change_bits_to(device, el, e, 1);
spin_unlock_irq(&b->bm_lock);
}
@@ -1584,10 +1574,10 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
* 0 ... bit not set
* -1 ... first out of bounds access, stop testing for bits!
*/
-int drbd_bm_test_bit(struct drbd_conf *mdev, const unsigned long bitnr)
+int drbd_bm_test_bit(struct drbd_device *device, const unsigned long bitnr)
{
unsigned long flags;
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
unsigned long *p_addr;
int i;
@@ -1598,7 +1588,7 @@ int drbd_bm_test_bit(struct drbd_conf *mdev, const unsigned long bitnr)
spin_lock_irqsave(&b->bm_lock, flags);
if (BM_DONT_TEST & b->bm_flags)
- bm_print_lock_info(mdev);
+ bm_print_lock_info(device);
if (bitnr < b->bm_bits) {
p_addr = bm_map_pidx(b, bm_bit_to_page_idx(b, bitnr));
i = test_bit_le(bitnr & BITS_PER_PAGE_MASK, p_addr) ? 1 : 0;
@@ -1606,7 +1596,7 @@ int drbd_bm_test_bit(struct drbd_conf *mdev, const unsigned long bitnr)
} else if (bitnr == b->bm_bits) {
i = -1;
} else { /* (bitnr > b->bm_bits) */
- dev_err(DEV, "bitnr=%lu > bm_bits=%lu\n", bitnr, b->bm_bits);
+ drbd_err(device, "bitnr=%lu > bm_bits=%lu\n", bitnr, b->bm_bits);
i = 0;
}
@@ -1615,10 +1605,10 @@ int drbd_bm_test_bit(struct drbd_conf *mdev, const unsigned long bitnr)
}
/* returns number of bits set in the range [s, e] */
-int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e)
+int drbd_bm_count_bits(struct drbd_device *device, const unsigned long s, const unsigned long e)
{
unsigned long flags;
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
unsigned long *p_addr = NULL;
unsigned long bitnr;
unsigned int page_nr = -1U;
@@ -1635,7 +1625,7 @@ int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
spin_lock_irqsave(&b->bm_lock, flags);
if (BM_DONT_TEST & b->bm_flags)
- bm_print_lock_info(mdev);
+ bm_print_lock_info(device);
for (bitnr = s; bitnr <= e; bitnr++) {
unsigned int idx = bm_bit_to_page_idx(b, bitnr);
if (page_nr != idx) {
@@ -1647,7 +1637,7 @@ int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
if (expect(bitnr < b->bm_bits))
c += (0 != test_bit_le(bitnr - (page_nr << (PAGE_SHIFT+3)), p_addr));
else
- dev_err(DEV, "bitnr=%lu bm_bits=%lu\n", bitnr, b->bm_bits);
+ drbd_err(device, "bitnr=%lu bm_bits=%lu\n", bitnr, b->bm_bits);
}
if (p_addr)
bm_unmap(p_addr);
@@ -1670,9 +1660,9 @@ int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
* reference count of some bitmap extent element from some lru instead...
*
*/
-int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr)
+int drbd_bm_e_weight(struct drbd_device *device, unsigned long enr)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
int count, s, e;
unsigned long flags;
unsigned long *p_addr, *bm;
@@ -1684,7 +1674,7 @@ int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr)
spin_lock_irqsave(&b->bm_lock, flags);
if (BM_DONT_TEST & b->bm_flags)
- bm_print_lock_info(mdev);
+ bm_print_lock_info(device);
s = S2W(enr);
e = min((size_t)S2W(enr+1), b->bm_words);
@@ -1697,7 +1687,7 @@ int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr)
count += hweight_long(*bm++);
bm_unmap(p_addr);
} else {
- dev_err(DEV, "start offset (%d) too large in drbd_bm_e_weight\n", s);
+ drbd_err(device, "start offset (%d) too large in drbd_bm_e_weight\n", s);
}
spin_unlock_irqrestore(&b->bm_lock, flags);
return count;
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index 0e06f0c5dd1e..e7093d4291f1 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -45,7 +45,9 @@
#include <linux/prefetch.h>
#include <linux/drbd_genl_api.h>
#include <linux/drbd.h>
+#include "drbd_strings.h"
#include "drbd_state.h"
+#include "drbd_protocol.h"
#ifdef __CHECKER__
# define __protected_by(x) __attribute__((require_context(x,1,999,"rdwr")))
@@ -65,6 +67,7 @@
extern unsigned int minor_count;
extern bool disable_sendpage;
extern bool allow_oos;
+void tl_abort_disk_io(struct drbd_device *device);
#ifdef CONFIG_DRBD_FAULT_INJECTION
extern int enable_faults;
@@ -95,25 +98,60 @@ extern char usermode_helper[];
#define UUID_NEW_BM_OFFSET ((u64)0x0001000000000000ULL)
-struct drbd_conf;
-struct drbd_tconn;
-
-
-/* to shorten dev_warn(DEV, "msg"); and relatives statements */
-#define DEV (disk_to_dev(mdev->vdisk))
-
-#define conn_printk(LEVEL, TCONN, FMT, ARGS...) \
- printk(LEVEL "d-con %s: " FMT, TCONN->name , ## ARGS)
-#define conn_alert(TCONN, FMT, ARGS...) conn_printk(KERN_ALERT, TCONN, FMT, ## ARGS)
-#define conn_crit(TCONN, FMT, ARGS...) conn_printk(KERN_CRIT, TCONN, FMT, ## ARGS)
-#define conn_err(TCONN, FMT, ARGS...) conn_printk(KERN_ERR, TCONN, FMT, ## ARGS)
-#define conn_warn(TCONN, FMT, ARGS...) conn_printk(KERN_WARNING, TCONN, FMT, ## ARGS)
-#define conn_notice(TCONN, FMT, ARGS...) conn_printk(KERN_NOTICE, TCONN, FMT, ## ARGS)
-#define conn_info(TCONN, FMT, ARGS...) conn_printk(KERN_INFO, TCONN, FMT, ## ARGS)
-#define conn_dbg(TCONN, FMT, ARGS...) conn_printk(KERN_DEBUG, TCONN, FMT, ## ARGS)
-
-#define D_ASSERT(exp) if (!(exp)) \
- dev_err(DEV, "ASSERT( " #exp " ) in %s:%d\n", __FILE__, __LINE__)
+struct drbd_device;
+struct drbd_connection;
+
+#define __drbd_printk_device(level, device, fmt, args...) \
+ dev_printk(level, disk_to_dev((device)->vdisk), fmt, ## args)
+#define __drbd_printk_peer_device(level, peer_device, fmt, args...) \
+ dev_printk(level, disk_to_dev((peer_device)->device->vdisk), fmt, ## args)
+#define __drbd_printk_resource(level, resource, fmt, args...) \
+ printk(level "drbd %s: " fmt, (resource)->name, ## args)
+#define __drbd_printk_connection(level, connection, fmt, args...) \
+ printk(level "drbd %s: " fmt, (connection)->resource->name, ## args)
+
+void drbd_printk_with_wrong_object_type(void);
+
+#define __drbd_printk_if_same_type(obj, type, func, level, fmt, args...) \
+ (__builtin_types_compatible_p(typeof(obj), type) || \
+ __builtin_types_compatible_p(typeof(obj), const type)), \
+ func(level, (const type)(obj), fmt, ## args)
+
+#define drbd_printk(level, obj, fmt, args...) \
+ __builtin_choose_expr( \
+ __drbd_printk_if_same_type(obj, struct drbd_device *, \
+ __drbd_printk_device, level, fmt, ## args), \
+ __builtin_choose_expr( \
+ __drbd_printk_if_same_type(obj, struct drbd_resource *, \
+ __drbd_printk_resource, level, fmt, ## args), \
+ __builtin_choose_expr( \
+ __drbd_printk_if_same_type(obj, struct drbd_connection *, \
+ __drbd_printk_connection, level, fmt, ## args), \
+ __builtin_choose_expr( \
+ __drbd_printk_if_same_type(obj, struct drbd_peer_device *, \
+ __drbd_printk_peer_device, level, fmt, ## args), \
+ drbd_printk_with_wrong_object_type()))))
+
+#define drbd_dbg(obj, fmt, args...) \
+ drbd_printk(KERN_DEBUG, obj, fmt, ## args)
+#define drbd_alert(obj, fmt, args...) \
+ drbd_printk(KERN_ALERT, obj, fmt, ## args)
+#define drbd_err(obj, fmt, args...) \
+ drbd_printk(KERN_ERR, obj, fmt, ## args)
+#define drbd_warn(obj, fmt, args...) \
+ drbd_printk(KERN_WARNING, obj, fmt, ## args)
+#define drbd_info(obj, fmt, args...) \
+ drbd_printk(KERN_INFO, obj, fmt, ## args)
+#define drbd_emerg(obj, fmt, args...) \
+ drbd_printk(KERN_EMERG, obj, fmt, ## args)
+
+#define dynamic_drbd_dbg(device, fmt, args...) \
+ dynamic_dev_dbg(disk_to_dev(device->vdisk), fmt, ## args)
+
+#define D_ASSERT(device, exp) do { \
+ if (!(exp)) \
+ drbd_err(device, "ASSERT( " #exp " ) in %s:%d\n", __FILE__, __LINE__); \
+ } while (0)
/**
* expect - Make an assertion
@@ -123,7 +161,7 @@ struct drbd_tconn;
#define expect(exp) ({ \
bool _bool = (exp); \
if (!_bool) \
- dev_err(DEV, "ASSERTION %s FAILED in %s\n", \
+ drbd_err(device, "ASSERTION %s FAILED in %s\n", \
#exp, __func__); \
_bool; \
})
@@ -145,14 +183,14 @@ enum {
};
extern unsigned int
-_drbd_insert_fault(struct drbd_conf *mdev, unsigned int type);
+_drbd_insert_fault(struct drbd_device *device, unsigned int type);
static inline int
-drbd_insert_fault(struct drbd_conf *mdev, unsigned int type) {
+drbd_insert_fault(struct drbd_device *device, unsigned int type) {
#ifdef CONFIG_DRBD_FAULT_INJECTION
return fault_rate &&
(enable_faults & (1<<type)) &&
- _drbd_insert_fault(mdev, type);
+ _drbd_insert_fault(device, type);
#else
return 0;
#endif
@@ -164,74 +202,8 @@ drbd_insert_fault(struct drbd_conf *mdev, unsigned int type) {
#define div_floor(A, B) ((A)/(B))
extern struct ratelimit_state drbd_ratelimit_state;
-extern struct idr minors; /* RCU, updates: genl_lock() */
-extern struct list_head drbd_tconns; /* RCU, updates: genl_lock() */
-
-/* on the wire */
-enum drbd_packet {
- /* receiver (data socket) */
- P_DATA = 0x00,
- P_DATA_REPLY = 0x01, /* Response to P_DATA_REQUEST */
- P_RS_DATA_REPLY = 0x02, /* Response to P_RS_DATA_REQUEST */
- P_BARRIER = 0x03,
- P_BITMAP = 0x04,
- P_BECOME_SYNC_TARGET = 0x05,
- P_BECOME_SYNC_SOURCE = 0x06,
- P_UNPLUG_REMOTE = 0x07, /* Used at various times to hint the peer */
- P_DATA_REQUEST = 0x08, /* Used to ask for a data block */
- P_RS_DATA_REQUEST = 0x09, /* Used to ask for a data block for resync */
- P_SYNC_PARAM = 0x0a,
- P_PROTOCOL = 0x0b,
- P_UUIDS = 0x0c,
- P_SIZES = 0x0d,
- P_STATE = 0x0e,
- P_SYNC_UUID = 0x0f,
- P_AUTH_CHALLENGE = 0x10,
- P_AUTH_RESPONSE = 0x11,
- P_STATE_CHG_REQ = 0x12,
-
- /* asender (meta socket */
- P_PING = 0x13,
- P_PING_ACK = 0x14,
- P_RECV_ACK = 0x15, /* Used in protocol B */
- P_WRITE_ACK = 0x16, /* Used in protocol C */
- P_RS_WRITE_ACK = 0x17, /* Is a P_WRITE_ACK, additionally call set_in_sync(). */
- P_SUPERSEDED = 0x18, /* Used in proto C, two-primaries conflict detection */
- P_NEG_ACK = 0x19, /* Sent if local disk is unusable */
- P_NEG_DREPLY = 0x1a, /* Local disk is broken... */
- P_NEG_RS_DREPLY = 0x1b, /* Local disk is broken... */
- P_BARRIER_ACK = 0x1c,
- P_STATE_CHG_REPLY = 0x1d,
-
- /* "new" commands, no longer fitting into the ordering scheme above */
-
- P_OV_REQUEST = 0x1e, /* data socket */
- P_OV_REPLY = 0x1f,
- P_OV_RESULT = 0x20, /* meta socket */
- P_CSUM_RS_REQUEST = 0x21, /* data socket */
- P_RS_IS_IN_SYNC = 0x22, /* meta socket */
- P_SYNC_PARAM89 = 0x23, /* data socket, protocol version 89 replacement for P_SYNC_PARAM */
- P_COMPRESSED_BITMAP = 0x24, /* compressed or otherwise encoded bitmap transfer */
- /* P_CKPT_FENCE_REQ = 0x25, * currently reserved for protocol D */
- /* P_CKPT_DISABLE_REQ = 0x26, * currently reserved for protocol D */
- P_DELAY_PROBE = 0x27, /* is used on BOTH sockets */
- P_OUT_OF_SYNC = 0x28, /* Mark as out of sync (Outrunning), data socket */
- P_RS_CANCEL = 0x29, /* meta: Used to cancel RS_DATA_REQUEST packet by SyncSource */
- P_CONN_ST_CHG_REQ = 0x2a, /* data sock: Connection wide state request */
- P_CONN_ST_CHG_REPLY = 0x2b, /* meta sock: Connection side state req reply */
- P_RETRY_WRITE = 0x2c, /* Protocol C: retry conflicting write request */
- P_PROTOCOL_UPDATE = 0x2d, /* data sock: is used in established connections */
-
- P_MAY_IGNORE = 0x100, /* Flag to test if (cmd > P_MAY_IGNORE) ... */
- P_MAX_OPT_CMD = 0x101,
-
- /* special command ids for handshake */
-
- P_INITIAL_META = 0xfff1, /* First Packet on the MetaSock */
- P_INITIAL_DATA = 0xfff2, /* First Packet on the Socket */
-
- P_CONNECTION_FEATURES = 0xfffe /* FIXED for the next century! */
-};
+extern struct idr drbd_devices; /* RCU, updates: genl_lock() */
+extern struct list_head drbd_resources; /* RCU, updates: genl_lock() */
extern const char *cmdname(enum drbd_packet cmd);
@@ -253,7 +225,7 @@ struct bm_xfer_ctx {
unsigned bytes[2];
};
-extern void INFO_bm_xfer_stats(struct drbd_conf *mdev,
+extern void INFO_bm_xfer_stats(struct drbd_device *device,
const char *direction, struct bm_xfer_ctx *c);
static inline void bm_xfer_ctx_bit_to_word_offset(struct bm_xfer_ctx *c)
@@ -275,233 +247,7 @@ static inline void bm_xfer_ctx_bit_to_word_offset(struct bm_xfer_ctx *c)
#endif
}
-#ifndef __packed
-#define __packed __attribute__((packed))
-#endif
-
-/* This is the layout for a packet on the wire.
- * The byteorder is the network byte order.
- * (except block_id and barrier fields.
- * these are pointers to local structs
- * and have no relevance for the partner,
- * which just echoes them as received.)
- *
- * NOTE that the payload starts at a long aligned offset,
- * regardless of 32 or 64 bit arch!
- */
-struct p_header80 {
- u32 magic;
- u16 command;
- u16 length; /* bytes of data after this header */
-} __packed;
-
-/* Header for big packets, Used for data packets exceeding 64kB */
-struct p_header95 {
- u16 magic; /* use DRBD_MAGIC_BIG here */
- u16 command;
- u32 length;
-} __packed;
-
-struct p_header100 {
- u32 magic;
- u16 volume;
- u16 command;
- u32 length;
- u32 pad;
-} __packed;
-
-extern unsigned int drbd_header_size(struct drbd_tconn *tconn);
-
-/* these defines must not be changed without changing the protocol version */
-#define DP_HARDBARRIER 1 /* depricated */
-#define DP_RW_SYNC 2 /* equals REQ_SYNC */
-#define DP_MAY_SET_IN_SYNC 4
-#define DP_UNPLUG 8 /* not used anymore */
-#define DP_FUA 16 /* equals REQ_FUA */
-#define DP_FLUSH 32 /* equals REQ_FLUSH */
-#define DP_DISCARD 64 /* equals REQ_DISCARD */
-#define DP_SEND_RECEIVE_ACK 128 /* This is a proto B write request */
-#define DP_SEND_WRITE_ACK 256 /* This is a proto C write request */
-
-struct p_data {
- u64 sector; /* 64 bits sector number */
- u64 block_id; /* to identify the request in protocol B&C */
- u32 seq_num;
- u32 dp_flags;
-} __packed;
-
-/*
- * commands which share a struct:
- * p_block_ack:
- * P_RECV_ACK (proto B), P_WRITE_ACK (proto C),
- * P_SUPERSEDED (proto C, two-primaries conflict detection)
- * p_block_req:
- * P_DATA_REQUEST, P_RS_DATA_REQUEST
- */
-struct p_block_ack {
- u64 sector;
- u64 block_id;
- u32 blksize;
- u32 seq_num;
-} __packed;
-
-struct p_block_req {
- u64 sector;
- u64 block_id;
- u32 blksize;
- u32 pad; /* to multiple of 8 Byte */
-} __packed;
-
-/*
- * commands with their own struct for additional fields:
- * P_CONNECTION_FEATURES
- * P_BARRIER
- * P_BARRIER_ACK
- * P_SYNC_PARAM
- * ReportParams
- */
-
-struct p_connection_features {
- u32 protocol_min;
- u32 feature_flags;
- u32 protocol_max;
-
- /* should be more than enough for future enhancements
- * for now, feature_flags and the reserved array shall be zero.
- */
-
- u32 _pad;
- u64 reserved[7];
-} __packed;
-
-struct p_barrier {
- u32 barrier; /* barrier number _handle_ only */
- u32 pad; /* to multiple of 8 Byte */
-} __packed;
-
-struct p_barrier_ack {
- u32 barrier;
- u32 set_size;
-} __packed;
-
-struct p_rs_param {
- u32 resync_rate;
-
- /* Since protocol version 88 and higher. */
- char verify_alg[0];
-} __packed;
-
-struct p_rs_param_89 {
- u32 resync_rate;
- /* protocol version 89: */
- char verify_alg[SHARED_SECRET_MAX];
- char csums_alg[SHARED_SECRET_MAX];
-} __packed;
-
-struct p_rs_param_95 {
- u32 resync_rate;
- char verify_alg[SHARED_SECRET_MAX];
- char csums_alg[SHARED_SECRET_MAX];
- u32 c_plan_ahead;
- u32 c_delay_target;
- u32 c_fill_target;
- u32 c_max_rate;
-} __packed;
-
-enum drbd_conn_flags {
- CF_DISCARD_MY_DATA = 1,
- CF_DRY_RUN = 2,
-};
-
-struct p_protocol {
- u32 protocol;
- u32 after_sb_0p;
- u32 after_sb_1p;
- u32 after_sb_2p;
- u32 conn_flags;
- u32 two_primaries;
-
- /* Since protocol version 87 and higher. */
- char integrity_alg[0];
-
-} __packed;
-
-struct p_uuids {
- u64 uuid[UI_EXTENDED_SIZE];
-} __packed;
-
-struct p_rs_uuid {
- u64 uuid;
-} __packed;
-
-struct p_sizes {
- u64 d_size; /* size of disk */
- u64 u_size; /* user requested size */
- u64 c_size; /* current exported size */
- u32 max_bio_size; /* Maximal size of a BIO */
- u16 queue_order_type; /* not yet implemented in DRBD*/
- u16 dds_flags; /* use enum dds_flags here. */
-} __packed;
-
-struct p_state {
- u32 state;
-} __packed;
-
-struct p_req_state {
- u32 mask;
- u32 val;
-} __packed;
-
-struct p_req_state_reply {
- u32 retcode;
-} __packed;
-
-struct p_drbd06_param {
- u64 size;
- u32 state;
- u32 blksize;
- u32 protocol;
- u32 version;
- u32 gen_cnt[5];
- u32 bit_map_gen[5];
-} __packed;
-
-struct p_block_desc {
- u64 sector;
- u32 blksize;
- u32 pad; /* to multiple of 8 Byte */
-} __packed;
-
-/* Valid values for the encoding field.
- * Bump proto version when changing this. */
-enum drbd_bitmap_code {
- /* RLE_VLI_Bytes = 0,
- * and other bit variants had been defined during
- * algorithm evaluation. */
- RLE_VLI_Bits = 2,
-};
-
-struct p_compressed_bm {
- /* (encoding & 0x0f): actual encoding, see enum drbd_bitmap_code
- * (encoding & 0x80): polarity (set/unset) of first runlength
- * ((encoding >> 4) & 0x07): pad_bits, number of trailing zero bits
- * used to pad up to head.length bytes
- */
- u8 encoding;
-
- u8 code[0];
-} __packed;
-
-struct p_delay_probe93 {
- u32 seq_num; /* sequence number to match the two probe packets */
- u32 offset; /* usecs the probe got sent after the reference time point */
-} __packed;
-
-/*
- * Bitmap packets need to fit within a single page on the sender and receiver,
- * so we are limited to 4 KiB (and not to PAGE_SIZE, which can be bigger).
- */
-#define DRBD_SOCKET_BUFFER_SIZE 4096
+extern unsigned int drbd_header_size(struct drbd_connection *connection);
/**********************************************************************/
enum drbd_thread_state {
@@ -517,9 +263,10 @@ struct drbd_thread {
struct completion stop;
enum drbd_thread_state t_state;
int (*function) (struct drbd_thread *);
- struct drbd_tconn *tconn;
+ struct drbd_resource *resource;
+ struct drbd_connection *connection;
int reset_cpu_mask;
- char name[9];
+ const char *name;
};
static inline enum drbd_thread_state get_t_state(struct drbd_thread *thi)
@@ -535,18 +282,20 @@ static inline enum drbd_thread_state get_t_state(struct drbd_thread *thi)
struct drbd_work {
struct list_head list;
int (*cb)(struct drbd_work *, int cancel);
- union {
- struct drbd_conf *mdev;
- struct drbd_tconn *tconn;
- };
+};
+
+struct drbd_device_work {
+ struct drbd_work w;
+ struct drbd_device *device;
};
#include "drbd_interval.h"
-extern int drbd_wait_misc(struct drbd_conf *, struct drbd_interval *);
+extern int drbd_wait_misc(struct drbd_device *, struct drbd_interval *);
struct drbd_request {
struct drbd_work w;
+ struct drbd_device *device;
/* if local IO is not allowed, will be NULL.
* if local IO _is_ allowed, holds the locally submitted bio clone,
@@ -579,7 +328,7 @@ struct drbd_request {
};
struct drbd_epoch {
- struct drbd_tconn *tconn;
+ struct drbd_connection *connection;
struct list_head list;
unsigned int barrier_nr;
atomic_t epoch_size; /* increased on every request added. */
@@ -587,6 +336,10 @@ struct drbd_epoch {
unsigned long flags;
};
+/* Prototype declaration of function defined in drbd_receiver.c */
+int drbdd_init(struct drbd_thread *);
+int drbd_asender(struct drbd_thread *);
+
/* drbd_epoch flag bits */
enum {
DE_HAVE_BARRIER_NUMBER,
@@ -599,11 +352,6 @@ enum epoch_event {
EV_CLEANUP = 32, /* used as flag */
};
-struct drbd_wq_barrier {
- struct drbd_work w;
- struct completion done;
-};
-
struct digest_info {
int digest_size;
void *digest;
@@ -611,6 +359,7 @@ struct digest_info {
struct drbd_peer_request {
struct drbd_work w;
+ struct drbd_peer_device *peer_device;
struct drbd_epoch *epoch; /* for writes */
struct page *pages;
atomic_t pending_bios;
@@ -663,7 +412,7 @@ enum {
#define EE_SEND_WRITE_ACK (1<<__EE_SEND_WRITE_ACK)
#define EE_IN_INTERVAL_TREE (1<<__EE_IN_INTERVAL_TREE)
-/* flag bits per mdev */
+/* flag bits per device */
enum {
UNPLUG_REMOTE, /* sending a "UnplugRemote" could help */
MD_DIRTY, /* current uuids and flags not yet on disk */
@@ -695,7 +444,7 @@ enum {
READ_BALANCE_RR,
};
-struct drbd_bitmap; /* opaque for drbd_conf */
+struct drbd_bitmap; /* opaque for drbd_device */
/* definition of bits in bm_flags to be used in drbd_bm_lock
* and drbd_bitmap_io and friends. */
@@ -769,7 +518,7 @@ struct drbd_backing_dev {
struct block_device *backing_bdev;
struct block_device *md_bdev;
struct drbd_md md;
- struct disk_conf *disk_conf; /* RCU, for updates: mdev->tconn->conf_update */
+ struct disk_conf *disk_conf; /* RCU, for updates: resource->conf_update */
sector_t known_size; /* last known size of that backing device */
};
@@ -782,8 +531,8 @@ struct bm_io_work {
struct drbd_work w;
char *why;
enum bm_flag flags;
- int (*io_fn)(struct drbd_conf *mdev);
- void (*done)(struct drbd_conf *mdev, int rv);
+ int (*io_fn)(struct drbd_device *device);
+ void (*done)(struct drbd_device *device, int rv);
};
enum write_ordering_e {
@@ -800,7 +549,7 @@ struct fifo_buffer {
};
extern struct fifo_buffer *fifo_alloc(int fifo_size);
-/* flag bits per tconn */
+/* flag bits per connection */
enum {
NET_CONGESTED, /* The data socket is congested */
RESOLVE_CONFLICTS, /* Set on one node, cleared on the peer! */
@@ -822,23 +571,35 @@ enum {
DISCONNECT_SENT,
};
-struct drbd_tconn { /* is a resource from the config file */
- char *name; /* Resource name */
- struct list_head all_tconn; /* linked on global drbd_tconns */
+struct drbd_resource {
+ char *name;
struct kref kref;
- struct idr volumes; /* <tconn, vnr> to mdev mapping */
- enum drbd_conns cstate; /* Only C_STANDALONE to C_WF_REPORT_PARAMS */
+ struct idr devices; /* volume number to device mapping */
+ struct list_head connections;
+ struct list_head resources;
+ struct res_opts res_opts;
+ struct mutex conf_update; /* mutex for ready-copy-update of net_conf and disk_conf */
+ spinlock_t req_lock;
+
unsigned susp:1; /* IO suspended by user */
unsigned susp_nod:1; /* IO suspended because no data */
unsigned susp_fen:1; /* IO suspended because fence peer handler runs */
+
+ cpumask_var_t cpu_mask;
+};
+
+struct drbd_connection {
+ struct list_head connections;
+ struct drbd_resource *resource;
+ struct kref kref;
+ struct idr peer_devices; /* volume number to peer device mapping */
+ enum drbd_conns cstate; /* Only C_STANDALONE to C_WF_REPORT_PARAMS */
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 */
- struct mutex conf_update; /* mutex for ready-copy-update of net_conf and disk_conf */
wait_queue_head_t ping_wait; /* Woken upon reception of a ping, and a state change */
- struct res_opts res_opts;
struct sockaddr_storage my_addr;
int my_addr_len;
@@ -851,12 +612,10 @@ struct drbd_tconn { /* is a resource from the config file */
unsigned long last_received; /* in jiffies, either socket */
unsigned int ko_count;
- spinlock_t req_lock;
-
struct list_head transfer_log; /* all requests not yet fully processed */
struct crypto_hash *cram_hmac_tfm;
- struct crypto_hash *integrity_tfm; /* checksums we compute, updates protected by tconn->data->mutex */
+ struct crypto_hash *integrity_tfm; /* checksums we compute, updates protected by connection->data->mutex */
struct crypto_hash *peer_integrity_tfm; /* checksums we verify, only accessed from receiver thread */
struct crypto_hash *csums_tfm;
struct crypto_hash *verify_tfm;
@@ -875,7 +634,6 @@ struct drbd_tconn { /* is a resource from the config file */
struct drbd_thread receiver;
struct drbd_thread worker;
struct drbd_thread asender;
- cpumask_var_t cpu_mask;
/* sender side */
struct drbd_work_queue sender_work;
@@ -903,8 +661,15 @@ struct submit_worker {
struct list_head writes;
};
-struct drbd_conf {
- struct drbd_tconn *tconn;
+struct drbd_peer_device {
+ struct list_head peer_devices;
+ struct drbd_device *device;
+ struct drbd_connection *connection;
+};
+
+struct drbd_device {
+ struct drbd_resource *resource;
+ struct list_head peer_devices;
int vnr; /* volume number within the connection */
struct kref kref;
@@ -920,11 +685,11 @@ struct drbd_conf {
struct gendisk *vdisk;
unsigned long last_reattach_jif;
- struct drbd_work resync_work,
- unplug_work,
- go_diskless,
- md_sync_work,
- start_resync_work;
+ struct drbd_work resync_work;
+ struct drbd_work unplug_work;
+ struct drbd_work go_diskless;
+ struct drbd_work md_sync_work;
+ struct drbd_work start_resync_work;
struct timer_list resync_timer;
struct timer_list md_sync_timer;
struct timer_list start_resync_timer;
@@ -1030,7 +795,7 @@ struct drbd_conf {
struct bm_io_work bm_io_work;
u64 ed_uuid; /* UUID of the exposed data */
struct mutex own_state_mutex;
- struct mutex *state_mutex; /* either own_state_mutex or mdev->tconn->cstate_mutex */
+ struct mutex *state_mutex; /* either own_state_mutex or first_peer_device(device)->connection->cstate_mutex */
char congestion_reason; /* Why we where congested... */
atomic_t rs_sect_in; /* for incoming resync data rate, SyncTarget */
atomic_t rs_sect_ev; /* for submitted resync data rate, both */
@@ -1038,7 +803,7 @@ struct drbd_conf {
int rs_last_events; /* counter of read or write "events" (unit sectors)
* on the lower level device when we last looked. */
int c_sync_rate; /* current resync rate after syncer throttle magic */
- struct fifo_buffer *rs_plan_s; /* correction values of resync planer (RCU, tconn->conn_update) */
+ struct fifo_buffer *rs_plan_s; /* correction values of resync planer (RCU, connection->conn_update) */
int rs_in_flight; /* resync sectors in flight (to proxy, in proxy and from proxy) */
atomic_t ap_in_flight; /* App sectors in flight (waiting for ack) */
unsigned int peer_max_bio_size;
@@ -1049,19 +814,46 @@ struct drbd_conf {
struct submit_worker submit;
};
-static inline struct drbd_conf *minor_to_mdev(unsigned int minor)
+static inline struct drbd_device *minor_to_device(unsigned int minor)
{
- return (struct drbd_conf *)idr_find(&minors, minor);
+ return (struct drbd_device *)idr_find(&drbd_devices, minor);
}
-static inline unsigned int mdev_to_minor(struct drbd_conf *mdev)
+static inline struct drbd_peer_device *first_peer_device(struct drbd_device *device)
{
- return mdev->minor;
+ return list_first_entry(&device->peer_devices, struct drbd_peer_device, peer_devices);
}
-static inline struct drbd_conf *vnr_to_mdev(struct drbd_tconn *tconn, int vnr)
+#define for_each_resource(resource, _resources) \
+ list_for_each_entry(resource, _resources, resources)
+
+#define for_each_resource_rcu(resource, _resources) \
+ list_for_each_entry_rcu(resource, _resources, resources)
+
+#define for_each_resource_safe(resource, tmp, _resources) \
+ list_for_each_entry_safe(resource, tmp, _resources, resources)
+
+#define for_each_connection(connection, resource) \
+ list_for_each_entry(connection, &resource->connections, connections)
+
+#define for_each_connection_rcu(connection, resource) \
+ list_for_each_entry_rcu(connection, &resource->connections, connections)
+
+#define for_each_connection_safe(connection, tmp, resource) \
+ list_for_each_entry_safe(connection, tmp, &resource->connections, connections)
+
+#define for_each_peer_device(peer_device, device) \
+ list_for_each_entry(peer_device, &device->peer_devices, peer_devices)
+
+#define for_each_peer_device_rcu(peer_device, device) \
+ list_for_each_entry_rcu(peer_device, &device->peer_devices, peer_devices)
+
+#define for_each_peer_device_safe(peer_device, tmp, device) \
+ list_for_each_entry_safe(peer_device, tmp, &device->peer_devices, peer_devices)
+
+static inline unsigned int device_to_minor(struct drbd_device *device)
{
- return (struct drbd_conf *)idr_find(&tconn->volumes, vnr);
+ return device->minor;
}
/*
@@ -1075,96 +867,93 @@ enum dds_flags {
DDSF_NO_RESYNC = 2, /* Do not run a resync for the new space */
};
-extern void drbd_init_set_defaults(struct drbd_conf *mdev);
+extern void drbd_init_set_defaults(struct drbd_device *device);
extern int drbd_thread_start(struct drbd_thread *thi);
extern void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait);
-extern char *drbd_task_to_thread_name(struct drbd_tconn *tconn, struct task_struct *task);
#ifdef CONFIG_SMP
extern void drbd_thread_current_set_cpu(struct drbd_thread *thi);
-extern void drbd_calc_cpu_mask(struct drbd_tconn *tconn);
#else
#define drbd_thread_current_set_cpu(A) ({})
-#define drbd_calc_cpu_mask(A) ({})
#endif
-extern void tl_release(struct drbd_tconn *, unsigned int barrier_nr,
+extern void tl_release(struct drbd_connection *, unsigned int barrier_nr,
unsigned int set_size);
-extern void tl_clear(struct drbd_tconn *);
-extern void drbd_free_sock(struct drbd_tconn *tconn);
-extern int drbd_send(struct drbd_tconn *tconn, struct socket *sock,
+extern void tl_clear(struct drbd_connection *);
+extern void drbd_free_sock(struct drbd_connection *connection);
+extern int drbd_send(struct drbd_connection *connection, struct socket *sock,
void *buf, size_t size, unsigned msg_flags);
-extern int drbd_send_all(struct drbd_tconn *, struct socket *, void *, size_t,
+extern int drbd_send_all(struct drbd_connection *, struct socket *, void *, size_t,
unsigned);
-extern int __drbd_send_protocol(struct drbd_tconn *tconn, enum drbd_packet cmd);
-extern int drbd_send_protocol(struct drbd_tconn *tconn);
-extern int drbd_send_uuids(struct drbd_conf *mdev);
-extern int drbd_send_uuids_skip_initial_sync(struct drbd_conf *mdev);
-extern void drbd_gen_and_send_sync_uuid(struct drbd_conf *mdev);
-extern int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags flags);
-extern int drbd_send_state(struct drbd_conf *mdev, union drbd_state s);
-extern int drbd_send_current_state(struct drbd_conf *mdev);
-extern int drbd_send_sync_param(struct drbd_conf *mdev);
-extern void drbd_send_b_ack(struct drbd_tconn *tconn, u32 barrier_nr,
+extern int __drbd_send_protocol(struct drbd_connection *connection, enum drbd_packet cmd);
+extern int drbd_send_protocol(struct drbd_connection *connection);
+extern int drbd_send_uuids(struct drbd_peer_device *);
+extern int drbd_send_uuids_skip_initial_sync(struct drbd_peer_device *);
+extern void drbd_gen_and_send_sync_uuid(struct drbd_peer_device *);
+extern int drbd_send_sizes(struct drbd_peer_device *, int trigger_reply, enum dds_flags flags);
+extern int drbd_send_state(struct drbd_peer_device *, union drbd_state s);
+extern int drbd_send_current_state(struct drbd_peer_device *);
+extern int drbd_send_sync_param(struct drbd_peer_device *);
+extern void drbd_send_b_ack(struct drbd_connection *connection, u32 barrier_nr,
u32 set_size);
-extern int drbd_send_ack(struct drbd_conf *, enum drbd_packet,
+extern int drbd_send_ack(struct drbd_peer_device *, enum drbd_packet,
struct drbd_peer_request *);
-extern void drbd_send_ack_rp(struct drbd_conf *mdev, enum drbd_packet cmd,
+extern void drbd_send_ack_rp(struct drbd_peer_device *, enum drbd_packet,
struct p_block_req *rp);
-extern void drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packet cmd,
+extern void drbd_send_ack_dp(struct drbd_peer_device *, enum drbd_packet,
struct p_data *dp, int data_size);
-extern int drbd_send_ack_ex(struct drbd_conf *mdev, enum drbd_packet cmd,
+extern int drbd_send_ack_ex(struct drbd_peer_device *, enum drbd_packet,
sector_t sector, int blksize, u64 block_id);
-extern int drbd_send_out_of_sync(struct drbd_conf *, struct drbd_request *);
-extern int drbd_send_block(struct drbd_conf *, enum drbd_packet,
+extern int drbd_send_out_of_sync(struct drbd_peer_device *, struct drbd_request *);
+extern int drbd_send_block(struct drbd_peer_device *, enum drbd_packet,
struct drbd_peer_request *);
-extern int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req);
-extern int drbd_send_drequest(struct drbd_conf *mdev, int cmd,
+extern int drbd_send_dblock(struct drbd_peer_device *, struct drbd_request *req);
+extern int drbd_send_drequest(struct drbd_peer_device *, int cmd,
sector_t sector, int size, u64 block_id);
-extern int drbd_send_drequest_csum(struct drbd_conf *mdev, sector_t sector,
+extern int drbd_send_drequest_csum(struct drbd_peer_device *, sector_t sector,
int size, void *digest, int digest_size,
enum drbd_packet cmd);
-extern int drbd_send_ov_request(struct drbd_conf *mdev,sector_t sector,int size);
+extern int drbd_send_ov_request(struct drbd_peer_device *, sector_t sector, int size);
-extern int drbd_send_bitmap(struct drbd_conf *mdev);
-extern void drbd_send_sr_reply(struct drbd_conf *mdev, enum drbd_state_rv retcode);
-extern void conn_send_sr_reply(struct drbd_tconn *tconn, enum drbd_state_rv retcode);
+extern int drbd_send_bitmap(struct drbd_device *device);
+extern void drbd_send_sr_reply(struct drbd_peer_device *, enum drbd_state_rv retcode);
+extern void conn_send_sr_reply(struct drbd_connection *connection, enum drbd_state_rv retcode);
extern void drbd_free_bc(struct drbd_backing_dev *ldev);
-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);
-extern void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local);
-extern void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local);
-extern void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local);
-extern void drbd_uuid_move_history(struct drbd_conf *mdev) __must_hold(local);
-extern void __drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local);
-extern void drbd_md_set_flag(struct drbd_conf *mdev, int flags) __must_hold(local);
-extern void drbd_md_clear_flag(struct drbd_conf *mdev, int flags)__must_hold(local);
+extern void drbd_device_cleanup(struct drbd_device *device);
+void drbd_print_uuids(struct drbd_device *device, const char *text);
+
+extern void conn_md_sync(struct drbd_connection *connection);
+extern void drbd_md_write(struct drbd_device *device, void *buffer);
+extern void drbd_md_sync(struct drbd_device *device);
+extern int drbd_md_read(struct drbd_device *device, struct drbd_backing_dev *bdev);
+extern void drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local);
+extern void _drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local);
+extern void drbd_uuid_new_current(struct drbd_device *device) __must_hold(local);
+extern void drbd_uuid_set_bm(struct drbd_device *device, u64 val) __must_hold(local);
+extern void drbd_uuid_move_history(struct drbd_device *device) __must_hold(local);
+extern void __drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local);
+extern void drbd_md_set_flag(struct drbd_device *device, int flags) __must_hold(local);
+extern void drbd_md_clear_flag(struct drbd_device *device, int flags)__must_hold(local);
extern int drbd_md_test_flag(struct drbd_backing_dev *, int);
#ifndef DRBD_DEBUG_MD_SYNC
-extern void drbd_md_mark_dirty(struct drbd_conf *mdev);
+extern void drbd_md_mark_dirty(struct drbd_device *device);
#else
#define drbd_md_mark_dirty(m) drbd_md_mark_dirty_(m, __LINE__ , __func__ )
-extern void drbd_md_mark_dirty_(struct drbd_conf *mdev,
+extern void drbd_md_mark_dirty_(struct drbd_device *device,
unsigned int line, const char *func);
#endif
-extern void drbd_queue_bitmap_io(struct drbd_conf *mdev,
- int (*io_fn)(struct drbd_conf *),
- void (*done)(struct drbd_conf *, int),
+extern void drbd_queue_bitmap_io(struct drbd_device *device,
+ int (*io_fn)(struct drbd_device *),
+ void (*done)(struct drbd_device *, int),
char *why, enum bm_flag flags);
-extern int drbd_bitmap_io(struct drbd_conf *mdev,
- int (*io_fn)(struct drbd_conf *),
+extern int drbd_bitmap_io(struct drbd_device *device,
+ int (*io_fn)(struct drbd_device *),
char *why, enum bm_flag flags);
-extern int drbd_bitmap_io_from_worker(struct drbd_conf *mdev,
- int (*io_fn)(struct drbd_conf *),
+extern int drbd_bitmap_io_from_worker(struct drbd_device *device,
+ int (*io_fn)(struct drbd_device *),
char *why, enum bm_flag flags);
-extern int drbd_bmio_set_n_write(struct drbd_conf *mdev);
-extern int drbd_bmio_clear_n_write(struct drbd_conf *mdev);
-extern void drbd_ldev_destroy(struct drbd_conf *mdev);
+extern int drbd_bmio_set_n_write(struct drbd_device *device);
+extern int drbd_bmio_clear_n_write(struct drbd_device *device);
+extern void drbd_ldev_destroy(struct drbd_device *device);
/* Meta data layout
*
@@ -1350,52 +1139,52 @@ struct bm_extent {
#define DRBD_MAX_SIZE_H80_PACKET (1U << 15) /* Header 80 only allows packets up to 32KiB data */
#define DRBD_MAX_BIO_SIZE_P95 (1U << 17) /* Protocol 95 to 99 allows bios up to 128KiB */
-extern int drbd_bm_init(struct drbd_conf *mdev);
-extern int drbd_bm_resize(struct drbd_conf *mdev, sector_t sectors, int set_new_bits);
-extern void drbd_bm_cleanup(struct drbd_conf *mdev);
-extern void drbd_bm_set_all(struct drbd_conf *mdev);
-extern void drbd_bm_clear_all(struct drbd_conf *mdev);
+extern int drbd_bm_init(struct drbd_device *device);
+extern int drbd_bm_resize(struct drbd_device *device, sector_t sectors, int set_new_bits);
+extern void drbd_bm_cleanup(struct drbd_device *device);
+extern void drbd_bm_set_all(struct drbd_device *device);
+extern void drbd_bm_clear_all(struct drbd_device *device);
/* set/clear/test only a few bits at a time */
extern int drbd_bm_set_bits(
- struct drbd_conf *mdev, unsigned long s, unsigned long e);
+ struct drbd_device *device, unsigned long s, unsigned long e);
extern int drbd_bm_clear_bits(
- struct drbd_conf *mdev, unsigned long s, unsigned long e);
+ struct drbd_device *device, unsigned long s, unsigned long e);
extern int drbd_bm_count_bits(
- struct drbd_conf *mdev, const unsigned long s, const unsigned long e);
+ struct drbd_device *device, const unsigned long s, const unsigned long e);
/* bm_set_bits variant for use while holding drbd_bm_lock,
* may process the whole bitmap in one go */
-extern void _drbd_bm_set_bits(struct drbd_conf *mdev,
+extern void _drbd_bm_set_bits(struct drbd_device *device,
const unsigned long s, const unsigned long e);
-extern int drbd_bm_test_bit(struct drbd_conf *mdev, unsigned long bitnr);
-extern int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr);
-extern int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(local);
-extern int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local);
-extern void drbd_bm_mark_for_writeout(struct drbd_conf *mdev, int page_nr);
-extern int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local);
-extern int drbd_bm_write_hinted(struct drbd_conf *mdev) __must_hold(local);
-extern int drbd_bm_write_all(struct drbd_conf *mdev) __must_hold(local);
-extern int drbd_bm_write_copy_pages(struct drbd_conf *mdev) __must_hold(local);
-extern size_t drbd_bm_words(struct drbd_conf *mdev);
-extern unsigned long drbd_bm_bits(struct drbd_conf *mdev);
-extern sector_t drbd_bm_capacity(struct drbd_conf *mdev);
+extern int drbd_bm_test_bit(struct drbd_device *device, unsigned long bitnr);
+extern int drbd_bm_e_weight(struct drbd_device *device, unsigned long enr);
+extern int drbd_bm_write_page(struct drbd_device *device, unsigned int idx) __must_hold(local);
+extern int drbd_bm_read(struct drbd_device *device) __must_hold(local);
+extern void drbd_bm_mark_for_writeout(struct drbd_device *device, int page_nr);
+extern int drbd_bm_write(struct drbd_device *device) __must_hold(local);
+extern int drbd_bm_write_hinted(struct drbd_device *device) __must_hold(local);
+extern int drbd_bm_write_all(struct drbd_device *device) __must_hold(local);
+extern int drbd_bm_write_copy_pages(struct drbd_device *device) __must_hold(local);
+extern size_t drbd_bm_words(struct drbd_device *device);
+extern unsigned long drbd_bm_bits(struct drbd_device *device);
+extern sector_t drbd_bm_capacity(struct drbd_device *device);
#define DRBD_END_OF_BITMAP (~(unsigned long)0)
-extern unsigned long drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo);
+extern unsigned long drbd_bm_find_next(struct drbd_device *device, unsigned long bm_fo);
/* bm_find_next variants for use while you hold drbd_bm_lock() */
-extern unsigned long _drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo);
-extern unsigned long _drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo);
-extern unsigned long _drbd_bm_total_weight(struct drbd_conf *mdev);
-extern unsigned long drbd_bm_total_weight(struct drbd_conf *mdev);
-extern int drbd_bm_rs_done(struct drbd_conf *mdev);
+extern unsigned long _drbd_bm_find_next(struct drbd_device *device, unsigned long bm_fo);
+extern unsigned long _drbd_bm_find_next_zero(struct drbd_device *device, unsigned long bm_fo);
+extern unsigned long _drbd_bm_total_weight(struct drbd_device *device);
+extern unsigned long drbd_bm_total_weight(struct drbd_device *device);
+extern int drbd_bm_rs_done(struct drbd_device *device);
/* for receive_bitmap */
-extern void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset,
+extern void drbd_bm_merge_lel(struct drbd_device *device, size_t offset,
size_t number, unsigned long *buffer);
/* for _drbd_send_bitmap */
-extern void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset,
+extern void drbd_bm_get_lel(struct drbd_device *device, size_t offset,
size_t number, unsigned long *buffer);
-extern void drbd_bm_lock(struct drbd_conf *mdev, char *why, enum bm_flag flags);
-extern void drbd_bm_unlock(struct drbd_conf *mdev);
+extern void drbd_bm_lock(struct drbd_device *device, char *why, enum bm_flag flags);
+extern void drbd_bm_unlock(struct drbd_device *device);
/* drbd_main.c */
extern struct kmem_cache *drbd_request_cache;
@@ -1439,35 +1228,40 @@ extern struct bio *bio_alloc_drbd(gfp_t gfp_mask);
extern rwlock_t global_state_lock;
-extern int conn_lowest_minor(struct drbd_tconn *tconn);
-enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor, int vnr);
-extern void drbd_minor_destroy(struct kref *kref);
+extern int conn_lowest_minor(struct drbd_connection *connection);
+enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned int minor, int vnr);
+extern void drbd_destroy_device(struct kref *kref);
+extern void drbd_delete_device(struct drbd_device *mdev);
+
+extern struct drbd_resource *drbd_create_resource(const char *name);
+extern void drbd_free_resource(struct drbd_resource *resource);
-extern int set_resource_options(struct drbd_tconn *tconn, struct res_opts *res_opts);
-extern struct drbd_tconn *conn_create(const char *name, struct res_opts *res_opts);
-extern void conn_destroy(struct kref *kref);
-struct drbd_tconn *conn_get_by_name(const char *name);
-extern struct drbd_tconn *conn_get_by_addrs(void *my_addr, int my_addr_len,
+extern int set_resource_options(struct drbd_resource *resource, struct res_opts *res_opts);
+extern struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts);
+extern void drbd_destroy_connection(struct kref *kref);
+extern struct drbd_connection *conn_get_by_addrs(void *my_addr, int my_addr_len,
void *peer_addr, int peer_addr_len);
-extern void conn_free_crypto(struct drbd_tconn *tconn);
+extern struct drbd_resource *drbd_find_resource(const char *name);
+extern void drbd_destroy_resource(struct kref *kref);
+extern void conn_free_crypto(struct drbd_connection *connection);
extern int proc_details;
/* drbd_req */
extern void do_submit(struct work_struct *ws);
-extern void __drbd_make_request(struct drbd_conf *, struct bio *, unsigned long);
+extern void __drbd_make_request(struct drbd_device *, struct bio *, unsigned long);
extern void drbd_make_request(struct request_queue *q, struct bio *bio);
-extern int drbd_read_remote(struct drbd_conf *mdev, struct drbd_request *req);
+extern int drbd_read_remote(struct drbd_device *device, struct drbd_request *req);
extern int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct bio_vec *bvec);
extern int is_valid_ar_handle(struct drbd_request *, sector_t);
/* drbd_nl.c */
extern int drbd_msg_put_info(const char *info);
-extern void drbd_suspend_io(struct drbd_conf *mdev);
-extern void drbd_resume_io(struct drbd_conf *mdev);
+extern void drbd_suspend_io(struct drbd_device *device);
+extern void drbd_resume_io(struct drbd_device *device);
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);
+extern sector_t drbd_new_dev_size(struct drbd_device *, struct drbd_backing_dev *, sector_t, int);
enum determine_dev_size {
DS_ERROR_SHRINK = -3,
DS_ERROR_SPACE_MD = -2,
@@ -1478,48 +1272,47 @@ enum determine_dev_size {
DS_GREW_FROM_ZERO = 3,
};
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,
+drbd_determine_dev_size(struct drbd_device *, enum dds_flags, struct resize_parms *) __must_hold(local);
+extern void resync_after_online_grow(struct drbd_device *);
+extern void drbd_reconsider_max_bio_size(struct drbd_device *device);
+extern enum drbd_state_rv drbd_set_role(struct drbd_device *device,
enum drbd_role new_role,
int force);
-extern bool conn_try_outdate_peer(struct drbd_tconn *tconn);
-extern void conn_try_outdate_peer_async(struct drbd_tconn *tconn);
-extern int drbd_khelper(struct drbd_conf *mdev, char *cmd);
+extern bool conn_try_outdate_peer(struct drbd_connection *connection);
+extern void conn_try_outdate_peer_async(struct drbd_connection *connection);
+extern int drbd_khelper(struct drbd_device *device, char *cmd);
/* drbd_worker.c */
extern int drbd_worker(struct drbd_thread *thi);
-enum drbd_ret_code drbd_resync_after_valid(struct drbd_conf *mdev, int o_minor);
-void drbd_resync_after_changed(struct drbd_conf *mdev);
-extern void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side);
-extern void resume_next_sg(struct drbd_conf *mdev);
-extern void suspend_other_sg(struct drbd_conf *mdev);
-extern int drbd_resync_finished(struct drbd_conf *mdev);
+enum drbd_ret_code drbd_resync_after_valid(struct drbd_device *device, int o_minor);
+void drbd_resync_after_changed(struct drbd_device *device);
+extern void drbd_start_resync(struct drbd_device *device, enum drbd_conns side);
+extern void resume_next_sg(struct drbd_device *device);
+extern void suspend_other_sg(struct drbd_device *device);
+extern int drbd_resync_finished(struct drbd_device *device);
/* maybe rather drbd_main.c ? */
-extern void *drbd_md_get_buffer(struct drbd_conf *mdev);
-extern void drbd_md_put_buffer(struct drbd_conf *mdev);
-extern int drbd_md_sync_page_io(struct drbd_conf *mdev,
+extern void *drbd_md_get_buffer(struct drbd_device *device);
+extern void drbd_md_put_buffer(struct drbd_device *device);
+extern int drbd_md_sync_page_io(struct drbd_device *device,
struct drbd_backing_dev *bdev, sector_t sector, int rw);
-extern void drbd_ov_out_of_sync_found(struct drbd_conf *, sector_t, int);
-extern void wait_until_done_or_force_detached(struct drbd_conf *mdev,
+extern void drbd_ov_out_of_sync_found(struct drbd_device *, sector_t, int);
+extern void wait_until_done_or_force_detached(struct drbd_device *device,
struct drbd_backing_dev *bdev, unsigned int *done);
-extern void drbd_rs_controller_reset(struct drbd_conf *mdev);
+extern void drbd_rs_controller_reset(struct drbd_device *device);
-static inline void ov_out_of_sync_print(struct drbd_conf *mdev)
+static inline void ov_out_of_sync_print(struct drbd_device *device)
{
- if (mdev->ov_last_oos_size) {
- dev_err(DEV, "Out of sync: start=%llu, size=%lu (sectors)\n",
- (unsigned long long)mdev->ov_last_oos_start,
- (unsigned long)mdev->ov_last_oos_size);
+ if (device->ov_last_oos_size) {
+ drbd_err(device, "Out of sync: start=%llu, size=%lu (sectors)\n",
+ (unsigned long long)device->ov_last_oos_start,
+ (unsigned long)device->ov_last_oos_size);
}
- mdev->ov_last_oos_size=0;
+ device->ov_last_oos_size = 0;
}
-extern void drbd_csum_bio(struct drbd_conf *, struct crypto_hash *, struct bio *, void *);
-extern void drbd_csum_ee(struct drbd_conf *, struct crypto_hash *,
- struct drbd_peer_request *, void *);
+extern void drbd_csum_bio(struct crypto_hash *, struct bio *, void *);
+extern void drbd_csum_ee(struct crypto_hash *, struct drbd_peer_request *, void *);
/* worker callbacks */
extern int w_e_end_data_req(struct drbd_work *, int);
extern int w_e_end_rsdata_req(struct drbd_work *, int);
@@ -1529,10 +1322,8 @@ extern int w_e_end_ov_req(struct drbd_work *, int);
extern int w_ov_finished(struct drbd_work *, int);
extern int w_resync_timer(struct drbd_work *, int);
extern int w_send_write_hint(struct drbd_work *, int);
-extern int w_make_resync_request(struct drbd_work *, int);
extern int w_send_dblock(struct drbd_work *, int);
extern int w_send_read_req(struct drbd_work *, int);
-extern int w_prev_work_done(struct drbd_work *, int);
extern int w_e_reissue(struct drbd_work *, int);
extern int w_restart_disk_io(struct drbd_work *, int);
extern int w_send_out_of_sync(struct drbd_work *, int);
@@ -1542,27 +1333,24 @@ extern void resync_timer_fn(unsigned long data);
extern void start_resync_timer_fn(unsigned long data);
/* drbd_receiver.c */
-extern int drbd_rs_should_slow_down(struct drbd_conf *mdev, sector_t sector);
-extern int drbd_submit_peer_request(struct drbd_conf *,
+extern int drbd_receiver(struct drbd_thread *thi);
+extern int drbd_asender(struct drbd_thread *thi);
+extern int drbd_rs_should_slow_down(struct drbd_device *device, sector_t sector);
+extern int drbd_submit_peer_request(struct drbd_device *,
struct drbd_peer_request *, const unsigned,
const int);
-extern int drbd_free_peer_reqs(struct drbd_conf *, struct list_head *);
-extern struct drbd_peer_request *drbd_alloc_peer_req(struct drbd_conf *, u64,
+extern int drbd_free_peer_reqs(struct drbd_device *, struct list_head *);
+extern struct drbd_peer_request *drbd_alloc_peer_req(struct drbd_peer_device *, u64,
sector_t, unsigned int,
gfp_t) __must_hold(local);
-extern void __drbd_free_peer_req(struct drbd_conf *, struct drbd_peer_request *,
+extern void __drbd_free_peer_req(struct drbd_device *, struct drbd_peer_request *,
int);
#define drbd_free_peer_req(m,e) __drbd_free_peer_req(m, e, 0)
#define drbd_free_net_peer_req(m,e) __drbd_free_peer_req(m, e, 1)
-extern struct page *drbd_alloc_pages(struct drbd_conf *, unsigned int, bool);
-extern void drbd_set_recv_tcq(struct drbd_conf *mdev, int tcq_enabled);
-extern void _drbd_clear_done_ee(struct drbd_conf *mdev, struct list_head *to_be_freed);
-extern void conn_flush_workqueue(struct drbd_tconn *tconn);
-extern int drbd_connected(struct drbd_conf *mdev);
-static inline void drbd_flush_workqueue(struct drbd_conf *mdev)
-{
- conn_flush_workqueue(mdev->tconn);
-}
+extern struct page *drbd_alloc_pages(struct drbd_peer_device *, unsigned int, bool);
+extern void drbd_set_recv_tcq(struct drbd_device *device, int tcq_enabled);
+extern void _drbd_clear_done_ee(struct drbd_device *device, struct list_head *to_be_freed);
+extern int drbd_connected(struct drbd_peer_device *);
/* Yes, there is kernel_setsockopt, but only since 2.6.18.
* So we have our own copy of it here. */
@@ -1613,7 +1401,7 @@ static inline void drbd_tcp_quickack(struct socket *sock)
(char*)&val, sizeof(val));
}
-void drbd_bump_write_ordering(struct drbd_tconn *tconn, enum write_ordering_e wo);
+void drbd_bump_write_ordering(struct drbd_connection *connection, enum write_ordering_e wo);
/* drbd_proc.c */
extern struct proc_dir_entry *drbd_proc;
@@ -1622,29 +1410,29 @@ extern const char *drbd_conn_str(enum drbd_conns s);
extern const char *drbd_role_str(enum drbd_role s);
/* drbd_actlog.c */
-extern int drbd_al_begin_io_nonblock(struct drbd_conf *mdev, struct drbd_interval *i);
-extern void drbd_al_begin_io_commit(struct drbd_conf *mdev, bool delegate);
-extern bool drbd_al_begin_io_fastpath(struct drbd_conf *mdev, struct drbd_interval *i);
-extern void drbd_al_begin_io(struct drbd_conf *mdev, struct drbd_interval *i, bool delegate);
-extern void drbd_al_complete_io(struct drbd_conf *mdev, struct drbd_interval *i);
-extern void drbd_rs_complete_io(struct drbd_conf *mdev, sector_t sector);
-extern int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector);
-extern int drbd_try_rs_begin_io(struct drbd_conf *mdev, sector_t sector);
-extern void drbd_rs_cancel_all(struct drbd_conf *mdev);
-extern int drbd_rs_del_all(struct drbd_conf *mdev);
-extern void drbd_rs_failed_io(struct drbd_conf *mdev,
+extern int drbd_al_begin_io_nonblock(struct drbd_device *device, struct drbd_interval *i);
+extern void drbd_al_begin_io_commit(struct drbd_device *device, bool delegate);
+extern bool drbd_al_begin_io_fastpath(struct drbd_device *device, struct drbd_interval *i);
+extern void drbd_al_begin_io(struct drbd_device *device, struct drbd_interval *i, bool delegate);
+extern void drbd_al_complete_io(struct drbd_device *device, struct drbd_interval *i);
+extern void drbd_rs_complete_io(struct drbd_device *device, sector_t sector);
+extern int drbd_rs_begin_io(struct drbd_device *device, sector_t sector);
+extern int drbd_try_rs_begin_io(struct drbd_device *device, sector_t sector);
+extern void drbd_rs_cancel_all(struct drbd_device *device);
+extern int drbd_rs_del_all(struct drbd_device *device);
+extern void drbd_rs_failed_io(struct drbd_device *device,
sector_t sector, int size);
-extern void drbd_advance_rs_marks(struct drbd_conf *mdev, unsigned long still_to_go);
-extern void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector,
+extern void drbd_advance_rs_marks(struct drbd_device *device, unsigned long still_to_go);
+extern void __drbd_set_in_sync(struct drbd_device *device, sector_t sector,
int size, const char *file, const unsigned int line);
-#define drbd_set_in_sync(mdev, sector, size) \
- __drbd_set_in_sync(mdev, sector, size, __FILE__, __LINE__)
-extern int __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector,
+#define drbd_set_in_sync(device, sector, size) \
+ __drbd_set_in_sync(device, sector, size, __FILE__, __LINE__)
+extern int __drbd_set_out_of_sync(struct drbd_device *device, sector_t sector,
int size, const char *file, const unsigned int line);
-#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 *);
+#define drbd_set_out_of_sync(device, sector, size) \
+ __drbd_set_out_of_sync(device, sector, size, __FILE__, __LINE__)
+extern void drbd_al_shrink(struct drbd_device *device);
+extern int drbd_initialize_al(struct drbd_device *, void *);
/* drbd_nl.c */
/* state info broadcast */
@@ -1661,7 +1449,7 @@ struct sib_info {
};
};
};
-void drbd_bcast_event(struct drbd_conf *mdev, const struct sib_info *sib);
+void drbd_bcast_event(struct drbd_device *device, const struct sib_info *sib);
/*
* inline helper functions
@@ -1690,26 +1478,27 @@ static inline int drbd_peer_req_has_active_page(struct drbd_peer_request *peer_r
}
static inline enum drbd_state_rv
-_drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
+_drbd_set_state(struct drbd_device *device, union drbd_state ns,
enum chg_state_flags flags, struct completion *done)
{
enum drbd_state_rv rv;
read_lock(&global_state_lock);
- rv = __drbd_set_state(mdev, ns, flags, done);
+ rv = __drbd_set_state(device, ns, flags, done);
read_unlock(&global_state_lock);
return rv;
}
-static inline union drbd_state drbd_read_state(struct drbd_conf *mdev)
+static inline union drbd_state drbd_read_state(struct drbd_device *device)
{
+ struct drbd_resource *resource = device->resource;
union drbd_state rv;
- rv.i = mdev->state.i;
- rv.susp = mdev->tconn->susp;
- rv.susp_nod = mdev->tconn->susp_nod;
- rv.susp_fen = mdev->tconn->susp_fen;
+ rv.i = device->state.i;
+ rv.susp = resource->susp;
+ rv.susp_nod = resource->susp_nod;
+ rv.susp_fen = resource->susp_fen;
return rv;
}
@@ -1722,22 +1511,22 @@ enum drbd_force_detach_flags {
};
#define __drbd_chk_io_error(m,f) __drbd_chk_io_error_(m,f, __func__)
-static inline void __drbd_chk_io_error_(struct drbd_conf *mdev,
+static inline void __drbd_chk_io_error_(struct drbd_device *device,
enum drbd_force_detach_flags df,
const char *where)
{
enum drbd_io_error_p ep;
rcu_read_lock();
- ep = rcu_dereference(mdev->ldev->disk_conf)->on_io_error;
+ ep = rcu_dereference(device->ldev->disk_conf)->on_io_error;
rcu_read_unlock();
switch (ep) {
case EP_PASS_ON: /* FIXME would this be better named "Ignore"? */
if (df == DRBD_READ_ERROR || df == DRBD_WRITE_ERROR) {
if (__ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "Local IO failed in %s.\n", where);
- if (mdev->state.disk > D_INCONSISTENT)
- _drbd_set_state(_NS(mdev, disk, D_INCONSISTENT), CS_HARD, NULL);
+ drbd_err(device, "Local IO failed in %s.\n", where);
+ if (device->state.disk > D_INCONSISTENT)
+ _drbd_set_state(_NS(device, disk, D_INCONSISTENT), CS_HARD, NULL);
break;
}
/* NOTE fall through for DRBD_META_IO_ERROR or DRBD_FORCE_DETACH */
@@ -1763,14 +1552,14 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev,
* we read meta data only once during attach,
* which will fail in case of errors.
*/
- set_bit(WAS_IO_ERROR, &mdev->flags);
+ set_bit(WAS_IO_ERROR, &device->flags);
if (df == DRBD_READ_ERROR)
- set_bit(WAS_READ_ERROR, &mdev->flags);
+ set_bit(WAS_READ_ERROR, &device->flags);
if (df == DRBD_FORCE_DETACH)
- set_bit(FORCE_DETACH, &mdev->flags);
- if (mdev->state.disk > D_FAILED) {
- _drbd_set_state(_NS(mdev, disk, D_FAILED), CS_HARD, NULL);
- dev_err(DEV,
+ set_bit(FORCE_DETACH, &device->flags);
+ if (device->state.disk > D_FAILED) {
+ _drbd_set_state(_NS(device, disk, D_FAILED), CS_HARD, NULL);
+ drbd_err(device,
"Local IO failed in %s. Detaching...\n", where);
}
break;
@@ -1779,21 +1568,21 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev,
/**
* drbd_chk_io_error: Handle the on_io_error setting, should be called from all io completion handlers
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @error: Error code passed to the IO completion callback
* @forcedetach: Force detach. I.e. the error happened while accessing the meta data
*
* See also drbd_main.c:after_state_ch() if (os.disk > D_FAILED && ns.disk == D_FAILED)
*/
#define drbd_chk_io_error(m,e,f) drbd_chk_io_error_(m,e,f, __func__)
-static inline void drbd_chk_io_error_(struct drbd_conf *mdev,
+static inline void drbd_chk_io_error_(struct drbd_device *device,
int error, enum drbd_force_detach_flags forcedetach, const char *where)
{
if (error) {
unsigned long flags;
- spin_lock_irqsave(&mdev->tconn->req_lock, flags);
- __drbd_chk_io_error_(mdev, forcedetach, where);
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
+ spin_lock_irqsave(&device->resource->req_lock, flags);
+ __drbd_chk_io_error_(device, forcedetach, where);
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
}
}
@@ -1916,31 +1705,33 @@ drbd_queue_work(struct drbd_work_queue *q, struct drbd_work *w)
wake_up(&q->q_wait);
}
-static inline void wake_asender(struct drbd_tconn *tconn)
+extern void drbd_flush_workqueue(struct drbd_work_queue *work_queue);
+
+static inline void wake_asender(struct drbd_connection *connection)
{
- if (test_bit(SIGNAL_ASENDER, &tconn->flags))
- force_sig(DRBD_SIG, tconn->asender.task);
+ if (test_bit(SIGNAL_ASENDER, &connection->flags))
+ force_sig(DRBD_SIG, connection->asender.task);
}
-static inline void request_ping(struct drbd_tconn *tconn)
+static inline void request_ping(struct drbd_connection *connection)
{
- set_bit(SEND_PING, &tconn->flags);
- wake_asender(tconn);
+ set_bit(SEND_PING, &connection->flags);
+ wake_asender(connection);
}
-extern void *conn_prepare_command(struct drbd_tconn *, struct drbd_socket *);
-extern void *drbd_prepare_command(struct drbd_conf *, struct drbd_socket *);
-extern int conn_send_command(struct drbd_tconn *, struct drbd_socket *,
+extern void *conn_prepare_command(struct drbd_connection *, struct drbd_socket *);
+extern void *drbd_prepare_command(struct drbd_peer_device *, struct drbd_socket *);
+extern int conn_send_command(struct drbd_connection *, struct drbd_socket *,
enum drbd_packet, unsigned int, void *,
unsigned int);
-extern int drbd_send_command(struct drbd_conf *, struct drbd_socket *,
+extern int drbd_send_command(struct drbd_peer_device *, struct drbd_socket *,
enum drbd_packet, unsigned int, void *,
unsigned int);
-extern int drbd_send_ping(struct drbd_tconn *tconn);
-extern int drbd_send_ping_ack(struct drbd_tconn *tconn);
-extern int drbd_send_state_req(struct drbd_conf *, union drbd_state, union drbd_state);
-extern int conn_send_state_req(struct drbd_tconn *, union drbd_state, union drbd_state);
+extern int drbd_send_ping(struct drbd_connection *connection);
+extern int drbd_send_ping_ack(struct drbd_connection *connection);
+extern int drbd_send_state_req(struct drbd_peer_device *, union drbd_state, union drbd_state);
+extern int conn_send_state_req(struct drbd_connection *, union drbd_state, union drbd_state);
static inline void drbd_thread_stop(struct drbd_thread *thi)
{
@@ -1979,22 +1770,22 @@ static inline void drbd_thread_restart_nowait(struct drbd_thread *thi)
* _req_mod(req, CONNECTION_LOST_WHILE_PENDING)
* [from tl_clear_barrier]
*/
-static inline void inc_ap_pending(struct drbd_conf *mdev)
+static inline void inc_ap_pending(struct drbd_device *device)
{
- atomic_inc(&mdev->ap_pending_cnt);
+ atomic_inc(&device->ap_pending_cnt);
}
#define ERR_IF_CNT_IS_NEGATIVE(which, func, line) \
- if (atomic_read(&mdev->which) < 0) \
- dev_err(DEV, "in %s:%d: " #which " = %d < 0 !\n", \
+ if (atomic_read(&device->which) < 0) \
+ drbd_err(device, "in %s:%d: " #which " = %d < 0 !\n", \
func, line, \
- atomic_read(&mdev->which))
+ atomic_read(&device->which))
-#define dec_ap_pending(mdev) _dec_ap_pending(mdev, __FUNCTION__, __LINE__)
-static inline void _dec_ap_pending(struct drbd_conf *mdev, const char *func, int line)
+#define dec_ap_pending(device) _dec_ap_pending(device, __FUNCTION__, __LINE__)
+static inline void _dec_ap_pending(struct drbd_device *device, const char *func, int line)
{
- if (atomic_dec_and_test(&mdev->ap_pending_cnt))
- wake_up(&mdev->misc_wait);
+ if (atomic_dec_and_test(&device->ap_pending_cnt))
+ wake_up(&device->misc_wait);
ERR_IF_CNT_IS_NEGATIVE(ap_pending_cnt, func, line);
}
@@ -2004,15 +1795,15 @@ static inline void _dec_ap_pending(struct drbd_conf *mdev, const char *func, int
* C_SYNC_SOURCE sends P_RS_DATA_REPLY (and expects P_WRITE_ACK with ID_SYNCER)
* (or P_NEG_ACK with ID_SYNCER)
*/
-static inline void inc_rs_pending(struct drbd_conf *mdev)
+static inline void inc_rs_pending(struct drbd_device *device)
{
- atomic_inc(&mdev->rs_pending_cnt);
+ atomic_inc(&device->rs_pending_cnt);
}
-#define dec_rs_pending(mdev) _dec_rs_pending(mdev, __FUNCTION__, __LINE__)
-static inline void _dec_rs_pending(struct drbd_conf *mdev, const char *func, int line)
+#define dec_rs_pending(device) _dec_rs_pending(device, __FUNCTION__, __LINE__)
+static inline void _dec_rs_pending(struct drbd_device *device, const char *func, int line)
{
- atomic_dec(&mdev->rs_pending_cnt);
+ atomic_dec(&device->rs_pending_cnt);
ERR_IF_CNT_IS_NEGATIVE(rs_pending_cnt, func, line);
}
@@ -2025,103 +1816,104 @@ static inline void _dec_rs_pending(struct drbd_conf *mdev, const char *func, int
* receive_DataRequest (receive_RSDataRequest) we need to send back P_DATA
* receive_Barrier_* we need to send a P_BARRIER_ACK
*/
-static inline void inc_unacked(struct drbd_conf *mdev)
+static inline void inc_unacked(struct drbd_device *device)
{
- atomic_inc(&mdev->unacked_cnt);
+ atomic_inc(&device->unacked_cnt);
}
-#define dec_unacked(mdev) _dec_unacked(mdev, __FUNCTION__, __LINE__)
-static inline void _dec_unacked(struct drbd_conf *mdev, const char *func, int line)
+#define dec_unacked(device) _dec_unacked(device, __FUNCTION__, __LINE__)
+static inline void _dec_unacked(struct drbd_device *device, const char *func, int line)
{
- atomic_dec(&mdev->unacked_cnt);
+ atomic_dec(&device->unacked_cnt);
ERR_IF_CNT_IS_NEGATIVE(unacked_cnt, func, line);
}
-#define sub_unacked(mdev, n) _sub_unacked(mdev, n, __FUNCTION__, __LINE__)
-static inline void _sub_unacked(struct drbd_conf *mdev, int n, const char *func, int line)
+#define sub_unacked(device, n) _sub_unacked(device, n, __FUNCTION__, __LINE__)
+static inline void _sub_unacked(struct drbd_device *device, int n, const char *func, int line)
{
- atomic_sub(n, &mdev->unacked_cnt);
+ atomic_sub(n, &device->unacked_cnt);
ERR_IF_CNT_IS_NEGATIVE(unacked_cnt, func, line);
}
/**
- * get_ldev() - Increase the ref count on mdev->ldev. Returns 0 if there is no ldev
+ * get_ldev() - Increase the ref count on device->ldev. Returns 0 if there is no ldev
* @M: DRBD device.
*
- * You have to call put_ldev() when finished working with mdev->ldev.
+ * You have to call put_ldev() when finished working with device->ldev.
*/
#define get_ldev(M) __cond_lock(local, _get_ldev_if_state(M,D_INCONSISTENT))
#define get_ldev_if_state(M,MINS) __cond_lock(local, _get_ldev_if_state(M,MINS))
-static inline void put_ldev(struct drbd_conf *mdev)
+static inline void put_ldev(struct drbd_device *device)
{
- int i = atomic_dec_return(&mdev->local_cnt);
+ int i = atomic_dec_return(&device->local_cnt);
/* This may be called from some endio handler,
* so we must not sleep here. */
__release(local);
- D_ASSERT(i >= 0);
+ D_ASSERT(device, i >= 0);
if (i == 0) {
- if (mdev->state.disk == D_DISKLESS)
+ if (device->state.disk == D_DISKLESS)
/* even internal references gone, safe to destroy */
- drbd_ldev_destroy(mdev);
- if (mdev->state.disk == D_FAILED) {
+ drbd_ldev_destroy(device);
+ if (device->state.disk == D_FAILED) {
/* all application IO references gone. */
- if (!test_and_set_bit(GO_DISKLESS, &mdev->flags))
- drbd_queue_work(&mdev->tconn->sender_work, &mdev->go_diskless);
+ if (!test_and_set_bit(GO_DISKLESS, &device->flags))
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &device->go_diskless);
}
- wake_up(&mdev->misc_wait);
+ wake_up(&device->misc_wait);
}
}
#ifndef __CHECKER__
-static inline int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins)
+static inline int _get_ldev_if_state(struct drbd_device *device, enum drbd_disk_state mins)
{
int io_allowed;
/* never get a reference while D_DISKLESS */
- if (mdev->state.disk == D_DISKLESS)
+ if (device->state.disk == D_DISKLESS)
return 0;
- atomic_inc(&mdev->local_cnt);
- io_allowed = (mdev->state.disk >= mins);
+ atomic_inc(&device->local_cnt);
+ io_allowed = (device->state.disk >= mins);
if (!io_allowed)
- put_ldev(mdev);
+ put_ldev(device);
return io_allowed;
}
#else
-extern int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins);
+extern int _get_ldev_if_state(struct drbd_device *device, enum drbd_disk_state mins);
#endif
/* you must have an "get_ldev" reference */
-static inline void drbd_get_syncer_progress(struct drbd_conf *mdev,
+static inline void drbd_get_syncer_progress(struct drbd_device *device,
unsigned long *bits_left, unsigned int *per_mil_done)
{
/* this is to break it at compile time when we change that, in case we
* want to support more than (1<<32) bits on a 32bit arch. */
- typecheck(unsigned long, mdev->rs_total);
+ typecheck(unsigned long, device->rs_total);
/* note: both rs_total and rs_left are in bits, i.e. in
* units of BM_BLOCK_SIZE.
* for the percentage, we don't care. */
- if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T)
- *bits_left = mdev->ov_left;
+ if (device->state.conn == C_VERIFY_S || device->state.conn == C_VERIFY_T)
+ *bits_left = device->ov_left;
else
- *bits_left = drbd_bm_total_weight(mdev) - mdev->rs_failed;
+ *bits_left = drbd_bm_total_weight(device) - device->rs_failed;
/* >> 10 to prevent overflow,
* +1 to prevent division by zero */
- if (*bits_left > mdev->rs_total) {
+ if (*bits_left > device->rs_total) {
/* doh. maybe a logic bug somewhere.
* may also be just a race condition
* between this and a disconnect during sync.
* for now, just prevent in-kernel buffer overflow.
*/
smp_rmb();
- dev_warn(DEV, "cs:%s rs_left=%lu > rs_total=%lu (rs_failed %lu)\n",
- drbd_conn_str(mdev->state.conn),
- *bits_left, mdev->rs_total, mdev->rs_failed);
+ drbd_warn(device, "cs:%s rs_left=%lu > rs_total=%lu (rs_failed %lu)\n",
+ drbd_conn_str(device->state.conn),
+ *bits_left, device->rs_total, device->rs_failed);
*per_mil_done = 0;
} else {
/* Make sure the division happens in long context.
@@ -2133,9 +1925,9 @@ static inline void drbd_get_syncer_progress(struct drbd_conf *mdev,
* Note: currently we don't support such large bitmaps on 32bit
* arch anyways, but no harm done to be prepared for it here.
*/
- unsigned int shift = mdev->rs_total > UINT_MAX ? 16 : 10;
+ unsigned int shift = device->rs_total > UINT_MAX ? 16 : 10;
unsigned long left = *bits_left >> shift;
- unsigned long total = 1UL + (mdev->rs_total >> shift);
+ unsigned long total = 1UL + (device->rs_total >> shift);
unsigned long tmp = 1000UL - left * 1000UL/total;
*per_mil_done = tmp;
}
@@ -2145,22 +1937,22 @@ static inline void drbd_get_syncer_progress(struct drbd_conf *mdev,
/* this throttles on-the-fly application requests
* according to max_buffers settings;
* maybe re-implement using semaphores? */
-static inline int drbd_get_max_buffers(struct drbd_conf *mdev)
+static inline int drbd_get_max_buffers(struct drbd_device *device)
{
struct net_conf *nc;
int mxb;
rcu_read_lock();
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
mxb = nc ? nc->max_buffers : 1000000; /* arbitrary limit on open requests */
rcu_read_unlock();
return mxb;
}
-static inline int drbd_state_is_stable(struct drbd_conf *mdev)
+static inline int drbd_state_is_stable(struct drbd_device *device)
{
- union drbd_dev_state s = mdev->state;
+ union drbd_dev_state s = device->state;
/* DO NOT add a default clause, we want the compiler to warn us
* for any newly introduced state we may have forgotten to add here */
@@ -2194,7 +1986,7 @@ static inline int drbd_state_is_stable(struct drbd_conf *mdev)
/* Allow IO in BM exchange states with new protocols */
case C_WF_BITMAP_S:
- if (mdev->tconn->agreed_pro_version < 96)
+ if (first_peer_device(device)->connection->agreed_pro_version < 96)
return 0;
break;
@@ -2228,20 +2020,20 @@ static inline int drbd_state_is_stable(struct drbd_conf *mdev)
return 1;
}
-static inline int drbd_suspended(struct drbd_conf *mdev)
+static inline int drbd_suspended(struct drbd_device *device)
{
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_resource *resource = device->resource;
- return tconn->susp || tconn->susp_fen || tconn->susp_nod;
+ return resource->susp || resource->susp_fen || resource->susp_nod;
}
-static inline bool may_inc_ap_bio(struct drbd_conf *mdev)
+static inline bool may_inc_ap_bio(struct drbd_device *device)
{
- int mxb = drbd_get_max_buffers(mdev);
+ int mxb = drbd_get_max_buffers(device);
- if (drbd_suspended(mdev))
+ if (drbd_suspended(device))
return false;
- if (test_bit(SUSPEND_IO, &mdev->flags))
+ if (test_bit(SUSPEND_IO, &device->flags))
return false;
/* to avoid potential deadlock or bitmap corruption,
@@ -2249,32 +2041,32 @@ static inline bool may_inc_ap_bio(struct drbd_conf *mdev)
* to start during "stable" states. */
/* no new io accepted when attaching or detaching the disk */
- if (!drbd_state_is_stable(mdev))
+ if (!drbd_state_is_stable(device))
return false;
/* since some older kernels don't have atomic_add_unless,
* and we are within the spinlock anyways, we have this workaround. */
- if (atomic_read(&mdev->ap_bio_cnt) > mxb)
+ if (atomic_read(&device->ap_bio_cnt) > mxb)
return false;
- if (test_bit(BITMAP_IO, &mdev->flags))
+ if (test_bit(BITMAP_IO, &device->flags))
return false;
return true;
}
-static inline bool inc_ap_bio_cond(struct drbd_conf *mdev)
+static inline bool inc_ap_bio_cond(struct drbd_device *device)
{
bool rv = false;
- spin_lock_irq(&mdev->tconn->req_lock);
- rv = may_inc_ap_bio(mdev);
+ spin_lock_irq(&device->resource->req_lock);
+ rv = may_inc_ap_bio(device);
if (rv)
- atomic_inc(&mdev->ap_bio_cnt);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ atomic_inc(&device->ap_bio_cnt);
+ spin_unlock_irq(&device->resource->req_lock);
return rv;
}
-static inline void inc_ap_bio(struct drbd_conf *mdev)
+static inline void inc_ap_bio(struct drbd_device *device)
{
/* we wait here
* as long as the device is suspended
@@ -2284,42 +2076,44 @@ static inline void inc_ap_bio(struct drbd_conf *mdev)
* to avoid races with the reconnect code,
* we need to atomic_inc within the spinlock. */
- wait_event(mdev->misc_wait, inc_ap_bio_cond(mdev));
+ wait_event(device->misc_wait, inc_ap_bio_cond(device));
}
-static inline void dec_ap_bio(struct drbd_conf *mdev)
+static inline void dec_ap_bio(struct drbd_device *device)
{
- int mxb = drbd_get_max_buffers(mdev);
- int ap_bio = atomic_dec_return(&mdev->ap_bio_cnt);
+ int mxb = drbd_get_max_buffers(device);
+ int ap_bio = atomic_dec_return(&device->ap_bio_cnt);
- D_ASSERT(ap_bio >= 0);
+ D_ASSERT(device, ap_bio >= 0);
- if (ap_bio == 0 && test_bit(BITMAP_IO, &mdev->flags)) {
- if (!test_and_set_bit(BITMAP_IO_QUEUED, &mdev->flags))
- drbd_queue_work(&mdev->tconn->sender_work, &mdev->bm_io_work.w);
+ if (ap_bio == 0 && test_bit(BITMAP_IO, &device->flags)) {
+ if (!test_and_set_bit(BITMAP_IO_QUEUED, &device->flags))
+ drbd_queue_work(&first_peer_device(device)->
+ connection->sender_work,
+ &device->bm_io_work.w);
}
/* this currently does wake_up for every dec_ap_bio!
* maybe rather introduce some type of hysteresis?
* e.g. (ap_bio == mxb/2 || ap_bio == 0) ? */
if (ap_bio < mxb)
- wake_up(&mdev->misc_wait);
+ wake_up(&device->misc_wait);
}
-static inline bool verify_can_do_stop_sector(struct drbd_conf *mdev)
+static inline bool verify_can_do_stop_sector(struct drbd_device *device)
{
- return mdev->tconn->agreed_pro_version >= 97 &&
- mdev->tconn->agreed_pro_version != 100;
+ return first_peer_device(device)->connection->agreed_pro_version >= 97 &&
+ first_peer_device(device)->connection->agreed_pro_version != 100;
}
-static inline int drbd_set_ed_uuid(struct drbd_conf *mdev, u64 val)
+static inline int drbd_set_ed_uuid(struct drbd_device *device, u64 val)
{
- int changed = mdev->ed_uuid != val;
- mdev->ed_uuid = val;
+ int changed = device->ed_uuid != val;
+ device->ed_uuid = val;
return changed;
}
-static inline int drbd_queue_order_type(struct drbd_conf *mdev)
+static inline int drbd_queue_order_type(struct drbd_device *device)
{
/* sorry, we currently have no working implementation
* of distributed TCQ stuff */
@@ -2329,23 +2123,29 @@ static inline int drbd_queue_order_type(struct drbd_conf *mdev)
return QUEUE_ORDERED_NONE;
}
-static inline void drbd_md_flush(struct drbd_conf *mdev)
+static inline void drbd_md_flush(struct drbd_device *device)
{
int r;
- if (mdev->ldev == NULL) {
- dev_warn(DEV, "mdev->ldev == NULL in drbd_md_flush\n");
+ if (device->ldev == NULL) {
+ drbd_warn(device, "device->ldev == NULL in drbd_md_flush\n");
return;
}
- if (test_bit(MD_NO_FUA, &mdev->flags))
+ if (test_bit(MD_NO_FUA, &device->flags))
return;
- r = blkdev_issue_flush(mdev->ldev->md_bdev, GFP_NOIO, NULL);
+ r = blkdev_issue_flush(device->ldev->md_bdev, GFP_NOIO, NULL);
if (r) {
- set_bit(MD_NO_FUA, &mdev->flags);
- dev_err(DEV, "meta data flush failed with status %d, disabling md-flushes\n", r);
+ set_bit(MD_NO_FUA, &device->flags);
+ drbd_err(device, "meta data flush failed with status %d, disabling md-flushes\n", r);
}
}
+static inline struct drbd_connection *first_connection(struct drbd_resource *resource)
+{
+ return list_first_entry(&resource->connections,
+ struct drbd_connection, connections);
+}
+
#endif
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 929468e1512a..331e5cc1227d 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -52,16 +52,12 @@
#include <linux/drbd_limits.h>
#include "drbd_int.h"
+#include "drbd_protocol.h"
#include "drbd_req.h" /* only for _req_mod in tl_release and tl_clear */
#include "drbd_vli.h"
static DEFINE_MUTEX(drbd_main_mutex);
-int drbdd_init(struct drbd_thread *);
-int drbd_worker(struct drbd_thread *);
-int drbd_asender(struct drbd_thread *);
-
-int drbd_init(void);
static int drbd_open(struct block_device *bdev, fmode_t mode);
static void drbd_release(struct gendisk *gd, fmode_t mode);
static int w_md_sync(struct drbd_work *w, int unused);
@@ -118,8 +114,8 @@ module_param_string(usermode_helper, usermode_helper, sizeof(usermode_helper), 0
/* in 2.6.x, our device mapping and config info contains our virtual gendisks
* as member "struct gendisk *vdisk;"
*/
-struct idr minors;
-struct list_head drbd_tconns; /* list of struct drbd_tconn */
+struct idr drbd_devices;
+struct list_head drbd_resources;
struct kmem_cache *drbd_request_cache;
struct kmem_cache *drbd_ee_cache; /* peer requests */
@@ -166,15 +162,15 @@ struct bio *bio_alloc_drbd(gfp_t gfp_mask)
/* When checking with sparse, and this is an inline function, sparse will
give tons of false positives. When this is a real functions sparse works.
*/
-int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins)
+int _get_ldev_if_state(struct drbd_device *device, enum drbd_disk_state mins)
{
int io_allowed;
- atomic_inc(&mdev->local_cnt);
- io_allowed = (mdev->state.disk >= mins);
+ atomic_inc(&device->local_cnt);
+ io_allowed = (device->state.disk >= mins);
if (!io_allowed) {
- if (atomic_dec_and_test(&mdev->local_cnt))
- wake_up(&mdev->misc_wait);
+ if (atomic_dec_and_test(&device->local_cnt))
+ wake_up(&device->misc_wait);
}
return io_allowed;
}
@@ -183,7 +179,7 @@ int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins)
/**
* tl_release() - mark as BARRIER_ACKED all requests in the corresponding transfer log epoch
- * @tconn: DRBD connection.
+ * @connection: DRBD connection.
* @barrier_nr: Expected identifier of the DRBD write barrier packet.
* @set_size: Expected number of requests before that barrier.
*
@@ -191,7 +187,7 @@ int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins)
* epoch of not yet barrier-acked requests, this function will cause a
* termination of the connection.
*/
-void tl_release(struct drbd_tconn *tconn, unsigned int barrier_nr,
+void tl_release(struct drbd_connection *connection, unsigned int barrier_nr,
unsigned int set_size)
{
struct drbd_request *r;
@@ -199,11 +195,11 @@ void tl_release(struct drbd_tconn *tconn, unsigned int barrier_nr,
int expect_epoch = 0;
int expect_size = 0;
- spin_lock_irq(&tconn->req_lock);
+ spin_lock_irq(&connection->resource->req_lock);
/* find oldest not yet barrier-acked write request,
* count writes in its epoch. */
- list_for_each_entry(r, &tconn->transfer_log, tl_requests) {
+ list_for_each_entry(r, &connection->transfer_log, tl_requests) {
const unsigned s = r->rq_state;
if (!req) {
if (!(s & RQ_WRITE))
@@ -228,18 +224,18 @@ void tl_release(struct drbd_tconn *tconn, unsigned int barrier_nr,
/* first some paranoia code */
if (req == NULL) {
- conn_err(tconn, "BAD! BarrierAck #%u received, but no epoch in tl!?\n",
+ drbd_err(connection, "BAD! BarrierAck #%u received, but no epoch in tl!?\n",
barrier_nr);
goto bail;
}
if (expect_epoch != barrier_nr) {
- conn_err(tconn, "BAD! BarrierAck #%u received, expected #%u!\n",
+ drbd_err(connection, "BAD! BarrierAck #%u received, expected #%u!\n",
barrier_nr, expect_epoch);
goto bail;
}
if (expect_size != set_size) {
- conn_err(tconn, "BAD! BarrierAck #%u received with n_writes=%u, expected n_writes=%u!\n",
+ drbd_err(connection, "BAD! BarrierAck #%u received with n_writes=%u, expected n_writes=%u!\n",
barrier_nr, set_size, expect_size);
goto bail;
}
@@ -248,90 +244,91 @@ void tl_release(struct drbd_tconn *tconn, unsigned int barrier_nr,
/* this extra list walk restart is paranoia,
* to catch requests being barrier-acked "unexpectedly".
* It usually should find the same req again, or some READ preceding it. */
- list_for_each_entry(req, &tconn->transfer_log, tl_requests)
+ list_for_each_entry(req, &connection->transfer_log, tl_requests)
if (req->epoch == expect_epoch)
break;
- list_for_each_entry_safe_from(req, r, &tconn->transfer_log, tl_requests) {
+ list_for_each_entry_safe_from(req, r, &connection->transfer_log, tl_requests) {
if (req->epoch != expect_epoch)
break;
_req_mod(req, BARRIER_ACKED);
}
- spin_unlock_irq(&tconn->req_lock);
+ spin_unlock_irq(&connection->resource->req_lock);
return;
bail:
- spin_unlock_irq(&tconn->req_lock);
- conn_request_state(tconn, NS(conn, C_PROTOCOL_ERROR), CS_HARD);
+ spin_unlock_irq(&connection->resource->req_lock);
+ conn_request_state(connection, NS(conn, C_PROTOCOL_ERROR), CS_HARD);
}
/**
* _tl_restart() - Walks the transfer log, and applies an action to all requests
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @what: The action/event to perform with all request objects
*
* @what might be one of CONNECTION_LOST_WHILE_PENDING, RESEND, FAIL_FROZEN_DISK_IO,
* RESTART_FROZEN_DISK_IO.
*/
/* must hold resource->req_lock */
-void _tl_restart(struct drbd_tconn *tconn, enum drbd_req_event what)
+void _tl_restart(struct drbd_connection *connection, enum drbd_req_event what)
{
struct drbd_request *req, *r;
- list_for_each_entry_safe(req, r, &tconn->transfer_log, tl_requests)
+ list_for_each_entry_safe(req, r, &connection->transfer_log, tl_requests)
_req_mod(req, what);
}
-void tl_restart(struct drbd_tconn *tconn, enum drbd_req_event what)
+void tl_restart(struct drbd_connection *connection, enum drbd_req_event what)
{
- spin_lock_irq(&tconn->req_lock);
- _tl_restart(tconn, what);
- spin_unlock_irq(&tconn->req_lock);
+ spin_lock_irq(&connection->resource->req_lock);
+ _tl_restart(connection, what);
+ spin_unlock_irq(&connection->resource->req_lock);
}
/**
* tl_clear() - Clears all requests and &struct drbd_tl_epoch objects out of the TL
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* This is called after the connection to the peer was lost. The storage covered
* by the requests on the transfer gets marked as our of sync. Called from the
* receiver thread and the worker thread.
*/
-void tl_clear(struct drbd_tconn *tconn)
+void tl_clear(struct drbd_connection *connection)
{
- tl_restart(tconn, CONNECTION_LOST_WHILE_PENDING);
+ tl_restart(connection, CONNECTION_LOST_WHILE_PENDING);
}
/**
- * tl_abort_disk_io() - Abort disk I/O for all requests for a certain mdev in the TL
- * @mdev: DRBD device.
+ * tl_abort_disk_io() - Abort disk I/O for all requests for a certain device in the TL
+ * @device: DRBD device.
*/
-void tl_abort_disk_io(struct drbd_conf *mdev)
+void tl_abort_disk_io(struct drbd_device *device)
{
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_connection *connection = first_peer_device(device)->connection;
struct drbd_request *req, *r;
- spin_lock_irq(&tconn->req_lock);
- list_for_each_entry_safe(req, r, &tconn->transfer_log, tl_requests) {
+ spin_lock_irq(&connection->resource->req_lock);
+ list_for_each_entry_safe(req, r, &connection->transfer_log, tl_requests) {
if (!(req->rq_state & RQ_LOCAL_PENDING))
continue;
- if (req->w.mdev != mdev)
+ if (req->device != device)
continue;
_req_mod(req, ABORT_DISK_IO);
}
- spin_unlock_irq(&tconn->req_lock);
+ spin_unlock_irq(&connection->resource->req_lock);
}
static int drbd_thread_setup(void *arg)
{
struct drbd_thread *thi = (struct drbd_thread *) arg;
- struct drbd_tconn *tconn = thi->tconn;
+ struct drbd_resource *resource = thi->resource;
unsigned long flags;
int retval;
snprintf(current->comm, sizeof(current->comm), "drbd_%c_%s",
- thi->name[0], thi->tconn->name);
+ thi->name[0],
+ resource->name);
restart:
retval = thi->function(thi);
@@ -349,7 +346,7 @@ restart:
*/
if (thi->t_state == RESTARTING) {
- conn_info(tconn, "Restarting %s thread\n", thi->name);
+ drbd_info(resource, "Restarting %s thread\n", thi->name);
thi->t_state = RUNNING;
spin_unlock_irqrestore(&thi->t_lock, flags);
goto restart;
@@ -361,29 +358,32 @@ restart:
complete_all(&thi->stop);
spin_unlock_irqrestore(&thi->t_lock, flags);
- conn_info(tconn, "Terminating %s\n", current->comm);
+ drbd_info(resource, "Terminating %s\n", current->comm);
/* Release mod reference taken when thread was started */
- kref_put(&tconn->kref, &conn_destroy);
+ if (thi->connection)
+ kref_put(&thi->connection->kref, drbd_destroy_connection);
+ kref_put(&resource->kref, drbd_destroy_resource);
module_put(THIS_MODULE);
return retval;
}
-static void drbd_thread_init(struct drbd_tconn *tconn, struct drbd_thread *thi,
- int (*func) (struct drbd_thread *), char *name)
+static void drbd_thread_init(struct drbd_resource *resource, struct drbd_thread *thi,
+ int (*func) (struct drbd_thread *), const char *name)
{
spin_lock_init(&thi->t_lock);
thi->task = NULL;
thi->t_state = NONE;
thi->function = func;
- thi->tconn = tconn;
- strncpy(thi->name, name, ARRAY_SIZE(thi->name));
+ thi->resource = resource;
+ thi->connection = NULL;
+ thi->name = name;
}
int drbd_thread_start(struct drbd_thread *thi)
{
- struct drbd_tconn *tconn = thi->tconn;
+ struct drbd_resource *resource = thi->resource;
struct task_struct *nt;
unsigned long flags;
@@ -393,17 +393,19 @@ int drbd_thread_start(struct drbd_thread *thi)
switch (thi->t_state) {
case NONE:
- conn_info(tconn, "Starting %s thread (from %s [%d])\n",
+ drbd_info(resource, "Starting %s thread (from %s [%d])\n",
thi->name, current->comm, current->pid);
/* Get ref on module for thread - this is released when thread exits */
if (!try_module_get(THIS_MODULE)) {
- conn_err(tconn, "Failed to get module reference in drbd_thread_start\n");
+ drbd_err(resource, "Failed to get module reference in drbd_thread_start\n");
spin_unlock_irqrestore(&thi->t_lock, flags);
return false;
}
- kref_get(&thi->tconn->kref);
+ kref_get(&resource->kref);
+ if (thi->connection)
+ kref_get(&thi->connection->kref);
init_completion(&thi->stop);
thi->reset_cpu_mask = 1;
@@ -412,12 +414,14 @@ int drbd_thread_start(struct drbd_thread *thi)
flush_signals(current); /* otherw. may get -ERESTARTNOINTR */
nt = kthread_create(drbd_thread_setup, (void *) thi,
- "drbd_%c_%s", thi->name[0], thi->tconn->name);
+ "drbd_%c_%s", thi->name[0], thi->resource->name);
if (IS_ERR(nt)) {
- conn_err(tconn, "Couldn't start thread\n");
+ drbd_err(resource, "Couldn't start thread\n");
- kref_put(&tconn->kref, &conn_destroy);
+ if (thi->connection)
+ kref_put(&thi->connection->kref, drbd_destroy_connection);
+ kref_put(&resource->kref, drbd_destroy_resource);
module_put(THIS_MODULE);
return false;
}
@@ -429,7 +433,7 @@ int drbd_thread_start(struct drbd_thread *thi)
break;
case EXITING:
thi->t_state = RESTARTING;
- conn_info(tconn, "Restarting %s thread (from %s [%d])\n",
+ drbd_info(resource, "Restarting %s thread (from %s [%d])\n",
thi->name, current->comm, current->pid);
/* fall through */
case RUNNING:
@@ -478,65 +482,60 @@ void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait)
wait_for_completion(&thi->stop);
}
-static struct drbd_thread *drbd_task_to_thread(struct drbd_tconn *tconn, struct task_struct *task)
-{
- struct drbd_thread *thi =
- task == tconn->receiver.task ? &tconn->receiver :
- task == tconn->asender.task ? &tconn->asender :
- task == tconn->worker.task ? &tconn->worker : NULL;
-
- return thi;
-}
-
-char *drbd_task_to_thread_name(struct drbd_tconn *tconn, struct task_struct *task)
+int conn_lowest_minor(struct drbd_connection *connection)
{
- struct drbd_thread *thi = drbd_task_to_thread(tconn, task);
- return thi ? thi->name : task->comm;
-}
-
-int conn_lowest_minor(struct drbd_tconn *tconn)
-{
- struct drbd_conf *mdev;
- int vnr = 0, m;
+ struct drbd_peer_device *peer_device;
+ int vnr = 0, minor = -1;
rcu_read_lock();
- mdev = idr_get_next(&tconn->volumes, &vnr);
- m = mdev ? mdev_to_minor(mdev) : -1;
+ peer_device = idr_get_next(&connection->peer_devices, &vnr);
+ if (peer_device)
+ minor = device_to_minor(peer_device->device);
rcu_read_unlock();
- return m;
+ return minor;
}
#ifdef CONFIG_SMP
/**
* drbd_calc_cpu_mask() - Generate CPU masks, spread over all CPUs
- * @mdev: DRBD device.
*
- * Forces all threads of a device onto the same CPU. This is beneficial for
+ * Forces all threads of a resource onto the same CPU. This is beneficial for
* DRBD's performance. May be overwritten by user's configuration.
*/
-void drbd_calc_cpu_mask(struct drbd_tconn *tconn)
+static void drbd_calc_cpu_mask(cpumask_var_t *cpu_mask)
{
- int ord, cpu;
+ unsigned int *resources_per_cpu, min_index = ~0;
- /* user override. */
- if (cpumask_weight(tconn->cpu_mask))
- return;
+ resources_per_cpu = kzalloc(nr_cpu_ids * sizeof(*resources_per_cpu), GFP_KERNEL);
+ if (resources_per_cpu) {
+ struct drbd_resource *resource;
+ unsigned int cpu, min = ~0;
- ord = conn_lowest_minor(tconn) % cpumask_weight(cpu_online_mask);
- for_each_online_cpu(cpu) {
- if (ord-- == 0) {
- cpumask_set_cpu(cpu, tconn->cpu_mask);
- return;
+ rcu_read_lock();
+ for_each_resource_rcu(resource, &drbd_resources) {
+ for_each_cpu(cpu, resource->cpu_mask)
+ resources_per_cpu[cpu]++;
}
+ rcu_read_unlock();
+ for_each_online_cpu(cpu) {
+ if (resources_per_cpu[cpu] < min) {
+ min = resources_per_cpu[cpu];
+ min_index = cpu;
+ }
+ }
+ kfree(resources_per_cpu);
}
- /* should not be reached */
- cpumask_setall(tconn->cpu_mask);
+ if (min_index == ~0) {
+ cpumask_setall(*cpu_mask);
+ return;
+ }
+ cpumask_set_cpu(min_index, *cpu_mask);
}
/**
* drbd_thread_current_set_cpu() - modifies the cpu mask of the _current_ thread
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @thi: drbd_thread object
*
* call in the "main loop" of _all_ threads, no need for any mutex, current won't die
@@ -544,13 +543,16 @@ void drbd_calc_cpu_mask(struct drbd_tconn *tconn)
*/
void drbd_thread_current_set_cpu(struct drbd_thread *thi)
{
+ struct drbd_resource *resource = thi->resource;
struct task_struct *p = current;
if (!thi->reset_cpu_mask)
return;
thi->reset_cpu_mask = 0;
- set_cpus_allowed_ptr(p, thi->tconn->cpu_mask);
+ set_cpus_allowed_ptr(p, resource->cpu_mask);
}
+#else
+#define drbd_calc_cpu_mask(A) ({})
#endif
/**
@@ -560,9 +562,9 @@ void drbd_thread_current_set_cpu(struct drbd_thread *thi)
* word aligned on 64-bit architectures. (The bitmap send and receive code
* relies on this.)
*/
-unsigned int drbd_header_size(struct drbd_tconn *tconn)
+unsigned int drbd_header_size(struct drbd_connection *connection)
{
- if (tconn->agreed_pro_version >= 100) {
+ if (connection->agreed_pro_version >= 100) {
BUILD_BUG_ON(!IS_ALIGNED(sizeof(struct p_header100), 8));
return sizeof(struct p_header100);
} else {
@@ -600,44 +602,44 @@ static unsigned int prepare_header100(struct p_header100 *h, enum drbd_packet cm
return sizeof(struct p_header100);
}
-static unsigned int prepare_header(struct drbd_tconn *tconn, int vnr,
+static unsigned int prepare_header(struct drbd_connection *connection, int vnr,
void *buffer, enum drbd_packet cmd, int size)
{
- if (tconn->agreed_pro_version >= 100)
+ if (connection->agreed_pro_version >= 100)
return prepare_header100(buffer, cmd, size, vnr);
- else if (tconn->agreed_pro_version >= 95 &&
+ else if (connection->agreed_pro_version >= 95 &&
size > DRBD_MAX_SIZE_H80_PACKET)
return prepare_header95(buffer, cmd, size);
else
return prepare_header80(buffer, cmd, size);
}
-static void *__conn_prepare_command(struct drbd_tconn *tconn,
+static void *__conn_prepare_command(struct drbd_connection *connection,
struct drbd_socket *sock)
{
if (!sock->socket)
return NULL;
- return sock->sbuf + drbd_header_size(tconn);
+ return sock->sbuf + drbd_header_size(connection);
}
-void *conn_prepare_command(struct drbd_tconn *tconn, struct drbd_socket *sock)
+void *conn_prepare_command(struct drbd_connection *connection, struct drbd_socket *sock)
{
void *p;
mutex_lock(&sock->mutex);
- p = __conn_prepare_command(tconn, sock);
+ p = __conn_prepare_command(connection, sock);
if (!p)
mutex_unlock(&sock->mutex);
return p;
}
-void *drbd_prepare_command(struct drbd_conf *mdev, struct drbd_socket *sock)
+void *drbd_prepare_command(struct drbd_peer_device *peer_device, struct drbd_socket *sock)
{
- return conn_prepare_command(mdev->tconn, sock);
+ return conn_prepare_command(peer_device->connection, sock);
}
-static int __send_command(struct drbd_tconn *tconn, int vnr,
+static int __send_command(struct drbd_connection *connection, int vnr,
struct drbd_socket *sock, enum drbd_packet cmd,
unsigned int header_size, void *data,
unsigned int size)
@@ -654,82 +656,82 @@ static int __send_command(struct drbd_tconn *tconn, int vnr,
*/
msg_flags = data ? MSG_MORE : 0;
- header_size += prepare_header(tconn, vnr, sock->sbuf, cmd,
+ header_size += prepare_header(connection, vnr, sock->sbuf, cmd,
header_size + size);
- err = drbd_send_all(tconn, sock->socket, sock->sbuf, header_size,
+ err = drbd_send_all(connection, sock->socket, sock->sbuf, header_size,
msg_flags);
if (data && !err)
- err = drbd_send_all(tconn, sock->socket, data, size, 0);
+ err = drbd_send_all(connection, sock->socket, data, size, 0);
return err;
}
-static int __conn_send_command(struct drbd_tconn *tconn, struct drbd_socket *sock,
+static int __conn_send_command(struct drbd_connection *connection, struct drbd_socket *sock,
enum drbd_packet cmd, unsigned int header_size,
void *data, unsigned int size)
{
- return __send_command(tconn, 0, sock, cmd, header_size, data, size);
+ return __send_command(connection, 0, sock, cmd, header_size, data, size);
}
-int conn_send_command(struct drbd_tconn *tconn, struct drbd_socket *sock,
+int conn_send_command(struct drbd_connection *connection, struct drbd_socket *sock,
enum drbd_packet cmd, unsigned int header_size,
void *data, unsigned int size)
{
int err;
- err = __conn_send_command(tconn, sock, cmd, header_size, data, size);
+ err = __conn_send_command(connection, sock, cmd, header_size, data, size);
mutex_unlock(&sock->mutex);
return err;
}
-int drbd_send_command(struct drbd_conf *mdev, struct drbd_socket *sock,
+int drbd_send_command(struct drbd_peer_device *peer_device, struct drbd_socket *sock,
enum drbd_packet cmd, unsigned int header_size,
void *data, unsigned int size)
{
int err;
- err = __send_command(mdev->tconn, mdev->vnr, sock, cmd, header_size,
- data, size);
+ err = __send_command(peer_device->connection, peer_device->device->vnr,
+ sock, cmd, header_size, data, size);
mutex_unlock(&sock->mutex);
return err;
}
-int drbd_send_ping(struct drbd_tconn *tconn)
+int drbd_send_ping(struct drbd_connection *connection)
{
struct drbd_socket *sock;
- sock = &tconn->meta;
- if (!conn_prepare_command(tconn, sock))
+ sock = &connection->meta;
+ if (!conn_prepare_command(connection, sock))
return -EIO;
- return conn_send_command(tconn, sock, P_PING, 0, NULL, 0);
+ return conn_send_command(connection, sock, P_PING, 0, NULL, 0);
}
-int drbd_send_ping_ack(struct drbd_tconn *tconn)
+int drbd_send_ping_ack(struct drbd_connection *connection)
{
struct drbd_socket *sock;
- sock = &tconn->meta;
- if (!conn_prepare_command(tconn, sock))
+ sock = &connection->meta;
+ if (!conn_prepare_command(connection, sock))
return -EIO;
- return conn_send_command(tconn, sock, P_PING_ACK, 0, NULL, 0);
+ return conn_send_command(connection, sock, P_PING_ACK, 0, NULL, 0);
}
-int drbd_send_sync_param(struct drbd_conf *mdev)
+int drbd_send_sync_param(struct drbd_peer_device *peer_device)
{
struct drbd_socket *sock;
struct p_rs_param_95 *p;
int size;
- const int apv = mdev->tconn->agreed_pro_version;
+ const int apv = peer_device->connection->agreed_pro_version;
enum drbd_packet cmd;
struct net_conf *nc;
struct disk_conf *dc;
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (!p)
return -EIO;
rcu_read_lock();
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(peer_device->connection->net_conf);
size = apv <= 87 ? sizeof(struct p_rs_param)
: apv == 88 ? sizeof(struct p_rs_param)
@@ -742,14 +744,14 @@ int drbd_send_sync_param(struct drbd_conf *mdev)
/* initialize verify_alg and csums_alg */
memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX);
- if (get_ldev(mdev)) {
- dc = rcu_dereference(mdev->ldev->disk_conf);
+ if (get_ldev(peer_device->device)) {
+ dc = rcu_dereference(peer_device->device->ldev->disk_conf);
p->resync_rate = cpu_to_be32(dc->resync_rate);
p->c_plan_ahead = cpu_to_be32(dc->c_plan_ahead);
p->c_delay_target = cpu_to_be32(dc->c_delay_target);
p->c_fill_target = cpu_to_be32(dc->c_fill_target);
p->c_max_rate = cpu_to_be32(dc->c_max_rate);
- put_ldev(mdev);
+ put_ldev(peer_device->device);
} else {
p->resync_rate = cpu_to_be32(DRBD_RESYNC_RATE_DEF);
p->c_plan_ahead = cpu_to_be32(DRBD_C_PLAN_AHEAD_DEF);
@@ -764,33 +766,33 @@ int drbd_send_sync_param(struct drbd_conf *mdev)
strcpy(p->csums_alg, nc->csums_alg);
rcu_read_unlock();
- return drbd_send_command(mdev, sock, cmd, size, NULL, 0);
+ return drbd_send_command(peer_device, sock, cmd, size, NULL, 0);
}
-int __drbd_send_protocol(struct drbd_tconn *tconn, enum drbd_packet cmd)
+int __drbd_send_protocol(struct drbd_connection *connection, enum drbd_packet cmd)
{
struct drbd_socket *sock;
struct p_protocol *p;
struct net_conf *nc;
int size, cf;
- sock = &tconn->data;
- p = __conn_prepare_command(tconn, sock);
+ sock = &connection->data;
+ p = __conn_prepare_command(connection, sock);
if (!p)
return -EIO;
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
+ nc = rcu_dereference(connection->net_conf);
- if (nc->tentative && tconn->agreed_pro_version < 92) {
+ if (nc->tentative && connection->agreed_pro_version < 92) {
rcu_read_unlock();
mutex_unlock(&sock->mutex);
- conn_err(tconn, "--dry-run is not supported by peer");
+ drbd_err(connection, "--dry-run is not supported by peer");
return -EOPNOTSUPP;
}
size = sizeof(*p);
- if (tconn->agreed_pro_version >= 87)
+ if (connection->agreed_pro_version >= 87)
size += strlen(nc->integrity_alg) + 1;
p->protocol = cpu_to_be32(nc->wire_protocol);
@@ -805,128 +807,131 @@ int __drbd_send_protocol(struct drbd_tconn *tconn, enum drbd_packet cmd)
cf |= CF_DRY_RUN;
p->conn_flags = cpu_to_be32(cf);
- if (tconn->agreed_pro_version >= 87)
+ if (connection->agreed_pro_version >= 87)
strcpy(p->integrity_alg, nc->integrity_alg);
rcu_read_unlock();
- return __conn_send_command(tconn, sock, cmd, size, NULL, 0);
+ return __conn_send_command(connection, sock, cmd, size, NULL, 0);
}
-int drbd_send_protocol(struct drbd_tconn *tconn)
+int drbd_send_protocol(struct drbd_connection *connection)
{
int err;
- mutex_lock(&tconn->data.mutex);
- err = __drbd_send_protocol(tconn, P_PROTOCOL);
- mutex_unlock(&tconn->data.mutex);
+ mutex_lock(&connection->data.mutex);
+ err = __drbd_send_protocol(connection, P_PROTOCOL);
+ mutex_unlock(&connection->data.mutex);
return err;
}
-int _drbd_send_uuids(struct drbd_conf *mdev, u64 uuid_flags)
+static int _drbd_send_uuids(struct drbd_peer_device *peer_device, u64 uuid_flags)
{
+ struct drbd_device *device = peer_device->device;
struct drbd_socket *sock;
struct p_uuids *p;
int i;
- if (!get_ldev_if_state(mdev, D_NEGOTIATING))
+ if (!get_ldev_if_state(device, D_NEGOTIATING))
return 0;
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (!p) {
- put_ldev(mdev);
+ put_ldev(device);
return -EIO;
}
- spin_lock_irq(&mdev->ldev->md.uuid_lock);
+ spin_lock_irq(&device->ldev->md.uuid_lock);
for (i = UI_CURRENT; i < UI_SIZE; i++)
- p->uuid[i] = cpu_to_be64(mdev->ldev->md.uuid[i]);
- spin_unlock_irq(&mdev->ldev->md.uuid_lock);
+ p->uuid[i] = cpu_to_be64(device->ldev->md.uuid[i]);
+ spin_unlock_irq(&device->ldev->md.uuid_lock);
- mdev->comm_bm_set = drbd_bm_total_weight(mdev);
- p->uuid[UI_SIZE] = cpu_to_be64(mdev->comm_bm_set);
+ device->comm_bm_set = drbd_bm_total_weight(device);
+ p->uuid[UI_SIZE] = cpu_to_be64(device->comm_bm_set);
rcu_read_lock();
- uuid_flags |= rcu_dereference(mdev->tconn->net_conf)->discard_my_data ? 1 : 0;
+ uuid_flags |= rcu_dereference(peer_device->connection->net_conf)->discard_my_data ? 1 : 0;
rcu_read_unlock();
- uuid_flags |= test_bit(CRASHED_PRIMARY, &mdev->flags) ? 2 : 0;
- uuid_flags |= mdev->new_state_tmp.disk == D_INCONSISTENT ? 4 : 0;
+ uuid_flags |= test_bit(CRASHED_PRIMARY, &device->flags) ? 2 : 0;
+ uuid_flags |= device->new_state_tmp.disk == D_INCONSISTENT ? 4 : 0;
p->uuid[UI_FLAGS] = cpu_to_be64(uuid_flags);
- put_ldev(mdev);
- return drbd_send_command(mdev, sock, P_UUIDS, sizeof(*p), NULL, 0);
+ put_ldev(device);
+ return drbd_send_command(peer_device, sock, P_UUIDS, sizeof(*p), NULL, 0);
}
-int drbd_send_uuids(struct drbd_conf *mdev)
+int drbd_send_uuids(struct drbd_peer_device *peer_device)
{
- return _drbd_send_uuids(mdev, 0);
+ return _drbd_send_uuids(peer_device, 0);
}
-int drbd_send_uuids_skip_initial_sync(struct drbd_conf *mdev)
+int drbd_send_uuids_skip_initial_sync(struct drbd_peer_device *peer_device)
{
- return _drbd_send_uuids(mdev, 8);
+ return _drbd_send_uuids(peer_device, 8);
}
-void drbd_print_uuids(struct drbd_conf *mdev, const char *text)
+void drbd_print_uuids(struct drbd_device *device, const char *text)
{
- if (get_ldev_if_state(mdev, D_NEGOTIATING)) {
- u64 *uuid = mdev->ldev->md.uuid;
- dev_info(DEV, "%s %016llX:%016llX:%016llX:%016llX\n",
+ if (get_ldev_if_state(device, D_NEGOTIATING)) {
+ u64 *uuid = device->ldev->md.uuid;
+ drbd_info(device, "%s %016llX:%016llX:%016llX:%016llX\n",
text,
(unsigned long long)uuid[UI_CURRENT],
(unsigned long long)uuid[UI_BITMAP],
(unsigned long long)uuid[UI_HISTORY_START],
(unsigned long long)uuid[UI_HISTORY_END]);
- put_ldev(mdev);
+ put_ldev(device);
} else {
- dev_info(DEV, "%s effective data uuid: %016llX\n",
+ drbd_info(device, "%s effective data uuid: %016llX\n",
text,
- (unsigned long long)mdev->ed_uuid);
+ (unsigned long long)device->ed_uuid);
}
}
-void drbd_gen_and_send_sync_uuid(struct drbd_conf *mdev)
+void drbd_gen_and_send_sync_uuid(struct drbd_peer_device *peer_device)
{
+ struct drbd_device *device = peer_device->device;
struct drbd_socket *sock;
struct p_rs_uuid *p;
u64 uuid;
- D_ASSERT(mdev->state.disk == D_UP_TO_DATE);
+ D_ASSERT(device, device->state.disk == D_UP_TO_DATE);
- uuid = mdev->ldev->md.uuid[UI_BITMAP];
+ uuid = device->ldev->md.uuid[UI_BITMAP];
if (uuid && uuid != UUID_JUST_CREATED)
uuid = uuid + UUID_NEW_BM_OFFSET;
else
get_random_bytes(&uuid, sizeof(u64));
- drbd_uuid_set(mdev, UI_BITMAP, uuid);
- drbd_print_uuids(mdev, "updated sync UUID");
- drbd_md_sync(mdev);
+ drbd_uuid_set(device, UI_BITMAP, uuid);
+ drbd_print_uuids(device, "updated sync UUID");
+ drbd_md_sync(device);
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (p) {
p->uuid = cpu_to_be64(uuid);
- drbd_send_command(mdev, sock, P_SYNC_UUID, sizeof(*p), NULL, 0);
+ drbd_send_command(peer_device, sock, P_SYNC_UUID, sizeof(*p), NULL, 0);
}
}
-int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags flags)
+int drbd_send_sizes(struct drbd_peer_device *peer_device, int trigger_reply, enum dds_flags flags)
{
+ struct drbd_device *device = peer_device->device;
struct drbd_socket *sock;
struct p_sizes *p;
sector_t d_size, u_size;
int q_order_type;
unsigned int max_bio_size;
- if (get_ldev_if_state(mdev, D_NEGOTIATING)) {
- D_ASSERT(mdev->ldev->backing_bdev);
- d_size = drbd_get_max_capacity(mdev->ldev);
+ if (get_ldev_if_state(device, D_NEGOTIATING)) {
+ D_ASSERT(device, device->ldev->backing_bdev);
+ d_size = drbd_get_max_capacity(device->ldev);
rcu_read_lock();
- u_size = rcu_dereference(mdev->ldev->disk_conf)->disk_size;
+ u_size = rcu_dereference(device->ldev->disk_conf)->disk_size;
rcu_read_unlock();
- q_order_type = drbd_queue_order_type(mdev);
- max_bio_size = queue_max_hw_sectors(mdev->ldev->backing_bdev->bd_disk->queue) << 9;
+ q_order_type = drbd_queue_order_type(device);
+ max_bio_size = queue_max_hw_sectors(device->ldev->backing_bdev->bd_disk->queue) << 9;
max_bio_size = min(max_bio_size, DRBD_MAX_BIO_SIZE);
- put_ldev(mdev);
+ put_ldev(device);
} else {
d_size = 0;
u_size = 0;
@@ -934,45 +939,45 @@ int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags fl
max_bio_size = DRBD_MAX_BIO_SIZE; /* ... multiple BIOs per peer_request */
}
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (!p)
return -EIO;
- if (mdev->tconn->agreed_pro_version <= 94)
+ if (peer_device->connection->agreed_pro_version <= 94)
max_bio_size = min(max_bio_size, DRBD_MAX_SIZE_H80_PACKET);
- else if (mdev->tconn->agreed_pro_version < 100)
+ else if (peer_device->connection->agreed_pro_version < 100)
max_bio_size = min(max_bio_size, DRBD_MAX_BIO_SIZE_P95);
p->d_size = cpu_to_be64(d_size);
p->u_size = cpu_to_be64(u_size);
- p->c_size = cpu_to_be64(trigger_reply ? 0 : drbd_get_capacity(mdev->this_bdev));
+ p->c_size = cpu_to_be64(trigger_reply ? 0 : drbd_get_capacity(device->this_bdev));
p->max_bio_size = cpu_to_be32(max_bio_size);
p->queue_order_type = cpu_to_be16(q_order_type);
p->dds_flags = cpu_to_be16(flags);
- return drbd_send_command(mdev, sock, P_SIZES, sizeof(*p), NULL, 0);
+ return drbd_send_command(peer_device, sock, P_SIZES, sizeof(*p), NULL, 0);
}
/**
* drbd_send_current_state() - Sends the drbd state to the peer
- * @mdev: DRBD device.
+ * @peer_device: DRBD peer device.
*/
-int drbd_send_current_state(struct drbd_conf *mdev)
+int drbd_send_current_state(struct drbd_peer_device *peer_device)
{
struct drbd_socket *sock;
struct p_state *p;
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (!p)
return -EIO;
- p->state = cpu_to_be32(mdev->state.i); /* Within the send mutex */
- return drbd_send_command(mdev, sock, P_STATE, sizeof(*p), NULL, 0);
+ p->state = cpu_to_be32(peer_device->device->state.i); /* Within the send mutex */
+ return drbd_send_command(peer_device, sock, P_STATE, sizeof(*p), NULL, 0);
}
/**
* drbd_send_state() - After a state change, sends the new state to the peer
- * @mdev: DRBD device.
+ * @peer_device: DRBD peer device.
* @state: the state to send, not necessarily the current state.
*
* Each state change queues an "after_state_ch" work, which will eventually
@@ -980,73 +985,73 @@ int drbd_send_current_state(struct drbd_conf *mdev)
* between queuing and processing of the after_state_ch work, we still
* want to send each intermediary state in the order it occurred.
*/
-int drbd_send_state(struct drbd_conf *mdev, union drbd_state state)
+int drbd_send_state(struct drbd_peer_device *peer_device, union drbd_state state)
{
struct drbd_socket *sock;
struct p_state *p;
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (!p)
return -EIO;
p->state = cpu_to_be32(state.i); /* Within the send mutex */
- return drbd_send_command(mdev, sock, P_STATE, sizeof(*p), NULL, 0);
+ return drbd_send_command(peer_device, sock, P_STATE, sizeof(*p), NULL, 0);
}
-int drbd_send_state_req(struct drbd_conf *mdev, union drbd_state mask, union drbd_state val)
+int drbd_send_state_req(struct drbd_peer_device *peer_device, union drbd_state mask, union drbd_state val)
{
struct drbd_socket *sock;
struct p_req_state *p;
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (!p)
return -EIO;
p->mask = cpu_to_be32(mask.i);
p->val = cpu_to_be32(val.i);
- return drbd_send_command(mdev, sock, P_STATE_CHG_REQ, sizeof(*p), NULL, 0);
+ return drbd_send_command(peer_device, sock, P_STATE_CHG_REQ, sizeof(*p), NULL, 0);
}
-int conn_send_state_req(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val)
+int conn_send_state_req(struct drbd_connection *connection, union drbd_state mask, union drbd_state val)
{
enum drbd_packet cmd;
struct drbd_socket *sock;
struct p_req_state *p;
- cmd = tconn->agreed_pro_version < 100 ? P_STATE_CHG_REQ : P_CONN_ST_CHG_REQ;
- sock = &tconn->data;
- p = conn_prepare_command(tconn, sock);
+ cmd = connection->agreed_pro_version < 100 ? P_STATE_CHG_REQ : P_CONN_ST_CHG_REQ;
+ sock = &connection->data;
+ p = conn_prepare_command(connection, sock);
if (!p)
return -EIO;
p->mask = cpu_to_be32(mask.i);
p->val = cpu_to_be32(val.i);
- return conn_send_command(tconn, sock, cmd, sizeof(*p), NULL, 0);
+ return conn_send_command(connection, sock, cmd, sizeof(*p), NULL, 0);
}
-void drbd_send_sr_reply(struct drbd_conf *mdev, enum drbd_state_rv retcode)
+void drbd_send_sr_reply(struct drbd_peer_device *peer_device, enum drbd_state_rv retcode)
{
struct drbd_socket *sock;
struct p_req_state_reply *p;
- sock = &mdev->tconn->meta;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->meta;
+ p = drbd_prepare_command(peer_device, sock);
if (p) {
p->retcode = cpu_to_be32(retcode);
- drbd_send_command(mdev, sock, P_STATE_CHG_REPLY, sizeof(*p), NULL, 0);
+ drbd_send_command(peer_device, sock, P_STATE_CHG_REPLY, sizeof(*p), NULL, 0);
}
}
-void conn_send_sr_reply(struct drbd_tconn *tconn, enum drbd_state_rv retcode)
+void conn_send_sr_reply(struct drbd_connection *connection, enum drbd_state_rv retcode)
{
struct drbd_socket *sock;
struct p_req_state_reply *p;
- enum drbd_packet cmd = tconn->agreed_pro_version < 100 ? P_STATE_CHG_REPLY : P_CONN_ST_CHG_REPLY;
+ enum drbd_packet cmd = connection->agreed_pro_version < 100 ? P_STATE_CHG_REPLY : P_CONN_ST_CHG_REPLY;
- sock = &tconn->meta;
- p = conn_prepare_command(tconn, sock);
+ sock = &connection->meta;
+ p = conn_prepare_command(connection, sock);
if (p) {
p->retcode = cpu_to_be32(retcode);
- conn_send_command(tconn, sock, cmd, sizeof(*p), NULL, 0);
+ conn_send_command(connection, sock, cmd, sizeof(*p), NULL, 0);
}
}
@@ -1067,7 +1072,7 @@ static void dcbp_set_pad_bits(struct p_compressed_bm *p, int n)
p->encoding = (p->encoding & (~0x7 << 4)) | (n << 4);
}
-int fill_bitmap_rle_bits(struct drbd_conf *mdev,
+static int fill_bitmap_rle_bits(struct drbd_device *device,
struct p_compressed_bm *p,
unsigned int size,
struct bm_xfer_ctx *c)
@@ -1082,9 +1087,9 @@ int fill_bitmap_rle_bits(struct drbd_conf *mdev,
/* may we use this feature? */
rcu_read_lock();
- use_rle = rcu_dereference(mdev->tconn->net_conf)->use_rle;
+ use_rle = rcu_dereference(first_peer_device(device)->connection->net_conf)->use_rle;
rcu_read_unlock();
- if (!use_rle || mdev->tconn->agreed_pro_version < 90)
+ if (!use_rle || first_peer_device(device)->connection->agreed_pro_version < 90)
return 0;
if (c->bit_offset >= c->bm_bits)
@@ -1104,8 +1109,8 @@ int fill_bitmap_rle_bits(struct drbd_conf *mdev,
/* see how much plain bits we can stuff into one packet
* using RLE and VLI. */
do {
- tmp = (toggle == 0) ? _drbd_bm_find_next_zero(mdev, c->bit_offset)
- : _drbd_bm_find_next(mdev, c->bit_offset);
+ tmp = (toggle == 0) ? _drbd_bm_find_next_zero(device, c->bit_offset)
+ : _drbd_bm_find_next(device, c->bit_offset);
if (tmp == -1UL)
tmp = c->bm_bits;
rl = tmp - c->bit_offset;
@@ -1125,7 +1130,7 @@ int fill_bitmap_rle_bits(struct drbd_conf *mdev,
/* paranoia: catch zero runlength.
* can only happen if bitmap is modified while we scan it. */
if (rl == 0) {
- dev_err(DEV, "unexpected zero runlength while encoding bitmap "
+ drbd_err(device, "unexpected zero runlength while encoding bitmap "
"t:%u bo:%lu\n", toggle, c->bit_offset);
return -1;
}
@@ -1134,7 +1139,7 @@ int fill_bitmap_rle_bits(struct drbd_conf *mdev,
if (bits == -ENOBUFS) /* buffer full */
break;
if (bits <= 0) {
- dev_err(DEV, "error while encoding bitmap: %d\n", bits);
+ drbd_err(device, "error while encoding bitmap: %d\n", bits);
return 0;
}
@@ -1171,21 +1176,21 @@ int fill_bitmap_rle_bits(struct drbd_conf *mdev,
* code upon failure.
*/
static int
-send_bitmap_rle_or_plain(struct drbd_conf *mdev, struct bm_xfer_ctx *c)
+send_bitmap_rle_or_plain(struct drbd_device *device, struct bm_xfer_ctx *c)
{
- struct drbd_socket *sock = &mdev->tconn->data;
- unsigned int header_size = drbd_header_size(mdev->tconn);
+ struct drbd_socket *sock = &first_peer_device(device)->connection->data;
+ unsigned int header_size = drbd_header_size(first_peer_device(device)->connection);
struct p_compressed_bm *p = sock->sbuf + header_size;
int len, err;
- len = fill_bitmap_rle_bits(mdev, p,
+ len = fill_bitmap_rle_bits(device, p,
DRBD_SOCKET_BUFFER_SIZE - header_size - sizeof(*p), c);
if (len < 0)
return -EIO;
if (len) {
dcbp_set_code(p, RLE_VLI_Bits);
- err = __send_command(mdev->tconn, mdev->vnr, sock,
+ err = __send_command(first_peer_device(device)->connection, device->vnr, sock,
P_COMPRESSED_BITMAP, sizeof(*p) + len,
NULL, 0);
c->packets[0]++;
@@ -1205,8 +1210,8 @@ send_bitmap_rle_or_plain(struct drbd_conf *mdev, struct bm_xfer_ctx *c)
c->bm_words - c->word_offset);
len = num_words * sizeof(*p);
if (len)
- drbd_bm_get_lel(mdev, c->word_offset, num_words, p);
- err = __send_command(mdev->tconn, mdev->vnr, sock, P_BITMAP, len, NULL, 0);
+ drbd_bm_get_lel(device, c->word_offset, num_words, p);
+ err = __send_command(first_peer_device(device)->connection, device->vnr, sock, P_BITMAP, len, NULL, 0);
c->word_offset += num_words;
c->bit_offset = c->word_offset * BITS_PER_LONG;
@@ -1218,7 +1223,7 @@ send_bitmap_rle_or_plain(struct drbd_conf *mdev, struct bm_xfer_ctx *c)
}
if (!err) {
if (len == 0) {
- INFO_bm_xfer_stats(mdev, "send", c);
+ INFO_bm_xfer_stats(device, "send", c);
return 0;
} else
return 1;
@@ -1227,128 +1232,128 @@ send_bitmap_rle_or_plain(struct drbd_conf *mdev, struct bm_xfer_ctx *c)
}
/* See the comment at receive_bitmap() */
-static int _drbd_send_bitmap(struct drbd_conf *mdev)
+static int _drbd_send_bitmap(struct drbd_device *device)
{
struct bm_xfer_ctx c;
int err;
- if (!expect(mdev->bitmap))
+ if (!expect(device->bitmap))
return false;
- if (get_ldev(mdev)) {
- if (drbd_md_test_flag(mdev->ldev, MDF_FULL_SYNC)) {
- dev_info(DEV, "Writing the whole bitmap, MDF_FullSync was set.\n");
- drbd_bm_set_all(mdev);
- if (drbd_bm_write(mdev)) {
+ if (get_ldev(device)) {
+ if (drbd_md_test_flag(device->ldev, MDF_FULL_SYNC)) {
+ drbd_info(device, "Writing the whole bitmap, MDF_FullSync was set.\n");
+ drbd_bm_set_all(device);
+ if (drbd_bm_write(device)) {
/* write_bm did fail! Leave full sync flag set in Meta P_DATA
* but otherwise process as per normal - need to tell other
* side that a full resync is required! */
- dev_err(DEV, "Failed to write bitmap to disk!\n");
+ drbd_err(device, "Failed to write bitmap to disk!\n");
} else {
- drbd_md_clear_flag(mdev, MDF_FULL_SYNC);
- drbd_md_sync(mdev);
+ drbd_md_clear_flag(device, MDF_FULL_SYNC);
+ drbd_md_sync(device);
}
}
- put_ldev(mdev);
+ put_ldev(device);
}
c = (struct bm_xfer_ctx) {
- .bm_bits = drbd_bm_bits(mdev),
- .bm_words = drbd_bm_words(mdev),
+ .bm_bits = drbd_bm_bits(device),
+ .bm_words = drbd_bm_words(device),
};
do {
- err = send_bitmap_rle_or_plain(mdev, &c);
+ err = send_bitmap_rle_or_plain(device, &c);
} while (err > 0);
return err == 0;
}
-int drbd_send_bitmap(struct drbd_conf *mdev)
+int drbd_send_bitmap(struct drbd_device *device)
{
- struct drbd_socket *sock = &mdev->tconn->data;
+ struct drbd_socket *sock = &first_peer_device(device)->connection->data;
int err = -1;
mutex_lock(&sock->mutex);
if (sock->socket)
- err = !_drbd_send_bitmap(mdev);
+ err = !_drbd_send_bitmap(device);
mutex_unlock(&sock->mutex);
return err;
}
-void drbd_send_b_ack(struct drbd_tconn *tconn, u32 barrier_nr, u32 set_size)
+void drbd_send_b_ack(struct drbd_connection *connection, u32 barrier_nr, u32 set_size)
{
struct drbd_socket *sock;
struct p_barrier_ack *p;
- if (tconn->cstate < C_WF_REPORT_PARAMS)
+ if (connection->cstate < C_WF_REPORT_PARAMS)
return;
- sock = &tconn->meta;
- p = conn_prepare_command(tconn, sock);
+ sock = &connection->meta;
+ p = conn_prepare_command(connection, sock);
if (!p)
return;
p->barrier = barrier_nr;
p->set_size = cpu_to_be32(set_size);
- conn_send_command(tconn, sock, P_BARRIER_ACK, sizeof(*p), NULL, 0);
+ conn_send_command(connection, sock, P_BARRIER_ACK, sizeof(*p), NULL, 0);
}
/**
* _drbd_send_ack() - Sends an ack packet
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @cmd: Packet command code.
* @sector: sector, needs to be in big endian byte order
* @blksize: size in byte, needs to be in big endian byte order
* @block_id: Id, big endian byte order
*/
-static int _drbd_send_ack(struct drbd_conf *mdev, enum drbd_packet cmd,
+static int _drbd_send_ack(struct drbd_peer_device *peer_device, enum drbd_packet cmd,
u64 sector, u32 blksize, u64 block_id)
{
struct drbd_socket *sock;
struct p_block_ack *p;
- if (mdev->state.conn < C_CONNECTED)
+ if (peer_device->device->state.conn < C_CONNECTED)
return -EIO;
- sock = &mdev->tconn->meta;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->meta;
+ p = drbd_prepare_command(peer_device, sock);
if (!p)
return -EIO;
p->sector = sector;
p->block_id = block_id;
p->blksize = blksize;
- p->seq_num = cpu_to_be32(atomic_inc_return(&mdev->packet_seq));
- return drbd_send_command(mdev, sock, cmd, sizeof(*p), NULL, 0);
+ p->seq_num = cpu_to_be32(atomic_inc_return(&peer_device->device->packet_seq));
+ return drbd_send_command(peer_device, sock, cmd, sizeof(*p), NULL, 0);
}
/* dp->sector and dp->block_id already/still in network byte order,
* data_size is payload size according to dp->head,
* and may need to be corrected for digest size. */
-void drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packet cmd,
+void drbd_send_ack_dp(struct drbd_peer_device *peer_device, enum drbd_packet cmd,
struct p_data *dp, int data_size)
{
- if (mdev->tconn->peer_integrity_tfm)
- data_size -= crypto_hash_digestsize(mdev->tconn->peer_integrity_tfm);
- _drbd_send_ack(mdev, cmd, dp->sector, cpu_to_be32(data_size),
+ if (peer_device->connection->peer_integrity_tfm)
+ data_size -= crypto_hash_digestsize(peer_device->connection->peer_integrity_tfm);
+ _drbd_send_ack(peer_device, cmd, dp->sector, cpu_to_be32(data_size),
dp->block_id);
}
-void drbd_send_ack_rp(struct drbd_conf *mdev, enum drbd_packet cmd,
+void drbd_send_ack_rp(struct drbd_peer_device *peer_device, enum drbd_packet cmd,
struct p_block_req *rp)
{
- _drbd_send_ack(mdev, cmd, rp->sector, rp->blksize, rp->block_id);
+ _drbd_send_ack(peer_device, cmd, rp->sector, rp->blksize, rp->block_id);
}
/**
* drbd_send_ack() - Sends an ack packet
- * @mdev: DRBD device
+ * @device: DRBD device
* @cmd: packet command code
* @peer_req: peer request
*/
-int drbd_send_ack(struct drbd_conf *mdev, enum drbd_packet cmd,
+int drbd_send_ack(struct drbd_peer_device *peer_device, enum drbd_packet cmd,
struct drbd_peer_request *peer_req)
{
- return _drbd_send_ack(mdev, cmd,
+ return _drbd_send_ack(peer_device, cmd,
cpu_to_be64(peer_req->i.sector),
cpu_to_be32(peer_req->i.size),
peer_req->block_id);
@@ -1356,32 +1361,32 @@ int drbd_send_ack(struct drbd_conf *mdev, enum drbd_packet cmd,
/* This function misuses the block_id field to signal if the blocks
* are is sync or not. */
-int drbd_send_ack_ex(struct drbd_conf *mdev, enum drbd_packet cmd,
+int drbd_send_ack_ex(struct drbd_peer_device *peer_device, enum drbd_packet cmd,
sector_t sector, int blksize, u64 block_id)
{
- return _drbd_send_ack(mdev, cmd,
+ return _drbd_send_ack(peer_device, cmd,
cpu_to_be64(sector),
cpu_to_be32(blksize),
cpu_to_be64(block_id));
}
-int drbd_send_drequest(struct drbd_conf *mdev, int cmd,
+int drbd_send_drequest(struct drbd_peer_device *peer_device, int cmd,
sector_t sector, int size, u64 block_id)
{
struct drbd_socket *sock;
struct p_block_req *p;
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (!p)
return -EIO;
p->sector = cpu_to_be64(sector);
p->block_id = block_id;
p->blksize = cpu_to_be32(size);
- return drbd_send_command(mdev, sock, cmd, sizeof(*p), NULL, 0);
+ return drbd_send_command(peer_device, sock, cmd, sizeof(*p), NULL, 0);
}
-int drbd_send_drequest_csum(struct drbd_conf *mdev, sector_t sector, int size,
+int drbd_send_drequest_csum(struct drbd_peer_device *peer_device, sector_t sector, int size,
void *digest, int digest_size, enum drbd_packet cmd)
{
struct drbd_socket *sock;
@@ -1389,64 +1394,63 @@ int drbd_send_drequest_csum(struct drbd_conf *mdev, sector_t sector, int size,
/* FIXME: Put the digest into the preallocated socket buffer. */
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (!p)
return -EIO;
p->sector = cpu_to_be64(sector);
p->block_id = ID_SYNCER /* unused */;
p->blksize = cpu_to_be32(size);
- return drbd_send_command(mdev, sock, cmd, sizeof(*p),
- digest, digest_size);
+ return drbd_send_command(peer_device, sock, cmd, sizeof(*p), digest, digest_size);
}
-int drbd_send_ov_request(struct drbd_conf *mdev, sector_t sector, int size)
+int drbd_send_ov_request(struct drbd_peer_device *peer_device, sector_t sector, int size)
{
struct drbd_socket *sock;
struct p_block_req *p;
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (!p)
return -EIO;
p->sector = cpu_to_be64(sector);
p->block_id = ID_SYNCER /* unused */;
p->blksize = cpu_to_be32(size);
- return drbd_send_command(mdev, sock, P_OV_REQUEST, sizeof(*p), NULL, 0);
+ return drbd_send_command(peer_device, sock, P_OV_REQUEST, sizeof(*p), NULL, 0);
}
/* called on sndtimeo
* returns false if we should retry,
* true if we think connection is dead
*/
-static int we_should_drop_the_connection(struct drbd_tconn *tconn, struct socket *sock)
+static int we_should_drop_the_connection(struct drbd_connection *connection, struct socket *sock)
{
int drop_it;
- /* long elapsed = (long)(jiffies - mdev->last_received); */
+ /* long elapsed = (long)(jiffies - device->last_received); */
- drop_it = tconn->meta.socket == sock
- || !tconn->asender.task
- || get_t_state(&tconn->asender) != RUNNING
- || tconn->cstate < C_WF_REPORT_PARAMS;
+ drop_it = connection->meta.socket == sock
+ || !connection->asender.task
+ || get_t_state(&connection->asender) != RUNNING
+ || connection->cstate < C_WF_REPORT_PARAMS;
if (drop_it)
return true;
- drop_it = !--tconn->ko_count;
+ drop_it = !--connection->ko_count;
if (!drop_it) {
- conn_err(tconn, "[%s/%d] sock_sendmsg time expired, ko = %u\n",
- current->comm, current->pid, tconn->ko_count);
- request_ping(tconn);
+ drbd_err(connection, "[%s/%d] sock_sendmsg time expired, ko = %u\n",
+ current->comm, current->pid, connection->ko_count);
+ request_ping(connection);
}
- return drop_it; /* && (mdev->state == R_PRIMARY) */;
+ return drop_it; /* && (device->state == R_PRIMARY) */;
}
-static void drbd_update_congested(struct drbd_tconn *tconn)
+static void drbd_update_congested(struct drbd_connection *connection)
{
- struct sock *sk = tconn->data.socket->sk;
+ struct sock *sk = connection->data.socket->sk;
if (sk->sk_wmem_queued > sk->sk_sndbuf * 4 / 5)
- set_bit(NET_CONGESTED, &tconn->flags);
+ set_bit(NET_CONGESTED, &connection->flags);
}
/* The idea of sendpage seems to be to put some kind of reference
@@ -1470,26 +1474,26 @@ static void drbd_update_congested(struct drbd_tconn *tconn)
* As a workaround, we disable sendpage on pages
* with page_count == 0 or PageSlab.
*/
-static int _drbd_no_send_page(struct drbd_conf *mdev, struct page *page,
+static int _drbd_no_send_page(struct drbd_peer_device *peer_device, struct page *page,
int offset, size_t size, unsigned msg_flags)
{
struct socket *socket;
void *addr;
int err;
- socket = mdev->tconn->data.socket;
+ socket = peer_device->connection->data.socket;
addr = kmap(page) + offset;
- err = drbd_send_all(mdev->tconn, socket, addr, size, msg_flags);
+ err = drbd_send_all(peer_device->connection, socket, addr, size, msg_flags);
kunmap(page);
if (!err)
- mdev->send_cnt += size >> 9;
+ peer_device->device->send_cnt += size >> 9;
return err;
}
-static int _drbd_send_page(struct drbd_conf *mdev, struct page *page,
+static int _drbd_send_page(struct drbd_peer_device *peer_device, struct page *page,
int offset, size_t size, unsigned msg_flags)
{
- struct socket *socket = mdev->tconn->data.socket;
+ struct socket *socket = peer_device->connection->data.socket;
mm_segment_t oldfs = get_fs();
int len = size;
int err = -EIO;
@@ -1501,10 +1505,10 @@ static int _drbd_send_page(struct drbd_conf *mdev, struct page *page,
* __page_cache_release a page that would actually still be referenced
* by someone, leading to some obscure delayed Oops somewhere else. */
if (disable_sendpage || (page_count(page) < 1) || PageSlab(page))
- return _drbd_no_send_page(mdev, page, offset, size, msg_flags);
+ return _drbd_no_send_page(peer_device, page, offset, size, msg_flags);
msg_flags |= MSG_NOSIGNAL;
- drbd_update_congested(mdev->tconn);
+ drbd_update_congested(peer_device->connection);
set_fs(KERNEL_DS);
do {
int sent;
@@ -1512,11 +1516,11 @@ static int _drbd_send_page(struct drbd_conf *mdev, struct page *page,
sent = socket->ops->sendpage(socket, page, offset, len, msg_flags);
if (sent <= 0) {
if (sent == -EAGAIN) {
- if (we_should_drop_the_connection(mdev->tconn, socket))
+ if (we_should_drop_the_connection(peer_device->connection, socket))
break;
continue;
}
- dev_warn(DEV, "%s: size=%d len=%d sent=%d\n",
+ drbd_warn(peer_device->device, "%s: size=%d len=%d sent=%d\n",
__func__, (int)size, len, sent);
if (sent < 0)
err = sent;
@@ -1524,18 +1528,18 @@ static int _drbd_send_page(struct drbd_conf *mdev, struct page *page,
}
len -= sent;
offset += sent;
- } while (len > 0 /* THINK && mdev->cstate >= C_CONNECTED*/);
+ } while (len > 0 /* THINK && device->cstate >= C_CONNECTED*/);
set_fs(oldfs);
- clear_bit(NET_CONGESTED, &mdev->tconn->flags);
+ clear_bit(NET_CONGESTED, &peer_device->connection->flags);
if (len == 0) {
err = 0;
- mdev->send_cnt += size >> 9;
+ peer_device->device->send_cnt += size >> 9;
}
return err;
}
-static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio)
+static int _drbd_send_bio(struct drbd_peer_device *peer_device, struct bio *bio)
{
struct bio_vec bvec;
struct bvec_iter iter;
@@ -1544,7 +1548,7 @@ static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio)
bio_for_each_segment(bvec, bio, iter) {
int err;
- err = _drbd_no_send_page(mdev, bvec.bv_page,
+ err = _drbd_no_send_page(peer_device, bvec.bv_page,
bvec.bv_offset, bvec.bv_len,
bio_iter_last(bvec, iter)
? 0 : MSG_MORE);
@@ -1554,7 +1558,7 @@ static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio)
return 0;
}
-static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio)
+static int _drbd_send_zc_bio(struct drbd_peer_device *peer_device, struct bio *bio)
{
struct bio_vec bvec;
struct bvec_iter iter;
@@ -1563,7 +1567,7 @@ static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio)
bio_for_each_segment(bvec, bio, iter) {
int err;
- err = _drbd_send_page(mdev, bvec.bv_page,
+ err = _drbd_send_page(peer_device, bvec.bv_page,
bvec.bv_offset, bvec.bv_len,
bio_iter_last(bvec, iter) ? 0 : MSG_MORE);
if (err)
@@ -1572,7 +1576,7 @@ static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio)
return 0;
}
-static int _drbd_send_zc_ee(struct drbd_conf *mdev,
+static int _drbd_send_zc_ee(struct drbd_peer_device *peer_device,
struct drbd_peer_request *peer_req)
{
struct page *page = peer_req->pages;
@@ -1583,7 +1587,7 @@ static int _drbd_send_zc_ee(struct drbd_conf *mdev,
page_chain_for_each(page) {
unsigned l = min_t(unsigned, len, PAGE_SIZE);
- err = _drbd_send_page(mdev, page, 0, l,
+ err = _drbd_send_page(peer_device, page, 0, l,
page_chain_next(page) ? MSG_MORE : 0);
if (err)
return err;
@@ -1592,9 +1596,9 @@ static int _drbd_send_zc_ee(struct drbd_conf *mdev,
return 0;
}
-static u32 bio_flags_to_wire(struct drbd_conf *mdev, unsigned long bi_rw)
+static u32 bio_flags_to_wire(struct drbd_connection *connection, unsigned long bi_rw)
{
- if (mdev->tconn->agreed_pro_version >= 95)
+ if (connection->agreed_pro_version >= 95)
return (bi_rw & REQ_SYNC ? DP_RW_SYNC : 0) |
(bi_rw & REQ_FUA ? DP_FUA : 0) |
(bi_rw & REQ_FLUSH ? DP_FLUSH : 0) |
@@ -1606,28 +1610,30 @@ static u32 bio_flags_to_wire(struct drbd_conf *mdev, unsigned long bi_rw)
/* Used to send write requests
* R_PRIMARY -> Peer (P_DATA)
*/
-int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req)
+int drbd_send_dblock(struct drbd_peer_device *peer_device, struct drbd_request *req)
{
+ struct drbd_device *device = peer_device->device;
struct drbd_socket *sock;
struct p_data *p;
unsigned int dp_flags = 0;
int dgs;
int err;
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
- dgs = mdev->tconn->integrity_tfm ? crypto_hash_digestsize(mdev->tconn->integrity_tfm) : 0;
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
+ dgs = peer_device->connection->integrity_tfm ?
+ crypto_hash_digestsize(peer_device->connection->integrity_tfm) : 0;
if (!p)
return -EIO;
p->sector = cpu_to_be64(req->i.sector);
p->block_id = (unsigned long)req;
- p->seq_num = cpu_to_be32(atomic_inc_return(&mdev->packet_seq));
- dp_flags = bio_flags_to_wire(mdev, req->master_bio->bi_rw);
- if (mdev->state.conn >= C_SYNC_SOURCE &&
- mdev->state.conn <= C_PAUSED_SYNC_T)
+ p->seq_num = cpu_to_be32(atomic_inc_return(&device->packet_seq));
+ dp_flags = bio_flags_to_wire(peer_device->connection, req->master_bio->bi_rw);
+ if (device->state.conn >= C_SYNC_SOURCE &&
+ device->state.conn <= C_PAUSED_SYNC_T)
dp_flags |= DP_MAY_SET_IN_SYNC;
- if (mdev->tconn->agreed_pro_version >= 100) {
+ if (peer_device->connection->agreed_pro_version >= 100) {
if (req->rq_state & RQ_EXP_RECEIVE_ACK)
dp_flags |= DP_SEND_RECEIVE_ACK;
if (req->rq_state & RQ_EXP_WRITE_ACK)
@@ -1635,8 +1641,8 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req)
}
p->dp_flags = cpu_to_be32(dp_flags);
if (dgs)
- drbd_csum_bio(mdev, mdev->tconn->integrity_tfm, req->master_bio, p + 1);
- err = __send_command(mdev->tconn, mdev->vnr, sock, P_DATA, sizeof(*p) + dgs, NULL, req->i.size);
+ drbd_csum_bio(peer_device->connection->integrity_tfm, req->master_bio, p + 1);
+ err = __send_command(peer_device->connection, device->vnr, sock, P_DATA, sizeof(*p) + dgs, NULL, req->i.size);
if (!err) {
/* For protocol A, we have to memcpy the payload into
* socket buffers, as we may complete right away
@@ -1650,18 +1656,18 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req)
* receiving side, we sure have detected corruption elsewhere.
*/
if (!(req->rq_state & (RQ_EXP_RECEIVE_ACK | RQ_EXP_WRITE_ACK)) || dgs)
- err = _drbd_send_bio(mdev, req->master_bio);
+ err = _drbd_send_bio(peer_device, req->master_bio);
else
- err = _drbd_send_zc_bio(mdev, req->master_bio);
+ err = _drbd_send_zc_bio(peer_device, req->master_bio);
/* double check digest, sometimes buffers have been modified in flight. */
if (dgs > 0 && dgs <= 64) {
/* 64 byte, 512 bit, is the largest digest size
* currently supported in kernel crypto. */
unsigned char digest[64];
- drbd_csum_bio(mdev, mdev->tconn->integrity_tfm, req->master_bio, digest);
+ drbd_csum_bio(peer_device->connection->integrity_tfm, req->master_bio, digest);
if (memcmp(p + 1, digest, dgs)) {
- dev_warn(DEV,
+ drbd_warn(device,
"Digest mismatch, buffer modified by upper layers during write: %llus +%u\n",
(unsigned long long)req->i.sector, req->i.size);
}
@@ -1678,18 +1684,20 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req)
* Peer -> (diskless) R_PRIMARY (P_DATA_REPLY)
* C_SYNC_SOURCE -> C_SYNC_TARGET (P_RS_DATA_REPLY)
*/
-int drbd_send_block(struct drbd_conf *mdev, enum drbd_packet cmd,
+int drbd_send_block(struct drbd_peer_device *peer_device, enum drbd_packet cmd,
struct drbd_peer_request *peer_req)
{
+ struct drbd_device *device = peer_device->device;
struct drbd_socket *sock;
struct p_data *p;
int err;
int dgs;
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
- dgs = mdev->tconn->integrity_tfm ? crypto_hash_digestsize(mdev->tconn->integrity_tfm) : 0;
+ dgs = peer_device->connection->integrity_tfm ?
+ crypto_hash_digestsize(peer_device->connection->integrity_tfm) : 0;
if (!p)
return -EIO;
@@ -1698,27 +1706,27 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packet cmd,
p->seq_num = 0; /* unused */
p->dp_flags = 0;
if (dgs)
- drbd_csum_ee(mdev, mdev->tconn->integrity_tfm, peer_req, p + 1);
- err = __send_command(mdev->tconn, mdev->vnr, sock, cmd, sizeof(*p) + dgs, NULL, peer_req->i.size);
+ drbd_csum_ee(peer_device->connection->integrity_tfm, peer_req, p + 1);
+ err = __send_command(peer_device->connection, device->vnr, sock, cmd, sizeof(*p) + dgs, NULL, peer_req->i.size);
if (!err)
- err = _drbd_send_zc_ee(mdev, peer_req);
+ err = _drbd_send_zc_ee(peer_device, peer_req);
mutex_unlock(&sock->mutex); /* locked by drbd_prepare_command() */
return err;
}
-int drbd_send_out_of_sync(struct drbd_conf *mdev, struct drbd_request *req)
+int drbd_send_out_of_sync(struct drbd_peer_device *peer_device, struct drbd_request *req)
{
struct drbd_socket *sock;
struct p_block_desc *p;
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (!p)
return -EIO;
p->sector = cpu_to_be64(req->i.sector);
p->blksize = cpu_to_be32(req->i.size);
- return drbd_send_command(mdev, sock, P_OUT_OF_SYNC, sizeof(*p), NULL, 0);
+ return drbd_send_command(peer_device, sock, P_OUT_OF_SYNC, sizeof(*p), NULL, 0);
}
/*
@@ -1737,7 +1745,7 @@ int drbd_send_out_of_sync(struct drbd_conf *mdev, struct drbd_request *req)
/*
* you must have down()ed the appropriate [m]sock_mutex elsewhere!
*/
-int drbd_send(struct drbd_tconn *tconn, struct socket *sock,
+int drbd_send(struct drbd_connection *connection, struct socket *sock,
void *buf, size_t size, unsigned msg_flags)
{
struct kvec iov;
@@ -1758,11 +1766,11 @@ int drbd_send(struct drbd_tconn *tconn, struct socket *sock,
msg.msg_controllen = 0;
msg.msg_flags = msg_flags | MSG_NOSIGNAL;
- if (sock == tconn->data.socket) {
+ if (sock == connection->data.socket) {
rcu_read_lock();
- tconn->ko_count = rcu_dereference(tconn->net_conf)->ko_count;
+ connection->ko_count = rcu_dereference(connection->net_conf)->ko_count;
rcu_read_unlock();
- drbd_update_congested(tconn);
+ drbd_update_congested(connection);
}
do {
/* STRANGE
@@ -1776,7 +1784,7 @@ int drbd_send(struct drbd_tconn *tconn, struct socket *sock,
*/
rv = kernel_sendmsg(sock, &msg, &iov, 1, size);
if (rv == -EAGAIN) {
- if (we_should_drop_the_connection(tconn, sock))
+ if (we_should_drop_the_connection(connection, sock))
break;
else
continue;
@@ -1792,17 +1800,17 @@ int drbd_send(struct drbd_tconn *tconn, struct socket *sock,
iov.iov_len -= rv;
} while (sent < size);
- if (sock == tconn->data.socket)
- clear_bit(NET_CONGESTED, &tconn->flags);
+ if (sock == connection->data.socket)
+ clear_bit(NET_CONGESTED, &connection->flags);
if (rv <= 0) {
if (rv != -EAGAIN) {
- conn_err(tconn, "%s_sendmsg returned %d\n",
- sock == tconn->meta.socket ? "msock" : "sock",
+ drbd_err(connection, "%s_sendmsg returned %d\n",
+ sock == connection->meta.socket ? "msock" : "sock",
rv);
- conn_request_state(tconn, NS(conn, C_BROKEN_PIPE), CS_HARD);
+ conn_request_state(connection, NS(conn, C_BROKEN_PIPE), CS_HARD);
} else
- conn_request_state(tconn, NS(conn, C_TIMEOUT), CS_HARD);
+ conn_request_state(connection, NS(conn, C_TIMEOUT), CS_HARD);
}
return sent;
@@ -1813,12 +1821,12 @@ int drbd_send(struct drbd_tconn *tconn, struct socket *sock,
*
* Returns 0 upon success and a negative error value otherwise.
*/
-int drbd_send_all(struct drbd_tconn *tconn, struct socket *sock, void *buffer,
+int drbd_send_all(struct drbd_connection *connection, struct socket *sock, void *buffer,
size_t size, unsigned msg_flags)
{
int err;
- err = drbd_send(tconn, sock, buffer, size, msg_flags);
+ err = drbd_send(connection, sock, buffer, size, msg_flags);
if (err < 0)
return err;
if (err != size)
@@ -1828,16 +1836,16 @@ int drbd_send_all(struct drbd_tconn *tconn, struct socket *sock, void *buffer,
static int drbd_open(struct block_device *bdev, fmode_t mode)
{
- struct drbd_conf *mdev = bdev->bd_disk->private_data;
+ struct drbd_device *device = bdev->bd_disk->private_data;
unsigned long flags;
int rv = 0;
mutex_lock(&drbd_main_mutex);
- spin_lock_irqsave(&mdev->tconn->req_lock, flags);
- /* to have a stable mdev->state.role
+ spin_lock_irqsave(&device->resource->req_lock, flags);
+ /* to have a stable device->state.role
* and no race with updating open_cnt */
- if (mdev->state.role != R_PRIMARY) {
+ if (device->state.role != R_PRIMARY) {
if (mode & FMODE_WRITE)
rv = -EROFS;
else if (!allow_oos)
@@ -1845,8 +1853,8 @@ static int drbd_open(struct block_device *bdev, fmode_t mode)
}
if (!rv)
- mdev->open_cnt++;
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
+ device->open_cnt++;
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
mutex_unlock(&drbd_main_mutex);
return rv;
@@ -1854,17 +1862,17 @@ static int drbd_open(struct block_device *bdev, fmode_t mode)
static void drbd_release(struct gendisk *gd, fmode_t mode)
{
- struct drbd_conf *mdev = gd->private_data;
+ struct drbd_device *device = gd->private_data;
mutex_lock(&drbd_main_mutex);
- mdev->open_cnt--;
+ device->open_cnt--;
mutex_unlock(&drbd_main_mutex);
}
-static void drbd_set_defaults(struct drbd_conf *mdev)
+static void drbd_set_defaults(struct drbd_device *device)
{
/* Beware! The actual layout differs
* between big endian and little endian */
- mdev->state = (union drbd_dev_state) {
+ device->state = (union drbd_dev_state) {
{ .role = R_SECONDARY,
.peer = R_UNKNOWN,
.conn = C_STANDALONE,
@@ -1873,130 +1881,123 @@ static void drbd_set_defaults(struct drbd_conf *mdev)
} };
}
-void drbd_init_set_defaults(struct drbd_conf *mdev)
+void drbd_init_set_defaults(struct drbd_device *device)
{
/* the memset(,0,) did most of this.
* note: only assignments, no allocation in here */
- drbd_set_defaults(mdev);
-
- atomic_set(&mdev->ap_bio_cnt, 0);
- atomic_set(&mdev->ap_pending_cnt, 0);
- atomic_set(&mdev->rs_pending_cnt, 0);
- atomic_set(&mdev->unacked_cnt, 0);
- atomic_set(&mdev->local_cnt, 0);
- atomic_set(&mdev->pp_in_use_by_net, 0);
- atomic_set(&mdev->rs_sect_in, 0);
- atomic_set(&mdev->rs_sect_ev, 0);
- atomic_set(&mdev->ap_in_flight, 0);
- atomic_set(&mdev->md_io_in_use, 0);
-
- mutex_init(&mdev->own_state_mutex);
- mdev->state_mutex = &mdev->own_state_mutex;
-
- spin_lock_init(&mdev->al_lock);
- spin_lock_init(&mdev->peer_seq_lock);
-
- INIT_LIST_HEAD(&mdev->active_ee);
- INIT_LIST_HEAD(&mdev->sync_ee);
- INIT_LIST_HEAD(&mdev->done_ee);
- INIT_LIST_HEAD(&mdev->read_ee);
- INIT_LIST_HEAD(&mdev->net_ee);
- INIT_LIST_HEAD(&mdev->resync_reads);
- INIT_LIST_HEAD(&mdev->resync_work.list);
- INIT_LIST_HEAD(&mdev->unplug_work.list);
- INIT_LIST_HEAD(&mdev->go_diskless.list);
- INIT_LIST_HEAD(&mdev->md_sync_work.list);
- INIT_LIST_HEAD(&mdev->start_resync_work.list);
- INIT_LIST_HEAD(&mdev->bm_io_work.w.list);
-
- mdev->resync_work.cb = w_resync_timer;
- mdev->unplug_work.cb = w_send_write_hint;
- mdev->go_diskless.cb = w_go_diskless;
- mdev->md_sync_work.cb = w_md_sync;
- mdev->bm_io_work.w.cb = w_bitmap_io;
- mdev->start_resync_work.cb = w_start_resync;
-
- mdev->resync_work.mdev = mdev;
- mdev->unplug_work.mdev = mdev;
- mdev->go_diskless.mdev = mdev;
- mdev->md_sync_work.mdev = mdev;
- mdev->bm_io_work.w.mdev = mdev;
- mdev->start_resync_work.mdev = mdev;
-
- init_timer(&mdev->resync_timer);
- init_timer(&mdev->md_sync_timer);
- init_timer(&mdev->start_resync_timer);
- init_timer(&mdev->request_timer);
- mdev->resync_timer.function = resync_timer_fn;
- mdev->resync_timer.data = (unsigned long) mdev;
- mdev->md_sync_timer.function = md_sync_timer_fn;
- mdev->md_sync_timer.data = (unsigned long) mdev;
- mdev->start_resync_timer.function = start_resync_timer_fn;
- mdev->start_resync_timer.data = (unsigned long) mdev;
- mdev->request_timer.function = request_timer_fn;
- mdev->request_timer.data = (unsigned long) mdev;
-
- init_waitqueue_head(&mdev->misc_wait);
- init_waitqueue_head(&mdev->state_wait);
- init_waitqueue_head(&mdev->ee_wait);
- init_waitqueue_head(&mdev->al_wait);
- init_waitqueue_head(&mdev->seq_wait);
-
- mdev->resync_wenr = LC_FREE;
- mdev->peer_max_bio_size = DRBD_MAX_BIO_SIZE_SAFE;
- mdev->local_max_bio_size = DRBD_MAX_BIO_SIZE_SAFE;
-}
-
-void drbd_mdev_cleanup(struct drbd_conf *mdev)
+ drbd_set_defaults(device);
+
+ atomic_set(&device->ap_bio_cnt, 0);
+ atomic_set(&device->ap_pending_cnt, 0);
+ atomic_set(&device->rs_pending_cnt, 0);
+ atomic_set(&device->unacked_cnt, 0);
+ atomic_set(&device->local_cnt, 0);
+ atomic_set(&device->pp_in_use_by_net, 0);
+ atomic_set(&device->rs_sect_in, 0);
+ atomic_set(&device->rs_sect_ev, 0);
+ atomic_set(&device->ap_in_flight, 0);
+ atomic_set(&device->md_io_in_use, 0);
+
+ mutex_init(&device->own_state_mutex);
+ device->state_mutex = &device->own_state_mutex;
+
+ spin_lock_init(&device->al_lock);
+ spin_lock_init(&device->peer_seq_lock);
+
+ INIT_LIST_HEAD(&device->active_ee);
+ INIT_LIST_HEAD(&device->sync_ee);
+ INIT_LIST_HEAD(&device->done_ee);
+ INIT_LIST_HEAD(&device->read_ee);
+ INIT_LIST_HEAD(&device->net_ee);
+ INIT_LIST_HEAD(&device->resync_reads);
+ INIT_LIST_HEAD(&device->resync_work.list);
+ INIT_LIST_HEAD(&device->unplug_work.list);
+ INIT_LIST_HEAD(&device->go_diskless.list);
+ INIT_LIST_HEAD(&device->md_sync_work.list);
+ INIT_LIST_HEAD(&device->start_resync_work.list);
+ INIT_LIST_HEAD(&device->bm_io_work.w.list);
+
+ device->resync_work.cb = w_resync_timer;
+ device->unplug_work.cb = w_send_write_hint;
+ device->go_diskless.cb = w_go_diskless;
+ device->md_sync_work.cb = w_md_sync;
+ device->bm_io_work.w.cb = w_bitmap_io;
+ device->start_resync_work.cb = w_start_resync;
+
+ init_timer(&device->resync_timer);
+ init_timer(&device->md_sync_timer);
+ init_timer(&device->start_resync_timer);
+ init_timer(&device->request_timer);
+ device->resync_timer.function = resync_timer_fn;
+ device->resync_timer.data = (unsigned long) device;
+ device->md_sync_timer.function = md_sync_timer_fn;
+ device->md_sync_timer.data = (unsigned long) device;
+ device->start_resync_timer.function = start_resync_timer_fn;
+ device->start_resync_timer.data = (unsigned long) device;
+ device->request_timer.function = request_timer_fn;
+ device->request_timer.data = (unsigned long) device;
+
+ init_waitqueue_head(&device->misc_wait);
+ init_waitqueue_head(&device->state_wait);
+ init_waitqueue_head(&device->ee_wait);
+ init_waitqueue_head(&device->al_wait);
+ init_waitqueue_head(&device->seq_wait);
+
+ device->resync_wenr = LC_FREE;
+ device->peer_max_bio_size = DRBD_MAX_BIO_SIZE_SAFE;
+ device->local_max_bio_size = DRBD_MAX_BIO_SIZE_SAFE;
+}
+
+void drbd_device_cleanup(struct drbd_device *device)
{
int i;
- if (mdev->tconn->receiver.t_state != NONE)
- dev_err(DEV, "ASSERT FAILED: receiver t_state == %d expected 0.\n",
- mdev->tconn->receiver.t_state);
-
- mdev->al_writ_cnt =
- mdev->bm_writ_cnt =
- mdev->read_cnt =
- mdev->recv_cnt =
- mdev->send_cnt =
- mdev->writ_cnt =
- mdev->p_size =
- mdev->rs_start =
- mdev->rs_total =
- mdev->rs_failed = 0;
- mdev->rs_last_events = 0;
- mdev->rs_last_sect_ev = 0;
+ if (first_peer_device(device)->connection->receiver.t_state != NONE)
+ drbd_err(device, "ASSERT FAILED: receiver t_state == %d expected 0.\n",
+ first_peer_device(device)->connection->receiver.t_state);
+
+ device->al_writ_cnt =
+ device->bm_writ_cnt =
+ device->read_cnt =
+ device->recv_cnt =
+ device->send_cnt =
+ device->writ_cnt =
+ device->p_size =
+ device->rs_start =
+ device->rs_total =
+ device->rs_failed = 0;
+ device->rs_last_events = 0;
+ device->rs_last_sect_ev = 0;
for (i = 0; i < DRBD_SYNC_MARKS; i++) {
- mdev->rs_mark_left[i] = 0;
- mdev->rs_mark_time[i] = 0;
+ device->rs_mark_left[i] = 0;
+ device->rs_mark_time[i] = 0;
}
- D_ASSERT(mdev->tconn->net_conf == NULL);
+ D_ASSERT(device, first_peer_device(device)->connection->net_conf == NULL);
- drbd_set_my_capacity(mdev, 0);
- if (mdev->bitmap) {
+ drbd_set_my_capacity(device, 0);
+ if (device->bitmap) {
/* maybe never allocated. */
- drbd_bm_resize(mdev, 0, 1);
- drbd_bm_cleanup(mdev);
+ drbd_bm_resize(device, 0, 1);
+ drbd_bm_cleanup(device);
}
- drbd_free_bc(mdev->ldev);
- mdev->ldev = NULL;
+ drbd_free_bc(device->ldev);
+ device->ldev = NULL;
- clear_bit(AL_SUSPENDED, &mdev->flags);
+ clear_bit(AL_SUSPENDED, &device->flags);
- D_ASSERT(list_empty(&mdev->active_ee));
- D_ASSERT(list_empty(&mdev->sync_ee));
- D_ASSERT(list_empty(&mdev->done_ee));
- D_ASSERT(list_empty(&mdev->read_ee));
- D_ASSERT(list_empty(&mdev->net_ee));
- D_ASSERT(list_empty(&mdev->resync_reads));
- D_ASSERT(list_empty(&mdev->tconn->sender_work.q));
- D_ASSERT(list_empty(&mdev->resync_work.list));
- D_ASSERT(list_empty(&mdev->unplug_work.list));
- D_ASSERT(list_empty(&mdev->go_diskless.list));
+ D_ASSERT(device, list_empty(&device->active_ee));
+ D_ASSERT(device, list_empty(&device->sync_ee));
+ D_ASSERT(device, list_empty(&device->done_ee));
+ D_ASSERT(device, list_empty(&device->read_ee));
+ D_ASSERT(device, list_empty(&device->net_ee));
+ D_ASSERT(device, list_empty(&device->resync_reads));
+ D_ASSERT(device, list_empty(&first_peer_device(device)->connection->sender_work.q));
+ D_ASSERT(device, list_empty(&device->resync_work.list));
+ D_ASSERT(device, list_empty(&device->unplug_work.list));
+ D_ASSERT(device, list_empty(&device->go_diskless.list));
- drbd_set_defaults(mdev);
+ drbd_set_defaults(device);
}
@@ -2011,7 +2012,7 @@ static void drbd_destroy_mempools(void)
drbd_pp_vacant--;
}
- /* D_ASSERT(atomic_read(&drbd_pp_vacant)==0); */
+ /* D_ASSERT(device, atomic_read(&drbd_pp_vacant)==0); */
if (drbd_md_io_bio_set)
bioset_free(drbd_md_io_bio_set);
@@ -2131,69 +2132,73 @@ static struct notifier_block drbd_notifier = {
.notifier_call = drbd_notify_sys,
};
-static void drbd_release_all_peer_reqs(struct drbd_conf *mdev)
+static void drbd_release_all_peer_reqs(struct drbd_device *device)
{
int rr;
- rr = drbd_free_peer_reqs(mdev, &mdev->active_ee);
+ rr = drbd_free_peer_reqs(device, &device->active_ee);
if (rr)
- dev_err(DEV, "%d EEs in active list found!\n", rr);
+ drbd_err(device, "%d EEs in active list found!\n", rr);
- rr = drbd_free_peer_reqs(mdev, &mdev->sync_ee);
+ rr = drbd_free_peer_reqs(device, &device->sync_ee);
if (rr)
- dev_err(DEV, "%d EEs in sync list found!\n", rr);
+ drbd_err(device, "%d EEs in sync list found!\n", rr);
- rr = drbd_free_peer_reqs(mdev, &mdev->read_ee);
+ rr = drbd_free_peer_reqs(device, &device->read_ee);
if (rr)
- dev_err(DEV, "%d EEs in read list found!\n", rr);
+ drbd_err(device, "%d EEs in read list found!\n", rr);
- rr = drbd_free_peer_reqs(mdev, &mdev->done_ee);
+ rr = drbd_free_peer_reqs(device, &device->done_ee);
if (rr)
- dev_err(DEV, "%d EEs in done list found!\n", rr);
+ drbd_err(device, "%d EEs in done list found!\n", rr);
- rr = drbd_free_peer_reqs(mdev, &mdev->net_ee);
+ rr = drbd_free_peer_reqs(device, &device->net_ee);
if (rr)
- dev_err(DEV, "%d EEs in net list found!\n", rr);
+ drbd_err(device, "%d EEs in net list found!\n", rr);
}
/* caution. no locking. */
-void drbd_minor_destroy(struct kref *kref)
+void drbd_destroy_device(struct kref *kref)
{
- struct drbd_conf *mdev = container_of(kref, struct drbd_conf, kref);
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_device *device = container_of(kref, struct drbd_device, kref);
+ struct drbd_resource *resource = device->resource;
+ struct drbd_connection *connection;
- del_timer_sync(&mdev->request_timer);
+ del_timer_sync(&device->request_timer);
/* paranoia asserts */
- D_ASSERT(mdev->open_cnt == 0);
+ D_ASSERT(device, device->open_cnt == 0);
/* end paranoia asserts */
/* cleanup stuff that may have been allocated during
* device (re-)configuration or state changes */
- if (mdev->this_bdev)
- bdput(mdev->this_bdev);
+ if (device->this_bdev)
+ bdput(device->this_bdev);
- drbd_free_bc(mdev->ldev);
- mdev->ldev = NULL;
+ drbd_free_bc(device->ldev);
+ device->ldev = NULL;
- drbd_release_all_peer_reqs(mdev);
+ drbd_release_all_peer_reqs(device);
- lc_destroy(mdev->act_log);
- lc_destroy(mdev->resync);
+ lc_destroy(device->act_log);
+ lc_destroy(device->resync);
- kfree(mdev->p_uuid);
- /* mdev->p_uuid = NULL; */
+ kfree(device->p_uuid);
+ /* device->p_uuid = NULL; */
- if (mdev->bitmap) /* should no longer be there. */
- drbd_bm_cleanup(mdev);
- __free_page(mdev->md_io_page);
- put_disk(mdev->vdisk);
- blk_cleanup_queue(mdev->rq_queue);
- kfree(mdev->rs_plan_s);
- kfree(mdev);
+ if (device->bitmap) /* should no longer be there. */
+ drbd_bm_cleanup(device);
+ __free_page(device->md_io_page);
+ put_disk(device->vdisk);
+ blk_cleanup_queue(device->rq_queue);
+ kfree(device->rs_plan_s);
+ kfree(first_peer_device(device));
+ kfree(device);
- kref_put(&tconn->kref, &conn_destroy);
+ for_each_connection(connection, resource)
+ kref_put(&connection->kref, drbd_destroy_connection);
+ kref_put(&resource->kref, drbd_destroy_resource);
}
/* One global retry thread, if we need to push back some bio and have it
@@ -2218,19 +2223,19 @@ static void do_retry(struct work_struct *ws)
spin_unlock_irq(&retry->lock);
list_for_each_entry_safe(req, tmp, &writes, tl_requests) {
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
struct bio *bio = req->master_bio;
unsigned long start_time = req->start_time;
bool expected;
- expected =
+ expected =
expect(atomic_read(&req->completion_ref) == 0) &&
expect(req->rq_state & RQ_POSTPONED) &&
expect((req->rq_state & RQ_LOCAL_PENDING) == 0 ||
(req->rq_state & RQ_LOCAL_ABORTED) != 0);
if (!expected)
- dev_err(DEV, "req=%p completion_ref=%d rq_state=%x\n",
+ drbd_err(device, "req=%p completion_ref=%d rq_state=%x\n",
req, atomic_read(&req->completion_ref),
req->rq_state);
@@ -2254,8 +2259,8 @@ static void do_retry(struct work_struct *ws)
/* We are not just doing generic_make_request(),
* as we want to keep the start_time information. */
- inc_ap_bio(mdev);
- __drbd_make_request(mdev, bio, start_time);
+ inc_ap_bio(device);
+ __drbd_make_request(device, bio, start_time);
}
}
@@ -2269,17 +2274,38 @@ void drbd_restart_request(struct drbd_request *req)
/* Drop the extra reference that would otherwise
* have been dropped by complete_master_bio.
* do_retry() needs to grab a new one. */
- dec_ap_bio(req->w.mdev);
+ dec_ap_bio(req->device);
queue_work(retry.wq, &retry.worker);
}
+void drbd_destroy_resource(struct kref *kref)
+{
+ struct drbd_resource *resource =
+ container_of(kref, struct drbd_resource, kref);
+
+ idr_destroy(&resource->devices);
+ free_cpumask_var(resource->cpu_mask);
+ kfree(resource->name);
+ kfree(resource);
+}
+
+void drbd_free_resource(struct drbd_resource *resource)
+{
+ struct drbd_connection *connection, *tmp;
+
+ for_each_connection_safe(connection, tmp, resource) {
+ list_del(&connection->connections);
+ kref_put(&connection->kref, drbd_destroy_connection);
+ }
+ kref_put(&resource->kref, drbd_destroy_resource);
+}
static void drbd_cleanup(void)
{
unsigned int i;
- struct drbd_conf *mdev;
- struct drbd_tconn *tconn, *tmp;
+ struct drbd_device *device;
+ struct drbd_resource *resource, *tmp;
unregister_reboot_notifier(&drbd_notifier);
@@ -2299,26 +2325,19 @@ static void drbd_cleanup(void)
drbd_genl_unregister();
- idr_for_each_entry(&minors, mdev, i) {
- idr_remove(&minors, mdev_to_minor(mdev));
- idr_remove(&mdev->tconn->volumes, mdev->vnr);
- destroy_workqueue(mdev->submit.wq);
- del_gendisk(mdev->vdisk);
- /* synchronize_rcu(); No other threads running at this point */
- kref_put(&mdev->kref, &drbd_minor_destroy);
- }
+ idr_for_each_entry(&drbd_devices, device, i)
+ drbd_delete_device(device);
/* not _rcu since, no other updater anymore. Genl already unregistered */
- list_for_each_entry_safe(tconn, tmp, &drbd_tconns, all_tconn) {
- list_del(&tconn->all_tconn); /* not _rcu no proc, not other threads */
- /* synchronize_rcu(); */
- kref_put(&tconn->kref, &conn_destroy);
+ for_each_resource_safe(resource, tmp, &drbd_resources) {
+ list_del(&resource->resources);
+ drbd_free_resource(resource);
}
drbd_destroy_mempools();
unregister_blkdev(DRBD_MAJOR, "drbd");
- idr_destroy(&minors);
+ idr_destroy(&drbd_devices);
printk(KERN_INFO "drbd: module cleanup done.\n");
}
@@ -2332,49 +2351,50 @@ static void drbd_cleanup(void)
*/
static int drbd_congested(void *congested_data, int bdi_bits)
{
- struct drbd_conf *mdev = congested_data;
+ struct drbd_device *device = congested_data;
struct request_queue *q;
char reason = '-';
int r = 0;
- if (!may_inc_ap_bio(mdev)) {
+ if (!may_inc_ap_bio(device)) {
/* DRBD has frozen IO */
r = bdi_bits;
reason = 'd';
goto out;
}
- if (test_bit(CALLBACK_PENDING, &mdev->tconn->flags)) {
+ if (test_bit(CALLBACK_PENDING, &first_peer_device(device)->connection->flags)) {
r |= (1 << BDI_async_congested);
/* Without good local data, we would need to read from remote,
* and that would need the worker thread as well, which is
* currently blocked waiting for that usermode helper to
* finish.
*/
- if (!get_ldev_if_state(mdev, D_UP_TO_DATE))
+ if (!get_ldev_if_state(device, D_UP_TO_DATE))
r |= (1 << BDI_sync_congested);
else
- put_ldev(mdev);
+ put_ldev(device);
r &= bdi_bits;
reason = 'c';
goto out;
}
- if (get_ldev(mdev)) {
- q = bdev_get_queue(mdev->ldev->backing_bdev);
+ if (get_ldev(device)) {
+ q = bdev_get_queue(device->ldev->backing_bdev);
r = bdi_congested(&q->backing_dev_info, bdi_bits);
- put_ldev(mdev);
+ put_ldev(device);
if (r)
reason = 'b';
}
- if (bdi_bits & (1 << BDI_async_congested) && test_bit(NET_CONGESTED, &mdev->tconn->flags)) {
+ if (bdi_bits & (1 << BDI_async_congested) &&
+ test_bit(NET_CONGESTED, &first_peer_device(device)->connection->flags)) {
r |= (1 << BDI_async_congested);
reason = reason == 'b' ? 'a' : 'n';
}
out:
- mdev->congestion_reason = reason;
+ device->congestion_reason = reason;
return r;
}
@@ -2385,45 +2405,72 @@ static void drbd_init_workqueue(struct drbd_work_queue* wq)
init_waitqueue_head(&wq->q_wait);
}
-struct drbd_tconn *conn_get_by_name(const char *name)
+struct completion_work {
+ struct drbd_work w;
+ struct completion done;
+};
+
+static int w_complete(struct drbd_work *w, int cancel)
+{
+ struct completion_work *completion_work =
+ container_of(w, struct completion_work, w);
+
+ complete(&completion_work->done);
+ return 0;
+}
+
+void drbd_flush_workqueue(struct drbd_work_queue *work_queue)
+{
+ struct completion_work completion_work;
+
+ completion_work.w.cb = w_complete;
+ init_completion(&completion_work.done);
+ drbd_queue_work(work_queue, &completion_work.w);
+ wait_for_completion(&completion_work.done);
+}
+
+struct drbd_resource *drbd_find_resource(const char *name)
{
- struct drbd_tconn *tconn;
+ struct drbd_resource *resource;
if (!name || !name[0])
return NULL;
rcu_read_lock();
- list_for_each_entry_rcu(tconn, &drbd_tconns, all_tconn) {
- if (!strcmp(tconn->name, name)) {
- kref_get(&tconn->kref);
+ for_each_resource_rcu(resource, &drbd_resources) {
+ if (!strcmp(resource->name, name)) {
+ kref_get(&resource->kref);
goto found;
}
}
- tconn = NULL;
+ resource = NULL;
found:
rcu_read_unlock();
- return tconn;
+ return resource;
}
-struct drbd_tconn *conn_get_by_addrs(void *my_addr, int my_addr_len,
+struct drbd_connection *conn_get_by_addrs(void *my_addr, int my_addr_len,
void *peer_addr, int peer_addr_len)
{
- struct drbd_tconn *tconn;
+ struct drbd_resource *resource;
+ struct drbd_connection *connection;
rcu_read_lock();
- list_for_each_entry_rcu(tconn, &drbd_tconns, all_tconn) {
- if (tconn->my_addr_len == my_addr_len &&
- tconn->peer_addr_len == peer_addr_len &&
- !memcmp(&tconn->my_addr, my_addr, my_addr_len) &&
- !memcmp(&tconn->peer_addr, peer_addr, peer_addr_len)) {
- kref_get(&tconn->kref);
- goto found;
+ for_each_resource_rcu(resource, &drbd_resources) {
+ for_each_connection_rcu(connection, resource) {
+ if (connection->my_addr_len == my_addr_len &&
+ connection->peer_addr_len == peer_addr_len &&
+ !memcmp(&connection->my_addr, my_addr, my_addr_len) &&
+ !memcmp(&connection->peer_addr, peer_addr, peer_addr_len)) {
+ kref_get(&connection->kref);
+ goto found;
+ }
}
}
- tconn = NULL;
+ connection = NULL;
found:
rcu_read_unlock();
- return tconn;
+ return connection;
}
static int drbd_alloc_socket(struct drbd_socket *socket)
@@ -2443,29 +2490,30 @@ static void drbd_free_socket(struct drbd_socket *socket)
free_page((unsigned long) socket->rbuf);
}
-void conn_free_crypto(struct drbd_tconn *tconn)
+void conn_free_crypto(struct drbd_connection *connection)
{
- drbd_free_sock(tconn);
+ drbd_free_sock(connection);
- crypto_free_hash(tconn->csums_tfm);
- crypto_free_hash(tconn->verify_tfm);
- crypto_free_hash(tconn->cram_hmac_tfm);
- crypto_free_hash(tconn->integrity_tfm);
- crypto_free_hash(tconn->peer_integrity_tfm);
- kfree(tconn->int_dig_in);
- kfree(tconn->int_dig_vv);
+ crypto_free_hash(connection->csums_tfm);
+ crypto_free_hash(connection->verify_tfm);
+ crypto_free_hash(connection->cram_hmac_tfm);
+ crypto_free_hash(connection->integrity_tfm);
+ crypto_free_hash(connection->peer_integrity_tfm);
+ kfree(connection->int_dig_in);
+ kfree(connection->int_dig_vv);
- tconn->csums_tfm = NULL;
- tconn->verify_tfm = NULL;
- tconn->cram_hmac_tfm = NULL;
- tconn->integrity_tfm = NULL;
- tconn->peer_integrity_tfm = NULL;
- tconn->int_dig_in = NULL;
- tconn->int_dig_vv = NULL;
+ connection->csums_tfm = NULL;
+ connection->verify_tfm = NULL;
+ connection->cram_hmac_tfm = NULL;
+ connection->integrity_tfm = NULL;
+ connection->peer_integrity_tfm = NULL;
+ connection->int_dig_in = NULL;
+ connection->int_dig_vv = NULL;
}
-int set_resource_options(struct drbd_tconn *tconn, struct res_opts *res_opts)
+int set_resource_options(struct drbd_resource *resource, struct res_opts *res_opts)
{
+ struct drbd_connection *connection;
cpumask_var_t new_cpu_mask;
int err;
@@ -2478,22 +2526,24 @@ int set_resource_options(struct drbd_tconn *tconn, struct res_opts *res_opts)
/* silently ignore cpu mask on UP kernel */
if (nr_cpu_ids > 1 && res_opts->cpu_mask[0] != 0) {
- /* FIXME: Get rid of constant 32 here */
- err = bitmap_parse(res_opts->cpu_mask, 32,
+ err = bitmap_parse(res_opts->cpu_mask, DRBD_CPU_MASK_SIZE,
cpumask_bits(new_cpu_mask), nr_cpu_ids);
if (err) {
- conn_warn(tconn, "bitmap_parse() failed with %d\n", err);
+ drbd_warn(resource, "bitmap_parse() failed with %d\n", err);
/* retcode = ERR_CPU_MASK_PARSE; */
goto fail;
}
}
- tconn->res_opts = *res_opts;
- if (!cpumask_equal(tconn->cpu_mask, new_cpu_mask)) {
- cpumask_copy(tconn->cpu_mask, new_cpu_mask);
- drbd_calc_cpu_mask(tconn);
- tconn->receiver.reset_cpu_mask = 1;
- tconn->asender.reset_cpu_mask = 1;
- tconn->worker.reset_cpu_mask = 1;
+ resource->res_opts = *res_opts;
+ if (cpumask_empty(new_cpu_mask))
+ drbd_calc_cpu_mask(&new_cpu_mask);
+ if (!cpumask_equal(resource->cpu_mask, new_cpu_mask)) {
+ cpumask_copy(resource->cpu_mask, new_cpu_mask);
+ for_each_connection_rcu(connection, resource) {
+ connection->receiver.reset_cpu_mask = 1;
+ connection->asender.reset_cpu_mask = 1;
+ connection->worker.reset_cpu_mask = 1;
+ }
}
err = 0;
@@ -2503,146 +2553,177 @@ fail:
}
+struct drbd_resource *drbd_create_resource(const char *name)
+{
+ struct drbd_resource *resource;
+
+ resource = kzalloc(sizeof(struct drbd_resource), GFP_KERNEL);
+ if (!resource)
+ goto fail;
+ resource->name = kstrdup(name, GFP_KERNEL);
+ if (!resource->name)
+ goto fail_free_resource;
+ if (!zalloc_cpumask_var(&resource->cpu_mask, GFP_KERNEL))
+ goto fail_free_name;
+ kref_init(&resource->kref);
+ idr_init(&resource->devices);
+ INIT_LIST_HEAD(&resource->connections);
+ list_add_tail_rcu(&resource->resources, &drbd_resources);
+ mutex_init(&resource->conf_update);
+ spin_lock_init(&resource->req_lock);
+ return resource;
+
+fail_free_name:
+ kfree(resource->name);
+fail_free_resource:
+ kfree(resource);
+fail:
+ return NULL;
+}
+
/* caller must be under genl_lock() */
-struct drbd_tconn *conn_create(const char *name, struct res_opts *res_opts)
+struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts)
{
- struct drbd_tconn *tconn;
+ struct drbd_resource *resource;
+ struct drbd_connection *connection;
- tconn = kzalloc(sizeof(struct drbd_tconn), GFP_KERNEL);
- if (!tconn)
+ connection = kzalloc(sizeof(struct drbd_connection), GFP_KERNEL);
+ if (!connection)
return NULL;
- tconn->name = kstrdup(name, GFP_KERNEL);
- if (!tconn->name)
+ if (drbd_alloc_socket(&connection->data))
goto fail;
-
- if (drbd_alloc_socket(&tconn->data))
- goto fail;
- if (drbd_alloc_socket(&tconn->meta))
+ if (drbd_alloc_socket(&connection->meta))
goto fail;
- if (!zalloc_cpumask_var(&tconn->cpu_mask, GFP_KERNEL))
+ connection->current_epoch = kzalloc(sizeof(struct drbd_epoch), GFP_KERNEL);
+ if (!connection->current_epoch)
goto fail;
- if (set_resource_options(tconn, res_opts))
- goto fail;
+ INIT_LIST_HEAD(&connection->transfer_log);
- tconn->current_epoch = kzalloc(sizeof(struct drbd_epoch), GFP_KERNEL);
- if (!tconn->current_epoch)
- goto fail;
+ INIT_LIST_HEAD(&connection->current_epoch->list);
+ connection->epochs = 1;
+ spin_lock_init(&connection->epoch_lock);
+ connection->write_ordering = WO_bdev_flush;
- INIT_LIST_HEAD(&tconn->transfer_log);
+ connection->send.seen_any_write_yet = false;
+ connection->send.current_epoch_nr = 0;
+ connection->send.current_epoch_writes = 0;
- INIT_LIST_HEAD(&tconn->current_epoch->list);
- tconn->epochs = 1;
- spin_lock_init(&tconn->epoch_lock);
- tconn->write_ordering = WO_bdev_flush;
+ resource = drbd_create_resource(name);
+ if (!resource)
+ goto fail;
- tconn->send.seen_any_write_yet = false;
- tconn->send.current_epoch_nr = 0;
- tconn->send.current_epoch_writes = 0;
+ connection->cstate = C_STANDALONE;
+ mutex_init(&connection->cstate_mutex);
+ init_waitqueue_head(&connection->ping_wait);
+ idr_init(&connection->peer_devices);
- tconn->cstate = C_STANDALONE;
- mutex_init(&tconn->cstate_mutex);
- spin_lock_init(&tconn->req_lock);
- mutex_init(&tconn->conf_update);
- init_waitqueue_head(&tconn->ping_wait);
- idr_init(&tconn->volumes);
+ drbd_init_workqueue(&connection->sender_work);
+ mutex_init(&connection->data.mutex);
+ mutex_init(&connection->meta.mutex);
- drbd_init_workqueue(&tconn->sender_work);
- mutex_init(&tconn->data.mutex);
- mutex_init(&tconn->meta.mutex);
+ drbd_thread_init(resource, &connection->receiver, drbd_receiver, "receiver");
+ connection->receiver.connection = connection;
+ drbd_thread_init(resource, &connection->worker, drbd_worker, "worker");
+ connection->worker.connection = connection;
+ drbd_thread_init(resource, &connection->asender, drbd_asender, "asender");
+ connection->asender.connection = connection;
- drbd_thread_init(tconn, &tconn->receiver, drbdd_init, "receiver");
- drbd_thread_init(tconn, &tconn->worker, drbd_worker, "worker");
- drbd_thread_init(tconn, &tconn->asender, drbd_asender, "asender");
+ kref_init(&connection->kref);
- kref_init(&tconn->kref);
- list_add_tail_rcu(&tconn->all_tconn, &drbd_tconns);
+ connection->resource = resource;
- return tconn;
+ if (set_resource_options(resource, res_opts))
+ goto fail_resource;
-fail:
- kfree(tconn->current_epoch);
- free_cpumask_var(tconn->cpu_mask);
- drbd_free_socket(&tconn->meta);
- drbd_free_socket(&tconn->data);
- kfree(tconn->name);
- kfree(tconn);
+ kref_get(&resource->kref);
+ list_add_tail_rcu(&connection->connections, &resource->connections);
+ return connection;
+fail_resource:
+ list_del(&resource->resources);
+ drbd_free_resource(resource);
+fail:
+ kfree(connection->current_epoch);
+ drbd_free_socket(&connection->meta);
+ drbd_free_socket(&connection->data);
+ kfree(connection);
return NULL;
}
-void conn_destroy(struct kref *kref)
+void drbd_destroy_connection(struct kref *kref)
{
- struct drbd_tconn *tconn = container_of(kref, struct drbd_tconn, kref);
+ struct drbd_connection *connection = container_of(kref, struct drbd_connection, kref);
+ struct drbd_resource *resource = connection->resource;
- if (atomic_read(&tconn->current_epoch->epoch_size) != 0)
- conn_err(tconn, "epoch_size:%d\n", atomic_read(&tconn->current_epoch->epoch_size));
- kfree(tconn->current_epoch);
+ if (atomic_read(&connection->current_epoch->epoch_size) != 0)
+ drbd_err(connection, "epoch_size:%d\n", atomic_read(&connection->current_epoch->epoch_size));
+ kfree(connection->current_epoch);
- idr_destroy(&tconn->volumes);
+ idr_destroy(&connection->peer_devices);
- free_cpumask_var(tconn->cpu_mask);
- drbd_free_socket(&tconn->meta);
- drbd_free_socket(&tconn->data);
- kfree(tconn->name);
- kfree(tconn->int_dig_in);
- kfree(tconn->int_dig_vv);
- kfree(tconn);
+ drbd_free_socket(&connection->meta);
+ drbd_free_socket(&connection->data);
+ kfree(connection->int_dig_in);
+ kfree(connection->int_dig_vv);
+ kfree(connection);
+ kref_put(&resource->kref, drbd_destroy_resource);
}
-int init_submitter(struct drbd_conf *mdev)
+static int init_submitter(struct drbd_device *device)
{
/* opencoded create_singlethread_workqueue(),
* to be able to say "drbd%d", ..., minor */
- mdev->submit.wq = alloc_workqueue("drbd%u_submit",
- WQ_UNBOUND | WQ_MEM_RECLAIM, 1, mdev->minor);
- if (!mdev->submit.wq)
+ device->submit.wq = alloc_workqueue("drbd%u_submit",
+ WQ_UNBOUND | WQ_MEM_RECLAIM, 1, device->minor);
+ if (!device->submit.wq)
return -ENOMEM;
- INIT_WORK(&mdev->submit.worker, do_submit);
- spin_lock_init(&mdev->submit.lock);
- INIT_LIST_HEAD(&mdev->submit.writes);
+ INIT_WORK(&device->submit.worker, do_submit);
+ spin_lock_init(&device->submit.lock);
+ INIT_LIST_HEAD(&device->submit.writes);
return 0;
}
-enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor, int vnr)
+enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned int minor, int vnr)
{
- struct drbd_conf *mdev;
+ struct drbd_connection *connection;
+ struct drbd_device *device;
+ struct drbd_peer_device *peer_device, *tmp_peer_device;
struct gendisk *disk;
struct request_queue *q;
- int vnr_got = vnr;
- int minor_got = minor;
+ int id;
enum drbd_ret_code err = ERR_NOMEM;
- mdev = minor_to_mdev(minor);
- if (mdev)
+ device = minor_to_device(minor);
+ if (device)
return ERR_MINOR_EXISTS;
/* GFP_KERNEL, we are outside of all write-out paths */
- mdev = kzalloc(sizeof(struct drbd_conf), GFP_KERNEL);
- if (!mdev)
+ device = kzalloc(sizeof(struct drbd_device), GFP_KERNEL);
+ if (!device)
return ERR_NOMEM;
+ kref_init(&device->kref);
- kref_get(&tconn->kref);
- mdev->tconn = tconn;
+ kref_get(&resource->kref);
+ device->resource = resource;
+ device->minor = minor;
+ device->vnr = vnr;
- mdev->minor = minor;
- mdev->vnr = vnr;
-
- drbd_init_set_defaults(mdev);
+ drbd_init_set_defaults(device);
q = blk_alloc_queue(GFP_KERNEL);
if (!q)
goto out_no_q;
- mdev->rq_queue = q;
- q->queuedata = mdev;
+ device->rq_queue = q;
+ q->queuedata = device;
disk = alloc_disk(1);
if (!disk)
goto out_no_disk;
- mdev->vdisk = disk;
+ device->vdisk = disk;
set_disk_ro(disk, true);
@@ -2651,14 +2732,14 @@ enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor,
disk->first_minor = minor;
disk->fops = &drbd_ops;
sprintf(disk->disk_name, "drbd%d", minor);
- disk->private_data = mdev;
+ disk->private_data = device;
- mdev->this_bdev = bdget(MKDEV(DRBD_MAJOR, minor));
+ device->this_bdev = bdget(MKDEV(DRBD_MAJOR, minor));
/* we have no partitions. we contain only ourselves. */
- mdev->this_bdev->bd_contains = mdev->this_bdev;
+ device->this_bdev->bd_contains = device->this_bdev;
q->backing_dev_info.congested_fn = drbd_congested;
- q->backing_dev_info.congested_data = mdev;
+ q->backing_dev_info.congested_data = device;
blk_queue_make_request(q, drbd_make_request);
blk_queue_flush(q, REQ_FLUSH | REQ_FUA);
@@ -2667,70 +2748,125 @@ enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor,
blk_queue_max_hw_sectors(q, DRBD_MAX_BIO_SIZE_SAFE >> 8);
blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
blk_queue_merge_bvec(q, drbd_merge_bvec);
- q->queue_lock = &mdev->tconn->req_lock; /* needed since we use */
+ q->queue_lock = &resource->req_lock;
- mdev->md_io_page = alloc_page(GFP_KERNEL);
- if (!mdev->md_io_page)
+ device->md_io_page = alloc_page(GFP_KERNEL);
+ if (!device->md_io_page)
goto out_no_io_page;
- if (drbd_bm_init(mdev))
+ if (drbd_bm_init(device))
goto out_no_bitmap;
- mdev->read_requests = RB_ROOT;
- mdev->write_requests = RB_ROOT;
+ device->read_requests = RB_ROOT;
+ device->write_requests = RB_ROOT;
- minor_got = idr_alloc(&minors, mdev, minor, minor + 1, GFP_KERNEL);
- if (minor_got < 0) {
- if (minor_got == -ENOSPC) {
+ id = idr_alloc(&drbd_devices, device, minor, minor + 1, GFP_KERNEL);
+ if (id < 0) {
+ if (id == -ENOSPC) {
err = ERR_MINOR_EXISTS;
drbd_msg_put_info("requested minor exists already");
}
goto out_no_minor_idr;
}
+ kref_get(&device->kref);
- vnr_got = idr_alloc(&tconn->volumes, mdev, vnr, vnr + 1, GFP_KERNEL);
- if (vnr_got < 0) {
- if (vnr_got == -ENOSPC) {
- err = ERR_INVALID_REQUEST;
- drbd_msg_put_info("requested volume exists already");
+ id = idr_alloc(&resource->devices, device, vnr, vnr + 1, GFP_KERNEL);
+ if (id < 0) {
+ if (id == -ENOSPC) {
+ err = ERR_MINOR_EXISTS;
+ drbd_msg_put_info("requested minor exists already");
}
goto out_idr_remove_minor;
}
+ kref_get(&device->kref);
+
+ INIT_LIST_HEAD(&device->peer_devices);
+ for_each_connection(connection, resource) {
+ peer_device = kzalloc(sizeof(struct drbd_peer_device), GFP_KERNEL);
+ if (!peer_device)
+ goto out_idr_remove_from_resource;
+ peer_device->connection = connection;
+ peer_device->device = device;
+
+ list_add(&peer_device->peer_devices, &device->peer_devices);
+ kref_get(&device->kref);
- if (init_submitter(mdev)) {
+ id = idr_alloc(&connection->peer_devices, peer_device, vnr, vnr + 1, GFP_KERNEL);
+ if (id < 0) {
+ if (id == -ENOSPC) {
+ err = ERR_INVALID_REQUEST;
+ drbd_msg_put_info("requested volume exists already");
+ }
+ goto out_idr_remove_from_resource;
+ }
+ kref_get(&connection->kref);
+ }
+
+ if (init_submitter(device)) {
err = ERR_NOMEM;
drbd_msg_put_info("unable to create submit workqueue");
goto out_idr_remove_vol;
}
add_disk(disk);
- kref_init(&mdev->kref); /* one ref for both idrs and the the add_disk */
/* inherit the connection state */
- mdev->state.conn = tconn->cstate;
- if (mdev->state.conn == C_WF_REPORT_PARAMS)
- drbd_connected(mdev);
+ device->state.conn = first_connection(resource)->cstate;
+ if (device->state.conn == C_WF_REPORT_PARAMS) {
+ for_each_peer_device(peer_device, device)
+ drbd_connected(peer_device);
+ }
return NO_ERROR;
out_idr_remove_vol:
- idr_remove(&tconn->volumes, vnr_got);
+ idr_remove(&connection->peer_devices, vnr);
+out_idr_remove_from_resource:
+ for_each_connection(connection, resource) {
+ peer_device = idr_find(&connection->peer_devices, vnr);
+ if (peer_device) {
+ idr_remove(&connection->peer_devices, vnr);
+ kref_put(&connection->kref, drbd_destroy_connection);
+ }
+ }
+ for_each_peer_device_safe(peer_device, tmp_peer_device, device) {
+ list_del(&peer_device->peer_devices);
+ kfree(peer_device);
+ }
+ idr_remove(&resource->devices, vnr);
out_idr_remove_minor:
- idr_remove(&minors, minor_got);
+ idr_remove(&drbd_devices, minor);
synchronize_rcu();
out_no_minor_idr:
- drbd_bm_cleanup(mdev);
+ drbd_bm_cleanup(device);
out_no_bitmap:
- __free_page(mdev->md_io_page);
+ __free_page(device->md_io_page);
out_no_io_page:
put_disk(disk);
out_no_disk:
blk_cleanup_queue(q);
out_no_q:
- kfree(mdev);
- kref_put(&tconn->kref, &conn_destroy);
+ kref_put(&resource->kref, drbd_destroy_resource);
+ kfree(device);
return err;
}
+void drbd_delete_device(struct drbd_device *device)
+{
+ struct drbd_resource *resource = device->resource;
+ struct drbd_connection *connection;
+ int refs = 3;
+
+ for_each_connection(connection, resource) {
+ idr_remove(&connection->peer_devices, device->vnr);
+ refs++;
+ }
+ idr_remove(&resource->devices, device->vnr);
+ idr_remove(&drbd_devices, device_to_minor(device));
+ del_gendisk(device->vdisk);
+ synchronize_rcu();
+ kref_sub(&device->kref, refs, drbd_destroy_device);
+}
+
int __init drbd_init(void)
{
int err;
@@ -2761,10 +2897,10 @@ int __init drbd_init(void)
init_waitqueue_head(&drbd_pp_wait);
drbd_proc = NULL; /* play safe for drbd_cleanup */
- idr_init(&minors);
+ idr_init(&drbd_devices);
rwlock_init(&global_state_lock);
- INIT_LIST_HEAD(&drbd_tconns);
+ INIT_LIST_HEAD(&drbd_resources);
err = drbd_genl_register();
if (err) {
@@ -2822,37 +2958,39 @@ void drbd_free_bc(struct drbd_backing_dev *ldev)
kfree(ldev);
}
-void drbd_free_sock(struct drbd_tconn *tconn)
+void drbd_free_sock(struct drbd_connection *connection)
{
- if (tconn->data.socket) {
- mutex_lock(&tconn->data.mutex);
- kernel_sock_shutdown(tconn->data.socket, SHUT_RDWR);
- sock_release(tconn->data.socket);
- tconn->data.socket = NULL;
- mutex_unlock(&tconn->data.mutex);
+ if (connection->data.socket) {
+ mutex_lock(&connection->data.mutex);
+ kernel_sock_shutdown(connection->data.socket, SHUT_RDWR);
+ sock_release(connection->data.socket);
+ connection->data.socket = NULL;
+ mutex_unlock(&connection->data.mutex);
}
- if (tconn->meta.socket) {
- mutex_lock(&tconn->meta.mutex);
- kernel_sock_shutdown(tconn->meta.socket, SHUT_RDWR);
- sock_release(tconn->meta.socket);
- tconn->meta.socket = NULL;
- mutex_unlock(&tconn->meta.mutex);
+ if (connection->meta.socket) {
+ mutex_lock(&connection->meta.mutex);
+ kernel_sock_shutdown(connection->meta.socket, SHUT_RDWR);
+ sock_release(connection->meta.socket);
+ connection->meta.socket = NULL;
+ mutex_unlock(&connection->meta.mutex);
}
}
/* meta data management */
-void conn_md_sync(struct drbd_tconn *tconn)
+void conn_md_sync(struct drbd_connection *connection)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- kref_get(&mdev->kref);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+
+ kref_get(&device->kref);
rcu_read_unlock();
- drbd_md_sync(mdev);
- kref_put(&mdev->kref, &drbd_minor_destroy);
+ drbd_md_sync(device);
+ kref_put(&device->kref, drbd_destroy_device);
rcu_read_lock();
}
rcu_read_unlock();
@@ -2883,7 +3021,7 @@ struct meta_data_on_disk {
-void drbd_md_write(struct drbd_conf *mdev, void *b)
+void drbd_md_write(struct drbd_device *device, void *b)
{
struct meta_data_on_disk *buffer = b;
sector_t sector;
@@ -2891,39 +3029,39 @@ void drbd_md_write(struct drbd_conf *mdev, void *b)
memset(buffer, 0, sizeof(*buffer));
- buffer->la_size_sect = cpu_to_be64(drbd_get_capacity(mdev->this_bdev));
+ buffer->la_size_sect = cpu_to_be64(drbd_get_capacity(device->this_bdev));
for (i = UI_CURRENT; i < UI_SIZE; i++)
- buffer->uuid[i] = cpu_to_be64(mdev->ldev->md.uuid[i]);
- buffer->flags = cpu_to_be32(mdev->ldev->md.flags);
+ buffer->uuid[i] = cpu_to_be64(device->ldev->md.uuid[i]);
+ buffer->flags = cpu_to_be32(device->ldev->md.flags);
buffer->magic = cpu_to_be32(DRBD_MD_MAGIC_84_UNCLEAN);
- buffer->md_size_sect = cpu_to_be32(mdev->ldev->md.md_size_sect);
- buffer->al_offset = cpu_to_be32(mdev->ldev->md.al_offset);
- buffer->al_nr_extents = cpu_to_be32(mdev->act_log->nr_elements);
+ buffer->md_size_sect = cpu_to_be32(device->ldev->md.md_size_sect);
+ buffer->al_offset = cpu_to_be32(device->ldev->md.al_offset);
+ buffer->al_nr_extents = cpu_to_be32(device->act_log->nr_elements);
buffer->bm_bytes_per_bit = cpu_to_be32(BM_BLOCK_SIZE);
- buffer->device_uuid = cpu_to_be64(mdev->ldev->md.device_uuid);
+ buffer->device_uuid = cpu_to_be64(device->ldev->md.device_uuid);
- buffer->bm_offset = cpu_to_be32(mdev->ldev->md.bm_offset);
- buffer->la_peer_max_bio_size = cpu_to_be32(mdev->peer_max_bio_size);
+ buffer->bm_offset = cpu_to_be32(device->ldev->md.bm_offset);
+ buffer->la_peer_max_bio_size = cpu_to_be32(device->peer_max_bio_size);
- buffer->al_stripes = cpu_to_be32(mdev->ldev->md.al_stripes);
- buffer->al_stripe_size_4k = cpu_to_be32(mdev->ldev->md.al_stripe_size_4k);
+ buffer->al_stripes = cpu_to_be32(device->ldev->md.al_stripes);
+ buffer->al_stripe_size_4k = cpu_to_be32(device->ldev->md.al_stripe_size_4k);
- D_ASSERT(drbd_md_ss(mdev->ldev) == mdev->ldev->md.md_offset);
- sector = mdev->ldev->md.md_offset;
+ D_ASSERT(device, drbd_md_ss(device->ldev) == device->ldev->md.md_offset);
+ sector = device->ldev->md.md_offset;
- if (drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) {
+ if (drbd_md_sync_page_io(device, device->ldev, sector, WRITE)) {
/* this was a try anyways ... */
- dev_err(DEV, "meta data update failed!\n");
- drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
+ drbd_err(device, "meta data update failed!\n");
+ drbd_chk_io_error(device, 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.
+ * @device: DRBD device.
*/
-void drbd_md_sync(struct drbd_conf *mdev)
+void drbd_md_sync(struct drbd_device *device)
{
struct meta_data_on_disk *buffer;
@@ -2931,32 +3069,32 @@ void drbd_md_sync(struct drbd_conf *mdev)
BUILD_BUG_ON(UI_SIZE != 4);
BUILD_BUG_ON(sizeof(struct meta_data_on_disk) != 4096);
- del_timer(&mdev->md_sync_timer);
+ del_timer(&device->md_sync_timer);
/* timer may be rearmed by drbd_md_mark_dirty() now. */
- if (!test_and_clear_bit(MD_DIRTY, &mdev->flags))
+ if (!test_and_clear_bit(MD_DIRTY, &device->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))
+ if (!get_ldev_if_state(device, D_FAILED))
return;
- buffer = drbd_md_get_buffer(mdev);
+ buffer = drbd_md_get_buffer(device);
if (!buffer)
goto out;
- drbd_md_write(mdev, buffer);
+ drbd_md_write(device, buffer);
- /* Update mdev->ldev->md.la_size_sect,
+ /* Update device->ldev->md.la_size_sect,
* since we updated it on metadata. */
- mdev->ldev->md.la_size_sect = drbd_get_capacity(mdev->this_bdev);
+ device->ldev->md.la_size_sect = drbd_get_capacity(device->this_bdev);
- drbd_md_put_buffer(mdev);
+ drbd_md_put_buffer(device);
out:
- put_ldev(mdev);
+ put_ldev(device);
}
-static int check_activity_log_stripe_size(struct drbd_conf *mdev,
+static int check_activity_log_stripe_size(struct drbd_device *device,
struct meta_data_on_disk *on_disk,
struct drbd_md *in_core)
{
@@ -2996,12 +3134,12 @@ static int check_activity_log_stripe_size(struct drbd_conf *mdev,
return 0;
err:
- dev_err(DEV, "invalid activity log striping: al_stripes=%u, al_stripe_size_4k=%u\n",
+ drbd_err(device, "invalid activity log striping: al_stripes=%u, al_stripe_size_4k=%u\n",
al_stripes, al_stripe_size_4k);
return -EINVAL;
}
-static int check_offsets_and_sizes(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
+static int check_offsets_and_sizes(struct drbd_device *device, struct drbd_backing_dev *bdev)
{
sector_t capacity = drbd_get_capacity(bdev->md_bdev);
struct drbd_md *in_core = &bdev->md;
@@ -3068,7 +3206,7 @@ static int check_offsets_and_sizes(struct drbd_conf *mdev, struct drbd_backing_d
return 0;
err:
- dev_err(DEV, "meta data offsets don't make sense: idx=%d "
+ drbd_err(device, "meta data offsets don't make sense: idx=%d "
"al_s=%u, al_sz4k=%u, al_offset=%d, bm_offset=%d, "
"md_size_sect=%u, la_size=%llu, md_capacity=%llu\n",
in_core->meta_dev_idx,
@@ -3083,25 +3221,25 @@ err:
/**
* drbd_md_read() - Reads in the meta data super block
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @bdev: Device from which the meta data should be read in.
*
* Return NO_ERROR on success, and an enum drbd_ret_code in case
* something goes wrong.
*
* Called exactly once during drbd_adm_attach(), while still being D_DISKLESS,
- * even before @bdev is assigned to @mdev->ldev.
+ * even before @bdev is assigned to @device->ldev.
*/
-int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
+int drbd_md_read(struct drbd_device *device, struct drbd_backing_dev *bdev)
{
struct meta_data_on_disk *buffer;
u32 magic, flags;
int i, rv = NO_ERROR;
- if (mdev->state.disk != D_DISKLESS)
+ if (device->state.disk != D_DISKLESS)
return ERR_DISK_CONFIGURED;
- buffer = drbd_md_get_buffer(mdev);
+ buffer = drbd_md_get_buffer(device);
if (!buffer)
return ERR_NOMEM;
@@ -3110,10 +3248,10 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
bdev->md.meta_dev_idx = bdev->disk_conf->meta_dev_idx;
bdev->md.md_offset = drbd_md_ss(bdev);
- if (drbd_md_sync_page_io(mdev, bdev, bdev->md.md_offset, READ)) {
+ if (drbd_md_sync_page_io(device, bdev, bdev->md.md_offset, READ)) {
/* NOTE: can't do normal error processing here as this is
called BEFORE disk is attached */
- dev_err(DEV, "Error while reading metadata.\n");
+ drbd_err(device, "Error while reading metadata.\n");
rv = ERR_IO_MD_DISK;
goto err;
}
@@ -3123,7 +3261,7 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
if (magic == DRBD_MD_MAGIC_84_UNCLEAN ||
(magic == DRBD_MD_MAGIC_08 && !(flags & MDF_AL_CLEAN))) {
/* btw: that's Activity Log clean, not "all" clean. */
- dev_err(DEV, "Found unclean meta data. Did you \"drbdadm apply-al\"?\n");
+ drbd_err(device, "Found unclean meta data. Did you \"drbdadm apply-al\"?\n");
rv = ERR_MD_UNCLEAN;
goto err;
}
@@ -3131,14 +3269,14 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
rv = ERR_MD_INVALID;
if (magic != DRBD_MD_MAGIC_08) {
if (magic == DRBD_MD_MAGIC_07)
- dev_err(DEV, "Found old (0.7) meta data magic. Did you \"drbdadm create-md\"?\n");
+ drbd_err(device, "Found old (0.7) meta data magic. Did you \"drbdadm create-md\"?\n");
else
- dev_err(DEV, "Meta data magic not found. Did you \"drbdadm create-md\"?\n");
+ drbd_err(device, "Meta data magic not found. Did you \"drbdadm create-md\"?\n");
goto err;
}
if (be32_to_cpu(buffer->bm_bytes_per_bit) != BM_BLOCK_SIZE) {
- dev_err(DEV, "unexpected bm_bytes_per_bit: %u (expected %u)\n",
+ drbd_err(device, "unexpected bm_bytes_per_bit: %u (expected %u)\n",
be32_to_cpu(buffer->bm_bytes_per_bit), BM_BLOCK_SIZE);
goto err;
}
@@ -3155,182 +3293,182 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
bdev->md.al_offset = be32_to_cpu(buffer->al_offset);
bdev->md.bm_offset = be32_to_cpu(buffer->bm_offset);
- if (check_activity_log_stripe_size(mdev, buffer, &bdev->md))
+ if (check_activity_log_stripe_size(device, buffer, &bdev->md))
goto err;
- if (check_offsets_and_sizes(mdev, bdev))
+ if (check_offsets_and_sizes(device, bdev))
goto err;
if (be32_to_cpu(buffer->bm_offset) != bdev->md.bm_offset) {
- dev_err(DEV, "unexpected bm_offset: %d (expected %d)\n",
+ drbd_err(device, "unexpected bm_offset: %d (expected %d)\n",
be32_to_cpu(buffer->bm_offset), bdev->md.bm_offset);
goto err;
}
if (be32_to_cpu(buffer->md_size_sect) != bdev->md.md_size_sect) {
- dev_err(DEV, "unexpected md_size: %u (expected %u)\n",
+ drbd_err(device, "unexpected md_size: %u (expected %u)\n",
be32_to_cpu(buffer->md_size_sect), bdev->md.md_size_sect);
goto err;
}
rv = NO_ERROR;
- spin_lock_irq(&mdev->tconn->req_lock);
- if (mdev->state.conn < C_CONNECTED) {
+ spin_lock_irq(&device->resource->req_lock);
+ if (device->state.conn < C_CONNECTED) {
unsigned int peer;
peer = be32_to_cpu(buffer->la_peer_max_bio_size);
peer = max(peer, DRBD_MAX_BIO_SIZE_SAFE);
- mdev->peer_max_bio_size = peer;
+ device->peer_max_bio_size = peer;
}
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
err:
- drbd_md_put_buffer(mdev);
+ drbd_md_put_buffer(device);
return rv;
}
/**
* drbd_md_mark_dirty() - Mark meta data super block as dirty
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Call this function if you change anything that should be written to
* the meta-data super block. This function sets MD_DIRTY, and starts a
* timer that ensures that within five seconds you have to call drbd_md_sync().
*/
#ifdef DEBUG
-void drbd_md_mark_dirty_(struct drbd_conf *mdev, unsigned int line, const char *func)
+void drbd_md_mark_dirty_(struct drbd_device *device, unsigned int line, const char *func)
{
- if (!test_and_set_bit(MD_DIRTY, &mdev->flags)) {
- mod_timer(&mdev->md_sync_timer, jiffies + HZ);
- mdev->last_md_mark_dirty.line = line;
- mdev->last_md_mark_dirty.func = func;
+ if (!test_and_set_bit(MD_DIRTY, &device->flags)) {
+ mod_timer(&device->md_sync_timer, jiffies + HZ);
+ device->last_md_mark_dirty.line = line;
+ device->last_md_mark_dirty.func = func;
}
}
#else
-void drbd_md_mark_dirty(struct drbd_conf *mdev)
+void drbd_md_mark_dirty(struct drbd_device *device)
{
- if (!test_and_set_bit(MD_DIRTY, &mdev->flags))
- mod_timer(&mdev->md_sync_timer, jiffies + 5*HZ);
+ if (!test_and_set_bit(MD_DIRTY, &device->flags))
+ mod_timer(&device->md_sync_timer, jiffies + 5*HZ);
}
#endif
-void drbd_uuid_move_history(struct drbd_conf *mdev) __must_hold(local)
+void drbd_uuid_move_history(struct drbd_device *device) __must_hold(local)
{
int i;
for (i = UI_HISTORY_START; i < UI_HISTORY_END; i++)
- mdev->ldev->md.uuid[i+1] = mdev->ldev->md.uuid[i];
+ device->ldev->md.uuid[i+1] = device->ldev->md.uuid[i];
}
-void __drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local)
+void __drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local)
{
if (idx == UI_CURRENT) {
- if (mdev->state.role == R_PRIMARY)
+ if (device->state.role == R_PRIMARY)
val |= 1;
else
val &= ~((u64)1);
- drbd_set_ed_uuid(mdev, val);
+ drbd_set_ed_uuid(device, val);
}
- mdev->ldev->md.uuid[idx] = val;
- drbd_md_mark_dirty(mdev);
+ device->ldev->md.uuid[idx] = val;
+ drbd_md_mark_dirty(device);
}
-void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local)
+void _drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local)
{
unsigned long flags;
- spin_lock_irqsave(&mdev->ldev->md.uuid_lock, flags);
- __drbd_uuid_set(mdev, idx, val);
- spin_unlock_irqrestore(&mdev->ldev->md.uuid_lock, flags);
+ spin_lock_irqsave(&device->ldev->md.uuid_lock, flags);
+ __drbd_uuid_set(device, idx, val);
+ spin_unlock_irqrestore(&device->ldev->md.uuid_lock, flags);
}
-void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local)
+void drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local)
{
unsigned long flags;
- spin_lock_irqsave(&mdev->ldev->md.uuid_lock, flags);
- if (mdev->ldev->md.uuid[idx]) {
- drbd_uuid_move_history(mdev);
- mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[idx];
+ spin_lock_irqsave(&device->ldev->md.uuid_lock, flags);
+ if (device->ldev->md.uuid[idx]) {
+ drbd_uuid_move_history(device);
+ device->ldev->md.uuid[UI_HISTORY_START] = device->ldev->md.uuid[idx];
}
- __drbd_uuid_set(mdev, idx, val);
- spin_unlock_irqrestore(&mdev->ldev->md.uuid_lock, flags);
+ __drbd_uuid_set(device, idx, val);
+ spin_unlock_irqrestore(&device->ldev->md.uuid_lock, flags);
}
/**
* drbd_uuid_new_current() - Creates a new current UUID
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Creates a new current UUID, and rotates the old current UUID into
* the bitmap slot. Causes an incremental resync upon next connect.
*/
-void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local)
+void drbd_uuid_new_current(struct drbd_device *device) __must_hold(local)
{
u64 val;
unsigned long long bm_uuid;
get_random_bytes(&val, sizeof(u64));
- spin_lock_irq(&mdev->ldev->md.uuid_lock);
- bm_uuid = mdev->ldev->md.uuid[UI_BITMAP];
+ spin_lock_irq(&device->ldev->md.uuid_lock);
+ bm_uuid = device->ldev->md.uuid[UI_BITMAP];
if (bm_uuid)
- dev_warn(DEV, "bm UUID was already set: %llX\n", bm_uuid);
+ drbd_warn(device, "bm UUID was already set: %llX\n", bm_uuid);
- mdev->ldev->md.uuid[UI_BITMAP] = mdev->ldev->md.uuid[UI_CURRENT];
- __drbd_uuid_set(mdev, UI_CURRENT, val);
- spin_unlock_irq(&mdev->ldev->md.uuid_lock);
+ device->ldev->md.uuid[UI_BITMAP] = device->ldev->md.uuid[UI_CURRENT];
+ __drbd_uuid_set(device, UI_CURRENT, val);
+ spin_unlock_irq(&device->ldev->md.uuid_lock);
- drbd_print_uuids(mdev, "new current UUID");
+ drbd_print_uuids(device, "new current UUID");
/* get it to stable storage _now_ */
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
}
-void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local)
+void drbd_uuid_set_bm(struct drbd_device *device, u64 val) __must_hold(local)
{
unsigned long flags;
- if (mdev->ldev->md.uuid[UI_BITMAP] == 0 && val == 0)
+ if (device->ldev->md.uuid[UI_BITMAP] == 0 && val == 0)
return;
- spin_lock_irqsave(&mdev->ldev->md.uuid_lock, flags);
+ spin_lock_irqsave(&device->ldev->md.uuid_lock, flags);
if (val == 0) {
- drbd_uuid_move_history(mdev);
- mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[UI_BITMAP];
- mdev->ldev->md.uuid[UI_BITMAP] = 0;
+ drbd_uuid_move_history(device);
+ device->ldev->md.uuid[UI_HISTORY_START] = device->ldev->md.uuid[UI_BITMAP];
+ device->ldev->md.uuid[UI_BITMAP] = 0;
} else {
- unsigned long long bm_uuid = mdev->ldev->md.uuid[UI_BITMAP];
+ unsigned long long bm_uuid = device->ldev->md.uuid[UI_BITMAP];
if (bm_uuid)
- dev_warn(DEV, "bm UUID was already set: %llX\n", bm_uuid);
+ drbd_warn(device, "bm UUID was already set: %llX\n", bm_uuid);
- mdev->ldev->md.uuid[UI_BITMAP] = val & ~((u64)1);
+ device->ldev->md.uuid[UI_BITMAP] = val & ~((u64)1);
}
- spin_unlock_irqrestore(&mdev->ldev->md.uuid_lock, flags);
+ spin_unlock_irqrestore(&device->ldev->md.uuid_lock, flags);
- drbd_md_mark_dirty(mdev);
+ drbd_md_mark_dirty(device);
}
/**
* drbd_bmio_set_n_write() - io_fn for drbd_queue_bitmap_io() or drbd_bitmap_io()
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Sets all bits in the bitmap and writes the whole bitmap to stable storage.
*/
-int drbd_bmio_set_n_write(struct drbd_conf *mdev)
+int drbd_bmio_set_n_write(struct drbd_device *device)
{
int rv = -EIO;
- if (get_ldev_if_state(mdev, D_ATTACHING)) {
- drbd_md_set_flag(mdev, MDF_FULL_SYNC);
- drbd_md_sync(mdev);
- drbd_bm_set_all(mdev);
+ if (get_ldev_if_state(device, D_ATTACHING)) {
+ drbd_md_set_flag(device, MDF_FULL_SYNC);
+ drbd_md_sync(device);
+ drbd_bm_set_all(device);
- rv = drbd_bm_write(mdev);
+ rv = drbd_bm_write(device);
if (!rv) {
- drbd_md_clear_flag(mdev, MDF_FULL_SYNC);
- drbd_md_sync(mdev);
+ drbd_md_clear_flag(device, MDF_FULL_SYNC);
+ drbd_md_sync(device);
}
- put_ldev(mdev);
+ put_ldev(device);
}
return rv;
@@ -3338,19 +3476,19 @@ int drbd_bmio_set_n_write(struct drbd_conf *mdev)
/**
* drbd_bmio_clear_n_write() - io_fn for drbd_queue_bitmap_io() or drbd_bitmap_io()
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Clears all bits in the bitmap and writes the whole bitmap to stable storage.
*/
-int drbd_bmio_clear_n_write(struct drbd_conf *mdev)
+int drbd_bmio_clear_n_write(struct drbd_device *device)
{
int rv = -EIO;
- drbd_resume_al(mdev);
- if (get_ldev_if_state(mdev, D_ATTACHING)) {
- drbd_bm_clear_all(mdev);
- rv = drbd_bm_write(mdev);
- put_ldev(mdev);
+ drbd_resume_al(device);
+ if (get_ldev_if_state(device, D_ATTACHING)) {
+ drbd_bm_clear_all(device);
+ rv = drbd_bm_write(device);
+ put_ldev(device);
}
return rv;
@@ -3358,50 +3496,52 @@ int drbd_bmio_clear_n_write(struct drbd_conf *mdev)
static int w_bitmap_io(struct drbd_work *w, int unused)
{
- struct bm_io_work *work = container_of(w, struct bm_io_work, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_device *device =
+ container_of(w, struct drbd_device, bm_io_work.w);
+ struct bm_io_work *work = &device->bm_io_work;
int rv = -EIO;
- D_ASSERT(atomic_read(&mdev->ap_bio_cnt) == 0);
+ D_ASSERT(device, atomic_read(&device->ap_bio_cnt) == 0);
- if (get_ldev(mdev)) {
- drbd_bm_lock(mdev, work->why, work->flags);
- rv = work->io_fn(mdev);
- drbd_bm_unlock(mdev);
- put_ldev(mdev);
+ if (get_ldev(device)) {
+ drbd_bm_lock(device, work->why, work->flags);
+ rv = work->io_fn(device);
+ drbd_bm_unlock(device);
+ put_ldev(device);
}
- clear_bit_unlock(BITMAP_IO, &mdev->flags);
- wake_up(&mdev->misc_wait);
+ clear_bit_unlock(BITMAP_IO, &device->flags);
+ wake_up(&device->misc_wait);
if (work->done)
- work->done(mdev, rv);
+ work->done(device, rv);
- clear_bit(BITMAP_IO_QUEUED, &mdev->flags);
+ clear_bit(BITMAP_IO_QUEUED, &device->flags);
work->why = NULL;
work->flags = 0;
return 0;
}
-void drbd_ldev_destroy(struct drbd_conf *mdev)
+void drbd_ldev_destroy(struct drbd_device *device)
{
- lc_destroy(mdev->resync);
- mdev->resync = NULL;
- lc_destroy(mdev->act_log);
- mdev->act_log = NULL;
+ lc_destroy(device->resync);
+ device->resync = NULL;
+ lc_destroy(device->act_log);
+ device->act_log = NULL;
__no_warn(local,
- drbd_free_bc(mdev->ldev);
- mdev->ldev = NULL;);
+ drbd_free_bc(device->ldev);
+ device->ldev = NULL;);
- clear_bit(GO_DISKLESS, &mdev->flags);
+ clear_bit(GO_DISKLESS, &device->flags);
}
static int w_go_diskless(struct drbd_work *w, int unused)
{
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_device *device =
+ container_of(w, struct drbd_device, go_diskless);
- D_ASSERT(mdev->state.disk == D_FAILED);
+ D_ASSERT(device, device->state.disk == D_FAILED);
/* we cannot assert local_cnt == 0 here, as get_ldev_if_state will
* inc/dec it frequently. Once we are D_DISKLESS, no one will touch
* the protected members anymore, though, so once put_ldev reaches zero
@@ -3420,27 +3560,27 @@ static int w_go_diskless(struct drbd_work *w, int unused)
* We still need to check if both bitmap and ldev are present, we may
* end up here after a failed attach, before ldev was even assigned.
*/
- if (mdev->bitmap && mdev->ldev) {
+ if (device->bitmap && device->ldev) {
/* An interrupted resync or similar is allowed to recounts bits
* while we detach.
* Any modifications would not be expected anymore, though.
*/
- if (drbd_bitmap_io_from_worker(mdev, drbd_bm_write,
+ if (drbd_bitmap_io_from_worker(device, drbd_bm_write,
"detach", BM_LOCKED_TEST_ALLOWED)) {
- if (test_bit(WAS_READ_ERROR, &mdev->flags)) {
- drbd_md_set_flag(mdev, MDF_FULL_SYNC);
- drbd_md_sync(mdev);
+ if (test_bit(WAS_READ_ERROR, &device->flags)) {
+ drbd_md_set_flag(device, MDF_FULL_SYNC);
+ drbd_md_sync(device);
}
}
}
- drbd_force_state(mdev, NS(disk, D_DISKLESS));
+ drbd_force_state(device, NS(disk, D_DISKLESS));
return 0;
}
/**
* drbd_queue_bitmap_io() - Queues an IO operation on the whole bitmap
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @io_fn: IO callback to be called when bitmap IO is possible
* @done: callback to be called after the bitmap IO was performed
* @why: Descriptive text of the reason for doing the IO
@@ -3450,76 +3590,77 @@ static int w_go_diskless(struct drbd_work *w, int unused)
* called from worker context. It MUST NOT be used while a previous such
* work is still pending!
*/
-void drbd_queue_bitmap_io(struct drbd_conf *mdev,
- int (*io_fn)(struct drbd_conf *),
- void (*done)(struct drbd_conf *, int),
+void drbd_queue_bitmap_io(struct drbd_device *device,
+ int (*io_fn)(struct drbd_device *),
+ void (*done)(struct drbd_device *, int),
char *why, enum bm_flag flags)
{
- D_ASSERT(current == mdev->tconn->worker.task);
+ D_ASSERT(device, current == first_peer_device(device)->connection->worker.task);
- D_ASSERT(!test_bit(BITMAP_IO_QUEUED, &mdev->flags));
- D_ASSERT(!test_bit(BITMAP_IO, &mdev->flags));
- D_ASSERT(list_empty(&mdev->bm_io_work.w.list));
- if (mdev->bm_io_work.why)
- dev_err(DEV, "FIXME going to queue '%s' but '%s' still pending?\n",
- why, mdev->bm_io_work.why);
+ D_ASSERT(device, !test_bit(BITMAP_IO_QUEUED, &device->flags));
+ D_ASSERT(device, !test_bit(BITMAP_IO, &device->flags));
+ D_ASSERT(device, list_empty(&device->bm_io_work.w.list));
+ if (device->bm_io_work.why)
+ drbd_err(device, "FIXME going to queue '%s' but '%s' still pending?\n",
+ why, device->bm_io_work.why);
- mdev->bm_io_work.io_fn = io_fn;
- mdev->bm_io_work.done = done;
- mdev->bm_io_work.why = why;
- mdev->bm_io_work.flags = flags;
+ device->bm_io_work.io_fn = io_fn;
+ device->bm_io_work.done = done;
+ device->bm_io_work.why = why;
+ device->bm_io_work.flags = flags;
- spin_lock_irq(&mdev->tconn->req_lock);
- set_bit(BITMAP_IO, &mdev->flags);
- if (atomic_read(&mdev->ap_bio_cnt) == 0) {
- if (!test_and_set_bit(BITMAP_IO_QUEUED, &mdev->flags))
- drbd_queue_work(&mdev->tconn->sender_work, &mdev->bm_io_work.w);
+ spin_lock_irq(&device->resource->req_lock);
+ set_bit(BITMAP_IO, &device->flags);
+ if (atomic_read(&device->ap_bio_cnt) == 0) {
+ if (!test_and_set_bit(BITMAP_IO_QUEUED, &device->flags))
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &device->bm_io_work.w);
}
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
}
/**
* drbd_bitmap_io() - Does an IO operation on the whole bitmap
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @io_fn: IO callback to be called when bitmap IO is possible
* @why: Descriptive text of the reason for doing the IO
*
* freezes application IO while that the actual IO operations runs. This
* functions MAY NOT be called from worker context.
*/
-int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *),
+int drbd_bitmap_io(struct drbd_device *device, int (*io_fn)(struct drbd_device *),
char *why, enum bm_flag flags)
{
int rv;
- D_ASSERT(current != mdev->tconn->worker.task);
+ D_ASSERT(device, current != first_peer_device(device)->connection->worker.task);
if ((flags & BM_LOCKED_SET_ALLOWED) == 0)
- drbd_suspend_io(mdev);
+ drbd_suspend_io(device);
- drbd_bm_lock(mdev, why, flags);
- rv = io_fn(mdev);
- drbd_bm_unlock(mdev);
+ drbd_bm_lock(device, why, flags);
+ rv = io_fn(device);
+ drbd_bm_unlock(device);
if ((flags & BM_LOCKED_SET_ALLOWED) == 0)
- drbd_resume_io(mdev);
+ drbd_resume_io(device);
return rv;
}
-void drbd_md_set_flag(struct drbd_conf *mdev, int flag) __must_hold(local)
+void drbd_md_set_flag(struct drbd_device *device, int flag) __must_hold(local)
{
- if ((mdev->ldev->md.flags & flag) != flag) {
- drbd_md_mark_dirty(mdev);
- mdev->ldev->md.flags |= flag;
+ if ((device->ldev->md.flags & flag) != flag) {
+ drbd_md_mark_dirty(device);
+ device->ldev->md.flags |= flag;
}
}
-void drbd_md_clear_flag(struct drbd_conf *mdev, int flag) __must_hold(local)
+void drbd_md_clear_flag(struct drbd_device *device, int flag) __must_hold(local)
{
- if ((mdev->ldev->md.flags & flag) != 0) {
- drbd_md_mark_dirty(mdev);
- mdev->ldev->md.flags &= ~flag;
+ if ((device->ldev->md.flags & flag) != 0) {
+ drbd_md_mark_dirty(device);
+ device->ldev->md.flags &= ~flag;
}
}
int drbd_md_test_flag(struct drbd_backing_dev *bdev, int flag)
@@ -3529,23 +3670,25 @@ int drbd_md_test_flag(struct drbd_backing_dev *bdev, int flag)
static void md_sync_timer_fn(unsigned long data)
{
- struct drbd_conf *mdev = (struct drbd_conf *) data;
+ struct drbd_device *device = (struct drbd_device *) data;
/* must not double-queue! */
- if (list_empty(&mdev->md_sync_work.list))
- drbd_queue_work_front(&mdev->tconn->sender_work, &mdev->md_sync_work);
+ if (list_empty(&device->md_sync_work.list))
+ drbd_queue_work_front(&first_peer_device(device)->connection->sender_work,
+ &device->md_sync_work);
}
static int w_md_sync(struct drbd_work *w, int unused)
{
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_device *device =
+ container_of(w, struct drbd_device, md_sync_work);
- dev_warn(DEV, "md_sync_timer expired! Worker calls drbd_md_sync().\n");
+ drbd_warn(device, "md_sync_timer expired! Worker calls drbd_md_sync().\n");
#ifdef DEBUG
- dev_warn(DEV, "last md_mark_dirty: %s:%u\n",
- mdev->last_md_mark_dirty.func, mdev->last_md_mark_dirty.line);
+ drbd_warn(device, "last md_mark_dirty: %s:%u\n",
+ device->last_md_mark_dirty.func, device->last_md_mark_dirty.line);
#endif
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
return 0;
}
@@ -3621,18 +3764,18 @@ const char *cmdname(enum drbd_packet cmd)
/**
* drbd_wait_misc - wait for a request to make progress
- * @mdev: device associated with the request
+ * @device: device associated with the request
* @i: the struct drbd_interval embedded in struct drbd_request or
* struct drbd_peer_request
*/
-int drbd_wait_misc(struct drbd_conf *mdev, struct drbd_interval *i)
+int drbd_wait_misc(struct drbd_device *device, struct drbd_interval *i)
{
struct net_conf *nc;
DEFINE_WAIT(wait);
long timeout;
rcu_read_lock();
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
if (!nc) {
rcu_read_unlock();
return -ETIMEDOUT;
@@ -3640,14 +3783,14 @@ int drbd_wait_misc(struct drbd_conf *mdev, struct drbd_interval *i)
timeout = nc->ko_count ? nc->timeout * HZ / 10 * nc->ko_count : MAX_SCHEDULE_TIMEOUT;
rcu_read_unlock();
- /* Indicate to wake up mdev->misc_wait on progress. */
+ /* Indicate to wake up device->misc_wait on progress. */
i->waiting = true;
- prepare_to_wait(&mdev->misc_wait, &wait, TASK_INTERRUPTIBLE);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ prepare_to_wait(&device->misc_wait, &wait, TASK_INTERRUPTIBLE);
+ spin_unlock_irq(&device->resource->req_lock);
timeout = schedule_timeout(timeout);
- finish_wait(&mdev->misc_wait, &wait);
- spin_lock_irq(&mdev->tconn->req_lock);
- if (!timeout || mdev->state.conn < C_CONNECTED)
+ finish_wait(&device->misc_wait, &wait);
+ spin_lock_irq(&device->resource->req_lock);
+ if (!timeout || device->state.conn < C_CONNECTED)
return -ETIMEDOUT;
if (signal_pending(current))
return -ERESTARTSYS;
@@ -3703,20 +3846,20 @@ _drbd_fault_str(unsigned int type) {
}
unsigned int
-_drbd_insert_fault(struct drbd_conf *mdev, unsigned int type)
+_drbd_insert_fault(struct drbd_device *device, unsigned int type)
{
static struct fault_random_state rrs = {0, 0};
unsigned int ret = (
(fault_devs == 0 ||
- ((1 << mdev_to_minor(mdev)) & fault_devs) != 0) &&
+ ((1 << device_to_minor(device)) & fault_devs) != 0) &&
(((_drbd_fault_random(&rrs) % 100) + 1) <= fault_rate));
if (ret) {
fault_count++;
if (__ratelimit(&drbd_ratelimit_state))
- dev_warn(DEV, "***Simulating %s failure\n",
+ drbd_warn(device, "***Simulating %s failure\n",
_drbd_fault_str(type));
}
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index c706d50a8b06..526414bc2cab 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -32,6 +32,7 @@
#include <linux/blkpg.h>
#include <linux/cpumask.h>
#include "drbd_int.h"
+#include "drbd_protocol.h"
#include "drbd_req.h"
#include "drbd_wrappers.h"
#include <asm/unaligned.h>
@@ -44,8 +45,8 @@
// int drbd_adm_create_resource(struct sk_buff *skb, struct genl_info *info);
// int drbd_adm_delete_resource(struct sk_buff *skb, struct genl_info *info);
-int drbd_adm_add_minor(struct sk_buff *skb, struct genl_info *info);
-int drbd_adm_delete_minor(struct sk_buff *skb, struct genl_info *info);
+int drbd_adm_new_minor(struct sk_buff *skb, struct genl_info *info);
+int drbd_adm_del_minor(struct sk_buff *skb, struct genl_info *info);
int drbd_adm_new_resource(struct sk_buff *skb, struct genl_info *info);
int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info);
@@ -102,8 +103,9 @@ static struct drbd_config_context {
/* pointer into reply buffer */
struct drbd_genlmsghdr *reply_dh;
/* resolved from attributes, if possible */
- struct drbd_conf *mdev;
- struct drbd_tconn *tconn;
+ struct drbd_device *device;
+ struct drbd_resource *resource;
+ struct drbd_connection *connection;
} adm_ctx;
static void drbd_adm_send_reply(struct sk_buff *skb, struct genl_info *info)
@@ -202,62 +204,67 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
adm_ctx.my_addr = nested_attr_tb[__nla_type(T_ctx_my_addr)];
adm_ctx.peer_addr = nested_attr_tb[__nla_type(T_ctx_peer_addr)];
if ((adm_ctx.my_addr &&
- nla_len(adm_ctx.my_addr) > sizeof(adm_ctx.tconn->my_addr)) ||
+ nla_len(adm_ctx.my_addr) > sizeof(adm_ctx.connection->my_addr)) ||
(adm_ctx.peer_addr &&
- nla_len(adm_ctx.peer_addr) > sizeof(adm_ctx.tconn->peer_addr))) {
+ nla_len(adm_ctx.peer_addr) > sizeof(adm_ctx.connection->peer_addr))) {
err = -EINVAL;
goto fail;
}
}
adm_ctx.minor = d_in->minor;
- adm_ctx.mdev = minor_to_mdev(d_in->minor);
- adm_ctx.tconn = conn_get_by_name(adm_ctx.resource_name);
+ adm_ctx.device = minor_to_device(d_in->minor);
+ if (adm_ctx.resource_name) {
+ adm_ctx.resource = drbd_find_resource(adm_ctx.resource_name);
+ }
- if (!adm_ctx.mdev && (flags & DRBD_ADM_NEED_MINOR)) {
+ if (!adm_ctx.device && (flags & DRBD_ADM_NEED_MINOR)) {
drbd_msg_put_info("unknown minor");
return ERR_MINOR_INVALID;
}
- if (!adm_ctx.tconn && (flags & DRBD_ADM_NEED_RESOURCE)) {
+ if (!adm_ctx.resource && (flags & DRBD_ADM_NEED_RESOURCE)) {
drbd_msg_put_info("unknown resource");
+ if (adm_ctx.resource_name)
+ return ERR_RES_NOT_KNOWN;
return ERR_INVALID_REQUEST;
}
if (flags & DRBD_ADM_NEED_CONNECTION) {
- if (adm_ctx.tconn && !(flags & DRBD_ADM_NEED_RESOURCE)) {
+ if (adm_ctx.resource) {
drbd_msg_put_info("no resource name expected");
return ERR_INVALID_REQUEST;
}
- if (adm_ctx.mdev) {
+ if (adm_ctx.device) {
drbd_msg_put_info("no minor number expected");
return ERR_INVALID_REQUEST;
}
if (adm_ctx.my_addr && adm_ctx.peer_addr)
- adm_ctx.tconn = conn_get_by_addrs(nla_data(adm_ctx.my_addr),
+ adm_ctx.connection = conn_get_by_addrs(nla_data(adm_ctx.my_addr),
nla_len(adm_ctx.my_addr),
nla_data(adm_ctx.peer_addr),
nla_len(adm_ctx.peer_addr));
- if (!adm_ctx.tconn) {
+ if (!adm_ctx.connection) {
drbd_msg_put_info("unknown connection");
return ERR_INVALID_REQUEST;
}
}
/* some more paranoia, if the request was over-determined */
- if (adm_ctx.mdev && adm_ctx.tconn &&
- adm_ctx.mdev->tconn != adm_ctx.tconn) {
- pr_warning("request: minor=%u, resource=%s; but that minor belongs to connection %s\n",
- adm_ctx.minor, adm_ctx.resource_name,
- adm_ctx.mdev->tconn->name);
+ if (adm_ctx.device && adm_ctx.resource &&
+ adm_ctx.device->resource != adm_ctx.resource) {
+ pr_warning("request: minor=%u, resource=%s; but that minor belongs to resource %s\n",
+ adm_ctx.minor, adm_ctx.resource->name,
+ adm_ctx.device->resource->name);
drbd_msg_put_info("minor exists in different resource");
return ERR_INVALID_REQUEST;
}
- if (adm_ctx.mdev &&
+ if (adm_ctx.device &&
adm_ctx.volume != VOLUME_UNSPECIFIED &&
- adm_ctx.volume != adm_ctx.mdev->vnr) {
+ adm_ctx.volume != adm_ctx.device->vnr) {
pr_warning("request: minor=%u, volume=%u; but that minor is volume %u in %s\n",
adm_ctx.minor, adm_ctx.volume,
- adm_ctx.mdev->vnr, adm_ctx.mdev->tconn->name);
+ adm_ctx.device->vnr,
+ adm_ctx.device->resource->name);
drbd_msg_put_info("minor exists as different volume");
return ERR_INVALID_REQUEST;
}
@@ -272,9 +279,13 @@ fail:
static int drbd_adm_finish(struct genl_info *info, int retcode)
{
- if (adm_ctx.tconn) {
- kref_put(&adm_ctx.tconn->kref, &conn_destroy);
- adm_ctx.tconn = NULL;
+ if (adm_ctx.connection) {
+ kref_put(&adm_ctx.connection->kref, drbd_destroy_connection);
+ adm_ctx.connection = NULL;
+ }
+ if (adm_ctx.resource) {
+ kref_put(&adm_ctx.resource->kref, drbd_destroy_resource);
+ adm_ctx.resource = NULL;
}
if (!adm_ctx.reply_skb)
@@ -285,34 +296,34 @@ static int drbd_adm_finish(struct genl_info *info, int retcode)
return 0;
}
-static void setup_khelper_env(struct drbd_tconn *tconn, char **envp)
+static void setup_khelper_env(struct drbd_connection *connection, char **envp)
{
char *afs;
/* FIXME: A future version will not allow this case. */
- if (tconn->my_addr_len == 0 || tconn->peer_addr_len == 0)
+ if (connection->my_addr_len == 0 || connection->peer_addr_len == 0)
return;
- switch (((struct sockaddr *)&tconn->peer_addr)->sa_family) {
+ switch (((struct sockaddr *)&connection->peer_addr)->sa_family) {
case AF_INET6:
afs = "ipv6";
snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI6",
- &((struct sockaddr_in6 *)&tconn->peer_addr)->sin6_addr);
+ &((struct sockaddr_in6 *)&connection->peer_addr)->sin6_addr);
break;
case AF_INET:
afs = "ipv4";
snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI4",
- &((struct sockaddr_in *)&tconn->peer_addr)->sin_addr);
+ &((struct sockaddr_in *)&connection->peer_addr)->sin_addr);
break;
default:
afs = "ssocks";
snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI4",
- &((struct sockaddr_in *)&tconn->peer_addr)->sin_addr);
+ &((struct sockaddr_in *)&connection->peer_addr)->sin_addr);
}
snprintf(envp[3], 20, "DRBD_PEER_AF=%s", afs);
}
-int drbd_khelper(struct drbd_conf *mdev, char *cmd)
+int drbd_khelper(struct drbd_device *device, char *cmd)
{
char *envp[] = { "HOME=/",
"TERM=linux",
@@ -322,39 +333,39 @@ int drbd_khelper(struct drbd_conf *mdev, char *cmd)
NULL };
char mb[12];
char *argv[] = {usermode_helper, cmd, mb, NULL };
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_connection *connection = first_peer_device(device)->connection;
struct sib_info sib;
int ret;
- if (current == tconn->worker.task)
- set_bit(CALLBACK_PENDING, &tconn->flags);
+ if (current == connection->worker.task)
+ set_bit(CALLBACK_PENDING, &connection->flags);
- snprintf(mb, 12, "minor-%d", mdev_to_minor(mdev));
- setup_khelper_env(tconn, envp);
+ snprintf(mb, 12, "minor-%d", device_to_minor(device));
+ setup_khelper_env(connection, envp);
/* The helper may take some time.
* write out any unsynced meta data changes now */
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
- dev_info(DEV, "helper command: %s %s %s\n", usermode_helper, cmd, mb);
+ drbd_info(device, "helper command: %s %s %s\n", usermode_helper, cmd, mb);
sib.sib_reason = SIB_HELPER_PRE;
sib.helper_name = cmd;
- drbd_bcast_event(mdev, &sib);
+ drbd_bcast_event(device, &sib);
ret = call_usermodehelper(usermode_helper, argv, envp, UMH_WAIT_PROC);
if (ret)
- dev_warn(DEV, "helper command: %s %s %s exit code %u (0x%x)\n",
+ drbd_warn(device, "helper command: %s %s %s exit code %u (0x%x)\n",
usermode_helper, cmd, mb,
(ret >> 8) & 0xff, ret);
else
- dev_info(DEV, "helper command: %s %s %s exit code %u (0x%x)\n",
+ drbd_info(device, "helper command: %s %s %s exit code %u (0x%x)\n",
usermode_helper, cmd, mb,
(ret >> 8) & 0xff, ret);
sib.sib_reason = SIB_HELPER_POST;
sib.helper_exit_code = ret;
- drbd_bcast_event(mdev, &sib);
+ drbd_bcast_event(device, &sib);
- if (current == tconn->worker.task)
- clear_bit(CALLBACK_PENDING, &tconn->flags);
+ if (current == connection->worker.task)
+ clear_bit(CALLBACK_PENDING, &connection->flags);
if (ret < 0) /* Ignore any ERRNOs we got. */
ret = 0;
@@ -362,7 +373,7 @@ int drbd_khelper(struct drbd_conf *mdev, char *cmd)
return ret;
}
-int conn_khelper(struct drbd_tconn *tconn, char *cmd)
+static int conn_khelper(struct drbd_connection *connection, char *cmd)
{
char *envp[] = { "HOME=/",
"TERM=linux",
@@ -370,23 +381,24 @@ int conn_khelper(struct drbd_tconn *tconn, char *cmd)
(char[20]) { }, /* address family */
(char[60]) { }, /* address */
NULL };
- char *argv[] = {usermode_helper, cmd, tconn->name, NULL };
+ char *resource_name = connection->resource->name;
+ char *argv[] = {usermode_helper, cmd, resource_name, NULL };
int ret;
- setup_khelper_env(tconn, envp);
- conn_md_sync(tconn);
+ setup_khelper_env(connection, envp);
+ conn_md_sync(connection);
- conn_info(tconn, "helper command: %s %s %s\n", usermode_helper, cmd, tconn->name);
+ drbd_info(connection, "helper command: %s %s %s\n", usermode_helper, cmd, resource_name);
/* TODO: conn_bcast_event() ?? */
ret = call_usermodehelper(usermode_helper, argv, envp, UMH_WAIT_PROC);
if (ret)
- conn_warn(tconn, "helper command: %s %s %s exit code %u (0x%x)\n",
- usermode_helper, cmd, tconn->name,
+ drbd_warn(connection, "helper command: %s %s %s exit code %u (0x%x)\n",
+ usermode_helper, cmd, resource_name,
(ret >> 8) & 0xff, ret);
else
- conn_info(tconn, "helper command: %s %s %s exit code %u (0x%x)\n",
- usermode_helper, cmd, tconn->name,
+ drbd_info(connection, "helper command: %s %s %s exit code %u (0x%x)\n",
+ usermode_helper, cmd, resource_name,
(ret >> 8) & 0xff, ret);
/* TODO: conn_bcast_event() ?? */
@@ -396,18 +408,20 @@ int conn_khelper(struct drbd_tconn *tconn, char *cmd)
return ret;
}
-static enum drbd_fencing_p highest_fencing_policy(struct drbd_tconn *tconn)
+static enum drbd_fencing_p highest_fencing_policy(struct drbd_connection *connection)
{
enum drbd_fencing_p fp = FP_NOT_AVAIL;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- if (get_ldev_if_state(mdev, D_CONSISTENT)) {
- fp = max_t(enum drbd_fencing_p, fp,
- rcu_dereference(mdev->ldev->disk_conf)->fencing);
- put_ldev(mdev);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ if (get_ldev_if_state(device, D_CONSISTENT)) {
+ struct disk_conf *disk_conf =
+ rcu_dereference(peer_device->device->ldev->disk_conf);
+ fp = max_t(enum drbd_fencing_p, fp, disk_conf->fencing);
+ put_ldev(device);
}
}
rcu_read_unlock();
@@ -415,7 +429,7 @@ static enum drbd_fencing_p highest_fencing_policy(struct drbd_tconn *tconn)
return fp;
}
-bool conn_try_outdate_peer(struct drbd_tconn *tconn)
+bool conn_try_outdate_peer(struct drbd_connection *connection)
{
unsigned int connect_cnt;
union drbd_state mask = { };
@@ -424,26 +438,26 @@ bool conn_try_outdate_peer(struct drbd_tconn *tconn)
char *ex_to_string;
int r;
- if (tconn->cstate >= C_WF_REPORT_PARAMS) {
- conn_err(tconn, "Expected cstate < C_WF_REPORT_PARAMS\n");
+ if (connection->cstate >= C_WF_REPORT_PARAMS) {
+ drbd_err(connection, "Expected cstate < C_WF_REPORT_PARAMS\n");
return false;
}
- spin_lock_irq(&tconn->req_lock);
- connect_cnt = tconn->connect_cnt;
- spin_unlock_irq(&tconn->req_lock);
+ spin_lock_irq(&connection->resource->req_lock);
+ connect_cnt = connection->connect_cnt;
+ spin_unlock_irq(&connection->resource->req_lock);
- fp = highest_fencing_policy(tconn);
+ fp = highest_fencing_policy(connection);
switch (fp) {
case FP_NOT_AVAIL:
- conn_warn(tconn, "Not fencing peer, I'm not even Consistent myself.\n");
+ drbd_warn(connection, "Not fencing peer, I'm not even Consistent myself.\n");
goto out;
case FP_DONT_CARE:
return true;
default: ;
}
- r = conn_khelper(tconn, "fence-peer");
+ r = conn_khelper(connection, "fence-peer");
switch ((r>>8) & 0xff) {
case 3: /* peer is inconsistent */
@@ -457,7 +471,7 @@ bool conn_try_outdate_peer(struct drbd_tconn *tconn)
val.pdsk = D_OUTDATED;
break;
case 5: /* peer was down */
- if (conn_highest_disk(tconn) == D_UP_TO_DATE) {
+ if (conn_highest_disk(connection) == D_UP_TO_DATE) {
/* we will(have) create(d) a new UUID anyways... */
ex_to_string = "peer is unreachable, assumed to be dead";
mask.pdsk = D_MASK;
@@ -470,70 +484,70 @@ bool conn_try_outdate_peer(struct drbd_tconn *tconn)
* This is useful when an unconnected R_SECONDARY is asked to
* become R_PRIMARY, but finds the other peer being active. */
ex_to_string = "peer is active";
- conn_warn(tconn, "Peer is primary, outdating myself.\n");
+ drbd_warn(connection, "Peer is primary, outdating myself.\n");
mask.disk = D_MASK;
val.disk = D_OUTDATED;
break;
case 7:
if (fp != FP_STONITH)
- conn_err(tconn, "fence-peer() = 7 && fencing != Stonith !!!\n");
+ drbd_err(connection, "fence-peer() = 7 && fencing != Stonith !!!\n");
ex_to_string = "peer was stonithed";
mask.pdsk = D_MASK;
val.pdsk = D_OUTDATED;
break;
default:
/* The script is broken ... */
- conn_err(tconn, "fence-peer helper broken, returned %d\n", (r>>8)&0xff);
+ drbd_err(connection, "fence-peer helper broken, returned %d\n", (r>>8)&0xff);
return false; /* Eventually leave IO frozen */
}
- conn_info(tconn, "fence-peer helper returned %d (%s)\n",
+ drbd_info(connection, "fence-peer helper returned %d (%s)\n",
(r>>8) & 0xff, ex_to_string);
out:
/* Not using
- conn_request_state(tconn, mask, val, CS_VERBOSE);
+ conn_request_state(connection, mask, val, CS_VERBOSE);
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)) {
- if (tconn->connect_cnt != connect_cnt)
+ spin_lock_irq(&connection->resource->req_lock);
+ if (connection->cstate < C_WF_REPORT_PARAMS && !test_bit(STATE_SENT, &connection->flags)) {
+ if (connection->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");
+ drbd_info(connection, "Ignoring fence-peer exit code\n");
else
- _conn_request_state(tconn, mask, val, CS_VERBOSE);
+ _conn_request_state(connection, mask, val, CS_VERBOSE);
}
- spin_unlock_irq(&tconn->req_lock);
+ spin_unlock_irq(&connection->resource->req_lock);
- return conn_highest_pdsk(tconn) <= D_OUTDATED;
+ return conn_highest_pdsk(connection) <= D_OUTDATED;
}
static int _try_outdate_peer_async(void *data)
{
- struct drbd_tconn *tconn = (struct drbd_tconn *)data;
+ struct drbd_connection *connection = (struct drbd_connection *)data;
- conn_try_outdate_peer(tconn);
+ conn_try_outdate_peer(connection);
- kref_put(&tconn->kref, &conn_destroy);
+ kref_put(&connection->kref, drbd_destroy_connection);
return 0;
}
-void conn_try_outdate_peer_async(struct drbd_tconn *tconn)
+void conn_try_outdate_peer_async(struct drbd_connection *connection)
{
struct task_struct *opa;
- kref_get(&tconn->kref);
- opa = kthread_run(_try_outdate_peer_async, tconn, "drbd_async_h");
+ kref_get(&connection->kref);
+ opa = kthread_run(_try_outdate_peer_async, connection, "drbd_async_h");
if (IS_ERR(opa)) {
- conn_err(tconn, "out of mem, failed to invoke fence-peer helper\n");
- kref_put(&tconn->kref, &conn_destroy);
+ drbd_err(connection, "out of mem, failed to invoke fence-peer helper\n");
+ kref_put(&connection->kref, drbd_destroy_connection);
}
}
enum drbd_state_rv
-drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
+drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force)
{
const int max_tries = 4;
enum drbd_state_rv rv = SS_UNKNOWN_ERROR;
@@ -542,16 +556,24 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
int forced = 0;
union drbd_state mask, val;
- if (new_role == R_PRIMARY)
- request_ping(mdev->tconn); /* Detect a dead peer ASAP */
+ if (new_role == R_PRIMARY) {
+ struct drbd_connection *connection;
- mutex_lock(mdev->state_mutex);
+ /* Detect dead peers as soon as possible. */
+
+ rcu_read_lock();
+ for_each_connection(connection, device->resource)
+ request_ping(connection);
+ rcu_read_unlock();
+ }
+
+ mutex_lock(device->state_mutex);
mask.i = 0; mask.role = R_MASK;
val.i = 0; val.role = new_role;
while (try++ < max_tries) {
- rv = _drbd_request_state(mdev, mask, val, CS_WAIT_COMPLETE);
+ rv = _drbd_request_state(device, mask, val, CS_WAIT_COMPLETE);
/* in case we first succeeded to outdate,
* but now suddenly could establish a connection */
@@ -562,8 +584,8 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
}
if (rv == SS_NO_UP_TO_DATE_DISK && force &&
- (mdev->state.disk < D_UP_TO_DATE &&
- mdev->state.disk >= D_INCONSISTENT)) {
+ (device->state.disk < D_UP_TO_DATE &&
+ device->state.disk >= D_INCONSISTENT)) {
mask.disk = D_MASK;
val.disk = D_UP_TO_DATE;
forced = 1;
@@ -571,10 +593,10 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
}
if (rv == SS_NO_UP_TO_DATE_DISK &&
- mdev->state.disk == D_CONSISTENT && mask.pdsk == 0) {
- D_ASSERT(mdev->state.pdsk == D_UNKNOWN);
+ device->state.disk == D_CONSISTENT && mask.pdsk == 0) {
+ D_ASSERT(device, device->state.pdsk == D_UNKNOWN);
- if (conn_try_outdate_peer(mdev->tconn)) {
+ if (conn_try_outdate_peer(first_peer_device(device)->connection)) {
val.disk = D_UP_TO_DATE;
mask.disk = D_MASK;
}
@@ -584,8 +606,8 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
if (rv == SS_NOTHING_TO_DO)
goto out;
if (rv == SS_PRIMARY_NOP && mask.pdsk == 0) {
- if (!conn_try_outdate_peer(mdev->tconn) && force) {
- dev_warn(DEV, "Forced into split brain situation!\n");
+ if (!conn_try_outdate_peer(first_peer_device(device)->connection) && force) {
+ drbd_warn(device, "Forced into split brain situation!\n");
mask.pdsk = D_MASK;
val.pdsk = D_OUTDATED;
@@ -597,7 +619,7 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
retry at most once more in this case. */
int timeo;
rcu_read_lock();
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
timeo = nc ? (nc->ping_timeo + 1) * HZ / 10 : 1;
rcu_read_unlock();
schedule_timeout_interruptible(timeo);
@@ -606,7 +628,7 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
continue;
}
if (rv < SS_SUCCESS) {
- rv = _drbd_request_state(mdev, mask, val,
+ rv = _drbd_request_state(device, mask, val,
CS_VERBOSE + CS_WAIT_COMPLETE);
if (rv < SS_SUCCESS)
goto out;
@@ -618,53 +640,53 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
goto out;
if (forced)
- dev_warn(DEV, "Forced to consider local data as UpToDate!\n");
+ drbd_warn(device, "Forced to consider local data as UpToDate!\n");
/* Wait until nothing is on the fly :) */
- wait_event(mdev->misc_wait, atomic_read(&mdev->ap_pending_cnt) == 0);
+ wait_event(device->misc_wait, atomic_read(&device->ap_pending_cnt) == 0);
/* FIXME also wait for all pending P_BARRIER_ACK? */
if (new_role == R_SECONDARY) {
- set_disk_ro(mdev->vdisk, true);
- if (get_ldev(mdev)) {
- mdev->ldev->md.uuid[UI_CURRENT] &= ~(u64)1;
- put_ldev(mdev);
+ set_disk_ro(device->vdisk, true);
+ if (get_ldev(device)) {
+ device->ldev->md.uuid[UI_CURRENT] &= ~(u64)1;
+ put_ldev(device);
}
} else {
- mutex_lock(&mdev->tconn->conf_update);
- nc = mdev->tconn->net_conf;
+ mutex_lock(&device->resource->conf_update);
+ nc = first_peer_device(device)->connection->net_conf;
if (nc)
nc->discard_my_data = 0; /* without copy; single bit op is atomic */
- mutex_unlock(&mdev->tconn->conf_update);
+ mutex_unlock(&device->resource->conf_update);
- set_disk_ro(mdev->vdisk, false);
- if (get_ldev(mdev)) {
- if (((mdev->state.conn < C_CONNECTED ||
- mdev->state.pdsk <= D_FAILED)
- && mdev->ldev->md.uuid[UI_BITMAP] == 0) || forced)
- drbd_uuid_new_current(mdev);
+ set_disk_ro(device->vdisk, false);
+ if (get_ldev(device)) {
+ if (((device->state.conn < C_CONNECTED ||
+ device->state.pdsk <= D_FAILED)
+ && device->ldev->md.uuid[UI_BITMAP] == 0) || forced)
+ drbd_uuid_new_current(device);
- mdev->ldev->md.uuid[UI_CURRENT] |= (u64)1;
- put_ldev(mdev);
+ device->ldev->md.uuid[UI_CURRENT] |= (u64)1;
+ put_ldev(device);
}
}
/* writeout of activity log covered areas of the bitmap
* to stable storage done in after state change already */
- if (mdev->state.conn >= C_WF_REPORT_PARAMS) {
+ if (device->state.conn >= C_WF_REPORT_PARAMS) {
/* if this was forced, we should consider sync */
if (forced)
- drbd_send_uuids(mdev);
- drbd_send_current_state(mdev);
+ drbd_send_uuids(first_peer_device(device));
+ drbd_send_current_state(first_peer_device(device));
}
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
- kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE);
+ kobject_uevent(&disk_to_dev(device->vdisk)->kobj, KOBJ_CHANGE);
out:
- mutex_unlock(mdev->state_mutex);
+ mutex_unlock(device->state_mutex);
return rv;
}
@@ -699,9 +721,9 @@ int drbd_adm_set_role(struct sk_buff *skb, struct genl_info *info)
}
if (info->genlhdr->cmd == DRBD_ADM_PRIMARY)
- retcode = drbd_set_role(adm_ctx.mdev, R_PRIMARY, parms.assume_uptodate);
+ retcode = drbd_set_role(adm_ctx.device, R_PRIMARY, parms.assume_uptodate);
else
- retcode = drbd_set_role(adm_ctx.mdev, R_SECONDARY, 0);
+ retcode = drbd_set_role(adm_ctx.device, R_SECONDARY, 0);
out:
drbd_adm_finish(info, retcode);
return 0;
@@ -728,7 +750,7 @@ out:
* Activity log size used to be fixed 32kB,
* but is about to become configurable.
*/
-static void drbd_md_set_sector_offsets(struct drbd_conf *mdev,
+static void drbd_md_set_sector_offsets(struct drbd_device *device,
struct drbd_backing_dev *bdev)
{
sector_t md_size_sect = 0;
@@ -804,35 +826,35 @@ char *ppsize(char *buf, unsigned long long size)
* drbd_adm_suspend_io/drbd_adm_resume_io,
* which are (sub) state changes triggered by admin (drbdsetup),
* and can be long lived.
- * This changes an mdev->flag, is triggered by drbd internals,
+ * This changes an device->flag, is triggered by drbd internals,
* and should be short-lived. */
-void drbd_suspend_io(struct drbd_conf *mdev)
+void drbd_suspend_io(struct drbd_device *device)
{
- set_bit(SUSPEND_IO, &mdev->flags);
- if (drbd_suspended(mdev))
+ set_bit(SUSPEND_IO, &device->flags);
+ if (drbd_suspended(device))
return;
- wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt));
+ wait_event(device->misc_wait, !atomic_read(&device->ap_bio_cnt));
}
-void drbd_resume_io(struct drbd_conf *mdev)
+void drbd_resume_io(struct drbd_device *device)
{
- clear_bit(SUSPEND_IO, &mdev->flags);
- wake_up(&mdev->misc_wait);
+ clear_bit(SUSPEND_IO, &device->flags);
+ wake_up(&device->misc_wait);
}
/**
* drbd_determine_dev_size() - Sets the right device size obeying all constraints
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* 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, struct resize_parms *rs) __must_hold(local)
+drbd_determine_dev_size(struct drbd_device *device, 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;
+ struct drbd_md *md = &device->ldev->md;
u32 prev_al_stripe_size_4k;
u32 prev_al_stripes;
sector_t size;
@@ -851,19 +873,19 @@ drbd_determine_dev_size(struct drbd_conf *mdev, enum dds_flags flags, struct res
* Suspend IO right here.
* still lock the act_log to not trigger ASSERTs there.
*/
- drbd_suspend_io(mdev);
- buffer = drbd_md_get_buffer(mdev); /* Lock meta-data IO */
+ drbd_suspend_io(device);
+ buffer = drbd_md_get_buffer(device); /* Lock meta-data IO */
if (!buffer) {
- drbd_resume_io(mdev);
+ drbd_resume_io(device);
return DS_ERROR;
}
/* no wait necessary anymore, actually we could assert that */
- wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
+ wait_event(device->al_wait, lc_try_lock(device->act_log));
- prev_first_sect = drbd_md_first_sector(mdev->ldev);
- prev_size = mdev->ldev->md.md_size_sect;
- la_size_sect = mdev->ldev->md.la_size_sect;
+ prev_first_sect = drbd_md_first_sector(device->ldev);
+ prev_size = device->ldev->md.md_size_sect;
+ la_size_sect = device->ldev->md.la_size_sect;
if (rs) {
/* rs is non NULL if we should change the AL layout only */
@@ -876,18 +898,18 @@ drbd_determine_dev_size(struct drbd_conf *mdev, enum dds_flags flags, struct res
md->al_size_4k = (u64)rs->al_stripes * rs->al_stripe_size / 4;
}
- drbd_md_set_sector_offsets(mdev, mdev->ldev);
+ drbd_md_set_sector_offsets(device, device->ldev);
rcu_read_lock();
- u_size = rcu_dereference(mdev->ldev->disk_conf)->disk_size;
+ u_size = rcu_dereference(device->ldev->disk_conf)->disk_size;
rcu_read_unlock();
- size = drbd_new_dev_size(mdev, mdev->ldev, u_size, flags & DDSF_FORCED);
+ size = drbd_new_dev_size(device, device->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. "
+ drbd_warn(device, "Implicit shrink not allowed. "
"Use --size=%llus for explicit shrink.\n",
(unsigned long long)size);
rv = DS_ERROR_SHRINK;
@@ -898,60 +920,60 @@ drbd_determine_dev_size(struct drbd_conf *mdev, enum dds_flags flags, struct res
goto err_out;
}
- if (drbd_get_capacity(mdev->this_bdev) != size ||
- drbd_bm_capacity(mdev) != size) {
+ if (drbd_get_capacity(device->this_bdev) != size ||
+ drbd_bm_capacity(device) != size) {
int err;
- err = drbd_bm_resize(mdev, size, !(flags & DDSF_NO_RESYNC));
+ err = drbd_bm_resize(device, size, !(flags & DDSF_NO_RESYNC));
if (unlikely(err)) {
/* currently there is only one error: ENOMEM! */
- size = drbd_bm_capacity(mdev)>>1;
+ size = drbd_bm_capacity(device)>>1;
if (size == 0) {
- dev_err(DEV, "OUT OF MEMORY! "
+ drbd_err(device, "OUT OF MEMORY! "
"Could not allocate bitmap!\n");
} else {
- dev_err(DEV, "BM resizing failed. "
+ drbd_err(device, "BM resizing failed. "
"Leaving size unchanged at size = %lu KB\n",
(unsigned long)size);
}
rv = DS_ERROR;
}
/* racy, see comments above. */
- drbd_set_my_capacity(mdev, size);
- mdev->ldev->md.la_size_sect = size;
- dev_info(DEV, "size = %s (%llu KB)\n", ppsize(ppb, size>>1),
+ drbd_set_my_capacity(device, size);
+ device->ldev->md.la_size_sect = size;
+ drbd_info(device, "size = %s (%llu KB)\n", ppsize(ppb, size>>1),
(unsigned long long)size>>1);
}
if (rv <= DS_ERROR)
goto err_out;
- la_size_changed = (la_size_sect != mdev->ldev->md.la_size_sect);
+ la_size_changed = (la_size_sect != device->ldev->md.la_size_sect);
- md_moved = prev_first_sect != drbd_md_first_sector(mdev->ldev)
- || prev_size != mdev->ldev->md.md_size_sect;
+ md_moved = prev_first_sect != drbd_md_first_sector(device->ldev)
+ || prev_size != device->ldev->md.md_size_sect;
if (la_size_changed || md_moved || rs) {
u32 prev_flags;
- drbd_al_shrink(mdev); /* All extents inactive. */
+ drbd_al_shrink(device); /* All extents inactive. */
prev_flags = md->flags;
md->flags &= ~MDF_PRIMARY_IND;
- drbd_md_write(mdev, buffer);
+ drbd_md_write(device, buffer);
- dev_info(DEV, "Writing the whole bitmap, %s\n",
+ drbd_info(device, "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() */
- drbd_bitmap_io(mdev, md_moved ? &drbd_bm_write_all : &drbd_bm_write,
+ drbd_bitmap_io(device, md_moved ? &drbd_bm_write_all : &drbd_bm_write,
"size changed", BM_LOCKED_MASK);
- drbd_initialize_al(mdev, buffer);
+ drbd_initialize_al(device, buffer);
md->flags = prev_flags;
- drbd_md_write(mdev, buffer);
+ drbd_md_write(device, 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);
+ drbd_info(device, "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)
@@ -966,30 +988,30 @@ drbd_determine_dev_size(struct drbd_conf *mdev, enum dds_flags flags, struct res
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);
+ drbd_md_set_sector_offsets(device, device->ldev);
}
}
- lc_unlock(mdev->act_log);
- wake_up(&mdev->al_wait);
- drbd_md_put_buffer(mdev);
- drbd_resume_io(mdev);
+ lc_unlock(device->act_log);
+ wake_up(&device->al_wait);
+ drbd_md_put_buffer(device);
+ drbd_resume_io(device);
return rv;
}
sector_t
-drbd_new_dev_size(struct drbd_conf *mdev, struct drbd_backing_dev *bdev,
+drbd_new_dev_size(struct drbd_device *device, struct drbd_backing_dev *bdev,
sector_t u_size, int assume_peer_has_space)
{
- sector_t p_size = mdev->p_size; /* partner's disk size. */
+ sector_t p_size = device->p_size; /* partner's disk size. */
sector_t la_size_sect = bdev->md.la_size_sect; /* last agreed size. */
sector_t m_size; /* my size */
sector_t size = 0;
m_size = drbd_get_max_capacity(bdev);
- if (mdev->state.conn < C_CONNECTED && assume_peer_has_space) {
- dev_warn(DEV, "Resize while not connected was forced by the user!\n");
+ if (device->state.conn < C_CONNECTED && assume_peer_has_space) {
+ drbd_warn(device, "Resize while not connected was forced by the user!\n");
p_size = m_size;
}
@@ -1011,11 +1033,11 @@ drbd_new_dev_size(struct drbd_conf *mdev, struct drbd_backing_dev *bdev,
}
if (size == 0)
- dev_err(DEV, "Both nodes diskless!\n");
+ drbd_err(device, "Both nodes diskless!\n");
if (u_size) {
if (u_size > size)
- dev_err(DEV, "Requested disk size is too big (%lu > %lu)\n",
+ drbd_err(device, "Requested disk size is too big (%lu > %lu)\n",
(unsigned long)u_size>>1, (unsigned long)size>>1);
else
size = u_size;
@@ -1026,71 +1048,71 @@ drbd_new_dev_size(struct drbd_conf *mdev, struct drbd_backing_dev *bdev,
/**
* drbd_check_al_size() - Ensures that the AL is of the right size
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Returns -EBUSY if current al lru is still used, -ENOMEM when allocation
* failed, and 0 on success. You should call drbd_md_sync() after you called
* this function.
*/
-static int drbd_check_al_size(struct drbd_conf *mdev, struct disk_conf *dc)
+static int drbd_check_al_size(struct drbd_device *device, struct disk_conf *dc)
{
struct lru_cache *n, *t;
struct lc_element *e;
unsigned int in_use;
int i;
- if (mdev->act_log &&
- mdev->act_log->nr_elements == dc->al_extents)
+ if (device->act_log &&
+ device->act_log->nr_elements == dc->al_extents)
return 0;
in_use = 0;
- t = mdev->act_log;
+ t = device->act_log;
n = lc_create("act_log", drbd_al_ext_cache, AL_UPDATES_PER_TRANSACTION,
dc->al_extents, sizeof(struct lc_element), 0);
if (n == NULL) {
- dev_err(DEV, "Cannot allocate act_log lru!\n");
+ drbd_err(device, "Cannot allocate act_log lru!\n");
return -ENOMEM;
}
- spin_lock_irq(&mdev->al_lock);
+ spin_lock_irq(&device->al_lock);
if (t) {
for (i = 0; i < t->nr_elements; i++) {
e = lc_element_by_index(t, i);
if (e->refcnt)
- dev_err(DEV, "refcnt(%d)==%d\n",
+ drbd_err(device, "refcnt(%d)==%d\n",
e->lc_number, e->refcnt);
in_use += e->refcnt;
}
}
if (!in_use)
- mdev->act_log = n;
- spin_unlock_irq(&mdev->al_lock);
+ device->act_log = n;
+ spin_unlock_irq(&device->al_lock);
if (in_use) {
- dev_err(DEV, "Activity log still in use!\n");
+ drbd_err(device, "Activity log still in use!\n");
lc_destroy(n);
return -EBUSY;
} else {
if (t)
lc_destroy(t);
}
- drbd_md_mark_dirty(mdev); /* we changed mdev->act_log->nr_elemens */
+ drbd_md_mark_dirty(device); /* we changed device->act_log->nr_elemens */
return 0;
}
-static void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_bio_size)
+static void drbd_setup_queue_param(struct drbd_device *device, unsigned int max_bio_size)
{
- struct request_queue * const q = mdev->rq_queue;
+ struct request_queue * const q = device->rq_queue;
unsigned int max_hw_sectors = max_bio_size >> 9;
unsigned int max_segments = 0;
- if (get_ldev_if_state(mdev, D_ATTACHING)) {
- struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue;
+ if (get_ldev_if_state(device, D_ATTACHING)) {
+ struct request_queue * const b = device->ldev->backing_bdev->bd_disk->queue;
max_hw_sectors = min(queue_max_hw_sectors(b), max_bio_size >> 9);
rcu_read_lock();
- max_segments = rcu_dereference(mdev->ldev->disk_conf)->max_bio_bvecs;
+ max_segments = rcu_dereference(device->ldev->disk_conf)->max_bio_bvecs;
rcu_read_unlock();
- put_ldev(mdev);
+ put_ldev(device);
}
blk_queue_logical_block_size(q, 512);
@@ -1099,46 +1121,46 @@ static void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_bio_
blk_queue_max_segments(q, max_segments ? max_segments : BLK_MAX_SEGMENTS);
blk_queue_segment_boundary(q, PAGE_CACHE_SIZE-1);
- if (get_ldev_if_state(mdev, D_ATTACHING)) {
- struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue;
+ if (get_ldev_if_state(device, D_ATTACHING)) {
+ struct request_queue * const b = device->ldev->backing_bdev->bd_disk->queue;
blk_queue_stack_limits(q, b);
if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) {
- dev_info(DEV, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n",
+ drbd_info(device, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n",
q->backing_dev_info.ra_pages,
b->backing_dev_info.ra_pages);
q->backing_dev_info.ra_pages = b->backing_dev_info.ra_pages;
}
- put_ldev(mdev);
+ put_ldev(device);
}
}
-void drbd_reconsider_max_bio_size(struct drbd_conf *mdev)
+void drbd_reconsider_max_bio_size(struct drbd_device *device)
{
unsigned int now, new, local, peer;
- now = queue_max_hw_sectors(mdev->rq_queue) << 9;
- local = mdev->local_max_bio_size; /* Eventually last known value, from volatile memory */
- peer = mdev->peer_max_bio_size; /* Eventually last known value, from meta data */
+ now = queue_max_hw_sectors(device->rq_queue) << 9;
+ local = device->local_max_bio_size; /* Eventually last known value, from volatile memory */
+ peer = device->peer_max_bio_size; /* Eventually last known value, from meta data */
- if (get_ldev_if_state(mdev, D_ATTACHING)) {
- local = queue_max_hw_sectors(mdev->ldev->backing_bdev->bd_disk->queue) << 9;
- mdev->local_max_bio_size = local;
- put_ldev(mdev);
+ if (get_ldev_if_state(device, D_ATTACHING)) {
+ local = queue_max_hw_sectors(device->ldev->backing_bdev->bd_disk->queue) << 9;
+ device->local_max_bio_size = local;
+ put_ldev(device);
}
local = min(local, DRBD_MAX_BIO_SIZE);
/* We may ignore peer limits if the peer is modern enough.
Because new from 8.3.8 onwards the peer can use multiple
BIOs for a single peer_request */
- if (mdev->state.conn >= C_WF_REPORT_PARAMS) {
- if (mdev->tconn->agreed_pro_version < 94)
- peer = min(mdev->peer_max_bio_size, DRBD_MAX_SIZE_H80_PACKET);
+ if (device->state.conn >= C_WF_REPORT_PARAMS) {
+ if (first_peer_device(device)->connection->agreed_pro_version < 94)
+ peer = min(device->peer_max_bio_size, DRBD_MAX_SIZE_H80_PACKET);
/* Correct old drbd (up to 8.3.7) if it believes it can do more than 32KiB */
- else if (mdev->tconn->agreed_pro_version == 94)
+ else if (first_peer_device(device)->connection->agreed_pro_version == 94)
peer = DRBD_MAX_SIZE_H80_PACKET;
- else if (mdev->tconn->agreed_pro_version < 100)
+ else if (first_peer_device(device)->connection->agreed_pro_version < 100)
peer = DRBD_MAX_BIO_SIZE_P95; /* drbd 8.3.8 onwards, before 8.4.0 */
else
peer = DRBD_MAX_BIO_SIZE;
@@ -1146,57 +1168,57 @@ void drbd_reconsider_max_bio_size(struct drbd_conf *mdev)
new = min(local, peer);
- if (mdev->state.role == R_PRIMARY && new < now)
- dev_err(DEV, "ASSERT FAILED new < now; (%u < %u)\n", new, now);
+ if (device->state.role == R_PRIMARY && new < now)
+ drbd_err(device, "ASSERT FAILED new < now; (%u < %u)\n", new, now);
if (new != now)
- dev_info(DEV, "max BIO size = %u\n", new);
+ drbd_info(device, "max BIO size = %u\n", new);
- drbd_setup_queue_param(mdev, new);
+ drbd_setup_queue_param(device, new);
}
/* Starts the worker thread */
-static void conn_reconfig_start(struct drbd_tconn *tconn)
+static void conn_reconfig_start(struct drbd_connection *connection)
{
- drbd_thread_start(&tconn->worker);
- conn_flush_workqueue(tconn);
+ drbd_thread_start(&connection->worker);
+ drbd_flush_workqueue(&connection->sender_work);
}
/* if still unconfigured, stops worker again. */
-static void conn_reconfig_done(struct drbd_tconn *tconn)
+static void conn_reconfig_done(struct drbd_connection *connection)
{
bool stop_threads;
- spin_lock_irq(&tconn->req_lock);
- stop_threads = conn_all_vols_unconf(tconn) &&
- tconn->cstate == C_STANDALONE;
- spin_unlock_irq(&tconn->req_lock);
+ spin_lock_irq(&connection->resource->req_lock);
+ stop_threads = conn_all_vols_unconf(connection) &&
+ connection->cstate == C_STANDALONE;
+ spin_unlock_irq(&connection->resource->req_lock);
if (stop_threads) {
/* asender is implicitly stopped by receiver
* in conn_disconnect() */
- drbd_thread_stop(&tconn->receiver);
- drbd_thread_stop(&tconn->worker);
+ drbd_thread_stop(&connection->receiver);
+ drbd_thread_stop(&connection->worker);
}
}
/* Make sure IO is suspended before calling this function(). */
-static void drbd_suspend_al(struct drbd_conf *mdev)
+static void drbd_suspend_al(struct drbd_device *device)
{
int s = 0;
- if (!lc_try_lock(mdev->act_log)) {
- dev_warn(DEV, "Failed to lock al in drbd_suspend_al()\n");
+ if (!lc_try_lock(device->act_log)) {
+ drbd_warn(device, "Failed to lock al in drbd_suspend_al()\n");
return;
}
- drbd_al_shrink(mdev);
- spin_lock_irq(&mdev->tconn->req_lock);
- if (mdev->state.conn < C_CONNECTED)
- s = !test_and_set_bit(AL_SUSPENDED, &mdev->flags);
- spin_unlock_irq(&mdev->tconn->req_lock);
- lc_unlock(mdev->act_log);
+ drbd_al_shrink(device);
+ spin_lock_irq(&device->resource->req_lock);
+ if (device->state.conn < C_CONNECTED)
+ s = !test_and_set_bit(AL_SUSPENDED, &device->flags);
+ spin_unlock_irq(&device->resource->req_lock);
+ lc_unlock(device->act_log);
if (s)
- dev_info(DEV, "Suspended AL updates\n");
+ drbd_info(device, "Suspended AL updates\n");
}
@@ -1237,7 +1259,7 @@ static unsigned int drbd_al_extents_max(struct drbd_backing_dev *bdev)
int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
{
enum drbd_ret_code retcode;
- struct drbd_conf *mdev;
+ struct drbd_device *device;
struct disk_conf *new_disk_conf, *old_disk_conf;
struct fifo_buffer *old_plan = NULL, *new_plan = NULL;
int err, fifo_size;
@@ -1248,11 +1270,11 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- mdev = adm_ctx.mdev;
+ device = adm_ctx.device;
/* we also need a disk
* to change the options on */
- if (!get_ldev(mdev)) {
+ if (!get_ldev(device)) {
retcode = ERR_NO_DISK;
goto out;
}
@@ -1263,8 +1285,8 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
goto fail;
}
- mutex_lock(&mdev->tconn->conf_update);
- old_disk_conf = mdev->ldev->disk_conf;
+ mutex_lock(&device->resource->conf_update);
+ old_disk_conf = device->ldev->disk_conf;
*new_disk_conf = *old_disk_conf;
if (should_set_defaults(info))
set_disk_conf_defaults(new_disk_conf);
@@ -1273,6 +1295,7 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
if (err && err != -ENOMSG) {
retcode = ERR_MANDATORY_TAG;
drbd_msg_put_info(from_attrs_err_to_txt(err));
+ goto fail_unlock;
}
if (!expect(new_disk_conf->resync_rate >= 1))
@@ -1280,29 +1303,29 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
if (new_disk_conf->al_extents < DRBD_AL_EXTENTS_MIN)
new_disk_conf->al_extents = DRBD_AL_EXTENTS_MIN;
- if (new_disk_conf->al_extents > drbd_al_extents_max(mdev->ldev))
- new_disk_conf->al_extents = drbd_al_extents_max(mdev->ldev);
+ if (new_disk_conf->al_extents > drbd_al_extents_max(device->ldev))
+ new_disk_conf->al_extents = drbd_al_extents_max(device->ldev);
if (new_disk_conf->c_plan_ahead > DRBD_C_PLAN_AHEAD_MAX)
new_disk_conf->c_plan_ahead = DRBD_C_PLAN_AHEAD_MAX;
fifo_size = (new_disk_conf->c_plan_ahead * 10 * SLEEP_TIME) / HZ;
- if (fifo_size != mdev->rs_plan_s->size) {
+ if (fifo_size != device->rs_plan_s->size) {
new_plan = fifo_alloc(fifo_size);
if (!new_plan) {
- dev_err(DEV, "kmalloc of fifo_buffer failed");
+ drbd_err(device, "kmalloc of fifo_buffer failed");
retcode = ERR_NOMEM;
goto fail_unlock;
}
}
- drbd_suspend_io(mdev);
- wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
- drbd_al_shrink(mdev);
- err = drbd_check_al_size(mdev, new_disk_conf);
- lc_unlock(mdev->act_log);
- wake_up(&mdev->al_wait);
- drbd_resume_io(mdev);
+ drbd_suspend_io(device);
+ wait_event(device->al_wait, lc_try_lock(device->act_log));
+ drbd_al_shrink(device);
+ err = drbd_check_al_size(device, new_disk_conf);
+ lc_unlock(device->act_log);
+ wake_up(&device->al_wait);
+ drbd_resume_io(device);
if (err) {
retcode = ERR_NOMEM;
@@ -1310,10 +1333,10 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
}
write_lock_irq(&global_state_lock);
- retcode = drbd_resync_after_valid(mdev, new_disk_conf->resync_after);
+ retcode = drbd_resync_after_valid(device, new_disk_conf->resync_after);
if (retcode == NO_ERROR) {
- rcu_assign_pointer(mdev->ldev->disk_conf, new_disk_conf);
- drbd_resync_after_changed(mdev);
+ rcu_assign_pointer(device->ldev->disk_conf, new_disk_conf);
+ drbd_resync_after_changed(device);
}
write_unlock_irq(&global_state_lock);
@@ -1321,42 +1344,46 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
goto fail_unlock;
if (new_plan) {
- old_plan = mdev->rs_plan_s;
- rcu_assign_pointer(mdev->rs_plan_s, new_plan);
+ old_plan = device->rs_plan_s;
+ rcu_assign_pointer(device->rs_plan_s, new_plan);
}
- mutex_unlock(&mdev->tconn->conf_update);
+ mutex_unlock(&device->resource->conf_update);
if (new_disk_conf->al_updates)
- mdev->ldev->md.flags &= ~MDF_AL_DISABLED;
+ device->ldev->md.flags &= ~MDF_AL_DISABLED;
else
- mdev->ldev->md.flags |= MDF_AL_DISABLED;
+ device->ldev->md.flags |= MDF_AL_DISABLED;
if (new_disk_conf->md_flushes)
- clear_bit(MD_NO_FUA, &mdev->flags);
+ clear_bit(MD_NO_FUA, &device->flags);
else
- set_bit(MD_NO_FUA, &mdev->flags);
+ set_bit(MD_NO_FUA, &device->flags);
- drbd_bump_write_ordering(mdev->tconn, WO_bdev_flush);
+ drbd_bump_write_ordering(first_peer_device(device)->connection, WO_bdev_flush);
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
- if (mdev->state.conn >= C_CONNECTED)
- drbd_send_sync_param(mdev);
+ if (device->state.conn >= C_CONNECTED) {
+ struct drbd_peer_device *peer_device;
+
+ for_each_peer_device(peer_device, device)
+ drbd_send_sync_param(peer_device);
+ }
synchronize_rcu();
kfree(old_disk_conf);
kfree(old_plan);
- mod_timer(&mdev->request_timer, jiffies + HZ);
+ mod_timer(&device->request_timer, jiffies + HZ);
goto success;
fail_unlock:
- mutex_unlock(&mdev->tconn->conf_update);
+ mutex_unlock(&device->resource->conf_update);
fail:
kfree(new_disk_conf);
kfree(new_plan);
success:
- put_ldev(mdev);
+ put_ldev(device);
out:
drbd_adm_finish(info, retcode);
return 0;
@@ -1364,7 +1391,7 @@ success:
int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
{
- struct drbd_conf *mdev;
+ struct drbd_device *device;
int err;
enum drbd_ret_code retcode;
enum determine_dev_size dd;
@@ -1385,11 +1412,11 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto finish;
- mdev = adm_ctx.mdev;
- conn_reconfig_start(mdev->tconn);
+ device = adm_ctx.device;
+ conn_reconfig_start(first_peer_device(device)->connection);
/* if you want to reconfigure, please tear down first */
- if (mdev->state.disk > D_DISKLESS) {
+ if (device->state.disk > D_DISKLESS) {
retcode = ERR_DISK_CONFIGURED;
goto fail;
}
@@ -1397,17 +1424,17 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
* drbd_ldev_destroy is done already, we may end up here very fast,
* e.g. if someone calls attach from the on-io-error handler,
* to realize a "hot spare" feature (not that I'd recommend that) */
- wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
+ wait_event(device->misc_wait, !atomic_read(&device->local_cnt));
/* make sure there is no leftover from previous force-detach attempts */
- clear_bit(FORCE_DETACH, &mdev->flags);
- clear_bit(WAS_IO_ERROR, &mdev->flags);
- clear_bit(WAS_READ_ERROR, &mdev->flags);
+ clear_bit(FORCE_DETACH, &device->flags);
+ clear_bit(WAS_IO_ERROR, &device->flags);
+ clear_bit(WAS_READ_ERROR, &device->flags);
/* and no leftover from previously aborted resync or verify, either */
- mdev->rs_total = 0;
- mdev->rs_failed = 0;
- atomic_set(&mdev->rs_pending_cnt, 0);
+ device->rs_total = 0;
+ device->rs_failed = 0;
+ atomic_set(&device->rs_pending_cnt, 0);
/* allocation not in the IO path, drbdsetup context */
nbc = kzalloc(sizeof(struct drbd_backing_dev), GFP_KERNEL);
@@ -1447,13 +1474,13 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
}
write_lock_irq(&global_state_lock);
- retcode = drbd_resync_after_valid(mdev, new_disk_conf->resync_after);
+ retcode = drbd_resync_after_valid(device, new_disk_conf->resync_after);
write_unlock_irq(&global_state_lock);
if (retcode != NO_ERROR)
goto fail;
rcu_read_lock();
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
if (nc) {
if (new_disk_conf->fencing == FP_STONITH && nc->wire_protocol == DRBD_PROT_A) {
rcu_read_unlock();
@@ -1464,9 +1491,9 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
rcu_read_unlock();
bdev = blkdev_get_by_path(new_disk_conf->backing_dev,
- FMODE_READ | FMODE_WRITE | FMODE_EXCL, mdev);
+ FMODE_READ | FMODE_WRITE | FMODE_EXCL, device);
if (IS_ERR(bdev)) {
- dev_err(DEV, "open(\"%s\") failed with %ld\n", new_disk_conf->backing_dev,
+ drbd_err(device, "open(\"%s\") failed with %ld\n", new_disk_conf->backing_dev,
PTR_ERR(bdev));
retcode = ERR_OPEN_DISK;
goto fail;
@@ -1484,9 +1511,9 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
bdev = blkdev_get_by_path(new_disk_conf->meta_dev,
FMODE_READ | FMODE_WRITE | FMODE_EXCL,
(new_disk_conf->meta_dev_idx < 0) ?
- (void *)mdev : (void *)drbd_m_holder);
+ (void *)device : (void *)drbd_m_holder);
if (IS_ERR(bdev)) {
- dev_err(DEV, "open(\"%s\") failed with %ld\n", new_disk_conf->meta_dev,
+ drbd_err(device, "open(\"%s\") failed with %ld\n", new_disk_conf->meta_dev,
PTR_ERR(bdev));
retcode = ERR_OPEN_MD_DISK;
goto fail;
@@ -1510,7 +1537,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
/* Read our meta data super block early.
* This also sets other on-disk offsets. */
- retcode = drbd_md_read(mdev, nbc);
+ retcode = drbd_md_read(device, nbc);
if (retcode != NO_ERROR)
goto fail;
@@ -1520,7 +1547,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
new_disk_conf->al_extents = drbd_al_extents_max(nbc);
if (drbd_get_max_capacity(nbc) < new_disk_conf->disk_size) {
- dev_err(DEV, "max capacity %llu smaller than disk size %llu\n",
+ drbd_err(device, "max capacity %llu smaller than disk size %llu\n",
(unsigned long long) drbd_get_max_capacity(nbc),
(unsigned long long) new_disk_conf->disk_size);
retcode = ERR_DISK_TOO_SMALL;
@@ -1538,7 +1565,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
if (drbd_get_capacity(nbc->md_bdev) < min_md_device_sectors) {
retcode = ERR_MD_DISK_TOO_SMALL;
- dev_warn(DEV, "refusing attach: md-device too small, "
+ drbd_warn(device, "refusing attach: md-device too small, "
"at least %llu sectors needed for this meta-disk type\n",
(unsigned long long) min_md_device_sectors);
goto fail;
@@ -1547,7 +1574,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
/* Make sure the new disk is big enough
* (we may currently be R_PRIMARY with no local disk...) */
if (drbd_get_max_capacity(nbc) <
- drbd_get_capacity(mdev->this_bdev)) {
+ drbd_get_capacity(device->this_bdev)) {
retcode = ERR_DISK_TOO_SMALL;
goto fail;
}
@@ -1555,15 +1582,15 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
nbc->known_size = drbd_get_capacity(nbc->backing_bdev);
if (nbc->known_size > max_possible_sectors) {
- dev_warn(DEV, "==> truncating very big lower level device "
+ drbd_warn(device, "==> truncating very big lower level device "
"to currently maximum possible %llu sectors <==\n",
(unsigned long long) max_possible_sectors);
if (new_disk_conf->meta_dev_idx >= 0)
- dev_warn(DEV, "==>> using internal or flexible "
+ drbd_warn(device, "==>> using internal or flexible "
"meta data may help <<==\n");
}
- drbd_suspend_io(mdev);
+ drbd_suspend_io(device);
/* also wait for the last barrier ack. */
/* FIXME see also https://daiquiri.linbit/cgi-bin/bugzilla/show_bug.cgi?id=171
* We need a way to either ignore barrier acks for barriers sent before a device
@@ -1571,45 +1598,45 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
* As barriers are counted per resource,
* we'd need to suspend io on all devices of a resource.
*/
- wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_pending_cnt) || drbd_suspended(mdev));
+ wait_event(device->misc_wait, !atomic_read(&device->ap_pending_cnt) || drbd_suspended(device));
/* and for any other previously queued work */
- drbd_flush_workqueue(mdev);
+ drbd_flush_workqueue(&first_peer_device(device)->connection->sender_work);
- rv = _drbd_request_state(mdev, NS(disk, D_ATTACHING), CS_VERBOSE);
+ rv = _drbd_request_state(device, NS(disk, D_ATTACHING), CS_VERBOSE);
retcode = rv; /* FIXME: Type mismatch. */
- drbd_resume_io(mdev);
+ drbd_resume_io(device);
if (rv < SS_SUCCESS)
goto fail;
- if (!get_ldev_if_state(mdev, D_ATTACHING))
+ if (!get_ldev_if_state(device, D_ATTACHING))
goto force_diskless;
- if (!mdev->bitmap) {
- if (drbd_bm_init(mdev)) {
+ if (!device->bitmap) {
+ if (drbd_bm_init(device)) {
retcode = ERR_NOMEM;
goto force_diskless_dec;
}
}
- if (mdev->state.conn < C_CONNECTED &&
- mdev->state.role == R_PRIMARY &&
- (mdev->ed_uuid & ~((u64)1)) != (nbc->md.uuid[UI_CURRENT] & ~((u64)1))) {
- dev_err(DEV, "Can only attach to data with current UUID=%016llX\n",
- (unsigned long long)mdev->ed_uuid);
+ if (device->state.conn < C_CONNECTED &&
+ device->state.role == R_PRIMARY &&
+ (device->ed_uuid & ~((u64)1)) != (nbc->md.uuid[UI_CURRENT] & ~((u64)1))) {
+ drbd_err(device, "Can only attach to data with current UUID=%016llX\n",
+ (unsigned long long)device->ed_uuid);
retcode = ERR_DATA_NOT_CURRENT;
goto force_diskless_dec;
}
/* Since we are diskless, fix the activity log first... */
- if (drbd_check_al_size(mdev, new_disk_conf)) {
+ if (drbd_check_al_size(device, new_disk_conf)) {
retcode = ERR_NOMEM;
goto force_diskless_dec;
}
/* Prevent shrinking of consistent devices ! */
if (drbd_md_test_flag(nbc, MDF_CONSISTENT) &&
- drbd_new_dev_size(mdev, nbc, nbc->disk_conf->disk_size, 0) < nbc->md.la_size_sect) {
- dev_warn(DEV, "refusing to truncate a consistent device\n");
+ drbd_new_dev_size(device, nbc, nbc->disk_conf->disk_size, 0) < nbc->md.la_size_sect) {
+ drbd_warn(device, "refusing to truncate a consistent device\n");
retcode = ERR_DISK_TOO_SMALL;
goto force_diskless_dec;
}
@@ -1617,40 +1644,40 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
/* Reset the "barriers don't work" bits here, then force meta data to
* be written, to ensure we determine if barriers are supported. */
if (new_disk_conf->md_flushes)
- clear_bit(MD_NO_FUA, &mdev->flags);
+ clear_bit(MD_NO_FUA, &device->flags);
else
- set_bit(MD_NO_FUA, &mdev->flags);
+ set_bit(MD_NO_FUA, &device->flags);
/* Point of no return reached.
* Devices and memory are no longer released by error cleanup below.
- * now mdev takes over responsibility, and the state engine should
+ * now device takes over responsibility, and the state engine should
* clean it up somewhere. */
- D_ASSERT(mdev->ldev == NULL);
- mdev->ldev = nbc;
- mdev->resync = resync_lru;
- mdev->rs_plan_s = new_plan;
+ D_ASSERT(device, device->ldev == NULL);
+ device->ldev = nbc;
+ device->resync = resync_lru;
+ device->rs_plan_s = new_plan;
nbc = NULL;
resync_lru = NULL;
new_disk_conf = NULL;
new_plan = NULL;
- drbd_bump_write_ordering(mdev->tconn, WO_bdev_flush);
+ drbd_bump_write_ordering(first_peer_device(device)->connection, WO_bdev_flush);
- if (drbd_md_test_flag(mdev->ldev, MDF_CRASHED_PRIMARY))
- set_bit(CRASHED_PRIMARY, &mdev->flags);
+ if (drbd_md_test_flag(device->ldev, MDF_CRASHED_PRIMARY))
+ set_bit(CRASHED_PRIMARY, &device->flags);
else
- clear_bit(CRASHED_PRIMARY, &mdev->flags);
+ clear_bit(CRASHED_PRIMARY, &device->flags);
- if (drbd_md_test_flag(mdev->ldev, MDF_PRIMARY_IND) &&
- !(mdev->state.role == R_PRIMARY && mdev->tconn->susp_nod))
- set_bit(CRASHED_PRIMARY, &mdev->flags);
+ if (drbd_md_test_flag(device->ldev, MDF_PRIMARY_IND) &&
+ !(device->state.role == R_PRIMARY && device->resource->susp_nod))
+ set_bit(CRASHED_PRIMARY, &device->flags);
- mdev->send_cnt = 0;
- mdev->recv_cnt = 0;
- mdev->read_cnt = 0;
- mdev->writ_cnt = 0;
+ device->send_cnt = 0;
+ device->recv_cnt = 0;
+ device->read_cnt = 0;
+ device->writ_cnt = 0;
- drbd_reconsider_max_bio_size(mdev);
+ drbd_reconsider_max_bio_size(device);
/* If I am currently not R_PRIMARY,
* but meta data primary indicator is set,
@@ -1666,50 +1693,50 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
* so we can automatically recover from a crash of a
* degraded but active "cluster" after a certain timeout.
*/
- clear_bit(USE_DEGR_WFC_T, &mdev->flags);
- if (mdev->state.role != R_PRIMARY &&
- drbd_md_test_flag(mdev->ldev, MDF_PRIMARY_IND) &&
- !drbd_md_test_flag(mdev->ldev, MDF_CONNECTED_IND))
- set_bit(USE_DEGR_WFC_T, &mdev->flags);
+ clear_bit(USE_DEGR_WFC_T, &device->flags);
+ if (device->state.role != R_PRIMARY &&
+ drbd_md_test_flag(device->ldev, MDF_PRIMARY_IND) &&
+ !drbd_md_test_flag(device->ldev, MDF_CONNECTED_IND))
+ set_bit(USE_DEGR_WFC_T, &device->flags);
- dd = drbd_determine_dev_size(mdev, 0, NULL);
+ dd = drbd_determine_dev_size(device, 0, NULL);
if (dd <= DS_ERROR) {
retcode = ERR_NOMEM_BITMAP;
goto force_diskless_dec;
} else if (dd == DS_GREW)
- set_bit(RESYNC_AFTER_NEG, &mdev->flags);
+ set_bit(RESYNC_AFTER_NEG, &device->flags);
- if (drbd_md_test_flag(mdev->ldev, MDF_FULL_SYNC) ||
- (test_bit(CRASHED_PRIMARY, &mdev->flags) &&
- drbd_md_test_flag(mdev->ldev, MDF_AL_DISABLED))) {
- dev_info(DEV, "Assuming that all blocks are out of sync "
+ if (drbd_md_test_flag(device->ldev, MDF_FULL_SYNC) ||
+ (test_bit(CRASHED_PRIMARY, &device->flags) &&
+ drbd_md_test_flag(device->ldev, MDF_AL_DISABLED))) {
+ drbd_info(device, "Assuming that all blocks are out of sync "
"(aka FullSync)\n");
- if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write,
+ if (drbd_bitmap_io(device, &drbd_bmio_set_n_write,
"set_n_write from attaching", BM_LOCKED_MASK)) {
retcode = ERR_IO_MD_DISK;
goto force_diskless_dec;
}
} else {
- if (drbd_bitmap_io(mdev, &drbd_bm_read,
+ if (drbd_bitmap_io(device, &drbd_bm_read,
"read from attaching", BM_LOCKED_MASK)) {
retcode = ERR_IO_MD_DISK;
goto force_diskless_dec;
}
}
- if (_drbd_bm_total_weight(mdev) == drbd_bm_bits(mdev))
- drbd_suspend_al(mdev); /* IO is still suspended here... */
+ if (_drbd_bm_total_weight(device) == drbd_bm_bits(device))
+ drbd_suspend_al(device); /* IO is still suspended here... */
- spin_lock_irq(&mdev->tconn->req_lock);
- os = drbd_read_state(mdev);
+ spin_lock_irq(&device->resource->req_lock);
+ os = drbd_read_state(device);
ns = os;
/* If MDF_CONSISTENT is not set go into inconsistent state,
otherwise investigate MDF_WasUpToDate...
If MDF_WAS_UP_TO_DATE is not set go into D_OUTDATED disk state,
otherwise into D_CONSISTENT state.
*/
- if (drbd_md_test_flag(mdev->ldev, MDF_CONSISTENT)) {
- if (drbd_md_test_flag(mdev->ldev, MDF_WAS_UP_TO_DATE))
+ if (drbd_md_test_flag(device->ldev, MDF_CONSISTENT)) {
+ if (drbd_md_test_flag(device->ldev, MDF_WAS_UP_TO_DATE))
ns.disk = D_CONSISTENT;
else
ns.disk = D_OUTDATED;
@@ -1717,12 +1744,12 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
ns.disk = D_INCONSISTENT;
}
- if (drbd_md_test_flag(mdev->ldev, MDF_PEER_OUT_DATED))
+ if (drbd_md_test_flag(device->ldev, MDF_PEER_OUT_DATED))
ns.pdsk = D_OUTDATED;
rcu_read_lock();
if (ns.disk == D_CONSISTENT &&
- (ns.pdsk == D_OUTDATED || rcu_dereference(mdev->ldev->disk_conf)->fencing == FP_DONT_CARE))
+ (ns.pdsk == D_OUTDATED || rcu_dereference(device->ldev->disk_conf)->fencing == FP_DONT_CARE))
ns.disk = D_UP_TO_DATE;
/* All tests on MDF_PRIMARY_IND, MDF_CONNECTED_IND,
@@ -1730,56 +1757,56 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
this point, because drbd_request_state() modifies these
flags. */
- if (rcu_dereference(mdev->ldev->disk_conf)->al_updates)
- mdev->ldev->md.flags &= ~MDF_AL_DISABLED;
+ if (rcu_dereference(device->ldev->disk_conf)->al_updates)
+ device->ldev->md.flags &= ~MDF_AL_DISABLED;
else
- mdev->ldev->md.flags |= MDF_AL_DISABLED;
+ device->ldev->md.flags |= MDF_AL_DISABLED;
rcu_read_unlock();
/* In case we are C_CONNECTED postpone any decision on the new disk
state after the negotiation phase. */
- if (mdev->state.conn == C_CONNECTED) {
- mdev->new_state_tmp.i = ns.i;
+ if (device->state.conn == C_CONNECTED) {
+ device->new_state_tmp.i = ns.i;
ns.i = os.i;
ns.disk = D_NEGOTIATING;
/* We expect to receive up-to-date UUIDs soon.
To avoid a race in receive_state, free p_uuid while
holding req_lock. I.e. atomic with the state change */
- kfree(mdev->p_uuid);
- mdev->p_uuid = NULL;
+ kfree(device->p_uuid);
+ device->p_uuid = NULL;
}
- rv = _drbd_set_state(mdev, ns, CS_VERBOSE, NULL);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ rv = _drbd_set_state(device, ns, CS_VERBOSE, NULL);
+ spin_unlock_irq(&device->resource->req_lock);
if (rv < SS_SUCCESS)
goto force_diskless_dec;
- mod_timer(&mdev->request_timer, jiffies + HZ);
+ mod_timer(&device->request_timer, jiffies + HZ);
- if (mdev->state.role == R_PRIMARY)
- mdev->ldev->md.uuid[UI_CURRENT] |= (u64)1;
+ if (device->state.role == R_PRIMARY)
+ device->ldev->md.uuid[UI_CURRENT] |= (u64)1;
else
- mdev->ldev->md.uuid[UI_CURRENT] &= ~(u64)1;
+ device->ldev->md.uuid[UI_CURRENT] &= ~(u64)1;
- drbd_md_mark_dirty(mdev);
- drbd_md_sync(mdev);
+ drbd_md_mark_dirty(device);
+ drbd_md_sync(device);
- kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE);
- put_ldev(mdev);
- conn_reconfig_done(mdev->tconn);
+ kobject_uevent(&disk_to_dev(device->vdisk)->kobj, KOBJ_CHANGE);
+ put_ldev(device);
+ conn_reconfig_done(first_peer_device(device)->connection);
drbd_adm_finish(info, retcode);
return 0;
force_diskless_dec:
- put_ldev(mdev);
+ put_ldev(device);
force_diskless:
- drbd_force_state(mdev, NS(disk, D_DISKLESS));
- drbd_md_sync(mdev);
+ drbd_force_state(device, NS(disk, D_DISKLESS));
+ drbd_md_sync(device);
fail:
- conn_reconfig_done(mdev->tconn);
+ conn_reconfig_done(first_peer_device(device)->connection);
if (nbc) {
if (nbc->backing_bdev)
blkdev_put(nbc->backing_bdev,
@@ -1798,26 +1825,26 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
return 0;
}
-static int adm_detach(struct drbd_conf *mdev, int force)
+static int adm_detach(struct drbd_device *device, int force)
{
enum drbd_state_rv retcode;
int ret;
if (force) {
- set_bit(FORCE_DETACH, &mdev->flags);
- drbd_force_state(mdev, NS(disk, D_FAILED));
+ set_bit(FORCE_DETACH, &device->flags);
+ drbd_force_state(device, NS(disk, D_FAILED));
retcode = SS_SUCCESS;
goto out;
}
- drbd_suspend_io(mdev); /* so no-one is stuck in drbd_al_begin_io */
- drbd_md_get_buffer(mdev); /* make sure there is no in-flight meta-data IO */
- retcode = drbd_request_state(mdev, NS(disk, D_FAILED));
- drbd_md_put_buffer(mdev);
+ drbd_suspend_io(device); /* so no-one is stuck in drbd_al_begin_io */
+ drbd_md_get_buffer(device); /* make sure there is no in-flight meta-data IO */
+ retcode = drbd_request_state(device, NS(disk, D_FAILED));
+ drbd_md_put_buffer(device);
/* D_FAILED will transition to DISKLESS. */
- ret = wait_event_interruptible(mdev->misc_wait,
- mdev->state.disk != D_FAILED);
- drbd_resume_io(mdev);
+ ret = wait_event_interruptible(device->misc_wait,
+ device->state.disk != D_FAILED);
+ drbd_resume_io(device);
if ((int)retcode == (int)SS_IS_DISKLESS)
retcode = SS_NOTHING_TO_DO;
if (ret)
@@ -1852,24 +1879,25 @@ int drbd_adm_detach(struct sk_buff *skb, struct genl_info *info)
}
}
- retcode = adm_detach(adm_ctx.mdev, parms.force_detach);
+ retcode = adm_detach(adm_ctx.device, parms.force_detach);
out:
drbd_adm_finish(info, retcode);
return 0;
}
-static bool conn_resync_running(struct drbd_tconn *tconn)
+static bool conn_resync_running(struct drbd_connection *connection)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
bool rv = false;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- if (mdev->state.conn == C_SYNC_SOURCE ||
- mdev->state.conn == C_SYNC_TARGET ||
- mdev->state.conn == C_PAUSED_SYNC_S ||
- mdev->state.conn == C_PAUSED_SYNC_T) {
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ if (device->state.conn == C_SYNC_SOURCE ||
+ device->state.conn == C_SYNC_TARGET ||
+ device->state.conn == C_PAUSED_SYNC_S ||
+ device->state.conn == C_PAUSED_SYNC_T) {
rv = true;
break;
}
@@ -1879,16 +1907,17 @@ static bool conn_resync_running(struct drbd_tconn *tconn)
return rv;
}
-static bool conn_ov_running(struct drbd_tconn *tconn)
+static bool conn_ov_running(struct drbd_connection *connection)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
bool rv = false;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- if (mdev->state.conn == C_VERIFY_S ||
- mdev->state.conn == C_VERIFY_T) {
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ if (device->state.conn == C_VERIFY_S ||
+ device->state.conn == C_VERIFY_T) {
rv = true;
break;
}
@@ -1899,63 +1928,65 @@ static bool conn_ov_running(struct drbd_tconn *tconn)
}
static enum drbd_ret_code
-_check_net_options(struct drbd_tconn *tconn, struct net_conf *old_conf, struct net_conf *new_conf)
+_check_net_options(struct drbd_connection *connection, struct net_conf *old_net_conf, struct net_conf *new_net_conf)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int i;
- if (old_conf && tconn->cstate == C_WF_REPORT_PARAMS && tconn->agreed_pro_version < 100) {
- if (new_conf->wire_protocol != old_conf->wire_protocol)
+ if (old_net_conf && connection->cstate == C_WF_REPORT_PARAMS && connection->agreed_pro_version < 100) {
+ if (new_net_conf->wire_protocol != old_net_conf->wire_protocol)
return ERR_NEED_APV_100;
- if (new_conf->two_primaries != old_conf->two_primaries)
+ if (new_net_conf->two_primaries != old_net_conf->two_primaries)
return ERR_NEED_APV_100;
- if (strcmp(new_conf->integrity_alg, old_conf->integrity_alg))
+ if (strcmp(new_net_conf->integrity_alg, old_net_conf->integrity_alg))
return ERR_NEED_APV_100;
}
- if (!new_conf->two_primaries &&
- conn_highest_role(tconn) == R_PRIMARY &&
- conn_highest_peer(tconn) == R_PRIMARY)
+ if (!new_net_conf->two_primaries &&
+ conn_highest_role(connection) == R_PRIMARY &&
+ conn_highest_peer(connection) == R_PRIMARY)
return ERR_NEED_ALLOW_TWO_PRI;
- if (new_conf->two_primaries &&
- (new_conf->wire_protocol != DRBD_PROT_C))
+ if (new_net_conf->two_primaries &&
+ (new_net_conf->wire_protocol != DRBD_PROT_C))
return ERR_NOT_PROTO_C;
- idr_for_each_entry(&tconn->volumes, mdev, i) {
- if (get_ldev(mdev)) {
- enum drbd_fencing_p fp = rcu_dereference(mdev->ldev->disk_conf)->fencing;
- put_ldev(mdev);
- if (new_conf->wire_protocol == DRBD_PROT_A && fp == FP_STONITH)
+ idr_for_each_entry(&connection->peer_devices, peer_device, i) {
+ struct drbd_device *device = peer_device->device;
+ if (get_ldev(device)) {
+ enum drbd_fencing_p fp = rcu_dereference(device->ldev->disk_conf)->fencing;
+ put_ldev(device);
+ if (new_net_conf->wire_protocol == DRBD_PROT_A && fp == FP_STONITH)
return ERR_STONITH_AND_PROT_A;
}
- if (mdev->state.role == R_PRIMARY && new_conf->discard_my_data)
+ if (device->state.role == R_PRIMARY && new_net_conf->discard_my_data)
return ERR_DISCARD_IMPOSSIBLE;
}
- if (new_conf->on_congestion != OC_BLOCK && new_conf->wire_protocol != DRBD_PROT_A)
+ if (new_net_conf->on_congestion != OC_BLOCK && new_net_conf->wire_protocol != DRBD_PROT_A)
return ERR_CONG_NOT_PROTO_A;
return NO_ERROR;
}
static enum drbd_ret_code
-check_net_options(struct drbd_tconn *tconn, struct net_conf *new_conf)
+check_net_options(struct drbd_connection *connection, struct net_conf *new_net_conf)
{
static enum drbd_ret_code rv;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int i;
rcu_read_lock();
- rv = _check_net_options(tconn, rcu_dereference(tconn->net_conf), new_conf);
+ rv = _check_net_options(connection, rcu_dereference(connection->net_conf), new_net_conf);
rcu_read_unlock();
- /* tconn->volumes protected by genl_lock() here */
- idr_for_each_entry(&tconn->volumes, mdev, i) {
- if (!mdev->bitmap) {
- if(drbd_bm_init(mdev))
+ /* connection->volumes protected by genl_lock() here */
+ idr_for_each_entry(&connection->peer_devices, peer_device, i) {
+ struct drbd_device *device = peer_device->device;
+ if (!device->bitmap) {
+ if (drbd_bm_init(device))
return ERR_NOMEM;
}
}
@@ -1986,26 +2017,26 @@ alloc_hash(struct crypto_hash **tfm, char *tfm_name, int err_alg)
}
static enum drbd_ret_code
-alloc_crypto(struct crypto *crypto, struct net_conf *new_conf)
+alloc_crypto(struct crypto *crypto, struct net_conf *new_net_conf)
{
char hmac_name[CRYPTO_MAX_ALG_NAME];
enum drbd_ret_code rv;
- rv = alloc_hash(&crypto->csums_tfm, new_conf->csums_alg,
+ rv = alloc_hash(&crypto->csums_tfm, new_net_conf->csums_alg,
ERR_CSUMS_ALG);
if (rv != NO_ERROR)
return rv;
- rv = alloc_hash(&crypto->verify_tfm, new_conf->verify_alg,
+ rv = alloc_hash(&crypto->verify_tfm, new_net_conf->verify_alg,
ERR_VERIFY_ALG);
if (rv != NO_ERROR)
return rv;
- rv = alloc_hash(&crypto->integrity_tfm, new_conf->integrity_alg,
+ rv = alloc_hash(&crypto->integrity_tfm, new_net_conf->integrity_alg,
ERR_INTEGRITY_ALG);
if (rv != NO_ERROR)
return rv;
- if (new_conf->cram_hmac_alg[0] != 0) {
+ if (new_net_conf->cram_hmac_alg[0] != 0) {
snprintf(hmac_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)",
- new_conf->cram_hmac_alg);
+ new_net_conf->cram_hmac_alg);
rv = alloc_hash(&crypto->cram_hmac_tfm, hmac_name,
ERR_AUTH_ALG);
@@ -2025,8 +2056,8 @@ static void free_crypto(struct crypto *crypto)
int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
{
enum drbd_ret_code retcode;
- struct drbd_tconn *tconn;
- struct net_conf *old_conf, *new_conf = NULL;
+ struct drbd_connection *connection;
+ struct net_conf *old_net_conf, *new_net_conf = NULL;
int err;
int ovr; /* online verify running */
int rsr; /* re-sync running */
@@ -2038,98 +2069,103 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- tconn = adm_ctx.tconn;
+ connection = adm_ctx.connection;
- new_conf = kzalloc(sizeof(struct net_conf), GFP_KERNEL);
- if (!new_conf) {
+ new_net_conf = kzalloc(sizeof(struct net_conf), GFP_KERNEL);
+ if (!new_net_conf) {
retcode = ERR_NOMEM;
goto out;
}
- conn_reconfig_start(tconn);
+ conn_reconfig_start(connection);
- mutex_lock(&tconn->data.mutex);
- mutex_lock(&tconn->conf_update);
- old_conf = tconn->net_conf;
+ mutex_lock(&connection->data.mutex);
+ mutex_lock(&connection->resource->conf_update);
+ old_net_conf = connection->net_conf;
- if (!old_conf) {
+ if (!old_net_conf) {
drbd_msg_put_info("net conf missing, try connect");
retcode = ERR_INVALID_REQUEST;
goto fail;
}
- *new_conf = *old_conf;
+ *new_net_conf = *old_net_conf;
if (should_set_defaults(info))
- set_net_conf_defaults(new_conf);
+ set_net_conf_defaults(new_net_conf);
- err = net_conf_from_attrs_for_change(new_conf, info);
+ err = net_conf_from_attrs_for_change(new_net_conf, info);
if (err && err != -ENOMSG) {
retcode = ERR_MANDATORY_TAG;
drbd_msg_put_info(from_attrs_err_to_txt(err));
goto fail;
}
- retcode = check_net_options(tconn, new_conf);
+ retcode = check_net_options(connection, new_net_conf);
if (retcode != NO_ERROR)
goto fail;
/* re-sync running */
- rsr = conn_resync_running(tconn);
- if (rsr && strcmp(new_conf->csums_alg, old_conf->csums_alg)) {
+ rsr = conn_resync_running(connection);
+ if (rsr && strcmp(new_net_conf->csums_alg, old_net_conf->csums_alg)) {
retcode = ERR_CSUMS_RESYNC_RUNNING;
goto fail;
}
/* online verify running */
- ovr = conn_ov_running(tconn);
- if (ovr && strcmp(new_conf->verify_alg, old_conf->verify_alg)) {
+ ovr = conn_ov_running(connection);
+ if (ovr && strcmp(new_net_conf->verify_alg, old_net_conf->verify_alg)) {
retcode = ERR_VERIFY_RUNNING;
goto fail;
}
- retcode = alloc_crypto(&crypto, new_conf);
+ retcode = alloc_crypto(&crypto, new_net_conf);
if (retcode != NO_ERROR)
goto fail;
- rcu_assign_pointer(tconn->net_conf, new_conf);
+ rcu_assign_pointer(connection->net_conf, new_net_conf);
if (!rsr) {
- crypto_free_hash(tconn->csums_tfm);
- tconn->csums_tfm = crypto.csums_tfm;
+ crypto_free_hash(connection->csums_tfm);
+ connection->csums_tfm = crypto.csums_tfm;
crypto.csums_tfm = NULL;
}
if (!ovr) {
- crypto_free_hash(tconn->verify_tfm);
- tconn->verify_tfm = crypto.verify_tfm;
+ crypto_free_hash(connection->verify_tfm);
+ connection->verify_tfm = crypto.verify_tfm;
crypto.verify_tfm = NULL;
}
- crypto_free_hash(tconn->integrity_tfm);
- tconn->integrity_tfm = crypto.integrity_tfm;
- if (tconn->cstate >= C_WF_REPORT_PARAMS && tconn->agreed_pro_version >= 100)
- /* Do this without trying to take tconn->data.mutex again. */
- __drbd_send_protocol(tconn, P_PROTOCOL_UPDATE);
+ crypto_free_hash(connection->integrity_tfm);
+ connection->integrity_tfm = crypto.integrity_tfm;
+ if (connection->cstate >= C_WF_REPORT_PARAMS && connection->agreed_pro_version >= 100)
+ /* Do this without trying to take connection->data.mutex again. */
+ __drbd_send_protocol(connection, P_PROTOCOL_UPDATE);
- crypto_free_hash(tconn->cram_hmac_tfm);
- tconn->cram_hmac_tfm = crypto.cram_hmac_tfm;
+ crypto_free_hash(connection->cram_hmac_tfm);
+ connection->cram_hmac_tfm = crypto.cram_hmac_tfm;
- mutex_unlock(&tconn->conf_update);
- mutex_unlock(&tconn->data.mutex);
+ mutex_unlock(&connection->resource->conf_update);
+ mutex_unlock(&connection->data.mutex);
synchronize_rcu();
- kfree(old_conf);
+ kfree(old_net_conf);
+
+ if (connection->cstate >= C_WF_REPORT_PARAMS) {
+ struct drbd_peer_device *peer_device;
+ int vnr;
- if (tconn->cstate >= C_WF_REPORT_PARAMS)
- drbd_send_sync_param(minor_to_mdev(conn_lowest_minor(tconn)));
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr)
+ drbd_send_sync_param(peer_device);
+ }
goto done;
fail:
- mutex_unlock(&tconn->conf_update);
- mutex_unlock(&tconn->data.mutex);
+ mutex_unlock(&connection->resource->conf_update);
+ mutex_unlock(&connection->data.mutex);
free_crypto(&crypto);
- kfree(new_conf);
+ kfree(new_net_conf);
done:
- conn_reconfig_done(tconn);
+ conn_reconfig_done(connection);
out:
drbd_adm_finish(info, retcode);
return 0;
@@ -2137,10 +2173,11 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
{
- struct drbd_conf *mdev;
- struct net_conf *old_conf, *new_conf = NULL;
+ struct drbd_peer_device *peer_device;
+ struct net_conf *old_net_conf, *new_net_conf = NULL;
struct crypto crypto = { };
- struct drbd_tconn *tconn;
+ struct drbd_resource *resource;
+ struct drbd_connection *connection;
enum drbd_ret_code retcode;
int i;
int err;
@@ -2160,106 +2197,111 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
/* No need for _rcu here. All reconfiguration is
* strictly serialized on genl_lock(). We are protected against
* concurrent reconfiguration/addition/deletion */
- list_for_each_entry(tconn, &drbd_tconns, all_tconn) {
- if (nla_len(adm_ctx.my_addr) == tconn->my_addr_len &&
- !memcmp(nla_data(adm_ctx.my_addr), &tconn->my_addr, tconn->my_addr_len)) {
- retcode = ERR_LOCAL_ADDR;
- goto out;
- }
+ for_each_resource(resource, &drbd_resources) {
+ for_each_connection(connection, resource) {
+ if (nla_len(adm_ctx.my_addr) == connection->my_addr_len &&
+ !memcmp(nla_data(adm_ctx.my_addr), &connection->my_addr,
+ connection->my_addr_len)) {
+ retcode = ERR_LOCAL_ADDR;
+ goto out;
+ }
- if (nla_len(adm_ctx.peer_addr) == tconn->peer_addr_len &&
- !memcmp(nla_data(adm_ctx.peer_addr), &tconn->peer_addr, tconn->peer_addr_len)) {
- retcode = ERR_PEER_ADDR;
- goto out;
+ if (nla_len(adm_ctx.peer_addr) == connection->peer_addr_len &&
+ !memcmp(nla_data(adm_ctx.peer_addr), &connection->peer_addr,
+ connection->peer_addr_len)) {
+ retcode = ERR_PEER_ADDR;
+ goto out;
+ }
}
}
- tconn = adm_ctx.tconn;
- conn_reconfig_start(tconn);
+ connection = first_connection(adm_ctx.resource);
+ conn_reconfig_start(connection);
- if (tconn->cstate > C_STANDALONE) {
+ if (connection->cstate > C_STANDALONE) {
retcode = ERR_NET_CONFIGURED;
goto fail;
}
/* allocation not in the IO path, drbdsetup / netlink process context */
- new_conf = kzalloc(sizeof(*new_conf), GFP_KERNEL);
- if (!new_conf) {
+ new_net_conf = kzalloc(sizeof(*new_net_conf), GFP_KERNEL);
+ if (!new_net_conf) {
retcode = ERR_NOMEM;
goto fail;
}
- set_net_conf_defaults(new_conf);
+ set_net_conf_defaults(new_net_conf);
- err = net_conf_from_attrs(new_conf, info);
+ err = net_conf_from_attrs(new_net_conf, info);
if (err && err != -ENOMSG) {
retcode = ERR_MANDATORY_TAG;
drbd_msg_put_info(from_attrs_err_to_txt(err));
goto fail;
}
- retcode = check_net_options(tconn, new_conf);
+ retcode = check_net_options(connection, new_net_conf);
if (retcode != NO_ERROR)
goto fail;
- retcode = alloc_crypto(&crypto, new_conf);
+ retcode = alloc_crypto(&crypto, new_net_conf);
if (retcode != NO_ERROR)
goto fail;
- ((char *)new_conf->shared_secret)[SHARED_SECRET_MAX-1] = 0;
+ ((char *)new_net_conf->shared_secret)[SHARED_SECRET_MAX-1] = 0;
- conn_flush_workqueue(tconn);
+ drbd_flush_workqueue(&connection->sender_work);
- mutex_lock(&tconn->conf_update);
- old_conf = tconn->net_conf;
- if (old_conf) {
+ mutex_lock(&adm_ctx.resource->conf_update);
+ old_net_conf = connection->net_conf;
+ if (old_net_conf) {
retcode = ERR_NET_CONFIGURED;
- mutex_unlock(&tconn->conf_update);
+ mutex_unlock(&adm_ctx.resource->conf_update);
goto fail;
}
- rcu_assign_pointer(tconn->net_conf, new_conf);
+ rcu_assign_pointer(connection->net_conf, new_net_conf);
- conn_free_crypto(tconn);
- tconn->cram_hmac_tfm = crypto.cram_hmac_tfm;
- tconn->integrity_tfm = crypto.integrity_tfm;
- tconn->csums_tfm = crypto.csums_tfm;
- tconn->verify_tfm = crypto.verify_tfm;
+ conn_free_crypto(connection);
+ connection->cram_hmac_tfm = crypto.cram_hmac_tfm;
+ connection->integrity_tfm = crypto.integrity_tfm;
+ connection->csums_tfm = crypto.csums_tfm;
+ connection->verify_tfm = crypto.verify_tfm;
- tconn->my_addr_len = nla_len(adm_ctx.my_addr);
- memcpy(&tconn->my_addr, nla_data(adm_ctx.my_addr), tconn->my_addr_len);
- tconn->peer_addr_len = nla_len(adm_ctx.peer_addr);
- memcpy(&tconn->peer_addr, nla_data(adm_ctx.peer_addr), tconn->peer_addr_len);
+ connection->my_addr_len = nla_len(adm_ctx.my_addr);
+ memcpy(&connection->my_addr, nla_data(adm_ctx.my_addr), connection->my_addr_len);
+ connection->peer_addr_len = nla_len(adm_ctx.peer_addr);
+ memcpy(&connection->peer_addr, nla_data(adm_ctx.peer_addr), connection->peer_addr_len);
- mutex_unlock(&tconn->conf_update);
+ mutex_unlock(&adm_ctx.resource->conf_update);
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, i) {
- mdev->send_cnt = 0;
- mdev->recv_cnt = 0;
+ idr_for_each_entry(&connection->peer_devices, peer_device, i) {
+ struct drbd_device *device = peer_device->device;
+ device->send_cnt = 0;
+ device->recv_cnt = 0;
}
rcu_read_unlock();
- retcode = conn_request_state(tconn, NS(conn, C_UNCONNECTED), CS_VERBOSE);
+ retcode = conn_request_state(connection, NS(conn, C_UNCONNECTED), CS_VERBOSE);
- conn_reconfig_done(tconn);
+ conn_reconfig_done(connection);
drbd_adm_finish(info, retcode);
return 0;
fail:
free_crypto(&crypto);
- kfree(new_conf);
+ kfree(new_net_conf);
- conn_reconfig_done(tconn);
+ conn_reconfig_done(connection);
out:
drbd_adm_finish(info, retcode);
return 0;
}
-static enum drbd_state_rv conn_try_disconnect(struct drbd_tconn *tconn, bool force)
+static enum drbd_state_rv conn_try_disconnect(struct drbd_connection *connection, bool force)
{
enum drbd_state_rv rv;
- rv = conn_request_state(tconn, NS(conn, C_DISCONNECTING),
+ rv = conn_request_state(connection, NS(conn, C_DISCONNECTING),
force ? CS_HARD : 0);
switch (rv) {
@@ -2269,18 +2311,18 @@ static enum drbd_state_rv conn_try_disconnect(struct drbd_tconn *tconn, bool for
return SS_SUCCESS;
case SS_PRIMARY_NOP:
/* Our state checking code wants to see the peer outdated. */
- rv = conn_request_state(tconn, NS2(conn, C_DISCONNECTING, pdsk, D_OUTDATED), 0);
+ rv = conn_request_state(connection, NS2(conn, C_DISCONNECTING, pdsk, D_OUTDATED), 0);
if (rv == SS_OUTDATE_WO_CONN) /* lost connection before graceful disconnect succeeded */
- rv = conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_VERBOSE);
+ rv = conn_request_state(connection, NS(conn, C_DISCONNECTING), CS_VERBOSE);
break;
case SS_CW_FAILED_BY_PEER:
/* The peer probably wants to see us outdated. */
- rv = conn_request_state(tconn, NS2(conn, C_DISCONNECTING,
+ rv = conn_request_state(connection, NS2(conn, C_DISCONNECTING,
disk, D_OUTDATED), 0);
if (rv == SS_IS_DISKLESS || rv == SS_LOWER_THAN_OUTDATED) {
- rv = conn_request_state(tconn, NS(conn, C_DISCONNECTING),
+ rv = conn_request_state(connection, NS(conn, C_DISCONNECTING),
CS_HARD);
}
break;
@@ -2294,18 +2336,18 @@ static enum drbd_state_rv conn_try_disconnect(struct drbd_tconn *tconn, bool for
* The state handling only uses drbd_thread_stop_nowait(),
* we want to really wait here until the receiver is no more.
*/
- drbd_thread_stop(&adm_ctx.tconn->receiver);
+ drbd_thread_stop(&connection->receiver);
/* Race breaker. This additional state change request may be
* necessary, if this was a forced disconnect during a receiver
* restart. We may have "killed" the receiver thread just
- * after drbdd_init() returned. Typically, we should be
+ * after drbd_receiver() returned. Typically, we should be
* C_STANDALONE already, now, and this becomes a no-op.
*/
- rv2 = conn_request_state(tconn, NS(conn, C_STANDALONE),
+ rv2 = conn_request_state(connection, NS(conn, C_STANDALONE),
CS_VERBOSE | CS_HARD);
if (rv2 < SS_SUCCESS)
- conn_err(tconn,
+ drbd_err(connection,
"unexpected rv2=%d in conn_try_disconnect()\n",
rv2);
}
@@ -2315,7 +2357,7 @@ static enum drbd_state_rv conn_try_disconnect(struct drbd_tconn *tconn, bool for
int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info)
{
struct disconnect_parms parms;
- struct drbd_tconn *tconn;
+ struct drbd_connection *connection;
enum drbd_state_rv rv;
enum drbd_ret_code retcode;
int err;
@@ -2326,7 +2368,7 @@ int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto fail;
- tconn = adm_ctx.tconn;
+ connection = adm_ctx.connection;
memset(&parms, 0, sizeof(parms));
if (info->attrs[DRBD_NLA_DISCONNECT_PARMS]) {
err = disconnect_parms_from_attrs(&parms, info);
@@ -2337,7 +2379,7 @@ int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info)
}
}
- rv = conn_try_disconnect(tconn, parms.force_disconnect);
+ rv = conn_try_disconnect(connection, parms.force_disconnect);
if (rv < SS_SUCCESS)
retcode = rv; /* FIXME: Type mismatch. */
else
@@ -2347,27 +2389,27 @@ int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info)
return 0;
}
-void resync_after_online_grow(struct drbd_conf *mdev)
+void resync_after_online_grow(struct drbd_device *device)
{
int iass; /* I am sync source */
- dev_info(DEV, "Resync of new storage after online grow\n");
- if (mdev->state.role != mdev->state.peer)
- iass = (mdev->state.role == R_PRIMARY);
+ drbd_info(device, "Resync of new storage after online grow\n");
+ if (device->state.role != device->state.peer)
+ iass = (device->state.role == R_PRIMARY);
else
- iass = test_bit(RESOLVE_CONFLICTS, &mdev->tconn->flags);
+ iass = test_bit(RESOLVE_CONFLICTS, &first_peer_device(device)->connection->flags);
if (iass)
- drbd_start_resync(mdev, C_SYNC_SOURCE);
+ drbd_start_resync(device, C_SYNC_SOURCE);
else
- _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE + CS_SERIALIZE);
+ _drbd_request_state(device, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE + CS_SERIALIZE);
}
int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
{
struct disk_conf *old_disk_conf, *new_disk_conf = NULL;
struct resize_parms rs;
- struct drbd_conf *mdev;
+ struct drbd_device *device;
enum drbd_ret_code retcode;
enum determine_dev_size dd;
bool change_al_layout = false;
@@ -2381,15 +2423,15 @@ 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)) {
+ device = adm_ctx.device;
+ if (!get_ldev(device)) {
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;
+ rs.al_stripes = device->ldev->md.al_stripes;
+ rs.al_stripe_size = device->ldev->md.al_stripe_size_4k * 4;
if (info->attrs[DRBD_NLA_RESIZE_PARMS]) {
err = resize_parms_from_attrs(&rs, info);
if (err) {
@@ -2399,24 +2441,24 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
}
}
- if (mdev->state.conn > C_CONNECTED) {
+ if (device->state.conn > C_CONNECTED) {
retcode = ERR_RESIZE_RESYNC;
goto fail_ldev;
}
- if (mdev->state.role == R_SECONDARY &&
- mdev->state.peer == R_SECONDARY) {
+ if (device->state.role == R_SECONDARY &&
+ device->state.peer == R_SECONDARY) {
retcode = ERR_NO_PRIMARY;
goto fail_ldev;
}
- if (rs.no_resync && mdev->tconn->agreed_pro_version < 93) {
+ if (rs.no_resync && first_peer_device(device)->connection->agreed_pro_version < 93) {
retcode = ERR_NEED_APV_93;
goto fail_ldev;
}
rcu_read_lock();
- u_size = rcu_dereference(mdev->ldev->disk_conf)->disk_size;
+ u_size = rcu_dereference(device->ldev->disk_conf)->disk_size;
rcu_read_unlock();
if (u_size != (sector_t)rs.resize_size) {
new_disk_conf = kmalloc(sizeof(struct disk_conf), GFP_KERNEL);
@@ -2426,8 +2468,8 @@ 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) {
+ if (device->ldev->md.al_stripes != rs.al_stripes ||
+ device->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)) {
@@ -2440,7 +2482,7 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
goto fail_ldev;
}
- if (mdev->state.conn != C_CONNECTED) {
+ if (device->state.conn != C_CONNECTED) {
retcode = ERR_MD_LAYOUT_CONNECTED;
goto fail_ldev;
}
@@ -2448,24 +2490,24 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
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);
+ if (device->ldev->known_size != drbd_get_capacity(device->ldev->backing_bdev))
+ device->ldev->known_size = drbd_get_capacity(device->ldev->backing_bdev);
if (new_disk_conf) {
- mutex_lock(&mdev->tconn->conf_update);
- old_disk_conf = mdev->ldev->disk_conf;
+ mutex_lock(&device->resource->conf_update);
+ old_disk_conf = device->ldev->disk_conf;
*new_disk_conf = *old_disk_conf;
new_disk_conf->disk_size = (sector_t)rs.resize_size;
- rcu_assign_pointer(mdev->ldev->disk_conf, new_disk_conf);
- mutex_unlock(&mdev->tconn->conf_update);
+ rcu_assign_pointer(device->ldev->disk_conf, new_disk_conf);
+ mutex_unlock(&device->resource->conf_update);
synchronize_rcu();
kfree(old_disk_conf);
}
ddsf = (rs.resize_force ? DDSF_FORCED : 0) | (rs.no_resync ? DDSF_NO_RESYNC : 0);
- dd = drbd_determine_dev_size(mdev, ddsf, change_al_layout ? &rs : NULL);
- drbd_md_sync(mdev);
- put_ldev(mdev);
+ dd = drbd_determine_dev_size(device, ddsf, change_al_layout ? &rs : NULL);
+ drbd_md_sync(device);
+ put_ldev(device);
if (dd == DS_ERROR) {
retcode = ERR_NOMEM_BITMAP;
goto fail;
@@ -2477,12 +2519,12 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
goto fail;
}
- if (mdev->state.conn == C_CONNECTED) {
+ if (device->state.conn == C_CONNECTED) {
if (dd == DS_GREW)
- set_bit(RESIZE_PENDING, &mdev->flags);
+ set_bit(RESIZE_PENDING, &device->flags);
- drbd_send_uuids(mdev);
- drbd_send_sizes(mdev, 1, ddsf);
+ drbd_send_uuids(first_peer_device(device));
+ drbd_send_sizes(first_peer_device(device), 1, ddsf);
}
fail:
@@ -2490,14 +2532,13 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
return 0;
fail_ldev:
- put_ldev(mdev);
+ put_ldev(device);
goto fail;
}
int drbd_adm_resource_opts(struct sk_buff *skb, struct genl_info *info)
{
enum drbd_ret_code retcode;
- struct drbd_tconn *tconn;
struct res_opts res_opts;
int err;
@@ -2506,9 +2547,8 @@ int drbd_adm_resource_opts(struct sk_buff *skb, struct genl_info *info)
return retcode;
if (retcode != NO_ERROR)
goto fail;
- tconn = adm_ctx.tconn;
- res_opts = tconn->res_opts;
+ res_opts = adm_ctx.resource->res_opts;
if (should_set_defaults(info))
set_res_opts_defaults(&res_opts);
@@ -2519,7 +2559,7 @@ int drbd_adm_resource_opts(struct sk_buff *skb, struct genl_info *info)
goto fail;
}
- err = set_resource_options(tconn, &res_opts);
+ err = set_resource_options(adm_ctx.resource, &res_opts);
if (err) {
retcode = ERR_INVALID_REQUEST;
if (err == -ENOMEM)
@@ -2533,7 +2573,7 @@ fail:
int drbd_adm_invalidate(struct sk_buff *skb, struct genl_info *info)
{
- struct drbd_conf *mdev;
+ struct drbd_device *device;
int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */
retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
@@ -2542,29 +2582,29 @@ int drbd_adm_invalidate(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- mdev = adm_ctx.mdev;
+ device = adm_ctx.device;
/* If there is still bitmap IO pending, probably because of a previous
* resync just being finished, wait for it before requesting a new resync.
* Also wait for it's after_state_ch(). */
- drbd_suspend_io(mdev);
- wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags));
- drbd_flush_workqueue(mdev);
+ drbd_suspend_io(device);
+ wait_event(device->misc_wait, !test_bit(BITMAP_IO, &device->flags));
+ drbd_flush_workqueue(&first_peer_device(device)->connection->sender_work);
/* If we happen to be C_STANDALONE R_SECONDARY, just change to
* D_INCONSISTENT, and set all bits in the bitmap. Otherwise,
* try to start a resync handshake as sync target for full sync.
*/
- if (mdev->state.conn == C_STANDALONE && mdev->state.role == R_SECONDARY) {
- retcode = drbd_request_state(mdev, NS(disk, D_INCONSISTENT));
+ if (device->state.conn == C_STANDALONE && device->state.role == R_SECONDARY) {
+ retcode = drbd_request_state(device, NS(disk, D_INCONSISTENT));
if (retcode >= SS_SUCCESS) {
- if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write,
+ if (drbd_bitmap_io(device, &drbd_bmio_set_n_write,
"set_n_write from invalidate", BM_LOCKED_MASK))
retcode = ERR_IO_MD_DISK;
}
} else
- retcode = drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_T));
- drbd_resume_io(mdev);
+ retcode = drbd_request_state(device, NS(conn, C_STARTING_SYNC_T));
+ drbd_resume_io(device);
out:
drbd_adm_finish(info, retcode);
@@ -2582,25 +2622,25 @@ static int drbd_adm_simple_request_state(struct sk_buff *skb, struct genl_info *
if (retcode != NO_ERROR)
goto out;
- retcode = drbd_request_state(adm_ctx.mdev, mask, val);
+ retcode = drbd_request_state(adm_ctx.device, mask, val);
out:
drbd_adm_finish(info, retcode);
return 0;
}
-static int drbd_bmio_set_susp_al(struct drbd_conf *mdev)
+static int drbd_bmio_set_susp_al(struct drbd_device *device)
{
int rv;
- rv = drbd_bmio_set_n_write(mdev);
- drbd_suspend_al(mdev);
+ rv = drbd_bmio_set_n_write(device);
+ drbd_suspend_al(device);
return rv;
}
int drbd_adm_invalidate_peer(struct sk_buff *skb, struct genl_info *info)
{
int retcode; /* drbd_ret_code, drbd_state_rv */
- struct drbd_conf *mdev;
+ struct drbd_device *device;
retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
if (!adm_ctx.reply_skb)
@@ -2608,32 +2648,32 @@ int drbd_adm_invalidate_peer(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- mdev = adm_ctx.mdev;
+ device = adm_ctx.device;
/* If there is still bitmap IO pending, probably because of a previous
* resync just being finished, wait for it before requesting a new resync.
* Also wait for it's after_state_ch(). */
- drbd_suspend_io(mdev);
- wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags));
- drbd_flush_workqueue(mdev);
+ drbd_suspend_io(device);
+ wait_event(device->misc_wait, !test_bit(BITMAP_IO, &device->flags));
+ drbd_flush_workqueue(&first_peer_device(device)->connection->sender_work);
/* If we happen to be C_STANDALONE R_PRIMARY, just set all bits
* in the bitmap. Otherwise, try to start a resync handshake
* as sync source for full sync.
*/
- if (mdev->state.conn == C_STANDALONE && mdev->state.role == R_PRIMARY) {
+ if (device->state.conn == C_STANDALONE && device->state.role == R_PRIMARY) {
/* The peer will get a resync upon connect anyways. Just make that
into a full resync. */
- retcode = drbd_request_state(mdev, NS(pdsk, D_INCONSISTENT));
+ retcode = drbd_request_state(device, NS(pdsk, D_INCONSISTENT));
if (retcode >= SS_SUCCESS) {
- if (drbd_bitmap_io(mdev, &drbd_bmio_set_susp_al,
+ if (drbd_bitmap_io(device, &drbd_bmio_set_susp_al,
"set_n_write from invalidate_peer",
BM_LOCKED_SET_ALLOWED))
retcode = ERR_IO_MD_DISK;
}
} else
- retcode = drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_S));
- drbd_resume_io(mdev);
+ retcode = drbd_request_state(device, NS(conn, C_STARTING_SYNC_S));
+ drbd_resume_io(device);
out:
drbd_adm_finish(info, retcode);
@@ -2650,7 +2690,7 @@ int drbd_adm_pause_sync(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- if (drbd_request_state(adm_ctx.mdev, NS(user_isp, 1)) == SS_NOTHING_TO_DO)
+ if (drbd_request_state(adm_ctx.device, NS(user_isp, 1)) == SS_NOTHING_TO_DO)
retcode = ERR_PAUSE_IS_SET;
out:
drbd_adm_finish(info, retcode);
@@ -2668,8 +2708,8 @@ int drbd_adm_resume_sync(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- if (drbd_request_state(adm_ctx.mdev, NS(user_isp, 0)) == SS_NOTHING_TO_DO) {
- s = adm_ctx.mdev->state;
+ if (drbd_request_state(adm_ctx.device, NS(user_isp, 0)) == SS_NOTHING_TO_DO) {
+ s = adm_ctx.device->state;
if (s.conn == C_PAUSED_SYNC_S || s.conn == C_PAUSED_SYNC_T) {
retcode = s.aftr_isp ? ERR_PIC_AFTER_DEP :
s.peer_isp ? ERR_PIC_PEER_DEP : ERR_PAUSE_IS_CLEAR;
@@ -2690,7 +2730,7 @@ int drbd_adm_suspend_io(struct sk_buff *skb, struct genl_info *info)
int drbd_adm_resume_io(struct sk_buff *skb, struct genl_info *info)
{
- struct drbd_conf *mdev;
+ struct drbd_device *device;
int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */
retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
@@ -2699,20 +2739,20 @@ int drbd_adm_resume_io(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- mdev = adm_ctx.mdev;
- if (test_bit(NEW_CUR_UUID, &mdev->flags)) {
- drbd_uuid_new_current(mdev);
- clear_bit(NEW_CUR_UUID, &mdev->flags);
+ device = adm_ctx.device;
+ if (test_bit(NEW_CUR_UUID, &device->flags)) {
+ drbd_uuid_new_current(device);
+ clear_bit(NEW_CUR_UUID, &device->flags);
}
- drbd_suspend_io(mdev);
- retcode = drbd_request_state(mdev, NS3(susp, 0, susp_nod, 0, susp_fen, 0));
+ drbd_suspend_io(device);
+ retcode = drbd_request_state(device, NS3(susp, 0, susp_nod, 0, susp_fen, 0));
if (retcode == SS_SUCCESS) {
- if (mdev->state.conn < C_CONNECTED)
- tl_clear(mdev->tconn);
- if (mdev->state.disk == D_DISKLESS || mdev->state.disk == D_FAILED)
- tl_restart(mdev->tconn, FAIL_FROZEN_DISK_IO);
+ if (device->state.conn < C_CONNECTED)
+ tl_clear(first_peer_device(device)->connection);
+ if (device->state.disk == D_DISKLESS || device->state.disk == D_FAILED)
+ tl_restart(first_peer_device(device)->connection, FAIL_FROZEN_DISK_IO);
}
- drbd_resume_io(mdev);
+ drbd_resume_io(device);
out:
drbd_adm_finish(info, retcode);
@@ -2724,23 +2764,28 @@ int drbd_adm_outdate(struct sk_buff *skb, struct genl_info *info)
return drbd_adm_simple_request_state(skb, info, NS(disk, D_OUTDATED));
}
-int nla_put_drbd_cfg_context(struct sk_buff *skb, struct drbd_tconn *tconn, unsigned vnr)
+static int nla_put_drbd_cfg_context(struct sk_buff *skb,
+ struct drbd_resource *resource,
+ struct drbd_connection *connection,
+ struct drbd_device *device)
{
struct nlattr *nla;
nla = nla_nest_start(skb, DRBD_NLA_CFG_CONTEXT);
if (!nla)
goto nla_put_failure;
- if (vnr != VOLUME_UNSPECIFIED &&
- nla_put_u32(skb, T_ctx_volume, vnr))
- goto nla_put_failure;
- if (nla_put_string(skb, T_ctx_resource_name, tconn->name))
- goto nla_put_failure;
- if (tconn->my_addr_len &&
- nla_put(skb, T_ctx_my_addr, tconn->my_addr_len, &tconn->my_addr))
+ if (device &&
+ nla_put_u32(skb, T_ctx_volume, device->vnr))
goto nla_put_failure;
- if (tconn->peer_addr_len &&
- nla_put(skb, T_ctx_peer_addr, tconn->peer_addr_len, &tconn->peer_addr))
+ if (nla_put_string(skb, T_ctx_resource_name, resource->name))
goto nla_put_failure;
+ if (connection) {
+ if (connection->my_addr_len &&
+ nla_put(skb, T_ctx_my_addr, connection->my_addr_len, &connection->my_addr))
+ goto nla_put_failure;
+ if (connection->peer_addr_len &&
+ nla_put(skb, T_ctx_peer_addr, connection->peer_addr_len, &connection->peer_addr))
+ goto nla_put_failure;
+ }
nla_nest_end(skb, nla);
return 0;
@@ -2750,9 +2795,22 @@ nla_put_failure:
return -EMSGSIZE;
}
-int nla_put_status_info(struct sk_buff *skb, struct drbd_conf *mdev,
+/*
+ * Return the connection of @resource if @resource has exactly one connection.
+ */
+static struct drbd_connection *the_only_connection(struct drbd_resource *resource)
+{
+ struct list_head *connections = &resource->connections;
+
+ if (list_empty(connections) || connections->next->next != connections)
+ return NULL;
+ return list_first_entry(&resource->connections, struct drbd_connection, connections);
+}
+
+int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device,
const struct sib_info *sib)
{
+ struct drbd_resource *resource = device->resource;
struct state_info *si = NULL; /* for sizeof(si->member); */
struct nlattr *nla;
int got_ldev;
@@ -2772,27 +2830,27 @@ int nla_put_status_info(struct sk_buff *skb, struct drbd_conf *mdev,
* always in the context of the receiving process */
exclude_sensitive = sib || !capable(CAP_SYS_ADMIN);
- got_ldev = get_ldev(mdev);
+ got_ldev = get_ldev(device);
/* We need to add connection name and volume number information still.
* Minor number is in drbd_genlmsghdr. */
- if (nla_put_drbd_cfg_context(skb, mdev->tconn, mdev->vnr))
+ if (nla_put_drbd_cfg_context(skb, resource, the_only_connection(resource), device))
goto nla_put_failure;
- if (res_opts_to_skb(skb, &mdev->tconn->res_opts, exclude_sensitive))
+ if (res_opts_to_skb(skb, &device->resource->res_opts, exclude_sensitive))
goto nla_put_failure;
rcu_read_lock();
if (got_ldev) {
struct disk_conf *disk_conf;
- disk_conf = rcu_dereference(mdev->ldev->disk_conf);
+ disk_conf = rcu_dereference(device->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);
+ nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
if (nc)
err = net_conf_to_skb(skb, nc, exclude_sensitive);
}
@@ -2804,38 +2862,38 @@ int nla_put_status_info(struct sk_buff *skb, struct drbd_conf *mdev,
if (!nla)
goto nla_put_failure;
if (nla_put_u32(skb, T_sib_reason, sib ? sib->sib_reason : SIB_GET_STATUS_REPLY) ||
- nla_put_u32(skb, T_current_state, mdev->state.i) ||
- nla_put_u64(skb, T_ed_uuid, mdev->ed_uuid) ||
- nla_put_u64(skb, T_capacity, drbd_get_capacity(mdev->this_bdev)) ||
- nla_put_u64(skb, T_send_cnt, mdev->send_cnt) ||
- nla_put_u64(skb, T_recv_cnt, mdev->recv_cnt) ||
- nla_put_u64(skb, T_read_cnt, mdev->read_cnt) ||
- nla_put_u64(skb, T_writ_cnt, mdev->writ_cnt) ||
- nla_put_u64(skb, T_al_writ_cnt, mdev->al_writ_cnt) ||
- nla_put_u64(skb, T_bm_writ_cnt, mdev->bm_writ_cnt) ||
- nla_put_u32(skb, T_ap_bio_cnt, atomic_read(&mdev->ap_bio_cnt)) ||
- nla_put_u32(skb, T_ap_pending_cnt, atomic_read(&mdev->ap_pending_cnt)) ||
- nla_put_u32(skb, T_rs_pending_cnt, atomic_read(&mdev->rs_pending_cnt)))
+ nla_put_u32(skb, T_current_state, device->state.i) ||
+ nla_put_u64(skb, T_ed_uuid, device->ed_uuid) ||
+ nla_put_u64(skb, T_capacity, drbd_get_capacity(device->this_bdev)) ||
+ nla_put_u64(skb, T_send_cnt, device->send_cnt) ||
+ nla_put_u64(skb, T_recv_cnt, device->recv_cnt) ||
+ nla_put_u64(skb, T_read_cnt, device->read_cnt) ||
+ nla_put_u64(skb, T_writ_cnt, device->writ_cnt) ||
+ nla_put_u64(skb, T_al_writ_cnt, device->al_writ_cnt) ||
+ nla_put_u64(skb, T_bm_writ_cnt, device->bm_writ_cnt) ||
+ nla_put_u32(skb, T_ap_bio_cnt, atomic_read(&device->ap_bio_cnt)) ||
+ nla_put_u32(skb, T_ap_pending_cnt, atomic_read(&device->ap_pending_cnt)) ||
+ nla_put_u32(skb, T_rs_pending_cnt, atomic_read(&device->rs_pending_cnt)))
goto nla_put_failure;
if (got_ldev) {
int err;
- spin_lock_irq(&mdev->ldev->md.uuid_lock);
- err = nla_put(skb, T_uuids, sizeof(si->uuids), mdev->ldev->md.uuid);
- spin_unlock_irq(&mdev->ldev->md.uuid_lock);
+ spin_lock_irq(&device->ldev->md.uuid_lock);
+ err = nla_put(skb, T_uuids, sizeof(si->uuids), device->ldev->md.uuid);
+ spin_unlock_irq(&device->ldev->md.uuid_lock);
if (err)
goto nla_put_failure;
- if (nla_put_u32(skb, T_disk_flags, mdev->ldev->md.flags) ||
- nla_put_u64(skb, T_bits_total, drbd_bm_bits(mdev)) ||
- nla_put_u64(skb, T_bits_oos, drbd_bm_total_weight(mdev)))
+ if (nla_put_u32(skb, T_disk_flags, device->ldev->md.flags) ||
+ nla_put_u64(skb, T_bits_total, drbd_bm_bits(device)) ||
+ nla_put_u64(skb, T_bits_oos, drbd_bm_total_weight(device)))
goto nla_put_failure;
- if (C_SYNC_SOURCE <= mdev->state.conn &&
- C_PAUSED_SYNC_T >= mdev->state.conn) {
- if (nla_put_u64(skb, T_bits_rs_total, mdev->rs_total) ||
- nla_put_u64(skb, T_bits_rs_failed, mdev->rs_failed))
+ if (C_SYNC_SOURCE <= device->state.conn &&
+ C_PAUSED_SYNC_T >= device->state.conn) {
+ if (nla_put_u64(skb, T_bits_rs_total, device->rs_total) ||
+ nla_put_u64(skb, T_bits_rs_failed, device->rs_failed))
goto nla_put_failure;
}
}
@@ -2867,7 +2925,7 @@ int nla_put_status_info(struct sk_buff *skb, struct drbd_conf *mdev,
nla_put_failure:
err = -EMSGSIZE;
if (got_ldev)
- put_ldev(mdev);
+ put_ldev(device);
return err;
}
@@ -2882,7 +2940,7 @@ int drbd_adm_get_status(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- err = nla_put_status_info(adm_ctx.reply_skb, adm_ctx.mdev, NULL);
+ err = nla_put_status_info(adm_ctx.reply_skb, adm_ctx.device, NULL);
if (err) {
nlmsg_free(adm_ctx.reply_skb);
return err;
@@ -2892,22 +2950,23 @@ out:
return 0;
}
-int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
+static int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
{
- struct drbd_conf *mdev;
+ struct drbd_device *device;
struct drbd_genlmsghdr *dh;
- struct drbd_tconn *pos = (struct drbd_tconn*)cb->args[0];
- struct drbd_tconn *tconn = NULL;
- struct drbd_tconn *tmp;
+ struct drbd_resource *pos = (struct drbd_resource *)cb->args[0];
+ struct drbd_resource *resource = NULL;
+ struct drbd_resource *tmp;
unsigned volume = cb->args[1];
/* Open coded, deferred, iteration:
- * list_for_each_entry_safe(tconn, tmp, &drbd_tconns, all_tconn) {
- * idr_for_each_entry(&tconn->volumes, mdev, i) {
+ * for_each_resource_safe(resource, tmp, &drbd_resources) {
+ * connection = "first connection of resource or undefined";
+ * idr_for_each_entry(&resource->devices, device, i) {
* ...
* }
* }
- * where tconn is cb->args[0];
+ * where resource is cb->args[0];
* and i is cb->args[1];
*
* cb->args[2] indicates if we shall loop over all resources,
@@ -2916,44 +2975,44 @@ int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
* This may miss entries inserted after this dump started,
* or entries deleted before they are reached.
*
- * We need to make sure the mdev won't disappear while
+ * We need to make sure the device won't disappear while
* we are looking at it, and revalidate our iterators
* on each iteration.
*/
- /* synchronize with conn_create()/conn_destroy() */
+ /* synchronize with conn_create()/drbd_destroy_connection() */
rcu_read_lock();
/* revalidate iterator position */
- list_for_each_entry_rcu(tmp, &drbd_tconns, all_tconn) {
+ for_each_resource_rcu(tmp, &drbd_resources) {
if (pos == NULL) {
/* first iteration */
pos = tmp;
- tconn = pos;
+ resource = pos;
break;
}
if (tmp == pos) {
- tconn = pos;
+ resource = pos;
break;
}
}
- if (tconn) {
-next_tconn:
- mdev = idr_get_next(&tconn->volumes, &volume);
- if (!mdev) {
- /* No more volumes to dump on this tconn.
- * Advance tconn iterator. */
- pos = list_entry_rcu(tconn->all_tconn.next,
- struct drbd_tconn, all_tconn);
- /* Did we dump any volume on this tconn yet? */
+ if (resource) {
+next_resource:
+ device = idr_get_next(&resource->devices, &volume);
+ if (!device) {
+ /* No more volumes to dump on this resource.
+ * Advance resource iterator. */
+ pos = list_entry_rcu(resource->resources.next,
+ struct drbd_resource, resources);
+ /* Did we dump any volume of this resource yet? */
if (volume != 0) {
/* If we reached the end of the list,
* or only a single resource dump was requested,
* we are done. */
- if (&pos->all_tconn == &drbd_tconns || cb->args[2])
+ if (&pos->resources == &drbd_resources || cb->args[2])
goto out;
volume = 0;
- tconn = pos;
- goto next_tconn;
+ resource = pos;
+ goto next_resource;
}
}
@@ -2963,43 +3022,49 @@ next_tconn:
if (!dh)
goto out;
- if (!mdev) {
- /* This is a tconn without a single volume.
+ if (!device) {
+ /* This is a connection without a single volume.
* Suprisingly enough, it may have a network
* configuration. */
- struct net_conf *nc;
+ struct drbd_connection *connection;
+
dh->minor = -1U;
dh->ret_code = NO_ERROR;
- if (nla_put_drbd_cfg_context(skb, tconn, VOLUME_UNSPECIFIED))
- goto cancel;
- nc = rcu_dereference(tconn->net_conf);
- if (nc && net_conf_to_skb(skb, nc, 1) != 0)
+ connection = the_only_connection(resource);
+ if (nla_put_drbd_cfg_context(skb, resource, connection, NULL))
goto cancel;
+ if (connection) {
+ struct net_conf *nc;
+
+ nc = rcu_dereference(connection->net_conf);
+ if (nc && net_conf_to_skb(skb, nc, 1) != 0)
+ goto cancel;
+ }
goto done;
}
- D_ASSERT(mdev->vnr == volume);
- D_ASSERT(mdev->tconn == tconn);
+ D_ASSERT(device, device->vnr == volume);
+ D_ASSERT(device, device->resource == resource);
- dh->minor = mdev_to_minor(mdev);
+ dh->minor = device_to_minor(device);
dh->ret_code = NO_ERROR;
- if (nla_put_status_info(skb, mdev, NULL)) {
+ if (nla_put_status_info(skb, device, NULL)) {
cancel:
genlmsg_cancel(skb, dh);
goto out;
}
done:
genlmsg_end(skb, dh);
- }
+ }
out:
rcu_read_unlock();
/* where to start the next iteration */
- cb->args[0] = (long)pos;
- cb->args[1] = (pos == tconn) ? volume + 1 : 0;
+ cb->args[0] = (long)pos;
+ cb->args[1] = (pos == resource) ? volume + 1 : 0;
- /* No more tconns/volumes/minors found results in an empty skb.
+ /* No more resources/volumes/minors found results in an empty skb.
* Which will terminate the dump. */
return skb->len;
}
@@ -3019,7 +3084,7 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb)
const unsigned hdrlen = GENL_HDRLEN + GENL_MAGIC_FAMILY_HDRSZ;
struct nlattr *nla;
const char *resource_name;
- struct drbd_tconn *tconn;
+ struct drbd_resource *resource;
int maxtype;
/* Is this a followup call? */
@@ -3048,18 +3113,19 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb)
if (!nla)
return -EINVAL;
resource_name = nla_data(nla);
- tconn = conn_get_by_name(resource_name);
-
- if (!tconn)
+ if (!*resource_name)
+ return -ENODEV;
+ resource = drbd_find_resource(resource_name);
+ if (!resource)
return -ENODEV;
- kref_put(&tconn->kref, &conn_destroy); /* get_one_status() (re)validates tconn by itself */
+ kref_put(&resource->kref, drbd_destroy_resource); /* get_one_status() revalidates the resource */
/* prime iterators, and set "filter" mode mark:
- * only dump this tconn. */
- cb->args[0] = (long)tconn;
+ * only dump this connection. */
+ cb->args[0] = (long)resource;
/* cb->args[1] = 0; passed in this way. */
- cb->args[2] = (long)tconn;
+ cb->args[2] = (long)resource;
dump:
return get_one_status(skb, cb);
@@ -3078,8 +3144,8 @@ int drbd_adm_get_timeout_type(struct sk_buff *skb, struct genl_info *info)
goto out;
tp.timeout_type =
- adm_ctx.mdev->state.pdsk == D_OUTDATED ? UT_PEER_OUTDATED :
- test_bit(USE_DEGR_WFC_T, &adm_ctx.mdev->flags) ? UT_DEGRADED :
+ adm_ctx.device->state.pdsk == D_OUTDATED ? UT_PEER_OUTDATED :
+ test_bit(USE_DEGR_WFC_T, &adm_ctx.device->flags) ? UT_DEGRADED :
UT_DEFAULT;
err = timeout_parms_to_priv_skb(adm_ctx.reply_skb, &tp);
@@ -3094,7 +3160,7 @@ out:
int drbd_adm_start_ov(struct sk_buff *skb, struct genl_info *info)
{
- struct drbd_conf *mdev;
+ struct drbd_device *device;
enum drbd_ret_code retcode;
struct start_ov_parms parms;
@@ -3104,10 +3170,10 @@ int drbd_adm_start_ov(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- mdev = adm_ctx.mdev;
+ device = adm_ctx.device;
/* resume from last known position, if possible */
- parms.ov_start_sector = mdev->ov_start_sector;
+ parms.ov_start_sector = device->ov_start_sector;
parms.ov_stop_sector = ULLONG_MAX;
if (info->attrs[DRBD_NLA_START_OV_PARMS]) {
int err = start_ov_parms_from_attrs(&parms, info);
@@ -3118,15 +3184,15 @@ int drbd_adm_start_ov(struct sk_buff *skb, struct genl_info *info)
}
}
/* w_make_ov_request expects position to be aligned */
- mdev->ov_start_sector = parms.ov_start_sector & ~(BM_SECT_PER_BIT-1);
- mdev->ov_stop_sector = parms.ov_stop_sector;
+ device->ov_start_sector = parms.ov_start_sector & ~(BM_SECT_PER_BIT-1);
+ device->ov_stop_sector = parms.ov_stop_sector;
/* If there is still bitmap IO pending, e.g. previous resync or verify
* just being finished, wait for it before requesting a new resync. */
- drbd_suspend_io(mdev);
- wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags));
- retcode = drbd_request_state(mdev,NS(conn,C_VERIFY_S));
- drbd_resume_io(mdev);
+ drbd_suspend_io(device);
+ wait_event(device->misc_wait, !test_bit(BITMAP_IO, &device->flags));
+ retcode = drbd_request_state(device, NS(conn, C_VERIFY_S));
+ drbd_resume_io(device);
out:
drbd_adm_finish(info, retcode);
return 0;
@@ -3135,7 +3201,7 @@ out:
int drbd_adm_new_c_uuid(struct sk_buff *skb, struct genl_info *info)
{
- struct drbd_conf *mdev;
+ struct drbd_device *device;
enum drbd_ret_code retcode;
int skip_initial_sync = 0;
int err;
@@ -3147,7 +3213,7 @@ int drbd_adm_new_c_uuid(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out_nolock;
- mdev = adm_ctx.mdev;
+ device = adm_ctx.device;
memset(&args, 0, sizeof(args));
if (info->attrs[DRBD_NLA_NEW_C_UUID_PARMS]) {
err = new_c_uuid_parms_from_attrs(&args, info);
@@ -3158,49 +3224,50 @@ int drbd_adm_new_c_uuid(struct sk_buff *skb, struct genl_info *info)
}
}
- mutex_lock(mdev->state_mutex); /* Protects us against serialized state changes. */
+ mutex_lock(device->state_mutex); /* Protects us against serialized state changes. */
- if (!get_ldev(mdev)) {
+ if (!get_ldev(device)) {
retcode = ERR_NO_DISK;
goto out;
}
/* this is "skip initial sync", assume to be clean */
- if (mdev->state.conn == C_CONNECTED && mdev->tconn->agreed_pro_version >= 90 &&
- mdev->ldev->md.uuid[UI_CURRENT] == UUID_JUST_CREATED && args.clear_bm) {
- dev_info(DEV, "Preparing to skip initial sync\n");
+ if (device->state.conn == C_CONNECTED &&
+ first_peer_device(device)->connection->agreed_pro_version >= 90 &&
+ device->ldev->md.uuid[UI_CURRENT] == UUID_JUST_CREATED && args.clear_bm) {
+ drbd_info(device, "Preparing to skip initial sync\n");
skip_initial_sync = 1;
- } else if (mdev->state.conn != C_STANDALONE) {
+ } else if (device->state.conn != C_STANDALONE) {
retcode = ERR_CONNECTED;
goto out_dec;
}
- drbd_uuid_set(mdev, UI_BITMAP, 0); /* Rotate UI_BITMAP to History 1, etc... */
- drbd_uuid_new_current(mdev); /* New current, previous to UI_BITMAP */
+ drbd_uuid_set(device, UI_BITMAP, 0); /* Rotate UI_BITMAP to History 1, etc... */
+ drbd_uuid_new_current(device); /* New current, previous to UI_BITMAP */
if (args.clear_bm) {
- err = drbd_bitmap_io(mdev, &drbd_bmio_clear_n_write,
+ err = drbd_bitmap_io(device, &drbd_bmio_clear_n_write,
"clear_n_write from new_c_uuid", BM_LOCKED_MASK);
if (err) {
- dev_err(DEV, "Writing bitmap failed with %d\n",err);
+ drbd_err(device, "Writing bitmap failed with %d\n", err);
retcode = ERR_IO_MD_DISK;
}
if (skip_initial_sync) {
- drbd_send_uuids_skip_initial_sync(mdev);
- _drbd_uuid_set(mdev, UI_BITMAP, 0);
- drbd_print_uuids(mdev, "cleared bitmap UUID");
- spin_lock_irq(&mdev->tconn->req_lock);
- _drbd_set_state(_NS2(mdev, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE),
+ drbd_send_uuids_skip_initial_sync(first_peer_device(device));
+ _drbd_uuid_set(device, UI_BITMAP, 0);
+ drbd_print_uuids(device, "cleared bitmap UUID");
+ spin_lock_irq(&device->resource->req_lock);
+ _drbd_set_state(_NS2(device, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE),
CS_VERBOSE, NULL);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
}
}
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
out_dec:
- put_ldev(mdev);
+ put_ldev(device);
out:
- mutex_unlock(mdev->state_mutex);
+ mutex_unlock(device->state_mutex);
out_nolock:
drbd_adm_finish(info, retcode);
return 0;
@@ -3246,7 +3313,7 @@ int drbd_adm_new_resource(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- if (adm_ctx.tconn) {
+ if (adm_ctx.resource) {
if (info->nlhdr->nlmsg_flags & NLM_F_EXCL) {
retcode = ERR_INVALID_REQUEST;
drbd_msg_put_info("resource exists");
@@ -3262,7 +3329,7 @@ out:
return 0;
}
-int drbd_adm_add_minor(struct sk_buff *skb, struct genl_info *info)
+int drbd_adm_new_minor(struct sk_buff *skb, struct genl_info *info)
{
struct drbd_genlmsghdr *dh = info->userhdr;
enum drbd_ret_code retcode;
@@ -3285,41 +3352,36 @@ int drbd_adm_add_minor(struct sk_buff *skb, struct genl_info *info)
}
/* drbd_adm_prepare made sure already
- * that mdev->tconn and mdev->vnr match the request. */
- if (adm_ctx.mdev) {
+ * that first_peer_device(device)->connection and device->vnr match the request. */
+ if (adm_ctx.device) {
if (info->nlhdr->nlmsg_flags & NLM_F_EXCL)
retcode = ERR_MINOR_EXISTS;
/* else: still NO_ERROR */
goto out;
}
- retcode = conn_new_minor(adm_ctx.tconn, dh->minor, adm_ctx.volume);
+ retcode = drbd_create_device(adm_ctx.resource, dh->minor, adm_ctx.volume);
out:
drbd_adm_finish(info, retcode);
return 0;
}
-static enum drbd_ret_code adm_delete_minor(struct drbd_conf *mdev)
+static enum drbd_ret_code adm_del_minor(struct drbd_device *device)
{
- if (mdev->state.disk == D_DISKLESS &&
- /* no need to be mdev->state.conn == C_STANDALONE &&
+ if (device->state.disk == D_DISKLESS &&
+ /* no need to be device->state.conn == C_STANDALONE &&
* we may want to delete a minor from a live replication group.
*/
- mdev->state.role == R_SECONDARY) {
- _drbd_request_state(mdev, NS(conn, C_WF_REPORT_PARAMS),
+ device->state.role == R_SECONDARY) {
+ _drbd_request_state(device, NS(conn, C_WF_REPORT_PARAMS),
CS_VERBOSE + CS_WAIT_COMPLETE);
- idr_remove(&mdev->tconn->volumes, mdev->vnr);
- idr_remove(&minors, mdev_to_minor(mdev));
- destroy_workqueue(mdev->submit.wq);
- del_gendisk(mdev->vdisk);
- synchronize_rcu();
- kref_put(&mdev->kref, &drbd_minor_destroy);
+ drbd_delete_device(device);
return NO_ERROR;
} else
return ERR_MINOR_CONFIGURED;
}
-int drbd_adm_delete_minor(struct sk_buff *skb, struct genl_info *info)
+int drbd_adm_del_minor(struct sk_buff *skb, struct genl_info *info)
{
enum drbd_ret_code retcode;
@@ -3329,7 +3391,7 @@ int drbd_adm_delete_minor(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- retcode = adm_delete_minor(adm_ctx.mdev);
+ retcode = adm_del_minor(adm_ctx.device);
out:
drbd_adm_finish(info, retcode);
return 0;
@@ -3337,55 +3399,58 @@ out:
int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
{
+ struct drbd_resource *resource;
+ struct drbd_connection *connection;
+ struct drbd_device *device;
int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */
- struct drbd_conf *mdev;
unsigned i;
- retcode = drbd_adm_prepare(skb, info, 0);
+ retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE);
if (!adm_ctx.reply_skb)
return retcode;
if (retcode != NO_ERROR)
goto out;
- if (!adm_ctx.tconn) {
- retcode = ERR_RES_NOT_KNOWN;
- goto out;
- }
-
+ resource = adm_ctx.resource;
/* demote */
- idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) {
- retcode = drbd_set_role(mdev, R_SECONDARY, 0);
+ for_each_connection(connection, resource) {
+ struct drbd_peer_device *peer_device;
+
+ idr_for_each_entry(&connection->peer_devices, peer_device, i) {
+ retcode = drbd_set_role(peer_device->device, R_SECONDARY, 0);
+ if (retcode < SS_SUCCESS) {
+ drbd_msg_put_info("failed to demote");
+ goto out;
+ }
+ }
+
+ retcode = conn_try_disconnect(connection, 0);
if (retcode < SS_SUCCESS) {
- drbd_msg_put_info("failed to demote");
+ drbd_msg_put_info("failed to disconnect");
goto out;
}
}
- retcode = conn_try_disconnect(adm_ctx.tconn, 0);
- if (retcode < SS_SUCCESS) {
- drbd_msg_put_info("failed to disconnect");
- goto out;
- }
-
/* detach */
- idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) {
- retcode = adm_detach(mdev, 0);
+ idr_for_each_entry(&resource->devices, device, i) {
+ retcode = adm_detach(device, 0);
if (retcode < SS_SUCCESS || retcode > NO_ERROR) {
drbd_msg_put_info("failed to detach");
goto out;
}
}
- /* If we reach this, all volumes (of this tconn) are Secondary,
+ /* If we reach this, all volumes (of this connection) are Secondary,
* Disconnected, Diskless, aka Unconfigured. Make sure all threads have
* actually stopped, state handling only does drbd_thread_stop_nowait(). */
- drbd_thread_stop(&adm_ctx.tconn->worker);
+ for_each_connection(connection, resource)
+ drbd_thread_stop(&connection->worker);
/* Now, nothing can fail anymore */
/* delete volumes */
- idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) {
- retcode = adm_delete_minor(mdev);
+ idr_for_each_entry(&resource->devices, device, i) {
+ retcode = adm_del_minor(device);
if (retcode != NO_ERROR) {
/* "can not happen" */
drbd_msg_put_info("failed to delete volume");
@@ -3393,19 +3458,11 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
}
}
- /* delete connection */
- if (conn_lowest_minor(adm_ctx.tconn) < 0) {
- list_del_rcu(&adm_ctx.tconn->all_tconn);
- synchronize_rcu();
- kref_put(&adm_ctx.tconn->kref, &conn_destroy);
+ list_del_rcu(&resource->resources);
+ synchronize_rcu();
+ drbd_free_resource(resource);
+ retcode = NO_ERROR;
- retcode = NO_ERROR;
- } else {
- /* "can not happen" */
- retcode = ERR_RES_IN_USE;
- drbd_msg_put_info("failed to delete connection");
- }
- goto out;
out:
drbd_adm_finish(info, retcode);
return 0;
@@ -3413,6 +3470,8 @@ out:
int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info)
{
+ struct drbd_resource *resource;
+ struct drbd_connection *connection;
enum drbd_ret_code retcode;
retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE);
@@ -3421,24 +3480,30 @@ int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- if (conn_lowest_minor(adm_ctx.tconn) < 0) {
- list_del_rcu(&adm_ctx.tconn->all_tconn);
- synchronize_rcu();
- kref_put(&adm_ctx.tconn->kref, &conn_destroy);
-
- retcode = NO_ERROR;
- } else {
+ resource = adm_ctx.resource;
+ for_each_connection(connection, resource) {
+ if (connection->cstate > C_STANDALONE) {
+ retcode = ERR_NET_CONFIGURED;
+ goto out;
+ }
+ }
+ if (!idr_is_empty(&resource->devices)) {
retcode = ERR_RES_IN_USE;
+ goto out;
}
- if (retcode == NO_ERROR)
- drbd_thread_stop(&adm_ctx.tconn->worker);
+ list_del_rcu(&resource->resources);
+ for_each_connection(connection, resource)
+ drbd_thread_stop(&connection->worker);
+ synchronize_rcu();
+ drbd_free_resource(resource);
+ retcode = NO_ERROR;
out:
drbd_adm_finish(info, retcode);
return 0;
}
-void drbd_bcast_event(struct drbd_conf *mdev, const struct sib_info *sib)
+void drbd_bcast_event(struct drbd_device *device, const struct sib_info *sib)
{
static atomic_t drbd_genl_seq = ATOMIC_INIT(2); /* two. */
struct sk_buff *msg;
@@ -3447,8 +3512,8 @@ void drbd_bcast_event(struct drbd_conf *mdev, const struct sib_info *sib)
int err = -ENOMEM;
if (sib->sib_reason == SIB_SYNC_PROGRESS) {
- if (time_after(jiffies, mdev->rs_last_bcast + HZ))
- mdev->rs_last_bcast = jiffies;
+ if (time_after(jiffies, device->rs_last_bcast + HZ))
+ device->rs_last_bcast = jiffies;
else
return;
}
@@ -3462,10 +3527,10 @@ void drbd_bcast_event(struct drbd_conf *mdev, const struct sib_info *sib)
d_out = genlmsg_put(msg, 0, seq, &drbd_genl_family, 0, DRBD_EVENT);
if (!d_out) /* cannot happen, but anyways. */
goto nla_put_failure;
- d_out->minor = mdev_to_minor(mdev);
+ d_out->minor = device_to_minor(device);
d_out->ret_code = NO_ERROR;
- if (nla_put_status_info(msg, mdev, sib))
+ if (nla_put_status_info(msg, device, sib))
goto nla_put_failure;
genlmsg_end(msg, d_out);
err = drbd_genl_multicast_events(msg, 0);
@@ -3478,7 +3543,7 @@ void drbd_bcast_event(struct drbd_conf *mdev, const struct sib_info *sib)
nla_put_failure:
nlmsg_free(msg);
failed:
- dev_err(DEV, "Error %d while broadcasting event. "
+ drbd_err(device, "Error %d while broadcasting event. "
"Event seq:%u sib_reason:%u\n",
err, seq, sib->sib_reason);
}
diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c
index bf31d41dbaad..2f26e8ffa45b 100644
--- a/drivers/block/drbd/drbd_proc.c
+++ b/drivers/block/drbd/drbd_proc.c
@@ -46,7 +46,7 @@ const struct file_operations drbd_proc_fops = {
.release = drbd_proc_release,
};
-void seq_printf_with_thousands_grouping(struct seq_file *seq, long v)
+static void seq_printf_with_thousands_grouping(struct seq_file *seq, long v)
{
/* v is in kB/sec. We don't expect TiByte/sec yet. */
if (unlikely(v >= 1000000)) {
@@ -66,14 +66,14 @@ void seq_printf_with_thousands_grouping(struct seq_file *seq, long v)
* [=====>..............] 33.5% (23456/123456)
* finish: 2:20:20 speed: 6,345 (6,456) K/sec
*/
-static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq)
+static void drbd_syncer_progress(struct drbd_device *device, struct seq_file *seq)
{
unsigned long db, dt, dbdt, rt, rs_left;
unsigned int res;
int i, x, y;
int stalled = 0;
- drbd_get_syncer_progress(mdev, &rs_left, &res);
+ drbd_get_syncer_progress(device, &rs_left, &res);
x = res/50;
y = 20-x;
@@ -85,21 +85,21 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq)
seq_printf(seq, ".");
seq_printf(seq, "] ");
- if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T)
+ if (device->state.conn == C_VERIFY_S || device->state.conn == C_VERIFY_T)
seq_printf(seq, "verified:");
else
seq_printf(seq, "sync'ed:");
seq_printf(seq, "%3u.%u%% ", res / 10, res % 10);
/* if more than a few GB, display in MB */
- if (mdev->rs_total > (4UL << (30 - BM_BLOCK_SHIFT)))
+ if (device->rs_total > (4UL << (30 - BM_BLOCK_SHIFT)))
seq_printf(seq, "(%lu/%lu)M",
(unsigned long) Bit2KB(rs_left >> 10),
- (unsigned long) Bit2KB(mdev->rs_total >> 10));
+ (unsigned long) Bit2KB(device->rs_total >> 10));
else
seq_printf(seq, "(%lu/%lu)K\n\t",
(unsigned long) Bit2KB(rs_left),
- (unsigned long) Bit2KB(mdev->rs_total));
+ (unsigned long) Bit2KB(device->rs_total));
/* see drivers/md/md.c
* We do not want to overflow, so the order of operands and
@@ -114,14 +114,14 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq)
* at least (DRBD_SYNC_MARKS-2)*DRBD_SYNC_MARK_STEP old, and has at
* least DRBD_SYNC_MARK_STEP time before it will be modified. */
/* ------------------------ ~18s average ------------------------ */
- i = (mdev->rs_last_mark + 2) % DRBD_SYNC_MARKS;
- dt = (jiffies - mdev->rs_mark_time[i]) / HZ;
+ i = (device->rs_last_mark + 2) % DRBD_SYNC_MARKS;
+ dt = (jiffies - device->rs_mark_time[i]) / HZ;
if (dt > (DRBD_SYNC_MARK_STEP * DRBD_SYNC_MARKS))
stalled = 1;
if (!dt)
dt++;
- db = mdev->rs_mark_left[i] - rs_left;
+ db = device->rs_mark_left[i] - rs_left;
rt = (dt * (rs_left / (db/100+1)))/100; /* seconds */
seq_printf(seq, "finish: %lu:%02lu:%02lu",
@@ -134,11 +134,11 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq)
/* ------------------------- ~3s average ------------------------ */
if (proc_details >= 1) {
/* this is what drbd_rs_should_slow_down() uses */
- i = (mdev->rs_last_mark + DRBD_SYNC_MARKS-1) % DRBD_SYNC_MARKS;
- dt = (jiffies - mdev->rs_mark_time[i]) / HZ;
+ i = (device->rs_last_mark + DRBD_SYNC_MARKS-1) % DRBD_SYNC_MARKS;
+ dt = (jiffies - device->rs_mark_time[i]) / HZ;
if (!dt)
dt++;
- db = mdev->rs_mark_left[i] - rs_left;
+ db = device->rs_mark_left[i] - rs_left;
dbdt = Bit2KB(db/dt);
seq_printf_with_thousands_grouping(seq, dbdt);
seq_printf(seq, " -- ");
@@ -147,34 +147,34 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq)
/* --------------------- long term average ---------------------- */
/* mean speed since syncer started
* we do account for PausedSync periods */
- dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ;
+ dt = (jiffies - device->rs_start - device->rs_paused) / HZ;
if (dt == 0)
dt = 1;
- db = mdev->rs_total - rs_left;
+ db = device->rs_total - rs_left;
dbdt = Bit2KB(db/dt);
seq_printf_with_thousands_grouping(seq, dbdt);
seq_printf(seq, ")");
- if (mdev->state.conn == C_SYNC_TARGET ||
- mdev->state.conn == C_VERIFY_S) {
+ if (device->state.conn == C_SYNC_TARGET ||
+ device->state.conn == C_VERIFY_S) {
seq_printf(seq, " want: ");
- seq_printf_with_thousands_grouping(seq, mdev->c_sync_rate);
+ seq_printf_with_thousands_grouping(seq, device->c_sync_rate);
}
seq_printf(seq, " K/sec%s\n", stalled ? " (stalled)" : "");
if (proc_details >= 1) {
/* 64 bit:
* we convert to sectors in the display below. */
- unsigned long bm_bits = drbd_bm_bits(mdev);
+ unsigned long bm_bits = drbd_bm_bits(device);
unsigned long bit_pos;
unsigned long long stop_sector = 0;
- if (mdev->state.conn == C_VERIFY_S ||
- mdev->state.conn == C_VERIFY_T) {
- bit_pos = bm_bits - mdev->ov_left;
- if (verify_can_do_stop_sector(mdev))
- stop_sector = mdev->ov_stop_sector;
+ if (device->state.conn == C_VERIFY_S ||
+ device->state.conn == C_VERIFY_T) {
+ bit_pos = bm_bits - device->ov_left;
+ if (verify_can_do_stop_sector(device))
+ stop_sector = device->ov_stop_sector;
} else
- bit_pos = mdev->bm_resync_fo;
+ bit_pos = device->bm_resync_fo;
/* Total sectors may be slightly off for oddly
* sized devices. So what. */
seq_printf(seq,
@@ -202,7 +202,7 @@ static int drbd_seq_show(struct seq_file *seq, void *v)
{
int i, prev_i = -1;
const char *sn;
- struct drbd_conf *mdev;
+ struct drbd_device *device;
struct net_conf *nc;
char wp;
@@ -236,72 +236,72 @@ static int drbd_seq_show(struct seq_file *seq, void *v)
*/
rcu_read_lock();
- idr_for_each_entry(&minors, mdev, i) {
+ idr_for_each_entry(&drbd_devices, device, i) {
if (prev_i != i - 1)
seq_printf(seq, "\n");
prev_i = i;
- sn = drbd_conn_str(mdev->state.conn);
+ sn = drbd_conn_str(device->state.conn);
- if (mdev->state.conn == C_STANDALONE &&
- mdev->state.disk == D_DISKLESS &&
- mdev->state.role == R_SECONDARY) {
+ if (device->state.conn == C_STANDALONE &&
+ device->state.disk == D_DISKLESS &&
+ device->state.role == R_SECONDARY) {
seq_printf(seq, "%2d: cs:Unconfigured\n", i);
} else {
- /* reset mdev->congestion_reason */
- bdi_rw_congested(&mdev->rq_queue->backing_dev_info);
+ /* reset device->congestion_reason */
+ bdi_rw_congested(&device->rq_queue->backing_dev_info);
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
wp = nc ? nc->wire_protocol - DRBD_PROT_A + 'A' : ' ';
seq_printf(seq,
"%2d: cs:%s ro:%s/%s ds:%s/%s %c %c%c%c%c%c%c\n"
" ns:%u nr:%u dw:%u dr:%u al:%u bm:%u "
"lo:%d pe:%d ua:%d ap:%d ep:%d wo:%c",
i, sn,
- drbd_role_str(mdev->state.role),
- drbd_role_str(mdev->state.peer),
- drbd_disk_str(mdev->state.disk),
- drbd_disk_str(mdev->state.pdsk),
+ drbd_role_str(device->state.role),
+ drbd_role_str(device->state.peer),
+ drbd_disk_str(device->state.disk),
+ drbd_disk_str(device->state.pdsk),
wp,
- drbd_suspended(mdev) ? 's' : 'r',
- mdev->state.aftr_isp ? 'a' : '-',
- mdev->state.peer_isp ? 'p' : '-',
- mdev->state.user_isp ? 'u' : '-',
- mdev->congestion_reason ?: '-',
- test_bit(AL_SUSPENDED, &mdev->flags) ? 's' : '-',
- mdev->send_cnt/2,
- mdev->recv_cnt/2,
- mdev->writ_cnt/2,
- mdev->read_cnt/2,
- mdev->al_writ_cnt,
- mdev->bm_writ_cnt,
- atomic_read(&mdev->local_cnt),
- atomic_read(&mdev->ap_pending_cnt) +
- atomic_read(&mdev->rs_pending_cnt),
- atomic_read(&mdev->unacked_cnt),
- atomic_read(&mdev->ap_bio_cnt),
- mdev->tconn->epochs,
- write_ordering_chars[mdev->tconn->write_ordering]
+ drbd_suspended(device) ? 's' : 'r',
+ device->state.aftr_isp ? 'a' : '-',
+ device->state.peer_isp ? 'p' : '-',
+ device->state.user_isp ? 'u' : '-',
+ device->congestion_reason ?: '-',
+ test_bit(AL_SUSPENDED, &device->flags) ? 's' : '-',
+ device->send_cnt/2,
+ device->recv_cnt/2,
+ device->writ_cnt/2,
+ device->read_cnt/2,
+ device->al_writ_cnt,
+ device->bm_writ_cnt,
+ atomic_read(&device->local_cnt),
+ atomic_read(&device->ap_pending_cnt) +
+ atomic_read(&device->rs_pending_cnt),
+ atomic_read(&device->unacked_cnt),
+ atomic_read(&device->ap_bio_cnt),
+ first_peer_device(device)->connection->epochs,
+ write_ordering_chars[first_peer_device(device)->connection->write_ordering]
);
seq_printf(seq, " oos:%llu\n",
Bit2KB((unsigned long long)
- drbd_bm_total_weight(mdev)));
+ drbd_bm_total_weight(device)));
}
- if (mdev->state.conn == C_SYNC_SOURCE ||
- mdev->state.conn == C_SYNC_TARGET ||
- mdev->state.conn == C_VERIFY_S ||
- mdev->state.conn == C_VERIFY_T)
- drbd_syncer_progress(mdev, seq);
-
- if (proc_details >= 1 && get_ldev_if_state(mdev, D_FAILED)) {
- lc_seq_printf_stats(seq, mdev->resync);
- lc_seq_printf_stats(seq, mdev->act_log);
- put_ldev(mdev);
+ if (device->state.conn == C_SYNC_SOURCE ||
+ device->state.conn == C_SYNC_TARGET ||
+ device->state.conn == C_VERIFY_S ||
+ device->state.conn == C_VERIFY_T)
+ drbd_syncer_progress(device, seq);
+
+ if (proc_details >= 1 && get_ldev_if_state(device, D_FAILED)) {
+ lc_seq_printf_stats(seq, device->resync);
+ lc_seq_printf_stats(seq, device->act_log);
+ put_ldev(device);
}
if (proc_details >= 2) {
- if (mdev->resync) {
- lc_seq_dump_details(seq, mdev->resync, "rs_left",
+ if (device->resync) {
+ lc_seq_dump_details(seq, device->resync, "rs_left",
resync_dump_detail);
}
}
diff --git a/drivers/block/drbd/drbd_protocol.h b/drivers/block/drbd/drbd_protocol.h
new file mode 100644
index 000000000000..3c04ec0ea333
--- /dev/null
+++ b/drivers/block/drbd/drbd_protocol.h
@@ -0,0 +1,295 @@
+#ifndef __DRBD_PROTOCOL_H
+#define __DRBD_PROTOCOL_H
+
+enum drbd_packet {
+ /* receiver (data socket) */
+ P_DATA = 0x00,
+ P_DATA_REPLY = 0x01, /* Response to P_DATA_REQUEST */
+ P_RS_DATA_REPLY = 0x02, /* Response to P_RS_DATA_REQUEST */
+ P_BARRIER = 0x03,
+ P_BITMAP = 0x04,
+ P_BECOME_SYNC_TARGET = 0x05,
+ P_BECOME_SYNC_SOURCE = 0x06,
+ P_UNPLUG_REMOTE = 0x07, /* Used at various times to hint the peer */
+ P_DATA_REQUEST = 0x08, /* Used to ask for a data block */
+ P_RS_DATA_REQUEST = 0x09, /* Used to ask for a data block for resync */
+ P_SYNC_PARAM = 0x0a,
+ P_PROTOCOL = 0x0b,
+ P_UUIDS = 0x0c,
+ P_SIZES = 0x0d,
+ P_STATE = 0x0e,
+ P_SYNC_UUID = 0x0f,
+ P_AUTH_CHALLENGE = 0x10,
+ P_AUTH_RESPONSE = 0x11,
+ P_STATE_CHG_REQ = 0x12,
+
+ /* asender (meta socket */
+ P_PING = 0x13,
+ P_PING_ACK = 0x14,
+ P_RECV_ACK = 0x15, /* Used in protocol B */
+ P_WRITE_ACK = 0x16, /* Used in protocol C */
+ P_RS_WRITE_ACK = 0x17, /* Is a P_WRITE_ACK, additionally call set_in_sync(). */
+ P_SUPERSEDED = 0x18, /* Used in proto C, two-primaries conflict detection */
+ P_NEG_ACK = 0x19, /* Sent if local disk is unusable */
+ P_NEG_DREPLY = 0x1a, /* Local disk is broken... */
+ P_NEG_RS_DREPLY = 0x1b, /* Local disk is broken... */
+ P_BARRIER_ACK = 0x1c,
+ P_STATE_CHG_REPLY = 0x1d,
+
+ /* "new" commands, no longer fitting into the ordering scheme above */
+
+ P_OV_REQUEST = 0x1e, /* data socket */
+ P_OV_REPLY = 0x1f,
+ P_OV_RESULT = 0x20, /* meta socket */
+ P_CSUM_RS_REQUEST = 0x21, /* data socket */
+ P_RS_IS_IN_SYNC = 0x22, /* meta socket */
+ P_SYNC_PARAM89 = 0x23, /* data socket, protocol version 89 replacement for P_SYNC_PARAM */
+ P_COMPRESSED_BITMAP = 0x24, /* compressed or otherwise encoded bitmap transfer */
+ /* P_CKPT_FENCE_REQ = 0x25, * currently reserved for protocol D */
+ /* P_CKPT_DISABLE_REQ = 0x26, * currently reserved for protocol D */
+ P_DELAY_PROBE = 0x27, /* is used on BOTH sockets */
+ P_OUT_OF_SYNC = 0x28, /* Mark as out of sync (Outrunning), data socket */
+ P_RS_CANCEL = 0x29, /* meta: Used to cancel RS_DATA_REQUEST packet by SyncSource */
+ P_CONN_ST_CHG_REQ = 0x2a, /* data sock: Connection wide state request */
+ P_CONN_ST_CHG_REPLY = 0x2b, /* meta sock: Connection side state req reply */
+ P_RETRY_WRITE = 0x2c, /* Protocol C: retry conflicting write request */
+ P_PROTOCOL_UPDATE = 0x2d, /* data sock: is used in established connections */
+
+ P_MAY_IGNORE = 0x100, /* Flag to test if (cmd > P_MAY_IGNORE) ... */
+ P_MAX_OPT_CMD = 0x101,
+
+ /* special command ids for handshake */
+
+ P_INITIAL_META = 0xfff1, /* First Packet on the MetaSock */
+ P_INITIAL_DATA = 0xfff2, /* First Packet on the Socket */
+
+ P_CONNECTION_FEATURES = 0xfffe /* FIXED for the next century! */
+};
+
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+
+/* This is the layout for a packet on the wire.
+ * The byteorder is the network byte order.
+ * (except block_id and barrier fields.
+ * these are pointers to local structs
+ * and have no relevance for the partner,
+ * which just echoes them as received.)
+ *
+ * NOTE that the payload starts at a long aligned offset,
+ * regardless of 32 or 64 bit arch!
+ */
+struct p_header80 {
+ u32 magic;
+ u16 command;
+ u16 length; /* bytes of data after this header */
+} __packed;
+
+/* Header for big packets, Used for data packets exceeding 64kB */
+struct p_header95 {
+ u16 magic; /* use DRBD_MAGIC_BIG here */
+ u16 command;
+ u32 length;
+} __packed;
+
+struct p_header100 {
+ u32 magic;
+ u16 volume;
+ u16 command;
+ u32 length;
+ u32 pad;
+} __packed;
+
+/* these defines must not be changed without changing the protocol version */
+#define DP_HARDBARRIER 1 /* depricated */
+#define DP_RW_SYNC 2 /* equals REQ_SYNC */
+#define DP_MAY_SET_IN_SYNC 4
+#define DP_UNPLUG 8 /* not used anymore */
+#define DP_FUA 16 /* equals REQ_FUA */
+#define DP_FLUSH 32 /* equals REQ_FLUSH */
+#define DP_DISCARD 64 /* equals REQ_DISCARD */
+#define DP_SEND_RECEIVE_ACK 128 /* This is a proto B write request */
+#define DP_SEND_WRITE_ACK 256 /* This is a proto C write request */
+
+struct p_data {
+ u64 sector; /* 64 bits sector number */
+ u64 block_id; /* to identify the request in protocol B&C */
+ u32 seq_num;
+ u32 dp_flags;
+} __packed;
+
+/*
+ * commands which share a struct:
+ * p_block_ack:
+ * P_RECV_ACK (proto B), P_WRITE_ACK (proto C),
+ * P_SUPERSEDED (proto C, two-primaries conflict detection)
+ * p_block_req:
+ * P_DATA_REQUEST, P_RS_DATA_REQUEST
+ */
+struct p_block_ack {
+ u64 sector;
+ u64 block_id;
+ u32 blksize;
+ u32 seq_num;
+} __packed;
+
+struct p_block_req {
+ u64 sector;
+ u64 block_id;
+ u32 blksize;
+ u32 pad; /* to multiple of 8 Byte */
+} __packed;
+
+/*
+ * commands with their own struct for additional fields:
+ * P_CONNECTION_FEATURES
+ * P_BARRIER
+ * P_BARRIER_ACK
+ * P_SYNC_PARAM
+ * ReportParams
+ */
+
+struct p_connection_features {
+ u32 protocol_min;
+ u32 feature_flags;
+ u32 protocol_max;
+
+ /* should be more than enough for future enhancements
+ * for now, feature_flags and the reserved array shall be zero.
+ */
+
+ u32 _pad;
+ u64 reserved[7];
+} __packed;
+
+struct p_barrier {
+ u32 barrier; /* barrier number _handle_ only */
+ u32 pad; /* to multiple of 8 Byte */
+} __packed;
+
+struct p_barrier_ack {
+ u32 barrier;
+ u32 set_size;
+} __packed;
+
+struct p_rs_param {
+ u32 resync_rate;
+
+ /* Since protocol version 88 and higher. */
+ char verify_alg[0];
+} __packed;
+
+struct p_rs_param_89 {
+ u32 resync_rate;
+ /* protocol version 89: */
+ char verify_alg[SHARED_SECRET_MAX];
+ char csums_alg[SHARED_SECRET_MAX];
+} __packed;
+
+struct p_rs_param_95 {
+ u32 resync_rate;
+ char verify_alg[SHARED_SECRET_MAX];
+ char csums_alg[SHARED_SECRET_MAX];
+ u32 c_plan_ahead;
+ u32 c_delay_target;
+ u32 c_fill_target;
+ u32 c_max_rate;
+} __packed;
+
+enum drbd_conn_flags {
+ CF_DISCARD_MY_DATA = 1,
+ CF_DRY_RUN = 2,
+};
+
+struct p_protocol {
+ u32 protocol;
+ u32 after_sb_0p;
+ u32 after_sb_1p;
+ u32 after_sb_2p;
+ u32 conn_flags;
+ u32 two_primaries;
+
+ /* Since protocol version 87 and higher. */
+ char integrity_alg[0];
+
+} __packed;
+
+struct p_uuids {
+ u64 uuid[UI_EXTENDED_SIZE];
+} __packed;
+
+struct p_rs_uuid {
+ u64 uuid;
+} __packed;
+
+struct p_sizes {
+ u64 d_size; /* size of disk */
+ u64 u_size; /* user requested size */
+ u64 c_size; /* current exported size */
+ u32 max_bio_size; /* Maximal size of a BIO */
+ u16 queue_order_type; /* not yet implemented in DRBD*/
+ u16 dds_flags; /* use enum dds_flags here. */
+} __packed;
+
+struct p_state {
+ u32 state;
+} __packed;
+
+struct p_req_state {
+ u32 mask;
+ u32 val;
+} __packed;
+
+struct p_req_state_reply {
+ u32 retcode;
+} __packed;
+
+struct p_drbd06_param {
+ u64 size;
+ u32 state;
+ u32 blksize;
+ u32 protocol;
+ u32 version;
+ u32 gen_cnt[5];
+ u32 bit_map_gen[5];
+} __packed;
+
+struct p_block_desc {
+ u64 sector;
+ u32 blksize;
+ u32 pad; /* to multiple of 8 Byte */
+} __packed;
+
+/* Valid values for the encoding field.
+ * Bump proto version when changing this. */
+enum drbd_bitmap_code {
+ /* RLE_VLI_Bytes = 0,
+ * and other bit variants had been defined during
+ * algorithm evaluation. */
+ RLE_VLI_Bits = 2,
+};
+
+struct p_compressed_bm {
+ /* (encoding & 0x0f): actual encoding, see enum drbd_bitmap_code
+ * (encoding & 0x80): polarity (set/unset) of first runlength
+ * ((encoding >> 4) & 0x07): pad_bits, number of trailing zero bits
+ * used to pad up to head.length bytes
+ */
+ u8 encoding;
+
+ u8 code[0];
+} __packed;
+
+struct p_delay_probe93 {
+ u32 seq_num; /* sequence number to match the two probe packets */
+ u32 offset; /* usecs the probe got sent after the reference time point */
+} __packed;
+
+/*
+ * Bitmap packets need to fit within a single page on the sender and receiver,
+ * so we are limited to 4 KiB (and not to PAGE_SIZE, which can be bigger).
+ */
+#define DRBD_SOCKET_BUFFER_SIZE 4096
+
+#endif /* __DRBD_PROTOCOL_H */
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index d073305ffd5e..18c76e84d540 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -44,6 +44,7 @@
#include <linux/string.h>
#include <linux/scatterlist.h>
#include "drbd_int.h"
+#include "drbd_protocol.h"
#include "drbd_req.h"
#include "drbd_vli.h"
@@ -61,11 +62,11 @@ enum finish_epoch {
FE_RECYCLED,
};
-static int drbd_do_features(struct drbd_tconn *tconn);
-static int drbd_do_auth(struct drbd_tconn *tconn);
-static int drbd_disconnected(struct drbd_conf *mdev);
+static int drbd_do_features(struct drbd_connection *connection);
+static int drbd_do_auth(struct drbd_connection *connection);
+static int drbd_disconnected(struct drbd_peer_device *);
-static enum finish_epoch drbd_may_finish_epoch(struct drbd_tconn *, struct drbd_epoch *, enum epoch_event);
+static enum finish_epoch drbd_may_finish_epoch(struct drbd_connection *, struct drbd_epoch *, enum epoch_event);
static int e_end_block(struct drbd_work *, int);
@@ -150,7 +151,7 @@ static void page_chain_add(struct page **head,
*head = chain_first;
}
-static struct page *__drbd_alloc_pages(struct drbd_conf *mdev,
+static struct page *__drbd_alloc_pages(struct drbd_device *device,
unsigned int number)
{
struct page *page = NULL;
@@ -196,41 +197,39 @@ static struct page *__drbd_alloc_pages(struct drbd_conf *mdev,
return NULL;
}
-static void reclaim_finished_net_peer_reqs(struct drbd_conf *mdev,
+static void reclaim_finished_net_peer_reqs(struct drbd_device *device,
struct list_head *to_be_freed)
{
- struct drbd_peer_request *peer_req;
- struct list_head *le, *tle;
+ struct drbd_peer_request *peer_req, *tmp;
/* The EEs are always appended to the end of the list. Since
they are sent in order over the wire, they have to finish
in order. As soon as we see the first not finished we can
stop to examine the list... */
- list_for_each_safe(le, tle, &mdev->net_ee) {
- peer_req = list_entry(le, struct drbd_peer_request, w.list);
+ list_for_each_entry_safe(peer_req, tmp, &device->net_ee, w.list) {
if (drbd_peer_req_has_active_page(peer_req))
break;
- list_move(le, to_be_freed);
+ list_move(&peer_req->w.list, to_be_freed);
}
}
-static void drbd_kick_lo_and_reclaim_net(struct drbd_conf *mdev)
+static void drbd_kick_lo_and_reclaim_net(struct drbd_device *device)
{
LIST_HEAD(reclaimed);
struct drbd_peer_request *peer_req, *t;
- spin_lock_irq(&mdev->tconn->req_lock);
- reclaim_finished_net_peer_reqs(mdev, &reclaimed);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
+ reclaim_finished_net_peer_reqs(device, &reclaimed);
+ spin_unlock_irq(&device->resource->req_lock);
list_for_each_entry_safe(peer_req, t, &reclaimed, w.list)
- drbd_free_net_peer_req(mdev, peer_req);
+ drbd_free_net_peer_req(device, peer_req);
}
/**
* drbd_alloc_pages() - Returns @number pages, retries forever (or until signalled)
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @number: number of pages requested
* @retry: whether to retry, if not enough pages are available right now
*
@@ -240,9 +239,10 @@ static void drbd_kick_lo_and_reclaim_net(struct drbd_conf *mdev)
*
* Returns a page chain linked via page->private.
*/
-struct page *drbd_alloc_pages(struct drbd_conf *mdev, unsigned int number,
+struct page *drbd_alloc_pages(struct drbd_peer_device *peer_device, unsigned int number,
bool retry)
{
+ struct drbd_device *device = peer_device->device;
struct page *page = NULL;
struct net_conf *nc;
DEFINE_WAIT(wait);
@@ -251,20 +251,20 @@ struct page *drbd_alloc_pages(struct drbd_conf *mdev, unsigned int number,
/* Yes, we may run up to @number over max_buffers. If we
* follow it strictly, the admin will get it wrong anyways. */
rcu_read_lock();
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(peer_device->connection->net_conf);
mxb = nc ? nc->max_buffers : 1000000;
rcu_read_unlock();
- if (atomic_read(&mdev->pp_in_use) < mxb)
- page = __drbd_alloc_pages(mdev, number);
+ if (atomic_read(&device->pp_in_use) < mxb)
+ page = __drbd_alloc_pages(device, number);
while (page == NULL) {
prepare_to_wait(&drbd_pp_wait, &wait, TASK_INTERRUPTIBLE);
- drbd_kick_lo_and_reclaim_net(mdev);
+ drbd_kick_lo_and_reclaim_net(device);
- if (atomic_read(&mdev->pp_in_use) < mxb) {
- page = __drbd_alloc_pages(mdev, number);
+ if (atomic_read(&device->pp_in_use) < mxb) {
+ page = __drbd_alloc_pages(device, number);
if (page)
break;
}
@@ -273,7 +273,7 @@ struct page *drbd_alloc_pages(struct drbd_conf *mdev, unsigned int number,
break;
if (signal_pending(current)) {
- dev_warn(DEV, "drbd_alloc_pages interrupted!\n");
+ drbd_warn(device, "drbd_alloc_pages interrupted!\n");
break;
}
@@ -282,17 +282,17 @@ struct page *drbd_alloc_pages(struct drbd_conf *mdev, unsigned int number,
finish_wait(&drbd_pp_wait, &wait);
if (page)
- atomic_add(number, &mdev->pp_in_use);
+ atomic_add(number, &device->pp_in_use);
return page;
}
/* Must not be used from irq, as that may deadlock: see drbd_alloc_pages.
- * Is also used from inside an other spin_lock_irq(&mdev->tconn->req_lock);
+ * Is also used from inside an other spin_lock_irq(&resource->req_lock);
* Either links the page chain back to the global pool,
* or returns all pages to the system. */
-static void drbd_free_pages(struct drbd_conf *mdev, struct page *page, int is_net)
+static void drbd_free_pages(struct drbd_device *device, struct page *page, int is_net)
{
- atomic_t *a = is_net ? &mdev->pp_in_use_by_net : &mdev->pp_in_use;
+ atomic_t *a = is_net ? &device->pp_in_use_by_net : &device->pp_in_use;
int i;
if (page == NULL)
@@ -310,7 +310,7 @@ static void drbd_free_pages(struct drbd_conf *mdev, struct page *page, int is_ne
}
i = atomic_sub_return(i, a);
if (i < 0)
- dev_warn(DEV, "ASSERTION FAILED: %s: %d < 0\n",
+ drbd_warn(device, "ASSERTION FAILED: %s: %d < 0\n",
is_net ? "pp_in_use_by_net" : "pp_in_use", i);
wake_up(&drbd_pp_wait);
}
@@ -330,25 +330,26 @@ You must not have the req_lock:
*/
struct drbd_peer_request *
-drbd_alloc_peer_req(struct drbd_conf *mdev, u64 id, sector_t sector,
+drbd_alloc_peer_req(struct drbd_peer_device *peer_device, u64 id, sector_t sector,
unsigned int data_size, gfp_t gfp_mask) __must_hold(local)
{
+ struct drbd_device *device = peer_device->device;
struct drbd_peer_request *peer_req;
struct page *page = NULL;
unsigned nr_pages = (data_size + PAGE_SIZE -1) >> PAGE_SHIFT;
- if (drbd_insert_fault(mdev, DRBD_FAULT_AL_EE))
+ if (drbd_insert_fault(device, DRBD_FAULT_AL_EE))
return NULL;
peer_req = mempool_alloc(drbd_ee_mempool, gfp_mask & ~__GFP_HIGHMEM);
if (!peer_req) {
if (!(gfp_mask & __GFP_NOWARN))
- dev_err(DEV, "%s: allocation failed\n", __func__);
+ drbd_err(device, "%s: allocation failed\n", __func__);
return NULL;
}
if (data_size) {
- page = drbd_alloc_pages(mdev, nr_pages, (gfp_mask & __GFP_WAIT));
+ page = drbd_alloc_pages(peer_device, nr_pages, (gfp_mask & __GFP_WAIT));
if (!page)
goto fail;
}
@@ -360,7 +361,7 @@ drbd_alloc_peer_req(struct drbd_conf *mdev, u64 id, sector_t sector,
peer_req->i.waiting = false;
peer_req->epoch = NULL;
- peer_req->w.mdev = mdev;
+ peer_req->peer_device = peer_device;
peer_req->pages = page;
atomic_set(&peer_req->pending_bios, 0);
peer_req->flags = 0;
@@ -377,30 +378,30 @@ drbd_alloc_peer_req(struct drbd_conf *mdev, u64 id, sector_t sector,
return NULL;
}
-void __drbd_free_peer_req(struct drbd_conf *mdev, struct drbd_peer_request *peer_req,
+void __drbd_free_peer_req(struct drbd_device *device, struct drbd_peer_request *peer_req,
int is_net)
{
if (peer_req->flags & EE_HAS_DIGEST)
kfree(peer_req->digest);
- drbd_free_pages(mdev, peer_req->pages, is_net);
- D_ASSERT(atomic_read(&peer_req->pending_bios) == 0);
- D_ASSERT(drbd_interval_empty(&peer_req->i));
+ drbd_free_pages(device, peer_req->pages, is_net);
+ D_ASSERT(device, atomic_read(&peer_req->pending_bios) == 0);
+ D_ASSERT(device, drbd_interval_empty(&peer_req->i));
mempool_free(peer_req, drbd_ee_mempool);
}
-int drbd_free_peer_reqs(struct drbd_conf *mdev, struct list_head *list)
+int drbd_free_peer_reqs(struct drbd_device *device, struct list_head *list)
{
LIST_HEAD(work_list);
struct drbd_peer_request *peer_req, *t;
int count = 0;
- int is_net = list == &mdev->net_ee;
+ int is_net = list == &device->net_ee;
- spin_lock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
list_splice_init(list, &work_list);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
list_for_each_entry_safe(peer_req, t, &work_list, w.list) {
- __drbd_free_peer_req(mdev, peer_req, is_net);
+ __drbd_free_peer_req(device, peer_req, is_net);
count++;
}
return count;
@@ -409,20 +410,20 @@ int drbd_free_peer_reqs(struct drbd_conf *mdev, struct list_head *list)
/*
* See also comments in _req_mod(,BARRIER_ACKED) and receive_Barrier.
*/
-static int drbd_finish_peer_reqs(struct drbd_conf *mdev)
+static int drbd_finish_peer_reqs(struct drbd_device *device)
{
LIST_HEAD(work_list);
LIST_HEAD(reclaimed);
struct drbd_peer_request *peer_req, *t;
int err = 0;
- spin_lock_irq(&mdev->tconn->req_lock);
- reclaim_finished_net_peer_reqs(mdev, &reclaimed);
- list_splice_init(&mdev->done_ee, &work_list);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
+ reclaim_finished_net_peer_reqs(device, &reclaimed);
+ list_splice_init(&device->done_ee, &work_list);
+ spin_unlock_irq(&device->resource->req_lock);
list_for_each_entry_safe(peer_req, t, &reclaimed, w.list)
- drbd_free_net_peer_req(mdev, peer_req);
+ drbd_free_net_peer_req(device, peer_req);
/* possible callbacks here:
* e_end_block, and e_end_resync_block, e_send_superseded.
@@ -435,14 +436,14 @@ static int drbd_finish_peer_reqs(struct drbd_conf *mdev)
err2 = peer_req->w.cb(&peer_req->w, !!err);
if (!err)
err = err2;
- drbd_free_peer_req(mdev, peer_req);
+ drbd_free_peer_req(device, peer_req);
}
- wake_up(&mdev->ee_wait);
+ wake_up(&device->ee_wait);
return err;
}
-static void _drbd_wait_ee_list_empty(struct drbd_conf *mdev,
+static void _drbd_wait_ee_list_empty(struct drbd_device *device,
struct list_head *head)
{
DEFINE_WAIT(wait);
@@ -450,20 +451,20 @@ static void _drbd_wait_ee_list_empty(struct drbd_conf *mdev,
/* avoids spin_lock/unlock
* and calling prepare_to_wait in the fast path */
while (!list_empty(head)) {
- prepare_to_wait(&mdev->ee_wait, &wait, TASK_UNINTERRUPTIBLE);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ prepare_to_wait(&device->ee_wait, &wait, TASK_UNINTERRUPTIBLE);
+ spin_unlock_irq(&device->resource->req_lock);
io_schedule();
- finish_wait(&mdev->ee_wait, &wait);
- spin_lock_irq(&mdev->tconn->req_lock);
+ finish_wait(&device->ee_wait, &wait);
+ spin_lock_irq(&device->resource->req_lock);
}
}
-static void drbd_wait_ee_list_empty(struct drbd_conf *mdev,
+static void drbd_wait_ee_list_empty(struct drbd_device *device,
struct list_head *head)
{
- spin_lock_irq(&mdev->tconn->req_lock);
- _drbd_wait_ee_list_empty(mdev, head);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
+ _drbd_wait_ee_list_empty(device, head);
+ spin_unlock_irq(&device->resource->req_lock);
}
static int drbd_recv_short(struct socket *sock, void *buf, size_t size, int flags)
@@ -488,44 +489,44 @@ static int drbd_recv_short(struct socket *sock, void *buf, size_t size, int flag
return rv;
}
-static int drbd_recv(struct drbd_tconn *tconn, void *buf, size_t size)
+static int drbd_recv(struct drbd_connection *connection, void *buf, size_t size)
{
int rv;
- rv = drbd_recv_short(tconn->data.socket, buf, size, 0);
+ rv = drbd_recv_short(connection->data.socket, buf, size, 0);
if (rv < 0) {
if (rv == -ECONNRESET)
- conn_info(tconn, "sock was reset by peer\n");
+ drbd_info(connection, "sock was reset by peer\n");
else if (rv != -ERESTARTSYS)
- conn_err(tconn, "sock_recvmsg returned %d\n", rv);
+ drbd_err(connection, "sock_recvmsg returned %d\n", rv);
} else if (rv == 0) {
- if (test_bit(DISCONNECT_SENT, &tconn->flags)) {
+ if (test_bit(DISCONNECT_SENT, &connection->flags)) {
long t;
rcu_read_lock();
- t = rcu_dereference(tconn->net_conf)->ping_timeo * HZ/10;
+ t = rcu_dereference(connection->net_conf)->ping_timeo * HZ/10;
rcu_read_unlock();
- t = wait_event_timeout(tconn->ping_wait, tconn->cstate < C_WF_REPORT_PARAMS, t);
+ t = wait_event_timeout(connection->ping_wait, connection->cstate < C_WF_REPORT_PARAMS, t);
if (t)
goto out;
}
- conn_info(tconn, "sock was shut down by peer\n");
+ drbd_info(connection, "sock was shut down by peer\n");
}
if (rv != size)
- conn_request_state(tconn, NS(conn, C_BROKEN_PIPE), CS_HARD);
+ conn_request_state(connection, NS(conn, C_BROKEN_PIPE), CS_HARD);
out:
return rv;
}
-static int drbd_recv_all(struct drbd_tconn *tconn, void *buf, size_t size)
+static int drbd_recv_all(struct drbd_connection *connection, void *buf, size_t size)
{
int err;
- err = drbd_recv(tconn, buf, size);
+ err = drbd_recv(connection, buf, size);
if (err != size) {
if (err >= 0)
err = -EIO;
@@ -534,13 +535,13 @@ static int drbd_recv_all(struct drbd_tconn *tconn, void *buf, size_t size)
return err;
}
-static int drbd_recv_all_warn(struct drbd_tconn *tconn, void *buf, size_t size)
+static int drbd_recv_all_warn(struct drbd_connection *connection, void *buf, size_t size)
{
int err;
- err = drbd_recv_all(tconn, buf, size);
+ err = drbd_recv_all(connection, buf, size);
if (err && !signal_pending(current))
- conn_warn(tconn, "short read (expected size %d)\n", (int)size);
+ drbd_warn(connection, "short read (expected size %d)\n", (int)size);
return err;
}
@@ -563,7 +564,7 @@ static void drbd_setbufsize(struct socket *sock, unsigned int snd,
}
}
-static struct socket *drbd_try_connect(struct drbd_tconn *tconn)
+static struct socket *drbd_try_connect(struct drbd_connection *connection)
{
const char *what;
struct socket *sock;
@@ -575,7 +576,7 @@ static struct socket *drbd_try_connect(struct drbd_tconn *tconn)
int disconnect_on_error = 1;
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
+ nc = rcu_dereference(connection->net_conf);
if (!nc) {
rcu_read_unlock();
return NULL;
@@ -585,16 +586,16 @@ static struct socket *drbd_try_connect(struct drbd_tconn *tconn)
connect_int = nc->connect_int;
rcu_read_unlock();
- my_addr_len = min_t(int, tconn->my_addr_len, sizeof(src_in6));
- memcpy(&src_in6, &tconn->my_addr, my_addr_len);
+ my_addr_len = min_t(int, connection->my_addr_len, sizeof(src_in6));
+ memcpy(&src_in6, &connection->my_addr, my_addr_len);
- if (((struct sockaddr *)&tconn->my_addr)->sa_family == AF_INET6)
+ if (((struct sockaddr *)&connection->my_addr)->sa_family == AF_INET6)
src_in6.sin6_port = 0;
else
((struct sockaddr_in *)&src_in6)->sin_port = 0; /* AF_INET & AF_SCI */
- peer_addr_len = min_t(int, tconn->peer_addr_len, sizeof(src_in6));
- memcpy(&peer_in6, &tconn->peer_addr, peer_addr_len);
+ peer_addr_len = min_t(int, connection->peer_addr_len, sizeof(src_in6));
+ memcpy(&peer_in6, &connection->peer_addr, peer_addr_len);
what = "sock_create_kern";
err = sock_create_kern(((struct sockaddr *)&src_in6)->sa_family,
@@ -642,17 +643,17 @@ out:
disconnect_on_error = 0;
break;
default:
- conn_err(tconn, "%s failed, err = %d\n", what, err);
+ drbd_err(connection, "%s failed, err = %d\n", what, err);
}
if (disconnect_on_error)
- conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ conn_request_state(connection, NS(conn, C_DISCONNECTING), CS_HARD);
}
return sock;
}
struct accept_wait_data {
- struct drbd_tconn *tconn;
+ struct drbd_connection *connection;
struct socket *s_listen;
struct completion door_bell;
void (*original_sk_state_change)(struct sock *sk);
@@ -670,7 +671,7 @@ static void drbd_incoming_connection(struct sock *sk)
state_change(sk);
}
-static int prepare_listen_socket(struct drbd_tconn *tconn, struct accept_wait_data *ad)
+static int prepare_listen_socket(struct drbd_connection *connection, struct accept_wait_data *ad)
{
int err, sndbuf_size, rcvbuf_size, my_addr_len;
struct sockaddr_in6 my_addr;
@@ -679,7 +680,7 @@ static int prepare_listen_socket(struct drbd_tconn *tconn, struct accept_wait_da
const char *what;
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
+ nc = rcu_dereference(connection->net_conf);
if (!nc) {
rcu_read_unlock();
return -EIO;
@@ -688,8 +689,8 @@ static int prepare_listen_socket(struct drbd_tconn *tconn, struct accept_wait_da
rcvbuf_size = nc->rcvbuf_size;
rcu_read_unlock();
- my_addr_len = min_t(int, tconn->my_addr_len, sizeof(struct sockaddr_in6));
- memcpy(&my_addr, &tconn->my_addr, my_addr_len);
+ my_addr_len = min_t(int, connection->my_addr_len, sizeof(struct sockaddr_in6));
+ memcpy(&my_addr, &connection->my_addr, my_addr_len);
what = "sock_create_kern";
err = sock_create_kern(((struct sockaddr *)&my_addr)->sa_family,
@@ -725,8 +726,8 @@ out:
sock_release(s_listen);
if (err < 0) {
if (err != -EAGAIN && err != -EINTR && err != -ERESTARTSYS) {
- conn_err(tconn, "%s failed, err = %d\n", what, err);
- conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ drbd_err(connection, "%s failed, err = %d\n", what, err);
+ conn_request_state(connection, NS(conn, C_DISCONNECTING), CS_HARD);
}
}
@@ -741,14 +742,14 @@ static void unregister_state_change(struct sock *sk, struct accept_wait_data *ad
write_unlock_bh(&sk->sk_callback_lock);
}
-static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn, struct accept_wait_data *ad)
+static struct socket *drbd_wait_for_connect(struct drbd_connection *connection, struct accept_wait_data *ad)
{
int timeo, connect_int, err = 0;
struct socket *s_estab = NULL;
struct net_conf *nc;
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
+ nc = rcu_dereference(connection->net_conf);
if (!nc) {
rcu_read_unlock();
return NULL;
@@ -767,8 +768,8 @@ static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn, struct acc
err = kernel_accept(ad->s_listen, &s_estab, 0);
if (err < 0) {
if (err != -EAGAIN && err != -EINTR && err != -ERESTARTSYS) {
- conn_err(tconn, "accept failed, err = %d\n", err);
- conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ drbd_err(connection, "accept failed, err = %d\n", err);
+ conn_request_state(connection, NS(conn, C_DISCONNECTING), CS_HARD);
}
}
@@ -778,29 +779,29 @@ static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn, struct acc
return s_estab;
}
-static int decode_header(struct drbd_tconn *, void *, struct packet_info *);
+static int decode_header(struct drbd_connection *, void *, struct packet_info *);
-static int send_first_packet(struct drbd_tconn *tconn, struct drbd_socket *sock,
+static int send_first_packet(struct drbd_connection *connection, struct drbd_socket *sock,
enum drbd_packet cmd)
{
- if (!conn_prepare_command(tconn, sock))
+ if (!conn_prepare_command(connection, sock))
return -EIO;
- return conn_send_command(tconn, sock, cmd, 0, NULL, 0);
+ return conn_send_command(connection, sock, cmd, 0, NULL, 0);
}
-static int receive_first_packet(struct drbd_tconn *tconn, struct socket *sock)
+static int receive_first_packet(struct drbd_connection *connection, struct socket *sock)
{
- unsigned int header_size = drbd_header_size(tconn);
+ unsigned int header_size = drbd_header_size(connection);
struct packet_info pi;
int err;
- err = drbd_recv_short(sock, tconn->data.rbuf, header_size, 0);
+ err = drbd_recv_short(sock, connection->data.rbuf, header_size, 0);
if (err != header_size) {
if (err >= 0)
err = -EIO;
return err;
}
- err = decode_header(tconn, tconn->data.rbuf, &pi);
+ err = decode_header(connection, connection->data.rbuf, &pi);
if (err)
return err;
return pi.cmd;
@@ -830,28 +831,29 @@ static int drbd_socket_okay(struct socket **sock)
}
/* Gets called if a connection is established, or if a new minor gets created
in a connection */
-int drbd_connected(struct drbd_conf *mdev)
+int drbd_connected(struct drbd_peer_device *peer_device)
{
+ struct drbd_device *device = peer_device->device;
int err;
- atomic_set(&mdev->packet_seq, 0);
- mdev->peer_seq = 0;
+ atomic_set(&device->packet_seq, 0);
+ device->peer_seq = 0;
- mdev->state_mutex = mdev->tconn->agreed_pro_version < 100 ?
- &mdev->tconn->cstate_mutex :
- &mdev->own_state_mutex;
+ device->state_mutex = peer_device->connection->agreed_pro_version < 100 ?
+ &peer_device->connection->cstate_mutex :
+ &device->own_state_mutex;
- err = drbd_send_sync_param(mdev);
+ err = drbd_send_sync_param(peer_device);
if (!err)
- err = drbd_send_sizes(mdev, 0, 0);
+ err = drbd_send_sizes(peer_device, 0, 0);
if (!err)
- err = drbd_send_uuids(mdev);
+ err = drbd_send_uuids(peer_device);
if (!err)
- err = drbd_send_current_state(mdev);
- clear_bit(USE_DEGR_WFC_T, &mdev->flags);
- clear_bit(RESIZE_PENDING, &mdev->flags);
- atomic_set(&mdev->ap_in_flight, 0);
- mod_timer(&mdev->request_timer, jiffies + HZ); /* just start it here. */
+ err = drbd_send_current_state(peer_device);
+ clear_bit(USE_DEGR_WFC_T, &device->flags);
+ clear_bit(RESIZE_PENDING, &device->flags);
+ atomic_set(&device->ap_in_flight, 0);
+ mod_timer(&device->request_timer, jiffies + HZ); /* just start it here. */
return err;
}
@@ -863,59 +865,59 @@ int drbd_connected(struct drbd_conf *mdev)
* no point in trying again, please go standalone.
* -2 We do not have a network config...
*/
-static int conn_connect(struct drbd_tconn *tconn)
+static int conn_connect(struct drbd_connection *connection)
{
struct drbd_socket sock, msock;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
struct net_conf *nc;
int vnr, timeout, h, ok;
bool discard_my_data;
enum drbd_state_rv rv;
struct accept_wait_data ad = {
- .tconn = tconn,
+ .connection = connection,
.door_bell = COMPLETION_INITIALIZER_ONSTACK(ad.door_bell),
};
- clear_bit(DISCONNECT_SENT, &tconn->flags);
- if (conn_request_state(tconn, NS(conn, C_WF_CONNECTION), CS_VERBOSE) < SS_SUCCESS)
+ clear_bit(DISCONNECT_SENT, &connection->flags);
+ if (conn_request_state(connection, NS(conn, C_WF_CONNECTION), CS_VERBOSE) < SS_SUCCESS)
return -2;
mutex_init(&sock.mutex);
- sock.sbuf = tconn->data.sbuf;
- sock.rbuf = tconn->data.rbuf;
+ sock.sbuf = connection->data.sbuf;
+ sock.rbuf = connection->data.rbuf;
sock.socket = NULL;
mutex_init(&msock.mutex);
- msock.sbuf = tconn->meta.sbuf;
- msock.rbuf = tconn->meta.rbuf;
+ msock.sbuf = connection->meta.sbuf;
+ msock.rbuf = connection->meta.rbuf;
msock.socket = NULL;
/* Assume that the peer only understands protocol 80 until we know better. */
- tconn->agreed_pro_version = 80;
+ connection->agreed_pro_version = 80;
- if (prepare_listen_socket(tconn, &ad))
+ if (prepare_listen_socket(connection, &ad))
return 0;
do {
struct socket *s;
- s = drbd_try_connect(tconn);
+ s = drbd_try_connect(connection);
if (s) {
if (!sock.socket) {
sock.socket = s;
- send_first_packet(tconn, &sock, P_INITIAL_DATA);
+ send_first_packet(connection, &sock, P_INITIAL_DATA);
} else if (!msock.socket) {
- clear_bit(RESOLVE_CONFLICTS, &tconn->flags);
+ clear_bit(RESOLVE_CONFLICTS, &connection->flags);
msock.socket = s;
- send_first_packet(tconn, &msock, P_INITIAL_META);
+ send_first_packet(connection, &msock, P_INITIAL_META);
} else {
- conn_err(tconn, "Logic error in conn_connect()\n");
+ drbd_err(connection, "Logic error in conn_connect()\n");
goto out_release_sockets;
}
}
if (sock.socket && msock.socket) {
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
+ nc = rcu_dereference(connection->net_conf);
timeout = nc->ping_timeo * HZ / 10;
rcu_read_unlock();
schedule_timeout_interruptible(timeout);
@@ -926,15 +928,15 @@ static int conn_connect(struct drbd_tconn *tconn)
}
retry:
- s = drbd_wait_for_connect(tconn, &ad);
+ s = drbd_wait_for_connect(connection, &ad);
if (s) {
- int fp = receive_first_packet(tconn, s);
+ int fp = receive_first_packet(connection, s);
drbd_socket_okay(&sock.socket);
drbd_socket_okay(&msock.socket);
switch (fp) {
case P_INITIAL_DATA:
if (sock.socket) {
- conn_warn(tconn, "initial packet S crossed\n");
+ drbd_warn(connection, "initial packet S crossed\n");
sock_release(sock.socket);
sock.socket = s;
goto randomize;
@@ -942,9 +944,9 @@ retry:
sock.socket = s;
break;
case P_INITIAL_META:
- set_bit(RESOLVE_CONFLICTS, &tconn->flags);
+ set_bit(RESOLVE_CONFLICTS, &connection->flags);
if (msock.socket) {
- conn_warn(tconn, "initial packet M crossed\n");
+ drbd_warn(connection, "initial packet M crossed\n");
sock_release(msock.socket);
msock.socket = s;
goto randomize;
@@ -952,7 +954,7 @@ retry:
msock.socket = s;
break;
default:
- conn_warn(tconn, "Error receiving initial packet\n");
+ drbd_warn(connection, "Error receiving initial packet\n");
sock_release(s);
randomize:
if (prandom_u32() & 1)
@@ -960,12 +962,12 @@ randomize:
}
}
- if (tconn->cstate <= C_DISCONNECTING)
+ if (connection->cstate <= C_DISCONNECTING)
goto out_release_sockets;
if (signal_pending(current)) {
flush_signals(current);
smp_rmb();
- if (get_t_state(&tconn->receiver) == EXITING)
+ if (get_t_state(&connection->receiver) == EXITING)
goto out_release_sockets;
}
@@ -986,12 +988,12 @@ randomize:
msock.socket->sk->sk_priority = TC_PRIO_INTERACTIVE;
/* NOT YET ...
- * sock.socket->sk->sk_sndtimeo = tconn->net_conf->timeout*HZ/10;
+ * sock.socket->sk->sk_sndtimeo = connection->net_conf->timeout*HZ/10;
* sock.socket->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT;
* first set it to the P_CONNECTION_FEATURES timeout,
* which we set to 4x the configured ping_timeout. */
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
+ nc = rcu_dereference(connection->net_conf);
sock.socket->sk->sk_sndtimeo =
sock.socket->sk->sk_rcvtimeo = nc->ping_timeo*4*HZ/10;
@@ -1008,37 +1010,38 @@ randomize:
drbd_tcp_nodelay(sock.socket);
drbd_tcp_nodelay(msock.socket);
- tconn->data.socket = sock.socket;
- tconn->meta.socket = msock.socket;
- tconn->last_received = jiffies;
+ connection->data.socket = sock.socket;
+ connection->meta.socket = msock.socket;
+ connection->last_received = jiffies;
- h = drbd_do_features(tconn);
+ h = drbd_do_features(connection);
if (h <= 0)
return h;
- if (tconn->cram_hmac_tfm) {
- /* drbd_request_state(mdev, NS(conn, WFAuth)); */
- switch (drbd_do_auth(tconn)) {
+ if (connection->cram_hmac_tfm) {
+ /* drbd_request_state(device, NS(conn, WFAuth)); */
+ switch (drbd_do_auth(connection)) {
case -1:
- conn_err(tconn, "Authentication of peer failed\n");
+ drbd_err(connection, "Authentication of peer failed\n");
return -1;
case 0:
- conn_err(tconn, "Authentication of peer failed, trying again.\n");
+ drbd_err(connection, "Authentication of peer failed, trying again.\n");
return 0;
}
}
- tconn->data.socket->sk->sk_sndtimeo = timeout;
- tconn->data.socket->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT;
+ connection->data.socket->sk->sk_sndtimeo = timeout;
+ connection->data.socket->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT;
- if (drbd_send_protocol(tconn) == -EOPNOTSUPP)
+ if (drbd_send_protocol(connection) == -EOPNOTSUPP)
return -1;
- set_bit(STATE_SENT, &tconn->flags);
+ set_bit(STATE_SENT, &connection->flags);
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- kref_get(&mdev->kref);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ kref_get(&device->kref);
rcu_read_unlock();
/* Prevent a race between resync-handshake and
@@ -1048,35 +1051,35 @@ randomize:
* drbd_set_role() is finished, and any incoming drbd_set_role
* will see the STATE_SENT flag, and wait for it to be cleared.
*/
- mutex_lock(mdev->state_mutex);
- mutex_unlock(mdev->state_mutex);
+ mutex_lock(device->state_mutex);
+ mutex_unlock(device->state_mutex);
if (discard_my_data)
- set_bit(DISCARD_MY_DATA, &mdev->flags);
+ set_bit(DISCARD_MY_DATA, &device->flags);
else
- clear_bit(DISCARD_MY_DATA, &mdev->flags);
+ clear_bit(DISCARD_MY_DATA, &device->flags);
- drbd_connected(mdev);
- kref_put(&mdev->kref, &drbd_minor_destroy);
+ drbd_connected(peer_device);
+ kref_put(&device->kref, drbd_destroy_device);
rcu_read_lock();
}
rcu_read_unlock();
- rv = conn_request_state(tconn, NS(conn, C_WF_REPORT_PARAMS), CS_VERBOSE);
- if (rv < SS_SUCCESS || tconn->cstate != C_WF_REPORT_PARAMS) {
- clear_bit(STATE_SENT, &tconn->flags);
+ rv = conn_request_state(connection, NS(conn, C_WF_REPORT_PARAMS), CS_VERBOSE);
+ if (rv < SS_SUCCESS || connection->cstate != C_WF_REPORT_PARAMS) {
+ clear_bit(STATE_SENT, &connection->flags);
return 0;
}
- drbd_thread_start(&tconn->asender);
+ drbd_thread_start(&connection->asender);
- mutex_lock(&tconn->conf_update);
+ mutex_lock(&connection->resource->conf_update);
/* The discard_my_data flag is a single-shot modifier to the next
* connection attempt, the handshake of which is now well underway.
* No need for rcu style copying of the whole struct
* just to clear a single value. */
- tconn->net_conf->discard_my_data = 0;
- mutex_unlock(&tconn->conf_update);
+ connection->net_conf->discard_my_data = 0;
+ mutex_unlock(&connection->resource->conf_update);
return h;
@@ -1090,15 +1093,15 @@ out_release_sockets:
return -1;
}
-static int decode_header(struct drbd_tconn *tconn, void *header, struct packet_info *pi)
+static int decode_header(struct drbd_connection *connection, void *header, struct packet_info *pi)
{
- unsigned int header_size = drbd_header_size(tconn);
+ unsigned int header_size = drbd_header_size(connection);
if (header_size == sizeof(struct p_header100) &&
*(__be32 *)header == cpu_to_be32(DRBD_MAGIC_100)) {
struct p_header100 *h = header;
if (h->pad != 0) {
- conn_err(tconn, "Header padding is not zero\n");
+ drbd_err(connection, "Header padding is not zero\n");
return -EINVAL;
}
pi->vnr = be16_to_cpu(h->volume);
@@ -1117,55 +1120,57 @@ static int decode_header(struct drbd_tconn *tconn, void *header, struct packet_i
pi->size = be16_to_cpu(h->length);
pi->vnr = 0;
} else {
- conn_err(tconn, "Wrong magic value 0x%08x in protocol version %d\n",
+ drbd_err(connection, "Wrong magic value 0x%08x in protocol version %d\n",
be32_to_cpu(*(__be32 *)header),
- tconn->agreed_pro_version);
+ connection->agreed_pro_version);
return -EINVAL;
}
pi->data = header + header_size;
return 0;
}
-static int drbd_recv_header(struct drbd_tconn *tconn, struct packet_info *pi)
+static int drbd_recv_header(struct drbd_connection *connection, struct packet_info *pi)
{
- void *buffer = tconn->data.rbuf;
+ void *buffer = connection->data.rbuf;
int err;
- err = drbd_recv_all_warn(tconn, buffer, drbd_header_size(tconn));
+ err = drbd_recv_all_warn(connection, buffer, drbd_header_size(connection));
if (err)
return err;
- err = decode_header(tconn, buffer, pi);
- tconn->last_received = jiffies;
+ err = decode_header(connection, buffer, pi);
+ connection->last_received = jiffies;
return err;
}
-static void drbd_flush(struct drbd_tconn *tconn)
+static void drbd_flush(struct drbd_connection *connection)
{
int rv;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
- if (tconn->write_ordering >= WO_bdev_flush) {
+ if (connection->write_ordering >= WO_bdev_flush) {
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- if (!get_ldev(mdev))
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+
+ if (!get_ldev(device))
continue;
- kref_get(&mdev->kref);
+ kref_get(&device->kref);
rcu_read_unlock();
- rv = blkdev_issue_flush(mdev->ldev->backing_bdev,
+ rv = blkdev_issue_flush(device->ldev->backing_bdev,
GFP_NOIO, NULL);
if (rv) {
- dev_info(DEV, "local disk flush failed with status %d\n", rv);
+ drbd_info(device, "local disk flush failed with status %d\n", rv);
/* would rather check on EOPNOTSUPP, but that is not reliable.
* don't try again for ANY return value != 0
* if (rv == -EOPNOTSUPP) */
- drbd_bump_write_ordering(tconn, WO_drain_io);
+ drbd_bump_write_ordering(connection, WO_drain_io);
}
- put_ldev(mdev);
- kref_put(&mdev->kref, &drbd_minor_destroy);
+ put_ldev(device);
+ kref_put(&device->kref, drbd_destroy_device);
rcu_read_lock();
if (rv)
@@ -1177,11 +1182,11 @@ static void drbd_flush(struct drbd_tconn *tconn)
/**
* drbd_may_finish_epoch() - Applies an epoch_event to the epoch's state, eventually finishes it.
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @epoch: Epoch object.
* @ev: Epoch event.
*/
-static enum finish_epoch drbd_may_finish_epoch(struct drbd_tconn *tconn,
+static enum finish_epoch drbd_may_finish_epoch(struct drbd_connection *connection,
struct drbd_epoch *epoch,
enum epoch_event ev)
{
@@ -1189,7 +1194,7 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_tconn *tconn,
struct drbd_epoch *next_epoch;
enum finish_epoch rv = FE_STILL_LIVE;
- spin_lock(&tconn->epoch_lock);
+ spin_lock(&connection->epoch_lock);
do {
next_epoch = NULL;
@@ -1211,22 +1216,22 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_tconn *tconn,
atomic_read(&epoch->active) == 0 &&
(test_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags) || ev & EV_CLEANUP)) {
if (!(ev & EV_CLEANUP)) {
- spin_unlock(&tconn->epoch_lock);
- drbd_send_b_ack(epoch->tconn, epoch->barrier_nr, epoch_size);
- spin_lock(&tconn->epoch_lock);
+ spin_unlock(&connection->epoch_lock);
+ drbd_send_b_ack(epoch->connection, epoch->barrier_nr, epoch_size);
+ spin_lock(&connection->epoch_lock);
}
#if 0
/* FIXME: dec unacked on connection, once we have
* something to count pending connection packets in. */
if (test_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags))
- dec_unacked(epoch->tconn);
+ dec_unacked(epoch->connection);
#endif
- if (tconn->current_epoch != epoch) {
+ if (connection->current_epoch != epoch) {
next_epoch = list_entry(epoch->list.next, struct drbd_epoch, list);
list_del(&epoch->list);
ev = EV_BECAME_LAST | (ev & EV_CLEANUP);
- tconn->epochs--;
+ connection->epochs--;
kfree(epoch);
if (rv == FE_STILL_LIVE)
@@ -1246,20 +1251,20 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_tconn *tconn,
epoch = next_epoch;
} while (1);
- spin_unlock(&tconn->epoch_lock);
+ spin_unlock(&connection->epoch_lock);
return rv;
}
/**
* drbd_bump_write_ordering() - Fall back to an other write ordering method
- * @tconn: DRBD connection.
+ * @connection: DRBD connection.
* @wo: Write ordering method to try.
*/
-void drbd_bump_write_ordering(struct drbd_tconn *tconn, enum write_ordering_e wo)
+void drbd_bump_write_ordering(struct drbd_connection *connection, enum write_ordering_e wo)
{
struct disk_conf *dc;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
enum write_ordering_e pwo;
int vnr;
static char *write_ordering_str[] = {
@@ -1268,29 +1273,31 @@ void drbd_bump_write_ordering(struct drbd_tconn *tconn, enum write_ordering_e wo
[WO_bdev_flush] = "flush",
};
- pwo = tconn->write_ordering;
+ pwo = connection->write_ordering;
wo = min(pwo, wo);
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- if (!get_ldev_if_state(mdev, D_ATTACHING))
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+
+ if (!get_ldev_if_state(device, D_ATTACHING))
continue;
- dc = rcu_dereference(mdev->ldev->disk_conf);
+ dc = rcu_dereference(device->ldev->disk_conf);
if (wo == WO_bdev_flush && !dc->disk_flushes)
wo = WO_drain_io;
if (wo == WO_drain_io && !dc->disk_drain)
wo = WO_none;
- put_ldev(mdev);
+ put_ldev(device);
}
rcu_read_unlock();
- tconn->write_ordering = wo;
- if (pwo != tconn->write_ordering || wo == WO_bdev_flush)
- conn_info(tconn, "Method to ensure write ordering: %s\n", write_ordering_str[tconn->write_ordering]);
+ connection->write_ordering = wo;
+ if (pwo != connection->write_ordering || wo == WO_bdev_flush)
+ drbd_info(connection, "Method to ensure write ordering: %s\n", write_ordering_str[connection->write_ordering]);
}
/**
* drbd_submit_peer_request()
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @peer_req: peer request
* @rw: flag field, see bio->bi_rw
*
@@ -1305,7 +1312,7 @@ void drbd_bump_write_ordering(struct drbd_tconn *tconn, enum write_ordering_e wo
* on certain Xen deployments.
*/
/* TODO allocate from our own bio_set. */
-int drbd_submit_peer_request(struct drbd_conf *mdev,
+int drbd_submit_peer_request(struct drbd_device *device,
struct drbd_peer_request *peer_req,
const unsigned rw, const int fault_type)
{
@@ -1329,12 +1336,12 @@ int drbd_submit_peer_request(struct drbd_conf *mdev,
next_bio:
bio = bio_alloc(GFP_NOIO, nr_pages);
if (!bio) {
- dev_err(DEV, "submit_ee: Allocation of a bio failed\n");
+ drbd_err(device, "submit_ee: Allocation of a bio failed\n");
goto fail;
}
/* > peer_req->i.sector, unless this is the first bio */
bio->bi_iter.bi_sector = sector;
- bio->bi_bdev = mdev->ldev->backing_bdev;
+ bio->bi_bdev = device->ldev->backing_bdev;
bio->bi_rw = rw;
bio->bi_private = peer_req;
bio->bi_end_io = drbd_peer_request_endio;
@@ -1350,7 +1357,7 @@ next_bio:
* But in case it fails anyways,
* we deal with it, and complain (below). */
if (bio->bi_vcnt == 0) {
- dev_err(DEV,
+ drbd_err(device,
"bio_add_page failed for len=%u, "
"bi_vcnt=0 (bi_sector=%llu)\n",
len, (uint64_t)bio->bi_iter.bi_sector);
@@ -1363,8 +1370,8 @@ next_bio:
sector += len >> 9;
--nr_pages;
}
- D_ASSERT(page == NULL);
- D_ASSERT(ds == 0);
+ D_ASSERT(device, page == NULL);
+ D_ASSERT(device, ds == 0);
atomic_set(&peer_req->pending_bios, n_bios);
do {
@@ -1372,7 +1379,7 @@ next_bio:
bios = bios->bi_next;
bio->bi_next = NULL;
- drbd_generic_make_request(mdev, fault_type, bio);
+ drbd_generic_make_request(device, fault_type, bio);
} while (bios);
return 0;
@@ -1385,36 +1392,44 @@ fail:
return err;
}
-static void drbd_remove_epoch_entry_interval(struct drbd_conf *mdev,
+static void drbd_remove_epoch_entry_interval(struct drbd_device *device,
struct drbd_peer_request *peer_req)
{
struct drbd_interval *i = &peer_req->i;
- drbd_remove_interval(&mdev->write_requests, i);
+ drbd_remove_interval(&device->write_requests, i);
drbd_clear_interval(i);
/* Wake up any processes waiting for this peer request to complete. */
if (i->waiting)
- wake_up(&mdev->misc_wait);
+ wake_up(&device->misc_wait);
}
-void conn_wait_active_ee_empty(struct drbd_tconn *tconn)
+static void conn_wait_active_ee_empty(struct drbd_connection *connection)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- kref_get(&mdev->kref);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+
+ kref_get(&device->kref);
rcu_read_unlock();
- drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
- kref_put(&mdev->kref, &drbd_minor_destroy);
+ drbd_wait_ee_list_empty(device, &device->active_ee);
+ kref_put(&device->kref, drbd_destroy_device);
rcu_read_lock();
}
rcu_read_unlock();
}
-static int receive_Barrier(struct drbd_tconn *tconn, struct packet_info *pi)
+static struct drbd_peer_device *
+conn_peer_device(struct drbd_connection *connection, int volume_number)
+{
+ return idr_find(&connection->peer_devices, volume_number);
+}
+
+static int receive_Barrier(struct drbd_connection *connection, struct packet_info *pi)
{
int rv;
struct p_barrier *p = pi->data;
@@ -1423,16 +1438,16 @@ static int receive_Barrier(struct drbd_tconn *tconn, struct packet_info *pi)
/* FIXME these are unacked on connection,
* not a specific (peer)device.
*/
- tconn->current_epoch->barrier_nr = p->barrier;
- tconn->current_epoch->tconn = tconn;
- rv = drbd_may_finish_epoch(tconn, tconn->current_epoch, EV_GOT_BARRIER_NR);
+ connection->current_epoch->barrier_nr = p->barrier;
+ connection->current_epoch->connection = connection;
+ rv = drbd_may_finish_epoch(connection, connection->current_epoch, EV_GOT_BARRIER_NR);
/* P_BARRIER_ACK may imply that the corresponding extent is dropped from
* the activity log, which means it would not be resynced in case the
* R_PRIMARY crashes now.
* Therefore we must send the barrier_ack after the barrier request was
* completed. */
- switch (tconn->write_ordering) {
+ switch (connection->write_ordering) {
case WO_none:
if (rv == FE_RECYCLED)
return 0;
@@ -1443,15 +1458,15 @@ static int receive_Barrier(struct drbd_tconn *tconn, struct packet_info *pi)
if (epoch)
break;
else
- conn_warn(tconn, "Allocation of an epoch failed, slowing down\n");
+ drbd_warn(connection, "Allocation of an epoch failed, slowing down\n");
/* Fall through */
case WO_bdev_flush:
case WO_drain_io:
- conn_wait_active_ee_empty(tconn);
- drbd_flush(tconn);
+ conn_wait_active_ee_empty(connection);
+ drbd_flush(connection);
- if (atomic_read(&tconn->current_epoch->epoch_size)) {
+ if (atomic_read(&connection->current_epoch->epoch_size)) {
epoch = kmalloc(sizeof(struct drbd_epoch), GFP_NOIO);
if (epoch)
break;
@@ -1459,7 +1474,7 @@ static int receive_Barrier(struct drbd_tconn *tconn, struct packet_info *pi)
return 0;
default:
- conn_err(tconn, "Strangeness in tconn->write_ordering %d\n", tconn->write_ordering);
+ drbd_err(connection, "Strangeness in connection->write_ordering %d\n", connection->write_ordering);
return -EIO;
}
@@ -1467,16 +1482,16 @@ static int receive_Barrier(struct drbd_tconn *tconn, struct packet_info *pi)
atomic_set(&epoch->epoch_size, 0);
atomic_set(&epoch->active, 0);
- spin_lock(&tconn->epoch_lock);
- if (atomic_read(&tconn->current_epoch->epoch_size)) {
- list_add(&epoch->list, &tconn->current_epoch->list);
- tconn->current_epoch = epoch;
- tconn->epochs++;
+ spin_lock(&connection->epoch_lock);
+ if (atomic_read(&connection->current_epoch->epoch_size)) {
+ list_add(&epoch->list, &connection->current_epoch->list);
+ connection->current_epoch = epoch;
+ connection->epochs++;
} else {
/* The current_epoch got recycled while we allocated this one... */
kfree(epoch);
}
- spin_unlock(&tconn->epoch_lock);
+ spin_unlock(&connection->epoch_lock);
return 0;
}
@@ -1484,25 +1499,26 @@ static int receive_Barrier(struct drbd_tconn *tconn, struct packet_info *pi)
/* used from receive_RSDataReply (recv_resync_read)
* and from receive_Data */
static struct drbd_peer_request *
-read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector,
+read_in_block(struct drbd_peer_device *peer_device, u64 id, sector_t sector,
int data_size) __must_hold(local)
{
- const sector_t capacity = drbd_get_capacity(mdev->this_bdev);
+ struct drbd_device *device = peer_device->device;
+ const sector_t capacity = drbd_get_capacity(device->this_bdev);
struct drbd_peer_request *peer_req;
struct page *page;
int dgs, ds, err;
- void *dig_in = mdev->tconn->int_dig_in;
- void *dig_vv = mdev->tconn->int_dig_vv;
+ void *dig_in = peer_device->connection->int_dig_in;
+ void *dig_vv = peer_device->connection->int_dig_vv;
unsigned long *data;
dgs = 0;
- if (mdev->tconn->peer_integrity_tfm) {
- dgs = crypto_hash_digestsize(mdev->tconn->peer_integrity_tfm);
+ if (peer_device->connection->peer_integrity_tfm) {
+ dgs = crypto_hash_digestsize(peer_device->connection->peer_integrity_tfm);
/*
* FIXME: Receive the incoming digest into the receive buffer
* here, together with its struct p_data?
*/
- err = drbd_recv_all_warn(mdev->tconn, dig_in, dgs);
+ err = drbd_recv_all_warn(peer_device->connection, dig_in, dgs);
if (err)
return NULL;
data_size -= dgs;
@@ -1516,7 +1532,7 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector,
/* even though we trust out peer,
* we sometimes have to double check. */
if (sector + (data_size>>9) > capacity) {
- dev_err(DEV, "request from peer beyond end of local disk: "
+ drbd_err(device, "request from peer beyond end of local disk: "
"capacity: %llus < sector: %llus + size: %u\n",
(unsigned long long)capacity,
(unsigned long long)sector, data_size);
@@ -1526,7 +1542,7 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector,
/* GFP_NOIO, because we must not cause arbitrary write-out: in a DRBD
* "criss-cross" setup, that might cause write-out on some other DRBD,
* which in turn might block on the other node at this very place. */
- peer_req = drbd_alloc_peer_req(mdev, id, sector, data_size, GFP_NOIO);
+ peer_req = drbd_alloc_peer_req(peer_device, id, sector, data_size, GFP_NOIO);
if (!peer_req)
return NULL;
@@ -1538,36 +1554,36 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector,
page_chain_for_each(page) {
unsigned len = min_t(int, ds, PAGE_SIZE);
data = kmap(page);
- err = drbd_recv_all_warn(mdev->tconn, data, len);
- if (drbd_insert_fault(mdev, DRBD_FAULT_RECEIVE)) {
- dev_err(DEV, "Fault injection: Corrupting data on receive\n");
+ err = drbd_recv_all_warn(peer_device->connection, data, len);
+ if (drbd_insert_fault(device, DRBD_FAULT_RECEIVE)) {
+ drbd_err(device, "Fault injection: Corrupting data on receive\n");
data[0] = data[0] ^ (unsigned long)-1;
}
kunmap(page);
if (err) {
- drbd_free_peer_req(mdev, peer_req);
+ drbd_free_peer_req(device, peer_req);
return NULL;
}
ds -= len;
}
if (dgs) {
- drbd_csum_ee(mdev, mdev->tconn->peer_integrity_tfm, peer_req, dig_vv);
+ drbd_csum_ee(peer_device->connection->peer_integrity_tfm, peer_req, dig_vv);
if (memcmp(dig_in, dig_vv, dgs)) {
- dev_err(DEV, "Digest integrity check FAILED: %llus +%u\n",
+ drbd_err(device, "Digest integrity check FAILED: %llus +%u\n",
(unsigned long long)sector, data_size);
- drbd_free_peer_req(mdev, peer_req);
+ drbd_free_peer_req(device, peer_req);
return NULL;
}
}
- mdev->recv_cnt += data_size>>9;
+ device->recv_cnt += data_size>>9;
return peer_req;
}
/* drbd_drain_block() just takes a data block
* out of the socket input buffer, and discards it.
*/
-static int drbd_drain_block(struct drbd_conf *mdev, int data_size)
+static int drbd_drain_block(struct drbd_peer_device *peer_device, int data_size)
{
struct page *page;
int err = 0;
@@ -1576,36 +1592,36 @@ static int drbd_drain_block(struct drbd_conf *mdev, int data_size)
if (!data_size)
return 0;
- page = drbd_alloc_pages(mdev, 1, 1);
+ page = drbd_alloc_pages(peer_device, 1, 1);
data = kmap(page);
while (data_size) {
unsigned int len = min_t(int, data_size, PAGE_SIZE);
- err = drbd_recv_all_warn(mdev->tconn, data, len);
+ err = drbd_recv_all_warn(peer_device->connection, data, len);
if (err)
break;
data_size -= len;
}
kunmap(page);
- drbd_free_pages(mdev, page, 0);
+ drbd_free_pages(peer_device->device, page, 0);
return err;
}
-static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req,
+static int recv_dless_read(struct drbd_peer_device *peer_device, struct drbd_request *req,
sector_t sector, int data_size)
{
struct bio_vec bvec;
struct bvec_iter iter;
struct bio *bio;
int dgs, err, expect;
- void *dig_in = mdev->tconn->int_dig_in;
- void *dig_vv = mdev->tconn->int_dig_vv;
+ void *dig_in = peer_device->connection->int_dig_in;
+ void *dig_vv = peer_device->connection->int_dig_vv;
dgs = 0;
- if (mdev->tconn->peer_integrity_tfm) {
- dgs = crypto_hash_digestsize(mdev->tconn->peer_integrity_tfm);
- err = drbd_recv_all_warn(mdev->tconn, dig_in, dgs);
+ if (peer_device->connection->peer_integrity_tfm) {
+ dgs = crypto_hash_digestsize(peer_device->connection->peer_integrity_tfm);
+ err = drbd_recv_all_warn(peer_device->connection, dig_in, dgs);
if (err)
return err;
data_size -= dgs;
@@ -1613,15 +1629,15 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req,
/* optimistically update recv_cnt. if receiving fails below,
* we disconnect anyways, and counters will be reset. */
- mdev->recv_cnt += data_size>>9;
+ peer_device->device->recv_cnt += data_size>>9;
bio = req->master_bio;
- D_ASSERT(sector == bio->bi_iter.bi_sector);
+ D_ASSERT(peer_device->device, sector == bio->bi_iter.bi_sector);
bio_for_each_segment(bvec, bio, iter) {
void *mapped = kmap(bvec.bv_page) + bvec.bv_offset;
expect = min_t(int, data_size, bvec.bv_len);
- err = drbd_recv_all_warn(mdev->tconn, mapped, expect);
+ err = drbd_recv_all_warn(peer_device->connection, mapped, expect);
kunmap(bvec.bv_page);
if (err)
return err;
@@ -1629,14 +1645,14 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req,
}
if (dgs) {
- drbd_csum_bio(mdev, mdev->tconn->peer_integrity_tfm, bio, dig_vv);
+ drbd_csum_bio(peer_device->connection->peer_integrity_tfm, bio, dig_vv);
if (memcmp(dig_in, dig_vv, dgs)) {
- dev_err(DEV, "Digest integrity check FAILED. Broken NICs?\n");
+ drbd_err(peer_device, "Digest integrity check FAILED. Broken NICs?\n");
return -EINVAL;
}
}
- D_ASSERT(data_size == 0);
+ D_ASSERT(peer_device->device, data_size == 0);
return 0;
}
@@ -1648,64 +1664,67 @@ static int e_end_resync_block(struct drbd_work *w, int unused)
{
struct drbd_peer_request *peer_req =
container_of(w, struct drbd_peer_request, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
+ struct drbd_device *device = peer_device->device;
sector_t sector = peer_req->i.sector;
int err;
- D_ASSERT(drbd_interval_empty(&peer_req->i));
+ D_ASSERT(device, drbd_interval_empty(&peer_req->i));
if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) {
- drbd_set_in_sync(mdev, sector, peer_req->i.size);
- err = drbd_send_ack(mdev, P_RS_WRITE_ACK, peer_req);
+ drbd_set_in_sync(device, sector, peer_req->i.size);
+ err = drbd_send_ack(peer_device, P_RS_WRITE_ACK, peer_req);
} else {
/* Record failure to sync */
- drbd_rs_failed_io(mdev, sector, peer_req->i.size);
+ drbd_rs_failed_io(device, sector, peer_req->i.size);
- err = drbd_send_ack(mdev, P_NEG_ACK, peer_req);
+ err = drbd_send_ack(peer_device, P_NEG_ACK, peer_req);
}
- dec_unacked(mdev);
+ dec_unacked(device);
return err;
}
-static int recv_resync_read(struct drbd_conf *mdev, sector_t sector, int data_size) __releases(local)
+static int recv_resync_read(struct drbd_peer_device *peer_device, sector_t sector,
+ int data_size) __releases(local)
{
+ struct drbd_device *device = peer_device->device;
struct drbd_peer_request *peer_req;
- peer_req = read_in_block(mdev, ID_SYNCER, sector, data_size);
+ peer_req = read_in_block(peer_device, ID_SYNCER, sector, data_size);
if (!peer_req)
goto fail;
- dec_rs_pending(mdev);
+ dec_rs_pending(device);
- inc_unacked(mdev);
+ inc_unacked(device);
/* corresponding dec_unacked() in e_end_resync_block()
* respective _drbd_clear_done_ee */
peer_req->w.cb = e_end_resync_block;
- spin_lock_irq(&mdev->tconn->req_lock);
- list_add(&peer_req->w.list, &mdev->sync_ee);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
+ list_add(&peer_req->w.list, &device->sync_ee);
+ spin_unlock_irq(&device->resource->req_lock);
- atomic_add(data_size >> 9, &mdev->rs_sect_ev);
- if (drbd_submit_peer_request(mdev, peer_req, WRITE, DRBD_FAULT_RS_WR) == 0)
+ atomic_add(data_size >> 9, &device->rs_sect_ev);
+ if (drbd_submit_peer_request(device, peer_req, WRITE, DRBD_FAULT_RS_WR) == 0)
return 0;
/* don't care for the reason here */
- dev_err(DEV, "submit failed, triggering re-connect\n");
- spin_lock_irq(&mdev->tconn->req_lock);
+ drbd_err(device, "submit failed, triggering re-connect\n");
+ spin_lock_irq(&device->resource->req_lock);
list_del(&peer_req->w.list);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
- drbd_free_peer_req(mdev, peer_req);
+ drbd_free_peer_req(device, peer_req);
fail:
- put_ldev(mdev);
+ put_ldev(device);
return -EIO;
}
static struct drbd_request *
-find_request(struct drbd_conf *mdev, struct rb_root *root, u64 id,
+find_request(struct drbd_device *device, struct rb_root *root, u64 id,
sector_t sector, bool missing_ok, const char *func)
{
struct drbd_request *req;
@@ -1715,36 +1734,38 @@ find_request(struct drbd_conf *mdev, struct rb_root *root, u64 id,
if (drbd_contains_interval(root, sector, &req->i) && req->i.local)
return req;
if (!missing_ok) {
- dev_err(DEV, "%s: failed to find request 0x%lx, sector %llus\n", func,
+ drbd_err(device, "%s: failed to find request 0x%lx, sector %llus\n", func,
(unsigned long)id, (unsigned long long)sector);
}
return NULL;
}
-static int receive_DataReply(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_DataReply(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct drbd_request *req;
sector_t sector;
int err;
struct p_data *p = pi->data;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
sector = be64_to_cpu(p->sector);
- spin_lock_irq(&mdev->tconn->req_lock);
- req = find_request(mdev, &mdev->read_requests, p->block_id, sector, false, __func__);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
+ req = find_request(device, &device->read_requests, p->block_id, sector, false, __func__);
+ spin_unlock_irq(&device->resource->req_lock);
if (unlikely(!req))
return -EIO;
/* hlist_del(&req->collision) is done in _req_may_be_done, to avoid
* special casing it there for the various failure cases.
* still no race with drbd_fail_pending_reads */
- err = recv_dless_read(mdev, req, sector, pi->size);
+ err = recv_dless_read(peer_device, req, sector, pi->size);
if (!err)
req_mod(req, DATA_RECEIVED);
/* else: nothing. handled from drbd_disconnect...
@@ -1754,46 +1775,48 @@ static int receive_DataReply(struct drbd_tconn *tconn, struct packet_info *pi)
return err;
}
-static int receive_RSDataReply(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_RSDataReply(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
sector_t sector;
int err;
struct p_data *p = pi->data;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
sector = be64_to_cpu(p->sector);
- D_ASSERT(p->block_id == ID_SYNCER);
+ D_ASSERT(device, p->block_id == ID_SYNCER);
- if (get_ldev(mdev)) {
+ if (get_ldev(device)) {
/* data is submitted to disk within recv_resync_read.
* corresponding put_ldev done below on error,
* or in drbd_peer_request_endio. */
- err = recv_resync_read(mdev, sector, pi->size);
+ err = recv_resync_read(peer_device, sector, pi->size);
} else {
if (__ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "Can not write resync data to local disk.\n");
+ drbd_err(device, "Can not write resync data to local disk.\n");
- err = drbd_drain_block(mdev, pi->size);
+ err = drbd_drain_block(peer_device, pi->size);
- drbd_send_ack_dp(mdev, P_NEG_ACK, p, pi->size);
+ drbd_send_ack_dp(peer_device, P_NEG_ACK, p, pi->size);
}
- atomic_add(pi->size >> 9, &mdev->rs_sect_in);
+ atomic_add(pi->size >> 9, &device->rs_sect_in);
return err;
}
-static void restart_conflicting_writes(struct drbd_conf *mdev,
+static void restart_conflicting_writes(struct drbd_device *device,
sector_t sector, int size)
{
struct drbd_interval *i;
struct drbd_request *req;
- drbd_for_each_overlap(i, &mdev->write_requests, sector, size) {
+ drbd_for_each_overlap(i, &device->write_requests, sector, size) {
if (!i->local)
continue;
req = container_of(i, struct drbd_request, i);
@@ -1813,52 +1836,53 @@ static int e_end_block(struct drbd_work *w, int cancel)
{
struct drbd_peer_request *peer_req =
container_of(w, struct drbd_peer_request, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
+ struct drbd_device *device = peer_device->device;
sector_t sector = peer_req->i.sector;
int err = 0, pcmd;
if (peer_req->flags & EE_SEND_WRITE_ACK) {
if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) {
- pcmd = (mdev->state.conn >= C_SYNC_SOURCE &&
- mdev->state.conn <= C_PAUSED_SYNC_T &&
+ pcmd = (device->state.conn >= C_SYNC_SOURCE &&
+ device->state.conn <= C_PAUSED_SYNC_T &&
peer_req->flags & EE_MAY_SET_IN_SYNC) ?
P_RS_WRITE_ACK : P_WRITE_ACK;
- err = drbd_send_ack(mdev, pcmd, peer_req);
+ err = drbd_send_ack(peer_device, pcmd, peer_req);
if (pcmd == P_RS_WRITE_ACK)
- drbd_set_in_sync(mdev, sector, peer_req->i.size);
+ drbd_set_in_sync(device, sector, peer_req->i.size);
} else {
- err = drbd_send_ack(mdev, P_NEG_ACK, peer_req);
+ err = drbd_send_ack(peer_device, P_NEG_ACK, peer_req);
/* we expect it to be marked out of sync anyways...
* maybe assert this? */
}
- dec_unacked(mdev);
+ dec_unacked(device);
}
/* we delete from the conflict detection hash _after_ we sent out the
* P_WRITE_ACK / P_NEG_ACK, to get the sequence number right. */
if (peer_req->flags & EE_IN_INTERVAL_TREE) {
- spin_lock_irq(&mdev->tconn->req_lock);
- D_ASSERT(!drbd_interval_empty(&peer_req->i));
- drbd_remove_epoch_entry_interval(mdev, peer_req);
+ spin_lock_irq(&device->resource->req_lock);
+ D_ASSERT(device, !drbd_interval_empty(&peer_req->i));
+ drbd_remove_epoch_entry_interval(device, peer_req);
if (peer_req->flags & EE_RESTART_REQUESTS)
- restart_conflicting_writes(mdev, sector, peer_req->i.size);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ restart_conflicting_writes(device, sector, peer_req->i.size);
+ spin_unlock_irq(&device->resource->req_lock);
} else
- D_ASSERT(drbd_interval_empty(&peer_req->i));
+ D_ASSERT(device, drbd_interval_empty(&peer_req->i));
- drbd_may_finish_epoch(mdev->tconn, peer_req->epoch, EV_PUT + (cancel ? EV_CLEANUP : 0));
+ drbd_may_finish_epoch(first_peer_device(device)->connection, peer_req->epoch, EV_PUT + (cancel ? EV_CLEANUP : 0));
return err;
}
static int e_send_ack(struct drbd_work *w, enum drbd_packet ack)
{
- struct drbd_conf *mdev = w->mdev;
struct drbd_peer_request *peer_req =
container_of(w, struct drbd_peer_request, w);
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
int err;
- err = drbd_send_ack(mdev, ack, peer_req);
- dec_unacked(mdev);
+ err = drbd_send_ack(peer_device, ack, peer_req);
+ dec_unacked(peer_device->device);
return err;
}
@@ -1870,9 +1894,11 @@ static int e_send_superseded(struct drbd_work *w, int unused)
static int e_send_retry_write(struct drbd_work *w, int unused)
{
- struct drbd_tconn *tconn = w->mdev->tconn;
+ struct drbd_peer_request *peer_req =
+ container_of(w, struct drbd_peer_request, w);
+ struct drbd_connection *connection = peer_req->peer_device->connection;
- return e_send_ack(w, tconn->agreed_pro_version >= 100 ?
+ return e_send_ack(w, connection->agreed_pro_version >= 100 ?
P_RETRY_WRITE : P_SUPERSEDED);
}
@@ -1891,18 +1917,19 @@ static u32 seq_max(u32 a, u32 b)
return seq_greater(a, b) ? a : b;
}
-static void update_peer_seq(struct drbd_conf *mdev, unsigned int peer_seq)
+static void update_peer_seq(struct drbd_peer_device *peer_device, unsigned int peer_seq)
{
+ struct drbd_device *device = peer_device->device;
unsigned int newest_peer_seq;
- if (test_bit(RESOLVE_CONFLICTS, &mdev->tconn->flags)) {
- spin_lock(&mdev->peer_seq_lock);
- newest_peer_seq = seq_max(mdev->peer_seq, peer_seq);
- mdev->peer_seq = newest_peer_seq;
- spin_unlock(&mdev->peer_seq_lock);
- /* wake up only if we actually changed mdev->peer_seq */
+ if (test_bit(RESOLVE_CONFLICTS, &peer_device->connection->flags)) {
+ spin_lock(&device->peer_seq_lock);
+ newest_peer_seq = seq_max(device->peer_seq, peer_seq);
+ device->peer_seq = newest_peer_seq;
+ spin_unlock(&device->peer_seq_lock);
+ /* wake up only if we actually changed device->peer_seq */
if (peer_seq == newest_peer_seq)
- wake_up(&mdev->seq_wait);
+ wake_up(&device->seq_wait);
}
}
@@ -1912,20 +1939,20 @@ static inline int overlaps(sector_t s1, int l1, sector_t s2, int l2)
}
/* maybe change sync_ee into interval trees as well? */
-static bool overlapping_resync_write(struct drbd_conf *mdev, struct drbd_peer_request *peer_req)
+static bool overlapping_resync_write(struct drbd_device *device, struct drbd_peer_request *peer_req)
{
struct drbd_peer_request *rs_req;
bool rv = 0;
- spin_lock_irq(&mdev->tconn->req_lock);
- list_for_each_entry(rs_req, &mdev->sync_ee, w.list) {
+ spin_lock_irq(&device->resource->req_lock);
+ list_for_each_entry(rs_req, &device->sync_ee, w.list) {
if (overlaps(peer_req->i.sector, peer_req->i.size,
rs_req->i.sector, rs_req->i.size)) {
rv = 1;
break;
}
}
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
return rv;
}
@@ -1939,9 +1966,9 @@ static bool overlapping_resync_write(struct drbd_conf *mdev, struct drbd_peer_re
*
* Note: we don't care for Ack packets overtaking P_DATA packets.
*
- * In case packet_seq is larger than mdev->peer_seq number, there are
+ * In case packet_seq is larger than device->peer_seq number, there are
* outstanding packets on the msock. We wait for them to arrive.
- * In case we are the logically next packet, we update mdev->peer_seq
+ * In case we are the logically next packet, we update device->peer_seq
* ourselves. Correctly handles 32bit wrap around.
*
* Assume we have a 10 GBit connection, that is about 1<<30 byte per second,
@@ -1951,19 +1978,20 @@ static bool overlapping_resync_write(struct drbd_conf *mdev, struct drbd_peer_re
*
* returns 0 if we may process the packet,
* -ERESTARTSYS if we were interrupted (by disconnect signal). */
-static int wait_for_and_update_peer_seq(struct drbd_conf *mdev, const u32 peer_seq)
+static int wait_for_and_update_peer_seq(struct drbd_peer_device *peer_device, const u32 peer_seq)
{
+ struct drbd_device *device = peer_device->device;
DEFINE_WAIT(wait);
long timeout;
int ret = 0, tp;
- if (!test_bit(RESOLVE_CONFLICTS, &mdev->tconn->flags))
+ if (!test_bit(RESOLVE_CONFLICTS, &peer_device->connection->flags))
return 0;
- spin_lock(&mdev->peer_seq_lock);
+ spin_lock(&device->peer_seq_lock);
for (;;) {
- if (!seq_greater(peer_seq - 1, mdev->peer_seq)) {
- mdev->peer_seq = seq_max(mdev->peer_seq, peer_seq);
+ if (!seq_greater(peer_seq - 1, device->peer_seq)) {
+ device->peer_seq = seq_max(device->peer_seq, peer_seq);
break;
}
@@ -1973,35 +2001,35 @@ static int wait_for_and_update_peer_seq(struct drbd_conf *mdev, const u32 peer_s
}
rcu_read_lock();
- tp = rcu_dereference(mdev->tconn->net_conf)->two_primaries;
+ tp = rcu_dereference(first_peer_device(device)->connection->net_conf)->two_primaries;
rcu_read_unlock();
if (!tp)
break;
/* Only need to wait if two_primaries is enabled */
- prepare_to_wait(&mdev->seq_wait, &wait, TASK_INTERRUPTIBLE);
- spin_unlock(&mdev->peer_seq_lock);
+ prepare_to_wait(&device->seq_wait, &wait, TASK_INTERRUPTIBLE);
+ spin_unlock(&device->peer_seq_lock);
rcu_read_lock();
- timeout = rcu_dereference(mdev->tconn->net_conf)->ping_timeo*HZ/10;
+ timeout = rcu_dereference(peer_device->connection->net_conf)->ping_timeo*HZ/10;
rcu_read_unlock();
timeout = schedule_timeout(timeout);
- spin_lock(&mdev->peer_seq_lock);
+ spin_lock(&device->peer_seq_lock);
if (!timeout) {
ret = -ETIMEDOUT;
- dev_err(DEV, "Timed out waiting for missing ack packets; disconnecting\n");
+ drbd_err(device, "Timed out waiting for missing ack packets; disconnecting\n");
break;
}
}
- spin_unlock(&mdev->peer_seq_lock);
- finish_wait(&mdev->seq_wait, &wait);
+ spin_unlock(&device->peer_seq_lock);
+ finish_wait(&device->seq_wait, &wait);
return ret;
}
/* see also bio_flags_to_wire()
* DRBD_REQ_*, because we need to semantically map the flags to data packet
* flags and back. We may replicate to other kernel versions. */
-static unsigned long wire_flags_to_bio(struct drbd_conf *mdev, u32 dpf)
+static unsigned long wire_flags_to_bio(u32 dpf)
{
return (dpf & DP_RW_SYNC ? REQ_SYNC : 0) |
(dpf & DP_FUA ? REQ_FUA : 0) |
@@ -2009,13 +2037,13 @@ static unsigned long wire_flags_to_bio(struct drbd_conf *mdev, u32 dpf)
(dpf & DP_DISCARD ? REQ_DISCARD : 0);
}
-static void fail_postponed_requests(struct drbd_conf *mdev, sector_t sector,
+static void fail_postponed_requests(struct drbd_device *device, sector_t sector,
unsigned int size)
{
struct drbd_interval *i;
repeat:
- drbd_for_each_overlap(i, &mdev->write_requests, sector, size) {
+ drbd_for_each_overlap(i, &device->write_requests, sector, size) {
struct drbd_request *req;
struct bio_and_error m;
@@ -2026,19 +2054,19 @@ static void fail_postponed_requests(struct drbd_conf *mdev, sector_t sector,
continue;
req->rq_state &= ~RQ_POSTPONED;
__req_mod(req, NEG_ACKED, &m);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
if (m.bio)
- complete_master_bio(mdev, &m);
- spin_lock_irq(&mdev->tconn->req_lock);
+ complete_master_bio(device, &m);
+ spin_lock_irq(&device->resource->req_lock);
goto repeat;
}
}
-static int handle_write_conflicts(struct drbd_conf *mdev,
+static int handle_write_conflicts(struct drbd_device *device,
struct drbd_peer_request *peer_req)
{
- struct drbd_tconn *tconn = mdev->tconn;
- bool resolve_conflicts = test_bit(RESOLVE_CONFLICTS, &tconn->flags);
+ struct drbd_connection *connection = peer_req->peer_device->connection;
+ bool resolve_conflicts = test_bit(RESOLVE_CONFLICTS, &connection->flags);
sector_t sector = peer_req->i.sector;
const unsigned int size = peer_req->i.size;
struct drbd_interval *i;
@@ -2049,10 +2077,10 @@ static int handle_write_conflicts(struct drbd_conf *mdev,
* Inserting the peer request into the write_requests tree will prevent
* new conflicting local requests from being added.
*/
- drbd_insert_interval(&mdev->write_requests, &peer_req->i);
+ drbd_insert_interval(&device->write_requests, &peer_req->i);
repeat:
- drbd_for_each_overlap(i, &mdev->write_requests, sector, size) {
+ drbd_for_each_overlap(i, &device->write_requests, sector, size) {
if (i == &peer_req->i)
continue;
@@ -2062,7 +2090,7 @@ static int handle_write_conflicts(struct drbd_conf *mdev,
* should not happen in a two-node setup. Wait for the
* earlier peer request to complete.
*/
- err = drbd_wait_misc(mdev, i);
+ err = drbd_wait_misc(device, i);
if (err)
goto out;
goto repeat;
@@ -2080,18 +2108,18 @@ static int handle_write_conflicts(struct drbd_conf *mdev,
(i->size >> 9) >= sector + (size >> 9);
if (!equal)
- dev_alert(DEV, "Concurrent writes detected: "
+ drbd_alert(device, "Concurrent writes detected: "
"local=%llus +%u, remote=%llus +%u, "
"assuming %s came first\n",
(unsigned long long)i->sector, i->size,
(unsigned long long)sector, size,
superseded ? "local" : "remote");
- inc_unacked(mdev);
+ inc_unacked(device);
peer_req->w.cb = superseded ? e_send_superseded :
e_send_retry_write;
- list_add_tail(&peer_req->w.list, &mdev->done_ee);
- wake_asender(mdev->tconn);
+ list_add_tail(&peer_req->w.list, &device->done_ee);
+ wake_asender(connection);
err = -ENOENT;
goto out;
@@ -2100,7 +2128,7 @@ static int handle_write_conflicts(struct drbd_conf *mdev,
container_of(i, struct drbd_request, i);
if (!equal)
- dev_alert(DEV, "Concurrent writes detected: "
+ drbd_alert(device, "Concurrent writes detected: "
"local=%llus +%u, remote=%llus +%u\n",
(unsigned long long)i->sector, i->size,
(unsigned long long)sector, size);
@@ -2118,12 +2146,10 @@ static int handle_write_conflicts(struct drbd_conf *mdev,
* request to finish locally before submitting
* the conflicting peer request.
*/
- err = drbd_wait_misc(mdev, &req->i);
+ err = drbd_wait_misc(device, &req->i);
if (err) {
- _conn_request_state(mdev->tconn,
- NS(conn, C_TIMEOUT),
- CS_HARD);
- fail_postponed_requests(mdev, sector, size);
+ _conn_request_state(connection, NS(conn, C_TIMEOUT), CS_HARD);
+ fail_postponed_requests(device, sector, size);
goto out;
}
goto repeat;
@@ -2139,14 +2165,15 @@ static int handle_write_conflicts(struct drbd_conf *mdev,
out:
if (err)
- drbd_remove_epoch_entry_interval(mdev, peer_req);
+ drbd_remove_epoch_entry_interval(device, peer_req);
return err;
}
/* mirrored write */
-static int receive_Data(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_Data(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
sector_t sector;
struct drbd_peer_request *peer_req;
struct p_data *p = pi->data;
@@ -2155,17 +2182,18 @@ static int receive_Data(struct drbd_tconn *tconn, struct packet_info *pi)
u32 dp_flags;
int err, tp;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
- if (!get_ldev(mdev)) {
+ if (!get_ldev(device)) {
int err2;
- err = wait_for_and_update_peer_seq(mdev, peer_seq);
- drbd_send_ack_dp(mdev, P_NEG_ACK, p, pi->size);
- atomic_inc(&tconn->current_epoch->epoch_size);
- err2 = drbd_drain_block(mdev, pi->size);
+ err = wait_for_and_update_peer_seq(peer_device, peer_seq);
+ drbd_send_ack_dp(peer_device, P_NEG_ACK, p, pi->size);
+ atomic_inc(&connection->current_epoch->epoch_size);
+ err2 = drbd_drain_block(peer_device, pi->size);
if (!err)
err = err2;
return err;
@@ -2178,61 +2206,61 @@ static int receive_Data(struct drbd_tconn *tconn, struct packet_info *pi)
*/
sector = be64_to_cpu(p->sector);
- peer_req = read_in_block(mdev, p->block_id, sector, pi->size);
+ peer_req = read_in_block(peer_device, p->block_id, sector, pi->size);
if (!peer_req) {
- put_ldev(mdev);
+ put_ldev(device);
return -EIO;
}
peer_req->w.cb = e_end_block;
dp_flags = be32_to_cpu(p->dp_flags);
- rw |= wire_flags_to_bio(mdev, dp_flags);
+ rw |= wire_flags_to_bio(dp_flags);
if (peer_req->pages == NULL) {
- D_ASSERT(peer_req->i.size == 0);
- D_ASSERT(dp_flags & DP_FLUSH);
+ D_ASSERT(device, peer_req->i.size == 0);
+ D_ASSERT(device, dp_flags & DP_FLUSH);
}
if (dp_flags & DP_MAY_SET_IN_SYNC)
peer_req->flags |= EE_MAY_SET_IN_SYNC;
- spin_lock(&tconn->epoch_lock);
- peer_req->epoch = tconn->current_epoch;
+ spin_lock(&connection->epoch_lock);
+ peer_req->epoch = connection->current_epoch;
atomic_inc(&peer_req->epoch->epoch_size);
atomic_inc(&peer_req->epoch->active);
- spin_unlock(&tconn->epoch_lock);
+ spin_unlock(&connection->epoch_lock);
rcu_read_lock();
- tp = rcu_dereference(mdev->tconn->net_conf)->two_primaries;
+ tp = rcu_dereference(peer_device->connection->net_conf)->two_primaries;
rcu_read_unlock();
if (tp) {
peer_req->flags |= EE_IN_INTERVAL_TREE;
- err = wait_for_and_update_peer_seq(mdev, peer_seq);
+ err = wait_for_and_update_peer_seq(peer_device, peer_seq);
if (err)
goto out_interrupted;
- spin_lock_irq(&mdev->tconn->req_lock);
- err = handle_write_conflicts(mdev, peer_req);
+ spin_lock_irq(&device->resource->req_lock);
+ err = handle_write_conflicts(device, peer_req);
if (err) {
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
if (err == -ENOENT) {
- put_ldev(mdev);
+ put_ldev(device);
return 0;
}
goto out_interrupted;
}
} else {
- update_peer_seq(mdev, peer_seq);
- spin_lock_irq(&mdev->tconn->req_lock);
+ update_peer_seq(peer_device, peer_seq);
+ spin_lock_irq(&device->resource->req_lock);
}
- list_add(&peer_req->w.list, &mdev->active_ee);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ list_add(&peer_req->w.list, &device->active_ee);
+ spin_unlock_irq(&device->resource->req_lock);
- if (mdev->state.conn == C_SYNC_TARGET)
- wait_event(mdev->ee_wait, !overlapping_resync_write(mdev, peer_req));
+ if (device->state.conn == C_SYNC_TARGET)
+ wait_event(device->ee_wait, !overlapping_resync_write(device, peer_req));
- if (mdev->tconn->agreed_pro_version < 100) {
+ if (peer_device->connection->agreed_pro_version < 100) {
rcu_read_lock();
- switch (rcu_dereference(mdev->tconn->net_conf)->wire_protocol) {
+ switch (rcu_dereference(peer_device->connection->net_conf)->wire_protocol) {
case DRBD_PROT_C:
dp_flags |= DP_SEND_WRITE_ACK;
break;
@@ -2245,7 +2273,7 @@ static int receive_Data(struct drbd_tconn *tconn, struct packet_info *pi)
if (dp_flags & DP_SEND_WRITE_ACK) {
peer_req->flags |= EE_SEND_WRITE_ACK;
- inc_unacked(mdev);
+ inc_unacked(device);
/* corresponding dec_unacked() in e_end_block()
* respective _drbd_clear_done_ee */
}
@@ -2253,34 +2281,34 @@ static int receive_Data(struct drbd_tconn *tconn, struct packet_info *pi)
if (dp_flags & DP_SEND_RECEIVE_ACK) {
/* I really don't like it that the receiver thread
* sends on the msock, but anyways */
- drbd_send_ack(mdev, P_RECV_ACK, peer_req);
+ drbd_send_ack(first_peer_device(device), P_RECV_ACK, peer_req);
}
- if (mdev->state.pdsk < D_INCONSISTENT) {
+ if (device->state.pdsk < D_INCONSISTENT) {
/* In case we have the only disk of the cluster, */
- drbd_set_out_of_sync(mdev, peer_req->i.sector, peer_req->i.size);
+ drbd_set_out_of_sync(device, peer_req->i.sector, peer_req->i.size);
peer_req->flags |= EE_CALL_AL_COMPLETE_IO;
peer_req->flags &= ~EE_MAY_SET_IN_SYNC;
- drbd_al_begin_io(mdev, &peer_req->i, true);
+ drbd_al_begin_io(device, &peer_req->i, true);
}
- err = drbd_submit_peer_request(mdev, peer_req, rw, DRBD_FAULT_DT_WR);
+ err = drbd_submit_peer_request(device, peer_req, rw, DRBD_FAULT_DT_WR);
if (!err)
return 0;
/* don't care for the reason here */
- dev_err(DEV, "submit failed, triggering re-connect\n");
- spin_lock_irq(&mdev->tconn->req_lock);
+ drbd_err(device, "submit failed, triggering re-connect\n");
+ spin_lock_irq(&device->resource->req_lock);
list_del(&peer_req->w.list);
- drbd_remove_epoch_entry_interval(mdev, peer_req);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ drbd_remove_epoch_entry_interval(device, peer_req);
+ spin_unlock_irq(&device->resource->req_lock);
if (peer_req->flags & EE_CALL_AL_COMPLETE_IO)
- drbd_al_complete_io(mdev, &peer_req->i);
+ drbd_al_complete_io(device, &peer_req->i);
out_interrupted:
- drbd_may_finish_epoch(tconn, peer_req->epoch, EV_PUT + EV_CLEANUP);
- put_ldev(mdev);
- drbd_free_peer_req(mdev, peer_req);
+ drbd_may_finish_epoch(connection, peer_req->epoch, EV_PUT + EV_CLEANUP);
+ put_ldev(device);
+ drbd_free_peer_req(device, peer_req);
return err;
}
@@ -2295,9 +2323,9 @@ out_interrupted:
* The current sync rate used here uses only the most recent two step marks,
* to have a short time average so we can react faster.
*/
-int drbd_rs_should_slow_down(struct drbd_conf *mdev, sector_t sector)
+int drbd_rs_should_slow_down(struct drbd_device *device, sector_t sector)
{
- struct gendisk *disk = mdev->ldev->backing_bdev->bd_contains->bd_disk;
+ struct gendisk *disk = device->ldev->backing_bdev->bd_contains->bd_disk;
unsigned long db, dt, dbdt;
struct lc_element *tmp;
int curr_events;
@@ -2305,48 +2333,48 @@ int drbd_rs_should_slow_down(struct drbd_conf *mdev, sector_t sector)
unsigned int c_min_rate;
rcu_read_lock();
- c_min_rate = rcu_dereference(mdev->ldev->disk_conf)->c_min_rate;
+ c_min_rate = rcu_dereference(device->ldev->disk_conf)->c_min_rate;
rcu_read_unlock();
/* feature disabled? */
if (c_min_rate == 0)
return 0;
- spin_lock_irq(&mdev->al_lock);
- tmp = lc_find(mdev->resync, BM_SECT_TO_EXT(sector));
+ spin_lock_irq(&device->al_lock);
+ tmp = lc_find(device->resync, BM_SECT_TO_EXT(sector));
if (tmp) {
struct bm_extent *bm_ext = lc_entry(tmp, struct bm_extent, lce);
if (test_bit(BME_PRIORITY, &bm_ext->flags)) {
- spin_unlock_irq(&mdev->al_lock);
+ spin_unlock_irq(&device->al_lock);
return 0;
}
/* Do not slow down if app IO is already waiting for this extent */
}
- spin_unlock_irq(&mdev->al_lock);
+ spin_unlock_irq(&device->al_lock);
curr_events = (int)part_stat_read(&disk->part0, sectors[0]) +
(int)part_stat_read(&disk->part0, sectors[1]) -
- atomic_read(&mdev->rs_sect_ev);
+ atomic_read(&device->rs_sect_ev);
- if (!mdev->rs_last_events || curr_events - mdev->rs_last_events > 64) {
+ if (!device->rs_last_events || curr_events - device->rs_last_events > 64) {
unsigned long rs_left;
int i;
- mdev->rs_last_events = curr_events;
+ device->rs_last_events = curr_events;
/* sync speed average over the last 2*DRBD_SYNC_MARK_STEP,
* approx. */
- i = (mdev->rs_last_mark + DRBD_SYNC_MARKS-1) % DRBD_SYNC_MARKS;
+ i = (device->rs_last_mark + DRBD_SYNC_MARKS-1) % DRBD_SYNC_MARKS;
- if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T)
- rs_left = mdev->ov_left;
+ if (device->state.conn == C_VERIFY_S || device->state.conn == C_VERIFY_T)
+ rs_left = device->ov_left;
else
- rs_left = drbd_bm_total_weight(mdev) - mdev->rs_failed;
+ rs_left = drbd_bm_total_weight(device) - device->rs_failed;
- dt = ((long)jiffies - (long)mdev->rs_mark_time[i]) / HZ;
+ dt = ((long)jiffies - (long)device->rs_mark_time[i]) / HZ;
if (!dt)
dt++;
- db = mdev->rs_mark_left[i] - rs_left;
+ db = device->rs_mark_left[i] - rs_left;
dbdt = Bit2KB(db/dt);
if (dbdt > c_min_rate)
@@ -2356,9 +2384,10 @@ int drbd_rs_should_slow_down(struct drbd_conf *mdev, sector_t sector)
}
-static int receive_DataRequest(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_DataRequest(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
sector_t sector;
sector_t capacity;
struct drbd_peer_request *peer_req;
@@ -2367,58 +2396,59 @@ static int receive_DataRequest(struct drbd_tconn *tconn, struct packet_info *pi)
unsigned int fault_type;
struct p_block_req *p = pi->data;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
- capacity = drbd_get_capacity(mdev->this_bdev);
+ device = peer_device->device;
+ capacity = drbd_get_capacity(device->this_bdev);
sector = be64_to_cpu(p->sector);
size = be32_to_cpu(p->blksize);
if (size <= 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_BIO_SIZE) {
- dev_err(DEV, "%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__,
+ drbd_err(device, "%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__,
(unsigned long long)sector, size);
return -EINVAL;
}
if (sector + (size>>9) > capacity) {
- dev_err(DEV, "%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__,
+ drbd_err(device, "%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__,
(unsigned long long)sector, size);
return -EINVAL;
}
- if (!get_ldev_if_state(mdev, D_UP_TO_DATE)) {
+ if (!get_ldev_if_state(device, D_UP_TO_DATE)) {
verb = 1;
switch (pi->cmd) {
case P_DATA_REQUEST:
- drbd_send_ack_rp(mdev, P_NEG_DREPLY, p);
+ drbd_send_ack_rp(peer_device, P_NEG_DREPLY, p);
break;
case P_RS_DATA_REQUEST:
case P_CSUM_RS_REQUEST:
case P_OV_REQUEST:
- drbd_send_ack_rp(mdev, P_NEG_RS_DREPLY , p);
+ drbd_send_ack_rp(peer_device, P_NEG_RS_DREPLY , p);
break;
case P_OV_REPLY:
verb = 0;
- dec_rs_pending(mdev);
- drbd_send_ack_ex(mdev, P_OV_RESULT, sector, size, ID_IN_SYNC);
+ dec_rs_pending(device);
+ drbd_send_ack_ex(peer_device, P_OV_RESULT, sector, size, ID_IN_SYNC);
break;
default:
BUG();
}
if (verb && __ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "Can not satisfy peer's read request, "
+ drbd_err(device, "Can not satisfy peer's read request, "
"no local data.\n");
/* drain possibly payload */
- return drbd_drain_block(mdev, pi->size);
+ return drbd_drain_block(peer_device, pi->size);
}
/* GFP_NOIO, because we must not cause arbitrary write-out: in a DRBD
* "criss-cross" setup, that might cause write-out on some other DRBD,
* which in turn might block on the other node at this very place. */
- peer_req = drbd_alloc_peer_req(mdev, p->block_id, sector, size, GFP_NOIO);
+ peer_req = drbd_alloc_peer_req(peer_device, p->block_id, sector, size, GFP_NOIO);
if (!peer_req) {
- put_ldev(mdev);
+ put_ldev(device);
return -ENOMEM;
}
@@ -2433,7 +2463,7 @@ static int receive_DataRequest(struct drbd_tconn *tconn, struct packet_info *pi)
peer_req->w.cb = w_e_end_rsdata_req;
fault_type = DRBD_FAULT_RS_RD;
/* used in the sector offset progress display */
- mdev->bm_resync_fo = BM_SECT_TO_BIT(sector);
+ device->bm_resync_fo = BM_SECT_TO_BIT(sector);
break;
case P_OV_REPLY:
@@ -2449,19 +2479,19 @@ static int receive_DataRequest(struct drbd_tconn *tconn, struct packet_info *pi)
peer_req->digest = di;
peer_req->flags |= EE_HAS_DIGEST;
- if (drbd_recv_all(mdev->tconn, di->digest, pi->size))
+ if (drbd_recv_all(peer_device->connection, di->digest, pi->size))
goto out_free_e;
if (pi->cmd == P_CSUM_RS_REQUEST) {
- D_ASSERT(mdev->tconn->agreed_pro_version >= 89);
+ D_ASSERT(device, peer_device->connection->agreed_pro_version >= 89);
peer_req->w.cb = w_e_end_csum_rs_req;
/* used in the sector offset progress display */
- mdev->bm_resync_fo = BM_SECT_TO_BIT(sector);
+ device->bm_resync_fo = BM_SECT_TO_BIT(sector);
} else if (pi->cmd == P_OV_REPLY) {
/* track progress, we may need to throttle */
- atomic_add(size >> 9, &mdev->rs_sect_in);
+ atomic_add(size >> 9, &device->rs_sect_in);
peer_req->w.cb = w_e_end_ov_reply;
- dec_rs_pending(mdev);
+ dec_rs_pending(device);
/* drbd_rs_begin_io done when we sent this request,
* but accounting still needs to be done. */
goto submit_for_resync;
@@ -2469,19 +2499,19 @@ static int receive_DataRequest(struct drbd_tconn *tconn, struct packet_info *pi)
break;
case P_OV_REQUEST:
- if (mdev->ov_start_sector == ~(sector_t)0 &&
- mdev->tconn->agreed_pro_version >= 90) {
+ if (device->ov_start_sector == ~(sector_t)0 &&
+ peer_device->connection->agreed_pro_version >= 90) {
unsigned long now = jiffies;
int i;
- mdev->ov_start_sector = sector;
- mdev->ov_position = sector;
- mdev->ov_left = drbd_bm_bits(mdev) - BM_SECT_TO_BIT(sector);
- mdev->rs_total = mdev->ov_left;
+ device->ov_start_sector = sector;
+ device->ov_position = sector;
+ device->ov_left = drbd_bm_bits(device) - BM_SECT_TO_BIT(sector);
+ device->rs_total = device->ov_left;
for (i = 0; i < DRBD_SYNC_MARKS; i++) {
- mdev->rs_mark_left[i] = mdev->ov_left;
- mdev->rs_mark_time[i] = now;
+ device->rs_mark_left[i] = device->ov_left;
+ device->rs_mark_time[i] = now;
}
- dev_info(DEV, "Online Verify start sector: %llu\n",
+ drbd_info(device, "Online Verify start sector: %llu\n",
(unsigned long long)sector);
}
peer_req->w.cb = w_e_end_ov_req;
@@ -2514,57 +2544,61 @@ static int receive_DataRequest(struct drbd_tconn *tconn, struct packet_info *pi)
* we would also throttle its application reads.
* In that case, throttling is done on the SyncTarget only.
*/
- if (mdev->state.peer != R_PRIMARY && drbd_rs_should_slow_down(mdev, sector))
+ if (device->state.peer != R_PRIMARY && drbd_rs_should_slow_down(device, sector))
schedule_timeout_uninterruptible(HZ/10);
- if (drbd_rs_begin_io(mdev, sector))
+ if (drbd_rs_begin_io(device, sector))
goto out_free_e;
submit_for_resync:
- atomic_add(size >> 9, &mdev->rs_sect_ev);
+ atomic_add(size >> 9, &device->rs_sect_ev);
submit:
- inc_unacked(mdev);
- spin_lock_irq(&mdev->tconn->req_lock);
- list_add_tail(&peer_req->w.list, &mdev->read_ee);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ inc_unacked(device);
+ spin_lock_irq(&device->resource->req_lock);
+ list_add_tail(&peer_req->w.list, &device->read_ee);
+ spin_unlock_irq(&device->resource->req_lock);
- if (drbd_submit_peer_request(mdev, peer_req, READ, fault_type) == 0)
+ if (drbd_submit_peer_request(device, peer_req, READ, fault_type) == 0)
return 0;
/* don't care for the reason here */
- dev_err(DEV, "submit failed, triggering re-connect\n");
- spin_lock_irq(&mdev->tconn->req_lock);
+ drbd_err(device, "submit failed, triggering re-connect\n");
+ spin_lock_irq(&device->resource->req_lock);
list_del(&peer_req->w.list);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
/* no drbd_rs_complete_io(), we are dropping the connection anyways */
out_free_e:
- put_ldev(mdev);
- drbd_free_peer_req(mdev, peer_req);
+ put_ldev(device);
+ drbd_free_peer_req(device, peer_req);
return -EIO;
}
-static int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local)
+/**
+ * drbd_asb_recover_0p - Recover after split-brain with no remaining primaries
+ */
+static int drbd_asb_recover_0p(struct drbd_peer_device *peer_device) __must_hold(local)
{
+ struct drbd_device *device = peer_device->device;
int self, peer, rv = -100;
unsigned long ch_self, ch_peer;
enum drbd_after_sb_p after_sb_0p;
- self = mdev->ldev->md.uuid[UI_BITMAP] & 1;
- peer = mdev->p_uuid[UI_BITMAP] & 1;
+ self = device->ldev->md.uuid[UI_BITMAP] & 1;
+ peer = device->p_uuid[UI_BITMAP] & 1;
- ch_peer = mdev->p_uuid[UI_SIZE];
- ch_self = mdev->comm_bm_set;
+ ch_peer = device->p_uuid[UI_SIZE];
+ ch_self = device->comm_bm_set;
rcu_read_lock();
- after_sb_0p = rcu_dereference(mdev->tconn->net_conf)->after_sb_0p;
+ after_sb_0p = rcu_dereference(peer_device->connection->net_conf)->after_sb_0p;
rcu_read_unlock();
switch (after_sb_0p) {
case ASB_CONSENSUS:
case ASB_DISCARD_SECONDARY:
case ASB_CALL_HELPER:
case ASB_VIOLENTLY:
- dev_err(DEV, "Configuration error.\n");
+ drbd_err(device, "Configuration error.\n");
break;
case ASB_DISCONNECT:
break;
@@ -2588,11 +2622,11 @@ static int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local)
break;
}
/* Else fall through to one of the other strategies... */
- dev_warn(DEV, "Discard younger/older primary did not find a decision\n"
+ drbd_warn(device, "Discard younger/older primary did not find a decision\n"
"Using discard-least-changes instead\n");
case ASB_DISCARD_ZERO_CHG:
if (ch_peer == 0 && ch_self == 0) {
- rv = test_bit(RESOLVE_CONFLICTS, &mdev->tconn->flags)
+ rv = test_bit(RESOLVE_CONFLICTS, &peer_device->connection->flags)
? -1 : 1;
break;
} else {
@@ -2608,7 +2642,7 @@ static int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local)
rv = 1;
else /* ( ch_self == ch_peer ) */
/* Well, then use something else. */
- rv = test_bit(RESOLVE_CONFLICTS, &mdev->tconn->flags)
+ rv = test_bit(RESOLVE_CONFLICTS, &peer_device->connection->flags)
? -1 : 1;
break;
case ASB_DISCARD_LOCAL:
@@ -2621,13 +2655,17 @@ static int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local)
return rv;
}
-static int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local)
+/**
+ * drbd_asb_recover_1p - Recover after split-brain with one remaining primary
+ */
+static int drbd_asb_recover_1p(struct drbd_peer_device *peer_device) __must_hold(local)
{
+ struct drbd_device *device = peer_device->device;
int hg, rv = -100;
enum drbd_after_sb_p after_sb_1p;
rcu_read_lock();
- after_sb_1p = rcu_dereference(mdev->tconn->net_conf)->after_sb_1p;
+ after_sb_1p = rcu_dereference(peer_device->connection->net_conf)->after_sb_1p;
rcu_read_unlock();
switch (after_sb_1p) {
case ASB_DISCARD_YOUNGER_PRI:
@@ -2636,35 +2674,35 @@ static int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local)
case ASB_DISCARD_LOCAL:
case ASB_DISCARD_REMOTE:
case ASB_DISCARD_ZERO_CHG:
- dev_err(DEV, "Configuration error.\n");
+ drbd_err(device, "Configuration error.\n");
break;
case ASB_DISCONNECT:
break;
case ASB_CONSENSUS:
- hg = drbd_asb_recover_0p(mdev);
- if (hg == -1 && mdev->state.role == R_SECONDARY)
+ hg = drbd_asb_recover_0p(peer_device);
+ if (hg == -1 && device->state.role == R_SECONDARY)
rv = hg;
- if (hg == 1 && mdev->state.role == R_PRIMARY)
+ if (hg == 1 && device->state.role == R_PRIMARY)
rv = hg;
break;
case ASB_VIOLENTLY:
- rv = drbd_asb_recover_0p(mdev);
+ rv = drbd_asb_recover_0p(peer_device);
break;
case ASB_DISCARD_SECONDARY:
- return mdev->state.role == R_PRIMARY ? 1 : -1;
+ return device->state.role == R_PRIMARY ? 1 : -1;
case ASB_CALL_HELPER:
- hg = drbd_asb_recover_0p(mdev);
- if (hg == -1 && mdev->state.role == R_PRIMARY) {
+ hg = drbd_asb_recover_0p(peer_device);
+ if (hg == -1 && device->state.role == R_PRIMARY) {
enum drbd_state_rv rv2;
/* drbd_change_state() does not sleep while in SS_IN_TRANSIENT_STATE,
* we might be here in C_WF_REPORT_PARAMS which is transient.
* we do not need to wait for the after state change work either. */
- rv2 = drbd_change_state(mdev, CS_VERBOSE, NS(role, R_SECONDARY));
+ rv2 = drbd_change_state(device, CS_VERBOSE, NS(role, R_SECONDARY));
if (rv2 != SS_SUCCESS) {
- drbd_khelper(mdev, "pri-lost-after-sb");
+ drbd_khelper(device, "pri-lost-after-sb");
} else {
- dev_warn(DEV, "Successfully gave up primary role.\n");
+ drbd_warn(device, "Successfully gave up primary role.\n");
rv = hg;
}
} else
@@ -2674,13 +2712,17 @@ static int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local)
return rv;
}
-static int drbd_asb_recover_2p(struct drbd_conf *mdev) __must_hold(local)
+/**
+ * drbd_asb_recover_2p - Recover after split-brain with two remaining primaries
+ */
+static int drbd_asb_recover_2p(struct drbd_peer_device *peer_device) __must_hold(local)
{
+ struct drbd_device *device = peer_device->device;
int hg, rv = -100;
enum drbd_after_sb_p after_sb_2p;
rcu_read_lock();
- after_sb_2p = rcu_dereference(mdev->tconn->net_conf)->after_sb_2p;
+ after_sb_2p = rcu_dereference(peer_device->connection->net_conf)->after_sb_2p;
rcu_read_unlock();
switch (after_sb_2p) {
case ASB_DISCARD_YOUNGER_PRI:
@@ -2691,26 +2733,26 @@ static int drbd_asb_recover_2p(struct drbd_conf *mdev) __must_hold(local)
case ASB_CONSENSUS:
case ASB_DISCARD_SECONDARY:
case ASB_DISCARD_ZERO_CHG:
- dev_err(DEV, "Configuration error.\n");
+ drbd_err(device, "Configuration error.\n");
break;
case ASB_VIOLENTLY:
- rv = drbd_asb_recover_0p(mdev);
+ rv = drbd_asb_recover_0p(peer_device);
break;
case ASB_DISCONNECT:
break;
case ASB_CALL_HELPER:
- hg = drbd_asb_recover_0p(mdev);
+ hg = drbd_asb_recover_0p(peer_device);
if (hg == -1) {
enum drbd_state_rv rv2;
/* drbd_change_state() does not sleep while in SS_IN_TRANSIENT_STATE,
* we might be here in C_WF_REPORT_PARAMS which is transient.
* we do not need to wait for the after state change work either. */
- rv2 = drbd_change_state(mdev, CS_VERBOSE, NS(role, R_SECONDARY));
+ rv2 = drbd_change_state(device, CS_VERBOSE, NS(role, R_SECONDARY));
if (rv2 != SS_SUCCESS) {
- drbd_khelper(mdev, "pri-lost-after-sb");
+ drbd_khelper(device, "pri-lost-after-sb");
} else {
- dev_warn(DEV, "Successfully gave up primary role.\n");
+ drbd_warn(device, "Successfully gave up primary role.\n");
rv = hg;
}
} else
@@ -2720,14 +2762,14 @@ static int drbd_asb_recover_2p(struct drbd_conf *mdev) __must_hold(local)
return rv;
}
-static void drbd_uuid_dump(struct drbd_conf *mdev, char *text, u64 *uuid,
+static void drbd_uuid_dump(struct drbd_device *device, char *text, u64 *uuid,
u64 bits, u64 flags)
{
if (!uuid) {
- dev_info(DEV, "%s uuid info vanished while I was looking!\n", text);
+ drbd_info(device, "%s uuid info vanished while I was looking!\n", text);
return;
}
- dev_info(DEV, "%s %016llX:%016llX:%016llX:%016llX bits:%llu flags:%llX\n",
+ drbd_info(device, "%s %016llX:%016llX:%016llX:%016llX bits:%llu flags:%llX\n",
text,
(unsigned long long)uuid[UI_CURRENT],
(unsigned long long)uuid[UI_BITMAP],
@@ -2749,13 +2791,13 @@ static void drbd_uuid_dump(struct drbd_conf *mdev, char *text, u64 *uuid,
-1091 requires proto 91
-1096 requires proto 96
*/
-static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(local)
+static int drbd_uuid_compare(struct drbd_device *device, int *rule_nr) __must_hold(local)
{
u64 self, peer;
int i, j;
- self = mdev->ldev->md.uuid[UI_CURRENT] & ~((u64)1);
- peer = mdev->p_uuid[UI_CURRENT] & ~((u64)1);
+ self = device->ldev->md.uuid[UI_CURRENT] & ~((u64)1);
+ peer = device->p_uuid[UI_CURRENT] & ~((u64)1);
*rule_nr = 10;
if (self == UUID_JUST_CREATED && peer == UUID_JUST_CREATED)
@@ -2774,46 +2816,46 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l
if (self == peer) {
int rct, dc; /* roles at crash time */
- if (mdev->p_uuid[UI_BITMAP] == (u64)0 && mdev->ldev->md.uuid[UI_BITMAP] != (u64)0) {
+ if (device->p_uuid[UI_BITMAP] == (u64)0 && device->ldev->md.uuid[UI_BITMAP] != (u64)0) {
- if (mdev->tconn->agreed_pro_version < 91)
+ if (first_peer_device(device)->connection->agreed_pro_version < 91)
return -1091;
- if ((mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1)) &&
- (mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START + 1] & ~((u64)1))) {
- dev_info(DEV, "was SyncSource, missed the resync finished event, corrected myself:\n");
- drbd_uuid_move_history(mdev);
- mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[UI_BITMAP];
- mdev->ldev->md.uuid[UI_BITMAP] = 0;
+ if ((device->ldev->md.uuid[UI_BITMAP] & ~((u64)1)) == (device->p_uuid[UI_HISTORY_START] & ~((u64)1)) &&
+ (device->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (device->p_uuid[UI_HISTORY_START + 1] & ~((u64)1))) {
+ drbd_info(device, "was SyncSource, missed the resync finished event, corrected myself:\n");
+ drbd_uuid_move_history(device);
+ device->ldev->md.uuid[UI_HISTORY_START] = device->ldev->md.uuid[UI_BITMAP];
+ device->ldev->md.uuid[UI_BITMAP] = 0;
- drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid,
- mdev->state.disk >= D_NEGOTIATING ? drbd_bm_total_weight(mdev) : 0, 0);
+ drbd_uuid_dump(device, "self", device->ldev->md.uuid,
+ device->state.disk >= D_NEGOTIATING ? drbd_bm_total_weight(device) : 0, 0);
*rule_nr = 34;
} else {
- dev_info(DEV, "was SyncSource (peer failed to write sync_uuid)\n");
+ drbd_info(device, "was SyncSource (peer failed to write sync_uuid)\n");
*rule_nr = 36;
}
return 1;
}
- if (mdev->ldev->md.uuid[UI_BITMAP] == (u64)0 && mdev->p_uuid[UI_BITMAP] != (u64)0) {
+ if (device->ldev->md.uuid[UI_BITMAP] == (u64)0 && device->p_uuid[UI_BITMAP] != (u64)0) {
- if (mdev->tconn->agreed_pro_version < 91)
+ if (first_peer_device(device)->connection->agreed_pro_version < 91)
return -1091;
- if ((mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (mdev->p_uuid[UI_BITMAP] & ~((u64)1)) &&
- (mdev->ldev->md.uuid[UI_HISTORY_START + 1] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1))) {
- dev_info(DEV, "was SyncTarget, peer missed the resync finished event, corrected peer:\n");
+ if ((device->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (device->p_uuid[UI_BITMAP] & ~((u64)1)) &&
+ (device->ldev->md.uuid[UI_HISTORY_START + 1] & ~((u64)1)) == (device->p_uuid[UI_HISTORY_START] & ~((u64)1))) {
+ drbd_info(device, "was SyncTarget, peer missed the resync finished event, corrected peer:\n");
- mdev->p_uuid[UI_HISTORY_START + 1] = mdev->p_uuid[UI_HISTORY_START];
- mdev->p_uuid[UI_HISTORY_START] = mdev->p_uuid[UI_BITMAP];
- mdev->p_uuid[UI_BITMAP] = 0UL;
+ device->p_uuid[UI_HISTORY_START + 1] = device->p_uuid[UI_HISTORY_START];
+ device->p_uuid[UI_HISTORY_START] = device->p_uuid[UI_BITMAP];
+ device->p_uuid[UI_BITMAP] = 0UL;
- drbd_uuid_dump(mdev, "peer", mdev->p_uuid, mdev->p_uuid[UI_SIZE], mdev->p_uuid[UI_FLAGS]);
+ drbd_uuid_dump(device, "peer", device->p_uuid, device->p_uuid[UI_SIZE], device->p_uuid[UI_FLAGS]);
*rule_nr = 35;
} else {
- dev_info(DEV, "was SyncTarget (failed to write sync_uuid)\n");
+ drbd_info(device, "was SyncTarget (failed to write sync_uuid)\n");
*rule_nr = 37;
}
@@ -2821,8 +2863,8 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l
}
/* Common power [off|failure] */
- rct = (test_bit(CRASHED_PRIMARY, &mdev->flags) ? 1 : 0) +
- (mdev->p_uuid[UI_FLAGS] & 2);
+ rct = (test_bit(CRASHED_PRIMARY, &device->flags) ? 1 : 0) +
+ (device->p_uuid[UI_FLAGS] & 2);
/* lowest bit is set when we were primary,
* next bit (weight 2) is set when peer was primary */
*rule_nr = 40;
@@ -2832,72 +2874,72 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l
case 1: /* self_pri && !peer_pri */ return 1;
case 2: /* !self_pri && peer_pri */ return -1;
case 3: /* self_pri && peer_pri */
- dc = test_bit(RESOLVE_CONFLICTS, &mdev->tconn->flags);
+ dc = test_bit(RESOLVE_CONFLICTS, &first_peer_device(device)->connection->flags);
return dc ? -1 : 1;
}
}
*rule_nr = 50;
- peer = mdev->p_uuid[UI_BITMAP] & ~((u64)1);
+ peer = device->p_uuid[UI_BITMAP] & ~((u64)1);
if (self == peer)
return -1;
*rule_nr = 51;
- peer = mdev->p_uuid[UI_HISTORY_START] & ~((u64)1);
+ peer = device->p_uuid[UI_HISTORY_START] & ~((u64)1);
if (self == peer) {
- if (mdev->tconn->agreed_pro_version < 96 ?
- (mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) ==
- (mdev->p_uuid[UI_HISTORY_START + 1] & ~((u64)1)) :
- peer + UUID_NEW_BM_OFFSET == (mdev->p_uuid[UI_BITMAP] & ~((u64)1))) {
+ if (first_peer_device(device)->connection->agreed_pro_version < 96 ?
+ (device->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) ==
+ (device->p_uuid[UI_HISTORY_START + 1] & ~((u64)1)) :
+ peer + UUID_NEW_BM_OFFSET == (device->p_uuid[UI_BITMAP] & ~((u64)1))) {
/* The last P_SYNC_UUID did not get though. Undo the last start of
resync as sync source modifications of the peer's UUIDs. */
- if (mdev->tconn->agreed_pro_version < 91)
+ if (first_peer_device(device)->connection->agreed_pro_version < 91)
return -1091;
- mdev->p_uuid[UI_BITMAP] = mdev->p_uuid[UI_HISTORY_START];
- mdev->p_uuid[UI_HISTORY_START] = mdev->p_uuid[UI_HISTORY_START + 1];
+ device->p_uuid[UI_BITMAP] = device->p_uuid[UI_HISTORY_START];
+ device->p_uuid[UI_HISTORY_START] = device->p_uuid[UI_HISTORY_START + 1];
- dev_info(DEV, "Lost last syncUUID packet, corrected:\n");
- drbd_uuid_dump(mdev, "peer", mdev->p_uuid, mdev->p_uuid[UI_SIZE], mdev->p_uuid[UI_FLAGS]);
+ drbd_info(device, "Lost last syncUUID packet, corrected:\n");
+ drbd_uuid_dump(device, "peer", device->p_uuid, device->p_uuid[UI_SIZE], device->p_uuid[UI_FLAGS]);
return -1;
}
}
*rule_nr = 60;
- self = mdev->ldev->md.uuid[UI_CURRENT] & ~((u64)1);
+ self = device->ldev->md.uuid[UI_CURRENT] & ~((u64)1);
for (i = UI_HISTORY_START; i <= UI_HISTORY_END; i++) {
- peer = mdev->p_uuid[i] & ~((u64)1);
+ peer = device->p_uuid[i] & ~((u64)1);
if (self == peer)
return -2;
}
*rule_nr = 70;
- self = mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1);
- peer = mdev->p_uuid[UI_CURRENT] & ~((u64)1);
+ self = device->ldev->md.uuid[UI_BITMAP] & ~((u64)1);
+ peer = device->p_uuid[UI_CURRENT] & ~((u64)1);
if (self == peer)
return 1;
*rule_nr = 71;
- self = mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1);
+ self = device->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1);
if (self == peer) {
- if (mdev->tconn->agreed_pro_version < 96 ?
- (mdev->ldev->md.uuid[UI_HISTORY_START + 1] & ~((u64)1)) ==
- (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1)) :
- self + UUID_NEW_BM_OFFSET == (mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1))) {
+ if (first_peer_device(device)->connection->agreed_pro_version < 96 ?
+ (device->ldev->md.uuid[UI_HISTORY_START + 1] & ~((u64)1)) ==
+ (device->p_uuid[UI_HISTORY_START] & ~((u64)1)) :
+ self + UUID_NEW_BM_OFFSET == (device->ldev->md.uuid[UI_BITMAP] & ~((u64)1))) {
/* The last P_SYNC_UUID did not get though. Undo the last start of
resync as sync source modifications of our UUIDs. */
- if (mdev->tconn->agreed_pro_version < 91)
+ if (first_peer_device(device)->connection->agreed_pro_version < 91)
return -1091;
- __drbd_uuid_set(mdev, UI_BITMAP, mdev->ldev->md.uuid[UI_HISTORY_START]);
- __drbd_uuid_set(mdev, UI_HISTORY_START, mdev->ldev->md.uuid[UI_HISTORY_START + 1]);
+ __drbd_uuid_set(device, UI_BITMAP, device->ldev->md.uuid[UI_HISTORY_START]);
+ __drbd_uuid_set(device, UI_HISTORY_START, device->ldev->md.uuid[UI_HISTORY_START + 1]);
- dev_info(DEV, "Last syncUUID did not get through, corrected:\n");
- drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid,
- mdev->state.disk >= D_NEGOTIATING ? drbd_bm_total_weight(mdev) : 0, 0);
+ drbd_info(device, "Last syncUUID did not get through, corrected:\n");
+ drbd_uuid_dump(device, "self", device->ldev->md.uuid,
+ device->state.disk >= D_NEGOTIATING ? drbd_bm_total_weight(device) : 0, 0);
return 1;
}
@@ -2905,24 +2947,24 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l
*rule_nr = 80;
- peer = mdev->p_uuid[UI_CURRENT] & ~((u64)1);
+ peer = device->p_uuid[UI_CURRENT] & ~((u64)1);
for (i = UI_HISTORY_START; i <= UI_HISTORY_END; i++) {
- self = mdev->ldev->md.uuid[i] & ~((u64)1);
+ self = device->ldev->md.uuid[i] & ~((u64)1);
if (self == peer)
return 2;
}
*rule_nr = 90;
- self = mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1);
- peer = mdev->p_uuid[UI_BITMAP] & ~((u64)1);
+ self = device->ldev->md.uuid[UI_BITMAP] & ~((u64)1);
+ peer = device->p_uuid[UI_BITMAP] & ~((u64)1);
if (self == peer && self != ((u64)0))
return 100;
*rule_nr = 100;
for (i = UI_HISTORY_START; i <= UI_HISTORY_END; i++) {
- self = mdev->ldev->md.uuid[i] & ~((u64)1);
+ self = device->ldev->md.uuid[i] & ~((u64)1);
for (j = UI_HISTORY_START; j <= UI_HISTORY_END; j++) {
- peer = mdev->p_uuid[j] & ~((u64)1);
+ peer = device->p_uuid[j] & ~((u64)1);
if (self == peer)
return -100;
}
@@ -2934,36 +2976,38 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l
/* drbd_sync_handshake() returns the new conn state on success, or
CONN_MASK (-1) on failure.
*/
-static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_role peer_role,
+static enum drbd_conns drbd_sync_handshake(struct drbd_peer_device *peer_device,
+ enum drbd_role peer_role,
enum drbd_disk_state peer_disk) __must_hold(local)
{
+ struct drbd_device *device = peer_device->device;
enum drbd_conns rv = C_MASK;
enum drbd_disk_state mydisk;
struct net_conf *nc;
int hg, rule_nr, rr_conflict, tentative;
- mydisk = mdev->state.disk;
+ mydisk = device->state.disk;
if (mydisk == D_NEGOTIATING)
- mydisk = mdev->new_state_tmp.disk;
+ mydisk = device->new_state_tmp.disk;
- dev_info(DEV, "drbd_sync_handshake:\n");
+ drbd_info(device, "drbd_sync_handshake:\n");
- spin_lock_irq(&mdev->ldev->md.uuid_lock);
- drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid, mdev->comm_bm_set, 0);
- drbd_uuid_dump(mdev, "peer", mdev->p_uuid,
- mdev->p_uuid[UI_SIZE], mdev->p_uuid[UI_FLAGS]);
+ spin_lock_irq(&device->ldev->md.uuid_lock);
+ drbd_uuid_dump(device, "self", device->ldev->md.uuid, device->comm_bm_set, 0);
+ drbd_uuid_dump(device, "peer", device->p_uuid,
+ device->p_uuid[UI_SIZE], device->p_uuid[UI_FLAGS]);
- hg = drbd_uuid_compare(mdev, &rule_nr);
- spin_unlock_irq(&mdev->ldev->md.uuid_lock);
+ hg = drbd_uuid_compare(device, &rule_nr);
+ spin_unlock_irq(&device->ldev->md.uuid_lock);
- dev_info(DEV, "uuid_compare()=%d by rule %d\n", hg, rule_nr);
+ drbd_info(device, "uuid_compare()=%d by rule %d\n", hg, rule_nr);
if (hg == -1000) {
- dev_alert(DEV, "Unrelated data, aborting!\n");
+ drbd_alert(device, "Unrelated data, aborting!\n");
return C_MASK;
}
if (hg < -1000) {
- dev_alert(DEV, "To resolve this both sides have to support at least protocol %d\n", -hg - 1000);
+ drbd_alert(device, "To resolve this both sides have to support at least protocol %d\n", -hg - 1000);
return C_MASK;
}
@@ -2973,38 +3017,38 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol
hg = mydisk > D_INCONSISTENT ? 1 : -1;
if (f)
hg = hg*2;
- dev_info(DEV, "Becoming sync %s due to disk states.\n",
+ drbd_info(device, "Becoming sync %s due to disk states.\n",
hg > 0 ? "source" : "target");
}
if (abs(hg) == 100)
- drbd_khelper(mdev, "initial-split-brain");
+ drbd_khelper(device, "initial-split-brain");
rcu_read_lock();
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(peer_device->connection->net_conf);
if (hg == 100 || (hg == -100 && nc->always_asbp)) {
- int pcount = (mdev->state.role == R_PRIMARY)
+ int pcount = (device->state.role == R_PRIMARY)
+ (peer_role == R_PRIMARY);
int forced = (hg == -100);
switch (pcount) {
case 0:
- hg = drbd_asb_recover_0p(mdev);
+ hg = drbd_asb_recover_0p(peer_device);
break;
case 1:
- hg = drbd_asb_recover_1p(mdev);
+ hg = drbd_asb_recover_1p(peer_device);
break;
case 2:
- hg = drbd_asb_recover_2p(mdev);
+ hg = drbd_asb_recover_2p(peer_device);
break;
}
if (abs(hg) < 100) {
- dev_warn(DEV, "Split-Brain detected, %d primaries, "
+ drbd_warn(device, "Split-Brain detected, %d primaries, "
"automatically solved. Sync from %s node\n",
pcount, (hg < 0) ? "peer" : "this");
if (forced) {
- dev_warn(DEV, "Doing a full sync, since"
+ drbd_warn(device, "Doing a full sync, since"
" UUIDs where ambiguous.\n");
hg = hg*2;
}
@@ -3012,13 +3056,13 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol
}
if (hg == -100) {
- if (test_bit(DISCARD_MY_DATA, &mdev->flags) && !(mdev->p_uuid[UI_FLAGS]&1))
+ if (test_bit(DISCARD_MY_DATA, &device->flags) && !(device->p_uuid[UI_FLAGS]&1))
hg = -1;
- if (!test_bit(DISCARD_MY_DATA, &mdev->flags) && (mdev->p_uuid[UI_FLAGS]&1))
+ if (!test_bit(DISCARD_MY_DATA, &device->flags) && (device->p_uuid[UI_FLAGS]&1))
hg = 1;
if (abs(hg) < 100)
- dev_warn(DEV, "Split-Brain detected, manually solved. "
+ drbd_warn(device, "Split-Brain detected, manually solved. "
"Sync from %s node\n",
(hg < 0) ? "peer" : "this");
}
@@ -3031,44 +3075,44 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol
* after an attempted attach on a diskless node.
* We just refuse to attach -- well, we drop the "connection"
* to that disk, in a way... */
- dev_alert(DEV, "Split-Brain detected but unresolved, dropping connection!\n");
- drbd_khelper(mdev, "split-brain");
+ drbd_alert(device, "Split-Brain detected but unresolved, dropping connection!\n");
+ drbd_khelper(device, "split-brain");
return C_MASK;
}
if (hg > 0 && mydisk <= D_INCONSISTENT) {
- dev_err(DEV, "I shall become SyncSource, but I am inconsistent!\n");
+ drbd_err(device, "I shall become SyncSource, but I am inconsistent!\n");
return C_MASK;
}
if (hg < 0 && /* by intention we do not use mydisk here. */
- mdev->state.role == R_PRIMARY && mdev->state.disk >= D_CONSISTENT) {
+ device->state.role == R_PRIMARY && device->state.disk >= D_CONSISTENT) {
switch (rr_conflict) {
case ASB_CALL_HELPER:
- drbd_khelper(mdev, "pri-lost");
+ drbd_khelper(device, "pri-lost");
/* fall through */
case ASB_DISCONNECT:
- dev_err(DEV, "I shall become SyncTarget, but I am primary!\n");
+ drbd_err(device, "I shall become SyncTarget, but I am primary!\n");
return C_MASK;
case ASB_VIOLENTLY:
- dev_warn(DEV, "Becoming SyncTarget, violating the stable-data"
+ drbd_warn(device, "Becoming SyncTarget, violating the stable-data"
"assumption\n");
}
}
- if (tentative || test_bit(CONN_DRY_RUN, &mdev->tconn->flags)) {
+ if (tentative || test_bit(CONN_DRY_RUN, &peer_device->connection->flags)) {
if (hg == 0)
- dev_info(DEV, "dry-run connect: No resync, would become Connected immediately.\n");
+ drbd_info(device, "dry-run connect: No resync, would become Connected immediately.\n");
else
- dev_info(DEV, "dry-run connect: Would become %s, doing a %s resync.",
+ drbd_info(device, "dry-run connect: Would become %s, doing a %s resync.",
drbd_conn_str(hg > 0 ? C_SYNC_SOURCE : C_SYNC_TARGET),
abs(hg) >= 2 ? "full" : "bit-map based");
return C_MASK;
}
if (abs(hg) >= 2) {
- dev_info(DEV, "Writing the whole bitmap, full sync required after drbd_sync_handshake.\n");
- if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write, "set_n_write from sync_handshake",
+ drbd_info(device, "Writing the whole bitmap, full sync required after drbd_sync_handshake.\n");
+ if (drbd_bitmap_io(device, &drbd_bmio_set_n_write, "set_n_write from sync_handshake",
BM_LOCKED_SET_ALLOWED))
return C_MASK;
}
@@ -3079,9 +3123,9 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol
rv = C_WF_BITMAP_T;
} else {
rv = C_CONNECTED;
- if (drbd_bm_total_weight(mdev)) {
- dev_info(DEV, "No resync, but %lu bits in bitmap!\n",
- drbd_bm_total_weight(mdev));
+ if (drbd_bm_total_weight(device)) {
+ drbd_info(device, "No resync, but %lu bits in bitmap!\n",
+ drbd_bm_total_weight(device));
}
}
@@ -3102,7 +3146,7 @@ static enum drbd_after_sb_p convert_after_sb(enum drbd_after_sb_p peer)
return peer;
}
-static int receive_protocol(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_protocol(struct drbd_connection *connection, struct packet_info *pi)
{
struct p_protocol *p = pi->data;
enum drbd_after_sb_p p_after_sb_0p, p_after_sb_1p, p_after_sb_2p;
@@ -3120,58 +3164,58 @@ static int receive_protocol(struct drbd_tconn *tconn, struct packet_info *pi)
cf = be32_to_cpu(p->conn_flags);
p_discard_my_data = cf & CF_DISCARD_MY_DATA;
- if (tconn->agreed_pro_version >= 87) {
+ if (connection->agreed_pro_version >= 87) {
int err;
if (pi->size > sizeof(integrity_alg))
return -EIO;
- err = drbd_recv_all(tconn, integrity_alg, pi->size);
+ err = drbd_recv_all(connection, integrity_alg, pi->size);
if (err)
return err;
integrity_alg[SHARED_SECRET_MAX - 1] = 0;
}
if (pi->cmd != P_PROTOCOL_UPDATE) {
- clear_bit(CONN_DRY_RUN, &tconn->flags);
+ clear_bit(CONN_DRY_RUN, &connection->flags);
if (cf & CF_DRY_RUN)
- set_bit(CONN_DRY_RUN, &tconn->flags);
+ set_bit(CONN_DRY_RUN, &connection->flags);
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
+ nc = rcu_dereference(connection->net_conf);
if (p_proto != nc->wire_protocol) {
- conn_err(tconn, "incompatible %s settings\n", "protocol");
+ drbd_err(connection, "incompatible %s settings\n", "protocol");
goto disconnect_rcu_unlock;
}
if (convert_after_sb(p_after_sb_0p) != nc->after_sb_0p) {
- conn_err(tconn, "incompatible %s settings\n", "after-sb-0pri");
+ drbd_err(connection, "incompatible %s settings\n", "after-sb-0pri");
goto disconnect_rcu_unlock;
}
if (convert_after_sb(p_after_sb_1p) != nc->after_sb_1p) {
- conn_err(tconn, "incompatible %s settings\n", "after-sb-1pri");
+ drbd_err(connection, "incompatible %s settings\n", "after-sb-1pri");
goto disconnect_rcu_unlock;
}
if (convert_after_sb(p_after_sb_2p) != nc->after_sb_2p) {
- conn_err(tconn, "incompatible %s settings\n", "after-sb-2pri");
+ drbd_err(connection, "incompatible %s settings\n", "after-sb-2pri");
goto disconnect_rcu_unlock;
}
if (p_discard_my_data && nc->discard_my_data) {
- conn_err(tconn, "incompatible %s settings\n", "discard-my-data");
+ drbd_err(connection, "incompatible %s settings\n", "discard-my-data");
goto disconnect_rcu_unlock;
}
if (p_two_primaries != nc->two_primaries) {
- conn_err(tconn, "incompatible %s settings\n", "allow-two-primaries");
+ drbd_err(connection, "incompatible %s settings\n", "allow-two-primaries");
goto disconnect_rcu_unlock;
}
if (strcmp(integrity_alg, nc->integrity_alg)) {
- conn_err(tconn, "incompatible %s settings\n", "data-integrity-alg");
+ drbd_err(connection, "incompatible %s settings\n", "data-integrity-alg");
goto disconnect_rcu_unlock;
}
@@ -3192,7 +3236,7 @@ static int receive_protocol(struct drbd_tconn *tconn, struct packet_info *pi)
peer_integrity_tfm = crypto_alloc_hash(integrity_alg, 0, CRYPTO_ALG_ASYNC);
if (!peer_integrity_tfm) {
- conn_err(tconn, "peer data-integrity-alg %s not supported\n",
+ drbd_err(connection, "peer data-integrity-alg %s not supported\n",
integrity_alg);
goto disconnect;
}
@@ -3201,20 +3245,20 @@ static int receive_protocol(struct drbd_tconn *tconn, struct packet_info *pi)
int_dig_in = kmalloc(hash_size, GFP_KERNEL);
int_dig_vv = kmalloc(hash_size, GFP_KERNEL);
if (!(int_dig_in && int_dig_vv)) {
- conn_err(tconn, "Allocation of buffers for data integrity checking failed\n");
+ drbd_err(connection, "Allocation of buffers for data integrity checking failed\n");
goto disconnect;
}
}
new_net_conf = kmalloc(sizeof(struct net_conf), GFP_KERNEL);
if (!new_net_conf) {
- conn_err(tconn, "Allocation of new net_conf failed\n");
+ drbd_err(connection, "Allocation of new net_conf failed\n");
goto disconnect;
}
- mutex_lock(&tconn->data.mutex);
- mutex_lock(&tconn->conf_update);
- old_net_conf = tconn->net_conf;
+ mutex_lock(&connection->data.mutex);
+ mutex_lock(&connection->resource->conf_update);
+ old_net_conf = connection->net_conf;
*new_net_conf = *old_net_conf;
new_net_conf->wire_protocol = p_proto;
@@ -3223,19 +3267,19 @@ static int receive_protocol(struct drbd_tconn *tconn, struct packet_info *pi)
new_net_conf->after_sb_2p = convert_after_sb(p_after_sb_2p);
new_net_conf->two_primaries = p_two_primaries;
- rcu_assign_pointer(tconn->net_conf, new_net_conf);
- mutex_unlock(&tconn->conf_update);
- mutex_unlock(&tconn->data.mutex);
+ rcu_assign_pointer(connection->net_conf, new_net_conf);
+ mutex_unlock(&connection->resource->conf_update);
+ mutex_unlock(&connection->data.mutex);
- crypto_free_hash(tconn->peer_integrity_tfm);
- kfree(tconn->int_dig_in);
- kfree(tconn->int_dig_vv);
- tconn->peer_integrity_tfm = peer_integrity_tfm;
- tconn->int_dig_in = int_dig_in;
- tconn->int_dig_vv = int_dig_vv;
+ crypto_free_hash(connection->peer_integrity_tfm);
+ kfree(connection->int_dig_in);
+ kfree(connection->int_dig_vv);
+ connection->peer_integrity_tfm = peer_integrity_tfm;
+ connection->int_dig_in = int_dig_in;
+ connection->int_dig_vv = int_dig_vv;
if (strcmp(old_net_conf->integrity_alg, integrity_alg))
- conn_info(tconn, "peer data-integrity-alg: %s\n",
+ drbd_info(connection, "peer data-integrity-alg: %s\n",
integrity_alg[0] ? integrity_alg : "(none)");
synchronize_rcu();
@@ -3248,7 +3292,7 @@ disconnect:
crypto_free_hash(peer_integrity_tfm);
kfree(int_dig_in);
kfree(int_dig_vv);
- conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ conn_request_state(connection, NS(conn, C_DISCONNECTING), CS_HARD);
return -EIO;
}
@@ -3257,7 +3301,8 @@ disconnect:
* return: NULL (alg name was "")
* ERR_PTR(error) if something goes wrong
* or the crypto hash ptr, if it worked out ok. */
-struct crypto_hash *drbd_crypto_alloc_digest_safe(const struct drbd_conf *mdev,
+static
+struct crypto_hash *drbd_crypto_alloc_digest_safe(const struct drbd_device *device,
const char *alg, const char *name)
{
struct crypto_hash *tfm;
@@ -3267,21 +3312,21 @@ struct crypto_hash *drbd_crypto_alloc_digest_safe(const struct drbd_conf *mdev,
tfm = crypto_alloc_hash(alg, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(tfm)) {
- dev_err(DEV, "Can not allocate \"%s\" as %s (reason: %ld)\n",
+ drbd_err(device, "Can not allocate \"%s\" as %s (reason: %ld)\n",
alg, name, PTR_ERR(tfm));
return tfm;
}
return tfm;
}
-static int ignore_remaining_packet(struct drbd_tconn *tconn, struct packet_info *pi)
+static int ignore_remaining_packet(struct drbd_connection *connection, struct packet_info *pi)
{
- void *buffer = tconn->data.rbuf;
+ void *buffer = connection->data.rbuf;
int size = pi->size;
while (size) {
int s = min_t(int, size, DRBD_SOCKET_BUFFER_SIZE);
- s = drbd_recv(tconn, buffer, s);
+ s = drbd_recv(connection, buffer, s);
if (s <= 0) {
if (s < 0)
return s;
@@ -3305,30 +3350,32 @@ static int ignore_remaining_packet(struct drbd_tconn *tconn, struct packet_info
*
* (We can also end up here if drbd is misconfigured.)
*/
-static int config_unknown_volume(struct drbd_tconn *tconn, struct packet_info *pi)
+static int config_unknown_volume(struct drbd_connection *connection, struct packet_info *pi)
{
- conn_warn(tconn, "%s packet received for volume %u, which is not configured locally\n",
+ drbd_warn(connection, "%s packet received for volume %u, which is not configured locally\n",
cmdname(pi->cmd), pi->vnr);
- return ignore_remaining_packet(tconn, pi);
+ return ignore_remaining_packet(connection, pi);
}
-static int receive_SyncParam(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_SyncParam(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_rs_param_95 *p;
unsigned int header_size, data_size, exp_max_sz;
struct crypto_hash *verify_tfm = NULL;
struct crypto_hash *csums_tfm = NULL;
struct net_conf *old_net_conf, *new_net_conf = NULL;
struct disk_conf *old_disk_conf = NULL, *new_disk_conf = NULL;
- const int apv = tconn->agreed_pro_version;
+ const int apv = connection->agreed_pro_version;
struct fifo_buffer *old_plan = NULL, *new_plan = NULL;
int fifo_size = 0;
int err;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
- return config_unknown_volume(tconn, pi);
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
+ return config_unknown_volume(connection, pi);
+ device = peer_device->device;
exp_max_sz = apv <= 87 ? sizeof(struct p_rs_param)
: apv == 88 ? sizeof(struct p_rs_param)
@@ -3337,7 +3384,7 @@ static int receive_SyncParam(struct drbd_tconn *tconn, struct packet_info *pi)
: /* apv >= 95 */ sizeof(struct p_rs_param_95);
if (pi->size > exp_max_sz) {
- dev_err(DEV, "SyncParam packet too long: received %u, expected <= %u bytes\n",
+ drbd_err(device, "SyncParam packet too long: received %u, expected <= %u bytes\n",
pi->size, exp_max_sz);
return -EIO;
}
@@ -3348,33 +3395,33 @@ static int receive_SyncParam(struct drbd_tconn *tconn, struct packet_info *pi)
} else if (apv <= 94) {
header_size = sizeof(struct p_rs_param_89);
data_size = pi->size - header_size;
- D_ASSERT(data_size == 0);
+ D_ASSERT(device, data_size == 0);
} else {
header_size = sizeof(struct p_rs_param_95);
data_size = pi->size - header_size;
- D_ASSERT(data_size == 0);
+ D_ASSERT(device, data_size == 0);
}
/* initialize verify_alg and csums_alg */
p = pi->data;
memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX);
- err = drbd_recv_all(mdev->tconn, p, header_size);
+ err = drbd_recv_all(peer_device->connection, p, header_size);
if (err)
return err;
- mutex_lock(&mdev->tconn->conf_update);
- old_net_conf = mdev->tconn->net_conf;
- if (get_ldev(mdev)) {
+ mutex_lock(&connection->resource->conf_update);
+ old_net_conf = peer_device->connection->net_conf;
+ if (get_ldev(device)) {
new_disk_conf = kzalloc(sizeof(struct disk_conf), GFP_KERNEL);
if (!new_disk_conf) {
- put_ldev(mdev);
- mutex_unlock(&mdev->tconn->conf_update);
- dev_err(DEV, "Allocation of new disk_conf failed\n");
+ put_ldev(device);
+ mutex_unlock(&connection->resource->conf_update);
+ drbd_err(device, "Allocation of new disk_conf failed\n");
return -ENOMEM;
}
- old_disk_conf = mdev->ldev->disk_conf;
+ old_disk_conf = device->ldev->disk_conf;
*new_disk_conf = *old_disk_conf;
new_disk_conf->resync_rate = be32_to_cpu(p->resync_rate);
@@ -3383,37 +3430,37 @@ static int receive_SyncParam(struct drbd_tconn *tconn, struct packet_info *pi)
if (apv >= 88) {
if (apv == 88) {
if (data_size > SHARED_SECRET_MAX || data_size == 0) {
- dev_err(DEV, "verify-alg of wrong size, "
+ drbd_err(device, "verify-alg of wrong size, "
"peer wants %u, accepting only up to %u byte\n",
data_size, SHARED_SECRET_MAX);
err = -EIO;
goto reconnect;
}
- err = drbd_recv_all(mdev->tconn, p->verify_alg, data_size);
+ err = drbd_recv_all(peer_device->connection, p->verify_alg, data_size);
if (err)
goto reconnect;
/* we expect NUL terminated string */
/* but just in case someone tries to be evil */
- D_ASSERT(p->verify_alg[data_size-1] == 0);
+ D_ASSERT(device, p->verify_alg[data_size-1] == 0);
p->verify_alg[data_size-1] = 0;
} else /* apv >= 89 */ {
/* we still expect NUL terminated strings */
/* but just in case someone tries to be evil */
- D_ASSERT(p->verify_alg[SHARED_SECRET_MAX-1] == 0);
- D_ASSERT(p->csums_alg[SHARED_SECRET_MAX-1] == 0);
+ D_ASSERT(device, p->verify_alg[SHARED_SECRET_MAX-1] == 0);
+ D_ASSERT(device, p->csums_alg[SHARED_SECRET_MAX-1] == 0);
p->verify_alg[SHARED_SECRET_MAX-1] = 0;
p->csums_alg[SHARED_SECRET_MAX-1] = 0;
}
if (strcmp(old_net_conf->verify_alg, p->verify_alg)) {
- if (mdev->state.conn == C_WF_REPORT_PARAMS) {
- dev_err(DEV, "Different verify-alg settings. me=\"%s\" peer=\"%s\"\n",
+ if (device->state.conn == C_WF_REPORT_PARAMS) {
+ drbd_err(device, "Different verify-alg settings. me=\"%s\" peer=\"%s\"\n",
old_net_conf->verify_alg, p->verify_alg);
goto disconnect;
}
- verify_tfm = drbd_crypto_alloc_digest_safe(mdev,
+ verify_tfm = drbd_crypto_alloc_digest_safe(device,
p->verify_alg, "verify-alg");
if (IS_ERR(verify_tfm)) {
verify_tfm = NULL;
@@ -3422,12 +3469,12 @@ static int receive_SyncParam(struct drbd_tconn *tconn, struct packet_info *pi)
}
if (apv >= 89 && strcmp(old_net_conf->csums_alg, p->csums_alg)) {
- if (mdev->state.conn == C_WF_REPORT_PARAMS) {
- dev_err(DEV, "Different csums-alg settings. me=\"%s\" peer=\"%s\"\n",
+ if (device->state.conn == C_WF_REPORT_PARAMS) {
+ drbd_err(device, "Different csums-alg settings. me=\"%s\" peer=\"%s\"\n",
old_net_conf->csums_alg, p->csums_alg);
goto disconnect;
}
- csums_tfm = drbd_crypto_alloc_digest_safe(mdev,
+ csums_tfm = drbd_crypto_alloc_digest_safe(device,
p->csums_alg, "csums-alg");
if (IS_ERR(csums_tfm)) {
csums_tfm = NULL;
@@ -3442,11 +3489,11 @@ static int receive_SyncParam(struct drbd_tconn *tconn, struct packet_info *pi)
new_disk_conf->c_max_rate = be32_to_cpu(p->c_max_rate);
fifo_size = (new_disk_conf->c_plan_ahead * 10 * SLEEP_TIME) / HZ;
- if (fifo_size != mdev->rs_plan_s->size) {
+ if (fifo_size != device->rs_plan_s->size) {
new_plan = fifo_alloc(fifo_size);
if (!new_plan) {
- dev_err(DEV, "kmalloc of fifo_buffer failed");
- put_ldev(mdev);
+ drbd_err(device, "kmalloc of fifo_buffer failed");
+ put_ldev(device);
goto disconnect;
}
}
@@ -3455,7 +3502,7 @@ static int receive_SyncParam(struct drbd_tconn *tconn, struct packet_info *pi)
if (verify_tfm || csums_tfm) {
new_net_conf = kzalloc(sizeof(struct net_conf), GFP_KERNEL);
if (!new_net_conf) {
- dev_err(DEV, "Allocation of new net_conf failed\n");
+ drbd_err(device, "Allocation of new net_conf failed\n");
goto disconnect;
}
@@ -3464,32 +3511,32 @@ static int receive_SyncParam(struct drbd_tconn *tconn, struct packet_info *pi)
if (verify_tfm) {
strcpy(new_net_conf->verify_alg, p->verify_alg);
new_net_conf->verify_alg_len = strlen(p->verify_alg) + 1;
- crypto_free_hash(mdev->tconn->verify_tfm);
- mdev->tconn->verify_tfm = verify_tfm;
- dev_info(DEV, "using verify-alg: \"%s\"\n", p->verify_alg);
+ crypto_free_hash(peer_device->connection->verify_tfm);
+ peer_device->connection->verify_tfm = verify_tfm;
+ drbd_info(device, "using verify-alg: \"%s\"\n", p->verify_alg);
}
if (csums_tfm) {
strcpy(new_net_conf->csums_alg, p->csums_alg);
new_net_conf->csums_alg_len = strlen(p->csums_alg) + 1;
- crypto_free_hash(mdev->tconn->csums_tfm);
- mdev->tconn->csums_tfm = csums_tfm;
- dev_info(DEV, "using csums-alg: \"%s\"\n", p->csums_alg);
+ crypto_free_hash(peer_device->connection->csums_tfm);
+ peer_device->connection->csums_tfm = csums_tfm;
+ drbd_info(device, "using csums-alg: \"%s\"\n", p->csums_alg);
}
- rcu_assign_pointer(tconn->net_conf, new_net_conf);
+ rcu_assign_pointer(connection->net_conf, new_net_conf);
}
}
if (new_disk_conf) {
- rcu_assign_pointer(mdev->ldev->disk_conf, new_disk_conf);
- put_ldev(mdev);
+ rcu_assign_pointer(device->ldev->disk_conf, new_disk_conf);
+ put_ldev(device);
}
if (new_plan) {
- old_plan = mdev->rs_plan_s;
- rcu_assign_pointer(mdev->rs_plan_s, new_plan);
+ old_plan = device->rs_plan_s;
+ rcu_assign_pointer(device->rs_plan_s, new_plan);
}
- mutex_unlock(&mdev->tconn->conf_update);
+ mutex_unlock(&connection->resource->conf_update);
synchronize_rcu();
if (new_net_conf)
kfree(old_net_conf);
@@ -3500,30 +3547,30 @@ static int receive_SyncParam(struct drbd_tconn *tconn, struct packet_info *pi)
reconnect:
if (new_disk_conf) {
- put_ldev(mdev);
+ put_ldev(device);
kfree(new_disk_conf);
}
- mutex_unlock(&mdev->tconn->conf_update);
+ mutex_unlock(&connection->resource->conf_update);
return -EIO;
disconnect:
kfree(new_plan);
if (new_disk_conf) {
- put_ldev(mdev);
+ put_ldev(device);
kfree(new_disk_conf);
}
- mutex_unlock(&mdev->tconn->conf_update);
+ mutex_unlock(&connection->resource->conf_update);
/* just for completeness: actually not needed,
* as this is not reached if csums_tfm was ok. */
crypto_free_hash(csums_tfm);
/* but free the verify_tfm again, if csums_tfm did not work out */
crypto_free_hash(verify_tfm);
- conn_request_state(mdev->tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ conn_request_state(peer_device->connection, NS(conn, C_DISCONNECTING), CS_HARD);
return -EIO;
}
/* warn if the arguments differ by more than 12.5% */
-static void warn_if_differ_considerably(struct drbd_conf *mdev,
+static void warn_if_differ_considerably(struct drbd_device *device,
const char *s, sector_t a, sector_t b)
{
sector_t d;
@@ -3531,54 +3578,56 @@ static void warn_if_differ_considerably(struct drbd_conf *mdev,
return;
d = (a > b) ? (a - b) : (b - a);
if (d > (a>>3) || d > (b>>3))
- dev_warn(DEV, "Considerable difference in %s: %llus vs. %llus\n", s,
+ drbd_warn(device, "Considerable difference in %s: %llus vs. %llus\n", s,
(unsigned long long)a, (unsigned long long)b);
}
-static int receive_sizes(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_sizes(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_sizes *p = pi->data;
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;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
- return config_unknown_volume(tconn, pi);
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
+ return config_unknown_volume(connection, pi);
+ device = peer_device->device;
p_size = be64_to_cpu(p->d_size);
p_usize = be64_to_cpu(p->u_size);
/* just store the peer's disk size for now.
* we still need to figure out whether we accept that. */
- mdev->p_size = p_size;
+ device->p_size = p_size;
- if (get_ldev(mdev)) {
+ if (get_ldev(device)) {
rcu_read_lock();
- my_usize = rcu_dereference(mdev->ldev->disk_conf)->disk_size;
+ my_usize = rcu_dereference(device->ldev->disk_conf)->disk_size;
rcu_read_unlock();
- warn_if_differ_considerably(mdev, "lower level device sizes",
- p_size, drbd_get_max_capacity(mdev->ldev));
- warn_if_differ_considerably(mdev, "user requested size",
+ warn_if_differ_considerably(device, "lower level device sizes",
+ p_size, drbd_get_max_capacity(device->ldev));
+ warn_if_differ_considerably(device, "user requested size",
p_usize, my_usize);
/* if this is the first connect, or an otherwise expected
* param exchange, choose the minimum */
- if (mdev->state.conn == C_WF_REPORT_PARAMS)
+ if (device->state.conn == C_WF_REPORT_PARAMS)
p_usize = min_not_zero(my_usize, p_usize);
/* Never shrink a device with usable data during connect.
But allow online shrinking if we are connected. */
- if (drbd_new_dev_size(mdev, mdev->ldev, p_usize, 0) <
- drbd_get_capacity(mdev->this_bdev) &&
- mdev->state.disk >= D_OUTDATED &&
- mdev->state.conn < C_CONNECTED) {
- dev_err(DEV, "The peer's disk size is too small!\n");
- conn_request_state(mdev->tconn, NS(conn, C_DISCONNECTING), CS_HARD);
- put_ldev(mdev);
+ if (drbd_new_dev_size(device, device->ldev, p_usize, 0) <
+ drbd_get_capacity(device->this_bdev) &&
+ device->state.disk >= D_OUTDATED &&
+ device->state.conn < C_CONNECTED) {
+ drbd_err(device, "The peer's disk size is too small!\n");
+ conn_request_state(peer_device->connection, NS(conn, C_DISCONNECTING), CS_HARD);
+ put_ldev(device);
return -EIO;
}
@@ -3587,145 +3636,147 @@ static int receive_sizes(struct drbd_tconn *tconn, struct packet_info *pi)
new_disk_conf = kzalloc(sizeof(struct disk_conf), GFP_KERNEL);
if (!new_disk_conf) {
- dev_err(DEV, "Allocation of new disk_conf failed\n");
- put_ldev(mdev);
+ drbd_err(device, "Allocation of new disk_conf failed\n");
+ put_ldev(device);
return -ENOMEM;
}
- mutex_lock(&mdev->tconn->conf_update);
- old_disk_conf = mdev->ldev->disk_conf;
+ mutex_lock(&connection->resource->conf_update);
+ old_disk_conf = device->ldev->disk_conf;
*new_disk_conf = *old_disk_conf;
new_disk_conf->disk_size = p_usize;
- rcu_assign_pointer(mdev->ldev->disk_conf, new_disk_conf);
- mutex_unlock(&mdev->tconn->conf_update);
+ rcu_assign_pointer(device->ldev->disk_conf, new_disk_conf);
+ mutex_unlock(&connection->resource->conf_update);
synchronize_rcu();
kfree(old_disk_conf);
- dev_info(DEV, "Peer sets u_size to %lu sectors\n",
+ drbd_info(device, "Peer sets u_size to %lu sectors\n",
(unsigned long)my_usize);
}
- put_ldev(mdev);
+ put_ldev(device);
}
ddsf = be16_to_cpu(p->dds_flags);
- if (get_ldev(mdev)) {
- dd = drbd_determine_dev_size(mdev, ddsf, NULL);
- put_ldev(mdev);
+ if (get_ldev(device)) {
+ dd = drbd_determine_dev_size(device, ddsf, NULL);
+ put_ldev(device);
if (dd == DS_ERROR)
return -EIO;
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
} else {
/* I am diskless, need to accept the peer's size. */
- drbd_set_my_capacity(mdev, p_size);
+ drbd_set_my_capacity(device, p_size);
}
- mdev->peer_max_bio_size = be32_to_cpu(p->max_bio_size);
- drbd_reconsider_max_bio_size(mdev);
+ device->peer_max_bio_size = be32_to_cpu(p->max_bio_size);
+ drbd_reconsider_max_bio_size(device);
- if (get_ldev(mdev)) {
- if (mdev->ldev->known_size != drbd_get_capacity(mdev->ldev->backing_bdev)) {
- mdev->ldev->known_size = drbd_get_capacity(mdev->ldev->backing_bdev);
+ if (get_ldev(device)) {
+ if (device->ldev->known_size != drbd_get_capacity(device->ldev->backing_bdev)) {
+ device->ldev->known_size = drbd_get_capacity(device->ldev->backing_bdev);
ldsc = 1;
}
- put_ldev(mdev);
+ put_ldev(device);
}
- if (mdev->state.conn > C_WF_REPORT_PARAMS) {
+ if (device->state.conn > C_WF_REPORT_PARAMS) {
if (be64_to_cpu(p->c_size) !=
- drbd_get_capacity(mdev->this_bdev) || ldsc) {
+ drbd_get_capacity(device->this_bdev) || ldsc) {
/* we have different sizes, probably peer
* needs to know my new size... */
- drbd_send_sizes(mdev, 0, ddsf);
+ drbd_send_sizes(peer_device, 0, ddsf);
}
- if (test_and_clear_bit(RESIZE_PENDING, &mdev->flags) ||
- (dd == DS_GREW && mdev->state.conn == C_CONNECTED)) {
- if (mdev->state.pdsk >= D_INCONSISTENT &&
- mdev->state.disk >= D_INCONSISTENT) {
+ if (test_and_clear_bit(RESIZE_PENDING, &device->flags) ||
+ (dd == DS_GREW && device->state.conn == C_CONNECTED)) {
+ if (device->state.pdsk >= D_INCONSISTENT &&
+ device->state.disk >= D_INCONSISTENT) {
if (ddsf & DDSF_NO_RESYNC)
- dev_info(DEV, "Resync of new storage suppressed with --assume-clean\n");
+ drbd_info(device, "Resync of new storage suppressed with --assume-clean\n");
else
- resync_after_online_grow(mdev);
+ resync_after_online_grow(device);
} else
- set_bit(RESYNC_AFTER_NEG, &mdev->flags);
+ set_bit(RESYNC_AFTER_NEG, &device->flags);
}
}
return 0;
}
-static int receive_uuids(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_uuids(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_uuids *p = pi->data;
u64 *p_uuid;
int i, updated_uuids = 0;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
- return config_unknown_volume(tconn, pi);
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
+ return config_unknown_volume(connection, pi);
+ device = peer_device->device;
p_uuid = kmalloc(sizeof(u64)*UI_EXTENDED_SIZE, GFP_NOIO);
if (!p_uuid) {
- dev_err(DEV, "kmalloc of p_uuid failed\n");
+ drbd_err(device, "kmalloc of p_uuid failed\n");
return false;
}
for (i = UI_CURRENT; i < UI_EXTENDED_SIZE; i++)
p_uuid[i] = be64_to_cpu(p->uuid[i]);
- kfree(mdev->p_uuid);
- mdev->p_uuid = p_uuid;
+ kfree(device->p_uuid);
+ device->p_uuid = p_uuid;
- if (mdev->state.conn < C_CONNECTED &&
- mdev->state.disk < D_INCONSISTENT &&
- mdev->state.role == R_PRIMARY &&
- (mdev->ed_uuid & ~((u64)1)) != (p_uuid[UI_CURRENT] & ~((u64)1))) {
- dev_err(DEV, "Can only connect to data with current UUID=%016llX\n",
- (unsigned long long)mdev->ed_uuid);
- conn_request_state(mdev->tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ if (device->state.conn < C_CONNECTED &&
+ device->state.disk < D_INCONSISTENT &&
+ device->state.role == R_PRIMARY &&
+ (device->ed_uuid & ~((u64)1)) != (p_uuid[UI_CURRENT] & ~((u64)1))) {
+ drbd_err(device, "Can only connect to data with current UUID=%016llX\n",
+ (unsigned long long)device->ed_uuid);
+ conn_request_state(peer_device->connection, NS(conn, C_DISCONNECTING), CS_HARD);
return -EIO;
}
- if (get_ldev(mdev)) {
+ if (get_ldev(device)) {
int skip_initial_sync =
- mdev->state.conn == C_CONNECTED &&
- mdev->tconn->agreed_pro_version >= 90 &&
- mdev->ldev->md.uuid[UI_CURRENT] == UUID_JUST_CREATED &&
+ device->state.conn == C_CONNECTED &&
+ peer_device->connection->agreed_pro_version >= 90 &&
+ device->ldev->md.uuid[UI_CURRENT] == UUID_JUST_CREATED &&
(p_uuid[UI_FLAGS] & 8);
if (skip_initial_sync) {
- dev_info(DEV, "Accepted new current UUID, preparing to skip initial sync\n");
- drbd_bitmap_io(mdev, &drbd_bmio_clear_n_write,
+ drbd_info(device, "Accepted new current UUID, preparing to skip initial sync\n");
+ drbd_bitmap_io(device, &drbd_bmio_clear_n_write,
"clear_n_write from receive_uuids",
BM_LOCKED_TEST_ALLOWED);
- _drbd_uuid_set(mdev, UI_CURRENT, p_uuid[UI_CURRENT]);
- _drbd_uuid_set(mdev, UI_BITMAP, 0);
- _drbd_set_state(_NS2(mdev, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE),
+ _drbd_uuid_set(device, UI_CURRENT, p_uuid[UI_CURRENT]);
+ _drbd_uuid_set(device, UI_BITMAP, 0);
+ _drbd_set_state(_NS2(device, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE),
CS_VERBOSE, NULL);
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
updated_uuids = 1;
}
- put_ldev(mdev);
- } else if (mdev->state.disk < D_INCONSISTENT &&
- mdev->state.role == R_PRIMARY) {
+ put_ldev(device);
+ } else if (device->state.disk < D_INCONSISTENT &&
+ device->state.role == R_PRIMARY) {
/* I am a diskless primary, the peer just created a new current UUID
for me. */
- updated_uuids = drbd_set_ed_uuid(mdev, p_uuid[UI_CURRENT]);
+ updated_uuids = drbd_set_ed_uuid(device, p_uuid[UI_CURRENT]);
}
/* Before we test for the disk state, we should wait until an eventually
ongoing cluster wide state change is finished. That is important if
we are primary and are detaching from our disk. We need to see the
new disk state... */
- mutex_lock(mdev->state_mutex);
- mutex_unlock(mdev->state_mutex);
- if (mdev->state.conn >= C_CONNECTED && mdev->state.disk < D_INCONSISTENT)
- updated_uuids |= drbd_set_ed_uuid(mdev, p_uuid[UI_CURRENT]);
+ mutex_lock(device->state_mutex);
+ mutex_unlock(device->state_mutex);
+ if (device->state.conn >= C_CONNECTED && device->state.disk < D_INCONSISTENT)
+ updated_uuids |= drbd_set_ed_uuid(device, p_uuid[UI_CURRENT]);
if (updated_uuids)
- drbd_print_uuids(mdev, "receiver updated UUIDs to");
+ drbd_print_uuids(device, "receiver updated UUIDs to");
return 0;
}
@@ -3761,38 +3812,40 @@ static union drbd_state convert_state(union drbd_state ps)
return ms;
}
-static int receive_req_state(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_req_state(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_req_state *p = pi->data;
union drbd_state mask, val;
enum drbd_state_rv rv;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
mask.i = be32_to_cpu(p->mask);
val.i = be32_to_cpu(p->val);
- if (test_bit(RESOLVE_CONFLICTS, &mdev->tconn->flags) &&
- mutex_is_locked(mdev->state_mutex)) {
- drbd_send_sr_reply(mdev, SS_CONCURRENT_ST_CHG);
+ if (test_bit(RESOLVE_CONFLICTS, &peer_device->connection->flags) &&
+ mutex_is_locked(device->state_mutex)) {
+ drbd_send_sr_reply(peer_device, SS_CONCURRENT_ST_CHG);
return 0;
}
mask = convert_state(mask);
val = convert_state(val);
- rv = drbd_change_state(mdev, CS_VERBOSE, mask, val);
- drbd_send_sr_reply(mdev, rv);
+ rv = drbd_change_state(device, CS_VERBOSE, mask, val);
+ drbd_send_sr_reply(peer_device, rv);
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
return 0;
}
-static int receive_req_conn_state(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_req_conn_state(struct drbd_connection *connection, struct packet_info *pi)
{
struct p_req_state *p = pi->data;
union drbd_state mask, val;
@@ -3801,46 +3854,48 @@ static int receive_req_conn_state(struct drbd_tconn *tconn, struct packet_info *
mask.i = be32_to_cpu(p->mask);
val.i = be32_to_cpu(p->val);
- if (test_bit(RESOLVE_CONFLICTS, &tconn->flags) &&
- mutex_is_locked(&tconn->cstate_mutex)) {
- conn_send_sr_reply(tconn, SS_CONCURRENT_ST_CHG);
+ if (test_bit(RESOLVE_CONFLICTS, &connection->flags) &&
+ mutex_is_locked(&connection->cstate_mutex)) {
+ conn_send_sr_reply(connection, SS_CONCURRENT_ST_CHG);
return 0;
}
mask = convert_state(mask);
val = convert_state(val);
- rv = conn_request_state(tconn, mask, val, CS_VERBOSE | CS_LOCAL_ONLY | CS_IGN_OUTD_FAIL);
- conn_send_sr_reply(tconn, rv);
+ rv = conn_request_state(connection, mask, val, CS_VERBOSE | CS_LOCAL_ONLY | CS_IGN_OUTD_FAIL);
+ conn_send_sr_reply(connection, rv);
return 0;
}
-static int receive_state(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_state(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_state *p = pi->data;
union drbd_state os, ns, peer_state;
enum drbd_disk_state real_peer_disk;
enum chg_state_flags cs_flags;
int rv;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
- return config_unknown_volume(tconn, pi);
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
+ return config_unknown_volume(connection, pi);
+ device = peer_device->device;
peer_state.i = be32_to_cpu(p->state);
real_peer_disk = peer_state.disk;
if (peer_state.disk == D_NEGOTIATING) {
- real_peer_disk = mdev->p_uuid[UI_FLAGS] & 4 ? D_INCONSISTENT : D_CONSISTENT;
- dev_info(DEV, "real peer disk state = %s\n", drbd_disk_str(real_peer_disk));
+ real_peer_disk = device->p_uuid[UI_FLAGS] & 4 ? D_INCONSISTENT : D_CONSISTENT;
+ drbd_info(device, "real peer disk state = %s\n", drbd_disk_str(real_peer_disk));
}
- spin_lock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
retry:
- os = ns = drbd_read_state(mdev);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ os = ns = drbd_read_state(device);
+ spin_unlock_irq(&device->resource->req_lock);
/* If some other part of the code (asender thread, timeout)
* already decided to close the connection again,
@@ -3872,8 +3927,8 @@ static int receive_state(struct drbd_tconn *tconn, struct packet_info *pi)
* Maybe we should finish it up, too? */
else if (os.conn >= C_SYNC_SOURCE &&
peer_state.conn == C_CONNECTED) {
- if (drbd_bm_total_weight(mdev) <= mdev->rs_failed)
- drbd_resync_finished(mdev);
+ if (drbd_bm_total_weight(device) <= device->rs_failed)
+ drbd_resync_finished(device);
return 0;
}
}
@@ -3881,8 +3936,8 @@ static int receive_state(struct drbd_tconn *tconn, struct packet_info *pi)
/* explicit verify finished notification, stop sector reached. */
if (os.conn == C_VERIFY_T && os.disk == D_UP_TO_DATE &&
peer_state.conn == C_CONNECTED && real_peer_disk == D_UP_TO_DATE) {
- ov_out_of_sync_print(mdev);
- drbd_resync_finished(mdev);
+ ov_out_of_sync_print(device);
+ drbd_resync_finished(device);
return 0;
}
@@ -3901,8 +3956,8 @@ static int receive_state(struct drbd_tconn *tconn, struct packet_info *pi)
if (peer_state.conn == C_AHEAD)
ns.conn = C_BEHIND;
- if (mdev->p_uuid && peer_state.disk >= D_NEGOTIATING &&
- get_ldev_if_state(mdev, D_NEGOTIATING)) {
+ if (device->p_uuid && peer_state.disk >= D_NEGOTIATING &&
+ get_ldev_if_state(device, D_NEGOTIATING)) {
int cr; /* consider resync */
/* if we established a new connection */
@@ -3914,7 +3969,7 @@ static int receive_state(struct drbd_tconn *tconn, struct packet_info *pi)
os.disk == D_NEGOTIATING));
/* if we have both been inconsistent, and the peer has been
* forced to be UpToDate with --overwrite-data */
- cr |= test_bit(CONSIDER_RESYNC, &mdev->flags);
+ cr |= test_bit(CONSIDER_RESYNC, &device->flags);
/* if we had been plain connected, and the admin requested to
* start a sync by "invalidate" or "invalidate-remote" */
cr |= (os.conn == C_CONNECTED &&
@@ -3922,55 +3977,55 @@ static int receive_state(struct drbd_tconn *tconn, struct packet_info *pi)
peer_state.conn <= C_WF_BITMAP_T));
if (cr)
- ns.conn = drbd_sync_handshake(mdev, peer_state.role, real_peer_disk);
+ ns.conn = drbd_sync_handshake(peer_device, peer_state.role, real_peer_disk);
- put_ldev(mdev);
+ put_ldev(device);
if (ns.conn == C_MASK) {
ns.conn = C_CONNECTED;
- if (mdev->state.disk == D_NEGOTIATING) {
- drbd_force_state(mdev, NS(disk, D_FAILED));
+ if (device->state.disk == D_NEGOTIATING) {
+ drbd_force_state(device, NS(disk, D_FAILED));
} else if (peer_state.disk == D_NEGOTIATING) {
- dev_err(DEV, "Disk attach process on the peer node was aborted.\n");
+ drbd_err(device, "Disk attach process on the peer node was aborted.\n");
peer_state.disk = D_DISKLESS;
real_peer_disk = D_DISKLESS;
} else {
- if (test_and_clear_bit(CONN_DRY_RUN, &mdev->tconn->flags))
+ if (test_and_clear_bit(CONN_DRY_RUN, &peer_device->connection->flags))
return -EIO;
- D_ASSERT(os.conn == C_WF_REPORT_PARAMS);
- conn_request_state(mdev->tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ D_ASSERT(device, os.conn == C_WF_REPORT_PARAMS);
+ conn_request_state(peer_device->connection, NS(conn, C_DISCONNECTING), CS_HARD);
return -EIO;
}
}
}
- spin_lock_irq(&mdev->tconn->req_lock);
- if (os.i != drbd_read_state(mdev).i)
+ spin_lock_irq(&device->resource->req_lock);
+ if (os.i != drbd_read_state(device).i)
goto retry;
- clear_bit(CONSIDER_RESYNC, &mdev->flags);
+ clear_bit(CONSIDER_RESYNC, &device->flags);
ns.peer = peer_state.role;
ns.pdsk = real_peer_disk;
ns.peer_isp = (peer_state.aftr_isp | peer_state.user_isp);
if ((ns.conn == C_CONNECTED || ns.conn == C_WF_BITMAP_S) && ns.disk == D_NEGOTIATING)
- ns.disk = mdev->new_state_tmp.disk;
+ ns.disk = device->new_state_tmp.disk;
cs_flags = CS_VERBOSE + (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED ? 0 : CS_HARD);
- if (ns.pdsk == D_CONSISTENT && drbd_suspended(mdev) && ns.conn == C_CONNECTED && os.conn < C_CONNECTED &&
- test_bit(NEW_CUR_UUID, &mdev->flags)) {
+ if (ns.pdsk == D_CONSISTENT && drbd_suspended(device) && ns.conn == C_CONNECTED && os.conn < C_CONNECTED &&
+ test_bit(NEW_CUR_UUID, &device->flags)) {
/* Do not allow tl_restart(RESEND) for a rebooted peer. We can only allow this
for temporal network outages! */
- spin_unlock_irq(&mdev->tconn->req_lock);
- dev_err(DEV, "Aborting Connect, can not thaw IO with an only Consistent peer\n");
- tl_clear(mdev->tconn);
- drbd_uuid_new_current(mdev);
- clear_bit(NEW_CUR_UUID, &mdev->flags);
- conn_request_state(mdev->tconn, NS2(conn, C_PROTOCOL_ERROR, susp, 0), CS_HARD);
+ spin_unlock_irq(&device->resource->req_lock);
+ drbd_err(device, "Aborting Connect, can not thaw IO with an only Consistent peer\n");
+ tl_clear(peer_device->connection);
+ drbd_uuid_new_current(device);
+ clear_bit(NEW_CUR_UUID, &device->flags);
+ conn_request_state(peer_device->connection, NS2(conn, C_PROTOCOL_ERROR, susp, 0), CS_HARD);
return -EIO;
}
- rv = _drbd_set_state(mdev, ns, cs_flags, NULL);
- ns = drbd_read_state(mdev);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ rv = _drbd_set_state(device, ns, cs_flags, NULL);
+ ns = drbd_read_state(device);
+ spin_unlock_irq(&device->resource->req_lock);
if (rv < SS_SUCCESS) {
- conn_request_state(mdev->tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ conn_request_state(peer_device->connection, NS(conn, C_DISCONNECTING), CS_HARD);
return -EIO;
}
@@ -3980,47 +4035,49 @@ static int receive_state(struct drbd_tconn *tconn, struct packet_info *pi)
/* we want resync, peer has not yet decided to sync... */
/* Nowadays only used when forcing a node into primary role and
setting its disk to UpToDate with that */
- drbd_send_uuids(mdev);
- drbd_send_current_state(mdev);
+ drbd_send_uuids(peer_device);
+ drbd_send_current_state(peer_device);
}
}
- clear_bit(DISCARD_MY_DATA, &mdev->flags);
+ clear_bit(DISCARD_MY_DATA, &device->flags);
- drbd_md_sync(mdev); /* update connected indicator, la_size_sect, ... */
+ drbd_md_sync(device); /* update connected indicator, la_size_sect, ... */
return 0;
}
-static int receive_sync_uuid(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_sync_uuid(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_rs_uuid *p = pi->data;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
- wait_event(mdev->misc_wait,
- mdev->state.conn == C_WF_SYNC_UUID ||
- mdev->state.conn == C_BEHIND ||
- mdev->state.conn < C_CONNECTED ||
- mdev->state.disk < D_NEGOTIATING);
+ wait_event(device->misc_wait,
+ device->state.conn == C_WF_SYNC_UUID ||
+ device->state.conn == C_BEHIND ||
+ device->state.conn < C_CONNECTED ||
+ device->state.disk < D_NEGOTIATING);
- /* D_ASSERT( mdev->state.conn == C_WF_SYNC_UUID ); */
+ /* D_ASSERT(device, device->state.conn == C_WF_SYNC_UUID ); */
/* Here the _drbd_uuid_ functions are right, current should
_not_ be rotated into the history */
- if (get_ldev_if_state(mdev, D_NEGOTIATING)) {
- _drbd_uuid_set(mdev, UI_CURRENT, be64_to_cpu(p->uuid));
- _drbd_uuid_set(mdev, UI_BITMAP, 0UL);
+ if (get_ldev_if_state(device, D_NEGOTIATING)) {
+ _drbd_uuid_set(device, UI_CURRENT, be64_to_cpu(p->uuid));
+ _drbd_uuid_set(device, UI_BITMAP, 0UL);
- drbd_print_uuids(mdev, "updated sync uuid");
- drbd_start_resync(mdev, C_SYNC_TARGET);
+ drbd_print_uuids(device, "updated sync uuid");
+ drbd_start_resync(device, C_SYNC_TARGET);
- put_ldev(mdev);
+ put_ldev(device);
} else
- dev_err(DEV, "Ignoring SyncUUID packet!\n");
+ drbd_err(device, "Ignoring SyncUUID packet!\n");
return 0;
}
@@ -4032,27 +4089,27 @@ static int receive_sync_uuid(struct drbd_tconn *tconn, struct packet_info *pi)
* code upon failure.
*/
static int
-receive_bitmap_plain(struct drbd_conf *mdev, unsigned int size,
+receive_bitmap_plain(struct drbd_peer_device *peer_device, unsigned int size,
unsigned long *p, struct bm_xfer_ctx *c)
{
unsigned int data_size = DRBD_SOCKET_BUFFER_SIZE -
- drbd_header_size(mdev->tconn);
+ drbd_header_size(peer_device->connection);
unsigned int num_words = min_t(size_t, data_size / sizeof(*p),
c->bm_words - c->word_offset);
unsigned int want = num_words * sizeof(*p);
int err;
if (want != size) {
- dev_err(DEV, "%s:want (%u) != size (%u)\n", __func__, want, size);
+ drbd_err(peer_device, "%s:want (%u) != size (%u)\n", __func__, want, size);
return -EIO;
}
if (want == 0)
return 0;
- err = drbd_recv_all(mdev->tconn, p, want);
+ err = drbd_recv_all(peer_device->connection, p, want);
if (err)
return err;
- drbd_bm_merge_lel(mdev, c->word_offset, num_words, p);
+ drbd_bm_merge_lel(peer_device->device, c->word_offset, num_words, p);
c->word_offset += num_words;
c->bit_offset = c->word_offset * BITS_PER_LONG;
@@ -4084,7 +4141,7 @@ static int dcbp_get_pad_bits(struct p_compressed_bm *p)
* code upon failure.
*/
static int
-recv_bm_rle_bits(struct drbd_conf *mdev,
+recv_bm_rle_bits(struct drbd_peer_device *peer_device,
struct p_compressed_bm *p,
struct bm_xfer_ctx *c,
unsigned int len)
@@ -4113,14 +4170,14 @@ recv_bm_rle_bits(struct drbd_conf *mdev,
if (toggle) {
e = s + rl -1;
if (e >= c->bm_bits) {
- dev_err(DEV, "bitmap overflow (e:%lu) while decoding bm RLE packet\n", e);
+ drbd_err(peer_device, "bitmap overflow (e:%lu) while decoding bm RLE packet\n", e);
return -EIO;
}
- _drbd_bm_set_bits(mdev, s, e);
+ _drbd_bm_set_bits(peer_device->device, s, e);
}
if (have < bits) {
- dev_err(DEV, "bitmap decoding error: h:%d b:%d la:0x%08llx l:%u/%u\n",
+ drbd_err(peer_device, "bitmap decoding error: h:%d b:%d la:0x%08llx l:%u/%u\n",
have, bits, look_ahead,
(unsigned int)(bs.cur.b - p->code),
(unsigned int)bs.buf_len);
@@ -4153,28 +4210,28 @@ recv_bm_rle_bits(struct drbd_conf *mdev,
* code upon failure.
*/
static int
-decode_bitmap_c(struct drbd_conf *mdev,
+decode_bitmap_c(struct drbd_peer_device *peer_device,
struct p_compressed_bm *p,
struct bm_xfer_ctx *c,
unsigned int len)
{
if (dcbp_get_code(p) == RLE_VLI_Bits)
- return recv_bm_rle_bits(mdev, p, c, len - sizeof(*p));
+ return recv_bm_rle_bits(peer_device, p, c, len - sizeof(*p));
/* other variants had been implemented for evaluation,
* but have been dropped as this one turned out to be "best"
* during all our tests. */
- dev_err(DEV, "receive_bitmap_c: unknown encoding %u\n", p->encoding);
- conn_request_state(mdev->tconn, NS(conn, C_PROTOCOL_ERROR), CS_HARD);
+ drbd_err(peer_device, "receive_bitmap_c: unknown encoding %u\n", p->encoding);
+ conn_request_state(peer_device->connection, NS(conn, C_PROTOCOL_ERROR), CS_HARD);
return -EIO;
}
-void INFO_bm_xfer_stats(struct drbd_conf *mdev,
+void INFO_bm_xfer_stats(struct drbd_device *device,
const char *direction, struct bm_xfer_ctx *c)
{
/* what would it take to transfer it "plaintext" */
- unsigned int header_size = drbd_header_size(mdev->tconn);
+ unsigned int header_size = drbd_header_size(first_peer_device(device)->connection);
unsigned int data_size = DRBD_SOCKET_BUFFER_SIZE - header_size;
unsigned int plain =
header_size * (DIV_ROUND_UP(c->bm_words, data_size) + 1) +
@@ -4198,7 +4255,7 @@ void INFO_bm_xfer_stats(struct drbd_conf *mdev,
r = 1000;
r = 1000 - r;
- dev_info(DEV, "%s bitmap stats [Bytes(packets)]: plain %u(%u), RLE %u(%u), "
+ drbd_info(device, "%s bitmap stats [Bytes(packets)]: plain %u(%u), RLE %u(%u), "
"total %u; compression: %u.%u%%\n",
direction,
c->bytes[1], c->packets[1],
@@ -4214,129 +4271,133 @@ void INFO_bm_xfer_stats(struct drbd_conf *mdev,
in order to be agnostic to the 32 vs 64 bits issue.
returns 0 on failure, 1 if we successfully received it. */
-static int receive_bitmap(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_bitmap(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct bm_xfer_ctx c;
int err;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
- drbd_bm_lock(mdev, "receive bitmap", BM_LOCKED_SET_ALLOWED);
+ drbd_bm_lock(device, "receive bitmap", BM_LOCKED_SET_ALLOWED);
/* you are supposed to send additional out-of-sync information
* if you actually set bits during this phase */
c = (struct bm_xfer_ctx) {
- .bm_bits = drbd_bm_bits(mdev),
- .bm_words = drbd_bm_words(mdev),
+ .bm_bits = drbd_bm_bits(device),
+ .bm_words = drbd_bm_words(device),
};
for(;;) {
if (pi->cmd == P_BITMAP)
- err = receive_bitmap_plain(mdev, pi->size, pi->data, &c);
+ err = receive_bitmap_plain(peer_device, pi->size, pi->data, &c);
else if (pi->cmd == P_COMPRESSED_BITMAP) {
/* MAYBE: sanity check that we speak proto >= 90,
* and the feature is enabled! */
struct p_compressed_bm *p = pi->data;
- if (pi->size > DRBD_SOCKET_BUFFER_SIZE - drbd_header_size(tconn)) {
- dev_err(DEV, "ReportCBitmap packet too large\n");
+ if (pi->size > DRBD_SOCKET_BUFFER_SIZE - drbd_header_size(connection)) {
+ drbd_err(device, "ReportCBitmap packet too large\n");
err = -EIO;
goto out;
}
if (pi->size <= sizeof(*p)) {
- dev_err(DEV, "ReportCBitmap packet too small (l:%u)\n", pi->size);
+ drbd_err(device, "ReportCBitmap packet too small (l:%u)\n", pi->size);
err = -EIO;
goto out;
}
- err = drbd_recv_all(mdev->tconn, p, pi->size);
+ err = drbd_recv_all(peer_device->connection, p, pi->size);
if (err)
goto out;
- err = decode_bitmap_c(mdev, p, &c, pi->size);
+ err = decode_bitmap_c(peer_device, p, &c, pi->size);
} else {
- dev_warn(DEV, "receive_bitmap: cmd neither ReportBitMap nor ReportCBitMap (is 0x%x)", pi->cmd);
+ drbd_warn(device, "receive_bitmap: cmd neither ReportBitMap nor ReportCBitMap (is 0x%x)", pi->cmd);
err = -EIO;
goto out;
}
c.packets[pi->cmd == P_BITMAP]++;
- c.bytes[pi->cmd == P_BITMAP] += drbd_header_size(tconn) + pi->size;
+ c.bytes[pi->cmd == P_BITMAP] += drbd_header_size(connection) + pi->size;
if (err <= 0) {
if (err < 0)
goto out;
break;
}
- err = drbd_recv_header(mdev->tconn, pi);
+ err = drbd_recv_header(peer_device->connection, pi);
if (err)
goto out;
}
- INFO_bm_xfer_stats(mdev, "receive", &c);
+ INFO_bm_xfer_stats(device, "receive", &c);
- if (mdev->state.conn == C_WF_BITMAP_T) {
+ if (device->state.conn == C_WF_BITMAP_T) {
enum drbd_state_rv rv;
- err = drbd_send_bitmap(mdev);
+ err = drbd_send_bitmap(device);
if (err)
goto out;
/* Omit CS_ORDERED with this state transition to avoid deadlocks. */
- rv = _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE);
- D_ASSERT(rv == SS_SUCCESS);
- } else if (mdev->state.conn != C_WF_BITMAP_S) {
+ rv = _drbd_request_state(device, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE);
+ D_ASSERT(device, rv == SS_SUCCESS);
+ } else if (device->state.conn != C_WF_BITMAP_S) {
/* admin may have requested C_DISCONNECTING,
* other threads may have noticed network errors */
- dev_info(DEV, "unexpected cstate (%s) in receive_bitmap\n",
- drbd_conn_str(mdev->state.conn));
+ drbd_info(device, "unexpected cstate (%s) in receive_bitmap\n",
+ drbd_conn_str(device->state.conn));
}
err = 0;
out:
- drbd_bm_unlock(mdev);
- if (!err && mdev->state.conn == C_WF_BITMAP_S)
- drbd_start_resync(mdev, C_SYNC_SOURCE);
+ drbd_bm_unlock(device);
+ if (!err && device->state.conn == C_WF_BITMAP_S)
+ drbd_start_resync(device, C_SYNC_SOURCE);
return err;
}
-static int receive_skip(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_skip(struct drbd_connection *connection, struct packet_info *pi)
{
- conn_warn(tconn, "skipping unknown optional packet type %d, l: %d!\n",
+ drbd_warn(connection, "skipping unknown optional packet type %d, l: %d!\n",
pi->cmd, pi->size);
- return ignore_remaining_packet(tconn, pi);
+ return ignore_remaining_packet(connection, pi);
}
-static int receive_UnplugRemote(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_UnplugRemote(struct drbd_connection *connection, struct packet_info *pi)
{
/* Make sure we've acked all the TCP data associated
* with the data requests being unplugged */
- drbd_tcp_quickack(tconn->data.socket);
+ drbd_tcp_quickack(connection->data.socket);
return 0;
}
-static int receive_out_of_sync(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_out_of_sync(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_block_desc *p = pi->data;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
- switch (mdev->state.conn) {
+ switch (device->state.conn) {
case C_WF_SYNC_UUID:
case C_WF_BITMAP_T:
case C_BEHIND:
break;
default:
- dev_err(DEV, "ASSERT FAILED cstate = %s, expected: WFSyncUUID|WFBitMapT|Behind\n",
- drbd_conn_str(mdev->state.conn));
+ drbd_err(device, "ASSERT FAILED cstate = %s, expected: WFSyncUUID|WFBitMapT|Behind\n",
+ drbd_conn_str(device->state.conn));
}
- drbd_set_out_of_sync(mdev, be64_to_cpu(p->sector), be32_to_cpu(p->blksize));
+ drbd_set_out_of_sync(device, be64_to_cpu(p->sector), be32_to_cpu(p->blksize));
return 0;
}
@@ -4344,7 +4405,7 @@ static int receive_out_of_sync(struct drbd_tconn *tconn, struct packet_info *pi)
struct data_cmd {
int expect_payload;
size_t pkt_size;
- int (*fn)(struct drbd_tconn *, struct packet_info *);
+ int (*fn)(struct drbd_connection *, struct packet_info *);
};
static struct data_cmd drbd_cmd_handler[] = {
@@ -4374,43 +4435,43 @@ static struct data_cmd drbd_cmd_handler[] = {
[P_PROTOCOL_UPDATE] = { 1, sizeof(struct p_protocol), receive_protocol },
};
-static void drbdd(struct drbd_tconn *tconn)
+static void drbdd(struct drbd_connection *connection)
{
struct packet_info pi;
size_t shs; /* sub header size */
int err;
- while (get_t_state(&tconn->receiver) == RUNNING) {
+ while (get_t_state(&connection->receiver) == RUNNING) {
struct data_cmd *cmd;
- drbd_thread_current_set_cpu(&tconn->receiver);
- if (drbd_recv_header(tconn, &pi))
+ drbd_thread_current_set_cpu(&connection->receiver);
+ if (drbd_recv_header(connection, &pi))
goto err_out;
cmd = &drbd_cmd_handler[pi.cmd];
if (unlikely(pi.cmd >= ARRAY_SIZE(drbd_cmd_handler) || !cmd->fn)) {
- conn_err(tconn, "Unexpected data packet %s (0x%04x)",
+ drbd_err(connection, "Unexpected data packet %s (0x%04x)",
cmdname(pi.cmd), pi.cmd);
goto err_out;
}
shs = cmd->pkt_size;
if (pi.size > shs && !cmd->expect_payload) {
- conn_err(tconn, "No payload expected %s l:%d\n",
+ drbd_err(connection, "No payload expected %s l:%d\n",
cmdname(pi.cmd), pi.size);
goto err_out;
}
if (shs) {
- err = drbd_recv_all_warn(tconn, pi.data, shs);
+ err = drbd_recv_all_warn(connection, pi.data, shs);
if (err)
goto err_out;
pi.size -= shs;
}
- err = cmd->fn(tconn, &pi);
+ err = cmd->fn(connection, &pi);
if (err) {
- conn_err(tconn, "error receiving %s, e: %d l: %d!\n",
+ drbd_err(connection, "error receiving %s, e: %d l: %d!\n",
cmdname(pi.cmd), err, pi.size);
goto err_out;
}
@@ -4418,27 +4479,16 @@ static void drbdd(struct drbd_tconn *tconn)
return;
err_out:
- conn_request_state(tconn, NS(conn, C_PROTOCOL_ERROR), CS_HARD);
-}
-
-void conn_flush_workqueue(struct drbd_tconn *tconn)
-{
- struct drbd_wq_barrier barr;
-
- barr.w.cb = w_prev_work_done;
- barr.w.tconn = tconn;
- init_completion(&barr.done);
- drbd_queue_work(&tconn->sender_work, &barr.w);
- wait_for_completion(&barr.done);
+ conn_request_state(connection, NS(conn, C_PROTOCOL_ERROR), CS_HARD);
}
-static void conn_disconnect(struct drbd_tconn *tconn)
+static void conn_disconnect(struct drbd_connection *connection)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
enum drbd_conns oc;
int vnr;
- if (tconn->cstate == C_STANDALONE)
+ if (connection->cstate == C_STANDALONE)
return;
/* We are about to start the cleanup after connection loss.
@@ -4446,54 +4496,56 @@ static void conn_disconnect(struct drbd_tconn *tconn)
* Usually we should be in some network failure state already,
* but just in case we are not, we fix it up here.
*/
- conn_request_state(tconn, NS(conn, C_NETWORK_FAILURE), CS_HARD);
+ conn_request_state(connection, NS(conn, C_NETWORK_FAILURE), CS_HARD);
/* asender does not clean up anything. it must not interfere, either */
- drbd_thread_stop(&tconn->asender);
- drbd_free_sock(tconn);
+ drbd_thread_stop(&connection->asender);
+ drbd_free_sock(connection);
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- kref_get(&mdev->kref);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ kref_get(&device->kref);
rcu_read_unlock();
- drbd_disconnected(mdev);
- kref_put(&mdev->kref, &drbd_minor_destroy);
+ drbd_disconnected(peer_device);
+ kref_put(&device->kref, drbd_destroy_device);
rcu_read_lock();
}
rcu_read_unlock();
- if (!list_empty(&tconn->current_epoch->list))
- conn_err(tconn, "ASSERTION FAILED: tconn->current_epoch->list not empty\n");
+ if (!list_empty(&connection->current_epoch->list))
+ drbd_err(connection, "ASSERTION FAILED: connection->current_epoch->list not empty\n");
/* ok, no more ee's on the fly, it is safe to reset the epoch_size */
- atomic_set(&tconn->current_epoch->epoch_size, 0);
- tconn->send.seen_any_write_yet = false;
+ atomic_set(&connection->current_epoch->epoch_size, 0);
+ connection->send.seen_any_write_yet = false;
- conn_info(tconn, "Connection closed\n");
+ drbd_info(connection, "Connection closed\n");
- if (conn_highest_role(tconn) == R_PRIMARY && conn_highest_pdsk(tconn) >= D_UNKNOWN)
- conn_try_outdate_peer_async(tconn);
+ if (conn_highest_role(connection) == R_PRIMARY && conn_highest_pdsk(connection) >= D_UNKNOWN)
+ conn_try_outdate_peer_async(connection);
- spin_lock_irq(&tconn->req_lock);
- oc = tconn->cstate;
+ spin_lock_irq(&connection->resource->req_lock);
+ oc = connection->cstate;
if (oc >= C_UNCONNECTED)
- _conn_request_state(tconn, NS(conn, C_UNCONNECTED), CS_VERBOSE);
+ _conn_request_state(connection, NS(conn, C_UNCONNECTED), CS_VERBOSE);
- spin_unlock_irq(&tconn->req_lock);
+ spin_unlock_irq(&connection->resource->req_lock);
if (oc == C_DISCONNECTING)
- conn_request_state(tconn, NS(conn, C_STANDALONE), CS_VERBOSE | CS_HARD);
+ conn_request_state(connection, NS(conn, C_STANDALONE), CS_VERBOSE | CS_HARD);
}
-static int drbd_disconnected(struct drbd_conf *mdev)
+static int drbd_disconnected(struct drbd_peer_device *peer_device)
{
+ struct drbd_device *device = peer_device->device;
unsigned int i;
/* wait for current activity to cease. */
- spin_lock_irq(&mdev->tconn->req_lock);
- _drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
- _drbd_wait_ee_list_empty(mdev, &mdev->sync_ee);
- _drbd_wait_ee_list_empty(mdev, &mdev->read_ee);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
+ _drbd_wait_ee_list_empty(device, &device->active_ee);
+ _drbd_wait_ee_list_empty(device, &device->sync_ee);
+ _drbd_wait_ee_list_empty(device, &device->read_ee);
+ spin_unlock_irq(&device->resource->req_lock);
/* We do not have data structures that would allow us to
* get the rs_pending_cnt down to 0 again.
@@ -4505,42 +4557,42 @@ static int drbd_disconnected(struct drbd_conf *mdev)
* resync_LRU. The resync_LRU tracks the whole operation including
* the disk-IO, while the rs_pending_cnt only tracks the blocks
* on the fly. */
- drbd_rs_cancel_all(mdev);
- mdev->rs_total = 0;
- mdev->rs_failed = 0;
- atomic_set(&mdev->rs_pending_cnt, 0);
- wake_up(&mdev->misc_wait);
+ drbd_rs_cancel_all(device);
+ device->rs_total = 0;
+ device->rs_failed = 0;
+ atomic_set(&device->rs_pending_cnt, 0);
+ wake_up(&device->misc_wait);
- del_timer_sync(&mdev->resync_timer);
- resync_timer_fn((unsigned long)mdev);
+ del_timer_sync(&device->resync_timer);
+ resync_timer_fn((unsigned long)device);
/* wait for all w_e_end_data_req, w_e_end_rsdata_req, w_send_barrier,
* w_make_resync_request etc. which may still be on the worker queue
* to be "canceled" */
- drbd_flush_workqueue(mdev);
+ drbd_flush_workqueue(&peer_device->connection->sender_work);
- drbd_finish_peer_reqs(mdev);
+ drbd_finish_peer_reqs(device);
/* This second workqueue flush is necessary, since drbd_finish_peer_reqs()
might have issued a work again. The one before drbd_finish_peer_reqs() is
necessary to reclain net_ee in drbd_finish_peer_reqs(). */
- drbd_flush_workqueue(mdev);
+ drbd_flush_workqueue(&peer_device->connection->sender_work);
/* need to do it again, drbd_finish_peer_reqs() may have populated it
* again via drbd_try_clear_on_disk_bm(). */
- drbd_rs_cancel_all(mdev);
+ drbd_rs_cancel_all(device);
- kfree(mdev->p_uuid);
- mdev->p_uuid = NULL;
+ kfree(device->p_uuid);
+ device->p_uuid = NULL;
- if (!drbd_suspended(mdev))
- tl_clear(mdev->tconn);
+ if (!drbd_suspended(device))
+ tl_clear(peer_device->connection);
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
/* serialize with bitmap writeout triggered by the state change,
* if any. */
- wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags));
+ wait_event(device->misc_wait, !test_bit(BITMAP_IO, &device->flags));
/* tcp_close and release of sendpage pages can be deferred. I don't
* want to use SO_LINGER, because apparently it can be deferred for
@@ -4549,20 +4601,20 @@ static int drbd_disconnected(struct drbd_conf *mdev)
* Actually we don't care for exactly when the network stack does its
* put_page(), but release our reference on these pages right here.
*/
- i = drbd_free_peer_reqs(mdev, &mdev->net_ee);
+ i = drbd_free_peer_reqs(device, &device->net_ee);
if (i)
- dev_info(DEV, "net_ee not empty, killed %u entries\n", i);
- i = atomic_read(&mdev->pp_in_use_by_net);
+ drbd_info(device, "net_ee not empty, killed %u entries\n", i);
+ i = atomic_read(&device->pp_in_use_by_net);
if (i)
- dev_info(DEV, "pp_in_use_by_net = %d, expected 0\n", i);
- i = atomic_read(&mdev->pp_in_use);
+ drbd_info(device, "pp_in_use_by_net = %d, expected 0\n", i);
+ i = atomic_read(&device->pp_in_use);
if (i)
- dev_info(DEV, "pp_in_use = %d, expected 0\n", i);
+ drbd_info(device, "pp_in_use = %d, expected 0\n", i);
- D_ASSERT(list_empty(&mdev->read_ee));
- D_ASSERT(list_empty(&mdev->active_ee));
- D_ASSERT(list_empty(&mdev->sync_ee));
- D_ASSERT(list_empty(&mdev->done_ee));
+ D_ASSERT(device, list_empty(&device->read_ee));
+ D_ASSERT(device, list_empty(&device->active_ee));
+ D_ASSERT(device, list_empty(&device->sync_ee));
+ D_ASSERT(device, list_empty(&device->done_ee));
return 0;
}
@@ -4576,19 +4628,19 @@ static int drbd_disconnected(struct drbd_conf *mdev)
*
* for now, they are expected to be zero, but ignored.
*/
-static int drbd_send_features(struct drbd_tconn *tconn)
+static int drbd_send_features(struct drbd_connection *connection)
{
struct drbd_socket *sock;
struct p_connection_features *p;
- sock = &tconn->data;
- p = conn_prepare_command(tconn, sock);
+ sock = &connection->data;
+ p = conn_prepare_command(connection, sock);
if (!p)
return -EIO;
memset(p, 0, sizeof(*p));
p->protocol_min = cpu_to_be32(PRO_VERSION_MIN);
p->protocol_max = cpu_to_be32(PRO_VERSION_MAX);
- return conn_send_command(tconn, sock, P_CONNECTION_FEATURES, sizeof(*p), NULL, 0);
+ return conn_send_command(connection, sock, P_CONNECTION_FEATURES, sizeof(*p), NULL, 0);
}
/*
@@ -4598,36 +4650,36 @@ static int drbd_send_features(struct drbd_tconn *tconn)
* -1 peer talks different language,
* no point in trying again, please go standalone.
*/
-static int drbd_do_features(struct drbd_tconn *tconn)
+static int drbd_do_features(struct drbd_connection *connection)
{
- /* ASSERT current == tconn->receiver ... */
+ /* ASSERT current == connection->receiver ... */
struct p_connection_features *p;
const int expect = sizeof(struct p_connection_features);
struct packet_info pi;
int err;
- err = drbd_send_features(tconn);
+ err = drbd_send_features(connection);
if (err)
return 0;
- err = drbd_recv_header(tconn, &pi);
+ err = drbd_recv_header(connection, &pi);
if (err)
return 0;
if (pi.cmd != P_CONNECTION_FEATURES) {
- conn_err(tconn, "expected ConnectionFeatures packet, received: %s (0x%04x)\n",
+ drbd_err(connection, "expected ConnectionFeatures packet, received: %s (0x%04x)\n",
cmdname(pi.cmd), pi.cmd);
return -1;
}
if (pi.size != expect) {
- conn_err(tconn, "expected ConnectionFeatures length: %u, received: %u\n",
+ drbd_err(connection, "expected ConnectionFeatures length: %u, received: %u\n",
expect, pi.size);
return -1;
}
p = pi.data;
- err = drbd_recv_all_warn(tconn, p, expect);
+ err = drbd_recv_all_warn(connection, p, expect);
if (err)
return 0;
@@ -4640,15 +4692,15 @@ static int drbd_do_features(struct drbd_tconn *tconn)
PRO_VERSION_MIN > p->protocol_max)
goto incompat;
- tconn->agreed_pro_version = min_t(int, PRO_VERSION_MAX, p->protocol_max);
+ connection->agreed_pro_version = min_t(int, PRO_VERSION_MAX, p->protocol_max);
- conn_info(tconn, "Handshake successful: "
- "Agreed network protocol version %d\n", tconn->agreed_pro_version);
+ drbd_info(connection, "Handshake successful: "
+ "Agreed network protocol version %d\n", connection->agreed_pro_version);
return 1;
incompat:
- conn_err(tconn, "incompatible DRBD dialects: "
+ drbd_err(connection, "incompatible DRBD dialects: "
"I support %d-%d, peer supports %d-%d\n",
PRO_VERSION_MIN, PRO_VERSION_MAX,
p->protocol_min, p->protocol_max);
@@ -4656,10 +4708,10 @@ static int drbd_do_features(struct drbd_tconn *tconn)
}
#if !defined(CONFIG_CRYPTO_HMAC) && !defined(CONFIG_CRYPTO_HMAC_MODULE)
-static int drbd_do_auth(struct drbd_tconn *tconn)
+static int drbd_do_auth(struct drbd_connection *connection)
{
- conn_err(tconn, "This kernel was build without CONFIG_CRYPTO_HMAC.\n");
- conn_err(tconn, "You need to disable 'cram-hmac-alg' in drbd.conf.\n");
+ drbd_err(connection, "This kernel was build without CONFIG_CRYPTO_HMAC.\n");
+ drbd_err(connection, "You need to disable 'cram-hmac-alg' in drbd.conf.\n");
return -1;
}
#else
@@ -4671,7 +4723,7 @@ static int drbd_do_auth(struct drbd_tconn *tconn)
-1 - auth failed, don't try again.
*/
-static int drbd_do_auth(struct drbd_tconn *tconn)
+static int drbd_do_auth(struct drbd_connection *connection)
{
struct drbd_socket *sock;
char my_challenge[CHALLENGE_LEN]; /* 64 Bytes... */
@@ -4690,69 +4742,69 @@ static int drbd_do_auth(struct drbd_tconn *tconn)
/* FIXME: Put the challenge/response into the preallocated socket buffer. */
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
+ nc = rcu_dereference(connection->net_conf);
key_len = strlen(nc->shared_secret);
memcpy(secret, nc->shared_secret, key_len);
rcu_read_unlock();
- desc.tfm = tconn->cram_hmac_tfm;
+ desc.tfm = connection->cram_hmac_tfm;
desc.flags = 0;
- rv = crypto_hash_setkey(tconn->cram_hmac_tfm, (u8 *)secret, key_len);
+ rv = crypto_hash_setkey(connection->cram_hmac_tfm, (u8 *)secret, key_len);
if (rv) {
- conn_err(tconn, "crypto_hash_setkey() failed with %d\n", rv);
+ drbd_err(connection, "crypto_hash_setkey() failed with %d\n", rv);
rv = -1;
goto fail;
}
get_random_bytes(my_challenge, CHALLENGE_LEN);
- sock = &tconn->data;
- if (!conn_prepare_command(tconn, sock)) {
+ sock = &connection->data;
+ if (!conn_prepare_command(connection, sock)) {
rv = 0;
goto fail;
}
- rv = !conn_send_command(tconn, sock, P_AUTH_CHALLENGE, 0,
+ rv = !conn_send_command(connection, sock, P_AUTH_CHALLENGE, 0,
my_challenge, CHALLENGE_LEN);
if (!rv)
goto fail;
- err = drbd_recv_header(tconn, &pi);
+ err = drbd_recv_header(connection, &pi);
if (err) {
rv = 0;
goto fail;
}
if (pi.cmd != P_AUTH_CHALLENGE) {
- conn_err(tconn, "expected AuthChallenge packet, received: %s (0x%04x)\n",
+ drbd_err(connection, "expected AuthChallenge packet, received: %s (0x%04x)\n",
cmdname(pi.cmd), pi.cmd);
rv = 0;
goto fail;
}
if (pi.size > CHALLENGE_LEN * 2) {
- conn_err(tconn, "expected AuthChallenge payload too big.\n");
+ drbd_err(connection, "expected AuthChallenge payload too big.\n");
rv = -1;
goto fail;
}
peers_ch = kmalloc(pi.size, GFP_NOIO);
if (peers_ch == NULL) {
- conn_err(tconn, "kmalloc of peers_ch failed\n");
+ drbd_err(connection, "kmalloc of peers_ch failed\n");
rv = -1;
goto fail;
}
- err = drbd_recv_all_warn(tconn, peers_ch, pi.size);
+ err = drbd_recv_all_warn(connection, peers_ch, pi.size);
if (err) {
rv = 0;
goto fail;
}
- resp_size = crypto_hash_digestsize(tconn->cram_hmac_tfm);
+ resp_size = crypto_hash_digestsize(connection->cram_hmac_tfm);
response = kmalloc(resp_size, GFP_NOIO);
if (response == NULL) {
- conn_err(tconn, "kmalloc of response failed\n");
+ drbd_err(connection, "kmalloc of response failed\n");
rv = -1;
goto fail;
}
@@ -4762,40 +4814,40 @@ static int drbd_do_auth(struct drbd_tconn *tconn)
rv = crypto_hash_digest(&desc, &sg, sg.length, response);
if (rv) {
- conn_err(tconn, "crypto_hash_digest() failed with %d\n", rv);
+ drbd_err(connection, "crypto_hash_digest() failed with %d\n", rv);
rv = -1;
goto fail;
}
- if (!conn_prepare_command(tconn, sock)) {
+ if (!conn_prepare_command(connection, sock)) {
rv = 0;
goto fail;
}
- rv = !conn_send_command(tconn, sock, P_AUTH_RESPONSE, 0,
+ rv = !conn_send_command(connection, sock, P_AUTH_RESPONSE, 0,
response, resp_size);
if (!rv)
goto fail;
- err = drbd_recv_header(tconn, &pi);
+ err = drbd_recv_header(connection, &pi);
if (err) {
rv = 0;
goto fail;
}
if (pi.cmd != P_AUTH_RESPONSE) {
- conn_err(tconn, "expected AuthResponse packet, received: %s (0x%04x)\n",
+ drbd_err(connection, "expected AuthResponse packet, received: %s (0x%04x)\n",
cmdname(pi.cmd), pi.cmd);
rv = 0;
goto fail;
}
if (pi.size != resp_size) {
- conn_err(tconn, "expected AuthResponse payload of wrong size\n");
+ drbd_err(connection, "expected AuthResponse payload of wrong size\n");
rv = 0;
goto fail;
}
- err = drbd_recv_all_warn(tconn, response , resp_size);
+ err = drbd_recv_all_warn(connection, response , resp_size);
if (err) {
rv = 0;
goto fail;
@@ -4803,7 +4855,7 @@ static int drbd_do_auth(struct drbd_tconn *tconn)
right_response = kmalloc(resp_size, GFP_NOIO);
if (right_response == NULL) {
- conn_err(tconn, "kmalloc of right_response failed\n");
+ drbd_err(connection, "kmalloc of right_response failed\n");
rv = -1;
goto fail;
}
@@ -4812,7 +4864,7 @@ static int drbd_do_auth(struct drbd_tconn *tconn)
rv = crypto_hash_digest(&desc, &sg, sg.length, right_response);
if (rv) {
- conn_err(tconn, "crypto_hash_digest() failed with %d\n", rv);
+ drbd_err(connection, "crypto_hash_digest() failed with %d\n", rv);
rv = -1;
goto fail;
}
@@ -4820,7 +4872,7 @@ static int drbd_do_auth(struct drbd_tconn *tconn)
rv = !memcmp(response, right_response, resp_size);
if (rv)
- conn_info(tconn, "Peer authenticated using %d bytes HMAC\n",
+ drbd_info(connection, "Peer authenticated using %d bytes HMAC\n",
resp_size);
else
rv = -1;
@@ -4834,163 +4886,169 @@ static int drbd_do_auth(struct drbd_tconn *tconn)
}
#endif
-int drbdd_init(struct drbd_thread *thi)
+int drbd_receiver(struct drbd_thread *thi)
{
- struct drbd_tconn *tconn = thi->tconn;
+ struct drbd_connection *connection = thi->connection;
int h;
- conn_info(tconn, "receiver (re)started\n");
+ drbd_info(connection, "receiver (re)started\n");
do {
- h = conn_connect(tconn);
+ h = conn_connect(connection);
if (h == 0) {
- conn_disconnect(tconn);
+ conn_disconnect(connection);
schedule_timeout_interruptible(HZ);
}
if (h == -1) {
- conn_warn(tconn, "Discarding network configuration.\n");
- conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ drbd_warn(connection, "Discarding network configuration.\n");
+ conn_request_state(connection, NS(conn, C_DISCONNECTING), CS_HARD);
}
} while (h == 0);
if (h > 0)
- drbdd(tconn);
+ drbdd(connection);
- conn_disconnect(tconn);
+ conn_disconnect(connection);
- conn_info(tconn, "receiver terminated\n");
+ drbd_info(connection, "receiver terminated\n");
return 0;
}
/* ********* acknowledge sender ******** */
-static int got_conn_RqSReply(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_conn_RqSReply(struct drbd_connection *connection, struct packet_info *pi)
{
struct p_req_state_reply *p = pi->data;
int retcode = be32_to_cpu(p->retcode);
if (retcode >= SS_SUCCESS) {
- set_bit(CONN_WD_ST_CHG_OKAY, &tconn->flags);
+ set_bit(CONN_WD_ST_CHG_OKAY, &connection->flags);
} else {
- set_bit(CONN_WD_ST_CHG_FAIL, &tconn->flags);
- conn_err(tconn, "Requested state change failed by peer: %s (%d)\n",
+ set_bit(CONN_WD_ST_CHG_FAIL, &connection->flags);
+ drbd_err(connection, "Requested state change failed by peer: %s (%d)\n",
drbd_set_st_err_str(retcode), retcode);
}
- wake_up(&tconn->ping_wait);
+ wake_up(&connection->ping_wait);
return 0;
}
-static int got_RqSReply(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_RqSReply(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_req_state_reply *p = pi->data;
int retcode = be32_to_cpu(p->retcode);
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
- if (test_bit(CONN_WD_ST_CHG_REQ, &tconn->flags)) {
- D_ASSERT(tconn->agreed_pro_version < 100);
- return got_conn_RqSReply(tconn, pi);
+ if (test_bit(CONN_WD_ST_CHG_REQ, &connection->flags)) {
+ D_ASSERT(device, connection->agreed_pro_version < 100);
+ return got_conn_RqSReply(connection, pi);
}
if (retcode >= SS_SUCCESS) {
- set_bit(CL_ST_CHG_SUCCESS, &mdev->flags);
+ set_bit(CL_ST_CHG_SUCCESS, &device->flags);
} else {
- set_bit(CL_ST_CHG_FAIL, &mdev->flags);
- dev_err(DEV, "Requested state change failed by peer: %s (%d)\n",
+ set_bit(CL_ST_CHG_FAIL, &device->flags);
+ drbd_err(device, "Requested state change failed by peer: %s (%d)\n",
drbd_set_st_err_str(retcode), retcode);
}
- wake_up(&mdev->state_wait);
+ wake_up(&device->state_wait);
return 0;
}
-static int got_Ping(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_Ping(struct drbd_connection *connection, struct packet_info *pi)
{
- return drbd_send_ping_ack(tconn);
+ return drbd_send_ping_ack(connection);
}
-static int got_PingAck(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_PingAck(struct drbd_connection *connection, struct packet_info *pi)
{
/* restore idle timeout */
- tconn->meta.socket->sk->sk_rcvtimeo = tconn->net_conf->ping_int*HZ;
- if (!test_and_set_bit(GOT_PING_ACK, &tconn->flags))
- wake_up(&tconn->ping_wait);
+ connection->meta.socket->sk->sk_rcvtimeo = connection->net_conf->ping_int*HZ;
+ if (!test_and_set_bit(GOT_PING_ACK, &connection->flags))
+ wake_up(&connection->ping_wait);
return 0;
}
-static int got_IsInSync(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_IsInSync(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_block_ack *p = pi->data;
sector_t sector = be64_to_cpu(p->sector);
int blksize = be32_to_cpu(p->blksize);
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
- D_ASSERT(mdev->tconn->agreed_pro_version >= 89);
+ D_ASSERT(device, peer_device->connection->agreed_pro_version >= 89);
- update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+ update_peer_seq(peer_device, be32_to_cpu(p->seq_num));
- if (get_ldev(mdev)) {
- drbd_rs_complete_io(mdev, sector);
- drbd_set_in_sync(mdev, sector, blksize);
+ if (get_ldev(device)) {
+ drbd_rs_complete_io(device, sector);
+ drbd_set_in_sync(device, sector, blksize);
/* rs_same_csums is supposed to count in units of BM_BLOCK_SIZE */
- mdev->rs_same_csum += (blksize >> BM_BLOCK_SHIFT);
- put_ldev(mdev);
+ device->rs_same_csum += (blksize >> BM_BLOCK_SHIFT);
+ put_ldev(device);
}
- dec_rs_pending(mdev);
- atomic_add(blksize >> 9, &mdev->rs_sect_in);
+ dec_rs_pending(device);
+ atomic_add(blksize >> 9, &device->rs_sect_in);
return 0;
}
static int
-validate_req_change_req_state(struct drbd_conf *mdev, u64 id, sector_t sector,
+validate_req_change_req_state(struct drbd_device *device, u64 id, sector_t sector,
struct rb_root *root, const char *func,
enum drbd_req_event what, bool missing_ok)
{
struct drbd_request *req;
struct bio_and_error m;
- spin_lock_irq(&mdev->tconn->req_lock);
- req = find_request(mdev, root, id, sector, missing_ok, func);
+ spin_lock_irq(&device->resource->req_lock);
+ req = find_request(device, root, id, sector, missing_ok, func);
if (unlikely(!req)) {
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
return -EIO;
}
__req_mod(req, what, &m);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
if (m.bio)
- complete_master_bio(mdev, &m);
+ complete_master_bio(device, &m);
return 0;
}
-static int got_BlockAck(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_BlockAck(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_block_ack *p = pi->data;
sector_t sector = be64_to_cpu(p->sector);
int blksize = be32_to_cpu(p->blksize);
enum drbd_req_event what;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
- update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+ update_peer_seq(peer_device, be32_to_cpu(p->seq_num));
if (p->block_id == ID_SYNCER) {
- drbd_set_in_sync(mdev, sector, blksize);
- dec_rs_pending(mdev);
+ drbd_set_in_sync(device, sector, blksize);
+ dec_rs_pending(device);
return 0;
}
switch (pi->cmd) {
@@ -5013,33 +5071,35 @@ static int got_BlockAck(struct drbd_tconn *tconn, struct packet_info *pi)
BUG();
}
- return validate_req_change_req_state(mdev, p->block_id, sector,
- &mdev->write_requests, __func__,
+ return validate_req_change_req_state(device, p->block_id, sector,
+ &device->write_requests, __func__,
what, false);
}
-static int got_NegAck(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_NegAck(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_block_ack *p = pi->data;
sector_t sector = be64_to_cpu(p->sector);
int size = be32_to_cpu(p->blksize);
int err;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
- update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+ update_peer_seq(peer_device, be32_to_cpu(p->seq_num));
if (p->block_id == ID_SYNCER) {
- dec_rs_pending(mdev);
- drbd_rs_failed_io(mdev, sector, size);
+ dec_rs_pending(device);
+ drbd_rs_failed_io(device, sector, size);
return 0;
}
- err = validate_req_change_req_state(mdev, p->block_id, sector,
- &mdev->write_requests, __func__,
+ err = validate_req_change_req_state(device, p->block_id, sector,
+ &device->write_requests, __func__,
NEG_ACKED, true);
if (err) {
/* Protocol A has no P_WRITE_ACKs, but has P_NEG_ACKs.
@@ -5047,80 +5107,86 @@ static int got_NegAck(struct drbd_tconn *tconn, struct packet_info *pi)
request is no longer in the collision hash. */
/* In Protocol B we might already have got a P_RECV_ACK
but then get a P_NEG_ACK afterwards. */
- drbd_set_out_of_sync(mdev, sector, size);
+ drbd_set_out_of_sync(device, sector, size);
}
return 0;
}
-static int got_NegDReply(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_NegDReply(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_block_ack *p = pi->data;
sector_t sector = be64_to_cpu(p->sector);
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
- update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+ update_peer_seq(peer_device, be32_to_cpu(p->seq_num));
- dev_err(DEV, "Got NegDReply; Sector %llus, len %u.\n",
+ drbd_err(device, "Got NegDReply; Sector %llus, len %u.\n",
(unsigned long long)sector, be32_to_cpu(p->blksize));
- return validate_req_change_req_state(mdev, p->block_id, sector,
- &mdev->read_requests, __func__,
+ return validate_req_change_req_state(device, p->block_id, sector,
+ &device->read_requests, __func__,
NEG_ACKED, false);
}
-static int got_NegRSDReply(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_NegRSDReply(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
sector_t sector;
int size;
struct p_block_ack *p = pi->data;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
sector = be64_to_cpu(p->sector);
size = be32_to_cpu(p->blksize);
- update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+ update_peer_seq(peer_device, be32_to_cpu(p->seq_num));
- dec_rs_pending(mdev);
+ dec_rs_pending(device);
- if (get_ldev_if_state(mdev, D_FAILED)) {
- drbd_rs_complete_io(mdev, sector);
+ if (get_ldev_if_state(device, D_FAILED)) {
+ drbd_rs_complete_io(device, sector);
switch (pi->cmd) {
case P_NEG_RS_DREPLY:
- drbd_rs_failed_io(mdev, sector, size);
+ drbd_rs_failed_io(device, sector, size);
case P_RS_CANCEL:
break;
default:
BUG();
}
- put_ldev(mdev);
+ put_ldev(device);
}
return 0;
}
-static int got_BarrierAck(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_BarrierAck(struct drbd_connection *connection, struct packet_info *pi)
{
struct p_barrier_ack *p = pi->data;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
- tl_release(tconn, p->barrier, be32_to_cpu(p->set_size));
+ tl_release(connection, p->barrier, be32_to_cpu(p->set_size));
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- if (mdev->state.conn == C_AHEAD &&
- atomic_read(&mdev->ap_in_flight) == 0 &&
- !test_and_set_bit(AHEAD_TO_SYNC_SOURCE, &mdev->flags)) {
- mdev->start_resync_timer.expires = jiffies + HZ;
- add_timer(&mdev->start_resync_timer);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+
+ if (device->state.conn == C_AHEAD &&
+ atomic_read(&device->ap_in_flight) == 0 &&
+ !test_and_set_bit(AHEAD_TO_SYNC_SOURCE, &device->flags)) {
+ device->start_resync_timer.expires = jiffies + HZ;
+ add_timer(&device->start_resync_timer);
}
}
rcu_read_unlock();
@@ -5128,90 +5194,94 @@ static int got_BarrierAck(struct drbd_tconn *tconn, struct packet_info *pi)
return 0;
}
-static int got_OVResult(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_OVResult(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_block_ack *p = pi->data;
- struct drbd_work *w;
+ struct drbd_device_work *dw;
sector_t sector;
int size;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
sector = be64_to_cpu(p->sector);
size = be32_to_cpu(p->blksize);
- update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+ update_peer_seq(peer_device, be32_to_cpu(p->seq_num));
if (be64_to_cpu(p->block_id) == ID_OUT_OF_SYNC)
- drbd_ov_out_of_sync_found(mdev, sector, size);
+ drbd_ov_out_of_sync_found(device, sector, size);
else
- ov_out_of_sync_print(mdev);
+ ov_out_of_sync_print(device);
- if (!get_ldev(mdev))
+ if (!get_ldev(device))
return 0;
- drbd_rs_complete_io(mdev, sector);
- dec_rs_pending(mdev);
+ drbd_rs_complete_io(device, sector);
+ dec_rs_pending(device);
- --mdev->ov_left;
+ --device->ov_left;
/* let's advance progress step marks only for every other megabyte */
- if ((mdev->ov_left & 0x200) == 0x200)
- drbd_advance_rs_marks(mdev, mdev->ov_left);
-
- if (mdev->ov_left == 0) {
- w = kmalloc(sizeof(*w), GFP_NOIO);
- if (w) {
- w->cb = w_ov_finished;
- w->mdev = mdev;
- drbd_queue_work(&mdev->tconn->sender_work, w);
+ if ((device->ov_left & 0x200) == 0x200)
+ drbd_advance_rs_marks(device, device->ov_left);
+
+ if (device->ov_left == 0) {
+ dw = kmalloc(sizeof(*dw), GFP_NOIO);
+ if (dw) {
+ dw->w.cb = w_ov_finished;
+ dw->device = device;
+ drbd_queue_work(&peer_device->connection->sender_work, &dw->w);
} else {
- dev_err(DEV, "kmalloc(w) failed.");
- ov_out_of_sync_print(mdev);
- drbd_resync_finished(mdev);
+ drbd_err(device, "kmalloc(dw) failed.");
+ ov_out_of_sync_print(device);
+ drbd_resync_finished(device);
}
}
- put_ldev(mdev);
+ put_ldev(device);
return 0;
}
-static int got_skip(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_skip(struct drbd_connection *connection, struct packet_info *pi)
{
return 0;
}
-static int tconn_finish_peer_reqs(struct drbd_tconn *tconn)
+static int connection_finish_peer_reqs(struct drbd_connection *connection)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr, not_empty = 0;
do {
- clear_bit(SIGNAL_ASENDER, &tconn->flags);
+ clear_bit(SIGNAL_ASENDER, &connection->flags);
flush_signals(current);
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- kref_get(&mdev->kref);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ kref_get(&device->kref);
rcu_read_unlock();
- if (drbd_finish_peer_reqs(mdev)) {
- kref_put(&mdev->kref, &drbd_minor_destroy);
+ if (drbd_finish_peer_reqs(device)) {
+ kref_put(&device->kref, drbd_destroy_device);
return 1;
}
- kref_put(&mdev->kref, &drbd_minor_destroy);
+ kref_put(&device->kref, drbd_destroy_device);
rcu_read_lock();
}
- set_bit(SIGNAL_ASENDER, &tconn->flags);
+ set_bit(SIGNAL_ASENDER, &connection->flags);
- spin_lock_irq(&tconn->req_lock);
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- not_empty = !list_empty(&mdev->done_ee);
+ spin_lock_irq(&connection->resource->req_lock);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ not_empty = !list_empty(&device->done_ee);
if (not_empty)
break;
}
- spin_unlock_irq(&tconn->req_lock);
+ spin_unlock_irq(&connection->resource->req_lock);
rcu_read_unlock();
} while (not_empty);
@@ -5220,7 +5290,7 @@ static int tconn_finish_peer_reqs(struct drbd_tconn *tconn)
struct asender_cmd {
size_t pkt_size;
- int (*fn)(struct drbd_tconn *tconn, struct packet_info *);
+ int (*fn)(struct drbd_connection *connection, struct packet_info *);
};
static struct asender_cmd asender_tbl[] = {
@@ -5245,13 +5315,13 @@ static struct asender_cmd asender_tbl[] = {
int drbd_asender(struct drbd_thread *thi)
{
- struct drbd_tconn *tconn = thi->tconn;
+ struct drbd_connection *connection = thi->connection;
struct asender_cmd *cmd = NULL;
struct packet_info pi;
int rv;
- void *buf = tconn->meta.rbuf;
+ void *buf = connection->meta.rbuf;
int received = 0;
- unsigned int header_size = drbd_header_size(tconn);
+ unsigned int header_size = drbd_header_size(connection);
int expect = header_size;
bool ping_timeout_active = false;
struct net_conf *nc;
@@ -5260,45 +5330,45 @@ int drbd_asender(struct drbd_thread *thi)
rv = sched_setscheduler(current, SCHED_RR, &param);
if (rv < 0)
- conn_err(tconn, "drbd_asender: ERROR set priority, ret=%d\n", rv);
+ drbd_err(connection, "drbd_asender: ERROR set priority, ret=%d\n", rv);
while (get_t_state(thi) == RUNNING) {
drbd_thread_current_set_cpu(thi);
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
+ nc = rcu_dereference(connection->net_conf);
ping_timeo = nc->ping_timeo;
tcp_cork = nc->tcp_cork;
ping_int = nc->ping_int;
rcu_read_unlock();
- if (test_and_clear_bit(SEND_PING, &tconn->flags)) {
- if (drbd_send_ping(tconn)) {
- conn_err(tconn, "drbd_send_ping has failed\n");
+ if (test_and_clear_bit(SEND_PING, &connection->flags)) {
+ if (drbd_send_ping(connection)) {
+ drbd_err(connection, "drbd_send_ping has failed\n");
goto reconnect;
}
- tconn->meta.socket->sk->sk_rcvtimeo = ping_timeo * HZ / 10;
+ connection->meta.socket->sk->sk_rcvtimeo = ping_timeo * HZ / 10;
ping_timeout_active = true;
}
/* TODO: conditionally cork; it may hurt latency if we cork without
much to send */
if (tcp_cork)
- drbd_tcp_cork(tconn->meta.socket);
- if (tconn_finish_peer_reqs(tconn)) {
- conn_err(tconn, "tconn_finish_peer_reqs() failed\n");
+ drbd_tcp_cork(connection->meta.socket);
+ if (connection_finish_peer_reqs(connection)) {
+ drbd_err(connection, "connection_finish_peer_reqs() failed\n");
goto reconnect;
}
/* but unconditionally uncork unless disabled */
if (tcp_cork)
- drbd_tcp_uncork(tconn->meta.socket);
+ drbd_tcp_uncork(connection->meta.socket);
/* short circuit, recv_msg would return EINTR anyways. */
if (signal_pending(current))
continue;
- rv = drbd_recv_short(tconn->meta.socket, buf, expect-received, 0);
- clear_bit(SIGNAL_ASENDER, &tconn->flags);
+ rv = drbd_recv_short(connection->meta.socket, buf, expect-received, 0);
+ clear_bit(SIGNAL_ASENDER, &connection->flags);
flush_signals(current);
@@ -5316,51 +5386,51 @@ int drbd_asender(struct drbd_thread *thi)
received += rv;
buf += rv;
} else if (rv == 0) {
- if (test_bit(DISCONNECT_SENT, &tconn->flags)) {
+ if (test_bit(DISCONNECT_SENT, &connection->flags)) {
long t;
rcu_read_lock();
- t = rcu_dereference(tconn->net_conf)->ping_timeo * HZ/10;
+ t = rcu_dereference(connection->net_conf)->ping_timeo * HZ/10;
rcu_read_unlock();
- t = wait_event_timeout(tconn->ping_wait,
- tconn->cstate < C_WF_REPORT_PARAMS,
+ t = wait_event_timeout(connection->ping_wait,
+ connection->cstate < C_WF_REPORT_PARAMS,
t);
if (t)
break;
}
- conn_err(tconn, "meta connection shut down by peer.\n");
+ drbd_err(connection, "meta connection shut down by peer.\n");
goto reconnect;
} else if (rv == -EAGAIN) {
/* If the data socket received something meanwhile,
* that is good enough: peer is still alive. */
- if (time_after(tconn->last_received,
- jiffies - tconn->meta.socket->sk->sk_rcvtimeo))
+ if (time_after(connection->last_received,
+ jiffies - connection->meta.socket->sk->sk_rcvtimeo))
continue;
if (ping_timeout_active) {
- conn_err(tconn, "PingAck did not arrive in time.\n");
+ drbd_err(connection, "PingAck did not arrive in time.\n");
goto reconnect;
}
- set_bit(SEND_PING, &tconn->flags);
+ set_bit(SEND_PING, &connection->flags);
continue;
} else if (rv == -EINTR) {
continue;
} else {
- conn_err(tconn, "sock_recvmsg returned %d\n", rv);
+ drbd_err(connection, "sock_recvmsg returned %d\n", rv);
goto reconnect;
}
if (received == expect && cmd == NULL) {
- if (decode_header(tconn, tconn->meta.rbuf, &pi))
+ if (decode_header(connection, connection->meta.rbuf, &pi))
goto reconnect;
cmd = &asender_tbl[pi.cmd];
if (pi.cmd >= ARRAY_SIZE(asender_tbl) || !cmd->fn) {
- conn_err(tconn, "Unexpected meta packet %s (0x%04x)\n",
+ drbd_err(connection, "Unexpected meta packet %s (0x%04x)\n",
cmdname(pi.cmd), pi.cmd);
goto disconnect;
}
expect = header_size + cmd->pkt_size;
if (pi.size != expect - header_size) {
- conn_err(tconn, "Wrong packet size on meta (c: %d, l: %d)\n",
+ drbd_err(connection, "Wrong packet size on meta (c: %d, l: %d)\n",
pi.cmd, pi.size);
goto reconnect;
}
@@ -5368,21 +5438,21 @@ int drbd_asender(struct drbd_thread *thi)
if (received == expect) {
bool err;
- err = cmd->fn(tconn, &pi);
+ err = cmd->fn(connection, &pi);
if (err) {
- conn_err(tconn, "%pf failed\n", cmd->fn);
+ drbd_err(connection, "%pf failed\n", cmd->fn);
goto reconnect;
}
- tconn->last_received = jiffies;
+ connection->last_received = jiffies;
if (cmd == &asender_tbl[P_PING_ACK]) {
/* restore idle timeout */
- tconn->meta.socket->sk->sk_rcvtimeo = ping_int * HZ;
+ connection->meta.socket->sk->sk_rcvtimeo = ping_int * HZ;
ping_timeout_active = false;
}
- buf = tconn->meta.rbuf;
+ buf = connection->meta.rbuf;
received = 0;
expect = header_size;
cmd = NULL;
@@ -5391,16 +5461,16 @@ int drbd_asender(struct drbd_thread *thi)
if (0) {
reconnect:
- conn_request_state(tconn, NS(conn, C_NETWORK_FAILURE), CS_HARD);
- conn_md_sync(tconn);
+ conn_request_state(connection, NS(conn, C_NETWORK_FAILURE), CS_HARD);
+ conn_md_sync(connection);
}
if (0) {
disconnect:
- conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ conn_request_state(connection, NS(conn, C_DISCONNECTING), CS_HARD);
}
- clear_bit(SIGNAL_ASENDER, &tconn->flags);
+ clear_bit(SIGNAL_ASENDER, &connection->flags);
- conn_info(tconn, "asender terminated\n");
+ drbd_info(connection, "asender terminated\n");
return 0;
}
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
index 104a040f24de..3779c8d2875b 100644
--- a/drivers/block/drbd/drbd_req.c
+++ b/drivers/block/drbd/drbd_req.c
@@ -31,37 +31,37 @@
#include "drbd_req.h"
-static bool drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int size);
+static bool drbd_may_do_local_read(struct drbd_device *device, sector_t sector, int size);
/* Update disk stats at start of I/O request */
-static void _drbd_start_io_acct(struct drbd_conf *mdev, struct drbd_request *req)
+static void _drbd_start_io_acct(struct drbd_device *device, struct drbd_request *req)
{
const int rw = bio_data_dir(req->master_bio);
int cpu;
cpu = part_stat_lock();
- part_round_stats(cpu, &mdev->vdisk->part0);
- part_stat_inc(cpu, &mdev->vdisk->part0, ios[rw]);
- part_stat_add(cpu, &mdev->vdisk->part0, sectors[rw], req->i.size >> 9);
+ part_round_stats(cpu, &device->vdisk->part0);
+ part_stat_inc(cpu, &device->vdisk->part0, ios[rw]);
+ part_stat_add(cpu, &device->vdisk->part0, sectors[rw], req->i.size >> 9);
(void) cpu; /* The macro invocations above want the cpu argument, I do not like
the compiler warning about cpu only assigned but never used... */
- part_inc_in_flight(&mdev->vdisk->part0, rw);
+ part_inc_in_flight(&device->vdisk->part0, rw);
part_stat_unlock();
}
/* Update disk stats when completing request upwards */
-static void _drbd_end_io_acct(struct drbd_conf *mdev, struct drbd_request *req)
+static void _drbd_end_io_acct(struct drbd_device *device, struct drbd_request *req)
{
int rw = bio_data_dir(req->master_bio);
unsigned long duration = jiffies - req->start_time;
int cpu;
cpu = part_stat_lock();
- part_stat_add(cpu, &mdev->vdisk->part0, ticks[rw], duration);
- part_round_stats(cpu, &mdev->vdisk->part0);
- part_dec_in_flight(&mdev->vdisk->part0, rw);
+ part_stat_add(cpu, &device->vdisk->part0, ticks[rw], duration);
+ part_round_stats(cpu, &device->vdisk->part0);
+ part_dec_in_flight(&device->vdisk->part0, rw);
part_stat_unlock();
}
-static struct drbd_request *drbd_req_new(struct drbd_conf *mdev,
+static struct drbd_request *drbd_req_new(struct drbd_device *device,
struct bio *bio_src)
{
struct drbd_request *req;
@@ -72,7 +72,7 @@ static struct drbd_request *drbd_req_new(struct drbd_conf *mdev,
drbd_req_make_private_bio(req, bio_src);
req->rq_state = bio_data_dir(bio_src) == WRITE ? RQ_WRITE : 0;
- req->w.mdev = mdev;
+ req->device = device;
req->master_bio = bio_src;
req->epoch = 0;
@@ -95,14 +95,14 @@ static struct drbd_request *drbd_req_new(struct drbd_conf *mdev,
void drbd_req_destroy(struct kref *kref)
{
struct drbd_request *req = container_of(kref, struct drbd_request, kref);
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
const unsigned s = req->rq_state;
if ((req->master_bio && !(s & RQ_POSTPONED)) ||
atomic_read(&req->completion_ref) ||
(s & RQ_LOCAL_PENDING) ||
((s & RQ_NET_MASK) && !(s & RQ_NET_DONE))) {
- dev_err(DEV, "drbd_req_destroy: Logic BUG rq_state = 0x%x, completion_ref = %d\n",
+ drbd_err(device, "drbd_req_destroy: Logic BUG rq_state = 0x%x, completion_ref = %d\n",
s, atomic_read(&req->completion_ref));
return;
}
@@ -132,10 +132,10 @@ void drbd_req_destroy(struct kref *kref)
*/
if ((s & (RQ_POSTPONED|RQ_LOCAL_MASK|RQ_NET_MASK)) != RQ_POSTPONED) {
if (!(s & RQ_NET_OK) || !(s & RQ_LOCAL_OK))
- drbd_set_out_of_sync(mdev, req->i.sector, req->i.size);
+ drbd_set_out_of_sync(device, req->i.sector, req->i.size);
if ((s & RQ_NET_OK) && (s & RQ_LOCAL_OK) && (s & RQ_NET_SIS))
- drbd_set_in_sync(mdev, req->i.sector, req->i.size);
+ drbd_set_in_sync(device, req->i.sector, req->i.size);
}
/* one might be tempted to move the drbd_al_complete_io
@@ -149,11 +149,11 @@ void drbd_req_destroy(struct kref *kref)
* we would forget to resync the corresponding extent.
*/
if (s & RQ_IN_ACT_LOG) {
- if (get_ldev_if_state(mdev, D_FAILED)) {
- drbd_al_complete_io(mdev, &req->i);
- put_ldev(mdev);
+ if (get_ldev_if_state(device, D_FAILED)) {
+ drbd_al_complete_io(device, &req->i);
+ put_ldev(device);
} else if (__ratelimit(&drbd_ratelimit_state)) {
- dev_warn(DEV, "Should have called drbd_al_complete_io(, %llu, %u), "
+ drbd_warn(device, "Should have called drbd_al_complete_io(, %llu, %u), "
"but my Disk seems to have failed :(\n",
(unsigned long long) req->i.sector, req->i.size);
}
@@ -163,41 +163,42 @@ void drbd_req_destroy(struct kref *kref)
mempool_free(req, drbd_request_mempool);
}
-static void wake_all_senders(struct drbd_tconn *tconn) {
- wake_up(&tconn->sender_work.q_wait);
+static void wake_all_senders(struct drbd_connection *connection)
+{
+ wake_up(&connection->sender_work.q_wait);
}
/* must hold resource->req_lock */
-void start_new_tl_epoch(struct drbd_tconn *tconn)
+void start_new_tl_epoch(struct drbd_connection *connection)
{
/* no point closing an epoch, if it is empty, anyways. */
- if (tconn->current_tle_writes == 0)
+ if (connection->current_tle_writes == 0)
return;
- tconn->current_tle_writes = 0;
- atomic_inc(&tconn->current_tle_nr);
- wake_all_senders(tconn);
+ connection->current_tle_writes = 0;
+ atomic_inc(&connection->current_tle_nr);
+ wake_all_senders(connection);
}
-void complete_master_bio(struct drbd_conf *mdev,
+void complete_master_bio(struct drbd_device *device,
struct bio_and_error *m)
{
bio_endio(m->bio, m->error);
- dec_ap_bio(mdev);
+ dec_ap_bio(device);
}
static void drbd_remove_request_interval(struct rb_root *root,
struct drbd_request *req)
{
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
struct drbd_interval *i = &req->i;
drbd_remove_interval(root, i);
/* Wake up any processes waiting for this request to complete. */
if (i->waiting)
- wake_up(&mdev->misc_wait);
+ wake_up(&device->misc_wait);
}
/* Helper for __req_mod().
@@ -210,7 +211,7 @@ static
void drbd_req_complete(struct drbd_request *req, struct bio_and_error *m)
{
const unsigned s = req->rq_state;
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
int rw;
int error, ok;
@@ -226,12 +227,12 @@ void drbd_req_complete(struct drbd_request *req, struct bio_and_error *m)
if ((s & RQ_LOCAL_PENDING && !(s & RQ_LOCAL_ABORTED)) ||
(s & RQ_NET_QUEUED) || (s & RQ_NET_PENDING) ||
(s & RQ_COMPLETION_SUSP)) {
- dev_err(DEV, "drbd_req_complete: Logic BUG rq_state = 0x%x\n", s);
+ drbd_err(device, "drbd_req_complete: Logic BUG rq_state = 0x%x\n", s);
return;
}
if (!req->master_bio) {
- dev_err(DEV, "drbd_req_complete: Logic BUG, master_bio == NULL!\n");
+ drbd_err(device, "drbd_req_complete: Logic BUG, master_bio == NULL!\n");
return;
}
@@ -259,9 +260,9 @@ void drbd_req_complete(struct drbd_request *req, struct bio_and_error *m)
struct rb_root *root;
if (rw == WRITE)
- root = &mdev->write_requests;
+ root = &device->write_requests;
else
- root = &mdev->read_requests;
+ root = &device->read_requests;
drbd_remove_request_interval(root, req);
}
@@ -273,11 +274,11 @@ void drbd_req_complete(struct drbd_request *req, struct bio_and_error *m)
* and reset the transfer log epoch write_cnt.
*/
if (rw == WRITE &&
- req->epoch == atomic_read(&mdev->tconn->current_tle_nr))
- start_new_tl_epoch(mdev->tconn);
+ req->epoch == atomic_read(&first_peer_device(device)->connection->current_tle_nr))
+ start_new_tl_epoch(first_peer_device(device)->connection);
/* Update disk stats */
- _drbd_end_io_acct(mdev, req);
+ _drbd_end_io_acct(device, req);
/* If READ failed,
* have it be pushed back to the retry work queue,
@@ -305,8 +306,8 @@ void drbd_req_complete(struct drbd_request *req, struct bio_and_error *m)
static int drbd_req_put_completion_ref(struct drbd_request *req, struct bio_and_error *m, int put)
{
- struct drbd_conf *mdev = req->w.mdev;
- D_ASSERT(m || (req->rq_state & RQ_POSTPONED));
+ struct drbd_device *device = req->device;
+ D_ASSERT(device, m || (req->rq_state & RQ_POSTPONED));
if (!atomic_sub_and_test(put, &req->completion_ref))
return 0;
@@ -328,12 +329,12 @@ static int drbd_req_put_completion_ref(struct drbd_request *req, struct bio_and_
static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
int clear, int set)
{
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
unsigned s = req->rq_state;
int c_put = 0;
int k_put = 0;
- if (drbd_suspended(mdev) && !((s | clear) & RQ_COMPLETION_SUSP))
+ if (drbd_suspended(device) && !((s | clear) & RQ_COMPLETION_SUSP))
set |= RQ_COMPLETION_SUSP;
/* apply */
@@ -351,7 +352,7 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
atomic_inc(&req->completion_ref);
if (!(s & RQ_NET_PENDING) && (set & RQ_NET_PENDING)) {
- inc_ap_pending(mdev);
+ inc_ap_pending(device);
atomic_inc(&req->completion_ref);
}
@@ -362,7 +363,7 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
kref_get(&req->kref); /* wait for the DONE */
if (!(s & RQ_NET_SENT) && (set & RQ_NET_SENT))
- atomic_add(req->i.size >> 9, &mdev->ap_in_flight);
+ atomic_add(req->i.size >> 9, &device->ap_in_flight);
if (!(s & RQ_COMPLETION_SUSP) && (set & RQ_COMPLETION_SUSP))
atomic_inc(&req->completion_ref);
@@ -373,7 +374,7 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
++c_put;
if (!(s & RQ_LOCAL_ABORTED) && (set & RQ_LOCAL_ABORTED)) {
- D_ASSERT(req->rq_state & RQ_LOCAL_PENDING);
+ D_ASSERT(device, req->rq_state & RQ_LOCAL_PENDING);
/* local completion may still come in later,
* we need to keep the req object around. */
kref_get(&req->kref);
@@ -388,7 +389,7 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
}
if ((s & RQ_NET_PENDING) && (clear & RQ_NET_PENDING)) {
- dec_ap_pending(mdev);
+ dec_ap_pending(device);
++c_put;
}
@@ -397,7 +398,7 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
if ((s & RQ_EXP_BARR_ACK) && !(s & RQ_NET_DONE) && (set & RQ_NET_DONE)) {
if (req->rq_state & RQ_NET_SENT)
- atomic_sub(req->i.size >> 9, &mdev->ap_in_flight);
+ atomic_sub(req->i.size >> 9, &device->ap_in_flight);
++k_put;
}
@@ -409,14 +410,14 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
int at_least = k_put + !!c_put;
int refcount = atomic_read(&req->kref.refcount);
if (refcount < at_least)
- dev_err(DEV,
+ drbd_err(device,
"mod_rq_state: Logic BUG: %x -> %x: refcount = %d, should be >= %d\n",
s, req->rq_state, refcount, at_least);
}
/* If we made progress, retry conflicting peer requests, if any. */
if (req->i.waiting)
- wake_up(&mdev->misc_wait);
+ wake_up(&device->misc_wait);
if (c_put)
k_put += drbd_req_put_completion_ref(req, m, c_put);
@@ -424,18 +425,18 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
kref_sub(&req->kref, k_put, drbd_req_destroy);
}
-static void drbd_report_io_error(struct drbd_conf *mdev, struct drbd_request *req)
+static void drbd_report_io_error(struct drbd_device *device, struct drbd_request *req)
{
char b[BDEVNAME_SIZE];
if (!__ratelimit(&drbd_ratelimit_state))
return;
- dev_warn(DEV, "local %s IO error sector %llu+%u on %s\n",
+ drbd_warn(device, "local %s IO error sector %llu+%u on %s\n",
(req->rq_state & RQ_WRITE) ? "WRITE" : "READ",
(unsigned long long)req->i.sector,
req->i.size >> 9,
- bdevname(mdev->ldev->backing_bdev, b));
+ bdevname(device->ldev->backing_bdev, b));
}
/* obviously this could be coded as many single functions
@@ -453,7 +454,7 @@ static void drbd_report_io_error(struct drbd_conf *mdev, struct drbd_request *re
int __req_mod(struct drbd_request *req, enum drbd_req_event what,
struct bio_and_error *m)
{
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
struct net_conf *nc;
int p, rv = 0;
@@ -462,7 +463,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
switch (what) {
default:
- dev_err(DEV, "LOGIC BUG in %s:%u\n", __FILE__ , __LINE__);
+ drbd_err(device, "LOGIC BUG in %s:%u\n", __FILE__ , __LINE__);
break;
/* does not happen...
@@ -474,9 +475,9 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
case TO_BE_SENT: /* via network */
/* reached via __drbd_make_request
* and from w_read_retry_remote */
- D_ASSERT(!(req->rq_state & RQ_NET_MASK));
+ D_ASSERT(device, !(req->rq_state & RQ_NET_MASK));
rcu_read_lock();
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
p = nc->wire_protocol;
rcu_read_unlock();
req->rq_state |=
@@ -487,15 +488,15 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
case TO_BE_SUBMITTED: /* locally */
/* reached via __drbd_make_request */
- D_ASSERT(!(req->rq_state & RQ_LOCAL_MASK));
+ D_ASSERT(device, !(req->rq_state & RQ_LOCAL_MASK));
mod_rq_state(req, m, 0, RQ_LOCAL_PENDING);
break;
case COMPLETED_OK:
if (req->rq_state & RQ_WRITE)
- mdev->writ_cnt += req->i.size >> 9;
+ device->writ_cnt += req->i.size >> 9;
else
- mdev->read_cnt += req->i.size >> 9;
+ device->read_cnt += req->i.size >> 9;
mod_rq_state(req, m, RQ_LOCAL_PENDING,
RQ_LOCAL_COMPLETED|RQ_LOCAL_OK);
@@ -506,15 +507,15 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
break;
case WRITE_COMPLETED_WITH_ERROR:
- drbd_report_io_error(mdev, req);
- __drbd_chk_io_error(mdev, DRBD_WRITE_ERROR);
+ drbd_report_io_error(device, req);
+ __drbd_chk_io_error(device, DRBD_WRITE_ERROR);
mod_rq_state(req, m, RQ_LOCAL_PENDING, RQ_LOCAL_COMPLETED);
break;
case READ_COMPLETED_WITH_ERROR:
- drbd_set_out_of_sync(mdev, req->i.sector, req->i.size);
- drbd_report_io_error(mdev, req);
- __drbd_chk_io_error(mdev, DRBD_READ_ERROR);
+ drbd_set_out_of_sync(device, req->i.sector, req->i.size);
+ drbd_report_io_error(device, req);
+ __drbd_chk_io_error(device, DRBD_READ_ERROR);
/* fall through. */
case READ_AHEAD_COMPLETED_WITH_ERROR:
/* it is legal to fail READA, no __drbd_chk_io_error in that case. */
@@ -532,16 +533,17 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
/* So we can verify the handle in the answer packet.
* Corresponding drbd_remove_request_interval is in
* drbd_req_complete() */
- D_ASSERT(drbd_interval_empty(&req->i));
- drbd_insert_interval(&mdev->read_requests, &req->i);
+ D_ASSERT(device, drbd_interval_empty(&req->i));
+ drbd_insert_interval(&device->read_requests, &req->i);
- set_bit(UNPLUG_REMOTE, &mdev->flags);
+ set_bit(UNPLUG_REMOTE, &device->flags);
- D_ASSERT(req->rq_state & RQ_NET_PENDING);
- D_ASSERT((req->rq_state & RQ_LOCAL_MASK) == 0);
+ D_ASSERT(device, req->rq_state & RQ_NET_PENDING);
+ D_ASSERT(device, (req->rq_state & RQ_LOCAL_MASK) == 0);
mod_rq_state(req, m, 0, RQ_NET_QUEUED);
req->w.cb = w_send_read_req;
- drbd_queue_work(&mdev->tconn->sender_work, &req->w);
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &req->w);
break;
case QUEUE_FOR_NET_WRITE:
@@ -550,8 +552,8 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
/* Corresponding drbd_remove_request_interval is in
* drbd_req_complete() */
- D_ASSERT(drbd_interval_empty(&req->i));
- drbd_insert_interval(&mdev->write_requests, &req->i);
+ D_ASSERT(device, drbd_interval_empty(&req->i));
+ drbd_insert_interval(&device->write_requests, &req->i);
/* NOTE
* In case the req ended up on the transfer log before being
@@ -570,28 +572,30 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
/* otherwise we may lose an unplug, which may cause some remote
* io-scheduler timeout to expire, increasing maximum latency,
* hurting performance. */
- set_bit(UNPLUG_REMOTE, &mdev->flags);
+ set_bit(UNPLUG_REMOTE, &device->flags);
/* queue work item to send data */
- D_ASSERT(req->rq_state & RQ_NET_PENDING);
+ D_ASSERT(device, req->rq_state & RQ_NET_PENDING);
mod_rq_state(req, m, 0, RQ_NET_QUEUED|RQ_EXP_BARR_ACK);
req->w.cb = w_send_dblock;
- drbd_queue_work(&mdev->tconn->sender_work, &req->w);
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &req->w);
/* close the epoch, in case it outgrew the limit */
rcu_read_lock();
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
p = nc->max_epoch_size;
rcu_read_unlock();
- if (mdev->tconn->current_tle_writes >= p)
- start_new_tl_epoch(mdev->tconn);
+ if (first_peer_device(device)->connection->current_tle_writes >= p)
+ start_new_tl_epoch(first_peer_device(device)->connection);
break;
case QUEUE_FOR_SEND_OOS:
mod_rq_state(req, m, 0, RQ_NET_QUEUED);
req->w.cb = w_send_out_of_sync;
- drbd_queue_work(&mdev->tconn->sender_work, &req->w);
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &req->w);
break;
case READ_RETRY_REMOTE_CANCELED:
@@ -639,15 +643,15 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
* If this request had been marked as RQ_POSTPONED before,
* it will actually not be completed, but "restarted",
* resubmitted from the retry worker context. */
- D_ASSERT(req->rq_state & RQ_NET_PENDING);
- D_ASSERT(req->rq_state & RQ_EXP_WRITE_ACK);
+ D_ASSERT(device, req->rq_state & RQ_NET_PENDING);
+ D_ASSERT(device, req->rq_state & RQ_EXP_WRITE_ACK);
mod_rq_state(req, m, RQ_NET_PENDING, RQ_NET_DONE|RQ_NET_OK);
break;
case WRITE_ACKED_BY_PEER_AND_SIS:
req->rq_state |= RQ_NET_SIS;
case WRITE_ACKED_BY_PEER:
- D_ASSERT(req->rq_state & RQ_EXP_WRITE_ACK);
+ D_ASSERT(device, req->rq_state & RQ_EXP_WRITE_ACK);
/* protocol C; successfully written on peer.
* Nothing more to do here.
* We want to keep the tl in place for all protocols, to cater
@@ -655,25 +659,25 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
goto ack_common;
case RECV_ACKED_BY_PEER:
- D_ASSERT(req->rq_state & RQ_EXP_RECEIVE_ACK);
+ D_ASSERT(device, req->rq_state & RQ_EXP_RECEIVE_ACK);
/* protocol B; pretends to be successfully written on peer.
* see also notes above in HANDED_OVER_TO_NETWORK about
* protocol != C */
ack_common:
- D_ASSERT(req->rq_state & RQ_NET_PENDING);
+ D_ASSERT(device, req->rq_state & RQ_NET_PENDING);
mod_rq_state(req, m, RQ_NET_PENDING, RQ_NET_OK);
break;
case POSTPONE_WRITE:
- D_ASSERT(req->rq_state & RQ_EXP_WRITE_ACK);
+ D_ASSERT(device, req->rq_state & RQ_EXP_WRITE_ACK);
/* If this node has already detected the write conflict, the
* worker will be waiting on misc_wait. Wake it up once this
* request has completed locally.
*/
- D_ASSERT(req->rq_state & RQ_NET_PENDING);
+ D_ASSERT(device, req->rq_state & RQ_NET_PENDING);
req->rq_state |= RQ_POSTPONED;
if (req->i.waiting)
- wake_up(&mdev->misc_wait);
+ wake_up(&device->misc_wait);
/* Do not clear RQ_NET_PENDING. This request will make further
* progress via restart_conflicting_writes() or
* fail_postponed_requests(). Hopefully. */
@@ -701,9 +705,10 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
if (bio_data_dir(req->master_bio) == WRITE)
rv = MR_WRITE;
- get_ldev(mdev); /* always succeeds in this call path */
+ get_ldev(device); /* always succeeds in this call path */
req->w.cb = w_restart_disk_io;
- drbd_queue_work(&mdev->tconn->sender_work, &req->w);
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &req->w);
break;
case RESEND:
@@ -719,12 +724,13 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
Throwing them out of the TL here by pretending we got a BARRIER_ACK.
During connection handshake, we ensure that the peer was not rebooted. */
if (!(req->rq_state & RQ_NET_OK)) {
- /* FIXME could this possibly be a req->w.cb == w_send_out_of_sync?
+ /* FIXME could this possibly be a req->dw.cb == w_send_out_of_sync?
* in that case we must not set RQ_NET_PENDING. */
mod_rq_state(req, m, RQ_COMPLETION_SUSP, RQ_NET_QUEUED|RQ_NET_PENDING);
if (req->w.cb) {
- drbd_queue_work(&mdev->tconn->sender_work, &req->w);
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &req->w);
rv = req->rq_state & RQ_WRITE ? MR_WRITE : MR_READ;
} /* else: FIXME can this happen? */
break;
@@ -740,7 +746,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
/* barrier came in before all requests were acked.
* this is bad, because if the connection is lost now,
* we won't be able to clean them up... */
- dev_err(DEV, "FIXME (BARRIER_ACKED but pending)\n");
+ drbd_err(device, "FIXME (BARRIER_ACKED but pending)\n");
}
/* Allowed to complete requests, even while suspended.
* As this is called for all requests within a matching epoch,
@@ -751,12 +757,12 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
break;
case DATA_RECEIVED:
- D_ASSERT(req->rq_state & RQ_NET_PENDING);
+ D_ASSERT(device, req->rq_state & RQ_NET_PENDING);
mod_rq_state(req, m, RQ_NET_PENDING, RQ_NET_OK|RQ_NET_DONE);
break;
case QUEUE_AS_DRBD_BARRIER:
- start_new_tl_epoch(mdev->tconn);
+ start_new_tl_epoch(first_peer_device(device)->connection);
mod_rq_state(req, m, 0, RQ_NET_OK|RQ_NET_DONE);
break;
};
@@ -771,27 +777,27 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
* since size may be bigger than BM_BLOCK_SIZE,
* we may need to check several bits.
*/
-static bool drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int size)
+static bool drbd_may_do_local_read(struct drbd_device *device, sector_t sector, int size)
{
unsigned long sbnr, ebnr;
sector_t esector, nr_sectors;
- if (mdev->state.disk == D_UP_TO_DATE)
+ if (device->state.disk == D_UP_TO_DATE)
return true;
- if (mdev->state.disk != D_INCONSISTENT)
+ if (device->state.disk != D_INCONSISTENT)
return false;
esector = sector + (size >> 9) - 1;
- nr_sectors = drbd_get_capacity(mdev->this_bdev);
- D_ASSERT(sector < nr_sectors);
- D_ASSERT(esector < nr_sectors);
+ nr_sectors = drbd_get_capacity(device->this_bdev);
+ D_ASSERT(device, sector < nr_sectors);
+ D_ASSERT(device, esector < nr_sectors);
sbnr = BM_SECT_TO_BIT(sector);
ebnr = BM_SECT_TO_BIT(esector);
- return drbd_bm_count_bits(mdev, sbnr, ebnr) == 0;
+ return drbd_bm_count_bits(device, sbnr, ebnr) == 0;
}
-static bool remote_due_to_read_balancing(struct drbd_conf *mdev, sector_t sector,
+static bool remote_due_to_read_balancing(struct drbd_device *device, sector_t sector,
enum drbd_read_balancing rbm)
{
struct backing_dev_info *bdi;
@@ -799,11 +805,11 @@ static bool remote_due_to_read_balancing(struct drbd_conf *mdev, sector_t sector
switch (rbm) {
case RB_CONGESTED_REMOTE:
- bdi = &mdev->ldev->backing_bdev->bd_disk->queue->backing_dev_info;
+ bdi = &device->ldev->backing_bdev->bd_disk->queue->backing_dev_info;
return bdi_read_congested(bdi);
case RB_LEAST_PENDING:
- return atomic_read(&mdev->local_cnt) >
- atomic_read(&mdev->ap_pending_cnt) + atomic_read(&mdev->rs_pending_cnt);
+ return atomic_read(&device->local_cnt) >
+ atomic_read(&device->ap_pending_cnt) + atomic_read(&device->rs_pending_cnt);
case RB_32K_STRIPING: /* stripe_shift = 15 */
case RB_64K_STRIPING:
case RB_128K_STRIPING:
@@ -813,7 +819,7 @@ static bool remote_due_to_read_balancing(struct drbd_conf *mdev, sector_t sector
stripe_shift = (rbm - RB_32K_STRIPING + 15);
return (sector >> (stripe_shift - 9)) & 1;
case RB_ROUND_ROBIN:
- return test_and_change_bit(READ_BALANCE_RR, &mdev->flags);
+ return test_and_change_bit(READ_BALANCE_RR, &device->flags);
case RB_PREFER_REMOTE:
return true;
case RB_PREFER_LOCAL:
@@ -834,73 +840,73 @@ static bool remote_due_to_read_balancing(struct drbd_conf *mdev, sector_t sector
static void complete_conflicting_writes(struct drbd_request *req)
{
DEFINE_WAIT(wait);
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
struct drbd_interval *i;
sector_t sector = req->i.sector;
int size = req->i.size;
- i = drbd_find_overlap(&mdev->write_requests, sector, size);
+ i = drbd_find_overlap(&device->write_requests, sector, size);
if (!i)
return;
for (;;) {
- prepare_to_wait(&mdev->misc_wait, &wait, TASK_UNINTERRUPTIBLE);
- i = drbd_find_overlap(&mdev->write_requests, sector, size);
+ prepare_to_wait(&device->misc_wait, &wait, TASK_UNINTERRUPTIBLE);
+ i = drbd_find_overlap(&device->write_requests, sector, size);
if (!i)
break;
/* Indicate to wake up device->misc_wait on progress. */
i->waiting = true;
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
schedule();
- spin_lock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
}
- finish_wait(&mdev->misc_wait, &wait);
+ finish_wait(&device->misc_wait, &wait);
}
/* called within req_lock and rcu_read_lock() */
-static void maybe_pull_ahead(struct drbd_conf *mdev)
+static void maybe_pull_ahead(struct drbd_device *device)
{
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_connection *connection = first_peer_device(device)->connection;
struct net_conf *nc;
bool congested = false;
enum drbd_on_congestion on_congestion;
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
+ nc = rcu_dereference(connection->net_conf);
on_congestion = nc ? nc->on_congestion : OC_BLOCK;
rcu_read_unlock();
if (on_congestion == OC_BLOCK ||
- tconn->agreed_pro_version < 96)
+ connection->agreed_pro_version < 96)
return;
/* If I don't even have good local storage, we can not reasonably try
* to pull ahead of the peer. We also need the local reference to make
- * sure mdev->act_log is there.
+ * sure device->act_log is there.
*/
- if (!get_ldev_if_state(mdev, D_UP_TO_DATE))
+ if (!get_ldev_if_state(device, D_UP_TO_DATE))
return;
if (nc->cong_fill &&
- atomic_read(&mdev->ap_in_flight) >= nc->cong_fill) {
- dev_info(DEV, "Congestion-fill threshold reached\n");
+ atomic_read(&device->ap_in_flight) >= nc->cong_fill) {
+ drbd_info(device, "Congestion-fill threshold reached\n");
congested = true;
}
- if (mdev->act_log->used >= nc->cong_extents) {
- dev_info(DEV, "Congestion-extents threshold reached\n");
+ if (device->act_log->used >= nc->cong_extents) {
+ drbd_info(device, "Congestion-extents threshold reached\n");
congested = true;
}
if (congested) {
/* start a new epoch for non-mirrored writes */
- start_new_tl_epoch(mdev->tconn);
+ start_new_tl_epoch(first_peer_device(device)->connection);
if (on_congestion == OC_PULL_AHEAD)
- _drbd_set_state(_NS(mdev, conn, C_AHEAD), 0, NULL);
+ _drbd_set_state(_NS(device, conn, C_AHEAD), 0, NULL);
else /*nc->on_congestion == OC_DISCONNECT */
- _drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), 0, NULL);
+ _drbd_set_state(_NS(device, conn, C_DISCONNECTING), 0, NULL);
}
- put_ldev(mdev);
+ put_ldev(device);
}
/* If this returns false, and req->private_bio is still set,
@@ -914,19 +920,19 @@ static void maybe_pull_ahead(struct drbd_conf *mdev)
*/
static bool do_remote_read(struct drbd_request *req)
{
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
enum drbd_read_balancing rbm;
if (req->private_bio) {
- if (!drbd_may_do_local_read(mdev,
+ if (!drbd_may_do_local_read(device,
req->i.sector, req->i.size)) {
bio_put(req->private_bio);
req->private_bio = NULL;
- put_ldev(mdev);
+ put_ldev(device);
}
}
- if (mdev->state.pdsk != D_UP_TO_DATE)
+ if (device->state.pdsk != D_UP_TO_DATE)
return false;
if (req->private_bio == NULL)
@@ -936,17 +942,17 @@ static bool do_remote_read(struct drbd_request *req)
* protocol, pending requests etc. */
rcu_read_lock();
- rbm = rcu_dereference(mdev->ldev->disk_conf)->read_balancing;
+ rbm = rcu_dereference(device->ldev->disk_conf)->read_balancing;
rcu_read_unlock();
if (rbm == RB_PREFER_LOCAL && req->private_bio)
return false; /* submit locally */
- if (remote_due_to_read_balancing(mdev, req->i.sector, rbm)) {
+ if (remote_due_to_read_balancing(device, req->i.sector, rbm)) {
if (req->private_bio) {
bio_put(req->private_bio);
req->private_bio = NULL;
- put_ldev(mdev);
+ put_ldev(device);
}
return true;
}
@@ -959,11 +965,11 @@ static bool do_remote_read(struct drbd_request *req)
* which does NOT include those that we are L_AHEAD for. */
static int drbd_process_write_request(struct drbd_request *req)
{
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
int remote, send_oos;
- remote = drbd_should_do_remote(mdev->state);
- send_oos = drbd_should_send_out_of_sync(mdev->state);
+ remote = drbd_should_do_remote(device->state);
+ send_oos = drbd_should_send_out_of_sync(device->state);
/* Need to replicate writes. Unless it is an empty flush,
* which is better mapped to a DRBD P_BARRIER packet,
@@ -973,7 +979,7 @@ static int drbd_process_write_request(struct drbd_request *req)
* replicating, in which case there is no point. */
if (unlikely(req->i.size == 0)) {
/* The only size==0 bios we expect are empty flushes. */
- D_ASSERT(req->master_bio->bi_rw & REQ_FLUSH);
+ D_ASSERT(device, req->master_bio->bi_rw & REQ_FLUSH);
if (remote)
_req_mod(req, QUEUE_AS_DRBD_BARRIER);
return remote;
@@ -982,12 +988,12 @@ static int drbd_process_write_request(struct drbd_request *req)
if (!remote && !send_oos)
return 0;
- D_ASSERT(!(remote && send_oos));
+ D_ASSERT(device, !(remote && send_oos));
if (remote) {
_req_mod(req, TO_BE_SENT);
_req_mod(req, QUEUE_FOR_NET_WRITE);
- } else if (drbd_set_out_of_sync(mdev, req->i.sector, req->i.size))
+ } else if (drbd_set_out_of_sync(device, req->i.sector, req->i.size))
_req_mod(req, QUEUE_FOR_SEND_OOS);
return remote;
@@ -996,36 +1002,36 @@ static int drbd_process_write_request(struct drbd_request *req)
static void
drbd_submit_req_private_bio(struct drbd_request *req)
{
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
struct bio *bio = req->private_bio;
const int rw = bio_rw(bio);
- bio->bi_bdev = mdev->ldev->backing_bdev;
+ bio->bi_bdev = device->ldev->backing_bdev;
/* State may have changed since we grabbed our reference on the
* ->ldev member. Double check, and short-circuit to endio.
* In case the last activity log transaction failed to get on
* stable storage, and this is a WRITE, we may not even submit
* this bio. */
- if (get_ldev(mdev)) {
- if (drbd_insert_fault(mdev,
+ if (get_ldev(device)) {
+ if (drbd_insert_fault(device,
rw == WRITE ? DRBD_FAULT_DT_WR
: rw == READ ? DRBD_FAULT_DT_RD
: DRBD_FAULT_DT_RA))
bio_endio(bio, -EIO);
else
generic_make_request(bio);
- put_ldev(mdev);
+ put_ldev(device);
} else
bio_endio(bio, -EIO);
}
-static void drbd_queue_write(struct drbd_conf *mdev, struct drbd_request *req)
+static void drbd_queue_write(struct drbd_device *device, struct drbd_request *req)
{
- spin_lock(&mdev->submit.lock);
- list_add_tail(&req->tl_requests, &mdev->submit.writes);
- spin_unlock(&mdev->submit.lock);
- queue_work(mdev->submit.wq, &mdev->submit.worker);
+ spin_lock(&device->submit.lock);
+ list_add_tail(&req->tl_requests, &device->submit.writes);
+ spin_unlock(&device->submit.lock);
+ queue_work(device->submit.wq, &device->submit.worker);
}
/* returns the new drbd_request pointer, if the caller is expected to
@@ -1033,36 +1039,36 @@ static void drbd_queue_write(struct drbd_conf *mdev, struct drbd_request *req)
* request on the submitter thread.
* Returns ERR_PTR(-ENOMEM) if we cannot allocate a drbd_request.
*/
-struct drbd_request *
-drbd_request_prepare(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time)
+static struct drbd_request *
+drbd_request_prepare(struct drbd_device *device, struct bio *bio, unsigned long start_time)
{
const int rw = bio_data_dir(bio);
struct drbd_request *req;
/* allocate outside of all locks; */
- req = drbd_req_new(mdev, bio);
+ req = drbd_req_new(device, bio);
if (!req) {
- dec_ap_bio(mdev);
+ dec_ap_bio(device);
/* only pass the error to the upper layers.
* if user cannot handle io errors, that's not our business. */
- dev_err(DEV, "could not kmalloc() req\n");
+ drbd_err(device, "could not kmalloc() req\n");
bio_endio(bio, -ENOMEM);
return ERR_PTR(-ENOMEM);
}
req->start_time = start_time;
- if (!get_ldev(mdev)) {
+ if (!get_ldev(device)) {
bio_put(req->private_bio);
req->private_bio = NULL;
}
/* Update disk stats */
- _drbd_start_io_acct(mdev, req);
+ _drbd_start_io_acct(device, req);
if (rw == WRITE && req->private_bio && req->i.size
- && !test_bit(AL_SUSPENDED, &mdev->flags)) {
- if (!drbd_al_begin_io_fastpath(mdev, &req->i)) {
- drbd_queue_write(mdev, req);
+ && !test_bit(AL_SUSPENDED, &device->flags)) {
+ if (!drbd_al_begin_io_fastpath(device, &req->i)) {
+ drbd_queue_write(device, req);
return NULL;
}
req->rq_state |= RQ_IN_ACT_LOG;
@@ -1071,13 +1077,13 @@ drbd_request_prepare(struct drbd_conf *mdev, struct bio *bio, unsigned long star
return req;
}
-static void drbd_send_and_submit(struct drbd_conf *mdev, struct drbd_request *req)
+static void drbd_send_and_submit(struct drbd_device *device, struct drbd_request *req)
{
const int rw = bio_rw(req->master_bio);
struct bio_and_error m = { NULL, };
bool no_remote = false;
- spin_lock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
if (rw == WRITE) {
/* This may temporarily give up the req_lock,
* but will re-aquire it before it returns here.
@@ -1087,17 +1093,17 @@ static void drbd_send_and_submit(struct drbd_conf *mdev, struct drbd_request *re
/* check for congestion, and potentially stop sending
* full data updates, but start sending "dirty bits" only. */
- maybe_pull_ahead(mdev);
+ maybe_pull_ahead(device);
}
- if (drbd_suspended(mdev)) {
+ if (drbd_suspended(device)) {
/* push back and retry: */
req->rq_state |= RQ_POSTPONED;
if (req->private_bio) {
bio_put(req->private_bio);
req->private_bio = NULL;
- put_ldev(mdev);
+ put_ldev(device);
}
goto out;
}
@@ -1111,15 +1117,15 @@ static void drbd_send_and_submit(struct drbd_conf *mdev, struct drbd_request *re
}
/* which transfer log epoch does this belong to? */
- req->epoch = atomic_read(&mdev->tconn->current_tle_nr);
+ req->epoch = atomic_read(&first_peer_device(device)->connection->current_tle_nr);
/* no point in adding empty flushes to the transfer log,
* they are mapped to drbd barriers already. */
if (likely(req->i.size!=0)) {
if (rw == WRITE)
- mdev->tconn->current_tle_writes++;
+ first_peer_device(device)->connection->current_tle_writes++;
- list_add_tail(&req->tl_requests, &mdev->tconn->transfer_log);
+ list_add_tail(&req->tl_requests, &first_peer_device(device)->connection->transfer_log);
}
if (rw == WRITE) {
@@ -1139,13 +1145,13 @@ static void drbd_send_and_submit(struct drbd_conf *mdev, struct drbd_request *re
/* needs to be marked within the same spinlock */
_req_mod(req, TO_BE_SUBMITTED);
/* but we need to give up the spinlock to submit */
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
drbd_submit_req_private_bio(req);
- spin_lock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
} else if (no_remote) {
nodata:
if (__ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "IO ERROR: neither local nor remote data, sector %llu+%u\n",
+ drbd_err(device, "IO ERROR: neither local nor remote data, sector %llu+%u\n",
(unsigned long long)req->i.sector, req->i.size >> 9);
/* A write may have been queued for send_oos, however.
* So we can not simply free it, we must go through drbd_req_put_completion_ref() */
@@ -1154,21 +1160,21 @@ nodata:
out:
if (drbd_req_put_completion_ref(req, &m, 1))
kref_put(&req->kref, drbd_req_destroy);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
if (m.bio)
- complete_master_bio(mdev, &m);
+ complete_master_bio(device, &m);
}
-void __drbd_make_request(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time)
+void __drbd_make_request(struct drbd_device *device, struct bio *bio, unsigned long start_time)
{
- struct drbd_request *req = drbd_request_prepare(mdev, bio, start_time);
+ struct drbd_request *req = drbd_request_prepare(device, bio, start_time);
if (IS_ERR_OR_NULL(req))
return;
- drbd_send_and_submit(mdev, req);
+ drbd_send_and_submit(device, req);
}
-static void submit_fast_path(struct drbd_conf *mdev, struct list_head *incoming)
+static void submit_fast_path(struct drbd_device *device, struct list_head *incoming)
{
struct drbd_request *req, *tmp;
list_for_each_entry_safe(req, tmp, incoming, tl_requests) {
@@ -1176,19 +1182,19 @@ static void submit_fast_path(struct drbd_conf *mdev, struct list_head *incoming)
if (rw == WRITE /* rw != WRITE should not even end up here! */
&& req->private_bio && req->i.size
- && !test_bit(AL_SUSPENDED, &mdev->flags)) {
- if (!drbd_al_begin_io_fastpath(mdev, &req->i))
+ && !test_bit(AL_SUSPENDED, &device->flags)) {
+ if (!drbd_al_begin_io_fastpath(device, &req->i))
continue;
req->rq_state |= RQ_IN_ACT_LOG;
}
list_del_init(&req->tl_requests);
- drbd_send_and_submit(mdev, req);
+ drbd_send_and_submit(device, req);
}
}
-static bool prepare_al_transaction_nonblock(struct drbd_conf *mdev,
+static bool prepare_al_transaction_nonblock(struct drbd_device *device,
struct list_head *incoming,
struct list_head *pending)
{
@@ -1196,9 +1202,9 @@ static bool prepare_al_transaction_nonblock(struct drbd_conf *mdev,
int wake = 0;
int err;
- spin_lock_irq(&mdev->al_lock);
+ spin_lock_irq(&device->al_lock);
list_for_each_entry_safe(req, tmp, incoming, tl_requests) {
- err = drbd_al_begin_io_nonblock(mdev, &req->i);
+ err = drbd_al_begin_io_nonblock(device, &req->i);
if (err == -EBUSY)
wake = 1;
if (err)
@@ -1206,30 +1212,30 @@ static bool prepare_al_transaction_nonblock(struct drbd_conf *mdev,
req->rq_state |= RQ_IN_ACT_LOG;
list_move_tail(&req->tl_requests, pending);
}
- spin_unlock_irq(&mdev->al_lock);
+ spin_unlock_irq(&device->al_lock);
if (wake)
- wake_up(&mdev->al_wait);
+ wake_up(&device->al_wait);
return !list_empty(pending);
}
void do_submit(struct work_struct *ws)
{
- struct drbd_conf *mdev = container_of(ws, struct drbd_conf, submit.worker);
+ struct drbd_device *device = container_of(ws, struct drbd_device, submit.worker);
LIST_HEAD(incoming);
LIST_HEAD(pending);
struct drbd_request *req, *tmp;
for (;;) {
- spin_lock(&mdev->submit.lock);
- list_splice_tail_init(&mdev->submit.writes, &incoming);
- spin_unlock(&mdev->submit.lock);
+ spin_lock(&device->submit.lock);
+ list_splice_tail_init(&device->submit.writes, &incoming);
+ spin_unlock(&device->submit.lock);
- submit_fast_path(mdev, &incoming);
+ submit_fast_path(device, &incoming);
if (list_empty(&incoming))
break;
- wait_event(mdev->al_wait, prepare_al_transaction_nonblock(mdev, &incoming, &pending));
+ wait_event(device->al_wait, prepare_al_transaction_nonblock(device, &incoming, &pending));
/* Maybe more was queued, while we prepared the transaction?
* Try to stuff them into this transaction as well.
* Be strictly non-blocking here, no wait_event, we already
@@ -1243,17 +1249,17 @@ void do_submit(struct work_struct *ws)
/* It is ok to look outside the lock,
* it's only an optimization anyways */
- if (list_empty(&mdev->submit.writes))
+ if (list_empty(&device->submit.writes))
break;
- spin_lock(&mdev->submit.lock);
- list_splice_tail_init(&mdev->submit.writes, &more_incoming);
- spin_unlock(&mdev->submit.lock);
+ spin_lock(&device->submit.lock);
+ list_splice_tail_init(&device->submit.writes, &more_incoming);
+ spin_unlock(&device->submit.lock);
if (list_empty(&more_incoming))
break;
- made_progress = prepare_al_transaction_nonblock(mdev, &more_incoming, &more_pending);
+ made_progress = prepare_al_transaction_nonblock(device, &more_incoming, &more_pending);
list_splice_tail_init(&more_pending, &pending);
list_splice_tail_init(&more_incoming, &incoming);
@@ -1261,18 +1267,18 @@ void do_submit(struct work_struct *ws)
if (!made_progress)
break;
}
- drbd_al_begin_io_commit(mdev, false);
+ drbd_al_begin_io_commit(device, false);
list_for_each_entry_safe(req, tmp, &pending, tl_requests) {
list_del_init(&req->tl_requests);
- drbd_send_and_submit(mdev, req);
+ drbd_send_and_submit(device, req);
}
}
}
void drbd_make_request(struct request_queue *q, struct bio *bio)
{
- struct drbd_conf *mdev = (struct drbd_conf *) q->queuedata;
+ struct drbd_device *device = (struct drbd_device *) q->queuedata;
unsigned long start_time;
start_time = jiffies;
@@ -1280,10 +1286,10 @@ void drbd_make_request(struct request_queue *q, struct bio *bio)
/*
* what we "blindly" assume:
*/
- D_ASSERT(IS_ALIGNED(bio->bi_iter.bi_size, 512));
+ D_ASSERT(device, IS_ALIGNED(bio->bi_iter.bi_size, 512));
- inc_ap_bio(mdev);
- __drbd_make_request(mdev, bio, start_time);
+ inc_ap_bio(device);
+ __drbd_make_request(device, bio, start_time);
}
/* This is called by bio_add_page().
@@ -1300,32 +1306,32 @@ void drbd_make_request(struct request_queue *q, struct bio *bio)
*/
int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct bio_vec *bvec)
{
- struct drbd_conf *mdev = (struct drbd_conf *) q->queuedata;
+ struct drbd_device *device = (struct drbd_device *) q->queuedata;
unsigned int bio_size = bvm->bi_size;
int limit = DRBD_MAX_BIO_SIZE;
int backing_limit;
- if (bio_size && get_ldev(mdev)) {
+ if (bio_size && get_ldev(device)) {
unsigned int max_hw_sectors = queue_max_hw_sectors(q);
struct request_queue * const b =
- mdev->ldev->backing_bdev->bd_disk->queue;
+ device->ldev->backing_bdev->bd_disk->queue;
if (b->merge_bvec_fn) {
backing_limit = b->merge_bvec_fn(b, bvm, bvec);
limit = min(limit, backing_limit);
}
- put_ldev(mdev);
+ put_ldev(device);
if ((limit >> 9) > max_hw_sectors)
limit = max_hw_sectors << 9;
}
return limit;
}
-struct drbd_request *find_oldest_request(struct drbd_tconn *tconn)
+static struct drbd_request *find_oldest_request(struct drbd_connection *connection)
{
/* Walk the transfer log,
* and find the oldest not yet completed request */
struct drbd_request *r;
- list_for_each_entry(r, &tconn->transfer_log, tl_requests) {
+ list_for_each_entry(r, &connection->transfer_log, tl_requests) {
if (atomic_read(&r->completion_ref))
return r;
}
@@ -1334,21 +1340,21 @@ struct drbd_request *find_oldest_request(struct drbd_tconn *tconn)
void request_timer_fn(unsigned long data)
{
- struct drbd_conf *mdev = (struct drbd_conf *) data;
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_device *device = (struct drbd_device *) data;
+ struct drbd_connection *connection = first_peer_device(device)->connection;
struct drbd_request *req; /* oldest request */
struct net_conf *nc;
unsigned long ent = 0, dt = 0, et, nt; /* effective timeout = ko_count * timeout */
unsigned long now;
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
- if (nc && mdev->state.conn >= C_WF_REPORT_PARAMS)
+ nc = rcu_dereference(connection->net_conf);
+ if (nc && device->state.conn >= C_WF_REPORT_PARAMS)
ent = nc->timeout * HZ/10 * nc->ko_count;
- if (get_ldev(mdev)) { /* implicit state.disk >= D_INCONSISTENT */
- dt = rcu_dereference(mdev->ldev->disk_conf)->disk_timeout * HZ / 10;
- put_ldev(mdev);
+ if (get_ldev(device)) { /* implicit state.disk >= D_INCONSISTENT */
+ dt = rcu_dereference(device->ldev->disk_conf)->disk_timeout * HZ / 10;
+ put_ldev(device);
}
rcu_read_unlock();
@@ -1359,11 +1365,11 @@ void request_timer_fn(unsigned long data)
now = jiffies;
- spin_lock_irq(&tconn->req_lock);
- req = find_oldest_request(tconn);
+ spin_lock_irq(&device->resource->req_lock);
+ req = find_oldest_request(connection);
if (!req) {
- spin_unlock_irq(&tconn->req_lock);
- mod_timer(&mdev->request_timer, now + et);
+ spin_unlock_irq(&device->resource->req_lock);
+ mod_timer(&device->request_timer, now + et);
return;
}
@@ -1385,17 +1391,17 @@ void request_timer_fn(unsigned long data)
*/
if (ent && req->rq_state & RQ_NET_PENDING &&
time_after(now, req->start_time + ent) &&
- !time_in_range(now, tconn->last_reconnect_jif, tconn->last_reconnect_jif + ent)) {
- dev_warn(DEV, "Remote failed to finish a request within ko-count * timeout\n");
- _drbd_set_state(_NS(mdev, conn, C_TIMEOUT), CS_VERBOSE | CS_HARD, NULL);
+ !time_in_range(now, connection->last_reconnect_jif, connection->last_reconnect_jif + ent)) {
+ drbd_warn(device, "Remote failed to finish a request within ko-count * timeout\n");
+ _drbd_set_state(_NS(device, conn, C_TIMEOUT), CS_VERBOSE | CS_HARD, NULL);
}
- if (dt && req->rq_state & RQ_LOCAL_PENDING && req->w.mdev == mdev &&
+ if (dt && req->rq_state & RQ_LOCAL_PENDING && req->device == device &&
time_after(now, req->start_time + dt) &&
- !time_in_range(now, mdev->last_reattach_jif, mdev->last_reattach_jif + dt)) {
- dev_warn(DEV, "Local backing device failed to meet the disk-timeout\n");
- __drbd_chk_io_error(mdev, DRBD_FORCE_DETACH);
+ !time_in_range(now, device->last_reattach_jif, device->last_reattach_jif + dt)) {
+ drbd_warn(device, "Local backing device failed to meet the disk-timeout\n");
+ __drbd_chk_io_error(device, DRBD_FORCE_DETACH);
}
nt = (time_after(now, req->start_time + et) ? now : req->start_time) + et;
- spin_unlock_irq(&tconn->req_lock);
- mod_timer(&mdev->request_timer, nt);
+ spin_unlock_irq(&connection->resource->req_lock);
+ mod_timer(&device->request_timer, nt);
}
diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h
index 28e15d91197a..c684c963538e 100644
--- a/drivers/block/drbd/drbd_req.h
+++ b/drivers/block/drbd/drbd_req.h
@@ -275,17 +275,17 @@ struct bio_and_error {
int error;
};
-extern void start_new_tl_epoch(struct drbd_tconn *tconn);
+extern void start_new_tl_epoch(struct drbd_connection *connection);
extern void drbd_req_destroy(struct kref *kref);
extern void _req_may_be_done(struct drbd_request *req,
struct bio_and_error *m);
extern int __req_mod(struct drbd_request *req, enum drbd_req_event what,
struct bio_and_error *m);
-extern void complete_master_bio(struct drbd_conf *mdev,
+extern void complete_master_bio(struct drbd_device *device,
struct bio_and_error *m);
extern void request_timer_fn(unsigned long data);
-extern void tl_restart(struct drbd_tconn *tconn, enum drbd_req_event what);
-extern void _tl_restart(struct drbd_tconn *tconn, enum drbd_req_event what);
+extern void tl_restart(struct drbd_connection *connection, enum drbd_req_event what);
+extern void _tl_restart(struct drbd_connection *connection, enum drbd_req_event what);
/* this is in drbd_main.c */
extern void drbd_restart_request(struct drbd_request *req);
@@ -294,14 +294,14 @@ extern void drbd_restart_request(struct drbd_request *req);
* outside the spinlock, e.g. when walking some list on cleanup. */
static inline int _req_mod(struct drbd_request *req, enum drbd_req_event what)
{
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
struct bio_and_error m;
int rv;
/* __req_mod possibly frees req, do not touch req after that! */
rv = __req_mod(req, what, &m);
if (m.bio)
- complete_master_bio(mdev, &m);
+ complete_master_bio(device, &m);
return rv;
}
@@ -314,16 +314,16 @@ static inline int req_mod(struct drbd_request *req,
enum drbd_req_event what)
{
unsigned long flags;
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
struct bio_and_error m;
int rv;
- spin_lock_irqsave(&mdev->tconn->req_lock, flags);
+ spin_lock_irqsave(&device->resource->req_lock, flags);
rv = __req_mod(req, what, &m);
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
if (m.bio)
- complete_master_bio(mdev, &m);
+ complete_master_bio(device, &m);
return rv;
}
diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c
index 216d47b7e88b..1a84345a3868 100644
--- a/drivers/block/drbd/drbd_state.c
+++ b/drivers/block/drbd/drbd_state.c
@@ -27,13 +27,12 @@
#include <linux/drbd_limits.h>
#include "drbd_int.h"
+#include "drbd_protocol.h"
#include "drbd_req.h"
-/* in drbd_main.c */
-extern void tl_abort_disk_io(struct drbd_conf *mdev);
-
struct after_state_chg_work {
struct drbd_work w;
+ struct drbd_device *device;
union drbd_state os;
union drbd_state ns;
enum chg_state_flags flags;
@@ -50,12 +49,12 @@ enum sanitize_state_warnings {
};
static int w_after_state_ch(struct drbd_work *w, int unused);
-static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
+static void after_state_ch(struct drbd_device *device, union drbd_state os,
union drbd_state ns, enum chg_state_flags flags);
-static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state);
-static enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state, struct drbd_tconn *);
+static enum drbd_state_rv is_valid_state(struct drbd_device *, union drbd_state);
+static enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state, struct drbd_connection *);
static enum drbd_state_rv is_valid_transition(union drbd_state os, union drbd_state ns);
-static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state ns,
+static union drbd_state sanitize_state(struct drbd_device *device, union drbd_state ns,
enum sanitize_state_warnings *warn);
static inline bool is_susp(union drbd_state s)
@@ -63,17 +62,18 @@ static inline bool is_susp(union drbd_state s)
return s.susp || s.susp_nod || s.susp_fen;
}
-bool conn_all_vols_unconf(struct drbd_tconn *tconn)
+bool conn_all_vols_unconf(struct drbd_connection *connection)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
bool rv = true;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- if (mdev->state.disk != D_DISKLESS ||
- mdev->state.conn != C_STANDALONE ||
- mdev->state.role != R_SECONDARY) {
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ if (device->state.disk != D_DISKLESS ||
+ device->state.conn != C_STANDALONE ||
+ device->state.role != R_SECONDARY) {
rv = false;
break;
}
@@ -102,99 +102,111 @@ static enum drbd_role min_role(enum drbd_role role1, enum drbd_role role2)
return R_PRIMARY;
}
-enum drbd_role conn_highest_role(struct drbd_tconn *tconn)
+enum drbd_role conn_highest_role(struct drbd_connection *connection)
{
enum drbd_role role = R_UNKNOWN;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr)
- role = max_role(role, mdev->state.role);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ role = max_role(role, device->state.role);
+ }
rcu_read_unlock();
return role;
}
-enum drbd_role conn_highest_peer(struct drbd_tconn *tconn)
+enum drbd_role conn_highest_peer(struct drbd_connection *connection)
{
enum drbd_role peer = R_UNKNOWN;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr)
- peer = max_role(peer, mdev->state.peer);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ peer = max_role(peer, device->state.peer);
+ }
rcu_read_unlock();
return peer;
}
-enum drbd_disk_state conn_highest_disk(struct drbd_tconn *tconn)
+enum drbd_disk_state conn_highest_disk(struct drbd_connection *connection)
{
enum drbd_disk_state ds = D_DISKLESS;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr)
- ds = max_t(enum drbd_disk_state, ds, mdev->state.disk);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ ds = max_t(enum drbd_disk_state, ds, device->state.disk);
+ }
rcu_read_unlock();
return ds;
}
-enum drbd_disk_state conn_lowest_disk(struct drbd_tconn *tconn)
+enum drbd_disk_state conn_lowest_disk(struct drbd_connection *connection)
{
enum drbd_disk_state ds = D_MASK;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr)
- ds = min_t(enum drbd_disk_state, ds, mdev->state.disk);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ ds = min_t(enum drbd_disk_state, ds, device->state.disk);
+ }
rcu_read_unlock();
return ds;
}
-enum drbd_disk_state conn_highest_pdsk(struct drbd_tconn *tconn)
+enum drbd_disk_state conn_highest_pdsk(struct drbd_connection *connection)
{
enum drbd_disk_state ds = D_DISKLESS;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr)
- ds = max_t(enum drbd_disk_state, ds, mdev->state.pdsk);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ ds = max_t(enum drbd_disk_state, ds, device->state.pdsk);
+ }
rcu_read_unlock();
return ds;
}
-enum drbd_conns conn_lowest_conn(struct drbd_tconn *tconn)
+enum drbd_conns conn_lowest_conn(struct drbd_connection *connection)
{
enum drbd_conns conn = C_MASK;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr)
- conn = min_t(enum drbd_conns, conn, mdev->state.conn);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ conn = min_t(enum drbd_conns, conn, device->state.conn);
+ }
rcu_read_unlock();
return conn;
}
-static bool no_peer_wf_report_params(struct drbd_tconn *tconn)
+static bool no_peer_wf_report_params(struct drbd_connection *connection)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
bool rv = true;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr)
- if (mdev->state.conn == C_WF_REPORT_PARAMS) {
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr)
+ if (peer_device->device->state.conn == C_WF_REPORT_PARAMS) {
rv = false;
break;
}
@@ -206,11 +218,11 @@ static bool no_peer_wf_report_params(struct drbd_tconn *tconn)
/**
* cl_wide_st_chg() - true if the state change is a cluster wide one
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @os: old (current) state.
* @ns: new (wanted) state.
*/
-static int cl_wide_st_chg(struct drbd_conf *mdev,
+static int cl_wide_st_chg(struct drbd_device *device,
union drbd_state os, union drbd_state ns)
{
return (os.conn >= C_CONNECTED && ns.conn >= C_CONNECTED &&
@@ -232,72 +244,72 @@ apply_mask_val(union drbd_state os, union drbd_state mask, union drbd_state val)
}
enum drbd_state_rv
-drbd_change_state(struct drbd_conf *mdev, enum chg_state_flags f,
+drbd_change_state(struct drbd_device *device, enum chg_state_flags f,
union drbd_state mask, union drbd_state val)
{
unsigned long flags;
union drbd_state ns;
enum drbd_state_rv rv;
- spin_lock_irqsave(&mdev->tconn->req_lock, flags);
- ns = apply_mask_val(drbd_read_state(mdev), mask, val);
- rv = _drbd_set_state(mdev, ns, f, NULL);
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
+ spin_lock_irqsave(&device->resource->req_lock, flags);
+ ns = apply_mask_val(drbd_read_state(device), mask, val);
+ rv = _drbd_set_state(device, ns, f, NULL);
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
return rv;
}
/**
* drbd_force_state() - Impose a change which happens outside our control on our state
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @mask: mask of state bits to change.
* @val: value of new state bits.
*/
-void drbd_force_state(struct drbd_conf *mdev,
+void drbd_force_state(struct drbd_device *device,
union drbd_state mask, union drbd_state val)
{
- drbd_change_state(mdev, CS_HARD, mask, val);
+ drbd_change_state(device, CS_HARD, mask, val);
}
static enum drbd_state_rv
-_req_st_cond(struct drbd_conf *mdev, union drbd_state mask,
+_req_st_cond(struct drbd_device *device, union drbd_state mask,
union drbd_state val)
{
union drbd_state os, ns;
unsigned long flags;
enum drbd_state_rv rv;
- if (test_and_clear_bit(CL_ST_CHG_SUCCESS, &mdev->flags))
+ if (test_and_clear_bit(CL_ST_CHG_SUCCESS, &device->flags))
return SS_CW_SUCCESS;
- if (test_and_clear_bit(CL_ST_CHG_FAIL, &mdev->flags))
+ if (test_and_clear_bit(CL_ST_CHG_FAIL, &device->flags))
return SS_CW_FAILED_BY_PEER;
- spin_lock_irqsave(&mdev->tconn->req_lock, flags);
- os = drbd_read_state(mdev);
- ns = sanitize_state(mdev, apply_mask_val(os, mask, val), NULL);
+ spin_lock_irqsave(&device->resource->req_lock, flags);
+ os = drbd_read_state(device);
+ ns = sanitize_state(device, apply_mask_val(os, mask, val), NULL);
rv = is_valid_transition(os, ns);
if (rv >= SS_SUCCESS)
rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */
- if (!cl_wide_st_chg(mdev, os, ns))
+ if (!cl_wide_st_chg(device, os, ns))
rv = SS_CW_NO_NEED;
if (rv == SS_UNKNOWN_ERROR) {
- rv = is_valid_state(mdev, ns);
+ rv = is_valid_state(device, ns);
if (rv >= SS_SUCCESS) {
- rv = is_valid_soft_transition(os, ns, mdev->tconn);
+ rv = is_valid_soft_transition(os, ns, first_peer_device(device)->connection);
if (rv >= SS_SUCCESS)
rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */
}
}
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
return rv;
}
/**
* drbd_req_state() - Perform an eventually cluster wide state change
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @mask: mask of state bits to change.
* @val: value of new state bits.
* @f: flags
@@ -306,7 +318,7 @@ _req_st_cond(struct drbd_conf *mdev, union drbd_state mask,
* _drbd_request_state().
*/
static enum drbd_state_rv
-drbd_req_state(struct drbd_conf *mdev, union drbd_state mask,
+drbd_req_state(struct drbd_device *device, union drbd_state mask,
union drbd_state val, enum chg_state_flags f)
{
struct completion done;
@@ -317,68 +329,68 @@ drbd_req_state(struct drbd_conf *mdev, union drbd_state mask,
init_completion(&done);
if (f & CS_SERIALIZE)
- mutex_lock(mdev->state_mutex);
+ mutex_lock(device->state_mutex);
- spin_lock_irqsave(&mdev->tconn->req_lock, flags);
- os = drbd_read_state(mdev);
- ns = sanitize_state(mdev, apply_mask_val(os, mask, val), NULL);
+ spin_lock_irqsave(&device->resource->req_lock, flags);
+ os = drbd_read_state(device);
+ ns = sanitize_state(device, apply_mask_val(os, mask, val), NULL);
rv = is_valid_transition(os, ns);
if (rv < SS_SUCCESS) {
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
goto abort;
}
- if (cl_wide_st_chg(mdev, os, ns)) {
- rv = is_valid_state(mdev, ns);
+ if (cl_wide_st_chg(device, os, ns)) {
+ rv = is_valid_state(device, ns);
if (rv == SS_SUCCESS)
- rv = is_valid_soft_transition(os, ns, mdev->tconn);
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
+ rv = is_valid_soft_transition(os, ns, first_peer_device(device)->connection);
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
if (rv < SS_SUCCESS) {
if (f & CS_VERBOSE)
- print_st_err(mdev, os, ns, rv);
+ print_st_err(device, os, ns, rv);
goto abort;
}
- if (drbd_send_state_req(mdev, mask, val)) {
+ if (drbd_send_state_req(first_peer_device(device), mask, val)) {
rv = SS_CW_FAILED_BY_PEER;
if (f & CS_VERBOSE)
- print_st_err(mdev, os, ns, rv);
+ print_st_err(device, os, ns, rv);
goto abort;
}
- wait_event(mdev->state_wait,
- (rv = _req_st_cond(mdev, mask, val)));
+ wait_event(device->state_wait,
+ (rv = _req_st_cond(device, mask, val)));
if (rv < SS_SUCCESS) {
if (f & CS_VERBOSE)
- print_st_err(mdev, os, ns, rv);
+ print_st_err(device, os, ns, rv);
goto abort;
}
- spin_lock_irqsave(&mdev->tconn->req_lock, flags);
- ns = apply_mask_val(drbd_read_state(mdev), mask, val);
- rv = _drbd_set_state(mdev, ns, f, &done);
+ spin_lock_irqsave(&device->resource->req_lock, flags);
+ ns = apply_mask_val(drbd_read_state(device), mask, val);
+ rv = _drbd_set_state(device, ns, f, &done);
} else {
- rv = _drbd_set_state(mdev, ns, f, &done);
+ rv = _drbd_set_state(device, ns, f, &done);
}
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
if (f & CS_WAIT_COMPLETE && rv == SS_SUCCESS) {
- D_ASSERT(current != mdev->tconn->worker.task);
+ D_ASSERT(device, current != first_peer_device(device)->connection->worker.task);
wait_for_completion(&done);
}
abort:
if (f & CS_SERIALIZE)
- mutex_unlock(mdev->state_mutex);
+ mutex_unlock(device->state_mutex);
return rv;
}
/**
* _drbd_request_state() - Request a state change (with flags)
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @mask: mask of state bits to change.
* @val: value of new state bits.
* @f: flags
@@ -387,20 +399,20 @@ abort:
* flag, or when logging of failed state change requests is not desired.
*/
enum drbd_state_rv
-_drbd_request_state(struct drbd_conf *mdev, union drbd_state mask,
+_drbd_request_state(struct drbd_device *device, union drbd_state mask,
union drbd_state val, enum chg_state_flags f)
{
enum drbd_state_rv rv;
- wait_event(mdev->state_wait,
- (rv = drbd_req_state(mdev, mask, val, f)) != SS_IN_TRANSIENT_STATE);
+ wait_event(device->state_wait,
+ (rv = drbd_req_state(device, mask, val, f)) != SS_IN_TRANSIENT_STATE);
return rv;
}
-static void print_st(struct drbd_conf *mdev, char *name, union drbd_state ns)
+static void print_st(struct drbd_device *device, char *name, union drbd_state ns)
{
- dev_err(DEV, " %s = { cs:%s ro:%s/%s ds:%s/%s %c%c%c%c%c%c }\n",
+ drbd_err(device, " %s = { cs:%s ro:%s/%s ds:%s/%s %c%c%c%c%c%c }\n",
name,
drbd_conn_str(ns.conn),
drbd_role_str(ns.role),
@@ -416,14 +428,14 @@ static void print_st(struct drbd_conf *mdev, char *name, union drbd_state ns)
);
}
-void print_st_err(struct drbd_conf *mdev, union drbd_state os,
+void print_st_err(struct drbd_device *device, union drbd_state os,
union drbd_state ns, enum drbd_state_rv err)
{
if (err == SS_IN_TRANSIENT_STATE)
return;
- dev_err(DEV, "State change failed: %s\n", drbd_set_st_err_str(err));
- print_st(mdev, " state", os);
- print_st(mdev, "wanted", ns);
+ drbd_err(device, "State change failed: %s\n", drbd_set_st_err_str(err));
+ print_st(device, " state", os);
+ print_st(device, "wanted", ns);
}
static long print_state_change(char *pb, union drbd_state os, union drbd_state ns,
@@ -457,7 +469,7 @@ static long print_state_change(char *pb, union drbd_state os, union drbd_state n
return pbp - pb;
}
-static void drbd_pr_state_change(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns,
+static void drbd_pr_state_change(struct drbd_device *device, union drbd_state os, union drbd_state ns,
enum chg_state_flags flags)
{
char pb[300];
@@ -479,10 +491,10 @@ static void drbd_pr_state_change(struct drbd_conf *mdev, union drbd_state os, un
ns.user_isp);
if (pbp != pb)
- dev_info(DEV, "%s\n", pb);
+ drbd_info(device, "%s\n", pb);
}
-static void conn_pr_state_change(struct drbd_tconn *tconn, union drbd_state os, union drbd_state ns,
+static void conn_pr_state_change(struct drbd_connection *connection, union drbd_state os, union drbd_state ns,
enum chg_state_flags flags)
{
char pb[300];
@@ -496,17 +508,17 @@ static void conn_pr_state_change(struct drbd_tconn *tconn, union drbd_state os,
is_susp(ns));
if (pbp != pb)
- conn_info(tconn, "%s\n", pb);
+ drbd_info(connection, "%s\n", pb);
}
/**
* is_valid_state() - Returns an SS_ error code if ns is not valid
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @ns: State to consider.
*/
static enum drbd_state_rv
-is_valid_state(struct drbd_conf *mdev, union drbd_state ns)
+is_valid_state(struct drbd_device *device, union drbd_state ns)
{
/* See drbd_state_sw_errors in drbd_strings.c */
@@ -516,24 +528,24 @@ is_valid_state(struct drbd_conf *mdev, union drbd_state ns)
rcu_read_lock();
fp = FP_DONT_CARE;
- if (get_ldev(mdev)) {
- fp = rcu_dereference(mdev->ldev->disk_conf)->fencing;
- put_ldev(mdev);
+ if (get_ldev(device)) {
+ fp = rcu_dereference(device->ldev->disk_conf)->fencing;
+ put_ldev(device);
}
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
if (nc) {
if (!nc->two_primaries && ns.role == R_PRIMARY) {
if (ns.peer == R_PRIMARY)
rv = SS_TWO_PRIMARIES;
- else if (conn_highest_peer(mdev->tconn) == R_PRIMARY)
+ else if (conn_highest_peer(first_peer_device(device)->connection) == R_PRIMARY)
rv = SS_O_VOL_PEER_PRI;
}
}
if (rv <= 0)
/* already found a reason to abort */;
- else if (ns.role == R_SECONDARY && mdev->open_cnt)
+ else if (ns.role == R_SECONDARY && device->open_cnt)
rv = SS_DEVICE_IN_USE;
else if (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.disk < D_UP_TO_DATE)
@@ -567,7 +579,7 @@ is_valid_state(struct drbd_conf *mdev, union drbd_state ns)
rv = SS_NO_VERIFY_ALG;
else if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) &&
- mdev->tconn->agreed_pro_version < 88)
+ first_peer_device(device)->connection->agreed_pro_version < 88)
rv = SS_NOT_SUPPORTED;
else if (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE)
@@ -589,12 +601,12 @@ is_valid_state(struct drbd_conf *mdev, union drbd_state ns)
* is_valid_soft_transition() - Returns an SS_ error code if the state transition is not possible
* This function limits state transitions that may be declined by DRBD. I.e.
* user requests (aka soft transitions).
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @ns: new state.
* @os: old state.
*/
static enum drbd_state_rv
-is_valid_soft_transition(union drbd_state os, union drbd_state ns, struct drbd_tconn *tconn)
+is_valid_soft_transition(union drbd_state os, union drbd_state ns, struct drbd_connection *connection)
{
enum drbd_state_rv rv = SS_SUCCESS;
@@ -622,7 +634,7 @@ is_valid_soft_transition(union drbd_state os, union drbd_state ns, struct drbd_t
/* While establishing a connection only allow cstate to change.
Delay/refuse role changes, detach attach etc... */
- if (test_bit(STATE_SENT, &tconn->flags) &&
+ if (test_bit(STATE_SENT, &connection->flags) &&
!(os.conn == C_WF_REPORT_PARAMS ||
(ns.conn == C_WF_REPORT_PARAMS && os.conn == C_WF_CONNECTION)))
rv = SS_IN_TRANSIENT_STATE;
@@ -703,7 +715,7 @@ is_valid_transition(union drbd_state os, union drbd_state ns)
return rv;
}
-static void print_sanitize_warnings(struct drbd_conf *mdev, enum sanitize_state_warnings warn)
+static void print_sanitize_warnings(struct drbd_device *device, enum sanitize_state_warnings warn)
{
static const char *msg_table[] = {
[NO_WARNING] = "",
@@ -715,12 +727,12 @@ static void print_sanitize_warnings(struct drbd_conf *mdev, enum sanitize_state_
};
if (warn != NO_WARNING)
- dev_warn(DEV, "%s\n", msg_table[warn]);
+ drbd_warn(device, "%s\n", msg_table[warn]);
}
/**
* sanitize_state() - Resolves implicitly necessary additional changes to a state transition
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @os: old state.
* @ns: new state.
* @warn_sync_abort:
@@ -728,7 +740,7 @@ static void print_sanitize_warnings(struct drbd_conf *mdev, enum sanitize_state_
* When we loose connection, we have to set the state of the peers disk (pdsk)
* to D_UNKNOWN. This rule and many more along those lines are in this function.
*/
-static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state ns,
+static union drbd_state sanitize_state(struct drbd_device *device, union drbd_state ns,
enum sanitize_state_warnings *warn)
{
enum drbd_fencing_p fp;
@@ -738,11 +750,11 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state
*warn = NO_WARNING;
fp = FP_DONT_CARE;
- if (get_ldev(mdev)) {
+ if (get_ldev(device)) {
rcu_read_lock();
- fp = rcu_dereference(mdev->ldev->disk_conf)->fencing;
+ fp = rcu_dereference(device->ldev->disk_conf)->fencing;
rcu_read_unlock();
- put_ldev(mdev);
+ put_ldev(device);
}
/* Implications from connection to peer and peer_isp */
@@ -768,17 +780,17 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state
/* Connection breaks down before we finished "Negotiating" */
if (ns.conn < C_CONNECTED && ns.disk == D_NEGOTIATING &&
- get_ldev_if_state(mdev, D_NEGOTIATING)) {
- if (mdev->ed_uuid == mdev->ldev->md.uuid[UI_CURRENT]) {
- ns.disk = mdev->new_state_tmp.disk;
- ns.pdsk = mdev->new_state_tmp.pdsk;
+ get_ldev_if_state(device, D_NEGOTIATING)) {
+ if (device->ed_uuid == device->ldev->md.uuid[UI_CURRENT]) {
+ ns.disk = device->new_state_tmp.disk;
+ ns.pdsk = device->new_state_tmp.pdsk;
} else {
if (warn)
*warn = CONNECTION_LOST_NEGOTIATING;
ns.disk = D_DISKLESS;
ns.pdsk = D_UNKNOWN;
}
- put_ldev(mdev);
+ put_ldev(device);
}
/* D_CONSISTENT and D_OUTDATED vanish when we get connected */
@@ -873,7 +885,7 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state
(ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED))
ns.susp_fen = 1; /* Suspend IO while fence-peer handler runs (peer lost) */
- if (mdev->tconn->res_opts.on_no_data == OND_SUSPEND_IO &&
+ if (device->resource->res_opts.on_no_data == OND_SUSPEND_IO &&
(ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE))
ns.susp_nod = 1; /* Suspend IO while no data available (no accessible data available) */
@@ -892,42 +904,42 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state
return ns;
}
-void drbd_resume_al(struct drbd_conf *mdev)
+void drbd_resume_al(struct drbd_device *device)
{
- if (test_and_clear_bit(AL_SUSPENDED, &mdev->flags))
- dev_info(DEV, "Resumed AL updates\n");
+ if (test_and_clear_bit(AL_SUSPENDED, &device->flags))
+ drbd_info(device, "Resumed AL updates\n");
}
/* helper for __drbd_set_state */
-static void set_ov_position(struct drbd_conf *mdev, enum drbd_conns cs)
+static void set_ov_position(struct drbd_device *device, enum drbd_conns cs)
{
- if (mdev->tconn->agreed_pro_version < 90)
- mdev->ov_start_sector = 0;
- mdev->rs_total = drbd_bm_bits(mdev);
- mdev->ov_position = 0;
+ if (first_peer_device(device)->connection->agreed_pro_version < 90)
+ device->ov_start_sector = 0;
+ device->rs_total = drbd_bm_bits(device);
+ device->ov_position = 0;
if (cs == C_VERIFY_T) {
/* starting online verify from an arbitrary position
* does not fit well into the existing protocol.
* on C_VERIFY_T, we initialize ov_left and friends
* implicitly in receive_DataRequest once the
* first P_OV_REQUEST is received */
- mdev->ov_start_sector = ~(sector_t)0;
+ device->ov_start_sector = ~(sector_t)0;
} else {
- unsigned long bit = BM_SECT_TO_BIT(mdev->ov_start_sector);
- if (bit >= mdev->rs_total) {
- mdev->ov_start_sector =
- BM_BIT_TO_SECT(mdev->rs_total - 1);
- mdev->rs_total = 1;
+ unsigned long bit = BM_SECT_TO_BIT(device->ov_start_sector);
+ if (bit >= device->rs_total) {
+ device->ov_start_sector =
+ BM_BIT_TO_SECT(device->rs_total - 1);
+ device->rs_total = 1;
} else
- mdev->rs_total -= bit;
- mdev->ov_position = mdev->ov_start_sector;
+ device->rs_total -= bit;
+ device->ov_position = device->ov_start_sector;
}
- mdev->ov_left = mdev->rs_total;
+ device->ov_left = device->rs_total;
}
/**
* __drbd_set_state() - Set a new DRBD state
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @ns: new state.
* @flags: Flags
* @done: Optional completion, that will get completed after the after_state_ch() finished
@@ -935,7 +947,7 @@ static void set_ov_position(struct drbd_conf *mdev, enum drbd_conns cs)
* Caller needs to hold req_lock, and global_state_lock. Do not call directly.
*/
enum drbd_state_rv
-__drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
+__drbd_set_state(struct drbd_device *device, union drbd_state ns,
enum chg_state_flags flags, struct completion *done)
{
union drbd_state os;
@@ -944,9 +956,9 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
struct after_state_chg_work *ascw;
bool did_remote, should_do_remote;
- os = drbd_read_state(mdev);
+ os = drbd_read_state(device);
- ns = sanitize_state(mdev, ns, &ssw);
+ ns = sanitize_state(device, ns, &ssw);
if (ns.i == os.i)
return SS_NOTHING_TO_DO;
@@ -958,32 +970,33 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
/* pre-state-change checks ; only look at ns */
/* See drbd_state_sw_errors in drbd_strings.c */
- rv = is_valid_state(mdev, ns);
+ rv = is_valid_state(device, ns);
if (rv < SS_SUCCESS) {
/* If the old state was illegal as well, then let
this happen...*/
- if (is_valid_state(mdev, os) == rv)
- rv = is_valid_soft_transition(os, ns, mdev->tconn);
+ if (is_valid_state(device, os) == rv)
+ rv = is_valid_soft_transition(os, ns, first_peer_device(device)->connection);
} else
- rv = is_valid_soft_transition(os, ns, mdev->tconn);
+ rv = is_valid_soft_transition(os, ns, first_peer_device(device)->connection);
}
if (rv < SS_SUCCESS) {
if (flags & CS_VERBOSE)
- print_st_err(mdev, os, ns, rv);
+ print_st_err(device, os, ns, rv);
return rv;
}
- print_sanitize_warnings(mdev, ssw);
+ print_sanitize_warnings(device, ssw);
- drbd_pr_state_change(mdev, os, ns, flags);
+ drbd_pr_state_change(device, os, ns, flags);
/* Display changes to the susp* flags that where caused by the call to
sanitize_state(). Only display it here if we where not called from
_conn_request_state() */
if (!(flags & CS_DC_SUSP))
- conn_pr_state_change(mdev->tconn, os, ns, (flags & ~CS_DC_MASK) | CS_DC_SUSP);
+ conn_pr_state_change(first_peer_device(device)->connection, os, ns,
+ (flags & ~CS_DC_MASK) | CS_DC_SUSP);
/* if we are going -> D_FAILED or D_DISKLESS, grab one extra reference
* on the ldev here, to be sure the transition -> D_DISKLESS resp.
@@ -991,55 +1004,55 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
* after_state_ch works run, where we put_ldev again. */
if ((os.disk != D_FAILED && ns.disk == D_FAILED) ||
(os.disk != D_DISKLESS && ns.disk == D_DISKLESS))
- atomic_inc(&mdev->local_cnt);
+ atomic_inc(&device->local_cnt);
- did_remote = drbd_should_do_remote(mdev->state);
- mdev->state.i = ns.i;
- should_do_remote = drbd_should_do_remote(mdev->state);
- mdev->tconn->susp = ns.susp;
- mdev->tconn->susp_nod = ns.susp_nod;
- mdev->tconn->susp_fen = ns.susp_fen;
+ did_remote = drbd_should_do_remote(device->state);
+ device->state.i = ns.i;
+ should_do_remote = drbd_should_do_remote(device->state);
+ device->resource->susp = ns.susp;
+ device->resource->susp_nod = ns.susp_nod;
+ device->resource->susp_fen = ns.susp_fen;
/* put replicated vs not-replicated requests in seperate epochs */
if (did_remote != should_do_remote)
- start_new_tl_epoch(mdev->tconn);
+ start_new_tl_epoch(first_peer_device(device)->connection);
if (os.disk == D_ATTACHING && ns.disk >= D_NEGOTIATING)
- drbd_print_uuids(mdev, "attached to UUIDs");
+ drbd_print_uuids(device, "attached to UUIDs");
/* Wake up role changes, that were delayed because of connection establishing */
if (os.conn == C_WF_REPORT_PARAMS && ns.conn != C_WF_REPORT_PARAMS &&
- no_peer_wf_report_params(mdev->tconn))
- clear_bit(STATE_SENT, &mdev->tconn->flags);
+ no_peer_wf_report_params(first_peer_device(device)->connection))
+ clear_bit(STATE_SENT, &first_peer_device(device)->connection->flags);
- wake_up(&mdev->misc_wait);
- wake_up(&mdev->state_wait);
- wake_up(&mdev->tconn->ping_wait);
+ wake_up(&device->misc_wait);
+ wake_up(&device->state_wait);
+ wake_up(&first_peer_device(device)->connection->ping_wait);
/* Aborted verify run, or we reached the stop sector.
* Log the last position, unless end-of-device. */
if ((os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) &&
ns.conn <= C_CONNECTED) {
- mdev->ov_start_sector =
- BM_BIT_TO_SECT(drbd_bm_bits(mdev) - mdev->ov_left);
- if (mdev->ov_left)
- dev_info(DEV, "Online Verify reached sector %llu\n",
- (unsigned long long)mdev->ov_start_sector);
+ device->ov_start_sector =
+ BM_BIT_TO_SECT(drbd_bm_bits(device) - device->ov_left);
+ if (device->ov_left)
+ drbd_info(device, "Online Verify reached sector %llu\n",
+ (unsigned long long)device->ov_start_sector);
}
if ((os.conn == C_PAUSED_SYNC_T || os.conn == C_PAUSED_SYNC_S) &&
(ns.conn == C_SYNC_TARGET || ns.conn == C_SYNC_SOURCE)) {
- dev_info(DEV, "Syncer continues.\n");
- mdev->rs_paused += (long)jiffies
- -(long)mdev->rs_mark_time[mdev->rs_last_mark];
+ drbd_info(device, "Syncer continues.\n");
+ device->rs_paused += (long)jiffies
+ -(long)device->rs_mark_time[device->rs_last_mark];
if (ns.conn == C_SYNC_TARGET)
- mod_timer(&mdev->resync_timer, jiffies);
+ mod_timer(&device->resync_timer, jiffies);
}
if ((os.conn == C_SYNC_TARGET || os.conn == C_SYNC_SOURCE) &&
(ns.conn == C_PAUSED_SYNC_T || ns.conn == C_PAUSED_SYNC_S)) {
- dev_info(DEV, "Resync suspended\n");
- mdev->rs_mark_time[mdev->rs_last_mark] = jiffies;
+ drbd_info(device, "Resync suspended\n");
+ device->rs_mark_time[device->rs_last_mark] = jiffies;
}
if (os.conn == C_CONNECTED &&
@@ -1047,77 +1060,77 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
unsigned long now = jiffies;
int i;
- set_ov_position(mdev, ns.conn);
- mdev->rs_start = now;
- mdev->rs_last_events = 0;
- mdev->rs_last_sect_ev = 0;
- mdev->ov_last_oos_size = 0;
- mdev->ov_last_oos_start = 0;
+ set_ov_position(device, ns.conn);
+ device->rs_start = now;
+ device->rs_last_events = 0;
+ device->rs_last_sect_ev = 0;
+ device->ov_last_oos_size = 0;
+ device->ov_last_oos_start = 0;
for (i = 0; i < DRBD_SYNC_MARKS; i++) {
- mdev->rs_mark_left[i] = mdev->ov_left;
- mdev->rs_mark_time[i] = now;
+ device->rs_mark_left[i] = device->ov_left;
+ device->rs_mark_time[i] = now;
}
- drbd_rs_controller_reset(mdev);
+ drbd_rs_controller_reset(device);
if (ns.conn == C_VERIFY_S) {
- dev_info(DEV, "Starting Online Verify from sector %llu\n",
- (unsigned long long)mdev->ov_position);
- mod_timer(&mdev->resync_timer, jiffies);
+ drbd_info(device, "Starting Online Verify from sector %llu\n",
+ (unsigned long long)device->ov_position);
+ mod_timer(&device->resync_timer, jiffies);
}
}
- if (get_ldev(mdev)) {
- u32 mdf = mdev->ldev->md.flags & ~(MDF_CONSISTENT|MDF_PRIMARY_IND|
+ if (get_ldev(device)) {
+ u32 mdf = device->ldev->md.flags & ~(MDF_CONSISTENT|MDF_PRIMARY_IND|
MDF_CONNECTED_IND|MDF_WAS_UP_TO_DATE|
MDF_PEER_OUT_DATED|MDF_CRASHED_PRIMARY);
mdf &= ~MDF_AL_CLEAN;
- if (test_bit(CRASHED_PRIMARY, &mdev->flags))
+ if (test_bit(CRASHED_PRIMARY, &device->flags))
mdf |= MDF_CRASHED_PRIMARY;
- if (mdev->state.role == R_PRIMARY ||
- (mdev->state.pdsk < D_INCONSISTENT && mdev->state.peer == R_PRIMARY))
+ if (device->state.role == R_PRIMARY ||
+ (device->state.pdsk < D_INCONSISTENT && device->state.peer == R_PRIMARY))
mdf |= MDF_PRIMARY_IND;
- if (mdev->state.conn > C_WF_REPORT_PARAMS)
+ if (device->state.conn > C_WF_REPORT_PARAMS)
mdf |= MDF_CONNECTED_IND;
- if (mdev->state.disk > D_INCONSISTENT)
+ if (device->state.disk > D_INCONSISTENT)
mdf |= MDF_CONSISTENT;
- if (mdev->state.disk > D_OUTDATED)
+ if (device->state.disk > D_OUTDATED)
mdf |= MDF_WAS_UP_TO_DATE;
- if (mdev->state.pdsk <= D_OUTDATED && mdev->state.pdsk >= D_INCONSISTENT)
+ if (device->state.pdsk <= D_OUTDATED && device->state.pdsk >= D_INCONSISTENT)
mdf |= MDF_PEER_OUT_DATED;
- if (mdf != mdev->ldev->md.flags) {
- mdev->ldev->md.flags = mdf;
- drbd_md_mark_dirty(mdev);
+ if (mdf != device->ldev->md.flags) {
+ device->ldev->md.flags = mdf;
+ drbd_md_mark_dirty(device);
}
if (os.disk < D_CONSISTENT && ns.disk >= D_CONSISTENT)
- drbd_set_ed_uuid(mdev, mdev->ldev->md.uuid[UI_CURRENT]);
- put_ldev(mdev);
+ drbd_set_ed_uuid(device, device->ldev->md.uuid[UI_CURRENT]);
+ put_ldev(device);
}
/* Peer was forced D_UP_TO_DATE & R_PRIMARY, consider to resync */
if (os.disk == D_INCONSISTENT && os.pdsk == D_INCONSISTENT &&
os.peer == R_SECONDARY && ns.peer == R_PRIMARY)
- set_bit(CONSIDER_RESYNC, &mdev->flags);
+ set_bit(CONSIDER_RESYNC, &device->flags);
/* Receiver should clean up itself */
if (os.conn != C_DISCONNECTING && ns.conn == C_DISCONNECTING)
- drbd_thread_stop_nowait(&mdev->tconn->receiver);
+ drbd_thread_stop_nowait(&first_peer_device(device)->connection->receiver);
/* Now the receiver finished cleaning up itself, it should die */
if (os.conn != C_STANDALONE && ns.conn == C_STANDALONE)
- drbd_thread_stop_nowait(&mdev->tconn->receiver);
+ drbd_thread_stop_nowait(&first_peer_device(device)->connection->receiver);
/* Upon network failure, we need to restart the receiver. */
if (os.conn > C_WF_CONNECTION &&
ns.conn <= C_TEAR_DOWN && ns.conn >= C_TIMEOUT)
- drbd_thread_restart_nowait(&mdev->tconn->receiver);
+ drbd_thread_restart_nowait(&first_peer_device(device)->connection->receiver);
/* Resume AL writing if we get a connection */
if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) {
- drbd_resume_al(mdev);
- mdev->tconn->connect_cnt++;
+ drbd_resume_al(device);
+ first_peer_device(device)->connection->connect_cnt++;
}
/* remember last attach time so request_timer_fn() won't
@@ -1125,7 +1138,7 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
* previously frozen IO */
if ((os.disk == D_ATTACHING || os.disk == D_NEGOTIATING) &&
ns.disk > D_NEGOTIATING)
- mdev->last_reattach_jif = jiffies;
+ device->last_reattach_jif = jiffies;
ascw = kmalloc(sizeof(*ascw), GFP_ATOMIC);
if (ascw) {
@@ -1133,11 +1146,12 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
ascw->ns = ns;
ascw->flags = flags;
ascw->w.cb = w_after_state_ch;
- ascw->w.mdev = mdev;
+ ascw->device = device;
ascw->done = done;
- drbd_queue_work(&mdev->tconn->sender_work, &ascw->w);
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &ascw->w);
} else {
- dev_err(DEV, "Could not kmalloc an ascw\n");
+ drbd_err(device, "Could not kmalloc an ascw\n");
}
return rv;
@@ -1147,66 +1161,65 @@ static int w_after_state_ch(struct drbd_work *w, int unused)
{
struct after_state_chg_work *ascw =
container_of(w, struct after_state_chg_work, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_device *device = ascw->device;
- after_state_ch(mdev, ascw->os, ascw->ns, ascw->flags);
- if (ascw->flags & CS_WAIT_COMPLETE) {
- D_ASSERT(ascw->done != NULL);
+ after_state_ch(device, ascw->os, ascw->ns, ascw->flags);
+ if (ascw->flags & CS_WAIT_COMPLETE)
complete(ascw->done);
- }
kfree(ascw);
return 0;
}
-static void abw_start_sync(struct drbd_conf *mdev, int rv)
+static void abw_start_sync(struct drbd_device *device, int rv)
{
if (rv) {
- dev_err(DEV, "Writing the bitmap failed not starting resync.\n");
- _drbd_request_state(mdev, NS(conn, C_CONNECTED), CS_VERBOSE);
+ drbd_err(device, "Writing the bitmap failed not starting resync.\n");
+ _drbd_request_state(device, NS(conn, C_CONNECTED), CS_VERBOSE);
return;
}
- switch (mdev->state.conn) {
+ switch (device->state.conn) {
case C_STARTING_SYNC_T:
- _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE);
+ _drbd_request_state(device, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE);
break;
case C_STARTING_SYNC_S:
- drbd_start_resync(mdev, C_SYNC_SOURCE);
+ drbd_start_resync(device, C_SYNC_SOURCE);
break;
}
}
-int drbd_bitmap_io_from_worker(struct drbd_conf *mdev,
- int (*io_fn)(struct drbd_conf *),
+int drbd_bitmap_io_from_worker(struct drbd_device *device,
+ int (*io_fn)(struct drbd_device *),
char *why, enum bm_flag flags)
{
int rv;
- D_ASSERT(current == mdev->tconn->worker.task);
+ D_ASSERT(device, current == first_peer_device(device)->connection->worker.task);
- /* open coded non-blocking drbd_suspend_io(mdev); */
- set_bit(SUSPEND_IO, &mdev->flags);
+ /* open coded non-blocking drbd_suspend_io(device); */
+ set_bit(SUSPEND_IO, &device->flags);
- drbd_bm_lock(mdev, why, flags);
- rv = io_fn(mdev);
- drbd_bm_unlock(mdev);
+ drbd_bm_lock(device, why, flags);
+ rv = io_fn(device);
+ drbd_bm_unlock(device);
- drbd_resume_io(mdev);
+ drbd_resume_io(device);
return rv;
}
/**
* after_state_ch() - Perform after state change actions that may sleep
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @os: old state.
* @ns: new state.
* @flags: Flags
*/
-static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
+static void after_state_ch(struct drbd_device *device, union drbd_state os,
union drbd_state ns, enum chg_state_flags flags)
{
+ struct drbd_resource *resource = device->resource;
struct sib_info sib;
sib.sib_reason = SIB_STATE_CHANGE;
@@ -1214,63 +1227,63 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
sib.ns = ns;
if (os.conn != C_CONNECTED && ns.conn == C_CONNECTED) {
- clear_bit(CRASHED_PRIMARY, &mdev->flags);
- if (mdev->p_uuid)
- mdev->p_uuid[UI_FLAGS] &= ~((u64)2);
+ clear_bit(CRASHED_PRIMARY, &device->flags);
+ if (device->p_uuid)
+ device->p_uuid[UI_FLAGS] &= ~((u64)2);
}
/* Inform userspace about the change... */
- drbd_bcast_event(mdev, &sib);
+ drbd_bcast_event(device, &sib);
if (!(os.role == R_PRIMARY && os.disk < D_UP_TO_DATE && os.pdsk < D_UP_TO_DATE) &&
(ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE))
- drbd_khelper(mdev, "pri-on-incon-degr");
+ drbd_khelper(device, "pri-on-incon-degr");
/* Here we have the actions that are performed after a
state change. This function might sleep */
if (ns.susp_nod) {
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_connection *connection = first_peer_device(device)->connection;
enum drbd_req_event what = NOTHING;
- spin_lock_irq(&tconn->req_lock);
- if (os.conn < C_CONNECTED && conn_lowest_conn(tconn) >= C_CONNECTED)
+ spin_lock_irq(&device->resource->req_lock);
+ if (os.conn < C_CONNECTED && conn_lowest_conn(connection) >= C_CONNECTED)
what = RESEND;
if ((os.disk == D_ATTACHING || os.disk == D_NEGOTIATING) &&
- conn_lowest_disk(tconn) > D_NEGOTIATING)
+ conn_lowest_disk(connection) > D_NEGOTIATING)
what = RESTART_FROZEN_DISK_IO;
- if (tconn->susp_nod && what != NOTHING) {
- _tl_restart(tconn, what);
- _conn_request_state(tconn,
+ if (resource->susp_nod && what != NOTHING) {
+ _tl_restart(connection, what);
+ _conn_request_state(connection,
(union drbd_state) { { .susp_nod = 1 } },
(union drbd_state) { { .susp_nod = 0 } },
CS_VERBOSE);
}
- spin_unlock_irq(&tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
}
if (ns.susp_fen) {
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_connection *connection = first_peer_device(device)->connection;
- spin_lock_irq(&tconn->req_lock);
- if (tconn->susp_fen && conn_lowest_conn(tconn) >= C_CONNECTED) {
+ spin_lock_irq(&device->resource->req_lock);
+ if (resource->susp_fen && conn_lowest_conn(connection) >= C_CONNECTED) {
/* case2: The connection was established again: */
- struct drbd_conf *odev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, odev, vnr)
- clear_bit(NEW_CUR_UUID, &odev->flags);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr)
+ clear_bit(NEW_CUR_UUID, &peer_device->device->flags);
rcu_read_unlock();
- _tl_restart(tconn, RESEND);
- _conn_request_state(tconn,
+ _tl_restart(connection, RESEND);
+ _conn_request_state(connection,
(union drbd_state) { { .susp_fen = 1 } },
(union drbd_state) { { .susp_fen = 0 } },
CS_VERBOSE);
}
- spin_unlock_irq(&tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
}
/* Became sync source. With protocol >= 96, we still need to send out
@@ -1279,9 +1292,9 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
* which is unexpected. */
if ((os.conn != C_SYNC_SOURCE && os.conn != C_PAUSED_SYNC_S) &&
(ns.conn == C_SYNC_SOURCE || ns.conn == C_PAUSED_SYNC_S) &&
- mdev->tconn->agreed_pro_version >= 96 && get_ldev(mdev)) {
- drbd_gen_and_send_sync_uuid(mdev);
- put_ldev(mdev);
+ first_peer_device(device)->connection->agreed_pro_version >= 96 && get_ldev(device)) {
+ drbd_gen_and_send_sync_uuid(first_peer_device(device));
+ put_ldev(device);
}
/* Do not change the order of the if above and the two below... */
@@ -1289,20 +1302,20 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
ns.pdsk > D_DISKLESS && ns.pdsk != D_UNKNOWN) { /* attach on the peer */
/* we probably will start a resync soon.
* make sure those things are properly reset. */
- mdev->rs_total = 0;
- mdev->rs_failed = 0;
- atomic_set(&mdev->rs_pending_cnt, 0);
- drbd_rs_cancel_all(mdev);
+ device->rs_total = 0;
+ device->rs_failed = 0;
+ atomic_set(&device->rs_pending_cnt, 0);
+ drbd_rs_cancel_all(device);
- drbd_send_uuids(mdev);
- drbd_send_state(mdev, ns);
+ drbd_send_uuids(first_peer_device(device));
+ drbd_send_state(first_peer_device(device), ns);
}
/* No point in queuing send_bitmap if we don't have a connection
* anymore, so check also the _current_ state, not only the new state
* at the time this work was queued. */
if (os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S &&
- mdev->state.conn == C_WF_BITMAP_S)
- drbd_queue_bitmap_io(mdev, &drbd_send_bitmap, NULL,
+ device->state.conn == C_WF_BITMAP_S)
+ drbd_queue_bitmap_io(device, &drbd_send_bitmap, NULL,
"send_bitmap (WFBitMapS)",
BM_LOCKED_TEST_ALLOWED);
@@ -1313,80 +1326,80 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
&& (ns.pdsk < D_INCONSISTENT ||
ns.pdsk == D_UNKNOWN ||
ns.pdsk == D_OUTDATED)) {
- if (get_ldev(mdev)) {
+ if (get_ldev(device)) {
if ((ns.role == R_PRIMARY || ns.peer == R_PRIMARY) &&
- mdev->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) {
- if (drbd_suspended(mdev)) {
- set_bit(NEW_CUR_UUID, &mdev->flags);
+ device->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) {
+ if (drbd_suspended(device)) {
+ set_bit(NEW_CUR_UUID, &device->flags);
} else {
- drbd_uuid_new_current(mdev);
- drbd_send_uuids(mdev);
+ drbd_uuid_new_current(device);
+ drbd_send_uuids(first_peer_device(device));
}
}
- put_ldev(mdev);
+ put_ldev(device);
}
}
- if (ns.pdsk < D_INCONSISTENT && get_ldev(mdev)) {
+ if (ns.pdsk < D_INCONSISTENT && get_ldev(device)) {
if (os.peer == R_SECONDARY && ns.peer == R_PRIMARY &&
- mdev->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) {
- drbd_uuid_new_current(mdev);
- drbd_send_uuids(mdev);
+ device->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) {
+ drbd_uuid_new_current(device);
+ drbd_send_uuids(first_peer_device(device));
}
/* D_DISKLESS Peer becomes secondary */
if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY)
/* We may still be Primary ourselves.
* No harm done if the bitmap still changes,
* redirtied pages will follow later. */
- drbd_bitmap_io_from_worker(mdev, &drbd_bm_write,
+ drbd_bitmap_io_from_worker(device, &drbd_bm_write,
"demote diskless peer", BM_LOCKED_SET_ALLOWED);
- put_ldev(mdev);
+ put_ldev(device);
}
/* Write out all changed bits on demote.
* Though, no need to da that just yet
* if there is a resync going on still */
if (os.role == R_PRIMARY && ns.role == R_SECONDARY &&
- mdev->state.conn <= C_CONNECTED && get_ldev(mdev)) {
+ device->state.conn <= C_CONNECTED && get_ldev(device)) {
/* No changes to the bitmap expected this time, so assert that,
* even though no harm was done if it did change. */
- drbd_bitmap_io_from_worker(mdev, &drbd_bm_write,
+ drbd_bitmap_io_from_worker(device, &drbd_bm_write,
"demote", BM_LOCKED_TEST_ALLOWED);
- put_ldev(mdev);
+ put_ldev(device);
}
/* Last part of the attaching process ... */
if (ns.conn >= C_CONNECTED &&
os.disk == D_ATTACHING && ns.disk == D_NEGOTIATING) {
- drbd_send_sizes(mdev, 0, 0); /* to start sync... */
- drbd_send_uuids(mdev);
- drbd_send_state(mdev, ns);
+ drbd_send_sizes(first_peer_device(device), 0, 0); /* to start sync... */
+ drbd_send_uuids(first_peer_device(device));
+ drbd_send_state(first_peer_device(device), ns);
}
/* We want to pause/continue resync, tell peer. */
if (ns.conn >= C_CONNECTED &&
((os.aftr_isp != ns.aftr_isp) ||
(os.user_isp != ns.user_isp)))
- drbd_send_state(mdev, ns);
+ drbd_send_state(first_peer_device(device), ns);
/* In case one of the isp bits got set, suspend other devices. */
if ((!os.aftr_isp && !os.peer_isp && !os.user_isp) &&
(ns.aftr_isp || ns.peer_isp || ns.user_isp))
- suspend_other_sg(mdev);
+ suspend_other_sg(device);
/* Make sure the peer gets informed about eventual state
changes (ISP bits) while we were in WFReportParams. */
if (os.conn == C_WF_REPORT_PARAMS && ns.conn >= C_CONNECTED)
- drbd_send_state(mdev, ns);
+ drbd_send_state(first_peer_device(device), ns);
if (os.conn != C_AHEAD && ns.conn == C_AHEAD)
- drbd_send_state(mdev, ns);
+ drbd_send_state(first_peer_device(device), ns);
/* We are in the progress to start a full sync... */
if ((os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) ||
(os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S))
/* no other bitmap changes expected during this phase */
- drbd_queue_bitmap_io(mdev,
+ drbd_queue_bitmap_io(device,
&drbd_bmio_set_n_write, &abw_start_sync,
"set_n_write from StartingSync", BM_LOCKED_TEST_ALLOWED);
@@ -1399,15 +1412,15 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
* our cleanup here with the transition to D_DISKLESS.
* But is is still not save to dreference ldev here, since
* we might come from an failed Attach before ldev was set. */
- if (mdev->ldev) {
+ if (device->ldev) {
rcu_read_lock();
- eh = rcu_dereference(mdev->ldev->disk_conf)->on_io_error;
+ eh = rcu_dereference(device->ldev->disk_conf)->on_io_error;
rcu_read_unlock();
- was_io_error = test_and_clear_bit(WAS_IO_ERROR, &mdev->flags);
+ was_io_error = test_and_clear_bit(WAS_IO_ERROR, &device->flags);
if (was_io_error && eh == EP_CALL_HELPER)
- drbd_khelper(mdev, "local-io-error");
+ drbd_khelper(device, "local-io-error");
/* Immediately allow completion of all application IO,
* that waits for completion from the local disk,
@@ -1422,76 +1435,76 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
* So aborting local requests may cause crashes,
* or even worse, silent data corruption.
*/
- if (test_and_clear_bit(FORCE_DETACH, &mdev->flags))
- tl_abort_disk_io(mdev);
+ if (test_and_clear_bit(FORCE_DETACH, &device->flags))
+ tl_abort_disk_io(device);
/* current state still has to be D_FAILED,
* there is only one way out: to D_DISKLESS,
* and that may only happen after our put_ldev below. */
- if (mdev->state.disk != D_FAILED)
- dev_err(DEV,
+ if (device->state.disk != D_FAILED)
+ drbd_err(device,
"ASSERT FAILED: disk is %s during detach\n",
- drbd_disk_str(mdev->state.disk));
+ drbd_disk_str(device->state.disk));
if (ns.conn >= C_CONNECTED)
- drbd_send_state(mdev, ns);
+ drbd_send_state(first_peer_device(device), ns);
- drbd_rs_cancel_all(mdev);
+ drbd_rs_cancel_all(device);
/* In case we want to get something to stable storage still,
* this may be the last chance.
* Following put_ldev may transition to D_DISKLESS. */
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
}
- put_ldev(mdev);
+ put_ldev(device);
}
- /* second half of local IO error, failure to attach,
- * or administrative detach,
- * after local_cnt references have reached zero again */
- if (os.disk != D_DISKLESS && ns.disk == D_DISKLESS) {
- /* We must still be diskless,
- * re-attach has to be serialized with this! */
- if (mdev->state.disk != D_DISKLESS)
- dev_err(DEV,
- "ASSERT FAILED: disk is %s while going diskless\n",
- drbd_disk_str(mdev->state.disk));
+ /* second half of local IO error, failure to attach,
+ * or administrative detach,
+ * after local_cnt references have reached zero again */
+ if (os.disk != D_DISKLESS && ns.disk == D_DISKLESS) {
+ /* We must still be diskless,
+ * re-attach has to be serialized with this! */
+ if (device->state.disk != D_DISKLESS)
+ drbd_err(device,
+ "ASSERT FAILED: disk is %s while going diskless\n",
+ drbd_disk_str(device->state.disk));
if (ns.conn >= C_CONNECTED)
- drbd_send_state(mdev, ns);
+ drbd_send_state(first_peer_device(device), ns);
/* corresponding get_ldev in __drbd_set_state
* this may finally trigger drbd_ldev_destroy. */
- put_ldev(mdev);
+ put_ldev(device);
}
/* Notify peer that I had a local IO error, and did not detached.. */
if (os.disk == D_UP_TO_DATE && ns.disk == D_INCONSISTENT && ns.conn >= C_CONNECTED)
- drbd_send_state(mdev, ns);
+ drbd_send_state(first_peer_device(device), ns);
/* Disks got bigger while they were detached */
if (ns.disk > D_NEGOTIATING && ns.pdsk > D_NEGOTIATING &&
- test_and_clear_bit(RESYNC_AFTER_NEG, &mdev->flags)) {
+ test_and_clear_bit(RESYNC_AFTER_NEG, &device->flags)) {
if (ns.conn == C_CONNECTED)
- resync_after_online_grow(mdev);
+ resync_after_online_grow(device);
}
/* A resync finished or aborted, wake paused devices... */
if ((os.conn > C_CONNECTED && ns.conn <= C_CONNECTED) ||
(os.peer_isp && !ns.peer_isp) ||
(os.user_isp && !ns.user_isp))
- resume_next_sg(mdev);
+ resume_next_sg(device);
/* sync target done with resync. Explicitly notify peer, even though
* it should (at least for non-empty resyncs) already know itself. */
if (os.disk < D_UP_TO_DATE && os.conn >= C_SYNC_SOURCE && ns.conn == C_CONNECTED)
- drbd_send_state(mdev, ns);
+ drbd_send_state(first_peer_device(device), ns);
/* Verify finished, or reached stop sector. Peer did not know about
* the stop sector, and we may even have changed the stop sector during
* verify to interrupt/stop early. Send the new state. */
if (os.conn == C_VERIFY_S && ns.conn == C_CONNECTED
- && verify_can_do_stop_sector(mdev))
- drbd_send_state(mdev, ns);
+ && verify_can_do_stop_sector(device))
+ drbd_send_state(first_peer_device(device), ns);
/* This triggers bitmap writeout of potentially still unwritten pages
* if the resync finished cleanly, or aborted because of peer disk
@@ -1500,56 +1513,57 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
* any bitmap writeout anymore.
* No harm done if some bits change during this phase.
*/
- if (os.conn > C_CONNECTED && ns.conn <= C_CONNECTED && get_ldev(mdev)) {
- drbd_queue_bitmap_io(mdev, &drbd_bm_write_copy_pages, NULL,
+ if (os.conn > C_CONNECTED && ns.conn <= C_CONNECTED && get_ldev(device)) {
+ drbd_queue_bitmap_io(device, &drbd_bm_write_copy_pages, NULL,
"write from resync_finished", BM_LOCKED_CHANGE_ALLOWED);
- put_ldev(mdev);
+ put_ldev(device);
}
if (ns.disk == D_DISKLESS &&
ns.conn == C_STANDALONE &&
ns.role == R_SECONDARY) {
if (os.aftr_isp != ns.aftr_isp)
- resume_next_sg(mdev);
+ resume_next_sg(device);
}
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
}
struct after_conn_state_chg_work {
struct drbd_work w;
enum drbd_conns oc;
union drbd_state ns_min;
- union drbd_state ns_max; /* new, max state, over all mdevs */
+ union drbd_state ns_max; /* new, max state, over all devices */
enum chg_state_flags flags;
+ struct drbd_connection *connection;
};
static int w_after_conn_state_ch(struct drbd_work *w, int unused)
{
struct after_conn_state_chg_work *acscw =
container_of(w, struct after_conn_state_chg_work, w);
- struct drbd_tconn *tconn = w->tconn;
+ struct drbd_connection *connection = acscw->connection;
enum drbd_conns oc = acscw->oc;
union drbd_state ns_max = acscw->ns_max;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
kfree(acscw);
/* Upon network configuration, we need to start the receiver */
if (oc == C_STANDALONE && ns_max.conn == C_UNCONNECTED)
- drbd_thread_start(&tconn->receiver);
+ drbd_thread_start(&connection->receiver);
if (oc == C_DISCONNECTING && ns_max.conn == C_STANDALONE) {
struct net_conf *old_conf;
- mutex_lock(&tconn->conf_update);
- old_conf = tconn->net_conf;
- tconn->my_addr_len = 0;
- tconn->peer_addr_len = 0;
- rcu_assign_pointer(tconn->net_conf, NULL);
- conn_free_crypto(tconn);
- mutex_unlock(&tconn->conf_update);
+ mutex_lock(&connection->resource->conf_update);
+ old_conf = connection->net_conf;
+ connection->my_addr_len = 0;
+ connection->peer_addr_len = 0;
+ rcu_assign_pointer(connection->net_conf, NULL);
+ conn_free_crypto(connection);
+ mutex_unlock(&connection->resource->conf_update);
synchronize_rcu();
kfree(old_conf);
@@ -1559,45 +1573,47 @@ static int w_after_conn_state_ch(struct drbd_work *w, int unused)
/* case1: The outdate peer handler is successful: */
if (ns_max.pdsk <= D_OUTDATED) {
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- if (test_bit(NEW_CUR_UUID, &mdev->flags)) {
- drbd_uuid_new_current(mdev);
- clear_bit(NEW_CUR_UUID, &mdev->flags);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ if (test_bit(NEW_CUR_UUID, &device->flags)) {
+ drbd_uuid_new_current(device);
+ clear_bit(NEW_CUR_UUID, &device->flags);
}
}
rcu_read_unlock();
- spin_lock_irq(&tconn->req_lock);
- _tl_restart(tconn, CONNECTION_LOST_WHILE_PENDING);
- _conn_request_state(tconn,
+ spin_lock_irq(&connection->resource->req_lock);
+ _tl_restart(connection, CONNECTION_LOST_WHILE_PENDING);
+ _conn_request_state(connection,
(union drbd_state) { { .susp_fen = 1 } },
(union drbd_state) { { .susp_fen = 0 } },
CS_VERBOSE);
- spin_unlock_irq(&tconn->req_lock);
+ spin_unlock_irq(&connection->resource->req_lock);
}
}
- kref_put(&tconn->kref, &conn_destroy);
+ kref_put(&connection->kref, drbd_destroy_connection);
- conn_md_sync(tconn);
+ conn_md_sync(connection);
return 0;
}
-void conn_old_common_state(struct drbd_tconn *tconn, union drbd_state *pcs, enum chg_state_flags *pf)
+void conn_old_common_state(struct drbd_connection *connection, union drbd_state *pcs, enum chg_state_flags *pf)
{
enum chg_state_flags flags = ~0;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr, first_vol = 1;
union drbd_dev_state os, cs = {
{ .role = R_SECONDARY,
.peer = R_UNKNOWN,
- .conn = tconn->cstate,
+ .conn = connection->cstate,
.disk = D_DISKLESS,
.pdsk = D_UNKNOWN,
} };
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- os = mdev->state;
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ os = device->state;
if (first_vol) {
cs = os;
@@ -1628,18 +1644,19 @@ void conn_old_common_state(struct drbd_tconn *tconn, union drbd_state *pcs, enum
}
static enum drbd_state_rv
-conn_is_valid_transition(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
+conn_is_valid_transition(struct drbd_connection *connection, union drbd_state mask, union drbd_state val,
enum chg_state_flags flags)
{
enum drbd_state_rv rv = SS_SUCCESS;
union drbd_state ns, os;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- os = drbd_read_state(mdev);
- ns = sanitize_state(mdev, apply_mask_val(os, mask, val), NULL);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ os = drbd_read_state(device);
+ ns = sanitize_state(device, apply_mask_val(os, mask, val), NULL);
if (flags & CS_IGN_OUTD_FAIL && ns.disk == D_OUTDATED && os.disk < D_OUTDATED)
ns.disk = os.disk;
@@ -1648,30 +1665,29 @@ conn_is_valid_transition(struct drbd_tconn *tconn, union drbd_state mask, union
continue;
rv = is_valid_transition(os, ns);
- if (rv < SS_SUCCESS)
- break;
- if (!(flags & CS_HARD)) {
- rv = is_valid_state(mdev, ns);
+ if (rv >= SS_SUCCESS && !(flags & CS_HARD)) {
+ rv = is_valid_state(device, ns);
if (rv < SS_SUCCESS) {
- if (is_valid_state(mdev, os) == rv)
- rv = is_valid_soft_transition(os, ns, tconn);
+ if (is_valid_state(device, os) == rv)
+ rv = is_valid_soft_transition(os, ns, connection);
} else
- rv = is_valid_soft_transition(os, ns, tconn);
+ rv = is_valid_soft_transition(os, ns, connection);
}
- if (rv < SS_SUCCESS)
+
+ if (rv < SS_SUCCESS) {
+ if (flags & CS_VERBOSE)
+ print_st_err(device, os, ns, rv);
break;
+ }
}
rcu_read_unlock();
- if (rv < SS_SUCCESS && flags & CS_VERBOSE)
- print_st_err(mdev, os, ns, rv);
-
return rv;
}
void
-conn_set_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
+conn_set_state(struct drbd_connection *connection, union drbd_state mask, union drbd_state val,
union drbd_state *pns_min, union drbd_state *pns_max, enum chg_state_flags flags)
{
union drbd_state ns, os, ns_max = { };
@@ -1682,7 +1698,7 @@ conn_set_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state
.disk = D_MASK,
.pdsk = D_MASK
} };
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
enum drbd_state_rv rv;
int vnr, number_of_volumes = 0;
@@ -1690,27 +1706,28 @@ conn_set_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state
/* remember last connect time so request_timer_fn() won't
* kill newly established sessions while we are still trying to thaw
* previously frozen IO */
- if (tconn->cstate != C_WF_REPORT_PARAMS && val.conn == C_WF_REPORT_PARAMS)
- tconn->last_reconnect_jif = jiffies;
+ if (connection->cstate != C_WF_REPORT_PARAMS && val.conn == C_WF_REPORT_PARAMS)
+ connection->last_reconnect_jif = jiffies;
- tconn->cstate = val.conn;
+ connection->cstate = val.conn;
}
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
number_of_volumes++;
- os = drbd_read_state(mdev);
+ os = drbd_read_state(device);
ns = apply_mask_val(os, mask, val);
- ns = sanitize_state(mdev, ns, NULL);
+ ns = sanitize_state(device, ns, NULL);
if (flags & CS_IGN_OUTD_FAIL && ns.disk == D_OUTDATED && os.disk < D_OUTDATED)
ns.disk = os.disk;
- rv = __drbd_set_state(mdev, ns, flags, NULL);
+ rv = __drbd_set_state(device, ns, flags, NULL);
if (rv < SS_SUCCESS)
BUG();
- ns.i = mdev->state.i;
+ ns.i = device->state.i;
ns_max.role = max_role(ns.role, ns_max.role);
ns_max.peer = max_role(ns.peer, ns_max.peer);
ns_max.conn = max_t(enum drbd_conns, ns.conn, ns_max.conn);
@@ -1735,39 +1752,39 @@ conn_set_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state
} };
}
- ns_min.susp = ns_max.susp = tconn->susp;
- ns_min.susp_nod = ns_max.susp_nod = tconn->susp_nod;
- ns_min.susp_fen = ns_max.susp_fen = tconn->susp_fen;
+ ns_min.susp = ns_max.susp = connection->resource->susp;
+ ns_min.susp_nod = ns_max.susp_nod = connection->resource->susp_nod;
+ ns_min.susp_fen = ns_max.susp_fen = connection->resource->susp_fen;
*pns_min = ns_min;
*pns_max = ns_max;
}
static enum drbd_state_rv
-_conn_rq_cond(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val)
+_conn_rq_cond(struct drbd_connection *connection, union drbd_state mask, union drbd_state val)
{
enum drbd_state_rv rv;
- if (test_and_clear_bit(CONN_WD_ST_CHG_OKAY, &tconn->flags))
+ if (test_and_clear_bit(CONN_WD_ST_CHG_OKAY, &connection->flags))
return SS_CW_SUCCESS;
- if (test_and_clear_bit(CONN_WD_ST_CHG_FAIL, &tconn->flags))
+ if (test_and_clear_bit(CONN_WD_ST_CHG_FAIL, &connection->flags))
return SS_CW_FAILED_BY_PEER;
- rv = conn_is_valid_transition(tconn, mask, val, 0);
- if (rv == SS_SUCCESS && tconn->cstate == C_WF_REPORT_PARAMS)
+ rv = conn_is_valid_transition(connection, mask, val, 0);
+ if (rv == SS_SUCCESS && connection->cstate == C_WF_REPORT_PARAMS)
rv = SS_UNKNOWN_ERROR; /* continue waiting */
return rv;
}
enum drbd_state_rv
-_conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
+_conn_request_state(struct drbd_connection *connection, union drbd_state mask, union drbd_state val,
enum chg_state_flags flags)
{
enum drbd_state_rv rv = SS_SUCCESS;
struct after_conn_state_chg_work *acscw;
- enum drbd_conns oc = tconn->cstate;
+ enum drbd_conns oc = connection->cstate;
union drbd_state ns_max, ns_min, os;
bool have_mutex = false;
@@ -1777,7 +1794,7 @@ _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_
goto abort;
}
- rv = conn_is_valid_transition(tconn, mask, val, flags);
+ rv = conn_is_valid_transition(connection, mask, val, flags);
if (rv < SS_SUCCESS)
goto abort;
@@ -1787,38 +1804,38 @@ _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_
/* This will be a cluster-wide state change.
* Need to give up the spinlock, grab the mutex,
* then send the state change request, ... */
- spin_unlock_irq(&tconn->req_lock);
- mutex_lock(&tconn->cstate_mutex);
+ spin_unlock_irq(&connection->resource->req_lock);
+ mutex_lock(&connection->cstate_mutex);
have_mutex = true;
- set_bit(CONN_WD_ST_CHG_REQ, &tconn->flags);
- if (conn_send_state_req(tconn, mask, val)) {
+ set_bit(CONN_WD_ST_CHG_REQ, &connection->flags);
+ if (conn_send_state_req(connection, mask, val)) {
/* sending failed. */
- clear_bit(CONN_WD_ST_CHG_REQ, &tconn->flags);
+ clear_bit(CONN_WD_ST_CHG_REQ, &connection->flags);
rv = SS_CW_FAILED_BY_PEER;
/* need to re-aquire the spin lock, though */
goto abort_unlocked;
}
if (val.conn == C_DISCONNECTING)
- set_bit(DISCONNECT_SENT, &tconn->flags);
+ set_bit(DISCONNECT_SENT, &connection->flags);
/* ... and re-aquire the spinlock.
* If _conn_rq_cond() returned >= SS_SUCCESS, we must call
* conn_set_state() within the same spinlock. */
- spin_lock_irq(&tconn->req_lock);
- wait_event_lock_irq(tconn->ping_wait,
- (rv = _conn_rq_cond(tconn, mask, val)),
- tconn->req_lock);
- clear_bit(CONN_WD_ST_CHG_REQ, &tconn->flags);
+ spin_lock_irq(&connection->resource->req_lock);
+ wait_event_lock_irq(connection->ping_wait,
+ (rv = _conn_rq_cond(connection, mask, val)),
+ connection->resource->req_lock);
+ clear_bit(CONN_WD_ST_CHG_REQ, &connection->flags);
if (rv < SS_SUCCESS)
goto abort;
}
- conn_old_common_state(tconn, &os, &flags);
+ conn_old_common_state(connection, &os, &flags);
flags |= CS_DC_SUSP;
- conn_set_state(tconn, mask, val, &ns_min, &ns_max, flags);
- conn_pr_state_change(tconn, os, ns_max, flags);
+ conn_set_state(connection, mask, val, &ns_min, &ns_max, flags);
+ conn_pr_state_change(connection, os, ns_max, flags);
acscw = kmalloc(sizeof(*acscw), GFP_ATOMIC);
if (acscw) {
@@ -1827,39 +1844,39 @@ _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_
acscw->ns_max = ns_max;
acscw->flags = flags;
acscw->w.cb = w_after_conn_state_ch;
- kref_get(&tconn->kref);
- acscw->w.tconn = tconn;
- drbd_queue_work(&tconn->sender_work, &acscw->w);
+ kref_get(&connection->kref);
+ acscw->connection = connection;
+ drbd_queue_work(&connection->sender_work, &acscw->w);
} else {
- conn_err(tconn, "Could not kmalloc an acscw\n");
+ drbd_err(connection, "Could not kmalloc an acscw\n");
}
abort:
if (have_mutex) {
/* mutex_unlock() "... must not be used in interrupt context.",
* so give up the spinlock, then re-aquire it */
- spin_unlock_irq(&tconn->req_lock);
+ spin_unlock_irq(&connection->resource->req_lock);
abort_unlocked:
- mutex_unlock(&tconn->cstate_mutex);
- spin_lock_irq(&tconn->req_lock);
+ mutex_unlock(&connection->cstate_mutex);
+ spin_lock_irq(&connection->resource->req_lock);
}
if (rv < SS_SUCCESS && flags & CS_VERBOSE) {
- conn_err(tconn, "State change failed: %s\n", drbd_set_st_err_str(rv));
- conn_err(tconn, " mask = 0x%x val = 0x%x\n", mask.i, val.i);
- conn_err(tconn, " old_conn:%s wanted_conn:%s\n", drbd_conn_str(oc), drbd_conn_str(val.conn));
+ drbd_err(connection, "State change failed: %s\n", drbd_set_st_err_str(rv));
+ drbd_err(connection, " mask = 0x%x val = 0x%x\n", mask.i, val.i);
+ drbd_err(connection, " old_conn:%s wanted_conn:%s\n", drbd_conn_str(oc), drbd_conn_str(val.conn));
}
return rv;
}
enum drbd_state_rv
-conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
+conn_request_state(struct drbd_connection *connection, union drbd_state mask, union drbd_state val,
enum chg_state_flags flags)
{
enum drbd_state_rv rv;
- spin_lock_irq(&tconn->req_lock);
- rv = _conn_request_state(tconn, mask, val, flags);
- spin_unlock_irq(&tconn->req_lock);
+ spin_lock_irq(&connection->resource->req_lock);
+ rv = _conn_request_state(connection, mask, val, flags);
+ spin_unlock_irq(&connection->resource->req_lock);
return rv;
}
diff --git a/drivers/block/drbd/drbd_state.h b/drivers/block/drbd/drbd_state.h
index a3c361bbc4b6..cc41605ba21c 100644
--- a/drivers/block/drbd/drbd_state.h
+++ b/drivers/block/drbd/drbd_state.h
@@ -1,8 +1,8 @@
#ifndef DRBD_STATE_H
#define DRBD_STATE_H
-struct drbd_conf;
-struct drbd_tconn;
+struct drbd_device;
+struct drbd_connection;
/**
* DOC: DRBD State macros
@@ -107,36 +107,36 @@ union drbd_dev_state {
unsigned int i;
};
-extern enum drbd_state_rv drbd_change_state(struct drbd_conf *mdev,
+extern enum drbd_state_rv drbd_change_state(struct drbd_device *device,
enum chg_state_flags f,
union drbd_state mask,
union drbd_state val);
-extern void drbd_force_state(struct drbd_conf *, union drbd_state,
+extern void drbd_force_state(struct drbd_device *, union drbd_state,
union drbd_state);
-extern enum drbd_state_rv _drbd_request_state(struct drbd_conf *,
+extern enum drbd_state_rv _drbd_request_state(struct drbd_device *,
union drbd_state,
union drbd_state,
enum chg_state_flags);
-extern enum drbd_state_rv __drbd_set_state(struct drbd_conf *, union drbd_state,
+extern enum drbd_state_rv __drbd_set_state(struct drbd_device *, union drbd_state,
enum chg_state_flags,
struct completion *done);
-extern void print_st_err(struct drbd_conf *, union drbd_state,
+extern void print_st_err(struct drbd_device *, union drbd_state,
union drbd_state, int);
enum drbd_state_rv
-_conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
+_conn_request_state(struct drbd_connection *connection, union drbd_state mask, union drbd_state val,
enum chg_state_flags flags);
enum drbd_state_rv
-conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
+conn_request_state(struct drbd_connection *connection, union drbd_state mask, union drbd_state val,
enum chg_state_flags flags);
-extern void drbd_resume_al(struct drbd_conf *mdev);
-extern bool conn_all_vols_unconf(struct drbd_tconn *tconn);
+extern void drbd_resume_al(struct drbd_device *device);
+extern bool conn_all_vols_unconf(struct drbd_connection *connection);
/**
* drbd_request_state() - Reqest a state change
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @mask: mask of state bits to change.
* @val: value of new state bits.
*
@@ -144,18 +144,18 @@ extern bool conn_all_vols_unconf(struct drbd_tconn *tconn);
* quite verbose in case the state change is not possible, and all those
* state changes are globally serialized.
*/
-static inline int drbd_request_state(struct drbd_conf *mdev,
+static inline int drbd_request_state(struct drbd_device *device,
union drbd_state mask,
union drbd_state val)
{
- return _drbd_request_state(mdev, mask, val, CS_VERBOSE + CS_ORDERED);
+ return _drbd_request_state(device, mask, val, CS_VERBOSE + CS_ORDERED);
}
-enum drbd_role conn_highest_role(struct drbd_tconn *tconn);
-enum drbd_role conn_highest_peer(struct drbd_tconn *tconn);
-enum drbd_disk_state conn_highest_disk(struct drbd_tconn *tconn);
-enum drbd_disk_state conn_lowest_disk(struct drbd_tconn *tconn);
-enum drbd_disk_state conn_highest_pdsk(struct drbd_tconn *tconn);
-enum drbd_conns conn_lowest_conn(struct drbd_tconn *tconn);
+enum drbd_role conn_highest_role(struct drbd_connection *connection);
+enum drbd_role conn_highest_peer(struct drbd_connection *connection);
+enum drbd_disk_state conn_highest_disk(struct drbd_connection *connection);
+enum drbd_disk_state conn_lowest_disk(struct drbd_connection *connection);
+enum drbd_disk_state conn_highest_pdsk(struct drbd_connection *connection);
+enum drbd_conns conn_lowest_conn(struct drbd_connection *connection);
#endif
diff --git a/drivers/block/drbd/drbd_strings.c b/drivers/block/drbd/drbd_strings.c
index 58e08ff2b2ce..80b0f63c7075 100644
--- a/drivers/block/drbd/drbd_strings.c
+++ b/drivers/block/drbd/drbd_strings.c
@@ -24,6 +24,7 @@
*/
#include <linux/drbd.h>
+#include "drbd_strings.h"
static const char *drbd_conn_s_names[] = {
[C_STANDALONE] = "StandAlone",
diff --git a/drivers/block/drbd/drbd_strings.h b/drivers/block/drbd/drbd_strings.h
new file mode 100644
index 000000000000..f9923cc88afb
--- /dev/null
+++ b/drivers/block/drbd/drbd_strings.h
@@ -0,0 +1,9 @@
+#ifndef __DRBD_STRINGS_H
+#define __DRBD_STRINGS_H
+
+extern const char *drbd_conn_str(enum drbd_conns);
+extern const char *drbd_role_str(enum drbd_role);
+extern const char *drbd_disk_str(enum drbd_disk_state);
+extern const char *drbd_set_st_err_str(enum drbd_state_rv);
+
+#endif /* __DRBD_STRINGS_H */
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c
index 84d3175d493a..2c4ce42c3657 100644
--- a/drivers/block/drbd/drbd_worker.c
+++ b/drivers/block/drbd/drbd_worker.c
@@ -21,7 +21,7 @@
along with drbd; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- */
+*/
#include <linux/module.h>
#include <linux/drbd.h>
@@ -36,10 +36,11 @@
#include <linux/scatterlist.h>
#include "drbd_int.h"
+#include "drbd_protocol.h"
#include "drbd_req.h"
-static int w_make_ov_request(struct drbd_work *w, int cancel);
-
+static int make_ov_request(struct drbd_device *, int);
+static int make_resync_request(struct drbd_device *, int);
/* endio handlers:
* drbd_md_io_complete (defined here)
@@ -67,10 +68,10 @@ rwlock_t global_state_lock;
void drbd_md_io_complete(struct bio *bio, int error)
{
struct drbd_md_io *md_io;
- struct drbd_conf *mdev;
+ struct drbd_device *device;
md_io = (struct drbd_md_io *)bio->bi_private;
- mdev = container_of(md_io, struct drbd_conf, md_io);
+ device = container_of(md_io, struct drbd_device, md_io);
md_io->error = error;
@@ -83,35 +84,36 @@ void drbd_md_io_complete(struct bio *bio, int error)
* Make sure we first drop the reference, and only then signal
* completion, or we may (in drbd_al_read_log()) cycle so fast into the
* next drbd_md_sync_page_io(), that we trigger the
- * ASSERT(atomic_read(&mdev->md_io_in_use) == 1) there.
+ * ASSERT(atomic_read(&device->md_io_in_use) == 1) there.
*/
- drbd_md_put_buffer(mdev);
+ drbd_md_put_buffer(device);
md_io->done = 1;
- wake_up(&mdev->misc_wait);
+ wake_up(&device->misc_wait);
bio_put(bio);
- if (mdev->ldev) /* special case: drbd_md_read() during drbd_adm_attach() */
- put_ldev(mdev);
+ if (device->ldev) /* special case: drbd_md_read() during drbd_adm_attach() */
+ put_ldev(device);
}
/* reads on behalf of the partner,
* "submitted" by the receiver
*/
-void drbd_endio_read_sec_final(struct drbd_peer_request *peer_req) __releases(local)
+static void drbd_endio_read_sec_final(struct drbd_peer_request *peer_req) __releases(local)
{
unsigned long flags = 0;
- struct drbd_conf *mdev = peer_req->w.mdev;
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
+ struct drbd_device *device = peer_device->device;
- spin_lock_irqsave(&mdev->tconn->req_lock, flags);
- mdev->read_cnt += peer_req->i.size >> 9;
+ spin_lock_irqsave(&device->resource->req_lock, flags);
+ device->read_cnt += peer_req->i.size >> 9;
list_del(&peer_req->w.list);
- if (list_empty(&mdev->read_ee))
- wake_up(&mdev->ee_wait);
+ if (list_empty(&device->read_ee))
+ wake_up(&device->ee_wait);
if (test_bit(__EE_WAS_ERROR, &peer_req->flags))
- __drbd_chk_io_error(mdev, DRBD_READ_ERROR);
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
+ __drbd_chk_io_error(device, DRBD_READ_ERROR);
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
- drbd_queue_work(&mdev->tconn->sender_work, &peer_req->w);
- put_ldev(mdev);
+ drbd_queue_work(&peer_device->connection->sender_work, &peer_req->w);
+ put_ldev(device);
}
/* writes on behalf of the partner, or resync writes,
@@ -119,7 +121,8 @@ void drbd_endio_read_sec_final(struct drbd_peer_request *peer_req) __releases(lo
static void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __releases(local)
{
unsigned long flags = 0;
- struct drbd_conf *mdev = peer_req->w.mdev;
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
+ struct drbd_device *device = peer_device->device;
struct drbd_interval i;
int do_wake;
u64 block_id;
@@ -133,35 +136,35 @@ static void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __rel
do_al_complete_io = peer_req->flags & EE_CALL_AL_COMPLETE_IO;
block_id = peer_req->block_id;
- spin_lock_irqsave(&mdev->tconn->req_lock, flags);
- mdev->writ_cnt += peer_req->i.size >> 9;
- list_move_tail(&peer_req->w.list, &mdev->done_ee);
+ spin_lock_irqsave(&device->resource->req_lock, flags);
+ device->writ_cnt += peer_req->i.size >> 9;
+ list_move_tail(&peer_req->w.list, &device->done_ee);
/*
* Do not remove from the write_requests tree here: we did not send the
* Ack yet and did not wake possibly waiting conflicting requests.
* Removed from the tree from "drbd_process_done_ee" within the
- * appropriate w.cb (e_end_block/e_end_resync_block) or from
+ * appropriate dw.cb (e_end_block/e_end_resync_block) or from
* _drbd_clear_done_ee.
*/
- do_wake = list_empty(block_id == ID_SYNCER ? &mdev->sync_ee : &mdev->active_ee);
+ do_wake = list_empty(block_id == ID_SYNCER ? &device->sync_ee : &device->active_ee);
if (test_bit(__EE_WAS_ERROR, &peer_req->flags))
- __drbd_chk_io_error(mdev, DRBD_WRITE_ERROR);
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
+ __drbd_chk_io_error(device, DRBD_WRITE_ERROR);
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
if (block_id == ID_SYNCER)
- drbd_rs_complete_io(mdev, i.sector);
+ drbd_rs_complete_io(device, i.sector);
if (do_wake)
- wake_up(&mdev->ee_wait);
+ wake_up(&device->ee_wait);
if (do_al_complete_io)
- drbd_al_complete_io(mdev, &i);
+ drbd_al_complete_io(device, &i);
- wake_asender(mdev->tconn);
- put_ldev(mdev);
+ wake_asender(peer_device->connection);
+ put_ldev(device);
}
/* writes on behalf of the partner, or resync writes,
@@ -170,17 +173,17 @@ static void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __rel
void drbd_peer_request_endio(struct bio *bio, int error)
{
struct drbd_peer_request *peer_req = bio->bi_private;
- struct drbd_conf *mdev = peer_req->w.mdev;
+ struct drbd_device *device = peer_req->peer_device->device;
int uptodate = bio_flagged(bio, BIO_UPTODATE);
int is_write = bio_data_dir(bio) == WRITE;
if (error && __ratelimit(&drbd_ratelimit_state))
- dev_warn(DEV, "%s: error=%d s=%llus\n",
+ drbd_warn(device, "%s: error=%d s=%llus\n",
is_write ? "write" : "read", error,
(unsigned long long)peer_req->i.sector);
if (!error && !uptodate) {
if (__ratelimit(&drbd_ratelimit_state))
- dev_warn(DEV, "%s: setting error to -EIO s=%llus\n",
+ drbd_warn(device, "%s: setting error to -EIO s=%llus\n",
is_write ? "write" : "read",
(unsigned long long)peer_req->i.sector);
/* strange behavior of some lower level drivers...
@@ -207,13 +210,13 @@ void drbd_request_endio(struct bio *bio, int error)
{
unsigned long flags;
struct drbd_request *req = bio->bi_private;
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
struct bio_and_error m;
enum drbd_req_event what;
int uptodate = bio_flagged(bio, BIO_UPTODATE);
if (!error && !uptodate) {
- dev_warn(DEV, "p %s: setting error to -EIO\n",
+ drbd_warn(device, "p %s: setting error to -EIO\n",
bio_data_dir(bio) == WRITE ? "write" : "read");
/* strange behavior of some lower level drivers...
* fail the request by clearing the uptodate flag,
@@ -252,7 +255,7 @@ void drbd_request_endio(struct bio *bio, int error)
*/
if (unlikely(req->rq_state & RQ_LOCAL_ABORTED)) {
if (__ratelimit(&drbd_ratelimit_state))
- dev_emerg(DEV, "delayed completion of aborted local request; disk-timeout may be too aggressive\n");
+ drbd_emerg(device, "delayed completion of aborted local request; disk-timeout may be too aggressive\n");
if (!error)
panic("possible random memory corruption caused by delayed completion of aborted local request\n");
@@ -272,17 +275,16 @@ void drbd_request_endio(struct bio *bio, int error)
req->private_bio = ERR_PTR(error);
/* not req_mod(), we need irqsave here! */
- spin_lock_irqsave(&mdev->tconn->req_lock, flags);
+ spin_lock_irqsave(&device->resource->req_lock, flags);
__req_mod(req, what, &m);
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
- put_ldev(mdev);
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
+ put_ldev(device);
if (m.bio)
- complete_master_bio(mdev, &m);
+ complete_master_bio(device, &m);
}
-void drbd_csum_ee(struct drbd_conf *mdev, struct crypto_hash *tfm,
- struct drbd_peer_request *peer_req, void *digest)
+void drbd_csum_ee(struct crypto_hash *tfm, struct drbd_peer_request *peer_req, void *digest)
{
struct hash_desc desc;
struct scatterlist sg;
@@ -309,7 +311,7 @@ void drbd_csum_ee(struct drbd_conf *mdev, struct crypto_hash *tfm,
crypto_hash_final(&desc, digest);
}
-void drbd_csum_bio(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio *bio, void *digest)
+void drbd_csum_bio(struct crypto_hash *tfm, struct bio *bio, void *digest)
{
struct hash_desc desc;
struct scatterlist sg;
@@ -333,7 +335,8 @@ void drbd_csum_bio(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio *
static int w_e_send_csum(struct drbd_work *w, int cancel)
{
struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
+ struct drbd_device *device = peer_device->device;
int digest_size;
void *digest;
int err = 0;
@@ -344,89 +347,92 @@ static int w_e_send_csum(struct drbd_work *w, int cancel)
if (unlikely((peer_req->flags & EE_WAS_ERROR) != 0))
goto out;
- digest_size = crypto_hash_digestsize(mdev->tconn->csums_tfm);
+ digest_size = crypto_hash_digestsize(peer_device->connection->csums_tfm);
digest = kmalloc(digest_size, GFP_NOIO);
if (digest) {
sector_t sector = peer_req->i.sector;
unsigned int size = peer_req->i.size;
- drbd_csum_ee(mdev, mdev->tconn->csums_tfm, peer_req, digest);
+ drbd_csum_ee(peer_device->connection->csums_tfm, peer_req, digest);
/* Free peer_req and pages before send.
* In case we block on congestion, we could otherwise run into
* some distributed deadlock, if the other side blocks on
* congestion as well, because our receiver blocks in
* drbd_alloc_pages due to pp_in_use > max_buffers. */
- drbd_free_peer_req(mdev, peer_req);
+ drbd_free_peer_req(device, peer_req);
peer_req = NULL;
- inc_rs_pending(mdev);
- err = drbd_send_drequest_csum(mdev, sector, size,
+ inc_rs_pending(device);
+ err = drbd_send_drequest_csum(peer_device, sector, size,
digest, digest_size,
P_CSUM_RS_REQUEST);
kfree(digest);
} else {
- dev_err(DEV, "kmalloc() of digest failed.\n");
+ drbd_err(device, "kmalloc() of digest failed.\n");
err = -ENOMEM;
}
out:
if (peer_req)
- drbd_free_peer_req(mdev, peer_req);
+ drbd_free_peer_req(device, peer_req);
if (unlikely(err))
- dev_err(DEV, "drbd_send_drequest(..., csum) failed\n");
+ drbd_err(device, "drbd_send_drequest(..., csum) failed\n");
return err;
}
#define GFP_TRY (__GFP_HIGHMEM | __GFP_NOWARN)
-static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size)
+static int read_for_csum(struct drbd_peer_device *peer_device, sector_t sector, int size)
{
+ struct drbd_device *device = peer_device->device;
struct drbd_peer_request *peer_req;
- if (!get_ldev(mdev))
+ if (!get_ldev(device))
return -EIO;
- if (drbd_rs_should_slow_down(mdev, sector))
+ if (drbd_rs_should_slow_down(device, sector))
goto defer;
/* GFP_TRY, because if there is no memory available right now, this may
* be rescheduled for later. It is "only" background resync, after all. */
- peer_req = drbd_alloc_peer_req(mdev, ID_SYNCER /* unused */, sector,
+ peer_req = drbd_alloc_peer_req(peer_device, ID_SYNCER /* unused */, sector,
size, GFP_TRY);
if (!peer_req)
goto defer;
peer_req->w.cb = w_e_send_csum;
- spin_lock_irq(&mdev->tconn->req_lock);
- list_add(&peer_req->w.list, &mdev->read_ee);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
+ list_add(&peer_req->w.list, &device->read_ee);
+ spin_unlock_irq(&device->resource->req_lock);
- atomic_add(size >> 9, &mdev->rs_sect_ev);
- if (drbd_submit_peer_request(mdev, peer_req, READ, DRBD_FAULT_RS_RD) == 0)
+ atomic_add(size >> 9, &device->rs_sect_ev);
+ if (drbd_submit_peer_request(device, peer_req, READ, DRBD_FAULT_RS_RD) == 0)
return 0;
/* If it failed because of ENOMEM, retry should help. If it failed
* because bio_add_page failed (probably broken lower level driver),
* retry may or may not help.
* If it does not, you may need to force disconnect. */
- spin_lock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
list_del(&peer_req->w.list);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
- drbd_free_peer_req(mdev, peer_req);
+ drbd_free_peer_req(device, peer_req);
defer:
- put_ldev(mdev);
+ put_ldev(device);
return -EAGAIN;
}
int w_resync_timer(struct drbd_work *w, int cancel)
{
- struct drbd_conf *mdev = w->mdev;
- switch (mdev->state.conn) {
+ struct drbd_device *device =
+ container_of(w, struct drbd_device, resync_work);
+
+ switch (device->state.conn) {
case C_VERIFY_S:
- w_make_ov_request(w, cancel);
+ make_ov_request(device, cancel);
break;
case C_SYNC_TARGET:
- w_make_resync_request(w, cancel);
+ make_resync_request(device, cancel);
break;
}
@@ -435,10 +441,11 @@ int w_resync_timer(struct drbd_work *w, int cancel)
void resync_timer_fn(unsigned long data)
{
- struct drbd_conf *mdev = (struct drbd_conf *) data;
+ struct drbd_device *device = (struct drbd_device *) data;
- if (list_empty(&mdev->resync_work.list))
- drbd_queue_work(&mdev->tconn->sender_work, &mdev->resync_work);
+ if (list_empty(&device->resync_work.list))
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &device->resync_work);
}
static void fifo_set(struct fifo_buffer *fb, int value)
@@ -485,7 +492,7 @@ struct fifo_buffer *fifo_alloc(int fifo_size)
return fb;
}
-static int drbd_rs_controller(struct drbd_conf *mdev)
+static int drbd_rs_controller(struct drbd_device *device)
{
struct disk_conf *dc;
unsigned int sect_in; /* Number of sectors that came in since the last turn */
@@ -498,22 +505,22 @@ static int drbd_rs_controller(struct drbd_conf *mdev)
int max_sect;
struct fifo_buffer *plan;
- sect_in = atomic_xchg(&mdev->rs_sect_in, 0); /* Number of sectors that came in */
- mdev->rs_in_flight -= sect_in;
+ sect_in = atomic_xchg(&device->rs_sect_in, 0); /* Number of sectors that came in */
+ device->rs_in_flight -= sect_in;
- dc = rcu_dereference(mdev->ldev->disk_conf);
- plan = rcu_dereference(mdev->rs_plan_s);
+ dc = rcu_dereference(device->ldev->disk_conf);
+ plan = rcu_dereference(device->rs_plan_s);
steps = plan->size; /* (dc->c_plan_ahead * 10 * SLEEP_TIME) / HZ; */
- if (mdev->rs_in_flight + sect_in == 0) { /* At start of resync */
+ if (device->rs_in_flight + sect_in == 0) { /* At start of resync */
want = ((dc->resync_rate * 2 * SLEEP_TIME) / HZ) * steps;
} else { /* normal path */
want = dc->c_fill_target ? dc->c_fill_target :
sect_in * dc->c_delay_target * HZ / (SLEEP_TIME * 10);
}
- correction = want - mdev->rs_in_flight - plan->total;
+ correction = want - device->rs_in_flight - plan->total;
/* Plan ahead */
cps = correction / steps;
@@ -533,25 +540,25 @@ static int drbd_rs_controller(struct drbd_conf *mdev)
req_sect = max_sect;
/*
- dev_warn(DEV, "si=%u if=%d wa=%u co=%d st=%d cps=%d pl=%d cc=%d rs=%d\n",
- sect_in, mdev->rs_in_flight, want, correction,
- steps, cps, mdev->rs_planed, curr_corr, req_sect);
+ drbd_warn(device, "si=%u if=%d wa=%u co=%d st=%d cps=%d pl=%d cc=%d rs=%d\n",
+ sect_in, device->rs_in_flight, want, correction,
+ steps, cps, device->rs_planed, curr_corr, req_sect);
*/
return req_sect;
}
-static int drbd_rs_number_requests(struct drbd_conf *mdev)
+static int drbd_rs_number_requests(struct drbd_device *device)
{
int number;
rcu_read_lock();
- if (rcu_dereference(mdev->rs_plan_s)->size) {
- number = drbd_rs_controller(mdev) >> (BM_BLOCK_SHIFT - 9);
- mdev->c_sync_rate = number * HZ * (BM_BLOCK_SIZE / 1024) / SLEEP_TIME;
+ if (rcu_dereference(device->rs_plan_s)->size) {
+ number = drbd_rs_controller(device) >> (BM_BLOCK_SHIFT - 9);
+ device->c_sync_rate = number * HZ * (BM_BLOCK_SIZE / 1024) / SLEEP_TIME;
} else {
- mdev->c_sync_rate = rcu_dereference(mdev->ldev->disk_conf)->resync_rate;
- number = SLEEP_TIME * mdev->c_sync_rate / ((BM_BLOCK_SIZE / 1024) * HZ);
+ device->c_sync_rate = rcu_dereference(device->ldev->disk_conf)->resync_rate;
+ number = SLEEP_TIME * device->c_sync_rate / ((BM_BLOCK_SIZE / 1024) * HZ);
}
rcu_read_unlock();
@@ -560,12 +567,11 @@ static int drbd_rs_number_requests(struct drbd_conf *mdev)
return number;
}
-int w_make_resync_request(struct drbd_work *w, int cancel)
+static int make_resync_request(struct drbd_device *device, int cancel)
{
- struct drbd_conf *mdev = w->mdev;
unsigned long bit;
sector_t sector;
- const sector_t capacity = drbd_get_capacity(mdev->this_bdev);
+ const sector_t capacity = drbd_get_capacity(device->this_bdev);
int max_bio_size;
int number, rollback_i, size;
int align, queued, sndbuf;
@@ -574,61 +580,61 @@ int w_make_resync_request(struct drbd_work *w, int cancel)
if (unlikely(cancel))
return 0;
- if (mdev->rs_total == 0) {
+ if (device->rs_total == 0) {
/* empty resync? */
- drbd_resync_finished(mdev);
+ drbd_resync_finished(device);
return 0;
}
- if (!get_ldev(mdev)) {
- /* Since we only need to access mdev->rsync a
- get_ldev_if_state(mdev,D_FAILED) would be sufficient, but
+ if (!get_ldev(device)) {
+ /* Since we only need to access device->rsync a
+ get_ldev_if_state(device,D_FAILED) would be sufficient, but
to continue resync with a broken disk makes no sense at
all */
- dev_err(DEV, "Disk broke down during resync!\n");
+ drbd_err(device, "Disk broke down during resync!\n");
return 0;
}
- max_bio_size = queue_max_hw_sectors(mdev->rq_queue) << 9;
- number = drbd_rs_number_requests(mdev);
+ max_bio_size = queue_max_hw_sectors(device->rq_queue) << 9;
+ number = drbd_rs_number_requests(device);
if (number == 0)
goto requeue;
for (i = 0; i < number; i++) {
/* Stop generating RS requests, when half of the send buffer is filled */
- mutex_lock(&mdev->tconn->data.mutex);
- if (mdev->tconn->data.socket) {
- queued = mdev->tconn->data.socket->sk->sk_wmem_queued;
- sndbuf = mdev->tconn->data.socket->sk->sk_sndbuf;
+ mutex_lock(&first_peer_device(device)->connection->data.mutex);
+ if (first_peer_device(device)->connection->data.socket) {
+ queued = first_peer_device(device)->connection->data.socket->sk->sk_wmem_queued;
+ sndbuf = first_peer_device(device)->connection->data.socket->sk->sk_sndbuf;
} else {
queued = 1;
sndbuf = 0;
}
- mutex_unlock(&mdev->tconn->data.mutex);
+ mutex_unlock(&first_peer_device(device)->connection->data.mutex);
if (queued > sndbuf / 2)
goto requeue;
next_sector:
size = BM_BLOCK_SIZE;
- bit = drbd_bm_find_next(mdev, mdev->bm_resync_fo);
+ bit = drbd_bm_find_next(device, device->bm_resync_fo);
if (bit == DRBD_END_OF_BITMAP) {
- mdev->bm_resync_fo = drbd_bm_bits(mdev);
- put_ldev(mdev);
+ device->bm_resync_fo = drbd_bm_bits(device);
+ put_ldev(device);
return 0;
}
sector = BM_BIT_TO_SECT(bit);
- if (drbd_rs_should_slow_down(mdev, sector) ||
- drbd_try_rs_begin_io(mdev, sector)) {
- mdev->bm_resync_fo = bit;
+ if (drbd_rs_should_slow_down(device, sector) ||
+ drbd_try_rs_begin_io(device, sector)) {
+ device->bm_resync_fo = bit;
goto requeue;
}
- mdev->bm_resync_fo = bit + 1;
+ device->bm_resync_fo = bit + 1;
- if (unlikely(drbd_bm_test_bit(mdev, bit) == 0)) {
- drbd_rs_complete_io(mdev, sector);
+ if (unlikely(drbd_bm_test_bit(device, bit) == 0)) {
+ drbd_rs_complete_io(device, sector);
goto next_sector;
}
@@ -657,7 +663,7 @@ next_sector:
* obscure reason; ( b == 0 ) would get the out-of-band
* only accidentally right because of the "oddly sized"
* adjustment below */
- if (drbd_bm_test_bit(mdev, bit+1) != 1)
+ if (drbd_bm_test_bit(device, bit+1) != 1)
break;
bit++;
size += BM_BLOCK_SIZE;
@@ -668,20 +674,21 @@ next_sector:
/* if we merged some,
* reset the offset to start the next drbd_bm_find_next from */
if (size > BM_BLOCK_SIZE)
- mdev->bm_resync_fo = bit + 1;
+ device->bm_resync_fo = bit + 1;
#endif
/* adjust very last sectors, in case we are oddly sized */
if (sector + (size>>9) > capacity)
size = (capacity-sector)<<9;
- if (mdev->tconn->agreed_pro_version >= 89 && mdev->tconn->csums_tfm) {
- switch (read_for_csum(mdev, sector, size)) {
+ if (first_peer_device(device)->connection->agreed_pro_version >= 89 &&
+ first_peer_device(device)->connection->csums_tfm) {
+ switch (read_for_csum(first_peer_device(device), sector, size)) {
case -EIO: /* Disk failure */
- put_ldev(mdev);
+ put_ldev(device);
return -EIO;
case -EAGAIN: /* allocation failed, or ldev busy */
- drbd_rs_complete_io(mdev, sector);
- mdev->bm_resync_fo = BM_SECT_TO_BIT(sector);
+ drbd_rs_complete_io(device, sector);
+ device->bm_resync_fo = BM_SECT_TO_BIT(sector);
i = rollback_i;
goto requeue;
case 0:
@@ -693,50 +700,49 @@ next_sector:
} else {
int err;
- inc_rs_pending(mdev);
- err = drbd_send_drequest(mdev, P_RS_DATA_REQUEST,
+ inc_rs_pending(device);
+ err = drbd_send_drequest(first_peer_device(device), P_RS_DATA_REQUEST,
sector, size, ID_SYNCER);
if (err) {
- dev_err(DEV, "drbd_send_drequest() failed, aborting...\n");
- dec_rs_pending(mdev);
- put_ldev(mdev);
+ drbd_err(device, "drbd_send_drequest() failed, aborting...\n");
+ dec_rs_pending(device);
+ put_ldev(device);
return err;
}
}
}
- if (mdev->bm_resync_fo >= drbd_bm_bits(mdev)) {
+ if (device->bm_resync_fo >= drbd_bm_bits(device)) {
/* last syncer _request_ was sent,
* but the P_RS_DATA_REPLY not yet received. sync will end (and
* next sync group will resume), as soon as we receive the last
* resync data block, and the last bit is cleared.
* until then resync "work" is "inactive" ...
*/
- put_ldev(mdev);
+ put_ldev(device);
return 0;
}
requeue:
- mdev->rs_in_flight += (i << (BM_BLOCK_SHIFT - 9));
- mod_timer(&mdev->resync_timer, jiffies + SLEEP_TIME);
- put_ldev(mdev);
+ device->rs_in_flight += (i << (BM_BLOCK_SHIFT - 9));
+ mod_timer(&device->resync_timer, jiffies + SLEEP_TIME);
+ put_ldev(device);
return 0;
}
-static int w_make_ov_request(struct drbd_work *w, int cancel)
+static int make_ov_request(struct drbd_device *device, int cancel)
{
- struct drbd_conf *mdev = w->mdev;
int number, i, size;
sector_t sector;
- const sector_t capacity = drbd_get_capacity(mdev->this_bdev);
+ const sector_t capacity = drbd_get_capacity(device->this_bdev);
bool stop_sector_reached = false;
if (unlikely(cancel))
return 1;
- number = drbd_rs_number_requests(mdev);
+ number = drbd_rs_number_requests(device);
- sector = mdev->ov_position;
+ sector = device->ov_position;
for (i = 0; i < number; i++) {
if (sector >= capacity)
return 1;
@@ -745,116 +751,121 @@ static int w_make_ov_request(struct drbd_work *w, int cancel)
* w_e_end_ov_reply().
* We need to send at least one request out. */
stop_sector_reached = i > 0
- && verify_can_do_stop_sector(mdev)
- && sector >= mdev->ov_stop_sector;
+ && verify_can_do_stop_sector(device)
+ && sector >= device->ov_stop_sector;
if (stop_sector_reached)
break;
size = BM_BLOCK_SIZE;
- if (drbd_rs_should_slow_down(mdev, sector) ||
- drbd_try_rs_begin_io(mdev, sector)) {
- mdev->ov_position = sector;
+ if (drbd_rs_should_slow_down(device, sector) ||
+ drbd_try_rs_begin_io(device, sector)) {
+ device->ov_position = sector;
goto requeue;
}
if (sector + (size>>9) > capacity)
size = (capacity-sector)<<9;
- inc_rs_pending(mdev);
- if (drbd_send_ov_request(mdev, sector, size)) {
- dec_rs_pending(mdev);
+ inc_rs_pending(device);
+ if (drbd_send_ov_request(first_peer_device(device), sector, size)) {
+ dec_rs_pending(device);
return 0;
}
sector += BM_SECT_PER_BIT;
}
- mdev->ov_position = sector;
+ device->ov_position = sector;
requeue:
- mdev->rs_in_flight += (i << (BM_BLOCK_SHIFT - 9));
+ device->rs_in_flight += (i << (BM_BLOCK_SHIFT - 9));
if (i == 0 || !stop_sector_reached)
- mod_timer(&mdev->resync_timer, jiffies + SLEEP_TIME);
+ mod_timer(&device->resync_timer, jiffies + SLEEP_TIME);
return 1;
}
int w_ov_finished(struct drbd_work *w, int cancel)
{
- struct drbd_conf *mdev = w->mdev;
- kfree(w);
- ov_out_of_sync_print(mdev);
- drbd_resync_finished(mdev);
+ struct drbd_device_work *dw =
+ container_of(w, struct drbd_device_work, w);
+ struct drbd_device *device = dw->device;
+ kfree(dw);
+ ov_out_of_sync_print(device);
+ drbd_resync_finished(device);
return 0;
}
static int w_resync_finished(struct drbd_work *w, int cancel)
{
- struct drbd_conf *mdev = w->mdev;
- kfree(w);
+ struct drbd_device_work *dw =
+ container_of(w, struct drbd_device_work, w);
+ struct drbd_device *device = dw->device;
+ kfree(dw);
- drbd_resync_finished(mdev);
+ drbd_resync_finished(device);
return 0;
}
-static void ping_peer(struct drbd_conf *mdev)
+static void ping_peer(struct drbd_device *device)
{
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_connection *connection = first_peer_device(device)->connection;
- clear_bit(GOT_PING_ACK, &tconn->flags);
- request_ping(tconn);
- wait_event(tconn->ping_wait,
- test_bit(GOT_PING_ACK, &tconn->flags) || mdev->state.conn < C_CONNECTED);
+ clear_bit(GOT_PING_ACK, &connection->flags);
+ request_ping(connection);
+ wait_event(connection->ping_wait,
+ test_bit(GOT_PING_ACK, &connection->flags) || device->state.conn < C_CONNECTED);
}
-int drbd_resync_finished(struct drbd_conf *mdev)
+int drbd_resync_finished(struct drbd_device *device)
{
unsigned long db, dt, dbdt;
unsigned long n_oos;
union drbd_state os, ns;
- struct drbd_work *w;
+ struct drbd_device_work *dw;
char *khelper_cmd = NULL;
int verify_done = 0;
/* Remove all elements from the resync LRU. Since future actions
* might set bits in the (main) bitmap, then the entries in the
* resync LRU would be wrong. */
- if (drbd_rs_del_all(mdev)) {
+ if (drbd_rs_del_all(device)) {
/* In case this is not possible now, most probably because
* there are P_RS_DATA_REPLY Packets lingering on the worker's
* queue (or even the read operations for those packets
* is not finished by now). Retry in 100ms. */
schedule_timeout_interruptible(HZ / 10);
- w = kmalloc(sizeof(struct drbd_work), GFP_ATOMIC);
- if (w) {
- w->cb = w_resync_finished;
- w->mdev = mdev;
- drbd_queue_work(&mdev->tconn->sender_work, w);
+ dw = kmalloc(sizeof(struct drbd_device_work), GFP_ATOMIC);
+ if (dw) {
+ dw->w.cb = w_resync_finished;
+ dw->device = device;
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &dw->w);
return 1;
}
- dev_err(DEV, "Warn failed to drbd_rs_del_all() and to kmalloc(w).\n");
+ drbd_err(device, "Warn failed to drbd_rs_del_all() and to kmalloc(dw).\n");
}
- dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ;
+ dt = (jiffies - device->rs_start - device->rs_paused) / HZ;
if (dt <= 0)
dt = 1;
-
- db = mdev->rs_total;
+
+ db = device->rs_total;
/* adjust for verify start and stop sectors, respective reached position */
- if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T)
- db -= mdev->ov_left;
+ if (device->state.conn == C_VERIFY_S || device->state.conn == C_VERIFY_T)
+ db -= device->ov_left;
dbdt = Bit2KB(db/dt);
- mdev->rs_paused /= HZ;
+ device->rs_paused /= HZ;
- if (!get_ldev(mdev))
+ if (!get_ldev(device))
goto out;
- ping_peer(mdev);
+ ping_peer(device);
- spin_lock_irq(&mdev->tconn->req_lock);
- os = drbd_read_state(mdev);
+ spin_lock_irq(&device->resource->req_lock);
+ os = drbd_read_state(device);
verify_done = (os.conn == C_VERIFY_S || os.conn == C_VERIFY_T);
@@ -866,41 +877,41 @@ int drbd_resync_finished(struct drbd_conf *mdev)
ns = os;
ns.conn = C_CONNECTED;
- dev_info(DEV, "%s done (total %lu sec; paused %lu sec; %lu K/sec)\n",
+ drbd_info(device, "%s done (total %lu sec; paused %lu sec; %lu K/sec)\n",
verify_done ? "Online verify" : "Resync",
- dt + mdev->rs_paused, mdev->rs_paused, dbdt);
+ dt + device->rs_paused, device->rs_paused, dbdt);
- n_oos = drbd_bm_total_weight(mdev);
+ n_oos = drbd_bm_total_weight(device);
if (os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) {
if (n_oos) {
- dev_alert(DEV, "Online verify found %lu %dk block out of sync!\n",
+ drbd_alert(device, "Online verify found %lu %dk block out of sync!\n",
n_oos, Bit2KB(1));
khelper_cmd = "out-of-sync";
}
} else {
- D_ASSERT((n_oos - mdev->rs_failed) == 0);
+ D_ASSERT(device, (n_oos - device->rs_failed) == 0);
if (os.conn == C_SYNC_TARGET || os.conn == C_PAUSED_SYNC_T)
khelper_cmd = "after-resync-target";
- if (mdev->tconn->csums_tfm && mdev->rs_total) {
- const unsigned long s = mdev->rs_same_csum;
- const unsigned long t = mdev->rs_total;
+ if (first_peer_device(device)->connection->csums_tfm && device->rs_total) {
+ const unsigned long s = device->rs_same_csum;
+ const unsigned long t = device->rs_total;
const int ratio =
(t == 0) ? 0 :
(t < 100000) ? ((s*100)/t) : (s/(t/100));
- dev_info(DEV, "%u %% had equal checksums, eliminated: %luK; "
+ drbd_info(device, "%u %% had equal checksums, eliminated: %luK; "
"transferred %luK total %luK\n",
ratio,
- Bit2KB(mdev->rs_same_csum),
- Bit2KB(mdev->rs_total - mdev->rs_same_csum),
- Bit2KB(mdev->rs_total));
+ Bit2KB(device->rs_same_csum),
+ Bit2KB(device->rs_total - device->rs_same_csum),
+ Bit2KB(device->rs_total));
}
}
- if (mdev->rs_failed) {
- dev_info(DEV, " %lu failed blocks\n", mdev->rs_failed);
+ if (device->rs_failed) {
+ drbd_info(device, " %lu failed blocks\n", device->rs_failed);
if (os.conn == C_SYNC_TARGET || os.conn == C_PAUSED_SYNC_T) {
ns.disk = D_INCONSISTENT;
@@ -914,179 +925,181 @@ int drbd_resync_finished(struct drbd_conf *mdev)
ns.pdsk = D_UP_TO_DATE;
if (os.conn == C_SYNC_TARGET || os.conn == C_PAUSED_SYNC_T) {
- if (mdev->p_uuid) {
+ if (device->p_uuid) {
int i;
for (i = UI_BITMAP ; i <= UI_HISTORY_END ; i++)
- _drbd_uuid_set(mdev, i, mdev->p_uuid[i]);
- drbd_uuid_set(mdev, UI_BITMAP, mdev->ldev->md.uuid[UI_CURRENT]);
- _drbd_uuid_set(mdev, UI_CURRENT, mdev->p_uuid[UI_CURRENT]);
+ _drbd_uuid_set(device, i, device->p_uuid[i]);
+ drbd_uuid_set(device, UI_BITMAP, device->ldev->md.uuid[UI_CURRENT]);
+ _drbd_uuid_set(device, UI_CURRENT, device->p_uuid[UI_CURRENT]);
} else {
- dev_err(DEV, "mdev->p_uuid is NULL! BUG\n");
+ drbd_err(device, "device->p_uuid is NULL! BUG\n");
}
}
if (!(os.conn == C_VERIFY_S || os.conn == C_VERIFY_T)) {
/* for verify runs, we don't update uuids here,
* so there would be nothing to report. */
- drbd_uuid_set_bm(mdev, 0UL);
- drbd_print_uuids(mdev, "updated UUIDs");
- if (mdev->p_uuid) {
+ drbd_uuid_set_bm(device, 0UL);
+ drbd_print_uuids(device, "updated UUIDs");
+ if (device->p_uuid) {
/* Now the two UUID sets are equal, update what we
* know of the peer. */
int i;
for (i = UI_CURRENT ; i <= UI_HISTORY_END ; i++)
- mdev->p_uuid[i] = mdev->ldev->md.uuid[i];
+ device->p_uuid[i] = device->ldev->md.uuid[i];
}
}
}
- _drbd_set_state(mdev, ns, CS_VERBOSE, NULL);
+ _drbd_set_state(device, ns, CS_VERBOSE, NULL);
out_unlock:
- spin_unlock_irq(&mdev->tconn->req_lock);
- put_ldev(mdev);
+ spin_unlock_irq(&device->resource->req_lock);
+ put_ldev(device);
out:
- mdev->rs_total = 0;
- mdev->rs_failed = 0;
- mdev->rs_paused = 0;
+ device->rs_total = 0;
+ device->rs_failed = 0;
+ device->rs_paused = 0;
/* reset start sector, if we reached end of device */
- if (verify_done && mdev->ov_left == 0)
- mdev->ov_start_sector = 0;
+ if (verify_done && device->ov_left == 0)
+ device->ov_start_sector = 0;
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
if (khelper_cmd)
- drbd_khelper(mdev, khelper_cmd);
+ drbd_khelper(device, khelper_cmd);
return 1;
}
/* helper */
-static void move_to_net_ee_or_free(struct drbd_conf *mdev, struct drbd_peer_request *peer_req)
+static void move_to_net_ee_or_free(struct drbd_device *device, struct drbd_peer_request *peer_req)
{
if (drbd_peer_req_has_active_page(peer_req)) {
/* This might happen if sendpage() has not finished */
int i = (peer_req->i.size + PAGE_SIZE -1) >> PAGE_SHIFT;
- atomic_add(i, &mdev->pp_in_use_by_net);
- atomic_sub(i, &mdev->pp_in_use);
- spin_lock_irq(&mdev->tconn->req_lock);
- list_add_tail(&peer_req->w.list, &mdev->net_ee);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ atomic_add(i, &device->pp_in_use_by_net);
+ atomic_sub(i, &device->pp_in_use);
+ spin_lock_irq(&device->resource->req_lock);
+ list_add_tail(&peer_req->w.list, &device->net_ee);
+ spin_unlock_irq(&device->resource->req_lock);
wake_up(&drbd_pp_wait);
} else
- drbd_free_peer_req(mdev, peer_req);
+ drbd_free_peer_req(device, peer_req);
}
/**
* w_e_end_data_req() - Worker callback, to send a P_DATA_REPLY packet in response to a P_DATA_REQUEST
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @w: work object.
* @cancel: The connection will be closed anyways
*/
int w_e_end_data_req(struct drbd_work *w, int cancel)
{
struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
+ struct drbd_device *device = peer_device->device;
int err;
if (unlikely(cancel)) {
- drbd_free_peer_req(mdev, peer_req);
- dec_unacked(mdev);
+ drbd_free_peer_req(device, peer_req);
+ dec_unacked(device);
return 0;
}
if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) {
- err = drbd_send_block(mdev, P_DATA_REPLY, peer_req);
+ err = drbd_send_block(peer_device, P_DATA_REPLY, peer_req);
} else {
if (__ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "Sending NegDReply. sector=%llus.\n",
+ drbd_err(device, "Sending NegDReply. sector=%llus.\n",
(unsigned long long)peer_req->i.sector);
- err = drbd_send_ack(mdev, P_NEG_DREPLY, peer_req);
+ err = drbd_send_ack(peer_device, P_NEG_DREPLY, peer_req);
}
- dec_unacked(mdev);
+ dec_unacked(device);
- move_to_net_ee_or_free(mdev, peer_req);
+ move_to_net_ee_or_free(device, peer_req);
if (unlikely(err))
- dev_err(DEV, "drbd_send_block() failed\n");
+ drbd_err(device, "drbd_send_block() failed\n");
return err;
}
/**
* w_e_end_rsdata_req() - Worker callback to send a P_RS_DATA_REPLY packet in response to a P_RS_DATA_REQUEST
- * @mdev: DRBD device.
* @w: work object.
* @cancel: The connection will be closed anyways
*/
int w_e_end_rsdata_req(struct drbd_work *w, int cancel)
{
struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
+ struct drbd_device *device = peer_device->device;
int err;
if (unlikely(cancel)) {
- drbd_free_peer_req(mdev, peer_req);
- dec_unacked(mdev);
+ drbd_free_peer_req(device, peer_req);
+ dec_unacked(device);
return 0;
}
- if (get_ldev_if_state(mdev, D_FAILED)) {
- drbd_rs_complete_io(mdev, peer_req->i.sector);
- put_ldev(mdev);
+ if (get_ldev_if_state(device, D_FAILED)) {
+ drbd_rs_complete_io(device, peer_req->i.sector);
+ put_ldev(device);
}
- if (mdev->state.conn == C_AHEAD) {
- err = drbd_send_ack(mdev, P_RS_CANCEL, peer_req);
+ if (device->state.conn == C_AHEAD) {
+ err = drbd_send_ack(peer_device, P_RS_CANCEL, peer_req);
} else if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) {
- if (likely(mdev->state.pdsk >= D_INCONSISTENT)) {
- inc_rs_pending(mdev);
- err = drbd_send_block(mdev, P_RS_DATA_REPLY, peer_req);
+ if (likely(device->state.pdsk >= D_INCONSISTENT)) {
+ inc_rs_pending(device);
+ err = drbd_send_block(peer_device, P_RS_DATA_REPLY, peer_req);
} else {
if (__ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "Not sending RSDataReply, "
+ drbd_err(device, "Not sending RSDataReply, "
"partner DISKLESS!\n");
err = 0;
}
} else {
if (__ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "Sending NegRSDReply. sector %llus.\n",
+ drbd_err(device, "Sending NegRSDReply. sector %llus.\n",
(unsigned long long)peer_req->i.sector);
- err = drbd_send_ack(mdev, P_NEG_RS_DREPLY, peer_req);
+ err = drbd_send_ack(peer_device, P_NEG_RS_DREPLY, peer_req);
/* update resync data with failure */
- drbd_rs_failed_io(mdev, peer_req->i.sector, peer_req->i.size);
+ drbd_rs_failed_io(device, peer_req->i.sector, peer_req->i.size);
}
- dec_unacked(mdev);
+ dec_unacked(device);
- move_to_net_ee_or_free(mdev, peer_req);
+ move_to_net_ee_or_free(device, peer_req);
if (unlikely(err))
- dev_err(DEV, "drbd_send_block() failed\n");
+ drbd_err(device, "drbd_send_block() failed\n");
return err;
}
int w_e_end_csum_rs_req(struct drbd_work *w, int cancel)
{
struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
+ struct drbd_device *device = peer_device->device;
struct digest_info *di;
int digest_size;
void *digest = NULL;
int err, eq = 0;
if (unlikely(cancel)) {
- drbd_free_peer_req(mdev, peer_req);
- dec_unacked(mdev);
+ drbd_free_peer_req(device, peer_req);
+ dec_unacked(device);
return 0;
}
- if (get_ldev(mdev)) {
- drbd_rs_complete_io(mdev, peer_req->i.sector);
- put_ldev(mdev);
+ if (get_ldev(device)) {
+ drbd_rs_complete_io(device, peer_req->i.sector);
+ put_ldev(device);
}
di = peer_req->digest;
@@ -1095,47 +1108,48 @@ int w_e_end_csum_rs_req(struct drbd_work *w, int cancel)
/* quick hack to try to avoid a race against reconfiguration.
* a real fix would be much more involved,
* introducing more locking mechanisms */
- if (mdev->tconn->csums_tfm) {
- digest_size = crypto_hash_digestsize(mdev->tconn->csums_tfm);
- D_ASSERT(digest_size == di->digest_size);
+ if (peer_device->connection->csums_tfm) {
+ digest_size = crypto_hash_digestsize(peer_device->connection->csums_tfm);
+ D_ASSERT(device, digest_size == di->digest_size);
digest = kmalloc(digest_size, GFP_NOIO);
}
if (digest) {
- drbd_csum_ee(mdev, mdev->tconn->csums_tfm, peer_req, digest);
+ drbd_csum_ee(peer_device->connection->csums_tfm, peer_req, digest);
eq = !memcmp(digest, di->digest, digest_size);
kfree(digest);
}
if (eq) {
- drbd_set_in_sync(mdev, peer_req->i.sector, peer_req->i.size);
+ drbd_set_in_sync(device, peer_req->i.sector, peer_req->i.size);
/* rs_same_csums unit is BM_BLOCK_SIZE */
- mdev->rs_same_csum += peer_req->i.size >> BM_BLOCK_SHIFT;
- err = drbd_send_ack(mdev, P_RS_IS_IN_SYNC, peer_req);
+ device->rs_same_csum += peer_req->i.size >> BM_BLOCK_SHIFT;
+ err = drbd_send_ack(peer_device, P_RS_IS_IN_SYNC, peer_req);
} else {
- inc_rs_pending(mdev);
+ inc_rs_pending(device);
peer_req->block_id = ID_SYNCER; /* By setting block_id, digest pointer becomes invalid! */
peer_req->flags &= ~EE_HAS_DIGEST; /* This peer request no longer has a digest pointer */
kfree(di);
- err = drbd_send_block(mdev, P_RS_DATA_REPLY, peer_req);
+ err = drbd_send_block(peer_device, P_RS_DATA_REPLY, peer_req);
}
} else {
- err = drbd_send_ack(mdev, P_NEG_RS_DREPLY, peer_req);
+ err = drbd_send_ack(peer_device, P_NEG_RS_DREPLY, peer_req);
if (__ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "Sending NegDReply. I guess it gets messy.\n");
+ drbd_err(device, "Sending NegDReply. I guess it gets messy.\n");
}
- dec_unacked(mdev);
- move_to_net_ee_or_free(mdev, peer_req);
+ dec_unacked(device);
+ move_to_net_ee_or_free(device, peer_req);
if (unlikely(err))
- dev_err(DEV, "drbd_send_block/ack() failed\n");
+ drbd_err(device, "drbd_send_block/ack() failed\n");
return err;
}
int w_e_end_ov_req(struct drbd_work *w, int cancel)
{
struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
+ struct drbd_device *device = peer_device->device;
sector_t sector = peer_req->i.sector;
unsigned int size = peer_req->i.size;
int digest_size;
@@ -1145,7 +1159,7 @@ int w_e_end_ov_req(struct drbd_work *w, int cancel)
if (unlikely(cancel))
goto out;
- digest_size = crypto_hash_digestsize(mdev->tconn->verify_tfm);
+ digest_size = crypto_hash_digestsize(peer_device->connection->verify_tfm);
digest = kmalloc(digest_size, GFP_NOIO);
if (!digest) {
err = 1; /* terminate the connection in case the allocation failed */
@@ -1153,7 +1167,7 @@ int w_e_end_ov_req(struct drbd_work *w, int cancel)
}
if (likely(!(peer_req->flags & EE_WAS_ERROR)))
- drbd_csum_ee(mdev, mdev->tconn->verify_tfm, peer_req, digest);
+ drbd_csum_ee(peer_device->connection->verify_tfm, peer_req, digest);
else
memset(digest, 0, digest_size);
@@ -1162,36 +1176,37 @@ int w_e_end_ov_req(struct drbd_work *w, int cancel)
* some distributed deadlock, if the other side blocks on
* congestion as well, because our receiver blocks in
* drbd_alloc_pages due to pp_in_use > max_buffers. */
- drbd_free_peer_req(mdev, peer_req);
+ drbd_free_peer_req(device, peer_req);
peer_req = NULL;
- inc_rs_pending(mdev);
- err = drbd_send_drequest_csum(mdev, sector, size, digest, digest_size, P_OV_REPLY);
+ inc_rs_pending(device);
+ err = drbd_send_drequest_csum(peer_device, sector, size, digest, digest_size, P_OV_REPLY);
if (err)
- dec_rs_pending(mdev);
+ dec_rs_pending(device);
kfree(digest);
out:
if (peer_req)
- drbd_free_peer_req(mdev, peer_req);
- dec_unacked(mdev);
+ drbd_free_peer_req(device, peer_req);
+ dec_unacked(device);
return err;
}
-void drbd_ov_out_of_sync_found(struct drbd_conf *mdev, sector_t sector, int size)
+void drbd_ov_out_of_sync_found(struct drbd_device *device, sector_t sector, int size)
{
- if (mdev->ov_last_oos_start + mdev->ov_last_oos_size == sector) {
- mdev->ov_last_oos_size += size>>9;
+ if (device->ov_last_oos_start + device->ov_last_oos_size == sector) {
+ device->ov_last_oos_size += size>>9;
} else {
- mdev->ov_last_oos_start = sector;
- mdev->ov_last_oos_size = size>>9;
+ device->ov_last_oos_start = sector;
+ device->ov_last_oos_size = size>>9;
}
- drbd_set_out_of_sync(mdev, sector, size);
+ drbd_set_out_of_sync(device, sector, size);
}
int w_e_end_ov_reply(struct drbd_work *w, int cancel)
{
struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
+ struct drbd_device *device = peer_device->device;
struct digest_info *di;
void *digest;
sector_t sector = peer_req->i.sector;
@@ -1201,27 +1216,27 @@ int w_e_end_ov_reply(struct drbd_work *w, int cancel)
bool stop_sector_reached = false;
if (unlikely(cancel)) {
- drbd_free_peer_req(mdev, peer_req);
- dec_unacked(mdev);
+ drbd_free_peer_req(device, peer_req);
+ dec_unacked(device);
return 0;
}
/* after "cancel", because after drbd_disconnect/drbd_rs_cancel_all
* the resync lru has been cleaned up already */
- if (get_ldev(mdev)) {
- drbd_rs_complete_io(mdev, peer_req->i.sector);
- put_ldev(mdev);
+ if (get_ldev(device)) {
+ drbd_rs_complete_io(device, peer_req->i.sector);
+ put_ldev(device);
}
di = peer_req->digest;
if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) {
- digest_size = crypto_hash_digestsize(mdev->tconn->verify_tfm);
+ digest_size = crypto_hash_digestsize(peer_device->connection->verify_tfm);
digest = kmalloc(digest_size, GFP_NOIO);
if (digest) {
- drbd_csum_ee(mdev, mdev->tconn->verify_tfm, peer_req, digest);
+ drbd_csum_ee(peer_device->connection->verify_tfm, peer_req, digest);
- D_ASSERT(digest_size == di->digest_size);
+ D_ASSERT(device, digest_size == di->digest_size);
eq = !memcmp(digest, di->digest, digest_size);
kfree(digest);
}
@@ -1232,102 +1247,95 @@ int w_e_end_ov_reply(struct drbd_work *w, int cancel)
* some distributed deadlock, if the other side blocks on
* congestion as well, because our receiver blocks in
* drbd_alloc_pages due to pp_in_use > max_buffers. */
- drbd_free_peer_req(mdev, peer_req);
+ drbd_free_peer_req(device, peer_req);
if (!eq)
- drbd_ov_out_of_sync_found(mdev, sector, size);
+ drbd_ov_out_of_sync_found(device, sector, size);
else
- ov_out_of_sync_print(mdev);
+ ov_out_of_sync_print(device);
- err = drbd_send_ack_ex(mdev, P_OV_RESULT, sector, size,
+ err = drbd_send_ack_ex(peer_device, P_OV_RESULT, sector, size,
eq ? ID_IN_SYNC : ID_OUT_OF_SYNC);
- dec_unacked(mdev);
+ dec_unacked(device);
- --mdev->ov_left;
+ --device->ov_left;
/* let's advance progress step marks only for every other megabyte */
- if ((mdev->ov_left & 0x200) == 0x200)
- drbd_advance_rs_marks(mdev, mdev->ov_left);
+ if ((device->ov_left & 0x200) == 0x200)
+ drbd_advance_rs_marks(device, device->ov_left);
- stop_sector_reached = verify_can_do_stop_sector(mdev) &&
- (sector + (size>>9)) >= mdev->ov_stop_sector;
+ stop_sector_reached = verify_can_do_stop_sector(device) &&
+ (sector + (size>>9)) >= device->ov_stop_sector;
- if (mdev->ov_left == 0 || stop_sector_reached) {
- ov_out_of_sync_print(mdev);
- drbd_resync_finished(mdev);
+ if (device->ov_left == 0 || stop_sector_reached) {
+ ov_out_of_sync_print(device);
+ drbd_resync_finished(device);
}
return err;
}
-int w_prev_work_done(struct drbd_work *w, int cancel)
-{
- struct drbd_wq_barrier *b = container_of(w, struct drbd_wq_barrier, w);
-
- complete(&b->done);
- return 0;
-}
-
/* FIXME
* We need to track the number of pending barrier acks,
* and to be able to wait for them.
* See also comment in drbd_adm_attach before drbd_suspend_io.
*/
-int drbd_send_barrier(struct drbd_tconn *tconn)
+static int drbd_send_barrier(struct drbd_connection *connection)
{
struct p_barrier *p;
struct drbd_socket *sock;
- sock = &tconn->data;
- p = conn_prepare_command(tconn, sock);
+ sock = &connection->data;
+ p = conn_prepare_command(connection, sock);
if (!p)
return -EIO;
- p->barrier = tconn->send.current_epoch_nr;
+ p->barrier = connection->send.current_epoch_nr;
p->pad = 0;
- tconn->send.current_epoch_writes = 0;
+ connection->send.current_epoch_writes = 0;
- return conn_send_command(tconn, sock, P_BARRIER, sizeof(*p), NULL, 0);
+ return conn_send_command(connection, sock, P_BARRIER, sizeof(*p), NULL, 0);
}
int w_send_write_hint(struct drbd_work *w, int cancel)
{
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_device *device =
+ container_of(w, struct drbd_device, unplug_work);
struct drbd_socket *sock;
if (cancel)
return 0;
- sock = &mdev->tconn->data;
- if (!drbd_prepare_command(mdev, sock))
+ sock = &first_peer_device(device)->connection->data;
+ if (!drbd_prepare_command(first_peer_device(device), sock))
return -EIO;
- return drbd_send_command(mdev, sock, P_UNPLUG_REMOTE, 0, NULL, 0);
+ return drbd_send_command(first_peer_device(device), sock, P_UNPLUG_REMOTE, 0, NULL, 0);
}
-static void re_init_if_first_write(struct drbd_tconn *tconn, unsigned int epoch)
+static void re_init_if_first_write(struct drbd_connection *connection, unsigned int epoch)
{
- if (!tconn->send.seen_any_write_yet) {
- tconn->send.seen_any_write_yet = true;
- tconn->send.current_epoch_nr = epoch;
- tconn->send.current_epoch_writes = 0;
+ if (!connection->send.seen_any_write_yet) {
+ connection->send.seen_any_write_yet = true;
+ connection->send.current_epoch_nr = epoch;
+ connection->send.current_epoch_writes = 0;
}
}
-static void maybe_send_barrier(struct drbd_tconn *tconn, unsigned int epoch)
+static void maybe_send_barrier(struct drbd_connection *connection, unsigned int epoch)
{
/* re-init if first write on this connection */
- if (!tconn->send.seen_any_write_yet)
+ if (!connection->send.seen_any_write_yet)
return;
- if (tconn->send.current_epoch_nr != epoch) {
- if (tconn->send.current_epoch_writes)
- drbd_send_barrier(tconn);
- tconn->send.current_epoch_nr = epoch;
+ if (connection->send.current_epoch_nr != epoch) {
+ if (connection->send.current_epoch_writes)
+ drbd_send_barrier(connection);
+ connection->send.current_epoch_nr = epoch;
}
}
int w_send_out_of_sync(struct drbd_work *w, int cancel)
{
struct drbd_request *req = container_of(w, struct drbd_request, w);
- struct drbd_conf *mdev = w->mdev;
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_device *device = req->device;
+ struct drbd_connection *connection = first_peer_device(device)->connection;
int err;
if (unlikely(cancel)) {
@@ -1335,13 +1343,13 @@ int w_send_out_of_sync(struct drbd_work *w, int cancel)
return 0;
}
- /* this time, no tconn->send.current_epoch_writes++;
+ /* this time, no connection->send.current_epoch_writes++;
* If it was sent, it was the closing barrier for the last
* replicated epoch, before we went into AHEAD mode.
* No more barriers will be sent, until we leave AHEAD mode again. */
- maybe_send_barrier(tconn, req->epoch);
+ maybe_send_barrier(connection, req->epoch);
- err = drbd_send_out_of_sync(mdev, req);
+ err = drbd_send_out_of_sync(first_peer_device(device), req);
req_mod(req, OOS_HANDED_TO_NETWORK);
return err;
@@ -1349,15 +1357,14 @@ int w_send_out_of_sync(struct drbd_work *w, int cancel)
/**
* w_send_dblock() - Worker callback to send a P_DATA packet in order to mirror a write request
- * @mdev: DRBD device.
* @w: work object.
* @cancel: The connection will be closed anyways
*/
int w_send_dblock(struct drbd_work *w, int cancel)
{
struct drbd_request *req = container_of(w, struct drbd_request, w);
- struct drbd_conf *mdev = w->mdev;
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_device *device = req->device;
+ struct drbd_connection *connection = first_peer_device(device)->connection;
int err;
if (unlikely(cancel)) {
@@ -1365,11 +1372,11 @@ int w_send_dblock(struct drbd_work *w, int cancel)
return 0;
}
- re_init_if_first_write(tconn, req->epoch);
- maybe_send_barrier(tconn, req->epoch);
- tconn->send.current_epoch_writes++;
+ re_init_if_first_write(connection, req->epoch);
+ maybe_send_barrier(connection, req->epoch);
+ connection->send.current_epoch_writes++;
- err = drbd_send_dblock(mdev, req);
+ err = drbd_send_dblock(first_peer_device(device), req);
req_mod(req, err ? SEND_FAILED : HANDED_OVER_TO_NETWORK);
return err;
@@ -1377,15 +1384,14 @@ int w_send_dblock(struct drbd_work *w, int cancel)
/**
* w_send_read_req() - Worker callback to send a read request (P_DATA_REQUEST) packet
- * @mdev: DRBD device.
* @w: work object.
* @cancel: The connection will be closed anyways
*/
int w_send_read_req(struct drbd_work *w, int cancel)
{
struct drbd_request *req = container_of(w, struct drbd_request, w);
- struct drbd_conf *mdev = w->mdev;
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_device *device = req->device;
+ struct drbd_connection *connection = first_peer_device(device)->connection;
int err;
if (unlikely(cancel)) {
@@ -1395,9 +1401,9 @@ int w_send_read_req(struct drbd_work *w, int cancel)
/* Even read requests may close a write epoch,
* if there was any yet. */
- maybe_send_barrier(tconn, req->epoch);
+ maybe_send_barrier(connection, req->epoch);
- err = drbd_send_drequest(mdev, P_DATA_REQUEST, req->i.sector, req->i.size,
+ err = drbd_send_drequest(first_peer_device(device), P_DATA_REQUEST, req->i.sector, req->i.size,
(unsigned long)req);
req_mod(req, err ? SEND_FAILED : HANDED_OVER_TO_NETWORK);
@@ -1408,21 +1414,21 @@ int w_send_read_req(struct drbd_work *w, int cancel)
int w_restart_disk_io(struct drbd_work *w, int cancel)
{
struct drbd_request *req = container_of(w, struct drbd_request, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_device *device = req->device;
if (bio_data_dir(req->master_bio) == WRITE && req->rq_state & RQ_IN_ACT_LOG)
- drbd_al_begin_io(mdev, &req->i, false);
+ drbd_al_begin_io(device, &req->i, false);
drbd_req_make_private_bio(req, req->master_bio);
- req->private_bio->bi_bdev = mdev->ldev->backing_bdev;
+ req->private_bio->bi_bdev = device->ldev->backing_bdev;
generic_make_request(req->private_bio);
return 0;
}
-static int _drbd_may_sync_now(struct drbd_conf *mdev)
+static int _drbd_may_sync_now(struct drbd_device *device)
{
- struct drbd_conf *odev = mdev;
+ struct drbd_device *odev = device;
int resync_after;
while (1) {
@@ -1433,7 +1439,7 @@ static int _drbd_may_sync_now(struct drbd_conf *mdev)
rcu_read_unlock();
if (resync_after == -1)
return 1;
- odev = minor_to_mdev(resync_after);
+ odev = minor_to_device(resync_after);
if (!odev)
return 1;
if ((odev->state.conn >= C_SYNC_SOURCE &&
@@ -1446,17 +1452,17 @@ static int _drbd_may_sync_now(struct drbd_conf *mdev)
/**
* _drbd_pause_after() - Pause resync on all devices that may not resync now
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Called from process context only (admin command and after_state_ch).
*/
-static int _drbd_pause_after(struct drbd_conf *mdev)
+static int _drbd_pause_after(struct drbd_device *device)
{
- struct drbd_conf *odev;
+ struct drbd_device *odev;
int i, rv = 0;
rcu_read_lock();
- idr_for_each_entry(&minors, odev, i) {
+ idr_for_each_entry(&drbd_devices, odev, i) {
if (odev->state.conn == C_STANDALONE && odev->state.disk == D_DISKLESS)
continue;
if (!_drbd_may_sync_now(odev))
@@ -1470,17 +1476,17 @@ static int _drbd_pause_after(struct drbd_conf *mdev)
/**
* _drbd_resume_next() - Resume resync on all devices that may resync now
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Called from process context only (admin command and worker).
*/
-static int _drbd_resume_next(struct drbd_conf *mdev)
+static int _drbd_resume_next(struct drbd_device *device)
{
- struct drbd_conf *odev;
+ struct drbd_device *odev;
int i, rv = 0;
rcu_read_lock();
- idr_for_each_entry(&minors, odev, i) {
+ idr_for_each_entry(&drbd_devices, odev, i) {
if (odev->state.conn == C_STANDALONE && odev->state.disk == D_DISKLESS)
continue;
if (odev->state.aftr_isp) {
@@ -1494,24 +1500,24 @@ static int _drbd_resume_next(struct drbd_conf *mdev)
return rv;
}
-void resume_next_sg(struct drbd_conf *mdev)
+void resume_next_sg(struct drbd_device *device)
{
write_lock_irq(&global_state_lock);
- _drbd_resume_next(mdev);
+ _drbd_resume_next(device);
write_unlock_irq(&global_state_lock);
}
-void suspend_other_sg(struct drbd_conf *mdev)
+void suspend_other_sg(struct drbd_device *device)
{
write_lock_irq(&global_state_lock);
- _drbd_pause_after(mdev);
+ _drbd_pause_after(device);
write_unlock_irq(&global_state_lock);
}
/* caller must hold global_state_lock */
-enum drbd_ret_code drbd_resync_after_valid(struct drbd_conf *mdev, int o_minor)
+enum drbd_ret_code drbd_resync_after_valid(struct drbd_device *device, int o_minor)
{
- struct drbd_conf *odev;
+ struct drbd_device *odev;
int resync_after;
if (o_minor == -1)
@@ -1520,9 +1526,9 @@ enum drbd_ret_code drbd_resync_after_valid(struct drbd_conf *mdev, int o_minor)
return ERR_RESYNC_AFTER;
/* check for loops */
- odev = minor_to_mdev(o_minor);
+ odev = minor_to_device(o_minor);
while (1) {
- if (odev == mdev)
+ if (odev == device)
return ERR_RESYNC_AFTER_CYCLE;
/* You are free to depend on diskless, non-existing,
@@ -1542,35 +1548,35 @@ enum drbd_ret_code drbd_resync_after_valid(struct drbd_conf *mdev, int o_minor)
return NO_ERROR;
/* follow the dependency chain */
- odev = minor_to_mdev(resync_after);
+ odev = minor_to_device(resync_after);
}
}
/* caller must hold global_state_lock */
-void drbd_resync_after_changed(struct drbd_conf *mdev)
+void drbd_resync_after_changed(struct drbd_device *device)
{
int changes;
do {
- changes = _drbd_pause_after(mdev);
- changes |= _drbd_resume_next(mdev);
+ changes = _drbd_pause_after(device);
+ changes |= _drbd_resume_next(device);
} while (changes);
}
-void drbd_rs_controller_reset(struct drbd_conf *mdev)
+void drbd_rs_controller_reset(struct drbd_device *device)
{
struct fifo_buffer *plan;
- atomic_set(&mdev->rs_sect_in, 0);
- atomic_set(&mdev->rs_sect_ev, 0);
- mdev->rs_in_flight = 0;
+ atomic_set(&device->rs_sect_in, 0);
+ atomic_set(&device->rs_sect_ev, 0);
+ device->rs_in_flight = 0;
/* Updating the RCU protected object in place is necessary since
this function gets called from atomic context.
It is valid since all other updates also lead to an completely
empty fifo */
rcu_read_lock();
- plan = rcu_dereference(mdev->rs_plan_s);
+ plan = rcu_dereference(device->rs_plan_s);
plan->total = 0;
fifo_set(plan, 0);
rcu_read_unlock();
@@ -1578,101 +1584,104 @@ void drbd_rs_controller_reset(struct drbd_conf *mdev)
void start_resync_timer_fn(unsigned long data)
{
- struct drbd_conf *mdev = (struct drbd_conf *) data;
+ struct drbd_device *device = (struct drbd_device *) data;
- drbd_queue_work(&mdev->tconn->sender_work, &mdev->start_resync_work);
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &device->start_resync_work);
}
int w_start_resync(struct drbd_work *w, int cancel)
{
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_device *device =
+ container_of(w, struct drbd_device, start_resync_work);
- if (atomic_read(&mdev->unacked_cnt) || atomic_read(&mdev->rs_pending_cnt)) {
- dev_warn(DEV, "w_start_resync later...\n");
- mdev->start_resync_timer.expires = jiffies + HZ/10;
- add_timer(&mdev->start_resync_timer);
+ if (atomic_read(&device->unacked_cnt) || atomic_read(&device->rs_pending_cnt)) {
+ drbd_warn(device, "w_start_resync later...\n");
+ device->start_resync_timer.expires = jiffies + HZ/10;
+ add_timer(&device->start_resync_timer);
return 0;
}
- drbd_start_resync(mdev, C_SYNC_SOURCE);
- clear_bit(AHEAD_TO_SYNC_SOURCE, &mdev->flags);
+ drbd_start_resync(device, C_SYNC_SOURCE);
+ clear_bit(AHEAD_TO_SYNC_SOURCE, &device->flags);
return 0;
}
/**
* drbd_start_resync() - Start the resync process
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @side: Either C_SYNC_SOURCE or C_SYNC_TARGET
*
* This function might bring you directly into one of the
* C_PAUSED_SYNC_* states.
*/
-void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side)
+void drbd_start_resync(struct drbd_device *device, enum drbd_conns side)
{
union drbd_state ns;
int r;
- if (mdev->state.conn >= C_SYNC_SOURCE && mdev->state.conn < C_AHEAD) {
- dev_err(DEV, "Resync already running!\n");
+ if (device->state.conn >= C_SYNC_SOURCE && device->state.conn < C_AHEAD) {
+ drbd_err(device, "Resync already running!\n");
return;
}
- if (!test_bit(B_RS_H_DONE, &mdev->flags)) {
+ if (!test_bit(B_RS_H_DONE, &device->flags)) {
if (side == C_SYNC_TARGET) {
/* Since application IO was locked out during C_WF_BITMAP_T and
C_WF_SYNC_UUID we are still unmodified. Before going to C_SYNC_TARGET
we check that we might make the data inconsistent. */
- r = drbd_khelper(mdev, "before-resync-target");
+ r = drbd_khelper(device, "before-resync-target");
r = (r >> 8) & 0xff;
if (r > 0) {
- dev_info(DEV, "before-resync-target handler returned %d, "
+ drbd_info(device, "before-resync-target handler returned %d, "
"dropping connection.\n", r);
- conn_request_state(mdev->tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ conn_request_state(first_peer_device(device)->connection, NS(conn, C_DISCONNECTING), CS_HARD);
return;
}
} else /* C_SYNC_SOURCE */ {
- r = drbd_khelper(mdev, "before-resync-source");
+ r = drbd_khelper(device, "before-resync-source");
r = (r >> 8) & 0xff;
if (r > 0) {
if (r == 3) {
- dev_info(DEV, "before-resync-source handler returned %d, "
+ drbd_info(device, "before-resync-source handler returned %d, "
"ignoring. Old userland tools?", r);
} else {
- dev_info(DEV, "before-resync-source handler returned %d, "
+ drbd_info(device, "before-resync-source handler returned %d, "
"dropping connection.\n", r);
- conn_request_state(mdev->tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ conn_request_state(first_peer_device(device)->connection,
+ NS(conn, C_DISCONNECTING), CS_HARD);
return;
}
}
}
}
- if (current == mdev->tconn->worker.task) {
+ if (current == first_peer_device(device)->connection->worker.task) {
/* The worker should not sleep waiting for state_mutex,
that can take long */
- if (!mutex_trylock(mdev->state_mutex)) {
- set_bit(B_RS_H_DONE, &mdev->flags);
- mdev->start_resync_timer.expires = jiffies + HZ/5;
- add_timer(&mdev->start_resync_timer);
+ if (!mutex_trylock(device->state_mutex)) {
+ set_bit(B_RS_H_DONE, &device->flags);
+ device->start_resync_timer.expires = jiffies + HZ/5;
+ add_timer(&device->start_resync_timer);
return;
}
} else {
- mutex_lock(mdev->state_mutex);
+ mutex_lock(device->state_mutex);
}
- clear_bit(B_RS_H_DONE, &mdev->flags);
+ clear_bit(B_RS_H_DONE, &device->flags);
write_lock_irq(&global_state_lock);
/* Did some connection breakage or IO error race with us? */
- if (mdev->state.conn < C_CONNECTED
- || !get_ldev_if_state(mdev, D_NEGOTIATING)) {
+ if (device->state.conn < C_CONNECTED
+ || !get_ldev_if_state(device, D_NEGOTIATING)) {
write_unlock_irq(&global_state_lock);
- mutex_unlock(mdev->state_mutex);
+ mutex_unlock(device->state_mutex);
return;
}
- ns = drbd_read_state(mdev);
+ ns = drbd_read_state(device);
- ns.aftr_isp = !_drbd_may_sync_now(mdev);
+ ns.aftr_isp = !_drbd_may_sync_now(device);
ns.conn = side;
@@ -1681,43 +1690,43 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side)
else /* side == C_SYNC_SOURCE */
ns.pdsk = D_INCONSISTENT;
- r = __drbd_set_state(mdev, ns, CS_VERBOSE, NULL);
- ns = drbd_read_state(mdev);
+ r = __drbd_set_state(device, ns, CS_VERBOSE, NULL);
+ ns = drbd_read_state(device);
if (ns.conn < C_CONNECTED)
r = SS_UNKNOWN_ERROR;
if (r == SS_SUCCESS) {
- unsigned long tw = drbd_bm_total_weight(mdev);
+ unsigned long tw = drbd_bm_total_weight(device);
unsigned long now = jiffies;
int i;
- mdev->rs_failed = 0;
- mdev->rs_paused = 0;
- mdev->rs_same_csum = 0;
- mdev->rs_last_events = 0;
- mdev->rs_last_sect_ev = 0;
- mdev->rs_total = tw;
- mdev->rs_start = now;
+ device->rs_failed = 0;
+ device->rs_paused = 0;
+ device->rs_same_csum = 0;
+ device->rs_last_events = 0;
+ device->rs_last_sect_ev = 0;
+ device->rs_total = tw;
+ device->rs_start = now;
for (i = 0; i < DRBD_SYNC_MARKS; i++) {
- mdev->rs_mark_left[i] = tw;
- mdev->rs_mark_time[i] = now;
+ device->rs_mark_left[i] = tw;
+ device->rs_mark_time[i] = now;
}
- _drbd_pause_after(mdev);
+ _drbd_pause_after(device);
}
write_unlock_irq(&global_state_lock);
if (r == SS_SUCCESS) {
/* reset rs_last_bcast when a resync or verify is started,
* to deal with potential jiffies wrap. */
- mdev->rs_last_bcast = jiffies - HZ;
+ device->rs_last_bcast = jiffies - HZ;
- dev_info(DEV, "Began resync as %s (will sync %lu KB [%lu bits set]).\n",
+ drbd_info(device, "Began resync as %s (will sync %lu KB [%lu bits set]).\n",
drbd_conn_str(ns.conn),
- (unsigned long) mdev->rs_total << (BM_BLOCK_SHIFT-10),
- (unsigned long) mdev->rs_total);
+ (unsigned long) device->rs_total << (BM_BLOCK_SHIFT-10),
+ (unsigned long) device->rs_total);
if (side == C_SYNC_TARGET)
- mdev->bm_resync_fo = 0;
+ device->bm_resync_fo = 0;
/* Since protocol 96, we must serialize drbd_gen_and_send_sync_uuid
* with w_send_oos, or the sync target will get confused as to
@@ -1726,10 +1735,12 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side)
* drbd_resync_finished from here in that case.
* We drbd_gen_and_send_sync_uuid here for protocol < 96,
* and from after_state_ch otherwise. */
- if (side == C_SYNC_SOURCE && mdev->tconn->agreed_pro_version < 96)
- drbd_gen_and_send_sync_uuid(mdev);
+ if (side == C_SYNC_SOURCE &&
+ first_peer_device(device)->connection->agreed_pro_version < 96)
+ drbd_gen_and_send_sync_uuid(first_peer_device(device));
- if (mdev->tconn->agreed_pro_version < 95 && mdev->rs_total == 0) {
+ if (first_peer_device(device)->connection->agreed_pro_version < 95 &&
+ device->rs_total == 0) {
/* This still has a race (about when exactly the peers
* detect connection loss) that can lead to a full sync
* on next handshake. In 8.3.9 we fixed this with explicit
@@ -1745,33 +1756,33 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side)
int timeo;
rcu_read_lock();
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
timeo = nc->ping_int * HZ + nc->ping_timeo * HZ / 9;
rcu_read_unlock();
schedule_timeout_interruptible(timeo);
}
- drbd_resync_finished(mdev);
+ drbd_resync_finished(device);
}
- drbd_rs_controller_reset(mdev);
- /* ns.conn may already be != mdev->state.conn,
+ drbd_rs_controller_reset(device);
+ /* ns.conn may already be != device->state.conn,
* we may have been paused in between, or become paused until
* the timer triggers.
* No matter, that is handled in resync_timer_fn() */
if (ns.conn == C_SYNC_TARGET)
- mod_timer(&mdev->resync_timer, jiffies);
+ mod_timer(&device->resync_timer, jiffies);
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
}
- put_ldev(mdev);
- mutex_unlock(mdev->state_mutex);
+ put_ldev(device);
+ mutex_unlock(device->state_mutex);
}
/* If the resource already closed the current epoch, but we did not
* (because we have not yet seen new requests), we should send the
* corresponding barrier now. Must be checked within the same spinlock
* that is used to check for new requests. */
-bool need_to_send_barrier(struct drbd_tconn *connection)
+static bool need_to_send_barrier(struct drbd_connection *connection)
{
if (!connection->send.seen_any_write_yet)
return false;
@@ -1795,7 +1806,7 @@ bool need_to_send_barrier(struct drbd_tconn *connection)
return true;
}
-bool dequeue_work_batch(struct drbd_work_queue *queue, struct list_head *work_list)
+static bool dequeue_work_batch(struct drbd_work_queue *queue, struct list_head *work_list)
{
spin_lock_irq(&queue->q_lock);
list_splice_init(&queue->q, work_list);
@@ -1803,7 +1814,7 @@ bool dequeue_work_batch(struct drbd_work_queue *queue, struct list_head *work_li
return !list_empty(work_list);
}
-bool dequeue_work_item(struct drbd_work_queue *queue, struct list_head *work_list)
+static bool dequeue_work_item(struct drbd_work_queue *queue, struct list_head *work_list)
{
spin_lock_irq(&queue->q_lock);
if (!list_empty(&queue->q))
@@ -1812,7 +1823,7 @@ bool dequeue_work_item(struct drbd_work_queue *queue, struct list_head *work_lis
return !list_empty(work_list);
}
-void wait_for_work(struct drbd_tconn *connection, struct list_head *work_list)
+static void wait_for_work(struct drbd_connection *connection, struct list_head *work_list)
{
DEFINE_WAIT(wait);
struct net_conf *nc;
@@ -1842,7 +1853,7 @@ void wait_for_work(struct drbd_tconn *connection, struct list_head *work_list)
for (;;) {
int send_barrier;
prepare_to_wait(&connection->sender_work.q_wait, &wait, TASK_INTERRUPTIBLE);
- spin_lock_irq(&connection->req_lock);
+ spin_lock_irq(&connection->resource->req_lock);
spin_lock(&connection->sender_work.q_lock); /* FIXME get rid of this one? */
/* dequeue single item only,
* we still use drbd_queue_work_front() in some places */
@@ -1850,11 +1861,11 @@ void wait_for_work(struct drbd_tconn *connection, struct list_head *work_list)
list_move(connection->sender_work.q.next, work_list);
spin_unlock(&connection->sender_work.q_lock); /* FIXME get rid of this one? */
if (!list_empty(work_list) || signal_pending(current)) {
- spin_unlock_irq(&connection->req_lock);
+ spin_unlock_irq(&connection->resource->req_lock);
break;
}
send_barrier = need_to_send_barrier(connection);
- spin_unlock_irq(&connection->req_lock);
+ spin_unlock_irq(&connection->resource->req_lock);
if (send_barrier) {
drbd_send_barrier(connection);
connection->send.current_epoch_nr++;
@@ -1883,9 +1894,9 @@ void wait_for_work(struct drbd_tconn *connection, struct list_head *work_list)
int drbd_worker(struct drbd_thread *thi)
{
- struct drbd_tconn *tconn = thi->tconn;
+ struct drbd_connection *connection = thi->connection;
struct drbd_work *w = NULL;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
LIST_HEAD(work_list);
int vnr;
@@ -1895,12 +1906,12 @@ int drbd_worker(struct drbd_thread *thi)
/* as long as we use drbd_queue_work_front(),
* we may only dequeue single work items here, not batches. */
if (list_empty(&work_list))
- wait_for_work(tconn, &work_list);
+ wait_for_work(connection, &work_list);
if (signal_pending(current)) {
flush_signals(current);
if (get_t_state(thi) == RUNNING) {
- conn_warn(tconn, "Worker got an unexpected signal\n");
+ drbd_warn(connection, "Worker got an unexpected signal\n");
continue;
}
break;
@@ -1912,10 +1923,10 @@ int drbd_worker(struct drbd_thread *thi)
while (!list_empty(&work_list)) {
w = list_first_entry(&work_list, struct drbd_work, list);
list_del_init(&w->list);
- if (w->cb(w, tconn->cstate < C_WF_REPORT_PARAMS) == 0)
+ if (w->cb(w, connection->cstate < C_WF_REPORT_PARAMS) == 0)
continue;
- if (tconn->cstate >= C_WF_REPORT_PARAMS)
- conn_request_state(tconn, NS(conn, C_NETWORK_FAILURE), CS_HARD);
+ if (connection->cstate >= C_WF_REPORT_PARAMS)
+ conn_request_state(connection, NS(conn, C_NETWORK_FAILURE), CS_HARD);
}
}
@@ -1925,16 +1936,17 @@ int drbd_worker(struct drbd_thread *thi)
list_del_init(&w->list);
w->cb(w, 1);
}
- dequeue_work_batch(&tconn->sender_work, &work_list);
+ dequeue_work_batch(&connection->sender_work, &work_list);
} while (!list_empty(&work_list));
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- D_ASSERT(mdev->state.disk == D_DISKLESS && mdev->state.conn == C_STANDALONE);
- kref_get(&mdev->kref);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ D_ASSERT(device, device->state.disk == D_DISKLESS && device->state.conn == C_STANDALONE);
+ kref_get(&device->kref);
rcu_read_unlock();
- drbd_mdev_cleanup(mdev);
- kref_put(&mdev->kref, &drbd_minor_destroy);
+ drbd_device_cleanup(device);
+ kref_put(&device->kref, drbd_destroy_device);
rcu_read_lock();
}
rcu_read_unlock();
diff --git a/drivers/block/drbd/drbd_wrappers.h b/drivers/block/drbd/drbd_wrappers.h
index 328f18e4b4ee..3db9ebaf64f6 100644
--- a/drivers/block/drbd/drbd_wrappers.h
+++ b/drivers/block/drbd/drbd_wrappers.h
@@ -9,12 +9,12 @@
extern char *drbd_sec_holder;
/* sets the number of 512 byte sectors of our virtual device */
-static inline void drbd_set_my_capacity(struct drbd_conf *mdev,
+static inline void drbd_set_my_capacity(struct drbd_device *device,
sector_t size)
{
- /* set_capacity(mdev->this_bdev->bd_disk, size); */
- set_capacity(mdev->vdisk, size);
- mdev->this_bdev->bd_inode->i_size = (loff_t)size << 9;
+ /* set_capacity(device->this_bdev->bd_disk, size); */
+ set_capacity(device->vdisk, size);
+ device->this_bdev->bd_inode->i_size = (loff_t)size << 9;
}
#define drbd_bio_uptodate(bio) bio_flagged(bio, BIO_UPTODATE)
@@ -27,20 +27,20 @@ extern void drbd_request_endio(struct bio *bio, int error);
/*
* used to submit our private bio
*/
-static inline void drbd_generic_make_request(struct drbd_conf *mdev,
+static inline void drbd_generic_make_request(struct drbd_device *device,
int fault_type, struct bio *bio)
{
__release(local);
if (!bio->bi_bdev) {
printk(KERN_ERR "drbd%d: drbd_generic_make_request: "
"bio->bi_bdev == NULL\n",
- mdev_to_minor(mdev));
+ device_to_minor(device));
dump_stack();
bio_endio(bio, -ENODEV);
return;
}
- if (drbd_insert_fault(mdev, fault_type))
+ if (drbd_insert_fault(device, fault_type))
bio_endio(bio, -EIO);
else
generic_make_request(bio);
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 2023043ce7c0..8f5565bf34cd 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -961,17 +961,31 @@ static void empty(void)
{
}
-static DECLARE_WORK(floppy_work, NULL);
+static void (*floppy_work_fn)(void);
+
+static void floppy_work_workfn(struct work_struct *work)
+{
+ floppy_work_fn();
+}
+
+static DECLARE_WORK(floppy_work, floppy_work_workfn);
static void schedule_bh(void (*handler)(void))
{
WARN_ON(work_pending(&floppy_work));
- PREPARE_WORK(&floppy_work, (work_func_t)handler);
+ floppy_work_fn = handler;
queue_work(floppy_wq, &floppy_work);
}
-static DECLARE_DELAYED_WORK(fd_timer, NULL);
+static void (*fd_timer_fn)(void) = NULL;
+
+static void fd_timer_workfn(struct work_struct *work)
+{
+ fd_timer_fn();
+}
+
+static DECLARE_DELAYED_WORK(fd_timer, fd_timer_workfn);
static void cancel_activity(void)
{
@@ -982,7 +996,7 @@ static void cancel_activity(void)
/* this function makes sure that the disk stays in the drive during the
* transfer */
-static void fd_watchdog(struct work_struct *arg)
+static void fd_watchdog(void)
{
debug_dcl(DP->flags, "calling disk change from watchdog\n");
@@ -993,7 +1007,7 @@ static void fd_watchdog(struct work_struct *arg)
reset_fdc();
} else {
cancel_delayed_work(&fd_timer);
- PREPARE_DELAYED_WORK(&fd_timer, fd_watchdog);
+ fd_timer_fn = fd_watchdog;
queue_delayed_work(floppy_wq, &fd_timer, HZ / 10);
}
}
@@ -1005,7 +1019,8 @@ static void main_command_interrupt(void)
}
/* waits for a delay (spinup or select) to pass */
-static int fd_wait_for_completion(unsigned long expires, work_func_t function)
+static int fd_wait_for_completion(unsigned long expires,
+ void (*function)(void))
{
if (FDCS->reset) {
reset_fdc(); /* do the reset during sleep to win time
@@ -1016,7 +1031,7 @@ static int fd_wait_for_completion(unsigned long expires, work_func_t function)
if (time_before(jiffies, expires)) {
cancel_delayed_work(&fd_timer);
- PREPARE_DELAYED_WORK(&fd_timer, function);
+ fd_timer_fn = function;
queue_delayed_work(floppy_wq, &fd_timer, expires - jiffies);
return 1;
}
@@ -1334,8 +1349,7 @@ static int fdc_dtr(void)
* Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
*/
FDCS->dtr = raw_cmd->rate & 3;
- return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
- (work_func_t)floppy_ready);
+ return fd_wait_for_completion(jiffies + 2UL * HZ / 100, floppy_ready);
} /* fdc_dtr */
static void tell_sector(void)
@@ -1440,7 +1454,7 @@ static void setup_rw_floppy(void)
int flags;
int dflags;
unsigned long ready_date;
- work_func_t function;
+ void (*function)(void);
flags = raw_cmd->flags;
if (flags & (FD_RAW_READ | FD_RAW_WRITE))
@@ -1454,9 +1468,9 @@ static void setup_rw_floppy(void)
*/
if (time_after(ready_date, jiffies + DP->select_delay)) {
ready_date -= DP->select_delay;
- function = (work_func_t)floppy_start;
+ function = floppy_start;
} else
- function = (work_func_t)setup_rw_floppy;
+ function = setup_rw_floppy;
/* wait until the floppy is spinning fast enough */
if (fd_wait_for_completion(ready_date, function))
@@ -1486,7 +1500,7 @@ static void setup_rw_floppy(void)
inr = result();
cont->interrupt();
} else if (flags & FD_RAW_NEED_DISK)
- fd_watchdog(NULL);
+ fd_watchdog();
}
static int blind_seek;
@@ -1863,7 +1877,7 @@ static int start_motor(void (*function)(void))
/* wait_for_completion also schedules reset if needed. */
return fd_wait_for_completion(DRS->select_date + DP->select_delay,
- (work_func_t)function);
+ function);
}
static void floppy_ready(void)
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index 516026954be6..59c5abe32f06 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -252,38 +252,45 @@ static void mtip_async_complete(struct mtip_port *port,
void *data,
int status)
{
- struct mtip_cmd *command;
+ struct mtip_cmd *cmd;
struct driver_data *dd = data;
- int cb_status = status ? -EIO : 0;
+ int unaligned, cb_status = status ? -EIO : 0;
+ void (*func)(void *, int);
if (unlikely(!dd) || unlikely(!port))
return;
- command = &port->commands[tag];
+ cmd = &port->commands[tag];
if (unlikely(status == PORT_IRQ_TF_ERR)) {
dev_warn(&port->dd->pdev->dev,
"Command tag %d failed due to TFE\n", tag);
}
+ /* Clear the active flag */
+ atomic_set(&port->commands[tag].active, 0);
+
/* Upper layer callback */
- if (likely(command->async_callback))
- command->async_callback(command->async_data, cb_status);
+ func = cmd->async_callback;
+ if (likely(func && cmpxchg(&cmd->async_callback, func, 0) == func)) {
- command->async_callback = NULL;
- command->comp_func = NULL;
+ /* Unmap the DMA scatter list entries */
+ dma_unmap_sg(&dd->pdev->dev,
+ cmd->sg,
+ cmd->scatter_ents,
+ cmd->direction);
- /* Unmap the DMA scatter list entries */
- dma_unmap_sg(&dd->pdev->dev,
- command->sg,
- command->scatter_ents,
- command->direction);
+ func(cmd->async_data, cb_status);
+ unaligned = cmd->unaligned;
- /* Clear the allocated and active bits for the command */
- atomic_set(&port->commands[tag].active, 0);
- release_slot(port, tag);
+ /* Clear the allocated bit for the command */
+ release_slot(port, tag);
- up(&port->cmd_slot);
+ if (unlikely(unaligned))
+ up(&port->cmd_slot_unal);
+ else
+ up(&port->cmd_slot);
+ }
}
/*
@@ -660,11 +667,12 @@ static void mtip_timeout_function(unsigned long int data)
{
struct mtip_port *port = (struct mtip_port *) data;
struct host_to_dev_fis *fis;
- struct mtip_cmd *command;
- int tag, cmdto_cnt = 0;
+ struct mtip_cmd *cmd;
+ int unaligned, tag, cmdto_cnt = 0;
unsigned int bit, group;
unsigned int num_command_slots;
unsigned long to, tagaccum[SLOTBITS_IN_LONGS];
+ void (*func)(void *, int);
if (unlikely(!port))
return;
@@ -694,8 +702,8 @@ static void mtip_timeout_function(unsigned long int data)
group = tag >> 5;
bit = tag & 0x1F;
- command = &port->commands[tag];
- fis = (struct host_to_dev_fis *) command->command;
+ cmd = &port->commands[tag];
+ fis = (struct host_to_dev_fis *) cmd->command;
set_bit(tag, tagaccum);
cmdto_cnt++;
@@ -709,27 +717,30 @@ static void mtip_timeout_function(unsigned long int data)
*/
writel(1 << bit, port->completed[group]);
- /* Call the async completion callback. */
- if (likely(command->async_callback))
- command->async_callback(command->async_data,
- -EIO);
- command->async_callback = NULL;
- command->comp_func = NULL;
+ /* Clear the active flag for the command */
+ atomic_set(&port->commands[tag].active, 0);
- /* Unmap the DMA scatter list entries */
- dma_unmap_sg(&port->dd->pdev->dev,
- command->sg,
- command->scatter_ents,
- command->direction);
+ func = cmd->async_callback;
+ if (func &&
+ cmpxchg(&cmd->async_callback, func, 0) == func) {
- /*
- * Clear the allocated bit and active tag for the
- * command.
- */
- atomic_set(&port->commands[tag].active, 0);
- release_slot(port, tag);
+ /* Unmap the DMA scatter list entries */
+ dma_unmap_sg(&port->dd->pdev->dev,
+ cmd->sg,
+ cmd->scatter_ents,
+ cmd->direction);
- up(&port->cmd_slot);
+ func(cmd->async_data, -EIO);
+ unaligned = cmd->unaligned;
+
+ /* Clear the allocated bit for the command. */
+ release_slot(port, tag);
+
+ if (unaligned)
+ up(&port->cmd_slot_unal);
+ else
+ up(&port->cmd_slot);
+ }
}
}
@@ -4213,6 +4224,7 @@ skip_create_disk:
blk_queue_max_hw_sectors(dd->queue, 0xffff);
blk_queue_max_segment_size(dd->queue, 0x400000);
blk_queue_io_min(dd->queue, 4096);
+ blk_queue_bounce_limit(dd->queue, dd->pdev->dma_mask);
/*
* write back cache is not supported in the device. FUA depends on
@@ -4498,7 +4510,7 @@ static int mtip_pci_probe(struct pci_dev *pdev,
}
dev_info(&pdev->dev, "NUMA node %d (closest: %d,%d, probe on %d:%d)\n",
my_node, pcibus_to_node(pdev->bus), dev_to_node(&pdev->dev),
- cpu_to_node(smp_processor_id()), smp_processor_id());
+ cpu_to_node(raw_smp_processor_id()), raw_smp_processor_id());
dd = kzalloc_node(sizeof(struct driver_data), GFP_KERNEL, my_node);
if (dd == NULL) {
@@ -4615,7 +4627,7 @@ static int mtip_pci_probe(struct pci_dev *pdev,
if (rv) {
dev_warn(&pdev->dev,
"Unable to enable MSI interrupt.\n");
- goto block_initialize_err;
+ goto msi_initialize_err;
}
/* Initialize the block layer. */
@@ -4645,6 +4657,8 @@ static int mtip_pci_probe(struct pci_dev *pdev,
block_initialize_err:
pci_disable_msi(pdev);
+
+msi_initialize_err:
if (dd->isr_workq) {
flush_workqueue(dd->isr_workq);
destroy_workqueue(dd->isr_workq);
diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h
index b52e9a6d6aad..ffb955e7ccb9 100644
--- a/drivers/block/mtip32xx/mtip32xx.h
+++ b/drivers/block/mtip32xx/mtip32xx.h
@@ -53,7 +53,7 @@
#define MTIP_FTL_REBUILD_TIMEOUT_MS 2400000
/* unaligned IO handling */
-#define MTIP_MAX_UNALIGNED_SLOTS 8
+#define MTIP_MAX_UNALIGNED_SLOTS 2
/* Macro to extract the tag bit number from a tag value. */
#define MTIP_TAG_BIT(tag) (tag & 0x1F)
@@ -92,7 +92,7 @@
/* Driver name and version strings */
#define MTIP_DRV_NAME "mtip32xx"
-#define MTIP_DRV_VERSION "1.3.0"
+#define MTIP_DRV_VERSION "1.3.1"
/* Maximum number of minor device numbers per device. */
#define MTIP_MAX_MINORS 16
diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c
index 3107282a9741..091b9ea14feb 100644
--- a/drivers/block/null_blk.c
+++ b/drivers/block/null_blk.c
@@ -60,7 +60,9 @@ enum {
NULL_IRQ_NONE = 0,
NULL_IRQ_SOFTIRQ = 1,
NULL_IRQ_TIMER = 2,
+};
+enum {
NULL_Q_BIO = 0,
NULL_Q_RQ = 1,
NULL_Q_MQ = 2,
@@ -172,18 +174,20 @@ static struct nullb_cmd *alloc_cmd(struct nullb_queue *nq, int can_wait)
static void end_cmd(struct nullb_cmd *cmd)
{
- if (cmd->rq) {
- if (queue_mode == NULL_Q_MQ)
- blk_mq_end_io(cmd->rq, 0);
- else {
- INIT_LIST_HEAD(&cmd->rq->queuelist);
- blk_end_request_all(cmd->rq, 0);
- }
- } else if (cmd->bio)
+ switch (queue_mode) {
+ case NULL_Q_MQ:
+ blk_mq_end_io(cmd->rq, 0);
+ return;
+ case NULL_Q_RQ:
+ INIT_LIST_HEAD(&cmd->rq->queuelist);
+ blk_end_request_all(cmd->rq, 0);
+ break;
+ case NULL_Q_BIO:
bio_endio(cmd->bio, 0);
+ break;
+ }
- if (queue_mode != NULL_Q_MQ)
- free_cmd(cmd);
+ free_cmd(cmd);
}
static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer)
@@ -195,6 +199,7 @@ static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer)
cq = &per_cpu(completion_queues, smp_processor_id());
while ((entry = llist_del_all(&cq->list)) != NULL) {
+ entry = llist_reverse_order(entry);
do {
cmd = container_of(entry, struct nullb_cmd, ll_list);
end_cmd(cmd);
@@ -221,61 +226,31 @@ static void null_cmd_end_timer(struct nullb_cmd *cmd)
static void null_softirq_done_fn(struct request *rq)
{
- blk_end_request_all(rq, 0);
-}
-
-#ifdef CONFIG_SMP
-
-static void null_ipi_cmd_end_io(void *data)
-{
- struct completion_queue *cq;
- struct llist_node *entry, *next;
- struct nullb_cmd *cmd;
-
- cq = &per_cpu(completion_queues, smp_processor_id());
-
- entry = llist_del_all(&cq->list);
-
- while (entry) {
- next = entry->next;
- cmd = llist_entry(entry, struct nullb_cmd, ll_list);
- end_cmd(cmd);
- entry = next;
- }
-}
-
-static void null_cmd_end_ipi(struct nullb_cmd *cmd)
-{
- struct call_single_data *data = &cmd->csd;
- int cpu = get_cpu();
- struct completion_queue *cq = &per_cpu(completion_queues, cpu);
-
- cmd->ll_list.next = NULL;
-
- if (llist_add(&cmd->ll_list, &cq->list)) {
- data->func = null_ipi_cmd_end_io;
- data->flags = 0;
- __smp_call_function_single(cpu, data, 0);
- }
-
- put_cpu();
+ end_cmd(rq->special);
}
-#endif /* CONFIG_SMP */
-
static inline void null_handle_cmd(struct nullb_cmd *cmd)
{
/* Complete IO by inline, softirq or timer */
switch (irqmode) {
- case NULL_IRQ_NONE:
- end_cmd(cmd);
- break;
case NULL_IRQ_SOFTIRQ:
-#ifdef CONFIG_SMP
- null_cmd_end_ipi(cmd);
-#else
+ switch (queue_mode) {
+ case NULL_Q_MQ:
+ blk_mq_complete_request(cmd->rq);
+ break;
+ case NULL_Q_RQ:
+ blk_complete_request(cmd->rq);
+ break;
+ case NULL_Q_BIO:
+ /*
+ * XXX: no proper submitting cpu information available.
+ */
+ end_cmd(cmd);
+ break;
+ }
+ break;
+ case NULL_IRQ_NONE:
end_cmd(cmd);
-#endif
break;
case NULL_IRQ_TIMER:
null_cmd_end_timer(cmd);
@@ -411,6 +386,7 @@ static struct blk_mq_ops null_mq_ops = {
.queue_rq = null_queue_rq,
.map_queue = blk_mq_map_queue,
.init_hctx = null_init_hctx,
+ .complete = null_softirq_done_fn,
};
static struct blk_mq_reg null_mq_reg = {
@@ -609,13 +585,6 @@ static int __init null_init(void)
{
unsigned int i;
-#if !defined(CONFIG_SMP)
- if (irqmode == NULL_IRQ_SOFTIRQ) {
- pr_warn("null_blk: softirq completions not available.\n");
- pr_warn("null_blk: using direct completions.\n");
- irqmode = NULL_IRQ_NONE;
- }
-#endif
if (bs > PAGE_SIZE) {
pr_warn("null_blk: invalid block size\n");
pr_warn("null_blk: defaults block size to %lu\n", PAGE_SIZE);
diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c
index 51824d1f23ea..da085ff10d25 100644
--- a/drivers/block/nvme-core.c
+++ b/drivers/block/nvme-core.c
@@ -993,7 +993,7 @@ static void nvme_abort_cmd(int cmdid, struct nvme_queue *nvmeq)
dev_warn(&dev->pci_dev->dev,
"I/O %d QID %d timeout, reset controller\n", cmdid,
nvmeq->qid);
- PREPARE_WORK(&dev->reset_work, nvme_reset_failed_dev);
+ dev->reset_workfn = nvme_reset_failed_dev;
queue_work(nvme_workq, &dev->reset_work);
return;
}
@@ -1696,8 +1696,7 @@ static int nvme_kthread(void *data)
list_del_init(&dev->node);
dev_warn(&dev->pci_dev->dev,
"Failed status, reset controller\n");
- PREPARE_WORK(&dev->reset_work,
- nvme_reset_failed_dev);
+ dev->reset_workfn = nvme_reset_failed_dev;
queue_work(nvme_workq, &dev->reset_work);
continue;
}
@@ -1837,31 +1836,16 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
/* Deregister the admin queue's interrupt */
free_irq(dev->entry[0].vector, adminq);
- vecs = nr_io_queues;
- for (i = 0; i < vecs; i++)
+ for (i = 0; i < nr_io_queues; i++)
dev->entry[i].entry = i;
- for (;;) {
- result = pci_enable_msix(pdev, dev->entry, vecs);
- if (result <= 0)
- break;
- vecs = result;
- }
-
- if (result < 0) {
- vecs = nr_io_queues;
- if (vecs > 32)
- vecs = 32;
- for (;;) {
- result = pci_enable_msi_block(pdev, vecs);
- if (result == 0) {
- for (i = 0; i < vecs; i++)
- dev->entry[i].vector = i + pdev->irq;
- break;
- } else if (result < 0) {
- vecs = 1;
- break;
- }
- vecs = result;
+ vecs = pci_enable_msix_range(pdev, dev->entry, 1, nr_io_queues);
+ if (vecs < 0) {
+ vecs = pci_enable_msi_range(pdev, 1, min(nr_io_queues, 32));
+ if (vecs < 0) {
+ vecs = 1;
+ } else {
+ for (i = 0; i < vecs; i++)
+ dev->entry[i].vector = i + pdev->irq;
}
}
@@ -2406,7 +2390,7 @@ static int nvme_dev_resume(struct nvme_dev *dev)
return ret;
if (ret == -EBUSY) {
spin_lock(&dev_list_lock);
- PREPARE_WORK(&dev->reset_work, nvme_remove_disks);
+ dev->reset_workfn = nvme_remove_disks;
queue_work(nvme_workq, &dev->reset_work);
spin_unlock(&dev_list_lock);
}
@@ -2435,6 +2419,12 @@ static void nvme_reset_failed_dev(struct work_struct *ws)
nvme_dev_reset(dev);
}
+static void nvme_reset_workfn(struct work_struct *work)
+{
+ struct nvme_dev *dev = container_of(work, struct nvme_dev, reset_work);
+ dev->reset_workfn(work);
+}
+
static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
int result = -ENOMEM;
@@ -2453,7 +2443,8 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto free;
INIT_LIST_HEAD(&dev->namespaces);
- INIT_WORK(&dev->reset_work, nvme_reset_failed_dev);
+ dev->reset_workfn = nvme_reset_failed_dev;
+ INIT_WORK(&dev->reset_work, nvme_reset_workfn);
dev->pci_dev = pdev;
pci_set_drvdata(pdev, dev);
result = nvme_set_instance(dev);
@@ -2553,7 +2544,7 @@ static int nvme_resume(struct device *dev)
struct nvme_dev *ndev = pci_get_drvdata(pdev);
if (nvme_dev_resume(ndev) && !work_busy(&ndev->reset_work)) {
- PREPARE_WORK(&ndev->reset_work, nvme_reset_failed_dev);
+ ndev->reset_workfn = nvme_reset_failed_dev;
queue_work(nvme_workq, &ndev->reset_work);
}
return 0;
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index b365e0dfccb6..34898d53395b 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -2109,7 +2109,6 @@ static void rbd_img_obj_callback(struct rbd_obj_request *obj_request)
rbd_assert(img_request->obj_request_count > 0);
rbd_assert(which != BAD_WHICH);
rbd_assert(which < img_request->obj_request_count);
- rbd_assert(which >= img_request->next_completion);
spin_lock_irq(&img_request->completion_lock);
if (which != img_request->next_completion)
diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c
index eb6e1e0e8db2..a69dd93d1bd5 100644
--- a/drivers/block/skd_main.c
+++ b/drivers/block/skd_main.c
@@ -3910,18 +3910,22 @@ static void skd_release_msix(struct skd_device *skdev)
struct skd_msix_entry *qentry;
int i;
- if (skdev->msix_entries == NULL)
- return;
- for (i = 0; i < skdev->msix_count; i++) {
- qentry = &skdev->msix_entries[i];
- skdev = qentry->rsp;
+ if (skdev->msix_entries) {
+ for (i = 0; i < skdev->msix_count; i++) {
+ qentry = &skdev->msix_entries[i];
+ skdev = qentry->rsp;
+
+ if (qentry->have_irq)
+ devm_free_irq(&skdev->pdev->dev,
+ qentry->vector, qentry->rsp);
+ }
- if (qentry->have_irq)
- devm_free_irq(&skdev->pdev->dev,
- qentry->vector, qentry->rsp);
+ kfree(skdev->msix_entries);
}
- pci_disable_msix(skdev->pdev);
- kfree(skdev->msix_entries);
+
+ if (skdev->msix_count)
+ pci_disable_msix(skdev->pdev);
+
skdev->msix_count = 0;
skdev->msix_entries = NULL;
}
@@ -3929,12 +3933,10 @@ static void skd_release_msix(struct skd_device *skdev)
static int skd_acquire_msix(struct skd_device *skdev)
{
int i, rc;
- struct pci_dev *pdev;
- struct msix_entry *entries = NULL;
+ struct pci_dev *pdev = skdev->pdev;
+ struct msix_entry *entries;
struct skd_msix_entry *qentry;
- pdev = skdev->pdev;
- skdev->msix_count = SKD_MAX_MSIX_COUNT;
entries = kzalloc(sizeof(struct msix_entry) * SKD_MAX_MSIX_COUNT,
GFP_KERNEL);
if (!entries)
@@ -3943,40 +3945,26 @@ static int skd_acquire_msix(struct skd_device *skdev)
for (i = 0; i < SKD_MAX_MSIX_COUNT; i++)
entries[i].entry = i;
- rc = pci_enable_msix(pdev, entries, SKD_MAX_MSIX_COUNT);
- if (rc < 0)
+ rc = pci_enable_msix_range(pdev, entries,
+ SKD_MIN_MSIX_COUNT, SKD_MAX_MSIX_COUNT);
+ if (rc < 0) {
+ pr_err("(%s): failed to enable MSI-X %d\n",
+ skd_name(skdev), rc);
goto msix_out;
- if (rc) {
- if (rc < SKD_MIN_MSIX_COUNT) {
- pr_err("(%s): failed to enable MSI-X %d\n",
- skd_name(skdev), rc);
- goto msix_out;
- }
- pr_debug("%s:%s:%d %s: <%s> allocated %d MSI-X vectors\n",
- skdev->name, __func__, __LINE__,
- pci_name(pdev), skdev->name, rc);
-
- skdev->msix_count = rc;
- rc = pci_enable_msix(pdev, entries, skdev->msix_count);
- if (rc) {
- pr_err("(%s): failed to enable MSI-X "
- "support (%d) %d\n",
- skd_name(skdev), skdev->msix_count, rc);
- goto msix_out;
- }
}
+
+ skdev->msix_count = rc;
skdev->msix_entries = kzalloc(sizeof(struct skd_msix_entry) *
skdev->msix_count, GFP_KERNEL);
if (!skdev->msix_entries) {
rc = -ENOMEM;
- skdev->msix_count = 0;
pr_err("(%s): msix table allocation error\n",
skd_name(skdev));
goto msix_out;
}
- qentry = skdev->msix_entries;
for (i = 0; i < skdev->msix_count; i++) {
+ qentry = &skdev->msix_entries[i];
qentry->vector = entries[i].vector;
qentry->entry = entries[i].entry;
qentry->rsp = NULL;
@@ -3985,11 +3973,10 @@ static int skd_acquire_msix(struct skd_device *skdev)
skdev->name, __func__, __LINE__,
pci_name(pdev), skdev->name,
i, qentry->vector, qentry->entry);
- qentry++;
}
/* Enable MSI-X vectors for the base queue */
- for (i = 0; i < SKD_MAX_MSIX_COUNT; i++) {
+ for (i = 0; i < skdev->msix_count; i++) {
qentry = &skdev->msix_entries[i];
snprintf(qentry->isr_name, sizeof(qentry->isr_name),
"%s%d-msix %s", DRV_NAME, skdev->devno,
@@ -4045,8 +4032,8 @@ RETRY_IRQ_TYPE:
case SKD_IRQ_MSI:
snprintf(skdev->isr_name, sizeof(skdev->isr_name), "%s%d-msi",
DRV_NAME, skdev->devno);
- rc = pci_enable_msi(pdev);
- if (!rc) {
+ rc = pci_enable_msi_range(pdev, 1, 1);
+ if (rc > 0) {
rc = devm_request_irq(&pdev->dev, pdev->irq, skd_isr, 0,
skdev->isr_name, skdev);
if (rc) {
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index 20e061c3e023..c74f7b56e7c4 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -30,6 +30,7 @@
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/spinlock.h>
+#include <linux/wait.h>
#include <asm/io.h>
#include <asm/dbdma.h>
#include <asm/prom.h>
@@ -840,14 +841,17 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state,
spin_lock_irqsave(&swim3_lock, flags);
if (fs->state != idle && fs->state != available) {
++fs->wanted;
- while (fs->state != available) {
+ /* this will enable irqs in order to sleep */
+ if (!interruptible)
+ wait_event_lock_irq(fs->wait,
+ fs->state == available,
+ swim3_lock);
+ else if (wait_event_interruptible_lock_irq(fs->wait,
+ fs->state == available,
+ swim3_lock)) {
+ --fs->wanted;
spin_unlock_irqrestore(&swim3_lock, flags);
- if (interruptible && signal_pending(current)) {
- --fs->wanted;
- return -EINTR;
- }
- interruptible_sleep_on(&fs->wait);
- spin_lock_irqsave(&swim3_lock, flags);
+ return -EINTR;
}
--fs->wanted;
}
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 6a680d4de7f1..6d8a87f252de 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -110,9 +110,9 @@ static int __virtblk_add_req(struct virtqueue *vq,
return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC);
}
-static inline void virtblk_request_done(struct virtblk_req *vbr)
+static inline void virtblk_request_done(struct request *req)
{
- struct request *req = vbr->req;
+ struct virtblk_req *vbr = req->special;
int error = virtblk_result(vbr);
if (req->cmd_type == REQ_TYPE_BLOCK_PC) {
@@ -138,7 +138,7 @@ static void virtblk_done(struct virtqueue *vq)
do {
virtqueue_disable_cb(vq);
while ((vbr = virtqueue_get_buf(vblk->vq, &len)) != NULL) {
- virtblk_request_done(vbr);
+ blk_mq_complete_request(vbr->req);
req_done = true;
}
if (unlikely(virtqueue_is_broken(vq)))
@@ -158,6 +158,7 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req)
unsigned long flags;
unsigned int num;
const bool last = (req->cmd_flags & REQ_END) != 0;
+ int err;
BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems);
@@ -198,11 +199,16 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req)
}
spin_lock_irqsave(&vblk->vq_lock, flags);
- if (__virtblk_add_req(vblk->vq, vbr, vbr->sg, num) < 0) {
+ err = __virtblk_add_req(vblk->vq, vbr, vbr->sg, num);
+ if (err) {
virtqueue_kick(vblk->vq);
spin_unlock_irqrestore(&vblk->vq_lock, flags);
blk_mq_stop_hw_queue(hctx);
- return BLK_MQ_RQ_QUEUE_BUSY;
+ /* Out of mem doesn't actually happen, since we fall back
+ * to direct descriptors */
+ if (err == -ENOMEM || err == -ENOSPC)
+ return BLK_MQ_RQ_QUEUE_BUSY;
+ return BLK_MQ_RQ_QUEUE_ERROR;
}
if (last)
@@ -479,23 +485,26 @@ static struct blk_mq_ops virtio_mq_ops = {
.map_queue = blk_mq_map_queue,
.alloc_hctx = blk_mq_alloc_single_hw_queue,
.free_hctx = blk_mq_free_single_hw_queue,
+ .complete = virtblk_request_done,
};
static struct blk_mq_reg virtio_mq_reg = {
.ops = &virtio_mq_ops,
.nr_hw_queues = 1,
- .queue_depth = 64,
+ .queue_depth = 0, /* Set in virtblk_probe */
.numa_node = NUMA_NO_NODE,
.flags = BLK_MQ_F_SHOULD_MERGE,
};
+module_param_named(queue_depth, virtio_mq_reg.queue_depth, uint, 0444);
-static void virtblk_init_vbr(void *data, struct blk_mq_hw_ctx *hctx,
+static int virtblk_init_vbr(void *data, struct blk_mq_hw_ctx *hctx,
struct request *rq, unsigned int nr)
{
struct virtio_blk *vblk = data;
struct virtblk_req *vbr = rq->special;
sg_init_table(vbr->sg, vblk->sg_elems);
+ return 0;
}
static int virtblk_probe(struct virtio_device *vdev)
@@ -551,6 +560,13 @@ static int virtblk_probe(struct virtio_device *vdev)
goto out_free_vq;
}
+ /* Default queue sizing is to fill the ring. */
+ if (!virtio_mq_reg.queue_depth) {
+ virtio_mq_reg.queue_depth = vblk->vq->num_free;
+ /* ... but without indirect descs, we use 2 descs per req */
+ if (!virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC))
+ virtio_mq_reg.queue_depth /= 2;
+ }
virtio_mq_reg.cmd_size =
sizeof(struct virtblk_req) +
sizeof(struct scatterlist) * sg_elems;
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c
index 4b97b86da926..64c60edcdfbc 100644
--- a/drivers/block/xen-blkback/blkback.c
+++ b/drivers/block/xen-blkback/blkback.c
@@ -299,7 +299,7 @@ static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root,
BUG_ON(num != 0);
}
-static void unmap_purged_grants(struct work_struct *work)
+void xen_blkbk_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];
@@ -375,7 +375,7 @@ static void purge_persistent_gnt(struct xen_blkif *blkif)
pr_debug(DRV_PFX "Going to purge %u persistent grants\n", num_clean);
- INIT_LIST_HEAD(&blkif->persistent_purge_list);
+ BUG_ON(!list_empty(&blkif->persistent_purge_list));
root = &blkif->persistent_gnts;
purge_list:
foreach_grant_safe(persistent_gnt, n, root, node) {
@@ -420,7 +420,6 @@ finished:
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;
@@ -625,9 +624,23 @@ purge_gnt_list:
print_stats(blkif);
}
- /* Since we are shutting down remove all pages from the buffer */
- shrink_free_pagepool(blkif, 0 /* All */);
+ /* Drain pending purge work */
+ flush_work(&blkif->persistent_purge_work);
+ if (log_stats)
+ print_stats(blkif);
+
+ blkif->xenblkd = NULL;
+ xen_blkif_put(blkif);
+
+ return 0;
+}
+
+/*
+ * Remove persistent grants and empty the pool of free pages
+ */
+void xen_blkbk_free_caches(struct xen_blkif *blkif)
+{
/* Free all persistent grant pages */
if (!RB_EMPTY_ROOT(&blkif->persistent_gnts))
free_persistent_gnts(blkif, &blkif->persistent_gnts,
@@ -636,13 +649,8 @@ purge_gnt_list:
BUG_ON(!RB_EMPTY_ROOT(&blkif->persistent_gnts));
blkif->persistent_gnt_c = 0;
- if (log_stats)
- print_stats(blkif);
-
- blkif->xenblkd = NULL;
- xen_blkif_put(blkif);
-
- return 0;
+ /* Since we are shutting down remove all pages from the buffer */
+ shrink_free_pagepool(blkif, 0 /* All */);
}
/*
@@ -838,7 +846,7 @@ static int xen_blkbk_parse_indirect(struct blkif_request *req,
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;
+ struct blkif_request_segment *segments = NULL;
nseg = pending_req->nr_pages;
indirect_grefs = INDIRECT_PAGES(nseg);
@@ -934,9 +942,7 @@ static void xen_blk_drain_io(struct xen_blkif *blkif)
{
atomic_set(&blkif->drain, 1);
do {
- /* The initial value is one, and one refcnt taken at the
- * start of the xen_blkif_schedule thread. */
- if (atomic_read(&blkif->refcnt) <= 2)
+ if (atomic_read(&blkif->inflight) == 0)
break;
wait_for_completion_interruptible_timeout(
&blkif->drain_complete, HZ);
@@ -976,17 +982,30 @@ 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->blkif,
+ struct xen_blkif *blkif = pending_req->blkif;
+
+ xen_blkbk_unmap(blkif,
pending_req->segments,
pending_req->nr_pages);
- make_response(pending_req->blkif, pending_req->id,
+ make_response(blkif, pending_req->id,
pending_req->operation, pending_req->status);
- xen_blkif_put(pending_req->blkif);
- if (atomic_read(&pending_req->blkif->refcnt) <= 2) {
- if (atomic_read(&pending_req->blkif->drain))
- complete(&pending_req->blkif->drain_complete);
+ free_req(blkif, pending_req);
+ /*
+ * Make sure the request is freed before releasing blkif,
+ * or there could be a race between free_req and the
+ * cleanup done in xen_blkif_free during shutdown.
+ *
+ * NB: The fact that we might try to wake up pending_free_wq
+ * before drain_complete (in case there's a drain going on)
+ * it's not a problem with our current implementation
+ * because we can assure there's no thread waiting on
+ * pending_free_wq if there's a drain going on, but it has
+ * to be taken into account if the current model is changed.
+ */
+ if (atomic_dec_and_test(&blkif->inflight) && atomic_read(&blkif->drain)) {
+ complete(&blkif->drain_complete);
}
- free_req(pending_req->blkif, pending_req);
+ xen_blkif_put(blkif);
}
}
@@ -1240,6 +1259,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
* below (in "!bio") if we are handling a BLKIF_OP_DISCARD.
*/
xen_blkif_get(blkif);
+ atomic_inc(&blkif->inflight);
for (i = 0; i < nseg; i++) {
while ((bio == NULL) ||
diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h
index 8d8807563d99..be052773ad03 100644
--- a/drivers/block/xen-blkback/common.h
+++ b/drivers/block/xen-blkback/common.h
@@ -57,7 +57,7 @@
#define MAX_INDIRECT_SEGMENTS 256
#define SEGS_PER_INDIRECT_FRAME \
- (PAGE_SIZE/sizeof(struct blkif_request_segment_aligned))
+ (PAGE_SIZE/sizeof(struct blkif_request_segment))
#define MAX_INDIRECT_PAGES \
((MAX_INDIRECT_SEGMENTS + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME)
#define INDIRECT_PAGES(_segs) \
@@ -278,6 +278,7 @@ struct xen_blkif {
/* for barrier (drain) requests */
struct completion drain_complete;
atomic_t drain;
+ atomic_t inflight;
/* One thread per one blkif. */
struct task_struct *xenblkd;
unsigned int waiting_reqs;
@@ -376,6 +377,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);
+void xen_blkbk_free_caches(struct xen_blkif *blkif);
int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt,
struct backend_info *be, int state);
@@ -383,6 +385,7 @@ int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt,
int xen_blkbk_barrier(struct xenbus_transaction xbt,
struct backend_info *be, int state);
struct xenbus_device *xen_blkbk_xenbus(struct backend_info *be);
+void xen_blkbk_unmap_purged_grants(struct work_struct *work);
static inline void blkif_get_x86_32_req(struct blkif_request *dst,
struct blkif_x86_32_request *src)
diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c
index c2014a0aa206..9a547e6b6ebf 100644
--- a/drivers/block/xen-blkback/xenbus.c
+++ b/drivers/block/xen-blkback/xenbus.c
@@ -125,8 +125,11 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid)
blkif->persistent_gnts.rb_node = NULL;
spin_lock_init(&blkif->free_pages_lock);
INIT_LIST_HEAD(&blkif->free_pages);
+ INIT_LIST_HEAD(&blkif->persistent_purge_list);
blkif->free_pages_num = 0;
atomic_set(&blkif->persistent_gnt_in_use, 0);
+ atomic_set(&blkif->inflight, 0);
+ INIT_WORK(&blkif->persistent_purge_work, xen_blkbk_unmap_purged_grants);
INIT_LIST_HEAD(&blkif->pending_free);
@@ -259,6 +262,17 @@ static void xen_blkif_free(struct xen_blkif *blkif)
if (!atomic_dec_and_test(&blkif->refcnt))
BUG();
+ /* Remove all persistent grants and the cache of ballooned pages. */
+ xen_blkbk_free_caches(blkif);
+
+ /* Make sure everything is drained before shutting down */
+ BUG_ON(blkif->persistent_gnt_c != 0);
+ BUG_ON(atomic_read(&blkif->persistent_gnt_in_use) != 0);
+ BUG_ON(blkif->free_pages_num != 0);
+ BUG_ON(!list_empty(&blkif->persistent_purge_list));
+ BUG_ON(!list_empty(&blkif->free_pages));
+ BUG_ON(!RB_EMPTY_ROOT(&blkif->persistent_gnts));
+
/* 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);
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 8dcfb54f1603..efe1b4761735 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -162,7 +162,7 @@ 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))
+ (PAGE_SIZE/sizeof(struct blkif_request_segment))
#define INDIRECT_GREFS(_segs) \
((_segs + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME)
@@ -393,7 +393,7 @@ static int blkif_queue_request(struct request *req)
unsigned long id;
unsigned int fsect, lsect;
int i, ref, n;
- struct blkif_request_segment_aligned *segments = NULL;
+ struct blkif_request_segment *segments = NULL;
/*
* Used to store if we are able to queue the request by just using
@@ -550,7 +550,7 @@ static int blkif_queue_request(struct request *req)
} else {
n = i % SEGS_PER_INDIRECT_FRAME;
segments[n] =
- (struct blkif_request_segment_aligned) {
+ (struct blkif_request_segment) {
.gref = ref,
.first_sect = fsect,
.last_sect = lsect };
@@ -1904,13 +1904,16 @@ static void blkback_changed(struct xenbus_device *dev,
case XenbusStateReconfiguring:
case XenbusStateReconfigured:
case XenbusStateUnknown:
- case XenbusStateClosed:
break;
case XenbusStateConnected:
blkfront_connect(info);
break;
+ case XenbusStateClosed:
+ if (dev->state == XenbusStateClosed)
+ break;
+ /* Missed the backend's Closing state -- fallthrough */
case XenbusStateClosing:
blkfront_closing(info);
break;
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 011e55d820b1..51c557cfd92b 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -612,6 +612,8 @@ static ssize_t disksize_store(struct device *dev,
disksize = PAGE_ALIGN(disksize);
meta = zram_meta_alloc(disksize);
+ if (!meta)
+ return -ENOMEM;
down_write(&zram->init_lock);
if (zram->init_done) {
up_write(&zram->init_lock);
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 11a6104a1e4f..f5ce64e03fd7 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -241,5 +241,6 @@ config BT_WILINK
core driver to communicate with the BT core of the combo chip.
Say Y here to compile support for Texas Instrument's WiLink7 driver
- into the kernel or say M to compile it as module.
+ into the kernel or say M to compile it as module (btwilink).
+
endmenu
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 106d1d8e16ad..be571fef185d 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -62,50 +62,54 @@ static const struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x0CF3, 0x3000) },
/* Atheros AR3011 with sflash firmware*/
+ { USB_DEVICE(0x0489, 0xE027) },
+ { USB_DEVICE(0x0489, 0xE03D) },
+ { USB_DEVICE(0x0930, 0x0215) },
{ USB_DEVICE(0x0CF3, 0x3002) },
{ USB_DEVICE(0x0CF3, 0xE019) },
{ USB_DEVICE(0x13d3, 0x3304) },
- { USB_DEVICE(0x0930, 0x0215) },
- { USB_DEVICE(0x0489, 0xE03D) },
- { USB_DEVICE(0x0489, 0xE027) },
/* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE(0x03F0, 0x311D) },
/* Atheros AR3012 with sflash firmware*/
- { USB_DEVICE(0x0CF3, 0x0036) },
- { USB_DEVICE(0x0CF3, 0x3004) },
- { USB_DEVICE(0x0CF3, 0x3008) },
- { USB_DEVICE(0x0CF3, 0x311D) },
- { USB_DEVICE(0x0CF3, 0x817a) },
- { USB_DEVICE(0x13d3, 0x3375) },
+ { USB_DEVICE(0x0489, 0xe04d) },
+ { USB_DEVICE(0x0489, 0xe04e) },
+ { USB_DEVICE(0x0489, 0xe057) },
+ { USB_DEVICE(0x0489, 0xe056) },
+ { USB_DEVICE(0x0489, 0xe05f) },
+ { USB_DEVICE(0x04c5, 0x1330) },
{ USB_DEVICE(0x04CA, 0x3004) },
{ USB_DEVICE(0x04CA, 0x3005) },
{ USB_DEVICE(0x04CA, 0x3006) },
{ USB_DEVICE(0x04CA, 0x3008) },
{ USB_DEVICE(0x04CA, 0x300b) },
- { USB_DEVICE(0x13d3, 0x3362) },
- { USB_DEVICE(0x0CF3, 0xE004) },
- { USB_DEVICE(0x0CF3, 0xE005) },
{ USB_DEVICE(0x0930, 0x0219) },
{ USB_DEVICE(0x0930, 0x0220) },
- { USB_DEVICE(0x0489, 0xe057) },
- { USB_DEVICE(0x13d3, 0x3393) },
- { USB_DEVICE(0x0489, 0xe04e) },
- { USB_DEVICE(0x0489, 0xe056) },
- { USB_DEVICE(0x0489, 0xe04d) },
- { USB_DEVICE(0x04c5, 0x1330) },
- { USB_DEVICE(0x13d3, 0x3402) },
+ { USB_DEVICE(0x0b05, 0x17d0) },
+ { USB_DEVICE(0x0CF3, 0x0036) },
+ { USB_DEVICE(0x0CF3, 0x3004) },
+ { USB_DEVICE(0x0CF3, 0x3005) },
+ { USB_DEVICE(0x0CF3, 0x3008) },
+ { USB_DEVICE(0x0CF3, 0x311D) },
+ { USB_DEVICE(0x0CF3, 0x311E) },
+ { USB_DEVICE(0x0CF3, 0x311F) },
{ USB_DEVICE(0x0cf3, 0x3121) },
+ { USB_DEVICE(0x0CF3, 0x817a) },
{ USB_DEVICE(0x0cf3, 0xe003) },
- { USB_DEVICE(0x0489, 0xe05f) },
+ { USB_DEVICE(0x0CF3, 0xE004) },
+ { USB_DEVICE(0x0CF3, 0xE005) },
+ { USB_DEVICE(0x13d3, 0x3362) },
+ { USB_DEVICE(0x13d3, 0x3375) },
+ { USB_DEVICE(0x13d3, 0x3393) },
+ { USB_DEVICE(0x13d3, 0x3402) },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE02C) },
/* Atheros AR5BBU22 with sflash firmware */
- { USB_DEVICE(0x0489, 0xE03C) },
{ USB_DEVICE(0x0489, 0xE036) },
+ { USB_DEVICE(0x0489, 0xE03C) },
{ } /* Terminating entry */
};
@@ -118,36 +122,40 @@ MODULE_DEVICE_TABLE(usb, ath3k_table);
static const struct usb_device_id ath3k_blist_tbl[] = {
/* Atheros AR3012 with sflash firmware*/
- { USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
- { 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(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x3005), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x311E), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x311F), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU22 with sflash firmware */
- { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
{ } /* Terminating entry */
};
@@ -174,10 +182,9 @@ static int ath3k_load_firmware(struct usb_device *udev,
}
memcpy(send_buf, firmware->data, 20);
- if ((err = usb_control_msg(udev, pipe,
- USB_REQ_DFU_DNLOAD,
- USB_TYPE_VENDOR, 0, 0,
- send_buf, 20, USB_CTRL_SET_TIMEOUT)) < 0) {
+ err = usb_control_msg(udev, pipe, USB_REQ_DFU_DNLOAD, USB_TYPE_VENDOR,
+ 0, 0, send_buf, 20, USB_CTRL_SET_TIMEOUT);
+ if (err < 0) {
BT_ERR("Can't change to loading configuration err");
goto error;
}
@@ -360,7 +367,7 @@ static int ath3k_load_patch(struct usb_device *udev)
}
snprintf(filename, ATH3K_NAME_LEN, "ar3k/AthrBT_0x%08x.dfu",
- fw_version.rom_version);
+ le32_to_cpu(fw_version.rom_version));
ret = request_firmware(&firmware, filename, &udev->dev);
if (ret < 0) {
@@ -422,7 +429,7 @@ static int ath3k_load_syscfg(struct usb_device *udev)
}
snprintf(filename, ATH3K_NAME_LEN, "ar3k/ramps_0x%08x_%d%s",
- fw_version.rom_version, clk_value, ".dfu");
+ le32_to_cpu(fw_version.rom_version), clk_value, ".dfu");
ret = request_firmware(&firmware, filename, &udev->dev);
if (ret < 0) {
diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
index 31386998c9a7..b2e7e94a6771 100644
--- a/drivers/bluetooth/bfusb.c
+++ b/drivers/bluetooth/bfusb.c
@@ -131,8 +131,11 @@ static int bfusb_send_bulk(struct bfusb_data *data, struct sk_buff *skb)
BT_DBG("bfusb %p skb %p len %d", data, skb, skb->len);
- if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC)))
- return -ENOMEM;
+ if (!urb) {
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb)
+ return -ENOMEM;
+ }
pipe = usb_sndbulkpipe(data->udev, data->bulk_out_ep);
@@ -218,8 +221,11 @@ static int bfusb_rx_submit(struct bfusb_data *data, struct urb *urb)
BT_DBG("bfusb %p urb %p", data, urb);
- if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC)))
- return -ENOMEM;
+ if (!urb) {
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb)
+ return -ENOMEM;
+ }
skb = bt_skb_alloc(size, GFP_ATOMIC);
if (!skb) {
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index 57427de864a6..dfa5043e68ba 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -257,7 +257,8 @@ static void bluecard_write_wakeup(bluecard_info_t *info)
ready_bit = XMIT_BUF_ONE_READY;
}
- if (!(skb = skb_dequeue(&(info->txq))))
+ skb = skb_dequeue(&(info->txq));
+ if (!skb)
break;
if (bt_cb(skb)->pkt_type & 0x80) {
@@ -391,7 +392,8 @@ static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
if (info->rx_skb == NULL) {
info->rx_state = RECV_WAIT_PACKET_TYPE;
info->rx_count = 0;
- if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+ info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+ if (!info->rx_skb) {
BT_ERR("Can't allocate mem for new packet");
return;
}
@@ -566,7 +568,8 @@ static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
/* Ericsson baud rate command */
unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 };
- if (!(skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+ skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+ if (!skb) {
BT_ERR("Can't allocate mem for new packet");
return -1;
}
@@ -898,7 +901,7 @@ static void bluecard_release(struct pcmcia_device *link)
bluecard_close(info);
- del_timer(&(info->timer));
+ del_timer_sync(&(info->timer));
pcmcia_disable_device(link);
}
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 73d87994d028..1d82721cf9c6 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -193,8 +193,8 @@ static void bt3c_write_wakeup(bt3c_info_t *info)
if (!pcmcia_dev_present(info->p_dev))
break;
-
- if (!(skb = skb_dequeue(&(info->txq)))) {
+ skb = skb_dequeue(&(info->txq));
+ if (!skb) {
clear_bit(XMIT_SENDING, &(info->tx_state));
break;
}
@@ -238,7 +238,8 @@ static void bt3c_receive(bt3c_info_t *info)
if (info->rx_skb == NULL) {
info->rx_state = RECV_WAIT_PACKET_TYPE;
info->rx_count = 0;
- if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+ info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+ if (!info->rx_skb) {
BT_ERR("Can't allocate mem for new packet");
return;
}
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
index 1e0320af00c6..2c4997ce2484 100644
--- a/drivers/bluetooth/btmrvl_main.c
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -59,12 +59,13 @@ bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb)
priv->btmrvl_dev.sendcmdflag = false;
priv->adapter->cmd_complete = true;
wake_up_interruptible(&priv->adapter->cmd_wait_q);
- }
- if (hci_opcode_ogf(opcode) == 0x3F) {
- BT_DBG("vendor event skipped: opcode=%#4.4x", opcode);
- kfree_skb(skb);
- return false;
+ if (hci_opcode_ogf(opcode) == 0x3F) {
+ BT_DBG("vendor event skipped: opcode=%#4.4x",
+ opcode);
+ kfree_skb(skb);
+ return false;
+ }
}
}
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index a03ecc22a561..fb948f02eda5 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -149,7 +149,8 @@ static void btuart_write_wakeup(btuart_info_t *info)
if (!pcmcia_dev_present(info->p_dev))
return;
- if (!(skb = skb_dequeue(&(info->txq))))
+ skb = skb_dequeue(&(info->txq));
+ if (!skb)
break;
/* Send frame */
@@ -190,7 +191,8 @@ static void btuart_receive(btuart_info_t *info)
if (info->rx_skb == NULL) {
info->rx_state = RECV_WAIT_PACKET_TYPE;
info->rx_count = 0;
- if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+ info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+ if (!info->rx_skb) {
BT_ERR("Can't allocate mem for new packet");
return;
}
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index baeaaed299e4..f338b0c5a8de 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -101,21 +101,24 @@ static const struct usb_device_id btusb_table[] = {
{ USB_DEVICE(0x0c10, 0x0000) },
/* Broadcom BCM20702A0 */
+ { USB_DEVICE(0x0489, 0xe042) },
+ { USB_DEVICE(0x04ca, 0x2003) },
{ USB_DEVICE(0x0b05, 0x17b5) },
{ USB_DEVICE(0x0b05, 0x17cb) },
- { USB_DEVICE(0x04ca, 0x2003) },
- { USB_DEVICE(0x0489, 0xe042) },
{ USB_DEVICE(0x413c, 0x8197) },
/* Foxconn - Hon Hai */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) },
- /*Broadcom devices with vendor specific id */
+ /* Broadcom devices with vendor specific id */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
/* Belkin F8065bf - Broadcom based */
{ USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },
+ /* IMC Networks - Broadcom based */
+ { USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xff, 0x01, 0x01) },
+
{ } /* Terminating entry */
};
@@ -129,55 +132,59 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },
/* Atheros 3011 with sflash firmware */
+ { USB_DEVICE(0x0489, 0xe027), .driver_info = BTUSB_IGNORE },
+ { USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE },
+ { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE },
{ USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
{ USB_DEVICE(0x0cf3, 0xe019), .driver_info = BTUSB_IGNORE },
{ USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE },
- { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE },
- { USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE },
- { USB_DEVICE(0x0489, 0xe027), .driver_info = BTUSB_IGNORE },
/* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
/* Atheros 3012 with sflash firmware */
- { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
- { 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(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x3005), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x311f), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
/* Atheros AR5BBU12 with sflash firmware */
- { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
/* Broadcom BCM2035 */
- { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
- { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
+ { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
+ { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
/* Broadcom BCM2045 */
{ USB_DEVICE(0x0a5c, 0x2039), .driver_info = BTUSB_WRONG_SCO_MTU },
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index 52eed1f3565d..2bd8fad17206 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -153,7 +153,8 @@ static void dtl1_write_wakeup(dtl1_info_t *info)
if (!pcmcia_dev_present(info->p_dev))
return;
- if (!(skb = skb_dequeue(&(info->txq))))
+ skb = skb_dequeue(&(info->txq));
+ if (!skb)
break;
/* Send frame */
@@ -215,13 +216,15 @@ static void dtl1_receive(dtl1_info_t *info)
info->hdev->stat.byte_rx++;
/* Allocate packet */
- if (info->rx_skb == NULL)
- if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+ if (info->rx_skb == NULL) {
+ info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+ if (!info->rx_skb) {
BT_ERR("Can't allocate mem for new packet");
info->rx_state = RECV_WAIT_NSH;
info->rx_count = NSHL;
return;
}
+ }
*skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
nsh = (nsh_t *)info->rx_skb->data;
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index 0bc87f7abd95..21cc45b34f13 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -291,7 +291,8 @@ static struct sk_buff *bcsp_dequeue(struct hci_uart *hu)
/* First of all, check for unreliable messages in the queue,
since they have priority */
- if ((skb = skb_dequeue(&bcsp->unrel)) != NULL) {
+ skb = skb_dequeue(&bcsp->unrel);
+ if (skb != NULL) {
struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, bt_cb(skb)->pkt_type);
if (nskb) {
kfree_skb(skb);
@@ -308,16 +309,20 @@ static struct sk_buff *bcsp_dequeue(struct hci_uart *hu)
spin_lock_irqsave_nested(&bcsp->unack.lock, flags, SINGLE_DEPTH_NESTING);
- if (bcsp->unack.qlen < BCSP_TXWINSIZE && (skb = skb_dequeue(&bcsp->rel)) != NULL) {
- struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, bt_cb(skb)->pkt_type);
- if (nskb) {
- __skb_queue_tail(&bcsp->unack, skb);
- mod_timer(&bcsp->tbcsp, jiffies + HZ / 4);
- spin_unlock_irqrestore(&bcsp->unack.lock, flags);
- return nskb;
- } else {
- skb_queue_head(&bcsp->rel, skb);
- BT_ERR("Could not dequeue pkt because alloc_skb failed");
+ if (bcsp->unack.qlen < BCSP_TXWINSIZE) {
+ skb = skb_dequeue(&bcsp->rel);
+ if (skb != NULL) {
+ struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len,
+ bt_cb(skb)->pkt_type);
+ if (nskb) {
+ __skb_queue_tail(&bcsp->unack, skb);
+ mod_timer(&bcsp->tbcsp, jiffies + HZ / 4);
+ spin_unlock_irqrestore(&bcsp->unack.lock, flags);
+ return nskb;
+ } else {
+ skb_queue_head(&bcsp->rel, skb);
+ BT_ERR("Could not dequeue pkt because alloc_skb failed");
+ }
}
}
@@ -715,6 +720,9 @@ static int bcsp_open(struct hci_uart *hu)
static int bcsp_close(struct hci_uart *hu)
{
struct bcsp_struct *bcsp = hu->priv;
+
+ del_timer_sync(&bcsp->tbcsp);
+
hu->priv = NULL;
BT_DBG("hu %p", hu);
@@ -722,7 +730,6 @@ static int bcsp_close(struct hci_uart *hu)
skb_queue_purge(&bcsp->unack);
skb_queue_purge(&bcsp->rel);
skb_queue_purge(&bcsp->unrel);
- del_timer(&bcsp->tbcsp);
kfree(bcsp);
return 0;
diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c
index f6f497450560..04680ead9275 100644
--- a/drivers/bluetooth/hci_h5.c
+++ b/drivers/bluetooth/hci_h5.c
@@ -206,12 +206,12 @@ static int h5_close(struct hci_uart *hu)
{
struct h5 *h5 = hu->priv;
+ del_timer_sync(&h5->timer);
+
skb_queue_purge(&h5->unack);
skb_queue_purge(&h5->rel);
skb_queue_purge(&h5->unrel);
- del_timer(&h5->timer);
-
kfree(h5);
return 0;
@@ -673,7 +673,8 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu)
return h5_prepare_pkt(hu, HCI_3WIRE_LINK_PKT, wakeup_req, 2);
}
- if ((skb = skb_dequeue(&h5->unrel)) != NULL) {
+ skb = skb_dequeue(&h5->unrel);
+ if (skb != NULL) {
nskb = h5_prepare_pkt(hu, bt_cb(skb)->pkt_type,
skb->data, skb->len);
if (nskb) {
@@ -690,7 +691,8 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu)
if (h5->unack.qlen >= h5->tx_win)
goto unlock;
- if ((skb = skb_dequeue(&h5->rel)) != NULL) {
+ skb = skb_dequeue(&h5->rel);
+ if (skb != NULL) {
nskb = h5_prepare_pkt(hu, bt_cb(skb)->pkt_type,
skb->data, skb->len);
if (nskb) {
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 6e06f6f69152..f1fbf4f1e5be 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -271,7 +271,8 @@ static int hci_uart_tty_open(struct tty_struct *tty)
if (tty->ops->write == NULL)
return -EOPNOTSUPP;
- if (!(hu = kzalloc(sizeof(struct hci_uart), GFP_KERNEL))) {
+ hu = kzalloc(sizeof(struct hci_uart), GFP_KERNEL);
+ if (!hu) {
BT_ERR("Can't allocate control structure");
return -ENFILE;
}
@@ -569,7 +570,8 @@ static int __init hci_uart_init(void)
hci_uart_ldisc.write_wakeup = hci_uart_tty_wakeup;
hci_uart_ldisc.owner = THIS_MODULE;
- if ((err = tty_register_ldisc(N_HCI, &hci_uart_ldisc))) {
+ err = tty_register_ldisc(N_HCI, &hci_uart_ldisc);
+ if (err) {
BT_ERR("HCI line discipline registration failed. (%d)", err);
return err;
}
@@ -614,7 +616,8 @@ static void __exit hci_uart_exit(void)
#endif
/* Release tty registration of line discipline */
- if ((err = tty_unregister_ldisc(N_HCI)))
+ err = tty_unregister_ldisc(N_HCI);
+ if (err)
BT_ERR("Can't unregister HCI line discipline (%d)", err);
}
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
index 1ef6990a5c7e..add1c6a72063 100644
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -359,7 +359,7 @@ static const struct file_operations vhci_fops = {
static struct miscdevice vhci_miscdev= {
.name = "vhci",
.fops = &vhci_fops,
- .minor = MISC_DYNAMIC_MINOR,
+ .minor = VHCI_MINOR,
};
static int __init vhci_init(void)
@@ -385,3 +385,4 @@ MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
MODULE_ALIAS("devname:vhci");
+MODULE_ALIAS_MISCDEV(VHCI_MINOR);
diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
index 725c46162bbd..2ac754e18bcf 100644
--- a/drivers/bus/mvebu-mbus.c
+++ b/drivers/bus/mvebu-mbus.c
@@ -870,14 +870,14 @@ static void __init mvebu_mbus_get_pcie_resources(struct device_node *np,
ret = of_property_read_u32_array(np, "pcie-mem-aperture", reg, ARRAY_SIZE(reg));
if (!ret) {
mem->start = reg[0];
- mem->end = mem->start + reg[1];
+ mem->end = mem->start + reg[1] - 1;
mem->flags = IORESOURCE_MEM;
}
ret = of_property_read_u32_array(np, "pcie-io-aperture", reg, ARRAY_SIZE(reg));
if (!ret) {
io->start = reg[0];
- io->end = io->start + reg[1];
+ io->end = io->start + reg[1] - 1;
io->flags = IORESOURCE_IO;
}
}
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index fa3243d71c76..1386749b48ff 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -499,6 +499,7 @@ config RAW_DRIVER
config MAX_RAW_DEVS
int "Maximum number of RAW devices to support (1-65536)"
depends on RAW_DRIVER
+ range 1 65536
default "256"
help
The maximum number of RAW devices that are supported.
diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c
index 1b192395a90c..8121b4c70ede 100644
--- a/drivers/char/agp/frontend.c
+++ b/drivers/char/agp/frontend.c
@@ -31,7 +31,6 @@
#include <linux/module.h>
#include <linux/mman.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/agp_backend.h>
#include <linux/agpgart.h>
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index f39437addb58..0fbccce1cee9 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -29,7 +29,6 @@
*/
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/pagemap.h>
#include <linux/miscdevice.h>
#include <linux/pm.h>
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index 5c85350f4c3d..9a024f899dd4 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pagemap.h>
#include <linux/agp_backend.h>
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
index 05b8d0241bde..3051c73bc383 100644
--- a/drivers/char/agp/sgi-agp.c
+++ b/drivers/char/agp/sgi-agp.c
@@ -15,7 +15,6 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/init.h>
#include <linux/agp_backend.h>
#include <asm/sn/addrs.h>
#include <asm/sn/io.h>
diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c
index bf9fc6b79328..851bc7e20ad2 100644
--- a/drivers/char/hw_random/atmel-rng.c
+++ b/drivers/char/hw_random/atmel-rng.c
@@ -54,29 +54,22 @@ static int atmel_trng_probe(struct platform_device *pdev)
struct resource *res;
int ret;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -EINVAL;
-
trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
if (!trng)
return -ENOMEM;
- if (!devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res), pdev->name))
- return -EBUSY;
-
- trng->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!trng->base)
- return -EBUSY;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ trng->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(trng->base))
+ return PTR_ERR(trng->base);
- trng->clk = clk_get(&pdev->dev, NULL);
+ trng->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(trng->clk))
return PTR_ERR(trng->clk);
ret = clk_enable(trng->clk);
if (ret)
- goto err_enable;
+ return ret;
writel(TRNG_KEY | 1, trng->base + TRNG_CR);
trng->rng.name = pdev->name;
@@ -92,9 +85,6 @@ static int atmel_trng_probe(struct platform_device *pdev)
err_register:
clk_disable(trng->clk);
-err_enable:
- clk_put(trng->clk);
-
return ret;
}
@@ -106,7 +96,6 @@ static int atmel_trng_remove(struct platform_device *pdev)
writel(TRNG_KEY, trng->base + TRNG_CR);
clk_disable(trng->clk);
- clk_put(trng->clk);
return 0;
}
diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c
index 43577ca780e3..8c3b255e629a 100644
--- a/drivers/char/hw_random/bcm2835-rng.c
+++ b/drivers/char/hw_random/bcm2835-rng.c
@@ -8,7 +8,6 @@
*/
#include <linux/hw_random.h>
-#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index a0f7724852eb..334601cc81cf 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -37,10 +37,10 @@
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/sched.h>
-#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/random.h>
#include <asm/uaccess.h>
@@ -302,9 +302,10 @@ err_misc_dereg:
int hwrng_register(struct hwrng *rng)
{
- int must_register_misc;
int err = -EINVAL;
struct hwrng *old_rng, *tmp;
+ unsigned char bytes[16];
+ int bytes_read;
if (rng->name == NULL ||
(rng->data_read == NULL && rng->read == NULL))
@@ -327,7 +328,6 @@ int hwrng_register(struct hwrng *rng)
goto out_unlock;
}
- must_register_misc = (current_rng == NULL);
old_rng = current_rng;
if (!old_rng) {
err = hwrng_init(rng);
@@ -336,18 +336,20 @@ int hwrng_register(struct hwrng *rng)
current_rng = rng;
}
err = 0;
- if (must_register_misc) {
+ if (!old_rng) {
err = register_miscdev();
if (err) {
- if (!old_rng) {
- hwrng_cleanup(rng);
- current_rng = NULL;
- }
+ hwrng_cleanup(rng);
+ current_rng = NULL;
goto out_unlock;
}
}
INIT_LIST_HEAD(&rng->list);
list_add_tail(&rng->list, &rng_list);
+
+ bytes_read = rng_get_data(rng, bytes, sizeof(bytes), 1);
+ if (bytes_read > 0)
+ add_device_randomness(bytes, bytes_read);
out_unlock:
mutex_unlock(&rng_mutex);
out:
diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c
index 402ccfb625c5..9f8277cc44b4 100644
--- a/drivers/char/hw_random/exynos-rng.c
+++ b/drivers/char/hw_random/exynos-rng.c
@@ -22,7 +22,6 @@
#include <linux/hw_random.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c
index f9beed54d0c8..432232eefe05 100644
--- a/drivers/char/hw_random/n2-drv.c
+++ b/drivers/char/hw_random/n2-drv.c
@@ -7,7 +7,6 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/delay.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/preempt.h>
diff --git a/drivers/char/hw_random/nomadik-rng.c b/drivers/char/hw_random/nomadik-rng.c
index 232b87fb5fc9..9c8581577246 100644
--- a/drivers/char/hw_random/nomadik-rng.c
+++ b/drivers/char/hw_random/nomadik-rng.c
@@ -10,7 +10,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/device.h>
#include <linux/amba/bus.h>
#include <linux/hw_random.h>
@@ -44,7 +43,7 @@ static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id)
void __iomem *base;
int ret;
- rng_clk = clk_get(&dev->dev, NULL);
+ rng_clk = devm_clk_get(&dev->dev, NULL);
if (IS_ERR(rng_clk)) {
dev_err(&dev->dev, "could not get rng clock\n");
ret = PTR_ERR(rng_clk);
@@ -57,33 +56,28 @@ static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id)
if (ret)
goto out_clk;
ret = -ENOMEM;
- base = ioremap(dev->res.start, resource_size(&dev->res));
+ base = devm_ioremap(&dev->dev, dev->res.start,
+ resource_size(&dev->res));
if (!base)
goto out_release;
nmk_rng.priv = (unsigned long)base;
ret = hwrng_register(&nmk_rng);
if (ret)
- goto out_unmap;
+ goto out_release;
return 0;
-out_unmap:
- iounmap(base);
out_release:
amba_release_regions(dev);
out_clk:
clk_disable(rng_clk);
- clk_put(rng_clk);
return ret;
}
static int nmk_rng_remove(struct amba_device *dev)
{
- void __iomem *base = (void __iomem *)nmk_rng.priv;
hwrng_unregister(&nmk_rng);
- iounmap(base);
amba_release_regions(dev);
clk_disable(rng_clk);
- clk_put(rng_clk);
return 0;
}
diff --git a/drivers/char/hw_random/octeon-rng.c b/drivers/char/hw_random/octeon-rng.c
index f2885dbe1849..b5cc3420c659 100644
--- a/drivers/char/hw_random/octeon-rng.c
+++ b/drivers/char/hw_random/octeon-rng.c
@@ -10,7 +10,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/hw_random.h>
diff --git a/drivers/char/hw_random/omap3-rom-rng.c b/drivers/char/hw_random/omap3-rom-rng.c
index c853e9e68573..6f2eaffed623 100644
--- a/drivers/char/hw_random/omap3-rom-rng.c
+++ b/drivers/char/hw_random/omap3-rom-rng.c
@@ -103,7 +103,7 @@ static int omap3_rom_rng_probe(struct platform_device *pdev)
}
setup_timer(&idle_timer, omap3_rom_rng_idle, 0);
- rng_clk = clk_get(&pdev->dev, "ick");
+ rng_clk = devm_clk_get(&pdev->dev, "ick");
if (IS_ERR(rng_clk)) {
pr_err("unable to get RNG clock\n");
return PTR_ERR(rng_clk);
@@ -120,7 +120,6 @@ static int omap3_rom_rng_remove(struct platform_device *pdev)
{
hwrng_unregister(&omap3_rom_rng_ops);
clk_disable_unprepare(rng_clk);
- clk_put(rng_clk);
return 0;
}
diff --git a/drivers/char/hw_random/picoxcell-rng.c b/drivers/char/hw_random/picoxcell-rng.c
index 3d4c2293c6f5..eab5448ad56f 100644
--- a/drivers/char/hw_random/picoxcell-rng.c
+++ b/drivers/char/hw_random/picoxcell-rng.c
@@ -104,24 +104,11 @@ static int picoxcell_trng_probe(struct platform_device *pdev)
int ret;
struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_warn(&pdev->dev, "no memory resource\n");
- return -ENOMEM;
- }
-
- if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem),
- "picoxcell_trng")) {
- dev_warn(&pdev->dev, "unable to request io mem\n");
- return -EBUSY;
- }
+ rng_base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(rng_base))
+ return PTR_ERR(rng_base);
- rng_base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
- if (!rng_base) {
- dev_warn(&pdev->dev, "unable to remap io mem\n");
- return -ENOMEM;
- }
-
- rng_clk = clk_get(&pdev->dev, NULL);
+ rng_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(rng_clk)) {
dev_warn(&pdev->dev, "no clk\n");
return PTR_ERR(rng_clk);
@@ -130,7 +117,7 @@ static int picoxcell_trng_probe(struct platform_device *pdev)
ret = clk_enable(rng_clk);
if (ret) {
dev_warn(&pdev->dev, "unable to enable clk\n");
- goto err_enable;
+ return ret;
}
picoxcell_trng_start();
@@ -145,9 +132,6 @@ static int picoxcell_trng_probe(struct platform_device *pdev)
err_register:
clk_disable(rng_clk);
-err_enable:
- clk_put(rng_clk);
-
return ret;
}
@@ -155,7 +139,6 @@ static int picoxcell_trng_remove(struct platform_device *pdev)
{
hwrng_unregister(&picoxcell_trng);
clk_disable(rng_clk);
- clk_put(rng_clk);
return 0;
}
diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c
index 73ce739f8e19..439ff8b28c43 100644
--- a/drivers/char/hw_random/timeriomem-rng.c
+++ b/drivers/char/hw_random/timeriomem-rng.c
@@ -118,7 +118,8 @@ static int timeriomem_rng_probe(struct platform_device *pdev)
}
/* Allocate memory for the device structure (and zero it) */
- priv = kzalloc(sizeof(struct timeriomem_rng_private_data), GFP_KERNEL);
+ priv = devm_kzalloc(&pdev->dev,
+ sizeof(struct timeriomem_rng_private_data), GFP_KERNEL);
if (!priv) {
dev_err(&pdev->dev, "failed to allocate device structure.\n");
return -ENOMEM;
@@ -134,17 +135,16 @@ static int timeriomem_rng_probe(struct platform_device *pdev)
period = i;
else {
dev_err(&pdev->dev, "missing period\n");
- err = -EINVAL;
- goto out_free;
+ return -EINVAL;
}
- } else
+ } else {
period = pdata->period;
+ }
priv->period = usecs_to_jiffies(period);
if (priv->period < 1) {
dev_err(&pdev->dev, "period is less than one jiffy\n");
- err = -EINVAL;
- goto out_free;
+ return -EINVAL;
}
priv->expires = jiffies;
@@ -160,24 +160,16 @@ static int timeriomem_rng_probe(struct platform_device *pdev)
priv->timeriomem_rng_ops.data_read = timeriomem_rng_data_read;
priv->timeriomem_rng_ops.priv = (unsigned long)priv;
- if (!request_mem_region(res->start, resource_size(res),
- dev_name(&pdev->dev))) {
- dev_err(&pdev->dev, "request_mem_region failed\n");
- err = -EBUSY;
+ priv->io_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->io_base)) {
+ err = PTR_ERR(priv->io_base);
goto out_timer;
}
- priv->io_base = ioremap(res->start, resource_size(res));
- if (priv->io_base == NULL) {
- dev_err(&pdev->dev, "ioremap failed\n");
- err = -EIO;
- goto out_release_io;
- }
-
err = hwrng_register(&priv->timeriomem_rng_ops);
if (err) {
dev_err(&pdev->dev, "problem registering\n");
- goto out;
+ goto out_timer;
}
dev_info(&pdev->dev, "32bits from 0x%p @ %dus\n",
@@ -185,30 +177,18 @@ static int timeriomem_rng_probe(struct platform_device *pdev)
return 0;
-out:
- iounmap(priv->io_base);
-out_release_io:
- release_mem_region(res->start, resource_size(res));
out_timer:
del_timer_sync(&priv->timer);
-out_free:
- kfree(priv);
return err;
}
static int timeriomem_rng_remove(struct platform_device *pdev)
{
struct timeriomem_rng_private_data *priv = platform_get_drvdata(pdev);
- struct resource *res;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hwrng_unregister(&priv->timeriomem_rng_ops);
del_timer_sync(&priv->timer);
- iounmap(priv->io_base);
- release_mem_region(res->start, resource_size(res));
- kfree(priv);
return 0;
}
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
index c12398d1517c..2ce0e225e58c 100644
--- a/drivers/char/hw_random/virtio-rng.c
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -47,8 +47,7 @@ static void register_buffer(u8 *buf, size_t size)
sg_init_one(&sg, buf, size);
/* There should always be room for one buffer. */
- if (virtqueue_add_inbuf(vq, &sg, 1, buf, GFP_KERNEL) < 0)
- BUG();
+ virtqueue_add_inbuf(vq, &sg, 1, buf, GFP_KERNEL);
virtqueue_kick(vq);
}
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 03f41896d090..b7efd3c1a882 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -61,7 +61,6 @@
#include <linux/ipmi_smi.h>
#include <asm/io.h>
#include "ipmi_si_sm.h"
-#include <linux/init.h>
#include <linux/dmi.h>
#include <linux/string.h>
#include <linux/ctype.h>
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 92c5937f80c3..917403fe10da 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -99,6 +99,9 @@ static ssize_t read_mem(struct file *file, char __user *buf,
ssize_t read, sz;
char *ptr;
+ if (p != *ppos)
+ return 0;
+
if (!valid_phys_addr_range(p, count))
return -EFAULT;
read = 0;
@@ -157,6 +160,9 @@ static ssize_t write_mem(struct file *file, const char __user *buf,
unsigned long copied;
void *ptr;
+ if (p != *ppos)
+ return -EFBIG;
+
if (!valid_phys_addr_range(p, count))
return -EFAULT;
diff --git a/drivers/char/mwave/3780i.c b/drivers/char/mwave/3780i.c
index 881c9e595939..28740046bc83 100644
--- a/drivers/char/mwave/3780i.c
+++ b/drivers/char/mwave/3780i.c
@@ -50,7 +50,6 @@
#include <linux/unistd.h>
#include <linux/delay.h>
#include <linux/ioport.h>
-#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/sched.h> /* cond_resched() */
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index f3223aac4df1..6e8d65e9b1d3 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -190,7 +190,7 @@ static int bind_get(int number, dev_t *dev)
struct raw_device_data *rawdev;
struct block_device *bdev;
- if (number <= 0 || number >= MAX_RAW_MINORS)
+ if (number <= 0 || number >= max_raw_minors)
return -EINVAL;
rawdev = &raw_devices[number];
diff --git a/drivers/char/tile-srom.c b/drivers/char/tile-srom.c
index 0e506bad1986..bd377472dcfb 100644
--- a/drivers/char/tile-srom.c
+++ b/drivers/char/tile-srom.c
@@ -20,7 +20,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/init.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c
index 52b9b2b2f300..472af4bb1b61 100644
--- a/drivers/char/tpm/tpm_i2c_infineon.c
+++ b/drivers/char/tpm/tpm_i2c_infineon.c
@@ -21,7 +21,6 @@
*
*
*/
-#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/wait.h>
diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c
index 5b0dd8ef74c0..3b7bf2162898 100644
--- a/drivers/char/tpm/tpm_i2c_stm_st33.c
+++ b/drivers/char/tpm/tpm_i2c_stm_st33.c
@@ -38,7 +38,6 @@
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/delay.h>
-#include <linux/init.h>
#include <linux/wait.h>
#include <linux/string.h>
#include <linux/interrupt.h>
diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c
index bd313f7816a8..c1af80bcdf20 100644
--- a/drivers/clk/at91/clk-master.c
+++ b/drivers/clk/at91/clk-master.c
@@ -242,7 +242,7 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc,
irq = irq_of_parse_and_map(np, 0);
if (!irq)
- return;
+ goto out_free_characteristics;
clk = at91_clk_register_master(pmc, irq, name, num_parents,
parent_names, layout,
diff --git a/drivers/clk/clk-nomadik.c b/drivers/clk/clk-nomadik.c
index 6a934a5296bd..05e04ce0f148 100644
--- a/drivers/clk/clk-nomadik.c
+++ b/drivers/clk/clk-nomadik.c
@@ -494,6 +494,9 @@ static const struct file_operations nomadik_src_clk_debugfs_ops = {
static int __init nomadik_src_clk_init_debugfs(void)
{
+ /* Vital for multiplatform */
+ if (!src_base)
+ return -ENODEV;
src_pcksr0_boot = readl(src_base + SRC_PCKSR0);
src_pcksr1_boot = readl(src_base + SRC_PCKSR1);
debugfs_create_file("nomadik-src-clk", S_IFREG | S_IRUGO,
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 5517944495d8..c42e608af6bb 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2226,24 +2226,25 @@ EXPORT_SYMBOL_GPL(devm_clk_unregister);
*/
int __clk_get(struct clk *clk)
{
- if (clk && !try_module_get(clk->owner))
- return 0;
+ if (clk) {
+ if (!try_module_get(clk->owner))
+ return 0;
- kref_get(&clk->ref);
+ kref_get(&clk->ref);
+ }
return 1;
}
void __clk_put(struct clk *clk)
{
- if (WARN_ON_ONCE(IS_ERR(clk)))
+ if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
return;
clk_prepare_lock();
kref_put(&clk->ref, __clk_release);
clk_prepare_unlock();
- if (clk)
- module_put(clk->owner);
+ module_put(clk->owner);
}
/*** clk rate change notifiers ***/
diff --git a/drivers/clk/keystone/gate.c b/drivers/clk/keystone/gate.c
index 17a598398a53..86f1e362eafb 100644
--- a/drivers/clk/keystone/gate.c
+++ b/drivers/clk/keystone/gate.c
@@ -179,6 +179,7 @@ static struct clk *clk_register_psc(struct device *dev,
init.name = name;
init.ops = &clk_psc_ops;
+ init.flags = 0;
init.parent_names = (parent_name ? &parent_name : NULL);
init.num_parents = (parent_name ? 1 : 0);
diff --git a/drivers/clk/mvebu/armada-370.c b/drivers/clk/mvebu/armada-370.c
index 81a202d12a7a..bef198a83863 100644
--- a/drivers/clk/mvebu/armada-370.c
+++ b/drivers/clk/mvebu/armada-370.c
@@ -141,13 +141,6 @@ static const struct coreclk_soc_desc a370_coreclks = {
.num_ratios = ARRAY_SIZE(a370_coreclk_ratios),
};
-static void __init a370_coreclk_init(struct device_node *np)
-{
- mvebu_coreclk_setup(np, &a370_coreclks);
-}
-CLK_OF_DECLARE(a370_core_clk, "marvell,armada-370-core-clock",
- a370_coreclk_init);
-
/*
* Clock Gating Control
*/
@@ -168,9 +161,15 @@ static const struct clk_gating_soc_desc a370_gating_desc[] __initconst = {
{ }
};
-static void __init a370_clk_gating_init(struct device_node *np)
+static void __init a370_clk_init(struct device_node *np)
{
- mvebu_clk_gating_setup(np, a370_gating_desc);
+ struct device_node *cgnp =
+ of_find_compatible_node(NULL, NULL, "marvell,armada-370-gating-clock");
+
+ mvebu_coreclk_setup(np, &a370_coreclks);
+
+ if (cgnp)
+ mvebu_clk_gating_setup(cgnp, a370_gating_desc);
}
-CLK_OF_DECLARE(a370_clk_gating, "marvell,armada-370-gating-clock",
- a370_clk_gating_init);
+CLK_OF_DECLARE(a370_clk, "marvell,armada-370-core-clock", a370_clk_init);
+
diff --git a/drivers/clk/mvebu/armada-xp.c b/drivers/clk/mvebu/armada-xp.c
index 9922c4475aa8..b3094315a3c0 100644
--- a/drivers/clk/mvebu/armada-xp.c
+++ b/drivers/clk/mvebu/armada-xp.c
@@ -158,13 +158,6 @@ static const struct coreclk_soc_desc axp_coreclks = {
.num_ratios = ARRAY_SIZE(axp_coreclk_ratios),
};
-static void __init axp_coreclk_init(struct device_node *np)
-{
- mvebu_coreclk_setup(np, &axp_coreclks);
-}
-CLK_OF_DECLARE(axp_core_clk, "marvell,armada-xp-core-clock",
- axp_coreclk_init);
-
/*
* Clock Gating Control
*/
@@ -202,9 +195,14 @@ static const struct clk_gating_soc_desc axp_gating_desc[] __initconst = {
{ }
};
-static void __init axp_clk_gating_init(struct device_node *np)
+static void __init axp_clk_init(struct device_node *np)
{
- mvebu_clk_gating_setup(np, axp_gating_desc);
+ struct device_node *cgnp =
+ of_find_compatible_node(NULL, NULL, "marvell,armada-xp-gating-clock");
+
+ mvebu_coreclk_setup(np, &axp_coreclks);
+
+ if (cgnp)
+ mvebu_clk_gating_setup(cgnp, axp_gating_desc);
}
-CLK_OF_DECLARE(axp_clk_gating, "marvell,armada-xp-gating-clock",
- axp_clk_gating_init);
+CLK_OF_DECLARE(axp_clk, "marvell,armada-xp-core-clock", axp_clk_init);
diff --git a/drivers/clk/mvebu/dove.c b/drivers/clk/mvebu/dove.c
index 38aee1e3f242..b8c2424ac926 100644
--- a/drivers/clk/mvebu/dove.c
+++ b/drivers/clk/mvebu/dove.c
@@ -154,12 +154,6 @@ static const struct coreclk_soc_desc dove_coreclks = {
.num_ratios = ARRAY_SIZE(dove_coreclk_ratios),
};
-static void __init dove_coreclk_init(struct device_node *np)
-{
- mvebu_coreclk_setup(np, &dove_coreclks);
-}
-CLK_OF_DECLARE(dove_core_clk, "marvell,dove-core-clock", dove_coreclk_init);
-
/*
* Clock Gating Control
*/
@@ -186,9 +180,14 @@ static const struct clk_gating_soc_desc dove_gating_desc[] __initconst = {
{ }
};
-static void __init dove_clk_gating_init(struct device_node *np)
+static void __init dove_clk_init(struct device_node *np)
{
- mvebu_clk_gating_setup(np, dove_gating_desc);
+ struct device_node *cgnp =
+ of_find_compatible_node(NULL, NULL, "marvell,dove-gating-clock");
+
+ mvebu_coreclk_setup(np, &dove_coreclks);
+
+ if (cgnp)
+ mvebu_clk_gating_setup(cgnp, dove_gating_desc);
}
-CLK_OF_DECLARE(dove_clk_gating, "marvell,dove-gating-clock",
- dove_clk_gating_init);
+CLK_OF_DECLARE(dove_clk, "marvell,dove-core-clock", dove_clk_init);
diff --git a/drivers/clk/mvebu/kirkwood.c b/drivers/clk/mvebu/kirkwood.c
index 2636a55f29f9..ddb666a86500 100644
--- a/drivers/clk/mvebu/kirkwood.c
+++ b/drivers/clk/mvebu/kirkwood.c
@@ -193,13 +193,6 @@ static const struct coreclk_soc_desc kirkwood_coreclks = {
.num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
};
-static void __init kirkwood_coreclk_init(struct device_node *np)
-{
- mvebu_coreclk_setup(np, &kirkwood_coreclks);
-}
-CLK_OF_DECLARE(kirkwood_core_clk, "marvell,kirkwood-core-clock",
- kirkwood_coreclk_init);
-
static const struct coreclk_soc_desc mv88f6180_coreclks = {
.get_tclk_freq = kirkwood_get_tclk_freq,
.get_cpu_freq = mv88f6180_get_cpu_freq,
@@ -208,13 +201,6 @@ static const struct coreclk_soc_desc mv88f6180_coreclks = {
.num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
};
-static void __init mv88f6180_coreclk_init(struct device_node *np)
-{
- mvebu_coreclk_setup(np, &mv88f6180_coreclks);
-}
-CLK_OF_DECLARE(mv88f6180_core_clk, "marvell,mv88f6180-core-clock",
- mv88f6180_coreclk_init);
-
/*
* Clock Gating Control
*/
@@ -239,9 +225,21 @@ static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = {
{ }
};
-static void __init kirkwood_clk_gating_init(struct device_node *np)
+static void __init kirkwood_clk_init(struct device_node *np)
{
- mvebu_clk_gating_setup(np, kirkwood_gating_desc);
+ struct device_node *cgnp =
+ of_find_compatible_node(NULL, NULL, "marvell,kirkwood-gating-clock");
+
+
+ if (of_device_is_compatible(np, "marvell,mv88f6180-core-clock"))
+ mvebu_coreclk_setup(np, &mv88f6180_coreclks);
+ else
+ mvebu_coreclk_setup(np, &kirkwood_coreclks);
+
+ if (cgnp)
+ mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc);
}
-CLK_OF_DECLARE(kirkwood_clk_gating, "marvell,kirkwood-gating-clock",
- kirkwood_clk_gating_init);
+CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock",
+ kirkwood_clk_init);
+CLK_OF_DECLARE(mv88f6180_clk, "marvell,mv88f6180-core-clock",
+ kirkwood_clk_init);
diff --git a/drivers/clk/shmobile/clk-rcar-gen2.c b/drivers/clk/shmobile/clk-rcar-gen2.c
index a59ec217a124..99c27b1c625b 100644
--- a/drivers/clk/shmobile/clk-rcar-gen2.c
+++ b/drivers/clk/shmobile/clk-rcar-gen2.c
@@ -26,6 +26,8 @@ struct rcar_gen2_cpg {
void __iomem *reg;
};
+#define CPG_FRQCRB 0x00000004
+#define CPG_FRQCRB_KICK BIT(31)
#define CPG_SDCKCR 0x00000074
#define CPG_PLL0CR 0x000000d8
#define CPG_FRQCRC 0x000000e0
@@ -45,6 +47,7 @@ struct rcar_gen2_cpg {
struct cpg_z_clk {
struct clk_hw hw;
void __iomem *reg;
+ void __iomem *kick_reg;
};
#define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw)
@@ -83,17 +86,45 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate,
{
struct cpg_z_clk *zclk = to_z_clk(hw);
unsigned int mult;
- u32 val;
+ u32 val, kick;
+ unsigned int i;
mult = div_u64((u64)rate * 32, parent_rate);
mult = clamp(mult, 1U, 32U);
+ if (clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK)
+ return -EBUSY;
+
val = clk_readl(zclk->reg);
val &= ~CPG_FRQCRC_ZFC_MASK;
val |= (32 - mult) << CPG_FRQCRC_ZFC_SHIFT;
clk_writel(val, zclk->reg);
- return 0;
+ /*
+ * Set KICK bit in FRQCRB to update hardware setting and wait for
+ * clock change completion.
+ */
+ kick = clk_readl(zclk->kick_reg);
+ kick |= CPG_FRQCRB_KICK;
+ clk_writel(kick, zclk->kick_reg);
+
+ /*
+ * Note: There is no HW information about the worst case latency.
+ *
+ * Using experimental measurements, it seems that no more than
+ * ~10 iterations are needed, independently of the CPU rate.
+ * Since this value might be dependant of external xtal rate, pll1
+ * rate or even the other emulation clocks rate, use 1000 as a
+ * "super" safe value.
+ */
+ for (i = 1000; i; i--) {
+ if (!(clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK))
+ return 0;
+
+ cpu_relax();
+ }
+
+ return -ETIMEDOUT;
}
static const struct clk_ops cpg_z_clk_ops = {
@@ -120,6 +151,7 @@ static struct clk * __init cpg_z_clk_register(struct rcar_gen2_cpg *cpg)
init.num_parents = 1;
zclk->reg = cpg->reg + CPG_FRQCRC;
+ zclk->kick_reg = cpg->reg + CPG_FRQCRB;
zclk->hw.init = &init;
clk = clk_register(NULL, &zclk->hw);
@@ -186,7 +218,7 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
const char *name)
{
const struct clk_div_table *table = NULL;
- const char *parent_name = "main";
+ const char *parent_name;
unsigned int shift;
unsigned int mult = 1;
unsigned int div = 1;
@@ -201,23 +233,31 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
* the multiplier value.
*/
u32 value = clk_readl(cpg->reg + CPG_PLL0CR);
+ parent_name = "main";
mult = ((value >> 24) & ((1 << 7) - 1)) + 1;
} else if (!strcmp(name, "pll1")) {
+ parent_name = "main";
mult = config->pll1_mult / 2;
} else if (!strcmp(name, "pll3")) {
+ parent_name = "main";
mult = config->pll3_mult;
} else if (!strcmp(name, "lb")) {
+ parent_name = "pll1_div2";
div = cpg_mode & BIT(18) ? 36 : 24;
} else if (!strcmp(name, "qspi")) {
+ parent_name = "pll1_div2";
div = (cpg_mode & (BIT(3) | BIT(2) | BIT(1))) == BIT(2)
- ? 16 : 20;
+ ? 8 : 10;
} else if (!strcmp(name, "sdh")) {
+ parent_name = "pll1_div2";
table = cpg_sdh_div_table;
shift = 8;
} else if (!strcmp(name, "sd0")) {
+ parent_name = "pll1_div2";
table = cpg_sd01_div_table;
shift = 4;
} else if (!strcmp(name, "sd1")) {
+ parent_name = "pll1_div2";
table = cpg_sd01_div_table;
shift = 0;
} else if (!strcmp(name, "z")) {
diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c
index 4d75b1f37e3a..290f9c1a3749 100644
--- a/drivers/clk/tegra/clk-divider.c
+++ b/drivers/clk/tegra/clk-divider.c
@@ -59,7 +59,7 @@ static int get_div(struct tegra_clk_frac_div *divider, unsigned long rate,
return 0;
if (divider_ux1 > get_max_div(divider))
- return -EINVAL;
+ return get_max_div(divider);
return divider_ux1;
}
diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h
index cf0c323f2c36..c39613c519af 100644
--- a/drivers/clk/tegra/clk-id.h
+++ b/drivers/clk/tegra/clk-id.h
@@ -180,9 +180,13 @@ enum clk_id {
tegra_clk_sbc6_8,
tegra_clk_sclk,
tegra_clk_sdmmc1,
+ tegra_clk_sdmmc1_8,
tegra_clk_sdmmc2,
+ tegra_clk_sdmmc2_8,
tegra_clk_sdmmc3,
+ tegra_clk_sdmmc3_8,
tegra_clk_sdmmc4,
+ tegra_clk_sdmmc4_8,
tegra_clk_se,
tegra_clk_soc_therm,
tegra_clk_sor0,
diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c
index 5c35885f4a7c..1fa5c3f33b20 100644
--- a/drivers/clk/tegra/clk-tegra-periph.c
+++ b/drivers/clk/tegra/clk-tegra-periph.c
@@ -371,9 +371,7 @@ static const char *mux_pllp3_pllc_clkm[] = {
static const char *mux_pllm_pllc_pllp_plla_pllc2_c3_clkm[] = {
"pll_m", "pll_c", "pll_p", "pll_a", "pll_c2", "pll_c3", "clk_m"
};
-static u32 mux_pllm_pllc_pllp_plla_pllc2_c3_clkm_idx[] = {
- [0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 6,
-};
+#define mux_pllm_pllc_pllp_plla_pllc2_c3_clkm_idx NULL
static const char *mux_pllm_pllc2_c_c3_pllp_plla_pllc4[] = {
"pll_m", "pll_c2", "pll_c", "pll_c3", "pll_p", "pll_a_out0", "pll_c4",
@@ -465,6 +463,10 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX("adx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX1, 180, TEGRA_PERIPH_ON_APB, tegra_clk_adx1),
MUX("amx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX1, 185, TEGRA_PERIPH_ON_APB, tegra_clk_amx1),
MUX("vi_sensor2", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR2, 20, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor2),
+ MUX8("sdmmc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC1, 14, 0, tegra_clk_sdmmc1_8),
+ MUX8("sdmmc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC2, 9, 0, tegra_clk_sdmmc2_8),
+ MUX8("sdmmc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC3, 69, 0, tegra_clk_sdmmc3_8),
+ MUX8("sdmmc4", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC4, 15, 0, tegra_clk_sdmmc4_8),
MUX8("sbc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC1, 41, TEGRA_PERIPH_ON_APB, tegra_clk_sbc1_8),
MUX8("sbc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC2, 44, TEGRA_PERIPH_ON_APB, tegra_clk_sbc2_8),
MUX8("sbc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC3, 46, TEGRA_PERIPH_ON_APB, tegra_clk_sbc3_8),
@@ -492,7 +494,7 @@ static struct tegra_periph_init_data periph_clks[] = {
UART("uartb", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTB, 7, tegra_clk_uartb),
UART("uartc", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTC, 55, tegra_clk_uartc),
UART("uartd", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTD, 65, tegra_clk_uartd),
- UART("uarte", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTE, 65, tegra_clk_uarte),
+ UART("uarte", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTE, 66, tegra_clk_uarte),
XUSB("xusb_host_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_host_src),
XUSB("xusb_falcon_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src),
XUSB("xusb_fs_src", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_fs_src),
diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c
index 05dce4aa2c11..feb3201c85ce 100644
--- a/drivers/clk/tegra/clk-tegra-super-gen4.c
+++ b/drivers/clk/tegra/clk-tegra-super-gen4.c
@@ -120,7 +120,7 @@ void __init tegra_super_clk_gen4_init(void __iomem *clk_base,
ARRAY_SIZE(cclk_lp_parents),
CLK_SET_RATE_PARENT,
clk_base + CCLKLP_BURST_POLICY,
- 0, 4, 8, 9, NULL);
+ TEGRA_DIVIDER_2, 4, 8, 9, NULL);
*dt_clk = clk;
}
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index 90d9d25f2228..80431f0fb268 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -682,12 +682,12 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
[tegra_clk_timer] = { .dt_id = TEGRA114_CLK_TIMER, .present = true },
[tegra_clk_uarta] = { .dt_id = TEGRA114_CLK_UARTA, .present = true },
[tegra_clk_uartd] = { .dt_id = TEGRA114_CLK_UARTD, .present = true },
- [tegra_clk_sdmmc2] = { .dt_id = TEGRA114_CLK_SDMMC2, .present = true },
+ [tegra_clk_sdmmc2_8] = { .dt_id = TEGRA114_CLK_SDMMC2, .present = true },
[tegra_clk_i2s1] = { .dt_id = TEGRA114_CLK_I2S1, .present = true },
[tegra_clk_i2c1] = { .dt_id = TEGRA114_CLK_I2C1, .present = true },
[tegra_clk_ndflash] = { .dt_id = TEGRA114_CLK_NDFLASH, .present = true },
- [tegra_clk_sdmmc1] = { .dt_id = TEGRA114_CLK_SDMMC1, .present = true },
- [tegra_clk_sdmmc4] = { .dt_id = TEGRA114_CLK_SDMMC4, .present = true },
+ [tegra_clk_sdmmc1_8] = { .dt_id = TEGRA114_CLK_SDMMC1, .present = true },
+ [tegra_clk_sdmmc4_8] = { .dt_id = TEGRA114_CLK_SDMMC4, .present = true },
[tegra_clk_pwm] = { .dt_id = TEGRA114_CLK_PWM, .present = true },
[tegra_clk_i2s0] = { .dt_id = TEGRA114_CLK_I2S0, .present = true },
[tegra_clk_i2s2] = { .dt_id = TEGRA114_CLK_I2S2, .present = true },
@@ -723,7 +723,7 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
[tegra_clk_bsev] = { .dt_id = TEGRA114_CLK_BSEV, .present = true },
[tegra_clk_i2c3] = { .dt_id = TEGRA114_CLK_I2C3, .present = true },
[tegra_clk_sbc4_8] = { .dt_id = TEGRA114_CLK_SBC4, .present = true },
- [tegra_clk_sdmmc3] = { .dt_id = TEGRA114_CLK_SDMMC3, .present = true },
+ [tegra_clk_sdmmc3_8] = { .dt_id = TEGRA114_CLK_SDMMC3, .present = true },
[tegra_clk_owr] = { .dt_id = TEGRA114_CLK_OWR, .present = true },
[tegra_clk_csite] = { .dt_id = TEGRA114_CLK_CSITE, .present = true },
[tegra_clk_la] = { .dt_id = TEGRA114_CLK_LA, .present = true },
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c
index aff86b5bc745..166e02f16c8a 100644
--- a/drivers/clk/tegra/clk-tegra124.c
+++ b/drivers/clk/tegra/clk-tegra124.c
@@ -516,11 +516,11 @@ static struct div_nmp pllp_nmp = {
};
static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
- {12000000, 216000000, 432, 12, 1, 8},
- {13000000, 216000000, 432, 13, 1, 8},
- {16800000, 216000000, 360, 14, 1, 8},
- {19200000, 216000000, 360, 16, 1, 8},
- {26000000, 216000000, 432, 26, 1, 8},
+ {12000000, 408000000, 408, 12, 0, 8},
+ {13000000, 408000000, 408, 13, 0, 8},
+ {16800000, 408000000, 340, 14, 0, 8},
+ {19200000, 408000000, 340, 16, 0, 8},
+ {26000000, 408000000, 408, 26, 0, 8},
{0, 0, 0, 0, 0, 0},
};
@@ -570,6 +570,15 @@ static struct tegra_clk_pll_params pll_a_params = {
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
};
+static struct div_nmp plld_nmp = {
+ .divm_shift = 0,
+ .divm_width = 5,
+ .divn_shift = 8,
+ .divn_width = 11,
+ .divp_shift = 20,
+ .divp_width = 3,
+};
+
static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
{12000000, 216000000, 864, 12, 4, 12},
{13000000, 216000000, 864, 13, 4, 12},
@@ -603,19 +612,18 @@ static struct tegra_clk_pll_params pll_d_params = {
.lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
.lock_delay = 1000,
- .div_nmp = &pllp_nmp,
+ .div_nmp = &plld_nmp,
.freq_table = pll_d_freq_table,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
TEGRA_PLL_USE_LOCK,
};
static struct tegra_clk_pll_freq_table tegra124_pll_d2_freq_table[] = {
- { 12000000, 148500000, 99, 1, 8},
- { 12000000, 594000000, 99, 1, 1},
- { 13000000, 594000000, 91, 1, 1}, /* actual: 591.5 MHz */
- { 16800000, 594000000, 71, 1, 1}, /* actual: 596.4 MHz */
- { 19200000, 594000000, 62, 1, 1}, /* actual: 595.2 MHz */
- { 26000000, 594000000, 91, 2, 1}, /* actual: 591.5 MHz */
+ { 12000000, 594000000, 99, 1, 2},
+ { 13000000, 594000000, 91, 1, 2}, /* actual: 591.5 MHz */
+ { 16800000, 594000000, 71, 1, 2}, /* actual: 596.4 MHz */
+ { 19200000, 594000000, 62, 1, 2}, /* actual: 595.2 MHz */
+ { 26000000, 594000000, 91, 2, 2}, /* actual: 591.5 MHz */
{ 0, 0, 0, 0, 0, 0 },
};
@@ -753,21 +761,19 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
[tegra_clk_rtc] = { .dt_id = TEGRA124_CLK_RTC, .present = true },
[tegra_clk_timer] = { .dt_id = TEGRA124_CLK_TIMER, .present = true },
[tegra_clk_uarta] = { .dt_id = TEGRA124_CLK_UARTA, .present = true },
- [tegra_clk_sdmmc2] = { .dt_id = TEGRA124_CLK_SDMMC2, .present = true },
+ [tegra_clk_sdmmc2_8] = { .dt_id = TEGRA124_CLK_SDMMC2, .present = true },
[tegra_clk_i2s1] = { .dt_id = TEGRA124_CLK_I2S1, .present = true },
[tegra_clk_i2c1] = { .dt_id = TEGRA124_CLK_I2C1, .present = true },
[tegra_clk_ndflash] = { .dt_id = TEGRA124_CLK_NDFLASH, .present = true },
- [tegra_clk_sdmmc1] = { .dt_id = TEGRA124_CLK_SDMMC1, .present = true },
- [tegra_clk_sdmmc4] = { .dt_id = TEGRA124_CLK_SDMMC4, .present = true },
+ [tegra_clk_sdmmc1_8] = { .dt_id = TEGRA124_CLK_SDMMC1, .present = true },
+ [tegra_clk_sdmmc4_8] = { .dt_id = TEGRA124_CLK_SDMMC4, .present = true },
[tegra_clk_pwm] = { .dt_id = TEGRA124_CLK_PWM, .present = true },
[tegra_clk_i2s2] = { .dt_id = TEGRA124_CLK_I2S2, .present = true },
- [tegra_clk_gr2d] = { .dt_id = TEGRA124_CLK_GR_2D, .present = true },
[tegra_clk_usbd] = { .dt_id = TEGRA124_CLK_USBD, .present = true },
[tegra_clk_isp_8] = { .dt_id = TEGRA124_CLK_ISP, .present = true },
- [tegra_clk_gr3d] = { .dt_id = TEGRA124_CLK_GR_3D, .present = true },
[tegra_clk_disp2] = { .dt_id = TEGRA124_CLK_DISP2, .present = true },
[tegra_clk_disp1] = { .dt_id = TEGRA124_CLK_DISP1, .present = true },
- [tegra_clk_host1x] = { .dt_id = TEGRA124_CLK_HOST1X, .present = true },
+ [tegra_clk_host1x_8] = { .dt_id = TEGRA124_CLK_HOST1X, .present = true },
[tegra_clk_vcp] = { .dt_id = TEGRA124_CLK_VCP, .present = true },
[tegra_clk_i2s0] = { .dt_id = TEGRA124_CLK_I2S0, .present = true },
[tegra_clk_apbdma] = { .dt_id = TEGRA124_CLK_APBDMA, .present = true },
@@ -794,7 +800,7 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
[tegra_clk_uartd] = { .dt_id = TEGRA124_CLK_UARTD, .present = true },
[tegra_clk_i2c3] = { .dt_id = TEGRA124_CLK_I2C3, .present = true },
[tegra_clk_sbc4] = { .dt_id = TEGRA124_CLK_SBC4, .present = true },
- [tegra_clk_sdmmc3] = { .dt_id = TEGRA124_CLK_SDMMC3, .present = true },
+ [tegra_clk_sdmmc3_8] = { .dt_id = TEGRA124_CLK_SDMMC3, .present = true },
[tegra_clk_pcie] = { .dt_id = TEGRA124_CLK_PCIE, .present = true },
[tegra_clk_owr] = { .dt_id = TEGRA124_CLK_OWR, .present = true },
[tegra_clk_afi] = { .dt_id = TEGRA124_CLK_AFI, .present = true },
@@ -1286,9 +1292,9 @@ static void __init tegra124_pll_init(void __iomem *clk_base,
clk_register_clkdev(clk, "pll_d2", NULL);
clks[TEGRA124_CLK_PLL_D2] = clk;
- /* PLLD2_OUT0 ?? */
+ /* PLLD2_OUT0 */
clk = clk_register_fixed_factor(NULL, "pll_d2_out0", "pll_d2",
- CLK_SET_RATE_PARENT, 1, 2);
+ CLK_SET_RATE_PARENT, 1, 1);
clk_register_clkdev(clk, "pll_d2_out0", NULL);
clks[TEGRA124_CLK_PLL_D2_OUT0] = clk;
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index dbace152b2fa..dace2b1b5ae6 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -574,6 +574,8 @@ static struct tegra_clk tegra20_clks[tegra_clk_max] __initdata = {
[tegra_clk_tvdac] = { .dt_id = TEGRA20_CLK_TVDAC, .present = true },
[tegra_clk_vi_sensor] = { .dt_id = TEGRA20_CLK_VI_SENSOR, .present = true },
[tegra_clk_afi] = { .dt_id = TEGRA20_CLK_AFI, .present = true },
+ [tegra_clk_fuse] = { .dt_id = TEGRA20_CLK_FUSE, .present = true },
+ [tegra_clk_kfuse] = { .dt_id = TEGRA20_CLK_KFUSE, .present = true },
};
static unsigned long tegra20_clk_measure_input_freq(void)
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index cd6950fd8caf..52e9329e3c51 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -140,3 +140,51 @@ config VF_PIT_TIMER
bool
help
Support for Period Interrupt Timer on Freescale Vybrid Family SoCs.
+
+config SYS_SUPPORTS_SH_CMT
+ bool
+
+config SYS_SUPPORTS_SH_MTU2
+ bool
+
+config SYS_SUPPORTS_SH_TMU
+ bool
+
+config SYS_SUPPORTS_EM_STI
+ bool
+
+config SH_TIMER_CMT
+ bool "Renesas CMT timer driver" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
+ default SYS_SUPPORTS_SH_CMT
+ help
+ This enables build of a clocksource and clockevent driver for
+ the Compare Match Timer (CMT) hardware available in 16/32/48-bit
+ variants on a wide range of Mobile and Automotive SoCs from Renesas.
+
+config SH_TIMER_MTU2
+ bool "Renesas MTU2 timer driver" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
+ default SYS_SUPPORTS_SH_MTU2
+ help
+ This enables build of a clockevent driver for the Multi-Function
+ Timer Pulse Unit 2 (TMU2) hardware available on SoCs from Renesas.
+ This hardware comes with 16 bit-timer registers.
+
+config SH_TIMER_TMU
+ bool "Renesas TMU timer driver" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
+ default SYS_SUPPORTS_SH_TMU
+ help
+ This enables build of a clocksource and clockevent driver for
+ the 32-bit Timer Unit (TMU) hardware available on a wide range
+ SoCs from Renesas.
+
+config EM_TIMER_STI
+ bool "Renesas STI timer driver" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
+ default SYS_SUPPORTS_EM_STI
+ help
+ This enables build of a clocksource and clockevent driver for
+ the 48-bit System Timer (STI) hardware available on a SoCs
+ such as EMEV2 from former NEC Electronics.
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index c7ca50a9c232..f3fe4cb4974b 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -1,6 +1,5 @@
obj-$(CONFIG_CLKSRC_OF) += clksrc-of.o
obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o
-obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o
obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o
obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o
obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += cs5535-clockevt.o
@@ -21,6 +20,7 @@ obj-$(CONFIG_ARCH_MARCO) += timer-marco.o
obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o
obj-$(CONFIG_ARCH_MXS) += mxs_timer.o
obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o
+obj-$(CONFIG_ARCH_U300) += timer-u300.o
obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o
obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o
obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o
@@ -37,3 +37,4 @@ obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o
obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o
obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o
+obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 95fb944e15ee..57e823c44d2a 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -277,6 +277,7 @@ static void __arch_timer_setup(unsigned type,
clk->set_next_event = arch_timer_set_next_event_phys;
}
} else {
+ clk->features |= CLOCK_EVT_FEAT_DYNIRQ;
clk->name = "arch_mem_timer";
clk->rating = 400;
clk->cpumask = cpu_all_mask;
diff --git a/drivers/clocksource/bcm_kona_timer.c b/drivers/clocksource/bcm_kona_timer.c
index 974b2db2fe10..0595dc6c453e 100644
--- a/drivers/clocksource/bcm_kona_timer.c
+++ b/drivers/clocksource/bcm_kona_timer.c
@@ -99,31 +99,6 @@ kona_timer_get_counter(void *timer_base, uint32_t *msw, uint32_t *lsw)
return;
}
-static void __init kona_timers_init(struct device_node *node)
-{
- u32 freq;
- struct clk *external_clk;
-
- external_clk = of_clk_get_by_name(node, NULL);
-
- if (!IS_ERR(external_clk)) {
- arch_timer_rate = clk_get_rate(external_clk);
- clk_prepare_enable(external_clk);
- } else if (!of_property_read_u32(node, "clock-frequency", &freq)) {
- arch_timer_rate = freq;
- } else {
- panic("unable to determine clock-frequency");
- }
-
- /* Setup IRQ numbers */
- timers.tmr_irq = irq_of_parse_and_map(node, 0);
-
- /* Setup IO addresses */
- timers.tmr_regs = of_iomap(node, 0);
-
- kona_timer_disable_and_clear(timers.tmr_regs);
-}
-
static int kona_timer_set_next_event(unsigned long clc,
struct clock_event_device *unused)
{
@@ -198,7 +173,34 @@ static struct irqaction kona_timer_irq = {
static void __init kona_timer_init(struct device_node *node)
{
- kona_timers_init(node);
+ u32 freq;
+ struct clk *external_clk;
+
+ if (!of_device_is_available(node)) {
+ pr_info("Kona Timer v1 marked as disabled in device tree\n");
+ return;
+ }
+
+ external_clk = of_clk_get_by_name(node, NULL);
+
+ if (!IS_ERR(external_clk)) {
+ arch_timer_rate = clk_get_rate(external_clk);
+ clk_prepare_enable(external_clk);
+ } else if (!of_property_read_u32(node, "clock-frequency", &freq)) {
+ arch_timer_rate = freq;
+ } else {
+ pr_err("Kona Timer v1 unable to determine clock-frequency");
+ return;
+ }
+
+ /* Setup IRQ numbers */
+ timers.tmr_irq = irq_of_parse_and_map(node, 0);
+
+ /* Setup IO addresses */
+ timers.tmr_regs = of_iomap(node, 0);
+
+ kona_timer_disable_and_clear(timers.tmr_regs);
+
kona_timer_clockevents_init();
setup_irq(timers.tmr_irq, &kona_timer_irq);
kona_timer_set_next_event((arch_timer_rate / HZ), NULL);
diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c
index 63f176de0d02..49fbe2847c84 100644
--- a/drivers/clocksource/cadence_ttc_timer.c
+++ b/drivers/clocksource/cadence_ttc_timer.c
@@ -16,6 +16,7 @@
*/
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/interrupt.h>
#include <linux/clockchips.h>
#include <linux/of_address.h>
@@ -52,6 +53,8 @@
#define TTC_CNT_CNTRL_DISABLE_MASK 0x1
#define TTC_CLK_CNTRL_CSRC_MASK (1 << 5) /* clock source */
+#define TTC_CLK_CNTRL_PSV_MASK 0x1e
+#define TTC_CLK_CNTRL_PSV_SHIFT 1
/*
* Setup the timers to use pre-scaling, using a fixed value for now that will
@@ -63,6 +66,8 @@
#define CLK_CNTRL_PRESCALE_EN 1
#define CNT_CNTRL_RESET (1 << 4)
+#define MAX_F_ERR 50
+
/**
* struct ttc_timer - This definition defines local timer structure
*
@@ -82,6 +87,8 @@ struct ttc_timer {
container_of(x, struct ttc_timer, clk_rate_change_nb)
struct ttc_timer_clocksource {
+ u32 scale_clk_ctrl_reg_old;
+ u32 scale_clk_ctrl_reg_new;
struct ttc_timer ttc;
struct clocksource cs;
};
@@ -229,32 +236,89 @@ static int ttc_rate_change_clocksource_cb(struct notifier_block *nb,
struct ttc_timer_clocksource, ttc);
switch (event) {
- case POST_RATE_CHANGE:
+ case PRE_RATE_CHANGE:
+ {
+ u32 psv;
+ unsigned long factor, rate_low, rate_high;
+
+ if (ndata->new_rate > ndata->old_rate) {
+ factor = DIV_ROUND_CLOSEST(ndata->new_rate,
+ ndata->old_rate);
+ rate_low = ndata->old_rate;
+ rate_high = ndata->new_rate;
+ } else {
+ factor = DIV_ROUND_CLOSEST(ndata->old_rate,
+ ndata->new_rate);
+ rate_low = ndata->new_rate;
+ rate_high = ndata->old_rate;
+ }
+
+ if (!is_power_of_2(factor))
+ return NOTIFY_BAD;
+
+ if (abs(rate_high - (factor * rate_low)) > MAX_F_ERR)
+ return NOTIFY_BAD;
+
+ factor = __ilog2_u32(factor);
+
/*
- * Do whatever is necessary to maintain a proper time base
- *
- * I cannot find a way to adjust the currently used clocksource
- * to the new frequency. __clocksource_updatefreq_hz() sounds
- * good, but does not work. Not sure what's that missing.
- *
- * This approach works, but triggers two clocksource switches.
- * The first after unregister to clocksource jiffies. And
- * another one after the register to the newly registered timer.
- *
- * Alternatively we could 'waste' another HW timer to ping pong
- * between clock sources. That would also use one register and
- * one unregister call, but only trigger one clocksource switch
- * for the cost of another HW timer used by the OS.
+ * store timer clock ctrl register so we can restore it in case
+ * of an abort.
*/
- clocksource_unregister(&ttccs->cs);
- clocksource_register_hz(&ttccs->cs,
- ndata->new_rate / PRESCALE);
- /* fall through */
- case PRE_RATE_CHANGE:
+ ttccs->scale_clk_ctrl_reg_old =
+ __raw_readl(ttccs->ttc.base_addr +
+ TTC_CLK_CNTRL_OFFSET);
+
+ psv = (ttccs->scale_clk_ctrl_reg_old &
+ TTC_CLK_CNTRL_PSV_MASK) >>
+ TTC_CLK_CNTRL_PSV_SHIFT;
+ if (ndata->new_rate < ndata->old_rate)
+ psv -= factor;
+ else
+ psv += factor;
+
+ /* prescaler within legal range? */
+ if (psv & ~(TTC_CLK_CNTRL_PSV_MASK >> TTC_CLK_CNTRL_PSV_SHIFT))
+ return NOTIFY_BAD;
+
+ ttccs->scale_clk_ctrl_reg_new = ttccs->scale_clk_ctrl_reg_old &
+ ~TTC_CLK_CNTRL_PSV_MASK;
+ ttccs->scale_clk_ctrl_reg_new |= psv << TTC_CLK_CNTRL_PSV_SHIFT;
+
+
+ /* scale down: adjust divider in post-change notification */
+ if (ndata->new_rate < ndata->old_rate)
+ return NOTIFY_DONE;
+
+ /* scale up: adjust divider now - before frequency change */
+ __raw_writel(ttccs->scale_clk_ctrl_reg_new,
+ ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET);
+ break;
+ }
+ case POST_RATE_CHANGE:
+ /* scale up: pre-change notification did the adjustment */
+ if (ndata->new_rate > ndata->old_rate)
+ return NOTIFY_OK;
+
+ /* scale down: adjust divider now - after frequency change */
+ __raw_writel(ttccs->scale_clk_ctrl_reg_new,
+ ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET);
+ break;
+
case ABORT_RATE_CHANGE:
+ /* we have to undo the adjustment in case we scale up */
+ if (ndata->new_rate < ndata->old_rate)
+ return NOTIFY_OK;
+
+ /* restore original register value */
+ __raw_writel(ttccs->scale_clk_ctrl_reg_old,
+ ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET);
+ /* fall through */
default:
return NOTIFY_DONE;
}
+
+ return NOTIFY_DONE;
}
static void __init ttc_setup_clocksource(struct clk *clk, void __iomem *base)
@@ -321,25 +385,12 @@ static int ttc_rate_change_clockevent_cb(struct notifier_block *nb,
switch (event) {
case POST_RATE_CHANGE:
- {
- unsigned long flags;
-
- /*
- * clockevents_update_freq should be called with IRQ disabled on
- * the CPU the timer provides events for. The timer we use is
- * common to both CPUs, not sure if we need to run on both
- * cores.
- */
- local_irq_save(flags);
- clockevents_update_freq(&ttcce->ce,
- ndata->new_rate / PRESCALE);
- local_irq_restore(flags);
-
/* update cached frequency */
ttc->freq = ndata->new_rate;
+ clockevents_update_freq(&ttcce->ce, ndata->new_rate / PRESCALE);
+
/* fall through */
- }
case PRE_RATE_CHANGE:
case ABORT_RATE_CHANGE:
default:
diff --git a/drivers/clocksource/cyclone.c b/drivers/clocksource/cyclone.c
deleted file mode 100644
index 9e0998f22885..000000000000
--- a/drivers/clocksource/cyclone.c
+++ /dev/null
@@ -1,113 +0,0 @@
-#include <linux/clocksource.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/timex.h>
-#include <linux/init.h>
-
-#include <asm/pgtable.h>
-#include <asm/io.h>
-
-#include <asm/mach_timer.h>
-
-#define CYCLONE_CBAR_ADDR 0xFEB00CD0 /* base address ptr */
-#define CYCLONE_PMCC_OFFSET 0x51A0 /* offset to control register */
-#define CYCLONE_MPCS_OFFSET 0x51A8 /* offset to select register */
-#define CYCLONE_MPMC_OFFSET 0x51D0 /* offset to count register */
-#define CYCLONE_TIMER_FREQ 99780000 /* 100Mhz, but not really */
-#define CYCLONE_TIMER_MASK CLOCKSOURCE_MASK(32) /* 32 bit mask */
-
-int use_cyclone = 0;
-static void __iomem *cyclone_ptr;
-
-static cycle_t read_cyclone(struct clocksource *cs)
-{
- return (cycle_t)readl(cyclone_ptr);
-}
-
-static struct clocksource clocksource_cyclone = {
- .name = "cyclone",
- .rating = 250,
- .read = read_cyclone,
- .mask = CYCLONE_TIMER_MASK,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static int __init init_cyclone_clocksource(void)
-{
- unsigned long base; /* saved value from CBAR */
- unsigned long offset;
- u32 __iomem* volatile cyclone_timer; /* Cyclone MPMC0 register */
- u32 __iomem* reg;
- int i;
-
- /* make sure we're on a summit box: */
- if (!use_cyclone)
- return -ENODEV;
-
- printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
-
- /* find base address: */
- offset = CYCLONE_CBAR_ADDR;
- reg = ioremap_nocache(offset, sizeof(reg));
- if (!reg) {
- printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n");
- return -ENODEV;
- }
- /* even on 64bit systems, this is only 32bits: */
- base = readl(reg);
- iounmap(reg);
- if (!base) {
- printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
- return -ENODEV;
- }
-
- /* setup PMCC: */
- offset = base + CYCLONE_PMCC_OFFSET;
- reg = ioremap_nocache(offset, sizeof(reg));
- if (!reg) {
- printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n");
- return -ENODEV;
- }
- writel(0x00000001,reg);
- iounmap(reg);
-
- /* setup MPCS: */
- offset = base + CYCLONE_MPCS_OFFSET;
- reg = ioremap_nocache(offset, sizeof(reg));
- if (!reg) {
- printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n");
- return -ENODEV;
- }
- writel(0x00000001,reg);
- iounmap(reg);
-
- /* map in cyclone_timer: */
- offset = base + CYCLONE_MPMC_OFFSET;
- cyclone_timer = ioremap_nocache(offset, sizeof(u64));
- if (!cyclone_timer) {
- printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n");
- return -ENODEV;
- }
-
- /* quick test to make sure its ticking: */
- for (i = 0; i < 3; i++){
- u32 old = readl(cyclone_timer);
- int stall = 100;
-
- while (stall--)
- barrier();
-
- if (readl(cyclone_timer) == old) {
- printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n");
- iounmap(cyclone_timer);
- cyclone_timer = NULL;
- return -ENODEV;
- }
- }
- cyclone_ptr = cyclone_timer;
-
- return clocksource_register_hz(&clocksource_cyclone,
- CYCLONE_TIMER_FREQ);
-}
-
-arch_initcall(init_cyclone_clocksource);
diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c
index 48f76bc05da0..c2e390efbdca 100644
--- a/drivers/clocksource/exynos_mct.c
+++ b/drivers/clocksource/exynos_mct.c
@@ -410,7 +410,7 @@ static int exynos4_local_timer_setup(struct clock_event_device *evt)
mevt = container_of(evt, struct mct_clock_event_device, evt);
mevt->base = EXYNOS4_MCT_L_BASE(cpu);
- sprintf(mevt->name, "mct_tick%d", cpu);
+ snprintf(mevt->name, sizeof(mevt->name), "mct_tick%d", cpu);
evt->name = mevt->name;
evt->cpumask = cpumask_of(cpu);
diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c
index bf497afba9ad..efb17c3ee120 100644
--- a/drivers/clocksource/sun4i_timer.c
+++ b/drivers/clocksource/sun4i_timer.c
@@ -196,5 +196,5 @@ static void __init sun4i_timer_init(struct device_node *node)
clockevents_config_and_register(&sun4i_clockevent, rate,
TIMER_SYNC_TICKS, 0xffffffff);
}
-CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-timer",
+CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-a10-timer",
sun4i_timer_init);
diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c
index ee8691b89944..0451e62fac7a 100644
--- a/drivers/clocksource/time-armada-370-xp.c
+++ b/drivers/clocksource/time-armada-370-xp.c
@@ -85,12 +85,6 @@ static u32 ticks_per_jiffy;
static struct clock_event_device __percpu *armada_370_xp_evt;
-static void timer_ctrl_clrset(u32 clr, u32 set)
-{
- writel((readl(timer_base + TIMER_CTRL_OFF) & ~clr) | set,
- timer_base + TIMER_CTRL_OFF);
-}
-
static void local_timer_ctrl_clrset(u32 clr, u32 set)
{
writel((readl(local_base + TIMER_CTRL_OFF) & ~clr) | set,
@@ -245,7 +239,7 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np)
clr = TIMER0_25MHZ;
enable_mask = TIMER0_EN | TIMER0_DIV(TIMER_DIVIDER_SHIFT);
}
- timer_ctrl_clrset(clr, set);
+ atomic_io_modify(timer_base + TIMER_CTRL_OFF, clr | set, set);
local_timer_ctrl_clrset(clr, set);
/*
@@ -263,7 +257,9 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np)
writel(0xffffffff, timer_base + TIMER0_VAL_OFF);
writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF);
- timer_ctrl_clrset(0, TIMER0_RELOAD_EN | enable_mask);
+ atomic_io_modify(timer_base + TIMER_CTRL_OFF,
+ TIMER0_RELOAD_EN | enable_mask,
+ TIMER0_RELOAD_EN | enable_mask);
/*
* Set scale and timer for sched_clock.
diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/time-orion.c
index 20066222f3f2..0b3ce0399c51 100644
--- a/drivers/clocksource/time-orion.c
+++ b/drivers/clocksource/time-orion.c
@@ -35,20 +35,6 @@
#define ORION_ONESHOT_MAX 0xfffffffe
static void __iomem *timer_base;
-static DEFINE_SPINLOCK(timer_ctrl_lock);
-
-/*
- * Thread-safe access to TIMER_CTRL register
- * (shared with watchdog timer)
- */
-void orion_timer_ctrl_clrset(u32 clr, u32 set)
-{
- spin_lock(&timer_ctrl_lock);
- writel((readl(timer_base + TIMER_CTRL) & ~clr) | set,
- timer_base + TIMER_CTRL);
- spin_unlock(&timer_ctrl_lock);
-}
-EXPORT_SYMBOL(orion_timer_ctrl_clrset);
/*
* Free-running clocksource handling.
@@ -68,7 +54,8 @@ static int orion_clkevt_next_event(unsigned long delta,
{
/* setup and enable one-shot timer */
writel(delta, timer_base + TIMER1_VAL);
- orion_timer_ctrl_clrset(TIMER1_RELOAD_EN, TIMER1_EN);
+ atomic_io_modify(timer_base + TIMER_CTRL,
+ TIMER1_RELOAD_EN | TIMER1_EN, TIMER1_EN);
return 0;
}
@@ -80,10 +67,13 @@ static void orion_clkevt_mode(enum clock_event_mode mode,
/* setup and enable periodic timer at 1/HZ intervals */
writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD);
writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL);
- orion_timer_ctrl_clrset(0, TIMER1_RELOAD_EN | TIMER1_EN);
+ atomic_io_modify(timer_base + TIMER_CTRL,
+ TIMER1_RELOAD_EN | TIMER1_EN,
+ TIMER1_RELOAD_EN | TIMER1_EN);
} else {
/* disable timer */
- orion_timer_ctrl_clrset(TIMER1_RELOAD_EN | TIMER1_EN, 0);
+ atomic_io_modify(timer_base + TIMER_CTRL,
+ TIMER1_RELOAD_EN | TIMER1_EN, 0);
}
}
@@ -131,7 +121,9 @@ static void __init orion_timer_init(struct device_node *np)
/* setup timer0 as free-running clocksource */
writel(~0, timer_base + TIMER0_VAL);
writel(~0, timer_base + TIMER0_RELOAD);
- orion_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | TIMER0_EN);
+ atomic_io_modify(timer_base + TIMER_CTRL,
+ TIMER0_RELOAD_EN | TIMER0_EN,
+ TIMER0_RELOAD_EN | TIMER0_EN);
clocksource_mmio_init(timer_base + TIMER0_VAL, "orion_clocksource",
clk_get_rate(clk), 300, 32,
clocksource_mmio_readl_down);
diff --git a/drivers/clocksource/timer-keystone.c b/drivers/clocksource/timer-keystone.c
new file mode 100644
index 000000000000..0250354f7e55
--- /dev/null
+++ b/drivers/clocksource/timer-keystone.c
@@ -0,0 +1,241 @@
+/*
+ * Keystone broadcast clock-event
+ *
+ * Copyright 2013 Texas Instruments, Inc.
+ *
+ * Author: Ivan Khoronzhuk <ivan.khoronzhuk@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 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/interrupt.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#define TIMER_NAME "timer-keystone"
+
+/* Timer register offsets */
+#define TIM12 0x10
+#define TIM34 0x14
+#define PRD12 0x18
+#define PRD34 0x1c
+#define TCR 0x20
+#define TGCR 0x24
+#define INTCTLSTAT 0x44
+
+/* Timer register bitfields */
+#define TCR_ENAMODE_MASK 0xC0
+#define TCR_ENAMODE_ONESHOT_MASK 0x40
+#define TCR_ENAMODE_PERIODIC_MASK 0x80
+
+#define TGCR_TIM_UNRESET_MASK 0x03
+#define INTCTLSTAT_ENINT_MASK 0x01
+
+/**
+ * struct keystone_timer: holds timer's data
+ * @base: timer memory base address
+ * @hz_period: cycles per HZ period
+ * @event_dev: event device based on timer
+ */
+static struct keystone_timer {
+ void __iomem *base;
+ unsigned long hz_period;
+ struct clock_event_device event_dev;
+} timer;
+
+static inline u32 keystone_timer_readl(unsigned long rg)
+{
+ return readl_relaxed(timer.base + rg);
+}
+
+static inline void keystone_timer_writel(u32 val, unsigned long rg)
+{
+ writel_relaxed(val, timer.base + rg);
+}
+
+/**
+ * keystone_timer_barrier: write memory barrier
+ * use explicit barrier to avoid using readl/writel non relaxed function
+ * variants, because in our case non relaxed variants hide the true places
+ * where barrier is needed.
+ */
+static inline void keystone_timer_barrier(void)
+{
+ __iowmb();
+}
+
+/**
+ * keystone_timer_config: configures timer to work in oneshot/periodic modes.
+ * @ mode: mode to configure
+ * @ period: cycles number to configure for
+ */
+static int keystone_timer_config(u64 period, enum clock_event_mode mode)
+{
+ u32 tcr;
+ u32 off;
+
+ tcr = keystone_timer_readl(TCR);
+ off = tcr & ~(TCR_ENAMODE_MASK);
+
+ /* set enable mode */
+ switch (mode) {
+ case CLOCK_EVT_MODE_ONESHOT:
+ tcr |= TCR_ENAMODE_ONESHOT_MASK;
+ break;
+ case CLOCK_EVT_MODE_PERIODIC:
+ tcr |= TCR_ENAMODE_PERIODIC_MASK;
+ break;
+ default:
+ return -1;
+ }
+
+ /* disable timer */
+ keystone_timer_writel(off, TCR);
+ /* here we have to be sure the timer has been disabled */
+ keystone_timer_barrier();
+
+ /* reset counter to zero, set new period */
+ keystone_timer_writel(0, TIM12);
+ keystone_timer_writel(0, TIM34);
+ keystone_timer_writel(period & 0xffffffff, PRD12);
+ keystone_timer_writel(period >> 32, PRD34);
+
+ /*
+ * enable timer
+ * here we have to be sure that CNTLO, CNTHI, PRDLO, PRDHI registers
+ * have been written.
+ */
+ keystone_timer_barrier();
+ keystone_timer_writel(tcr, TCR);
+ return 0;
+}
+
+static void keystone_timer_disable(void)
+{
+ u32 tcr;
+
+ tcr = keystone_timer_readl(TCR);
+
+ /* disable timer */
+ tcr &= ~(TCR_ENAMODE_MASK);
+ keystone_timer_writel(tcr, TCR);
+}
+
+static irqreturn_t keystone_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+
+ evt->event_handler(evt);
+ return IRQ_HANDLED;
+}
+
+static int keystone_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ return keystone_timer_config(cycles, evt->mode);
+}
+
+static void keystone_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ keystone_timer_config(timer.hz_period, CLOCK_EVT_MODE_PERIODIC);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_ONESHOT:
+ keystone_timer_disable();
+ break;
+ default:
+ break;
+ }
+}
+
+static void __init keystone_timer_init(struct device_node *np)
+{
+ struct clock_event_device *event_dev = &timer.event_dev;
+ unsigned long rate;
+ struct clk *clk;
+ int irq, error;
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (irq == NO_IRQ) {
+ pr_err("%s: failed to map interrupts\n", __func__);
+ return;
+ }
+
+ timer.base = of_iomap(np, 0);
+ if (!timer.base) {
+ pr_err("%s: failed to map registers\n", __func__);
+ return;
+ }
+
+ clk = of_clk_get(np, 0);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to get clock\n", __func__);
+ iounmap(timer.base);
+ return;
+ }
+
+ error = clk_prepare_enable(clk);
+ if (error) {
+ pr_err("%s: failed to enable clock\n", __func__);
+ goto err;
+ }
+
+ rate = clk_get_rate(clk);
+
+ /* disable, use internal clock source */
+ keystone_timer_writel(0, TCR);
+ /* here we have to be sure the timer has been disabled */
+ keystone_timer_barrier();
+
+ /* reset timer as 64-bit, no pre-scaler, plus features are disabled */
+ keystone_timer_writel(0, TGCR);
+
+ /* unreset timer */
+ keystone_timer_writel(TGCR_TIM_UNRESET_MASK, TGCR);
+
+ /* init counter to zero */
+ keystone_timer_writel(0, TIM12);
+ keystone_timer_writel(0, TIM34);
+
+ timer.hz_period = DIV_ROUND_UP(rate, HZ);
+
+ /* enable timer interrupts */
+ keystone_timer_writel(INTCTLSTAT_ENINT_MASK, INTCTLSTAT);
+
+ error = request_irq(irq, keystone_timer_interrupt, IRQF_TIMER,
+ TIMER_NAME, event_dev);
+ if (error) {
+ pr_err("%s: failed to setup irq\n", __func__);
+ goto err;
+ }
+
+ /* setup clockevent */
+ event_dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+ event_dev->set_next_event = keystone_set_next_event;
+ event_dev->set_mode = keystone_set_mode;
+ event_dev->cpumask = cpu_all_mask;
+ event_dev->owner = THIS_MODULE;
+ event_dev->name = TIMER_NAME;
+ event_dev->irq = irq;
+
+ clockevents_config_and_register(event_dev, rate, 1, ULONG_MAX);
+
+ pr_info("keystone timer clock @%lu Hz\n", rate);
+ return;
+err:
+ clk_put(clk);
+ iounmap(timer.base);
+}
+
+CLOCKSOURCE_OF_DECLARE(keystone_timer, "ti,keystone-timer",
+ keystone_timer_init);
diff --git a/arch/arm/mach-u300/timer.c b/drivers/clocksource/timer-u300.c
index fe08fd34c0ce..e63d469661fd 100644
--- a/arch/arm/mach-u300/timer.c
+++ b/drivers/clocksource/timer-u300.c
@@ -1,8 +1,4 @@
/*
- *
- * arch/arm/mach-u300/timer.c
- *
- *
* Copyright (C) 2007-2009 ST-Ericsson AB
* License terms: GNU General Public License (GPL) version 2
* Timer COH 901 328, runs the OS timer interrupt.
diff --git a/drivers/clocksource/vf_pit_timer.c b/drivers/clocksource/vf_pit_timer.c
index 02821b06a39e..a918bc481c52 100644
--- a/drivers/clocksource/vf_pit_timer.c
+++ b/drivers/clocksource/vf_pit_timer.c
@@ -54,7 +54,7 @@ static inline void pit_irq_acknowledge(void)
static u64 pit_read_sched_clock(void)
{
- return __raw_readl(clksrc_base + PITCVAL);
+ return ~__raw_readl(clksrc_base + PITCVAL);
}
static int __init pit_clocksource_init(unsigned long rate)
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
index 18c5b9b16645..148d707a1d43 100644
--- a/drivers/connector/cn_proc.c
+++ b/drivers/connector/cn_proc.c
@@ -95,7 +95,7 @@ void proc_fork_connector(struct task_struct *task)
msg->len = sizeof(*ev);
msg->flags = 0; /* not used */
/* If cn_netlink_send() failed, the data is not sent */
- cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+ cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
}
void proc_exec_connector(struct task_struct *task)
@@ -122,7 +122,7 @@ void proc_exec_connector(struct task_struct *task)
msg->ack = 0; /* not used */
msg->len = sizeof(*ev);
msg->flags = 0; /* not used */
- cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+ cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
}
void proc_id_connector(struct task_struct *task, int which_id)
@@ -163,7 +163,7 @@ void proc_id_connector(struct task_struct *task, int which_id)
msg->ack = 0; /* not used */
msg->len = sizeof(*ev);
msg->flags = 0; /* not used */
- cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+ cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
}
void proc_sid_connector(struct task_struct *task)
@@ -190,7 +190,7 @@ void proc_sid_connector(struct task_struct *task)
msg->ack = 0; /* not used */
msg->len = sizeof(*ev);
msg->flags = 0; /* not used */
- cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+ cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
}
void proc_ptrace_connector(struct task_struct *task, int ptrace_id)
@@ -225,7 +225,7 @@ void proc_ptrace_connector(struct task_struct *task, int ptrace_id)
msg->ack = 0; /* not used */
msg->len = sizeof(*ev);
msg->flags = 0; /* not used */
- cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+ cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
}
void proc_comm_connector(struct task_struct *task)
@@ -253,7 +253,7 @@ void proc_comm_connector(struct task_struct *task)
msg->ack = 0; /* not used */
msg->len = sizeof(*ev);
msg->flags = 0; /* not used */
- cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+ cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
}
void proc_coredump_connector(struct task_struct *task)
@@ -280,7 +280,7 @@ void proc_coredump_connector(struct task_struct *task)
msg->ack = 0; /* not used */
msg->len = sizeof(*ev);
msg->flags = 0; /* not used */
- cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+ cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
}
void proc_exit_connector(struct task_struct *task)
@@ -309,7 +309,7 @@ void proc_exit_connector(struct task_struct *task)
msg->ack = 0; /* not used */
msg->len = sizeof(*ev);
msg->flags = 0; /* not used */
- cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+ cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
}
/*
@@ -343,7 +343,7 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
msg->ack = rcvd_ack + 1;
msg->len = sizeof(*ev);
msg->flags = 0; /* not used */
- cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+ cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
}
/**
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index a36749f1e44a..b14f1d36f897 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -50,7 +50,7 @@ static int cn_already_initialized;
*
* Sequence number is incremented with each message to be sent.
*
- * If we expect reply to our message then the sequence number in
+ * If we expect a reply to our message then the sequence number in
* received message MUST be the same as in original message, and
* acknowledge number MUST be the same + 1.
*
@@ -62,8 +62,11 @@ static int cn_already_initialized;
* the acknowledgement number in the original message + 1, then it is
* a new message.
*
+ * The message is sent to, the portid if given, the group if given, both if
+ * both, or if both are zero then the group is looked up and sent there.
*/
-int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)
+int cn_netlink_send(struct cn_msg *msg, u32 portid, u32 __group,
+ gfp_t gfp_mask)
{
struct cn_callback_entry *__cbq;
unsigned int size;
@@ -74,7 +77,9 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)
u32 group = 0;
int found = 0;
- if (!__group) {
+ if (portid || __group) {
+ group = __group;
+ } else {
spin_lock_bh(&dev->cbdev->queue_lock);
list_for_each_entry(__cbq, &dev->cbdev->queue_list,
callback_entry) {
@@ -88,11 +93,9 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)
if (!found)
return -ENODEV;
- } else {
- group = __group;
}
- if (!netlink_has_listeners(dev->nls, group))
+ if (!portid && !netlink_has_listeners(dev->nls, group))
return -ESRCH;
size = sizeof(*msg) + msg->len;
@@ -113,7 +116,10 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)
NETLINK_CB(skb).dst_group = group;
- return netlink_broadcast(dev->nls, skb, 0, group, gfp_mask);
+ if (group)
+ return netlink_broadcast(dev->nls, skb, portid, group,
+ gfp_mask);
+ return netlink_unicast(dev->nls, skb, portid, !(gfp_mask&__GFP_WAIT));
}
EXPORT_SYMBOL_GPL(cn_netlink_send);
@@ -139,7 +145,6 @@ static int cn_call_callback(struct sk_buff *skb)
spin_unlock_bh(&dev->cbdev->queue_lock);
if (cbq != NULL) {
- err = 0;
cbq->callback(msg, nsp);
kfree_skb(skb);
cn_queue_release_callback(cbq);
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 4b029c0944af..1fbe11f2a146 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -200,7 +200,7 @@ source "drivers/cpufreq/Kconfig.x86"
endmenu
menu "ARM CPU frequency scaling drivers"
-depends on ARM
+depends on ARM || ARM64
source "drivers/cpufreq/Kconfig.arm"
endmenu
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 31297499a60a..9fb627046e17 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -2,6 +2,7 @@
# ARM CPU Frequency scaling drivers
#
+# big LITTLE core layer and glue drivers
config ARM_BIG_LITTLE_CPUFREQ
tristate "Generic ARM big LITTLE CPUfreq driver"
depends on ARM && BIG_LITTLE && ARM_CPU_TOPOLOGY && HAVE_CLK
@@ -16,6 +17,14 @@ config ARM_DT_BL_CPUFREQ
This enables probing via DT for Generic CPUfreq driver for ARM
big.LITTLE platform. This gets frequency tables from DT.
+config ARM_VEXPRESS_SPC_CPUFREQ
+ tristate "Versatile Express SPC based CPUfreq driver"
+ depends on ARM_BIG_LITTLE_CPUFREQ && ARCH_VEXPRESS_SPC
+ help
+ This add the CPUfreq driver support for Versatile Express
+ big.LITTLE platforms using SPC for power management.
+
+
config ARM_EXYNOS_CPUFREQ
bool
@@ -241,11 +250,3 @@ config ARM_TEGRA_CPUFREQ
default y
help
This adds the CPUFreq driver support for TEGRA SOCs.
-
-config ARM_VEXPRESS_SPC_CPUFREQ
- tristate "Versatile Express SPC based CPUfreq driver"
- select ARM_BIG_LITTLE_CPUFREQ
- depends on ARCH_VEXPRESS_SPC
- help
- This add the CPUfreq driver support for Versatile Express
- big.LITTLE platforms using SPC for power management.
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 18448a7e9f86..822ca03a87f7 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -855,7 +855,6 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
pr_debug("acpi_cpufreq_cpu_exit\n");
if (data) {
- cpufreq_frequency_table_put_attr(policy->cpu);
per_cpu(acfreq_data, policy->cpu) = NULL;
acpi_processor_unregister_performance(data->acpi_data,
policy->cpu);
diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
index 72f87e9317e3..bad2ed317ba2 100644
--- a/drivers/cpufreq/arm_big_little.c
+++ b/drivers/cpufreq/arm_big_little.c
@@ -446,9 +446,12 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy)
}
if (cur_cluster < MAX_CLUSTERS) {
+ int cpu;
+
cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu));
- per_cpu(physical_cluster, policy->cpu) = cur_cluster;
+ for_each_cpu(cpu, policy->cpus)
+ per_cpu(physical_cluster, cpu) = cur_cluster;
} else {
/* Assumption: during init, we are always running on A15 */
per_cpu(physical_cluster, policy->cpu) = A15_CLUSTER;
@@ -478,7 +481,6 @@ static int bL_cpufreq_exit(struct cpufreq_policy *policy)
return -ENODEV;
}
- cpufreq_frequency_table_put_attr(policy->cpu);
put_cluster_clk_and_freq_table(cpu_dev);
dev_dbg(cpu_dev, "%s: Exited, cpu: %d\n", __func__, policy->cpu);
diff --git a/drivers/cpufreq/blackfin-cpufreq.c b/drivers/cpufreq/blackfin-cpufreq.c
index e9e63fc9c2c9..a9f8e5bd0716 100644
--- a/drivers/cpufreq/blackfin-cpufreq.c
+++ b/drivers/cpufreq/blackfin-cpufreq.c
@@ -195,7 +195,6 @@ static struct cpufreq_driver bfin_driver = {
.target_index = bfin_target,
.get = bfin_getfreq_khz,
.init = __bfin_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "bfin cpufreq",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
index 0c12ffc0ebcb..1bf6bbac3e03 100644
--- a/drivers/cpufreq/cpufreq-cpu0.c
+++ b/drivers/cpufreq/cpufreq-cpu0.c
@@ -109,7 +109,6 @@ static struct cpufreq_driver cpu0_cpufreq_driver = {
.target_index = cpu0_set_target,
.get = cpufreq_generic_get,
.init = cpu0_cpufreq_init,
- .exit = cpufreq_generic_exit,
.name = "generic_cpu0",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/cpufreq-nforce2.c b/drivers/cpufreq/cpufreq-nforce2.c
index a05b876f375e..bc447b9003c3 100644
--- a/drivers/cpufreq/cpufreq-nforce2.c
+++ b/drivers/cpufreq/cpufreq-nforce2.c
@@ -270,7 +270,7 @@ static int nforce2_target(struct cpufreq_policy *policy,
pr_debug("Old CPU frequency %d kHz, new %d kHz\n",
freqs.old, freqs.new);
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
/* Disable IRQs */
/* local_irq_save(flags); */
@@ -285,7 +285,7 @@ static int nforce2_target(struct cpufreq_policy *policy,
/* Enable IRQs */
/* local_irq_restore(flags); */
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freq_transition_end(policy, &freqs, 0);
return 0;
}
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 08ca8c9f41cd..abda6609d3e7 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -26,7 +26,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
-#include <linux/syscore_ops.h>
+#include <linux/suspend.h>
#include <linux/tick.h>
#include <trace/events/power.h>
@@ -42,10 +42,11 @@ static DEFINE_RWLOCK(cpufreq_driver_lock);
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 */
static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
-#endif
+
+/* Flag to suspend/resume CPUFreq governors */
+static bool cpufreq_suspended;
static inline bool has_target(void)
{
@@ -181,8 +182,8 @@ unsigned int cpufreq_generic_get(unsigned int cpu)
struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
if (!policy || IS_ERR(policy->clk)) {
- pr_err("%s: No %s associated to cpu: %d\n", __func__,
- policy ? "clk" : "policy", cpu);
+ pr_err("%s: No %s associated to cpu: %d\n",
+ __func__, policy ? "clk" : "policy", cpu);
return 0;
}
@@ -190,6 +191,12 @@ unsigned int cpufreq_generic_get(unsigned int cpu)
}
EXPORT_SYMBOL_GPL(cpufreq_generic_get);
+/* Only for cpufreq core internal use */
+struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu)
+{
+ return per_cpu(cpufreq_cpu_data, cpu);
+}
+
struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
{
struct cpufreq_policy *policy = NULL;
@@ -254,15 +261,14 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
if (!l_p_j_ref_freq) {
l_p_j_ref = loops_per_jiffy;
l_p_j_ref_freq = ci->old;
- pr_debug("saving %lu as reference value for loops_per_jiffy; "
- "freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq);
+ pr_debug("saving %lu as reference value for loops_per_jiffy; freq is %u kHz\n",
+ l_p_j_ref, l_p_j_ref_freq);
}
- if ((val == CPUFREQ_POSTCHANGE && ci->old != ci->new) ||
- (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
+ if (val == CPUFREQ_POSTCHANGE && ci->old != ci->new) {
loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq,
ci->new);
- pr_debug("scaling loops_per_jiffy to %lu "
- "for frequency %u kHz\n", loops_per_jiffy, ci->new);
+ pr_debug("scaling loops_per_jiffy to %lu for frequency %u kHz\n",
+ loops_per_jiffy, ci->new);
}
}
#else
@@ -282,7 +288,7 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
freqs->flags = cpufreq_driver->flags;
pr_debug("notification %u of frequency transition to %u kHz\n",
- state, freqs->new);
+ state, freqs->new);
switch (state) {
@@ -294,9 +300,8 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
if ((policy) && (policy->cpu == freqs->cpu) &&
(policy->cur) && (policy->cur != freqs->old)) {
- pr_debug("Warning: CPU frequency is"
- " %u, cpufreq assumed %u kHz.\n",
- freqs->old, policy->cur);
+ pr_debug("Warning: CPU frequency is %u, cpufreq assumed %u kHz\n",
+ freqs->old, policy->cur);
freqs->old = policy->cur;
}
}
@@ -307,8 +312,8 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
case CPUFREQ_POSTCHANGE:
adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
- pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
- (unsigned long)freqs->cpu);
+ pr_debug("FREQ: %lu - CPU: %lu\n",
+ (unsigned long)freqs->new, (unsigned long)freqs->cpu);
trace_cpu_frequency(freqs->new, freqs->cpu);
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_POSTCHANGE, freqs);
@@ -326,16 +331,15 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
* function. It is called twice on all CPU frequency changes that have
* external effects.
*/
-void cpufreq_notify_transition(struct cpufreq_policy *policy,
+static void cpufreq_notify_transition(struct cpufreq_policy *policy,
struct cpufreq_freqs *freqs, unsigned int state)
{
for_each_cpu(freqs->cpu, policy->cpus)
__cpufreq_notify_transition(policy, freqs, state);
}
-EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
/* Do post notifications when there are chances that transition has failed */
-void cpufreq_notify_post_transition(struct cpufreq_policy *policy,
+static void cpufreq_notify_post_transition(struct cpufreq_policy *policy,
struct cpufreq_freqs *freqs, int transition_failed)
{
cpufreq_notify_transition(policy, freqs, CPUFREQ_POSTCHANGE);
@@ -346,13 +350,47 @@ void cpufreq_notify_post_transition(struct cpufreq_policy *policy,
cpufreq_notify_transition(policy, freqs, CPUFREQ_PRECHANGE);
cpufreq_notify_transition(policy, freqs, CPUFREQ_POSTCHANGE);
}
-EXPORT_SYMBOL_GPL(cpufreq_notify_post_transition);
+
+void cpufreq_freq_transition_begin(struct cpufreq_policy *policy,
+ struct cpufreq_freqs *freqs)
+{
+wait:
+ wait_event(policy->transition_wait, !policy->transition_ongoing);
+
+ spin_lock(&policy->transition_lock);
+
+ if (unlikely(policy->transition_ongoing)) {
+ spin_unlock(&policy->transition_lock);
+ goto wait;
+ }
+
+ policy->transition_ongoing = true;
+
+ spin_unlock(&policy->transition_lock);
+
+ cpufreq_notify_transition(policy, freqs, CPUFREQ_PRECHANGE);
+}
+EXPORT_SYMBOL_GPL(cpufreq_freq_transition_begin);
+
+void cpufreq_freq_transition_end(struct cpufreq_policy *policy,
+ struct cpufreq_freqs *freqs, int transition_failed)
+{
+ if (unlikely(WARN_ON(!policy->transition_ongoing)))
+ return;
+
+ cpufreq_notify_post_transition(policy, freqs, transition_failed);
+
+ policy->transition_ongoing = false;
+
+ wake_up(&policy->transition_wait);
+}
+EXPORT_SYMBOL_GPL(cpufreq_freq_transition_end);
/*********************************************************************
* SYSFS INTERFACE *
*********************************************************************/
-ssize_t show_boost(struct kobject *kobj,
+static ssize_t show_boost(struct kobject *kobj,
struct attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", cpufreq_driver->boost_enabled);
@@ -368,13 +406,13 @@ static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
return -EINVAL;
if (cpufreq_boost_trigger_state(enable)) {
- pr_err("%s: Cannot %s BOOST!\n", __func__,
- enable ? "enable" : "disable");
+ pr_err("%s: Cannot %s BOOST!\n",
+ __func__, enable ? "enable" : "disable");
return -EINVAL;
}
- pr_debug("%s: cpufreq BOOST %s\n", __func__,
- enable ? "enabled" : "disabled");
+ pr_debug("%s: cpufreq BOOST %s\n",
+ __func__, enable ? "enabled" : "disabled");
return count;
}
@@ -879,18 +917,25 @@ err_out_kobj_put:
static void cpufreq_init_policy(struct cpufreq_policy *policy)
{
+ struct cpufreq_governor *gov = NULL;
struct cpufreq_policy new_policy;
int ret = 0;
memcpy(&new_policy, policy, sizeof(*policy));
+ /* Update governor of new_policy to the governor used before hotplug */
+ gov = __find_governor(per_cpu(cpufreq_cpu_governor, policy->cpu));
+ if (gov)
+ pr_debug("Restoring governor %s for cpu %d\n",
+ policy->governor->name, policy->cpu);
+ else
+ gov = CPUFREQ_DEFAULT_GOVERNOR;
+
+ new_policy.governor = gov;
+
/* Use the default policy if its valid. */
if (cpufreq_driver->setpolicy)
- cpufreq_parse_governor(policy->governor->name,
- &new_policy.policy, NULL);
-
- /* assure that the starting sequence is run in cpufreq_set_policy */
- policy->governor = NULL;
+ cpufreq_parse_governor(gov->name, &new_policy.policy, NULL);
/* set default policy */
ret = cpufreq_set_policy(policy, &new_policy);
@@ -927,8 +972,11 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
up_write(&policy->rwsem);
if (has_target()) {
- if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) ||
- (ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) {
+ ret = __cpufreq_governor(policy, CPUFREQ_GOV_START);
+ if (!ret)
+ ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+
+ if (ret) {
pr_err("%s: Failed to start governor\n", __func__);
return ret;
}
@@ -949,6 +997,8 @@ static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu)
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ policy->governor = NULL;
+
return policy;
}
@@ -968,6 +1018,8 @@ static struct cpufreq_policy *cpufreq_policy_alloc(void)
INIT_LIST_HEAD(&policy->policy_list);
init_rwsem(&policy->rwsem);
+ spin_lock_init(&policy->transition_lock);
+ init_waitqueue_head(&policy->transition_wait);
return policy;
@@ -1022,21 +1074,19 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
up_write(&policy->rwsem);
- cpufreq_frequency_table_update_policy_cpu(policy);
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_UPDATE_POLICY_CPU, policy);
}
-static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
- bool frozen)
+static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
{
unsigned int j, cpu = dev->id;
int ret = -ENOMEM;
struct cpufreq_policy *policy;
unsigned long flags;
+ bool recover_policy = cpufreq_suspended;
#ifdef CONFIG_HOTPLUG_CPU
struct cpufreq_policy *tpolicy;
- struct cpufreq_governor *gov;
#endif
if (cpu_is_offline(cpu))
@@ -1075,9 +1125,9 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
* Restore the saved policy when doing light-weight init and fall back
* to the full init if that fails.
*/
- policy = frozen ? cpufreq_policy_restore(cpu) : NULL;
+ policy = recover_policy ? cpufreq_policy_restore(cpu) : NULL;
if (!policy) {
- frozen = false;
+ recover_policy = false;
policy = cpufreq_policy_alloc();
if (!policy)
goto nomem_out;
@@ -1089,12 +1139,11 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
* the creation of a brand new one. So we need to perform this update
* by invoking update_policy_cpu().
*/
- if (frozen && cpu != policy->cpu)
+ if (recover_policy && cpu != policy->cpu)
update_policy_cpu(policy, cpu);
else
policy->cpu = cpu;
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
cpumask_copy(policy->cpus, cpumask_of(cpu));
init_completion(&policy->kobj_unregister);
@@ -1109,12 +1158,27 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
goto err_set_policy_cpu;
}
+ /* related cpus should atleast have policy->cpus */
+ cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
+
+ /*
+ * affected cpus must always be the one, which are online. We aren't
+ * managing offline cpus here.
+ */
+ cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
+
+ if (!recover_policy) {
+ policy->user_policy.min = policy->min;
+ policy->user_policy.max = policy->max;
+ }
+
+ down_write(&policy->rwsem);
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 (cpufreq_driver->get) {
+ if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
policy->cur = cpufreq_driver->get(policy->cpu);
if (!policy->cur) {
pr_err("%s: ->get() failed\n", __func__);
@@ -1162,33 +1226,10 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
}
}
- /* related cpus should atleast have policy->cpus */
- cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
-
- /*
- * affected cpus must always be the one, which are online. We aren't
- * managing offline cpus here.
- */
- cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
-
- if (!frozen) {
- policy->user_policy.min = policy->min;
- policy->user_policy.max = policy->max;
- }
-
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_START, policy);
-#ifdef CONFIG_HOTPLUG_CPU
- gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu));
- if (gov) {
- policy->governor = gov;
- pr_debug("Restoring governor %s for cpu %d\n",
- policy->governor->name, cpu);
- }
-#endif
-
- if (!frozen) {
+ if (!recover_policy) {
ret = cpufreq_add_dev_interface(policy, dev);
if (ret)
goto err_out_unregister;
@@ -1202,10 +1243,11 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
cpufreq_init_policy(policy);
- if (!frozen) {
+ if (!recover_policy) {
policy->user_policy.policy = policy->policy;
policy->user_policy.governor = policy->governor;
}
+ up_write(&policy->rwsem);
kobject_uevent(&policy->kobj, KOBJ_ADD);
up_read(&cpufreq_rwsem);
@@ -1224,7 +1266,7 @@ err_get_freq:
if (cpufreq_driver->exit)
cpufreq_driver->exit(policy);
err_set_policy_cpu:
- if (frozen) {
+ if (recover_policy) {
/* Do not leave stale fallback data behind. */
per_cpu(cpufreq_cpu_data_fallback, cpu) = NULL;
cpufreq_policy_put_kobj(policy);
@@ -1248,7 +1290,7 @@ nomem_out:
*/
static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
{
- return __cpufreq_add_dev(dev, sif, false);
+ return __cpufreq_add_dev(dev, sif);
}
static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
@@ -1263,7 +1305,7 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
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);
+ pr_err("%s: Failed to move kobj: %d\n", __func__, ret);
down_write(&policy->rwsem);
cpumask_set_cpu(old_cpu, policy->cpus);
@@ -1279,8 +1321,7 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
}
static int __cpufreq_remove_dev_prepare(struct device *dev,
- struct subsys_interface *sif,
- bool frozen)
+ struct subsys_interface *sif)
{
unsigned int cpu = dev->id, cpus;
int new_cpu, ret;
@@ -1294,7 +1335,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
policy = per_cpu(cpufreq_cpu_data, cpu);
/* Save the policy somewhere when doing a light-weight tear-down */
- if (frozen)
+ if (cpufreq_suspended)
per_cpu(cpufreq_cpu_data_fallback, cpu) = policy;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
@@ -1312,37 +1353,34 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
}
}
-#ifdef CONFIG_HOTPLUG_CPU
if (!cpufreq_driver->setpolicy)
strncpy(per_cpu(cpufreq_cpu_governor, cpu),
policy->governor->name, CPUFREQ_NAME_LEN);
-#endif
down_read(&policy->rwsem);
cpus = cpumask_weight(policy->cpus);
up_read(&policy->rwsem);
if (cpu != policy->cpu) {
- if (!frozen)
- sysfs_remove_link(&dev->kobj, "cpufreq");
+ sysfs_remove_link(&dev->kobj, "cpufreq");
} else if (cpus > 1) {
new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu);
if (new_cpu >= 0) {
update_policy_cpu(policy, new_cpu);
- if (!frozen) {
+ if (!cpufreq_suspended)
pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
- __func__, new_cpu, cpu);
- }
+ __func__, new_cpu, cpu);
}
+ } else if (cpufreq_driver->stop_cpu && cpufreq_driver->setpolicy) {
+ cpufreq_driver->stop_cpu(policy);
}
return 0;
}
static int __cpufreq_remove_dev_finish(struct device *dev,
- struct subsys_interface *sif,
- bool frozen)
+ struct subsys_interface *sif)
{
unsigned int cpu = dev->id, cpus;
int ret;
@@ -1372,12 +1410,12 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
CPUFREQ_GOV_POLICY_EXIT);
if (ret) {
pr_err("%s: Failed to exit governor\n",
- __func__);
+ __func__);
return ret;
}
}
- if (!frozen)
+ if (!cpufreq_suspended)
cpufreq_policy_put_kobj(policy);
/*
@@ -1393,16 +1431,16 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
list_del(&policy->policy_list);
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
- if (!frozen)
+ if (!cpufreq_suspended)
cpufreq_policy_free(policy);
- } else {
- if (has_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;
- }
+ } else if (has_target()) {
+ ret = __cpufreq_governor(policy, CPUFREQ_GOV_START);
+ if (!ret)
+ ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+
+ if (ret) {
+ pr_err("%s: Failed to start governor\n", __func__);
+ return ret;
}
}
@@ -1423,10 +1461,10 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
if (cpu_is_offline(cpu))
return 0;
- ret = __cpufreq_remove_dev_prepare(dev, sif, false);
+ ret = __cpufreq_remove_dev_prepare(dev, sif);
if (!ret)
- ret = __cpufreq_remove_dev_finish(dev, sif, false);
+ ret = __cpufreq_remove_dev_finish(dev, sif);
return ret;
}
@@ -1457,8 +1495,8 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
struct cpufreq_freqs freqs;
unsigned long flags;
- pr_debug("Warning: CPU frequency out of sync: cpufreq and timing "
- "core thinks of %u, is %u kHz.\n", old_freq, new_freq);
+ pr_debug("Warning: CPU frequency out of sync: cpufreq and timing core thinks of %u, is %u kHz\n",
+ old_freq, new_freq);
freqs.old = old_freq;
freqs.new = new_freq;
@@ -1467,8 +1505,8 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
policy = per_cpu(cpufreq_cpu_data, cpu);
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
+ cpufreq_freq_transition_end(policy, &freqs, 0);
}
/**
@@ -1547,23 +1585,16 @@ static unsigned int __cpufreq_get(unsigned int cpu)
*/
unsigned int cpufreq_get(unsigned int cpu)
{
- struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
+ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
unsigned int ret_freq = 0;
- if (cpufreq_disabled() || !cpufreq_driver)
- return -ENOENT;
-
- BUG_ON(!policy);
-
- if (!down_read_trylock(&cpufreq_rwsem))
- return 0;
-
- down_read(&policy->rwsem);
-
- ret_freq = __cpufreq_get(cpu);
+ if (policy) {
+ down_read(&policy->rwsem);
+ ret_freq = __cpufreq_get(cpu);
+ up_read(&policy->rwsem);
- up_read(&policy->rwsem);
- up_read(&cpufreq_rwsem);
+ cpufreq_cpu_put(policy);
+ }
return ret_freq;
}
@@ -1576,83 +1607,103 @@ static struct subsys_interface cpufreq_interface = {
.remove_dev = cpufreq_remove_dev,
};
+/*
+ * In case platform wants some specific frequency to be configured
+ * during suspend..
+ */
+int cpufreq_generic_suspend(struct cpufreq_policy *policy)
+{
+ int ret;
+
+ if (!policy->suspend_freq) {
+ pr_err("%s: suspend_freq can't be zero\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: Setting suspend-freq: %u\n", __func__,
+ policy->suspend_freq);
+
+ ret = __cpufreq_driver_target(policy, policy->suspend_freq,
+ CPUFREQ_RELATION_H);
+ if (ret)
+ pr_err("%s: unable to set suspend-freq: %u. err: %d\n",
+ __func__, policy->suspend_freq, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL(cpufreq_generic_suspend);
+
/**
- * cpufreq_bp_suspend - Prepare the boot CPU for system suspend.
+ * cpufreq_suspend() - Suspend CPUFreq governors
*
- * This function is only executed for the boot processor. The other CPUs
- * have been put offline by means of CPU hotplug.
+ * Called during system wide Suspend/Hibernate cycles for suspending governors
+ * as some platforms can't change frequency after this point in suspend cycle.
+ * Because some of the devices (like: i2c, regulators, etc) they use for
+ * changing frequency are suspended quickly after this point.
*/
-static int cpufreq_bp_suspend(void)
+void cpufreq_suspend(void)
{
- int ret = 0;
-
- int cpu = smp_processor_id();
struct cpufreq_policy *policy;
- pr_debug("suspending cpu %u\n", cpu);
+ if (!cpufreq_driver)
+ return;
- /* If there's no policy for the boot CPU, we have nothing to do. */
- policy = cpufreq_cpu_get(cpu);
- if (!policy)
- return 0;
+ if (!has_target())
+ return;
- if (cpufreq_driver->suspend) {
- ret = cpufreq_driver->suspend(policy);
- if (ret)
- printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
- "step on CPU %u\n", policy->cpu);
+ pr_debug("%s: Suspending Governors\n", __func__);
+
+ list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
+ if (__cpufreq_governor(policy, CPUFREQ_GOV_STOP))
+ pr_err("%s: Failed to stop governor for policy: %p\n",
+ __func__, policy);
+ else if (cpufreq_driver->suspend
+ && cpufreq_driver->suspend(policy))
+ pr_err("%s: Failed to suspend driver: %p\n", __func__,
+ policy);
}
- cpufreq_cpu_put(policy);
- return ret;
+ cpufreq_suspended = true;
}
/**
- * cpufreq_bp_resume - Restore proper frequency handling of the boot CPU.
- *
- * 1.) resume CPUfreq hardware support (cpufreq_driver->resume())
- * 2.) schedule call cpufreq_update_policy() ASAP as interrupts are
- * restored. It will verify that the current freq is in sync with
- * what we believe it to be. This is a bit later than when it
- * should be, but nonethteless it's better than calling
- * cpufreq_driver->get() here which might re-enable interrupts...
+ * cpufreq_resume() - Resume CPUFreq governors
*
- * This function is only executed for the boot CPU. The other CPUs have not
- * been turned on yet.
+ * Called during system wide Suspend/Hibernate cycle for resuming governors that
+ * are suspended with cpufreq_suspend().
*/
-static void cpufreq_bp_resume(void)
+void cpufreq_resume(void)
{
- int ret = 0;
-
- int cpu = smp_processor_id();
struct cpufreq_policy *policy;
- pr_debug("resuming cpu %u\n", cpu);
+ if (!cpufreq_driver)
+ return;
- /* If there's no policy for the boot CPU, we have nothing to do. */
- policy = cpufreq_cpu_get(cpu);
- if (!policy)
+ if (!has_target())
return;
- if (cpufreq_driver->resume) {
- ret = cpufreq_driver->resume(policy);
- if (ret) {
- printk(KERN_ERR "cpufreq: resume failed in ->resume "
- "step on CPU %u\n", policy->cpu);
- goto fail;
- }
- }
+ pr_debug("%s: Resuming Governors\n", __func__);
- schedule_work(&policy->update);
+ cpufreq_suspended = false;
-fail:
- cpufreq_cpu_put(policy);
-}
+ list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
+ if (cpufreq_driver->resume && cpufreq_driver->resume(policy))
+ pr_err("%s: Failed to resume driver: %p\n", __func__,
+ policy);
+ else if (__cpufreq_governor(policy, CPUFREQ_GOV_START)
+ || __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))
+ pr_err("%s: Failed to start governor for policy: %p\n",
+ __func__, policy);
-static struct syscore_ops cpufreq_syscore_ops = {
- .suspend = cpufreq_bp_suspend,
- .resume = cpufreq_bp_resume,
-};
+ /*
+ * schedule call cpufreq_update_policy() for boot CPU, i.e. last
+ * policy in list. It will verify that the current freq is in
+ * sync with what we believe it to be.
+ */
+ if (list_is_last(&policy->policy_list, &cpufreq_policy_list))
+ schedule_work(&policy->update);
+ }
+}
/**
* cpufreq_get_current_driver - return current driver's name
@@ -1768,7 +1819,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
target_freq = policy->min;
pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n",
- policy->cpu, target_freq, relation, old_target_freq);
+ policy->cpu, target_freq, relation, old_target_freq);
/*
* This might look like a redundant call as we are checking it again
@@ -1813,20 +1864,18 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
freqs.flags = 0;
pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n",
- __func__, policy->cpu, freqs.old,
- freqs.new);
+ __func__, policy->cpu, freqs.old, freqs.new);
- cpufreq_notify_transition(policy, &freqs,
- CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
}
retval = cpufreq_driver->target_index(policy, index);
if (retval)
pr_err("%s: Failed to change cpu frequency: %d\n",
- __func__, retval);
+ __func__, retval);
if (notify)
- cpufreq_notify_post_transition(policy, &freqs, retval);
+ cpufreq_freq_transition_end(policy, &freqs, retval);
}
out:
@@ -1869,17 +1918,18 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
struct cpufreq_governor *gov = NULL;
#endif
+ /* Don't start any governor operations if we are entering suspend */
+ if (cpufreq_suspended)
+ return 0;
+
if (policy->governor->max_transition_latency &&
policy->cpuinfo.transition_latency >
policy->governor->max_transition_latency) {
if (!gov)
return -EINVAL;
else {
- printk(KERN_WARNING "%s governor failed, too long"
- " transition latency of HW, fallback"
- " to %s governor\n",
- policy->governor->name,
- gov->name);
+ pr_warn("%s governor failed, too long transition latency of HW, fallback to %s governor\n",
+ policy->governor->name, gov->name);
policy->governor = gov;
}
}
@@ -1889,7 +1939,7 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
return -EINVAL;
pr_debug("__cpufreq_governor for CPU %u, event %u\n",
- policy->cpu, event);
+ policy->cpu, event);
mutex_lock(&cpufreq_governor_lock);
if ((policy->governor_enabled && event == CPUFREQ_GOV_START)
@@ -1956,9 +2006,7 @@ EXPORT_SYMBOL_GPL(cpufreq_register_governor);
void cpufreq_unregister_governor(struct cpufreq_governor *governor)
{
-#ifdef CONFIG_HOTPLUG_CPU
int cpu;
-#endif
if (!governor)
return;
@@ -1966,14 +2014,12 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor)
if (cpufreq_disabled())
return;
-#ifdef CONFIG_HOTPLUG_CPU
for_each_present_cpu(cpu) {
if (cpu_online(cpu))
continue;
if (!strcmp(per_cpu(cpufreq_cpu_governor, cpu), governor->name))
strcpy(per_cpu(cpufreq_cpu_governor, cpu), "\0");
}
-#endif
mutex_lock(&cpufreq_governor_mutex);
list_del(&governor->governor_list);
@@ -2018,22 +2064,21 @@ EXPORT_SYMBOL(cpufreq_get_policy);
static int cpufreq_set_policy(struct cpufreq_policy *policy,
struct cpufreq_policy *new_policy)
{
- int ret = 0, failed = 1;
+ struct cpufreq_governor *old_gov;
+ int ret;
- pr_debug("setting new policy for CPU %u: %u - %u kHz\n", new_policy->cpu,
- new_policy->min, new_policy->max);
+ pr_debug("setting new policy for CPU %u: %u - %u kHz\n",
+ new_policy->cpu, new_policy->min, new_policy->max);
memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));
- if (new_policy->min > policy->max || new_policy->max < policy->min) {
- ret = -EINVAL;
- goto error_out;
- }
+ if (new_policy->min > policy->max || new_policy->max < policy->min)
+ return -EINVAL;
/* verify the cpu speed can be set within this limit */
ret = cpufreq_driver->verify(new_policy);
if (ret)
- goto error_out;
+ return ret;
/* adjust if necessary - all reasons */
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
@@ -2049,7 +2094,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
*/
ret = cpufreq_driver->verify(new_policy);
if (ret)
- goto error_out;
+ return ret;
/* notification of the new policy */
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
@@ -2059,63 +2104,53 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
policy->max = new_policy->max;
pr_debug("new min and max freqs are %u - %u kHz\n",
- policy->min, policy->max);
+ policy->min, policy->max);
if (cpufreq_driver->setpolicy) {
policy->policy = new_policy->policy;
pr_debug("setting range\n");
- ret = cpufreq_driver->setpolicy(new_policy);
- } else {
- if (new_policy->governor != policy->governor) {
- /* save old, working values */
- struct cpufreq_governor *old_gov = policy->governor;
-
- pr_debug("governor switch\n");
-
- /* end old governor */
- if (policy->governor) {
- __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
- up_write(&policy->rwsem);
- __cpufreq_governor(policy,
- CPUFREQ_GOV_POLICY_EXIT);
- down_write(&policy->rwsem);
- }
+ return cpufreq_driver->setpolicy(new_policy);
+ }
- /* start new governor */
- policy->governor = new_policy->governor;
- if (!__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT)) {
- if (!__cpufreq_governor(policy, CPUFREQ_GOV_START)) {
- failed = 0;
- } else {
- up_write(&policy->rwsem);
- __cpufreq_governor(policy,
- CPUFREQ_GOV_POLICY_EXIT);
- down_write(&policy->rwsem);
- }
- }
+ if (new_policy->governor == policy->governor)
+ goto out;
- if (failed) {
- /* new governor failed, so re-start old one */
- pr_debug("starting governor %s failed\n",
- policy->governor->name);
- if (old_gov) {
- policy->governor = old_gov;
- __cpufreq_governor(policy,
- CPUFREQ_GOV_POLICY_INIT);
- __cpufreq_governor(policy,
- CPUFREQ_GOV_START);
- }
- ret = -EINVAL;
- goto error_out;
- }
- /* might be a policy change, too, so fall through */
- }
- pr_debug("governor: change or update limits\n");
- ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+ pr_debug("governor switch\n");
+
+ /* save old, working values */
+ old_gov = policy->governor;
+ /* end old governor */
+ if (old_gov) {
+ __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+ up_write(&policy->rwsem);
+ __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
+ down_write(&policy->rwsem);
}
-error_out:
- return ret;
+ /* start new governor */
+ policy->governor = new_policy->governor;
+ if (!__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT)) {
+ if (!__cpufreq_governor(policy, CPUFREQ_GOV_START))
+ goto out;
+
+ up_write(&policy->rwsem);
+ __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
+ down_write(&policy->rwsem);
+ }
+
+ /* new governor failed, so re-start old one */
+ pr_debug("starting governor %s failed\n", policy->governor->name);
+ if (old_gov) {
+ policy->governor = old_gov;
+ __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT);
+ __cpufreq_governor(policy, CPUFREQ_GOV_START);
+ }
+
+ return -EINVAL;
+
+ out:
+ pr_debug("governor: change or update limits\n");
+ return __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
}
/**
@@ -2149,10 +2184,15 @@ int cpufreq_update_policy(unsigned int cpu)
* BIOS might change freq behind our back
* -> ask driver for current freq and notify governors about a change
*/
- if (cpufreq_driver->get) {
+ if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
new_policy.cur = cpufreq_driver->get(cpu);
+ if (WARN_ON(!new_policy.cur)) {
+ ret = -EIO;
+ goto no_policy;
+ }
+
if (!policy->cur) {
- pr_debug("Driver did not initialize current freq");
+ pr_debug("Driver did not initialize current freq\n");
policy->cur = new_policy.cur;
} else {
if (policy->cur != new_policy.cur && has_target())
@@ -2176,30 +2216,24 @@ 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) {
-
- if (action & CPU_TASKS_FROZEN)
- frozen = true;
-
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_ONLINE:
- __cpufreq_add_dev(dev, NULL, frozen);
- cpufreq_update_policy(cpu);
+ __cpufreq_add_dev(dev, NULL);
break;
case CPU_DOWN_PREPARE:
- __cpufreq_remove_dev_prepare(dev, NULL, frozen);
+ __cpufreq_remove_dev_prepare(dev, NULL);
break;
case CPU_POST_DEAD:
- __cpufreq_remove_dev_finish(dev, NULL, frozen);
+ __cpufreq_remove_dev_finish(dev, NULL);
break;
case CPU_DOWN_FAILED:
- __cpufreq_add_dev(dev, NULL, frozen);
+ __cpufreq_add_dev(dev, NULL);
break;
}
}
@@ -2255,8 +2289,8 @@ int cpufreq_boost_trigger_state(int state)
cpufreq_driver->boost_enabled = !state;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
- pr_err("%s: Cannot %s BOOST\n", __func__,
- state ? "enable" : "disable");
+ pr_err("%s: Cannot %s BOOST\n",
+ __func__, state ? "enable" : "disable");
}
return ret;
@@ -2301,7 +2335,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
if (!driver_data || !driver_data->verify || !driver_data->init ||
!(driver_data->setpolicy || driver_data->target_index ||
- driver_data->target))
+ driver_data->target) ||
+ (driver_data->setpolicy && (driver_data->target_index ||
+ driver_data->target)))
return -EINVAL;
pr_debug("trying to register driver %s\n", driver_data->name);
@@ -2328,7 +2364,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
ret = cpufreq_sysfs_create_file(&boost.attr);
if (ret) {
pr_err("%s: cannot register global BOOST sysfs file\n",
- __func__);
+ __func__);
goto err_null_driver;
}
}
@@ -2351,7 +2387,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
/* if all ->init() calls failed, unregister */
if (ret) {
pr_debug("no CPU initialized for driver %s\n",
- driver_data->name);
+ driver_data->name);
goto err_if_unreg;
}
}
@@ -2415,7 +2451,6 @@ static int __init cpufreq_core_init(void)
cpufreq_global_kobject = kobject_create();
BUG_ON(!cpufreq_global_kobject);
- register_syscore_ops(&cpufreq_syscore_ops);
return 0;
}
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 5793e1447fb1..ecaaebf969fc 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -13,7 +13,7 @@
#include <linux/cpufreq.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <asm/cputime.h>
+#include <linux/cputime.h>
static spinlock_t cpufreq_stats_lock;
@@ -180,27 +180,25 @@ static void cpufreq_stats_free_table(unsigned int cpu)
cpufreq_cpu_put(policy);
}
-static int __cpufreq_stats_create_table(struct cpufreq_policy *policy,
- struct cpufreq_frequency_table *table)
+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 *current_policy;
unsigned int alloc_size;
unsigned int cpu = policy->cpu;
+ struct cpufreq_frequency_table *table;
+
+ table = cpufreq_frequency_get_table(cpu);
+ if (unlikely(!table))
+ return 0;
+
if (per_cpu(cpufreq_stats_table, cpu))
return -EBUSY;
stat = kzalloc(sizeof(*stat), GFP_KERNEL);
if ((stat) == NULL)
return -ENOMEM;
- current_policy = cpufreq_cpu_get(cpu);
- if (current_policy == NULL) {
- ret = -EINVAL;
- goto error_get_fail;
- }
-
- ret = sysfs_create_group(&current_policy->kobj, &stats_attr_group);
+ ret = sysfs_create_group(&policy->kobj, &stats_attr_group);
if (ret)
goto error_out;
@@ -223,7 +221,7 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy,
stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
if (!stat->time_in_state) {
ret = -ENOMEM;
- goto error_out;
+ goto error_alloc;
}
stat->freq_table = (unsigned int *)(stat->time_in_state + count);
@@ -243,11 +241,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(current_policy);
return 0;
+error_alloc:
+ sysfs_remove_group(&policy->kobj, &stats_attr_group);
error_out:
- cpufreq_cpu_put(current_policy);
-error_get_fail:
kfree(stat);
per_cpu(cpufreq_stats_table, cpu) = NULL;
return ret;
@@ -256,7 +253,6 @@ error_get_fail:
static void cpufreq_stats_create_table(unsigned int cpu)
{
struct cpufreq_policy *policy;
- struct cpufreq_frequency_table *table;
/*
* "likely(!policy)" because normally cpufreq_stats will be registered
@@ -266,9 +262,7 @@ static void cpufreq_stats_create_table(unsigned int cpu)
if (likely(!policy))
return;
- table = cpufreq_frequency_get_table(policy->cpu);
- if (likely(table))
- __cpufreq_stats_create_table(policy, table);
+ __cpufreq_stats_create_table(policy);
cpufreq_cpu_put(policy);
}
@@ -291,20 +285,14 @@ static int cpufreq_stat_notifier_policy(struct notifier_block *nb,
{
int ret = 0;
struct cpufreq_policy *policy = data;
- struct cpufreq_frequency_table *table;
- unsigned int cpu = policy->cpu;
if (val == CPUFREQ_UPDATE_POLICY_CPU) {
cpufreq_stats_update_policy_cpu(policy);
return 0;
}
- table = cpufreq_frequency_get_table(cpu);
- if (!table)
- return 0;
-
if (val == CPUFREQ_CREATE_POLICY)
- ret = __cpufreq_stats_create_table(policy, table);
+ ret = __cpufreq_stats_create_table(policy);
else if (val == CPUFREQ_REMOVE_POLICY)
__cpufreq_stats_free_table(policy);
diff --git a/drivers/cpufreq/cris-artpec3-cpufreq.c b/drivers/cpufreq/cris-artpec3-cpufreq.c
index 86559040c54c..d4573032cbbc 100644
--- a/drivers/cpufreq/cris-artpec3-cpufreq.c
+++ b/drivers/cpufreq/cris-artpec3-cpufreq.c
@@ -57,7 +57,6 @@ static struct cpufreq_driver cris_freq_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = cris_freq_target,
.init = cris_freq_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "cris_freq",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/cris-etraxfs-cpufreq.c b/drivers/cpufreq/cris-etraxfs-cpufreq.c
index 26d940d40b1d..13c3361437f7 100644
--- a/drivers/cpufreq/cris-etraxfs-cpufreq.c
+++ b/drivers/cpufreq/cris-etraxfs-cpufreq.c
@@ -57,7 +57,6 @@ static struct cpufreq_driver cris_freq_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = cris_freq_target,
.init = cris_freq_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "cris_freq",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/davinci-cpufreq.c b/drivers/cpufreq/davinci-cpufreq.c
index 2cf33848d86e..28a16dc6e02e 100644
--- a/drivers/cpufreq/davinci-cpufreq.c
+++ b/drivers/cpufreq/davinci-cpufreq.c
@@ -125,7 +125,6 @@ static struct cpufreq_driver davinci_driver = {
.target_index = davinci_target,
.get = cpufreq_generic_get,
.init = davinci_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "davinci",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c
index 9012b8bb6b64..a0d2a423cea9 100644
--- a/drivers/cpufreq/e_powersaver.c
+++ b/drivers/cpufreq/e_powersaver.c
@@ -382,7 +382,6 @@ static int eps_cpu_exit(struct cpufreq_policy *policy)
unsigned int cpu = policy->cpu;
/* Bye */
- cpufreq_frequency_table_put_attr(policy->cpu);
kfree(eps_cpu[cpu]);
eps_cpu[cpu] = NULL;
return 0;
diff --git a/drivers/cpufreq/elanfreq.c b/drivers/cpufreq/elanfreq.c
index de08acff5101..c987e94708f5 100644
--- a/drivers/cpufreq/elanfreq.c
+++ b/drivers/cpufreq/elanfreq.c
@@ -198,7 +198,6 @@ static struct cpufreq_driver elanfreq_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = elanfreq_target,
.init = elanfreq_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "elanfreq",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index fcd2914d081a..f99cfe24e7bc 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -16,7 +16,6 @@
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <linux/cpufreq.h>
-#include <linux/suspend.h>
#include <linux/platform_device.h>
#include <plat/cpu.h>
@@ -24,12 +23,8 @@
#include "exynos-cpufreq.h"
static struct exynos_dvfs_info *exynos_info;
-
static struct regulator *arm_regulator;
-
static unsigned int locking_frequency;
-static bool frequency_locked;
-static DEFINE_MUTEX(cpufreq_lock);
static int exynos_cpufreq_get_index(unsigned int freq)
{
@@ -134,83 +129,13 @@ out:
static int exynos_target(struct cpufreq_policy *policy, unsigned int index)
{
- struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
- int ret = 0;
-
- mutex_lock(&cpufreq_lock);
-
- if (frequency_locked)
- goto out;
-
- ret = exynos_cpufreq_scale(freq_table[index].frequency);
-
-out:
- mutex_unlock(&cpufreq_lock);
-
- return ret;
-}
-
-#ifdef CONFIG_PM
-static int exynos_cpufreq_suspend(struct cpufreq_policy *policy)
-{
- return 0;
-}
-
-static int exynos_cpufreq_resume(struct cpufreq_policy *policy)
-{
- return 0;
-}
-#endif
-
-/**
- * exynos_cpufreq_pm_notifier - block CPUFREQ's activities in suspend-resume
- * context
- * @notifier
- * @pm_event
- * @v
- *
- * While frequency_locked == true, target() ignores every frequency but
- * locking_frequency. The locking_frequency value is the initial frequency,
- * which is set by the bootloader. In order to eliminate possible
- * inconsistency in clock values, we save and restore frequencies during
- * suspend and resume and block CPUFREQ activities. Note that the standard
- * suspend/resume cannot be used as they are too deep (syscore_ops) for
- * regulator actions.
- */
-static int exynos_cpufreq_pm_notifier(struct notifier_block *notifier,
- unsigned long pm_event, void *v)
-{
- int ret;
-
- switch (pm_event) {
- case PM_SUSPEND_PREPARE:
- mutex_lock(&cpufreq_lock);
- frequency_locked = true;
- mutex_unlock(&cpufreq_lock);
-
- ret = exynos_cpufreq_scale(locking_frequency);
- if (ret < 0)
- return NOTIFY_BAD;
-
- break;
-
- case PM_POST_SUSPEND:
- mutex_lock(&cpufreq_lock);
- frequency_locked = false;
- mutex_unlock(&cpufreq_lock);
- break;
- }
-
- return NOTIFY_OK;
+ return exynos_cpufreq_scale(exynos_info->freq_table[index].frequency);
}
-static struct notifier_block exynos_cpufreq_nb = {
- .notifier_call = exynos_cpufreq_pm_notifier,
-};
-
static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
policy->clk = exynos_info->cpu_clk;
+ policy->suspend_freq = locking_frequency;
return cpufreq_generic_init(policy, exynos_info->freq_table, 100000);
}
@@ -220,15 +145,13 @@ static struct cpufreq_driver exynos_driver = {
.target_index = exynos_target,
.get = cpufreq_generic_get,
.init = exynos_cpufreq_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "exynos_cpufreq",
.attr = cpufreq_generic_attr,
#ifdef CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
.boost_supported = true,
#endif
#ifdef CONFIG_PM
- .suspend = exynos_cpufreq_suspend,
- .resume = exynos_cpufreq_resume,
+ .suspend = cpufreq_generic_suspend,
#endif
};
@@ -263,19 +186,13 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
goto err_vdd_arm;
}
+ /* Done here as we want to capture boot frequency */
locking_frequency = clk_get_rate(exynos_info->cpu_clk) / 1000;
- register_pm_notifier(&exynos_cpufreq_nb);
-
- if (cpufreq_register_driver(&exynos_driver)) {
- pr_err("%s: failed to register cpufreq driver\n", __func__);
- goto err_cpufreq;
- }
-
- return 0;
-err_cpufreq:
- unregister_pm_notifier(&exynos_cpufreq_nb);
+ if (!cpufreq_register_driver(&exynos_driver))
+ return 0;
+ pr_err("%s: failed to register cpufreq driver\n", __func__);
regulator_put(arm_regulator);
err_vdd_arm:
kfree(exynos_info);
diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c
index 49b756015316..a6b8214d7b77 100644
--- a/drivers/cpufreq/exynos5440-cpufreq.c
+++ b/drivers/cpufreq/exynos5440-cpufreq.c
@@ -219,7 +219,7 @@ static int exynos_target(struct cpufreq_policy *policy, unsigned int index)
freqs.old = policy->cur;
freqs.new = freq_table[index].frequency;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
/* Set the target frequency in all C0_3_PSTATE register */
for_each_cpu(i, policy->cpus) {
@@ -258,7 +258,7 @@ static void exynos_cpufreq_work(struct work_struct *work)
dev_crit(dvfs_info->dev, "New frequency out of range\n");
freqs.new = freqs.old;
}
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freq_transition_end(policy, &freqs, 0);
cpufreq_cpu_put(policy);
mutex_unlock(&cpufreq_lock);
@@ -312,7 +312,6 @@ static struct cpufreq_driver exynos_driver = {
.target_index = exynos_target,
.get = cpufreq_generic_get,
.init = exynos_cpufreq_cpu_init,
- .exit = cpufreq_generic_exit,
.name = CPUFREQ_NAME,
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index 8e54f97899ba..65a477075b3f 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -91,8 +91,8 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify);
/*
- * Generic routine to verify policy & frequency table, requires driver to call
- * cpufreq_frequency_table_get_attr() prior to it.
+ * Generic routine to verify policy & frequency table, requires driver to set
+ * policy->freq_table prior to it.
*/
int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy)
{
@@ -203,8 +203,6 @@ int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
}
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index);
-static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
-
/**
* show_available_freqs - show available frequencies for the specified CPU
*/
@@ -212,15 +210,12 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
bool show_boost)
{
unsigned int i = 0;
- unsigned int cpu = policy->cpu;
ssize_t count = 0;
- struct cpufreq_frequency_table *table;
+ struct cpufreq_frequency_table *table = policy->freq_table;
- if (!per_cpu(cpufreq_show_table, cpu))
+ if (!table)
return -ENODEV;
- table = per_cpu(cpufreq_show_table, cpu);
-
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
continue;
@@ -283,49 +278,24 @@ struct freq_attr *cpufreq_generic_attr[] = {
};
EXPORT_SYMBOL_GPL(cpufreq_generic_attr);
-/*
- * if you use these, you must assure that the frequency table is valid
- * all the time between get_attr and put_attr!
- */
-void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
- unsigned int cpu)
-{
- pr_debug("setting show_table for cpu %u to %p\n", cpu, table);
- per_cpu(cpufreq_show_table, cpu) = table;
-}
-EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr);
-
-void cpufreq_frequency_table_put_attr(unsigned int cpu)
-{
- pr_debug("clearing show_table for cpu %u\n", cpu);
- per_cpu(cpufreq_show_table, cpu) = NULL;
-}
-EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr);
-
int cpufreq_table_validate_and_show(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table)
{
int ret = cpufreq_frequency_table_cpuinfo(policy, table);
if (!ret)
- cpufreq_frequency_table_get_attr(table, policy->cpu);
+ policy->freq_table = table;
return ret;
}
EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show);
-void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy)
-{
- pr_debug("Updating show_table for new_cpu %u from last_cpu %u\n",
- policy->cpu, policy->last_cpu);
- per_cpu(cpufreq_show_table, policy->cpu) = per_cpu(cpufreq_show_table,
- policy->last_cpu);
- per_cpu(cpufreq_show_table, policy->last_cpu) = NULL;
-}
+struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu);
struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
{
- return per_cpu(cpufreq_show_table, cpu);
+ struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
+ return policy ? policy->freq_table : NULL;
}
EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
diff --git a/drivers/cpufreq/gx-suspmod.c b/drivers/cpufreq/gx-suspmod.c
index d83e8266a58e..1d723dc8880c 100644
--- a/drivers/cpufreq/gx-suspmod.c
+++ b/drivers/cpufreq/gx-suspmod.c
@@ -265,7 +265,7 @@ static void gx_set_cpuspeed(struct cpufreq_policy *policy, unsigned int khz)
freqs.new = new_khz;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
local_irq_save(flags);
if (new_khz != stock_freq) {
@@ -314,7 +314,7 @@ static void gx_set_cpuspeed(struct cpufreq_policy *policy, unsigned int khz)
gx_params->pci_suscfg = suscfg;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freq_transition_end(policy, &freqs, 0);
pr_debug("suspend modulation w/ duration of ON:%d us, OFF:%d us\n",
gx_params->on_duration * 32, gx_params->off_duration * 32);
diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c
index 53c6ac637e10..a22b5d182e0e 100644
--- a/drivers/cpufreq/ia64-acpi-cpufreq.c
+++ b/drivers/cpufreq/ia64-acpi-cpufreq.c
@@ -332,7 +332,6 @@ acpi_cpufreq_cpu_exit (
pr_debug("acpi_cpufreq_cpu_exit\n");
if (data) {
- cpufreq_frequency_table_put_attr(policy->cpu);
acpi_io_data[policy->cpu] = NULL;
acpi_processor_unregister_performance(&data->acpi_data,
policy->cpu);
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
index ce69059be1fc..e27fca86fe4f 100644
--- a/drivers/cpufreq/imx6q-cpufreq.c
+++ b/drivers/cpufreq/imx6q-cpufreq.c
@@ -144,7 +144,6 @@ static struct cpufreq_driver imx6q_cpufreq_driver = {
.target_index = imx6q_set_target,
.get = cpufreq_generic_get,
.init = imx6q_cpufreq_init,
- .exit = cpufreq_generic_exit,
.name = "imx6q-cpufreq",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/integrator-cpufreq.c b/drivers/cpufreq/integrator-cpufreq.c
index 0e27844e8c2d..e5122f1bfe78 100644
--- a/drivers/cpufreq/integrator-cpufreq.c
+++ b/drivers/cpufreq/integrator-cpufreq.c
@@ -122,7 +122,7 @@ static int integrator_set_target(struct cpufreq_policy *policy,
return 0;
}
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
cm_osc = __raw_readl(cm_base + INTEGRATOR_HDR_OSC_OFFSET);
@@ -143,7 +143,7 @@ static int integrator_set_target(struct cpufreq_policy *policy,
*/
set_cpus_allowed(current, cpus_allowed);
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freq_transition_end(policy, &freqs, 0);
return 0;
}
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index 79606f473f48..099967302bf2 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -34,12 +34,15 @@
#define SAMPLE_COUNT 3
-#define BYT_RATIOS 0x66a
-#define BYT_VIDS 0x66b
+#define BYT_RATIOS 0x66a
+#define BYT_VIDS 0x66b
+#define BYT_TURBO_RATIOS 0x66c
-#define FRAC_BITS 8
+
+#define FRAC_BITS 6
#define int_tofp(X) ((int64_t)(X) << FRAC_BITS)
#define fp_toint(X) ((X) >> FRAC_BITS)
+#define FP_ROUNDUP(X) ((X) += 1 << FRAC_BITS)
static inline int32_t mul_fp(int32_t x, int32_t y)
{
@@ -51,8 +54,6 @@ static inline int32_t div_fp(int32_t x, int32_t y)
return div_s64((int64_t)x << FRAC_BITS, (int64_t)y);
}
-static u64 energy_divisor;
-
struct sample {
int32_t core_pct_busy;
u64 aperf;
@@ -98,8 +99,7 @@ struct cpudata {
u64 prev_aperf;
u64 prev_mperf;
unsigned long long prev_tsc;
- int sample_ptr;
- struct sample samples[SAMPLE_COUNT];
+ struct sample sample;
};
static struct cpudata **all_cpu_data;
@@ -153,7 +153,7 @@ static inline void pid_reset(struct _pid *pid, int setpoint, int busy,
pid->setpoint = setpoint;
pid->deadband = deadband;
pid->integral = int_tofp(integral);
- pid->last_err = setpoint - busy;
+ pid->last_err = int_tofp(setpoint) - int_tofp(busy);
}
static inline void pid_p_gain_set(struct _pid *pid, int percent)
@@ -359,7 +359,7 @@ static int byt_get_min_pstate(void)
{
u64 value;
rdmsrl(BYT_RATIOS, value);
- return value & 0xFF;
+ return (value >> 8) & 0xFF;
}
static int byt_get_max_pstate(void)
@@ -369,6 +369,13 @@ static int byt_get_max_pstate(void)
return (value >> 16) & 0xFF;
}
+static int byt_get_turbo_pstate(void)
+{
+ u64 value;
+ rdmsrl(BYT_TURBO_RATIOS, value);
+ return value & 0x3F;
+}
+
static void byt_set_pstate(struct cpudata *cpudata, int pstate)
{
u64 val;
@@ -439,7 +446,7 @@ static void core_set_pstate(struct cpudata *cpudata, int pstate)
if (limits.no_turbo)
val |= (u64)1 << 32;
- wrmsrl(MSR_IA32_PERF_CTL, val);
+ wrmsrl_on_cpu(cpudata->cpu, MSR_IA32_PERF_CTL, val);
}
static struct cpu_defaults core_params = {
@@ -471,7 +478,7 @@ static struct cpu_defaults byt_params = {
.funcs = {
.get_max = byt_get_max_pstate,
.get_min = byt_get_min_pstate,
- .get_turbo = byt_get_max_pstate,
+ .get_turbo = byt_get_turbo_pstate,
.set = byt_set_pstate,
.get_vid = byt_get_vid,
},
@@ -549,18 +556,20 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
static inline void intel_pstate_calc_busy(struct cpudata *cpu,
struct sample *sample)
{
- u64 core_pct;
- u64 c0_pct;
+ int32_t core_pct;
+ int32_t c0_pct;
+
+ core_pct = div_fp(int_tofp((sample->aperf)),
+ int_tofp((sample->mperf)));
+ core_pct = mul_fp(core_pct, int_tofp(100));
+ FP_ROUNDUP(core_pct);
- core_pct = div64_u64(sample->aperf * 100, sample->mperf);
+ c0_pct = div_fp(int_tofp(sample->mperf), int_tofp(sample->tsc));
- c0_pct = div64_u64(sample->mperf * 100, sample->tsc);
sample->freq = fp_toint(
- mul_fp(int_tofp(cpu->pstate.max_pstate),
- int_tofp(core_pct * 1000)));
+ mul_fp(int_tofp(cpu->pstate.max_pstate * 1000), core_pct));
- sample->core_pct_busy = mul_fp(int_tofp(core_pct),
- div_fp(int_tofp(c0_pct + 1), int_tofp(100)));
+ sample->core_pct_busy = mul_fp(core_pct, c0_pct);
}
static inline void intel_pstate_sample(struct cpudata *cpu)
@@ -572,15 +581,18 @@ static inline void intel_pstate_sample(struct cpudata *cpu)
rdmsrl(MSR_IA32_MPERF, mperf);
tsc = native_read_tsc();
- cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT;
- cpu->samples[cpu->sample_ptr].aperf = aperf;
- cpu->samples[cpu->sample_ptr].mperf = mperf;
- cpu->samples[cpu->sample_ptr].tsc = tsc;
- cpu->samples[cpu->sample_ptr].aperf -= cpu->prev_aperf;
- cpu->samples[cpu->sample_ptr].mperf -= cpu->prev_mperf;
- cpu->samples[cpu->sample_ptr].tsc -= cpu->prev_tsc;
+ aperf = aperf >> FRAC_BITS;
+ mperf = mperf >> FRAC_BITS;
+ tsc = tsc >> FRAC_BITS;
+
+ cpu->sample.aperf = aperf;
+ cpu->sample.mperf = mperf;
+ cpu->sample.tsc = tsc;
+ cpu->sample.aperf -= cpu->prev_aperf;
+ cpu->sample.mperf -= cpu->prev_mperf;
+ cpu->sample.tsc -= cpu->prev_tsc;
- intel_pstate_calc_busy(cpu, &cpu->samples[cpu->sample_ptr]);
+ intel_pstate_calc_busy(cpu, &cpu->sample);
cpu->prev_aperf = aperf;
cpu->prev_mperf = mperf;
@@ -600,10 +612,11 @@ static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu)
{
int32_t core_busy, max_pstate, current_pstate;
- core_busy = cpu->samples[cpu->sample_ptr].core_pct_busy;
+ core_busy = cpu->sample.core_pct_busy;
max_pstate = int_tofp(cpu->pstate.max_pstate);
current_pstate = int_tofp(cpu->pstate.current_pstate);
- return mul_fp(core_busy, div_fp(max_pstate, current_pstate));
+ core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate));
+ return FP_ROUNDUP(core_busy);
}
static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
@@ -630,12 +643,10 @@ static void intel_pstate_timer_func(unsigned long __data)
{
struct cpudata *cpu = (struct cpudata *) __data;
struct sample *sample;
- u64 energy;
intel_pstate_sample(cpu);
- sample = &cpu->samples[cpu->sample_ptr];
- rdmsrl(MSR_PKG_ENERGY_STATUS, energy);
+ sample = &cpu->sample;
intel_pstate_adjust_busy_pstate(cpu);
@@ -644,7 +655,6 @@ static void intel_pstate_timer_func(unsigned long __data)
cpu->pstate.current_pstate,
sample->mperf,
sample->aperf,
- div64_u64(energy, energy_divisor),
sample->freq);
intel_pstate_set_sample_time(cpu);
@@ -717,7 +727,7 @@ static unsigned int intel_pstate_get(unsigned int cpu_num)
cpu = all_cpu_data[cpu_num];
if (!cpu)
return 0;
- sample = &cpu->samples[cpu->sample_ptr];
+ sample = &cpu->sample;
return sample->freq;
}
@@ -761,14 +771,17 @@ static int intel_pstate_verify_policy(struct cpufreq_policy *policy)
return 0;
}
-static int intel_pstate_cpu_exit(struct cpufreq_policy *policy)
+static void intel_pstate_stop_cpu(struct cpufreq_policy *policy)
{
- int cpu = policy->cpu;
+ int cpu_num = policy->cpu;
+ struct cpudata *cpu = all_cpu_data[cpu_num];
- del_timer(&all_cpu_data[cpu]->timer);
- kfree(all_cpu_data[cpu]);
- all_cpu_data[cpu] = NULL;
- return 0;
+ pr_info("intel_pstate CPU %d exiting\n", cpu_num);
+
+ del_timer_sync(&all_cpu_data[cpu_num]->timer);
+ intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate);
+ kfree(all_cpu_data[cpu_num]);
+ all_cpu_data[cpu_num] = NULL;
}
static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
@@ -806,7 +819,7 @@ static struct cpufreq_driver intel_pstate_driver = {
.setpolicy = intel_pstate_set_policy,
.get = intel_pstate_get,
.init = intel_pstate_cpu_init,
- .exit = intel_pstate_cpu_exit,
+ .stop_cpu = intel_pstate_stop_cpu,
.name = "intel_pstate",
};
@@ -926,7 +939,6 @@ static int __init intel_pstate_init(void)
int cpu, rc = 0;
const struct x86_cpu_id *id;
struct cpu_defaults *cpu_info;
- u64 units;
if (no_load)
return -ENODEV;
@@ -960,9 +972,6 @@ static int __init intel_pstate_init(void)
if (rc)
goto out;
- rdmsrl(MSR_RAPL_POWER_UNIT, units);
- energy_divisor = 1 << ((units >> 8) & 0x1f); /* bits{12:8} */
-
intel_pstate_debug_expose_params();
intel_pstate_sysfs_expose_params();
diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c
index eb7abe345b50..3d114bc5a97a 100644
--- a/drivers/cpufreq/kirkwood-cpufreq.c
+++ b/drivers/cpufreq/kirkwood-cpufreq.c
@@ -102,7 +102,6 @@ static struct cpufreq_driver kirkwood_cpufreq_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = kirkwood_cpufreq_target,
.init = kirkwood_cpufreq_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "kirkwood-cpufreq",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c
index 45bafddfd8ea..5c440f87ba8a 100644
--- a/drivers/cpufreq/longhaul.c
+++ b/drivers/cpufreq/longhaul.c
@@ -269,7 +269,7 @@ static void longhaul_setstate(struct cpufreq_policy *policy,
freqs.old = calc_speed(longhaul_get_cpu_mult());
freqs.new = speed;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
pr_debug("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
fsb, mult/10, mult%10, print_speed(speed/1000));
@@ -386,7 +386,7 @@ retry_loop:
}
}
/* Report true CPU frequency */
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freq_transition_end(policy, &freqs, 0);
if (!bm_timeout)
printk(KERN_INFO PFX "Warning: Timeout while waiting for "
@@ -913,7 +913,6 @@ static struct cpufreq_driver longhaul_driver = {
.target_index = longhaul_target,
.get = longhaul_get,
.init = longhaul_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "longhaul",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c
index b6581abc9207..a3588d61d933 100644
--- a/drivers/cpufreq/loongson2_cpufreq.c
+++ b/drivers/cpufreq/loongson2_cpufreq.c
@@ -104,7 +104,6 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
static int loongson2_cpufreq_exit(struct cpufreq_policy *policy)
{
- cpufreq_frequency_table_put_attr(policy->cpu);
clk_put(policy->clk);
return 0;
}
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
index 590f5b66d181..5f69c9aa703c 100644
--- a/drivers/cpufreq/omap-cpufreq.c
+++ b/drivers/cpufreq/omap-cpufreq.c
@@ -143,7 +143,6 @@ fail:
static int omap_cpu_exit(struct cpufreq_policy *policy)
{
- cpufreq_frequency_table_put_attr(policy->cpu);
freq_table_free();
clk_put(policy->clk);
return 0;
diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c
index 3d1cba9fd5f9..74f593e70e19 100644
--- a/drivers/cpufreq/p4-clockmod.c
+++ b/drivers/cpufreq/p4-clockmod.c
@@ -237,7 +237,6 @@ static struct cpufreq_driver p4clockmod_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = cpufreq_p4_target,
.init = cpufreq_p4_cpu_init,
- .exit = cpufreq_generic_exit,
.get = cpufreq_p4_get,
.name = "p4-clockmod",
.attr = cpufreq_generic_attr,
diff --git a/drivers/cpufreq/pasemi-cpufreq.c b/drivers/cpufreq/pasemi-cpufreq.c
index 0426008380d8..6a2b7d3e85a7 100644
--- a/drivers/cpufreq/pasemi-cpufreq.c
+++ b/drivers/cpufreq/pasemi-cpufreq.c
@@ -234,7 +234,6 @@ static int pas_cpufreq_cpu_exit(struct cpufreq_policy *policy)
if (sdcpwr_mapbase)
iounmap(sdcpwr_mapbase);
- cpufreq_frequency_table_put_attr(policy->cpu);
return 0;
}
diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c
index 1c0f1067af73..728a2d879499 100644
--- a/drivers/cpufreq/pcc-cpufreq.c
+++ b/drivers/cpufreq/pcc-cpufreq.c
@@ -215,7 +215,7 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy,
freqs.old = policy->cur;
freqs.new = target_freq;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
input_buffer = 0x1 | (((target_freq * 100)
/ (ioread32(&pcch_hdr->nominal) * 1000)) << 8);
@@ -231,7 +231,7 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy,
status = ioread16(&pcch_hdr->status);
iowrite16(0, &pcch_hdr->status);
- cpufreq_notify_post_transition(policy, &freqs, status != CMD_COMPLETE);
+ cpufreq_freq_transition_end(policy, &freqs, status != CMD_COMPLETE);
spin_unlock(&pcc_lock);
if (status != CMD_COMPLETE) {
diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c
index b9a444e358b5..62c6f2e5afce 100644
--- a/drivers/cpufreq/powernow-k6.c
+++ b/drivers/cpufreq/powernow-k6.c
@@ -148,11 +148,11 @@ static int powernow_k6_target(struct cpufreq_policy *policy,
freqs.old = busfreq * powernow_k6_get_cpu_multiplier();
freqs.new = busfreq * clock_ratio[best_i].driver_data;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
powernow_k6_set_cpu_multiplier(best_i);
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freq_transition_end(policy, &freqs, 0);
return 0;
}
@@ -231,7 +231,6 @@ static int powernow_k6_cpu_exit(struct cpufreq_policy *policy)
if (i == max_multiplier)
powernow_k6_target(policy, i);
}
- cpufreq_frequency_table_put_attr(policy->cpu);
return 0;
}
diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c
index 946708a1d745..f911645c3f6d 100644
--- a/drivers/cpufreq/powernow-k7.c
+++ b/drivers/cpufreq/powernow-k7.c
@@ -269,7 +269,7 @@ static int powernow_target(struct cpufreq_policy *policy, unsigned int index)
freqs.new = powernow_table[index].frequency;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
/* Now do the magic poking into the MSRs. */
@@ -290,7 +290,7 @@ static int powernow_target(struct cpufreq_policy *policy, unsigned int index)
if (have_a0 == 1)
local_irq_enable();
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freq_transition_end(policy, &freqs, 0);
return 0;
}
@@ -664,8 +664,6 @@ static int powernow_cpu_init(struct cpufreq_policy *policy)
static int powernow_cpu_exit(struct cpufreq_policy *policy)
{
- cpufreq_frequency_table_put_attr(policy->cpu);
-
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
if (acpi_processor_perf) {
acpi_processor_unregister_performance(acpi_processor_perf, 0);
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c
index e10b646634d7..770a9e1b3468 100644
--- a/drivers/cpufreq/powernow-k8.c
+++ b/drivers/cpufreq/powernow-k8.c
@@ -963,9 +963,9 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data,
policy = cpufreq_cpu_get(smp_processor_id());
cpufreq_cpu_put(policy);
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
res = transition_fid_vid(data, fid, vid);
- cpufreq_notify_post_transition(policy, &freqs, res);
+ cpufreq_freq_transition_end(policy, &freqs, res);
return res;
}
@@ -1076,7 +1076,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
{
struct powernow_k8_data *data;
struct init_on_cpu init_on_cpu;
- int rc;
+ int rc, cpu;
smp_call_function_single(pol->cpu, check_supported_cpu, &rc, 1);
if (rc)
@@ -1140,7 +1140,9 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
pr_debug("cpu_init done, current fid 0x%x, vid 0x%x\n",
data->currfid, data->currvid);
- per_cpu(powernow_data, pol->cpu) = data;
+ /* Point all the CPUs in this policy to the same data */
+ for_each_cpu(cpu, pol->cpus)
+ per_cpu(powernow_data, cpu) = data;
return 0;
@@ -1155,17 +1157,17 @@ err_out:
static int powernowk8_cpu_exit(struct cpufreq_policy *pol)
{
struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu);
+ int cpu;
if (!data)
return -EINVAL;
powernow_k8_cpu_exit_acpi(data);
- cpufreq_frequency_table_put_attr(pol->cpu);
-
kfree(data->powernow_table);
kfree(data);
- per_cpu(powernow_data, pol->cpu) = NULL;
+ for_each_cpu(cpu, pol->cpus)
+ per_cpu(powernow_data, cpu) = NULL;
return 0;
}
diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/ppc-corenet-cpufreq.c
index 051000f44ca2..3bd9123e7026 100644
--- a/drivers/cpufreq/ppc-corenet-cpufreq.c
+++ b/drivers/cpufreq/ppc-corenet-cpufreq.c
@@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/smp.h>
+#include <sysdev/fsl_soc.h>
/**
* struct cpu_data - per CPU data struct
@@ -205,7 +206,8 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
for_each_cpu(i, per_cpu(cpu_mask, cpu))
per_cpu(cpu_data, i) = data;
- policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+ policy->cpuinfo.transition_latency =
+ (12 * NSEC_PER_SEC) / fsl_get_sys_freq();
of_node_put(np);
return 0;
@@ -228,7 +230,6 @@ static int __exit corenet_cpufreq_cpu_exit(struct cpufreq_policy *policy)
struct cpu_data *data = per_cpu(cpu_data, policy->cpu);
unsigned int cpu;
- cpufreq_frequency_table_put_attr(policy->cpu);
of_node_put(data->parent);
kfree(data->table);
kfree(data);
diff --git a/drivers/cpufreq/ppc_cbe_cpufreq.c b/drivers/cpufreq/ppc_cbe_cpufreq.c
index e42ca9c31cea..af7b1cabd1e7 100644
--- a/drivers/cpufreq/ppc_cbe_cpufreq.c
+++ b/drivers/cpufreq/ppc_cbe_cpufreq.c
@@ -141,7 +141,6 @@ static struct cpufreq_driver cbe_cpufreq_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = cbe_cpufreq_target,
.init = cbe_cpufreq_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "cbe-cpufreq",
.flags = CPUFREQ_CONST_LOOPS,
};
diff --git a/drivers/cpufreq/pxa2xx-cpufreq.c b/drivers/cpufreq/pxa2xx-cpufreq.c
index a9195a86b069..e24269ab4e9b 100644
--- a/drivers/cpufreq/pxa2xx-cpufreq.c
+++ b/drivers/cpufreq/pxa2xx-cpufreq.c
@@ -427,7 +427,6 @@ static struct cpufreq_driver pxa_cpufreq_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = pxa_set_target,
.init = pxa_cpufreq_init,
- .exit = cpufreq_generic_exit,
.get = pxa_cpufreq_get,
.name = "PXA2xx",
};
diff --git a/drivers/cpufreq/pxa3xx-cpufreq.c b/drivers/cpufreq/pxa3xx-cpufreq.c
index 3785687e9d70..a01275900389 100644
--- a/drivers/cpufreq/pxa3xx-cpufreq.c
+++ b/drivers/cpufreq/pxa3xx-cpufreq.c
@@ -205,7 +205,6 @@ static struct cpufreq_driver pxa3xx_cpufreq_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = pxa3xx_cpufreq_set,
.init = pxa3xx_cpufreq_init,
- .exit = cpufreq_generic_exit,
.get = pxa3xx_cpufreq_get,
.name = "pxa3xx-cpufreq",
};
diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c
index 25069741b507..a3dc192d21f9 100644
--- a/drivers/cpufreq/s3c24xx-cpufreq.c
+++ b/drivers/cpufreq/s3c24xx-cpufreq.c
@@ -217,7 +217,7 @@ static int s3c_cpufreq_settarget(struct cpufreq_policy *policy,
s3c_cpufreq_updateclk(clk_pclk, cpu_new.freq.pclk);
/* start the frequency change */
- cpufreq_notify_transition(policy, &freqs.freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs.freqs);
/* If hclk is staying the same, then we do not need to
* re-write the IO or the refresh timings whilst we are changing
@@ -261,7 +261,7 @@ static int s3c_cpufreq_settarget(struct cpufreq_policy *policy,
local_irq_restore(flags);
/* notify everyone we've done this */
- cpufreq_notify_transition(policy, &freqs.freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freq_transition_end(policy, &freqs.freqs, 0);
s3c_freq_dbg("%s: finished\n", __func__);
return 0;
diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c
index 55a8e9fa9435..72421534fff5 100644
--- a/drivers/cpufreq/s5pv210-cpufreq.c
+++ b/drivers/cpufreq/s5pv210-cpufreq.c
@@ -18,7 +18,6 @@
#include <linux/cpufreq.h>
#include <linux/reboot.h>
#include <linux/regulator/consumer.h>
-#include <linux/suspend.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
@@ -435,18 +434,6 @@ exit:
return ret;
}
-#ifdef CONFIG_PM
-static int s5pv210_cpufreq_suspend(struct cpufreq_policy *policy)
-{
- return 0;
-}
-
-static int s5pv210_cpufreq_resume(struct cpufreq_policy *policy)
-{
- return 0;
-}
-#endif
-
static int check_mem_type(void __iomem *dmc_reg)
{
unsigned long val;
@@ -502,6 +489,7 @@ static int __init s5pv210_cpu_init(struct cpufreq_policy *policy)
s5pv210_dram_conf[1].refresh = (__raw_readl(S5P_VA_DMC1 + 0x30) * 1000);
s5pv210_dram_conf[1].freq = clk_get_rate(dmc1_clk);
+ policy->suspend_freq = SLEEP_FREQ;
return cpufreq_generic_init(policy, s5pv210_freq_table, 40000);
out_dmc1:
@@ -511,32 +499,6 @@ out_dmc0:
return ret;
}
-static int s5pv210_cpufreq_notifier_event(struct notifier_block *this,
- unsigned long event, void *ptr)
-{
- int ret;
-
- switch (event) {
- case PM_SUSPEND_PREPARE:
- ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, 0);
- if (ret < 0)
- return NOTIFY_BAD;
-
- /* Disable updation of cpu frequency */
- no_cpufreq_access = true;
- return NOTIFY_OK;
- case PM_POST_RESTORE:
- case PM_POST_SUSPEND:
- /* Enable updation of cpu frequency */
- no_cpufreq_access = false;
- cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, 0);
-
- return NOTIFY_OK;
- }
-
- return NOTIFY_DONE;
-}
-
static int s5pv210_cpufreq_reboot_notifier_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
@@ -558,15 +520,11 @@ static struct cpufreq_driver s5pv210_driver = {
.init = s5pv210_cpu_init,
.name = "s5pv210",
#ifdef CONFIG_PM
- .suspend = s5pv210_cpufreq_suspend,
- .resume = s5pv210_cpufreq_resume,
+ .suspend = cpufreq_generic_suspend,
+ .resume = cpufreq_generic_suspend, /* We need to set SLEEP FREQ again */
#endif
};
-static struct notifier_block s5pv210_cpufreq_notifier = {
- .notifier_call = s5pv210_cpufreq_notifier_event,
-};
-
static struct notifier_block s5pv210_cpufreq_reboot_notifier = {
.notifier_call = s5pv210_cpufreq_reboot_notifier_event,
};
@@ -586,7 +544,6 @@ static int __init s5pv210_cpufreq_init(void)
return PTR_ERR(int_regulator);
}
- register_pm_notifier(&s5pv210_cpufreq_notifier);
register_reboot_notifier(&s5pv210_cpufreq_reboot_notifier);
return cpufreq_register_driver(&s5pv210_driver);
diff --git a/drivers/cpufreq/sc520_freq.c b/drivers/cpufreq/sc520_freq.c
index 6adb354e359c..69371bf0886d 100644
--- a/drivers/cpufreq/sc520_freq.c
+++ b/drivers/cpufreq/sc520_freq.c
@@ -93,7 +93,6 @@ static struct cpufreq_driver sc520_freq_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = sc520_freq_target,
.init = sc520_freq_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "sc520_freq",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/sh-cpufreq.c b/drivers/cpufreq/sh-cpufreq.c
index 387af12503a6..86628e22b2a3 100644
--- a/drivers/cpufreq/sh-cpufreq.c
+++ b/drivers/cpufreq/sh-cpufreq.c
@@ -68,10 +68,10 @@ static int sh_cpufreq_target(struct cpufreq_policy *policy,
freqs.new = (freq + 500) / 1000;
freqs.flags = 0;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
set_cpus_allowed_ptr(current, &cpus_allowed);
clk_set_rate(cpuclk, freq);
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freq_transition_end(policy, &freqs, 0);
dev_dbg(dev, "set frequency %lu Hz\n", freq);
@@ -143,7 +143,6 @@ static int sh_cpufreq_cpu_exit(struct cpufreq_policy *policy)
unsigned int cpu = policy->cpu;
struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu);
- cpufreq_frequency_table_put_attr(cpu);
clk_put(cpuclk);
return 0;
diff --git a/drivers/cpufreq/sparc-us2e-cpufreq.c b/drivers/cpufreq/sparc-us2e-cpufreq.c
index 62aa23e219d4..b73feeb666f9 100644
--- a/drivers/cpufreq/sparc-us2e-cpufreq.c
+++ b/drivers/cpufreq/sparc-us2e-cpufreq.c
@@ -301,10 +301,8 @@ static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy)
static int us2e_freq_cpu_exit(struct cpufreq_policy *policy)
{
- if (cpufreq_us2e_driver) {
- cpufreq_frequency_table_put_attr(policy->cpu);
+ if (cpufreq_us2e_driver)
us2e_freq_target(policy, 0);
- }
return 0;
}
diff --git a/drivers/cpufreq/sparc-us3-cpufreq.c b/drivers/cpufreq/sparc-us3-cpufreq.c
index 724ffbd7105d..9bb42ba50efa 100644
--- a/drivers/cpufreq/sparc-us3-cpufreq.c
+++ b/drivers/cpufreq/sparc-us3-cpufreq.c
@@ -156,10 +156,8 @@ static int __init us3_freq_cpu_init(struct cpufreq_policy *policy)
static int us3_freq_cpu_exit(struct cpufreq_policy *policy)
{
- if (cpufreq_us3_driver) {
- cpufreq_frequency_table_put_attr(policy->cpu);
+ if (cpufreq_us3_driver)
us3_freq_target(policy, 0);
- }
return 0;
}
diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c
index 5c86e3fa5593..4cfdcff8a310 100644
--- a/drivers/cpufreq/spear-cpufreq.c
+++ b/drivers/cpufreq/spear-cpufreq.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
@@ -163,11 +164,10 @@ static struct cpufreq_driver spear_cpufreq_driver = {
.target_index = spear_cpufreq_target,
.get = cpufreq_generic_get,
.init = spear_cpufreq_init,
- .exit = cpufreq_generic_exit,
.attr = cpufreq_generic_attr,
};
-static int spear_cpufreq_driver_init(void)
+static int spear_cpufreq_probe(struct platform_device *pdev)
{
struct device_node *np;
const struct property *prop;
@@ -235,7 +235,15 @@ out_put_node:
of_node_put(np);
return ret;
}
-late_initcall(spear_cpufreq_driver_init);
+
+static struct platform_driver spear_cpufreq_platdrv = {
+ .driver = {
+ .name = "spear-cpufreq",
+ .owner = THIS_MODULE,
+ },
+ .probe = spear_cpufreq_probe,
+};
+module_platform_driver(spear_cpufreq_platdrv);
MODULE_AUTHOR("Deepak Sikri <deepak.sikri@st.com>");
MODULE_DESCRIPTION("SPEAr CPUFreq driver");
diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c
index 4e1daca5ce3b..6723f0390f20 100644
--- a/drivers/cpufreq/speedstep-centrino.c
+++ b/drivers/cpufreq/speedstep-centrino.c
@@ -406,8 +406,6 @@ static int centrino_cpu_exit(struct cpufreq_policy *policy)
if (!per_cpu(centrino_model, cpu))
return -ENODEV;
- cpufreq_frequency_table_put_attr(cpu);
-
per_cpu(centrino_model, cpu) = NULL;
return 0;
diff --git a/drivers/cpufreq/speedstep-ich.c b/drivers/cpufreq/speedstep-ich.c
index 7639b2be2a90..394ac159312a 100644
--- a/drivers/cpufreq/speedstep-ich.c
+++ b/drivers/cpufreq/speedstep-ich.c
@@ -311,7 +311,6 @@ static struct cpufreq_driver speedstep_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = speedstep_target,
.init = speedstep_cpu_init,
- .exit = cpufreq_generic_exit,
.get = speedstep_get,
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/speedstep-smi.c b/drivers/cpufreq/speedstep-smi.c
index 998c17b42200..db5d274dc13a 100644
--- a/drivers/cpufreq/speedstep-smi.c
+++ b/drivers/cpufreq/speedstep-smi.c
@@ -280,7 +280,6 @@ static struct cpufreq_driver speedstep_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = speedstep_target,
.init = speedstep_cpu_init,
- .exit = cpufreq_generic_exit,
.get = speedstep_get,
.resume = speedstep_resume,
.attr = cpufreq_generic_attr,
diff --git a/drivers/cpufreq/tegra-cpufreq.c b/drivers/cpufreq/tegra-cpufreq.c
index e652c1bd8d0f..63f00598a251 100644
--- a/drivers/cpufreq/tegra-cpufreq.c
+++ b/drivers/cpufreq/tegra-cpufreq.c
@@ -26,7 +26,6 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
-#include <linux/suspend.h>
static struct cpufreq_frequency_table freq_table[] = {
{ .frequency = 216000 },
@@ -47,9 +46,6 @@ static struct clk *pll_x_clk;
static struct clk *pll_p_clk;
static struct clk *emc_clk;
-static DEFINE_MUTEX(tegra_cpu_lock);
-static bool is_suspended;
-
static int tegra_cpu_clk_set_rate(unsigned long rate)
{
int ret;
@@ -112,42 +108,9 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy,
static int tegra_target(struct cpufreq_policy *policy, unsigned int index)
{
- int ret = -EBUSY;
-
- mutex_lock(&tegra_cpu_lock);
-
- if (!is_suspended)
- ret = tegra_update_cpu_speed(policy,
- freq_table[index].frequency);
-
- mutex_unlock(&tegra_cpu_lock);
- return ret;
+ return tegra_update_cpu_speed(policy, freq_table[index].frequency);
}
-static int tegra_pm_notify(struct notifier_block *nb, unsigned long event,
- void *dummy)
-{
- mutex_lock(&tegra_cpu_lock);
- if (event == PM_SUSPEND_PREPARE) {
- struct cpufreq_policy *policy = cpufreq_cpu_get(0);
- is_suspended = true;
- pr_info("Tegra cpufreq suspend: setting frequency to %d kHz\n",
- freq_table[0].frequency);
- if (clk_get_rate(cpu_clk) / 1000 != freq_table[0].frequency)
- tegra_update_cpu_speed(policy, freq_table[0].frequency);
- cpufreq_cpu_put(policy);
- } else if (event == PM_POST_SUSPEND) {
- is_suspended = false;
- }
- mutex_unlock(&tegra_cpu_lock);
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block tegra_cpu_pm_notifier = {
- .notifier_call = tegra_pm_notify,
-};
-
static int tegra_cpu_init(struct cpufreq_policy *policy)
{
int ret;
@@ -166,16 +129,13 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)
return ret;
}
- if (policy->cpu == 0)
- register_pm_notifier(&tegra_cpu_pm_notifier);
-
policy->clk = cpu_clk;
+ policy->suspend_freq = freq_table[0].frequency;
return 0;
}
static int tegra_cpu_exit(struct cpufreq_policy *policy)
{
- cpufreq_frequency_table_put_attr(policy->cpu);
clk_disable_unprepare(cpu_clk);
clk_disable_unprepare(emc_clk);
return 0;
@@ -190,6 +150,9 @@ static struct cpufreq_driver tegra_cpufreq_driver = {
.exit = tegra_cpu_exit,
.name = "tegra",
.attr = cpufreq_generic_attr,
+#ifdef CONFIG_PM
+ .suspend = cpufreq_generic_suspend,
+#endif
};
static int __init tegra_cpufreq_init(void)
diff --git a/drivers/cpufreq/unicore2-cpufreq.c b/drivers/cpufreq/unicore2-cpufreq.c
index 36cc330b8747..13be802b6170 100644
--- a/drivers/cpufreq/unicore2-cpufreq.c
+++ b/drivers/cpufreq/unicore2-cpufreq.c
@@ -44,9 +44,9 @@ static int ucv2_target(struct cpufreq_policy *policy,
freqs.old = policy->cur;
freqs.new = target_freq;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
ret = clk_set_rate(policy->mclk, target_freq * 1000);
- cpufreq_notify_post_transition(policy, &freqs, ret);
+ cpufreq_freq_transition_end(policy, &freqs, ret);
return ret;
}
diff --git a/drivers/cpuidle/coupled.c b/drivers/cpuidle/coupled.c
index e952936418d0..cb6654bfad77 100644
--- a/drivers/cpuidle/coupled.c
+++ b/drivers/cpuidle/coupled.c
@@ -323,7 +323,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_poke_pending))
- __smp_call_function_single(cpu, csd, 0);
+ smp_call_function_single_async(cpu, csd);
}
/**
diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c
index 78fd174c57e8..719f6fb5b1c3 100644
--- a/drivers/cpuidle/cpuidle-powernv.c
+++ b/drivers/cpuidle/cpuidle-powernv.c
@@ -11,9 +11,18 @@
#include <linux/cpuidle.h>
#include <linux/cpu.h>
#include <linux/notifier.h>
+#include <linux/clockchips.h>
+#include <linux/of.h>
#include <asm/machdep.h>
#include <asm/firmware.h>
+#include <asm/runlatch.h>
+
+/* Flags and constants used in PowerNV platform */
+
+#define MAX_POWERNV_IDLE_STATES 8
+#define IDLE_USE_INST_NAP 0x00010000 /* Use nap instruction */
+#define IDLE_USE_INST_SLEEP 0x00020000 /* Use sleep instruction */
struct cpuidle_driver powernv_idle_driver = {
.name = "powernv_idle",
@@ -30,12 +39,14 @@ static int snooze_loop(struct cpuidle_device *dev,
local_irq_enable();
set_thread_flag(TIF_POLLING_NRFLAG);
+ ppc64_runlatch_off();
while (!need_resched()) {
HMT_low();
HMT_very_low();
}
HMT_medium();
+ ppc64_runlatch_on();
clear_thread_flag(TIF_POLLING_NRFLAG);
smp_mb();
return index;
@@ -45,14 +56,42 @@ static int nap_loop(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
+ ppc64_runlatch_off();
power7_idle();
+ ppc64_runlatch_on();
+ return index;
+}
+
+static int fastsleep_loop(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ unsigned long old_lpcr = mfspr(SPRN_LPCR);
+ unsigned long new_lpcr;
+
+ if (unlikely(system_state < SYSTEM_RUNNING))
+ return index;
+
+ new_lpcr = old_lpcr;
+ new_lpcr &= ~(LPCR_MER | LPCR_PECE); /* lpcr[mer] must be 0 */
+
+ /* exit powersave upon external interrupt, but not decrementer
+ * interrupt.
+ */
+ new_lpcr |= LPCR_PECE0;
+
+ mtspr(SPRN_LPCR, new_lpcr);
+ power7_sleep();
+
+ mtspr(SPRN_LPCR, old_lpcr);
+
return index;
}
/*
* States for dedicated partition case.
*/
-static struct cpuidle_state powernv_states[] = {
+static struct cpuidle_state powernv_states[MAX_POWERNV_IDLE_STATES] = {
{ /* Snooze */
.name = "snooze",
.desc = "snooze",
@@ -60,13 +99,6 @@ static struct cpuidle_state powernv_states[] = {
.exit_latency = 0,
.target_residency = 0,
.enter = &snooze_loop },
- { /* NAP */
- .name = "NAP",
- .desc = "NAP",
- .flags = CPUIDLE_FLAG_TIME_VALID,
- .exit_latency = 10,
- .target_residency = 100,
- .enter = &nap_loop },
};
static int powernv_cpuidle_add_cpu_notifier(struct notifier_block *n,
@@ -127,19 +159,74 @@ static int powernv_cpuidle_driver_init(void)
return 0;
}
+static int powernv_add_idle_states(void)
+{
+ struct device_node *power_mgt;
+ struct property *prop;
+ int nr_idle_states = 1; /* Snooze */
+ int dt_idle_states;
+ u32 *flags;
+ int i;
+
+ /* Currently we have snooze statically defined */
+
+ power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
+ if (!power_mgt) {
+ pr_warn("opal: PowerMgmt Node not found\n");
+ return nr_idle_states;
+ }
+
+ prop = of_find_property(power_mgt, "ibm,cpu-idle-state-flags", NULL);
+ if (!prop) {
+ pr_warn("DT-PowerMgmt: missing ibm,cpu-idle-state-flags\n");
+ return nr_idle_states;
+ }
+
+ dt_idle_states = prop->length / sizeof(u32);
+ flags = (u32 *) prop->value;
+
+ for (i = 0; i < dt_idle_states; i++) {
+
+ if (flags[i] & IDLE_USE_INST_NAP) {
+ /* Add NAP state */
+ strcpy(powernv_states[nr_idle_states].name, "Nap");
+ strcpy(powernv_states[nr_idle_states].desc, "Nap");
+ powernv_states[nr_idle_states].flags = CPUIDLE_FLAG_TIME_VALID;
+ powernv_states[nr_idle_states].exit_latency = 10;
+ powernv_states[nr_idle_states].target_residency = 100;
+ powernv_states[nr_idle_states].enter = &nap_loop;
+ nr_idle_states++;
+ }
+
+ if (flags[i] & IDLE_USE_INST_SLEEP) {
+ /* Add FASTSLEEP state */
+ strcpy(powernv_states[nr_idle_states].name, "FastSleep");
+ strcpy(powernv_states[nr_idle_states].desc, "FastSleep");
+ powernv_states[nr_idle_states].flags =
+ CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TIMER_STOP;
+ powernv_states[nr_idle_states].exit_latency = 300;
+ powernv_states[nr_idle_states].target_residency = 1000000;
+ powernv_states[nr_idle_states].enter = &fastsleep_loop;
+ nr_idle_states++;
+ }
+ }
+
+ return nr_idle_states;
+}
+
/*
* powernv_idle_probe()
* Choose state table for shared versus dedicated partition
*/
static int powernv_idle_probe(void)
{
-
if (cpuidle_disable != IDLE_NO_OVERRIDE)
return -ENODEV;
if (firmware_has_feature(FW_FEATURE_OPALv3)) {
cpuidle_state_table = powernv_states;
- max_idle_state = ARRAY_SIZE(powernv_states);
+ /* Device tree can indicate more idle states */
+ max_idle_state = powernv_add_idle_states();
} else
return -ENODEV;
diff --git a/drivers/cpuidle/cpuidle-pseries.c b/drivers/cpuidle/cpuidle-pseries.c
index 7ab564aa0b1c..6f7b01956885 100644
--- a/drivers/cpuidle/cpuidle-pseries.c
+++ b/drivers/cpuidle/cpuidle-pseries.c
@@ -17,6 +17,7 @@
#include <asm/reg.h>
#include <asm/machdep.h>
#include <asm/firmware.h>
+#include <asm/runlatch.h>
#include <asm/plpar_wrappers.h>
struct cpuidle_driver pseries_idle_driver = {
@@ -29,6 +30,7 @@ static struct cpuidle_state *cpuidle_state_table;
static inline void idle_loop_prolog(unsigned long *in_purr)
{
+ ppc64_runlatch_off();
*in_purr = mfspr(SPRN_PURR);
/*
* Indicate to the HV that we are idle. Now would be
@@ -45,6 +47,10 @@ static inline void idle_loop_epilog(unsigned long in_purr)
wait_cycles += mfspr(SPRN_PURR) - in_purr;
get_lppaca()->wait_state_cycles = cpu_to_be64(wait_cycles);
get_lppaca()->idle = 0;
+
+ if (irqs_disabled())
+ local_irq_enable();
+ ppc64_runlatch_on();
}
static int snooze_loop(struct cpuidle_device *dev,
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index a55e68f2cfc8..8236746e46bb 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -65,6 +65,26 @@ int cpuidle_play_dead(void)
}
/**
+ * cpuidle_enabled - check if the cpuidle framework is ready
+ * @dev: cpuidle device for this cpu
+ * @drv: cpuidle driver for this cpu
+ *
+ * Return 0 on success, otherwise:
+ * -NODEV : the cpuidle framework is not available
+ * -EBUSY : the cpuidle framework is not initialized
+ */
+int cpuidle_enabled(struct cpuidle_driver *drv, struct cpuidle_device *dev)
+{
+ if (off || !initialized)
+ return -ENODEV;
+
+ if (!drv || !dev || !dev->enabled)
+ return -EBUSY;
+
+ return 0;
+}
+
+/**
* cpuidle_enter_state - enter the state and update stats
* @dev: cpuidle device for this cpu
* @drv: cpuidle driver for this cpu
@@ -85,7 +105,8 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
time_end = ktime_get();
- local_irq_enable();
+ if (!cpuidle_state_is_coupled(dev, drv, entered_state))
+ local_irq_enable();
diff = ktime_to_us(ktime_sub(time_end, time_start));
if (diff > INT_MAX)
@@ -108,61 +129,48 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
}
/**
- * cpuidle_idle_call - the main idle loop
+ * cpuidle_select - ask the cpuidle framework to choose an idle state
*
- * NOTE: no locks or semaphores should be used here
- * return non-zero on failure
+ * @drv: the cpuidle driver
+ * @dev: the cpuidle device
+ *
+ * Returns the index of the idle state.
*/
-int cpuidle_idle_call(void)
+int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
{
- struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
- struct cpuidle_driver *drv;
- int next_state, entered_state;
- bool broadcast;
-
- if (off || !initialized)
- return -ENODEV;
-
- /* check if the device is ready */
- if (!dev || !dev->enabled)
- return -EBUSY;
-
- drv = cpuidle_get_cpu_driver(dev);
-
- /* ask the governor for the next state */
- next_state = cpuidle_curr_governor->select(drv, dev);
- if (need_resched()) {
- dev->last_residency = 0;
- /* give the governor an opportunity to reflect on the outcome */
- if (cpuidle_curr_governor->reflect)
- cpuidle_curr_governor->reflect(dev, next_state);
- local_irq_enable();
- return 0;
- }
-
- trace_cpu_idle_rcuidle(next_state, dev->cpu);
-
- broadcast = !!(drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP);
-
- if (broadcast)
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
-
- if (cpuidle_state_is_coupled(dev, drv, next_state))
- entered_state = cpuidle_enter_state_coupled(dev, drv,
- next_state);
- else
- entered_state = cpuidle_enter_state(dev, drv, next_state);
-
- if (broadcast)
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
+ return cpuidle_curr_governor->select(drv, dev);
+}
- trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
+/**
+ * cpuidle_enter - enter into the specified idle state
+ *
+ * @drv: the cpuidle driver tied with the cpu
+ * @dev: the cpuidle device
+ * @index: the index in the idle state table
+ *
+ * Returns the index in the idle state, < 0 in case of error.
+ * The error code depends on the backend driver
+ */
+int cpuidle_enter(struct cpuidle_driver *drv, struct cpuidle_device *dev,
+ int index)
+{
+ if (cpuidle_state_is_coupled(dev, drv, index))
+ return cpuidle_enter_state_coupled(dev, drv, index);
+ return cpuidle_enter_state(dev, drv, index);
+}
- /* give the governor an opportunity to reflect on the outcome */
+/**
+ * cpuidle_reflect - tell the underlying governor what was the state
+ * we were in
+ *
+ * @dev : the cpuidle device
+ * @index: the index in the idle state table
+ *
+ */
+void cpuidle_reflect(struct cpuidle_device *dev, int index)
+{
if (cpuidle_curr_governor->reflect)
- cpuidle_curr_governor->reflect(dev, entered_state);
-
- return 0;
+ cpuidle_curr_governor->reflect(dev, index);
}
/**
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c
index 06dbe7c86199..136d6a283e0a 100644
--- a/drivers/cpuidle/driver.c
+++ b/drivers/cpuidle/driver.c
@@ -209,7 +209,7 @@ static void poll_idle_init(struct cpuidle_driver *drv)
state->exit_latency = 0;
state->target_residency = 0;
state->power_usage = -1;
- state->flags = 0;
+ state->flags = CPUIDLE_FLAG_TIME_VALID;
state->enter = poll_idle;
state->disabled = false;
}
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index cf7f2f0e4ef5..71b523293354 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -122,9 +122,8 @@ struct menu_device {
int last_state_idx;
int needs_update;
- unsigned int expected_us;
+ unsigned int next_timer_us;
unsigned int predicted_us;
- unsigned int exit_us;
unsigned int bucket;
unsigned int correction_factor[BUCKETS];
unsigned int intervals[INTERVALS];
@@ -257,7 +256,7 @@ again:
stddev = int_sqrt(stddev);
if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3))
|| stddev <= 20) {
- if (data->expected_us > avg)
+ if (data->next_timer_us > avg)
data->predicted_us = avg;
return;
}
@@ -289,7 +288,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
struct menu_device *data = &__get_cpu_var(menu_devices);
int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
int i;
- int multiplier;
+ unsigned int interactivity_req;
struct timespec t;
if (data->needs_update) {
@@ -298,7 +297,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
}
data->last_state_idx = 0;
- data->exit_us = 0;
/* Special case when user has set very strict latency requirement */
if (unlikely(latency_req == 0))
@@ -306,13 +304,11 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
/* determine the expected residency time, round up */
t = ktime_to_timespec(tick_nohz_get_sleep_length());
- data->expected_us =
+ data->next_timer_us =
t.tv_sec * USEC_PER_SEC + t.tv_nsec / NSEC_PER_USEC;
- data->bucket = which_bucket(data->expected_us);
-
- multiplier = performance_multiplier();
+ data->bucket = which_bucket(data->next_timer_us);
/*
* if the correction factor is 0 (eg first time init or cpu hotplug
@@ -326,17 +322,26 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
* operands are 32 bits.
* Make sure to round up for half microseconds.
*/
- data->predicted_us = div_round64((uint64_t)data->expected_us *
+ data->predicted_us = div_round64((uint64_t)data->next_timer_us *
data->correction_factor[data->bucket],
RESOLUTION * DECAY);
get_typical_interval(data);
/*
+ * Performance multiplier defines a minimum predicted idle
+ * duration / latency ratio. Adjust the latency limit if
+ * necessary.
+ */
+ interactivity_req = data->predicted_us / performance_multiplier();
+ if (latency_req > interactivity_req)
+ latency_req = interactivity_req;
+
+ /*
* We want to default to C1 (hlt), not to busy polling
* unless the timer is happening really really soon.
*/
- if (data->expected_us > 5 &&
+ if (data->next_timer_us > 5 &&
!drv->states[CPUIDLE_DRIVER_STATE_START].disabled &&
dev->states_usage[CPUIDLE_DRIVER_STATE_START].disable == 0)
data->last_state_idx = CPUIDLE_DRIVER_STATE_START;
@@ -355,11 +360,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
continue;
if (s->exit_latency > latency_req)
continue;
- if (s->exit_latency * multiplier > data->predicted_us)
- continue;
data->last_state_idx = i;
- data->exit_us = s->exit_latency;
}
return data->last_state_idx;
@@ -390,36 +392,47 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
{
struct menu_device *data = &__get_cpu_var(menu_devices);
int last_idx = data->last_state_idx;
- unsigned int last_idle_us = cpuidle_get_last_residency(dev);
struct cpuidle_state *target = &drv->states[last_idx];
unsigned int measured_us;
unsigned int new_factor;
/*
- * Ugh, this idle state doesn't support residency measurements, so we
- * are basically lost in the dark. As a compromise, assume we slept
- * for the whole expected time.
+ * Try to figure out how much time passed between entry to low
+ * power state and occurrence of the wakeup event.
+ *
+ * If the entered idle state didn't support residency measurements,
+ * we are basically lost in the dark how much time passed.
+ * As a compromise, assume we slept for the whole expected time.
+ *
+ * Any measured amount of time will include the exit latency.
+ * Since we are interested in when the wakeup begun, not when it
+ * was completed, we must substract the exit latency. However, if
+ * the measured amount of time is less than the exit latency,
+ * assume the state was never reached and the exit latency is 0.
*/
- if (unlikely(!(target->flags & CPUIDLE_FLAG_TIME_VALID)))
- last_idle_us = data->expected_us;
+ if (unlikely(!(target->flags & CPUIDLE_FLAG_TIME_VALID))) {
+ /* Use timer value as is */
+ measured_us = data->next_timer_us;
+ } else {
+ /* Use measured value */
+ measured_us = cpuidle_get_last_residency(dev);
- measured_us = last_idle_us;
-
- /*
- * We correct for the exit latency; we are assuming here that the
- * exit latency happens after the event that we're interested in.
- */
- if (measured_us > data->exit_us)
- measured_us -= data->exit_us;
+ /* Deduct exit latency */
+ if (measured_us > target->exit_latency)
+ measured_us -= target->exit_latency;
+ /* Make sure our coefficients do not exceed unity */
+ if (measured_us > data->next_timer_us)
+ measured_us = data->next_timer_us;
+ }
/* 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;
+ if (data->next_timer_us > 0 && measured_us < MAX_INTERESTING)
+ new_factor += RESOLUTION * measured_us / data->next_timer_us;
else
/*
* we were idle so long that we count it as a perfect
@@ -439,7 +452,7 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
data->correction_factor[data->bucket] = new_factor;
/* update the repeating-pattern data */
- data->intervals[data->interval_ptr++] = last_idle_us;
+ data->intervals[data->interval_ptr++] = measured_us;
if (data->interval_ptr >= INTERVALS)
data->interval_ptr = 0;
}
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 13857f5d28f7..03ccdb0ccf9e 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -262,6 +262,17 @@ config CRYPTO_DEV_OMAP_AES
OMAP processors have AES module accelerator. Select this if you
want to use the OMAP module for AES algorithms.
+config CRYPTO_DEV_OMAP_DES
+ tristate "Support for OMAP DES3DES hw engine"
+ depends on ARCH_OMAP2PLUS
+ select CRYPTO_DES
+ select CRYPTO_BLKCIPHER2
+ help
+ OMAP processors have DES/3DES module accelerator. Select this if you
+ want to use the OMAP module for DES and 3DES algorithms. Currently
+ the ECB and CBC modes of operation supported by the driver. Also
+ accesses made on unaligned boundaries are also supported.
+
config CRYPTO_DEV_PICOXCELL
tristate "Support for picoXcell IPSEC and Layer2 crypto engines"
depends on ARCH_PICOXCELL && HAVE_CLK
@@ -300,17 +311,6 @@ config CRYPTO_DEV_S5P
Select this to offload Samsung S5PV210 or S5PC110 from AES
algorithms execution.
-config CRYPTO_DEV_TEGRA_AES
- tristate "Support for TEGRA AES hw engine"
- depends on ARCH_TEGRA
- select CRYPTO_AES
- help
- TEGRA processors have AES module accelerator. Select this if you
- want to use the TEGRA module for AES algorithms.
-
- To compile this driver as a module, choose M here: the module
- will be called tegra-aes.
-
config CRYPTO_DEV_NX
bool "Support for IBM Power7+ in-Nest cryptographic acceleration"
depends on PPC64 && IBMVIO
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 0bc6aa0a54d7..482f090d16d0 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_CRYPTO_DEV_NIAGARA2) += n2_crypto.o
n2_crypto-y := n2_core.o n2_asm.o
obj-$(CONFIG_CRYPTO_DEV_NX) += nx/
obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
+obj-$(CONFIG_CRYPTO_DEV_OMAP_DES) += omap-des.o
obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o
obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
@@ -21,5 +22,4 @@ obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/
obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
obj-$(CONFIG_CRYPTO_DEV_SAHARA) += sahara.o
obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
-obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/
diff --git a/drivers/crypto/bfin_crc.c b/drivers/crypto/bfin_crc.c
index d797f31f5d85..c9ff298e6d26 100644
--- a/drivers/crypto/bfin_crc.c
+++ b/drivers/crypto/bfin_crc.c
@@ -139,7 +139,6 @@ static int bfin_crypto_crc_init_hw(struct bfin_crypto_crc *crc, u32 key)
/* setup CRC interrupts */
crc->regs->status = CMPERRI | DCNTEXPI;
crc->regs->intrenset = CMPERRI | DCNTEXPI;
- SSYNC();
return 0;
}
@@ -285,17 +284,12 @@ static void bfin_crypto_crc_config_dma(struct bfin_crypto_crc *crc)
if (i == 0)
return;
- flush_dcache_range((unsigned int)crc->sg_cpu,
- (unsigned int)crc->sg_cpu +
- i * sizeof(struct dma_desc_array));
-
/* Set the last descriptor to stop mode */
crc->sg_cpu[i - 1].cfg &= ~(DMAFLOW | NDSIZE);
crc->sg_cpu[i - 1].cfg |= DI_EN;
set_dma_curr_desc_addr(crc->dma_ch, (unsigned long *)crc->sg_dma);
set_dma_x_count(crc->dma_ch, 0);
set_dma_x_modify(crc->dma_ch, 0);
- SSYNC();
set_dma_config(crc->dma_ch, dma_config);
}
@@ -415,7 +409,6 @@ finish_update:
/* finally kick off CRC operation */
crc->regs->control |= BLKEN;
- SSYNC();
return -EINPROGRESS;
}
@@ -539,7 +532,6 @@ static irqreturn_t bfin_crypto_crc_handler(int irq, void *dev_id)
if (crc->regs->status & DCNTEXP) {
crc->regs->status = DCNTEXP;
- SSYNC();
/* prepare results */
put_unaligned_le32(crc->regs->result, crc->req->result);
@@ -594,7 +586,7 @@ static int bfin_crypto_crc_probe(struct platform_device *pdev)
unsigned int timeout = 100000;
int ret;
- crc = kzalloc(sizeof(*crc), GFP_KERNEL);
+ crc = devm_kzalloc(dev, sizeof(*crc), GFP_KERNEL);
if (!crc) {
dev_err(&pdev->dev, "fail to malloc bfin_crypto_crc\n");
return -ENOMEM;
@@ -610,42 +602,39 @@ static int bfin_crypto_crc_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
- ret = -ENOENT;
- goto out_error_free_mem;
+ return -ENOENT;
}
- crc->regs = ioremap(res->start, resource_size(res));
- if (!crc->regs) {
+ crc->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR((void *)crc->regs)) {
dev_err(&pdev->dev, "Cannot map CRC IO\n");
- ret = -ENXIO;
- goto out_error_free_mem;
+ return PTR_ERR((void *)crc->regs);
}
crc->irq = platform_get_irq(pdev, 0);
if (crc->irq < 0) {
dev_err(&pdev->dev, "No CRC DCNTEXP IRQ specified\n");
- ret = -ENOENT;
- goto out_error_unmap;
+ return -ENOENT;
}
- ret = request_irq(crc->irq, bfin_crypto_crc_handler, IRQF_SHARED, dev_name(dev), crc);
+ ret = devm_request_irq(dev, crc->irq, bfin_crypto_crc_handler,
+ IRQF_SHARED, dev_name(dev), crc);
if (ret) {
dev_err(&pdev->dev, "Unable to request blackfin crc irq\n");
- goto out_error_unmap;
+ return ret;
}
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (res == NULL) {
dev_err(&pdev->dev, "No CRC DMA channel specified\n");
- ret = -ENOENT;
- goto out_error_irq;
+ return -ENOENT;
}
crc->dma_ch = res->start;
ret = request_dma(crc->dma_ch, dev_name(dev));
if (ret) {
dev_err(&pdev->dev, "Unable to attach Blackfin CRC DMA channel\n");
- goto out_error_irq;
+ return ret;
}
crc->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &crc->sg_dma, GFP_KERNEL);
@@ -660,9 +649,7 @@ static int bfin_crypto_crc_probe(struct platform_device *pdev)
crc->sg_mid_buf = (u8 *)(crc->sg_cpu + ((CRC_MAX_DMA_DESC + 1) << 1));
crc->regs->control = 0;
- SSYNC();
crc->regs->poly = crc->poly = (u32)pdev->dev.platform_data;
- SSYNC();
while (!(crc->regs->status & LUTDONE) && (--timeout) > 0)
cpu_relax();
@@ -693,12 +680,6 @@ out_error_dma:
if (crc->sg_cpu)
dma_free_coherent(&pdev->dev, PAGE_SIZE, crc->sg_cpu, crc->sg_dma);
free_dma(crc->dma_ch);
-out_error_irq:
- free_irq(crc->irq, crc);
-out_error_unmap:
- iounmap((void *)crc->regs);
-out_error_free_mem:
- kfree(crc);
return ret;
}
@@ -721,10 +702,6 @@ static int bfin_crypto_crc_remove(struct platform_device *pdev)
crypto_unregister_ahash(&algs);
tasklet_kill(&crc->done_task);
free_dma(crc->dma_ch);
- if (crc->irq > 0)
- free_irq(crc->irq, crc);
- iounmap((void *)crc->regs);
- kfree(crc);
return 0;
}
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index b71f2fd749df..5f891254db73 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -66,10 +66,14 @@
/* length of descriptors text */
#define DESC_AEAD_BASE (4 * CAAM_CMD_SZ)
-#define DESC_AEAD_ENC_LEN (DESC_AEAD_BASE + 16 * CAAM_CMD_SZ)
-#define DESC_AEAD_DEC_LEN (DESC_AEAD_BASE + 21 * CAAM_CMD_SZ)
+#define DESC_AEAD_ENC_LEN (DESC_AEAD_BASE + 15 * CAAM_CMD_SZ)
+#define DESC_AEAD_DEC_LEN (DESC_AEAD_BASE + 18 * CAAM_CMD_SZ)
#define DESC_AEAD_GIVENC_LEN (DESC_AEAD_ENC_LEN + 7 * CAAM_CMD_SZ)
+#define DESC_AEAD_NULL_BASE (3 * CAAM_CMD_SZ)
+#define DESC_AEAD_NULL_ENC_LEN (DESC_AEAD_NULL_BASE + 14 * CAAM_CMD_SZ)
+#define DESC_AEAD_NULL_DEC_LEN (DESC_AEAD_NULL_BASE + 17 * CAAM_CMD_SZ)
+
#define DESC_ABLKCIPHER_BASE (3 * CAAM_CMD_SZ)
#define DESC_ABLKCIPHER_ENC_LEN (DESC_ABLKCIPHER_BASE + \
20 * CAAM_CMD_SZ)
@@ -104,27 +108,14 @@ static inline void append_dec_op1(u32 *desc, u32 type)
}
/*
- * Wait for completion of class 1 key loading before allowing
- * error propagation
- */
-static inline void append_dec_shr_done(u32 *desc)
-{
- u32 *jump_cmd;
-
- jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TEST_ALL);
- set_jump_tgt_here(desc, jump_cmd);
- append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD);
-}
-
-/*
* For aead functions, read payload and write payload,
* both of which are specified in req->src and req->dst
*/
static inline void aead_append_src_dst(u32 *desc, u32 msg_type)
{
+ append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF);
append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH |
KEY_VLF | msg_type | FIFOLD_TYPE_LASTBOTH);
- append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF);
}
/*
@@ -211,9 +202,196 @@ static void init_sh_desc_key_aead(u32 *desc, struct caam_ctx *ctx,
append_key_aead(desc, ctx, keys_fit_inline);
set_jump_tgt_here(desc, key_jump_cmd);
+}
+
+static int aead_null_set_sh_desc(struct crypto_aead *aead)
+{
+ struct aead_tfm *tfm = &aead->base.crt_aead;
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *jrdev = ctx->jrdev;
+ bool keys_fit_inline = false;
+ u32 *key_jump_cmd, *jump_cmd, *read_move_cmd, *write_move_cmd;
+ u32 *desc;
+
+ /*
+ * Job Descriptor and Shared Descriptors
+ * must all fit into the 64-word Descriptor h/w Buffer
+ */
+ if (DESC_AEAD_NULL_ENC_LEN + DESC_JOB_IO_LEN +
+ ctx->split_key_pad_len <= CAAM_DESC_BYTES_MAX)
+ keys_fit_inline = true;
+
+ /* aead_encrypt shared descriptor */
+ desc = ctx->sh_desc_enc;
+
+ init_sh_desc(desc, HDR_SHARE_SERIAL);
+
+ /* Skip if already shared */
+ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
+ JUMP_COND_SHRD);
+ if (keys_fit_inline)
+ append_key_as_imm(desc, ctx->key, ctx->split_key_pad_len,
+ ctx->split_key_len, CLASS_2 |
+ KEY_DEST_MDHA_SPLIT | KEY_ENC);
+ else
+ append_key(desc, ctx->key_dma, ctx->split_key_len, CLASS_2 |
+ KEY_DEST_MDHA_SPLIT | KEY_ENC);
+ set_jump_tgt_here(desc, key_jump_cmd);
+
+ /* cryptlen = seqoutlen - authsize */
+ append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize);
+
+ /*
+ * NULL encryption; IV is zero
+ * assoclen = (assoclen + cryptlen) - cryptlen
+ */
+ append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG3, CAAM_CMD_SZ);
+
+ /* read assoc before reading payload */
+ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG |
+ KEY_VLF);
+
+ /* Prepare to read and write cryptlen bytes */
+ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
+ append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
+
+ /*
+ * MOVE_LEN opcode is not available in all SEC HW revisions,
+ * thus need to do some magic, i.e. self-patch the descriptor
+ * buffer.
+ */
+ read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF |
+ MOVE_DEST_MATH3 |
+ (0x6 << MOVE_LEN_SHIFT));
+ write_move_cmd = append_move(desc, MOVE_SRC_MATH3 |
+ MOVE_DEST_DESCBUF |
+ MOVE_WAITCOMP |
+ (0x8 << MOVE_LEN_SHIFT));
+
+ /* Class 2 operation */
+ append_operation(desc, ctx->class2_alg_type |
+ OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT);
+
+ /* Read and write cryptlen bytes */
+ aead_append_src_dst(desc, FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1);
+
+ set_move_tgt_here(desc, read_move_cmd);
+ set_move_tgt_here(desc, write_move_cmd);
+ append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO);
+ append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO |
+ MOVE_AUX_LS);
+
+ /* Write ICV */
+ append_seq_store(desc, ctx->authsize, LDST_CLASS_2_CCB |
+ LDST_SRCDST_BYTE_CONTEXT);
+
+ ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc,
+ desc_bytes(desc),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(jrdev, ctx->sh_desc_enc_dma)) {
+ dev_err(jrdev, "unable to map shared descriptor\n");
+ return -ENOMEM;
+ }
+#ifdef DEBUG
+ print_hex_dump(KERN_ERR,
+ "aead null enc shdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc,
+ desc_bytes(desc), 1);
+#endif
+
+ /*
+ * Job Descriptor and Shared Descriptors
+ * must all fit into the 64-word Descriptor h/w Buffer
+ */
+ if (DESC_AEAD_NULL_DEC_LEN + DESC_JOB_IO_LEN +
+ ctx->split_key_pad_len <= CAAM_DESC_BYTES_MAX)
+ keys_fit_inline = true;
+
+ desc = ctx->sh_desc_dec;
+
+ /* aead_decrypt shared descriptor */
+ init_sh_desc(desc, HDR_SHARE_SERIAL);
+
+ /* Skip if already shared */
+ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
+ JUMP_COND_SHRD);
+ if (keys_fit_inline)
+ append_key_as_imm(desc, ctx->key, ctx->split_key_pad_len,
+ ctx->split_key_len, CLASS_2 |
+ KEY_DEST_MDHA_SPLIT | KEY_ENC);
+ else
+ append_key(desc, ctx->key_dma, ctx->split_key_len, CLASS_2 |
+ KEY_DEST_MDHA_SPLIT | KEY_ENC);
+ set_jump_tgt_here(desc, key_jump_cmd);
+
+ /* Class 2 operation */
+ append_operation(desc, ctx->class2_alg_type |
+ OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON);
+
+ /* assoclen + cryptlen = seqinlen - ivsize - authsize */
+ append_math_sub_imm_u32(desc, REG3, SEQINLEN, IMM,
+ ctx->authsize + tfm->ivsize);
+ /* assoclen = (assoclen + cryptlen) - cryptlen */
+ append_math_sub(desc, REG2, SEQOUTLEN, REG0, CAAM_CMD_SZ);
+ append_math_sub(desc, VARSEQINLEN, REG3, REG2, CAAM_CMD_SZ);
+
+ /* read assoc before reading payload */
+ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG |
+ KEY_VLF);
+
+ /* Prepare to read and write cryptlen bytes */
+ append_math_add(desc, VARSEQINLEN, ZERO, REG2, CAAM_CMD_SZ);
+ append_math_add(desc, VARSEQOUTLEN, ZERO, REG2, CAAM_CMD_SZ);
+
+ /*
+ * MOVE_LEN opcode is not available in all SEC HW revisions,
+ * thus need to do some magic, i.e. self-patch the descriptor
+ * buffer.
+ */
+ read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF |
+ MOVE_DEST_MATH2 |
+ (0x6 << MOVE_LEN_SHIFT));
+ write_move_cmd = append_move(desc, MOVE_SRC_MATH2 |
+ MOVE_DEST_DESCBUF |
+ MOVE_WAITCOMP |
+ (0x8 << MOVE_LEN_SHIFT));
+
+ /* Read and write cryptlen bytes */
+ aead_append_src_dst(desc, FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1);
+
+ /*
+ * Insert a NOP here, since we need at least 4 instructions between
+ * code patching the descriptor buffer and the location being patched.
+ */
+ jump_cmd = append_jump(desc, JUMP_TEST_ALL);
+ set_jump_tgt_here(desc, jump_cmd);
- /* Propagate errors from shared to job descriptor */
- append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD);
+ set_move_tgt_here(desc, read_move_cmd);
+ set_move_tgt_here(desc, write_move_cmd);
+ append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO);
+ append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO |
+ MOVE_AUX_LS);
+ append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO);
+
+ /* Load ICV */
+ append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS2 |
+ FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV);
+
+ ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc,
+ desc_bytes(desc),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(jrdev, ctx->sh_desc_dec_dma)) {
+ dev_err(jrdev, "unable to map shared descriptor\n");
+ return -ENOMEM;
+ }
+#ifdef DEBUG
+ print_hex_dump(KERN_ERR,
+ "aead null dec shdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc,
+ desc_bytes(desc), 1);
+#endif
+
+ return 0;
}
static int aead_set_sh_desc(struct crypto_aead *aead)
@@ -222,13 +400,16 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
struct caam_ctx *ctx = crypto_aead_ctx(aead);
struct device *jrdev = ctx->jrdev;
bool keys_fit_inline = false;
- u32 *key_jump_cmd, *jump_cmd;
u32 geniv, moveiv;
u32 *desc;
- if (!ctx->enckeylen || !ctx->authsize)
+ if (!ctx->authsize)
return 0;
+ /* NULL encryption / decryption */
+ if (!ctx->enckeylen)
+ return aead_null_set_sh_desc(aead);
+
/*
* Job Descriptor and Shared Descriptors
* must all fit into the 64-word Descriptor h/w Buffer
@@ -253,7 +434,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
/* assoclen + cryptlen = seqinlen - ivsize */
append_math_sub_imm_u32(desc, REG2, SEQINLEN, IMM, tfm->ivsize);
- /* assoclen + cryptlen = (assoclen + cryptlen) - cryptlen */
+ /* assoclen = (assoclen + cryptlen) - cryptlen */
append_math_sub(desc, VARSEQINLEN, REG2, REG3, CAAM_CMD_SZ);
/* read assoc before reading payload */
@@ -296,30 +477,18 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
CAAM_DESC_BYTES_MAX)
keys_fit_inline = true;
- desc = ctx->sh_desc_dec;
-
/* aead_decrypt shared descriptor */
- init_sh_desc(desc, HDR_SHARE_SERIAL);
-
- /* Skip if already shared */
- key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
- JUMP_COND_SHRD);
-
- append_key_aead(desc, ctx, keys_fit_inline);
+ desc = ctx->sh_desc_dec;
- /* Only propagate error immediately if shared */
- jump_cmd = append_jump(desc, JUMP_TEST_ALL);
- set_jump_tgt_here(desc, key_jump_cmd);
- append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD);
- set_jump_tgt_here(desc, jump_cmd);
+ init_sh_desc_key_aead(desc, ctx, keys_fit_inline);
/* Class 2 operation */
append_operation(desc, ctx->class2_alg_type |
OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON);
- /* assoclen + cryptlen = seqinlen - ivsize */
+ /* assoclen + cryptlen = seqinlen - ivsize - authsize */
append_math_sub_imm_u32(desc, REG3, SEQINLEN, IMM,
- ctx->authsize + tfm->ivsize)
+ ctx->authsize + tfm->ivsize);
/* assoclen = (assoclen + cryptlen) - cryptlen */
append_math_sub(desc, REG2, SEQOUTLEN, REG0, CAAM_CMD_SZ);
append_math_sub(desc, VARSEQINLEN, REG3, REG2, CAAM_CMD_SZ);
@@ -340,7 +509,6 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
/* Load ICV */
append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS2 |
FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV);
- append_dec_shr_done(desc);
ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc,
desc_bytes(desc),
@@ -532,7 +700,7 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
struct ablkcipher_tfm *tfm = &ablkcipher->base.crt_ablkcipher;
struct device *jrdev = ctx->jrdev;
int ret = 0;
- u32 *key_jump_cmd, *jump_cmd;
+ u32 *key_jump_cmd;
u32 *desc;
#ifdef DEBUG
@@ -563,9 +731,6 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
set_jump_tgt_here(desc, key_jump_cmd);
- /* Propagate errors from shared to job descriptor */
- append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD);
-
/* Load iv */
append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT |
LDST_CLASS_1_CCB | tfm->ivsize);
@@ -603,11 +768,7 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
ctx->enckeylen, CLASS_1 |
KEY_DEST_CLASS_REG);
- /* For aead, only propagate error immediately if shared */
- jump_cmd = append_jump(desc, JUMP_TEST_ALL);
set_jump_tgt_here(desc, key_jump_cmd);
- append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD);
- set_jump_tgt_here(desc, jump_cmd);
/* load IV */
append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT |
@@ -619,9 +780,6 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
/* Perform operation */
ablkcipher_append_src_dst(desc);
- /* Wait for key to load before allowing propagating error */
- append_dec_shr_done(desc);
-
ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc,
desc_bytes(desc),
DMA_TO_DEVICE);
@@ -1459,6 +1617,11 @@ static int aead_givencrypt(struct aead_givcrypt_request *areq)
return ret;
}
+static int aead_null_givencrypt(struct aead_givcrypt_request *areq)
+{
+ return aead_encrypt(&areq->areq);
+}
+
/*
* allocate and map the ablkcipher extended descriptor for ablkcipher
*/
@@ -1648,6 +1811,124 @@ struct caam_alg_template {
static struct caam_alg_template driver_algs[] = {
/* single-pass ipsec_esp descriptor */
{
+ .name = "authenc(hmac(md5),ecb(cipher_null))",
+ .driver_name = "authenc-hmac-md5-ecb-cipher_null-caam",
+ .blocksize = NULL_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .template_aead = {
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .givencrypt = aead_null_givencrypt,
+ .geniv = "<built-in>",
+ .ivsize = NULL_IV_SIZE,
+ .maxauthsize = MD5_DIGEST_SIZE,
+ },
+ .class1_alg_type = 0,
+ .class2_alg_type = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC_PRECOMP,
+ .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC,
+ },
+ {
+ .name = "authenc(hmac(sha1),ecb(cipher_null))",
+ .driver_name = "authenc-hmac-sha1-ecb-cipher_null-caam",
+ .blocksize = NULL_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .template_aead = {
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .givencrypt = aead_null_givencrypt,
+ .geniv = "<built-in>",
+ .ivsize = NULL_IV_SIZE,
+ .maxauthsize = SHA1_DIGEST_SIZE,
+ },
+ .class1_alg_type = 0,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP,
+ .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC,
+ },
+ {
+ .name = "authenc(hmac(sha224),ecb(cipher_null))",
+ .driver_name = "authenc-hmac-sha224-ecb-cipher_null-caam",
+ .blocksize = NULL_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .template_aead = {
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .givencrypt = aead_null_givencrypt,
+ .geniv = "<built-in>",
+ .ivsize = NULL_IV_SIZE,
+ .maxauthsize = SHA224_DIGEST_SIZE,
+ },
+ .class1_alg_type = 0,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC,
+ },
+ {
+ .name = "authenc(hmac(sha256),ecb(cipher_null))",
+ .driver_name = "authenc-hmac-sha256-ecb-cipher_null-caam",
+ .blocksize = NULL_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .template_aead = {
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .givencrypt = aead_null_givencrypt,
+ .geniv = "<built-in>",
+ .ivsize = NULL_IV_SIZE,
+ .maxauthsize = SHA256_DIGEST_SIZE,
+ },
+ .class1_alg_type = 0,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC,
+ },
+ {
+ .name = "authenc(hmac(sha384),ecb(cipher_null))",
+ .driver_name = "authenc-hmac-sha384-ecb-cipher_null-caam",
+ .blocksize = NULL_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .template_aead = {
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .givencrypt = aead_null_givencrypt,
+ .geniv = "<built-in>",
+ .ivsize = NULL_IV_SIZE,
+ .maxauthsize = SHA384_DIGEST_SIZE,
+ },
+ .class1_alg_type = 0,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC,
+ },
+ {
+ .name = "authenc(hmac(sha512),ecb(cipher_null))",
+ .driver_name = "authenc-hmac-sha512-ecb-cipher_null-caam",
+ .blocksize = NULL_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .template_aead = {
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .givencrypt = aead_null_givencrypt,
+ .geniv = "<built-in>",
+ .ivsize = NULL_IV_SIZE,
+ .maxauthsize = SHA512_DIGEST_SIZE,
+ },
+ .class1_alg_type = 0,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC,
+ },
+ {
.name = "authenc(hmac(md5),cbc(aes))",
.driver_name = "authenc-hmac-md5-cbc-aes-caam",
.blocksize = AES_BLOCK_SIZE,
@@ -2099,6 +2380,11 @@ static void caam_cra_exit(struct crypto_tfm *tfm)
dma_unmap_single(ctx->jrdev, ctx->sh_desc_givenc_dma,
desc_bytes(ctx->sh_desc_givenc),
DMA_TO_DEVICE);
+ if (ctx->key_dma &&
+ !dma_mapping_error(ctx->jrdev, ctx->key_dma))
+ dma_unmap_single(ctx->jrdev, ctx->key_dma,
+ ctx->enckeylen + ctx->split_key_pad_len,
+ DMA_TO_DEVICE);
caam_jr_free(ctx->jrdev);
}
diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c
index 28486b19fc36..3529b54048c9 100644
--- a/drivers/crypto/caam/caamrng.c
+++ b/drivers/crypto/caam/caamrng.c
@@ -76,7 +76,7 @@ struct caam_rng_ctx {
struct buf_data bufs[2];
};
-static struct caam_rng_ctx rng_ctx;
+static struct caam_rng_ctx *rng_ctx;
static inline void rng_unmap_buf(struct device *jrdev, struct buf_data *bd)
{
@@ -137,7 +137,7 @@ static inline int submit_job(struct caam_rng_ctx *ctx, int to_current)
static int caam_read(struct hwrng *rng, void *data, size_t max, bool wait)
{
- struct caam_rng_ctx *ctx = &rng_ctx;
+ struct caam_rng_ctx *ctx = rng_ctx;
struct buf_data *bd = &ctx->bufs[ctx->current_buf];
int next_buf_idx, copied_idx;
int err;
@@ -237,12 +237,12 @@ static void caam_cleanup(struct hwrng *rng)
struct buf_data *bd;
for (i = 0; i < 2; i++) {
- bd = &rng_ctx.bufs[i];
+ bd = &rng_ctx->bufs[i];
if (atomic_read(&bd->empty) == BUF_PENDING)
wait_for_completion(&bd->filled);
}
- rng_unmap_ctx(&rng_ctx);
+ rng_unmap_ctx(rng_ctx);
}
static void caam_init_buf(struct caam_rng_ctx *ctx, int buf_id)
@@ -273,8 +273,9 @@ static struct hwrng caam_rng = {
static void __exit caam_rng_exit(void)
{
- caam_jr_free(rng_ctx.jrdev);
+ caam_jr_free(rng_ctx->jrdev);
hwrng_unregister(&caam_rng);
+ kfree(rng_ctx);
}
static int __init caam_rng_init(void)
@@ -286,8 +287,10 @@ static int __init caam_rng_init(void)
pr_err("Job Ring Device allocation for transform failed\n");
return PTR_ERR(dev);
}
-
- caam_init_rng(&rng_ctx, dev);
+ rng_ctx = kmalloc(sizeof(struct caam_rng_ctx), GFP_DMA);
+ if (!rng_ctx)
+ return -ENOMEM;
+ caam_init_rng(rng_ctx, dev);
dev_info(dev, "registering rng-caam\n");
return hwrng_register(&caam_rng);
diff --git a/drivers/crypto/caam/compat.h b/drivers/crypto/caam/compat.h
index 762aeff626ac..f227922cea38 100644
--- a/drivers/crypto/caam/compat.h
+++ b/drivers/crypto/caam/compat.h
@@ -26,6 +26,7 @@
#include <net/xfrm.h>
#include <crypto/algapi.h>
+#include <crypto/null.h>
#include <crypto/aes.h>
#include <crypto/des.h>
#include <crypto/sha.h>
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index 63fb1af2c431..1c38f86bf63a 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -14,7 +14,6 @@
#include "jr.h"
#include "desc_constr.h"
#include "error.h"
-#include "ctrl.h"
/*
* Descriptor to instantiate RNG State Handle 0 in normal mode and
@@ -352,32 +351,17 @@ static void kick_trng(struct platform_device *pdev, int ent_delay)
/**
* caam_get_era() - Return the ERA of the SEC on SoC, based
- * on the SEC_VID register.
- * Returns the ERA number (1..4) or -ENOTSUPP if the ERA is unknown.
- * @caam_id - the value of the SEC_VID register
+ * on "sec-era" propery in the DTS. This property is updated by u-boot.
**/
-int caam_get_era(u64 caam_id)
+int caam_get_era(void)
{
- struct sec_vid *sec_vid = (struct sec_vid *)&caam_id;
- static const struct {
- u16 ip_id;
- u8 maj_rev;
- u8 era;
- } caam_eras[] = {
- {0x0A10, 1, 1},
- {0x0A10, 2, 2},
- {0x0A12, 1, 3},
- {0x0A14, 1, 3},
- {0x0A14, 2, 4},
- {0x0A16, 1, 4},
- {0x0A11, 1, 4}
- };
- int i;
-
- for (i = 0; i < ARRAY_SIZE(caam_eras); i++)
- if (caam_eras[i].ip_id == sec_vid->ip_id &&
- caam_eras[i].maj_rev == sec_vid->maj_rev)
- return caam_eras[i].era;
+ struct device_node *caam_node;
+ for_each_compatible_node(caam_node, NULL, "fsl,sec-v4.0") {
+ const uint32_t *prop = (uint32_t *)of_get_property(caam_node,
+ "fsl,sec-era",
+ NULL);
+ return prop ? *prop : -ENOTSUPP;
+ }
return -ENOTSUPP;
}
@@ -443,13 +427,10 @@ static int caam_probe(struct platform_device *pdev)
* for all, then go probe each one.
*/
rspec = 0;
- for_each_compatible_node(np, NULL, "fsl,sec-v4.0-job-ring")
- rspec++;
- if (!rspec) {
- /* for backward compatible with device trees */
- for_each_compatible_node(np, NULL, "fsl,sec4.0-job-ring")
+ for_each_available_child_of_node(nprop, np)
+ if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") ||
+ of_device_is_compatible(np, "fsl,sec4.0-job-ring"))
rspec++;
- }
ctrlpriv->jrpdev = kzalloc(sizeof(struct platform_device *) * rspec,
GFP_KERNEL);
@@ -460,18 +441,9 @@ static int caam_probe(struct platform_device *pdev)
ring = 0;
ctrlpriv->total_jobrs = 0;
- for_each_compatible_node(np, NULL, "fsl,sec-v4.0-job-ring") {
- ctrlpriv->jrpdev[ring] =
- of_platform_device_create(np, NULL, dev);
- if (!ctrlpriv->jrpdev[ring]) {
- pr_warn("JR%d Platform device creation error\n", ring);
- continue;
- }
- ctrlpriv->total_jobrs++;
- ring++;
- }
- if (!ring) {
- for_each_compatible_node(np, NULL, "fsl,sec4.0-job-ring") {
+ for_each_available_child_of_node(nprop, np)
+ if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") ||
+ of_device_is_compatible(np, "fsl,sec4.0-job-ring")) {
ctrlpriv->jrpdev[ring] =
of_platform_device_create(np, NULL, dev);
if (!ctrlpriv->jrpdev[ring]) {
@@ -482,7 +454,6 @@ static int caam_probe(struct platform_device *pdev)
ctrlpriv->total_jobrs++;
ring++;
}
- }
/* Check to see if QI present. If so, enable */
ctrlpriv->qi_present = !!(rd_reg64(&topregs->ctrl.perfmon.comp_parms) &
@@ -564,7 +535,7 @@ static int caam_probe(struct platform_device *pdev)
/* Report "alive" for developer to see */
dev_info(dev, "device ID = 0x%016llx (Era %d)\n", caam_id,
- caam_get_era(caam_id));
+ caam_get_era());
dev_info(dev, "job rings = %d, qi = %d\n",
ctrlpriv->total_jobrs, ctrlpriv->qi_present);
diff --git a/drivers/crypto/caam/ctrl.h b/drivers/crypto/caam/ctrl.h
index 980d44eaaf40..cac5402a46eb 100644
--- a/drivers/crypto/caam/ctrl.h
+++ b/drivers/crypto/caam/ctrl.h
@@ -8,6 +8,6 @@
#define CTRL_H
/* Prototypes for backend-level services exposed to APIs */
-int caam_get_era(u64 caam_id);
+int caam_get_era(void);
#endif /* CTRL_H */
diff --git a/drivers/crypto/caam/desc_constr.h b/drivers/crypto/caam/desc_constr.h
index cd5f678847ce..7eec20bb3849 100644
--- a/drivers/crypto/caam/desc_constr.h
+++ b/drivers/crypto/caam/desc_constr.h
@@ -155,21 +155,29 @@ static inline void append_cmd_data(u32 *desc, void *data, int len,
append_data(desc, data, len);
}
-static inline u32 *append_jump(u32 *desc, u32 options)
-{
- u32 *cmd = desc_end(desc);
-
- PRINT_POS;
- append_cmd(desc, CMD_JUMP | options);
-
- return cmd;
+#define APPEND_CMD_RET(cmd, op) \
+static inline u32 *append_##cmd(u32 *desc, u32 options) \
+{ \
+ u32 *cmd = desc_end(desc); \
+ PRINT_POS; \
+ append_cmd(desc, CMD_##op | options); \
+ return cmd; \
}
+APPEND_CMD_RET(jump, JUMP)
+APPEND_CMD_RET(move, MOVE)
static inline void set_jump_tgt_here(u32 *desc, u32 *jump_cmd)
{
*jump_cmd = *jump_cmd | (desc_len(desc) - (jump_cmd - desc));
}
+static inline void set_move_tgt_here(u32 *desc, u32 *move_cmd)
+{
+ *move_cmd &= ~MOVE_OFFSET_MASK;
+ *move_cmd = *move_cmd | ((desc_len(desc) << (MOVE_OFFSET_SHIFT + 2)) &
+ MOVE_OFFSET_MASK);
+}
+
#define APPEND_CMD(cmd, op) \
static inline void append_##cmd(u32 *desc, u32 options) \
{ \
@@ -177,7 +185,6 @@ static inline void append_##cmd(u32 *desc, u32 options) \
append_cmd(desc, CMD_##op | options); \
}
APPEND_CMD(operation, OPERATION)
-APPEND_CMD(move, MOVE)
#define APPEND_CMD_LEN(cmd, op) \
static inline void append_##cmd(u32 *desc, unsigned int len, u32 options) \
@@ -328,7 +335,7 @@ append_cmd(desc, CMD_MATH | MATH_FUN_##op | MATH_DEST_##dest | \
do { \
APPEND_MATH(op, desc, dest, src_0, src_1, CAAM_CMD_SZ); \
append_cmd(desc, data); \
-} while (0);
+} while (0)
#define append_math_add_imm_u32(desc, dest, src0, src1, data) \
APPEND_MATH_IMM_u32(ADD, desc, dest, src0, src1, data)
diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h
index d50174f45b21..cbde8b95a6f8 100644
--- a/drivers/crypto/caam/regs.h
+++ b/drivers/crypto/caam/regs.h
@@ -74,10 +74,10 @@
#endif
#else
#ifdef __LITTLE_ENDIAN
-#define wr_reg32(reg, data) __raw_writel(reg, data)
+#define wr_reg32(reg, data) __raw_writel(data, reg)
#define rd_reg32(reg) __raw_readl(reg)
#ifdef CONFIG_64BIT
-#define wr_reg64(reg, data) __raw_writeq(reg, data)
+#define wr_reg64(reg, data) __raw_writeq(data, reg)
#define rd_reg64(reg) __raw_readq(reg)
#endif
#endif
diff --git a/drivers/crypto/ccp/ccp-crypto-main.c b/drivers/crypto/ccp/ccp-crypto-main.c
index 2636f044789d..20dc848481e7 100644
--- a/drivers/crypto/ccp/ccp-crypto-main.c
+++ b/drivers/crypto/ccp/ccp-crypto-main.c
@@ -11,6 +11,7 @@
*/
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/ccp.h>
@@ -24,28 +25,33 @@ MODULE_LICENSE("GPL");
MODULE_VERSION("1.0.0");
MODULE_DESCRIPTION("AMD Cryptographic Coprocessor crypto API support");
+static unsigned int aes_disable;
+module_param(aes_disable, uint, 0444);
+MODULE_PARM_DESC(aes_disable, "Disable use of AES - any non-zero value");
+
+static unsigned int sha_disable;
+module_param(sha_disable, uint, 0444);
+MODULE_PARM_DESC(sha_disable, "Disable use of SHA - any non-zero value");
+
/* List heads for the supported algorithms */
static LIST_HEAD(hash_algs);
static LIST_HEAD(cipher_algs);
-/* For any tfm, requests for that tfm on the same CPU must be returned
- * in the order received. With multiple queues available, the CCP can
- * process more than one cmd at a time. Therefore we must maintain
- * a cmd list to insure the proper ordering of requests on a given tfm/cpu
- * combination.
+/* For any tfm, requests for that tfm must be returned on the order
+ * received. With multiple queues available, the CCP can process more
+ * than one cmd at a time. Therefore we must maintain a cmd list to insure
+ * the proper ordering of requests on a given tfm.
*/
-struct ccp_crypto_cpu_queue {
+struct ccp_crypto_queue {
struct list_head cmds;
struct list_head *backlog;
unsigned int cmd_count;
};
-#define CCP_CRYPTO_MAX_QLEN 50
+#define CCP_CRYPTO_MAX_QLEN 100
-struct ccp_crypto_percpu_queue {
- struct ccp_crypto_cpu_queue __percpu *cpu_queue;
-};
-static struct ccp_crypto_percpu_queue req_queue;
+static struct ccp_crypto_queue req_queue;
+static spinlock_t req_queue_lock;
struct ccp_crypto_cmd {
struct list_head entry;
@@ -62,8 +68,6 @@ struct ccp_crypto_cmd {
/* Used for held command processing to determine state */
int ret;
-
- int cpu;
};
struct ccp_crypto_cpu {
@@ -82,25 +86,21 @@ static inline bool ccp_crypto_success(int err)
return true;
}
-/*
- * ccp_crypto_cmd_complete must be called while running on the appropriate
- * cpu and the caller must have done a get_cpu to disable preemption
- */
static struct ccp_crypto_cmd *ccp_crypto_cmd_complete(
struct ccp_crypto_cmd *crypto_cmd, struct ccp_crypto_cmd **backlog)
{
- struct ccp_crypto_cpu_queue *cpu_queue;
struct ccp_crypto_cmd *held = NULL, *tmp;
+ unsigned long flags;
*backlog = NULL;
- cpu_queue = this_cpu_ptr(req_queue.cpu_queue);
+ spin_lock_irqsave(&req_queue_lock, flags);
/* Held cmds will be after the current cmd in the queue so start
* searching for a cmd with a matching tfm for submission.
*/
tmp = crypto_cmd;
- list_for_each_entry_continue(tmp, &cpu_queue->cmds, entry) {
+ list_for_each_entry_continue(tmp, &req_queue.cmds, entry) {
if (crypto_cmd->tfm != tmp->tfm)
continue;
held = tmp;
@@ -111,47 +111,45 @@ static struct ccp_crypto_cmd *ccp_crypto_cmd_complete(
* Because cmds can be executed from any point in the cmd list
* special precautions have to be taken when handling the backlog.
*/
- if (cpu_queue->backlog != &cpu_queue->cmds) {
+ if (req_queue.backlog != &req_queue.cmds) {
/* Skip over this cmd if it is the next backlog cmd */
- if (cpu_queue->backlog == &crypto_cmd->entry)
- cpu_queue->backlog = crypto_cmd->entry.next;
+ if (req_queue.backlog == &crypto_cmd->entry)
+ req_queue.backlog = crypto_cmd->entry.next;
- *backlog = container_of(cpu_queue->backlog,
+ *backlog = container_of(req_queue.backlog,
struct ccp_crypto_cmd, entry);
- cpu_queue->backlog = cpu_queue->backlog->next;
+ req_queue.backlog = req_queue.backlog->next;
/* Skip over this cmd if it is now the next backlog cmd */
- if (cpu_queue->backlog == &crypto_cmd->entry)
- cpu_queue->backlog = crypto_cmd->entry.next;
+ if (req_queue.backlog == &crypto_cmd->entry)
+ req_queue.backlog = crypto_cmd->entry.next;
}
/* Remove the cmd entry from the list of cmds */
- cpu_queue->cmd_count--;
+ req_queue.cmd_count--;
list_del(&crypto_cmd->entry);
+ spin_unlock_irqrestore(&req_queue_lock, flags);
+
return held;
}
-static void ccp_crypto_complete_on_cpu(struct work_struct *work)
+static void ccp_crypto_complete(void *data, int err)
{
- struct ccp_crypto_cpu *cpu_work =
- container_of(work, struct ccp_crypto_cpu, work);
- struct ccp_crypto_cmd *crypto_cmd = cpu_work->crypto_cmd;
+ struct ccp_crypto_cmd *crypto_cmd = data;
struct ccp_crypto_cmd *held, *next, *backlog;
struct crypto_async_request *req = crypto_cmd->req;
struct ccp_ctx *ctx = crypto_tfm_ctx(req->tfm);
- int cpu, ret;
-
- cpu = get_cpu();
+ int ret;
- if (cpu_work->err == -EINPROGRESS) {
+ if (err == -EINPROGRESS) {
/* Only propogate the -EINPROGRESS if necessary */
if (crypto_cmd->ret == -EBUSY) {
crypto_cmd->ret = -EINPROGRESS;
req->complete(req, -EINPROGRESS);
}
- goto e_cpu;
+ return;
}
/* Operation has completed - update the queue before invoking
@@ -169,18 +167,25 @@ static void ccp_crypto_complete_on_cpu(struct work_struct *work)
req->complete(req, -EINPROGRESS);
/* Completion callbacks */
- ret = cpu_work->err;
+ ret = err;
if (ctx->complete)
ret = ctx->complete(req, ret);
req->complete(req, ret);
/* Submit the next cmd */
while (held) {
+ /* Since we have already queued the cmd, we must indicate that
+ * we can backlog so as not to "lose" this request.
+ */
+ held->cmd->flags |= CCP_CMD_MAY_BACKLOG;
ret = ccp_enqueue_cmd(held->cmd);
if (ccp_crypto_success(ret))
break;
/* Error occurred, report it and get the next entry */
+ ctx = crypto_tfm_ctx(held->req->tfm);
+ if (ctx->complete)
+ ret = ctx->complete(held->req, ret);
held->req->complete(held->req, ret);
next = ccp_crypto_cmd_complete(held, &backlog);
@@ -194,52 +199,29 @@ static void ccp_crypto_complete_on_cpu(struct work_struct *work)
}
kfree(crypto_cmd);
-
-e_cpu:
- put_cpu();
-
- complete(&cpu_work->completion);
-}
-
-static void ccp_crypto_complete(void *data, int err)
-{
- struct ccp_crypto_cmd *crypto_cmd = data;
- struct ccp_crypto_cpu cpu_work;
-
- INIT_WORK(&cpu_work.work, ccp_crypto_complete_on_cpu);
- init_completion(&cpu_work.completion);
- cpu_work.crypto_cmd = crypto_cmd;
- cpu_work.err = err;
-
- schedule_work_on(crypto_cmd->cpu, &cpu_work.work);
-
- /* Keep the completion call synchronous */
- wait_for_completion(&cpu_work.completion);
}
static int ccp_crypto_enqueue_cmd(struct ccp_crypto_cmd *crypto_cmd)
{
- struct ccp_crypto_cpu_queue *cpu_queue;
struct ccp_crypto_cmd *active = NULL, *tmp;
- int cpu, ret;
-
- cpu = get_cpu();
- crypto_cmd->cpu = cpu;
+ unsigned long flags;
+ bool free_cmd = true;
+ int ret;
- cpu_queue = this_cpu_ptr(req_queue.cpu_queue);
+ spin_lock_irqsave(&req_queue_lock, flags);
/* Check if the cmd can/should be queued */
- if (cpu_queue->cmd_count >= CCP_CRYPTO_MAX_QLEN) {
+ if (req_queue.cmd_count >= CCP_CRYPTO_MAX_QLEN) {
ret = -EBUSY;
if (!(crypto_cmd->cmd->flags & CCP_CMD_MAY_BACKLOG))
- goto e_cpu;
+ goto e_lock;
}
/* Look for an entry with the same tfm. If there is a cmd
- * with the same tfm in the list for this cpu then the current
- * cmd cannot be submitted to the CCP yet.
+ * with the same tfm in the list then the current cmd cannot
+ * be submitted to the CCP yet.
*/
- list_for_each_entry(tmp, &cpu_queue->cmds, entry) {
+ list_for_each_entry(tmp, &req_queue.cmds, entry) {
if (crypto_cmd->tfm != tmp->tfm)
continue;
active = tmp;
@@ -250,21 +232,29 @@ static int ccp_crypto_enqueue_cmd(struct ccp_crypto_cmd *crypto_cmd)
if (!active) {
ret = ccp_enqueue_cmd(crypto_cmd->cmd);
if (!ccp_crypto_success(ret))
- goto e_cpu;
+ goto e_lock; /* Error, don't queue it */
+ if ((ret == -EBUSY) &&
+ !(crypto_cmd->cmd->flags & CCP_CMD_MAY_BACKLOG))
+ goto e_lock; /* Not backlogging, don't queue it */
}
- if (cpu_queue->cmd_count >= CCP_CRYPTO_MAX_QLEN) {
+ if (req_queue.cmd_count >= CCP_CRYPTO_MAX_QLEN) {
ret = -EBUSY;
- if (cpu_queue->backlog == &cpu_queue->cmds)
- cpu_queue->backlog = &crypto_cmd->entry;
+ if (req_queue.backlog == &req_queue.cmds)
+ req_queue.backlog = &crypto_cmd->entry;
}
crypto_cmd->ret = ret;
- cpu_queue->cmd_count++;
- list_add_tail(&crypto_cmd->entry, &cpu_queue->cmds);
+ req_queue.cmd_count++;
+ list_add_tail(&crypto_cmd->entry, &req_queue.cmds);
+
+ free_cmd = false;
-e_cpu:
- put_cpu();
+e_lock:
+ spin_unlock_irqrestore(&req_queue_lock, flags);
+
+ if (free_cmd)
+ kfree(crypto_cmd);
return ret;
}
@@ -281,7 +271,6 @@ int ccp_crypto_enqueue_request(struct crypto_async_request *req,
{
struct ccp_crypto_cmd *crypto_cmd;
gfp_t gfp;
- int ret;
gfp = req->flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : GFP_ATOMIC;
@@ -306,11 +295,7 @@ int ccp_crypto_enqueue_request(struct crypto_async_request *req,
else
cmd->flags &= ~CCP_CMD_MAY_BACKLOG;
- ret = ccp_crypto_enqueue_cmd(crypto_cmd);
- if (!ccp_crypto_success(ret))
- kfree(crypto_cmd);
-
- return ret;
+ return ccp_crypto_enqueue_cmd(crypto_cmd);
}
struct scatterlist *ccp_crypto_sg_table_add(struct sg_table *table,
@@ -337,21 +322,25 @@ static int ccp_register_algs(void)
{
int ret;
- ret = ccp_register_aes_algs(&cipher_algs);
- if (ret)
- return ret;
+ if (!aes_disable) {
+ ret = ccp_register_aes_algs(&cipher_algs);
+ if (ret)
+ return ret;
- ret = ccp_register_aes_cmac_algs(&hash_algs);
- if (ret)
- return ret;
+ ret = ccp_register_aes_cmac_algs(&hash_algs);
+ if (ret)
+ return ret;
- ret = ccp_register_aes_xts_algs(&cipher_algs);
- if (ret)
- return ret;
+ ret = ccp_register_aes_xts_algs(&cipher_algs);
+ if (ret)
+ return ret;
+ }
- ret = ccp_register_sha_algs(&hash_algs);
- if (ret)
- return ret;
+ if (!sha_disable) {
+ ret = ccp_register_sha_algs(&hash_algs);
+ if (ret)
+ return ret;
+ }
return 0;
}
@@ -374,50 +363,18 @@ static void ccp_unregister_algs(void)
}
}
-static int ccp_init_queues(void)
-{
- struct ccp_crypto_cpu_queue *cpu_queue;
- int cpu;
-
- req_queue.cpu_queue = alloc_percpu(struct ccp_crypto_cpu_queue);
- if (!req_queue.cpu_queue)
- return -ENOMEM;
-
- for_each_possible_cpu(cpu) {
- cpu_queue = per_cpu_ptr(req_queue.cpu_queue, cpu);
- INIT_LIST_HEAD(&cpu_queue->cmds);
- cpu_queue->backlog = &cpu_queue->cmds;
- cpu_queue->cmd_count = 0;
- }
-
- return 0;
-}
-
-static void ccp_fini_queue(void)
-{
- struct ccp_crypto_cpu_queue *cpu_queue;
- int cpu;
-
- for_each_possible_cpu(cpu) {
- cpu_queue = per_cpu_ptr(req_queue.cpu_queue, cpu);
- BUG_ON(!list_empty(&cpu_queue->cmds));
- }
- free_percpu(req_queue.cpu_queue);
-}
-
static int ccp_crypto_init(void)
{
int ret;
- ret = ccp_init_queues();
- if (ret)
- return ret;
+ spin_lock_init(&req_queue_lock);
+ INIT_LIST_HEAD(&req_queue.cmds);
+ req_queue.backlog = &req_queue.cmds;
+ req_queue.cmd_count = 0;
ret = ccp_register_algs();
- if (ret) {
+ if (ret)
ccp_unregister_algs();
- ccp_fini_queue();
- }
return ret;
}
@@ -425,7 +382,6 @@ static int ccp_crypto_init(void)
static void ccp_crypto_exit(void)
{
ccp_unregister_algs();
- ccp_fini_queue();
}
module_init(ccp_crypto_init);
diff --git a/drivers/crypto/ccp/ccp-crypto-sha.c b/drivers/crypto/ccp/ccp-crypto-sha.c
index 3867290b3531..873f23425245 100644
--- a/drivers/crypto/ccp/ccp-crypto-sha.c
+++ b/drivers/crypto/ccp/ccp-crypto-sha.c
@@ -24,75 +24,10 @@
#include "ccp-crypto.h"
-struct ccp_sha_result {
- struct completion completion;
- int err;
-};
-
-static void ccp_sync_hash_complete(struct crypto_async_request *req, int err)
-{
- struct ccp_sha_result *result = req->data;
-
- if (err == -EINPROGRESS)
- return;
-
- result->err = err;
- complete(&result->completion);
-}
-
-static int ccp_sync_hash(struct crypto_ahash *tfm, u8 *buf,
- struct scatterlist *sg, unsigned int len)
-{
- struct ccp_sha_result result;
- struct ahash_request *req;
- int ret;
-
- init_completion(&result.completion);
-
- req = ahash_request_alloc(tfm, GFP_KERNEL);
- if (!req)
- return -ENOMEM;
-
- ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
- ccp_sync_hash_complete, &result);
- ahash_request_set_crypt(req, sg, buf, len);
-
- ret = crypto_ahash_digest(req);
- if ((ret == -EINPROGRESS) || (ret == -EBUSY)) {
- ret = wait_for_completion_interruptible(&result.completion);
- if (!ret)
- ret = result.err;
- }
-
- ahash_request_free(req);
-
- return ret;
-}
-
-static int ccp_sha_finish_hmac(struct crypto_async_request *async_req)
-{
- struct ahash_request *req = ahash_request_cast(async_req);
- struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
- struct ccp_ctx *ctx = crypto_ahash_ctx(tfm);
- struct ccp_sha_req_ctx *rctx = ahash_request_ctx(req);
- struct scatterlist sg[2];
- unsigned int block_size =
- crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
- unsigned int digest_size = crypto_ahash_digestsize(tfm);
-
- sg_init_table(sg, ARRAY_SIZE(sg));
- sg_set_buf(&sg[0], ctx->u.sha.opad, block_size);
- sg_set_buf(&sg[1], rctx->ctx, digest_size);
-
- return ccp_sync_hash(ctx->u.sha.hmac_tfm, req->result, sg,
- block_size + digest_size);
-}
-
static int ccp_sha_complete(struct crypto_async_request *async_req, int ret)
{
struct ahash_request *req = ahash_request_cast(async_req);
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
- struct ccp_ctx *ctx = crypto_ahash_ctx(tfm);
struct ccp_sha_req_ctx *rctx = ahash_request_ctx(req);
unsigned int digest_size = crypto_ahash_digestsize(tfm);
@@ -112,10 +47,6 @@ static int ccp_sha_complete(struct crypto_async_request *async_req, int ret)
if (req->result)
memcpy(req->result, rctx->ctx, digest_size);
- /* If we're doing an HMAC, we need to perform that on the final op */
- if (rctx->final && ctx->u.sha.key_len)
- ret = ccp_sha_finish_hmac(async_req);
-
e_free:
sg_free_table(&rctx->data_sg);
@@ -126,6 +57,7 @@ static int ccp_do_sha_update(struct ahash_request *req, unsigned int nbytes,
unsigned int final)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ccp_ctx *ctx = crypto_ahash_ctx(tfm);
struct ccp_sha_req_ctx *rctx = ahash_request_ctx(req);
struct scatterlist *sg;
unsigned int block_size =
@@ -196,6 +128,11 @@ static int ccp_do_sha_update(struct ahash_request *req, unsigned int nbytes,
rctx->cmd.u.sha.ctx_len = sizeof(rctx->ctx);
rctx->cmd.u.sha.src = sg;
rctx->cmd.u.sha.src_len = rctx->hash_cnt;
+ rctx->cmd.u.sha.opad = ctx->u.sha.key_len ?
+ &ctx->u.sha.opad_sg : NULL;
+ rctx->cmd.u.sha.opad_len = ctx->u.sha.key_len ?
+ ctx->u.sha.opad_count : 0;
+ rctx->cmd.u.sha.first = rctx->first;
rctx->cmd.u.sha.final = rctx->final;
rctx->cmd.u.sha.msg_bits = rctx->msg_bits;
@@ -218,7 +155,6 @@ static int ccp_sha_init(struct ahash_request *req)
memset(rctx, 0, sizeof(*rctx));
- memcpy(rctx->ctx, alg->init, sizeof(rctx->ctx));
rctx->type = alg->type;
rctx->first = 1;
@@ -261,10 +197,13 @@ static int ccp_sha_setkey(struct crypto_ahash *tfm, const u8 *key,
unsigned int key_len)
{
struct ccp_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm));
- struct scatterlist sg;
- unsigned int block_size =
- crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
- unsigned int digest_size = crypto_ahash_digestsize(tfm);
+ struct crypto_shash *shash = ctx->u.sha.hmac_tfm;
+ struct {
+ struct shash_desc sdesc;
+ char ctx[crypto_shash_descsize(shash)];
+ } desc;
+ unsigned int block_size = crypto_shash_blocksize(shash);
+ unsigned int digest_size = crypto_shash_digestsize(shash);
int i, ret;
/* Set to zero until complete */
@@ -277,8 +216,12 @@ static int ccp_sha_setkey(struct crypto_ahash *tfm, const u8 *key,
if (key_len > block_size) {
/* Must hash the input key */
- sg_init_one(&sg, key, key_len);
- ret = ccp_sync_hash(tfm, ctx->u.sha.key, &sg, key_len);
+ desc.sdesc.tfm = shash;
+ desc.sdesc.flags = crypto_ahash_get_flags(tfm) &
+ CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ ret = crypto_shash_digest(&desc.sdesc, key, key_len,
+ ctx->u.sha.key);
if (ret) {
crypto_ahash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
return -EINVAL;
@@ -293,6 +236,9 @@ static int ccp_sha_setkey(struct crypto_ahash *tfm, const u8 *key,
ctx->u.sha.opad[i] = ctx->u.sha.key[i] ^ 0x5c;
}
+ sg_init_one(&ctx->u.sha.opad_sg, ctx->u.sha.opad, block_size);
+ ctx->u.sha.opad_count = block_size;
+
ctx->u.sha.key_len = key_len;
return 0;
@@ -319,10 +265,9 @@ static int ccp_hmac_sha_cra_init(struct crypto_tfm *tfm)
{
struct ccp_ctx *ctx = crypto_tfm_ctx(tfm);
struct ccp_crypto_ahash_alg *alg = ccp_crypto_ahash_alg(tfm);
- struct crypto_ahash *hmac_tfm;
+ struct crypto_shash *hmac_tfm;
- hmac_tfm = crypto_alloc_ahash(alg->child_alg,
- CRYPTO_ALG_TYPE_AHASH, 0);
+ hmac_tfm = crypto_alloc_shash(alg->child_alg, 0, 0);
if (IS_ERR(hmac_tfm)) {
pr_warn("could not load driver %s need for HMAC support\n",
alg->child_alg);
@@ -339,35 +284,14 @@ static void ccp_hmac_sha_cra_exit(struct crypto_tfm *tfm)
struct ccp_ctx *ctx = crypto_tfm_ctx(tfm);
if (ctx->u.sha.hmac_tfm)
- crypto_free_ahash(ctx->u.sha.hmac_tfm);
+ crypto_free_shash(ctx->u.sha.hmac_tfm);
ccp_sha_cra_exit(tfm);
}
-static const __be32 sha1_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = {
- cpu_to_be32(SHA1_H0), cpu_to_be32(SHA1_H1),
- cpu_to_be32(SHA1_H2), cpu_to_be32(SHA1_H3),
- cpu_to_be32(SHA1_H4), 0, 0, 0,
-};
-
-static const __be32 sha224_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = {
- cpu_to_be32(SHA224_H0), cpu_to_be32(SHA224_H1),
- cpu_to_be32(SHA224_H2), cpu_to_be32(SHA224_H3),
- cpu_to_be32(SHA224_H4), cpu_to_be32(SHA224_H5),
- cpu_to_be32(SHA224_H6), cpu_to_be32(SHA224_H7),
-};
-
-static const __be32 sha256_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = {
- cpu_to_be32(SHA256_H0), cpu_to_be32(SHA256_H1),
- cpu_to_be32(SHA256_H2), cpu_to_be32(SHA256_H3),
- cpu_to_be32(SHA256_H4), cpu_to_be32(SHA256_H5),
- cpu_to_be32(SHA256_H6), cpu_to_be32(SHA256_H7),
-};
-
struct ccp_sha_def {
const char *name;
const char *drv_name;
- const __be32 *init;
enum ccp_sha_type type;
u32 digest_size;
u32 block_size;
@@ -377,7 +301,6 @@ static struct ccp_sha_def sha_algs[] = {
{
.name = "sha1",
.drv_name = "sha1-ccp",
- .init = sha1_init,
.type = CCP_SHA_TYPE_1,
.digest_size = SHA1_DIGEST_SIZE,
.block_size = SHA1_BLOCK_SIZE,
@@ -385,7 +308,6 @@ static struct ccp_sha_def sha_algs[] = {
{
.name = "sha224",
.drv_name = "sha224-ccp",
- .init = sha224_init,
.type = CCP_SHA_TYPE_224,
.digest_size = SHA224_DIGEST_SIZE,
.block_size = SHA224_BLOCK_SIZE,
@@ -393,7 +315,6 @@ static struct ccp_sha_def sha_algs[] = {
{
.name = "sha256",
.drv_name = "sha256-ccp",
- .init = sha256_init,
.type = CCP_SHA_TYPE_256,
.digest_size = SHA256_DIGEST_SIZE,
.block_size = SHA256_BLOCK_SIZE,
@@ -460,7 +381,6 @@ static int ccp_register_sha_alg(struct list_head *head,
INIT_LIST_HEAD(&ccp_alg->entry);
- ccp_alg->init = def->init;
ccp_alg->type = def->type;
alg = &ccp_alg->alg;
diff --git a/drivers/crypto/ccp/ccp-crypto.h b/drivers/crypto/ccp/ccp-crypto.h
index b222231b6169..9aa4ae184f7f 100644
--- a/drivers/crypto/ccp/ccp-crypto.h
+++ b/drivers/crypto/ccp/ccp-crypto.h
@@ -137,11 +137,14 @@ struct ccp_aes_cmac_req_ctx {
#define MAX_SHA_BLOCK_SIZE SHA256_BLOCK_SIZE
struct ccp_sha_ctx {
+ struct scatterlist opad_sg;
+ unsigned int opad_count;
+
unsigned int key_len;
u8 key[MAX_SHA_BLOCK_SIZE];
u8 ipad[MAX_SHA_BLOCK_SIZE];
u8 opad[MAX_SHA_BLOCK_SIZE];
- struct crypto_ahash *hmac_tfm;
+ struct crypto_shash *hmac_tfm;
};
struct ccp_sha_req_ctx {
@@ -167,9 +170,6 @@ struct ccp_sha_req_ctx {
unsigned int buf_count;
u8 buf[MAX_SHA_BLOCK_SIZE];
- /* HMAC support field */
- struct scatterlist pad_sg;
-
/* CCP driver command */
struct ccp_cmd cmd;
};
diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c
index c3bc21264600..2c7816149b01 100644
--- a/drivers/crypto/ccp/ccp-dev.c
+++ b/drivers/crypto/ccp/ccp-dev.c
@@ -30,6 +30,11 @@ MODULE_LICENSE("GPL");
MODULE_VERSION("1.0.0");
MODULE_DESCRIPTION("AMD Cryptographic Coprocessor driver");
+struct ccp_tasklet_data {
+ struct completion completion;
+ struct ccp_cmd *cmd;
+};
+
static struct ccp_device *ccp_dev;
static inline struct ccp_device *ccp_get_device(void)
@@ -192,17 +197,23 @@ static struct ccp_cmd *ccp_dequeue_cmd(struct ccp_cmd_queue *cmd_q)
return cmd;
}
-static void ccp_do_cmd_complete(struct work_struct *work)
+static void ccp_do_cmd_complete(unsigned long data)
{
- struct ccp_cmd *cmd = container_of(work, struct ccp_cmd, work);
+ struct ccp_tasklet_data *tdata = (struct ccp_tasklet_data *)data;
+ struct ccp_cmd *cmd = tdata->cmd;
cmd->callback(cmd->data, cmd->ret);
+ complete(&tdata->completion);
}
static int ccp_cmd_queue_thread(void *data)
{
struct ccp_cmd_queue *cmd_q = (struct ccp_cmd_queue *)data;
struct ccp_cmd *cmd;
+ struct ccp_tasklet_data tdata;
+ struct tasklet_struct tasklet;
+
+ tasklet_init(&tasklet, ccp_do_cmd_complete, (unsigned long)&tdata);
set_current_state(TASK_INTERRUPTIBLE);
while (!kthread_should_stop()) {
@@ -220,8 +231,10 @@ static int ccp_cmd_queue_thread(void *data)
cmd->ret = ccp_run_cmd(cmd_q, cmd);
/* Schedule the completion callback */
- INIT_WORK(&cmd->work, ccp_do_cmd_complete);
- schedule_work(&cmd->work);
+ tdata.cmd = cmd;
+ init_completion(&tdata.completion);
+ tasklet_schedule(&tasklet);
+ wait_for_completion(&tdata.completion);
}
__set_current_state(TASK_RUNNING);
diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c
index 71ed3ade7e12..9ae006d69df4 100644
--- a/drivers/crypto/ccp/ccp-ops.c
+++ b/drivers/crypto/ccp/ccp-ops.c
@@ -23,6 +23,7 @@
#include <linux/ccp.h>
#include <linux/scatterlist.h>
#include <crypto/scatterwalk.h>
+#include <crypto/sha.h>
#include "ccp-dev.h"
@@ -132,6 +133,27 @@ struct ccp_op {
} u;
};
+/* SHA initial context values */
+static const __be32 ccp_sha1_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = {
+ cpu_to_be32(SHA1_H0), cpu_to_be32(SHA1_H1),
+ cpu_to_be32(SHA1_H2), cpu_to_be32(SHA1_H3),
+ cpu_to_be32(SHA1_H4), 0, 0, 0,
+};
+
+static const __be32 ccp_sha224_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = {
+ cpu_to_be32(SHA224_H0), cpu_to_be32(SHA224_H1),
+ cpu_to_be32(SHA224_H2), cpu_to_be32(SHA224_H3),
+ cpu_to_be32(SHA224_H4), cpu_to_be32(SHA224_H5),
+ cpu_to_be32(SHA224_H6), cpu_to_be32(SHA224_H7),
+};
+
+static const __be32 ccp_sha256_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = {
+ cpu_to_be32(SHA256_H0), cpu_to_be32(SHA256_H1),
+ cpu_to_be32(SHA256_H2), cpu_to_be32(SHA256_H3),
+ cpu_to_be32(SHA256_H4), cpu_to_be32(SHA256_H5),
+ cpu_to_be32(SHA256_H6), cpu_to_be32(SHA256_H7),
+};
+
/* The CCP cannot perform zero-length sha operations so the caller
* is required to buffer data for the final operation. However, a
* sha operation for a message with a total length of zero is valid
@@ -1411,7 +1433,27 @@ static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
if (ret)
return ret;
- ccp_set_dm_area(&ctx, 0, sha->ctx, 0, sha->ctx_len);
+ if (sha->first) {
+ const __be32 *init;
+
+ switch (sha->type) {
+ case CCP_SHA_TYPE_1:
+ init = ccp_sha1_init;
+ break;
+ case CCP_SHA_TYPE_224:
+ init = ccp_sha224_init;
+ break;
+ case CCP_SHA_TYPE_256:
+ init = ccp_sha256_init;
+ break;
+ default:
+ ret = -EINVAL;
+ goto e_ctx;
+ }
+ memcpy(ctx.address, init, CCP_SHA_CTXSIZE);
+ } else
+ ccp_set_dm_area(&ctx, 0, sha->ctx, 0, sha->ctx_len);
+
ret = ccp_copy_to_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx,
CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) {
@@ -1451,6 +1493,66 @@ static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
ccp_get_dm_area(&ctx, 0, sha->ctx, 0, sha->ctx_len);
+ if (sha->final && sha->opad) {
+ /* HMAC operation, recursively perform final SHA */
+ struct ccp_cmd hmac_cmd;
+ struct scatterlist sg;
+ u64 block_size, digest_size;
+ u8 *hmac_buf;
+
+ switch (sha->type) {
+ case CCP_SHA_TYPE_1:
+ block_size = SHA1_BLOCK_SIZE;
+ digest_size = SHA1_DIGEST_SIZE;
+ break;
+ case CCP_SHA_TYPE_224:
+ block_size = SHA224_BLOCK_SIZE;
+ digest_size = SHA224_DIGEST_SIZE;
+ break;
+ case CCP_SHA_TYPE_256:
+ block_size = SHA256_BLOCK_SIZE;
+ digest_size = SHA256_DIGEST_SIZE;
+ break;
+ default:
+ ret = -EINVAL;
+ goto e_data;
+ }
+
+ if (sha->opad_len != block_size) {
+ ret = -EINVAL;
+ goto e_data;
+ }
+
+ hmac_buf = kmalloc(block_size + digest_size, GFP_KERNEL);
+ if (!hmac_buf) {
+ ret = -ENOMEM;
+ goto e_data;
+ }
+ sg_init_one(&sg, hmac_buf, block_size + digest_size);
+
+ scatterwalk_map_and_copy(hmac_buf, sha->opad, 0, block_size, 0);
+ memcpy(hmac_buf + block_size, ctx.address, digest_size);
+
+ memset(&hmac_cmd, 0, sizeof(hmac_cmd));
+ hmac_cmd.engine = CCP_ENGINE_SHA;
+ hmac_cmd.u.sha.type = sha->type;
+ hmac_cmd.u.sha.ctx = sha->ctx;
+ hmac_cmd.u.sha.ctx_len = sha->ctx_len;
+ hmac_cmd.u.sha.src = &sg;
+ hmac_cmd.u.sha.src_len = block_size + digest_size;
+ hmac_cmd.u.sha.opad = NULL;
+ hmac_cmd.u.sha.opad_len = 0;
+ hmac_cmd.u.sha.first = 1;
+ hmac_cmd.u.sha.final = 1;
+ hmac_cmd.u.sha.msg_bits = (block_size + digest_size) << 3;
+
+ ret = ccp_run_sha_cmd(cmd_q, &hmac_cmd);
+ if (ret)
+ cmd->engine_error = hmac_cmd.engine_error;
+
+ kfree(hmac_buf);
+ }
+
e_data:
ccp_free_data(&src, cmd_q);
@@ -1666,8 +1768,8 @@ static int ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q,
op.dst.type = CCP_MEMTYPE_SYSTEM;
op.dst.u.dma.address = sg_dma_address(dst.sg_wa.sg);
- op.src.u.dma.offset = dst.sg_wa.sg_used;
- op.src.u.dma.length = op.src.u.dma.length;
+ op.dst.u.dma.offset = dst.sg_wa.sg_used;
+ op.dst.u.dma.length = op.src.u.dma.length;
ret = ccp_perform_passthru(&op);
if (ret) {
diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c
index a6db7fa6f891..7bbe0ab21eca 100644
--- a/drivers/crypto/mxs-dcp.c
+++ b/drivers/crypto/mxs-dcp.c
@@ -29,6 +29,8 @@
#define DCP_MAX_CHANS 4
#define DCP_BUF_SZ PAGE_SIZE
+#define DCP_ALIGNMENT 64
+
/* DCP DMA descriptor. */
struct dcp_dma_desc {
uint32_t next_cmd_addr;
@@ -48,7 +50,6 @@ struct dcp_coherent_block {
uint8_t sha_in_buf[DCP_BUF_SZ];
uint8_t aes_key[2 * AES_KEYSIZE_128];
- uint8_t sha_digest[SHA256_DIGEST_SIZE];
struct dcp_dma_desc desc[DCP_MAX_CHANS];
};
@@ -83,13 +84,16 @@ struct dcp_async_ctx {
unsigned int hot:1;
/* Crypto-specific context */
- unsigned int enc:1;
- unsigned int ecb:1;
struct crypto_ablkcipher *fallback;
unsigned int key_len;
uint8_t key[AES_KEYSIZE_128];
};
+struct dcp_aes_req_ctx {
+ unsigned int enc:1;
+ unsigned int ecb:1;
+};
+
struct dcp_sha_req_ctx {
unsigned int init:1;
unsigned int fini:1;
@@ -190,10 +194,12 @@ static int mxs_dcp_start_dma(struct dcp_async_ctx *actx)
/*
* Encryption (AES128)
*/
-static int mxs_dcp_run_aes(struct dcp_async_ctx *actx, int init)
+static int mxs_dcp_run_aes(struct dcp_async_ctx *actx,
+ struct ablkcipher_request *req, int init)
{
struct dcp *sdcp = global_sdcp;
struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan];
+ struct dcp_aes_req_ctx *rctx = ablkcipher_request_ctx(req);
int ret;
dma_addr_t key_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_key,
@@ -212,14 +218,14 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx, int init)
/* Payload contains the key. */
desc->control0 |= MXS_DCP_CONTROL0_PAYLOAD_KEY;
- if (actx->enc)
+ if (rctx->enc)
desc->control0 |= MXS_DCP_CONTROL0_CIPHER_ENCRYPT;
if (init)
desc->control0 |= MXS_DCP_CONTROL0_CIPHER_INIT;
desc->control1 = MXS_DCP_CONTROL1_CIPHER_SELECT_AES128;
- if (actx->ecb)
+ if (rctx->ecb)
desc->control1 |= MXS_DCP_CONTROL1_CIPHER_MODE_ECB;
else
desc->control1 |= MXS_DCP_CONTROL1_CIPHER_MODE_CBC;
@@ -247,6 +253,7 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq)
struct ablkcipher_request *req = ablkcipher_request_cast(arq);
struct dcp_async_ctx *actx = crypto_tfm_ctx(arq->tfm);
+ struct dcp_aes_req_ctx *rctx = ablkcipher_request_ctx(req);
struct scatterlist *dst = req->dst;
struct scatterlist *src = req->src;
@@ -271,7 +278,7 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq)
/* Copy the key from the temporary location. */
memcpy(key, actx->key, actx->key_len);
- if (!actx->ecb) {
+ if (!rctx->ecb) {
/* Copy the CBC IV just past the key. */
memcpy(key + AES_KEYSIZE_128, req->info, AES_KEYSIZE_128);
/* CBC needs the INIT set. */
@@ -300,7 +307,7 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq)
* submit the buffer.
*/
if (actx->fill == out_off || sg_is_last(src)) {
- ret = mxs_dcp_run_aes(actx, init);
+ ret = mxs_dcp_run_aes(actx, req, init);
if (ret)
return ret;
init = 0;
@@ -391,13 +398,14 @@ static int mxs_dcp_aes_enqueue(struct ablkcipher_request *req, int enc, int ecb)
struct dcp *sdcp = global_sdcp;
struct crypto_async_request *arq = &req->base;
struct dcp_async_ctx *actx = crypto_tfm_ctx(arq->tfm);
+ struct dcp_aes_req_ctx *rctx = ablkcipher_request_ctx(req);
int ret;
if (unlikely(actx->key_len != AES_KEYSIZE_128))
return mxs_dcp_block_fallback(req, enc);
- actx->enc = enc;
- actx->ecb = ecb;
+ rctx->enc = enc;
+ rctx->ecb = ecb;
actx->chan = DCP_CHAN_CRYPTO;
mutex_lock(&sdcp->mutex[actx->chan]);
@@ -484,7 +492,7 @@ static int mxs_dcp_aes_fallback_init(struct crypto_tfm *tfm)
return PTR_ERR(blk);
actx->fallback = blk;
- tfm->crt_ablkcipher.reqsize = sizeof(struct dcp_async_ctx);
+ tfm->crt_ablkcipher.reqsize = sizeof(struct dcp_aes_req_ctx);
return 0;
}
@@ -507,13 +515,11 @@ static int mxs_dcp_run_sha(struct ahash_request *req)
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm);
struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req);
+ struct hash_alg_common *halg = crypto_hash_alg_common(tfm);
struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan];
- dma_addr_t digest_phys = dma_map_single(sdcp->dev,
- sdcp->coh->sha_digest,
- SHA256_DIGEST_SIZE,
- DMA_FROM_DEVICE);
+ dma_addr_t digest_phys = 0;
dma_addr_t buf_phys = dma_map_single(sdcp->dev, sdcp->coh->sha_in_buf,
DCP_BUF_SZ, DMA_TO_DEVICE);
@@ -534,14 +540,18 @@ static int mxs_dcp_run_sha(struct ahash_request *req)
/* Set HASH_TERM bit for last transfer block. */
if (rctx->fini) {
+ digest_phys = dma_map_single(sdcp->dev, req->result,
+ halg->digestsize, DMA_FROM_DEVICE);
desc->control0 |= MXS_DCP_CONTROL0_HASH_TERM;
desc->payload = digest_phys;
}
ret = mxs_dcp_start_dma(actx);
- dma_unmap_single(sdcp->dev, digest_phys, SHA256_DIGEST_SIZE,
- DMA_FROM_DEVICE);
+ if (rctx->fini)
+ dma_unmap_single(sdcp->dev, digest_phys, halg->digestsize,
+ DMA_FROM_DEVICE);
+
dma_unmap_single(sdcp->dev, buf_phys, DCP_BUF_SZ, DMA_TO_DEVICE);
return ret;
@@ -558,7 +568,6 @@ static int dcp_sha_req_to_buf(struct crypto_async_request *arq)
struct hash_alg_common *halg = crypto_hash_alg_common(tfm);
const int nents = sg_nents(req->src);
- uint8_t *digest = sdcp->coh->sha_digest;
uint8_t *in_buf = sdcp->coh->sha_in_buf;
uint8_t *src_buf;
@@ -605,14 +614,20 @@ static int dcp_sha_req_to_buf(struct crypto_async_request *arq)
rctx->fini = 1;
/* Submit whatever is left. */
+ if (!req->result)
+ return -EINVAL;
+
ret = mxs_dcp_run_sha(req);
- if (ret || !req->result)
+ if (ret)
return ret;
+
actx->fill = 0;
/* For some reason, the result is flipped. */
- for (i = 0; i < halg->digestsize; i++)
- req->result[i] = digest[halg->digestsize - i - 1];
+ for (i = 0; i < halg->digestsize / 2; i++) {
+ swap(req->result[i],
+ req->result[halg->digestsize - i - 1]);
+ }
}
return 0;
@@ -901,9 +916,14 @@ static int mxs_dcp_probe(struct platform_device *pdev)
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dcp_vmi_irq = platform_get_irq(pdev, 0);
+ if (dcp_vmi_irq < 0) {
+ ret = dcp_vmi_irq;
+ goto err_mutex;
+ }
+
dcp_irq = platform_get_irq(pdev, 1);
- if (dcp_vmi_irq < 0 || dcp_irq < 0) {
- ret = -EINVAL;
+ if (dcp_irq < 0) {
+ ret = dcp_irq;
goto err_mutex;
}
@@ -935,15 +955,20 @@ static int mxs_dcp_probe(struct platform_device *pdev)
}
/* Allocate coherent helper block. */
- sdcp->coh = kzalloc(sizeof(struct dcp_coherent_block), GFP_KERNEL);
+ sdcp->coh = devm_kzalloc(dev, sizeof(*sdcp->coh) + DCP_ALIGNMENT,
+ GFP_KERNEL);
if (!sdcp->coh) {
- dev_err(dev, "Error allocating coherent block\n");
ret = -ENOMEM;
goto err_mutex;
}
+ /* Re-align the structure so it fits the DCP constraints. */
+ sdcp->coh = PTR_ALIGN(sdcp->coh, DCP_ALIGNMENT);
+
/* Restart the DCP block. */
- stmp_reset_block(sdcp->base);
+ ret = stmp_reset_block(sdcp->base);
+ if (ret)
+ goto err_mutex;
/* Initialize control register. */
writel(MXS_DCP_CTRL_GATHER_RESIDUAL_WRITES |
@@ -982,7 +1007,7 @@ static int mxs_dcp_probe(struct platform_device *pdev)
if (IS_ERR(sdcp->thread[DCP_CHAN_HASH_SHA])) {
dev_err(dev, "Error starting SHA thread!\n");
ret = PTR_ERR(sdcp->thread[DCP_CHAN_HASH_SHA]);
- goto err_free_coherent;
+ goto err_mutex;
}
sdcp->thread[DCP_CHAN_CRYPTO] = kthread_run(dcp_chan_thread_aes,
@@ -1040,8 +1065,6 @@ err_destroy_aes_thread:
err_destroy_sha_thread:
kthread_stop(sdcp->thread[DCP_CHAN_HASH_SHA]);
-err_free_coherent:
- kfree(sdcp->coh);
err_mutex:
mutex_unlock(&global_mutex);
return ret;
@@ -1051,8 +1074,6 @@ static int mxs_dcp_remove(struct platform_device *pdev)
{
struct dcp *sdcp = platform_get_drvdata(pdev);
- kfree(sdcp->coh);
-
if (sdcp->caps & MXS_DCP_CAPABILITY1_SHA256)
crypto_unregister_ahash(&dcp_sha256_alg);
diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c
index 6c4c000671c5..1e5481d88a26 100644
--- a/drivers/crypto/nx/nx-842.c
+++ b/drivers/crypto/nx/nx-842.c
@@ -158,6 +158,15 @@ static inline unsigned long nx842_get_scatterlist_size(
return sl->entry_nr * sizeof(struct nx842_slentry);
}
+static inline unsigned long nx842_get_pa(void *addr)
+{
+ if (is_vmalloc_addr(addr))
+ return page_to_phys(vmalloc_to_page(addr))
+ + offset_in_page(addr);
+ else
+ return __pa(addr);
+}
+
static int nx842_build_scatterlist(unsigned long buf, int len,
struct nx842_scatterlist *sl)
{
@@ -168,7 +177,7 @@ static int nx842_build_scatterlist(unsigned long buf, int len,
entry = sl->entries;
while (len) {
- entry->ptr = __pa(buf);
+ entry->ptr = nx842_get_pa((void *)buf);
nextpage = ALIGN(buf + 1, NX842_HW_PAGE_SIZE);
if (nextpage < buf + len) {
/* we aren't at the end yet */
@@ -370,8 +379,8 @@ int nx842_compress(const unsigned char *in, unsigned int inlen,
op.flags = NX842_OP_COMPRESS;
csbcpb = &workmem->csbcpb;
memset(csbcpb, 0, sizeof(*csbcpb));
- op.csbcpb = __pa(csbcpb);
- op.out = __pa(slout.entries);
+ op.csbcpb = nx842_get_pa(csbcpb);
+ op.out = nx842_get_pa(slout.entries);
for (i = 0; i < hdr->blocks_nr; i++) {
/*
@@ -401,13 +410,13 @@ int nx842_compress(const unsigned char *in, unsigned int inlen,
*/
if (likely(max_sync_size == NX842_HW_PAGE_SIZE)) {
/* Create direct DDE */
- op.in = __pa(inbuf);
+ op.in = nx842_get_pa((void *)inbuf);
op.inlen = max_sync_size;
} else {
/* Create indirect DDE (scatterlist) */
nx842_build_scatterlist(inbuf, max_sync_size, &slin);
- op.in = __pa(slin.entries);
+ op.in = nx842_get_pa(slin.entries);
op.inlen = -nx842_get_scatterlist_size(&slin);
}
@@ -565,7 +574,7 @@ int nx842_decompress(const unsigned char *in, unsigned int inlen,
op.flags = NX842_OP_DECOMPRESS;
csbcpb = &workmem->csbcpb;
memset(csbcpb, 0, sizeof(*csbcpb));
- op.csbcpb = __pa(csbcpb);
+ op.csbcpb = nx842_get_pa(csbcpb);
/*
* max_sync_size may have changed since compression,
@@ -597,12 +606,12 @@ int nx842_decompress(const unsigned char *in, unsigned int inlen,
if (likely((inbuf & NX842_HW_PAGE_MASK) ==
((inbuf + hdr->sizes[i] - 1) & NX842_HW_PAGE_MASK))) {
/* Create direct DDE */
- op.in = __pa(inbuf);
+ op.in = nx842_get_pa((void *)inbuf);
op.inlen = hdr->sizes[i];
} else {
/* Create indirect DDE (scatterlist) */
nx842_build_scatterlist(inbuf, hdr->sizes[i] , &slin);
- op.in = __pa(slin.entries);
+ op.in = nx842_get_pa(slin.entries);
op.inlen = -nx842_get_scatterlist_size(&slin);
}
@@ -613,12 +622,12 @@ int nx842_decompress(const unsigned char *in, unsigned int inlen,
*/
if (likely(max_sync_size == NX842_HW_PAGE_SIZE)) {
/* Create direct DDE */
- op.out = __pa(outbuf);
+ op.out = nx842_get_pa((void *)outbuf);
op.outlen = max_sync_size;
} else {
/* Create indirect DDE (scatterlist) */
nx842_build_scatterlist(outbuf, max_sync_size, &slout);
- op.out = __pa(slout.entries);
+ op.out = nx842_get_pa(slout.entries);
op.outlen = -nx842_get_scatterlist_size(&slout);
}
diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c
index dde41f1df608..cb98fa54573d 100644
--- a/drivers/crypto/omap-aes.c
+++ b/drivers/crypto/omap-aes.c
@@ -1307,9 +1307,7 @@ static int omap_aes_resume(struct device *dev)
}
#endif
-static const struct dev_pm_ops omap_aes_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(omap_aes_suspend, omap_aes_resume)
-};
+static SIMPLE_DEV_PM_OPS(omap_aes_pm_ops, omap_aes_suspend, omap_aes_resume);
static struct platform_driver omap_aes_driver = {
.probe = omap_aes_probe,
diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c
new file mode 100644
index 000000000000..ec5f13162b73
--- /dev/null
+++ b/drivers/crypto/omap-des.c
@@ -0,0 +1,1216 @@
+/*
+ * Support for OMAP DES and Triple DES HW acceleration.
+ *
+ * Copyright (c) 2013 Texas Instruments Incorporated
+ * Author: Joel Fernandes <joelf@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 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#ifdef DEBUG
+#define prn(num) printk(#num "=%d\n", num)
+#define prx(num) printk(#num "=%x\n", num)
+#else
+#define prn(num) do { } while (0)
+#define prx(num) do { } while (0)
+#endif
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/omap-dma.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+#include <linux/crypto.h>
+#include <linux/interrupt.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/des.h>
+
+#define DST_MAXBURST 2
+
+#define DES_BLOCK_WORDS (DES_BLOCK_SIZE >> 2)
+
+#define _calc_walked(inout) (dd->inout##_walk.offset - dd->inout##_sg->offset)
+
+#define DES_REG_KEY(dd, x) ((dd)->pdata->key_ofs - \
+ ((x ^ 0x01) * 0x04))
+
+#define DES_REG_IV(dd, x) ((dd)->pdata->iv_ofs + ((x) * 0x04))
+
+#define DES_REG_CTRL(dd) ((dd)->pdata->ctrl_ofs)
+#define DES_REG_CTRL_CBC BIT(4)
+#define DES_REG_CTRL_TDES BIT(3)
+#define DES_REG_CTRL_DIRECTION BIT(2)
+#define DES_REG_CTRL_INPUT_READY BIT(1)
+#define DES_REG_CTRL_OUTPUT_READY BIT(0)
+
+#define DES_REG_DATA_N(dd, x) ((dd)->pdata->data_ofs + ((x) * 0x04))
+
+#define DES_REG_REV(dd) ((dd)->pdata->rev_ofs)
+
+#define DES_REG_MASK(dd) ((dd)->pdata->mask_ofs)
+
+#define DES_REG_LENGTH_N(x) (0x24 + ((x) * 0x04))
+
+#define DES_REG_IRQ_STATUS(dd) ((dd)->pdata->irq_status_ofs)
+#define DES_REG_IRQ_ENABLE(dd) ((dd)->pdata->irq_enable_ofs)
+#define DES_REG_IRQ_DATA_IN BIT(1)
+#define DES_REG_IRQ_DATA_OUT BIT(2)
+
+#define FLAGS_MODE_MASK 0x000f
+#define FLAGS_ENCRYPT BIT(0)
+#define FLAGS_CBC BIT(1)
+#define FLAGS_INIT BIT(4)
+#define FLAGS_BUSY BIT(6)
+
+struct omap_des_ctx {
+ struct omap_des_dev *dd;
+
+ int keylen;
+ u32 key[(3 * DES_KEY_SIZE) / sizeof(u32)];
+ unsigned long flags;
+};
+
+struct omap_des_reqctx {
+ unsigned long mode;
+};
+
+#define OMAP_DES_QUEUE_LENGTH 1
+#define OMAP_DES_CACHE_SIZE 0
+
+struct omap_des_algs_info {
+ struct crypto_alg *algs_list;
+ unsigned int size;
+ unsigned int registered;
+};
+
+struct omap_des_pdata {
+ struct omap_des_algs_info *algs_info;
+ unsigned int algs_info_size;
+
+ void (*trigger)(struct omap_des_dev *dd, int length);
+
+ u32 key_ofs;
+ u32 iv_ofs;
+ u32 ctrl_ofs;
+ u32 data_ofs;
+ u32 rev_ofs;
+ u32 mask_ofs;
+ u32 irq_enable_ofs;
+ u32 irq_status_ofs;
+
+ u32 dma_enable_in;
+ u32 dma_enable_out;
+ u32 dma_start;
+
+ u32 major_mask;
+ u32 major_shift;
+ u32 minor_mask;
+ u32 minor_shift;
+};
+
+struct omap_des_dev {
+ struct list_head list;
+ unsigned long phys_base;
+ void __iomem *io_base;
+ struct omap_des_ctx *ctx;
+ struct device *dev;
+ unsigned long flags;
+ int err;
+
+ /* spinlock used for queues */
+ spinlock_t lock;
+ struct crypto_queue queue;
+
+ struct tasklet_struct done_task;
+ struct tasklet_struct queue_task;
+
+ struct ablkcipher_request *req;
+ /*
+ * total is used by PIO mode for book keeping so introduce
+ * variable total_save as need it to calc page_order
+ */
+ size_t total;
+ size_t total_save;
+
+ struct scatterlist *in_sg;
+ struct scatterlist *out_sg;
+
+ /* Buffers for copying for unaligned cases */
+ struct scatterlist in_sgl;
+ struct scatterlist out_sgl;
+ struct scatterlist *orig_out;
+ int sgs_copied;
+
+ struct scatter_walk in_walk;
+ struct scatter_walk out_walk;
+ int dma_in;
+ struct dma_chan *dma_lch_in;
+ int dma_out;
+ struct dma_chan *dma_lch_out;
+ int in_sg_len;
+ int out_sg_len;
+ int pio_only;
+ const struct omap_des_pdata *pdata;
+};
+
+/* keep registered devices data here */
+static LIST_HEAD(dev_list);
+static DEFINE_SPINLOCK(list_lock);
+
+#ifdef DEBUG
+#define omap_des_read(dd, offset) \
+ ({ \
+ int _read_ret; \
+ _read_ret = __raw_readl(dd->io_base + offset); \
+ pr_err("omap_des_read(" #offset "=%#x)= %#x\n", \
+ offset, _read_ret); \
+ _read_ret; \
+ })
+#else
+static inline u32 omap_des_read(struct omap_des_dev *dd, u32 offset)
+{
+ return __raw_readl(dd->io_base + offset);
+}
+#endif
+
+#ifdef DEBUG
+#define omap_des_write(dd, offset, value) \
+ do { \
+ pr_err("omap_des_write(" #offset "=%#x) value=%#x\n", \
+ offset, value); \
+ __raw_writel(value, dd->io_base + offset); \
+ } while (0)
+#else
+static inline void omap_des_write(struct omap_des_dev *dd, u32 offset,
+ u32 value)
+{
+ __raw_writel(value, dd->io_base + offset);
+}
+#endif
+
+static inline void omap_des_write_mask(struct omap_des_dev *dd, u32 offset,
+ u32 value, u32 mask)
+{
+ u32 val;
+
+ val = omap_des_read(dd, offset);
+ val &= ~mask;
+ val |= value;
+ omap_des_write(dd, offset, val);
+}
+
+static void omap_des_write_n(struct omap_des_dev *dd, u32 offset,
+ u32 *value, int count)
+{
+ for (; count--; value++, offset += 4)
+ omap_des_write(dd, offset, *value);
+}
+
+static int omap_des_hw_init(struct omap_des_dev *dd)
+{
+ /*
+ * clocks are enabled when request starts and disabled when finished.
+ * It may be long delays between requests.
+ * Device might go to off mode to save power.
+ */
+ pm_runtime_get_sync(dd->dev);
+
+ if (!(dd->flags & FLAGS_INIT)) {
+ dd->flags |= FLAGS_INIT;
+ dd->err = 0;
+ }
+
+ return 0;
+}
+
+static int omap_des_write_ctrl(struct omap_des_dev *dd)
+{
+ unsigned int key32;
+ int i, err;
+ u32 val = 0, mask = 0;
+
+ err = omap_des_hw_init(dd);
+ if (err)
+ return err;
+
+ key32 = dd->ctx->keylen / sizeof(u32);
+
+ /* it seems a key should always be set even if it has not changed */
+ for (i = 0; i < key32; i++) {
+ omap_des_write(dd, DES_REG_KEY(dd, i),
+ __le32_to_cpu(dd->ctx->key[i]));
+ }
+
+ if ((dd->flags & FLAGS_CBC) && dd->req->info)
+ omap_des_write_n(dd, DES_REG_IV(dd, 0), dd->req->info, 2);
+
+ if (dd->flags & FLAGS_CBC)
+ val |= DES_REG_CTRL_CBC;
+ if (dd->flags & FLAGS_ENCRYPT)
+ val |= DES_REG_CTRL_DIRECTION;
+ if (key32 == 6)
+ val |= DES_REG_CTRL_TDES;
+
+ mask |= DES_REG_CTRL_CBC | DES_REG_CTRL_DIRECTION | DES_REG_CTRL_TDES;
+
+ omap_des_write_mask(dd, DES_REG_CTRL(dd), val, mask);
+
+ return 0;
+}
+
+static void omap_des_dma_trigger_omap4(struct omap_des_dev *dd, int length)
+{
+ u32 mask, val;
+
+ omap_des_write(dd, DES_REG_LENGTH_N(0), length);
+
+ val = dd->pdata->dma_start;
+
+ if (dd->dma_lch_out != NULL)
+ val |= dd->pdata->dma_enable_out;
+ if (dd->dma_lch_in != NULL)
+ val |= dd->pdata->dma_enable_in;
+
+ mask = dd->pdata->dma_enable_out | dd->pdata->dma_enable_in |
+ dd->pdata->dma_start;
+
+ omap_des_write_mask(dd, DES_REG_MASK(dd), val, mask);
+}
+
+static void omap_des_dma_stop(struct omap_des_dev *dd)
+{
+ u32 mask;
+
+ mask = dd->pdata->dma_enable_out | dd->pdata->dma_enable_in |
+ dd->pdata->dma_start;
+
+ omap_des_write_mask(dd, DES_REG_MASK(dd), 0, mask);
+}
+
+static struct omap_des_dev *omap_des_find_dev(struct omap_des_ctx *ctx)
+{
+ struct omap_des_dev *dd = NULL, *tmp;
+
+ spin_lock_bh(&list_lock);
+ if (!ctx->dd) {
+ list_for_each_entry(tmp, &dev_list, list) {
+ /* FIXME: take fist available des core */
+ dd = tmp;
+ break;
+ }
+ ctx->dd = dd;
+ } else {
+ /* already found before */
+ dd = ctx->dd;
+ }
+ spin_unlock_bh(&list_lock);
+
+ return dd;
+}
+
+static void omap_des_dma_out_callback(void *data)
+{
+ struct omap_des_dev *dd = data;
+
+ /* dma_lch_out - completed */
+ tasklet_schedule(&dd->done_task);
+}
+
+static int omap_des_dma_init(struct omap_des_dev *dd)
+{
+ int err = -ENOMEM;
+ dma_cap_mask_t mask;
+
+ dd->dma_lch_out = NULL;
+ dd->dma_lch_in = NULL;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ dd->dma_lch_in = dma_request_slave_channel_compat(mask,
+ omap_dma_filter_fn,
+ &dd->dma_in,
+ dd->dev, "rx");
+ if (!dd->dma_lch_in) {
+ dev_err(dd->dev, "Unable to request in DMA channel\n");
+ goto err_dma_in;
+ }
+
+ dd->dma_lch_out = dma_request_slave_channel_compat(mask,
+ omap_dma_filter_fn,
+ &dd->dma_out,
+ dd->dev, "tx");
+ if (!dd->dma_lch_out) {
+ dev_err(dd->dev, "Unable to request out DMA channel\n");
+ goto err_dma_out;
+ }
+
+ return 0;
+
+err_dma_out:
+ dma_release_channel(dd->dma_lch_in);
+err_dma_in:
+ if (err)
+ pr_err("error: %d\n", err);
+ return err;
+}
+
+static void omap_des_dma_cleanup(struct omap_des_dev *dd)
+{
+ dma_release_channel(dd->dma_lch_out);
+ dma_release_channel(dd->dma_lch_in);
+}
+
+static void sg_copy_buf(void *buf, struct scatterlist *sg,
+ unsigned int start, unsigned int nbytes, int out)
+{
+ struct scatter_walk walk;
+
+ if (!nbytes)
+ return;
+
+ scatterwalk_start(&walk, sg);
+ scatterwalk_advance(&walk, start);
+ scatterwalk_copychunks(buf, &walk, nbytes, out);
+ scatterwalk_done(&walk, out, 0);
+}
+
+static int omap_des_crypt_dma(struct crypto_tfm *tfm,
+ struct scatterlist *in_sg, struct scatterlist *out_sg,
+ int in_sg_len, int out_sg_len)
+{
+ struct omap_des_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct omap_des_dev *dd = ctx->dd;
+ struct dma_async_tx_descriptor *tx_in, *tx_out;
+ struct dma_slave_config cfg;
+ int ret;
+
+ if (dd->pio_only) {
+ scatterwalk_start(&dd->in_walk, dd->in_sg);
+ scatterwalk_start(&dd->out_walk, dd->out_sg);
+
+ /* Enable DATAIN interrupt and let it take
+ care of the rest */
+ omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x2);
+ return 0;
+ }
+
+ dma_sync_sg_for_device(dd->dev, dd->in_sg, in_sg_len, DMA_TO_DEVICE);
+
+ memset(&cfg, 0, sizeof(cfg));
+
+ cfg.src_addr = dd->phys_base + DES_REG_DATA_N(dd, 0);
+ cfg.dst_addr = dd->phys_base + DES_REG_DATA_N(dd, 0);
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.src_maxburst = DST_MAXBURST;
+ cfg.dst_maxburst = DST_MAXBURST;
+
+ /* IN */
+ ret = dmaengine_slave_config(dd->dma_lch_in, &cfg);
+ if (ret) {
+ dev_err(dd->dev, "can't configure IN dmaengine slave: %d\n",
+ ret);
+ return ret;
+ }
+
+ tx_in = dmaengine_prep_slave_sg(dd->dma_lch_in, in_sg, in_sg_len,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!tx_in) {
+ dev_err(dd->dev, "IN prep_slave_sg() failed\n");
+ return -EINVAL;
+ }
+
+ /* No callback necessary */
+ tx_in->callback_param = dd;
+
+ /* OUT */
+ ret = dmaengine_slave_config(dd->dma_lch_out, &cfg);
+ if (ret) {
+ dev_err(dd->dev, "can't configure OUT dmaengine slave: %d\n",
+ ret);
+ return ret;
+ }
+
+ tx_out = dmaengine_prep_slave_sg(dd->dma_lch_out, out_sg, out_sg_len,
+ DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!tx_out) {
+ dev_err(dd->dev, "OUT prep_slave_sg() failed\n");
+ return -EINVAL;
+ }
+
+ tx_out->callback = omap_des_dma_out_callback;
+ tx_out->callback_param = dd;
+
+ dmaengine_submit(tx_in);
+ dmaengine_submit(tx_out);
+
+ dma_async_issue_pending(dd->dma_lch_in);
+ dma_async_issue_pending(dd->dma_lch_out);
+
+ /* start DMA */
+ dd->pdata->trigger(dd, dd->total);
+
+ return 0;
+}
+
+static int omap_des_crypt_dma_start(struct omap_des_dev *dd)
+{
+ struct crypto_tfm *tfm = crypto_ablkcipher_tfm(
+ crypto_ablkcipher_reqtfm(dd->req));
+ int err;
+
+ pr_debug("total: %d\n", dd->total);
+
+ if (!dd->pio_only) {
+ err = dma_map_sg(dd->dev, dd->in_sg, dd->in_sg_len,
+ DMA_TO_DEVICE);
+ if (!err) {
+ dev_err(dd->dev, "dma_map_sg() error\n");
+ return -EINVAL;
+ }
+
+ err = dma_map_sg(dd->dev, dd->out_sg, dd->out_sg_len,
+ DMA_FROM_DEVICE);
+ if (!err) {
+ dev_err(dd->dev, "dma_map_sg() error\n");
+ return -EINVAL;
+ }
+ }
+
+ err = omap_des_crypt_dma(tfm, dd->in_sg, dd->out_sg, dd->in_sg_len,
+ dd->out_sg_len);
+ if (err && !dd->pio_only) {
+ dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE);
+ dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len,
+ DMA_FROM_DEVICE);
+ }
+
+ return err;
+}
+
+static void omap_des_finish_req(struct omap_des_dev *dd, int err)
+{
+ struct ablkcipher_request *req = dd->req;
+
+ pr_debug("err: %d\n", err);
+
+ pm_runtime_put(dd->dev);
+ dd->flags &= ~FLAGS_BUSY;
+
+ req->base.complete(&req->base, err);
+}
+
+static int omap_des_crypt_dma_stop(struct omap_des_dev *dd)
+{
+ int err = 0;
+
+ pr_debug("total: %d\n", dd->total);
+
+ omap_des_dma_stop(dd);
+
+ dmaengine_terminate_all(dd->dma_lch_in);
+ dmaengine_terminate_all(dd->dma_lch_out);
+
+ dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE);
+ dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len, DMA_FROM_DEVICE);
+
+ return err;
+}
+
+static int omap_des_copy_needed(struct scatterlist *sg)
+{
+ while (sg) {
+ if (!IS_ALIGNED(sg->offset, 4))
+ return -1;
+ if (!IS_ALIGNED(sg->length, DES_BLOCK_SIZE))
+ return -1;
+ sg = sg_next(sg);
+ }
+ return 0;
+}
+
+static int omap_des_copy_sgs(struct omap_des_dev *dd)
+{
+ void *buf_in, *buf_out;
+ int pages;
+
+ pages = dd->total >> PAGE_SHIFT;
+
+ if (dd->total & (PAGE_SIZE-1))
+ pages++;
+
+ BUG_ON(!pages);
+
+ buf_in = (void *)__get_free_pages(GFP_ATOMIC, pages);
+ buf_out = (void *)__get_free_pages(GFP_ATOMIC, pages);
+
+ if (!buf_in || !buf_out) {
+ pr_err("Couldn't allocated pages for unaligned cases.\n");
+ return -1;
+ }
+
+ dd->orig_out = dd->out_sg;
+
+ sg_copy_buf(buf_in, dd->in_sg, 0, dd->total, 0);
+
+ sg_init_table(&dd->in_sgl, 1);
+ sg_set_buf(&dd->in_sgl, buf_in, dd->total);
+ dd->in_sg = &dd->in_sgl;
+
+ sg_init_table(&dd->out_sgl, 1);
+ sg_set_buf(&dd->out_sgl, buf_out, dd->total);
+ dd->out_sg = &dd->out_sgl;
+
+ return 0;
+}
+
+static int omap_des_handle_queue(struct omap_des_dev *dd,
+ struct ablkcipher_request *req)
+{
+ struct crypto_async_request *async_req, *backlog;
+ struct omap_des_ctx *ctx;
+ struct omap_des_reqctx *rctx;
+ unsigned long flags;
+ int err, ret = 0;
+
+ spin_lock_irqsave(&dd->lock, flags);
+ if (req)
+ ret = ablkcipher_enqueue_request(&dd->queue, req);
+ if (dd->flags & FLAGS_BUSY) {
+ spin_unlock_irqrestore(&dd->lock, flags);
+ return ret;
+ }
+ backlog = crypto_get_backlog(&dd->queue);
+ async_req = crypto_dequeue_request(&dd->queue);
+ if (async_req)
+ dd->flags |= FLAGS_BUSY;
+ spin_unlock_irqrestore(&dd->lock, flags);
+
+ if (!async_req)
+ return ret;
+
+ if (backlog)
+ backlog->complete(backlog, -EINPROGRESS);
+
+ req = ablkcipher_request_cast(async_req);
+
+ /* assign new request to device */
+ dd->req = req;
+ dd->total = req->nbytes;
+ dd->total_save = req->nbytes;
+ dd->in_sg = req->src;
+ dd->out_sg = req->dst;
+
+ if (omap_des_copy_needed(dd->in_sg) ||
+ omap_des_copy_needed(dd->out_sg)) {
+ if (omap_des_copy_sgs(dd))
+ pr_err("Failed to copy SGs for unaligned cases\n");
+ dd->sgs_copied = 1;
+ } else {
+ dd->sgs_copied = 0;
+ }
+
+ dd->in_sg_len = scatterwalk_bytes_sglen(dd->in_sg, dd->total);
+ dd->out_sg_len = scatterwalk_bytes_sglen(dd->out_sg, dd->total);
+ BUG_ON(dd->in_sg_len < 0 || dd->out_sg_len < 0);
+
+ rctx = ablkcipher_request_ctx(req);
+ ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
+ rctx->mode &= FLAGS_MODE_MASK;
+ dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode;
+
+ dd->ctx = ctx;
+ ctx->dd = dd;
+
+ err = omap_des_write_ctrl(dd);
+ if (!err)
+ err = omap_des_crypt_dma_start(dd);
+ if (err) {
+ /* des_task will not finish it, so do it here */
+ omap_des_finish_req(dd, err);
+ tasklet_schedule(&dd->queue_task);
+ }
+
+ return ret; /* return ret, which is enqueue return value */
+}
+
+static void omap_des_done_task(unsigned long data)
+{
+ struct omap_des_dev *dd = (struct omap_des_dev *)data;
+ void *buf_in, *buf_out;
+ int pages;
+
+ pr_debug("enter done_task\n");
+
+ if (!dd->pio_only) {
+ dma_sync_sg_for_device(dd->dev, dd->out_sg, dd->out_sg_len,
+ DMA_FROM_DEVICE);
+ dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE);
+ dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len,
+ DMA_FROM_DEVICE);
+ omap_des_crypt_dma_stop(dd);
+ }
+
+ if (dd->sgs_copied) {
+ buf_in = sg_virt(&dd->in_sgl);
+ buf_out = sg_virt(&dd->out_sgl);
+
+ sg_copy_buf(buf_out, dd->orig_out, 0, dd->total_save, 1);
+
+ pages = get_order(dd->total_save);
+ free_pages((unsigned long)buf_in, pages);
+ free_pages((unsigned long)buf_out, pages);
+ }
+
+ omap_des_finish_req(dd, 0);
+ omap_des_handle_queue(dd, NULL);
+
+ pr_debug("exit\n");
+}
+
+static void omap_des_queue_task(unsigned long data)
+{
+ struct omap_des_dev *dd = (struct omap_des_dev *)data;
+
+ omap_des_handle_queue(dd, NULL);
+}
+
+static int omap_des_crypt(struct ablkcipher_request *req, unsigned long mode)
+{
+ struct omap_des_ctx *ctx = crypto_ablkcipher_ctx(
+ crypto_ablkcipher_reqtfm(req));
+ struct omap_des_reqctx *rctx = ablkcipher_request_ctx(req);
+ struct omap_des_dev *dd;
+
+ pr_debug("nbytes: %d, enc: %d, cbc: %d\n", req->nbytes,
+ !!(mode & FLAGS_ENCRYPT),
+ !!(mode & FLAGS_CBC));
+
+ if (!IS_ALIGNED(req->nbytes, DES_BLOCK_SIZE)) {
+ pr_err("request size is not exact amount of DES blocks\n");
+ return -EINVAL;
+ }
+
+ dd = omap_des_find_dev(ctx);
+ if (!dd)
+ return -ENODEV;
+
+ rctx->mode = mode;
+
+ return omap_des_handle_queue(dd, req);
+}
+
+/* ********************** ALG API ************************************ */
+
+static int omap_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct omap_des_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+
+ if (keylen != DES_KEY_SIZE && keylen != (3*DES_KEY_SIZE))
+ return -EINVAL;
+
+ pr_debug("enter, keylen: %d\n", keylen);
+
+ memcpy(ctx->key, key, keylen);
+ ctx->keylen = keylen;
+
+ return 0;
+}
+
+static int omap_des_ecb_encrypt(struct ablkcipher_request *req)
+{
+ return omap_des_crypt(req, FLAGS_ENCRYPT);
+}
+
+static int omap_des_ecb_decrypt(struct ablkcipher_request *req)
+{
+ return omap_des_crypt(req, 0);
+}
+
+static int omap_des_cbc_encrypt(struct ablkcipher_request *req)
+{
+ return omap_des_crypt(req, FLAGS_ENCRYPT | FLAGS_CBC);
+}
+
+static int omap_des_cbc_decrypt(struct ablkcipher_request *req)
+{
+ return omap_des_crypt(req, FLAGS_CBC);
+}
+
+static int omap_des_cra_init(struct crypto_tfm *tfm)
+{
+ pr_debug("enter\n");
+
+ tfm->crt_ablkcipher.reqsize = sizeof(struct omap_des_reqctx);
+
+ return 0;
+}
+
+static void omap_des_cra_exit(struct crypto_tfm *tfm)
+{
+ pr_debug("enter\n");
+}
+
+/* ********************** ALGS ************************************ */
+
+static struct crypto_alg algs_ecb_cbc[] = {
+{
+ .cra_name = "ecb(des)",
+ .cra_driver_name = "ecb-des-omap",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_KERN_DRIVER_ONLY |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct omap_des_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = omap_des_cra_init,
+ .cra_exit = omap_des_cra_exit,
+ .cra_u.ablkcipher = {
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ .setkey = omap_des_setkey,
+ .encrypt = omap_des_ecb_encrypt,
+ .decrypt = omap_des_ecb_decrypt,
+ }
+},
+{
+ .cra_name = "cbc(des)",
+ .cra_driver_name = "cbc-des-omap",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_KERN_DRIVER_ONLY |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct omap_des_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = omap_des_cra_init,
+ .cra_exit = omap_des_cra_exit,
+ .cra_u.ablkcipher = {
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ .ivsize = DES_BLOCK_SIZE,
+ .setkey = omap_des_setkey,
+ .encrypt = omap_des_cbc_encrypt,
+ .decrypt = omap_des_cbc_decrypt,
+ }
+},
+{
+ .cra_name = "ecb(des3_ede)",
+ .cra_driver_name = "ecb-des3-omap",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_KERN_DRIVER_ONLY |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct omap_des_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = omap_des_cra_init,
+ .cra_exit = omap_des_cra_exit,
+ .cra_u.ablkcipher = {
+ .min_keysize = 3*DES_KEY_SIZE,
+ .max_keysize = 3*DES_KEY_SIZE,
+ .setkey = omap_des_setkey,
+ .encrypt = omap_des_ecb_encrypt,
+ .decrypt = omap_des_ecb_decrypt,
+ }
+},
+{
+ .cra_name = "cbc(des3_ede)",
+ .cra_driver_name = "cbc-des3-omap",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_KERN_DRIVER_ONLY |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct omap_des_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = omap_des_cra_init,
+ .cra_exit = omap_des_cra_exit,
+ .cra_u.ablkcipher = {
+ .min_keysize = 3*DES_KEY_SIZE,
+ .max_keysize = 3*DES_KEY_SIZE,
+ .ivsize = DES_BLOCK_SIZE,
+ .setkey = omap_des_setkey,
+ .encrypt = omap_des_cbc_encrypt,
+ .decrypt = omap_des_cbc_decrypt,
+ }
+}
+};
+
+static struct omap_des_algs_info omap_des_algs_info_ecb_cbc[] = {
+ {
+ .algs_list = algs_ecb_cbc,
+ .size = ARRAY_SIZE(algs_ecb_cbc),
+ },
+};
+
+#ifdef CONFIG_OF
+static const struct omap_des_pdata omap_des_pdata_omap4 = {
+ .algs_info = omap_des_algs_info_ecb_cbc,
+ .algs_info_size = ARRAY_SIZE(omap_des_algs_info_ecb_cbc),
+ .trigger = omap_des_dma_trigger_omap4,
+ .key_ofs = 0x14,
+ .iv_ofs = 0x18,
+ .ctrl_ofs = 0x20,
+ .data_ofs = 0x28,
+ .rev_ofs = 0x30,
+ .mask_ofs = 0x34,
+ .irq_status_ofs = 0x3c,
+ .irq_enable_ofs = 0x40,
+ .dma_enable_in = BIT(5),
+ .dma_enable_out = BIT(6),
+ .major_mask = 0x0700,
+ .major_shift = 8,
+ .minor_mask = 0x003f,
+ .minor_shift = 0,
+};
+
+static irqreturn_t omap_des_irq(int irq, void *dev_id)
+{
+ struct omap_des_dev *dd = dev_id;
+ u32 status, i;
+ u32 *src, *dst;
+
+ status = omap_des_read(dd, DES_REG_IRQ_STATUS(dd));
+ if (status & DES_REG_IRQ_DATA_IN) {
+ omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x0);
+
+ BUG_ON(!dd->in_sg);
+
+ BUG_ON(_calc_walked(in) > dd->in_sg->length);
+
+ src = sg_virt(dd->in_sg) + _calc_walked(in);
+
+ for (i = 0; i < DES_BLOCK_WORDS; i++) {
+ omap_des_write(dd, DES_REG_DATA_N(dd, i), *src);
+
+ scatterwalk_advance(&dd->in_walk, 4);
+ if (dd->in_sg->length == _calc_walked(in)) {
+ dd->in_sg = scatterwalk_sg_next(dd->in_sg);
+ if (dd->in_sg) {
+ scatterwalk_start(&dd->in_walk,
+ dd->in_sg);
+ src = sg_virt(dd->in_sg) +
+ _calc_walked(in);
+ }
+ } else {
+ src++;
+ }
+ }
+
+ /* Clear IRQ status */
+ status &= ~DES_REG_IRQ_DATA_IN;
+ omap_des_write(dd, DES_REG_IRQ_STATUS(dd), status);
+
+ /* Enable DATA_OUT interrupt */
+ omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x4);
+
+ } else if (status & DES_REG_IRQ_DATA_OUT) {
+ omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x0);
+
+ BUG_ON(!dd->out_sg);
+
+ BUG_ON(_calc_walked(out) > dd->out_sg->length);
+
+ dst = sg_virt(dd->out_sg) + _calc_walked(out);
+
+ for (i = 0; i < DES_BLOCK_WORDS; i++) {
+ *dst = omap_des_read(dd, DES_REG_DATA_N(dd, i));
+ scatterwalk_advance(&dd->out_walk, 4);
+ if (dd->out_sg->length == _calc_walked(out)) {
+ dd->out_sg = scatterwalk_sg_next(dd->out_sg);
+ if (dd->out_sg) {
+ scatterwalk_start(&dd->out_walk,
+ dd->out_sg);
+ dst = sg_virt(dd->out_sg) +
+ _calc_walked(out);
+ }
+ } else {
+ dst++;
+ }
+ }
+
+ dd->total -= DES_BLOCK_SIZE;
+
+ BUG_ON(dd->total < 0);
+
+ /* Clear IRQ status */
+ status &= ~DES_REG_IRQ_DATA_OUT;
+ omap_des_write(dd, DES_REG_IRQ_STATUS(dd), status);
+
+ if (!dd->total)
+ /* All bytes read! */
+ tasklet_schedule(&dd->done_task);
+ else
+ /* Enable DATA_IN interrupt for next block */
+ omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x2);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static const struct of_device_id omap_des_of_match[] = {
+ {
+ .compatible = "ti,omap4-des",
+ .data = &omap_des_pdata_omap4,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, omap_des_of_match);
+
+static int omap_des_get_of(struct omap_des_dev *dd,
+ struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+
+ match = of_match_device(of_match_ptr(omap_des_of_match), &pdev->dev);
+ if (!match) {
+ dev_err(&pdev->dev, "no compatible OF match\n");
+ return -EINVAL;
+ }
+
+ dd->dma_out = -1; /* Dummy value that's unused */
+ dd->dma_in = -1; /* Dummy value that's unused */
+ dd->pdata = match->data;
+
+ return 0;
+}
+#else
+static int omap_des_get_of(struct omap_des_dev *dd,
+ struct device *dev)
+{
+ return -EINVAL;
+}
+#endif
+
+static int omap_des_get_pdev(struct omap_des_dev *dd,
+ struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *r;
+ int err = 0;
+
+ /* Get the DMA out channel */
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!r) {
+ dev_err(dev, "no DMA out resource info\n");
+ err = -ENODEV;
+ goto err;
+ }
+ dd->dma_out = r->start;
+
+ /* Get the DMA in channel */
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!r) {
+ dev_err(dev, "no DMA in resource info\n");
+ err = -ENODEV;
+ goto err;
+ }
+ dd->dma_in = r->start;
+
+ /* non-DT devices get pdata from pdev */
+ dd->pdata = pdev->dev.platform_data;
+
+err:
+ return err;
+}
+
+static int omap_des_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct omap_des_dev *dd;
+ struct crypto_alg *algp;
+ struct resource *res;
+ int err = -ENOMEM, i, j, irq = -1;
+ u32 reg;
+
+ dd = devm_kzalloc(dev, sizeof(struct omap_des_dev), GFP_KERNEL);
+ if (dd == NULL) {
+ dev_err(dev, "unable to alloc data struct.\n");
+ goto err_data;
+ }
+ dd->dev = dev;
+ platform_set_drvdata(pdev, dd);
+
+ spin_lock_init(&dd->lock);
+ crypto_init_queue(&dd->queue, OMAP_DES_QUEUE_LENGTH);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "no MEM resource info\n");
+ goto err_res;
+ }
+
+ err = (dev->of_node) ? omap_des_get_of(dd, pdev) :
+ omap_des_get_pdev(dd, pdev);
+ if (err)
+ goto err_res;
+
+ dd->io_base = devm_request_and_ioremap(dev, res);
+ if (!dd->io_base) {
+ dev_err(dev, "can't ioremap\n");
+ err = -ENOMEM;
+ goto err_res;
+ }
+ dd->phys_base = res->start;
+
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+
+ omap_des_dma_stop(dd);
+
+ reg = omap_des_read(dd, DES_REG_REV(dd));
+
+ pm_runtime_put_sync(dev);
+
+ dev_info(dev, "OMAP DES hw accel rev: %u.%u\n",
+ (reg & dd->pdata->major_mask) >> dd->pdata->major_shift,
+ (reg & dd->pdata->minor_mask) >> dd->pdata->minor_shift);
+
+ tasklet_init(&dd->done_task, omap_des_done_task, (unsigned long)dd);
+ tasklet_init(&dd->queue_task, omap_des_queue_task, (unsigned long)dd);
+
+ err = omap_des_dma_init(dd);
+ if (err && DES_REG_IRQ_STATUS(dd) && DES_REG_IRQ_ENABLE(dd)) {
+ dd->pio_only = 1;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "can't get IRQ resource\n");
+ goto err_irq;
+ }
+
+ err = devm_request_irq(dev, irq, omap_des_irq, 0,
+ dev_name(dev), dd);
+ if (err) {
+ dev_err(dev, "Unable to grab omap-des IRQ\n");
+ goto err_irq;
+ }
+ }
+
+
+ INIT_LIST_HEAD(&dd->list);
+ spin_lock(&list_lock);
+ list_add_tail(&dd->list, &dev_list);
+ spin_unlock(&list_lock);
+
+ for (i = 0; i < dd->pdata->algs_info_size; i++) {
+ for (j = 0; j < dd->pdata->algs_info[i].size; j++) {
+ algp = &dd->pdata->algs_info[i].algs_list[j];
+
+ pr_debug("reg alg: %s\n", algp->cra_name);
+ INIT_LIST_HEAD(&algp->cra_list);
+
+ err = crypto_register_alg(algp);
+ if (err)
+ goto err_algs;
+
+ dd->pdata->algs_info[i].registered++;
+ }
+ }
+
+ return 0;
+err_algs:
+ for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
+ for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
+ crypto_unregister_alg(
+ &dd->pdata->algs_info[i].algs_list[j]);
+ if (!dd->pio_only)
+ omap_des_dma_cleanup(dd);
+err_irq:
+ tasklet_kill(&dd->done_task);
+ tasklet_kill(&dd->queue_task);
+ pm_runtime_disable(dev);
+err_res:
+ dd = NULL;
+err_data:
+ dev_err(dev, "initialization failed.\n");
+ return err;
+}
+
+static int omap_des_remove(struct platform_device *pdev)
+{
+ struct omap_des_dev *dd = platform_get_drvdata(pdev);
+ int i, j;
+
+ if (!dd)
+ return -ENODEV;
+
+ spin_lock(&list_lock);
+ list_del(&dd->list);
+ spin_unlock(&list_lock);
+
+ for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
+ for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
+ crypto_unregister_alg(
+ &dd->pdata->algs_info[i].algs_list[j]);
+
+ tasklet_kill(&dd->done_task);
+ tasklet_kill(&dd->queue_task);
+ omap_des_dma_cleanup(dd);
+ pm_runtime_disable(dd->dev);
+ dd = NULL;
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int omap_des_suspend(struct device *dev)
+{
+ pm_runtime_put_sync(dev);
+ return 0;
+}
+
+static int omap_des_resume(struct device *dev)
+{
+ pm_runtime_get_sync(dev);
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(omap_des_pm_ops, omap_des_suspend, omap_des_resume);
+
+static struct platform_driver omap_des_driver = {
+ .probe = omap_des_probe,
+ .remove = omap_des_remove,
+ .driver = {
+ .name = "omap-des",
+ .owner = THIS_MODULE,
+ .pm = &omap_des_pm_ops,
+ .of_match_table = of_match_ptr(omap_des_of_match),
+ },
+};
+
+module_platform_driver(omap_des_driver);
+
+MODULE_DESCRIPTION("OMAP DES hw acceleration support.");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Joel Fernandes <joelf@ti.com>");
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index a727a6a59653..710d86386965 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -636,11 +636,17 @@ static size_t omap_sham_append_buffer(struct omap_sham_reqctx *ctx,
static size_t omap_sham_append_sg(struct omap_sham_reqctx *ctx)
{
size_t count;
+ const u8 *vaddr;
while (ctx->sg) {
+ vaddr = kmap_atomic(sg_page(ctx->sg));
+
count = omap_sham_append_buffer(ctx,
- sg_virt(ctx->sg) + ctx->offset,
+ vaddr + ctx->offset,
ctx->sg->length - ctx->offset);
+
+ kunmap_atomic((void *)vaddr);
+
if (!count)
break;
ctx->offset += count;
@@ -2022,9 +2028,7 @@ static int omap_sham_resume(struct device *dev)
}
#endif
-static const struct dev_pm_ops omap_sham_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(omap_sham_suspend, omap_sham_resume)
-};
+static SIMPLE_DEV_PM_OPS(omap_sham_pm_ops, omap_sham_suspend, omap_sham_resume);
static struct platform_driver omap_sham_driver = {
.probe = omap_sham_probe,
diff --git a/drivers/crypto/picoxcell_crypto.c b/drivers/crypto/picoxcell_crypto.c
index a6175ba6d238..5da5b98b8f29 100644
--- a/drivers/crypto/picoxcell_crypto.c
+++ b/drivers/crypto/picoxcell_crypto.c
@@ -1720,22 +1720,16 @@ static int spacc_probe(struct platform_device *pdev)
engine->name = dev_name(&pdev->dev);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ engine->regs = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(engine->regs))
+ return PTR_ERR(engine->regs);
+
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!mem || !irq) {
+ if (!irq) {
dev_err(&pdev->dev, "no memory/irq resource for engine\n");
return -ENXIO;
}
- if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem),
- engine->name))
- return -ENOMEM;
-
- engine->regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
- if (!engine->regs) {
- dev_err(&pdev->dev, "memory map failed\n");
- return -ENOMEM;
- }
-
if (devm_request_irq(&pdev->dev, irq->start, spacc_spacc_irq, 0,
engine->name, engine)) {
dev_err(engine->dev, "failed to request IRQ\n");
diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c
index cf149b19ff47..be45762f390a 100644
--- a/drivers/crypto/s5p-sss.c
+++ b/drivers/crypto/s5p-sss.c
@@ -568,17 +568,14 @@ static int s5p_aes_probe(struct platform_device *pdev)
if (s5p_dev)
return -EEXIST;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
-
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
- if (!devm_request_mem_region(dev, res->start,
- resource_size(res), pdev->name))
- return -EBUSY;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pdata->ioaddr))
+ return PTR_ERR(pdata->ioaddr);
pdata->clk = devm_clk_get(dev, "secss");
if (IS_ERR(pdata->clk)) {
@@ -589,8 +586,6 @@ static int s5p_aes_probe(struct platform_device *pdev)
clk_enable(pdata->clk);
spin_lock_init(&pdata->lock);
- pdata->ioaddr = devm_ioremap(dev, res->start,
- resource_size(res));
pdata->irq_hash = platform_get_irq_byname(pdev, "hash");
if (pdata->irq_hash < 0) {
diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c
index 785a9ded7bdf..07a5987ce67d 100644
--- a/drivers/crypto/sahara.c
+++ b/drivers/crypto/sahara.c
@@ -885,22 +885,9 @@ static int sahara_probe(struct platform_device *pdev)
/* Get the base address */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "failed to get memory region resource\n");
- return -ENODEV;
- }
-
- if (devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res), SAHARA_NAME) == NULL) {
- dev_err(&pdev->dev, "failed to request memory region\n");
- return -ENOENT;
- }
- dev->regs_base = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (!dev->regs_base) {
- dev_err(&pdev->dev, "failed to ioremap address region\n");
- return -ENOENT;
- }
+ dev->regs_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dev->regs_base))
+ return PTR_ERR(dev->regs_base);
/* Get the IRQ */
irq = platform_get_irq(pdev, 0);
@@ -909,10 +896,11 @@ static int sahara_probe(struct platform_device *pdev)
return irq;
}
- if (devm_request_irq(&pdev->dev, irq, sahara_irq_handler,
- 0, SAHARA_NAME, dev) < 0) {
+ err = devm_request_irq(&pdev->dev, irq, sahara_irq_handler,
+ 0, dev_name(&pdev->dev), dev);
+ if (err) {
dev_err(&pdev->dev, "failed to request irq\n");
- return -ENOENT;
+ return err;
}
/* clocks */
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index 5967667e1a8f..624b8be0c365 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -2637,6 +2637,8 @@ static int talitos_probe(struct platform_device *ofdev)
if (!priv)
return -ENOMEM;
+ INIT_LIST_HEAD(&priv->alg_list);
+
dev_set_drvdata(dev, priv);
priv->ofdev = ofdev;
@@ -2657,8 +2659,6 @@ static int talitos_probe(struct platform_device *ofdev)
(unsigned long)dev);
}
- INIT_LIST_HEAD(&priv->alg_list);
-
priv->reg = of_iomap(np, 0);
if (!priv->reg) {
dev_err(dev, "failed to of_iomap\n");
diff --git a/drivers/crypto/tegra-aes.c b/drivers/crypto/tegra-aes.c
deleted file mode 100644
index 060eecc5dbc3..000000000000
--- a/drivers/crypto/tegra-aes.c
+++ /dev/null
@@ -1,1087 +0,0 @@
-/*
- * drivers/crypto/tegra-aes.c
- *
- * Driver for NVIDIA Tegra AES hardware engine residing inside the
- * Bit Stream Engine for Video (BSEV) hardware block.
- *
- * The programming sequence for this engine is with the help
- * of commands which travel via a command queue residing between the
- * CPU and the BSEV block. The BSEV engine has an internal RAM (VRAM)
- * where the final input plaintext, keys and the IV have to be copied
- * before starting the encrypt/decrypt operation.
- *
- * Copyright (c) 2010, NVIDIA 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
- * 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.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/scatterlist.h>
-#include <linux/dma-mapping.h>
-#include <linux/io.h>
-#include <linux/mutex.h>
-#include <linux/interrupt.h>
-#include <linux/completion.h>
-#include <linux/workqueue.h>
-
-#include <crypto/scatterwalk.h>
-#include <crypto/aes.h>
-#include <crypto/internal/rng.h>
-
-#include "tegra-aes.h"
-
-#define FLAGS_MODE_MASK 0x00FF
-#define FLAGS_ENCRYPT BIT(0)
-#define FLAGS_CBC BIT(1)
-#define FLAGS_GIV BIT(2)
-#define FLAGS_RNG BIT(3)
-#define FLAGS_OFB BIT(4)
-#define FLAGS_NEW_KEY BIT(5)
-#define FLAGS_NEW_IV BIT(6)
-#define FLAGS_INIT BIT(7)
-#define FLAGS_FAST BIT(8)
-#define FLAGS_BUSY 9
-
-/*
- * Defines AES engine Max process bytes size in one go, which takes 1 msec.
- * AES engine spends about 176 cycles/16-bytes or 11 cycles/byte
- * The duration CPU can use the BSE to 1 msec, then the number of available
- * cycles of AVP/BSE is 216K. In this duration, AES can process 216/11 ~= 19KB
- * Based on this AES_HW_DMA_BUFFER_SIZE_BYTES is configured to 16KB.
- */
-#define AES_HW_DMA_BUFFER_SIZE_BYTES 0x4000
-
-/*
- * The key table length is 64 bytes
- * (This includes first upto 32 bytes key + 16 bytes original initial vector
- * and 16 bytes updated initial vector)
- */
-#define AES_HW_KEY_TABLE_LENGTH_BYTES 64
-
-/*
- * The memory being used is divides as follows:
- * 1. Key - 32 bytes
- * 2. Original IV - 16 bytes
- * 3. Updated IV - 16 bytes
- * 4. Key schedule - 256 bytes
- *
- * 1+2+3 constitute the hw key table.
- */
-#define AES_HW_IV_SIZE 16
-#define AES_HW_KEYSCHEDULE_LEN 256
-#define AES_IVKEY_SIZE (AES_HW_KEY_TABLE_LENGTH_BYTES + AES_HW_KEYSCHEDULE_LEN)
-
-/* Define commands required for AES operation */
-enum {
- CMD_BLKSTARTENGINE = 0x0E,
- CMD_DMASETUP = 0x10,
- CMD_DMACOMPLETE = 0x11,
- CMD_SETTABLE = 0x15,
- CMD_MEMDMAVD = 0x22,
-};
-
-/* Define sub-commands */
-enum {
- SUBCMD_VRAM_SEL = 0x1,
- SUBCMD_CRYPTO_TABLE_SEL = 0x3,
- SUBCMD_KEY_TABLE_SEL = 0x8,
-};
-
-/* memdma_vd command */
-#define MEMDMA_DIR_DTOVRAM 0 /* sdram -> vram */
-#define MEMDMA_DIR_VTODRAM 1 /* vram -> sdram */
-#define MEMDMA_DIR_SHIFT 25
-#define MEMDMA_NUM_WORDS_SHIFT 12
-
-/* command queue bit shifts */
-enum {
- CMDQ_KEYTABLEADDR_SHIFT = 0,
- CMDQ_KEYTABLEID_SHIFT = 17,
- CMDQ_VRAMSEL_SHIFT = 23,
- CMDQ_TABLESEL_SHIFT = 24,
- CMDQ_OPCODE_SHIFT = 26,
-};
-
-/*
- * The secure key slot contains a unique secure key generated
- * and loaded by the bootloader. This slot is marked as non-accessible
- * to the kernel.
- */
-#define SSK_SLOT_NUM 4
-
-#define AES_NR_KEYSLOTS 8
-#define TEGRA_AES_QUEUE_LENGTH 50
-#define DEFAULT_RNG_BLK_SZ 16
-
-/* The command queue depth */
-#define AES_HW_MAX_ICQ_LENGTH 5
-
-struct tegra_aes_slot {
- struct list_head node;
- int slot_num;
-};
-
-static struct tegra_aes_slot ssk = {
- .slot_num = SSK_SLOT_NUM,
-};
-
-struct tegra_aes_reqctx {
- unsigned long mode;
-};
-
-struct tegra_aes_dev {
- struct device *dev;
- void __iomem *io_base;
- dma_addr_t ivkey_phys_base;
- void __iomem *ivkey_base;
- struct clk *aes_clk;
- struct tegra_aes_ctx *ctx;
- int irq;
- unsigned long flags;
- struct completion op_complete;
- u32 *buf_in;
- dma_addr_t dma_buf_in;
- u32 *buf_out;
- dma_addr_t dma_buf_out;
- u8 *iv;
- u8 dt[DEFAULT_RNG_BLK_SZ];
- int ivlen;
- u64 ctr;
- spinlock_t lock;
- struct crypto_queue queue;
- struct tegra_aes_slot *slots;
- struct ablkcipher_request *req;
- size_t total;
- struct scatterlist *in_sg;
- size_t in_offset;
- struct scatterlist *out_sg;
- size_t out_offset;
-};
-
-static struct tegra_aes_dev *aes_dev;
-
-struct tegra_aes_ctx {
- struct tegra_aes_dev *dd;
- unsigned long flags;
- struct tegra_aes_slot *slot;
- u8 key[AES_MAX_KEY_SIZE];
- size_t keylen;
-};
-
-static struct tegra_aes_ctx rng_ctx = {
- .flags = FLAGS_NEW_KEY,
- .keylen = AES_KEYSIZE_128,
-};
-
-/* keep registered devices data here */
-static struct list_head dev_list;
-static DEFINE_SPINLOCK(list_lock);
-static DEFINE_MUTEX(aes_lock);
-
-static void aes_workqueue_handler(struct work_struct *work);
-static DECLARE_WORK(aes_work, aes_workqueue_handler);
-static struct workqueue_struct *aes_wq;
-
-static inline u32 aes_readl(struct tegra_aes_dev *dd, u32 offset)
-{
- return readl(dd->io_base + offset);
-}
-
-static inline void aes_writel(struct tegra_aes_dev *dd, u32 val, u32 offset)
-{
- writel(val, dd->io_base + offset);
-}
-
-static int aes_start_crypt(struct tegra_aes_dev *dd, u32 in_addr, u32 out_addr,
- int nblocks, int mode, bool upd_iv)
-{
- u32 cmdq[AES_HW_MAX_ICQ_LENGTH];
- int i, eng_busy, icq_empty, ret;
- u32 value;
-
- /* reset all the interrupt bits */
- aes_writel(dd, 0xFFFFFFFF, TEGRA_AES_INTR_STATUS);
-
- /* enable error, dma xfer complete interrupts */
- aes_writel(dd, 0x33, TEGRA_AES_INT_ENB);
-
- cmdq[0] = CMD_DMASETUP << CMDQ_OPCODE_SHIFT;
- cmdq[1] = in_addr;
- cmdq[2] = CMD_BLKSTARTENGINE << CMDQ_OPCODE_SHIFT | (nblocks-1);
- cmdq[3] = CMD_DMACOMPLETE << CMDQ_OPCODE_SHIFT;
-
- value = aes_readl(dd, TEGRA_AES_CMDQUE_CONTROL);
- /* access SDRAM through AHB */
- value &= ~TEGRA_AES_CMDQ_CTRL_SRC_STM_SEL_FIELD;
- value &= ~TEGRA_AES_CMDQ_CTRL_DST_STM_SEL_FIELD;
- value |= TEGRA_AES_CMDQ_CTRL_SRC_STM_SEL_FIELD |
- TEGRA_AES_CMDQ_CTRL_DST_STM_SEL_FIELD |
- TEGRA_AES_CMDQ_CTRL_ICMDQEN_FIELD;
- aes_writel(dd, value, TEGRA_AES_CMDQUE_CONTROL);
- dev_dbg(dd->dev, "cmd_q_ctrl=0x%x", value);
-
- value = (0x1 << TEGRA_AES_SECURE_INPUT_ALG_SEL_SHIFT) |
- ((dd->ctx->keylen * 8) <<
- TEGRA_AES_SECURE_INPUT_KEY_LEN_SHIFT) |
- ((u32)upd_iv << TEGRA_AES_SECURE_IV_SELECT_SHIFT);
-
- if (mode & FLAGS_CBC) {
- value |= ((((mode & FLAGS_ENCRYPT) ? 2 : 3)
- << TEGRA_AES_SECURE_XOR_POS_SHIFT) |
- (((mode & FLAGS_ENCRYPT) ? 2 : 3)
- << TEGRA_AES_SECURE_VCTRAM_SEL_SHIFT) |
- ((mode & FLAGS_ENCRYPT) ? 1 : 0)
- << TEGRA_AES_SECURE_CORE_SEL_SHIFT);
- } else if (mode & FLAGS_OFB) {
- value |= ((TEGRA_AES_SECURE_XOR_POS_FIELD) |
- (2 << TEGRA_AES_SECURE_INPUT_SEL_SHIFT) |
- (TEGRA_AES_SECURE_CORE_SEL_FIELD));
- } else if (mode & FLAGS_RNG) {
- value |= (((mode & FLAGS_ENCRYPT) ? 1 : 0)
- << TEGRA_AES_SECURE_CORE_SEL_SHIFT |
- TEGRA_AES_SECURE_RNG_ENB_FIELD);
- } else {
- value |= (((mode & FLAGS_ENCRYPT) ? 1 : 0)
- << TEGRA_AES_SECURE_CORE_SEL_SHIFT);
- }
-
- dev_dbg(dd->dev, "secure_in_sel=0x%x", value);
- aes_writel(dd, value, TEGRA_AES_SECURE_INPUT_SELECT);
-
- aes_writel(dd, out_addr, TEGRA_AES_SECURE_DEST_ADDR);
- reinit_completion(&dd->op_complete);
-
- for (i = 0; i < AES_HW_MAX_ICQ_LENGTH - 1; i++) {
- do {
- value = aes_readl(dd, TEGRA_AES_INTR_STATUS);
- eng_busy = value & TEGRA_AES_ENGINE_BUSY_FIELD;
- icq_empty = value & TEGRA_AES_ICQ_EMPTY_FIELD;
- } while (eng_busy && !icq_empty);
- aes_writel(dd, cmdq[i], TEGRA_AES_ICMDQUE_WR);
- }
-
- ret = wait_for_completion_timeout(&dd->op_complete,
- msecs_to_jiffies(150));
- if (ret == 0) {
- dev_err(dd->dev, "timed out (0x%x)\n",
- aes_readl(dd, TEGRA_AES_INTR_STATUS));
- return -ETIMEDOUT;
- }
-
- aes_writel(dd, cmdq[AES_HW_MAX_ICQ_LENGTH - 1], TEGRA_AES_ICMDQUE_WR);
- return 0;
-}
-
-static void aes_release_key_slot(struct tegra_aes_slot *slot)
-{
- if (slot->slot_num == SSK_SLOT_NUM)
- return;
-
- spin_lock(&list_lock);
- list_add_tail(&slot->node, &dev_list);
- slot = NULL;
- spin_unlock(&list_lock);
-}
-
-static struct tegra_aes_slot *aes_find_key_slot(void)
-{
- struct tegra_aes_slot *slot = NULL;
- struct list_head *new_head;
- int empty;
-
- spin_lock(&list_lock);
- empty = list_empty(&dev_list);
- if (!empty) {
- slot = list_entry(&dev_list, struct tegra_aes_slot, node);
- new_head = dev_list.next;
- list_del(&dev_list);
- dev_list.next = new_head->next;
- dev_list.prev = NULL;
- }
- spin_unlock(&list_lock);
-
- return slot;
-}
-
-static int aes_set_key(struct tegra_aes_dev *dd)
-{
- u32 value, cmdq[2];
- struct tegra_aes_ctx *ctx = dd->ctx;
- int eng_busy, icq_empty, dma_busy;
- bool use_ssk = false;
-
- /* use ssk? */
- if (!dd->ctx->slot) {
- dev_dbg(dd->dev, "using ssk");
- dd->ctx->slot = &ssk;
- use_ssk = true;
- }
-
- /* enable key schedule generation in hardware */
- value = aes_readl(dd, TEGRA_AES_SECURE_CONFIG_EXT);
- value &= ~TEGRA_AES_SECURE_KEY_SCH_DIS_FIELD;
- aes_writel(dd, value, TEGRA_AES_SECURE_CONFIG_EXT);
-
- /* select the key slot */
- value = aes_readl(dd, TEGRA_AES_SECURE_CONFIG);
- value &= ~TEGRA_AES_SECURE_KEY_INDEX_FIELD;
- value |= (ctx->slot->slot_num << TEGRA_AES_SECURE_KEY_INDEX_SHIFT);
- aes_writel(dd, value, TEGRA_AES_SECURE_CONFIG);
-
- if (use_ssk)
- return 0;
-
- /* copy the key table from sdram to vram */
- cmdq[0] = CMD_MEMDMAVD << CMDQ_OPCODE_SHIFT |
- MEMDMA_DIR_DTOVRAM << MEMDMA_DIR_SHIFT |
- AES_HW_KEY_TABLE_LENGTH_BYTES / sizeof(u32) <<
- MEMDMA_NUM_WORDS_SHIFT;
- cmdq[1] = (u32)dd->ivkey_phys_base;
-
- aes_writel(dd, cmdq[0], TEGRA_AES_ICMDQUE_WR);
- aes_writel(dd, cmdq[1], TEGRA_AES_ICMDQUE_WR);
-
- do {
- value = aes_readl(dd, TEGRA_AES_INTR_STATUS);
- eng_busy = value & TEGRA_AES_ENGINE_BUSY_FIELD;
- icq_empty = value & TEGRA_AES_ICQ_EMPTY_FIELD;
- dma_busy = value & TEGRA_AES_DMA_BUSY_FIELD;
- } while (eng_busy && !icq_empty && dma_busy);
-
- /* settable command to get key into internal registers */
- value = CMD_SETTABLE << CMDQ_OPCODE_SHIFT |
- SUBCMD_CRYPTO_TABLE_SEL << CMDQ_TABLESEL_SHIFT |
- SUBCMD_VRAM_SEL << CMDQ_VRAMSEL_SHIFT |
- (SUBCMD_KEY_TABLE_SEL | ctx->slot->slot_num) <<
- CMDQ_KEYTABLEID_SHIFT;
- aes_writel(dd, value, TEGRA_AES_ICMDQUE_WR);
-
- do {
- value = aes_readl(dd, TEGRA_AES_INTR_STATUS);
- eng_busy = value & TEGRA_AES_ENGINE_BUSY_FIELD;
- icq_empty = value & TEGRA_AES_ICQ_EMPTY_FIELD;
- } while (eng_busy && !icq_empty);
-
- return 0;
-}
-
-static int tegra_aes_handle_req(struct tegra_aes_dev *dd)
-{
- struct crypto_async_request *async_req, *backlog;
- struct crypto_ablkcipher *tfm;
- struct tegra_aes_ctx *ctx;
- struct tegra_aes_reqctx *rctx;
- struct ablkcipher_request *req;
- unsigned long flags;
- int dma_max = AES_HW_DMA_BUFFER_SIZE_BYTES;
- int ret = 0, nblocks, total;
- int count = 0;
- dma_addr_t addr_in, addr_out;
- struct scatterlist *in_sg, *out_sg;
-
- if (!dd)
- return -EINVAL;
-
- spin_lock_irqsave(&dd->lock, flags);
- backlog = crypto_get_backlog(&dd->queue);
- async_req = crypto_dequeue_request(&dd->queue);
- if (!async_req)
- clear_bit(FLAGS_BUSY, &dd->flags);
- spin_unlock_irqrestore(&dd->lock, flags);
-
- if (!async_req)
- return -ENODATA;
-
- if (backlog)
- backlog->complete(backlog, -EINPROGRESS);
-
- req = ablkcipher_request_cast(async_req);
-
- dev_dbg(dd->dev, "%s: get new req\n", __func__);
-
- if (!req->src || !req->dst)
- return -EINVAL;
-
- /* take mutex to access the aes hw */
- mutex_lock(&aes_lock);
-
- /* assign new request to device */
- dd->req = req;
- dd->total = req->nbytes;
- dd->in_offset = 0;
- dd->in_sg = req->src;
- dd->out_offset = 0;
- dd->out_sg = req->dst;
-
- in_sg = dd->in_sg;
- out_sg = dd->out_sg;
-
- total = dd->total;
-
- tfm = crypto_ablkcipher_reqtfm(req);
- rctx = ablkcipher_request_ctx(req);
- ctx = crypto_ablkcipher_ctx(tfm);
- rctx->mode &= FLAGS_MODE_MASK;
- dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode;
-
- dd->iv = (u8 *)req->info;
- dd->ivlen = crypto_ablkcipher_ivsize(tfm);
-
- /* assign new context to device */
- ctx->dd = dd;
- dd->ctx = ctx;
-
- if (ctx->flags & FLAGS_NEW_KEY) {
- /* copy the key */
- memcpy(dd->ivkey_base, ctx->key, ctx->keylen);
- memset(dd->ivkey_base + ctx->keylen, 0, AES_HW_KEY_TABLE_LENGTH_BYTES - ctx->keylen);
- aes_set_key(dd);
- ctx->flags &= ~FLAGS_NEW_KEY;
- }
-
- if (((dd->flags & FLAGS_CBC) || (dd->flags & FLAGS_OFB)) && dd->iv) {
- /* set iv to the aes hw slot
- * Hw generates updated iv only after iv is set in slot.
- * So key and iv is passed asynchronously.
- */
- memcpy(dd->buf_in, dd->iv, dd->ivlen);
-
- ret = aes_start_crypt(dd, (u32)dd->dma_buf_in,
- dd->dma_buf_out, 1, FLAGS_CBC, false);
- if (ret < 0) {
- dev_err(dd->dev, "aes_start_crypt fail(%d)\n", ret);
- goto out;
- }
- }
-
- while (total) {
- dev_dbg(dd->dev, "remain: %d\n", total);
- ret = dma_map_sg(dd->dev, in_sg, 1, DMA_TO_DEVICE);
- if (!ret) {
- dev_err(dd->dev, "dma_map_sg() error\n");
- goto out;
- }
-
- ret = dma_map_sg(dd->dev, out_sg, 1, DMA_FROM_DEVICE);
- if (!ret) {
- dev_err(dd->dev, "dma_map_sg() error\n");
- dma_unmap_sg(dd->dev, dd->in_sg,
- 1, DMA_TO_DEVICE);
- goto out;
- }
-
- addr_in = sg_dma_address(in_sg);
- addr_out = sg_dma_address(out_sg);
- dd->flags |= FLAGS_FAST;
- count = min_t(int, sg_dma_len(in_sg), dma_max);
- WARN_ON(sg_dma_len(in_sg) != sg_dma_len(out_sg));
- nblocks = DIV_ROUND_UP(count, AES_BLOCK_SIZE);
-
- ret = aes_start_crypt(dd, addr_in, addr_out, nblocks,
- dd->flags, true);
-
- dma_unmap_sg(dd->dev, out_sg, 1, DMA_FROM_DEVICE);
- dma_unmap_sg(dd->dev, in_sg, 1, DMA_TO_DEVICE);
-
- if (ret < 0) {
- dev_err(dd->dev, "aes_start_crypt fail(%d)\n", ret);
- goto out;
- }
- dd->flags &= ~FLAGS_FAST;
-
- dev_dbg(dd->dev, "out: copied %d\n", count);
- total -= count;
- in_sg = sg_next(in_sg);
- out_sg = sg_next(out_sg);
- WARN_ON(((total != 0) && (!in_sg || !out_sg)));
- }
-
-out:
- mutex_unlock(&aes_lock);
-
- dd->total = total;
-
- if (dd->req->base.complete)
- dd->req->base.complete(&dd->req->base, ret);
-
- dev_dbg(dd->dev, "%s: exit\n", __func__);
- return ret;
-}
-
-static int tegra_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
- unsigned int keylen)
-{
- struct tegra_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
- struct tegra_aes_dev *dd = aes_dev;
- struct tegra_aes_slot *key_slot;
-
- if ((keylen != AES_KEYSIZE_128) && (keylen != AES_KEYSIZE_192) &&
- (keylen != AES_KEYSIZE_256)) {
- dev_err(dd->dev, "unsupported key size\n");
- crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
- return -EINVAL;
- }
-
- dev_dbg(dd->dev, "keylen: %d\n", keylen);
-
- ctx->dd = dd;
-
- if (key) {
- if (!ctx->slot) {
- key_slot = aes_find_key_slot();
- if (!key_slot) {
- dev_err(dd->dev, "no empty slot\n");
- return -ENOMEM;
- }
-
- ctx->slot = key_slot;
- }
-
- memcpy(ctx->key, key, keylen);
- ctx->keylen = keylen;
- }
-
- ctx->flags |= FLAGS_NEW_KEY;
- dev_dbg(dd->dev, "done\n");
- return 0;
-}
-
-static void aes_workqueue_handler(struct work_struct *work)
-{
- struct tegra_aes_dev *dd = aes_dev;
- int ret;
-
- ret = clk_prepare_enable(dd->aes_clk);
- if (ret)
- BUG_ON("clock enable failed");
-
- /* empty the crypto queue and then return */
- do {
- ret = tegra_aes_handle_req(dd);
- } while (!ret);
-
- clk_disable_unprepare(dd->aes_clk);
-}
-
-static irqreturn_t aes_irq(int irq, void *dev_id)
-{
- struct tegra_aes_dev *dd = (struct tegra_aes_dev *)dev_id;
- u32 value = aes_readl(dd, TEGRA_AES_INTR_STATUS);
- int busy = test_bit(FLAGS_BUSY, &dd->flags);
-
- if (!busy) {
- dev_dbg(dd->dev, "spurious interrupt\n");
- return IRQ_NONE;
- }
-
- dev_dbg(dd->dev, "irq_stat: 0x%x\n", value);
- if (value & TEGRA_AES_INT_ERROR_MASK)
- aes_writel(dd, TEGRA_AES_INT_ERROR_MASK, TEGRA_AES_INTR_STATUS);
-
- if (!(value & TEGRA_AES_ENGINE_BUSY_FIELD))
- complete(&dd->op_complete);
- else
- return IRQ_NONE;
-
- return IRQ_HANDLED;
-}
-
-static int tegra_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
-{
- struct tegra_aes_reqctx *rctx = ablkcipher_request_ctx(req);
- struct tegra_aes_dev *dd = aes_dev;
- unsigned long flags;
- int err = 0;
- int busy;
-
- dev_dbg(dd->dev, "nbytes: %d, enc: %d, cbc: %d, ofb: %d\n",
- req->nbytes, !!(mode & FLAGS_ENCRYPT),
- !!(mode & FLAGS_CBC), !!(mode & FLAGS_OFB));
-
- rctx->mode = mode;
-
- spin_lock_irqsave(&dd->lock, flags);
- err = ablkcipher_enqueue_request(&dd->queue, req);
- busy = test_and_set_bit(FLAGS_BUSY, &dd->flags);
- spin_unlock_irqrestore(&dd->lock, flags);
-
- if (!busy)
- queue_work(aes_wq, &aes_work);
-
- return err;
-}
-
-static int tegra_aes_ecb_encrypt(struct ablkcipher_request *req)
-{
- return tegra_aes_crypt(req, FLAGS_ENCRYPT);
-}
-
-static int tegra_aes_ecb_decrypt(struct ablkcipher_request *req)
-{
- return tegra_aes_crypt(req, 0);
-}
-
-static int tegra_aes_cbc_encrypt(struct ablkcipher_request *req)
-{
- return tegra_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_CBC);
-}
-
-static int tegra_aes_cbc_decrypt(struct ablkcipher_request *req)
-{
- return tegra_aes_crypt(req, FLAGS_CBC);
-}
-
-static int tegra_aes_ofb_encrypt(struct ablkcipher_request *req)
-{
- return tegra_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_OFB);
-}
-
-static int tegra_aes_ofb_decrypt(struct ablkcipher_request *req)
-{
- return tegra_aes_crypt(req, FLAGS_OFB);
-}
-
-static int tegra_aes_get_random(struct crypto_rng *tfm, u8 *rdata,
- unsigned int dlen)
-{
- struct tegra_aes_dev *dd = aes_dev;
- struct tegra_aes_ctx *ctx = &rng_ctx;
- int ret, i;
- u8 *dest = rdata, *dt = dd->dt;
-
- /* take mutex to access the aes hw */
- mutex_lock(&aes_lock);
-
- ret = clk_prepare_enable(dd->aes_clk);
- if (ret) {
- mutex_unlock(&aes_lock);
- return ret;
- }
-
- ctx->dd = dd;
- dd->ctx = ctx;
- dd->flags = FLAGS_ENCRYPT | FLAGS_RNG;
-
- memcpy(dd->buf_in, dt, DEFAULT_RNG_BLK_SZ);
-
- ret = aes_start_crypt(dd, (u32)dd->dma_buf_in,
- (u32)dd->dma_buf_out, 1, dd->flags, true);
- if (ret < 0) {
- dev_err(dd->dev, "aes_start_crypt fail(%d)\n", ret);
- dlen = ret;
- goto out;
- }
- memcpy(dest, dd->buf_out, dlen);
-
- /* update the DT */
- for (i = DEFAULT_RNG_BLK_SZ - 1; i >= 0; i--) {
- dt[i] += 1;
- if (dt[i] != 0)
- break;
- }
-
-out:
- clk_disable_unprepare(dd->aes_clk);
- mutex_unlock(&aes_lock);
-
- dev_dbg(dd->dev, "%s: done\n", __func__);
- return dlen;
-}
-
-static int tegra_aes_rng_reset(struct crypto_rng *tfm, u8 *seed,
- unsigned int slen)
-{
- struct tegra_aes_dev *dd = aes_dev;
- struct tegra_aes_ctx *ctx = &rng_ctx;
- struct tegra_aes_slot *key_slot;
- int ret = 0;
- u8 tmp[16]; /* 16 bytes = 128 bits of entropy */
- u8 *dt;
-
- if (!ctx || !dd) {
- pr_err("ctx=0x%x, dd=0x%x\n",
- (unsigned int)ctx, (unsigned int)dd);
- return -EINVAL;
- }
-
- if (slen < (DEFAULT_RNG_BLK_SZ + AES_KEYSIZE_128)) {
- dev_err(dd->dev, "seed size invalid");
- return -ENOMEM;
- }
-
- /* take mutex to access the aes hw */
- mutex_lock(&aes_lock);
-
- if (!ctx->slot) {
- key_slot = aes_find_key_slot();
- if (!key_slot) {
- dev_err(dd->dev, "no empty slot\n");
- mutex_unlock(&aes_lock);
- return -ENOMEM;
- }
- ctx->slot = key_slot;
- }
-
- ctx->dd = dd;
- dd->ctx = ctx;
- dd->ctr = 0;
-
- ctx->keylen = AES_KEYSIZE_128;
- ctx->flags |= FLAGS_NEW_KEY;
-
- /* copy the key to the key slot */
- memcpy(dd->ivkey_base, seed + DEFAULT_RNG_BLK_SZ, AES_KEYSIZE_128);
- memset(dd->ivkey_base + AES_KEYSIZE_128, 0, AES_HW_KEY_TABLE_LENGTH_BYTES - AES_KEYSIZE_128);
-
- dd->iv = seed;
- dd->ivlen = slen;
-
- dd->flags = FLAGS_ENCRYPT | FLAGS_RNG;
-
- ret = clk_prepare_enable(dd->aes_clk);
- if (ret) {
- mutex_unlock(&aes_lock);
- return ret;
- }
-
- aes_set_key(dd);
-
- /* set seed to the aes hw slot */
- memcpy(dd->buf_in, dd->iv, DEFAULT_RNG_BLK_SZ);
- ret = aes_start_crypt(dd, (u32)dd->dma_buf_in,
- dd->dma_buf_out, 1, FLAGS_CBC, false);
- if (ret < 0) {
- dev_err(dd->dev, "aes_start_crypt fail(%d)\n", ret);
- goto out;
- }
-
- if (dd->ivlen >= (2 * DEFAULT_RNG_BLK_SZ + AES_KEYSIZE_128)) {
- dt = dd->iv + DEFAULT_RNG_BLK_SZ + AES_KEYSIZE_128;
- } else {
- get_random_bytes(tmp, sizeof(tmp));
- dt = tmp;
- }
- memcpy(dd->dt, dt, DEFAULT_RNG_BLK_SZ);
-
-out:
- clk_disable_unprepare(dd->aes_clk);
- mutex_unlock(&aes_lock);
-
- dev_dbg(dd->dev, "%s: done\n", __func__);
- return ret;
-}
-
-static int tegra_aes_cra_init(struct crypto_tfm *tfm)
-{
- tfm->crt_ablkcipher.reqsize = sizeof(struct tegra_aes_reqctx);
-
- return 0;
-}
-
-static void tegra_aes_cra_exit(struct crypto_tfm *tfm)
-{
- struct tegra_aes_ctx *ctx =
- crypto_ablkcipher_ctx((struct crypto_ablkcipher *)tfm);
-
- if (ctx && ctx->slot)
- aes_release_key_slot(ctx->slot);
-}
-
-static struct crypto_alg algs[] = {
- {
- .cra_name = "ecb(aes)",
- .cra_driver_name = "ecb-aes-tegra",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_alignmask = 3,
- .cra_type = &crypto_ablkcipher_type,
- .cra_u.ablkcipher = {
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .setkey = tegra_aes_setkey,
- .encrypt = tegra_aes_ecb_encrypt,
- .decrypt = tegra_aes_ecb_decrypt,
- },
- }, {
- .cra_name = "cbc(aes)",
- .cra_driver_name = "cbc-aes-tegra",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_alignmask = 3,
- .cra_type = &crypto_ablkcipher_type,
- .cra_u.ablkcipher = {
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .ivsize = AES_MIN_KEY_SIZE,
- .setkey = tegra_aes_setkey,
- .encrypt = tegra_aes_cbc_encrypt,
- .decrypt = tegra_aes_cbc_decrypt,
- }
- }, {
- .cra_name = "ofb(aes)",
- .cra_driver_name = "ofb-aes-tegra",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_alignmask = 3,
- .cra_type = &crypto_ablkcipher_type,
- .cra_u.ablkcipher = {
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .ivsize = AES_MIN_KEY_SIZE,
- .setkey = tegra_aes_setkey,
- .encrypt = tegra_aes_ofb_encrypt,
- .decrypt = tegra_aes_ofb_decrypt,
- }
- }, {
- .cra_name = "ansi_cprng",
- .cra_driver_name = "rng-aes-tegra",
- .cra_flags = CRYPTO_ALG_TYPE_RNG,
- .cra_ctxsize = sizeof(struct tegra_aes_ctx),
- .cra_type = &crypto_rng_type,
- .cra_u.rng = {
- .rng_make_random = tegra_aes_get_random,
- .rng_reset = tegra_aes_rng_reset,
- .seedsize = AES_KEYSIZE_128 + (2 * DEFAULT_RNG_BLK_SZ),
- }
- }
-};
-
-static int tegra_aes_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct tegra_aes_dev *dd;
- struct resource *res;
- int err = -ENOMEM, i = 0, j;
-
- dd = devm_kzalloc(dev, sizeof(struct tegra_aes_dev), GFP_KERNEL);
- if (dd == NULL) {
- dev_err(dev, "unable to alloc data struct.\n");
- return err;
- }
-
- dd->dev = dev;
- platform_set_drvdata(pdev, dd);
-
- dd->slots = devm_kzalloc(dev, sizeof(struct tegra_aes_slot) *
- AES_NR_KEYSLOTS, GFP_KERNEL);
- if (dd->slots == NULL) {
- dev_err(dev, "unable to alloc slot struct.\n");
- goto out;
- }
-
- spin_lock_init(&dd->lock);
- crypto_init_queue(&dd->queue, TEGRA_AES_QUEUE_LENGTH);
-
- /* Get the module base address */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "invalid resource type: base\n");
- err = -ENODEV;
- goto out;
- }
-
- if (!devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res),
- dev_name(&pdev->dev))) {
- dev_err(&pdev->dev, "Couldn't request MEM resource\n");
- return -ENODEV;
- }
-
- dd->io_base = devm_ioremap(dev, res->start, resource_size(res));
- if (!dd->io_base) {
- dev_err(dev, "can't ioremap register space\n");
- err = -ENOMEM;
- goto out;
- }
-
- /* Initialize the vde clock */
- dd->aes_clk = devm_clk_get(dev, "vde");
- if (IS_ERR(dd->aes_clk)) {
- dev_err(dev, "iclock intialization failed.\n");
- err = -ENODEV;
- goto out;
- }
-
- err = clk_set_rate(dd->aes_clk, ULONG_MAX);
- if (err) {
- dev_err(dd->dev, "iclk set_rate fail(%d)\n", err);
- goto out;
- }
-
- /*
- * the foll contiguous memory is allocated as follows -
- * - hardware key table
- * - key schedule
- */
- dd->ivkey_base = dma_alloc_coherent(dev, AES_HW_KEY_TABLE_LENGTH_BYTES,
- &dd->ivkey_phys_base,
- GFP_KERNEL);
- if (!dd->ivkey_base) {
- dev_err(dev, "can not allocate iv/key buffer\n");
- err = -ENOMEM;
- goto out;
- }
-
- dd->buf_in = dma_alloc_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES,
- &dd->dma_buf_in, GFP_KERNEL);
- if (!dd->buf_in) {
- dev_err(dev, "can not allocate dma-in buffer\n");
- err = -ENOMEM;
- goto out;
- }
-
- dd->buf_out = dma_alloc_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES,
- &dd->dma_buf_out, GFP_KERNEL);
- if (!dd->buf_out) {
- dev_err(dev, "can not allocate dma-out buffer\n");
- err = -ENOMEM;
- goto out;
- }
-
- init_completion(&dd->op_complete);
- aes_wq = alloc_workqueue("tegra_aes_wq", WQ_HIGHPRI | WQ_UNBOUND, 1);
- if (!aes_wq) {
- dev_err(dev, "alloc_workqueue failed\n");
- err = -ENOMEM;
- goto out;
- }
-
- /* get the irq */
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res) {
- dev_err(dev, "invalid resource type: base\n");
- err = -ENODEV;
- goto out;
- }
- dd->irq = res->start;
-
- err = devm_request_irq(dev, dd->irq, aes_irq, IRQF_TRIGGER_HIGH |
- IRQF_SHARED, "tegra-aes", dd);
- if (err) {
- dev_err(dev, "request_irq failed\n");
- goto out;
- }
-
- mutex_init(&aes_lock);
- INIT_LIST_HEAD(&dev_list);
-
- spin_lock_init(&list_lock);
- spin_lock(&list_lock);
- for (i = 0; i < AES_NR_KEYSLOTS; i++) {
- if (i == SSK_SLOT_NUM)
- continue;
- dd->slots[i].slot_num = i;
- INIT_LIST_HEAD(&dd->slots[i].node);
- list_add_tail(&dd->slots[i].node, &dev_list);
- }
- spin_unlock(&list_lock);
-
- aes_dev = dd;
- for (i = 0; i < ARRAY_SIZE(algs); i++) {
- algs[i].cra_priority = 300;
- algs[i].cra_ctxsize = sizeof(struct tegra_aes_ctx);
- algs[i].cra_module = THIS_MODULE;
- algs[i].cra_init = tegra_aes_cra_init;
- algs[i].cra_exit = tegra_aes_cra_exit;
-
- err = crypto_register_alg(&algs[i]);
- if (err)
- goto out;
- }
-
- dev_info(dev, "registered");
- return 0;
-
-out:
- for (j = 0; j < i; j++)
- crypto_unregister_alg(&algs[j]);
- if (dd->ivkey_base)
- dma_free_coherent(dev, AES_HW_KEY_TABLE_LENGTH_BYTES,
- dd->ivkey_base, dd->ivkey_phys_base);
- if (dd->buf_in)
- dma_free_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES,
- dd->buf_in, dd->dma_buf_in);
- if (dd->buf_out)
- dma_free_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES,
- dd->buf_out, dd->dma_buf_out);
- if (aes_wq)
- destroy_workqueue(aes_wq);
- spin_lock(&list_lock);
- list_del(&dev_list);
- spin_unlock(&list_lock);
-
- aes_dev = NULL;
-
- dev_err(dev, "%s: initialization failed.\n", __func__);
- return err;
-}
-
-static int tegra_aes_remove(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct tegra_aes_dev *dd = platform_get_drvdata(pdev);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(algs); i++)
- crypto_unregister_alg(&algs[i]);
-
- cancel_work_sync(&aes_work);
- destroy_workqueue(aes_wq);
- spin_lock(&list_lock);
- list_del(&dev_list);
- spin_unlock(&list_lock);
-
- dma_free_coherent(dev, AES_HW_KEY_TABLE_LENGTH_BYTES,
- dd->ivkey_base, dd->ivkey_phys_base);
- dma_free_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES,
- dd->buf_in, dd->dma_buf_in);
- dma_free_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES,
- dd->buf_out, dd->dma_buf_out);
- aes_dev = NULL;
-
- return 0;
-}
-
-static struct of_device_id tegra_aes_of_match[] = {
- { .compatible = "nvidia,tegra20-aes", },
- { .compatible = "nvidia,tegra30-aes", },
- { },
-};
-
-static struct platform_driver tegra_aes_driver = {
- .probe = tegra_aes_probe,
- .remove = tegra_aes_remove,
- .driver = {
- .name = "tegra-aes",
- .owner = THIS_MODULE,
- .of_match_table = tegra_aes_of_match,
- },
-};
-
-module_platform_driver(tegra_aes_driver);
-
-MODULE_DESCRIPTION("Tegra AES/OFB/CPRNG hw acceleration support.");
-MODULE_AUTHOR("NVIDIA Corporation");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/crypto/tegra-aes.h b/drivers/crypto/tegra-aes.h
deleted file mode 100644
index 6006333a8934..000000000000
--- a/drivers/crypto/tegra-aes.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2010, NVIDIA 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
- * 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.
- */
-
-#ifndef __CRYPTODEV_TEGRA_AES_H
-#define __CRYPTODEV_TEGRA_AES_H
-
-#define TEGRA_AES_ICMDQUE_WR 0x1000
-#define TEGRA_AES_CMDQUE_CONTROL 0x1008
-#define TEGRA_AES_INTR_STATUS 0x1018
-#define TEGRA_AES_INT_ENB 0x1040
-#define TEGRA_AES_CONFIG 0x1044
-#define TEGRA_AES_IRAM_ACCESS_CFG 0x10A0
-#define TEGRA_AES_SECURE_DEST_ADDR 0x1100
-#define TEGRA_AES_SECURE_INPUT_SELECT 0x1104
-#define TEGRA_AES_SECURE_CONFIG 0x1108
-#define TEGRA_AES_SECURE_CONFIG_EXT 0x110C
-#define TEGRA_AES_SECURE_SECURITY 0x1110
-#define TEGRA_AES_SECURE_HASH_RESULT0 0x1120
-#define TEGRA_AES_SECURE_HASH_RESULT1 0x1124
-#define TEGRA_AES_SECURE_HASH_RESULT2 0x1128
-#define TEGRA_AES_SECURE_HASH_RESULT3 0x112C
-#define TEGRA_AES_SECURE_SEC_SEL0 0x1140
-#define TEGRA_AES_SECURE_SEC_SEL1 0x1144
-#define TEGRA_AES_SECURE_SEC_SEL2 0x1148
-#define TEGRA_AES_SECURE_SEC_SEL3 0x114C
-#define TEGRA_AES_SECURE_SEC_SEL4 0x1150
-#define TEGRA_AES_SECURE_SEC_SEL5 0x1154
-#define TEGRA_AES_SECURE_SEC_SEL6 0x1158
-#define TEGRA_AES_SECURE_SEC_SEL7 0x115C
-
-/* interrupt status reg masks and shifts */
-#define TEGRA_AES_ENGINE_BUSY_FIELD BIT(0)
-#define TEGRA_AES_ICQ_EMPTY_FIELD BIT(3)
-#define TEGRA_AES_DMA_BUSY_FIELD BIT(23)
-
-/* secure select reg masks and shifts */
-#define TEGRA_AES_SECURE_SEL0_KEYREAD_ENB0_FIELD BIT(0)
-
-/* secure config ext masks and shifts */
-#define TEGRA_AES_SECURE_KEY_SCH_DIS_FIELD BIT(15)
-
-/* secure config masks and shifts */
-#define TEGRA_AES_SECURE_KEY_INDEX_SHIFT 20
-#define TEGRA_AES_SECURE_KEY_INDEX_FIELD (0x1F << TEGRA_AES_SECURE_KEY_INDEX_SHIFT)
-#define TEGRA_AES_SECURE_BLOCK_CNT_SHIFT 0
-#define TEGRA_AES_SECURE_BLOCK_CNT_FIELD (0xFFFFF << TEGRA_AES_SECURE_BLOCK_CNT_SHIFT)
-
-/* stream interface select masks and shifts */
-#define TEGRA_AES_CMDQ_CTRL_UCMDQEN_FIELD BIT(0)
-#define TEGRA_AES_CMDQ_CTRL_ICMDQEN_FIELD BIT(1)
-#define TEGRA_AES_CMDQ_CTRL_SRC_STM_SEL_FIELD BIT(4)
-#define TEGRA_AES_CMDQ_CTRL_DST_STM_SEL_FIELD BIT(5)
-
-/* config register masks and shifts */
-#define TEGRA_AES_CONFIG_ENDIAN_ENB_FIELD BIT(10)
-#define TEGRA_AES_CONFIG_MODE_SEL_SHIFT 0
-#define TEGRA_AES_CONFIG_MODE_SEL_FIELD (0x1F << TEGRA_AES_CONFIG_MODE_SEL_SHIFT)
-
-/* extended config */
-#define TEGRA_AES_SECURE_OFFSET_CNT_SHIFT 24
-#define TEGRA_AES_SECURE_OFFSET_CNT_FIELD (0xFF << TEGRA_AES_SECURE_OFFSET_CNT_SHIFT)
-#define TEGRA_AES_SECURE_KEYSCHED_GEN_FIELD BIT(15)
-
-/* init vector select */
-#define TEGRA_AES_SECURE_IV_SELECT_SHIFT 10
-#define TEGRA_AES_SECURE_IV_SELECT_FIELD BIT(10)
-
-/* secure engine input */
-#define TEGRA_AES_SECURE_INPUT_ALG_SEL_SHIFT 28
-#define TEGRA_AES_SECURE_INPUT_ALG_SEL_FIELD (0xF << TEGRA_AES_SECURE_INPUT_ALG_SEL_SHIFT)
-#define TEGRA_AES_SECURE_INPUT_KEY_LEN_SHIFT 16
-#define TEGRA_AES_SECURE_INPUT_KEY_LEN_FIELD (0xFFF << TEGRA_AES_SECURE_INPUT_KEY_LEN_SHIFT)
-#define TEGRA_AES_SECURE_RNG_ENB_FIELD BIT(11)
-#define TEGRA_AES_SECURE_CORE_SEL_SHIFT 9
-#define TEGRA_AES_SECURE_CORE_SEL_FIELD BIT(9)
-#define TEGRA_AES_SECURE_VCTRAM_SEL_SHIFT 7
-#define TEGRA_AES_SECURE_VCTRAM_SEL_FIELD (0x3 << TEGRA_AES_SECURE_VCTRAM_SEL_SHIFT)
-#define TEGRA_AES_SECURE_INPUT_SEL_SHIFT 5
-#define TEGRA_AES_SECURE_INPUT_SEL_FIELD (0x3 << TEGRA_AES_SECURE_INPUT_SEL_SHIFT)
-#define TEGRA_AES_SECURE_XOR_POS_SHIFT 3
-#define TEGRA_AES_SECURE_XOR_POS_FIELD (0x3 << TEGRA_AES_SECURE_XOR_POS_SHIFT)
-#define TEGRA_AES_SECURE_HASH_ENB_FIELD BIT(2)
-#define TEGRA_AES_SECURE_ON_THE_FLY_FIELD BIT(0)
-
-/* interrupt error mask */
-#define TEGRA_AES_INT_ERROR_MASK 0xFFF000
-
-#endif
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index a0b2f7e0eedb..2042ec3656ba 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -91,26 +91,35 @@ static int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq)
*/
static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
{
- int lev, prev_lev;
+ int lev, prev_lev, ret = 0;
unsigned long cur_time;
- lev = devfreq_get_freq_level(devfreq, freq);
- if (lev < 0)
- return lev;
-
cur_time = jiffies;
- devfreq->time_in_state[lev] +=
+
+ prev_lev = devfreq_get_freq_level(devfreq, devfreq->previous_freq);
+ if (prev_lev < 0) {
+ ret = prev_lev;
+ goto out;
+ }
+
+ devfreq->time_in_state[prev_lev] +=
cur_time - devfreq->last_stat_updated;
- if (freq != devfreq->previous_freq) {
- prev_lev = devfreq_get_freq_level(devfreq,
- devfreq->previous_freq);
+
+ lev = devfreq_get_freq_level(devfreq, freq);
+ if (lev < 0) {
+ ret = lev;
+ goto out;
+ }
+
+ if (lev != prev_lev) {
devfreq->trans_table[(prev_lev *
devfreq->profile->max_state) + lev]++;
devfreq->total_trans++;
}
- devfreq->last_stat_updated = cur_time;
- return 0;
+out:
+ devfreq->last_stat_updated = cur_time;
+ return ret;
}
/**
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 9bed1a2a67a1..605b016bcea4 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -346,6 +346,7 @@ config MOXART_DMA
tristate "MOXART DMA support"
depends on ARCH_MOXART
select DMA_ENGINE
+ select DMA_OF
select DMA_VIRTUAL_CHANNELS
help
Enable support for the MOXA ART SoC DMA controller.
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 4e7918339b12..19041cefabb1 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -449,6 +449,7 @@ static const struct of_device_id sdma_dt_ids[] = {
{ .compatible = "fsl,imx51-sdma", .data = &sdma_imx51, },
{ .compatible = "fsl,imx35-sdma", .data = &sdma_imx35, },
{ .compatible = "fsl,imx31-sdma", .data = &sdma_imx31, },
+ { .compatible = "fsl,imx25-sdma", .data = &sdma_imx25, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sdma_dt_ids);
diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c
index 87529181efcc..4e3549a16132 100644
--- a/drivers/dma/ioat/dma.c
+++ b/drivers/dma/ioat/dma.c
@@ -77,7 +77,8 @@ static irqreturn_t ioat_dma_do_interrupt(int irq, void *data)
attnstatus = readl(instance->reg_base + IOAT_ATTNSTATUS_OFFSET);
for_each_set_bit(bit, &attnstatus, BITS_PER_LONG) {
chan = ioat_chan_by_index(instance, bit);
- tasklet_schedule(&chan->cleanup_task);
+ if (test_bit(IOAT_RUN, &chan->state))
+ tasklet_schedule(&chan->cleanup_task);
}
writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET);
@@ -93,7 +94,8 @@ static irqreturn_t ioat_dma_do_interrupt_msix(int irq, void *data)
{
struct ioat_chan_common *chan = data;
- tasklet_schedule(&chan->cleanup_task);
+ if (test_bit(IOAT_RUN, &chan->state))
+ tasklet_schedule(&chan->cleanup_task);
return IRQ_HANDLED;
}
@@ -116,7 +118,6 @@ void ioat_init_channel(struct ioatdma_device *device, struct ioat_chan_common *c
chan->timer.function = device->timer_fn;
chan->timer.data = data;
tasklet_init(&chan->cleanup_task, device->cleanup_fn, data);
- tasklet_disable(&chan->cleanup_task);
}
/**
@@ -354,13 +355,49 @@ static int ioat1_dma_alloc_chan_resources(struct dma_chan *c)
writel(((u64) chan->completion_dma) >> 32,
chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH);
- tasklet_enable(&chan->cleanup_task);
+ set_bit(IOAT_RUN, &chan->state);
ioat1_dma_start_null_desc(ioat); /* give chain to dma device */
dev_dbg(to_dev(chan), "%s: allocated %d descriptors\n",
__func__, ioat->desccount);
return ioat->desccount;
}
+void ioat_stop(struct ioat_chan_common *chan)
+{
+ struct ioatdma_device *device = chan->device;
+ struct pci_dev *pdev = device->pdev;
+ int chan_id = chan_num(chan);
+ struct msix_entry *msix;
+
+ /* 1/ stop irq from firing tasklets
+ * 2/ stop the tasklet from re-arming irqs
+ */
+ clear_bit(IOAT_RUN, &chan->state);
+
+ /* flush inflight interrupts */
+ switch (device->irq_mode) {
+ case IOAT_MSIX:
+ msix = &device->msix_entries[chan_id];
+ synchronize_irq(msix->vector);
+ break;
+ case IOAT_MSI:
+ case IOAT_INTX:
+ synchronize_irq(pdev->irq);
+ break;
+ default:
+ break;
+ }
+
+ /* flush inflight timers */
+ del_timer_sync(&chan->timer);
+
+ /* flush inflight tasklet runs */
+ tasklet_kill(&chan->cleanup_task);
+
+ /* final cleanup now that everything is quiesced and can't re-arm */
+ device->cleanup_fn((unsigned long) &chan->common);
+}
+
/**
* ioat1_dma_free_chan_resources - release all the descriptors
* @chan: the channel to be cleaned
@@ -379,9 +416,7 @@ static void ioat1_dma_free_chan_resources(struct dma_chan *c)
if (ioat->desccount == 0)
return;
- tasklet_disable(&chan->cleanup_task);
- del_timer_sync(&chan->timer);
- ioat1_cleanup(ioat);
+ ioat_stop(chan);
/* Delay 100ms after reset to allow internal DMA logic to quiesce
* before removing DMA descriptor resources.
@@ -526,8 +561,11 @@ ioat1_dma_prep_memcpy(struct dma_chan *c, dma_addr_t dma_dest,
static void ioat1_cleanup_event(unsigned long data)
{
struct ioat_dma_chan *ioat = to_ioat_chan((void *) data);
+ struct ioat_chan_common *chan = &ioat->base;
ioat1_cleanup(ioat);
+ if (!test_bit(IOAT_RUN, &chan->state))
+ return;
writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
}
diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h
index 11fb877ddca9..e982f00a9843 100644
--- a/drivers/dma/ioat/dma.h
+++ b/drivers/dma/ioat/dma.h
@@ -356,6 +356,7 @@ bool ioat_cleanup_preamble(struct ioat_chan_common *chan,
void ioat_kobject_add(struct ioatdma_device *device, struct kobj_type *type);
void ioat_kobject_del(struct ioatdma_device *device);
int ioat_dma_setup_interrupts(struct ioatdma_device *device);
+void ioat_stop(struct ioat_chan_common *chan);
extern const struct sysfs_ops ioat_sysfs_ops;
extern struct ioat_sysfs_entry ioat_version_attr;
extern struct ioat_sysfs_entry ioat_cap_attr;
diff --git a/drivers/dma/ioat/dma_v2.c b/drivers/dma/ioat/dma_v2.c
index 5d3affe7e976..8d1058085eeb 100644
--- a/drivers/dma/ioat/dma_v2.c
+++ b/drivers/dma/ioat/dma_v2.c
@@ -190,8 +190,11 @@ static void ioat2_cleanup(struct ioat2_dma_chan *ioat)
void ioat2_cleanup_event(unsigned long data)
{
struct ioat2_dma_chan *ioat = to_ioat2_chan((void *) data);
+ struct ioat_chan_common *chan = &ioat->base;
ioat2_cleanup(ioat);
+ if (!test_bit(IOAT_RUN, &chan->state))
+ return;
writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
}
@@ -553,10 +556,10 @@ int ioat2_alloc_chan_resources(struct dma_chan *c)
ioat->issued = 0;
ioat->tail = 0;
ioat->alloc_order = order;
+ set_bit(IOAT_RUN, &chan->state);
spin_unlock_bh(&ioat->prep_lock);
spin_unlock_bh(&chan->cleanup_lock);
- tasklet_enable(&chan->cleanup_task);
ioat2_start_null_desc(ioat);
/* check that we got off the ground */
@@ -566,7 +569,6 @@ int ioat2_alloc_chan_resources(struct dma_chan *c)
} while (i++ < 20 && !is_ioat_active(status) && !is_ioat_idle(status));
if (is_ioat_active(status) || is_ioat_idle(status)) {
- set_bit(IOAT_RUN, &chan->state);
return 1 << ioat->alloc_order;
} else {
u32 chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET);
@@ -809,11 +811,8 @@ void ioat2_free_chan_resources(struct dma_chan *c)
if (!ioat->ring)
return;
- tasklet_disable(&chan->cleanup_task);
- del_timer_sync(&chan->timer);
- device->cleanup_fn((unsigned long) c);
+ ioat_stop(chan);
device->reset_hw(chan);
- clear_bit(IOAT_RUN, &chan->state);
spin_lock_bh(&chan->cleanup_lock);
spin_lock_bh(&ioat->prep_lock);
diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c
index 820817e97e62..b9b38a1cf92f 100644
--- a/drivers/dma/ioat/dma_v3.c
+++ b/drivers/dma/ioat/dma_v3.c
@@ -464,8 +464,11 @@ static void ioat3_cleanup(struct ioat2_dma_chan *ioat)
static void ioat3_cleanup_event(unsigned long data)
{
struct ioat2_dma_chan *ioat = to_ioat2_chan((void *) data);
+ struct ioat_chan_common *chan = &ioat->base;
ioat3_cleanup(ioat);
+ if (!test_bit(IOAT_RUN, &chan->state))
+ return;
writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
}
diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index 53fb0c8365b0..766b68ed505c 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -497,8 +497,8 @@ mv_xor_tx_submit(struct dma_async_tx_descriptor *tx)
if (!mv_can_chain(grp_start))
goto submit_done;
- dev_dbg(mv_chan_to_devp(mv_chan), "Append to last desc %x\n",
- old_chain_tail->async_tx.phys);
+ dev_dbg(mv_chan_to_devp(mv_chan), "Append to last desc %pa\n",
+ &old_chain_tail->async_tx.phys);
/* fix up the hardware chain */
mv_desc_set_next_desc(old_chain_tail, grp_start->async_tx.phys);
@@ -527,7 +527,8 @@ submit_done:
/* returns the number of allocated descriptors */
static int mv_xor_alloc_chan_resources(struct dma_chan *chan)
{
- char *hw_desc;
+ void *virt_desc;
+ dma_addr_t dma_desc;
int idx;
struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan);
struct mv_xor_desc_slot *slot = NULL;
@@ -542,17 +543,16 @@ static int mv_xor_alloc_chan_resources(struct dma_chan *chan)
" %d descriptor slots", idx);
break;
}
- hw_desc = (char *) mv_chan->dma_desc_pool_virt;
- slot->hw_desc = (void *) &hw_desc[idx * MV_XOR_SLOT_SIZE];
+ virt_desc = mv_chan->dma_desc_pool_virt;
+ slot->hw_desc = virt_desc + idx * MV_XOR_SLOT_SIZE;
dma_async_tx_descriptor_init(&slot->async_tx, chan);
slot->async_tx.tx_submit = mv_xor_tx_submit;
INIT_LIST_HEAD(&slot->chain_node);
INIT_LIST_HEAD(&slot->slot_node);
INIT_LIST_HEAD(&slot->tx_list);
- hw_desc = (char *) mv_chan->dma_desc_pool;
- slot->async_tx.phys =
- (dma_addr_t) &hw_desc[idx * MV_XOR_SLOT_SIZE];
+ dma_desc = mv_chan->dma_desc_pool;
+ slot->async_tx.phys = dma_desc + idx * MV_XOR_SLOT_SIZE;
slot->idx = idx++;
spin_lock_bh(&mv_chan->lock);
@@ -582,8 +582,8 @@ mv_xor_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
int slot_cnt;
dev_dbg(mv_chan_to_devp(mv_chan),
- "%s dest: %x src %x len: %u flags: %ld\n",
- __func__, dest, src, len, flags);
+ "%s dest: %pad src %pad len: %u flags: %ld\n",
+ __func__, &dest, &src, len, flags);
if (unlikely(len < MV_XOR_MIN_BYTE_COUNT))
return NULL;
@@ -626,8 +626,8 @@ mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
BUG_ON(len > MV_XOR_MAX_BYTE_COUNT);
dev_dbg(mv_chan_to_devp(mv_chan),
- "%s src_cnt: %d len: dest %x %u flags: %ld\n",
- __func__, src_cnt, len, dest, flags);
+ "%s src_cnt: %d len: %u dest %pad flags: %ld\n",
+ __func__, src_cnt, len, &dest, flags);
spin_lock_bh(&mv_chan->lock);
slot_cnt = mv_chan_xor_slot_count(len, src_cnt);
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index 00a2de957b23..bf18c786ed40 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -1641,6 +1641,7 @@ static void dma_tasklet(unsigned long data)
struct d40_chan *d40c = (struct d40_chan *) data;
struct d40_desc *d40d;
unsigned long flags;
+ bool callback_active;
dma_async_tx_callback callback;
void *callback_param;
@@ -1668,6 +1669,7 @@ static void dma_tasklet(unsigned long data)
}
/* Callback to client */
+ callback_active = !!(d40d->txd.flags & DMA_PREP_INTERRUPT);
callback = d40d->txd.callback;
callback_param = d40d->txd.callback_param;
@@ -1690,7 +1692,7 @@ static void dma_tasklet(unsigned long data)
spin_unlock_irqrestore(&d40c->lock, flags);
- if (callback && (d40d->txd.flags & DMA_PREP_INTERRUPT))
+ if (callback_active && callback)
callback(callback_param);
return;
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 98e14ee4833c..f8bf00010d45 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -1239,9 +1239,17 @@ static u8 f15_m30h_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
if (num_dcts_intlv == 2) {
select = (sys_addr >> 8) & 0x3;
channel = select ? 0x3 : 0;
- } else if (num_dcts_intlv == 4)
- channel = (sys_addr >> 8) & 0x7;
-
+ } else if (num_dcts_intlv == 4) {
+ u8 intlv_addr = dct_sel_interleave_addr(pvt);
+ switch (intlv_addr) {
+ case 0x4:
+ channel = (sys_addr >> 8) & 0x3;
+ break;
+ case 0x5:
+ channel = (sys_addr >> 9) & 0x3;
+ break;
+ }
+ }
return channel;
}
@@ -1799,6 +1807,17 @@ static struct amd64_family_type family_types[] = {
.read_dct_pci_cfg = f10_read_dct_pci_cfg,
}
},
+ [F16_M30H_CPUS] = {
+ .ctl_name = "F16h_M30h",
+ .f1_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F1,
+ .f3_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F3,
+ .ops = {
+ .early_channel_count = f1x_early_channel_count,
+ .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
+ .dbam_to_cs = f16_dbam_to_chip_select,
+ .read_dct_pci_cfg = f10_read_dct_pci_cfg,
+ }
+ },
};
/*
@@ -2578,6 +2597,11 @@ static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt)
break;
case 0x16:
+ if (pvt->model == 0x30) {
+ fam_type = &family_types[F16_M30H_CPUS];
+ pvt->ops = &family_types[F16_M30H_CPUS].ops;
+ break;
+ }
fam_type = &family_types[F16_CPUS];
pvt->ops = &family_types[F16_CPUS].ops;
break;
@@ -2830,6 +2854,14 @@ static const struct pci_device_id amd64_pci_table[] = {
.class = 0,
.class_mask = 0,
},
+ {
+ .vendor = PCI_VENDOR_ID_AMD,
+ .device = PCI_DEVICE_ID_AMD_16H_M30H_NB_F2,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .class = 0,
+ .class_mask = 0,
+ },
{0, }
};
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index 6dc1fcc25afb..d903e0c21144 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -168,6 +168,8 @@
#define PCI_DEVICE_ID_AMD_15H_NB_F2 0x1602
#define PCI_DEVICE_ID_AMD_16H_NB_F1 0x1531
#define PCI_DEVICE_ID_AMD_16H_NB_F2 0x1532
+#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F1 0x1581
+#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F2 0x1582
/*
* Function 1 - Address Map
@@ -300,6 +302,7 @@ enum amd_families {
F15_CPUS,
F15_M30H_CPUS,
F16_CPUS,
+ F16_M30H_CPUS,
NUM_FAMILIES,
};
diff --git a/drivers/edac/amd8111_edac.c b/drivers/edac/amd8111_edac.c
index ddd890052ce2..2b63f7c2d6d2 100644
--- a/drivers/edac/amd8111_edac.c
+++ b/drivers/edac/amd8111_edac.c
@@ -350,6 +350,7 @@ static int amd8111_dev_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
struct amd8111_dev_info *dev_info = &amd8111_devices[id->driver_data];
+ int ret = -ENODEV;
dev_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,
dev_info->err_dev, NULL);
@@ -359,16 +360,15 @@ static int amd8111_dev_probe(struct pci_dev *dev,
"vendor %x, device %x, name %s\n",
PCI_VENDOR_ID_AMD, dev_info->err_dev,
dev_info->ctl_name);
- return -ENODEV;
+ goto err;
}
if (pci_enable_device(dev_info->dev)) {
- pci_dev_put(dev_info->dev);
printk(KERN_ERR "failed to enable:"
"vendor %x, device %x, name %s\n",
PCI_VENDOR_ID_AMD, dev_info->err_dev,
dev_info->ctl_name);
- return -ENODEV;
+ goto err_dev_put;
}
/*
@@ -381,8 +381,10 @@ static int amd8111_dev_probe(struct pci_dev *dev,
edac_device_alloc_ctl_info(0, dev_info->ctl_name, 1,
NULL, 0, 0,
NULL, 0, dev_info->edac_idx);
- if (!dev_info->edac_dev)
- return -ENOMEM;
+ if (!dev_info->edac_dev) {
+ ret = -ENOMEM;
+ goto err_dev_put;
+ }
dev_info->edac_dev->pvt_info = dev_info;
dev_info->edac_dev->dev = &dev_info->dev->dev;
@@ -399,8 +401,7 @@ static int amd8111_dev_probe(struct pci_dev *dev,
if (edac_device_add_device(dev_info->edac_dev) > 0) {
printk(KERN_ERR "failed to add edac_dev for %s\n",
dev_info->ctl_name);
- edac_device_free_ctl_info(dev_info->edac_dev);
- return -ENODEV;
+ goto err_edac_free_ctl;
}
printk(KERN_INFO "added one edac_dev on AMD8111 "
@@ -409,6 +410,13 @@ static int amd8111_dev_probe(struct pci_dev *dev,
dev_info->ctl_name);
return 0;
+
+err_edac_free_ctl:
+ edac_device_free_ctl_info(dev_info->edac_dev);
+err_dev_put:
+ pci_dev_put(dev_info->dev);
+err:
+ return ret;
}
static void amd8111_dev_remove(struct pci_dev *dev)
@@ -437,6 +445,7 @@ static int amd8111_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
struct amd8111_pci_info *pci_info = &amd8111_pcis[id->driver_data];
+ int ret = -ENODEV;
pci_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,
pci_info->err_dev, NULL);
@@ -446,16 +455,15 @@ static int amd8111_pci_probe(struct pci_dev *dev,
"vendor %x, device %x, name %s\n",
PCI_VENDOR_ID_AMD, pci_info->err_dev,
pci_info->ctl_name);
- return -ENODEV;
+ goto err;
}
if (pci_enable_device(pci_info->dev)) {
- pci_dev_put(pci_info->dev);
printk(KERN_ERR "failed to enable:"
"vendor %x, device %x, name %s\n",
PCI_VENDOR_ID_AMD, pci_info->err_dev,
pci_info->ctl_name);
- return -ENODEV;
+ goto err_dev_put;
}
/*
@@ -465,8 +473,10 @@ static int amd8111_pci_probe(struct pci_dev *dev,
*/
pci_info->edac_idx = edac_pci_alloc_index();
pci_info->edac_dev = edac_pci_alloc_ctl_info(0, pci_info->ctl_name);
- if (!pci_info->edac_dev)
- return -ENOMEM;
+ if (!pci_info->edac_dev) {
+ ret = -ENOMEM;
+ goto err_dev_put;
+ }
pci_info->edac_dev->pvt_info = pci_info;
pci_info->edac_dev->dev = &pci_info->dev->dev;
@@ -483,8 +493,7 @@ static int amd8111_pci_probe(struct pci_dev *dev,
if (edac_pci_add_device(pci_info->edac_dev, pci_info->edac_idx) > 0) {
printk(KERN_ERR "failed to add edac_pci for %s\n",
pci_info->ctl_name);
- edac_pci_free_ctl_info(pci_info->edac_dev);
- return -ENODEV;
+ goto err_edac_free_ctl;
}
printk(KERN_INFO "added one edac_pci on AMD8111 "
@@ -493,6 +502,13 @@ static int amd8111_pci_probe(struct pci_dev *dev,
pci_info->ctl_name);
return 0;
+
+err_edac_free_ctl:
+ edac_pci_free_ctl_info(pci_info->edac_dev);
+err_dev_put:
+ pci_dev_put(pci_info->dev);
+err:
+ return ret;
}
static void amd8111_pci_remove(struct pci_dev *dev)
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index 92d54fa65f93..b2d71388172b 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -209,7 +209,6 @@ enum e752x_chips {
*/
struct e752x_pvt {
- struct pci_dev *bridge_ck;
struct pci_dev *dev_d0f0;
struct pci_dev *dev_d0f1;
u32 tolm;
@@ -891,7 +890,7 @@ static void e752x_get_error_info(struct mem_ctl_info *mci,
info->buf_ferr);
if (info->dram_ferr)
- pci_write_bits16(pvt->bridge_ck, E752X_DRAM_FERR,
+ pci_write_bits16(pvt->dev_d0f1, E752X_DRAM_FERR,
info->dram_ferr, info->dram_ferr);
pci_write_config_dword(dev, E752X_FERR_GLOBAL,
@@ -936,7 +935,7 @@ static void e752x_get_error_info(struct mem_ctl_info *mci,
info->buf_nerr);
if (info->dram_nerr)
- pci_write_bits16(pvt->bridge_ck, E752X_DRAM_NERR,
+ pci_write_bits16(pvt->dev_d0f1, E752X_DRAM_NERR,
info->dram_nerr, info->dram_nerr);
pci_write_config_dword(dev, E752X_NERR_GLOBAL,
@@ -1177,38 +1176,33 @@ static void e752x_init_mem_map_table(struct pci_dev *pdev,
static int e752x_get_devs(struct pci_dev *pdev, int dev_idx,
struct e752x_pvt *pvt)
{
- struct pci_dev *dev;
-
- pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
- pvt->dev_info->err_dev, pvt->bridge_ck);
+ pvt->dev_d0f1 = pci_get_device(PCI_VENDOR_ID_INTEL,
+ pvt->dev_info->err_dev, NULL);
- if (pvt->bridge_ck == NULL) {
- pvt->bridge_ck = pci_scan_single_device(pdev->bus,
+ if (pvt->dev_d0f1 == NULL) {
+ pvt->dev_d0f1 = pci_scan_single_device(pdev->bus,
PCI_DEVFN(0, 1));
- pci_dev_get(pvt->bridge_ck);
+ pci_dev_get(pvt->dev_d0f1);
}
- if (pvt->bridge_ck == NULL) {
+ if (pvt->dev_d0f1 == NULL) {
e752x_printk(KERN_ERR, "error reporting device not found:"
"vendor %x device 0x%x (broken BIOS?)\n",
PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev);
return 1;
}
- dev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ pvt->dev_d0f0 = pci_get_device(PCI_VENDOR_ID_INTEL,
e752x_devs[dev_idx].ctl_dev,
NULL);
- if (dev == NULL)
+ if (pvt->dev_d0f0 == NULL)
goto fail;
- pvt->dev_d0f0 = dev;
- pvt->dev_d0f1 = pci_dev_get(pvt->bridge_ck);
-
return 0;
fail:
- pci_dev_put(pvt->bridge_ck);
+ pci_dev_put(pvt->dev_d0f1);
return 1;
}
@@ -1385,7 +1379,6 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
fail:
pci_dev_put(pvt->dev_d0f0);
pci_dev_put(pvt->dev_d0f1);
- pci_dev_put(pvt->bridge_ck);
edac_mc_free(mci);
return -ENODEV;
@@ -1419,7 +1412,6 @@ static void e752x_remove_one(struct pci_dev *pdev)
pvt = (struct e752x_pvt *)mci->pvt_info;
pci_dev_put(pvt->dev_d0f0);
pci_dev_put(pvt->dev_d0f1);
- pci_dev_put(pvt->bridge_ck);
edac_mc_free(mci);
}
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index e8c9ef03495b..33edd6766344 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -559,7 +559,8 @@ static void edac_mc_workq_function(struct work_struct *work_req)
*
* called with the mem_ctls_mutex held
*/
-static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
+static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec,
+ bool init)
{
edac_dbg(0, "\n");
@@ -567,7 +568,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
if (mci->op_state != OP_RUNNING_POLL)
return;
- INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
+ if (init)
+ INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
+
mod_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));
}
@@ -601,7 +604,7 @@ static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
* user space has updated our poll period value, need to
* reset our workq delays
*/
-void edac_mc_reset_delay_period(int value)
+void edac_mc_reset_delay_period(unsigned long value)
{
struct mem_ctl_info *mci;
struct list_head *item;
@@ -611,7 +614,7 @@ void edac_mc_reset_delay_period(int value)
list_for_each(item, &mc_devices) {
mci = list_entry(item, struct mem_ctl_info, link);
- edac_mc_workq_setup(mci, (unsigned long) value);
+ edac_mc_workq_setup(mci, value, false);
}
mutex_unlock(&mem_ctls_mutex);
@@ -782,7 +785,7 @@ int edac_mc_add_mc(struct mem_ctl_info *mci)
/* This instance is NOW RUNNING */
mci->op_state = OP_RUNNING_POLL;
- edac_mc_workq_setup(mci, edac_mc_get_poll_msec());
+ edac_mc_workq_setup(mci, edac_mc_get_poll_msec(), true);
} else {
mci->op_state = OP_RUNNING_INTERRUPT;
}
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 51c0362acf5c..01fae8289cf0 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -7,7 +7,7 @@
*
* Written Doug Thompson <norsk5@xmission.com> www.softwarebitmaker.com
*
- * (c) 2012-2013 - Mauro Carvalho Chehab <mchehab@redhat.com>
+ * (c) 2012-2013 - Mauro Carvalho Chehab
* The entire API were re-written, and ported to use struct device
*
*/
@@ -52,18 +52,20 @@ int edac_mc_get_poll_msec(void)
static int edac_set_poll_msec(const char *val, struct kernel_param *kp)
{
- long l;
+ unsigned long l;
int ret;
if (!val)
return -EINVAL;
- ret = kstrtol(val, 0, &l);
+ ret = kstrtoul(val, 0, &l);
if (ret)
return ret;
- if ((int)l != l)
+
+ if (l < 1000)
return -EINVAL;
- *((int *)kp->arg) = l;
+
+ *((unsigned long *)kp->arg) = l;
/* notify edac_mc engine to reset the poll period */
edac_mc_reset_delay_period(l);
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h
index 3d139c6e7fe3..f2118bfcf8df 100644
--- a/drivers/edac/edac_module.h
+++ b/drivers/edac/edac_module.h
@@ -52,7 +52,7 @@ extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev);
extern void edac_device_reset_delay_period(struct edac_device_ctl_info
*edac_dev, unsigned long value);
-extern void edac_mc_reset_delay_period(int value);
+extern void edac_mc_reset_delay_period(unsigned long value);
extern void *edac_align_ptr(void **p, unsigned size, int n_elems);
diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c
index d5a98a45c062..8399b4e16fe0 100644
--- a/drivers/edac/ghes_edac.c
+++ b/drivers/edac/ghes_edac.c
@@ -4,7 +4,7 @@
* This file may be distributed under the terms of the GNU General Public
* License version 2.
*
- * Copyright (c) 2013 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2013 by Mauro Carvalho Chehab
*
* Red Hat Inc. http://www.redhat.com
*/
diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c
index fa1326e5a4b0..022a70273ada 100644
--- a/drivers/edac/i3200_edac.c
+++ b/drivers/edac/i3200_edac.c
@@ -464,6 +464,8 @@ static void i3200_remove_one(struct pci_dev *pdev)
iounmap(priv->window);
edac_mc_free(mci);
+
+ pci_disable_device(pdev);
}
static const struct pci_device_id i3200_pci_tbl[] = {
diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c
index 36a38ee94fa8..6247d186177e 100644
--- a/drivers/edac/i5100_edac.c
+++ b/drivers/edac/i5100_edac.c
@@ -869,16 +869,13 @@ static void i5100_init_csrows(struct mem_ctl_info *mci)
chan, rank, 0);
dimm->nr_pages = npages;
- if (npages) {
- dimm->grain = 32;
- dimm->dtype = (priv->mtr[chan][rank].width == 4) ?
- DEV_X4 : DEV_X8;
- dimm->mtype = MEM_RDDR2;
- dimm->edac_mode = EDAC_SECDED;
- snprintf(dimm->label, sizeof(dimm->label),
- "DIMM%u",
- i5100_rank_to_slot(mci, chan, rank));
- }
+ dimm->grain = 32;
+ dimm->dtype = (priv->mtr[chan][rank].width == 4) ?
+ DEV_X4 : DEV_X8;
+ dimm->mtype = MEM_RDDR2;
+ dimm->edac_mode = EDAC_SECDED;
+ snprintf(dimm->label, sizeof(dimm->label), "DIMM%u",
+ i5100_rank_to_slot(mci, chan, rank));
edac_dbg(2, "dimm channel %d, rank %d, size %ld\n",
chan, rank, (long)PAGES_TO_MiB(npages));
diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c
index e080cbfa8fc9..6ef6ad1ba16e 100644
--- a/drivers/edac/i5400_edac.c
+++ b/drivers/edac/i5400_edac.c
@@ -6,7 +6,7 @@
*
* Copyright (c) 2008 by:
* Ben Woodard <woodard@redhat.com>
- * Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Mauro Carvalho Chehab
*
* Red Hat Inc. http://www.redhat.com
*
@@ -1408,6 +1408,8 @@ static void i5400_remove_one(struct pci_dev *pdev)
/* retrieve references to resources, and free those resources */
i5400_put_devices(mci);
+ pci_disable_device(pdev);
+
edac_mc_free(mci);
}
@@ -1467,7 +1469,7 @@ module_exit(i5400_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ben Woodard <woodard@redhat.com>");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
MODULE_DESCRIPTION("MC Driver for Intel I5400 memory controllers - "
I5400_REVISION);
diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c
index d63f4798f7d0..dcac982fdc7a 100644
--- a/drivers/edac/i7300_edac.c
+++ b/drivers/edac/i7300_edac.c
@@ -5,7 +5,7 @@
* GNU General Public License version 2 only.
*
* Copyright (c) 2010 by:
- * Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Mauro Carvalho Chehab
*
* Red Hat Inc. http://www.redhat.com
*
@@ -943,33 +943,35 @@ static int i7300_get_devices(struct mem_ctl_info *mci)
/* Attempt to 'get' the MCH register we want */
pdev = NULL;
- while (!pvt->pci_dev_16_1_fsb_addr_map ||
- !pvt->pci_dev_16_2_fsb_err_regs) {
- pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, pdev);
- if (!pdev) {
- /* End of list, leave */
- i7300_printk(KERN_ERR,
- "'system address,Process Bus' "
- "device not found:"
- "vendor 0x%x device 0x%x ERR funcs "
- "(broken BIOS?)\n",
- PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_I7300_MCH_ERR);
- goto error;
- }
-
+ while ((pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I7300_MCH_ERR,
+ pdev))) {
/* Store device 16 funcs 1 and 2 */
switch (PCI_FUNC(pdev->devfn)) {
case 1:
- pvt->pci_dev_16_1_fsb_addr_map = pdev;
+ if (!pvt->pci_dev_16_1_fsb_addr_map)
+ pvt->pci_dev_16_1_fsb_addr_map =
+ pci_dev_get(pdev);
break;
case 2:
- pvt->pci_dev_16_2_fsb_err_regs = pdev;
+ if (!pvt->pci_dev_16_2_fsb_err_regs)
+ pvt->pci_dev_16_2_fsb_err_regs =
+ pci_dev_get(pdev);
break;
}
}
+ if (!pvt->pci_dev_16_1_fsb_addr_map ||
+ !pvt->pci_dev_16_2_fsb_err_regs) {
+ /* At least one device was not found */
+ i7300_printk(KERN_ERR,
+ "'system address,Process Bus' device not found:"
+ "vendor 0x%x device 0x%x ERR funcs (broken BIOS?)\n",
+ PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I7300_MCH_ERR);
+ goto error;
+ }
+
edac_dbg(1, "System Address, processor bus- PCI Bus ID: %s %x:%x\n",
pci_name(pvt->pci_dev_16_0_fsb_ctlr),
pvt->pci_dev_16_0_fsb_ctlr->vendor,
@@ -1207,7 +1209,7 @@ module_init(i7300_init);
module_exit(i7300_exit);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
MODULE_DESCRIPTION("MC Driver for Intel I7300 memory controllers - "
I7300_REVISION);
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index 87533ca7752e..9cd0b301f81b 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -9,7 +9,7 @@
* GNU General Public License version 2 only.
*
* Copyright (c) 2009-2010 by:
- * Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Mauro Carvalho Chehab
*
* Red Hat Inc. http://www.redhat.com
*
@@ -1334,14 +1334,19 @@ static int i7core_get_onedevice(struct pci_dev **prev,
* is at addr 8086:2c40, instead of 8086:2c41. So, we need
* to probe for the alternate address in case of failure
*/
- if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev)
+ if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) {
+ pci_dev_get(*prev); /* pci_get_device will put it */
pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev);
+ }
- if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev)
+ if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE &&
+ !pdev) {
+ pci_dev_get(*prev); /* pci_get_device will put it */
pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT,
*prev);
+ }
if (!pdev) {
if (*prev) {
@@ -1703,7 +1708,7 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
const struct mce *m)
{
struct i7core_pvt *pvt = mci->pvt_info;
- char *type, *optype, *err;
+ char *optype, *err;
enum hw_event_mc_err_type tp_event;
unsigned long error = m->status & 0x1ff0000l;
bool uncorrected_error = m->mcgstatus & 1ll << 61;
@@ -1716,15 +1721,11 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
u32 errnum = find_first_bit(&error, 32);
if (uncorrected_error) {
- if (ripv) {
- type = "FATAL";
+ if (ripv)
tp_event = HW_EVENT_ERR_FATAL;
- } else {
- type = "NON_FATAL";
+ else
tp_event = HW_EVENT_ERR_UNCORRECTED;
- }
} else {
- type = "CORRECTED";
tp_event = HW_EVENT_ERR_CORRECTED;
}
@@ -2456,7 +2457,7 @@ module_init(i7core_init);
module_exit(i7core_exit);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
MODULE_DESCRIPTION("MC Driver for Intel i7 Core memory controllers - "
I7CORE_REVISION);
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c
index 80573df0a4d7..8d0450b9b9af 100644
--- a/drivers/edac/i82875p_edac.c
+++ b/drivers/edac/i82875p_edac.c
@@ -406,8 +406,6 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
edac_dbg(0, "\n");
- ovrfl_pdev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL);
-
if (i82875p_setup_overfl_dev(pdev, &ovrfl_pdev, &ovrfl_window))
return -ENODEV;
drc = readl(ovrfl_window + I82875P_DRC);
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c
index 30f7309446a6..51b9caa0b024 100644
--- a/drivers/edac/mce_amd.c
+++ b/drivers/edac/mce_amd.c
@@ -741,6 +741,36 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
if (amd_filter_mce(m))
return NOTIFY_STOP;
+ pr_emerg(HW_ERR "%s\n", decode_error_status(m));
+
+ pr_emerg(HW_ERR "CPU:%d (%x:%x:%x) MC%d_STATUS[%s|%s|%s|%s|%s",
+ m->extcpu,
+ c->x86, c->x86_model, c->x86_mask,
+ m->bank,
+ ((m->status & MCI_STATUS_OVER) ? "Over" : "-"),
+ ((m->status & MCI_STATUS_UC) ? "UE" : "CE"),
+ ((m->status & MCI_STATUS_MISCV) ? "MiscV" : "-"),
+ ((m->status & MCI_STATUS_PCC) ? "PCC" : "-"),
+ ((m->status & MCI_STATUS_ADDRV) ? "AddrV" : "-"));
+
+ if (c->x86 == 0x15 || c->x86 == 0x16)
+ pr_cont("|%s|%s",
+ ((m->status & MCI_STATUS_DEFERRED) ? "Deferred" : "-"),
+ ((m->status & MCI_STATUS_POISON) ? "Poison" : "-"));
+
+ /* do the two bits[14:13] together */
+ ecc = (m->status >> 45) & 0x3;
+ if (ecc)
+ pr_cont("|%sECC", ((ecc == 2) ? "C" : "U"));
+
+ pr_cont("]: 0x%016llx\n", m->status);
+
+ if (m->status & MCI_STATUS_ADDRV)
+ pr_emerg(HW_ERR "MC%d_ADDR: 0x%016llx\n", m->bank, m->addr);
+
+ if (!fam_ops)
+ goto err_code;
+
switch (m->bank) {
case 0:
decode_mc0_mce(m);
@@ -774,33 +804,7 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
break;
}
- pr_emerg(HW_ERR "Error Status: %s\n", decode_error_status(m));
-
- pr_emerg(HW_ERR "CPU:%d (%x:%x:%x) MC%d_STATUS[%s|%s|%s|%s|%s",
- m->extcpu,
- c->x86, c->x86_model, c->x86_mask,
- m->bank,
- ((m->status & MCI_STATUS_OVER) ? "Over" : "-"),
- ((m->status & MCI_STATUS_UC) ? "UE" : "CE"),
- ((m->status & MCI_STATUS_MISCV) ? "MiscV" : "-"),
- ((m->status & MCI_STATUS_PCC) ? "PCC" : "-"),
- ((m->status & MCI_STATUS_ADDRV) ? "AddrV" : "-"));
-
- if (c->x86 == 0x15 || c->x86 == 0x16)
- pr_cont("|%s|%s",
- ((m->status & MCI_STATUS_DEFERRED) ? "Deferred" : "-"),
- ((m->status & MCI_STATUS_POISON) ? "Poison" : "-"));
-
- /* do the two bits[14:13] together */
- ecc = (m->status >> 45) & 0x3;
- if (ecc)
- pr_cont("|%sECC", ((ecc == 2) ? "C" : "U"));
-
- pr_cont("]: 0x%016llx\n", m->status);
-
- if (m->status & MCI_STATUS_ADDRV)
- pr_emerg(HW_ERR "MC%d_ADDR: 0x%016llx\n", m->bank, m->addr);
-
+ err_code:
amd_decode_err_code(m->status & 0xffff);
return NOTIFY_STOP;
@@ -816,10 +820,7 @@ static int __init mce_amd_init(void)
struct cpuinfo_x86 *c = &boot_cpu_data;
if (c->x86_vendor != X86_VENDOR_AMD)
- return 0;
-
- if (c->x86 < 0xf || c->x86 > 0x16)
- return 0;
+ return -ENODEV;
fam_ops = kzalloc(sizeof(struct amd_decoder_ops), GFP_KERNEL);
if (!fam_ops)
@@ -874,7 +875,7 @@ static int __init mce_amd_init(void)
default:
printk(KERN_WARNING "Huh? What family is it: 0x%x?!\n", c->x86);
kfree(fam_ops);
- return -EINVAL;
+ fam_ops = NULL;
}
pr_info("MCE: In-kernel MCE decoding enabled.\n");
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index 8f9182179a7c..f4aec2e6ef56 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -357,7 +357,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
res = devm_request_irq(&op->dev, pdata->irq,
mpc85xx_pci_isr,
- IRQF_DISABLED | IRQF_SHARED,
+ IRQF_SHARED,
"[EDAC] PCI err", pci);
if (res < 0) {
printk(KERN_ERR
@@ -633,7 +633,7 @@ static int mpc85xx_l2_err_probe(struct platform_device *op)
if (edac_op_state == EDAC_OPSTATE_INT) {
pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
res = devm_request_irq(&op->dev, pdata->irq,
- mpc85xx_l2_isr, IRQF_DISABLED,
+ mpc85xx_l2_isr, 0,
"[EDAC] L2 err", edac_dev);
if (res < 0) {
printk(KERN_ERR
@@ -1133,7 +1133,7 @@ static int mpc85xx_mc_err_probe(struct platform_device *op)
pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
res = devm_request_irq(&op->dev, pdata->irq,
mpc85xx_mc_isr,
- IRQF_DISABLED | IRQF_SHARED,
+ IRQF_SHARED,
"[EDAC] MC err", mci);
if (res < 0) {
printk(KERN_ERR "%s: Unable to request irq %d for "
diff --git a/drivers/edac/octeon_edac-lmc.c b/drivers/edac/octeon_edac-lmc.c
index 93412d6b3af1..4bd10f94f068 100644
--- a/drivers/edac/octeon_edac-lmc.c
+++ b/drivers/edac/octeon_edac-lmc.c
@@ -5,12 +5,16 @@
*
* Copyright (C) 2009 Wind River Systems,
* written by Ralf Baechle <ralf@linux-mips.org>
+ *
+ * Copyright (c) 2013 by Cisco Systems, Inc.
+ * All rights reserved.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/edac.h>
+#include <linux/ctype.h>
#include <asm/octeon/octeon.h>
#include <asm/octeon/cvmx-lmcx-defs.h>
@@ -20,6 +24,18 @@
#define OCTEON_MAX_MC 4
+#define to_mci(k) container_of(k, struct mem_ctl_info, dev)
+
+struct octeon_lmc_pvt {
+ unsigned long inject;
+ unsigned long error_type;
+ unsigned long dimm;
+ unsigned long rank;
+ unsigned long bank;
+ unsigned long row;
+ unsigned long col;
+};
+
static void octeon_lmc_edac_poll(struct mem_ctl_info *mci)
{
union cvmx_lmcx_mem_cfg0 cfg0;
@@ -55,14 +71,31 @@ static void octeon_lmc_edac_poll(struct mem_ctl_info *mci)
static void octeon_lmc_edac_poll_o2(struct mem_ctl_info *mci)
{
+ struct octeon_lmc_pvt *pvt = mci->pvt_info;
union cvmx_lmcx_int int_reg;
bool do_clear = false;
char msg[64];
- int_reg.u64 = cvmx_read_csr(CVMX_LMCX_INT(mci->mc_idx));
+ if (!pvt->inject)
+ int_reg.u64 = cvmx_read_csr(CVMX_LMCX_INT(mci->mc_idx));
+ else {
+ if (pvt->error_type == 1)
+ int_reg.s.sec_err = 1;
+ if (pvt->error_type == 2)
+ int_reg.s.ded_err = 1;
+ }
+
if (int_reg.s.sec_err || int_reg.s.ded_err) {
union cvmx_lmcx_fadr fadr;
- fadr.u64 = cvmx_read_csr(CVMX_LMCX_FADR(mci->mc_idx));
+ if (likely(!pvt->inject))
+ fadr.u64 = cvmx_read_csr(CVMX_LMCX_FADR(mci->mc_idx));
+ else {
+ fadr.cn61xx.fdimm = pvt->dimm;
+ fadr.cn61xx.fbunk = pvt->rank;
+ fadr.cn61xx.fbank = pvt->bank;
+ fadr.cn61xx.frow = pvt->row;
+ fadr.cn61xx.fcol = pvt->col;
+ }
snprintf(msg, sizeof(msg),
"DIMM %d rank %d bank %d row %d col %d",
fadr.cn61xx.fdimm, fadr.cn61xx.fbunk,
@@ -82,8 +115,128 @@ static void octeon_lmc_edac_poll_o2(struct mem_ctl_info *mci)
int_reg.s.ded_err = -1; /* Done, re-arm */
do_clear = true;
}
- if (do_clear)
- cvmx_write_csr(CVMX_LMCX_INT(mci->mc_idx), int_reg.u64);
+
+ if (do_clear) {
+ if (likely(!pvt->inject))
+ cvmx_write_csr(CVMX_LMCX_INT(mci->mc_idx), int_reg.u64);
+ else
+ pvt->inject = 0;
+ }
+}
+
+/************************ MC SYSFS parts ***********************************/
+
+/* Only a couple naming differences per template, so very similar */
+#define TEMPLATE_SHOW(reg) \
+static ssize_t octeon_mc_inject_##reg##_show(struct device *dev, \
+ struct device_attribute *attr, \
+ char *data) \
+{ \
+ struct mem_ctl_info *mci = to_mci(dev); \
+ struct octeon_lmc_pvt *pvt = mci->pvt_info; \
+ return sprintf(data, "%016llu\n", (u64)pvt->reg); \
+}
+
+#define TEMPLATE_STORE(reg) \
+static ssize_t octeon_mc_inject_##reg##_store(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *data, size_t count) \
+{ \
+ struct mem_ctl_info *mci = to_mci(dev); \
+ struct octeon_lmc_pvt *pvt = mci->pvt_info; \
+ if (isdigit(*data)) { \
+ if (!kstrtoul(data, 0, &pvt->reg)) \
+ return count; \
+ } \
+ return 0; \
+}
+
+TEMPLATE_SHOW(inject);
+TEMPLATE_STORE(inject);
+TEMPLATE_SHOW(dimm);
+TEMPLATE_STORE(dimm);
+TEMPLATE_SHOW(bank);
+TEMPLATE_STORE(bank);
+TEMPLATE_SHOW(rank);
+TEMPLATE_STORE(rank);
+TEMPLATE_SHOW(row);
+TEMPLATE_STORE(row);
+TEMPLATE_SHOW(col);
+TEMPLATE_STORE(col);
+
+static ssize_t octeon_mc_inject_error_type_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *data,
+ size_t count)
+{
+ struct mem_ctl_info *mci = to_mci(dev);
+ struct octeon_lmc_pvt *pvt = mci->pvt_info;
+
+ if (!strncmp(data, "single", 6))
+ pvt->error_type = 1;
+ else if (!strncmp(data, "double", 6))
+ pvt->error_type = 2;
+
+ return count;
+}
+
+static ssize_t octeon_mc_inject_error_type_show(struct device *dev,
+ struct device_attribute *attr,
+ char *data)
+{
+ struct mem_ctl_info *mci = to_mci(dev);
+ struct octeon_lmc_pvt *pvt = mci->pvt_info;
+ if (pvt->error_type == 1)
+ return sprintf(data, "single");
+ else if (pvt->error_type == 2)
+ return sprintf(data, "double");
+
+ return 0;
+}
+
+static DEVICE_ATTR(inject, S_IRUGO | S_IWUSR,
+ octeon_mc_inject_inject_show, octeon_mc_inject_inject_store);
+static DEVICE_ATTR(error_type, S_IRUGO | S_IWUSR,
+ octeon_mc_inject_error_type_show, octeon_mc_inject_error_type_store);
+static DEVICE_ATTR(dimm, S_IRUGO | S_IWUSR,
+ octeon_mc_inject_dimm_show, octeon_mc_inject_dimm_store);
+static DEVICE_ATTR(rank, S_IRUGO | S_IWUSR,
+ octeon_mc_inject_rank_show, octeon_mc_inject_rank_store);
+static DEVICE_ATTR(bank, S_IRUGO | S_IWUSR,
+ octeon_mc_inject_bank_show, octeon_mc_inject_bank_store);
+static DEVICE_ATTR(row, S_IRUGO | S_IWUSR,
+ octeon_mc_inject_row_show, octeon_mc_inject_row_store);
+static DEVICE_ATTR(col, S_IRUGO | S_IWUSR,
+ octeon_mc_inject_col_show, octeon_mc_inject_col_store);
+
+
+static int octeon_set_mc_sysfs_attributes(struct mem_ctl_info *mci)
+{
+ int rc;
+
+ rc = device_create_file(&mci->dev, &dev_attr_inject);
+ if (rc < 0)
+ return rc;
+ rc = device_create_file(&mci->dev, &dev_attr_error_type);
+ if (rc < 0)
+ return rc;
+ rc = device_create_file(&mci->dev, &dev_attr_dimm);
+ if (rc < 0)
+ return rc;
+ rc = device_create_file(&mci->dev, &dev_attr_rank);
+ if (rc < 0)
+ return rc;
+ rc = device_create_file(&mci->dev, &dev_attr_bank);
+ if (rc < 0)
+ return rc;
+ rc = device_create_file(&mci->dev, &dev_attr_row);
+ if (rc < 0)
+ return rc;
+ rc = device_create_file(&mci->dev, &dev_attr_col);
+ if (rc < 0)
+ return rc;
+
+ return 0;
}
static int octeon_lmc_edac_probe(struct platform_device *pdev)
@@ -92,6 +245,8 @@ static int octeon_lmc_edac_probe(struct platform_device *pdev)
struct edac_mc_layer layers[1];
int mc = pdev->id;
+ opstate_init();
+
layers[0].type = EDAC_MC_LAYER_CHANNEL;
layers[0].size = 1;
layers[0].is_virt_csrow = false;
@@ -105,7 +260,7 @@ static int octeon_lmc_edac_probe(struct platform_device *pdev)
return 0;
}
- mci = edac_mc_alloc(mc, ARRAY_SIZE(layers), layers, 0);
+ mci = edac_mc_alloc(mc, ARRAY_SIZE(layers), layers, sizeof(struct octeon_lmc_pvt));
if (!mci)
return -ENXIO;
@@ -122,6 +277,12 @@ static int octeon_lmc_edac_probe(struct platform_device *pdev)
return -ENXIO;
}
+ if (octeon_set_mc_sysfs_attributes(mci)) {
+ dev_err(&pdev->dev, "octeon_set_mc_sysfs_attributes() failed\n");
+ return -ENXIO;
+ }
+
+
cfg0.u64 = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(mc));
cfg0.s.intr_ded_ena = 0; /* We poll */
cfg0.s.intr_sec_ena = 0;
@@ -137,7 +298,7 @@ static int octeon_lmc_edac_probe(struct platform_device *pdev)
return 0;
}
- mci = edac_mc_alloc(mc, ARRAY_SIZE(layers), layers, 0);
+ mci = edac_mc_alloc(mc, ARRAY_SIZE(layers), layers, sizeof(struct octeon_lmc_pvt));
if (!mci)
return -ENXIO;
@@ -154,6 +315,12 @@ static int octeon_lmc_edac_probe(struct platform_device *pdev)
return -ENXIO;
}
+ if (octeon_set_mc_sysfs_attributes(mci)) {
+ dev_err(&pdev->dev, "octeon_set_mc_sysfs_attributes() failed\n");
+ return -ENXIO;
+ }
+
+
en.u64 = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(mc));
en.s.intr_ded_ena = 0; /* We poll */
en.s.intr_sec_ena = 0;
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 54e2abe671f7..deea0dc9999b 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -7,7 +7,7 @@
* GNU General Public License version 2 only.
*
* Copyright (c) 2011 by:
- * Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Mauro Carvalho Chehab
*/
#include <linux/module.h>
@@ -1263,7 +1263,7 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
struct pci_dev *pdev = NULL;
u8 bus = 0;
- sbridge_printk(KERN_INFO,
+ sbridge_printk(KERN_DEBUG,
"Seeking for: dev %02x.%d PCI ID %04x:%04x\n",
dev_descr->dev, dev_descr->func,
PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
@@ -1828,6 +1828,7 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val,
struct mce *mce = (struct mce *)data;
struct mem_ctl_info *mci;
struct sbridge_pvt *pvt;
+ char *type;
if (get_edac_report_status() == EDAC_REPORTING_DISABLED)
return NOTIFY_DONE;
@@ -1846,17 +1847,23 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val,
if ((mce->status & 0xefff) >> 7 != 1)
return NOTIFY_DONE;
- printk("sbridge: HANDLING MCE MEMORY ERROR\n");
+ if (mce->mcgstatus & MCG_STATUS_MCIP)
+ type = "Exception";
+ else
+ type = "Event";
+
+ sbridge_mc_printk(mci, KERN_DEBUG, "HANDLING MCE MEMORY ERROR\n");
- printk("CPU %d: Machine Check Exception: %Lx Bank %d: %016Lx\n",
- mce->extcpu, mce->mcgstatus, mce->bank, mce->status);
- printk("TSC %llx ", mce->tsc);
- printk("ADDR %llx ", mce->addr);
- printk("MISC %llx ", mce->misc);
+ sbridge_mc_printk(mci, KERN_DEBUG, "CPU %d: Machine Check %s: %Lx "
+ "Bank %d: %016Lx\n", mce->extcpu, type,
+ mce->mcgstatus, mce->bank, mce->status);
+ sbridge_mc_printk(mci, KERN_DEBUG, "TSC %llx ", mce->tsc);
+ sbridge_mc_printk(mci, KERN_DEBUG, "ADDR %llx ", mce->addr);
+ sbridge_mc_printk(mci, KERN_DEBUG, "MISC %llx ", mce->misc);
- printk("PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x\n",
- mce->cpuvendor, mce->cpuid, mce->time,
- mce->socketid, mce->apicid);
+ sbridge_mc_printk(mci, KERN_DEBUG, "PROCESSOR %u:%x TIME %llu SOCKET "
+ "%u APIC %x\n", mce->cpuvendor, mce->cpuid,
+ mce->time, mce->socketid, mce->apicid);
/* Only handle if it is the right mc controller */
if (cpu_data(mce->cpu).phys_proc_id != pvt->sbridge_dev->mc)
@@ -2176,7 +2183,7 @@ module_param(edac_op_state, int, 0444);
MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
MODULE_DESCRIPTION("MC Driver for Intel Sandy Bridge and Ivy Bridge memory controllers - "
SBRIDGE_REVISION);
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index bdb5a00f1dfa..be56e8ac95e6 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -14,10 +14,6 @@ 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 43eccc0e3448..bf7861ec0906 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -2,8 +2,6 @@
# 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-arizona.c b/drivers/extcon/extcon-arizona.c
index c20602f601ee..98a14f6143a7 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -222,27 +222,19 @@ static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
struct snd_soc_dapm_context *dapm = arizona->dapm;
int ret;
- mutex_lock(&dapm->card->dapm_mutex);
-
ret = snd_soc_dapm_force_enable_pin(dapm, widget);
if (ret != 0)
dev_warn(arizona->dev, "Failed to enable %s: %d\n",
widget, ret);
- mutex_unlock(&dapm->card->dapm_mutex);
-
snd_soc_dapm_sync(dapm);
if (!arizona->pdata.micd_force_micbias) {
- mutex_lock(&dapm->card->dapm_mutex);
-
ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
if (ret != 0)
dev_warn(arizona->dev, "Failed to disable %s: %d\n",
widget, ret);
- mutex_unlock(&dapm->card->dapm_mutex);
-
snd_soc_dapm_sync(dapm);
}
}
@@ -304,16 +296,12 @@ static void arizona_stop_mic(struct arizona_extcon_info *info)
ARIZONA_MICD_ENA, 0,
&change);
- mutex_lock(&dapm->card->dapm_mutex);
-
ret = snd_soc_dapm_disable_pin(dapm, widget);
if (ret != 0)
dev_warn(arizona->dev,
"Failed to disable %s: %d\n",
widget, ret);
- mutex_unlock(&dapm->card->dapm_mutex);
-
snd_soc_dapm_sync(dapm);
if (info->micd_reva) {
diff --git a/drivers/extcon/extcon-class.c b/drivers/extcon/extcon-class.c
index 76322330cbd7..7ab21aa6eaa1 100644
--- a/drivers/extcon/extcon-class.c
+++ b/drivers/extcon/extcon-class.c
@@ -31,6 +31,7 @@
#include <linux/extcon.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
+#include <linux/of.h>
/*
* extcon_cable_name suggests the standard cable names for commonly used
@@ -818,6 +819,47 @@ void extcon_dev_unregister(struct extcon_dev *edev)
}
EXPORT_SYMBOL_GPL(extcon_dev_unregister);
+#ifdef CONFIG_OF
+/*
+ * extcon_get_edev_by_phandle - Get the 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 *extcon_get_edev_by_phandle(struct device *dev, int index)
+{
+ struct device_node *node;
+ struct extcon_dev *edev;
+
+ if (!dev->of_node) {
+ dev_err(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_err(dev, "failed to get phandle in %s node\n",
+ dev->of_node->full_name);
+ return ERR_PTR(-ENODEV);
+ }
+
+ edev = extcon_get_extcon_dev(node->name);
+ if (!edev) {
+ dev_err(dev, "unable to get extcon device : %s\n", node->name);
+ return ERR_PTR(-ENODEV);
+ }
+
+ return edev;
+}
+#else
+struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index)
+{
+ return ERR_PTR(-ENOSYS);
+}
+#endif /* CONFIG_OF */
+EXPORT_SYMBOL_GPL(extcon_get_edev_by_phandle);
+
static int __init extcon_class_init(void)
{
return create_extcon_class();
diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c
index a63a6b21c9ad..13d522255d81 100644
--- a/drivers/extcon/extcon-gpio.c
+++ b/drivers/extcon/extcon-gpio.c
@@ -176,9 +176,7 @@ static int gpio_extcon_resume(struct device *dev)
}
#endif
-static const struct dev_pm_ops gpio_extcon_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(NULL, gpio_extcon_resume)
-};
+static SIMPLE_DEV_PM_OPS(gpio_extcon_pm_ops, NULL, gpio_extcon_resume);
static struct platform_driver gpio_extcon_driver = {
.probe = gpio_extcon_probe,
diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c
index 2aea4bcdd7f3..ddff2b72f0a8 100644
--- a/drivers/extcon/extcon-palmas.c
+++ b/drivers/extcon/extcon-palmas.c
@@ -271,10 +271,7 @@ static int palmas_usb_resume(struct device *dev)
};
#endif
-static const struct dev_pm_ops palmas_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(palmas_usb_suspend,
- palmas_usb_resume)
-};
+static SIMPLE_DEV_PM_OPS(palmas_pm_ops, palmas_usb_suspend, palmas_usb_resume);
static struct of_device_id of_palmas_match_tbl[] = {
{ .compatible = "ti,palmas-usb", },
diff --git a/drivers/extcon/of_extcon.c b/drivers/extcon/of_extcon.c
deleted file mode 100644
index 72173ecbb311..000000000000
--- a/drivers/extcon/of_extcon.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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-device.c b/drivers/firewire/core-device.c
index de4aa409abe2..2c6d5e118ac1 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -916,7 +916,7 @@ static int lookup_existing_device(struct device *dev, void *data)
old->config_rom_retries = 0;
fw_notice(card, "rediscovered device %s\n", dev_name(dev));
- PREPARE_DELAYED_WORK(&old->work, fw_device_update);
+ old->workfn = fw_device_update;
fw_schedule_device_work(old, 0);
if (current_node == card->root_node)
@@ -1075,7 +1075,7 @@ static void fw_device_init(struct work_struct *work)
if (atomic_cmpxchg(&device->state,
FW_DEVICE_INITIALIZING,
FW_DEVICE_RUNNING) == FW_DEVICE_GONE) {
- PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
+ device->workfn = fw_device_shutdown;
fw_schedule_device_work(device, SHUTDOWN_DELAY);
} else {
fw_notice(card, "created device %s: GUID %08x%08x, S%d00\n",
@@ -1196,13 +1196,20 @@ static void fw_device_refresh(struct work_struct *work)
dev_name(&device->device), fw_rcode_string(ret));
gone:
atomic_set(&device->state, FW_DEVICE_GONE);
- PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
+ device->workfn = fw_device_shutdown;
fw_schedule_device_work(device, SHUTDOWN_DELAY);
out:
if (node_id == card->root_node->node_id)
fw_schedule_bm_work(card, 0);
}
+static void fw_device_workfn(struct work_struct *work)
+{
+ struct fw_device *device = container_of(to_delayed_work(work),
+ struct fw_device, work);
+ device->workfn(work);
+}
+
void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
{
struct fw_device *device;
@@ -1252,7 +1259,8 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
* power-up after getting plugged in. We schedule the
* first config rom scan half a second after bus reset.
*/
- INIT_DELAYED_WORK(&device->work, fw_device_init);
+ device->workfn = fw_device_init;
+ INIT_DELAYED_WORK(&device->work, fw_device_workfn);
fw_schedule_device_work(device, INITIAL_DELAY);
break;
@@ -1268,7 +1276,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
if (atomic_cmpxchg(&device->state,
FW_DEVICE_RUNNING,
FW_DEVICE_INITIALIZING) == FW_DEVICE_RUNNING) {
- PREPARE_DELAYED_WORK(&device->work, fw_device_refresh);
+ device->workfn = fw_device_refresh;
fw_schedule_device_work(device,
device->is_local ? 0 : INITIAL_DELAY);
}
@@ -1283,7 +1291,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
smp_wmb(); /* update node_id before generation */
device->generation = card->generation;
if (atomic_read(&device->state) == FW_DEVICE_RUNNING) {
- PREPARE_DELAYED_WORK(&device->work, fw_device_update);
+ device->workfn = fw_device_update;
fw_schedule_device_work(device, 0);
}
break;
@@ -1308,7 +1316,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
device = node->data;
if (atomic_xchg(&device->state,
FW_DEVICE_GONE) == FW_DEVICE_RUNNING) {
- PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
+ device->workfn = fw_device_shutdown;
fw_schedule_device_work(device,
list_empty(&card->link) ? 0 : SHUTDOWN_DELAY);
}
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c
index 6b895986dc22..4af0a7bad7f2 100644
--- a/drivers/firewire/net.c
+++ b/drivers/firewire/net.c
@@ -929,8 +929,6 @@ static void fwnet_write_complete(struct fw_card *card, int rcode,
if (rcode == RCODE_COMPLETE) {
fwnet_transmit_packet_done(ptask);
} else {
- fwnet_transmit_packet_failed(ptask);
-
if (printk_timed_ratelimit(&j, 1000) || rcode != last_rcode) {
dev_err(&ptask->dev->netdev->dev,
"fwnet_write_complete failed: %x (skipped %d)\n",
@@ -938,8 +936,10 @@ static void fwnet_write_complete(struct fw_card *card, int rcode,
errors_skipped = 0;
last_rcode = rcode;
- } else
+ } else {
errors_skipped++;
+ }
+ fwnet_transmit_packet_failed(ptask);
}
}
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 6f74d8d3f700..8db663219560 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -290,7 +290,6 @@ static char ohci_driver_name[] = KBUILD_MODNAME;
#define QUIRK_NO_MSI 0x10
#define QUIRK_TI_SLLZ059 0x20
#define QUIRK_IR_WAKE 0x40
-#define QUIRK_PHY_LCTRL_TIMEOUT 0x80
/* In case of multiple matches in ohci_quirks[], only the first one is used. */
static const struct {
@@ -303,10 +302,7 @@ static const struct {
QUIRK_BE_HEADERS},
{PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_AGERE_FW643, 6,
- QUIRK_PHY_LCTRL_TIMEOUT | QUIRK_NO_MSI},
-
- {PCI_VENDOR_ID_ATT, PCI_ANY_ID, PCI_ANY_ID,
- QUIRK_PHY_LCTRL_TIMEOUT},
+ QUIRK_NO_MSI},
{PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_SB1394, PCI_ANY_ID,
QUIRK_RESET_PACKET},
@@ -353,7 +349,6 @@ MODULE_PARM_DESC(quirks, "Chip quirks (default = 0"
", disable MSI = " __stringify(QUIRK_NO_MSI)
", TI SLLZ059 erratum = " __stringify(QUIRK_TI_SLLZ059)
", IR wake unreliable = " __stringify(QUIRK_IR_WAKE)
- ", phy LCtrl timeout = " __stringify(QUIRK_PHY_LCTRL_TIMEOUT)
")");
#define OHCI_PARAM_DEBUG_AT_AR 1
@@ -2299,9 +2294,6 @@ static int ohci_enable(struct fw_card *card,
* TI TSB82AA2 + TSB81BA3(A) cards signal LPS enabled early but
* cannot actually use the phy at that time. These need tens of
* millisecods pause between LPS write and first phy access too.
- *
- * But do not wait for 50msec on Agere/LSI cards. Their phy
- * arbitration state machine may time out during such a long wait.
*/
reg_write(ohci, OHCI1394_HCControlSet,
@@ -2309,11 +2301,8 @@ static int ohci_enable(struct fw_card *card,
OHCI1394_HCControl_postedWriteEnable);
flush_writes(ohci);
- if (!(ohci->quirks & QUIRK_PHY_LCTRL_TIMEOUT))
+ for (lps = 0, i = 0; !lps && i < 3; i++) {
msleep(50);
-
- for (lps = 0, i = 0; !lps && i < 150; i++) {
- msleep(1);
lps = reg_read(ohci, OHCI1394_HCControlSet) &
OHCI1394_HCControl_LPS;
}
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
index 281029daf98c..7aef911fdc71 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -146,6 +146,7 @@ struct sbp2_logical_unit {
*/
int generation;
int retries;
+ work_func_t workfn;
struct delayed_work work;
bool has_sdev;
bool blocked;
@@ -864,7 +865,7 @@ static void sbp2_login(struct work_struct *work)
/* set appropriate retry limit(s) in BUSY_TIMEOUT register */
sbp2_set_busy_timeout(lu);
- PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect);
+ lu->workfn = sbp2_reconnect;
sbp2_agent_reset(lu);
/* This was a re-login. */
@@ -918,7 +919,7 @@ static void sbp2_login(struct work_struct *work)
* If a bus reset happened, sbp2_update will have requeued
* lu->work already. Reset the work from reconnect to login.
*/
- PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
+ lu->workfn = sbp2_login;
}
static void sbp2_reconnect(struct work_struct *work)
@@ -952,7 +953,7 @@ static void sbp2_reconnect(struct work_struct *work)
lu->retries++ >= 5) {
dev_err(tgt_dev(tgt), "failed to reconnect\n");
lu->retries = 0;
- PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
+ lu->workfn = sbp2_login;
}
sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5));
@@ -972,6 +973,13 @@ static void sbp2_reconnect(struct work_struct *work)
sbp2_conditionally_unblock(lu);
}
+static void sbp2_lu_workfn(struct work_struct *work)
+{
+ struct sbp2_logical_unit *lu = container_of(to_delayed_work(work),
+ struct sbp2_logical_unit, work);
+ lu->workfn(work);
+}
+
static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
{
struct sbp2_logical_unit *lu;
@@ -998,7 +1006,8 @@ static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
lu->blocked = false;
++tgt->dont_block;
INIT_LIST_HEAD(&lu->orb_list);
- INIT_DELAYED_WORK(&lu->work, sbp2_login);
+ lu->workfn = sbp2_login;
+ INIT_DELAYED_WORK(&lu->work, sbp2_lu_workfn);
list_add_tail(&lu->link, &tgt->lu_list);
return 0;
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
index 1b5e8e46226d..7160c43c59fc 100644
--- a/drivers/firmware/dcdbas.c
+++ b/drivers/firmware/dcdbas.c
@@ -584,7 +584,7 @@ static struct platform_driver dcdbas_driver = {
.remove = dcdbas_remove,
};
-static const struct platform_device_info dcdbas_dev_info __initdata = {
+static const struct platform_device_info dcdbas_dev_info __initconst = {
.name = DRIVER_NAME,
.id = -1,
.dma_mask = DMA_BIT_MASK(32),
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index b6bffbfd3be7..ff50aeebf0d9 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -16,18 +16,6 @@ struct file_info {
u64 size;
};
-
-
-
-static void efi_char16_printk(efi_system_table_t *sys_table_arg,
- efi_char16_t *str)
-{
- struct efi_simple_text_output_protocol *out;
-
- out = (struct efi_simple_text_output_protocol *)sys_table_arg->con_out;
- efi_call_phys2(out->output_string, out, str);
-}
-
static void efi_printk(efi_system_table_t *sys_table_arg, char *str)
{
char *s8;
@@ -65,20 +53,23 @@ again:
* allocation which may be in a new descriptor region.
*/
*map_size += sizeof(*m);
- status = efi_call_phys3(sys_table_arg->boottime->allocate_pool,
- EFI_LOADER_DATA, *map_size, (void **)&m);
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+ *map_size, (void **)&m);
if (status != EFI_SUCCESS)
goto fail;
- status = efi_call_phys5(sys_table_arg->boottime->get_memory_map,
- map_size, m, &key, desc_size, &desc_version);
+ *desc_size = 0;
+ key = 0;
+ status = efi_call_early(get_memory_map, map_size, m,
+ &key, desc_size, &desc_version);
if (status == EFI_BUFFER_TOO_SMALL) {
- efi_call_phys1(sys_table_arg->boottime->free_pool, m);
+ efi_call_early(free_pool, m);
goto again;
}
if (status != EFI_SUCCESS)
- efi_call_phys1(sys_table_arg->boottime->free_pool, m);
+ efi_call_early(free_pool, m);
+
if (key_ptr && status == EFI_SUCCESS)
*key_ptr = key;
if (desc_ver && status == EFI_SUCCESS)
@@ -158,7 +149,7 @@ again:
if (!max_addr)
status = EFI_NOT_FOUND;
else {
- status = efi_call_phys4(sys_table_arg->boottime->allocate_pages,
+ status = efi_call_early(allocate_pages,
EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
nr_pages, &max_addr);
if (status != EFI_SUCCESS) {
@@ -170,8 +161,7 @@ again:
*addr = max_addr;
}
- efi_call_phys1(sys_table_arg->boottime->free_pool, map);
-
+ efi_call_early(free_pool, map);
fail:
return status;
}
@@ -231,7 +221,7 @@ static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
if ((start + size) > end)
continue;
- status = efi_call_phys4(sys_table_arg->boottime->allocate_pages,
+ status = efi_call_early(allocate_pages,
EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
nr_pages, &start);
if (status == EFI_SUCCESS) {
@@ -243,7 +233,7 @@ static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
if (i == map_size / desc_size)
status = EFI_NOT_FOUND;
- efi_call_phys1(sys_table_arg->boottime->free_pool, map);
+ efi_call_early(free_pool, map);
fail:
return status;
}
@@ -257,7 +247,7 @@ static void efi_free(efi_system_table_t *sys_table_arg, unsigned long size,
return;
nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
- efi_call_phys2(sys_table_arg->boottime->free_pages, addr, nr_pages);
+ efi_call_early(free_pages, addr, nr_pages);
}
@@ -276,9 +266,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
{
struct file_info *files;
unsigned long file_addr;
- efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
u64 file_size_total;
- efi_file_io_interface_t *io;
efi_file_handle_t *fh;
efi_status_t status;
int nr_files;
@@ -319,10 +307,8 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
if (!nr_files)
return EFI_SUCCESS;
- status = efi_call_phys3(sys_table_arg->boottime->allocate_pool,
- EFI_LOADER_DATA,
- nr_files * sizeof(*files),
- (void **)&files);
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+ nr_files * sizeof(*files), (void **)&files);
if (status != EFI_SUCCESS) {
efi_printk(sys_table_arg, "Failed to alloc mem for file handle list\n");
goto fail;
@@ -331,13 +317,8 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
str = cmd_line;
for (i = 0; i < nr_files; i++) {
struct file_info *file;
- efi_file_handle_t *h;
- efi_file_info_t *info;
efi_char16_t filename_16[256];
- unsigned long info_sz;
- efi_guid_t info_guid = EFI_FILE_INFO_ID;
efi_char16_t *p;
- u64 file_sz;
str = strstr(str, option_string);
if (!str)
@@ -368,71 +349,18 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
/* Only open the volume once. */
if (!i) {
- efi_boot_services_t *boottime;
-
- boottime = sys_table_arg->boottime;
-
- status = efi_call_phys3(boottime->handle_protocol,
- image->device_handle, &fs_proto,
- (void **)&io);
- if (status != EFI_SUCCESS) {
- efi_printk(sys_table_arg, "Failed to handle fs_proto\n");
- goto free_files;
- }
-
- status = efi_call_phys2(io->open_volume, io, &fh);
- if (status != EFI_SUCCESS) {
- efi_printk(sys_table_arg, "Failed to open volume\n");
+ status = efi_open_volume(sys_table_arg, image,
+ (void **)&fh);
+ if (status != EFI_SUCCESS)
goto free_files;
- }
}
- status = efi_call_phys5(fh->open, fh, &h, filename_16,
- EFI_FILE_MODE_READ, (u64)0);
- if (status != EFI_SUCCESS) {
- efi_printk(sys_table_arg, "Failed to open file: ");
- efi_char16_printk(sys_table_arg, filename_16);
- efi_printk(sys_table_arg, "\n");
+ status = efi_file_size(sys_table_arg, fh, filename_16,
+ (void **)&file->handle, &file->size);
+ if (status != EFI_SUCCESS)
goto close_handles;
- }
- file->handle = h;
-
- info_sz = 0;
- status = efi_call_phys4(h->get_info, h, &info_guid,
- &info_sz, NULL);
- if (status != EFI_BUFFER_TOO_SMALL) {
- efi_printk(sys_table_arg, "Failed to get file info size\n");
- goto close_handles;
- }
-
-grow:
- status = efi_call_phys3(sys_table_arg->boottime->allocate_pool,
- EFI_LOADER_DATA, info_sz,
- (void **)&info);
- if (status != EFI_SUCCESS) {
- efi_printk(sys_table_arg, "Failed to alloc mem for file info\n");
- goto close_handles;
- }
-
- status = efi_call_phys4(h->get_info, h, &info_guid,
- &info_sz, info);
- if (status == EFI_BUFFER_TOO_SMALL) {
- efi_call_phys1(sys_table_arg->boottime->free_pool,
- info);
- goto grow;
- }
-
- file_sz = info->file_size;
- efi_call_phys1(sys_table_arg->boottime->free_pool, info);
-
- if (status != EFI_SUCCESS) {
- efi_printk(sys_table_arg, "Failed to get file info\n");
- goto close_handles;
- }
-
- file->size = file_sz;
- file_size_total += file_sz;
+ file_size_total += file->size;
}
if (file_size_total) {
@@ -468,10 +396,10 @@ grow:
chunksize = EFI_READ_CHUNK_SIZE;
else
chunksize = size;
- status = efi_call_phys3(fh->read,
- files[j].handle,
- &chunksize,
- (void *)addr);
+
+ status = efi_file_read(fh, files[j].handle,
+ &chunksize,
+ (void *)addr);
if (status != EFI_SUCCESS) {
efi_printk(sys_table_arg, "Failed to read file\n");
goto free_file_total;
@@ -480,12 +408,12 @@ grow:
size -= chunksize;
}
- efi_call_phys1(fh->close, files[j].handle);
+ efi_file_close(fh, files[j].handle);
}
}
- efi_call_phys1(sys_table_arg->boottime->free_pool, files);
+ efi_call_early(free_pool, files);
*load_addr = file_addr;
*load_size = file_size_total;
@@ -497,9 +425,9 @@ free_file_total:
close_handles:
for (k = j; k < i; k++)
- efi_call_phys1(fh->close, files[k].handle);
+ efi_file_close(fh, files[k].handle);
free_files:
- efi_call_phys1(sys_table_arg->boottime->free_pool, files);
+ efi_call_early(free_pool, files);
fail:
*load_addr = 0;
*load_size = 0;
@@ -545,7 +473,7 @@ static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
* as possible while respecting the required alignment.
*/
nr_pages = round_up(alloc_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
- status = efi_call_phys4(sys_table_arg->boottime->allocate_pages,
+ status = efi_call_early(allocate_pages,
EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
nr_pages, &efi_addr);
new_addr = efi_addr;
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 4753bac65279..af20f1712337 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -233,7 +233,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
{SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab},
{SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},
{UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
- {NULL_GUID, NULL, 0},
+ {NULL_GUID, NULL, NULL},
};
static __init int match_config_table(efi_guid_t *guid,
@@ -313,5 +313,8 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
}
pr_cont("\n");
early_iounmap(config_tables, efi.systab->nr_tables * sz);
+
+ set_bit(EFI_CONFIG_TABLES, &efi.flags);
+
return 0;
}
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c
index 3dc248239197..50ea412a25e6 100644
--- a/drivers/firmware/efi/efivars.c
+++ b/drivers/firmware/efi/efivars.c
@@ -227,7 +227,7 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
memcpy(&entry->var, new_var, count);
err = efivar_entry_set(entry, new_var->Attributes,
- new_var->DataSize, new_var->Data, false);
+ new_var->DataSize, new_var->Data, NULL);
if (err) {
printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err);
return -EIO;
diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c
index e5a67b24587a..f1ab05ea56bb 100644
--- a/drivers/firmware/google/gsmi.c
+++ b/drivers/firmware/google/gsmi.c
@@ -892,13 +892,6 @@ static __init int gsmi_init(void)
goto out_remove_sysfs_files;
}
- ret = efivars_sysfs_init();
- if (ret) {
- printk(KERN_INFO "gsmi: Failed to create efivars files\n");
- efivars_unregister(&efivars);
- goto out_remove_sysfs_files;
- }
-
register_reboot_notifier(&gsmi_reboot_notifier);
register_die_notifier(&gsmi_die_notifier);
atomic_notifier_chain_register(&panic_notifier_list,
diff --git a/drivers/firmware/google/memconsole.c b/drivers/firmware/google/memconsole.c
index 2a90ba613613..2f569aaed4c7 100644
--- a/drivers/firmware/google/memconsole.c
+++ b/drivers/firmware/google/memconsole.c
@@ -15,6 +15,7 @@
#include <linux/kobject.h>
#include <linux/module.h>
#include <linux/dmi.h>
+#include <linux/io.h>
#include <asm/bios_ebda.h>
#define BIOS_MEMCONSOLE_V1_MAGIC 0xDEADBABE
@@ -41,15 +42,25 @@ struct biosmemcon_ebda {
};
} __packed;
-static char *memconsole_baseaddr;
+static u32 memconsole_baseaddr;
static size_t memconsole_length;
static ssize_t memconsole_read(struct file *filp, struct kobject *kobp,
struct bin_attribute *bin_attr, char *buf,
loff_t pos, size_t count)
{
- return memory_read_from_buffer(buf, count, &pos, memconsole_baseaddr,
- memconsole_length);
+ char *memconsole;
+ ssize_t ret;
+
+ memconsole = ioremap_cache(memconsole_baseaddr, memconsole_length);
+ if (!memconsole) {
+ pr_err("memconsole: ioremap_cache failed\n");
+ return -ENOMEM;
+ }
+ ret = memory_read_from_buffer(buf, count, &pos, memconsole,
+ memconsole_length);
+ iounmap(memconsole);
+ return ret;
}
static struct bin_attribute memconsole_bin_attr = {
@@ -58,43 +69,42 @@ static struct bin_attribute memconsole_bin_attr = {
};
-static void found_v1_header(struct biosmemcon_ebda *hdr)
+static void __init found_v1_header(struct biosmemcon_ebda *hdr)
{
- printk(KERN_INFO "BIOS console v1 EBDA structure found at %p\n", hdr);
- printk(KERN_INFO "BIOS console buffer at 0x%.8x, "
+ pr_info("BIOS console v1 EBDA structure found at %p\n", hdr);
+ pr_info("BIOS console buffer at 0x%.8x, "
"start = %d, end = %d, num = %d\n",
hdr->v1.buffer_addr, hdr->v1.start,
hdr->v1.end, hdr->v1.num_chars);
memconsole_length = hdr->v1.num_chars;
- memconsole_baseaddr = phys_to_virt(hdr->v1.buffer_addr);
+ memconsole_baseaddr = hdr->v1.buffer_addr;
}
-static void found_v2_header(struct biosmemcon_ebda *hdr)
+static void __init found_v2_header(struct biosmemcon_ebda *hdr)
{
- printk(KERN_INFO "BIOS console v2 EBDA structure found at %p\n", hdr);
- printk(KERN_INFO "BIOS console buffer at 0x%.8x, "
+ pr_info("BIOS console v2 EBDA structure found at %p\n", hdr);
+ pr_info("BIOS console buffer at 0x%.8x, "
"start = %d, end = %d, num_bytes = %d\n",
hdr->v2.buffer_addr, hdr->v2.start,
hdr->v2.end, hdr->v2.num_bytes);
memconsole_length = hdr->v2.end - hdr->v2.start;
- memconsole_baseaddr = phys_to_virt(hdr->v2.buffer_addr
- + hdr->v2.start);
+ memconsole_baseaddr = hdr->v2.buffer_addr + hdr->v2.start;
}
/*
* Search through the EBDA for the BIOS Memory Console, and
* set the global variables to point to it. Return true if found.
*/
-static bool found_memconsole(void)
+static bool __init found_memconsole(void)
{
unsigned int address;
size_t length, cur;
address = get_bios_ebda();
if (!address) {
- printk(KERN_INFO "BIOS EBDA non-existent.\n");
+ pr_info("BIOS EBDA non-existent.\n");
return false;
}
@@ -122,7 +132,7 @@ static bool found_memconsole(void)
}
}
- printk(KERN_INFO "BIOS console EBDA structure not found!\n");
+ pr_info("BIOS console EBDA structure not found!\n");
return false;
}
@@ -139,8 +149,6 @@ MODULE_DEVICE_TABLE(dmi, memconsole_dmi_table);
static int __init memconsole_init(void)
{
- int ret;
-
if (!dmi_check_system(memconsole_dmi_table))
return -ENODEV;
@@ -148,10 +156,7 @@ static int __init memconsole_init(void)
return -ENODEV;
memconsole_bin_attr.size = memconsole_length;
-
- ret = sysfs_create_bin_file(firmware_kobj, &memconsole_bin_attr);
-
- return ret;
+ return sysfs_create_bin_file(firmware_kobj, &memconsole_bin_attr);
}
static void __exit memconsole_exit(void)
diff --git a/drivers/fmc/fmc-core.c b/drivers/fmc/fmc-core.c
index 24d52497524d..353fc546fb08 100644
--- a/drivers/fmc/fmc-core.c
+++ b/drivers/fmc/fmc-core.c
@@ -99,10 +99,23 @@ static ssize_t fmc_read_eeprom(struct file *file, struct kobject *kobj,
return count;
}
+static ssize_t fmc_write_eeprom(struct file *file, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct device *dev;
+ struct fmc_device *fmc;
+
+ dev = container_of(kobj, struct device, kobj);
+ fmc = container_of(dev, struct fmc_device, dev);
+ return fmc->op->write_ee(fmc, off, buf, count);
+}
+
static struct bin_attribute fmc_eeprom_attr = {
- .attr = { .name = "eeprom", .mode = S_IRUGO, },
+ .attr = { .name = "eeprom", .mode = S_IRUGO | S_IWUSR, },
.size = 8192, /* more or less standard */
.read = fmc_read_eeprom,
+ .write = fmc_write_eeprom,
};
/*
@@ -154,7 +167,7 @@ int fmc_device_register_n(struct fmc_device **devs, int n)
ret = -EINVAL;
break;
}
- if (fmc->flags == FMC_DEVICE_NO_MEZZANINE) {
+ if (fmc->flags & FMC_DEVICE_NO_MEZZANINE) {
dev_info(fmc->hwdev, "absent mezzanine in slot %d\n",
fmc->slot_id);
continue;
@@ -189,9 +202,6 @@ int fmc_device_register_n(struct fmc_device **devs, int n)
for (i = 0; i < n; i++) {
fmc = devarray[i];
- if (fmc->flags == FMC_DEVICE_NO_MEZZANINE)
- continue; /* dev_info already done above */
-
fmc->nr_slots = n; /* each slot must know how many are there */
fmc->devarray = devarray;
@@ -263,8 +273,6 @@ void fmc_device_unregister_n(struct fmc_device **devs, int n)
kfree(devs[0]->devarray);
for (i = 0; i < n; i++) {
- if (devs[i]->flags == FMC_DEVICE_NO_MEZZANINE)
- continue;
sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr);
device_del(&devs[i]->dev);
fmc_free_id_info(devs[i]);
diff --git a/drivers/fmc/fmc-sdb.c b/drivers/fmc/fmc-sdb.c
index 79adc39221ea..4603fdb74465 100644
--- a/drivers/fmc/fmc-sdb.c
+++ b/drivers/fmc/fmc-sdb.c
@@ -150,23 +150,36 @@ int fmc_reprogram(struct fmc_device *fmc, struct fmc_driver *d, char *gw,
}
EXPORT_SYMBOL(fmc_reprogram);
+static char *__strip_trailing_space(char *buf, char *str, int len)
+{
+ int i = len - 1;
+
+ memcpy(buf, str, len);
+ while(i >= 0 && buf[i] == ' ')
+ buf[i--] = '\0';
+ return buf;
+}
+
+#define __sdb_string(buf, field) ({ \
+ BUILD_BUG_ON(sizeof(buf) < sizeof(field)); \
+ __strip_trailing_space(buf, (void *)(field), sizeof(field)); \
+ })
+
static void __fmc_show_sdb_tree(const struct fmc_device *fmc,
const struct sdb_array *arr)
{
+ unsigned long base = arr->baseaddr;
int i, j, n = arr->len, level = arr->level;
- const struct sdb_array *ap;
+ char buf[64];
for (i = 0; i < n; i++) {
- unsigned long base;
union sdb_record *r;
struct sdb_product *p;
struct sdb_component *c;
r = &arr->record[i];
c = &r->dev.sdb_component;
p = &c->product;
- base = 0;
- for (ap = arr; ap; ap = ap->parent)
- base += ap->baseaddr;
+
dev_info(&fmc->dev, "SDB: ");
for (j = 0; j < level; j++)
@@ -193,8 +206,8 @@ static void __fmc_show_sdb_tree(const struct fmc_device *fmc,
p->name,
__be64_to_cpu(c->addr_first) + base);
if (IS_ERR(arr->subtree[i])) {
- printk(KERN_CONT "(bridge error %li)\n",
- PTR_ERR(arr->subtree[i]));
+ dev_info(&fmc->dev, "SDB: (bridge error %li)\n",
+ PTR_ERR(arr->subtree[i]));
break;
}
__fmc_show_sdb_tree(fmc, arr->subtree[i]);
@@ -203,10 +216,20 @@ static void __fmc_show_sdb_tree(const struct fmc_device *fmc,
printk(KERN_CONT "integration\n");
break;
case sdb_type_repo_url:
- printk(KERN_CONT "repo-url\n");
+ printk(KERN_CONT "Synthesis repository: %s\n",
+ __sdb_string(buf, r->repo_url.repo_url));
break;
case sdb_type_synthesis:
- printk(KERN_CONT "synthesis-info\n");
+ printk(KERN_CONT "Bitstream '%s' ",
+ __sdb_string(buf, r->synthesis.syn_name));
+ printk(KERN_CONT "synthesized %08x by %s ",
+ __be32_to_cpu(r->synthesis.date),
+ __sdb_string(buf, r->synthesis.user_name));
+ printk(KERN_CONT "(%s version %x), ",
+ __sdb_string(buf, r->synthesis.tool_name),
+ __be32_to_cpu(r->synthesis.tool_version));
+ printk(KERN_CONT "commit %pm\n",
+ r->synthesis.commit_id);
break;
case sdb_type_empty:
printk(KERN_CONT "empty\n");
diff --git a/drivers/fmc/fmc-write-eeprom.c b/drivers/fmc/fmc-write-eeprom.c
index ee5b47904130..9bb2cbd5c9f2 100644
--- a/drivers/fmc/fmc-write-eeprom.c
+++ b/drivers/fmc/fmc-write-eeprom.c
@@ -27,7 +27,7 @@ FMC_PARAM_BUSID(fwe_drv);
/* The "file=" is like the generic "gateware=" used elsewhere */
static char *fwe_file[FMC_MAX_CARDS];
static int fwe_file_n;
-module_param_array_named(file, fwe_file, charp, &fwe_file_n, 444);
+module_param_array_named(file, fwe_file, charp, &fwe_file_n, 0444);
static int fwe_run_tlv(struct fmc_device *fmc, const struct firmware *fw,
int write)
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 697338772b64..92d8e9a064b4 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -55,6 +55,9 @@ config GPIO_ACPI
def_bool y
depends on ACPI
+config GPIOLIB_IRQCHIP
+ bool
+
config DEBUG_GPIO
bool "Debug GPIO calls"
depends on DEBUG_KERNEL
@@ -128,6 +131,15 @@ config GPIO_GENERIC_PLATFORM
help
Say yes here to support basic platform_device memory-mapped GPIO controllers.
+config GPIO_DWAPB
+ tristate "Synopsys DesignWare APB GPIO driver"
+ select GPIO_GENERIC
+ select GENERIC_IRQ_CHIP
+ depends on OF_GPIO
+ help
+ Say Y or M here to build support for the Synopsys DesignWare APB
+ GPIO block.
+
config GPIO_IT8761E
tristate "IT8761E GPIO support"
depends on X86 # unconditional access to IO space.
@@ -145,6 +157,12 @@ config GPIO_EP93XX
depends on ARCH_EP93XX
select GPIO_GENERIC
+config GPIO_ZEVIO
+ bool "LSI ZEVIO SoC memory mapped GPIOs"
+ depends on ARM && OF_GPIO
+ help
+ Say yes here to support the GPIO controller in LSI ZEVIO SoCs.
+
config GPIO_MM_LANTIQ
bool "Lantiq Memory mapped GPIOs"
depends on LANTIQ && SOC_XWAY
@@ -228,7 +246,8 @@ config GPIO_OCTEON
config GPIO_PL061
bool "PrimeCell PL061 GPIO support"
depends on ARM_AMBA
- select GENERIC_IRQ_CHIP
+ select IRQ_DOMAIN
+ select GPIOLIB_IRQCHIP
help
Say yes here to support the PrimeCell PL061 GPIO device
@@ -275,8 +294,15 @@ config GPIO_STA2X11
Say yes here to support the STA2x11/ConneXt GPIO device.
The GPIO module has 128 GPIO pins with alternate functions.
+config GPIO_SYSCON
+ tristate "GPIO based on SYSCON"
+ depends on MFD_SYSCON && OF
+ help
+ Say yes here to support GPIO functionality though SYSCON driver.
+
config GPIO_TS5500
tristate "TS-5500 DIO blocks and compatibles"
+ depends on TS5500 || COMPILE_TEST
help
This driver supports Digital I/O exposed by pin blocks found on some
Technologic Systems platforms. It includes, but is not limited to, 3
@@ -403,6 +429,7 @@ config GPIO_GRGPIO
config GPIO_TB10X
bool
+ select GENERIC_IRQ_CHIP
select OF_GPIO
comment "I2C GPIO expanders:"
@@ -461,7 +488,7 @@ config GPIO_MC9S08DZ60
Select this to enable the MC9S08DZ60 GPIO driver
config GPIO_PCA953X
- tristate "PCA953x, PCA955x, PCA957x, TCA64xx, and MAX7310 I/O ports"
+ tristate "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports"
depends on I2C
help
Say yes here to provide access to several register-oriented
@@ -471,11 +498,15 @@ config GPIO_PCA953X
4 bits: pca9536, pca9537
8 bits: max7310, max7315, pca6107, pca9534, pca9538, pca9554,
- pca9556, pca9557, pca9574, tca6408
+ pca9556, pca9557, pca9574, tca6408, xra1202
16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575,
tca6416
+ 24 bits: tca6424
+
+ 40 bits: pca9505, pca9698
+
config GPIO_PCA953X_IRQ
bool "Interrupt controller support for PCA953x"
depends on GPIO_PCA953X=y
@@ -629,7 +660,7 @@ comment "PCI GPIO expanders:"
config GPIO_CS5535
tristate "AMD CS5535/CS5536 GPIO support"
- depends on PCI && X86 && MFD_CS5535
+ depends on MFD_CS5535
help
The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that
can be used for quite a number of things. The CS5535/6 is found on
@@ -641,7 +672,7 @@ config GPIO_BT8XX
tristate "BT8XX GPIO abuser"
depends on PCI && VIDEO_BT848=n
help
- The BT8xx frame grabber chip has 24 GPIO pins than can be abused
+ The BT8xx frame grabber chip has 24 GPIO pins that can be abused
as a cheap PCI GPIO card.
This chip can be found on Miro, Hauppauge and STB TV-cards.
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 5d50179ece16..6309aff1d806 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o
obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o
+obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
@@ -76,11 +77,11 @@ obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o
obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o
+obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o
obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o
obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o
obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o
-obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += gpio-tnetv107x.o
obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o
obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o
obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o
@@ -99,3 +100,4 @@ obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o
obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o
+obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c
index 6fc6206b38bd..b2239d678d01 100644
--- a/drivers/gpio/gpio-adnp.c
+++ b/drivers/gpio/gpio-adnp.c
@@ -408,24 +408,23 @@ static void adnp_irq_bus_unlock(struct irq_data *data)
mutex_unlock(&adnp->irq_lock);
}
-static unsigned int adnp_irq_startup(struct irq_data *data)
+static int adnp_irq_reqres(struct irq_data *data)
{
struct adnp *adnp = irq_data_get_irq_chip_data(data);
- if (gpio_lock_as_irq(&adnp->gpio, data->hwirq))
+ if (gpio_lock_as_irq(&adnp->gpio, data->hwirq)) {
dev_err(adnp->gpio.dev,
"unable to lock HW IRQ %lu for IRQ\n",
data->hwirq);
- /* Satisfy the .enable semantics by unmasking the line */
- adnp_irq_unmask(data);
+ return -EINVAL;
+ }
return 0;
}
-static void adnp_irq_shutdown(struct irq_data *data)
+static void adnp_irq_relres(struct irq_data *data)
{
struct adnp *adnp = irq_data_get_irq_chip_data(data);
- adnp_irq_mask(data);
gpio_unlock_as_irq(&adnp->gpio, data->hwirq);
}
@@ -436,8 +435,8 @@ static struct irq_chip adnp_irq_chip = {
.irq_set_type = adnp_irq_set_type,
.irq_bus_lock = adnp_irq_bus_lock,
.irq_bus_sync_unlock = adnp_irq_bus_unlock,
- .irq_startup = adnp_irq_startup,
- .irq_shutdown = adnp_irq_shutdown,
+ .irq_request_resources = adnp_irq_reqres,
+ .irq_release_resources = adnp_irq_relres,
};
static int adnp_irq_map(struct irq_domain *domain, unsigned int irq,
diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c
index 3f190e68f973..d974020b78bb 100644
--- a/drivers/gpio/gpio-adp5588.c
+++ b/drivers/gpio/gpio-adp5588.c
@@ -67,9 +67,20 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
{
struct adp5588_gpio *dev =
container_of(chip, struct adp5588_gpio, gpio_chip);
+ unsigned bank = ADP5588_BANK(off);
+ unsigned bit = ADP5588_BIT(off);
+ int val;
- return !!(adp5588_gpio_read(dev->client,
- GPIO_DAT_STAT1 + ADP5588_BANK(off)) & ADP5588_BIT(off));
+ mutex_lock(&dev->lock);
+
+ if (dev->dir[bank] & bit)
+ val = dev->dat_out[bank];
+ else
+ val = adp5588_gpio_read(dev->client, GPIO_DAT_STAT1 + bank);
+
+ mutex_unlock(&dev->lock);
+
+ return !!(val & bit);
}
static void adp5588_gpio_set_value(struct gpio_chip *chip,
@@ -386,6 +397,7 @@ static int adp5588_gpio_probe(struct i2c_client *client,
gc->ngpio = ADP5588_MAXGPIO;
gc->label = client->name;
gc->owner = THIS_MODULE;
+ gc->names = pdata->names;
mutex_init(&dev->lock);
diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c
index 233d088ac59f..3f6b33ce9bd4 100644
--- a/drivers/gpio/gpio-bcm-kona.c
+++ b/drivers/gpio/gpio-bcm-kona.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2013 Broadcom Corporation
+ * Copyright (C) 2012-2014 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
@@ -28,6 +28,10 @@
#define GPIO_BANK(gpio) ((gpio) >> 5)
#define GPIO_BIT(gpio) ((gpio) & (GPIO_PER_BANK - 1))
+/* There is a GPIO control register for each GPIO */
+#define GPIO_CONTROL(gpio) (0x00000100 + ((gpio) << 2))
+
+/* The remaining registers are per GPIO bank */
#define GPIO_OUT_STATUS(bank) (0x00000000 + ((bank) << 2))
#define GPIO_IN_STATUS(bank) (0x00000020 + ((bank) << 2))
#define GPIO_OUT_SET(bank) (0x00000040 + ((bank) << 2))
@@ -35,7 +39,6 @@
#define GPIO_INT_STATUS(bank) (0x00000080 + ((bank) << 2))
#define GPIO_INT_MASK(bank) (0x000000a0 + ((bank) << 2))
#define GPIO_INT_MSKCLR(bank) (0x000000c0 + ((bank) << 2))
-#define GPIO_CONTROL(bank) (0x00000100 + ((bank) << 2))
#define GPIO_PWD_STATUS(bank) (0x00000500 + ((bank) << 2))
#define GPIO_GPPWR_OFFSET 0x00000520
@@ -80,22 +83,43 @@ static inline struct bcm_kona_gpio *to_kona_gpio(struct gpio_chip *chip)
return container_of(chip, struct bcm_kona_gpio, gpio_chip);
}
-static void bcm_kona_gpio_set_lockcode_bank(void __iomem *reg_base,
- int bank_id, int lockcode)
+static inline void bcm_kona_gpio_write_lock_regs(void __iomem *reg_base,
+ int bank_id, u32 lockcode)
{
writel(BCM_GPIO_PASSWD, reg_base + GPIO_GPPWR_OFFSET);
writel(lockcode, reg_base + GPIO_PWD_STATUS(bank_id));
}
-static inline void bcm_kona_gpio_lock_bank(void __iomem *reg_base, int bank_id)
+static void bcm_kona_gpio_lock_gpio(struct bcm_kona_gpio *kona_gpio,
+ unsigned gpio)
{
- bcm_kona_gpio_set_lockcode_bank(reg_base, bank_id, LOCK_CODE);
+ u32 val;
+ unsigned long flags;
+ int bank_id = GPIO_BANK(gpio);
+
+ spin_lock_irqsave(&kona_gpio->lock, flags);
+
+ val = readl(kona_gpio->reg_base + GPIO_PWD_STATUS(bank_id));
+ val |= BIT(gpio);
+ bcm_kona_gpio_write_lock_regs(kona_gpio->reg_base, bank_id, val);
+
+ spin_unlock_irqrestore(&kona_gpio->lock, flags);
}
-static inline void bcm_kona_gpio_unlock_bank(void __iomem *reg_base,
- int bank_id)
+static void bcm_kona_gpio_unlock_gpio(struct bcm_kona_gpio *kona_gpio,
+ unsigned gpio)
{
- bcm_kona_gpio_set_lockcode_bank(reg_base, bank_id, UNLOCK_CODE);
+ u32 val;
+ unsigned long flags;
+ int bank_id = GPIO_BANK(gpio);
+
+ spin_lock_irqsave(&kona_gpio->lock, flags);
+
+ val = readl(kona_gpio->reg_base + GPIO_PWD_STATUS(bank_id));
+ val &= ~BIT(gpio);
+ bcm_kona_gpio_write_lock_regs(kona_gpio->reg_base, bank_id, val);
+
+ spin_unlock_irqrestore(&kona_gpio->lock, flags);
}
static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
@@ -110,7 +134,6 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
kona_gpio = to_kona_gpio(chip);
reg_base = kona_gpio->reg_base;
spin_lock_irqsave(&kona_gpio->lock, flags);
- bcm_kona_gpio_unlock_bank(reg_base, bank_id);
/* determine the GPIO pin direction */
val = readl(reg_base + GPIO_CONTROL(gpio));
@@ -127,7 +150,6 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
writel(val, reg_base + reg_offset);
out:
- bcm_kona_gpio_lock_bank(reg_base, bank_id);
spin_unlock_irqrestore(&kona_gpio->lock, flags);
}
@@ -143,7 +165,6 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio)
kona_gpio = to_kona_gpio(chip);
reg_base = kona_gpio->reg_base;
spin_lock_irqsave(&kona_gpio->lock, flags);
- bcm_kona_gpio_unlock_bank(reg_base, bank_id);
/* determine the GPIO pin direction */
val = readl(reg_base + GPIO_CONTROL(gpio));
@@ -154,32 +175,43 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio)
GPIO_IN_STATUS(bank_id) : GPIO_OUT_STATUS(bank_id);
val = readl(reg_base + reg_offset);
- bcm_kona_gpio_lock_bank(reg_base, bank_id);
spin_unlock_irqrestore(&kona_gpio->lock, flags);
/* return the specified bit status */
return !!(val & BIT(bit));
}
+static int bcm_kona_gpio_request(struct gpio_chip *chip, unsigned gpio)
+{
+ struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip);
+
+ bcm_kona_gpio_unlock_gpio(kona_gpio, gpio);
+ return 0;
+}
+
+static void bcm_kona_gpio_free(struct gpio_chip *chip, unsigned gpio)
+{
+ struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip);
+
+ bcm_kona_gpio_lock_gpio(kona_gpio, gpio);
+}
+
static int bcm_kona_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{
struct bcm_kona_gpio *kona_gpio;
void __iomem *reg_base;
u32 val;
unsigned long flags;
- int bank_id = GPIO_BANK(gpio);
kona_gpio = to_kona_gpio(chip);
reg_base = kona_gpio->reg_base;
spin_lock_irqsave(&kona_gpio->lock, flags);
- bcm_kona_gpio_unlock_bank(reg_base, bank_id);
val = readl(reg_base + GPIO_CONTROL(gpio));
val &= ~GPIO_GPCTR0_IOTR_MASK;
val |= GPIO_GPCTR0_IOTR_CMD_INPUT;
writel(val, reg_base + GPIO_CONTROL(gpio));
- bcm_kona_gpio_lock_bank(reg_base, bank_id);
spin_unlock_irqrestore(&kona_gpio->lock, flags);
return 0;
@@ -198,7 +230,6 @@ static int bcm_kona_gpio_direction_output(struct gpio_chip *chip,
kona_gpio = to_kona_gpio(chip);
reg_base = kona_gpio->reg_base;
spin_lock_irqsave(&kona_gpio->lock, flags);
- bcm_kona_gpio_unlock_bank(reg_base, bank_id);
val = readl(reg_base + GPIO_CONTROL(gpio));
val &= ~GPIO_GPCTR0_IOTR_MASK;
@@ -210,7 +241,6 @@ static int bcm_kona_gpio_direction_output(struct gpio_chip *chip,
val |= BIT(bit);
writel(val, reg_base + reg_offset);
- bcm_kona_gpio_lock_bank(reg_base, bank_id);
spin_unlock_irqrestore(&kona_gpio->lock, flags);
return 0;
@@ -233,7 +263,6 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio,
void __iomem *reg_base;
u32 val, res;
unsigned long flags;
- int bank_id = GPIO_BANK(gpio);
kona_gpio = to_kona_gpio(chip);
reg_base = kona_gpio->reg_base;
@@ -257,7 +286,6 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio,
/* spin lock for read-modify-write of the GPIO register */
spin_lock_irqsave(&kona_gpio->lock, flags);
- bcm_kona_gpio_unlock_bank(reg_base, bank_id);
val = readl(reg_base + GPIO_CONTROL(gpio));
val &= ~GPIO_GPCTR0_DBR_MASK;
@@ -272,7 +300,6 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio,
writel(val, reg_base + GPIO_CONTROL(gpio));
- bcm_kona_gpio_lock_bank(reg_base, bank_id);
spin_unlock_irqrestore(&kona_gpio->lock, flags);
return 0;
@@ -281,6 +308,8 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio,
static struct gpio_chip template_chip = {
.label = "bcm-kona-gpio",
.owner = THIS_MODULE,
+ .request = bcm_kona_gpio_request,
+ .free = bcm_kona_gpio_free,
.direction_input = bcm_kona_gpio_direction_input,
.get = bcm_kona_gpio_get,
.direction_output = bcm_kona_gpio_direction_output,
@@ -294,7 +323,7 @@ static void bcm_kona_gpio_irq_ack(struct irq_data *d)
{
struct bcm_kona_gpio *kona_gpio;
void __iomem *reg_base;
- int gpio = d->hwirq;
+ unsigned gpio = d->hwirq;
int bank_id = GPIO_BANK(gpio);
int bit = GPIO_BIT(gpio);
u32 val;
@@ -303,13 +332,11 @@ static void bcm_kona_gpio_irq_ack(struct irq_data *d)
kona_gpio = irq_data_get_irq_chip_data(d);
reg_base = kona_gpio->reg_base;
spin_lock_irqsave(&kona_gpio->lock, flags);
- bcm_kona_gpio_unlock_bank(reg_base, bank_id);
val = readl(reg_base + GPIO_INT_STATUS(bank_id));
val |= BIT(bit);
writel(val, reg_base + GPIO_INT_STATUS(bank_id));
- bcm_kona_gpio_lock_bank(reg_base, bank_id);
spin_unlock_irqrestore(&kona_gpio->lock, flags);
}
@@ -317,7 +344,7 @@ static void bcm_kona_gpio_irq_mask(struct irq_data *d)
{
struct bcm_kona_gpio *kona_gpio;
void __iomem *reg_base;
- int gpio = d->hwirq;
+ unsigned gpio = d->hwirq;
int bank_id = GPIO_BANK(gpio);
int bit = GPIO_BIT(gpio);
u32 val;
@@ -326,13 +353,11 @@ static void bcm_kona_gpio_irq_mask(struct irq_data *d)
kona_gpio = irq_data_get_irq_chip_data(d);
reg_base = kona_gpio->reg_base;
spin_lock_irqsave(&kona_gpio->lock, flags);
- bcm_kona_gpio_unlock_bank(reg_base, bank_id);
val = readl(reg_base + GPIO_INT_MASK(bank_id));
val |= BIT(bit);
writel(val, reg_base + GPIO_INT_MASK(bank_id));
- bcm_kona_gpio_lock_bank(reg_base, bank_id);
spin_unlock_irqrestore(&kona_gpio->lock, flags);
}
@@ -340,7 +365,7 @@ static void bcm_kona_gpio_irq_unmask(struct irq_data *d)
{
struct bcm_kona_gpio *kona_gpio;
void __iomem *reg_base;
- int gpio = d->hwirq;
+ unsigned gpio = d->hwirq;
int bank_id = GPIO_BANK(gpio);
int bit = GPIO_BIT(gpio);
u32 val;
@@ -349,13 +374,11 @@ static void bcm_kona_gpio_irq_unmask(struct irq_data *d)
kona_gpio = irq_data_get_irq_chip_data(d);
reg_base = kona_gpio->reg_base;
spin_lock_irqsave(&kona_gpio->lock, flags);
- bcm_kona_gpio_unlock_bank(reg_base, bank_id);
val = readl(reg_base + GPIO_INT_MSKCLR(bank_id));
val |= BIT(bit);
writel(val, reg_base + GPIO_INT_MSKCLR(bank_id));
- bcm_kona_gpio_lock_bank(reg_base, bank_id);
spin_unlock_irqrestore(&kona_gpio->lock, flags);
}
@@ -363,11 +386,10 @@ static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
struct bcm_kona_gpio *kona_gpio;
void __iomem *reg_base;
- int gpio = d->hwirq;
+ unsigned gpio = d->hwirq;
u32 lvl_type;
u32 val;
unsigned long flags;
- int bank_id = GPIO_BANK(gpio);
kona_gpio = irq_data_get_irq_chip_data(d);
reg_base = kona_gpio->reg_base;
@@ -394,14 +416,12 @@ static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type)
}
spin_lock_irqsave(&kona_gpio->lock, flags);
- bcm_kona_gpio_unlock_bank(reg_base, bank_id);
val = readl(reg_base + GPIO_CONTROL(gpio));
val &= ~GPIO_GPCTR0_ITR_MASK;
val |= lvl_type << GPIO_GPCTR0_ITR_SHIFT;
writel(val, reg_base + GPIO_CONTROL(gpio));
- bcm_kona_gpio_lock_bank(reg_base, bank_id);
spin_unlock_irqrestore(&kona_gpio->lock, flags);
return 0;
@@ -424,7 +444,6 @@ static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
*/
reg_base = bank->kona_gpio->reg_base;
bank_id = bank->id;
- bcm_kona_gpio_unlock_bank(reg_base, bank_id);
while ((sta = readl(reg_base + GPIO_INT_STATUS(bank_id)) &
(~(readl(reg_base + GPIO_INT_MASK(bank_id)))))) {
@@ -444,28 +463,26 @@ static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
}
}
- bcm_kona_gpio_lock_bank(reg_base, bank_id);
-
chained_irq_exit(chip, desc);
}
-static unsigned int bcm_kona_gpio_irq_startup(struct irq_data *d)
+static int bcm_kona_gpio_irq_reqres(struct irq_data *d)
{
struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d);
- if (gpio_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq))
+ if (gpio_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq)) {
dev_err(kona_gpio->gpio_chip.dev,
"unable to lock HW IRQ %lu for IRQ\n",
d->hwirq);
- bcm_kona_gpio_irq_unmask(d);
+ return -EINVAL;
+ }
return 0;
}
-static void bcm_kona_gpio_irq_shutdown(struct irq_data *d)
+static void bcm_kona_gpio_irq_relres(struct irq_data *d)
{
struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d);
- bcm_kona_gpio_irq_mask(d);
gpio_unlock_as_irq(&kona_gpio->gpio_chip, d->hwirq);
}
@@ -475,8 +492,8 @@ static struct irq_chip bcm_gpio_irq_chip = {
.irq_mask = bcm_kona_gpio_irq_mask,
.irq_unmask = bcm_kona_gpio_irq_unmask,
.irq_set_type = bcm_kona_gpio_irq_set_type,
- .irq_startup = bcm_kona_gpio_irq_startup,
- .irq_shutdown = bcm_kona_gpio_irq_shutdown,
+ .irq_request_resources = bcm_kona_gpio_irq_reqres,
+ .irq_release_resources = bcm_kona_gpio_irq_relres,
};
static struct __initconst of_device_id bcm_kona_gpio_of_match[] = {
@@ -531,10 +548,12 @@ static void bcm_kona_gpio_reset(struct bcm_kona_gpio *kona_gpio)
reg_base = kona_gpio->reg_base;
/* disable interrupts and clear status */
for (i = 0; i < kona_gpio->num_bank; i++) {
- bcm_kona_gpio_unlock_bank(reg_base, i);
+ /* Unlock the entire bank first */
+ bcm_kona_gpio_write_lock_regs(kona_gpio, i, UNLOCK_CODE);
writel(0xffffffff, reg_base + GPIO_INT_MASK(i));
writel(0xffffffff, reg_base + GPIO_INT_STATUS(i));
- bcm_kona_gpio_lock_bank(reg_base, i);
+ /* Now re-lock the bank */
+ bcm_kona_gpio_write_lock_regs(kona_gpio, i, LOCK_CODE);
}
}
@@ -657,6 +676,6 @@ static struct platform_driver bcm_kona_gpio_driver = {
module_platform_driver(bcm_kona_gpio_driver);
-MODULE_AUTHOR("Broadcom");
+MODULE_AUTHOR("Broadcom Corporation <bcm-kernel-feedback-list@broadcom.com>");
MODULE_DESCRIPTION("Broadcom Kona GPIO Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c
index d3550274b8f7..e1e861239e95 100644
--- a/drivers/gpio/gpio-clps711x.c
+++ b/drivers/gpio/gpio-clps711x.c
@@ -65,6 +65,7 @@ static int clps711x_gpio_probe(struct platform_device *pdev)
}
bgc->gc.base = id * 8;
+ bgc->gc.owner = THIS_MODULE;
platform_set_drvdata(pdev, bgc);
return gpiochip_add(&bgc->gc);
@@ -97,3 +98,4 @@ module_platform_driver(clps711x_gpio_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
MODULE_DESCRIPTION("CLPS711X GPIO driver");
+MODULE_ALIAS("platform:clps711x-gpio");
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index 7629b4f12b7f..339f9dac591b 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -37,6 +37,8 @@ struct davinci_gpio_regs {
u32 intstat;
};
+typedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq);
+
#define BINTEN 0x8 /* GPIO Interrupt Per-Bank Enable Register */
#define chip2controller(chip) \
@@ -172,6 +174,27 @@ of_err:
return NULL;
}
+#ifdef CONFIG_OF_GPIO
+static int davinci_gpio_of_xlate(struct gpio_chip *gc,
+ const struct of_phandle_args *gpiospec,
+ u32 *flags)
+{
+ struct davinci_gpio_controller *chips = dev_get_drvdata(gc->dev);
+ struct davinci_gpio_platform_data *pdata = dev_get_platdata(gc->dev);
+
+ if (gpiospec->args[0] > pdata->ngpio)
+ return -EINVAL;
+
+ if (gc != &chips[gpiospec->args[0] / 32].chip)
+ return -EINVAL;
+
+ if (flags)
+ *flags = gpiospec->args[1];
+
+ return gpiospec->args[0] % 32;
+}
+#endif
+
static int davinci_gpio_probe(struct platform_device *pdev)
{
int i, base;
@@ -236,6 +259,9 @@ static int davinci_gpio_probe(struct platform_device *pdev)
chips[i].chip.ngpio = 32;
#ifdef CONFIG_OF_GPIO
+ chips[i].chip.of_gpio_n_cells = 2;
+ chips[i].chip.of_xlate = davinci_gpio_of_xlate;
+ chips[i].chip.dev = dev;
chips[i].chip.of_node = dev->of_node;
#endif
spin_lock_init(&chips[i].lock);
@@ -413,6 +439,26 @@ static const struct irq_domain_ops davinci_gpio_irq_ops = {
.xlate = irq_domain_xlate_onetwocell,
};
+static struct irq_chip *davinci_gpio_get_irq_chip(unsigned int irq)
+{
+ static struct irq_chip_type gpio_unbanked;
+
+ gpio_unbanked = *container_of(irq_get_chip(irq),
+ struct irq_chip_type, chip);
+
+ return &gpio_unbanked.chip;
+};
+
+static struct irq_chip *keystone_gpio_get_irq_chip(unsigned int irq)
+{
+ static struct irq_chip gpio_unbanked;
+
+ gpio_unbanked = *irq_get_chip(irq);
+ return &gpio_unbanked;
+};
+
+static const struct of_device_id davinci_gpio_ids[];
+
/*
* NOTE: for suspend/resume, probably best to make a platform_device with
* suspend_late/resume_resume calls hooking into results of the set_wake()
@@ -423,7 +469,8 @@ static const struct irq_domain_ops davinci_gpio_irq_ops = {
static int davinci_gpio_irq_setup(struct platform_device *pdev)
{
- unsigned gpio, irq, bank;
+ unsigned gpio, bank;
+ int irq;
struct clk *clk;
u32 binten = 0;
unsigned ngpio, bank_irq;
@@ -433,6 +480,18 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
struct davinci_gpio_platform_data *pdata = dev->platform_data;
struct davinci_gpio_regs __iomem *g;
struct irq_domain *irq_domain = NULL;
+ const struct of_device_id *match;
+ struct irq_chip *irq_chip;
+ gpio_get_irq_chip_cb_t gpio_get_irq_chip;
+
+ /*
+ * Use davinci_gpio_get_irq_chip by default to handle non DT cases
+ */
+ gpio_get_irq_chip = davinci_gpio_get_irq_chip;
+ match = of_match_device(of_match_ptr(davinci_gpio_ids),
+ dev);
+ if (match)
+ gpio_get_irq_chip = (gpio_get_irq_chip_cb_t)match->data;
ngpio = pdata->ngpio;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -489,8 +548,6 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
* IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs.
*/
if (pdata->gpio_unbanked) {
- static struct irq_chip_type gpio_unbanked;
-
/* pass "bank 0" GPIO IRQs to AINTC */
chips[0].chip.to_irq = gpio_to_irq_unbanked;
chips[0].gpio_irq = bank_irq;
@@ -499,10 +556,9 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
/* AINTC handles mask/unmask; GPIO handles triggering */
irq = bank_irq;
- gpio_unbanked = *container_of(irq_get_chip(irq),
- struct irq_chip_type, chip);
- gpio_unbanked.chip.name = "GPIO-AINTC";
- gpio_unbanked.chip.irq_set_type = gpio_irq_type_unbanked;
+ irq_chip = gpio_get_irq_chip(irq);
+ irq_chip->name = "GPIO-AINTC";
+ irq_chip->irq_set_type = gpio_irq_type_unbanked;
/* default trigger: both edges */
g = gpio2regs(0);
@@ -511,7 +567,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
/* set the direct IRQs up to use that irqchip */
for (gpio = 0; gpio < pdata->gpio_unbanked; gpio++, irq++) {
- irq_set_chip(irq, &gpio_unbanked.chip);
+ irq_set_chip(irq, irq_chip);
irq_set_handler_data(irq, &chips[gpio / 32]);
irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH);
}
@@ -554,7 +610,8 @@ done:
#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id davinci_gpio_ids[] = {
- { .compatible = "ti,dm6441-gpio", },
+ { .compatible = "ti,keystone-gpio", keystone_gpio_get_irq_chip},
+ { .compatible = "ti,dm6441-gpio", davinci_gpio_get_irq_chip},
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, davinci_gpio_ids);
diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
new file mode 100644
index 000000000000..ed5711f77e2d
--- /dev/null
+++ b/drivers/gpio/gpio-dwapb.c
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 2011 Jamie Iles
+ *
+ * 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.
+ *
+ * All enquiries to support@picochip.com
+ */
+#include <linux/basic_mmio_gpio.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#define GPIO_SWPORTA_DR 0x00
+#define GPIO_SWPORTA_DDR 0x04
+#define GPIO_SWPORTB_DR 0x0c
+#define GPIO_SWPORTB_DDR 0x10
+#define GPIO_SWPORTC_DR 0x18
+#define GPIO_SWPORTC_DDR 0x1c
+#define GPIO_SWPORTD_DR 0x24
+#define GPIO_SWPORTD_DDR 0x28
+#define GPIO_INTEN 0x30
+#define GPIO_INTMASK 0x34
+#define GPIO_INTTYPE_LEVEL 0x38
+#define GPIO_INT_POLARITY 0x3c
+#define GPIO_INTSTATUS 0x40
+#define GPIO_PORTA_EOI 0x4c
+#define GPIO_EXT_PORTA 0x50
+#define GPIO_EXT_PORTB 0x54
+#define GPIO_EXT_PORTC 0x58
+#define GPIO_EXT_PORTD 0x5c
+
+#define DWAPB_MAX_PORTS 4
+#define GPIO_EXT_PORT_SIZE (GPIO_EXT_PORTB - GPIO_EXT_PORTA)
+#define GPIO_SWPORT_DR_SIZE (GPIO_SWPORTB_DR - GPIO_SWPORTA_DR)
+#define GPIO_SWPORT_DDR_SIZE (GPIO_SWPORTB_DDR - GPIO_SWPORTA_DDR)
+
+struct dwapb_gpio;
+
+struct dwapb_gpio_port {
+ struct bgpio_chip bgc;
+ bool is_registered;
+ struct dwapb_gpio *gpio;
+};
+
+struct dwapb_gpio {
+ struct device *dev;
+ void __iomem *regs;
+ struct dwapb_gpio_port *ports;
+ unsigned int nr_ports;
+ struct irq_domain *domain;
+};
+
+static int dwapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+ struct dwapb_gpio_port *port = container_of(bgc, struct
+ dwapb_gpio_port, bgc);
+ struct dwapb_gpio *gpio = port->gpio;
+
+ return irq_find_mapping(gpio->domain, offset);
+}
+
+static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs)
+{
+ u32 v = readl(gpio->regs + GPIO_INT_POLARITY);
+
+ if (gpio_get_value(gpio->ports[0].bgc.gc.base + offs))
+ v &= ~BIT(offs);
+ else
+ v |= BIT(offs);
+
+ writel(v, gpio->regs + GPIO_INT_POLARITY);
+}
+
+static void dwapb_irq_handler(u32 irq, struct irq_desc *desc)
+{
+ struct dwapb_gpio *gpio = irq_get_handler_data(irq);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ u32 irq_status = readl_relaxed(gpio->regs + GPIO_INTSTATUS);
+
+ while (irq_status) {
+ int hwirq = fls(irq_status) - 1;
+ int gpio_irq = irq_find_mapping(gpio->domain, hwirq);
+
+ generic_handle_irq(gpio_irq);
+ irq_status &= ~BIT(hwirq);
+
+ if ((irq_get_trigger_type(gpio_irq) & IRQ_TYPE_SENSE_MASK)
+ == IRQ_TYPE_EDGE_BOTH)
+ dwapb_toggle_trigger(gpio, hwirq);
+ }
+
+ if (chip->irq_eoi)
+ chip->irq_eoi(irq_desc_get_irq_data(desc));
+}
+
+static void dwapb_irq_enable(struct irq_data *d)
+{
+ struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
+ struct dwapb_gpio *gpio = igc->private;
+ struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&bgc->lock, flags);
+ val = readl(gpio->regs + GPIO_INTEN);
+ val |= BIT(d->hwirq);
+ writel(val, gpio->regs + GPIO_INTEN);
+ spin_unlock_irqrestore(&bgc->lock, flags);
+}
+
+static void dwapb_irq_disable(struct irq_data *d)
+{
+ struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
+ struct dwapb_gpio *gpio = igc->private;
+ struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&bgc->lock, flags);
+ val = readl(gpio->regs + GPIO_INTEN);
+ val &= ~BIT(d->hwirq);
+ writel(val, gpio->regs + GPIO_INTEN);
+ spin_unlock_irqrestore(&bgc->lock, flags);
+}
+
+static int dwapb_irq_reqres(struct irq_data *d)
+{
+ struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
+ struct dwapb_gpio *gpio = igc->private;
+ struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+
+ if (gpio_lock_as_irq(&bgc->gc, irqd_to_hwirq(d))) {
+ dev_err(gpio->dev, "unable to lock HW IRQ %lu for IRQ\n",
+ irqd_to_hwirq(d));
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void dwapb_irq_relres(struct irq_data *d)
+{
+ struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
+ struct dwapb_gpio *gpio = igc->private;
+ struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+
+ gpio_unlock_as_irq(&bgc->gc, irqd_to_hwirq(d));
+}
+
+static int dwapb_irq_set_type(struct irq_data *d, u32 type)
+{
+ struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
+ struct dwapb_gpio *gpio = igc->private;
+ struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+ int bit = d->hwirq;
+ unsigned long level, polarity, flags;
+
+ if (type & ~(IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
+ IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
+ return -EINVAL;
+
+ spin_lock_irqsave(&bgc->lock, flags);
+ level = readl(gpio->regs + GPIO_INTTYPE_LEVEL);
+ polarity = readl(gpio->regs + GPIO_INT_POLARITY);
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_BOTH:
+ level |= BIT(bit);
+ dwapb_toggle_trigger(gpio, bit);
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ level |= BIT(bit);
+ polarity |= BIT(bit);
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ level |= BIT(bit);
+ polarity &= ~BIT(bit);
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ level &= ~BIT(bit);
+ polarity |= BIT(bit);
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ level &= ~BIT(bit);
+ polarity &= ~BIT(bit);
+ break;
+ }
+
+ writel(level, gpio->regs + GPIO_INTTYPE_LEVEL);
+ writel(polarity, gpio->regs + GPIO_INT_POLARITY);
+ spin_unlock_irqrestore(&bgc->lock, flags);
+
+ return 0;
+}
+
+static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
+ struct dwapb_gpio_port *port)
+{
+ struct gpio_chip *gc = &port->bgc.gc;
+ struct device_node *node = gc->of_node;
+ struct irq_chip_generic *irq_gc;
+ unsigned int hwirq, ngpio = gc->ngpio;
+ struct irq_chip_type *ct;
+ int err, irq;
+
+ irq = irq_of_parse_and_map(node, 0);
+ if (!irq) {
+ dev_warn(gpio->dev, "no irq for bank %s\n",
+ port->bgc.gc.of_node->full_name);
+ return;
+ }
+
+ gpio->domain = irq_domain_add_linear(node, ngpio,
+ &irq_generic_chip_ops, gpio);
+ if (!gpio->domain)
+ return;
+
+ err = irq_alloc_domain_generic_chips(gpio->domain, ngpio, 1,
+ "gpio-dwapb", handle_level_irq,
+ IRQ_NOREQUEST, 0,
+ IRQ_GC_INIT_NESTED_LOCK);
+ if (err) {
+ dev_info(gpio->dev, "irq_alloc_domain_generic_chips failed\n");
+ irq_domain_remove(gpio->domain);
+ gpio->domain = NULL;
+ return;
+ }
+
+ irq_gc = irq_get_domain_generic_chip(gpio->domain, 0);
+ if (!irq_gc) {
+ irq_domain_remove(gpio->domain);
+ gpio->domain = NULL;
+ return;
+ }
+
+ irq_gc->reg_base = gpio->regs;
+ irq_gc->private = gpio;
+
+ ct = irq_gc->chip_types;
+ ct->chip.irq_ack = irq_gc_ack_set_bit;
+ ct->chip.irq_mask = irq_gc_mask_set_bit;
+ ct->chip.irq_unmask = irq_gc_mask_clr_bit;
+ ct->chip.irq_set_type = dwapb_irq_set_type;
+ ct->chip.irq_enable = dwapb_irq_enable;
+ ct->chip.irq_disable = dwapb_irq_disable;
+ ct->chip.irq_request_resources = dwapb_irq_reqres;
+ ct->chip.irq_release_resources = dwapb_irq_relres;
+ ct->regs.ack = GPIO_PORTA_EOI;
+ ct->regs.mask = GPIO_INTMASK;
+
+ irq_setup_generic_chip(irq_gc, IRQ_MSK(port->bgc.gc.ngpio),
+ IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0);
+
+ irq_set_chained_handler(irq, dwapb_irq_handler);
+ irq_set_handler_data(irq, gpio);
+
+ for (hwirq = 0 ; hwirq < ngpio ; hwirq++)
+ irq_create_mapping(gpio->domain, hwirq);
+
+ port->bgc.gc.to_irq = dwapb_gpio_to_irq;
+}
+
+static void dwapb_irq_teardown(struct dwapb_gpio *gpio)
+{
+ struct dwapb_gpio_port *port = &gpio->ports[0];
+ struct gpio_chip *gc = &port->bgc.gc;
+ unsigned int ngpio = gc->ngpio;
+ irq_hw_number_t hwirq;
+
+ if (!gpio->domain)
+ return;
+
+ for (hwirq = 0 ; hwirq < ngpio ; hwirq++)
+ irq_dispose_mapping(irq_find_mapping(gpio->domain, hwirq));
+
+ irq_domain_remove(gpio->domain);
+ gpio->domain = NULL;
+}
+
+static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
+ struct device_node *port_np,
+ unsigned int offs)
+{
+ struct dwapb_gpio_port *port;
+ u32 port_idx, ngpio;
+ void __iomem *dat, *set, *dirout;
+ int err;
+
+ if (of_property_read_u32(port_np, "reg", &port_idx) ||
+ port_idx >= DWAPB_MAX_PORTS) {
+ dev_err(gpio->dev, "missing/invalid port index for %s\n",
+ port_np->full_name);
+ return -EINVAL;
+ }
+
+ port = &gpio->ports[offs];
+ port->gpio = gpio;
+
+ if (of_property_read_u32(port_np, "snps,nr-gpios", &ngpio)) {
+ dev_info(gpio->dev, "failed to get number of gpios for %s\n",
+ port_np->full_name);
+ ngpio = 32;
+ }
+
+ dat = gpio->regs + GPIO_EXT_PORTA + (port_idx * GPIO_EXT_PORT_SIZE);
+ set = gpio->regs + GPIO_SWPORTA_DR + (port_idx * GPIO_SWPORT_DR_SIZE);
+ dirout = gpio->regs + GPIO_SWPORTA_DDR +
+ (port_idx * GPIO_SWPORT_DDR_SIZE);
+
+ err = bgpio_init(&port->bgc, gpio->dev, 4, dat, set, NULL, dirout,
+ NULL, false);
+ if (err) {
+ dev_err(gpio->dev, "failed to init gpio chip for %s\n",
+ port_np->full_name);
+ return err;
+ }
+
+ port->bgc.gc.ngpio = ngpio;
+ port->bgc.gc.of_node = port_np;
+
+ /*
+ * Only port A can provide interrupts in all configurations of the IP.
+ */
+ if (port_idx == 0 &&
+ of_property_read_bool(port_np, "interrupt-controller"))
+ dwapb_configure_irqs(gpio, port);
+
+ err = gpiochip_add(&port->bgc.gc);
+ if (err)
+ dev_err(gpio->dev, "failed to register gpiochip for %s\n",
+ port_np->full_name);
+ else
+ port->is_registered = true;
+
+ return err;
+}
+
+static void dwapb_gpio_unregister(struct dwapb_gpio *gpio)
+{
+ unsigned int m;
+
+ for (m = 0; m < gpio->nr_ports; ++m)
+ if (gpio->ports[m].is_registered)
+ WARN_ON(gpiochip_remove(&gpio->ports[m].bgc.gc));
+}
+
+static int dwapb_gpio_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct dwapb_gpio *gpio;
+ struct device_node *np;
+ int err;
+ unsigned int offs = 0;
+
+ gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+ if (!gpio)
+ return -ENOMEM;
+ gpio->dev = &pdev->dev;
+
+ gpio->nr_ports = of_get_child_count(pdev->dev.of_node);
+ if (!gpio->nr_ports) {
+ err = -EINVAL;
+ goto out_err;
+ }
+ gpio->ports = devm_kzalloc(&pdev->dev, gpio->nr_ports *
+ sizeof(*gpio->ports), GFP_KERNEL);
+ if (!gpio->ports) {
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ gpio->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(gpio->regs)) {
+ err = PTR_ERR(gpio->regs);
+ goto out_err;
+ }
+
+ for_each_child_of_node(pdev->dev.of_node, np) {
+ err = dwapb_gpio_add_port(gpio, np, offs++);
+ if (err)
+ goto out_unregister;
+ }
+ platform_set_drvdata(pdev, gpio);
+
+ return 0;
+
+out_unregister:
+ dwapb_gpio_unregister(gpio);
+ dwapb_irq_teardown(gpio);
+
+out_err:
+ return err;
+}
+
+static int dwapb_gpio_remove(struct platform_device *pdev)
+{
+ struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
+
+ dwapb_gpio_unregister(gpio);
+ dwapb_irq_teardown(gpio);
+
+ return 0;
+}
+
+static const struct of_device_id dwapb_of_match[] = {
+ { .compatible = "snps,dw-apb-gpio" },
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, dwapb_of_match);
+
+static struct platform_driver dwapb_gpio_driver = {
+ .driver = {
+ .name = "gpio-dwapb",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(dwapb_of_match),
+ },
+ .probe = dwapb_gpio_probe,
+ .remove = dwapb_gpio_remove,
+};
+
+module_platform_driver(dwapb_gpio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jamie Iles");
+MODULE_DESCRIPTION("Synopsys DesignWare APB GPIO driver");
diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c
index 1e98a9873967..8765bd6f48e1 100644
--- a/drivers/gpio/gpio-em.c
+++ b/drivers/gpio/gpio-em.c
@@ -99,23 +99,23 @@ static void em_gio_irq_enable(struct irq_data *d)
em_gio_write(p, GIO_IEN, BIT(irqd_to_hwirq(d)));
}
-static unsigned int em_gio_irq_startup(struct irq_data *d)
+static int em_gio_irq_reqres(struct irq_data *d)
{
struct em_gio_priv *p = irq_data_get_irq_chip_data(d);
- if (gpio_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d)))
+ if (gpio_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d))) {
dev_err(p->gpio_chip.dev,
"unable to lock HW IRQ %lu for IRQ\n",
irqd_to_hwirq(d));
- em_gio_irq_enable(d);
+ return -EINVAL;
+ }
return 0;
}
-static void em_gio_irq_shutdown(struct irq_data *d)
+static void em_gio_irq_relres(struct irq_data *d)
{
struct em_gio_priv *p = irq_data_get_irq_chip_data(d);
- em_gio_irq_disable(d);
gpio_unlock_as_irq(&p->gpio_chip, irqd_to_hwirq(d));
}
@@ -359,8 +359,8 @@ static int em_gio_probe(struct platform_device *pdev)
irq_chip->irq_mask = em_gio_irq_disable;
irq_chip->irq_unmask = em_gio_irq_enable;
irq_chip->irq_set_type = em_gio_irq_set_type;
- irq_chip->irq_startup = em_gio_irq_startup;
- irq_chip->irq_shutdown = em_gio_irq_shutdown;
+ irq_chip->irq_request_resources = em_gio_irq_reqres;
+ irq_chip->irq_release_resources = em_gio_irq_relres;
irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND;
p->irq_domain = irq_domain_add_simple(pdev->dev.of_node,
diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c
index d2196bf73847..b5dff9e742f8 100644
--- a/drivers/gpio/gpio-generic.c
+++ b/drivers/gpio/gpio-generic.c
@@ -139,7 +139,7 @@ static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
- return bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio);
+ return !!(bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio));
}
static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
@@ -488,7 +488,7 @@ static int bgpio_pdev_probe(struct platform_device *pdev)
void __iomem *dirout;
void __iomem *dirin;
unsigned long sz;
- unsigned long flags = 0;
+ unsigned long flags = pdev->id_entry->driver_data;
int err;
struct bgpio_chip *bgc;
struct bgpio_pdata *pdata = dev_get_platdata(dev);
@@ -519,9 +519,6 @@ static int bgpio_pdev_probe(struct platform_device *pdev)
if (err)
return err;
- if (!strcmp(platform_get_device_id(pdev)->name, "basic-mmio-gpio-be"))
- flags |= BGPIOF_BIG_ENDIAN;
-
bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
if (!bgc)
return -ENOMEM;
@@ -531,6 +528,8 @@ static int bgpio_pdev_probe(struct platform_device *pdev)
return err;
if (pdata) {
+ if (pdata->label)
+ bgc->gc.label = pdata->label;
bgc->gc.base = pdata->base;
if (pdata->ngpio > 0)
bgc->gc.ngpio = pdata->ngpio;
@@ -549,9 +548,14 @@ static int bgpio_pdev_remove(struct platform_device *pdev)
}
static const struct platform_device_id bgpio_id_table[] = {
- { "basic-mmio-gpio", },
- { "basic-mmio-gpio-be", },
- {},
+ {
+ .name = "basic-mmio-gpio",
+ .driver_data = 0,
+ }, {
+ .name = "basic-mmio-gpio-be",
+ .driver_data = BGPIOF_BIG_ENDIAN,
+ },
+ { }
};
MODULE_DEVICE_TABLE(platform, bgpio_id_table);
diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c
index f5bf3c38bca6..bfef20f8ab48 100644
--- a/drivers/gpio/gpio-ich.c
+++ b/drivers/gpio/gpio-ich.c
@@ -62,6 +62,13 @@ struct ichx_desc {
/* Max GPIO pins the chipset can have */
uint ngpio;
+ /* chipset registers */
+ const u8 (*regs)[3];
+ const u8 *reglen;
+
+ /* GPO_BLINK is available on this chipset */
+ bool have_blink;
+
/* Whether the chipset has GPIO in GPE0_STS in the PM IO region */
bool uses_gpe0;
@@ -71,6 +78,12 @@ struct ichx_desc {
/* Some chipsets have quirks, let these use their own request/get */
int (*request)(struct gpio_chip *chip, unsigned offset);
int (*get)(struct gpio_chip *chip, unsigned offset);
+
+ /*
+ * Some chipsets don't let reading output values on GPIO_LVL register
+ * this option allows driver caching written output values
+ */
+ bool use_outlvl_cache;
};
static struct {
@@ -82,6 +95,7 @@ static struct {
struct ichx_desc *desc; /* Pointer to chipset-specific description */
u32 orig_gpio_ctrl; /* Orig CTRL value, used to restore on exit */
u8 use_gpio; /* Which GPIO groups are usable */
+ int outlvl_cache[3]; /* cached output values */
} ichx_priv;
static int modparam_gpiobase = -1; /* dynamic */
@@ -99,13 +113,23 @@ static int ichx_write_bit(int reg, unsigned nr, int val, int verify)
spin_lock_irqsave(&ichx_priv.lock, flags);
- data = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base);
+ if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache)
+ data = ichx_priv.outlvl_cache[reg_nr];
+ else
+ data = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr],
+ ichx_priv.gpio_base);
+
if (val)
data |= 1 << bit;
else
data &= ~(1 << bit);
- ICHX_WRITE(data, ichx_regs[reg][reg_nr], ichx_priv.gpio_base);
- tmp = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base);
+ ICHX_WRITE(data, ichx_priv.desc->regs[reg][reg_nr],
+ ichx_priv.gpio_base);
+ if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache)
+ ichx_priv.outlvl_cache[reg_nr] = data;
+
+ tmp = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr],
+ ichx_priv.gpio_base);
if (verify && data != tmp)
ret = -EPERM;
@@ -123,7 +147,11 @@ static int ichx_read_bit(int reg, unsigned nr)
spin_lock_irqsave(&ichx_priv.lock, flags);
- data = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base);
+ data = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr],
+ ichx_priv.gpio_base);
+
+ if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache)
+ data = ichx_priv.outlvl_cache[reg_nr] | data;
spin_unlock_irqrestore(&ichx_priv.lock, flags);
@@ -151,7 +179,7 @@ static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
int val)
{
/* Disable blink hardware which is available for GPIOs from 0 to 31. */
- if (nr < 32)
+ if (nr < 32 && ichx_priv.desc->have_blink)
ichx_write_bit(GPO_BLINK, nr, 0, 0);
/* Set GPIO output value. */
@@ -266,6 +294,7 @@ static struct ichx_desc ich6_desc = {
.uses_gpe0 = true,
.ngpio = 50,
+ .have_blink = true,
};
/* Intel 3100 */
@@ -290,24 +319,38 @@ static struct ichx_desc i3100_desc = {
/* ICH7 and ICH8-based */
static struct ichx_desc ich7_desc = {
.ngpio = 50,
+ .have_blink = true,
+ .regs = ichx_regs,
+ .reglen = ichx_reglen,
};
/* ICH9-based */
static struct ichx_desc ich9_desc = {
.ngpio = 61,
+ .have_blink = true,
+ .regs = ichx_regs,
+ .reglen = ichx_reglen,
};
/* ICH10-based - Consumer/corporate versions have different amount of GPIO */
static struct ichx_desc ich10_cons_desc = {
.ngpio = 61,
+ .have_blink = true,
+ .regs = ichx_regs,
+ .reglen = ichx_reglen,
};
static struct ichx_desc ich10_corp_desc = {
.ngpio = 72,
+ .have_blink = true,
+ .regs = ichx_regs,
+ .reglen = ichx_reglen,
};
/* Intel 5 series, 6 series, 3400 series, and C200 series */
static struct ichx_desc intel5_desc = {
.ngpio = 76,
+ .regs = ichx_regs,
+ .reglen = ichx_reglen,
};
static int ichx_gpio_request_regions(struct resource *res_base,
@@ -318,11 +361,12 @@ static int ichx_gpio_request_regions(struct resource *res_base,
if (!res_base || !res_base->start || !res_base->end)
return -ENODEV;
- for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) {
if (!(use_gpio & (1 << i)))
continue;
- if (!request_region(res_base->start + ichx_regs[0][i],
- ichx_reglen[i], name))
+ if (!request_region(
+ res_base->start + ichx_priv.desc->regs[0][i],
+ ichx_priv.desc->reglen[i], name))
goto request_err;
}
return 0;
@@ -332,8 +376,8 @@ request_err:
for (i--; i >= 0; i--) {
if (!(use_gpio & (1 << i)))
continue;
- release_region(res_base->start + ichx_regs[0][i],
- ichx_reglen[i]);
+ release_region(res_base->start + ichx_priv.desc->regs[0][i],
+ ichx_priv.desc->reglen[i]);
}
return -EBUSY;
}
@@ -342,11 +386,11 @@ static void ichx_gpio_release_regions(struct resource *res_base, u8 use_gpio)
{
int i;
- for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) {
if (!(use_gpio & (1 << i)))
continue;
- release_region(res_base->start + ichx_regs[0][i],
- ichx_reglen[i]);
+ release_region(res_base->start + ichx_priv.desc->regs[0][i],
+ ichx_priv.desc->reglen[i]);
}
}
diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c
index d1b50ef5fab8..118a6bf455d9 100644
--- a/drivers/gpio/gpio-intel-mid.c
+++ b/drivers/gpio/gpio-intel-mid.c
@@ -1,7 +1,7 @@
/*
- * Moorestown platform Langwell chip GPIO driver
+ * Intel MID GPIO driver
*
- * Copyright (c) 2008, 2009, 2013, Intel Corporation.
+ * Copyright (c) 2008-2014 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -11,10 +11,6 @@
* but WITHOUT 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.
*/
/* Supports:
@@ -235,23 +231,23 @@ static void intel_mid_irq_mask(struct irq_data *d)
{
}
-static unsigned int intel_mid_irq_startup(struct irq_data *d)
+static int intel_mid_irq_reqres(struct irq_data *d)
{
struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d);
- if (gpio_lock_as_irq(&priv->chip, irqd_to_hwirq(d)))
+ if (gpio_lock_as_irq(&priv->chip, irqd_to_hwirq(d))) {
dev_err(priv->chip.dev,
"unable to lock HW IRQ %lu for IRQ\n",
irqd_to_hwirq(d));
- intel_mid_irq_unmask(d);
+ return -EINVAL;
+ }
return 0;
}
-static void intel_mid_irq_shutdown(struct irq_data *d)
+static void intel_mid_irq_relres(struct irq_data *d)
{
struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d);
- intel_mid_irq_mask(d);
gpio_unlock_as_irq(&priv->chip, irqd_to_hwirq(d));
}
@@ -260,8 +256,8 @@ static struct irq_chip intel_mid_irqchip = {
.irq_mask = intel_mid_irq_mask,
.irq_unmask = intel_mid_irq_unmask,
.irq_set_type = intel_mid_irq_type,
- .irq_startup = intel_mid_irq_startup,
- .irq_shutdown = intel_mid_irq_shutdown,
+ .irq_request_resources = intel_mid_irq_reqres,
+ .irq_release_resources = intel_mid_irq_relres,
};
static const struct intel_mid_gpio_ddata gpio_lincroft = {
@@ -394,8 +390,8 @@ static const struct irq_domain_ops intel_gpio_irq_ops = {
static int intel_gpio_runtime_idle(struct device *dev)
{
- pm_schedule_suspend(dev, 500);
- return -EBUSY;
+ int err = pm_schedule_suspend(dev, 500);
+ return err ?: -EBUSY;
}
static const struct dev_pm_ops intel_gpio_pm_ops = {
diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c
index c22a61be3a9c..0a5e9d3f308c 100644
--- a/drivers/gpio/gpio-iop.c
+++ b/drivers/gpio/gpio-iop.c
@@ -111,6 +111,8 @@ static int iop3xx_gpio_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
return gpiochip_add(&iop3xx_chip);
}
diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c
index 66b18535b5ae..9a82a9074a2c 100644
--- a/drivers/gpio/gpio-lynxpoint.c
+++ b/drivers/gpio/gpio-lynxpoint.c
@@ -188,7 +188,7 @@ static int lp_irq_type(struct irq_data *d, unsigned type)
static int lp_gpio_get(struct gpio_chip *chip, unsigned offset)
{
unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
- return inl(reg) & IN_LVL_BIT;
+ return !!(inl(reg) & IN_LVL_BIT);
}
static void lp_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
@@ -301,23 +301,23 @@ static void lp_irq_disable(struct irq_data *d)
spin_unlock_irqrestore(&lg->lock, flags);
}
-static unsigned int lp_irq_startup(struct irq_data *d)
+static int lp_irq_reqres(struct irq_data *d)
{
struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
- if (gpio_lock_as_irq(&lg->chip, irqd_to_hwirq(d)))
+ if (gpio_lock_as_irq(&lg->chip, irqd_to_hwirq(d))) {
dev_err(lg->chip.dev,
"unable to lock HW IRQ %lu for IRQ\n",
irqd_to_hwirq(d));
- lp_irq_enable(d);
+ return -EINVAL;
+ }
return 0;
}
-static void lp_irq_shutdown(struct irq_data *d)
+static void lp_irq_relres(struct irq_data *d)
{
struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
- lp_irq_disable(d);
gpio_unlock_as_irq(&lg->chip, irqd_to_hwirq(d));
}
@@ -328,8 +328,8 @@ static struct irq_chip lp_irqchip = {
.irq_enable = lp_irq_enable,
.irq_disable = lp_irq_disable,
.irq_set_type = lp_irq_type,
- .irq_startup = lp_irq_startup,
- .irq_shutdown = lp_irq_shutdown,
+ .irq_request_resources = lp_irq_reqres,
+ .irq_release_resources = lp_irq_relres,
.flags = IRQCHIP_SKIP_SET_WAKE,
};
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c
index 36cb290764b6..7c36f2b0983d 100644
--- a/drivers/gpio/gpio-max732x.c
+++ b/drivers/gpio/gpio-max732x.c
@@ -622,6 +622,13 @@ static int max732x_probe(struct i2c_client *client,
goto out_failed;
}
+ if (nr_port > 8 && !chip->client_dummy) {
+ dev_err(&client->dev,
+ "Failed to allocate second group I2C device\n");
+ ret = -ENODEV;
+ goto out_failed;
+ }
+
mutex_init(&chip->lock);
max732x_readb(chip, is_group_a(chip, 0), &chip->reg_out[0]);
@@ -647,6 +654,8 @@ static int max732x_probe(struct i2c_client *client,
return 0;
out_failed:
+ if (chip->client_dummy)
+ i2c_unregister_device(chip->client_dummy);
max732x_irq_teardown(chip);
return ret;
}
diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c
index 1ac288ea810d..99a68310e7c0 100644
--- a/drivers/gpio/gpio-mcp23s08.c
+++ b/drivers/gpio/gpio-mcp23s08.c
@@ -173,7 +173,7 @@ static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg)
tx[0] = mcp->addr | 0x01;
tx[1] = reg;
- status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx);
+ status = spi_write_then_read(mcp->data, tx, sizeof(tx), rx, sizeof(rx));
return (status < 0) ? status : rx[0];
}
@@ -184,7 +184,7 @@ static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, unsigned val)
tx[0] = mcp->addr;
tx[1] = reg;
tx[2] = val;
- return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0);
+ return spi_write_then_read(mcp->data, tx, sizeof(tx), NULL, 0);
}
static int
@@ -193,13 +193,13 @@ mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n)
u8 tx[2], *tmp;
int status;
- if ((n + reg) > sizeof mcp->cache)
+ if ((n + reg) > sizeof(mcp->cache))
return -EINVAL;
tx[0] = mcp->addr | 0x01;
tx[1] = reg;
tmp = (u8 *)vals;
- status = spi_write_then_read(mcp->data, tx, sizeof tx, tmp, n);
+ status = spi_write_then_read(mcp->data, tx, sizeof(tx), tmp, n);
if (status >= 0) {
while (n--)
vals[n] = tmp[n]; /* expand to 16bit */
@@ -214,7 +214,7 @@ static int mcp23s17_read(struct mcp23s08 *mcp, unsigned reg)
tx[0] = mcp->addr | 0x01;
tx[1] = reg << 1;
- status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx);
+ status = spi_write_then_read(mcp->data, tx, sizeof(tx), rx, sizeof(rx));
return (status < 0) ? status : (rx[0] | (rx[1] << 8));
}
@@ -226,7 +226,7 @@ static int mcp23s17_write(struct mcp23s08 *mcp, unsigned reg, unsigned val)
tx[1] = reg << 1;
tx[2] = val;
tx[3] = val >> 8;
- return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0);
+ return spi_write_then_read(mcp->data, tx, sizeof(tx), NULL, 0);
}
static int
@@ -235,12 +235,12 @@ mcp23s17_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n)
u8 tx[2];
int status;
- if ((n + reg) > sizeof mcp->cache)
+ if ((n + reg) > sizeof(mcp->cache))
return -EINVAL;
tx[0] = mcp->addr | 0x01;
tx[1] = reg << 1;
- status = spi_write_then_read(mcp->data, tx, sizeof tx,
+ status = spi_write_then_read(mcp->data, tx, sizeof(tx),
(u8 *)vals, n * 2);
if (status >= 0) {
while (n--)
@@ -440,24 +440,24 @@ static void mcp23s08_irq_bus_unlock(struct irq_data *data)
mutex_unlock(&mcp->irq_lock);
}
-static unsigned int mcp23s08_irq_startup(struct irq_data *data)
+static int mcp23s08_irq_reqres(struct irq_data *data)
{
struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
- if (gpio_lock_as_irq(&mcp->chip, data->hwirq))
+ if (gpio_lock_as_irq(&mcp->chip, data->hwirq)) {
dev_err(mcp->chip.dev,
"unable to lock HW IRQ %lu for IRQ usage\n",
data->hwirq);
+ return -EINVAL;
+ }
- mcp23s08_irq_unmask(data);
return 0;
}
-static void mcp23s08_irq_shutdown(struct irq_data *data)
+static void mcp23s08_irq_relres(struct irq_data *data)
{
struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
- mcp23s08_irq_mask(data);
gpio_unlock_as_irq(&mcp->chip, data->hwirq);
}
@@ -468,8 +468,8 @@ static struct irq_chip mcp23s08_irq_chip = {
.irq_set_type = mcp23s08_irq_set_type,
.irq_bus_lock = mcp23s08_irq_bus_lock,
.irq_bus_sync_unlock = mcp23s08_irq_bus_unlock,
- .irq_startup = mcp23s08_irq_startup,
- .irq_shutdown = mcp23s08_irq_shutdown,
+ .irq_request_resources = mcp23s08_irq_reqres,
+ .irq_release_resources = mcp23s08_irq_relres,
};
static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
@@ -567,7 +567,7 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip)
(mcp->cache[MCP_GPIO] & mask) ? "hi" : "lo",
(mcp->cache[MCP_GPPU] & mask) ? "up" : " ");
/* NOTE: ignoring the irq-related registers */
- seq_printf(s, "\n");
+ seq_puts(s, "\n");
}
done:
mutex_unlock(&mcp->lock);
@@ -789,7 +789,7 @@ static int mcp230xx_probe(struct i2c_client *client,
pullups = pdata->chip[0].pullups;
}
- mcp = kzalloc(sizeof *mcp, GFP_KERNEL);
+ mcp = kzalloc(sizeof(*mcp), GFP_KERNEL);
if (!mcp)
return -ENOMEM;
@@ -925,7 +925,7 @@ static int mcp23s08_probe(struct spi_device *spi)
base = pdata->base;
}
- data = kzalloc(sizeof *data + chips * sizeof(struct mcp23s08),
+ data = kzalloc(sizeof(*data) + chips * sizeof(struct mcp23s08),
GFP_KERNEL);
if (!data)
return -ENOMEM;
diff --git a/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c
index 2af990022cc9..ccd45704e5fd 100644
--- a/drivers/gpio/gpio-moxart.c
+++ b/drivers/gpio/gpio-moxart.c
@@ -48,25 +48,6 @@ static void moxart_gpio_free(struct gpio_chip *chip, unsigned offset)
pinctrl_free_gpio(offset);
}
-static int moxart_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
- struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
- void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION;
-
- writel(readl(ioaddr) & ~BIT(offset), ioaddr);
- return 0;
-}
-
-static int moxart_gpio_direction_output(struct gpio_chip *chip,
- unsigned offset, int value)
-{
- struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
- void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION;
-
- writel(readl(ioaddr) | BIT(offset), ioaddr);
- return 0;
-}
-
static void moxart_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
@@ -78,7 +59,6 @@ static void moxart_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
else
reg = reg & ~BIT(offset);
-
writel(reg, ioaddr);
}
@@ -93,6 +73,26 @@ static int moxart_gpio_get(struct gpio_chip *chip, unsigned offset)
return !!(readl(gc->base + GPIO_DATA_IN) & BIT(offset));
}
+static int moxart_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
+ void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION;
+
+ writel(readl(ioaddr) & ~BIT(offset), ioaddr);
+ return 0;
+}
+
+static int moxart_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
+ void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION;
+
+ moxart_gpio_set(chip, offset, value);
+ writel(readl(ioaddr) | BIT(offset), ioaddr);
+ return 0;
+}
+
static struct gpio_chip moxart_template_chip = {
.label = "moxart-gpio",
.request = moxart_gpio_request,
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index 3b1fd1ce460f..d42509422394 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -44,6 +44,7 @@
#include <linux/of_device.h>
#include <linux/clk.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/irqchip/chained_irq.h>
/*
* GPIO unit register offsets.
@@ -438,12 +439,15 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type)
static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
{
struct mvebu_gpio_chip *mvchip = irq_get_handler_data(irq);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
u32 cause, type;
int i;
if (mvchip == NULL)
return;
+ chained_irq_enter(chip, desc);
+
cause = readl_relaxed(mvebu_gpioreg_data_in(mvchip)) &
readl_relaxed(mvebu_gpioreg_level_mask(mvchip));
cause |= readl_relaxed(mvebu_gpioreg_edge_cause(mvchip)) &
@@ -466,8 +470,11 @@ static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
polarity ^= 1 << i;
writel_relaxed(polarity, mvebu_gpioreg_in_pol(mvchip));
}
+
generic_handle_irq(irq);
}
+
+ chained_irq_exit(chip, desc);
}
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c
index 532bcb336eff..8ffdd7d2bade 100644
--- a/drivers/gpio/gpio-mxs.c
+++ b/drivers/gpio/gpio-mxs.c
@@ -214,7 +214,8 @@ static void __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base)
ct->regs.ack = PINCTRL_IRQSTAT(port) + MXS_CLR;
ct->regs.mask = PINCTRL_IRQEN(port);
- irq_setup_generic_chip(gc, IRQ_MSK(32), 0, IRQ_NOREQUEST, 0);
+ irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK,
+ IRQ_NOREQUEST, 0);
}
static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 424319061e09..19b886c21b1d 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -1214,24 +1214,10 @@ static int omap_gpio_probe(struct platform_device *pdev)
/* Static mapping, never released */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (unlikely(!res)) {
- dev_err(dev, "Invalid mem resource\n");
- irq_domain_remove(bank->domain);
- return -ENODEV;
- }
-
- if (!devm_request_mem_region(dev, res->start, resource_size(res),
- pdev->name)) {
- dev_err(dev, "Region already claimed\n");
+ bank->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(bank->base)) {
irq_domain_remove(bank->domain);
- return -EBUSY;
- }
-
- bank->base = devm_ioremap(dev, res->start, resource_size(res));
- if (!bank->base) {
- dev_err(dev, "Could not ioremap\n");
- irq_domain_remove(bank->domain);
- return -ENOMEM;
+ return PTR_ERR(bank->base);
}
platform_set_drvdata(pdev, bank);
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 019b23b955a2..d550d8e58705 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -1,5 +1,5 @@
/*
- * PCA953x 4/8/16 bit I/O ports
+ * PCA953x 4/8/16/24/40 bit I/O ports
*
* Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
* Copyright (C) 2007 Marvell International Ltd.
@@ -59,6 +59,7 @@ static const struct i2c_device_id pca953x_id[] = {
{ "pca9557", 8 | PCA953X_TYPE, },
{ "pca9574", 8 | PCA957X_TYPE | PCA_INT, },
{ "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
+ { "pca9698", 40 | PCA953X_TYPE, },
{ "max7310", 8 | PCA953X_TYPE, },
{ "max7312", 16 | PCA953X_TYPE | PCA_INT, },
@@ -68,6 +69,7 @@ static const struct i2c_device_id pca953x_id[] = {
{ "tca6408", 8 | PCA953X_TYPE | PCA_INT, },
{ "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
{ "tca6424", 24 | PCA953X_TYPE | PCA_INT, },
+ { "xra1202", 8 | PCA953X_TYPE },
{ }
};
MODULE_DEVICE_TABLE(i2c, pca953x_id);
@@ -625,11 +627,12 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert)
const __be32 *val;
int size;
+ *gpio_base = -1;
+
node = client->dev.of_node;
if (node == NULL)
return;
- *gpio_base = -1;
val = of_get_property(node, "linux,gpio-base", &size);
WARN(val, "%s: device-tree property 'linux,gpio-base' is deprecated!", __func__);
if (val) {
@@ -812,6 +815,7 @@ static const struct of_device_id pca953x_dt_ids[] = {
{ .compatible = "nxp,pca9557", },
{ .compatible = "nxp,pca9574", },
{ .compatible = "nxp,pca9575", },
+ { .compatible = "nxp,pca9698", },
{ .compatible = "maxim,max7310", },
{ .compatible = "maxim,max7312", },
@@ -822,6 +826,8 @@ static const struct of_device_id pca953x_dt_ids[] = {
{ .compatible = "ti,tca6408", },
{ .compatible = "ti,tca6416", },
{ .compatible = "ti,tca6424", },
+
+ { .compatible = "exar,xra1202", },
{ }
};
diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c
index 9656c196772e..83a156397474 100644
--- a/drivers/gpio/gpio-pch.c
+++ b/drivers/gpio/gpio-pch.c
@@ -138,9 +138,6 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
unsigned long flags;
spin_lock_irqsave(&chip->spinlock, flags);
- pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1);
- pm |= (1 << nr);
- iowrite32(pm, &chip->reg->pm);
reg_val = ioread32(&chip->reg->po);
if (val)
@@ -148,6 +145,11 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
else
reg_val &= ~(1 << nr);
iowrite32(reg_val, &chip->reg->po);
+
+ pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1);
+ pm |= (1 << nr);
+ iowrite32(pm, &chip->reg->pm);
+
spin_unlock_irqrestore(&chip->spinlock, flags);
return 0;
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index b4d42112d02d..b0f475243cef 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -15,7 +15,6 @@
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/irq.h>
-#include <linux/irqdomain.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/bitops.h>
#include <linux/workqueue.h>
@@ -53,7 +52,6 @@ struct pl061_gpio {
spinlock_t lock;
void __iomem *base;
- struct irq_domain *domain;
struct gpio_chip gc;
#ifdef CONFIG_PM
@@ -137,19 +135,14 @@ static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value)
writeb(!!value << offset, chip->base + (1 << (offset + 2)));
}
-static int pl061_to_irq(struct gpio_chip *gc, unsigned offset)
-{
- struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
-
- return irq_create_mapping(chip->domain, offset);
-}
-
static int pl061_irq_type(struct irq_data *d, unsigned trigger)
{
- struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
int offset = irqd_to_hwirq(d);
unsigned long flags;
u8 gpiois, gpioibe, gpioiev;
+ u8 bit = BIT(offset);
if (offset < 0 || offset >= PL061_GPIO_NR)
return -EINVAL;
@@ -157,30 +150,31 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
spin_lock_irqsave(&chip->lock, flags);
gpioiev = readb(chip->base + GPIOIEV);
-
gpiois = readb(chip->base + GPIOIS);
+ gpioibe = readb(chip->base + GPIOIBE);
+
if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
- gpiois |= 1 << offset;
+ gpiois |= bit;
if (trigger & IRQ_TYPE_LEVEL_HIGH)
- gpioiev |= 1 << offset;
+ gpioiev |= bit;
else
- gpioiev &= ~(1 << offset);
+ gpioiev &= ~bit;
} else
- gpiois &= ~(1 << offset);
- writeb(gpiois, chip->base + GPIOIS);
+ gpiois &= ~bit;
- gpioibe = readb(chip->base + GPIOIBE);
if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
- gpioibe |= 1 << offset;
+ /* Setting this makes GPIOEV be ignored */
+ gpioibe |= bit;
else {
- gpioibe &= ~(1 << offset);
+ gpioibe &= ~bit;
if (trigger & IRQ_TYPE_EDGE_RISING)
- gpioiev |= 1 << offset;
+ gpioiev |= bit;
else if (trigger & IRQ_TYPE_EDGE_FALLING)
- gpioiev &= ~(1 << offset);
+ gpioiev &= ~bit;
}
- writeb(gpioibe, chip->base + GPIOIBE);
+ writeb(gpiois, chip->base + GPIOIS);
+ writeb(gpioibe, chip->base + GPIOIBE);
writeb(gpioiev, chip->base + GPIOIEV);
spin_unlock_irqrestore(&chip->lock, flags);
@@ -192,7 +186,8 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
{
unsigned long pending;
int offset;
- struct pl061_gpio *chip = irq_desc_get_handler_data(desc);
+ struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+ struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
struct irq_chip *irqchip = irq_desc_get_chip(desc);
chained_irq_enter(irqchip, desc);
@@ -201,7 +196,8 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
writeb(pending, chip->base + GPIOIC);
if (pending) {
for_each_set_bit(offset, &pending, PL061_GPIO_NR)
- generic_handle_irq(pl061_to_irq(&chip->gc, offset));
+ generic_handle_irq(irq_find_mapping(gc->irqdomain,
+ offset));
}
chained_irq_exit(irqchip, desc);
@@ -209,7 +205,8 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
static void pl061_irq_mask(struct irq_data *d)
{
- struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
u8 mask = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR);
u8 gpioie;
@@ -221,7 +218,8 @@ static void pl061_irq_mask(struct irq_data *d)
static void pl061_irq_unmask(struct irq_data *d)
{
- struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
u8 mask = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR);
u8 gpioie;
@@ -232,30 +230,12 @@ static void pl061_irq_unmask(struct irq_data *d)
}
static struct irq_chip pl061_irqchip = {
- .name = "pl061 gpio",
+ .name = "pl061",
.irq_mask = pl061_irq_mask,
.irq_unmask = pl061_irq_unmask,
.irq_set_type = pl061_irq_type,
};
-static int pl061_irq_map(struct irq_domain *d, unsigned int irq,
- irq_hw_number_t hwirq)
-{
- struct pl061_gpio *chip = d->host_data;
-
- irq_set_chip_and_handler_name(irq, &pl061_irqchip, handle_simple_irq,
- "pl061");
- irq_set_chip_data(irq, chip);
- irq_set_irq_type(irq, IRQ_TYPE_NONE);
-
- return 0;
-}
-
-static const struct irq_domain_ops pl061_domain_ops = {
- .map = pl061_irq_map,
- .xlate = irq_domain_xlate_twocell,
-};
-
static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
{
struct device *dev = &adev->dev;
@@ -270,21 +250,18 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
if (pdata) {
chip->gc.base = pdata->gpio_base;
irq_base = pdata->irq_base;
- if (irq_base <= 0)
+ if (irq_base <= 0) {
+ dev_err(&adev->dev, "invalid IRQ base in pdata\n");
return -ENODEV;
+ }
} else {
chip->gc.base = -1;
irq_base = 0;
}
- if (!devm_request_mem_region(dev, adev->res.start,
- resource_size(&adev->res), "pl061"))
- return -EBUSY;
-
- chip->base = devm_ioremap(dev, adev->res.start,
- resource_size(&adev->res));
- if (!chip->base)
- return -ENOMEM;
+ chip->base = devm_ioremap_resource(dev, &adev->res);
+ if (IS_ERR(chip->base))
+ return PTR_ERR(chip->base);
spin_lock_init(&chip->lock);
@@ -294,7 +271,6 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
chip->gc.direction_output = pl061_direction_output;
chip->gc.get = pl061_get_value;
chip->gc.set = pl061_set_value;
- chip->gc.to_irq = pl061_to_irq;
chip->gc.ngpio = PL061_GPIO_NR;
chip->gc.label = dev_name(dev);
chip->gc.dev = dev;
@@ -309,16 +285,20 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
*/
writeb(0, chip->base + GPIOIE); /* disable irqs */
irq = adev->irq[0];
- if (irq < 0)
+ if (irq < 0) {
+ dev_err(&adev->dev, "invalid IRQ\n");
return -ENODEV;
+ }
- irq_set_chained_handler(irq, pl061_irq_handler);
- irq_set_handler_data(irq, chip);
-
- chip->domain = irq_domain_add_simple(adev->dev.of_node, PL061_GPIO_NR,
- irq_base, &pl061_domain_ops, chip);
- if (!chip->domain)
- return -ENODEV;
+ ret = gpiochip_irqchip_add(&chip->gc, &pl061_irqchip,
+ irq_base, handle_simple_irq,
+ IRQ_TYPE_NONE);
+ if (ret) {
+ dev_info(&adev->dev, "could not add irqchip\n");
+ return ret;
+ }
+ gpiochip_set_chained_irqchip(&chip->gc, &pl061_irqchip,
+ irq, pl061_irq_handler);
for (i = 0; i < PL061_GPIO_NR; i++) {
if (pdata) {
@@ -331,6 +311,8 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
}
amba_set_drvdata(adev, chip);
+ dev_info(&adev->dev, "PL061 GPIO chip @%pa registered\n",
+ &adev->res.start);
return 0;
}
diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c
index 122b776fdc0b..9b423173ab50 100644
--- a/drivers/gpio/gpio-rc5t583.c
+++ b/drivers/gpio/gpio-rc5t583.c
@@ -97,7 +97,7 @@ static int rc5t583_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
- if ((offset >= 0) && (offset < 8))
+ if (offset < RC5T583_MAX_GPIO)
return rc5t583_gpio->rc5t583->irq_base +
RC5T583_IRQ_GPIO0 + offset;
return -EINVAL;
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index ca76ce751540..03c91482432c 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -356,12 +356,13 @@ static int gpio_rcar_probe(struct platform_device *pdev)
struct resource *io, *irq;
struct gpio_chip *gpio_chip;
struct irq_chip *irq_chip;
- const char *name = dev_name(&pdev->dev);
+ struct device *dev = &pdev->dev;
+ const char *name = dev_name(dev);
int ret;
- p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
+ p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
if (!p) {
- dev_err(&pdev->dev, "failed to allocate driver data\n");
+ dev_err(dev, "failed to allocate driver data\n");
ret = -ENOMEM;
goto err0;
}
@@ -380,15 +381,14 @@ static int gpio_rcar_probe(struct platform_device *pdev)
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!io || !irq) {
- dev_err(&pdev->dev, "missing IRQ or IOMEM\n");
+ dev_err(dev, "missing IRQ or IOMEM\n");
ret = -EINVAL;
goto err0;
}
- p->base = devm_ioremap_nocache(&pdev->dev, io->start,
- resource_size(io));
+ p->base = devm_ioremap_nocache(dev, io->start, resource_size(io));
if (!p->base) {
- dev_err(&pdev->dev, "failed to remap I/O memory\n");
+ dev_err(dev, "failed to remap I/O memory\n");
ret = -ENXIO;
goto err0;
}
@@ -402,7 +402,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
gpio_chip->set = gpio_rcar_set;
gpio_chip->to_irq = gpio_rcar_to_irq;
gpio_chip->label = name;
- gpio_chip->dev = &pdev->dev;
+ gpio_chip->dev = dev;
gpio_chip->owner = THIS_MODULE;
gpio_chip->base = p->config.gpio_base;
gpio_chip->ngpio = p->config.number_of_pins;
@@ -421,30 +421,30 @@ static int gpio_rcar_probe(struct platform_device *pdev)
&gpio_rcar_irq_domain_ops, p);
if (!p->irq_domain) {
ret = -ENXIO;
- dev_err(&pdev->dev, "cannot initialize irq domain\n");
+ dev_err(dev, "cannot initialize irq domain\n");
goto err0;
}
- if (devm_request_irq(&pdev->dev, irq->start,
- gpio_rcar_irq_handler, IRQF_SHARED, name, p)) {
- dev_err(&pdev->dev, "failed to request IRQ\n");
+ if (devm_request_irq(dev, irq->start, gpio_rcar_irq_handler,
+ IRQF_SHARED, name, p)) {
+ dev_err(dev, "failed to request IRQ\n");
ret = -ENOENT;
goto err1;
}
ret = gpiochip_add(gpio_chip);
if (ret) {
- dev_err(&pdev->dev, "failed to add GPIO controller\n");
+ dev_err(dev, "failed to add GPIO controller\n");
goto err1;
}
- dev_info(&pdev->dev, "driving %d GPIOs\n", p->config.number_of_pins);
+ dev_info(dev, "driving %d GPIOs\n", p->config.number_of_pins);
/* warn in case of mismatch if irq base is specified */
if (p->config.irq_base) {
ret = irq_find_mapping(p->irq_domain, 0);
if (p->config.irq_base != ret)
- dev_warn(&pdev->dev, "irq base mismatch (%u/%u)\n",
+ dev_warn(dev, "irq base mismatch (%u/%u)\n",
p->config.irq_base, ret);
}
@@ -452,7 +452,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
ret = gpiochip_add_pin_range(gpio_chip, p->config.pctl_name, 0,
gpio_chip->base, gpio_chip->ngpio);
if (ret < 0)
- dev_warn(&pdev->dev, "failed to add pin range\n");
+ dev_warn(dev, "failed to add pin range\n");
}
return 0;
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c
index a85e00bf9834..07105ee5c9ae 100644
--- a/drivers/gpio/gpio-samsung.c
+++ b/drivers/gpio/gpio-samsung.c
@@ -379,6 +379,7 @@ static int s5p64x0_gpio_setcfg_rbank(struct samsung_gpio_chip *chip,
case 6:
shift = ((off + 1) & 7) * 4;
reg -= 4;
+ break;
default:
shift = ((off + 1) & 7) * 4;
break;
diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c
new file mode 100644
index 000000000000..b50fe1297748
--- /dev/null
+++ b/drivers/gpio/gpio-syscon.c
@@ -0,0 +1,191 @@
+/*
+ * SYSCON GPIO driver
+ *
+ * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#define GPIO_SYSCON_FEAT_IN BIT(0)
+#define GPIO_SYSCON_FEAT_OUT BIT(1)
+#define GPIO_SYSCON_FEAT_DIR BIT(2)
+
+/* SYSCON driver is designed to use 32-bit wide registers */
+#define SYSCON_REG_SIZE (4)
+#define SYSCON_REG_BITS (SYSCON_REG_SIZE * 8)
+
+/**
+ * struct syscon_gpio_data - Configuration for the device.
+ * compatible: SYSCON driver compatible string.
+ * flags: Set of GPIO_SYSCON_FEAT_ flags:
+ * GPIO_SYSCON_FEAT_IN: GPIOs supports input,
+ * GPIO_SYSCON_FEAT_OUT: GPIOs supports output,
+ * GPIO_SYSCON_FEAT_DIR: GPIOs supports switch direction.
+ * bit_count: Number of bits used as GPIOs.
+ * dat_bit_offset: Offset (in bits) to the first GPIO bit.
+ * dir_bit_offset: Optional offset (in bits) to the first bit to switch
+ * GPIO direction (Used with GPIO_SYSCON_FEAT_DIR flag).
+ */
+
+struct syscon_gpio_data {
+ const char *compatible;
+ unsigned int flags;
+ unsigned int bit_count;
+ unsigned int dat_bit_offset;
+ unsigned int dir_bit_offset;
+};
+
+struct syscon_gpio_priv {
+ struct gpio_chip chip;
+ struct regmap *syscon;
+ const struct syscon_gpio_data *data;
+};
+
+static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip)
+{
+ return container_of(chip, struct syscon_gpio_priv, chip);
+}
+
+static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
+ unsigned int val, offs = priv->data->dat_bit_offset + offset;
+ int ret;
+
+ ret = regmap_read(priv->syscon,
+ (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, &val);
+ if (ret)
+ return ret;
+
+ return !!(val & BIT(offs % SYSCON_REG_BITS));
+}
+
+static void syscon_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+ struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
+ unsigned int offs = priv->data->dat_bit_offset + offset;
+
+ regmap_update_bits(priv->syscon,
+ (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
+ BIT(offs % SYSCON_REG_BITS),
+ val ? BIT(offs % SYSCON_REG_BITS) : 0);
+}
+
+static int syscon_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
+{
+ struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
+
+ if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) {
+ unsigned int offs = priv->data->dir_bit_offset + offset;
+
+ regmap_update_bits(priv->syscon,
+ (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
+ BIT(offs % SYSCON_REG_BITS), 0);
+ }
+
+ return 0;
+}
+
+static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val)
+{
+ struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
+
+ if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) {
+ unsigned int offs = priv->data->dir_bit_offset + offset;
+
+ regmap_update_bits(priv->syscon,
+ (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
+ BIT(offs % SYSCON_REG_BITS),
+ BIT(offs % SYSCON_REG_BITS));
+ }
+
+ syscon_gpio_set(chip, offset, val);
+
+ return 0;
+}
+
+static const struct syscon_gpio_data clps711x_mctrl_gpio = {
+ /* ARM CLPS711X SYSFLG1 Bits 8-10 */
+ .compatible = "cirrus,clps711x-syscon1",
+ .flags = GPIO_SYSCON_FEAT_IN,
+ .bit_count = 3,
+ .dat_bit_offset = 0x40 * 8 + 8,
+};
+
+static const struct of_device_id syscon_gpio_ids[] = {
+ {
+ .compatible = "cirrus,clps711x-mctrl-gpio",
+ .data = &clps711x_mctrl_gpio,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, syscon_gpio_ids);
+
+static int syscon_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *of_id = of_match_device(syscon_gpio_ids, dev);
+ struct syscon_gpio_priv *priv;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->data = of_id->data;
+
+ priv->syscon =
+ syscon_regmap_lookup_by_compatible(priv->data->compatible);
+ if (IS_ERR(priv->syscon))
+ return PTR_ERR(priv->syscon);
+
+ priv->chip.dev = dev;
+ priv->chip.owner = THIS_MODULE;
+ priv->chip.label = dev_name(dev);
+ priv->chip.base = -1;
+ priv->chip.ngpio = priv->data->bit_count;
+ priv->chip.get = syscon_gpio_get;
+ if (priv->data->flags & GPIO_SYSCON_FEAT_IN)
+ priv->chip.direction_input = syscon_gpio_dir_in;
+ if (priv->data->flags & GPIO_SYSCON_FEAT_OUT) {
+ priv->chip.set = syscon_gpio_set;
+ priv->chip.direction_output = syscon_gpio_dir_out;
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ return gpiochip_add(&priv->chip);
+}
+
+static int syscon_gpio_remove(struct platform_device *pdev)
+{
+ struct syscon_gpio_priv *priv = platform_get_drvdata(pdev);
+
+ return gpiochip_remove(&priv->chip);
+}
+
+static struct platform_driver syscon_gpio_driver = {
+ .driver = {
+ .name = "gpio-syscon",
+ .owner = THIS_MODULE,
+ .of_match_table = syscon_gpio_ids,
+ },
+ .probe = syscon_gpio_probe,
+ .remove = syscon_gpio_remove,
+};
+module_platform_driver(syscon_gpio_driver);
+
+MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
+MODULE_DESCRIPTION("SYSCON GPIO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-tnetv107x.c b/drivers/gpio/gpio-tnetv107x.c
deleted file mode 100644
index 4aa481579a05..000000000000
--- a/drivers/gpio/gpio-tnetv107x.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Texas Instruments TNETV107X GPIO Controller
- *
- * Copyright (C) 2010 Texas Instruments
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/platform_data/gpio-davinci.h>
-
-#include <mach/common.h>
-#include <mach/tnetv107x.h>
-
-struct tnetv107x_gpio_regs {
- u32 idver;
- u32 data_in[3];
- u32 data_out[3];
- u32 direction[3];
- u32 enable[3];
-};
-
-#define gpio_reg_index(gpio) ((gpio) >> 5)
-#define gpio_reg_bit(gpio) BIT((gpio) & 0x1f)
-
-#define gpio_reg_rmw(reg, mask, val) \
- __raw_writel((__raw_readl(reg) & ~(mask)) | (val), (reg))
-
-#define gpio_reg_set_bit(reg, gpio) \
- gpio_reg_rmw((reg) + gpio_reg_index(gpio), 0, gpio_reg_bit(gpio))
-
-#define gpio_reg_clear_bit(reg, gpio) \
- gpio_reg_rmw((reg) + gpio_reg_index(gpio), gpio_reg_bit(gpio), 0)
-
-#define gpio_reg_get_bit(reg, gpio) \
- (__raw_readl((reg) + gpio_reg_index(gpio)) & gpio_reg_bit(gpio))
-
-#define chip2controller(chip) \
- container_of(chip, struct davinci_gpio_controller, chip)
-
-#define TNETV107X_GPIO_CTLRS DIV_ROUND_UP(TNETV107X_N_GPIO, 32)
-
-static struct davinci_gpio_controller chips[TNETV107X_GPIO_CTLRS];
-
-static int tnetv107x_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
- struct davinci_gpio_controller *ctlr = chip2controller(chip);
- struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
- unsigned gpio = chip->base + offset;
- unsigned long flags;
-
- spin_lock_irqsave(&ctlr->lock, flags);
-
- gpio_reg_set_bit(regs->enable, gpio);
-
- spin_unlock_irqrestore(&ctlr->lock, flags);
-
- return 0;
-}
-
-static void tnetv107x_gpio_free(struct gpio_chip *chip, unsigned offset)
-{
- struct davinci_gpio_controller *ctlr = chip2controller(chip);
- struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
- unsigned gpio = chip->base + offset;
- unsigned long flags;
-
- spin_lock_irqsave(&ctlr->lock, flags);
-
- gpio_reg_clear_bit(regs->enable, gpio);
-
- spin_unlock_irqrestore(&ctlr->lock, flags);
-}
-
-static int tnetv107x_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
-{
- struct davinci_gpio_controller *ctlr = chip2controller(chip);
- struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
- unsigned gpio = chip->base + offset;
- unsigned long flags;
-
- spin_lock_irqsave(&ctlr->lock, flags);
-
- gpio_reg_set_bit(regs->direction, gpio);
-
- spin_unlock_irqrestore(&ctlr->lock, flags);
-
- return 0;
-}
-
-static int tnetv107x_gpio_dir_out(struct gpio_chip *chip,
- unsigned offset, int value)
-{
- struct davinci_gpio_controller *ctlr = chip2controller(chip);
- struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
- unsigned gpio = chip->base + offset;
- unsigned long flags;
-
- spin_lock_irqsave(&ctlr->lock, flags);
-
- if (value)
- gpio_reg_set_bit(regs->data_out, gpio);
- else
- gpio_reg_clear_bit(regs->data_out, gpio);
-
- gpio_reg_clear_bit(regs->direction, gpio);
-
- spin_unlock_irqrestore(&ctlr->lock, flags);
-
- return 0;
-}
-
-static int tnetv107x_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
- struct davinci_gpio_controller *ctlr = chip2controller(chip);
- struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
- unsigned gpio = chip->base + offset;
- int ret;
-
- ret = gpio_reg_get_bit(regs->data_in, gpio);
-
- return ret ? 1 : 0;
-}
-
-static void tnetv107x_gpio_set(struct gpio_chip *chip,
- unsigned offset, int value)
-{
- struct davinci_gpio_controller *ctlr = chip2controller(chip);
- struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
- unsigned gpio = chip->base + offset;
- unsigned long flags;
-
- spin_lock_irqsave(&ctlr->lock, flags);
-
- if (value)
- gpio_reg_set_bit(regs->data_out, gpio);
- else
- gpio_reg_clear_bit(regs->data_out, gpio);
-
- spin_unlock_irqrestore(&ctlr->lock, flags);
-}
-
-static int __init tnetv107x_gpio_setup(void)
-{
- int i, base;
- unsigned ngpio;
- struct davinci_soc_info *soc_info = &davinci_soc_info;
- struct tnetv107x_gpio_regs *regs;
- struct davinci_gpio_controller *ctlr;
-
- if (soc_info->gpio_type != GPIO_TYPE_TNETV107X)
- return 0;
-
- ngpio = soc_info->gpio_num;
- if (ngpio == 0) {
- pr_err("GPIO setup: how many GPIOs?\n");
- return -EINVAL;
- }
-
- if (WARN_ON(TNETV107X_N_GPIO < ngpio))
- ngpio = TNETV107X_N_GPIO;
-
- regs = ioremap(soc_info->gpio_base, SZ_4K);
- if (WARN_ON(!regs))
- return -EINVAL;
-
- for (i = 0, base = 0; base < ngpio; i++, base += 32) {
- ctlr = &chips[i];
-
- ctlr->chip.label = "tnetv107x";
- ctlr->chip.can_sleep = false;
- ctlr->chip.base = base;
- ctlr->chip.ngpio = ngpio - base;
- if (ctlr->chip.ngpio > 32)
- ctlr->chip.ngpio = 32;
-
- ctlr->chip.request = tnetv107x_gpio_request;
- ctlr->chip.free = tnetv107x_gpio_free;
- ctlr->chip.direction_input = tnetv107x_gpio_dir_in;
- ctlr->chip.get = tnetv107x_gpio_get;
- ctlr->chip.direction_output = tnetv107x_gpio_dir_out;
- ctlr->chip.set = tnetv107x_gpio_set;
-
- spin_lock_init(&ctlr->lock);
-
- ctlr->regs = regs;
- ctlr->set_data = &regs->data_out[i];
- ctlr->clr_data = &regs->data_out[i];
- ctlr->in_data = &regs->data_in[i];
-
- gpiochip_add(&ctlr->chip);
- }
-
- soc_info->gpio_ctlrs = chips;
- soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32);
- return 0;
-}
-pure_initcall(tnetv107x_gpio_setup);
diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c
index 8b88ca2eda9c..3ebb1a5ff22e 100644
--- a/drivers/gpio/gpio-twl4030.c
+++ b/drivers/gpio/gpio-twl4030.c
@@ -139,7 +139,6 @@ static u8 cached_leden;
static void twl4030_led_set_value(int led, int value)
{
u8 mask = LEDEN_LEDAON | LEDEN_LEDAPWM;
- int status;
if (led)
mask <<= 1;
@@ -148,8 +147,9 @@ static void twl4030_led_set_value(int led, int value)
cached_leden &= ~mask;
else
cached_leden |= mask;
- status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
- TWL4030_LED_LEDEN_REG);
+
+ WARN_ON_ONCE(twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
+ TWL4030_LED_LEDEN_REG));
}
static int twl4030_set_gpio_direction(int gpio, int is_input)
diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c
index 23e061392411..5246a60eff6d 100644
--- a/drivers/gpio/gpio-tz1090.c
+++ b/drivers/gpio/gpio-tz1090.c
@@ -488,26 +488,26 @@ static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info)
gc->chip_types[0].handler = handle_level_irq;
gc->chip_types[0].regs.ack = REG_GPIO_IRQ_STS;
gc->chip_types[0].regs.mask = REG_GPIO_IRQ_EN;
- gc->chip_types[0].chip.irq_startup = gpio_startup_irq,
- gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit,
- gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit,
- gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit,
- gc->chip_types[0].chip.irq_set_type = gpio_set_irq_type,
- gc->chip_types[0].chip.irq_set_wake = gpio_set_irq_wake,
- gc->chip_types[0].chip.flags = IRQCHIP_MASK_ON_SUSPEND,
+ gc->chip_types[0].chip.irq_startup = gpio_startup_irq;
+ gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+ gc->chip_types[0].chip.irq_set_type = gpio_set_irq_type;
+ gc->chip_types[0].chip.irq_set_wake = gpio_set_irq_wake;
+ gc->chip_types[0].chip.flags = IRQCHIP_MASK_ON_SUSPEND;
/* edge chip type */
gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
gc->chip_types[1].handler = handle_edge_irq;
gc->chip_types[1].regs.ack = REG_GPIO_IRQ_STS;
gc->chip_types[1].regs.mask = REG_GPIO_IRQ_EN;
- gc->chip_types[1].chip.irq_startup = gpio_startup_irq,
- gc->chip_types[1].chip.irq_ack = irq_gc_ack_clr_bit,
- gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit,
- gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit,
- gc->chip_types[1].chip.irq_set_type = gpio_set_irq_type,
- gc->chip_types[1].chip.irq_set_wake = gpio_set_irq_wake,
- gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND,
+ gc->chip_types[1].chip.irq_startup = gpio_startup_irq;
+ gc->chip_types[1].chip.irq_ack = irq_gc_ack_clr_bit;
+ gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit;
+ gc->chip_types[1].chip.irq_set_type = gpio_set_irq_type;
+ gc->chip_types[1].chip.irq_set_wake = gpio_set_irq_wake;
+ gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND;
/* Setup chained handler for this GPIO bank */
irq_set_handler_data(bank->irq, bank);
diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/gpio-vr41xx.c
index 9902732a382d..66cbcc108e62 100644
--- a/drivers/gpio/gpio-vr41xx.c
+++ b/drivers/gpio/gpio-vr41xx.c
@@ -81,6 +81,7 @@ static DEFINE_SPINLOCK(giu_lock);
static unsigned long giu_flags;
static void __iomem *giu_base;
+static struct gpio_chip vr41xx_gpio_chip;
#define giu_read(offset) readw(giu_base + (offset))
#define giu_write(offset, value) writew((value), giu_base + (offset))
@@ -135,12 +136,31 @@ static void unmask_giuint_low(struct irq_data *d)
giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq));
}
+static unsigned int startup_giuint(struct irq_data *data)
+{
+ if (gpio_lock_as_irq(&vr41xx_gpio_chip, data->hwirq))
+ dev_err(vr41xx_gpio_chip.dev,
+ "unable to lock HW IRQ %lu for IRQ\n",
+ data->hwirq);
+ /* Satisfy the .enable semantics by unmasking the line */
+ unmask_giuint_low(data);
+ return 0;
+}
+
+static void shutdown_giuint(struct irq_data *data)
+{
+ mask_giuint_low(data);
+ gpio_unlock_as_irq(&vr41xx_gpio_chip, data->hwirq);
+}
+
static struct irq_chip giuint_low_irq_chip = {
.name = "GIUINTL",
.irq_ack = ack_giuint_low,
.irq_mask = mask_giuint_low,
.irq_mask_ack = mask_ack_giuint_low,
.irq_unmask = unmask_giuint_low,
+ .irq_startup = startup_giuint,
+ .irq_shutdown = shutdown_giuint,
};
static void ack_giuint_high(struct irq_data *d)
diff --git a/drivers/gpio/gpio-xtensa.c b/drivers/gpio/gpio-xtensa.c
index 1d136eceda62..7081304d6797 100644
--- a/drivers/gpio/gpio-xtensa.c
+++ b/drivers/gpio/gpio-xtensa.c
@@ -40,6 +40,8 @@
#error GPIO32 option is not enabled for your xtensa core variant
#endif
+#if XCHAL_HAVE_CP
+
static inline unsigned long enable_cp(unsigned long *cpenable)
{
unsigned long flags;
@@ -57,6 +59,20 @@ static inline void disable_cp(unsigned long flags, unsigned long cpenable)
local_irq_restore(flags);
}
+#else
+
+static inline unsigned long enable_cp(unsigned long *cpenable)
+{
+ *cpenable = 0; /* avoid uninitialized value warning */
+ return 0;
+}
+
+static inline void disable_cp(unsigned long flags, unsigned long cpenable)
+{
+}
+
+#endif /* XCHAL_HAVE_CP */
+
static int xtensa_impwire_get_direction(struct gpio_chip *gc, unsigned offset)
{
return 1; /* input only */
diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c
new file mode 100644
index 000000000000..9bf5034b6cdb
--- /dev/null
+++ b/drivers/gpio/gpio-zevio.c
@@ -0,0 +1,220 @@
+/*
+ * GPIO controller in LSI ZEVIO SoCs.
+ *
+ * Author: Fabian Vogt <fabian@ritter-vogt.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/spinlock.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+
+/*
+ * Memory layout:
+ * This chip has four gpio sections, each controls 8 GPIOs.
+ * Bit 0 in section 0 is GPIO 0, bit 2 in section 1 is GPIO 10.
+ * Disclaimer: Reverse engineered!
+ * For more information refer to:
+ * http://hackspire.unsads.com/wiki/index.php/Memory-mapped_I/O_ports#90000000_-_General_Purpose_I.2FO_.28GPIO.29
+ *
+ * 0x00-0x3F: Section 0
+ * +0x00: Masked interrupt status (read-only)
+ * +0x04: R: Interrupt status W: Reset interrupt status
+ * +0x08: R: Interrupt mask W: Mask interrupt
+ * +0x0C: W: Unmask interrupt (write-only)
+ * +0x10: Direction: I/O=1/0
+ * +0x14: Output
+ * +0x18: Input (read-only)
+ * +0x20: R: Level interrupt W: Set as level interrupt
+ * 0x40-0x7F: Section 1
+ * 0x80-0xBF: Section 2
+ * 0xC0-0xFF: Section 3
+ */
+
+#define ZEVIO_GPIO_SECTION_SIZE 0x40
+
+/* Offsets to various registers */
+#define ZEVIO_GPIO_INT_MASKED_STATUS 0x00
+#define ZEVIO_GPIO_INT_STATUS 0x04
+#define ZEVIO_GPIO_INT_UNMASK 0x08
+#define ZEVIO_GPIO_INT_MASK 0x0C
+#define ZEVIO_GPIO_DIRECTION 0x10
+#define ZEVIO_GPIO_OUTPUT 0x14
+#define ZEVIO_GPIO_INPUT 0x18
+#define ZEVIO_GPIO_INT_STICKY 0x20
+
+#define to_zevio_gpio(chip) container_of(to_of_mm_gpio_chip(chip), \
+ struct zevio_gpio, chip)
+
+/* Bit number of GPIO in its section */
+#define ZEVIO_GPIO_BIT(gpio) (gpio&7)
+
+struct zevio_gpio {
+ spinlock_t lock;
+ struct of_mm_gpio_chip chip;
+};
+
+static inline u32 zevio_gpio_port_get(struct zevio_gpio *c, unsigned pin,
+ unsigned port_offset)
+{
+ unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE;
+ return readl(IOMEM(c->chip.regs + section_offset + port_offset));
+}
+
+static inline void zevio_gpio_port_set(struct zevio_gpio *c, unsigned pin,
+ unsigned port_offset, u32 val)
+{
+ unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE;
+ writel(val, IOMEM(c->chip.regs + section_offset + port_offset));
+}
+
+/* Functions for struct gpio_chip */
+static int zevio_gpio_get(struct gpio_chip *chip, unsigned pin)
+{
+ struct zevio_gpio *controller = to_zevio_gpio(chip);
+
+ /* Only reading allowed, so no spinlock needed */
+ u32 val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_INPUT);
+
+ return (val >> ZEVIO_GPIO_BIT(pin)) & 0x1;
+}
+
+static void zevio_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
+{
+ struct zevio_gpio *controller = to_zevio_gpio(chip);
+ u32 val;
+
+ spin_lock(&controller->lock);
+ val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT);
+ if (value)
+ val |= BIT(ZEVIO_GPIO_BIT(pin));
+ else
+ val &= ~BIT(ZEVIO_GPIO_BIT(pin));
+
+ zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val);
+ spin_unlock(&controller->lock);
+}
+
+static int zevio_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
+{
+ struct zevio_gpio *controller = to_zevio_gpio(chip);
+ u32 val;
+
+ spin_lock(&controller->lock);
+
+ val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION);
+ val |= BIT(ZEVIO_GPIO_BIT(pin));
+ zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val);
+
+ spin_unlock(&controller->lock);
+
+ return 0;
+}
+
+static int zevio_gpio_direction_output(struct gpio_chip *chip,
+ unsigned pin, int value)
+{
+ struct zevio_gpio *controller = to_zevio_gpio(chip);
+ u32 val;
+
+ spin_lock(&controller->lock);
+ val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT);
+ if (value)
+ val |= BIT(ZEVIO_GPIO_BIT(pin));
+ else
+ val &= ~BIT(ZEVIO_GPIO_BIT(pin));
+
+ zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val);
+ val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION);
+ val &= ~BIT(ZEVIO_GPIO_BIT(pin));
+ zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val);
+
+ spin_unlock(&controller->lock);
+
+ return 0;
+}
+
+static int zevio_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
+{
+ /*
+ * TODO: Implement IRQs.
+ * Not implemented yet due to weird lockups
+ */
+
+ return -ENXIO;
+}
+
+static struct gpio_chip zevio_gpio_chip = {
+ .direction_input = zevio_gpio_direction_input,
+ .direction_output = zevio_gpio_direction_output,
+ .set = zevio_gpio_set,
+ .get = zevio_gpio_get,
+ .to_irq = zevio_gpio_to_irq,
+ .base = 0,
+ .owner = THIS_MODULE,
+ .ngpio = 32,
+ .of_gpio_n_cells = 2,
+};
+
+/* Initialization */
+static int zevio_gpio_probe(struct platform_device *pdev)
+{
+ struct zevio_gpio *controller;
+ int status, i;
+
+ controller = devm_kzalloc(&pdev->dev, sizeof(*controller), GFP_KERNEL);
+ if (!controller) {
+ dev_err(&pdev->dev, "not enough free memory\n");
+ return -ENOMEM;
+ }
+
+ /* Copy our reference */
+ controller->chip.gc = zevio_gpio_chip;
+ controller->chip.gc.dev = &pdev->dev;
+
+ status = of_mm_gpiochip_add(pdev->dev.of_node, &(controller->chip));
+ if (status) {
+ dev_err(&pdev->dev, "failed to add gpiochip: %d\n", status);
+ return status;
+ }
+
+ spin_lock_init(&controller->lock);
+
+ /* Disable interrupts, they only cause errors */
+ for (i = 0; i < controller->chip.gc.ngpio; i += 8)
+ zevio_gpio_port_set(controller, i, ZEVIO_GPIO_INT_MASK, 0xFF);
+
+ dev_dbg(controller->chip.gc.dev, "ZEVIO GPIO controller set up!\n");
+
+ return 0;
+}
+
+static struct of_device_id zevio_gpio_of_match[] = {
+ { .compatible = "lsi,zevio-gpio", },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, zevio_gpio_of_match);
+
+static struct platform_driver zevio_gpio_driver = {
+ .driver = {
+ .name = "gpio-zevio",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(zevio_gpio_of_match),
+ },
+ .probe = zevio_gpio_probe,
+};
+module_platform_driver(zevio_gpio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Fabian Vogt <fabian@ritter-vogt.de>");
+MODULE_DESCRIPTION("LSI ZEVIO SoC GPIO driver");
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 716ee9843110..bf0f8b476696 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -16,16 +16,35 @@
#include <linux/export.h>
#include <linux/acpi.h>
#include <linux/interrupt.h>
+#include <linux/mutex.h>
#include "gpiolib.h"
-struct acpi_gpio_evt_pin {
+struct acpi_gpio_event {
struct list_head node;
- acpi_handle *evt_handle;
+ acpi_handle handle;
unsigned int pin;
unsigned int irq;
};
+struct acpi_gpio_connection {
+ struct list_head node;
+ struct gpio_desc *desc;
+};
+
+struct acpi_gpio_chip {
+ /*
+ * ACPICA requires that the first field of the context parameter
+ * passed to acpi_install_address_space_handler() is large enough
+ * to hold struct acpi_connection_info.
+ */
+ struct acpi_connection_info conn_info;
+ struct list_head conns;
+ struct mutex conn_lock;
+ struct gpio_chip *chip;
+ struct list_head events;
+};
+
static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
{
if (!gc->dev)
@@ -60,176 +79,195 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
if (pin < 0 || pin > chip->ngpio)
return ERR_PTR(-EINVAL);
- return gpio_to_desc(chip->base + pin);
+ return gpiochip_get_desc(chip, pin);
}
static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
{
- acpi_handle handle = data;
+ struct acpi_gpio_event *event = data;
- acpi_evaluate_object(handle, NULL, NULL, NULL);
+ acpi_evaluate_object(event->handle, NULL, NULL, NULL);
return IRQ_HANDLED;
}
static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data)
{
- struct acpi_gpio_evt_pin *evt_pin = data;
+ struct acpi_gpio_event *event = data;
- acpi_execute_simple_method(evt_pin->evt_handle, NULL, evt_pin->pin);
+ acpi_execute_simple_method(event->handle, NULL, event->pin);
return IRQ_HANDLED;
}
-static void acpi_gpio_evt_dh(acpi_handle handle, void *data)
+static void acpi_gpio_chip_dh(acpi_handle handle, void *data)
{
/* The address of this function is used as a key. */
}
-/**
- * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events
- * @chip: gpio chip
- *
- * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are
- * handled by ACPI event methods which need to be called from the GPIO
- * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which
- * gpio pins have acpi event methods and assigns interrupt handlers that calls
- * the acpi event methods for those pins.
- */
-static void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
+static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
+ void *context)
{
- struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
- struct acpi_resource *res;
+ struct acpi_gpio_chip *acpi_gpio = context;
+ struct gpio_chip *chip = acpi_gpio->chip;
+ struct acpi_resource_gpio *agpio;
acpi_handle handle, evt_handle;
- struct list_head *evt_pins = NULL;
- acpi_status status;
- unsigned int pin;
- int irq, ret;
- char ev_name[5];
+ struct acpi_gpio_event *event;
+ irq_handler_t handler = NULL;
+ struct gpio_desc *desc;
+ unsigned long irqflags;
+ int ret, pin, irq;
- if (!chip->dev || !chip->to_irq)
- return;
+ if (ares->type != ACPI_RESOURCE_TYPE_GPIO)
+ return AE_OK;
- handle = ACPI_HANDLE(chip->dev);
- if (!handle)
- return;
+ agpio = &ares->data.gpio;
+ if (agpio->connection_type != ACPI_RESOURCE_GPIO_TYPE_INT)
+ return AE_OK;
- status = acpi_get_event_resources(handle, &buf);
- if (ACPI_FAILURE(status))
- return;
+ handle = ACPI_HANDLE(chip->dev);
+ pin = agpio->pin_table[0];
+
+ if (pin <= 255) {
+ char ev_name[5];
+ sprintf(ev_name, "_%c%02X",
+ agpio->triggering == ACPI_EDGE_SENSITIVE ? 'E' : 'L',
+ pin);
+ if (ACPI_SUCCESS(acpi_get_handle(handle, ev_name, &evt_handle)))
+ handler = acpi_gpio_irq_handler;
+ }
+ if (!handler) {
+ if (ACPI_SUCCESS(acpi_get_handle(handle, "_EVT", &evt_handle)))
+ handler = acpi_gpio_irq_handler_evt;
+ }
+ if (!handler)
+ return AE_BAD_PARAMETER;
- status = acpi_get_handle(handle, "_EVT", &evt_handle);
- if (ACPI_SUCCESS(status)) {
- evt_pins = kzalloc(sizeof(*evt_pins), GFP_KERNEL);
- if (evt_pins) {
- INIT_LIST_HEAD(evt_pins);
- status = acpi_attach_data(handle, acpi_gpio_evt_dh,
- evt_pins);
- if (ACPI_FAILURE(status)) {
- kfree(evt_pins);
- evt_pins = NULL;
- }
- }
+ desc = gpiochip_get_desc(chip, pin);
+ if (IS_ERR(desc)) {
+ dev_err(chip->dev, "Failed to get GPIO descriptor\n");
+ return AE_ERROR;
}
- /*
- * If a GPIO interrupt has an ACPI event handler method, or _EVT is
- * present, set up an interrupt handler that calls the ACPI event
- * handler.
- */
- for (res = buf.pointer;
- res && (res->type != ACPI_RESOURCE_TYPE_END_TAG);
- res = ACPI_NEXT_RESOURCE(res)) {
- irq_handler_t handler = NULL;
- void *data;
-
- if (res->type != ACPI_RESOURCE_TYPE_GPIO ||
- res->data.gpio.connection_type !=
- ACPI_RESOURCE_GPIO_TYPE_INT)
- continue;
+ ret = gpiochip_request_own_desc(desc, "ACPI:Event");
+ if (ret) {
+ dev_err(chip->dev, "Failed to request GPIO\n");
+ return AE_ERROR;
+ }
- pin = res->data.gpio.pin_table[0];
- if (pin > chip->ngpio)
- continue;
+ gpiod_direction_input(desc);
- irq = chip->to_irq(chip, pin);
- if (irq < 0)
- continue;
+ ret = gpiod_lock_as_irq(desc);
+ if (ret) {
+ dev_err(chip->dev, "Failed to lock GPIO as interrupt\n");
+ goto fail_free_desc;
+ }
- if (pin <= 255) {
- acpi_handle ev_handle;
+ irq = gpiod_to_irq(desc);
+ if (irq < 0) {
+ dev_err(chip->dev, "Failed to translate GPIO to IRQ\n");
+ goto fail_unlock_irq;
+ }
- sprintf(ev_name, "_%c%02X",
- res->data.gpio.triggering ? 'E' : 'L', pin);
- status = acpi_get_handle(handle, ev_name, &ev_handle);
- if (ACPI_SUCCESS(status)) {
- handler = acpi_gpio_irq_handler;
- data = ev_handle;
- }
+ irqflags = IRQF_ONESHOT;
+ if (agpio->triggering == ACPI_LEVEL_SENSITIVE) {
+ if (agpio->polarity == ACPI_ACTIVE_HIGH)
+ irqflags |= IRQF_TRIGGER_HIGH;
+ else
+ irqflags |= IRQF_TRIGGER_LOW;
+ } else {
+ switch (agpio->polarity) {
+ case ACPI_ACTIVE_HIGH:
+ irqflags |= IRQF_TRIGGER_RISING;
+ break;
+ case ACPI_ACTIVE_LOW:
+ irqflags |= IRQF_TRIGGER_FALLING;
+ break;
+ default:
+ irqflags |= IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING;
+ break;
}
- if (!handler && evt_pins) {
- struct acpi_gpio_evt_pin *evt_pin;
+ }
- evt_pin = kzalloc(sizeof(*evt_pin), GFP_KERNEL);
- if (!evt_pin)
- continue;
+ event = kzalloc(sizeof(*event), GFP_KERNEL);
+ if (!event)
+ goto fail_unlock_irq;
- list_add_tail(&evt_pin->node, evt_pins);
- evt_pin->evt_handle = evt_handle;
- evt_pin->pin = pin;
- evt_pin->irq = irq;
- handler = acpi_gpio_irq_handler_evt;
- data = evt_pin;
- }
- if (!handler)
- continue;
+ event->handle = evt_handle;
+ event->irq = irq;
+ event->pin = pin;
- /* Assume BIOS sets the triggering, so no flags */
- ret = devm_request_threaded_irq(chip->dev, irq, NULL, handler,
- 0, "GPIO-signaled-ACPI-event",
- data);
- if (ret)
- dev_err(chip->dev,
- "Failed to request IRQ %d ACPI event handler\n",
- irq);
+ ret = request_threaded_irq(event->irq, NULL, handler, irqflags,
+ "ACPI:Event", event);
+ if (ret) {
+ dev_err(chip->dev, "Failed to setup interrupt handler for %d\n",
+ event->irq);
+ goto fail_free_event;
}
+
+ list_add_tail(&event->node, &acpi_gpio->events);
+ return AE_OK;
+
+fail_free_event:
+ kfree(event);
+fail_unlock_irq:
+ gpiod_unlock_as_irq(desc);
+fail_free_desc:
+ gpiochip_free_own_desc(desc);
+
+ return AE_ERROR;
}
/**
- * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts.
- * @chip: gpio chip
- *
- * Free interrupts associated with the _EVT method for the given GPIO chip.
+ * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events
+ * @acpi_gpio: ACPI GPIO chip
*
- * The remaining ACPI event interrupts associated with the chip are freed
- * automatically.
+ * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are
+ * handled by ACPI event methods which need to be called from the GPIO
+ * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which
+ * gpio pins have acpi event methods and assigns interrupt handlers that calls
+ * the acpi event methods for those pins.
*/
-static void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
+static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio)
{
- acpi_handle handle;
- acpi_status status;
- struct list_head *evt_pins;
- struct acpi_gpio_evt_pin *evt_pin, *ep;
+ struct gpio_chip *chip = acpi_gpio->chip;
if (!chip->dev || !chip->to_irq)
return;
- handle = ACPI_HANDLE(chip->dev);
- if (!handle)
- return;
+ INIT_LIST_HEAD(&acpi_gpio->events);
+ acpi_walk_resources(ACPI_HANDLE(chip->dev), "_AEI",
+ acpi_gpiochip_request_interrupt, acpi_gpio);
+}
- status = acpi_get_data(handle, acpi_gpio_evt_dh, (void **)&evt_pins);
- if (ACPI_FAILURE(status))
+/**
+ * acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts.
+ * @acpi_gpio: ACPI GPIO chip
+ *
+ * Free interrupts associated with GPIO ACPI event method for the given
+ * GPIO chip.
+ */
+static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio)
+{
+ struct acpi_gpio_event *event, *ep;
+ struct gpio_chip *chip = acpi_gpio->chip;
+
+ if (!chip->dev || !chip->to_irq)
return;
- list_for_each_entry_safe_reverse(evt_pin, ep, evt_pins, node) {
- devm_free_irq(chip->dev, evt_pin->irq, evt_pin);
- list_del(&evt_pin->node);
- kfree(evt_pin);
- }
+ list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) {
+ struct gpio_desc *desc;
- acpi_detach_data(handle, acpi_gpio_evt_dh);
- kfree(evt_pins);
+ free_irq(event->irq, event);
+ desc = gpiochip_get_desc(chip, event->pin);
+ if (WARN_ON(IS_ERR(desc)))
+ continue;
+ gpiod_unlock_as_irq(desc);
+ gpiochip_free_own_desc(desc);
+ list_del(&event->node);
+ kfree(event);
+ }
}
struct acpi_gpio_lookup {
@@ -310,12 +348,202 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT);
}
+static acpi_status
+acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
+ u32 bits, u64 *value, void *handler_context,
+ void *region_context)
+{
+ struct acpi_gpio_chip *achip = region_context;
+ struct gpio_chip *chip = achip->chip;
+ struct acpi_resource_gpio *agpio;
+ struct acpi_resource *ares;
+ acpi_status status;
+ bool pull_up;
+ int i;
+
+ status = acpi_buffer_to_resource(achip->conn_info.connection,
+ achip->conn_info.length, &ares);
+ if (ACPI_FAILURE(status))
+ return status;
+
+ if (WARN_ON(ares->type != ACPI_RESOURCE_TYPE_GPIO)) {
+ ACPI_FREE(ares);
+ return AE_BAD_PARAMETER;
+ }
+
+ agpio = &ares->data.gpio;
+ pull_up = agpio->pin_config == ACPI_PIN_CONFIG_PULLUP;
+
+ if (WARN_ON(agpio->io_restriction == ACPI_IO_RESTRICT_INPUT &&
+ function == ACPI_WRITE)) {
+ ACPI_FREE(ares);
+ return AE_BAD_PARAMETER;
+ }
+
+ for (i = 0; i < agpio->pin_table_length; i++) {
+ unsigned pin = agpio->pin_table[i];
+ struct acpi_gpio_connection *conn;
+ struct gpio_desc *desc;
+ bool found;
+
+ desc = gpiochip_get_desc(chip, pin);
+ if (IS_ERR(desc)) {
+ status = AE_ERROR;
+ goto out;
+ }
+
+ mutex_lock(&achip->conn_lock);
+
+ found = false;
+ list_for_each_entry(conn, &achip->conns, node) {
+ if (conn->desc == desc) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ int ret;
+
+ ret = gpiochip_request_own_desc(desc, "ACPI:OpRegion");
+ if (ret) {
+ status = AE_ERROR;
+ mutex_unlock(&achip->conn_lock);
+ goto out;
+ }
+
+ switch (agpio->io_restriction) {
+ case ACPI_IO_RESTRICT_INPUT:
+ gpiod_direction_input(desc);
+ break;
+ case ACPI_IO_RESTRICT_OUTPUT:
+ /*
+ * ACPI GPIO resources don't contain an
+ * initial value for the GPIO. Therefore we
+ * deduce that value from the pull field
+ * instead. If the pin is pulled up we
+ * assume default to be high, otherwise
+ * low.
+ */
+ gpiod_direction_output(desc, pull_up);
+ break;
+ default:
+ /*
+ * Assume that the BIOS has configured the
+ * direction and pull accordingly.
+ */
+ break;
+ }
+
+ conn = kzalloc(sizeof(*conn), GFP_KERNEL);
+ if (!conn) {
+ status = AE_NO_MEMORY;
+ gpiochip_free_own_desc(desc);
+ mutex_unlock(&achip->conn_lock);
+ goto out;
+ }
+
+ conn->desc = desc;
+ list_add_tail(&conn->node, &achip->conns);
+ }
+
+ mutex_unlock(&achip->conn_lock);
+
+ if (function == ACPI_WRITE)
+ gpiod_set_raw_value(desc, !!((1 << i) & *value));
+ else
+ *value |= gpiod_get_raw_value(desc) << i;
+ }
+
+out:
+ ACPI_FREE(ares);
+ return status;
+}
+
+static void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip)
+{
+ struct gpio_chip *chip = achip->chip;
+ acpi_handle handle = ACPI_HANDLE(chip->dev);
+ acpi_status status;
+
+ INIT_LIST_HEAD(&achip->conns);
+ mutex_init(&achip->conn_lock);
+ status = acpi_install_address_space_handler(handle, ACPI_ADR_SPACE_GPIO,
+ acpi_gpio_adr_space_handler,
+ NULL, achip);
+ if (ACPI_FAILURE(status))
+ dev_err(chip->dev, "Failed to install GPIO OpRegion handler\n");
+}
+
+static void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip)
+{
+ struct gpio_chip *chip = achip->chip;
+ acpi_handle handle = ACPI_HANDLE(chip->dev);
+ struct acpi_gpio_connection *conn, *tmp;
+ acpi_status status;
+
+ status = acpi_remove_address_space_handler(handle, ACPI_ADR_SPACE_GPIO,
+ acpi_gpio_adr_space_handler);
+ if (ACPI_FAILURE(status)) {
+ dev_err(chip->dev, "Failed to remove GPIO OpRegion handler\n");
+ return;
+ }
+
+ list_for_each_entry_safe_reverse(conn, tmp, &achip->conns, node) {
+ gpiochip_free_own_desc(conn->desc);
+ list_del(&conn->node);
+ kfree(conn);
+ }
+}
+
void acpi_gpiochip_add(struct gpio_chip *chip)
{
- acpi_gpiochip_request_interrupts(chip);
+ struct acpi_gpio_chip *acpi_gpio;
+ acpi_handle handle;
+ acpi_status status;
+
+ handle = ACPI_HANDLE(chip->dev);
+ if (!handle)
+ return;
+
+ acpi_gpio = kzalloc(sizeof(*acpi_gpio), GFP_KERNEL);
+ if (!acpi_gpio) {
+ dev_err(chip->dev,
+ "Failed to allocate memory for ACPI GPIO chip\n");
+ return;
+ }
+
+ acpi_gpio->chip = chip;
+
+ status = acpi_attach_data(handle, acpi_gpio_chip_dh, acpi_gpio);
+ if (ACPI_FAILURE(status)) {
+ dev_err(chip->dev, "Failed to attach ACPI GPIO chip\n");
+ kfree(acpi_gpio);
+ return;
+ }
+
+ acpi_gpiochip_request_interrupts(acpi_gpio);
+ acpi_gpiochip_request_regions(acpi_gpio);
}
void acpi_gpiochip_remove(struct gpio_chip *chip)
{
- acpi_gpiochip_free_interrupts(chip);
+ struct acpi_gpio_chip *acpi_gpio;
+ acpi_handle handle;
+ acpi_status status;
+
+ handle = ACPI_HANDLE(chip->dev);
+ if (!handle)
+ return;
+
+ status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio);
+ if (ACPI_FAILURE(status)) {
+ dev_warn(chip->dev, "Failed to retrieve ACPI GPIO chip\n");
+ return;
+ }
+
+ acpi_gpiochip_free_regions(acpi_gpio);
+ acpi_gpiochip_free_interrupts(acpi_gpio);
+
+ acpi_detach_data(handle, acpi_gpio_chip_dh);
+ kfree(acpi_gpio);
}
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index e0a98f581f58..2024d45e5503 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -12,6 +12,7 @@
*/
#include <linux/device.h>
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/io.h>
@@ -90,7 +91,7 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
of_node_put(gg_data.gpiospec.np);
pr_debug("%s exited with status %d\n", __func__,
- PTR_RET(gg_data.out_gpio));
+ PTR_ERR_OR_ZERO(gg_data.out_gpio));
return gg_data.out_gpio;
}
EXPORT_SYMBOL(of_get_named_gpiod_flags);
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 50c4922fe53a..761013f8b82f 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -164,16 +164,17 @@ struct gpio_desc *gpio_to_desc(unsigned gpio)
EXPORT_SYMBOL_GPL(gpio_to_desc);
/**
- * Convert an offset on a certain chip to a corresponding descriptor
+ * Get the GPIO descriptor corresponding to the given hw number for this chip.
*/
-static struct gpio_desc *gpiochip_offset_to_desc(struct gpio_chip *chip,
- unsigned int offset)
+struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip,
+ u16 hwnum)
{
- if (offset >= chip->ngpio)
+ if (hwnum >= chip->ngpio)
return ERR_PTR(-EINVAL);
- return &chip->desc[offset];
+ return &chip->desc[hwnum];
}
+EXPORT_SYMBOL_GPL(gpiochip_get_desc);
/**
* Convert a GPIO descriptor to the integer namespace.
@@ -350,9 +351,9 @@ static ssize_t gpio_direction_store(struct device *dev,
if (!test_bit(FLAG_EXPORT, &desc->flags))
status = -EIO;
else if (sysfs_streq(buf, "high"))
- status = gpiod_direction_output(desc, 1);
+ status = gpiod_direction_output_raw(desc, 1);
else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
- status = gpiod_direction_output(desc, 0);
+ status = gpiod_direction_output_raw(desc, 0);
else if (sysfs_streq(buf, "in"))
status = gpiod_direction_input(desc);
else
@@ -1253,6 +1254,9 @@ fail:
}
EXPORT_SYMBOL_GPL(gpiochip_add);
+/* Forward-declaration */
+static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
+
/**
* gpiochip_remove() - unregister a gpio_chip
* @chip: the chip to unregister
@@ -1265,11 +1269,13 @@ int gpiochip_remove(struct gpio_chip *chip)
int status = 0;
unsigned id;
+ acpi_gpiochip_remove(chip);
+
spin_lock_irqsave(&gpio_lock, flags);
+ gpiochip_irqchip_remove(chip);
gpiochip_remove_pin_ranges(chip);
of_gpiochip_remove(chip);
- acpi_gpiochip_remove(chip);
for (id = 0; id < chip->ngpio; id++) {
if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) {
@@ -1337,6 +1343,215 @@ static struct gpio_chip *find_chip_by_name(const char *name)
return gpiochip_find((void *)name, gpiochip_match_name);
}
+#ifdef CONFIG_GPIOLIB_IRQCHIP
+
+/*
+ * The following is irqchip helper code for gpiochips.
+ */
+
+/**
+ * gpiochip_add_chained_irqchip() - adds a chained irqchip to a gpiochip
+ * @gpiochip: the gpiochip to add the irqchip to
+ * @irqchip: the irqchip to add to the gpiochip
+ * @parent_irq: the irq number corresponding to the parent IRQ for this
+ * chained irqchip
+ * @parent_handler: the parent interrupt handler for the accumulated IRQ
+ * coming out of the gpiochip
+ */
+void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
+ struct irq_chip *irqchip,
+ int parent_irq,
+ irq_flow_handler_t parent_handler)
+{
+ irq_set_chained_handler(parent_irq, parent_handler);
+ /*
+ * The parent irqchip is already using the chip_data for this
+ * irqchip, so our callbacks simply use the handler_data.
+ */
+ irq_set_handler_data(parent_irq, gpiochip);
+}
+EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip);
+
+/**
+ * gpiochip_irq_map() - maps an IRQ into a GPIO irqchip
+ * @d: the irqdomain used by this irqchip
+ * @irq: the global irq number used by this GPIO irqchip irq
+ * @hwirq: the local IRQ/GPIO line offset on this gpiochip
+ *
+ * This function will set up the mapping for a certain IRQ line on a
+ * gpiochip by assigning the gpiochip as chip data, and using the irqchip
+ * stored inside the gpiochip.
+ */
+static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ struct gpio_chip *chip = d->host_data;
+
+ irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler);
+ irq_set_chip_data(irq, chip);
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, IRQF_VALID);
+#else
+ irq_set_noprobe(irq);
+#endif
+ irq_set_irq_type(irq, chip->irq_default_type);
+
+ return 0;
+}
+
+static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
+{
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, 0);
+#endif
+ irq_set_chip_and_handler(irq, NULL, NULL);
+ irq_set_chip_data(irq, NULL);
+}
+
+static const struct irq_domain_ops gpiochip_domain_ops = {
+ .map = gpiochip_irq_map,
+ .unmap = gpiochip_irq_unmap,
+ /* Virtually all GPIO irqchips are twocell:ed */
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static int gpiochip_irq_reqres(struct irq_data *d)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+
+ if (gpio_lock_as_irq(chip, d->hwirq)) {
+ chip_err(chip,
+ "unable to lock HW IRQ %lu for IRQ\n",
+ d->hwirq);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void gpiochip_irq_relres(struct irq_data *d)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+
+ gpio_unlock_as_irq(chip, d->hwirq);
+}
+
+static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ return irq_find_mapping(chip->irqdomain, offset);
+}
+
+/**
+ * gpiochip_irqchip_remove() - removes an irqchip added to a gpiochip
+ * @gpiochip: the gpiochip to remove the irqchip from
+ *
+ * This is called only from gpiochip_remove()
+ */
+static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
+{
+ unsigned int offset;
+
+ /* Remove all IRQ mappings and delete the domain */
+ if (gpiochip->irqdomain) {
+ for (offset = 0; offset < gpiochip->ngpio; offset++)
+ irq_dispose_mapping(gpiochip->irq_base + offset);
+ irq_domain_remove(gpiochip->irqdomain);
+ }
+
+ if (gpiochip->irqchip) {
+ gpiochip->irqchip->irq_request_resources = NULL;
+ gpiochip->irqchip->irq_release_resources = NULL;
+ gpiochip->irqchip = NULL;
+ }
+}
+
+/**
+ * gpiochip_irqchip_add() - adds an irqchip to a gpiochip
+ * @gpiochip: the gpiochip to add the irqchip to
+ * @irqchip: the irqchip to add to the gpiochip
+ * @first_irq: if not dynamically assigned, the base (first) IRQ to
+ * allocate gpiochip irqs from
+ * @handler: the irq handler to use (often a predefined irq core function)
+ * @type: the default type for IRQs on this irqchip
+ *
+ * This function closely associates a certain irqchip with a certain
+ * gpiochip, providing an irq domain to translate the local IRQs to
+ * global irqs in the gpiolib core, and making sure that the gpiochip
+ * is passed as chip data to all related functions. Driver callbacks
+ * need to use container_of() to get their local state containers back
+ * from the gpiochip passed as chip data. An irqdomain will be stored
+ * in the gpiochip that shall be used by the driver to handle IRQ number
+ * translation. The gpiochip will need to be initialized and registered
+ * before calling this function.
+ *
+ * This function will handle two cell:ed simple IRQs and assumes all
+ * the pins on the gpiochip can generate a unique IRQ. Everything else
+ * need to be open coded.
+ */
+int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
+ struct irq_chip *irqchip,
+ unsigned int first_irq,
+ irq_flow_handler_t handler,
+ unsigned int type)
+{
+ struct device_node *of_node;
+ unsigned int offset;
+ unsigned irq_base = 0;
+
+ if (!gpiochip || !irqchip)
+ return -EINVAL;
+
+ if (!gpiochip->dev) {
+ pr_err("missing gpiochip .dev parent pointer\n");
+ return -EINVAL;
+ }
+ of_node = gpiochip->dev->of_node;
+#ifdef CONFIG_OF_GPIO
+ /*
+ * If the gpiochip has an assigned OF node this takes precendence
+ * FIXME: get rid of this and use gpiochip->dev->of_node everywhere
+ */
+ if (gpiochip->of_node)
+ of_node = gpiochip->of_node;
+#endif
+ gpiochip->irqchip = irqchip;
+ gpiochip->irq_handler = handler;
+ gpiochip->irq_default_type = type;
+ gpiochip->to_irq = gpiochip_to_irq;
+ gpiochip->irqdomain = irq_domain_add_simple(of_node,
+ gpiochip->ngpio, first_irq,
+ &gpiochip_domain_ops, gpiochip);
+ if (!gpiochip->irqdomain) {
+ gpiochip->irqchip = NULL;
+ return -EINVAL;
+ }
+ irqchip->irq_request_resources = gpiochip_irq_reqres;
+ irqchip->irq_release_resources = gpiochip_irq_relres;
+
+ /*
+ * Prepare the mapping since the irqchip shall be orthogonal to
+ * any gpiochip calls. If the first_irq was zero, this is
+ * necessary to allocate descriptors for all IRQs.
+ */
+ for (offset = 0; offset < gpiochip->ngpio; offset++) {
+ irq_base = irq_create_mapping(gpiochip->irqdomain, offset);
+ if (offset == 0)
+ /*
+ * Store the base into the gpiochip to be used when
+ * unmapping the irqs.
+ */
+ gpiochip->irq_base = irq_base;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gpiochip_irqchip_add);
+
+#else /* CONFIG_GPIOLIB_IRQCHIP */
+
+static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {}
+
+#endif /* CONFIG_GPIOLIB_IRQCHIP */
+
#ifdef CONFIG_PINCTRL
/**
@@ -1457,26 +1672,14 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges);
* on each other, and help provide better diagnostics in debugfs.
* They're called even less than the "set direction" calls.
*/
-static int gpiod_request(struct gpio_desc *desc, const char *label)
+static int __gpiod_request(struct gpio_desc *desc, const char *label)
{
- struct gpio_chip *chip;
- int status = -EPROBE_DEFER;
+ struct gpio_chip *chip = desc->chip;
+ int status;
unsigned long flags;
- if (!desc) {
- pr_warn("%s: invalid GPIO\n", __func__);
- return -EINVAL;
- }
-
spin_lock_irqsave(&gpio_lock, flags);
- chip = desc->chip;
- if (chip == NULL)
- goto done;
-
- if (!try_module_get(chip->owner))
- goto done;
-
/* NOTE: gpio_request() can be called in early boot,
* before IRQs are enabled, for non-sleeping (SOC) GPIOs.
*/
@@ -1486,7 +1689,6 @@ static int gpiod_request(struct gpio_desc *desc, const char *label)
status = 0;
} else {
status = -EBUSY;
- module_put(chip->owner);
goto done;
}
@@ -1498,7 +1700,6 @@ static int gpiod_request(struct gpio_desc *desc, const char *label)
if (status < 0) {
desc_set_label(desc, NULL);
- module_put(chip->owner);
clear_bit(FLAG_REQUESTED, &desc->flags);
goto done;
}
@@ -1510,9 +1711,34 @@ static int gpiod_request(struct gpio_desc *desc, const char *label)
spin_lock_irqsave(&gpio_lock, flags);
}
done:
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ return status;
+}
+
+static int gpiod_request(struct gpio_desc *desc, const char *label)
+{
+ int status = -EPROBE_DEFER;
+ struct gpio_chip *chip;
+
+ if (!desc) {
+ pr_warn("%s: invalid GPIO\n", __func__);
+ return -EINVAL;
+ }
+
+ chip = desc->chip;
+ if (!chip)
+ goto done;
+
+ if (try_module_get(chip->owner)) {
+ status = __gpiod_request(desc, label);
+ if (status < 0)
+ module_put(chip->owner);
+ }
+
+done:
if (status)
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
- spin_unlock_irqrestore(&gpio_lock, flags);
+
return status;
}
@@ -1522,18 +1748,14 @@ int gpio_request(unsigned gpio, const char *label)
}
EXPORT_SYMBOL_GPL(gpio_request);
-static void gpiod_free(struct gpio_desc *desc)
+static bool __gpiod_free(struct gpio_desc *desc)
{
+ bool ret = false;
unsigned long flags;
struct gpio_chip *chip;
might_sleep();
- if (!desc) {
- WARN_ON(extra_checks);
- return;
- }
-
gpiod_unexport(desc);
spin_lock_irqsave(&gpio_lock, flags);
@@ -1547,15 +1769,23 @@ static void gpiod_free(struct gpio_desc *desc)
spin_lock_irqsave(&gpio_lock, flags);
}
desc_set_label(desc, NULL);
- module_put(desc->chip->owner);
clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
clear_bit(FLAG_REQUESTED, &desc->flags);
clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
- } else
- WARN_ON(extra_checks);
+ ret = true;
+ }
spin_unlock_irqrestore(&gpio_lock, flags);
+ return ret;
+}
+
+static void gpiod_free(struct gpio_desc *desc)
+{
+ if (desc && __gpiod_free(desc))
+ module_put(desc->chip->owner);
+ else
+ WARN_ON(extra_checks);
}
void gpio_free(unsigned gpio)
@@ -1590,7 +1820,7 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
if (flags & GPIOF_DIR_IN)
err = gpiod_direction_input(desc);
else
- err = gpiod_direction_output(desc,
+ err = gpiod_direction_output_raw(desc,
(flags & GPIOF_INIT_HIGH) ? 1 : 0);
if (err)
@@ -1677,6 +1907,37 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)
}
EXPORT_SYMBOL_GPL(gpiochip_is_requested);
+/**
+ * gpiochip_request_own_desc - Allow GPIO chip to request its own descriptor
+ * @desc: GPIO descriptor to request
+ * @label: label for the GPIO
+ *
+ * Function allows GPIO chip drivers to request and use their own GPIO
+ * descriptors via gpiolib API. Difference to gpiod_request() is that this
+ * function will not increase reference count of the GPIO chip module. This
+ * allows the GPIO chip module to be unloaded as needed (we assume that the
+ * GPIO chip driver handles freeing the GPIOs it has requested).
+ */
+int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label)
+{
+ if (!desc || !desc->chip)
+ return -EINVAL;
+
+ return __gpiod_request(desc, label);
+}
+
+/**
+ * gpiochip_free_own_desc - Free GPIO requested by the chip driver
+ * @desc: GPIO descriptor to free
+ *
+ * Function frees the given GPIO requested previously with
+ * gpiochip_request_own_desc().
+ */
+void gpiochip_free_own_desc(struct gpio_desc *desc)
+{
+ if (desc)
+ __gpiod_free(desc);
+}
/* Drivers MUST set GPIO direction before making get/set calls. In
* some cases this is done in early boot, before IRQs are enabled.
@@ -1756,28 +2017,13 @@ fail:
}
EXPORT_SYMBOL_GPL(gpiod_direction_input);
-/**
- * gpiod_direction_output - set the GPIO direction to input
- * @desc: GPIO to set to output
- * @value: initial output value of the GPIO
- *
- * Set the direction of the passed GPIO to output, such as gpiod_set_value() can
- * be called safely on it. The initial value of the output must be specified.
- *
- * Return 0 in case of success, else an error code.
- */
-int gpiod_direction_output(struct gpio_desc *desc, int value)
+static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
{
unsigned long flags;
struct gpio_chip *chip;
int status = -EINVAL;
int offset;
- if (!desc || !desc->chip) {
- pr_warn("%s: invalid GPIO\n", __func__);
- return -EINVAL;
- }
-
/* GPIOs used for IRQs shall not be set as output */
if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) {
gpiod_err(desc,
@@ -1840,6 +2086,50 @@ fail:
gpiod_dbg(desc, "%s: gpio status %d\n", __func__, status);
return status;
}
+
+/**
+ * gpiod_direction_output_raw - set the GPIO direction to output
+ * @desc: GPIO to set to output
+ * @value: initial output value of the GPIO
+ *
+ * Set the direction of the passed GPIO to output, such as gpiod_set_value() can
+ * be called safely on it. The initial value of the output must be specified
+ * as raw value on the physical line without regard for the ACTIVE_LOW status.
+ *
+ * Return 0 in case of success, else an error code.
+ */
+int gpiod_direction_output_raw(struct gpio_desc *desc, int value)
+{
+ if (!desc || !desc->chip) {
+ pr_warn("%s: invalid GPIO\n", __func__);
+ return -EINVAL;
+ }
+ return _gpiod_direction_output_raw(desc, value);
+}
+EXPORT_SYMBOL_GPL(gpiod_direction_output_raw);
+
+/**
+ * gpiod_direction_output - set the GPIO direction to output
+ * @desc: GPIO to set to output
+ * @value: initial output value of the GPIO
+ *
+ * Set the direction of the passed GPIO to output, such as gpiod_set_value() can
+ * be called safely on it. The initial value of the output must be specified
+ * as the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into
+ * account.
+ *
+ * Return 0 in case of success, else an error code.
+ */
+int gpiod_direction_output(struct gpio_desc *desc, int value)
+{
+ if (!desc || !desc->chip) {
+ pr_warn("%s: invalid GPIO\n", __func__);
+ return -EINVAL;
+ }
+ if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
+ value = !value;
+ return _gpiod_direction_output_raw(desc, value);
+}
EXPORT_SYMBOL_GPL(gpiod_direction_output);
/**
@@ -1928,15 +2218,15 @@ EXPORT_SYMBOL_GPL(gpiod_is_active_low);
* that the GPIO was actually requested.
*/
-static int _gpiod_get_raw_value(const struct gpio_desc *desc)
+static bool _gpiod_get_raw_value(const struct gpio_desc *desc)
{
struct gpio_chip *chip;
- int value;
+ bool value;
int offset;
chip = desc->chip;
offset = gpio_chip_hwgpio(desc);
- value = chip->get ? chip->get(chip, offset) : 0;
+ value = chip->get ? chip->get(chip, offset) : false;
trace_gpio_value(desc_to_gpio(desc), 1, value);
return value;
}
@@ -1992,7 +2282,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_value);
* @desc: gpio descriptor whose state need to be set.
* @value: Non-zero for setting it HIGH otherise it will set to LOW.
*/
-static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value)
+static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value)
{
int err = 0;
struct gpio_chip *chip = desc->chip;
@@ -2019,7 +2309,7 @@ static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value)
* @desc: gpio descriptor whose state need to be set.
* @value: Non-zero for setting it HIGH otherise it will set to LOW.
*/
-static void _gpio_set_open_source_value(struct gpio_desc *desc, int value)
+static void _gpio_set_open_source_value(struct gpio_desc *desc, bool value)
{
int err = 0;
struct gpio_chip *chip = desc->chip;
@@ -2041,7 +2331,7 @@ static void _gpio_set_open_source_value(struct gpio_desc *desc, int value)
__func__, err);
}
-static void _gpiod_set_raw_value(struct gpio_desc *desc, int value)
+static void _gpiod_set_raw_value(struct gpio_desc *desc, bool value)
{
struct gpio_chip *chip;
@@ -2137,10 +2427,7 @@ EXPORT_SYMBOL_GPL(gpiod_to_irq);
* @gpio: the GPIO line to lock as used for IRQ
*
* This is used directly by GPIO drivers that want to lock down
- * a certain GPIO line to be used as IRQs, for example in the
- * .to_irq() callback of their gpio_chip, or in the .irq_enable()
- * of its irq_chip implementation if the GPIO is known from that
- * code.
+ * a certain GPIO line to be used for IRQs.
*/
int gpiod_lock_as_irq(struct gpio_desc *desc)
{
@@ -2161,7 +2448,7 @@ EXPORT_SYMBOL_GPL(gpiod_lock_as_irq);
int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
{
- return gpiod_lock_as_irq(gpiochip_offset_to_desc(chip, offset));
+ return gpiod_lock_as_irq(gpiochip_get_desc(chip, offset));
}
EXPORT_SYMBOL_GPL(gpio_lock_as_irq);
@@ -2183,7 +2470,7 @@ EXPORT_SYMBOL_GPL(gpiod_unlock_as_irq);
void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
{
- return gpiod_unlock_as_irq(gpiochip_offset_to_desc(chip, offset));
+ return gpiod_unlock_as_irq(gpiochip_get_desc(chip, offset));
}
EXPORT_SYMBOL_GPL(gpio_unlock_as_irq);
@@ -2404,7 +2691,7 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
return ERR_PTR(-EINVAL);
}
- desc = gpiochip_offset_to_desc(chip, p->chip_hwnum);
+ desc = gpiochip_get_desc(chip, p->chip_hwnum);
*flags = p->flags;
return desc;
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index 82be586c1f90..cf092941a9fd 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -43,4 +43,7 @@ acpi_get_gpiod_by_index(struct device *dev, int index,
}
#endif
+int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label);
+void gpiochip_free_own_desc(struct gpio_desc *desc);
+
#endif /* GPIOLIB_H */
diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c
index acf3a36c9ebc..32982da82694 100644
--- a/drivers/gpu/drm/armada/armada_drv.c
+++ b/drivers/gpu/drm/armada/armada_drv.c
@@ -68,15 +68,7 @@ void __armada_drm_queue_unref_work(struct drm_device *dev,
{
struct armada_private *priv = dev->dev_private;
- /*
- * Yes, we really must jump through these hoops just to store a
- * _pointer_ to something into the kfifo. This is utterly insane
- * and idiotic, because it kfifo requires the _data_ pointed to by
- * the pointer const, not the pointer itself. Not only that, but
- * you have to pass a pointer _to_ the pointer you want stored.
- */
- const struct drm_framebuffer *silly_api_alert = fb;
- WARN_ON(!kfifo_put(&priv->fb_unref, &silly_api_alert));
+ WARN_ON(!kfifo_put(&priv->fb_unref, fb));
schedule_work(&priv->fb_unref_work);
}
diff --git a/drivers/gpu/drm/bochs/Kconfig b/drivers/gpu/drm/bochs/Kconfig
index c8fcf12019f0..5f8b0c2b9a44 100644
--- a/drivers/gpu/drm/bochs/Kconfig
+++ b/drivers/gpu/drm/bochs/Kconfig
@@ -2,6 +2,7 @@ config DRM_BOCHS
tristate "DRM Support for bochs dispi vga interface (qemu stdvga)"
depends on DRM && PCI
select DRM_KMS_HELPER
+ select DRM_KMS_FB_HELPER
select FB_SYS_FILLRECT
select FB_SYS_COPYAREA
select FB_SYS_IMAGEBLIT
diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c
index bb8f58012189..534cb89b160d 100644
--- a/drivers/gpu/drm/drm_cache.c
+++ b/drivers/gpu/drm/drm_cache.c
@@ -32,6 +32,12 @@
#include <drm/drmP.h>
#if defined(CONFIG_X86)
+
+/*
+ * clflushopt is an unordered instruction which needs fencing with mfence or
+ * sfence to avoid ordering issues. For drm_clflush_page this fencing happens
+ * in the caller.
+ */
static void
drm_clflush_page(struct page *page)
{
@@ -44,7 +50,7 @@ drm_clflush_page(struct page *page)
page_virtual = kmap_atomic(page);
for (i = 0; i < PAGE_SIZE; i += size)
- clflush(page_virtual + i);
+ clflushopt(page_virtual + i);
kunmap_atomic(page_virtual);
}
@@ -133,7 +139,7 @@ drm_clflush_virt_range(char *addr, unsigned long length)
mb();
for (; addr < end; addr += boot_cpu_data.x86_clflush_size)
clflush(addr);
- clflush(end - 1);
+ clflushopt(end - 1);
mb();
return;
}
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index ea92b827e787..f7a81209beb3 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -564,7 +564,7 @@ drm_crtc_helper_disable(struct drm_crtc *crtc)
* Caller must hold mode config lock.
*
* Setup a new configuration, provided by the upper layers (either an ioctl call
- * from userspace or internally e.g. from the fbdev suppport code) in @set, and
+ * from userspace or internally e.g. from the fbdev support code) in @set, and
* enable it. This is the main helper functions for drivers that implement
* kernel mode setting with the crtc helper functions and the assorted
* ->prepare(), ->modeset() and ->commit() helper callbacks.
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 7f2af9aca038..309023f12d7f 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -319,7 +319,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
pci_dev_put(pci_dev);
}
if (!dev->hose) {
- struct pci_bus *b = pci_bus_b(pci_root_buses.next);
+ struct pci_bus *b = list_entry(pci_root_buses.next,
+ struct pci_bus, node);
if (b)
dev->hose = b->sysdata;
}
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index dffc836144cc..f4dc9b7a3831 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -296,6 +296,18 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
case DRM_CAP_ASYNC_PAGE_FLIP:
req->value = dev->mode_config.async_page_flip;
break;
+ case DRM_CAP_CURSOR_WIDTH:
+ if (dev->mode_config.cursor_width)
+ req->value = dev->mode_config.cursor_width;
+ else
+ req->value = 64;
+ break;
+ case DRM_CAP_CURSOR_HEIGHT:
+ if (dev->mode_config.cursor_height)
+ req->value = dev->mode_config.cursor_height;
+ else
+ req->value = 64;
+ break;
default:
return -EINVAL;
}
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index 5736aaa7e86c..f7af69bcf3f4 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -468,8 +468,8 @@ void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver)
} else {
list_for_each_entry_safe(dev, tmp, &driver->legacy_dev_list,
legacy_dev_list) {
- drm_put_dev(dev);
list_del(&dev->legacy_dev_list);
+ drm_put_dev(dev);
}
}
DRM_INFO("Module unloaded\n");
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 56805c39c906..bb516fdd195d 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -471,7 +471,7 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
get_dma_buf(dma_buf);
sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
- if (IS_ERR_OR_NULL(sgt)) {
+ if (IS_ERR(sgt)) {
ret = PTR_ERR(sgt);
goto fail_detach;
}
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index f227f544aa36..6e1a1a20cf6b 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -51,7 +51,7 @@ config DRM_EXYNOS_G2D
config DRM_EXYNOS_IPP
bool "Exynos DRM IPP"
- depends on DRM_EXYNOS && !ARCH_MULTIPLATFORM
+ depends on DRM_EXYNOS
help
Choose this option if you want to use IPP feature for DRM.
@@ -69,6 +69,6 @@ config DRM_EXYNOS_ROTATOR
config DRM_EXYNOS_GSC
bool "Exynos DRM GSC"
- depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5
+ depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 && !ARCH_MULTIPLATFORM
help
Choose this option if you want to use Exynos GSC for DRM.
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
index 59827cc5e770..c786cd4f457b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
@@ -224,7 +224,7 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
get_dma_buf(dma_buf);
sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
- if (IS_ERR_OR_NULL(sgt)) {
+ if (IS_ERR(sgt)) {
ret = PTR_ERR(sgt);
goto err_buf_detach;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 9d096a0c5f8d..c204b4e3356e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -171,22 +171,28 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
file->driver_priv = file_priv;
ret = exynos_drm_subdrv_open(dev, file);
- if (ret) {
- kfree(file_priv);
- file->driver_priv = NULL;
- }
+ if (ret)
+ goto err_file_priv_free;
anon_filp = anon_inode_getfile("exynos_gem", &exynos_drm_gem_fops,
NULL, 0);
if (IS_ERR(anon_filp)) {
- kfree(file_priv);
- return PTR_ERR(anon_filp);
+ ret = PTR_ERR(anon_filp);
+ goto err_subdrv_close;
}
anon_filp->f_mode = FMODE_READ | FMODE_WRITE;
file_priv->anon_filp = anon_filp;
return ret;
+
+err_subdrv_close:
+ exynos_drm_subdrv_close(dev, file);
+
+err_file_priv_free:
+ kfree(file_priv);
+ file->driver_priv = NULL;
+ return ret;
}
static void exynos_drm_preclose(struct drm_device *dev,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 0eaf5a27e120..a8f9dba2a816 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -237,7 +237,6 @@ struct drm_exynos_file_private {
* otherwise default one.
* @da_space_size: size of device address space.
* if 0 then default value is used for it.
- * @da_space_order: order to device address space.
*/
struct exynos_drm_private {
struct drm_fb_helper *fb_helper;
@@ -255,7 +254,6 @@ struct exynos_drm_private {
unsigned long da_start;
unsigned long da_space_size;
- unsigned long da_space_order;
};
/*
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 380aec28840b..6c1885eedfdf 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -607,7 +607,7 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset)
reg_type = REG_TYPE_NONE;
DRM_ERROR("Unknown register offset![%d]\n", reg_offset);
break;
- };
+ }
return reg_type;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.c b/drivers/gpu/drm/exynos/exynos_drm_iommu.c
index fb8db0378274..b32b291f88ff 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_iommu.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.c
@@ -36,12 +36,10 @@ int drm_create_iommu_mapping(struct drm_device *drm_dev)
priv->da_start = EXYNOS_DEV_ADDR_START;
if (!priv->da_space_size)
priv->da_space_size = EXYNOS_DEV_ADDR_SIZE;
- if (!priv->da_space_order)
- priv->da_space_order = EXYNOS_DEV_ADDR_ORDER;
mapping = arm_iommu_create_mapping(&platform_bus_type, priv->da_start,
- priv->da_space_size,
- priv->da_space_order);
+ priv->da_space_size);
+
if (IS_ERR(mapping))
return PTR_ERR(mapping);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.h b/drivers/gpu/drm/exynos/exynos_drm_iommu.h
index 598e60f57d4b..72376d41c512 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_iommu.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.h
@@ -14,7 +14,6 @@
#define EXYNOS_DEV_ADDR_START 0x20000000
#define EXYNOS_DEV_ADDR_SIZE 0x40000000
-#define EXYNOS_DEV_ADDR_ORDER 0x0
#ifdef CONFIG_DRM_EXYNOS_IOMMU
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
index d519a4e5fe40..09312b877470 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
@@ -16,7 +16,6 @@
#include <linux/types.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
-#include <plat/map-base.h>
#include <drm/drmP.h>
#include <drm/exynos_drm.h>
@@ -826,7 +825,7 @@ static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node,
DRM_DEBUG_KMS("count[%d]e[0x%x]\n", count++, (int)e);
/*
- * quf == NULL condition means all event deletion.
+ * qbuf == NULL condition means all event deletion.
* stop operations want to delete all event list.
* another case delete only same buf id.
*/
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index a0e10aeb0e67..c021ddc1ffb4 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -34,6 +34,7 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
+#include <linux/hdmi.h>
#include <drm/exynos_drm.h>
@@ -59,19 +60,6 @@
#define HDMI_AUI_VERSION 0x01
#define HDMI_AUI_LENGTH 0x0A
-/* HDMI infoframe to configure HDMI out packet header, AUI and AVI */
-enum HDMI_PACKET_TYPE {
- /* refer to Table 5-8 Packet Type in HDMI specification v1.4a */
- /* InfoFrame packet type */
- HDMI_PACKET_TYPE_INFOFRAME = 0x80,
- /* Vendor-Specific InfoFrame */
- HDMI_PACKET_TYPE_VSI = HDMI_PACKET_TYPE_INFOFRAME + 1,
- /* Auxiliary Video information InfoFrame */
- HDMI_PACKET_TYPE_AVI = HDMI_PACKET_TYPE_INFOFRAME + 2,
- /* Audio information InfoFrame */
- HDMI_PACKET_TYPE_AUI = HDMI_PACKET_TYPE_INFOFRAME + 4
-};
-
enum hdmi_type {
HDMI_TYPE13,
HDMI_TYPE14,
@@ -379,12 +367,6 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = {
},
};
-struct hdmi_infoframe {
- enum HDMI_PACKET_TYPE type;
- u8 ver;
- u8 len;
-};
-
static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
{
return readl(hdata->regs + reg_id);
@@ -682,7 +664,7 @@ static u8 hdmi_chksum(struct hdmi_context *hdata,
}
static void hdmi_reg_infoframe(struct hdmi_context *hdata,
- struct hdmi_infoframe *infoframe)
+ union hdmi_infoframe *infoframe)
{
u32 hdr_sum;
u8 chksum;
@@ -700,13 +682,15 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
return;
}
- switch (infoframe->type) {
- case HDMI_PACKET_TYPE_AVI:
+ switch (infoframe->any.type) {
+ case HDMI_INFOFRAME_TYPE_AVI:
hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
- hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->type);
- hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1, infoframe->ver);
- hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->len);
- hdr_sum = infoframe->type + infoframe->ver + infoframe->len;
+ hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
+ hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
+ infoframe->any.version);
+ hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
+ hdr_sum = infoframe->any.type + infoframe->any.version +
+ infoframe->any.length;
/* Output format zero hardcoded ,RGB YBCR selection */
hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
@@ -722,18 +706,20 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
- infoframe->len, hdr_sum);
+ infoframe->any.length, hdr_sum);
DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
break;
- case HDMI_PACKET_TYPE_AUI:
+ case HDMI_INFOFRAME_TYPE_AUDIO:
hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
- hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->type);
- hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1, infoframe->ver);
- hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->len);
- hdr_sum = infoframe->type + infoframe->ver + infoframe->len;
+ hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
+ hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
+ infoframe->any.version);
+ hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
+ hdr_sum = infoframe->any.type + infoframe->any.version +
+ infoframe->any.length;
chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
- infoframe->len, hdr_sum);
+ infoframe->any.length, hdr_sum);
DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
break;
@@ -985,7 +971,7 @@ static void hdmi_conf_reset(struct hdmi_context *hdata)
static void hdmi_conf_init(struct hdmi_context *hdata)
{
- struct hdmi_infoframe infoframe;
+ union hdmi_infoframe infoframe;
/* disable HPD interrupts from HDMI IP block, use GPIO instead */
hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
@@ -1021,14 +1007,14 @@ static void hdmi_conf_init(struct hdmi_context *hdata)
hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
} else {
- infoframe.type = HDMI_PACKET_TYPE_AVI;
- infoframe.ver = HDMI_AVI_VERSION;
- infoframe.len = HDMI_AVI_LENGTH;
+ infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
+ infoframe.any.version = HDMI_AVI_VERSION;
+ infoframe.any.length = HDMI_AVI_LENGTH;
hdmi_reg_infoframe(hdata, &infoframe);
- infoframe.type = HDMI_PACKET_TYPE_AUI;
- infoframe.ver = HDMI_AUI_VERSION;
- infoframe.len = HDMI_AUI_LENGTH;
+ infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
+ infoframe.any.version = HDMI_AUI_VERSION;
+ infoframe.any.length = HDMI_AUI_LENGTH;
hdmi_reg_infoframe(hdata, &infoframe);
/* enable AVI packet every vsync, fixes purple line problem */
diff --git a/drivers/gpu/drm/gma500/Kconfig b/drivers/gpu/drm/gma500/Kconfig
index 508cf99a292d..17f928ec84ea 100644
--- a/drivers/gpu/drm/gma500/Kconfig
+++ b/drivers/gpu/drm/gma500/Kconfig
@@ -10,7 +10,6 @@ config DRM_GMA500
# GMA500 depends on ACPI_VIDEO when ACPI is enabled, just like i915
select ACPI_VIDEO if ACPI
select BACKLIGHT_CLASS_DEVICE if ACPI
- select VIDEO_OUTPUT_CONTROL if ACPI
select INPUT if ACPI
help
Say yes for an experimental 2D KMS framebuffer driver for the
diff --git a/drivers/gpu/drm/gma500/mmu.c b/drivers/gpu/drm/gma500/mmu.c
index 49bac41beefb..c3e67ba94446 100644
--- a/drivers/gpu/drm/gma500/mmu.c
+++ b/drivers/gpu/drm/gma500/mmu.c
@@ -520,7 +520,7 @@ struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers,
driver->has_clflush = 0;
- if (boot_cpu_has(X86_FEATURE_CLFLSH)) {
+ if (boot_cpu_has(X86_FEATURE_CLFLUSH)) {
uint32_t tfms, misc, cap0, cap4, clflush_size;
/*
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index 400b0c4a10fb..faa77f543a07 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -208,7 +208,7 @@ struct tda998x_priv {
# define PLL_SERIAL_1_SRL_IZ(x) (((x) & 3) << 1)
# define PLL_SERIAL_1_SRL_MAN_IZ (1 << 6)
#define REG_PLL_SERIAL_2 REG(0x02, 0x01) /* read/write */
-# define PLL_SERIAL_2_SRL_NOSC(x) (((x) & 3) << 0)
+# define PLL_SERIAL_2_SRL_NOSC(x) ((x) << 0)
# define PLL_SERIAL_2_SRL_PR(x) (((x) & 0xf) << 4)
#define REG_PLL_SERIAL_3 REG(0x02, 0x02) /* read/write */
# define PLL_SERIAL_3_SRL_CCIR (1 << 0)
@@ -528,10 +528,10 @@ tda998x_write_aif(struct drm_encoder *encoder, struct tda998x_encoder_params *p)
{
uint8_t buf[PB(5) + 1];
+ memset(buf, 0, sizeof(buf));
buf[HB(0)] = 0x84;
buf[HB(1)] = 0x01;
buf[HB(2)] = 10;
- buf[PB(0)] = 0;
buf[PB(1)] = p->audio_frame[1] & 0x07; /* CC */
buf[PB(2)] = p->audio_frame[2] & 0x1c; /* SF */
buf[PB(4)] = p->audio_frame[4];
@@ -824,6 +824,11 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,
}
div = 148500 / mode->clock;
+ if (div != 0) {
+ div--;
+ if (div > 3)
+ div = 3;
+ }
/* mute the audio FIFO: */
reg_set(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO);
@@ -913,7 +918,7 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,
if (priv->rev == TDA19988) {
/* let incoming pixels fill the active space (if any) */
- reg_write(encoder, REG_ENABLE_SPACE, 0x01);
+ reg_write(encoder, REG_ENABLE_SPACE, 0x00);
}
/* must be last register set: */
@@ -1094,6 +1099,8 @@ tda998x_encoder_destroy(struct drm_encoder *encoder)
{
struct tda998x_priv *priv = to_tda998x_priv(encoder);
drm_i2c_encoder_destroy(encoder);
+ if (priv->cec)
+ i2c_unregister_device(priv->cec);
kfree(priv);
}
@@ -1142,8 +1149,12 @@ tda998x_encoder_init(struct i2c_client *client,
priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(0) | VIP_CNTRL_1_SWAP_D(1);
priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(4) | VIP_CNTRL_2_SWAP_F(5);
- priv->current_page = 0;
+ priv->current_page = 0xff;
priv->cec = i2c_new_dummy(client->adapter, 0x34);
+ if (!priv->cec) {
+ kfree(priv);
+ return -ENODEV;
+ }
priv->dpms = DRM_MODE_DPMS_OFF;
encoder_slave->slave_priv = priv;
diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index 73ed59eff139..bea2d67196fb 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -14,7 +14,6 @@ config DRM_I915
# but for select to work, need to select ACPI_VIDEO's dependencies, ick
select BACKLIGHT_LCD_SUPPORT if ACPI
select BACKLIGHT_CLASS_DEVICE if ACPI
- select VIDEO_OUTPUT_CONTROL if ACPI
select INPUT if ACPI
select ACPI_VIDEO if ACPI
select ACPI_BUTTON if ACPI
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 04f1f02c4019..ec7bb0fc71bc 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -403,7 +403,7 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
void intel_detect_pch(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct pci_dev *pch;
+ struct pci_dev *pch = NULL;
/* In all current cases, num_pipes is equivalent to the PCH_NOP setting
* (which really amounts to a PCH but no South Display).
@@ -424,12 +424,9 @@ void intel_detect_pch(struct drm_device *dev)
* all the ISA bridge devices and check for the first match, instead
* of only checking the first one.
*/
- pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
- while (pch) {
- struct pci_dev *curr = pch;
+ while ((pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, pch))) {
if (pch->vendor == PCI_VENDOR_ID_INTEL) {
- unsigned short id;
- id = pch->device & INTEL_PCH_DEVICE_ID_MASK;
+ unsigned short id = pch->device & INTEL_PCH_DEVICE_ID_MASK;
dev_priv->pch_id = id;
if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) {
@@ -461,18 +458,16 @@ void intel_detect_pch(struct drm_device *dev)
DRM_DEBUG_KMS("Found LynxPoint LP PCH\n");
WARN_ON(!IS_HASWELL(dev));
WARN_ON(!IS_ULT(dev));
- } else {
- goto check_next;
- }
- pci_dev_put(pch);
+ } else
+ continue;
+
break;
}
-check_next:
- pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, curr);
- pci_dev_put(curr);
}
if (!pch)
- DRM_DEBUG_KMS("No PCH found?\n");
+ DRM_DEBUG_KMS("No PCH found.\n");
+
+ pci_dev_put(pch);
}
bool i915_semaphore_is_enabled(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 4a2bf8e3f739..df77e20e3c3d 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1831,6 +1831,14 @@ struct drm_i915_file_private {
/* Early gen2 have a totally busted CS tlb and require pinned batches. */
#define HAS_BROKEN_CS_TLB(dev) (IS_I830(dev) || IS_845G(dev))
+/*
+ * dp aux and gmbus irq on gen4 seems to be able to generate legacy interrupts
+ * even when in MSI mode. This results in spurious interrupt warnings if the
+ * legacy irq no. is shared with another device. The kernel then disables that
+ * interrupt source and so prevents the other device from working properly.
+ */
+#define HAS_AUX_IRQ(dev) (INTEL_INFO(dev)->gen >= 5)
+#define HAS_GMBUS_IRQ(dev) (INTEL_INFO(dev)->gen >= 5)
/* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
* rows, which changed the alignment requirements and fence programming.
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 40a2b36b276b..d278be110805 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -842,7 +842,7 @@ void i915_gem_suspend_gtt_mappings(struct drm_device *dev)
dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
dev_priv->gtt.base.start / PAGE_SIZE,
dev_priv->gtt.base.total / PAGE_SIZE,
- false);
+ true);
}
void i915_gem_restore_gtt_mappings(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c
index 1a24e84f2315..28d24caa49f3 100644
--- a/drivers/gpu/drm/i915/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
@@ -82,9 +82,22 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
r = devm_request_mem_region(dev->dev, base, dev_priv->gtt.stolen_size,
"Graphics Stolen Memory");
if (r == NULL) {
- DRM_ERROR("conflict detected with stolen region: [0x%08x - 0x%08x]\n",
- base, base + (uint32_t)dev_priv->gtt.stolen_size);
- base = 0;
+ /*
+ * One more attempt but this time requesting region from
+ * base + 1, as we have seen that this resolves the region
+ * conflict with the PCI Bus.
+ * This is a BIOS w/a: Some BIOS wrap stolen in the root
+ * PCI bus, but have an off-by-one error. Hence retry the
+ * reservation starting from 1 instead of 0.
+ */
+ r = devm_request_mem_region(dev->dev, base + 1,
+ dev_priv->gtt.stolen_size - 1,
+ "Graphics Stolen Memory");
+ if (r == NULL) {
+ DRM_ERROR("conflict detected with stolen region: [0x%08x - 0x%08x]\n",
+ base, base + (uint32_t)dev_priv->gtt.stolen_size);
+ base = 0;
+ }
}
return base;
@@ -201,6 +214,13 @@ int i915_gem_init_stolen(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
int bios_reserved = 0;
+#ifdef CONFIG_INTEL_IOMMU
+ if (intel_iommu_gfx_mapped) {
+ DRM_INFO("DMAR active, disabling use of stolen memory\n");
+ return 0;
+ }
+#endif
+
if (dev_priv->gtt.stolen_size == 0)
return 0;
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index d7fd2fd2f0a5..990cf8f43efd 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -146,7 +146,10 @@ static void i915_error_vprintf(struct drm_i915_error_state_buf *e,
va_list tmp;
va_copy(tmp, args);
- if (!__i915_error_seek(e, vsnprintf(NULL, 0, f, tmp)))
+ len = vsnprintf(NULL, 0, f, tmp);
+ va_end(tmp);
+
+ if (!__i915_error_seek(e, len))
return;
}
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 17d8fcb1b6f7..d554169ac592 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -567,8 +567,7 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
vbl_start = mode->crtc_vblank_start * mode->crtc_htotal;
} else {
- enum transcoder cpu_transcoder =
- intel_pipe_to_cpu_transcoder(dev_priv, pipe);
+ enum transcoder cpu_transcoder = (enum transcoder) pipe;
u32 htotal;
htotal = ((I915_READ(HTOTAL(cpu_transcoder)) >> 16) & 0x1fff) + 1;
@@ -619,33 +618,25 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
/* raw reads, only for fast reads of display block, no need for forcewake etc. */
#define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__))
-#define __raw_i915_read16(dev_priv__, reg__) readw((dev_priv__)->regs + (reg__))
static bool ilk_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t status;
-
- if (INTEL_INFO(dev)->gen < 7) {
- status = pipe == PIPE_A ?
- DE_PIPEA_VBLANK :
- DE_PIPEB_VBLANK;
+ int reg;
+
+ if (INTEL_INFO(dev)->gen >= 8) {
+ status = GEN8_PIPE_VBLANK;
+ reg = GEN8_DE_PIPE_ISR(pipe);
+ } else if (INTEL_INFO(dev)->gen >= 7) {
+ status = DE_PIPE_VBLANK_IVB(pipe);
+ reg = DEISR;
} else {
- switch (pipe) {
- default:
- case PIPE_A:
- status = DE_PIPEA_VBLANK_IVB;
- break;
- case PIPE_B:
- status = DE_PIPEB_VBLANK_IVB;
- break;
- case PIPE_C:
- status = DE_PIPEC_VBLANK_IVB;
- break;
- }
+ status = DE_PIPE_VBLANK(pipe);
+ reg = DEISR;
}
- return __raw_i915_read32(dev_priv, DEISR) & status;
+ return __raw_i915_read32(dev_priv, reg) & status;
}
static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
@@ -703,7 +694,28 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
else
position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
- if (HAS_PCH_SPLIT(dev)) {
+ if (HAS_DDI(dev)) {
+ /*
+ * On HSW HDMI outputs there seems to be a 2 line
+ * difference, whereas eDP has the normal 1 line
+ * difference that earlier platforms have. External
+ * DP is unknown. For now just check for the 2 line
+ * difference case on all output types on HSW+.
+ *
+ * This might misinterpret the scanline counter being
+ * one line too far along on eDP, but that's less
+ * dangerous than the alternative since that would lead
+ * the vblank timestamp code astray when it sees a
+ * scanline count before vblank_start during a vblank
+ * interrupt.
+ */
+ in_vbl = ilk_pipe_in_vblank_locked(dev, pipe);
+ if ((in_vbl && (position == vbl_start - 2 ||
+ position == vbl_start - 1)) ||
+ (!in_vbl && (position == vbl_end - 2 ||
+ position == vbl_end - 1)))
+ position = (position + 2) % vtotal;
+ } else if (HAS_PCH_SPLIT(dev)) {
/*
* The scanline counter increments at the leading edge
* of hsync, ie. it completely misses the active portion
@@ -2770,10 +2782,9 @@ static void ibx_irq_postinstall(struct drm_device *dev)
return;
if (HAS_PCH_IBX(dev)) {
- mask = SDE_GMBUS | SDE_AUX_MASK | SDE_TRANSB_FIFO_UNDER |
- SDE_TRANSA_FIFO_UNDER | SDE_POISON;
+ mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON;
} else {
- mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT | SDE_ERROR_CPT;
+ mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT;
I915_WRITE(SERR_INT, I915_READ(SERR_INT));
}
@@ -2833,20 +2844,19 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE_IVB |
DE_PCH_EVENT_IVB | DE_PLANEC_FLIP_DONE_IVB |
DE_PLANEB_FLIP_DONE_IVB |
- DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB |
- DE_ERR_INT_IVB);
+ DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB);
extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB |
- DE_PIPEA_VBLANK_IVB);
+ DE_PIPEA_VBLANK_IVB | DE_ERR_INT_IVB);
I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT));
} else {
display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
DE_AUX_CHANNEL_A |
- DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN |
DE_PIPEB_CRC_DONE | DE_PIPEA_CRC_DONE |
DE_POISON);
- extra_mask = DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT;
+ extra_mask = DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT |
+ DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN;
}
dev_priv->irq_mask = ~display_mask;
@@ -2962,9 +2972,9 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
struct drm_device *dev = dev_priv->dev;
uint32_t de_pipe_masked = GEN8_PIPE_FLIP_DONE |
GEN8_PIPE_CDCLK_CRC_DONE |
- GEN8_PIPE_FIFO_UNDERRUN |
GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
- uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK;
+ uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK |
+ GEN8_PIPE_FIFO_UNDERRUN;
int pipe;
dev_priv->de_irq_mask[PIPE_A] = ~de_pipe_masked;
dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_masked;
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index e06b9e017d6b..234ac5f7bc5a 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1244,6 +1244,7 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
+ ironlake_edp_panel_vdd_on(intel_dp);
ironlake_edp_panel_off(intel_dp);
}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 9fa24347963a..9b8a7c7ea7fc 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1092,12 +1092,12 @@ static void assert_cursor(struct drm_i915_private *dev_priv,
struct drm_device *dev = dev_priv->dev;
bool cur_state;
- if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
- cur_state = I915_READ(CURCNTR_IVB(pipe)) & CURSOR_MODE;
- else if (IS_845G(dev) || IS_I865G(dev))
+ if (IS_845G(dev) || IS_I865G(dev))
cur_state = I915_READ(_CURACNTR) & CURSOR_ENABLE;
- else
+ else if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev))
cur_state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE;
+ else
+ cur_state = I915_READ(CURCNTR_IVB(pipe)) & CURSOR_MODE;
WARN(cur_state != state,
"cursor on pipe %c assertion failure (expected %s, current %s)\n",
@@ -8586,6 +8586,20 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
if (ring->id == RCS)
len += 6;
+ /*
+ * BSpec MI_DISPLAY_FLIP for IVB:
+ * "The full packet must be contained within the same cache line."
+ *
+ * Currently the LRI+SRM+MI_DISPLAY_FLIP all fit within the same
+ * cacheline, if we ever start emitting more commands before
+ * the MI_DISPLAY_FLIP we may need to first emit everything else,
+ * then do the cacheline alignment, and finally emit the
+ * MI_DISPLAY_FLIP.
+ */
+ ret = intel_ring_cacheline_align(ring);
+ if (ret)
+ goto err_unpin;
+
ret = intel_ring_begin(ring, len);
if (ret)
goto err_unpin;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 5ede4e8e290d..2688f6d64bb9 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -404,7 +404,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
int i, ret, recv_bytes;
uint32_t status;
int try, precharge, clock = 0;
- bool has_aux_irq = true;
+ bool has_aux_irq = HAS_AUX_IRQ(dev);
uint32_t timeout;
/* dp aux is extremely sensitive to irq latency, hence request the
@@ -537,6 +537,7 @@ intel_dp_aux_native_write(struct intel_dp *intel_dp,
uint8_t msg[20];
int msg_bytes;
uint8_t ack;
+ int retry;
if (WARN_ON(send_bytes > 16))
return -E2BIG;
@@ -548,19 +549,21 @@ intel_dp_aux_native_write(struct intel_dp *intel_dp,
msg[3] = send_bytes - 1;
memcpy(&msg[4], send, send_bytes);
msg_bytes = send_bytes + 4;
- for (;;) {
+ for (retry = 0; retry < 7; retry++) {
ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes, &ack, 1);
if (ret < 0)
return ret;
ack >>= 4;
if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK)
- break;
+ return send_bytes;
else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER)
- udelay(100);
+ usleep_range(400, 500);
else
return -EIO;
}
- return send_bytes;
+
+ DRM_ERROR("too many retries, giving up\n");
+ return -EIO;
}
/* Write a single byte to the aux channel in native mode */
@@ -582,6 +585,7 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp,
int reply_bytes;
uint8_t ack;
int ret;
+ int retry;
if (WARN_ON(recv_bytes > 19))
return -E2BIG;
@@ -595,7 +599,7 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp,
msg_bytes = 4;
reply_bytes = recv_bytes + 1;
- for (;;) {
+ for (retry = 0; retry < 7; retry++) {
ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes,
reply, reply_bytes);
if (ret == 0)
@@ -608,10 +612,13 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp,
return ret - 1;
}
else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER)
- udelay(100);
+ usleep_range(400, 500);
else
return -EIO;
}
+
+ DRM_ERROR("too many retries, giving up\n");
+ return -EIO;
}
static int
@@ -1242,17 +1249,24 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp)
DRM_DEBUG_KMS("Turn eDP power off\n");
+ WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n");
+
pp = ironlake_get_pp_control(intel_dp);
/* We need to switch off panel power _and_ force vdd, for otherwise some
* panels get very unhappy and cease to work. */
- pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_BLC_ENABLE);
+ pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE);
pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
I915_WRITE(pp_ctrl_reg, pp);
POSTING_READ(pp_ctrl_reg);
+ intel_dp->want_panel_vdd = false;
+
ironlake_wait_panel_off(intel_dp);
+
+ /* We got a reference when we enabled the VDD. */
+ intel_runtime_pm_put(dev_priv);
}
void ironlake_edp_backlight_on(struct intel_dp *intel_dp)
@@ -1632,7 +1646,7 @@ static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
val |= EDP_PSR_LINK_DISABLE;
I915_WRITE(EDP_PSR_CTL(dev), val |
- IS_BROADWELL(dev) ? 0 : link_entry_time |
+ (IS_BROADWELL(dev) ? 0 : link_entry_time) |
max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT |
idle_frames << EDP_PSR_IDLE_FRAME_SHIFT |
EDP_PSR_ENABLE);
@@ -1777,6 +1791,7 @@ static void intel_disable_dp(struct intel_encoder *encoder)
/* Make sure the panel is off before trying to change the mode. But also
* ensure that we have vdd while we switch off the panel. */
+ ironlake_edp_panel_vdd_on(intel_dp);
ironlake_edp_backlight_off(intel_dp);
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
ironlake_edp_panel_off(intel_dp);
@@ -1869,10 +1884,12 @@ static void vlv_pre_enable_dp(struct intel_encoder *encoder)
mutex_unlock(&dev_priv->dpio_lock);
- /* init power sequencer on this pipe and port */
- intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
- intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
- &power_seq);
+ if (is_edp(intel_dp)) {
+ /* init power sequencer on this pipe and port */
+ intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
+ intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
+ &power_seq);
+ }
intel_enable_dp(encoder);
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 6db0d9d17f47..ee3181ebcc92 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -845,7 +845,7 @@ static int hdmi_portclock_limit(struct intel_hdmi *hdmi)
{
struct drm_device *dev = intel_hdmi_to_dev(hdmi);
- if (IS_G4X(dev))
+ if (!hdmi->has_hdmi_sink || IS_G4X(dev))
return 165000;
else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8)
return 300000;
@@ -899,8 +899,8 @@ 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 <= portclock_limit
- && HAS_PCH_SPLIT(dev)) {
+ if (pipe_config->pipe_bpp > 8*3 && intel_hdmi->has_hdmi_sink &&
+ clock_12bpc <= portclock_limit && HAS_PCH_SPLIT(dev)) {
DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
desired_bpp = 12*3;
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index b1dc33f47899..d33b61d0dd33 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -258,13 +258,6 @@ intel_gpio_setup(struct intel_gmbus *bus, u32 pin)
algo->data = bus;
}
-/*
- * gmbus on gen4 seems to be able to generate legacy interrupts even when in MSI
- * mode. This results in spurious interrupt warnings if the legacy irq no. is
- * shared with another device. The kernel then disables that interrupt source
- * and so prevents the other device from working properly.
- */
-#define HAS_GMBUS_IRQ(dev) (INTEL_INFO(dev)->gen >= 5)
static int
gmbus_wait_hw_status(struct drm_i915_private *dev_priv,
u32 gmbus2_status,
diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c
index 4e960ec7419f..acde2945eb8a 100644
--- a/drivers/gpu/drm/i915/intel_opregion.c
+++ b/drivers/gpu/drm/i915/intel_opregion.c
@@ -226,6 +226,8 @@ struct opregion_asle {
#define ACPI_DIGITAL_OUTPUT (3<<8)
#define ACPI_LVDS_OUTPUT (4<<8)
+#define MAX_DSLP 1500
+
#ifdef CONFIG_ACPI
static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out)
{
@@ -260,10 +262,11 @@ static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out)
/* The spec says 2ms should be the default, but it's too small
* for some machines. */
dslp = 50;
- } else if (dslp > 500) {
+ } else if (dslp > MAX_DSLP) {
/* Hey bios, trust must be earned. */
- WARN_ONCE(1, "excessive driver sleep timeout (DSPL) %u\n", dslp);
- dslp = 500;
+ DRM_INFO_ONCE("ACPI BIOS requests an excessive sleep of %u ms, "
+ "using %u ms instead\n", dslp, MAX_DSLP);
+ dslp = MAX_DSLP;
}
/* The spec tells us to do this, but we are the only user... */
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 350de359123a..079ea38f14d9 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -698,7 +698,7 @@ static void i9xx_enable_backlight(struct intel_connector *connector)
freq /= 0xff;
ctl = freq << 17;
- if (IS_GEN2(dev) && panel->backlight.combination_mode)
+ if (panel->backlight.combination_mode)
ctl |= BLM_LEGACY_MODE;
if (IS_PINEVIEW(dev) && panel->backlight.active_low_pwm)
ctl |= BLM_POLARITY_PNV;
@@ -979,7 +979,7 @@ static int i9xx_setup_backlight(struct intel_connector *connector)
ctl = I915_READ(BLC_PWM_CTL);
- if (IS_GEN2(dev))
+ if (IS_GEN2(dev) || IS_I915GM(dev) || IS_I945GM(dev))
panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE;
if (IS_PINEVIEW(dev))
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index d77cc81900f9..e1fc35a72656 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3493,6 +3493,8 @@ static void valleyview_setup_pctx(struct drm_device *dev)
u32 pcbr;
int pctx_size = 24*1024;
+ WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
pcbr = I915_READ(VLV_PCBR);
if (pcbr) {
/* BIOS set it up already, grab the pre-alloc'd space */
@@ -3542,8 +3544,6 @@ static void valleyview_enable_rps(struct drm_device *dev)
I915_WRITE(GTFIFODBG, gtfifodbg);
}
- valleyview_setup_pctx(dev);
-
/* If VLV, Forcewake all wells, else re-direct to regular path */
gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
@@ -4395,6 +4395,8 @@ void intel_enable_gt_powersave(struct drm_device *dev)
ironlake_enable_rc6(dev);
intel_init_emon(dev);
} else if (IS_GEN6(dev) || IS_GEN7(dev)) {
+ if (IS_VALLEYVIEW(dev))
+ valleyview_setup_pctx(dev);
/*
* PCU communication is slow and this doesn't need to be
* done at any specific time, so do this out of our fast path
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index b7f1742caf87..31b36c5ac894 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1653,6 +1653,27 @@ int intel_ring_begin(struct intel_ring_buffer *ring,
return 0;
}
+/* Align the ring tail to a cacheline boundary */
+int intel_ring_cacheline_align(struct intel_ring_buffer *ring)
+{
+ int num_dwords = (64 - (ring->tail & 63)) / sizeof(uint32_t);
+ int ret;
+
+ if (num_dwords == 0)
+ return 0;
+
+ ret = intel_ring_begin(ring, num_dwords);
+ if (ret)
+ return ret;
+
+ while (num_dwords--)
+ intel_ring_emit(ring, MI_NOOP);
+
+ intel_ring_advance(ring);
+
+ return 0;
+}
+
void intel_ring_init_seqno(struct intel_ring_buffer *ring, u32 seqno)
{
struct drm_i915_private *dev_priv = ring->dev->dev_private;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 71a73f4fe252..0b243ce33714 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -233,6 +233,7 @@ intel_write_status_page(struct intel_ring_buffer *ring,
void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring);
int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n);
+int __must_check intel_ring_cacheline_align(struct intel_ring_buffer *ring);
static inline void intel_ring_emit(struct intel_ring_buffer *ring,
u32 data)
{
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
index 1964f4f0d452..84c5b13b33c9 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
@@ -39,6 +39,7 @@ struct mdp4_crtc {
spinlock_t lock;
bool stale;
uint32_t width, height;
+ uint32_t x, y;
/* next cursor to scan-out: */
uint32_t next_iova;
@@ -57,9 +58,16 @@ struct mdp4_crtc {
#define PENDING_FLIP 0x2
atomic_t pending;
- /* the fb that we currently hold a scanout ref to: */
+ /* the fb that we logically (from PoV of KMS API) hold a ref
+ * to. Which we may not yet be scanning out (we may still
+ * be scanning out previous in case of page_flip while waiting
+ * for gpu rendering to complete:
+ */
struct drm_framebuffer *fb;
+ /* the fb that we currently hold a scanout ref to: */
+ struct drm_framebuffer *scanout_fb;
+
/* for unref'ing framebuffers after scanout completes: */
struct drm_flip_work unref_fb_work;
@@ -77,24 +85,73 @@ static struct mdp4_kms *get_kms(struct drm_crtc *crtc)
return to_mdp4_kms(to_mdp_kms(priv->kms));
}
-static void update_fb(struct drm_crtc *crtc, bool async,
- struct drm_framebuffer *new_fb)
+static void request_pending(struct drm_crtc *crtc, uint32_t pending)
{
struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
- struct drm_framebuffer *old_fb = mdp4_crtc->fb;
- if (old_fb)
- drm_flip_work_queue(&mdp4_crtc->unref_fb_work, old_fb);
+ atomic_or(pending, &mdp4_crtc->pending);
+ mdp_irq_register(&get_kms(crtc)->base, &mdp4_crtc->vblank);
+}
+
+static void crtc_flush(struct drm_crtc *crtc)
+{
+ struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+ struct mdp4_kms *mdp4_kms = get_kms(crtc);
+ uint32_t i, flush = 0;
+
+ for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) {
+ struct drm_plane *plane = mdp4_crtc->planes[i];
+ if (plane) {
+ enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
+ flush |= pipe2flush(pipe_id);
+ }
+ }
+ flush |= ovlp2flush(mdp4_crtc->ovlp);
+
+ DBG("%s: flush=%08x", mdp4_crtc->name, flush);
+
+ mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush);
+}
+
+static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb)
+{
+ struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+ struct drm_framebuffer *old_fb = mdp4_crtc->fb;
/* grab reference to incoming scanout fb: */
drm_framebuffer_reference(new_fb);
mdp4_crtc->base.fb = new_fb;
mdp4_crtc->fb = new_fb;
- if (!async) {
- /* enable vblank to pick up the old_fb */
- mdp_irq_register(&get_kms(crtc)->base, &mdp4_crtc->vblank);
- }
+ if (old_fb)
+ drm_flip_work_queue(&mdp4_crtc->unref_fb_work, old_fb);
+}
+
+/* unlike update_fb(), take a ref to the new scanout fb *before* updating
+ * plane, then call this. Needed to ensure we don't unref the buffer that
+ * is actually still being scanned out.
+ *
+ * Note that this whole thing goes away with atomic.. since we can defer
+ * calling into driver until rendering is done.
+ */
+static void update_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb)
+{
+ struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+
+ /* flush updates, to make sure hw is updated to new scanout fb,
+ * so that we can safely queue unref to current fb (ie. next
+ * vblank we know hw is done w/ previous scanout_fb).
+ */
+ crtc_flush(crtc);
+
+ if (mdp4_crtc->scanout_fb)
+ drm_flip_work_queue(&mdp4_crtc->unref_fb_work,
+ mdp4_crtc->scanout_fb);
+
+ mdp4_crtc->scanout_fb = fb;
+
+ /* enable vblank to complete flip: */
+ request_pending(crtc, PENDING_FLIP);
}
/* if file!=NULL, this is preclose potential cancel-flip path */
@@ -120,34 +177,6 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
spin_unlock_irqrestore(&dev->event_lock, flags);
}
-static void crtc_flush(struct drm_crtc *crtc)
-{
- struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
- struct mdp4_kms *mdp4_kms = get_kms(crtc);
- uint32_t i, flush = 0;
-
- for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) {
- struct drm_plane *plane = mdp4_crtc->planes[i];
- if (plane) {
- enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
- flush |= pipe2flush(pipe_id);
- }
- }
- flush |= ovlp2flush(mdp4_crtc->ovlp);
-
- DBG("%s: flush=%08x", mdp4_crtc->name, flush);
-
- mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush);
-}
-
-static void request_pending(struct drm_crtc *crtc, uint32_t pending)
-{
- struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-
- atomic_or(pending, &mdp4_crtc->pending);
- mdp_irq_register(&get_kms(crtc)->base, &mdp4_crtc->vblank);
-}
-
static void pageflip_cb(struct msm_fence_cb *cb)
{
struct mdp4_crtc *mdp4_crtc =
@@ -158,11 +187,9 @@ static void pageflip_cb(struct msm_fence_cb *cb)
if (!fb)
return;
+ drm_framebuffer_reference(fb);
mdp4_plane_set_scanout(mdp4_crtc->plane, fb);
- crtc_flush(crtc);
-
- /* enable vblank to complete flip: */
- request_pending(crtc, PENDING_FLIP);
+ update_scanout(crtc, fb);
}
static void unref_fb_worker(struct drm_flip_work *work, void *val)
@@ -320,6 +347,20 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
mode->vsync_end, mode->vtotal,
mode->type, mode->flags);
+ /* grab extra ref for update_scanout() */
+ drm_framebuffer_reference(crtc->fb);
+
+ ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->fb,
+ 0, 0, mode->hdisplay, mode->vdisplay,
+ x << 16, y << 16,
+ mode->hdisplay << 16, mode->vdisplay << 16);
+ if (ret) {
+ drm_framebuffer_unreference(crtc->fb);
+ dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n",
+ mdp4_crtc->name, ret);
+ return ret;
+ }
+
mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_SIZE(dma),
MDP4_DMA_SRC_SIZE_WIDTH(mode->hdisplay) |
MDP4_DMA_SRC_SIZE_HEIGHT(mode->vdisplay));
@@ -341,24 +382,15 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
mdp4_write(mdp4_kms, REG_MDP4_OVLP_CFG(ovlp), 1);
- update_fb(crtc, false, crtc->fb);
-
- ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->fb,
- 0, 0, mode->hdisplay, mode->vdisplay,
- x << 16, y << 16,
- mode->hdisplay << 16, mode->vdisplay << 16);
- if (ret) {
- dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n",
- mdp4_crtc->name, ret);
- return ret;
- }
-
if (dma == DMA_E) {
mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(0), 0x00ff0000);
mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(1), 0x00ff0000);
mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(2), 0x00ff0000);
}
+ update_fb(crtc, crtc->fb);
+ update_scanout(crtc, crtc->fb);
+
return 0;
}
@@ -385,13 +417,24 @@ static int mdp4_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
struct drm_plane *plane = mdp4_crtc->plane;
struct drm_display_mode *mode = &crtc->mode;
+ int ret;
- update_fb(crtc, false, crtc->fb);
+ /* grab extra ref for update_scanout() */
+ drm_framebuffer_reference(crtc->fb);
- return mdp4_plane_mode_set(plane, crtc, crtc->fb,
+ ret = mdp4_plane_mode_set(plane, crtc, crtc->fb,
0, 0, mode->hdisplay, mode->vdisplay,
x << 16, y << 16,
mode->hdisplay << 16, mode->vdisplay << 16);
+ if (ret) {
+ drm_framebuffer_unreference(crtc->fb);
+ return ret;
+ }
+
+ update_fb(crtc, crtc->fb);
+ update_scanout(crtc, crtc->fb);
+
+ return 0;
}
static void mdp4_crtc_load_lut(struct drm_crtc *crtc)
@@ -419,7 +462,7 @@ static int mdp4_crtc_page_flip(struct drm_crtc *crtc,
mdp4_crtc->event = event;
spin_unlock_irqrestore(&dev->event_lock, flags);
- update_fb(crtc, true, new_fb);
+ update_fb(crtc, new_fb);
return msm_gem_queue_inactive_cb(obj, &mdp4_crtc->pageflip_cb);
}
@@ -442,12 +485,12 @@ static int mdp4_crtc_set_property(struct drm_crtc *crtc,
static void update_cursor(struct drm_crtc *crtc)
{
struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+ struct mdp4_kms *mdp4_kms = get_kms(crtc);
enum mdp4_dma dma = mdp4_crtc->dma;
unsigned long flags;
spin_lock_irqsave(&mdp4_crtc->cursor.lock, flags);
if (mdp4_crtc->cursor.stale) {
- struct mdp4_kms *mdp4_kms = get_kms(crtc);
struct drm_gem_object *next_bo = mdp4_crtc->cursor.next_bo;
struct drm_gem_object *prev_bo = mdp4_crtc->cursor.scanout_bo;
uint32_t iova = mdp4_crtc->cursor.next_iova;
@@ -479,6 +522,11 @@ static void update_cursor(struct drm_crtc *crtc)
mdp4_crtc->cursor.scanout_bo = next_bo;
mdp4_crtc->cursor.stale = false;
}
+
+ mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_POS(dma),
+ MDP4_DMA_CURSOR_POS_X(mdp4_crtc->cursor.x) |
+ MDP4_DMA_CURSOR_POS_Y(mdp4_crtc->cursor.y));
+
spin_unlock_irqrestore(&mdp4_crtc->cursor.lock, flags);
}
@@ -530,6 +578,7 @@ static int mdp4_crtc_cursor_set(struct drm_crtc *crtc,
drm_gem_object_unreference_unlocked(old_bo);
}
+ crtc_flush(crtc);
request_pending(crtc, PENDING_CURSOR);
return 0;
@@ -542,12 +591,15 @@ fail:
static int mdp4_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
{
struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
- struct mdp4_kms *mdp4_kms = get_kms(crtc);
- enum mdp4_dma dma = mdp4_crtc->dma;
+ unsigned long flags;
- mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_POS(dma),
- MDP4_DMA_CURSOR_POS_X(x) |
- MDP4_DMA_CURSOR_POS_Y(y));
+ spin_lock_irqsave(&mdp4_crtc->cursor.lock, flags);
+ mdp4_crtc->cursor.x = x;
+ mdp4_crtc->cursor.y = y;
+ spin_unlock_irqrestore(&mdp4_crtc->cursor.lock, flags);
+
+ crtc_flush(crtc);
+ request_pending(crtc, PENDING_CURSOR);
return 0;
}
@@ -713,6 +765,7 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
crtc = &mdp4_crtc->base;
mdp4_crtc->plane = plane;
+ mdp4_crtc->id = id;
mdp4_crtc->ovlp = ovlp_id;
mdp4_crtc->dma = dma_id;
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
index 2406027200ec..1e893dd13859 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
@@ -170,8 +170,8 @@ int mdp4_plane_mode_set(struct drm_plane *plane,
MDP4_PIPE_DST_SIZE_HEIGHT(crtc_h));
mdp4_write(mdp4_kms, REG_MDP4_PIPE_DST_XY(pipe),
- MDP4_PIPE_SRC_XY_X(crtc_x) |
- MDP4_PIPE_SRC_XY_Y(crtc_y));
+ MDP4_PIPE_DST_XY_X(crtc_x) |
+ MDP4_PIPE_DST_XY_Y(crtc_y));
mdp4_plane_set_scanout(plane, fb);
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
index 71a3b2345eb3..f2794021f086 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
@@ -296,6 +296,7 @@ static int mdp5_crtc_mode_set(struct drm_crtc *crtc,
x << 16, y << 16,
mode->hdisplay << 16, mode->vdisplay << 16);
if (ret) {
+ drm_framebuffer_unreference(crtc->fb);
dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n",
mdp5_crtc->name, ret);
return ret;
@@ -343,11 +344,15 @@ static int mdp5_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
0, 0, mode->hdisplay, mode->vdisplay,
x << 16, y << 16,
mode->hdisplay << 16, mode->vdisplay << 16);
+ if (ret) {
+ drm_framebuffer_unreference(crtc->fb);
+ return ret;
+ }
update_fb(crtc, crtc->fb);
update_scanout(crtc, crtc->fb);
- return ret;
+ return 0;
}
static void mdp5_crtc_load_lut(struct drm_crtc *crtc)
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index d8d60c969ac7..3da8264d3039 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -644,7 +644,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
fail:
if (obj)
- drm_gem_object_unreference_unlocked(obj);
+ drm_gem_object_unreference(obj);
return ERR_PTR(ret);
}
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
index 5281d4bc37f7..5423e914e491 100644
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -163,7 +163,7 @@ retry:
/* if locking succeeded, pin bo: */
- ret = msm_gem_get_iova(&msm_obj->base,
+ ret = msm_gem_get_iova_locked(&msm_obj->base,
submit->gpu->id, &iova);
/* this would break the logic in the fail path.. there is no
@@ -247,7 +247,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
/* For now, just map the entire thing. Eventually we probably
* to do it page-by-page, w/ kmap() if not vmap()d..
*/
- ptr = msm_gem_vaddr(&obj->base);
+ ptr = msm_gem_vaddr_locked(&obj->base);
if (IS_ERR(ptr)) {
ret = PTR_ERR(ptr);
@@ -307,14 +307,12 @@ static void submit_cleanup(struct msm_gem_submit *submit, bool fail)
{
unsigned i;
- mutex_lock(&submit->dev->struct_mutex);
for (i = 0; i < submit->nr_bos; i++) {
struct msm_gem_object *msm_obj = submit->bos[i].obj;
submit_unlock_unpin_bo(submit, i);
list_del_init(&msm_obj->submit_entry);
drm_gem_object_unreference(&msm_obj->base);
}
- mutex_unlock(&submit->dev->struct_mutex);
ww_acquire_fini(&submit->ticket);
kfree(submit);
@@ -342,6 +340,8 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
if (args->nr_cmds > MAX_CMDS)
return -EINVAL;
+ mutex_lock(&dev->struct_mutex);
+
submit = submit_create(dev, gpu, args->nr_bos);
if (!submit) {
ret = -ENOMEM;
@@ -410,5 +410,6 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
out:
if (submit)
submit_cleanup(submit, !!ret);
+ mutex_unlock(&dev->struct_mutex);
return ret;
}
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 4ebce8be489d..0cfe3f426ee4 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -298,8 +298,6 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
struct msm_drm_private *priv = dev->dev_private;
int i, ret;
- mutex_lock(&dev->struct_mutex);
-
submit->fence = ++priv->next_fence;
gpu->submitted_fence = submit->fence;
@@ -331,7 +329,6 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
msm_gem_move_to_active(&msm_obj->base, gpu, true, submit->fence);
}
hangcheck_timer_reset(gpu);
- mutex_unlock(&dev->struct_mutex);
return ret;
}
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
index 7cf787d697b1..637c29a33127 100644
--- a/drivers/gpu/drm/nouveau/Kconfig
+++ b/drivers/gpu/drm/nouveau/Kconfig
@@ -11,7 +11,7 @@ config DRM_NOUVEAU
select FB
select FRAMEBUFFER_CONSOLE if !EXPERT
select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
- select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT
+ select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && INPUT
select X86_PLATFORM_DEVICES if ACPI && X86
select ACPI_WMI if ACPI && X86
select MXM_WMI if ACPI && X86
@@ -19,7 +19,6 @@ config DRM_NOUVEAU
# Similar to i915, we need to select ACPI_VIDEO and it's dependencies
select BACKLIGHT_LCD_SUPPORT if ACPI && X86
select BACKLIGHT_CLASS_DEVICE if ACPI && X86
- select VIDEO_OUTPUT_CONTROL if ACPI && X86
select INPUT if ACPI && X86
select THERMAL if ACPI && X86
select ACPI_VIDEO if ACPI && X86
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index e88145ba1bf5..d310c195bdfe 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -141,6 +141,7 @@ nouveau-y += core/subdev/mc/base.o
nouveau-y += core/subdev/mc/nv04.o
nouveau-y += core/subdev/mc/nv40.o
nouveau-y += core/subdev/mc/nv44.o
+nouveau-y += core/subdev/mc/nv4c.o
nouveau-y += core/subdev/mc/nv50.o
nouveau-y += core/subdev/mc/nv94.o
nouveau-y += core/subdev/mc/nv98.o
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv40.c b/drivers/gpu/drm/nouveau/core/engine/device/nv40.c
index 1b653dd74a70..08b88591ed60 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv40.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/nv40.c
@@ -311,7 +311,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass;
@@ -334,7 +334,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = nv4e_fb_oclass;
@@ -357,7 +357,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass;
@@ -380,7 +380,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass;
@@ -403,7 +403,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
index 940eaa5d8b9a..9ad722e4e087 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
@@ -1142,7 +1142,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
if (conf != ~0) {
if (outp.location == 0 && outp.type == DCB_OUTPUT_DP) {
u32 soff = (ffs(outp.or) - 1) * 0x08;
- u32 ctrl = nv_rd32(priv, 0x610798 + soff);
+ u32 ctrl = nv_rd32(priv, 0x610794 + soff);
u32 datarate;
switch ((ctrl & 0x000f0000) >> 16) {
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
index 9a850fe19515..54c1b5b471cd 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
@@ -112,7 +112,7 @@ nve0_fifo_runlist_update(struct nve0_fifo_priv *priv, u32 engine)
nv_wr32(priv, 0x002270, cur->addr >> 12);
nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3));
- if (!nv_wait(priv, 0x002284 + (engine * 4), 0x00100000, 0x00000000))
+ if (!nv_wait(priv, 0x002284 + (engine * 8), 0x00100000, 0x00000000))
nv_error(priv, "runlist %d update timeout\n", engine);
mutex_unlock(&nv_subdev(priv)->mutex);
}
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
index 30ed19c52e05..7a367c402978 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
@@ -539,7 +539,7 @@ nv50_priv_tp_trap(struct nv50_graph_priv *priv, int type, u32 ustatus_old,
ustatus &= ~0x04030000;
}
if (ustatus && display) {
- nv_error("%s - TP%d:", name, i);
+ nv_error(priv, "%s - TP%d:", name, i);
nouveau_bitfield_print(nv50_mpc_traps, ustatus);
pr_cont("\n");
ustatus = 0;
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h
index adc88b73d911..3c6738edd127 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h
@@ -47,6 +47,7 @@ struct nouveau_mc_oclass {
extern struct nouveau_oclass *nv04_mc_oclass;
extern struct nouveau_oclass *nv40_mc_oclass;
extern struct nouveau_oclass *nv44_mc_oclass;
+extern struct nouveau_oclass *nv4c_mc_oclass;
extern struct nouveau_oclass *nv50_mc_oclass;
extern struct nouveau_oclass *nv94_mc_oclass;
extern struct nouveau_oclass *nv98_mc_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
index aa0fbbec7f08..ef0c9c4a8cc3 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
@@ -130,6 +130,10 @@ nouveau_bios_shadow_prom(struct nouveau_bios *bios)
u16 pcir;
int i;
+ /* there is no prom on nv4x IGP's */
+ if (device->card_type == NV_40 && device->chipset >= 0x4c)
+ return;
+
/* enable access to rom */
if (device->card_type >= NV_50)
pcireg = 0x088050;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
index 9159a5ccee93..265d1253624a 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
@@ -36,7 +36,7 @@ nv1a_fb_oclass = &(struct nv04_fb_impl) {
.fini = _nouveau_fb_fini,
},
.base.memtype = nv04_fb_memtype_valid,
- .base.ram = &nv10_ram_oclass,
+ .base.ram = &nv1a_ram_oclass,
.tile.regions = 8,
.tile.init = nv10_fb_tile_init,
.tile.fini = nv10_fb_tile_fini,
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h
index b0d5c31606c1..81a408e7d034 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h
@@ -14,6 +14,7 @@ int nv04_mc_ctor(struct nouveau_object *, struct nouveau_object *,
extern const struct nouveau_mc_intr nv04_mc_intr[];
int nv04_mc_init(struct nouveau_object *);
void nv40_mc_msi_rearm(struct nouveau_mc *);
+int nv44_mc_init(struct nouveau_object *object);
int nv50_mc_init(struct nouveau_object *);
extern const struct nouveau_mc_intr nv50_mc_intr[];
extern const struct nouveau_mc_intr nvc0_mc_intr[];
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
index 3bfee5c6c4f2..cc4d0d2d886e 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
@@ -24,7 +24,7 @@
#include "nv04.h"
-static int
+int
nv44_mc_init(struct nouveau_object *object)
{
struct nv04_mc_priv *priv = (void *)object;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c
new file mode 100644
index 000000000000..a75c35ccf25c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2014 Ilia Mirkin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ilia Mirkin
+ */
+
+#include "nv04.h"
+
+static void
+nv4c_mc_msi_rearm(struct nouveau_mc *pmc)
+{
+ struct nv04_mc_priv *priv = (void *)pmc;
+ nv_wr08(priv, 0x088050, 0xff);
+}
+
+struct nouveau_oclass *
+nv4c_mc_oclass = &(struct nouveau_mc_oclass) {
+ .base.handle = NV_SUBDEV(MC, 0x4c),
+ .base.ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv04_mc_ctor,
+ .dtor = _nouveau_mc_dtor,
+ .init = nv44_mc_init,
+ .fini = _nouveau_mc_fini,
+ },
+ .intr = nv04_mc_intr,
+ .msi_rearm = nv4c_mc_msi_rearm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index 4ef83df2b246..83face3f608f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -106,6 +106,29 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *
return 0;
}
+/*
+ * On some platforms, _DSM(nouveau_op_dsm_muid, func0) has special
+ * requirements on the fourth parameter, so a private implementation
+ * instead of using acpi_check_dsm().
+ */
+static int nouveau_check_optimus_dsm(acpi_handle handle)
+{
+ int result;
+
+ /*
+ * Function 0 returns a Buffer containing available functions.
+ * The args parameter is ignored for function 0, so just put 0 in it
+ */
+ if (nouveau_optimus_dsm(handle, 0, 0, &result))
+ return 0;
+
+ /*
+ * ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported.
+ * If the n-th bit is enabled, function n is supported
+ */
+ return result & 1 && result & (1 << NOUVEAU_DSM_OPTIMUS_CAPS);
+}
+
static int nouveau_dsm(acpi_handle handle, int func, int arg)
{
int ret = 0;
@@ -207,8 +230,7 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
1 << NOUVEAU_DSM_POWER))
retval |= NOUVEAU_DSM_HAS_MUX;
- if (acpi_check_dsm(dhandle, nouveau_op_dsm_muid, 0x00000100,
- 1 << NOUVEAU_DSM_OPTIMUS_CAPS))
+ if (nouveau_check_optimus_dsm(dhandle))
retval |= NOUVEAU_DSM_HAS_OPT;
if (retval & NOUVEAU_DSM_HAS_OPT) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 488686d490c0..4aed1714b9ab 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -1249,7 +1249,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
mem->bus.is_iomem = !dev->agp->cant_use_aperture;
}
#endif
- if (!node->memtype)
+ if (nv_device(drm->device)->card_type < NV_50 || !node->memtype)
/* untiled */
break;
/* fallthrough, tiled memory */
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 78c8e7146d56..4ee702ac8907 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -376,6 +376,8 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
if (ret)
goto fail_device;
+ dev->irq_enabled = true;
+
/* workaround an odd issue on nvc1 by disabling the device's
* nosnoop capability. hopefully won't cause issues until a
* better fix is found - assuming there is one...
@@ -475,6 +477,7 @@ nouveau_drm_remove(struct pci_dev *pdev)
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_object *device;
+ dev->irq_enabled = false;
device = drm->client.base.device;
drm_put_dev(dev);
@@ -863,13 +866,16 @@ static int nouveau_pmops_runtime_suspend(struct device *dev)
struct drm_device *drm_dev = pci_get_drvdata(pdev);
int ret;
- if (nouveau_runtime_pm == 0)
- return -EINVAL;
+ if (nouveau_runtime_pm == 0) {
+ pm_runtime_forbid(dev);
+ return -EBUSY;
+ }
/* are we optimus enabled? */
if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) {
DRM_DEBUG_DRIVER("failing to power off - not optimus\n");
- return -EINVAL;
+ pm_runtime_forbid(dev);
+ return -EBUSY;
}
nv_debug_level(SILENT);
@@ -920,12 +926,15 @@ static int nouveau_pmops_runtime_idle(struct device *dev)
struct nouveau_drm *drm = nouveau_drm(drm_dev);
struct drm_crtc *crtc;
- if (nouveau_runtime_pm == 0)
+ if (nouveau_runtime_pm == 0) {
+ pm_runtime_forbid(dev);
return -EBUSY;
+ }
/* are we optimus enabled? */
if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) {
DRM_DEBUG_DRIVER("failing to power off - not optimus\n");
+ pm_runtime_forbid(dev);
return -EBUSY;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c
index 81638d7f2eff..471347edc27e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_vga.c
+++ b/drivers/gpu/drm/nouveau/nouveau_vga.c
@@ -14,7 +14,9 @@ nouveau_vga_set_decode(void *priv, bool state)
{
struct nouveau_device *device = nouveau_dev(priv);
- if (device->chipset >= 0x40)
+ if (device->card_type == NV_40 && device->chipset >= 0x4c)
+ nv_wr32(device, 0x088060, state);
+ else if (device->chipset >= 0x40)
nv_wr32(device, 0x088054, state);
else
nv_wr32(device, 0x001854, state);
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index a9338c85630f..daa4dd375ab1 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -559,7 +559,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
u32 adjusted_clock = mode->clock;
int encoder_mode = atombios_get_encoder_mode(encoder);
u32 dp_clock = mode->clock;
- int bpc = radeon_get_monitor_bpc(connector);
+ int bpc = radeon_crtc->bpc;
bool is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock);
/* reset the pll flags */
@@ -1176,7 +1176,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split);
/* Set NUM_BANKS. */
- if (rdev->family >= CHIP_BONAIRE) {
+ if (rdev->family >= CHIP_TAHITI) {
unsigned tileb, index, num_banks, tile_split_bytes;
/* Calculate the macrotile mode index. */
@@ -1194,13 +1194,14 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
return -EINVAL;
}
- num_banks = (rdev->config.cik.macrotile_mode_array[index] >> 6) & 0x3;
+ if (rdev->family >= CHIP_BONAIRE)
+ num_banks = (rdev->config.cik.macrotile_mode_array[index] >> 6) & 0x3;
+ else
+ num_banks = (rdev->config.si.tile_mode_array[index] >> 20) & 0x3;
fb_format |= EVERGREEN_GRPH_NUM_BANKS(num_banks);
} else {
- /* SI and older. */
- if (rdev->family >= CHIP_TAHITI)
- tmp = rdev->config.si.tile_config;
- else if (rdev->family >= CHIP_CAYMAN)
+ /* NI and older. */
+ if (rdev->family >= CHIP_CAYMAN)
tmp = rdev->config.cayman.tile_config;
else
tmp = rdev->config.evergreen.tile_config;
@@ -1773,6 +1774,20 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
return ATOM_PPLL1;
DRM_ERROR("unable to allocate a PPLL\n");
return ATOM_PPLL_INVALID;
+ } else if (ASIC_IS_DCE41(rdev)) {
+ /* Don't share PLLs on DCE4.1 chips */
+ if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) {
+ if (rdev->clock.dp_extclk)
+ /* skip PPLL programming if using ext clock */
+ return ATOM_PPLL_INVALID;
+ }
+ pll_in_use = radeon_get_pll_use_mask(crtc);
+ if (!(pll_in_use & (1 << ATOM_PPLL1)))
+ return ATOM_PPLL1;
+ if (!(pll_in_use & (1 << ATOM_PPLL2)))
+ return ATOM_PPLL2;
+ DRM_ERROR("unable to allocate a PPLL\n");
+ return ATOM_PPLL_INVALID;
} else if (ASIC_IS_DCE4(rdev)) {
/* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock,
* depending on the asic:
@@ -1800,7 +1815,7 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
if (pll != ATOM_PPLL_INVALID)
return pll;
}
- } else if (!ASIC_IS_DCE41(rdev)) { /* Don't share PLLs on DCE4.1 chips */
+ } else {
/* use the same PPLL for all monitors with the same clock */
pll = radeon_get_shared_nondp_ppll(crtc);
if (pll != ATOM_PPLL_INVALID)
diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index a42d61571f49..607dc14d195e 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -464,11 +464,12 @@ atombios_tv_setup(struct drm_encoder *encoder, int action)
static u8 radeon_atom_get_bpc(struct drm_encoder *encoder)
{
- struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
int bpc = 8;
- if (connector)
- bpc = radeon_get_monitor_bpc(connector);
+ if (encoder->crtc) {
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+ bpc = radeon_crtc->bpc;
+ }
switch (bpc) {
case 0:
@@ -1313,7 +1314,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
}
if (is_dp)
args.v5.ucLaneNum = dp_lane_count;
- else if (radeon_encoder->pixel_clock > 165000)
+ else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
args.v5.ucLaneNum = 8;
else
args.v5.ucLaneNum = 4;
diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c
index 0fbd36f3d4e9..ea103ccdf4bd 100644
--- a/drivers/gpu/drm/radeon/btc_dpm.c
+++ b/drivers/gpu/drm/radeon/btc_dpm.c
@@ -29,6 +29,7 @@
#include "cypress_dpm.h"
#include "btc_dpm.h"
#include "atom.h"
+#include <linux/seq_file.h>
#define MC_CG_ARB_FREQ_F0 0x0a
#define MC_CG_ARB_FREQ_F1 0x0b
@@ -2756,6 +2757,37 @@ void btc_dpm_fini(struct radeon_device *rdev)
r600_free_extended_power_table(rdev);
}
+void btc_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+ struct seq_file *m)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct radeon_ps *rps = &eg_pi->current_rps;
+ struct rv7xx_ps *ps = rv770_get_ps(rps);
+ struct rv7xx_pl *pl;
+ u32 current_index =
+ (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+ CURRENT_PROFILE_INDEX_SHIFT;
+
+ if (current_index > 2) {
+ seq_printf(m, "invalid dpm profile %d\n", current_index);
+ } else {
+ if (current_index == 0)
+ pl = &ps->low;
+ else if (current_index == 1)
+ pl = &ps->medium;
+ else /* current_index == 2 */
+ pl = &ps->high;
+ seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+ if (rdev->family >= CHIP_CEDAR) {
+ seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u vddci: %u\n",
+ current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci);
+ } else {
+ seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u\n",
+ current_index, pl->sclk, pl->mclk, pl->vddc);
+ }
+ }
+}
+
u32 btc_dpm_get_sclk(struct radeon_device *rdev, bool low)
{
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
diff --git a/drivers/gpu/drm/radeon/btcd.h b/drivers/gpu/drm/radeon/btcd.h
index 29e32de7e025..9c65be2d55a9 100644
--- a/drivers/gpu/drm/radeon/btcd.h
+++ b/drivers/gpu/drm/radeon/btcd.h
@@ -44,6 +44,10 @@
# define DYN_SPREAD_SPECTRUM_EN (1 << 23)
# define AC_DC_SW (1 << 24)
+#define TARGET_AND_CURRENT_PROFILE_INDEX 0x66c
+# define CURRENT_PROFILE_INDEX_MASK (0xf << 4)
+# define CURRENT_PROFILE_INDEX_SHIFT 4
+
#define CG_BIF_REQ_AND_RSP 0x7f4
#define CG_CLIENT_REQ(x) ((x) << 0)
#define CG_CLIENT_REQ_MASK (0xff << 0)
diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index e6419ca7cd37..bbb17841a9e5 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -3046,7 +3046,7 @@ static u32 cik_create_bitmask(u32 bit_width)
}
/**
- * cik_select_se_sh - select which SE, SH to address
+ * cik_get_rb_disabled - computes the mask of disabled RBs
*
* @rdev: radeon_device pointer
* @max_rb_num: max RBs (render backends) for the asic
@@ -4134,8 +4134,11 @@ static void cik_cp_compute_enable(struct radeon_device *rdev, bool enable)
{
if (enable)
WREG32(CP_MEC_CNTL, 0);
- else
+ else {
WREG32(CP_MEC_CNTL, (MEC_ME1_HALT | MEC_ME2_HALT));
+ rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX].ready = false;
+ rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX].ready = false;
+ }
udelay(50);
}
@@ -7902,7 +7905,8 @@ int cik_resume(struct radeon_device *rdev)
/* init golden registers */
cik_init_golden_registers(rdev);
- radeon_pm_resume(rdev);
+ if (rdev->pm.pm_method == PM_METHOD_DPM)
+ radeon_pm_resume(rdev);
rdev->accel_working = true;
r = cik_startup(rdev);
diff --git a/drivers/gpu/drm/radeon/cik_sdma.c b/drivers/gpu/drm/radeon/cik_sdma.c
index 1ecb3f1070e3..94626ea90fa5 100644
--- a/drivers/gpu/drm/radeon/cik_sdma.c
+++ b/drivers/gpu/drm/radeon/cik_sdma.c
@@ -264,6 +264,8 @@ static void cik_sdma_gfx_stop(struct radeon_device *rdev)
WREG32(SDMA0_GFX_RB_CNTL + reg_offset, rb_cntl);
WREG32(SDMA0_GFX_IB_CNTL + reg_offset, 0);
}
+ rdev->ring[R600_RING_TYPE_DMA_INDEX].ready = false;
+ rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX].ready = false;
}
/**
@@ -291,6 +293,11 @@ void cik_sdma_enable(struct radeon_device *rdev, bool enable)
u32 me_cntl, reg_offset;
int i;
+ if (enable == false) {
+ cik_sdma_gfx_stop(rdev);
+ cik_sdma_rlc_stop(rdev);
+ }
+
for (i = 0; i < 2; i++) {
if (i == 0)
reg_offset = SDMA0_REGISTER_OFFSET;
@@ -420,10 +427,6 @@ static int cik_sdma_load_microcode(struct radeon_device *rdev)
if (!rdev->sdma_fw)
return -EINVAL;
- /* stop the gfx rings and rlc compute queues */
- cik_sdma_gfx_stop(rdev);
- cik_sdma_rlc_stop(rdev);
-
/* halt the MEs */
cik_sdma_enable(rdev, false);
@@ -492,9 +495,6 @@ int cik_sdma_resume(struct radeon_device *rdev)
*/
void cik_sdma_fini(struct radeon_device *rdev)
{
- /* stop the gfx rings and rlc compute queues */
- cik_sdma_gfx_stop(rdev);
- cik_sdma_rlc_stop(rdev);
/* halt the MEs */
cik_sdma_enable(rdev, false);
radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX]);
diff --git a/drivers/gpu/drm/radeon/dce6_afmt.c b/drivers/gpu/drm/radeon/dce6_afmt.c
index 713a5d359901..94e858751994 100644
--- a/drivers/gpu/drm/radeon/dce6_afmt.c
+++ b/drivers/gpu/drm/radeon/dce6_afmt.c
@@ -278,13 +278,15 @@ static int dce6_audio_chipset_supported(struct radeon_device *rdev)
return !ASIC_IS_NODCE(rdev);
}
-static void dce6_audio_enable(struct radeon_device *rdev,
- struct r600_audio_pin *pin,
- bool enable)
+void dce6_audio_enable(struct radeon_device *rdev,
+ struct r600_audio_pin *pin,
+ bool enable)
{
+ if (!pin)
+ return;
+
WREG32_ENDPOINT(pin->offset, AZ_F0_CODEC_PIN_CONTROL_HOTPLUG_CONTROL,
- AUDIO_ENABLED);
- DRM_INFO("%s audio %d support\n", enable ? "Enabling" : "Disabling", pin->id);
+ enable ? AUDIO_ENABLED : 0);
}
static const u32 pin_offsets[7] =
@@ -323,7 +325,8 @@ int dce6_audio_init(struct radeon_device *rdev)
rdev->audio.pin[i].connected = false;
rdev->audio.pin[i].offset = pin_offsets[i];
rdev->audio.pin[i].id = i;
- dce6_audio_enable(rdev, &rdev->audio.pin[i], true);
+ /* disable audio. it will be set up later */
+ dce6_audio_enable(rdev, &rdev->audio.pin[i], false);
}
return 0;
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index f2b9e21ce4da..27b0ff16082e 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -1680,7 +1680,7 @@ bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd)
case RADEON_HPD_6:
if (RREG32(DC_HPD6_INT_STATUS) & DC_HPDx_SENSE)
connected = true;
- break;
+ break;
default:
break;
}
@@ -5299,7 +5299,8 @@ int evergreen_resume(struct radeon_device *rdev)
/* init golden registers */
evergreen_init_golden_registers(rdev);
- radeon_pm_resume(rdev);
+ if (rdev->pm.pm_method == PM_METHOD_DPM)
+ radeon_pm_resume(rdev);
rdev->accel_working = true;
r = evergreen_startup(rdev);
@@ -5475,9 +5476,9 @@ void evergreen_fini(struct radeon_device *rdev)
radeon_wb_fini(rdev);
radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev);
- evergreen_pcie_gart_fini(rdev);
uvd_v1_0_fini(rdev);
radeon_uvd_fini(rdev);
+ evergreen_pcie_gart_fini(rdev);
r600_vram_scratch_fini(rdev);
radeon_gem_fini(rdev);
radeon_fence_driver_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c
index 0c6d5cef4cf1..05b0c95813fd 100644
--- a/drivers/gpu/drm/radeon/evergreen_hdmi.c
+++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c
@@ -306,6 +306,15 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
return;
offset = dig->afmt->offset;
+ /* disable audio prior to setting up hw */
+ if (ASIC_IS_DCE6(rdev)) {
+ dig->afmt->pin = dce6_audio_get_pin(rdev);
+ dce6_audio_enable(rdev, dig->afmt->pin, false);
+ } else {
+ dig->afmt->pin = r600_audio_get_pin(rdev);
+ r600_audio_enable(rdev, dig->afmt->pin, false);
+ }
+
evergreen_audio_set_dto(encoder, mode->clock);
WREG32(HDMI_VBI_PACKET_CONTROL + offset,
@@ -409,12 +418,16 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
WREG32(AFMT_RAMP_CONTROL1 + offset, 0x007FFFFF);
WREG32(AFMT_RAMP_CONTROL2 + offset, 0x00000001);
WREG32(AFMT_RAMP_CONTROL3 + offset, 0x00000001);
+
+ /* enable audio after to setting up hw */
+ if (ASIC_IS_DCE6(rdev))
+ dce6_audio_enable(rdev, dig->afmt->pin, true);
+ else
+ r600_audio_enable(rdev, dig->afmt->pin, true);
}
void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
{
- struct drm_device *dev = encoder->dev;
- struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
@@ -427,15 +440,6 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
if (!enable && !dig->afmt->enabled)
return;
- if (enable) {
- if (ASIC_IS_DCE6(rdev))
- dig->afmt->pin = dce6_audio_get_pin(rdev);
- else
- dig->afmt->pin = r600_audio_get_pin(rdev);
- } else {
- dig->afmt->pin = NULL;
- }
-
dig->afmt->enabled = enable;
DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n",
diff --git a/drivers/gpu/drm/radeon/evergreen_smc.h b/drivers/gpu/drm/radeon/evergreen_smc.h
index 76ada8cfe902..3a03ba37d043 100644
--- a/drivers/gpu/drm/radeon/evergreen_smc.h
+++ b/drivers/gpu/drm/radeon/evergreen_smc.h
@@ -57,7 +57,7 @@ typedef struct SMC_Evergreen_MCRegisters SMC_Evergreen_MCRegisters;
#define EVERGREEN_SMC_FIRMWARE_HEADER_LOCATION 0x100
-#define EVERGREEN_SMC_FIRMWARE_HEADER_softRegisters 0x0
+#define EVERGREEN_SMC_FIRMWARE_HEADER_softRegisters 0x8
#define EVERGREEN_SMC_FIRMWARE_HEADER_stateTable 0xC
#define EVERGREEN_SMC_FIRMWARE_HEADER_mcRegisterTable 0x20
diff --git a/drivers/gpu/drm/radeon/kv_dpm.c b/drivers/gpu/drm/radeon/kv_dpm.c
index b6e01d5d2cce..351db361239d 100644
--- a/drivers/gpu/drm/radeon/kv_dpm.c
+++ b/drivers/gpu/drm/radeon/kv_dpm.c
@@ -1223,7 +1223,7 @@ int kv_dpm_enable(struct radeon_device *rdev)
int kv_dpm_late_enable(struct radeon_device *rdev)
{
- int ret;
+ int ret = 0;
if (rdev->irq.installed &&
r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index ea932ac66fc6..bf6300cfd62d 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -2105,7 +2105,8 @@ int cayman_resume(struct radeon_device *rdev)
/* init golden registers */
ni_init_golden_registers(rdev);
- radeon_pm_resume(rdev);
+ if (rdev->pm.pm_method == PM_METHOD_DPM)
+ radeon_pm_resume(rdev);
rdev->accel_working = true;
r = cayman_startup(rdev);
diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c
index c351226ecb31..ca814276b075 100644
--- a/drivers/gpu/drm/radeon/ni_dpm.c
+++ b/drivers/gpu/drm/radeon/ni_dpm.c
@@ -2588,7 +2588,7 @@ static int ni_populate_sq_ramping_values(struct radeon_device *rdev,
if (NISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT))
enable_sq_ramping = false;
- if (NISLANDS_DPM2_SQ_RAMP_LTI_RATIO <= (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
+ if (NISLANDS_DPM2_SQ_RAMP_LTI_RATIO > (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
enable_sq_ramping = false;
for (i = 0; i < state->performance_level_count; i++) {
@@ -3945,7 +3945,6 @@ static void ni_parse_pplib_clock_info(struct radeon_device *rdev,
struct rv7xx_power_info *pi = rv770_get_pi(rdev);
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
struct ni_ps *ps = ni_get_ps(rps);
- u16 vddc;
struct rv7xx_pl *pl = &ps->performance_levels[index];
ps->performance_level_count = index + 1;
@@ -3961,8 +3960,8 @@ static void ni_parse_pplib_clock_info(struct radeon_device *rdev,
/* patch up vddc if necessary */
if (pl->vddc == 0xff01) {
- if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0)
- pl->vddc = vddc;
+ if (pi->max_vddc)
+ pl->vddc = pi->max_vddc;
}
if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) {
@@ -4322,7 +4321,8 @@ void ni_dpm_print_power_state(struct radeon_device *rdev,
void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
struct seq_file *m)
{
- struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct radeon_ps *rps = &eg_pi->current_rps;
struct ni_ps *ps = ni_get_ps(rps);
struct rv7xx_pl *pl;
u32 current_index =
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index ef024ce3f7cc..3cc78bb66042 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -3942,8 +3942,6 @@ int r100_resume(struct radeon_device *rdev)
/* Initialize surface registers */
radeon_surface_init(rdev);
- radeon_pm_resume(rdev);
-
rdev->accel_working = true;
r = r100_startup(rdev);
if (r) {
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index 7c63ef840e86..0b658b34b33a 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -1430,8 +1430,6 @@ int r300_resume(struct radeon_device *rdev)
/* Initialize surface registers */
radeon_surface_init(rdev);
- radeon_pm_resume(rdev);
-
rdev->accel_working = true;
r = r300_startup(rdev);
if (r) {
diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c
index 3768aab2710b..802b19220a21 100644
--- a/drivers/gpu/drm/radeon/r420.c
+++ b/drivers/gpu/drm/radeon/r420.c
@@ -325,8 +325,6 @@ int r420_resume(struct radeon_device *rdev)
/* Initialize surface registers */
radeon_surface_init(rdev);
- radeon_pm_resume(rdev);
-
rdev->accel_working = true;
r = r420_startup(rdev);
if (r) {
diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c
index e209eb75024f..98d6053c36c6 100644
--- a/drivers/gpu/drm/radeon/r520.c
+++ b/drivers/gpu/drm/radeon/r520.c
@@ -240,8 +240,6 @@ int r520_resume(struct radeon_device *rdev)
/* Initialize surface registers */
radeon_surface_init(rdev);
- radeon_pm_resume(rdev);
-
rdev->accel_working = true;
r = r520_startup(rdev);
if (r) {
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 56140b4e5bb2..647ef4079217 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -2968,7 +2968,8 @@ int r600_resume(struct radeon_device *rdev)
/* post card */
atom_asic_init(rdev->mode_info.atom_context);
- radeon_pm_resume(rdev);
+ if (rdev->pm.pm_method == PM_METHOD_DPM)
+ radeon_pm_resume(rdev);
rdev->accel_working = true;
r = r600_startup(rdev);
@@ -3991,6 +3992,10 @@ restart_ih:
break;
}
break;
+ case 124: /* UVD */
+ DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data);
+ radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX);
+ break;
case 176: /* CP_INT in ring buffer */
case 177: /* CP_INT in IB1 */
case 178: /* CP_INT in IB2 */
diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c
index 47fc2b886979..bffac10c4296 100644
--- a/drivers/gpu/drm/radeon/r600_audio.c
+++ b/drivers/gpu/drm/radeon/r600_audio.c
@@ -142,12 +142,15 @@ void r600_audio_update_hdmi(struct work_struct *work)
}
/* enable the audio stream */
-static void r600_audio_enable(struct radeon_device *rdev,
- struct r600_audio_pin *pin,
- bool enable)
+void r600_audio_enable(struct radeon_device *rdev,
+ struct r600_audio_pin *pin,
+ bool enable)
{
u32 value = 0;
+ if (!pin)
+ return;
+
if (ASIC_IS_DCE4(rdev)) {
if (enable) {
value |= 0x81000000; /* Required to enable audio */
@@ -158,7 +161,6 @@ static void r600_audio_enable(struct radeon_device *rdev,
WREG32_P(R600_AUDIO_ENABLE,
enable ? 0x81000000 : 0x0, ~0x81000000);
}
- DRM_INFO("%s audio %d support\n", enable ? "Enabling" : "Disabling", pin->id);
}
/*
@@ -178,8 +180,8 @@ int r600_audio_init(struct radeon_device *rdev)
rdev->audio.pin[0].status_bits = 0;
rdev->audio.pin[0].category_code = 0;
rdev->audio.pin[0].id = 0;
-
- r600_audio_enable(rdev, &rdev->audio.pin[0], true);
+ /* disable audio. it will be set up later */
+ r600_audio_enable(rdev, &rdev->audio.pin[0], false);
return 0;
}
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c
index 3016fc14f502..85a2bb28aed2 100644
--- a/drivers/gpu/drm/radeon/r600_hdmi.c
+++ b/drivers/gpu/drm/radeon/r600_hdmi.c
@@ -329,9 +329,6 @@ static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder)
u8 *sadb;
int sad_count;
- /* XXX: setting this register causes hangs on some asics */
- return;
-
list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
if (connector->encoder == encoder) {
radeon_connector = to_radeon_connector(connector);
@@ -460,6 +457,10 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
return;
offset = dig->afmt->offset;
+ /* disable audio prior to setting up hw */
+ dig->afmt->pin = r600_audio_get_pin(rdev);
+ r600_audio_enable(rdev, dig->afmt->pin, false);
+
r600_audio_set_dto(encoder, mode->clock);
WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
@@ -531,6 +532,9 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001);
r600_hdmi_audio_workaround(encoder);
+
+ /* enable audio after to setting up hw */
+ r600_audio_enable(rdev, dig->afmt->pin, true);
}
/*
@@ -651,11 +655,6 @@ void r600_hdmi_enable(struct drm_encoder *encoder, bool enable)
if (!enable && !dig->afmt->enabled)
return;
- if (enable)
- dig->afmt->pin = r600_audio_get_pin(rdev);
- else
- dig->afmt->pin = NULL;
-
/* Older chipsets require setting HDMI and routing manually */
if (!ASIC_IS_DCE3(rdev)) {
if (enable)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 4a8ac1cd6b4c..e887d027b6d0 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -135,6 +135,9 @@ extern int radeon_hard_reset;
/* R600+ */
#define R600_RING_TYPE_UVD_INDEX 5
+/* number of hw syncs before falling back on blocking */
+#define RADEON_NUM_SYNCS 4
+
/* hardcode those limit for now */
#define RADEON_VA_IB_OFFSET (1 << 20)
#define RADEON_VA_RESERVED_SIZE (8 << 20)
@@ -554,7 +557,6 @@ int radeon_mode_dumb_mmap(struct drm_file *filp,
/*
* Semaphores.
*/
-/* everything here is constant */
struct radeon_semaphore {
struct radeon_sa_bo *sa_bo;
signed waiters;
@@ -2745,6 +2747,12 @@ int radeon_vm_bo_rmv(struct radeon_device *rdev,
void r600_audio_update_hdmi(struct work_struct *work);
struct r600_audio_pin *r600_audio_get_pin(struct radeon_device *rdev);
struct r600_audio_pin *dce6_audio_get_pin(struct radeon_device *rdev);
+void r600_audio_enable(struct radeon_device *rdev,
+ struct r600_audio_pin *pin,
+ bool enable);
+void dce6_audio_enable(struct radeon_device *rdev,
+ struct r600_audio_pin *pin,
+ bool enable);
/*
* R600 vram scratch functions
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index f74db43346fd..dda02bfc10a4 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1555,7 +1555,7 @@ static struct radeon_asic btc_asic = {
.get_sclk = &btc_dpm_get_sclk,
.get_mclk = &btc_dpm_get_mclk,
.print_power_state = &rv770_dpm_print_power_state,
- .debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level,
+ .debugfs_print_current_performance_level = &btc_dpm_debugfs_print_current_performance_level,
.force_performance_level = &rv770_dpm_force_performance_level,
.vblank_too_short = &btc_dpm_vblank_too_short,
},
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index b3bc433eed4c..ae637cfda783 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -551,6 +551,8 @@ void btc_dpm_fini(struct radeon_device *rdev);
u32 btc_dpm_get_sclk(struct radeon_device *rdev, bool low);
u32 btc_dpm_get_mclk(struct radeon_device *rdev, bool low);
bool btc_dpm_vblank_too_short(struct radeon_device *rdev);
+void btc_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+ struct seq_file *m);
int sumo_dpm_init(struct radeon_device *rdev);
int sumo_dpm_enable(struct radeon_device *rdev);
int sumo_dpm_late_enable(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c
index 485848f889f5..fa9a9c02751e 100644
--- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c
+++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c
@@ -219,7 +219,8 @@ static int radeon_atpx_verify_interface(struct radeon_atpx *atpx)
memcpy(&output, info->buffer.pointer, size);
/* TODO: check version? */
- printk("ATPX version %u\n", output.version);
+ printk("ATPX version %u, functions 0x%08x\n",
+ output.version, output.function_bits);
radeon_atpx_parse_functions(&atpx->functions, output.function_bits);
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index b012cbbc3ed5..044bc98fb459 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -1521,13 +1521,16 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
if (r)
DRM_ERROR("ib ring test failed (%d).\n", r);
- if (rdev->pm.dpm_enabled) {
+ if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
/* do dpm late init */
r = radeon_pm_late_init(rdev);
if (r) {
rdev->pm.dpm_enabled = false;
DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n");
}
+ } else {
+ /* resume old pm late */
+ radeon_pm_resume(rdev);
}
radeon_restore_bios_scratch_regs(rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index d680608f6f5b..fbd8b930f2be 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -571,6 +571,8 @@ static void radeon_crtc_init(struct drm_device *dev, int index)
radeon_crtc->max_cursor_width = CURSOR_WIDTH;
radeon_crtc->max_cursor_height = CURSOR_HEIGHT;
}
+ dev->mode_config.cursor_width = radeon_crtc->max_cursor_width;
+ dev->mode_config.cursor_height = radeon_crtc->max_cursor_height;
#if 0
radeon_crtc->mode_set.crtc = &radeon_crtc->base;
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 84a1bbb75f91..f633c2782170 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -403,11 +403,15 @@ static int radeon_pmops_runtime_suspend(struct device *dev)
struct drm_device *drm_dev = pci_get_drvdata(pdev);
int ret;
- if (radeon_runtime_pm == 0)
- return -EINVAL;
+ if (radeon_runtime_pm == 0) {
+ pm_runtime_forbid(dev);
+ return -EBUSY;
+ }
- if (radeon_runtime_pm == -1 && !radeon_is_px())
- return -EINVAL;
+ if (radeon_runtime_pm == -1 && !radeon_is_px()) {
+ pm_runtime_forbid(dev);
+ return -EBUSY;
+ }
drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
drm_kms_helper_poll_disable(drm_dev);
@@ -456,12 +460,15 @@ static int radeon_pmops_runtime_idle(struct device *dev)
struct drm_device *drm_dev = pci_get_drvdata(pdev);
struct drm_crtc *crtc;
- if (radeon_runtime_pm == 0)
+ if (radeon_runtime_pm == 0) {
+ pm_runtime_forbid(dev);
return -EBUSY;
+ }
/* are we PX enabled? */
if (radeon_runtime_pm == -1 && !radeon_is_px()) {
DRM_DEBUG_DRIVER("failing to power off - not px\n");
+ pm_runtime_forbid(dev);
return -EBUSY;
}
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index 114d1672d616..66ed3ea71440 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -33,6 +33,13 @@
#include <linux/vga_switcheroo.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
+
+#if defined(CONFIG_VGA_SWITCHEROO)
+bool radeon_is_px(void);
+#else
+static inline bool radeon_is_px(void) { return false; }
+#endif
+
/**
* radeon_driver_unload_kms - Main unload function for KMS.
*
@@ -130,7 +137,8 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)
"Error during ACPI methods call\n");
}
- if (radeon_runtime_pm != 0) {
+ if ((radeon_runtime_pm == 1) ||
+ ((radeon_runtime_pm == -1) && radeon_is_px())) {
pm_runtime_use_autosuspend(dev->dev);
pm_runtime_set_autosuspend_delay(dev->dev, 5000);
pm_runtime_set_active(dev->dev);
@@ -537,6 +545,10 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
radeon_vm_init(rdev, &fpriv->vm);
+ r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false);
+ if (r)
+ return r;
+
/* map the ib pool buffer read only into
* virtual address space */
bo_va = radeon_vm_bo_add(rdev, &fpriv->vm,
@@ -544,6 +556,8 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
r = radeon_vm_bo_set_addr(rdev, bo_va, RADEON_VA_IB_OFFSET,
RADEON_VM_PAGE_READABLE |
RADEON_VM_PAGE_SNOOPED);
+
+ radeon_bo_unreserve(rdev->ring_tmp_bo.bo);
if (r) {
radeon_vm_fini(rdev, &fpriv->vm);
kfree(fpriv);
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index 1b783f0e6d3a..15e44a7281ab 100644
--- a/drivers/gpu/drm/radeon/radeon_ring.c
+++ b/drivers/gpu/drm/radeon/radeon_ring.c
@@ -139,7 +139,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib,
}
/* 64 dwords should be enough for fence too */
- r = radeon_ring_lock(rdev, ring, 64 + RADEON_NUM_RINGS * 8);
+ r = radeon_ring_lock(rdev, ring, 64 + RADEON_NUM_SYNCS * 8);
if (r) {
dev_err(rdev->dev, "scheduling IB failed (%d).\n", r);
return r;
diff --git a/drivers/gpu/drm/radeon/radeon_semaphore.c b/drivers/gpu/drm/radeon/radeon_semaphore.c
index 2b42aa1914f2..9006b32d5eed 100644
--- a/drivers/gpu/drm/radeon/radeon_semaphore.c
+++ b/drivers/gpu/drm/radeon/radeon_semaphore.c
@@ -34,14 +34,15 @@
int radeon_semaphore_create(struct radeon_device *rdev,
struct radeon_semaphore **semaphore)
{
+ uint32_t *cpu_addr;
int i, r;
*semaphore = kmalloc(sizeof(struct radeon_semaphore), GFP_KERNEL);
if (*semaphore == NULL) {
return -ENOMEM;
}
- r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo,
- &(*semaphore)->sa_bo, 8, 8, true);
+ r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, &(*semaphore)->sa_bo,
+ 8 * RADEON_NUM_SYNCS, 8, true);
if (r) {
kfree(*semaphore);
*semaphore = NULL;
@@ -49,7 +50,10 @@ int radeon_semaphore_create(struct radeon_device *rdev,
}
(*semaphore)->waiters = 0;
(*semaphore)->gpu_addr = radeon_sa_bo_gpu_addr((*semaphore)->sa_bo);
- *((uint64_t*)radeon_sa_bo_cpu_addr((*semaphore)->sa_bo)) = 0;
+
+ cpu_addr = radeon_sa_bo_cpu_addr((*semaphore)->sa_bo);
+ for (i = 0; i < RADEON_NUM_SYNCS; ++i)
+ cpu_addr[i] = 0;
for (i = 0; i < RADEON_NUM_RINGS; ++i)
(*semaphore)->sync_to[i] = NULL;
@@ -125,6 +129,7 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev,
struct radeon_semaphore *semaphore,
int ring)
{
+ unsigned count = 0;
int i, r;
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
@@ -140,6 +145,12 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev,
return -EINVAL;
}
+ if (++count > RADEON_NUM_SYNCS) {
+ /* not enough room, wait manually */
+ radeon_fence_wait_locked(fence);
+ continue;
+ }
+
/* allocate enough space for sync command */
r = radeon_ring_alloc(rdev, &rdev->ring[i], 16);
if (r) {
@@ -164,6 +175,8 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev,
radeon_ring_commit(rdev, &rdev->ring[i]);
radeon_fence_note_sync(fence, ring);
+
+ semaphore->gpu_addr += 8;
}
return 0;
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index 77f5b0c3edb8..040a2a10ea17 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -714,6 +714,9 @@ int radeon_ttm_init(struct radeon_device *rdev)
DRM_ERROR("Failed initializing VRAM heap.\n");
return r;
}
+ /* Change the size here instead of the init above so only lpfn is affected */
+ radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
+
r = radeon_bo_create(rdev, 256 * 1024, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_VRAM,
NULL, &rdev->stollen_vga_memory);
@@ -935,7 +938,7 @@ static ssize_t radeon_ttm_gtt_read(struct file *f, char __user *buf,
while (size) {
loff_t p = *pos / PAGE_SIZE;
unsigned off = *pos & ~PAGE_MASK;
- ssize_t cur_size = min(size, PAGE_SIZE - off);
+ size_t cur_size = min_t(size_t, size, PAGE_SIZE - off);
struct page *page;
void *ptr;
diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c
index 6781fee1eaad..3e6804b2b2ef 100644
--- a/drivers/gpu/drm/radeon/radeon_uvd.c
+++ b/drivers/gpu/drm/radeon/radeon_uvd.c
@@ -171,6 +171,8 @@ void radeon_uvd_fini(struct radeon_device *rdev)
radeon_bo_unref(&rdev->uvd.vcpu_bo);
+ radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX]);
+
release_firmware(rdev->uvd_fw);
}
diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c
index b5c2369cda2f..130d5cc50d43 100644
--- a/drivers/gpu/drm/radeon/rs400.c
+++ b/drivers/gpu/drm/radeon/rs400.c
@@ -474,8 +474,6 @@ int rs400_resume(struct radeon_device *rdev)
/* Initialize surface registers */
radeon_surface_init(rdev);
- radeon_pm_resume(rdev);
-
rdev->accel_working = true;
r = rs400_startup(rdev);
if (r) {
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index fdcde7693032..72d3616de08e 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -1048,8 +1048,6 @@ int rs600_resume(struct radeon_device *rdev)
/* Initialize surface registers */
radeon_surface_init(rdev);
- radeon_pm_resume(rdev);
-
rdev->accel_working = true;
r = rs600_startup(rdev);
if (r) {
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index 35950738bd5e..3462b64369bf 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -756,8 +756,6 @@ int rs690_resume(struct radeon_device *rdev)
/* Initialize surface registers */
radeon_surface_init(rdev);
- radeon_pm_resume(rdev);
-
rdev->accel_working = true;
r = rs690_startup(rdev);
if (r) {
diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c
index 98e8138ff779..237dd29d9f1c 100644
--- a/drivers/gpu/drm/radeon/rv515.c
+++ b/drivers/gpu/drm/radeon/rv515.c
@@ -586,8 +586,6 @@ int rv515_resume(struct radeon_device *rdev)
/* Initialize surface registers */
radeon_surface_init(rdev);
- radeon_pm_resume(rdev);
-
rdev->accel_working = true;
r = rv515_startup(rdev);
if (r) {
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 6c772e58c784..fef310773aad 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -1811,7 +1811,8 @@ int rv770_resume(struct radeon_device *rdev)
/* init golden registers */
rv770_init_golden_registers(rdev);
- radeon_pm_resume(rdev);
+ if (rdev->pm.pm_method == PM_METHOD_DPM)
+ radeon_pm_resume(rdev);
rdev->accel_working = true;
r = rv770_startup(rdev);
@@ -1955,9 +1956,9 @@ void rv770_fini(struct radeon_device *rdev)
radeon_wb_fini(rdev);
radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev);
- rv770_pcie_gart_fini(rdev);
uvd_v1_0_fini(rdev);
radeon_uvd_fini(rdev);
+ rv770_pcie_gart_fini(rdev);
r600_vram_scratch_fini(rdev);
radeon_gem_fini(rdev);
radeon_fence_driver_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c
index 80c595aba359..b5f63f5e22a3 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.c
+++ b/drivers/gpu/drm/radeon/rv770_dpm.c
@@ -2174,7 +2174,6 @@ static void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev,
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
struct rv7xx_ps *ps = rv770_get_ps(rps);
u32 sclk, mclk;
- u16 vddc;
struct rv7xx_pl *pl;
switch (index) {
@@ -2214,8 +2213,8 @@ static void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev,
/* patch up vddc if necessary */
if (pl->vddc == 0xff01) {
- if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0)
- pl->vddc = vddc;
+ if (pi->max_vddc)
+ pl->vddc = pi->max_vddc;
}
if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) {
@@ -2527,14 +2526,7 @@ u32 rv770_dpm_get_mclk(struct radeon_device *rdev, bool low)
bool rv770_dpm_vblank_too_short(struct radeon_device *rdev)
{
u32 vblank_time = r600_dpm_get_vblank_time(rdev);
- u32 switch_limit = 300;
-
- /* quirks */
- /* ASUS K70AF */
- if ((rdev->pdev->device == 0x9553) &&
- (rdev->pdev->subsystem_vendor == 0x1043) &&
- (rdev->pdev->subsystem_device == 0x1c42))
- switch_limit = 200;
+ u32 switch_limit = 200; /* 300 */
/* RV770 */
/* mclk switching doesn't seem to work reliably on desktop RV770s */
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index 09ec4f6c53bb..9a124d0608b3 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -6338,6 +6338,10 @@ restart_ih:
break;
}
break;
+ case 124: /* UVD */
+ DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data);
+ radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX);
+ break;
case 146:
case 147:
addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR);
@@ -6614,7 +6618,8 @@ int si_resume(struct radeon_device *rdev)
/* init golden registers */
si_init_golden_registers(rdev);
- radeon_pm_resume(rdev);
+ if (rdev->pm.pm_method == PM_METHOD_DPM)
+ radeon_pm_resume(rdev);
rdev->accel_working = true;
r = si_startup(rdev);
diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c
index 0471501338fb..0a2f5b4bca43 100644
--- a/drivers/gpu/drm/radeon/si_dpm.c
+++ b/drivers/gpu/drm/radeon/si_dpm.c
@@ -2395,7 +2395,7 @@ static int si_populate_sq_ramping_values(struct radeon_device *rdev,
if (SISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT))
enable_sq_ramping = false;
- if (SISLANDS_DPM2_SQ_RAMP_LTI_RATIO <= (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
+ if (SISLANDS_DPM2_SQ_RAMP_LTI_RATIO > (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
enable_sq_ramping = false;
for (i = 0; i < state->performance_level_count; i++) {
@@ -6472,7 +6472,8 @@ void si_dpm_fini(struct radeon_device *rdev)
void si_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
struct seq_file *m)
{
- struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct radeon_ps *rps = &eg_pi->current_rps;
struct ni_ps *ps = ni_get_ps(rps);
struct rv7xx_pl *pl;
u32 current_index =
diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c
index f121efe12dc5..8b47b3cd0357 100644
--- a/drivers/gpu/drm/radeon/sumo_dpm.c
+++ b/drivers/gpu/drm/radeon/sumo_dpm.c
@@ -1807,7 +1807,7 @@ void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev
struct seq_file *m)
{
struct sumo_power_info *pi = sumo_get_pi(rdev);
- struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+ struct radeon_ps *rps = &pi->current_rps;
struct sumo_ps *ps = sumo_get_ps(rps);
struct sumo_pl *pl;
u32 current_index =
diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c
index 2d447192d6f7..2da0e17eb960 100644
--- a/drivers/gpu/drm/radeon/trinity_dpm.c
+++ b/drivers/gpu/drm/radeon/trinity_dpm.c
@@ -1926,7 +1926,8 @@ void trinity_dpm_print_power_state(struct radeon_device *rdev,
void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
struct seq_file *m)
{
- struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ struct radeon_ps *rps = &pi->current_rps;
struct trinity_ps *ps = trinity_get_ps(rps);
struct trinity_pl *pl;
u32 current_index =
diff --git a/drivers/gpu/drm/radeon/uvd_v2_2.c b/drivers/gpu/drm/radeon/uvd_v2_2.c
index 824550db3fed..d1771004cb52 100644
--- a/drivers/gpu/drm/radeon/uvd_v2_2.c
+++ b/drivers/gpu/drm/radeon/uvd_v2_2.c
@@ -57,7 +57,6 @@ void uvd_v2_2_fence_emit(struct radeon_device *rdev,
radeon_ring_write(ring, 0);
radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0));
radeon_ring_write(ring, 2);
- return;
}
/**
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 88a529008ce0..c71594754f46 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -104,7 +104,7 @@ static void tegra_drm_context_free(struct tegra_drm_context *context)
static void tegra_drm_lastclose(struct drm_device *drm)
{
-#ifdef CONFIG_TEGRA_DRM_FBDEV
+#ifdef CONFIG_DRM_TEGRA_FBDEV
struct tegra_drm *tegra = drm->dev_private;
tegra_fbdev_restore_mode(tegra->fbdev);
diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c
index 338f7f6561d7..0266fb40479e 100644
--- a/drivers/gpu/drm/tegra/rgb.c
+++ b/drivers/gpu/drm/tegra/rgb.c
@@ -15,6 +15,7 @@
struct tegra_rgb {
struct tegra_output output;
struct tegra_dc *dc;
+ bool enabled;
struct clk *clk_parent;
struct clk *clk;
@@ -89,6 +90,9 @@ static int tegra_output_rgb_enable(struct tegra_output *output)
struct tegra_rgb *rgb = to_rgb(output);
unsigned long value;
+ if (rgb->enabled)
+ return 0;
+
tegra_dc_write_regs(rgb->dc, rgb_enable, ARRAY_SIZE(rgb_enable));
value = DE_SELECT_ACTIVE | DE_CONTROL_NORMAL;
@@ -122,6 +126,8 @@ static int tegra_output_rgb_enable(struct tegra_output *output)
tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+ rgb->enabled = true;
+
return 0;
}
@@ -130,6 +136,9 @@ static int tegra_output_rgb_disable(struct tegra_output *output)
struct tegra_rgb *rgb = to_rgb(output);
unsigned long value;
+ if (!rgb->enabled)
+ return 0;
+
value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_POWER_CONTROL);
value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
@@ -144,6 +153,8 @@ static int tegra_output_rgb_disable(struct tegra_output *output)
tegra_dc_write_regs(rgb->dc, rgb_disable, ARRAY_SIZE(rgb_disable));
+ rgb->enabled = false;
+
return 0;
}
diff --git a/drivers/gpu/drm/ttm/ttm_agp_backend.c b/drivers/gpu/drm/ttm/ttm_agp_backend.c
index 3302f99e7497..764be36397fd 100644
--- a/drivers/gpu/drm/ttm/ttm_agp_backend.c
+++ b/drivers/gpu/drm/ttm/ttm_agp_backend.c
@@ -126,6 +126,7 @@ struct ttm_tt *ttm_agp_tt_create(struct ttm_bo_device *bdev,
agp_be->ttm.func = &ttm_agp_func;
if (ttm_tt_init(&agp_be->ttm, bdev, size, page_flags, dummy_read_page)) {
+ kfree(agp_be);
return NULL;
}
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index a06651309388..214b7992a3aa 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -351,9 +351,11 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
moved:
if (bo->evicted) {
- ret = bdev->driver->invalidate_caches(bdev, bo->mem.placement);
- if (ret)
- pr_err("Can not flush read caches\n");
+ if (bdev->driver->invalidate_caches) {
+ ret = bdev->driver->invalidate_caches(bdev, bo->mem.placement);
+ if (ret)
+ pr_err("Can not flush read caches\n");
+ }
bo->evicted = false;
}
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
index 801231c9ae48..0ce48e5a9cb4 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -339,11 +339,13 @@ int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma,
vma->vm_private_data = bo;
/*
- * PFNMAP is faster than MIXEDMAP due to reduced page
- * administration. So use MIXEDMAP only if private VMA, where
- * we need to support COW.
+ * We'd like to use VM_PFNMAP on shared mappings, where
+ * (vma->vm_flags & VM_SHARED) != 0, for performance reasons,
+ * but for some reason VM_PFNMAP + x86 PAT + write-combine is very
+ * bad for performance. Until that has been sorted out, use
+ * VM_MIXEDMAP on all mappings. See freedesktop.org bug #75719
*/
- vma->vm_flags |= (vma->vm_flags & VM_SHARED) ? VM_PFNMAP : VM_MIXEDMAP;
+ vma->vm_flags |= VM_MIXEDMAP;
vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
return 0;
out_unref:
@@ -359,7 +361,7 @@ int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
vma->vm_ops = &ttm_bo_vm_ops;
vma->vm_private_data = ttm_bo_reference(bo);
- vma->vm_flags |= (vma->vm_flags & VM_SHARED) ? VM_PFNMAP : VM_MIXEDMAP;
+ vma->vm_flags |= VM_MIXEDMAP;
vma->vm_flags |= VM_IO | VM_DONTEXPAND;
return 0;
}
diff --git a/drivers/gpu/drm/udl/udl_gem.c b/drivers/gpu/drm/udl/udl_gem.c
index 8d67b943ac05..0394811251bd 100644
--- a/drivers/gpu/drm/udl/udl_gem.c
+++ b/drivers/gpu/drm/udl/udl_gem.c
@@ -177,8 +177,10 @@ void udl_gem_free_object(struct drm_gem_object *gem_obj)
if (obj->vmapping)
udl_gem_vunmap(obj);
- if (gem_obj->import_attach)
+ if (gem_obj->import_attach) {
drm_prime_gem_destroy(gem_obj, obj->sg);
+ put_device(gem_obj->dev->dev);
+ }
if (obj->pages)
udl_gem_put_pages(obj);
@@ -256,9 +258,12 @@ struct drm_gem_object *udl_gem_prime_import(struct drm_device *dev,
int ret;
/* need to attach */
+ get_device(dev->dev);
attach = dma_buf_attach(dma_buf, dev->dev);
- if (IS_ERR(attach))
+ if (IS_ERR(attach)) {
+ put_device(dev->dev);
return ERR_CAST(attach);
+ }
get_dma_buf(dma_buf);
@@ -282,6 +287,6 @@ fail_unmap:
fail_detach:
dma_buf_detach(dma_buf, attach);
dma_buf_put(dma_buf);
-
+ put_device(dev->dev);
return ERR_PTR(ret);
}
diff --git a/drivers/gpu/drm/vmwgfx/svga3d_reg.h b/drivers/gpu/drm/vmwgfx/svga3d_reg.h
index b645647b7776..f58dc7dd15c5 100644
--- a/drivers/gpu/drm/vmwgfx/svga3d_reg.h
+++ b/drivers/gpu/drm/vmwgfx/svga3d_reg.h
@@ -261,12 +261,7 @@ typedef enum SVGA3dSurfaceFormat {
/* Planar video formats. */
SVGA3D_YV12 = 121,
- /* Shader constant formats. */
- SVGA3D_SURFACE_SHADERCONST_FLOAT = 122,
- SVGA3D_SURFACE_SHADERCONST_INT = 123,
- SVGA3D_SURFACE_SHADERCONST_BOOL = 124,
-
- SVGA3D_FORMAT_MAX = 125,
+ SVGA3D_FORMAT_MAX = 122,
} SVGA3dSurfaceFormat;
typedef uint32 SVGA3dColor; /* a, r, g, b */
@@ -1223,9 +1218,19 @@ typedef enum {
#define SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL 1129
#define SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE 1130
-
+#define SVGA_3D_CMD_GB_SCREEN_DMA 1131
+#define SVGA_3D_CMD_BIND_GB_SURFACE_WITH_PITCH 1132
+#define SVGA_3D_CMD_GB_MOB_FENCE 1133
+#define SVGA_3D_CMD_DEFINE_GB_SURFACE_V2 1134
#define SVGA_3D_CMD_DEFINE_GB_MOB64 1135
#define SVGA_3D_CMD_REDEFINE_GB_MOB64 1136
+#define SVGA_3D_CMD_NOP_ERROR 1137
+
+#define SVGA_3D_CMD_RESERVED1 1138
+#define SVGA_3D_CMD_RESERVED2 1139
+#define SVGA_3D_CMD_RESERVED3 1140
+#define SVGA_3D_CMD_RESERVED4 1141
+#define SVGA_3D_CMD_RESERVED5 1142
#define SVGA_3D_CMD_MAX 1142
#define SVGA_3D_CMD_FUTURE_MAX 3000
@@ -1973,8 +1978,7 @@ struct {
uint32 sizeInBytes;
uint32 validSizeInBytes;
SVGAMobFormat ptDepth;
-}
-__attribute__((__packed__))
+} __packed
SVGA3dCmdSetOTableBase; /* SVGA_3D_CMD_SET_OTABLE_BASE */
typedef
@@ -1984,15 +1988,13 @@ struct {
uint32 sizeInBytes;
uint32 validSizeInBytes;
SVGAMobFormat ptDepth;
-}
-__attribute__((__packed__))
+} __packed
SVGA3dCmdSetOTableBase64; /* SVGA_3D_CMD_SET_OTABLE_BASE64 */
typedef
struct {
SVGAOTableType type;
-}
-__attribute__((__packed__))
+} __packed
SVGA3dCmdReadbackOTable; /* SVGA_3D_CMD_READBACK_OTABLE */
/*
@@ -2005,8 +2007,7 @@ struct SVGA3dCmdDefineGBMob {
SVGAMobFormat ptDepth;
PPN base;
uint32 sizeInBytes;
-}
-__attribute__((__packed__))
+} __packed
SVGA3dCmdDefineGBMob; /* SVGA_3D_CMD_DEFINE_GB_MOB */
@@ -2017,8 +2018,7 @@ SVGA3dCmdDefineGBMob; /* SVGA_3D_CMD_DEFINE_GB_MOB */
typedef
struct SVGA3dCmdDestroyGBMob {
SVGAMobId mobid;
-}
-__attribute__((__packed__))
+} __packed
SVGA3dCmdDestroyGBMob; /* SVGA_3D_CMD_DESTROY_GB_MOB */
/*
@@ -2031,8 +2031,7 @@ struct SVGA3dCmdRedefineGBMob {
SVGAMobFormat ptDepth;
PPN base;
uint32 sizeInBytes;
-}
-__attribute__((__packed__))
+} __packed
SVGA3dCmdRedefineGBMob; /* SVGA_3D_CMD_REDEFINE_GB_MOB */
/*
@@ -2045,8 +2044,7 @@ struct SVGA3dCmdDefineGBMob64 {
SVGAMobFormat ptDepth;
PPN64 base;
uint32 sizeInBytes;
-}
-__attribute__((__packed__))
+} __packed
SVGA3dCmdDefineGBMob64; /* SVGA_3D_CMD_DEFINE_GB_MOB64 */
/*
@@ -2059,8 +2057,7 @@ struct SVGA3dCmdRedefineGBMob64 {
SVGAMobFormat ptDepth;
PPN64 base;
uint32 sizeInBytes;
-}
-__attribute__((__packed__))
+} __packed
SVGA3dCmdRedefineGBMob64; /* SVGA_3D_CMD_REDEFINE_GB_MOB64 */
/*
@@ -2070,8 +2067,7 @@ SVGA3dCmdRedefineGBMob64; /* SVGA_3D_CMD_REDEFINE_GB_MOB64 */
typedef
struct SVGA3dCmdUpdateGBMobMapping {
SVGAMobId mobid;
-}
-__attribute__((__packed__))
+} __packed
SVGA3dCmdUpdateGBMobMapping; /* SVGA_3D_CMD_UPDATE_GB_MOB_MAPPING */
/*
@@ -2087,7 +2083,8 @@ struct SVGA3dCmdDefineGBSurface {
uint32 multisampleCount;
SVGA3dTextureFilter autogenFilter;
SVGA3dSize size;
-} SVGA3dCmdDefineGBSurface; /* SVGA_3D_CMD_DEFINE_GB_SURFACE */
+} __packed
+SVGA3dCmdDefineGBSurface; /* SVGA_3D_CMD_DEFINE_GB_SURFACE */
/*
* Destroy a guest-backed surface.
@@ -2096,7 +2093,8 @@ struct SVGA3dCmdDefineGBSurface {
typedef
struct SVGA3dCmdDestroyGBSurface {
uint32 sid;
-} SVGA3dCmdDestroyGBSurface; /* SVGA_3D_CMD_DESTROY_GB_SURFACE */
+} __packed
+SVGA3dCmdDestroyGBSurface; /* SVGA_3D_CMD_DESTROY_GB_SURFACE */
/*
* Bind a guest-backed surface to an object.
@@ -2106,7 +2104,8 @@ typedef
struct SVGA3dCmdBindGBSurface {
uint32 sid;
SVGAMobId mobid;
-} SVGA3dCmdBindGBSurface; /* SVGA_3D_CMD_BIND_GB_SURFACE */
+} __packed
+SVGA3dCmdBindGBSurface; /* SVGA_3D_CMD_BIND_GB_SURFACE */
/*
* Conditionally bind a mob to a guest backed surface if testMobid
@@ -2123,7 +2122,7 @@ struct{
SVGAMobId testMobid;
SVGAMobId mobid;
uint32 flags;
-}
+} __packed
SVGA3dCmdCondBindGBSurface; /* SVGA_3D_CMD_COND_BIND_GB_SURFACE */
/*
@@ -2135,7 +2134,8 @@ typedef
struct SVGA3dCmdUpdateGBImage {
SVGA3dSurfaceImageId image;
SVGA3dBox box;
-} SVGA3dCmdUpdateGBImage; /* SVGA_3D_CMD_UPDATE_GB_IMAGE */
+} __packed
+SVGA3dCmdUpdateGBImage; /* SVGA_3D_CMD_UPDATE_GB_IMAGE */
/*
* Update an entire guest-backed surface.
@@ -2145,7 +2145,8 @@ struct SVGA3dCmdUpdateGBImage {
typedef
struct SVGA3dCmdUpdateGBSurface {
uint32 sid;
-} SVGA3dCmdUpdateGBSurface; /* SVGA_3D_CMD_UPDATE_GB_SURFACE */
+} __packed
+SVGA3dCmdUpdateGBSurface; /* SVGA_3D_CMD_UPDATE_GB_SURFACE */
/*
* Readback an image in a guest-backed surface.
@@ -2155,7 +2156,8 @@ struct SVGA3dCmdUpdateGBSurface {
typedef
struct SVGA3dCmdReadbackGBImage {
SVGA3dSurfaceImageId image;
-} SVGA3dCmdReadbackGBImage; /* SVGA_3D_CMD_READBACK_GB_IMAGE*/
+} __packed
+SVGA3dCmdReadbackGBImage; /* SVGA_3D_CMD_READBACK_GB_IMAGE*/
/*
* Readback an entire guest-backed surface.
@@ -2165,7 +2167,8 @@ struct SVGA3dCmdReadbackGBImage {
typedef
struct SVGA3dCmdReadbackGBSurface {
uint32 sid;
-} SVGA3dCmdReadbackGBSurface; /* SVGA_3D_CMD_READBACK_GB_SURFACE */
+} __packed
+SVGA3dCmdReadbackGBSurface; /* SVGA_3D_CMD_READBACK_GB_SURFACE */
/*
* Readback a sub rect of an image in a guest-backed surface. After
@@ -2179,7 +2182,7 @@ struct SVGA3dCmdReadbackGBImagePartial {
SVGA3dSurfaceImageId image;
SVGA3dBox box;
uint32 invertBox;
-}
+} __packed
SVGA3dCmdReadbackGBImagePartial; /* SVGA_3D_CMD_READBACK_GB_IMAGE_PARTIAL */
/*
@@ -2190,7 +2193,8 @@ SVGA3dCmdReadbackGBImagePartial; /* SVGA_3D_CMD_READBACK_GB_IMAGE_PARTIAL */
typedef
struct SVGA3dCmdInvalidateGBImage {
SVGA3dSurfaceImageId image;
-} SVGA3dCmdInvalidateGBImage; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE */
+} __packed
+SVGA3dCmdInvalidateGBImage; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE */
/*
* Invalidate an entire guest-backed surface.
@@ -2200,7 +2204,8 @@ struct SVGA3dCmdInvalidateGBImage {
typedef
struct SVGA3dCmdInvalidateGBSurface {
uint32 sid;
-} SVGA3dCmdInvalidateGBSurface; /* SVGA_3D_CMD_INVALIDATE_GB_SURFACE */
+} __packed
+SVGA3dCmdInvalidateGBSurface; /* SVGA_3D_CMD_INVALIDATE_GB_SURFACE */
/*
* Invalidate a sub rect of an image in a guest-backed surface. After
@@ -2214,7 +2219,7 @@ struct SVGA3dCmdInvalidateGBImagePartial {
SVGA3dSurfaceImageId image;
SVGA3dBox box;
uint32 invertBox;
-}
+} __packed
SVGA3dCmdInvalidateGBImagePartial; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL */
/*
@@ -2224,7 +2229,8 @@ SVGA3dCmdInvalidateGBImagePartial; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL */
typedef
struct SVGA3dCmdDefineGBContext {
uint32 cid;
-} SVGA3dCmdDefineGBContext; /* SVGA_3D_CMD_DEFINE_GB_CONTEXT */
+} __packed
+SVGA3dCmdDefineGBContext; /* SVGA_3D_CMD_DEFINE_GB_CONTEXT */
/*
* Destroy a guest-backed context.
@@ -2233,7 +2239,8 @@ struct SVGA3dCmdDefineGBContext {
typedef
struct SVGA3dCmdDestroyGBContext {
uint32 cid;
-} SVGA3dCmdDestroyGBContext; /* SVGA_3D_CMD_DESTROY_GB_CONTEXT */
+} __packed
+SVGA3dCmdDestroyGBContext; /* SVGA_3D_CMD_DESTROY_GB_CONTEXT */
/*
* Bind a guest-backed context.
@@ -2252,7 +2259,8 @@ struct SVGA3dCmdBindGBContext {
uint32 cid;
SVGAMobId mobid;
uint32 validContents;
-} SVGA3dCmdBindGBContext; /* SVGA_3D_CMD_BIND_GB_CONTEXT */
+} __packed
+SVGA3dCmdBindGBContext; /* SVGA_3D_CMD_BIND_GB_CONTEXT */
/*
* Readback a guest-backed context.
@@ -2262,7 +2270,8 @@ struct SVGA3dCmdBindGBContext {
typedef
struct SVGA3dCmdReadbackGBContext {
uint32 cid;
-} SVGA3dCmdReadbackGBContext; /* SVGA_3D_CMD_READBACK_GB_CONTEXT */
+} __packed
+SVGA3dCmdReadbackGBContext; /* SVGA_3D_CMD_READBACK_GB_CONTEXT */
/*
* Invalidate a guest-backed context.
@@ -2270,7 +2279,8 @@ struct SVGA3dCmdReadbackGBContext {
typedef
struct SVGA3dCmdInvalidateGBContext {
uint32 cid;
-} SVGA3dCmdInvalidateGBContext; /* SVGA_3D_CMD_INVALIDATE_GB_CONTEXT */
+} __packed
+SVGA3dCmdInvalidateGBContext; /* SVGA_3D_CMD_INVALIDATE_GB_CONTEXT */
/*
* Define a guest-backed shader.
@@ -2281,7 +2291,8 @@ struct SVGA3dCmdDefineGBShader {
uint32 shid;
SVGA3dShaderType type;
uint32 sizeInBytes;
-} SVGA3dCmdDefineGBShader; /* SVGA_3D_CMD_DEFINE_GB_SHADER */
+} __packed
+SVGA3dCmdDefineGBShader; /* SVGA_3D_CMD_DEFINE_GB_SHADER */
/*
* Bind a guest-backed shader.
@@ -2291,7 +2302,8 @@ typedef struct SVGA3dCmdBindGBShader {
uint32 shid;
SVGAMobId mobid;
uint32 offsetInBytes;
-} SVGA3dCmdBindGBShader; /* SVGA_3D_CMD_BIND_GB_SHADER */
+} __packed
+SVGA3dCmdBindGBShader; /* SVGA_3D_CMD_BIND_GB_SHADER */
/*
* Destroy a guest-backed shader.
@@ -2299,7 +2311,8 @@ typedef struct SVGA3dCmdBindGBShader {
typedef struct SVGA3dCmdDestroyGBShader {
uint32 shid;
-} SVGA3dCmdDestroyGBShader; /* SVGA_3D_CMD_DESTROY_GB_SHADER */
+} __packed
+SVGA3dCmdDestroyGBShader; /* SVGA_3D_CMD_DESTROY_GB_SHADER */
typedef
struct {
@@ -2314,14 +2327,16 @@ struct {
* Note that FLOAT and INT constants are 4-dwords in length, while
* BOOL constants are 1-dword in length.
*/
-} SVGA3dCmdSetGBShaderConstInline;
+} __packed
+SVGA3dCmdSetGBShaderConstInline;
/* SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE */
typedef
struct {
uint32 cid;
SVGA3dQueryType type;
-} SVGA3dCmdBeginGBQuery; /* SVGA_3D_CMD_BEGIN_GB_QUERY */
+} __packed
+SVGA3dCmdBeginGBQuery; /* SVGA_3D_CMD_BEGIN_GB_QUERY */
typedef
struct {
@@ -2329,7 +2344,8 @@ struct {
SVGA3dQueryType type;
SVGAMobId mobid;
uint32 offset;
-} SVGA3dCmdEndGBQuery; /* SVGA_3D_CMD_END_GB_QUERY */
+} __packed
+SVGA3dCmdEndGBQuery; /* SVGA_3D_CMD_END_GB_QUERY */
/*
@@ -2346,21 +2362,22 @@ struct {
SVGA3dQueryType type;
SVGAMobId mobid;
uint32 offset;
-} SVGA3dCmdWaitForGBQuery; /* SVGA_3D_CMD_WAIT_FOR_GB_QUERY */
+} __packed
+SVGA3dCmdWaitForGBQuery; /* SVGA_3D_CMD_WAIT_FOR_GB_QUERY */
typedef
struct {
SVGAMobId mobid;
uint32 fbOffset;
uint32 initalized;
-}
+} __packed
SVGA3dCmdEnableGart; /* SVGA_3D_CMD_ENABLE_GART */
typedef
struct {
SVGAMobId mobid;
uint32 gartOffset;
-}
+} __packed
SVGA3dCmdMapMobIntoGart; /* SVGA_3D_CMD_MAP_MOB_INTO_GART */
@@ -2368,7 +2385,7 @@ typedef
struct {
uint32 gartOffset;
uint32 numPages;
-}
+} __packed
SVGA3dCmdUnmapGartRange; /* SVGA_3D_CMD_UNMAP_GART_RANGE */
@@ -2385,27 +2402,27 @@ struct {
int32 xRoot;
int32 yRoot;
uint32 flags;
-}
+} __packed
SVGA3dCmdDefineGBScreenTarget; /* SVGA_3D_CMD_DEFINE_GB_SCREENTARGET */
typedef
struct {
uint32 stid;
-}
+} __packed
SVGA3dCmdDestroyGBScreenTarget; /* SVGA_3D_CMD_DESTROY_GB_SCREENTARGET */
typedef
struct {
uint32 stid;
SVGA3dSurfaceImageId image;
-}
+} __packed
SVGA3dCmdBindGBScreenTarget; /* SVGA_3D_CMD_BIND_GB_SCREENTARGET */
typedef
struct {
uint32 stid;
SVGA3dBox box;
-}
+} __packed
SVGA3dCmdUpdateGBScreenTarget; /* SVGA_3D_CMD_UPDATE_GB_SCREENTARGET */
/*
diff --git a/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h b/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h
index 8369c3ba10fe..ef3385096145 100644
--- a/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h
+++ b/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h
@@ -38,8 +38,11 @@
#define DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y))
#define max_t(type, x, y) ((x) > (y) ? (x) : (y))
+#define min_t(type, x, y) ((x) < (y) ? (x) : (y))
#define surf_size_struct SVGA3dSize
#define u32 uint32
+#define u64 uint64_t
+#define U32_MAX ((u32)~0U)
#endif /* __KERNEL__ */
@@ -704,8 +707,8 @@ static const struct svga3d_surface_desc svga3d_surface_descs[] = {
static inline u32 clamped_umul32(u32 a, u32 b)
{
- uint64_t tmp = (uint64_t) a*b;
- return (tmp > (uint64_t) ((u32) -1)) ? (u32) -1 : tmp;
+ u64 tmp = (u64) a*b;
+ return (tmp > (u64) U32_MAX) ? U32_MAX : tmp;
}
static inline const struct svga3d_surface_desc *
@@ -834,7 +837,7 @@ svga3dsurface_get_serialized_size(SVGA3dSurfaceFormat format,
bool cubemap)
{
const struct svga3d_surface_desc *desc = svga3dsurface_get_desc(format);
- u32 total_size = 0;
+ u64 total_size = 0;
u32 mip;
for (mip = 0; mip < num_mip_levels; mip++) {
@@ -847,7 +850,7 @@ svga3dsurface_get_serialized_size(SVGA3dSurfaceFormat format,
if (cubemap)
total_size *= SVGA3D_MAX_SURFACE_FACES;
- return total_size;
+ return (u32) min_t(u64, total_size, (u64) U32_MAX);
}
diff --git a/drivers/gpu/drm/vmwgfx/svga_reg.h b/drivers/gpu/drm/vmwgfx/svga_reg.h
index 71defa4d2d75..11323dd5196f 100644
--- a/drivers/gpu/drm/vmwgfx/svga_reg.h
+++ b/drivers/gpu/drm/vmwgfx/svga_reg.h
@@ -169,10 +169,17 @@ enum {
SVGA_REG_TRACES = 45, /* Enable trace-based updates even when FIFO is on */
SVGA_REG_GMRS_MAX_PAGES = 46, /* Maximum number of 4KB pages for all GMRs */
SVGA_REG_MEMORY_SIZE = 47, /* Total dedicated device memory excluding FIFO */
+ SVGA_REG_COMMAND_LOW = 48, /* Lower 32 bits and submits commands */
+ SVGA_REG_COMMAND_HIGH = 49, /* Upper 32 bits of command buffer PA */
SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM = 50, /* Max primary memory */
SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB = 51, /* Suggested limit on mob mem */
SVGA_REG_DEV_CAP = 52, /* Write dev cap index, read value */
- SVGA_REG_TOP = 53, /* Must be 1 more than the last register */
+ SVGA_REG_CMD_PREPEND_LOW = 53,
+ SVGA_REG_CMD_PREPEND_HIGH = 54,
+ SVGA_REG_SCREENTARGET_MAX_WIDTH = 55,
+ SVGA_REG_SCREENTARGET_MAX_HEIGHT = 56,
+ SVGA_REG_MOB_MAX_SIZE = 57,
+ SVGA_REG_TOP = 58, /* Must be 1 more than the last register */
SVGA_PALETTE_BASE = 1024, /* Base of SVGA color map */
/* Next 768 (== 256*3) registers exist for colormap */
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c
index 9426c53fb483..1e80152674b5 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c
@@ -551,8 +551,7 @@ static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi, bool rebind)
cmd->header.size = sizeof(cmd->body);
cmd->body.cid = bi->ctx->id;
cmd->body.type = bi->i1.shader_type;
- cmd->body.shid =
- cpu_to_le32((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
+ cmd->body.shid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
vmw_fifo_commit(dev_priv, sizeof(*cmd));
return 0;
@@ -585,8 +584,7 @@ static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi,
cmd->header.size = sizeof(cmd->body);
cmd->body.cid = bi->ctx->id;
cmd->body.type = bi->i1.rt_type;
- cmd->body.target.sid =
- cpu_to_le32((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
+ cmd->body.target.sid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
cmd->body.target.face = 0;
cmd->body.target.mipmap = 0;
vmw_fifo_commit(dev_priv, sizeof(*cmd));
@@ -628,8 +626,7 @@ static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi,
cmd->body.c.cid = bi->ctx->id;
cmd->body.s1.stage = bi->i1.texture_stage;
cmd->body.s1.name = SVGA3D_TS_BIND_TEXTURE;
- cmd->body.s1.value =
- cpu_to_le32((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
+ cmd->body.s1.value = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
vmw_fifo_commit(dev_priv, sizeof(*cmd));
return 0;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 3bdc0adc656d..0083cbf99edf 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -667,6 +667,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv->memory_size = 512*1024*1024;
}
dev_priv->max_mob_pages = 0;
+ dev_priv->max_mob_size = 0;
if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) {
uint64_t mem_size =
vmw_read(dev_priv,
@@ -676,6 +677,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv->prim_bb_mem =
vmw_read(dev_priv,
SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM);
+ dev_priv->max_mob_size =
+ vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE);
} else
dev_priv->prim_bb_mem = dev_priv->vram_size;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index ecaa302a6154..07831554dad7 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -40,7 +40,7 @@
#include <drm/ttm/ttm_module.h>
#include "vmwgfx_fence.h"
-#define VMWGFX_DRIVER_DATE "20121114"
+#define VMWGFX_DRIVER_DATE "20140228"
#define VMWGFX_DRIVER_MAJOR 2
#define VMWGFX_DRIVER_MINOR 5
#define VMWGFX_DRIVER_PATCHLEVEL 0
@@ -386,6 +386,7 @@ struct vmw_private {
uint32_t max_gmr_ids;
uint32_t max_gmr_pages;
uint32_t max_mob_pages;
+ uint32_t max_mob_size;
uint32_t memory_size;
bool has_gmr;
bool has_mob;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index 269b85cc875a..efb575a7996c 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -602,7 +602,7 @@ static int vmw_cmd_cid_check(struct vmw_private *dev_priv,
{
struct vmw_cid_cmd {
SVGA3dCmdHeader header;
- __le32 cid;
+ uint32_t cid;
} *cmd;
cmd = container_of(header, struct vmw_cid_cmd, header);
@@ -1835,7 +1835,7 @@ static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv,
return 0;
}
-static const struct vmw_cmd_entry const vmw_cmd_entries[SVGA_3D_CMD_MAX] = {
+static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = {
VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DEFINE, &vmw_cmd_invalid,
false, false, false),
VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DESTROY, &vmw_cmd_invalid,
@@ -2032,6 +2032,9 @@ static int vmw_cmd_check(struct vmw_private *dev_priv,
goto out_invalid;
entry = &vmw_cmd_entries[cmd_id];
+ if (unlikely(!entry->func))
+ goto out_invalid;
+
if (unlikely(!entry->user_allow && !sw_context->kernel))
goto out_privileged;
@@ -2469,7 +2472,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
if (dev_priv->has_mob) {
ret = vmw_rebind_contexts(sw_context);
if (unlikely(ret != 0))
- goto out_err;
+ goto out_unlock_binding;
}
cmd = vmw_fifo_reserve(dev_priv, command_size);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
index f9881f9e62bd..47b70949bf3a 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -102,6 +102,9 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
vmw_fp->gb_aware = true;
param->value = dev_priv->max_mob_pages * PAGE_SIZE;
break;
+ case DRM_VMW_PARAM_MAX_MOB_SIZE:
+ param->value = dev_priv->max_mob_size;
+ break;
default:
DRM_ERROR("Illegal vmwgfx get param request: %d\n",
param->param);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
index d4a5a19cb8c3..04a64b8cd3cd 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
@@ -188,18 +188,20 @@ static void vmw_takedown_otable_base(struct vmw_private *dev_priv,
bo = otable->page_table->pt_bo;
cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
- if (unlikely(cmd == NULL))
- DRM_ERROR("Failed reserving FIFO space for OTable setup.\n");
-
- memset(cmd, 0, sizeof(*cmd));
- cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE;
- cmd->header.size = sizeof(cmd->body);
- cmd->body.type = type;
- cmd->body.baseAddress = 0;
- cmd->body.sizeInBytes = 0;
- cmd->body.validSizeInBytes = 0;
- cmd->body.ptDepth = SVGA3D_MOBFMT_INVALID;
- vmw_fifo_commit(dev_priv, sizeof(*cmd));
+ if (unlikely(cmd == NULL)) {
+ DRM_ERROR("Failed reserving FIFO space for OTable "
+ "takedown.\n");
+ } else {
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE;
+ cmd->header.size = sizeof(cmd->body);
+ cmd->body.type = type;
+ cmd->body.baseAddress = 0;
+ cmd->body.sizeInBytes = 0;
+ cmd->body.validSizeInBytes = 0;
+ cmd->body.ptDepth = SVGA3D_MOBFMT_INVALID;
+ vmw_fifo_commit(dev_priv, sizeof(*cmd));
+ }
if (bo) {
int ret;
@@ -562,11 +564,12 @@ void vmw_mob_unbind(struct vmw_private *dev_priv,
if (unlikely(cmd == NULL)) {
DRM_ERROR("Failed reserving FIFO space for Memory "
"Object unbinding.\n");
+ } else {
+ cmd->header.id = SVGA_3D_CMD_DESTROY_GB_MOB;
+ cmd->header.size = sizeof(cmd->body);
+ cmd->body.mobid = mob->id;
+ vmw_fifo_commit(dev_priv, sizeof(*cmd));
}
- cmd->header.id = SVGA_3D_CMD_DESTROY_GB_MOB;
- cmd->header.size = sizeof(cmd->body);
- cmd->body.mobid = mob->id;
- vmw_fifo_commit(dev_priv, sizeof(*cmd));
if (bo) {
vmw_fence_single_bo(bo, NULL);
ttm_bo_unreserve(bo);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index 2aa4bc6a4d60..9757b57f8388 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -427,8 +427,7 @@ int vmw_dmabuf_init(struct vmw_private *dev_priv,
INIT_LIST_HEAD(&vmw_bo->res_list);
ret = ttm_bo_init(bdev, &vmw_bo->base, size,
- (user) ? ttm_bo_type_device :
- ttm_bo_type_kernel, placement,
+ ttm_bo_type_device, placement,
0, interruptible,
NULL, acc_size, NULL, bo_free);
return ret;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
index 217d941b8176..ee3856578a12 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
@@ -371,13 +371,13 @@ int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data,
TTM_REF_USAGE);
}
-int vmw_shader_alloc(struct vmw_private *dev_priv,
- struct vmw_dma_buffer *buffer,
- size_t shader_size,
- size_t offset,
- SVGA3dShaderType shader_type,
- struct ttm_object_file *tfile,
- u32 *handle)
+static int vmw_shader_alloc(struct vmw_private *dev_priv,
+ struct vmw_dma_buffer *buffer,
+ size_t shader_size,
+ size_t offset,
+ SVGA3dShaderType shader_type,
+ struct ttm_object_file *tfile,
+ u32 *handle)
{
struct vmw_user_shader *ushader;
struct vmw_resource *res, *tmp;
@@ -779,6 +779,8 @@ vmw_compat_shader_man_create(struct vmw_private *dev_priv)
int ret;
man = kzalloc(sizeof(*man), GFP_KERNEL);
+ if (man == NULL)
+ return ERR_PTR(-ENOMEM);
man->dev_priv = dev_priv;
INIT_LIST_HEAD(&man->list);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
index 82468d902915..e7af580ab977 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
@@ -830,6 +830,24 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
if (unlikely(ret != 0))
goto out_unlock;
+ /*
+ * A gb-aware client referencing a shared surface will
+ * expect a backup buffer to be present.
+ */
+ if (dev_priv->has_mob && req->shareable) {
+ uint32_t backup_handle;
+
+ ret = vmw_user_dmabuf_alloc(dev_priv, tfile,
+ res->backup_size,
+ true,
+ &backup_handle,
+ &res->backup);
+ if (unlikely(ret != 0)) {
+ vmw_resource_unreference(&res);
+ goto out_unlock;
+ }
+ }
+
tmp = vmw_resource_reference(&srf->res);
ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime,
req->shareable, VMW_RES_SURFACE,
diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c
index 1146e3bba6e1..112f27e51bc7 100644
--- a/drivers/gpu/host1x/job.c
+++ b/drivers/gpu/host1x/job.c
@@ -538,7 +538,7 @@ int host1x_job_pin(struct host1x_job *job, struct device *dev)
g->base = job->gather_addr_phys[i];
- for (j = 0; j < job->num_gathers; j++)
+ for (j = i + 1; j < job->num_gathers; j++)
if (job->gathers[j].bo == g->bo)
job->gathers[j].handled = true;
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index f7220011a00b..7af9d0b5dea1 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -175,6 +175,15 @@ config HID_PRODIKEYS
multimedia keyboard, but will lack support for the musical keyboard
and some additional multimedia keys.
+config HID_CP2112
+ tristate "Silicon Labs CP2112 HID USB-to-SMBus Bridge support"
+ depends on USB_HID && I2C && GPIOLIB
+ ---help---
+ Support for Silicon Labs CP2112 HID USB to SMBus Master Bridge.
+ This is a HID device driver which registers as an i2c adapter
+ and gpiochip to expose these functions of the CP2112. The
+ customizable USB descriptor fields are exposed as sysfs attributes.
+
config HID_CYPRESS
tristate "Cypress mouse and barcode readers" if EXPERT
depends on HID
@@ -608,25 +617,27 @@ config HID_SAMSUNG
Support for Samsung InfraRed remote control or keyboards.
config HID_SONY
- tristate "Sony PS2/3 accessories"
+ tristate "Sony PS2/3/4 accessories"
depends on USB_HID
depends on NEW_LEDS
depends on LEDS_CLASS
+ select POWER_SUPPLY
---help---
Support for
* Sony PS3 6-axis controllers
+ * Sony PS4 DualShock 4 controllers
* Buzz controllers
* Sony PS3 Blue-ray Disk Remote Control (Bluetooth)
* Logitech Harmony adapter for Sony Playstation 3 (Bluetooth)
config SONY_FF
- bool "Sony PS2/3 accessories force feedback support"
+ bool "Sony PS2/3/4 accessories force feedback support"
depends on HID_SONY
select INPUT_FF_MEMLESS
---help---
- Say Y here if you have a Sony PS2/3 accessory and want to enable force
- feedback support for it.
+ Say Y here if you have a Sony PS2/3/4 accessory and want to enable
+ force feedback support for it.
config HID_SPEEDLINK
tristate "Speedlink VAD Cezanne mouse support"
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 30e44318f87f..fc712dde02a4 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
+obj-$(CONFIG_HID_CP2112) += hid-cp2112.o
obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o
obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 497558127bb3..f822fd2a1ada 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -469,6 +469,9 @@ static const struct hid_device_id apple_devices[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
+ USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 3bfac3accd22..9e8064205bc7 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1248,6 +1248,11 @@ void hid_output_report(struct hid_report *report, __u8 *data)
}
EXPORT_SYMBOL_GPL(hid_output_report);
+static int hid_report_len(struct hid_report *report)
+{
+ return ((report->size - 1) >> 3) + 1 + (report->id > 0) + 7;
+}
+
/*
* Allocator for buffer that is going to be passed to hid_output_report()
*/
@@ -1258,7 +1263,7 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags)
* of implement() working on 8 byte chunks
*/
- int len = ((report->size - 1) >> 3) + 1 + (report->id > 0) + 7;
+ int len = hid_report_len(report);
return kmalloc(len, flags);
}
@@ -1314,6 +1319,41 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
return report;
}
+/*
+ * Implement a generic .request() callback, using .raw_request()
+ * DO NOT USE in hid drivers directly, but through hid_hw_request instead.
+ */
+void __hid_request(struct hid_device *hid, struct hid_report *report,
+ int reqtype)
+{
+ char *buf;
+ int ret;
+ int len;
+
+ buf = hid_alloc_report_buf(report, GFP_KERNEL);
+ if (!buf)
+ return;
+
+ len = hid_report_len(report);
+
+ if (reqtype == HID_REQ_SET_REPORT)
+ hid_output_report(report, buf);
+
+ ret = hid->ll_driver->raw_request(hid, report->id, buf, len,
+ report->type, reqtype);
+ if (ret < 0) {
+ dbg_hid("unable to complete request: %d\n", ret);
+ goto out;
+ }
+
+ if (reqtype == HID_REQ_GET_REPORT)
+ hid_input_report(hid, report->type, buf, ret, 0);
+
+out:
+ kfree(buf);
+}
+EXPORT_SYMBOL_GPL(__hid_request);
+
int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
int interrupt)
{
@@ -1679,6 +1719,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
@@ -1692,6 +1733,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_CP2112) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) },
@@ -1779,6 +1821,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) },
@@ -2275,6 +2320,7 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT) },
{ HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_RISO_KAGAKU, USB_DEVICE_ID_RI_KA_WEBMAIL) },
{ }
};
@@ -2430,6 +2476,14 @@ int hid_add_device(struct hid_device *hdev)
return -ENODEV;
/*
+ * Check for the mandatory transport channel.
+ */
+ if (!hdev->ll_driver->raw_request) {
+ hid_err(hdev, "transport driver missing .raw_request()\n");
+ return -EINVAL;
+ }
+
+ /*
* Read the device report descriptor once and use as template
* for the driver-specific modifications.
*/
diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c
new file mode 100644
index 000000000000..56be85a9a77c
--- /dev/null
+++ b/drivers/hid/hid-cp2112.c
@@ -0,0 +1,1073 @@
+/*
+ * hid-cp2112.c - Silicon Labs HID USB to SMBus master bridge
+ * Copyright (c) 2013,2014 Uplogix, Inc.
+ * David Barksdale <dbarksdale@uplogix.com>
+ *
+ * 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.
+ */
+
+/*
+ * The Silicon Labs CP2112 chip is a USB HID device which provides an
+ * SMBus controller for talking to slave devices and 8 GPIO pins. The
+ * host communicates with the CP2112 via raw HID reports.
+ *
+ * Data Sheet:
+ * http://www.silabs.com/Support%20Documents/TechnicalDocs/CP2112.pdf
+ * Programming Interface Specification:
+ * http://www.silabs.com/Support%20Documents/TechnicalDocs/AN495.pdf
+ */
+
+#include <linux/gpio.h>
+#include <linux/hid.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/nls.h>
+#include <linux/usb/ch9.h>
+#include "hid-ids.h"
+
+enum {
+ CP2112_GPIO_CONFIG = 0x02,
+ CP2112_GPIO_GET = 0x03,
+ CP2112_GPIO_SET = 0x04,
+ CP2112_GET_VERSION_INFO = 0x05,
+ CP2112_SMBUS_CONFIG = 0x06,
+ CP2112_DATA_READ_REQUEST = 0x10,
+ CP2112_DATA_WRITE_READ_REQUEST = 0x11,
+ CP2112_DATA_READ_FORCE_SEND = 0x12,
+ CP2112_DATA_READ_RESPONSE = 0x13,
+ CP2112_DATA_WRITE_REQUEST = 0x14,
+ CP2112_TRANSFER_STATUS_REQUEST = 0x15,
+ CP2112_TRANSFER_STATUS_RESPONSE = 0x16,
+ CP2112_CANCEL_TRANSFER = 0x17,
+ CP2112_LOCK_BYTE = 0x20,
+ CP2112_USB_CONFIG = 0x21,
+ CP2112_MANUFACTURER_STRING = 0x22,
+ CP2112_PRODUCT_STRING = 0x23,
+ CP2112_SERIAL_STRING = 0x24,
+};
+
+enum {
+ STATUS0_IDLE = 0x00,
+ STATUS0_BUSY = 0x01,
+ STATUS0_COMPLETE = 0x02,
+ STATUS0_ERROR = 0x03,
+};
+
+enum {
+ STATUS1_TIMEOUT_NACK = 0x00,
+ STATUS1_TIMEOUT_BUS = 0x01,
+ STATUS1_ARBITRATION_LOST = 0x02,
+ STATUS1_READ_INCOMPLETE = 0x03,
+ STATUS1_WRITE_INCOMPLETE = 0x04,
+ STATUS1_SUCCESS = 0x05,
+};
+
+struct cp2112_smbus_config_report {
+ u8 report; /* CP2112_SMBUS_CONFIG */
+ __be32 clock_speed; /* Hz */
+ u8 device_address; /* Stored in the upper 7 bits */
+ u8 auto_send_read; /* 1 = enabled, 0 = disabled */
+ __be16 write_timeout; /* ms, 0 = no timeout */
+ __be16 read_timeout; /* ms, 0 = no timeout */
+ u8 scl_low_timeout; /* 1 = enabled, 0 = disabled */
+ __be16 retry_time; /* # of retries, 0 = no limit */
+} __packed;
+
+struct cp2112_usb_config_report {
+ u8 report; /* CP2112_USB_CONFIG */
+ __le16 vid; /* Vendor ID */
+ __le16 pid; /* Product ID */
+ u8 max_power; /* Power requested in 2mA units */
+ u8 power_mode; /* 0x00 = bus powered
+ 0x01 = self powered & regulator off
+ 0x02 = self powered & regulator on */
+ u8 release_major;
+ u8 release_minor;
+ u8 mask; /* What fields to program */
+} __packed;
+
+struct cp2112_read_req_report {
+ u8 report; /* CP2112_DATA_READ_REQUEST */
+ u8 slave_address;
+ __be16 length;
+} __packed;
+
+struct cp2112_write_read_req_report {
+ u8 report; /* CP2112_DATA_WRITE_READ_REQUEST */
+ u8 slave_address;
+ __be16 length;
+ u8 target_address_length;
+ u8 target_address[16];
+} __packed;
+
+struct cp2112_write_req_report {
+ u8 report; /* CP2112_DATA_WRITE_REQUEST */
+ u8 slave_address;
+ u8 length;
+ u8 data[61];
+} __packed;
+
+struct cp2112_force_read_report {
+ u8 report; /* CP2112_DATA_READ_FORCE_SEND */
+ __be16 length;
+} __packed;
+
+struct cp2112_xfer_status_report {
+ u8 report; /* CP2112_TRANSFER_STATUS_RESPONSE */
+ u8 status0; /* STATUS0_* */
+ u8 status1; /* STATUS1_* */
+ __be16 retries;
+ __be16 length;
+} __packed;
+
+struct cp2112_string_report {
+ u8 dummy; /* force .string to be aligned */
+ u8 report; /* CP2112_*_STRING */
+ u8 length; /* length in bytes of everyting after .report */
+ u8 type; /* USB_DT_STRING */
+ wchar_t string[30]; /* UTF16_LITTLE_ENDIAN string */
+} __packed;
+
+/* Number of times to request transfer status before giving up waiting for a
+ transfer to complete. This may need to be changed if SMBUS clock, retries,
+ or read/write/scl_low timeout settings are changed. */
+static const int XFER_STATUS_RETRIES = 10;
+
+/* Time in ms to wait for a CP2112_DATA_READ_RESPONSE or
+ CP2112_TRANSFER_STATUS_RESPONSE. */
+static const int RESPONSE_TIMEOUT = 50;
+
+static const struct hid_device_id cp2112_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_CP2112) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, cp2112_devices);
+
+struct cp2112_device {
+ struct i2c_adapter adap;
+ struct hid_device *hdev;
+ wait_queue_head_t wait;
+ u8 read_data[61];
+ u8 read_length;
+ int xfer_status;
+ atomic_t read_avail;
+ atomic_t xfer_avail;
+ struct gpio_chip gc;
+};
+
+static int gpio_push_pull = 0xFF;
+module_param(gpio_push_pull, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(gpio_push_pull, "GPIO push-pull configuration bitmask");
+
+static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct cp2112_device *dev = container_of(chip, struct cp2112_device,
+ gc);
+ struct hid_device *hdev = dev->hdev;
+ u8 buf[5];
+ int ret;
+
+ ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
+ sizeof(buf), HID_FEATURE_REPORT,
+ HID_REQ_GET_REPORT);
+ if (ret != sizeof(buf)) {
+ hid_err(hdev, "error requesting GPIO config: %d\n", ret);
+ return ret;
+ }
+
+ buf[1] &= ~(1 << offset);
+ buf[2] = gpio_push_pull;
+
+ ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, sizeof(buf),
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+ if (ret < 0) {
+ hid_err(hdev, "error setting GPIO config: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct cp2112_device *dev = container_of(chip, struct cp2112_device,
+ gc);
+ struct hid_device *hdev = dev->hdev;
+ u8 buf[3];
+ int ret;
+
+ buf[0] = CP2112_GPIO_SET;
+ buf[1] = value ? 0xff : 0;
+ buf[2] = 1 << offset;
+
+ ret = hid_hw_raw_request(hdev, CP2112_GPIO_SET, buf, sizeof(buf),
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+ if (ret < 0)
+ hid_err(hdev, "error setting GPIO values: %d\n", ret);
+}
+
+static int cp2112_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct cp2112_device *dev = container_of(chip, struct cp2112_device,
+ gc);
+ struct hid_device *hdev = dev->hdev;
+ u8 buf[2];
+ int ret;
+
+ ret = hid_hw_raw_request(hdev, CP2112_GPIO_GET, buf, sizeof(buf),
+ HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
+ if (ret != sizeof(buf)) {
+ hid_err(hdev, "error requesting GPIO values: %d\n", ret);
+ return ret;
+ }
+
+ return (buf[1] >> offset) & 1;
+}
+
+static int cp2112_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct cp2112_device *dev = container_of(chip, struct cp2112_device,
+ gc);
+ struct hid_device *hdev = dev->hdev;
+ u8 buf[5];
+ int ret;
+
+ cp2112_gpio_set(chip, offset, value);
+
+ ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
+ sizeof(buf), HID_FEATURE_REPORT,
+ HID_REQ_GET_REPORT);
+ if (ret != sizeof(buf)) {
+ hid_err(hdev, "error requesting GPIO config: %d\n", ret);
+ return ret;
+ }
+
+ buf[1] |= 1 << offset;
+ buf[2] = gpio_push_pull;
+
+ ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, sizeof(buf),
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+ if (ret < 0) {
+ hid_err(hdev, "error setting GPIO config: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cp2112_hid_get(struct hid_device *hdev, unsigned char report_number,
+ u8 *data, size_t count, unsigned char report_type)
+{
+ u8 *buf;
+ int ret;
+
+ buf = kmalloc(count, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = hid_hw_raw_request(hdev, report_number, buf, count,
+ report_type, HID_REQ_GET_REPORT);
+ memcpy(data, buf, count);
+ kfree(buf);
+ return ret;
+}
+
+static int cp2112_hid_output(struct hid_device *hdev, u8 *data, size_t count,
+ unsigned char report_type)
+{
+ u8 *buf;
+ int ret;
+
+ buf = kmemdup(data, count, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (report_type == HID_OUTPUT_REPORT)
+ ret = hid_hw_output_report(hdev, buf, count);
+ else
+ ret = hid_hw_raw_request(hdev, buf[0], buf, count, report_type,
+ HID_REQ_SET_REPORT);
+
+ kfree(buf);
+ return ret;
+}
+
+static int cp2112_wait(struct cp2112_device *dev, atomic_t *avail)
+{
+ int ret = 0;
+
+ /* We have sent either a CP2112_TRANSFER_STATUS_REQUEST or a
+ * CP2112_DATA_READ_FORCE_SEND and we are waiting for the response to
+ * come in cp2112_raw_event or timeout. There will only be one of these
+ * in flight at any one time. The timeout is extremely large and is a
+ * last resort if the CP2112 has died. If we do timeout we don't expect
+ * to receive the response which would cause data races, it's not like
+ * we can do anything about it anyway.
+ */
+ ret = wait_event_interruptible_timeout(dev->wait,
+ atomic_read(avail), msecs_to_jiffies(RESPONSE_TIMEOUT));
+ if (-ERESTARTSYS == ret)
+ return ret;
+ if (!ret)
+ return -ETIMEDOUT;
+
+ atomic_set(avail, 0);
+ return 0;
+}
+
+static int cp2112_xfer_status(struct cp2112_device *dev)
+{
+ struct hid_device *hdev = dev->hdev;
+ u8 buf[2];
+ int ret;
+
+ buf[0] = CP2112_TRANSFER_STATUS_REQUEST;
+ buf[1] = 0x01;
+ atomic_set(&dev->xfer_avail, 0);
+
+ ret = cp2112_hid_output(hdev, buf, 2, HID_OUTPUT_REPORT);
+ if (ret < 0) {
+ hid_warn(hdev, "Error requesting status: %d\n", ret);
+ return ret;
+ }
+
+ ret = cp2112_wait(dev, &dev->xfer_avail);
+ if (ret)
+ return ret;
+
+ return dev->xfer_status;
+}
+
+static int cp2112_read(struct cp2112_device *dev, u8 *data, size_t size)
+{
+ struct hid_device *hdev = dev->hdev;
+ struct cp2112_force_read_report report;
+ int ret;
+
+ report.report = CP2112_DATA_READ_FORCE_SEND;
+ report.length = cpu_to_be16(size);
+
+ atomic_set(&dev->read_avail, 0);
+
+ ret = cp2112_hid_output(hdev, &report.report, sizeof(report),
+ HID_OUTPUT_REPORT);
+ if (ret < 0) {
+ hid_warn(hdev, "Error requesting data: %d\n", ret);
+ return ret;
+ }
+
+ ret = cp2112_wait(dev, &dev->read_avail);
+ if (ret)
+ return ret;
+
+ hid_dbg(hdev, "read %d of %zd bytes requested\n",
+ dev->read_length, size);
+
+ if (size > dev->read_length)
+ size = dev->read_length;
+
+ memcpy(data, dev->read_data, size);
+ return dev->read_length;
+}
+
+static int cp2112_read_req(void *buf, u8 slave_address, u16 length)
+{
+ struct cp2112_read_req_report *report = buf;
+
+ if (length < 1 || length > 512)
+ return -EINVAL;
+
+ report->report = CP2112_DATA_READ_REQUEST;
+ report->slave_address = slave_address << 1;
+ report->length = cpu_to_be16(length);
+ return sizeof(*report);
+}
+
+static int cp2112_write_read_req(void *buf, u8 slave_address, u16 length,
+ u8 command, u8 *data, u8 data_length)
+{
+ struct cp2112_write_read_req_report *report = buf;
+
+ if (length < 1 || length > 512
+ || data_length > sizeof(report->target_address) - 1)
+ return -EINVAL;
+
+ report->report = CP2112_DATA_WRITE_READ_REQUEST;
+ report->slave_address = slave_address << 1;
+ report->length = cpu_to_be16(length);
+ report->target_address_length = data_length + 1;
+ report->target_address[0] = command;
+ memcpy(&report->target_address[1], data, data_length);
+ return data_length + 6;
+}
+
+static int cp2112_write_req(void *buf, u8 slave_address, u8 command, u8 *data,
+ u8 data_length)
+{
+ struct cp2112_write_req_report *report = buf;
+
+ if (data_length > sizeof(report->data) - 1)
+ return -EINVAL;
+
+ report->report = CP2112_DATA_WRITE_REQUEST;
+ report->slave_address = slave_address << 1;
+ report->length = data_length + 1;
+ report->data[0] = command;
+ memcpy(&report->data[1], data, data_length);
+ return data_length + 4;
+}
+
+static int cp2112_xfer(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ struct cp2112_device *dev = (struct cp2112_device *)adap->algo_data;
+ struct hid_device *hdev = dev->hdev;
+ u8 buf[64];
+ __be16 word;
+ ssize_t count;
+ size_t read_length = 0;
+ unsigned int retries;
+ int ret;
+
+ hid_dbg(hdev, "%s addr 0x%x flags 0x%x cmd 0x%x size %d\n",
+ read_write == I2C_SMBUS_WRITE ? "write" : "read",
+ addr, flags, command, size);
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ read_length = 1;
+
+ if (I2C_SMBUS_READ == read_write)
+ count = cp2112_read_req(buf, addr, read_length);
+ else
+ count = cp2112_write_req(buf, addr, data->byte, NULL,
+ 0);
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ read_length = 1;
+
+ if (I2C_SMBUS_READ == read_write)
+ count = cp2112_write_read_req(buf, addr, read_length,
+ command, NULL, 0);
+ else
+ count = cp2112_write_req(buf, addr, command,
+ &data->byte, 1);
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ read_length = 2;
+ word = cpu_to_be16(data->word);
+
+ if (I2C_SMBUS_READ == read_write)
+ count = cp2112_write_read_req(buf, addr, read_length,
+ command, NULL, 0);
+ else
+ count = cp2112_write_req(buf, addr, command,
+ (u8 *)&word, 2);
+ break;
+ case I2C_SMBUS_PROC_CALL:
+ size = I2C_SMBUS_WORD_DATA;
+ read_write = I2C_SMBUS_READ;
+ read_length = 2;
+ word = cpu_to_be16(data->word);
+
+ count = cp2112_write_read_req(buf, addr, read_length, command,
+ (u8 *)&word, 2);
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ size = I2C_SMBUS_BLOCK_DATA;
+ /* fallthrough */
+ case I2C_SMBUS_BLOCK_DATA:
+ if (I2C_SMBUS_READ == read_write) {
+ count = cp2112_write_read_req(buf, addr,
+ I2C_SMBUS_BLOCK_MAX,
+ command, NULL, 0);
+ } else {
+ count = cp2112_write_req(buf, addr, command,
+ data->block,
+ data->block[0] + 1);
+ }
+ break;
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ size = I2C_SMBUS_BLOCK_DATA;
+ read_write = I2C_SMBUS_READ;
+
+ count = cp2112_write_read_req(buf, addr, I2C_SMBUS_BLOCK_MAX,
+ command, data->block,
+ data->block[0] + 1);
+ break;
+ default:
+ hid_warn(hdev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ if (count < 0)
+ return count;
+
+ ret = hid_hw_power(hdev, PM_HINT_FULLON);
+ if (ret < 0) {
+ hid_err(hdev, "power management error: %d\n", ret);
+ return ret;
+ }
+
+ ret = cp2112_hid_output(hdev, buf, count, HID_OUTPUT_REPORT);
+ if (ret < 0) {
+ hid_warn(hdev, "Error starting transaction: %d\n", ret);
+ goto power_normal;
+ }
+
+ for (retries = 0; retries < XFER_STATUS_RETRIES; ++retries) {
+ ret = cp2112_xfer_status(dev);
+ if (-EBUSY == ret)
+ continue;
+ if (ret < 0)
+ goto power_normal;
+ break;
+ }
+
+ if (XFER_STATUS_RETRIES <= retries) {
+ hid_warn(hdev, "Transfer timed out, cancelling.\n");
+ buf[0] = CP2112_CANCEL_TRANSFER;
+ buf[1] = 0x01;
+
+ ret = cp2112_hid_output(hdev, buf, 2, HID_OUTPUT_REPORT);
+ if (ret < 0)
+ hid_warn(hdev, "Error cancelling transaction: %d\n",
+ ret);
+
+ ret = -ETIMEDOUT;
+ goto power_normal;
+ }
+
+ if (I2C_SMBUS_WRITE == read_write) {
+ ret = 0;
+ goto power_normal;
+ }
+
+ if (I2C_SMBUS_BLOCK_DATA == size)
+ read_length = ret;
+
+ ret = cp2112_read(dev, buf, read_length);
+ if (ret < 0)
+ goto power_normal;
+ if (ret != read_length) {
+ hid_warn(hdev, "short read: %d < %zd\n", ret, read_length);
+ ret = -EIO;
+ goto power_normal;
+ }
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ data->byte = buf[0];
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ data->word = be16_to_cpup((__be16 *)buf);
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ if (read_length > I2C_SMBUS_BLOCK_MAX) {
+ ret = -EPROTO;
+ goto power_normal;
+ }
+
+ memcpy(data->block, buf, read_length);
+ break;
+ }
+
+ ret = 0;
+power_normal:
+ hid_hw_power(hdev, PM_HINT_NORMAL);
+ hid_dbg(hdev, "transfer finished: %d\n", ret);
+ return ret;
+}
+
+static u32 cp2112_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK |
+ I2C_FUNC_SMBUS_PROC_CALL |
+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = cp2112_xfer,
+ .functionality = cp2112_functionality,
+};
+
+static int cp2112_get_usb_config(struct hid_device *hdev,
+ struct cp2112_usb_config_report *cfg)
+{
+ int ret;
+
+ ret = cp2112_hid_get(hdev, CP2112_USB_CONFIG, (u8 *)cfg, sizeof(*cfg),
+ HID_FEATURE_REPORT);
+ if (ret != sizeof(*cfg)) {
+ hid_err(hdev, "error reading usb config: %d\n", ret);
+ if (ret < 0)
+ return ret;
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int cp2112_set_usb_config(struct hid_device *hdev,
+ struct cp2112_usb_config_report *cfg)
+{
+ int ret;
+
+ BUG_ON(cfg->report != CP2112_USB_CONFIG);
+
+ ret = cp2112_hid_output(hdev, (u8 *)cfg, sizeof(*cfg),
+ HID_FEATURE_REPORT);
+ if (ret != sizeof(*cfg)) {
+ hid_err(hdev, "error writing usb config: %d\n", ret);
+ if (ret < 0)
+ return ret;
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void chmod_sysfs_attrs(struct hid_device *hdev);
+
+#define CP2112_CONFIG_ATTR(name, store, format, ...) \
+static ssize_t name##_store(struct device *kdev, \
+ struct device_attribute *attr, const char *buf, \
+ size_t count) \
+{ \
+ struct hid_device *hdev = container_of(kdev, struct hid_device, dev); \
+ struct cp2112_usb_config_report cfg; \
+ int ret = cp2112_get_usb_config(hdev, &cfg); \
+ if (ret) \
+ return ret; \
+ store; \
+ ret = cp2112_set_usb_config(hdev, &cfg); \
+ if (ret) \
+ return ret; \
+ chmod_sysfs_attrs(hdev); \
+ return count; \
+} \
+static ssize_t name##_show(struct device *kdev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct hid_device *hdev = container_of(kdev, struct hid_device, dev); \
+ struct cp2112_usb_config_report cfg; \
+ int ret = cp2112_get_usb_config(hdev, &cfg); \
+ if (ret) \
+ return ret; \
+ return scnprintf(buf, PAGE_SIZE, format, ##__VA_ARGS__); \
+} \
+static DEVICE_ATTR_RW(name);
+
+CP2112_CONFIG_ATTR(vendor_id, ({
+ u16 vid;
+
+ if (sscanf(buf, "%hi", &vid) != 1)
+ return -EINVAL;
+
+ cfg.vid = cpu_to_le16(vid);
+ cfg.mask = 0x01;
+}), "0x%04x\n", le16_to_cpu(cfg.vid));
+
+CP2112_CONFIG_ATTR(product_id, ({
+ u16 pid;
+
+ if (sscanf(buf, "%hi", &pid) != 1)
+ return -EINVAL;
+
+ cfg.pid = cpu_to_le16(pid);
+ cfg.mask = 0x02;
+}), "0x%04x\n", le16_to_cpu(cfg.pid));
+
+CP2112_CONFIG_ATTR(max_power, ({
+ int mA;
+
+ if (sscanf(buf, "%i", &mA) != 1)
+ return -EINVAL;
+
+ cfg.max_power = (mA + 1) / 2;
+ cfg.mask = 0x04;
+}), "%u mA\n", cfg.max_power * 2);
+
+CP2112_CONFIG_ATTR(power_mode, ({
+ if (sscanf(buf, "%hhi", &cfg.power_mode) != 1)
+ return -EINVAL;
+
+ cfg.mask = 0x08;
+}), "%u\n", cfg.power_mode);
+
+CP2112_CONFIG_ATTR(release_version, ({
+ if (sscanf(buf, "%hhi.%hhi", &cfg.release_major, &cfg.release_minor)
+ != 2)
+ return -EINVAL;
+
+ cfg.mask = 0x10;
+}), "%u.%u\n", cfg.release_major, cfg.release_minor);
+
+#undef CP2112_CONFIG_ATTR
+
+struct cp2112_pstring_attribute {
+ struct device_attribute attr;
+ unsigned char report;
+};
+
+static ssize_t pstr_store(struct device *kdev,
+ struct device_attribute *kattr, const char *buf,
+ size_t count)
+{
+ struct hid_device *hdev = container_of(kdev, struct hid_device, dev);
+ struct cp2112_pstring_attribute *attr =
+ container_of(kattr, struct cp2112_pstring_attribute, attr);
+ struct cp2112_string_report report;
+ int ret;
+
+ memset(&report, 0, sizeof(report));
+
+ ret = utf8s_to_utf16s(buf, count, UTF16_LITTLE_ENDIAN,
+ report.string, ARRAY_SIZE(report.string));
+ report.report = attr->report;
+ report.length = ret * sizeof(report.string[0]) + 2;
+ report.type = USB_DT_STRING;
+
+ ret = cp2112_hid_output(hdev, &report.report, report.length + 1,
+ HID_FEATURE_REPORT);
+ if (ret != report.length + 1) {
+ hid_err(hdev, "error writing %s string: %d\n", kattr->attr.name,
+ ret);
+ if (ret < 0)
+ return ret;
+ return -EIO;
+ }
+
+ chmod_sysfs_attrs(hdev);
+ return count;
+}
+
+static ssize_t pstr_show(struct device *kdev,
+ struct device_attribute *kattr, char *buf)
+{
+ struct hid_device *hdev = container_of(kdev, struct hid_device, dev);
+ struct cp2112_pstring_attribute *attr =
+ container_of(kattr, struct cp2112_pstring_attribute, attr);
+ struct cp2112_string_report report;
+ u8 length;
+ int ret;
+
+ ret = cp2112_hid_get(hdev, attr->report, &report.report,
+ sizeof(report) - 1, HID_FEATURE_REPORT);
+ if (ret < 3) {
+ hid_err(hdev, "error reading %s string: %d\n", kattr->attr.name,
+ ret);
+ if (ret < 0)
+ return ret;
+ return -EIO;
+ }
+
+ if (report.length < 2) {
+ hid_err(hdev, "invalid %s string length: %d\n",
+ kattr->attr.name, report.length);
+ return -EIO;
+ }
+
+ length = report.length > ret - 1 ? ret - 1 : report.length;
+ length = (length - 2) / sizeof(report.string[0]);
+ ret = utf16s_to_utf8s(report.string, length, UTF16_LITTLE_ENDIAN, buf,
+ PAGE_SIZE - 1);
+ buf[ret++] = '\n';
+ return ret;
+}
+
+#define CP2112_PSTR_ATTR(name, _report) \
+static struct cp2112_pstring_attribute dev_attr_##name = { \
+ .attr = __ATTR(name, (S_IWUSR | S_IRUGO), pstr_show, pstr_store), \
+ .report = _report, \
+};
+
+CP2112_PSTR_ATTR(manufacturer, CP2112_MANUFACTURER_STRING);
+CP2112_PSTR_ATTR(product, CP2112_PRODUCT_STRING);
+CP2112_PSTR_ATTR(serial, CP2112_SERIAL_STRING);
+
+#undef CP2112_PSTR_ATTR
+
+static const struct attribute_group cp2112_attr_group = {
+ .attrs = (struct attribute *[]){
+ &dev_attr_vendor_id.attr,
+ &dev_attr_product_id.attr,
+ &dev_attr_max_power.attr,
+ &dev_attr_power_mode.attr,
+ &dev_attr_release_version.attr,
+ &dev_attr_manufacturer.attr.attr,
+ &dev_attr_product.attr.attr,
+ &dev_attr_serial.attr.attr,
+ NULL
+ }
+};
+
+/* Chmoding our sysfs attributes is simply a way to expose which fields in the
+ * PROM have already been programmed. We do not depend on this preventing
+ * writing to these attributes since the CP2112 will simply ignore writes to
+ * already-programmed fields. This is why there is no sense in fixing this
+ * racy behaviour.
+ */
+static void chmod_sysfs_attrs(struct hid_device *hdev)
+{
+ struct attribute **attr;
+ u8 buf[2];
+ int ret;
+
+ ret = cp2112_hid_get(hdev, CP2112_LOCK_BYTE, buf, sizeof(buf),
+ HID_FEATURE_REPORT);
+ if (ret != sizeof(buf)) {
+ hid_err(hdev, "error reading lock byte: %d\n", ret);
+ return;
+ }
+
+ for (attr = cp2112_attr_group.attrs; *attr; ++attr) {
+ umode_t mode = (buf[1] & 1) ? S_IWUSR | S_IRUGO : S_IRUGO;
+ ret = sysfs_chmod_file(&hdev->dev.kobj, *attr, mode);
+ if (ret < 0)
+ hid_err(hdev, "error chmoding sysfs file %s\n",
+ (*attr)->name);
+ buf[1] >>= 1;
+ }
+}
+
+static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ struct cp2112_device *dev;
+ u8 buf[3];
+ struct cp2112_smbus_config_report config;
+ int ret;
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "parse failed\n");
+ return ret;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
+ if (ret) {
+ hid_err(hdev, "hw start failed\n");
+ return ret;
+ }
+
+ ret = hid_hw_open(hdev);
+ if (ret) {
+ hid_err(hdev, "hw open failed\n");
+ goto err_hid_stop;
+ }
+
+ ret = hid_hw_power(hdev, PM_HINT_FULLON);
+ if (ret < 0) {
+ hid_err(hdev, "power management error: %d\n", ret);
+ goto err_hid_close;
+ }
+
+ ret = cp2112_hid_get(hdev, CP2112_GET_VERSION_INFO, buf, sizeof(buf),
+ HID_FEATURE_REPORT);
+ if (ret != sizeof(buf)) {
+ hid_err(hdev, "error requesting version\n");
+ if (ret >= 0)
+ ret = -EIO;
+ goto err_power_normal;
+ }
+
+ hid_info(hdev, "Part Number: 0x%02X Device Version: 0x%02X\n",
+ buf[1], buf[2]);
+
+ ret = cp2112_hid_get(hdev, CP2112_SMBUS_CONFIG, (u8 *)&config,
+ sizeof(config), HID_FEATURE_REPORT);
+ if (ret != sizeof(config)) {
+ hid_err(hdev, "error requesting SMBus config\n");
+ if (ret >= 0)
+ ret = -EIO;
+ goto err_power_normal;
+ }
+
+ config.retry_time = cpu_to_be16(1);
+
+ ret = cp2112_hid_output(hdev, (u8 *)&config, sizeof(config),
+ HID_FEATURE_REPORT);
+ if (ret != sizeof(config)) {
+ hid_err(hdev, "error setting SMBus config\n");
+ if (ret >= 0)
+ ret = -EIO;
+ goto err_power_normal;
+ }
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ ret = -ENOMEM;
+ goto err_power_normal;
+ }
+
+ hid_set_drvdata(hdev, (void *)dev);
+ dev->hdev = hdev;
+ dev->adap.owner = THIS_MODULE;
+ dev->adap.class = I2C_CLASS_HWMON;
+ dev->adap.algo = &smbus_algorithm;
+ dev->adap.algo_data = dev;
+ dev->adap.dev.parent = &hdev->dev;
+ snprintf(dev->adap.name, sizeof(dev->adap.name),
+ "CP2112 SMBus Bridge on hiddev%d", hdev->minor);
+ init_waitqueue_head(&dev->wait);
+
+ hid_device_io_start(hdev);
+ ret = i2c_add_adapter(&dev->adap);
+ hid_device_io_stop(hdev);
+
+ if (ret) {
+ hid_err(hdev, "error registering i2c adapter\n");
+ goto err_free_dev;
+ }
+
+ hid_dbg(hdev, "adapter registered\n");
+
+ dev->gc.label = "cp2112_gpio";
+ dev->gc.direction_input = cp2112_gpio_direction_input;
+ dev->gc.direction_output = cp2112_gpio_direction_output;
+ dev->gc.set = cp2112_gpio_set;
+ dev->gc.get = cp2112_gpio_get;
+ dev->gc.base = -1;
+ dev->gc.ngpio = 8;
+ dev->gc.can_sleep = 1;
+ dev->gc.dev = &hdev->dev;
+
+ ret = gpiochip_add(&dev->gc);
+ if (ret < 0) {
+ hid_err(hdev, "error registering gpio chip\n");
+ goto err_free_i2c;
+ }
+
+ ret = sysfs_create_group(&hdev->dev.kobj, &cp2112_attr_group);
+ if (ret < 0) {
+ hid_err(hdev, "error creating sysfs attrs\n");
+ goto err_gpiochip_remove;
+ }
+
+ chmod_sysfs_attrs(hdev);
+ hid_hw_power(hdev, PM_HINT_NORMAL);
+
+ return ret;
+
+err_gpiochip_remove:
+ if (gpiochip_remove(&dev->gc) < 0)
+ hid_err(hdev, "error removing gpio chip\n");
+err_free_i2c:
+ i2c_del_adapter(&dev->adap);
+err_free_dev:
+ kfree(dev);
+err_power_normal:
+ hid_hw_power(hdev, PM_HINT_NORMAL);
+err_hid_close:
+ hid_hw_close(hdev);
+err_hid_stop:
+ hid_hw_stop(hdev);
+ return ret;
+}
+
+static void cp2112_remove(struct hid_device *hdev)
+{
+ struct cp2112_device *dev = hid_get_drvdata(hdev);
+
+ sysfs_remove_group(&hdev->dev.kobj, &cp2112_attr_group);
+ if (gpiochip_remove(&dev->gc))
+ hid_err(hdev, "unable to remove gpio chip\n");
+ i2c_del_adapter(&dev->adap);
+ /* i2c_del_adapter has finished removing all i2c devices from our
+ * adapter. Well behaved devices should no longer call our cp2112_xfer
+ * and should have waited for any pending calls to finish. It has also
+ * waited for device_unregister(&adap->dev) to complete. Therefore we
+ * can safely free our struct cp2112_device.
+ */
+ hid_hw_close(hdev);
+ hid_hw_stop(hdev);
+ kfree(dev);
+}
+
+static int cp2112_raw_event(struct hid_device *hdev, struct hid_report *report,
+ u8 *data, int size)
+{
+ struct cp2112_device *dev = hid_get_drvdata(hdev);
+ struct cp2112_xfer_status_report *xfer = (void *)data;
+
+ switch (data[0]) {
+ case CP2112_TRANSFER_STATUS_RESPONSE:
+ hid_dbg(hdev, "xfer status: %02x %02x %04x %04x\n",
+ xfer->status0, xfer->status1,
+ be16_to_cpu(xfer->retries), be16_to_cpu(xfer->length));
+
+ switch (xfer->status0) {
+ case STATUS0_IDLE:
+ dev->xfer_status = -EAGAIN;
+ break;
+ case STATUS0_BUSY:
+ dev->xfer_status = -EBUSY;
+ break;
+ case STATUS0_COMPLETE:
+ dev->xfer_status = be16_to_cpu(xfer->length);
+ break;
+ case STATUS0_ERROR:
+ switch (xfer->status1) {
+ case STATUS1_TIMEOUT_NACK:
+ case STATUS1_TIMEOUT_BUS:
+ dev->xfer_status = -ETIMEDOUT;
+ break;
+ default:
+ dev->xfer_status = -EIO;
+ break;
+ }
+ break;
+ default:
+ dev->xfer_status = -EINVAL;
+ break;
+ }
+
+ atomic_set(&dev->xfer_avail, 1);
+ break;
+ case CP2112_DATA_READ_RESPONSE:
+ hid_dbg(hdev, "read response: %02x %02x\n", data[1], data[2]);
+
+ dev->read_length = data[2];
+ if (dev->read_length > sizeof(dev->read_data))
+ dev->read_length = sizeof(dev->read_data);
+
+ memcpy(dev->read_data, &data[3], dev->read_length);
+ atomic_set(&dev->read_avail, 1);
+ break;
+ default:
+ hid_err(hdev, "unknown report\n");
+
+ return 0;
+ }
+
+ wake_up_interruptible(&dev->wait);
+ return 1;
+}
+
+static struct hid_driver cp2112_driver = {
+ .name = "cp2112",
+ .id_table = cp2112_devices,
+ .probe = cp2112_probe,
+ .remove = cp2112_remove,
+ .raw_event = cp2112_raw_event,
+};
+
+module_hid_driver(cp2112_driver);
+MODULE_DESCRIPTION("Silicon Labs HID USB to SMBus master bridge");
+MODULE_AUTHOR("David Barksdale <dbarksdale@uplogix.com>");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index 8fae6d1414cc..f52dbcb7133b 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -157,6 +157,7 @@ struct mousevsc_dev {
u32 report_desc_size;
struct hv_input_dev_info hid_dev_info;
struct hid_device *hid_device;
+ u8 input_buf[HID_MAX_BUFFER_SIZE];
};
@@ -256,6 +257,7 @@ static void mousevsc_on_receive(struct hv_device *device,
struct synthhid_msg *hid_msg;
struct mousevsc_dev *input_dev = hv_get_drvdata(device);
struct synthhid_input_report *input_report;
+ size_t len;
pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
(packet->offset8 << 3));
@@ -300,9 +302,12 @@ static void mousevsc_on_receive(struct hv_device *device,
(struct synthhid_input_report *)pipe_msg->data;
if (!input_dev->init_complete)
break;
- hid_input_report(input_dev->hid_device,
- HID_INPUT_REPORT, input_report->buffer,
- input_report->header.size, 1);
+
+ len = min(input_report->header.size,
+ (u32)sizeof(input_dev->input_buf));
+ memcpy(input_dev->input_buf, input_report->buffer, len);
+ hid_input_report(input_dev->hid_device, HID_INPUT_REPORT,
+ input_dev->input_buf, len, 1);
break;
default:
pr_err("unsupported hid msg type - type %d len %d",
@@ -455,12 +460,22 @@ static void mousevsc_hid_stop(struct hid_device *hid)
{
}
+static int mousevsc_hid_raw_request(struct hid_device *hid,
+ unsigned char report_num,
+ __u8 *buf, size_t len,
+ unsigned char rtype,
+ int reqtype)
+{
+ return 0;
+}
+
static struct hid_ll_driver mousevsc_ll_driver = {
.parse = mousevsc_hid_parse,
.open = mousevsc_hid_open,
.close = mousevsc_hid_close,
.start = mousevsc_hid_start,
.stop = mousevsc_hid_stop,
+ .raw_request = mousevsc_hid_raw_request,
};
static struct hid_driver mousevsc_hid_driver;
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 5a5248f2cc07..bd221263c739 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -67,6 +67,9 @@
#define USB_VENDOR_ID_ALPS 0x0433
#define USB_DEVICE_ID_IBM_GAMEPAD 0x1101
+#define USB_VENDOR_ID_ANTON 0x1130
+#define USB_DEVICE_ID_ANTON_TOUCH_PAD 0x3101
+
#define USB_VENDOR_ID_APPLE 0x05ac
#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304
#define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d
@@ -135,6 +138,7 @@
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI 0x0255
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO 0x0256
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS 0x0257
#define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI 0x0290
#define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0291
#define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0292
@@ -240,6 +244,8 @@
#define USB_VENDOR_ID_CYGNAL 0x10c4
#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a
+#define USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH 0x81b9
+#define USB_DEVICE_ID_CYGNAL_CP2112 0xea90
#define USB_DEVICE_ID_CYGNAL_RADIO_SI4713 0x8244
@@ -451,6 +457,9 @@
#define USB_VENDOR_ID_INTEL_1 0x8087
#define USB_DEVICE_ID_INTEL_HID_SENSOR 0x09fa
+#define USB_VENDOR_ID_STM_0 0x0483
+#define USB_DEVICE_ID_STM_HID_SENSOR 0x91d1
+
#define USB_VENDOR_ID_ION 0x15e4
#define USB_DEVICE_ID_ICADE 0x0132
@@ -611,6 +620,7 @@
#define USB_VENDOR_ID_MICROSOFT 0x045e
#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b
+#define USB_DEVICE_ID_MS_OFFICE_KB 0x0048
#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
#define USB_DEVICE_ID_MS_NE4K 0x00db
#define USB_DEVICE_ID_MS_NE4K_JP 0x00dc
@@ -619,6 +629,8 @@
#define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713
#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K 0x0730
#define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500 0x076c
+#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7
+#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9
#define USB_VENDOR_ID_MOJO 0x8282
#define USB_DEVICE_ID_RETRO_ADAPTER 0x3201
@@ -644,6 +656,7 @@
#define USB_VENDOR_ID_NEXIO 0x1870
#define USB_DEVICE_ID_NEXIO_MULTITOUCH_420 0x010d
+#define USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750 0x0110
#define USB_VENDOR_ID_NEXTWINDOW 0x1926
#define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN 0x0003
@@ -953,4 +966,7 @@
#define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05
+#define USB_VENDOR_ID_RISO_KAGAKU 0x1294 /* Riso Kagaku Corp. */
+#define USB_DEVICE_ID_RI_KA_WEBMAIL 0x1320 /* Webmail Notifier */
+
#endif
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index d50e7313b171..e7e8b19a9284 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -350,9 +350,9 @@ static int hidinput_get_battery_property(struct power_supply *psy,
ret = -ENOMEM;
break;
}
- ret = dev->hid_get_raw_report(dev, dev->battery_report_id,
- buf, 2,
- dev->battery_report_type);
+ ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 2,
+ dev->battery_report_type,
+ HID_REQ_GET_REPORT);
if (ret != 2) {
ret = -ENODATA;
@@ -789,10 +789,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x199: map_key_clear(KEY_CHAT); break;
case 0x19c: map_key_clear(KEY_LOGOFF); break;
case 0x19e: map_key_clear(KEY_COFFEE); break;
+ case 0x1a3: map_key_clear(KEY_NEXT); break;
+ case 0x1a4: map_key_clear(KEY_PREVIOUS); break;
case 0x1a6: map_key_clear(KEY_HELP); break;
case 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
case 0x1ab: map_key_clear(KEY_SPELLCHECK); break;
case 0x1ae: map_key_clear(KEY_KEYBOARD); break;
+ case 0x1b4: map_key_clear(KEY_FILE); break;
case 0x1b6: map_key_clear(KEY_IMAGES); break;
case 0x1b7: map_key_clear(KEY_AUDIO); break;
case 0x1b8: map_key_clear(KEY_VIDEO); break;
@@ -1150,7 +1153,7 @@ static void hidinput_led_worker(struct work_struct *work)
led_work);
struct hid_field *field;
struct hid_report *report;
- int len;
+ int len, ret;
__u8 *buf;
field = hidinput_get_led_field(hid);
@@ -1178,13 +1181,16 @@ static void hidinput_led_worker(struct work_struct *work)
/* fall back to generic raw-output-report */
len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
- buf = kmalloc(len, GFP_KERNEL);
+ buf = hid_alloc_report_buf(report, GFP_KERNEL);
if (!buf)
return;
hid_output_report(report, buf);
/* synchronous output report */
- hid->hid_output_raw_report(hid, buf, len, HID_OUTPUT_REPORT);
+ ret = hid_hw_output_report(hid, buf, len);
+ if (ret == -ENOSYS)
+ hid_hw_raw_request(hid, report->id, buf, len, HID_OUTPUT_REPORT,
+ HID_REQ_SET_REPORT);
kfree(buf);
}
@@ -1263,10 +1269,7 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid)
}
input_set_drvdata(input_dev, hid);
- if (hid->ll_driver->hidinput_input_event)
- input_dev->event = hid->ll_driver->hidinput_input_event;
- else if (hid->ll_driver->request || hid->hid_output_raw_report)
- input_dev->event = hidinput_input_event;
+ input_dev->event = hidinput_input_event;
input_dev->open = hidinput_open;
input_dev->close = hidinput_close;
input_dev->setkeycode = hidinput_setkeycode;
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index 9fe9d4ac3114..a976f48263f6 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -692,7 +692,8 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
- ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret >= 0) {
/* insert a little delay of 10 jiffies ~ 40ms */
@@ -704,7 +705,8 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
buf[1] = 0xB2;
get_random_bytes(&buf[2], 2);
- ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
}
}
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index befe0e336471..24883b4d1a49 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -43,6 +43,7 @@
#define G25_REV_MIN 0x22
#define G27_REV_MAJ 0x12
#define G27_REV_MIN 0x38
+#define G27_2_REV_MIN 0x39
#define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
@@ -130,6 +131,7 @@ static const struct lg4ff_usb_revision lg4ff_revs[] = {
{DFP_REV_MAJ, DFP_REV_MIN, &native_dfp}, /* Driving Force Pro */
{G25_REV_MAJ, G25_REV_MIN, &native_g25}, /* G25 */
{G27_REV_MAJ, G27_REV_MIN, &native_g27}, /* G27 */
+ {G27_REV_MAJ, G27_2_REV_MIN, &native_g27}, /* G27 v2 */
};
/* Recalculates X axis value accordingly to currently selected range */
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index f45279c3b11a..486dbde2ba2d 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -44,14 +44,6 @@ static const char kbd_descriptor[] = {
0x19, 0xE0, /* USAGE_MINIMUM (Left Control) */
0x29, 0xE7, /* USAGE_MAXIMUM (Right GUI) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */
- 0x95, 0x05, /* REPORT COUNT (5) */
- 0x05, 0x08, /* USAGE PAGE (LED page) */
- 0x19, 0x01, /* USAGE MINIMUM (1) */
- 0x29, 0x05, /* USAGE MAXIMUM (5) */
- 0x91, 0x02, /* OUTPUT (Data, Variable, Absolute) */
- 0x95, 0x01, /* REPORT COUNT (1) */
- 0x75, 0x03, /* REPORT SIZE (3) */
- 0x91, 0x01, /* OUTPUT (Constant) */
0x95, 0x06, /* REPORT_COUNT (6) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
@@ -60,6 +52,18 @@ static const char kbd_descriptor[] = {
0x19, 0x00, /* USAGE_MINIMUM (no event) */
0x2A, 0xFF, 0x00, /* USAGE_MAXIMUM (reserved) */
0x81, 0x00, /* INPUT (Data,Ary,Abs) */
+ 0x85, 0x0e, /* REPORT_ID (14) */
+ 0x05, 0x08, /* USAGE PAGE (LED page) */
+ 0x95, 0x05, /* REPORT COUNT (5) */
+ 0x75, 0x01, /* REPORT SIZE (1) */
+ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
+ 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
+ 0x19, 0x01, /* USAGE MINIMUM (1) */
+ 0x29, 0x05, /* USAGE MAXIMUM (5) */
+ 0x91, 0x02, /* OUTPUT (Data, Variable, Absolute) */
+ 0x95, 0x01, /* REPORT COUNT (1) */
+ 0x75, 0x03, /* REPORT SIZE (3) */
+ 0x91, 0x01, /* OUTPUT (Constant) */
0xC0
};
@@ -189,9 +193,6 @@ static const u8 hid_reportid_size_map[NUMBER_OF_HID_REPORTS] = {
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,
@@ -258,7 +259,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
}
dj_hiddev->ll_driver = &logi_dj_ll_driver;
- dj_hiddev->hid_output_raw_report = logi_dj_output_hidraw_report;
dj_hiddev->dev.parent = &djrcv_hdev->dev;
dj_hiddev->bus = BUS_USB;
@@ -540,14 +540,35 @@ static void logi_dj_ll_close(struct hid_device *hid)
dbg_hid("%s:%s\n", __func__, hid->phys);
}
-static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
- size_t count,
- unsigned char report_type)
+static int logi_dj_ll_raw_request(struct hid_device *hid,
+ unsigned char reportnum, __u8 *buf,
+ size_t count, unsigned char report_type,
+ int reqtype)
{
- /* Called by hid raw to send data */
- dbg_hid("%s\n", __func__);
+ struct dj_device *djdev = hid->driver_data;
+ struct dj_receiver_dev *djrcv_dev = djdev->dj_receiver_dev;
+ u8 *out_buf;
+ int ret;
- return 0;
+ if (buf[0] != REPORT_TYPE_LEDS)
+ return -EINVAL;
+
+ out_buf = kzalloc(DJREPORT_SHORT_LENGTH, GFP_ATOMIC);
+ if (!out_buf)
+ return -ENOMEM;
+
+ if (count < DJREPORT_SHORT_LENGTH - 2)
+ count = DJREPORT_SHORT_LENGTH - 2;
+
+ out_buf[0] = REPORT_ID_DJ_SHORT;
+ out_buf[1] = djdev->device_index;
+ memcpy(out_buf + 2, buf, count);
+
+ ret = hid_hw_raw_request(djrcv_dev->hdev, out_buf[0], out_buf,
+ DJREPORT_SHORT_LENGTH, report_type, reqtype);
+
+ kfree(out_buf);
+ return ret;
}
static void rdcat(char *rdesc, unsigned int *rsize, const char *data, unsigned int size)
@@ -613,58 +634,6 @@ static int logi_dj_ll_parse(struct hid_device *hid)
return retval;
}
-static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
- unsigned int code, int value)
-{
- /* Sent by the input layer to handle leds and Force Feedback */
- struct hid_device *dj_hiddev = input_get_drvdata(dev);
- struct dj_device *dj_dev = dj_hiddev->driver_data;
-
- struct dj_receiver_dev *djrcv_dev =
- dev_get_drvdata(dj_hiddev->dev.parent);
- struct hid_device *dj_rcv_hiddev = djrcv_dev->hdev;
- struct hid_report_enum *output_report_enum;
-
- struct hid_field *field;
- struct hid_report *report;
- unsigned char *data;
- int offset;
-
- dbg_hid("%s: %s, type:%d | code:%d | value:%d\n",
- __func__, dev->phys, type, code, value);
-
- if (type != EV_LED)
- return -1;
-
- offset = hidinput_find_field(dj_hiddev, type, code, &field);
-
- if (offset == -1) {
- dev_warn(&dev->dev, "event field not found\n");
- return -1;
- }
- hid_set_field(field, offset, value);
-
- data = hid_alloc_report_buf(field->report, GFP_ATOMIC);
- if (!data) {
- dev_warn(&dev->dev, "failed to allocate report buf memory\n");
- return -1;
- }
-
- hid_output_report(field->report, &data[0]);
-
- output_report_enum = &dj_rcv_hiddev->report_enum[HID_OUTPUT_REPORT];
- report = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT];
- hid_set_field(report->field[0], 0, dj_dev->device_index);
- hid_set_field(report->field[0], 1, REPORT_TYPE_LEDS);
- hid_set_field(report->field[0], 2, data[1]);
-
- hid_hw_request(dj_rcv_hiddev, report, HID_REQ_SET_REPORT);
-
- kfree(data);
-
- return 0;
-}
-
static int logi_dj_ll_start(struct hid_device *hid)
{
dbg_hid("%s\n", __func__);
@@ -683,7 +652,7 @@ static struct hid_ll_driver logi_dj_ll_driver = {
.stop = logi_dj_ll_stop,
.open = logi_dj_ll_open,
.close = logi_dj_ll_close,
- .hidinput_input_event = logi_dj_ll_input_event,
+ .raw_request = logi_dj_ll_raw_request,
};
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index 3b43d1cfa936..ecc2cbf300cc 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -538,8 +538,8 @@ static int magicmouse_probe(struct hid_device *hdev,
* but there seems to be no other way of switching the mode.
* Thus the super-ugly hacky success check below.
*/
- ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature),
- HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(hdev, feature[0], feature, sizeof(feature),
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret != -EIO && ret != sizeof(feature)) {
hid_err(hdev, "unable to request touch data (%d)\n", ret);
goto err_stop_hw;
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index c6ef6eed3091..6fd58175a291 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -62,9 +62,48 @@ static int ms_ergonomy_kb_quirk(struct hid_input *hi, struct hid_usage *usage,
{
struct input_dev *input = hi->input;
+ if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) {
+ switch (usage->hid & HID_USAGE) {
+ /*
+ * Microsoft uses these 2 reserved usage ids for 2 keys on
+ * the MS office kb labelled "Office Home" and "Task Pane".
+ */
+ case 0x29d:
+ ms_map_key_clear(KEY_PROG1);
+ return 1;
+ case 0x29e:
+ ms_map_key_clear(KEY_PROG2);
+ return 1;
+ }
+ return 0;
+ }
+
+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
+ return 0;
+
switch (usage->hid & HID_USAGE) {
case 0xfd06: ms_map_key_clear(KEY_CHAT); break;
case 0xfd07: ms_map_key_clear(KEY_PHONE); break;
+ case 0xff00:
+ /* Special keypad keys */
+ ms_map_key_clear(KEY_KPEQUAL);
+ set_bit(KEY_KPLEFTPAREN, input->keybit);
+ set_bit(KEY_KPRIGHTPAREN, input->keybit);
+ break;
+ case 0xff01:
+ /* Scroll wheel */
+ hid_map_usage_clear(hi, usage, bit, max, EV_REL, REL_WHEEL);
+ break;
+ case 0xff02:
+ /*
+ * This byte contains a copy of the modifier keys byte of a
+ * standard hid keyboard report, as send by interface 0
+ * (this usage is found on interface 1).
+ *
+ * This byte only gets send when another key in the same report
+ * changes state, and as such is useless, ignore it.
+ */
+ return -1;
case 0xff05:
set_bit(EV_REP, input->evbit);
ms_map_key_clear(KEY_F13);
@@ -83,6 +122,9 @@ static int ms_ergonomy_kb_quirk(struct hid_input *hi, struct hid_usage *usage,
static int ms_presenter_8k_quirk(struct hid_input *hi, struct hid_usage *usage,
unsigned long **bit, int *max)
{
+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
+ return 0;
+
set_bit(EV_REP, hi->input->evbit);
switch (usage->hid & HID_USAGE) {
case 0xfd08: ms_map_key_clear(KEY_FORWARD); break;
@@ -102,9 +144,6 @@ static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi,
{
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
- if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
- return 0;
-
if (quirks & MS_ERGONOMY) {
int ret = ms_ergonomy_kb_quirk(hi, usage, bit, max);
if (ret)
@@ -134,14 +173,39 @@ static int ms_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+ struct input_dev *input;
if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
!usage->type)
return 0;
+ input = field->hidinput->input;
+
/* Handling MS keyboards special buttons */
+ if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff00)) {
+ /* Special keypad keys */
+ input_report_key(input, KEY_KPEQUAL, value & 0x01);
+ input_report_key(input, KEY_KPLEFTPAREN, value & 0x02);
+ input_report_key(input, KEY_KPRIGHTPAREN, value & 0x04);
+ return 1;
+ }
+
+ if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff01)) {
+ /* Scroll wheel */
+ int step = ((value & 0x60) >> 5) + 1;
+
+ switch (value & 0x1f) {
+ case 0x01:
+ input_report_rel(input, REL_WHEEL, step);
+ break;
+ case 0x1f:
+ input_report_rel(input, REL_WHEEL, -step);
+ break;
+ }
+ return 1;
+ }
+
if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff05)) {
- struct input_dev *input = field->hidinput->input;
static unsigned int last_key = 0;
unsigned int key = 0;
switch (value) {
@@ -194,6 +258,8 @@ err_free:
static const struct hid_device_id ms_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV),
.driver_data = MS_HIDINPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB),
+ .driver_data = MS_ERGONOMY },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K),
.driver_data = MS_ERGONOMY },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP),
@@ -208,6 +274,10 @@ static const struct hid_device_id ms_devices[] = {
.driver_data = MS_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500),
.driver_data = MS_DUPLICATE_USAGES },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2),
+ .driver_data = 0 },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2),
+ .driver_data = 0 },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT),
.driver_data = MS_PRESENTER },
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index f134d73beca1..35278e43c7a4 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -68,6 +68,9 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_HOVERING (1 << 11)
#define MT_QUIRK_CONTACT_CNT_ACCURATE (1 << 12)
+#define MT_INPUTMODE_TOUCHSCREEN 0x02
+#define MT_INPUTMODE_TOUCHPAD 0x03
+
struct mt_slot {
__s32 x, y, cx, cy, p, w, h;
__s32 contactid; /* the device ContactID assigned to this slot */
@@ -84,6 +87,7 @@ struct mt_class {
__s32 sn_pressure; /* Signal/noise ratio for pressure events */
__u8 maxcontacts;
bool is_indirect; /* true for touchpads */
+ bool export_all_inputs; /* do not ignore mouse, keyboards, etc... */
};
struct mt_fields {
@@ -100,11 +104,11 @@ struct mt_device {
int cc_value_index; /* contact count value index in the field */
unsigned last_slot_field; /* the last field of a slot */
unsigned mt_report_id; /* the report ID of the multitouch device */
- unsigned pen_report_id; /* the report ID of the pen device */
__s16 inputmode; /* InputMode HID feature, -1 if non-existent */
__s16 inputmode_index; /* InputMode HID feature index in the report */
__s16 maxcontact_report_id; /* Maximum Contact Number HID feature,
-1 if non-existent */
+ __u8 inputmode_value; /* InputMode HID feature value */
__u8 num_received; /* how many contacts we received */
__u8 num_expected; /* expected last contact index */
__u8 maxcontacts;
@@ -128,16 +132,17 @@ static void mt_post_parse(struct mt_device *td);
#define MT_CLS_CONFIDENCE_MINUS_ONE 0x0005
#define MT_CLS_DUAL_INRANGE_CONTACTID 0x0006
#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0007
-#define MT_CLS_DUAL_NSMU_CONTACTID 0x0008
+/* reserved 0x0008 */
#define MT_CLS_INRANGE_CONTACTNUMBER 0x0009
#define MT_CLS_NSMU 0x000a
-#define MT_CLS_DUAL_CONTACT_NUMBER 0x0010
-#define MT_CLS_DUAL_CONTACT_ID 0x0011
+/* reserved 0x0010 */
+/* reserved 0x0011 */
#define MT_CLS_WIN_8 0x0012
+#define MT_CLS_EXPORT_ALL_INPUTS 0x0013
/* vendor specific classes */
#define MT_CLS_3M 0x0101
-#define MT_CLS_CYPRESS 0x0102
+/* reserved 0x0102 */
#define MT_CLS_EGALAX 0x0103
#define MT_CLS_EGALAX_SERIAL 0x0104
#define MT_CLS_TOPSEED 0x0105
@@ -189,28 +194,18 @@ static struct mt_class mt_classes[] = {
.quirks = MT_QUIRK_VALID_IS_INRANGE |
MT_QUIRK_SLOT_IS_CONTACTNUMBER,
.maxcontacts = 2 },
- { .name = MT_CLS_DUAL_NSMU_CONTACTID,
- .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
- MT_QUIRK_SLOT_IS_CONTACTID,
- .maxcontacts = 2 },
{ .name = MT_CLS_INRANGE_CONTACTNUMBER,
.quirks = MT_QUIRK_VALID_IS_INRANGE |
MT_QUIRK_SLOT_IS_CONTACTNUMBER },
- { .name = MT_CLS_DUAL_CONTACT_NUMBER,
- .quirks = MT_QUIRK_ALWAYS_VALID |
- MT_QUIRK_CONTACT_CNT_ACCURATE |
- MT_QUIRK_SLOT_IS_CONTACTNUMBER,
- .maxcontacts = 2 },
- { .name = MT_CLS_DUAL_CONTACT_ID,
- .quirks = MT_QUIRK_ALWAYS_VALID |
- MT_QUIRK_CONTACT_CNT_ACCURATE |
- MT_QUIRK_SLOT_IS_CONTACTID,
- .maxcontacts = 2 },
{ .name = MT_CLS_WIN_8,
.quirks = MT_QUIRK_ALWAYS_VALID |
MT_QUIRK_IGNORE_DUPLICATES |
MT_QUIRK_HOVERING |
MT_QUIRK_CONTACT_CNT_ACCURATE },
+ { .name = MT_CLS_EXPORT_ALL_INPUTS,
+ .quirks = MT_QUIRK_ALWAYS_VALID |
+ MT_QUIRK_CONTACT_CNT_ACCURATE,
+ .export_all_inputs = true },
/*
* vendor specific classes
@@ -223,10 +218,6 @@ static struct mt_class mt_classes[] = {
.sn_height = 128,
.maxcontacts = 60,
},
- { .name = MT_CLS_CYPRESS,
- .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
- MT_QUIRK_CYPRESS,
- .maxcontacts = 10 },
{ .name = MT_CLS_EGALAX,
.quirks = MT_QUIRK_SLOT_IS_CONTACTID |
MT_QUIRK_VALID_IS_INRANGE,
@@ -360,45 +351,6 @@ static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
f->usages[f->length++] = usage->hid;
}
-static int mt_pen_input_mapping(struct hid_device *hdev, struct hid_input *hi,
- struct hid_field *field, struct hid_usage *usage,
- unsigned long **bit, int *max)
-{
- struct mt_device *td = hid_get_drvdata(hdev);
-
- td->pen_report_id = field->report->id;
-
- return 0;
-}
-
-static int mt_pen_input_mapped(struct hid_device *hdev, struct hid_input *hi,
- struct hid_field *field, struct hid_usage *usage,
- unsigned long **bit, int *max)
-{
- return 0;
-}
-
-static int mt_pen_event(struct hid_device *hid, struct hid_field *field,
- struct hid_usage *usage, __s32 value)
-{
- /* let hid-input handle it */
- return 0;
-}
-
-static void mt_pen_report(struct hid_device *hid, struct hid_report *report)
-{
- struct hid_field *field = report->field[0];
-
- input_sync(field->hidinput->input);
-}
-
-static void mt_pen_input_configured(struct hid_device *hdev,
- struct hid_input *hi)
-{
- /* force BTN_STYLUS to allow tablet matching in udev */
- __set_bit(BTN_STYLUS, hi->input->keybit);
-}
-
static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
@@ -415,8 +367,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
* Model touchscreens providing buttons as touchpads.
*/
if (field->application == HID_DG_TOUCHPAD ||
- (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)
+ (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
td->mt_flags |= INPUT_MT_POINTER;
+ td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
+ }
if (usage->usage_index)
prev_usage = &field->usage[usage->usage_index - 1];
@@ -776,28 +730,52 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
- /* Only map fields from TouchScreen or TouchPad collections.
- * We need to ignore fields that belong to other collections
- * such as Mouse that might have the same GenericDesktop usages. */
- if (field->application != HID_DG_TOUCHSCREEN &&
+ struct mt_device *td = hid_get_drvdata(hdev);
+
+ /*
+ * If mtclass.export_all_inputs is not set, only map fields from
+ * TouchScreen or TouchPad collections. We need to ignore fields
+ * that belong to other collections such as Mouse that might have
+ * the same GenericDesktop usages.
+ */
+ if (!td->mtclass.export_all_inputs &&
+ field->application != HID_DG_TOUCHSCREEN &&
field->application != HID_DG_PEN &&
field->application != HID_DG_TOUCHPAD)
return -1;
+ /*
+ * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
+ * for the stylus.
+ */
if (field->physical == HID_DG_STYLUS)
- return mt_pen_input_mapping(hdev, hi, field, usage, bit, max);
+ return 0;
+
+ if (field->application == HID_DG_TOUCHSCREEN ||
+ field->application == HID_DG_TOUCHPAD)
+ return mt_touch_input_mapping(hdev, hi, field, usage, bit, max);
- return mt_touch_input_mapping(hdev, hi, field, usage, bit, max);
+ /* let hid-core decide for the others */
+ return 0;
}
static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
+ /*
+ * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
+ * for the stylus.
+ */
if (field->physical == HID_DG_STYLUS)
- return mt_pen_input_mapped(hdev, hi, field, usage, bit, max);
+ return 0;
+
+ if (field->application == HID_DG_TOUCHSCREEN ||
+ field->application == HID_DG_TOUCHPAD)
+ return mt_touch_input_mapped(hdev, hi, field, usage, bit, max);
- return mt_touch_input_mapped(hdev, hi, field, usage, bit, max);
+ /* let hid-core decide for the others */
+ return 0;
}
static int mt_event(struct hid_device *hid, struct hid_field *field,
@@ -808,25 +786,22 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
if (field->report->id == td->mt_report_id)
return mt_touch_event(hid, field, usage, value);
- if (field->report->id == td->pen_report_id)
- return mt_pen_event(hid, field, usage, value);
-
- /* ignore other reports */
- return 1;
+ return 0;
}
static void mt_report(struct hid_device *hid, struct hid_report *report)
{
struct mt_device *td = hid_get_drvdata(hid);
+ struct hid_field *field = report->field[0];
if (!(hid->claimed & HID_CLAIMED_INPUT))
return;
if (report->id == td->mt_report_id)
- mt_touch_report(hid, report);
+ return mt_touch_report(hid, report);
- if (report->id == td->pen_report_id)
- mt_pen_report(hid, report);
+ if (field && field->hidinput && field->hidinput->input)
+ input_sync(field->hidinput->input);
}
static void mt_set_input_mode(struct hid_device *hdev)
@@ -841,7 +816,7 @@ static void mt_set_input_mode(struct hid_device *hdev)
re = &(hdev->report_enum[HID_FEATURE_REPORT]);
r = re->report_id_hash[td->inputmode];
if (r) {
- r->field[0]->value[td->inputmode_index] = 0x02;
+ r->field[0]->value[td->inputmode_index] = td->inputmode_value;
hid_hw_request(hdev, r, HID_REQ_SET_REPORT);
}
}
@@ -907,13 +882,49 @@ static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
struct mt_device *td = hid_get_drvdata(hdev);
char *name;
const char *suffix = NULL;
+ struct hid_field *field = hi->report->field[0];
if (hi->report->id == td->mt_report_id)
mt_touch_input_configured(hdev, hi);
+ /*
+ * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
+ * for the stylus. Check this first, and then rely on the application
+ * field.
+ */
if (hi->report->field[0]->physical == HID_DG_STYLUS) {
suffix = "Pen";
- mt_pen_input_configured(hdev, hi);
+ /* force BTN_STYLUS to allow tablet matching in udev */
+ __set_bit(BTN_STYLUS, hi->input->keybit);
+ } else {
+ switch (field->application) {
+ case HID_GD_KEYBOARD:
+ suffix = "Keyboard";
+ break;
+ case HID_GD_KEYPAD:
+ suffix = "Keypad";
+ break;
+ case HID_GD_MOUSE:
+ suffix = "Mouse";
+ break;
+ case HID_DG_STYLUS:
+ suffix = "Pen";
+ /* force BTN_STYLUS to allow tablet matching in udev */
+ __set_bit(BTN_STYLUS, hi->input->keybit);
+ break;
+ case HID_DG_TOUCHSCREEN:
+ /* we do not set suffix = "Touchscreen" */
+ break;
+ case HID_GD_SYSTEM_CONTROL:
+ suffix = "System Control";
+ break;
+ case HID_CP_CONSUMER_CONTROL:
+ suffix = "Consumer Control";
+ break;
+ default:
+ suffix = "UNKNOWN";
+ break;
+ }
}
if (suffix) {
@@ -973,9 +984,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
td->mtclass = *mtclass;
td->inputmode = -1;
td->maxcontact_report_id = -1;
+ td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
td->cc_index = -1;
td->mt_report_id = -1;
- td->pen_report_id = -1;
hid_set_drvdata(hdev, td);
td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields),
@@ -1034,6 +1045,12 @@ static void mt_remove(struct hid_device *hdev)
hid_hw_stop(hdev);
}
+/*
+ * This list contains only:
+ * - VID/PID of products not working with the default multitouch handling
+ * - 2 generic rules.
+ * So there is no point in adding here any device with MT_CLS_DEFAULT.
+ */
static const struct hid_device_id mt_devices[] = {
/* 3M panels */
@@ -1047,33 +1064,25 @@ static const struct hid_device_id mt_devices[] = {
MT_USB_DEVICE(USB_VENDOR_ID_3M,
USB_DEVICE_ID_3M3266) },
- /* ActionStar panels */
- { .driver_data = MT_CLS_NSMU,
- MT_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR,
- USB_DEVICE_ID_ACTIONSTAR_1011) },
+ /* Anton devices */
+ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
+ MT_USB_DEVICE(USB_VENDOR_ID_ANTON,
+ USB_DEVICE_ID_ANTON_TOUCH_PAD) },
/* Atmel panels */
{ .driver_data = MT_CLS_SERIAL,
MT_USB_DEVICE(USB_VENDOR_ID_ATMEL,
- USB_DEVICE_ID_ATMEL_MULTITOUCH) },
- { .driver_data = MT_CLS_SERIAL,
- MT_USB_DEVICE(USB_VENDOR_ID_ATMEL,
USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) },
/* Baanto multitouch devices */
{ .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_BAANTO,
USB_DEVICE_ID_BAANTO_MT_190W2) },
+
/* Cando panels */
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
- { .driver_data = MT_CLS_DUAL_CONTACT_NUMBER,
- MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
- USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
- { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
- MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
- USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
@@ -1088,16 +1097,6 @@ static const struct hid_device_id mt_devices[] = {
MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH,
USB_DEVICE_ID_CVTOUCH_SCREEN) },
- /* Cypress panel */
- { .driver_data = MT_CLS_CYPRESS,
- HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS,
- USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
-
- /* Data Modul easyMaxTouch */
- { .driver_data = MT_CLS_DEFAULT,
- MT_USB_DEVICE(USB_VENDOR_ID_DATA_MODUL,
- USB_VENDOR_ID_DATA_MODUL_EASYMAXTOUCH) },
-
/* eGalax devices (resistive) */
{ .driver_data = MT_CLS_EGALAX,
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
@@ -1156,16 +1155,16 @@ static const struct hid_device_id mt_devices[] = {
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },
- /* Elo TouchSystems IntelliTouch Plus panel */
- { .driver_data = MT_CLS_DUAL_CONTACT_ID,
- MT_USB_DEVICE(USB_VENDOR_ID_ELO,
- USB_DEVICE_ID_ELO_TS2515) },
-
/* Flatfrog Panels */
{ .driver_data = MT_CLS_FLATFROG,
MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG,
USB_DEVICE_ID_MULTITOUCH_3200) },
+ /* FocalTech Panels */
+ { .driver_data = MT_CLS_SERIAL,
+ MT_USB_DEVICE(USB_VENDOR_ID_CYGNAL,
+ USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH) },
+
/* GeneralTouch panel */
{ .driver_data = MT_CLS_GENERALTOUCH_TWOFINGERS,
MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
@@ -1204,37 +1203,11 @@ static const struct hid_device_id mt_devices[] = {
MT_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT,
USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) },
- /* Ideacom panel */
- { .driver_data = MT_CLS_SERIAL,
- MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
- USB_DEVICE_ID_IDEACOM_IDC6650) },
- { .driver_data = MT_CLS_SERIAL,
- MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
- USB_DEVICE_ID_IDEACOM_IDC6651) },
-
/* Ilitek dual touch panel */
{ .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_ILITEK,
USB_DEVICE_ID_ILITEK_MULTITOUCH) },
- /* IRTOUCH panels */
- { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
- MT_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS,
- USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
-
- /* LG Display panels */
- { .driver_data = MT_CLS_DEFAULT,
- MT_USB_DEVICE(USB_VENDOR_ID_LG,
- USB_DEVICE_ID_LG_MULTITOUCH) },
-
- /* Lumio panels */
- { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
- MT_USB_DEVICE(USB_VENDOR_ID_LUMIO,
- USB_DEVICE_ID_CRYSTALTOUCH) },
- { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
- MT_USB_DEVICE(USB_VENDOR_ID_LUMIO,
- USB_DEVICE_ID_CRYSTALTOUCH_DUAL) },
-
/* MosArt panels */
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
MT_USB_DEVICE(USB_VENDOR_ID_ASUS,
@@ -1246,11 +1219,6 @@ static const struct hid_device_id mt_devices[] = {
MT_USB_DEVICE(USB_VENDOR_ID_TURBOX,
USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
- /* Nexio panels */
- { .driver_data = MT_CLS_DEFAULT,
- MT_USB_DEVICE(USB_VENDOR_ID_NEXIO,
- USB_DEVICE_ID_NEXIO_MULTITOUCH_420)},
-
/* Panasonic panels */
{ .driver_data = MT_CLS_PANASONIC,
MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
@@ -1264,11 +1232,6 @@ static const struct hid_device_id mt_devices[] = {
MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK,
USB_DEVICE_ID_NOVATEK_PCT) },
- /* PenMount panels */
- { .driver_data = MT_CLS_CONFIDENCE,
- MT_USB_DEVICE(USB_VENDOR_ID_PENMOUNT,
- USB_DEVICE_ID_PENMOUNT_PCI) },
-
/* PixArt optical touch screen */
{ .driver_data = MT_CLS_INRANGE_CONTACTNUMBER,
MT_USB_DEVICE(USB_VENDOR_ID_PIXART,
@@ -1282,44 +1245,18 @@ static const struct hid_device_id mt_devices[] = {
/* PixCir-based panels */
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
- MT_USB_DEVICE(USB_VENDOR_ID_HANVON,
- USB_DEVICE_ID_HANVON_MULTITOUCH) },
- { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) },
/* Quanta-based panels */
{ .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID,
MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
- USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
- { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID,
- MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001) },
- { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID,
- MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
- USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008) },
-
- /* SiS panels */
- { .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH,
- USB_DEVICE_ID_SIS9200_TOUCH) },
- { .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH,
- USB_DEVICE_ID_SIS817_TOUCH) },
- { .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH,
- USB_DEVICE_ID_SIS1030_TOUCH) },
/* Stantum panels */
{ .driver_data = MT_CLS_CONFIDENCE,
- MT_USB_DEVICE(USB_VENDOR_ID_STANTUM,
- USB_DEVICE_ID_MTP)},
- { .driver_data = MT_CLS_CONFIDENCE,
MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
USB_DEVICE_ID_MTP_STM)},
- { .driver_data = MT_CLS_DEFAULT,
- MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX,
- USB_DEVICE_ID_MTP_SITRONIX)},
/* TopSeed panels */
{ .driver_data = MT_CLS_TOPSEED,
@@ -1378,11 +1315,6 @@ static const struct hid_device_id mt_devices[] = {
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_CSR2) },
- /* Zytronic panels */
- { .driver_data = MT_CLS_SERIAL,
- MT_USB_DEVICE(USB_VENDOR_ID_ZYTRONIC,
- USB_DEVICE_ID_ZYTRONIC_ZXY100) },
-
/* Generic MT device */
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) },
diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c
index 59d5eb1e742c..cf1a9f1c1217 100644
--- a/drivers/hid/hid-picolcd_cir.c
+++ b/drivers/hid/hid-picolcd_cir.c
@@ -114,7 +114,7 @@ int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report)
rdev->priv = data;
rdev->driver_type = RC_DRIVER_IR_RAW;
- rdev->allowed_protos = RC_BIT_ALL;
+ rc_set_allowed_protocols(rdev, RC_BIT_ALL);
rdev->open = picolcd_cir_open;
rdev->close = picolcd_cir_close;
rdev->input_name = data->hdev->name;
diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c
index 7ed828056414..91fab975063c 100644
--- a/drivers/hid/hid-prodikeys.c
+++ b/drivers/hid/hid-prodikeys.c
@@ -624,7 +624,8 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm)
/* Setup sound card */
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pm->pk->hdev->dev, index[dev], id[dev],
+ THIS_MODULE, 0, &card);
if (err < 0) {
pk_error("failed to create pc-midi sound card\n");
err = -ENOMEM;
@@ -660,8 +661,6 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm)
snd_rawmidi_set_ops(rwmidi, SNDRV_RAWMIDI_STREAM_INPUT,
&pcmidi_in_ops);
- snd_card_set_dev(card, &pm->pk->hdev->dev);
-
/* create sysfs variables */
err = device_create_file(&pm->pk->hdev->dev,
sysfs_device_attr_channel);
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index 46f4480035bc..5182031f7b52 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -56,9 +56,9 @@ struct sensor_hub_pending {
* @dyn_callback_lock: spin lock to protect callback list
* @hid_sensor_hub_client_devs: Stores all MFD cells for a hub instance.
* @hid_sensor_client_cnt: Number of MFD cells, (no of sensors attached).
+ * @ref_cnt: Number of MFD clients have opened this device
*/
struct sensor_hub_data {
- struct hid_sensor_hub_device *hsdev;
struct mutex mutex;
spinlock_t lock;
struct sensor_hub_pending pending;
@@ -67,6 +67,7 @@ struct sensor_hub_data {
struct mfd_cell *hid_sensor_hub_client_devs;
int hid_sensor_client_cnt;
unsigned long quirks;
+ int ref_cnt;
};
/**
@@ -79,6 +80,7 @@ struct sensor_hub_data {
struct hid_sensor_hub_callbacks_list {
struct list_head list;
u32 usage_id;
+ struct hid_sensor_hub_device *hsdev;
struct hid_sensor_hub_callbacks *usage_callback;
void *priv;
};
@@ -97,20 +99,18 @@ static struct hid_report *sensor_hub_report(int id, struct hid_device *hdev,
return NULL;
}
-static int sensor_hub_get_physical_device_count(
- struct hid_report_enum *report_enum)
+static int sensor_hub_get_physical_device_count(struct hid_device *hdev)
{
- struct hid_report *report;
- struct hid_field *field;
- int cnt = 0;
+ int i;
+ int count = 0;
- list_for_each_entry(report, &report_enum->report_list, list) {
- field = report->field[0];
- if (report->maxfield && field && field->physical)
- cnt++;
+ for (i = 0; i < hdev->maxcollection; ++i) {
+ struct hid_collection *collection = &hdev->collection[i];
+ if (collection->type == HID_COLLECTION_PHYSICAL)
+ ++count;
}
- return cnt;
+ return count;
}
static void sensor_hub_fill_attr_info(
@@ -128,15 +128,23 @@ static void sensor_hub_fill_attr_info(
static struct hid_sensor_hub_callbacks *sensor_hub_get_callback(
struct hid_device *hdev,
- u32 usage_id, void **priv)
+ u32 usage_id,
+ int collection_index,
+ struct hid_sensor_hub_device **hsdev,
+ void **priv)
{
struct hid_sensor_hub_callbacks_list *callback;
struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
spin_lock(&pdata->dyn_callback_lock);
list_for_each_entry(callback, &pdata->dyn_callback_list, list)
- if (callback->usage_id == usage_id) {
+ if (callback->usage_id == usage_id &&
+ (collection_index >=
+ callback->hsdev->start_collection_index) &&
+ (collection_index <
+ callback->hsdev->end_collection_index)) {
*priv = callback->priv;
+ *hsdev = callback->hsdev;
spin_unlock(&pdata->dyn_callback_lock);
return callback->usage_callback;
}
@@ -154,7 +162,8 @@ int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
spin_lock(&pdata->dyn_callback_lock);
list_for_each_entry(callback, &pdata->dyn_callback_list, list)
- if (callback->usage_id == usage_id) {
+ if (callback->usage_id == usage_id &&
+ callback->hsdev == hsdev) {
spin_unlock(&pdata->dyn_callback_lock);
return -EINVAL;
}
@@ -163,6 +172,7 @@ int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
spin_unlock(&pdata->dyn_callback_lock);
return -ENOMEM;
}
+ callback->hsdev = hsdev;
callback->usage_callback = usage_callback;
callback->usage_id = usage_id;
callback->priv = NULL;
@@ -181,7 +191,8 @@ int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
spin_lock(&pdata->dyn_callback_lock);
list_for_each_entry(callback, &pdata->dyn_callback_list, list)
- if (callback->usage_id == usage_id) {
+ if (callback->usage_id == usage_id &&
+ callback->hsdev == hsdev) {
list_del(&callback->list);
kfree(callback);
break;
@@ -260,13 +271,12 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
spin_lock_irqsave(&data->lock, flags);
data->pending.status = true;
+ spin_unlock_irqrestore(&data->lock, flags);
report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT);
- if (!report) {
- spin_unlock_irqrestore(&data->lock, flags);
+ if (!report)
goto err_free;
- }
+
hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
- spin_unlock_irqrestore(&data->lock, flags);
wait_for_completion_interruptible_timeout(&data->pending.ready, HZ*5);
switch (data->pending.raw_size) {
case 1:
@@ -291,6 +301,28 @@ err_free:
}
EXPORT_SYMBOL_GPL(sensor_hub_input_attr_get_raw_value);
+int hid_sensor_get_usage_index(struct hid_sensor_hub_device *hsdev,
+ u32 report_id, int field_index, u32 usage_id)
+{
+ struct hid_report *report;
+ struct hid_field *field;
+ int i;
+
+ report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT);
+ if (!report || (field_index >= report->maxfield))
+ goto done_proc;
+
+ field = report->field[field_index];
+ for (i = 0; i < field->maxusage; ++i) {
+ if (field->usage[i].hid == usage_id)
+ return field->usage[i].usage_index;
+ }
+
+done_proc:
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(hid_sensor_get_usage_index);
+
int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
u8 type,
u32 usage_id,
@@ -298,8 +330,7 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
struct hid_sensor_hub_attribute_info *info)
{
int ret = -1;
- int i, j;
- int collection_index = -1;
+ int i;
struct hid_report *report;
struct hid_field *field;
struct hid_report_enum *report_enum;
@@ -313,44 +344,31 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
info->units = -1;
info->unit_expo = -1;
- for (i = 0; i < hdev->maxcollection; ++i) {
- struct hid_collection *collection = &hdev->collection[i];
- if (usage_id == collection->usage) {
- collection_index = i;
- break;
- }
- }
- if (collection_index == -1)
- goto err_ret;
-
report_enum = &hdev->report_enum[type];
list_for_each_entry(report, &report_enum->report_list, list) {
for (i = 0; i < report->maxfield; ++i) {
field = report->field[i];
- if (field->physical == usage_id &&
- field->logical == attr_usage_id) {
- sensor_hub_fill_attr_info(info, i, report->id,
- field);
- ret = 0;
- } else {
- for (j = 0; j < field->maxusage; ++j) {
- if (field->usage[j].hid ==
- attr_usage_id &&
- field->usage[j].collection_index ==
- collection_index) {
- sensor_hub_fill_attr_info(info,
- i, report->id, field);
- ret = 0;
- break;
- }
+ if (field->maxusage) {
+ if (field->physical == usage_id &&
+ (field->logical == attr_usage_id ||
+ field->usage[0].hid ==
+ attr_usage_id) &&
+ (field->usage[0].collection_index >=
+ hsdev->start_collection_index) &&
+ (field->usage[0].collection_index <
+ hsdev->end_collection_index)) {
+
+ sensor_hub_fill_attr_info(info, i,
+ report->id,
+ field);
+ ret = 0;
+ break;
}
}
- if (ret == 0)
- break;
}
+
}
-err_ret:
return ret;
}
EXPORT_SYMBOL_GPL(sensor_hub_input_get_attribute_info);
@@ -366,7 +384,7 @@ static int sensor_hub_suspend(struct hid_device *hdev, pm_message_t message)
list_for_each_entry(callback, &pdata->dyn_callback_list, list) {
if (callback->usage_callback->suspend)
callback->usage_callback->suspend(
- pdata->hsdev, callback->priv);
+ callback->hsdev, callback->priv);
}
spin_unlock(&pdata->dyn_callback_lock);
@@ -383,7 +401,7 @@ static int sensor_hub_resume(struct hid_device *hdev)
list_for_each_entry(callback, &pdata->dyn_callback_list, list) {
if (callback->usage_callback->resume)
callback->usage_callback->resume(
- pdata->hsdev, callback->priv);
+ callback->hsdev, callback->priv);
}
spin_unlock(&pdata->dyn_callback_lock);
@@ -410,6 +428,7 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
struct hid_sensor_hub_callbacks *callback = NULL;
struct hid_collection *collection = NULL;
void *priv = NULL;
+ struct hid_sensor_hub_device *hsdev = NULL;
hid_dbg(hdev, "sensor_hub_raw_event report id:0x%x size:%d type:%d\n",
report->id, size, report->type);
@@ -444,23 +463,26 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
report->field[i]->usage->collection_index];
hid_dbg(hdev, "collection->usage %x\n",
collection->usage);
- callback = sensor_hub_get_callback(pdata->hsdev->hdev,
- report->field[i]->physical,
- &priv);
+
+ callback = sensor_hub_get_callback(hdev,
+ report->field[i]->physical,
+ report->field[i]->usage[0].collection_index,
+ &hsdev, &priv);
+
if (callback && callback->capture_sample) {
if (report->field[i]->logical)
- callback->capture_sample(pdata->hsdev,
+ callback->capture_sample(hsdev,
report->field[i]->logical, sz, ptr,
callback->pdev);
else
- callback->capture_sample(pdata->hsdev,
+ callback->capture_sample(hsdev,
report->field[i]->usage->hid, sz, ptr,
callback->pdev);
}
ptr += sz;
}
if (callback && collection && callback->send_event)
- callback->send_event(pdata->hsdev, collection->usage,
+ callback->send_event(hsdev, collection->usage,
callback->pdev);
spin_unlock_irqrestore(&pdata->lock, flags);
@@ -473,7 +495,7 @@ int sensor_hub_device_open(struct hid_sensor_hub_device *hsdev)
struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
mutex_lock(&data->mutex);
- if (!hsdev->ref_cnt) {
+ if (!data->ref_cnt) {
ret = hid_hw_open(hsdev->hdev);
if (ret) {
hid_err(hsdev->hdev, "failed to open hid device\n");
@@ -481,7 +503,7 @@ int sensor_hub_device_open(struct hid_sensor_hub_device *hsdev)
return ret;
}
}
- hsdev->ref_cnt++;
+ data->ref_cnt++;
mutex_unlock(&data->mutex);
return ret;
@@ -493,8 +515,8 @@ void sensor_hub_device_close(struct hid_sensor_hub_device *hsdev)
struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
mutex_lock(&data->mutex);
- hsdev->ref_cnt--;
- if (!hsdev->ref_cnt)
+ data->ref_cnt--;
+ if (!data->ref_cnt)
hid_hw_close(hsdev->hdev);
mutex_unlock(&data->mutex);
}
@@ -541,26 +563,19 @@ static int sensor_hub_probe(struct hid_device *hdev,
struct sensor_hub_data *sd;
int i;
char *name;
- struct hid_report *report;
- struct hid_report_enum *report_enum;
- struct hid_field *field;
int dev_cnt;
+ struct hid_sensor_hub_device *hsdev;
+ struct hid_sensor_hub_device *last_hsdev = NULL;
sd = devm_kzalloc(&hdev->dev, sizeof(*sd), GFP_KERNEL);
if (!sd) {
hid_err(hdev, "cannot allocate Sensor data\n");
return -ENOMEM;
}
- sd->hsdev = devm_kzalloc(&hdev->dev, sizeof(*sd->hsdev), GFP_KERNEL);
- if (!sd->hsdev) {
- hid_err(hdev, "cannot allocate hid_sensor_hub_device\n");
- return -ENOMEM;
- }
+
hid_set_drvdata(hdev, sd);
sd->quirks = id->driver_data;
- sd->hsdev->hdev = hdev;
- sd->hsdev->vendor_id = hdev->vendor;
- sd->hsdev->product_id = hdev->product;
+
spin_lock_init(&sd->lock);
spin_lock_init(&sd->dyn_callback_lock);
mutex_init(&sd->mutex);
@@ -578,9 +593,8 @@ static int sensor_hub_probe(struct hid_device *hdev,
}
INIT_LIST_HEAD(&sd->dyn_callback_list);
sd->hid_sensor_client_cnt = 0;
- report_enum = &hdev->report_enum[HID_INPUT_REPORT];
- dev_cnt = sensor_hub_get_physical_device_count(report_enum);
+ dev_cnt = sensor_hub_get_physical_device_count(hdev);
if (dev_cnt > HID_MAX_PHY_DEVICES) {
hid_err(hdev, "Invalid Physical device count\n");
ret = -EINVAL;
@@ -594,42 +608,63 @@ static int sensor_hub_probe(struct hid_device *hdev,
ret = -ENOMEM;
goto err_stop_hw;
}
- list_for_each_entry(report, &report_enum->report_list, list) {
- hid_dbg(hdev, "Report id:%x\n", report->id);
- field = report->field[0];
- if (report->maxfield && field &&
- field->physical) {
+
+ for (i = 0; i < hdev->maxcollection; ++i) {
+ struct hid_collection *collection = &hdev->collection[i];
+
+ if (collection->type == HID_COLLECTION_PHYSICAL) {
+
+ hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL);
+ if (!hsdev) {
+ hid_err(hdev, "cannot allocate hid_sensor_hub_device\n");
+ ret = -ENOMEM;
+ goto err_no_mem;
+ }
+ hsdev->hdev = hdev;
+ hsdev->vendor_id = hdev->vendor;
+ hsdev->product_id = hdev->product;
+ hsdev->start_collection_index = i;
+ if (last_hsdev)
+ last_hsdev->end_collection_index = i;
+ last_hsdev = hsdev;
name = kasprintf(GFP_KERNEL, "HID-SENSOR-%x",
- field->physical);
+ collection->usage);
if (name == NULL) {
hid_err(hdev, "Failed MFD device name\n");
ret = -ENOMEM;
- goto err_free_names;
+ goto err_no_mem;
}
sd->hid_sensor_hub_client_devs[
- sd->hid_sensor_client_cnt].id = PLATFORM_DEVID_AUTO;
+ sd->hid_sensor_client_cnt].id =
+ PLATFORM_DEVID_AUTO;
sd->hid_sensor_hub_client_devs[
sd->hid_sensor_client_cnt].name = name;
sd->hid_sensor_hub_client_devs[
sd->hid_sensor_client_cnt].platform_data =
- sd->hsdev;
+ hsdev;
sd->hid_sensor_hub_client_devs[
sd->hid_sensor_client_cnt].pdata_size =
- sizeof(*sd->hsdev);
- hid_dbg(hdev, "Adding %s:%p\n", name, sd);
+ sizeof(*hsdev);
+ hid_dbg(hdev, "Adding %s:%d\n", name,
+ hsdev->start_collection_index);
sd->hid_sensor_client_cnt++;
}
}
+ if (last_hsdev)
+ last_hsdev->end_collection_index = i;
+
ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs,
sd->hid_sensor_client_cnt, NULL, 0, NULL);
if (ret < 0)
- goto err_free_names;
+ goto err_no_mem;
return ret;
-err_free_names:
- for (i = 0; i < sd->hid_sensor_client_cnt ; ++i)
+err_no_mem:
+ for (i = 0; i < sd->hid_sensor_client_cnt; ++i) {
kfree(sd->hid_sensor_hub_client_devs[i].name);
+ kfree(sd->hid_sensor_hub_client_devs[i].platform_data);
+ }
kfree(sd->hid_sensor_hub_client_devs);
err_stop_hw:
hid_hw_stop(hdev);
@@ -651,8 +686,10 @@ static void sensor_hub_remove(struct hid_device *hdev)
complete(&data->pending.ready);
spin_unlock_irqrestore(&data->lock, flags);
mfd_remove_devices(&hdev->dev);
- for (i = 0; i < data->hid_sensor_client_cnt ; ++i)
+ for (i = 0; i < data->hid_sensor_client_cnt; ++i) {
kfree(data->hid_sensor_hub_client_devs[i].name);
+ kfree(data->hid_sensor_hub_client_devs[i].platform_data);
+ }
kfree(data->hid_sensor_hub_client_devs);
hid_set_drvdata(hdev, NULL);
mutex_destroy(&data->mutex);
@@ -665,6 +702,9 @@ static const struct hid_device_id sensor_hub_devices[] = {
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_1,
USB_DEVICE_ID_INTEL_HID_SENSOR),
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
+ { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_STM_0,
+ USB_DEVICE_ID_STM_HID_SENSOR),
+ .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID,
HID_ANY_ID) },
{ }
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 12354055d474..69204afea7a4 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -17,7 +17,8 @@
* any later version.
*/
-/* NOTE: in order for the Sony PS3 BD Remote Control to be found by
+/*
+ * NOTE: in order for the Sony PS3 BD Remote Control to be found by
* a Bluetooth host, the key combination Start+Enter has to be kept pressed
* for about 7 seconds with the Bluetooth Host Controller in discovering mode.
*
@@ -28,8 +29,11 @@
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/usb.h>
#include <linux/leds.h>
+#include <linux/power_supply.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/input/mt.h>
#include "hid-ids.h"
@@ -41,7 +45,13 @@
#define DUALSHOCK4_CONTROLLER_USB BIT(5)
#define DUALSHOCK4_CONTROLLER_BT BIT(6)
-#define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER_USB | BUZZ_CONTROLLER | DUALSHOCK4_CONTROLLER_USB)
+#define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT)
+#define DUALSHOCK4_CONTROLLER (DUALSHOCK4_CONTROLLER_USB |\
+ DUALSHOCK4_CONTROLLER_BT)
+#define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER | BUZZ_CONTROLLER |\
+ DUALSHOCK4_CONTROLLER)
+#define SONY_BATTERY_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER)
+#define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER)
#define MAX_LEDS 4
@@ -73,7 +83,8 @@ static const u8 sixaxis_rdesc_fixup2[] = {
0xb1, 0x02, 0xc0, 0xc0,
};
-/* The default descriptor doesn't provide mapping for the accelerometers
+/*
+ * The default descriptor doesn't provide mapping for the accelerometers
* or orientation sensors. This fixed descriptor maps the accelerometers
* to usage values 0x40, 0x41 and 0x42 and maps the orientation sensors
* to usage values 0x43, 0x44 and 0x45.
@@ -332,6 +343,217 @@ static u8 dualshock4_usb_rdesc[] = {
0xC0 /* End Collection */
};
+/*
+ * The default behavior of the Dualshock 4 is to send reports using report
+ * type 1 when running over Bluetooth. However, as soon as it receives a
+ * report of type 17 to set the LEDs or rumble it starts returning it's state
+ * in report 17 instead of 1. Since report 17 is undefined in the default HID
+ * descriptor the button and axis definitions must be moved to report 17 or
+ * the HID layer won't process the received input once a report is sent.
+ */
+static u8 dualshock4_bt_rdesc[] = {
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x05, /* Usage (Gamepad), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x01, /* Report ID (1), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x0A, /* Report Count (9), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x06, 0x04, 0xFF, /* Usage Page (FF04h), */
+ 0x85, 0x02, /* Report ID (2), */
+ 0x09, 0x24, /* Usage (24h), */
+ 0x95, 0x24, /* Report Count (36), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x85, 0xA3, /* Report ID (163), */
+ 0x09, 0x25, /* Usage (25h), */
+ 0x95, 0x30, /* Report Count (48), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x85, 0x05, /* Report ID (5), */
+ 0x09, 0x26, /* Usage (26h), */
+ 0x95, 0x28, /* Report Count (40), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x85, 0x06, /* Report ID (6), */
+ 0x09, 0x27, /* Usage (27h), */
+ 0x95, 0x34, /* Report Count (52), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x85, 0x07, /* Report ID (7), */
+ 0x09, 0x28, /* Usage (28h), */
+ 0x95, 0x30, /* Report Count (48), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x85, 0x08, /* Report ID (8), */
+ 0x09, 0x29, /* Usage (29h), */
+ 0x95, 0x2F, /* Report Count (47), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x06, 0x03, 0xFF, /* Usage Page (FF03h), */
+ 0x85, 0x03, /* Report ID (3), */
+ 0x09, 0x21, /* Usage (21h), */
+ 0x95, 0x26, /* Report Count (38), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x85, 0x04, /* Report ID (4), */
+ 0x09, 0x22, /* Usage (22h), */
+ 0x95, 0x2E, /* Report Count (46), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x85, 0xF0, /* Report ID (240), */
+ 0x09, 0x47, /* Usage (47h), */
+ 0x95, 0x3F, /* Report Count (63), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x85, 0xF1, /* Report ID (241), */
+ 0x09, 0x48, /* Usage (48h), */
+ 0x95, 0x3F, /* Report Count (63), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x85, 0xF2, /* Report ID (242), */
+ 0x09, 0x49, /* Usage (49h), */
+ 0x95, 0x0F, /* Report Count (15), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x85, 0x11, /* Report ID (17), */
+ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
+ 0x09, 0x20, /* Usage (20h), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x09, 0x32, /* Usage (Z), */
+ 0x09, 0x35, /* Usage (Rz), */
+ 0x15, 0x00, /* Logical Minimum (0), */
+ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x04, /* Report Count (4), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x39, /* Usage (Hat Switch), */
+ 0x15, 0x00, /* Logical Minimum (0), */
+ 0x25, 0x07, /* Logical Maximum (7), */
+ 0x75, 0x04, /* Report Size (4), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x42, /* Input (Variable, Null State), */
+ 0x05, 0x09, /* Usage Page (Button), */
+ 0x19, 0x01, /* Usage Minimum (01h), */
+ 0x29, 0x0E, /* Usage Maximum (0Eh), */
+ 0x15, 0x00, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x0E, /* Report Count (14), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x75, 0x06, /* Report Size (6), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x33, /* Usage (Rx), */
+ 0x09, 0x34, /* Usage (Ry), */
+ 0x15, 0x00, /* Logical Minimum (0), */
+ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
+ 0x09, 0x20, /* Usage (20h), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x19, 0x40, /* Usage Minimum (40h), */
+ 0x29, 0x42, /* Usage Maximum (42h), */
+ 0x16, 0x00, 0x80, /* Logical Minimum (-32768), */
+ 0x26, 0x00, 0x7F, /* Logical Maximum (32767), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x19, 0x43, /* Usage Minimum (43h), */
+ 0x29, 0x45, /* Usage Maximum (45h), */
+ 0x16, 0xFF, 0xBF, /* Logical Minimum (-16385), */
+ 0x26, 0x00, 0x40, /* Logical Maximum (16384), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
+ 0x09, 0x20, /* Usage (20h), */
+ 0x15, 0x00, /* Logical Minimum (0), */
+ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x31, /* Report Count (51), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x21, /* Usage (21h), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x4D, /* Report Count (77), */
+ 0x91, 0x02, /* Output (Variable), */
+ 0x85, 0x12, /* Report ID (18), */
+ 0x09, 0x22, /* Usage (22h), */
+ 0x95, 0x8D, /* Report Count (141), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x23, /* Usage (23h), */
+ 0x91, 0x02, /* Output (Variable), */
+ 0x85, 0x13, /* Report ID (19), */
+ 0x09, 0x24, /* Usage (24h), */
+ 0x95, 0xCD, /* Report Count (205), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x25, /* Usage (25h), */
+ 0x91, 0x02, /* Output (Variable), */
+ 0x85, 0x14, /* Report ID (20), */
+ 0x09, 0x26, /* Usage (26h), */
+ 0x96, 0x0D, 0x01, /* Report Count (269), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x27, /* Usage (27h), */
+ 0x91, 0x02, /* Output (Variable), */
+ 0x85, 0x15, /* Report ID (21), */
+ 0x09, 0x28, /* Usage (28h), */
+ 0x96, 0x4D, 0x01, /* Report Count (333), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x29, /* Usage (29h), */
+ 0x91, 0x02, /* Output (Variable), */
+ 0x85, 0x16, /* Report ID (22), */
+ 0x09, 0x2A, /* Usage (2Ah), */
+ 0x96, 0x8D, 0x01, /* Report Count (397), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x2B, /* Usage (2Bh), */
+ 0x91, 0x02, /* Output (Variable), */
+ 0x85, 0x17, /* Report ID (23), */
+ 0x09, 0x2C, /* Usage (2Ch), */
+ 0x96, 0xCD, 0x01, /* Report Count (461), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x2D, /* Usage (2Dh), */
+ 0x91, 0x02, /* Output (Variable), */
+ 0x85, 0x18, /* Report ID (24), */
+ 0x09, 0x2E, /* Usage (2Eh), */
+ 0x96, 0x0D, 0x02, /* Report Count (525), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x2F, /* Usage (2Fh), */
+ 0x91, 0x02, /* Output (Variable), */
+ 0x85, 0x19, /* Report ID (25), */
+ 0x09, 0x30, /* Usage (30h), */
+ 0x96, 0x22, 0x02, /* Report Count (546), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x31, /* Usage (31h), */
+ 0x91, 0x02, /* Output (Variable), */
+ 0x06, 0x80, 0xFF, /* Usage Page (FF80h), */
+ 0x85, 0x82, /* Report ID (130), */
+ 0x09, 0x22, /* Usage (22h), */
+ 0x95, 0x3F, /* Report Count (63), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x85, 0x83, /* Report ID (131), */
+ 0x09, 0x23, /* Usage (23h), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x85, 0x84, /* Report ID (132), */
+ 0x09, 0x24, /* Usage (24h), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x85, 0x90, /* Report ID (144), */
+ 0x09, 0x30, /* Usage (30h), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x85, 0x91, /* Report ID (145), */
+ 0x09, 0x31, /* Usage (31h), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x85, 0x92, /* Report ID (146), */
+ 0x09, 0x32, /* Usage (32h), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x85, 0x93, /* Report ID (147), */
+ 0x09, 0x33, /* Usage (33h), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x85, 0xA0, /* Report ID (160), */
+ 0x09, 0x40, /* Usage (40h), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x85, 0xA4, /* Report ID (164), */
+ 0x09, 0x44, /* Usage (44h), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0xC0 /* End Collection */
+};
+
static __u8 ps3remote_rdesc[] = {
0x05, 0x01, /* GUsagePage Generic Desktop */
0x09, 0x05, /* LUsage 0x05 [Game Pad] */
@@ -449,7 +671,8 @@ static const unsigned int ps3remote_keymap_remote_buttons[] = {
};
static const unsigned int buzz_keymap[] = {
- /* The controller has 4 remote buzzers, each with one LED and 5
+ /*
+ * The controller has 4 remote buzzers, each with one LED and 5
* buttons.
*
* We use the mapping chosen by the controller, which is:
@@ -487,18 +710,35 @@ static const unsigned int buzz_keymap[] = {
[20] = BTN_TRIGGER_HAPPY20,
};
+static enum power_supply_property sony_battery_props[] = {
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_SCOPE,
+ POWER_SUPPLY_PROP_STATUS,
+};
+
+static spinlock_t sony_dev_list_lock;
+static LIST_HEAD(sony_device_list);
+
struct sony_sc {
+ spinlock_t lock;
+ struct list_head list_node;
struct hid_device *hdev;
struct led_classdev *leds[MAX_LEDS];
- struct hid_report *output_report;
unsigned long quirks;
struct work_struct state_worker;
+ struct power_supply battery;
#ifdef CONFIG_SONY_FF
__u8 left;
__u8 right;
#endif
+ __u8 mac_address[6];
+ __u8 worker_initialized;
+ __u8 cable_state;
+ __u8 battery_charging;
+ __u8 battery_capacity;
__u8 led_state[MAX_LEDS];
__u8 led_count;
};
@@ -576,6 +816,10 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
hid_info(hdev, "Using modified Dualshock 4 report descriptor with gyroscope axes\n");
rdesc = dualshock4_usb_rdesc;
*rsize = sizeof(dualshock4_usb_rdesc);
+ } else if ((sc->quirks & DUALSHOCK4_CONTROLLER_BT) && *rsize == 357) {
+ hid_info(hdev, "Using modified Dualshock 4 Bluetooth report descriptor\n");
+ rdesc = dualshock4_bt_rdesc;
+ *rsize = sizeof(dualshock4_bt_rdesc);
}
/* The HID descriptor exposed over BT has a trailing zero byte */
@@ -599,20 +843,127 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
return rdesc;
}
+static void sixaxis_parse_report(struct sony_sc *sc, __u8 *rd, int size)
+{
+ static const __u8 sixaxis_battery_capacity[] = { 0, 1, 25, 50, 75, 100 };
+ unsigned long flags;
+ __u8 cable_state, battery_capacity, battery_charging;
+
+ /*
+ * The sixaxis is charging if the battery value is 0xee
+ * and it is fully charged if the value is 0xef.
+ * It does not report the actual level while charging so it
+ * is set to 100% while charging is in progress.
+ */
+ if (rd[30] >= 0xee) {
+ battery_capacity = 100;
+ battery_charging = !(rd[30] & 0x01);
+ } else {
+ __u8 index = rd[30] <= 5 ? rd[30] : 5;
+ battery_capacity = sixaxis_battery_capacity[index];
+ battery_charging = 0;
+ }
+ cable_state = !(rd[31] & 0x04);
+
+ spin_lock_irqsave(&sc->lock, flags);
+ sc->cable_state = cable_state;
+ sc->battery_capacity = battery_capacity;
+ sc->battery_charging = battery_charging;
+ spin_unlock_irqrestore(&sc->lock, flags);
+}
+
+static void dualshock4_parse_report(struct sony_sc *sc, __u8 *rd, int size)
+{
+ struct hid_input *hidinput = list_entry(sc->hdev->inputs.next,
+ struct hid_input, list);
+ struct input_dev *input_dev = hidinput->input;
+ unsigned long flags;
+ int n, offset;
+ __u8 cable_state, battery_capacity, battery_charging;
+
+ /*
+ * Battery and touchpad data starts at byte 30 in the USB report and
+ * 32 in Bluetooth report.
+ */
+ offset = (sc->quirks & DUALSHOCK4_CONTROLLER_USB) ? 30 : 32;
+
+ /*
+ * The lower 4 bits of byte 30 contain the battery level
+ * and the 5th bit contains the USB cable state.
+ */
+ cable_state = (rd[offset] >> 4) & 0x01;
+ battery_capacity = rd[offset] & 0x0F;
+
+ /*
+ * When a USB power source is connected the battery level ranges from
+ * 0 to 10, and when running on battery power it ranges from 0 to 9.
+ * A battery level above 10 when plugged in means charge completed.
+ */
+ if (!cable_state || battery_capacity > 10)
+ battery_charging = 0;
+ else
+ battery_charging = 1;
+
+ if (!cable_state)
+ battery_capacity++;
+ if (battery_capacity > 10)
+ battery_capacity = 10;
+
+ battery_capacity *= 10;
+
+ spin_lock_irqsave(&sc->lock, flags);
+ sc->cable_state = cable_state;
+ sc->battery_capacity = battery_capacity;
+ sc->battery_charging = battery_charging;
+ spin_unlock_irqrestore(&sc->lock, flags);
+
+ offset += 5;
+
+ /*
+ * The Dualshock 4 multi-touch trackpad data starts at offset 35 on USB
+ * and 37 on Bluetooth.
+ * The first 7 bits of the first byte is a counter and bit 8 is a touch
+ * indicator that is 0 when pressed and 1 when not pressed.
+ * The next 3 bytes are two 12 bit touch coordinates, X and Y.
+ * The data for the second touch is in the same format and immediatly
+ * follows the data for the first.
+ */
+ for (n = 0; n < 2; n++) {
+ __u16 x, y;
+
+ x = rd[offset+1] | ((rd[offset+2] & 0xF) << 8);
+ y = ((rd[offset+2] & 0xF0) >> 4) | (rd[offset+3] << 4);
+
+ input_mt_slot(input_dev, n);
+ input_mt_report_slot_state(input_dev, MT_TOOL_FINGER,
+ !(rd[offset] >> 7));
+ input_report_abs(input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+
+ offset += 4;
+ }
+}
+
static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
__u8 *rd, int size)
{
struct sony_sc *sc = hid_get_drvdata(hdev);
- /* Sixaxis HID report has acclerometers/gyro with MSByte first, this
+ /*
+ * Sixaxis HID report has acclerometers/gyro with MSByte first, this
* has to be BYTE_SWAPPED before passing up to joystick interface
*/
- if ((sc->quirks & (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT)) &&
- rd[0] == 0x01 && size == 49) {
+ if ((sc->quirks & SIXAXIS_CONTROLLER) && rd[0] == 0x01 && size == 49) {
swap(rd[41], rd[42]);
swap(rd[43], rd[44]);
swap(rd[45], rd[46]);
swap(rd[47], rd[48]);
+
+ sixaxis_parse_report(sc, rd, size);
+ } else if (((sc->quirks & DUALSHOCK4_CONTROLLER_USB) && rd[0] == 0x01 &&
+ size == 64) || ((sc->quirks & DUALSHOCK4_CONTROLLER_BT)
+ && rd[0] == 0x11 && size == 78)) {
+ dualshock4_parse_report(sc, rd, size);
}
return 0;
@@ -655,45 +1006,6 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi,
}
/*
- * The Sony Sixaxis does not handle HID Output Reports on the Interrupt EP
- * like it should according to usbhid/hid-core.c::usbhid_output_raw_report()
- * so we need to override that forcing HID Output Reports on the Control EP.
- *
- * There is also another issue about HID Output Reports via USB, the Sixaxis
- * does not want the report_id as part of the data packet, so we have to
- * discard buf[0] when sending the actual control message, even for numbered
- * reports, humpf!
- */
-static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
- size_t count, unsigned char report_type)
-{
- struct usb_interface *intf = to_usb_interface(hid->dev.parent);
- struct usb_device *dev = interface_to_usbdev(intf);
- struct usb_host_interface *interface = intf->cur_altsetting;
- int report_id = buf[0];
- int ret;
-
- if (report_type == HID_OUTPUT_REPORT) {
- /* Don't send the Report ID */
- buf++;
- count--;
- }
-
- ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- HID_REQ_SET_REPORT,
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- ((report_type + 1) << 8) | report_id,
- interface->desc.bInterfaceNumber, buf, count,
- USB_CTRL_SET_TIMEOUT);
-
- /* Count also the Report ID, in case of an Output report. */
- if (ret > 0 && report_type == HID_OUTPUT_REPORT)
- ret++;
-
- return ret;
-}
-
-/*
* Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
* to "operational". Without this, the ps3 controller will not report any
* events.
@@ -706,7 +1018,8 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev)
if (!buf)
return -ENOMEM;
- ret = hdev->hid_get_raw_report(hdev, 0xf2, buf, 17, HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(hdev, 0xf2, buf, 17, HID_FEATURE_REPORT,
+ HID_REQ_GET_REPORT);
if (ret < 0)
hid_err(hdev, "can't set operational mode\n");
@@ -719,7 +1032,20 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev)
static int sixaxis_set_operational_bt(struct hid_device *hdev)
{
unsigned char buf[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 };
- return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
+ return hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+}
+
+/*
+ * Requesting feature report 0x02 in Bluetooth mode changes the state of the
+ * controller so that it sends full input reports of type 0x11.
+ */
+static int dualshock4_set_operational_bt(struct hid_device *hdev)
+{
+ __u8 buf[37] = { 0 };
+
+ return hid_hw_raw_request(hdev, 0x02, buf, sizeof(buf),
+ HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
}
static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds)
@@ -749,8 +1075,7 @@ static void sony_set_leds(struct hid_device *hdev, const __u8 *leds, int count)
if (drv_data->quirks & BUZZ_CONTROLLER && count == 4) {
buzz_set_leds(hdev, leds);
- } else if ((drv_data->quirks & SIXAXIS_CONTROLLER_USB) ||
- (drv_data->quirks & DUALSHOCK4_CONTROLLER_USB)) {
+ } else {
for (n = 0; n < count; n++)
drv_data->led_state[n] = leds[n];
schedule_work(&drv_data->state_worker);
@@ -790,7 +1115,6 @@ static enum led_brightness sony_led_get_brightness(struct led_classdev *led)
struct sony_sc *drv_data;
int n;
- int on = 0;
drv_data = hid_get_drvdata(hdev);
if (!drv_data) {
@@ -799,13 +1123,11 @@ static enum led_brightness sony_led_get_brightness(struct led_classdev *led)
}
for (n = 0; n < drv_data->led_count; n++) {
- if (led == drv_data->leds[n]) {
- on = !!(drv_data->led_state[n]);
- break;
- }
+ if (led == drv_data->leds[n])
+ return drv_data->led_state[n];
}
- return on ? LED_FULL : LED_OFF;
+ return LED_OFF;
}
static void sony_leds_remove(struct hid_device *hdev)
@@ -855,7 +1177,7 @@ static int sony_leds_init(struct hid_device *hdev)
/* Validate expected report characteristics. */
if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 7))
return -ENODEV;
- } else if (drv_data->quirks & DUALSHOCK4_CONTROLLER_USB) {
+ } else if (drv_data->quirks & DUALSHOCK4_CONTROLLER) {
drv_data->led_count = 3;
max_brightness = 255;
use_colors = 1;
@@ -869,9 +1191,11 @@ static int sony_leds_init(struct hid_device *hdev)
name_fmt = "%s::sony%d";
}
- /* Clear LEDs as we have no way of reading their initial state. This is
+ /*
+ * Clear LEDs as we have no way of reading their initial state. This is
* only relevant if the driver is loaded after somebody actively set the
- * LEDs to on */
+ * LEDs to on
+ */
sony_set_leds(hdev, initial_values, drv_data->led_count);
name_sz = strlen(dev_name(&hdev->dev)) + name_len + 1;
@@ -941,29 +1265,45 @@ static void sixaxis_state_worker(struct work_struct *work)
buf[10] |= sc->led_state[2] << 3;
buf[10] |= sc->led_state[3] << 4;
- sc->hdev->hid_output_raw_report(sc->hdev, buf, sizeof(buf),
- HID_OUTPUT_REPORT);
+ hid_hw_raw_request(sc->hdev, 0x01, buf, sizeof(buf), HID_OUTPUT_REPORT,
+ HID_REQ_SET_REPORT);
}
static void dualshock4_state_worker(struct work_struct *work)
{
struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
struct hid_device *hdev = sc->hdev;
- struct hid_report *report = sc->output_report;
- __s32 *value = report->field[0]->value;
+ int offset;
- value[0] = 0x03;
+ __u8 buf[78] = { 0 };
+
+ if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) {
+ buf[0] = 0x05;
+ buf[1] = 0x03;
+ offset = 4;
+ } else {
+ buf[0] = 0x11;
+ buf[1] = 0xB0;
+ buf[3] = 0x0F;
+ offset = 6;
+ }
#ifdef CONFIG_SONY_FF
- value[3] = sc->right;
- value[4] = sc->left;
+ buf[offset++] = sc->right;
+ buf[offset++] = sc->left;
+#else
+ offset += 2;
#endif
- value[5] = sc->led_state[0];
- value[6] = sc->led_state[1];
- value[7] = sc->led_state[2];
+ buf[offset++] = sc->led_state[0];
+ buf[offset++] = sc->led_state[1];
+ buf[offset++] = sc->led_state[2];
- hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
+ if (sc->quirks & DUALSHOCK4_CONTROLLER_USB)
+ hid_hw_output_report(hdev, buf, 32);
+ else
+ hid_hw_raw_request(hdev, 0x11, buf, 78,
+ HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
}
#ifdef CONFIG_SONY_FF
@@ -993,51 +1333,252 @@ static int sony_init_ff(struct hid_device *hdev)
return input_ff_create_memless(input_dev, NULL, sony_play_effect);
}
-static void sony_destroy_ff(struct hid_device *hdev)
+#else
+static int sony_init_ff(struct hid_device *hdev)
{
- struct sony_sc *sc = hid_get_drvdata(hdev);
+ return 0;
+}
- cancel_work_sync(&sc->state_worker);
+#endif
+
+static int sony_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct sony_sc *sc = container_of(psy, struct sony_sc, battery);
+ unsigned long flags;
+ int ret = 0;
+ u8 battery_charging, battery_capacity, cable_state;
+
+ spin_lock_irqsave(&sc->lock, flags);
+ battery_charging = sc->battery_charging;
+ battery_capacity = sc->battery_capacity;
+ cable_state = sc->cable_state;
+ spin_unlock_irqrestore(&sc->lock, flags);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = 1;
+ break;
+ case POWER_SUPPLY_PROP_SCOPE:
+ val->intval = POWER_SUPPLY_SCOPE_DEVICE;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = battery_capacity;
+ break;
+ case POWER_SUPPLY_PROP_STATUS:
+ if (battery_charging)
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ else
+ if (battery_capacity == 100 && cable_state)
+ val->intval = POWER_SUPPLY_STATUS_FULL;
+ else
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
}
-#else
-static int sony_init_ff(struct hid_device *hdev)
+static int sony_battery_probe(struct sony_sc *sc)
{
+ static atomic_t power_id_seq = ATOMIC_INIT(0);
+ unsigned long power_id;
+ struct hid_device *hdev = sc->hdev;
+ int ret;
+
+ /*
+ * Set the default battery level to 100% to avoid low battery warnings
+ * if the battery is polled before the first device report is received.
+ */
+ sc->battery_capacity = 100;
+
+ power_id = (unsigned long)atomic_inc_return(&power_id_seq);
+
+ sc->battery.properties = sony_battery_props;
+ sc->battery.num_properties = ARRAY_SIZE(sony_battery_props);
+ sc->battery.get_property = sony_battery_get_property;
+ sc->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+ sc->battery.use_for_apm = 0;
+ sc->battery.name = kasprintf(GFP_KERNEL, "sony_controller_battery_%lu",
+ power_id);
+ if (!sc->battery.name)
+ return -ENOMEM;
+
+ ret = power_supply_register(&hdev->dev, &sc->battery);
+ if (ret) {
+ hid_err(hdev, "Unable to register battery device\n");
+ goto err_free;
+ }
+
+ power_supply_powers(&sc->battery, &hdev->dev);
return 0;
+
+err_free:
+ kfree(sc->battery.name);
+ sc->battery.name = NULL;
+ return ret;
}
-static void sony_destroy_ff(struct hid_device *hdev)
+static void sony_battery_remove(struct sony_sc *sc)
{
+ if (!sc->battery.name)
+ return;
+
+ power_supply_unregister(&sc->battery);
+ kfree(sc->battery.name);
+ sc->battery.name = NULL;
}
-#endif
-static int sony_set_output_report(struct sony_sc *sc, int req_id, int req_size)
+static int sony_register_touchpad(struct sony_sc *sc, int touch_count,
+ int w, int h)
{
- struct list_head *head, *list;
- struct hid_report *report;
- struct hid_device *hdev = sc->hdev;
+ struct hid_input *hidinput = list_entry(sc->hdev->inputs.next,
+ struct hid_input, list);
+ struct input_dev *input_dev = hidinput->input;
+ int ret;
- list = &hdev->report_enum[HID_OUTPUT_REPORT].report_list;
+ ret = input_mt_init_slots(input_dev, touch_count, 0);
+ if (ret < 0) {
+ hid_err(sc->hdev, "Unable to initialize multi-touch slots\n");
+ return ret;
+ }
- list_for_each(head, list) {
- report = list_entry(head, struct hid_report, list);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, w, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, h, 0, 0);
- if (report->id == req_id) {
- if (report->size < req_size) {
- hid_err(hdev, "Output report 0x%02x (%i bits) is smaller than requested size (%i bits)\n",
- req_id, report->size, req_size);
- return -EINVAL;
- }
- sc->output_report = report;
- return 0;
+ return 0;
+}
+
+/*
+ * If a controller is plugged in via USB while already connected via Bluetooth
+ * it will show up as two devices. A global list of connected controllers and
+ * their MAC addresses is maintained to ensure that a device is only connected
+ * once.
+ */
+static int sony_check_add_dev_list(struct sony_sc *sc)
+{
+ struct sony_sc *entry;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&sony_dev_list_lock, flags);
+
+ list_for_each_entry(entry, &sony_device_list, list_node) {
+ ret = memcmp(sc->mac_address, entry->mac_address,
+ sizeof(sc->mac_address));
+ if (!ret) {
+ ret = -EEXIST;
+ hid_info(sc->hdev, "controller with MAC address %pMR already connected\n",
+ sc->mac_address);
+ goto unlock;
}
}
- hid_err(hdev, "Unable to locate output report 0x%02x\n", req_id);
+ ret = 0;
+ list_add(&(sc->list_node), &sony_device_list);
+
+unlock:
+ spin_unlock_irqrestore(&sony_dev_list_lock, flags);
+ return ret;
+}
+
+static void sony_remove_dev_list(struct sony_sc *sc)
+{
+ unsigned long flags;
+
+ if (sc->list_node.next) {
+ spin_lock_irqsave(&sony_dev_list_lock, flags);
+ list_del(&(sc->list_node));
+ spin_unlock_irqrestore(&sony_dev_list_lock, flags);
+ }
+}
+
+static int sony_get_bt_devaddr(struct sony_sc *sc)
+{
+ int ret;
+
+ /* HIDP stores the device MAC address as a string in the uniq field. */
+ ret = strlen(sc->hdev->uniq);
+ if (ret != 17)
+ return -EINVAL;
+
+ ret = sscanf(sc->hdev->uniq,
+ "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+ &sc->mac_address[5], &sc->mac_address[4], &sc->mac_address[3],
+ &sc->mac_address[2], &sc->mac_address[1], &sc->mac_address[0]);
+
+ if (ret != 6)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int sony_check_add(struct sony_sc *sc)
+{
+ int n, ret;
+
+ if ((sc->quirks & DUALSHOCK4_CONTROLLER_BT) ||
+ (sc->quirks & SIXAXIS_CONTROLLER_BT)) {
+ /*
+ * sony_get_bt_devaddr() attempts to parse the Bluetooth MAC
+ * address from the uniq string where HIDP stores it.
+ * As uniq cannot be guaranteed to be a MAC address in all cases
+ * a failure of this function should not prevent the connection.
+ */
+ if (sony_get_bt_devaddr(sc) < 0) {
+ hid_warn(sc->hdev, "UNIQ does not contain a MAC address; duplicate check skipped\n");
+ return 0;
+ }
+ } else if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) {
+ __u8 buf[7];
+
+ /*
+ * The MAC address of a DS4 controller connected via USB can be
+ * retrieved with feature report 0x81. The address begins at
+ * offset 1.
+ */
+ ret = hid_hw_raw_request(sc->hdev, 0x81, buf, sizeof(buf),
+ HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
+
+ if (ret != 7) {
+ hid_err(sc->hdev, "failed to retrieve feature report 0x81 with the DualShock 4 MAC address\n");
+ return ret < 0 ? ret : -EINVAL;
+ }
+
+ memcpy(sc->mac_address, &buf[1], sizeof(sc->mac_address));
+ } else if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
+ __u8 buf[18];
+
+ /*
+ * The MAC address of a Sixaxis controller connected via USB can
+ * be retrieved with feature report 0xf2. The address begins at
+ * offset 4.
+ */
+ ret = hid_hw_raw_request(sc->hdev, 0xf2, buf, sizeof(buf),
+ HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
+
+ if (ret != 18) {
+ hid_err(sc->hdev, "failed to retrieve feature report 0xf2 with the Sixaxis MAC address\n");
+ return ret < 0 ? ret : -EINVAL;
+ }
- return -EINVAL;
+ /*
+ * The Sixaxis device MAC in the report is big-endian and must
+ * be byte-swapped.
+ */
+ for (n = 0; n < 6; n++)
+ sc->mac_address[5-n] = buf[4+n];
+ } else {
+ return 0;
+ }
+
+ return sony_check_add_dev_list(sc);
}
+
static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
@@ -1075,18 +1616,52 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
- hdev->hid_output_raw_report = sixaxis_usb_output_raw_report;
+ /*
+ * The Sony Sixaxis does not handle HID Output Reports on the
+ * Interrupt EP like it could, so we need to force HID Output
+ * Reports to use HID_REQ_SET_REPORT on the Control EP.
+ *
+ * There is also another issue about HID Output Reports via USB,
+ * the Sixaxis does not want the report_id as part of the data
+ * packet, so we have to discard buf[0] when sending the actual
+ * control message, even for numbered reports, humpf!
+ */
+ hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
+ hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID;
ret = sixaxis_set_operational_usb(hdev);
+ sc->worker_initialized = 1;
INIT_WORK(&sc->state_worker, sixaxis_state_worker);
- }
- else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
+ } else if (sc->quirks & SIXAXIS_CONTROLLER_BT) {
+ /*
+ * The Sixaxis wants output reports sent on the ctrl endpoint
+ * when connected via Bluetooth.
+ */
+ hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
ret = sixaxis_set_operational_bt(hdev);
- else if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) {
- /* Report 5 (31 bytes) is used to send data to the controller via USB */
- ret = sony_set_output_report(sc, 0x05, 248);
+ sc->worker_initialized = 1;
+ INIT_WORK(&sc->state_worker, sixaxis_state_worker);
+ } else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
+ if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) {
+ /*
+ * The DualShock 4 wants output reports sent on the ctrl
+ * endpoint when connected via Bluetooth.
+ */
+ hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
+ ret = dualshock4_set_operational_bt(hdev);
+ if (ret < 0) {
+ hid_err(hdev, "failed to set the Dualshock 4 operational mode\n");
+ goto err_stop;
+ }
+ }
+ /*
+ * The Dualshock 4 touchpad supports 2 touches and has a
+ * resolution of 1920x940.
+ */
+ ret = sony_register_touchpad(sc, 2, 1920, 940);
if (ret < 0)
goto err_stop;
+ sc->worker_initialized = 1;
INIT_WORK(&sc->state_worker, dualshock4_state_worker);
} else {
ret = 0;
@@ -1095,20 +1670,46 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret < 0)
goto err_stop;
+ ret = sony_check_add(sc);
+ if (ret < 0)
+ goto err_stop;
+
if (sc->quirks & SONY_LED_SUPPORT) {
ret = sony_leds_init(hdev);
if (ret < 0)
goto err_stop;
}
- ret = sony_init_ff(hdev);
- if (ret < 0)
- goto err_stop;
+ if (sc->quirks & SONY_BATTERY_SUPPORT) {
+ ret = sony_battery_probe(sc);
+ if (ret < 0)
+ goto err_stop;
+
+ /* Open the device to receive reports with battery info */
+ ret = hid_hw_open(hdev);
+ if (ret < 0) {
+ hid_err(hdev, "hw open failed\n");
+ goto err_stop;
+ }
+ }
+
+ if (sc->quirks & SONY_FF_SUPPORT) {
+ ret = sony_init_ff(hdev);
+ if (ret < 0)
+ goto err_close;
+ }
return 0;
+err_close:
+ hid_hw_close(hdev);
err_stop:
if (sc->quirks & SONY_LED_SUPPORT)
sony_leds_remove(hdev);
+ if (sc->quirks & SONY_BATTERY_SUPPORT)
+ sony_battery_remove(sc);
+ if (sc->worker_initialized)
+ cancel_work_sync(&sc->state_worker);
+ sony_remove_dev_list(sc);
hid_hw_stop(hdev);
return ret;
}
@@ -1120,7 +1721,17 @@ static void sony_remove(struct hid_device *hdev)
if (sc->quirks & SONY_LED_SUPPORT)
sony_leds_remove(hdev);
- sony_destroy_ff(hdev);
+ if (sc->worker_initialized)
+ cancel_work_sync(&sc->state_worker);
+ if (sc->quirks & SONY_BATTERY_SUPPORT) {
+ hid_hw_close(hdev);
+ sony_battery_remove(sc);
+ }
+
+ if (sc->worker_initialized)
+ cancel_work_sync(&sc->state_worker);
+
+ sony_remove_dev_list(sc);
hid_hw_stop(hdev);
}
diff --git a/drivers/hid/hid-thingm.c b/drivers/hid/hid-thingm.c
index 99342cfa0ea2..a97c78845f7b 100644
--- a/drivers/hid/hid-thingm.c
+++ b/drivers/hid/hid-thingm.c
@@ -48,8 +48,8 @@ static int blink1_send_command(struct blink1_data *data,
buf[0], buf[1], buf[2], buf[3], buf[4],
buf[5], buf[6], buf[7], buf[8]);
- ret = data->hdev->hid_output_raw_report(data->hdev, buf,
- BLINK1_CMD_SIZE, HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(data->hdev, buf[0], buf, BLINK1_CMD_SIZE,
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
return ret < 0 ? ret : 0;
}
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
index 60c75dcbbdb8..902013ec041b 100644
--- a/drivers/hid/hid-wacom.c
+++ b/drivers/hid/hid-wacom.c
@@ -128,8 +128,8 @@ static void wacom_set_image(struct hid_device *hdev, const char *image,
rep_data[0] = WAC_CMD_ICON_START_STOP;
rep_data[1] = 0;
- ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
- HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret < 0)
goto err;
@@ -143,15 +143,15 @@ static void wacom_set_image(struct hid_device *hdev, const char *image,
rep_data[j + 3] = p[(i << 6) + j];
rep_data[2] = i;
- ret = hdev->hid_output_raw_report(hdev, rep_data, 67,
- HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 67,
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
}
rep_data[0] = WAC_CMD_ICON_START_STOP;
rep_data[1] = 0;
- ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
- HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
err:
return;
@@ -183,7 +183,8 @@ static void wacom_leds_set_brightness(struct led_classdev *led_dev,
buf[3] = value;
/* use fixed brightness for OLEDs */
buf[4] = 0x08;
- hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT);
+ hid_hw_raw_request(hdev, buf[0], buf, 9, HID_FEATURE_REPORT,
+ HID_REQ_SET_REPORT);
kfree(buf);
}
@@ -339,8 +340,8 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed)
rep_data[0] = 0x03 ; rep_data[1] = 0x00;
limit = 3;
do {
- ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
- HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
} while (ret < 0 && limit-- > 0);
if (ret >= 0) {
@@ -352,8 +353,9 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed)
rep_data[1] = 0x00;
limit = 3;
do {
- ret = hdev->hid_output_raw_report(hdev,
- rep_data, 2, HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(hdev, rep_data[0],
+ rep_data, 2, HID_FEATURE_REPORT,
+ HID_REQ_SET_REPORT);
} while (ret < 0 && limit-- > 0);
if (ret >= 0) {
@@ -378,8 +380,8 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed)
rep_data[0] = 0x03;
rep_data[1] = wdata->features;
- ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
- HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret >= 0)
wdata->high_speed = speed;
break;
diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c
index abb20db2b443..d00391418d1a 100644
--- a/drivers/hid/hid-wiimote-core.c
+++ b/drivers/hid/hid-wiimote-core.c
@@ -28,14 +28,14 @@ static int wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
__u8 *buf;
int ret;
- if (!hdev->hid_output_raw_report)
+ if (!hdev->ll_driver->output_report)
return -ENODEV;
buf = kmemdup(buffer, count, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- ret = hdev->hid_output_raw_report(hdev, buf, count, HID_OUTPUT_REPORT);
+ ret = hid_hw_output_report(hdev, buf, count);
kfree(buf);
return ret;
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index cb0137b3718d..9c2d7c23f296 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -123,10 +123,6 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
dev = hidraw_table[minor]->hid;
- if (!dev->hid_output_raw_report) {
- ret = -ENODEV;
- goto out;
- }
if (count > HID_MAX_BUFFER_SIZE) {
hid_warn(dev, "pid %d passed too large report\n",
@@ -153,7 +149,21 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
goto out_free;
}
- ret = dev->hid_output_raw_report(dev, buf, count, report_type);
+ if ((report_type == HID_OUTPUT_REPORT) &&
+ !(dev->quirks & HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP)) {
+ ret = hid_hw_output_report(dev, buf, count);
+ /*
+ * compatibility with old implementation of USB-HID and I2C-HID:
+ * if the device does not support receiving output reports,
+ * on an interrupt endpoint, fallback to SET_REPORT HID command.
+ */
+ if (ret != -ENOSYS)
+ goto out_free;
+ }
+
+ ret = hid_hw_raw_request(dev, buf[0], buf, count, report_type,
+ HID_REQ_SET_REPORT);
+
out_free:
kfree(buf);
out:
@@ -189,7 +199,7 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
dev = hidraw_table[minor]->hid;
- if (!dev->hid_get_raw_report) {
+ if (!dev->ll_driver->raw_request) {
ret = -ENODEV;
goto out;
}
@@ -216,14 +226,15 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
/*
* Read the first byte from the user. This is the report number,
- * which is passed to dev->hid_get_raw_report().
+ * which is passed to hid_hw_raw_request().
*/
if (copy_from_user(&report_number, buffer, 1)) {
ret = -EFAULT;
goto out_free;
}
- ret = dev->hid_get_raw_report(dev, report_number, buf, count, report_type);
+ ret = hid_hw_raw_request(dev, report_number, buf, count, report_type,
+ HID_REQ_GET_REPORT);
if (ret < 0)
goto out_free;
@@ -320,13 +331,13 @@ static void drop_ref(struct hidraw *hidraw, int exists_bit)
hid_hw_close(hidraw->hid);
wake_up_interruptible(&hidraw->wait);
}
+ device_destroy(hidraw_class,
+ MKDEV(hidraw_major, hidraw->minor));
} else {
--hidraw->open;
}
if (!hidraw->open) {
if (!hidraw->exist) {
- device_destroy(hidraw_class,
- MKDEV(hidraw_major, hidraw->minor));
hidraw_table[hidraw->minor] = NULL;
kfree(hidraw);
} else {
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index d1f81f52481a..b50860db92f1 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -25,6 +25,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pm.h>
+#include <linux/pm_runtime.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/err.h>
@@ -256,18 +257,27 @@ static int i2c_hid_get_report(struct i2c_client *client, u8 reportType,
return 0;
}
-static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,
- u8 reportID, unsigned char *buf, size_t data_len)
+/**
+ * i2c_hid_set_or_send_report: forward an incoming report to the device
+ * @client: the i2c_client of the device
+ * @reportType: 0x03 for HID_FEATURE_REPORT ; 0x02 for HID_OUTPUT_REPORT
+ * @reportID: the report ID
+ * @buf: the actual data to transfer, without the report ID
+ * @len: size of buf
+ * @use_data: true: use SET_REPORT HID command, false: send plain OUTPUT report
+ */
+static int i2c_hid_set_or_send_report(struct i2c_client *client, u8 reportType,
+ u8 reportID, unsigned char *buf, size_t data_len, bool use_data)
{
struct i2c_hid *ihid = i2c_get_clientdata(client);
u8 *args = ihid->argsbuf;
- const struct i2c_hid_cmd * hidcmd = &hid_set_report_cmd;
+ const struct i2c_hid_cmd *hidcmd;
int ret;
u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister);
u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister);
u16 maxOutputLength = le16_to_cpu(ihid->hdesc.wMaxOutputLength);
- /* hidraw already checked that data_len < HID_MAX_BUFFER_SIZE */
+ /* hid_hw_* already checked that data_len < HID_MAX_BUFFER_SIZE */
u16 size = 2 /* size */ +
(reportID ? 1 : 0) /* reportID */ +
data_len /* buf */;
@@ -278,6 +288,9 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,
i2c_hid_dbg(ihid, "%s\n", __func__);
+ if (!use_data && maxOutputLength == 0)
+ return -ENOSYS;
+
if (reportID >= 0x0F) {
args[index++] = reportID;
reportID = 0x0F;
@@ -287,9 +300,10 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,
* use the data register for feature reports or if the device does not
* support the output register
*/
- if (reportType == 0x03 || maxOutputLength == 0) {
+ if (use_data) {
args[index++] = dataRegister & 0xFF;
args[index++] = dataRegister >> 8;
+ hidcmd = &hid_set_report_cmd;
} else {
args[index++] = outputRegister & 0xFF;
args[index++] = outputRegister >> 8;
@@ -454,10 +468,18 @@ static void i2c_hid_init_reports(struct hid_device *hid)
return;
}
+ /*
+ * The device must be powered on while we fetch initial reports
+ * from it.
+ */
+ pm_runtime_get_sync(&client->dev);
+
list_for_each_entry(report,
&hid->report_enum[HID_FEATURE_REPORT].report_list, list)
i2c_hid_init_report(report, inbuf, ihid->bufsize);
+ pm_runtime_put(&client->dev);
+
kfree(inbuf);
}
@@ -550,7 +572,7 @@ static int i2c_hid_get_raw_report(struct hid_device *hid,
}
static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
- size_t count, unsigned char report_type)
+ size_t count, unsigned char report_type, bool use_data)
{
struct i2c_client *client = hid->driver_data;
int report_id = buf[0];
@@ -564,9 +586,9 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
count--;
}
- ret = i2c_hid_set_report(client,
+ ret = i2c_hid_set_or_send_report(client,
report_type == HID_FEATURE_REPORT ? 0x03 : 0x02,
- report_id, buf, count);
+ report_id, buf, count, use_data);
if (report_id && ret >= 0)
ret++; /* add report_id to the number of transfered bytes */
@@ -574,34 +596,27 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
return ret;
}
-static void i2c_hid_request(struct hid_device *hid, struct hid_report *rep,
- int reqtype)
+static int i2c_hid_output_report(struct hid_device *hid, __u8 *buf,
+ size_t count)
{
- struct i2c_client *client = hid->driver_data;
- char *buf;
- int ret;
- int len = i2c_hid_get_report_length(rep) - 2;
-
- buf = kzalloc(len, GFP_KERNEL);
- if (!buf)
- return;
+ return i2c_hid_output_raw_report(hid, buf, count, HID_OUTPUT_REPORT,
+ false);
+}
+static int i2c_hid_raw_request(struct hid_device *hid, unsigned char reportnum,
+ __u8 *buf, size_t len, unsigned char rtype,
+ int reqtype)
+{
switch (reqtype) {
case HID_REQ_GET_REPORT:
- ret = i2c_hid_get_raw_report(hid, rep->id, buf, len, rep->type);
- if (ret < 0)
- dev_err(&client->dev, "%s: unable to get report: %d\n",
- __func__, ret);
- else
- hid_input_report(hid, rep->type, buf, ret, 0);
- break;
+ return i2c_hid_get_raw_report(hid, reportnum, buf, len, rtype);
case HID_REQ_SET_REPORT:
- hid_output_report(rep, buf);
- i2c_hid_output_raw_report(hid, buf, len, rep->type);
- break;
+ if (buf[0] != reportnum)
+ return -EINVAL;
+ return i2c_hid_output_raw_report(hid, buf, len, rtype, true);
+ default:
+ return -EIO;
}
-
- kfree(buf);
}
static int i2c_hid_parse(struct hid_device *hid)
@@ -703,8 +718,8 @@ static int i2c_hid_open(struct hid_device *hid)
mutex_lock(&i2c_hid_open_mut);
if (!hid->open++) {
- ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
- if (ret) {
+ ret = pm_runtime_get_sync(&client->dev);
+ if (ret < 0) {
hid->open--;
goto done;
}
@@ -712,7 +727,7 @@ static int i2c_hid_open(struct hid_device *hid)
}
done:
mutex_unlock(&i2c_hid_open_mut);
- return ret;
+ return ret < 0 ? ret : 0;
}
static void i2c_hid_close(struct hid_device *hid)
@@ -729,7 +744,7 @@ static void i2c_hid_close(struct hid_device *hid)
clear_bit(I2C_HID_STARTED, &ihid->flags);
/* Save some power */
- i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
+ pm_runtime_put(&client->dev);
}
mutex_unlock(&i2c_hid_open_mut);
}
@@ -738,19 +753,18 @@ static int i2c_hid_power(struct hid_device *hid, int lvl)
{
struct i2c_client *client = hid->driver_data;
struct i2c_hid *ihid = i2c_get_clientdata(client);
- int ret = 0;
i2c_hid_dbg(ihid, "%s lvl:%d\n", __func__, lvl);
switch (lvl) {
case PM_HINT_FULLON:
- ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
+ pm_runtime_get_sync(&client->dev);
break;
case PM_HINT_NORMAL:
- ret = i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
+ pm_runtime_put(&client->dev);
break;
}
- return ret;
+ return 0;
}
static struct hid_ll_driver i2c_hid_ll_driver = {
@@ -760,7 +774,8 @@ static struct hid_ll_driver i2c_hid_ll_driver = {
.open = i2c_hid_open,
.close = i2c_hid_close,
.power = i2c_hid_power,
- .request = i2c_hid_request,
+ .output_report = i2c_hid_output_report,
+ .raw_request = i2c_hid_raw_request,
};
static int i2c_hid_init_irq(struct i2c_client *client)
@@ -973,13 +988,17 @@ static int i2c_hid_probe(struct i2c_client *client,
if (ret < 0)
goto err;
+ pm_runtime_get_noresume(&client->dev);
+ pm_runtime_set_active(&client->dev);
+ pm_runtime_enable(&client->dev);
+
ret = i2c_hid_fetch_hid_descriptor(ihid);
if (ret < 0)
- goto err;
+ goto err_pm;
ret = i2c_hid_init_irq(client);
if (ret < 0)
- goto err;
+ goto err_pm;
hid = hid_allocate_device();
if (IS_ERR(hid)) {
@@ -991,8 +1010,6 @@ static int i2c_hid_probe(struct i2c_client *client,
hid->driver_data = client;
hid->ll_driver = &i2c_hid_ll_driver;
- hid->hid_get_raw_report = i2c_hid_get_raw_report;
- hid->hid_output_raw_report = i2c_hid_output_raw_report;
hid->dev.parent = &client->dev;
ACPI_COMPANION_SET(&hid->dev, ACPI_COMPANION(&client->dev));
hid->bus = BUS_I2C;
@@ -1010,6 +1027,7 @@ static int i2c_hid_probe(struct i2c_client *client,
goto err_mem_free;
}
+ pm_runtime_put(&client->dev);
return 0;
err_mem_free:
@@ -1018,6 +1036,10 @@ err_mem_free:
err_irq:
free_irq(client->irq, ihid);
+err_pm:
+ pm_runtime_put_noidle(&client->dev);
+ pm_runtime_disable(&client->dev);
+
err:
i2c_hid_free_buffers(ihid);
kfree(ihid);
@@ -1029,6 +1051,11 @@ static int i2c_hid_remove(struct i2c_client *client)
struct i2c_hid *ihid = i2c_get_clientdata(client);
struct hid_device *hid;
+ pm_runtime_get_sync(&client->dev);
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+ pm_runtime_put_noidle(&client->dev);
+
hid = ihid->hid;
hid_destroy_device(hid);
@@ -1074,7 +1101,31 @@ static int i2c_hid_resume(struct device *dev)
}
#endif
-static SIMPLE_DEV_PM_OPS(i2c_hid_pm, i2c_hid_suspend, i2c_hid_resume);
+#ifdef CONFIG_PM_RUNTIME
+static int i2c_hid_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
+ disable_irq(client->irq);
+ return 0;
+}
+
+static int i2c_hid_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ enable_irq(client->irq);
+ i2c_hid_set_power(client, I2C_HID_PWR_ON);
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops i2c_hid_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(i2c_hid_suspend, i2c_hid_resume)
+ SET_RUNTIME_PM_OPS(i2c_hid_runtime_suspend, i2c_hid_runtime_resume,
+ NULL)
+};
static const struct i2c_device_id i2c_hid_id_table[] = {
{ "hid", 0 },
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index cedc6da93c19..0d078c32db4f 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -244,12 +244,35 @@ static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count,
return count;
}
+static int uhid_hid_output_report(struct hid_device *hid, __u8 *buf,
+ size_t count)
+{
+ return uhid_hid_output_raw(hid, buf, count, HID_OUTPUT_REPORT);
+}
+
+static int uhid_raw_request(struct hid_device *hid, unsigned char reportnum,
+ __u8 *buf, size_t len, unsigned char rtype,
+ int reqtype)
+{
+ switch (reqtype) {
+ case HID_REQ_GET_REPORT:
+ return uhid_hid_get_raw(hid, reportnum, buf, len, rtype);
+ case HID_REQ_SET_REPORT:
+ /* TODO: implement proper SET_REPORT functionality */
+ return -ENOSYS;
+ default:
+ return -EIO;
+ }
+}
+
static struct hid_ll_driver uhid_hid_driver = {
.start = uhid_hid_start,
.stop = uhid_hid_stop,
.open = uhid_hid_open,
.close = uhid_hid_close,
.parse = uhid_hid_parse,
+ .output_report = uhid_hid_output_report,
+ .raw_request = uhid_raw_request,
};
#ifdef CONFIG_COMPAT
@@ -377,8 +400,6 @@ static int uhid_dev_create(struct uhid_device *uhid,
hid->uniq[63] = 0;
hid->ll_driver = &uhid_hid_driver;
- hid->hid_get_raw_report = uhid_hid_get_raw;
- hid->hid_output_raw_report = uhid_hid_output_raw;
hid->bus = ev->u.create.bus;
hid->vendor = ev->u.create.vendor;
hid->product = ev->u.create.product;
@@ -407,6 +428,67 @@ err_free:
return ret;
}
+static int uhid_dev_create2(struct uhid_device *uhid,
+ const struct uhid_event *ev)
+{
+ struct hid_device *hid;
+ int ret;
+
+ if (uhid->running)
+ return -EALREADY;
+
+ uhid->rd_size = ev->u.create2.rd_size;
+ if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE)
+ return -EINVAL;
+
+ uhid->rd_data = kmalloc(uhid->rd_size, GFP_KERNEL);
+ if (!uhid->rd_data)
+ return -ENOMEM;
+
+ memcpy(uhid->rd_data, ev->u.create2.rd_data, uhid->rd_size);
+
+ hid = hid_allocate_device();
+ if (IS_ERR(hid)) {
+ ret = PTR_ERR(hid);
+ goto err_free;
+ }
+
+ strncpy(hid->name, ev->u.create2.name, 127);
+ hid->name[127] = 0;
+ strncpy(hid->phys, ev->u.create2.phys, 63);
+ hid->phys[63] = 0;
+ strncpy(hid->uniq, ev->u.create2.uniq, 63);
+ hid->uniq[63] = 0;
+
+ hid->ll_driver = &uhid_hid_driver;
+ hid->bus = ev->u.create2.bus;
+ hid->vendor = ev->u.create2.vendor;
+ hid->product = ev->u.create2.product;
+ hid->version = ev->u.create2.version;
+ hid->country = ev->u.create2.country;
+ hid->driver_data = uhid;
+ hid->dev.parent = uhid_misc.this_device;
+
+ uhid->hid = hid;
+ uhid->running = true;
+
+ ret = hid_add_device(hid);
+ if (ret) {
+ hid_err(hid, "Cannot register HID device\n");
+ goto err_hid;
+ }
+
+ return 0;
+
+err_hid:
+ hid_destroy_device(hid);
+ uhid->hid = NULL;
+ uhid->running = false;
+err_free:
+ kfree(uhid->rd_data);
+ return ret;
+}
+
static int uhid_dev_destroy(struct uhid_device *uhid)
{
if (!uhid->running)
@@ -435,6 +517,17 @@ static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
return 0;
}
+static int uhid_dev_input2(struct uhid_device *uhid, struct uhid_event *ev)
+{
+ if (!uhid->running)
+ return -EINVAL;
+
+ hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data,
+ min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0);
+
+ return 0;
+}
+
static int uhid_dev_feature_answer(struct uhid_device *uhid,
struct uhid_event *ev)
{
@@ -571,12 +664,18 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
case UHID_CREATE:
ret = uhid_dev_create(uhid, &uhid->input_buf);
break;
+ case UHID_CREATE2:
+ ret = uhid_dev_create2(uhid, &uhid->input_buf);
+ break;
case UHID_DESTROY:
ret = uhid_dev_destroy(uhid);
break;
case UHID_INPUT:
ret = uhid_dev_input(uhid, &uhid->input_buf);
break;
+ case UHID_INPUT2:
+ ret = uhid_dev_input2(uhid, &uhid->input_buf);
+ break;
case UHID_FEATURE_ANSWER:
ret = uhid_dev_feature_answer(uhid, &uhid->input_buf);
break;
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 44df131d390a..7b88f4cb9902 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -884,52 +884,66 @@ static int usbhid_get_raw_report(struct hid_device *hid,
return ret;
}
-static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count,
- unsigned char report_type)
+static int usbhid_set_raw_report(struct hid_device *hid, unsigned int reportnum,
+ __u8 *buf, size_t count, unsigned char rtype)
{
struct usbhid_device *usbhid = hid->driver_data;
struct usb_device *dev = hid_to_usb_dev(hid);
struct usb_interface *intf = usbhid->intf;
struct usb_host_interface *interface = intf->cur_altsetting;
- int ret;
+ int ret, skipped_report_id = 0;
- if (usbhid->urbout && report_type != HID_FEATURE_REPORT) {
- int actual_length;
- int skipped_report_id = 0;
+ /* Byte 0 is the report number. Report data starts at byte 1.*/
+ if ((rtype == HID_OUTPUT_REPORT) &&
+ (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORT_ID))
+ buf[0] = 0;
+ else
+ buf[0] = reportnum;
+
+ if (buf[0] == 0x0) {
+ /* Don't send the Report ID */
+ buf++;
+ count--;
+ skipped_report_id = 1;
+ }
- if (buf[0] == 0x0) {
- /* Don't send the Report ID */
- buf++;
- count--;
- skipped_report_id = 1;
- }
- ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
- buf, count, &actual_length,
- USB_CTRL_SET_TIMEOUT);
- /* return the number of bytes transferred */
- if (ret == 0) {
- ret = actual_length;
- /* count also the report id */
- if (skipped_report_id)
- ret++;
- }
- } else {
- int skipped_report_id = 0;
- int report_id = buf[0];
- if (buf[0] == 0x0) {
- /* Don't send the Report ID */
- buf++;
- count--;
- skipped_report_id = 1;
- }
- ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
HID_REQ_SET_REPORT,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- ((report_type + 1) << 8) | report_id,
+ ((rtype + 1) << 8) | reportnum,
interface->desc.bInterfaceNumber, buf, count,
USB_CTRL_SET_TIMEOUT);
- /* count also the report id, if this was a numbered report. */
- if (ret > 0 && skipped_report_id)
+ /* count also the report id, if this was a numbered report. */
+ if (ret > 0 && skipped_report_id)
+ ret++;
+
+ return ret;
+}
+
+static int usbhid_output_report(struct hid_device *hid, __u8 *buf, size_t count)
+{
+ struct usbhid_device *usbhid = hid->driver_data;
+ struct usb_device *dev = hid_to_usb_dev(hid);
+ int actual_length, skipped_report_id = 0, ret;
+
+ if (!usbhid->urbout)
+ return -ENOSYS;
+
+ if (buf[0] == 0x0) {
+ /* Don't send the Report ID */
+ buf++;
+ count--;
+ skipped_report_id = 1;
+ }
+
+ ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
+ buf, count, &actual_length,
+ USB_CTRL_SET_TIMEOUT);
+ /* return the number of bytes transferred */
+ if (ret == 0) {
+ ret = actual_length;
+ /* count also the report id */
+ if (skipped_report_id)
ret++;
}
@@ -1200,6 +1214,20 @@ static void usbhid_request(struct hid_device *hid, struct hid_report *rep, int r
}
}
+static int usbhid_raw_request(struct hid_device *hid, unsigned char reportnum,
+ __u8 *buf, size_t len, unsigned char rtype,
+ int reqtype)
+{
+ switch (reqtype) {
+ case HID_REQ_GET_REPORT:
+ return usbhid_get_raw_report(hid, reportnum, buf, len, rtype);
+ case HID_REQ_SET_REPORT:
+ return usbhid_set_raw_report(hid, reportnum, buf, len, rtype);
+ default:
+ return -EIO;
+ }
+}
+
static int usbhid_idle(struct hid_device *hid, int report, int idle,
int reqtype)
{
@@ -1223,6 +1251,8 @@ static struct hid_ll_driver usb_hid_driver = {
.power = usbhid_power,
.request = usbhid_request,
.wait = usbhid_wait_io,
+ .raw_request = usbhid_raw_request,
+ .output_report = usbhid_output_report,
.idle = usbhid_idle,
};
@@ -1253,8 +1283,6 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
usb_set_intfdata(intf, hid);
hid->ll_driver = &usb_hid_driver;
- hid->hid_get_raw_report = usbhid_get_raw_report;
- hid->hid_output_raw_report = usbhid_output_raw_report;
hid->ff_init = hid_pidff_init;
#ifdef CONFIG_USB_HIDDEV
hid->hiddev_connect = hiddev_connect;
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 175ec0afb70c..dbd83878ff99 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -74,6 +74,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS },
diff --git a/drivers/hv/Makefile b/drivers/hv/Makefile
index 0a74b5661186..5e4dfa4cfe22 100644
--- a/drivers/hv/Makefile
+++ b/drivers/hv/Makefile
@@ -5,4 +5,4 @@ obj-$(CONFIG_HYPERV_BALLOON) += hv_balloon.o
hv_vmbus-y := vmbus_drv.o \
hv.o connection.o channel.o \
channel_mgmt.o ring_buffer.o
-hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o
+hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_fcopy.o
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index 69ea36f07b4d..602ca86a6488 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -27,6 +27,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/hyperv.h>
+#include <linux/uio.h>
#include "hyperv_vmbus.h"
@@ -554,14 +555,14 @@ EXPORT_SYMBOL_GPL(vmbus_close);
*
* Mainly used by Hyper-V drivers.
*/
-int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer,
+int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer,
u32 bufferlen, u64 requestid,
enum vmbus_packet_type type, u32 flags)
{
struct vmpacket_descriptor desc;
u32 packetlen = sizeof(struct vmpacket_descriptor) + bufferlen;
u32 packetlen_aligned = ALIGN(packetlen, sizeof(u64));
- struct scatterlist bufferlist[3];
+ struct kvec bufferlist[3];
u64 aligned_data = 0;
int ret;
bool signal = false;
@@ -575,11 +576,12 @@ int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer,
desc.len8 = (u16)(packetlen_aligned >> 3);
desc.trans_id = requestid;
- sg_init_table(bufferlist, 3);
- sg_set_buf(&bufferlist[0], &desc, sizeof(struct vmpacket_descriptor));
- sg_set_buf(&bufferlist[1], buffer, bufferlen);
- sg_set_buf(&bufferlist[2], &aligned_data,
- packetlen_aligned - packetlen);
+ bufferlist[0].iov_base = &desc;
+ bufferlist[0].iov_len = sizeof(struct vmpacket_descriptor);
+ bufferlist[1].iov_base = buffer;
+ bufferlist[1].iov_len = bufferlen;
+ bufferlist[2].iov_base = &aligned_data;
+ bufferlist[2].iov_len = (packetlen_aligned - packetlen);
ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
@@ -605,7 +607,7 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
u32 descsize;
u32 packetlen;
u32 packetlen_aligned;
- struct scatterlist bufferlist[3];
+ struct kvec bufferlist[3];
u64 aligned_data = 0;
bool signal = false;
@@ -637,11 +639,12 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
desc.range[i].pfn = pagebuffers[i].pfn;
}
- sg_init_table(bufferlist, 3);
- sg_set_buf(&bufferlist[0], &desc, descsize);
- sg_set_buf(&bufferlist[1], buffer, bufferlen);
- sg_set_buf(&bufferlist[2], &aligned_data,
- packetlen_aligned - packetlen);
+ bufferlist[0].iov_base = &desc;
+ bufferlist[0].iov_len = descsize;
+ bufferlist[1].iov_base = buffer;
+ bufferlist[1].iov_len = bufferlen;
+ bufferlist[2].iov_base = &aligned_data;
+ bufferlist[2].iov_len = (packetlen_aligned - packetlen);
ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
@@ -665,7 +668,7 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
u32 descsize;
u32 packetlen;
u32 packetlen_aligned;
- struct scatterlist bufferlist[3];
+ struct kvec bufferlist[3];
u64 aligned_data = 0;
bool signal = false;
u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->offset,
@@ -700,11 +703,12 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
memcpy(desc.range.pfn_array, multi_pagebuffer->pfn_array,
pfncount * sizeof(u64));
- sg_init_table(bufferlist, 3);
- sg_set_buf(&bufferlist[0], &desc, descsize);
- sg_set_buf(&bufferlist[1], buffer, bufferlen);
- sg_set_buf(&bufferlist[2], &aligned_data,
- packetlen_aligned - packetlen);
+ bufferlist[0].iov_base = &desc;
+ bufferlist[0].iov_len = descsize;
+ bufferlist[1].iov_base = buffer;
+ bufferlist[1].iov_len = bufferlen;
+ bufferlist[2].iov_base = &aligned_data;
+ bufferlist[2].iov_len = (packetlen_aligned - packetlen);
ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index af6edf9b1936..f2d7bf90c9fe 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -67,7 +67,6 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
int ret = 0;
struct vmbus_channel_initiate_contact *msg;
unsigned long flags;
- int t;
init_completion(&msginfo->waitevent);
@@ -78,6 +77,8 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]);
msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]);
+ if (version == VERSION_WIN8)
+ msg->target_vcpu = hv_context.vp_index[smp_processor_id()];
/*
* Add to list before we send the request since we may
@@ -100,15 +101,7 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
}
/* Wait for the connection response */
- t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
- if (t == 0) {
- spin_lock_irqsave(&vmbus_connection.channelmsg_lock,
- flags);
- list_del(&msginfo->msglistentry);
- spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock,
- flags);
- return -ETIMEDOUT;
- }
+ wait_for_completion(&msginfo->waitevent);
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
list_del(&msginfo->msglistentry);
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
index 7e17a5495e02..7e6d78dc9437 100644
--- a/drivers/hv/hv_balloon.c
+++ b/drivers/hv/hv_balloon.c
@@ -1171,7 +1171,8 @@ static int dm_thread_func(void *dm_dev)
int t;
while (!kthread_should_stop()) {
- t = wait_for_completion_timeout(&dm_device.config_event, 1*HZ);
+ t = wait_for_completion_interruptible_timeout(
+ &dm_device.config_event, 1*HZ);
/*
* The host expects us to post information on the memory
* pressure every second.
diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c
new file mode 100644
index 000000000000..eaaa3d843b80
--- /dev/null
+++ b/drivers/hv/hv_fcopy.c
@@ -0,0 +1,414 @@
+/*
+ * An implementation of file copy service.
+ *
+ * Copyright (C) 2014, Microsoft, Inc.
+ *
+ * Author : K. Y. Srinivasan <ksrinivasan@novell.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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/semaphore.h>
+#include <linux/fs.h>
+#include <linux/nls.h>
+#include <linux/workqueue.h>
+#include <linux/cdev.h>
+#include <linux/hyperv.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+
+#include "hyperv_vmbus.h"
+
+#define WIN8_SRV_MAJOR 1
+#define WIN8_SRV_MINOR 1
+#define WIN8_SRV_VERSION (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
+
+/*
+ * Global state maintained for transaction that is being processed.
+ * For a class of integration services, including the "file copy service",
+ * the specified protocol is a "request/response" protocol which means that
+ * there can only be single outstanding transaction from the host at any
+ * given point in time. We use this to simplify memory management in this
+ * driver - we cache and process only one message at a time.
+ *
+ * While the request/response protocol is guaranteed by the host, we further
+ * ensure this by serializing packet processing in this driver - we do not
+ * read additional packets from the VMBUs until the current packet is fully
+ * handled.
+ *
+ * The transaction "active" state is set when we receive a request from the
+ * host and we cleanup this state when the transaction is completed - when we
+ * respond to the host with our response. When the transaction active state is
+ * set, we defer handling incoming packets.
+ */
+
+static struct {
+ bool active; /* transaction status - active or not */
+ int recv_len; /* number of bytes received. */
+ struct hv_fcopy_hdr *fcopy_msg; /* current message */
+ struct hv_start_fcopy message; /* sent to daemon */
+ struct vmbus_channel *recv_channel; /* chn we got the request */
+ u64 recv_req_id; /* request ID. */
+ void *fcopy_context; /* for the channel callback */
+ struct semaphore read_sema;
+} fcopy_transaction;
+
+static bool opened; /* currently device opened */
+
+/*
+ * Before we can accept copy messages from the host, we need
+ * to handshake with the user level daemon. This state tracks
+ * if we are in the handshake phase.
+ */
+static bool in_hand_shake = true;
+static void fcopy_send_data(void);
+static void fcopy_respond_to_host(int error);
+static void fcopy_work_func(struct work_struct *dummy);
+static DECLARE_DELAYED_WORK(fcopy_work, fcopy_work_func);
+static u8 *recv_buffer;
+
+static void fcopy_work_func(struct work_struct *dummy)
+{
+ /*
+ * If the timer fires, the user-mode component has not responded;
+ * process the pending transaction.
+ */
+ fcopy_respond_to_host(HV_E_FAIL);
+}
+
+static int fcopy_handle_handshake(u32 version)
+{
+ switch (version) {
+ case FCOPY_CURRENT_VERSION:
+ break;
+ default:
+ /*
+ * For now we will fail the registration.
+ * If and when we have multiple versions to
+ * deal with, we will be backward compatible.
+ * We will add this code when needed.
+ */
+ return -EINVAL;
+ }
+ pr_info("FCP: user-mode registering done. Daemon version: %d\n",
+ version);
+ fcopy_transaction.active = false;
+ if (fcopy_transaction.fcopy_context)
+ hv_fcopy_onchannelcallback(fcopy_transaction.fcopy_context);
+ in_hand_shake = false;
+ return 0;
+}
+
+static void fcopy_send_data(void)
+{
+ struct hv_start_fcopy *smsg_out = &fcopy_transaction.message;
+ int operation = fcopy_transaction.fcopy_msg->operation;
+ struct hv_start_fcopy *smsg_in;
+
+ /*
+ * The strings sent from the host are encoded in
+ * in utf16; convert it to utf8 strings.
+ * The host assures us that the utf16 strings will not exceed
+ * the max lengths specified. We will however, reserve room
+ * for the string terminating character - in the utf16s_utf8s()
+ * function we limit the size of the buffer where the converted
+ * string is placed to W_MAX_PATH -1 to guarantee
+ * that the strings can be properly terminated!
+ */
+
+ switch (operation) {
+ case START_FILE_COPY:
+ memset(smsg_out, 0, sizeof(struct hv_start_fcopy));
+ smsg_out->hdr.operation = operation;
+ smsg_in = (struct hv_start_fcopy *)fcopy_transaction.fcopy_msg;
+
+ utf16s_to_utf8s((wchar_t *)smsg_in->file_name, W_MAX_PATH,
+ UTF16_LITTLE_ENDIAN,
+ (__u8 *)smsg_out->file_name, W_MAX_PATH - 1);
+
+ utf16s_to_utf8s((wchar_t *)smsg_in->path_name, W_MAX_PATH,
+ UTF16_LITTLE_ENDIAN,
+ (__u8 *)smsg_out->path_name, W_MAX_PATH - 1);
+
+ smsg_out->copy_flags = smsg_in->copy_flags;
+ smsg_out->file_size = smsg_in->file_size;
+ break;
+
+ default:
+ break;
+ }
+ up(&fcopy_transaction.read_sema);
+ return;
+}
+
+/*
+ * Send a response back to the host.
+ */
+
+static void
+fcopy_respond_to_host(int error)
+{
+ struct icmsg_hdr *icmsghdr;
+ u32 buf_len;
+ struct vmbus_channel *channel;
+ u64 req_id;
+
+ /*
+ * Copy the global state for completing the transaction. Note that
+ * only one transaction can be active at a time. This is guaranteed
+ * by the file copy protocol implemented by the host. Furthermore,
+ * the "transaction active" state we maintain ensures that there can
+ * only be one active transaction at a time.
+ */
+
+ buf_len = fcopy_transaction.recv_len;
+ channel = fcopy_transaction.recv_channel;
+ req_id = fcopy_transaction.recv_req_id;
+
+ fcopy_transaction.active = false;
+
+ icmsghdr = (struct icmsg_hdr *)
+ &recv_buffer[sizeof(struct vmbuspipe_hdr)];
+
+ if (channel->onchannel_callback == NULL)
+ /*
+ * We have raced with util driver being unloaded;
+ * silently return.
+ */
+ return;
+
+ icmsghdr->status = error;
+ icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
+ vmbus_sendpacket(channel, recv_buffer, buf_len, req_id,
+ VM_PKT_DATA_INBAND, 0);
+}
+
+void hv_fcopy_onchannelcallback(void *context)
+{
+ struct vmbus_channel *channel = context;
+ u32 recvlen;
+ u64 requestid;
+ struct hv_fcopy_hdr *fcopy_msg;
+ struct icmsg_hdr *icmsghdr;
+ struct icmsg_negotiate *negop = NULL;
+ int util_fw_version;
+ int fcopy_srv_version;
+
+ if (fcopy_transaction.active) {
+ /*
+ * We will defer processing this callback once
+ * the current transaction is complete.
+ */
+ fcopy_transaction.fcopy_context = context;
+ return;
+ }
+
+ vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
+ &requestid);
+ if (recvlen <= 0)
+ return;
+
+ icmsghdr = (struct icmsg_hdr *)&recv_buffer[
+ sizeof(struct vmbuspipe_hdr)];
+ if (icmsghdr->icmsgtype == ICMSGTYPE_NEGOTIATE) {
+ util_fw_version = UTIL_FW_VERSION;
+ fcopy_srv_version = WIN8_SRV_VERSION;
+ vmbus_prep_negotiate_resp(icmsghdr, negop, recv_buffer,
+ util_fw_version, fcopy_srv_version);
+ } else {
+ fcopy_msg = (struct hv_fcopy_hdr *)&recv_buffer[
+ sizeof(struct vmbuspipe_hdr) +
+ sizeof(struct icmsg_hdr)];
+
+ /*
+ * Stash away this global state for completing the
+ * transaction; note transactions are serialized.
+ */
+
+ fcopy_transaction.active = true;
+ fcopy_transaction.recv_len = recvlen;
+ fcopy_transaction.recv_channel = channel;
+ fcopy_transaction.recv_req_id = requestid;
+ fcopy_transaction.fcopy_msg = fcopy_msg;
+
+ /*
+ * Send the information to the user-level daemon.
+ */
+ fcopy_send_data();
+ schedule_delayed_work(&fcopy_work, 5*HZ);
+ return;
+ }
+ icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
+ vmbus_sendpacket(channel, recv_buffer, recvlen, requestid,
+ VM_PKT_DATA_INBAND, 0);
+}
+
+/*
+ * Create a char device that can support read/write for passing
+ * the payload.
+ */
+
+static ssize_t fcopy_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ void *src;
+ size_t copy_size;
+ int operation;
+
+ /*
+ * Wait until there is something to be read.
+ */
+ if (down_interruptible(&fcopy_transaction.read_sema))
+ return -EINTR;
+
+ /*
+ * The channel may be rescinded and in this case, we will wakeup the
+ * the thread blocked on the semaphore and we will use the opened
+ * state to correctly handle this case.
+ */
+ if (!opened)
+ return -ENODEV;
+
+ operation = fcopy_transaction.fcopy_msg->operation;
+
+ if (operation == START_FILE_COPY) {
+ src = &fcopy_transaction.message;
+ copy_size = sizeof(struct hv_start_fcopy);
+ if (count < copy_size)
+ return 0;
+ } else {
+ src = fcopy_transaction.fcopy_msg;
+ copy_size = sizeof(struct hv_do_fcopy);
+ if (count < copy_size)
+ return 0;
+ }
+ if (copy_to_user(buf, src, copy_size))
+ return -EFAULT;
+
+ return copy_size;
+}
+
+static ssize_t fcopy_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int response = 0;
+
+ if (count != sizeof(int))
+ return -EINVAL;
+
+ if (copy_from_user(&response, buf, sizeof(int)))
+ return -EFAULT;
+
+ if (in_hand_shake) {
+ if (fcopy_handle_handshake(response))
+ return -EINVAL;
+ return sizeof(int);
+ }
+
+ /*
+ * Complete the transaction by forwarding the result
+ * to the host. But first, cancel the timeout.
+ */
+ if (cancel_delayed_work_sync(&fcopy_work))
+ fcopy_respond_to_host(response);
+
+ return sizeof(int);
+}
+
+static int fcopy_open(struct inode *inode, struct file *f)
+{
+ /*
+ * The user level daemon that will open this device is
+ * really an extension of this driver. We can have only
+ * active open at a time.
+ */
+ if (opened)
+ return -EBUSY;
+
+ /*
+ * The daemon is alive; setup the state.
+ */
+ opened = true;
+ return 0;
+}
+
+static int fcopy_release(struct inode *inode, struct file *f)
+{
+ /*
+ * The daemon has exited; reset the state.
+ */
+ in_hand_shake = true;
+ opened = false;
+ return 0;
+}
+
+
+static const struct file_operations fcopy_fops = {
+ .read = fcopy_read,
+ .write = fcopy_write,
+ .release = fcopy_release,
+ .open = fcopy_open,
+};
+
+static struct miscdevice fcopy_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "vmbus/hv_fcopy",
+ .fops = &fcopy_fops,
+};
+
+static int fcopy_dev_init(void)
+{
+ return misc_register(&fcopy_misc);
+}
+
+static void fcopy_dev_deinit(void)
+{
+
+ /*
+ * The device is going away - perhaps because the
+ * host has rescinded the channel. Setup state so that
+ * user level daemon can gracefully exit if it is blocked
+ * on the read semaphore.
+ */
+ opened = false;
+ /*
+ * Signal the semaphore as the device is
+ * going away.
+ */
+ up(&fcopy_transaction.read_sema);
+ misc_deregister(&fcopy_misc);
+}
+
+int hv_fcopy_init(struct hv_util_service *srv)
+{
+ recv_buffer = srv->recv_buffer;
+
+ /*
+ * When this driver loads, the user level daemon that
+ * processes the host requests may not yet be running.
+ * Defer processing channel callbacks until the daemon
+ * has registered.
+ */
+ fcopy_transaction.active = true;
+ sema_init(&fcopy_transaction.read_sema, 0);
+
+ return fcopy_dev_init();
+}
+
+void hv_fcopy_deinit(void)
+{
+ cancel_delayed_work_sync(&fcopy_work);
+ fcopy_dev_deinit();
+}
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 09988b289622..ea852537307e 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -113,7 +113,7 @@ kvp_register(int reg_value)
kvp_msg->kvp_hdr.operation = reg_value;
strcpy(version, HV_DRV_VERSION);
msg->len = sizeof(struct hv_kvp_msg);
- cn_netlink_send(msg, 0, GFP_ATOMIC);
+ cn_netlink_send(msg, 0, 0, GFP_ATOMIC);
kfree(msg);
}
}
@@ -435,7 +435,7 @@ kvp_send_key(struct work_struct *dummy)
}
msg->len = sizeof(struct hv_kvp_msg);
- cn_netlink_send(msg, 0, GFP_ATOMIC);
+ cn_netlink_send(msg, 0, 0, GFP_ATOMIC);
kfree(msg);
return;
diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c
index 0c3546224376..34f14fddb666 100644
--- a/drivers/hv/hv_snapshot.c
+++ b/drivers/hv/hv_snapshot.c
@@ -98,7 +98,7 @@ static void vss_send_op(struct work_struct *dummy)
vss_msg->vss_hdr.operation = op;
msg->len = sizeof(struct hv_vss_msg);
- cn_netlink_send(msg, 0, GFP_ATOMIC);
+ cn_netlink_send(msg, 0, 0, GFP_ATOMIC);
kfree(msg);
return;
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c
index 62dfd246b948..dd761806f0e8 100644
--- a/drivers/hv/hv_util.c
+++ b/drivers/hv/hv_util.c
@@ -28,6 +28,7 @@
#include <linux/reboot.h>
#include <linux/hyperv.h>
+#include "hyperv_vmbus.h"
#define SD_MAJOR 3
#define SD_MINOR 0
@@ -82,6 +83,12 @@ static struct hv_util_service util_vss = {
.util_deinit = hv_vss_deinit,
};
+static struct hv_util_service util_fcopy = {
+ .util_cb = hv_fcopy_onchannelcallback,
+ .util_init = hv_fcopy_init,
+ .util_deinit = hv_fcopy_deinit,
+};
+
static void perform_shutdown(struct work_struct *dummy)
{
orderly_poweroff(true);
@@ -401,6 +408,10 @@ static const struct hv_vmbus_device_id id_table[] = {
{ HV_VSS_GUID,
.driver_data = (unsigned long)&util_vss
},
+ /* File copy GUID */
+ { HV_FCOPY_GUID,
+ .driver_data = (unsigned long)&util_fcopy
+ },
{ },
};
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index e05517616a06..860134da8039 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -559,8 +559,8 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, void *buffer,
void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info,
- struct scatterlist *sglist,
- u32 sgcount, bool *signal);
+ struct kvec *kv_list,
+ u32 kv_count, bool *signal);
int hv_ringbuffer_peek(struct hv_ring_buffer_info *ring_info, void *buffer,
u32 buflen);
@@ -669,5 +669,9 @@ int vmbus_set_event(struct vmbus_channel *channel);
void vmbus_on_event(unsigned long data);
+int hv_fcopy_init(struct hv_util_service *);
+void hv_fcopy_deinit(void);
+void hv_fcopy_onchannelcallback(void *);
+
#endif /* _HYPERV_VMBUS_H */
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c
index 26c93cf9f6be..15db66b74141 100644
--- a/drivers/hv/ring_buffer.c
+++ b/drivers/hv/ring_buffer.c
@@ -26,6 +26,7 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/hyperv.h>
+#include <linux/uio.h>
#include "hyperv_vmbus.h"
@@ -387,23 +388,20 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
*
*/
int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
- struct scatterlist *sglist, u32 sgcount, bool *signal)
+ struct kvec *kv_list, u32 kv_count, bool *signal)
{
int i = 0;
u32 bytes_avail_towrite;
u32 bytes_avail_toread;
u32 totalbytes_towrite = 0;
- struct scatterlist *sg;
u32 next_write_location;
u32 old_write;
u64 prev_indices = 0;
unsigned long flags;
- for_each_sg(sglist, sg, sgcount, i)
- {
- totalbytes_towrite += sg->length;
- }
+ for (i = 0; i < kv_count; i++)
+ totalbytes_towrite += kv_list[i].iov_len;
totalbytes_towrite += sizeof(u64);
@@ -427,12 +425,11 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
old_write = next_write_location;
- for_each_sg(sglist, sg, sgcount, i)
- {
+ for (i = 0; i < kv_count; i++) {
next_write_location = hv_copyto_ringbuffer(outring_info,
next_write_location,
- sg_virt(sg),
- sg->length);
+ kv_list[i].iov_base,
+ kv_list[i].iov_len);
}
/* Set previous packet start */
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 077bb1bdac34..8e53a3c2607e 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -25,7 +25,6 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
-#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/sysctl.h>
#include <linux/slab.h>
@@ -44,6 +43,12 @@ static struct tasklet_struct msg_dpc;
static struct completion probe_event;
static int irq;
+struct resource hyperv_mmio = {
+ .name = "hyperv mmio",
+ .flags = IORESOURCE_MEM,
+};
+EXPORT_SYMBOL_GPL(hyperv_mmio);
+
static int vmbus_exists(void)
{
if (hv_acpi_dev == NULL)
@@ -558,9 +563,6 @@ static struct bus_type hv_bus = {
.dev_groups = vmbus_groups,
};
-static const char *driver_name = "hyperv";
-
-
struct onmessage_work_context {
struct work_struct work;
struct hv_message msg;
@@ -619,7 +621,7 @@ static void vmbus_on_msg_dpc(unsigned long data)
}
}
-static irqreturn_t vmbus_isr(int irq, void *dev_id)
+static void vmbus_isr(void)
{
int cpu = smp_processor_id();
void *page_addr;
@@ -629,7 +631,7 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id)
page_addr = hv_context.synic_event_page[cpu];
if (page_addr == NULL)
- return IRQ_NONE;
+ return;
event = (union hv_synic_event_flags *)page_addr +
VMBUS_MESSAGE_SINT;
@@ -665,28 +667,8 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id)
msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
/* Check if there are actual msgs to be processed */
- if (msg->header.message_type != HVMSG_NONE) {
- handled = true;
+ if (msg->header.message_type != HVMSG_NONE)
tasklet_schedule(&msg_dpc);
- }
-
- if (handled)
- return IRQ_HANDLED;
- else
- return IRQ_NONE;
-}
-
-/*
- * vmbus interrupt flow handler:
- * vmbus interrupts can concurrently occur on multiple CPUs and
- * can be handled concurrently.
- */
-
-static void vmbus_flow_handler(unsigned int irq, struct irq_desc *desc)
-{
- kstat_incr_irqs_this_cpu(irq, desc);
-
- desc->action->handler(irq, desc->action->dev_id);
}
/*
@@ -715,25 +697,7 @@ static int vmbus_bus_init(int irq)
if (ret)
goto err_cleanup;
- ret = request_irq(irq, vmbus_isr, 0, driver_name, hv_acpi_dev);
-
- if (ret != 0) {
- pr_err("Unable to request IRQ %d\n",
- irq);
- goto err_unregister;
- }
-
- /*
- * Vmbus interrupts can be handled concurrently on
- * different CPUs. Establish an appropriate interrupt flow
- * handler that can support this model.
- */
- irq_set_handler(irq, vmbus_flow_handler);
-
- /*
- * Register our interrupt handler.
- */
- hv_register_vmbus_handler(irq, vmbus_isr);
+ hv_setup_vmbus_irq(vmbus_isr);
ret = hv_synic_alloc();
if (ret)
@@ -753,9 +717,8 @@ static int vmbus_bus_init(int irq)
err_alloc:
hv_synic_free();
- free_irq(irq, hv_acpi_dev);
+ hv_remove_vmbus_irq();
-err_unregister:
bus_unregister(&hv_bus);
err_cleanup:
@@ -886,18 +849,21 @@ void vmbus_device_unregister(struct hv_device *device_obj)
/*
- * VMBUS is an acpi enumerated device. Get the the IRQ information
- * from DSDT.
+ * VMBUS is an acpi enumerated device. Get the the information we
+ * need from DSDT.
*/
-static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *irq)
+static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
{
+ switch (res->type) {
+ case ACPI_RESOURCE_TYPE_IRQ:
+ irq = res->data.irq.interrupts[0];
+ break;
- if (res->type == ACPI_RESOURCE_TYPE_IRQ) {
- struct acpi_resource_irq *irqp;
- irqp = &res->data.irq;
-
- *((unsigned int *)irq) = irqp->interrupts[0];
+ case ACPI_RESOURCE_TYPE_ADDRESS64:
+ hyperv_mmio.start = res->data.address64.minimum;
+ hyperv_mmio.end = res->data.address64.maximum;
+ break;
}
return AE_OK;
@@ -906,18 +872,34 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *irq)
static int vmbus_acpi_add(struct acpi_device *device)
{
acpi_status result;
+ int ret_val = -ENODEV;
hv_acpi_dev = device;
result = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
- vmbus_walk_resources, &irq);
+ vmbus_walk_resources, NULL);
- if (ACPI_FAILURE(result)) {
- complete(&probe_event);
- return -ENODEV;
+ if (ACPI_FAILURE(result))
+ goto acpi_walk_err;
+ /*
+ * The parent of the vmbus acpi device (Gen2 firmware) is the VMOD that
+ * has the mmio ranges. Get that.
+ */
+ if (device->parent) {
+ result = acpi_walk_resources(device->parent->handle,
+ METHOD_NAME__CRS,
+ vmbus_walk_resources, NULL);
+
+ if (ACPI_FAILURE(result))
+ goto acpi_walk_err;
+ if (hyperv_mmio.start && hyperv_mmio.end)
+ request_resource(&iomem_resource, &hyperv_mmio);
}
+ ret_val = 0;
+
+acpi_walk_err:
complete(&probe_event);
- return 0;
+ return ret_val;
}
static const struct acpi_device_id vmbus_acpi_device_ids[] = {
@@ -947,7 +929,6 @@ static int __init hv_acpi_init(void)
/*
* Get irq resources first.
*/
-
ret = acpi_bus_register_driver(&vmbus_acpi_driver);
if (ret)
@@ -978,8 +959,7 @@ cleanup:
static void __exit vmbus_exit(void)
{
-
- free_irq(irq, hv_acpi_dev);
+ hv_remove_vmbus_irq();
vmbus_free_channels();
bus_unregister(&hv_bus);
hv_cleanup();
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 5ce43d8dfa98..b13172cfbeef 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -111,22 +111,6 @@ config SENSORS_AD7418
This driver can also be built as a module. If so, the module
will be called ad7418.
-config SENSORS_ADCXX
- tristate "National Semiconductor ADCxxxSxxx"
- depends on SPI_MASTER
- help
- If you say yes here you get support for the National Semiconductor
- ADC<bb><c>S<sss> chip family, where
- * bb is the resolution in number of bits (8, 10, 12)
- * c is the number of channels (1, 2, 4, 8)
- * sss is the maximum conversion speed (021 for 200 kSPS, 051 for 500
- kSPS and 101 for 1 MSPS)
-
- Examples : ADC081S101, ADC124S501, ...
-
- This driver can also be built as a module. If so, the module
- will be called adcxx.
-
config SENSORS_ADM1021
tristate "Analog Devices ADM1021 and compatibles"
depends on I2C
@@ -296,8 +280,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), 15h (Bulldozer/Trinity) and
- 16h (Kabini) microarchitectures.
+ 12h (Llano), 14h (Brazos), 15h (Bulldozer/Trinity/Kaveri) and
+ 16h (Kabini/Mullins) microarchitectures.
This driver can also be built as a module. If so, the module
will be called k10temp.
@@ -312,6 +296,31 @@ config SENSORS_FAM15H_POWER
This driver can also be built as a module. If so, the module
will be called fam15h_power.
+config SENSORS_APPLESMC
+ tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
+ depends on INPUT && X86
+ select NEW_LEDS
+ select LEDS_CLASS
+ select INPUT_POLLDEV
+ default n
+ help
+ This driver provides support for the Apple System Management
+ Controller, which provides an accelerometer (Apple Sudden Motion
+ Sensor), light sensors, temperature sensors, keyboard backlight
+ control and fan control.
+
+ Only Intel-based Apple's computers are supported (MacBook Pro,
+ MacBook, MacMini).
+
+ Data from the different sensors, keyboard backlight control and fan
+ control are accessible via sysfs.
+
+ This driver also provides an absolute input class device, allowing
+ the laptop to act as a pinball machine-esque joystick.
+
+ Say Y here if you have an applicable laptop and want to experience
+ the awesome power of applesmc.
+
config SENSORS_ASB100
tristate "Asus ASB100 Bach"
depends on X86 && I2C
@@ -435,6 +444,12 @@ config SENSORS_F75375S
This driver can also be built as a module. If so, the module
will be called f75375s.
+config SENSORS_MC13783_ADC
+ tristate "Freescale MC13783/MC13892 ADC"
+ depends on MFD_MC13XXX
+ help
+ Support for the A/D converter on MC13783 and MC13892 PMIC.
+
config SENSORS_FSCHMD
tristate "Fujitsu Siemens Computers sensor chips"
depends on X86 && I2C
@@ -451,26 +466,6 @@ config SENSORS_FSCHMD
This driver can also be built as a module. If so, the module
will be called fschmd.
-config SENSORS_G760A
- tristate "GMT G760A"
- depends on I2C
- help
- If you say yes here you get support for Global Mixed-mode
- Technology Inc G760A fan speed PWM controller chips.
-
- This driver can also be built as a module. If so, the module
- will be called g760a.
-
-config SENSORS_G762
- tristate "GMT G762 and G763"
- depends on I2C
- help
- If you say yes here you get support for Global Mixed-mode
- Technology Inc G762 and G763 fan speed PWM controller chips.
-
- This driver can also be built as a module. If so, the module
- will be called g762.
-
config SENSORS_GL518SM
tristate "Genesys Logic GL518SM"
depends on I2C
@@ -492,6 +487,26 @@ config SENSORS_GL520SM
This driver can also be built as a module. If so, the module
will be called gl520sm.
+config SENSORS_G760A
+ tristate "GMT G760A"
+ depends on I2C
+ help
+ If you say yes here you get support for Global Mixed-mode
+ Technology Inc G760A fan speed PWM controller chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called g760a.
+
+config SENSORS_G762
+ tristate "GMT G762 and G763"
+ depends on I2C
+ help
+ If you say yes here you get support for Global Mixed-mode
+ Technology Inc G762 and G763 fan speed PWM controller chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called g762.
+
config SENSORS_GPIO_FAN
tristate "GPIO fan"
depends on GPIOLIB
@@ -511,24 +526,6 @@ 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
- help
- If you say yes here you get support for the temperature
- sensor inside your CPU. Most of the family 6 CPUs
- are supported. Check Documentation/hwmon/coretemp for details.
-
config SENSORS_IBMAEM
tristate "IBM Active Energy Manager temperature/power sensors and control"
select IPMI_SI
@@ -557,6 +554,14 @@ config SENSORS_IBMPEX
This driver can also be built as a module. If so, the module
will be called ibmpex.
+config SENSORS_IBMPOWERNV
+ tristate "IBM PowerNv Platform temperature/power/fan sensor"
+ depends on PPC_POWERNV
+ default y
+ help
+ If you say yes here you get support for the temperature/fan/power
+ sensors on your platform.
+
config SENSORS_IIO_HWMON
tristate "Hwmon driver that uses channels specified via iio maps"
depends on IIO
@@ -566,6 +571,14 @@ config SENSORS_IIO_HWMON
for those channels specified in the map. This map can be provided
either via platform data or the device tree bindings.
+config SENSORS_CORETEMP
+ tristate "Intel Core/Core2/Atom temperature sensor"
+ depends on X86
+ help
+ If you say yes here you get support for the temperature
+ sensor inside your CPU. Most of the family 6 CPUs
+ are supported. Check Documentation/hwmon/coretemp for details.
+
config SENSORS_IT87
tristate "ITE IT87xx and compatibles"
depends on !PPC
@@ -614,6 +627,219 @@ config SENSORS_LINEAGE
This driver can also be built as a module. If so, the module
will be called lineage-pem.
+config SENSORS_LTC2945
+ tristate "Linear Technology LTC2945"
+ depends on I2C
+ select REGMAP_I2C
+ default n
+ help
+ If you say yes here you get support for Linear Technology LTC2945
+ I2C System Monitor.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc2945.
+
+config SENSORS_LTC4151
+ tristate "Linear Technology LTC4151"
+ depends on I2C
+ default n
+ help
+ If you say yes here you get support for Linear Technology LTC4151
+ High Voltage I2C Current and Voltage Monitor interface.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc4151.
+
+config SENSORS_LTC4215
+ tristate "Linear Technology LTC4215"
+ depends on I2C
+ default n
+ help
+ If you say yes here you get support for Linear Technology LTC4215
+ Hot Swap Controller I2C interface.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc4215.
+
+config SENSORS_LTC4222
+ tristate "Linear Technology LTC4222"
+ depends on I2C
+ select REGMAP_I2C
+ default n
+ help
+ If you say yes here you get support for Linear Technology LTC4222
+ Dual Hot Swap Controller I2C interface.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc4222.
+
+config SENSORS_LTC4245
+ tristate "Linear Technology LTC4245"
+ depends on I2C
+ default n
+ help
+ If you say yes here you get support for Linear Technology LTC4245
+ Multiple Supply Hot Swap Controller I2C interface.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc4245.
+
+config SENSORS_LTC4260
+ tristate "Linear Technology LTC4260"
+ depends on I2C
+ select REGMAP_I2C
+ default n
+ help
+ If you say yes here you get support for Linear Technology LTC4260
+ Positive Voltage Hot Swap Controller I2C interface.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc4260.
+
+config SENSORS_LTC4261
+ tristate "Linear Technology LTC4261"
+ depends on I2C
+ default n
+ help
+ If you say yes here you get support for Linear Technology LTC4261
+ Negative Voltage Hot Swap Controller I2C interface.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc4261.
+
+config SENSORS_MAX1111
+ tristate "Maxim MAX1111 Serial 8-bit ADC chip and compatibles"
+ depends on SPI_MASTER
+ help
+ Say y here to support Maxim's MAX1110, MAX1111, MAX1112, and MAX1113
+ ADC chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called max1111.
+
+config SENSORS_MAX16065
+ tristate "Maxim MAX16065 System Manager and compatibles"
+ depends on I2C
+ help
+ If you say yes here you get support for hardware monitoring
+ capabilities of the following Maxim System Manager chips.
+ MAX16065
+ MAX16066
+ MAX16067
+ MAX16068
+ MAX16070
+ MAX16071
+
+ This driver can also be built as a module. If so, the module
+ will be called max16065.
+
+config SENSORS_MAX1619
+ tristate "Maxim MAX1619 sensor chip"
+ depends on I2C
+ help
+ If you say yes here you get support for MAX1619 sensor chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called max1619.
+
+config SENSORS_MAX1668
+ tristate "Maxim MAX1668 and compatibles"
+ depends on I2C
+ help
+ If you say yes here you get support for MAX1668, MAX1989 and
+ MAX1805 chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called max1668.
+
+config SENSORS_MAX197
+ tristate "Maxim MAX197 and compatibles"
+ help
+ Support for the Maxim MAX197 A/D converter.
+ Support will include, but not be limited to, MAX197, and MAX199.
+
+ This driver can also be built as a module. If so, the module
+ will be called max197.
+
+config SENSORS_MAX6639
+ tristate "Maxim MAX6639 sensor chip"
+ depends on I2C
+ help
+ If you say yes here you get support for the MAX6639
+ sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called max6639.
+
+config SENSORS_MAX6642
+ tristate "Maxim MAX6642 sensor chip"
+ depends on I2C
+ help
+ If you say yes here you get support for MAX6642 sensor chip.
+ MAX6642 is a SMBus-Compatible Remote/Local Temperature Sensor
+ with Overtemperature Alarm from Maxim.
+
+ This driver can also be built as a module. If so, the module
+ will be called max6642.
+
+config SENSORS_MAX6650
+ tristate "Maxim MAX6650 sensor chip"
+ depends on I2C
+ help
+ If you say yes here you get support for the MAX6650 / MAX6651
+ sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called max6650.
+
+config SENSORS_MAX6697
+ tristate "Maxim MAX6697 and compatibles"
+ depends on I2C
+ help
+ If you say yes here you get support for MAX6581, MAX6602, MAX6622,
+ MAX6636, MAX6689, MAX6693, MAX6694, MAX6697, MAX6698, and MAX6699
+ temperature sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called max6697.
+
+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_MCP3021
+ tristate "Microchip MCP3021 and compatibles"
+ depends on I2C
+ help
+ If you say yes here you get support for MCP3021 and MCP3221.
+ The MCP3021 is a A/D converter (ADC) with 10-bit and the MCP3221
+ with 12-bit resolution.
+
+ This driver can also be built as a module. If so, the module
+ will be called mcp3021.
+
+config SENSORS_ADCXX
+ tristate "National Semiconductor ADCxxxSxxx"
+ depends on SPI_MASTER
+ help
+ If you say yes here you get support for the National Semiconductor
+ ADC<bb><c>S<sss> chip family, where
+ * bb is the resolution in number of bits (8, 10, 12)
+ * c is the number of channels (1, 2, 4, 8)
+ * sss is the maximum conversion speed (021 for 200 kSPS, 051 for 500
+ kSPS and 101 for 1 MSPS)
+
+ Examples : ADC081S101, ADC124S501, ...
+
+ This driver can also be built as a module. If so, the module
+ will be called adcxx.
+
config SENSORS_LM63
tristate "National Semiconductor LM63 and compatibles"
depends on I2C
@@ -776,50 +1002,6 @@ config SENSORS_LM93
This driver can also be built as a module. If so, the module
will be called lm93.
-config SENSORS_LTC4151
- tristate "Linear Technology LTC4151"
- depends on I2C
- default n
- help
- If you say yes here you get support for Linear Technology LTC4151
- High Voltage I2C Current and Voltage Monitor interface.
-
- This driver can also be built as a module. If so, the module will
- be called ltc4151.
-
-config SENSORS_LTC4215
- tristate "Linear Technology LTC4215"
- depends on I2C
- default n
- help
- If you say yes here you get support for Linear Technology LTC4215
- Hot Swap Controller I2C interface.
-
- This driver can also be built as a module. If so, the module will
- be called ltc4215.
-
-config SENSORS_LTC4245
- tristate "Linear Technology LTC4245"
- depends on I2C
- default n
- help
- If you say yes here you get support for Linear Technology LTC4245
- Multiple Supply Hot Swap Controller I2C interface.
-
- This driver can also be built as a module. If so, the module will
- be called ltc4245.
-
-config SENSORS_LTC4261
- tristate "Linear Technology LTC4261"
- depends on I2C
- default n
- help
- If you say yes here you get support for Linear Technology LTC4261
- Negative Voltage Hot Swap Controller I2C interface.
-
- This driver can also be built as a module. If so, the module will
- be called ltc4261.
-
config SENSORS_LM95234
tristate "National Semiconductor LM95234"
depends on I2C
@@ -849,125 +1031,33 @@ config SENSORS_LM95245
This driver can also be built as a module. If so, the module
will be called lm95245.
-config SENSORS_MAX1111
- tristate "Maxim MAX1111 Serial 8-bit ADC chip and compatibles"
- depends on SPI_MASTER
- help
- Say y here to support Maxim's MAX1110, MAX1111, MAX1112, and MAX1113
- ADC chips.
-
- This driver can also be built as a module. If so, the module
- will be called max1111.
-
-config SENSORS_MAX16065
- tristate "Maxim MAX16065 System Manager and compatibles"
- depends on I2C
- help
- If you say yes here you get support for hardware monitoring
- capabilities of the following Maxim System Manager chips.
- MAX16065
- MAX16066
- MAX16067
- MAX16068
- MAX16070
- MAX16071
-
- This driver can also be built as a module. If so, the module
- will be called max16065.
-
-config SENSORS_MAX1619
- tristate "Maxim MAX1619 sensor chip"
- depends on I2C
- help
- If you say yes here you get support for MAX1619 sensor chip.
-
- This driver can also be built as a module. If so, the module
- will be called max1619.
-
-config SENSORS_MAX1668
- tristate "Maxim MAX1668 and compatibles"
- depends on I2C
- help
- If you say yes here you get support for MAX1668, MAX1989 and
- MAX1805 chips.
-
- This driver can also be built as a module. If so, the module
- will be called max1668.
-
-config SENSORS_MAX197
- tristate "Maxim MAX197 and compatibles"
- help
- Support for the Maxim MAX197 A/D converter.
- Support will include, but not be limited to, MAX197, and MAX199.
-
- This driver can also be built as a module. If so, the module
- will be called max197.
-
-config SENSORS_MAX6639
- tristate "Maxim MAX6639 sensor chip"
- depends on I2C
- help
- If you say yes here you get support for the MAX6639
- sensor chips.
-
- This driver can also be built as a module. If so, the module
- will be called max6639.
-
-config SENSORS_MAX6642
- tristate "Maxim MAX6642 sensor chip"
- depends on I2C
- help
- If you say yes here you get support for MAX6642 sensor chip.
- MAX6642 is a SMBus-Compatible Remote/Local Temperature Sensor
- with Overtemperature Alarm from Maxim.
-
- This driver can also be built as a module. If so, the module
- will be called max6642.
-
-config SENSORS_MAX6650
- tristate "Maxim MAX6650 sensor chip"
- depends on I2C
- help
- If you say yes here you get support for the MAX6650 / MAX6651
- sensor chips.
-
- This driver can also be built as a module. If so, the module
- will be called max6650.
-
-config SENSORS_MAX6697
- tristate "Maxim MAX6697 and compatibles"
- depends on I2C
- help
- If you say yes here you get support for MAX6581, MAX6602, MAX6622,
- MAX6636, MAX6689, MAX6693, MAX6694, MAX6697, MAX6698, and MAX6699
- temperature sensor chips.
-
- This driver can also be built as a module. If so, the module
- will be called max6697.
-
-config SENSORS_MCP3021
- tristate "Microchip MCP3021 and compatibles"
- depends on I2C
+config SENSORS_PC87360
+ tristate "National Semiconductor PC87360 family"
+ depends on !PPC
+ select HWMON_VID
help
- If you say yes here you get support for MCP3021 and MCP3221.
- The MCP3021 is a A/D converter (ADC) with 10-bit and the MCP3221
- with 12-bit resolution.
+ If you say yes here you get access to the hardware monitoring
+ functions of the National Semiconductor PC8736x Super-I/O chips.
+ The PC87360, PC87363 and PC87364 only have fan monitoring and
+ control. The PC87365 and PC87366 additionally have voltage and
+ temperature monitoring.
This driver can also be built as a module. If so, the module
- will be called mcp3021.
+ will be called pc87360.
-config SENSORS_NCT6775
- tristate "Nuvoton NCT6775F and compatibles"
+config SENSORS_PC87427
+ tristate "National Semiconductor PC87427"
depends on !PPC
- select HWMON_VID
help
- If you say yes here you get support for the hardware monitoring
- functionality of the Nuvoton NCT6775F, NCT6776F, NCT6779D
- and compatible Super-I/O chips. This driver replaces the
- w83627ehf driver for NCT6775F and NCT6776F.
+ If you say yes here you get access to the hardware monitoring
+ functions of the National Semiconductor PC87427 Super-I/O chip.
+ The chip has two distinct logical devices, one for fan speed
+ monitoring and control, and one for voltage and temperature
+ monitoring. Fan speed monitoring and control are supported, as
+ well as temperature monitoring. Voltages aren't supported yet.
This driver can also be built as a module. If so, the module
- will be called nct6775.
+ will be called pc87427.
config SENSORS_NTC_THERMISTOR
tristate "NTC thermistor support"
@@ -983,33 +1073,18 @@ config SENSORS_NTC_THERMISTOR
This driver can also be built as a module. If so, the module
will be called ntc-thermistor.
-config SENSORS_PC87360
- tristate "National Semiconductor PC87360 family"
+config SENSORS_NCT6775
+ tristate "Nuvoton NCT6775F and compatibles"
depends on !PPC
select HWMON_VID
help
- If you say yes here you get access to the hardware monitoring
- functions of the National Semiconductor PC8736x Super-I/O chips.
- The PC87360, PC87363 and PC87364 only have fan monitoring and
- control. The PC87365 and PC87366 additionally have voltage and
- temperature monitoring.
-
- This driver can also be built as a module. If so, the module
- will be called pc87360.
-
-config SENSORS_PC87427
- tristate "National Semiconductor PC87427"
- depends on !PPC
- help
- If you say yes here you get access to the hardware monitoring
- functions of the National Semiconductor PC87427 Super-I/O chip.
- The chip has two distinct logical devices, one for fan speed
- monitoring and control, and one for voltage and temperature
- monitoring. Fan speed monitoring and control are supported, as
- well as temperature monitoring. Voltages aren't supported yet.
+ If you say yes here you get support for the hardware monitoring
+ functionality of the Nuvoton NCT6775F, NCT6776F, NCT6779D
+ and compatible Super-I/O chips. This driver replaces the
+ w83627ehf driver for NCT6775F and NCT6776F.
This driver can also be built as a module. If so, the module
- will be called pc87427.
+ will be called nct6775.
config SENSORS_PCF8591
tristate "Philips PCF8591 ADC/DAC"
@@ -1074,21 +1149,6 @@ config SENSORS_SIS5595
This driver can also be built as a module. If so, the module
will be called sis5595.
-config SENSORS_SMM665
- tristate "Summit Microelectronics SMM665"
- depends on I2C
- default n
- help
- If you say yes here you get support for the hardware monitoring
- features of the Summit Microelectronics SMM665/SMM665B Six-Channel
- Active DC Output Controller / Monitor.
-
- Other supported chips are SMM465, SMM665C, SMM764, and SMM766.
- Support for those chips is untested.
-
- This driver can also be built as a module. If so, the module will
- be called smm665.
-
config SENSORS_DME1737
tristate "SMSC DME1737, SCH311x and compatibles"
depends on I2C && !PPC
@@ -1210,6 +1270,31 @@ config SENSORS_SCH5636
This driver can also be built as a module. If so, the module
will be called sch5636.
+config SENSORS_SMM665
+ tristate "Summit Microelectronics SMM665"
+ depends on I2C
+ default n
+ help
+ If you say yes here you get support for the hardware monitoring
+ features of the Summit Microelectronics SMM665/SMM665B Six-Channel
+ Active DC Output Controller / Monitor.
+
+ Other supported chips are SMM465, SMM665C, SMM764, and SMM766.
+ Support for those chips is untested.
+
+ This driver can also be built as a module. If so, the module will
+ be called smm665.
+
+config SENSORS_ADC128D818
+ tristate "Texas Instruments ADC128D818"
+ depends on I2C
+ help
+ If you say yes here you get support for the Texas Instruments
+ ADC128D818 System Monitor with Temperature Sensor chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called adc128d818.
+
config SENSORS_ADS1015
tristate "Texas Instruments ADS1015"
depends on I2C
@@ -1525,37 +1610,6 @@ config SENSORS_ULTRA45
This driver provides support for the Ultra45 workstation environmental
sensors.
-config SENSORS_APPLESMC
- tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
- depends on INPUT && X86
- select NEW_LEDS
- select LEDS_CLASS
- select INPUT_POLLDEV
- default n
- help
- This driver provides support for the Apple System Management
- Controller, which provides an accelerometer (Apple Sudden Motion
- Sensor), light sensors, temperature sensors, keyboard backlight
- control and fan control.
-
- Only Intel-based Apple's computers are supported (MacBook Pro,
- MacBook, MacMini).
-
- Data from the different sensors, keyboard backlight control and fan
- control are accessible via sysfs.
-
- This driver also provides an absolute input class device, allowing
- the laptop to act as a pinball machine-esque joystick.
-
- Say Y here if you have an applicable laptop and want to experience
- the awesome power of applesmc.
-
-config SENSORS_MC13783_ADC
- tristate "Freescale MC13783/MC13892 ADC"
- depends on MFD_MC13XXX
- help
- Support for the A/D converter on MC13783 and MC13892 PMIC.
-
if ACPI
comment "ACPI drivers"
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index ec7cde06eb52..199c401bf8d9 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
obj-$(CONFIG_SENSORS_AD7314) += ad7314.o
obj-$(CONFIG_SENSORS_AD7414) += ad7414.o
obj-$(CONFIG_SENSORS_AD7418) += ad7418.o
+obj-$(CONFIG_SENSORS_ADC128D818) += adc128d818.o
obj-$(CONFIG_SENSORS_ADCXX) += adcxx.o
obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
@@ -70,6 +71,7 @@ obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
+obj-$(CONFIG_SENSORS_IBMPOWERNV)+= ibmpowernv.o
obj-$(CONFIG_SENSORS_IIO_HWMON) += iio_hwmon.o
obj-$(CONFIG_SENSORS_INA209) += ina209.o
obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o
@@ -95,9 +97,12 @@ obj-$(CONFIG_SENSORS_LM93) += lm93.o
obj-$(CONFIG_SENSORS_LM95234) += lm95234.o
obj-$(CONFIG_SENSORS_LM95241) += lm95241.o
obj-$(CONFIG_SENSORS_LM95245) += lm95245.o
+obj-$(CONFIG_SENSORS_LTC2945) += ltc2945.o
obj-$(CONFIG_SENSORS_LTC4151) += ltc4151.o
obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o
+obj-$(CONFIG_SENSORS_LTC4222) += ltc4222.o
obj-$(CONFIG_SENSORS_LTC4245) += ltc4245.o
+obj-$(CONFIG_SENSORS_LTC4260) += ltc4260.o
obj-$(CONFIG_SENSORS_LTC4261) += ltc4261.o
obj-$(CONFIG_SENSORS_MAX1111) += max1111.o
obj-$(CONFIG_SENSORS_MAX16065) += max16065.o
diff --git a/drivers/hwmon/adc128d818.c b/drivers/hwmon/adc128d818.c
new file mode 100644
index 000000000000..5ffd81f19d01
--- /dev/null
+++ b/drivers/hwmon/adc128d818.c
@@ -0,0 +1,491 @@
+/*
+ * Driver for TI ADC128D818 System Monitor with Temperature Sensor
+ *
+ * Copyright (c) 2014 Guenter Roeck
+ *
+ * Derived from lm80.c
+ * Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
+ * and Philip Edelbrock <phil@netroedge.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/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mutex.h>
+
+/* Addresses to scan
+ * The chip also supports addresses 0x35..0x37. Don't scan those addresses
+ * since they are also used by some EEPROMs, which may result in false
+ * positives.
+ */
+static const unsigned short normal_i2c[] = {
+ 0x1d, 0x1e, 0x1f, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
+
+/* registers */
+#define ADC128_REG_IN_MAX(nr) (0x2a + (nr) * 2)
+#define ADC128_REG_IN_MIN(nr) (0x2b + (nr) * 2)
+#define ADC128_REG_IN(nr) (0x20 + (nr))
+
+#define ADC128_REG_TEMP 0x27
+#define ADC128_REG_TEMP_MAX 0x38
+#define ADC128_REG_TEMP_HYST 0x39
+
+#define ADC128_REG_CONFIG 0x00
+#define ADC128_REG_ALARM 0x01
+#define ADC128_REG_MASK 0x03
+#define ADC128_REG_CONV_RATE 0x07
+#define ADC128_REG_ONESHOT 0x09
+#define ADC128_REG_SHUTDOWN 0x0a
+#define ADC128_REG_CONFIG_ADV 0x0b
+#define ADC128_REG_BUSY_STATUS 0x0c
+
+#define ADC128_REG_MAN_ID 0x3e
+#define ADC128_REG_DEV_ID 0x3f
+
+struct adc128_data {
+ struct i2c_client *client;
+ struct regulator *regulator;
+ int vref; /* Reference voltage in mV */
+ struct mutex update_lock;
+ bool valid; /* true if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+
+ u16 in[3][7]; /* Register value, normalized to 12 bit
+ * 0: input voltage
+ * 1: min limit
+ * 2: max limit
+ */
+ s16 temp[3]; /* Register value, normalized to 9 bit
+ * 0: sensor 1: limit 2: hyst
+ */
+ u8 alarms; /* alarm register value */
+};
+
+static struct adc128_data *adc128_update_device(struct device *dev)
+{
+ struct adc128_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ struct adc128_data *ret = data;
+ int i, rv;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+ for (i = 0; i < 7; i++) {
+ rv = i2c_smbus_read_word_swapped(client,
+ ADC128_REG_IN(i));
+ if (rv < 0)
+ goto abort;
+ data->in[0][i] = rv >> 4;
+
+ rv = i2c_smbus_read_byte_data(client,
+ ADC128_REG_IN_MIN(i));
+ if (rv < 0)
+ goto abort;
+ data->in[1][i] = rv << 4;
+
+ rv = i2c_smbus_read_byte_data(client,
+ ADC128_REG_IN_MAX(i));
+ if (rv < 0)
+ goto abort;
+ data->in[2][i] = rv << 4;
+ }
+
+ rv = i2c_smbus_read_word_swapped(client, ADC128_REG_TEMP);
+ if (rv < 0)
+ goto abort;
+ data->temp[0] = rv >> 7;
+
+ rv = i2c_smbus_read_byte_data(client, ADC128_REG_TEMP_MAX);
+ if (rv < 0)
+ goto abort;
+ data->temp[1] = rv << 1;
+
+ rv = i2c_smbus_read_byte_data(client, ADC128_REG_TEMP_HYST);
+ if (rv < 0)
+ goto abort;
+ data->temp[2] = rv << 1;
+
+ rv = i2c_smbus_read_byte_data(client, ADC128_REG_ALARM);
+ if (rv < 0)
+ goto abort;
+ data->alarms |= rv;
+
+ data->last_updated = jiffies;
+ data->valid = true;
+ }
+ goto done;
+
+abort:
+ ret = ERR_PTR(rv);
+ data->valid = false;
+done:
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+static ssize_t adc128_show_in(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct adc128_data *data = adc128_update_device(dev);
+ int index = to_sensor_dev_attr_2(attr)->index;
+ int nr = to_sensor_dev_attr_2(attr)->nr;
+ int val;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ val = DIV_ROUND_CLOSEST(data->in[index][nr] * data->vref, 4095);
+ return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t adc128_set_in(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct adc128_data *data = dev_get_drvdata(dev);
+ int index = to_sensor_dev_attr_2(attr)->index;
+ int nr = to_sensor_dev_attr_2(attr)->nr;
+ u8 reg, regval;
+ long val;
+ int err;
+
+ err = kstrtol(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ mutex_lock(&data->update_lock);
+ /* 10 mV LSB on limit registers */
+ regval = clamp_val(DIV_ROUND_CLOSEST(val, 10), 0, 255);
+ data->in[index][nr] = regval << 4;
+ reg = index == 1 ? ADC128_REG_IN_MIN(nr) : ADC128_REG_IN_MAX(nr);
+ i2c_smbus_write_byte_data(data->client, reg, regval);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t adc128_show_temp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct adc128_data *data = adc128_update_device(dev);
+ int index = to_sensor_dev_attr(attr)->index;
+ int temp;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ temp = (data->temp[index] << 7) >> 7; /* sign extend */
+ return sprintf(buf, "%d\n", temp * 500);/* 0.5 degrees C resolution */
+}
+
+static ssize_t adc128_set_temp(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct adc128_data *data = dev_get_drvdata(dev);
+ int index = to_sensor_dev_attr(attr)->index;
+ long val;
+ int err;
+ s8 regval;
+
+ err = kstrtol(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ mutex_lock(&data->update_lock);
+ regval = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
+ data->temp[index] = regval << 1;
+ i2c_smbus_write_byte_data(data->client,
+ index == 1 ? ADC128_REG_TEMP_MAX
+ : ADC128_REG_TEMP_HYST,
+ regval);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t adc128_show_alarm(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct adc128_data *data = adc128_update_device(dev);
+ int mask = 1 << to_sensor_dev_attr(attr)->index;
+ u8 alarms;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ /*
+ * Clear an alarm after reporting it to user space. If it is still
+ * active, the next update sequence will set the alarm bit again.
+ */
+ alarms = data->alarms;
+ data->alarms &= ~mask;
+
+ return sprintf(buf, "%u\n", !!(alarms & mask));
+}
+
+static SENSOR_DEVICE_ATTR_2(in0_input, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 0, 0);
+static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 0, 1);
+static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 0, 2);
+
+static SENSOR_DEVICE_ATTR_2(in1_input, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 1, 0);
+static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 1, 1);
+static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 1, 2);
+
+static SENSOR_DEVICE_ATTR_2(in2_input, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 2, 0);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 2, 1);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 2, 2);
+
+static SENSOR_DEVICE_ATTR_2(in3_input, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 3, 0);
+static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 3, 1);
+static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 3, 2);
+
+static SENSOR_DEVICE_ATTR_2(in4_input, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 4, 0);
+static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 4, 1);
+static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 4, 2);
+
+static SENSOR_DEVICE_ATTR_2(in5_input, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 5, 0);
+static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 5, 1);
+static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 5, 2);
+
+static SENSOR_DEVICE_ATTR_2(in6_input, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 6, 0);
+static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 6, 1);
+static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 6, 2);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adc128_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+ adc128_show_temp, adc128_set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+ adc128_show_temp, adc128_set_temp, 2);
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, adc128_show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, adc128_show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, adc128_show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, adc128_show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, adc128_show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, adc128_show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, adc128_show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adc128_show_alarm, NULL, 7);
+
+static struct attribute *adc128_attrs[] = {
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
+ &sensor_dev_attr_in6_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(adc128);
+
+static int adc128_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+ int man_id, dev_id;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA))
+ return -ENODEV;
+
+ man_id = i2c_smbus_read_byte_data(client, ADC128_REG_MAN_ID);
+ dev_id = i2c_smbus_read_byte_data(client, ADC128_REG_DEV_ID);
+ if (man_id != 0x01 || dev_id != 0x09)
+ return -ENODEV;
+
+ /* Check unused bits for confirmation */
+ if (i2c_smbus_read_byte_data(client, ADC128_REG_CONFIG) & 0xf4)
+ return -ENODEV;
+ if (i2c_smbus_read_byte_data(client, ADC128_REG_CONV_RATE) & 0xfe)
+ return -ENODEV;
+ if (i2c_smbus_read_byte_data(client, ADC128_REG_ONESHOT) & 0xfe)
+ return -ENODEV;
+ if (i2c_smbus_read_byte_data(client, ADC128_REG_SHUTDOWN) & 0xfe)
+ return -ENODEV;
+ if (i2c_smbus_read_byte_data(client, ADC128_REG_CONFIG_ADV) & 0xf8)
+ return -ENODEV;
+ if (i2c_smbus_read_byte_data(client, ADC128_REG_BUSY_STATUS) & 0xfc)
+ return -ENODEV;
+
+ strlcpy(info->type, "adc128d818", I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int adc128_init_client(struct adc128_data *data)
+{
+ struct i2c_client *client = data->client;
+ int err;
+
+ /*
+ * Reset chip to defaults.
+ * This makes most other initializations unnecessary.
+ */
+ err = i2c_smbus_write_byte_data(client, ADC128_REG_CONFIG, 0x80);
+ if (err)
+ return err;
+
+ /* Start monitoring */
+ err = i2c_smbus_write_byte_data(client, ADC128_REG_CONFIG, 0x01);
+ if (err)
+ return err;
+
+ /* If external vref is selected, configure the chip to use it */
+ if (data->regulator) {
+ err = i2c_smbus_write_byte_data(client,
+ ADC128_REG_CONFIG_ADV, 0x01);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int adc128_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct regulator *regulator;
+ struct device *hwmon_dev;
+ struct adc128_data *data;
+ int err, vref;
+
+ data = devm_kzalloc(dev, sizeof(struct adc128_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ /* vref is optional. If specified, is used as chip reference voltage */
+ regulator = devm_regulator_get_optional(dev, "vref");
+ if (!IS_ERR(regulator)) {
+ data->regulator = regulator;
+ err = regulator_enable(regulator);
+ if (err < 0)
+ return err;
+ vref = regulator_get_voltage(regulator);
+ if (vref < 0) {
+ err = vref;
+ goto error;
+ }
+ data->vref = DIV_ROUND_CLOSEST(vref, 1000);
+ } else {
+ data->vref = 2560; /* 2.56V, in mV */
+ }
+
+ data->client = client;
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ /* Initialize the chip */
+ err = adc128_init_client(data);
+ if (err < 0)
+ goto error;
+
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ data, adc128_groups);
+ if (IS_ERR(hwmon_dev)) {
+ err = PTR_ERR(hwmon_dev);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ if (data->regulator)
+ regulator_disable(data->regulator);
+ return err;
+}
+
+static int adc128_remove(struct i2c_client *client)
+{
+ struct adc128_data *data = i2c_get_clientdata(client);
+
+ if (data->regulator)
+ regulator_disable(data->regulator);
+
+ return 0;
+}
+
+static const struct i2c_device_id adc128_id[] = {
+ { "adc128d818", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adc128_id);
+
+static struct i2c_driver adc128_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "adc128d818",
+ },
+ .probe = adc128_probe,
+ .remove = adc128_remove,
+ .id_table = adc128_id,
+ .detect = adc128_detect,
+ .address_list = normal_i2c,
+};
+
+module_i2c_driver(adc128_driver);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("Driver for ADC128D818");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index bbb0b0d463f7..f31bc4c48644 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -94,6 +94,8 @@ struct temp_data {
bool valid;
struct sensor_device_attribute sd_attrs[TOTAL_ATTRS];
char attr_name[TOTAL_ATTRS][CORETEMP_NAME_LENGTH];
+ struct attribute *attrs[TOTAL_ATTRS + 1];
+ struct attribute_group attr_group;
struct mutex update_lock;
};
@@ -114,12 +116,6 @@ struct pdev_entry {
static LIST_HEAD(pdev_list);
static DEFINE_MUTEX(pdev_list_mutex);
-static ssize_t show_name(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- return sprintf(buf, "%s\n", DRVNAME);
-}
-
static ssize_t show_label(struct device *dev,
struct device_attribute *devattr, char *buf)
{
@@ -393,20 +389,10 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
return adjust_tjmax(c, id, dev);
}
-static int create_name_attr(struct platform_data *pdata,
- struct device *dev)
-{
- sysfs_attr_init(&pdata->name_attr.attr);
- pdata->name_attr.attr.name = "name";
- pdata->name_attr.attr.mode = S_IRUGO;
- pdata->name_attr.show = show_name;
- return device_create_file(dev, &pdata->name_attr);
-}
-
static int create_core_attrs(struct temp_data *tdata, struct device *dev,
int attr_no)
{
- int err, i;
+ int i;
static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev,
struct device_attribute *devattr, char *buf) = {
show_label, show_crit_alarm, show_temp, show_tjmax,
@@ -424,16 +410,10 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev,
tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO;
tdata->sd_attrs[i].dev_attr.show = rd_ptr[i];
tdata->sd_attrs[i].index = attr_no;
- err = device_create_file(dev, &tdata->sd_attrs[i].dev_attr);
- if (err)
- goto exit_free;
+ tdata->attrs[i] = &tdata->sd_attrs[i].dev_attr.attr;
}
- return 0;
-
-exit_free:
- while (--i >= 0)
- device_remove_file(dev, &tdata->sd_attrs[i].dev_attr);
- return err;
+ tdata->attr_group.attrs = tdata->attrs;
+ return sysfs_create_group(&dev->kobj, &tdata->attr_group);
}
@@ -548,7 +528,7 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,
pdata->core_data[attr_no] = tdata;
/* Create sysfs interfaces */
- err = create_core_attrs(tdata, &pdev->dev, attr_no);
+ err = create_core_attrs(tdata, pdata->hwmon_dev, attr_no);
if (err)
goto exit_free;
@@ -573,14 +553,12 @@ static void coretemp_add_core(unsigned int cpu, int pkg_flag)
}
static void coretemp_remove_core(struct platform_data *pdata,
- struct device *dev, int indx)
+ int indx)
{
- int i;
struct temp_data *tdata = pdata->core_data[indx];
/* Remove the sysfs attributes */
- for (i = 0; i < tdata->attr_size; i++)
- device_remove_file(dev, &tdata->sd_attrs[i].dev_attr);
+ sysfs_remove_group(&pdata->hwmon_dev->kobj, &tdata->attr_group);
kfree(pdata->core_data[indx]);
pdata->core_data[indx] = NULL;
@@ -588,34 +566,20 @@ static void coretemp_remove_core(struct platform_data *pdata,
static int coretemp_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct platform_data *pdata;
- int err;
/* Initialize the per-package data structures */
- pdata = kzalloc(sizeof(struct platform_data), GFP_KERNEL);
+ pdata = devm_kzalloc(dev, sizeof(struct platform_data), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
- err = create_name_attr(pdata, &pdev->dev);
- if (err)
- goto exit_free;
-
pdata->phys_proc_id = pdev->id;
platform_set_drvdata(pdev, pdata);
- pdata->hwmon_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(pdata->hwmon_dev)) {
- err = PTR_ERR(pdata->hwmon_dev);
- dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
- goto exit_name;
- }
- return 0;
-
-exit_name:
- device_remove_file(&pdev->dev, &pdata->name_attr);
-exit_free:
- kfree(pdata);
- return err;
+ pdata->hwmon_dev = devm_hwmon_device_register_with_groups(dev, DRVNAME,
+ pdata, NULL);
+ return PTR_ERR_OR_ZERO(pdata->hwmon_dev);
}
static int coretemp_remove(struct platform_device *pdev)
@@ -625,11 +589,8 @@ static int coretemp_remove(struct platform_device *pdev)
for (i = MAX_CORE_DATA - 1; i >= 0; --i)
if (pdata->core_data[i])
- coretemp_remove_core(pdata, &pdev->dev, i);
+ coretemp_remove_core(pdata, i);
- device_remove_file(&pdev->dev, &pdata->name_attr);
- hwmon_device_unregister(pdata->hwmon_dev);
- kfree(pdata);
return 0;
}
@@ -777,7 +738,7 @@ static void put_core_offline(unsigned int cpu)
return;
if (pdata->core_data[indx] && pdata->core_data[indx]->cpu == cpu)
- coretemp_remove_core(pdata, &pdev->dev, indx);
+ coretemp_remove_core(pdata, indx);
/*
* If a HT sibling of a core is taken offline, but another HT sibling
diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c
index 2c137b26acb4..fd892dd48e4c 100644
--- a/drivers/hwmon/emc2103.c
+++ b/drivers/hwmon/emc2103.c
@@ -349,7 +349,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
dev_dbg(&client->dev, "reg 0x%02x, err %d\n",
REG_FAN_CONF1, status);
mutex_unlock(&data->update_lock);
- return -EIO;
+ return status;
}
status &= 0x9F;
status |= (new_range_bits << 5);
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
index e176a43af63d..a26c385a435b 100644
--- a/drivers/hwmon/hwmon.c
+++ b/drivers/hwmon/hwmon.c
@@ -22,6 +22,7 @@
#include <linux/gfp.h>
#include <linux/spinlock.h>
#include <linux/pci.h>
+#include <linux/string.h>
#define HWMON_ID_PREFIX "hwmon"
#define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d"
@@ -99,6 +100,10 @@ hwmon_device_register_with_groups(struct device *dev, const char *name,
struct hwmon_device *hwdev;
int err, id;
+ /* Do not accept invalid characters in hwmon name attribute */
+ if (name && (!strlen(name) || strpbrk(name, "-* \t\n")))
+ return ERR_PTR(-EINVAL);
+
id = ida_simple_get(&hwmon_ida, 0, 0, GFP_KERNEL);
if (id < 0)
return ERR_PTR(id);
diff --git a/drivers/hwmon/ibmpowernv.c b/drivers/hwmon/ibmpowernv.c
new file mode 100644
index 000000000000..b7b1297a9b02
--- /dev/null
+++ b/drivers/hwmon/ibmpowernv.c
@@ -0,0 +1,529 @@
+/*
+ * hwmon driver for temperature/power/fan on IBM PowerNV platform
+ * Copyright (C) 2013 IBM
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <asm/opal.h>
+#include <linux/err.h>
+
+MODULE_DESCRIPTION("IBM PowerNV Platform power/temp/fan sensor hwmon module");
+MODULE_LICENSE("GPL");
+
+#define MAX_ATTR_LENGTH 32
+
+/* Device tree sensor name prefixes. The device tree has the names in the
+ * format "cooling-fan#2-faulted" where the "cooling-fan" is the sensor type,
+ * 2 is the sensor count, and "faulted" is the sensor data attribute type.
+ */
+#define DT_FAULT_ATTR_SUFFIX "faulted"
+#define DT_DATA_ATTR_SUFFIX "data"
+#define DT_THRESHOLD_ATTR_SUFFIX "thrs"
+
+enum sensors {
+ FAN,
+ TEMPERATURE,
+ POWERSUPPLY,
+ POWER,
+ MAX_SENSOR_TYPE,
+};
+
+enum attributes {
+ INPUT,
+ MINIMUM,
+ MAXIMUM,
+ FAULT,
+ MAX_ATTR_TYPES
+};
+
+static struct sensor_name {
+ char *name;
+ char *compaible;
+} sensor_names[] = {
+ {"fan-sensor", "ibm,opal-sensor-cooling-fan"},
+ {"amb-temp-sensor", "ibm,opal-sensor-amb-temp"},
+ {"power-sensor", "ibm,opal-sensor-power-supply"},
+ {"power", "ibm,opal-sensor-power"}
+};
+
+static const char * const attribute_type_table[] = {
+ "input",
+ "min",
+ "max",
+ "fault",
+ NULL
+};
+
+struct pdev_entry {
+ struct list_head list;
+ struct platform_device *pdev;
+ enum sensors type;
+};
+
+static LIST_HEAD(pdev_list);
+
+/* The sensors are categorised on type.
+ *
+ * The sensors of same type are categorised under a common platform device.
+ * So, The pdev is shared by all sensors of same type.
+ * Ex : temp1_input, temp1_max, temp2_input,temp2_max all share same platform
+ * device.
+ *
+ * "sensor_data" is the Platform device specific data.
+ * There is one hwmon_device instance for all the sensors of same type.
+ * This also holds the list of all sensors with same type but different
+ * attribute and index.
+ */
+struct sensor_specific_data {
+ u32 sensor_id; /* The hex value as in the device tree */
+ u32 sensor_index; /* The sensor instance index */
+ struct sensor_device_attribute sd_attr;
+ enum attributes attr_type;
+ char attr_name[64];
+};
+
+struct sensor_data {
+ struct device *hwmon_dev;
+ struct list_head sensor_list;
+ struct device_attribute name_attr;
+};
+
+struct sensor_entry {
+ struct list_head list;
+ struct sensor_specific_data *sensor_data;
+};
+
+static struct platform_device *powernv_sensor_get_pdev(enum sensors type)
+{
+ struct pdev_entry *p;
+ list_for_each_entry(p, &pdev_list, list)
+ if (p->type == type)
+ return p->pdev;
+
+ return NULL;
+}
+
+static struct sensor_specific_data *powernv_sensor_get_sensor_data(
+ struct sensor_data *pdata,
+ int index, enum attributes attr_type)
+{
+ struct sensor_entry *p;
+ list_for_each_entry(p, &pdata->sensor_list, list)
+ if ((p->sensor_data->sensor_index == index) &&
+ (attr_type == p->sensor_data->attr_type))
+ return p->sensor_data;
+
+ return NULL;
+}
+
+static ssize_t show_name(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ return sprintf(buf, "%s\n", pdev->name);
+}
+
+/* Note: Data from the sensors for each sensor type needs to be converted to
+ * the dimension appropriate.
+ */
+static ssize_t show_sensor(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(devattr);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sensor_data *pdata = platform_get_drvdata(pdev);
+ struct sensor_specific_data *tdata = NULL;
+ enum sensors sensor_type = pdev->id;
+ u32 x = -1;
+ int ret;
+
+ if (sd_attr && sd_attr->dev_attr.attr.name) {
+ char *pos = strchr(sd_attr->dev_attr.attr.name, '_');
+ int i;
+
+ for (i = 0; i < MAX_ATTR_TYPES; i++) {
+ if (strcmp(pos+1, attribute_type_table[i]) == 0) {
+ tdata = powernv_sensor_get_sensor_data(pdata,
+ sd_attr->index, i);
+ break;
+ }
+ }
+ }
+
+ if (tdata) {
+ ret = opal_get_sensor_data(tdata->sensor_id, &x);
+ if (ret)
+ x = -1;
+ }
+
+ if (sensor_type == TEMPERATURE && x > 0) {
+ /* Temperature comes in Degrees and convert it to
+ * milli-degrees.
+ */
+ x = x*1000;
+ } else if (sensor_type == POWER && x > 0) {
+ /* Power value comes in watts, convert to micro-watts */
+ x = x * 1000000;
+ }
+
+ return sprintf(buf, "%d\n", x);
+}
+
+static u32 get_sensor_index_from_name(const char *name)
+{
+ char *hash_position = strchr(name, '#');
+ u32 index = 0, copy_length;
+ char newbuf[8];
+
+ if (hash_position) {
+ copy_length = strchr(hash_position, '-') - hash_position - 1;
+ if (copy_length < sizeof(newbuf)) {
+ strncpy(newbuf, hash_position + 1, copy_length);
+ sscanf(newbuf, "%d", &index);
+ }
+ }
+
+ return index;
+}
+
+static inline void get_sensor_suffix_from_name(const char *name, char *suffix)
+{
+ char *dash_position = strrchr(name, '-');
+ if (dash_position)
+ strncpy(suffix, dash_position+1, MAX_ATTR_LENGTH);
+ else
+ strcpy(suffix,"");
+}
+
+static int get_sensor_attr_properties(const char *sensor_name,
+ enum sensors sensor_type, enum attributes *attr_type,
+ u32 *sensor_index)
+{
+ char suffix[MAX_ATTR_LENGTH];
+
+ *attr_type = MAX_ATTR_TYPES;
+ *sensor_index = get_sensor_index_from_name(sensor_name);
+ if (*sensor_index == 0)
+ return -EINVAL;
+
+ get_sensor_suffix_from_name(sensor_name, suffix);
+ if (strcmp(suffix, "") == 0)
+ return -EINVAL;
+
+ if (strcmp(suffix, DT_FAULT_ATTR_SUFFIX) == 0)
+ *attr_type = FAULT;
+ else if (strcmp(suffix, DT_DATA_ATTR_SUFFIX) == 0)
+ *attr_type = INPUT;
+ else if ((sensor_type == TEMPERATURE) &&
+ (strcmp(suffix, DT_THRESHOLD_ATTR_SUFFIX) == 0))
+ *attr_type = MAXIMUM;
+ else if ((sensor_type == FAN) &&
+ (strcmp(suffix, DT_THRESHOLD_ATTR_SUFFIX) == 0))
+ *attr_type = MINIMUM;
+ else
+ return -ENOENT;
+
+ if (((sensor_type == FAN) && ((*attr_type == INPUT) ||
+ (*attr_type == MINIMUM)))
+ || ((sensor_type == TEMPERATURE) && ((*attr_type == INPUT) ||
+ (*attr_type == MAXIMUM)))
+ || ((sensor_type == POWER) && ((*attr_type == INPUT))))
+ return 0;
+
+ return -ENOENT;
+}
+
+static int create_sensor_attr(struct sensor_specific_data *tdata,
+ struct device *dev, enum sensors sensor_type,
+ enum attributes attr_type)
+{
+ int err = 0;
+ char temp_file_prefix[50];
+ static const char *const file_name_format = "%s%d_%s";
+
+ tdata->attr_type = attr_type;
+
+ if (sensor_type == FAN)
+ strcpy(temp_file_prefix, "fan");
+ else if (sensor_type == TEMPERATURE)
+ strcpy(temp_file_prefix, "temp");
+ else if (sensor_type == POWERSUPPLY)
+ strcpy(temp_file_prefix, "powersupply");
+ else if (sensor_type == POWER)
+ strcpy(temp_file_prefix, "power");
+
+ snprintf(tdata->attr_name, sizeof(tdata->attr_name), file_name_format,
+ temp_file_prefix, tdata->sensor_index,
+ attribute_type_table[tdata->attr_type]);
+
+ sysfs_attr_init(&tdata->sd_attr.dev_attr.attr);
+ tdata->sd_attr.dev_attr.attr.name = tdata->attr_name;
+ tdata->sd_attr.dev_attr.attr.mode = S_IRUGO;
+ tdata->sd_attr.dev_attr.show = show_sensor;
+
+ tdata->sd_attr.index = tdata->sensor_index;
+ err = device_create_file(dev, &tdata->sd_attr.dev_attr);
+
+ return err;
+}
+
+static int create_name_attr(struct sensor_data *pdata,
+ struct device *dev)
+{
+ sysfs_attr_init(&pdata->name_attr.attr);
+ pdata->name_attr.attr.name = "name";
+ pdata->name_attr.attr.mode = S_IRUGO;
+ pdata->name_attr.show = show_name;
+ return device_create_file(dev, &pdata->name_attr);
+}
+
+static int create_platform_device(enum sensors sensor_type,
+ struct platform_device **pdev)
+{
+ struct pdev_entry *pdev_entry = NULL;
+ int err;
+
+ *pdev = platform_device_alloc(sensor_names[sensor_type].name,
+ sensor_type);
+ if (!*pdev) {
+ pr_err("Device allocation failed\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ pdev_entry = kzalloc(sizeof(struct pdev_entry), GFP_KERNEL);
+ if (!pdev_entry) {
+ pr_err("Device allocation failed\n");
+ err = -ENOMEM;
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(*pdev);
+ if (err) {
+ pr_err("Device addition failed (%d)\n", err);
+ goto exit_device_free;
+ }
+
+ pdev_entry->pdev = *pdev;
+ pdev_entry->type = (*pdev)->id;
+
+ list_add_tail(&pdev_entry->list, &pdev_list);
+
+ return 0;
+exit_device_free:
+ kfree(pdev_entry);
+exit_device_put:
+ platform_device_put(*pdev);
+exit:
+ return err;
+}
+
+static int create_sensor_data(struct platform_device *pdev)
+{
+ struct sensor_data *pdata = NULL;
+ int err = 0;
+
+ pdata = kzalloc(sizeof(struct sensor_data), GFP_KERNEL);
+ if (!pdata) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ err = create_name_attr(pdata, &pdev->dev);
+ if (err)
+ goto exit_free;
+
+ pdata->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(pdata->hwmon_dev)) {
+ err = PTR_ERR(pdata->hwmon_dev);
+ dev_err(&pdev->dev, "Class registration failed (%d)\n",
+ err);
+ goto exit_name;
+ }
+
+ INIT_LIST_HEAD(&pdata->sensor_list);
+ platform_set_drvdata(pdev, pdata);
+
+ return 0;
+
+exit_name:
+ device_remove_file(&pdev->dev, &pdata->name_attr);
+exit_free:
+ kfree(pdata);
+exit:
+ return err;
+}
+
+static void delete_sensor_attr(struct sensor_data *pdata)
+{
+ struct sensor_entry *s, *l;
+
+ list_for_each_entry_safe(s, l, &pdata->sensor_list, list) {
+ struct sensor_specific_data *tdata = s->sensor_data;
+ kfree(tdata);
+ list_del(&s->list);
+ kfree(s);
+ }
+}
+
+static int powernv_sensor_init(u32 sensor_id, const struct device_node *np,
+ enum sensors sensor_type, enum attributes attr_type,
+ u32 sensor_index)
+{
+ struct platform_device *pdev = powernv_sensor_get_pdev(sensor_type);
+ struct sensor_specific_data *tdata;
+ struct sensor_entry *sensor_entry;
+ struct sensor_data *pdata;
+ int err = 0;
+
+ if (!pdev) {
+ err = create_platform_device(sensor_type, &pdev);
+ if (err)
+ goto exit;
+
+ err = create_sensor_data(pdev);
+ if (err)
+ goto exit;
+ }
+
+ pdata = platform_get_drvdata(pdev);
+ if (!pdata) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ tdata = kzalloc(sizeof(struct sensor_specific_data), GFP_KERNEL);
+ if (!tdata) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ tdata->sensor_id = sensor_id;
+ tdata->sensor_index = sensor_index;
+
+ err = create_sensor_attr(tdata, &pdev->dev, sensor_type, attr_type);
+ if (err)
+ goto exit_free;
+
+ sensor_entry = kzalloc(sizeof(struct sensor_entry), GFP_KERNEL);
+ if (!sensor_entry) {
+ err = -ENOMEM;
+ goto exit_attr;
+ }
+
+ sensor_entry->sensor_data = tdata;
+
+ list_add_tail(&sensor_entry->list, &pdata->sensor_list);
+
+ return 0;
+exit_attr:
+ device_remove_file(&pdev->dev, &tdata->sd_attr.dev_attr);
+exit_free:
+ kfree(tdata);
+exit:
+ return err;
+}
+
+static void delete_unregister_sensors(void)
+{
+ struct pdev_entry *p, *n;
+
+ list_for_each_entry_safe(p, n, &pdev_list, list) {
+ struct sensor_data *pdata = platform_get_drvdata(p->pdev);
+ if (pdata) {
+ delete_sensor_attr(pdata);
+
+ hwmon_device_unregister(pdata->hwmon_dev);
+ kfree(pdata);
+ }
+ platform_device_unregister(p->pdev);
+ list_del(&p->list);
+ kfree(p);
+ }
+}
+
+static int __init powernv_hwmon_init(void)
+{
+ struct device_node *opal, *np = NULL;
+ enum attributes attr_type;
+ enum sensors type;
+ const u32 *sensor_id;
+ u32 sensor_index;
+ int err;
+
+ opal = of_find_node_by_path("/ibm,opal/sensors");
+ if (!opal) {
+ pr_err("%s: Opal 'sensors' node not found\n", __func__);
+ return -ENXIO;
+ }
+
+ for_each_child_of_node(opal, np) {
+ if (np->name == NULL)
+ continue;
+
+ for (type = 0; type < MAX_SENSOR_TYPE; type++)
+ if (of_device_is_compatible(np,
+ sensor_names[type].compaible))
+ break;
+
+ if (type == MAX_SENSOR_TYPE)
+ continue;
+
+ if (get_sensor_attr_properties(np->name, type, &attr_type,
+ &sensor_index))
+ continue;
+
+ sensor_id = of_get_property(np, "sensor-id", NULL);
+ if (!sensor_id) {
+ pr_info("%s: %s doesn't have sensor-id\n", __func__,
+ np->name);
+ continue;
+ }
+
+ err = powernv_sensor_init(*sensor_id, np, type, attr_type,
+ sensor_index);
+ if (err) {
+ of_node_put(opal);
+ goto exit;
+ }
+ }
+ of_node_put(opal);
+
+ return 0;
+exit:
+ delete_unregister_sensors();
+ return err;
+
+}
+
+static void powernv_hwmon_exit(void)
+{
+ delete_unregister_sensors();
+}
+
+module_init(powernv_hwmon_init);
+module_exit(powernv_hwmon_exit);
diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c
index 708081b68c6f..9fbb1b1fdff3 100644
--- a/drivers/hwmon/iio_hwmon.c
+++ b/drivers/hwmon/iio_hwmon.c
@@ -31,6 +31,7 @@ struct iio_hwmon_state {
int num_channels;
struct device *hwmon_dev;
struct attribute_group attr_group;
+ const struct attribute_group *groups[2];
struct attribute **attrs;
};
@@ -56,19 +57,6 @@ static ssize_t iio_hwmon_read_val(struct device *dev,
return sprintf(buf, "%d\n", result);
}
-static ssize_t show_name(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- const char *name = "iio_hwmon";
-
- if (dev->of_node && dev->of_node->name)
- name = dev->of_node->name;
-
- return sprintf(buf, "%s\n", name);
-}
-
-static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
-
static int iio_hwmon_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -78,6 +66,10 @@ static int iio_hwmon_probe(struct platform_device *pdev)
int in_i = 1, temp_i = 1, curr_i = 1;
enum iio_chan_type type;
struct iio_channel *channels;
+ const char *name = "iio_hwmon";
+
+ if (dev->of_node && dev->of_node->name)
+ name = dev->of_node->name;
channels = iio_channel_get_all(dev);
if (IS_ERR(channels))
@@ -96,7 +88,7 @@ static int iio_hwmon_probe(struct platform_device *pdev)
st->num_channels++;
st->attrs = devm_kzalloc(dev,
- sizeof(*st->attrs) * (st->num_channels + 2),
+ sizeof(*st->attrs) * (st->num_channels + 1),
GFP_KERNEL);
if (st->attrs == NULL) {
ret = -ENOMEM;
@@ -144,22 +136,18 @@ static int iio_hwmon_probe(struct platform_device *pdev)
a->index = i;
st->attrs[i] = &a->dev_attr.attr;
}
- st->attrs[st->num_channels] = &dev_attr_name.attr;
- st->attr_group.attrs = st->attrs;
- platform_set_drvdata(pdev, st);
- ret = sysfs_create_group(&dev->kobj, &st->attr_group);
- if (ret < 0)
- goto error_release_channels;
- st->hwmon_dev = hwmon_device_register(dev);
+ st->attr_group.attrs = st->attrs;
+ st->groups[0] = &st->attr_group;
+ st->hwmon_dev = hwmon_device_register_with_groups(dev, name, st,
+ st->groups);
if (IS_ERR(st->hwmon_dev)) {
ret = PTR_ERR(st->hwmon_dev);
- goto error_remove_group;
+ goto error_release_channels;
}
+ platform_set_drvdata(pdev, st);
return 0;
-error_remove_group:
- sysfs_remove_group(&dev->kobj, &st->attr_group);
error_release_channels:
iio_channel_release_all(channels);
return ret;
@@ -170,7 +158,6 @@ static int iio_hwmon_remove(struct platform_device *pdev)
struct iio_hwmon_state *st = platform_get_drvdata(pdev);
hwmon_device_unregister(st->hwmon_dev);
- sysfs_remove_group(&pdev->dev.kobj, &st->attr_group);
iio_channel_release_all(st->channels);
return 0;
diff --git a/drivers/hwmon/jz4740-hwmon.c b/drivers/hwmon/jz4740-hwmon.c
index a183e488db78..7488e36809c8 100644
--- a/drivers/hwmon/jz4740-hwmon.c
+++ b/drivers/hwmon/jz4740-hwmon.c
@@ -28,7 +28,6 @@
#include <linux/hwmon.h>
struct jz4740_hwmon {
- struct resource *mem;
void __iomem *base;
int irq;
@@ -106,6 +105,7 @@ static int jz4740_hwmon_probe(struct platform_device *pdev)
{
int ret;
struct jz4740_hwmon *hwmon;
+ struct resource *mem;
hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL);
if (!hwmon)
@@ -120,25 +120,10 @@ static int jz4740_hwmon_probe(struct platform_device *pdev)
return hwmon->irq;
}
- hwmon->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!hwmon->mem) {
- dev_err(&pdev->dev, "Failed to get platform mmio resource\n");
- return -ENOENT;
- }
-
- hwmon->mem = devm_request_mem_region(&pdev->dev, hwmon->mem->start,
- resource_size(hwmon->mem), pdev->name);
- if (!hwmon->mem) {
- dev_err(&pdev->dev, "Failed to request mmio memory region\n");
- return -EBUSY;
- }
-
- hwmon->base = devm_ioremap_nocache(&pdev->dev, hwmon->mem->start,
- resource_size(hwmon->mem));
- if (!hwmon->base) {
- dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
- return -EBUSY;
- }
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hwmon->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(hwmon->base))
+ return PTR_ERR(hwmon->base);
init_completion(&hwmon->read_completion);
mutex_init(&hwmon->lock);
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
index baf375b5ab0d..f7b46f68ef43 100644
--- a/drivers/hwmon/k10temp.c
+++ b/drivers/hwmon/k10temp.c
@@ -212,6 +212,7 @@ static const struct pci_device_id k10temp_id_table[] = {
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
{}
};
MODULE_DEVICE_TABLE(pci, k10temp_id_table);
diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c
index 4b68fb2a31d7..cdf19adaec79 100644
--- a/drivers/hwmon/lm95241.c
+++ b/drivers/hwmon/lm95241.c
@@ -89,7 +89,7 @@ static const u8 lm95241_reg_address[] = {
/* Client data (each client gets its own) */
struct lm95241_data {
- struct device *hwmon_dev;
+ struct i2c_client *client;
struct mutex update_lock;
unsigned long last_updated, interval; /* in jiffies */
char valid; /* zero until following fields are valid */
@@ -113,8 +113,8 @@ static int temp_from_reg_unsigned(u8 val_h, u8 val_l)
static struct lm95241_data *lm95241_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95241_data *data = i2c_get_clientdata(client);
+ struct lm95241_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
mutex_lock(&data->update_lock);
@@ -122,7 +122,7 @@ static struct lm95241_data *lm95241_update_device(struct device *dev)
!data->valid) {
int i;
- dev_dbg(&client->dev, "Updating lm95241 data.\n");
+ dev_dbg(dev, "Updating lm95241 data.\n");
for (i = 0; i < ARRAY_SIZE(lm95241_reg_address); i++)
data->temp[i]
= i2c_smbus_read_byte_data(client,
@@ -153,8 +153,7 @@ static ssize_t show_input(struct device *dev, struct device_attribute *attr,
static ssize_t show_type(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95241_data *data = i2c_get_clientdata(client);
+ struct lm95241_data *data = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE - 1,
data->model & to_sensor_dev_attr(attr)->index ? "1\n" : "2\n");
@@ -163,8 +162,8 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr,
static ssize_t set_type(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95241_data *data = i2c_get_clientdata(client);
+ struct lm95241_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
unsigned long val;
int shift;
u8 mask = to_sensor_dev_attr(attr)->index;
@@ -201,8 +200,7 @@ static ssize_t set_type(struct device *dev, struct device_attribute *attr,
static ssize_t show_min(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95241_data *data = i2c_get_clientdata(client);
+ struct lm95241_data *data = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE - 1,
data->config & to_sensor_dev_attr(attr)->index ?
@@ -212,8 +210,7 @@ static ssize_t show_min(struct device *dev, struct device_attribute *attr,
static ssize_t set_min(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95241_data *data = i2c_get_clientdata(client);
+ struct lm95241_data *data = dev_get_drvdata(dev);
long val;
if (kstrtol(buf, 10, &val) < 0)
@@ -229,7 +226,8 @@ static ssize_t set_min(struct device *dev, struct device_attribute *attr,
data->config &= ~to_sensor_dev_attr(attr)->index;
data->valid = 0;
- i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
+ i2c_smbus_write_byte_data(data->client, LM95241_REG_RW_CONFIG,
+ data->config);
mutex_unlock(&data->update_lock);
@@ -239,8 +237,7 @@ static ssize_t set_min(struct device *dev, struct device_attribute *attr,
static ssize_t show_max(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95241_data *data = i2c_get_clientdata(client);
+ struct lm95241_data *data = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE - 1,
data->config & to_sensor_dev_attr(attr)->index ?
@@ -250,8 +247,7 @@ static ssize_t show_max(struct device *dev, struct device_attribute *attr,
static ssize_t set_max(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95241_data *data = i2c_get_clientdata(client);
+ struct lm95241_data *data = dev_get_drvdata(dev);
long val;
if (kstrtol(buf, 10, &val) < 0)
@@ -267,7 +263,8 @@ static ssize_t set_max(struct device *dev, struct device_attribute *attr,
data->config &= ~to_sensor_dev_attr(attr)->index;
data->valid = 0;
- i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
+ i2c_smbus_write_byte_data(data->client, LM95241_REG_RW_CONFIG,
+ data->config);
mutex_unlock(&data->update_lock);
@@ -286,8 +283,7 @@ static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95241_data *data = i2c_get_clientdata(client);
+ struct lm95241_data *data = dev_get_drvdata(dev);
unsigned long val;
if (kstrtoul(buf, 10, &val) < 0)
@@ -316,7 +312,7 @@ static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max, set_max,
static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
set_interval);
-static struct attribute *lm95241_attributes[] = {
+static struct attribute *lm95241_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
&sensor_dev_attr_temp3_input.dev_attr.attr,
@@ -329,10 +325,7 @@ static struct attribute *lm95241_attributes[] = {
&dev_attr_update_interval.attr,
NULL
};
-
-static const struct attribute_group lm95241_group = {
- .attrs = lm95241_attributes,
-};
+ATTRIBUTE_GROUPS(lm95241);
/* Return 0 if detection is successful, -ENODEV otherwise */
static int lm95241_detect(struct i2c_client *new_client,
@@ -366,14 +359,11 @@ static int lm95241_detect(struct i2c_client *new_client,
return 0;
}
-static void lm95241_init_client(struct i2c_client *client)
+static void lm95241_init_client(struct i2c_client *client,
+ struct lm95241_data *data)
{
- struct lm95241_data *data = i2c_get_clientdata(client);
-
data->interval = HZ; /* 1 sec default */
- data->valid = 0;
data->config = CFG_CR0076;
- data->model = 0;
data->trutherm = (TT_OFF << TT1_SHIFT) | (TT_OFF << TT2_SHIFT);
i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
@@ -385,49 +375,27 @@ static void lm95241_init_client(struct i2c_client *client)
data->model);
}
-static int lm95241_probe(struct i2c_client *new_client,
+static int lm95241_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct device *dev = &client->dev;
struct lm95241_data *data;
- int err;
+ struct device *hwmon_dev;
- data = devm_kzalloc(&new_client->dev, sizeof(struct lm95241_data),
- GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(struct lm95241_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- i2c_set_clientdata(new_client, data);
+ data->client = client;
mutex_init(&data->update_lock);
/* Initialize the LM95241 chip */
- lm95241_init_client(new_client);
+ lm95241_init_client(client, data);
- /* Register sysfs hooks */
- err = sysfs_create_group(&new_client->dev.kobj, &lm95241_group);
- if (err)
- return err;
-
- data->hwmon_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->hwmon_dev)) {
- err = PTR_ERR(data->hwmon_dev);
- goto exit_remove_files;
- }
-
- return 0;
-
-exit_remove_files:
- sysfs_remove_group(&new_client->dev.kobj, &lm95241_group);
- return err;
-}
-
-static int lm95241_remove(struct i2c_client *client)
-{
- struct lm95241_data *data = i2c_get_clientdata(client);
-
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &lm95241_group);
-
- return 0;
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ data,
+ lm95241_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}
/* Driver data (common to all clients) */
@@ -444,7 +412,6 @@ static struct i2c_driver lm95241_driver = {
.name = DEVNAME,
},
.probe = lm95241_probe,
- .remove = lm95241_remove,
.id_table = lm95241_id,
.detect = lm95241_detect,
.address_list = normal_i2c,
diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c
index a6c85f0ff8f3..0ae0dfdafdff 100644
--- a/drivers/hwmon/lm95245.c
+++ b/drivers/hwmon/lm95245.c
@@ -115,7 +115,7 @@ static const u8 lm95245_reg_address[] = {
/* Client data (each client gets its own) */
struct lm95245_data {
- struct device *hwmon_dev;
+ struct i2c_client *client;
struct mutex update_lock;
unsigned long last_updated; /* in jiffies */
unsigned long interval; /* in msecs */
@@ -140,8 +140,8 @@ static int temp_from_reg_signed(u8 val_h, u8 val_l)
static struct lm95245_data *lm95245_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95245_data *data = i2c_get_clientdata(client);
+ struct lm95245_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
mutex_lock(&data->update_lock);
@@ -149,7 +149,6 @@ static struct lm95245_data *lm95245_update_device(struct device *dev)
+ msecs_to_jiffies(data->interval)) || !data->valid) {
int i;
- dev_dbg(&client->dev, "Updating lm95245 data.\n");
for (i = 0; i < ARRAY_SIZE(lm95245_reg_address); i++)
data->regs[i]
= i2c_smbus_read_byte_data(client,
@@ -249,9 +248,9 @@ static ssize_t show_limit(struct device *dev, struct device_attribute *attr,
static ssize_t set_limit(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95245_data *data = i2c_get_clientdata(client);
+ struct lm95245_data *data = dev_get_drvdata(dev);
int index = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = data->client;
unsigned long val;
if (kstrtoul(buf, 10, &val) < 0)
@@ -272,27 +271,38 @@ static ssize_t set_limit(struct device *dev, struct device_attribute *attr,
return count;
}
+static ssize_t show_crit_hyst(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct lm95245_data *data = lm95245_update_device(dev);
+ int index = to_sensor_dev_attr(attr)->index;
+ int hyst = data->regs[index] - data->regs[8];
+
+ return snprintf(buf, PAGE_SIZE - 1, "%d\n", hyst * 1000);
+}
+
static ssize_t set_crit_hyst(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95245_data *data = i2c_get_clientdata(client);
+ struct lm95245_data *data = dev_get_drvdata(dev);
+ int index = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = data->client;
unsigned long val;
+ int hyst, limit;
if (kstrtoul(buf, 10, &val) < 0)
return -EINVAL;
- val /= 1000;
-
- val = clamp_val(val, 0, 31);
-
mutex_lock(&data->update_lock);
- data->valid = 0;
+ limit = i2c_smbus_read_byte_data(client, lm95245_reg_address[index]);
+ hyst = limit - val / 1000;
+ hyst = clamp_val(hyst, 0, 31);
+ data->regs[8] = hyst;
/* shared crit hysteresis */
i2c_smbus_write_byte_data(client, LM95245_REG_RW_COMMON_HYSTERESIS,
- val);
+ hyst);
mutex_unlock(&data->update_lock);
@@ -302,8 +312,7 @@ static ssize_t set_crit_hyst(struct device *dev, struct device_attribute *attr,
static ssize_t show_type(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95245_data *data = i2c_get_clientdata(client);
+ struct lm95245_data *data = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE - 1,
data->config2 & CFG2_REMOTE_TT ? "1\n" : "2\n");
@@ -312,8 +321,8 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr,
static ssize_t set_type(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95245_data *data = i2c_get_clientdata(client);
+ struct lm95245_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
unsigned long val;
if (kstrtoul(buf, 10, &val) < 0)
@@ -359,8 +368,8 @@ static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95245_data *data = i2c_get_clientdata(client);
+ struct lm95245_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
unsigned long val;
if (kstrtoul(buf, 10, &val) < 0)
@@ -378,16 +387,15 @@ static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_limit,
set_limit, 6);
-static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_limit,
- set_crit_hyst, 8);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_crit_hyst,
+ set_crit_hyst, 6);
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL,
STATUS1_LOC);
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, 2);
static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_limit,
set_limit, 7);
-static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_limit,
- set_crit_hyst, 8);
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_crit_hyst, NULL, 7);
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL,
STATUS1_RTCRIT);
static SENSOR_DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type,
@@ -398,7 +406,7 @@ static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL,
static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
set_interval);
-static struct attribute *lm95245_attributes[] = {
+static struct attribute *lm95245_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_crit.dev_attr.attr,
&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
@@ -412,10 +420,7 @@ static struct attribute *lm95245_attributes[] = {
&dev_attr_update_interval.attr,
NULL
};
-
-static const struct attribute_group lm95245_group = {
- .attrs = lm95245_attributes,
-};
+ATTRIBUTE_GROUPS(lm95245);
/* Return 0 if detection is successful, -ENODEV otherwise */
static int lm95245_detect(struct i2c_client *new_client,
@@ -436,11 +441,9 @@ static int lm95245_detect(struct i2c_client *new_client,
return 0;
}
-static void lm95245_init_client(struct i2c_client *client)
+static void lm95245_init_client(struct i2c_client *client,
+ struct lm95245_data *data)
{
- struct lm95245_data *data = i2c_get_clientdata(client);
-
- data->valid = 0;
data->interval = lm95245_read_conversion_rate(client);
data->config1 = i2c_smbus_read_byte_data(client,
@@ -456,49 +459,27 @@ static void lm95245_init_client(struct i2c_client *client)
}
}
-static int lm95245_probe(struct i2c_client *new_client,
+static int lm95245_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct device *dev = &client->dev;
struct lm95245_data *data;
- int err;
+ struct device *hwmon_dev;
- data = devm_kzalloc(&new_client->dev, sizeof(struct lm95245_data),
- GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(struct lm95245_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- i2c_set_clientdata(new_client, data);
+ data->client = client;
mutex_init(&data->update_lock);
/* Initialize the LM95245 chip */
- lm95245_init_client(new_client);
-
- /* Register sysfs hooks */
- err = sysfs_create_group(&new_client->dev.kobj, &lm95245_group);
- if (err)
- return err;
-
- data->hwmon_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->hwmon_dev)) {
- err = PTR_ERR(data->hwmon_dev);
- goto exit_remove_files;
- }
-
- return 0;
-
-exit_remove_files:
- sysfs_remove_group(&new_client->dev.kobj, &lm95245_group);
- return err;
-}
+ lm95245_init_client(client, data);
-static int lm95245_remove(struct i2c_client *client)
-{
- struct lm95245_data *data = i2c_get_clientdata(client);
-
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &lm95245_group);
-
- return 0;
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ data,
+ lm95245_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}
/* Driver data (common to all clients) */
@@ -514,7 +495,6 @@ static struct i2c_driver lm95245_driver = {
.name = DEVNAME,
},
.probe = lm95245_probe,
- .remove = lm95245_remove,
.id_table = lm95245_id,
.detect = lm95245_detect,
.address_list = normal_i2c,
diff --git a/drivers/hwmon/ltc2945.c b/drivers/hwmon/ltc2945.c
new file mode 100644
index 000000000000..c104cc32989d
--- /dev/null
+++ b/drivers/hwmon/ltc2945.c
@@ -0,0 +1,519 @@
+/*
+ * Driver for Linear Technology LTC2945 I2C Power Monitor
+ *
+ * Copyright (c) 2014 Guenter Roeck
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/regmap.h>
+
+/* chip registers */
+#define LTC2945_CONTROL 0x00
+#define LTC2945_ALERT 0x01
+#define LTC2945_STATUS 0x02
+#define LTC2945_FAULT 0x03
+#define LTC2945_POWER_H 0x05
+#define LTC2945_MAX_POWER_H 0x08
+#define LTC2945_MIN_POWER_H 0x0b
+#define LTC2945_MAX_POWER_THRES_H 0x0e
+#define LTC2945_MIN_POWER_THRES_H 0x11
+#define LTC2945_SENSE_H 0x14
+#define LTC2945_MAX_SENSE_H 0x16
+#define LTC2945_MIN_SENSE_H 0x18
+#define LTC2945_MAX_SENSE_THRES_H 0x1a
+#define LTC2945_MIN_SENSE_THRES_H 0x1c
+#define LTC2945_VIN_H 0x1e
+#define LTC2945_MAX_VIN_H 0x20
+#define LTC2945_MIN_VIN_H 0x22
+#define LTC2945_MAX_VIN_THRES_H 0x24
+#define LTC2945_MIN_VIN_THRES_H 0x26
+#define LTC2945_ADIN_H 0x28
+#define LTC2945_MAX_ADIN_H 0x2a
+#define LTC2945_MIN_ADIN_H 0x2c
+#define LTC2945_MAX_ADIN_THRES_H 0x2e
+#define LTC2945_MIN_ADIN_THRES_H 0x30
+#define LTC2945_MIN_ADIN_THRES_L 0x31
+
+/* Fault register bits */
+
+#define FAULT_ADIN_UV (1 << 0)
+#define FAULT_ADIN_OV (1 << 1)
+#define FAULT_VIN_UV (1 << 2)
+#define FAULT_VIN_OV (1 << 3)
+#define FAULT_SENSE_UV (1 << 4)
+#define FAULT_SENSE_OV (1 << 5)
+#define FAULT_POWER_UV (1 << 6)
+#define FAULT_POWER_OV (1 << 7)
+
+/* Control register bits */
+
+#define CONTROL_MULT_SELECT (1 << 0)
+#define CONTROL_TEST_MODE (1 << 4)
+
+static inline bool is_power_reg(u8 reg)
+{
+ return reg < LTC2945_SENSE_H;
+}
+
+/* Return the value from the given register in uW, mV, or mA */
+static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
+{
+ struct regmap *regmap = dev_get_drvdata(dev);
+ unsigned int control;
+ u8 buf[3];
+ long long val;
+ int ret;
+
+ ret = regmap_bulk_read(regmap, reg, buf,
+ is_power_reg(reg) ? 3 : 2);
+ if (ret < 0)
+ return ret;
+
+ if (is_power_reg(reg)) {
+ /* power */
+ val = (buf[0] << 16) + (buf[1] << 8) + buf[2];
+ } else {
+ /* current, voltage */
+ val = (buf[0] << 4) + (buf[1] >> 4);
+ }
+
+ switch (reg) {
+ case LTC2945_POWER_H:
+ case LTC2945_MAX_POWER_H:
+ case LTC2945_MIN_POWER_H:
+ case LTC2945_MAX_POWER_THRES_H:
+ case LTC2945_MIN_POWER_THRES_H:
+ /*
+ * Convert to uW by assuming current is measured with
+ * an 1mOhm sense resistor, similar to current
+ * measurements.
+ * Control register bit 0 selects if voltage at SENSE+/VDD
+ * or voltage at ADIN is used to measure power.
+ */
+ ret = regmap_read(regmap, LTC2945_CONTROL, &control);
+ if (ret < 0)
+ return ret;
+ if (control & CONTROL_MULT_SELECT) {
+ /* 25 mV * 25 uV = 0.625 uV resolution. */
+ val *= 625LL;
+ } else {
+ /* 0.5 mV * 25 uV = 0.0125 uV resolution. */
+ val = (val * 25LL) >> 1;
+ }
+ break;
+ case LTC2945_VIN_H:
+ case LTC2945_MAX_VIN_H:
+ case LTC2945_MIN_VIN_H:
+ case LTC2945_MAX_VIN_THRES_H:
+ case LTC2945_MIN_VIN_THRES_H:
+ /* 25 mV resolution. Convert to mV. */
+ val *= 25;
+ break;
+ case LTC2945_ADIN_H:
+ case LTC2945_MAX_ADIN_H:
+ case LTC2945_MIN_ADIN_THRES_H:
+ case LTC2945_MAX_ADIN_THRES_H:
+ case LTC2945_MIN_ADIN_H:
+ /* 0.5mV resolution. Convert to mV. */
+ val = val >> 1;
+ break;
+ case LTC2945_SENSE_H:
+ case LTC2945_MAX_SENSE_H:
+ case LTC2945_MIN_SENSE_H:
+ case LTC2945_MAX_SENSE_THRES_H:
+ case LTC2945_MIN_SENSE_THRES_H:
+ /*
+ * 25 uV resolution. Convert to current as measured with
+ * an 1 mOhm sense resistor, in mA. If a different sense
+ * resistor is installed, calculate the actual current by
+ * dividing the reported current by the sense resistor value
+ * in mOhm.
+ */
+ val *= 25;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return val;
+}
+
+static int ltc2945_val_to_reg(struct device *dev, u8 reg,
+ unsigned long val)
+{
+ struct regmap *regmap = dev_get_drvdata(dev);
+ unsigned int control;
+ int ret;
+
+ switch (reg) {
+ case LTC2945_POWER_H:
+ case LTC2945_MAX_POWER_H:
+ case LTC2945_MIN_POWER_H:
+ case LTC2945_MAX_POWER_THRES_H:
+ case LTC2945_MIN_POWER_THRES_H:
+ /*
+ * Convert to register value by assuming current is measured
+ * with an 1mOhm sense resistor, similar to current
+ * measurements.
+ * Control register bit 0 selects if voltage at SENSE+/VDD
+ * or voltage at ADIN is used to measure power, which in turn
+ * determines register calculations.
+ */
+ ret = regmap_read(regmap, LTC2945_CONTROL, &control);
+ if (ret < 0)
+ return ret;
+ if (control & CONTROL_MULT_SELECT) {
+ /* 25 mV * 25 uV = 0.625 uV resolution. */
+ val = DIV_ROUND_CLOSEST(val, 625);
+ } else {
+ /*
+ * 0.5 mV * 25 uV = 0.0125 uV resolution.
+ * Divide first to avoid overflow;
+ * accept loss of accuracy.
+ */
+ val = DIV_ROUND_CLOSEST(val, 25) * 2;
+ }
+ break;
+ case LTC2945_VIN_H:
+ case LTC2945_MAX_VIN_H:
+ case LTC2945_MIN_VIN_H:
+ case LTC2945_MAX_VIN_THRES_H:
+ case LTC2945_MIN_VIN_THRES_H:
+ /* 25 mV resolution. */
+ val /= 25;
+ break;
+ case LTC2945_ADIN_H:
+ case LTC2945_MAX_ADIN_H:
+ case LTC2945_MIN_ADIN_THRES_H:
+ case LTC2945_MAX_ADIN_THRES_H:
+ case LTC2945_MIN_ADIN_H:
+ /* 0.5mV resolution. */
+ val *= 2;
+ break;
+ case LTC2945_SENSE_H:
+ case LTC2945_MAX_SENSE_H:
+ case LTC2945_MIN_SENSE_H:
+ case LTC2945_MAX_SENSE_THRES_H:
+ case LTC2945_MIN_SENSE_THRES_H:
+ /*
+ * 25 uV resolution. Convert to current as measured with
+ * an 1 mOhm sense resistor, in mA. If a different sense
+ * resistor is installed, calculate the actual current by
+ * dividing the reported current by the sense resistor value
+ * in mOhm.
+ */
+ val = DIV_ROUND_CLOSEST(val, 25);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return val;
+}
+
+static ssize_t ltc2945_show_value(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ long long value;
+
+ value = ltc2945_reg_to_val(dev, attr->index);
+ if (value < 0)
+ return value;
+ return snprintf(buf, PAGE_SIZE, "%lld\n", value);
+}
+
+static ssize_t ltc2945_set_value(struct device *dev,
+ struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct regmap *regmap = dev_get_drvdata(dev);
+ u8 reg = attr->index;
+ unsigned long val;
+ u8 regbuf[3];
+ int num_regs;
+ int regval;
+ int ret;
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ /* convert to register value, then clamp and write result */
+ regval = ltc2945_val_to_reg(dev, reg, val);
+ if (is_power_reg(reg)) {
+ regval = clamp_val(regval, 0, 0xffffff);
+ regbuf[0] = regval >> 16;
+ regbuf[1] = (regval >> 8) & 0xff;
+ regbuf[2] = regval;
+ num_regs = 3;
+ } else {
+ regval = clamp_val(regval, 0, 0xfff) << 4;
+ regbuf[0] = regval >> 8;
+ regbuf[1] = regval & 0xff;
+ num_regs = 2;
+ }
+ ret = regmap_bulk_write(regmap, reg, regbuf, num_regs);
+ return ret < 0 ? ret : count;
+}
+
+static ssize_t ltc2945_reset_history(struct device *dev,
+ struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct regmap *regmap = dev_get_drvdata(dev);
+ u8 reg = attr->index;
+ int num_regs = is_power_reg(reg) ? 3 : 2;
+ u8 buf_min[3] = { 0xff, 0xff, 0xff };
+ u8 buf_max[3] = { 0, 0, 0 };
+ unsigned long val;
+ int ret;
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret)
+ return ret;
+ if (val != 1)
+ return -EINVAL;
+
+ ret = regmap_update_bits(regmap, LTC2945_CONTROL, CONTROL_TEST_MODE,
+ CONTROL_TEST_MODE);
+
+ /* Reset minimum */
+ ret = regmap_bulk_write(regmap, reg, buf_min, num_regs);
+ if (ret)
+ return ret;
+
+ switch (reg) {
+ case LTC2945_MIN_POWER_H:
+ reg = LTC2945_MAX_POWER_H;
+ break;
+ case LTC2945_MIN_SENSE_H:
+ reg = LTC2945_MAX_SENSE_H;
+ break;
+ case LTC2945_MIN_VIN_H:
+ reg = LTC2945_MAX_VIN_H;
+ break;
+ case LTC2945_MIN_ADIN_H:
+ reg = LTC2945_MAX_ADIN_H;
+ break;
+ default:
+ BUG();
+ break;
+ }
+ /* Reset maximum */
+ ret = regmap_bulk_write(regmap, reg, buf_max, num_regs);
+
+ /* Try resetting test mode even if there was an error */
+ regmap_update_bits(regmap, LTC2945_CONTROL, CONTROL_TEST_MODE, 0);
+
+ return ret ? : count;
+}
+
+static ssize_t ltc2945_show_bool(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct regmap *regmap = dev_get_drvdata(dev);
+ unsigned int fault;
+ int ret;
+
+ ret = regmap_read(regmap, LTC2945_FAULT, &fault);
+ if (ret < 0)
+ return ret;
+
+ fault &= attr->index;
+ if (fault) /* Clear reported faults in chip register */
+ regmap_update_bits(regmap, LTC2945_FAULT, attr->index, 0);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
+}
+
+/* Input voltages */
+
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc2945_show_value, NULL,
+ LTC2945_VIN_H);
+static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR, ltc2945_show_value,
+ ltc2945_set_value, LTC2945_MIN_VIN_THRES_H);
+static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, ltc2945_show_value,
+ ltc2945_set_value, LTC2945_MAX_VIN_THRES_H);
+static SENSOR_DEVICE_ATTR(in1_lowest, S_IRUGO, ltc2945_show_value, NULL,
+ LTC2945_MIN_VIN_H);
+static SENSOR_DEVICE_ATTR(in1_highest, S_IRUGO, ltc2945_show_value, NULL,
+ LTC2945_MAX_VIN_H);
+static SENSOR_DEVICE_ATTR(in1_reset_history, S_IWUSR, NULL,
+ ltc2945_reset_history, LTC2945_MIN_VIN_H);
+
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc2945_show_value, NULL,
+ LTC2945_ADIN_H);
+static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO | S_IWUSR, ltc2945_show_value,
+ ltc2945_set_value, LTC2945_MIN_ADIN_THRES_H);
+static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO | S_IWUSR, ltc2945_show_value,
+ ltc2945_set_value, LTC2945_MAX_ADIN_THRES_H);
+static SENSOR_DEVICE_ATTR(in2_lowest, S_IRUGO, ltc2945_show_value, NULL,
+ LTC2945_MIN_ADIN_H);
+static SENSOR_DEVICE_ATTR(in2_highest, S_IRUGO, ltc2945_show_value, NULL,
+ LTC2945_MAX_ADIN_H);
+static SENSOR_DEVICE_ATTR(in2_reset_history, S_IWUSR, NULL,
+ ltc2945_reset_history, LTC2945_MIN_ADIN_H);
+
+/* Voltage alarms */
+
+static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+ FAULT_VIN_UV);
+static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+ FAULT_VIN_OV);
+static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+ FAULT_ADIN_UV);
+static SENSOR_DEVICE_ATTR(in2_max_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+ FAULT_ADIN_OV);
+
+/* Currents (via sense resistor) */
+
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc2945_show_value, NULL,
+ LTC2945_SENSE_H);
+static SENSOR_DEVICE_ATTR(curr1_min, S_IRUGO | S_IWUSR, ltc2945_show_value,
+ ltc2945_set_value, LTC2945_MIN_SENSE_THRES_H);
+static SENSOR_DEVICE_ATTR(curr1_max, S_IRUGO | S_IWUSR, ltc2945_show_value,
+ ltc2945_set_value, LTC2945_MAX_SENSE_THRES_H);
+static SENSOR_DEVICE_ATTR(curr1_lowest, S_IRUGO, ltc2945_show_value, NULL,
+ LTC2945_MIN_SENSE_H);
+static SENSOR_DEVICE_ATTR(curr1_highest, S_IRUGO, ltc2945_show_value, NULL,
+ LTC2945_MAX_SENSE_H);
+static SENSOR_DEVICE_ATTR(curr1_reset_history, S_IWUSR, NULL,
+ ltc2945_reset_history, LTC2945_MIN_SENSE_H);
+
+/* Current alarms */
+
+static SENSOR_DEVICE_ATTR(curr1_min_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+ FAULT_SENSE_UV);
+static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+ FAULT_SENSE_OV);
+
+/* Power */
+
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ltc2945_show_value, NULL,
+ LTC2945_POWER_H);
+static SENSOR_DEVICE_ATTR(power1_min, S_IRUGO | S_IWUSR, ltc2945_show_value,
+ ltc2945_set_value, LTC2945_MIN_POWER_THRES_H);
+static SENSOR_DEVICE_ATTR(power1_max, S_IRUGO | S_IWUSR, ltc2945_show_value,
+ ltc2945_set_value, LTC2945_MAX_POWER_THRES_H);
+static SENSOR_DEVICE_ATTR(power1_input_lowest, S_IRUGO, ltc2945_show_value,
+ NULL, LTC2945_MIN_POWER_H);
+static SENSOR_DEVICE_ATTR(power1_input_highest, S_IRUGO, ltc2945_show_value,
+ NULL, LTC2945_MAX_POWER_H);
+static SENSOR_DEVICE_ATTR(power1_reset_history, S_IWUSR, NULL,
+ ltc2945_reset_history, LTC2945_MIN_POWER_H);
+
+/* Power alarms */
+
+static SENSOR_DEVICE_ATTR(power1_min_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+ FAULT_POWER_UV);
+static SENSOR_DEVICE_ATTR(power1_max_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+ FAULT_POWER_OV);
+
+static struct attribute *ltc2945_attrs[] = {
+ &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_lowest.dev_attr.attr,
+ &sensor_dev_attr_in1_highest.dev_attr.attr,
+ &sensor_dev_attr_in1_reset_history.dev_attr.attr,
+ &sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+
+ &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_lowest.dev_attr.attr,
+ &sensor_dev_attr_in2_highest.dev_attr.attr,
+ &sensor_dev_attr_in2_reset_history.dev_attr.attr,
+ &sensor_dev_attr_in2_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_max_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_curr1_input.dev_attr.attr,
+ &sensor_dev_attr_curr1_min.dev_attr.attr,
+ &sensor_dev_attr_curr1_max.dev_attr.attr,
+ &sensor_dev_attr_curr1_lowest.dev_attr.attr,
+ &sensor_dev_attr_curr1_highest.dev_attr.attr,
+ &sensor_dev_attr_curr1_reset_history.dev_attr.attr,
+ &sensor_dev_attr_curr1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_power1_input.dev_attr.attr,
+ &sensor_dev_attr_power1_min.dev_attr.attr,
+ &sensor_dev_attr_power1_max.dev_attr.attr,
+ &sensor_dev_attr_power1_input_lowest.dev_attr.attr,
+ &sensor_dev_attr_power1_input_highest.dev_attr.attr,
+ &sensor_dev_attr_power1_reset_history.dev_attr.attr,
+ &sensor_dev_attr_power1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_power1_max_alarm.dev_attr.attr,
+
+ NULL,
+};
+ATTRIBUTE_GROUPS(ltc2945);
+
+static struct regmap_config ltc2945_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = LTC2945_MIN_ADIN_THRES_L,
+};
+
+static int ltc2945_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct device *hwmon_dev;
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_i2c(client, &ltc2945_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "failed to allocate register map\n");
+ return PTR_ERR(regmap);
+ }
+
+ /* Clear faults */
+ regmap_write(regmap, LTC2945_FAULT, 0x00);
+
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ regmap,
+ ltc2945_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ltc2945_id[] = {
+ {"ltc2945", 0},
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, ltc2945_id);
+
+static struct i2c_driver ltc2945_driver = {
+ .driver = {
+ .name = "ltc2945",
+ },
+ .probe = ltc2945_probe,
+ .id_table = ltc2945_id,
+};
+
+module_i2c_driver(ltc2945_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("LTC2945 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ltc4215.c b/drivers/hwmon/ltc4215.c
index 8a142960d69e..c8a9bd9b050f 100644
--- a/drivers/hwmon/ltc4215.c
+++ b/drivers/hwmon/ltc4215.c
@@ -33,7 +33,7 @@ enum ltc4215_cmd {
};
struct ltc4215_data {
- struct device *hwmon_dev;
+ struct i2c_client *client;
struct mutex update_lock;
bool valid;
@@ -45,8 +45,8 @@ struct ltc4215_data {
static struct ltc4215_data *ltc4215_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct ltc4215_data *data = i2c_get_clientdata(client);
+ struct ltc4215_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
s32 val;
int i;
@@ -214,7 +214,7 @@ static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
* Finally, construct an array of pointers to members of the above objects,
* as required for sysfs_create_group()
*/
-static struct attribute *ltc4215_attributes[] = {
+static struct attribute *ltc4215_attrs[] = {
&sensor_dev_attr_curr1_input.dev_attr.attr,
&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
@@ -229,57 +229,33 @@ static struct attribute *ltc4215_attributes[] = {
NULL,
};
-
-static const struct attribute_group ltc4215_group = {
- .attrs = ltc4215_attributes,
-};
+ATTRIBUTE_GROUPS(ltc4215);
static int ltc4215_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = client->adapter;
+ struct device *dev = &client->dev;
struct ltc4215_data *data;
- int ret;
+ struct device *hwmon_dev;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- i2c_set_clientdata(client, data);
+ data->client = client;
mutex_init(&data->update_lock);
/* Initialize the LTC4215 chip */
i2c_smbus_write_byte_data(client, LTC4215_FAULT, 0x00);
- /* Register sysfs hooks */
- ret = sysfs_create_group(&client->dev.kobj, &ltc4215_group);
- if (ret)
- return ret;
-
- data->hwmon_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->hwmon_dev)) {
- ret = PTR_ERR(data->hwmon_dev);
- goto out_hwmon_device_register;
- }
-
- return 0;
-
-out_hwmon_device_register:
- sysfs_remove_group(&client->dev.kobj, &ltc4215_group);
- return ret;
-}
-
-static int ltc4215_remove(struct i2c_client *client)
-{
- struct ltc4215_data *data = i2c_get_clientdata(client);
-
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &ltc4215_group);
-
- return 0;
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ data,
+ ltc4215_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct i2c_device_id ltc4215_id[] = {
@@ -294,7 +270,6 @@ static struct i2c_driver ltc4215_driver = {
.name = "ltc4215",
},
.probe = ltc4215_probe,
- .remove = ltc4215_remove,
.id_table = ltc4215_id,
};
diff --git a/drivers/hwmon/ltc4222.c b/drivers/hwmon/ltc4222.c
new file mode 100644
index 000000000000..07c25653659f
--- /dev/null
+++ b/drivers/hwmon/ltc4222.c
@@ -0,0 +1,237 @@
+/*
+ * Driver for Linear Technology LTC4222 Dual Hot Swap controller
+ *
+ * Copyright (c) 2014 Guenter Roeck
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/regmap.h>
+
+/* chip registers */
+
+#define LTC4222_CONTROL1 0xd0
+#define LTC4222_ALERT1 0xd1
+#define LTC4222_STATUS1 0xd2
+#define LTC4222_FAULT1 0xd3
+#define LTC4222_CONTROL2 0xd4
+#define LTC4222_ALERT2 0xd5
+#define LTC4222_STATUS2 0xd6
+#define LTC4222_FAULT2 0xd7
+#define LTC4222_SOURCE1 0xd8
+#define LTC4222_SOURCE2 0xda
+#define LTC4222_ADIN1 0xdc
+#define LTC4222_ADIN2 0xde
+#define LTC4222_SENSE1 0xe0
+#define LTC4222_SENSE2 0xe2
+#define LTC4222_ADC_CONTROL 0xe4
+
+/*
+ * Fault register bits
+ */
+#define FAULT_OV BIT(0)
+#define FAULT_UV BIT(1)
+#define FAULT_OC BIT(2)
+#define FAULT_POWER_BAD BIT(3)
+#define FAULT_FET_BAD BIT(5)
+
+/* Return the voltage from the given register in mV or mA */
+static int ltc4222_get_value(struct device *dev, u8 reg)
+{
+ struct regmap *regmap = dev_get_drvdata(dev);
+ unsigned int val;
+ u8 buf[2];
+ int ret;
+
+ ret = regmap_bulk_read(regmap, reg, buf, 2);
+ if (ret < 0)
+ return ret;
+
+ val = ((buf[0] << 8) + buf[1]) >> 6;
+
+ switch (reg) {
+ case LTC4222_ADIN1:
+ case LTC4222_ADIN2:
+ /* 1.25 mV resolution. Convert to mV. */
+ val = DIV_ROUND_CLOSEST(val * 5, 4);
+ break;
+ case LTC4222_SOURCE1:
+ case LTC4222_SOURCE2:
+ /* 31.25 mV resolution. Convert to mV. */
+ val = DIV_ROUND_CLOSEST(val * 125, 4);
+ break;
+ case LTC4222_SENSE1:
+ case LTC4222_SENSE2:
+ /*
+ * 62.5 uV resolution. Convert to current as measured with
+ * an 1 mOhm sense resistor, in mA. If a different sense
+ * resistor is installed, calculate the actual current by
+ * dividing the reported current by the sense resistor value
+ * in mOhm.
+ */
+ val = DIV_ROUND_CLOSEST(val * 125, 2);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return val;
+}
+
+static ssize_t ltc4222_show_value(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int value;
+
+ value = ltc4222_get_value(dev, attr->index);
+ if (value < 0)
+ return value;
+ return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+static ssize_t ltc4222_show_bool(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(da);
+ struct regmap *regmap = dev_get_drvdata(dev);
+ unsigned int fault;
+ int ret;
+
+ ret = regmap_read(regmap, attr->nr, &fault);
+ if (ret < 0)
+ return ret;
+ fault &= attr->index;
+ if (fault) /* Clear reported faults in chip register */
+ regmap_update_bits(regmap, attr->nr, attr->index, 0);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
+}
+
+/* Voltages */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4222_show_value, NULL,
+ LTC4222_SOURCE1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4222_show_value, NULL,
+ LTC4222_ADIN1);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ltc4222_show_value, NULL,
+ LTC4222_SOURCE2);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ltc4222_show_value, NULL,
+ LTC4222_ADIN2);
+
+/*
+ * Voltage alarms
+ * UV/OV faults are associated with the input voltage, and power bad and fet
+ * faults are associated with the output voltage.
+ */
+static SENSOR_DEVICE_ATTR_2(in1_min_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+ LTC4222_FAULT1, FAULT_UV);
+static SENSOR_DEVICE_ATTR_2(in1_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+ LTC4222_FAULT1, FAULT_OV);
+static SENSOR_DEVICE_ATTR_2(in2_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+ LTC4222_FAULT1, FAULT_POWER_BAD | FAULT_FET_BAD);
+
+static SENSOR_DEVICE_ATTR_2(in3_min_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+ LTC4222_FAULT2, FAULT_UV);
+static SENSOR_DEVICE_ATTR_2(in3_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+ LTC4222_FAULT2, FAULT_OV);
+static SENSOR_DEVICE_ATTR_2(in4_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+ LTC4222_FAULT2, FAULT_POWER_BAD | FAULT_FET_BAD);
+
+/* Current (via sense resistor) */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4222_show_value, NULL,
+ LTC4222_SENSE1);
+static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc4222_show_value, NULL,
+ LTC4222_SENSE2);
+
+/* Overcurrent alarm */
+static SENSOR_DEVICE_ATTR_2(curr1_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+ LTC4222_FAULT1, FAULT_OC);
+static SENSOR_DEVICE_ATTR_2(curr2_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+ LTC4222_FAULT2, FAULT_OC);
+
+static struct attribute *ltc4222_attrs[] = {
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_curr1_input.dev_attr.attr,
+ &sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_curr2_input.dev_attr.attr,
+ &sensor_dev_attr_curr2_max_alarm.dev_attr.attr,
+
+ NULL,
+};
+ATTRIBUTE_GROUPS(ltc4222);
+
+static struct regmap_config ltc4222_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = LTC4222_ADC_CONTROL,
+};
+
+static int ltc4222_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct device *hwmon_dev;
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_i2c(client, &ltc4222_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "failed to allocate register map\n");
+ return PTR_ERR(regmap);
+ }
+
+ /* Clear faults */
+ regmap_write(regmap, LTC4222_FAULT1, 0x00);
+ regmap_write(regmap, LTC4222_FAULT2, 0x00);
+
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ regmap,
+ ltc4222_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ltc4222_id[] = {
+ {"ltc4222", 0},
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, ltc4222_id);
+
+static struct i2c_driver ltc4222_driver = {
+ .driver = {
+ .name = "ltc4222",
+ },
+ .probe = ltc4222_probe,
+ .id_table = ltc4222_id,
+};
+
+module_i2c_driver(ltc4222_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("LTC4222 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ltc4245.c b/drivers/hwmon/ltc4245.c
index d4172933ce4f..681b5b7b3c3b 100644
--- a/drivers/hwmon/ltc4245.c
+++ b/drivers/hwmon/ltc4245.c
@@ -95,7 +95,6 @@ static void ltc4245_update_gpios(struct device *dev)
* readings as stale by setting them to -EAGAIN
*/
if (time_after(jiffies, data->last_updated + 5 * HZ)) {
- dev_dbg(&client->dev, "Marking GPIOs invalid\n");
for (i = 0; i < ARRAY_SIZE(data->gpios); i++)
data->gpios[i] = -EAGAIN;
}
@@ -141,8 +140,6 @@ static struct ltc4245_data *ltc4245_update_device(struct device *dev)
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
- dev_dbg(&client->dev, "Starting ltc4245 update\n");
-
/* Read control registers -- 0x00 to 0x07 */
for (i = 0; i < ARRAY_SIZE(data->cregs); i++) {
val = i2c_smbus_read_byte_data(client, i);
@@ -470,19 +467,15 @@ static void ltc4245_sysfs_add_groups(struct ltc4245_data *data)
static bool ltc4245_use_extra_gpios(struct i2c_client *client)
{
struct ltc4245_platform_data *pdata = dev_get_platdata(&client->dev);
-#ifdef CONFIG_OF
struct device_node *np = client->dev.of_node;
-#endif
/* prefer platform data */
if (pdata)
return pdata->use_extra_gpios;
-#ifdef CONFIG_OF
/* fallback on OF */
if (of_find_property(np, "ltc4245,use-extra-gpios", NULL))
return true;
-#endif
return false;
}
@@ -512,24 +505,10 @@ static int ltc4245_probe(struct i2c_client *client,
/* Add sysfs hooks */
ltc4245_sysfs_add_groups(data);
- hwmon_dev = hwmon_device_register_with_groups(&client->dev,
- client->name, data,
- data->groups);
- if (IS_ERR(hwmon_dev))
- return PTR_ERR(hwmon_dev);
-
- i2c_set_clientdata(client, hwmon_dev);
-
- return 0;
-}
-
-static int ltc4245_remove(struct i2c_client *client)
-{
- struct device *hwmon_dev = i2c_get_clientdata(client);
-
- hwmon_device_unregister(hwmon_dev);
-
- return 0;
+ hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
+ client->name, data,
+ data->groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct i2c_device_id ltc4245_id[] = {
@@ -544,7 +523,6 @@ static struct i2c_driver ltc4245_driver = {
.name = "ltc4245",
},
.probe = ltc4245_probe,
- .remove = ltc4245_remove,
.id_table = ltc4245_id,
};
diff --git a/drivers/hwmon/ltc4260.c b/drivers/hwmon/ltc4260.c
new file mode 100644
index 000000000000..453a250d9df5
--- /dev/null
+++ b/drivers/hwmon/ltc4260.c
@@ -0,0 +1,200 @@
+/*
+ * Driver for Linear Technology LTC4260 I2C Positive Voltage Hot Swap Controller
+ *
+ * Copyright (c) 2014 Guenter Roeck
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/regmap.h>
+
+/* chip registers */
+#define LTC4260_CONTROL 0x00
+#define LTC4260_ALERT 0x01
+#define LTC4260_STATUS 0x02
+#define LTC4260_FAULT 0x03
+#define LTC4260_SENSE 0x04
+#define LTC4260_SOURCE 0x05
+#define LTC4260_ADIN 0x06
+
+/*
+ * Fault register bits
+ */
+#define FAULT_OV (1 << 0)
+#define FAULT_UV (1 << 1)
+#define FAULT_OC (1 << 2)
+#define FAULT_POWER_BAD (1 << 3)
+#define FAULT_FET_SHORT (1 << 5)
+
+/* Return the voltage from the given register in mV or mA */
+static int ltc4260_get_value(struct device *dev, u8 reg)
+{
+ struct regmap *regmap = dev_get_drvdata(dev);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(regmap, reg, &val);
+ if (ret < 0)
+ return ret;
+
+ switch (reg) {
+ case LTC4260_ADIN:
+ /* 10 mV resolution. Convert to mV. */
+ val = val * 10;
+ break;
+ case LTC4260_SOURCE:
+ /* 400 mV resolution. Convert to mV. */
+ val = val * 400;
+ break;
+ case LTC4260_SENSE:
+ /*
+ * 300 uV resolution. Convert to current as measured with
+ * an 1 mOhm sense resistor, in mA. If a different sense
+ * resistor is installed, calculate the actual current by
+ * dividing the reported current by the sense resistor value
+ * in mOhm.
+ */
+ val = val * 300;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return val;
+}
+
+static ssize_t ltc4260_show_value(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int value;
+
+ value = ltc4260_get_value(dev, attr->index);
+ if (value < 0)
+ return value;
+ return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+static ssize_t ltc4260_show_bool(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct regmap *regmap = dev_get_drvdata(dev);
+ unsigned int fault;
+ int ret;
+
+ ret = regmap_read(regmap, LTC4260_FAULT, &fault);
+ if (ret < 0)
+ return ret;
+
+ fault &= attr->index;
+ if (fault) /* Clear reported faults in chip register */
+ regmap_update_bits(regmap, LTC4260_FAULT, attr->index, 0);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
+}
+
+/* Voltages */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4260_show_value, NULL,
+ LTC4260_SOURCE);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4260_show_value, NULL,
+ LTC4260_ADIN);
+
+/*
+ * Voltage alarms
+ * UV/OV faults are associated with the input voltage, and the POWER BAD and
+ * FET SHORT faults are associated with the output voltage.
+ */
+static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc4260_show_bool, NULL,
+ FAULT_UV);
+static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc4260_show_bool, NULL,
+ FAULT_OV);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, ltc4260_show_bool, NULL,
+ FAULT_POWER_BAD | FAULT_FET_SHORT);
+
+/* Current (via sense resistor) */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4260_show_value, NULL,
+ LTC4260_SENSE);
+
+/* Overcurrent alarm */
+static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc4260_show_bool, NULL,
+ FAULT_OC);
+
+static struct attribute *ltc4260_attrs[] = {
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_curr1_input.dev_attr.attr,
+ &sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+
+ NULL,
+};
+ATTRIBUTE_GROUPS(ltc4260);
+
+static struct regmap_config ltc4260_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = LTC4260_ADIN,
+};
+
+static int ltc4260_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct device *hwmon_dev;
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_i2c(client, &ltc4260_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "failed to allocate register map\n");
+ return PTR_ERR(regmap);
+ }
+
+ /* Clear faults */
+ regmap_write(regmap, LTC4260_FAULT, 0x00);
+
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ regmap,
+ ltc4260_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ltc4260_id[] = {
+ {"ltc4260", 0},
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, ltc4260_id);
+
+static struct i2c_driver ltc4260_driver = {
+ .driver = {
+ .name = "ltc4260",
+ },
+ .probe = ltc4260_probe,
+ .id_table = ltc4260_id,
+};
+
+module_i2c_driver(ltc4260_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("LTC4260 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c
index a7626358c95d..e3ed0a5b6d94 100644
--- a/drivers/hwmon/max1668.c
+++ b/drivers/hwmon/max1668.c
@@ -66,7 +66,8 @@ MODULE_PARM_DESC(read_only, "Don't set any values, read only mode");
enum chips { max1668, max1805, max1989 };
struct max1668_data {
- struct device *hwmon_dev;
+ struct i2c_client *client;
+ const struct attribute_group *groups[3];
enum chips type;
struct mutex update_lock;
@@ -82,8 +83,8 @@ struct max1668_data {
static struct max1668_data *max1668_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max1668_data *data = i2c_get_clientdata(client);
+ struct max1668_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
struct max1668_data *ret = data;
s32 val;
int i;
@@ -205,8 +206,8 @@ static ssize_t set_temp_max(struct device *dev,
const char *buf, size_t count)
{
int index = to_sensor_dev_attr(devattr)->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct max1668_data *data = i2c_get_clientdata(client);
+ struct max1668_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
long temp;
int ret;
@@ -216,10 +217,11 @@ static ssize_t set_temp_max(struct device *dev,
mutex_lock(&data->update_lock);
data->temp_max[index] = clamp_val(temp/1000, -128, 127);
- if (i2c_smbus_write_byte_data(client,
+ ret = i2c_smbus_write_byte_data(client,
MAX1668_REG_LIMH_WR(index),
- data->temp_max[index]))
- count = -EIO;
+ data->temp_max[index]);
+ if (ret < 0)
+ count = ret;
mutex_unlock(&data->update_lock);
return count;
@@ -230,8 +232,8 @@ static ssize_t set_temp_min(struct device *dev,
const char *buf, size_t count)
{
int index = to_sensor_dev_attr(devattr)->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct max1668_data *data = i2c_get_clientdata(client);
+ struct max1668_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
long temp;
int ret;
@@ -241,10 +243,11 @@ static ssize_t set_temp_min(struct device *dev,
mutex_lock(&data->update_lock);
data->temp_min[index] = clamp_val(temp/1000, -128, 127);
- if (i2c_smbus_write_byte_data(client,
+ ret = i2c_smbus_write_byte_data(client,
MAX1668_REG_LIML_WR(index),
- data->temp_max[index]))
- count = -EIO;
+ data->temp_min[index]);
+ if (ret < 0)
+ count = ret;
mutex_unlock(&data->update_lock);
return count;
@@ -405,60 +408,29 @@ static int max1668_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = client->adapter;
+ struct device *dev = &client->dev;
+ struct device *hwmon_dev;
struct max1668_data *data;
- int err;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- data = devm_kzalloc(&client->dev, sizeof(struct max1668_data),
- GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(struct max1668_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- i2c_set_clientdata(client, data);
+ data->client = client;
data->type = id->driver_data;
mutex_init(&data->update_lock);
- /* Register sysfs hooks */
- err = sysfs_create_group(&client->dev.kobj, &max1668_group_common);
- if (err)
- return err;
-
- if (data->type == max1668 || data->type == max1989) {
- err = sysfs_create_group(&client->dev.kobj,
- &max1668_group_unique);
- if (err)
- goto error_sysrem0;
- }
-
- data->hwmon_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->hwmon_dev)) {
- err = PTR_ERR(data->hwmon_dev);
- goto error_sysrem1;
- }
-
- return 0;
-
-error_sysrem1:
+ /* sysfs hooks */
+ data->groups[0] = &max1668_group_common;
if (data->type == max1668 || data->type == max1989)
- sysfs_remove_group(&client->dev.kobj, &max1668_group_unique);
-error_sysrem0:
- sysfs_remove_group(&client->dev.kobj, &max1668_group_common);
- return err;
-}
-
-static int max1668_remove(struct i2c_client *client)
-{
- struct max1668_data *data = i2c_get_clientdata(client);
+ data->groups[1] = &max1668_group_unique;
- hwmon_device_unregister(data->hwmon_dev);
- if (data->type == max1668 || data->type == max1989)
- sysfs_remove_group(&client->dev.kobj, &max1668_group_unique);
-
- sysfs_remove_group(&client->dev.kobj, &max1668_group_common);
-
- return 0;
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ data, data->groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct i2c_device_id max1668_id[] = {
@@ -476,7 +448,6 @@ static struct i2c_driver max1668_driver = {
.name = "max1668",
},
.probe = max1668_probe,
- .remove = max1668_remove,
.id_table = max1668_id,
.detect = max1668_detect,
.address_list = max1668_addr_list,
diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c
index 066e587a18a5..70650de2cbd1 100644
--- a/drivers/hwmon/max6639.c
+++ b/drivers/hwmon/max6639.c
@@ -80,7 +80,7 @@ static const int rpm_ranges[] = { 2000, 4000, 8000, 16000 };
* Client data (each client gets its own)
*/
struct max6639_data {
- struct device *hwmon_dev;
+ struct i2c_client *client;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -104,8 +104,8 @@ struct max6639_data {
static struct max6639_data *max6639_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6639_data *data = i2c_get_clientdata(client);
+ struct max6639_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
struct max6639_data *ret = data;
int i;
int status_reg;
@@ -191,9 +191,8 @@ static ssize_t show_temp_fault(struct device *dev,
static ssize_t show_temp_max(struct device *dev,
struct device_attribute *dev_attr, char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6639_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+ struct max6639_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", (data->temp_therm[attr->index] * 1000));
}
@@ -202,9 +201,9 @@ static ssize_t set_temp_max(struct device *dev,
struct device_attribute *dev_attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6639_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+ struct max6639_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
unsigned long val;
int res;
@@ -224,9 +223,8 @@ static ssize_t set_temp_max(struct device *dev,
static ssize_t show_temp_crit(struct device *dev,
struct device_attribute *dev_attr, char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6639_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+ struct max6639_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", (data->temp_alert[attr->index] * 1000));
}
@@ -235,9 +233,9 @@ static ssize_t set_temp_crit(struct device *dev,
struct device_attribute *dev_attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6639_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+ struct max6639_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
unsigned long val;
int res;
@@ -258,9 +256,8 @@ static ssize_t show_temp_emergency(struct device *dev,
struct device_attribute *dev_attr,
char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6639_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+ struct max6639_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", (data->temp_ot[attr->index] * 1000));
}
@@ -269,9 +266,9 @@ static ssize_t set_temp_emergency(struct device *dev,
struct device_attribute *dev_attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6639_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+ struct max6639_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
unsigned long val;
int res;
@@ -291,9 +288,8 @@ static ssize_t set_temp_emergency(struct device *dev,
static ssize_t show_pwm(struct device *dev,
struct device_attribute *dev_attr, char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6639_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+ struct max6639_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", data->pwm[attr->index] * 255 / 120);
}
@@ -302,9 +298,9 @@ static ssize_t set_pwm(struct device *dev,
struct device_attribute *dev_attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6639_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+ struct max6639_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
unsigned long val;
int res;
@@ -378,7 +374,7 @@ static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO, show_alarm, NULL, 5);
static SENSOR_DEVICE_ATTR(temp2_emergency_alarm, S_IRUGO, show_alarm, NULL, 4);
-static struct attribute *max6639_attributes[] = {
+static struct attribute *max6639_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
&sensor_dev_attr_temp1_fault.dev_attr.attr,
@@ -403,10 +399,7 @@ static struct attribute *max6639_attributes[] = {
&sensor_dev_attr_temp2_emergency_alarm.dev_attr.attr,
NULL
};
-
-static const struct attribute_group max6639_group = {
- .attrs = max6639_attributes,
-};
+ATTRIBUTE_GROUPS(max6639);
/*
* returns respective index in rpm_ranges table
@@ -424,9 +417,9 @@ static int rpm_range_to_reg(int range)
return 1; /* default: 4000 RPM */
}
-static int max6639_init_client(struct i2c_client *client)
+static int max6639_init_client(struct i2c_client *client,
+ struct max6639_data *data)
{
- struct max6639_data *data = i2c_get_clientdata(client);
struct max6639_platform_data *max6639_info =
dev_get_platdata(&client->dev);
int i;
@@ -545,50 +538,27 @@ static int max6639_detect(struct i2c_client *client,
static int max6639_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct device *dev = &client->dev;
struct max6639_data *data;
+ struct device *hwmon_dev;
int err;
- data = devm_kzalloc(&client->dev, sizeof(struct max6639_data),
- GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(struct max6639_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- i2c_set_clientdata(client, data);
+ data->client = client;
mutex_init(&data->update_lock);
/* Initialize the max6639 chip */
- err = max6639_init_client(client);
+ err = max6639_init_client(client, data);
if (err < 0)
return err;
- /* Register sysfs hooks */
- err = sysfs_create_group(&client->dev.kobj, &max6639_group);
- if (err)
- return err;
-
- data->hwmon_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->hwmon_dev)) {
- err = PTR_ERR(data->hwmon_dev);
- goto error_remove;
- }
-
- dev_info(&client->dev, "temperature sensor and fan control found\n");
-
- return 0;
-
-error_remove:
- sysfs_remove_group(&client->dev.kobj, &max6639_group);
- return err;
-}
-
-static int max6639_remove(struct i2c_client *client)
-{
- struct max6639_data *data = i2c_get_clientdata(client);
-
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &max6639_group);
-
- return 0;
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ data,
+ max6639_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}
#ifdef CONFIG_PM_SLEEP
@@ -622,9 +592,7 @@ static const struct i2c_device_id max6639_id[] = {
MODULE_DEVICE_TABLE(i2c, max6639_id);
-static const struct dev_pm_ops max6639_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(max6639_suspend, max6639_resume)
-};
+static SIMPLE_DEV_PM_OPS(max6639_pm_ops, max6639_suspend, max6639_resume);
static struct i2c_driver max6639_driver = {
.class = I2C_CLASS_HWMON,
@@ -633,7 +601,6 @@ static struct i2c_driver max6639_driver = {
.pm = &max6639_pm_ops,
},
.probe = max6639_probe,
- .remove = max6639_remove,
.id_table = max6639_id,
.detect = max6639_detect,
.address_list = normal_i2c,
diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c
index 0cafc390db4d..162a520f4bd6 100644
--- a/drivers/hwmon/max6650.c
+++ b/drivers/hwmon/max6650.c
@@ -105,38 +105,13 @@ module_param(clock, int, S_IRUGO);
#define DIV_FROM_REG(reg) (1 << (reg & 7))
-static int max6650_probe(struct i2c_client *client,
- const struct i2c_device_id *id);
-static int max6650_init_client(struct i2c_client *client);
-static int max6650_remove(struct i2c_client *client);
-static struct max6650_data *max6650_update_device(struct device *dev);
-
-/*
- * Driver data (common to all clients)
- */
-
-static const struct i2c_device_id max6650_id[] = {
- { "max6650", 1 },
- { "max6651", 4 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, max6650_id);
-
-static struct i2c_driver max6650_driver = {
- .driver = {
- .name = "max6650",
- },
- .probe = max6650_probe,
- .remove = max6650_remove,
- .id_table = max6650_id,
-};
-
/*
* Client data (each client gets its own)
*/
struct max6650_data {
- struct device *hwmon_dev;
+ struct i2c_client *client;
+ const struct attribute_group *groups[3];
struct mutex update_lock;
int nr_fans;
char valid; /* zero until following fields are valid */
@@ -151,6 +126,51 @@ struct max6650_data {
u8 alarm;
};
+static const u8 tach_reg[] = {
+ MAX6650_REG_TACH0,
+ MAX6650_REG_TACH1,
+ MAX6650_REG_TACH2,
+ MAX6650_REG_TACH3,
+};
+
+static struct max6650_data *max6650_update_device(struct device *dev)
+{
+ struct max6650_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ int i;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+ data->speed = i2c_smbus_read_byte_data(client,
+ MAX6650_REG_SPEED);
+ data->config = i2c_smbus_read_byte_data(client,
+ MAX6650_REG_CONFIG);
+ for (i = 0; i < data->nr_fans; i++) {
+ data->tach[i] = i2c_smbus_read_byte_data(client,
+ tach_reg[i]);
+ }
+ data->count = i2c_smbus_read_byte_data(client,
+ MAX6650_REG_COUNT);
+ data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
+
+ /*
+ * Alarms are cleared on read in case the condition that
+ * caused the alarm is removed. Keep the value latched here
+ * for providing the register through different alarm files.
+ */
+ data->alarm |= i2c_smbus_read_byte_data(client,
+ MAX6650_REG_ALARM);
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
static ssize_t get_fan(struct device *dev, struct device_attribute *devattr,
char *buf)
{
@@ -235,8 +255,8 @@ static ssize_t get_target(struct device *dev, struct device_attribute *devattr,
static ssize_t set_target(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6650_data *data = i2c_get_clientdata(client);
+ struct max6650_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
int kscale, ktach;
unsigned long rpm;
int err;
@@ -304,8 +324,8 @@ static ssize_t get_pwm(struct device *dev, struct device_attribute *devattr,
static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6650_data *data = i2c_get_clientdata(client);
+ struct max6650_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
unsigned long pwm;
int err;
@@ -350,8 +370,8 @@ static ssize_t get_enable(struct device *dev, struct device_attribute *devattr,
static ssize_t set_enable(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6650_data *data = i2c_get_clientdata(client);
+ struct max6650_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
int max6650_modes[3] = {0, 3, 2};
unsigned long mode;
int err;
@@ -400,8 +420,8 @@ static ssize_t get_div(struct device *dev, struct device_attribute *devattr,
static ssize_t set_div(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6650_data *data = i2c_get_clientdata(client);
+ struct max6650_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
unsigned long div;
int err;
@@ -446,7 +466,7 @@ static ssize_t get_alarm(struct device *dev, struct device_attribute *devattr,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct max6650_data *data = max6650_update_device(dev);
- struct i2c_client *client = to_i2c_client(dev);
+ struct i2c_client *client = data->client;
int alarm = 0;
if (data->alarm & attr->index) {
@@ -484,7 +504,8 @@ static umode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
- struct i2c_client *client = to_i2c_client(dev);
+ struct max6650_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
u8 alarm_en = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN);
struct device_attribute *devattr;
@@ -519,7 +540,7 @@ static struct attribute *max6650_attrs[] = {
NULL
};
-static struct attribute_group max6650_attr_grp = {
+static const struct attribute_group max6650_group = {
.attrs = max6650_attrs,
.is_visible = max6650_attrs_visible,
};
@@ -531,7 +552,7 @@ static struct attribute *max6651_attrs[] = {
NULL
};
-static const struct attribute_group max6651_attr_grp = {
+static const struct attribute_group max6651_group = {
.attrs = max6651_attrs,
};
@@ -539,74 +560,17 @@ static const struct attribute_group max6651_attr_grp = {
* Real code
*/
-static int max6650_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct max6650_data *data;
- int err;
-
- data = devm_kzalloc(&client->dev, sizeof(struct max6650_data),
- GFP_KERNEL);
- if (!data) {
- dev_err(&client->dev, "out of memory.\n");
- return -ENOMEM;
- }
-
- i2c_set_clientdata(client, data);
- mutex_init(&data->update_lock);
- data->nr_fans = id->driver_data;
-
- /*
- * Initialize the max6650 chip
- */
- err = max6650_init_client(client);
- if (err)
- return err;
-
- err = sysfs_create_group(&client->dev.kobj, &max6650_attr_grp);
- if (err)
- return err;
- /* 3 additional fan inputs for the MAX6651 */
- if (data->nr_fans == 4) {
- err = sysfs_create_group(&client->dev.kobj, &max6651_attr_grp);
- if (err)
- goto err_remove;
- }
-
- data->hwmon_dev = hwmon_device_register(&client->dev);
- if (!IS_ERR(data->hwmon_dev))
- return 0;
-
- err = PTR_ERR(data->hwmon_dev);
- dev_err(&client->dev, "error registering hwmon device.\n");
- if (data->nr_fans == 4)
- sysfs_remove_group(&client->dev.kobj, &max6651_attr_grp);
-err_remove:
- sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
- return err;
-}
-
-static int max6650_remove(struct i2c_client *client)
+static int max6650_init_client(struct max6650_data *data,
+ struct i2c_client *client)
{
- struct max6650_data *data = i2c_get_clientdata(client);
-
- hwmon_device_unregister(data->hwmon_dev);
- if (data->nr_fans == 4)
- sysfs_remove_group(&client->dev.kobj, &max6651_attr_grp);
- sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
- return 0;
-}
-
-static int max6650_init_client(struct i2c_client *client)
-{
- struct max6650_data *data = i2c_get_clientdata(client);
+ struct device *dev = &client->dev;
int config;
int err = -EIO;
config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);
if (config < 0) {
- dev_err(&client->dev, "Error reading config, aborting.\n");
+ dev_err(dev, "Error reading config, aborting.\n");
return err;
}
@@ -620,11 +584,11 @@ static int max6650_init_client(struct i2c_client *client)
config |= MAX6650_CFG_V12;
break;
default:
- dev_err(&client->dev, "illegal value for fan_voltage (%d)\n",
+ dev_err(dev, "illegal value for fan_voltage (%d)\n",
fan_voltage);
}
- dev_info(&client->dev, "Fan voltage is set to %dV.\n",
+ dev_info(dev, "Fan voltage is set to %dV.\n",
(config & MAX6650_CFG_V12) ? 12 : 5);
switch (prescaler) {
@@ -650,11 +614,10 @@ static int max6650_init_client(struct i2c_client *client)
| MAX6650_CFG_PRESCALER_16;
break;
default:
- dev_err(&client->dev, "illegal value for prescaler (%d)\n",
- prescaler);
+ dev_err(dev, "illegal value for prescaler (%d)\n", prescaler);
}
- dev_info(&client->dev, "Prescaler is set to %d.\n",
+ dev_info(dev, "Prescaler is set to %d.\n",
1 << (config & MAX6650_CFG_PRESCALER_MASK));
/*
@@ -664,17 +627,17 @@ static int max6650_init_client(struct i2c_client *client)
*/
if ((config & MAX6650_CFG_MODE_MASK) == MAX6650_CFG_MODE_OFF) {
- dev_dbg(&client->dev, "Change mode to open loop, full off.\n");
+ dev_dbg(dev, "Change mode to open loop, full off.\n");
config = (config & ~MAX6650_CFG_MODE_MASK)
| MAX6650_CFG_MODE_OPEN_LOOP;
if (i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, 255)) {
- dev_err(&client->dev, "DAC write error, aborting.\n");
+ dev_err(dev, "DAC write error, aborting.\n");
return err;
}
}
if (i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, config)) {
- dev_err(&client->dev, "Config write error, aborting.\n");
+ dev_err(dev, "Config write error, aborting.\n");
return err;
}
@@ -684,51 +647,55 @@ static int max6650_init_client(struct i2c_client *client)
return 0;
}
-static const u8 tach_reg[] = {
- MAX6650_REG_TACH0,
- MAX6650_REG_TACH1,
- MAX6650_REG_TACH2,
- MAX6650_REG_TACH3,
-};
-
-static struct max6650_data *max6650_update_device(struct device *dev)
+static int max6650_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- int i;
- struct i2c_client *client = to_i2c_client(dev);
- struct max6650_data *data = i2c_get_clientdata(client);
-
- mutex_lock(&data->update_lock);
+ struct device *dev = &client->dev;
+ struct max6650_data *data;
+ struct device *hwmon_dev;
+ int err;
- if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
- data->speed = i2c_smbus_read_byte_data(client,
- MAX6650_REG_SPEED);
- data->config = i2c_smbus_read_byte_data(client,
- MAX6650_REG_CONFIG);
- for (i = 0; i < data->nr_fans; i++) {
- data->tach[i] = i2c_smbus_read_byte_data(client,
- tach_reg[i]);
- }
- data->count = i2c_smbus_read_byte_data(client,
- MAX6650_REG_COUNT);
- data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
+ data = devm_kzalloc(dev, sizeof(struct max6650_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
- /*
- * Alarms are cleared on read in case the condition that
- * caused the alarm is removed. Keep the value latched here
- * for providing the register through different alarm files.
- */
- data->alarm |= i2c_smbus_read_byte_data(client,
- MAX6650_REG_ALARM);
+ data->client = client;
+ mutex_init(&data->update_lock);
+ data->nr_fans = id->driver_data;
- data->last_updated = jiffies;
- data->valid = 1;
- }
+ /*
+ * Initialize the max6650 chip
+ */
+ err = max6650_init_client(data, client);
+ if (err)
+ return err;
- mutex_unlock(&data->update_lock);
+ data->groups[0] = &max6650_group;
+ /* 3 additional fan inputs for the MAX6651 */
+ if (data->nr_fans == 4)
+ data->groups[1] = &max6651_group;
- return data;
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev,
+ client->name, data,
+ data->groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}
+static const struct i2c_device_id max6650_id[] = {
+ { "max6650", 1 },
+ { "max6651", 4 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max6650_id);
+
+static struct i2c_driver max6650_driver = {
+ .driver = {
+ .name = "max6650",
+ },
+ .probe = max6650_probe,
+ .id_table = max6650_id,
+};
+
module_i2c_driver(max6650_driver);
MODULE_AUTHOR("Hans J. Koch");
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
index 8c23203915af..8a17f01e8672 100644
--- a/drivers/hwmon/ntc_thermistor.c
+++ b/drivers/hwmon/ntc_thermistor.c
@@ -145,7 +145,7 @@ struct ntc_data {
static int ntc_adc_iio_read(struct ntc_thermistor_platform_data *pdata)
{
struct iio_channel *channel = pdata->chan;
- unsigned int result;
+ s64 result;
int val, ret;
ret = iio_read_channel_raw(channel, &val);
@@ -155,10 +155,10 @@ static int ntc_adc_iio_read(struct ntc_thermistor_platform_data *pdata)
}
/* unit: mV */
- result = pdata->pullup_uv * val;
+ result = pdata->pullup_uv * (s64) val;
result >>= 12;
- return result;
+ return (int)result;
}
static const struct of_device_id ntc_match[] = {
diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c
index de3c152a1d9a..e24ed521051a 100644
--- a/drivers/hwmon/pmbus/ltc2978.c
+++ b/drivers/hwmon/pmbus/ltc2978.c
@@ -1,9 +1,9 @@
/*
* Hardware monitoring driver for LTC2974, LTC2977, LTC2978, LTC3880,
- * and LTC3883
+ * LTC3883, and LTM4676
*
* Copyright (c) 2011 Ericsson AB.
- * Copyright (c) 2013 Guenter Roeck
+ * Copyright (c) 2013, 2014 Guenter Roeck
*
* 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
@@ -14,10 +14,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
@@ -28,7 +24,7 @@
#include <linux/i2c.h>
#include "pmbus.h"
-enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 };
+enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883, ltm4676 };
/* Common for all chips */
#define LTC2978_MFR_VOUT_PEAK 0xdd
@@ -45,7 +41,7 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 };
#define LTC2974_MFR_IOUT_PEAK 0xd7
#define LTC2974_MFR_IOUT_MIN 0xd8
-/* LTC3880 and LTC3883 */
+/* LTC3880, LTC3883, and LTM4676 */
#define LTC3880_MFR_IOUT_PEAK 0xd7
#define LTC3880_MFR_CLEAR_PEAKS 0xe3
#define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4
@@ -53,7 +49,8 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 };
/* LTC3883 only */
#define LTC3883_MFR_IIN_PEAK 0xe1
-#define LTC2974_ID 0x0212
+#define LTC2974_ID_REV1 0x0212
+#define LTC2974_ID_REV2 0x0213
#define LTC2977_ID 0x0130
#define LTC2978_ID_REV1 0x0121
#define LTC2978_ID_REV2 0x0122
@@ -62,6 +59,8 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 };
#define LTC3880_ID_MASK 0xff00
#define LTC3883_ID 0x4300
#define LTC3883_ID_MASK 0xff00
+#define LTM4676_ID 0x4480 /* datasheet claims 0x440X */
+#define LTM4676_ID_MASK 0xfff0
#define LTC2974_NUM_PAGES 4
#define LTC2978_NUM_PAGES 8
@@ -370,6 +369,7 @@ static const struct i2c_device_id ltc2978_id[] = {
{"ltc2978", ltc2978},
{"ltc3880", ltc3880},
{"ltc3883", ltc3883},
+ {"ltm4676", ltm4676},
{}
};
MODULE_DEVICE_TABLE(i2c, ltc2978_id);
@@ -394,7 +394,7 @@ static int ltc2978_probe(struct i2c_client *client,
if (chip_id < 0)
return chip_id;
- if (chip_id == LTC2974_ID) {
+ if (chip_id == LTC2974_ID_REV1 || chip_id == LTC2974_ID_REV2) {
data->id = ltc2974;
} else if (chip_id == LTC2977_ID) {
data->id = ltc2977;
@@ -405,6 +405,8 @@ static int ltc2978_probe(struct i2c_client *client,
data->id = ltc3880;
} else if ((chip_id & LTC3883_ID_MASK) == LTC3883_ID) {
data->id = ltc3883;
+ } else if ((chip_id & LTM4676_ID_MASK) == LTM4676_ID) {
+ data->id = ltm4676;
} else {
dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
return -ENODEV;
@@ -458,6 +460,7 @@ static int ltc2978_probe(struct i2c_client *client,
}
break;
case ltc3880:
+ case ltm4676:
info->read_word_data = ltc3880_read_word_data;
info->pages = LTC3880_NUM_PAGES;
info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
@@ -500,5 +503,5 @@ static struct i2c_driver ltc2978_driver = {
module_i2c_driver(ltc2978_driver);
MODULE_AUTHOR("Guenter Roeck");
-MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, and LTC3883");
+MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, LTC3883, and LTM4676");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/smm665.c b/drivers/hwmon/smm665.c
index d9e1b7de78da..4ef5802df6d8 100644
--- a/drivers/hwmon/smm665.c
+++ b/drivers/hwmon/smm665.c
@@ -222,7 +222,7 @@ static int smm665_read_adc(struct smm665_data *data, int adc)
rv = i2c_smbus_read_word_swapped(client, 0);
if (rv < 0) {
dev_dbg(&client->dev, "Failed to read ADC value: error %d", rv);
- return -1;
+ return rv;
}
/*
* Validate/verify readback adc channel (in bit 11..14).
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index f5ed03164d86..de17c5593d97 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -387,7 +387,7 @@ config I2C_CBUS_GPIO
config I2C_CPM
tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)"
- depends on (CPM1 || CPM2) && OF_I2C
+ depends on CPM1 || CPM2
help
This supports the use of the I2C interface on Freescale
processors with CPM1 or CPM2.
diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
index be7f0a20d634..f3b89a4698b6 100644
--- a/drivers/i2c/busses/i2c-cpm.c
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -39,7 +39,9 @@
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
+#include <linux/of_address.h>
#include <linux/of_device.h>
+#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <sysdev/fsl_soc.h>
#include <asm/cpm.h>
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index b8c5187b9ee0..d52d84937ad3 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -97,7 +97,6 @@ enum {
enum {
MV64XXX_I2C_ACTION_INVALID,
MV64XXX_I2C_ACTION_CONTINUE,
- MV64XXX_I2C_ACTION_OFFLOAD_SEND_START,
MV64XXX_I2C_ACTION_SEND_START,
MV64XXX_I2C_ACTION_SEND_RESTART,
MV64XXX_I2C_ACTION_OFFLOAD_RESTART,
@@ -204,6 +203,9 @@ static int mv64xxx_i2c_offload_msg(struct mv64xxx_i2c_data *drv_data)
unsigned long ctrl_reg;
struct i2c_msg *msg = drv_data->msgs;
+ if (!drv_data->offload_enabled)
+ return -EOPNOTSUPP;
+
drv_data->msg = msg;
drv_data->byte_posn = 0;
drv_data->bytes_left = msg->len;
@@ -433,8 +435,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
drv_data->msgs++;
drv_data->num_msgs--;
- if (!(drv_data->offload_enabled &&
- mv64xxx_i2c_offload_msg(drv_data))) {
+ if (mv64xxx_i2c_offload_msg(drv_data) < 0) {
drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START;
writel(drv_data->cntl_bits,
drv_data->reg_base + drv_data->reg_offsets.control);
@@ -458,15 +459,14 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
drv_data->reg_base + drv_data->reg_offsets.control);
break;
- case MV64XXX_I2C_ACTION_OFFLOAD_SEND_START:
- if (!mv64xxx_i2c_offload_msg(drv_data))
- break;
- else
- drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
- /* FALLTHRU */
case MV64XXX_I2C_ACTION_SEND_START:
- writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
- drv_data->reg_base + drv_data->reg_offsets.control);
+ /* Can we offload this msg ? */
+ if (mv64xxx_i2c_offload_msg(drv_data) < 0) {
+ /* No, switch to standard path */
+ mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs);
+ writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
+ drv_data->reg_base + drv_data->reg_offsets.control);
+ }
break;
case MV64XXX_I2C_ACTION_SEND_ADDR_1:
@@ -625,15 +625,10 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
unsigned long flags;
spin_lock_irqsave(&drv_data->lock, flags);
- if (drv_data->offload_enabled) {
- drv_data->action = MV64XXX_I2C_ACTION_OFFLOAD_SEND_START;
- drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
- } else {
- mv64xxx_i2c_prepare_for_io(drv_data, msg);
- drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
- drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
- }
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
+ drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
+
drv_data->send_stop = is_last;
drv_data->block = 1;
mv64xxx_i2c_do_action(drv_data);
diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c
index 3bec9220df04..a7e68c81f89d 100644
--- a/drivers/iio/accel/bma180.c
+++ b/drivers/iio/accel/bma180.c
@@ -447,14 +447,14 @@ static const struct iio_chan_spec_ext_info bma180_ext_info[] = {
{ },
};
-#define BMA180_CHANNEL(_index) { \
+#define BMA180_CHANNEL(_axis) { \
.type = IIO_ACCEL, \
- .indexed = 1, \
- .channel = (_index), \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ .modified = 1, \
+ .channel2 = IIO_MOD_##_axis, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
- .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
- .scan_index = (_index), \
+ .scan_index = AXIS_##_axis, \
.scan_type = { \
.sign = 's', \
.realbits = 14, \
@@ -465,10 +465,10 @@ static const struct iio_chan_spec_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),
+ BMA180_CHANNEL(X),
+ BMA180_CHANNEL(Y),
+ BMA180_CHANNEL(Z),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
};
static irqreturn_t bma180_trigger_handler(int irq, void *p)
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 2209f28441e9..4bf4c16de976 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -155,6 +155,16 @@ config MCP3422
This driver can also be built as a module. If so, the module will be
called mcp3422.
+config MEN_Z188_ADC
+ tristate "MEN 16z188 ADC IP Core support"
+ depends on MCB
+ help
+ Say yes here to enable support for the MEN 16z188 ADC IP-Core on a MCB
+ carrier.
+
+ This driver can also be built as a module. If so, the module will be
+ called men_z188_adc.
+
config NAU7802
tristate "Nuvoton NAU7802 ADC driver"
depends on I2C
@@ -197,6 +207,16 @@ config TWL6030_GPADC
This driver can also be built as a module. If so, the module will be
called twl6030-gpadc.
+config VF610_ADC
+ tristate "Freescale vf610 ADC driver"
+ depends on OF
+ help
+ Say yes here to support for Vybrid board analog-to-digital converter.
+ Since the IP is used for i.MX6SLX, the driver also support i.MX6SLX.
+
+ This driver can also be built as a module. If so, the module will be
+ called vf610_adc.
+
config VIPERBOARD_ADC
tristate "Viperboard ADC support"
depends on MFD_VIPERBOARD && USB
@@ -204,4 +224,17 @@ config VIPERBOARD_ADC
Say yes here to access the ADC part of the Nano River
Technologies Viperboard.
+config XILINX_XADC
+ tristate "Xilinx XADC driver"
+ depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST
+ depends on HAS_IOMEM
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to have support for the Xilinx XADC. The driver does support
+ both the ZYNQ interface to the XADC as well as the AXI-XADC interface.
+
+ The driver can also be build as a module. If so, the module will be called
+ xilinx-xadc.
+
endmenu
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index ba9a10a24cd0..bb252540664a 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -17,8 +17,12 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
+obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.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_VF610_ADC) += vf610_adc.o
obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
+xilinx-xadc-y := xilinx-xadc-core.o xilinx-xadc-events.o
+obj-$(CONFIG_XILINX_XADC) += xilinx-xadc.o
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
index e283f2f2ee2f..9cf3229a7272 100644
--- a/drivers/iio/adc/max1363.c
+++ b/drivers/iio/adc/max1363.c
@@ -8,17 +8,11 @@
* based on linux/drivers/acron/char/pcf8583.c
* Copyright (C) 2000 Russell King
*
+ * Driver for max1363 and similar chips.
+ *
* 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.
- *
- * max1363.c
- *
- * Partial support for max1363 and similar chips.
- *
- * Not currently implemented.
- *
- * - Control of internal reference.
*/
#include <linux/interrupt.h>
@@ -1253,7 +1247,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
},
[max11604] = {
.bits = 8,
- .int_vref_mv = 4098,
+ .int_vref_mv = 4096,
.mode_list = max1238_mode_list,
.num_modes = ARRAY_SIZE(max1238_mode_list),
.default_mode = s0to11,
@@ -1313,7 +1307,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
},
[max11610] = {
.bits = 10,
- .int_vref_mv = 4098,
+ .int_vref_mv = 4096,
.mode_list = max1238_mode_list,
.num_modes = ARRAY_SIZE(max1238_mode_list),
.default_mode = s0to11,
@@ -1373,7 +1367,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
},
[max11616] = {
.bits = 12,
- .int_vref_mv = 4098,
+ .int_vref_mv = 4096,
.mode_list = max1238_mode_list,
.num_modes = ARRAY_SIZE(max1238_mode_list),
.default_mode = s0to11,
@@ -1560,7 +1554,7 @@ static int max1363_probe(struct i2c_client *client,
st->client = client;
st->vref_uv = st->chip_info->int_vref_mv * 1000;
- vref = devm_regulator_get(&client->dev, "vref");
+ vref = devm_regulator_get_optional(&client->dev, "vref");
if (!IS_ERR(vref)) {
int vref_uv;
diff --git a/drivers/iio/adc/men_z188_adc.c b/drivers/iio/adc/men_z188_adc.c
new file mode 100644
index 000000000000..6989c16aec2b
--- /dev/null
+++ b/drivers/iio/adc/men_z188_adc.c
@@ -0,0 +1,172 @@
+/*
+ * MEN 16z188 Analog to Digial Converter
+ *
+ * Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de)
+ * Author: Johannes Thumshirn <johannes.thumshirn@men.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mcb.h>
+#include <linux/io.h>
+#include <linux/iio/iio.h>
+
+#define Z188_ADC_MAX_CHAN 8
+#define Z188_ADC_GAIN 0x0700000
+#define Z188_MODE_VOLTAGE BIT(27)
+#define Z188_CFG_AUTO 0x1
+#define Z188_CTRL_REG 0x40
+
+#define ADC_DATA(x) (((x) >> 2) & 0x7ffffc)
+#define ADC_OVR(x) ((x) & 0x1)
+
+struct z188_adc {
+ struct resource *mem;
+ void __iomem *base;
+};
+
+#define Z188_ADC_CHANNEL(idx) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = (idx), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+}
+
+static const struct iio_chan_spec z188_adc_iio_channels[] = {
+ Z188_ADC_CHANNEL(0),
+ Z188_ADC_CHANNEL(1),
+ Z188_ADC_CHANNEL(2),
+ Z188_ADC_CHANNEL(3),
+ Z188_ADC_CHANNEL(4),
+ Z188_ADC_CHANNEL(5),
+ Z188_ADC_CHANNEL(6),
+ Z188_ADC_CHANNEL(7),
+};
+
+static int z188_iio_read_raw(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long info)
+{
+ struct z188_adc *adc = iio_priv(iio_dev);
+ int ret;
+ u16 tmp;
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ tmp = readw(adc->base + chan->channel * 4);
+
+ if (ADC_OVR(tmp)) {
+ dev_info(&iio_dev->dev,
+ "Oversampling error on ADC channel %d\n",
+ chan->channel);
+ return -EIO;
+ }
+ *val = ADC_DATA(tmp);
+ ret = IIO_VAL_INT;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static struct iio_info z188_adc_info = {
+ .read_raw = &z188_iio_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static void men_z188_config_channels(void __iomem *addr)
+{
+ int i;
+ u32 cfg;
+ u32 ctl;
+
+ ctl = readl(addr + Z188_CTRL_REG);
+ ctl |= Z188_CFG_AUTO;
+ writel(ctl, addr + Z188_CTRL_REG);
+
+ for (i = 0; i < Z188_ADC_MAX_CHAN; i++) {
+ cfg = readl(addr + i);
+ cfg &= ~Z188_ADC_GAIN;
+ cfg |= Z188_MODE_VOLTAGE;
+ writel(cfg, addr + i);
+ }
+}
+
+static int men_z188_probe(struct mcb_device *dev,
+ const struct mcb_device_id *id)
+{
+ struct z188_adc *adc;
+ struct iio_dev *indio_dev;
+ struct resource *mem;
+
+ indio_dev = devm_iio_device_alloc(&dev->dev, sizeof(struct z188_adc));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ adc = iio_priv(indio_dev);
+ indio_dev->name = "z188-adc";
+ indio_dev->dev.parent = &dev->dev;
+ indio_dev->info = &z188_adc_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = z188_adc_iio_channels;
+ indio_dev->num_channels = ARRAY_SIZE(z188_adc_iio_channels);
+
+ mem = mcb_request_mem(dev, "z188-adc");
+ if (!mem)
+ return -ENOMEM;
+
+ adc->base = ioremap(mem->start, resource_size(mem));
+ if (adc->base == NULL)
+ goto err;
+
+ men_z188_config_channels(adc->base);
+
+ adc->mem = mem;
+ mcb_set_drvdata(dev, indio_dev);
+
+ return iio_device_register(indio_dev);
+
+err:
+ mcb_release_mem(mem);
+ return -ENXIO;
+}
+
+static void men_z188_remove(struct mcb_device *dev)
+{
+ struct iio_dev *indio_dev = mcb_get_drvdata(dev);
+ struct z188_adc *adc = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ iounmap(adc->base);
+ mcb_release_mem(adc->mem);
+}
+
+static const struct mcb_device_id men_z188_ids[] = {
+ { .device = 0xbc },
+};
+MODULE_DEVICE_TABLE(mcb, men_z188_ids);
+
+static struct mcb_driver men_z188_driver = {
+ .driver = {
+ .name = "z188-adc",
+ .owner = THIS_MODULE,
+ },
+ .probe = men_z188_probe,
+ .remove = men_z188_remove,
+ .id_table = men_z188_ids,
+};
+module_mcb_driver(men_z188_driver);
+
+MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IIO ADC driver for MEN 16z188 ADC Core");
+MODULE_ALIAS("mcb:16z188");
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
index 31e786e3999b..a4db3026bec6 100644
--- a/drivers/iio/adc/ti_am335x_adc.c
+++ b/drivers/iio/adc/ti_am335x_adc.c
@@ -13,7 +13,6 @@
* GNU General Public License for more details.
*/
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/module.h>
diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c
index 53a24ebb92c3..15282f148b3b 100644
--- a/drivers/iio/adc/twl6030-gpadc.c
+++ b/drivers/iio/adc/twl6030-gpadc.c
@@ -28,7 +28,6 @@
* 02110-1301 USA
*
*/
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
new file mode 100644
index 000000000000..44799eb5930e
--- /dev/null
+++ b/drivers/iio/adc/vf610_adc.c
@@ -0,0 +1,711 @@
+/*
+ * Freescale Vybrid vf610 ADC driver
+ *
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * 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/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/of.h>
+#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/sysfs.h>
+#include <linux/iio/driver.h>
+
+/* This will be the driver name the kernel reports */
+#define DRIVER_NAME "vf610-adc"
+
+/* Vybrid/IMX ADC registers */
+#define VF610_REG_ADC_HC0 0x00
+#define VF610_REG_ADC_HC1 0x04
+#define VF610_REG_ADC_HS 0x08
+#define VF610_REG_ADC_R0 0x0c
+#define VF610_REG_ADC_R1 0x10
+#define VF610_REG_ADC_CFG 0x14
+#define VF610_REG_ADC_GC 0x18
+#define VF610_REG_ADC_GS 0x1c
+#define VF610_REG_ADC_CV 0x20
+#define VF610_REG_ADC_OFS 0x24
+#define VF610_REG_ADC_CAL 0x28
+#define VF610_REG_ADC_PCTL 0x30
+
+/* Configuration register field define */
+#define VF610_ADC_MODE_BIT8 0x00
+#define VF610_ADC_MODE_BIT10 0x04
+#define VF610_ADC_MODE_BIT12 0x08
+#define VF610_ADC_MODE_MASK 0x0c
+#define VF610_ADC_BUSCLK2_SEL 0x01
+#define VF610_ADC_ALTCLK_SEL 0x02
+#define VF610_ADC_ADACK_SEL 0x03
+#define VF610_ADC_ADCCLK_MASK 0x03
+#define VF610_ADC_CLK_DIV2 0x20
+#define VF610_ADC_CLK_DIV4 0x40
+#define VF610_ADC_CLK_DIV8 0x60
+#define VF610_ADC_CLK_MASK 0x60
+#define VF610_ADC_ADLSMP_LONG 0x10
+#define VF610_ADC_ADSTS_MASK 0x300
+#define VF610_ADC_ADLPC_EN 0x80
+#define VF610_ADC_ADHSC_EN 0x400
+#define VF610_ADC_REFSEL_VALT 0x100
+#define VF610_ADC_REFSEL_VBG 0x1000
+#define VF610_ADC_ADTRG_HARD 0x2000
+#define VF610_ADC_AVGS_8 0x4000
+#define VF610_ADC_AVGS_16 0x8000
+#define VF610_ADC_AVGS_32 0xC000
+#define VF610_ADC_AVGS_MASK 0xC000
+#define VF610_ADC_OVWREN 0x10000
+
+/* General control register field define */
+#define VF610_ADC_ADACKEN 0x1
+#define VF610_ADC_DMAEN 0x2
+#define VF610_ADC_ACREN 0x4
+#define VF610_ADC_ACFGT 0x8
+#define VF610_ADC_ACFE 0x10
+#define VF610_ADC_AVGEN 0x20
+#define VF610_ADC_ADCON 0x40
+#define VF610_ADC_CAL 0x80
+
+/* Other field define */
+#define VF610_ADC_ADCHC(x) ((x) & 0xF)
+#define VF610_ADC_AIEN (0x1 << 7)
+#define VF610_ADC_CONV_DISABLE 0x1F
+#define VF610_ADC_HS_COCO0 0x1
+#define VF610_ADC_CALF 0x2
+#define VF610_ADC_TIMEOUT msecs_to_jiffies(100)
+
+enum clk_sel {
+ VF610_ADCIOC_BUSCLK_SET,
+ VF610_ADCIOC_ALTCLK_SET,
+ VF610_ADCIOC_ADACK_SET,
+};
+
+enum vol_ref {
+ VF610_ADCIOC_VR_VREF_SET,
+ VF610_ADCIOC_VR_VALT_SET,
+ VF610_ADCIOC_VR_VBG_SET,
+};
+
+enum average_sel {
+ VF610_ADC_SAMPLE_1,
+ VF610_ADC_SAMPLE_4,
+ VF610_ADC_SAMPLE_8,
+ VF610_ADC_SAMPLE_16,
+ VF610_ADC_SAMPLE_32,
+};
+
+struct vf610_adc_feature {
+ enum clk_sel clk_sel;
+ enum vol_ref vol_ref;
+
+ int clk_div;
+ int sample_rate;
+ int res_mode;
+
+ bool lpm;
+ bool calibration;
+ bool ovwren;
+};
+
+struct vf610_adc {
+ struct device *dev;
+ void __iomem *regs;
+ struct clk *clk;
+
+ u32 vref_uv;
+ u32 value;
+ struct regulator *vref;
+ struct vf610_adc_feature adc_feature;
+
+ struct completion completion;
+};
+
+#define VF610_ADC_CHAN(_idx, _chan_type) { \
+ .type = (_chan_type), \
+ .indexed = 1, \
+ .channel = (_idx), \
+ .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 vf610_adc_iio_channels[] = {
+ VF610_ADC_CHAN(0, IIO_VOLTAGE),
+ VF610_ADC_CHAN(1, IIO_VOLTAGE),
+ VF610_ADC_CHAN(2, IIO_VOLTAGE),
+ VF610_ADC_CHAN(3, IIO_VOLTAGE),
+ VF610_ADC_CHAN(4, IIO_VOLTAGE),
+ VF610_ADC_CHAN(5, IIO_VOLTAGE),
+ VF610_ADC_CHAN(6, IIO_VOLTAGE),
+ VF610_ADC_CHAN(7, IIO_VOLTAGE),
+ VF610_ADC_CHAN(8, IIO_VOLTAGE),
+ VF610_ADC_CHAN(9, IIO_VOLTAGE),
+ VF610_ADC_CHAN(10, IIO_VOLTAGE),
+ VF610_ADC_CHAN(11, IIO_VOLTAGE),
+ VF610_ADC_CHAN(12, IIO_VOLTAGE),
+ VF610_ADC_CHAN(13, IIO_VOLTAGE),
+ VF610_ADC_CHAN(14, IIO_VOLTAGE),
+ VF610_ADC_CHAN(15, IIO_VOLTAGE),
+ /* sentinel */
+};
+
+/*
+ * ADC sample frequency, unit is ADCK cycles.
+ * ADC clk source is ipg clock, which is the same as bus clock.
+ *
+ * ADC conversion time = SFCAdder + AverageNum x (BCT + LSTAdder)
+ * SFCAdder: fixed to 6 ADCK cycles
+ * AverageNum: 1, 4, 8, 16, 32 samples for hardware average.
+ * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode
+ * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles
+ *
+ * By default, enable 12 bit resolution mode, clock source
+ * set to ipg clock, So get below frequency group:
+ */
+static const u32 vf610_sample_freq_avail[5] =
+{1941176, 559332, 286957, 145374, 73171};
+
+static inline void vf610_adc_cfg_init(struct vf610_adc *info)
+{
+ /* set default Configuration for ADC controller */
+ info->adc_feature.clk_sel = VF610_ADCIOC_BUSCLK_SET;
+ info->adc_feature.vol_ref = VF610_ADCIOC_VR_VREF_SET;
+
+ info->adc_feature.calibration = true;
+ info->adc_feature.ovwren = true;
+
+ info->adc_feature.clk_div = 1;
+ info->adc_feature.res_mode = 12;
+ info->adc_feature.sample_rate = 1;
+ info->adc_feature.lpm = true;
+}
+
+static void vf610_adc_cfg_post_set(struct vf610_adc *info)
+{
+ struct vf610_adc_feature *adc_feature = &info->adc_feature;
+ int cfg_data = 0;
+ int gc_data = 0;
+
+ switch (adc_feature->clk_sel) {
+ case VF610_ADCIOC_ALTCLK_SET:
+ cfg_data |= VF610_ADC_ALTCLK_SEL;
+ break;
+ case VF610_ADCIOC_ADACK_SET:
+ cfg_data |= VF610_ADC_ADACK_SEL;
+ break;
+ default:
+ break;
+ }
+
+ /* low power set for calibration */
+ cfg_data |= VF610_ADC_ADLPC_EN;
+
+ /* enable high speed for calibration */
+ cfg_data |= VF610_ADC_ADHSC_EN;
+
+ /* voltage reference */
+ switch (adc_feature->vol_ref) {
+ case VF610_ADCIOC_VR_VREF_SET:
+ break;
+ case VF610_ADCIOC_VR_VALT_SET:
+ cfg_data |= VF610_ADC_REFSEL_VALT;
+ break;
+ case VF610_ADCIOC_VR_VBG_SET:
+ cfg_data |= VF610_ADC_REFSEL_VBG;
+ break;
+ default:
+ dev_err(info->dev, "error voltage reference\n");
+ }
+
+ /* data overwrite enable */
+ if (adc_feature->ovwren)
+ cfg_data |= VF610_ADC_OVWREN;
+
+ writel(cfg_data, info->regs + VF610_REG_ADC_CFG);
+ writel(gc_data, info->regs + VF610_REG_ADC_GC);
+}
+
+static void vf610_adc_calibration(struct vf610_adc *info)
+{
+ int adc_gc, hc_cfg;
+ int timeout;
+
+ if (!info->adc_feature.calibration)
+ return;
+
+ /* enable calibration interrupt */
+ hc_cfg = VF610_ADC_AIEN | VF610_ADC_CONV_DISABLE;
+ writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
+
+ adc_gc = readl(info->regs + VF610_REG_ADC_GC);
+ writel(adc_gc | VF610_ADC_CAL, info->regs + VF610_REG_ADC_GC);
+
+ timeout = wait_for_completion_timeout
+ (&info->completion, VF610_ADC_TIMEOUT);
+ if (timeout == 0)
+ dev_err(info->dev, "Timeout for adc calibration\n");
+
+ adc_gc = readl(info->regs + VF610_REG_ADC_GS);
+ if (adc_gc & VF610_ADC_CALF)
+ dev_err(info->dev, "ADC calibration failed\n");
+
+ info->adc_feature.calibration = false;
+}
+
+static void vf610_adc_cfg_set(struct vf610_adc *info)
+{
+ struct vf610_adc_feature *adc_feature = &(info->adc_feature);
+ int cfg_data;
+
+ cfg_data = readl(info->regs + VF610_REG_ADC_CFG);
+
+ /* low power configuration */
+ cfg_data &= ~VF610_ADC_ADLPC_EN;
+ if (adc_feature->lpm)
+ cfg_data |= VF610_ADC_ADLPC_EN;
+
+ /* disable high speed */
+ cfg_data &= ~VF610_ADC_ADHSC_EN;
+
+ writel(cfg_data, info->regs + VF610_REG_ADC_CFG);
+}
+
+static void vf610_adc_sample_set(struct vf610_adc *info)
+{
+ struct vf610_adc_feature *adc_feature = &(info->adc_feature);
+ int cfg_data, gc_data;
+
+ cfg_data = readl(info->regs + VF610_REG_ADC_CFG);
+ gc_data = readl(info->regs + VF610_REG_ADC_GC);
+
+ /* resolution mode */
+ cfg_data &= ~VF610_ADC_MODE_MASK;
+ switch (adc_feature->res_mode) {
+ case 8:
+ cfg_data |= VF610_ADC_MODE_BIT8;
+ break;
+ case 10:
+ cfg_data |= VF610_ADC_MODE_BIT10;
+ break;
+ case 12:
+ cfg_data |= VF610_ADC_MODE_BIT12;
+ break;
+ default:
+ dev_err(info->dev, "error resolution mode\n");
+ break;
+ }
+
+ /* clock select and clock divider */
+ cfg_data &= ~(VF610_ADC_CLK_MASK | VF610_ADC_ADCCLK_MASK);
+ switch (adc_feature->clk_div) {
+ case 1:
+ break;
+ case 2:
+ cfg_data |= VF610_ADC_CLK_DIV2;
+ break;
+ case 4:
+ cfg_data |= VF610_ADC_CLK_DIV4;
+ break;
+ case 8:
+ cfg_data |= VF610_ADC_CLK_DIV8;
+ break;
+ case 16:
+ switch (adc_feature->clk_sel) {
+ case VF610_ADCIOC_BUSCLK_SET:
+ cfg_data |= VF610_ADC_BUSCLK2_SEL | VF610_ADC_CLK_DIV8;
+ break;
+ default:
+ dev_err(info->dev, "error clk divider\n");
+ break;
+ }
+ break;
+ }
+
+ /* Use the short sample mode */
+ cfg_data &= ~(VF610_ADC_ADLSMP_LONG | VF610_ADC_ADSTS_MASK);
+
+ /* update hardware average selection */
+ cfg_data &= ~VF610_ADC_AVGS_MASK;
+ gc_data &= ~VF610_ADC_AVGEN;
+ switch (adc_feature->sample_rate) {
+ case VF610_ADC_SAMPLE_1:
+ break;
+ case VF610_ADC_SAMPLE_4:
+ gc_data |= VF610_ADC_AVGEN;
+ break;
+ case VF610_ADC_SAMPLE_8:
+ gc_data |= VF610_ADC_AVGEN;
+ cfg_data |= VF610_ADC_AVGS_8;
+ break;
+ case VF610_ADC_SAMPLE_16:
+ gc_data |= VF610_ADC_AVGEN;
+ cfg_data |= VF610_ADC_AVGS_16;
+ break;
+ case VF610_ADC_SAMPLE_32:
+ gc_data |= VF610_ADC_AVGEN;
+ cfg_data |= VF610_ADC_AVGS_32;
+ break;
+ default:
+ dev_err(info->dev,
+ "error hardware sample average select\n");
+ }
+
+ writel(cfg_data, info->regs + VF610_REG_ADC_CFG);
+ writel(gc_data, info->regs + VF610_REG_ADC_GC);
+}
+
+static void vf610_adc_hw_init(struct vf610_adc *info)
+{
+ /* CFG: Feature set */
+ vf610_adc_cfg_post_set(info);
+ vf610_adc_sample_set(info);
+
+ /* adc calibration */
+ vf610_adc_calibration(info);
+
+ /* CFG: power and speed set */
+ vf610_adc_cfg_set(info);
+}
+
+static int vf610_adc_read_data(struct vf610_adc *info)
+{
+ int result;
+
+ result = readl(info->regs + VF610_REG_ADC_R0);
+
+ switch (info->adc_feature.res_mode) {
+ case 8:
+ result &= 0xFF;
+ break;
+ case 10:
+ result &= 0x3FF;
+ break;
+ case 12:
+ result &= 0xFFF;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+static irqreturn_t vf610_adc_isr(int irq, void *dev_id)
+{
+ struct vf610_adc *info = (struct vf610_adc *)dev_id;
+ int coco;
+
+ coco = readl(info->regs + VF610_REG_ADC_HS);
+ if (coco & VF610_ADC_HS_COCO0) {
+ info->value = vf610_adc_read_data(info);
+ complete(&info->completion);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("1941176, 559332, 286957, 145374, 73171");
+
+static struct attribute *vf610_attributes[] = {
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group vf610_attribute_group = {
+ .attrs = vf610_attributes,
+};
+
+static int vf610_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long mask)
+{
+ struct vf610_adc *info = iio_priv(indio_dev);
+ unsigned int hc_cfg;
+ long ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&indio_dev->mlock);
+ reinit_completion(&info->completion);
+
+ hc_cfg = VF610_ADC_ADCHC(chan->channel);
+ hc_cfg |= VF610_ADC_AIEN;
+ writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
+ ret = wait_for_completion_interruptible_timeout
+ (&info->completion, VF610_ADC_TIMEOUT);
+ if (ret == 0) {
+ mutex_unlock(&indio_dev->mlock);
+ return -ETIMEDOUT;
+ }
+ if (ret < 0) {
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+ }
+
+ *val = info->value;
+ mutex_unlock(&indio_dev->mlock);
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ *val = info->vref_uv / 1000;
+ *val2 = info->adc_feature.res_mode;
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = vf610_sample_freq_avail[info->adc_feature.sample_rate];
+ *val2 = 0;
+ return IIO_VAL_INT;
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int vf610_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ struct vf610_adc *info = iio_priv(indio_dev);
+ int i;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ for (i = 0;
+ i < ARRAY_SIZE(vf610_sample_freq_avail);
+ i++)
+ if (val == vf610_sample_freq_avail[i]) {
+ info->adc_feature.sample_rate = i;
+ vf610_adc_sample_set(info);
+ return 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int vf610_adc_reg_access(struct iio_dev *indio_dev,
+ unsigned reg, unsigned writeval,
+ unsigned *readval)
+{
+ struct vf610_adc *info = iio_priv(indio_dev);
+
+ if ((readval == NULL) ||
+ (!(reg % 4) || (reg > VF610_REG_ADC_PCTL)))
+ return -EINVAL;
+
+ *readval = readl(info->regs + reg);
+
+ return 0;
+}
+
+static const struct iio_info vf610_adc_iio_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = &vf610_read_raw,
+ .write_raw = &vf610_write_raw,
+ .debugfs_reg_access = &vf610_adc_reg_access,
+ .attrs = &vf610_attribute_group,
+};
+
+static const struct of_device_id vf610_adc_match[] = {
+ { .compatible = "fsl,vf610-adc", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, vf610_adc_match);
+
+static int vf610_adc_probe(struct platform_device *pdev)
+{
+ struct vf610_adc *info;
+ struct iio_dev *indio_dev;
+ struct resource *mem;
+ int irq;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct vf610_adc));
+ if (!indio_dev) {
+ dev_err(&pdev->dev, "Failed allocating iio device\n");
+ return -ENOMEM;
+ }
+
+ info = iio_priv(indio_dev);
+ info->dev = &pdev->dev;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ info->regs = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(info->regs))
+ return PTR_ERR(info->regs);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ return -EINVAL;
+ }
+
+ ret = devm_request_irq(info->dev, irq,
+ vf610_adc_isr, 0,
+ dev_name(&pdev->dev), info);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", irq);
+ return ret;
+ }
+
+ info->clk = devm_clk_get(&pdev->dev, "adc");
+ if (IS_ERR(info->clk)) {
+ dev_err(&pdev->dev, "failed getting clock, err = %ld\n",
+ PTR_ERR(info->clk));
+ ret = PTR_ERR(info->clk);
+ return ret;
+ }
+
+ info->vref = devm_regulator_get(&pdev->dev, "vref");
+ if (IS_ERR(info->vref))
+ return PTR_ERR(info->vref);
+
+ ret = regulator_enable(info->vref);
+ if (ret)
+ return ret;
+
+ info->vref_uv = regulator_get_voltage(info->vref);
+
+ platform_set_drvdata(pdev, indio_dev);
+
+ init_completion(&info->completion);
+
+ indio_dev->name = dev_name(&pdev->dev);
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->dev.of_node = pdev->dev.of_node;
+ indio_dev->info = &vf610_adc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = vf610_adc_iio_channels;
+ indio_dev->num_channels = ARRAY_SIZE(vf610_adc_iio_channels);
+
+ ret = clk_prepare_enable(info->clk);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Could not prepare or enable the clock.\n");
+ goto error_adc_clk_enable;
+ }
+
+ vf610_adc_cfg_init(info);
+ vf610_adc_hw_init(info);
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't register the device.\n");
+ goto error_iio_device_register;
+ }
+
+ return 0;
+
+
+error_iio_device_register:
+ clk_disable_unprepare(info->clk);
+error_adc_clk_enable:
+ regulator_disable(info->vref);
+
+ return ret;
+}
+
+static int vf610_adc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct vf610_adc *info = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ regulator_disable(info->vref);
+ clk_disable_unprepare(info->clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int vf610_adc_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct vf610_adc *info = iio_priv(indio_dev);
+ int hc_cfg;
+
+ /* ADC controller enters to stop mode */
+ hc_cfg = readl(info->regs + VF610_REG_ADC_HC0);
+ hc_cfg |= VF610_ADC_CONV_DISABLE;
+ writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
+
+ clk_disable_unprepare(info->clk);
+ regulator_disable(info->vref);
+
+ return 0;
+}
+
+static int vf610_adc_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct vf610_adc *info = iio_priv(indio_dev);
+ int ret;
+
+ ret = regulator_enable(info->vref);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(info->clk);
+ if (ret)
+ return ret;
+
+ vf610_adc_hw_init(info);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops,
+ vf610_adc_suspend,
+ vf610_adc_resume);
+
+static struct platform_driver vf610_adc_driver = {
+ .probe = vf610_adc_probe,
+ .remove = vf610_adc_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = vf610_adc_match,
+ .pm = &vf610_adc_pm_ops,
+ },
+};
+
+module_platform_driver(vf610_adc_driver);
+
+MODULE_AUTHOR("Fugang Duan <B38611@freescale.com>");
+MODULE_DESCRIPTION("Freescale VF610 ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/viperboard_adc.c b/drivers/iio/adc/viperboard_adc.c
index d0add8f9416b..9acf6b6d705b 100644
--- a/drivers/iio/adc/viperboard_adc.c
+++ b/drivers/iio/adc/viperboard_adc.c
@@ -139,8 +139,6 @@ static int vprbrd_adc_probe(struct platform_device *pdev)
return ret;
}
- platform_set_drvdata(pdev, indio_dev);
-
return 0;
}
diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c
new file mode 100644
index 000000000000..ab52be29141b
--- /dev/null
+++ b/drivers/iio/adc/xilinx-xadc-core.c
@@ -0,0 +1,1333 @@
+/*
+ * Xilinx XADC driver
+ *
+ * Copyright 2013-2014 Analog Devices Inc.
+ * Author: Lars-Peter Clauen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ *
+ * Documentation for the parts can be found at:
+ * - XADC hardmacro: Xilinx UG480
+ * - ZYNQ XADC interface: Xilinx UG585
+ * - AXI XADC interface: Xilinx PG019
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#include "xilinx-xadc.h"
+
+static const unsigned int XADC_ZYNQ_UNMASK_TIMEOUT = 500;
+
+/* ZYNQ register definitions */
+#define XADC_ZYNQ_REG_CFG 0x00
+#define XADC_ZYNQ_REG_INTSTS 0x04
+#define XADC_ZYNQ_REG_INTMSK 0x08
+#define XADC_ZYNQ_REG_STATUS 0x0c
+#define XADC_ZYNQ_REG_CFIFO 0x10
+#define XADC_ZYNQ_REG_DFIFO 0x14
+#define XADC_ZYNQ_REG_CTL 0x18
+
+#define XADC_ZYNQ_CFG_ENABLE BIT(31)
+#define XADC_ZYNQ_CFG_CFIFOTH_MASK (0xf << 20)
+#define XADC_ZYNQ_CFG_CFIFOTH_OFFSET 20
+#define XADC_ZYNQ_CFG_DFIFOTH_MASK (0xf << 16)
+#define XADC_ZYNQ_CFG_DFIFOTH_OFFSET 16
+#define XADC_ZYNQ_CFG_WEDGE BIT(13)
+#define XADC_ZYNQ_CFG_REDGE BIT(12)
+#define XADC_ZYNQ_CFG_TCKRATE_MASK (0x3 << 8)
+#define XADC_ZYNQ_CFG_TCKRATE_DIV2 (0x0 << 8)
+#define XADC_ZYNQ_CFG_TCKRATE_DIV4 (0x1 << 8)
+#define XADC_ZYNQ_CFG_TCKRATE_DIV8 (0x2 << 8)
+#define XADC_ZYNQ_CFG_TCKRATE_DIV16 (0x3 << 8)
+#define XADC_ZYNQ_CFG_IGAP_MASK 0x1f
+#define XADC_ZYNQ_CFG_IGAP(x) (x)
+
+#define XADC_ZYNQ_INT_CFIFO_LTH BIT(9)
+#define XADC_ZYNQ_INT_DFIFO_GTH BIT(8)
+#define XADC_ZYNQ_INT_ALARM_MASK 0xff
+#define XADC_ZYNQ_INT_ALARM_OFFSET 0
+
+#define XADC_ZYNQ_STATUS_CFIFO_LVL_MASK (0xf << 16)
+#define XADC_ZYNQ_STATUS_CFIFO_LVL_OFFSET 16
+#define XADC_ZYNQ_STATUS_DFIFO_LVL_MASK (0xf << 12)
+#define XADC_ZYNQ_STATUS_DFIFO_LVL_OFFSET 12
+#define XADC_ZYNQ_STATUS_CFIFOF BIT(11)
+#define XADC_ZYNQ_STATUS_CFIFOE BIT(10)
+#define XADC_ZYNQ_STATUS_DFIFOF BIT(9)
+#define XADC_ZYNQ_STATUS_DFIFOE BIT(8)
+#define XADC_ZYNQ_STATUS_OT BIT(7)
+#define XADC_ZYNQ_STATUS_ALM(x) BIT(x)
+
+#define XADC_ZYNQ_CTL_RESET BIT(4)
+
+#define XADC_ZYNQ_CMD_NOP 0x00
+#define XADC_ZYNQ_CMD_READ 0x01
+#define XADC_ZYNQ_CMD_WRITE 0x02
+
+#define XADC_ZYNQ_CMD(cmd, addr, data) (((cmd) << 26) | ((addr) << 16) | (data))
+
+/* AXI register definitions */
+#define XADC_AXI_REG_RESET 0x00
+#define XADC_AXI_REG_STATUS 0x04
+#define XADC_AXI_REG_ALARM_STATUS 0x08
+#define XADC_AXI_REG_CONVST 0x0c
+#define XADC_AXI_REG_XADC_RESET 0x10
+#define XADC_AXI_REG_GIER 0x5c
+#define XADC_AXI_REG_IPISR 0x60
+#define XADC_AXI_REG_IPIER 0x68
+#define XADC_AXI_ADC_REG_OFFSET 0x200
+
+#define XADC_AXI_RESET_MAGIC 0xa
+#define XADC_AXI_GIER_ENABLE BIT(31)
+
+#define XADC_AXI_INT_EOS BIT(4)
+#define XADC_AXI_INT_ALARM_MASK 0x3c0f
+
+#define XADC_FLAGS_BUFFERED BIT(0)
+
+static void xadc_write_reg(struct xadc *xadc, unsigned int reg,
+ uint32_t val)
+{
+ writel(val, xadc->base + reg);
+}
+
+static void xadc_read_reg(struct xadc *xadc, unsigned int reg,
+ uint32_t *val)
+{
+ *val = readl(xadc->base + reg);
+}
+
+/*
+ * The ZYNQ interface uses two asynchronous FIFOs for communication with the
+ * XADC. Reads and writes to the XADC register are performed by submitting a
+ * request to the command FIFO (CFIFO), once the request has been completed the
+ * result can be read from the data FIFO (DFIFO). The method currently used in
+ * this driver is to submit the request for a read/write operation, then go to
+ * sleep and wait for an interrupt that signals that a response is available in
+ * the data FIFO.
+ */
+
+static void xadc_zynq_write_fifo(struct xadc *xadc, uint32_t *cmd,
+ unsigned int n)
+{
+ unsigned int i;
+
+ for (i = 0; i < n; i++)
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_CFIFO, cmd[i]);
+}
+
+static void xadc_zynq_drain_fifo(struct xadc *xadc)
+{
+ uint32_t status, tmp;
+
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_STATUS, &status);
+
+ while (!(status & XADC_ZYNQ_STATUS_DFIFOE)) {
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &tmp);
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_STATUS, &status);
+ }
+}
+
+static void xadc_zynq_update_intmsk(struct xadc *xadc, unsigned int mask,
+ unsigned int val)
+{
+ xadc->zynq_intmask &= ~mask;
+ xadc->zynq_intmask |= val;
+
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_INTMSK,
+ xadc->zynq_intmask | xadc->zynq_masked_alarm);
+}
+
+static int xadc_zynq_write_adc_reg(struct xadc *xadc, unsigned int reg,
+ uint16_t val)
+{
+ uint32_t cmd[1];
+ uint32_t tmp;
+ int ret;
+
+ spin_lock_irq(&xadc->lock);
+ xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH,
+ XADC_ZYNQ_INT_DFIFO_GTH);
+
+ reinit_completion(&xadc->completion);
+
+ cmd[0] = XADC_ZYNQ_CMD(XADC_ZYNQ_CMD_WRITE, reg, val);
+ xadc_zynq_write_fifo(xadc, cmd, ARRAY_SIZE(cmd));
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_CFG, &tmp);
+ tmp &= ~XADC_ZYNQ_CFG_DFIFOTH_MASK;
+ tmp |= 0 << XADC_ZYNQ_CFG_DFIFOTH_OFFSET;
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_CFG, tmp);
+
+ xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, 0);
+ spin_unlock_irq(&xadc->lock);
+
+ ret = wait_for_completion_interruptible_timeout(&xadc->completion, HZ);
+ if (ret == 0)
+ ret = -EIO;
+ else
+ ret = 0;
+
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &tmp);
+
+ return ret;
+}
+
+static int xadc_zynq_read_adc_reg(struct xadc *xadc, unsigned int reg,
+ uint16_t *val)
+{
+ uint32_t cmd[2];
+ uint32_t resp, tmp;
+ int ret;
+
+ cmd[0] = XADC_ZYNQ_CMD(XADC_ZYNQ_CMD_READ, reg, 0);
+ cmd[1] = XADC_ZYNQ_CMD(XADC_ZYNQ_CMD_NOP, 0, 0);
+
+ spin_lock_irq(&xadc->lock);
+ xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH,
+ XADC_ZYNQ_INT_DFIFO_GTH);
+ xadc_zynq_drain_fifo(xadc);
+ reinit_completion(&xadc->completion);
+
+ xadc_zynq_write_fifo(xadc, cmd, ARRAY_SIZE(cmd));
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_CFG, &tmp);
+ tmp &= ~XADC_ZYNQ_CFG_DFIFOTH_MASK;
+ tmp |= 1 << XADC_ZYNQ_CFG_DFIFOTH_OFFSET;
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_CFG, tmp);
+
+ xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, 0);
+ spin_unlock_irq(&xadc->lock);
+ ret = wait_for_completion_interruptible_timeout(&xadc->completion, HZ);
+ if (ret == 0)
+ ret = -EIO;
+ if (ret < 0)
+ return ret;
+
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &resp);
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &resp);
+
+ *val = resp & 0xffff;
+
+ return 0;
+}
+
+static unsigned int xadc_zynq_transform_alarm(unsigned int alarm)
+{
+ return ((alarm & 0x80) >> 4) |
+ ((alarm & 0x78) << 1) |
+ (alarm & 0x07);
+}
+
+/*
+ * The ZYNQ threshold interrupts are level sensitive. Since we can't make the
+ * threshold condition go way from within the interrupt handler, this means as
+ * soon as a threshold condition is present we would enter the interrupt handler
+ * again and again. To work around this we mask all active thresholds interrupts
+ * in the interrupt handler and start a timer. In this timer we poll the
+ * interrupt status and only if the interrupt is inactive we unmask it again.
+ */
+static void xadc_zynq_unmask_worker(struct work_struct *work)
+{
+ struct xadc *xadc = container_of(work, struct xadc, zynq_unmask_work.work);
+ unsigned int misc_sts, unmask;
+
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_STATUS, &misc_sts);
+
+ misc_sts &= XADC_ZYNQ_INT_ALARM_MASK;
+
+ spin_lock_irq(&xadc->lock);
+
+ /* Clear those bits which are not active anymore */
+ unmask = (xadc->zynq_masked_alarm ^ misc_sts) & xadc->zynq_masked_alarm;
+ xadc->zynq_masked_alarm &= misc_sts;
+
+ /* Also clear those which are masked out anyway */
+ xadc->zynq_masked_alarm &= ~xadc->zynq_intmask;
+
+ /* Clear the interrupts before we unmask them */
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, unmask);
+
+ xadc_zynq_update_intmsk(xadc, 0, 0);
+
+ spin_unlock_irq(&xadc->lock);
+
+ /* if still pending some alarm re-trigger the timer */
+ if (xadc->zynq_masked_alarm) {
+ schedule_delayed_work(&xadc->zynq_unmask_work,
+ msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT));
+ }
+}
+
+static irqreturn_t xadc_zynq_threaded_interrupt_handler(int irq, void *devid)
+{
+ struct iio_dev *indio_dev = devid;
+ struct xadc *xadc = iio_priv(indio_dev);
+ unsigned int alarm;
+
+ spin_lock_irq(&xadc->lock);
+ alarm = xadc->zynq_alarm;
+ xadc->zynq_alarm = 0;
+ spin_unlock_irq(&xadc->lock);
+
+ xadc_handle_events(indio_dev, xadc_zynq_transform_alarm(alarm));
+
+ /* unmask the required interrupts in timer. */
+ schedule_delayed_work(&xadc->zynq_unmask_work,
+ msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT));
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t xadc_zynq_interrupt_handler(int irq, void *devid)
+{
+ struct iio_dev *indio_dev = devid;
+ struct xadc *xadc = iio_priv(indio_dev);
+ irqreturn_t ret = IRQ_HANDLED;
+ uint32_t status;
+
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_INTSTS, &status);
+
+ status &= ~(xadc->zynq_intmask | xadc->zynq_masked_alarm);
+
+ if (!status)
+ return IRQ_NONE;
+
+ spin_lock(&xadc->lock);
+
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, status);
+
+ if (status & XADC_ZYNQ_INT_DFIFO_GTH) {
+ xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH,
+ XADC_ZYNQ_INT_DFIFO_GTH);
+ complete(&xadc->completion);
+ }
+
+ status &= XADC_ZYNQ_INT_ALARM_MASK;
+ if (status) {
+ xadc->zynq_alarm |= status;
+ xadc->zynq_masked_alarm |= status;
+ /*
+ * mask the current event interrupt,
+ * unmask it when the interrupt is no more active.
+ */
+ xadc_zynq_update_intmsk(xadc, 0, 0);
+ ret = IRQ_WAKE_THREAD;
+ }
+ spin_unlock(&xadc->lock);
+
+ return ret;
+}
+
+#define XADC_ZYNQ_TCK_RATE_MAX 50000000
+#define XADC_ZYNQ_IGAP_DEFAULT 20
+
+static int xadc_zynq_setup(struct platform_device *pdev,
+ struct iio_dev *indio_dev, int irq)
+{
+ struct xadc *xadc = iio_priv(indio_dev);
+ unsigned long pcap_rate;
+ unsigned int tck_div;
+ unsigned int div;
+ unsigned int igap;
+ unsigned int tck_rate;
+
+ /* TODO: Figure out how to make igap and tck_rate configurable */
+ igap = XADC_ZYNQ_IGAP_DEFAULT;
+ tck_rate = XADC_ZYNQ_TCK_RATE_MAX;
+
+ xadc->zynq_intmask = ~0;
+
+ pcap_rate = clk_get_rate(xadc->clk);
+
+ if (tck_rate > XADC_ZYNQ_TCK_RATE_MAX)
+ tck_rate = XADC_ZYNQ_TCK_RATE_MAX;
+ if (tck_rate > pcap_rate / 2) {
+ div = 2;
+ } else {
+ div = pcap_rate / tck_rate;
+ if (pcap_rate / div > XADC_ZYNQ_TCK_RATE_MAX)
+ div++;
+ }
+
+ if (div <= 3)
+ tck_div = XADC_ZYNQ_CFG_TCKRATE_DIV2;
+ else if (div <= 7)
+ tck_div = XADC_ZYNQ_CFG_TCKRATE_DIV4;
+ else if (div <= 15)
+ tck_div = XADC_ZYNQ_CFG_TCKRATE_DIV8;
+ else
+ tck_div = XADC_ZYNQ_CFG_TCKRATE_DIV16;
+
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_CTL, XADC_ZYNQ_CTL_RESET);
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_CTL, 0);
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, ~0);
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_INTMSK, xadc->zynq_intmask);
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_CFG, XADC_ZYNQ_CFG_ENABLE |
+ XADC_ZYNQ_CFG_REDGE | XADC_ZYNQ_CFG_WEDGE |
+ tck_div | XADC_ZYNQ_CFG_IGAP(igap));
+
+ return 0;
+}
+
+static unsigned long xadc_zynq_get_dclk_rate(struct xadc *xadc)
+{
+ unsigned int div;
+ uint32_t val;
+
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_CFG, &val);
+
+ switch (val & XADC_ZYNQ_CFG_TCKRATE_MASK) {
+ case XADC_ZYNQ_CFG_TCKRATE_DIV4:
+ div = 4;
+ break;
+ case XADC_ZYNQ_CFG_TCKRATE_DIV8:
+ div = 8;
+ break;
+ case XADC_ZYNQ_CFG_TCKRATE_DIV16:
+ div = 16;
+ break;
+ default:
+ div = 2;
+ break;
+ }
+
+ return clk_get_rate(xadc->clk) / div;
+}
+
+static void xadc_zynq_update_alarm(struct xadc *xadc, unsigned int alarm)
+{
+ unsigned long flags;
+ uint32_t status;
+
+ /* Move OT to bit 7 */
+ alarm = ((alarm & 0x08) << 4) | ((alarm & 0xf0) >> 1) | (alarm & 0x07);
+
+ spin_lock_irqsave(&xadc->lock, flags);
+
+ /* Clear previous interrupts if any. */
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_INTSTS, &status);
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, status & alarm);
+
+ xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_ALARM_MASK,
+ ~alarm & XADC_ZYNQ_INT_ALARM_MASK);
+
+ spin_unlock_irqrestore(&xadc->lock, flags);
+}
+
+static const struct xadc_ops xadc_zynq_ops = {
+ .read = xadc_zynq_read_adc_reg,
+ .write = xadc_zynq_write_adc_reg,
+ .setup = xadc_zynq_setup,
+ .get_dclk_rate = xadc_zynq_get_dclk_rate,
+ .interrupt_handler = xadc_zynq_interrupt_handler,
+ .threaded_interrupt_handler = xadc_zynq_threaded_interrupt_handler,
+ .update_alarm = xadc_zynq_update_alarm,
+};
+
+static int xadc_axi_read_adc_reg(struct xadc *xadc, unsigned int reg,
+ uint16_t *val)
+{
+ uint32_t val32;
+
+ xadc_read_reg(xadc, XADC_AXI_ADC_REG_OFFSET + reg * 4, &val32);
+ *val = val32 & 0xffff;
+
+ return 0;
+}
+
+static int xadc_axi_write_adc_reg(struct xadc *xadc, unsigned int reg,
+ uint16_t val)
+{
+ xadc_write_reg(xadc, XADC_AXI_ADC_REG_OFFSET + reg * 4, val);
+
+ return 0;
+}
+
+static int xadc_axi_setup(struct platform_device *pdev,
+ struct iio_dev *indio_dev, int irq)
+{
+ struct xadc *xadc = iio_priv(indio_dev);
+
+ xadc_write_reg(xadc, XADC_AXI_REG_RESET, XADC_AXI_RESET_MAGIC);
+ xadc_write_reg(xadc, XADC_AXI_REG_GIER, XADC_AXI_GIER_ENABLE);
+
+ return 0;
+}
+
+static irqreturn_t xadc_axi_interrupt_handler(int irq, void *devid)
+{
+ struct iio_dev *indio_dev = devid;
+ struct xadc *xadc = iio_priv(indio_dev);
+ uint32_t status, mask;
+ unsigned int events;
+
+ xadc_read_reg(xadc, XADC_AXI_REG_IPISR, &status);
+ xadc_read_reg(xadc, XADC_AXI_REG_IPIER, &mask);
+ status &= mask;
+
+ if (!status)
+ return IRQ_NONE;
+
+ if ((status & XADC_AXI_INT_EOS) && xadc->trigger)
+ iio_trigger_poll(xadc->trigger, 0);
+
+ if (status & XADC_AXI_INT_ALARM_MASK) {
+ /*
+ * The order of the bits in the AXI-XADC status register does
+ * not match the order of the bits in the XADC alarm enable
+ * register. xadc_handle_events() expects the events to be in
+ * the same order as the XADC alarm enable register.
+ */
+ events = (status & 0x000e) >> 1;
+ events |= (status & 0x0001) << 3;
+ events |= (status & 0x3c00) >> 6;
+ xadc_handle_events(indio_dev, events);
+ }
+
+ xadc_write_reg(xadc, XADC_AXI_REG_IPISR, status);
+
+ return IRQ_HANDLED;
+}
+
+static void xadc_axi_update_alarm(struct xadc *xadc, unsigned int alarm)
+{
+ uint32_t val;
+ unsigned long flags;
+
+ /*
+ * The order of the bits in the AXI-XADC status register does not match
+ * the order of the bits in the XADC alarm enable register. We get
+ * passed the alarm mask in the same order as in the XADC alarm enable
+ * register.
+ */
+ alarm = ((alarm & 0x07) << 1) | ((alarm & 0x08) >> 3) |
+ ((alarm & 0xf0) << 6);
+
+ spin_lock_irqsave(&xadc->lock, flags);
+ xadc_read_reg(xadc, XADC_AXI_REG_IPIER, &val);
+ val &= ~XADC_AXI_INT_ALARM_MASK;
+ val |= alarm;
+ xadc_write_reg(xadc, XADC_AXI_REG_IPIER, val);
+ spin_unlock_irqrestore(&xadc->lock, flags);
+}
+
+static unsigned long xadc_axi_get_dclk(struct xadc *xadc)
+{
+ return clk_get_rate(xadc->clk);
+}
+
+static const struct xadc_ops xadc_axi_ops = {
+ .read = xadc_axi_read_adc_reg,
+ .write = xadc_axi_write_adc_reg,
+ .setup = xadc_axi_setup,
+ .get_dclk_rate = xadc_axi_get_dclk,
+ .update_alarm = xadc_axi_update_alarm,
+ .interrupt_handler = xadc_axi_interrupt_handler,
+ .flags = XADC_FLAGS_BUFFERED,
+};
+
+static int _xadc_update_adc_reg(struct xadc *xadc, unsigned int reg,
+ uint16_t mask, uint16_t val)
+{
+ uint16_t tmp;
+ int ret;
+
+ ret = _xadc_read_adc_reg(xadc, reg, &tmp);
+ if (ret)
+ return ret;
+
+ return _xadc_write_adc_reg(xadc, reg, (tmp & ~mask) | val);
+}
+
+static int xadc_update_adc_reg(struct xadc *xadc, unsigned int reg,
+ uint16_t mask, uint16_t val)
+{
+ int ret;
+
+ mutex_lock(&xadc->mutex);
+ ret = _xadc_update_adc_reg(xadc, reg, mask, val);
+ mutex_unlock(&xadc->mutex);
+
+ return ret;
+}
+
+static unsigned long xadc_get_dclk_rate(struct xadc *xadc)
+{
+ return xadc->ops->get_dclk_rate(xadc);
+}
+
+static int xadc_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *mask)
+{
+ struct xadc *xadc = iio_priv(indio_dev);
+ unsigned int n;
+
+ n = bitmap_weight(mask, indio_dev->masklength);
+
+ kfree(xadc->data);
+ xadc->data = kcalloc(n, sizeof(*xadc->data), GFP_KERNEL);
+ if (!xadc->data)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static unsigned int xadc_scan_index_to_channel(unsigned int scan_index)
+{
+ switch (scan_index) {
+ case 5:
+ return XADC_REG_VCCPINT;
+ case 6:
+ return XADC_REG_VCCPAUX;
+ case 7:
+ return XADC_REG_VCCO_DDR;
+ case 8:
+ return XADC_REG_TEMP;
+ case 9:
+ return XADC_REG_VCCINT;
+ case 10:
+ return XADC_REG_VCCAUX;
+ case 11:
+ return XADC_REG_VPVN;
+ case 12:
+ return XADC_REG_VREFP;
+ case 13:
+ return XADC_REG_VREFN;
+ case 14:
+ return XADC_REG_VCCBRAM;
+ default:
+ return XADC_REG_VAUX(scan_index - 16);
+ }
+}
+
+static irqreturn_t xadc_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct xadc *xadc = iio_priv(indio_dev);
+ unsigned int chan;
+ int i, j;
+
+ if (!xadc->data)
+ goto out;
+
+ j = 0;
+ for_each_set_bit(i, indio_dev->active_scan_mask,
+ indio_dev->masklength) {
+ chan = xadc_scan_index_to_channel(i);
+ xadc_read_adc_reg(xadc, chan, &xadc->data[j]);
+ j++;
+ }
+
+ iio_push_to_buffers(indio_dev, xadc->data);
+
+out:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int xadc_trigger_set_state(struct iio_trigger *trigger, bool state)
+{
+ struct xadc *xadc = iio_trigger_get_drvdata(trigger);
+ unsigned long flags;
+ unsigned int convst;
+ unsigned int val;
+ int ret = 0;
+
+ mutex_lock(&xadc->mutex);
+
+ if (state) {
+ /* Only one of the two triggers can be active at the a time. */
+ if (xadc->trigger != NULL) {
+ ret = -EBUSY;
+ goto err_out;
+ } else {
+ xadc->trigger = trigger;
+ if (trigger == xadc->convst_trigger)
+ convst = XADC_CONF0_EC;
+ else
+ convst = 0;
+ }
+ ret = _xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF0_EC,
+ convst);
+ if (ret)
+ goto err_out;
+ } else {
+ xadc->trigger = NULL;
+ }
+
+ spin_lock_irqsave(&xadc->lock, flags);
+ xadc_read_reg(xadc, XADC_AXI_REG_IPIER, &val);
+ xadc_write_reg(xadc, XADC_AXI_REG_IPISR, val & XADC_AXI_INT_EOS);
+ if (state)
+ val |= XADC_AXI_INT_EOS;
+ else
+ val &= ~XADC_AXI_INT_EOS;
+ xadc_write_reg(xadc, XADC_AXI_REG_IPIER, val);
+ spin_unlock_irqrestore(&xadc->lock, flags);
+
+err_out:
+ mutex_unlock(&xadc->mutex);
+
+ return ret;
+}
+
+static const struct iio_trigger_ops xadc_trigger_ops = {
+ .owner = THIS_MODULE,
+ .set_trigger_state = &xadc_trigger_set_state,
+};
+
+static struct iio_trigger *xadc_alloc_trigger(struct iio_dev *indio_dev,
+ const char *name)
+{
+ struct iio_trigger *trig;
+ int ret;
+
+ trig = iio_trigger_alloc("%s%d-%s", indio_dev->name,
+ indio_dev->id, name);
+ if (trig == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ trig->dev.parent = indio_dev->dev.parent;
+ trig->ops = &xadc_trigger_ops;
+ iio_trigger_set_drvdata(trig, iio_priv(indio_dev));
+
+ ret = iio_trigger_register(trig);
+ if (ret)
+ goto error_free_trig;
+
+ return trig;
+
+error_free_trig:
+ iio_trigger_free(trig);
+ return ERR_PTR(ret);
+}
+
+static int xadc_power_adc_b(struct xadc *xadc, unsigned int seq_mode)
+{
+ uint16_t val;
+
+ switch (seq_mode) {
+ case XADC_CONF1_SEQ_SIMULTANEOUS:
+ case XADC_CONF1_SEQ_INDEPENDENT:
+ val = XADC_CONF2_PD_ADC_B;
+ break;
+ default:
+ val = 0;
+ break;
+ }
+
+ return xadc_update_adc_reg(xadc, XADC_REG_CONF2, XADC_CONF2_PD_MASK,
+ val);
+}
+
+static int xadc_get_seq_mode(struct xadc *xadc, unsigned long scan_mode)
+{
+ unsigned int aux_scan_mode = scan_mode >> 16;
+
+ if (xadc->external_mux_mode == XADC_EXTERNAL_MUX_DUAL)
+ return XADC_CONF1_SEQ_SIMULTANEOUS;
+
+ if ((aux_scan_mode & 0xff00) == 0 ||
+ (aux_scan_mode & 0x00ff) == 0)
+ return XADC_CONF1_SEQ_CONTINUOUS;
+
+ return XADC_CONF1_SEQ_SIMULTANEOUS;
+}
+
+static int xadc_postdisable(struct iio_dev *indio_dev)
+{
+ struct xadc *xadc = iio_priv(indio_dev);
+ unsigned long scan_mask;
+ int ret;
+ int i;
+
+ scan_mask = 1; /* Run calibration as part of the sequence */
+ for (i = 0; i < indio_dev->num_channels; i++)
+ scan_mask |= BIT(indio_dev->channels[i].scan_index);
+
+ /* Enable all channels and calibration */
+ ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(0), scan_mask & 0xffff);
+ if (ret)
+ return ret;
+
+ ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(1), scan_mask >> 16);
+ if (ret)
+ return ret;
+
+ ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_SEQ_MASK,
+ XADC_CONF1_SEQ_CONTINUOUS);
+ if (ret)
+ return ret;
+
+ return xadc_power_adc_b(xadc, XADC_CONF1_SEQ_CONTINUOUS);
+}
+
+static int xadc_preenable(struct iio_dev *indio_dev)
+{
+ struct xadc *xadc = iio_priv(indio_dev);
+ unsigned long scan_mask;
+ int seq_mode;
+ int ret;
+
+ ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_SEQ_MASK,
+ XADC_CONF1_SEQ_DEFAULT);
+ if (ret)
+ goto err;
+
+ scan_mask = *indio_dev->active_scan_mask;
+ seq_mode = xadc_get_seq_mode(xadc, scan_mask);
+
+ ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(0), scan_mask & 0xffff);
+ if (ret)
+ goto err;
+
+ ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(1), scan_mask >> 16);
+ if (ret)
+ goto err;
+
+ ret = xadc_power_adc_b(xadc, seq_mode);
+ if (ret)
+ goto err;
+
+ ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_SEQ_MASK,
+ seq_mode);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ xadc_postdisable(indio_dev);
+ return ret;
+}
+
+static struct iio_buffer_setup_ops xadc_buffer_ops = {
+ .preenable = &xadc_preenable,
+ .postenable = &iio_triggered_buffer_postenable,
+ .predisable = &iio_triggered_buffer_predisable,
+ .postdisable = &xadc_postdisable,
+};
+
+static int xadc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val, int *val2, long info)
+{
+ struct xadc *xadc = iio_priv(indio_dev);
+ unsigned int div;
+ uint16_t val16;
+ int ret;
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ if (iio_buffer_enabled(indio_dev))
+ return -EBUSY;
+ ret = xadc_read_adc_reg(xadc, chan->address, &val16);
+ if (ret < 0)
+ return ret;
+
+ val16 >>= 4;
+ if (chan->scan_type.sign == 'u')
+ *val = val16;
+ else
+ *val = sign_extend32(val16, 11);
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ /* V = (val * 3.0) / 4096 */
+ switch (chan->address) {
+ case XADC_REG_VCCINT:
+ case XADC_REG_VCCAUX:
+ case XADC_REG_VCCBRAM:
+ case XADC_REG_VCCPINT:
+ case XADC_REG_VCCPAUX:
+ case XADC_REG_VCCO_DDR:
+ *val = 3000;
+ break;
+ default:
+ *val = 1000;
+ break;
+ }
+ *val2 = 12;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_TEMP:
+ /* Temp in C = (val * 503.975) / 4096 - 273.15 */
+ *val = 503975;
+ *val2 = 12;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_OFFSET:
+ /* Only the temperature channel has an offset */
+ *val = -((273150 << 12) / 503975);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = xadc_read_adc_reg(xadc, XADC_REG_CONF2, &val16);
+ if (ret)
+ return ret;
+
+ div = (val16 & XADC_CONF2_DIV_MASK) >> XADC_CONF2_DIV_OFFSET;
+ if (div < 2)
+ div = 2;
+
+ *val = xadc_get_dclk_rate(xadc) / div / 26;
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int xadc_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2, long info)
+{
+ struct xadc *xadc = iio_priv(indio_dev);
+ unsigned long clk_rate = xadc_get_dclk_rate(xadc);
+ unsigned int div;
+
+ if (info != IIO_CHAN_INFO_SAMP_FREQ)
+ return -EINVAL;
+
+ if (val <= 0)
+ return -EINVAL;
+
+ /* Max. 150 kSPS */
+ if (val > 150000)
+ val = 150000;
+
+ val *= 26;
+
+ /* Min 1MHz */
+ if (val < 1000000)
+ val = 1000000;
+
+ /*
+ * We want to round down, but only if we do not exceed the 150 kSPS
+ * limit.
+ */
+ div = clk_rate / val;
+ if (clk_rate / div / 26 > 150000)
+ div++;
+ if (div < 2)
+ div = 2;
+ else if (div > 0xff)
+ div = 0xff;
+
+ return xadc_update_adc_reg(xadc, XADC_REG_CONF2, XADC_CONF2_DIV_MASK,
+ div << XADC_CONF2_DIV_OFFSET);
+}
+
+static const struct iio_event_spec xadc_temp_events[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
+ BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_HYSTERESIS),
+ },
+};
+
+/* Separate values for upper and lower thresholds, but only a shared enabled */
+static const struct iio_event_spec xadc_voltage_events[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ }, {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ }, {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ },
+};
+
+#define XADC_CHAN_TEMP(_chan, _scan_index, _addr) { \
+ .type = IIO_TEMP, \
+ .indexed = 1, \
+ .channel = (_chan), \
+ .address = (_addr), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .event_spec = xadc_temp_events, \
+ .num_event_specs = ARRAY_SIZE(xadc_temp_events), \
+ .scan_index = (_scan_index), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ .shift = 4, \
+ .endianness = IIO_CPU, \
+ }, \
+}
+
+#define XADC_CHAN_VOLTAGE(_chan, _scan_index, _addr, _ext, _alarm) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = (_chan), \
+ .address = (_addr), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .event_spec = (_alarm) ? xadc_voltage_events : NULL, \
+ .num_event_specs = (_alarm) ? ARRAY_SIZE(xadc_voltage_events) : 0, \
+ .scan_index = (_scan_index), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ .shift = 4, \
+ .endianness = IIO_CPU, \
+ }, \
+ .extend_name = _ext, \
+}
+
+static const struct iio_chan_spec xadc_channels[] = {
+ XADC_CHAN_TEMP(0, 8, XADC_REG_TEMP),
+ XADC_CHAN_VOLTAGE(0, 9, XADC_REG_VCCINT, "vccint", true),
+ XADC_CHAN_VOLTAGE(1, 10, XADC_REG_VCCINT, "vccaux", true),
+ XADC_CHAN_VOLTAGE(2, 14, XADC_REG_VCCBRAM, "vccbram", true),
+ XADC_CHAN_VOLTAGE(3, 5, XADC_REG_VCCPINT, "vccpint", true),
+ XADC_CHAN_VOLTAGE(4, 6, XADC_REG_VCCPAUX, "vccpaux", true),
+ XADC_CHAN_VOLTAGE(5, 7, XADC_REG_VCCO_DDR, "vccoddr", true),
+ XADC_CHAN_VOLTAGE(6, 12, XADC_REG_VREFP, "vrefp", false),
+ XADC_CHAN_VOLTAGE(7, 13, XADC_REG_VREFN, "vrefn", false),
+ XADC_CHAN_VOLTAGE(8, 11, XADC_REG_VPVN, NULL, false),
+ XADC_CHAN_VOLTAGE(9, 16, XADC_REG_VAUX(0), NULL, false),
+ XADC_CHAN_VOLTAGE(10, 17, XADC_REG_VAUX(1), NULL, false),
+ XADC_CHAN_VOLTAGE(11, 18, XADC_REG_VAUX(2), NULL, false),
+ XADC_CHAN_VOLTAGE(12, 19, XADC_REG_VAUX(3), NULL, false),
+ XADC_CHAN_VOLTAGE(13, 20, XADC_REG_VAUX(4), NULL, false),
+ XADC_CHAN_VOLTAGE(14, 21, XADC_REG_VAUX(5), NULL, false),
+ XADC_CHAN_VOLTAGE(15, 22, XADC_REG_VAUX(6), NULL, false),
+ XADC_CHAN_VOLTAGE(16, 23, XADC_REG_VAUX(7), NULL, false),
+ XADC_CHAN_VOLTAGE(17, 24, XADC_REG_VAUX(8), NULL, false),
+ XADC_CHAN_VOLTAGE(18, 25, XADC_REG_VAUX(9), NULL, false),
+ XADC_CHAN_VOLTAGE(19, 26, XADC_REG_VAUX(10), NULL, false),
+ XADC_CHAN_VOLTAGE(20, 27, XADC_REG_VAUX(11), NULL, false),
+ XADC_CHAN_VOLTAGE(21, 28, XADC_REG_VAUX(12), NULL, false),
+ XADC_CHAN_VOLTAGE(22, 29, XADC_REG_VAUX(13), NULL, false),
+ XADC_CHAN_VOLTAGE(23, 30, XADC_REG_VAUX(14), NULL, false),
+ XADC_CHAN_VOLTAGE(24, 31, XADC_REG_VAUX(15), NULL, false),
+};
+
+static const struct iio_info xadc_info = {
+ .read_raw = &xadc_read_raw,
+ .write_raw = &xadc_write_raw,
+ .read_event_config = &xadc_read_event_config,
+ .write_event_config = &xadc_write_event_config,
+ .read_event_value = &xadc_read_event_value,
+ .write_event_value = &xadc_write_event_value,
+ .update_scan_mode = &xadc_update_scan_mode,
+ .driver_module = THIS_MODULE,
+};
+
+static const struct of_device_id xadc_of_match_table[] = {
+ { .compatible = "xlnx,zynq-xadc-1.00.a", (void *)&xadc_zynq_ops },
+ { .compatible = "xlnx,axi-xadc-1.00.a", (void *)&xadc_axi_ops },
+ { },
+};
+MODULE_DEVICE_TABLE(of, xadc_of_match_table);
+
+static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np,
+ unsigned int *conf)
+{
+ struct xadc *xadc = iio_priv(indio_dev);
+ struct iio_chan_spec *channels, *chan;
+ struct device_node *chan_node, *child;
+ unsigned int num_channels;
+ const char *external_mux;
+ u32 ext_mux_chan;
+ int reg;
+ int ret;
+
+ *conf = 0;
+
+ ret = of_property_read_string(np, "xlnx,external-mux", &external_mux);
+ if (ret < 0 || strcasecmp(external_mux, "none") == 0)
+ xadc->external_mux_mode = XADC_EXTERNAL_MUX_NONE;
+ else if (strcasecmp(external_mux, "single") == 0)
+ xadc->external_mux_mode = XADC_EXTERNAL_MUX_SINGLE;
+ else if (strcasecmp(external_mux, "dual") == 0)
+ xadc->external_mux_mode = XADC_EXTERNAL_MUX_DUAL;
+ else
+ return -EINVAL;
+
+ if (xadc->external_mux_mode != XADC_EXTERNAL_MUX_NONE) {
+ ret = of_property_read_u32(np, "xlnx,external-mux-channel",
+ &ext_mux_chan);
+ if (ret < 0)
+ return ret;
+
+ if (xadc->external_mux_mode == XADC_EXTERNAL_MUX_SINGLE) {
+ if (ext_mux_chan == 0)
+ ext_mux_chan = XADC_REG_VPVN;
+ else if (ext_mux_chan <= 16)
+ ext_mux_chan = XADC_REG_VAUX(ext_mux_chan - 1);
+ else
+ return -EINVAL;
+ } else {
+ if (ext_mux_chan > 0 && ext_mux_chan <= 8)
+ ext_mux_chan = XADC_REG_VAUX(ext_mux_chan - 1);
+ else
+ return -EINVAL;
+ }
+
+ *conf |= XADC_CONF0_MUX | XADC_CONF0_CHAN(ext_mux_chan);
+ }
+
+ channels = kmemdup(xadc_channels, sizeof(xadc_channels), GFP_KERNEL);
+ if (!channels)
+ return -ENOMEM;
+
+ num_channels = 9;
+ chan = &channels[9];
+
+ chan_node = of_get_child_by_name(np, "xlnx,channels");
+ if (chan_node) {
+ for_each_child_of_node(chan_node, child) {
+ if (num_channels >= ARRAY_SIZE(xadc_channels)) {
+ of_node_put(child);
+ break;
+ }
+
+ ret = of_property_read_u32(child, "reg", &reg);
+ if (ret || reg > 16)
+ continue;
+
+ if (of_property_read_bool(child, "xlnx,bipolar"))
+ chan->scan_type.sign = 's';
+
+ if (reg == 0) {
+ chan->scan_index = 11;
+ chan->address = XADC_REG_VPVN;
+ } else {
+ chan->scan_index = 15 + reg;
+ chan->scan_index = XADC_REG_VAUX(reg - 1);
+ }
+ num_channels++;
+ chan++;
+ }
+ }
+ of_node_put(chan_node);
+
+ indio_dev->num_channels = num_channels;
+ indio_dev->channels = krealloc(channels, sizeof(*channels) *
+ num_channels, GFP_KERNEL);
+ /* If we can't resize the channels array, just use the original */
+ if (!indio_dev->channels)
+ indio_dev->channels = channels;
+
+ return 0;
+}
+
+static int xadc_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *id;
+ struct iio_dev *indio_dev;
+ unsigned int bipolar_mask;
+ struct resource *mem;
+ unsigned int conf0;
+ struct xadc *xadc;
+ int ret;
+ int irq;
+ int i;
+
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ id = of_match_node(xadc_of_match_table, pdev->dev.of_node);
+ if (!id)
+ return -EINVAL;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0)
+ return -ENXIO;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*xadc));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ xadc = iio_priv(indio_dev);
+ xadc->ops = id->data;
+ init_completion(&xadc->completion);
+ mutex_init(&xadc->mutex);
+ spin_lock_init(&xadc->lock);
+ INIT_DELAYED_WORK(&xadc->zynq_unmask_work, xadc_zynq_unmask_worker);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ xadc->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(xadc->base))
+ return PTR_ERR(xadc->base);
+
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->dev.of_node = pdev->dev.of_node;
+ indio_dev->name = "xadc";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &xadc_info;
+
+ ret = xadc_parse_dt(indio_dev, pdev->dev.of_node, &conf0);
+ if (ret)
+ goto err_device_free;
+
+ if (xadc->ops->flags & XADC_FLAGS_BUFFERED) {
+ ret = iio_triggered_buffer_setup(indio_dev,
+ &iio_pollfunc_store_time, &xadc_trigger_handler,
+ &xadc_buffer_ops);
+ if (ret)
+ goto err_device_free;
+
+ xadc->convst_trigger = xadc_alloc_trigger(indio_dev, "convst");
+ if (IS_ERR(xadc->convst_trigger))
+ goto err_triggered_buffer_cleanup;
+ xadc->samplerate_trigger = xadc_alloc_trigger(indio_dev,
+ "samplerate");
+ if (IS_ERR(xadc->samplerate_trigger))
+ goto err_free_convst_trigger;
+ }
+
+ xadc->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(xadc->clk)) {
+ ret = PTR_ERR(xadc->clk);
+ goto err_free_samplerate_trigger;
+ }
+ clk_prepare_enable(xadc->clk);
+
+ ret = xadc->ops->setup(pdev, indio_dev, irq);
+ if (ret)
+ goto err_free_samplerate_trigger;
+
+ ret = request_threaded_irq(irq, xadc->ops->interrupt_handler,
+ xadc->ops->threaded_interrupt_handler,
+ 0, dev_name(&pdev->dev), indio_dev);
+ if (ret)
+ goto err_clk_disable_unprepare;
+
+ for (i = 0; i < 16; i++)
+ xadc_read_adc_reg(xadc, XADC_REG_THRESHOLD(i),
+ &xadc->threshold[i]);
+
+ ret = xadc_write_adc_reg(xadc, XADC_REG_CONF0, conf0);
+ if (ret)
+ goto err_free_irq;
+
+ bipolar_mask = 0;
+ for (i = 0; i < indio_dev->num_channels; i++) {
+ if (indio_dev->channels[i].scan_type.sign == 's')
+ bipolar_mask |= BIT(indio_dev->channels[i].scan_index);
+ }
+
+ ret = xadc_write_adc_reg(xadc, XADC_REG_INPUT_MODE(0), bipolar_mask);
+ if (ret)
+ goto err_free_irq;
+ ret = xadc_write_adc_reg(xadc, XADC_REG_INPUT_MODE(1),
+ bipolar_mask >> 16);
+ if (ret)
+ goto err_free_irq;
+
+ /* Disable all alarms */
+ xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_ALARM_MASK,
+ XADC_CONF1_ALARM_MASK);
+
+ /* Set thresholds to min/max */
+ for (i = 0; i < 16; i++) {
+ /*
+ * Set max voltage threshold and both temperature thresholds to
+ * 0xffff, min voltage threshold to 0.
+ */
+ if (i % 8 < 4 || i == 7)
+ xadc->threshold[i] = 0xffff;
+ else
+ xadc->threshold[i] = 0;
+ xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(i),
+ xadc->threshold[i]);
+ }
+
+ /* Go to non-buffered mode */
+ xadc_postdisable(indio_dev);
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto err_free_irq;
+
+ platform_set_drvdata(pdev, indio_dev);
+
+ return 0;
+
+err_free_irq:
+ free_irq(irq, indio_dev);
+err_free_samplerate_trigger:
+ if (xadc->ops->flags & XADC_FLAGS_BUFFERED)
+ iio_trigger_free(xadc->samplerate_trigger);
+err_free_convst_trigger:
+ if (xadc->ops->flags & XADC_FLAGS_BUFFERED)
+ iio_trigger_free(xadc->convst_trigger);
+err_triggered_buffer_cleanup:
+ if (xadc->ops->flags & XADC_FLAGS_BUFFERED)
+ iio_triggered_buffer_cleanup(indio_dev);
+err_clk_disable_unprepare:
+ clk_disable_unprepare(xadc->clk);
+err_device_free:
+ kfree(indio_dev->channels);
+
+ return ret;
+}
+
+static int xadc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct xadc *xadc = iio_priv(indio_dev);
+ int irq = platform_get_irq(pdev, 0);
+
+ iio_device_unregister(indio_dev);
+ if (xadc->ops->flags & XADC_FLAGS_BUFFERED) {
+ iio_trigger_free(xadc->samplerate_trigger);
+ iio_trigger_free(xadc->convst_trigger);
+ iio_triggered_buffer_cleanup(indio_dev);
+ }
+ free_irq(irq, indio_dev);
+ clk_disable_unprepare(xadc->clk);
+ cancel_delayed_work(&xadc->zynq_unmask_work);
+ kfree(xadc->data);
+ kfree(indio_dev->channels);
+
+ return 0;
+}
+
+static struct platform_driver xadc_driver = {
+ .probe = xadc_probe,
+ .remove = xadc_remove,
+ .driver = {
+ .name = "xadc",
+ .owner = THIS_MODULE,
+ .of_match_table = xadc_of_match_table,
+ },
+};
+module_platform_driver(xadc_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Xilinx XADC IIO driver");
diff --git a/drivers/iio/adc/xilinx-xadc-events.c b/drivers/iio/adc/xilinx-xadc-events.c
new file mode 100644
index 000000000000..3e7f0d7a80c3
--- /dev/null
+++ b/drivers/iio/adc/xilinx-xadc-events.c
@@ -0,0 +1,254 @@
+/*
+ * Xilinx XADC driver
+ *
+ * Copyright 2013 Analog Devices Inc.
+ * Author: Lars-Peter Clauen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.h>
+
+#include "xilinx-xadc.h"
+
+static const struct iio_chan_spec *xadc_event_to_channel(
+ struct iio_dev *indio_dev, unsigned int event)
+{
+ switch (event) {
+ case XADC_THRESHOLD_OT_MAX:
+ case XADC_THRESHOLD_TEMP_MAX:
+ return &indio_dev->channels[0];
+ case XADC_THRESHOLD_VCCINT_MAX:
+ case XADC_THRESHOLD_VCCAUX_MAX:
+ return &indio_dev->channels[event];
+ default:
+ return &indio_dev->channels[event-1];
+ }
+}
+
+static void xadc_handle_event(struct iio_dev *indio_dev, unsigned int event)
+{
+ const struct iio_chan_spec *chan;
+ unsigned int offset;
+
+ /* Temperature threshold error, we don't handle this yet */
+ if (event == 0)
+ return;
+
+ if (event < 4)
+ offset = event;
+ else
+ offset = event + 4;
+
+ chan = xadc_event_to_channel(indio_dev, event);
+
+ if (chan->type == IIO_TEMP) {
+ /*
+ * The temperature channel only supports over-temperature
+ * events.
+ */
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
+ IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING),
+ iio_get_time_ns());
+ } else {
+ /*
+ * For other channels we don't know whether it is a upper or
+ * lower threshold event. Userspace will have to check the
+ * channel value if it wants to know.
+ */
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
+ IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER),
+ iio_get_time_ns());
+ }
+}
+
+void xadc_handle_events(struct iio_dev *indio_dev, unsigned long events)
+{
+ unsigned int i;
+
+ for_each_set_bit(i, &events, 8)
+ xadc_handle_event(indio_dev, i);
+}
+
+static unsigned xadc_get_threshold_offset(const struct iio_chan_spec *chan,
+ enum iio_event_direction dir)
+{
+ unsigned int offset;
+
+ if (chan->type == IIO_TEMP) {
+ offset = XADC_THRESHOLD_OT_MAX;
+ } else {
+ if (chan->channel < 2)
+ offset = chan->channel + 1;
+ else
+ offset = chan->channel + 6;
+ }
+
+ if (dir == IIO_EV_DIR_FALLING)
+ offset += 4;
+
+ return offset;
+}
+
+static unsigned int xadc_get_alarm_mask(const struct iio_chan_spec *chan)
+{
+ if (chan->type == IIO_TEMP) {
+ return XADC_ALARM_OT_MASK;
+ } else {
+ switch (chan->channel) {
+ case 0:
+ return XADC_ALARM_VCCINT_MASK;
+ case 1:
+ return XADC_ALARM_VCCAUX_MASK;
+ case 2:
+ return XADC_ALARM_VCCBRAM_MASK;
+ case 3:
+ return XADC_ALARM_VCCPINT_MASK;
+ case 4:
+ return XADC_ALARM_VCCPAUX_MASK;
+ case 5:
+ return XADC_ALARM_VCCODDR_MASK;
+ default:
+ /* We will never get here */
+ return 0;
+ }
+ }
+}
+
+int xadc_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct xadc *xadc = iio_priv(indio_dev);
+
+ return (bool)(xadc->alarm_mask & xadc_get_alarm_mask(chan));
+}
+
+int xadc_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir, int state)
+{
+ unsigned int alarm = xadc_get_alarm_mask(chan);
+ struct xadc *xadc = iio_priv(indio_dev);
+ uint16_t cfg, old_cfg;
+ int ret;
+
+ mutex_lock(&xadc->mutex);
+
+ if (state)
+ xadc->alarm_mask |= alarm;
+ else
+ xadc->alarm_mask &= ~alarm;
+
+ xadc->ops->update_alarm(xadc, xadc->alarm_mask);
+
+ ret = _xadc_read_adc_reg(xadc, XADC_REG_CONF1, &cfg);
+ if (ret)
+ goto err_out;
+
+ old_cfg = cfg;
+ cfg |= XADC_CONF1_ALARM_MASK;
+ cfg &= ~((xadc->alarm_mask & 0xf0) << 4); /* bram, pint, paux, ddr */
+ cfg &= ~((xadc->alarm_mask & 0x08) >> 3); /* ot */
+ cfg &= ~((xadc->alarm_mask & 0x07) << 1); /* temp, vccint, vccaux */
+ if (old_cfg != cfg)
+ ret = _xadc_write_adc_reg(xadc, XADC_REG_CONF1, cfg);
+
+err_out:
+ mutex_unlock(&xadc->mutex);
+
+ return ret;
+}
+
+/* Register value is msb aligned, the lower 4 bits are ignored */
+#define XADC_THRESHOLD_VALUE_SHIFT 4
+
+int xadc_read_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir, enum iio_event_info info,
+ int *val, int *val2)
+{
+ unsigned int offset = xadc_get_threshold_offset(chan, dir);
+ struct xadc *xadc = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ *val = xadc->threshold[offset];
+ break;
+ case IIO_EV_INFO_HYSTERESIS:
+ *val = xadc->temp_hysteresis;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *val >>= XADC_THRESHOLD_VALUE_SHIFT;
+
+ return IIO_VAL_INT;
+}
+
+int xadc_write_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir, enum iio_event_info info,
+ int val, int val2)
+{
+ unsigned int offset = xadc_get_threshold_offset(chan, dir);
+ struct xadc *xadc = iio_priv(indio_dev);
+ int ret = 0;
+
+ val <<= XADC_THRESHOLD_VALUE_SHIFT;
+
+ if (val < 0 || val > 0xffff)
+ return -EINVAL;
+
+ mutex_lock(&xadc->mutex);
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ xadc->threshold[offset] = val;
+ break;
+ case IIO_EV_INFO_HYSTERESIS:
+ xadc->temp_hysteresis = val;
+ break;
+ default:
+ mutex_unlock(&xadc->mutex);
+ return -EINVAL;
+ }
+
+ if (chan->type == IIO_TEMP) {
+ /*
+ * According to the datasheet we need to set the lower 4 bits to
+ * 0x3, otherwise 125 degree celsius will be used as the
+ * threshold.
+ */
+ val |= 0x3;
+
+ /*
+ * Since we store the hysteresis as relative (to the threshold)
+ * value, but the hardware expects an absolute value we need to
+ * recalcualte this value whenever the hysteresis or the
+ * threshold changes.
+ */
+ if (xadc->threshold[offset] < xadc->temp_hysteresis)
+ xadc->threshold[offset + 4] = 0;
+ else
+ xadc->threshold[offset + 4] = xadc->threshold[offset] -
+ xadc->temp_hysteresis;
+ ret = _xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(offset + 4),
+ xadc->threshold[offset + 4]);
+ if (ret)
+ goto out_unlock;
+ }
+
+ if (info == IIO_EV_INFO_VALUE)
+ ret = _xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(offset), val);
+
+out_unlock:
+ mutex_unlock(&xadc->mutex);
+
+ return ret;
+}
diff --git a/drivers/iio/adc/xilinx-xadc.h b/drivers/iio/adc/xilinx-xadc.h
new file mode 100644
index 000000000000..c7487e8d7f80
--- /dev/null
+++ b/drivers/iio/adc/xilinx-xadc.h
@@ -0,0 +1,209 @@
+/*
+ * Xilinx XADC driver
+ *
+ * Copyright 2013 Analog Devices Inc.
+ * Author: Lars-Peter Clauen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __IIO_XILINX_XADC__
+#define __IIO_XILINX_XADC__
+
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
+struct iio_dev;
+struct clk;
+struct xadc_ops;
+struct platform_device;
+
+void xadc_handle_events(struct iio_dev *indio_dev, unsigned long events);
+
+int xadc_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir);
+int xadc_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir, int state);
+int xadc_read_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir, enum iio_event_info info,
+ int *val, int *val2);
+int xadc_write_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir, enum iio_event_info info,
+ int val, int val2);
+
+enum xadc_external_mux_mode {
+ XADC_EXTERNAL_MUX_NONE,
+ XADC_EXTERNAL_MUX_SINGLE,
+ XADC_EXTERNAL_MUX_DUAL,
+};
+
+struct xadc {
+ void __iomem *base;
+ struct clk *clk;
+
+ const struct xadc_ops *ops;
+
+ uint16_t threshold[16];
+ uint16_t temp_hysteresis;
+ unsigned int alarm_mask;
+
+ uint16_t *data;
+
+ struct iio_trigger *trigger;
+ struct iio_trigger *convst_trigger;
+ struct iio_trigger *samplerate_trigger;
+
+ enum xadc_external_mux_mode external_mux_mode;
+
+ unsigned int zynq_alarm;
+ unsigned int zynq_masked_alarm;
+ unsigned int zynq_intmask;
+ struct delayed_work zynq_unmask_work;
+
+ struct mutex mutex;
+ spinlock_t lock;
+
+ struct completion completion;
+};
+
+struct xadc_ops {
+ int (*read)(struct xadc *, unsigned int, uint16_t *);
+ int (*write)(struct xadc *, unsigned int, uint16_t);
+ int (*setup)(struct platform_device *pdev, struct iio_dev *indio_dev,
+ int irq);
+ void (*update_alarm)(struct xadc *, unsigned int);
+ unsigned long (*get_dclk_rate)(struct xadc *);
+ irqreturn_t (*interrupt_handler)(int, void *);
+ irqreturn_t (*threaded_interrupt_handler)(int, void *);
+
+ unsigned int flags;
+};
+
+static inline int _xadc_read_adc_reg(struct xadc *xadc, unsigned int reg,
+ uint16_t *val)
+{
+ lockdep_assert_held(&xadc->mutex);
+ return xadc->ops->read(xadc, reg, val);
+}
+
+static inline int _xadc_write_adc_reg(struct xadc *xadc, unsigned int reg,
+ uint16_t val)
+{
+ lockdep_assert_held(&xadc->mutex);
+ return xadc->ops->write(xadc, reg, val);
+}
+
+static inline int xadc_read_adc_reg(struct xadc *xadc, unsigned int reg,
+ uint16_t *val)
+{
+ int ret;
+
+ mutex_lock(&xadc->mutex);
+ ret = _xadc_read_adc_reg(xadc, reg, val);
+ mutex_unlock(&xadc->mutex);
+ return ret;
+}
+
+static inline int xadc_write_adc_reg(struct xadc *xadc, unsigned int reg,
+ uint16_t val)
+{
+ int ret;
+
+ mutex_lock(&xadc->mutex);
+ ret = _xadc_write_adc_reg(xadc, reg, val);
+ mutex_unlock(&xadc->mutex);
+ return ret;
+}
+
+/* XADC hardmacro register definitions */
+#define XADC_REG_TEMP 0x00
+#define XADC_REG_VCCINT 0x01
+#define XADC_REG_VCCAUX 0x02
+#define XADC_REG_VPVN 0x03
+#define XADC_REG_VREFP 0x04
+#define XADC_REG_VREFN 0x05
+#define XADC_REG_VCCBRAM 0x06
+
+#define XADC_REG_VCCPINT 0x0d
+#define XADC_REG_VCCPAUX 0x0e
+#define XADC_REG_VCCO_DDR 0x0f
+#define XADC_REG_VAUX(x) (0x10 + (x))
+
+#define XADC_REG_MAX_TEMP 0x20
+#define XADC_REG_MAX_VCCINT 0x21
+#define XADC_REG_MAX_VCCAUX 0x22
+#define XADC_REG_MAX_VCCBRAM 0x23
+#define XADC_REG_MIN_TEMP 0x24
+#define XADC_REG_MIN_VCCINT 0x25
+#define XADC_REG_MIN_VCCAUX 0x26
+#define XADC_REG_MIN_VCCBRAM 0x27
+#define XADC_REG_MAX_VCCPINT 0x28
+#define XADC_REG_MAX_VCCPAUX 0x29
+#define XADC_REG_MAX_VCCO_DDR 0x2a
+#define XADC_REG_MIN_VCCPINT 0x2b
+#define XADC_REG_MIN_VCCPAUX 0x2c
+#define XADC_REG_MIN_VCCO_DDR 0x2d
+
+#define XADC_REG_CONF0 0x40
+#define XADC_REG_CONF1 0x41
+#define XADC_REG_CONF2 0x42
+#define XADC_REG_SEQ(x) (0x48 + (x))
+#define XADC_REG_INPUT_MODE(x) (0x4c + (x))
+#define XADC_REG_THRESHOLD(x) (0x50 + (x))
+
+#define XADC_REG_FLAG 0x3f
+
+#define XADC_CONF0_EC BIT(9)
+#define XADC_CONF0_ACQ BIT(8)
+#define XADC_CONF0_MUX BIT(11)
+#define XADC_CONF0_CHAN(x) (x)
+
+#define XADC_CONF1_SEQ_MASK (0xf << 12)
+#define XADC_CONF1_SEQ_DEFAULT (0 << 12)
+#define XADC_CONF1_SEQ_SINGLE_PASS (1 << 12)
+#define XADC_CONF1_SEQ_CONTINUOUS (2 << 12)
+#define XADC_CONF1_SEQ_SINGLE_CHANNEL (3 << 12)
+#define XADC_CONF1_SEQ_SIMULTANEOUS (4 << 12)
+#define XADC_CONF1_SEQ_INDEPENDENT (8 << 12)
+#define XADC_CONF1_ALARM_MASK 0x0f0f
+
+#define XADC_CONF2_DIV_MASK 0xff00
+#define XADC_CONF2_DIV_OFFSET 8
+
+#define XADC_CONF2_PD_MASK (0x3 << 4)
+#define XADC_CONF2_PD_NONE (0x0 << 4)
+#define XADC_CONF2_PD_ADC_B (0x2 << 4)
+#define XADC_CONF2_PD_BOTH (0x3 << 4)
+
+#define XADC_ALARM_TEMP_MASK BIT(0)
+#define XADC_ALARM_VCCINT_MASK BIT(1)
+#define XADC_ALARM_VCCAUX_MASK BIT(2)
+#define XADC_ALARM_OT_MASK BIT(3)
+#define XADC_ALARM_VCCBRAM_MASK BIT(4)
+#define XADC_ALARM_VCCPINT_MASK BIT(5)
+#define XADC_ALARM_VCCPAUX_MASK BIT(6)
+#define XADC_ALARM_VCCODDR_MASK BIT(7)
+
+#define XADC_THRESHOLD_TEMP_MAX 0x0
+#define XADC_THRESHOLD_VCCINT_MAX 0x1
+#define XADC_THRESHOLD_VCCAUX_MAX 0x2
+#define XADC_THRESHOLD_OT_MAX 0x3
+#define XADC_THRESHOLD_TEMP_MIN 0x4
+#define XADC_THRESHOLD_VCCINT_MIN 0x5
+#define XADC_THRESHOLD_VCCAUX_MIN 0x6
+#define XADC_THRESHOLD_OT_MIN 0x7
+#define XADC_THRESHOLD_VCCBRAM_MAX 0x8
+#define XADC_THRESHOLD_VCCPINT_MAX 0x9
+#define XADC_THRESHOLD_VCCPAUX_MAX 0xa
+#define XADC_THRESHOLD_VCCODDR_MAX 0xb
+#define XADC_THRESHOLD_VCCBRAM_MIN 0xc
+#define XADC_THRESHOLD_VCCPINT_MIN 0xd
+#define XADC_THRESHOLD_VCCPAUX_MIN 0xe
+#define XADC_THRESHOLD_VCCODDR_MIN 0xf
+
+#endif
diff --git a/drivers/iio/buffer_cb.c b/drivers/iio/buffer_cb.c
index 2d9c6f8c06db..eb46e728aa2e 100644
--- a/drivers/iio/buffer_cb.c
+++ b/drivers/iio/buffer_cb.c
@@ -46,10 +46,8 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
struct iio_channel *chan;
cb_buff = kzalloc(sizeof(*cb_buff), GFP_KERNEL);
- if (cb_buff == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ if (cb_buff == NULL)
+ return ERR_PTR(-ENOMEM);
iio_buffer_init(&cb_buff->buffer);
@@ -91,7 +89,6 @@ error_release_channels:
iio_channel_release_all(cb_buff->channels);
error_free_cb_buff:
kfree(cb_buff);
-error_ret:
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(iio_channel_get_all_cb);
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index 7dcf83998e6f..dbefbdaf7cd1 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -38,29 +38,40 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
if (state) {
if (sensor_hub_device_open(st->hsdev))
return -EIO;
- state_val =
- HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM;
- report_val =
- HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM;
-
+ state_val = hid_sensor_get_usage_index(st->hsdev,
+ st->power_state.report_id,
+ st->power_state.index,
+ HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM);
+ report_val = hid_sensor_get_usage_index(st->hsdev,
+ st->report_state.report_id,
+ st->report_state.index,
+ HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM);
} else {
sensor_hub_device_close(st->hsdev);
- state_val =
- HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM;
- report_val =
- HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM;
+ state_val = hid_sensor_get_usage_index(st->hsdev,
+ st->power_state.report_id,
+ st->power_state.index,
+ HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM);
+ report_val = hid_sensor_get_usage_index(st->hsdev,
+ st->report_state.report_id,
+ st->report_state.index,
+ HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM);
}
-
st->data_ready = state;
- state_val += st->power_state.logical_minimum;
- report_val += st->report_state.logical_minimum;
- sensor_hub_set_feature(st->hsdev, st->power_state.report_id,
+
+ if (state_val >= 0) {
+ state_val += st->power_state.logical_minimum;
+ sensor_hub_set_feature(st->hsdev, st->power_state.report_id,
st->power_state.index,
(s32)state_val);
+ }
- sensor_hub_set_feature(st->hsdev, st->report_state.report_id,
+ if (report_val >= 0) {
+ report_val += st->report_state.logical_minimum;
+ sensor_hub_set_feature(st->hsdev, st->report_state.report_id,
st->report_state.index,
(s32)report_val);
+ }
return 0;
}
diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c
index d0505fd22ef4..fa2810032968 100644
--- a/drivers/iio/dac/ad7303.c
+++ b/drivers/iio/dac/ad7303.c
@@ -92,7 +92,7 @@ static ssize_t ad7303_write_dac_powerdown(struct iio_dev *indio_dev,
ad7303_write(st, chan->channel, st->dac_cache[chan->channel]);
mutex_unlock(&indio_dev->mlock);
- return ret ? ret : len;
+ return len;
}
static int ad7303_get_vref(struct ad7303_state *st,
diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c
index de76e6a34c1e..9a82a7255ebb 100644
--- a/drivers/iio/dac/max517.c
+++ b/drivers/iio/dac/max517.c
@@ -19,7 +19,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c
index 7d9f5c31d2fc..43d14588448d 100644
--- a/drivers/iio/dac/mcp4725.c
+++ b/drivers/iio/dac/mcp4725.c
@@ -15,7 +15,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/delay.h>
diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig
index 41c64a43bcab..ac2d69e34c8c 100644
--- a/drivers/iio/gyro/Kconfig
+++ b/drivers/iio/gyro/Kconfig
@@ -70,7 +70,7 @@ config IIO_ST_GYRO_3AXIS
select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
help
Say yes here to build support for STMicroelectronics gyroscopes:
- L3G4200D, LSM330DL, L3GD20, L3GD20H, LSM330DLC, L3G4IS, LSM330.
+ L3G4200D, LSM330DL, L3GD20, LSM330DLC, L3G4IS, LSM330.
This driver can also be built as a module. If so, these modules
will be created:
diff --git a/drivers/iio/gyro/st_gyro.h b/drivers/iio/gyro/st_gyro.h
index f8f2bf84a5a2..c197360c450b 100644
--- a/drivers/iio/gyro/st_gyro.h
+++ b/drivers/iio/gyro/st_gyro.h
@@ -19,7 +19,6 @@
#define LSM330DL_GYRO_DEV_NAME "lsm330dl_gyro"
#define LSM330DLC_GYRO_DEV_NAME "lsm330dlc_gyro"
#define L3GD20_GYRO_DEV_NAME "l3gd20"
-#define L3GD20H_GYRO_DEV_NAME "l3gd20h"
#define L3G4IS_GYRO_DEV_NAME "l3g4is_ui"
#define LSM330_GYRO_DEV_NAME "lsm330_gyro"
diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c
index d53d91adfb55..a8e174a47bc4 100644
--- a/drivers/iio/gyro/st_gyro_core.c
+++ b/drivers/iio/gyro/st_gyro_core.c
@@ -167,11 +167,10 @@ static const struct st_sensors st_gyro_sensors[] = {
.wai = ST_GYRO_2_WAI_EXP,
.sensors_supported = {
[0] = L3GD20_GYRO_DEV_NAME,
- [1] = L3GD20H_GYRO_DEV_NAME,
- [2] = LSM330D_GYRO_DEV_NAME,
- [3] = LSM330DLC_GYRO_DEV_NAME,
- [4] = L3G4IS_GYRO_DEV_NAME,
- [5] = LSM330_GYRO_DEV_NAME,
+ [1] = LSM330D_GYRO_DEV_NAME,
+ [2] = LSM330DLC_GYRO_DEV_NAME,
+ [3] = L3G4IS_GYRO_DEV_NAME,
+ [4] = LSM330_GYRO_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_gyro_16bit_channels,
.odr = {
diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c
index 16b8b8d70bf1..23c12f361b05 100644
--- a/drivers/iio/gyro/st_gyro_i2c.c
+++ b/drivers/iio/gyro/st_gyro_i2c.c
@@ -55,7 +55,6 @@ static const struct i2c_device_id st_gyro_id_table[] = {
{ LSM330DL_GYRO_DEV_NAME },
{ LSM330DLC_GYRO_DEV_NAME },
{ L3GD20_GYRO_DEV_NAME },
- { L3GD20H_GYRO_DEV_NAME },
{ L3G4IS_GYRO_DEV_NAME },
{ LSM330_GYRO_DEV_NAME },
{},
diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c
index 94763e25caf9..b4ad3be26687 100644
--- a/drivers/iio/gyro/st_gyro_spi.c
+++ b/drivers/iio/gyro/st_gyro_spi.c
@@ -54,7 +54,6 @@ static const struct spi_device_id st_gyro_id_table[] = {
{ LSM330DL_GYRO_DEV_NAME },
{ LSM330DLC_GYRO_DEV_NAME },
{ L3GD20_GYRO_DEV_NAME },
- { L3GD20H_GYRO_DEV_NAME },
{ L3G4IS_GYRO_DEV_NAME },
{ LSM330_GYRO_DEV_NAME },
{},
diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig
index 463c4d9da79e..e116bd8dd0e4 100644
--- a/drivers/iio/humidity/Kconfig
+++ b/drivers/iio/humidity/Kconfig
@@ -12,4 +12,14 @@ config DHT11
Other sensors should work as well as long as they speak the
same protocol.
+config SI7005
+ tristate "SI7005 relative humidity and temperature sensor"
+ depends on I2C
+ help
+ Say yes here to build support for the Silabs Si7005 relative
+ humidity and temperature sensor.
+
+ To compile this driver as a module, choose M here: the module
+ will be called si7005.
+
endmenu
diff --git a/drivers/iio/humidity/Makefile b/drivers/iio/humidity/Makefile
index d5d36c0c95f9..e3f3d942e646 100644
--- a/drivers/iio/humidity/Makefile
+++ b/drivers/iio/humidity/Makefile
@@ -3,3 +3,4 @@
#
obj-$(CONFIG_DHT11) += dht11.o
+obj-$(CONFIG_SI7005) += si7005.o
diff --git a/drivers/iio/humidity/si7005.c b/drivers/iio/humidity/si7005.c
new file mode 100644
index 000000000000..bdd586e6d955
--- /dev/null
+++ b/drivers/iio/humidity/si7005.c
@@ -0,0 +1,189 @@
+/*
+ * si7005.c - Support for Silabs Si7005 humidity and temperature sensor
+ *
+ * Copyright (c) 2014 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.
+ *
+ * (7-bit I2C slave address 0x40)
+ *
+ * TODO: heater, fast mode, processed mode (temp. / linearity compensation)
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define SI7005_STATUS 0x00
+#define SI7005_DATA 0x01 /* 16-bit, MSB */
+#define SI7005_CONFIG 0x03
+#define SI7005_ID 0x11
+
+#define SI7005_STATUS_NRDY BIT(0)
+#define SI7005_CONFIG_TEMP BIT(4)
+#define SI7005_CONFIG_START BIT(0)
+
+#define SI7005_ID_7005 0x50
+#define SI7005_ID_7015 0xf0
+
+struct si7005_data {
+ struct i2c_client *client;
+ struct mutex lock;
+ u8 config;
+};
+
+static int si7005_read_measurement(struct si7005_data *data, bool temp)
+{
+ int tries = 50;
+ int ret;
+
+ mutex_lock(&data->lock);
+
+ ret = i2c_smbus_write_byte_data(data->client, SI7005_CONFIG,
+ data->config | SI7005_CONFIG_START |
+ (temp ? SI7005_CONFIG_TEMP : 0));
+ if (ret < 0)
+ goto done;
+
+ while (tries-- > 0) {
+ msleep(20);
+ ret = i2c_smbus_read_byte_data(data->client, SI7005_STATUS);
+ if (ret < 0)
+ goto done;
+ if (!(ret & SI7005_STATUS_NRDY))
+ break;
+ }
+ if (tries < 0) {
+ ret = -EIO;
+ goto done;
+ }
+
+ ret = i2c_smbus_read_word_swapped(data->client, SI7005_DATA);
+
+done:
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+static int si7005_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct si7005_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = si7005_read_measurement(data, chan->type == IIO_TEMP);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->type == IIO_TEMP) {
+ *val = 7;
+ *val2 = 812500;
+ } else {
+ *val = 3;
+ *val2 = 906250;
+ }
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_OFFSET:
+ if (chan->type == IIO_TEMP)
+ *val = -50 * 32 * 4;
+ else
+ *val = -24 * 16 * 16;
+ return IIO_VAL_INT;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static const struct iio_chan_spec si7005_channels[] = {
+ {
+ .type = IIO_HUMIDITYRELATIVE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
+ },
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
+ }
+};
+
+static const struct iio_info si7005_info = {
+ .read_raw = si7005_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static int si7005_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct iio_dev *indio_dev;
+ struct si7005_data *data;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
+ 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;
+ mutex_init(&data->lock);
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->name = dev_name(&client->dev);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &si7005_info;
+
+ indio_dev->channels = si7005_channels;
+ indio_dev->num_channels = ARRAY_SIZE(si7005_channels);
+
+ ret = i2c_smbus_read_byte_data(client, SI7005_ID);
+ if (ret < 0)
+ return ret;
+ if (ret != SI7005_ID_7005 && ret != SI7005_ID_7015)
+ return -ENODEV;
+
+ ret = i2c_smbus_read_byte_data(client, SI7005_CONFIG);
+ if (ret < 0)
+ return ret;
+ data->config = ret;
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id si7005_id[] = {
+ { "si7005", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, si7005_id);
+
+static struct i2c_driver si7005_driver = {
+ .driver = {
+ .name = "si7005",
+ .owner = THIS_MODULE,
+ },
+ .probe = si7005_probe,
+ .id_table = si7005_id,
+};
+module_i2c_driver(si7005_driver);
+
+MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
+MODULE_DESCRIPTION("Silabs Si7005 humidity and temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 663e88a1a3c1..2b0e45133e9d 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -25,6 +25,8 @@ config ADIS16480
Say yes here to build support for Analog Devices ADIS16375, ADIS16480,
ADIS16485, ADIS16488 inertial sensors.
+source "drivers/iio/imu/inv_mpu6050/Kconfig"
+
endmenu
config IIO_ADIS_LIB
@@ -38,5 +40,3 @@ config IIO_ADIS_LIB_BUFFER
help
A set of buffer helper functions for the Analog Devices ADIS* device
family.
-
-source "drivers/iio/imu/inv_mpu6050/Kconfig"
diff --git a/drivers/iio/imu/adis16400.h b/drivers/iio/imu/adis16400.h
index 2f8f9d632386..0916bf6b6c31 100644
--- a/drivers/iio/imu/adis16400.h
+++ b/drivers/iio/imu/adis16400.h
@@ -189,6 +189,7 @@ enum {
ADIS16300_SCAN_INCLI_X,
ADIS16300_SCAN_INCLI_Y,
ADIS16400_SCAN_ADC,
+ ADIS16400_SCAN_TIMESTAMP,
};
#ifdef CONFIG_IIO_BUFFER
diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c
index 368660dfe135..433583b6f800 100644
--- a/drivers/iio/imu/adis16400_core.c
+++ b/drivers/iio/imu/adis16400_core.c
@@ -281,7 +281,7 @@ static ssize_t adis16400_write_frequency(struct device *dev,
st->variant->set_freq(st, val);
mutex_unlock(&indio_dev->mlock);
- return ret ? ret : len;
+ return len;
}
/* Power down the device */
@@ -632,7 +632,7 @@ static const struct iio_chan_spec adis16400_channels[] = {
ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14),
ADIS16400_TEMP_CHAN(ADIS16400_TEMP_OUT, 12),
ADIS16400_AUX_ADC_CHAN(ADIS16400_AUX_ADC, 12),
- IIO_CHAN_SOFT_TIMESTAMP(12)
+ IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP),
};
static const struct iio_chan_spec adis16448_channels[] = {
@@ -659,7 +659,7 @@ static const struct iio_chan_spec adis16448_channels[] = {
},
},
ADIS16400_TEMP_CHAN(ADIS16448_TEMP_OUT, 12),
- IIO_CHAN_SOFT_TIMESTAMP(11)
+ IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP),
};
static const struct iio_chan_spec adis16350_channels[] = {
@@ -677,7 +677,7 @@ static const struct iio_chan_spec adis16350_channels[] = {
ADIS16400_MOD_TEMP_CHAN(X, ADIS16350_XTEMP_OUT, 12),
ADIS16400_MOD_TEMP_CHAN(Y, ADIS16350_YTEMP_OUT, 12),
ADIS16400_MOD_TEMP_CHAN(Z, ADIS16350_ZTEMP_OUT, 12),
- IIO_CHAN_SOFT_TIMESTAMP(11)
+ IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP),
};
static const struct iio_chan_spec adis16300_channels[] = {
@@ -690,7 +690,7 @@ static const struct iio_chan_spec adis16300_channels[] = {
ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12),
ADIS16400_INCLI_CHAN(X, ADIS16300_PITCH_OUT, 13),
ADIS16400_INCLI_CHAN(Y, ADIS16300_ROLL_OUT, 13),
- IIO_CHAN_SOFT_TIMESTAMP(14)
+ IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP),
};
static const struct iio_chan_spec adis16334_channels[] = {
@@ -701,7 +701,7 @@ static const struct iio_chan_spec adis16334_channels[] = {
ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14),
ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14),
ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12),
- IIO_CHAN_SOFT_TIMESTAMP(8)
+ IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP),
};
static struct attribute *adis16400_attributes[] = {
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index df7f1e1157ae..cb9f96b446a5 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -12,7 +12,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/err.h>
@@ -117,7 +116,7 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
return result;
if (en) {
- /* Wait for output stablize */
+ /* Wait for output stabilize */
msleep(INV_MPU6050_TEMP_UP_TIME);
if (INV_MPU6050_BIT_PWR_GYRO_STBY == mask) {
/* switch internal clock to PLL */
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index f38395529a44..0ab382be1e64 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -126,35 +126,35 @@ struct inv_mpu6050_state {
#define INV_MPU6050_REG_SAMPLE_RATE_DIV 0x19
#define INV_MPU6050_REG_CONFIG 0x1A
#define INV_MPU6050_REG_GYRO_CONFIG 0x1B
-#define INV_MPU6050_REG_ACCEL_CONFIG 0x1C
+#define INV_MPU6050_REG_ACCEL_CONFIG 0x1C
#define INV_MPU6050_REG_FIFO_EN 0x23
-#define INV_MPU6050_BIT_ACCEL_OUT 0x08
-#define INV_MPU6050_BITS_GYRO_OUT 0x70
+#define INV_MPU6050_BIT_ACCEL_OUT 0x08
+#define INV_MPU6050_BITS_GYRO_OUT 0x70
#define INV_MPU6050_REG_INT_ENABLE 0x38
-#define INV_MPU6050_BIT_DATA_RDY_EN 0x01
-#define INV_MPU6050_BIT_DMP_INT_EN 0x02
+#define INV_MPU6050_BIT_DATA_RDY_EN 0x01
+#define INV_MPU6050_BIT_DMP_INT_EN 0x02
#define INV_MPU6050_REG_RAW_ACCEL 0x3B
#define INV_MPU6050_REG_TEMPERATURE 0x41
#define INV_MPU6050_REG_RAW_GYRO 0x43
#define INV_MPU6050_REG_USER_CTRL 0x6A
-#define INV_MPU6050_BIT_FIFO_RST 0x04
-#define INV_MPU6050_BIT_DMP_RST 0x08
-#define INV_MPU6050_BIT_I2C_MST_EN 0x20
-#define INV_MPU6050_BIT_FIFO_EN 0x40
-#define INV_MPU6050_BIT_DMP_EN 0x80
+#define INV_MPU6050_BIT_FIFO_RST 0x04
+#define INV_MPU6050_BIT_DMP_RST 0x08
+#define INV_MPU6050_BIT_I2C_MST_EN 0x20
+#define INV_MPU6050_BIT_FIFO_EN 0x40
+#define INV_MPU6050_BIT_DMP_EN 0x80
#define INV_MPU6050_REG_PWR_MGMT_1 0x6B
-#define INV_MPU6050_BIT_H_RESET 0x80
-#define INV_MPU6050_BIT_SLEEP 0x40
-#define INV_MPU6050_BIT_CLK_MASK 0x7
+#define INV_MPU6050_BIT_H_RESET 0x80
+#define INV_MPU6050_BIT_SLEEP 0x40
+#define INV_MPU6050_BIT_CLK_MASK 0x7
#define INV_MPU6050_REG_PWR_MGMT_2 0x6C
-#define INV_MPU6050_BIT_PWR_ACCL_STBY 0x38
-#define INV_MPU6050_BIT_PWR_GYRO_STBY 0x07
+#define INV_MPU6050_BIT_PWR_ACCL_STBY 0x38
+#define INV_MPU6050_BIT_PWR_GYRO_STBY 0x07
#define INV_MPU6050_REG_FIFO_COUNT_H 0x72
#define INV_MPU6050_REG_FIFO_R_W 0x74
@@ -180,10 +180,10 @@ struct inv_mpu6050_state {
/* init parameters */
#define INV_MPU6050_INIT_FIFO_RATE 50
-#define INV_MPU6050_TIME_STAMP_TOR 5
-#define INV_MPU6050_MAX_FIFO_RATE 1000
-#define INV_MPU6050_MIN_FIFO_RATE 4
-#define INV_MPU6050_ONE_K_HZ 1000
+#define INV_MPU6050_TIME_STAMP_TOR 5
+#define INV_MPU6050_MAX_FIFO_RATE 1000
+#define INV_MPU6050_MIN_FIFO_RATE 4
+#define INV_MPU6050_ONE_K_HZ 1000
/* scan element definition */
enum inv_mpu6050_scan {
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
index 429517117eff..0cd306a72a6e 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
@@ -12,7 +12,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/err.h>
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index c67d83bdc8f0..e108f2a9d827 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -264,7 +264,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
&indio_dev->dev,
&buffer->scan_el_dev_attr_list);
if (ret)
- goto error_ret;
+ return ret;
attrcount++;
ret = __iio_add_chan_devattr("type",
chan,
@@ -275,7 +275,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
&indio_dev->dev,
&buffer->scan_el_dev_attr_list);
if (ret)
- goto error_ret;
+ return ret;
attrcount++;
if (chan->type != IIO_TIMESTAMP)
ret = __iio_add_chan_devattr("en",
@@ -296,10 +296,9 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
&indio_dev->dev,
&buffer->scan_el_dev_attr_list);
if (ret)
- goto error_ret;
+ return ret;
attrcount++;
ret = attrcount;
-error_ret:
return ret;
}
@@ -553,13 +552,13 @@ static int __iio_update_buffers(struct iio_dev *indio_dev,
if (indio_dev->setup_ops->predisable) {
ret = indio_dev->setup_ops->predisable(indio_dev);
if (ret)
- goto error_ret;
+ return ret;
}
indio_dev->currentmode = INDIO_DIRECT_MODE;
if (indio_dev->setup_ops->postdisable) {
ret = indio_dev->setup_ops->postdisable(indio_dev);
if (ret)
- goto error_ret;
+ return ret;
}
}
/* Keep a copy of current setup to allow roll back */
@@ -613,7 +612,7 @@ static int __iio_update_buffers(struct iio_dev *indio_dev,
else {
kfree(compound_mask);
ret = -EINVAL;
- goto error_ret;
+ return ret;
}
}
} else {
@@ -696,13 +695,10 @@ error_run_postdisable:
if (indio_dev->setup_ops->postdisable)
indio_dev->setup_ops->postdisable(indio_dev);
error_remove_inserted:
-
if (insert_buffer)
iio_buffer_deactivate(insert_buffer);
indio_dev->active_scan_mask = old_mask;
kfree(compound_mask);
-error_ret:
-
return ret;
}
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index acc911a836ca..ede16aec20fb 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -540,7 +540,7 @@ int __iio_device_attr_init(struct device_attribute *dev_attr,
enum iio_shared_by shared_by)
{
int ret = 0;
- char *name_format = NULL;
+ char *name = NULL;
char *full_postfix;
sysfs_attr_init(&dev_attr->attr);
@@ -558,7 +558,7 @@ int __iio_device_attr_init(struct device_attribute *dev_attr,
->channel2],
postfix);
} else {
- if (chan->extend_name == NULL)
+ if (chan->extend_name == NULL || shared_by != IIO_SEPARATE)
full_postfix = kstrdup(postfix, GFP_KERNEL);
else
full_postfix = kasprintf(GFP_KERNEL,
@@ -572,16 +572,15 @@ int __iio_device_attr_init(struct device_attribute *dev_attr,
if (chan->differential) { /* Differential can not have modifier */
switch (shared_by) {
case IIO_SHARED_BY_ALL:
- name_format = kasprintf(GFP_KERNEL, "%s", full_postfix);
+ name = kasprintf(GFP_KERNEL, "%s", full_postfix);
break;
case IIO_SHARED_BY_DIR:
- name_format = kasprintf(GFP_KERNEL, "%s_%s",
+ name = kasprintf(GFP_KERNEL, "%s_%s",
iio_direction[chan->output],
full_postfix);
break;
case IIO_SHARED_BY_TYPE:
- name_format
- = kasprintf(GFP_KERNEL, "%s_%s-%s_%s",
+ name = kasprintf(GFP_KERNEL, "%s_%s-%s_%s",
iio_direction[chan->output],
iio_chan_type_name_spec[chan->type],
iio_chan_type_name_spec[chan->type],
@@ -593,8 +592,7 @@ int __iio_device_attr_init(struct device_attribute *dev_attr,
ret = -EINVAL;
goto error_free_full_postfix;
}
- name_format
- = kasprintf(GFP_KERNEL,
+ name = kasprintf(GFP_KERNEL,
"%s_%s%d-%s%d_%s",
iio_direction[chan->output],
iio_chan_type_name_spec[chan->type],
@@ -607,16 +605,15 @@ int __iio_device_attr_init(struct device_attribute *dev_attr,
} else { /* Single ended */
switch (shared_by) {
case IIO_SHARED_BY_ALL:
- name_format = kasprintf(GFP_KERNEL, "%s", full_postfix);
+ name = kasprintf(GFP_KERNEL, "%s", full_postfix);
break;
case IIO_SHARED_BY_DIR:
- name_format = kasprintf(GFP_KERNEL, "%s_%s",
+ name = kasprintf(GFP_KERNEL, "%s_%s",
iio_direction[chan->output],
full_postfix);
break;
case IIO_SHARED_BY_TYPE:
- name_format
- = kasprintf(GFP_KERNEL, "%s_%s_%s",
+ name = kasprintf(GFP_KERNEL, "%s_%s_%s",
iio_direction[chan->output],
iio_chan_type_name_spec[chan->type],
full_postfix);
@@ -624,33 +621,24 @@ int __iio_device_attr_init(struct device_attribute *dev_attr,
case IIO_SEPARATE:
if (chan->indexed)
- name_format
- = kasprintf(GFP_KERNEL, "%s_%s%d_%s",
+ name = kasprintf(GFP_KERNEL, "%s_%s%d_%s",
iio_direction[chan->output],
iio_chan_type_name_spec[chan->type],
chan->channel,
full_postfix);
else
- name_format
- = kasprintf(GFP_KERNEL, "%s_%s_%s",
+ name = kasprintf(GFP_KERNEL, "%s_%s_%s",
iio_direction[chan->output],
iio_chan_type_name_spec[chan->type],
full_postfix);
break;
}
}
- if (name_format == NULL) {
+ if (name == NULL) {
ret = -ENOMEM;
goto error_free_full_postfix;
}
- dev_attr->attr.name = kasprintf(GFP_KERNEL,
- name_format,
- chan->channel,
- chan->channel2);
- if (dev_attr->attr.name == NULL) {
- ret = -ENOMEM;
- goto error_free_name_format;
- }
+ dev_attr->attr.name = name;
if (readfunc) {
dev_attr->attr.mode |= S_IRUGO;
@@ -661,8 +649,7 @@ int __iio_device_attr_init(struct device_attribute *dev_attr,
dev_attr->attr.mode |= S_IWUSR;
dev_attr->store = writefunc;
}
-error_free_name_format:
- kfree(name_format);
+
error_free_full_postfix:
kfree(full_postfix);
@@ -692,10 +679,8 @@ int __iio_add_chan_devattr(const char *postfix,
struct iio_dev_attr *iio_attr, *t;
iio_attr = kzalloc(sizeof(*iio_attr), GFP_KERNEL);
- if (iio_attr == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ if (iio_attr == NULL)
+ return -ENOMEM;
ret = __iio_device_attr_init(&iio_attr->dev_attr,
postfix, chan,
readfunc, writefunc, shared_by);
@@ -720,7 +705,6 @@ error_device_attr_deinit:
__iio_device_attr_deinit(&iio_attr->dev_attr);
error_iio_dev_attr_free:
kfree(iio_attr);
-error_ret:
return ret;
}
@@ -1134,7 +1118,7 @@ int iio_device_register(struct iio_dev *indio_dev)
if (ret) {
dev_err(indio_dev->dev.parent,
"Failed to register debugfs interfaces\n");
- goto error_ret;
+ return ret;
}
ret = iio_device_register_sysfs(indio_dev);
if (ret) {
@@ -1175,7 +1159,6 @@ error_free_sysfs:
iio_device_unregister_sysfs(indio_dev);
error_unreg_debugfs:
iio_device_unregister_debugfs(indio_dev);
-error_ret:
return ret;
}
EXPORT_SYMBOL(iio_device_register);
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index c9c1419fe6e0..ea6e06b9c7d4 100644
--- a/drivers/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -40,6 +40,7 @@ struct iio_event_interface {
struct list_head dev_attr_list;
unsigned long flags;
struct attribute_group group;
+ struct mutex read_lock;
};
/**
@@ -47,16 +48,17 @@ struct iio_event_interface {
* @indio_dev: IIO device structure
* @ev_code: What event
* @timestamp: When the event occurred
+ *
+ * Note: The caller must make sure that this function is not running
+ * concurrently for the same indio_dev more than once.
**/
int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
{
struct iio_event_interface *ev_int = indio_dev->event_interface;
struct iio_event_data ev;
- unsigned long flags;
int copied;
/* Does anyone care? */
- spin_lock_irqsave(&ev_int->wait.lock, flags);
if (test_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
ev.id = ev_code;
@@ -64,9 +66,8 @@ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
copied = kfifo_put(&ev_int->det_events, ev);
if (copied != 0)
- wake_up_locked_poll(&ev_int->wait, POLLIN);
+ wake_up_poll(&ev_int->wait, POLLIN);
}
- spin_unlock_irqrestore(&ev_int->wait.lock, flags);
return 0;
}
@@ -87,10 +88,8 @@ static unsigned int iio_event_poll(struct file *filep,
poll_wait(filep, &ev_int->wait, wait);
- spin_lock_irq(&ev_int->wait.lock);
if (!kfifo_is_empty(&ev_int->det_events))
events = POLLIN | POLLRDNORM;
- spin_unlock_irq(&ev_int->wait.lock);
return events;
}
@@ -111,31 +110,40 @@ static ssize_t iio_event_chrdev_read(struct file *filep,
if (count < sizeof(struct iio_event_data))
return -EINVAL;
- spin_lock_irq(&ev_int->wait.lock);
- if (kfifo_is_empty(&ev_int->det_events)) {
- if (filep->f_flags & O_NONBLOCK) {
- ret = -EAGAIN;
- goto error_unlock;
- }
- /* Blocking on device; waiting for something to be there */
- ret = wait_event_interruptible_locked_irq(ev_int->wait,
+ do {
+ if (kfifo_is_empty(&ev_int->det_events)) {
+ if (filep->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ ret = wait_event_interruptible(ev_int->wait,
!kfifo_is_empty(&ev_int->det_events) ||
indio_dev->info == NULL);
- if (ret)
- goto error_unlock;
- if (indio_dev->info == NULL) {
- ret = -ENODEV;
- goto error_unlock;
+ if (ret)
+ return ret;
+ if (indio_dev->info == NULL)
+ return -ENODEV;
}
- /* Single access device so no one else can get the data */
- }
- ret = kfifo_to_user(&ev_int->det_events, buf, count, &copied);
+ if (mutex_lock_interruptible(&ev_int->read_lock))
+ return -ERESTARTSYS;
+ ret = kfifo_to_user(&ev_int->det_events, buf, count, &copied);
+ mutex_unlock(&ev_int->read_lock);
-error_unlock:
- spin_unlock_irq(&ev_int->wait.lock);
+ if (ret)
+ return ret;
+
+ /*
+ * If we couldn't read anything from the fifo (a different
+ * thread might have been faster) we either return -EAGAIN if
+ * the file descriptor is non-blocking, otherwise we go back to
+ * sleep and wait for more data to arrive.
+ */
+ if (copied == 0 && (filep->f_flags & O_NONBLOCK))
+ return -EAGAIN;
- return ret ? ret : copied;
+ } while (copied == 0);
+
+ return copied;
}
static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
@@ -143,15 +151,7 @@ static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
struct iio_dev *indio_dev = filep->private_data;
struct iio_event_interface *ev_int = indio_dev->event_interface;
- spin_lock_irq(&ev_int->wait.lock);
- __clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
- /*
- * In order to maintain a clean state for reopening,
- * clear out any awaiting events. The mask will prevent
- * any new __iio_push_event calls running.
- */
- kfifo_reset_out(&ev_int->det_events);
- spin_unlock_irq(&ev_int->wait.lock);
+ clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
iio_device_put(indio_dev);
@@ -174,22 +174,20 @@ int iio_event_getfd(struct iio_dev *indio_dev)
if (ev_int == NULL)
return -ENODEV;
- spin_lock_irq(&ev_int->wait.lock);
- if (__test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
- spin_unlock_irq(&ev_int->wait.lock);
+ if (test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags))
return -EBUSY;
- }
- spin_unlock_irq(&ev_int->wait.lock);
+
iio_device_get(indio_dev);
fd = anon_inode_getfd("iio:event", &iio_event_chrdev_fileops,
indio_dev, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
- spin_lock_irq(&ev_int->wait.lock);
- __clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
- spin_unlock_irq(&ev_int->wait.lock);
+ clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
iio_device_put(indio_dev);
+ } else {
+ kfifo_reset_out(&ev_int->det_events);
}
+
return fd;
}
@@ -366,32 +364,31 @@ static int iio_device_add_event_sysfs(struct iio_dev *indio_dev,
ret = iio_device_add_event(indio_dev, chan, i, type, dir,
IIO_SEPARATE, &chan->event_spec[i].mask_separate);
if (ret < 0)
- goto error_ret;
+ return ret;
attrcount += ret;
ret = iio_device_add_event(indio_dev, chan, i, type, dir,
IIO_SHARED_BY_TYPE,
&chan->event_spec[i].mask_shared_by_type);
if (ret < 0)
- goto error_ret;
+ return ret;
attrcount += ret;
ret = iio_device_add_event(indio_dev, chan, i, type, dir,
IIO_SHARED_BY_DIR,
&chan->event_spec[i].mask_shared_by_dir);
if (ret < 0)
- goto error_ret;
+ return ret;
attrcount += ret;
ret = iio_device_add_event(indio_dev, chan, i, type, dir,
IIO_SHARED_BY_ALL,
&chan->event_spec[i].mask_shared_by_all);
if (ret < 0)
- goto error_ret;
+ return ret;
attrcount += ret;
}
ret = attrcount;
-error_ret:
return ret;
}
@@ -425,6 +422,7 @@ static void iio_setup_ev_int(struct iio_event_interface *ev_int)
{
INIT_KFIFO(ev_int->det_events);
init_waitqueue_head(&ev_int->wait);
+ mutex_init(&ev_int->read_lock);
}
static const char *iio_event_group_name = "events";
@@ -440,10 +438,8 @@ int iio_device_register_eventset(struct iio_dev *indio_dev)
indio_dev->event_interface =
kzalloc(sizeof(struct iio_event_interface), GFP_KERNEL);
- if (indio_dev->event_interface == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ if (indio_dev->event_interface == NULL)
+ return -ENOMEM;
INIT_LIST_HEAD(&indio_dev->event_interface->dev_attr_list);
@@ -489,8 +485,6 @@ int iio_device_register_eventset(struct iio_dev *indio_dev)
error_free_setup_event_lines:
iio_free_chan_devattr_list(&indio_dev->event_interface->dev_attr_list);
kfree(indio_dev->event_interface);
-error_ret:
-
return ret;
}
diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
index 766fab24b720..3383b025f62e 100644
--- a/drivers/iio/industrialio-trigger.c
+++ b/drivers/iio/industrialio-trigger.c
@@ -62,10 +62,9 @@ int iio_trigger_register(struct iio_trigger *trig_info)
int ret;
trig_info->id = ida_simple_get(&iio_trigger_ida, 0, 0, GFP_KERNEL);
- if (trig_info->id < 0) {
- ret = trig_info->id;
- goto error_ret;
- }
+ if (trig_info->id < 0)
+ return trig_info->id;
+
/* Set the name used for the sysfs directory etc */
dev_set_name(&trig_info->dev, "trigger%ld",
(unsigned long) trig_info->id);
@@ -83,7 +82,6 @@ int iio_trigger_register(struct iio_trigger *trig_info)
error_unregister_id:
ida_simple_remove(&iio_trigger_ida, trig_info->id);
-error_ret:
return ret;
}
EXPORT_SYMBOL(iio_trigger_register);
@@ -234,13 +232,12 @@ static int iio_trigger_detach_poll_func(struct iio_trigger *trig,
if (trig->ops && trig->ops->set_trigger_state && no_other_users) {
ret = trig->ops->set_trigger_state(trig, false);
if (ret)
- goto error_ret;
+ return ret;
}
iio_trigger_put_irq(trig, pf->irq);
free_irq(pf->irq, pf);
module_put(pf->indio_dev->info->driver_module);
-error_ret:
return ret;
}
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index d12b2a0dbfbc..c89740d4748f 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -73,6 +73,20 @@ config HID_SENSOR_ALS
Say yes here to build support for the HID SENSOR
Ambient light sensor.
+config HID_SENSOR_PROX
+ depends on HID_SENSOR_HUB
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ select HID_SENSOR_IIO_COMMON
+ select HID_SENSOR_IIO_TRIGGER
+ tristate "HID PROX"
+ help
+ Say yes here to build support for the HID SENSOR
+ Proximity sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called hid-sensor-prox.
+
config SENSORS_LM3533
tristate "LM3533 ambient light sensor"
depends on MFD_LM3533
@@ -90,6 +104,18 @@ config SENSORS_LM3533
changes. The ALS-control output values can be set per zone for the
three current output channels.
+config LTR501
+ tristate "LTR-501ALS-01 light sensor"
+ depends on I2C
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ If you say yes here you get support for the Lite-On LTR-501ALS-01
+ ambient light and proximity sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called ltr501.
+
config TCS3472
tristate "TAOS TCS3472 color light-to-digital converter"
depends on I2C
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index 60e35ac07ff0..3eb36e5151fa 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -9,7 +9,9 @@ obj-$(CONFIG_CM32181) += cm32181.o
obj-$(CONFIG_CM36651) += cm36651.o
obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o
obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
+obj-$(CONFIG_HID_SENSOR_PROX) += hid-sensor-prox.o
obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
+obj-$(CONFIG_LTR501) += ltr501.o
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_TCS3472) += tcs3472.o
obj-$(CONFIG_TSL4531) += tsl4531.o
diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c
index f3068477b466..09ad5f1ce539 100644
--- a/drivers/iio/light/adjd_s311.c
+++ b/drivers/iio/light/adjd_s311.c
@@ -14,7 +14,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
@@ -120,7 +119,6 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct adjd_s311_data *data = iio_priv(indio_dev);
s64 time_ns = iio_get_time_ns();
- int len = 0;
int i, j = 0;
int ret = adjd_s311_req_data(indio_dev);
@@ -135,7 +133,6 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p)
goto done;
data->buffer[j++] = ret & ADJD_S311_DATA_MASK;
- len += 2;
}
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, time_ns);
diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index f17b4e6183c6..47a6dbac2d0c 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -103,13 +103,13 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
/**
* cm32181_read_als_it() - Get sensor integration time (ms)
* @cm32181: pointer of struct cm32181
- * @val: pointer of int to load the als_it value.
+ * @val2: pointer of int to load the als_it value.
*
* Report the current integartion time by millisecond.
*
- * Return: IIO_VAL_INT for success, otherwise -EINVAL.
+ * Return: IIO_VAL_INT_PLUS_MICRO for success, otherwise -EINVAL.
*/
-static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val)
+static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val2)
{
u16 als_it;
int i;
@@ -119,8 +119,8 @@ static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val)
als_it >>= CM32181_CMD_ALS_IT_SHIFT;
for (i = 0; i < ARRAY_SIZE(als_it_bits); i++) {
if (als_it == als_it_bits[i]) {
- *val = als_it_value[i];
- return IIO_VAL_INT;
+ *val2 = als_it_value[i];
+ return IIO_VAL_INT_PLUS_MICRO;
}
}
@@ -221,7 +221,7 @@ static int cm32181_read_raw(struct iio_dev *indio_dev,
*val = cm32181->calibscale;
return IIO_VAL_INT;
case IIO_CHAN_INFO_INT_TIME:
- ret = cm32181_read_als_it(cm32181, val);
+ ret = cm32181_read_als_it(cm32181, val2);
return ret;
}
@@ -240,7 +240,7 @@ static int cm32181_write_raw(struct iio_dev *indio_dev,
cm32181->calibscale = val;
return val;
case IIO_CHAN_INFO_INT_TIME:
- ret = cm32181_write_als_it(cm32181, val);
+ ret = cm32181_write_als_it(cm32181, val2);
return ret;
}
@@ -264,7 +264,7 @@ static ssize_t cm32181_get_it_available(struct device *dev,
n = ARRAY_SIZE(als_it_value);
for (i = 0, len = 0; i < n; i++)
- len += sprintf(buf + len, "%d ", als_it_value[i]);
+ len += sprintf(buf + len, "0.%06u ", als_it_value[i]);
return len + sprintf(buf + len, "\n");
}
diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c
index 0a142af83e25..a45e07492db3 100644
--- a/drivers/iio/light/cm36651.c
+++ b/drivers/iio/light/cm36651.c
@@ -50,10 +50,10 @@
#define CM36651_CS_CONF2_DEFAULT_BIT 0x08
/* CS_CONF3 channel integration time */
-#define CM36651_CS_IT1 0x00 /* Integration time 80000 usec */
-#define CM36651_CS_IT2 0x40 /* Integration time 160000 usec */
-#define CM36651_CS_IT3 0x80 /* Integration time 320000 usec */
-#define CM36651_CS_IT4 0xC0 /* Integration time 640000 usec */
+#define CM36651_CS_IT1 0x00 /* Integration time 80 msec */
+#define CM36651_CS_IT2 0x40 /* Integration time 160 msec */
+#define CM36651_CS_IT3 0x80 /* Integration time 320 msec */
+#define CM36651_CS_IT4 0xC0 /* Integration time 640 msec */
/* PS_CONF1 command code */
#define CM36651_PS_ENABLE 0x00
@@ -64,10 +64,10 @@
#define CM36651_PS_PERS4 0x0C
/* PS_CONF1 command code: integration time */
-#define CM36651_PS_IT1 0x00 /* Integration time 320 usec */
-#define CM36651_PS_IT2 0x10 /* Integration time 420 usec */
-#define CM36651_PS_IT3 0x20 /* Integration time 520 usec */
-#define CM36651_PS_IT4 0x30 /* Integration time 640 usec */
+#define CM36651_PS_IT1 0x00 /* Integration time 0.32 msec */
+#define CM36651_PS_IT2 0x10 /* Integration time 0.42 msec */
+#define CM36651_PS_IT3 0x20 /* Integration time 0.52 msec */
+#define CM36651_PS_IT4 0x30 /* Integration time 0.64 msec */
/* PS_CONF1 command code: duty ratio */
#define CM36651_PS_DR1 0x00 /* Duty ratio 1/80 */
@@ -93,8 +93,8 @@
#define CM36651_CLOSE_PROXIMITY 0x32
#define CM36651_FAR_PROXIMITY 0x33
-#define CM36651_CS_INT_TIME_AVAIL "80000 160000 320000 640000"
-#define CM36651_PS_INT_TIME_AVAIL "320 420 520 640"
+#define CM36651_CS_INT_TIME_AVAIL "0.08 0.16 0.32 0.64"
+#define CM36651_PS_INT_TIME_AVAIL "0.000320 0.000420 0.000520 0.000640"
enum cm36651_operation_mode {
CM36651_LIGHT_EN,
@@ -356,30 +356,30 @@ static int cm36651_read_channel(struct cm36651_data *cm36651,
}
static int cm36651_read_int_time(struct cm36651_data *cm36651,
- struct iio_chan_spec const *chan, int *val)
+ struct iio_chan_spec const *chan, int *val2)
{
switch (chan->type) {
case IIO_LIGHT:
if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT1)
- *val = 80000;
+ *val2 = 80000;
else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT2)
- *val = 160000;
+ *val2 = 160000;
else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT3)
- *val = 320000;
+ *val2 = 320000;
else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT4)
- *val = 640000;
+ *val2 = 640000;
else
return -EINVAL;
break;
case IIO_PROXIMITY:
if (cm36651->ps_int_time == CM36651_PS_IT1)
- *val = 320;
+ *val2 = 320;
else if (cm36651->ps_int_time == CM36651_PS_IT2)
- *val = 420;
+ *val2 = 420;
else if (cm36651->ps_int_time == CM36651_PS_IT3)
- *val = 520;
+ *val2 = 520;
else if (cm36651->ps_int_time == CM36651_PS_IT4)
- *val = 640;
+ *val2 = 640;
else
return -EINVAL;
break;
@@ -387,7 +387,7 @@ static int cm36651_read_int_time(struct cm36651_data *cm36651,
return -EINVAL;
}
- return IIO_VAL_INT;
+ return IIO_VAL_INT_PLUS_MICRO;
}
static int cm36651_write_int_time(struct cm36651_data *cm36651,
@@ -459,7 +459,8 @@ static int cm36651_read_raw(struct iio_dev *indio_dev,
ret = cm36651_read_channel(cm36651, chan, val);
break;
case IIO_CHAN_INFO_INT_TIME:
- ret = cm36651_read_int_time(cm36651, chan, val);
+ *val = 0;
+ ret = cm36651_read_int_time(cm36651, chan, val2);
break;
default:
ret = -EINVAL;
@@ -479,7 +480,7 @@ static int cm36651_write_raw(struct iio_dev *indio_dev,
int ret = -EINVAL;
if (mask == IIO_CHAN_INFO_INT_TIME) {
- ret = cm36651_write_int_time(cm36651, chan, val);
+ ret = cm36651_write_int_time(cm36651, chan, val2);
if (ret < 0)
dev_err(&client->dev, "Integration time write failed\n");
}
diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c
new file mode 100644
index 000000000000..1894ab196f97
--- /dev/null
+++ b/drivers/iio/light/hid-sensor-prox.c
@@ -0,0 +1,375 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.
+ *
+ */
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/hid-sensor-hub.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include "../common/hid-sensors/hid-sensor-trigger.h"
+
+#define CHANNEL_SCAN_INDEX_PRESENCE 0
+
+struct prox_state {
+ struct hid_sensor_hub_callbacks callbacks;
+ struct hid_sensor_common common_attributes;
+ struct hid_sensor_hub_attribute_info prox_attr;
+ u32 human_presence;
+};
+
+/* Channel definitions */
+static const struct iio_chan_spec prox_channels[] = {
+ {
+ .type = IIO_PROXIMITY,
+ .modified = 1,
+ .channel2 = IIO_NO_MOD,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
+ .scan_index = CHANNEL_SCAN_INDEX_PRESENCE,
+ }
+};
+
+/* Adjust channel real bits based on report descriptor */
+static void prox_adjust_channel_bit_mask(struct iio_chan_spec *channels,
+ int channel, int size)
+{
+ channels[channel].scan_type.sign = 's';
+ /* Real storage bits will change based on the report desc. */
+ channels[channel].scan_type.realbits = size * 8;
+ /* Maximum size of a sample to capture is u32 */
+ channels[channel].scan_type.storagebits = sizeof(u32) * 8;
+}
+
+/* Channel read_raw handler */
+static int prox_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2,
+ long mask)
+{
+ struct prox_state *prox_state = iio_priv(indio_dev);
+ int report_id = -1;
+ u32 address;
+ int ret;
+ int ret_type;
+
+ *val = 0;
+ *val2 = 0;
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->scan_index) {
+ case CHANNEL_SCAN_INDEX_PRESENCE:
+ report_id = prox_state->prox_attr.report_id;
+ address =
+ HID_USAGE_SENSOR_HUMAN_PRESENCE;
+ break;
+ default:
+ report_id = -1;
+ break;
+ }
+ if (report_id >= 0)
+ *val = sensor_hub_input_attr_get_raw_value(
+ prox_state->common_attributes.hsdev,
+ HID_USAGE_SENSOR_PROX, address,
+ report_id);
+ else {
+ *val = 0;
+ return -EINVAL;
+ }
+ ret_type = IIO_VAL_INT;
+ break;
+ case IIO_CHAN_INFO_SCALE:
+ *val = prox_state->prox_attr.units;
+ ret_type = IIO_VAL_INT;
+ break;
+ case IIO_CHAN_INFO_OFFSET:
+ *val = hid_sensor_convert_exponent(
+ prox_state->prox_attr.unit_expo);
+ ret_type = IIO_VAL_INT;
+ break;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = hid_sensor_read_samp_freq_value(
+ &prox_state->common_attributes, val, val2);
+ ret_type = IIO_VAL_INT_PLUS_MICRO;
+ break;
+ case IIO_CHAN_INFO_HYSTERESIS:
+ ret = hid_sensor_read_raw_hyst_value(
+ &prox_state->common_attributes, val, val2);
+ ret_type = IIO_VAL_INT_PLUS_MICRO;
+ break;
+ default:
+ ret_type = -EINVAL;
+ break;
+ }
+
+ return ret_type;
+}
+
+/* Channel write_raw handler */
+static int prox_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ struct prox_state *prox_state = iio_priv(indio_dev);
+ int ret = 0;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = hid_sensor_write_samp_freq_value(
+ &prox_state->common_attributes, val, val2);
+ break;
+ case IIO_CHAN_INFO_HYSTERESIS:
+ ret = hid_sensor_write_raw_hyst_value(
+ &prox_state->common_attributes, val, val2);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct iio_info prox_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = &prox_read_raw,
+ .write_raw = &prox_write_raw,
+};
+
+/* Function to push data to buffer */
+static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data,
+ int len)
+{
+ dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
+ iio_push_to_buffers(indio_dev, data);
+}
+
+/* Callback handler to send event after all samples are received and captured */
+static int prox_proc_event(struct hid_sensor_hub_device *hsdev,
+ unsigned usage_id,
+ void *priv)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(priv);
+ struct prox_state *prox_state = iio_priv(indio_dev);
+
+ dev_dbg(&indio_dev->dev, "prox_proc_event [%d]\n",
+ prox_state->common_attributes.data_ready);
+ if (prox_state->common_attributes.data_ready)
+ hid_sensor_push_data(indio_dev,
+ &prox_state->human_presence,
+ sizeof(prox_state->human_presence));
+
+ return 0;
+}
+
+/* Capture samples in local storage */
+static int prox_capture_sample(struct hid_sensor_hub_device *hsdev,
+ unsigned usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(priv);
+ struct prox_state *prox_state = iio_priv(indio_dev);
+ int ret = -EINVAL;
+
+ switch (usage_id) {
+ case HID_USAGE_SENSOR_HUMAN_PRESENCE:
+ prox_state->human_presence = *(u32 *)raw_data;
+ ret = 0;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/* Parse report which is specific to an usage id*/
+static int prox_parse_report(struct platform_device *pdev,
+ struct hid_sensor_hub_device *hsdev,
+ struct iio_chan_spec *channels,
+ unsigned usage_id,
+ struct prox_state *st)
+{
+ int ret;
+
+ ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+ usage_id,
+ HID_USAGE_SENSOR_HUMAN_PRESENCE,
+ &st->prox_attr);
+ if (ret < 0)
+ return ret;
+ prox_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_PRESENCE,
+ st->prox_attr.size);
+
+ dev_dbg(&pdev->dev, "prox %x:%x\n", st->prox_attr.index,
+ st->prox_attr.report_id);
+
+ /* Set Sensitivity field ids, when there is no individual modifier */
+ if (st->common_attributes.sensitivity.index < 0) {
+ sensor_hub_input_get_attribute_info(hsdev,
+ HID_FEATURE_REPORT, usage_id,
+ HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
+ HID_USAGE_SENSOR_DATA_PRESENCE,
+ &st->common_attributes.sensitivity);
+ dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
+ st->common_attributes.sensitivity.index,
+ st->common_attributes.sensitivity.report_id);
+ }
+ return ret;
+}
+
+/* Function to initialize the processing for usage id */
+static int hid_prox_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ static const char *name = "prox";
+ struct iio_dev *indio_dev;
+ struct prox_state *prox_state;
+ struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
+ struct iio_chan_spec *channels;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev,
+ sizeof(struct prox_state));
+ if (!indio_dev)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, indio_dev);
+
+ prox_state = iio_priv(indio_dev);
+ prox_state->common_attributes.hsdev = hsdev;
+ prox_state->common_attributes.pdev = pdev;
+
+ ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_PROX,
+ &prox_state->common_attributes);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to setup common attributes\n");
+ return ret;
+ }
+
+ channels = kmemdup(prox_channels, sizeof(prox_channels), GFP_KERNEL);
+ if (!channels) {
+ dev_err(&pdev->dev, "failed to duplicate channels\n");
+ return -ENOMEM;
+ }
+
+ ret = prox_parse_report(pdev, hsdev, channels,
+ HID_USAGE_SENSOR_PROX, prox_state);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to setup attributes\n");
+ goto error_free_dev_mem;
+ }
+
+ indio_dev->channels = channels;
+ indio_dev->num_channels =
+ ARRAY_SIZE(prox_channels);
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->info = &prox_info;
+ indio_dev->name = name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+ NULL, NULL);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
+ goto error_free_dev_mem;
+ }
+ prox_state->common_attributes.data_ready = false;
+ ret = hid_sensor_setup_trigger(indio_dev, name,
+ &prox_state->common_attributes);
+ if (ret) {
+ dev_err(&pdev->dev, "trigger setup failed\n");
+ goto error_unreg_buffer_funcs;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_trigger;
+ }
+
+ prox_state->callbacks.send_event = prox_proc_event;
+ prox_state->callbacks.capture_sample = prox_capture_sample;
+ prox_state->callbacks.pdev = pdev;
+ ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_PROX,
+ &prox_state->callbacks);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "callback reg failed\n");
+ goto error_iio_unreg;
+ }
+
+ return ret;
+
+error_iio_unreg:
+ iio_device_unregister(indio_dev);
+error_remove_trigger:
+ hid_sensor_remove_trigger(&prox_state->common_attributes);
+error_unreg_buffer_funcs:
+ iio_triggered_buffer_cleanup(indio_dev);
+error_free_dev_mem:
+ kfree(indio_dev->channels);
+ return ret;
+}
+
+/* Function to deinitialize the processing for usage id */
+static int hid_prox_remove(struct platform_device *pdev)
+{
+ struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct prox_state *prox_state = iio_priv(indio_dev);
+
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PROX);
+ iio_device_unregister(indio_dev);
+ hid_sensor_remove_trigger(&prox_state->common_attributes);
+ iio_triggered_buffer_cleanup(indio_dev);
+ kfree(indio_dev->channels);
+
+ return 0;
+}
+
+static struct platform_device_id hid_prox_ids[] = {
+ {
+ /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
+ .name = "HID-SENSOR-200011",
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, hid_prox_ids);
+
+static struct platform_driver hid_prox_platform_driver = {
+ .id_table = hid_prox_ids,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = hid_prox_probe,
+ .remove = hid_prox_remove,
+};
+module_platform_driver(hid_prox_platform_driver);
+
+MODULE_DESCRIPTION("HID Sensor Proximity");
+MODULE_AUTHOR("Archana Patni <archana.patni@intel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c
new file mode 100644
index 000000000000..62b7072af4de
--- /dev/null
+++ b/drivers/iio/light/ltr501.c
@@ -0,0 +1,445 @@
+/*
+ * ltr501.c - Support for Lite-On LTR501 ambient light and proximity sensor
+ *
+ * Copyright 2014 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.
+ *
+ * 7-bit I2C slave address 0x23
+ *
+ * TODO: interrupt, threshold, measurement rate, IR LED characteristics
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define LTR501_DRV_NAME "ltr501"
+
+#define LTR501_ALS_CONTR 0x80 /* ALS operation mode, SW reset */
+#define LTR501_PS_CONTR 0x81 /* PS operation mode */
+#define LTR501_PART_ID 0x86
+#define LTR501_MANUFAC_ID 0x87
+#define LTR501_ALS_DATA1 0x88 /* 16-bit, little endian */
+#define LTR501_ALS_DATA0 0x8a /* 16-bit, little endian */
+#define LTR501_ALS_PS_STATUS 0x8c
+#define LTR501_PS_DATA 0x8d /* 16-bit, little endian */
+
+#define LTR501_ALS_CONTR_SW_RESET BIT(2)
+#define LTR501_CONTR_PS_GAIN_MASK (BIT(3) | BIT(2))
+#define LTR501_CONTR_PS_GAIN_SHIFT 2
+#define LTR501_CONTR_ALS_GAIN_MASK BIT(3)
+#define LTR501_CONTR_ACTIVE BIT(1)
+
+#define LTR501_STATUS_ALS_RDY BIT(2)
+#define LTR501_STATUS_PS_RDY BIT(0)
+
+#define LTR501_PS_DATA_MASK 0x7ff
+
+struct ltr501_data {
+ struct i2c_client *client;
+ struct mutex lock_als, lock_ps;
+ u8 als_contr, ps_contr;
+};
+
+static int ltr501_drdy(struct ltr501_data *data, u8 drdy_mask)
+{
+ int tries = 100;
+ int ret;
+
+ while (tries--) {
+ ret = i2c_smbus_read_byte_data(data->client,
+ LTR501_ALS_PS_STATUS);
+ if (ret < 0)
+ return ret;
+ if ((ret & drdy_mask) == drdy_mask)
+ return 0;
+ msleep(25);
+ }
+
+ dev_err(&data->client->dev, "ltr501_drdy() failed, data not ready\n");
+ return -EIO;
+}
+
+static int ltr501_read_als(struct ltr501_data *data, __le16 buf[2])
+{
+ int ret = ltr501_drdy(data, LTR501_STATUS_ALS_RDY);
+ if (ret < 0)
+ return ret;
+ /* always read both ALS channels in given order */
+ return i2c_smbus_read_i2c_block_data(data->client,
+ LTR501_ALS_DATA1, 2 * sizeof(__le16), (u8 *) buf);
+}
+
+static int ltr501_read_ps(struct ltr501_data *data)
+{
+ int ret = ltr501_drdy(data, LTR501_STATUS_PS_RDY);
+ if (ret < 0)
+ return ret;
+ return i2c_smbus_read_word_data(data->client, LTR501_PS_DATA);
+}
+
+#define LTR501_INTENSITY_CHANNEL(_idx, _addr, _mod, _shared) { \
+ .type = IIO_INTENSITY, \
+ .modified = 1, \
+ .address = (_addr), \
+ .channel2 = (_mod), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = (_shared), \
+ .scan_index = (_idx), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_CPU, \
+ } \
+}
+
+static const struct iio_chan_spec ltr501_channels[] = {
+ LTR501_INTENSITY_CHANNEL(0, LTR501_ALS_DATA0, IIO_MOD_LIGHT_BOTH, 0),
+ LTR501_INTENSITY_CHANNEL(1, LTR501_ALS_DATA1, IIO_MOD_LIGHT_IR,
+ BIT(IIO_CHAN_INFO_SCALE)),
+ {
+ .type = IIO_PROXIMITY,
+ .address = LTR501_PS_DATA,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = 2,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 11,
+ .storagebits = 16,
+ .endianness = IIO_CPU,
+ },
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const int ltr501_ps_gain[4][2] = {
+ {1, 0}, {0, 250000}, {0, 125000}, {0, 62500}
+};
+
+static int ltr501_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct ltr501_data *data = iio_priv(indio_dev);
+ __le16 buf[2];
+ int ret, i;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (iio_buffer_enabled(indio_dev))
+ return -EBUSY;
+
+ switch (chan->type) {
+ case IIO_INTENSITY:
+ mutex_lock(&data->lock_als);
+ ret = ltr501_read_als(data, buf);
+ mutex_unlock(&data->lock_als);
+ if (ret < 0)
+ return ret;
+ *val = le16_to_cpu(chan->address == LTR501_ALS_DATA1 ?
+ buf[0] : buf[1]);
+ return IIO_VAL_INT;
+ case IIO_PROXIMITY:
+ mutex_lock(&data->lock_ps);
+ ret = ltr501_read_ps(data);
+ mutex_unlock(&data->lock_ps);
+ if (ret < 0)
+ return ret;
+ *val = ret & LTR501_PS_DATA_MASK;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_INTENSITY:
+ if (data->als_contr & LTR501_CONTR_ALS_GAIN_MASK) {
+ *val = 0;
+ *val2 = 5000;
+ return IIO_VAL_INT_PLUS_MICRO;
+ } else {
+ *val = 1;
+ *val2 = 0;
+ return IIO_VAL_INT;
+ }
+ case IIO_PROXIMITY:
+ i = (data->ps_contr & LTR501_CONTR_PS_GAIN_MASK) >>
+ LTR501_CONTR_PS_GAIN_SHIFT;
+ *val = ltr501_ps_gain[i][0];
+ *val2 = ltr501_ps_gain[i][1];
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+ }
+ return -EINVAL;
+}
+
+static int ltr501_get_ps_gain_index(int val, int val2)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ltr501_ps_gain); i++)
+ if (val == ltr501_ps_gain[i][0] && val2 == ltr501_ps_gain[i][1])
+ return i;
+
+ return -1;
+}
+
+static int ltr501_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ltr501_data *data = iio_priv(indio_dev);
+ int i;
+
+ if (iio_buffer_enabled(indio_dev))
+ return -EBUSY;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_INTENSITY:
+ if (val == 0 && val2 == 5000)
+ data->als_contr |= LTR501_CONTR_ALS_GAIN_MASK;
+ else if (val == 1 && val2 == 0)
+ data->als_contr &= ~LTR501_CONTR_ALS_GAIN_MASK;
+ else
+ return -EINVAL;
+ return i2c_smbus_write_byte_data(data->client,
+ LTR501_ALS_CONTR, data->als_contr);
+ case IIO_PROXIMITY:
+ i = ltr501_get_ps_gain_index(val, val2);
+ if (i < 0)
+ return -EINVAL;
+ data->ps_contr &= ~LTR501_CONTR_PS_GAIN_MASK;
+ data->ps_contr |= i << LTR501_CONTR_PS_GAIN_SHIFT;
+ return i2c_smbus_write_byte_data(data->client,
+ LTR501_PS_CONTR, data->ps_contr);
+ default:
+ return -EINVAL;
+ }
+ }
+ return -EINVAL;
+}
+
+static IIO_CONST_ATTR(in_proximity_scale_available, "1 0.25 0.125 0.0625");
+static IIO_CONST_ATTR(in_intensity_scale_available, "1 0.005");
+
+static struct attribute *ltr501_attributes[] = {
+ &iio_const_attr_in_proximity_scale_available.dev_attr.attr,
+ &iio_const_attr_in_intensity_scale_available.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group ltr501_attribute_group = {
+ .attrs = ltr501_attributes,
+};
+
+static const struct iio_info ltr501_info = {
+ .read_raw = ltr501_read_raw,
+ .write_raw = ltr501_write_raw,
+ .attrs = &ltr501_attribute_group,
+ .driver_module = THIS_MODULE,
+};
+
+static int ltr501_write_contr(struct i2c_client *client, u8 als_val, u8 ps_val)
+{
+ int ret = i2c_smbus_write_byte_data(client, LTR501_ALS_CONTR, als_val);
+ if (ret < 0)
+ return ret;
+
+ return i2c_smbus_write_byte_data(client, LTR501_PS_CONTR, ps_val);
+}
+
+static irqreturn_t ltr501_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ltr501_data *data = iio_priv(indio_dev);
+ u16 buf[8];
+ __le16 als_buf[2];
+ u8 mask = 0;
+ int j = 0;
+ int ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ /* figure out which data needs to be ready */
+ if (test_bit(0, indio_dev->active_scan_mask) ||
+ test_bit(1, indio_dev->active_scan_mask))
+ mask |= LTR501_STATUS_ALS_RDY;
+ if (test_bit(2, indio_dev->active_scan_mask))
+ mask |= LTR501_STATUS_PS_RDY;
+
+ ret = ltr501_drdy(data, mask);
+ if (ret < 0)
+ goto done;
+
+ if (mask & LTR501_STATUS_ALS_RDY) {
+ ret = i2c_smbus_read_i2c_block_data(data->client,
+ LTR501_ALS_DATA1, sizeof(als_buf), (u8 *) als_buf);
+ if (ret < 0)
+ return ret;
+ if (test_bit(0, indio_dev->active_scan_mask))
+ buf[j++] = le16_to_cpu(als_buf[1]);
+ if (test_bit(1, indio_dev->active_scan_mask))
+ buf[j++] = le16_to_cpu(als_buf[0]);
+ }
+
+ if (mask & LTR501_STATUS_PS_RDY) {
+ ret = i2c_smbus_read_word_data(data->client, LTR501_PS_DATA);
+ if (ret < 0)
+ goto done;
+ buf[j++] = ret & LTR501_PS_DATA_MASK;
+ }
+
+ iio_push_to_buffers_with_timestamp(indio_dev, buf,
+ iio_get_time_ns());
+
+done:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int ltr501_init(struct ltr501_data *data)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(data->client, LTR501_ALS_CONTR);
+ if (ret < 0)
+ return ret;
+ data->als_contr = ret | LTR501_CONTR_ACTIVE;
+
+ ret = i2c_smbus_read_byte_data(data->client, LTR501_PS_CONTR);
+ if (ret < 0)
+ return ret;
+ data->ps_contr = ret | LTR501_CONTR_ACTIVE;
+
+ return ltr501_write_contr(data->client, data->als_contr,
+ data->ps_contr);
+}
+
+static int ltr501_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ltr501_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;
+ mutex_init(&data->lock_als);
+ mutex_init(&data->lock_ps);
+
+ ret = i2c_smbus_read_byte_data(data->client, LTR501_PART_ID);
+ if (ret < 0)
+ return ret;
+ if ((ret >> 4) != 0x8)
+ return -ENODEV;
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->info = &ltr501_info;
+ indio_dev->channels = ltr501_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ltr501_channels);
+ indio_dev->name = LTR501_DRV_NAME;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = ltr501_init(data);
+ if (ret < 0)
+ return ret;
+
+ ret = iio_triggered_buffer_setup(indio_dev, NULL,
+ ltr501_trigger_handler, NULL);
+ if (ret)
+ return ret;
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_unreg_buffer;
+
+ return 0;
+
+error_unreg_buffer:
+ iio_triggered_buffer_cleanup(indio_dev);
+ return ret;
+}
+
+static int ltr501_powerdown(struct ltr501_data *data)
+{
+ return ltr501_write_contr(data->client,
+ data->als_contr & ~LTR501_CONTR_ACTIVE,
+ data->ps_contr & ~LTR501_CONTR_ACTIVE);
+}
+
+static int ltr501_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+ iio_device_unregister(indio_dev);
+ iio_triggered_buffer_cleanup(indio_dev);
+ ltr501_powerdown(iio_priv(indio_dev));
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ltr501_suspend(struct device *dev)
+{
+ struct ltr501_data *data = iio_priv(i2c_get_clientdata(
+ to_i2c_client(dev)));
+ return ltr501_powerdown(data);
+}
+
+static int ltr501_resume(struct device *dev)
+{
+ struct ltr501_data *data = iio_priv(i2c_get_clientdata(
+ to_i2c_client(dev)));
+
+ return ltr501_write_contr(data->client, data->als_contr,
+ data->ps_contr);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(ltr501_pm_ops, ltr501_suspend, ltr501_resume);
+
+static const struct i2c_device_id ltr501_id[] = {
+ { "ltr501", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ltr501_id);
+
+static struct i2c_driver ltr501_driver = {
+ .driver = {
+ .name = LTR501_DRV_NAME,
+ .pm = &ltr501_pm_ops,
+ .owner = THIS_MODULE,
+ },
+ .probe = ltr501_probe,
+ .remove = ltr501_remove,
+ .id_table = ltr501_id,
+};
+
+module_i2c_driver(ltr501_driver);
+
+MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
+MODULE_DESCRIPTION("Lite-On LTR501 ambient light and proximity sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c
index 887fecf1f9bb..fe063a0a21cd 100644
--- a/drivers/iio/light/tcs3472.c
+++ b/drivers/iio/light/tcs3472.c
@@ -179,7 +179,6 @@ static irqreturn_t tcs3472_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct tcs3472_data *data = iio_priv(indio_dev);
- int len = 0;
int i, j = 0;
int ret = tcs3472_req_data(data);
@@ -194,7 +193,6 @@ static irqreturn_t tcs3472_trigger_handler(int irq, void *p)
goto done;
data->buffer[j++] = ret;
- len += 2;
}
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c
index 3d8110157f2d..94daa9fc1247 100644
--- a/drivers/iio/light/tsl2563.c
+++ b/drivers/iio/light/tsl2563.c
@@ -460,10 +460,14 @@ static int tsl2563_write_raw(struct iio_dev *indio_dev,
{
struct tsl2563_chip *chip = iio_priv(indio_dev);
- if (chan->channel == IIO_MOD_LIGHT_BOTH)
+ if (mask != IIO_CHAN_INFO_CALIBSCALE)
+ return -EINVAL;
+ if (chan->channel2 == IIO_MOD_LIGHT_BOTH)
chip->calib0 = calib_from_sysfs(val);
- else
+ else if (chan->channel2 == IIO_MOD_LIGHT_IR)
chip->calib1 = calib_from_sysfs(val);
+ else
+ return -EINVAL;
return 0;
}
@@ -472,14 +476,14 @@ static int tsl2563_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
- long m)
+ long mask)
{
int ret = -EINVAL;
u32 calib0, calib1;
struct tsl2563_chip *chip = iio_priv(indio_dev);
mutex_lock(&chip->lock);
- switch (m) {
+ switch (mask) {
case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
@@ -498,7 +502,7 @@ static int tsl2563_read_raw(struct iio_dev *indio_dev,
ret = tsl2563_get_adc(chip);
if (ret)
goto error_ret;
- if (chan->channel == 0)
+ if (chan->channel2 == IIO_MOD_LIGHT_BOTH)
*val = chip->data0;
else
*val = chip->data1;
@@ -510,7 +514,7 @@ static int tsl2563_read_raw(struct iio_dev *indio_dev,
break;
case IIO_CHAN_INFO_CALIBSCALE:
- if (chan->channel == 0)
+ if (chan->channel2 == IIO_MOD_LIGHT_BOTH)
*val = calib_to_sysfs(chip->calib0);
else
*val = calib_to_sysfs(chip->calib1);
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index ff284e5afd95..74866d1efd1b 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -85,6 +85,7 @@
#define AK8975_MAX_CONVERSION_TIMEOUT 500
#define AK8975_CONVERSION_DONE_POLL_TIME 10
#define AK8975_DATA_READY_TIMEOUT ((100*HZ)/1000)
+#define RAW_TO_GAUSS(asa) ((((asa) + 128) * 3000) / 256)
/*
* Per-instance context data for the device.
@@ -265,15 +266,15 @@ static int ak8975_setup(struct i2c_client *client)
*
* Since 1uT = 0.01 gauss, our final scale factor becomes:
*
- * Hadj = H * ((ASA + 128) / 256) * 3/10 * 100
- * Hadj = H * ((ASA + 128) * 30 / 256
+ * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
+ * Hadj = H * ((ASA + 128) * 0.003) / 256
*
* Since ASA doesn't change, we cache the resultant scale factor into the
* device context in ak8975_setup().
*/
- data->raw_to_gauss[0] = ((data->asa[0] + 128) * 30) >> 8;
- data->raw_to_gauss[1] = ((data->asa[1] + 128) * 30) >> 8;
- data->raw_to_gauss[2] = ((data->asa[2] + 128) * 30) >> 8;
+ data->raw_to_gauss[0] = RAW_TO_GAUSS(data->asa[0]);
+ data->raw_to_gauss[1] = RAW_TO_GAUSS(data->asa[1]);
+ data->raw_to_gauss[2] = RAW_TO_GAUSS(data->asa[2]);
return 0;
}
@@ -428,8 +429,9 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_RAW:
return ak8975_read_axis(indio_dev, chan->address, val);
case IIO_CHAN_INFO_SCALE:
- *val = data->raw_to_gauss[chan->address];
- return IIO_VAL_INT;
+ *val = 0;
+ *val2 = data->raw_to_gauss[chan->address];
+ return IIO_VAL_INT_PLUS_MICRO;
}
return -EINVAL;
}
@@ -511,6 +513,7 @@ static int ak8975_probe(struct i2c_client *client,
indio_dev->channels = ak8975_channels;
indio_dev->num_channels = ARRAY_SIZE(ak8975_channels);
indio_dev->info = &ak8975_info;
+ indio_dev->name = id->name;
indio_dev->modes = INDIO_DIRECT_MODE;
err = iio_device_register(indio_dev);
diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c
index 4b65b6d3bdb1..8b77782474d7 100644
--- a/drivers/iio/magnetometer/mag3110.c
+++ b/drivers/iio/magnetometer/mag3110.c
@@ -106,7 +106,7 @@ static ssize_t mag3110_show_int_plus_micros(char *buf,
while (n-- > 0)
len += scnprintf(buf + len, PAGE_SIZE - len,
- "%d.%d ", vals[n][0], vals[n][1]);
+ "%d.%06d ", vals[n][0], vals[n][1]);
/* replace trailing space by newline */
buf[len - 1] = '\n';
@@ -154,6 +154,9 @@ static int mag3110_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
+ if (iio_buffer_enabled(indio_dev))
+ return -EBUSY;
+
switch (chan->type) {
case IIO_MAGN: /* in 0.1 uT / LSB */
ret = mag3110_read(data, buffer);
@@ -180,9 +183,17 @@ static int mag3110_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
case IIO_CHAN_INFO_SCALE:
- *val = 0;
- *val2 = 1000;
- return IIO_VAL_INT_PLUS_MICRO;
+ switch (chan->type) {
+ case IIO_MAGN:
+ *val = 0;
+ *val2 = 1000;
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_TEMP:
+ *val = 1000;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
case IIO_CHAN_INFO_SAMP_FREQ:
i = data->ctrl_reg1 >> MAG3110_CTRL_DR_SHIFT;
*val = mag3110_samp_freq[i][0];
@@ -199,6 +210,9 @@ static int mag3110_write_raw(struct iio_dev *indio_dev,
struct mag3110_data *data = iio_priv(indio_dev);
int rate;
+ if (iio_buffer_enabled(indio_dev))
+ return -EBUSY;
+
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
rate = mag3110_get_samp_freq_index(data, val, val2);
@@ -264,7 +278,8 @@ static const struct iio_chan_spec mag3110_channels[] = {
MAG3110_CHANNEL(Z, 2),
{
.type = IIO_TEMP,
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
.scan_index = 3,
.scan_type = {
.sign = 's',
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
index a8b9cae5c173..d88ff17fedb2 100644
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -5,6 +5,20 @@
menu "Pressure sensors"
+config HID_SENSOR_PRESS
+ depends on HID_SENSOR_HUB
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ select HID_SENSOR_IIO_COMMON
+ select HID_SENSOR_IIO_TRIGGER
+ tristate "HID PRESS"
+ help
+ Say yes here to build support for the HID SENSOR
+ Pressure driver
+
+ To compile this driver as a module, choose M here: the module
+ will be called hid-sensor-press.
+
config MPL3115
tristate "Freescale MPL3115A2 pressure sensor driver"
depends on I2C
@@ -26,7 +40,7 @@ config IIO_ST_PRESS
select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
help
Say yes here to build support for STMicroelectronics pressure
- sensors: LPS001WP, LPS331AP.
+ sensors: LPS001WP, LPS25H, LPS331AP.
This driver can also be built as a module. If so, these modules
will be created:
diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile
index 42bb9fcf5436..4a57bf65b04b 100644
--- a/drivers/iio/pressure/Makefile
+++ b/drivers/iio/pressure/Makefile
@@ -3,6 +3,7 @@
#
# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o
obj-$(CONFIG_MPL3115) += mpl3115.o
obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o
st_pressure-y := st_pressure_core.o
diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c
new file mode 100644
index 000000000000..e0e6409aa94e
--- /dev/null
+++ b/drivers/iio/pressure/hid-sensor-press.c
@@ -0,0 +1,376 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.
+ *
+ */
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/hid-sensor-hub.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include "../common/hid-sensors/hid-sensor-trigger.h"
+
+#define CHANNEL_SCAN_INDEX_PRESSURE 0
+
+struct press_state {
+ struct hid_sensor_hub_callbacks callbacks;
+ struct hid_sensor_common common_attributes;
+ struct hid_sensor_hub_attribute_info press_attr;
+ u32 press_data;
+};
+
+/* Channel definitions */
+static const struct iio_chan_spec press_channels[] = {
+ {
+ .type = IIO_PRESSURE,
+ .modified = 1,
+ .channel2 = IIO_NO_MOD,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
+ .scan_index = CHANNEL_SCAN_INDEX_PRESSURE,
+ }
+};
+
+/* Adjust channel real bits based on report descriptor */
+static void press_adjust_channel_bit_mask(struct iio_chan_spec *channels,
+ int channel, int size)
+{
+ channels[channel].scan_type.sign = 's';
+ /* Real storage bits will change based on the report desc. */
+ channels[channel].scan_type.realbits = size * 8;
+ /* Maximum size of a sample to capture is u32 */
+ channels[channel].scan_type.storagebits = sizeof(u32) * 8;
+}
+
+/* Channel read_raw handler */
+static int press_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2,
+ long mask)
+{
+ struct press_state *press_state = iio_priv(indio_dev);
+ int report_id = -1;
+ u32 address;
+ int ret;
+ int ret_type;
+
+ *val = 0;
+ *val2 = 0;
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->scan_index) {
+ case CHANNEL_SCAN_INDEX_PRESSURE:
+ report_id = press_state->press_attr.report_id;
+ address =
+ HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE;
+ break;
+ default:
+ report_id = -1;
+ break;
+ }
+ if (report_id >= 0)
+ *val = sensor_hub_input_attr_get_raw_value(
+ press_state->common_attributes.hsdev,
+ HID_USAGE_SENSOR_PRESSURE, address,
+ report_id);
+ else {
+ *val = 0;
+ return -EINVAL;
+ }
+ ret_type = IIO_VAL_INT;
+ break;
+ case IIO_CHAN_INFO_SCALE:
+ *val = press_state->press_attr.units;
+ ret_type = IIO_VAL_INT;
+ break;
+ case IIO_CHAN_INFO_OFFSET:
+ *val = hid_sensor_convert_exponent(
+ press_state->press_attr.unit_expo);
+ ret_type = IIO_VAL_INT;
+ break;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = hid_sensor_read_samp_freq_value(
+ &press_state->common_attributes, val, val2);
+ ret_type = IIO_VAL_INT_PLUS_MICRO;
+ break;
+ case IIO_CHAN_INFO_HYSTERESIS:
+ ret = hid_sensor_read_raw_hyst_value(
+ &press_state->common_attributes, val, val2);
+ ret_type = IIO_VAL_INT_PLUS_MICRO;
+ break;
+ default:
+ ret_type = -EINVAL;
+ break;
+ }
+
+ return ret_type;
+}
+
+/* Channel write_raw handler */
+static int press_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ struct press_state *press_state = iio_priv(indio_dev);
+ int ret = 0;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = hid_sensor_write_samp_freq_value(
+ &press_state->common_attributes, val, val2);
+ break;
+ case IIO_CHAN_INFO_HYSTERESIS:
+ ret = hid_sensor_write_raw_hyst_value(
+ &press_state->common_attributes, val, val2);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct iio_info press_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = &press_read_raw,
+ .write_raw = &press_write_raw,
+};
+
+/* Function to push data to buffer */
+static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data,
+ int len)
+{
+ dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
+ iio_push_to_buffers(indio_dev, data);
+}
+
+/* Callback handler to send event after all samples are received and captured */
+static int press_proc_event(struct hid_sensor_hub_device *hsdev,
+ unsigned usage_id,
+ void *priv)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(priv);
+ struct press_state *press_state = iio_priv(indio_dev);
+
+ dev_dbg(&indio_dev->dev, "press_proc_event [%d]\n",
+ press_state->common_attributes.data_ready);
+ if (press_state->common_attributes.data_ready)
+ hid_sensor_push_data(indio_dev,
+ &press_state->press_data,
+ sizeof(press_state->press_data));
+
+ return 0;
+}
+
+/* Capture samples in local storage */
+static int press_capture_sample(struct hid_sensor_hub_device *hsdev,
+ unsigned usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(priv);
+ struct press_state *press_state = iio_priv(indio_dev);
+ int ret = -EINVAL;
+
+ switch (usage_id) {
+ case HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE:
+ press_state->press_data = *(u32 *)raw_data;
+ ret = 0;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/* Parse report which is specific to an usage id*/
+static int press_parse_report(struct platform_device *pdev,
+ struct hid_sensor_hub_device *hsdev,
+ struct iio_chan_spec *channels,
+ unsigned usage_id,
+ struct press_state *st)
+{
+ int ret;
+
+ ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+ usage_id,
+ HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE,
+ &st->press_attr);
+ if (ret < 0)
+ return ret;
+ press_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_PRESSURE,
+ st->press_attr.size);
+
+ dev_dbg(&pdev->dev, "press %x:%x\n", st->press_attr.index,
+ st->press_attr.report_id);
+
+ /* Set Sensitivity field ids, when there is no individual modifier */
+ if (st->common_attributes.sensitivity.index < 0) {
+ sensor_hub_input_get_attribute_info(hsdev,
+ HID_FEATURE_REPORT, usage_id,
+ HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
+ HID_USAGE_SENSOR_DATA_ATMOSPHERIC_PRESSURE,
+ &st->common_attributes.sensitivity);
+ dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
+ st->common_attributes.sensitivity.index,
+ st->common_attributes.sensitivity.report_id);
+ }
+ return ret;
+}
+
+/* Function to initialize the processing for usage id */
+static int hid_press_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ static const char *name = "press";
+ struct iio_dev *indio_dev;
+ struct press_state *press_state;
+ struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
+ struct iio_chan_spec *channels;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev,
+ sizeof(struct press_state));
+ if (!indio_dev)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, indio_dev);
+
+ press_state = iio_priv(indio_dev);
+ press_state->common_attributes.hsdev = hsdev;
+ press_state->common_attributes.pdev = pdev;
+
+ ret = hid_sensor_parse_common_attributes(hsdev,
+ HID_USAGE_SENSOR_PRESSURE,
+ &press_state->common_attributes);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to setup common attributes\n");
+ return ret;
+ }
+
+ channels = kmemdup(press_channels, sizeof(press_channels), GFP_KERNEL);
+ if (!channels) {
+ dev_err(&pdev->dev, "failed to duplicate channels\n");
+ return -ENOMEM;
+ }
+
+ ret = press_parse_report(pdev, hsdev, channels,
+ HID_USAGE_SENSOR_PRESSURE, press_state);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to setup attributes\n");
+ goto error_free_dev_mem;
+ }
+
+ indio_dev->channels = channels;
+ indio_dev->num_channels =
+ ARRAY_SIZE(press_channels);
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->info = &press_info;
+ indio_dev->name = name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+ NULL, NULL);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
+ goto error_free_dev_mem;
+ }
+ press_state->common_attributes.data_ready = false;
+ ret = hid_sensor_setup_trigger(indio_dev, name,
+ &press_state->common_attributes);
+ if (ret) {
+ dev_err(&pdev->dev, "trigger setup failed\n");
+ goto error_unreg_buffer_funcs;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_trigger;
+ }
+
+ press_state->callbacks.send_event = press_proc_event;
+ press_state->callbacks.capture_sample = press_capture_sample;
+ press_state->callbacks.pdev = pdev;
+ ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_PRESSURE,
+ &press_state->callbacks);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "callback reg failed\n");
+ goto error_iio_unreg;
+ }
+
+ return ret;
+
+error_iio_unreg:
+ iio_device_unregister(indio_dev);
+error_remove_trigger:
+ hid_sensor_remove_trigger(&press_state->common_attributes);
+error_unreg_buffer_funcs:
+ iio_triggered_buffer_cleanup(indio_dev);
+error_free_dev_mem:
+ kfree(indio_dev->channels);
+ return ret;
+}
+
+/* Function to deinitialize the processing for usage id */
+static int hid_press_remove(struct platform_device *pdev)
+{
+ struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct press_state *press_state = iio_priv(indio_dev);
+
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE);
+ iio_device_unregister(indio_dev);
+ hid_sensor_remove_trigger(&press_state->common_attributes);
+ iio_triggered_buffer_cleanup(indio_dev);
+ kfree(indio_dev->channels);
+
+ return 0;
+}
+
+static struct platform_device_id hid_press_ids[] = {
+ {
+ /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
+ .name = "HID-SENSOR-200031",
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, hid_press_ids);
+
+static struct platform_driver hid_press_platform_driver = {
+ .id_table = hid_press_ids,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = hid_press_probe,
+ .remove = hid_press_remove,
+};
+module_platform_driver(hid_press_platform_driver);
+
+MODULE_DESCRIPTION("HID Sensor Pressure");
+MODULE_AUTHOR("Archana Patni <archana.patni@intel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c
index ac8c8ab723e5..ba6d0c520e63 100644
--- a/drivers/iio/pressure/mpl3115.c
+++ b/drivers/iio/pressure/mpl3115.c
@@ -77,7 +77,7 @@ static int mpl3115_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct mpl3115_data *data = iio_priv(indio_dev);
- s32 tmp = 0;
+ __be32 tmp = 0;
int ret;
switch (mask) {
diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h
index 049c21acf1f0..242943c0c4e4 100644
--- a/drivers/iio/pressure/st_pressure.h
+++ b/drivers/iio/pressure/st_pressure.h
@@ -15,6 +15,7 @@
#include <linux/iio/common/st_sensors.h>
#define LPS001WP_PRESS_DEV_NAME "lps001wp"
+#define LPS25H_PRESS_DEV_NAME "lps25h"
#define LPS331AP_PRESS_DEV_NAME "lps331ap"
/**
diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c
index 58083f9d51c5..7418768ed49c 100644
--- a/drivers/iio/pressure/st_pressure_core.c
+++ b/drivers/iio/pressure/st_pressure_core.c
@@ -40,6 +40,9 @@
/* FULLSCALE */
#define ST_PRESS_FS_AVL_1260MB 1260
+#define ST_PRESS_1_OUT_XL_ADDR 0x28
+#define ST_TEMP_1_OUT_L_ADDR 0x2b
+
/* CUSTOM VALUES FOR LPS331AP SENSOR */
#define ST_PRESS_LPS331AP_WAI_EXP 0xbb
#define ST_PRESS_LPS331AP_ODR_ADDR 0x20
@@ -62,8 +65,6 @@
#define ST_PRESS_LPS331AP_DRDY_IRQ_INT2_MASK 0x20
#define ST_PRESS_LPS331AP_MULTIREAD_BIT true
#define ST_PRESS_LPS331AP_TEMP_OFFSET 42500
-#define ST_PRESS_LPS331AP_OUT_XL_ADDR 0x28
-#define ST_TEMP_LPS331AP_OUT_L_ADDR 0x2b
/* CUSTOM VALUES FOR LPS001WP SENSOR */
#define ST_PRESS_LPS001WP_WAI_EXP 0xba
@@ -80,11 +81,36 @@
#define ST_PRESS_LPS001WP_OUT_L_ADDR 0x28
#define ST_TEMP_LPS001WP_OUT_L_ADDR 0x2a
-static const struct iio_chan_spec st_press_lps331ap_channels[] = {
+/* CUSTOM VALUES FOR LPS25H SENSOR */
+#define ST_PRESS_LPS25H_WAI_EXP 0xbd
+#define ST_PRESS_LPS25H_ODR_ADDR 0x20
+#define ST_PRESS_LPS25H_ODR_MASK 0x70
+#define ST_PRESS_LPS25H_ODR_AVL_1HZ_VAL 0x01
+#define ST_PRESS_LPS25H_ODR_AVL_7HZ_VAL 0x02
+#define ST_PRESS_LPS25H_ODR_AVL_13HZ_VAL 0x03
+#define ST_PRESS_LPS25H_ODR_AVL_25HZ_VAL 0x04
+#define ST_PRESS_LPS25H_PW_ADDR 0x20
+#define ST_PRESS_LPS25H_PW_MASK 0x80
+#define ST_PRESS_LPS25H_FS_ADDR 0x00
+#define ST_PRESS_LPS25H_FS_MASK 0x00
+#define ST_PRESS_LPS25H_FS_AVL_1260_VAL 0x00
+#define ST_PRESS_LPS25H_FS_AVL_1260_GAIN ST_PRESS_KPASCAL_NANO_SCALE
+#define ST_PRESS_LPS25H_FS_AVL_TEMP_GAIN ST_PRESS_CELSIUS_NANO_SCALE
+#define ST_PRESS_LPS25H_BDU_ADDR 0x20
+#define ST_PRESS_LPS25H_BDU_MASK 0x04
+#define ST_PRESS_LPS25H_DRDY_IRQ_ADDR 0x23
+#define ST_PRESS_LPS25H_DRDY_IRQ_INT1_MASK 0x01
+#define ST_PRESS_LPS25H_DRDY_IRQ_INT2_MASK 0x10
+#define ST_PRESS_LPS25H_MULTIREAD_BIT true
+#define ST_PRESS_LPS25H_TEMP_OFFSET 42500
+#define ST_PRESS_LPS25H_OUT_XL_ADDR 0x28
+#define ST_TEMP_LPS25H_OUT_L_ADDR 0x2b
+
+static const struct iio_chan_spec st_press_1_channels[] = {
{
.type = IIO_PRESSURE,
.channel2 = IIO_NO_MOD,
- .address = ST_PRESS_LPS331AP_OUT_XL_ADDR,
+ .address = ST_PRESS_1_OUT_XL_ADDR,
.scan_index = ST_SENSORS_SCAN_X,
.scan_type = {
.sign = 'u',
@@ -99,7 +125,7 @@ static const struct iio_chan_spec st_press_lps331ap_channels[] = {
{
.type = IIO_TEMP,
.channel2 = IIO_NO_MOD,
- .address = ST_TEMP_LPS331AP_OUT_L_ADDR,
+ .address = ST_TEMP_1_OUT_L_ADDR,
.scan_index = -1,
.scan_type = {
.sign = 'u',
@@ -156,8 +182,8 @@ static const struct st_sensors st_press_sensors[] = {
.sensors_supported = {
[0] = LPS331AP_PRESS_DEV_NAME,
},
- .ch = (struct iio_chan_spec *)st_press_lps331ap_channels,
- .num_ch = ARRAY_SIZE(st_press_lps331ap_channels),
+ .ch = (struct iio_chan_spec *)st_press_1_channels,
+ .num_ch = ARRAY_SIZE(st_press_1_channels),
.odr = {
.addr = ST_PRESS_LPS331AP_ODR_ADDR,
.mask = ST_PRESS_LPS331AP_ODR_MASK,
@@ -233,6 +259,53 @@ static const struct st_sensors st_press_sensors[] = {
.multi_read_bit = ST_PRESS_LPS001WP_MULTIREAD_BIT,
.bootime = 2,
},
+ {
+ .wai = ST_PRESS_LPS25H_WAI_EXP,
+ .sensors_supported = {
+ [0] = LPS25H_PRESS_DEV_NAME,
+ },
+ .ch = (struct iio_chan_spec *)st_press_1_channels,
+ .num_ch = ARRAY_SIZE(st_press_1_channels),
+ .odr = {
+ .addr = ST_PRESS_LPS25H_ODR_ADDR,
+ .mask = ST_PRESS_LPS25H_ODR_MASK,
+ .odr_avl = {
+ { 1, ST_PRESS_LPS25H_ODR_AVL_1HZ_VAL, },
+ { 7, ST_PRESS_LPS25H_ODR_AVL_7HZ_VAL, },
+ { 13, ST_PRESS_LPS25H_ODR_AVL_13HZ_VAL, },
+ { 25, ST_PRESS_LPS25H_ODR_AVL_25HZ_VAL, },
+ },
+ },
+ .pw = {
+ .addr = ST_PRESS_LPS25H_PW_ADDR,
+ .mask = ST_PRESS_LPS25H_PW_MASK,
+ .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
+ .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
+ },
+ .fs = {
+ .addr = ST_PRESS_LPS25H_FS_ADDR,
+ .mask = ST_PRESS_LPS25H_FS_MASK,
+ .fs_avl = {
+ [0] = {
+ .num = ST_PRESS_FS_AVL_1260MB,
+ .value = ST_PRESS_LPS25H_FS_AVL_1260_VAL,
+ .gain = ST_PRESS_LPS25H_FS_AVL_1260_GAIN,
+ .gain2 = ST_PRESS_LPS25H_FS_AVL_TEMP_GAIN,
+ },
+ },
+ },
+ .bdu = {
+ .addr = ST_PRESS_LPS25H_BDU_ADDR,
+ .mask = ST_PRESS_LPS25H_BDU_MASK,
+ },
+ .drdy_irq = {
+ .addr = ST_PRESS_LPS25H_DRDY_IRQ_ADDR,
+ .mask_int1 = ST_PRESS_LPS25H_DRDY_IRQ_INT1_MASK,
+ .mask_int2 = ST_PRESS_LPS25H_DRDY_IRQ_INT2_MASK,
+ },
+ .multi_read_bit = ST_PRESS_LPS25H_MULTIREAD_BIT,
+ .bootime = 2,
+ },
};
static int st_press_read_raw(struct iio_dev *indio_dev,
diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c
index 51eab7fcb194..3cd73e39b840 100644
--- a/drivers/iio/pressure/st_pressure_i2c.c
+++ b/drivers/iio/pressure/st_pressure_i2c.c
@@ -50,6 +50,7 @@ static int st_press_i2c_remove(struct i2c_client *client)
static const struct i2c_device_id st_press_id_table[] = {
{ LPS001WP_PRESS_DEV_NAME },
+ { LPS25H_PRESS_DEV_NAME },
{ LPS331AP_PRESS_DEV_NAME },
{},
};
diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c
index 27322af6d665..f45d430ec529 100644
--- a/drivers/iio/pressure/st_pressure_spi.c
+++ b/drivers/iio/pressure/st_pressure_spi.c
@@ -49,6 +49,7 @@ static int st_press_spi_remove(struct spi_device *spi)
static const struct spi_device_id st_press_id_table[] = {
{ LPS001WP_PRESS_DEV_NAME },
+ { LPS25H_PRESS_DEV_NAME },
{ LPS331AP_PRESS_DEV_NAME },
{},
};
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 0601b9daf840..c3239170d8b7 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -349,23 +349,6 @@ static void cm_init_av_for_response(struct cm_port *port, struct ib_wc *wc,
grh, &av->ah_attr);
}
-int ib_update_cm_av(struct ib_cm_id *id, const u8 *smac, const u8 *alt_smac)
-{
- struct cm_id_private *cm_id_priv;
-
- cm_id_priv = container_of(id, struct cm_id_private, id);
-
- if (smac != NULL)
- memcpy(cm_id_priv->av.smac, smac, sizeof(cm_id_priv->av.smac));
-
- if (alt_smac != NULL)
- memcpy(cm_id_priv->alt_av.smac, alt_smac,
- sizeof(cm_id_priv->alt_av.smac));
-
- return 0;
-}
-EXPORT_SYMBOL(ib_update_cm_av);
-
static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
{
struct cm_device *cm_dev;
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 199958d9ddc8..42c3058e6e9c 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -1284,15 +1284,6 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
struct rdma_id_private *listen_id, *conn_id;
struct rdma_cm_event event;
int offset, ret;
- u8 smac[ETH_ALEN];
- u8 alt_smac[ETH_ALEN];
- u8 *psmac = smac;
- u8 *palt_smac = alt_smac;
- int is_iboe = ((rdma_node_get_transport(cm_id->device->node_type) ==
- RDMA_TRANSPORT_IB) &&
- (rdma_port_get_link_layer(cm_id->device,
- ib_event->param.req_rcvd.port) ==
- IB_LINK_LAYER_ETHERNET));
listen_id = cm_id->context;
if (!cma_check_req_qp_type(&listen_id->id, ib_event))
@@ -1336,28 +1327,11 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
ret = conn_id->id.event_handler(&conn_id->id, &event);
if (ret)
goto err3;
-
- if (is_iboe) {
- if (ib_event->param.req_rcvd.primary_path != NULL)
- rdma_addr_find_smac_by_sgid(
- &ib_event->param.req_rcvd.primary_path->sgid,
- psmac, NULL);
- else
- psmac = NULL;
- if (ib_event->param.req_rcvd.alternate_path != NULL)
- rdma_addr_find_smac_by_sgid(
- &ib_event->param.req_rcvd.alternate_path->sgid,
- palt_smac, NULL);
- else
- palt_smac = NULL;
- }
/*
* Acquire mutex to prevent user executing rdma_destroy_id()
* while we're accessing the cm_id.
*/
mutex_lock(&lock);
- if (is_iboe)
- ib_update_cm_av(cm_id, psmac, palt_smac);
if (cma_comp(conn_id, RDMA_CM_CONNECT) &&
(conn_id->id.qp_type != IB_QPT_UD))
ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0);
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 4c837e66516b..ab31f136d04b 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -1022,12 +1022,21 @@ int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr)
mad_send_wr->send_buf.mad,
sge[0].length,
DMA_TO_DEVICE);
+ if (unlikely(ib_dma_mapping_error(mad_agent->device, sge[0].addr)))
+ return -ENOMEM;
+
mad_send_wr->header_mapping = sge[0].addr;
sge[1].addr = ib_dma_map_single(mad_agent->device,
ib_get_payload(mad_send_wr),
sge[1].length,
DMA_TO_DEVICE);
+ if (unlikely(ib_dma_mapping_error(mad_agent->device, sge[1].addr))) {
+ ib_dma_unmap_single(mad_agent->device,
+ mad_send_wr->header_mapping,
+ sge[0].length, DMA_TO_DEVICE);
+ return -ENOMEM;
+ }
mad_send_wr->payload_mapping = sge[1].addr;
spin_lock_irqsave(&qp_info->send_queue.lock, flags);
@@ -2590,6 +2599,11 @@ static int ib_mad_post_receive_mads(struct ib_mad_qp_info *qp_info,
sizeof *mad_priv -
sizeof mad_priv->header,
DMA_FROM_DEVICE);
+ if (unlikely(ib_dma_mapping_error(qp_info->port_priv->device,
+ sg_list.addr))) {
+ ret = -ENOMEM;
+ break;
+ }
mad_priv->header.mapping = sg_list.addr;
recv_wr.wr_id = (unsigned long)&mad_priv->header.mad_list;
mad_priv->header.mad_list.mad_queue = recv_queue;
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index a84112322071..a3a2e9c1639b 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -42,29 +42,29 @@
#include "uverbs.h"
-#define IB_UMEM_MAX_PAGE_CHUNK \
- ((PAGE_SIZE - offsetof(struct ib_umem_chunk, page_list)) / \
- ((void *) &((struct ib_umem_chunk *) 0)->page_list[1] - \
- (void *) &((struct ib_umem_chunk *) 0)->page_list[0]))
static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int dirty)
{
- struct ib_umem_chunk *chunk, *tmp;
+ struct scatterlist *sg;
+ struct page *page;
int i;
- list_for_each_entry_safe(chunk, tmp, &umem->chunk_list, list) {
- ib_dma_unmap_sg(dev, chunk->page_list,
- chunk->nents, DMA_BIDIRECTIONAL);
- for (i = 0; i < chunk->nents; ++i) {
- struct page *page = sg_page(&chunk->page_list[i]);
+ if (umem->nmap > 0)
+ ib_dma_unmap_sg(dev, umem->sg_head.sgl,
+ umem->nmap,
+ DMA_BIDIRECTIONAL);
- if (umem->writable && dirty)
- set_page_dirty_lock(page);
- put_page(page);
- }
+ for_each_sg(umem->sg_head.sgl, sg, umem->npages, i) {
- kfree(chunk);
+ page = sg_page(sg);
+ if (umem->writable && dirty)
+ set_page_dirty_lock(page);
+ put_page(page);
}
+
+ sg_free_table(&umem->sg_head);
+ return;
+
}
/**
@@ -81,15 +81,15 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
struct ib_umem *umem;
struct page **page_list;
struct vm_area_struct **vma_list;
- struct ib_umem_chunk *chunk;
unsigned long locked;
unsigned long lock_limit;
unsigned long cur_base;
unsigned long npages;
int ret;
- int off;
int i;
DEFINE_DMA_ATTRS(attrs);
+ struct scatterlist *sg, *sg_list_start;
+ int need_release = 0;
if (dmasync)
dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs);
@@ -97,7 +97,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
if (!can_do_mlock())
return ERR_PTR(-EPERM);
- umem = kmalloc(sizeof *umem, GFP_KERNEL);
+ umem = kzalloc(sizeof *umem, GFP_KERNEL);
if (!umem)
return ERR_PTR(-ENOMEM);
@@ -117,8 +117,6 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
/* We assume the memory is from hugetlb until proved otherwise */
umem->hugetlb = 1;
- INIT_LIST_HEAD(&umem->chunk_list);
-
page_list = (struct page **) __get_free_page(GFP_KERNEL);
if (!page_list) {
kfree(umem);
@@ -147,7 +145,18 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
cur_base = addr & PAGE_MASK;
- ret = 0;
+ if (npages == 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = sg_alloc_table(&umem->sg_head, npages, GFP_KERNEL);
+ if (ret)
+ goto out;
+
+ need_release = 1;
+ sg_list_start = umem->sg_head.sgl;
+
while (npages) {
ret = get_user_pages(current, current->mm, cur_base,
min_t(unsigned long, npages,
@@ -157,54 +166,38 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
if (ret < 0)
goto out;
+ umem->npages += ret;
cur_base += ret * PAGE_SIZE;
npages -= ret;
- off = 0;
-
- while (ret) {
- chunk = kmalloc(sizeof *chunk + sizeof (struct scatterlist) *
- min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK),
- GFP_KERNEL);
- if (!chunk) {
- ret = -ENOMEM;
- goto out;
- }
-
- chunk->nents = min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK);
- sg_init_table(chunk->page_list, chunk->nents);
- for (i = 0; i < chunk->nents; ++i) {
- if (vma_list &&
- !is_vm_hugetlb_page(vma_list[i + off]))
- umem->hugetlb = 0;
- sg_set_page(&chunk->page_list[i], page_list[i + off], PAGE_SIZE, 0);
- }
-
- chunk->nmap = ib_dma_map_sg_attrs(context->device,
- &chunk->page_list[0],
- chunk->nents,
- DMA_BIDIRECTIONAL,
- &attrs);
- if (chunk->nmap <= 0) {
- for (i = 0; i < chunk->nents; ++i)
- put_page(sg_page(&chunk->page_list[i]));
- kfree(chunk);
-
- ret = -ENOMEM;
- goto out;
- }
-
- ret -= chunk->nents;
- off += chunk->nents;
- list_add_tail(&chunk->list, &umem->chunk_list);
+ for_each_sg(sg_list_start, sg, ret, i) {
+ if (vma_list && !is_vm_hugetlb_page(vma_list[i]))
+ umem->hugetlb = 0;
+
+ sg_set_page(sg, page_list[i], PAGE_SIZE, 0);
}
- ret = 0;
+ /* preparing for next loop */
+ sg_list_start = sg;
}
+ umem->nmap = ib_dma_map_sg_attrs(context->device,
+ umem->sg_head.sgl,
+ umem->npages,
+ DMA_BIDIRECTIONAL,
+ &attrs);
+
+ if (umem->nmap <= 0) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = 0;
+
out:
if (ret < 0) {
- __ib_umem_release(context->device, umem, 0);
+ if (need_release)
+ __ib_umem_release(context->device, umem, 0);
kfree(umem);
} else
current->mm->pinned_vm = locked;
@@ -278,17 +271,16 @@ EXPORT_SYMBOL(ib_umem_release);
int ib_umem_page_count(struct ib_umem *umem)
{
- struct ib_umem_chunk *chunk;
int shift;
int i;
int n;
+ struct scatterlist *sg;
shift = ilog2(umem->page_size);
n = 0;
- list_for_each_entry(chunk, &umem->chunk_list, list)
- for (i = 0; i < chunk->nmap; ++i)
- n += sg_dma_len(&chunk->page_list[i]) >> shift;
+ for_each_sg(umem->sg_head.sgl, sg, umem->nmap, i)
+ n += sg_dma_len(sg) >> shift;
return n;
}
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index 3ac795115438..92525f855d82 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -1169,6 +1169,45 @@ int ib_dereg_mr(struct ib_mr *mr)
}
EXPORT_SYMBOL(ib_dereg_mr);
+struct ib_mr *ib_create_mr(struct ib_pd *pd,
+ struct ib_mr_init_attr *mr_init_attr)
+{
+ struct ib_mr *mr;
+
+ if (!pd->device->create_mr)
+ return ERR_PTR(-ENOSYS);
+
+ mr = pd->device->create_mr(pd, mr_init_attr);
+
+ if (!IS_ERR(mr)) {
+ mr->device = pd->device;
+ mr->pd = pd;
+ mr->uobject = NULL;
+ atomic_inc(&pd->usecnt);
+ atomic_set(&mr->usecnt, 0);
+ }
+
+ return mr;
+}
+EXPORT_SYMBOL(ib_create_mr);
+
+int ib_destroy_mr(struct ib_mr *mr)
+{
+ struct ib_pd *pd;
+ int ret;
+
+ if (atomic_read(&mr->usecnt))
+ return -EBUSY;
+
+ pd = mr->pd;
+ ret = mr->device->destroy_mr(mr);
+ if (!ret)
+ atomic_dec(&pd->usecnt);
+
+ return ret;
+}
+EXPORT_SYMBOL(ib_destroy_mr);
+
struct ib_mr *ib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len)
{
struct ib_mr *mr;
@@ -1398,3 +1437,11 @@ int ib_destroy_flow(struct ib_flow *flow_id)
return err;
}
EXPORT_SYMBOL(ib_destroy_flow);
+
+int ib_check_mr_status(struct ib_mr *mr, u32 check_mask,
+ struct ib_mr_status *mr_status)
+{
+ return mr->device->check_mr_status ?
+ mr->device->check_mr_status(mr, check_mask, mr_status) : -ENOSYS;
+}
+EXPORT_SYMBOL(ib_check_mr_status);
diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c
index d53cf519f42a..00400c352c1a 100644
--- a/drivers/infiniband/hw/amso1100/c2.c
+++ b/drivers/infiniband/hw/amso1100/c2.c
@@ -1082,6 +1082,7 @@ static int c2_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
/* Initialize network device */
if ((netdev = c2_devinit(c2dev, mmio_regs)) == NULL) {
+ ret = -ENOMEM;
iounmap(mmio_regs);
goto bail4;
}
@@ -1151,7 +1152,8 @@ static int c2_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
goto bail10;
}
- if (c2_register_device(c2dev))
+ ret = c2_register_device(c2dev);
+ if (ret)
goto bail10;
return 0;
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c
index 07eb3a8067d8..8af33cf1fc4e 100644
--- a/drivers/infiniband/hw/amso1100/c2_provider.c
+++ b/drivers/infiniband/hw/amso1100/c2_provider.c
@@ -431,9 +431,9 @@ static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
u64 *pages;
u64 kva = 0;
int shift, n, len;
- int i, j, k;
+ int i, k, entry;
int err = 0;
- struct ib_umem_chunk *chunk;
+ struct scatterlist *sg;
struct c2_pd *c2pd = to_c2pd(pd);
struct c2_mr *c2mr;
@@ -452,10 +452,7 @@ static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
}
shift = ffs(c2mr->umem->page_size) - 1;
-
- n = 0;
- list_for_each_entry(chunk, &c2mr->umem->chunk_list, list)
- n += chunk->nents;
+ n = c2mr->umem->nmap;
pages = kmalloc(n * sizeof(u64), GFP_KERNEL);
if (!pages) {
@@ -464,14 +461,12 @@ static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
}
i = 0;
- list_for_each_entry(chunk, &c2mr->umem->chunk_list, list) {
- for (j = 0; j < chunk->nmap; ++j) {
- len = sg_dma_len(&chunk->page_list[j]) >> shift;
- for (k = 0; k < len; ++k) {
- pages[i++] =
- sg_dma_address(&chunk->page_list[j]) +
- (c2mr->umem->page_size * k);
- }
+ for_each_sg(c2mr->umem->sg_head.sgl, sg, c2mr->umem->nmap, entry) {
+ len = sg_dma_len(sg) >> shift;
+ for (k = 0; k < len; ++k) {
+ pages[i++] =
+ sg_dma_address(sg) +
+ (c2mr->umem->page_size * k);
}
}
diff --git a/drivers/infiniband/hw/amso1100/c2_rnic.c b/drivers/infiniband/hw/amso1100/c2_rnic.c
index b7c986990053..d2a6d961344b 100644
--- a/drivers/infiniband/hw/amso1100/c2_rnic.c
+++ b/drivers/infiniband/hw/amso1100/c2_rnic.c
@@ -576,7 +576,8 @@ int c2_rnic_init(struct c2_dev *c2dev)
goto bail4;
/* Initialize cached the adapter limits */
- if (c2_rnic_query(c2dev, &c2dev->props))
+ err = c2_rnic_query(c2dev, &c2dev->props);
+ if (err)
goto bail5;
/* Initialize the PD pool */
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index d2283837d451..811b24a539c0 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -618,14 +618,13 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
{
__be64 *pages;
int shift, n, len;
- int i, j, k;
+ int i, k, entry;
int err = 0;
- struct ib_umem_chunk *chunk;
struct iwch_dev *rhp;
struct iwch_pd *php;
struct iwch_mr *mhp;
struct iwch_reg_user_mr_resp uresp;
-
+ struct scatterlist *sg;
PDBG("%s ib_pd %p\n", __func__, pd);
php = to_iwch_pd(pd);
@@ -645,9 +644,7 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
shift = ffs(mhp->umem->page_size) - 1;
- n = 0;
- list_for_each_entry(chunk, &mhp->umem->chunk_list, list)
- n += chunk->nents;
+ n = mhp->umem->nmap;
err = iwch_alloc_pbl(mhp, n);
if (err)
@@ -661,12 +658,10 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
i = n = 0;
- list_for_each_entry(chunk, &mhp->umem->chunk_list, list)
- for (j = 0; j < chunk->nmap; ++j) {
- len = sg_dma_len(&chunk->page_list[j]) >> shift;
+ for_each_sg(mhp->umem->sg_head.sgl, sg, mhp->umem->nmap, entry) {
+ len = sg_dma_len(sg) >> shift;
for (k = 0; k < len; ++k) {
- pages[i++] = cpu_to_be64(sg_dma_address(
- &chunk->page_list[j]) +
+ pages[i++] = cpu_to_be64(sg_dma_address(sg) +
mhp->umem->page_size * k);
if (i == PAGE_SIZE / sizeof *pages) {
err = iwch_write_pbl(mhp, pages, i, n);
@@ -676,7 +671,7 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
i = 0;
}
}
- }
+ }
if (i)
err = iwch_write_pbl(mhp, pages, i, n);
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index 45126879ad28..02436d5d0dab 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -98,9 +98,9 @@ int c4iw_debug;
module_param(c4iw_debug, int, 0644);
MODULE_PARM_DESC(c4iw_debug, "Enable debug logging (default=0)");
-static int peer2peer;
+static int peer2peer = 1;
module_param(peer2peer, int, 0644);
-MODULE_PARM_DESC(peer2peer, "Support peer2peer ULPs (default=0)");
+MODULE_PARM_DESC(peer2peer, "Support peer2peer ULPs (default=1)");
static int p2p_type = FW_RI_INIT_P2PTYPE_READ_REQ;
module_param(p2p_type, int, 0644);
@@ -400,7 +400,8 @@ static struct dst_entry *find_route(struct c4iw_dev *dev, __be32 local_ip,
n = dst_neigh_lookup(&rt->dst, &peer_ip);
if (!n)
return NULL;
- if (!our_interface(dev, n->dev)) {
+ if (!our_interface(dev, n->dev) &&
+ !(n->dev->flags & IFF_LOOPBACK)) {
dst_release(&rt->dst);
return NULL;
}
@@ -759,8 +760,9 @@ static void send_mpa_req(struct c4iw_ep *ep, struct sk_buff *skb,
ep->mpa_skb = skb;
c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
start_ep_timer(ep);
- state_set(&ep->com, MPA_REQ_SENT);
+ __state_set(&ep->com, MPA_REQ_SENT);
ep->mpa_attr.initiator = 1;
+ ep->snd_seq += mpalen;
return;
}
@@ -840,6 +842,7 @@ static int send_mpa_reject(struct c4iw_ep *ep, const void *pdata, u8 plen)
t4_set_arp_err_handler(skb, NULL, arp_failure_discard);
BUG_ON(ep->mpa_skb);
ep->mpa_skb = skb;
+ ep->snd_seq += mpalen;
return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
}
@@ -923,7 +926,8 @@ static int send_mpa_reply(struct c4iw_ep *ep, const void *pdata, u8 plen)
skb_get(skb);
t4_set_arp_err_handler(skb, NULL, arp_failure_discard);
ep->mpa_skb = skb;
- state_set(&ep->com, MPA_REP_SENT);
+ __state_set(&ep->com, MPA_REP_SENT);
+ ep->snd_seq += mpalen;
return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
}
@@ -940,6 +944,7 @@ static int act_establish(struct c4iw_dev *dev, struct sk_buff *skb)
PDBG("%s ep %p tid %u snd_isn %u rcv_isn %u\n", __func__, ep, tid,
be32_to_cpu(req->snd_isn), be32_to_cpu(req->rcv_isn));
+ mutex_lock(&ep->com.mutex);
dst_confirm(ep->dst);
/* setup the hwtid for this connection */
@@ -963,17 +968,18 @@ static int act_establish(struct c4iw_dev *dev, struct sk_buff *skb)
send_mpa_req(ep, skb, 1);
else
send_mpa_req(ep, skb, mpa_rev);
-
+ mutex_unlock(&ep->com.mutex);
return 0;
}
-static void close_complete_upcall(struct c4iw_ep *ep)
+static void close_complete_upcall(struct c4iw_ep *ep, int status)
{
struct iw_cm_event event;
PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
memset(&event, 0, sizeof(event));
event.event = IW_CM_EVENT_CLOSE;
+ event.status = status;
if (ep->com.cm_id) {
PDBG("close complete delivered ep %p cm_id %p tid %u\n",
ep, ep->com.cm_id, ep->hwtid);
@@ -987,7 +993,6 @@ static void close_complete_upcall(struct c4iw_ep *ep)
static int abort_connection(struct c4iw_ep *ep, struct sk_buff *skb, gfp_t gfp)
{
PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
- close_complete_upcall(ep);
state_set(&ep->com, ABORTING);
set_bit(ABORT_CONN, &ep->com.history);
return send_abort(ep, skb, gfp);
@@ -1066,9 +1071,10 @@ static void connect_reply_upcall(struct c4iw_ep *ep, int status)
}
}
-static void connect_request_upcall(struct c4iw_ep *ep)
+static int connect_request_upcall(struct c4iw_ep *ep)
{
struct iw_cm_event event;
+ int ret;
PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
memset(&event, 0, sizeof(event));
@@ -1093,15 +1099,14 @@ static void connect_request_upcall(struct c4iw_ep *ep)
event.private_data_len = ep->plen;
event.private_data = ep->mpa_pkt + sizeof(struct mpa_message);
}
- if (state_read(&ep->parent_ep->com) != DEAD) {
- c4iw_get_ep(&ep->com);
- ep->parent_ep->com.cm_id->event_handler(
- ep->parent_ep->com.cm_id,
- &event);
- }
+ c4iw_get_ep(&ep->com);
+ ret = ep->parent_ep->com.cm_id->event_handler(ep->parent_ep->com.cm_id,
+ &event);
+ if (ret)
+ c4iw_put_ep(&ep->com);
set_bit(CONNREQ_UPCALL, &ep->com.history);
c4iw_put_ep(&ep->parent_ep->com);
- ep->parent_ep = NULL;
+ return ret;
}
static void established_upcall(struct c4iw_ep *ep)
@@ -1165,7 +1170,7 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
* the connection.
*/
stop_ep_timer(ep);
- if (state_read(&ep->com) != MPA_REQ_SENT)
+ if (ep->com.state != MPA_REQ_SENT)
return;
/*
@@ -1240,7 +1245,7 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
* start reply message including private data. And
* the MPA header is valid.
*/
- state_set(&ep->com, FPDU_MODE);
+ __state_set(&ep->com, FPDU_MODE);
ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0;
ep->mpa_attr.recv_marker_enabled = markers_enabled;
ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0;
@@ -1355,7 +1360,7 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
}
goto out;
err:
- state_set(&ep->com, ABORTING);
+ __state_set(&ep->com, ABORTING);
send_abort(ep, skb, GFP_KERNEL);
out:
connect_reply_upcall(ep, err);
@@ -1370,7 +1375,7 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)
PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
- if (state_read(&ep->com) != MPA_REQ_WAIT)
+ if (ep->com.state != MPA_REQ_WAIT)
return;
/*
@@ -1400,7 +1405,6 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)
return;
PDBG("%s enter (%s line %u)\n", __func__, __FILE__, __LINE__);
- stop_ep_timer(ep);
mpa = (struct mpa_message *) ep->mpa_pkt;
/*
@@ -1492,10 +1496,18 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)
ep->mpa_attr.xmit_marker_enabled, ep->mpa_attr.version,
ep->mpa_attr.p2p_type);
- state_set(&ep->com, MPA_REQ_RCVD);
+ __state_set(&ep->com, MPA_REQ_RCVD);
+ stop_ep_timer(ep);
/* drive upcall */
- connect_request_upcall(ep);
+ mutex_lock(&ep->parent_ep->com.mutex);
+ if (ep->parent_ep->com.state != DEAD) {
+ if (connect_request_upcall(ep))
+ abort_connection(ep, skb, GFP_KERNEL);
+ } else {
+ abort_connection(ep, skb, GFP_KERNEL);
+ }
+ mutex_unlock(&ep->parent_ep->com.mutex);
return;
}
@@ -1509,14 +1521,17 @@ static int rx_data(struct c4iw_dev *dev, struct sk_buff *skb)
__u8 status = hdr->status;
ep = lookup_tid(t, tid);
+ if (!ep)
+ return 0;
PDBG("%s ep %p tid %u dlen %u\n", __func__, ep, ep->hwtid, dlen);
skb_pull(skb, sizeof(*hdr));
skb_trim(skb, dlen);
+ mutex_lock(&ep->com.mutex);
/* update RX credits */
update_rx_credits(ep, dlen);
- switch (state_read(&ep->com)) {
+ switch (ep->com.state) {
case MPA_REQ_SENT:
ep->rcv_seq += dlen;
process_mpa_reply(ep, skb);
@@ -1532,7 +1547,7 @@ static int rx_data(struct c4iw_dev *dev, struct sk_buff *skb)
pr_err("%s Unexpected streaming data." \
" qpid %u ep %p state %d tid %u status %d\n",
__func__, ep->com.qp->wq.sq.qid, ep,
- state_read(&ep->com), ep->hwtid, status);
+ ep->com.state, ep->hwtid, status);
attrs.next_state = C4IW_QP_STATE_TERMINATE;
c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
C4IW_QP_ATTR_NEXT_STATE, &attrs, 0);
@@ -1541,6 +1556,7 @@ static int rx_data(struct c4iw_dev *dev, struct sk_buff *skb)
default:
break;
}
+ mutex_unlock(&ep->com.mutex);
return 0;
}
@@ -1647,6 +1663,15 @@ static inline int act_open_has_tid(int status)
status != CPL_ERR_ARP_MISS;
}
+/* Returns whether a CPL status conveys negative advice.
+ */
+static int is_neg_adv(unsigned int status)
+{
+ return status == CPL_ERR_RTX_NEG_ADVICE ||
+ status == CPL_ERR_PERSIST_NEG_ADVICE ||
+ status == CPL_ERR_KEEPALV_NEG_ADVICE;
+}
+
#define ACT_OPEN_RETRY_COUNT 2
static int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip,
@@ -1835,7 +1860,7 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
PDBG("%s ep %p atid %u status %u errno %d\n", __func__, ep, atid,
status, status2errno(status));
- if (status == CPL_ERR_RTX_NEG_ADVICE) {
+ if (is_neg_adv(status)) {
printk(KERN_WARNING MOD "Connection problems for atid %u\n",
atid);
return 0;
@@ -2246,7 +2271,7 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
}
- close_complete_upcall(ep);
+ close_complete_upcall(ep, 0);
__state_set(&ep->com, DEAD);
release = 1;
disconnect = 0;
@@ -2265,15 +2290,6 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
return 0;
}
-/*
- * Returns whether an ABORT_REQ_RSS message is a negative advice.
- */
-static int is_neg_adv_abort(unsigned int status)
-{
- return status == CPL_ERR_RTX_NEG_ADVICE ||
- status == CPL_ERR_PERSIST_NEG_ADVICE;
-}
-
static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
{
struct cpl_abort_req_rss *req = cplhdr(skb);
@@ -2287,7 +2303,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
unsigned int tid = GET_TID(req);
ep = lookup_tid(t, tid);
- if (is_neg_adv_abort(req->status)) {
+ if (is_neg_adv(req->status)) {
PDBG("%s neg_adv_abort ep %p tid %u\n", __func__, ep,
ep->hwtid);
return 0;
@@ -2425,7 +2441,7 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
C4IW_QP_ATTR_NEXT_STATE,
&attrs, 1);
}
- close_complete_upcall(ep);
+ close_complete_upcall(ep, 0);
__state_set(&ep->com, DEAD);
release = 1;
break;
@@ -2500,22 +2516,28 @@ static int fw4_ack(struct c4iw_dev *dev, struct sk_buff *skb)
int c4iw_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
{
- int err;
+ int err = 0;
+ int disconnect = 0;
struct c4iw_ep *ep = to_ep(cm_id);
PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
- if (state_read(&ep->com) == DEAD) {
+ mutex_lock(&ep->com.mutex);
+ if (ep->com.state == DEAD) {
+ mutex_unlock(&ep->com.mutex);
c4iw_put_ep(&ep->com);
return -ECONNRESET;
}
set_bit(ULP_REJECT, &ep->com.history);
- BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD);
+ BUG_ON(ep->com.state != MPA_REQ_RCVD);
if (mpa_rev == 0)
abort_connection(ep, NULL, GFP_KERNEL);
else {
err = send_mpa_reject(ep, pdata, pdata_len);
- err = c4iw_ep_disconnect(ep, 0, GFP_KERNEL);
+ disconnect = 1;
}
+ mutex_unlock(&ep->com.mutex);
+ if (disconnect)
+ err = c4iw_ep_disconnect(ep, 0, GFP_KERNEL);
c4iw_put_ep(&ep->com);
return 0;
}
@@ -2530,12 +2552,14 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
struct c4iw_qp *qp = get_qhp(h, conn_param->qpn);
PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
- if (state_read(&ep->com) == DEAD) {
+
+ mutex_lock(&ep->com.mutex);
+ if (ep->com.state == DEAD) {
err = -ECONNRESET;
goto err;
}
- BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD);
+ BUG_ON(ep->com.state != MPA_REQ_RCVD);
BUG_ON(!qp);
set_bit(ULP_ACCEPT, &ep->com.history);
@@ -2604,14 +2628,16 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
if (err)
goto err1;
- state_set(&ep->com, FPDU_MODE);
+ __state_set(&ep->com, FPDU_MODE);
established_upcall(ep);
+ mutex_unlock(&ep->com.mutex);
c4iw_put_ep(&ep->com);
return 0;
err1:
ep->com.cm_id = NULL;
cm_id->rem_ref(cm_id);
err:
+ mutex_unlock(&ep->com.mutex);
c4iw_put_ep(&ep->com);
return err;
}
@@ -2980,7 +3006,7 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
rdev = &ep->com.dev->rdev;
if (c4iw_fatal_error(rdev)) {
fatal = 1;
- close_complete_upcall(ep);
+ close_complete_upcall(ep, -EIO);
ep->com.state = DEAD;
}
switch (ep->com.state) {
@@ -3022,7 +3048,7 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
if (close) {
if (abrupt) {
set_bit(EP_DISC_ABORT, &ep->com.history);
- close_complete_upcall(ep);
+ close_complete_upcall(ep, -ECONNRESET);
ret = send_abort(ep, NULL, gfp);
} else {
set_bit(EP_DISC_CLOSE, &ep->com.history);
@@ -3203,6 +3229,7 @@ static void send_fw_pass_open_req(struct c4iw_dev *dev, struct sk_buff *skb,
struct sk_buff *req_skb;
struct fw_ofld_connection_wr *req;
struct cpl_pass_accept_req *cpl = cplhdr(skb);
+ int ret;
req_skb = alloc_skb(sizeof(struct fw_ofld_connection_wr), GFP_KERNEL);
req = (struct fw_ofld_connection_wr *)__skb_put(req_skb, sizeof(*req));
@@ -3239,7 +3266,13 @@ static void send_fw_pass_open_req(struct c4iw_dev *dev, struct sk_buff *skb,
req->cookie = (unsigned long)skb;
set_wr_txq(req_skb, CPL_PRIORITY_CONTROL, port_id);
- cxgb4_ofld_send(dev->rdev.lldi.ports[0], req_skb);
+ ret = cxgb4_ofld_send(dev->rdev.lldi.ports[0], req_skb);
+ if (ret < 0) {
+ pr_err("%s - cxgb4_ofld_send error %d - dropping\n", __func__,
+ ret);
+ kfree_skb(skb);
+ kfree_skb(req_skb);
+ }
}
/*
@@ -3346,6 +3379,7 @@ static int rx_pkt(struct c4iw_dev *dev, struct sk_buff *skb)
pi = (struct port_info *)netdev_priv(pdev);
tx_chan = cxgb4_port_chan(pdev);
}
+ neigh_release(neigh);
if (!e) {
pr_err("%s - failed to allocate l2t entry!\n",
__func__);
@@ -3426,6 +3460,7 @@ static void process_timeout(struct c4iw_ep *ep)
&attrs, 1);
}
__state_set(&ep->com, ABORTING);
+ close_complete_upcall(ep, -ETIMEDOUT);
break;
default:
WARN(1, "%s unexpected state ep %p tid %u state %u\n",
@@ -3569,7 +3604,7 @@ static int peer_abort_intr(struct c4iw_dev *dev, struct sk_buff *skb)
kfree_skb(skb);
return 0;
}
- if (is_neg_adv_abort(req->status)) {
+ if (is_neg_adv(req->status)) {
PDBG("%s neg_adv_abort ep %p tid %u\n", __func__, ep,
ep->hwtid);
kfree_skb(skb);
diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c
index 88de3aa9c5b0..ce468e542428 100644
--- a/drivers/infiniband/hw/cxgb4/cq.c
+++ b/drivers/infiniband/hw/cxgb4/cq.c
@@ -365,8 +365,14 @@ void c4iw_flush_hw_cq(struct c4iw_cq *chp)
if (CQE_OPCODE(hw_cqe) == FW_RI_READ_RESP) {
- /*
- * drop peer2peer RTR reads.
+ /* If we have reached here because of async
+ * event or other error, and have egress error
+ * then drop
+ */
+ if (CQE_TYPE(hw_cqe) == 1)
+ goto next_cqe;
+
+ /* drop peer2peer RTR reads.
*/
if (CQE_WRID_STAG(hw_cqe) == 1)
goto next_cqe;
@@ -511,8 +517,18 @@ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe,
*/
if (RQ_TYPE(hw_cqe) && (CQE_OPCODE(hw_cqe) == FW_RI_READ_RESP)) {
- /*
- * If this is an unsolicited read response, then the read
+ /* If we have reached here because of async
+ * event or other error, and have egress error
+ * then drop
+ */
+ if (CQE_TYPE(hw_cqe) == 1) {
+ if (CQE_STATUS(hw_cqe))
+ t4_set_wq_in_error(wq);
+ ret = -EAGAIN;
+ goto skip_cqe;
+ }
+
+ /* If this is an unsolicited read response, then the read
* was generated by the kernel driver as part of peer-2-peer
* connection setup. So ignore the completion.
*/
@@ -603,7 +619,7 @@ proc_cqe:
*/
if (SQ_TYPE(hw_cqe)) {
int idx = CQE_WRID_SQ_IDX(hw_cqe);
- BUG_ON(idx > wq->sq.size);
+ BUG_ON(idx >= wq->sq.size);
/*
* Account for any unsignaled completions completed by
@@ -617,7 +633,7 @@ proc_cqe:
wq->sq.in_use -= wq->sq.size + idx - wq->sq.cidx;
else
wq->sq.in_use -= idx - wq->sq.cidx;
- BUG_ON(wq->sq.in_use < 0 && wq->sq.in_use < wq->sq.size);
+ BUG_ON(wq->sq.in_use <= 0 && wq->sq.in_use >= wq->sq.size);
wq->sq.cidx = (uint16_t)idx;
PDBG("%s completing sq idx %u\n", __func__, wq->sq.cidx);
@@ -881,7 +897,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries,
/*
* Make actual HW queue 2x to avoid cdix_inc overflows.
*/
- hwentries = entries * 2;
+ hwentries = min(entries * 2, T4_MAX_IQ_SIZE);
/*
* Make HW queue at least 64 entries so GTS updates aren't too
@@ -930,6 +946,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries,
if (!mm2)
goto err4;
+ memset(&uresp, 0, sizeof(uresp));
uresp.qid_mask = rhp->rdev.cqmask;
uresp.cqid = chp->cq.cqid;
uresp.size = chp->cq.size;
diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c
index 4a033853312e..9489a388376c 100644
--- a/drivers/infiniband/hw/cxgb4/device.c
+++ b/drivers/infiniband/hw/cxgb4/device.c
@@ -64,6 +64,10 @@ struct uld_ctx {
static LIST_HEAD(uld_ctx_list);
static DEFINE_MUTEX(dev_mutex);
+#define DB_FC_RESUME_SIZE 64
+#define DB_FC_RESUME_DELAY 1
+#define DB_FC_DRAIN_THRESH 0
+
static struct dentry *c4iw_debugfs_root;
struct c4iw_debugfs_data {
@@ -282,7 +286,7 @@ static const struct file_operations stag_debugfs_fops = {
.llseek = default_llseek,
};
-static char *db_state_str[] = {"NORMAL", "FLOW_CONTROL", "RECOVERY"};
+static char *db_state_str[] = {"NORMAL", "FLOW_CONTROL", "RECOVERY", "STOPPED"};
static int stats_show(struct seq_file *seq, void *v)
{
@@ -311,9 +315,10 @@ static int stats_show(struct seq_file *seq, void *v)
seq_printf(seq, " DB FULL: %10llu\n", dev->rdev.stats.db_full);
seq_printf(seq, " DB EMPTY: %10llu\n", dev->rdev.stats.db_empty);
seq_printf(seq, " DB DROP: %10llu\n", dev->rdev.stats.db_drop);
- seq_printf(seq, " DB State: %s Transitions %llu\n",
+ seq_printf(seq, " DB State: %s Transitions %llu FC Interruptions %llu\n",
db_state_str[dev->db_state],
- dev->rdev.stats.db_state_transitions);
+ dev->rdev.stats.db_state_transitions,
+ dev->rdev.stats.db_fc_interruptions);
seq_printf(seq, "TCAM_FULL: %10llu\n", dev->rdev.stats.tcam_full);
seq_printf(seq, "ACT_OFLD_CONN_FAILS: %10llu\n",
dev->rdev.stats.act_ofld_conn_fails);
@@ -643,6 +648,12 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev)
printk(KERN_ERR MOD "error %d initializing ocqp pool\n", err);
goto err4;
}
+ rdev->status_page = (struct t4_dev_status_page *)
+ __get_free_page(GFP_KERNEL);
+ if (!rdev->status_page) {
+ pr_err(MOD "error allocating status page\n");
+ goto err4;
+ }
return 0;
err4:
c4iw_rqtpool_destroy(rdev);
@@ -656,6 +667,7 @@ err1:
static void c4iw_rdev_close(struct c4iw_rdev *rdev)
{
+ free_page((unsigned long)rdev->status_page);
c4iw_pblpool_destroy(rdev);
c4iw_rqtpool_destroy(rdev);
c4iw_destroy_resource(&rdev->resource);
@@ -703,18 +715,6 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
pr_info("%s: On-Chip Queues not supported on this device.\n",
pci_name(infop->pdev));
- if (!is_t4(infop->adapter_type)) {
- if (!allow_db_fc_on_t5) {
- db_fc_threshold = 100000;
- pr_info("DB Flow Control Disabled.\n");
- }
-
- if (!allow_db_coalescing_on_t5) {
- db_coalescing_threshold = -1;
- pr_info("DB Coalescing Disabled.\n");
- }
- }
-
devp = (struct c4iw_dev *)ib_alloc_device(sizeof(*devp));
if (!devp) {
printk(KERN_ERR MOD "Cannot allocate ib device\n");
@@ -749,6 +749,7 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
spin_lock_init(&devp->lock);
mutex_init(&devp->rdev.stats.lock);
mutex_init(&devp->db_mutex);
+ INIT_LIST_HEAD(&devp->db_fc_list);
if (c4iw_debugfs_root) {
devp->debugfs_root = debugfs_create_dir(
@@ -897,11 +898,13 @@ static int c4iw_uld_rx_handler(void *handle, const __be64 *rsp,
}
opcode = *(u8 *)rsp;
- if (c4iw_handlers[opcode])
+ if (c4iw_handlers[opcode]) {
c4iw_handlers[opcode](dev, skb);
- else
+ } else {
pr_info("%s no handler opcode 0x%x...\n", __func__,
opcode);
+ kfree_skb(skb);
+ }
return 0;
nomem:
@@ -977,13 +980,16 @@ static int disable_qp_db(int id, void *p, void *data)
static void stop_queues(struct uld_ctx *ctx)
{
- spin_lock_irq(&ctx->dev->lock);
- if (ctx->dev->db_state == NORMAL) {
- ctx->dev->rdev.stats.db_state_transitions++;
- ctx->dev->db_state = FLOW_CONTROL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctx->dev->lock, flags);
+ ctx->dev->rdev.stats.db_state_transitions++;
+ ctx->dev->db_state = STOPPED;
+ if (ctx->dev->rdev.flags & T4_STATUS_PAGE_DISABLED)
idr_for_each(&ctx->dev->qpidr, disable_qp_db, NULL);
- }
- spin_unlock_irq(&ctx->dev->lock);
+ else
+ ctx->dev->rdev.status_page->db_off = 1;
+ spin_unlock_irqrestore(&ctx->dev->lock, flags);
}
static int enable_qp_db(int id, void *p, void *data)
@@ -994,15 +1000,70 @@ static int enable_qp_db(int id, void *p, void *data)
return 0;
}
+static void resume_rc_qp(struct c4iw_qp *qp)
+{
+ spin_lock(&qp->lock);
+ t4_ring_sq_db(&qp->wq, qp->wq.sq.wq_pidx_inc);
+ qp->wq.sq.wq_pidx_inc = 0;
+ t4_ring_rq_db(&qp->wq, qp->wq.rq.wq_pidx_inc);
+ qp->wq.rq.wq_pidx_inc = 0;
+ spin_unlock(&qp->lock);
+}
+
+static void resume_a_chunk(struct uld_ctx *ctx)
+{
+ int i;
+ struct c4iw_qp *qp;
+
+ for (i = 0; i < DB_FC_RESUME_SIZE; i++) {
+ qp = list_first_entry(&ctx->dev->db_fc_list, struct c4iw_qp,
+ db_fc_entry);
+ list_del_init(&qp->db_fc_entry);
+ resume_rc_qp(qp);
+ if (list_empty(&ctx->dev->db_fc_list))
+ break;
+ }
+}
+
static void resume_queues(struct uld_ctx *ctx)
{
spin_lock_irq(&ctx->dev->lock);
- if (ctx->dev->qpcnt <= db_fc_threshold &&
- ctx->dev->db_state == FLOW_CONTROL) {
- ctx->dev->db_state = NORMAL;
- ctx->dev->rdev.stats.db_state_transitions++;
- idr_for_each(&ctx->dev->qpidr, enable_qp_db, NULL);
+ if (ctx->dev->db_state != STOPPED)
+ goto out;
+ ctx->dev->db_state = FLOW_CONTROL;
+ while (1) {
+ if (list_empty(&ctx->dev->db_fc_list)) {
+ WARN_ON(ctx->dev->db_state != FLOW_CONTROL);
+ ctx->dev->db_state = NORMAL;
+ ctx->dev->rdev.stats.db_state_transitions++;
+ if (ctx->dev->rdev.flags & T4_STATUS_PAGE_DISABLED) {
+ idr_for_each(&ctx->dev->qpidr, enable_qp_db,
+ NULL);
+ } else {
+ ctx->dev->rdev.status_page->db_off = 0;
+ }
+ break;
+ } else {
+ if (cxgb4_dbfifo_count(ctx->dev->rdev.lldi.ports[0], 1)
+ < (ctx->dev->rdev.lldi.dbfifo_int_thresh <<
+ DB_FC_DRAIN_THRESH)) {
+ resume_a_chunk(ctx);
+ }
+ if (!list_empty(&ctx->dev->db_fc_list)) {
+ spin_unlock_irq(&ctx->dev->lock);
+ if (DB_FC_RESUME_DELAY) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(DB_FC_RESUME_DELAY);
+ }
+ spin_lock_irq(&ctx->dev->lock);
+ if (ctx->dev->db_state != FLOW_CONTROL)
+ break;
+ }
+ }
}
+out:
+ if (ctx->dev->db_state != NORMAL)
+ ctx->dev->rdev.stats.db_fc_interruptions++;
spin_unlock_irq(&ctx->dev->lock);
}
@@ -1028,12 +1089,12 @@ static int count_qps(int id, void *p, void *data)
return 0;
}
-static void deref_qps(struct qp_list qp_list)
+static void deref_qps(struct qp_list *qp_list)
{
int idx;
- for (idx = 0; idx < qp_list.idx; idx++)
- c4iw_qp_rem_ref(&qp_list.qps[idx]->ibqp);
+ for (idx = 0; idx < qp_list->idx; idx++)
+ c4iw_qp_rem_ref(&qp_list->qps[idx]->ibqp);
}
static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list)
@@ -1044,17 +1105,22 @@ static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list)
for (idx = 0; idx < qp_list->idx; idx++) {
struct c4iw_qp *qp = qp_list->qps[idx];
+ spin_lock_irq(&qp->rhp->lock);
+ spin_lock(&qp->lock);
ret = cxgb4_sync_txq_pidx(qp->rhp->rdev.lldi.ports[0],
qp->wq.sq.qid,
t4_sq_host_wq_pidx(&qp->wq),
t4_sq_wq_size(&qp->wq));
if (ret) {
- printk(KERN_ERR MOD "%s: Fatal error - "
+ pr_err(KERN_ERR MOD "%s: Fatal error - "
"DB overflow recovery failed - "
"error syncing SQ qid %u\n",
pci_name(ctx->lldi.pdev), qp->wq.sq.qid);
+ spin_unlock(&qp->lock);
+ spin_unlock_irq(&qp->rhp->lock);
return;
}
+ qp->wq.sq.wq_pidx_inc = 0;
ret = cxgb4_sync_txq_pidx(qp->rhp->rdev.lldi.ports[0],
qp->wq.rq.qid,
@@ -1062,12 +1128,17 @@ static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list)
t4_rq_wq_size(&qp->wq));
if (ret) {
- printk(KERN_ERR MOD "%s: Fatal error - "
+ pr_err(KERN_ERR MOD "%s: Fatal error - "
"DB overflow recovery failed - "
"error syncing RQ qid %u\n",
pci_name(ctx->lldi.pdev), qp->wq.rq.qid);
+ spin_unlock(&qp->lock);
+ spin_unlock_irq(&qp->rhp->lock);
return;
}
+ qp->wq.rq.wq_pidx_inc = 0;
+ spin_unlock(&qp->lock);
+ spin_unlock_irq(&qp->rhp->lock);
/* Wait for the dbfifo to drain */
while (cxgb4_dbfifo_count(qp->rhp->rdev.lldi.ports[0], 1) > 0) {
@@ -1083,36 +1154,22 @@ static void recover_queues(struct uld_ctx *ctx)
struct qp_list qp_list;
int ret;
- /* lock out kernel db ringers */
- mutex_lock(&ctx->dev->db_mutex);
-
- /* put all queues in to recovery mode */
- spin_lock_irq(&ctx->dev->lock);
- ctx->dev->db_state = RECOVERY;
- ctx->dev->rdev.stats.db_state_transitions++;
- idr_for_each(&ctx->dev->qpidr, disable_qp_db, NULL);
- spin_unlock_irq(&ctx->dev->lock);
-
/* slow everybody down */
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(usecs_to_jiffies(1000));
- /* Wait for the dbfifo to completely drain. */
- while (cxgb4_dbfifo_count(ctx->dev->rdev.lldi.ports[0], 1) > 0) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(usecs_to_jiffies(10));
- }
-
/* flush the SGE contexts */
ret = cxgb4_flush_eq_cache(ctx->dev->rdev.lldi.ports[0]);
if (ret) {
printk(KERN_ERR MOD "%s: Fatal error - DB overflow recovery failed\n",
pci_name(ctx->lldi.pdev));
- goto out;
+ return;
}
/* Count active queues so we can build a list of queues to recover */
spin_lock_irq(&ctx->dev->lock);
+ WARN_ON(ctx->dev->db_state != STOPPED);
+ ctx->dev->db_state = RECOVERY;
idr_for_each(&ctx->dev->qpidr, count_qps, &count);
qp_list.qps = kzalloc(count * sizeof *qp_list.qps, GFP_ATOMIC);
@@ -1120,7 +1177,7 @@ static void recover_queues(struct uld_ctx *ctx)
printk(KERN_ERR MOD "%s: Fatal error - DB overflow recovery failed\n",
pci_name(ctx->lldi.pdev));
spin_unlock_irq(&ctx->dev->lock);
- goto out;
+ return;
}
qp_list.idx = 0;
@@ -1133,29 +1190,13 @@ static void recover_queues(struct uld_ctx *ctx)
recover_lost_dbs(ctx, &qp_list);
/* we're almost done! deref the qps and clean up */
- deref_qps(qp_list);
+ deref_qps(&qp_list);
kfree(qp_list.qps);
- /* Wait for the dbfifo to completely drain again */
- while (cxgb4_dbfifo_count(ctx->dev->rdev.lldi.ports[0], 1) > 0) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(usecs_to_jiffies(10));
- }
-
- /* resume the queues */
spin_lock_irq(&ctx->dev->lock);
- if (ctx->dev->qpcnt > db_fc_threshold)
- ctx->dev->db_state = FLOW_CONTROL;
- else {
- ctx->dev->db_state = NORMAL;
- idr_for_each(&ctx->dev->qpidr, enable_qp_db, NULL);
- }
- ctx->dev->rdev.stats.db_state_transitions++;
+ WARN_ON(ctx->dev->db_state != RECOVERY);
+ ctx->dev->db_state = STOPPED;
spin_unlock_irq(&ctx->dev->lock);
-
-out:
- /* start up kernel db ringers again */
- mutex_unlock(&ctx->dev->db_mutex);
}
static int c4iw_uld_control(void *handle, enum cxgb4_control control, ...)
@@ -1165,9 +1206,7 @@ static int c4iw_uld_control(void *handle, enum cxgb4_control control, ...)
switch (control) {
case CXGB4_CONTROL_DB_FULL:
stop_queues(ctx);
- mutex_lock(&ctx->dev->rdev.stats.lock);
ctx->dev->rdev.stats.db_full++;
- mutex_unlock(&ctx->dev->rdev.stats.lock);
break;
case CXGB4_CONTROL_DB_EMPTY:
resume_queues(ctx);
diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
index 23eaeabab93b..e872203c5424 100644
--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
@@ -109,6 +109,7 @@ struct c4iw_dev_ucontext {
enum c4iw_rdev_flags {
T4_FATAL_ERROR = (1<<0),
+ T4_STATUS_PAGE_DISABLED = (1<<1),
};
struct c4iw_stat {
@@ -130,6 +131,7 @@ struct c4iw_stats {
u64 db_empty;
u64 db_drop;
u64 db_state_transitions;
+ u64 db_fc_interruptions;
u64 tcam_full;
u64 act_ofld_conn_fails;
u64 pas_ofld_conn_fails;
@@ -150,6 +152,7 @@ struct c4iw_rdev {
unsigned long oc_mw_pa;
void __iomem *oc_mw_kva;
struct c4iw_stats stats;
+ struct t4_dev_status_page *status_page;
};
static inline int c4iw_fatal_error(struct c4iw_rdev *rdev)
@@ -211,7 +214,8 @@ static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev,
enum db_state {
NORMAL = 0,
FLOW_CONTROL = 1,
- RECOVERY = 2
+ RECOVERY = 2,
+ STOPPED = 3
};
struct c4iw_dev {
@@ -225,10 +229,10 @@ struct c4iw_dev {
struct mutex db_mutex;
struct dentry *debugfs_root;
enum db_state db_state;
- int qpcnt;
struct idr hwtid_idr;
struct idr atid_idr;
struct idr stid_idr;
+ struct list_head db_fc_list;
};
static inline struct c4iw_dev *to_c4iw_dev(struct ib_device *ibdev)
@@ -369,6 +373,7 @@ struct c4iw_fr_page_list {
DEFINE_DMA_UNMAP_ADDR(mapping);
dma_addr_t dma_addr;
struct c4iw_dev *dev;
+ int pll_len;
};
static inline struct c4iw_fr_page_list *to_c4iw_fr_page_list(
@@ -432,6 +437,7 @@ struct c4iw_qp_attributes {
struct c4iw_qp {
struct ib_qp ibqp;
+ struct list_head db_fc_entry;
struct c4iw_dev *rhp;
struct c4iw_ep *ep;
struct c4iw_qp_attributes attr;
@@ -441,6 +447,7 @@ struct c4iw_qp {
atomic_t refcnt;
wait_queue_head_t wait;
struct timer_list timer;
+ int sq_sig_all;
};
static inline struct c4iw_qp *to_c4iw_qp(struct ib_qp *ibqp)
diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c
index 41b11951a30a..f9ca072a99ed 100644
--- a/drivers/infiniband/hw/cxgb4/mem.c
+++ b/drivers/infiniband/hw/cxgb4/mem.c
@@ -37,9 +37,9 @@
#include "iw_cxgb4.h"
-int use_dsgl = 1;
+int use_dsgl = 0;
module_param(use_dsgl, int, 0644);
-MODULE_PARM_DESC(use_dsgl, "Use DSGL for PBL/FastReg (default=1)");
+MODULE_PARM_DESC(use_dsgl, "Use DSGL for PBL/FastReg (default=0)");
#define T4_ULPTX_MIN_IO 32
#define C4IW_MAX_INLINE_SIZE 96
@@ -678,9 +678,9 @@ struct ib_mr *c4iw_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
{
__be64 *pages;
int shift, n, len;
- int i, j, k;
+ int i, k, entry;
int err = 0;
- struct ib_umem_chunk *chunk;
+ struct scatterlist *sg;
struct c4iw_dev *rhp;
struct c4iw_pd *php;
struct c4iw_mr *mhp;
@@ -710,10 +710,7 @@ struct ib_mr *c4iw_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
shift = ffs(mhp->umem->page_size) - 1;
- n = 0;
- list_for_each_entry(chunk, &mhp->umem->chunk_list, list)
- n += chunk->nents;
-
+ n = mhp->umem->nmap;
err = alloc_pbl(mhp, n);
if (err)
goto err;
@@ -726,24 +723,22 @@ struct ib_mr *c4iw_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
i = n = 0;
- list_for_each_entry(chunk, &mhp->umem->chunk_list, list)
- for (j = 0; j < chunk->nmap; ++j) {
- len = sg_dma_len(&chunk->page_list[j]) >> shift;
- for (k = 0; k < len; ++k) {
- pages[i++] = cpu_to_be64(sg_dma_address(
- &chunk->page_list[j]) +
- mhp->umem->page_size * k);
- if (i == PAGE_SIZE / sizeof *pages) {
- err = write_pbl(&mhp->rhp->rdev,
- pages,
- mhp->attr.pbl_addr + (n << 3), i);
- if (err)
- goto pbl_done;
- n += i;
- i = 0;
- }
+ for_each_sg(mhp->umem->sg_head.sgl, sg, mhp->umem->nmap, entry) {
+ len = sg_dma_len(sg) >> shift;
+ for (k = 0; k < len; ++k) {
+ pages[i++] = cpu_to_be64(sg_dma_address(sg) +
+ mhp->umem->page_size * k);
+ if (i == PAGE_SIZE / sizeof *pages) {
+ err = write_pbl(&mhp->rhp->rdev,
+ pages,
+ mhp->attr.pbl_addr + (n << 3), i);
+ if (err)
+ goto pbl_done;
+ n += i;
+ i = 0;
}
}
+ }
if (i)
err = write_pbl(&mhp->rhp->rdev, pages,
@@ -903,7 +898,11 @@ struct ib_fast_reg_page_list *c4iw_alloc_fastreg_pbl(struct ib_device *device,
dma_unmap_addr_set(c4pl, mapping, dma_addr);
c4pl->dma_addr = dma_addr;
c4pl->dev = dev;
- c4pl->ibpl.max_page_list_len = pll_len;
+ c4pl->pll_len = pll_len;
+
+ PDBG("%s c4pl %p pll_len %u page_list %p dma_addr %pad\n",
+ __func__, c4pl, c4pl->pll_len, c4pl->ibpl.page_list,
+ &c4pl->dma_addr);
return &c4pl->ibpl;
}
@@ -912,8 +911,12 @@ void c4iw_free_fastreg_pbl(struct ib_fast_reg_page_list *ibpl)
{
struct c4iw_fr_page_list *c4pl = to_c4iw_fr_page_list(ibpl);
+ PDBG("%s c4pl %p pll_len %u page_list %p dma_addr %pad\n",
+ __func__, c4pl, c4pl->pll_len, c4pl->ibpl.page_list,
+ &c4pl->dma_addr);
+
dma_free_coherent(&c4pl->dev->rdev.lldi.pdev->dev,
- c4pl->ibpl.max_page_list_len,
+ c4pl->pll_len,
c4pl->ibpl.page_list, dma_unmap_addr(c4pl, mapping));
kfree(c4pl);
}
diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c
index 7e94c9a656a1..79429256023a 100644
--- a/drivers/infiniband/hw/cxgb4/provider.c
+++ b/drivers/infiniband/hw/cxgb4/provider.c
@@ -106,15 +106,56 @@ static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device *ibdev,
{
struct c4iw_ucontext *context;
struct c4iw_dev *rhp = to_c4iw_dev(ibdev);
+ static int warned;
+ struct c4iw_alloc_ucontext_resp uresp;
+ int ret = 0;
+ struct c4iw_mm_entry *mm = NULL;
PDBG("%s ibdev %p\n", __func__, ibdev);
context = kzalloc(sizeof(*context), GFP_KERNEL);
- if (!context)
- return ERR_PTR(-ENOMEM);
+ if (!context) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
c4iw_init_dev_ucontext(&rhp->rdev, &context->uctx);
INIT_LIST_HEAD(&context->mmaps);
spin_lock_init(&context->mmap_lock);
+
+ if (udata->outlen < sizeof(uresp)) {
+ if (!warned++)
+ pr_err(MOD "Warning - downlevel libcxgb4 (non-fatal), device status page disabled.");
+ rhp->rdev.flags |= T4_STATUS_PAGE_DISABLED;
+ } else {
+ mm = kmalloc(sizeof(*mm), GFP_KERNEL);
+ if (!mm) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ uresp.status_page_size = PAGE_SIZE;
+
+ spin_lock(&context->mmap_lock);
+ uresp.status_page_key = context->key;
+ context->key += PAGE_SIZE;
+ spin_unlock(&context->mmap_lock);
+
+ ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
+ if (ret)
+ goto err_mm;
+
+ mm->key = uresp.status_page_key;
+ mm->addr = virt_to_phys(rhp->rdev.status_page);
+ mm->len = PAGE_SIZE;
+ insert_mmap(context, mm);
+ }
return &context->ibucontext;
+err_mm:
+ kfree(mm);
+err_free:
+ kfree(context);
+err:
+ return ERR_PTR(ret);
}
static int c4iw_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c
index 582936708e6e..cb76eb5eee1f 100644
--- a/drivers/infiniband/hw/cxgb4/qp.c
+++ b/drivers/infiniband/hw/cxgb4/qp.c
@@ -638,6 +638,46 @@ void c4iw_qp_rem_ref(struct ib_qp *qp)
wake_up(&(to_c4iw_qp(qp)->wait));
}
+static void add_to_fc_list(struct list_head *head, struct list_head *entry)
+{
+ if (list_empty(entry))
+ list_add_tail(entry, head);
+}
+
+static int ring_kernel_sq_db(struct c4iw_qp *qhp, u16 inc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&qhp->rhp->lock, flags);
+ spin_lock(&qhp->lock);
+ if (qhp->rhp->db_state == NORMAL) {
+ t4_ring_sq_db(&qhp->wq, inc);
+ } else {
+ add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry);
+ qhp->wq.sq.wq_pidx_inc += inc;
+ }
+ spin_unlock(&qhp->lock);
+ spin_unlock_irqrestore(&qhp->rhp->lock, flags);
+ return 0;
+}
+
+static int ring_kernel_rq_db(struct c4iw_qp *qhp, u16 inc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&qhp->rhp->lock, flags);
+ spin_lock(&qhp->lock);
+ if (qhp->rhp->db_state == NORMAL) {
+ t4_ring_rq_db(&qhp->wq, inc);
+ } else {
+ add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry);
+ qhp->wq.rq.wq_pidx_inc += inc;
+ }
+ spin_unlock(&qhp->lock);
+ spin_unlock_irqrestore(&qhp->rhp->lock, flags);
+ return 0;
+}
+
int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
struct ib_send_wr **bad_wr)
{
@@ -675,7 +715,7 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
fw_flags = 0;
if (wr->send_flags & IB_SEND_SOLICITED)
fw_flags |= FW_RI_SOLICITED_EVENT_FLAG;
- if (wr->send_flags & IB_SEND_SIGNALED)
+ if (wr->send_flags & IB_SEND_SIGNALED || qhp->sq_sig_all)
fw_flags |= FW_RI_COMPLETION_FLAG;
swsqe = &qhp->wq.sq.sw_sq[qhp->wq.sq.pidx];
switch (wr->opcode) {
@@ -736,7 +776,8 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
}
swsqe->idx = qhp->wq.sq.pidx;
swsqe->complete = 0;
- swsqe->signaled = (wr->send_flags & IB_SEND_SIGNALED);
+ swsqe->signaled = (wr->send_flags & IB_SEND_SIGNALED) ||
+ qhp->sq_sig_all;
swsqe->flushed = 0;
swsqe->wr_id = wr->wr_id;
@@ -750,9 +791,13 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
t4_sq_produce(&qhp->wq, len16);
idx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE);
}
- if (t4_wq_db_enabled(&qhp->wq))
+ if (!qhp->rhp->rdev.status_page->db_off) {
t4_ring_sq_db(&qhp->wq, idx);
- spin_unlock_irqrestore(&qhp->lock, flag);
+ spin_unlock_irqrestore(&qhp->lock, flag);
+ } else {
+ spin_unlock_irqrestore(&qhp->lock, flag);
+ ring_kernel_sq_db(qhp, idx);
+ }
return err;
}
@@ -812,9 +857,13 @@ int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
wr = wr->next;
num_wrs--;
}
- if (t4_wq_db_enabled(&qhp->wq))
+ if (!qhp->rhp->rdev.status_page->db_off) {
t4_ring_rq_db(&qhp->wq, idx);
- spin_unlock_irqrestore(&qhp->lock, flag);
+ spin_unlock_irqrestore(&qhp->lock, flag);
+ } else {
+ spin_unlock_irqrestore(&qhp->lock, flag);
+ ring_kernel_rq_db(qhp, idx);
+ }
return err;
}
@@ -1200,35 +1249,6 @@ out:
return ret;
}
-/*
- * Called by the library when the qp has user dbs disabled due to
- * a DB_FULL condition. This function will single-thread all user
- * DB rings to avoid overflowing the hw db-fifo.
- */
-static int ring_kernel_db(struct c4iw_qp *qhp, u32 qid, u16 inc)
-{
- int delay = db_delay_usecs;
-
- mutex_lock(&qhp->rhp->db_mutex);
- do {
-
- /*
- * The interrupt threshold is dbfifo_int_thresh << 6. So
- * make sure we don't cross that and generate an interrupt.
- */
- if (cxgb4_dbfifo_count(qhp->rhp->rdev.lldi.ports[0], 1) <
- (qhp->rhp->rdev.lldi.dbfifo_int_thresh << 5)) {
- writel(QID(qid) | PIDX(inc), qhp->wq.db);
- break;
- }
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(usecs_to_jiffies(delay));
- delay = min(delay << 1, 2000);
- } while (1);
- mutex_unlock(&qhp->rhp->db_mutex);
- return 0;
-}
-
int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
enum c4iw_qp_attr_mask mask,
struct c4iw_qp_attributes *attrs,
@@ -1278,11 +1298,11 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
}
if (mask & C4IW_QP_ATTR_SQ_DB) {
- ret = ring_kernel_db(qhp, qhp->wq.sq.qid, attrs->sq_db_inc);
+ ret = ring_kernel_sq_db(qhp, attrs->sq_db_inc);
goto out;
}
if (mask & C4IW_QP_ATTR_RQ_DB) {
- ret = ring_kernel_db(qhp, qhp->wq.rq.qid, attrs->rq_db_inc);
+ ret = ring_kernel_rq_db(qhp, attrs->rq_db_inc);
goto out;
}
@@ -1465,14 +1485,6 @@ out:
return ret;
}
-static int enable_qp_db(int id, void *p, void *data)
-{
- struct c4iw_qp *qp = p;
-
- t4_enable_wq_db(&qp->wq);
- return 0;
-}
-
int c4iw_destroy_qp(struct ib_qp *ib_qp)
{
struct c4iw_dev *rhp;
@@ -1490,22 +1502,15 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp)
c4iw_modify_qp(rhp, qhp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 0);
wait_event(qhp->wait, !qhp->ep);
- spin_lock_irq(&rhp->lock);
- remove_handle_nolock(rhp, &rhp->qpidr, qhp->wq.sq.qid);
- rhp->qpcnt--;
- BUG_ON(rhp->qpcnt < 0);
- if (rhp->qpcnt <= db_fc_threshold && rhp->db_state == FLOW_CONTROL) {
- rhp->rdev.stats.db_state_transitions++;
- rhp->db_state = NORMAL;
- idr_for_each(&rhp->qpidr, enable_qp_db, NULL);
- }
- if (db_coalescing_threshold >= 0)
- if (rhp->qpcnt <= db_coalescing_threshold)
- cxgb4_enable_db_coalescing(rhp->rdev.lldi.ports[0]);
- spin_unlock_irq(&rhp->lock);
+ remove_handle(rhp, &rhp->qpidr, qhp->wq.sq.qid);
atomic_dec(&qhp->refcnt);
wait_event(qhp->wait, !atomic_read(&qhp->refcnt));
+ spin_lock_irq(&rhp->lock);
+ if (!list_empty(&qhp->db_fc_entry))
+ list_del_init(&qhp->db_fc_entry);
+ spin_unlock_irq(&rhp->lock);
+
ucontext = ib_qp->uobject ?
to_c4iw_ucontext(ib_qp->uobject->context) : NULL;
destroy_qp(&rhp->rdev, &qhp->wq,
@@ -1516,14 +1521,6 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp)
return 0;
}
-static int disable_qp_db(int id, void *p, void *data)
-{
- struct c4iw_qp *qp = p;
-
- t4_disable_wq_db(&qp->wq);
- return 0;
-}
-
struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
struct ib_udata *udata)
{
@@ -1533,7 +1530,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
struct c4iw_cq *schp;
struct c4iw_cq *rchp;
struct c4iw_create_qp_resp uresp;
- int sqsize, rqsize;
+ unsigned int sqsize, rqsize;
struct c4iw_ucontext *ucontext;
int ret;
struct c4iw_mm_entry *mm1, *mm2, *mm3, *mm4, *mm5 = NULL;
@@ -1605,25 +1602,13 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
qhp->attr.enable_bind = 1;
qhp->attr.max_ord = 1;
qhp->attr.max_ird = 1;
+ qhp->sq_sig_all = attrs->sq_sig_type == IB_SIGNAL_ALL_WR;
spin_lock_init(&qhp->lock);
mutex_init(&qhp->mutex);
init_waitqueue_head(&qhp->wait);
atomic_set(&qhp->refcnt, 1);
- spin_lock_irq(&rhp->lock);
- if (rhp->db_state != NORMAL)
- t4_disable_wq_db(&qhp->wq);
- rhp->qpcnt++;
- if (rhp->qpcnt > db_fc_threshold && rhp->db_state == NORMAL) {
- rhp->rdev.stats.db_state_transitions++;
- rhp->db_state = FLOW_CONTROL;
- idr_for_each(&rhp->qpidr, disable_qp_db, NULL);
- }
- if (db_coalescing_threshold >= 0)
- if (rhp->qpcnt > db_coalescing_threshold)
- cxgb4_disable_db_coalescing(rhp->rdev.lldi.ports[0]);
- ret = insert_handle_nolock(rhp, &rhp->qpidr, qhp, qhp->wq.sq.qid);
- spin_unlock_irq(&rhp->lock);
+ ret = insert_handle(rhp, &rhp->qpidr, qhp, qhp->wq.sq.qid);
if (ret)
goto err2;
@@ -1709,6 +1694,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
}
qhp->ibqp.qp_num = qhp->wq.sq.qid;
init_timer(&(qhp->timer));
+ INIT_LIST_HEAD(&qhp->db_fc_entry);
PDBG("%s qhp %p sq_num_entries %d, rq_num_entries %d qpid 0x%0x\n",
__func__, qhp, qhp->attr.sq_num_entries, qhp->attr.rq_num_entries,
qhp->wq.sq.qid);
diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h
index e73ace739183..eeca8b1e6376 100644
--- a/drivers/infiniband/hw/cxgb4/t4.h
+++ b/drivers/infiniband/hw/cxgb4/t4.h
@@ -300,6 +300,7 @@ struct t4_sq {
u16 cidx;
u16 pidx;
u16 wq_pidx;
+ u16 wq_pidx_inc;
u16 flags;
short flush_cidx;
};
@@ -324,6 +325,7 @@ struct t4_rq {
u16 cidx;
u16 pidx;
u16 wq_pidx;
+ u16 wq_pidx_inc;
};
struct t4_wq {
@@ -609,3 +611,7 @@ static inline void t4_set_cq_in_error(struct t4_cq *cq)
((struct t4_status_page *)&cq->queue[cq->size])->qp_err = 1;
}
#endif
+
+struct t4_dev_status_page {
+ u8 db_off;
+};
diff --git a/drivers/infiniband/hw/cxgb4/user.h b/drivers/infiniband/hw/cxgb4/user.h
index 32b754c35ab7..11ccd276e5d9 100644
--- a/drivers/infiniband/hw/cxgb4/user.h
+++ b/drivers/infiniband/hw/cxgb4/user.h
@@ -70,4 +70,9 @@ struct c4iw_create_qp_resp {
__u32 qid_mask;
__u32 flags;
};
+
+struct c4iw_alloc_ucontext_resp {
+ __u64 status_page_key;
+ __u32 status_page_size;
+};
#endif
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index f08f6eaf3fa8..bd45e0f3923f 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -322,7 +322,7 @@ struct ehca_mr_pginfo {
} phy;
struct { /* type EHCA_MR_PGI_USER section */
struct ib_umem *region;
- struct ib_umem_chunk *next_chunk;
+ struct scatterlist *next_sg;
u64 next_nmap;
} usr;
struct { /* type EHCA_MR_PGI_FMR section */
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
index 212150c25ea0..8cc837537768 100644
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -283,6 +283,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
(my_cq->galpas.user.fw_handle & (PAGE_SIZE - 1));
if (ib_copy_to_udata(udata, &resp, sizeof(resp))) {
ehca_err(device, "Copy to udata failed.");
+ cq = ERR_PTR(-EFAULT);
goto create_cq_exit4;
}
}
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c
index bcfb0c183620..3488e8c9fcb4 100644
--- a/drivers/infiniband/hw/ehca/ehca_mrmw.c
+++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c
@@ -400,10 +400,7 @@ reg_user_mr_fallback:
pginfo.num_hwpages = num_hwpages;
pginfo.u.usr.region = e_mr->umem;
pginfo.next_hwpage = e_mr->umem->offset / hwpage_size;
- pginfo.u.usr.next_chunk = list_prepare_entry(pginfo.u.usr.next_chunk,
- (&e_mr->umem->chunk_list),
- list);
-
+ pginfo.u.usr.next_sg = pginfo.u.usr.region->sg_head.sgl;
ret = ehca_reg_mr(shca, e_mr, (u64 *)virt, length, mr_access_flags,
e_pd, &pginfo, &e_mr->ib.ib_mr.lkey,
&e_mr->ib.ib_mr.rkey, EHCA_REG_MR);
@@ -1858,61 +1855,39 @@ static int ehca_set_pagebuf_user1(struct ehca_mr_pginfo *pginfo,
u64 *kpage)
{
int ret = 0;
- struct ib_umem_chunk *prev_chunk;
- struct ib_umem_chunk *chunk;
u64 pgaddr;
- u32 i = 0;
u32 j = 0;
int hwpages_per_kpage = PAGE_SIZE / pginfo->hwpage_size;
-
- /* loop over desired chunk entries */
- chunk = pginfo->u.usr.next_chunk;
- prev_chunk = pginfo->u.usr.next_chunk;
- list_for_each_entry_continue(
- chunk, (&(pginfo->u.usr.region->chunk_list)), list) {
- for (i = pginfo->u.usr.next_nmap; i < chunk->nmap; ) {
- pgaddr = page_to_pfn(sg_page(&chunk->page_list[i]))
- << PAGE_SHIFT ;
- *kpage = pgaddr + (pginfo->next_hwpage *
- pginfo->hwpage_size);
- if ( !(*kpage) ) {
- ehca_gen_err("pgaddr=%llx "
- "chunk->page_list[i]=%llx "
- "i=%x next_hwpage=%llx",
- pgaddr, (u64)sg_dma_address(
- &chunk->page_list[i]),
- i, pginfo->next_hwpage);
- return -EFAULT;
- }
- (pginfo->hwpage_cnt)++;
- (pginfo->next_hwpage)++;
- kpage++;
- if (pginfo->next_hwpage % hwpages_per_kpage == 0) {
- (pginfo->kpage_cnt)++;
- (pginfo->u.usr.next_nmap)++;
- pginfo->next_hwpage = 0;
- i++;
- }
- j++;
- if (j >= number) break;
+ struct scatterlist **sg = &pginfo->u.usr.next_sg;
+
+ while (*sg != NULL) {
+ pgaddr = page_to_pfn(sg_page(*sg))
+ << PAGE_SHIFT;
+ *kpage = pgaddr + (pginfo->next_hwpage *
+ pginfo->hwpage_size);
+ if (!(*kpage)) {
+ ehca_gen_err("pgaddr=%llx "
+ "sg_dma_address=%llx "
+ "entry=%llx next_hwpage=%llx",
+ pgaddr, (u64)sg_dma_address(*sg),
+ pginfo->u.usr.next_nmap,
+ pginfo->next_hwpage);
+ return -EFAULT;
}
- if ((pginfo->u.usr.next_nmap >= chunk->nmap) &&
- (j >= number)) {
- pginfo->u.usr.next_nmap = 0;
- prev_chunk = chunk;
- break;
- } else if (pginfo->u.usr.next_nmap >= chunk->nmap) {
- pginfo->u.usr.next_nmap = 0;
- prev_chunk = chunk;
- } else if (j >= number)
+ (pginfo->hwpage_cnt)++;
+ (pginfo->next_hwpage)++;
+ kpage++;
+ if (pginfo->next_hwpage % hwpages_per_kpage == 0) {
+ (pginfo->kpage_cnt)++;
+ (pginfo->u.usr.next_nmap)++;
+ pginfo->next_hwpage = 0;
+ *sg = sg_next(*sg);
+ }
+ j++;
+ if (j >= number)
break;
- else
- prev_chunk = chunk;
}
- pginfo->u.usr.next_chunk =
- list_prepare_entry(prev_chunk,
- (&(pginfo->u.usr.region->chunk_list)),
- list);
+
return ret;
}
@@ -1920,20 +1895,19 @@ static int ehca_set_pagebuf_user1(struct ehca_mr_pginfo *pginfo,
* check given pages for contiguous layout
* last page addr is returned in prev_pgaddr for further check
*/
-static int ehca_check_kpages_per_ate(struct scatterlist *page_list,
- int start_idx, int end_idx,
+static int ehca_check_kpages_per_ate(struct scatterlist **sg,
+ int num_pages,
u64 *prev_pgaddr)
{
- int t;
- for (t = start_idx; t <= end_idx; t++) {
- u64 pgaddr = page_to_pfn(sg_page(&page_list[t])) << PAGE_SHIFT;
+ for (; *sg && num_pages > 0; *sg = sg_next(*sg), num_pages--) {
+ u64 pgaddr = page_to_pfn(sg_page(*sg)) << PAGE_SHIFT;
if (ehca_debug_level >= 3)
ehca_gen_dbg("chunk_page=%llx value=%016llx", pgaddr,
*(u64 *)__va(pgaddr));
if (pgaddr - PAGE_SIZE != *prev_pgaddr) {
ehca_gen_err("uncontiguous page found pgaddr=%llx "
- "prev_pgaddr=%llx page_list_i=%x",
- pgaddr, *prev_pgaddr, t);
+ "prev_pgaddr=%llx entries_left_in_hwpage=%x",
+ pgaddr, *prev_pgaddr, num_pages);
return -EINVAL;
}
*prev_pgaddr = pgaddr;
@@ -1947,111 +1921,80 @@ static int ehca_set_pagebuf_user2(struct ehca_mr_pginfo *pginfo,
u64 *kpage)
{
int ret = 0;
- struct ib_umem_chunk *prev_chunk;
- struct ib_umem_chunk *chunk;
u64 pgaddr, prev_pgaddr;
- u32 i = 0;
u32 j = 0;
int kpages_per_hwpage = pginfo->hwpage_size / PAGE_SIZE;
int nr_kpages = kpages_per_hwpage;
+ struct scatterlist **sg = &pginfo->u.usr.next_sg;
+
+ while (*sg != NULL) {
- /* loop over desired chunk entries */
- chunk = pginfo->u.usr.next_chunk;
- prev_chunk = pginfo->u.usr.next_chunk;
- list_for_each_entry_continue(
- chunk, (&(pginfo->u.usr.region->chunk_list)), list) {
- for (i = pginfo->u.usr.next_nmap; i < chunk->nmap; ) {
- if (nr_kpages == kpages_per_hwpage) {
- pgaddr = ( page_to_pfn(sg_page(&chunk->page_list[i]))
- << PAGE_SHIFT );
- *kpage = pgaddr;
- if ( !(*kpage) ) {
- ehca_gen_err("pgaddr=%llx i=%x",
- pgaddr, i);
+ if (nr_kpages == kpages_per_hwpage) {
+ pgaddr = (page_to_pfn(sg_page(*sg))
+ << PAGE_SHIFT);
+ *kpage = pgaddr;
+ if (!(*kpage)) {
+ ehca_gen_err("pgaddr=%llx entry=%llx",
+ pgaddr, pginfo->u.usr.next_nmap);
+ ret = -EFAULT;
+ return ret;
+ }
+ /*
+ * The first page in a hwpage must be aligned;
+ * the first MR page is exempt from this rule.
+ */
+ if (pgaddr & (pginfo->hwpage_size - 1)) {
+ if (pginfo->hwpage_cnt) {
+ ehca_gen_err(
+ "invalid alignment "
+ "pgaddr=%llx entry=%llx "
+ "mr_pgsize=%llx",
+ pgaddr, pginfo->u.usr.next_nmap,
+ pginfo->hwpage_size);
ret = -EFAULT;
return ret;
}
- /*
- * The first page in a hwpage must be aligned;
- * the first MR page is exempt from this rule.
- */
- if (pgaddr & (pginfo->hwpage_size - 1)) {
- if (pginfo->hwpage_cnt) {
- ehca_gen_err(
- "invalid alignment "
- "pgaddr=%llx i=%x "
- "mr_pgsize=%llx",
- pgaddr, i,
- pginfo->hwpage_size);
- ret = -EFAULT;
- return ret;
- }
- /* first MR page */
- pginfo->kpage_cnt =
- (pgaddr &
- (pginfo->hwpage_size - 1)) >>
- PAGE_SHIFT;
- nr_kpages -= pginfo->kpage_cnt;
- *kpage = pgaddr &
- ~(pginfo->hwpage_size - 1);
- }
- if (ehca_debug_level >= 3) {
- u64 val = *(u64 *)__va(pgaddr);
- ehca_gen_dbg("kpage=%llx chunk_page=%llx "
- "value=%016llx",
- *kpage, pgaddr, val);
- }
- prev_pgaddr = pgaddr;
- i++;
- pginfo->kpage_cnt++;
- pginfo->u.usr.next_nmap++;
- nr_kpages--;
- if (!nr_kpages)
- goto next_kpage;
- continue;
+ /* first MR page */
+ pginfo->kpage_cnt =
+ (pgaddr &
+ (pginfo->hwpage_size - 1)) >>
+ PAGE_SHIFT;
+ nr_kpages -= pginfo->kpage_cnt;
+ *kpage = pgaddr &
+ ~(pginfo->hwpage_size - 1);
}
- if (i + nr_kpages > chunk->nmap) {
- ret = ehca_check_kpages_per_ate(
- chunk->page_list, i,
- chunk->nmap - 1, &prev_pgaddr);
- if (ret) return ret;
- pginfo->kpage_cnt += chunk->nmap - i;
- pginfo->u.usr.next_nmap += chunk->nmap - i;
- nr_kpages -= chunk->nmap - i;
- break;
+ if (ehca_debug_level >= 3) {
+ u64 val = *(u64 *)__va(pgaddr);
+ ehca_gen_dbg("kpage=%llx page=%llx "
+ "value=%016llx",
+ *kpage, pgaddr, val);
}
+ prev_pgaddr = pgaddr;
+ *sg = sg_next(*sg);
+ pginfo->kpage_cnt++;
+ pginfo->u.usr.next_nmap++;
+ nr_kpages--;
+ if (!nr_kpages)
+ goto next_kpage;
+ continue;
+ }
+
+ ret = ehca_check_kpages_per_ate(sg, nr_kpages,
+ &prev_pgaddr);
+ if (ret)
+ return ret;
+ pginfo->kpage_cnt += nr_kpages;
+ pginfo->u.usr.next_nmap += nr_kpages;
- ret = ehca_check_kpages_per_ate(chunk->page_list, i,
- i + nr_kpages - 1,
- &prev_pgaddr);
- if (ret) return ret;
- i += nr_kpages;
- pginfo->kpage_cnt += nr_kpages;
- pginfo->u.usr.next_nmap += nr_kpages;
next_kpage:
- nr_kpages = kpages_per_hwpage;
- (pginfo->hwpage_cnt)++;
- kpage++;
- j++;
- if (j >= number) break;
- }
- if ((pginfo->u.usr.next_nmap >= chunk->nmap) &&
- (j >= number)) {
- pginfo->u.usr.next_nmap = 0;
- prev_chunk = chunk;
- break;
- } else if (pginfo->u.usr.next_nmap >= chunk->nmap) {
- pginfo->u.usr.next_nmap = 0;
- prev_chunk = chunk;
- } else if (j >= number)
+ nr_kpages = kpages_per_hwpage;
+ (pginfo->hwpage_cnt)++;
+ kpage++;
+ j++;
+ if (j >= number)
break;
- else
- prev_chunk = chunk;
}
- pginfo->u.usr.next_chunk =
- list_prepare_entry(prev_chunk,
- (&(pginfo->u.usr.region->chunk_list)),
- list);
+
return ret;
}
@@ -2591,16 +2534,6 @@ static void ehca_dma_unmap_sg(struct ib_device *dev, struct scatterlist *sg,
/* This is only a stub; nothing to be done here */
}
-static u64 ehca_dma_address(struct ib_device *dev, struct scatterlist *sg)
-{
- return sg->dma_address;
-}
-
-static unsigned int ehca_dma_len(struct ib_device *dev, struct scatterlist *sg)
-{
- return sg->length;
-}
-
static void ehca_dma_sync_single_for_cpu(struct ib_device *dev, u64 addr,
size_t size,
enum dma_data_direction dir)
@@ -2653,8 +2586,6 @@ struct ib_dma_mapping_ops ehca_dma_mapping_ops = {
.unmap_page = ehca_dma_unmap_page,
.map_sg = ehca_dma_map_sg,
.unmap_sg = ehca_dma_unmap_sg,
- .dma_address = ehca_dma_address,
- .dma_len = ehca_dma_len,
.sync_single_for_cpu = ehca_dma_sync_single_for_cpu,
.sync_single_for_device = ehca_dma_sync_single_for_device,
.alloc_coherent = ehca_dma_alloc_coherent,
diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c
index 714293b78518..e2f9a51f4a38 100644
--- a/drivers/infiniband/hw/ipath/ipath_diag.c
+++ b/drivers/infiniband/hw/ipath/ipath_diag.c
@@ -326,7 +326,7 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
size_t count, loff_t *off)
{
u32 __iomem *piobuf;
- u32 plen, clen, pbufn;
+ u32 plen, pbufn, maxlen_reserve;
struct ipath_diag_pkt odp;
struct ipath_diag_xpkt dp;
u32 *tmpbuf = NULL;
@@ -335,51 +335,29 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
u64 val;
u32 l_state, lt_state; /* LinkState, LinkTrainingState */
- if (count < sizeof(odp)) {
- ret = -EINVAL;
- goto bail;
- }
if (count == sizeof(dp)) {
if (copy_from_user(&dp, data, sizeof(dp))) {
ret = -EFAULT;
goto bail;
}
- } else if (copy_from_user(&odp, data, sizeof(odp))) {
- ret = -EFAULT;
+ } else if (count == sizeof(odp)) {
+ if (copy_from_user(&odp, data, sizeof(odp))) {
+ ret = -EFAULT;
+ goto bail;
+ }
+ } else {
+ ret = -EINVAL;
goto bail;
}
- /*
- * Due to padding/alignment issues (lessened with new struct)
- * the old and new structs are the same length. We need to
- * disambiguate them, which we can do because odp.len has never
- * been less than the total of LRH+BTH+DETH so far, while
- * dp.unit (same offset) unit is unlikely to get that high.
- * Similarly, dp.data, the pointer to user at the same offset
- * as odp.unit, is almost certainly at least one (512byte)page
- * "above" NULL. The if-block below can be omitted if compatibility
- * between a new driver and older diagnostic code is unimportant.
- * compatibility the other direction (new diags, old driver) is
- * handled in the diagnostic code, with a warning.
- */
- if (dp.unit >= 20 && dp.data < 512) {
- /* very probable version mismatch. Fix it up */
- memcpy(&odp, &dp, sizeof(odp));
- /* We got a legacy dp, copy elements to dp */
- dp.unit = odp.unit;
- dp.data = odp.data;
- dp.len = odp.len;
- dp.pbc_wd = 0; /* Indicate we need to compute PBC wd */
- }
-
/* send count must be an exact number of dwords */
if (dp.len & 3) {
ret = -EINVAL;
goto bail;
}
- clen = dp.len >> 2;
+ plen = dp.len >> 2;
dd = ipath_lookup(dp.unit);
if (!dd || !(dd->ipath_flags & IPATH_PRESENT) ||
@@ -422,16 +400,22 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
goto bail;
}
- /* need total length before first word written */
- /* +1 word is for the qword padding */
- plen = sizeof(u32) + dp.len;
-
- if ((plen + 4) > dd->ipath_ibmaxlen) {
+ /*
+ * need total length before first word written, plus 2 Dwords. One Dword
+ * is for padding so we get the full user data when not aligned on
+ * a word boundary. The other Dword is to make sure we have room for the
+ * ICRC which gets tacked on later.
+ */
+ maxlen_reserve = 2 * sizeof(u32);
+ if (dp.len > dd->ipath_ibmaxlen - maxlen_reserve) {
ipath_dbg("Pkt len 0x%x > ibmaxlen %x\n",
- plen - 4, dd->ipath_ibmaxlen);
+ dp.len, dd->ipath_ibmaxlen);
ret = -EINVAL;
- goto bail; /* before writing pbc */
+ goto bail;
}
+
+ plen = sizeof(u32) + dp.len;
+
tmpbuf = vmalloc(plen);
if (!tmpbuf) {
dev_info(&dd->pcidev->dev, "Unable to allocate tmp buffer, "
@@ -473,11 +457,11 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
*/
if (dd->ipath_flags & IPATH_PIO_FLUSH_WC) {
ipath_flush_wc();
- __iowrite32_copy(piobuf + 2, tmpbuf, clen - 1);
+ __iowrite32_copy(piobuf + 2, tmpbuf, plen - 1);
ipath_flush_wc();
- __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1);
+ __raw_writel(tmpbuf[plen - 1], piobuf + plen + 1);
} else
- __iowrite32_copy(piobuf + 2, tmpbuf, clen);
+ __iowrite32_copy(piobuf + 2, tmpbuf, plen);
ipath_flush_wc();
diff --git a/drivers/infiniband/hw/ipath/ipath_dma.c b/drivers/infiniband/hw/ipath/ipath_dma.c
index 644c2c74e054..123a8c053539 100644
--- a/drivers/infiniband/hw/ipath/ipath_dma.c
+++ b/drivers/infiniband/hw/ipath/ipath_dma.c
@@ -115,6 +115,10 @@ static int ipath_map_sg(struct ib_device *dev, struct scatterlist *sgl,
ret = 0;
break;
}
+ sg->dma_address = addr + sg->offset;
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
+ sg->dma_length = sg->length;
+#endif
}
return ret;
}
@@ -126,21 +130,6 @@ static void ipath_unmap_sg(struct ib_device *dev,
BUG_ON(!valid_dma_direction(direction));
}
-static u64 ipath_sg_dma_address(struct ib_device *dev, struct scatterlist *sg)
-{
- u64 addr = (u64) page_address(sg_page(sg));
-
- if (addr)
- addr += sg->offset;
- return addr;
-}
-
-static unsigned int ipath_sg_dma_len(struct ib_device *dev,
- struct scatterlist *sg)
-{
- return sg->length;
-}
-
static void ipath_sync_single_for_cpu(struct ib_device *dev,
u64 addr,
size_t size,
@@ -176,17 +165,15 @@ static void ipath_dma_free_coherent(struct ib_device *dev, size_t size,
}
struct ib_dma_mapping_ops ipath_dma_mapping_ops = {
- ipath_mapping_error,
- ipath_dma_map_single,
- ipath_dma_unmap_single,
- ipath_dma_map_page,
- ipath_dma_unmap_page,
- ipath_map_sg,
- ipath_unmap_sg,
- ipath_sg_dma_address,
- ipath_sg_dma_len,
- ipath_sync_single_for_cpu,
- ipath_sync_single_for_device,
- ipath_dma_alloc_coherent,
- ipath_dma_free_coherent
+ .mapping_error = ipath_mapping_error,
+ .map_single = ipath_dma_map_single,
+ .unmap_single = ipath_dma_unmap_single,
+ .map_page = ipath_dma_map_page,
+ .unmap_page = ipath_dma_unmap_page,
+ .map_sg = ipath_map_sg,
+ .unmap_sg = ipath_unmap_sg,
+ .sync_single_for_cpu = ipath_sync_single_for_cpu,
+ .sync_single_for_device = ipath_sync_single_for_device,
+ .alloc_coherent = ipath_dma_alloc_coherent,
+ .free_coherent = ipath_dma_free_coherent
};
diff --git a/drivers/infiniband/hw/ipath/ipath_mr.c b/drivers/infiniband/hw/ipath/ipath_mr.c
index e346d3890a0e..5e61e9bff697 100644
--- a/drivers/infiniband/hw/ipath/ipath_mr.c
+++ b/drivers/infiniband/hw/ipath/ipath_mr.c
@@ -188,8 +188,8 @@ struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
{
struct ipath_mr *mr;
struct ib_umem *umem;
- struct ib_umem_chunk *chunk;
- int n, m, i;
+ int n, m, entry;
+ struct scatterlist *sg;
struct ib_mr *ret;
if (length == 0) {
@@ -202,10 +202,7 @@ struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
if (IS_ERR(umem))
return (void *) umem;
- n = 0;
- list_for_each_entry(chunk, &umem->chunk_list, list)
- n += chunk->nents;
-
+ n = umem->nmap;
mr = alloc_mr(n, &to_idev(pd->device)->lk_table);
if (!mr) {
ret = ERR_PTR(-ENOMEM);
@@ -224,22 +221,20 @@ struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
m = 0;
n = 0;
- list_for_each_entry(chunk, &umem->chunk_list, list) {
- for (i = 0; i < chunk->nents; i++) {
- void *vaddr;
-
- vaddr = page_address(sg_page(&chunk->page_list[i]));
- if (!vaddr) {
- ret = ERR_PTR(-EINVAL);
- goto bail;
- }
- mr->mr.map[m]->segs[n].vaddr = vaddr;
- mr->mr.map[m]->segs[n].length = umem->page_size;
- n++;
- if (n == IPATH_SEGSZ) {
- m++;
- n = 0;
- }
+ for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) {
+ void *vaddr;
+
+ vaddr = page_address(sg_page(sg));
+ if (!vaddr) {
+ ret = ERR_PTR(-EINVAL);
+ goto bail;
+ }
+ mr->mr.map[m]->segs[n].vaddr = vaddr;
+ mr->mr.map[m]->segs[n].length = umem->page_size;
+ n++;
+ if (n == IPATH_SEGSZ) {
+ m++;
+ n = 0;
}
}
ret = &mr->ibmr;
diff --git a/drivers/infiniband/hw/mlx4/alias_GUID.c b/drivers/infiniband/hw/mlx4/alias_GUID.c
index 2f215b93db6b..0eb141c41416 100644
--- a/drivers/infiniband/hw/mlx4/alias_GUID.c
+++ b/drivers/infiniband/hw/mlx4/alias_GUID.c
@@ -154,7 +154,7 @@ void mlx4_ib_notify_slaves_on_guid_change(struct mlx4_ib_dev *dev,
continue;
slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ;
- if (slave_id >= dev->dev->num_slaves)
+ if (slave_id >= dev->dev->num_vfs + 1)
return;
tmp_cur_ag = *(__be64 *)&p_data[i * GUID_REC_SIZE];
form_cache_ag = get_cached_alias_guid(dev, port_num,
diff --git a/drivers/infiniband/hw/mlx4/cm.c b/drivers/infiniband/hw/mlx4/cm.c
index d1f5f1dd77b0..56a593e0ae5d 100644
--- a/drivers/infiniband/hw/mlx4/cm.c
+++ b/drivers/infiniband/hw/mlx4/cm.c
@@ -61,6 +61,11 @@ struct cm_generic_msg {
__be32 remote_comm_id;
};
+struct cm_sidr_generic_msg {
+ struct ib_mad_hdr hdr;
+ __be32 request_id;
+};
+
struct cm_req_msg {
unsigned char unused[0x60];
union ib_gid primary_path_sgid;
@@ -69,28 +74,62 @@ struct cm_req_msg {
static void set_local_comm_id(struct ib_mad *mad, u32 cm_id)
{
- struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
- msg->local_comm_id = cpu_to_be32(cm_id);
+ if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
+ struct cm_sidr_generic_msg *msg =
+ (struct cm_sidr_generic_msg *)mad;
+ msg->request_id = cpu_to_be32(cm_id);
+ } else if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
+ pr_err("trying to set local_comm_id in SIDR_REP\n");
+ return;
+ } else {
+ struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
+ msg->local_comm_id = cpu_to_be32(cm_id);
+ }
}
static u32 get_local_comm_id(struct ib_mad *mad)
{
- struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
-
- return be32_to_cpu(msg->local_comm_id);
+ if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
+ struct cm_sidr_generic_msg *msg =
+ (struct cm_sidr_generic_msg *)mad;
+ return be32_to_cpu(msg->request_id);
+ } else if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
+ pr_err("trying to set local_comm_id in SIDR_REP\n");
+ return -1;
+ } else {
+ struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
+ return be32_to_cpu(msg->local_comm_id);
+ }
}
static void set_remote_comm_id(struct ib_mad *mad, u32 cm_id)
{
- struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
- msg->remote_comm_id = cpu_to_be32(cm_id);
+ if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
+ struct cm_sidr_generic_msg *msg =
+ (struct cm_sidr_generic_msg *)mad;
+ msg->request_id = cpu_to_be32(cm_id);
+ } else if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
+ pr_err("trying to set remote_comm_id in SIDR_REQ\n");
+ return;
+ } else {
+ struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
+ msg->remote_comm_id = cpu_to_be32(cm_id);
+ }
}
static u32 get_remote_comm_id(struct ib_mad *mad)
{
- struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
-
- return be32_to_cpu(msg->remote_comm_id);
+ if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
+ struct cm_sidr_generic_msg *msg =
+ (struct cm_sidr_generic_msg *)mad;
+ return be32_to_cpu(msg->request_id);
+ } else if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
+ pr_err("trying to set remote_comm_id in SIDR_REQ\n");
+ return -1;
+ } else {
+ struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
+ return be32_to_cpu(msg->remote_comm_id);
+ }
}
static union ib_gid gid_from_req_msg(struct ib_device *ibdev, struct ib_mad *mad)
@@ -282,19 +321,21 @@ int mlx4_ib_multiplex_cm_handler(struct ib_device *ibdev, int port, int slave_id
u32 sl_cm_id;
int pv_cm_id = -1;
- sl_cm_id = get_local_comm_id(mad);
-
if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID ||
- mad->mad_hdr.attr_id == CM_REP_ATTR_ID) {
+ mad->mad_hdr.attr_id == CM_REP_ATTR_ID ||
+ mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
+ sl_cm_id = get_local_comm_id(mad);
id = id_map_alloc(ibdev, slave_id, sl_cm_id);
if (IS_ERR(id)) {
mlx4_ib_warn(ibdev, "%s: id{slave: %d, sl_cm_id: 0x%x} Failed to id_map_alloc\n",
__func__, slave_id, sl_cm_id);
return PTR_ERR(id);
}
- } else if (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID) {
+ } else if (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID ||
+ mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
return 0;
} else {
+ sl_cm_id = get_local_comm_id(mad);
id = id_map_get(ibdev, &pv_cm_id, slave_id, sl_cm_id);
}
@@ -315,14 +356,18 @@ int mlx4_ib_multiplex_cm_handler(struct ib_device *ibdev, int port, int slave_id
}
int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave,
- struct ib_mad *mad)
+ struct ib_mad *mad)
{
u32 pv_cm_id;
struct id_map_entry *id;
- if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID) {
+ if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID ||
+ mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
union ib_gid gid;
+ if (!slave)
+ return 0;
+
gid = gid_from_req_msg(ibdev, mad);
*slave = mlx4_ib_find_real_gid(ibdev, port, gid.global.interface_id);
if (*slave < 0) {
@@ -341,7 +386,8 @@ int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave,
return -ENOENT;
}
- *slave = id->slave_id;
+ if (slave)
+ *slave = id->slave_id;
set_remote_comm_id(mad, id->sl_cm_id);
if (mad->mad_hdr.attr_id == CM_DREQ_ATTR_ID)
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
index cc40f08ca8f1..5f640814cc81 100644
--- a/drivers/infiniband/hw/mlx4/cq.c
+++ b/drivers/infiniband/hw/mlx4/cq.c
@@ -564,7 +564,7 @@ static int mlx4_ib_ipoib_csum_ok(__be16 status, __be16 checksum)
}
static int use_tunnel_data(struct mlx4_ib_qp *qp, struct mlx4_ib_cq *cq, struct ib_wc *wc,
- unsigned tail, struct mlx4_cqe *cqe)
+ unsigned tail, struct mlx4_cqe *cqe, int is_eth)
{
struct mlx4_ib_proxy_sqp_hdr *hdr;
@@ -574,12 +574,20 @@ static int use_tunnel_data(struct mlx4_ib_qp *qp, struct mlx4_ib_cq *cq, struct
DMA_FROM_DEVICE);
hdr = (struct mlx4_ib_proxy_sqp_hdr *) (qp->sqp_proxy_rcv[tail].addr);
wc->pkey_index = be16_to_cpu(hdr->tun.pkey_index);
- wc->slid = be16_to_cpu(hdr->tun.slid_mac_47_32);
- wc->sl = (u8) (be16_to_cpu(hdr->tun.sl_vid) >> 12);
wc->src_qp = be32_to_cpu(hdr->tun.flags_src_qp) & 0xFFFFFF;
wc->wc_flags |= (hdr->tun.g_ml_path & 0x80) ? (IB_WC_GRH) : 0;
wc->dlid_path_bits = 0;
+ if (is_eth) {
+ wc->vlan_id = be16_to_cpu(hdr->tun.sl_vid);
+ memcpy(&(wc->smac[0]), (char *)&hdr->tun.mac_31_0, 4);
+ memcpy(&(wc->smac[4]), (char *)&hdr->tun.slid_mac_47_32, 2);
+ wc->wc_flags |= (IB_WC_WITH_VLAN | IB_WC_WITH_SMAC);
+ } else {
+ wc->slid = be16_to_cpu(hdr->tun.slid_mac_47_32);
+ wc->sl = (u8) (be16_to_cpu(hdr->tun.sl_vid) >> 12);
+ }
+
return 0;
}
@@ -594,6 +602,7 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq,
struct mlx4_srq *msrq = NULL;
int is_send;
int is_error;
+ int is_eth;
u32 g_mlpath_rqpn;
u16 wqe_ctr;
unsigned tail = 0;
@@ -778,11 +787,15 @@ repoll:
break;
}
+ is_eth = (rdma_port_get_link_layer(wc->qp->device,
+ (*cur_qp)->port) ==
+ IB_LINK_LAYER_ETHERNET);
if (mlx4_is_mfunc(to_mdev(cq->ibcq.device)->dev)) {
if ((*cur_qp)->mlx4_ib_qp_type &
(MLX4_IB_QPT_PROXY_SMI_OWNER |
MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_GSI))
- return use_tunnel_data(*cur_qp, cq, wc, tail, cqe);
+ return use_tunnel_data(*cur_qp, cq, wc, tail,
+ cqe, is_eth);
}
wc->slid = be16_to_cpu(cqe->rlid);
@@ -793,20 +806,21 @@ repoll:
wc->pkey_index = be32_to_cpu(cqe->immed_rss_invalid) & 0x7f;
wc->wc_flags |= mlx4_ib_ipoib_csum_ok(cqe->status,
cqe->checksum) ? IB_WC_IP_CSUM_OK : 0;
- if (rdma_port_get_link_layer(wc->qp->device,
- (*cur_qp)->port) == IB_LINK_LAYER_ETHERNET)
+ if (is_eth) {
wc->sl = be16_to_cpu(cqe->sl_vid) >> 13;
- else
- wc->sl = be16_to_cpu(cqe->sl_vid) >> 12;
- if (be32_to_cpu(cqe->vlan_my_qpn) & MLX4_CQE_VLAN_PRESENT_MASK) {
- wc->vlan_id = be16_to_cpu(cqe->sl_vid) &
- MLX4_CQE_VID_MASK;
+ if (be32_to_cpu(cqe->vlan_my_qpn) &
+ MLX4_CQE_VLAN_PRESENT_MASK) {
+ wc->vlan_id = be16_to_cpu(cqe->sl_vid) &
+ MLX4_CQE_VID_MASK;
+ } else {
+ wc->vlan_id = 0xffff;
+ }
+ memcpy(wc->smac, cqe->smac, ETH_ALEN);
+ wc->wc_flags |= (IB_WC_WITH_VLAN | IB_WC_WITH_SMAC);
} else {
+ wc->sl = be16_to_cpu(cqe->sl_vid) >> 12;
wc->vlan_id = 0xffff;
}
- wc->wc_flags |= IB_WC_WITH_VLAN;
- memcpy(wc->smac, cqe->smac, ETH_ALEN);
- wc->wc_flags |= IB_WC_WITH_SMAC;
}
return 0;
diff --git a/drivers/infiniband/hw/mlx4/doorbell.c b/drivers/infiniband/hw/mlx4/doorbell.c
index 8aee4233b388..c51740986367 100644
--- a/drivers/infiniband/hw/mlx4/doorbell.c
+++ b/drivers/infiniband/hw/mlx4/doorbell.c
@@ -45,7 +45,6 @@ int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, unsigned long virt,
struct mlx4_db *db)
{
struct mlx4_ib_user_db_page *page;
- struct ib_umem_chunk *chunk;
int err = 0;
mutex_lock(&context->db_page_mutex);
@@ -73,8 +72,7 @@ int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, unsigned long virt,
list_add(&page->list, &context->db_page_list);
found:
- chunk = list_entry(page->umem->chunk_list.next, struct ib_umem_chunk, list);
- db->dma = sg_dma_address(chunk->page_list) + (virt & ~PAGE_MASK);
+ db->dma = sg_dma_address(page->umem->sg_head.sgl) + (virt & ~PAGE_MASK);
db->u.user_page = page;
++page->refcnt;
diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c
index f2a3f48107e7..fd36ec672632 100644
--- a/drivers/infiniband/hw/mlx4/mad.c
+++ b/drivers/infiniband/hw/mlx4/mad.c
@@ -467,6 +467,7 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
int ret = 0;
u16 tun_pkey_ix;
u16 cached_pkey;
+ u8 is_eth = dev->dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH;
if (dest_qpt > IB_QPT_GSI)
return -EINVAL;
@@ -509,6 +510,10 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
* The driver will set the force loopback bit in post_send */
memset(&attr, 0, sizeof attr);
attr.port_num = port;
+ if (is_eth) {
+ memcpy(&attr.grh.dgid.raw[0], &grh->dgid.raw[0], 16);
+ attr.ah_flags = IB_AH_GRH;
+ }
ah = ib_create_ah(tun_ctx->pd, &attr);
if (IS_ERR(ah))
return -ENOMEM;
@@ -540,11 +545,36 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
/* adjust tunnel data */
tun_mad->hdr.pkey_index = cpu_to_be16(tun_pkey_ix);
- tun_mad->hdr.sl_vid = cpu_to_be16(((u16)(wc->sl)) << 12);
- tun_mad->hdr.slid_mac_47_32 = cpu_to_be16(wc->slid);
tun_mad->hdr.flags_src_qp = cpu_to_be32(wc->src_qp & 0xFFFFFF);
tun_mad->hdr.g_ml_path = (grh && (wc->wc_flags & IB_WC_GRH)) ? 0x80 : 0;
+ if (is_eth) {
+ u16 vlan = 0;
+ if (mlx4_get_slave_default_vlan(dev->dev, port, slave, &vlan,
+ NULL)) {
+ /* VST mode */
+ if (vlan != wc->vlan_id)
+ /* Packet vlan is not the VST-assigned vlan.
+ * Drop the packet.
+ */
+ goto out;
+ else
+ /* Remove the vlan tag before forwarding
+ * the packet to the VF.
+ */
+ vlan = 0xffff;
+ } else {
+ vlan = wc->vlan_id;
+ }
+
+ tun_mad->hdr.sl_vid = cpu_to_be16(vlan);
+ memcpy((char *)&tun_mad->hdr.mac_31_0, &(wc->smac[0]), 4);
+ memcpy((char *)&tun_mad->hdr.slid_mac_47_32, &(wc->smac[4]), 2);
+ } else {
+ tun_mad->hdr.sl_vid = cpu_to_be16(((u16)(wc->sl)) << 12);
+ tun_mad->hdr.slid_mac_47_32 = cpu_to_be16(wc->slid);
+ }
+
ib_dma_sync_single_for_device(&dev->ib_dev,
tun_qp->tx_ring[tun_tx_ix].buf.map,
sizeof (struct mlx4_rcv_tunnel_mad),
@@ -580,6 +610,41 @@ static int mlx4_ib_demux_mad(struct ib_device *ibdev, u8 port,
int err;
int slave;
u8 *slave_id;
+ int is_eth = 0;
+
+ if (rdma_port_get_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND)
+ is_eth = 0;
+ else
+ is_eth = 1;
+
+ if (is_eth) {
+ if (!(wc->wc_flags & IB_WC_GRH)) {
+ mlx4_ib_warn(ibdev, "RoCE grh not present.\n");
+ return -EINVAL;
+ }
+ if (mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_CM) {
+ mlx4_ib_warn(ibdev, "RoCE mgmt class is not CM\n");
+ return -EINVAL;
+ }
+ if (mlx4_get_slave_from_roce_gid(dev->dev, port, grh->dgid.raw, &slave)) {
+ mlx4_ib_warn(ibdev, "failed matching grh\n");
+ return -ENOENT;
+ }
+ if (slave >= dev->dev->caps.sqp_demux) {
+ mlx4_ib_warn(ibdev, "slave id: %d is bigger than allowed:%d\n",
+ slave, dev->dev->caps.sqp_demux);
+ return -ENOENT;
+ }
+
+ if (mlx4_ib_demux_cm_handler(ibdev, port, NULL, mad))
+ return 0;
+
+ err = mlx4_ib_send_to_slave(dev, slave, port, wc->qp->qp_type, wc, grh, mad);
+ if (err)
+ pr_debug("failed sending to slave %d via tunnel qp (%d)\n",
+ slave, err);
+ return 0;
+ }
/* Initially assume that this mad is for us */
slave = mlx4_master_func_num(dev->dev);
@@ -1076,8 +1141,9 @@ static int is_proxy_qp0(struct mlx4_ib_dev *dev, int qpn, int slave)
int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port,
- enum ib_qp_type dest_qpt, u16 pkey_index, u32 remote_qpn,
- u32 qkey, struct ib_ah_attr *attr, struct ib_mad *mad)
+ enum ib_qp_type dest_qpt, u16 pkey_index,
+ u32 remote_qpn, u32 qkey, struct ib_ah_attr *attr,
+ u8 *s_mac, struct ib_mad *mad)
{
struct ib_sge list;
struct ib_send_wr wr, *bad_wr;
@@ -1166,6 +1232,9 @@ int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port,
wr.num_sge = 1;
wr.opcode = IB_WR_SEND;
wr.send_flags = IB_SEND_SIGNALED;
+ if (s_mac)
+ memcpy(to_mah(ah)->av.eth.s_mac, s_mac, 6);
+
ret = ib_post_send(send_qp, &wr, &bad_wr);
out:
@@ -1174,6 +1243,22 @@ out:
return ret;
}
+static int get_slave_base_gid_ix(struct mlx4_ib_dev *dev, int slave, int port)
+{
+ if (rdma_port_get_link_layer(&dev->ib_dev, port) == IB_LINK_LAYER_INFINIBAND)
+ return slave;
+ return mlx4_get_base_gid_ix(dev->dev, slave, port);
+}
+
+static void fill_in_real_sgid_index(struct mlx4_ib_dev *dev, int slave, int port,
+ struct ib_ah_attr *ah_attr)
+{
+ if (rdma_port_get_link_layer(&dev->ib_dev, port) == IB_LINK_LAYER_INFINIBAND)
+ ah_attr->grh.sgid_index = slave;
+ else
+ ah_attr->grh.sgid_index += get_slave_base_gid_ix(dev, slave, port);
+}
+
static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc *wc)
{
struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev);
@@ -1184,6 +1269,7 @@ static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc
struct ib_ah_attr ah_attr;
u8 *slave_id;
int slave;
+ int port;
/* Get slave that sent this packet */
if (wc->src_qp < dev->dev->phys_caps.base_proxy_sqpn ||
@@ -1260,12 +1346,18 @@ static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc
memcpy(&ah.av, &tunnel->hdr.av, sizeof (struct mlx4_av));
ah.ibah.device = ctx->ib_dev;
mlx4_ib_query_ah(&ah.ibah, &ah_attr);
- if ((ah_attr.ah_flags & IB_AH_GRH) &&
- (ah_attr.grh.sgid_index != slave)) {
- mlx4_ib_warn(ctx->ib_dev, "slave:%d accessed invalid sgid_index:%d\n",
- slave, ah_attr.grh.sgid_index);
+ if (ah_attr.ah_flags & IB_AH_GRH)
+ fill_in_real_sgid_index(dev, slave, ctx->port, &ah_attr);
+
+ port = mlx4_slave_convert_port(dev->dev, slave, ah_attr.port_num);
+ if (port < 0)
return;
- }
+ ah_attr.port_num = port;
+ memcpy(ah_attr.dmac, tunnel->hdr.mac, 6);
+ ah_attr.vlan_id = be16_to_cpu(tunnel->hdr.vlan);
+ /* if slave have default vlan use it */
+ mlx4_get_slave_default_vlan(dev->dev, ctx->port, slave,
+ &ah_attr.vlan_id, &ah_attr.sl);
mlx4_ib_send_to_wire(dev, slave, ctx->port,
is_proxy_qp0(dev, wc->src_qp, slave) ?
@@ -1273,7 +1365,7 @@ static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc
be16_to_cpu(tunnel->hdr.pkey_index),
be32_to_cpu(tunnel->hdr.remote_qpn),
be32_to_cpu(tunnel->hdr.qkey),
- &ah_attr, &tunnel->mad);
+ &ah_attr, wc->smac, &tunnel->mad);
}
static int mlx4_ib_alloc_pv_bufs(struct mlx4_ib_demux_pv_ctx *ctx,
@@ -1850,7 +1942,15 @@ static int mlx4_ib_alloc_demux_ctx(struct mlx4_ib_dev *dev,
ctx->port = port;
ctx->ib_dev = &dev->ib_dev;
- for (i = 0; i < dev->dev->caps.sqp_demux; i++) {
+ for (i = 0;
+ i < min(dev->dev->caps.sqp_demux, (u16)(dev->dev->num_vfs + 1));
+ i++) {
+ struct mlx4_active_ports actv_ports =
+ mlx4_get_active_ports(dev->dev, i);
+
+ if (!test_bit(port - 1, actv_ports.ports))
+ continue;
+
ret = alloc_pv_object(dev, i, port, &ctx->tun[i]);
if (ret) {
ret = -ENOMEM;
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index c2702f549f10..1b6dbe156a37 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -53,8 +53,8 @@
#include "user.h"
#define DRV_NAME MLX4_IB_DRV_NAME
-#define DRV_VERSION "1.0"
-#define DRV_RELDATE "April 4, 2008"
+#define DRV_VERSION "2.2-1"
+#define DRV_RELDATE "Feb 2014"
#define MLX4_IB_FLOW_MAX_PRIO 0xFFF
#define MLX4_IB_FLOW_QPN_MASK 0xFFFFFF
@@ -347,7 +347,7 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port,
props->active_width = (((u8 *)mailbox->buf)[5] == 0x40) ?
IB_WIDTH_4X : IB_WIDTH_1X;
props->active_speed = IB_SPEED_QDR;
- props->port_cap_flags = IB_PORT_CM_SUP;
+ props->port_cap_flags = IB_PORT_CM_SUP | IB_PORT_IP_BASED_GIDS;
props->gid_tbl_len = mdev->dev->caps.gid_table_len[port];
props->max_msg_sz = mdev->dev->caps.max_msg_sz;
props->pkey_tbl_len = 1;
@@ -1357,6 +1357,21 @@ static struct device_attribute *mlx4_class_attributes[] = {
&dev_attr_board_id
};
+static void mlx4_addrconf_ifid_eui48(u8 *eui, u16 vlan_id,
+ struct net_device *dev)
+{
+ memcpy(eui, dev->dev_addr, 3);
+ memcpy(eui + 5, dev->dev_addr + 3, 3);
+ if (vlan_id < 0x1000) {
+ eui[3] = vlan_id >> 8;
+ eui[4] = vlan_id & 0xff;
+ } else {
+ eui[3] = 0xff;
+ eui[4] = 0xfe;
+ }
+ eui[0] ^= 2;
+}
+
static void update_gids_task(struct work_struct *work)
{
struct update_gid_work *gw = container_of(work, struct update_gid_work, work);
@@ -1393,7 +1408,6 @@ static void reset_gids_task(struct work_struct *work)
struct mlx4_cmd_mailbox *mailbox;
union ib_gid *gids;
int err;
- int i;
struct mlx4_dev *dev = gw->dev->dev;
mailbox = mlx4_alloc_cmd_mailbox(dev);
@@ -1405,18 +1419,16 @@ static void reset_gids_task(struct work_struct *work)
gids = mailbox->buf;
memcpy(gids, gw->gids, sizeof(gw->gids));
- for (i = 1; i < gw->dev->num_ports + 1; i++) {
- if (mlx4_ib_port_link_layer(&gw->dev->ib_dev, i) ==
- IB_LINK_LAYER_ETHERNET) {
- err = mlx4_cmd(dev, mailbox->dma,
- MLX4_SET_PORT_GID_TABLE << 8 | i,
- 1, MLX4_CMD_SET_PORT,
- MLX4_CMD_TIME_CLASS_B,
- MLX4_CMD_WRAPPED);
- if (err)
- pr_warn(KERN_WARNING
- "set port %d command failed\n", i);
- }
+ if (mlx4_ib_port_link_layer(&gw->dev->ib_dev, gw->port) ==
+ IB_LINK_LAYER_ETHERNET) {
+ err = mlx4_cmd(dev, mailbox->dma,
+ MLX4_SET_PORT_GID_TABLE << 8 | gw->port,
+ 1, MLX4_CMD_SET_PORT,
+ MLX4_CMD_TIME_CLASS_B,
+ MLX4_CMD_WRAPPED);
+ if (err)
+ pr_warn(KERN_WARNING
+ "set port %d command failed\n", gw->port);
}
mlx4_free_cmd_mailbox(dev, mailbox);
@@ -1425,7 +1437,8 @@ free:
}
static int update_gid_table(struct mlx4_ib_dev *dev, int port,
- union ib_gid *gid, int clear)
+ union ib_gid *gid, int clear,
+ int default_gid)
{
struct update_gid_work *work;
int i;
@@ -1434,26 +1447,31 @@ static int update_gid_table(struct mlx4_ib_dev *dev, int port,
int found = -1;
int max_gids;
- max_gids = dev->dev->caps.gid_table_len[port];
- for (i = 0; i < max_gids; ++i) {
- if (!memcmp(&dev->iboe.gid_table[port - 1][i], gid,
- sizeof(*gid)))
- found = i;
-
- if (clear) {
- if (found >= 0) {
- need_update = 1;
- dev->iboe.gid_table[port - 1][found] = zgid;
- break;
- }
- } else {
- if (found >= 0)
- break;
-
- if (free < 0 &&
- !memcmp(&dev->iboe.gid_table[port - 1][i], &zgid,
+ if (default_gid) {
+ free = 0;
+ } else {
+ max_gids = dev->dev->caps.gid_table_len[port];
+ for (i = 1; i < max_gids; ++i) {
+ if (!memcmp(&dev->iboe.gid_table[port - 1][i], gid,
sizeof(*gid)))
- free = i;
+ found = i;
+
+ if (clear) {
+ if (found >= 0) {
+ need_update = 1;
+ dev->iboe.gid_table[port - 1][found] =
+ zgid;
+ break;
+ }
+ } else {
+ if (found >= 0)
+ break;
+
+ if (free < 0 &&
+ !memcmp(&dev->iboe.gid_table[port - 1][i],
+ &zgid, sizeof(*gid)))
+ free = i;
+ }
}
}
@@ -1478,18 +1496,26 @@ static int update_gid_table(struct mlx4_ib_dev *dev, int port,
return 0;
}
-static int reset_gid_table(struct mlx4_ib_dev *dev)
+static void mlx4_make_default_gid(struct net_device *dev, union ib_gid *gid)
{
- struct update_gid_work *work;
+ gid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL);
+ mlx4_addrconf_ifid_eui48(&gid->raw[8], 0xffff, dev);
+}
+
+static int reset_gid_table(struct mlx4_ib_dev *dev, u8 port)
+{
+ struct update_gid_work *work;
work = kzalloc(sizeof(*work), GFP_ATOMIC);
if (!work)
return -ENOMEM;
- memset(dev->iboe.gid_table, 0, sizeof(dev->iboe.gid_table));
+
+ memset(dev->iboe.gid_table[port - 1], 0, sizeof(work->gids));
memset(work->gids, 0, sizeof(work->gids));
INIT_WORK(&work->work, reset_gids_task);
work->dev = dev;
+ work->port = port;
queue_work(wq, &work->work);
return 0;
}
@@ -1502,6 +1528,12 @@ static int mlx4_ib_addr_event(int event, struct net_device *event_netdev,
struct net_device *real_dev = rdma_vlan_dev_real_dev(event_netdev) ?
rdma_vlan_dev_real_dev(event_netdev) :
event_netdev;
+ union ib_gid default_gid;
+
+ mlx4_make_default_gid(real_dev, &default_gid);
+
+ if (!memcmp(gid, &default_gid, sizeof(*gid)))
+ return 0;
if (event != NETDEV_DOWN && event != NETDEV_UP)
return 0;
@@ -1514,13 +1546,13 @@ static int mlx4_ib_addr_event(int event, struct net_device *event_netdev,
iboe = &ibdev->iboe;
spin_lock(&iboe->lock);
- for (port = 1; port <= MLX4_MAX_PORTS; ++port)
+ for (port = 1; port <= ibdev->dev->caps.num_ports; ++port)
if ((netif_is_bond_master(real_dev) &&
(real_dev == iboe->masters[port - 1])) ||
(!netif_is_bond_master(real_dev) &&
(real_dev == iboe->netdevs[port - 1])))
update_gid_table(ibdev, port, gid,
- event == NETDEV_DOWN);
+ event == NETDEV_DOWN, 0);
spin_unlock(&iboe->lock);
return 0;
@@ -1536,18 +1568,15 @@ static u8 mlx4_ib_get_dev_port(struct net_device *dev,
rdma_vlan_dev_real_dev(dev) : dev;
iboe = &ibdev->iboe;
- spin_lock(&iboe->lock);
- for (port = 1; port <= MLX4_MAX_PORTS; ++port)
+ for (port = 1; port <= ibdev->dev->caps.num_ports; ++port)
if ((netif_is_bond_master(real_dev) &&
(real_dev == iboe->masters[port - 1])) ||
(!netif_is_bond_master(real_dev) &&
(real_dev == iboe->netdevs[port - 1])))
break;
- spin_unlock(&iboe->lock);
-
- if ((port == 0) || (port > MLX4_MAX_PORTS))
+ if ((port == 0) || (port > ibdev->dev->caps.num_ports))
return 0;
else
return port;
@@ -1597,7 +1626,7 @@ static void mlx4_ib_get_dev_addr(struct net_device *dev,
union ib_gid gid;
- if ((port == 0) || (port > MLX4_MAX_PORTS))
+ if ((port == 0) || (port > ibdev->dev->caps.num_ports))
return;
/* IPv4 gids */
@@ -1607,7 +1636,7 @@ static void mlx4_ib_get_dev_addr(struct net_device *dev,
/*ifa->ifa_address;*/
ipv6_addr_set_v4mapped(ifa->ifa_address,
(struct in6_addr *)&gid);
- update_gid_table(ibdev, port, &gid, 0);
+ update_gid_table(ibdev, port, &gid, 0, 0);
}
endfor_ifa(in_dev);
in_dev_put(in_dev);
@@ -1619,7 +1648,7 @@ static void mlx4_ib_get_dev_addr(struct net_device *dev,
read_lock_bh(&in6_dev->lock);
list_for_each_entry(ifp, &in6_dev->addr_list, if_list) {
pgid = (union ib_gid *)&ifp->addr;
- update_gid_table(ibdev, port, pgid, 0);
+ update_gid_table(ibdev, port, pgid, 0, 0);
}
read_unlock_bh(&in6_dev->lock);
in6_dev_put(in6_dev);
@@ -1627,14 +1656,26 @@ static void mlx4_ib_get_dev_addr(struct net_device *dev,
#endif
}
+static void mlx4_ib_set_default_gid(struct mlx4_ib_dev *ibdev,
+ struct net_device *dev, u8 port)
+{
+ union ib_gid gid;
+ mlx4_make_default_gid(dev, &gid);
+ update_gid_table(ibdev, port, &gid, 0, 1);
+}
+
static int mlx4_ib_init_gid_table(struct mlx4_ib_dev *ibdev)
{
struct net_device *dev;
+ struct mlx4_ib_iboe *iboe = &ibdev->iboe;
+ int i;
- if (reset_gid_table(ibdev))
- return -1;
+ for (i = 1; i <= ibdev->num_ports; ++i)
+ if (reset_gid_table(ibdev, i))
+ return -1;
read_lock(&dev_base_lock);
+ spin_lock(&iboe->lock);
for_each_netdev(&init_net, dev) {
u8 port = mlx4_ib_get_dev_port(dev, ibdev);
@@ -1642,6 +1683,7 @@ static int mlx4_ib_init_gid_table(struct mlx4_ib_dev *ibdev)
mlx4_ib_get_dev_addr(dev, ibdev, port);
}
+ spin_unlock(&iboe->lock);
read_unlock(&dev_base_lock);
return 0;
@@ -1656,25 +1698,57 @@ static void mlx4_ib_scan_netdevs(struct mlx4_ib_dev *ibdev)
spin_lock(&iboe->lock);
mlx4_foreach_ib_transport_port(port, ibdev->dev) {
+ enum ib_port_state port_state = IB_PORT_NOP;
struct net_device *old_master = iboe->masters[port - 1];
+ struct net_device *curr_netdev;
struct net_device *curr_master;
+
iboe->netdevs[port - 1] =
mlx4_get_protocol_dev(ibdev->dev, MLX4_PROT_ETH, port);
+ if (iboe->netdevs[port - 1])
+ mlx4_ib_set_default_gid(ibdev,
+ iboe->netdevs[port - 1], port);
+ curr_netdev = iboe->netdevs[port - 1];
if (iboe->netdevs[port - 1] &&
netif_is_bond_slave(iboe->netdevs[port - 1])) {
- rtnl_lock();
iboe->masters[port - 1] = netdev_master_upper_dev_get(
iboe->netdevs[port - 1]);
- rtnl_unlock();
+ } else {
+ iboe->masters[port - 1] = NULL;
}
curr_master = iboe->masters[port - 1];
+ if (curr_netdev) {
+ port_state = (netif_running(curr_netdev) && netif_carrier_ok(curr_netdev)) ?
+ IB_PORT_ACTIVE : IB_PORT_DOWN;
+ mlx4_ib_set_default_gid(ibdev, curr_netdev, port);
+ } else {
+ reset_gid_table(ibdev, port);
+ }
+ /* if using bonding/team and a slave port is down, we don't the bond IP
+ * based gids in the table since flows that select port by gid may get
+ * the down port.
+ */
+ if (curr_master && (port_state == IB_PORT_DOWN)) {
+ reset_gid_table(ibdev, port);
+ mlx4_ib_set_default_gid(ibdev, curr_netdev, port);
+ }
/* if bonding is used it is possible that we add it to masters
- only after IP address is assigned to the net bonding
- interface */
- if (curr_master && (old_master != curr_master))
+ * only after IP address is assigned to the net bonding
+ * interface.
+ */
+ if (curr_master && (old_master != curr_master)) {
+ reset_gid_table(ibdev, port);
+ mlx4_ib_set_default_gid(ibdev, curr_netdev, port);
mlx4_ib_get_dev_addr(curr_master, ibdev, port);
+ }
+
+ if (!curr_master && (old_master != curr_master)) {
+ reset_gid_table(ibdev, port);
+ mlx4_ib_set_default_gid(ibdev, curr_netdev, port);
+ mlx4_ib_get_dev_addr(curr_netdev, ibdev, port);
+ }
}
spin_unlock(&iboe->lock);
@@ -1729,7 +1803,7 @@ static void init_pkeys(struct mlx4_ib_dev *ibdev)
static void mlx4_ib_alloc_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev)
{
- char name[32];
+ char name[80];
int eq_per_port = 0;
int added_eqs = 0;
int total_eqs = 0;
@@ -1759,8 +1833,8 @@ static void mlx4_ib_alloc_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev)
eq = 0;
mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) {
for (j = 0; j < eq_per_port; j++) {
- sprintf(name, "mlx4-ib-%d-%d@%s",
- i, j, dev->pdev->bus->name);
+ snprintf(name, sizeof(name), "mlx4-ib-%d-%d@%s",
+ i, j, dev->pdev->bus->name);
/* Set IRQ for specific name (per ring) */
if (mlx4_assign_eq(dev, name, NULL,
&ibdev->eq_table[eq])) {
@@ -1810,17 +1884,10 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
int i, j;
int err;
struct mlx4_ib_iboe *iboe;
+ int ib_num_ports = 0;
pr_info_once("%s", mlx4_ib_version);
- mlx4_foreach_non_ib_transport_port(i, dev)
- num_ports++;
-
- if (mlx4_is_mfunc(dev) && num_ports) {
- dev_err(&dev->pdev->dev, "RoCE is not supported over SRIOV as yet\n");
- return NULL;
- }
-
num_ports = 0;
mlx4_foreach_ib_transport_port(i, dev)
num_ports++;
@@ -1981,14 +2048,19 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
err = mlx4_counter_alloc(ibdev->dev, &ibdev->counters[i]);
if (err)
ibdev->counters[i] = -1;
- } else
- ibdev->counters[i] = -1;
+ } else {
+ ibdev->counters[i] = -1;
+ }
}
+ mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
+ ib_num_ports++;
+
spin_lock_init(&ibdev->sm_lock);
mutex_init(&ibdev->cap_mask_mutex);
- if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED) {
+ if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED &&
+ ib_num_ports) {
ibdev->steer_qpn_count = MLX4_IB_UC_MAX_NUM_QPS;
err = mlx4_qp_reserve_range(dev, ibdev->steer_qpn_count,
MLX4_IB_UC_STEER_QPN_ALIGN,
@@ -2051,7 +2123,11 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
}
}
#endif
+ for (i = 1 ; i <= ibdev->num_ports ; ++i)
+ reset_gid_table(ibdev, i);
+ rtnl_lock();
mlx4_ib_scan_netdevs(ibdev);
+ rtnl_unlock();
mlx4_ib_init_gid_table(ibdev);
}
@@ -2248,17 +2324,24 @@ static void do_slave_init(struct mlx4_ib_dev *ibdev, int slave, int do_init)
struct mlx4_dev *dev = ibdev->dev;
int i;
unsigned long flags;
+ struct mlx4_active_ports actv_ports;
+ unsigned int ports;
+ unsigned int first_port;
if (!mlx4_is_master(dev))
return;
- dm = kcalloc(dev->caps.num_ports, sizeof *dm, GFP_ATOMIC);
+ actv_ports = mlx4_get_active_ports(dev, slave);
+ ports = bitmap_weight(actv_ports.ports, dev->caps.num_ports);
+ first_port = find_first_bit(actv_ports.ports, dev->caps.num_ports);
+
+ dm = kcalloc(ports, sizeof(*dm), GFP_ATOMIC);
if (!dm) {
pr_err("failed to allocate memory for tunneling qp update\n");
goto out;
}
- for (i = 0; i < dev->caps.num_ports; i++) {
+ for (i = 0; i < ports; i++) {
dm[i] = kmalloc(sizeof (struct mlx4_ib_demux_work), GFP_ATOMIC);
if (!dm[i]) {
pr_err("failed to allocate memory for tunneling qp update work struct\n");
@@ -2270,9 +2353,9 @@ static void do_slave_init(struct mlx4_ib_dev *ibdev, int slave, int do_init)
}
}
/* initialize or tear down tunnel QPs for the slave */
- for (i = 0; i < dev->caps.num_ports; i++) {
+ for (i = 0; i < ports; i++) {
INIT_WORK(&dm[i]->work, mlx4_ib_tunnels_update_work);
- dm[i]->port = i + 1;
+ dm[i]->port = first_port + i + 1;
dm[i]->slave = slave;
dm[i]->do_init = do_init;
dm[i]->dev = ibdev;
diff --git a/drivers/infiniband/hw/mlx4/mcg.c b/drivers/infiniband/hw/mlx4/mcg.c
index 25b2cdff00f8..ed327e6c8fdc 100644
--- a/drivers/infiniband/hw/mlx4/mcg.c
+++ b/drivers/infiniband/hw/mlx4/mcg.c
@@ -215,8 +215,9 @@ static int send_mad_to_wire(struct mlx4_ib_demux_ctx *ctx, struct ib_mad *mad)
}
mlx4_ib_query_ah(dev->sm_ah[ctx->port - 1], &ah_attr);
spin_unlock(&dev->sm_lock);
- return mlx4_ib_send_to_wire(dev, mlx4_master_func_num(dev->dev), ctx->port,
- IB_QPT_GSI, 0, 1, IB_QP1_QKEY, &ah_attr, mad);
+ return mlx4_ib_send_to_wire(dev, mlx4_master_func_num(dev->dev),
+ ctx->port, IB_QPT_GSI, 0, 1, IB_QP1_QKEY,
+ &ah_attr, NULL, mad);
}
static int send_mad_to_slave(int slave, struct mlx4_ib_demux_ctx *ctx,
diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h
index a230683af940..f589522fddfd 100644
--- a/drivers/infiniband/hw/mlx4/mlx4_ib.h
+++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h
@@ -241,6 +241,22 @@ struct mlx4_ib_proxy_sqp_hdr {
struct mlx4_rcv_tunnel_hdr tun;
} __packed;
+struct mlx4_roce_smac_vlan_info {
+ u64 smac;
+ int smac_index;
+ int smac_port;
+ u64 candidate_smac;
+ int candidate_smac_index;
+ int candidate_smac_port;
+ u16 vid;
+ int vlan_index;
+ int vlan_port;
+ u16 candidate_vid;
+ int candidate_vlan_index;
+ int candidate_vlan_port;
+ int update_vid;
+};
+
struct mlx4_ib_qp {
struct ib_qp ibqp;
struct mlx4_qp mqp;
@@ -273,8 +289,9 @@ struct mlx4_ib_qp {
struct list_head gid_list;
struct list_head steering_rules;
struct mlx4_ib_buf *sqp_proxy_rcv;
+ struct mlx4_roce_smac_vlan_info pri;
+ struct mlx4_roce_smac_vlan_info alt;
u64 reg_id;
-
};
struct mlx4_ib_srq {
@@ -720,9 +737,12 @@ void mlx4_ib_tunnels_update_work(struct work_struct *work);
int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
enum ib_qp_type qpt, struct ib_wc *wc,
struct ib_grh *grh, struct ib_mad *mad);
+
int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port,
enum ib_qp_type dest_qpt, u16 pkey_index, u32 remote_qpn,
- u32 qkey, struct ib_ah_attr *attr, struct ib_mad *mad);
+ u32 qkey, struct ib_ah_attr *attr, u8 *s_mac,
+ struct ib_mad *mad);
+
__be64 mlx4_ib_get_new_demux_tid(struct mlx4_ib_demux_ctx *ctx);
int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave,
diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c
index e471f089ff00..cb2a8727f3fb 100644
--- a/drivers/infiniband/hw/mlx4/mr.c
+++ b/drivers/infiniband/hw/mlx4/mr.c
@@ -90,11 +90,11 @@ int mlx4_ib_umem_write_mtt(struct mlx4_ib_dev *dev, struct mlx4_mtt *mtt,
struct ib_umem *umem)
{
u64 *pages;
- struct ib_umem_chunk *chunk;
- int i, j, k;
+ int i, k, entry;
int n;
int len;
int err = 0;
+ struct scatterlist *sg;
pages = (u64 *) __get_free_page(GFP_KERNEL);
if (!pages)
@@ -102,26 +102,25 @@ int mlx4_ib_umem_write_mtt(struct mlx4_ib_dev *dev, struct mlx4_mtt *mtt,
i = n = 0;
- list_for_each_entry(chunk, &umem->chunk_list, list)
- for (j = 0; j < chunk->nmap; ++j) {
- len = sg_dma_len(&chunk->page_list[j]) >> mtt->page_shift;
- for (k = 0; k < len; ++k) {
- pages[i++] = sg_dma_address(&chunk->page_list[j]) +
- umem->page_size * k;
- /*
- * Be friendly to mlx4_write_mtt() and
- * pass it chunks of appropriate size.
- */
- if (i == PAGE_SIZE / sizeof (u64)) {
- err = mlx4_write_mtt(dev->dev, mtt, n,
- i, pages);
- if (err)
- goto out;
- n += i;
- i = 0;
- }
+ for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) {
+ len = sg_dma_len(sg) >> mtt->page_shift;
+ for (k = 0; k < len; ++k) {
+ pages[i++] = sg_dma_address(sg) +
+ umem->page_size * k;
+ /*
+ * Be friendly to mlx4_write_mtt() and
+ * pass it chunks of appropriate size.
+ */
+ if (i == PAGE_SIZE / sizeof (u64)) {
+ err = mlx4_write_mtt(dev->dev, mtt, n,
+ i, pages);
+ if (err)
+ goto out;
+ n += i;
+ i = 0;
}
}
+ }
if (i)
err = mlx4_write_mtt(dev->dev, mtt, n, i, pages);
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index d8f4d1fe8494..41308af4163c 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -662,10 +662,14 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
if (!sqp)
return -ENOMEM;
qp = &sqp->qp;
+ qp->pri.vid = 0xFFFF;
+ qp->alt.vid = 0xFFFF;
} else {
qp = kzalloc(sizeof (struct mlx4_ib_qp), GFP_KERNEL);
if (!qp)
return -ENOMEM;
+ qp->pri.vid = 0xFFFF;
+ qp->alt.vid = 0xFFFF;
}
} else
qp = *caller_qp;
@@ -940,11 +944,32 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
{
struct mlx4_ib_cq *send_cq, *recv_cq;
- if (qp->state != IB_QPS_RESET)
+ if (qp->state != IB_QPS_RESET) {
if (mlx4_qp_modify(dev->dev, NULL, to_mlx4_state(qp->state),
MLX4_QP_STATE_RST, NULL, 0, 0, &qp->mqp))
pr_warn("modify QP %06x to RESET failed.\n",
qp->mqp.qpn);
+ if (qp->pri.smac) {
+ mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac);
+ qp->pri.smac = 0;
+ }
+ if (qp->alt.smac) {
+ mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac);
+ qp->alt.smac = 0;
+ }
+ if (qp->pri.vid < 0x1000) {
+ mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port, qp->pri.vid);
+ qp->pri.vid = 0xFFFF;
+ qp->pri.candidate_vid = 0xFFFF;
+ qp->pri.update_vid = 0;
+ }
+ if (qp->alt.vid < 0x1000) {
+ mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port, qp->alt.vid);
+ qp->alt.vid = 0xFFFF;
+ qp->alt.candidate_vid = 0xFFFF;
+ qp->alt.update_vid = 0;
+ }
+ }
get_cqs(qp, &send_cq, &recv_cq);
@@ -1057,6 +1082,8 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
qp = kzalloc(sizeof *qp, GFP_KERNEL);
if (!qp)
return ERR_PTR(-ENOMEM);
+ qp->pri.vid = 0xFFFF;
+ qp->alt.vid = 0xFFFF;
/* fall through */
case IB_QPT_UD:
{
@@ -1188,12 +1215,13 @@ static void mlx4_set_sched(struct mlx4_qp_path *path, u8 port)
static int _mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah,
u64 smac, u16 vlan_tag, struct mlx4_qp_path *path,
- u8 port)
+ struct mlx4_roce_smac_vlan_info *smac_info, u8 port)
{
int is_eth = rdma_port_get_link_layer(&dev->ib_dev, port) ==
IB_LINK_LAYER_ETHERNET;
int vidx;
int smac_index;
+ int err;
path->grh_mylmc = ah->src_path_bits & 0x7f;
@@ -1223,61 +1251,103 @@ static int _mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah,
}
if (is_eth) {
- path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE |
- ((port - 1) << 6) | ((ah->sl & 7) << 3);
-
if (!(ah->ah_flags & IB_AH_GRH))
return -1;
- memcpy(path->dmac, ah->dmac, ETH_ALEN);
- path->ackto = MLX4_IB_LINK_TYPE_ETH;
- /* find the index into MAC table for IBoE */
- if (!is_zero_ether_addr((const u8 *)&smac)) {
- if (mlx4_find_cached_mac(dev->dev, port, smac,
- &smac_index))
- return -ENOENT;
- } else {
- smac_index = 0;
- }
-
- path->grh_mylmc &= 0x80 | smac_index;
+ path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE |
+ ((port - 1) << 6) | ((ah->sl & 7) << 3);
path->feup |= MLX4_FEUP_FORCE_ETH_UP;
if (vlan_tag < 0x1000) {
- if (mlx4_find_cached_vlan(dev->dev, port, vlan_tag, &vidx))
- return -ENOENT;
-
- path->vlan_index = vidx;
- path->fl = 1 << 6;
+ if (smac_info->vid < 0x1000) {
+ /* both valid vlan ids */
+ if (smac_info->vid != vlan_tag) {
+ /* different VIDs. unreg old and reg new */
+ err = mlx4_register_vlan(dev->dev, port, vlan_tag, &vidx);
+ if (err)
+ return err;
+ smac_info->candidate_vid = vlan_tag;
+ smac_info->candidate_vlan_index = vidx;
+ smac_info->candidate_vlan_port = port;
+ smac_info->update_vid = 1;
+ path->vlan_index = vidx;
+ } else {
+ path->vlan_index = smac_info->vlan_index;
+ }
+ } else {
+ /* no current vlan tag in qp */
+ err = mlx4_register_vlan(dev->dev, port, vlan_tag, &vidx);
+ if (err)
+ return err;
+ smac_info->candidate_vid = vlan_tag;
+ smac_info->candidate_vlan_index = vidx;
+ smac_info->candidate_vlan_port = port;
+ smac_info->update_vid = 1;
+ path->vlan_index = vidx;
+ }
path->feup |= MLX4_FVL_FORCE_ETH_VLAN;
+ path->fl = 1 << 6;
+ } else {
+ /* have current vlan tag. unregister it at modify-qp success */
+ if (smac_info->vid < 0x1000) {
+ smac_info->candidate_vid = 0xFFFF;
+ smac_info->update_vid = 1;
+ }
}
- } else
+
+ /* get smac_index for RoCE use.
+ * If no smac was yet assigned, register one.
+ * If one was already assigned, but the new mac differs,
+ * unregister the old one and register the new one.
+ */
+ if (!smac_info->smac || smac_info->smac != smac) {
+ /* register candidate now, unreg if needed, after success */
+ smac_index = mlx4_register_mac(dev->dev, port, smac);
+ if (smac_index >= 0) {
+ smac_info->candidate_smac_index = smac_index;
+ smac_info->candidate_smac = smac;
+ smac_info->candidate_smac_port = port;
+ } else {
+ return -EINVAL;
+ }
+ } else {
+ smac_index = smac_info->smac_index;
+ }
+
+ memcpy(path->dmac, ah->dmac, 6);
+ path->ackto = MLX4_IB_LINK_TYPE_ETH;
+ /* put MAC table smac index for IBoE */
+ path->grh_mylmc = (u8) (smac_index) | 0x80;
+ } else {
path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE |
((port - 1) << 6) | ((ah->sl & 0xf) << 2);
+ }
return 0;
}
static int mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_qp_attr *qp,
enum ib_qp_attr_mask qp_attr_mask,
+ struct mlx4_ib_qp *mqp,
struct mlx4_qp_path *path, u8 port)
{
return _mlx4_set_path(dev, &qp->ah_attr,
mlx4_mac_to_u64((u8 *)qp->smac),
(qp_attr_mask & IB_QP_VID) ? qp->vlan_id : 0xffff,
- path, port);
+ path, &mqp->pri, port);
}
static int mlx4_set_alt_path(struct mlx4_ib_dev *dev,
const struct ib_qp_attr *qp,
enum ib_qp_attr_mask qp_attr_mask,
+ struct mlx4_ib_qp *mqp,
struct mlx4_qp_path *path, u8 port)
{
return _mlx4_set_path(dev, &qp->alt_ah_attr,
mlx4_mac_to_u64((u8 *)qp->alt_smac),
(qp_attr_mask & IB_QP_ALT_VID) ?
qp->alt_vlan_id : 0xffff,
- path, port);
+ path, &mqp->alt, port);
}
static void update_mcg_macs(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp)
@@ -1292,6 +1362,37 @@ static void update_mcg_macs(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp)
}
}
+static int handle_eth_ud_smac_index(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, u8 *smac,
+ struct mlx4_qp_context *context)
+{
+ struct net_device *ndev;
+ u64 u64_mac;
+ int smac_index;
+
+
+ ndev = dev->iboe.netdevs[qp->port - 1];
+ if (ndev) {
+ smac = ndev->dev_addr;
+ u64_mac = mlx4_mac_to_u64(smac);
+ } else {
+ u64_mac = dev->dev->caps.def_mac[qp->port];
+ }
+
+ context->pri_path.sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE | ((qp->port - 1) << 6);
+ if (!qp->pri.smac) {
+ smac_index = mlx4_register_mac(dev->dev, qp->port, u64_mac);
+ if (smac_index >= 0) {
+ qp->pri.candidate_smac_index = smac_index;
+ qp->pri.candidate_smac = u64_mac;
+ qp->pri.candidate_smac_port = qp->port;
+ context->pri_path.grh_mylmc = 0x80 | (u8) smac_index;
+ } else {
+ return -ENOENT;
+ }
+ }
+ return 0;
+}
+
static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
const struct ib_qp_attr *attr, int attr_mask,
enum ib_qp_state cur_state, enum ib_qp_state new_state)
@@ -1403,7 +1504,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
}
if (attr_mask & IB_QP_AV) {
- if (mlx4_set_path(dev, attr, attr_mask, &context->pri_path,
+ if (mlx4_set_path(dev, attr, attr_mask, qp, &context->pri_path,
attr_mask & IB_QP_PORT ?
attr->port_num : qp->port))
goto out;
@@ -1426,7 +1527,8 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
dev->dev->caps.pkey_table_len[attr->alt_port_num])
goto out;
- if (mlx4_set_alt_path(dev, attr, attr_mask, &context->alt_path,
+ if (mlx4_set_alt_path(dev, attr, attr_mask, qp,
+ &context->alt_path,
attr->alt_port_num))
goto out;
@@ -1532,6 +1634,20 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
context->pri_path.fl = 0x80;
context->pri_path.sched_queue |= MLX4_IB_DEFAULT_SCHED_QUEUE;
}
+ if (rdma_port_get_link_layer(&dev->ib_dev, qp->port) ==
+ IB_LINK_LAYER_ETHERNET) {
+ if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_TUN_GSI ||
+ qp->mlx4_ib_qp_type == MLX4_IB_QPT_GSI)
+ context->pri_path.feup = 1 << 7; /* don't fsm */
+ /* handle smac_index */
+ if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_UD ||
+ qp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI ||
+ qp->mlx4_ib_qp_type == MLX4_IB_QPT_TUN_GSI) {
+ err = handle_eth_ud_smac_index(dev, qp, (u8 *)attr->smac, context);
+ if (err)
+ return -EINVAL;
+ }
+ }
}
if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET)
@@ -1619,28 +1735,113 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
* If we moved a kernel QP to RESET, clean up all old CQ
* entries and reinitialize the QP.
*/
- if (new_state == IB_QPS_RESET && !ibqp->uobject) {
- mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn,
- ibqp->srq ? to_msrq(ibqp->srq): NULL);
- if (send_cq != recv_cq)
- mlx4_ib_cq_clean(send_cq, qp->mqp.qpn, NULL);
+ if (new_state == IB_QPS_RESET) {
+ if (!ibqp->uobject) {
+ mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn,
+ ibqp->srq ? to_msrq(ibqp->srq) : NULL);
+ if (send_cq != recv_cq)
+ mlx4_ib_cq_clean(send_cq, qp->mqp.qpn, NULL);
+
+ qp->rq.head = 0;
+ qp->rq.tail = 0;
+ qp->sq.head = 0;
+ qp->sq.tail = 0;
+ qp->sq_next_wqe = 0;
+ if (qp->rq.wqe_cnt)
+ *qp->db.db = 0;
- qp->rq.head = 0;
- qp->rq.tail = 0;
- qp->sq.head = 0;
- qp->sq.tail = 0;
- qp->sq_next_wqe = 0;
- if (qp->rq.wqe_cnt)
- *qp->db.db = 0;
+ if (qp->flags & MLX4_IB_QP_NETIF)
+ mlx4_ib_steer_qp_reg(dev, qp, 0);
+ }
+ if (qp->pri.smac) {
+ mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac);
+ qp->pri.smac = 0;
+ }
+ if (qp->alt.smac) {
+ mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac);
+ qp->alt.smac = 0;
+ }
+ if (qp->pri.vid < 0x1000) {
+ mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port, qp->pri.vid);
+ qp->pri.vid = 0xFFFF;
+ qp->pri.candidate_vid = 0xFFFF;
+ qp->pri.update_vid = 0;
+ }
- if (qp->flags & MLX4_IB_QP_NETIF)
- mlx4_ib_steer_qp_reg(dev, qp, 0);
+ if (qp->alt.vid < 0x1000) {
+ mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port, qp->alt.vid);
+ qp->alt.vid = 0xFFFF;
+ qp->alt.candidate_vid = 0xFFFF;
+ qp->alt.update_vid = 0;
+ }
}
-
out:
if (err && steer_qp)
mlx4_ib_steer_qp_reg(dev, qp, 0);
kfree(context);
+ if (qp->pri.candidate_smac) {
+ if (err) {
+ mlx4_unregister_mac(dev->dev, qp->pri.candidate_smac_port, qp->pri.candidate_smac);
+ } else {
+ if (qp->pri.smac)
+ mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac);
+ qp->pri.smac = qp->pri.candidate_smac;
+ qp->pri.smac_index = qp->pri.candidate_smac_index;
+ qp->pri.smac_port = qp->pri.candidate_smac_port;
+ }
+ qp->pri.candidate_smac = 0;
+ qp->pri.candidate_smac_index = 0;
+ qp->pri.candidate_smac_port = 0;
+ }
+ if (qp->alt.candidate_smac) {
+ if (err) {
+ mlx4_unregister_mac(dev->dev, qp->alt.candidate_smac_port, qp->alt.candidate_smac);
+ } else {
+ if (qp->alt.smac)
+ mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac);
+ qp->alt.smac = qp->alt.candidate_smac;
+ qp->alt.smac_index = qp->alt.candidate_smac_index;
+ qp->alt.smac_port = qp->alt.candidate_smac_port;
+ }
+ qp->alt.candidate_smac = 0;
+ qp->alt.candidate_smac_index = 0;
+ qp->alt.candidate_smac_port = 0;
+ }
+
+ if (qp->pri.update_vid) {
+ if (err) {
+ if (qp->pri.candidate_vid < 0x1000)
+ mlx4_unregister_vlan(dev->dev, qp->pri.candidate_vlan_port,
+ qp->pri.candidate_vid);
+ } else {
+ if (qp->pri.vid < 0x1000)
+ mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port,
+ qp->pri.vid);
+ qp->pri.vid = qp->pri.candidate_vid;
+ qp->pri.vlan_port = qp->pri.candidate_vlan_port;
+ qp->pri.vlan_index = qp->pri.candidate_vlan_index;
+ }
+ qp->pri.candidate_vid = 0xFFFF;
+ qp->pri.update_vid = 0;
+ }
+
+ if (qp->alt.update_vid) {
+ if (err) {
+ if (qp->alt.candidate_vid < 0x1000)
+ mlx4_unregister_vlan(dev->dev, qp->alt.candidate_vlan_port,
+ qp->alt.candidate_vid);
+ } else {
+ if (qp->alt.vid < 0x1000)
+ mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port,
+ qp->alt.vid);
+ qp->alt.vid = qp->alt.candidate_vid;
+ qp->alt.vlan_port = qp->alt.candidate_vlan_port;
+ qp->alt.vlan_index = qp->alt.candidate_vlan_index;
+ }
+ qp->alt.candidate_vid = 0xFFFF;
+ qp->alt.update_vid = 0;
+ }
+
return err;
}
@@ -1842,9 +2043,9 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
{
struct ib_device *ib_dev = sqp->qp.ibqp.device;
struct mlx4_wqe_mlx_seg *mlx = wqe;
+ struct mlx4_wqe_ctrl_seg *ctrl = wqe;
struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx;
struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah);
- struct net_device *ndev;
union ib_gid sgid;
u16 pkey;
int send_size;
@@ -1868,12 +2069,11 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
/* When multi-function is enabled, the ib_core gid
* indexes don't necessarily match the hw ones, so
* we must use our own cache */
- sgid.global.subnet_prefix =
- to_mdev(ib_dev)->sriov.demux[sqp->qp.port - 1].
- subnet_prefix;
- sgid.global.interface_id =
- to_mdev(ib_dev)->sriov.demux[sqp->qp.port - 1].
- guid_cache[ah->av.ib.gid_index];
+ err = mlx4_get_roce_gid_from_slave(to_mdev(ib_dev)->dev,
+ be32_to_cpu(ah->av.ib.port_pd) >> 24,
+ ah->av.ib.gid_index, &sgid.raw[0]);
+ if (err)
+ return err;
} else {
err = ib_get_cached_gid(ib_dev,
be32_to_cpu(ah->av.ib.port_pd) >> 24,
@@ -1882,7 +2082,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
return err;
}
- if (ah->av.eth.vlan != 0xffff) {
+ if (ah->av.eth.vlan != cpu_to_be16(0xffff)) {
vlan = be16_to_cpu(ah->av.eth.vlan) & 0x0fff;
is_vlan = 1;
}
@@ -1902,6 +2102,9 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
sqp->ud_header.grh.flow_label =
ah->av.ib.sl_tclass_flowlabel & cpu_to_be32(0xfffff);
sqp->ud_header.grh.hop_limit = ah->av.ib.hop_limit;
+ if (is_eth)
+ memcpy(sqp->ud_header.grh.source_gid.raw, sgid.raw, 16);
+ else {
if (mlx4_is_mfunc(to_mdev(ib_dev)->dev)) {
/* When multi-function is enabled, the ib_core gid
* indexes don't necessarily match the hw ones, so
@@ -1917,6 +2120,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
be32_to_cpu(ah->av.ib.port_pd) >> 24,
ah->av.ib.gid_index,
&sqp->ud_header.grh.source_gid);
+ }
memcpy(sqp->ud_header.grh.destination_gid.raw,
ah->av.ib.dgid, 16);
}
@@ -1949,16 +2153,23 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
if (is_eth) {
u8 *smac;
+ struct in6_addr in6;
+
u16 pcp = (be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 29) << 13;
mlx->sched_prio = cpu_to_be16(pcp);
memcpy(sqp->ud_header.eth.dmac_h, ah->av.eth.mac, 6);
/* FIXME: cache smac value? */
- ndev = to_mdev(sqp->qp.ibqp.device)->iboe.netdevs[sqp->qp.port - 1];
- if (!ndev)
- return -ENODEV;
- smac = ndev->dev_addr;
+ memcpy(&ctrl->srcrb_flags16[0], ah->av.eth.mac, 2);
+ memcpy(&ctrl->imm, ah->av.eth.mac + 2, 4);
+ memcpy(&in6, sgid.raw, sizeof(in6));
+
+ if (!mlx4_is_mfunc(to_mdev(ib_dev)->dev))
+ smac = to_mdev(sqp->qp.ibqp.device)->
+ iboe.netdevs[sqp->qp.port - 1]->dev_addr;
+ else /* use the src mac of the tunnel */
+ smac = ah->av.eth.s_mac;
memcpy(sqp->ud_header.eth.smac_h, smac, 6);
if (!memcmp(sqp->ud_header.eth.smac_h, sqp->ud_header.eth.dmac_h, 6))
mlx->flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK);
@@ -2190,6 +2401,8 @@ static void build_tunnel_header(struct ib_send_wr *wr, void *wqe, unsigned *mlx_
hdr.remote_qpn = cpu_to_be32(wr->wr.ud.remote_qpn);
hdr.pkey_index = cpu_to_be16(wr->wr.ud.pkey_index);
hdr.qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+ memcpy(hdr.mac, ah->av.eth.mac, 6);
+ hdr.vlan = ah->av.eth.vlan;
spc = MLX4_INLINE_ALIGN -
((unsigned long) (inl + 1) & (MLX4_INLINE_ALIGN - 1));
diff --git a/drivers/infiniband/hw/mlx4/sysfs.c b/drivers/infiniband/hw/mlx4/sysfs.c
index db2ea31df832..5a38e43eca65 100644
--- a/drivers/infiniband/hw/mlx4/sysfs.c
+++ b/drivers/infiniband/hw/mlx4/sysfs.c
@@ -627,6 +627,7 @@ static int register_one_pkey_tree(struct mlx4_ib_dev *dev, int slave)
int port;
struct kobject *p, *t;
struct mlx4_port *mport;
+ struct mlx4_active_ports actv_ports;
get_name(dev, name, slave, sizeof name);
@@ -649,7 +650,11 @@ static int register_one_pkey_tree(struct mlx4_ib_dev *dev, int slave)
goto err_ports;
}
+ actv_ports = mlx4_get_active_ports(dev->dev, slave);
+
for (port = 1; port <= dev->dev->caps.num_ports; ++port) {
+ if (!test_bit(port - 1, actv_ports.ports))
+ continue;
err = add_port(dev, port, slave);
if (err)
goto err_add;
diff --git a/drivers/infiniband/hw/mlx5/Kconfig b/drivers/infiniband/hw/mlx5/Kconfig
index 8e6aebfaf8a4..10df386c6344 100644
--- a/drivers/infiniband/hw/mlx5/Kconfig
+++ b/drivers/infiniband/hw/mlx5/Kconfig
@@ -1,6 +1,6 @@
config MLX5_INFINIBAND
tristate "Mellanox Connect-IB HCA support"
- depends on NETDEVICES && ETHERNET && PCI && X86
+ depends on NETDEVICES && ETHERNET && PCI
select NET_VENDOR_MELLANOX
select MLX5_CORE
---help---
diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c
index b1705ce6eb88..62bb6b49dc1d 100644
--- a/drivers/infiniband/hw/mlx5/cq.c
+++ b/drivers/infiniband/hw/mlx5/cq.c
@@ -366,6 +366,38 @@ static void free_cq_buf(struct mlx5_ib_dev *dev, struct mlx5_ib_cq_buf *buf)
mlx5_buf_free(&dev->mdev, &buf->buf);
}
+static void get_sig_err_item(struct mlx5_sig_err_cqe *cqe,
+ struct ib_sig_err *item)
+{
+ u16 syndrome = be16_to_cpu(cqe->syndrome);
+
+#define GUARD_ERR (1 << 13)
+#define APPTAG_ERR (1 << 12)
+#define REFTAG_ERR (1 << 11)
+
+ if (syndrome & GUARD_ERR) {
+ item->err_type = IB_SIG_BAD_GUARD;
+ item->expected = be32_to_cpu(cqe->expected_trans_sig) >> 16;
+ item->actual = be32_to_cpu(cqe->actual_trans_sig) >> 16;
+ } else
+ if (syndrome & REFTAG_ERR) {
+ item->err_type = IB_SIG_BAD_REFTAG;
+ item->expected = be32_to_cpu(cqe->expected_reftag);
+ item->actual = be32_to_cpu(cqe->actual_reftag);
+ } else
+ if (syndrome & APPTAG_ERR) {
+ item->err_type = IB_SIG_BAD_APPTAG;
+ item->expected = be32_to_cpu(cqe->expected_trans_sig) & 0xffff;
+ item->actual = be32_to_cpu(cqe->actual_trans_sig) & 0xffff;
+ } else {
+ pr_err("Got signature completion error with bad syndrome %04x\n",
+ syndrome);
+ }
+
+ item->sig_err_offset = be64_to_cpu(cqe->err_offset);
+ item->key = be32_to_cpu(cqe->mkey);
+}
+
static int mlx5_poll_one(struct mlx5_ib_cq *cq,
struct mlx5_ib_qp **cur_qp,
struct ib_wc *wc)
@@ -375,6 +407,9 @@ static int mlx5_poll_one(struct mlx5_ib_cq *cq,
struct mlx5_cqe64 *cqe64;
struct mlx5_core_qp *mqp;
struct mlx5_ib_wq *wq;
+ struct mlx5_sig_err_cqe *sig_err_cqe;
+ struct mlx5_core_mr *mmr;
+ struct mlx5_ib_mr *mr;
uint8_t opcode;
uint32_t qpn;
u16 wqe_ctr;
@@ -475,6 +510,33 @@ repoll:
}
}
break;
+ case MLX5_CQE_SIG_ERR:
+ sig_err_cqe = (struct mlx5_sig_err_cqe *)cqe64;
+
+ read_lock(&dev->mdev.priv.mr_table.lock);
+ mmr = __mlx5_mr_lookup(&dev->mdev,
+ mlx5_base_mkey(be32_to_cpu(sig_err_cqe->mkey)));
+ if (unlikely(!mmr)) {
+ read_unlock(&dev->mdev.priv.mr_table.lock);
+ mlx5_ib_warn(dev, "CQE@CQ %06x for unknown MR %6x\n",
+ cq->mcq.cqn, be32_to_cpu(sig_err_cqe->mkey));
+ return -EINVAL;
+ }
+
+ mr = to_mibmr(mmr);
+ get_sig_err_item(sig_err_cqe, &mr->sig->err_item);
+ mr->sig->sig_err_exists = true;
+ mr->sig->sigerr_count++;
+
+ mlx5_ib_warn(dev, "CQN: 0x%x Got SIGERR on key: 0x%x err_type %x err_offset %llx expected %x actual %x\n",
+ cq->mcq.cqn, mr->sig->err_item.key,
+ mr->sig->err_item.err_type,
+ mr->sig->err_item.sig_err_offset,
+ mr->sig->err_item.expected,
+ mr->sig->err_item.actual);
+
+ read_unlock(&dev->mdev.priv.mr_table.lock);
+ goto repoll;
}
return 0;
diff --git a/drivers/infiniband/hw/mlx5/doorbell.c b/drivers/infiniband/hw/mlx5/doorbell.c
index 256a23344f28..ece028fc47d6 100644
--- a/drivers/infiniband/hw/mlx5/doorbell.c
+++ b/drivers/infiniband/hw/mlx5/doorbell.c
@@ -47,7 +47,6 @@ int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context, unsigned long virt,
struct mlx5_db *db)
{
struct mlx5_ib_user_db_page *page;
- struct ib_umem_chunk *chunk;
int err = 0;
mutex_lock(&context->db_page_mutex);
@@ -75,8 +74,7 @@ int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context, unsigned long virt,
list_add(&page->list, &context->db_page_list);
found:
- chunk = list_entry(page->umem->chunk_list.next, struct ib_umem_chunk, list);
- db->dma = sg_dma_address(chunk->page_list) + (virt & ~PAGE_MASK);
+ db->dma = sg_dma_address(page->umem->sg_head.sgl) + (virt & ~PAGE_MASK);
db->u.user_page = page;
++page->refcnt;
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index 9660d093f8cf..fa6dc870adae 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -46,8 +46,8 @@
#include "mlx5_ib.h"
#define DRIVER_NAME "mlx5_ib"
-#define DRIVER_VERSION "1.0"
-#define DRIVER_RELDATE "June 2013"
+#define DRIVER_VERSION "2.2-1"
+#define DRIVER_RELDATE "Feb 2014"
MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
MODULE_DESCRIPTION("Mellanox Connect-IB HCA IB driver");
@@ -261,8 +261,7 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
props->device_cap_flags = IB_DEVICE_CHANGE_PHY_PORT |
IB_DEVICE_PORT_ACTIVE_EVENT |
IB_DEVICE_SYS_IMAGE_GUID |
- IB_DEVICE_RC_RNR_NAK_GEN |
- IB_DEVICE_BLOCK_MULTICAST_LOOPBACK;
+ IB_DEVICE_RC_RNR_NAK_GEN;
flags = dev->mdev.caps.flags;
if (flags & MLX5_DEV_CAP_FLAG_BAD_PKEY_CNTR)
props->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR;
@@ -274,6 +273,15 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
if (flags & MLX5_DEV_CAP_FLAG_XRC)
props->device_cap_flags |= IB_DEVICE_XRC;
props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS;
+ if (flags & MLX5_DEV_CAP_FLAG_SIG_HAND_OVER) {
+ props->device_cap_flags |= IB_DEVICE_SIGNATURE_HANDOVER;
+ /* At this stage no support for signature handover */
+ props->sig_prot_cap = IB_PROT_T10DIF_TYPE_1 |
+ IB_PROT_T10DIF_TYPE_2 |
+ IB_PROT_T10DIF_TYPE_3;
+ props->sig_guard_cap = IB_GUARD_T10DIF_CRC |
+ IB_GUARD_T10DIF_CSUM;
+ }
props->vendor_id = be32_to_cpup((__be32 *)(out_mad->data + 36)) &
0xffffff;
@@ -536,24 +544,38 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
struct ib_udata *udata)
{
struct mlx5_ib_dev *dev = to_mdev(ibdev);
- struct mlx5_ib_alloc_ucontext_req req;
+ struct mlx5_ib_alloc_ucontext_req_v2 req;
struct mlx5_ib_alloc_ucontext_resp resp;
struct mlx5_ib_ucontext *context;
struct mlx5_uuar_info *uuari;
struct mlx5_uar *uars;
int gross_uuars;
int num_uars;
+ int ver;
int uuarn;
int err;
int i;
+ int reqlen;
if (!dev->ib_active)
return ERR_PTR(-EAGAIN);
- err = ib_copy_from_udata(&req, udata, sizeof(req));
+ memset(&req, 0, sizeof(req));
+ reqlen = udata->inlen - sizeof(struct ib_uverbs_cmd_hdr);
+ if (reqlen == sizeof(struct mlx5_ib_alloc_ucontext_req))
+ ver = 0;
+ else if (reqlen == sizeof(struct mlx5_ib_alloc_ucontext_req_v2))
+ ver = 2;
+ else
+ return ERR_PTR(-EINVAL);
+
+ err = ib_copy_from_udata(&req, udata, reqlen);
if (err)
return ERR_PTR(err);
+ if (req.flags || req.reserved)
+ return ERR_PTR(-EINVAL);
+
if (req.total_num_uuars > MLX5_MAX_UUARS)
return ERR_PTR(-ENOMEM);
@@ -626,6 +648,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
if (err)
goto out_uars;
+ uuari->ver = ver;
uuari->num_low_latency_uuars = req.num_low_latency_uuars;
uuari->uars = uars;
uuari->num_uars = num_uars;
@@ -1409,12 +1432,15 @@ static int init_one(struct pci_dev *pdev,
dev->ib_dev.get_dma_mr = mlx5_ib_get_dma_mr;
dev->ib_dev.reg_user_mr = mlx5_ib_reg_user_mr;
dev->ib_dev.dereg_mr = mlx5_ib_dereg_mr;
+ dev->ib_dev.destroy_mr = mlx5_ib_destroy_mr;
dev->ib_dev.attach_mcast = mlx5_ib_mcg_attach;
dev->ib_dev.detach_mcast = mlx5_ib_mcg_detach;
dev->ib_dev.process_mad = mlx5_ib_process_mad;
+ dev->ib_dev.create_mr = mlx5_ib_create_mr;
dev->ib_dev.alloc_fast_reg_mr = mlx5_ib_alloc_fast_reg_mr;
dev->ib_dev.alloc_fast_reg_page_list = mlx5_ib_alloc_fast_reg_page_list;
dev->ib_dev.free_fast_reg_page_list = mlx5_ib_free_fast_reg_page_list;
+ dev->ib_dev.check_mr_status = mlx5_ib_check_mr_status;
if (mdev->caps.flags & MLX5_DEV_CAP_FLAG_XRC) {
dev->ib_dev.alloc_xrcd = mlx5_ib_alloc_xrcd;
diff --git a/drivers/infiniband/hw/mlx5/mem.c b/drivers/infiniband/hw/mlx5/mem.c
index 3a5322870b96..8499aec94db6 100644
--- a/drivers/infiniband/hw/mlx5/mem.c
+++ b/drivers/infiniband/hw/mlx5/mem.c
@@ -44,16 +44,17 @@
void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift,
int *ncont, int *order)
{
- struct ib_umem_chunk *chunk;
unsigned long tmp;
unsigned long m;
- int i, j, k;
+ int i, k;
u64 base = 0;
int p = 0;
int skip;
int mask;
u64 len;
u64 pfn;
+ struct scatterlist *sg;
+ int entry;
addr = addr >> PAGE_SHIFT;
tmp = (unsigned long)addr;
@@ -61,32 +62,31 @@ void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift,
skip = 1 << m;
mask = skip - 1;
i = 0;
- list_for_each_entry(chunk, &umem->chunk_list, list)
- for (j = 0; j < chunk->nmap; j++) {
- len = sg_dma_len(&chunk->page_list[j]) >> PAGE_SHIFT;
- pfn = sg_dma_address(&chunk->page_list[j]) >> PAGE_SHIFT;
- for (k = 0; k < len; k++) {
- if (!(i & mask)) {
- tmp = (unsigned long)pfn;
- m = min(m, find_first_bit(&tmp, sizeof(tmp)));
+ for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) {
+ len = sg_dma_len(sg) >> PAGE_SHIFT;
+ pfn = sg_dma_address(sg) >> PAGE_SHIFT;
+ for (k = 0; k < len; k++) {
+ if (!(i & mask)) {
+ tmp = (unsigned long)pfn;
+ m = min(m, find_first_bit(&tmp, sizeof(tmp)));
+ skip = 1 << m;
+ mask = skip - 1;
+ base = pfn;
+ p = 0;
+ } else {
+ if (base + p != pfn) {
+ tmp = (unsigned long)p;
+ m = find_first_bit(&tmp, sizeof(tmp));
skip = 1 << m;
mask = skip - 1;
base = pfn;
p = 0;
- } else {
- if (base + p != pfn) {
- tmp = (unsigned long)p;
- m = find_first_bit(&tmp, sizeof(tmp));
- skip = 1 << m;
- mask = skip - 1;
- base = pfn;
- p = 0;
- }
}
- p++;
- i++;
}
+ p++;
+ i++;
}
+ }
if (i) {
m = min_t(unsigned long, ilog2(roundup_pow_of_two(i)), m);
@@ -112,32 +112,32 @@ void mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem,
{
int shift = page_shift - PAGE_SHIFT;
int mask = (1 << shift) - 1;
- struct ib_umem_chunk *chunk;
- int i, j, k;
+ int i, k;
u64 cur = 0;
u64 base;
int len;
+ struct scatterlist *sg;
+ int entry;
i = 0;
- list_for_each_entry(chunk, &umem->chunk_list, list)
- for (j = 0; j < chunk->nmap; j++) {
- len = sg_dma_len(&chunk->page_list[j]) >> PAGE_SHIFT;
- base = sg_dma_address(&chunk->page_list[j]);
- for (k = 0; k < len; k++) {
- if (!(i & mask)) {
- cur = base + (k << PAGE_SHIFT);
- if (umr)
- cur |= 3;
+ for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) {
+ len = sg_dma_len(sg) >> PAGE_SHIFT;
+ base = sg_dma_address(sg);
+ for (k = 0; k < len; k++) {
+ if (!(i & mask)) {
+ cur = base + (k << PAGE_SHIFT);
+ if (umr)
+ cur |= 3;
- pas[i >> shift] = cpu_to_be64(cur);
- mlx5_ib_dbg(dev, "pas[%d] 0x%llx\n",
- i >> shift, be64_to_cpu(pas[i >> shift]));
- } else
- mlx5_ib_dbg(dev, "=====> 0x%llx\n",
- base + (k << PAGE_SHIFT));
- i++;
- }
+ pas[i >> shift] = cpu_to_be64(cur);
+ mlx5_ib_dbg(dev, "pas[%d] 0x%llx\n",
+ i >> shift, be64_to_cpu(pas[i >> shift]));
+ } else
+ mlx5_ib_dbg(dev, "=====> 0x%llx\n",
+ base + (k << PAGE_SHIFT));
+ i++;
}
+ }
}
int mlx5_ib_get_buf_offset(u64 addr, int page_shift, u32 *offset)
diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h
index 389e31965773..50541586e0a6 100644
--- a/drivers/infiniband/hw/mlx5/mlx5_ib.h
+++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h
@@ -189,6 +189,9 @@ struct mlx5_ib_qp {
int create_type;
u32 pa_lkey;
+
+ /* Store signature errors */
+ bool signature_en;
};
struct mlx5_ib_cq_buf {
@@ -265,6 +268,7 @@ struct mlx5_ib_mr {
enum ib_wc_status status;
struct mlx5_ib_dev *dev;
struct mlx5_create_mkey_mbox_out out;
+ struct mlx5_core_sig_ctx *sig;
};
struct mlx5_ib_fast_reg_page_list {
@@ -396,6 +400,11 @@ static inline struct mlx5_ib_qp *to_mibqp(struct mlx5_core_qp *mqp)
return container_of(mqp, struct mlx5_ib_qp, mqp);
}
+static inline struct mlx5_ib_mr *to_mibmr(struct mlx5_core_mr *mmr)
+{
+ return container_of(mmr, struct mlx5_ib_mr, mmr);
+}
+
static inline struct mlx5_ib_pd *to_mpd(struct ib_pd *ibpd)
{
return container_of(ibpd, struct mlx5_ib_pd, ibpd);
@@ -495,6 +504,9 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
u64 virt_addr, int access_flags,
struct ib_udata *udata);
int mlx5_ib_dereg_mr(struct ib_mr *ibmr);
+int mlx5_ib_destroy_mr(struct ib_mr *ibmr);
+struct ib_mr *mlx5_ib_create_mr(struct ib_pd *pd,
+ struct ib_mr_init_attr *mr_init_attr);
struct ib_mr *mlx5_ib_alloc_fast_reg_mr(struct ib_pd *pd,
int max_page_list_len);
struct ib_fast_reg_page_list *mlx5_ib_alloc_fast_reg_page_list(struct ib_device *ibdev,
@@ -530,6 +542,8 @@ int mlx5_mr_cache_init(struct mlx5_ib_dev *dev);
int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev);
int mlx5_mr_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift);
void mlx5_umr_cq_handler(struct ib_cq *cq, void *cq_context);
+int mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask,
+ struct ib_mr_status *mr_status);
static inline void init_query_mad(struct ib_smp *mad)
{
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
index 7c95ca1f0c25..81392b26d078 100644
--- a/drivers/infiniband/hw/mlx5/mr.c
+++ b/drivers/infiniband/hw/mlx5/mr.c
@@ -992,6 +992,122 @@ int mlx5_ib_dereg_mr(struct ib_mr *ibmr)
return 0;
}
+struct ib_mr *mlx5_ib_create_mr(struct ib_pd *pd,
+ struct ib_mr_init_attr *mr_init_attr)
+{
+ struct mlx5_ib_dev *dev = to_mdev(pd->device);
+ struct mlx5_create_mkey_mbox_in *in;
+ struct mlx5_ib_mr *mr;
+ int access_mode, err;
+ int ndescs = roundup(mr_init_attr->max_reg_descriptors, 4);
+
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+ if (!mr)
+ return ERR_PTR(-ENOMEM);
+
+ in = kzalloc(sizeof(*in), GFP_KERNEL);
+ if (!in) {
+ err = -ENOMEM;
+ goto err_free;
+ }
+
+ in->seg.status = 1 << 6; /* free */
+ in->seg.xlt_oct_size = cpu_to_be32(ndescs);
+ in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
+ in->seg.flags_pd = cpu_to_be32(to_mpd(pd)->pdn);
+ access_mode = MLX5_ACCESS_MODE_MTT;
+
+ if (mr_init_attr->flags & IB_MR_SIGNATURE_EN) {
+ u32 psv_index[2];
+
+ in->seg.flags_pd = cpu_to_be32(be32_to_cpu(in->seg.flags_pd) |
+ MLX5_MKEY_BSF_EN);
+ in->seg.bsfs_octo_size = cpu_to_be32(MLX5_MKEY_BSF_OCTO_SIZE);
+ mr->sig = kzalloc(sizeof(*mr->sig), GFP_KERNEL);
+ if (!mr->sig) {
+ err = -ENOMEM;
+ goto err_free_in;
+ }
+
+ /* create mem & wire PSVs */
+ err = mlx5_core_create_psv(&dev->mdev, to_mpd(pd)->pdn,
+ 2, psv_index);
+ if (err)
+ goto err_free_sig;
+
+ access_mode = MLX5_ACCESS_MODE_KLM;
+ mr->sig->psv_memory.psv_idx = psv_index[0];
+ mr->sig->psv_wire.psv_idx = psv_index[1];
+
+ mr->sig->sig_status_checked = true;
+ mr->sig->sig_err_exists = false;
+ /* Next UMR, Arm SIGERR */
+ ++mr->sig->sigerr_count;
+ }
+
+ in->seg.flags = MLX5_PERM_UMR_EN | access_mode;
+ err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in, sizeof(*in),
+ NULL, NULL, NULL);
+ if (err)
+ goto err_destroy_psv;
+
+ mr->ibmr.lkey = mr->mmr.key;
+ mr->ibmr.rkey = mr->mmr.key;
+ mr->umem = NULL;
+ kfree(in);
+
+ return &mr->ibmr;
+
+err_destroy_psv:
+ if (mr->sig) {
+ if (mlx5_core_destroy_psv(&dev->mdev,
+ mr->sig->psv_memory.psv_idx))
+ mlx5_ib_warn(dev, "failed to destroy mem psv %d\n",
+ mr->sig->psv_memory.psv_idx);
+ if (mlx5_core_destroy_psv(&dev->mdev,
+ mr->sig->psv_wire.psv_idx))
+ mlx5_ib_warn(dev, "failed to destroy wire psv %d\n",
+ mr->sig->psv_wire.psv_idx);
+ }
+err_free_sig:
+ kfree(mr->sig);
+err_free_in:
+ kfree(in);
+err_free:
+ kfree(mr);
+ return ERR_PTR(err);
+}
+
+int mlx5_ib_destroy_mr(struct ib_mr *ibmr)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibmr->device);
+ struct mlx5_ib_mr *mr = to_mmr(ibmr);
+ int err;
+
+ if (mr->sig) {
+ if (mlx5_core_destroy_psv(&dev->mdev,
+ mr->sig->psv_memory.psv_idx))
+ mlx5_ib_warn(dev, "failed to destroy mem psv %d\n",
+ mr->sig->psv_memory.psv_idx);
+ if (mlx5_core_destroy_psv(&dev->mdev,
+ mr->sig->psv_wire.psv_idx))
+ mlx5_ib_warn(dev, "failed to destroy wire psv %d\n",
+ mr->sig->psv_wire.psv_idx);
+ kfree(mr->sig);
+ }
+
+ err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr);
+ if (err) {
+ mlx5_ib_warn(dev, "failed to destroy mkey 0x%x (%d)\n",
+ mr->mmr.key, err);
+ return err;
+ }
+
+ kfree(mr);
+
+ return err;
+}
+
struct ib_mr *mlx5_ib_alloc_fast_reg_mr(struct ib_pd *pd,
int max_page_list_len)
{
@@ -1077,3 +1193,44 @@ void mlx5_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list)
kfree(mfrpl->ibfrpl.page_list);
kfree(mfrpl);
}
+
+int mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask,
+ struct ib_mr_status *mr_status)
+{
+ struct mlx5_ib_mr *mmr = to_mmr(ibmr);
+ int ret = 0;
+
+ if (check_mask & ~IB_MR_CHECK_SIG_STATUS) {
+ pr_err("Invalid status check mask\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mr_status->fail_status = 0;
+ if (check_mask & IB_MR_CHECK_SIG_STATUS) {
+ if (!mmr->sig) {
+ ret = -EINVAL;
+ pr_err("signature status check requested on a non-signature enabled MR\n");
+ goto done;
+ }
+
+ mmr->sig->sig_status_checked = true;
+ if (!mmr->sig->sig_err_exists)
+ goto done;
+
+ if (ibmr->lkey == mmr->sig->err_item.key)
+ memcpy(&mr_status->sig_err, &mmr->sig->err_item,
+ sizeof(mr_status->sig_err));
+ else {
+ mr_status->sig_err.err_type = IB_SIG_BAD_GUARD;
+ mr_status->sig_err.sig_err_offset = 0;
+ mr_status->sig_err.key = mmr->sig->err_item.key;
+ }
+
+ mmr->sig->sig_err_exists = false;
+ mr_status->fail_status |= IB_MR_CHECK_SIG_STATUS;
+ }
+
+done:
+ return ret;
+}
diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c
index ae37fb9bf262..ae788d27b93f 100644
--- a/drivers/infiniband/hw/mlx5/qp.c
+++ b/drivers/infiniband/hw/mlx5/qp.c
@@ -216,7 +216,9 @@ static int sq_overhead(enum ib_qp_type qp_type)
case IB_QPT_UC:
size += sizeof(struct mlx5_wqe_ctrl_seg) +
- sizeof(struct mlx5_wqe_raddr_seg);
+ sizeof(struct mlx5_wqe_raddr_seg) +
+ sizeof(struct mlx5_wqe_umr_ctrl_seg) +
+ sizeof(struct mlx5_mkey_seg);
break;
case IB_QPT_UD:
@@ -254,8 +256,11 @@ static int calc_send_wqe(struct ib_qp_init_attr *attr)
}
size += attr->cap.max_send_sge * sizeof(struct mlx5_wqe_data_seg);
-
- return ALIGN(max_t(int, inl_size, size), MLX5_SEND_WQE_BB);
+ if (attr->create_flags & IB_QP_CREATE_SIGNATURE_EN &&
+ ALIGN(max_t(int, inl_size, size), MLX5_SEND_WQE_BB) < MLX5_SIG_WQE_SIZE)
+ return MLX5_SIG_WQE_SIZE;
+ else
+ return ALIGN(max_t(int, inl_size, size), MLX5_SEND_WQE_BB);
}
static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr,
@@ -282,6 +287,9 @@ static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr,
sizeof(struct mlx5_wqe_inline_seg);
attr->cap.max_inline_data = qp->max_inline_data;
+ if (attr->create_flags & IB_QP_CREATE_SIGNATURE_EN)
+ qp->signature_en = true;
+
wq_size = roundup_pow_of_two(attr->cap.max_send_wr * wqe_size);
qp->sq.wqe_cnt = wq_size / MLX5_SEND_WQE_BB;
if (qp->sq.wqe_cnt > dev->mdev.caps.max_wqes) {
@@ -428,11 +436,17 @@ static int alloc_uuar(struct mlx5_uuar_info *uuari,
break;
case MLX5_IB_LATENCY_CLASS_MEDIUM:
- uuarn = alloc_med_class_uuar(uuari);
+ if (uuari->ver < 2)
+ uuarn = -ENOMEM;
+ else
+ uuarn = alloc_med_class_uuar(uuari);
break;
case MLX5_IB_LATENCY_CLASS_HIGH:
- uuarn = alloc_high_class_uuar(uuari);
+ if (uuari->ver < 2)
+ uuarn = -ENOMEM;
+ else
+ uuarn = alloc_high_class_uuar(uuari);
break;
case MLX5_IB_LATENCY_CLASS_FAST_PATH:
@@ -657,8 +671,8 @@ static int create_kernel_qp(struct mlx5_ib_dev *dev,
int err;
uuari = &dev->mdev.priv.uuari;
- if (init_attr->create_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK)
- qp->flags |= MLX5_IB_QP_BLOCK_MULTICAST_LOOPBACK;
+ if (init_attr->create_flags & ~IB_QP_CREATE_SIGNATURE_EN)
+ return -EINVAL;
if (init_attr->qp_type == MLX5_IB_QPT_REG_UMR)
lc = MLX5_IB_LATENCY_CLASS_FAST_PATH;
@@ -1763,6 +1777,27 @@ static __be64 frwr_mkey_mask(void)
return cpu_to_be64(result);
}
+static __be64 sig_mkey_mask(void)
+{
+ u64 result;
+
+ result = MLX5_MKEY_MASK_LEN |
+ MLX5_MKEY_MASK_PAGE_SIZE |
+ MLX5_MKEY_MASK_START_ADDR |
+ MLX5_MKEY_MASK_EN_SIGERR |
+ MLX5_MKEY_MASK_EN_RINVAL |
+ MLX5_MKEY_MASK_KEY |
+ MLX5_MKEY_MASK_LR |
+ MLX5_MKEY_MASK_LW |
+ MLX5_MKEY_MASK_RR |
+ MLX5_MKEY_MASK_RW |
+ MLX5_MKEY_MASK_SMALL_FENCE |
+ MLX5_MKEY_MASK_FREE |
+ MLX5_MKEY_MASK_BSF_EN;
+
+ return cpu_to_be64(result);
+}
+
static void set_frwr_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr,
struct ib_send_wr *wr, int li)
{
@@ -1818,7 +1853,7 @@ static u8 get_umr_flags(int acc)
(acc & IB_ACCESS_REMOTE_WRITE ? MLX5_PERM_REMOTE_WRITE : 0) |
(acc & IB_ACCESS_REMOTE_READ ? MLX5_PERM_REMOTE_READ : 0) |
(acc & IB_ACCESS_LOCAL_WRITE ? MLX5_PERM_LOCAL_WRITE : 0) |
- MLX5_PERM_LOCAL_READ | MLX5_PERM_UMR_EN | MLX5_ACCESS_MODE_MTT;
+ MLX5_PERM_LOCAL_READ | MLX5_PERM_UMR_EN;
}
static void set_mkey_segment(struct mlx5_mkey_seg *seg, struct ib_send_wr *wr,
@@ -1830,7 +1865,8 @@ static void set_mkey_segment(struct mlx5_mkey_seg *seg, struct ib_send_wr *wr,
return;
}
- seg->flags = get_umr_flags(wr->wr.fast_reg.access_flags);
+ seg->flags = get_umr_flags(wr->wr.fast_reg.access_flags) |
+ MLX5_ACCESS_MODE_MTT;
*writ = seg->flags & (MLX5_PERM_LOCAL_WRITE | IB_ACCESS_REMOTE_WRITE);
seg->qpn_mkey7_0 = cpu_to_be32((wr->wr.fast_reg.rkey & 0xff) | 0xffffff00);
seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL);
@@ -1946,6 +1982,342 @@ static int set_data_inl_seg(struct mlx5_ib_qp *qp, struct ib_send_wr *wr,
return 0;
}
+static u16 prot_field_size(enum ib_signature_type type)
+{
+ switch (type) {
+ case IB_SIG_TYPE_T10_DIF:
+ return MLX5_DIF_SIZE;
+ default:
+ return 0;
+ }
+}
+
+static u8 bs_selector(int block_size)
+{
+ switch (block_size) {
+ case 512: return 0x1;
+ case 520: return 0x2;
+ case 4096: return 0x3;
+ case 4160: return 0x4;
+ case 1073741824: return 0x5;
+ default: return 0;
+ }
+}
+
+static int format_selector(struct ib_sig_attrs *attr,
+ struct ib_sig_domain *domain,
+ int *selector)
+{
+
+#define FORMAT_DIF_NONE 0
+#define FORMAT_DIF_CRC_INC 8
+#define FORMAT_DIF_CRC_NO_INC 12
+#define FORMAT_DIF_CSUM_INC 13
+#define FORMAT_DIF_CSUM_NO_INC 14
+
+ switch (domain->sig.dif.type) {
+ case IB_T10DIF_NONE:
+ /* No DIF */
+ *selector = FORMAT_DIF_NONE;
+ break;
+ case IB_T10DIF_TYPE1: /* Fall through */
+ case IB_T10DIF_TYPE2:
+ switch (domain->sig.dif.bg_type) {
+ case IB_T10DIF_CRC:
+ *selector = FORMAT_DIF_CRC_INC;
+ break;
+ case IB_T10DIF_CSUM:
+ *selector = FORMAT_DIF_CSUM_INC;
+ break;
+ default:
+ return 1;
+ }
+ break;
+ case IB_T10DIF_TYPE3:
+ switch (domain->sig.dif.bg_type) {
+ case IB_T10DIF_CRC:
+ *selector = domain->sig.dif.type3_inc_reftag ?
+ FORMAT_DIF_CRC_INC :
+ FORMAT_DIF_CRC_NO_INC;
+ break;
+ case IB_T10DIF_CSUM:
+ *selector = domain->sig.dif.type3_inc_reftag ?
+ FORMAT_DIF_CSUM_INC :
+ FORMAT_DIF_CSUM_NO_INC;
+ break;
+ default:
+ return 1;
+ }
+ break;
+ default:
+ return 1;
+ }
+
+ return 0;
+}
+
+static int mlx5_set_bsf(struct ib_mr *sig_mr,
+ struct ib_sig_attrs *sig_attrs,
+ struct mlx5_bsf *bsf, u32 data_size)
+{
+ struct mlx5_core_sig_ctx *msig = to_mmr(sig_mr)->sig;
+ struct mlx5_bsf_basic *basic = &bsf->basic;
+ struct ib_sig_domain *mem = &sig_attrs->mem;
+ struct ib_sig_domain *wire = &sig_attrs->wire;
+ int ret, selector;
+
+ switch (sig_attrs->mem.sig_type) {
+ case IB_SIG_TYPE_T10_DIF:
+ if (sig_attrs->wire.sig_type != IB_SIG_TYPE_T10_DIF)
+ return -EINVAL;
+
+ /* Input domain check byte mask */
+ basic->check_byte_mask = sig_attrs->check_mask;
+ if (mem->sig.dif.pi_interval == wire->sig.dif.pi_interval &&
+ mem->sig.dif.type == wire->sig.dif.type) {
+ /* Same block structure */
+ basic->bsf_size_sbs = 1 << 4;
+ if (mem->sig.dif.bg_type == wire->sig.dif.bg_type)
+ basic->wire.copy_byte_mask = 0xff;
+ else
+ basic->wire.copy_byte_mask = 0x3f;
+ } else
+ basic->wire.bs_selector = bs_selector(wire->sig.dif.pi_interval);
+
+ basic->mem.bs_selector = bs_selector(mem->sig.dif.pi_interval);
+ basic->raw_data_size = cpu_to_be32(data_size);
+
+ ret = format_selector(sig_attrs, mem, &selector);
+ if (ret)
+ return -EINVAL;
+ basic->m_bfs_psv = cpu_to_be32(selector << 24 |
+ msig->psv_memory.psv_idx);
+
+ ret = format_selector(sig_attrs, wire, &selector);
+ if (ret)
+ return -EINVAL;
+ basic->w_bfs_psv = cpu_to_be32(selector << 24 |
+ msig->psv_wire.psv_idx);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int set_sig_data_segment(struct ib_send_wr *wr, struct mlx5_ib_qp *qp,
+ void **seg, int *size)
+{
+ struct ib_sig_attrs *sig_attrs = wr->wr.sig_handover.sig_attrs;
+ struct ib_mr *sig_mr = wr->wr.sig_handover.sig_mr;
+ struct mlx5_bsf *bsf;
+ u32 data_len = wr->sg_list->length;
+ u32 data_key = wr->sg_list->lkey;
+ u64 data_va = wr->sg_list->addr;
+ int ret;
+ int wqe_size;
+
+ if (!wr->wr.sig_handover.prot) {
+ /**
+ * Source domain doesn't contain signature information
+ * So need construct:
+ * ------------------
+ * | data_klm |
+ * ------------------
+ * | BSF |
+ * ------------------
+ **/
+ struct mlx5_klm *data_klm = *seg;
+
+ data_klm->bcount = cpu_to_be32(data_len);
+ data_klm->key = cpu_to_be32(data_key);
+ data_klm->va = cpu_to_be64(data_va);
+ wqe_size = ALIGN(sizeof(*data_klm), 64);
+ } else {
+ /**
+ * Source domain contains signature information
+ * So need construct a strided block format:
+ * ---------------------------
+ * | stride_block_ctrl |
+ * ---------------------------
+ * | data_klm |
+ * ---------------------------
+ * | prot_klm |
+ * ---------------------------
+ * | BSF |
+ * ---------------------------
+ **/
+ struct mlx5_stride_block_ctrl_seg *sblock_ctrl;
+ struct mlx5_stride_block_entry *data_sentry;
+ struct mlx5_stride_block_entry *prot_sentry;
+ u32 prot_key = wr->wr.sig_handover.prot->lkey;
+ u64 prot_va = wr->wr.sig_handover.prot->addr;
+ u16 block_size = sig_attrs->mem.sig.dif.pi_interval;
+ int prot_size;
+
+ sblock_ctrl = *seg;
+ data_sentry = (void *)sblock_ctrl + sizeof(*sblock_ctrl);
+ prot_sentry = (void *)data_sentry + sizeof(*data_sentry);
+
+ prot_size = prot_field_size(sig_attrs->mem.sig_type);
+ if (!prot_size) {
+ pr_err("Bad block size given: %u\n", block_size);
+ return -EINVAL;
+ }
+ sblock_ctrl->bcount_per_cycle = cpu_to_be32(block_size +
+ prot_size);
+ sblock_ctrl->op = cpu_to_be32(MLX5_STRIDE_BLOCK_OP);
+ sblock_ctrl->repeat_count = cpu_to_be32(data_len / block_size);
+ sblock_ctrl->num_entries = cpu_to_be16(2);
+
+ data_sentry->bcount = cpu_to_be16(block_size);
+ data_sentry->key = cpu_to_be32(data_key);
+ data_sentry->va = cpu_to_be64(data_va);
+ prot_sentry->bcount = cpu_to_be16(prot_size);
+ prot_sentry->key = cpu_to_be32(prot_key);
+
+ if (prot_key == data_key && prot_va == data_va) {
+ /**
+ * The data and protection are interleaved
+ * in a single memory region
+ **/
+ prot_sentry->va = cpu_to_be64(data_va + block_size);
+ prot_sentry->stride = cpu_to_be16(block_size + prot_size);
+ data_sentry->stride = prot_sentry->stride;
+ } else {
+ /* The data and protection are two different buffers */
+ prot_sentry->va = cpu_to_be64(prot_va);
+ data_sentry->stride = cpu_to_be16(block_size);
+ prot_sentry->stride = cpu_to_be16(prot_size);
+ }
+ wqe_size = ALIGN(sizeof(*sblock_ctrl) + sizeof(*data_sentry) +
+ sizeof(*prot_sentry), 64);
+ }
+
+ *seg += wqe_size;
+ *size += wqe_size / 16;
+ if (unlikely((*seg == qp->sq.qend)))
+ *seg = mlx5_get_send_wqe(qp, 0);
+
+ bsf = *seg;
+ ret = mlx5_set_bsf(sig_mr, sig_attrs, bsf, data_len);
+ if (ret)
+ return -EINVAL;
+
+ *seg += sizeof(*bsf);
+ *size += sizeof(*bsf) / 16;
+ if (unlikely((*seg == qp->sq.qend)))
+ *seg = mlx5_get_send_wqe(qp, 0);
+
+ return 0;
+}
+
+static void set_sig_mkey_segment(struct mlx5_mkey_seg *seg,
+ struct ib_send_wr *wr, u32 nelements,
+ u32 length, u32 pdn)
+{
+ struct ib_mr *sig_mr = wr->wr.sig_handover.sig_mr;
+ u32 sig_key = sig_mr->rkey;
+ u8 sigerr = to_mmr(sig_mr)->sig->sigerr_count & 1;
+
+ memset(seg, 0, sizeof(*seg));
+
+ seg->flags = get_umr_flags(wr->wr.sig_handover.access_flags) |
+ MLX5_ACCESS_MODE_KLM;
+ seg->qpn_mkey7_0 = cpu_to_be32((sig_key & 0xff) | 0xffffff00);
+ seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL | sigerr << 26 |
+ MLX5_MKEY_BSF_EN | pdn);
+ seg->len = cpu_to_be64(length);
+ seg->xlt_oct_size = cpu_to_be32(be16_to_cpu(get_klm_octo(nelements)));
+ seg->bsfs_octo_size = cpu_to_be32(MLX5_MKEY_BSF_OCTO_SIZE);
+}
+
+static void set_sig_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr,
+ struct ib_send_wr *wr, u32 nelements)
+{
+ memset(umr, 0, sizeof(*umr));
+
+ umr->flags = MLX5_FLAGS_INLINE | MLX5_FLAGS_CHECK_FREE;
+ umr->klm_octowords = get_klm_octo(nelements);
+ umr->bsf_octowords = cpu_to_be16(MLX5_MKEY_BSF_OCTO_SIZE);
+ umr->mkey_mask = sig_mkey_mask();
+}
+
+
+static int set_sig_umr_wr(struct ib_send_wr *wr, struct mlx5_ib_qp *qp,
+ void **seg, int *size)
+{
+ struct mlx5_ib_mr *sig_mr = to_mmr(wr->wr.sig_handover.sig_mr);
+ u32 pdn = get_pd(qp)->pdn;
+ u32 klm_oct_size;
+ int region_len, ret;
+
+ if (unlikely(wr->num_sge != 1) ||
+ unlikely(wr->wr.sig_handover.access_flags &
+ IB_ACCESS_REMOTE_ATOMIC) ||
+ unlikely(!sig_mr->sig) || unlikely(!qp->signature_en) ||
+ unlikely(!sig_mr->sig->sig_status_checked))
+ return -EINVAL;
+
+ /* length of the protected region, data + protection */
+ region_len = wr->sg_list->length;
+ if (wr->wr.sig_handover.prot)
+ region_len += wr->wr.sig_handover.prot->length;
+
+ /**
+ * KLM octoword size - if protection was provided
+ * then we use strided block format (3 octowords),
+ * else we use single KLM (1 octoword)
+ **/
+ klm_oct_size = wr->wr.sig_handover.prot ? 3 : 1;
+
+ set_sig_umr_segment(*seg, wr, klm_oct_size);
+ *seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
+ *size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
+ if (unlikely((*seg == qp->sq.qend)))
+ *seg = mlx5_get_send_wqe(qp, 0);
+
+ set_sig_mkey_segment(*seg, wr, klm_oct_size, region_len, pdn);
+ *seg += sizeof(struct mlx5_mkey_seg);
+ *size += sizeof(struct mlx5_mkey_seg) / 16;
+ if (unlikely((*seg == qp->sq.qend)))
+ *seg = mlx5_get_send_wqe(qp, 0);
+
+ ret = set_sig_data_segment(wr, qp, seg, size);
+ if (ret)
+ return ret;
+
+ sig_mr->sig->sig_status_checked = false;
+ return 0;
+}
+
+static int set_psv_wr(struct ib_sig_domain *domain,
+ u32 psv_idx, void **seg, int *size)
+{
+ struct mlx5_seg_set_psv *psv_seg = *seg;
+
+ memset(psv_seg, 0, sizeof(*psv_seg));
+ psv_seg->psv_num = cpu_to_be32(psv_idx);
+ switch (domain->sig_type) {
+ case IB_SIG_TYPE_T10_DIF:
+ psv_seg->transient_sig = cpu_to_be32(domain->sig.dif.bg << 16 |
+ domain->sig.dif.app_tag);
+ psv_seg->ref_tag = cpu_to_be32(domain->sig.dif.ref_tag);
+
+ *seg += sizeof(*psv_seg);
+ *size += sizeof(*psv_seg) / 16;
+ break;
+
+ default:
+ pr_err("Bad signature type given.\n");
+ return 1;
+ }
+
+ return 0;
+}
+
static int set_frwr_li_wr(void **seg, struct ib_send_wr *wr, int *size,
struct mlx5_core_dev *mdev, struct mlx5_ib_pd *pd, struct mlx5_ib_qp *qp)
{
@@ -2033,6 +2405,59 @@ static u8 get_fence(u8 fence, struct ib_send_wr *wr)
}
}
+static int begin_wqe(struct mlx5_ib_qp *qp, void **seg,
+ struct mlx5_wqe_ctrl_seg **ctrl,
+ struct ib_send_wr *wr, int *idx,
+ int *size, int nreq)
+{
+ int err = 0;
+
+ if (unlikely(mlx5_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq))) {
+ err = -ENOMEM;
+ return err;
+ }
+
+ *idx = qp->sq.cur_post & (qp->sq.wqe_cnt - 1);
+ *seg = mlx5_get_send_wqe(qp, *idx);
+ *ctrl = *seg;
+ *(uint32_t *)(*seg + 8) = 0;
+ (*ctrl)->imm = send_ieth(wr);
+ (*ctrl)->fm_ce_se = qp->sq_signal_bits |
+ (wr->send_flags & IB_SEND_SIGNALED ?
+ MLX5_WQE_CTRL_CQ_UPDATE : 0) |
+ (wr->send_flags & IB_SEND_SOLICITED ?
+ MLX5_WQE_CTRL_SOLICITED : 0);
+
+ *seg += sizeof(**ctrl);
+ *size = sizeof(**ctrl) / 16;
+
+ return err;
+}
+
+static void finish_wqe(struct mlx5_ib_qp *qp,
+ struct mlx5_wqe_ctrl_seg *ctrl,
+ u8 size, unsigned idx, u64 wr_id,
+ int nreq, u8 fence, u8 next_fence,
+ u32 mlx5_opcode)
+{
+ u8 opmod = 0;
+
+ ctrl->opmod_idx_opcode = cpu_to_be32(((u32)(qp->sq.cur_post) << 8) |
+ mlx5_opcode | ((u32)opmod << 24));
+ ctrl->qpn_ds = cpu_to_be32(size | (qp->mqp.qpn << 8));
+ ctrl->fm_ce_se |= fence;
+ qp->fm_cache = next_fence;
+ if (unlikely(qp->wq_sig))
+ ctrl->signature = wq_sig(ctrl);
+
+ qp->sq.wrid[idx] = wr_id;
+ qp->sq.w_list[idx].opcode = mlx5_opcode;
+ qp->sq.wqe_head[idx] = qp->sq.head + nreq;
+ qp->sq.cur_post += DIV_ROUND_UP(size * 16, MLX5_SEND_WQE_BB);
+ qp->sq.w_list[idx].next = qp->sq.cur_post;
+}
+
+
int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
struct ib_send_wr **bad_wr)
{
@@ -2040,13 +2465,13 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
struct mlx5_core_dev *mdev = &dev->mdev;
struct mlx5_ib_qp *qp = to_mqp(ibqp);
+ struct mlx5_ib_mr *mr;
struct mlx5_wqe_data_seg *dpseg;
struct mlx5_wqe_xrc_seg *xrc;
struct mlx5_bf *bf = qp->bf;
int uninitialized_var(size);
void *qend = qp->sq.qend;
unsigned long flags;
- u32 mlx5_opcode;
unsigned idx;
int err = 0;
int inl = 0;
@@ -2055,7 +2480,6 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
int nreq;
int i;
u8 next_fence = 0;
- u8 opmod = 0;
u8 fence;
spin_lock_irqsave(&qp->sq.lock, flags);
@@ -2068,36 +2492,23 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
goto out;
}
- if (unlikely(mlx5_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq))) {
+ fence = qp->fm_cache;
+ num_sge = wr->num_sge;
+ if (unlikely(num_sge > qp->sq.max_gs)) {
mlx5_ib_warn(dev, "\n");
err = -ENOMEM;
*bad_wr = wr;
goto out;
}
- fence = qp->fm_cache;
- num_sge = wr->num_sge;
- if (unlikely(num_sge > qp->sq.max_gs)) {
+ err = begin_wqe(qp, &seg, &ctrl, wr, &idx, &size, nreq);
+ if (err) {
mlx5_ib_warn(dev, "\n");
err = -ENOMEM;
*bad_wr = wr;
goto out;
}
- idx = qp->sq.cur_post & (qp->sq.wqe_cnt - 1);
- seg = mlx5_get_send_wqe(qp, idx);
- ctrl = seg;
- *(uint32_t *)(seg + 8) = 0;
- ctrl->imm = send_ieth(wr);
- ctrl->fm_ce_se = qp->sq_signal_bits |
- (wr->send_flags & IB_SEND_SIGNALED ?
- MLX5_WQE_CTRL_CQ_UPDATE : 0) |
- (wr->send_flags & IB_SEND_SOLICITED ?
- MLX5_WQE_CTRL_SOLICITED : 0);
-
- seg += sizeof(*ctrl);
- size = sizeof(*ctrl) / 16;
-
switch (ibqp->qp_type) {
case IB_QPT_XRC_INI:
xrc = seg;
@@ -2150,6 +2561,73 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
num_sge = 0;
break;
+ case IB_WR_REG_SIG_MR:
+ qp->sq.wr_data[idx] = IB_WR_REG_SIG_MR;
+ mr = to_mmr(wr->wr.sig_handover.sig_mr);
+
+ ctrl->imm = cpu_to_be32(mr->ibmr.rkey);
+ err = set_sig_umr_wr(wr, qp, &seg, &size);
+ if (err) {
+ mlx5_ib_warn(dev, "\n");
+ *bad_wr = wr;
+ goto out;
+ }
+
+ finish_wqe(qp, ctrl, size, idx, wr->wr_id,
+ nreq, get_fence(fence, wr),
+ next_fence, MLX5_OPCODE_UMR);
+ /*
+ * SET_PSV WQEs are not signaled and solicited
+ * on error
+ */
+ wr->send_flags &= ~IB_SEND_SIGNALED;
+ wr->send_flags |= IB_SEND_SOLICITED;
+ err = begin_wqe(qp, &seg, &ctrl, wr,
+ &idx, &size, nreq);
+ if (err) {
+ mlx5_ib_warn(dev, "\n");
+ err = -ENOMEM;
+ *bad_wr = wr;
+ goto out;
+ }
+
+ err = set_psv_wr(&wr->wr.sig_handover.sig_attrs->mem,
+ mr->sig->psv_memory.psv_idx, &seg,
+ &size);
+ if (err) {
+ mlx5_ib_warn(dev, "\n");
+ *bad_wr = wr;
+ goto out;
+ }
+
+ finish_wqe(qp, ctrl, size, idx, wr->wr_id,
+ nreq, get_fence(fence, wr),
+ next_fence, MLX5_OPCODE_SET_PSV);
+ err = begin_wqe(qp, &seg, &ctrl, wr,
+ &idx, &size, nreq);
+ if (err) {
+ mlx5_ib_warn(dev, "\n");
+ err = -ENOMEM;
+ *bad_wr = wr;
+ goto out;
+ }
+
+ next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
+ err = set_psv_wr(&wr->wr.sig_handover.sig_attrs->wire,
+ mr->sig->psv_wire.psv_idx, &seg,
+ &size);
+ if (err) {
+ mlx5_ib_warn(dev, "\n");
+ *bad_wr = wr;
+ goto out;
+ }
+
+ finish_wqe(qp, ctrl, size, idx, wr->wr_id,
+ nreq, get_fence(fence, wr),
+ next_fence, MLX5_OPCODE_SET_PSV);
+ num_sge = 0;
+ goto skip_psv;
+
default:
break;
}
@@ -2230,22 +2708,10 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
}
}
- mlx5_opcode = mlx5_ib_opcode[wr->opcode];
- ctrl->opmod_idx_opcode = cpu_to_be32(((u32)(qp->sq.cur_post) << 8) |
- mlx5_opcode |
- ((u32)opmod << 24));
- ctrl->qpn_ds = cpu_to_be32(size | (qp->mqp.qpn << 8));
- ctrl->fm_ce_se |= get_fence(fence, wr);
- qp->fm_cache = next_fence;
- if (unlikely(qp->wq_sig))
- ctrl->signature = wq_sig(ctrl);
-
- qp->sq.wrid[idx] = wr->wr_id;
- qp->sq.w_list[idx].opcode = mlx5_opcode;
- qp->sq.wqe_head[idx] = qp->sq.head + nreq;
- qp->sq.cur_post += DIV_ROUND_UP(size * 16, MLX5_SEND_WQE_BB);
- qp->sq.w_list[idx].next = qp->sq.cur_post;
-
+ finish_wqe(qp, ctrl, size, idx, wr->wr_id, nreq,
+ get_fence(fence, wr), next_fence,
+ mlx5_ib_opcode[wr->opcode]);
+skip_psv:
if (0)
dump_wqe(qp, idx, size);
}
diff --git a/drivers/infiniband/hw/mlx5/user.h b/drivers/infiniband/hw/mlx5/user.h
index 32a2a5dfc523..0f4f8e42a17f 100644
--- a/drivers/infiniband/hw/mlx5/user.h
+++ b/drivers/infiniband/hw/mlx5/user.h
@@ -62,6 +62,13 @@ struct mlx5_ib_alloc_ucontext_req {
__u32 num_low_latency_uuars;
};
+struct mlx5_ib_alloc_ucontext_req_v2 {
+ __u32 total_num_uuars;
+ __u32 num_low_latency_uuars;
+ __u32 flags;
+ __u32 reserved;
+};
+
struct mlx5_ib_alloc_ucontext_resp {
__u32 qp_tab_size;
__u32 bf_reg_size;
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 5b71d43bd89c..415f8e1a54db 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -695,6 +695,7 @@ static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries,
if (context && ib_copy_to_udata(udata, &cq->cqn, sizeof (__u32))) {
mthca_free_cq(to_mdev(ibdev), cq);
+ err = -EFAULT;
goto err_free;
}
@@ -976,12 +977,12 @@ static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
u64 virt, int acc, struct ib_udata *udata)
{
struct mthca_dev *dev = to_mdev(pd->device);
- struct ib_umem_chunk *chunk;
+ struct scatterlist *sg;
struct mthca_mr *mr;
struct mthca_reg_mr ucmd;
u64 *pages;
int shift, n, len;
- int i, j, k;
+ int i, k, entry;
int err = 0;
int write_mtt_size;
@@ -1009,10 +1010,7 @@ static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
}
shift = ffs(mr->umem->page_size) - 1;
-
- n = 0;
- list_for_each_entry(chunk, &mr->umem->chunk_list, list)
- n += chunk->nents;
+ n = mr->umem->nmap;
mr->mtt = mthca_alloc_mtt(dev, n);
if (IS_ERR(mr->mtt)) {
@@ -1030,25 +1028,24 @@ static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
write_mtt_size = min(mthca_write_mtt_size(dev), (int) (PAGE_SIZE / sizeof *pages));
- list_for_each_entry(chunk, &mr->umem->chunk_list, list)
- for (j = 0; j < chunk->nmap; ++j) {
- len = sg_dma_len(&chunk->page_list[j]) >> shift;
- for (k = 0; k < len; ++k) {
- pages[i++] = sg_dma_address(&chunk->page_list[j]) +
- mr->umem->page_size * k;
- /*
- * Be friendly to write_mtt and pass it chunks
- * of appropriate size.
- */
- if (i == write_mtt_size) {
- err = mthca_write_mtt(dev, mr->mtt, n, pages, i);
- if (err)
- goto mtt_done;
- n += i;
- i = 0;
- }
+ for_each_sg(mr->umem->sg_head.sgl, sg, mr->umem->nmap, entry) {
+ len = sg_dma_len(sg) >> shift;
+ for (k = 0; k < len; ++k) {
+ pages[i++] = sg_dma_address(sg) +
+ mr->umem->page_size * k;
+ /*
+ * Be friendly to write_mtt and pass it chunks
+ * of appropriate size.
+ */
+ if (i == write_mtt_size) {
+ err = mthca_write_mtt(dev, mr->mtt, n, pages, i);
+ if (err)
+ goto mtt_done;
+ n += i;
+ i = 0;
}
}
+ }
if (i)
err = mthca_write_mtt(dev, mr->mtt, n, pages, i);
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
index 429141078eec..353c7b05a90a 100644
--- a/drivers/infiniband/hw/nes/nes.c
+++ b/drivers/infiniband/hw/nes/nes.c
@@ -675,8 +675,11 @@ static int nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
INIT_DELAYED_WORK(&nesdev->work, nes_recheck_link_status);
/* Initialize network devices */
- if ((netdev = nes_netdev_init(nesdev, mmio_regs)) == NULL)
+ netdev = nes_netdev_init(nesdev, mmio_regs);
+ if (netdev == NULL) {
+ ret = -ENOMEM;
goto bail7;
+ }
/* Register network device */
ret = register_netdev(netdev);
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 9c9f2f57e960..dfa9df484505 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -128,6 +128,7 @@ static void build_mpa_v1(struct nes_cm_node *, void *, u8);
static void build_rdma0_msg(struct nes_cm_node *, struct nes_qp **);
static void print_core(struct nes_cm_core *core);
+static void record_ird_ord(struct nes_cm_node *, u16, u16);
/* External CM API Interface */
/* instance of function pointers for client API */
@@ -317,7 +318,6 @@ static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 *type,
}
}
-
if (priv_data_len + mpa_hdr_len != len) {
nes_debug(NES_DBG_CM, "The received ietf buffer was not right"
" complete (%x + %x != %x)\n",
@@ -356,25 +356,57 @@ static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 *type,
/* send reset */
return -EINVAL;
}
+ if (ird_size == IETF_NO_IRD_ORD || ord_size == IETF_NO_IRD_ORD)
+ cm_node->mpav2_ird_ord = IETF_NO_IRD_ORD;
- if (cm_node->state != NES_CM_STATE_MPAREQ_SENT) {
+ if (cm_node->mpav2_ird_ord != IETF_NO_IRD_ORD) {
/* responder */
- if (cm_node->ord_size > ird_size)
- cm_node->ord_size = ird_size;
- } else {
- /* initiator */
- if (cm_node->ord_size > ird_size)
- cm_node->ord_size = ird_size;
-
- if (cm_node->ird_size < ord_size) {
- /* no resources available */
- /* send terminate message */
- return -EINVAL;
+ if (cm_node->state != NES_CM_STATE_MPAREQ_SENT) {
+ /* we are still negotiating */
+ if (ord_size > NES_MAX_IRD) {
+ cm_node->ird_size = NES_MAX_IRD;
+ } else {
+ cm_node->ird_size = ord_size;
+ if (ord_size == 0 &&
+ (rtr_ctrl_ord & IETF_RDMA0_READ)) {
+ cm_node->ird_size = 1;
+ nes_debug(NES_DBG_CM,
+ "%s: Remote peer doesn't support RDMA0_READ (ord=%u)\n",
+ __func__, ord_size);
+ }
+ }
+ if (ird_size > NES_MAX_ORD)
+ cm_node->ord_size = NES_MAX_ORD;
+ else
+ cm_node->ord_size = ird_size;
+ } else { /* initiator */
+ if (ord_size > NES_MAX_IRD) {
+ nes_debug(NES_DBG_CM,
+ "%s: Unable to support the requested (ord =%u)\n",
+ __func__, ord_size);
+ return -EINVAL;
+ }
+ cm_node->ird_size = ord_size;
+
+ if (ird_size > NES_MAX_ORD) {
+ cm_node->ord_size = NES_MAX_ORD;
+ } else {
+ if (ird_size == 0 &&
+ (rtr_ctrl_ord & IETF_RDMA0_READ)) {
+ nes_debug(NES_DBG_CM,
+ "%s: Remote peer doesn't support RDMA0_READ (ird=%u)\n",
+ __func__, ird_size);
+ return -EINVAL;
+ } else {
+ cm_node->ord_size = ird_size;
+ }
+ }
}
}
if (rtr_ctrl_ord & IETF_RDMA0_READ) {
cm_node->send_rdma0_op = SEND_RDMA_READ_ZERO;
+
} else if (rtr_ctrl_ord & IETF_RDMA0_WRITE) {
cm_node->send_rdma0_op = SEND_RDMA_WRITE_ZERO;
} else { /* Not supported RDMA0 operation */
@@ -514,6 +546,19 @@ static void print_core(struct nes_cm_core *core)
nes_debug(NES_DBG_CM, "-------------- end core ---------------\n");
}
+static void record_ird_ord(struct nes_cm_node *cm_node,
+ u16 conn_ird, u16 conn_ord)
+{
+ if (conn_ird > NES_MAX_IRD)
+ conn_ird = NES_MAX_IRD;
+
+ if (conn_ord > NES_MAX_ORD)
+ conn_ord = NES_MAX_ORD;
+
+ cm_node->ird_size = conn_ird;
+ cm_node->ord_size = conn_ord;
+}
+
/**
* cm_build_mpa_frame - build a MPA V1 frame or MPA V2 frame
*/
@@ -557,11 +602,13 @@ static void build_mpa_v2(struct nes_cm_node *cm_node,
mpa_frame->priv_data_len += htons(IETF_RTR_MSG_SIZE);
/* initialize RTR msg */
- ctrl_ird = (cm_node->ird_size > IETF_NO_IRD_ORD) ?
- IETF_NO_IRD_ORD : cm_node->ird_size;
- ctrl_ord = (cm_node->ord_size > IETF_NO_IRD_ORD) ?
- IETF_NO_IRD_ORD : cm_node->ord_size;
-
+ if (cm_node->mpav2_ird_ord == IETF_NO_IRD_ORD) {
+ ctrl_ird = IETF_NO_IRD_ORD;
+ ctrl_ord = IETF_NO_IRD_ORD;
+ } else {
+ ctrl_ird = cm_node->ird_size & IETF_NO_IRD_ORD;
+ ctrl_ord = cm_node->ord_size & IETF_NO_IRD_ORD;
+ }
ctrl_ird |= IETF_PEER_TO_PEER;
ctrl_ird |= IETF_FLPDU_ZERO_LEN;
@@ -610,7 +657,7 @@ static void build_rdma0_msg(struct nes_cm_node *cm_node, struct nes_qp **nesqp_a
struct nes_qp *nesqp = *nesqp_addr;
struct nes_hw_qp_wqe *wqe = &nesqp->hwqp.sq_vbase[0];
- u64temp = (unsigned long)nesqp;
+ u64temp = (unsigned long)nesqp->nesuqp_addr;
u64temp |= NES_SW_CONTEXT_ALIGN >> 1;
set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX, u64temp);
@@ -1409,8 +1456,9 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
cm_node->mpa_frame_rev = mpa_version;
cm_node->send_rdma0_op = SEND_RDMA_READ_ZERO;
- cm_node->ird_size = IETF_NO_IRD_ORD;
- cm_node->ord_size = IETF_NO_IRD_ORD;
+ cm_node->mpav2_ird_ord = 0;
+ cm_node->ird_size = 0;
+ cm_node->ord_size = 0;
nes_debug(NES_DBG_CM, "Make node addresses : loc = %pI4:%x, rem = %pI4:%x\n",
&cm_node->loc_addr, cm_node->loc_port,
@@ -3027,11 +3075,11 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
rem_ref_cm_node(cm_node->cm_core, cm_node);
return -ECONNRESET;
}
-
/* associate the node with the QP */
nesqp->cm_node = (void *)cm_node;
cm_node->nesqp = nesqp;
+
nes_debug(NES_DBG_CM, "QP%u, cm_node=%p, jiffies = %lu listener = %p\n",
nesqp->hwqp.qp_id, cm_node, jiffies, cm_node->listener);
atomic_inc(&cm_accepts);
@@ -3054,6 +3102,11 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
if (cm_node->mpa_frame_rev == IETF_MPA_V1)
mpa_frame_offset = 4;
+ if (cm_node->mpa_frame_rev == IETF_MPA_V1 ||
+ cm_node->mpav2_ird_ord == IETF_NO_IRD_ORD) {
+ record_ird_ord(cm_node, (u16)conn_param->ird, (u16)conn_param->ord);
+ }
+
memcpy(mpa_v2_frame->priv_data, conn_param->private_data,
conn_param->private_data_len);
@@ -3117,7 +3170,6 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
}
nesqp->skip_lsmm = 1;
-
/* Cache the cm_id in the qp */
nesqp->cm_id = cm_id;
cm_node->cm_id = cm_id;
@@ -3154,7 +3206,7 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32(
((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT));
nesqp->nesqp_context->ird_ord_sizes |=
- cpu_to_le32((u32)conn_param->ord);
+ cpu_to_le32((u32)cm_node->ord_size);
memset(&nes_quad, 0, sizeof(nes_quad));
nes_quad.DstIpAdrIndex =
@@ -3194,6 +3246,9 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
cm_event.remote_addr = cm_id->remote_addr;
cm_event.private_data = NULL;
cm_event.private_data_len = 0;
+ cm_event.ird = cm_node->ird_size;
+ cm_event.ord = cm_node->ord_size;
+
ret = cm_id->event_handler(cm_id, &cm_event);
attr.qp_state = IB_QPS_RTS;
nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
@@ -3290,14 +3345,8 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
/* cache the cm_id in the qp */
nesqp->cm_id = cm_id;
-
cm_id->provider_data = nesqp;
-
nesqp->private_data_len = conn_param->private_data_len;
- nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((u32)conn_param->ord);
- /* space for rdma0 read msg */
- if (conn_param->ord == 0)
- nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32(1);
nes_debug(NES_DBG_CM, "requested ord = 0x%08X.\n", (u32)conn_param->ord);
nes_debug(NES_DBG_CM, "mpa private data len =%u\n",
@@ -3334,6 +3383,11 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
return -ENOMEM;
}
+ record_ird_ord(cm_node, (u16)conn_param->ird, (u16)conn_param->ord);
+ if (cm_node->send_rdma0_op == SEND_RDMA_READ_ZERO &&
+ cm_node->ord_size == 0)
+ cm_node->ord_size = 1;
+
cm_node->apbvt_set = apbvt_set;
nesqp->cm_node = cm_node;
cm_node->nesqp = nesqp;
@@ -3530,6 +3584,8 @@ static void cm_event_connected(struct nes_cm_event *event)
nesqp->nesqp_context->ird_ord_sizes |=
cpu_to_le32((u32)1 <<
NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT);
+ nesqp->nesqp_context->ird_ord_sizes |=
+ cpu_to_le32((u32)cm_node->ord_size);
/* Adjust tail for not having a LSMM */
/*nesqp->hwqp.sq_tail = 1;*/
@@ -3742,8 +3798,13 @@ static void cm_event_mpa_req(struct nes_cm_event *event)
cm_event_raddr->sin_addr.s_addr = htonl(event->cm_info.rem_addr);
cm_event.private_data = cm_node->mpa_frame_buf;
cm_event.private_data_len = (u8)cm_node->mpa_frame_size;
+ if (cm_node->mpa_frame_rev == IETF_MPA_V1) {
+ cm_event.ird = NES_MAX_IRD;
+ cm_event.ord = NES_MAX_ORD;
+ } else {
cm_event.ird = cm_node->ird_size;
cm_event.ord = cm_node->ord_size;
+ }
ret = cm_id->event_handler(cm_id, &cm_event);
if (ret)
diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h
index 4646e6666087..522c99cd07c4 100644
--- a/drivers/infiniband/hw/nes/nes_cm.h
+++ b/drivers/infiniband/hw/nes/nes_cm.h
@@ -58,6 +58,8 @@
#define IETF_RDMA0_WRITE 0x8000
#define IETF_RDMA0_READ 0x4000
#define IETF_NO_IRD_ORD 0x3FFF
+#define NES_MAX_IRD 0x40
+#define NES_MAX_ORD 0x7F
enum ietf_mpa_flags {
IETF_MPA_FLAGS_MARKERS = 0x80, /* receive Markers */
@@ -333,6 +335,7 @@ struct nes_cm_node {
enum mpa_frame_version mpa_frame_rev;
u16 ird_size;
u16 ord_size;
+ u16 mpav2_ird_ord;
u16 mpa_frame_size;
struct iw_cm_id *cm_id;
diff --git a/drivers/infiniband/hw/nes/nes_user.h b/drivers/infiniband/hw/nes/nes_user.h
index 4926de744488..529c421bb15c 100644
--- a/drivers/infiniband/hw/nes/nes_user.h
+++ b/drivers/infiniband/hw/nes/nes_user.h
@@ -39,8 +39,8 @@
#include <linux/types.h>
-#define NES_ABI_USERSPACE_VER 1
-#define NES_ABI_KERNEL_VER 1
+#define NES_ABI_USERSPACE_VER 2
+#define NES_ABI_KERNEL_VER 2
/*
* Make sure that all structs defined in this file remain laid out so
@@ -78,6 +78,7 @@ struct nes_create_cq_req {
struct nes_create_qp_req {
__u64 user_wqe_buffers;
+ __u64 user_qp_buffer;
};
enum iwnes_memreg_type {
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
index 8308e3634767..218dd3574285 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.c
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
@@ -1186,11 +1186,13 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,
nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
kfree(nesqp->allocated_buffer);
nes_debug(NES_DBG_QP, "ib_copy_from_udata() Failed \n");
- return NULL;
+ return ERR_PTR(-EFAULT);
}
if (req.user_wqe_buffers) {
virt_wqs = 1;
}
+ if (req.user_qp_buffer)
+ nesqp->nesuqp_addr = req.user_qp_buffer;
if ((ibpd->uobject) && (ibpd->uobject->context)) {
nesqp->user_mode = 1;
nes_ucontext = to_nesucontext(ibpd->uobject->context);
@@ -2307,7 +2309,7 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
struct nes_device *nesdev = nesvnic->nesdev;
struct nes_adapter *nesadapter = nesdev->nesadapter;
struct ib_mr *ibmr = ERR_PTR(-EINVAL);
- struct ib_umem_chunk *chunk;
+ struct scatterlist *sg;
struct nes_ucontext *nes_ucontext;
struct nes_pbl *nespbl;
struct nes_mr *nesmr;
@@ -2315,7 +2317,7 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
struct nes_mem_reg_req req;
struct nes_vpbl vpbl;
struct nes_root_vpbl root_vpbl;
- int nmap_index, page_index;
+ int entry, page_index;
int page_count = 0;
int err, pbl_depth = 0;
int chunk_pages;
@@ -2330,6 +2332,7 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
u16 pbl_count;
u8 single_page = 1;
u8 stag_key;
+ int first_page = 1;
region = ib_umem_get(pd->uobject->context, start, length, acc, 0);
if (IS_ERR(region)) {
@@ -2380,128 +2383,125 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
}
nesmr->region = region;
- list_for_each_entry(chunk, &region->chunk_list, list) {
- nes_debug(NES_DBG_MR, "Chunk: nents = %u, nmap = %u .\n",
- chunk->nents, chunk->nmap);
- for (nmap_index = 0; nmap_index < chunk->nmap; ++nmap_index) {
- if (sg_dma_address(&chunk->page_list[nmap_index]) & ~PAGE_MASK) {
- ib_umem_release(region);
- nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
- nes_debug(NES_DBG_MR, "Unaligned Memory Buffer: 0x%x\n",
- (unsigned int) sg_dma_address(&chunk->page_list[nmap_index]));
- ibmr = ERR_PTR(-EINVAL);
- kfree(nesmr);
- goto reg_user_mr_err;
- }
+ for_each_sg(region->sg_head.sgl, sg, region->nmap, entry) {
+ if (sg_dma_address(sg) & ~PAGE_MASK) {
+ ib_umem_release(region);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ nes_debug(NES_DBG_MR, "Unaligned Memory Buffer: 0x%x\n",
+ (unsigned int) sg_dma_address(sg));
+ ibmr = ERR_PTR(-EINVAL);
+ kfree(nesmr);
+ goto reg_user_mr_err;
+ }
- if (!sg_dma_len(&chunk->page_list[nmap_index])) {
- ib_umem_release(region);
- nes_free_resource(nesadapter, nesadapter->allocated_mrs,
- stag_index);
- nes_debug(NES_DBG_MR, "Invalid Buffer Size\n");
- ibmr = ERR_PTR(-EINVAL);
- kfree(nesmr);
- goto reg_user_mr_err;
- }
+ if (!sg_dma_len(sg)) {
+ ib_umem_release(region);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs,
+ stag_index);
+ nes_debug(NES_DBG_MR, "Invalid Buffer Size\n");
+ ibmr = ERR_PTR(-EINVAL);
+ kfree(nesmr);
+ goto reg_user_mr_err;
+ }
- region_length += sg_dma_len(&chunk->page_list[nmap_index]);
- chunk_pages = sg_dma_len(&chunk->page_list[nmap_index]) >> 12;
- region_length -= skip_pages << 12;
- for (page_index=skip_pages; page_index < chunk_pages; page_index++) {
- skip_pages = 0;
- if ((page_count!=0)&&(page_count<<12)-(region->offset&(4096-1))>=region->length)
- goto enough_pages;
- if ((page_count&0x01FF) == 0) {
- if (page_count >= 1024 * 512) {
+ region_length += sg_dma_len(sg);
+ chunk_pages = sg_dma_len(sg) >> 12;
+ region_length -= skip_pages << 12;
+ for (page_index = skip_pages; page_index < chunk_pages; page_index++) {
+ skip_pages = 0;
+ if ((page_count != 0) && (page_count<<12)-(region->offset&(4096-1)) >= region->length)
+ goto enough_pages;
+ if ((page_count&0x01FF) == 0) {
+ if (page_count >= 1024 * 512) {
+ ib_umem_release(region);
+ nes_free_resource(nesadapter,
+ nesadapter->allocated_mrs, stag_index);
+ kfree(nesmr);
+ ibmr = ERR_PTR(-E2BIG);
+ goto reg_user_mr_err;
+ }
+ if (root_pbl_index == 1) {
+ root_vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev,
+ 8192, &root_vpbl.pbl_pbase);
+ nes_debug(NES_DBG_MR, "Allocating root PBL, va = %p, pa = 0x%08X\n",
+ root_vpbl.pbl_vbase, (unsigned int)root_vpbl.pbl_pbase);
+ if (!root_vpbl.pbl_vbase) {
ib_umem_release(region);
- nes_free_resource(nesadapter,
- nesadapter->allocated_mrs, stag_index);
+ pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
+ vpbl.pbl_pbase);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs,
+ stag_index);
kfree(nesmr);
- ibmr = ERR_PTR(-E2BIG);
+ ibmr = ERR_PTR(-ENOMEM);
goto reg_user_mr_err;
}
- if (root_pbl_index == 1) {
- root_vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev,
- 8192, &root_vpbl.pbl_pbase);
- nes_debug(NES_DBG_MR, "Allocating root PBL, va = %p, pa = 0x%08X\n",
- root_vpbl.pbl_vbase, (unsigned int)root_vpbl.pbl_pbase);
- if (!root_vpbl.pbl_vbase) {
- ib_umem_release(region);
- pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
- vpbl.pbl_pbase);
- nes_free_resource(nesadapter, nesadapter->allocated_mrs,
- stag_index);
- kfree(nesmr);
- ibmr = ERR_PTR(-ENOMEM);
- goto reg_user_mr_err;
- }
- root_vpbl.leaf_vpbl = kzalloc(sizeof(*root_vpbl.leaf_vpbl)*1024,
- GFP_KERNEL);
- if (!root_vpbl.leaf_vpbl) {
- ib_umem_release(region);
- pci_free_consistent(nesdev->pcidev, 8192, root_vpbl.pbl_vbase,
- root_vpbl.pbl_pbase);
- pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
- vpbl.pbl_pbase);
- nes_free_resource(nesadapter, nesadapter->allocated_mrs,
- stag_index);
- kfree(nesmr);
- ibmr = ERR_PTR(-ENOMEM);
- goto reg_user_mr_err;
- }
- root_vpbl.pbl_vbase[0].pa_low =
- cpu_to_le32((u32)vpbl.pbl_pbase);
- root_vpbl.pbl_vbase[0].pa_high =
- cpu_to_le32((u32)((((u64)vpbl.pbl_pbase) >> 32)));
- root_vpbl.leaf_vpbl[0] = vpbl;
- }
- vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 4096,
- &vpbl.pbl_pbase);
- nes_debug(NES_DBG_MR, "Allocating leaf PBL, va = %p, pa = 0x%08X\n",
- vpbl.pbl_vbase, (unsigned int)vpbl.pbl_pbase);
- if (!vpbl.pbl_vbase) {
+ root_vpbl.leaf_vpbl = kzalloc(sizeof(*root_vpbl.leaf_vpbl)*1024,
+ GFP_KERNEL);
+ if (!root_vpbl.leaf_vpbl) {
ib_umem_release(region);
- nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
- ibmr = ERR_PTR(-ENOMEM);
+ pci_free_consistent(nesdev->pcidev, 8192, root_vpbl.pbl_vbase,
+ root_vpbl.pbl_pbase);
+ pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
+ vpbl.pbl_pbase);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs,
+ stag_index);
kfree(nesmr);
+ ibmr = ERR_PTR(-ENOMEM);
goto reg_user_mr_err;
}
- if (1 <= root_pbl_index) {
- root_vpbl.pbl_vbase[root_pbl_index].pa_low =
- cpu_to_le32((u32)vpbl.pbl_pbase);
- root_vpbl.pbl_vbase[root_pbl_index].pa_high =
- cpu_to_le32((u32)((((u64)vpbl.pbl_pbase)>>32)));
- root_vpbl.leaf_vpbl[root_pbl_index] = vpbl;
- }
- root_pbl_index++;
- cur_pbl_index = 0;
+ root_vpbl.pbl_vbase[0].pa_low =
+ cpu_to_le32((u32)vpbl.pbl_pbase);
+ root_vpbl.pbl_vbase[0].pa_high =
+ cpu_to_le32((u32)((((u64)vpbl.pbl_pbase) >> 32)));
+ root_vpbl.leaf_vpbl[0] = vpbl;
}
- if (single_page) {
- if (page_count != 0) {
- if ((last_dma_addr+4096) !=
- (sg_dma_address(&chunk->page_list[nmap_index])+
- (page_index*4096)))
- single_page = 0;
- last_dma_addr = sg_dma_address(&chunk->page_list[nmap_index])+
- (page_index*4096);
- } else {
- first_dma_addr = sg_dma_address(&chunk->page_list[nmap_index])+
- (page_index*4096);
- last_dma_addr = first_dma_addr;
- }
+ vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 4096,
+ &vpbl.pbl_pbase);
+ nes_debug(NES_DBG_MR, "Allocating leaf PBL, va = %p, pa = 0x%08X\n",
+ vpbl.pbl_vbase, (unsigned int)vpbl.pbl_pbase);
+ if (!vpbl.pbl_vbase) {
+ ib_umem_release(region);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ ibmr = ERR_PTR(-ENOMEM);
+ kfree(nesmr);
+ goto reg_user_mr_err;
+ }
+ if (1 <= root_pbl_index) {
+ root_vpbl.pbl_vbase[root_pbl_index].pa_low =
+ cpu_to_le32((u32)vpbl.pbl_pbase);
+ root_vpbl.pbl_vbase[root_pbl_index].pa_high =
+ cpu_to_le32((u32)((((u64)vpbl.pbl_pbase)>>32)));
+ root_vpbl.leaf_vpbl[root_pbl_index] = vpbl;
+ }
+ root_pbl_index++;
+ cur_pbl_index = 0;
+ }
+ if (single_page) {
+ if (page_count != 0) {
+ if ((last_dma_addr+4096) !=
+ (sg_dma_address(sg)+
+ (page_index*4096)))
+ single_page = 0;
+ last_dma_addr = sg_dma_address(sg)+
+ (page_index*4096);
+ } else {
+ first_dma_addr = sg_dma_address(sg)+
+ (page_index*4096);
+ last_dma_addr = first_dma_addr;
}
-
- vpbl.pbl_vbase[cur_pbl_index].pa_low =
- cpu_to_le32((u32)(sg_dma_address(&chunk->page_list[nmap_index])+
- (page_index*4096)));
- vpbl.pbl_vbase[cur_pbl_index].pa_high =
- cpu_to_le32((u32)((((u64)(sg_dma_address(&chunk->page_list[nmap_index])+
- (page_index*4096))) >> 32)));
- cur_pbl_index++;
- page_count++;
}
+
+ vpbl.pbl_vbase[cur_pbl_index].pa_low =
+ cpu_to_le32((u32)(sg_dma_address(sg)+
+ (page_index*4096)));
+ vpbl.pbl_vbase[cur_pbl_index].pa_high =
+ cpu_to_le32((u32)((((u64)(sg_dma_address(sg)+
+ (page_index*4096))) >> 32)));
+ cur_pbl_index++;
+ page_count++;
}
}
+
enough_pages:
nes_debug(NES_DBG_MR, "calculating stag, stag_index=0x%08x, driver_key=0x%08x,"
" stag_key=0x%08x\n",
@@ -2613,25 +2613,28 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
nespbl->pbl_size, (unsigned long) nespbl->pbl_pbase,
(void *) nespbl->pbl_vbase, nespbl->user_base);
- list_for_each_entry(chunk, &region->chunk_list, list) {
- for (nmap_index = 0; nmap_index < chunk->nmap; ++nmap_index) {
- chunk_pages = sg_dma_len(&chunk->page_list[nmap_index]) >> 12;
- chunk_pages += (sg_dma_len(&chunk->page_list[nmap_index]) & (4096-1)) ? 1 : 0;
- nespbl->page = sg_page(&chunk->page_list[0]);
- for (page_index=0; page_index<chunk_pages; page_index++) {
- ((__le32 *)pbl)[0] = cpu_to_le32((u32)
- (sg_dma_address(&chunk->page_list[nmap_index])+
- (page_index*4096)));
- ((__le32 *)pbl)[1] = cpu_to_le32(((u64)
- (sg_dma_address(&chunk->page_list[nmap_index])+
- (page_index*4096)))>>32);
- nes_debug(NES_DBG_MR, "pbl=%p, *pbl=0x%016llx, 0x%08x%08x\n", pbl,
- (unsigned long long)*pbl,
- le32_to_cpu(((__le32 *)pbl)[1]), le32_to_cpu(((__le32 *)pbl)[0]));
- pbl++;
- }
+ for_each_sg(region->sg_head.sgl, sg, region->nmap, entry) {
+ chunk_pages = sg_dma_len(sg) >> 12;
+ chunk_pages += (sg_dma_len(sg) & (4096-1)) ? 1 : 0;
+ if (first_page) {
+ nespbl->page = sg_page(sg);
+ first_page = 0;
+ }
+
+ for (page_index = 0; page_index < chunk_pages; page_index++) {
+ ((__le32 *)pbl)[0] = cpu_to_le32((u32)
+ (sg_dma_address(sg)+
+ (page_index*4096)));
+ ((__le32 *)pbl)[1] = cpu_to_le32(((u64)
+ (sg_dma_address(sg)+
+ (page_index*4096)))>>32);
+ nes_debug(NES_DBG_MR, "pbl=%p, *pbl=0x%016llx, 0x%08x%08x\n", pbl,
+ (unsigned long long)*pbl,
+ le32_to_cpu(((__le32 *)pbl)[1]), le32_to_cpu(((__le32 *)pbl)[0]));
+ pbl++;
}
}
+
if (req.reg_type == IWNES_MEMREG_TYPE_QP) {
list_add_tail(&nespbl->list, &nes_ucontext->qp_reg_mem_list);
} else {
@@ -3134,9 +3137,7 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
" original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
original_last_aeq, nesqp->last_aeq);
- if ((!ret) ||
- ((original_last_aeq != NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) &&
- (ret))) {
+ if (!ret || original_last_aeq != NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) {
if (dont_wait) {
if (nesqp->cm_id && nesqp->hw_tcp_state != 0) {
nes_debug(NES_DBG_MOD_QP, "QP%u Queuing fake disconnect for QP refcount (%d),"
diff --git a/drivers/infiniband/hw/nes/nes_verbs.h b/drivers/infiniband/hw/nes/nes_verbs.h
index 0eff7c44d76b..309b31c31ae1 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.h
+++ b/drivers/infiniband/hw/nes/nes_verbs.h
@@ -184,5 +184,6 @@ struct nes_qp {
u8 pau_busy;
u8 pau_pending;
u8 pau_state;
+ __u64 nesuqp_addr;
};
#endif /* NES_VERBS_H */
diff --git a/drivers/infiniband/hw/ocrdma/Makefile b/drivers/infiniband/hw/ocrdma/Makefile
index 06a5bed12e43..d1bfd4f4cdde 100644
--- a/drivers/infiniband/hw/ocrdma/Makefile
+++ b/drivers/infiniband/hw/ocrdma/Makefile
@@ -2,4 +2,4 @@ ccflags-y := -Idrivers/net/ethernet/emulex/benet
obj-$(CONFIG_INFINIBAND_OCRDMA) += ocrdma.o
-ocrdma-y := ocrdma_main.o ocrdma_verbs.o ocrdma_hw.o ocrdma_ah.o
+ocrdma-y := ocrdma_main.o ocrdma_verbs.o ocrdma_hw.o ocrdma_ah.o ocrdma_stats.o
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma.h b/drivers/infiniband/hw/ocrdma/ocrdma.h
index 7c001b97b23f..19011dbb930f 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma.h
@@ -35,17 +35,27 @@
#include <rdma/ib_verbs.h>
#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_addr.h>
#include <be_roce.h>
#include "ocrdma_sli.h"
-#define OCRDMA_ROCE_DEV_VERSION "1.0.0"
+#define OCRDMA_ROCE_DRV_VERSION "10.2.145.0u"
+
+#define OCRDMA_ROCE_DRV_DESC "Emulex OneConnect RoCE Driver"
#define OCRDMA_NODE_DESC "Emulex OneConnect RoCE HCA"
+#define OC_NAME_SH OCRDMA_NODE_DESC "(Skyhawk)"
+#define OC_NAME_UNKNOWN OCRDMA_NODE_DESC "(Unknown)"
+
+#define OC_SKH_DEVICE_PF 0x720
+#define OC_SKH_DEVICE_VF 0x728
#define OCRDMA_MAX_AH 512
#define OCRDMA_UVERBS(CMD_NAME) (1ull << IB_USER_VERBS_CMD_##CMD_NAME)
+#define convert_to_64bit(lo, hi) ((u64)hi << 32 | (u64)lo)
+
struct ocrdma_dev_attr {
u8 fw_ver[32];
u32 vendor_id;
@@ -65,6 +75,7 @@ struct ocrdma_dev_attr {
int max_mr;
u64 max_mr_size;
u32 max_num_mr_pbl;
+ int max_mw;
int max_fmr;
int max_map_per_fmr;
int max_pages_per_frmr;
@@ -83,6 +94,12 @@ struct ocrdma_dev_attr {
u8 num_ird_pages;
};
+struct ocrdma_dma_mem {
+ void *va;
+ dma_addr_t pa;
+ u32 size;
+};
+
struct ocrdma_pbl {
void *va;
dma_addr_t pa;
@@ -148,6 +165,26 @@ struct ocrdma_mr {
struct ocrdma_hw_mr hwmr;
};
+struct ocrdma_stats {
+ u8 type;
+ struct ocrdma_dev *dev;
+};
+
+struct stats_mem {
+ struct ocrdma_mqe mqe;
+ void *va;
+ dma_addr_t pa;
+ u32 size;
+ char *debugfs_mem;
+};
+
+struct phy_info {
+ u16 auto_speeds_supported;
+ u16 fixed_speeds_supported;
+ u16 phy_type;
+ u16 interface_type;
+};
+
struct ocrdma_dev {
struct ib_device ibdev;
struct ocrdma_dev_attr attr;
@@ -191,12 +228,30 @@ struct ocrdma_dev {
struct mqe_ctx mqe_ctx;
struct be_dev_info nic_info;
+ struct phy_info phy;
+ char model_number[32];
+ u32 hba_port_num;
struct list_head entry;
struct rcu_head rcu;
int id;
- struct ocrdma_mr *stag_arr[OCRDMA_MAX_STAG];
+ u64 stag_arr[OCRDMA_MAX_STAG];
u16 pvid;
+ u32 asic_id;
+
+ ulong last_stats_time;
+ struct mutex stats_lock; /* provide synch for debugfs operations */
+ struct stats_mem stats_mem;
+ struct ocrdma_stats rsrc_stats;
+ struct ocrdma_stats rx_stats;
+ struct ocrdma_stats wqe_stats;
+ struct ocrdma_stats tx_stats;
+ struct ocrdma_stats db_err_stats;
+ struct ocrdma_stats tx_qp_err_stats;
+ struct ocrdma_stats rx_qp_err_stats;
+ struct ocrdma_stats tx_dbg_stats;
+ struct ocrdma_stats rx_dbg_stats;
+ struct dentry *dir;
};
struct ocrdma_cq {
@@ -209,8 +264,8 @@ struct ocrdma_cq {
*/
u32 max_hw_cqe;
bool phase_change;
- bool armed, solicited;
- bool arm_needed;
+ bool deferred_arm, deferred_sol;
+ bool first_arm;
spinlock_t cq_lock ____cacheline_aligned; /* provide synchronization
* to cq polling
@@ -223,6 +278,7 @@ struct ocrdma_cq {
struct ocrdma_ucontext *ucontext;
dma_addr_t pa;
u32 len;
+ u32 cqe_cnt;
/* head of all qp's sq and rq for which cqes need to be flushed
* by the software.
@@ -232,7 +288,6 @@ struct ocrdma_cq {
struct ocrdma_pd {
struct ib_pd ibpd;
- struct ocrdma_dev *dev;
struct ocrdma_ucontext *uctx;
u32 id;
int num_dpp_qp;
@@ -317,10 +372,8 @@ struct ocrdma_qp {
bool dpp_enabled;
u8 *ird_q_va;
bool signaled;
- u16 db_cache;
};
-
struct ocrdma_ucontext {
struct ib_ucontext ibucontext;
@@ -385,13 +438,6 @@ static inline struct ocrdma_srq *get_ocrdma_srq(struct ib_srq *ibsrq)
return container_of(ibsrq, struct ocrdma_srq, ibsrq);
}
-
-static inline int ocrdma_get_num_posted_shift(struct ocrdma_qp *qp)
-{
- return ((qp->dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY &&
- qp->id < 128) ? 24 : 16);
-}
-
static inline int is_cqe_valid(struct ocrdma_cq *cq, struct ocrdma_cqe *cqe)
{
int cqe_valid;
@@ -436,4 +482,40 @@ static inline int ocrdma_resolve_dmac(struct ocrdma_dev *dev,
return 0;
}
+static inline char *hca_name(struct ocrdma_dev *dev)
+{
+ switch (dev->nic_info.pdev->device) {
+ case OC_SKH_DEVICE_PF:
+ case OC_SKH_DEVICE_VF:
+ return OC_NAME_SH;
+ default:
+ return OC_NAME_UNKNOWN;
+ }
+}
+
+static inline int ocrdma_get_eq_table_index(struct ocrdma_dev *dev,
+ int eqid)
+{
+ int indx;
+
+ for (indx = 0; indx < dev->eq_cnt; indx++) {
+ if (dev->eq_tbl[indx].q.id == eqid)
+ return indx;
+ }
+
+ return -EINVAL;
+}
+
+static inline u8 ocrdma_get_asic_type(struct ocrdma_dev *dev)
+{
+ if (dev->nic_info.dev_family == 0xF && !dev->asic_id) {
+ pci_read_config_dword(
+ dev->nic_info.pdev,
+ OCRDMA_SLI_ASIC_ID_OFFSET, &dev->asic_id);
+ }
+
+ return (dev->asic_id & OCRDMA_SLI_ASIC_GEN_NUM_MASK) >>
+ OCRDMA_SLI_ASIC_GEN_NUM_SHIFT;
+}
+
#endif
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_abi.h b/drivers/infiniband/hw/ocrdma/ocrdma_abi.h
index fbac8eb44036..1554cca5712a 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_abi.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_abi.h
@@ -28,7 +28,8 @@
#ifndef __OCRDMA_ABI_H__
#define __OCRDMA_ABI_H__
-#define OCRDMA_ABI_VERSION 1
+#define OCRDMA_ABI_VERSION 2
+#define OCRDMA_BE_ROCE_ABI_VERSION 1
/* user kernel communication data structures. */
struct ocrdma_alloc_ucontext_resp {
@@ -107,9 +108,7 @@ struct ocrdma_create_qp_uresp {
u32 db_sq_offset;
u32 db_rq_offset;
u32 db_shift;
- u64 rsvd1;
- u64 rsvd2;
- u64 rsvd3;
+ u64 rsvd[11];
} __packed;
struct ocrdma_create_srq_uresp {
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_ah.c b/drivers/infiniband/hw/ocrdma/ocrdma_ah.c
index 34071143006e..d4cc01f10c01 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_ah.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_ah.c
@@ -100,7 +100,7 @@ struct ib_ah *ocrdma_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr)
if (!(attr->ah_flags & IB_AH_GRH))
return ERR_PTR(-EINVAL);
- ah = kzalloc(sizeof *ah, GFP_ATOMIC);
+ ah = kzalloc(sizeof(*ah), GFP_ATOMIC);
if (!ah)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
index 1664d648cbfc..3bbf2010a821 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
@@ -32,7 +32,6 @@
#include <rdma/ib_verbs.h>
#include <rdma/ib_user_verbs.h>
-#include <rdma/ib_addr.h>
#include "ocrdma.h"
#include "ocrdma_hw.h"
@@ -243,6 +242,23 @@ static int ocrdma_get_mbx_errno(u32 status)
return err_num;
}
+char *port_speed_string(struct ocrdma_dev *dev)
+{
+ char *str = "";
+ u16 speeds_supported;
+
+ speeds_supported = dev->phy.fixed_speeds_supported |
+ dev->phy.auto_speeds_supported;
+ if (speeds_supported & OCRDMA_PHY_SPEED_40GBPS)
+ str = "40Gbps ";
+ else if (speeds_supported & OCRDMA_PHY_SPEED_10GBPS)
+ str = "10Gbps ";
+ else if (speeds_supported & OCRDMA_PHY_SPEED_1GBPS)
+ str = "1Gbps ";
+
+ return str;
+}
+
static int ocrdma_get_mbx_cqe_errno(u16 cqe_status)
{
int err_num = -EINVAL;
@@ -332,6 +348,11 @@ static void *ocrdma_init_emb_mqe(u8 opcode, u32 cmd_len)
return mqe;
}
+static void *ocrdma_alloc_mqe(void)
+{
+ return kzalloc(sizeof(struct ocrdma_mqe), GFP_KERNEL);
+}
+
static void ocrdma_free_q(struct ocrdma_dev *dev, struct ocrdma_queue_info *q)
{
dma_free_coherent(&dev->nic_info.pdev->dev, q->size, q->va, q->dma);
@@ -364,8 +385,8 @@ static void ocrdma_build_q_pages(struct ocrdma_pa *q_pa, int cnt,
}
}
-static int ocrdma_mbx_delete_q(struct ocrdma_dev *dev, struct ocrdma_queue_info *q,
- int queue_type)
+static int ocrdma_mbx_delete_q(struct ocrdma_dev *dev,
+ struct ocrdma_queue_info *q, int queue_type)
{
u8 opcode = 0;
int status;
@@ -444,7 +465,7 @@ mbx_err:
return status;
}
-static int ocrdma_get_irq(struct ocrdma_dev *dev, struct ocrdma_eq *eq)
+int ocrdma_get_irq(struct ocrdma_dev *dev, struct ocrdma_eq *eq)
{
int irq;
@@ -574,6 +595,7 @@ static int ocrdma_create_mq(struct ocrdma_dev *dev)
if (status)
goto alloc_err;
+ dev->eq_tbl[0].cq_cnt++;
status = ocrdma_mbx_mq_cq_create(dev, &dev->mq.cq, &dev->eq_tbl[0].q);
if (status)
goto mbx_cq_free;
@@ -639,7 +661,7 @@ static void ocrdma_dispatch_ibevent(struct ocrdma_dev *dev,
{
struct ocrdma_qp *qp = NULL;
struct ocrdma_cq *cq = NULL;
- struct ib_event ib_evt;
+ struct ib_event ib_evt = { 0 };
int cq_event = 0;
int qp_event = 1;
int srq_event = 0;
@@ -664,6 +686,8 @@ static void ocrdma_dispatch_ibevent(struct ocrdma_dev *dev,
case OCRDMA_CQ_OVERRUN_ERROR:
ib_evt.element.cq = &cq->ibcq;
ib_evt.event = IB_EVENT_CQ_ERR;
+ cq_event = 1;
+ qp_event = 0;
break;
case OCRDMA_CQ_QPCAT_ERROR:
ib_evt.element.qp = &qp->ibqp;
@@ -725,6 +749,7 @@ static void ocrdma_dispatch_ibevent(struct ocrdma_dev *dev,
qp->srq->ibsrq.
srq_context);
} else if (dev_event) {
+ pr_err("%s: Fatal event received\n", dev->ibdev.name);
ib_dispatch_event(&ib_evt);
}
@@ -752,7 +777,6 @@ static void ocrdma_process_grp5_aync(struct ocrdma_dev *dev,
}
}
-
static void ocrdma_process_acqe(struct ocrdma_dev *dev, void *ae_cqe)
{
/* async CQE processing */
@@ -799,8 +823,6 @@ static int ocrdma_mq_cq_handler(struct ocrdma_dev *dev, u16 cq_id)
ocrdma_process_acqe(dev, cqe);
else if (cqe->valid_ae_cmpl_cons & OCRDMA_MCQE_CMPL_MASK)
ocrdma_process_mcqe(dev, cqe);
- else
- pr_err("%s() cqe->compl is not set.\n", __func__);
memset(cqe, 0, sizeof(struct ocrdma_mcqe));
ocrdma_mcq_inc_tail(dev);
}
@@ -858,16 +880,8 @@ static void ocrdma_qp_cq_handler(struct ocrdma_dev *dev, u16 cq_idx)
BUG();
cq = dev->cq_tbl[cq_idx];
- if (cq == NULL) {
- pr_err("%s%d invalid id=0x%x\n", __func__, dev->id, cq_idx);
+ if (cq == NULL)
return;
- }
- spin_lock_irqsave(&cq->cq_lock, flags);
- cq->armed = false;
- cq->solicited = false;
- spin_unlock_irqrestore(&cq->cq_lock, flags);
-
- ocrdma_ring_cq_db(dev, cq->id, false, false, 0);
if (cq->ibcq.comp_handler) {
spin_lock_irqsave(&cq->comp_handler_lock, flags);
@@ -892,27 +906,35 @@ static irqreturn_t ocrdma_irq_handler(int irq, void *handle)
struct ocrdma_dev *dev = eq->dev;
struct ocrdma_eqe eqe;
struct ocrdma_eqe *ptr;
- u16 eqe_popped = 0;
u16 cq_id;
- while (1) {
+ int budget = eq->cq_cnt;
+
+ do {
ptr = ocrdma_get_eqe(eq);
eqe = *ptr;
ocrdma_le32_to_cpu(&eqe, sizeof(eqe));
if ((eqe.id_valid & OCRDMA_EQE_VALID_MASK) == 0)
break;
- eqe_popped += 1;
+
ptr->id_valid = 0;
+ /* ring eq doorbell as soon as its consumed. */
+ ocrdma_ring_eq_db(dev, eq->q.id, false, true, 1);
/* check whether its CQE or not. */
if ((eqe.id_valid & OCRDMA_EQE_FOR_CQE_MASK) == 0) {
cq_id = eqe.id_valid >> OCRDMA_EQE_RESOURCE_ID_SHIFT;
ocrdma_cq_handler(dev, cq_id);
}
ocrdma_eq_inc_tail(eq);
- }
- ocrdma_ring_eq_db(dev, eq->q.id, true, true, eqe_popped);
- /* Ring EQ doorbell with num_popped to 0 to enable interrupts again. */
- if (dev->nic_info.intr_mode == BE_INTERRUPT_MODE_INTX)
- ocrdma_ring_eq_db(dev, eq->q.id, true, true, 0);
+
+ /* There can be a stale EQE after the last bound CQ is
+ * destroyed. EQE valid and budget == 0 implies this.
+ */
+ if (budget)
+ budget--;
+
+ } while (budget);
+
+ ocrdma_ring_eq_db(dev, eq->q.id, true, true, 0);
return IRQ_HANDLED;
}
@@ -949,7 +971,8 @@ static int ocrdma_mbx_cmd(struct ocrdma_dev *dev, struct ocrdma_mqe *mqe)
{
int status = 0;
u16 cqe_status, ext_status;
- struct ocrdma_mqe *rsp;
+ struct ocrdma_mqe *rsp_mqe;
+ struct ocrdma_mbx_rsp *rsp = NULL;
mutex_lock(&dev->mqe_ctx.lock);
ocrdma_post_mqe(dev, mqe);
@@ -958,23 +981,61 @@ static int ocrdma_mbx_cmd(struct ocrdma_dev *dev, struct ocrdma_mqe *mqe)
goto mbx_err;
cqe_status = dev->mqe_ctx.cqe_status;
ext_status = dev->mqe_ctx.ext_status;
- rsp = ocrdma_get_mqe_rsp(dev);
- ocrdma_copy_le32_to_cpu(mqe, rsp, (sizeof(*mqe)));
+ rsp_mqe = ocrdma_get_mqe_rsp(dev);
+ ocrdma_copy_le32_to_cpu(mqe, rsp_mqe, (sizeof(*mqe)));
+ if ((mqe->hdr.spcl_sge_cnt_emb & OCRDMA_MQE_HDR_EMB_MASK) >>
+ OCRDMA_MQE_HDR_EMB_SHIFT)
+ rsp = &mqe->u.rsp;
+
if (cqe_status || ext_status) {
- pr_err("%s() opcode=0x%x, cqe_status=0x%x, ext_status=0x%x\n",
- __func__,
- (rsp->u.rsp.subsys_op & OCRDMA_MBX_RSP_OPCODE_MASK) >>
- OCRDMA_MBX_RSP_OPCODE_SHIFT, cqe_status, ext_status);
+ pr_err("%s() cqe_status=0x%x, ext_status=0x%x,",
+ __func__, cqe_status, ext_status);
+ if (rsp) {
+ /* This is for embedded cmds. */
+ pr_err("opcode=0x%x, subsystem=0x%x\n",
+ (rsp->subsys_op & OCRDMA_MBX_RSP_OPCODE_MASK) >>
+ OCRDMA_MBX_RSP_OPCODE_SHIFT,
+ (rsp->subsys_op & OCRDMA_MBX_RSP_SUBSYS_MASK) >>
+ OCRDMA_MBX_RSP_SUBSYS_SHIFT);
+ }
status = ocrdma_get_mbx_cqe_errno(cqe_status);
goto mbx_err;
}
- if (mqe->u.rsp.status & OCRDMA_MBX_RSP_STATUS_MASK)
+ /* For non embedded, rsp errors are handled in ocrdma_nonemb_mbx_cmd */
+ if (rsp && (mqe->u.rsp.status & OCRDMA_MBX_RSP_STATUS_MASK))
status = ocrdma_get_mbx_errno(mqe->u.rsp.status);
mbx_err:
mutex_unlock(&dev->mqe_ctx.lock);
return status;
}
+static int ocrdma_nonemb_mbx_cmd(struct ocrdma_dev *dev, struct ocrdma_mqe *mqe,
+ void *payload_va)
+{
+ int status = 0;
+ struct ocrdma_mbx_rsp *rsp = payload_va;
+
+ if ((mqe->hdr.spcl_sge_cnt_emb & OCRDMA_MQE_HDR_EMB_MASK) >>
+ OCRDMA_MQE_HDR_EMB_SHIFT)
+ BUG();
+
+ status = ocrdma_mbx_cmd(dev, mqe);
+ if (!status)
+ /* For non embedded, only CQE failures are handled in
+ * ocrdma_mbx_cmd. We need to check for RSP errors.
+ */
+ if (rsp->status & OCRDMA_MBX_RSP_STATUS_MASK)
+ status = ocrdma_get_mbx_errno(rsp->status);
+
+ if (status)
+ pr_err("opcode=0x%x, subsystem=0x%x\n",
+ (rsp->subsys_op & OCRDMA_MBX_RSP_OPCODE_MASK) >>
+ OCRDMA_MBX_RSP_OPCODE_SHIFT,
+ (rsp->subsys_op & OCRDMA_MBX_RSP_SUBSYS_MASK) >>
+ OCRDMA_MBX_RSP_SUBSYS_SHIFT);
+ return status;
+}
+
static void ocrdma_get_attr(struct ocrdma_dev *dev,
struct ocrdma_dev_attr *attr,
struct ocrdma_mbx_query_config *rsp)
@@ -985,6 +1046,9 @@ static void ocrdma_get_attr(struct ocrdma_dev *dev,
attr->max_qp =
(rsp->qp_srq_cq_ird_ord & OCRDMA_MBX_QUERY_CFG_MAX_QP_MASK) >>
OCRDMA_MBX_QUERY_CFG_MAX_QP_SHIFT;
+ attr->max_srq =
+ (rsp->max_srq_rpir_qps & OCRDMA_MBX_QUERY_CFG_MAX_SRQ_MASK) >>
+ OCRDMA_MBX_QUERY_CFG_MAX_SRQ_OFFSET;
attr->max_send_sge = ((rsp->max_write_send_sge &
OCRDMA_MBX_QUERY_CFG_MAX_SEND_SGE_MASK) >>
OCRDMA_MBX_QUERY_CFG_MAX_SEND_SGE_SHIFT);
@@ -1000,9 +1064,6 @@ static void ocrdma_get_attr(struct ocrdma_dev *dev,
attr->max_ord_per_qp = (rsp->max_ird_ord_per_qp &
OCRDMA_MBX_QUERY_CFG_MAX_ORD_PER_QP_MASK) >>
OCRDMA_MBX_QUERY_CFG_MAX_ORD_PER_QP_SHIFT;
- attr->max_srq =
- (rsp->max_srq_rpir_qps & OCRDMA_MBX_QUERY_CFG_MAX_SRQ_MASK) >>
- OCRDMA_MBX_QUERY_CFG_MAX_SRQ_OFFSET;
attr->max_ird_per_qp = (rsp->max_ird_ord_per_qp &
OCRDMA_MBX_QUERY_CFG_MAX_IRD_PER_QP_MASK) >>
OCRDMA_MBX_QUERY_CFG_MAX_IRD_PER_QP_SHIFT;
@@ -1015,6 +1076,7 @@ static void ocrdma_get_attr(struct ocrdma_dev *dev,
attr->local_ca_ack_delay = (rsp->max_pd_ca_ack_delay &
OCRDMA_MBX_QUERY_CFG_CA_ACK_DELAY_MASK) >>
OCRDMA_MBX_QUERY_CFG_CA_ACK_DELAY_SHIFT;
+ attr->max_mw = rsp->max_mw;
attr->max_mr = rsp->max_mr;
attr->max_mr_size = ~0ull;
attr->max_fmr = 0;
@@ -1036,7 +1098,7 @@ static void ocrdma_get_attr(struct ocrdma_dev *dev,
attr->max_inline_data =
attr->wqe_size - (sizeof(struct ocrdma_hdr_wqe) +
sizeof(struct ocrdma_sge));
- if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {
+ if (ocrdma_get_asic_type(dev) == OCRDMA_ASIC_GEN_SKH_R) {
attr->ird = 1;
attr->ird_page_size = OCRDMA_MIN_Q_PAGE_SIZE;
attr->num_ird_pages = MAX_OCRDMA_IRD_PAGES;
@@ -1110,6 +1172,96 @@ mbx_err:
return status;
}
+int ocrdma_mbx_rdma_stats(struct ocrdma_dev *dev, bool reset)
+{
+ struct ocrdma_rdma_stats_req *req = dev->stats_mem.va;
+ struct ocrdma_mqe *mqe = &dev->stats_mem.mqe;
+ struct ocrdma_rdma_stats_resp *old_stats = NULL;
+ int status;
+
+ old_stats = kzalloc(sizeof(*old_stats), GFP_KERNEL);
+ if (old_stats == NULL)
+ return -ENOMEM;
+
+ memset(mqe, 0, sizeof(*mqe));
+ mqe->hdr.pyld_len = dev->stats_mem.size;
+ mqe->hdr.spcl_sge_cnt_emb |=
+ (1 << OCRDMA_MQE_HDR_SGE_CNT_SHIFT) &
+ OCRDMA_MQE_HDR_SGE_CNT_MASK;
+ mqe->u.nonemb_req.sge[0].pa_lo = (u32) (dev->stats_mem.pa & 0xffffffff);
+ mqe->u.nonemb_req.sge[0].pa_hi = (u32) upper_32_bits(dev->stats_mem.pa);
+ mqe->u.nonemb_req.sge[0].len = dev->stats_mem.size;
+
+ /* Cache the old stats */
+ memcpy(old_stats, req, sizeof(struct ocrdma_rdma_stats_resp));
+ memset(req, 0, dev->stats_mem.size);
+
+ ocrdma_init_mch((struct ocrdma_mbx_hdr *)req,
+ OCRDMA_CMD_GET_RDMA_STATS,
+ OCRDMA_SUBSYS_ROCE,
+ dev->stats_mem.size);
+ if (reset)
+ req->reset_stats = reset;
+
+ status = ocrdma_nonemb_mbx_cmd(dev, mqe, dev->stats_mem.va);
+ if (status)
+ /* Copy from cache, if mbox fails */
+ memcpy(req, old_stats, sizeof(struct ocrdma_rdma_stats_resp));
+ else
+ ocrdma_le32_to_cpu(req, dev->stats_mem.size);
+
+ kfree(old_stats);
+ return status;
+}
+
+static int ocrdma_mbx_get_ctrl_attribs(struct ocrdma_dev *dev)
+{
+ int status = -ENOMEM;
+ struct ocrdma_dma_mem dma;
+ struct ocrdma_mqe *mqe;
+ struct ocrdma_get_ctrl_attribs_rsp *ctrl_attr_rsp;
+ struct mgmt_hba_attribs *hba_attribs;
+
+ mqe = ocrdma_alloc_mqe();
+ if (!mqe)
+ return status;
+ memset(mqe, 0, sizeof(*mqe));
+
+ dma.size = sizeof(struct ocrdma_get_ctrl_attribs_rsp);
+ dma.va = dma_alloc_coherent(&dev->nic_info.pdev->dev,
+ dma.size, &dma.pa, GFP_KERNEL);
+ if (!dma.va)
+ goto free_mqe;
+
+ mqe->hdr.pyld_len = dma.size;
+ mqe->hdr.spcl_sge_cnt_emb |=
+ (1 << OCRDMA_MQE_HDR_SGE_CNT_SHIFT) &
+ OCRDMA_MQE_HDR_SGE_CNT_MASK;
+ mqe->u.nonemb_req.sge[0].pa_lo = (u32) (dma.pa & 0xffffffff);
+ mqe->u.nonemb_req.sge[0].pa_hi = (u32) upper_32_bits(dma.pa);
+ mqe->u.nonemb_req.sge[0].len = dma.size;
+
+ memset(dma.va, 0, dma.size);
+ ocrdma_init_mch((struct ocrdma_mbx_hdr *)dma.va,
+ OCRDMA_CMD_GET_CTRL_ATTRIBUTES,
+ OCRDMA_SUBSYS_COMMON,
+ dma.size);
+
+ status = ocrdma_nonemb_mbx_cmd(dev, mqe, dma.va);
+ if (!status) {
+ ctrl_attr_rsp = (struct ocrdma_get_ctrl_attribs_rsp *)dma.va;
+ hba_attribs = &ctrl_attr_rsp->ctrl_attribs.hba_attribs;
+
+ dev->hba_port_num = hba_attribs->phy_port;
+ strncpy(dev->model_number,
+ hba_attribs->controller_model_number, 31);
+ }
+ dma_free_coherent(&dev->nic_info.pdev->dev, dma.size, dma.va, dma.pa);
+free_mqe:
+ kfree(mqe);
+ return status;
+}
+
static int ocrdma_mbx_query_dev(struct ocrdma_dev *dev)
{
int status = -ENOMEM;
@@ -1157,6 +1309,35 @@ mbx_err:
return status;
}
+static int ocrdma_mbx_get_phy_info(struct ocrdma_dev *dev)
+{
+ int status = -ENOMEM;
+ struct ocrdma_mqe *cmd;
+ struct ocrdma_get_phy_info_rsp *rsp;
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_PHY_DETAILS, sizeof(*cmd));
+ if (!cmd)
+ return status;
+
+ ocrdma_init_mch((struct ocrdma_mbx_hdr *)&cmd->u.cmd[0],
+ OCRDMA_CMD_PHY_DETAILS, OCRDMA_SUBSYS_COMMON,
+ sizeof(*cmd));
+
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+
+ rsp = (struct ocrdma_get_phy_info_rsp *)cmd;
+ dev->phy.phy_type = le16_to_cpu(rsp->phy_type);
+ dev->phy.auto_speeds_supported =
+ le16_to_cpu(rsp->auto_speeds_supported);
+ dev->phy.fixed_speeds_supported =
+ le16_to_cpu(rsp->fixed_speeds_supported);
+mbx_err:
+ kfree(cmd);
+ return status;
+}
+
int ocrdma_mbx_alloc_pd(struct ocrdma_dev *dev, struct ocrdma_pd *pd)
{
int status = -ENOMEM;
@@ -1226,7 +1407,7 @@ static int ocrdma_build_q_conf(u32 *num_entries, int entry_size,
static int ocrdma_mbx_create_ah_tbl(struct ocrdma_dev *dev)
{
- int i ;
+ int i;
int status = 0;
int max_ah;
struct ocrdma_create_ah_tbl *cmd;
@@ -1357,12 +1538,10 @@ static void ocrdma_unbind_eq(struct ocrdma_dev *dev, u16 eq_id)
int i;
mutex_lock(&dev->dev_lock);
- for (i = 0; i < dev->eq_cnt; i++) {
- if (dev->eq_tbl[i].q.id != eq_id)
- continue;
- dev->eq_tbl[i].cq_cnt -= 1;
- break;
- }
+ i = ocrdma_get_eq_table_index(dev, eq_id);
+ if (i == -EINVAL)
+ BUG();
+ dev->eq_tbl[i].cq_cnt -= 1;
mutex_unlock(&dev->dev_lock);
}
@@ -1380,7 +1559,7 @@ int ocrdma_mbx_create_cq(struct ocrdma_dev *dev, struct ocrdma_cq *cq,
__func__, dev->id, dev->attr.max_cqe, entries);
return -EINVAL;
}
- if (dpp_cq && (dev->nic_info.dev_family != OCRDMA_GEN2_FAMILY))
+ if (dpp_cq && (ocrdma_get_asic_type(dev) != OCRDMA_ASIC_GEN_SKH_R))
return -EINVAL;
if (dpp_cq) {
@@ -1417,6 +1596,7 @@ int ocrdma_mbx_create_cq(struct ocrdma_dev *dev, struct ocrdma_cq *cq,
cq->eqn = ocrdma_bind_eq(dev);
cmd->cmd.req.rsvd_version = OCRDMA_CREATE_CQ_VER3;
cqe_count = cq->len / cqe_size;
+ cq->cqe_cnt = cqe_count;
if (cqe_count > 1024) {
/* Set cnt to 3 to indicate more than 1024 cq entries */
cmd->cmd.ev_cnt_flags |= (0x3 << OCRDMA_CREATE_CQ_CNT_SHIFT);
@@ -1439,7 +1619,7 @@ int ocrdma_mbx_create_cq(struct ocrdma_dev *dev, struct ocrdma_cq *cq,
}
/* shared eq between all the consumer cqs. */
cmd->cmd.eqn = cq->eqn;
- if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {
+ if (ocrdma_get_asic_type(dev) == OCRDMA_ASIC_GEN_SKH_R) {
if (dpp_cq)
cmd->cmd.pgsz_pgcnt |= OCRDMA_CREATE_CQ_DPP <<
OCRDMA_CREATE_CQ_TYPE_SHIFT;
@@ -1484,12 +1664,9 @@ int ocrdma_mbx_destroy_cq(struct ocrdma_dev *dev, struct ocrdma_cq *cq)
(cq->id << OCRDMA_DESTROY_CQ_QID_SHIFT) &
OCRDMA_DESTROY_CQ_QID_MASK;
- ocrdma_unbind_eq(dev, cq->eqn);
status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
- if (status)
- goto mbx_err;
+ ocrdma_unbind_eq(dev, cq->eqn);
dma_free_coherent(&dev->nic_info.pdev->dev, cq->len, cq->va, cq->pa);
-mbx_err:
kfree(cmd);
return status;
}
@@ -2029,8 +2206,7 @@ int ocrdma_mbx_create_qp(struct ocrdma_qp *qp, struct ib_qp_init_attr *attrs,
OCRDMA_CREATE_QP_REQ_RQ_CQID_MASK;
qp->rq_cq = cq;
- if (pd->dpp_enabled && attrs->cap.max_inline_data && pd->num_dpp_qp &&
- (attrs->cap.max_inline_data <= dev->attr.max_inline_data)) {
+ if (pd->dpp_enabled && pd->num_dpp_qp) {
ocrdma_set_create_qp_dpp_cmd(cmd, pd, qp, enable_dpp_cq,
dpp_cq_id);
}
@@ -2099,7 +2275,7 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
memcpy(&cmd->params.dgid[0], &ah_attr->grh.dgid.raw[0],
sizeof(cmd->params.dgid));
status = ocrdma_query_gid(&qp->dev->ibdev, 1,
- ah_attr->grh.sgid_index, &sgid);
+ ah_attr->grh.sgid_index, &sgid);
if (status)
return status;
@@ -2127,8 +2303,7 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
static int ocrdma_set_qp_params(struct ocrdma_qp *qp,
struct ocrdma_modify_qp *cmd,
- struct ib_qp_attr *attrs, int attr_mask,
- enum ib_qp_state old_qps)
+ struct ib_qp_attr *attrs, int attr_mask)
{
int status = 0;
@@ -2233,8 +2408,7 @@ pmtu_err:
}
int ocrdma_mbx_modify_qp(struct ocrdma_dev *dev, struct ocrdma_qp *qp,
- struct ib_qp_attr *attrs, int attr_mask,
- enum ib_qp_state old_qps)
+ struct ib_qp_attr *attrs, int attr_mask)
{
int status = -ENOMEM;
struct ocrdma_modify_qp *cmd;
@@ -2257,7 +2431,7 @@ int ocrdma_mbx_modify_qp(struct ocrdma_dev *dev, struct ocrdma_qp *qp,
OCRDMA_QP_PARAMS_STATE_MASK;
}
- status = ocrdma_set_qp_params(qp, cmd, attrs, attr_mask, old_qps);
+ status = ocrdma_set_qp_params(qp, cmd, attrs, attr_mask);
if (status)
goto mbx_err;
status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
@@ -2488,7 +2662,7 @@ static int ocrdma_create_eqs(struct ocrdma_dev *dev)
for (i = 0; i < num_eq; i++) {
status = ocrdma_create_eq(dev, &dev->eq_tbl[i],
- OCRDMA_EQ_LEN);
+ OCRDMA_EQ_LEN);
if (status) {
status = -EINVAL;
break;
@@ -2533,6 +2707,13 @@ int ocrdma_init_hw(struct ocrdma_dev *dev)
status = ocrdma_mbx_create_ah_tbl(dev);
if (status)
goto conf_err;
+ status = ocrdma_mbx_get_phy_info(dev);
+ if (status)
+ goto conf_err;
+ status = ocrdma_mbx_get_ctrl_attribs(dev);
+ if (status)
+ goto conf_err;
+
return 0;
conf_err:
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.h b/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
index 82fe332ae6c6..e513f7293142 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
@@ -112,8 +112,7 @@ int ocrdma_mbx_create_qp(struct ocrdma_qp *, struct ib_qp_init_attr *attrs,
u8 enable_dpp_cq, u16 dpp_cq_id, u16 *dpp_offset,
u16 *dpp_credit_lmt);
int ocrdma_mbx_modify_qp(struct ocrdma_dev *, struct ocrdma_qp *,
- struct ib_qp_attr *attrs, int attr_mask,
- enum ib_qp_state old_qps);
+ struct ib_qp_attr *attrs, int attr_mask);
int ocrdma_mbx_query_qp(struct ocrdma_dev *, struct ocrdma_qp *,
struct ocrdma_qp_params *param);
int ocrdma_mbx_destroy_qp(struct ocrdma_dev *, struct ocrdma_qp *);
@@ -132,5 +131,8 @@ int ocrdma_qp_state_change(struct ocrdma_qp *, enum ib_qp_state new_state,
bool ocrdma_is_qp_in_sq_flushlist(struct ocrdma_cq *, struct ocrdma_qp *);
bool ocrdma_is_qp_in_rq_flushlist(struct ocrdma_cq *, struct ocrdma_qp *);
void ocrdma_flush_qp(struct ocrdma_qp *);
+int ocrdma_get_irq(struct ocrdma_dev *dev, struct ocrdma_eq *eq);
+int ocrdma_mbx_rdma_stats(struct ocrdma_dev *, bool reset);
+char *port_speed_string(struct ocrdma_dev *dev);
#endif /* __OCRDMA_HW_H__ */
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
index 2ca86ca818bd..7c504e079744 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
@@ -39,10 +39,11 @@
#include "ocrdma_ah.h"
#include "be_roce.h"
#include "ocrdma_hw.h"
+#include "ocrdma_stats.h"
#include "ocrdma_abi.h"
-MODULE_VERSION(OCRDMA_ROCE_DEV_VERSION);
-MODULE_DESCRIPTION("Emulex RoCE HCA Driver");
+MODULE_VERSION(OCRDMA_ROCE_DRV_VERSION);
+MODULE_DESCRIPTION(OCRDMA_ROCE_DRV_DESC " " OCRDMA_ROCE_DRV_VERSION);
MODULE_AUTHOR("Emulex Corporation");
MODULE_LICENSE("GPL");
@@ -127,7 +128,7 @@ static int ocrdma_addr_event(unsigned long event, struct net_device *netdev,
is_vlan = netdev->priv_flags & IFF_802_1Q_VLAN;
if (is_vlan)
- netdev = vlan_dev_real_dev(netdev);
+ netdev = rdma_vlan_dev_real_dev(netdev);
rcu_read_lock();
list_for_each_entry_rcu(dev, &ocrdma_dev_list, entry) {
@@ -286,7 +287,7 @@ static int ocrdma_register_device(struct ocrdma_dev *dev)
dev->ibdev.process_mad = ocrdma_process_mad;
- if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {
+ if (ocrdma_get_asic_type(dev) == OCRDMA_ASIC_GEN_SKH_R) {
dev->ibdev.uverbs_cmd_mask |=
OCRDMA_UVERBS(CREATE_SRQ) |
OCRDMA_UVERBS(MODIFY_SRQ) |
@@ -338,9 +339,42 @@ static void ocrdma_free_resources(struct ocrdma_dev *dev)
kfree(dev->sgid_tbl);
}
+/* OCRDMA sysfs interface */
+static ssize_t show_rev(struct device *device, struct device_attribute *attr,
+ char *buf)
+{
+ struct ocrdma_dev *dev = dev_get_drvdata(device);
+
+ return scnprintf(buf, PAGE_SIZE, "0x%x\n", dev->nic_info.pdev->vendor);
+}
+
+static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr,
+ char *buf)
+{
+ struct ocrdma_dev *dev = dev_get_drvdata(device);
+
+ return scnprintf(buf, PAGE_SIZE, "%s", &dev->attr.fw_ver[0]);
+}
+
+static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
+static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
+
+static struct device_attribute *ocrdma_attributes[] = {
+ &dev_attr_hw_rev,
+ &dev_attr_fw_ver
+};
+
+static void ocrdma_remove_sysfiles(struct ocrdma_dev *dev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ocrdma_attributes); i++)
+ device_remove_file(&dev->ibdev.dev, ocrdma_attributes[i]);
+}
+
static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
{
- int status = 0;
+ int status = 0, i;
struct ocrdma_dev *dev;
dev = (struct ocrdma_dev *)ib_alloc_device(sizeof(struct ocrdma_dev));
@@ -369,11 +403,25 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
if (status)
goto alloc_err;
+ for (i = 0; i < ARRAY_SIZE(ocrdma_attributes); i++)
+ if (device_create_file(&dev->ibdev.dev, ocrdma_attributes[i]))
+ goto sysfs_err;
spin_lock(&ocrdma_devlist_lock);
list_add_tail_rcu(&dev->entry, &ocrdma_dev_list);
spin_unlock(&ocrdma_devlist_lock);
+ /* Init stats */
+ ocrdma_add_port_stats(dev);
+
+ pr_info("%s %s: %s \"%s\" port %d\n",
+ dev_name(&dev->nic_info.pdev->dev), hca_name(dev),
+ port_speed_string(dev), dev->model_number,
+ dev->hba_port_num);
+ pr_info("%s ocrdma%d driver loaded successfully\n",
+ dev_name(&dev->nic_info.pdev->dev), dev->id);
return dev;
+sysfs_err:
+ ocrdma_remove_sysfiles(dev);
alloc_err:
ocrdma_free_resources(dev);
ocrdma_cleanup_hw(dev);
@@ -400,6 +448,9 @@ static void ocrdma_remove(struct ocrdma_dev *dev)
/* first unregister with stack to stop all the active traffic
* of the registered clients.
*/
+ ocrdma_rem_port_stats(dev);
+ ocrdma_remove_sysfiles(dev);
+
ib_unregister_device(&dev->ibdev);
spin_lock(&ocrdma_devlist_lock);
@@ -437,7 +488,7 @@ static int ocrdma_close(struct ocrdma_dev *dev)
cur_qp = dev->qp_tbl;
for (i = 0; i < OCRDMA_MAX_QP; i++) {
qp = cur_qp[i];
- if (qp) {
+ if (qp && qp->ibqp.qp_type != IB_QPT_GSI) {
/* change the QP state to ERROR */
_ocrdma_modify_qp(&qp->ibqp, &attrs, attr_mask);
@@ -478,6 +529,7 @@ static struct ocrdma_driver ocrdma_drv = {
.add = ocrdma_add,
.remove = ocrdma_remove,
.state_change_handler = ocrdma_event_handler,
+ .be_abi_version = OCRDMA_BE_ROCE_ABI_VERSION,
};
static void ocrdma_unregister_inet6addr_notifier(void)
@@ -487,10 +539,17 @@ static void ocrdma_unregister_inet6addr_notifier(void)
#endif
}
+static void ocrdma_unregister_inetaddr_notifier(void)
+{
+ unregister_inetaddr_notifier(&ocrdma_inetaddr_notifier);
+}
+
static int __init ocrdma_init_module(void)
{
int status;
+ ocrdma_init_debugfs();
+
status = register_inetaddr_notifier(&ocrdma_inetaddr_notifier);
if (status)
return status;
@@ -498,13 +557,19 @@ static int __init ocrdma_init_module(void)
#if IS_ENABLED(CONFIG_IPV6)
status = register_inet6addr_notifier(&ocrdma_inet6addr_notifier);
if (status)
- return status;
+ goto err_notifier6;
#endif
status = be_roce_register_driver(&ocrdma_drv);
if (status)
- ocrdma_unregister_inet6addr_notifier();
+ goto err_be_reg;
+ return 0;
+
+err_be_reg:
+ ocrdma_unregister_inet6addr_notifier();
+err_notifier6:
+ ocrdma_unregister_inetaddr_notifier();
return status;
}
@@ -512,6 +577,8 @@ static void __exit ocrdma_exit_module(void)
{
be_roce_unregister_driver(&ocrdma_drv);
ocrdma_unregister_inet6addr_notifier();
+ ocrdma_unregister_inetaddr_notifier();
+ ocrdma_rem_debugfs();
}
module_init(ocrdma_init_module);
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_sli.h b/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
index 60d5ac23ea80..96c9ee602ba4 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
@@ -30,8 +30,16 @@
#define Bit(_b) (1 << (_b))
-#define OCRDMA_GEN1_FAMILY 0xB
-#define OCRDMA_GEN2_FAMILY 0x0F
+enum {
+ OCRDMA_ASIC_GEN_SKH_R = 0x04,
+ OCRDMA_ASIC_GEN_LANCER = 0x0B
+};
+
+enum {
+ OCRDMA_ASIC_REV_A0 = 0x00,
+ OCRDMA_ASIC_REV_B0 = 0x10,
+ OCRDMA_ASIC_REV_C0 = 0x20
+};
#define OCRDMA_SUBSYS_ROCE 10
enum {
@@ -64,6 +72,7 @@ enum {
OCRDMA_CMD_ATTACH_MCAST,
OCRDMA_CMD_DETACH_MCAST,
+ OCRDMA_CMD_GET_RDMA_STATS,
OCRDMA_CMD_MAX
};
@@ -74,12 +83,14 @@ enum {
OCRDMA_CMD_CREATE_CQ = 12,
OCRDMA_CMD_CREATE_EQ = 13,
OCRDMA_CMD_CREATE_MQ = 21,
+ OCRDMA_CMD_GET_CTRL_ATTRIBUTES = 32,
OCRDMA_CMD_GET_FW_VER = 35,
OCRDMA_CMD_DELETE_MQ = 53,
OCRDMA_CMD_DELETE_CQ = 54,
OCRDMA_CMD_DELETE_EQ = 55,
OCRDMA_CMD_GET_FW_CONFIG = 58,
- OCRDMA_CMD_CREATE_MQ_EXT = 90
+ OCRDMA_CMD_CREATE_MQ_EXT = 90,
+ OCRDMA_CMD_PHY_DETAILS = 102
};
enum {
@@ -103,7 +114,10 @@ enum {
OCRDMA_DB_GEN2_SRQ_OFFSET = OCRDMA_DB_GEN2_RQ_OFFSET,
OCRDMA_DB_CQ_OFFSET = 0x120,
OCRDMA_DB_EQ_OFFSET = OCRDMA_DB_CQ_OFFSET,
- OCRDMA_DB_MQ_OFFSET = 0x140
+ OCRDMA_DB_MQ_OFFSET = 0x140,
+
+ OCRDMA_DB_SQ_SHIFT = 16,
+ OCRDMA_DB_RQ_SHIFT = 24
};
#define OCRDMA_DB_CQ_RING_ID_MASK 0x3FF /* bits 0 - 9 */
@@ -138,6 +152,10 @@ enum {
#define OCRDMA_MIN_Q_PAGE_SIZE (4096)
#define OCRDMA_MAX_Q_PAGES (8)
+#define OCRDMA_SLI_ASIC_ID_OFFSET 0x9C
+#define OCRDMA_SLI_ASIC_REV_MASK 0x000000FF
+#define OCRDMA_SLI_ASIC_GEN_NUM_MASK 0x0000FF00
+#define OCRDMA_SLI_ASIC_GEN_NUM_SHIFT 0x08
/*
# 0: 4K Bytes
# 1: 8K Bytes
@@ -562,6 +580,30 @@ enum {
OCRDMA_FN_MODE_RDMA = 0x4
};
+struct ocrdma_get_phy_info_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+
+ u16 phy_type;
+ u16 interface_type;
+ u32 misc_params;
+ u16 ext_phy_details;
+ u16 rsvd;
+ u16 auto_speeds_supported;
+ u16 fixed_speeds_supported;
+ u32 future_use[2];
+};
+
+enum {
+ OCRDMA_PHY_SPEED_ZERO = 0x0,
+ OCRDMA_PHY_SPEED_10MBPS = 0x1,
+ OCRDMA_PHY_SPEED_100MBPS = 0x2,
+ OCRDMA_PHY_SPEED_1GBPS = 0x4,
+ OCRDMA_PHY_SPEED_10GBPS = 0x8,
+ OCRDMA_PHY_SPEED_40GBPS = 0x20
+};
+
+
struct ocrdma_get_link_speed_rsp {
struct ocrdma_mqe_hdr hdr;
struct ocrdma_mbx_rsp rsp;
@@ -590,7 +632,7 @@ enum {
enum {
OCRDMA_CREATE_CQ_VER2 = 2,
- OCRDMA_CREATE_CQ_VER3 = 3,
+ OCRDMA_CREATE_CQ_VER3 = 3,
OCRDMA_CREATE_CQ_PAGE_CNT_MASK = 0xFFFF,
OCRDMA_CREATE_CQ_PAGE_SIZE_SHIFT = 16,
@@ -1050,6 +1092,7 @@ enum {
OCRDMA_MODIFY_QP_RSP_MAX_ORD_MASK = 0xFFFF <<
OCRDMA_MODIFY_QP_RSP_MAX_ORD_SHIFT
};
+
struct ocrdma_modify_qp_rsp {
struct ocrdma_mqe_hdr hdr;
struct ocrdma_mbx_rsp rsp;
@@ -1062,8 +1105,8 @@ struct ocrdma_query_qp {
struct ocrdma_mqe_hdr hdr;
struct ocrdma_mbx_hdr req;
-#define OCRDMA_QUERY_UP_QP_ID_SHIFT 0
-#define OCRDMA_QUERY_UP_QP_ID_MASK 0xFFFFFF
+#define OCRDMA_QUERY_UP_QP_ID_SHIFT 0
+#define OCRDMA_QUERY_UP_QP_ID_MASK 0xFFFFFF
u32 qp_id;
};
@@ -1703,4 +1746,208 @@ struct ocrdma_av {
u32 valid;
} __packed;
+struct ocrdma_rsrc_stats {
+ u32 dpp_pds;
+ u32 non_dpp_pds;
+ u32 rc_dpp_qps;
+ u32 uc_dpp_qps;
+ u32 ud_dpp_qps;
+ u32 rc_non_dpp_qps;
+ u32 rsvd;
+ u32 uc_non_dpp_qps;
+ u32 ud_non_dpp_qps;
+ u32 rsvd1;
+ u32 srqs;
+ u32 rbqs;
+ u32 r64K_nsmr;
+ u32 r64K_to_2M_nsmr;
+ u32 r2M_to_44M_nsmr;
+ u32 r44M_to_1G_nsmr;
+ u32 r1G_to_4G_nsmr;
+ u32 nsmr_count_4G_to_32G;
+ u32 r32G_to_64G_nsmr;
+ u32 r64G_to_128G_nsmr;
+ u32 r128G_to_higher_nsmr;
+ u32 embedded_nsmr;
+ u32 frmr;
+ u32 prefetch_qps;
+ u32 ondemand_qps;
+ u32 phy_mr;
+ u32 mw;
+ u32 rsvd2[7];
+};
+
+struct ocrdma_db_err_stats {
+ u32 sq_doorbell_errors;
+ u32 cq_doorbell_errors;
+ u32 rq_srq_doorbell_errors;
+ u32 cq_overflow_errors;
+ u32 rsvd[4];
+};
+
+struct ocrdma_wqe_stats {
+ u32 large_send_rc_wqes_lo;
+ u32 large_send_rc_wqes_hi;
+ u32 large_write_rc_wqes_lo;
+ u32 large_write_rc_wqes_hi;
+ u32 rsvd[4];
+ u32 read_wqes_lo;
+ u32 read_wqes_hi;
+ u32 frmr_wqes_lo;
+ u32 frmr_wqes_hi;
+ u32 mw_bind_wqes_lo;
+ u32 mw_bind_wqes_hi;
+ u32 invalidate_wqes_lo;
+ u32 invalidate_wqes_hi;
+ u32 rsvd1[2];
+ u32 dpp_wqe_drops;
+ u32 rsvd2[5];
+};
+
+struct ocrdma_tx_stats {
+ u32 send_pkts_lo;
+ u32 send_pkts_hi;
+ u32 write_pkts_lo;
+ u32 write_pkts_hi;
+ u32 read_pkts_lo;
+ u32 read_pkts_hi;
+ u32 read_rsp_pkts_lo;
+ u32 read_rsp_pkts_hi;
+ u32 ack_pkts_lo;
+ u32 ack_pkts_hi;
+ u32 send_bytes_lo;
+ u32 send_bytes_hi;
+ u32 write_bytes_lo;
+ u32 write_bytes_hi;
+ u32 read_req_bytes_lo;
+ u32 read_req_bytes_hi;
+ u32 read_rsp_bytes_lo;
+ u32 read_rsp_bytes_hi;
+ u32 ack_timeouts;
+ u32 rsvd[5];
+};
+
+
+struct ocrdma_tx_qp_err_stats {
+ u32 local_length_errors;
+ u32 local_protection_errors;
+ u32 local_qp_operation_errors;
+ u32 retry_count_exceeded_errors;
+ u32 rnr_retry_count_exceeded_errors;
+ u32 rsvd[3];
+};
+
+struct ocrdma_rx_stats {
+ u32 roce_frame_bytes_lo;
+ u32 roce_frame_bytes_hi;
+ u32 roce_frame_icrc_drops;
+ u32 roce_frame_payload_len_drops;
+ u32 ud_drops;
+ u32 qp1_drops;
+ u32 psn_error_request_packets;
+ u32 psn_error_resp_packets;
+ u32 rnr_nak_timeouts;
+ u32 rnr_nak_receives;
+ u32 roce_frame_rxmt_drops;
+ u32 nak_count_psn_sequence_errors;
+ u32 rc_drop_count_lookup_errors;
+ u32 rq_rnr_naks;
+ u32 srq_rnr_naks;
+ u32 roce_frames_lo;
+ u32 roce_frames_hi;
+ u32 rsvd;
+};
+
+struct ocrdma_rx_qp_err_stats {
+ u32 nak_invalid_requst_errors;
+ u32 nak_remote_operation_errors;
+ u32 nak_count_remote_access_errors;
+ u32 local_length_errors;
+ u32 local_protection_errors;
+ u32 local_qp_operation_errors;
+ u32 rsvd[2];
+};
+
+struct ocrdma_tx_dbg_stats {
+ u32 data[100];
+};
+
+struct ocrdma_rx_dbg_stats {
+ u32 data[200];
+};
+
+struct ocrdma_rdma_stats_req {
+ struct ocrdma_mbx_hdr hdr;
+ u8 reset_stats;
+ u8 rsvd[3];
+} __packed;
+
+struct ocrdma_rdma_stats_resp {
+ struct ocrdma_mbx_hdr hdr;
+ struct ocrdma_rsrc_stats act_rsrc_stats;
+ struct ocrdma_rsrc_stats th_rsrc_stats;
+ struct ocrdma_db_err_stats db_err_stats;
+ struct ocrdma_wqe_stats wqe_stats;
+ struct ocrdma_tx_stats tx_stats;
+ struct ocrdma_tx_qp_err_stats tx_qp_err_stats;
+ struct ocrdma_rx_stats rx_stats;
+ struct ocrdma_rx_qp_err_stats rx_qp_err_stats;
+ struct ocrdma_tx_dbg_stats tx_dbg_stats;
+ struct ocrdma_rx_dbg_stats rx_dbg_stats;
+} __packed;
+
+
+struct mgmt_hba_attribs {
+ u8 flashrom_version_string[32];
+ u8 manufacturer_name[32];
+ u32 supported_modes;
+ u32 rsvd0[3];
+ u8 ncsi_ver_string[12];
+ u32 default_extended_timeout;
+ u8 controller_model_number[32];
+ u8 controller_description[64];
+ u8 controller_serial_number[32];
+ u8 ip_version_string[32];
+ u8 firmware_version_string[32];
+ u8 bios_version_string[32];
+ u8 redboot_version_string[32];
+ u8 driver_version_string[32];
+ u8 fw_on_flash_version_string[32];
+ u32 functionalities_supported;
+ u16 max_cdblength;
+ u8 asic_revision;
+ u8 generational_guid[16];
+ u8 hba_port_count;
+ u16 default_link_down_timeout;
+ u8 iscsi_ver_min_max;
+ u8 multifunction_device;
+ u8 cache_valid;
+ u8 hba_status;
+ u8 max_domains_supported;
+ u8 phy_port;
+ u32 firmware_post_status;
+ u32 hba_mtu[8];
+ u32 rsvd1[4];
+};
+
+struct mgmt_controller_attrib {
+ struct mgmt_hba_attribs hba_attribs;
+ u16 pci_vendor_id;
+ u16 pci_device_id;
+ u16 pci_sub_vendor_id;
+ u16 pci_sub_system_id;
+ u8 pci_bus_number;
+ u8 pci_device_number;
+ u8 pci_function_number;
+ u8 interface_type;
+ u64 unique_identifier;
+ u32 rsvd0[5];
+};
+
+struct ocrdma_get_ctrl_attribs_rsp {
+ struct ocrdma_mbx_hdr hdr;
+ struct mgmt_controller_attrib ctrl_attribs;
+};
+
+
#endif /* __OCRDMA_SLI_H__ */
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_stats.c b/drivers/infiniband/hw/ocrdma/ocrdma_stats.c
new file mode 100644
index 000000000000..6c54106f5e64
--- /dev/null
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_stats.c
@@ -0,0 +1,623 @@
+/*******************************************************************
+ * This file is part of the Emulex RoCE Device Driver for *
+ * RoCE (RDMA over Converged Ethernet) adapters. *
+ * Copyright (C) 2008-2014 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * *
+ * 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. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *
+ * Contact Information:
+ * linux-drivers@emulex.com
+ *
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
+ *******************************************************************/
+
+#include <rdma/ib_addr.h>
+#include "ocrdma_stats.h"
+
+static struct dentry *ocrdma_dbgfs_dir;
+
+static int ocrdma_add_stat(char *start, char *pcur,
+ char *name, u64 count)
+{
+ char buff[128] = {0};
+ int cpy_len = 0;
+
+ snprintf(buff, 128, "%s: %llu\n", name, count);
+ cpy_len = strlen(buff);
+
+ if (pcur + cpy_len > start + OCRDMA_MAX_DBGFS_MEM) {
+ pr_err("%s: No space in stats buff\n", __func__);
+ return 0;
+ }
+
+ memcpy(pcur, buff, cpy_len);
+ return cpy_len;
+}
+
+static bool ocrdma_alloc_stats_mem(struct ocrdma_dev *dev)
+{
+ struct stats_mem *mem = &dev->stats_mem;
+
+ /* Alloc mbox command mem*/
+ mem->size = max_t(u32, sizeof(struct ocrdma_rdma_stats_req),
+ sizeof(struct ocrdma_rdma_stats_resp));
+
+ mem->va = dma_alloc_coherent(&dev->nic_info.pdev->dev, mem->size,
+ &mem->pa, GFP_KERNEL);
+ if (!mem->va) {
+ pr_err("%s: stats mbox allocation failed\n", __func__);
+ return false;
+ }
+
+ memset(mem->va, 0, mem->size);
+
+ /* Alloc debugfs mem */
+ mem->debugfs_mem = kzalloc(OCRDMA_MAX_DBGFS_MEM, GFP_KERNEL);
+ if (!mem->debugfs_mem) {
+ pr_err("%s: stats debugfs mem allocation failed\n", __func__);
+ return false;
+ }
+
+ return true;
+}
+
+static void ocrdma_release_stats_mem(struct ocrdma_dev *dev)
+{
+ struct stats_mem *mem = &dev->stats_mem;
+
+ if (mem->va)
+ dma_free_coherent(&dev->nic_info.pdev->dev, mem->size,
+ mem->va, mem->pa);
+ kfree(mem->debugfs_mem);
+}
+
+static char *ocrdma_resource_stats(struct ocrdma_dev *dev)
+{
+ char *stats = dev->stats_mem.debugfs_mem, *pcur;
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_rsrc_stats *rsrc_stats = &rdma_stats->act_rsrc_stats;
+
+ memset(stats, 0, (OCRDMA_MAX_DBGFS_MEM));
+
+ pcur = stats;
+ pcur += ocrdma_add_stat(stats, pcur, "active_dpp_pds",
+ (u64)rsrc_stats->dpp_pds);
+ pcur += ocrdma_add_stat(stats, pcur, "active_non_dpp_pds",
+ (u64)rsrc_stats->non_dpp_pds);
+ pcur += ocrdma_add_stat(stats, pcur, "active_rc_dpp_qps",
+ (u64)rsrc_stats->rc_dpp_qps);
+ pcur += ocrdma_add_stat(stats, pcur, "active_uc_dpp_qps",
+ (u64)rsrc_stats->uc_dpp_qps);
+ pcur += ocrdma_add_stat(stats, pcur, "active_ud_dpp_qps",
+ (u64)rsrc_stats->ud_dpp_qps);
+ pcur += ocrdma_add_stat(stats, pcur, "active_rc_non_dpp_qps",
+ (u64)rsrc_stats->rc_non_dpp_qps);
+ pcur += ocrdma_add_stat(stats, pcur, "active_uc_non_dpp_qps",
+ (u64)rsrc_stats->uc_non_dpp_qps);
+ pcur += ocrdma_add_stat(stats, pcur, "active_ud_non_dpp_qps",
+ (u64)rsrc_stats->ud_non_dpp_qps);
+ pcur += ocrdma_add_stat(stats, pcur, "active_srqs",
+ (u64)rsrc_stats->srqs);
+ pcur += ocrdma_add_stat(stats, pcur, "active_rbqs",
+ (u64)rsrc_stats->rbqs);
+ pcur += ocrdma_add_stat(stats, pcur, "active_64K_nsmr",
+ (u64)rsrc_stats->r64K_nsmr);
+ pcur += ocrdma_add_stat(stats, pcur, "active_64K_to_2M_nsmr",
+ (u64)rsrc_stats->r64K_to_2M_nsmr);
+ pcur += ocrdma_add_stat(stats, pcur, "active_2M_to_44M_nsmr",
+ (u64)rsrc_stats->r2M_to_44M_nsmr);
+ pcur += ocrdma_add_stat(stats, pcur, "active_44M_to_1G_nsmr",
+ (u64)rsrc_stats->r44M_to_1G_nsmr);
+ pcur += ocrdma_add_stat(stats, pcur, "active_1G_to_4G_nsmr",
+ (u64)rsrc_stats->r1G_to_4G_nsmr);
+ pcur += ocrdma_add_stat(stats, pcur, "active_nsmr_count_4G_to_32G",
+ (u64)rsrc_stats->nsmr_count_4G_to_32G);
+ pcur += ocrdma_add_stat(stats, pcur, "active_32G_to_64G_nsmr",
+ (u64)rsrc_stats->r32G_to_64G_nsmr);
+ pcur += ocrdma_add_stat(stats, pcur, "active_64G_to_128G_nsmr",
+ (u64)rsrc_stats->r64G_to_128G_nsmr);
+ pcur += ocrdma_add_stat(stats, pcur, "active_128G_to_higher_nsmr",
+ (u64)rsrc_stats->r128G_to_higher_nsmr);
+ pcur += ocrdma_add_stat(stats, pcur, "active_embedded_nsmr",
+ (u64)rsrc_stats->embedded_nsmr);
+ pcur += ocrdma_add_stat(stats, pcur, "active_frmr",
+ (u64)rsrc_stats->frmr);
+ pcur += ocrdma_add_stat(stats, pcur, "active_prefetch_qps",
+ (u64)rsrc_stats->prefetch_qps);
+ pcur += ocrdma_add_stat(stats, pcur, "active_ondemand_qps",
+ (u64)rsrc_stats->ondemand_qps);
+ pcur += ocrdma_add_stat(stats, pcur, "active_phy_mr",
+ (u64)rsrc_stats->phy_mr);
+ pcur += ocrdma_add_stat(stats, pcur, "active_mw",
+ (u64)rsrc_stats->mw);
+
+ /* Print the threshold stats */
+ rsrc_stats = &rdma_stats->th_rsrc_stats;
+
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_dpp_pds",
+ (u64)rsrc_stats->dpp_pds);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_non_dpp_pds",
+ (u64)rsrc_stats->non_dpp_pds);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_rc_dpp_qps",
+ (u64)rsrc_stats->rc_dpp_qps);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_uc_dpp_qps",
+ (u64)rsrc_stats->uc_dpp_qps);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_ud_dpp_qps",
+ (u64)rsrc_stats->ud_dpp_qps);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_rc_non_dpp_qps",
+ (u64)rsrc_stats->rc_non_dpp_qps);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_uc_non_dpp_qps",
+ (u64)rsrc_stats->uc_non_dpp_qps);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_ud_non_dpp_qps",
+ (u64)rsrc_stats->ud_non_dpp_qps);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_srqs",
+ (u64)rsrc_stats->srqs);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_rbqs",
+ (u64)rsrc_stats->rbqs);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_64K_nsmr",
+ (u64)rsrc_stats->r64K_nsmr);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_64K_to_2M_nsmr",
+ (u64)rsrc_stats->r64K_to_2M_nsmr);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_2M_to_44M_nsmr",
+ (u64)rsrc_stats->r2M_to_44M_nsmr);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_44M_to_1G_nsmr",
+ (u64)rsrc_stats->r44M_to_1G_nsmr);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_1G_to_4G_nsmr",
+ (u64)rsrc_stats->r1G_to_4G_nsmr);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_nsmr_count_4G_to_32G",
+ (u64)rsrc_stats->nsmr_count_4G_to_32G);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_32G_to_64G_nsmr",
+ (u64)rsrc_stats->r32G_to_64G_nsmr);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_64G_to_128G_nsmr",
+ (u64)rsrc_stats->r64G_to_128G_nsmr);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_128G_to_higher_nsmr",
+ (u64)rsrc_stats->r128G_to_higher_nsmr);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_embedded_nsmr",
+ (u64)rsrc_stats->embedded_nsmr);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_frmr",
+ (u64)rsrc_stats->frmr);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_prefetch_qps",
+ (u64)rsrc_stats->prefetch_qps);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_ondemand_qps",
+ (u64)rsrc_stats->ondemand_qps);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_phy_mr",
+ (u64)rsrc_stats->phy_mr);
+ pcur += ocrdma_add_stat(stats, pcur, "threshold_mw",
+ (u64)rsrc_stats->mw);
+ return stats;
+}
+
+static char *ocrdma_rx_stats(struct ocrdma_dev *dev)
+{
+ char *stats = dev->stats_mem.debugfs_mem, *pcur;
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_rx_stats *rx_stats = &rdma_stats->rx_stats;
+
+ memset(stats, 0, (OCRDMA_MAX_DBGFS_MEM));
+
+ pcur = stats;
+ pcur += ocrdma_add_stat
+ (stats, pcur, "roce_frame_bytes",
+ convert_to_64bit(rx_stats->roce_frame_bytes_lo,
+ rx_stats->roce_frame_bytes_hi));
+ pcur += ocrdma_add_stat(stats, pcur, "roce_frame_icrc_drops",
+ (u64)rx_stats->roce_frame_icrc_drops);
+ pcur += ocrdma_add_stat(stats, pcur, "roce_frame_payload_len_drops",
+ (u64)rx_stats->roce_frame_payload_len_drops);
+ pcur += ocrdma_add_stat(stats, pcur, "ud_drops",
+ (u64)rx_stats->ud_drops);
+ pcur += ocrdma_add_stat(stats, pcur, "qp1_drops",
+ (u64)rx_stats->qp1_drops);
+ pcur += ocrdma_add_stat(stats, pcur, "psn_error_request_packets",
+ (u64)rx_stats->psn_error_request_packets);
+ pcur += ocrdma_add_stat(stats, pcur, "psn_error_resp_packets",
+ (u64)rx_stats->psn_error_resp_packets);
+ pcur += ocrdma_add_stat(stats, pcur, "rnr_nak_timeouts",
+ (u64)rx_stats->rnr_nak_timeouts);
+ pcur += ocrdma_add_stat(stats, pcur, "rnr_nak_receives",
+ (u64)rx_stats->rnr_nak_receives);
+ pcur += ocrdma_add_stat(stats, pcur, "roce_frame_rxmt_drops",
+ (u64)rx_stats->roce_frame_rxmt_drops);
+ pcur += ocrdma_add_stat(stats, pcur, "nak_count_psn_sequence_errors",
+ (u64)rx_stats->nak_count_psn_sequence_errors);
+ pcur += ocrdma_add_stat(stats, pcur, "rc_drop_count_lookup_errors",
+ (u64)rx_stats->rc_drop_count_lookup_errors);
+ pcur += ocrdma_add_stat(stats, pcur, "rq_rnr_naks",
+ (u64)rx_stats->rq_rnr_naks);
+ pcur += ocrdma_add_stat(stats, pcur, "srq_rnr_naks",
+ (u64)rx_stats->srq_rnr_naks);
+ pcur += ocrdma_add_stat(stats, pcur, "roce_frames",
+ convert_to_64bit(rx_stats->roce_frames_lo,
+ rx_stats->roce_frames_hi));
+
+ return stats;
+}
+
+static char *ocrdma_tx_stats(struct ocrdma_dev *dev)
+{
+ char *stats = dev->stats_mem.debugfs_mem, *pcur;
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_tx_stats *tx_stats = &rdma_stats->tx_stats;
+
+ memset(stats, 0, (OCRDMA_MAX_DBGFS_MEM));
+
+ pcur = stats;
+ pcur += ocrdma_add_stat(stats, pcur, "send_pkts",
+ convert_to_64bit(tx_stats->send_pkts_lo,
+ tx_stats->send_pkts_hi));
+ pcur += ocrdma_add_stat(stats, pcur, "write_pkts",
+ convert_to_64bit(tx_stats->write_pkts_lo,
+ tx_stats->write_pkts_hi));
+ pcur += ocrdma_add_stat(stats, pcur, "read_pkts",
+ convert_to_64bit(tx_stats->read_pkts_lo,
+ tx_stats->read_pkts_hi));
+ pcur += ocrdma_add_stat(stats, pcur, "read_rsp_pkts",
+ convert_to_64bit(tx_stats->read_rsp_pkts_lo,
+ tx_stats->read_rsp_pkts_hi));
+ pcur += ocrdma_add_stat(stats, pcur, "ack_pkts",
+ convert_to_64bit(tx_stats->ack_pkts_lo,
+ tx_stats->ack_pkts_hi));
+ pcur += ocrdma_add_stat(stats, pcur, "send_bytes",
+ convert_to_64bit(tx_stats->send_bytes_lo,
+ tx_stats->send_bytes_hi));
+ pcur += ocrdma_add_stat(stats, pcur, "write_bytes",
+ convert_to_64bit(tx_stats->write_bytes_lo,
+ tx_stats->write_bytes_hi));
+ pcur += ocrdma_add_stat(stats, pcur, "read_req_bytes",
+ convert_to_64bit(tx_stats->read_req_bytes_lo,
+ tx_stats->read_req_bytes_hi));
+ pcur += ocrdma_add_stat(stats, pcur, "read_rsp_bytes",
+ convert_to_64bit(tx_stats->read_rsp_bytes_lo,
+ tx_stats->read_rsp_bytes_hi));
+ pcur += ocrdma_add_stat(stats, pcur, "ack_timeouts",
+ (u64)tx_stats->ack_timeouts);
+
+ return stats;
+}
+
+static char *ocrdma_wqe_stats(struct ocrdma_dev *dev)
+{
+ char *stats = dev->stats_mem.debugfs_mem, *pcur;
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_wqe_stats *wqe_stats = &rdma_stats->wqe_stats;
+
+ memset(stats, 0, (OCRDMA_MAX_DBGFS_MEM));
+
+ pcur = stats;
+ pcur += ocrdma_add_stat(stats, pcur, "large_send_rc_wqes",
+ convert_to_64bit(wqe_stats->large_send_rc_wqes_lo,
+ wqe_stats->large_send_rc_wqes_hi));
+ pcur += ocrdma_add_stat(stats, pcur, "large_write_rc_wqes",
+ convert_to_64bit(wqe_stats->large_write_rc_wqes_lo,
+ wqe_stats->large_write_rc_wqes_hi));
+ pcur += ocrdma_add_stat(stats, pcur, "read_wqes",
+ convert_to_64bit(wqe_stats->read_wqes_lo,
+ wqe_stats->read_wqes_hi));
+ pcur += ocrdma_add_stat(stats, pcur, "frmr_wqes",
+ convert_to_64bit(wqe_stats->frmr_wqes_lo,
+ wqe_stats->frmr_wqes_hi));
+ pcur += ocrdma_add_stat(stats, pcur, "mw_bind_wqes",
+ convert_to_64bit(wqe_stats->mw_bind_wqes_lo,
+ wqe_stats->mw_bind_wqes_hi));
+ pcur += ocrdma_add_stat(stats, pcur, "invalidate_wqes",
+ convert_to_64bit(wqe_stats->invalidate_wqes_lo,
+ wqe_stats->invalidate_wqes_hi));
+ pcur += ocrdma_add_stat(stats, pcur, "dpp_wqe_drops",
+ (u64)wqe_stats->dpp_wqe_drops);
+ return stats;
+}
+
+static char *ocrdma_db_errstats(struct ocrdma_dev *dev)
+{
+ char *stats = dev->stats_mem.debugfs_mem, *pcur;
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_db_err_stats *db_err_stats = &rdma_stats->db_err_stats;
+
+ memset(stats, 0, (OCRDMA_MAX_DBGFS_MEM));
+
+ pcur = stats;
+ pcur += ocrdma_add_stat(stats, pcur, "sq_doorbell_errors",
+ (u64)db_err_stats->sq_doorbell_errors);
+ pcur += ocrdma_add_stat(stats, pcur, "cq_doorbell_errors",
+ (u64)db_err_stats->cq_doorbell_errors);
+ pcur += ocrdma_add_stat(stats, pcur, "rq_srq_doorbell_errors",
+ (u64)db_err_stats->rq_srq_doorbell_errors);
+ pcur += ocrdma_add_stat(stats, pcur, "cq_overflow_errors",
+ (u64)db_err_stats->cq_overflow_errors);
+ return stats;
+}
+
+static char *ocrdma_rxqp_errstats(struct ocrdma_dev *dev)
+{
+ char *stats = dev->stats_mem.debugfs_mem, *pcur;
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_rx_qp_err_stats *rx_qp_err_stats =
+ &rdma_stats->rx_qp_err_stats;
+
+ memset(stats, 0, (OCRDMA_MAX_DBGFS_MEM));
+
+ pcur = stats;
+ pcur += ocrdma_add_stat(stats, pcur, "nak_invalid_requst_errors",
+ (u64)rx_qp_err_stats->nak_invalid_requst_errors);
+ pcur += ocrdma_add_stat(stats, pcur, "nak_remote_operation_errors",
+ (u64)rx_qp_err_stats->nak_remote_operation_errors);
+ pcur += ocrdma_add_stat(stats, pcur, "nak_count_remote_access_errors",
+ (u64)rx_qp_err_stats->nak_count_remote_access_errors);
+ pcur += ocrdma_add_stat(stats, pcur, "local_length_errors",
+ (u64)rx_qp_err_stats->local_length_errors);
+ pcur += ocrdma_add_stat(stats, pcur, "local_protection_errors",
+ (u64)rx_qp_err_stats->local_protection_errors);
+ pcur += ocrdma_add_stat(stats, pcur, "local_qp_operation_errors",
+ (u64)rx_qp_err_stats->local_qp_operation_errors);
+ return stats;
+}
+
+static char *ocrdma_txqp_errstats(struct ocrdma_dev *dev)
+{
+ char *stats = dev->stats_mem.debugfs_mem, *pcur;
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_tx_qp_err_stats *tx_qp_err_stats =
+ &rdma_stats->tx_qp_err_stats;
+
+ memset(stats, 0, (OCRDMA_MAX_DBGFS_MEM));
+
+ pcur = stats;
+ pcur += ocrdma_add_stat(stats, pcur, "local_length_errors",
+ (u64)tx_qp_err_stats->local_length_errors);
+ pcur += ocrdma_add_stat(stats, pcur, "local_protection_errors",
+ (u64)tx_qp_err_stats->local_protection_errors);
+ pcur += ocrdma_add_stat(stats, pcur, "local_qp_operation_errors",
+ (u64)tx_qp_err_stats->local_qp_operation_errors);
+ pcur += ocrdma_add_stat(stats, pcur, "retry_count_exceeded_errors",
+ (u64)tx_qp_err_stats->retry_count_exceeded_errors);
+ pcur += ocrdma_add_stat(stats, pcur, "rnr_retry_count_exceeded_errors",
+ (u64)tx_qp_err_stats->rnr_retry_count_exceeded_errors);
+ return stats;
+}
+
+static char *ocrdma_tx_dbg_stats(struct ocrdma_dev *dev)
+{
+ int i;
+ char *pstats = dev->stats_mem.debugfs_mem;
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_tx_dbg_stats *tx_dbg_stats =
+ &rdma_stats->tx_dbg_stats;
+
+ memset(pstats, 0, (OCRDMA_MAX_DBGFS_MEM));
+
+ for (i = 0; i < 100; i++)
+ pstats += snprintf(pstats, 80, "DW[%d] = 0x%x\n", i,
+ tx_dbg_stats->data[i]);
+
+ return dev->stats_mem.debugfs_mem;
+}
+
+static char *ocrdma_rx_dbg_stats(struct ocrdma_dev *dev)
+{
+ int i;
+ char *pstats = dev->stats_mem.debugfs_mem;
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_rx_dbg_stats *rx_dbg_stats =
+ &rdma_stats->rx_dbg_stats;
+
+ memset(pstats, 0, (OCRDMA_MAX_DBGFS_MEM));
+
+ for (i = 0; i < 200; i++)
+ pstats += snprintf(pstats, 80, "DW[%d] = 0x%x\n", i,
+ rx_dbg_stats->data[i]);
+
+ return dev->stats_mem.debugfs_mem;
+}
+
+static void ocrdma_update_stats(struct ocrdma_dev *dev)
+{
+ ulong now = jiffies, secs;
+ int status = 0;
+
+ secs = jiffies_to_msecs(now - dev->last_stats_time) / 1000U;
+ if (secs) {
+ /* update */
+ status = ocrdma_mbx_rdma_stats(dev, false);
+ if (status)
+ pr_err("%s: stats mbox failed with status = %d\n",
+ __func__, status);
+ dev->last_stats_time = jiffies;
+ }
+}
+
+static ssize_t ocrdma_dbgfs_ops_read(struct file *filp, char __user *buffer,
+ size_t usr_buf_len, loff_t *ppos)
+{
+ struct ocrdma_stats *pstats = filp->private_data;
+ struct ocrdma_dev *dev = pstats->dev;
+ ssize_t status = 0;
+ char *data = NULL;
+
+ /* No partial reads */
+ if (*ppos != 0)
+ return 0;
+
+ mutex_lock(&dev->stats_lock);
+
+ ocrdma_update_stats(dev);
+
+ switch (pstats->type) {
+ case OCRDMA_RSRC_STATS:
+ data = ocrdma_resource_stats(dev);
+ break;
+ case OCRDMA_RXSTATS:
+ data = ocrdma_rx_stats(dev);
+ break;
+ case OCRDMA_WQESTATS:
+ data = ocrdma_wqe_stats(dev);
+ break;
+ case OCRDMA_TXSTATS:
+ data = ocrdma_tx_stats(dev);
+ break;
+ case OCRDMA_DB_ERRSTATS:
+ data = ocrdma_db_errstats(dev);
+ break;
+ case OCRDMA_RXQP_ERRSTATS:
+ data = ocrdma_rxqp_errstats(dev);
+ break;
+ case OCRDMA_TXQP_ERRSTATS:
+ data = ocrdma_txqp_errstats(dev);
+ break;
+ case OCRDMA_TX_DBG_STATS:
+ data = ocrdma_tx_dbg_stats(dev);
+ break;
+ case OCRDMA_RX_DBG_STATS:
+ data = ocrdma_rx_dbg_stats(dev);
+ break;
+
+ default:
+ status = -EFAULT;
+ goto exit;
+ }
+
+ if (usr_buf_len < strlen(data)) {
+ status = -ENOSPC;
+ goto exit;
+ }
+
+ status = simple_read_from_buffer(buffer, usr_buf_len, ppos, data,
+ strlen(data));
+exit:
+ mutex_unlock(&dev->stats_lock);
+ return status;
+}
+
+static int ocrdma_debugfs_open(struct inode *inode, struct file *file)
+{
+ if (inode->i_private)
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static const struct file_operations ocrdma_dbg_ops = {
+ .owner = THIS_MODULE,
+ .open = ocrdma_debugfs_open,
+ .read = ocrdma_dbgfs_ops_read,
+};
+
+void ocrdma_add_port_stats(struct ocrdma_dev *dev)
+{
+ if (!ocrdma_dbgfs_dir)
+ return;
+
+ /* Create post stats base dir */
+ dev->dir = debugfs_create_dir(dev->ibdev.name, ocrdma_dbgfs_dir);
+ if (!dev->dir)
+ goto err;
+
+ dev->rsrc_stats.type = OCRDMA_RSRC_STATS;
+ dev->rsrc_stats.dev = dev;
+ if (!debugfs_create_file("resource_stats", S_IRUSR, dev->dir,
+ &dev->rsrc_stats, &ocrdma_dbg_ops))
+ goto err;
+
+ dev->rx_stats.type = OCRDMA_RXSTATS;
+ dev->rx_stats.dev = dev;
+ if (!debugfs_create_file("rx_stats", S_IRUSR, dev->dir,
+ &dev->rx_stats, &ocrdma_dbg_ops))
+ goto err;
+
+ dev->wqe_stats.type = OCRDMA_WQESTATS;
+ dev->wqe_stats.dev = dev;
+ if (!debugfs_create_file("wqe_stats", S_IRUSR, dev->dir,
+ &dev->wqe_stats, &ocrdma_dbg_ops))
+ goto err;
+
+ dev->tx_stats.type = OCRDMA_TXSTATS;
+ dev->tx_stats.dev = dev;
+ if (!debugfs_create_file("tx_stats", S_IRUSR, dev->dir,
+ &dev->tx_stats, &ocrdma_dbg_ops))
+ goto err;
+
+ dev->db_err_stats.type = OCRDMA_DB_ERRSTATS;
+ dev->db_err_stats.dev = dev;
+ if (!debugfs_create_file("db_err_stats", S_IRUSR, dev->dir,
+ &dev->db_err_stats, &ocrdma_dbg_ops))
+ goto err;
+
+
+ dev->tx_qp_err_stats.type = OCRDMA_TXQP_ERRSTATS;
+ dev->tx_qp_err_stats.dev = dev;
+ if (!debugfs_create_file("tx_qp_err_stats", S_IRUSR, dev->dir,
+ &dev->tx_qp_err_stats, &ocrdma_dbg_ops))
+ goto err;
+
+ dev->rx_qp_err_stats.type = OCRDMA_RXQP_ERRSTATS;
+ dev->rx_qp_err_stats.dev = dev;
+ if (!debugfs_create_file("rx_qp_err_stats", S_IRUSR, dev->dir,
+ &dev->rx_qp_err_stats, &ocrdma_dbg_ops))
+ goto err;
+
+
+ dev->tx_dbg_stats.type = OCRDMA_TX_DBG_STATS;
+ dev->tx_dbg_stats.dev = dev;
+ if (!debugfs_create_file("tx_dbg_stats", S_IRUSR, dev->dir,
+ &dev->tx_dbg_stats, &ocrdma_dbg_ops))
+ goto err;
+
+ dev->rx_dbg_stats.type = OCRDMA_RX_DBG_STATS;
+ dev->rx_dbg_stats.dev = dev;
+ if (!debugfs_create_file("rx_dbg_stats", S_IRUSR, dev->dir,
+ &dev->rx_dbg_stats, &ocrdma_dbg_ops))
+ goto err;
+
+ /* Now create dma_mem for stats mbx command */
+ if (!ocrdma_alloc_stats_mem(dev))
+ goto err;
+
+ mutex_init(&dev->stats_lock);
+
+ return;
+err:
+ ocrdma_release_stats_mem(dev);
+ debugfs_remove_recursive(dev->dir);
+ dev->dir = NULL;
+}
+
+void ocrdma_rem_port_stats(struct ocrdma_dev *dev)
+{
+ if (!dev->dir)
+ return;
+ mutex_destroy(&dev->stats_lock);
+ ocrdma_release_stats_mem(dev);
+ debugfs_remove(dev->dir);
+}
+
+void ocrdma_init_debugfs(void)
+{
+ /* Create base dir in debugfs root dir */
+ ocrdma_dbgfs_dir = debugfs_create_dir("ocrdma", NULL);
+}
+
+void ocrdma_rem_debugfs(void)
+{
+ debugfs_remove_recursive(ocrdma_dbgfs_dir);
+}
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_stats.h b/drivers/infiniband/hw/ocrdma/ocrdma_stats.h
new file mode 100644
index 000000000000..5f5e20c46d7c
--- /dev/null
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_stats.h
@@ -0,0 +1,54 @@
+/*******************************************************************
+ * This file is part of the Emulex RoCE Device Driver for *
+ * RoCE (RDMA over Converged Ethernet) adapters. *
+ * Copyright (C) 2008-2014 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * *
+ * 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. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *
+ * Contact Information:
+ * linux-drivers@emulex.com
+ *
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
+ *******************************************************************/
+
+#ifndef __OCRDMA_STATS_H__
+#define __OCRDMA_STATS_H__
+
+#include <linux/debugfs.h>
+#include "ocrdma.h"
+#include "ocrdma_hw.h"
+
+#define OCRDMA_MAX_DBGFS_MEM 4096
+
+enum OCRDMA_STATS_TYPE {
+ OCRDMA_RSRC_STATS,
+ OCRDMA_RXSTATS,
+ OCRDMA_WQESTATS,
+ OCRDMA_TXSTATS,
+ OCRDMA_DB_ERRSTATS,
+ OCRDMA_RXQP_ERRSTATS,
+ OCRDMA_TXQP_ERRSTATS,
+ OCRDMA_TX_DBG_STATS,
+ OCRDMA_RX_DBG_STATS
+};
+
+void ocrdma_rem_debugfs(void);
+void ocrdma_init_debugfs(void);
+void ocrdma_rem_port_stats(struct ocrdma_dev *dev);
+void ocrdma_add_port_stats(struct ocrdma_dev *dev);
+
+#endif /* __OCRDMA_STATS_H__ */
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
index aa92f40c9d50..edf6211d84b8 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
@@ -53,7 +53,7 @@ int ocrdma_query_gid(struct ib_device *ibdev, u8 port,
dev = get_ocrdma_dev(ibdev);
memset(sgid, 0, sizeof(*sgid));
- if (index >= OCRDMA_MAX_SGID)
+ if (index > OCRDMA_MAX_SGID)
return -EINVAL;
memcpy(sgid, &dev->sgid_tbl[index], sizeof(*sgid));
@@ -89,7 +89,7 @@ int ocrdma_query_device(struct ib_device *ibdev, struct ib_device_attr *attr)
attr->max_cq = dev->attr.max_cq;
attr->max_cqe = dev->attr.max_cqe;
attr->max_mr = dev->attr.max_mr;
- attr->max_mw = 0;
+ attr->max_mw = dev->attr.max_mw;
attr->max_pd = dev->attr.max_pd;
attr->atomic_cap = 0;
attr->max_fmr = 0;
@@ -144,7 +144,6 @@ static inline void get_link_speed_and_width(struct ocrdma_dev *dev,
}
}
-
int ocrdma_query_port(struct ib_device *ibdev,
u8 port, struct ib_port_attr *props)
{
@@ -176,7 +175,7 @@ int ocrdma_query_port(struct ib_device *ibdev,
props->port_cap_flags =
IB_PORT_CM_SUP |
IB_PORT_REINIT_SUP |
- IB_PORT_DEVICE_MGMT_SUP | IB_PORT_VENDOR_CLASS_SUP;
+ IB_PORT_DEVICE_MGMT_SUP | IB_PORT_VENDOR_CLASS_SUP | IB_PORT_IP_BASED_GIDS;
props->gid_tbl_len = OCRDMA_MAX_SGID;
props->pkey_tbl_len = 1;
props->bad_pkey_cntr = 0;
@@ -267,7 +266,7 @@ static struct ocrdma_pd *_ocrdma_alloc_pd(struct ocrdma_dev *dev,
if (udata && uctx) {
pd->dpp_enabled =
- dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY;
+ ocrdma_get_asic_type(dev) == OCRDMA_ASIC_GEN_SKH_R;
pd->num_dpp_qp =
pd->dpp_enabled ? OCRDMA_PD_MAX_DPP_ENABLED_QP : 0;
}
@@ -726,10 +725,10 @@ static void build_user_pbes(struct ocrdma_dev *dev, struct ocrdma_mr *mr,
u32 num_pbes)
{
struct ocrdma_pbe *pbe;
- struct ib_umem_chunk *chunk;
+ struct scatterlist *sg;
struct ocrdma_pbl *pbl_tbl = mr->hwmr.pbl_table;
struct ib_umem *umem = mr->umem;
- int i, shift, pg_cnt, pages, pbe_cnt, total_num_pbes = 0;
+ int shift, pg_cnt, pages, pbe_cnt, entry, total_num_pbes = 0;
if (!mr->hwmr.num_pbes)
return;
@@ -739,39 +738,37 @@ static void build_user_pbes(struct ocrdma_dev *dev, struct ocrdma_mr *mr,
shift = ilog2(umem->page_size);
- list_for_each_entry(chunk, &umem->chunk_list, list) {
- /* get all the dma regions from the chunk. */
- for (i = 0; i < chunk->nmap; i++) {
- pages = sg_dma_len(&chunk->page_list[i]) >> shift;
- for (pg_cnt = 0; pg_cnt < pages; pg_cnt++) {
- /* store the page address in pbe */
- pbe->pa_lo =
- cpu_to_le32(sg_dma_address
- (&chunk->page_list[i]) +
- (umem->page_size * pg_cnt));
- pbe->pa_hi =
- cpu_to_le32(upper_32_bits
- ((sg_dma_address
- (&chunk->page_list[i]) +
- umem->page_size * pg_cnt)));
- pbe_cnt += 1;
- total_num_pbes += 1;
- pbe++;
-
- /* if done building pbes, issue the mbx cmd. */
- if (total_num_pbes == num_pbes)
- return;
-
- /* if the given pbl is full storing the pbes,
- * move to next pbl.
- */
- if (pbe_cnt ==
- (mr->hwmr.pbl_size / sizeof(u64))) {
- pbl_tbl++;
- pbe = (struct ocrdma_pbe *)pbl_tbl->va;
- pbe_cnt = 0;
- }
+ for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) {
+ pages = sg_dma_len(sg) >> shift;
+ for (pg_cnt = 0; pg_cnt < pages; pg_cnt++) {
+ /* store the page address in pbe */
+ pbe->pa_lo =
+ cpu_to_le32(sg_dma_address
+ (sg) +
+ (umem->page_size * pg_cnt));
+ pbe->pa_hi =
+ cpu_to_le32(upper_32_bits
+ ((sg_dma_address
+ (sg) +
+ umem->page_size * pg_cnt)));
+ pbe_cnt += 1;
+ total_num_pbes += 1;
+ pbe++;
+
+ /* if done building pbes, issue the mbx cmd. */
+ if (total_num_pbes == num_pbes)
+ return;
+
+ /* if the given pbl is full storing the pbes,
+ * move to next pbl.
+ */
+ if (pbe_cnt ==
+ (mr->hwmr.pbl_size / sizeof(u64))) {
+ pbl_tbl++;
+ pbe = (struct ocrdma_pbe *)pbl_tbl->va;
+ pbe_cnt = 0;
}
+
}
}
}
@@ -840,8 +837,7 @@ int ocrdma_dereg_mr(struct ib_mr *ib_mr)
status = ocrdma_mbx_dealloc_lkey(dev, mr->hwmr.fr_mr, mr->hwmr.lkey);
- if (mr->hwmr.fr_mr == 0)
- ocrdma_free_mr_pbl_tbl(dev, &mr->hwmr);
+ ocrdma_free_mr_pbl_tbl(dev, &mr->hwmr);
/* it could be user registered memory. */
if (mr->umem)
@@ -910,6 +906,7 @@ struct ib_cq *ocrdma_create_cq(struct ib_device *ibdev, int entries, int vector,
spin_lock_init(&cq->comp_handler_lock);
INIT_LIST_HEAD(&cq->sq_head);
INIT_LIST_HEAD(&cq->rq_head);
+ cq->first_arm = true;
if (ib_ctx) {
uctx = get_ocrdma_ucontext(ib_ctx);
@@ -927,9 +924,7 @@ struct ib_cq *ocrdma_create_cq(struct ib_device *ibdev, int entries, int vector,
goto ctx_err;
}
cq->phase = OCRDMA_CQE_VALID;
- cq->arm_needed = true;
dev->cq_tbl[cq->id] = cq;
-
return &cq->ibcq;
ctx_err:
@@ -952,15 +947,52 @@ int ocrdma_resize_cq(struct ib_cq *ibcq, int new_cnt,
return status;
}
+static void ocrdma_flush_cq(struct ocrdma_cq *cq)
+{
+ int cqe_cnt;
+ int valid_count = 0;
+ unsigned long flags;
+
+ struct ocrdma_dev *dev = get_ocrdma_dev(cq->ibcq.device);
+ struct ocrdma_cqe *cqe = NULL;
+
+ cqe = cq->va;
+ cqe_cnt = cq->cqe_cnt;
+
+ /* Last irq might have scheduled a polling thread
+ * sync-up with it before hard flushing.
+ */
+ spin_lock_irqsave(&cq->cq_lock, flags);
+ while (cqe_cnt) {
+ if (is_cqe_valid(cq, cqe))
+ valid_count++;
+ cqe++;
+ cqe_cnt--;
+ }
+ ocrdma_ring_cq_db(dev, cq->id, false, false, valid_count);
+ spin_unlock_irqrestore(&cq->cq_lock, flags);
+}
+
int ocrdma_destroy_cq(struct ib_cq *ibcq)
{
int status;
struct ocrdma_cq *cq = get_ocrdma_cq(ibcq);
+ struct ocrdma_eq *eq = NULL;
struct ocrdma_dev *dev = get_ocrdma_dev(ibcq->device);
int pdid = 0;
+ u32 irq, indx;
- status = ocrdma_mbx_destroy_cq(dev, cq);
+ dev->cq_tbl[cq->id] = NULL;
+ indx = ocrdma_get_eq_table_index(dev, cq->eqn);
+ if (indx == -EINVAL)
+ BUG();
+ eq = &dev->eq_tbl[indx];
+ irq = ocrdma_get_irq(dev, eq);
+ synchronize_irq(irq);
+ ocrdma_flush_cq(cq);
+
+ status = ocrdma_mbx_destroy_cq(dev, cq);
if (cq->ucontext) {
pdid = cq->ucontext->cntxt_pd->id;
ocrdma_del_mmap(cq->ucontext, (u64) cq->pa,
@@ -969,7 +1001,6 @@ int ocrdma_destroy_cq(struct ib_cq *ibcq)
ocrdma_get_db_addr(dev, pdid),
dev->nic_info.db_page_size);
}
- dev->cq_tbl[cq->id] = NULL;
kfree(cq);
return status;
@@ -1092,15 +1123,9 @@ static int ocrdma_copy_qp_uresp(struct ocrdma_qp *qp,
}
uresp.db_page_addr = usr_db;
uresp.db_page_size = dev->nic_info.db_page_size;
- if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {
- uresp.db_sq_offset = OCRDMA_DB_GEN2_SQ_OFFSET;
- uresp.db_rq_offset = OCRDMA_DB_GEN2_RQ_OFFSET;
- uresp.db_shift = 24;
- } else {
- uresp.db_sq_offset = OCRDMA_DB_SQ_OFFSET;
- uresp.db_rq_offset = OCRDMA_DB_RQ_OFFSET;
- uresp.db_shift = 16;
- }
+ uresp.db_sq_offset = OCRDMA_DB_GEN2_SQ_OFFSET;
+ uresp.db_rq_offset = OCRDMA_DB_GEN2_RQ_OFFSET;
+ uresp.db_shift = OCRDMA_DB_RQ_SHIFT;
if (qp->dpp_enabled) {
uresp.dpp_credit = dpp_credit_lmt;
@@ -1132,7 +1157,7 @@ err:
static void ocrdma_set_qp_db(struct ocrdma_dev *dev, struct ocrdma_qp *qp,
struct ocrdma_pd *pd)
{
- if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {
+ if (ocrdma_get_asic_type(dev) == OCRDMA_ASIC_GEN_SKH_R) {
qp->sq_db = dev->nic_info.db +
(pd->id * dev->nic_info.db_page_size) +
OCRDMA_DB_GEN2_SQ_OFFSET;
@@ -1182,7 +1207,6 @@ static void ocrdma_set_qp_init_params(struct ocrdma_qp *qp,
qp->signaled = (attrs->sq_sig_type == IB_SIGNAL_ALL_WR) ? true : false;
}
-
static void ocrdma_store_gsi_qp_cq(struct ocrdma_dev *dev,
struct ib_qp_init_attr *attrs)
{
@@ -1268,17 +1292,6 @@ gen_err:
return ERR_PTR(status);
}
-
-static void ocrdma_flush_rq_db(struct ocrdma_qp *qp)
-{
- if (qp->db_cache) {
- u32 val = qp->rq.dbid | (qp->db_cache <<
- ocrdma_get_num_posted_shift(qp));
- iowrite32(val, qp->rq_db);
- qp->db_cache = 0;
- }
-}
-
int _ocrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
int attr_mask)
{
@@ -1296,9 +1309,7 @@ int _ocrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
*/
if (status < 0)
return status;
- status = ocrdma_mbx_modify_qp(dev, qp, attr, attr_mask, old_qps);
- if (!status && attr_mask & IB_QP_STATE && attr->qp_state == IB_QPS_RTR)
- ocrdma_flush_rq_db(qp);
+ status = ocrdma_mbx_modify_qp(dev, qp, attr, attr_mask);
return status;
}
@@ -1416,7 +1427,7 @@ int ocrdma_query_qp(struct ib_qp *ibqp,
OCRDMA_QP_PARAMS_HOP_LMT_MASK) >>
OCRDMA_QP_PARAMS_HOP_LMT_SHIFT;
qp_attr->ah_attr.grh.traffic_class = (params.tclass_sq_psn &
- OCRDMA_QP_PARAMS_SQ_PSN_MASK) >>
+ OCRDMA_QP_PARAMS_TCLASS_MASK) >>
OCRDMA_QP_PARAMS_TCLASS_SHIFT;
qp_attr->ah_attr.ah_flags = IB_AH_GRH;
@@ -1510,7 +1521,7 @@ static void ocrdma_discard_cqes(struct ocrdma_qp *qp, struct ocrdma_cq *cq)
int discard_cnt = 0;
u32 cur_getp, stop_getp;
struct ocrdma_cqe *cqe;
- u32 qpn = 0;
+ u32 qpn = 0, wqe_idx = 0;
spin_lock_irqsave(&cq->cq_lock, cq_flags);
@@ -1539,24 +1550,29 @@ static void ocrdma_discard_cqes(struct ocrdma_qp *qp, struct ocrdma_cq *cq)
if (qpn == 0 || qpn != qp->id)
goto skip_cqe;
- /* mark cqe discarded so that it is not picked up later
- * in the poll_cq().
- */
- discard_cnt += 1;
- cqe->cmn.qpn = 0;
if (is_cqe_for_sq(cqe)) {
ocrdma_hwq_inc_tail(&qp->sq);
} else {
if (qp->srq) {
+ wqe_idx = (le32_to_cpu(cqe->rq.buftag_qpn) >>
+ OCRDMA_CQE_BUFTAG_SHIFT) &
+ qp->srq->rq.max_wqe_idx;
+ if (wqe_idx < 1)
+ BUG();
spin_lock_irqsave(&qp->srq->q_lock, flags);
ocrdma_hwq_inc_tail(&qp->srq->rq);
- ocrdma_srq_toggle_bit(qp->srq, cur_getp);
+ ocrdma_srq_toggle_bit(qp->srq, wqe_idx - 1);
spin_unlock_irqrestore(&qp->srq->q_lock, flags);
} else {
ocrdma_hwq_inc_tail(&qp->rq);
}
}
+ /* mark cqe discarded so that it is not picked up later
+ * in the poll_cq().
+ */
+ discard_cnt += 1;
+ cqe->cmn.qpn = 0;
skip_cqe:
cur_getp = (cur_getp + 1) % cq->max_hw_cqe;
} while (cur_getp != stop_getp);
@@ -1659,7 +1675,7 @@ static int ocrdma_copy_srq_uresp(struct ocrdma_dev *dev, struct ocrdma_srq *srq,
(srq->pd->id * dev->nic_info.db_page_size);
uresp.db_page_size = dev->nic_info.db_page_size;
uresp.num_rqe_allocated = srq->rq.max_cnt;
- if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {
+ if (ocrdma_get_asic_type(dev) == OCRDMA_ASIC_GEN_SKH_R) {
uresp.db_rq_offset = OCRDMA_DB_GEN2_RQ_OFFSET;
uresp.db_shift = 24;
} else {
@@ -2009,15 +2025,15 @@ static int ocrdma_build_fr(struct ocrdma_qp *qp, struct ocrdma_hdr_wqe *hdr,
fast_reg->num_sges = wr->wr.fast_reg.page_list_len;
fast_reg->size_sge =
get_encoded_page_size(1 << wr->wr.fast_reg.page_shift);
- mr = (struct ocrdma_mr *) (unsigned long) qp->dev->stag_arr[(hdr->lkey >> 8) &
- (OCRDMA_MAX_STAG - 1)];
+ mr = (struct ocrdma_mr *) (unsigned long)
+ qp->dev->stag_arr[(hdr->lkey >> 8) & (OCRDMA_MAX_STAG - 1)];
build_frmr_pbes(wr, mr->hwmr.pbl_table, &mr->hwmr);
return 0;
}
static void ocrdma_ring_sq_db(struct ocrdma_qp *qp)
{
- u32 val = qp->sq.dbid | (1 << 16);
+ u32 val = qp->sq.dbid | (1 << OCRDMA_DB_SQ_SHIFT);
iowrite32(val, qp->sq_db);
}
@@ -2122,12 +2138,9 @@ int ocrdma_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
static void ocrdma_ring_rq_db(struct ocrdma_qp *qp)
{
- u32 val = qp->rq.dbid | (1 << ocrdma_get_num_posted_shift(qp));
+ u32 val = qp->rq.dbid | (1 << OCRDMA_DB_RQ_SHIFT);
- if (qp->state != OCRDMA_QPS_INIT)
- iowrite32(val, qp->rq_db);
- else
- qp->db_cache++;
+ iowrite32(val, qp->rq_db);
}
static void ocrdma_build_rqe(struct ocrdma_hdr_wqe *rqe, struct ib_recv_wr *wr,
@@ -2213,7 +2226,7 @@ static int ocrdma_srq_get_idx(struct ocrdma_srq *srq)
if (row == srq->bit_fields_len)
BUG();
- return indx;
+ return indx + 1; /* Use from index 1 */
}
static void ocrdma_ring_srq_db(struct ocrdma_srq *srq)
@@ -2550,10 +2563,13 @@ static void ocrdma_update_free_srq_cqe(struct ib_wc *ibwc,
srq = get_ocrdma_srq(qp->ibqp.srq);
wqe_idx = (le32_to_cpu(cqe->rq.buftag_qpn) >>
- OCRDMA_CQE_BUFTAG_SHIFT) & srq->rq.max_wqe_idx;
+ OCRDMA_CQE_BUFTAG_SHIFT) & srq->rq.max_wqe_idx;
+ if (wqe_idx < 1)
+ BUG();
+
ibwc->wr_id = srq->rqe_wr_id_tbl[wqe_idx];
spin_lock_irqsave(&srq->q_lock, flags);
- ocrdma_srq_toggle_bit(srq, wqe_idx);
+ ocrdma_srq_toggle_bit(srq, wqe_idx - 1);
spin_unlock_irqrestore(&srq->q_lock, flags);
ocrdma_hwq_inc_tail(&srq->rq);
}
@@ -2705,10 +2721,18 @@ expand_cqe:
}
stop_cqe:
cq->getp = cur_getp;
- if (polled_hw_cqes || expand || stop) {
- ocrdma_ring_cq_db(dev, cq->id, cq->armed, cq->solicited,
+ if (cq->deferred_arm) {
+ ocrdma_ring_cq_db(dev, cq->id, true, cq->deferred_sol,
+ polled_hw_cqes);
+ cq->deferred_arm = false;
+ cq->deferred_sol = false;
+ } else {
+ /* We need to pop the CQE. No need to arm */
+ ocrdma_ring_cq_db(dev, cq->id, false, cq->deferred_sol,
polled_hw_cqes);
+ cq->deferred_sol = false;
}
+
return i;
}
@@ -2780,30 +2804,28 @@ int ocrdma_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags cq_flags)
struct ocrdma_cq *cq = get_ocrdma_cq(ibcq);
struct ocrdma_dev *dev = get_ocrdma_dev(ibcq->device);
u16 cq_id;
- u16 cur_getp;
- struct ocrdma_cqe *cqe;
unsigned long flags;
+ bool arm_needed = false, sol_needed = false;
cq_id = cq->id;
spin_lock_irqsave(&cq->cq_lock, flags);
if (cq_flags & IB_CQ_NEXT_COMP || cq_flags & IB_CQ_SOLICITED)
- cq->armed = true;
+ arm_needed = true;
if (cq_flags & IB_CQ_SOLICITED)
- cq->solicited = true;
-
- cur_getp = cq->getp;
- cqe = cq->va + cur_getp;
+ sol_needed = true;
- /* check whether any valid cqe exist or not, if not then safe to
- * arm. If cqe is not yet consumed, then let it get consumed and then
- * we arm it to avoid false interrupts.
- */
- if (!is_cqe_valid(cq, cqe) || cq->arm_needed) {
- cq->arm_needed = false;
- ocrdma_ring_cq_db(dev, cq_id, cq->armed, cq->solicited, 0);
+ if (cq->first_arm) {
+ ocrdma_ring_cq_db(dev, cq_id, arm_needed, sol_needed, 0);
+ cq->first_arm = false;
+ goto skip_defer;
}
+ cq->deferred_arm = true;
+
+skip_defer:
+ cq->deferred_sol = sol_needed;
spin_unlock_irqrestore(&cq->cq_lock, flags);
+
return 0;
}
@@ -2838,7 +2860,8 @@ struct ib_mr *ocrdma_alloc_frmr(struct ib_pd *ibpd, int max_page_list_len)
goto mbx_err;
mr->ibmr.rkey = mr->hwmr.lkey;
mr->ibmr.lkey = mr->hwmr.lkey;
- dev->stag_arr[(mr->hwmr.lkey >> 8) & (OCRDMA_MAX_STAG - 1)] = mr;
+ dev->stag_arr[(mr->hwmr.lkey >> 8) & (OCRDMA_MAX_STAG - 1)] =
+ (unsigned long) mr;
return &mr->ibmr;
mbx_err:
ocrdma_free_mr_pbl_tbl(dev, &mr->hwmr);
diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h
index 1946101419a3..c00ae093b6f8 100644
--- a/drivers/infiniband/hw/qib/qib.h
+++ b/drivers/infiniband/hw/qib/qib.h
@@ -868,8 +868,10 @@ struct qib_devdata {
/* last buffer for user use */
u32 lastctxt_piobuf;
- /* saturating counter of (non-port-specific) device interrupts */
- u32 int_counter;
+ /* reset value */
+ u64 z_int_counter;
+ /* percpu intcounter */
+ u64 __percpu *int_counter;
/* pio bufs allocated per ctxt */
u32 pbufsctxt;
@@ -1184,7 +1186,7 @@ int qib_setup_eagerbufs(struct qib_ctxtdata *);
void qib_set_ctxtcnt(struct qib_devdata *);
int qib_create_ctxts(struct qib_devdata *dd);
struct qib_ctxtdata *qib_create_ctxtdata(struct qib_pportdata *, u32, int);
-void qib_init_pportdata(struct qib_pportdata *, struct qib_devdata *, u8, u8);
+int qib_init_pportdata(struct qib_pportdata *, struct qib_devdata *, u8, u8);
void qib_free_ctxtdata(struct qib_devdata *, struct qib_ctxtdata *);
u32 qib_kreceive(struct qib_ctxtdata *, u32 *, u32 *);
@@ -1449,6 +1451,10 @@ void qib_nomsi(struct qib_devdata *);
void qib_nomsix(struct qib_devdata *);
void qib_pcie_getcmd(struct qib_devdata *, u16 *, u8 *, u8 *);
void qib_pcie_reenable(struct qib_devdata *, u16, u8, u8);
+/* interrupts for device */
+u64 qib_int_counter(struct qib_devdata *);
+/* interrupt for all devices */
+u64 qib_sps_ints(void);
/*
* dma_addr wrappers - all 0's invalid for hw
diff --git a/drivers/infiniband/hw/qib/qib_diag.c b/drivers/infiniband/hw/qib/qib_diag.c
index 1686fd4bda87..5dfda4c5cc9c 100644
--- a/drivers/infiniband/hw/qib/qib_diag.c
+++ b/drivers/infiniband/hw/qib/qib_diag.c
@@ -546,7 +546,7 @@ static ssize_t qib_diagpkt_write(struct file *fp,
size_t count, loff_t *off)
{
u32 __iomem *piobuf;
- u32 plen, clen, pbufn;
+ u32 plen, pbufn, maxlen_reserve;
struct qib_diag_xpkt dp;
u32 *tmpbuf = NULL;
struct qib_devdata *dd;
@@ -590,15 +590,20 @@ static ssize_t qib_diagpkt_write(struct file *fp,
}
ppd = &dd->pport[dp.port - 1];
- /* need total length before first word written */
- /* +1 word is for the qword padding */
- plen = sizeof(u32) + dp.len;
- clen = dp.len >> 2;
-
- if ((plen + 4) > ppd->ibmaxlen) {
+ /*
+ * need total length before first word written, plus 2 Dwords. One Dword
+ * is for padding so we get the full user data when not aligned on
+ * a word boundary. The other Dword is to make sure we have room for the
+ * ICRC which gets tacked on later.
+ */
+ maxlen_reserve = 2 * sizeof(u32);
+ if (dp.len > ppd->ibmaxlen - maxlen_reserve) {
ret = -EINVAL;
- goto bail; /* before writing pbc */
+ goto bail;
}
+
+ plen = sizeof(u32) + dp.len;
+
tmpbuf = vmalloc(plen);
if (!tmpbuf) {
qib_devinfo(dd->pcidev,
@@ -638,11 +643,11 @@ static ssize_t qib_diagpkt_write(struct file *fp,
*/
if (dd->flags & QIB_PIO_FLUSH_WC) {
qib_flush_wc();
- qib_pio_copy(piobuf + 2, tmpbuf, clen - 1);
+ qib_pio_copy(piobuf + 2, tmpbuf, plen - 1);
qib_flush_wc();
- __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1);
+ __raw_writel(tmpbuf[plen - 1], piobuf + plen + 1);
} else
- qib_pio_copy(piobuf + 2, tmpbuf, clen);
+ qib_pio_copy(piobuf + 2, tmpbuf, plen);
if (dd->flags & QIB_USE_SPCL_TRIG) {
u32 spcl_off = (pbufn >= dd->piobcnt2k) ? 2047 : 1023;
@@ -689,28 +694,23 @@ int qib_register_observer(struct qib_devdata *dd,
const struct diag_observer *op)
{
struct diag_observer_list_elt *olp;
- int ret = -EINVAL;
+ unsigned long flags;
if (!dd || !op)
- goto bail;
- ret = -ENOMEM;
+ return -EINVAL;
olp = vmalloc(sizeof *olp);
if (!olp) {
pr_err("vmalloc for observer failed\n");
- goto bail;
+ return -ENOMEM;
}
- if (olp) {
- unsigned long flags;
- spin_lock_irqsave(&dd->qib_diag_trans_lock, flags);
- olp->op = op;
- olp->next = dd->diag_observer_list;
- dd->diag_observer_list = olp;
- spin_unlock_irqrestore(&dd->qib_diag_trans_lock, flags);
- ret = 0;
- }
-bail:
- return ret;
+ spin_lock_irqsave(&dd->qib_diag_trans_lock, flags);
+ olp->op = op;
+ olp->next = dd->diag_observer_list;
+ dd->diag_observer_list = olp;
+ spin_unlock_irqrestore(&dd->qib_diag_trans_lock, flags);
+
+ return 0;
}
/* Remove all registered observers when device is closed */
diff --git a/drivers/infiniband/hw/qib/qib_dma.c b/drivers/infiniband/hw/qib/qib_dma.c
index 2920bb39a65b..59fe092b4b0f 100644
--- a/drivers/infiniband/hw/qib/qib_dma.c
+++ b/drivers/infiniband/hw/qib/qib_dma.c
@@ -108,6 +108,10 @@ static int qib_map_sg(struct ib_device *dev, struct scatterlist *sgl,
ret = 0;
break;
}
+ sg->dma_address = addr + sg->offset;
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
+ sg->dma_length = sg->length;
+#endif
}
return ret;
}
@@ -119,21 +123,6 @@ static void qib_unmap_sg(struct ib_device *dev,
BUG_ON(!valid_dma_direction(direction));
}
-static u64 qib_sg_dma_address(struct ib_device *dev, struct scatterlist *sg)
-{
- u64 addr = (u64) page_address(sg_page(sg));
-
- if (addr)
- addr += sg->offset;
- return addr;
-}
-
-static unsigned int qib_sg_dma_len(struct ib_device *dev,
- struct scatterlist *sg)
-{
- return sg->length;
-}
-
static void qib_sync_single_for_cpu(struct ib_device *dev, u64 addr,
size_t size, enum dma_data_direction dir)
{
@@ -173,8 +162,6 @@ struct ib_dma_mapping_ops qib_dma_mapping_ops = {
.unmap_page = qib_dma_unmap_page,
.map_sg = qib_map_sg,
.unmap_sg = qib_unmap_sg,
- .dma_address = qib_sg_dma_address,
- .dma_len = qib_sg_dma_len,
.sync_single_for_cpu = qib_sync_single_for_cpu,
.sync_single_for_device = qib_sync_single_for_device,
.alloc_coherent = qib_dma_alloc_coherent,
diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c
index 275f247f9fca..b15e34eeef68 100644
--- a/drivers/infiniband/hw/qib/qib_file_ops.c
+++ b/drivers/infiniband/hw/qib/qib_file_ops.c
@@ -1459,7 +1459,7 @@ static int get_a_ctxt(struct file *fp, const struct qib_user_info *uinfo,
cused++;
else
cfree++;
- if (pusable && cfree && cused < inuse) {
+ if (cfree && cused < inuse) {
udd = dd;
inuse = cused;
}
@@ -1578,7 +1578,7 @@ static int do_qib_user_sdma_queue_create(struct file *fp)
struct qib_ctxtdata *rcd = fd->rcd;
struct qib_devdata *dd = rcd->dd;
- if (dd->flags & QIB_HAS_SEND_DMA)
+ if (dd->flags & QIB_HAS_SEND_DMA) {
fd->pq = qib_user_sdma_queue_create(&dd->pcidev->dev,
dd->unit,
@@ -1586,6 +1586,7 @@ static int do_qib_user_sdma_queue_create(struct file *fp)
fd->subctxt);
if (!fd->pq)
return -ENOMEM;
+ }
return 0;
}
diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c
index c61e2a92b3c1..cab610ccd50e 100644
--- a/drivers/infiniband/hw/qib/qib_fs.c
+++ b/drivers/infiniband/hw/qib/qib_fs.c
@@ -105,6 +105,7 @@ static int create_file(const char *name, umode_t mode,
static ssize_t driver_stats_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
+ qib_stats.sps_ints = qib_sps_ints();
return simple_read_from_buffer(buf, count, ppos, &qib_stats,
sizeof qib_stats);
}
diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c
index 84e593d6007b..d68266ac7619 100644
--- a/drivers/infiniband/hw/qib/qib_iba6120.c
+++ b/drivers/infiniband/hw/qib/qib_iba6120.c
@@ -1634,9 +1634,7 @@ static irqreturn_t qib_6120intr(int irq, void *data)
goto bail;
}
- qib_stats.sps_ints++;
- if (dd->int_counter != (u32) -1)
- dd->int_counter++;
+ this_cpu_inc(*dd->int_counter);
if (unlikely(istat & (~QLOGIC_IB_I_BITSEXTANT |
QLOGIC_IB_I_GPIO | QLOGIC_IB_I_ERROR)))
@@ -1808,7 +1806,8 @@ static int qib_6120_setup_reset(struct qib_devdata *dd)
* isn't set.
*/
dd->flags &= ~(QIB_INITTED | QIB_PRESENT);
- dd->int_counter = 0; /* so we check interrupts work again */
+ /* so we check interrupts work again */
+ dd->z_int_counter = qib_int_counter(dd);
val = dd->control | QLOGIC_IB_C_RESET;
writeq(val, &dd->kregbase[kr_control]);
mb(); /* prevent compiler re-ordering around actual reset */
@@ -3266,7 +3265,9 @@ static int init_6120_variables(struct qib_devdata *dd)
dd->eep_st_masks[2].errs_to_log = ERR_MASK(ResetNegated);
- qib_init_pportdata(ppd, dd, 0, 1);
+ ret = qib_init_pportdata(ppd, dd, 0, 1);
+ if (ret)
+ goto bail;
ppd->link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X;
ppd->link_speed_supported = QIB_IB_SDR;
ppd->link_width_enabled = IB_WIDTH_4X;
diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c
index 454c2e7668fe..7dec89fdc124 100644
--- a/drivers/infiniband/hw/qib/qib_iba7220.c
+++ b/drivers/infiniband/hw/qib/qib_iba7220.c
@@ -1962,10 +1962,7 @@ static irqreturn_t qib_7220intr(int irq, void *data)
goto bail;
}
- qib_stats.sps_ints++;
- if (dd->int_counter != (u32) -1)
- dd->int_counter++;
-
+ this_cpu_inc(*dd->int_counter);
if (unlikely(istat & (~QLOGIC_IB_I_BITSEXTANT |
QLOGIC_IB_I_GPIO | QLOGIC_IB_I_ERROR)))
unlikely_7220_intr(dd, istat);
@@ -2120,7 +2117,8 @@ static int qib_setup_7220_reset(struct qib_devdata *dd)
* isn't set.
*/
dd->flags &= ~(QIB_INITTED | QIB_PRESENT);
- dd->int_counter = 0; /* so we check interrupts work again */
+ /* so we check interrupts work again */
+ dd->z_int_counter = qib_int_counter(dd);
val = dd->control | QLOGIC_IB_C_RESET;
writeq(val, &dd->kregbase[kr_control]);
mb(); /* prevent compiler reordering around actual reset */
@@ -4061,7 +4059,9 @@ static int qib_init_7220_variables(struct qib_devdata *dd)
init_waitqueue_head(&cpspec->autoneg_wait);
INIT_DELAYED_WORK(&cpspec->autoneg_work, autoneg_7220_work);
- qib_init_pportdata(ppd, dd, 0, 1);
+ ret = qib_init_pportdata(ppd, dd, 0, 1);
+ if (ret)
+ goto bail;
ppd->link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X;
ppd->link_speed_supported = QIB_IB_SDR | QIB_IB_DDR;
diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c
index 5bfc02f450e6..a7eb32517a04 100644
--- a/drivers/infiniband/hw/qib/qib_iba7322.c
+++ b/drivers/infiniband/hw/qib/qib_iba7322.c
@@ -2395,6 +2395,11 @@ static int qib_7322_bringup_serdes(struct qib_pportdata *ppd)
qib_write_kreg_port(ppd, krp_ibcctrl_a, ppd->cpspec->ibcctrl_a);
qib_write_kreg(dd, kr_scratch, 0ULL);
+ /* ensure previous Tx parameters are not still forced */
+ qib_write_kreg_port(ppd, krp_tx_deemph_override,
+ SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+ reset_tx_deemphasis_override));
+
if (qib_compat_ddr_negotiate) {
ppd->cpspec->ibdeltainprog = 1;
ppd->cpspec->ibsymsnap = read_7322_creg32_port(ppd,
@@ -3110,9 +3115,7 @@ static irqreturn_t qib_7322intr(int irq, void *data)
goto bail;
}
- qib_stats.sps_ints++;
- if (dd->int_counter != (u32) -1)
- dd->int_counter++;
+ this_cpu_inc(*dd->int_counter);
/* handle "errors" of various kinds first, device ahead of port */
if (unlikely(istat & (~QIB_I_BITSEXTANT | QIB_I_GPIO |
@@ -3181,9 +3184,7 @@ static irqreturn_t qib_7322pintr(int irq, void *data)
*/
return IRQ_HANDLED;
- qib_stats.sps_ints++;
- if (dd->int_counter != (u32) -1)
- dd->int_counter++;
+ this_cpu_inc(*dd->int_counter);
/* Clear the interrupt bit we expect to be set. */
qib_write_kreg(dd, kr_intclear, ((1ULL << QIB_I_RCVAVAIL_LSB) |
@@ -3210,9 +3211,7 @@ static irqreturn_t qib_7322bufavail(int irq, void *data)
*/
return IRQ_HANDLED;
- qib_stats.sps_ints++;
- if (dd->int_counter != (u32) -1)
- dd->int_counter++;
+ this_cpu_inc(*dd->int_counter);
/* Clear the interrupt bit we expect to be set. */
qib_write_kreg(dd, kr_intclear, QIB_I_SPIOBUFAVAIL);
@@ -3243,9 +3242,7 @@ static irqreturn_t sdma_intr(int irq, void *data)
*/
return IRQ_HANDLED;
- qib_stats.sps_ints++;
- if (dd->int_counter != (u32) -1)
- dd->int_counter++;
+ this_cpu_inc(*dd->int_counter);
/* Clear the interrupt bit we expect to be set. */
qib_write_kreg(dd, kr_intclear, ppd->hw_pidx ?
@@ -3272,9 +3269,7 @@ static irqreturn_t sdma_idle_intr(int irq, void *data)
*/
return IRQ_HANDLED;
- qib_stats.sps_ints++;
- if (dd->int_counter != (u32) -1)
- dd->int_counter++;
+ this_cpu_inc(*dd->int_counter);
/* Clear the interrupt bit we expect to be set. */
qib_write_kreg(dd, kr_intclear, ppd->hw_pidx ?
@@ -3301,9 +3296,7 @@ static irqreturn_t sdma_progress_intr(int irq, void *data)
*/
return IRQ_HANDLED;
- qib_stats.sps_ints++;
- if (dd->int_counter != (u32) -1)
- dd->int_counter++;
+ this_cpu_inc(*dd->int_counter);
/* Clear the interrupt bit we expect to be set. */
qib_write_kreg(dd, kr_intclear, ppd->hw_pidx ?
@@ -3331,9 +3324,7 @@ static irqreturn_t sdma_cleanup_intr(int irq, void *data)
*/
return IRQ_HANDLED;
- qib_stats.sps_ints++;
- if (dd->int_counter != (u32) -1)
- dd->int_counter++;
+ this_cpu_inc(*dd->int_counter);
/* Clear the interrupt bit we expect to be set. */
qib_write_kreg(dd, kr_intclear, ppd->hw_pidx ?
@@ -3718,7 +3709,8 @@ static int qib_do_7322_reset(struct qib_devdata *dd)
dd->pport->cpspec->ibsymdelta = 0;
dd->pport->cpspec->iblnkerrdelta = 0;
dd->pport->cpspec->ibmalfdelta = 0;
- dd->int_counter = 0; /* so we check interrupts work again */
+ /* so we check interrupts work again */
+ dd->z_int_counter = qib_int_counter(dd);
/*
* Keep chip from being accessed until we are ready. Use
@@ -6552,7 +6544,11 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
}
dd->num_pports++;
- qib_init_pportdata(ppd, dd, pidx, dd->num_pports);
+ ret = qib_init_pportdata(ppd, dd, pidx, dd->num_pports);
+ if (ret) {
+ dd->num_pports--;
+ goto bail;
+ }
ppd->link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X;
ppd->link_width_enabled = IB_WIDTH_4X;
diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c
index 24e802f4ea2f..5b7aeb224a30 100644
--- a/drivers/infiniband/hw/qib/qib_init.c
+++ b/drivers/infiniband/hw/qib/qib_init.c
@@ -130,7 +130,6 @@ void qib_set_ctxtcnt(struct qib_devdata *dd)
int qib_create_ctxts(struct qib_devdata *dd)
{
unsigned i;
- int ret;
int local_node_id = pcibus_to_node(dd->pcidev->bus);
if (local_node_id < 0)
@@ -145,8 +144,7 @@ int qib_create_ctxts(struct qib_devdata *dd)
if (!dd->rcd) {
qib_dev_err(dd,
"Unable to allocate ctxtdata array, failing\n");
- ret = -ENOMEM;
- goto done;
+ return -ENOMEM;
}
/* create (one or more) kctxt */
@@ -163,15 +161,14 @@ int qib_create_ctxts(struct qib_devdata *dd)
if (!rcd) {
qib_dev_err(dd,
"Unable to allocate ctxtdata for Kernel ctxt, failing\n");
- ret = -ENOMEM;
- goto done;
+ kfree(dd->rcd);
+ dd->rcd = NULL;
+ return -ENOMEM;
}
rcd->pkeys[0] = QIB_DEFAULT_P_KEY;
rcd->seq_cnt = 1;
}
- ret = 0;
-done:
- return ret;
+ return 0;
}
/*
@@ -233,7 +230,7 @@ struct qib_ctxtdata *qib_create_ctxtdata(struct qib_pportdata *ppd, u32 ctxt,
/*
* Common code for initializing the physical port structure.
*/
-void qib_init_pportdata(struct qib_pportdata *ppd, struct qib_devdata *dd,
+int qib_init_pportdata(struct qib_pportdata *ppd, struct qib_devdata *dd,
u8 hw_pidx, u8 port)
{
int size;
@@ -243,6 +240,7 @@ void qib_init_pportdata(struct qib_pportdata *ppd, struct qib_devdata *dd,
spin_lock_init(&ppd->sdma_lock);
spin_lock_init(&ppd->lflags_lock);
+ spin_lock_init(&ppd->cc_shadow_lock);
init_waitqueue_head(&ppd->state_wait);
init_timer(&ppd->symerr_clear_timer);
@@ -250,8 +248,10 @@ void qib_init_pportdata(struct qib_pportdata *ppd, struct qib_devdata *dd,
ppd->symerr_clear_timer.data = (unsigned long)ppd;
ppd->qib_wq = NULL;
-
- spin_lock_init(&ppd->cc_shadow_lock);
+ ppd->ibport_data.pmastats =
+ alloc_percpu(struct qib_pma_counters);
+ if (!ppd->ibport_data.pmastats)
+ return -ENOMEM;
if (qib_cc_table_size < IB_CCT_MIN_ENTRIES)
goto bail;
@@ -299,7 +299,7 @@ void qib_init_pportdata(struct qib_pportdata *ppd, struct qib_devdata *dd,
goto bail_3;
}
- return;
+ return 0;
bail_3:
kfree(ppd->ccti_entries_shadow);
@@ -313,7 +313,7 @@ bail_1:
bail:
/* User is intentionally disabling the congestion control agent */
if (!qib_cc_table_size)
- return;
+ return 0;
if (qib_cc_table_size < IB_CCT_MIN_ENTRIES) {
qib_cc_table_size = 0;
@@ -324,7 +324,7 @@ bail:
qib_dev_err(dd, "Congestion Control Agent disabled for port %d\n",
port);
- return;
+ return 0;
}
static int init_pioavailregs(struct qib_devdata *dd)
@@ -525,6 +525,7 @@ static void enable_chip(struct qib_devdata *dd)
static void verify_interrupt(unsigned long opaque)
{
struct qib_devdata *dd = (struct qib_devdata *) opaque;
+ u64 int_counter;
if (!dd)
return; /* being torn down */
@@ -533,7 +534,8 @@ static void verify_interrupt(unsigned long opaque)
* If we don't have a lid or any interrupts, let the user know and
* don't bother checking again.
*/
- if (dd->int_counter == 0) {
+ int_counter = qib_int_counter(dd) - dd->z_int_counter;
+ if (int_counter == 0) {
if (!dd->f_intr_fallback(dd))
dev_err(&dd->pcidev->dev,
"No interrupts detected, not usable.\n");
@@ -633,6 +635,12 @@ wq_error:
return -ENOMEM;
}
+static void qib_free_pportdata(struct qib_pportdata *ppd)
+{
+ free_percpu(ppd->ibport_data.pmastats);
+ ppd->ibport_data.pmastats = NULL;
+}
+
/**
* qib_init - do the actual initialization sequence on the chip
* @dd: the qlogic_ib device
@@ -920,6 +928,7 @@ static void qib_shutdown_device(struct qib_devdata *dd)
destroy_workqueue(ppd->qib_wq);
ppd->qib_wq = NULL;
}
+ qib_free_pportdata(ppd);
}
qib_update_eeprom_log(dd);
@@ -1079,9 +1088,34 @@ void qib_free_devdata(struct qib_devdata *dd)
#ifdef CONFIG_DEBUG_FS
qib_dbg_ibdev_exit(&dd->verbs_dev);
#endif
+ free_percpu(dd->int_counter);
ib_dealloc_device(&dd->verbs_dev.ibdev);
}
+u64 qib_int_counter(struct qib_devdata *dd)
+{
+ int cpu;
+ u64 int_counter = 0;
+
+ for_each_possible_cpu(cpu)
+ int_counter += *per_cpu_ptr(dd->int_counter, cpu);
+ return int_counter;
+}
+
+u64 qib_sps_ints(void)
+{
+ unsigned long flags;
+ struct qib_devdata *dd;
+ u64 sps_ints = 0;
+
+ spin_lock_irqsave(&qib_devs_lock, flags);
+ list_for_each_entry(dd, &qib_dev_list, list) {
+ sps_ints += qib_int_counter(dd);
+ }
+ spin_unlock_irqrestore(&qib_devs_lock, flags);
+ return sps_ints;
+}
+
/*
* Allocate our primary per-unit data structure. Must be done via verbs
* allocator, because the verbs cleanup process both does cleanup and
@@ -1097,14 +1131,10 @@ struct qib_devdata *qib_alloc_devdata(struct pci_dev *pdev, size_t extra)
int ret;
dd = (struct qib_devdata *) ib_alloc_device(sizeof(*dd) + extra);
- if (!dd) {
- dd = ERR_PTR(-ENOMEM);
- goto bail;
- }
+ if (!dd)
+ return ERR_PTR(-ENOMEM);
-#ifdef CONFIG_DEBUG_FS
- qib_dbg_ibdev_init(&dd->verbs_dev);
-#endif
+ INIT_LIST_HEAD(&dd->list);
idr_preload(GFP_KERNEL);
spin_lock_irqsave(&qib_devs_lock, flags);
@@ -1121,11 +1151,13 @@ struct qib_devdata *qib_alloc_devdata(struct pci_dev *pdev, size_t extra)
if (ret < 0) {
qib_early_err(&pdev->dev,
"Could not allocate unit ID: error %d\n", -ret);
-#ifdef CONFIG_DEBUG_FS
- qib_dbg_ibdev_exit(&dd->verbs_dev);
-#endif
- ib_dealloc_device(&dd->verbs_dev.ibdev);
- dd = ERR_PTR(ret);
+ goto bail;
+ }
+ dd->int_counter = alloc_percpu(u64);
+ if (!dd->int_counter) {
+ ret = -ENOMEM;
+ qib_early_err(&pdev->dev,
+ "Could not allocate per-cpu int_counter\n");
goto bail;
}
@@ -1139,9 +1171,15 @@ struct qib_devdata *qib_alloc_devdata(struct pci_dev *pdev, size_t extra)
qib_early_err(&pdev->dev,
"Could not alloc cpulist info, cpu affinity might be wrong\n");
}
-
-bail:
+#ifdef CONFIG_DEBUG_FS
+ qib_dbg_ibdev_init(&dd->verbs_dev);
+#endif
return dd;
+bail:
+ if (!list_empty(&dd->list))
+ list_del_init(&dd->list);
+ ib_dealloc_device(&dd->verbs_dev.ibdev);
+ return ERR_PTR(ret);;
}
/*
diff --git a/drivers/infiniband/hw/qib/qib_mad.c b/drivers/infiniband/hw/qib/qib_mad.c
index ccb119143d20..edad991d60ed 100644
--- a/drivers/infiniband/hw/qib/qib_mad.c
+++ b/drivers/infiniband/hw/qib/qib_mad.c
@@ -1634,6 +1634,23 @@ static int pma_get_portcounters_cong(struct ib_pma_mad *pmp,
return reply((struct ib_smp *)pmp);
}
+static void qib_snapshot_pmacounters(
+ struct qib_ibport *ibp,
+ struct qib_pma_counters *pmacounters)
+{
+ struct qib_pma_counters *p;
+ int cpu;
+
+ memset(pmacounters, 0, sizeof(*pmacounters));
+ for_each_possible_cpu(cpu) {
+ p = per_cpu_ptr(ibp->pmastats, cpu);
+ pmacounters->n_unicast_xmit += p->n_unicast_xmit;
+ pmacounters->n_unicast_rcv += p->n_unicast_rcv;
+ pmacounters->n_multicast_xmit += p->n_multicast_xmit;
+ pmacounters->n_multicast_rcv += p->n_multicast_rcv;
+ }
+}
+
static int pma_get_portcounters_ext(struct ib_pma_mad *pmp,
struct ib_device *ibdev, u8 port)
{
@@ -1642,6 +1659,7 @@ static int pma_get_portcounters_ext(struct ib_pma_mad *pmp,
struct qib_ibport *ibp = to_iport(ibdev, port);
struct qib_pportdata *ppd = ppd_from_ibp(ibp);
u64 swords, rwords, spkts, rpkts, xwait;
+ struct qib_pma_counters pma;
u8 port_select = p->port_select;
memset(pmp->data, 0, sizeof(pmp->data));
@@ -1664,10 +1682,17 @@ static int pma_get_portcounters_ext(struct ib_pma_mad *pmp,
p->port_rcv_data = cpu_to_be64(rwords);
p->port_xmit_packets = cpu_to_be64(spkts);
p->port_rcv_packets = cpu_to_be64(rpkts);
- p->port_unicast_xmit_packets = cpu_to_be64(ibp->n_unicast_xmit);
- p->port_unicast_rcv_packets = cpu_to_be64(ibp->n_unicast_rcv);
- p->port_multicast_xmit_packets = cpu_to_be64(ibp->n_multicast_xmit);
- p->port_multicast_rcv_packets = cpu_to_be64(ibp->n_multicast_rcv);
+
+ qib_snapshot_pmacounters(ibp, &pma);
+
+ p->port_unicast_xmit_packets = cpu_to_be64(pma.n_unicast_xmit
+ - ibp->z_unicast_xmit);
+ p->port_unicast_rcv_packets = cpu_to_be64(pma.n_unicast_rcv
+ - ibp->z_unicast_rcv);
+ p->port_multicast_xmit_packets = cpu_to_be64(pma.n_multicast_xmit
+ - ibp->z_multicast_xmit);
+ p->port_multicast_rcv_packets = cpu_to_be64(pma.n_multicast_rcv
+ - ibp->z_multicast_rcv);
bail:
return reply((struct ib_smp *) pmp);
@@ -1795,6 +1820,7 @@ static int pma_set_portcounters_ext(struct ib_pma_mad *pmp,
struct qib_ibport *ibp = to_iport(ibdev, port);
struct qib_pportdata *ppd = ppd_from_ibp(ibp);
u64 swords, rwords, spkts, rpkts, xwait;
+ struct qib_pma_counters pma;
qib_snapshot_counters(ppd, &swords, &rwords, &spkts, &rpkts, &xwait);
@@ -1810,17 +1836,19 @@ static int pma_set_portcounters_ext(struct ib_pma_mad *pmp,
if (p->counter_select & IB_PMA_SELX_PORT_RCV_PACKETS)
ibp->z_port_rcv_packets = rpkts;
+ qib_snapshot_pmacounters(ibp, &pma);
+
if (p->counter_select & IB_PMA_SELX_PORT_UNI_XMIT_PACKETS)
- ibp->n_unicast_xmit = 0;
+ ibp->z_unicast_xmit = pma.n_unicast_xmit;
if (p->counter_select & IB_PMA_SELX_PORT_UNI_RCV_PACKETS)
- ibp->n_unicast_rcv = 0;
+ ibp->z_unicast_rcv = pma.n_unicast_rcv;
if (p->counter_select & IB_PMA_SELX_PORT_MULTI_XMIT_PACKETS)
- ibp->n_multicast_xmit = 0;
+ ibp->z_multicast_xmit = pma.n_multicast_xmit;
if (p->counter_select & IB_PMA_SELX_PORT_MULTI_RCV_PACKETS)
- ibp->n_multicast_rcv = 0;
+ ibp->z_multicast_rcv = pma.n_multicast_rcv;
return pma_get_portcounters_ext(pmp, ibdev, port);
}
diff --git a/drivers/infiniband/hw/qib/qib_mr.c b/drivers/infiniband/hw/qib/qib_mr.c
index e6687ded8210..9bbb55347cc1 100644
--- a/drivers/infiniband/hw/qib/qib_mr.c
+++ b/drivers/infiniband/hw/qib/qib_mr.c
@@ -232,8 +232,8 @@ struct ib_mr *qib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
{
struct qib_mr *mr;
struct ib_umem *umem;
- struct ib_umem_chunk *chunk;
- int n, m, i;
+ struct scatterlist *sg;
+ int n, m, entry;
struct ib_mr *ret;
if (length == 0) {
@@ -246,9 +246,7 @@ struct ib_mr *qib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
if (IS_ERR(umem))
return (void *) umem;
- n = 0;
- list_for_each_entry(chunk, &umem->chunk_list, list)
- n += chunk->nents;
+ n = umem->nmap;
mr = alloc_mr(n, pd);
if (IS_ERR(mr)) {
@@ -268,11 +266,10 @@ struct ib_mr *qib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
mr->mr.page_shift = ilog2(umem->page_size);
m = 0;
n = 0;
- list_for_each_entry(chunk, &umem->chunk_list, list) {
- for (i = 0; i < chunk->nents; i++) {
+ for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) {
void *vaddr;
- vaddr = page_address(sg_page(&chunk->page_list[i]));
+ vaddr = page_address(sg_page(sg));
if (!vaddr) {
ret = ERR_PTR(-EINVAL);
goto bail;
@@ -284,7 +281,6 @@ struct ib_mr *qib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
m++;
n = 0;
}
- }
}
ret = &mr->ibmr;
diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c
index 3ab341320ead..2f2501890c4e 100644
--- a/drivers/infiniband/hw/qib/qib_rc.c
+++ b/drivers/infiniband/hw/qib/qib_rc.c
@@ -752,7 +752,7 @@ void qib_send_rc_ack(struct qib_qp *qp)
qib_flush_wc();
qib_sendbuf_done(dd, pbufn);
- ibp->n_unicast_xmit++;
+ this_cpu_inc(ibp->pmastats->n_unicast_xmit);
goto done;
queue_ack:
diff --git a/drivers/infiniband/hw/qib/qib_ruc.c b/drivers/infiniband/hw/qib/qib_ruc.c
index 357b6cfcd46c..4c07a8b34ffe 100644
--- a/drivers/infiniband/hw/qib/qib_ruc.c
+++ b/drivers/infiniband/hw/qib/qib_ruc.c
@@ -703,6 +703,7 @@ void qib_make_ruc_header(struct qib_qp *qp, struct qib_other_headers *ohdr,
ohdr->bth[0] = cpu_to_be32(bth0);
ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
ohdr->bth[2] = cpu_to_be32(bth2);
+ this_cpu_inc(ibp->pmastats->n_unicast_xmit);
}
/**
diff --git a/drivers/infiniband/hw/qib/qib_ud.c b/drivers/infiniband/hw/qib/qib_ud.c
index 3ad651c3356c..aaf7039f8ed2 100644
--- a/drivers/infiniband/hw/qib/qib_ud.c
+++ b/drivers/infiniband/hw/qib/qib_ud.c
@@ -280,11 +280,11 @@ int qib_make_ud_req(struct qib_qp *qp)
ah_attr = &to_iah(wqe->wr.wr.ud.ah)->attr;
if (ah_attr->dlid >= QIB_MULTICAST_LID_BASE) {
if (ah_attr->dlid != QIB_PERMISSIVE_LID)
- ibp->n_multicast_xmit++;
+ this_cpu_inc(ibp->pmastats->n_multicast_xmit);
else
- ibp->n_unicast_xmit++;
+ this_cpu_inc(ibp->pmastats->n_unicast_xmit);
} else {
- ibp->n_unicast_xmit++;
+ this_cpu_inc(ibp->pmastats->n_unicast_xmit);
lid = ah_attr->dlid & ~((1 << ppd->lmc) - 1);
if (unlikely(lid == ppd->lid)) {
/*
diff --git a/drivers/infiniband/hw/qib/qib_user_sdma.c b/drivers/infiniband/hw/qib/qib_user_sdma.c
index 165aee2ca8a0..d2806cae234c 100644
--- a/drivers/infiniband/hw/qib/qib_user_sdma.c
+++ b/drivers/infiniband/hw/qib/qib_user_sdma.c
@@ -52,6 +52,17 @@
/* attempt to drain the queue for 5secs */
#define QIB_USER_SDMA_DRAIN_TIMEOUT 500
+/*
+ * track how many times a process open this driver.
+ */
+static struct rb_root qib_user_sdma_rb_root = RB_ROOT;
+
+struct qib_user_sdma_rb_node {
+ struct rb_node node;
+ int refcount;
+ pid_t pid;
+};
+
struct qib_user_sdma_pkt {
struct list_head list; /* list element */
@@ -120,15 +131,60 @@ struct qib_user_sdma_queue {
/* dma page table */
struct rb_root dma_pages_root;
+ struct qib_user_sdma_rb_node *sdma_rb_node;
+
/* protect everything above... */
struct mutex lock;
};
+static struct qib_user_sdma_rb_node *
+qib_user_sdma_rb_search(struct rb_root *root, pid_t pid)
+{
+ struct qib_user_sdma_rb_node *sdma_rb_node;
+ struct rb_node *node = root->rb_node;
+
+ while (node) {
+ sdma_rb_node = container_of(node,
+ struct qib_user_sdma_rb_node, node);
+ if (pid < sdma_rb_node->pid)
+ node = node->rb_left;
+ else if (pid > sdma_rb_node->pid)
+ node = node->rb_right;
+ else
+ return sdma_rb_node;
+ }
+ return NULL;
+}
+
+static int
+qib_user_sdma_rb_insert(struct rb_root *root, struct qib_user_sdma_rb_node *new)
+{
+ struct rb_node **node = &(root->rb_node);
+ struct rb_node *parent = NULL;
+ struct qib_user_sdma_rb_node *got;
+
+ while (*node) {
+ got = container_of(*node, struct qib_user_sdma_rb_node, node);
+ parent = *node;
+ if (new->pid < got->pid)
+ node = &((*node)->rb_left);
+ else if (new->pid > got->pid)
+ node = &((*node)->rb_right);
+ else
+ return 0;
+ }
+
+ rb_link_node(&new->node, parent, node);
+ rb_insert_color(&new->node, root);
+ return 1;
+}
+
struct qib_user_sdma_queue *
qib_user_sdma_queue_create(struct device *dev, int unit, int ctxt, int sctxt)
{
struct qib_user_sdma_queue *pq =
kmalloc(sizeof(struct qib_user_sdma_queue), GFP_KERNEL);
+ struct qib_user_sdma_rb_node *sdma_rb_node;
if (!pq)
goto done;
@@ -138,6 +194,7 @@ qib_user_sdma_queue_create(struct device *dev, int unit, int ctxt, int sctxt)
pq->num_pending = 0;
pq->num_sending = 0;
pq->added = 0;
+ pq->sdma_rb_node = NULL;
INIT_LIST_HEAD(&pq->sent);
spin_lock_init(&pq->sent_lock);
@@ -163,8 +220,30 @@ qib_user_sdma_queue_create(struct device *dev, int unit, int ctxt, int sctxt)
pq->dma_pages_root = RB_ROOT;
+ sdma_rb_node = qib_user_sdma_rb_search(&qib_user_sdma_rb_root,
+ current->pid);
+ if (sdma_rb_node) {
+ sdma_rb_node->refcount++;
+ } else {
+ int ret;
+ sdma_rb_node = kmalloc(sizeof(
+ struct qib_user_sdma_rb_node), GFP_KERNEL);
+ if (!sdma_rb_node)
+ goto err_rb;
+
+ sdma_rb_node->refcount = 1;
+ sdma_rb_node->pid = current->pid;
+
+ ret = qib_user_sdma_rb_insert(&qib_user_sdma_rb_root,
+ sdma_rb_node);
+ BUG_ON(ret == 0);
+ }
+ pq->sdma_rb_node = sdma_rb_node;
+
goto done;
+err_rb:
+ dma_pool_destroy(pq->header_cache);
err_slab:
kmem_cache_destroy(pq->pkt_slab);
err_kfree:
@@ -1020,8 +1099,13 @@ void qib_user_sdma_queue_destroy(struct qib_user_sdma_queue *pq)
if (!pq)
return;
- kmem_cache_destroy(pq->pkt_slab);
+ pq->sdma_rb_node->refcount--;
+ if (pq->sdma_rb_node->refcount == 0) {
+ rb_erase(&pq->sdma_rb_node->node, &qib_user_sdma_rb_root);
+ kfree(pq->sdma_rb_node);
+ }
dma_pool_destroy(pq->header_cache);
+ kmem_cache_destroy(pq->pkt_slab);
kfree(pq);
}
@@ -1241,26 +1325,52 @@ static int qib_user_sdma_push_pkts(struct qib_pportdata *ppd,
struct qib_user_sdma_queue *pq,
struct list_head *pktlist, int count)
{
- int ret = 0;
unsigned long flags;
if (unlikely(!(ppd->lflags & QIBL_LINKACTIVE)))
return -ECOMM;
- spin_lock_irqsave(&ppd->sdma_lock, flags);
-
- if (unlikely(!__qib_sdma_running(ppd))) {
- ret = -ECOMM;
- goto unlock;
+ /* non-blocking mode */
+ if (pq->sdma_rb_node->refcount > 1) {
+ spin_lock_irqsave(&ppd->sdma_lock, flags);
+ if (unlikely(!__qib_sdma_running(ppd))) {
+ spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+ return -ECOMM;
+ }
+ pq->num_pending += count;
+ list_splice_tail_init(pktlist, &ppd->sdma_userpending);
+ qib_user_sdma_send_desc(ppd, &ppd->sdma_userpending);
+ spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+ return 0;
}
+ /* In this case, descriptors from this process are not
+ * linked to ppd pending queue, interrupt handler
+ * won't update this process, it is OK to directly
+ * modify without sdma lock.
+ */
+
+
pq->num_pending += count;
- list_splice_tail_init(pktlist, &ppd->sdma_userpending);
- qib_user_sdma_send_desc(ppd, &ppd->sdma_userpending);
+ /*
+ * Blocking mode for single rail process, we must
+ * release/regain sdma_lock to give other process
+ * chance to make progress. This is important for
+ * performance.
+ */
+ do {
+ spin_lock_irqsave(&ppd->sdma_lock, flags);
+ if (unlikely(!__qib_sdma_running(ppd))) {
+ spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+ return -ECOMM;
+ }
+ qib_user_sdma_send_desc(ppd, pktlist);
+ if (!list_empty(pktlist))
+ qib_sdma_make_progress(ppd);
+ spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+ } while (!list_empty(pktlist));
-unlock:
- spin_unlock_irqrestore(&ppd->sdma_lock, flags);
- return ret;
+ return 0;
}
int qib_user_sdma_writev(struct qib_ctxtdata *rcd,
@@ -1290,7 +1400,7 @@ int qib_user_sdma_writev(struct qib_ctxtdata *rcd,
qib_user_sdma_queue_clean(ppd, pq);
while (dim) {
- int mxp = 8;
+ int mxp = 1;
int ndesc = 0;
ret = qib_user_sdma_queue_pkts(dd, ppd, pq,
diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c
index 092b0bb1bb78..9bcfbd842980 100644
--- a/drivers/infiniband/hw/qib/qib_verbs.c
+++ b/drivers/infiniband/hw/qib/qib_verbs.c
@@ -662,7 +662,7 @@ void qib_ib_rcv(struct qib_ctxtdata *rcd, void *rhdr, void *data, u32 tlen)
mcast = qib_mcast_find(ibp, &hdr->u.l.grh.dgid);
if (mcast == NULL)
goto drop;
- ibp->n_multicast_rcv++;
+ this_cpu_inc(ibp->pmastats->n_multicast_rcv);
list_for_each_entry_rcu(p, &mcast->qp_list, list)
qib_qp_rcv(rcd, hdr, 1, data, tlen, p->qp);
/*
@@ -678,8 +678,8 @@ void qib_ib_rcv(struct qib_ctxtdata *rcd, void *rhdr, void *data, u32 tlen)
&rcd->lookaside_qp->refcount))
wake_up(
&rcd->lookaside_qp->wait);
- rcd->lookaside_qp = NULL;
- }
+ rcd->lookaside_qp = NULL;
+ }
}
if (!rcd->lookaside_qp) {
qp = qib_lookup_qpn(ibp, qp_num);
@@ -689,7 +689,7 @@ void qib_ib_rcv(struct qib_ctxtdata *rcd, void *rhdr, void *data, u32 tlen)
rcd->lookaside_qpn = qp_num;
} else
qp = rcd->lookaside_qp;
- ibp->n_unicast_rcv++;
+ this_cpu_inc(ibp->pmastats->n_unicast_rcv);
qib_qp_rcv(rcd, hdr, lnh == QIB_LRH_GRH, data, tlen, qp);
}
return;
diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h
index a01c7d2cf541..bfc8948fdd35 100644
--- a/drivers/infiniband/hw/qib/qib_verbs.h
+++ b/drivers/infiniband/hw/qib/qib_verbs.h
@@ -664,6 +664,13 @@ struct qib_opcode_stats_perctx {
struct qib_opcode_stats stats[128];
};
+struct qib_pma_counters {
+ u64 n_unicast_xmit; /* total unicast packets sent */
+ u64 n_unicast_rcv; /* total unicast packets received */
+ u64 n_multicast_xmit; /* total multicast packets sent */
+ u64 n_multicast_rcv; /* total multicast packets received */
+};
+
struct qib_ibport {
struct qib_qp __rcu *qp0;
struct qib_qp __rcu *qp1;
@@ -680,10 +687,11 @@ struct qib_ibport {
__be64 mkey;
__be64 guids[QIB_GUIDS_PER_PORT - 1]; /* writable GUIDs */
u64 tid; /* TID for traps */
- u64 n_unicast_xmit; /* total unicast packets sent */
- u64 n_unicast_rcv; /* total unicast packets received */
- u64 n_multicast_xmit; /* total multicast packets sent */
- u64 n_multicast_rcv; /* total multicast packets received */
+ struct qib_pma_counters __percpu *pmastats;
+ u64 z_unicast_xmit; /* starting count for PMA */
+ u64 z_unicast_rcv; /* starting count for PMA */
+ u64 z_multicast_xmit; /* starting count for PMA */
+ u64 z_multicast_rcv; /* starting count for PMA */
u64 z_symbol_error_counter; /* starting count for PMA */
u64 z_link_error_recovery_counter; /* starting count for PMA */
u64 z_link_downed_counter; /* starting count for PMA */
diff --git a/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c b/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c
index 7ecc6061f1f4..f8dfd76be89f 100644
--- a/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c
+++ b/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c
@@ -629,6 +629,7 @@ static int qp_grp_id_from_flow(struct usnic_ib_qp_grp_flow *qp_flow,
{
enum usnic_transport_type trans_type = qp_flow->trans_type;
int err;
+ uint16_t port_num = 0;
switch (trans_type) {
case USNIC_TRANSPORT_ROCE_CUSTOM:
@@ -637,9 +638,15 @@ static int qp_grp_id_from_flow(struct usnic_ib_qp_grp_flow *qp_flow,
case USNIC_TRANSPORT_IPV4_UDP:
err = usnic_transport_sock_get_addr(qp_flow->udp.sock,
NULL, NULL,
- (uint16_t *) id);
+ &port_num);
if (err)
return err;
+ /*
+ * Copy port_num to stack first and then to *id,
+ * so that the short to int cast works for little
+ * and big endian systems.
+ */
+ *id = port_num;
break;
default:
usnic_err("Unsupported transport %u\n", trans_type);
diff --git a/drivers/infiniband/hw/usnic/usnic_uiom.c b/drivers/infiniband/hw/usnic/usnic_uiom.c
index 16755cdab2c0..801a1d6937e4 100644
--- a/drivers/infiniband/hw/usnic/usnic_uiom.c
+++ b/drivers/infiniband/hw/usnic/usnic_uiom.c
@@ -286,7 +286,7 @@ iter_chunk:
err = iommu_map(pd->domain, va_start, pa_start,
size, flags);
if (err) {
- usnic_err("Failed to map va 0x%lx pa 0x%pa size 0x%zx with err %d\n",
+ usnic_err("Failed to map va 0x%lx pa %pa size 0x%zx with err %d\n",
va_start, &pa_start, size, err);
goto err_out;
}
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index dd03cfe596d6..25f195ef44b0 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -5,7 +5,7 @@
* Copyright (C) 2004 Alex Aizman
* Copyright (C) 2005 Mike Christie
* Copyright (c) 2005, 2006 Voltaire, Inc. All rights reserved.
- * Copyright (c) 2013 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2013-2014 Mellanox Technologies. All rights reserved.
* maintained by openib-general@openib.org
*
* This software is available to you under a choice of one of two
@@ -82,6 +82,8 @@ static unsigned int iscsi_max_lun = 512;
module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
int iser_debug_level = 0;
+bool iser_pi_enable = false;
+int iser_pi_guard = 0;
MODULE_DESCRIPTION("iSER (iSCSI Extensions for RDMA) Datamover");
MODULE_LICENSE("Dual BSD/GPL");
@@ -91,6 +93,12 @@ MODULE_VERSION(DRV_VER);
module_param_named(debug_level, iser_debug_level, int, 0644);
MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0 (default:disabled)");
+module_param_named(pi_enable, iser_pi_enable, bool, 0644);
+MODULE_PARM_DESC(pi_enable, "Enable T10-PI offload support (default:disabled)");
+
+module_param_named(pi_guard, iser_pi_guard, int, 0644);
+MODULE_PARM_DESC(pi_guard, "T10-PI guard_type, 0:CRC|1:IP_CSUM (default:CRC)");
+
struct iser_global ig;
void
@@ -138,8 +146,8 @@ static int iscsi_iser_pdu_alloc(struct iscsi_task *task, uint8_t opcode)
int iser_initialize_task_headers(struct iscsi_task *task,
struct iser_tx_desc *tx_desc)
{
- struct iscsi_iser_conn *iser_conn = task->conn->dd_data;
- struct iser_device *device = iser_conn->ib_conn->device;
+ struct iser_conn *ib_conn = task->conn->dd_data;
+ struct iser_device *device = ib_conn->device;
struct iscsi_iser_task *iser_task = task->dd_data;
u64 dma_addr;
@@ -153,7 +161,7 @@ int iser_initialize_task_headers(struct iscsi_task *task,
tx_desc->tx_sg[0].length = ISER_HEADERS_LEN;
tx_desc->tx_sg[0].lkey = device->mr->lkey;
- iser_task->iser_conn = iser_conn;
+ iser_task->ib_conn = ib_conn;
return 0;
}
/**
@@ -176,6 +184,8 @@ iscsi_iser_task_init(struct iscsi_task *task)
iser_task->command_sent = 0;
iser_task_rdma_init(iser_task);
+ iser_task->sc = task->sc;
+
return 0;
}
@@ -278,10 +288,9 @@ iscsi_iser_task_xmit(struct iscsi_task *task)
static void iscsi_iser_cleanup_task(struct iscsi_task *task)
{
struct iscsi_iser_task *iser_task = task->dd_data;
- struct iser_tx_desc *tx_desc = &iser_task->desc;
-
- struct iscsi_iser_conn *iser_conn = task->conn->dd_data;
- struct iser_device *device = iser_conn->ib_conn->device;
+ struct iser_tx_desc *tx_desc = &iser_task->desc;
+ struct iser_conn *ib_conn = task->conn->dd_data;
+ struct iser_device *device = ib_conn->device;
ib_dma_unmap_single(device->ib_device,
tx_desc->dma_addr, ISER_HEADERS_LEN, DMA_TO_DEVICE);
@@ -296,14 +305,25 @@ static void iscsi_iser_cleanup_task(struct iscsi_task *task)
}
}
+static u8 iscsi_iser_check_protection(struct iscsi_task *task, sector_t *sector)
+{
+ struct iscsi_iser_task *iser_task = task->dd_data;
+
+ if (iser_task->dir[ISER_DIR_IN])
+ return iser_check_task_pi_status(iser_task, ISER_DIR_IN,
+ sector);
+ else
+ return iser_check_task_pi_status(iser_task, ISER_DIR_OUT,
+ sector);
+}
+
static struct iscsi_cls_conn *
iscsi_iser_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
{
struct iscsi_conn *conn;
struct iscsi_cls_conn *cls_conn;
- struct iscsi_iser_conn *iser_conn;
- cls_conn = iscsi_conn_setup(cls_session, sizeof(*iser_conn), conn_idx);
+ cls_conn = iscsi_conn_setup(cls_session, 0, conn_idx);
if (!cls_conn)
return NULL;
conn = cls_conn->dd_data;
@@ -314,10 +334,6 @@ iscsi_iser_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
*/
conn->max_recv_dlength = ISER_RECV_DATA_SEG_LEN;
- iser_conn = conn->dd_data;
- conn->dd_data = iser_conn;
- iser_conn->iscsi_conn = conn;
-
return cls_conn;
}
@@ -325,8 +341,7 @@ static void
iscsi_iser_conn_destroy(struct iscsi_cls_conn *cls_conn)
{
struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_iser_conn *iser_conn = conn->dd_data;
- struct iser_conn *ib_conn = iser_conn->ib_conn;
+ struct iser_conn *ib_conn = conn->dd_data;
iscsi_conn_teardown(cls_conn);
/*
@@ -335,7 +350,7 @@ iscsi_iser_conn_destroy(struct iscsi_cls_conn *cls_conn)
* we free it here.
*/
if (ib_conn) {
- ib_conn->iser_conn = NULL;
+ ib_conn->iscsi_conn = NULL;
iser_conn_put(ib_conn, 1); /* deref iscsi/ib conn unbinding */
}
}
@@ -346,7 +361,6 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session,
int is_leading)
{
struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_iser_conn *iser_conn;
struct iscsi_session *session;
struct iser_conn *ib_conn;
struct iscsi_endpoint *ep;
@@ -373,11 +387,11 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session,
/* binds the iSER connection retrieved from the previously
* connected ep_handle to the iSCSI layer connection. exchanges
* connection pointers */
- iser_info("binding iscsi/iser conn %p %p to ib_conn %p\n",
- conn, conn->dd_data, ib_conn);
- iser_conn = conn->dd_data;
- ib_conn->iser_conn = iser_conn;
- iser_conn->ib_conn = ib_conn;
+ iser_info("binding iscsi conn %p to ib_conn %p\n", conn, ib_conn);
+
+ conn->dd_data = ib_conn;
+ ib_conn->iscsi_conn = conn;
+
iser_conn_get(ib_conn); /* ref iscsi/ib conn binding */
return 0;
}
@@ -386,8 +400,7 @@ static void
iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
{
struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_iser_conn *iser_conn = conn->dd_data;
- struct iser_conn *ib_conn = iser_conn->ib_conn;
+ struct iser_conn *ib_conn = conn->dd_data;
/*
* Userspace may have goofed up and not bound the connection or
@@ -401,7 +414,7 @@ iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
*/
iser_conn_put(ib_conn, 1); /* deref iscsi/ib conn unbinding */
}
- iser_conn->ib_conn = NULL;
+ conn->dd_data = NULL;
}
static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session)
@@ -413,6 +426,17 @@ static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session)
iscsi_host_free(shost);
}
+static inline unsigned int
+iser_dif_prot_caps(int prot_caps)
+{
+ return ((prot_caps & IB_PROT_T10DIF_TYPE_1) ? SHOST_DIF_TYPE1_PROTECTION |
+ SHOST_DIX_TYPE1_PROTECTION : 0) |
+ ((prot_caps & IB_PROT_T10DIF_TYPE_2) ? SHOST_DIF_TYPE2_PROTECTION |
+ SHOST_DIX_TYPE2_PROTECTION : 0) |
+ ((prot_caps & IB_PROT_T10DIF_TYPE_3) ? SHOST_DIF_TYPE3_PROTECTION |
+ SHOST_DIX_TYPE3_PROTECTION : 0);
+}
+
static struct iscsi_cls_session *
iscsi_iser_session_create(struct iscsi_endpoint *ep,
uint16_t cmds_max, uint16_t qdepth,
@@ -437,8 +461,18 @@ iscsi_iser_session_create(struct iscsi_endpoint *ep,
* older userspace tools (before 2.0-870) did not pass us
* the leading conn's ep so this will be NULL;
*/
- if (ep)
+ if (ep) {
ib_conn = ep->dd_data;
+ if (ib_conn->pi_support) {
+ u32 sig_caps = ib_conn->device->dev_attr.sig_prot_cap;
+
+ scsi_host_set_prot(shost, iser_dif_prot_caps(sig_caps));
+ if (iser_pi_guard)
+ scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP);
+ else
+ scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
+ }
+ }
if (iscsi_host_add(shost,
ep ? ib_conn->device->ib_device->dma_device : NULL))
@@ -618,7 +652,7 @@ iscsi_iser_ep_disconnect(struct iscsi_endpoint *ep)
struct iser_conn *ib_conn;
ib_conn = ep->dd_data;
- if (ib_conn->iser_conn)
+ if (ib_conn->iscsi_conn)
/*
* Must suspend xmit path if the ep is bound to the
* iscsi_conn, so we know we are not accessing the ib_conn
@@ -626,7 +660,7 @@ iscsi_iser_ep_disconnect(struct iscsi_endpoint *ep)
*
* This may not be bound if the ep poll failed.
*/
- iscsi_suspend_tx(ib_conn->iser_conn->iscsi_conn);
+ iscsi_suspend_tx(ib_conn->iscsi_conn);
iser_info("ib conn %p state %d\n", ib_conn, ib_conn->state);
@@ -732,6 +766,7 @@ static struct iscsi_transport iscsi_iser_transport = {
.xmit_task = iscsi_iser_task_xmit,
.cleanup_task = iscsi_iser_cleanup_task,
.alloc_pdu = iscsi_iser_pdu_alloc,
+ .check_protection = iscsi_iser_check_protection,
/* recovery */
.session_recovery_timedout = iscsi_session_recovery_timedout,
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 67914027c614..324129f80d40 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -8,7 +8,7 @@
*
* Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved.
* Copyright (c) 2005, 2006 Cisco Systems. All rights reserved.
- * Copyright (c) 2013 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2013-2014 Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -46,6 +46,8 @@
#include <linux/printk.h>
#include <scsi/libiscsi.h>
#include <scsi/scsi_transport_iscsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
@@ -67,7 +69,7 @@
#define DRV_NAME "iser"
#define PFX DRV_NAME ": "
-#define DRV_VER "1.1"
+#define DRV_VER "1.3"
#define iser_dbg(fmt, arg...) \
do { \
@@ -134,10 +136,21 @@
ISER_MAX_TX_MISC_PDUS + \
ISER_MAX_RX_MISC_PDUS)
+/* Max registration work requests per command */
+#define ISER_MAX_REG_WR_PER_CMD 5
+
+/* For Signature we don't support DATAOUTs so no need to make room for them */
+#define ISER_QP_SIG_MAX_REQ_DTOS (ISER_DEF_XMIT_CMDS_MAX * \
+ (1 + ISER_MAX_REG_WR_PER_CMD) + \
+ ISER_MAX_TX_MISC_PDUS + \
+ ISER_MAX_RX_MISC_PDUS)
+
#define ISER_VER 0x10
#define ISER_WSV 0x08
#define ISER_RSV 0x04
+#define ISER_FASTREG_LI_WRID 0xffffffffffffffffULL
+
struct iser_hdr {
u8 flags;
u8 rsvd[3];
@@ -201,7 +214,6 @@ struct iser_data_buf {
/* fwd declarations */
struct iser_device;
struct iser_cq_desc;
-struct iscsi_iser_conn;
struct iscsi_iser_task;
struct iscsi_endpoint;
@@ -258,6 +270,7 @@ struct iscsi_iser_task;
struct iser_device {
struct ib_device *ib_device;
struct ib_pd *pd;
+ struct ib_device_attr dev_attr;
struct ib_cq *rx_cq[ISER_MAX_CQ];
struct ib_cq *tx_cq[ISER_MAX_CQ];
struct ib_mr *mr;
@@ -277,17 +290,35 @@ struct iser_device {
enum iser_data_dir cmd_dir);
};
+#define ISER_CHECK_GUARD 0xc0
+#define ISER_CHECK_REFTAG 0x0f
+#define ISER_CHECK_APPTAG 0x30
+
+enum iser_reg_indicator {
+ ISER_DATA_KEY_VALID = 1 << 0,
+ ISER_PROT_KEY_VALID = 1 << 1,
+ ISER_SIG_KEY_VALID = 1 << 2,
+ ISER_FASTREG_PROTECTED = 1 << 3,
+};
+
+struct iser_pi_context {
+ struct ib_mr *prot_mr;
+ struct ib_fast_reg_page_list *prot_frpl;
+ struct ib_mr *sig_mr;
+};
+
struct fast_reg_descriptor {
struct list_head list;
/* For fast registration - FRWR */
struct ib_mr *data_mr;
struct ib_fast_reg_page_list *data_frpl;
- /* Valid for fast registration flag */
- bool valid;
+ struct iser_pi_context *pi_ctx;
+ /* registration indicators container */
+ u8 reg_indicators;
};
struct iser_conn {
- struct iscsi_iser_conn *iser_conn; /* iser conn for upcalls */
+ struct iscsi_conn *iscsi_conn;
struct iscsi_endpoint *ep;
enum iser_ib_conn_state state; /* rdma connection state */
atomic_t refcount;
@@ -310,6 +341,9 @@ struct iser_conn {
unsigned int rx_desc_head;
struct iser_rx_desc *rx_descs;
struct ib_recv_wr rx_wr[ISER_MIN_POSTED_RX];
+ bool pi_support;
+
+ /* Connection memory registration pool */
union {
struct {
struct ib_fmr_pool *pool; /* pool of IB FMRs */
@@ -319,24 +353,22 @@ struct iser_conn {
struct {
struct list_head pool;
int pool_size;
- } frwr;
- } fastreg;
-};
-
-struct iscsi_iser_conn {
- struct iscsi_conn *iscsi_conn;/* ptr to iscsi conn */
- struct iser_conn *ib_conn; /* iSER IB conn */
+ } fastreg;
+ };
};
struct iscsi_iser_task {
struct iser_tx_desc desc;
- struct iscsi_iser_conn *iser_conn;
+ struct iser_conn *ib_conn;
enum iser_task_status status;
+ struct scsi_cmnd *sc;
int command_sent; /* set if command sent */
int dir[ISER_DIRS_NUM]; /* set if dir use*/
struct iser_regd_buf rdma_regd[ISER_DIRS_NUM];/* regd rdma buf */
struct iser_data_buf data[ISER_DIRS_NUM]; /* orig. data des*/
struct iser_data_buf data_copy[ISER_DIRS_NUM];/* contig. copy */
+ struct iser_data_buf prot[ISER_DIRS_NUM]; /* prot desc */
+ struct iser_data_buf prot_copy[ISER_DIRS_NUM];/* prot copy */
};
struct iser_page_vec {
@@ -362,6 +394,8 @@ struct iser_global {
extern struct iser_global ig;
extern int iser_debug_level;
+extern bool iser_pi_enable;
+extern int iser_pi_guard;
/* allocate connection resources needed for rdma functionality */
int iser_conn_set_full_featured_mode(struct iscsi_conn *conn);
@@ -401,13 +435,15 @@ void iser_task_rdma_finalize(struct iscsi_iser_task *task);
void iser_free_rx_descriptors(struct iser_conn *ib_conn);
-void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *task,
- enum iser_data_dir cmd_dir);
+void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *iser_task,
+ struct iser_data_buf *mem,
+ struct iser_data_buf *mem_copy,
+ enum iser_data_dir cmd_dir);
int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *task,
enum iser_data_dir cmd_dir);
-int iser_reg_rdma_mem_frwr(struct iscsi_iser_task *task,
- enum iser_data_dir cmd_dir);
+int iser_reg_rdma_mem_fastreg(struct iscsi_iser_task *task,
+ enum iser_data_dir cmd_dir);
int iser_connect(struct iser_conn *ib_conn,
struct sockaddr_in *src_addr,
@@ -420,8 +456,8 @@ int iser_reg_page_vec(struct iser_conn *ib_conn,
void iser_unreg_mem_fmr(struct iscsi_iser_task *iser_task,
enum iser_data_dir cmd_dir);
-void iser_unreg_mem_frwr(struct iscsi_iser_task *iser_task,
- enum iser_data_dir cmd_dir);
+void iser_unreg_mem_fastreg(struct iscsi_iser_task *iser_task,
+ enum iser_data_dir cmd_dir);
int iser_post_recvl(struct iser_conn *ib_conn);
int iser_post_recvm(struct iser_conn *ib_conn, int count);
@@ -432,12 +468,15 @@ int iser_dma_map_task_data(struct iscsi_iser_task *iser_task,
enum iser_data_dir iser_dir,
enum dma_data_direction dma_dir);
-void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task);
+void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task,
+ struct iser_data_buf *data);
int iser_initialize_task_headers(struct iscsi_task *task,
struct iser_tx_desc *tx_desc);
int iser_alloc_rx_descriptors(struct iser_conn *ib_conn, struct iscsi_session *session);
int iser_create_fmr_pool(struct iser_conn *ib_conn, unsigned cmds_max);
void iser_free_fmr_pool(struct iser_conn *ib_conn);
-int iser_create_frwr_pool(struct iser_conn *ib_conn, unsigned cmds_max);
-void iser_free_frwr_pool(struct iser_conn *ib_conn);
+int iser_create_fastreg_pool(struct iser_conn *ib_conn, unsigned cmds_max);
+void iser_free_fastreg_pool(struct iser_conn *ib_conn);
+u8 iser_check_task_pi_status(struct iscsi_iser_task *iser_task,
+ enum iser_data_dir cmd_dir, sector_t *sector);
#endif
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 538822684d5b..2e2d903db838 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved.
- * Copyright (c) 2013 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2013-2014 Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -49,7 +49,7 @@ static int iser_prepare_read_cmd(struct iscsi_task *task,
{
struct iscsi_iser_task *iser_task = task->dd_data;
- struct iser_device *device = iser_task->iser_conn->ib_conn->device;
+ struct iser_device *device = iser_task->ib_conn->device;
struct iser_regd_buf *regd_buf;
int err;
struct iser_hdr *hdr = &iser_task->desc.iser_header;
@@ -62,11 +62,22 @@ static int iser_prepare_read_cmd(struct iscsi_task *task,
if (err)
return err;
+ if (scsi_prot_sg_count(iser_task->sc)) {
+ struct iser_data_buf *pbuf_in = &iser_task->prot[ISER_DIR_IN];
+
+ err = iser_dma_map_task_data(iser_task,
+ pbuf_in,
+ ISER_DIR_IN,
+ DMA_FROM_DEVICE);
+ if (err)
+ return err;
+ }
+
if (edtl > iser_task->data[ISER_DIR_IN].data_len) {
iser_err("Total data length: %ld, less than EDTL: "
"%d, in READ cmd BHS itt: %d, conn: 0x%p\n",
iser_task->data[ISER_DIR_IN].data_len, edtl,
- task->itt, iser_task->iser_conn);
+ task->itt, iser_task->ib_conn);
return -EINVAL;
}
@@ -99,7 +110,7 @@ iser_prepare_write_cmd(struct iscsi_task *task,
unsigned int edtl)
{
struct iscsi_iser_task *iser_task = task->dd_data;
- struct iser_device *device = iser_task->iser_conn->ib_conn->device;
+ struct iser_device *device = iser_task->ib_conn->device;
struct iser_regd_buf *regd_buf;
int err;
struct iser_hdr *hdr = &iser_task->desc.iser_header;
@@ -113,6 +124,17 @@ iser_prepare_write_cmd(struct iscsi_task *task,
if (err)
return err;
+ if (scsi_prot_sg_count(iser_task->sc)) {
+ struct iser_data_buf *pbuf_out = &iser_task->prot[ISER_DIR_OUT];
+
+ err = iser_dma_map_task_data(iser_task,
+ pbuf_out,
+ ISER_DIR_OUT,
+ DMA_TO_DEVICE);
+ if (err)
+ return err;
+ }
+
if (edtl > iser_task->data[ISER_DIR_OUT].data_len) {
iser_err("Total data length: %ld, less than EDTL: %d, "
"in WRITE cmd BHS itt: %d, conn: 0x%p\n",
@@ -327,7 +349,7 @@ free_login_buf:
static int iser_post_rx_bufs(struct iscsi_conn *conn, struct iscsi_hdr *req)
{
- struct iscsi_iser_conn *iser_conn = conn->dd_data;
+ struct iser_conn *ib_conn = conn->dd_data;
struct iscsi_session *session = conn->session;
iser_dbg("req op %x flags %x\n", req->opcode, req->flags);
@@ -340,19 +362,18 @@ static int iser_post_rx_bufs(struct iscsi_conn *conn, struct iscsi_hdr *req)
* response) and no posted send buffers left - they must have been
* consumed during previous login phases.
*/
- WARN_ON(iser_conn->ib_conn->post_recv_buf_count != 1);
- WARN_ON(atomic_read(&iser_conn->ib_conn->post_send_buf_count) != 0);
+ WARN_ON(ib_conn->post_recv_buf_count != 1);
+ WARN_ON(atomic_read(&ib_conn->post_send_buf_count) != 0);
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_conn->ib_conn->min_posted_rx);
+ ib_conn->min_posted_rx);
/* Initial post receive buffers */
- if (iser_post_recvm(iser_conn->ib_conn,
- iser_conn->ib_conn->min_posted_rx))
+ if (iser_post_recvm(ib_conn, ib_conn->min_posted_rx))
return -ENOMEM;
return 0;
@@ -364,11 +385,11 @@ static int iser_post_rx_bufs(struct iscsi_conn *conn, struct iscsi_hdr *req)
int iser_send_command(struct iscsi_conn *conn,
struct iscsi_task *task)
{
- struct iscsi_iser_conn *iser_conn = conn->dd_data;
+ struct iser_conn *ib_conn = conn->dd_data;
struct iscsi_iser_task *iser_task = task->dd_data;
unsigned long edtl;
int err;
- struct iser_data_buf *data_buf;
+ struct iser_data_buf *data_buf, *prot_buf;
struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)task->hdr;
struct scsi_cmnd *sc = task->sc;
struct iser_tx_desc *tx_desc = &iser_task->desc;
@@ -377,20 +398,28 @@ int iser_send_command(struct iscsi_conn *conn,
/* build the tx desc regd header and add it to the tx desc dto */
tx_desc->type = ISCSI_TX_SCSI_COMMAND;
- iser_create_send_desc(iser_conn->ib_conn, tx_desc);
+ iser_create_send_desc(ib_conn, tx_desc);
- if (hdr->flags & ISCSI_FLAG_CMD_READ)
+ if (hdr->flags & ISCSI_FLAG_CMD_READ) {
data_buf = &iser_task->data[ISER_DIR_IN];
- else
+ prot_buf = &iser_task->prot[ISER_DIR_IN];
+ } else {
data_buf = &iser_task->data[ISER_DIR_OUT];
+ prot_buf = &iser_task->prot[ISER_DIR_OUT];
+ }
if (scsi_sg_count(sc)) { /* using a scatter list */
data_buf->buf = scsi_sglist(sc);
data_buf->size = scsi_sg_count(sc);
}
-
data_buf->data_len = scsi_bufflen(sc);
+ if (scsi_prot_sg_count(sc)) {
+ prot_buf->buf = scsi_prot_sglist(sc);
+ prot_buf->size = scsi_prot_sg_count(sc);
+ prot_buf->data_len = sc->prot_sdb->length;
+ }
+
if (hdr->flags & ISCSI_FLAG_CMD_READ) {
err = iser_prepare_read_cmd(task, edtl);
if (err)
@@ -408,7 +437,7 @@ int iser_send_command(struct iscsi_conn *conn,
iser_task->status = ISER_TASK_STATUS_STARTED;
- err = iser_post_send(iser_conn->ib_conn, tx_desc);
+ err = iser_post_send(ib_conn, tx_desc);
if (!err)
return 0;
@@ -424,7 +453,7 @@ int iser_send_data_out(struct iscsi_conn *conn,
struct iscsi_task *task,
struct iscsi_data *hdr)
{
- struct iscsi_iser_conn *iser_conn = conn->dd_data;
+ struct iser_conn *ib_conn = conn->dd_data;
struct iscsi_iser_task *iser_task = task->dd_data;
struct iser_tx_desc *tx_desc = NULL;
struct iser_regd_buf *regd_buf;
@@ -473,7 +502,7 @@ int iser_send_data_out(struct iscsi_conn *conn,
itt, buf_offset, data_seg_len);
- err = iser_post_send(iser_conn->ib_conn, tx_desc);
+ err = iser_post_send(ib_conn, tx_desc);
if (!err)
return 0;
@@ -486,19 +515,18 @@ send_data_out_error:
int iser_send_control(struct iscsi_conn *conn,
struct iscsi_task *task)
{
- struct iscsi_iser_conn *iser_conn = conn->dd_data;
+ struct iser_conn *ib_conn = conn->dd_data;
struct iscsi_iser_task *iser_task = task->dd_data;
struct iser_tx_desc *mdesc = &iser_task->desc;
unsigned long data_seg_len;
int err = 0;
struct iser_device *device;
- struct iser_conn *ib_conn = iser_conn->ib_conn;
/* build the tx desc regd header and add it to the tx desc dto */
mdesc->type = ISCSI_TX_CONTROL;
- iser_create_send_desc(iser_conn->ib_conn, mdesc);
+ iser_create_send_desc(ib_conn, mdesc);
- device = iser_conn->ib_conn->device;
+ device = ib_conn->device;
data_seg_len = ntoh24(task->hdr->dlength);
@@ -513,14 +541,13 @@ int iser_send_control(struct iscsi_conn *conn,
ib_conn->login_req_dma, task->data_count,
DMA_TO_DEVICE);
- memcpy(iser_conn->ib_conn->login_req_buf, task->data,
- task->data_count);
+ memcpy(ib_conn->login_req_buf, task->data, task->data_count);
ib_dma_sync_single_for_device(device->ib_device,
ib_conn->login_req_dma, task->data_count,
DMA_TO_DEVICE);
- tx_dsg->addr = iser_conn->ib_conn->login_req_dma;
+ tx_dsg->addr = ib_conn->login_req_dma;
tx_dsg->length = task->data_count;
tx_dsg->lkey = device->mr->lkey;
mdesc->num_sge = 2;
@@ -529,7 +556,7 @@ 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);
+ err = iser_post_recvl(ib_conn);
if (err)
goto send_control_error;
err = iser_post_rx_bufs(conn, task->hdr);
@@ -537,7 +564,7 @@ int iser_send_control(struct iscsi_conn *conn,
goto send_control_error;
}
- err = iser_post_send(iser_conn->ib_conn, mdesc);
+ err = iser_post_send(ib_conn, mdesc);
if (!err)
return 0;
@@ -553,7 +580,6 @@ void iser_rcv_completion(struct iser_rx_desc *rx_desc,
unsigned long rx_xfer_len,
struct iser_conn *ib_conn)
{
- struct iscsi_iser_conn *conn = ib_conn->iser_conn;
struct iscsi_hdr *hdr;
u64 rx_dma;
int rx_buflen, outstanding, count, err;
@@ -575,17 +601,17 @@ void iser_rcv_completion(struct iser_rx_desc *rx_desc,
iser_dbg("op 0x%x itt 0x%x dlen %d\n", hdr->opcode,
hdr->itt, (int)(rx_xfer_len - ISER_HEADERS_LEN));
- iscsi_iser_recv(conn->iscsi_conn, hdr,
- rx_desc->data, rx_xfer_len - ISER_HEADERS_LEN);
+ iscsi_iser_recv(ib_conn->iscsi_conn, hdr, rx_desc->data,
+ rx_xfer_len - ISER_HEADERS_LEN);
ib_dma_sync_single_for_device(ib_conn->device->ib_device, rx_dma,
- rx_buflen, DMA_FROM_DEVICE);
+ rx_buflen, DMA_FROM_DEVICE);
/* decrementing conn->post_recv_buf_count only --after-- freeing the *
* task eliminates the need to worry on tasks which are completed in *
* parallel to the execution of iser_conn_term. So the code that waits *
* for the posted rx bufs refcount to become zero handles everything */
- conn->ib_conn->post_recv_buf_count--;
+ ib_conn->post_recv_buf_count--;
if (rx_dma == ib_conn->login_resp_dma)
return;
@@ -610,11 +636,12 @@ void iser_snd_completion(struct iser_tx_desc *tx_desc,
ib_dma_unmap_single(device->ib_device, tx_desc->dma_addr,
ISER_HEADERS_LEN, DMA_TO_DEVICE);
kmem_cache_free(ig.desc_cache, tx_desc);
+ tx_desc = NULL;
}
atomic_dec(&ib_conn->post_send_buf_count);
- if (tx_desc->type == ISCSI_TX_CONTROL) {
+ if (tx_desc && tx_desc->type == ISCSI_TX_CONTROL) {
/* this arithmetic is legal by libiscsi dd_data allocation */
task = (void *) ((long)(void *)tx_desc -
sizeof(struct iscsi_task));
@@ -634,6 +661,9 @@ void iser_task_rdma_init(struct iscsi_iser_task *iser_task)
iser_task->data[ISER_DIR_IN].data_len = 0;
iser_task->data[ISER_DIR_OUT].data_len = 0;
+ iser_task->prot[ISER_DIR_IN].data_len = 0;
+ iser_task->prot[ISER_DIR_OUT].data_len = 0;
+
memset(&iser_task->rdma_regd[ISER_DIR_IN], 0,
sizeof(struct iser_regd_buf));
memset(&iser_task->rdma_regd[ISER_DIR_OUT], 0,
@@ -642,28 +672,63 @@ void iser_task_rdma_init(struct iscsi_iser_task *iser_task)
void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task)
{
- struct iser_device *device = iser_task->iser_conn->ib_conn->device;
- int is_rdma_aligned = 1;
+ struct iser_device *device = iser_task->ib_conn->device;
+ int is_rdma_data_aligned = 1;
+ int is_rdma_prot_aligned = 1;
+ int prot_count = scsi_prot_sg_count(iser_task->sc);
/* if we were reading, copy back to unaligned sglist,
* anyway dma_unmap and free the copy
*/
if (iser_task->data_copy[ISER_DIR_IN].copy_buf != NULL) {
- is_rdma_aligned = 0;
- iser_finalize_rdma_unaligned_sg(iser_task, ISER_DIR_IN);
+ is_rdma_data_aligned = 0;
+ iser_finalize_rdma_unaligned_sg(iser_task,
+ &iser_task->data[ISER_DIR_IN],
+ &iser_task->data_copy[ISER_DIR_IN],
+ ISER_DIR_IN);
}
+
if (iser_task->data_copy[ISER_DIR_OUT].copy_buf != NULL) {
- is_rdma_aligned = 0;
- iser_finalize_rdma_unaligned_sg(iser_task, ISER_DIR_OUT);
+ is_rdma_data_aligned = 0;
+ iser_finalize_rdma_unaligned_sg(iser_task,
+ &iser_task->data[ISER_DIR_OUT],
+ &iser_task->data_copy[ISER_DIR_OUT],
+ ISER_DIR_OUT);
+ }
+
+ if (iser_task->prot_copy[ISER_DIR_IN].copy_buf != NULL) {
+ is_rdma_prot_aligned = 0;
+ iser_finalize_rdma_unaligned_sg(iser_task,
+ &iser_task->prot[ISER_DIR_IN],
+ &iser_task->prot_copy[ISER_DIR_IN],
+ ISER_DIR_IN);
+ }
+
+ if (iser_task->prot_copy[ISER_DIR_OUT].copy_buf != NULL) {
+ is_rdma_prot_aligned = 0;
+ iser_finalize_rdma_unaligned_sg(iser_task,
+ &iser_task->prot[ISER_DIR_OUT],
+ &iser_task->prot_copy[ISER_DIR_OUT],
+ ISER_DIR_OUT);
}
- if (iser_task->dir[ISER_DIR_IN])
+ if (iser_task->dir[ISER_DIR_IN]) {
device->iser_unreg_rdma_mem(iser_task, ISER_DIR_IN);
+ if (is_rdma_data_aligned)
+ iser_dma_unmap_task_data(iser_task,
+ &iser_task->data[ISER_DIR_IN]);
+ if (prot_count && is_rdma_prot_aligned)
+ iser_dma_unmap_task_data(iser_task,
+ &iser_task->prot[ISER_DIR_IN]);
+ }
- if (iser_task->dir[ISER_DIR_OUT])
+ if (iser_task->dir[ISER_DIR_OUT]) {
device->iser_unreg_rdma_mem(iser_task, ISER_DIR_OUT);
-
- /* if the data was unaligned, it was already unmapped and then copied */
- if (is_rdma_aligned)
- iser_dma_unmap_task_data(iser_task);
+ if (is_rdma_data_aligned)
+ iser_dma_unmap_task_data(iser_task,
+ &iser_task->data[ISER_DIR_OUT]);
+ if (prot_count && is_rdma_prot_aligned)
+ iser_dma_unmap_task_data(iser_task,
+ &iser_task->prot[ISER_DIR_OUT]);
+ }
}
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c
index 1ce0c97d2ccb..47acd3ad3a17 100644
--- a/drivers/infiniband/ulp/iser/iser_memory.c
+++ b/drivers/infiniband/ulp/iser/iser_memory.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved.
- * Copyright (c) 2013 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2013-2014 Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -45,13 +45,19 @@
* iser_start_rdma_unaligned_sg
*/
static int iser_start_rdma_unaligned_sg(struct iscsi_iser_task *iser_task,
+ struct iser_data_buf *data,
+ struct iser_data_buf *data_copy,
enum iser_data_dir cmd_dir)
{
- int dma_nents;
- struct ib_device *dev;
+ struct ib_device *dev = iser_task->ib_conn->device->ib_device;
+ struct scatterlist *sgl = (struct scatterlist *)data->buf;
+ struct scatterlist *sg;
char *mem = NULL;
- struct iser_data_buf *data = &iser_task->data[cmd_dir];
- unsigned long cmd_data_len = data->data_len;
+ unsigned long cmd_data_len = 0;
+ int dma_nents, i;
+
+ for_each_sg(sgl, sg, data->size, i)
+ cmd_data_len += ib_sg_dma_len(dev, sg);
if (cmd_data_len > ISER_KMALLOC_THRESHOLD)
mem = (void *)__get_free_pages(GFP_ATOMIC,
@@ -61,17 +67,16 @@ static int iser_start_rdma_unaligned_sg(struct iscsi_iser_task *iser_task,
if (mem == NULL) {
iser_err("Failed to allocate mem size %d %d for copying sglist\n",
- data->size,(int)cmd_data_len);
+ data->size, (int)cmd_data_len);
return -ENOMEM;
}
if (cmd_dir == ISER_DIR_OUT) {
/* copy the unaligned sg the buffer which is used for RDMA */
- struct scatterlist *sgl = (struct scatterlist *)data->buf;
- struct scatterlist *sg;
int i;
char *p, *from;
+ sgl = (struct scatterlist *)data->buf;
p = mem;
for_each_sg(sgl, sg, data->size, i) {
from = kmap_atomic(sg_page(sg));
@@ -83,39 +88,37 @@ static int iser_start_rdma_unaligned_sg(struct iscsi_iser_task *iser_task,
}
}
- sg_init_one(&iser_task->data_copy[cmd_dir].sg_single, mem, cmd_data_len);
- iser_task->data_copy[cmd_dir].buf =
- &iser_task->data_copy[cmd_dir].sg_single;
- iser_task->data_copy[cmd_dir].size = 1;
+ sg_init_one(&data_copy->sg_single, mem, cmd_data_len);
+ data_copy->buf = &data_copy->sg_single;
+ data_copy->size = 1;
+ data_copy->copy_buf = mem;
- iser_task->data_copy[cmd_dir].copy_buf = mem;
-
- dev = iser_task->iser_conn->ib_conn->device->ib_device;
- dma_nents = ib_dma_map_sg(dev,
- &iser_task->data_copy[cmd_dir].sg_single,
- 1,
+ dma_nents = ib_dma_map_sg(dev, &data_copy->sg_single, 1,
(cmd_dir == ISER_DIR_OUT) ?
DMA_TO_DEVICE : DMA_FROM_DEVICE);
BUG_ON(dma_nents == 0);
- iser_task->data_copy[cmd_dir].dma_nents = dma_nents;
+ data_copy->dma_nents = dma_nents;
+ data_copy->data_len = cmd_data_len;
+
return 0;
}
/**
* iser_finalize_rdma_unaligned_sg
*/
+
void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *iser_task,
- enum iser_data_dir cmd_dir)
+ struct iser_data_buf *data,
+ struct iser_data_buf *data_copy,
+ enum iser_data_dir cmd_dir)
{
struct ib_device *dev;
- struct iser_data_buf *mem_copy;
unsigned long cmd_data_len;
- dev = iser_task->iser_conn->ib_conn->device->ib_device;
- mem_copy = &iser_task->data_copy[cmd_dir];
+ dev = iser_task->ib_conn->device->ib_device;
- ib_dma_unmap_sg(dev, &mem_copy->sg_single, 1,
+ ib_dma_unmap_sg(dev, &data_copy->sg_single, 1,
(cmd_dir == ISER_DIR_OUT) ?
DMA_TO_DEVICE : DMA_FROM_DEVICE);
@@ -127,10 +130,10 @@ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *iser_task,
int i;
/* copy back read RDMA to unaligned sg */
- mem = mem_copy->copy_buf;
+ mem = data_copy->copy_buf;
- sgl = (struct scatterlist *)iser_task->data[ISER_DIR_IN].buf;
- sg_size = iser_task->data[ISER_DIR_IN].size;
+ sgl = (struct scatterlist *)data->buf;
+ sg_size = data->size;
p = mem;
for_each_sg(sgl, sg, sg_size, i) {
@@ -143,15 +146,15 @@ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *iser_task,
}
}
- cmd_data_len = iser_task->data[cmd_dir].data_len;
+ cmd_data_len = data->data_len;
if (cmd_data_len > ISER_KMALLOC_THRESHOLD)
- free_pages((unsigned long)mem_copy->copy_buf,
+ free_pages((unsigned long)data_copy->copy_buf,
ilog2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
else
- kfree(mem_copy->copy_buf);
+ kfree(data_copy->copy_buf);
- mem_copy->copy_buf = NULL;
+ data_copy->copy_buf = NULL;
}
#define IS_4K_ALIGNED(addr) ((((unsigned long)addr) & ~MASK_4K) == 0)
@@ -319,7 +322,7 @@ int iser_dma_map_task_data(struct iscsi_iser_task *iser_task,
struct ib_device *dev;
iser_task->dir[iser_dir] = 1;
- dev = iser_task->iser_conn->ib_conn->device->ib_device;
+ dev = iser_task->ib_conn->device->ib_device;
data->dma_nents = ib_dma_map_sg(dev, data->buf, data->size, dma_dir);
if (data->dma_nents == 0) {
@@ -329,31 +332,23 @@ int iser_dma_map_task_data(struct iscsi_iser_task *iser_task,
return 0;
}
-void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task)
+void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task,
+ struct iser_data_buf *data)
{
struct ib_device *dev;
- struct iser_data_buf *data;
- dev = iser_task->iser_conn->ib_conn->device->ib_device;
-
- if (iser_task->dir[ISER_DIR_IN]) {
- data = &iser_task->data[ISER_DIR_IN];
- ib_dma_unmap_sg(dev, data->buf, data->size, DMA_FROM_DEVICE);
- }
-
- if (iser_task->dir[ISER_DIR_OUT]) {
- data = &iser_task->data[ISER_DIR_OUT];
- ib_dma_unmap_sg(dev, data->buf, data->size, DMA_TO_DEVICE);
- }
+ dev = iser_task->ib_conn->device->ib_device;
+ ib_dma_unmap_sg(dev, data->buf, data->size, DMA_FROM_DEVICE);
}
static int fall_to_bounce_buf(struct iscsi_iser_task *iser_task,
struct ib_device *ibdev,
+ struct iser_data_buf *mem,
+ struct iser_data_buf *mem_copy,
enum iser_data_dir cmd_dir,
int aligned_len)
{
- struct iscsi_conn *iscsi_conn = iser_task->iser_conn->iscsi_conn;
- struct iser_data_buf *mem = &iser_task->data[cmd_dir];
+ struct iscsi_conn *iscsi_conn = iser_task->ib_conn->iscsi_conn;
iscsi_conn->fmr_unalign_cnt++;
iser_warn("rdma alignment violation (%d/%d aligned) or FMR not supported\n",
@@ -363,12 +358,12 @@ static int fall_to_bounce_buf(struct iscsi_iser_task *iser_task,
iser_data_buf_dump(mem, ibdev);
/* unmap the command data before accessing it */
- iser_dma_unmap_task_data(iser_task);
+ iser_dma_unmap_task_data(iser_task, mem);
/* allocate copy buf, if we are writing, copy the */
/* unaligned scatterlist, dma map the copy */
- if (iser_start_rdma_unaligned_sg(iser_task, cmd_dir) != 0)
- return -ENOMEM;
+ if (iser_start_rdma_unaligned_sg(iser_task, mem, mem_copy, cmd_dir) != 0)
+ return -ENOMEM;
return 0;
}
@@ -382,7 +377,7 @@ static int fall_to_bounce_buf(struct iscsi_iser_task *iser_task,
int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *iser_task,
enum iser_data_dir cmd_dir)
{
- struct iser_conn *ib_conn = iser_task->iser_conn->ib_conn;
+ struct iser_conn *ib_conn = iser_task->ib_conn;
struct iser_device *device = ib_conn->device;
struct ib_device *ibdev = device->ib_device;
struct iser_data_buf *mem = &iser_task->data[cmd_dir];
@@ -396,7 +391,8 @@ int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *iser_task,
aligned_len = iser_data_buf_aligned_len(mem, ibdev);
if (aligned_len != mem->dma_nents) {
- err = fall_to_bounce_buf(iser_task, ibdev,
+ err = fall_to_bounce_buf(iser_task, ibdev, mem,
+ &iser_task->data_copy[cmd_dir],
cmd_dir, aligned_len);
if (err) {
iser_err("failed to allocate bounce buffer\n");
@@ -422,8 +418,8 @@ int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *iser_task,
(unsigned long)regd_buf->reg.va,
(unsigned long)regd_buf->reg.len);
} else { /* use FMR for multiple dma entries */
- iser_page_vec_build(mem, ib_conn->fastreg.fmr.page_vec, ibdev);
- err = iser_reg_page_vec(ib_conn, ib_conn->fastreg.fmr.page_vec,
+ iser_page_vec_build(mem, ib_conn->fmr.page_vec, ibdev);
+ err = iser_reg_page_vec(ib_conn, ib_conn->fmr.page_vec,
&regd_buf->reg);
if (err && err != -EAGAIN) {
iser_data_buf_dump(mem, ibdev);
@@ -431,12 +427,12 @@ int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *iser_task,
mem->dma_nents,
ntoh24(iser_task->desc.iscsi_header.dlength));
iser_err("page_vec: data_size = 0x%x, length = %d, offset = 0x%x\n",
- ib_conn->fastreg.fmr.page_vec->data_size,
- ib_conn->fastreg.fmr.page_vec->length,
- ib_conn->fastreg.fmr.page_vec->offset);
- for (i = 0; i < ib_conn->fastreg.fmr.page_vec->length; i++)
+ ib_conn->fmr.page_vec->data_size,
+ ib_conn->fmr.page_vec->length,
+ ib_conn->fmr.page_vec->offset);
+ for (i = 0; i < ib_conn->fmr.page_vec->length; i++)
iser_err("page_vec[%d] = 0x%llx\n", i,
- (unsigned long long) ib_conn->fastreg.fmr.page_vec->pages[i]);
+ (unsigned long long) ib_conn->fmr.page_vec->pages[i]);
}
if (err)
return err;
@@ -444,94 +440,280 @@ int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *iser_task,
return 0;
}
-static int iser_fast_reg_mr(struct fast_reg_descriptor *desc,
- struct iser_conn *ib_conn,
+static inline enum ib_t10_dif_type
+scsi2ib_prot_type(unsigned char prot_type)
+{
+ switch (prot_type) {
+ case SCSI_PROT_DIF_TYPE0:
+ return IB_T10DIF_NONE;
+ case SCSI_PROT_DIF_TYPE1:
+ return IB_T10DIF_TYPE1;
+ case SCSI_PROT_DIF_TYPE2:
+ return IB_T10DIF_TYPE2;
+ case SCSI_PROT_DIF_TYPE3:
+ return IB_T10DIF_TYPE3;
+ default:
+ return IB_T10DIF_NONE;
+ }
+}
+
+
+static int
+iser_set_sig_attrs(struct scsi_cmnd *sc, struct ib_sig_attrs *sig_attrs)
+{
+ unsigned char scsi_ptype = scsi_get_prot_type(sc);
+
+ sig_attrs->mem.sig_type = IB_SIG_TYPE_T10_DIF;
+ sig_attrs->wire.sig_type = IB_SIG_TYPE_T10_DIF;
+ sig_attrs->mem.sig.dif.pi_interval = sc->device->sector_size;
+ sig_attrs->wire.sig.dif.pi_interval = sc->device->sector_size;
+
+ switch (scsi_get_prot_op(sc)) {
+ case SCSI_PROT_WRITE_INSERT:
+ case SCSI_PROT_READ_STRIP:
+ sig_attrs->mem.sig.dif.type = IB_T10DIF_NONE;
+ sig_attrs->wire.sig.dif.type = scsi2ib_prot_type(scsi_ptype);
+ sig_attrs->wire.sig.dif.bg_type = IB_T10DIF_CRC;
+ sig_attrs->wire.sig.dif.ref_tag = scsi_get_lba(sc) &
+ 0xffffffff;
+ break;
+ case SCSI_PROT_READ_INSERT:
+ case SCSI_PROT_WRITE_STRIP:
+ sig_attrs->mem.sig.dif.type = scsi2ib_prot_type(scsi_ptype);
+ sig_attrs->mem.sig.dif.bg_type = IB_T10DIF_CRC;
+ sig_attrs->mem.sig.dif.ref_tag = scsi_get_lba(sc) &
+ 0xffffffff;
+ sig_attrs->wire.sig.dif.type = IB_T10DIF_NONE;
+ break;
+ case SCSI_PROT_READ_PASS:
+ case SCSI_PROT_WRITE_PASS:
+ sig_attrs->mem.sig.dif.type = scsi2ib_prot_type(scsi_ptype);
+ sig_attrs->mem.sig.dif.bg_type = IB_T10DIF_CRC;
+ sig_attrs->mem.sig.dif.ref_tag = scsi_get_lba(sc) &
+ 0xffffffff;
+ sig_attrs->wire.sig.dif.type = scsi2ib_prot_type(scsi_ptype);
+ sig_attrs->wire.sig.dif.bg_type = IB_T10DIF_CRC;
+ sig_attrs->wire.sig.dif.ref_tag = scsi_get_lba(sc) &
+ 0xffffffff;
+ break;
+ default:
+ iser_err("Unsupported PI operation %d\n",
+ scsi_get_prot_op(sc));
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+static int
+iser_set_prot_checks(struct scsi_cmnd *sc, u8 *mask)
+{
+ switch (scsi_get_prot_type(sc)) {
+ case SCSI_PROT_DIF_TYPE0:
+ *mask = 0x0;
+ break;
+ case SCSI_PROT_DIF_TYPE1:
+ case SCSI_PROT_DIF_TYPE2:
+ *mask = ISER_CHECK_GUARD | ISER_CHECK_REFTAG;
+ break;
+ case SCSI_PROT_DIF_TYPE3:
+ *mask = ISER_CHECK_GUARD;
+ break;
+ default:
+ iser_err("Unsupported protection type %d\n",
+ scsi_get_prot_type(sc));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+iser_reg_sig_mr(struct iscsi_iser_task *iser_task,
+ struct fast_reg_descriptor *desc, struct ib_sge *data_sge,
+ struct ib_sge *prot_sge, struct ib_sge *sig_sge)
+{
+ struct iser_conn *ib_conn = iser_task->ib_conn;
+ struct iser_pi_context *pi_ctx = desc->pi_ctx;
+ struct ib_send_wr sig_wr, inv_wr;
+ struct ib_send_wr *bad_wr, *wr = NULL;
+ struct ib_sig_attrs sig_attrs;
+ int ret;
+ u32 key;
+
+ memset(&sig_attrs, 0, sizeof(sig_attrs));
+ ret = iser_set_sig_attrs(iser_task->sc, &sig_attrs);
+ if (ret)
+ goto err;
+
+ ret = iser_set_prot_checks(iser_task->sc, &sig_attrs.check_mask);
+ if (ret)
+ goto err;
+
+ if (!(desc->reg_indicators & ISER_SIG_KEY_VALID)) {
+ memset(&inv_wr, 0, sizeof(inv_wr));
+ inv_wr.opcode = IB_WR_LOCAL_INV;
+ inv_wr.wr_id = ISER_FASTREG_LI_WRID;
+ inv_wr.ex.invalidate_rkey = pi_ctx->sig_mr->rkey;
+ wr = &inv_wr;
+ /* Bump the key */
+ key = (u8)(pi_ctx->sig_mr->rkey & 0x000000FF);
+ ib_update_fast_reg_key(pi_ctx->sig_mr, ++key);
+ }
+
+ memset(&sig_wr, 0, sizeof(sig_wr));
+ sig_wr.opcode = IB_WR_REG_SIG_MR;
+ sig_wr.wr_id = ISER_FASTREG_LI_WRID;
+ sig_wr.sg_list = data_sge;
+ sig_wr.num_sge = 1;
+ sig_wr.wr.sig_handover.sig_attrs = &sig_attrs;
+ sig_wr.wr.sig_handover.sig_mr = pi_ctx->sig_mr;
+ if (scsi_prot_sg_count(iser_task->sc))
+ sig_wr.wr.sig_handover.prot = prot_sge;
+ sig_wr.wr.sig_handover.access_flags = IB_ACCESS_LOCAL_WRITE |
+ IB_ACCESS_REMOTE_READ |
+ IB_ACCESS_REMOTE_WRITE;
+
+ if (!wr)
+ wr = &sig_wr;
+ else
+ wr->next = &sig_wr;
+
+ ret = ib_post_send(ib_conn->qp, wr, &bad_wr);
+ if (ret) {
+ iser_err("reg_sig_mr failed, ret:%d\n", ret);
+ goto err;
+ }
+ desc->reg_indicators &= ~ISER_SIG_KEY_VALID;
+
+ sig_sge->lkey = pi_ctx->sig_mr->lkey;
+ sig_sge->addr = 0;
+ sig_sge->length = data_sge->length + prot_sge->length;
+ if (scsi_get_prot_op(iser_task->sc) == SCSI_PROT_WRITE_INSERT ||
+ scsi_get_prot_op(iser_task->sc) == SCSI_PROT_READ_STRIP) {
+ sig_sge->length += (data_sge->length /
+ iser_task->sc->device->sector_size) * 8;
+ }
+
+ iser_dbg("sig_sge: addr: 0x%llx length: %u lkey: 0x%x\n",
+ sig_sge->addr, sig_sge->length,
+ sig_sge->lkey);
+err:
+ return ret;
+}
+
+static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task,
struct iser_regd_buf *regd_buf,
- u32 offset, unsigned int data_size,
- unsigned int page_list_len)
+ struct iser_data_buf *mem,
+ enum iser_reg_indicator ind,
+ struct ib_sge *sge)
{
+ struct fast_reg_descriptor *desc = regd_buf->reg.mem_h;
+ struct iser_conn *ib_conn = iser_task->ib_conn;
+ struct iser_device *device = ib_conn->device;
+ struct ib_device *ibdev = device->ib_device;
+ struct ib_mr *mr;
+ struct ib_fast_reg_page_list *frpl;
struct ib_send_wr fastreg_wr, inv_wr;
struct ib_send_wr *bad_wr, *wr = NULL;
u8 key;
- int ret;
+ int ret, offset, size, plen;
+
+ /* if there a single dma entry, dma mr suffices */
+ if (mem->dma_nents == 1) {
+ struct scatterlist *sg = (struct scatterlist *)mem->buf;
- if (!desc->valid) {
+ sge->lkey = device->mr->lkey;
+ sge->addr = ib_sg_dma_address(ibdev, &sg[0]);
+ sge->length = ib_sg_dma_len(ibdev, &sg[0]);
+
+ iser_dbg("Single DMA entry: lkey=0x%x, addr=0x%llx, length=0x%x\n",
+ sge->lkey, sge->addr, sge->length);
+ return 0;
+ }
+
+ if (ind == ISER_DATA_KEY_VALID) {
+ mr = desc->data_mr;
+ frpl = desc->data_frpl;
+ } else {
+ mr = desc->pi_ctx->prot_mr;
+ frpl = desc->pi_ctx->prot_frpl;
+ }
+
+ plen = iser_sg_to_page_vec(mem, device->ib_device, frpl->page_list,
+ &offset, &size);
+ if (plen * SIZE_4K < size) {
+ iser_err("fast reg page_list too short to hold this SG\n");
+ return -EINVAL;
+ }
+
+ if (!(desc->reg_indicators & ind)) {
memset(&inv_wr, 0, sizeof(inv_wr));
+ inv_wr.wr_id = ISER_FASTREG_LI_WRID;
inv_wr.opcode = IB_WR_LOCAL_INV;
- inv_wr.send_flags = IB_SEND_SIGNALED;
- inv_wr.ex.invalidate_rkey = desc->data_mr->rkey;
+ inv_wr.ex.invalidate_rkey = mr->rkey;
wr = &inv_wr;
/* Bump the key */
- key = (u8)(desc->data_mr->rkey & 0x000000FF);
- ib_update_fast_reg_key(desc->data_mr, ++key);
+ key = (u8)(mr->rkey & 0x000000FF);
+ ib_update_fast_reg_key(mr, ++key);
}
/* Prepare FASTREG WR */
memset(&fastreg_wr, 0, sizeof(fastreg_wr));
+ fastreg_wr.wr_id = ISER_FASTREG_LI_WRID;
fastreg_wr.opcode = IB_WR_FAST_REG_MR;
- fastreg_wr.send_flags = IB_SEND_SIGNALED;
- fastreg_wr.wr.fast_reg.iova_start = desc->data_frpl->page_list[0] + offset;
- fastreg_wr.wr.fast_reg.page_list = desc->data_frpl;
- fastreg_wr.wr.fast_reg.page_list_len = page_list_len;
+ fastreg_wr.wr.fast_reg.iova_start = frpl->page_list[0] + offset;
+ fastreg_wr.wr.fast_reg.page_list = frpl;
+ fastreg_wr.wr.fast_reg.page_list_len = plen;
fastreg_wr.wr.fast_reg.page_shift = SHIFT_4K;
- fastreg_wr.wr.fast_reg.length = data_size;
- fastreg_wr.wr.fast_reg.rkey = desc->data_mr->rkey;
+ fastreg_wr.wr.fast_reg.length = size;
+ fastreg_wr.wr.fast_reg.rkey = mr->rkey;
fastreg_wr.wr.fast_reg.access_flags = (IB_ACCESS_LOCAL_WRITE |
IB_ACCESS_REMOTE_WRITE |
IB_ACCESS_REMOTE_READ);
- if (!wr) {
+ if (!wr)
wr = &fastreg_wr;
- atomic_inc(&ib_conn->post_send_buf_count);
- } else {
+ else
wr->next = &fastreg_wr;
- atomic_add(2, &ib_conn->post_send_buf_count);
- }
ret = ib_post_send(ib_conn->qp, wr, &bad_wr);
if (ret) {
- if (bad_wr->next)
- atomic_sub(2, &ib_conn->post_send_buf_count);
- else
- atomic_dec(&ib_conn->post_send_buf_count);
iser_err("fast registration failed, ret:%d\n", ret);
return ret;
}
- desc->valid = false;
+ desc->reg_indicators &= ~ind;
- regd_buf->reg.mem_h = desc;
- regd_buf->reg.lkey = desc->data_mr->lkey;
- regd_buf->reg.rkey = desc->data_mr->rkey;
- regd_buf->reg.va = desc->data_frpl->page_list[0] + offset;
- regd_buf->reg.len = data_size;
- regd_buf->reg.is_mr = 1;
+ sge->lkey = mr->lkey;
+ sge->addr = frpl->page_list[0] + offset;
+ sge->length = size;
return ret;
}
/**
- * iser_reg_rdma_mem_frwr - Registers memory intended for RDMA,
+ * iser_reg_rdma_mem_fastreg - Registers memory intended for RDMA,
* using Fast Registration WR (if possible) obtaining rkey and va
*
* returns 0 on success, errno code on failure
*/
-int iser_reg_rdma_mem_frwr(struct iscsi_iser_task *iser_task,
- enum iser_data_dir cmd_dir)
+int iser_reg_rdma_mem_fastreg(struct iscsi_iser_task *iser_task,
+ enum iser_data_dir cmd_dir)
{
- struct iser_conn *ib_conn = iser_task->iser_conn->ib_conn;
+ struct iser_conn *ib_conn = iser_task->ib_conn;
struct iser_device *device = ib_conn->device;
struct ib_device *ibdev = device->ib_device;
struct iser_data_buf *mem = &iser_task->data[cmd_dir];
struct iser_regd_buf *regd_buf = &iser_task->rdma_regd[cmd_dir];
- struct fast_reg_descriptor *desc;
- unsigned int data_size, page_list_len;
+ struct fast_reg_descriptor *desc = NULL;
+ struct ib_sge data_sge;
int err, aligned_len;
unsigned long flags;
- u32 offset;
aligned_len = iser_data_buf_aligned_len(mem, ibdev);
if (aligned_len != mem->dma_nents) {
- err = fall_to_bounce_buf(iser_task, ibdev,
+ err = fall_to_bounce_buf(iser_task, ibdev, mem,
+ &iser_task->data_copy[cmd_dir],
cmd_dir, aligned_len);
if (err) {
iser_err("failed to allocate bounce buffer\n");
@@ -540,41 +722,79 @@ int iser_reg_rdma_mem_frwr(struct iscsi_iser_task *iser_task,
mem = &iser_task->data_copy[cmd_dir];
}
- /* if there a single dma entry, dma mr suffices */
- if (mem->dma_nents == 1) {
- struct scatterlist *sg = (struct scatterlist *)mem->buf;
-
- regd_buf->reg.lkey = device->mr->lkey;
- regd_buf->reg.rkey = device->mr->rkey;
- regd_buf->reg.len = ib_sg_dma_len(ibdev, &sg[0]);
- regd_buf->reg.va = ib_sg_dma_address(ibdev, &sg[0]);
- regd_buf->reg.is_mr = 0;
- } else {
+ if (mem->dma_nents != 1 ||
+ scsi_get_prot_op(iser_task->sc) != SCSI_PROT_NORMAL) {
spin_lock_irqsave(&ib_conn->lock, flags);
- desc = list_first_entry(&ib_conn->fastreg.frwr.pool,
+ desc = list_first_entry(&ib_conn->fastreg.pool,
struct fast_reg_descriptor, list);
list_del(&desc->list);
spin_unlock_irqrestore(&ib_conn->lock, flags);
- page_list_len = iser_sg_to_page_vec(mem, device->ib_device,
- desc->data_frpl->page_list,
- &offset, &data_size);
-
- if (page_list_len * SIZE_4K < data_size) {
- iser_err("fast reg page_list too short to hold this SG\n");
- err = -EINVAL;
- goto err_reg;
+ regd_buf->reg.mem_h = desc;
+ }
+
+ err = iser_fast_reg_mr(iser_task, regd_buf, mem,
+ ISER_DATA_KEY_VALID, &data_sge);
+ if (err)
+ goto err_reg;
+
+ if (scsi_get_prot_op(iser_task->sc) != SCSI_PROT_NORMAL) {
+ struct ib_sge prot_sge, sig_sge;
+
+ memset(&prot_sge, 0, sizeof(prot_sge));
+ if (scsi_prot_sg_count(iser_task->sc)) {
+ mem = &iser_task->prot[cmd_dir];
+ aligned_len = iser_data_buf_aligned_len(mem, ibdev);
+ if (aligned_len != mem->dma_nents) {
+ err = fall_to_bounce_buf(iser_task, ibdev, mem,
+ &iser_task->prot_copy[cmd_dir],
+ cmd_dir, aligned_len);
+ if (err) {
+ iser_err("failed to allocate bounce buffer\n");
+ return err;
+ }
+ mem = &iser_task->prot_copy[cmd_dir];
+ }
+
+ err = iser_fast_reg_mr(iser_task, regd_buf, mem,
+ ISER_PROT_KEY_VALID, &prot_sge);
+ if (err)
+ goto err_reg;
}
- err = iser_fast_reg_mr(desc, ib_conn, regd_buf,
- offset, data_size, page_list_len);
- if (err)
- goto err_reg;
+ err = iser_reg_sig_mr(iser_task, desc, &data_sge,
+ &prot_sge, &sig_sge);
+ if (err) {
+ iser_err("Failed to register signature mr\n");
+ return err;
+ }
+ desc->reg_indicators |= ISER_FASTREG_PROTECTED;
+
+ regd_buf->reg.lkey = sig_sge.lkey;
+ regd_buf->reg.rkey = desc->pi_ctx->sig_mr->rkey;
+ regd_buf->reg.va = sig_sge.addr;
+ regd_buf->reg.len = sig_sge.length;
+ regd_buf->reg.is_mr = 1;
+ } else {
+ if (desc) {
+ regd_buf->reg.rkey = desc->data_mr->rkey;
+ regd_buf->reg.is_mr = 1;
+ } else {
+ regd_buf->reg.rkey = device->mr->rkey;
+ regd_buf->reg.is_mr = 0;
+ }
+
+ regd_buf->reg.lkey = data_sge.lkey;
+ regd_buf->reg.va = data_sge.addr;
+ regd_buf->reg.len = data_sge.length;
}
return 0;
err_reg:
- spin_lock_irqsave(&ib_conn->lock, flags);
- list_add_tail(&desc->list, &ib_conn->fastreg.frwr.pool);
- spin_unlock_irqrestore(&ib_conn->lock, flags);
+ if (desc) {
+ spin_lock_irqsave(&ib_conn->lock, flags);
+ list_add_tail(&desc->list, &ib_conn->fastreg.pool);
+ spin_unlock_irqrestore(&ib_conn->lock, flags);
+ }
+
return err;
}
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index afe95674008b..32849f2becde 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved.
* Copyright (c) 2005, 2006 Cisco Systems. All rights reserved.
- * Copyright (c) 2013 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2013-2014 Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -71,17 +71,14 @@ static void iser_event_handler(struct ib_event_handler *handler,
*/
static int iser_create_device_ib_res(struct iser_device *device)
{
- int i, j;
struct iser_cq_desc *cq_desc;
- struct ib_device_attr *dev_attr;
+ struct ib_device_attr *dev_attr = &device->dev_attr;
+ int ret, i, j;
- dev_attr = kmalloc(sizeof(*dev_attr), GFP_KERNEL);
- if (!dev_attr)
- return -ENOMEM;
-
- if (ib_query_device(device->ib_device, dev_attr)) {
+ ret = ib_query_device(device->ib_device, dev_attr);
+ if (ret) {
pr_warn("Query device failed for %s\n", device->ib_device->name);
- goto dev_attr_err;
+ return ret;
}
/* Assign function handles - based on FMR support */
@@ -94,14 +91,14 @@ static int iser_create_device_ib_res(struct iser_device *device)
device->iser_unreg_rdma_mem = iser_unreg_mem_fmr;
} else
if (dev_attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) {
- iser_info("FRWR supported, using FRWR for registration\n");
- device->iser_alloc_rdma_reg_res = iser_create_frwr_pool;
- device->iser_free_rdma_reg_res = iser_free_frwr_pool;
- device->iser_reg_rdma_mem = iser_reg_rdma_mem_frwr;
- device->iser_unreg_rdma_mem = iser_unreg_mem_frwr;
+ iser_info("FastReg supported, using FastReg for registration\n");
+ device->iser_alloc_rdma_reg_res = iser_create_fastreg_pool;
+ device->iser_free_rdma_reg_res = iser_free_fastreg_pool;
+ device->iser_reg_rdma_mem = iser_reg_rdma_mem_fastreg;
+ device->iser_unreg_rdma_mem = iser_unreg_mem_fastreg;
} else {
- iser_err("IB device does not support FMRs nor FRWRs, can't register memory\n");
- goto dev_attr_err;
+ iser_err("IB device does not support FMRs nor FastRegs, can't register memory\n");
+ return -1;
}
device->cqs_used = min(ISER_MAX_CQ, device->ib_device->num_comp_vectors);
@@ -158,7 +155,6 @@ static int iser_create_device_ib_res(struct iser_device *device)
if (ib_register_event_handler(&device->event_handler))
goto handler_err;
- kfree(dev_attr);
return 0;
handler_err:
@@ -178,8 +174,6 @@ pd_err:
kfree(device->cq_desc);
cq_desc_err:
iser_err("failed to allocate an IB resource\n");
-dev_attr_err:
- kfree(dev_attr);
return -1;
}
@@ -221,13 +215,13 @@ int iser_create_fmr_pool(struct iser_conn *ib_conn, unsigned cmds_max)
struct ib_fmr_pool_param params;
int ret = -ENOMEM;
- ib_conn->fastreg.fmr.page_vec = kmalloc(sizeof(struct iser_page_vec) +
- (sizeof(u64)*(ISCSI_ISER_SG_TABLESIZE + 1)),
- GFP_KERNEL);
- if (!ib_conn->fastreg.fmr.page_vec)
+ ib_conn->fmr.page_vec = kmalloc(sizeof(*ib_conn->fmr.page_vec) +
+ (sizeof(u64)*(ISCSI_ISER_SG_TABLESIZE + 1)),
+ GFP_KERNEL);
+ if (!ib_conn->fmr.page_vec)
return ret;
- ib_conn->fastreg.fmr.page_vec->pages = (u64 *)(ib_conn->fastreg.fmr.page_vec + 1);
+ ib_conn->fmr.page_vec->pages = (u64 *)(ib_conn->fmr.page_vec + 1);
params.page_shift = SHIFT_4K;
/* when the first/last SG element are not start/end *
@@ -243,16 +237,16 @@ int iser_create_fmr_pool(struct iser_conn *ib_conn, unsigned cmds_max)
IB_ACCESS_REMOTE_WRITE |
IB_ACCESS_REMOTE_READ);
- ib_conn->fastreg.fmr.pool = ib_create_fmr_pool(device->pd, &params);
- if (!IS_ERR(ib_conn->fastreg.fmr.pool))
+ ib_conn->fmr.pool = ib_create_fmr_pool(device->pd, &params);
+ if (!IS_ERR(ib_conn->fmr.pool))
return 0;
/* no FMR => no need for page_vec */
- kfree(ib_conn->fastreg.fmr.page_vec);
- ib_conn->fastreg.fmr.page_vec = NULL;
+ kfree(ib_conn->fmr.page_vec);
+ ib_conn->fmr.page_vec = NULL;
- ret = PTR_ERR(ib_conn->fastreg.fmr.pool);
- ib_conn->fastreg.fmr.pool = NULL;
+ ret = PTR_ERR(ib_conn->fmr.pool);
+ ib_conn->fmr.pool = NULL;
if (ret != -ENOSYS) {
iser_err("FMR allocation failed, err %d\n", ret);
return ret;
@@ -268,93 +262,173 @@ int iser_create_fmr_pool(struct iser_conn *ib_conn, unsigned cmds_max)
void iser_free_fmr_pool(struct iser_conn *ib_conn)
{
iser_info("freeing conn %p fmr pool %p\n",
- ib_conn, ib_conn->fastreg.fmr.pool);
+ ib_conn, ib_conn->fmr.pool);
+
+ if (ib_conn->fmr.pool != NULL)
+ ib_destroy_fmr_pool(ib_conn->fmr.pool);
+
+ ib_conn->fmr.pool = NULL;
+
+ kfree(ib_conn->fmr.page_vec);
+ ib_conn->fmr.page_vec = NULL;
+}
+
+static int
+iser_create_fastreg_desc(struct ib_device *ib_device, struct ib_pd *pd,
+ bool pi_enable, struct fast_reg_descriptor *desc)
+{
+ int ret;
+
+ desc->data_frpl = ib_alloc_fast_reg_page_list(ib_device,
+ ISCSI_ISER_SG_TABLESIZE + 1);
+ if (IS_ERR(desc->data_frpl)) {
+ ret = PTR_ERR(desc->data_frpl);
+ iser_err("Failed to allocate ib_fast_reg_page_list err=%d\n",
+ ret);
+ return PTR_ERR(desc->data_frpl);
+ }
+
+ desc->data_mr = ib_alloc_fast_reg_mr(pd, ISCSI_ISER_SG_TABLESIZE + 1);
+ if (IS_ERR(desc->data_mr)) {
+ ret = PTR_ERR(desc->data_mr);
+ iser_err("Failed to allocate ib_fast_reg_mr err=%d\n", ret);
+ goto fast_reg_mr_failure;
+ }
+ desc->reg_indicators |= ISER_DATA_KEY_VALID;
+
+ if (pi_enable) {
+ struct ib_mr_init_attr mr_init_attr = {0};
+ struct iser_pi_context *pi_ctx = NULL;
- if (ib_conn->fastreg.fmr.pool != NULL)
- ib_destroy_fmr_pool(ib_conn->fastreg.fmr.pool);
+ desc->pi_ctx = kzalloc(sizeof(*desc->pi_ctx), GFP_KERNEL);
+ if (!desc->pi_ctx) {
+ iser_err("Failed to allocate pi context\n");
+ ret = -ENOMEM;
+ goto pi_ctx_alloc_failure;
+ }
+ pi_ctx = desc->pi_ctx;
+
+ pi_ctx->prot_frpl = ib_alloc_fast_reg_page_list(ib_device,
+ ISCSI_ISER_SG_TABLESIZE);
+ if (IS_ERR(pi_ctx->prot_frpl)) {
+ ret = PTR_ERR(pi_ctx->prot_frpl);
+ iser_err("Failed to allocate prot frpl ret=%d\n",
+ ret);
+ goto prot_frpl_failure;
+ }
+
+ pi_ctx->prot_mr = ib_alloc_fast_reg_mr(pd,
+ ISCSI_ISER_SG_TABLESIZE + 1);
+ if (IS_ERR(pi_ctx->prot_mr)) {
+ ret = PTR_ERR(pi_ctx->prot_mr);
+ iser_err("Failed to allocate prot frmr ret=%d\n",
+ ret);
+ goto prot_mr_failure;
+ }
+ desc->reg_indicators |= ISER_PROT_KEY_VALID;
+
+ mr_init_attr.max_reg_descriptors = 2;
+ mr_init_attr.flags |= IB_MR_SIGNATURE_EN;
+ pi_ctx->sig_mr = ib_create_mr(pd, &mr_init_attr);
+ if (IS_ERR(pi_ctx->sig_mr)) {
+ ret = PTR_ERR(pi_ctx->sig_mr);
+ iser_err("Failed to allocate signature enabled mr err=%d\n",
+ ret);
+ goto sig_mr_failure;
+ }
+ desc->reg_indicators |= ISER_SIG_KEY_VALID;
+ }
+ desc->reg_indicators &= ~ISER_FASTREG_PROTECTED;
- ib_conn->fastreg.fmr.pool = NULL;
+ iser_dbg("Create fr_desc %p page_list %p\n",
+ desc, desc->data_frpl->page_list);
- kfree(ib_conn->fastreg.fmr.page_vec);
- ib_conn->fastreg.fmr.page_vec = NULL;
+ return 0;
+sig_mr_failure:
+ ib_dereg_mr(desc->pi_ctx->prot_mr);
+prot_mr_failure:
+ ib_free_fast_reg_page_list(desc->pi_ctx->prot_frpl);
+prot_frpl_failure:
+ kfree(desc->pi_ctx);
+pi_ctx_alloc_failure:
+ ib_dereg_mr(desc->data_mr);
+fast_reg_mr_failure:
+ ib_free_fast_reg_page_list(desc->data_frpl);
+
+ return ret;
}
/**
- * iser_create_frwr_pool - Creates pool of fast_reg descriptors
+ * iser_create_fastreg_pool - Creates pool of fast_reg descriptors
* for fast registration work requests.
* returns 0 on success, or errno code on failure
*/
-int iser_create_frwr_pool(struct iser_conn *ib_conn, unsigned cmds_max)
+int iser_create_fastreg_pool(struct iser_conn *ib_conn, unsigned cmds_max)
{
struct iser_device *device = ib_conn->device;
struct fast_reg_descriptor *desc;
int i, ret;
- INIT_LIST_HEAD(&ib_conn->fastreg.frwr.pool);
- ib_conn->fastreg.frwr.pool_size = 0;
+ INIT_LIST_HEAD(&ib_conn->fastreg.pool);
+ ib_conn->fastreg.pool_size = 0;
for (i = 0; i < cmds_max; i++) {
- desc = kmalloc(sizeof(*desc), GFP_KERNEL);
+ desc = kzalloc(sizeof(*desc), GFP_KERNEL);
if (!desc) {
iser_err("Failed to allocate a new fast_reg descriptor\n");
ret = -ENOMEM;
goto err;
}
- desc->data_frpl = ib_alloc_fast_reg_page_list(device->ib_device,
- ISCSI_ISER_SG_TABLESIZE + 1);
- if (IS_ERR(desc->data_frpl)) {
- ret = PTR_ERR(desc->data_frpl);
- iser_err("Failed to allocate ib_fast_reg_page_list err=%d\n", ret);
- goto fast_reg_page_failure;
+ ret = iser_create_fastreg_desc(device->ib_device, device->pd,
+ ib_conn->pi_support, desc);
+ if (ret) {
+ iser_err("Failed to create fastreg descriptor err=%d\n",
+ ret);
+ kfree(desc);
+ goto err;
}
- desc->data_mr = ib_alloc_fast_reg_mr(device->pd,
- ISCSI_ISER_SG_TABLESIZE + 1);
- if (IS_ERR(desc->data_mr)) {
- ret = PTR_ERR(desc->data_mr);
- iser_err("Failed to allocate ib_fast_reg_mr err=%d\n", ret);
- goto fast_reg_mr_failure;
- }
- desc->valid = true;
- list_add_tail(&desc->list, &ib_conn->fastreg.frwr.pool);
- ib_conn->fastreg.frwr.pool_size++;
+ list_add_tail(&desc->list, &ib_conn->fastreg.pool);
+ ib_conn->fastreg.pool_size++;
}
return 0;
-fast_reg_mr_failure:
- ib_free_fast_reg_page_list(desc->data_frpl);
-fast_reg_page_failure:
- kfree(desc);
err:
- iser_free_frwr_pool(ib_conn);
+ iser_free_fastreg_pool(ib_conn);
return ret;
}
/**
- * iser_free_frwr_pool - releases the pool of fast_reg descriptors
+ * iser_free_fastreg_pool - releases the pool of fast_reg descriptors
*/
-void iser_free_frwr_pool(struct iser_conn *ib_conn)
+void iser_free_fastreg_pool(struct iser_conn *ib_conn)
{
struct fast_reg_descriptor *desc, *tmp;
int i = 0;
- if (list_empty(&ib_conn->fastreg.frwr.pool))
+ if (list_empty(&ib_conn->fastreg.pool))
return;
- iser_info("freeing conn %p frwr pool\n", ib_conn);
+ iser_info("freeing conn %p fr pool\n", ib_conn);
- list_for_each_entry_safe(desc, tmp, &ib_conn->fastreg.frwr.pool, list) {
+ list_for_each_entry_safe(desc, tmp, &ib_conn->fastreg.pool, list) {
list_del(&desc->list);
ib_free_fast_reg_page_list(desc->data_frpl);
ib_dereg_mr(desc->data_mr);
+ if (desc->pi_ctx) {
+ ib_free_fast_reg_page_list(desc->pi_ctx->prot_frpl);
+ ib_dereg_mr(desc->pi_ctx->prot_mr);
+ ib_destroy_mr(desc->pi_ctx->sig_mr);
+ kfree(desc->pi_ctx);
+ }
kfree(desc);
++i;
}
- if (i < ib_conn->fastreg.frwr.pool_size)
+ if (i < ib_conn->fastreg.pool_size)
iser_warn("pool still has %d regions registered\n",
- ib_conn->fastreg.frwr.pool_size - i);
+ ib_conn->fastreg.pool_size - i);
}
/**
@@ -389,12 +463,17 @@ static int iser_create_ib_conn_res(struct iser_conn *ib_conn)
init_attr.qp_context = (void *)ib_conn;
init_attr.send_cq = device->tx_cq[min_index];
init_attr.recv_cq = device->rx_cq[min_index];
- init_attr.cap.max_send_wr = ISER_QP_MAX_REQ_DTOS;
init_attr.cap.max_recv_wr = ISER_QP_MAX_RECV_DTOS;
init_attr.cap.max_send_sge = 2;
init_attr.cap.max_recv_sge = 1;
init_attr.sq_sig_type = IB_SIGNAL_REQ_WR;
init_attr.qp_type = IB_QPT_RC;
+ if (ib_conn->pi_support) {
+ init_attr.cap.max_send_wr = ISER_QP_SIG_MAX_REQ_DTOS;
+ init_attr.create_flags |= IB_QP_CREATE_SIGNATURE_EN;
+ } else {
+ init_attr.cap.max_send_wr = ISER_QP_MAX_REQ_DTOS;
+ }
ret = rdma_create_qp(ib_conn->cma_id, device->pd, &init_attr);
if (ret)
@@ -591,6 +670,19 @@ static int iser_addr_handler(struct rdma_cm_id *cma_id)
ib_conn = (struct iser_conn *)cma_id->context;
ib_conn->device = device;
+ /* connection T10-PI support */
+ if (iser_pi_enable) {
+ if (!(device->dev_attr.device_cap_flags &
+ IB_DEVICE_SIGNATURE_HANDOVER)) {
+ iser_warn("T10-PI requested but not supported on %s, "
+ "continue without T10-PI\n",
+ ib_conn->device->ib_device->name);
+ ib_conn->pi_support = false;
+ } else {
+ ib_conn->pi_support = true;
+ }
+ }
+
ret = rdma_resolve_route(cma_id, 1000);
if (ret) {
iser_err("resolve route failed: %d\n", ret);
@@ -636,6 +728,11 @@ failure:
static void iser_connected_handler(struct rdma_cm_id *cma_id)
{
struct iser_conn *ib_conn;
+ struct ib_qp_attr attr;
+ struct ib_qp_init_attr init_attr;
+
+ (void)ib_query_qp(cma_id->qp, &attr, ~0, &init_attr);
+ iser_info("remote qpn:%x my qpn:%x\n", attr.dest_qp_num, cma_id->qp->qp_num);
ib_conn = (struct iser_conn *)cma_id->context;
ib_conn->state = ISER_CONN_UP;
@@ -652,9 +749,12 @@ static int iser_disconnected_handler(struct rdma_cm_id *cma_id)
/* getting here when the state is UP means that the conn is being *
* terminated asynchronously from the iSCSI layer's perspective. */
if (iser_conn_state_comp_exch(ib_conn, ISER_CONN_UP,
- ISER_CONN_TERMINATING))
- iscsi_conn_failure(ib_conn->iser_conn->iscsi_conn,
- ISCSI_ERR_CONN_FAILED);
+ ISER_CONN_TERMINATING)){
+ if (ib_conn->iscsi_conn)
+ iscsi_conn_failure(ib_conn->iscsi_conn, ISCSI_ERR_CONN_FAILED);
+ else
+ iser_err("iscsi_iser connection isn't bound\n");
+ }
/* Complete the termination process if no posts are pending */
if (ib_conn->post_recv_buf_count == 0 &&
@@ -797,7 +897,7 @@ int iser_reg_page_vec(struct iser_conn *ib_conn,
page_list = page_vec->pages;
io_addr = page_list[0];
- mem = ib_fmr_pool_map_phys(ib_conn->fastreg.fmr.pool,
+ mem = ib_fmr_pool_map_phys(ib_conn->fmr.pool,
page_list,
page_vec->length,
io_addr);
@@ -851,11 +951,11 @@ void iser_unreg_mem_fmr(struct iscsi_iser_task *iser_task,
reg->mem_h = NULL;
}
-void iser_unreg_mem_frwr(struct iscsi_iser_task *iser_task,
- enum iser_data_dir cmd_dir)
+void iser_unreg_mem_fastreg(struct iscsi_iser_task *iser_task,
+ enum iser_data_dir cmd_dir)
{
struct iser_mem_reg *reg = &iser_task->rdma_regd[cmd_dir].reg;
- struct iser_conn *ib_conn = iser_task->iser_conn->ib_conn;
+ struct iser_conn *ib_conn = iser_task->ib_conn;
struct fast_reg_descriptor *desc = reg->mem_h;
if (!reg->is_mr)
@@ -864,7 +964,7 @@ void iser_unreg_mem_frwr(struct iscsi_iser_task *iser_task,
reg->mem_h = NULL;
reg->is_mr = 0;
spin_lock_bh(&ib_conn->lock);
- list_add_tail(&desc->list, &ib_conn->fastreg.frwr.pool);
+ list_add_tail(&desc->list, &ib_conn->fastreg.pool);
spin_unlock_bh(&ib_conn->lock);
}
@@ -965,7 +1065,7 @@ static void iser_handle_comp_error(struct iser_tx_desc *desc,
* perspective. */
if (iser_conn_state_comp_exch(ib_conn, ISER_CONN_UP,
ISER_CONN_TERMINATING))
- iscsi_conn_failure(ib_conn->iser_conn->iscsi_conn,
+ iscsi_conn_failure(ib_conn->iscsi_conn,
ISCSI_ERR_CONN_FAILED);
/* no more non completed posts to the QP, complete the
@@ -989,18 +1089,16 @@ static int iser_drain_tx_cq(struct iser_device *device, int cq_index)
if (wc.status == IB_WC_SUCCESS) {
if (wc.opcode == IB_WC_SEND)
iser_snd_completion(tx_desc, ib_conn);
- else if (wc.opcode == IB_WC_LOCAL_INV ||
- wc.opcode == IB_WC_FAST_REG_MR) {
- atomic_dec(&ib_conn->post_send_buf_count);
- continue;
- } else
+ else
iser_err("expected opcode %d got %d\n",
IB_WC_SEND, wc.opcode);
} else {
iser_err("tx id %llx status %d vend_err %x\n",
- wc.wr_id, wc.status, wc.vendor_err);
- atomic_dec(&ib_conn->post_send_buf_count);
- iser_handle_comp_error(tx_desc, ib_conn);
+ wc.wr_id, wc.status, wc.vendor_err);
+ if (wc.wr_id != ISER_FASTREG_LI_WRID) {
+ atomic_dec(&ib_conn->post_send_buf_count);
+ iser_handle_comp_error(tx_desc, ib_conn);
+ }
}
completed_tx++;
}
@@ -1018,8 +1116,12 @@ static void iser_cq_tasklet_fn(unsigned long data)
struct iser_rx_desc *desc;
unsigned long xfer_len;
struct iser_conn *ib_conn;
- int completed_tx, completed_rx;
- completed_tx = completed_rx = 0;
+ int completed_tx, completed_rx = 0;
+
+ /* First do tx drain, so in a case where we have rx flushes and a successful
+ * tx completion we will still go through completion error handling.
+ */
+ completed_tx = iser_drain_tx_cq(device, cq_index);
while (ib_poll_cq(cq, 1, &wc) == 1) {
desc = (struct iser_rx_desc *) (unsigned long) wc.wr_id;
@@ -1047,7 +1149,6 @@ static void iser_cq_tasklet_fn(unsigned long data)
* " would not cause interrupts to be missed" */
ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
- completed_tx += iser_drain_tx_cq(device, cq_index);
iser_dbg("got %d rx %d tx completions\n", completed_rx, completed_tx);
}
@@ -1059,3 +1160,51 @@ static void iser_cq_callback(struct ib_cq *cq, void *cq_context)
tasklet_schedule(&device->cq_tasklet[cq_index]);
}
+
+u8 iser_check_task_pi_status(struct iscsi_iser_task *iser_task,
+ enum iser_data_dir cmd_dir, sector_t *sector)
+{
+ struct iser_mem_reg *reg = &iser_task->rdma_regd[cmd_dir].reg;
+ struct fast_reg_descriptor *desc = reg->mem_h;
+ unsigned long sector_size = iser_task->sc->device->sector_size;
+ struct ib_mr_status mr_status;
+ int ret;
+
+ if (desc && desc->reg_indicators & ISER_FASTREG_PROTECTED) {
+ desc->reg_indicators &= ~ISER_FASTREG_PROTECTED;
+ ret = ib_check_mr_status(desc->pi_ctx->sig_mr,
+ IB_MR_CHECK_SIG_STATUS, &mr_status);
+ if (ret) {
+ pr_err("ib_check_mr_status failed, ret %d\n", ret);
+ goto err;
+ }
+
+ if (mr_status.fail_status & IB_MR_CHECK_SIG_STATUS) {
+ sector_t sector_off = mr_status.sig_err.sig_err_offset;
+
+ do_div(sector_off, sector_size + 8);
+ *sector = scsi_get_lba(iser_task->sc) + sector_off;
+
+ pr_err("PI error found type %d at sector %llx "
+ "expected %x vs actual %x\n",
+ mr_status.sig_err.err_type,
+ (unsigned long long)*sector,
+ mr_status.sig_err.expected,
+ mr_status.sig_err.actual);
+
+ switch (mr_status.sig_err.err_type) {
+ case IB_SIG_BAD_GUARD:
+ return 0x1;
+ case IB_SIG_BAD_REFTAG:
+ return 0x3;
+ case IB_SIG_BAD_APPTAG:
+ return 0x2;
+ }
+ }
+ }
+
+ return 0;
+err:
+ /* Not alot we can do here, return ambiguous guard error */
+ return 0x1;
+}
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index 2b161be3c1a3..8ee228e9ab5a 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -453,6 +453,7 @@ isert_conn_create_fastreg_pool(struct isert_conn *isert_conn)
if (ret) {
pr_err("Failed to create fastreg descriptor err=%d\n",
ret);
+ kfree(fr_desc);
goto err;
}
@@ -491,12 +492,11 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
isert_conn->state = ISER_CONN_INIT;
INIT_LIST_HEAD(&isert_conn->conn_accept_node);
init_completion(&isert_conn->conn_login_comp);
- init_waitqueue_head(&isert_conn->conn_wait);
- init_waitqueue_head(&isert_conn->conn_wait_comp_err);
+ init_completion(&isert_conn->conn_wait);
+ init_completion(&isert_conn->conn_wait_comp_err);
kref_init(&isert_conn->conn_kref);
kref_get(&isert_conn->conn_kref);
mutex_init(&isert_conn->conn_mutex);
- mutex_init(&isert_conn->conn_comp_mutex);
spin_lock_init(&isert_conn->conn_lock);
cma_id->context = isert_conn;
@@ -687,11 +687,11 @@ isert_disconnect_work(struct work_struct *work)
pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
mutex_lock(&isert_conn->conn_mutex);
- isert_conn->state = ISER_CONN_DOWN;
+ if (isert_conn->state == ISER_CONN_UP)
+ isert_conn->state = ISER_CONN_TERMINATING;
if (isert_conn->post_recv_buf_count == 0 &&
atomic_read(&isert_conn->post_send_buf_count) == 0) {
- pr_debug("Calling wake_up(&isert_conn->conn_wait);\n");
mutex_unlock(&isert_conn->conn_mutex);
goto wake_up;
}
@@ -711,7 +711,7 @@ isert_disconnect_work(struct work_struct *work)
mutex_unlock(&isert_conn->conn_mutex);
wake_up:
- wake_up(&isert_conn->conn_wait);
+ complete(&isert_conn->conn_wait);
isert_put_conn(isert_conn);
}
@@ -887,16 +887,17 @@ isert_init_send_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
* Coalesce send completion interrupts by only setting IB_SEND_SIGNALED
* bit for every ISERT_COMP_BATCH_COUNT number of ib_post_send() calls.
*/
- mutex_lock(&isert_conn->conn_comp_mutex);
- if (coalesce &&
+ mutex_lock(&isert_conn->conn_mutex);
+ if (coalesce && isert_conn->state == ISER_CONN_UP &&
++isert_conn->conn_comp_batch < ISERT_COMP_BATCH_COUNT) {
+ tx_desc->llnode_active = true;
llist_add(&tx_desc->comp_llnode, &isert_conn->conn_comp_llist);
- mutex_unlock(&isert_conn->conn_comp_mutex);
+ mutex_unlock(&isert_conn->conn_mutex);
return;
}
isert_conn->conn_comp_batch = 0;
tx_desc->comp_llnode_batch = llist_del_all(&isert_conn->conn_comp_llist);
- mutex_unlock(&isert_conn->conn_comp_mutex);
+ mutex_unlock(&isert_conn->conn_mutex);
send_wr->send_flags = IB_SEND_SIGNALED;
}
@@ -1463,7 +1464,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
case ISCSI_OP_SCSI_CMD:
spin_lock_bh(&conn->cmd_lock);
if (!list_empty(&cmd->i_conn_node))
- list_del(&cmd->i_conn_node);
+ list_del_init(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
if (cmd->data_direction == DMA_TO_DEVICE)
@@ -1475,7 +1476,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
case ISCSI_OP_SCSI_TMFUNC:
spin_lock_bh(&conn->cmd_lock);
if (!list_empty(&cmd->i_conn_node))
- list_del(&cmd->i_conn_node);
+ list_del_init(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
transport_generic_free_cmd(&cmd->se_cmd, 0);
@@ -1485,7 +1486,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
case ISCSI_OP_TEXT:
spin_lock_bh(&conn->cmd_lock);
if (!list_empty(&cmd->i_conn_node))
- list_del(&cmd->i_conn_node);
+ list_del_init(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
/*
@@ -1548,6 +1549,7 @@ isert_completion_rdma_read(struct iser_tx_desc *tx_desc,
iscsit_stop_dataout_timer(cmd);
device->unreg_rdma_mem(isert_cmd, isert_conn);
cmd->write_data_done = wr->cur_rdma_length;
+ wr->send_wr_num = 0;
pr_debug("Cmd: %p RDMA_READ comp calling execute_cmd\n", isert_cmd);
spin_lock_bh(&cmd->istate_lock);
@@ -1588,7 +1590,7 @@ isert_do_control_comp(struct work_struct *work)
pr_debug("Calling iscsit_logout_post_handler >>>>>>>>>>>>>>\n");
/*
* Call atomic_dec(&isert_conn->post_send_buf_count)
- * from isert_free_conn()
+ * from isert_wait_conn()
*/
isert_conn->logout_posted = true;
iscsit_logout_post_handler(cmd, cmd->conn);
@@ -1612,6 +1614,7 @@ isert_response_completion(struct iser_tx_desc *tx_desc,
struct ib_device *ib_dev)
{
struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd;
+ struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
if (cmd->i_state == ISTATE_SEND_TASKMGTRSP ||
cmd->i_state == ISTATE_SEND_LOGOUTRSP ||
@@ -1623,7 +1626,7 @@ isert_response_completion(struct iser_tx_desc *tx_desc,
queue_work(isert_comp_wq, &isert_cmd->comp_work);
return;
}
- atomic_dec(&isert_conn->post_send_buf_count);
+ atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
cmd->i_state = ISTATE_SENT_STATUS;
isert_completion_put(tx_desc, isert_cmd, ib_dev);
@@ -1661,7 +1664,7 @@ __isert_send_completion(struct iser_tx_desc *tx_desc,
case ISER_IB_RDMA_READ:
pr_debug("isert_send_completion: Got ISER_IB_RDMA_READ:\n");
- atomic_dec(&isert_conn->post_send_buf_count);
+ atomic_sub(wr->send_wr_num, &isert_conn->post_send_buf_count);
isert_completion_rdma_read(tx_desc, isert_cmd);
break;
default:
@@ -1690,31 +1693,76 @@ isert_send_completion(struct iser_tx_desc *tx_desc,
}
static void
-isert_cq_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
+isert_cq_drain_comp_llist(struct isert_conn *isert_conn, struct ib_device *ib_dev)
+{
+ struct llist_node *llnode;
+ struct isert_rdma_wr *wr;
+ struct iser_tx_desc *t;
+
+ mutex_lock(&isert_conn->conn_mutex);
+ llnode = llist_del_all(&isert_conn->conn_comp_llist);
+ isert_conn->conn_comp_batch = 0;
+ mutex_unlock(&isert_conn->conn_mutex);
+
+ while (llnode) {
+ t = llist_entry(llnode, struct iser_tx_desc, comp_llnode);
+ llnode = llist_next(llnode);
+ wr = &t->isert_cmd->rdma_wr;
+
+ atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
+ isert_completion_put(t, t->isert_cmd, ib_dev);
+ }
+}
+
+static void
+isert_cq_tx_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
{
struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct isert_cmd *isert_cmd = tx_desc->isert_cmd;
+ struct llist_node *llnode = tx_desc->comp_llnode_batch;
+ struct isert_rdma_wr *wr;
+ struct iser_tx_desc *t;
- if (tx_desc) {
- struct isert_cmd *isert_cmd = tx_desc->isert_cmd;
+ while (llnode) {
+ t = llist_entry(llnode, struct iser_tx_desc, comp_llnode);
+ llnode = llist_next(llnode);
+ wr = &t->isert_cmd->rdma_wr;
- if (!isert_cmd)
- isert_unmap_tx_desc(tx_desc, ib_dev);
- else
- isert_completion_put(tx_desc, isert_cmd, ib_dev);
+ atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
+ isert_completion_put(t, t->isert_cmd, ib_dev);
}
+ tx_desc->comp_llnode_batch = NULL;
- if (isert_conn->post_recv_buf_count == 0 &&
- atomic_read(&isert_conn->post_send_buf_count) == 0) {
- pr_debug("isert_cq_comp_err >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
- pr_debug("Calling wake_up from isert_cq_comp_err\n");
+ if (!isert_cmd)
+ isert_unmap_tx_desc(tx_desc, ib_dev);
+ else
+ isert_completion_put(tx_desc, isert_cmd, ib_dev);
+}
- mutex_lock(&isert_conn->conn_mutex);
- if (isert_conn->state != ISER_CONN_DOWN)
- isert_conn->state = ISER_CONN_TERMINATING;
- mutex_unlock(&isert_conn->conn_mutex);
+static void
+isert_cq_rx_comp_err(struct isert_conn *isert_conn)
+{
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct iscsi_conn *conn = isert_conn->conn;
- wake_up(&isert_conn->conn_wait_comp_err);
+ if (isert_conn->post_recv_buf_count)
+ return;
+
+ isert_cq_drain_comp_llist(isert_conn, ib_dev);
+
+ if (conn->sess) {
+ target_sess_cmd_list_set_waiting(conn->sess->se_sess);
+ target_wait_for_sess_cmds(conn->sess->se_sess);
}
+
+ while (atomic_read(&isert_conn->post_send_buf_count))
+ msleep(3000);
+
+ mutex_lock(&isert_conn->conn_mutex);
+ isert_conn->state = ISER_CONN_DOWN;
+ mutex_unlock(&isert_conn->conn_mutex);
+
+ complete(&isert_conn->conn_wait_comp_err);
}
static void
@@ -1739,8 +1787,14 @@ isert_cq_tx_work(struct work_struct *work)
pr_debug("TX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
pr_debug("TX wc.status: 0x%08x\n", wc.status);
pr_debug("TX wc.vendor_err: 0x%08x\n", wc.vendor_err);
- atomic_dec(&isert_conn->post_send_buf_count);
- isert_cq_comp_err(tx_desc, isert_conn);
+
+ if (wc.wr_id != ISER_FASTREG_LI_WRID) {
+ if (tx_desc->llnode_active)
+ continue;
+
+ atomic_dec(&isert_conn->post_send_buf_count);
+ isert_cq_tx_comp_err(tx_desc, isert_conn);
+ }
}
}
@@ -1783,7 +1837,7 @@ isert_cq_rx_work(struct work_struct *work)
wc.vendor_err);
}
isert_conn->post_recv_buf_count--;
- isert_cq_comp_err(NULL, isert_conn);
+ isert_cq_rx_comp_err(isert_conn);
}
}
@@ -2201,6 +2255,7 @@ isert_fast_reg_mr(struct fast_reg_descriptor *fr_desc,
if (!fr_desc->valid) {
memset(&inv_wr, 0, sizeof(inv_wr));
+ inv_wr.wr_id = ISER_FASTREG_LI_WRID;
inv_wr.opcode = IB_WR_LOCAL_INV;
inv_wr.ex.invalidate_rkey = fr_desc->data_mr->rkey;
wr = &inv_wr;
@@ -2211,6 +2266,7 @@ isert_fast_reg_mr(struct fast_reg_descriptor *fr_desc,
/* Prepare FASTREG WR */
memset(&fr_wr, 0, sizeof(fr_wr));
+ fr_wr.wr_id = ISER_FASTREG_LI_WRID;
fr_wr.opcode = IB_WR_FAST_REG_MR;
fr_wr.wr.fast_reg.iova_start =
fr_desc->data_frpl->page_list[0] + page_off;
@@ -2376,12 +2432,12 @@ isert_put_datain(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
isert_init_send_wr(isert_conn, isert_cmd,
&isert_cmd->tx_desc.send_wr, true);
- atomic_inc(&isert_conn->post_send_buf_count);
+ atomic_add(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed);
if (rc) {
pr_warn("ib_post_send() failed for IB_WR_RDMA_WRITE\n");
- atomic_dec(&isert_conn->post_send_buf_count);
+ atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
}
pr_debug("Cmd: %p posted RDMA_WRITE + Response for iSER Data READ\n",
isert_cmd);
@@ -2409,12 +2465,12 @@ isert_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd, bool recovery)
return rc;
}
- atomic_inc(&isert_conn->post_send_buf_count);
+ atomic_add(wr->send_wr_num, &isert_conn->post_send_buf_count);
rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed);
if (rc) {
pr_warn("ib_post_send() failed for IB_WR_RDMA_READ\n");
- atomic_dec(&isert_conn->post_send_buf_count);
+ atomic_sub(wr->send_wr_num, &isert_conn->post_send_buf_count);
}
pr_debug("Cmd: %p posted RDMA_READ memory for ISER Data WRITE\n",
isert_cmd);
@@ -2701,22 +2757,11 @@ isert_free_np(struct iscsi_np *np)
kfree(isert_np);
}
-static int isert_check_state(struct isert_conn *isert_conn, int state)
-{
- int ret;
-
- mutex_lock(&isert_conn->conn_mutex);
- ret = (isert_conn->state == state);
- mutex_unlock(&isert_conn->conn_mutex);
-
- return ret;
-}
-
-static void isert_free_conn(struct iscsi_conn *conn)
+static void isert_wait_conn(struct iscsi_conn *conn)
{
struct isert_conn *isert_conn = conn->context;
- pr_debug("isert_free_conn: Starting \n");
+ pr_debug("isert_wait_conn: Starting \n");
/*
* Decrement post_send_buf_count for special case when called
* from isert_do_control_comp() -> iscsit_logout_post_handler()
@@ -2726,38 +2771,29 @@ static void isert_free_conn(struct iscsi_conn *conn)
atomic_dec(&isert_conn->post_send_buf_count);
if (isert_conn->conn_cm_id && isert_conn->state != ISER_CONN_DOWN) {
- pr_debug("Calling rdma_disconnect from isert_free_conn\n");
+ pr_debug("Calling rdma_disconnect from isert_wait_conn\n");
rdma_disconnect(isert_conn->conn_cm_id);
}
/*
* Only wait for conn_wait_comp_err if the isert_conn made it
* into full feature phase..
*/
- if (isert_conn->state == ISER_CONN_UP) {
- pr_debug("isert_free_conn: Before wait_event comp_err %d\n",
- isert_conn->state);
- mutex_unlock(&isert_conn->conn_mutex);
-
- wait_event(isert_conn->conn_wait_comp_err,
- (isert_check_state(isert_conn, ISER_CONN_TERMINATING)));
-
- wait_event(isert_conn->conn_wait,
- (isert_check_state(isert_conn, ISER_CONN_DOWN)));
-
- isert_put_conn(isert_conn);
- return;
- }
if (isert_conn->state == ISER_CONN_INIT) {
mutex_unlock(&isert_conn->conn_mutex);
- isert_put_conn(isert_conn);
return;
}
- pr_debug("isert_free_conn: wait_event conn_wait %d\n",
- isert_conn->state);
+ if (isert_conn->state == ISER_CONN_UP)
+ isert_conn->state = ISER_CONN_TERMINATING;
mutex_unlock(&isert_conn->conn_mutex);
- wait_event(isert_conn->conn_wait,
- (isert_check_state(isert_conn, ISER_CONN_DOWN)));
+ wait_for_completion(&isert_conn->conn_wait_comp_err);
+
+ wait_for_completion(&isert_conn->conn_wait);
+}
+
+static void isert_free_conn(struct iscsi_conn *conn)
+{
+ struct isert_conn *isert_conn = conn->context;
isert_put_conn(isert_conn);
}
@@ -2770,6 +2806,7 @@ static struct iscsit_transport iser_target_transport = {
.iscsit_setup_np = isert_setup_np,
.iscsit_accept_np = isert_accept_np,
.iscsit_free_np = isert_free_np,
+ .iscsit_wait_conn = isert_wait_conn,
.iscsit_free_conn = isert_free_conn,
.iscsit_get_login_rx = isert_get_login_rx,
.iscsit_put_login_tx = isert_put_login_tx,
diff --git a/drivers/infiniband/ulp/isert/ib_isert.h b/drivers/infiniband/ulp/isert/ib_isert.h
index 708a069002f3..f6ae7f5dd408 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.h
+++ b/drivers/infiniband/ulp/isert/ib_isert.h
@@ -6,6 +6,7 @@
#define ISERT_RDMA_LISTEN_BACKLOG 10
#define ISCSI_ISER_SG_TABLESIZE 256
+#define ISER_FASTREG_LI_WRID 0xffffffffffffffffULL
enum isert_desc_type {
ISCSI_TX_CONTROL,
@@ -45,6 +46,7 @@ struct iser_tx_desc {
struct isert_cmd *isert_cmd;
struct llist_node *comp_llnode_batch;
struct llist_node comp_llnode;
+ bool llnode_active;
struct ib_send_wr send_wr;
} __packed;
@@ -116,8 +118,8 @@ struct isert_conn {
struct isert_device *conn_device;
struct work_struct conn_logout_work;
struct mutex conn_mutex;
- wait_queue_head_t conn_wait;
- wait_queue_head_t conn_wait_comp_err;
+ struct completion conn_wait;
+ struct completion conn_wait_comp_err;
struct kref conn_kref;
struct list_head conn_fr_pool;
int conn_fr_pool_size;
@@ -126,7 +128,6 @@ struct isert_conn {
#define ISERT_COMP_BATCH_COUNT 8
int conn_comp_batch;
struct llist_head conn_comp_llist;
- struct mutex conn_comp_mutex;
};
#define ISERT_MAX_CQ 64
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 529b6bcdca7a..66a908bf3fb9 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -411,6 +411,8 @@ static void srp_path_rec_completion(int status,
static int srp_lookup_path(struct srp_target_port *target)
{
+ int ret;
+
target->path.numb_path = 1;
init_completion(&target->done);
@@ -431,7 +433,9 @@ static int srp_lookup_path(struct srp_target_port *target)
if (target->path_query_id < 0)
return target->path_query_id;
- wait_for_completion(&target->done);
+ ret = wait_for_completion_interruptible(&target->done);
+ if (ret < 0)
+ return ret;
if (target->status < 0)
shost_printk(KERN_WARNING, target->scsi_host,
@@ -710,7 +714,9 @@ static int srp_connect_target(struct srp_target_port *target)
ret = srp_send_req(target);
if (ret)
return ret;
- wait_for_completion(&target->done);
+ ret = wait_for_completion_interruptible(&target->done);
+ if (ret < 0)
+ return ret;
/*
* The CM event handling code will set status to
@@ -777,6 +783,7 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,
* srp_claim_req - Take ownership of the scmnd associated with a request.
* @target: SRP target port.
* @req: SRP request.
+ * @sdev: If not NULL, only take ownership for this SCSI device.
* @scmnd: If NULL, take ownership of @req->scmnd. If not NULL, only take
* ownership of @req->scmnd if it equals @scmnd.
*
@@ -785,16 +792,17 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,
*/
static struct scsi_cmnd *srp_claim_req(struct srp_target_port *target,
struct srp_request *req,
+ struct scsi_device *sdev,
struct scsi_cmnd *scmnd)
{
unsigned long flags;
spin_lock_irqsave(&target->lock, flags);
- if (!scmnd) {
+ if (req->scmnd &&
+ (!sdev || req->scmnd->device == sdev) &&
+ (!scmnd || req->scmnd == scmnd)) {
scmnd = req->scmnd;
req->scmnd = NULL;
- } else if (req->scmnd == scmnd) {
- req->scmnd = NULL;
} else {
scmnd = NULL;
}
@@ -821,9 +829,10 @@ static void srp_free_req(struct srp_target_port *target,
}
static void srp_finish_req(struct srp_target_port *target,
- struct srp_request *req, int result)
+ struct srp_request *req, struct scsi_device *sdev,
+ int result)
{
- struct scsi_cmnd *scmnd = srp_claim_req(target, req, NULL);
+ struct scsi_cmnd *scmnd = srp_claim_req(target, req, sdev, NULL);
if (scmnd) {
srp_free_req(target, req, scmnd, 0);
@@ -835,11 +844,20 @@ static void srp_finish_req(struct srp_target_port *target,
static void srp_terminate_io(struct srp_rport *rport)
{
struct srp_target_port *target = rport->lld_data;
+ struct Scsi_Host *shost = target->scsi_host;
+ struct scsi_device *sdev;
int i;
+ /*
+ * Invoking srp_terminate_io() while srp_queuecommand() is running
+ * is not safe. Hence the warning statement below.
+ */
+ shost_for_each_device(sdev, shost)
+ WARN_ON_ONCE(sdev->request_queue->request_fn_active);
+
for (i = 0; i < target->req_ring_size; ++i) {
struct srp_request *req = &target->req_ring[i];
- srp_finish_req(target, req, DID_TRANSPORT_FAILFAST << 16);
+ srp_finish_req(target, req, NULL, DID_TRANSPORT_FAILFAST << 16);
}
}
@@ -876,7 +894,7 @@ static int srp_rport_reconnect(struct srp_rport *rport)
for (i = 0; i < target->req_ring_size; ++i) {
struct srp_request *req = &target->req_ring[i];
- srp_finish_req(target, req, DID_RESET << 16);
+ srp_finish_req(target, req, NULL, DID_RESET << 16);
}
INIT_LIST_HEAD(&target->free_tx);
@@ -1284,7 +1302,7 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
complete(&target->tsk_mgmt_done);
} else {
req = &target->req_ring[rsp->tag];
- scmnd = srp_claim_req(target, req, NULL);
+ scmnd = srp_claim_req(target, req, NULL, NULL);
if (!scmnd) {
shost_printk(KERN_ERR, target->scsi_host,
"Null scmnd for RSP w/tag %016llx\n",
@@ -1804,8 +1822,10 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
shost_printk(KERN_WARNING, shost,
PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n");
else
- shost_printk(KERN_WARNING, shost,
- PFX "SRP LOGIN REJECTED, reason 0x%08x\n", reason);
+ shost_printk(KERN_WARNING, shost, PFX
+ "SRP LOGIN from %pI6 to %pI6 REJECTED, reason 0x%08x\n",
+ target->path.sgid.raw,
+ target->orig_dgid, reason);
} else
shost_printk(KERN_WARNING, shost,
" REJ reason: IB_CM_REJ_CONSUMER_DEFINED,"
@@ -1863,6 +1883,7 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
case IB_CM_TIMEWAIT_EXIT:
shost_printk(KERN_ERR, target->scsi_host,
PFX "connection closed\n");
+ comp = 1;
target->status = 0;
break;
@@ -1999,7 +2020,7 @@ static int srp_abort(struct scsi_cmnd *scmnd)
shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n");
- if (!req || !srp_claim_req(target, req, scmnd))
+ if (!req || !srp_claim_req(target, req, NULL, scmnd))
return SUCCESS;
if (srp_send_tsk_mgmt(target, req->index, scmnd->device->lun,
SRP_TSK_ABORT_TASK) == 0)
@@ -2030,8 +2051,7 @@ static int srp_reset_device(struct scsi_cmnd *scmnd)
for (i = 0; i < target->req_ring_size; ++i) {
struct srp_request *req = &target->req_ring[i];
- if (req->scmnd && req->scmnd->device == scmnd->device)
- srp_finish_req(target, req, DID_RESET << 16);
+ srp_finish_req(target, req, scmnd->device, DID_RESET << 16);
}
return SUCCESS;
@@ -2612,6 +2632,8 @@ static ssize_t srp_create_target(struct device *dev,
target->tl_retry_count = 7;
target->queue_size = SRP_DEFAULT_QUEUE_SIZE;
+ mutex_lock(&host->add_target_mutex);
+
ret = srp_parse_options(buf, target);
if (ret)
goto err;
@@ -2649,16 +2671,9 @@ static ssize_t srp_create_target(struct device *dev,
if (ret)
goto err_free_mem;
- ib_query_gid(ibdev, host->port, 0, &target->path.sgid);
-
- shost_printk(KERN_DEBUG, target->scsi_host, PFX
- "new target: id_ext %016llx ioc_guid %016llx pkey %04x "
- "service_id %016llx dgid %pI6\n",
- (unsigned long long) be64_to_cpu(target->id_ext),
- (unsigned long long) be64_to_cpu(target->ioc_guid),
- be16_to_cpu(target->path.pkey),
- (unsigned long long) be64_to_cpu(target->service_id),
- target->path.dgid.raw);
+ ret = ib_query_gid(ibdev, host->port, 0, &target->path.sgid);
+ if (ret)
+ goto err_free_mem;
ret = srp_create_target_ib(target);
if (ret)
@@ -2679,7 +2694,19 @@ static ssize_t srp_create_target(struct device *dev,
if (ret)
goto err_disconnect;
- return count;
+ shost_printk(KERN_DEBUG, target->scsi_host, PFX
+ "new target: id_ext %016llx ioc_guid %016llx pkey %04x service_id %016llx sgid %pI6 dgid %pI6\n",
+ be64_to_cpu(target->id_ext),
+ be64_to_cpu(target->ioc_guid),
+ be16_to_cpu(target->path.pkey),
+ be64_to_cpu(target->service_id),
+ target->path.sgid.raw, target->path.dgid.raw);
+
+ ret = count;
+
+out:
+ mutex_unlock(&host->add_target_mutex);
+ return ret;
err_disconnect:
srp_disconnect_target(target);
@@ -2695,8 +2722,7 @@ err_free_mem:
err:
scsi_host_put(target_host);
-
- return ret;
+ goto out;
}
static DEVICE_ATTR(add_target, S_IWUSR, NULL, srp_create_target);
@@ -2732,6 +2758,7 @@ static struct srp_host *srp_add_port(struct srp_device *device, u8 port)
INIT_LIST_HEAD(&host->target_list);
spin_lock_init(&host->target_lock);
init_completion(&host->released);
+ mutex_init(&host->add_target_mutex);
host->srp_dev = device;
host->port = port;
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index 575681063f38..aad27b7b4a46 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -105,6 +105,7 @@ struct srp_host {
spinlock_t target_lock;
struct completion released;
struct list_head list;
+ struct mutex add_target_mutex;
};
struct srp_request {
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index 520a7e5a490b..0e537d8d0e47 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -3666,9 +3666,9 @@ static ssize_t srpt_tpg_attrib_store_srp_max_rdma_size(
unsigned long val;
int ret;
- ret = strict_strtoul(page, 0, &val);
+ ret = kstrtoul(page, 0, &val);
if (ret < 0) {
- pr_err("strict_strtoul() failed with ret: %d\n", ret);
+ pr_err("kstrtoul() failed with ret: %d\n", ret);
return -EINVAL;
}
if (val > MAX_SRPT_RDMA_SIZE) {
@@ -3706,9 +3706,9 @@ static ssize_t srpt_tpg_attrib_store_srp_max_rsp_size(
unsigned long val;
int ret;
- ret = strict_strtoul(page, 0, &val);
+ ret = kstrtoul(page, 0, &val);
if (ret < 0) {
- pr_err("strict_strtoul() failed with ret: %d\n", ret);
+ pr_err("kstrtoul() failed with ret: %d\n", ret);
return -EINVAL;
}
if (val > MAX_SRPT_RSP_SIZE) {
@@ -3746,9 +3746,9 @@ static ssize_t srpt_tpg_attrib_store_srp_sq_size(
unsigned long val;
int ret;
- ret = strict_strtoul(page, 0, &val);
+ ret = kstrtoul(page, 0, &val);
if (ret < 0) {
- pr_err("strict_strtoul() failed with ret: %d\n", ret);
+ pr_err("kstrtoul() failed with ret: %d\n", ret);
return -EINVAL;
}
if (val > MAX_SRPT_SRQ_SIZE) {
@@ -3793,7 +3793,7 @@ static ssize_t srpt_tpg_store_enable(
unsigned long tmp;
int ret;
- ret = strict_strtoul(page, 0, &tmp);
+ ret = kstrtoul(page, 0, &tmp);
if (ret < 0) {
printk(KERN_ERR "Unable to extract srpt_tpg_store_enable\n");
return -EINVAL;
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index a06e12552886..ce953d895f5b 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -954,11 +954,13 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
return -EFAULT;
error = input_ff_upload(dev, &effect, file);
+ if (error)
+ return error;
if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
return -EFAULT;
- return error;
+ return 0;
}
/* Multi-number variable-length handlers */
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index a673c9f3a0b9..76842d7dc2e3 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -151,6 +151,18 @@ config KEYBOARD_BFIN
To compile this driver as a module, choose M here: the
module will be called bf54x-keys.
+config KEYBOARD_CLPS711X
+ tristate "CLPS711X Keypad support"
+ depends on OF_GPIO && (ARCH_CLPS711X || COMPILE_TEST)
+ select INPUT_MATRIXKMAP
+ select INPUT_POLLDEV
+ help
+ Say Y here to enable the matrix keypad on the Cirrus Logic
+ CLPS711X CPUs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called clps711x-keypad.
+
config KEYBOARD_LKKBD
tristate "DECstation/VAXstation LK201/LK401 keyboard"
select SERIO
@@ -595,16 +607,6 @@ config KEYBOARD_TC3589X
To compile this driver as a module, choose M here: the
module will be called tc3589x-keypad.
-config KEYBOARD_TNETV107X
- tristate "TI TNETV107X keypad support"
- depends on ARCH_DAVINCI_TNETV107X
- select INPUT_MATRIXKMAP
- help
- Say Y here if you want to use the TNETV107X keypad.
-
- To compile this driver as a module, choose M here: the
- module will be called tnetv107x-keypad.
-
config KEYBOARD_TWL4030
tristate "TI TWL4030/TWL5030/TPS659x0 keypad support"
depends on TWL4030_CORE
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index a699b6172303..11cff7b84b47 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
+obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o
obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
@@ -53,7 +54,6 @@ obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o
obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o
-obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o
obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index bb3b57bea8ba..5ef7fcf0e250 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -76,8 +76,18 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
+ int val;
- return !!(adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank) & bit);
+ mutex_lock(&kpad->gpio_lock);
+
+ if (kpad->dir[bank] & bit)
+ val = kpad->dat_out[bank];
+ else
+ val = adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank);
+
+ mutex_unlock(&kpad->gpio_lock);
+
+ return !!(val & bit);
}
static void adp5588_gpio_set_value(struct gpio_chip *chip,
diff --git a/drivers/input/keyboard/clps711x-keypad.c b/drivers/input/keyboard/clps711x-keypad.c
new file mode 100644
index 000000000000..3955aecee44b
--- /dev/null
+++ b/drivers/input/keyboard/clps711x-keypad.c
@@ -0,0 +1,207 @@
+/*
+ * Cirrus Logic CLPS711X Keypad driver
+ *
+ * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/input.h>
+#include <linux/input-polldev.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/sched.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/clps711x.h>
+
+#define CLPS711X_KEYPAD_COL_COUNT 8
+
+struct clps711x_gpio_data {
+ struct gpio_desc *desc;
+ DECLARE_BITMAP(last_state, CLPS711X_KEYPAD_COL_COUNT);
+};
+
+struct clps711x_keypad_data {
+ struct regmap *syscon;
+ int row_count;
+ unsigned int row_shift;
+ struct clps711x_gpio_data *gpio_data;
+};
+
+static void clps711x_keypad_poll(struct input_polled_dev *dev)
+{
+ const unsigned short *keycodes = dev->input->keycode;
+ struct clps711x_keypad_data *priv = dev->private;
+ bool sync = false;
+ int col, row;
+
+ for (col = 0; col < CLPS711X_KEYPAD_COL_COUNT; col++) {
+ /* Assert column */
+ regmap_update_bits(priv->syscon, SYSCON_OFFSET,
+ SYSCON1_KBDSCAN_MASK,
+ SYSCON1_KBDSCAN(8 + col));
+
+ /* Scan rows */
+ for (row = 0; row < priv->row_count; row++) {
+ struct clps711x_gpio_data *data = &priv->gpio_data[row];
+ bool state, state1;
+
+ /* Read twice for protection against fluctuations */
+ do {
+ state = gpiod_get_value_cansleep(data->desc);
+ cond_resched();
+ state1 = gpiod_get_value_cansleep(data->desc);
+ } while (state != state1);
+
+ if (test_bit(col, data->last_state) != state) {
+ int code = MATRIX_SCAN_CODE(row, col,
+ priv->row_shift);
+
+ if (state) {
+ set_bit(col, data->last_state);
+ input_event(dev->input, EV_MSC,
+ MSC_SCAN, code);
+ } else {
+ clear_bit(col, data->last_state);
+ }
+
+ if (keycodes[code])
+ input_report_key(dev->input,
+ keycodes[code], state);
+ sync = true;
+ }
+ }
+
+ /* Set all columns to low */
+ regmap_update_bits(priv->syscon, SYSCON_OFFSET,
+ SYSCON1_KBDSCAN_MASK, SYSCON1_KBDSCAN(1));
+ }
+
+ if (sync)
+ input_sync(dev->input);
+}
+
+static int clps711x_keypad_probe(struct platform_device *pdev)
+{
+ struct clps711x_keypad_data *priv;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct input_polled_dev *poll_dev;
+ u32 poll_interval;
+ int i, err;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->syscon =
+ syscon_regmap_lookup_by_compatible("cirrus,clps711x-syscon1");
+ if (IS_ERR(priv->syscon))
+ return PTR_ERR(priv->syscon);
+
+ priv->row_count = of_gpio_named_count(np, "row-gpios");
+ if (priv->row_count < 1)
+ return -EINVAL;
+
+ priv->gpio_data = devm_kzalloc(dev,
+ sizeof(*priv->gpio_data) * priv->row_count,
+ GFP_KERNEL);
+ if (!priv->gpio_data)
+ return -ENOMEM;
+
+ priv->row_shift = get_count_order(CLPS711X_KEYPAD_COL_COUNT);
+
+ for (i = 0; i < priv->row_count; i++) {
+ struct clps711x_gpio_data *data = &priv->gpio_data[i];
+
+ data->desc = devm_gpiod_get_index(dev, "row", i);
+ if (!data->desc)
+ return -EINVAL;
+
+ if (IS_ERR(data->desc))
+ return PTR_ERR(data->desc);
+
+ gpiod_direction_input(data->desc);
+ }
+
+ err = of_property_read_u32(np, "poll-interval", &poll_interval);
+ if (err)
+ return err;
+
+ poll_dev = input_allocate_polled_device();
+ if (!poll_dev)
+ return -ENOMEM;
+
+ poll_dev->private = priv;
+ poll_dev->poll = clps711x_keypad_poll;
+ poll_dev->poll_interval = poll_interval;
+ poll_dev->input->name = pdev->name;
+ poll_dev->input->dev.parent = dev;
+ poll_dev->input->id.bustype = BUS_HOST;
+ poll_dev->input->id.vendor = 0x0001;
+ poll_dev->input->id.product = 0x0001;
+ poll_dev->input->id.version = 0x0100;
+
+ err = matrix_keypad_build_keymap(NULL, NULL, priv->row_count,
+ CLPS711X_KEYPAD_COL_COUNT,
+ NULL, poll_dev->input);
+ if (err)
+ goto out_err;
+
+ input_set_capability(poll_dev->input, EV_MSC, MSC_SCAN);
+ if (of_property_read_bool(np, "autorepeat"))
+ __set_bit(EV_REP, poll_dev->input->evbit);
+
+ platform_set_drvdata(pdev, poll_dev);
+
+ /* Set all columns to low */
+ regmap_update_bits(priv->syscon, SYSCON_OFFSET, SYSCON1_KBDSCAN_MASK,
+ SYSCON1_KBDSCAN(1));
+
+ err = input_register_polled_device(poll_dev);
+ if (err)
+ goto out_err;
+
+ return 0;
+
+out_err:
+ input_free_polled_device(poll_dev);
+ return err;
+}
+
+static int clps711x_keypad_remove(struct platform_device *pdev)
+{
+ struct input_polled_dev *poll_dev = platform_get_drvdata(pdev);
+
+ input_unregister_polled_device(poll_dev);
+ input_free_polled_device(poll_dev);
+
+ return 0;
+}
+
+static struct of_device_id clps711x_keypad_of_match[] = {
+ { .compatible = "cirrus,clps711x-keypad", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, clps711x_keypad_of_match);
+
+static struct platform_driver clps711x_keypad_driver = {
+ .driver = {
+ .name = "clps711x-keypad",
+ .owner = THIS_MODULE,
+ .of_match_table = clps711x_keypad_of_match,
+ },
+ .probe = clps711x_keypad_probe,
+ .remove = clps711x_keypad_remove,
+};
+module_platform_driver(clps711x_keypad_driver);
+
+MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
+MODULE_DESCRIPTION("Cirrus Logic CLPS711X Keypad driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
index cbf4f8038cba..97ec33572e56 100644
--- a/drivers/input/keyboard/imx_keypad.c
+++ b/drivers/input/keyboard/imx_keypad.c
@@ -439,7 +439,7 @@ static int imx_keypad_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq defined in platform data\n");
- return -EINVAL;
+ return irq;
}
input_dev = devm_input_allocate_device(&pdev->dev);
@@ -449,7 +449,7 @@ static int imx_keypad_probe(struct platform_device *pdev)
}
keypad = devm_kzalloc(&pdev->dev, sizeof(struct imx_keypad),
- GFP_KERNEL);
+ GFP_KERNEL);
if (!keypad) {
dev_err(&pdev->dev, "not enough memory for driver data\n");
return -ENOMEM;
diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c
index 2c9f19ac35ea..80c6b0ef3fc8 100644
--- a/drivers/input/keyboard/pmic8xxx-keypad.c
+++ b/drivers/input/keyboard/pmic8xxx-keypad.c
@@ -19,10 +19,9 @@
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/mutex.h>
-
-#include <linux/mfd/pm8xxx/core.h>
-#include <linux/mfd/pm8xxx/gpio.h>
-#include <linux/input/pmic8xxx-keypad.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/input/matrix_keypad.h>
#define PM8XXX_MAX_ROWS 18
#define PM8XXX_MAX_COLS 8
@@ -85,8 +84,10 @@
/**
* struct pmic8xxx_kp - internal keypad data structure
- * @pdata - keypad platform data pointer
+ * @num_cols - number of columns of keypad
+ * @num_rows - number of row of keypad
* @input - input device pointer for keypad
+ * @regmap - regmap handle
* @key_sense_irq - key press/release irq number
* @key_stuck_irq - key stuck notification irq number
* @keycodes - array to hold the key codes
@@ -96,8 +97,10 @@
* @ctrl_reg - control register value
*/
struct pmic8xxx_kp {
- const struct pm8xxx_keypad_platform_data *pdata;
+ unsigned int num_rows;
+ unsigned int num_cols;
struct input_dev *input;
+ struct regmap *regmap;
int key_sense_irq;
int key_stuck_irq;
@@ -110,40 +113,13 @@ struct pmic8xxx_kp {
u8 ctrl_reg;
};
-static int pmic8xxx_kp_write_u8(struct pmic8xxx_kp *kp,
- u8 data, u16 reg)
-{
- int rc;
-
- rc = pm8xxx_writeb(kp->dev->parent, reg, data);
- return rc;
-}
-
-static int pmic8xxx_kp_read(struct pmic8xxx_kp *kp,
- u8 *data, u16 reg, unsigned num_bytes)
-{
- int rc;
-
- rc = pm8xxx_read_buf(kp->dev->parent, reg, data, num_bytes);
- return rc;
-}
-
-static int pmic8xxx_kp_read_u8(struct pmic8xxx_kp *kp,
- u8 *data, u16 reg)
-{
- int rc;
-
- rc = pmic8xxx_kp_read(kp, data, reg, 1);
- return rc;
-}
-
static u8 pmic8xxx_col_state(struct pmic8xxx_kp *kp, u8 col)
{
/* all keys pressed on that particular row? */
if (col == 0x00)
- return 1 << kp->pdata->num_cols;
+ return 1 << kp->num_cols;
else
- return col & ((1 << kp->pdata->num_cols) - 1);
+ return col & ((1 << kp->num_cols) - 1);
}
/*
@@ -161,9 +137,9 @@ static u8 pmic8xxx_col_state(struct pmic8xxx_kp *kp, u8 col)
static int pmic8xxx_chk_sync_read(struct pmic8xxx_kp *kp)
{
int rc;
- u8 scan_val;
+ unsigned int scan_val;
- rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN);
+ rc = regmap_read(kp->regmap, KEYP_SCAN, &scan_val);
if (rc < 0) {
dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc);
return rc;
@@ -171,7 +147,7 @@ static int pmic8xxx_chk_sync_read(struct pmic8xxx_kp *kp)
scan_val |= 0x1;
- rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
+ rc = regmap_write(kp->regmap, KEYP_SCAN, scan_val);
if (rc < 0) {
dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
return rc;
@@ -187,31 +163,29 @@ static int pmic8xxx_kp_read_data(struct pmic8xxx_kp *kp, u16 *state,
u16 data_reg, int read_rows)
{
int rc, row;
- u8 new_data[PM8XXX_MAX_ROWS];
-
- rc = pmic8xxx_kp_read(kp, new_data, data_reg, read_rows);
- if (rc)
- return rc;
+ unsigned int val;
- for (row = 0; row < kp->pdata->num_rows; row++) {
- dev_dbg(kp->dev, "new_data[%d] = %d\n", row,
- new_data[row]);
- state[row] = pmic8xxx_col_state(kp, new_data[row]);
+ for (row = 0; row < read_rows; row++) {
+ rc = regmap_read(kp->regmap, data_reg, &val);
+ if (rc)
+ return rc;
+ dev_dbg(kp->dev, "%d = %d\n", row, val);
+ state[row] = pmic8xxx_col_state(kp, val);
}
- return rc;
+ return 0;
}
static int pmic8xxx_kp_read_matrix(struct pmic8xxx_kp *kp, u16 *new_state,
u16 *old_state)
{
int rc, read_rows;
- u8 scan_val;
+ unsigned int scan_val;
- if (kp->pdata->num_rows < PM8XXX_MIN_ROWS)
+ if (kp->num_rows < PM8XXX_MIN_ROWS)
read_rows = PM8XXX_MIN_ROWS;
else
- read_rows = kp->pdata->num_rows;
+ read_rows = kp->num_rows;
pmic8xxx_chk_sync_read(kp);
@@ -236,14 +210,14 @@ static int pmic8xxx_kp_read_matrix(struct pmic8xxx_kp *kp, u16 *new_state,
/* 4 * 32KHz clocks */
udelay((4 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1);
- rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN);
+ rc = regmap_read(kp->regmap, KEYP_SCAN, &scan_val);
if (rc < 0) {
dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc);
return rc;
}
scan_val &= 0xFE;
- rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
+ rc = regmap_write(kp->regmap, KEYP_SCAN, scan_val);
if (rc < 0)
dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
@@ -255,13 +229,13 @@ static void __pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, u16 *new_state,
{
int row, col, code;
- for (row = 0; row < kp->pdata->num_rows; row++) {
+ for (row = 0; row < kp->num_rows; row++) {
int bits_changed = new_state[row] ^ old_state[row];
if (!bits_changed)
continue;
- for (col = 0; col < kp->pdata->num_cols; col++) {
+ for (col = 0; col < kp->num_cols; col++) {
if (!(bits_changed & (1 << col)))
continue;
@@ -287,9 +261,9 @@ static bool pmic8xxx_detect_ghost_keys(struct pmic8xxx_kp *kp, u16 *new_state)
u16 check, row_state;
check = 0;
- for (row = 0; row < kp->pdata->num_rows; row++) {
+ for (row = 0; row < kp->num_rows; row++) {
row_state = (~new_state[row]) &
- ((1 << kp->pdata->num_cols) - 1);
+ ((1 << kp->num_cols) - 1);
if (hweight16(row_state) > 1) {
if (found_first == -1)
@@ -379,10 +353,10 @@ static irqreturn_t pmic8xxx_kp_stuck_irq(int irq, void *data)
static irqreturn_t pmic8xxx_kp_irq(int irq, void *data)
{
struct pmic8xxx_kp *kp = data;
- u8 ctrl_val, events;
+ unsigned int ctrl_val, events;
int rc;
- rc = pmic8xxx_kp_read(kp, &ctrl_val, KEYP_CTRL, 1);
+ rc = regmap_read(kp->regmap, KEYP_CTRL, &ctrl_val);
if (rc < 0) {
dev_err(kp->dev, "failed to read keyp_ctrl register\n");
return IRQ_HANDLED;
@@ -397,8 +371,13 @@ static irqreturn_t pmic8xxx_kp_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp)
+static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp,
+ struct platform_device *pdev)
{
+ const struct device_node *of_node = pdev->dev.of_node;
+ unsigned int scan_delay_ms;
+ unsigned int row_hold_ns;
+ unsigned int debounce_ms;
int bits, rc, cycles;
u8 scan_val = 0, ctrl_val = 0;
static const u8 row_bits[] = {
@@ -406,40 +385,69 @@ static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp)
};
/* Find column bits */
- if (kp->pdata->num_cols < KEYP_CTRL_SCAN_COLS_MIN)
+ if (kp->num_cols < KEYP_CTRL_SCAN_COLS_MIN)
bits = 0;
else
- bits = kp->pdata->num_cols - KEYP_CTRL_SCAN_COLS_MIN;
+ bits = kp->num_cols - KEYP_CTRL_SCAN_COLS_MIN;
ctrl_val = (bits & KEYP_CTRL_SCAN_COLS_BITS) <<
KEYP_CTRL_SCAN_COLS_SHIFT;
/* Find row bits */
- if (kp->pdata->num_rows < KEYP_CTRL_SCAN_ROWS_MIN)
+ if (kp->num_rows < KEYP_CTRL_SCAN_ROWS_MIN)
bits = 0;
else
- bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN];
+ bits = row_bits[kp->num_rows - KEYP_CTRL_SCAN_ROWS_MIN];
ctrl_val |= (bits << KEYP_CTRL_SCAN_ROWS_SHIFT);
- rc = pmic8xxx_kp_write_u8(kp, ctrl_val, KEYP_CTRL);
+ rc = regmap_write(kp->regmap, KEYP_CTRL, ctrl_val);
if (rc < 0) {
dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc);
return rc;
}
- bits = (kp->pdata->debounce_ms / 5) - 1;
+ if (of_property_read_u32(of_node, "scan-delay", &scan_delay_ms))
+ scan_delay_ms = MIN_SCAN_DELAY;
+
+ if (scan_delay_ms > MAX_SCAN_DELAY || scan_delay_ms < MIN_SCAN_DELAY ||
+ !is_power_of_2(scan_delay_ms)) {
+ dev_err(&pdev->dev, "invalid keypad scan time supplied\n");
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32(of_node, "row-hold", &row_hold_ns))
+ row_hold_ns = MIN_ROW_HOLD_DELAY;
+
+ if (row_hold_ns > MAX_ROW_HOLD_DELAY ||
+ row_hold_ns < MIN_ROW_HOLD_DELAY ||
+ ((row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) {
+ dev_err(&pdev->dev, "invalid keypad row hold time supplied\n");
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32(of_node, "debounce", &debounce_ms))
+ debounce_ms = MIN_DEBOUNCE_TIME;
+
+ if (((debounce_ms % 5) != 0) ||
+ debounce_ms > MAX_DEBOUNCE_TIME ||
+ debounce_ms < MIN_DEBOUNCE_TIME) {
+ dev_err(&pdev->dev, "invalid debounce time supplied\n");
+ return -EINVAL;
+ }
+
+ bits = (debounce_ms / 5) - 1;
scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT);
- bits = fls(kp->pdata->scan_delay_ms) - 1;
+ bits = fls(scan_delay_ms) - 1;
scan_val |= (bits << KEYP_SCAN_PAUSE_SHIFT);
/* Row hold time is a multiple of 32KHz cycles. */
- cycles = (kp->pdata->row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC;
+ cycles = (row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC;
scan_val |= (cycles << KEYP_SCAN_ROW_HOLD_SHIFT);
- rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
+ rc = regmap_write(kp->regmap, KEYP_SCAN, scan_val);
if (rc)
dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
@@ -447,34 +455,13 @@ static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp)
}
-static int pmic8xxx_kp_config_gpio(int gpio_start, int num_gpios,
- struct pmic8xxx_kp *kp, struct pm_gpio *gpio_config)
-{
- int rc, i;
-
- if (gpio_start < 0 || num_gpios < 0)
- return -EINVAL;
-
- for (i = 0; i < num_gpios; i++) {
- rc = pm8xxx_gpio_config(gpio_start + i, gpio_config);
- if (rc) {
- dev_err(kp->dev, "%s: FAIL pm8xxx_gpio_config():"
- "for PM GPIO [%d] rc=%d.\n",
- __func__, gpio_start + i, rc);
- return rc;
- }
- }
-
- return 0;
-}
-
static int pmic8xxx_kp_enable(struct pmic8xxx_kp *kp)
{
int rc;
kp->ctrl_reg |= KEYP_CTRL_KEYP_EN;
- rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL);
+ rc = regmap_write(kp->regmap, KEYP_CTRL, kp->ctrl_reg);
if (rc < 0)
dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc);
@@ -487,7 +474,7 @@ static int pmic8xxx_kp_disable(struct pmic8xxx_kp *kp)
kp->ctrl_reg &= ~KEYP_CTRL_KEYP_EN;
- rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL);
+ rc = regmap_write(kp->regmap, KEYP_CTRL, kp->ctrl_reg);
if (rc < 0)
return rc;
@@ -520,106 +507,62 @@ static void pmic8xxx_kp_close(struct input_dev *dev)
*/
static int pmic8xxx_kp_probe(struct platform_device *pdev)
{
- const struct pm8xxx_keypad_platform_data *pdata =
- dev_get_platdata(&pdev->dev);
- const struct matrix_keymap_data *keymap_data;
+ unsigned int rows, cols;
+ bool repeat;
+ bool wakeup;
struct pmic8xxx_kp *kp;
int rc;
- u8 ctrl_val;
-
- struct pm_gpio kypd_drv = {
- .direction = PM_GPIO_DIR_OUT,
- .output_buffer = PM_GPIO_OUT_BUF_OPEN_DRAIN,
- .output_value = 0,
- .pull = PM_GPIO_PULL_NO,
- .vin_sel = PM_GPIO_VIN_S3,
- .out_strength = PM_GPIO_STRENGTH_LOW,
- .function = PM_GPIO_FUNC_1,
- .inv_int_pol = 1,
- };
-
- struct pm_gpio kypd_sns = {
- .direction = PM_GPIO_DIR_IN,
- .pull = PM_GPIO_PULL_UP_31P5,
- .vin_sel = PM_GPIO_VIN_S3,
- .out_strength = PM_GPIO_STRENGTH_NO,
- .function = PM_GPIO_FUNC_NORMAL,
- .inv_int_pol = 1,
- };
+ unsigned int ctrl_val;
+ rc = matrix_keypad_parse_of_params(&pdev->dev, &rows, &cols);
+ if (rc)
+ return rc;
- if (!pdata || !pdata->num_cols || !pdata->num_rows ||
- pdata->num_cols > PM8XXX_MAX_COLS ||
- pdata->num_rows > PM8XXX_MAX_ROWS ||
- pdata->num_cols < PM8XXX_MIN_COLS) {
+ if (cols > PM8XXX_MAX_COLS || rows > PM8XXX_MAX_ROWS ||
+ cols < PM8XXX_MIN_COLS) {
dev_err(&pdev->dev, "invalid platform data\n");
return -EINVAL;
}
- if (!pdata->scan_delay_ms ||
- pdata->scan_delay_ms > MAX_SCAN_DELAY ||
- pdata->scan_delay_ms < MIN_SCAN_DELAY ||
- !is_power_of_2(pdata->scan_delay_ms)) {
- dev_err(&pdev->dev, "invalid keypad scan time supplied\n");
- return -EINVAL;
- }
-
- if (!pdata->row_hold_ns ||
- pdata->row_hold_ns > MAX_ROW_HOLD_DELAY ||
- pdata->row_hold_ns < MIN_ROW_HOLD_DELAY ||
- ((pdata->row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) {
- dev_err(&pdev->dev, "invalid keypad row hold time supplied\n");
- return -EINVAL;
- }
-
- if (!pdata->debounce_ms ||
- ((pdata->debounce_ms % 5) != 0) ||
- pdata->debounce_ms > MAX_DEBOUNCE_TIME ||
- pdata->debounce_ms < MIN_DEBOUNCE_TIME) {
- dev_err(&pdev->dev, "invalid debounce time supplied\n");
- return -EINVAL;
- }
-
- keymap_data = pdata->keymap_data;
- if (!keymap_data) {
- dev_err(&pdev->dev, "no keymap data supplied\n");
- return -EINVAL;
- }
+ repeat = !of_property_read_bool(pdev->dev.of_node,
+ "linux,input-no-autorepeat");
+ wakeup = of_property_read_bool(pdev->dev.of_node,
+ "linux,keypad-wakeup");
- kp = kzalloc(sizeof(*kp), GFP_KERNEL);
+ kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL);
if (!kp)
return -ENOMEM;
+ kp->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!kp->regmap)
+ return -ENODEV;
+
platform_set_drvdata(pdev, kp);
- kp->pdata = pdata;
+ kp->num_rows = rows;
+ kp->num_cols = cols;
kp->dev = &pdev->dev;
- kp->input = input_allocate_device();
+ kp->input = devm_input_allocate_device(&pdev->dev);
if (!kp->input) {
dev_err(&pdev->dev, "unable to allocate input device\n");
- rc = -ENOMEM;
- goto err_alloc_device;
+ return -ENOMEM;
}
kp->key_sense_irq = platform_get_irq(pdev, 0);
if (kp->key_sense_irq < 0) {
dev_err(&pdev->dev, "unable to get keypad sense irq\n");
- rc = -ENXIO;
- goto err_get_irq;
+ return kp->key_sense_irq;
}
kp->key_stuck_irq = platform_get_irq(pdev, 1);
if (kp->key_stuck_irq < 0) {
dev_err(&pdev->dev, "unable to get keypad stuck irq\n");
- rc = -ENXIO;
- goto err_get_irq;
+ return kp->key_stuck_irq;
}
- kp->input->name = pdata->input_name ? : "PMIC8XXX keypad";
- kp->input->phys = pdata->input_phys_device ? : "pmic8xxx_keypad/input0";
-
- kp->input->dev.parent = &pdev->dev;
+ kp->input->name = "PMIC8XXX keypad";
+ kp->input->phys = "pmic8xxx_keypad/input0";
kp->input->id.bustype = BUS_I2C;
kp->input->id.version = 0x0001;
@@ -629,15 +572,15 @@ static int pmic8xxx_kp_probe(struct platform_device *pdev)
kp->input->open = pmic8xxx_kp_open;
kp->input->close = pmic8xxx_kp_close;
- rc = matrix_keypad_build_keymap(keymap_data, NULL,
+ rc = matrix_keypad_build_keymap(NULL, NULL,
PM8XXX_MAX_ROWS, PM8XXX_MAX_COLS,
kp->keycodes, kp->input);
if (rc) {
dev_err(&pdev->dev, "failed to build keymap\n");
- goto err_get_irq;
+ return rc;
}
- if (pdata->rep)
+ if (repeat)
__set_bit(EV_REP, kp->input->evbit);
input_set_capability(kp->input, EV_MSC, MSC_SCAN);
@@ -647,44 +590,32 @@ static int pmic8xxx_kp_probe(struct platform_device *pdev)
memset(kp->keystate, 0xff, sizeof(kp->keystate));
memset(kp->stuckstate, 0xff, sizeof(kp->stuckstate));
- rc = pmic8xxx_kpd_init(kp);
+ rc = pmic8xxx_kpd_init(kp, pdev);
if (rc < 0) {
dev_err(&pdev->dev, "unable to initialize keypad controller\n");
- goto err_get_irq;
- }
-
- rc = pmic8xxx_kp_config_gpio(pdata->cols_gpio_start,
- pdata->num_cols, kp, &kypd_sns);
- if (rc < 0) {
- dev_err(&pdev->dev, "unable to configure keypad sense lines\n");
- goto err_gpio_config;
- }
-
- rc = pmic8xxx_kp_config_gpio(pdata->rows_gpio_start,
- pdata->num_rows, kp, &kypd_drv);
- if (rc < 0) {
- dev_err(&pdev->dev, "unable to configure keypad drive lines\n");
- goto err_gpio_config;
+ return rc;
}
- rc = request_any_context_irq(kp->key_sense_irq, pmic8xxx_kp_irq,
- IRQF_TRIGGER_RISING, "pmic-keypad", kp);
+ rc = devm_request_any_context_irq(&pdev->dev, kp->key_sense_irq,
+ pmic8xxx_kp_irq, IRQF_TRIGGER_RISING, "pmic-keypad",
+ kp);
if (rc < 0) {
dev_err(&pdev->dev, "failed to request keypad sense irq\n");
- goto err_get_irq;
+ return rc;
}
- rc = request_any_context_irq(kp->key_stuck_irq, pmic8xxx_kp_stuck_irq,
- IRQF_TRIGGER_RISING, "pmic-keypad-stuck", kp);
+ rc = devm_request_any_context_irq(&pdev->dev, kp->key_stuck_irq,
+ pmic8xxx_kp_stuck_irq, IRQF_TRIGGER_RISING,
+ "pmic-keypad-stuck", kp);
if (rc < 0) {
dev_err(&pdev->dev, "failed to request keypad stuck irq\n");
- goto err_req_stuck_irq;
+ return rc;
}
- rc = pmic8xxx_kp_read_u8(kp, &ctrl_val, KEYP_CTRL);
+ rc = regmap_read(kp->regmap, KEYP_CTRL, &ctrl_val);
if (rc < 0) {
dev_err(&pdev->dev, "failed to read KEYP_CTRL register\n");
- goto err_pmic_reg_read;
+ return rc;
}
kp->ctrl_reg = ctrl_val;
@@ -692,34 +623,10 @@ static int pmic8xxx_kp_probe(struct platform_device *pdev)
rc = input_register_device(kp->input);
if (rc < 0) {
dev_err(&pdev->dev, "unable to register keypad input device\n");
- goto err_pmic_reg_read;
+ return rc;
}
- device_init_wakeup(&pdev->dev, pdata->wakeup);
-
- return 0;
-
-err_pmic_reg_read:
- free_irq(kp->key_stuck_irq, kp);
-err_req_stuck_irq:
- free_irq(kp->key_sense_irq, kp);
-err_gpio_config:
-err_get_irq:
- input_free_device(kp->input);
-err_alloc_device:
- kfree(kp);
- return rc;
-}
-
-static int pmic8xxx_kp_remove(struct platform_device *pdev)
-{
- struct pmic8xxx_kp *kp = platform_get_drvdata(pdev);
-
- device_init_wakeup(&pdev->dev, 0);
- free_irq(kp->key_stuck_irq, kp);
- free_irq(kp->key_sense_irq, kp);
- input_unregister_device(kp->input);
- kfree(kp);
+ device_init_wakeup(&pdev->dev, wakeup);
return 0;
}
@@ -769,13 +676,20 @@ static int pmic8xxx_kp_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(pm8xxx_kp_pm_ops,
pmic8xxx_kp_suspend, pmic8xxx_kp_resume);
+static const struct of_device_id pm8xxx_match_table[] = {
+ { .compatible = "qcom,pm8058-keypad" },
+ { .compatible = "qcom,pm8921-keypad" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pm8xxx_match_table);
+
static struct platform_driver pmic8xxx_kp_driver = {
.probe = pmic8xxx_kp_probe,
- .remove = pmic8xxx_kp_remove,
.driver = {
- .name = PM8XXX_KEYPAD_DEV_NAME,
+ .name = "pm8xxx-keypad",
.owner = THIS_MODULE,
.pm = &pm8xxx_kp_pm_ops,
+ .of_match_table = pm8xxx_match_table,
},
};
module_platform_driver(pmic8xxx_kp_driver);
diff --git a/drivers/input/keyboard/tnetv107x-keypad.c b/drivers/input/keyboard/tnetv107x-keypad.c
deleted file mode 100644
index 086511c2121b..000000000000
--- a/drivers/input/keyboard/tnetv107x-keypad.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Texas Instruments TNETV107X Keypad Driver
- *
- * Copyright (C) 2010 Texas Instruments
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/input.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/input/matrix_keypad.h>
-#include <linux/module.h>
-
-#define BITS(x) (BIT(x) - 1)
-
-#define KEYPAD_ROWS 9
-#define KEYPAD_COLS 9
-
-#define DEBOUNCE_MIN 0x400ul
-#define DEBOUNCE_MAX 0x3ffffffful
-
-struct keypad_regs {
- u32 rev;
- u32 mode;
- u32 mask;
- u32 pol;
- u32 dclock;
- u32 rclock;
- u32 stable_cnt;
- u32 in_en;
- u32 out;
- u32 out_en;
- u32 in;
- u32 lock;
- u32 pres[3];
-};
-
-#define keypad_read(kp, reg) __raw_readl(&(kp)->regs->reg)
-#define keypad_write(kp, reg, val) __raw_writel(val, &(kp)->regs->reg)
-
-struct keypad_data {
- struct input_dev *input_dev;
- struct resource *res;
- struct keypad_regs __iomem *regs;
- struct clk *clk;
- struct device *dev;
- spinlock_t lock;
- int irq_press;
- int irq_release;
- int rows, cols, row_shift;
- int debounce_ms, active_low;
- u32 prev_keys[3];
- unsigned short keycodes[];
-};
-
-static irqreturn_t keypad_irq(int irq, void *data)
-{
- struct keypad_data *kp = data;
- int i, bit, val, row, col, code;
- unsigned long flags;
- u32 curr_keys[3];
- u32 change;
-
- spin_lock_irqsave(&kp->lock, flags);
-
- memset(curr_keys, 0, sizeof(curr_keys));
- if (irq == kp->irq_press)
- for (i = 0; i < 3; i++)
- curr_keys[i] = keypad_read(kp, pres[i]);
-
- for (i = 0; i < 3; i++) {
- change = curr_keys[i] ^ kp->prev_keys[i];
-
- while (change) {
- bit = fls(change) - 1;
- change ^= BIT(bit);
- val = curr_keys[i] & BIT(bit);
- bit += i * 32;
- row = bit / KEYPAD_COLS;
- col = bit % KEYPAD_COLS;
-
- code = MATRIX_SCAN_CODE(row, col, kp->row_shift);
- input_event(kp->input_dev, EV_MSC, MSC_SCAN, code);
- input_report_key(kp->input_dev, kp->keycodes[code],
- val);
- }
- }
- input_sync(kp->input_dev);
- memcpy(kp->prev_keys, curr_keys, sizeof(curr_keys));
-
- if (irq == kp->irq_press)
- keypad_write(kp, lock, 0); /* Allow hardware updates */
-
- spin_unlock_irqrestore(&kp->lock, flags);
-
- return IRQ_HANDLED;
-}
-
-static int keypad_start(struct input_dev *dev)
-{
- struct keypad_data *kp = input_get_drvdata(dev);
- unsigned long mask, debounce, clk_rate_khz;
- unsigned long flags;
-
- clk_enable(kp->clk);
- clk_rate_khz = clk_get_rate(kp->clk) / 1000;
-
- spin_lock_irqsave(&kp->lock, flags);
-
- /* Initialize device registers */
- keypad_write(kp, mode, 0);
-
- mask = BITS(kp->rows) << KEYPAD_COLS;
- mask |= BITS(kp->cols);
- keypad_write(kp, mask, ~mask);
-
- keypad_write(kp, pol, kp->active_low ? 0 : 0x3ffff);
- keypad_write(kp, stable_cnt, 3);
-
- debounce = kp->debounce_ms * clk_rate_khz;
- debounce = clamp(debounce, DEBOUNCE_MIN, DEBOUNCE_MAX);
- keypad_write(kp, dclock, debounce);
- keypad_write(kp, rclock, 4 * debounce);
-
- keypad_write(kp, in_en, 1);
-
- spin_unlock_irqrestore(&kp->lock, flags);
-
- return 0;
-}
-
-static void keypad_stop(struct input_dev *dev)
-{
- struct keypad_data *kp = input_get_drvdata(dev);
-
- synchronize_irq(kp->irq_press);
- synchronize_irq(kp->irq_release);
- clk_disable(kp->clk);
-}
-
-static int keypad_probe(struct platform_device *pdev)
-{
- const struct matrix_keypad_platform_data *pdata;
- const struct matrix_keymap_data *keymap_data;
- struct device *dev = &pdev->dev;
- struct keypad_data *kp;
- int error = 0, sz, row_shift;
- u32 rev = 0;
-
- pdata = dev_get_platdata(&pdev->dev);
- if (!pdata) {
- dev_err(dev, "cannot find device data\n");
- return -EINVAL;
- }
-
- keymap_data = pdata->keymap_data;
- if (!keymap_data) {
- dev_err(dev, "cannot find keymap data\n");
- return -EINVAL;
- }
-
- row_shift = get_count_order(pdata->num_col_gpios);
- sz = offsetof(struct keypad_data, keycodes);
- sz += (pdata->num_row_gpios << row_shift) * sizeof(kp->keycodes[0]);
- kp = kzalloc(sz, GFP_KERNEL);
- if (!kp) {
- dev_err(dev, "cannot allocate device info\n");
- return -ENOMEM;
- }
-
- kp->dev = dev;
- kp->rows = pdata->num_row_gpios;
- kp->cols = pdata->num_col_gpios;
- kp->row_shift = row_shift;
- platform_set_drvdata(pdev, kp);
- spin_lock_init(&kp->lock);
-
- kp->irq_press = platform_get_irq_byname(pdev, "press");
- kp->irq_release = platform_get_irq_byname(pdev, "release");
- if (kp->irq_press < 0 || kp->irq_release < 0) {
- dev_err(dev, "cannot determine device interrupts\n");
- error = -ENODEV;
- goto error_res;
- }
-
- kp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!kp->res) {
- dev_err(dev, "cannot determine register area\n");
- error = -ENODEV;
- goto error_res;
- }
-
- if (!request_mem_region(kp->res->start, resource_size(kp->res),
- pdev->name)) {
- dev_err(dev, "cannot claim register memory\n");
- kp->res = NULL;
- error = -EINVAL;
- goto error_res;
- }
-
- kp->regs = ioremap(kp->res->start, resource_size(kp->res));
- if (!kp->regs) {
- dev_err(dev, "cannot map register memory\n");
- error = -ENOMEM;
- goto error_map;
- }
-
- kp->clk = clk_get(dev, NULL);
- if (IS_ERR(kp->clk)) {
- dev_err(dev, "cannot claim device clock\n");
- error = PTR_ERR(kp->clk);
- goto error_clk;
- }
-
- error = request_threaded_irq(kp->irq_press, NULL, keypad_irq,
- IRQF_ONESHOT, dev_name(dev), kp);
- if (error < 0) {
- dev_err(kp->dev, "Could not allocate keypad press key irq\n");
- goto error_irq_press;
- }
-
- error = request_threaded_irq(kp->irq_release, NULL, keypad_irq,
- IRQF_ONESHOT, dev_name(dev), kp);
- if (error < 0) {
- dev_err(kp->dev, "Could not allocate keypad release key irq\n");
- goto error_irq_release;
- }
-
- kp->input_dev = input_allocate_device();
- if (!kp->input_dev) {
- dev_err(dev, "cannot allocate input device\n");
- error = -ENOMEM;
- goto error_input;
- }
-
- kp->input_dev->name = pdev->name;
- kp->input_dev->dev.parent = &pdev->dev;
- kp->input_dev->open = keypad_start;
- kp->input_dev->close = keypad_stop;
-
- clk_enable(kp->clk);
- rev = keypad_read(kp, rev);
- kp->input_dev->id.bustype = BUS_HOST;
- kp->input_dev->id.product = ((rev >> 8) & 0x07);
- kp->input_dev->id.version = ((rev >> 16) & 0xfff);
- clk_disable(kp->clk);
-
- error = matrix_keypad_build_keymap(keymap_data, NULL,
- kp->rows, kp->cols,
- kp->keycodes, kp->input_dev);
- if (error) {
- dev_err(dev, "Failed to build keymap\n");
- goto error_reg;
- }
-
- if (!pdata->no_autorepeat)
- kp->input_dev->evbit[0] |= BIT_MASK(EV_REP);
- input_set_capability(kp->input_dev, EV_MSC, MSC_SCAN);
-
- input_set_drvdata(kp->input_dev, kp);
-
- error = input_register_device(kp->input_dev);
- if (error < 0) {
- dev_err(dev, "Could not register input device\n");
- goto error_reg;
- }
-
- return 0;
-
-
-error_reg:
- input_free_device(kp->input_dev);
-error_input:
- free_irq(kp->irq_release, kp);
-error_irq_release:
- free_irq(kp->irq_press, kp);
-error_irq_press:
- clk_put(kp->clk);
-error_clk:
- iounmap(kp->regs);
-error_map:
- release_mem_region(kp->res->start, resource_size(kp->res));
-error_res:
- kfree(kp);
- return error;
-}
-
-static int keypad_remove(struct platform_device *pdev)
-{
- struct keypad_data *kp = platform_get_drvdata(pdev);
-
- free_irq(kp->irq_press, kp);
- free_irq(kp->irq_release, kp);
- input_unregister_device(kp->input_dev);
- clk_put(kp->clk);
- iounmap(kp->regs);
- release_mem_region(kp->res->start, resource_size(kp->res));
- kfree(kp);
-
- return 0;
-}
-
-static struct platform_driver keypad_driver = {
- .probe = keypad_probe,
- .remove = keypad_remove,
- .driver.name = "tnetv107x-keypad",
- .driver.owner = THIS_MODULE,
-};
-module_platform_driver(keypad_driver);
-
-MODULE_AUTHOR("Cyril Chemparathy");
-MODULE_DESCRIPTION("TNETV107X Keypad Driver");
-MODULE_ALIAS("platform:tnetv107x-keypad");
-MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 7904ab05527a..f772981bdcdb 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -269,7 +269,7 @@ config INPUT_COBALT_BTNS
config INPUT_WISTRON_BTNS
tristate "x86 Wistron laptop button interface"
- depends on X86 && !X86_64
+ depends on X86_32
select INPUT_POLLDEV
select INPUT_SPARSEKMAP
select NEW_LEDS
@@ -666,4 +666,14 @@ config INPUT_IDEAPAD_SLIDEBAR
To compile this driver as a module, choose M here: the
module will be called ideapad_slidebar.
+config INPUT_SOC_BUTTON_ARRAY
+ tristate "Windows-compatible SoC Button Array"
+ depends on KEYBOARD_GPIO
+ help
+ Say Y here if you have a SoC-based tablet that originally
+ runs Windows 8.
+
+ To compile this driver as a module, choose M here: the
+ module will be called soc_button_array.
+
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index cda71fc52fb3..4955ad322a01 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o
obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o
+obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY) += soc_button_array.o
obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o
obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o
diff --git a/drivers/input/misc/arizona-haptics.c b/drivers/input/misc/arizona-haptics.c
index 7a04f54ef961..ef2e281b0a43 100644
--- a/drivers/input/misc/arizona-haptics.c
+++ b/drivers/input/misc/arizona-haptics.c
@@ -37,7 +37,6 @@ static void arizona_haptics_work(struct work_struct *work)
struct arizona_haptics,
work);
struct arizona *arizona = haptics->arizona;
- struct mutex *dapm_mutex = &arizona->dapm->card->dapm_mutex;
int ret;
if (!haptics->arizona->dapm) {
@@ -67,13 +66,10 @@ static void arizona_haptics_work(struct work_struct *work)
return;
}
- mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-
ret = snd_soc_dapm_enable_pin(arizona->dapm, "HAPTICS");
if (ret != 0) {
dev_err(arizona->dev, "Failed to start HAPTICS: %d\n",
ret);
- mutex_unlock(dapm_mutex);
return;
}
@@ -81,21 +77,14 @@ static void arizona_haptics_work(struct work_struct *work)
if (ret != 0) {
dev_err(arizona->dev, "Failed to sync DAPM: %d\n",
ret);
- mutex_unlock(dapm_mutex);
return;
}
-
- mutex_unlock(dapm_mutex);
-
} else {
/* This disable sequence will be a noop if already enabled */
- mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-
ret = snd_soc_dapm_disable_pin(arizona->dapm, "HAPTICS");
if (ret != 0) {
dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n",
ret);
- mutex_unlock(dapm_mutex);
return;
}
@@ -103,12 +92,9 @@ static void arizona_haptics_work(struct work_struct *work)
if (ret != 0) {
dev_err(arizona->dev, "Failed to sync DAPM: %d\n",
ret);
- mutex_unlock(dapm_mutex);
return;
}
- mutex_unlock(dapm_mutex);
-
ret = regmap_update_bits(arizona->regmap,
ARIZONA_HAPTICS_CONTROL_1,
ARIZONA_HAP_CTRL_MASK,
@@ -155,16 +141,11 @@ static int arizona_haptics_play(struct input_dev *input, void *data,
static void arizona_haptics_close(struct input_dev *input)
{
struct arizona_haptics *haptics = input_get_drvdata(input);
- struct mutex *dapm_mutex = &haptics->arizona->dapm->card->dapm_mutex;
cancel_work_sync(&haptics->work);
- mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-
if (haptics->arizona->dapm)
snd_soc_dapm_disable_pin(haptics->arizona->dapm, "HAPTICS");
-
- mutex_unlock(dapm_mutex);
}
static int arizona_haptics_probe(struct platform_device *pdev)
diff --git a/drivers/input/misc/da9052_onkey.c b/drivers/input/misc/da9052_onkey.c
index 1f695f229ea8..184c8f21ab59 100644
--- a/drivers/input/misc/da9052_onkey.c
+++ b/drivers/input/misc/da9052_onkey.c
@@ -27,29 +27,32 @@ struct da9052_onkey {
static void da9052_onkey_query(struct da9052_onkey *onkey)
{
- int key_stat;
+ int ret;
- key_stat = da9052_reg_read(onkey->da9052, DA9052_EVENT_B_REG);
- if (key_stat < 0) {
+ ret = da9052_reg_read(onkey->da9052, DA9052_STATUS_A_REG);
+ if (ret < 0) {
dev_err(onkey->da9052->dev,
- "Failed to read onkey event %d\n", key_stat);
+ "Failed to read onkey event err=%d\n", ret);
} else {
/*
* Since interrupt for deassertion of ONKEY pin is not
* generated, onkey event state determines the onkey
* button state.
*/
- key_stat &= DA9052_EVENTB_ENONKEY;
- input_report_key(onkey->input, KEY_POWER, key_stat);
+ bool pressed = !(ret & DA9052_STATUSA_NONKEY);
+
+ input_report_key(onkey->input, KEY_POWER, pressed);
input_sync(onkey->input);
- }
- /*
- * Interrupt is generated only when the ONKEY pin is asserted.
- * Hence the deassertion of the pin is simulated through work queue.
- */
- if (key_stat)
- schedule_delayed_work(&onkey->work, msecs_to_jiffies(50));
+ /*
+ * Interrupt is generated only when the ONKEY pin
+ * is asserted. Hence the deassertion of the pin
+ * is simulated through work queue.
+ */
+ if (pressed)
+ schedule_delayed_work(&onkey->work,
+ msecs_to_jiffies(50));
+ }
}
static void da9052_onkey_work(struct work_struct *work)
diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c
index e204f26b0011..5a736397d9c8 100644
--- a/drivers/input/misc/ims-pcu.c
+++ b/drivers/input/misc/ims-pcu.c
@@ -51,6 +51,8 @@ struct ims_pcu_backlight {
#define IMS_PCU_BL_VERSION_LEN (9 + 1)
#define IMS_PCU_BL_RESET_REASON_LEN (2 + 1)
+#define IMS_PCU_PCU_B_DEVICE_ID 5
+
#define IMS_PCU_BUF_SIZE 128
struct ims_pcu {
@@ -68,6 +70,9 @@ struct ims_pcu {
char bl_version[IMS_PCU_BL_VERSION_LEN];
char reset_reason[IMS_PCU_BL_RESET_REASON_LEN];
int update_firmware_status;
+ u8 device_id;
+
+ u8 ofn_reg_addr;
struct usb_interface *ctrl_intf;
@@ -371,6 +376,8 @@ static void ims_pcu_destroy_gamepad(struct ims_pcu *pcu)
#define IMS_PCU_CMD_GET_DEVICE_ID 0xae
#define IMS_PCU_CMD_SPECIAL_INFO 0xb0
#define IMS_PCU_CMD_BOOTLOADER 0xb1 /* Pass data to bootloader */
+#define IMS_PCU_CMD_OFN_SET_CONFIG 0xb3
+#define IMS_PCU_CMD_OFN_GET_CONFIG 0xb4
/* PCU responses */
#define IMS_PCU_RSP_STATUS 0xc0
@@ -389,6 +396,9 @@ static void ims_pcu_destroy_gamepad(struct ims_pcu *pcu)
#define IMS_PCU_RSP_GET_DEVICE_ID 0xce
#define IMS_PCU_RSP_SPECIAL_INFO 0xd0
#define IMS_PCU_RSP_BOOTLOADER 0xd1 /* Bootloader response */
+#define IMS_PCU_RSP_OFN_SET_CONFIG 0xd2
+#define IMS_PCU_RSP_OFN_GET_CONFIG 0xd3
+
#define IMS_PCU_RSP_EVNT_BUTTONS 0xe0 /* Unsolicited, button state */
#define IMS_PCU_GAMEPAD_MASK 0x0001ff80UL /* Bits 7 through 16 */
@@ -1256,6 +1266,225 @@ static struct attribute_group ims_pcu_attr_group = {
.attrs = ims_pcu_attrs,
};
+/* Support for a separate OFN attribute group */
+
+#define OFN_REG_RESULT_OFFSET 2
+
+static int ims_pcu_read_ofn_config(struct ims_pcu *pcu, u8 addr, u8 *data)
+{
+ int error;
+ s16 result;
+
+ error = ims_pcu_execute_command(pcu, OFN_GET_CONFIG,
+ &addr, sizeof(addr));
+ if (error)
+ return error;
+
+ result = (s16)get_unaligned_le16(pcu->cmd_buf + OFN_REG_RESULT_OFFSET);
+ if (result < 0)
+ return -EIO;
+
+ /* We only need LSB */
+ *data = pcu->cmd_buf[OFN_REG_RESULT_OFFSET];
+ return 0;
+}
+
+static int ims_pcu_write_ofn_config(struct ims_pcu *pcu, u8 addr, u8 data)
+{
+ u8 buffer[] = { addr, data };
+ int error;
+ s16 result;
+
+ error = ims_pcu_execute_command(pcu, OFN_SET_CONFIG,
+ &buffer, sizeof(buffer));
+ if (error)
+ return error;
+
+ result = (s16)get_unaligned_le16(pcu->cmd_buf + OFN_REG_RESULT_OFFSET);
+ if (result < 0)
+ return -EIO;
+
+ return 0;
+}
+
+static ssize_t ims_pcu_ofn_reg_data_show(struct device *dev,
+ struct device_attribute *dattr,
+ char *buf)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct ims_pcu *pcu = usb_get_intfdata(intf);
+ int error;
+ u8 data;
+
+ mutex_lock(&pcu->cmd_mutex);
+ error = ims_pcu_read_ofn_config(pcu, pcu->ofn_reg_addr, &data);
+ mutex_unlock(&pcu->cmd_mutex);
+
+ if (error)
+ return error;
+
+ return scnprintf(buf, PAGE_SIZE, "%x\n", data);
+}
+
+static ssize_t ims_pcu_ofn_reg_data_store(struct device *dev,
+ struct device_attribute *dattr,
+ const char *buf, size_t count)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct ims_pcu *pcu = usb_get_intfdata(intf);
+ int error;
+ u8 value;
+
+ error = kstrtou8(buf, 0, &value);
+ if (error)
+ return error;
+
+ mutex_lock(&pcu->cmd_mutex);
+ error = ims_pcu_write_ofn_config(pcu, pcu->ofn_reg_addr, value);
+ mutex_unlock(&pcu->cmd_mutex);
+
+ return error ?: count;
+}
+
+static DEVICE_ATTR(reg_data, S_IRUGO | S_IWUSR,
+ ims_pcu_ofn_reg_data_show, ims_pcu_ofn_reg_data_store);
+
+static ssize_t ims_pcu_ofn_reg_addr_show(struct device *dev,
+ struct device_attribute *dattr,
+ char *buf)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct ims_pcu *pcu = usb_get_intfdata(intf);
+ int error;
+
+ mutex_lock(&pcu->cmd_mutex);
+ error = scnprintf(buf, PAGE_SIZE, "%x\n", pcu->ofn_reg_addr);
+ mutex_unlock(&pcu->cmd_mutex);
+
+ return error;
+}
+
+static ssize_t ims_pcu_ofn_reg_addr_store(struct device *dev,
+ struct device_attribute *dattr,
+ const char *buf, size_t count)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct ims_pcu *pcu = usb_get_intfdata(intf);
+ int error;
+ u8 value;
+
+ error = kstrtou8(buf, 0, &value);
+ if (error)
+ return error;
+
+ mutex_lock(&pcu->cmd_mutex);
+ pcu->ofn_reg_addr = value;
+ mutex_unlock(&pcu->cmd_mutex);
+
+ return error ?: count;
+}
+
+static DEVICE_ATTR(reg_addr, S_IRUGO | S_IWUSR,
+ ims_pcu_ofn_reg_addr_show, ims_pcu_ofn_reg_addr_store);
+
+struct ims_pcu_ofn_bit_attribute {
+ struct device_attribute dattr;
+ u8 addr;
+ u8 nr;
+};
+
+static ssize_t ims_pcu_ofn_bit_show(struct device *dev,
+ struct device_attribute *dattr,
+ char *buf)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct ims_pcu *pcu = usb_get_intfdata(intf);
+ struct ims_pcu_ofn_bit_attribute *attr =
+ container_of(dattr, struct ims_pcu_ofn_bit_attribute, dattr);
+ int error;
+ u8 data;
+
+ mutex_lock(&pcu->cmd_mutex);
+ error = ims_pcu_read_ofn_config(pcu, attr->addr, &data);
+ mutex_unlock(&pcu->cmd_mutex);
+
+ if (error)
+ return error;
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", !!(data & (1 << attr->nr)));
+}
+
+static ssize_t ims_pcu_ofn_bit_store(struct device *dev,
+ struct device_attribute *dattr,
+ const char *buf, size_t count)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct ims_pcu *pcu = usb_get_intfdata(intf);
+ struct ims_pcu_ofn_bit_attribute *attr =
+ container_of(dattr, struct ims_pcu_ofn_bit_attribute, dattr);
+ int error;
+ int value;
+ u8 data;
+
+ error = kstrtoint(buf, 0, &value);
+ if (error)
+ return error;
+
+ if (value > 1)
+ return -EINVAL;
+
+ mutex_lock(&pcu->cmd_mutex);
+
+ error = ims_pcu_read_ofn_config(pcu, attr->addr, &data);
+ if (!error) {
+ if (value)
+ data |= 1U << attr->nr;
+ else
+ data &= ~(1U << attr->nr);
+
+ error = ims_pcu_write_ofn_config(pcu, attr->addr, data);
+ }
+
+ mutex_unlock(&pcu->cmd_mutex);
+
+ return error ?: count;
+}
+
+#define IMS_PCU_OFN_BIT_ATTR(_field, _addr, _nr) \
+struct ims_pcu_ofn_bit_attribute ims_pcu_ofn_attr_##_field = { \
+ .dattr = __ATTR(_field, S_IWUSR | S_IRUGO, \
+ ims_pcu_ofn_bit_show, ims_pcu_ofn_bit_store), \
+ .addr = _addr, \
+ .nr = _nr, \
+}
+
+static IMS_PCU_OFN_BIT_ATTR(engine_enable, 0x60, 7);
+static IMS_PCU_OFN_BIT_ATTR(speed_enable, 0x60, 6);
+static IMS_PCU_OFN_BIT_ATTR(assert_enable, 0x60, 5);
+static IMS_PCU_OFN_BIT_ATTR(xyquant_enable, 0x60, 4);
+static IMS_PCU_OFN_BIT_ATTR(xyscale_enable, 0x60, 1);
+
+static IMS_PCU_OFN_BIT_ATTR(scale_x2, 0x63, 6);
+static IMS_PCU_OFN_BIT_ATTR(scale_y2, 0x63, 7);
+
+static struct attribute *ims_pcu_ofn_attrs[] = {
+ &dev_attr_reg_data.attr,
+ &dev_attr_reg_addr.attr,
+ &ims_pcu_ofn_attr_engine_enable.dattr.attr,
+ &ims_pcu_ofn_attr_speed_enable.dattr.attr,
+ &ims_pcu_ofn_attr_assert_enable.dattr.attr,
+ &ims_pcu_ofn_attr_xyquant_enable.dattr.attr,
+ &ims_pcu_ofn_attr_xyscale_enable.dattr.attr,
+ &ims_pcu_ofn_attr_scale_x2.dattr.attr,
+ &ims_pcu_ofn_attr_scale_y2.dattr.attr,
+ NULL
+};
+
+static struct attribute_group ims_pcu_ofn_attr_group = {
+ .name = "ofn",
+ .attrs = ims_pcu_ofn_attrs,
+};
+
static void ims_pcu_irq(struct urb *urb)
{
struct ims_pcu *pcu = urb->context;
@@ -1624,7 +1853,6 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
static atomic_t device_no = ATOMIC_INIT(0);
const struct ims_pcu_device_info *info;
- u8 device_id;
int error;
error = ims_pcu_get_device_info(pcu);
@@ -1633,7 +1861,7 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
return error;
}
- error = ims_pcu_identify_type(pcu, &device_id);
+ error = ims_pcu_identify_type(pcu, &pcu->device_id);
if (error) {
dev_err(pcu->dev,
"Failed to identify device, error: %d\n", error);
@@ -1645,9 +1873,9 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
return 0;
}
- if (device_id >= ARRAY_SIZE(ims_pcu_device_info) ||
- !ims_pcu_device_info[device_id].keymap) {
- dev_err(pcu->dev, "Device ID %d is not valid\n", device_id);
+ if (pcu->device_id >= ARRAY_SIZE(ims_pcu_device_info) ||
+ !ims_pcu_device_info[pcu->device_id].keymap) {
+ dev_err(pcu->dev, "Device ID %d is not valid\n", pcu->device_id);
/* Same as above, punt to userspace */
return 0;
}
@@ -1655,11 +1883,21 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
/* Device appears to be operable, complete initialization */
pcu->device_no = atomic_inc_return(&device_no) - 1;
+ /*
+ * PCU-B devices, both GEN_1 and GEN_2 do not have OFN sensor
+ */
+ if (pcu->device_id != IMS_PCU_PCU_B_DEVICE_ID) {
+ error = sysfs_create_group(&pcu->dev->kobj,
+ &ims_pcu_ofn_attr_group);
+ if (error)
+ return error;
+ }
+
error = ims_pcu_setup_backlight(pcu);
if (error)
return error;
- info = &ims_pcu_device_info[device_id];
+ info = &ims_pcu_device_info[pcu->device_id];
error = ims_pcu_setup_buttons(pcu, info->keymap, info->keymap_len);
if (error)
goto err_destroy_backlight;
@@ -1674,10 +1912,10 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
return 0;
-err_destroy_backlight:
- ims_pcu_destroy_backlight(pcu);
err_destroy_buttons:
ims_pcu_destroy_buttons(pcu);
+err_destroy_backlight:
+ ims_pcu_destroy_backlight(pcu);
return error;
}
@@ -1691,6 +1929,10 @@ static void ims_pcu_destroy_application_mode(struct ims_pcu *pcu)
ims_pcu_destroy_gamepad(pcu);
ims_pcu_destroy_buttons(pcu);
ims_pcu_destroy_backlight(pcu);
+
+ if (pcu->device_id != IMS_PCU_PCU_B_DEVICE_ID)
+ sysfs_remove_group(&pcu->dev->kobj,
+ &ims_pcu_ofn_attr_group);
}
}
diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c
index b88b7cbf93e2..6a915ba31bba 100644
--- a/drivers/input/misc/pm8xxx-vibrator.c
+++ b/drivers/input/misc/pm8xxx-vibrator.c
@@ -142,7 +142,6 @@ static int pm8xxx_vib_play_effect(struct input_dev *dev, void *data,
}
static int pm8xxx_vib_probe(struct platform_device *pdev)
-
{
struct pm8xxx_vib *vib;
struct input_dev *input_dev;
@@ -214,12 +213,20 @@ static int pm8xxx_vib_suspend(struct device *dev)
static SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL);
+static const struct of_device_id pm8xxx_vib_id_table[] = {
+ { .compatible = "qcom,pm8058-vib" },
+ { .compatible = "qcom,pm8921-vib" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pm8xxx_vib_id_table);
+
static struct platform_driver pm8xxx_vib_driver = {
.probe = pm8xxx_vib_probe,
.driver = {
.name = "pm8xxx-vib",
.owner = THIS_MODULE,
.pm = &pm8xxx_vib_pm_ops,
+ .of_match_table = pm8xxx_vib_id_table,
},
};
module_platform_driver(pm8xxx_vib_driver);
diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c
index 0e1a05f95858..1cb8fda7a166 100644
--- a/drivers/input/misc/pmic8xxx-pwrkey.c
+++ b/drivers/input/misc/pmic8xxx-pwrkey.c
@@ -19,8 +19,7 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/log2.h>
-
-#include <linux/input/pmic8xxx-pwrkey.h>
+#include <linux/of.h>
#define PON_CNTL_1 0x1C
#define PON_CNTL_PULL_UP BIT(7)
@@ -89,15 +88,15 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
unsigned int pon_cntl;
struct regmap *regmap;
struct pmic8xxx_pwrkey *pwrkey;
- const struct pm8xxx_pwrkey_platform_data *pdata =
- dev_get_platdata(&pdev->dev);
+ u32 kpd_delay;
+ bool pull_up;
- if (!pdata) {
- dev_err(&pdev->dev, "power key platform data not supplied\n");
- return -EINVAL;
- }
+ if (of_property_read_u32(pdev->dev.of_node, "debounce", &kpd_delay))
+ kpd_delay = 0;
- if (pdata->kpd_trigger_delay_us > 62500) {
+ pull_up = of_property_read_bool(pdev->dev.of_node, "pull-up");
+
+ if (kpd_delay > 62500) {
dev_err(&pdev->dev, "invalid power key trigger delay\n");
return -EINVAL;
}
@@ -125,7 +124,7 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
pwr->name = "pmic8xxx_pwrkey";
pwr->phys = "pmic8xxx_pwrkey/input0";
- delay = (pdata->kpd_trigger_delay_us << 10) / USEC_PER_SEC;
+ delay = (kpd_delay << 10) / USEC_PER_SEC;
delay = 1 + ilog2(delay);
err = regmap_read(regmap, PON_CNTL_1, &pon_cntl);
@@ -136,7 +135,7 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
- if (pdata->pull_up)
+ if (pull_up)
pon_cntl |= PON_CNTL_PULL_UP;
else
pon_cntl &= ~PON_CNTL_PULL_UP;
@@ -172,7 +171,7 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, pwrkey);
- device_init_wakeup(&pdev->dev, pdata->wakeup);
+ device_init_wakeup(&pdev->dev, 1);
return 0;
}
@@ -184,13 +183,21 @@ static int pmic8xxx_pwrkey_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id pm8xxx_pwr_key_id_table[] = {
+ { .compatible = "qcom,pm8058-pwrkey" },
+ { .compatible = "qcom,pm8921-pwrkey" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pm8xxx_pwr_key_id_table);
+
static struct platform_driver pmic8xxx_pwrkey_driver = {
.probe = pmic8xxx_pwrkey_probe,
.remove = pmic8xxx_pwrkey_remove,
.driver = {
- .name = PM8XXX_PWRKEY_DEV_NAME,
+ .name = "pm8xxx-pwrkey",
.owner = THIS_MODULE,
.pm = &pm8xxx_pwr_key_pm_ops,
+ .of_match_table = pm8xxx_pwr_key_id_table,
},
};
module_platform_driver(pmic8xxx_pwrkey_driver);
diff --git a/drivers/input/misc/sirfsoc-onkey.c b/drivers/input/misc/sirfsoc-onkey.c
index e8897c36d21b..e4104f9b2e6d 100644
--- a/drivers/input/misc/sirfsoc-onkey.c
+++ b/drivers/input/misc/sirfsoc-onkey.c
@@ -1,7 +1,8 @@
/*
* Power key driver for SiRF PrimaII
*
- * Copyright (c) 2013 Cambridge Silicon Radio Limited, a CSR plc group company.
+ * Copyright (c) 2013 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
+ * company.
*
* Licensed under GPLv2 or later.
*/
@@ -13,16 +14,41 @@
#include <linux/input.h>
#include <linux/rtc/sirfsoc_rtciobrg.h>
#include <linux/of.h>
+#include <linux/workqueue.h>
struct sirfsoc_pwrc_drvdata {
u32 pwrc_base;
struct input_dev *input;
+ struct delayed_work work;
};
#define PWRC_ON_KEY_BIT (1 << 0)
#define PWRC_INT_STATUS 0xc
#define PWRC_INT_MASK 0x10
+#define PWRC_PIN_STATUS 0x14
+#define PWRC_KEY_DETECT_UP_TIME 20 /* ms*/
+
+static int sirfsoc_pwrc_is_on_key_down(struct sirfsoc_pwrc_drvdata *pwrcdrv)
+{
+ u32 state = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base +
+ PWRC_PIN_STATUS);
+ return !(state & PWRC_ON_KEY_BIT); /* ON_KEY is active low */
+}
+
+static void sirfsoc_pwrc_report_event(struct work_struct *work)
+{
+ struct sirfsoc_pwrc_drvdata *pwrcdrv =
+ container_of(work, struct sirfsoc_pwrc_drvdata, work.work);
+
+ if (sirfsoc_pwrc_is_on_key_down(pwrcdrv)) {
+ schedule_delayed_work(&pwrcdrv->work,
+ msecs_to_jiffies(PWRC_KEY_DETECT_UP_TIME));
+ } else {
+ input_event(pwrcdrv->input, EV_KEY, KEY_POWER, 0);
+ input_sync(pwrcdrv->input);
+ }
+}
static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)
{
@@ -34,21 +60,44 @@ static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)
sirfsoc_rtc_iobrg_writel(int_status & ~PWRC_ON_KEY_BIT,
pwrcdrv->pwrc_base + PWRC_INT_STATUS);
- /*
- * For a typical Linux system, we report KEY_SUSPEND to trigger apm-power.c
- * to queue a SUSPEND APM event
- */
- input_event(pwrcdrv->input, EV_PWR, KEY_SUSPEND, 1);
+ input_event(pwrcdrv->input, EV_KEY, KEY_POWER, 1);
input_sync(pwrcdrv->input);
-
- /*
- * Todo: report KEY_POWER event for Android platforms, Android PowerManager
- * will handle the suspend and powerdown/hibernation
- */
+ schedule_delayed_work(&pwrcdrv->work,
+ msecs_to_jiffies(PWRC_KEY_DETECT_UP_TIME));
return IRQ_HANDLED;
}
+static void sirfsoc_pwrc_toggle_interrupts(struct sirfsoc_pwrc_drvdata *pwrcdrv,
+ bool enable)
+{
+ u32 int_mask;
+
+ int_mask = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + PWRC_INT_MASK);
+ if (enable)
+ int_mask |= PWRC_ON_KEY_BIT;
+ else
+ int_mask &= ~PWRC_ON_KEY_BIT;
+ sirfsoc_rtc_iobrg_writel(int_mask, pwrcdrv->pwrc_base + PWRC_INT_MASK);
+}
+
+static int sirfsoc_pwrc_open(struct input_dev *input)
+{
+ struct sirfsoc_pwrc_drvdata *pwrcdrv = input_get_drvdata(input);
+
+ sirfsoc_pwrc_toggle_interrupts(pwrcdrv, true);
+
+ return 0;
+}
+
+static void sirfsoc_pwrc_close(struct input_dev *input)
+{
+ struct sirfsoc_pwrc_drvdata *pwrcdrv = input_get_drvdata(input);
+
+ sirfsoc_pwrc_toggle_interrupts(pwrcdrv, false);
+ cancel_delayed_work_sync(&pwrcdrv->work);
+}
+
static const struct of_device_id sirfsoc_pwrc_of_match[] = {
{ .compatible = "sirf,prima2-pwrc" },
{},
@@ -70,7 +119,7 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)
}
/*
- * we can't use of_iomap because pwrc is not mapped in memory,
+ * We can't use of_iomap because pwrc is not mapped in memory,
* the so-called base address is only offset in rtciobrg
*/
error = of_property_read_u32(np, "reg", &pwrcdrv->pwrc_base);
@@ -86,11 +135,22 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)
pwrcdrv->input->name = "sirfsoc pwrckey";
pwrcdrv->input->phys = "pwrc/input0";
- pwrcdrv->input->evbit[0] = BIT_MASK(EV_PWR);
+ pwrcdrv->input->evbit[0] = BIT_MASK(EV_KEY);
+ input_set_capability(pwrcdrv->input, EV_KEY, KEY_POWER);
+
+ INIT_DELAYED_WORK(&pwrcdrv->work, sirfsoc_pwrc_report_event);
+
+ pwrcdrv->input->open = sirfsoc_pwrc_open;
+ pwrcdrv->input->close = sirfsoc_pwrc_close;
+
+ input_set_drvdata(pwrcdrv->input, pwrcdrv);
+
+ /* Make sure the device is quiesced */
+ sirfsoc_pwrc_toggle_interrupts(pwrcdrv, false);
irq = platform_get_irq(pdev, 0);
error = devm_request_irq(&pdev->dev, irq,
- sirfsoc_pwrc_isr, IRQF_SHARED,
+ sirfsoc_pwrc_isr, 0,
"sirfsoc_pwrc_int", pwrcdrv);
if (error) {
dev_err(&pdev->dev, "unable to claim irq %d, error: %d\n",
@@ -98,11 +158,6 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)
return error;
}
- sirfsoc_rtc_iobrg_writel(
- sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + PWRC_INT_MASK) |
- PWRC_ON_KEY_BIT,
- pwrcdrv->pwrc_base + PWRC_INT_MASK);
-
error = input_register_device(pwrcdrv->input);
if (error) {
dev_err(&pdev->dev,
@@ -111,7 +166,7 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)
return error;
}
- platform_set_drvdata(pdev, pwrcdrv);
+ dev_set_drvdata(&pdev->dev, pwrcdrv);
device_init_wakeup(&pdev->dev, 1);
return 0;
@@ -125,25 +180,25 @@ static int sirfsoc_pwrc_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM_SLEEP
-static int pwrc_resume(struct device *dev)
+static int sirfsoc_pwrc_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct sirfsoc_pwrc_drvdata *pwrcdrv = platform_get_drvdata(pdev);
+ struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_get_drvdata(dev);
+ struct input_dev *input = pwrcdrv->input;
/*
* Do not mask pwrc interrupt as we want pwrc work as a wakeup source
* if users touch X_ONKEY_B, see arch/arm/mach-prima2/pm.c
*/
- sirfsoc_rtc_iobrg_writel(
- sirfsoc_rtc_iobrg_readl(
- pwrcdrv->pwrc_base + PWRC_INT_MASK) | PWRC_ON_KEY_BIT,
- pwrcdrv->pwrc_base + PWRC_INT_MASK);
+ mutex_lock(&input->mutex);
+ if (input->users)
+ sirfsoc_pwrc_toggle_interrupts(pwrcdrv, true);
+ mutex_unlock(&input->mutex);
return 0;
}
#endif
-static SIMPLE_DEV_PM_OPS(sirfsoc_pwrc_pm_ops, NULL, pwrc_resume);
+static SIMPLE_DEV_PM_OPS(sirfsoc_pwrc_pm_ops, NULL, sirfsoc_pwrc_resume);
static struct platform_driver sirfsoc_pwrc_driver = {
.probe = sirfsoc_pwrc_probe,
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
new file mode 100644
index 000000000000..08ead2aaede5
--- /dev/null
+++ b/drivers/input/misc/soc_button_array.c
@@ -0,0 +1,218 @@
+/*
+ * Supports for the button array on SoC tablets originally running
+ * Windows 8.
+ *
+ * (C) Copyright 2014 Intel 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 the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/pnp.h>
+
+/*
+ * Definition of buttons on the tablet. The ACPI index of each button
+ * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
+ * Platforms"
+ */
+#define MAX_NBUTTONS 5
+
+struct soc_button_info {
+ const char *name;
+ int acpi_index;
+ unsigned int event_type;
+ unsigned int event_code;
+ bool autorepeat;
+ bool wakeup;
+};
+
+/*
+ * Some of the buttons like volume up/down are auto repeat, while others
+ * are not. To support both, we register two platform devices, and put
+ * buttons into them based on whether the key should be auto repeat.
+ */
+#define BUTTON_TYPES 2
+
+struct soc_button_data {
+ struct platform_device *children[BUTTON_TYPES];
+};
+
+/*
+ * Get the Nth GPIO number from the ACPI object.
+ */
+static int soc_button_lookup_gpio(struct device *dev, int acpi_index)
+{
+ struct gpio_desc *desc;
+ int gpio;
+
+ desc = gpiod_get_index(dev, KBUILD_MODNAME, acpi_index);
+ if (IS_ERR(desc))
+ return PTR_ERR(desc);
+
+ gpio = desc_to_gpio(desc);
+
+ gpiod_put(desc);
+
+ return gpio;
+}
+
+static struct platform_device *
+soc_button_device_create(struct pnp_dev *pdev,
+ const struct soc_button_info *button_info,
+ bool autorepeat)
+{
+ const struct soc_button_info *info;
+ struct platform_device *pd;
+ struct gpio_keys_button *gpio_keys;
+ struct gpio_keys_platform_data *gpio_keys_pdata;
+ int n_buttons = 0;
+ int gpio;
+ int error;
+
+ gpio_keys_pdata = devm_kzalloc(&pdev->dev,
+ sizeof(*gpio_keys_pdata) +
+ sizeof(*gpio_keys) * MAX_NBUTTONS,
+ GFP_KERNEL);
+ gpio_keys = (void *)(gpio_keys_pdata + 1);
+
+ for (info = button_info; info->name; info++) {
+ if (info->autorepeat != autorepeat)
+ continue;
+
+ gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
+ if (gpio < 0)
+ continue;
+
+ gpio_keys[n_buttons].type = info->event_type;
+ gpio_keys[n_buttons].code = info->event_code;
+ gpio_keys[n_buttons].gpio = gpio;
+ gpio_keys[n_buttons].active_low = 1;
+ gpio_keys[n_buttons].desc = info->name;
+ gpio_keys[n_buttons].wakeup = info->wakeup;
+ n_buttons++;
+ }
+
+ if (n_buttons == 0) {
+ error = -ENODEV;
+ goto err_free_mem;
+ }
+
+ gpio_keys_pdata->buttons = gpio_keys;
+ gpio_keys_pdata->nbuttons = n_buttons;
+ gpio_keys_pdata->rep = autorepeat;
+
+ pd = platform_device_alloc("gpio-keys", PLATFORM_DEVID_AUTO);
+ if (!pd) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ error = platform_device_add_data(pd, gpio_keys_pdata,
+ sizeof(*gpio_keys_pdata));
+ if (error)
+ goto err_free_pdev;
+
+ error = platform_device_add(pd);
+ if (error)
+ goto err_free_pdev;
+
+ return pd;
+
+err_free_pdev:
+ platform_device_put(pd);
+err_free_mem:
+ devm_kfree(&pdev->dev, gpio_keys_pdata);
+ return ERR_PTR(error);
+}
+
+static void soc_button_remove(struct pnp_dev *pdev)
+{
+ struct soc_button_data *priv = pnp_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < BUTTON_TYPES; i++)
+ if (priv->children[i])
+ platform_device_unregister(priv->children[i]);
+}
+
+static int soc_button_pnp_probe(struct pnp_dev *pdev,
+ const struct pnp_device_id *id)
+{
+ const struct soc_button_info *button_info = (void *)id->driver_data;
+ struct soc_button_data *priv;
+ struct platform_device *pd;
+ int i;
+ int error;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ pnp_set_drvdata(pdev, priv);
+
+ for (i = 0; i < BUTTON_TYPES; i++) {
+ pd = soc_button_device_create(pdev, button_info, i == 0);
+ if (IS_ERR(pd)) {
+ error = PTR_ERR(pd);
+ if (error != -ENODEV) {
+ soc_button_remove(pdev);
+ return error;
+ }
+ }
+
+ priv->children[i] = pd;
+ }
+
+ if (!priv->children[0] && !priv->children[1])
+ return -ENODEV;
+
+ return 0;
+}
+
+static struct soc_button_info soc_button_PNP0C40[] = {
+ { "power", 0, EV_KEY, KEY_POWER, false, true },
+ { "home", 1, EV_KEY, KEY_HOME, false, true },
+ { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
+ { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false },
+ { "rotation_lock", 4, EV_SW, SW_ROTATE_LOCK, false, false },
+ { }
+};
+
+static const struct pnp_device_id soc_button_pnp_match[] = {
+ { .id = "PNP0C40", .driver_data = (long)soc_button_PNP0C40 },
+ { .id = "" }
+};
+MODULE_DEVICE_TABLE(pnp, soc_button_pnp_match);
+
+static struct pnp_driver soc_button_pnp_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = soc_button_pnp_match,
+ .probe = soc_button_pnp_probe,
+ .remove = soc_button_remove,
+};
+
+static int __init soc_button_init(void)
+{
+ return pnp_register_driver(&soc_button_pnp_driver);
+}
+
+static void __exit soc_button_exit(void)
+{
+ pnp_unregister_driver(&soc_button_pnp_driver);
+}
+
+module_init(soc_button_init);
+module_exit(soc_button_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 772835938a52..856936247500 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -20,6 +20,8 @@
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
*
* Changes/Revisions:
+ * 0.4 01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>)
+ * - add UI_GET_SYSNAME ioctl
* 0.3 09/04/2006 (Anssi Hannula <anssi.hannula@gmail.com>)
* - updated ff support for the changes in kernel interface
* - added MODULE_VERSION
@@ -670,6 +672,31 @@ static int uinput_ff_upload_from_user(const char __user *buffer,
__ret; \
})
+static int uinput_str_to_user(void __user *dest, const char *str,
+ unsigned int maxlen)
+{
+ char __user *p = dest;
+ int len, ret;
+
+ if (!str)
+ return -ENOENT;
+
+ if (maxlen == 0)
+ return -EINVAL;
+
+ len = strlen(str) + 1;
+ if (len > maxlen)
+ len = maxlen;
+
+ ret = copy_to_user(p, str, len);
+ if (ret)
+ return -EFAULT;
+
+ /* force terminating '\0' */
+ ret = put_user(0, p + len - 1);
+ return ret ? -EFAULT : len;
+}
+
static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
unsigned long arg, void __user *p)
{
@@ -679,6 +706,8 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
struct uinput_ff_erase ff_erase;
struct uinput_request *req;
char *phys;
+ const char *name;
+ unsigned int size;
retval = mutex_lock_interruptible(&udev->mutex);
if (retval)
@@ -693,51 +722,51 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
switch (cmd) {
case UI_DEV_CREATE:
retval = uinput_create_device(udev);
- break;
+ goto out;
case UI_DEV_DESTROY:
uinput_destroy_device(udev);
- break;
+ goto out;
case UI_SET_EVBIT:
retval = uinput_set_bit(arg, evbit, EV_MAX);
- break;
+ goto out;
case UI_SET_KEYBIT:
retval = uinput_set_bit(arg, keybit, KEY_MAX);
- break;
+ goto out;
case UI_SET_RELBIT:
retval = uinput_set_bit(arg, relbit, REL_MAX);
- break;
+ goto out;
case UI_SET_ABSBIT:
retval = uinput_set_bit(arg, absbit, ABS_MAX);
- break;
+ goto out;
case UI_SET_MSCBIT:
retval = uinput_set_bit(arg, mscbit, MSC_MAX);
- break;
+ goto out;
case UI_SET_LEDBIT:
retval = uinput_set_bit(arg, ledbit, LED_MAX);
- break;
+ goto out;
case UI_SET_SNDBIT:
retval = uinput_set_bit(arg, sndbit, SND_MAX);
- break;
+ goto out;
case UI_SET_FFBIT:
retval = uinput_set_bit(arg, ffbit, FF_MAX);
- break;
+ goto out;
case UI_SET_SWBIT:
retval = uinput_set_bit(arg, swbit, SW_MAX);
- break;
+ goto out;
case UI_SET_PROPBIT:
retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX);
- break;
+ goto out;
case UI_SET_PHYS:
if (udev->state == UIST_CREATED) {
@@ -753,18 +782,18 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
kfree(udev->dev->phys);
udev->dev->phys = phys;
- break;
+ goto out;
case UI_BEGIN_FF_UPLOAD:
retval = uinput_ff_upload_from_user(p, &ff_up);
if (retval)
- break;
+ goto out;
req = uinput_request_find(udev, ff_up.request_id);
if (!req || req->code != UI_FF_UPLOAD ||
!req->u.upload.effect) {
retval = -EINVAL;
- break;
+ goto out;
}
ff_up.retval = 0;
@@ -775,65 +804,77 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
memset(&ff_up.old, 0, sizeof(struct ff_effect));
retval = uinput_ff_upload_to_user(p, &ff_up);
- break;
+ goto out;
case UI_BEGIN_FF_ERASE:
if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
retval = -EFAULT;
- break;
+ goto out;
}
req = uinput_request_find(udev, ff_erase.request_id);
if (!req || req->code != UI_FF_ERASE) {
retval = -EINVAL;
- break;
+ goto out;
}
ff_erase.retval = 0;
ff_erase.effect_id = req->u.effect_id;
if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) {
retval = -EFAULT;
- break;
+ goto out;
}
- break;
+ goto out;
case UI_END_FF_UPLOAD:
retval = uinput_ff_upload_from_user(p, &ff_up);
if (retval)
- break;
+ goto out;
req = uinput_request_find(udev, ff_up.request_id);
if (!req || req->code != UI_FF_UPLOAD ||
!req->u.upload.effect) {
retval = -EINVAL;
- break;
+ goto out;
}
req->retval = ff_up.retval;
uinput_request_done(udev, req);
- break;
+ goto out;
case UI_END_FF_ERASE:
if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
retval = -EFAULT;
- break;
+ goto out;
}
req = uinput_request_find(udev, ff_erase.request_id);
if (!req || req->code != UI_FF_ERASE) {
retval = -EINVAL;
- break;
+ goto out;
}
req->retval = ff_erase.retval;
uinput_request_done(udev, req);
- break;
+ goto out;
+ }
- default:
- retval = -EINVAL;
+ size = _IOC_SIZE(cmd);
+
+ /* Now check variable-length commands */
+ switch (cmd & ~IOCSIZE_MASK) {
+ case UI_GET_SYSNAME(0):
+ if (udev->state != UIST_CREATED) {
+ retval = -ENOENT;
+ goto out;
+ }
+ name = dev_name(&udev->dev->dev);
+ retval = uinput_str_to_user(p, name, size);
+ goto out;
}
+ retval = -EINVAL;
out:
mutex_unlock(&udev->mutex);
return retval;
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index b6505454bcc4..7b7add5061a5 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -277,6 +277,16 @@ static struct key_entry keymap_fs_amilo_pro_v3505[] __initdata = {
{ KE_END, 0 }
};
+static struct key_entry keymap_fs_amilo_pro_v8210[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} }, /* Fn+F1 */
+ { KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Fn+F4 */
+ { KE_BLUETOOTH, 0x30 }, /* Fn+F10 */
+ { KE_KEY, 0x31, {KEY_MAIL} }, /* mail button */
+ { KE_KEY, 0x36, {KEY_WWW} }, /* www button */
+ { KE_WIFI, 0x78 }, /* satelite dish button */
+ { KE_END, FE_WIFI_LED }
+};
+
static struct key_entry keymap_fujitsu_n3510[] __initdata = {
{ KE_KEY, 0x11, {KEY_PROG1} },
{ KE_KEY, 0x12, {KEY_PROG2} },
@@ -654,6 +664,15 @@ static const struct dmi_system_id dmi_ids[] __initconst = {
.driver_data = keymap_fs_amilo_pro_v3505
},
{
+ /* Fujitsu-Siemens Amilo Pro Edition V8210 */
+ .callback = dmi_matched,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Series V8210"),
+ },
+ .driver_data = keymap_fs_amilo_pro_v8210
+ },
+ {
/* Fujitsu-Siemens Amilo M7400 */
.callback = dmi_matched,
.matches = {
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index 800ca7dfafc2..ef234c9b2f2f 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -48,6 +48,7 @@ struct atp_info {
int yfact; /* Y multiplication factor */
int datalen; /* size of USB transfers */
void (*callback)(struct urb *); /* callback function */
+ int fuzz; /* fuzz touchpad generates */
};
static void atp_complete_geyser_1_2(struct urb *urb);
@@ -61,6 +62,7 @@ static const struct atp_info fountain_info = {
.yfact = 43,
.datalen = 81,
.callback = atp_complete_geyser_1_2,
+ .fuzz = 16,
};
static const struct atp_info geyser1_info = {
@@ -71,6 +73,7 @@ static const struct atp_info geyser1_info = {
.yfact = 43,
.datalen = 81,
.callback = atp_complete_geyser_1_2,
+ .fuzz = 16,
};
static const struct atp_info geyser2_info = {
@@ -81,6 +84,7 @@ static const struct atp_info geyser2_info = {
.yfact = 43,
.datalen = 64,
.callback = atp_complete_geyser_1_2,
+ .fuzz = 0,
};
static const struct atp_info geyser3_info = {
@@ -90,6 +94,7 @@ static const struct atp_info geyser3_info = {
.yfact = 64,
.datalen = 64,
.callback = atp_complete_geyser_3_4,
+ .fuzz = 0,
};
static const struct atp_info geyser4_info = {
@@ -99,6 +104,7 @@ static const struct atp_info geyser4_info = {
.yfact = 64,
.datalen = 64,
.callback = atp_complete_geyser_3_4,
+ .fuzz = 0,
};
#define ATP_DEVICE(prod, info) \
@@ -155,8 +161,11 @@ MODULE_DEVICE_TABLE(usb, atp_table);
#define ATP_XSENSORS 26
#define ATP_YSENSORS 16
-/* amount of fuzz this touchpad generates */
-#define ATP_FUZZ 16
+/*
+ * The largest possible bank of sensors with additional buffer of 4 extra values
+ * on either side, for an array of smoothed sensor values.
+ */
+#define ATP_SMOOTHSIZE 34
/* maximum pressure this driver will report */
#define ATP_PRESSURE 300
@@ -165,7 +174,13 @@ MODULE_DEVICE_TABLE(usb, atp_table);
* Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is
* ignored.
*/
-#define ATP_THRESHOLD 5
+#define ATP_THRESHOLD 5
+
+/*
+ * How far we'll bitshift our sensor values before averaging them. Mitigates
+ * rounding errors.
+ */
+#define ATP_SCALE 12
/* Geyser initialization constants */
#define ATP_GEYSER_MODE_READ_REQUEST_ID 1
@@ -203,11 +218,14 @@ struct atp {
bool valid; /* are the samples valid? */
bool size_detect_done;
bool overflow_warned;
+ int fingers_old; /* last reported finger count */
int x_old; /* last reported x/y, */
int y_old; /* used for smoothing */
signed char xy_cur[ATP_XSENSORS + ATP_YSENSORS];
signed char xy_old[ATP_XSENSORS + ATP_YSENSORS];
int xy_acc[ATP_XSENSORS + ATP_YSENSORS];
+ int smooth[ATP_SMOOTHSIZE];
+ int smooth_tmp[ATP_SMOOTHSIZE];
int idlecount; /* number of empty packets */
struct work_struct work;
};
@@ -326,10 +344,17 @@ static void atp_reinit(struct work_struct *work)
retval);
}
-static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
- int *z, int *fingers)
+static int atp_calculate_abs(struct atp *dev, int offset, int nb_sensors,
+ int fact, int *z, int *fingers)
{
- int i;
+ int i, pass;
+
+ /*
+ * Use offset to point xy_sensors at the first value in dev->xy_acc
+ * for whichever dimension we're looking at this particular go-round.
+ */
+ int *xy_sensors = dev->xy_acc + offset;
+
/* values to calculate mean */
int pcum = 0, psum = 0;
int is_increasing = 0;
@@ -341,9 +366,6 @@ static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
if (is_increasing)
is_increasing = 0;
- continue;
- }
-
/*
* Makes the finger detection more versatile. For example,
* two fingers with no gap will be detected. Also, my
@@ -358,27 +380,63 @@ static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
*
* - Jason Parekh <jasonparekh@gmail.com>
*/
- if (i < 1 ||
+
+ } else if (i < 1 ||
(!is_increasing && xy_sensors[i - 1] < xy_sensors[i])) {
(*fingers)++;
is_increasing = 1;
} else if (i > 0 && (xy_sensors[i - 1] - xy_sensors[i] > threshold)) {
is_increasing = 0;
}
+ }
+
+ if (*fingers < 1) /* No need to continue if no fingers are found. */
+ return 0;
+ /*
+ * Use a smoothed version of sensor data for movement calculations, to
+ * combat noise without needing to rely so heavily on a threshold.
+ * This improves tracking.
+ *
+ * The smoothed array is bigger than the original so that the smoothing
+ * doesn't result in edge values being truncated.
+ */
+
+ memset(dev->smooth, 0, 4 * sizeof(dev->smooth[0]));
+ /* Pull base values, scaled up to help avoid truncation errors. */
+ for (i = 0; i < nb_sensors; i++)
+ dev->smooth[i + 4] = xy_sensors[i] << ATP_SCALE;
+ memset(&dev->smooth[nb_sensors + 4], 0, 4 * sizeof(dev->smooth[0]));
+
+ for (pass = 0; pass < 4; pass++) {
+ /* Handle edge. */
+ dev->smooth_tmp[0] = (dev->smooth[0] + dev->smooth[1]) / 2;
+
+ /* Average values with neighbors. */
+ for (i = 1; i < nb_sensors + 7; i++)
+ dev->smooth_tmp[i] = (dev->smooth[i - 1] +
+ dev->smooth[i] * 2 +
+ dev->smooth[i + 1]) / 4;
+
+ /* Handle other edge. */
+ dev->smooth_tmp[i] = (dev->smooth[i - 1] + dev->smooth[i]) / 2;
+
+ memcpy(dev->smooth, dev->smooth_tmp, sizeof(dev->smooth));
+ }
+
+ for (i = 0; i < nb_sensors + 8; i++) {
/*
- * Subtracts threshold so a high sensor that just passes the
- * threshold won't skew the calculated absolute coordinate.
- * Fixes an issue where slowly moving the mouse would
- * occasionally jump a number of pixels (slowly moving the
- * finger makes this issue most apparent.)
+ * Skip values if they're small enough to be truncated to 0
+ * by scale. Mostly noise.
*/
- pcum += (xy_sensors[i] - threshold) * i;
- psum += (xy_sensors[i] - threshold);
+ if ((dev->smooth[i] >> ATP_SCALE) > 0) {
+ pcum += dev->smooth[i] * i;
+ psum += dev->smooth[i];
+ }
}
if (psum > 0) {
- *z = psum;
+ *z = psum >> ATP_SCALE; /* Scale down pressure output. */
return pcum * fact / psum;
}
@@ -455,7 +513,7 @@ static void atp_detect_size(struct atp *dev)
input_set_abs_params(dev->input, ABS_X, 0,
(dev->info->xsensors_17 - 1) *
dev->info->xfact - 1,
- ATP_FUZZ, 0);
+ dev->info->fuzz, 0);
break;
}
}
@@ -471,7 +529,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)
{
int x, y, x_z, y_z, x_f, y_f;
int retval, i, j;
- int key;
+ int key, fingers;
struct atp *dev = urb->context;
int status = atp_status_check(urb);
@@ -548,16 +606,18 @@ static void atp_complete_geyser_1_2(struct urb *urb)
dbg_dump("accumulator", dev->xy_acc);
- x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
+ x = atp_calculate_abs(dev, 0, ATP_XSENSORS,
dev->info->xfact, &x_z, &x_f);
- y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
+ y = atp_calculate_abs(dev, ATP_XSENSORS, ATP_YSENSORS,
dev->info->yfact, &y_z, &y_f);
key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON;
- if (x && y) {
+ fingers = max(x_f, y_f);
+
+ if (x && y && fingers == dev->fingers_old) {
if (dev->x_old != -1) {
- x = (dev->x_old * 3 + x) >> 2;
- y = (dev->y_old * 3 + y) >> 2;
+ x = (dev->x_old * 7 + x) >> 3;
+ y = (dev->y_old * 7 + y) >> 3;
dev->x_old = x;
dev->y_old = y;
@@ -571,7 +631,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)
input_report_abs(dev->input, ABS_Y, y);
input_report_abs(dev->input, ABS_PRESSURE,
min(ATP_PRESSURE, x_z + y_z));
- atp_report_fingers(dev->input, max(x_f, y_f));
+ atp_report_fingers(dev->input, fingers);
}
dev->x_old = x;
dev->y_old = y;
@@ -579,6 +639,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)
} else if (!x && !y) {
dev->x_old = dev->y_old = -1;
+ dev->fingers_old = 0;
input_report_key(dev->input, BTN_TOUCH, 0);
input_report_abs(dev->input, ABS_PRESSURE, 0);
atp_report_fingers(dev->input, 0);
@@ -587,6 +648,10 @@ static void atp_complete_geyser_1_2(struct urb *urb)
memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
}
+ if (fingers != dev->fingers_old)
+ dev->x_old = dev->y_old = -1;
+ dev->fingers_old = fingers;
+
input_report_key(dev->input, BTN_LEFT, key);
input_sync(dev->input);
@@ -604,7 +669,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)
{
int x, y, x_z, y_z, x_f, y_f;
int retval, i, j;
- int key;
+ int key, fingers;
struct atp *dev = urb->context;
int status = atp_status_check(urb);
@@ -660,16 +725,19 @@ static void atp_complete_geyser_3_4(struct urb *urb)
dbg_dump("accumulator", dev->xy_acc);
- x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
+ x = atp_calculate_abs(dev, 0, ATP_XSENSORS,
dev->info->xfact, &x_z, &x_f);
- y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
+ y = atp_calculate_abs(dev, ATP_XSENSORS, ATP_YSENSORS,
dev->info->yfact, &y_z, &y_f);
+
key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON;
- if (x && y) {
+ fingers = max(x_f, y_f);
+
+ if (x && y && fingers == dev->fingers_old) {
if (dev->x_old != -1) {
- x = (dev->x_old * 3 + x) >> 2;
- y = (dev->y_old * 3 + y) >> 2;
+ x = (dev->x_old * 7 + x) >> 3;
+ y = (dev->y_old * 7 + y) >> 3;
dev->x_old = x;
dev->y_old = y;
@@ -683,7 +751,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)
input_report_abs(dev->input, ABS_Y, y);
input_report_abs(dev->input, ABS_PRESSURE,
min(ATP_PRESSURE, x_z + y_z));
- atp_report_fingers(dev->input, max(x_f, y_f));
+ atp_report_fingers(dev->input, fingers);
}
dev->x_old = x;
dev->y_old = y;
@@ -691,6 +759,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)
} else if (!x && !y) {
dev->x_old = dev->y_old = -1;
+ dev->fingers_old = 0;
input_report_key(dev->input, BTN_TOUCH, 0);
input_report_abs(dev->input, ABS_PRESSURE, 0);
atp_report_fingers(dev->input, 0);
@@ -699,6 +768,10 @@ static void atp_complete_geyser_3_4(struct urb *urb)
memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
}
+ if (fingers != dev->fingers_old)
+ dev->x_old = dev->y_old = -1;
+ dev->fingers_old = fingers;
+
input_report_key(dev->input, BTN_LEFT, key);
input_sync(dev->input);
@@ -843,10 +916,10 @@ static int atp_probe(struct usb_interface *iface,
input_set_abs_params(input_dev, ABS_X, 0,
(dev->info->xsensors - 1) * dev->info->xfact - 1,
- ATP_FUZZ, 0);
+ dev->info->fuzz, 0);
input_set_abs_params(input_dev, ABS_Y, 0,
(dev->info->ysensors - 1) * dev->info->yfact - 1,
- ATP_FUZZ, 0);
+ dev->info->fuzz, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0);
set_bit(EV_KEY, input_dev->evbit);
diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c
index 87095e2f5153..8af34ffe208b 100644
--- a/drivers/input/mouse/cypress_ps2.c
+++ b/drivers/input/mouse/cypress_ps2.c
@@ -409,7 +409,6 @@ static int cypress_set_input_params(struct input_dev *input,
__clear_bit(REL_X, input->relbit);
__clear_bit(REL_Y, input->relbit);
- __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
__set_bit(EV_KEY, input->evbit);
__set_bit(BTN_LEFT, input->keybit);
__set_bit(BTN_RIGHT, input->keybit);
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 26386f9d2569..d8d49d10f9bb 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -265,11 +265,22 @@ static int synaptics_identify(struct psmouse *psmouse)
* Read touchpad resolution and maximum reported coordinates
* Resolution is left zero if touchpad does not support the query
*/
+
+static const int *quirk_min_max;
+
static int synaptics_resolution(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
unsigned char resp[3];
+ if (quirk_min_max) {
+ priv->x_min = quirk_min_max[0];
+ priv->x_max = quirk_min_max[1];
+ priv->y_min = quirk_min_max[2];
+ priv->y_max = quirk_min_max[3];
+ return 0;
+ }
+
if (SYN_ID_MAJOR(priv->identity) < 4)
return 0;
@@ -1485,10 +1496,54 @@ static const struct dmi_system_id olpc_dmi_table[] __initconst = {
{ }
};
+static const struct dmi_system_id min_max_dmi_table[] __initconst = {
+#if defined(CONFIG_DMI)
+ {
+ /* Lenovo ThinkPad Helix */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Helix"),
+ },
+ .driver_data = (int []){1024, 5052, 2258, 4832},
+ },
+ {
+ /* Lenovo ThinkPad X240 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X240"),
+ },
+ .driver_data = (int []){1232, 5710, 1156, 4696},
+ },
+ {
+ /* Lenovo ThinkPad T440s */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T440"),
+ },
+ .driver_data = (int []){1024, 5112, 2024, 4832},
+ },
+ {
+ /* Lenovo ThinkPad T540p */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T540"),
+ },
+ .driver_data = (int []){1024, 5056, 2058, 4832},
+ },
+#endif
+ { }
+};
+
void __init synaptics_module_init(void)
{
+ const struct dmi_system_id *min_max_dmi;
+
impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
broken_olpc_ec = dmi_check_system(olpc_dmi_table);
+
+ min_max_dmi = dmi_first_match(min_max_dmi_table);
+ if (min_max_dmi)
+ quirk_min_max = min_max_dmi->driver_data;
}
static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 4c842c320c2e..b604564dec5c 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -67,7 +67,6 @@ struct mousedev {
struct device dev;
struct cdev cdev;
bool exist;
- bool is_mixdev;
struct list_head mixdev_node;
bool opened_by_mixdev;
@@ -77,6 +76,9 @@ struct mousedev {
int old_x[4], old_y[4];
int frac_dx, frac_dy;
unsigned long touch;
+
+ int (*open_device)(struct mousedev *mousedev);
+ void (*close_device)(struct mousedev *mousedev);
};
enum mousedev_emul {
@@ -116,9 +118,6 @@ static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 };
static struct mousedev *mousedev_mix;
static LIST_HEAD(mousedev_mix_list);
-static void mixdev_open_devices(void);
-static void mixdev_close_devices(void);
-
#define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
#define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
@@ -428,9 +427,7 @@ static int mousedev_open_device(struct mousedev *mousedev)
if (retval)
return retval;
- if (mousedev->is_mixdev)
- mixdev_open_devices();
- else if (!mousedev->exist)
+ if (!mousedev->exist)
retval = -ENODEV;
else if (!mousedev->open++) {
retval = input_open_device(&mousedev->handle);
@@ -446,9 +443,7 @@ static void mousedev_close_device(struct mousedev *mousedev)
{
mutex_lock(&mousedev->mutex);
- if (mousedev->is_mixdev)
- mixdev_close_devices();
- else if (mousedev->exist && !--mousedev->open)
+ if (mousedev->exist && !--mousedev->open)
input_close_device(&mousedev->handle);
mutex_unlock(&mousedev->mutex);
@@ -459,21 +454,29 @@ static void mousedev_close_device(struct mousedev *mousedev)
* stream. Note that this function is called with mousedev_mix->mutex
* held.
*/
-static void mixdev_open_devices(void)
+static int mixdev_open_devices(struct mousedev *mixdev)
{
- struct mousedev *mousedev;
+ int error;
+
+ error = mutex_lock_interruptible(&mixdev->mutex);
+ if (error)
+ return error;
- if (mousedev_mix->open++)
- return;
+ if (!mixdev->open++) {
+ struct mousedev *mousedev;
- list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
- if (!mousedev->opened_by_mixdev) {
- if (mousedev_open_device(mousedev))
- continue;
+ list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
+ if (!mousedev->opened_by_mixdev) {
+ if (mousedev_open_device(mousedev))
+ continue;
- mousedev->opened_by_mixdev = true;
+ mousedev->opened_by_mixdev = true;
+ }
}
}
+
+ mutex_unlock(&mixdev->mutex);
+ return 0;
}
/*
@@ -481,19 +484,22 @@ static void mixdev_open_devices(void)
* device. Note that this function is called with mousedev_mix->mutex
* held.
*/
-static void mixdev_close_devices(void)
+static void mixdev_close_devices(struct mousedev *mixdev)
{
- struct mousedev *mousedev;
+ mutex_lock(&mixdev->mutex);
- if (--mousedev_mix->open)
- return;
+ if (!--mixdev->open) {
+ struct mousedev *mousedev;
- list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
- if (mousedev->opened_by_mixdev) {
- mousedev->opened_by_mixdev = false;
- mousedev_close_device(mousedev);
+ list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
+ if (mousedev->opened_by_mixdev) {
+ mousedev->opened_by_mixdev = false;
+ mousedev_close_device(mousedev);
+ }
}
}
+
+ mutex_unlock(&mixdev->mutex);
}
@@ -522,7 +528,7 @@ static int mousedev_release(struct inode *inode, struct file *file)
mousedev_detach_client(mousedev, client);
kfree(client);
- mousedev_close_device(mousedev);
+ mousedev->close_device(mousedev);
return 0;
}
@@ -550,7 +556,7 @@ static int mousedev_open(struct inode *inode, struct file *file)
client->mousedev = mousedev;
mousedev_attach_client(mousedev, client);
- error = mousedev_open_device(mousedev);
+ error = mousedev->open_device(mousedev);
if (error)
goto err_free_client;
@@ -861,16 +867,21 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
if (mixdev) {
dev_set_name(&mousedev->dev, "mice");
+
+ mousedev->open_device = mixdev_open_devices;
+ mousedev->close_device = mixdev_close_devices;
} else {
int dev_no = minor;
/* Normalize device number if it falls into legacy range */
if (dev_no < MOUSEDEV_MINOR_BASE + MOUSEDEV_MINORS)
dev_no -= MOUSEDEV_MINOR_BASE;
dev_set_name(&mousedev->dev, "mouse%d", dev_no);
+
+ mousedev->open_device = mousedev_open_device;
+ mousedev->close_device = mousedev_close_device;
}
mousedev->exist = true;
- mousedev->is_mixdev = mixdev;
mousedev->handle.dev = input_get_device(dev);
mousedev->handle.name = dev_name(&mousedev->dev);
mousedev->handle.handler = handler;
@@ -919,7 +930,7 @@ static void mousedev_destroy(struct mousedev *mousedev)
device_del(&mousedev->dev);
mousedev_cleanup(mousedev);
input_free_minor(MINOR(mousedev->dev.devt));
- if (!mousedev->is_mixdev)
+ if (mousedev != mousedev_mix)
input_unregister_handle(&mousedev->handle);
put_device(&mousedev->dev);
}
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index aec54e283580..bc2d47431bdc 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -263,7 +263,7 @@ config SERIO_APBPS2
config SERIO_OLPC_APSP
tristate "OLPC AP-SP input support"
- depends on OF
+ depends on OLPC || COMPILE_TEST
help
Say Y here if you want support for the keyboard and touchpad included
in the OLPC XO-1.75 and XO-4 laptops.
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index d7a7e54f6465..852858e5d8d0 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -984,7 +984,7 @@ static void hp_sdc_exit(void)
free_irq(hp_sdc.irq, &hp_sdc);
write_unlock_irq(&hp_sdc.lock);
- del_timer(&hp_sdc.kicker);
+ del_timer_sync(&hp_sdc.kicker);
tasklet_kill(&hp_sdc.task);
diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c
index a70aa555bbff..e7409c45bdd0 100644
--- a/drivers/input/sparse-keymap.c
+++ b/drivers/input/sparse-keymap.c
@@ -236,7 +236,7 @@ EXPORT_SYMBOL(sparse_keymap_setup);
* in an input device that was set up by sparse_keymap_setup().
* NOTE: It is safe to cal this function while input device is
* still registered (however the drivers should care not to try to
- * use freed keymap and thus have to shut off interrups/polling
+ * use freed keymap and thus have to shut off interrupts/polling
* before freeing the keymap).
*/
void sparse_keymap_free(struct input_dev *dev)
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
index caecffe8caff..858045694e9d 100644
--- a/drivers/input/tablet/gtco.c
+++ b/drivers/input/tablet/gtco.c
@@ -848,7 +848,7 @@ static int gtco_probe(struct usb_interface *usbinterface,
gtco->inputdevice = input_dev;
/* Save interface information */
- gtco->usbdev = usb_get_dev(interface_to_usbdev(usbinterface));
+ gtco->usbdev = interface_to_usbdev(usbinterface);
gtco->intf = usbinterface;
/* Allocate some data for incoming reports */
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 07e9e82029d1..68edc9db2c64 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -514,15 +514,6 @@ config TOUCHSCREEN_MIGOR
To compile this driver as a module, choose M here: the
module will be called migor_ts.
-config TOUCHSCREEN_TNETV107X
- tristate "TI TNETV107X touchscreen support"
- depends on ARCH_DAVINCI_TNETV107X
- help
- Say Y here if you want to use the TNETV107X touchscreen.
-
- To compile this driver as a module, choose M here: the
- module will be called tnetv107x-ts.
-
config TOUCHSCREEN_TOUCHRIGHT
tristate "Touchright serial touchscreen"
select SERIO
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 62801f213346..4bc954b7c7c3 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -56,7 +56,6 @@ obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o
obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
-obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index 412a85ec9ba5..f8815bebc9ef 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -1,5 +1,7 @@
/*
* Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de>
+ * Daniel Wagener <daniel.wagener@kernelconcepts.de> (M09 firmware support)
+ * Lothar Waßmann <LW@KARO-electronics.de> (DT support)
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -33,6 +35,7 @@
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/gpio.h>
+#include <linux/of_gpio.h>
#include <linux/input/mt.h>
#include <linux/input/edt-ft5x06.h>
@@ -45,6 +48,14 @@
#define WORK_REGISTER_NUM_X 0x33
#define WORK_REGISTER_NUM_Y 0x34
+#define M09_REGISTER_THRESHOLD 0x80
+#define M09_REGISTER_GAIN 0x92
+#define M09_REGISTER_OFFSET 0x93
+#define M09_REGISTER_NUM_X 0x94
+#define M09_REGISTER_NUM_Y 0x95
+
+#define NO_REGISTER 0xff
+
#define WORK_REGISTER_OPMODE 0x3c
#define FACTORY_REGISTER_OPMODE 0x01
@@ -59,12 +70,30 @@
#define EDT_RAW_DATA_RETRIES 100
#define EDT_RAW_DATA_DELAY 1 /* msec */
+enum edt_ver {
+ M06,
+ M09,
+};
+
+struct edt_reg_addr {
+ int reg_threshold;
+ int reg_report_rate;
+ int reg_gain;
+ int reg_offset;
+ int reg_num_x;
+ int reg_num_y;
+};
+
struct edt_ft5x06_ts_data {
struct i2c_client *client;
struct input_dev *input;
u16 num_x;
u16 num_y;
+ int reset_pin;
+ int irq_pin;
+ int wake_pin;
+
#if defined(CONFIG_DEBUG_FS)
struct dentry *debug_dir;
u8 *raw_buffer;
@@ -79,6 +108,9 @@ struct edt_ft5x06_ts_data {
int report_rate;
char name[EDT_NAME_LEN];
+
+ struct edt_reg_addr reg_addr;
+ enum edt_ver version;
};
static int edt_ft5x06_ts_readwrite(struct i2c_client *client,
@@ -136,33 +168,58 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
{
struct edt_ft5x06_ts_data *tsdata = dev_id;
struct device *dev = &tsdata->client->dev;
- u8 cmd = 0xf9;
- u8 rdbuf[26];
+ u8 cmd;
+ u8 rdbuf[29];
int i, type, x, y, id;
+ int offset, tplen, datalen;
int error;
+ switch (tsdata->version) {
+ case M06:
+ cmd = 0xf9; /* tell the controller to send touch data */
+ offset = 5; /* where the actual touch data starts */
+ tplen = 4; /* data comes in so called frames */
+ datalen = 26; /* how much bytes to listen for */
+ break;
+
+ case M09:
+ cmd = 0x02;
+ offset = 1;
+ tplen = 6;
+ datalen = 29;
+ break;
+
+ default:
+ goto out;
+ }
+
memset(rdbuf, 0, sizeof(rdbuf));
error = edt_ft5x06_ts_readwrite(tsdata->client,
sizeof(cmd), &cmd,
- sizeof(rdbuf), rdbuf);
+ datalen, rdbuf);
if (error) {
dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n",
error);
goto out;
}
- if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || rdbuf[2] != 26) {
- dev_err_ratelimited(dev, "Unexpected header: %02x%02x%02x!\n",
- rdbuf[0], rdbuf[1], rdbuf[2]);
- goto out;
- }
+ /* M09 does not send header or CRC */
+ if (tsdata->version == M06) {
+ if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa ||
+ rdbuf[2] != datalen) {
+ dev_err_ratelimited(dev,
+ "Unexpected header: %02x%02x%02x!\n",
+ rdbuf[0], rdbuf[1], rdbuf[2]);
+ goto out;
+ }
- if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, 26))
- goto out;
+ if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, datalen))
+ goto out;
+ }
for (i = 0; i < MAX_SUPPORT_POINTS; i++) {
- u8 *buf = &rdbuf[i * 4 + 5];
+ u8 *buf = &rdbuf[i * tplen + offset];
bool down;
type = buf[0] >> 6;
@@ -170,10 +227,14 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
if (type == TOUCH_EVENT_RESERVED)
continue;
+ /* M06 sometimes sends bogus coordinates in TOUCH_DOWN */
+ if (tsdata->version == M06 && type == TOUCH_EVENT_DOWN)
+ continue;
+
x = ((buf[0] << 8) | buf[1]) & 0x0fff;
y = ((buf[2] << 8) | buf[3]) & 0x0fff;
id = (buf[2] >> 4) & 0x0f;
- down = (type != TOUCH_EVENT_UP);
+ down = type != TOUCH_EVENT_UP;
input_mt_slot(tsdata->input, id);
input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, down);
@@ -197,12 +258,25 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,
{
u8 wrbuf[4];
- wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
- wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
- wrbuf[2] = value;
- wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
-
- return edt_ft5x06_ts_readwrite(tsdata->client, 4, wrbuf, 0, NULL);
+ switch (tsdata->version) {
+ case M06:
+ wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
+ wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
+ wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
+ wrbuf[2] = value;
+ wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
+ return edt_ft5x06_ts_readwrite(tsdata->client, 4,
+ wrbuf, 0, NULL);
+ case M09:
+ wrbuf[0] = addr;
+ wrbuf[1] = value;
+
+ return edt_ft5x06_ts_readwrite(tsdata->client, 3,
+ wrbuf, 0, NULL);
+
+ default:
+ return -EINVAL;
+ }
}
static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
@@ -211,19 +285,36 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
u8 wrbuf[2], rdbuf[2];
int error;
- wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
- wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
- wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40;
+ switch (tsdata->version) {
+ case M06:
+ wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
+ wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
+ wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40;
- error = edt_ft5x06_ts_readwrite(tsdata->client, 2, wrbuf, 2, rdbuf);
- if (error)
- return error;
+ error = edt_ft5x06_ts_readwrite(tsdata->client, 2, wrbuf, 2,
+ rdbuf);
+ if (error)
+ return error;
- if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) {
- dev_err(&tsdata->client->dev,
- "crc error: 0x%02x expected, got 0x%02x\n",
- wrbuf[0] ^ wrbuf[1] ^ rdbuf[0], rdbuf[1]);
- return -EIO;
+ if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) {
+ dev_err(&tsdata->client->dev,
+ "crc error: 0x%02x expected, got 0x%02x\n",
+ wrbuf[0] ^ wrbuf[1] ^ rdbuf[0],
+ rdbuf[1]);
+ return -EIO;
+ }
+ break;
+
+ case M09:
+ wrbuf[0] = addr;
+ error = edt_ft5x06_ts_readwrite(tsdata->client, 1,
+ wrbuf, 1, rdbuf);
+ if (error)
+ return error;
+ break;
+
+ default:
+ return -EINVAL;
}
return rdbuf[0];
@@ -234,19 +325,21 @@ struct edt_ft5x06_attribute {
size_t field_offset;
u8 limit_low;
u8 limit_high;
- u8 addr;
+ u8 addr_m06;
+ u8 addr_m09;
};
-#define EDT_ATTR(_field, _mode, _addr, _limit_low, _limit_high) \
+#define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, \
+ _limit_low, _limit_high) \
struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = { \
.dattr = __ATTR(_field, _mode, \
edt_ft5x06_setting_show, \
edt_ft5x06_setting_store), \
- .field_offset = \
- offsetof(struct edt_ft5x06_ts_data, _field), \
+ .field_offset = offsetof(struct edt_ft5x06_ts_data, _field), \
+ .addr_m06 = _addr_m06, \
+ .addr_m09 = _addr_m09, \
.limit_low = _limit_low, \
.limit_high = _limit_high, \
- .addr = _addr, \
}
static ssize_t edt_ft5x06_setting_show(struct device *dev,
@@ -257,10 +350,11 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
struct edt_ft5x06_attribute *attr =
container_of(dattr, struct edt_ft5x06_attribute, dattr);
- u8 *field = (u8 *)((char *)tsdata + attr->field_offset);
+ u8 *field = (u8 *)tsdata + attr->field_offset;
int val;
size_t count = 0;
int error = 0;
+ u8 addr;
mutex_lock(&tsdata->mutex);
@@ -269,15 +363,33 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
goto out;
}
- val = edt_ft5x06_register_read(tsdata, attr->addr);
- if (val < 0) {
- error = val;
- dev_err(&tsdata->client->dev,
- "Failed to fetch attribute %s, error %d\n",
- dattr->attr.name, error);
+ switch (tsdata->version) {
+ case M06:
+ addr = attr->addr_m06;
+ break;
+
+ case M09:
+ addr = attr->addr_m09;
+ break;
+
+ default:
+ error = -ENODEV;
goto out;
}
+ if (addr != NO_REGISTER) {
+ val = edt_ft5x06_register_read(tsdata, addr);
+ if (val < 0) {
+ error = val;
+ dev_err(&tsdata->client->dev,
+ "Failed to fetch attribute %s, error %d\n",
+ dattr->attr.name, error);
+ goto out;
+ }
+ } else {
+ val = *field;
+ }
+
if (val != *field) {
dev_warn(&tsdata->client->dev,
"%s: read (%d) and stored value (%d) differ\n",
@@ -299,9 +411,10 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
struct edt_ft5x06_attribute *attr =
container_of(dattr, struct edt_ft5x06_attribute, dattr);
- u8 *field = (u8 *)((char *)tsdata + attr->field_offset);
+ u8 *field = (u8 *)tsdata + attr->field_offset;
unsigned int val;
int error;
+ u8 addr;
mutex_lock(&tsdata->mutex);
@@ -319,14 +432,29 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,
goto out;
}
- error = edt_ft5x06_register_write(tsdata, attr->addr, val);
- if (error) {
- dev_err(&tsdata->client->dev,
- "Failed to update attribute %s, error: %d\n",
- dattr->attr.name, error);
+ switch (tsdata->version) {
+ case M06:
+ addr = attr->addr_m06;
+ break;
+
+ case M09:
+ addr = attr->addr_m09;
+ break;
+
+ default:
+ error = -ENODEV;
goto out;
}
+ if (addr != NO_REGISTER) {
+ error = edt_ft5x06_register_write(tsdata, addr, val);
+ if (error) {
+ dev_err(&tsdata->client->dev,
+ "Failed to update attribute %s, error: %d\n",
+ dattr->attr.name, error);
+ goto out;
+ }
+ }
*field = val;
out:
@@ -334,12 +462,14 @@ out:
return error ?: count;
}
-static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, 0, 31);
-static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, 0, 31);
-static EDT_ATTR(threshold, S_IWUSR | S_IRUGO,
- WORK_REGISTER_THRESHOLD, 20, 80);
-static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO,
- WORK_REGISTER_REPORT_RATE, 3, 14);
+static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN,
+ M09_REGISTER_GAIN, 0, 31);
+static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET,
+ M09_REGISTER_OFFSET, 0, 31);
+static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD,
+ M09_REGISTER_THRESHOLD, 20, 80);
+static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE,
+ NO_REGISTER, 3, 14);
static struct attribute *edt_ft5x06_attrs[] = {
&edt_ft5x06_attr_gain.dattr.attr,
@@ -374,6 +504,9 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
}
/* mode register is 0x3c when in the work mode */
+ if (tsdata->version == M09)
+ goto m09_out;
+
error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03);
if (error) {
dev_err(&client->dev,
@@ -406,12 +539,18 @@ err_out:
enable_irq(client->irq);
return error;
+
+m09_out:
+ dev_err(&client->dev, "No factory mode support for M09\n");
+ return -EINVAL;
+
}
static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)
{
struct i2c_client *client = tsdata->client;
int retries = EDT_SWITCH_MODE_RETRIES;
+ struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
int ret;
int error;
@@ -444,13 +583,14 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)
tsdata->raw_buffer = NULL;
/* restore parameters */
- edt_ft5x06_register_write(tsdata, WORK_REGISTER_THRESHOLD,
+ edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold,
tsdata->threshold);
- edt_ft5x06_register_write(tsdata, WORK_REGISTER_GAIN,
+ edt_ft5x06_register_write(tsdata, reg_addr->reg_gain,
tsdata->gain);
- edt_ft5x06_register_write(tsdata, WORK_REGISTER_OFFSET,
+ edt_ft5x06_register_write(tsdata, reg_addr->reg_offset,
tsdata->offset);
- edt_ft5x06_register_write(tsdata, WORK_REGISTER_REPORT_RATE,
+ if (reg_addr->reg_report_rate)
+ edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate,
tsdata->report_rate);
enable_irq(client->irq);
@@ -479,7 +619,7 @@ static int edt_ft5x06_debugfs_mode_set(void *data, u64 mode)
if (mode != tsdata->factory_mode) {
retval = mode ? edt_ft5x06_factory_mode(tsdata) :
- edt_ft5x06_work_mode(tsdata);
+ edt_ft5x06_work_mode(tsdata);
}
mutex_unlock(&tsdata->mutex);
@@ -568,7 +708,6 @@ out:
return error ?: read;
};
-
static const struct file_operations debugfs_raw_data_fops = {
.open = simple_open,
.read = edt_ft5x06_debugfs_raw_data_read,
@@ -614,58 +753,100 @@ edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
#endif /* CONFIG_DEBUGFS */
-
-
static int edt_ft5x06_ts_reset(struct i2c_client *client,
- int reset_pin)
+ struct edt_ft5x06_ts_data *tsdata)
{
int error;
- if (gpio_is_valid(reset_pin)) {
+ if (gpio_is_valid(tsdata->wake_pin)) {
+ error = devm_gpio_request_one(&client->dev,
+ tsdata->wake_pin, GPIOF_OUT_INIT_LOW,
+ "edt-ft5x06 wake");
+ if (error) {
+ dev_err(&client->dev,
+ "Failed to request GPIO %d as wake pin, error %d\n",
+ tsdata->wake_pin, error);
+ return error;
+ }
+
+ msleep(5);
+ gpio_set_value(tsdata->wake_pin, 1);
+ }
+ if (gpio_is_valid(tsdata->reset_pin)) {
/* this pulls reset down, enabling the low active reset */
- error = devm_gpio_request_one(&client->dev, reset_pin,
- GPIOF_OUT_INIT_LOW,
- "edt-ft5x06 reset");
+ error = devm_gpio_request_one(&client->dev,
+ tsdata->reset_pin, GPIOF_OUT_INIT_LOW,
+ "edt-ft5x06 reset");
if (error) {
dev_err(&client->dev,
"Failed to request GPIO %d as reset pin, error %d\n",
- reset_pin, error);
+ tsdata->reset_pin, error);
return error;
}
- mdelay(50);
- gpio_set_value(reset_pin, 1);
- mdelay(100);
+ msleep(5);
+ gpio_set_value(tsdata->reset_pin, 1);
+ msleep(300);
}
return 0;
}
static int edt_ft5x06_ts_identify(struct i2c_client *client,
- char *model_name,
- char *fw_version)
+ struct edt_ft5x06_ts_data *tsdata,
+ char *fw_version)
{
u8 rdbuf[EDT_NAME_LEN];
char *p;
int error;
+ char *model_name = tsdata->name;
+ /* see what we find if we assume it is a M06 *
+ * if we get less than EDT_NAME_LEN, we don't want
+ * to have garbage in there
+ */
+ memset(rdbuf, 0, sizeof(rdbuf));
error = edt_ft5x06_ts_readwrite(client, 1, "\xbb",
EDT_NAME_LEN - 1, rdbuf);
if (error)
return error;
- /* remove last '$' end marker */
- rdbuf[EDT_NAME_LEN - 1] = '\0';
- if (rdbuf[EDT_NAME_LEN - 2] == '$')
- rdbuf[EDT_NAME_LEN - 2] = '\0';
+ /* if we find something consistent, stay with that assumption
+ * at least M09 won't send 3 bytes here
+ */
+ if (!(strnicmp(rdbuf + 1, "EP0", 3))) {
+ tsdata->version = M06;
+
+ /* remove last '$' end marker */
+ rdbuf[EDT_NAME_LEN - 1] = '\0';
+ if (rdbuf[EDT_NAME_LEN - 2] == '$')
+ rdbuf[EDT_NAME_LEN - 2] = '\0';
+
+ /* look for Model/Version separator */
+ p = strchr(rdbuf, '*');
+ if (p)
+ *p++ = '\0';
+ strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN);
+ strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
+ } else {
+ /* since there are only two versions around (M06, M09) */
+ tsdata->version = M09;
+
+ error = edt_ft5x06_ts_readwrite(client, 1, "\xA6",
+ 2, rdbuf);
+ if (error)
+ return error;
+
+ strlcpy(fw_version, rdbuf, 2);
- /* look for Model/Version separator */
- p = strchr(rdbuf, '*');
- if (p)
- *p++ = '\0';
+ error = edt_ft5x06_ts_readwrite(client, 1, "\xA8",
+ 1, rdbuf);
+ if (error)
+ return error;
- strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN);
- strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
+ snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09",
+ rdbuf[0] >> 4, rdbuf[0] & 0x0F);
+ }
return 0;
}
@@ -675,33 +856,104 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
pdata->name <= edt_ft5x06_attr_##name.limit_high) \
edt_ft5x06_register_write(tsdata, reg, pdata->name)
+#define EDT_GET_PROP(name, reg) { \
+ u32 val; \
+ if (of_property_read_u32(np, #name, &val) == 0) \
+ edt_ft5x06_register_write(tsdata, reg, val); \
+}
+
+static void edt_ft5x06_ts_get_dt_defaults(struct device_node *np,
+ struct edt_ft5x06_ts_data *tsdata)
+{
+ struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
+
+ EDT_GET_PROP(threshold, reg_addr->reg_threshold);
+ EDT_GET_PROP(gain, reg_addr->reg_gain);
+ EDT_GET_PROP(offset, reg_addr->reg_offset);
+}
+
static void
edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata,
const struct edt_ft5x06_platform_data *pdata)
{
+ struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
+
if (!pdata->use_parameters)
return;
/* pick up defaults from the platform data */
- EDT_ATTR_CHECKSET(threshold, WORK_REGISTER_THRESHOLD);
- EDT_ATTR_CHECKSET(gain, WORK_REGISTER_GAIN);
- EDT_ATTR_CHECKSET(offset, WORK_REGISTER_OFFSET);
- EDT_ATTR_CHECKSET(report_rate, WORK_REGISTER_REPORT_RATE);
+ EDT_ATTR_CHECKSET(threshold, reg_addr->reg_threshold);
+ EDT_ATTR_CHECKSET(gain, reg_addr->reg_gain);
+ EDT_ATTR_CHECKSET(offset, reg_addr->reg_offset);
+ if (reg_addr->reg_report_rate != NO_REGISTER)
+ EDT_ATTR_CHECKSET(report_rate, reg_addr->reg_report_rate);
}
static void
edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
{
+ struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
+
tsdata->threshold = edt_ft5x06_register_read(tsdata,
- WORK_REGISTER_THRESHOLD);
- tsdata->gain = edt_ft5x06_register_read(tsdata, WORK_REGISTER_GAIN);
- tsdata->offset = edt_ft5x06_register_read(tsdata, WORK_REGISTER_OFFSET);
- tsdata->report_rate = edt_ft5x06_register_read(tsdata,
- WORK_REGISTER_REPORT_RATE);
- tsdata->num_x = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_X);
- tsdata->num_y = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_Y);
+ reg_addr->reg_threshold);
+ tsdata->gain = edt_ft5x06_register_read(tsdata, reg_addr->reg_gain);
+ tsdata->offset = edt_ft5x06_register_read(tsdata, reg_addr->reg_offset);
+ if (reg_addr->reg_report_rate != NO_REGISTER)
+ tsdata->report_rate = edt_ft5x06_register_read(tsdata,
+ reg_addr->reg_report_rate);
+ tsdata->num_x = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_x);
+ tsdata->num_y = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_y);
+}
+
+static void
+edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
+{
+ struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
+
+ switch (tsdata->version) {
+ case M06:
+ reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD;
+ reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE;
+ reg_addr->reg_gain = WORK_REGISTER_GAIN;
+ reg_addr->reg_offset = WORK_REGISTER_OFFSET;
+ reg_addr->reg_num_x = WORK_REGISTER_NUM_X;
+ reg_addr->reg_num_y = WORK_REGISTER_NUM_Y;
+ break;
+
+ case M09:
+ reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
+ reg_addr->reg_gain = M09_REGISTER_GAIN;
+ reg_addr->reg_offset = M09_REGISTER_OFFSET;
+ reg_addr->reg_num_x = M09_REGISTER_NUM_X;
+ reg_addr->reg_num_y = M09_REGISTER_NUM_Y;
+ break;
+ }
}
+#ifdef CONFIG_OF
+static int edt_ft5x06_i2c_ts_probe_dt(struct device *dev,
+ struct edt_ft5x06_ts_data *tsdata)
+{
+ struct device_node *np = dev->of_node;
+
+ /*
+ * irq_pin is not needed for DT setup.
+ * irq is associated via 'interrupts' property in DT
+ */
+ tsdata->irq_pin = -EINVAL;
+ tsdata->reset_pin = of_get_named_gpio(np, "reset-gpios", 0);
+ tsdata->wake_pin = of_get_named_gpio(np, "wake-gpios", 0);
+
+ return 0;
+}
+#else
+static inline int edt_ft5x06_i2c_ts_probe_dt(struct device *dev,
+ struct edt_ft5x06_ts_data *tsdata)
+{
+ return -ENODEV;
+}
+#endif
+
static int edt_ft5x06_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -714,32 +966,40 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n");
+ tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL);
+ if (!tsdata) {
+ dev_err(&client->dev, "failed to allocate driver data.\n");
+ return -ENOMEM;
+ }
+
if (!pdata) {
- dev_err(&client->dev, "no platform data?\n");
- return -EINVAL;
+ error = edt_ft5x06_i2c_ts_probe_dt(&client->dev, tsdata);
+ if (error) {
+ dev_err(&client->dev,
+ "DT probe failed and no platform data present\n");
+ return error;
+ }
+ } else {
+ tsdata->reset_pin = pdata->reset_pin;
+ tsdata->irq_pin = pdata->irq_pin;
+ tsdata->wake_pin = -EINVAL;
}
- error = edt_ft5x06_ts_reset(client, pdata->reset_pin);
+ error = edt_ft5x06_ts_reset(client, tsdata);
if (error)
return error;
- if (gpio_is_valid(pdata->irq_pin)) {
- error = devm_gpio_request_one(&client->dev, pdata->irq_pin,
- GPIOF_IN, "edt-ft5x06 irq");
+ if (gpio_is_valid(tsdata->irq_pin)) {
+ error = devm_gpio_request_one(&client->dev, tsdata->irq_pin,
+ GPIOF_IN, "edt-ft5x06 irq");
if (error) {
dev_err(&client->dev,
"Failed to request GPIO %d, error %d\n",
- pdata->irq_pin, error);
+ tsdata->irq_pin, error);
return error;
}
}
- tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL);
- if (!tsdata) {
- dev_err(&client->dev, "failed to allocate driver data.\n");
- return -ENOMEM;
- }
-
input = devm_input_allocate_device(&client->dev);
if (!input) {
dev_err(&client->dev, "failed to allocate input device.\n");
@@ -751,13 +1011,19 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
tsdata->input = input;
tsdata->factory_mode = false;
- error = edt_ft5x06_ts_identify(client, tsdata->name, fw_version);
+ error = edt_ft5x06_ts_identify(client, tsdata, fw_version);
if (error) {
dev_err(&client->dev, "touchscreen probe failed\n");
return error;
}
- edt_ft5x06_ts_get_defaults(tsdata, pdata);
+ edt_ft5x06_ts_set_regs(tsdata);
+
+ if (!pdata)
+ edt_ft5x06_ts_get_dt_defaults(client->dev.of_node, tsdata);
+ else
+ edt_ft5x06_ts_get_defaults(tsdata, pdata);
+
edt_ft5x06_ts_get_parameters(tsdata);
dev_dbg(&client->dev,
@@ -787,10 +1053,10 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
input_set_drvdata(input, tsdata);
i2c_set_clientdata(client, tsdata);
- error = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, edt_ft5x06_ts_isr,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- client->name, tsdata);
+ error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+ edt_ft5x06_ts_isr,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ client->name, tsdata);
if (error) {
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
return error;
@@ -801,19 +1067,21 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
return error;
error = input_register_device(input);
- if (error) {
- sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
- return error;
- }
+ if (error)
+ goto err_remove_attrs;
edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
device_init_wakeup(&client->dev, 1);
dev_dbg(&client->dev,
- "EDT FT5x06 initialized: IRQ pin %d, Reset pin %d.\n",
- pdata->irq_pin, pdata->reset_pin);
+ "EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n",
+ client->irq, tsdata->wake_pin, tsdata->reset_pin);
return 0;
+
+err_remove_attrs:
+ sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
+ return error;
}
static int edt_ft5x06_ts_remove(struct i2c_client *client)
@@ -852,15 +1120,26 @@ static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops,
edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume);
static const struct i2c_device_id edt_ft5x06_ts_id[] = {
- { "edt-ft5x06", 0 },
- { }
+ { "edt-ft5x06", 0, },
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id);
+#ifdef CONFIG_OF
+static const struct of_device_id edt_ft5x06_of_match[] = {
+ { .compatible = "edt,edt-ft5206", },
+ { .compatible = "edt,edt-ft5306", },
+ { .compatible = "edt,edt-ft5406", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match);
+#endif
+
static struct i2c_driver edt_ft5x06_ts_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "edt_ft5x06",
+ .of_match_table = of_match_ptr(edt_ft5x06_of_match),
.pm = &edt_ft5x06_ts_pm_ops,
},
.id_table = edt_ft5x06_ts_id,
diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c
index 5c342b3139e8..3c0f57efe7b1 100644
--- a/drivers/input/touchscreen/st1232.c
+++ b/drivers/input/touchscreen/st1232.c
@@ -134,7 +134,8 @@ static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id)
} else if (!ts->low_latency_req.dev) {
/* First contact, request 100 us latency. */
dev_pm_qos_add_ancestor_request(&ts->client->dev,
- &ts->low_latency_req, 100);
+ &ts->low_latency_req,
+ DEV_PM_QOS_RESUME_LATENCY, 100);
}
/* SYN_REPORT */
diff --git a/drivers/input/touchscreen/tnetv107x-ts.c b/drivers/input/touchscreen/tnetv107x-ts.c
deleted file mode 100644
index c47827a26e3c..000000000000
--- a/drivers/input/touchscreen/tnetv107x-ts.c
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Texas Instruments TNETV107X Touchscreen Driver
- *
- * Copyright (C) 2010 Texas Instruments
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/input.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/ctype.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-
-#include <mach/tnetv107x.h>
-
-#define TSC_PENUP_POLL (HZ / 5)
-#define IDLE_TIMEOUT 100 /* msec */
-
-/*
- * The first and last samples of a touch interval are usually garbage and need
- * to be filtered out with these devices. The following definitions control
- * the number of samples skipped.
- */
-#define TSC_HEAD_SKIP 1
-#define TSC_TAIL_SKIP 1
-#define TSC_SKIP (TSC_HEAD_SKIP + TSC_TAIL_SKIP + 1)
-#define TSC_SAMPLES (TSC_SKIP + 1)
-
-/* Register Offsets */
-struct tsc_regs {
- u32 rev;
- u32 tscm;
- u32 bwcm;
- u32 swc;
- u32 adcchnl;
- u32 adcdata;
- u32 chval[4];
-};
-
-/* TSC Mode Configuration Register (tscm) bits */
-#define WMODE BIT(0)
-#define TSKIND BIT(1)
-#define ZMEASURE_EN BIT(2)
-#define IDLE BIT(3)
-#define TSC_EN BIT(4)
-#define STOP BIT(5)
-#define ONE_SHOT BIT(6)
-#define SINGLE BIT(7)
-#define AVG BIT(8)
-#define AVGNUM(x) (((x) & 0x03) << 9)
-#define PVSTC(x) (((x) & 0x07) << 11)
-#define PON BIT(14)
-#define PONBG BIT(15)
-#define AFERST BIT(16)
-
-/* ADC DATA Capture Register bits */
-#define DATA_VALID BIT(16)
-
-/* Register Access Macros */
-#define tsc_read(ts, reg) __raw_readl(&(ts)->regs->reg)
-#define tsc_write(ts, reg, val) __raw_writel(val, &(ts)->regs->reg);
-#define tsc_set_bits(ts, reg, val) \
- tsc_write(ts, reg, tsc_read(ts, reg) | (val))
-#define tsc_clr_bits(ts, reg, val) \
- tsc_write(ts, reg, tsc_read(ts, reg) & ~(val))
-
-struct sample {
- int x, y, p;
-};
-
-struct tsc_data {
- struct input_dev *input_dev;
- struct resource *res;
- struct tsc_regs __iomem *regs;
- struct timer_list timer;
- spinlock_t lock;
- struct clk *clk;
- struct device *dev;
- int sample_count;
- struct sample samples[TSC_SAMPLES];
- int tsc_irq;
-};
-
-static int tsc_read_sample(struct tsc_data *ts, struct sample* sample)
-{
- int x, y, z1, z2, t, p = 0;
- u32 val;
-
- val = tsc_read(ts, chval[0]);
- if (val & DATA_VALID)
- x = val & 0xffff;
- else
- return -EINVAL;
-
- y = tsc_read(ts, chval[1]) & 0xffff;
- z1 = tsc_read(ts, chval[2]) & 0xffff;
- z2 = tsc_read(ts, chval[3]) & 0xffff;
-
- if (z1) {
- t = ((600 * x) * (z2 - z1));
- p = t / (u32) (z1 << 12);
- if (p < 0)
- p = 0;
- }
-
- sample->x = x;
- sample->y = y;
- sample->p = p;
-
- return 0;
-}
-
-static void tsc_poll(unsigned long data)
-{
- struct tsc_data *ts = (struct tsc_data *)data;
- unsigned long flags;
- int i, val, x, y, p;
-
- spin_lock_irqsave(&ts->lock, flags);
-
- if (ts->sample_count >= TSC_SKIP) {
- input_report_abs(ts->input_dev, ABS_PRESSURE, 0);
- input_report_key(ts->input_dev, BTN_TOUCH, 0);
- input_sync(ts->input_dev);
- } else if (ts->sample_count > 0) {
- /*
- * A touch event lasted less than our skip count. Salvage and
- * report anyway.
- */
- for (i = 0, val = 0; i < ts->sample_count; i++)
- val += ts->samples[i].x;
- x = val / ts->sample_count;
-
- for (i = 0, val = 0; i < ts->sample_count; i++)
- val += ts->samples[i].y;
- y = val / ts->sample_count;
-
- for (i = 0, val = 0; i < ts->sample_count; i++)
- val += ts->samples[i].p;
- p = val / ts->sample_count;
-
- input_report_abs(ts->input_dev, ABS_X, x);
- input_report_abs(ts->input_dev, ABS_Y, y);
- input_report_abs(ts->input_dev, ABS_PRESSURE, p);
- input_report_key(ts->input_dev, BTN_TOUCH, 1);
- input_sync(ts->input_dev);
- }
-
- ts->sample_count = 0;
-
- spin_unlock_irqrestore(&ts->lock, flags);
-}
-
-static irqreturn_t tsc_irq(int irq, void *dev_id)
-{
- struct tsc_data *ts = (struct tsc_data *)dev_id;
- struct sample *sample;
- int index;
-
- spin_lock(&ts->lock);
-
- index = ts->sample_count % TSC_SAMPLES;
- sample = &ts->samples[index];
- if (tsc_read_sample(ts, sample) < 0)
- goto out;
-
- if (++ts->sample_count >= TSC_SKIP) {
- index = (ts->sample_count - TSC_TAIL_SKIP - 1) % TSC_SAMPLES;
- sample = &ts->samples[index];
-
- input_report_abs(ts->input_dev, ABS_X, sample->x);
- input_report_abs(ts->input_dev, ABS_Y, sample->y);
- input_report_abs(ts->input_dev, ABS_PRESSURE, sample->p);
- if (ts->sample_count == TSC_SKIP)
- input_report_key(ts->input_dev, BTN_TOUCH, 1);
- input_sync(ts->input_dev);
- }
- mod_timer(&ts->timer, jiffies + TSC_PENUP_POLL);
-out:
- spin_unlock(&ts->lock);
- return IRQ_HANDLED;
-}
-
-static int tsc_start(struct input_dev *dev)
-{
- struct tsc_data *ts = input_get_drvdata(dev);
- unsigned long timeout = jiffies + msecs_to_jiffies(IDLE_TIMEOUT);
- u32 val;
-
- clk_enable(ts->clk);
-
- /* Go to idle mode, before any initialization */
- while (time_after(timeout, jiffies)) {
- if (tsc_read(ts, tscm) & IDLE)
- break;
- }
-
- if (time_before(timeout, jiffies)) {
- dev_warn(ts->dev, "timeout waiting for idle\n");
- clk_disable(ts->clk);
- return -EIO;
- }
-
- /* Configure TSC Control register*/
- val = (PONBG | PON | PVSTC(4) | ONE_SHOT | ZMEASURE_EN);
- tsc_write(ts, tscm, val);
-
- /* Bring TSC out of reset: Clear AFE reset bit */
- val &= ~(AFERST);
- tsc_write(ts, tscm, val);
-
- /* Configure all pins for hardware control*/
- tsc_write(ts, bwcm, 0);
-
- /* Finally enable the TSC */
- tsc_set_bits(ts, tscm, TSC_EN);
-
- return 0;
-}
-
-static void tsc_stop(struct input_dev *dev)
-{
- struct tsc_data *ts = input_get_drvdata(dev);
-
- tsc_clr_bits(ts, tscm, TSC_EN);
- synchronize_irq(ts->tsc_irq);
- del_timer_sync(&ts->timer);
- clk_disable(ts->clk);
-}
-
-static int tsc_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct tsc_data *ts;
- int error = 0;
- u32 rev = 0;
-
- ts = kzalloc(sizeof(struct tsc_data), GFP_KERNEL);
- if (!ts) {
- dev_err(dev, "cannot allocate device info\n");
- return -ENOMEM;
- }
-
- ts->dev = dev;
- spin_lock_init(&ts->lock);
- setup_timer(&ts->timer, tsc_poll, (unsigned long)ts);
- platform_set_drvdata(pdev, ts);
-
- ts->tsc_irq = platform_get_irq(pdev, 0);
- if (ts->tsc_irq < 0) {
- dev_err(dev, "cannot determine device interrupt\n");
- error = -ENODEV;
- goto error_res;
- }
-
- ts->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!ts->res) {
- dev_err(dev, "cannot determine register area\n");
- error = -ENODEV;
- goto error_res;
- }
-
- if (!request_mem_region(ts->res->start, resource_size(ts->res),
- pdev->name)) {
- dev_err(dev, "cannot claim register memory\n");
- ts->res = NULL;
- error = -EINVAL;
- goto error_res;
- }
-
- ts->regs = ioremap(ts->res->start, resource_size(ts->res));
- if (!ts->regs) {
- dev_err(dev, "cannot map register memory\n");
- error = -ENOMEM;
- goto error_map;
- }
-
- ts->clk = clk_get(dev, NULL);
- if (IS_ERR(ts->clk)) {
- dev_err(dev, "cannot claim device clock\n");
- error = PTR_ERR(ts->clk);
- goto error_clk;
- }
-
- error = request_threaded_irq(ts->tsc_irq, NULL, tsc_irq, IRQF_ONESHOT,
- dev_name(dev), ts);
- if (error < 0) {
- dev_err(ts->dev, "Could not allocate ts irq\n");
- goto error_irq;
- }
-
- ts->input_dev = input_allocate_device();
- if (!ts->input_dev) {
- dev_err(dev, "cannot allocate input device\n");
- error = -ENOMEM;
- goto error_input;
- }
- input_set_drvdata(ts->input_dev, ts);
-
- ts->input_dev->name = pdev->name;
- ts->input_dev->id.bustype = BUS_HOST;
- ts->input_dev->dev.parent = &pdev->dev;
- ts->input_dev->open = tsc_start;
- ts->input_dev->close = tsc_stop;
-
- clk_enable(ts->clk);
- rev = tsc_read(ts, rev);
- ts->input_dev->id.product = ((rev >> 8) & 0x07);
- ts->input_dev->id.version = ((rev >> 16) & 0xfff);
- clk_disable(ts->clk);
-
- __set_bit(EV_KEY, ts->input_dev->evbit);
- __set_bit(EV_ABS, ts->input_dev->evbit);
- __set_bit(BTN_TOUCH, ts->input_dev->keybit);
-
- input_set_abs_params(ts->input_dev, ABS_X, 0, 0xffff, 5, 0);
- input_set_abs_params(ts->input_dev, ABS_Y, 0, 0xffff, 5, 0);
- input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 4095, 128, 0);
-
- error = input_register_device(ts->input_dev);
- if (error < 0) {
- dev_err(dev, "failed input device registration\n");
- goto error_reg;
- }
-
- return 0;
-
-error_reg:
- input_free_device(ts->input_dev);
-error_input:
- free_irq(ts->tsc_irq, ts);
-error_irq:
- clk_put(ts->clk);
-error_clk:
- iounmap(ts->regs);
-error_map:
- release_mem_region(ts->res->start, resource_size(ts->res));
-error_res:
- kfree(ts);
-
- return error;
-}
-
-static int tsc_remove(struct platform_device *pdev)
-{
- struct tsc_data *ts = platform_get_drvdata(pdev);
-
- input_unregister_device(ts->input_dev);
- free_irq(ts->tsc_irq, ts);
- clk_put(ts->clk);
- iounmap(ts->regs);
- release_mem_region(ts->res->start, resource_size(ts->res));
- kfree(ts);
-
- return 0;
-}
-
-static struct platform_driver tsc_driver = {
- .probe = tsc_probe,
- .remove = tsc_remove,
- .driver.name = "tnetv107x-ts",
- .driver.owner = THIS_MODULE,
-};
-module_platform_driver(tsc_driver);
-
-MODULE_AUTHOR("Cyril Chemparathy");
-MODULE_DESCRIPTION("TNETV107X Touchscreen Driver");
-MODULE_ALIAS("platform:tnetv107x-ts");
-MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c
index 2175f3419002..01d30cedde46 100644
--- a/drivers/input/touchscreen/zforce_ts.c
+++ b/drivers/input/touchscreen/zforce_ts.c
@@ -29,10 +29,13 @@
#include <linux/sysfs.h>
#include <linux/input/mt.h>
#include <linux/platform_data/zforce_ts.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
#define WAIT_TIMEOUT msecs_to_jiffies(1000)
#define FRAME_START 0xee
+#define FRAME_MAXSIZE 257
/* Offsets of the different parts of the payload the controller sends */
#define PAYLOAD_HEADER 0
@@ -64,7 +67,7 @@
#define RESPONSE_STATUS 0X1e
/*
- * Notifications are send by the touch controller without
+ * Notifications are sent by the touch controller without
* being requested by the driver and include for example
* touch indications
*/
@@ -103,8 +106,8 @@ struct zforce_point {
* @suspended device suspended
* @access_mutex serialize i2c-access, to keep multipart reads together
* @command_done completion to wait for the command result
- * @command_mutex serialize commands send to the ic
- * @command_waiting the id of the command that that is currently waiting
+ * @command_mutex serialize commands sent to the ic
+ * @command_waiting the id of the command that is currently waiting
* for a result
* @command_result returned result of the command
*/
@@ -235,7 +238,8 @@ static int zforce_scan_frequency(struct zforce_ts *ts, u16 idle, u16 finger,
(finger & 0xff), ((finger >> 8) & 0xff),
(stylus & 0xff), ((stylus >> 8) & 0xff) };
- dev_dbg(&client->dev, "set scan frequency to (idle: %d, finger: %d, stylus: %d)\n",
+ dev_dbg(&client->dev,
+ "set scan frequency to (idle: %d, finger: %d, stylus: %d)\n",
idle, finger, stylus);
return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf));
@@ -255,7 +259,7 @@ static int zforce_setconfig(struct zforce_ts *ts, char b1)
static int zforce_start(struct zforce_ts *ts)
{
struct i2c_client *client = ts->client;
- const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev);
+ const struct zforce_ts_platdata *pdata = ts->pdata;
int ret;
dev_dbg(&client->dev, "starting device\n");
@@ -326,13 +330,14 @@ static int zforce_stop(struct zforce_ts *ts)
static int zforce_touch_event(struct zforce_ts *ts, u8 *payload)
{
struct i2c_client *client = ts->client;
- const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev);
+ const struct zforce_ts_platdata *pdata = ts->pdata;
struct zforce_point point;
int count, i, num = 0;
count = payload[0];
if (count > ZFORCE_REPORT_POINTS) {
- dev_warn(&client->dev, "to many coordinates %d, expected max %d\n",
+ dev_warn(&client->dev,
+ "too many coordinates %d, expected max %d\n",
count, ZFORCE_REPORT_POINTS);
count = ZFORCE_REPORT_POINTS;
}
@@ -421,7 +426,7 @@ static int zforce_read_packet(struct zforce_ts *ts, u8 *buf)
goto unlock;
}
- if (buf[PAYLOAD_LENGTH] <= 0 || buf[PAYLOAD_LENGTH] > 255) {
+ if (buf[PAYLOAD_LENGTH] == 0) {
dev_err(&client->dev, "invalid payload length: %d\n",
buf[PAYLOAD_LENGTH]);
ret = -EIO;
@@ -471,9 +476,9 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
{
struct zforce_ts *ts = dev_id;
struct i2c_client *client = ts->client;
- const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev);
+ const struct zforce_ts_platdata *pdata = ts->pdata;
int ret;
- u8 payload_buffer[512];
+ u8 payload_buffer[FRAME_MAXSIZE];
u8 *payload;
/*
@@ -494,8 +499,8 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
while (!gpio_get_value(pdata->gpio_int)) {
ret = zforce_read_packet(ts, payload_buffer);
if (ret < 0) {
- dev_err(&client->dev, "could not read packet, ret: %d\n",
- ret);
+ dev_err(&client->dev,
+ "could not read packet, ret: %d\n", ret);
break;
}
@@ -539,7 +544,8 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
payload[RESPONSE_DATA + 4];
ts->version_rev = (payload[RESPONSE_DATA + 7] << 8) |
payload[RESPONSE_DATA + 6];
- dev_dbg(&ts->client->dev, "Firmware Version %04x:%04x %04x:%04x\n",
+ dev_dbg(&ts->client->dev,
+ "Firmware Version %04x:%04x %04x:%04x\n",
ts->version_major, ts->version_minor,
ts->version_build, ts->version_rev);
@@ -552,7 +558,8 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
break;
default:
- dev_err(&ts->client->dev, "unrecognized response id: 0x%x\n",
+ dev_err(&ts->client->dev,
+ "unrecognized response id: 0x%x\n",
payload[RESPONSE_ID]);
break;
}
@@ -618,7 +625,8 @@ static int zforce_suspend(struct device *dev)
enable_irq_wake(client->irq);
} else if (input->users) {
- dev_dbg(&client->dev, "suspend without being a wakeup source\n");
+ dev_dbg(&client->dev,
+ "suspend without being a wakeup source\n");
ret = zforce_stop(ts);
if (ret)
@@ -684,6 +692,45 @@ static void zforce_reset(void *data)
gpio_set_value(ts->pdata->gpio_rst, 0);
}
+static struct zforce_ts_platdata *zforce_parse_dt(struct device *dev)
+{
+ struct zforce_ts_platdata *pdata;
+ struct device_node *np = dev->of_node;
+
+ if (!np)
+ return ERR_PTR(-ENOENT);
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(dev, "failed to allocate platform data\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ pdata->gpio_int = of_get_gpio(np, 0);
+ if (!gpio_is_valid(pdata->gpio_int)) {
+ dev_err(dev, "failed to get interrupt gpio\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ pdata->gpio_rst = of_get_gpio(np, 1);
+ if (!gpio_is_valid(pdata->gpio_rst)) {
+ dev_err(dev, "failed to get reset gpio\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (of_property_read_u32(np, "x-size", &pdata->x_max)) {
+ dev_err(dev, "failed to get x-size property\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (of_property_read_u32(np, "y-size", &pdata->y_max)) {
+ dev_err(dev, "failed to get y-size property\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ return pdata;
+}
+
static int zforce_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -692,8 +739,11 @@ static int zforce_probe(struct i2c_client *client,
struct input_dev *input_dev;
int ret;
- if (!pdata)
- return -EINVAL;
+ if (!pdata) {
+ pdata = zforce_parse_dt(&client->dev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ }
ts = devm_kzalloc(&client->dev, sizeof(struct zforce_ts), GFP_KERNEL);
if (!ts)
@@ -798,7 +848,7 @@ static int zforce_probe(struct i2c_client *client,
return ret;
}
- /* this gets the firmware version among other informations */
+ /* this gets the firmware version among other information */
ret = zforce_command_wait(ts, COMMAND_STATUS);
if (ret < 0) {
dev_err(&client->dev, "couldn't get status, %d\n", ret);
@@ -829,11 +879,20 @@ static struct i2c_device_id zforce_idtable[] = {
};
MODULE_DEVICE_TABLE(i2c, zforce_idtable);
+#ifdef CONFIG_OF
+static struct of_device_id zforce_dt_idtable[] = {
+ { .compatible = "neonode,zforce" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, zforce_dt_idtable);
+#endif
+
static struct i2c_driver zforce_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "zforce-ts",
.pm = &zforce_pm_ops,
+ .of_match_table = of_match_ptr(zforce_dt_idtable),
},
.probe = zforce_probe,
.id_table = zforce_idtable,
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
index e400fbe411de..cff039df056e 100644
--- a/drivers/iommu/amd_iommu_types.h
+++ b/drivers/iommu/amd_iommu_types.h
@@ -25,6 +25,7 @@
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/pci.h>
+#include <linux/irqreturn.h>
/*
* Maximum number of IOMMUs supported
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 8911850c9444..1d9ab39af29f 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -79,7 +79,6 @@
#define ARM_SMMU_PTE_CONT_SIZE (PAGE_SIZE * ARM_SMMU_PTE_CONT_ENTRIES)
#define ARM_SMMU_PTE_CONT_MASK (~(ARM_SMMU_PTE_CONT_SIZE - 1))
-#define ARM_SMMU_PTE_HWTABLE_SIZE (PTRS_PER_PTE * sizeof(pte_t))
/* Stage-1 PTE */
#define ARM_SMMU_PTE_AP_UNPRIV (((pteval_t)1) << 6)
@@ -191,6 +190,9 @@
#define ARM_SMMU_GR1_CBAR(n) (0x0 + ((n) << 2))
#define CBAR_VMID_SHIFT 0
#define CBAR_VMID_MASK 0xff
+#define CBAR_S1_BPSHCFG_SHIFT 8
+#define CBAR_S1_BPSHCFG_MASK 3
+#define CBAR_S1_BPSHCFG_NSH 3
#define CBAR_S1_MEMATTR_SHIFT 12
#define CBAR_S1_MEMATTR_MASK 0xf
#define CBAR_S1_MEMATTR_WB 0xf
@@ -393,7 +395,7 @@ struct arm_smmu_domain {
struct arm_smmu_cfg root_cfg;
phys_addr_t output_mask;
- struct mutex lock;
+ spinlock_t lock;
};
static DEFINE_SPINLOCK(arm_smmu_devices_lock);
@@ -632,6 +634,28 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
return IRQ_HANDLED;
}
+static void arm_smmu_flush_pgtable(struct arm_smmu_device *smmu, void *addr,
+ size_t size)
+{
+ unsigned long offset = (unsigned long)addr & ~PAGE_MASK;
+
+
+ /* Ensure new page tables are visible to the hardware walker */
+ if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) {
+ dsb();
+ } else {
+ /*
+ * If the SMMU can't walk tables in the CPU caches, treat them
+ * like non-coherent DMA since we need to flush the new entries
+ * all the way out to memory. There's no possibility of
+ * recursion here as the SMMU table walker will not be wired
+ * through another SMMU.
+ */
+ dma_map_page(smmu->dev, virt_to_page(addr), offset, size,
+ DMA_TO_DEVICE);
+ }
+}
+
static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
{
u32 reg;
@@ -650,11 +674,16 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
if (smmu->version == 1)
reg |= root_cfg->irptndx << CBAR_IRPTNDX_SHIFT;
- /* Use the weakest memory type, so it is overridden by the pte */
- if (stage1)
- reg |= (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT);
- else
+ /*
+ * Use the weakest shareability/memory types, so they are
+ * overridden by the ttbcr/pte.
+ */
+ if (stage1) {
+ reg |= (CBAR_S1_BPSHCFG_NSH << CBAR_S1_BPSHCFG_SHIFT) |
+ (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT);
+ } else {
reg |= ARM_SMMU_CB_VMID(root_cfg) << CBAR_VMID_SHIFT;
+ }
writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(root_cfg->cbndx));
if (smmu->version > 1) {
@@ -715,6 +744,8 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
}
/* TTBR0 */
+ arm_smmu_flush_pgtable(smmu, root_cfg->pgd,
+ PTRS_PER_PGD * sizeof(pgd_t));
reg = __pa(root_cfg->pgd);
writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO);
reg = (phys_addr_t)__pa(root_cfg->pgd) >> 32;
@@ -901,7 +932,7 @@ static int arm_smmu_domain_init(struct iommu_domain *domain)
goto out_free_domain;
smmu_domain->root_cfg.pgd = pgd;
- mutex_init(&smmu_domain->lock);
+ spin_lock_init(&smmu_domain->lock);
domain->priv = smmu_domain;
return 0;
@@ -1128,6 +1159,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
struct arm_smmu_domain *smmu_domain = domain->priv;
struct arm_smmu_device *device_smmu = dev->archdata.iommu;
struct arm_smmu_master *master;
+ unsigned long flags;
if (!device_smmu) {
dev_err(dev, "cannot attach to SMMU, is it on the same bus?\n");
@@ -1138,7 +1170,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
* Sanity check the domain. We don't currently support domains
* that cross between different SMMU chains.
*/
- mutex_lock(&smmu_domain->lock);
+ spin_lock_irqsave(&smmu_domain->lock, flags);
if (!smmu_domain->leaf_smmu) {
/* Now that we have a master, we can finalise the domain */
ret = arm_smmu_init_domain_context(domain, dev);
@@ -1153,7 +1185,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
dev_name(device_smmu->dev));
goto err_unlock;
}
- mutex_unlock(&smmu_domain->lock);
+ spin_unlock_irqrestore(&smmu_domain->lock, flags);
/* Looks ok, so add the device to the domain */
master = find_smmu_master(smmu_domain->leaf_smmu, dev->of_node);
@@ -1163,7 +1195,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
return arm_smmu_domain_add_master(smmu_domain, master);
err_unlock:
- mutex_unlock(&smmu_domain->lock);
+ spin_unlock_irqrestore(&smmu_domain->lock, flags);
return ret;
}
@@ -1177,23 +1209,6 @@ static void arm_smmu_detach_dev(struct iommu_domain *domain, struct device *dev)
arm_smmu_domain_remove_master(smmu_domain, master);
}
-static void arm_smmu_flush_pgtable(struct arm_smmu_device *smmu, void *addr,
- size_t size)
-{
- unsigned long offset = (unsigned long)addr & ~PAGE_MASK;
-
- /*
- * If the SMMU can't walk tables in the CPU caches, treat them
- * like non-coherent DMA since we need to flush the new entries
- * all the way out to memory. There's no possibility of recursion
- * here as the SMMU table walker will not be wired through another
- * SMMU.
- */
- if (!(smmu->features & ARM_SMMU_FEAT_COHERENT_WALK))
- dma_map_page(smmu->dev, virt_to_page(addr), offset, size,
- DMA_TO_DEVICE);
-}
-
static bool arm_smmu_pte_is_contiguous_range(unsigned long addr,
unsigned long end)
{
@@ -1210,12 +1225,11 @@ static int arm_smmu_alloc_init_pte(struct arm_smmu_device *smmu, pmd_t *pmd,
if (pmd_none(*pmd)) {
/* Allocate a new set of tables */
- pgtable_t table = alloc_page(PGALLOC_GFP);
+ pgtable_t table = alloc_page(GFP_ATOMIC|__GFP_ZERO);
if (!table)
return -ENOMEM;
- arm_smmu_flush_pgtable(smmu, page_address(table),
- ARM_SMMU_PTE_HWTABLE_SIZE);
+ arm_smmu_flush_pgtable(smmu, page_address(table), PAGE_SIZE);
if (!pgtable_page_ctor(table)) {
__free_page(table);
return -ENOMEM;
@@ -1317,9 +1331,15 @@ static int arm_smmu_alloc_init_pmd(struct arm_smmu_device *smmu, pud_t *pud,
#ifndef __PAGETABLE_PMD_FOLDED
if (pud_none(*pud)) {
- pmd = pmd_alloc_one(NULL, addr);
+ pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC);
if (!pmd)
return -ENOMEM;
+
+ arm_smmu_flush_pgtable(smmu, pmd, PAGE_SIZE);
+ pud_populate(NULL, pud, pmd);
+ arm_smmu_flush_pgtable(smmu, pud, sizeof(*pud));
+
+ pmd += pmd_index(addr);
} else
#endif
pmd = pmd_offset(pud, addr);
@@ -1328,8 +1348,6 @@ static int arm_smmu_alloc_init_pmd(struct arm_smmu_device *smmu, pud_t *pud,
next = pmd_addr_end(addr, end);
ret = arm_smmu_alloc_init_pte(smmu, pmd, addr, end, pfn,
flags, stage);
- pud_populate(NULL, pud, pmd);
- arm_smmu_flush_pgtable(smmu, pud, sizeof(*pud));
phys += next - addr;
} while (pmd++, addr = next, addr < end);
@@ -1346,9 +1364,15 @@ static int arm_smmu_alloc_init_pud(struct arm_smmu_device *smmu, pgd_t *pgd,
#ifndef __PAGETABLE_PUD_FOLDED
if (pgd_none(*pgd)) {
- pud = pud_alloc_one(NULL, addr);
+ pud = (pud_t *)get_zeroed_page(GFP_ATOMIC);
if (!pud)
return -ENOMEM;
+
+ arm_smmu_flush_pgtable(smmu, pud, PAGE_SIZE);
+ pgd_populate(NULL, pgd, pud);
+ arm_smmu_flush_pgtable(smmu, pgd, sizeof(*pgd));
+
+ pud += pud_index(addr);
} else
#endif
pud = pud_offset(pgd, addr);
@@ -1357,8 +1381,6 @@ static int arm_smmu_alloc_init_pud(struct arm_smmu_device *smmu, pgd_t *pgd,
next = pud_addr_end(addr, end);
ret = arm_smmu_alloc_init_pmd(smmu, pud, addr, next, phys,
flags, stage);
- pgd_populate(NULL, pud, pgd);
- arm_smmu_flush_pgtable(smmu, pgd, sizeof(*pgd));
phys += next - addr;
} while (pud++, addr = next, addr < end);
@@ -1375,6 +1397,7 @@ static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain,
struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
pgd_t *pgd = root_cfg->pgd;
struct arm_smmu_device *smmu = root_cfg->smmu;
+ unsigned long irqflags;
if (root_cfg->cbar == CBAR_TYPE_S2_TRANS) {
stage = 2;
@@ -1397,7 +1420,7 @@ static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain,
if (paddr & ~output_mask)
return -ERANGE;
- mutex_lock(&smmu_domain->lock);
+ spin_lock_irqsave(&smmu_domain->lock, irqflags);
pgd += pgd_index(iova);
end = iova + size;
do {
@@ -1413,11 +1436,7 @@ static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain,
} while (pgd++, iova != end);
out_unlock:
- mutex_unlock(&smmu_domain->lock);
-
- /* Ensure new page tables are visible to the hardware walker */
- if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
- dsb();
+ spin_unlock_irqrestore(&smmu_domain->lock, irqflags);
return ret;
}
@@ -1987,8 +2006,10 @@ static int __init arm_smmu_init(void)
if (!iommu_present(&platform_bus_type))
bus_set_iommu(&platform_bus_type, &arm_smmu_ops);
+#ifdef CONFIG_ARM_AMBA
if (!iommu_present(&amba_bustype))
bus_set_iommu(&amba_bustype, &arm_smmu_ops);
+#endif
return 0;
}
diff --git a/drivers/iommu/omap-iommu-debug.c b/drivers/iommu/omap-iommu-debug.c
index d97fbe4fb9b1..80fffba7f12d 100644
--- a/drivers/iommu/omap-iommu-debug.c
+++ b/drivers/iommu/omap-iommu-debug.c
@@ -354,8 +354,8 @@ DEBUG_FOPS(mem);
return -ENOMEM; \
}
-#define DEBUG_ADD_FILE(name) __DEBUG_ADD_FILE(name, 600)
-#define DEBUG_ADD_FILE_RO(name) __DEBUG_ADD_FILE(name, 400)
+#define DEBUG_ADD_FILE(name) __DEBUG_ADD_FILE(name, 0600)
+#define DEBUG_ADD_FILE_RO(name) __DEBUG_ADD_FILE(name, 0400)
static int iommu_debug_register(struct device *dev, void *data)
{
diff --git a/drivers/iommu/shmobile-iommu.c b/drivers/iommu/shmobile-iommu.c
index 7a3b928fad1c..464acda0bbc4 100644
--- a/drivers/iommu/shmobile-iommu.c
+++ b/drivers/iommu/shmobile-iommu.c
@@ -343,7 +343,7 @@ static int shmobile_iommu_add_device(struct device *dev)
mapping = archdata->iommu_mapping;
if (!mapping) {
mapping = arm_iommu_create_mapping(&platform_bus_type, 0,
- L1_LEN << 20, 0);
+ L1_LEN << 20);
if (IS_ERR(mapping))
return PTR_ERR(mapping);
archdata->iommu_mapping = mapping;
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 5194afb39e78..1c0c151d108c 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
obj-$(CONFIG_ARCH_MOXART) += irq-moxart.o
obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o
obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o
+obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi-nmi.o
obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
obj-$(CONFIG_ARM_GIC) += irq-gic.o
obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c
index 540956465ed2..41be897df8d5 100644
--- a/drivers/irqchip/irq-armada-370-xp.c
+++ b/drivers/irqchip/irq-armada-370-xp.c
@@ -18,6 +18,7 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -42,6 +43,7 @@
#define ARMADA_370_XP_INT_SOURCE_CTL(irq) (0x100 + irq*4)
#define ARMADA_370_XP_CPU_INTACK_OFFS (0x44)
+#define ARMADA_375_PPI_CAUSE (0x10)
#define ARMADA_370_XP_SW_TRIG_INT_OFFS (0x4)
#define ARMADA_370_XP_IN_DRBEL_MSK_OFFS (0xc)
@@ -352,7 +354,63 @@ static struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
.xlate = irq_domain_xlate_onecell,
};
-static asmlinkage void __exception_irq_entry
+#ifdef CONFIG_PCI_MSI
+static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained)
+{
+ u32 msimask, msinr;
+
+ msimask = readl_relaxed(per_cpu_int_base +
+ ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
+ & PCI_MSI_DOORBELL_MASK;
+
+ writel(~msimask, per_cpu_int_base +
+ ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
+
+ for (msinr = PCI_MSI_DOORBELL_START;
+ msinr < PCI_MSI_DOORBELL_END; msinr++) {
+ int irq;
+
+ if (!(msimask & BIT(msinr)))
+ continue;
+
+ irq = irq_find_mapping(armada_370_xp_msi_domain,
+ msinr - 16);
+
+ if (is_chained)
+ generic_handle_irq(irq);
+ else
+ handle_IRQ(irq, regs);
+ }
+}
+#else
+static void armada_370_xp_handle_msi_irq(struct pt_regs *r, bool b) {}
+#endif
+
+static void armada_370_xp_mpic_handle_cascade_irq(unsigned int irq,
+ struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_get_chip(irq);
+ unsigned long irqmap, irqn;
+ unsigned int cascade_irq;
+
+ chained_irq_enter(chip, desc);
+
+ irqmap = readl_relaxed(per_cpu_int_base + ARMADA_375_PPI_CAUSE);
+
+ if (irqmap & BIT(0)) {
+ armada_370_xp_handle_msi_irq(NULL, true);
+ irqmap &= ~BIT(0);
+ }
+
+ for_each_set_bit(irqn, &irqmap, BITS_PER_LONG) {
+ cascade_irq = irq_find_mapping(armada_370_xp_mpic_domain, irqn);
+ generic_handle_irq(cascade_irq);
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static void __exception_irq_entry
armada_370_xp_handle_irq(struct pt_regs *regs)
{
u32 irqstat, irqnr;
@@ -372,31 +430,9 @@ armada_370_xp_handle_irq(struct pt_regs *regs)
continue;
}
-#ifdef CONFIG_PCI_MSI
/* MSI handling */
- if (irqnr == 1) {
- u32 msimask, msinr;
-
- msimask = readl_relaxed(per_cpu_int_base +
- ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
- & PCI_MSI_DOORBELL_MASK;
-
- writel(~msimask, per_cpu_int_base +
- ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
-
- for (msinr = PCI_MSI_DOORBELL_START;
- msinr < PCI_MSI_DOORBELL_END; msinr++) {
- int irq;
-
- if (!(msimask & BIT(msinr)))
- continue;
-
- irq = irq_find_mapping(armada_370_xp_msi_domain,
- msinr - 16);
- handle_IRQ(irq, regs);
- }
- }
-#endif
+ if (irqnr == 1)
+ armada_370_xp_handle_msi_irq(regs, false);
#ifdef CONFIG_SMP
/* IPI Handling */
@@ -427,6 +463,7 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
struct device_node *parent)
{
struct resource main_int_res, per_cpu_int_res;
+ int parent_irq;
u32 control;
BUG_ON(of_address_to_resource(node, 0, &main_int_res));
@@ -455,8 +492,6 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
BUG_ON(!armada_370_xp_mpic_domain);
- irq_set_default_host(armada_370_xp_mpic_domain);
-
#ifdef CONFIG_SMP
armada_xp_mpic_smp_cpu_init();
@@ -472,7 +507,14 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
armada_370_xp_msi_init(node, main_int_res.start);
- set_handle_irq(armada_370_xp_handle_irq);
+ parent_irq = irq_of_parse_and_map(node, 0);
+ if (parent_irq <= 0) {
+ irq_set_default_host(armada_370_xp_mpic_domain);
+ set_handle_irq(armada_370_xp_handle_irq);
+ } else {
+ irq_set_chained_handler(parent_irq,
+ armada_370_xp_mpic_handle_cascade_irq);
+ }
return 0;
}
diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c
index 1693b8e7f26a..5916d6cdafa1 100644
--- a/drivers/irqchip/irq-bcm2835.c
+++ b/drivers/irqchip/irq-bcm2835.c
@@ -95,7 +95,7 @@ struct armctrl_ic {
};
static struct armctrl_ic intc __read_mostly;
-static asmlinkage void __exception_irq_entry bcm2835_handle_irq(
+static void __exception_irq_entry bcm2835_handle_irq(
struct pt_regs *regs);
static void armctrl_mask_irq(struct irq_data *d)
@@ -196,7 +196,7 @@ static void armctrl_handle_shortcut(int bank, struct pt_regs *regs,
handle_IRQ(irq_linear_revmap(intc.domain, irq), regs);
}
-static asmlinkage void __exception_irq_entry bcm2835_handle_irq(
+static void __exception_irq_entry bcm2835_handle_irq(
struct pt_regs *regs)
{
u32 stat, irq;
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 341c6016812d..531769b2433a 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -50,7 +50,7 @@
union gic_base {
void __iomem *common_base;
- void __percpu __iomem **percpu_base;
+ void __percpu * __iomem *percpu_base;
};
struct gic_chip_data {
@@ -279,7 +279,7 @@ static int gic_set_wake(struct irq_data *d, unsigned int on)
#define gic_set_wake NULL
#endif
-static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
{
u32 irqstat, irqnr;
struct gic_chip_data *gic = &gic_data[0];
@@ -648,7 +648,7 @@ static void __init gic_pm_init(struct gic_chip_data *gic)
#endif
#ifdef CONFIG_SMP
-void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
+static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
{
int cpu;
unsigned long flags, map = 0;
@@ -869,7 +869,7 @@ static struct notifier_block gic_cpu_notifier = {
};
#endif
-const struct irq_domain_ops gic_irq_domain_ops = {
+static const struct irq_domain_ops gic_irq_domain_ops = {
.map = gic_irq_domain_map,
.xlate = gic_irq_domain_xlate,
};
@@ -974,7 +974,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
#ifdef CONFIG_OF
static int gic_cnt __initdata;
-int __init gic_of_init(struct device_node *node, struct device_node *parent)
+static int __init
+gic_of_init(struct device_node *node, struct device_node *parent)
{
void __iomem *cpu_base;
void __iomem *dist_base;
diff --git a/drivers/irqchip/irq-metag-ext.c b/drivers/irqchip/irq-metag-ext.c
index 92c41ab4dbfd..2cb474ad8809 100644
--- a/drivers/irqchip/irq-metag-ext.c
+++ b/drivers/irqchip/irq-metag-ext.c
@@ -515,7 +515,7 @@ static int meta_intc_set_affinity(struct irq_data *data,
* one cpu (the interrupt code doesn't support it), so we just
* pick the first cpu we find in 'cpumask'.
*/
- cpu = cpumask_any(cpumask);
+ cpu = cpumask_any_and(cpumask, cpu_online_mask);
thread = cpu_2_hwthread_id[cpu];
metag_out32(TBI_TRIG_VEC(TBID_SIGNUM_TR2(thread)), vec_addr);
diff --git a/drivers/irqchip/irq-metag.c b/drivers/irqchip/irq-metag.c
index 8e94d7a3b20d..c16c186d97d3 100644
--- a/drivers/irqchip/irq-metag.c
+++ b/drivers/irqchip/irq-metag.c
@@ -201,7 +201,7 @@ static int metag_internal_irq_set_affinity(struct irq_data *data,
* one cpu (the interrupt code doesn't support it), so we just
* pick the first cpu we find in 'cpumask'.
*/
- cpu = cpumask_any(cpumask);
+ cpu = cpumask_any_and(cpumask, cpu_online_mask);
thread = cpu_2_hwthread_id[cpu];
metag_out32(TBI_TRIG_VEC(TBID_SIGNUM_TR1(thread)),
diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c
index 2cb7cd0bc2f5..3c8827fe83f3 100644
--- a/drivers/irqchip/irq-mmp.c
+++ b/drivers/irqchip/irq-mmp.c
@@ -194,8 +194,7 @@ static struct mmp_intc_conf mmp2_conf = {
.conf_mask = 0x7f,
};
-static asmlinkage void __exception_irq_entry
-mmp_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs)
{
int irq, hwirq;
@@ -207,8 +206,7 @@ mmp_handle_irq(struct pt_regs *regs)
handle_IRQ(irq, regs);
}
-static asmlinkage void __exception_irq_entry
-mmp2_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry mmp2_handle_irq(struct pt_regs *regs)
{
int irq, hwirq;
diff --git a/drivers/irqchip/irq-moxart.c b/drivers/irqchip/irq-moxart.c
index 5552fc2bf28a..00b3cc908f76 100644
--- a/drivers/irqchip/irq-moxart.c
+++ b/drivers/irqchip/irq-moxart.c
@@ -44,7 +44,7 @@ struct moxart_irq_data {
static struct moxart_irq_data intc;
-static asmlinkage void __exception_irq_entry handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry handle_irq(struct pt_regs *regs)
{
u32 irqstat;
int hwirq;
diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c
index e51d40031884..e25f246cd2fb 100644
--- a/drivers/irqchip/irq-orion.c
+++ b/drivers/irqchip/irq-orion.c
@@ -30,7 +30,7 @@
static struct irq_domain *orion_irq_domain;
-static asmlinkage void
+static void
__exception_irq_entry orion_handle_irq(struct pt_regs *regs)
{
struct irq_domain_chip_generic *dgc = orion_irq_domain->gc;
@@ -111,7 +111,8 @@ IRQCHIP_DECLARE(orion_intc, "marvell,orion-intc", orion_irq_init);
static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc)
{
struct irq_domain *d = irq_get_handler_data(irq);
- struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, irq);
+
+ struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, 0);
u32 stat = readl_relaxed(gc->reg_base + ORION_BRIDGE_IRQ_CAUSE) &
gc->mask_cache;
@@ -123,6 +124,19 @@ static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc)
}
}
+/*
+ * Bridge IRQ_CAUSE is asserted regardless of IRQ_MASK register.
+ * To avoid interrupt events on stale irqs, we clear them before unmask.
+ */
+static unsigned int orion_bridge_irq_startup(struct irq_data *d)
+{
+ struct irq_chip_type *ct = irq_data_get_chip_type(d);
+
+ ct->chip.irq_ack(d);
+ ct->chip.irq_unmask(d);
+ return 0;
+}
+
static int __init orion_bridge_irq_init(struct device_node *np,
struct device_node *parent)
{
@@ -143,7 +157,7 @@ static int __init orion_bridge_irq_init(struct device_node *np,
}
ret = irq_alloc_domain_generic_chips(domain, nrirqs, 1, np->name,
- handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE);
+ handle_edge_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE);
if (ret) {
pr_err("%s: unable to alloc irq domain gc\n", np->name);
return ret;
@@ -176,12 +190,14 @@ static int __init orion_bridge_irq_init(struct device_node *np,
gc->chip_types[0].regs.ack = ORION_BRIDGE_IRQ_CAUSE;
gc->chip_types[0].regs.mask = ORION_BRIDGE_IRQ_MASK;
+ gc->chip_types[0].chip.irq_startup = orion_bridge_irq_startup;
gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit;
gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
- /* mask all interrupts */
+ /* mask and clear all interrupts */
writel(0, gc->reg_base + ORION_BRIDGE_IRQ_MASK);
+ writel(0, gc->reg_base + ORION_BRIDGE_IRQ_CAUSE);
irq_set_handler_data(irq, domain);
irq_set_chained_handler(irq, orion_bridge_irq_handler);
diff --git a/drivers/irqchip/irq-sirfsoc.c b/drivers/irqchip/irq-sirfsoc.c
index 3a070c587ed9..581eefe331ae 100644
--- a/drivers/irqchip/irq-sirfsoc.c
+++ b/drivers/irqchip/irq-sirfsoc.c
@@ -47,7 +47,7 @@ sirfsoc_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
ct->regs.mask = SIRFSOC_INT_RISC_MASK0;
}
-static asmlinkage void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs)
{
void __iomem *base = sirfsoc_irqdomain->host_data;
u32 irqstat, irqnr;
diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c
index a5438d889245..6fcef4a95a18 100644
--- a/drivers/irqchip/irq-sun4i.c
+++ b/drivers/irqchip/irq-sun4i.c
@@ -36,18 +36,16 @@
static void __iomem *sun4i_irq_base;
static struct irq_domain *sun4i_irq_domain;
-static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs);
+static void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs);
static void sun4i_irq_ack(struct irq_data *irqd)
{
unsigned int irq = irqd_to_hwirq(irqd);
- unsigned int irq_off = irq % 32;
- int reg = irq / 32;
- u32 val;
- val = readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg));
- writel(val | (1 << irq_off),
- sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg));
+ if (irq != 0)
+ return; /* Only IRQ 0 / the ENMI needs to be acked */
+
+ writel(BIT(0), sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0));
}
static void sun4i_irq_mask(struct irq_data *irqd)
@@ -76,16 +74,16 @@ static void sun4i_irq_unmask(struct irq_data *irqd)
static struct irq_chip sun4i_irq_chip = {
.name = "sun4i_irq",
- .irq_ack = sun4i_irq_ack,
+ .irq_eoi = sun4i_irq_ack,
.irq_mask = sun4i_irq_mask,
.irq_unmask = sun4i_irq_unmask,
+ .flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED,
};
static int sun4i_irq_map(struct irq_domain *d, unsigned int virq,
irq_hw_number_t hw)
{
- irq_set_chip_and_handler(virq, &sun4i_irq_chip,
- handle_level_irq);
+ irq_set_chip_and_handler(virq, &sun4i_irq_chip, handle_fasteoi_irq);
set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
return 0;
@@ -109,7 +107,7 @@ static int __init sun4i_of_init(struct device_node *node,
writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(1));
writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(2));
- /* Mask all the interrupts */
+ /* Unmask all the interrupts, ENABLE_REG(x) is used for masking */
writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(0));
writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(1));
writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(2));
@@ -134,16 +132,30 @@ static int __init sun4i_of_init(struct device_node *node,
return 0;
}
-IRQCHIP_DECLARE(allwinner_sun4i_ic, "allwinner,sun4i-ic", sun4i_of_init);
+IRQCHIP_DECLARE(allwinner_sun4i_ic, "allwinner,sun4i-a10-ic", sun4i_of_init);
-static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs)
{
u32 irq, hwirq;
+ /*
+ * hwirq == 0 can mean one of 3 things:
+ * 1) no more irqs pending
+ * 2) irq 0 pending
+ * 3) spurious irq
+ * So if we immediately get a reading of 0, check the irq-pending reg
+ * to differentiate between 2 and 3. We only do this once to avoid
+ * the extra check in the common case of 1 hapening after having
+ * read the vector-reg once.
+ */
hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2;
- while (hwirq != 0) {
+ if (hwirq == 0 &&
+ !(readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0)) & BIT(0)))
+ return;
+
+ do {
irq = irq_find_mapping(sun4i_irq_domain, hwirq);
handle_IRQ(irq, regs);
hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2;
- }
+ } while (hwirq != 0);
}
diff --git a/drivers/irqchip/irq-sunxi-nmi.c b/drivers/irqchip/irq-sunxi-nmi.c
new file mode 100644
index 000000000000..12f547a44ae4
--- /dev/null
+++ b/drivers/irqchip/irq-sunxi-nmi.c
@@ -0,0 +1,208 @@
+/*
+ * Allwinner A20/A31 SoCs NMI IRQ chip driver.
+ *
+ * Carlo Caione <carlo.caione@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/irqchip/chained_irq.h>
+#include "irqchip.h"
+
+#define SUNXI_NMI_SRC_TYPE_MASK 0x00000003
+
+enum {
+ SUNXI_SRC_TYPE_LEVEL_LOW = 0,
+ SUNXI_SRC_TYPE_EDGE_FALLING,
+ SUNXI_SRC_TYPE_LEVEL_HIGH,
+ SUNXI_SRC_TYPE_EDGE_RISING,
+};
+
+struct sunxi_sc_nmi_reg_offs {
+ u32 ctrl;
+ u32 pend;
+ u32 enable;
+};
+
+static struct sunxi_sc_nmi_reg_offs sun7i_reg_offs = {
+ .ctrl = 0x00,
+ .pend = 0x04,
+ .enable = 0x08,
+};
+
+static struct sunxi_sc_nmi_reg_offs sun6i_reg_offs = {
+ .ctrl = 0x00,
+ .pend = 0x04,
+ .enable = 0x34,
+};
+
+static inline void sunxi_sc_nmi_write(struct irq_chip_generic *gc, u32 off,
+ u32 val)
+{
+ irq_reg_writel(val, gc->reg_base + off);
+}
+
+static inline u32 sunxi_sc_nmi_read(struct irq_chip_generic *gc, u32 off)
+{
+ return irq_reg_readl(gc->reg_base + off);
+}
+
+static void sunxi_sc_nmi_handle_irq(unsigned int irq, struct irq_desc *desc)
+{
+ struct irq_domain *domain = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_get_chip(irq);
+ unsigned int virq = irq_find_mapping(domain, 0);
+
+ chained_irq_enter(chip, desc);
+ generic_handle_irq(virq);
+ chained_irq_exit(chip, desc);
+}
+
+static int sunxi_sc_nmi_set_type(struct irq_data *data, unsigned int flow_type)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
+ struct irq_chip_type *ct = gc->chip_types;
+ u32 src_type_reg;
+ u32 ctrl_off = ct->regs.type;
+ unsigned int src_type;
+ unsigned int i;
+
+ irq_gc_lock(gc);
+
+ switch (flow_type & IRQF_TRIGGER_MASK) {
+ case IRQ_TYPE_EDGE_FALLING:
+ src_type = SUNXI_SRC_TYPE_EDGE_FALLING;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ src_type = SUNXI_SRC_TYPE_EDGE_RISING;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ src_type = SUNXI_SRC_TYPE_LEVEL_HIGH;
+ break;
+ case IRQ_TYPE_NONE:
+ case IRQ_TYPE_LEVEL_LOW:
+ src_type = SUNXI_SRC_TYPE_LEVEL_LOW;
+ break;
+ default:
+ irq_gc_unlock(gc);
+ pr_err("%s: Cannot assign multiple trigger modes to IRQ %d.\n",
+ __func__, data->irq);
+ return -EBADR;
+ }
+
+ irqd_set_trigger_type(data, flow_type);
+ irq_setup_alt_chip(data, flow_type);
+
+ for (i = 0; i <= gc->num_ct; i++, ct++)
+ if (ct->type & flow_type)
+ ctrl_off = ct->regs.type;
+
+ src_type_reg = sunxi_sc_nmi_read(gc, ctrl_off);
+ src_type_reg &= ~SUNXI_NMI_SRC_TYPE_MASK;
+ src_type_reg |= src_type;
+ sunxi_sc_nmi_write(gc, ctrl_off, src_type_reg);
+
+ irq_gc_unlock(gc);
+
+ return IRQ_SET_MASK_OK;
+}
+
+static int __init sunxi_sc_nmi_irq_init(struct device_node *node,
+ struct sunxi_sc_nmi_reg_offs *reg_offs)
+{
+ struct irq_domain *domain;
+ struct irq_chip_generic *gc;
+ unsigned int irq;
+ unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+ int ret;
+
+
+ domain = irq_domain_add_linear(node, 1, &irq_generic_chip_ops, NULL);
+ if (!domain) {
+ pr_err("%s: Could not register interrupt domain.\n", node->name);
+ return -ENOMEM;
+ }
+
+ ret = irq_alloc_domain_generic_chips(domain, 1, 2, node->name,
+ handle_fasteoi_irq, clr, 0,
+ IRQ_GC_INIT_MASK_CACHE);
+ if (ret) {
+ pr_err("%s: Could not allocate generic interrupt chip.\n",
+ node->name);
+ goto fail_irqd_remove;
+ }
+
+ irq = irq_of_parse_and_map(node, 0);
+ if (irq <= 0) {
+ pr_err("%s: unable to parse irq\n", node->name);
+ ret = -EINVAL;
+ goto fail_irqd_remove;
+ }
+
+ gc = irq_get_domain_generic_chip(domain, 0);
+ gc->reg_base = of_iomap(node, 0);
+ if (!gc->reg_base) {
+ pr_err("%s: unable to map resource\n", node->name);
+ ret = -ENOMEM;
+ goto fail_irqd_remove;
+ }
+
+ gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+ gc->chip_types[0].chip.irq_eoi = irq_gc_ack_set_bit;
+ gc->chip_types[0].chip.irq_set_type = sunxi_sc_nmi_set_type;
+ gc->chip_types[0].chip.flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED;
+ gc->chip_types[0].regs.ack = reg_offs->pend;
+ gc->chip_types[0].regs.mask = reg_offs->enable;
+ gc->chip_types[0].regs.type = reg_offs->ctrl;
+
+ gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
+ gc->chip_types[1].chip.name = gc->chip_types[0].chip.name;
+ gc->chip_types[1].chip.irq_ack = irq_gc_ack_set_bit;
+ gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit;
+ gc->chip_types[1].chip.irq_set_type = sunxi_sc_nmi_set_type;
+ gc->chip_types[1].regs.ack = reg_offs->pend;
+ gc->chip_types[1].regs.mask = reg_offs->enable;
+ gc->chip_types[1].regs.type = reg_offs->ctrl;
+ gc->chip_types[1].handler = handle_edge_irq;
+
+ sunxi_sc_nmi_write(gc, reg_offs->enable, 0);
+ sunxi_sc_nmi_write(gc, reg_offs->pend, 0x1);
+
+ irq_set_handler_data(irq, domain);
+ irq_set_chained_handler(irq, sunxi_sc_nmi_handle_irq);
+
+ return 0;
+
+fail_irqd_remove:
+ irq_domain_remove(domain);
+
+ return ret;
+}
+
+static int __init sun6i_sc_nmi_irq_init(struct device_node *node,
+ struct device_node *parent)
+{
+ return sunxi_sc_nmi_irq_init(node, &sun6i_reg_offs);
+}
+IRQCHIP_DECLARE(sun6i_sc_nmi, "allwinner,sun6i-a31-sc-nmi", sun6i_sc_nmi_irq_init);
+
+static int __init sun7i_sc_nmi_irq_init(struct device_node *node,
+ struct device_node *parent)
+{
+ return sunxi_sc_nmi_irq_init(node, &sun7i_reg_offs);
+}
+IRQCHIP_DECLARE(sun7i_sc_nmi, "allwinner,sun7i-a20-sc-nmi", sun7i_sc_nmi_irq_init);
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 8e21ae0bab46..473f09a74d4d 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -228,7 +228,7 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs)
* Keep iterating over all registered VIC's until there are no pending
* interrupts.
*/
-static asmlinkage void __exception_irq_entry vic_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry vic_handle_irq(struct pt_regs *regs)
{
int i, handled;
diff --git a/drivers/irqchip/irq-vt8500.c b/drivers/irqchip/irq-vt8500.c
index 1846e7d66681..eb6e91efdec8 100644
--- a/drivers/irqchip/irq-vt8500.c
+++ b/drivers/irqchip/irq-vt8500.c
@@ -178,8 +178,7 @@ static struct irq_domain_ops vt8500_irq_domain_ops = {
.xlate = irq_domain_xlate_onecell,
};
-static asmlinkage
-void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
{
u32 stat, i;
int irqnr, virq;
diff --git a/drivers/irqchip/irq-xtensa-mx.c b/drivers/irqchip/irq-xtensa-mx.c
index f693f1bc1348..e1c2f9632893 100644
--- a/drivers/irqchip/irq-xtensa-mx.c
+++ b/drivers/irqchip/irq-xtensa-mx.c
@@ -122,7 +122,7 @@ static int xtensa_mx_irq_retrigger(struct irq_data *d)
static int xtensa_mx_irq_set_affinity(struct irq_data *d,
const struct cpumask *dest, bool force)
{
- unsigned mask = 1u << cpumask_any(dest);
+ unsigned mask = 1u << cpumask_any_and(dest, cpu_online_mask);
set_er(mask, MIROUT(d->hwirq - HW_IRQ_MX_BASE));
return 0;
diff --git a/drivers/irqchip/irq-zevio.c b/drivers/irqchip/irq-zevio.c
index 8ed04c4a43ee..ceb3a4318f73 100644
--- a/drivers/irqchip/irq-zevio.c
+++ b/drivers/irqchip/irq-zevio.c
@@ -50,7 +50,7 @@ static void zevio_irq_ack(struct irq_data *irqd)
readl(gc->reg_base + regs->ack);
}
-static asmlinkage void __exception_irq_entry zevio_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry zevio_handle_irq(struct pt_regs *regs)
{
int irqnr;
diff --git a/drivers/irqchip/irqchip.c b/drivers/irqchip/irqchip.c
index f496afce29de..cad3e2495552 100644
--- a/drivers/irqchip/irqchip.c
+++ b/drivers/irqchip/irqchip.c
@@ -10,8 +10,7 @@
#include <linux/init.h>
#include <linux/of_irq.h>
-
-#include "irqchip.h"
+#include <linux/irqchip.h>
/*
* This special of_device_id is the sentinel at the end of the
diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c
index b4147c0b14b7..c3a1b061838d 100644
--- a/drivers/isdn/act2000/module.c
+++ b/drivers/isdn/act2000/module.c
@@ -796,7 +796,7 @@ static void __exit act2000_exit(void)
act2000_card *last;
while (card) {
unregister_card(card);
- del_timer(&card->ptimer);
+ del_timer_sync(&card->ptimer);
card = card->next;
}
card = cards;
diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig
index f04686580040..9816c51eb5c2 100644
--- a/drivers/isdn/capi/Kconfig
+++ b/drivers/isdn/capi/Kconfig
@@ -16,9 +16,17 @@ config CAPI_TRACE
This will increase the size of the kernelcapi module by 20 KB.
If unsure, say Y.
+config ISDN_CAPI_CAPI20
+ tristate "CAPI2.0 /dev/capi support"
+ help
+ This option will provide the CAPI 2.0 interface to userspace
+ applications via /dev/capi20. Applications should use the
+ standardized libcapi20 to access this functionality. You should say
+ Y/M here.
+
config ISDN_CAPI_MIDDLEWARE
bool "CAPI2.0 Middleware support"
- depends on TTY
+ depends on ISDN_CAPI_CAPI20 && TTY
help
This option will enhance the capabilities of the /dev/capi20
interface. It will provide a means of moving a data connection,
@@ -26,14 +34,6 @@ config ISDN_CAPI_MIDDLEWARE
device. If you want to use pppd with pppdcapiplugin to dial up to
your ISP, say Y here.
-config ISDN_CAPI_CAPI20
- tristate "CAPI2.0 /dev/capi support"
- help
- This option will provide the CAPI 2.0 interface to userspace
- applications via /dev/capi20. Applications should use the
- standardized libcapi20 to access this functionality. You should say
- Y/M here.
-
config ISDN_CAPI_CAPIDRV
tristate "CAPI2.0 capidrv interface support"
depends on ISDN_I4L
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index fb4f1bac0133..1c5dc345e7c5 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -86,12 +86,13 @@ isdn_divert_read(struct file *file, char __user *buf, size_t count, loff_t *off)
struct divert_info *inf;
int len;
- if (!*((struct divert_info **) file->private_data)) {
+ if (!(inf = *((struct divert_info **) file->private_data))) {
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
- interruptible_sleep_on(&(rd_queue));
+ wait_event_interruptible(rd_queue, (inf =
+ *((struct divert_info **) file->private_data)));
}
- if (!(inf = *((struct divert_info **) file->private_data)))
+ if (!inf)
return (0);
inf->usage_cnt--; /* new usage count */
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
index 2be1c8a3bb5f..d8ef64da26f1 100644
--- a/drivers/isdn/hisax/elsa.c
+++ b/drivers/isdn/hisax/elsa.c
@@ -509,7 +509,8 @@ static void
set_arcofi(struct IsdnCardState *cs, int bc) {
cs->dc.isac.arcofi_bc = bc;
arcofi_fsm(cs, ARCOFI_START, &ARCOFI_COP_5);
- interruptible_sleep_on(&cs->dc.isac.arcofi_wait);
+ wait_event_interruptible(cs->dc.isac.arcofi_wait,
+ cs->dc.isac.arcofi_state == ARCOFI_NOP);
}
static int
@@ -528,7 +529,8 @@ check_arcofi(struct IsdnCardState *cs)
}
cs->dc.isac.arcofi_bc = 0;
arcofi_fsm(cs, ARCOFI_START, &ARCOFI_VERSION);
- interruptible_sleep_on(&cs->dc.isac.arcofi_wait);
+ wait_event_interruptible(cs->dc.isac.arcofi_wait,
+ cs->dc.isac.arcofi_state == ARCOFI_NOP);
if (!test_and_clear_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags)) {
debugl1(cs, "Arcofi response received %d bytes", cs->dc.isac.mon_rxp);
p = cs->dc.isac.mon_rx;
@@ -595,7 +597,8 @@ check_arcofi(struct IsdnCardState *cs)
Elsa_Types[cs->subtyp],
cs->hw.elsa.base + 8);
arcofi_fsm(cs, ARCOFI_START, &ARCOFI_XOP_0);
- interruptible_sleep_on(&cs->dc.isac.arcofi_wait);
+ wait_event_interruptible(cs->dc.isac.arcofi_wait,
+ cs->dc.isac.arcofi_state == ARCOFI_NOP);
return (1);
}
return (0);
diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c
index 3f84dd8f1757..a2a358c1dc8e 100644
--- a/drivers/isdn/hisax/elsa_ser.c
+++ b/drivers/isdn/hisax/elsa_ser.c
@@ -573,7 +573,8 @@ modem_l2l1(struct PStack *st, int pr, void *arg)
test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
bcs->cs->dc.isac.arcofi_bc = st->l1.bc;
arcofi_fsm(bcs->cs, ARCOFI_START, &ARCOFI_XOP_0);
- interruptible_sleep_on(&bcs->cs->dc.isac.arcofi_wait);
+ wait_event_interruptible(bcs->cs->dc.isac.arcofi_wait,
+ bcs->cs->dc.isac.arcofi_state == ARCOFI_NOP);
bcs->cs->hw.elsa.MFlag = 1;
} else {
printk(KERN_WARNING "ElsaSer: unknown pr %x\n", pr);
diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c
index af1b020a81f1..b420f8bd862e 100644
--- a/drivers/isdn/hisax/q931.c
+++ b/drivers/isdn/hisax/q931.c
@@ -810,7 +810,7 @@ prfeatureind(char *dest, u_char *p)
dp += sprintf(dp, " octet 3 ");
dp += prbits(dp, *p, 8, 8);
*dp++ = '\n';
- if (!(*p++ & 80)) {
+ if (!(*p++ & 0x80)) {
dp += sprintf(dp, " octet 4 ");
dp += prbits(dp, *p++, 8, 8);
*dp++ = '\n';
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
index b61e8d5e84ad..7b5fd8fb1761 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -175,14 +175,15 @@ hysdn_log_read(struct file *file, char __user *buf, size_t count, loff_t *off)
int len;
hysdn_card *card = PDE_DATA(file_inode(file));
- if (!*((struct log_data **) file->private_data)) {
+ if (!(inf = *((struct log_data **) file->private_data))) {
struct procdata *pd = card->proclog;
if (file->f_flags & O_NONBLOCK)
return (-EAGAIN);
- interruptible_sleep_on(&(pd->rd_queue));
+ wait_event_interruptible(pd->rd_queue, (inf =
+ *((struct log_data **) file->private_data)));
}
- if (!(inf = *((struct log_data **) file->private_data)))
+ if (!inf)
return (0);
inf->usage_cnt--; /* new usage count */
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index 9bb12ba3191f..9b856e1890d1 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -777,7 +777,8 @@ isdn_readbchan(int di, int channel, u_char *buf, u_char *fp, int len, wait_queue
return 0;
if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) {
if (sleep)
- interruptible_sleep_on(sleep);
+ wait_event_interruptible(*sleep,
+ !skb_queue_empty(&dev->drv[di]->rpqueue[channel]));
else
return 0;
}
@@ -1072,7 +1073,8 @@ isdn_read(struct file *file, char __user *buf, size_t count, loff_t *off)
retval = -EAGAIN;
goto out;
}
- interruptible_sleep_on(&(dev->info_waitq));
+ wait_event_interruptible(dev->info_waitq,
+ file->private_data);
}
p = isdn_statstr();
file->private_data = NULL;
@@ -1128,7 +1130,8 @@ isdn_read(struct file *file, char __user *buf, size_t count, loff_t *off)
retval = -EAGAIN;
goto out;
}
- interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
+ wait_event_interruptible(dev->drv[drvidx]->st_waitq,
+ dev->drv[drvidx]->stavail);
}
if (dev->drv[drvidx]->interface->readstat) {
if (count > dev->drv[drvidx]->stavail)
@@ -1188,8 +1191,8 @@ isdn_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
goto out;
}
chidx = isdn_minor2chan(minor);
- while ((retval = isdn_writebuf_stub(drvidx, chidx, buf, count)) == 0)
- interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]);
+ wait_event_interruptible(dev->drv[drvidx]->snd_waitq[chidx],
+ (retval = isdn_writebuf_stub(drvidx, chidx, buf, count)));
goto out;
}
if (minor <= ISDN_MINOR_CTRLMAX) {
@@ -2378,7 +2381,7 @@ static void __exit isdn_exit(void)
}
isdn_tty_exit();
unregister_chrdev(ISDN_MAJOR, "isdn");
- del_timer(&dev->timer);
+ del_timer_sync(&dev->timer);
/* call vfree with interrupts enabled, else it will hang */
vfree(dev);
printk(KERN_NOTICE "ISDN-subsystem unloaded\n");
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index 38ceac5053a0..a5da511e3c9a 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -378,10 +378,15 @@ isdn_ppp_release(int min, struct file *file)
is->slcomp = NULL;
#endif
#ifdef CONFIG_IPPP_FILTER
- kfree(is->pass_filter);
- is->pass_filter = NULL;
- kfree(is->active_filter);
- is->active_filter = NULL;
+ if (is->pass_filter) {
+ sk_unattached_filter_destroy(is->pass_filter);
+ is->pass_filter = NULL;
+ }
+
+ if (is->active_filter) {
+ sk_unattached_filter_destroy(is->active_filter);
+ is->active_filter = NULL;
+ }
#endif
/* TODO: if this was the previous master: link the stuff to the new master */
@@ -629,25 +634,41 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
#ifdef CONFIG_IPPP_FILTER
case PPPIOCSPASS:
{
+ struct sock_fprog fprog;
struct sock_filter *code;
- int len = get_filter(argp, &code);
+ int err, len = get_filter(argp, &code);
+
if (len < 0)
return len;
- kfree(is->pass_filter);
- is->pass_filter = code;
- is->pass_len = len;
- break;
+
+ fprog.len = len;
+ fprog.filter = code;
+
+ if (is->pass_filter)
+ sk_unattached_filter_destroy(is->pass_filter);
+ err = sk_unattached_filter_create(&is->pass_filter, &fprog);
+ kfree(code);
+
+ return err;
}
case PPPIOCSACTIVE:
{
+ struct sock_fprog fprog;
struct sock_filter *code;
- int len = get_filter(argp, &code);
+ int err, len = get_filter(argp, &code);
+
if (len < 0)
return len;
- kfree(is->active_filter);
- is->active_filter = code;
- is->active_len = len;
- break;
+
+ fprog.len = len;
+ fprog.filter = code;
+
+ if (is->active_filter)
+ sk_unattached_filter_destroy(is->active_filter);
+ err = sk_unattached_filter_create(&is->active_filter, &fprog);
+ kfree(code);
+
+ return err;
}
#endif /* CONFIG_IPPP_FILTER */
default:
@@ -1147,14 +1168,14 @@ isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *
}
if (is->pass_filter
- && sk_run_filter(skb, is->pass_filter) == 0) {
+ && SK_RUN_FILTER(is->pass_filter, skb) == 0) {
if (is->debug & 0x2)
printk(KERN_DEBUG "IPPP: inbound frame filtered.\n");
kfree_skb(skb);
return;
}
if (!(is->active_filter
- && sk_run_filter(skb, is->active_filter) == 0)) {
+ && SK_RUN_FILTER(is->active_filter, skb) == 0)) {
if (is->debug & 0x2)
printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n");
lp->huptimer = 0;
@@ -1293,14 +1314,14 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
}
if (ipt->pass_filter
- && sk_run_filter(skb, ipt->pass_filter) == 0) {
+ && SK_RUN_FILTER(ipt->pass_filter, skb) == 0) {
if (ipt->debug & 0x4)
printk(KERN_DEBUG "IPPP: outbound frame filtered.\n");
kfree_skb(skb);
goto unlock;
}
if (!(ipt->active_filter
- && sk_run_filter(skb, ipt->active_filter) == 0)) {
+ && SK_RUN_FILTER(ipt->active_filter, skb) == 0)) {
if (ipt->debug & 0x4)
printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n");
lp->huptimer = 0;
@@ -1490,9 +1511,9 @@ int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp)
}
drop |= is->pass_filter
- && sk_run_filter(skb, is->pass_filter) == 0;
+ && SK_RUN_FILTER(is->pass_filter, skb) == 0;
drop |= is->active_filter
- && sk_run_filter(skb, is->active_filter) == 0;
+ && SK_RUN_FILTER(is->active_filter, skb) == 0;
skb_push(skb, IPPP_MAX_HEADER - 4);
return drop;
diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c
index 1eaf62273903..f02cc506fbfa 100644
--- a/drivers/isdn/pcbit/drv.c
+++ b/drivers/isdn/pcbit/drv.c
@@ -796,6 +796,7 @@ static void set_running_timeout(unsigned long ptr)
#endif
dev = (struct pcbit_dev *) ptr;
+ dev->l2_state = L2_DOWN;
wake_up_interruptible(&dev->set_running_wq);
}
@@ -818,7 +819,8 @@ static int set_protocol_running(struct pcbit_dev *dev)
add_timer(&dev->set_running_timer);
- interruptible_sleep_on(&dev->set_running_wq);
+ wait_event(dev->set_running_wq, dev->l2_state == L2_RUNNING ||
+ dev->l2_state == L2_DOWN);
del_timer(&dev->set_running_timer);
@@ -842,8 +844,6 @@ static int set_protocol_running(struct pcbit_dev *dev)
printk(KERN_DEBUG "pcbit: initialization failed\n");
printk(KERN_DEBUG "pcbit: firmware not loaded\n");
- dev->l2_state = L2_DOWN;
-
#ifdef DEBUG
printk(KERN_DEBUG "Bank3 = %02x\n",
readb(dev->sh_mem + BANK3));
diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c
index 92acc81f844d..d6f19b168e8a 100644
--- a/drivers/isdn/sc/init.c
+++ b/drivers/isdn/sc/init.c
@@ -390,8 +390,8 @@ static void __exit sc_exit(void)
/*
* kill the timers
*/
- del_timer(&(sc_adapter[i]->reset_timer));
- del_timer(&(sc_adapter[i]->stat_timer));
+ del_timer_sync(&(sc_adapter[i]->reset_timer));
+ del_timer_sync(&(sc_adapter[i]->stat_timer));
/*
* Tell I4L we're toast
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index 04a50498f257..9e9c56758a08 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -38,7 +38,7 @@
#include <linux/platform_device.h>
#include <linux/mutex.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#ifdef CONFIG_PPC
#include <asm/prom.h>
#include <asm/machdep.h>
@@ -193,8 +193,7 @@ static int adb_scan_bus(void)
break;
noMovement = 0;
- }
- else {
+ } else {
/*
* No devices left at address i; move the
* one(s) we moved to `highFree' back to i.
@@ -263,7 +262,7 @@ adb_reset_bus(void)
/*
* notify clients before sleep
*/
-static int adb_suspend(struct platform_device *dev, pm_message_t state)
+static int __adb_suspend(struct platform_device *dev, pm_message_t state)
{
adb_got_sleep = 1;
/* We need to get a lock on the probe thread */
@@ -276,10 +275,25 @@ static int adb_suspend(struct platform_device *dev, pm_message_t state)
return 0;
}
+static int adb_suspend(struct device *dev)
+{
+ return __adb_suspend(to_platform_device(dev), PMSG_SUSPEND);
+}
+
+static int adb_freeze(struct device *dev)
+{
+ return __adb_suspend(to_platform_device(dev), PMSG_FREEZE);
+}
+
+static int adb_poweroff(struct device *dev)
+{
+ return __adb_suspend(to_platform_device(dev), PMSG_HIBERNATE);
+}
+
/*
* reset bus after sleep
*/
-static int adb_resume(struct platform_device *dev)
+static int __adb_resume(struct platform_device *dev)
{
adb_got_sleep = 0;
up(&adb_probe_mutex);
@@ -287,6 +301,11 @@ static int adb_resume(struct platform_device *dev)
return 0;
}
+
+static int adb_resume(struct device *dev)
+{
+ return __adb_resume(to_platform_device(dev));
+}
#endif /* CONFIG_PM */
static int __init adb_init(void)
@@ -502,7 +521,7 @@ void
adb_input(unsigned char *buf, int nb, int autopoll)
{
int i, id;
- static int dump_adb_input = 0;
+ static int dump_adb_input;
unsigned long flags;
void (*handler)(unsigned char *, int, int);
@@ -624,8 +643,7 @@ do_adb_query(struct adb_request *req)
{
int ret = -EINVAL;
- switch(req->data[1])
- {
+ switch(req->data[1]) {
case ADB_QUERY_GETDEVINFO:
if (req->nbytes < 3)
break;
@@ -697,7 +715,7 @@ static ssize_t adb_read(struct file *file, char __user *buf,
int ret = 0;
struct adbdev_state *state = file->private_data;
struct adb_request *req;
- DECLARE_WAITQUEUE(wait,current);
+ DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
if (count < 2)
@@ -794,8 +812,8 @@ static ssize_t adb_write(struct file *file, const char __user *buf,
}
/* Special case for ADB_BUSRESET request, all others are sent to
the controller */
- else if ((req->data[0] == ADB_PACKET)&&(count > 1)
- &&(req->data[1] == ADB_BUSRESET)) {
+ else if ((req->data[0] == ADB_PACKET) && (count > 1)
+ && (req->data[1] == ADB_BUSRESET)) {
ret = do_adb_reset_bus();
up(&adb_probe_mutex);
atomic_dec(&state->n_pending);
@@ -831,14 +849,25 @@ static const struct file_operations adb_fops = {
.release = adb_release,
};
+#ifdef CONFIG_PM
+static const struct dev_pm_ops adb_dev_pm_ops = {
+ .suspend = adb_suspend,
+ .resume = adb_resume,
+ /* Hibernate hooks */
+ .freeze = adb_freeze,
+ .thaw = adb_resume,
+ .poweroff = adb_poweroff,
+ .restore = adb_resume,
+};
+#endif
+
static struct platform_driver adb_pfdrv = {
.driver = {
.name = "adb",
- },
#ifdef CONFIG_PM
- .suspend = adb_suspend,
- .resume = adb_resume,
+ .pm = &adb_dev_pm_ops,
#endif
+ },
};
static struct platform_device adb_pfdev = {
diff --git a/drivers/mcb/Kconfig b/drivers/mcb/Kconfig
new file mode 100644
index 000000000000..e9a6976e1010
--- /dev/null
+++ b/drivers/mcb/Kconfig
@@ -0,0 +1,31 @@
+#
+# MEN Chameleon Bus (MCB) support
+#
+
+menuconfig MCB
+ tristate "MCB support"
+ default n
+ depends on HAS_IOMEM
+ help
+
+ The MCB (MEN Chameleon Bus) is a Bus specific to MEN Mikroelektronik
+ FPGA based devices. It is used to identify MCB based IP-Cores within
+ an FPGA and provide the necessary framework for instantiating drivers
+ for these devices.
+
+ If build as a module, the module is called mcb.ko
+
+if MCB
+config MCB_PCI
+ tristate "PCI based MCB carrier"
+ default n
+ depends on PCI
+ help
+
+ This is a MCB carrier on a PCI device. Both PCI attached on-board
+ FPGAs as well as CompactPCI attached MCB FPGAs are supported with
+ this driver.
+
+ If build as a module, the module is called mcb-pci.ko
+
+endif # MCB
diff --git a/drivers/mcb/Makefile b/drivers/mcb/Makefile
new file mode 100644
index 000000000000..1ae141311def
--- /dev/null
+++ b/drivers/mcb/Makefile
@@ -0,0 +1,7 @@
+
+obj-$(CONFIG_MCB) += mcb.o
+
+mcb-y += mcb-core.o
+mcb-y += mcb-parse.o
+
+obj-$(CONFIG_MCB_PCI) += mcb-pci.o
diff --git a/drivers/mcb/mcb-core.c b/drivers/mcb/mcb-core.c
new file mode 100644
index 000000000000..bbe12932d404
--- /dev/null
+++ b/drivers/mcb/mcb-core.c
@@ -0,0 +1,414 @@
+/*
+ * MEN Chameleon Bus.
+ *
+ * Copyright (C) 2013 MEN Mikroelektronik GmbH (www.men.de)
+ * Author: Johannes Thumshirn <johannes.thumshirn@men.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/idr.h>
+#include <linux/mcb.h>
+
+static DEFINE_IDA(mcb_ida);
+
+static const struct mcb_device_id *mcb_match_id(const struct mcb_device_id *ids,
+ struct mcb_device *dev)
+{
+ if (ids) {
+ while (ids->device) {
+ if (ids->device == dev->id)
+ return ids;
+ ids++;
+ }
+ }
+
+ return NULL;
+}
+
+static int mcb_match(struct device *dev, struct device_driver *drv)
+{
+ struct mcb_driver *mdrv = to_mcb_driver(drv);
+ struct mcb_device *mdev = to_mcb_device(dev);
+ const struct mcb_device_id *found_id;
+
+ found_id = mcb_match_id(mdrv->id_table, mdev);
+ if (found_id)
+ return 1;
+
+ return 0;
+}
+
+static int mcb_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct mcb_device *mdev = to_mcb_device(dev);
+ int ret;
+
+ ret = add_uevent_var(env, "MODALIAS=mcb:16z%03d", mdev->id);
+ if (ret)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int mcb_probe(struct device *dev)
+{
+ struct mcb_driver *mdrv = to_mcb_driver(dev->driver);
+ struct mcb_device *mdev = to_mcb_device(dev);
+ const struct mcb_device_id *found_id;
+
+ found_id = mcb_match_id(mdrv->id_table, mdev);
+ if (!found_id)
+ return -ENODEV;
+
+ return mdrv->probe(mdev, found_id);
+}
+
+static int mcb_remove(struct device *dev)
+{
+ struct mcb_driver *mdrv = to_mcb_driver(dev->driver);
+ struct mcb_device *mdev = to_mcb_device(dev);
+
+ mdrv->remove(mdev);
+
+ put_device(&mdev->dev);
+
+ return 0;
+}
+
+static void mcb_shutdown(struct device *dev)
+{
+ struct mcb_device *mdev = to_mcb_device(dev);
+ struct mcb_driver *mdrv = mdev->driver;
+
+ if (mdrv && mdrv->shutdown)
+ mdrv->shutdown(mdev);
+}
+
+static struct bus_type mcb_bus_type = {
+ .name = "mcb",
+ .match = mcb_match,
+ .uevent = mcb_uevent,
+ .probe = mcb_probe,
+ .remove = mcb_remove,
+ .shutdown = mcb_shutdown,
+};
+
+/**
+ * __mcb_register_driver() - Register a @mcb_driver at the system
+ * @drv: The @mcb_driver
+ * @owner: The @mcb_driver's module
+ * @mod_name: The name of the @mcb_driver's module
+ *
+ * Register a @mcb_driver at the system. Perform some sanity checks, if
+ * the .probe and .remove methods are provided by the driver.
+ */
+int __mcb_register_driver(struct mcb_driver *drv, struct module *owner,
+ const char *mod_name)
+{
+ if (!drv->probe || !drv->remove)
+ return -EINVAL;
+
+ drv->driver.owner = owner;
+ drv->driver.bus = &mcb_bus_type;
+ drv->driver.mod_name = mod_name;
+
+ return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(__mcb_register_driver);
+
+/**
+ * mcb_unregister_driver() - Unregister a @mcb_driver from the system
+ * @drv: The @mcb_driver
+ *
+ * Unregister a @mcb_driver from the system.
+ */
+void mcb_unregister_driver(struct mcb_driver *drv)
+{
+ driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(mcb_unregister_driver);
+
+static void mcb_release_dev(struct device *dev)
+{
+ struct mcb_device *mdev = to_mcb_device(dev);
+
+ mcb_bus_put(mdev->bus);
+ kfree(mdev);
+}
+
+/**
+ * mcb_device_register() - Register a mcb_device
+ * @bus: The @mcb_bus of the device
+ * @dev: The @mcb_device
+ *
+ * Register a specific @mcb_device at a @mcb_bus and the system itself.
+ */
+int mcb_device_register(struct mcb_bus *bus, struct mcb_device *dev)
+{
+ int ret;
+ int device_id;
+
+ device_initialize(&dev->dev);
+ dev->dev.bus = &mcb_bus_type;
+ dev->dev.parent = bus->dev.parent;
+ dev->dev.release = mcb_release_dev;
+
+ device_id = dev->id;
+ dev_set_name(&dev->dev, "mcb%d-16z%03d-%d:%d:%d",
+ bus->bus_nr, device_id, dev->inst, dev->group, dev->var);
+
+ ret = device_add(&dev->dev);
+ if (ret < 0) {
+ pr_err("Failed registering device 16z%03d on bus mcb%d (%d)\n",
+ device_id, bus->bus_nr, ret);
+ goto out;
+ }
+
+ return 0;
+
+out:
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mcb_device_register);
+
+/**
+ * mcb_alloc_bus() - Allocate a new @mcb_bus
+ *
+ * Allocate a new @mcb_bus.
+ */
+struct mcb_bus *mcb_alloc_bus(void)
+{
+ struct mcb_bus *bus;
+ int bus_nr;
+
+ bus = kzalloc(sizeof(struct mcb_bus), GFP_KERNEL);
+ if (!bus)
+ return NULL;
+
+ bus_nr = ida_simple_get(&mcb_ida, 0, 0, GFP_KERNEL);
+ if (bus_nr < 0) {
+ kfree(bus);
+ return ERR_PTR(bus_nr);
+ }
+
+ INIT_LIST_HEAD(&bus->children);
+ bus->bus_nr = bus_nr;
+
+ return bus;
+}
+EXPORT_SYMBOL_GPL(mcb_alloc_bus);
+
+static int __mcb_devices_unregister(struct device *dev, void *data)
+{
+ device_unregister(dev);
+ return 0;
+}
+
+static void mcb_devices_unregister(struct mcb_bus *bus)
+{
+ bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_devices_unregister);
+}
+/**
+ * mcb_release_bus() - Free a @mcb_bus
+ * @bus: The @mcb_bus to release
+ *
+ * Release an allocated @mcb_bus from the system.
+ */
+void mcb_release_bus(struct mcb_bus *bus)
+{
+ mcb_devices_unregister(bus);
+
+ ida_simple_remove(&mcb_ida, bus->bus_nr);
+
+ kfree(bus);
+}
+EXPORT_SYMBOL_GPL(mcb_release_bus);
+
+/**
+ * mcb_bus_put() - Increment refcnt
+ * @bus: The @mcb_bus
+ *
+ * Get a @mcb_bus' ref
+ */
+struct mcb_bus *mcb_bus_get(struct mcb_bus *bus)
+{
+ if (bus)
+ get_device(&bus->dev);
+
+ return bus;
+}
+EXPORT_SYMBOL_GPL(mcb_bus_get);
+
+/**
+ * mcb_bus_put() - Decrement refcnt
+ * @bus: The @mcb_bus
+ *
+ * Release a @mcb_bus' ref
+ */
+void mcb_bus_put(struct mcb_bus *bus)
+{
+ if (bus)
+ put_device(&bus->dev);
+}
+EXPORT_SYMBOL_GPL(mcb_bus_put);
+
+/**
+ * mcb_alloc_dev() - Allocate a device
+ * @bus: The @mcb_bus the device is part of
+ *
+ * Allocate a @mcb_device and add bus.
+ */
+struct mcb_device *mcb_alloc_dev(struct mcb_bus *bus)
+{
+ struct mcb_device *dev;
+
+ dev = kzalloc(sizeof(struct mcb_device), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ INIT_LIST_HEAD(&dev->bus_list);
+ dev->bus = bus;
+
+ return dev;
+}
+EXPORT_SYMBOL_GPL(mcb_alloc_dev);
+
+/**
+ * mcb_free_dev() - Free @mcb_device
+ * @dev: The device to free
+ *
+ * Free a @mcb_device
+ */
+void mcb_free_dev(struct mcb_device *dev)
+{
+ kfree(dev);
+}
+EXPORT_SYMBOL_GPL(mcb_free_dev);
+
+static int __mcb_bus_add_devices(struct device *dev, void *data)
+{
+ struct mcb_device *mdev = to_mcb_device(dev);
+ int retval;
+
+ if (mdev->is_added)
+ return 0;
+
+ retval = device_attach(dev);
+ if (retval < 0)
+ dev_err(dev, "Error adding device (%d)\n", retval);
+
+ mdev->is_added = true;
+
+ return 0;
+}
+
+static int __mcb_bus_add_child(struct device *dev, void *data)
+{
+ struct mcb_device *mdev = to_mcb_device(dev);
+ struct mcb_bus *child;
+
+ BUG_ON(!mdev->is_added);
+ child = mdev->subordinate;
+
+ if (child)
+ mcb_bus_add_devices(child);
+
+ return 0;
+}
+
+/**
+ * mcb_bus_add_devices() - Add devices in the bus' internal device list
+ * @bus: The @mcb_bus we add the devices
+ *
+ * Add devices in the bus' internal device list to the system.
+ */
+void mcb_bus_add_devices(const struct mcb_bus *bus)
+{
+ bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_devices);
+ bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_child);
+
+}
+EXPORT_SYMBOL_GPL(mcb_bus_add_devices);
+
+/**
+ * mcb_request_mem() - Request memory
+ * @dev: The @mcb_device the memory is for
+ * @name: The name for the memory reference.
+ *
+ * Request memory for a @mcb_device. If @name is NULL the driver name will
+ * be used.
+ */
+struct resource *mcb_request_mem(struct mcb_device *dev, const char *name)
+{
+ struct resource *mem;
+ u32 size;
+
+ if (!name)
+ name = dev->dev.driver->name;
+
+ size = resource_size(&dev->mem);
+
+ mem = request_mem_region(dev->mem.start, size, name);
+ if (!mem)
+ return ERR_PTR(-EBUSY);
+
+ return mem;
+}
+EXPORT_SYMBOL_GPL(mcb_request_mem);
+
+/**
+ * mcb_release_mem() - Release memory requested by device
+ * @dev: The @mcb_device that requested the memory
+ *
+ * Release memory that was prior requested via @mcb_request_mem().
+ */
+void mcb_release_mem(struct resource *mem)
+{
+ u32 size;
+
+ size = resource_size(mem);
+ release_mem_region(mem->start, size);
+}
+EXPORT_SYMBOL_GPL(mcb_release_mem);
+
+/**
+ * mcb_get_irq() - Get device's IRQ number
+ * @dev: The @mcb_device the IRQ is for
+ *
+ * Get the IRQ number of a given @mcb_device.
+ */
+int mcb_get_irq(struct mcb_device *dev)
+{
+ struct resource *irq = &dev->irq;
+
+ return irq->start;
+}
+EXPORT_SYMBOL_GPL(mcb_get_irq);
+
+static int mcb_init(void)
+{
+ return bus_register(&mcb_bus_type);
+}
+
+static void mcb_exit(void)
+{
+ bus_unregister(&mcb_bus_type);
+}
+
+/* mcb must be initialized after PCI but before the chameleon drivers.
+ * That means we must use some initcall between subsys_initcall and
+ * device_initcall.
+ */
+fs_initcall(mcb_init);
+module_exit(mcb_exit);
+
+MODULE_DESCRIPTION("MEN Chameleon Bus Driver");
+MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mcb/mcb-internal.h b/drivers/mcb/mcb-internal.h
new file mode 100644
index 000000000000..f956ef26c0ce
--- /dev/null
+++ b/drivers/mcb/mcb-internal.h
@@ -0,0 +1,118 @@
+#ifndef __MCB_INTERNAL
+#define __MCB_INTERNAL
+
+#include <linux/types.h>
+
+#define PCI_VENDOR_ID_MEN 0x1a88
+#define PCI_DEVICE_ID_MEN_CHAMELEON 0x4d45
+#define CHAMELEON_FILENAME_LEN 12
+#define CHAMELEONV2_MAGIC 0xabce
+
+enum chameleon_descriptor_type {
+ CHAMELEON_DTYPE_GENERAL = 0x0,
+ CHAMELEON_DTYPE_BRIDGE = 0x1,
+ CHAMELEON_DTYPE_CPU = 0x2,
+ CHAMELEON_DTYPE_BAR = 0x3,
+ CHAMELEON_DTYPE_END = 0xf,
+};
+
+enum chameleon_bus_type {
+ CHAMELEON_BUS_WISHBONE,
+ CHAMELEON_BUS_AVALON,
+ CHAMELEON_BUS_LPC,
+ CHAMELEON_BUS_ISA,
+};
+
+/**
+ * struct chameleon_fpga_header
+ *
+ * @revision: Revison of Chameleon table in FPGA
+ * @model: Chameleon table model ASCII char
+ * @minor: Revision minor
+ * @bus_type: Bus type (usually %CHAMELEON_BUS_WISHBONE)
+ * @magic: Chameleon header magic number (0xabce for version 2)
+ * @reserved: Reserved
+ * @filename: Filename of FPGA bitstream
+ */
+struct chameleon_fpga_header {
+ u8 revision;
+ char model;
+ u8 minor;
+ u8 bus_type;
+ u16 magic;
+ u16 reserved;
+ /* This one has no '\0' at the end!!! */
+ char filename[CHAMELEON_FILENAME_LEN];
+} __packed;
+#define HEADER_MAGIC_OFFSET 0x4
+
+/**
+ * struct chameleon_gdd - Chameleon General Device Descriptor
+ *
+ * @irq: the position in the FPGA's IRQ controller vector
+ * @rev: the revision of the variant's implementation
+ * @var: the variant of the IP core
+ * @dev: the device the IP core is
+ * @dtype: device descriptor type
+ * @bar: BAR offset that must be added to module offset
+ * @inst: the instance number of the device, 0 is first instance
+ * @group: the group the device belongs to (0 = no group)
+ * @reserved: reserved
+ * @offset: beginning of the address window of desired module
+ * @size: size of the module's address window
+ */
+struct chameleon_gdd {
+ __le32 reg1;
+ __le32 reg2;
+ __le32 offset;
+ __le32 size;
+
+} __packed;
+
+/* GDD Register 1 fields */
+#define GDD_IRQ(x) ((x) & 0x1f)
+#define GDD_REV(x) (((x) >> 5) & 0x3f)
+#define GDD_VAR(x) (((x) >> 11) & 0x3f)
+#define GDD_DEV(x) (((x) >> 18) & 0x3ff)
+#define GDD_DTY(x) (((x) >> 28) & 0xf)
+
+/* GDD Register 2 fields */
+#define GDD_BAR(x) ((x) & 0x7)
+#define GDD_INS(x) (((x) >> 3) & 0x3f)
+#define GDD_GRP(x) (((x) >> 9) & 0x3f)
+
+/**
+ * struct chameleon_bdd - Chameleon Bridge Device Descriptor
+ *
+ * @irq: the position in the FPGA's IRQ controller vector
+ * @rev: the revision of the variant's implementation
+ * @var: the variant of the IP core
+ * @dev: the device the IP core is
+ * @dtype: device descriptor type
+ * @bar: BAR offset that must be added to module offset
+ * @inst: the instance number of the device, 0 is first instance
+ * @dbar: destination bar from the bus _behind_ the bridge
+ * @chamoff: offset within the BAR of the source bus
+ * @offset:
+ * @size:
+ */
+struct chameleon_bdd {
+ unsigned int irq:6;
+ unsigned int rev:6;
+ unsigned int var:6;
+ unsigned int dev:10;
+ unsigned int dtype:4;
+ unsigned int bar:3;
+ unsigned int inst:6;
+ unsigned int dbar:3;
+ unsigned int group:6;
+ unsigned int reserved:14;
+ u32 chamoff;
+ u32 offset;
+ u32 size;
+} __packed;
+
+int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase,
+ void __iomem *base);
+
+#endif
diff --git a/drivers/mcb/mcb-parse.c b/drivers/mcb/mcb-parse.c
new file mode 100644
index 000000000000..d1278b5f3028
--- /dev/null
+++ b/drivers/mcb/mcb-parse.c
@@ -0,0 +1,159 @@
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/mcb.h>
+
+#include "mcb-internal.h"
+
+struct mcb_parse_priv {
+ phys_addr_t mapbase;
+ void __iomem *base;
+};
+
+#define for_each_chameleon_cell(dtype, p) \
+ for ((dtype) = get_next_dtype((p)); \
+ (dtype) != CHAMELEON_DTYPE_END; \
+ (dtype) = get_next_dtype((p)))
+
+static inline uint32_t get_next_dtype(void __iomem *p)
+{
+ uint32_t dtype;
+
+ dtype = readl(p);
+ return dtype >> 28;
+}
+
+static int chameleon_parse_bdd(struct mcb_bus *bus,
+ phys_addr_t mapbase,
+ void __iomem *base)
+{
+ return 0;
+}
+
+static int chameleon_parse_gdd(struct mcb_bus *bus,
+ phys_addr_t mapbase,
+ void __iomem *base)
+{
+ struct chameleon_gdd __iomem *gdd =
+ (struct chameleon_gdd __iomem *) base;
+ struct mcb_device *mdev;
+ u32 offset;
+ u32 size;
+ int ret;
+ __le32 reg1;
+ __le32 reg2;
+
+ mdev = mcb_alloc_dev(bus);
+ if (!mdev)
+ return -ENOMEM;
+
+ reg1 = readl(&gdd->reg1);
+ reg2 = readl(&gdd->reg2);
+ offset = readl(&gdd->offset);
+ size = readl(&gdd->size);
+
+ mdev->id = GDD_DEV(reg1);
+ mdev->rev = GDD_REV(reg1);
+ mdev->var = GDD_VAR(reg1);
+ mdev->bar = GDD_BAR(reg1);
+ mdev->group = GDD_GRP(reg2);
+ mdev->inst = GDD_INS(reg2);
+
+ pr_debug("Found a 16z%03d\n", mdev->id);
+
+ mdev->irq.start = GDD_IRQ(reg1);
+ mdev->irq.end = GDD_IRQ(reg1);
+ mdev->irq.flags = IORESOURCE_IRQ;
+
+ mdev->mem.start = mapbase + offset;
+ mdev->mem.end = mdev->mem.start + size - 1;
+ mdev->mem.flags = IORESOURCE_MEM;
+
+ mdev->is_added = false;
+
+ ret = mcb_device_register(bus, mdev);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+
+err:
+ mcb_free_dev(mdev);
+
+ return ret;
+}
+
+int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase,
+ void __iomem *base)
+{
+ char __iomem *p = base;
+ struct chameleon_fpga_header *header;
+ uint32_t dtype;
+ int num_cells = 0;
+ int ret = 0;
+ u32 hsize;
+
+ hsize = sizeof(struct chameleon_fpga_header);
+
+ header = kzalloc(hsize, GFP_KERNEL);
+ if (!header)
+ return -ENOMEM;
+
+ /* Extract header information */
+ memcpy_fromio(header, p, hsize);
+ /* We only support chameleon v2 at the moment */
+ header->magic = le16_to_cpu(header->magic);
+ if (header->magic != CHAMELEONV2_MAGIC) {
+ pr_err("Unsupported chameleon version 0x%x\n",
+ header->magic);
+ kfree(header);
+ return -ENODEV;
+ }
+ p += hsize;
+
+ pr_debug("header->revision = %d\n", header->revision);
+ pr_debug("header->model = 0x%x ('%c')\n", header->model,
+ header->model);
+ pr_debug("header->minor = %d\n", header->minor);
+ pr_debug("header->bus_type = 0x%x\n", header->bus_type);
+
+
+ pr_debug("header->magic = 0x%x\n", header->magic);
+ pr_debug("header->filename = \"%.*s\"\n", CHAMELEON_FILENAME_LEN,
+ header->filename);
+
+ for_each_chameleon_cell(dtype, p) {
+ switch (dtype) {
+ case CHAMELEON_DTYPE_GENERAL:
+ ret = chameleon_parse_gdd(bus, mapbase, p);
+ if (ret < 0)
+ goto out;
+ p += sizeof(struct chameleon_gdd);
+ break;
+ case CHAMELEON_DTYPE_BRIDGE:
+ chameleon_parse_bdd(bus, mapbase, p);
+ p += sizeof(struct chameleon_bdd);
+ break;
+ case CHAMELEON_DTYPE_END:
+ break;
+ default:
+ pr_err("Invalid chameleon descriptor type 0x%x\n",
+ dtype);
+ return -EINVAL;
+ }
+ num_cells++;
+ }
+
+ if (num_cells == 0)
+ num_cells = -EINVAL;
+
+ kfree(header);
+ return num_cells;
+
+out:
+ kfree(header);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(chameleon_parse_cells);
diff --git a/drivers/mcb/mcb-pci.c b/drivers/mcb/mcb-pci.c
new file mode 100644
index 000000000000..99c742cbfb5b
--- /dev/null
+++ b/drivers/mcb/mcb-pci.c
@@ -0,0 +1,114 @@
+/*
+ * MEN Chameleon Bus.
+ *
+ * Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de)
+ * Author: Johannes Thumshirn <johannes.thumshirn@men.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/mcb.h>
+
+#include "mcb-internal.h"
+
+struct priv {
+ struct mcb_bus *bus;
+ void __iomem *base;
+};
+
+static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct priv *priv;
+ phys_addr_t mapbase;
+ int ret;
+ int num_cells;
+ unsigned long flags;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to enable PCI device\n");
+ return -ENODEV;
+ }
+
+ mapbase = pci_resource_start(pdev, 0);
+ if (!mapbase) {
+ dev_err(&pdev->dev, "No PCI resource\n");
+ goto err_start;
+ }
+
+ ret = pci_request_region(pdev, 0, KBUILD_MODNAME);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request PCI BARs\n");
+ goto err_start;
+ }
+
+ priv->base = pci_iomap(pdev, 0, 0);
+ if (!priv->base) {
+ dev_err(&pdev->dev, "Cannot ioremap\n");
+ ret = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ flags = pci_resource_flags(pdev, 0);
+ if (flags & IORESOURCE_IO) {
+ ret = -ENOTSUPP;
+ dev_err(&pdev->dev,
+ "IO mapped PCI devices are not supported\n");
+ goto err_ioremap;
+ }
+
+ pci_set_drvdata(pdev, priv);
+
+ priv->bus = mcb_alloc_bus();
+
+ ret = chameleon_parse_cells(priv->bus, mapbase, priv->base);
+ if (ret < 0)
+ goto err_drvdata;
+ num_cells = ret;
+
+ dev_dbg(&pdev->dev, "Found %d cells\n", num_cells);
+
+ mcb_bus_add_devices(priv->bus);
+
+err_drvdata:
+ pci_iounmap(pdev, priv->base);
+err_ioremap:
+ pci_release_region(pdev, 0);
+err_start:
+ pci_disable_device(pdev);
+ return ret;
+}
+
+static void mcb_pci_remove(struct pci_dev *pdev)
+{
+ struct priv *priv = pci_get_drvdata(pdev);
+
+ mcb_release_bus(priv->bus);
+}
+
+static const struct pci_device_id mcb_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_MEN, PCI_DEVICE_ID_MEN_CHAMELEON) },
+ { 0 },
+};
+MODULE_DEVICE_TABLE(pci, mcb_pci_tbl);
+
+static struct pci_driver mcb_pci_driver = {
+ .name = "mcb-pci",
+ .id_table = mcb_pci_tbl,
+ .probe = mcb_pci_probe,
+ .remove = mcb_pci_remove,
+};
+
+module_pci_driver(mcb_pci_driver);
+
+MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MCB over PCI support");
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 9a06fe883766..95ad936e6048 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -254,16 +254,6 @@ config DM_THIN_PROVISIONING
---help---
Provides thin provisioning and snapshots that share a data store.
-config DM_DEBUG_BLOCK_STACK_TRACING
- boolean "Keep stack trace of persistent data block lock holders"
- depends on STACKTRACE_SUPPORT && DM_PERSISTENT_DATA
- select STACKTRACE
- ---help---
- Enable this for messages that may help debug problems with the
- block manager locking used by thin provisioning and caching.
-
- If unsure, say N.
-
config DM_CACHE
tristate "Cache target (EXPERIMENTAL)"
depends on BLK_DEV_DM
diff --git a/drivers/md/bcache/Kconfig b/drivers/md/bcache/Kconfig
index 2638417b19aa..4d200883c505 100644
--- a/drivers/md/bcache/Kconfig
+++ b/drivers/md/bcache/Kconfig
@@ -24,11 +24,3 @@ config BCACHE_CLOSURES_DEBUG
Keeps all active closures in a linked list and provides a debugfs
interface to list them, which makes it possible to see asynchronous
operations that get stuck.
-
-# cgroup code needs to be updated:
-#
-#config CGROUP_BCACHE
-# bool "Cgroup controls for bcache"
-# depends on BCACHE && BLK_CGROUP
-# ---help---
-# TODO
diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c
index c0d37d082443..443d03fbac47 100644
--- a/drivers/md/bcache/alloc.c
+++ b/drivers/md/bcache/alloc.c
@@ -78,12 +78,6 @@ uint8_t bch_inc_gen(struct cache *ca, struct bucket *b)
ca->set->need_gc = max(ca->set->need_gc, bucket_gc_gen(b));
WARN_ON_ONCE(ca->set->need_gc > BUCKET_GC_GEN_MAX);
- if (CACHE_SYNC(&ca->set->sb)) {
- ca->need_save_prio = max(ca->need_save_prio,
- bucket_disk_gen(b));
- WARN_ON_ONCE(ca->need_save_prio > BUCKET_DISK_GEN_MAX);
- }
-
return ret;
}
@@ -120,51 +114,45 @@ void bch_rescale_priorities(struct cache_set *c, int sectors)
mutex_unlock(&c->bucket_lock);
}
-/* Allocation */
+/*
+ * Background allocation thread: scans for buckets to be invalidated,
+ * invalidates them, rewrites prios/gens (marking them as invalidated on disk),
+ * then optionally issues discard commands to the newly free buckets, then puts
+ * them on the various freelists.
+ */
static inline bool can_inc_bucket_gen(struct bucket *b)
{
- return bucket_gc_gen(b) < BUCKET_GC_GEN_MAX &&
- bucket_disk_gen(b) < BUCKET_DISK_GEN_MAX;
+ return bucket_gc_gen(b) < BUCKET_GC_GEN_MAX;
}
-bool bch_bucket_add_unused(struct cache *ca, struct bucket *b)
+bool bch_can_invalidate_bucket(struct cache *ca, struct bucket *b)
{
- BUG_ON(GC_MARK(b) || GC_SECTORS_USED(b));
-
- if (CACHE_REPLACEMENT(&ca->sb) == CACHE_REPLACEMENT_FIFO) {
- unsigned i;
-
- for (i = 0; i < RESERVE_NONE; i++)
- if (!fifo_full(&ca->free[i]))
- goto add;
+ BUG_ON(!ca->set->gc_mark_valid);
- return false;
- }
-add:
- b->prio = 0;
-
- if (can_inc_bucket_gen(b) &&
- fifo_push(&ca->unused, b - ca->buckets)) {
- atomic_inc(&b->pin);
- return true;
- }
-
- return false;
-}
-
-static bool can_invalidate_bucket(struct cache *ca, struct bucket *b)
-{
- return GC_MARK(b) == GC_MARK_RECLAIMABLE &&
+ return (!GC_MARK(b) ||
+ GC_MARK(b) == GC_MARK_RECLAIMABLE) &&
!atomic_read(&b->pin) &&
can_inc_bucket_gen(b);
}
-static void invalidate_one_bucket(struct cache *ca, struct bucket *b)
+void __bch_invalidate_one_bucket(struct cache *ca, struct bucket *b)
{
+ lockdep_assert_held(&ca->set->bucket_lock);
+ BUG_ON(GC_MARK(b) && GC_MARK(b) != GC_MARK_RECLAIMABLE);
+
+ if (GC_SECTORS_USED(b))
+ trace_bcache_invalidate(ca, b - ca->buckets);
+
bch_inc_gen(ca, b);
b->prio = INITIAL_PRIO;
atomic_inc(&b->pin);
+}
+
+static void bch_invalidate_one_bucket(struct cache *ca, struct bucket *b)
+{
+ __bch_invalidate_one_bucket(ca, b);
+
fifo_push(&ca->free_inc, b - ca->buckets);
}
@@ -195,20 +183,7 @@ static void invalidate_buckets_lru(struct cache *ca)
ca->heap.used = 0;
for_each_bucket(b, ca) {
- /*
- * If we fill up the unused list, if we then return before
- * adding anything to the free_inc list we'll skip writing
- * prios/gens and just go back to allocating from the unused
- * list:
- */
- if (fifo_full(&ca->unused))
- return;
-
- if (!can_invalidate_bucket(ca, b))
- continue;
-
- if (!GC_SECTORS_USED(b) &&
- bch_bucket_add_unused(ca, b))
+ if (!bch_can_invalidate_bucket(ca, b))
continue;
if (!heap_full(&ca->heap))
@@ -233,7 +208,7 @@ static void invalidate_buckets_lru(struct cache *ca)
return;
}
- invalidate_one_bucket(ca, b);
+ bch_invalidate_one_bucket(ca, b);
}
}
@@ -249,8 +224,8 @@ static void invalidate_buckets_fifo(struct cache *ca)
b = ca->buckets + ca->fifo_last_bucket++;
- if (can_invalidate_bucket(ca, b))
- invalidate_one_bucket(ca, b);
+ if (bch_can_invalidate_bucket(ca, b))
+ bch_invalidate_one_bucket(ca, b);
if (++checked >= ca->sb.nbuckets) {
ca->invalidate_needs_gc = 1;
@@ -274,8 +249,8 @@ static void invalidate_buckets_random(struct cache *ca)
b = ca->buckets + n;
- if (can_invalidate_bucket(ca, b))
- invalidate_one_bucket(ca, b);
+ if (bch_can_invalidate_bucket(ca, b))
+ bch_invalidate_one_bucket(ca, b);
if (++checked >= ca->sb.nbuckets / 2) {
ca->invalidate_needs_gc = 1;
@@ -287,8 +262,7 @@ static void invalidate_buckets_random(struct cache *ca)
static void invalidate_buckets(struct cache *ca)
{
- if (ca->invalidate_needs_gc)
- return;
+ BUG_ON(ca->invalidate_needs_gc);
switch (CACHE_REPLACEMENT(&ca->sb)) {
case CACHE_REPLACEMENT_LRU:
@@ -301,8 +275,6 @@ static void invalidate_buckets(struct cache *ca)
invalidate_buckets_random(ca);
break;
}
-
- trace_bcache_alloc_invalidate(ca);
}
#define allocator_wait(ca, cond) \
@@ -350,17 +322,10 @@ static int bch_allocator_thread(void *arg)
* possibly issue discards to them, then we add the bucket to
* the free list:
*/
- while (1) {
+ while (!fifo_empty(&ca->free_inc)) {
long bucket;
- if ((!atomic_read(&ca->set->prio_blocked) ||
- !CACHE_SYNC(&ca->set->sb)) &&
- !fifo_empty(&ca->unused))
- fifo_pop(&ca->unused, bucket);
- else if (!fifo_empty(&ca->free_inc))
- fifo_pop(&ca->free_inc, bucket);
- else
- break;
+ fifo_pop(&ca->free_inc, bucket);
if (ca->discard) {
mutex_unlock(&ca->set->bucket_lock);
@@ -371,6 +336,7 @@ static int bch_allocator_thread(void *arg)
}
allocator_wait(ca, bch_allocator_push(ca, bucket));
+ wake_up(&ca->set->btree_cache_wait);
wake_up(&ca->set->bucket_wait);
}
@@ -380,9 +346,9 @@ static int bch_allocator_thread(void *arg)
* them to the free_inc list:
*/
+retry_invalidate:
allocator_wait(ca, ca->set->gc_mark_valid &&
- (ca->need_save_prio > 64 ||
- !ca->invalidate_needs_gc));
+ !ca->invalidate_needs_gc);
invalidate_buckets(ca);
/*
@@ -390,13 +356,28 @@ static int bch_allocator_thread(void *arg)
* new stuff to them:
*/
allocator_wait(ca, !atomic_read(&ca->set->prio_blocked));
- if (CACHE_SYNC(&ca->set->sb) &&
- (!fifo_empty(&ca->free_inc) ||
- ca->need_save_prio > 64))
+ if (CACHE_SYNC(&ca->set->sb)) {
+ /*
+ * This could deadlock if an allocation with a btree
+ * node locked ever blocked - having the btree node
+ * locked would block garbage collection, but here we're
+ * waiting on garbage collection before we invalidate
+ * and free anything.
+ *
+ * But this should be safe since the btree code always
+ * uses btree_check_reserve() before allocating now, and
+ * if it fails it blocks without btree nodes locked.
+ */
+ if (!fifo_full(&ca->free_inc))
+ goto retry_invalidate;
+
bch_prio_write(ca);
+ }
}
}
+/* Allocation */
+
long bch_bucket_alloc(struct cache *ca, unsigned reserve, bool wait)
{
DEFINE_WAIT(w);
@@ -408,8 +389,10 @@ long bch_bucket_alloc(struct cache *ca, unsigned reserve, bool wait)
fifo_pop(&ca->free[reserve], r))
goto out;
- if (!wait)
+ if (!wait) {
+ trace_bcache_alloc_fail(ca, reserve);
return -1;
+ }
do {
prepare_to_wait(&ca->set->bucket_wait, &w,
@@ -425,6 +408,8 @@ long bch_bucket_alloc(struct cache *ca, unsigned reserve, bool wait)
out:
wake_up_process(ca->alloc_thread);
+ trace_bcache_alloc(ca, reserve);
+
if (expensive_debug_checks(ca->set)) {
size_t iter;
long i;
@@ -438,8 +423,6 @@ out:
BUG_ON(i == r);
fifo_for_each(i, &ca->free_inc, iter)
BUG_ON(i == r);
- fifo_for_each(i, &ca->unused, iter)
- BUG_ON(i == r);
}
b = ca->buckets + r;
@@ -461,17 +444,19 @@ out:
return r;
}
+void __bch_bucket_free(struct cache *ca, struct bucket *b)
+{
+ SET_GC_MARK(b, 0);
+ SET_GC_SECTORS_USED(b, 0);
+}
+
void bch_bucket_free(struct cache_set *c, struct bkey *k)
{
unsigned i;
- for (i = 0; i < KEY_PTRS(k); i++) {
- struct bucket *b = PTR_BUCKET(c, k, i);
-
- SET_GC_MARK(b, GC_MARK_RECLAIMABLE);
- SET_GC_SECTORS_USED(b, 0);
- bch_bucket_add_unused(PTR_CACHE(c, k, i), b);
- }
+ for (i = 0; i < KEY_PTRS(k); i++)
+ __bch_bucket_free(PTR_CACHE(c, k, i),
+ PTR_BUCKET(c, k, i));
}
int __bch_bucket_alloc_set(struct cache_set *c, unsigned reserve,
@@ -709,25 +694,3 @@ int bch_cache_allocator_start(struct cache *ca)
ca->alloc_thread = k;
return 0;
}
-
-int bch_cache_allocator_init(struct cache *ca)
-{
- /*
- * Reserve:
- * Prio/gen writes first
- * Then 8 for btree allocations
- * Then half for the moving garbage collector
- */
-#if 0
- ca->watermark[WATERMARK_PRIO] = 0;
-
- ca->watermark[WATERMARK_METADATA] = prio_buckets(ca);
-
- ca->watermark[WATERMARK_MOVINGGC] = 8 +
- ca->watermark[WATERMARK_METADATA];
-
- ca->watermark[WATERMARK_NONE] = ca->free.size / 2 +
- ca->watermark[WATERMARK_MOVINGGC];
-#endif
- return 0;
-}
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index 0c707e4f4eaf..82c9c5d35251 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -195,9 +195,7 @@ struct bucket {
atomic_t pin;
uint16_t prio;
uint8_t gen;
- uint8_t disk_gen;
uint8_t last_gc; /* Most out of date gen in the btree */
- uint8_t gc_gen;
uint16_t gc_mark; /* Bitfield used by GC. See below for field */
};
@@ -207,10 +205,12 @@ struct bucket {
*/
BITMASK(GC_MARK, struct bucket, gc_mark, 0, 2);
-#define GC_MARK_RECLAIMABLE 0
-#define GC_MARK_DIRTY 1
-#define GC_MARK_METADATA 2
-BITMASK(GC_SECTORS_USED, struct bucket, gc_mark, 2, 13);
+#define GC_MARK_RECLAIMABLE 1
+#define GC_MARK_DIRTY 2
+#define GC_MARK_METADATA 3
+#define GC_SECTORS_USED_SIZE 13
+#define MAX_GC_SECTORS_USED (~(~0ULL << GC_SECTORS_USED_SIZE))
+BITMASK(GC_SECTORS_USED, struct bucket, gc_mark, 2, GC_SECTORS_USED_SIZE);
BITMASK(GC_MOVE, struct bucket, gc_mark, 15, 1);
#include "journal.h"
@@ -424,14 +424,9 @@ struct cache {
* their new gen to disk. After prio_write() finishes writing the new
* gens/prios, they'll be moved to the free list (and possibly discarded
* in the process)
- *
- * unused: GC found nothing pointing into these buckets (possibly
- * because all the data they contained was overwritten), so we only
- * need to discard them before they can be moved to the free list.
*/
DECLARE_FIFO(long, free)[RESERVE_NR];
DECLARE_FIFO(long, free_inc);
- DECLARE_FIFO(long, unused);
size_t fifo_last_bucket;
@@ -441,12 +436,6 @@ struct cache {
DECLARE_HEAP(struct bucket *, heap);
/*
- * max(gen - disk_gen) for all buckets. When it gets too big we have to
- * call prio_write() to keep gens from wrapping.
- */
- uint8_t need_save_prio;
-
- /*
* If nonzero, we know we aren't going to find any buckets to invalidate
* until a gc finishes - otherwise we could pointlessly burn a ton of
* cpu
@@ -560,19 +549,16 @@ struct cache_set {
struct list_head btree_cache_freed;
/* Number of elements in btree_cache + btree_cache_freeable lists */
- unsigned bucket_cache_used;
+ unsigned btree_cache_used;
/*
* If we need to allocate memory for a new btree node and that
* allocation fails, we can cannibalize another node in the btree cache
- * to satisfy the allocation. However, only one thread can be doing this
- * at a time, for obvious reasons - try_harder and try_wait are
- * basically a lock for this that we can wait on asynchronously. The
- * btree_root() macro releases the lock when it returns.
+ * to satisfy the allocation - lock to guarantee only one thread does
+ * this at a time:
*/
- struct task_struct *try_harder;
- wait_queue_head_t try_wait;
- uint64_t try_harder_start;
+ wait_queue_head_t btree_cache_wait;
+ struct task_struct *btree_cache_alloc_lock;
/*
* When we free a btree node, we increment the gen of the bucket the
@@ -601,7 +587,7 @@ struct cache_set {
uint16_t min_prio;
/*
- * max(gen - gc_gen) for all buckets. When it gets too big we have to gc
+ * max(gen - last_gc) for all buckets. When it gets too big we have to gc
* to keep gens from wrapping around.
*/
uint8_t need_gc;
@@ -626,6 +612,8 @@ struct cache_set {
/* Number of moving GC bios in flight */
struct semaphore moving_in_flight;
+ struct workqueue_struct *moving_gc_wq;
+
struct btree *root;
#ifdef CONFIG_BCACHE_DEBUG
@@ -665,7 +653,6 @@ struct cache_set {
struct time_stats btree_gc_time;
struct time_stats btree_split_time;
struct time_stats btree_read_time;
- struct time_stats try_harder_time;
atomic_long_t cache_read_races;
atomic_long_t writeback_keys_done;
@@ -848,9 +835,6 @@ static inline bool cached_dev_get(struct cached_dev *dc)
/*
* bucket_gc_gen() returns the difference between the bucket's current gen and
* the oldest gen of any pointer into that bucket in the btree (last_gc).
- *
- * bucket_disk_gen() returns the difference between the current gen and the gen
- * on disk; they're both used to make sure gens don't wrap around.
*/
static inline uint8_t bucket_gc_gen(struct bucket *b)
@@ -858,13 +842,7 @@ static inline uint8_t bucket_gc_gen(struct bucket *b)
return b->gen - b->last_gc;
}
-static inline uint8_t bucket_disk_gen(struct bucket *b)
-{
- return b->gen - b->disk_gen;
-}
-
#define BUCKET_GC_GEN_MAX 96U
-#define BUCKET_DISK_GEN_MAX 64U
#define kobj_attribute_write(n, fn) \
static struct kobj_attribute ksysfs_##n = __ATTR(n, S_IWUSR, NULL, fn)
@@ -897,11 +875,14 @@ 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 *);
-long bch_bucket_alloc(struct cache *, unsigned, bool);
+bool bch_can_invalidate_bucket(struct cache *, struct bucket *);
+void __bch_invalidate_one_bucket(struct cache *, struct bucket *);
+
+void __bch_bucket_free(struct cache *, struct bucket *);
void bch_bucket_free(struct cache_set *, struct bkey *);
+long bch_bucket_alloc(struct cache *, unsigned, bool);
int __bch_bucket_alloc_set(struct cache_set *, unsigned,
struct bkey *, int, bool);
int bch_bucket_alloc_set(struct cache_set *, unsigned,
@@ -952,13 +933,10 @@ int bch_open_buckets_alloc(struct cache_set *);
void bch_open_buckets_free(struct cache_set *);
int bch_cache_allocator_start(struct cache *ca);
-int bch_cache_allocator_init(struct cache *ca);
void bch_debug_exit(void);
int bch_debug_init(struct kobject *);
void bch_request_exit(void);
int bch_request_init(void);
-void bch_btree_exit(void);
-int bch_btree_init(void);
#endif /* _BCACHE_H */
diff --git a/drivers/md/bcache/bset.c b/drivers/md/bcache/bset.c
index 4f6b5940e609..545416415305 100644
--- a/drivers/md/bcache/bset.c
+++ b/drivers/md/bcache/bset.c
@@ -23,8 +23,8 @@ void bch_dump_bset(struct btree_keys *b, struct bset *i, unsigned set)
for (k = i->start; k < bset_bkey_last(i); k = next) {
next = bkey_next(k);
- printk(KERN_ERR "block %u key %zi/%u: ", set,
- (uint64_t *) k - i->d, i->keys);
+ printk(KERN_ERR "block %u key %u/%u: ", set,
+ (unsigned) ((u64 *) k - i->d), i->keys);
if (b->ops->key_dump)
b->ops->key_dump(b, k);
@@ -1185,9 +1185,12 @@ static void __btree_sort(struct btree_keys *b, struct btree_iter *iter,
struct bset *out = (void *) __get_free_pages(__GFP_NOWARN|GFP_NOIO,
order);
if (!out) {
+ struct page *outp;
+
BUG_ON(order > state->page_order);
- out = page_address(mempool_alloc(state->pool, GFP_NOIO));
+ outp = mempool_alloc(state->pool, GFP_NOIO);
+ out = page_address(outp);
used_mempool = true;
order = state->page_order;
}
diff --git a/drivers/md/bcache/bset.h b/drivers/md/bcache/bset.h
index 003260f4ddf6..5f6728d5d4dd 100644
--- a/drivers/md/bcache/bset.h
+++ b/drivers/md/bcache/bset.h
@@ -478,6 +478,12 @@ static inline void bch_keylist_init(struct keylist *l)
l->top_p = l->keys_p = l->inline_keys;
}
+static inline void bch_keylist_init_single(struct keylist *l, struct bkey *k)
+{
+ l->keys = k;
+ l->top = bkey_next(k);
+}
+
static inline void bch_keylist_push(struct keylist *l)
{
l->top = bkey_next(l->top);
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
index 98cc0a810a36..7347b6100961 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -68,15 +68,11 @@
* alloc_bucket() cannot fail. This should be true but is not completely
* obvious.
*
- * Make sure all allocations get charged to the root cgroup
- *
* Plugging?
*
* If data write is less than hard sector size of ssd, round up offset in open
* bucket to the next whole sector
*
- * Also lookup by cgroup in get_open_bucket()
- *
* Superblock needs to be fleshed out for multiple cache devices
*
* Add a sysfs tunable for the number of writeback IOs in flight
@@ -97,8 +93,6 @@
#define PTR_HASH(c, k) \
(((k)->ptr[0] >> c->bucket_bits) | PTR_GEN(k, 0))
-static struct workqueue_struct *btree_io_wq;
-
#define insert_lock(s, b) ((b)->level <= (s)->lock)
/*
@@ -123,7 +117,7 @@ static struct workqueue_struct *btree_io_wq;
({ \
int _r, l = (b)->level - 1; \
bool _w = l <= (op)->lock; \
- struct btree *_child = bch_btree_node_get((b)->c, key, l, _w); \
+ struct btree *_child = bch_btree_node_get((b)->c, op, key, l, _w);\
if (!IS_ERR(_child)) { \
_child->parent = (b); \
_r = bch_btree_ ## fn(_child, op, ##__VA_ARGS__); \
@@ -152,17 +146,12 @@ static struct workqueue_struct *btree_io_wq;
_r = bch_btree_ ## fn(_b, op, ##__VA_ARGS__); \
} \
rw_unlock(_w, _b); \
+ bch_cannibalize_unlock(c); \
if (_r == -EINTR) \
schedule(); \
- bch_cannibalize_unlock(c); \
- if (_r == -ENOSPC) { \
- wait_event((c)->try_wait, \
- !(c)->try_harder); \
- _r = -EINTR; \
- } \
} while (_r == -EINTR); \
\
- finish_wait(&(c)->bucket_wait, &(op)->wait); \
+ finish_wait(&(c)->btree_cache_wait, &(op)->wait); \
_r; \
})
@@ -171,6 +160,20 @@ static inline struct bset *write_block(struct btree *b)
return ((void *) btree_bset_first(b)) + b->written * block_bytes(b->c);
}
+static void bch_btree_init_next(struct btree *b)
+{
+ /* If not a leaf node, always sort */
+ if (b->level && b->keys.nsets)
+ bch_btree_sort(&b->keys, &b->c->sort);
+ else
+ bch_btree_sort_lazy(&b->keys, &b->c->sort);
+
+ if (b->written < btree_blocks(b))
+ bch_bset_init_next(&b->keys, write_block(b),
+ bset_magic(&b->c->sb));
+
+}
+
/* Btree key manipulation */
void bkey_put(struct cache_set *c, struct bkey *k)
@@ -352,8 +355,7 @@ static void __btree_node_write_done(struct closure *cl)
btree_complete_write(b, w);
if (btree_node_dirty(b))
- queue_delayed_work(btree_io_wq, &b->work,
- msecs_to_jiffies(30000));
+ schedule_delayed_work(&b->work, 30 * HZ);
closure_return_with_destructor(cl, btree_node_write_unlock);
}
@@ -442,10 +444,12 @@ static void do_btree_node_write(struct btree *b)
}
}
-void bch_btree_node_write(struct btree *b, struct closure *parent)
+void __bch_btree_node_write(struct btree *b, struct closure *parent)
{
struct bset *i = btree_bset_last(b);
+ lockdep_assert_held(&b->write_lock);
+
trace_bcache_btree_write(b);
BUG_ON(current->bio_list);
@@ -469,23 +473,24 @@ void bch_btree_node_write(struct btree *b, struct closure *parent)
&PTR_CACHE(b->c, &b->key, 0)->btree_sectors_written);
b->written += set_blocks(i, block_bytes(b->c));
+}
- /* If not a leaf node, always sort */
- if (b->level && b->keys.nsets)
- bch_btree_sort(&b->keys, &b->c->sort);
- else
- bch_btree_sort_lazy(&b->keys, &b->c->sort);
+void bch_btree_node_write(struct btree *b, struct closure *parent)
+{
+ unsigned nsets = b->keys.nsets;
+
+ lockdep_assert_held(&b->lock);
+
+ __bch_btree_node_write(b, parent);
/*
* do verify if there was more than one set initially (i.e. we did a
* sort) and we sorted down to a single set:
*/
- if (i != b->keys.set->data && !b->keys.nsets)
+ if (nsets && !b->keys.nsets)
bch_btree_verify(b);
- if (b->written < btree_blocks(b))
- bch_bset_init_next(&b->keys, write_block(b),
- bset_magic(&b->c->sb));
+ bch_btree_init_next(b);
}
static void bch_btree_node_write_sync(struct btree *b)
@@ -493,7 +498,11 @@ static void bch_btree_node_write_sync(struct btree *b)
struct closure cl;
closure_init_stack(&cl);
+
+ mutex_lock(&b->write_lock);
bch_btree_node_write(b, &cl);
+ mutex_unlock(&b->write_lock);
+
closure_sync(&cl);
}
@@ -501,11 +510,10 @@ static void btree_node_write_work(struct work_struct *w)
{
struct btree *b = container_of(to_delayed_work(w), struct btree, work);
- rw_lock(true, b, b->level);
-
+ mutex_lock(&b->write_lock);
if (btree_node_dirty(b))
- bch_btree_node_write(b, NULL);
- rw_unlock(true, b);
+ __bch_btree_node_write(b, NULL);
+ mutex_unlock(&b->write_lock);
}
static void bch_btree_leaf_dirty(struct btree *b, atomic_t *journal_ref)
@@ -513,11 +521,13 @@ static void bch_btree_leaf_dirty(struct btree *b, atomic_t *journal_ref)
struct bset *i = btree_bset_last(b);
struct btree_write *w = btree_current_write(b);
+ lockdep_assert_held(&b->write_lock);
+
BUG_ON(!b->written);
BUG_ON(!i->keys);
if (!btree_node_dirty(b))
- queue_delayed_work(btree_io_wq, &b->work, 30 * HZ);
+ schedule_delayed_work(&b->work, 30 * HZ);
set_btree_node_dirty(b);
@@ -548,7 +558,7 @@ static void bch_btree_leaf_dirty(struct btree *b, atomic_t *journal_ref)
#define mca_reserve(c) (((c->root && c->root->level) \
? c->root->level : 1) * 8 + 16)
#define mca_can_free(c) \
- max_t(int, 0, c->bucket_cache_used - mca_reserve(c))
+ max_t(int, 0, c->btree_cache_used - mca_reserve(c))
static void mca_data_free(struct btree *b)
{
@@ -556,7 +566,7 @@ static void mca_data_free(struct btree *b)
bch_btree_keys_free(&b->keys);
- b->c->bucket_cache_used--;
+ b->c->btree_cache_used--;
list_move(&b->list, &b->c->btree_cache_freed);
}
@@ -581,7 +591,7 @@ static void mca_data_alloc(struct btree *b, struct bkey *k, gfp_t gfp)
ilog2(b->c->btree_pages),
btree_order(k)),
gfp)) {
- b->c->bucket_cache_used++;
+ b->c->btree_cache_used++;
list_move(&b->list, &b->c->btree_cache);
} else {
list_move(&b->list, &b->c->btree_cache_freed);
@@ -597,6 +607,8 @@ static struct btree *mca_bucket_alloc(struct cache_set *c,
init_rwsem(&b->lock);
lockdep_set_novalidate_class(&b->lock);
+ mutex_init(&b->write_lock);
+ lockdep_set_novalidate_class(&b->write_lock);
INIT_LIST_HEAD(&b->list);
INIT_DELAYED_WORK(&b->work, btree_node_write_work);
b->c = c;
@@ -630,8 +642,12 @@ static int mca_reap(struct btree *b, unsigned min_order, bool flush)
up(&b->io_mutex);
}
+ mutex_lock(&b->write_lock);
if (btree_node_dirty(b))
- bch_btree_node_write_sync(b);
+ __bch_btree_node_write(b, &cl);
+ mutex_unlock(&b->write_lock);
+
+ closure_sync(&cl);
/* wait for any in flight btree write */
down(&b->io_mutex);
@@ -654,7 +670,7 @@ static unsigned long bch_mca_scan(struct shrinker *shrink,
if (c->shrinker_disabled)
return SHRINK_STOP;
- if (c->try_harder)
+ if (c->btree_cache_alloc_lock)
return SHRINK_STOP;
/* Return -1 if we can't do anything right now */
@@ -686,7 +702,7 @@ static unsigned long bch_mca_scan(struct shrinker *shrink,
}
}
- for (i = 0; (nr--) && i < c->bucket_cache_used; i++) {
+ for (i = 0; (nr--) && i < c->btree_cache_used; i++) {
if (list_empty(&c->btree_cache))
goto out;
@@ -715,7 +731,7 @@ static unsigned long bch_mca_count(struct shrinker *shrink,
if (c->shrinker_disabled)
return 0;
- if (c->try_harder)
+ if (c->btree_cache_alloc_lock)
return 0;
return mca_can_free(c) * c->btree_pages;
@@ -819,17 +835,30 @@ out:
return b;
}
-static struct btree *mca_cannibalize(struct cache_set *c, struct bkey *k)
+static int mca_cannibalize_lock(struct cache_set *c, struct btree_op *op)
+{
+ struct task_struct *old;
+
+ old = cmpxchg(&c->btree_cache_alloc_lock, NULL, current);
+ if (old && old != current) {
+ if (op)
+ prepare_to_wait(&c->btree_cache_wait, &op->wait,
+ TASK_UNINTERRUPTIBLE);
+ return -EINTR;
+ }
+
+ return 0;
+}
+
+static struct btree *mca_cannibalize(struct cache_set *c, struct btree_op *op,
+ struct bkey *k)
{
struct btree *b;
trace_bcache_btree_cache_cannibalize(c);
- if (!c->try_harder) {
- c->try_harder = current;
- c->try_harder_start = local_clock();
- } else if (c->try_harder != current)
- return ERR_PTR(-ENOSPC);
+ if (mca_cannibalize_lock(c, op))
+ return ERR_PTR(-EINTR);
list_for_each_entry_reverse(b, &c->btree_cache, list)
if (!mca_reap(b, btree_order(k), false))
@@ -839,6 +868,7 @@ static struct btree *mca_cannibalize(struct cache_set *c, struct bkey *k)
if (!mca_reap(b, btree_order(k), true))
return b;
+ WARN(1, "btree cache cannibalize failed\n");
return ERR_PTR(-ENOMEM);
}
@@ -850,14 +880,14 @@ static struct btree *mca_cannibalize(struct cache_set *c, struct bkey *k)
*/
static void bch_cannibalize_unlock(struct cache_set *c)
{
- if (c->try_harder == current) {
- bch_time_stats_update(&c->try_harder_time, c->try_harder_start);
- c->try_harder = NULL;
- wake_up(&c->try_wait);
+ if (c->btree_cache_alloc_lock == current) {
+ c->btree_cache_alloc_lock = NULL;
+ wake_up(&c->btree_cache_wait);
}
}
-static struct btree *mca_alloc(struct cache_set *c, struct bkey *k, int level)
+static struct btree *mca_alloc(struct cache_set *c, struct btree_op *op,
+ struct bkey *k, int level)
{
struct btree *b;
@@ -920,7 +950,7 @@ err:
if (b)
rw_unlock(true, b);
- b = mca_cannibalize(c, k);
+ b = mca_cannibalize(c, op, k);
if (!IS_ERR(b))
goto out;
@@ -936,8 +966,8 @@ err:
* The btree node will have either a read or a write lock held, depending on
* level and op->lock.
*/
-struct btree *bch_btree_node_get(struct cache_set *c, struct bkey *k,
- int level, bool write)
+struct btree *bch_btree_node_get(struct cache_set *c, struct btree_op *op,
+ struct bkey *k, int level, bool write)
{
int i = 0;
struct btree *b;
@@ -951,7 +981,7 @@ retry:
return ERR_PTR(-EAGAIN);
mutex_lock(&c->bucket_lock);
- b = mca_alloc(c, k, level);
+ b = mca_alloc(c, op, k, level);
mutex_unlock(&c->bucket_lock);
if (!b)
@@ -997,7 +1027,7 @@ static void btree_node_prefetch(struct cache_set *c, struct bkey *k, int level)
struct btree *b;
mutex_lock(&c->bucket_lock);
- b = mca_alloc(c, k, level);
+ b = mca_alloc(c, NULL, k, level);
mutex_unlock(&c->bucket_lock);
if (!IS_ERR_OR_NULL(b)) {
@@ -1010,46 +1040,41 @@ static void btree_node_prefetch(struct cache_set *c, struct bkey *k, int level)
static void btree_node_free(struct btree *b)
{
- unsigned i;
-
trace_bcache_btree_node_free(b);
BUG_ON(b == b->c->root);
+ mutex_lock(&b->write_lock);
+
if (btree_node_dirty(b))
btree_complete_write(b, btree_current_write(b));
clear_bit(BTREE_NODE_dirty, &b->flags);
+ mutex_unlock(&b->write_lock);
+
cancel_delayed_work(&b->work);
mutex_lock(&b->c->bucket_lock);
-
- for (i = 0; i < KEY_PTRS(&b->key); i++) {
- BUG_ON(atomic_read(&PTR_BUCKET(b->c, &b->key, i)->pin));
-
- bch_inc_gen(PTR_CACHE(b->c, &b->key, i),
- PTR_BUCKET(b->c, &b->key, i));
- }
-
bch_bucket_free(b->c, &b->key);
mca_bucket_free(b);
mutex_unlock(&b->c->bucket_lock);
}
-struct btree *bch_btree_node_alloc(struct cache_set *c, int level, bool wait)
+struct btree *bch_btree_node_alloc(struct cache_set *c, struct btree_op *op,
+ int level)
{
BKEY_PADDED(key) k;
struct btree *b = ERR_PTR(-EAGAIN);
mutex_lock(&c->bucket_lock);
retry:
- if (__bch_bucket_alloc_set(c, RESERVE_BTREE, &k.key, 1, wait))
+ if (__bch_bucket_alloc_set(c, RESERVE_BTREE, &k.key, 1, op != NULL))
goto err;
bkey_put(c, &k.key);
SET_KEY_SIZE(&k.key, c->btree_pages * PAGE_SECTORS);
- b = mca_alloc(c, &k.key, level);
+ b = mca_alloc(c, op, &k.key, level);
if (IS_ERR(b))
goto err_free;
@@ -1075,12 +1100,15 @@ err:
return b;
}
-static struct btree *btree_node_alloc_replacement(struct btree *b, bool wait)
+static struct btree *btree_node_alloc_replacement(struct btree *b,
+ struct btree_op *op)
{
- struct btree *n = bch_btree_node_alloc(b->c, b->level, wait);
+ struct btree *n = bch_btree_node_alloc(b->c, op, b->level);
if (!IS_ERR_OR_NULL(n)) {
+ mutex_lock(&n->write_lock);
bch_btree_sort_into(&b->keys, &n->keys, &b->c->sort);
bkey_copy_key(&n->key, &b->key);
+ mutex_unlock(&n->write_lock);
}
return n;
@@ -1090,43 +1118,47 @@ static void make_btree_freeing_key(struct btree *b, struct bkey *k)
{
unsigned i;
+ mutex_lock(&b->c->bucket_lock);
+
+ atomic_inc(&b->c->prio_blocked);
+
bkey_copy(k, &b->key);
bkey_copy_key(k, &ZERO_KEY);
- for (i = 0; i < KEY_PTRS(k); i++) {
- uint8_t g = PTR_BUCKET(b->c, k, i)->gen + 1;
-
- SET_PTR_GEN(k, i, g);
- }
+ for (i = 0; i < KEY_PTRS(k); i++)
+ SET_PTR_GEN(k, i,
+ bch_inc_gen(PTR_CACHE(b->c, &b->key, i),
+ PTR_BUCKET(b->c, &b->key, i)));
- atomic_inc(&b->c->prio_blocked);
+ mutex_unlock(&b->c->bucket_lock);
}
static int btree_check_reserve(struct btree *b, struct btree_op *op)
{
struct cache_set *c = b->c;
struct cache *ca;
- unsigned i, reserve = c->root->level * 2 + 1;
- int ret = 0;
+ unsigned i, reserve = (c->root->level - b->level) * 2 + 1;
mutex_lock(&c->bucket_lock);
for_each_cache(ca, c, i)
if (fifo_used(&ca->free[RESERVE_BTREE]) < reserve) {
if (op)
- prepare_to_wait(&c->bucket_wait, &op->wait,
+ prepare_to_wait(&c->btree_cache_wait, &op->wait,
TASK_UNINTERRUPTIBLE);
- ret = -EINTR;
- break;
+ mutex_unlock(&c->bucket_lock);
+ return -EINTR;
}
mutex_unlock(&c->bucket_lock);
- return ret;
+
+ return mca_cannibalize_lock(b->c, op);
}
/* Garbage collection */
-uint8_t __bch_btree_mark_key(struct cache_set *c, int level, struct bkey *k)
+static uint8_t __bch_btree_mark_key(struct cache_set *c, int level,
+ struct bkey *k)
{
uint8_t stale = 0;
unsigned i;
@@ -1146,8 +1178,8 @@ uint8_t __bch_btree_mark_key(struct cache_set *c, int level, struct bkey *k)
g = PTR_BUCKET(c, k, i);
- if (gen_after(g->gc_gen, PTR_GEN(k, i)))
- g->gc_gen = PTR_GEN(k, i);
+ if (gen_after(g->last_gc, PTR_GEN(k, i)))
+ g->last_gc = PTR_GEN(k, i);
if (ptr_stale(c, k, i)) {
stale = max(stale, ptr_stale(c, k, i));
@@ -1163,11 +1195,13 @@ uint8_t __bch_btree_mark_key(struct cache_set *c, int level, struct bkey *k)
SET_GC_MARK(g, GC_MARK_METADATA);
else if (KEY_DIRTY(k))
SET_GC_MARK(g, GC_MARK_DIRTY);
+ else if (!GC_MARK(g))
+ SET_GC_MARK(g, GC_MARK_RECLAIMABLE);
/* guard against overflow */
SET_GC_SECTORS_USED(g, min_t(unsigned,
GC_SECTORS_USED(g) + KEY_SIZE(k),
- (1 << 14) - 1));
+ MAX_GC_SECTORS_USED));
BUG_ON(!GC_SECTORS_USED(g));
}
@@ -1177,6 +1211,26 @@ uint8_t __bch_btree_mark_key(struct cache_set *c, int level, struct bkey *k)
#define btree_mark_key(b, k) __bch_btree_mark_key(b->c, b->level, k)
+void bch_initial_mark_key(struct cache_set *c, int level, struct bkey *k)
+{
+ unsigned i;
+
+ for (i = 0; i < KEY_PTRS(k); i++)
+ if (ptr_available(c, k, i) &&
+ !ptr_stale(c, k, i)) {
+ struct bucket *b = PTR_BUCKET(c, k, i);
+
+ b->gen = PTR_GEN(k, i);
+
+ if (level && bkey_cmp(k, &ZERO_KEY))
+ b->prio = BTREE_PRIO;
+ else if (!level && b->prio == BTREE_PRIO)
+ b->prio = INITIAL_PRIO;
+ }
+
+ __bch_btree_mark_key(c, level, k);
+}
+
static bool btree_gc_mark_node(struct btree *b, struct gc_stat *gc)
{
uint8_t stale = 0;
@@ -1230,14 +1284,19 @@ static int bch_btree_insert_node(struct btree *, struct btree_op *,
struct keylist *, atomic_t *, struct bkey *);
static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
- struct keylist *keylist, struct gc_stat *gc,
- struct gc_merge_info *r)
+ struct gc_stat *gc, struct gc_merge_info *r)
{
unsigned i, nodes = 0, keys = 0, blocks;
struct btree *new_nodes[GC_MERGE_NODES];
+ struct keylist keylist;
struct closure cl;
struct bkey *k;
+ bch_keylist_init(&keylist);
+
+ if (btree_check_reserve(b, NULL))
+ return 0;
+
memset(new_nodes, 0, sizeof(new_nodes));
closure_init_stack(&cl);
@@ -1252,11 +1311,23 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
return 0;
for (i = 0; i < nodes; i++) {
- new_nodes[i] = btree_node_alloc_replacement(r[i].b, false);
+ new_nodes[i] = btree_node_alloc_replacement(r[i].b, NULL);
if (IS_ERR_OR_NULL(new_nodes[i]))
goto out_nocoalesce;
}
+ /*
+ * We have to check the reserve here, after we've allocated our new
+ * nodes, to make sure the insert below will succeed - we also check
+ * before as an optimization to potentially avoid a bunch of expensive
+ * allocs/sorts
+ */
+ if (btree_check_reserve(b, NULL))
+ goto out_nocoalesce;
+
+ for (i = 0; i < nodes; i++)
+ mutex_lock(&new_nodes[i]->write_lock);
+
for (i = nodes - 1; i > 0; --i) {
struct bset *n1 = btree_bset_first(new_nodes[i]);
struct bset *n2 = btree_bset_first(new_nodes[i - 1]);
@@ -1315,28 +1386,34 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
n2->keys -= keys;
- if (__bch_keylist_realloc(keylist,
+ if (__bch_keylist_realloc(&keylist,
bkey_u64s(&new_nodes[i]->key)))
goto out_nocoalesce;
bch_btree_node_write(new_nodes[i], &cl);
- bch_keylist_add(keylist, &new_nodes[i]->key);
+ bch_keylist_add(&keylist, &new_nodes[i]->key);
}
- for (i = 0; i < nodes; i++) {
- if (__bch_keylist_realloc(keylist, bkey_u64s(&r[i].b->key)))
- goto out_nocoalesce;
+ for (i = 0; i < nodes; i++)
+ mutex_unlock(&new_nodes[i]->write_lock);
- make_btree_freeing_key(r[i].b, keylist->top);
- bch_keylist_push(keylist);
- }
+ closure_sync(&cl);
/* We emptied out this node */
BUG_ON(btree_bset_first(new_nodes[0])->keys);
btree_node_free(new_nodes[0]);
rw_unlock(true, new_nodes[0]);
- closure_sync(&cl);
+ for (i = 0; i < nodes; i++) {
+ if (__bch_keylist_realloc(&keylist, bkey_u64s(&r[i].b->key)))
+ goto out_nocoalesce;
+
+ make_btree_freeing_key(r[i].b, keylist.top);
+ bch_keylist_push(&keylist);
+ }
+
+ bch_btree_insert_node(b, op, &keylist, NULL, NULL);
+ BUG_ON(!bch_keylist_empty(&keylist));
for (i = 0; i < nodes; i++) {
btree_node_free(r[i].b);
@@ -1345,22 +1422,22 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
r[i].b = new_nodes[i];
}
- bch_btree_insert_node(b, op, keylist, NULL, NULL);
- BUG_ON(!bch_keylist_empty(keylist));
-
memmove(r, r + 1, sizeof(r[0]) * (nodes - 1));
r[nodes - 1].b = ERR_PTR(-EINTR);
trace_bcache_btree_gc_coalesce(nodes);
gc->nodes--;
+ bch_keylist_free(&keylist);
+
/* Invalidated our iterator */
return -EINTR;
out_nocoalesce:
closure_sync(&cl);
+ bch_keylist_free(&keylist);
- while ((k = bch_keylist_pop(keylist)))
+ while ((k = bch_keylist_pop(&keylist)))
if (!bkey_cmp(k, &ZERO_KEY))
atomic_dec(&b->c->prio_blocked);
@@ -1372,6 +1449,42 @@ out_nocoalesce:
return 0;
}
+static int btree_gc_rewrite_node(struct btree *b, struct btree_op *op,
+ struct btree *replace)
+{
+ struct keylist keys;
+ struct btree *n;
+
+ if (btree_check_reserve(b, NULL))
+ return 0;
+
+ n = btree_node_alloc_replacement(replace, NULL);
+
+ /* recheck reserve after allocating replacement node */
+ if (btree_check_reserve(b, NULL)) {
+ btree_node_free(n);
+ rw_unlock(true, n);
+ return 0;
+ }
+
+ bch_btree_node_write_sync(n);
+
+ bch_keylist_init(&keys);
+ bch_keylist_add(&keys, &n->key);
+
+ make_btree_freeing_key(replace, keys.top);
+ bch_keylist_push(&keys);
+
+ bch_btree_insert_node(b, op, &keys, NULL, NULL);
+ BUG_ON(!bch_keylist_empty(&keys));
+
+ btree_node_free(replace);
+ rw_unlock(true, n);
+
+ /* Invalidated our iterator */
+ return -EINTR;
+}
+
static unsigned btree_gc_count_keys(struct btree *b)
{
struct bkey *k;
@@ -1387,26 +1500,23 @@ static unsigned btree_gc_count_keys(struct btree *b)
static int btree_gc_recurse(struct btree *b, struct btree_op *op,
struct closure *writes, struct gc_stat *gc)
{
- unsigned i;
int ret = 0;
bool should_rewrite;
- struct btree *n;
struct bkey *k;
- struct keylist keys;
struct btree_iter iter;
struct gc_merge_info r[GC_MERGE_NODES];
- struct gc_merge_info *last = r + GC_MERGE_NODES - 1;
+ struct gc_merge_info *i, *last = r + ARRAY_SIZE(r) - 1;
- bch_keylist_init(&keys);
bch_btree_iter_init(&b->keys, &iter, &b->c->gc_done);
- for (i = 0; i < GC_MERGE_NODES; i++)
- r[i].b = ERR_PTR(-EINTR);
+ for (i = r; i < r + ARRAY_SIZE(r); i++)
+ i->b = ERR_PTR(-EINTR);
while (1) {
k = bch_btree_iter_next_filter(&iter, &b->keys, bch_ptr_bad);
if (k) {
- r->b = bch_btree_node_get(b->c, k, b->level - 1, true);
+ r->b = bch_btree_node_get(b->c, op, k, b->level - 1,
+ true);
if (IS_ERR(r->b)) {
ret = PTR_ERR(r->b);
break;
@@ -1414,7 +1524,7 @@ static int btree_gc_recurse(struct btree *b, struct btree_op *op,
r->keys = btree_gc_count_keys(r->b);
- ret = btree_gc_coalesce(b, op, &keys, gc, r);
+ ret = btree_gc_coalesce(b, op, gc, r);
if (ret)
break;
}
@@ -1424,32 +1534,10 @@ static int btree_gc_recurse(struct btree *b, struct btree_op *op,
if (!IS_ERR(last->b)) {
should_rewrite = btree_gc_mark_node(last->b, gc);
- if (should_rewrite &&
- !btree_check_reserve(b, NULL)) {
- n = btree_node_alloc_replacement(last->b,
- false);
-
- if (!IS_ERR_OR_NULL(n)) {
- bch_btree_node_write_sync(n);
- bch_keylist_add(&keys, &n->key);
-
- make_btree_freeing_key(last->b,
- keys.top);
- bch_keylist_push(&keys);
-
- btree_node_free(last->b);
-
- bch_btree_insert_node(b, op, &keys,
- NULL, NULL);
- BUG_ON(!bch_keylist_empty(&keys));
-
- rw_unlock(true, last->b);
- last->b = n;
-
- /* Invalidated our iterator */
- ret = -EINTR;
+ if (should_rewrite) {
+ ret = btree_gc_rewrite_node(b, op, last->b);
+ if (ret)
break;
- }
}
if (last->b->level) {
@@ -1464,8 +1552,10 @@ static int btree_gc_recurse(struct btree *b, struct btree_op *op,
* Must flush leaf nodes before gc ends, since replace
* operations aren't journalled
*/
+ mutex_lock(&last->b->write_lock);
if (btree_node_dirty(last->b))
bch_btree_node_write(last->b, writes);
+ mutex_unlock(&last->b->write_lock);
rw_unlock(true, last->b);
}
@@ -1478,15 +1568,15 @@ static int btree_gc_recurse(struct btree *b, struct btree_op *op,
}
}
- for (i = 0; i < GC_MERGE_NODES; i++)
- if (!IS_ERR_OR_NULL(r[i].b)) {
- if (btree_node_dirty(r[i].b))
- bch_btree_node_write(r[i].b, writes);
- rw_unlock(true, r[i].b);
+ for (i = r; i < r + ARRAY_SIZE(r); i++)
+ if (!IS_ERR_OR_NULL(i->b)) {
+ mutex_lock(&i->b->write_lock);
+ if (btree_node_dirty(i->b))
+ bch_btree_node_write(i->b, writes);
+ mutex_unlock(&i->b->write_lock);
+ rw_unlock(true, i->b);
}
- bch_keylist_free(&keys);
-
return ret;
}
@@ -1499,10 +1589,11 @@ static int bch_btree_gc_root(struct btree *b, struct btree_op *op,
should_rewrite = btree_gc_mark_node(b, gc);
if (should_rewrite) {
- n = btree_node_alloc_replacement(b, false);
+ n = btree_node_alloc_replacement(b, NULL);
if (!IS_ERR_OR_NULL(n)) {
bch_btree_node_write_sync(n);
+
bch_btree_set_root(n);
btree_node_free(b);
rw_unlock(true, n);
@@ -1511,6 +1602,8 @@ static int bch_btree_gc_root(struct btree *b, struct btree_op *op,
}
}
+ __bch_btree_mark_key(b->c, b->level + 1, &b->key);
+
if (b->level) {
ret = btree_gc_recurse(b, op, writes, gc);
if (ret)
@@ -1538,9 +1631,9 @@ 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;
+ b->last_gc = b->gen;
if (!atomic_read(&b->pin)) {
- SET_GC_MARK(b, GC_MARK_RECLAIMABLE);
+ SET_GC_MARK(b, 0);
SET_GC_SECTORS_USED(b, 0);
}
}
@@ -1548,7 +1641,7 @@ static void btree_gc_start(struct cache_set *c)
mutex_unlock(&c->bucket_lock);
}
-size_t bch_btree_gc_finish(struct cache_set *c)
+static size_t bch_btree_gc_finish(struct cache_set *c)
{
size_t available = 0;
struct bucket *b;
@@ -1561,11 +1654,6 @@ size_t bch_btree_gc_finish(struct cache_set *c)
c->gc_mark_valid = 1;
c->need_gc = 0;
- if (c->root)
- for (i = 0; i < KEY_PTRS(&c->root->key); i++)
- SET_GC_MARK(PTR_BUCKET(c, &c->root->key, i),
- GC_MARK_METADATA);
-
for (i = 0; i < KEY_PTRS(&c->uuid_bucket); i++)
SET_GC_MARK(PTR_BUCKET(c, &c->uuid_bucket, i),
GC_MARK_METADATA);
@@ -1605,15 +1693,15 @@ size_t bch_btree_gc_finish(struct cache_set *c)
SET_GC_MARK(ca->buckets + *i, GC_MARK_METADATA);
for_each_bucket(b, ca) {
- b->last_gc = b->gc_gen;
c->need_gc = max(c->need_gc, bucket_gc_gen(b));
- if (!atomic_read(&b->pin) &&
- GC_MARK(b) == GC_MARK_RECLAIMABLE) {
+ if (atomic_read(&b->pin))
+ continue;
+
+ BUG_ON(!GC_MARK(b) && GC_SECTORS_USED(b));
+
+ if (!GC_MARK(b) || GC_MARK(b) == GC_MARK_RECLAIMABLE)
available++;
- if (!GC_SECTORS_USED(b))
- bch_bucket_add_unused(ca, b);
- }
}
}
@@ -1705,36 +1793,16 @@ int bch_gc_thread_start(struct cache_set *c)
/* Initial partial gc */
-static int bch_btree_check_recurse(struct btree *b, struct btree_op *op,
- unsigned long **seen)
+static int bch_btree_check_recurse(struct btree *b, struct btree_op *op)
{
int ret = 0;
- unsigned i;
struct bkey *k, *p = NULL;
- struct bucket *g;
struct btree_iter iter;
- for_each_key_filter(&b->keys, k, &iter, bch_ptr_invalid) {
- for (i = 0; i < KEY_PTRS(k); i++) {
- if (!ptr_available(b->c, k, i))
- continue;
-
- g = PTR_BUCKET(b->c, k, i);
+ for_each_key_filter(&b->keys, k, &iter, bch_ptr_invalid)
+ bch_initial_mark_key(b->c, b->level, k);
- if (!__test_and_set_bit(PTR_BUCKET_NR(b->c, k, i),
- seen[PTR_DEV(k, i)]) ||
- !ptr_stale(b->c, k, i)) {
- g->gen = PTR_GEN(k, i);
-
- if (b->level)
- g->prio = BTREE_PRIO;
- else if (g->prio == BTREE_PRIO)
- g->prio = INITIAL_PRIO;
- }
- }
-
- btree_mark_key(b, k);
- }
+ bch_initial_mark_key(b->c, b->level + 1, &b->key);
if (b->level) {
bch_btree_iter_init(&b->keys, &iter, NULL);
@@ -1746,40 +1814,58 @@ static int bch_btree_check_recurse(struct btree *b, struct btree_op *op,
btree_node_prefetch(b->c, k, b->level - 1);
if (p)
- ret = btree(check_recurse, p, b, op, seen);
+ ret = btree(check_recurse, p, b, op);
p = k;
} while (p && !ret);
}
- return 0;
+ return ret;
}
int bch_btree_check(struct cache_set *c)
{
- int ret = -ENOMEM;
- unsigned i;
- unsigned long *seen[MAX_CACHES_PER_SET];
struct btree_op op;
- memset(seen, 0, sizeof(seen));
bch_btree_op_init(&op, SHRT_MAX);
- for (i = 0; c->cache[i]; i++) {
- size_t n = DIV_ROUND_UP(c->cache[i]->sb.nbuckets, 8);
- seen[i] = kmalloc(n, GFP_KERNEL);
- if (!seen[i])
- goto err;
+ return btree_root(check_recurse, c, &op);
+}
+
+void bch_initial_gc_finish(struct cache_set *c)
+{
+ struct cache *ca;
+ struct bucket *b;
+ unsigned i;
+
+ bch_btree_gc_finish(c);
- /* Disables the seen array until prio_read() uses it too */
- memset(seen[i], 0xFF, n);
+ mutex_lock(&c->bucket_lock);
+
+ /*
+ * We need to put some unused buckets directly on the prio freelist in
+ * order to get the allocator thread started - it needs freed buckets in
+ * order to rewrite the prios and gens, and it needs to rewrite prios
+ * and gens in order to free buckets.
+ *
+ * This is only safe for buckets that have no live data in them, which
+ * there should always be some of.
+ */
+ for_each_cache(ca, c, i) {
+ for_each_bucket(b, ca) {
+ if (fifo_full(&ca->free[RESERVE_PRIO]))
+ break;
+
+ if (bch_can_invalidate_bucket(ca, b) &&
+ !GC_MARK(b)) {
+ __bch_invalidate_one_bucket(ca, b);
+ fifo_push(&ca->free[RESERVE_PRIO],
+ b - ca->buckets);
+ }
+ }
}
- ret = btree_root(check_recurse, c, &op, seen);
-err:
- for (i = 0; i < MAX_CACHES_PER_SET; i++)
- kfree(seen[i]);
- return ret;
+ mutex_unlock(&c->bucket_lock);
}
/* Btree insertion */
@@ -1805,7 +1891,7 @@ static bool btree_insert_key(struct btree *b, struct bkey *k,
static size_t insert_u64s_remaining(struct btree *b)
{
- ssize_t ret = bch_btree_keys_u64s_remaining(&b->keys);
+ long ret = bch_btree_keys_u64s_remaining(&b->keys);
/*
* Might land in the middle of an existing extent and have to split it
@@ -1871,11 +1957,14 @@ static int btree_split(struct btree *b, struct btree_op *op,
closure_init_stack(&cl);
bch_keylist_init(&parent_keys);
- if (!b->level &&
- btree_check_reserve(b, op))
- return -EINTR;
+ if (btree_check_reserve(b, op)) {
+ if (!b->level)
+ return -EINTR;
+ else
+ WARN(1, "insufficient reserve for split\n");
+ }
- n1 = btree_node_alloc_replacement(b, true);
+ n1 = btree_node_alloc_replacement(b, op);
if (IS_ERR(n1))
goto err;
@@ -1887,16 +1976,19 @@ static int btree_split(struct btree *b, struct btree_op *op,
trace_bcache_btree_node_split(b, btree_bset_first(n1)->keys);
- n2 = bch_btree_node_alloc(b->c, b->level, true);
+ n2 = bch_btree_node_alloc(b->c, op, b->level);
if (IS_ERR(n2))
goto err_free1;
if (!b->parent) {
- n3 = bch_btree_node_alloc(b->c, b->level + 1, true);
+ n3 = bch_btree_node_alloc(b->c, op, b->level + 1);
if (IS_ERR(n3))
goto err_free2;
}
+ mutex_lock(&n1->write_lock);
+ mutex_lock(&n2->write_lock);
+
bch_btree_insert_keys(n1, op, insert_keys, replace_key);
/*
@@ -1923,45 +2015,45 @@ static int btree_split(struct btree *b, struct btree_op *op,
bch_keylist_add(&parent_keys, &n2->key);
bch_btree_node_write(n2, &cl);
+ mutex_unlock(&n2->write_lock);
rw_unlock(true, n2);
} else {
trace_bcache_btree_node_compact(b, btree_bset_first(n1)->keys);
+ mutex_lock(&n1->write_lock);
bch_btree_insert_keys(n1, op, insert_keys, replace_key);
}
bch_keylist_add(&parent_keys, &n1->key);
bch_btree_node_write(n1, &cl);
+ mutex_unlock(&n1->write_lock);
if (n3) {
/* Depth increases, make a new root */
+ mutex_lock(&n3->write_lock);
bkey_copy_key(&n3->key, &MAX_KEY);
bch_btree_insert_keys(n3, op, &parent_keys, NULL);
bch_btree_node_write(n3, &cl);
+ mutex_unlock(&n3->write_lock);
closure_sync(&cl);
bch_btree_set_root(n3);
rw_unlock(true, n3);
-
- btree_node_free(b);
} else if (!b->parent) {
/* Root filled up but didn't need to be split */
closure_sync(&cl);
bch_btree_set_root(n1);
-
- btree_node_free(b);
} else {
/* Split a non root node */
closure_sync(&cl);
make_btree_freeing_key(b, parent_keys.top);
bch_keylist_push(&parent_keys);
- btree_node_free(b);
-
bch_btree_insert_node(b->parent, op, &parent_keys, NULL, NULL);
BUG_ON(!bch_keylist_empty(&parent_keys));
}
+ btree_node_free(b);
rw_unlock(true, n1);
bch_time_stats_update(&b->c->btree_split_time, start_time);
@@ -1976,7 +2068,7 @@ err_free1:
btree_node_free(n1);
rw_unlock(true, n1);
err:
- WARN(1, "bcache: btree split failed");
+ WARN(1, "bcache: btree split failed (level %u)", b->level);
if (n3 == ERR_PTR(-EAGAIN) ||
n2 == ERR_PTR(-EAGAIN) ||
@@ -1991,33 +2083,54 @@ static int bch_btree_insert_node(struct btree *b, struct btree_op *op,
atomic_t *journal_ref,
struct bkey *replace_key)
{
+ struct closure cl;
+
BUG_ON(b->level && replace_key);
+ closure_init_stack(&cl);
+
+ mutex_lock(&b->write_lock);
+
+ if (write_block(b) != btree_bset_last(b) &&
+ b->keys.last_set_unwritten)
+ bch_btree_init_next(b); /* just wrote a set */
+
if (bch_keylist_nkeys(insert_keys) > insert_u64s_remaining(b)) {
- if (current->bio_list) {
- op->lock = b->c->root->level + 1;
- return -EAGAIN;
- } else if (op->lock <= b->c->root->level) {
- op->lock = b->c->root->level + 1;
- return -EINTR;
- } else {
- /* Invalidated all iterators */
- int ret = btree_split(b, op, insert_keys, replace_key);
+ mutex_unlock(&b->write_lock);
+ goto split;
+ }
- return bch_keylist_empty(insert_keys) ?
- 0 : ret ?: -EINTR;
- }
- } else {
- BUG_ON(write_block(b) != btree_bset_last(b));
+ BUG_ON(write_block(b) != btree_bset_last(b));
- if (bch_btree_insert_keys(b, op, insert_keys, replace_key)) {
- if (!b->level)
- bch_btree_leaf_dirty(b, journal_ref);
- else
- bch_btree_node_write_sync(b);
- }
+ if (bch_btree_insert_keys(b, op, insert_keys, replace_key)) {
+ if (!b->level)
+ bch_btree_leaf_dirty(b, journal_ref);
+ else
+ bch_btree_node_write(b, &cl);
+ }
- return 0;
+ mutex_unlock(&b->write_lock);
+
+ /* wait for btree node write if necessary, after unlock */
+ closure_sync(&cl);
+
+ return 0;
+split:
+ if (current->bio_list) {
+ op->lock = b->c->root->level + 1;
+ return -EAGAIN;
+ } else if (op->lock <= b->c->root->level) {
+ op->lock = b->c->root->level + 1;
+ return -EINTR;
+ } else {
+ /* Invalidated all iterators */
+ int ret = btree_split(b, op, insert_keys, replace_key);
+
+ if (bch_keylist_empty(insert_keys))
+ return 0;
+ else if (!ret)
+ return -EINTR;
+ return ret;
}
}
@@ -2403,18 +2516,3 @@ void bch_keybuf_init(struct keybuf *buf)
spin_lock_init(&buf->lock);
array_allocator_init(&buf->freelist);
}
-
-void bch_btree_exit(void)
-{
- if (btree_io_wq)
- destroy_workqueue(btree_io_wq);
-}
-
-int __init bch_btree_init(void)
-{
- btree_io_wq = create_singlethread_workqueue("bch_btree_io");
- if (!btree_io_wq)
- return -ENOMEM;
-
- return 0;
-}
diff --git a/drivers/md/bcache/btree.h b/drivers/md/bcache/btree.h
index af065e97e55c..91dfa5e69685 100644
--- a/drivers/md/bcache/btree.h
+++ b/drivers/md/bcache/btree.h
@@ -127,6 +127,8 @@ struct btree {
struct cache_set *c;
struct btree *parent;
+ struct mutex write_lock;
+
unsigned long flags;
uint16_t written; /* would be nice to kill */
uint8_t level;
@@ -236,11 +238,13 @@ static inline void rw_unlock(bool w, struct btree *b)
}
void bch_btree_node_read_done(struct btree *);
+void __bch_btree_node_write(struct btree *, struct closure *);
void bch_btree_node_write(struct btree *, struct closure *);
void bch_btree_set_root(struct btree *);
-struct btree *bch_btree_node_alloc(struct cache_set *, int, bool);
-struct btree *bch_btree_node_get(struct cache_set *, struct bkey *, int, bool);
+struct btree *bch_btree_node_alloc(struct cache_set *, struct btree_op *, int);
+struct btree *bch_btree_node_get(struct cache_set *, struct btree_op *,
+ struct bkey *, int, bool);
int bch_btree_insert_check_key(struct btree *, struct btree_op *,
struct bkey *);
@@ -248,10 +252,10 @@ int bch_btree_insert(struct cache_set *, struct keylist *,
atomic_t *, struct bkey *);
int bch_gc_thread_start(struct cache_set *);
-size_t bch_btree_gc_finish(struct cache_set *);
+void bch_initial_gc_finish(struct cache_set *);
void bch_moving_gc(struct cache_set *);
int bch_btree_check(struct cache_set *);
-uint8_t __bch_btree_mark_key(struct cache_set *, int, struct bkey *);
+void bch_initial_mark_key(struct cache_set *, int, struct bkey *);
static inline void wake_up_gc(struct cache_set *c)
{
diff --git a/drivers/md/bcache/extents.c b/drivers/md/bcache/extents.c
index c3ead586dc27..3a0de4cf9771 100644
--- a/drivers/md/bcache/extents.c
+++ b/drivers/md/bcache/extents.c
@@ -194,9 +194,9 @@ err:
mutex_unlock(&b->c->bucket_lock);
bch_extent_to_text(buf, sizeof(buf), k);
btree_bug(b,
-"inconsistent btree pointer %s: bucket %li pin %i prio %i gen %i last_gc %i mark %llu gc_gen %i",
+"inconsistent btree pointer %s: bucket %zi pin %i prio %i gen %i last_gc %i mark %llu",
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);
+ g->prio, g->gen, g->last_gc, GC_MARK(g));
return true;
}
@@ -308,6 +308,16 @@ static struct bkey *bch_extent_sort_fixup(struct btree_iter *iter,
return NULL;
}
+static void bch_subtract_dirty(struct bkey *k,
+ struct cache_set *c,
+ uint64_t offset,
+ int sectors)
+{
+ if (KEY_DIRTY(k))
+ bcache_dev_sectors_dirty_add(c, KEY_INODE(k),
+ offset, -sectors);
+}
+
static bool bch_extent_insert_fixup(struct btree_keys *b,
struct bkey *insert,
struct btree_iter *iter,
@@ -315,13 +325,6 @@ static bool bch_extent_insert_fixup(struct btree_keys *b,
{
struct cache_set *c = container_of(b, struct btree, keys)->c;
- void subtract_dirty(struct bkey *k, uint64_t offset, int sectors)
- {
- if (KEY_DIRTY(k))
- bcache_dev_sectors_dirty_add(c, KEY_INODE(k),
- offset, -sectors);
- }
-
uint64_t old_offset;
unsigned old_size, sectors_found = 0;
@@ -398,7 +401,8 @@ static bool bch_extent_insert_fixup(struct btree_keys *b,
struct bkey *top;
- subtract_dirty(k, KEY_START(insert), KEY_SIZE(insert));
+ bch_subtract_dirty(k, c, KEY_START(insert),
+ KEY_SIZE(insert));
if (bkey_written(b, k)) {
/*
@@ -448,7 +452,7 @@ static bool bch_extent_insert_fixup(struct btree_keys *b,
}
}
- subtract_dirty(k, old_offset, old_size - KEY_SIZE(k));
+ bch_subtract_dirty(k, c, old_offset, old_size - KEY_SIZE(k));
}
check_failed:
@@ -499,9 +503,9 @@ static bool bch_extent_bad_expensive(struct btree *b, const struct bkey *k,
if (mutex_trylock(&b->c->bucket_lock)) {
if (b->c->gc_mark_valid &&
- ((GC_MARK(g) != GC_MARK_DIRTY &&
- KEY_DIRTY(k)) ||
- GC_MARK(g) == GC_MARK_METADATA))
+ (!GC_MARK(g) ||
+ GC_MARK(g) == GC_MARK_METADATA ||
+ (GC_MARK(g) != GC_MARK_DIRTY && KEY_DIRTY(k))))
goto err;
if (g->prio == BTREE_PRIO)
@@ -515,9 +519,9 @@ err:
mutex_unlock(&b->c->bucket_lock);
bch_extent_to_text(buf, sizeof(buf), k);
btree_bug(b,
-"inconsistent extent pointer %s:\nbucket %zu pin %i prio %i gen %i last_gc %i mark %llu gc_gen %i",
+"inconsistent extent pointer %s:\nbucket %zu pin %i prio %i gen %i last_gc %i mark %llu",
buf, PTR_BUCKET_NR(b->c, k, ptr), atomic_read(&g->pin),
- g->prio, g->gen, g->last_gc, GC_MARK(g), g->gc_gen);
+ g->prio, g->gen, g->last_gc, GC_MARK(g));
return true;
}
diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c
index 18039affc306..59e82021b5bb 100644
--- a/drivers/md/bcache/journal.c
+++ b/drivers/md/bcache/journal.c
@@ -237,8 +237,14 @@ bsearch:
for (i = 0; i < ca->sb.njournal_buckets; i++)
if (ja->seq[i] > seq) {
seq = ja->seq[i];
- ja->cur_idx = ja->discard_idx =
- ja->last_idx = i;
+ /*
+ * When journal_reclaim() goes to allocate for
+ * the first time, it'll use the bucket after
+ * ja->cur_idx
+ */
+ ja->cur_idx = i;
+ ja->last_idx = ja->discard_idx = (i + 1) %
+ ca->sb.njournal_buckets;
}
}
@@ -288,16 +294,11 @@ void bch_journal_mark(struct cache_set *c, struct list_head *list)
k = bkey_next(k)) {
unsigned j;
- for (j = 0; j < KEY_PTRS(k); j++) {
- struct bucket *g = PTR_BUCKET(c, k, j);
- atomic_inc(&g->pin);
+ for (j = 0; j < KEY_PTRS(k); j++)
+ if (ptr_available(c, k, j))
+ atomic_inc(&PTR_BUCKET(c, k, j)->pin);
- if (g->prio == BTREE_PRIO &&
- !ptr_stale(c, k, j))
- g->prio = INITIAL_PRIO;
- }
-
- __bch_btree_mark_key(c, 0, k);
+ bch_initial_mark_key(c, 0, k);
}
}
}
@@ -312,8 +313,6 @@ int bch_journal_replay(struct cache_set *s, struct list_head *list)
uint64_t start = i->j.last_seq, end = i->j.seq, n = start;
struct keylist keylist;
- bch_keylist_init(&keylist);
-
list_for_each_entry(i, list, list) {
BUG_ON(i->pin && atomic_read(i->pin) != 1);
@@ -326,8 +325,7 @@ int bch_journal_replay(struct cache_set *s, struct list_head *list)
k = bkey_next(k)) {
trace_bcache_journal_replay_key(k);
- bkey_copy(keylist.top, k);
- bch_keylist_push(&keylist);
+ bch_keylist_init_single(&keylist, k);
ret = bch_btree_insert(s, &keylist, i->pin, NULL);
if (ret)
@@ -383,16 +381,15 @@ retry:
b = best;
if (b) {
- rw_lock(true, b, b->level);
-
+ mutex_lock(&b->write_lock);
if (!btree_current_write(b)->journal) {
- rw_unlock(true, b);
+ mutex_unlock(&b->write_lock);
/* We raced */
goto retry;
}
- bch_btree_node_write(b, NULL);
- rw_unlock(true, b);
+ __bch_btree_node_write(b, NULL);
+ mutex_unlock(&b->write_lock);
}
}
@@ -536,6 +533,7 @@ void bch_journal_next(struct journal *j)
atomic_set(&fifo_back(&j->pin), 1);
j->cur->data->seq = ++j->seq;
+ j->cur->dirty = false;
j->cur->need_write = false;
j->cur->data->keys = 0;
@@ -731,7 +729,10 @@ static void journal_write_work(struct work_struct *work)
struct cache_set,
journal.work);
spin_lock(&c->journal.lock);
- journal_try_write(c);
+ if (c->journal.cur->dirty)
+ journal_try_write(c);
+ else
+ spin_unlock(&c->journal.lock);
}
/*
@@ -761,7 +762,8 @@ atomic_t *bch_journal(struct cache_set *c,
if (parent) {
closure_wait(&w->wait, parent);
journal_try_write(c);
- } else if (!w->need_write) {
+ } else if (!w->dirty) {
+ w->dirty = true;
schedule_delayed_work(&c->journal.work,
msecs_to_jiffies(c->journal_delay_ms));
spin_unlock(&c->journal.lock);
diff --git a/drivers/md/bcache/journal.h b/drivers/md/bcache/journal.h
index 9180c4465075..e3c39457afbb 100644
--- a/drivers/md/bcache/journal.h
+++ b/drivers/md/bcache/journal.h
@@ -95,6 +95,7 @@ struct journal_write {
struct cache_set *c;
struct closure_waitlist wait;
+ bool dirty;
bool need_write;
};
diff --git a/drivers/md/bcache/movinggc.c b/drivers/md/bcache/movinggc.c
index 9eb60d102de8..cd7490311e51 100644
--- a/drivers/md/bcache/movinggc.c
+++ b/drivers/md/bcache/movinggc.c
@@ -24,12 +24,10 @@ static bool moving_pred(struct keybuf *buf, struct bkey *k)
moving_gc_keys);
unsigned i;
- for (i = 0; i < KEY_PTRS(k); i++) {
- struct bucket *g = PTR_BUCKET(c, k, i);
-
- if (GC_MOVE(g))
+ for (i = 0; i < KEY_PTRS(k); i++)
+ if (ptr_available(c, k, i) &&
+ GC_MOVE(PTR_BUCKET(c, k, i)))
return true;
- }
return false;
}
@@ -115,7 +113,7 @@ static void write_moving(struct closure *cl)
closure_call(&op->cl, bch_data_insert, NULL, cl);
}
- continue_at(cl, write_moving_finish, system_wq);
+ continue_at(cl, write_moving_finish, op->wq);
}
static void read_moving_submit(struct closure *cl)
@@ -125,7 +123,7 @@ static void read_moving_submit(struct closure *cl)
bch_submit_bbio(bio, io->op.c, &io->w->key, 0);
- continue_at(cl, write_moving, system_wq);
+ continue_at(cl, write_moving, io->op.wq);
}
static void read_moving(struct cache_set *c)
@@ -160,6 +158,7 @@ static void read_moving(struct cache_set *c)
io->w = w;
io->op.inode = KEY_INODE(&w->key);
io->op.c = c;
+ io->op.wq = c->moving_gc_wq;
moving_init(io);
bio = &io->bio.bio;
@@ -216,7 +215,10 @@ void bch_moving_gc(struct cache_set *c)
ca->heap.used = 0;
for_each_bucket(b, ca) {
- if (!GC_SECTORS_USED(b))
+ if (GC_MARK(b) == GC_MARK_METADATA ||
+ !GC_SECTORS_USED(b) ||
+ GC_SECTORS_USED(b) == ca->sb.bucket_size ||
+ atomic_read(&b->pin))
continue;
if (!heap_full(&ca->heap)) {
diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
index 72cd213f213f..15fff4f68a7c 100644
--- a/drivers/md/bcache/request.c
+++ b/drivers/md/bcache/request.c
@@ -12,11 +12,9 @@
#include "request.h"
#include "writeback.h"
-#include <linux/cgroup.h>
#include <linux/module.h>
#include <linux/hash.h>
#include <linux/random.h>
-#include "blk-cgroup.h"
#include <trace/events/bcache.h>
@@ -27,171 +25,13 @@ struct kmem_cache *bch_search_cache;
static void bch_data_insert_start(struct closure *);
-/* Cgroup interface */
-
-#ifdef CONFIG_CGROUP_BCACHE
-static struct bch_cgroup bcache_default_cgroup = { .cache_mode = -1 };
-
-static struct bch_cgroup *cgroup_to_bcache(struct cgroup *cgroup)
-{
- struct cgroup_subsys_state *css;
- return cgroup &&
- (css = cgroup_subsys_state(cgroup, bcache_subsys_id))
- ? container_of(css, struct bch_cgroup, css)
- : &bcache_default_cgroup;
-}
-
-struct bch_cgroup *bch_bio_to_cgroup(struct bio *bio)
-{
- struct cgroup_subsys_state *css = bio->bi_css
- ? cgroup_subsys_state(bio->bi_css->cgroup, bcache_subsys_id)
- : task_subsys_state(current, bcache_subsys_id);
-
- return css
- ? container_of(css, struct bch_cgroup, css)
- : &bcache_default_cgroup;
-}
-
-static ssize_t cache_mode_read(struct cgroup *cgrp, struct cftype *cft,
- struct file *file,
- char __user *buf, size_t nbytes, loff_t *ppos)
-{
- char tmp[1024];
- int len = bch_snprint_string_list(tmp, PAGE_SIZE, bch_cache_modes,
- cgroup_to_bcache(cgrp)->cache_mode + 1);
-
- if (len < 0)
- return len;
-
- return simple_read_from_buffer(buf, nbytes, ppos, tmp, len);
-}
-
-static int cache_mode_write(struct cgroup *cgrp, struct cftype *cft,
- const char *buf)
-{
- int v = bch_read_string_list(buf, bch_cache_modes);
- if (v < 0)
- return v;
-
- cgroup_to_bcache(cgrp)->cache_mode = v - 1;
- return 0;
-}
-
-static u64 bch_verify_read(struct cgroup *cgrp, struct cftype *cft)
-{
- return cgroup_to_bcache(cgrp)->verify;
-}
-
-static int bch_verify_write(struct cgroup *cgrp, struct cftype *cft, u64 val)
-{
- cgroup_to_bcache(cgrp)->verify = val;
- return 0;
-}
-
-static u64 bch_cache_hits_read(struct cgroup *cgrp, struct cftype *cft)
-{
- struct bch_cgroup *bcachecg = cgroup_to_bcache(cgrp);
- return atomic_read(&bcachecg->stats.cache_hits);
-}
-
-static u64 bch_cache_misses_read(struct cgroup *cgrp, struct cftype *cft)
-{
- struct bch_cgroup *bcachecg = cgroup_to_bcache(cgrp);
- return atomic_read(&bcachecg->stats.cache_misses);
-}
-
-static u64 bch_cache_bypass_hits_read(struct cgroup *cgrp,
- struct cftype *cft)
-{
- struct bch_cgroup *bcachecg = cgroup_to_bcache(cgrp);
- return atomic_read(&bcachecg->stats.cache_bypass_hits);
-}
-
-static u64 bch_cache_bypass_misses_read(struct cgroup *cgrp,
- struct cftype *cft)
-{
- struct bch_cgroup *bcachecg = cgroup_to_bcache(cgrp);
- return atomic_read(&bcachecg->stats.cache_bypass_misses);
-}
-
-static struct cftype bch_files[] = {
- {
- .name = "cache_mode",
- .read = cache_mode_read,
- .write_string = cache_mode_write,
- },
- {
- .name = "verify",
- .read_u64 = bch_verify_read,
- .write_u64 = bch_verify_write,
- },
- {
- .name = "cache_hits",
- .read_u64 = bch_cache_hits_read,
- },
- {
- .name = "cache_misses",
- .read_u64 = bch_cache_misses_read,
- },
- {
- .name = "cache_bypass_hits",
- .read_u64 = bch_cache_bypass_hits_read,
- },
- {
- .name = "cache_bypass_misses",
- .read_u64 = bch_cache_bypass_misses_read,
- },
- { } /* terminate */
-};
-
-static void init_bch_cgroup(struct bch_cgroup *cg)
-{
- cg->cache_mode = -1;
-}
-
-static struct cgroup_subsys_state *bcachecg_create(struct cgroup *cgroup)
-{
- struct bch_cgroup *cg;
-
- cg = kzalloc(sizeof(*cg), GFP_KERNEL);
- if (!cg)
- return ERR_PTR(-ENOMEM);
- init_bch_cgroup(cg);
- return &cg->css;
-}
-
-static void bcachecg_destroy(struct cgroup *cgroup)
-{
- struct bch_cgroup *cg = cgroup_to_bcache(cgroup);
- kfree(cg);
-}
-
-struct cgroup_subsys bcache_subsys = {
- .create = bcachecg_create,
- .destroy = bcachecg_destroy,
- .subsys_id = bcache_subsys_id,
- .name = "bcache",
- .module = THIS_MODULE,
-};
-EXPORT_SYMBOL_GPL(bcache_subsys);
-#endif
-
static unsigned cache_mode(struct cached_dev *dc, struct bio *bio)
{
-#ifdef CONFIG_CGROUP_BCACHE
- int r = bch_bio_to_cgroup(bio)->cache_mode;
- if (r >= 0)
- return r;
-#endif
return BDEV_CACHE_MODE(&dc->sb);
}
static bool verify(struct cached_dev *dc, struct bio *bio)
{
-#ifdef CONFIG_CGROUP_BCACHE
- if (bch_bio_to_cgroup(bio)->verify)
- return true;
-#endif
return dc->verify;
}
@@ -248,7 +88,7 @@ static void bch_data_insert_keys(struct closure *cl)
atomic_dec_bug(journal_ref);
if (!op->insert_data_done)
- continue_at(cl, bch_data_insert_start, bcache_wq);
+ continue_at(cl, bch_data_insert_start, op->wq);
bch_keylist_free(&op->insert_keys);
closure_return(cl);
@@ -297,7 +137,7 @@ static void bch_data_invalidate(struct closure *cl)
op->insert_data_done = true;
bio_put(bio);
out:
- continue_at(cl, bch_data_insert_keys, bcache_wq);
+ continue_at(cl, bch_data_insert_keys, op->wq);
}
static void bch_data_insert_error(struct closure *cl)
@@ -340,7 +180,7 @@ static void bch_data_insert_endio(struct bio *bio, int error)
if (op->writeback)
op->error = error;
else if (!op->replace)
- set_closure_fn(cl, bch_data_insert_error, bcache_wq);
+ set_closure_fn(cl, bch_data_insert_error, op->wq);
else
set_closure_fn(cl, NULL, NULL);
}
@@ -353,14 +193,14 @@ static void bch_data_insert_start(struct closure *cl)
struct data_insert_op *op = container_of(cl, struct data_insert_op, cl);
struct bio *bio = op->bio, *n;
- if (op->bypass)
- return bch_data_invalidate(cl);
-
if (atomic_sub_return(bio_sectors(bio), &op->c->sectors_to_gc) < 0) {
set_gc_sectors(op->c);
wake_up_gc(op->c);
}
+ if (op->bypass)
+ return bch_data_invalidate(cl);
+
/*
* Journal writes are marked REQ_FLUSH; if the original write was a
* flush, it'll wait on the journal write.
@@ -376,7 +216,7 @@ static void bch_data_insert_start(struct closure *cl)
if (bch_keylist_realloc(&op->insert_keys,
3 + (op->csum ? 1 : 0),
op->c))
- continue_at(cl, bch_data_insert_keys, bcache_wq);
+ continue_at(cl, bch_data_insert_keys, op->wq);
k = op->insert_keys.top;
bkey_init(k);
@@ -413,7 +253,7 @@ static void bch_data_insert_start(struct closure *cl)
} while (n != bio);
op->insert_data_done = true;
- continue_at(cl, bch_data_insert_keys, bcache_wq);
+ continue_at(cl, bch_data_insert_keys, op->wq);
err:
/* bch_alloc_sectors() blocks if s->writeback = true */
BUG_ON(op->writeback);
@@ -442,7 +282,7 @@ err:
bio_put(bio);
if (!bch_keylist_empty(&op->insert_keys))
- continue_at(cl, bch_data_insert_keys, bcache_wq);
+ continue_at(cl, bch_data_insert_keys, op->wq);
else
closure_return(cl);
}
@@ -824,6 +664,7 @@ static inline struct search *search_alloc(struct bio *bio,
s->iop.error = 0;
s->iop.flags = 0;
s->iop.flush_journal = (bio->bi_rw & (REQ_FLUSH|REQ_FUA)) != 0;
+ s->iop.wq = bcache_wq;
return s;
}
@@ -1203,22 +1044,13 @@ 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;
- struct bvec_iter iter;
+ unsigned bytes = min(sectors, bio_sectors(bio)) << 9;
- /* Zero fill bio */
+ swap(bio->bi_iter.bi_size, bytes);
+ zero_fill_bio(bio);
+ swap(bio->bi_iter.bi_size, bytes);
- bio_for_each_segment(bv, bio, iter) {
- 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);
-
- sectors -= j;
- }
-
- bio_advance(bio, min(sectors << 9, bio->bi_iter.bi_size));
+ bio_advance(bio, bytes);
if (!bio->bi_iter.bi_size)
return MAP_DONE;
@@ -1313,9 +1145,6 @@ void bch_flash_dev_request_init(struct bcache_device *d)
void bch_request_exit(void)
{
-#ifdef CONFIG_CGROUP_BCACHE
- cgroup_unload_subsys(&bcache_subsys);
-#endif
if (bch_search_cache)
kmem_cache_destroy(bch_search_cache);
}
@@ -1326,11 +1155,5 @@ int __init bch_request_init(void)
if (!bch_search_cache)
return -ENOMEM;
-#ifdef CONFIG_CGROUP_BCACHE
- cgroup_load_subsys(&bcache_subsys);
- init_bch_cgroup(&bcache_default_cgroup);
-
- cgroup_add_cftypes(&bcache_subsys, bch_files);
-#endif
return 0;
}
diff --git a/drivers/md/bcache/request.h b/drivers/md/bcache/request.h
index 39f21dbedc38..1ff36875c2b3 100644
--- a/drivers/md/bcache/request.h
+++ b/drivers/md/bcache/request.h
@@ -1,12 +1,11 @@
#ifndef _BCACHE_REQUEST_H_
#define _BCACHE_REQUEST_H_
-#include <linux/cgroup.h>
-
struct data_insert_op {
struct closure cl;
struct cache_set *c;
struct bio *bio;
+ struct workqueue_struct *wq;
unsigned inode;
uint16_t write_point;
@@ -41,20 +40,4 @@ void bch_flash_dev_request_init(struct bcache_device *d);
extern struct kmem_cache *bch_search_cache, *bch_passthrough_cache;
-struct bch_cgroup {
-#ifdef CONFIG_CGROUP_BCACHE
- struct cgroup_subsys_state css;
-#endif
- /*
- * We subtract one from the index into bch_cache_modes[], so that
- * default == -1; this makes it so the rest match up with d->cache_mode,
- * and we use d->cache_mode if cgrp->cache_mode < 0
- */
- short cache_mode;
- bool verify;
- struct cache_stat_collector stats;
-};
-
-struct bch_cgroup *bch_bio_to_cgroup(struct bio *bio);
-
#endif /* _BCACHE_REQUEST_H_ */
diff --git a/drivers/md/bcache/stats.c b/drivers/md/bcache/stats.c
index 84d0782f702e..0ca072c20d0d 100644
--- a/drivers/md/bcache/stats.c
+++ b/drivers/md/bcache/stats.c
@@ -201,9 +201,6 @@ void bch_mark_cache_accounting(struct cache_set *c, struct bcache_device *d,
struct cached_dev *dc = container_of(d, struct cached_dev, disk);
mark_cache_stats(&dc->accounting.collector, hit, bypass);
mark_cache_stats(&c->accounting.collector, hit, bypass);
-#ifdef CONFIG_CGROUP_BCACHE
- mark_cache_stats(&(bch_bio_to_cgroup(s->orig_bio)->stats), hit, bypass);
-#endif
}
void bch_mark_cache_readahead(struct cache_set *c, struct bcache_device *d)
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 24a3a1546caa..926ded8ccbf5 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -541,9 +541,6 @@ static void prio_io(struct cache *ca, uint64_t bucket, unsigned long rw)
closure_sync(cl);
}
-#define buckets_free(c) "free %zu, free_inc %zu, unused %zu", \
- fifo_used(&c->free), fifo_used(&c->free_inc), fifo_used(&c->unused)
-
void bch_prio_write(struct cache *ca)
{
int i;
@@ -554,10 +551,6 @@ void bch_prio_write(struct cache *ca)
lockdep_assert_held(&ca->set->bucket_lock);
- for (b = ca->buckets;
- b < ca->buckets + ca->sb.nbuckets; b++)
- b->disk_gen = b->gen;
-
ca->disk_buckets->seq++;
atomic_long_add(ca->sb.bucket_size * prio_buckets(ca),
@@ -601,14 +594,17 @@ void bch_prio_write(struct cache *ca)
mutex_lock(&ca->set->bucket_lock);
- ca->need_save_prio = 0;
-
/*
* Don't want the old priorities to get garbage collected until after we
* finish writing the new ones, and they're journalled
*/
- for (i = 0; i < prio_buckets(ca); i++)
+ for (i = 0; i < prio_buckets(ca); i++) {
+ if (ca->prio_last_buckets[i])
+ __bch_bucket_free(ca,
+ &ca->buckets[ca->prio_last_buckets[i]]);
+
ca->prio_last_buckets[i] = ca->prio_buckets[i];
+ }
}
static void prio_read(struct cache *ca, uint64_t bucket)
@@ -639,7 +635,7 @@ static void prio_read(struct cache *ca, uint64_t bucket)
}
b->prio = le16_to_cpu(d->prio);
- b->gen = b->disk_gen = b->last_gc = b->gc_gen = d->gen;
+ b->gen = b->last_gc = d->gen;
}
}
@@ -843,6 +839,7 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size,
q->limits.max_segment_size = UINT_MAX;
q->limits.max_segments = BIO_MAX_PAGES;
q->limits.max_discard_sectors = UINT_MAX;
+ q->limits.discard_granularity = 512;
q->limits.io_min = block_size;
q->limits.logical_block_size = block_size;
q->limits.physical_block_size = block_size;
@@ -1355,6 +1352,8 @@ static void cache_set_free(struct closure *cl)
bch_bset_sort_state_free(&c->sort);
free_pages((unsigned long) c->uuids, ilog2(bucket_pages(c)));
+ if (c->moving_gc_wq)
+ destroy_workqueue(c->moving_gc_wq);
if (c->bio_split)
bioset_free(c->bio_split);
if (c->fill_iter)
@@ -1395,14 +1394,21 @@ static void cache_set_flush(struct closure *cl)
list_add(&c->root->list, &c->btree_cache);
/* Should skip this if we're unregistering because of an error */
- list_for_each_entry(b, &c->btree_cache, list)
+ list_for_each_entry(b, &c->btree_cache, list) {
+ mutex_lock(&b->write_lock);
if (btree_node_dirty(b))
- bch_btree_node_write(b, NULL);
+ __bch_btree_node_write(b, NULL);
+ mutex_unlock(&b->write_lock);
+ }
for_each_cache(ca, c, i)
if (ca->alloc_thread)
kthread_stop(ca->alloc_thread);
+ cancel_delayed_work_sync(&c->journal.work);
+ /* flush last journal entry if needed */
+ c->journal.work.work.func(&c->journal.work.work);
+
closure_return(cl);
}
@@ -1485,14 +1491,13 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb)
sema_init(&c->sb_write_mutex, 1);
mutex_init(&c->bucket_lock);
- init_waitqueue_head(&c->try_wait);
+ init_waitqueue_head(&c->btree_cache_wait);
init_waitqueue_head(&c->bucket_wait);
sema_init(&c->uuid_write_mutex, 1);
spin_lock_init(&c->btree_gc_time.lock);
spin_lock_init(&c->btree_split_time.lock);
spin_lock_init(&c->btree_read_time.lock);
- spin_lock_init(&c->try_harder_time.lock);
bch_moving_init_cache_set(c);
@@ -1517,6 +1522,7 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb)
!(c->fill_iter = mempool_create_kmalloc_pool(1, iter_size)) ||
!(c->bio_split = bioset_create(4, offsetof(struct bbio, bio))) ||
!(c->uuids = alloc_bucket_pages(GFP_KERNEL, c)) ||
+ !(c->moving_gc_wq = create_workqueue("bcache_gc")) ||
bch_journal_alloc(c) ||
bch_btree_cache_alloc(c) ||
bch_open_buckets_alloc(c) ||
@@ -1580,7 +1586,7 @@ static void run_cache_set(struct cache_set *c)
goto err;
err = "error reading btree root";
- c->root = bch_btree_node_get(c, k, j->btree_level, true);
+ c->root = bch_btree_node_get(c, NULL, k, j->btree_level, true);
if (IS_ERR_OR_NULL(c->root))
goto err;
@@ -1596,7 +1602,7 @@ static void run_cache_set(struct cache_set *c)
goto err;
bch_journal_mark(c, &journal);
- bch_btree_gc_finish(c);
+ bch_initial_gc_finish(c);
pr_debug("btree_check() done");
/*
@@ -1638,7 +1644,7 @@ static void run_cache_set(struct cache_set *c)
ca->sb.d[j] = ca->sb.first_bucket + j;
}
- bch_btree_gc_finish(c);
+ bch_initial_gc_finish(c);
err = "error starting allocator thread";
for_each_cache(ca, c, i)
@@ -1655,12 +1661,14 @@ static void run_cache_set(struct cache_set *c)
goto err;
err = "cannot allocate new btree root";
- c->root = bch_btree_node_alloc(c, 0, true);
+ c->root = bch_btree_node_alloc(c, NULL, 0);
if (IS_ERR_OR_NULL(c->root))
goto err;
+ mutex_lock(&c->root->write_lock);
bkey_copy_key(&c->root->key, &MAX_KEY);
bch_btree_node_write(c->root, &cl);
+ mutex_unlock(&c->root->write_lock);
bch_btree_set_root(c->root);
rw_unlock(true, c->root);
@@ -1782,7 +1790,6 @@ void bch_cache_release(struct kobject *kobj)
vfree(ca->buckets);
free_heap(&ca->heap);
- free_fifo(&ca->unused);
free_fifo(&ca->free_inc);
for (i = 0; i < RESERVE_NR; i++)
@@ -1819,7 +1826,6 @@ static int cache_alloc(struct cache_sb *sb, struct cache *ca)
!init_fifo(&ca->free[RESERVE_MOVINGGC], free, GFP_KERNEL) ||
!init_fifo(&ca->free[RESERVE_NONE], free, GFP_KERNEL) ||
!init_fifo(&ca->free_inc, free << 2, GFP_KERNEL) ||
- !init_fifo(&ca->unused, free << 2, GFP_KERNEL) ||
!init_heap(&ca->heap, free << 3, GFP_KERNEL) ||
!(ca->buckets = vzalloc(sizeof(struct bucket) *
ca->sb.nbuckets)) ||
@@ -1834,13 +1840,7 @@ static int cache_alloc(struct cache_sb *sb, struct cache *ca)
for_each_bucket(b, ca)
atomic_set(&b->pin, 0);
- if (bch_cache_allocator_init(ca))
- goto err;
-
return 0;
-err:
- kobject_put(&ca->kobj);
- return -ENOMEM;
}
static void register_cache(struct cache_sb *sb, struct page *sb_page,
@@ -1869,7 +1869,10 @@ static void register_cache(struct cache_sb *sb, struct page *sb_page,
if (kobject_add(&ca->kobj, &part_to_dev(bdev->bd_part)->kobj, "bcache"))
goto err;
+ mutex_lock(&bch_register_lock);
err = register_cache_set(ca);
+ mutex_unlock(&bch_register_lock);
+
if (err)
goto err;
@@ -1931,8 +1934,6 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
if (!try_module_get(THIS_MODULE))
return -EBUSY;
- mutex_lock(&bch_register_lock);
-
if (!(path = kstrndup(buffer, size, GFP_KERNEL)) ||
!(sb = kmalloc(sizeof(struct cache_sb), GFP_KERNEL)))
goto err;
@@ -1965,7 +1966,9 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
if (!dc)
goto err_close;
+ mutex_lock(&bch_register_lock);
register_bdev(sb, sb_page, bdev, dc);
+ mutex_unlock(&bch_register_lock);
} else {
struct cache *ca = kzalloc(sizeof(*ca), GFP_KERNEL);
if (!ca)
@@ -1978,7 +1981,6 @@ out:
put_page(sb_page);
kfree(sb);
kfree(path);
- mutex_unlock(&bch_register_lock);
module_put(THIS_MODULE);
return ret;
@@ -2057,7 +2059,6 @@ static void bcache_exit(void)
{
bch_debug_exit();
bch_request_exit();
- bch_btree_exit();
if (bcache_kobj)
kobject_put(bcache_kobj);
if (bcache_wq)
@@ -2087,7 +2088,6 @@ static int __init bcache_init(void)
if (!(bcache_wq = create_workqueue("bcache")) ||
!(bcache_kobj = kobject_create_and_add("bcache", fs_kobj)) ||
sysfs_create_files(bcache_kobj, files) ||
- bch_btree_init() ||
bch_request_init() ||
bch_debug_init(bcache_kobj))
goto err;
diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c
index c6ab69333a6d..b3ff57d61dde 100644
--- a/drivers/md/bcache/sysfs.c
+++ b/drivers/md/bcache/sysfs.c
@@ -54,7 +54,6 @@ sysfs_time_stats_attribute(btree_gc, sec, ms);
sysfs_time_stats_attribute(btree_split, sec, us);
sysfs_time_stats_attribute(btree_sort, ms, us);
sysfs_time_stats_attribute(btree_read, ms, us);
-sysfs_time_stats_attribute(try_harder, ms, us);
read_attribute(btree_nodes);
read_attribute(btree_used_percent);
@@ -406,7 +405,7 @@ struct bset_stats_op {
struct bset_stats stats;
};
-static int btree_bset_stats(struct btree_op *b_op, struct btree *b)
+static int bch_btree_bset_stats(struct btree_op *b_op, struct btree *b)
{
struct bset_stats_op *op = container_of(b_op, struct bset_stats_op, op);
@@ -416,7 +415,7 @@ static int btree_bset_stats(struct btree_op *b_op, struct btree *b)
return MAP_CONTINUE;
}
-int bch_bset_print_stats(struct cache_set *c, char *buf)
+static int bch_bset_print_stats(struct cache_set *c, char *buf)
{
struct bset_stats_op op;
int ret;
@@ -424,7 +423,7 @@ int bch_bset_print_stats(struct cache_set *c, char *buf)
memset(&op, 0, sizeof(op));
bch_btree_op_init(&op.op, -1);
- ret = bch_btree_map_nodes(&op.op, c, &ZERO_KEY, btree_bset_stats);
+ ret = bch_btree_map_nodes(&op.op, c, &ZERO_KEY, bch_btree_bset_stats);
if (ret < 0)
return ret;
@@ -442,81 +441,81 @@ int bch_bset_print_stats(struct cache_set *c, char *buf)
op.stats.floats, op.stats.failed);
}
-SHOW(__bch_cache_set)
+static unsigned bch_root_usage(struct cache_set *c)
{
- unsigned root_usage(struct cache_set *c)
- {
- unsigned bytes = 0;
- struct bkey *k;
- struct btree *b;
- struct btree_iter iter;
+ unsigned bytes = 0;
+ struct bkey *k;
+ struct btree *b;
+ struct btree_iter iter;
- goto lock_root;
+ goto lock_root;
- do {
- rw_unlock(false, b);
+ do {
+ rw_unlock(false, b);
lock_root:
- b = c->root;
- rw_lock(false, b, b->level);
- } while (b != c->root);
+ b = c->root;
+ rw_lock(false, b, b->level);
+ } while (b != c->root);
- for_each_key_filter(&b->keys, k, &iter, bch_ptr_bad)
- bytes += bkey_bytes(k);
+ for_each_key_filter(&b->keys, k, &iter, bch_ptr_bad)
+ bytes += bkey_bytes(k);
- rw_unlock(false, b);
+ rw_unlock(false, b);
- return (bytes * 100) / btree_bytes(c);
- }
+ return (bytes * 100) / btree_bytes(c);
+}
- size_t cache_size(struct cache_set *c)
- {
- size_t ret = 0;
- struct btree *b;
+static size_t bch_cache_size(struct cache_set *c)
+{
+ size_t ret = 0;
+ struct btree *b;
- mutex_lock(&c->bucket_lock);
- list_for_each_entry(b, &c->btree_cache, list)
- ret += 1 << (b->keys.page_order + PAGE_SHIFT);
+ mutex_lock(&c->bucket_lock);
+ list_for_each_entry(b, &c->btree_cache, list)
+ ret += 1 << (b->keys.page_order + PAGE_SHIFT);
- mutex_unlock(&c->bucket_lock);
- return ret;
- }
-
- unsigned cache_max_chain(struct cache_set *c)
- {
- unsigned ret = 0;
- struct hlist_head *h;
+ mutex_unlock(&c->bucket_lock);
+ return ret;
+}
- mutex_lock(&c->bucket_lock);
+static unsigned bch_cache_max_chain(struct cache_set *c)
+{
+ unsigned ret = 0;
+ struct hlist_head *h;
- for (h = c->bucket_hash;
- h < c->bucket_hash + (1 << BUCKET_HASH_BITS);
- h++) {
- unsigned i = 0;
- struct hlist_node *p;
+ mutex_lock(&c->bucket_lock);
- hlist_for_each(p, h)
- i++;
+ for (h = c->bucket_hash;
+ h < c->bucket_hash + (1 << BUCKET_HASH_BITS);
+ h++) {
+ unsigned i = 0;
+ struct hlist_node *p;
- ret = max(ret, i);
- }
+ hlist_for_each(p, h)
+ i++;
- mutex_unlock(&c->bucket_lock);
- return ret;
+ ret = max(ret, i);
}
- unsigned btree_used(struct cache_set *c)
- {
- return div64_u64(c->gc_stats.key_bytes * 100,
- (c->gc_stats.nodes ?: 1) * btree_bytes(c));
- }
+ mutex_unlock(&c->bucket_lock);
+ return ret;
+}
- unsigned average_key_size(struct cache_set *c)
- {
- return c->gc_stats.nkeys
- ? div64_u64(c->gc_stats.data, c->gc_stats.nkeys)
- : 0;
- }
+static unsigned bch_btree_used(struct cache_set *c)
+{
+ return div64_u64(c->gc_stats.key_bytes * 100,
+ (c->gc_stats.nodes ?: 1) * btree_bytes(c));
+}
+static unsigned bch_average_key_size(struct cache_set *c)
+{
+ return c->gc_stats.nkeys
+ ? div64_u64(c->gc_stats.data, c->gc_stats.nkeys)
+ : 0;
+}
+
+SHOW(__bch_cache_set)
+{
struct cache_set *c = container_of(kobj, struct cache_set, kobj);
sysfs_print(synchronous, CACHE_SYNC(&c->sb));
@@ -524,21 +523,20 @@ lock_root:
sysfs_hprint(bucket_size, bucket_bytes(c));
sysfs_hprint(block_size, block_bytes(c));
sysfs_print(tree_depth, c->root->level);
- sysfs_print(root_usage_percent, root_usage(c));
+ sysfs_print(root_usage_percent, bch_root_usage(c));
- sysfs_hprint(btree_cache_size, cache_size(c));
- sysfs_print(btree_cache_max_chain, cache_max_chain(c));
+ sysfs_hprint(btree_cache_size, bch_cache_size(c));
+ sysfs_print(btree_cache_max_chain, bch_cache_max_chain(c));
sysfs_print(cache_available_percent, 100 - c->gc_stats.in_use);
sysfs_print_time_stats(&c->btree_gc_time, btree_gc, sec, ms);
sysfs_print_time_stats(&c->btree_split_time, btree_split, sec, us);
sysfs_print_time_stats(&c->sort.time, btree_sort, ms, us);
sysfs_print_time_stats(&c->btree_read_time, btree_read, ms, us);
- sysfs_print_time_stats(&c->try_harder_time, try_harder, ms, us);
- sysfs_print(btree_used_percent, btree_used(c));
+ sysfs_print(btree_used_percent, bch_btree_used(c));
sysfs_print(btree_nodes, c->gc_stats.nodes);
- sysfs_hprint(average_key_size, average_key_size(c));
+ sysfs_hprint(average_key_size, bch_average_key_size(c));
sysfs_print(cache_read_races,
atomic_long_read(&c->cache_read_races));
@@ -709,7 +707,6 @@ static struct attribute *bch_cache_set_internal_files[] = {
sysfs_time_stats_attribute_list(btree_split, sec, us)
sysfs_time_stats_attribute_list(btree_sort, ms, us)
sysfs_time_stats_attribute_list(btree_read, ms, us)
- sysfs_time_stats_attribute_list(try_harder, ms, us)
&sysfs_btree_nodes,
&sysfs_btree_used_percent,
@@ -761,7 +758,9 @@ SHOW(__bch_cache)
int cmp(const void *l, const void *r)
{ return *((uint16_t *) r) - *((uint16_t *) l); }
- size_t n = ca->sb.nbuckets, i, unused, btree;
+ struct bucket *b;
+ size_t n = ca->sb.nbuckets, i;
+ size_t unused = 0, available = 0, dirty = 0, meta = 0;
uint64_t sum = 0;
/* Compute 31 quantiles */
uint16_t q[31], *p, *cached;
@@ -772,6 +771,17 @@ SHOW(__bch_cache)
return -ENOMEM;
mutex_lock(&ca->set->bucket_lock);
+ for_each_bucket(b, ca) {
+ if (!GC_SECTORS_USED(b))
+ unused++;
+ if (GC_MARK(b) == GC_MARK_RECLAIMABLE)
+ available++;
+ if (GC_MARK(b) == GC_MARK_DIRTY)
+ dirty++;
+ if (GC_MARK(b) == GC_MARK_METADATA)
+ meta++;
+ }
+
for (i = ca->sb.first_bucket; i < n; i++)
p[i] = ca->buckets[i].prio;
mutex_unlock(&ca->set->bucket_lock);
@@ -786,10 +796,7 @@ SHOW(__bch_cache)
while (cached < p + n &&
*cached == BTREE_PRIO)
- cached++;
-
- btree = cached - p;
- n -= btree;
+ cached++, n--;
for (i = 0; i < n; i++)
sum += INITIAL_PRIO - cached[i];
@@ -805,12 +812,16 @@ SHOW(__bch_cache)
ret = scnprintf(buf, PAGE_SIZE,
"Unused: %zu%%\n"
+ "Clean: %zu%%\n"
+ "Dirty: %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,
+ available * 100 / (size_t) ca->sb.nbuckets,
+ dirty * 100 / (size_t) ca->sb.nbuckets,
+ meta * 100 / (size_t) ca->sb.nbuckets, sum,
n * ca->sb.bucket_size / (ARRAY_SIZE(q) + 1));
for (i = 0; i < ARRAY_SIZE(q); i++)
diff --git a/drivers/md/bcache/trace.c b/drivers/md/bcache/trace.c
index adbc3df17a80..b7820b0d2621 100644
--- a/drivers/md/bcache/trace.c
+++ b/drivers/md/bcache/trace.c
@@ -45,7 +45,7 @@ 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_invalidate);
EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_alloc_fail);
EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_writeback);
diff --git a/drivers/md/dm-cache-policy-mq.c b/drivers/md/dm-cache-policy-mq.c
index 1e018e986610..0e385e40909e 100644
--- a/drivers/md/dm-cache-policy-mq.c
+++ b/drivers/md/dm-cache-policy-mq.c
@@ -872,7 +872,7 @@ static void mq_destroy(struct dm_cache_policy *p)
{
struct mq_policy *mq = to_mq_policy(p);
- kfree(mq->table);
+ vfree(mq->table);
epool_exit(&mq->cache_pool);
epool_exit(&mq->pre_cache_pool);
kfree(mq);
@@ -1245,7 +1245,7 @@ static struct dm_cache_policy *mq_create(dm_cblock_t cache_size,
mq->nr_buckets = next_power(from_cblock(cache_size) / 2, 16);
mq->hash_bits = ffs(mq->nr_buckets) - 1;
- mq->table = kzalloc(sizeof(*mq->table) * mq->nr_buckets, GFP_KERNEL);
+ mq->table = vzalloc(sizeof(*mq->table) * mq->nr_buckets);
if (!mq->table)
goto bad_alloc_table;
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index ffd472e015ca..074b9c8e4cf0 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -289,6 +289,7 @@ struct per_bio_data {
bool tick:1;
unsigned req_nr:2;
struct dm_deferred_entry *all_io_entry;
+ struct dm_hook_info hook_info;
/*
* writethrough fields. These MUST remain at the end of this
@@ -297,7 +298,6 @@ struct per_bio_data {
*/
struct cache *cache;
dm_cblock_t cblock;
- struct dm_hook_info hook_info;
struct dm_bio_details bio_details;
};
@@ -671,15 +671,16 @@ static void remap_to_cache(struct cache *cache, struct bio *bio,
dm_cblock_t cblock)
{
sector_t bi_sector = bio->bi_iter.bi_sector;
+ sector_t block = from_cblock(cblock);
bio->bi_bdev = cache->cache_dev->bdev;
if (!block_size_is_power_of_two(cache))
bio->bi_iter.bi_sector =
- (from_cblock(cblock) * cache->sectors_per_block) +
+ (block * cache->sectors_per_block) +
sector_div(bi_sector, cache->sectors_per_block);
else
bio->bi_iter.bi_sector =
- (from_cblock(cblock) << cache->sectors_per_block_shift) |
+ (block << cache->sectors_per_block_shift) |
(bi_sector & (cache->sectors_per_block - 1));
}
@@ -978,12 +979,13 @@ static void issue_copy_real(struct dm_cache_migration *mg)
int r;
struct dm_io_region o_region, c_region;
struct cache *cache = mg->cache;
+ sector_t cblock = from_cblock(mg->cblock);
o_region.bdev = cache->origin_dev->bdev;
o_region.count = cache->sectors_per_block;
c_region.bdev = cache->cache_dev->bdev;
- c_region.sector = from_cblock(mg->cblock) * cache->sectors_per_block;
+ c_region.sector = cblock * cache->sectors_per_block;
c_region.count = cache->sectors_per_block;
if (mg->writeback || mg->demote) {
@@ -1010,13 +1012,15 @@ static void overwrite_endio(struct bio *bio, int err)
struct per_bio_data *pb = get_per_bio_data(bio, pb_data_size);
unsigned long flags;
+ dm_unhook_bio(&pb->hook_info, bio);
+
if (err)
mg->err = true;
+ mg->requeue_holder = false;
+
spin_lock_irqsave(&cache->lock, flags);
list_add_tail(&mg->list, &cache->completed_migrations);
- dm_unhook_bio(&pb->hook_info, bio);
- mg->requeue_holder = false;
spin_unlock_irqrestore(&cache->lock, flags);
wake_worker(cache);
@@ -2461,20 +2465,18 @@ static int cache_map(struct dm_target *ti, struct bio *bio)
bool discarded_block;
struct dm_bio_prison_cell *cell;
struct policy_result lookup_result;
- struct per_bio_data *pb;
+ struct per_bio_data *pb = init_per_bio_data(bio, pb_data_size);
- if (from_oblock(block) > from_oblock(cache->origin_blocks)) {
+ if (unlikely(from_oblock(block) >= from_oblock(cache->origin_blocks))) {
/*
* This can only occur if the io goes to a partial block at
* the end of the origin device. We don't cache these.
* Just remap to the origin and carry on.
*/
- remap_to_origin_clear_discard(cache, bio, block);
+ remap_to_origin(cache, bio);
return DM_MAPIO_REMAPPED;
}
- pb = init_per_bio_data(bio, pb_data_size);
-
if (bio->bi_rw & (REQ_FLUSH | REQ_FUA | REQ_DISCARD)) {
defer_bio(cache, bio);
return DM_MAPIO_SUBMITTED;
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index b2b8a10e8427..3842ac738f98 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -201,29 +201,28 @@ static void list_dp_init(struct dpages *dp, struct page_list *pl, unsigned offse
/*
* Functions for getting the pages from a bvec.
*/
-static void bio_get_page(struct dpages *dp,
- struct page **p, unsigned long *len, unsigned *offset)
+static void bio_get_page(struct dpages *dp, struct page **p,
+ unsigned long *len, unsigned *offset)
{
- struct bio *bio = dp->context_ptr;
- struct bio_vec bvec = bio_iovec(bio);
- *p = bvec.bv_page;
- *len = bvec.bv_len;
- *offset = bvec.bv_offset;
+ struct bio_vec *bvec = dp->context_ptr;
+ *p = bvec->bv_page;
+ *len = bvec->bv_len - dp->context_u;
+ *offset = bvec->bv_offset + dp->context_u;
}
static void bio_next_page(struct dpages *dp)
{
- struct bio *bio = dp->context_ptr;
- struct bio_vec bvec = bio_iovec(bio);
-
- bio_advance(bio, bvec.bv_len);
+ struct bio_vec *bvec = dp->context_ptr;
+ dp->context_ptr = bvec + 1;
+ dp->context_u = 0;
}
static void bio_dp_init(struct dpages *dp, struct bio *bio)
{
dp->get_page = bio_get_page;
dp->next_page = bio_next_page;
- dp->context_ptr = bio;
+ dp->context_ptr = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter);
+ dp->context_u = bio->bi_iter.bi_bvec_done;
}
/*
diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm-log-userspace-transfer.c
index 08d9a207259a..b428c0ae63d5 100644
--- a/drivers/md/dm-log-userspace-transfer.c
+++ b/drivers/md/dm-log-userspace-transfer.c
@@ -66,7 +66,7 @@ static int dm_ulog_sendto_server(struct dm_ulog_request *tfr)
msg->seq = tfr->seq;
msg->len = sizeof(struct dm_ulog_request) + tfr->data_size;
- r = cn_netlink_send(msg, 0, gfp_any());
+ r = cn_netlink_send(msg, 0, 0, gfp_any());
return r;
}
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 6eb9dc9ef8f3..422a9fdeb53e 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -1626,8 +1626,11 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
/*
* Only pass ioctls through if the device sizes match exactly.
*/
- if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT)
- r = scsi_verify_blk_ioctl(NULL, cmd);
+ if (!bdev || ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) {
+ int err = scsi_verify_blk_ioctl(NULL, cmd);
+ if (err)
+ r = err;
+ }
if (r == -ENOTCONN && !fatal_signal_pending(current))
queue_work(kmultipathd, &m->process_queued_ios);
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index f284e0bfb25f..7dfdb5c746d6 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -1244,6 +1244,9 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error)
dm_bio_restore(bd, bio);
bio_record->details.bi_bdev = NULL;
+
+ atomic_inc(&bio->bi_remaining);
+
queue_bio(ms, bio, rw);
return DM_ENDIO_INCOMPLETE;
}
diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c
index afc3d017de4c..d6e88178d22c 100644
--- a/drivers/md/dm-snap-persistent.c
+++ b/drivers/md/dm-snap-persistent.c
@@ -546,6 +546,9 @@ static int read_exceptions(struct pstore *ps,
r = insert_exceptions(ps, area, callback, callback_context,
&full);
+ if (!full)
+ memcpy(ps->area, area, ps->store->chunk_size << SECTOR_SHIFT);
+
dm_bufio_release(bp);
dm_bufio_forget(client, chunk);
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index 7da347665552..fb9efc829182 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -76,7 +76,7 @@
#define THIN_SUPERBLOCK_MAGIC 27022010
#define THIN_SUPERBLOCK_LOCATION 0
-#define THIN_VERSION 1
+#define THIN_VERSION 2
#define THIN_METADATA_CACHE_SIZE 64
#define SECTOR_TO_BLOCK_SHIFT 3
@@ -483,7 +483,7 @@ static int __write_initial_superblock(struct dm_pool_metadata *pmd)
disk_super->data_mapping_root = cpu_to_le64(pmd->root);
disk_super->device_details_root = cpu_to_le64(pmd->details_root);
- disk_super->metadata_block_size = cpu_to_le32(THIN_METADATA_BLOCK_SIZE >> SECTOR_SHIFT);
+ disk_super->metadata_block_size = cpu_to_le32(THIN_METADATA_BLOCK_SIZE);
disk_super->metadata_nr_blocks = cpu_to_le64(bdev_size >> SECTOR_TO_BLOCK_SHIFT);
disk_super->data_block_size = cpu_to_le32(pmd->data_block_size);
@@ -651,7 +651,7 @@ static int __create_persistent_data_objects(struct dm_pool_metadata *pmd, bool f
{
int r;
- pmd->bm = dm_block_manager_create(pmd->bdev, THIN_METADATA_BLOCK_SIZE,
+ pmd->bm = dm_block_manager_create(pmd->bdev, THIN_METADATA_BLOCK_SIZE << SECTOR_SHIFT,
THIN_METADATA_CACHE_SIZE,
THIN_MAX_CONCURRENT_LOCKS);
if (IS_ERR(pmd->bm)) {
@@ -1489,6 +1489,23 @@ bool dm_thin_changed_this_transaction(struct dm_thin_device *td)
return r;
}
+bool dm_pool_changed_this_transaction(struct dm_pool_metadata *pmd)
+{
+ bool r = false;
+ struct dm_thin_device *td, *tmp;
+
+ down_read(&pmd->root_lock);
+ list_for_each_entry_safe(td, tmp, &pmd->thin_devices, list) {
+ if (td->changed) {
+ r = td->changed;
+ break;
+ }
+ }
+ up_read(&pmd->root_lock);
+
+ return r;
+}
+
bool dm_thin_aborted_changes(struct dm_thin_device *td)
{
bool r;
@@ -1738,3 +1755,38 @@ int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
return r;
}
+
+int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd)
+{
+ int r;
+ struct dm_block *sblock;
+ struct thin_disk_superblock *disk_super;
+
+ down_write(&pmd->root_lock);
+ pmd->flags |= THIN_METADATA_NEEDS_CHECK_FLAG;
+
+ r = superblock_lock(pmd, &sblock);
+ if (r) {
+ DMERR("couldn't read superblock");
+ goto out;
+ }
+
+ disk_super = dm_block_data(sblock);
+ disk_super->flags = cpu_to_le32(pmd->flags);
+
+ dm_bm_unlock(sblock);
+out:
+ up_write(&pmd->root_lock);
+ return r;
+}
+
+bool dm_pool_metadata_needs_check(struct dm_pool_metadata *pmd)
+{
+ bool needs_check;
+
+ down_read(&pmd->root_lock);
+ needs_check = pmd->flags & THIN_METADATA_NEEDS_CHECK_FLAG;
+ up_read(&pmd->root_lock);
+
+ return needs_check;
+}
diff --git a/drivers/md/dm-thin-metadata.h b/drivers/md/dm-thin-metadata.h
index 9a368567632f..e3c857db195a 100644
--- a/drivers/md/dm-thin-metadata.h
+++ b/drivers/md/dm-thin-metadata.h
@@ -9,16 +9,14 @@
#include "persistent-data/dm-block-manager.h"
#include "persistent-data/dm-space-map.h"
+#include "persistent-data/dm-space-map-metadata.h"
-#define THIN_METADATA_BLOCK_SIZE 4096
+#define THIN_METADATA_BLOCK_SIZE DM_SM_METADATA_BLOCK_SIZE
/*
* The metadata device is currently limited in size.
- *
- * We have one block of index, which can hold 255 index entries. Each
- * index entry contains allocation info about 16k metadata blocks.
*/
-#define THIN_METADATA_MAX_SECTORS (255 * (1 << 14) * (THIN_METADATA_BLOCK_SIZE / (1 << SECTOR_SHIFT)))
+#define THIN_METADATA_MAX_SECTORS DM_SM_METADATA_MAX_SECTORS
/*
* A metadata device larger than 16GB triggers a warning.
@@ -27,6 +25,11 @@
/*----------------------------------------------------------------*/
+/*
+ * Thin metadata superblock flags.
+ */
+#define THIN_METADATA_NEEDS_CHECK_FLAG (1 << 0)
+
struct dm_pool_metadata;
struct dm_thin_device;
@@ -161,6 +164,8 @@ int dm_thin_remove_block(struct dm_thin_device *td, dm_block_t block);
*/
bool dm_thin_changed_this_transaction(struct dm_thin_device *td);
+bool dm_pool_changed_this_transaction(struct dm_pool_metadata *pmd);
+
bool dm_thin_aborted_changes(struct dm_thin_device *td);
int dm_thin_get_highest_mapped_block(struct dm_thin_device *td,
@@ -202,6 +207,12 @@ int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
dm_sm_threshold_fn fn,
void *context);
+/*
+ * Updates the superblock immediately.
+ */
+int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd);
+bool dm_pool_metadata_needs_check(struct dm_pool_metadata *pmd);
+
/*----------------------------------------------------------------*/
#endif
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index faaf944597ab..be70d38745f7 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -130,10 +130,11 @@ static void build_virtual_key(struct dm_thin_device *td, dm_block_t b,
struct dm_thin_new_mapping;
/*
- * The pool runs in 3 modes. Ordered in degraded order for comparisons.
+ * The pool runs in 4 modes. Ordered in degraded order for comparisons.
*/
enum pool_mode {
PM_WRITE, /* metadata may be changed */
+ PM_OUT_OF_DATA_SPACE, /* metadata may be changed, though data may not be allocated */
PM_READ_ONLY, /* metadata may not be changed */
PM_FAIL, /* all I/O fails */
};
@@ -198,7 +199,6 @@ struct pool {
};
static enum pool_mode get_pool_mode(struct pool *pool);
-static void out_of_data_space(struct pool *pool);
static void metadata_operation_failed(struct pool *pool, const char *op, int r);
/*
@@ -226,6 +226,7 @@ struct thin_c {
struct pool *pool;
struct dm_thin_device *td;
+ bool requeue_mode:1;
};
/*----------------------------------------------------------------*/
@@ -369,14 +370,18 @@ struct dm_thin_endio_hook {
struct dm_thin_new_mapping *overwrite_mapping;
};
-static void __requeue_bio_list(struct thin_c *tc, struct bio_list *master)
+static void requeue_bio_list(struct thin_c *tc, struct bio_list *master)
{
struct bio *bio;
struct bio_list bios;
+ unsigned long flags;
bio_list_init(&bios);
+
+ spin_lock_irqsave(&tc->pool->lock, flags);
bio_list_merge(&bios, master);
bio_list_init(master);
+ spin_unlock_irqrestore(&tc->pool->lock, flags);
while ((bio = bio_list_pop(&bios))) {
struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
@@ -391,12 +396,26 @@ static void __requeue_bio_list(struct thin_c *tc, struct bio_list *master)
static void requeue_io(struct thin_c *tc)
{
struct pool *pool = tc->pool;
+
+ requeue_bio_list(tc, &pool->deferred_bios);
+ requeue_bio_list(tc, &pool->retry_on_resume_list);
+}
+
+static void error_retry_list(struct pool *pool)
+{
+ struct bio *bio;
unsigned long flags;
+ struct bio_list bios;
+
+ bio_list_init(&bios);
spin_lock_irqsave(&pool->lock, flags);
- __requeue_bio_list(tc, &pool->deferred_bios);
- __requeue_bio_list(tc, &pool->retry_on_resume_list);
+ bio_list_merge(&bios, &pool->retry_on_resume_list);
+ bio_list_init(&pool->retry_on_resume_list);
spin_unlock_irqrestore(&pool->lock, flags);
+
+ while ((bio = bio_list_pop(&bios)))
+ bio_io_error(bio);
}
/*
@@ -925,13 +944,15 @@ static void check_low_water_mark(struct pool *pool, dm_block_t free_blocks)
}
}
+static void set_pool_mode(struct pool *pool, enum pool_mode new_mode);
+
static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
{
int r;
dm_block_t free_blocks;
struct pool *pool = tc->pool;
- if (get_pool_mode(pool) != PM_WRITE)
+ if (WARN_ON(get_pool_mode(pool) != PM_WRITE))
return -EINVAL;
r = dm_pool_get_free_block_count(pool->pmd, &free_blocks);
@@ -958,7 +979,7 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
}
if (!free_blocks) {
- out_of_data_space(pool);
+ set_pool_mode(pool, PM_OUT_OF_DATA_SPACE);
return -ENOSPC;
}
}
@@ -988,15 +1009,32 @@ static void retry_on_resume(struct bio *bio)
spin_unlock_irqrestore(&pool->lock, flags);
}
-static void handle_unserviceable_bio(struct pool *pool, struct bio *bio)
+static bool should_error_unserviceable_bio(struct pool *pool)
{
- /*
- * When pool is read-only, no cell locking is needed because
- * nothing is changing.
- */
- WARN_ON_ONCE(get_pool_mode(pool) != PM_READ_ONLY);
+ enum pool_mode m = get_pool_mode(pool);
- if (pool->pf.error_if_no_space)
+ switch (m) {
+ case PM_WRITE:
+ /* Shouldn't get here */
+ DMERR_LIMIT("bio unserviceable, yet pool is in PM_WRITE mode");
+ return true;
+
+ case PM_OUT_OF_DATA_SPACE:
+ return pool->pf.error_if_no_space;
+
+ case PM_READ_ONLY:
+ case PM_FAIL:
+ return true;
+ default:
+ /* Shouldn't get here */
+ DMERR_LIMIT("bio unserviceable, yet pool has an unknown mode");
+ return true;
+ }
+}
+
+static void handle_unserviceable_bio(struct pool *pool, struct bio *bio)
+{
+ if (should_error_unserviceable_bio(pool))
bio_io_error(bio);
else
retry_on_resume(bio);
@@ -1007,11 +1045,20 @@ static void retry_bios_on_resume(struct pool *pool, struct dm_bio_prison_cell *c
struct bio *bio;
struct bio_list bios;
+ if (should_error_unserviceable_bio(pool)) {
+ cell_error(pool, cell);
+ return;
+ }
+
bio_list_init(&bios);
cell_release(pool, cell, &bios);
- while ((bio = bio_list_pop(&bios)))
- handle_unserviceable_bio(pool, bio);
+ if (should_error_unserviceable_bio(pool))
+ while ((bio = bio_list_pop(&bios)))
+ bio_io_error(bio);
+ else
+ while ((bio = bio_list_pop(&bios)))
+ retry_on_resume(bio);
}
static void process_discard(struct thin_c *tc, struct bio *bio)
@@ -1296,6 +1343,11 @@ static void process_bio_read_only(struct thin_c *tc, struct bio *bio)
}
}
+static void process_bio_success(struct thin_c *tc, struct bio *bio)
+{
+ bio_endio(bio, 0);
+}
+
static void process_bio_fail(struct thin_c *tc, struct bio *bio)
{
bio_io_error(bio);
@@ -1328,6 +1380,11 @@ static void process_deferred_bios(struct pool *pool)
struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
struct thin_c *tc = h->tc;
+ if (tc->requeue_mode) {
+ bio_endio(bio, DM_ENDIO_REQUEUE);
+ continue;
+ }
+
/*
* If we've got no free new_mapping structs, and processing
* this bio might require one, we pause until there are some
@@ -1357,7 +1414,8 @@ static void process_deferred_bios(struct pool *pool)
bio_list_init(&pool->deferred_flush_bios);
spin_unlock_irqrestore(&pool->lock, flags);
- if (bio_list_empty(&bios) && !need_commit_due_to_time(pool))
+ if (bio_list_empty(&bios) &&
+ !(dm_pool_changed_this_transaction(pool->pmd) && need_commit_due_to_time(pool)))
return;
if (commit(pool)) {
@@ -1393,51 +1451,134 @@ static void do_waker(struct work_struct *ws)
/*----------------------------------------------------------------*/
+struct noflush_work {
+ struct work_struct worker;
+ struct thin_c *tc;
+
+ atomic_t complete;
+ wait_queue_head_t wait;
+};
+
+static void complete_noflush_work(struct noflush_work *w)
+{
+ atomic_set(&w->complete, 1);
+ wake_up(&w->wait);
+}
+
+static void do_noflush_start(struct work_struct *ws)
+{
+ struct noflush_work *w = container_of(ws, struct noflush_work, worker);
+ w->tc->requeue_mode = true;
+ requeue_io(w->tc);
+ complete_noflush_work(w);
+}
+
+static void do_noflush_stop(struct work_struct *ws)
+{
+ struct noflush_work *w = container_of(ws, struct noflush_work, worker);
+ w->tc->requeue_mode = false;
+ complete_noflush_work(w);
+}
+
+static void noflush_work(struct thin_c *tc, void (*fn)(struct work_struct *))
+{
+ struct noflush_work w;
+
+ INIT_WORK(&w.worker, fn);
+ w.tc = tc;
+ atomic_set(&w.complete, 0);
+ init_waitqueue_head(&w.wait);
+
+ queue_work(tc->pool->wq, &w.worker);
+
+ wait_event(w.wait, atomic_read(&w.complete));
+}
+
+/*----------------------------------------------------------------*/
+
static enum pool_mode get_pool_mode(struct pool *pool)
{
return pool->pf.mode;
}
+static void notify_of_pool_mode_change(struct pool *pool, const char *new_mode)
+{
+ dm_table_event(pool->ti->table);
+ DMINFO("%s: switching pool to %s mode",
+ dm_device_name(pool->pool_md), new_mode);
+}
+
static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
{
- int r;
- enum pool_mode old_mode = pool->pf.mode;
+ struct pool_c *pt = pool->ti->private;
+ bool needs_check = dm_pool_metadata_needs_check(pool->pmd);
+ enum pool_mode old_mode = get_pool_mode(pool);
+
+ /*
+ * Never allow the pool to transition to PM_WRITE mode if user
+ * intervention is required to verify metadata and data consistency.
+ */
+ if (new_mode == PM_WRITE && needs_check) {
+ DMERR("%s: unable to switch pool to write mode until repaired.",
+ dm_device_name(pool->pool_md));
+ if (old_mode != new_mode)
+ new_mode = old_mode;
+ else
+ new_mode = PM_READ_ONLY;
+ }
+ /*
+ * If we were in PM_FAIL mode, rollback of metadata failed. We're
+ * not going to recover without a thin_repair. So we never let the
+ * pool move out of the old mode.
+ */
+ if (old_mode == PM_FAIL)
+ new_mode = old_mode;
switch (new_mode) {
case PM_FAIL:
if (old_mode != new_mode)
- DMERR("%s: switching pool to failure mode",
- dm_device_name(pool->pool_md));
+ notify_of_pool_mode_change(pool, "failure");
dm_pool_metadata_read_only(pool->pmd);
pool->process_bio = process_bio_fail;
pool->process_discard = process_bio_fail;
pool->process_prepared_mapping = process_prepared_mapping_fail;
pool->process_prepared_discard = process_prepared_discard_fail;
+
+ error_retry_list(pool);
break;
case PM_READ_ONLY:
if (old_mode != new_mode)
- DMERR("%s: switching pool to read-only mode",
- dm_device_name(pool->pool_md));
- r = dm_pool_abort_metadata(pool->pmd);
- if (r) {
- DMERR("%s: aborting transaction failed",
- dm_device_name(pool->pool_md));
- new_mode = PM_FAIL;
- set_pool_mode(pool, new_mode);
- } else {
- dm_pool_metadata_read_only(pool->pmd);
- pool->process_bio = process_bio_read_only;
- pool->process_discard = process_discard;
- pool->process_prepared_mapping = process_prepared_mapping_fail;
- pool->process_prepared_discard = process_prepared_discard_passdown;
- }
+ notify_of_pool_mode_change(pool, "read-only");
+ dm_pool_metadata_read_only(pool->pmd);
+ pool->process_bio = process_bio_read_only;
+ pool->process_discard = process_bio_success;
+ pool->process_prepared_mapping = process_prepared_mapping_fail;
+ pool->process_prepared_discard = process_prepared_discard_passdown;
+
+ error_retry_list(pool);
+ break;
+
+ case PM_OUT_OF_DATA_SPACE:
+ /*
+ * Ideally we'd never hit this state; the low water mark
+ * would trigger userland to extend the pool before we
+ * completely run out of data space. However, many small
+ * IOs to unprovisioned space can consume data space at an
+ * alarming rate. Adjust your low water mark if you're
+ * frequently seeing this mode.
+ */
+ if (old_mode != new_mode)
+ notify_of_pool_mode_change(pool, "out-of-data-space");
+ pool->process_bio = process_bio_read_only;
+ pool->process_discard = process_discard;
+ pool->process_prepared_mapping = process_prepared_mapping;
+ pool->process_prepared_discard = process_prepared_discard_passdown;
break;
case PM_WRITE:
if (old_mode != new_mode)
- DMINFO("%s: switching pool to write mode",
- dm_device_name(pool->pool_md));
+ notify_of_pool_mode_change(pool, "write");
dm_pool_metadata_read_write(pool->pmd);
pool->process_bio = process_bio;
pool->process_discard = process_discard;
@@ -1447,32 +1588,35 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
}
pool->pf.mode = new_mode;
+ /*
+ * The pool mode may have changed, sync it so bind_control_target()
+ * doesn't cause an unexpected mode transition on resume.
+ */
+ pt->adjusted_pf.mode = new_mode;
}
-/*
- * Rather than calling set_pool_mode directly, use these which describe the
- * reason for mode degradation.
- */
-static void out_of_data_space(struct pool *pool)
+static void abort_transaction(struct pool *pool)
{
- DMERR_LIMIT("%s: no free data space available.",
- dm_device_name(pool->pool_md));
- set_pool_mode(pool, PM_READ_ONLY);
+ const char *dev_name = dm_device_name(pool->pool_md);
+
+ DMERR_LIMIT("%s: aborting current metadata transaction", dev_name);
+ if (dm_pool_abort_metadata(pool->pmd)) {
+ DMERR("%s: failed to abort metadata transaction", dev_name);
+ set_pool_mode(pool, PM_FAIL);
+ }
+
+ if (dm_pool_metadata_set_needs_check(pool->pmd)) {
+ DMERR("%s: failed to set 'needs_check' flag in metadata", dev_name);
+ set_pool_mode(pool, PM_FAIL);
+ }
}
static void metadata_operation_failed(struct pool *pool, const char *op, int r)
{
- dm_block_t free_blocks;
-
DMERR_LIMIT("%s: metadata operation '%s' failed: error = %d",
dm_device_name(pool->pool_md), op, r);
- if (r == -ENOSPC &&
- !dm_pool_get_free_metadata_block_count(pool->pmd, &free_blocks) &&
- !free_blocks)
- DMERR_LIMIT("%s: no free metadata space available.",
- dm_device_name(pool->pool_md));
-
+ abort_transaction(pool);
set_pool_mode(pool, PM_READ_ONLY);
}
@@ -1523,6 +1667,11 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
thin_hook_bio(tc, bio);
+ if (tc->requeue_mode) {
+ bio_endio(bio, DM_ENDIO_REQUEUE);
+ return DM_MAPIO_SUBMITTED;
+ }
+
if (get_pool_mode(tc->pool) == PM_FAIL) {
bio_io_error(bio);
return DM_MAPIO_SUBMITTED;
@@ -1686,7 +1835,7 @@ static int bind_control_target(struct pool *pool, struct dm_target *ti)
/*
* We want to make sure that a pool in PM_FAIL mode is never upgraded.
*/
- enum pool_mode old_mode = pool->pf.mode;
+ enum pool_mode old_mode = get_pool_mode(pool);
enum pool_mode new_mode = pt->adjusted_pf.mode;
/*
@@ -1700,16 +1849,6 @@ static int bind_control_target(struct pool *pool, struct dm_target *ti)
pool->pf = pt->adjusted_pf;
pool->low_water_blocks = pt->low_water_blocks;
- /*
- * If we were in PM_FAIL mode, rollback of metadata failed. We're
- * not going to recover without a thin_repair. So we never let the
- * pool move out of the old mode. On the other hand a PM_READ_ONLY
- * may have been due to a lack of metadata or data space, and may
- * now work (ie. if the underlying devices have been resized).
- */
- if (old_mode == PM_FAIL)
- new_mode = old_mode;
-
set_pool_mode(pool, new_mode);
return 0;
@@ -1999,16 +2138,27 @@ static void metadata_low_callback(void *context)
dm_table_event(pool->ti->table);
}
-static sector_t get_metadata_dev_size(struct block_device *bdev)
+static sector_t get_dev_size(struct block_device *bdev)
+{
+ return i_size_read(bdev->bd_inode) >> SECTOR_SHIFT;
+}
+
+static void warn_if_metadata_device_too_big(struct block_device *bdev)
{
- sector_t metadata_dev_size = i_size_read(bdev->bd_inode) >> SECTOR_SHIFT;
+ sector_t metadata_dev_size = get_dev_size(bdev);
char buffer[BDEVNAME_SIZE];
- if (metadata_dev_size > THIN_METADATA_MAX_SECTORS_WARNING) {
+ if (metadata_dev_size > THIN_METADATA_MAX_SECTORS_WARNING)
DMWARN("Metadata device %s is larger than %u sectors: excess space will not be used.",
bdevname(bdev, buffer), THIN_METADATA_MAX_SECTORS);
- metadata_dev_size = THIN_METADATA_MAX_SECTORS_WARNING;
- }
+}
+
+static sector_t get_metadata_dev_size(struct block_device *bdev)
+{
+ sector_t metadata_dev_size = get_dev_size(bdev);
+
+ if (metadata_dev_size > THIN_METADATA_MAX_SECTORS)
+ metadata_dev_size = THIN_METADATA_MAX_SECTORS;
return metadata_dev_size;
}
@@ -2017,7 +2167,7 @@ static dm_block_t get_metadata_dev_size_in_blocks(struct block_device *bdev)
{
sector_t metadata_dev_size = get_metadata_dev_size(bdev);
- sector_div(metadata_dev_size, THIN_METADATA_BLOCK_SIZE >> SECTOR_SHIFT);
+ sector_div(metadata_dev_size, THIN_METADATA_BLOCK_SIZE);
return metadata_dev_size;
}
@@ -2095,12 +2245,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
ti->error = "Error opening metadata block device";
goto out_unlock;
}
-
- /*
- * Run for the side-effect of possibly issuing a warning if the
- * device is too big.
- */
- (void) get_metadata_dev_size(metadata_dev->bdev);
+ warn_if_metadata_device_too_big(metadata_dev->bdev);
r = dm_get_device(ti, argv[1], FMODE_READ | FMODE_WRITE, &data_dev);
if (r) {
@@ -2246,6 +2391,12 @@ static int maybe_resize_data_dev(struct dm_target *ti, bool *need_commit)
return -EINVAL;
} else if (data_size > sb_data_size) {
+ if (dm_pool_metadata_needs_check(pool->pmd)) {
+ DMERR("%s: unable to grow the data device until repaired.",
+ dm_device_name(pool->pool_md));
+ return 0;
+ }
+
if (sb_data_size)
DMINFO("%s: growing the data device from %llu to %llu blocks",
dm_device_name(pool->pool_md),
@@ -2287,6 +2438,13 @@ static int maybe_resize_metadata_dev(struct dm_target *ti, bool *need_commit)
return -EINVAL;
} else if (metadata_dev_size > sb_metadata_dev_size) {
+ if (dm_pool_metadata_needs_check(pool->pmd)) {
+ DMERR("%s: unable to grow the metadata device until repaired.",
+ dm_device_name(pool->pool_md));
+ return 0;
+ }
+
+ warn_if_metadata_device_too_big(pool->md_dev);
DMINFO("%s: growing the metadata device from %llu to %llu blocks",
dm_device_name(pool->pool_md),
sb_metadata_dev_size, metadata_dev_size);
@@ -2673,7 +2831,9 @@ static void pool_status(struct dm_target *ti, status_type_t type,
else
DMEMIT("- ");
- if (pool->pf.mode == PM_READ_ONLY)
+ if (pool->pf.mode == PM_OUT_OF_DATA_SPACE)
+ DMEMIT("out_of_data_space ");
+ else if (pool->pf.mode == PM_READ_ONLY)
DMEMIT("ro ");
else
DMEMIT("rw ");
@@ -2787,7 +2947,7 @@ static struct target_type pool_target = {
.name = "thin-pool",
.features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
DM_TARGET_IMMUTABLE,
- .version = {1, 10, 0},
+ .version = {1, 11, 0},
.module = THIS_MODULE,
.ctr = pool_ctr,
.dtr = pool_dtr,
@@ -2894,6 +3054,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
if (get_pool_mode(tc->pool) == PM_FAIL) {
ti->error = "Couldn't open thin device, Pool is in fail mode";
+ r = -EINVAL;
goto bad_thin_open;
}
@@ -2905,7 +3066,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
r = dm_set_target_max_io_len(ti, tc->pool->sectors_per_block);
if (r)
- goto bad_thin_open;
+ goto bad_target_max_io_len;
ti->num_flush_bios = 1;
ti->flush_supported = true;
@@ -2926,6 +3087,8 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
return 0;
+bad_target_max_io_len:
+ dm_pool_close_thin_device(tc->td);
bad_thin_open:
__pool_dec(tc->pool);
bad_pool_lookup:
@@ -2986,10 +3149,23 @@ static int thin_endio(struct dm_target *ti, struct bio *bio, int err)
return 0;
}
-static void thin_postsuspend(struct dm_target *ti)
+static void thin_presuspend(struct dm_target *ti)
{
+ struct thin_c *tc = ti->private;
+
if (dm_noflush_suspending(ti))
- requeue_io((struct thin_c *)ti->private);
+ noflush_work(tc, do_noflush_start);
+}
+
+static void thin_postsuspend(struct dm_target *ti)
+{
+ struct thin_c *tc = ti->private;
+
+ /*
+ * The dm_noflush_suspending flag has been cleared by now, so
+ * unfortunately we must always run this.
+ */
+ noflush_work(tc, do_noflush_stop);
}
/*
@@ -3074,12 +3250,13 @@ static int thin_iterate_devices(struct dm_target *ti,
static struct target_type thin_target = {
.name = "thin",
- .version = {1, 10, 0},
+ .version = {1, 11, 0},
.module = THIS_MODULE,
.ctr = thin_ctr,
.dtr = thin_dtr,
.map = thin_map,
.end_io = thin_endio,
+ .presuspend = thin_presuspend,
.postsuspend = thin_postsuspend,
.status = thin_status,
.iterate_devices = thin_iterate_devices,
diff --git a/drivers/md/persistent-data/Kconfig b/drivers/md/persistent-data/Kconfig
index 19b268795415..0c2dec7aec20 100644
--- a/drivers/md/persistent-data/Kconfig
+++ b/drivers/md/persistent-data/Kconfig
@@ -6,3 +6,13 @@ config DM_PERSISTENT_DATA
---help---
Library providing immutable on-disk data structure support for
device-mapper targets such as the thin provisioning target.
+
+config DM_DEBUG_BLOCK_STACK_TRACING
+ boolean "Keep stack trace of persistent data block lock holders"
+ depends on STACKTRACE_SUPPORT && DM_PERSISTENT_DATA
+ select STACKTRACE
+ ---help---
+ Enable this for messages that may help debug problems with the
+ block manager locking used by thin provisioning and caching.
+
+ If unsure, say N.
diff --git a/drivers/md/persistent-data/dm-space-map-metadata.c b/drivers/md/persistent-data/dm-space-map-metadata.c
index 536782e3bcb7..786b689bdfc7 100644
--- a/drivers/md/persistent-data/dm-space-map-metadata.c
+++ b/drivers/md/persistent-data/dm-space-map-metadata.c
@@ -91,6 +91,69 @@ struct block_op {
dm_block_t block;
};
+struct bop_ring_buffer {
+ unsigned begin;
+ unsigned end;
+ struct block_op bops[MAX_RECURSIVE_ALLOCATIONS + 1];
+};
+
+static void brb_init(struct bop_ring_buffer *brb)
+{
+ brb->begin = 0;
+ brb->end = 0;
+}
+
+static bool brb_empty(struct bop_ring_buffer *brb)
+{
+ return brb->begin == brb->end;
+}
+
+static unsigned brb_next(struct bop_ring_buffer *brb, unsigned old)
+{
+ unsigned r = old + 1;
+ return (r >= (sizeof(brb->bops) / sizeof(*brb->bops))) ? 0 : r;
+}
+
+static int brb_push(struct bop_ring_buffer *brb,
+ enum block_op_type type, dm_block_t b)
+{
+ struct block_op *bop;
+ unsigned next = brb_next(brb, brb->end);
+
+ /*
+ * We don't allow the last bop to be filled, this way we can
+ * differentiate between full and empty.
+ */
+ if (next == brb->begin)
+ return -ENOMEM;
+
+ bop = brb->bops + brb->end;
+ bop->type = type;
+ bop->block = b;
+
+ brb->end = next;
+
+ return 0;
+}
+
+static int brb_pop(struct bop_ring_buffer *brb, struct block_op *result)
+{
+ struct block_op *bop;
+
+ if (brb_empty(brb))
+ return -ENODATA;
+
+ bop = brb->bops + brb->begin;
+ result->type = bop->type;
+ result->block = bop->block;
+
+ brb->begin = brb_next(brb, brb->begin);
+
+ return 0;
+}
+
+/*----------------------------------------------------------------*/
+
struct sm_metadata {
struct dm_space_map sm;
@@ -101,25 +164,20 @@ struct sm_metadata {
unsigned recursion_count;
unsigned allocated_this_transaction;
- unsigned nr_uncommitted;
- struct block_op uncommitted[MAX_RECURSIVE_ALLOCATIONS];
+ struct bop_ring_buffer uncommitted;
struct threshold threshold;
};
static int add_bop(struct sm_metadata *smm, enum block_op_type type, dm_block_t b)
{
- struct block_op *op;
+ int r = brb_push(&smm->uncommitted, type, b);
- if (smm->nr_uncommitted == MAX_RECURSIVE_ALLOCATIONS) {
+ if (r) {
DMERR("too many recursive allocations");
return -ENOMEM;
}
- op = smm->uncommitted + smm->nr_uncommitted++;
- op->type = type;
- op->block = b;
-
return 0;
}
@@ -158,11 +216,17 @@ static int out(struct sm_metadata *smm)
return -ENOMEM;
}
- if (smm->recursion_count == 1 && smm->nr_uncommitted) {
- while (smm->nr_uncommitted && !r) {
- smm->nr_uncommitted--;
- r = commit_bop(smm, smm->uncommitted +
- smm->nr_uncommitted);
+ if (smm->recursion_count == 1) {
+ while (!brb_empty(&smm->uncommitted)) {
+ struct block_op bop;
+
+ r = brb_pop(&smm->uncommitted, &bop);
+ if (r) {
+ DMERR("bug in bop ring buffer");
+ break;
+ }
+
+ r = commit_bop(smm, &bop);
if (r)
break;
}
@@ -217,7 +281,8 @@ static int sm_metadata_get_nr_free(struct dm_space_map *sm, dm_block_t *count)
static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b,
uint32_t *result)
{
- int r, i;
+ int r;
+ unsigned i;
struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
unsigned adjustment = 0;
@@ -225,8 +290,10 @@ static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b,
* We may have some uncommitted adjustments to add. This list
* should always be really short.
*/
- for (i = 0; i < smm->nr_uncommitted; i++) {
- struct block_op *op = smm->uncommitted + i;
+ for (i = smm->uncommitted.begin;
+ i != smm->uncommitted.end;
+ i = brb_next(&smm->uncommitted, i)) {
+ struct block_op *op = smm->uncommitted.bops + i;
if (op->block != b)
continue;
@@ -254,7 +321,8 @@ static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b,
static int sm_metadata_count_is_more_than_one(struct dm_space_map *sm,
dm_block_t b, int *result)
{
- int r, i, adjustment = 0;
+ int r, adjustment = 0;
+ unsigned i;
struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
uint32_t rc;
@@ -262,8 +330,11 @@ static int sm_metadata_count_is_more_than_one(struct dm_space_map *sm,
* We may have some uncommitted adjustments to add. This list
* should always be really short.
*/
- for (i = 0; i < smm->nr_uncommitted; i++) {
- struct block_op *op = smm->uncommitted + i;
+ for (i = smm->uncommitted.begin;
+ i != smm->uncommitted.end;
+ i = brb_next(&smm->uncommitted, i)) {
+
+ struct block_op *op = smm->uncommitted.bops + i;
if (op->block != b)
continue;
@@ -671,7 +742,7 @@ int dm_sm_metadata_create(struct dm_space_map *sm,
smm->begin = superblock + 1;
smm->recursion_count = 0;
smm->allocated_this_transaction = 0;
- smm->nr_uncommitted = 0;
+ brb_init(&smm->uncommitted);
threshold_init(&smm->threshold);
memcpy(&smm->sm, &bootstrap_ops, sizeof(smm->sm));
@@ -680,6 +751,8 @@ int dm_sm_metadata_create(struct dm_space_map *sm,
if (r)
return r;
+ if (nr_blocks > DM_SM_METADATA_MAX_BLOCKS)
+ nr_blocks = DM_SM_METADATA_MAX_BLOCKS;
r = sm_ll_extend(&smm->ll, nr_blocks);
if (r)
return r;
@@ -713,7 +786,7 @@ int dm_sm_metadata_open(struct dm_space_map *sm,
smm->begin = 0;
smm->recursion_count = 0;
smm->allocated_this_transaction = 0;
- smm->nr_uncommitted = 0;
+ brb_init(&smm->uncommitted);
threshold_init(&smm->threshold);
memcpy(&smm->old_ll, &smm->ll, sizeof(smm->old_ll));
diff --git a/drivers/md/persistent-data/dm-space-map-metadata.h b/drivers/md/persistent-data/dm-space-map-metadata.h
index 39bba0801cf2..64df923974d8 100644
--- a/drivers/md/persistent-data/dm-space-map-metadata.h
+++ b/drivers/md/persistent-data/dm-space-map-metadata.h
@@ -9,6 +9,17 @@
#include "dm-transaction-manager.h"
+#define DM_SM_METADATA_BLOCK_SIZE (4096 >> SECTOR_SHIFT)
+
+/*
+ * The metadata device is currently limited in size.
+ *
+ * We have one block of index, which can hold 255 index entries. Each
+ * index entry contains allocation info about ~16k metadata blocks.
+ */
+#define DM_SM_METADATA_MAX_BLOCKS (255 * ((1 << 14) - 64))
+#define DM_SM_METADATA_MAX_SECTORS (DM_SM_METADATA_MAX_BLOCKS * DM_SM_METADATA_BLOCK_SIZE)
+
/*
* Unfortunately we have to use two-phase construction due to the cycle
* between the tm and sm.
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index fd3a2a14b587..4a6ca1cb2e78 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1953,11 +1953,15 @@ static int process_checks(struct r1bio *r1_bio)
for (i = 0; i < conf->raid_disks * 2; i++) {
int j;
int size;
+ int uptodate;
struct bio *b = r1_bio->bios[i];
if (b->bi_end_io != end_sync_read)
continue;
- /* fixup the bio for reuse */
+ /* fixup the bio for reuse, but preserve BIO_UPTODATE */
+ uptodate = test_bit(BIO_UPTODATE, &b->bi_flags);
bio_reset(b);
+ if (!uptodate)
+ clear_bit(BIO_UPTODATE, &b->bi_flags);
b->bi_vcnt = vcnt;
b->bi_iter.bi_size = r1_bio->sectors << 9;
b->bi_iter.bi_sector = r1_bio->sector +
@@ -1990,11 +1994,14 @@ static int process_checks(struct r1bio *r1_bio)
int j;
struct bio *pbio = r1_bio->bios[primary];
struct bio *sbio = r1_bio->bios[i];
+ int uptodate = test_bit(BIO_UPTODATE, &sbio->bi_flags);
if (sbio->bi_end_io != end_sync_read)
continue;
+ /* Now we can 'fixup' the BIO_UPTODATE flag */
+ set_bit(BIO_UPTODATE, &sbio->bi_flags);
- if (test_bit(BIO_UPTODATE, &sbio->bi_flags)) {
+ if (uptodate) {
for (j = vcnt; j-- ; ) {
struct page *p, *s;
p = pbio->bi_io_vec[j].bv_page;
@@ -2009,7 +2016,7 @@ static int process_checks(struct r1bio *r1_bio)
if (j >= 0)
atomic64_add(r1_bio->sectors, &mddev->resync_mismatches);
if (j < 0 || (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)
- && test_bit(BIO_UPTODATE, &sbio->bi_flags))) {
+ && uptodate)) {
/* No need to write to this device. */
sbio->bi_end_io = NULL;
rdev_dec_pending(conf->mirrors[i].rdev, mddev);
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index f1feadeb7bb2..16f5c21963db 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -5514,23 +5514,43 @@ raid5_size(struct mddev *mddev, sector_t sectors, int raid_disks)
return sectors * (raid_disks - conf->max_degraded);
}
+static void free_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu)
+{
+ safe_put_page(percpu->spare_page);
+ kfree(percpu->scribble);
+ percpu->spare_page = NULL;
+ percpu->scribble = NULL;
+}
+
+static int alloc_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu)
+{
+ if (conf->level == 6 && !percpu->spare_page)
+ percpu->spare_page = alloc_page(GFP_KERNEL);
+ if (!percpu->scribble)
+ percpu->scribble = kmalloc(conf->scribble_len, GFP_KERNEL);
+
+ if (!percpu->scribble || (conf->level == 6 && !percpu->spare_page)) {
+ free_scratch_buffer(conf, percpu);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
static void raid5_free_percpu(struct r5conf *conf)
{
- struct raid5_percpu *percpu;
unsigned long cpu;
if (!conf->percpu)
return;
- get_online_cpus();
- for_each_possible_cpu(cpu) {
- percpu = per_cpu_ptr(conf->percpu, cpu);
- safe_put_page(percpu->spare_page);
- kfree(percpu->scribble);
- }
#ifdef CONFIG_HOTPLUG_CPU
unregister_cpu_notifier(&conf->cpu_notify);
#endif
+
+ get_online_cpus();
+ for_each_possible_cpu(cpu)
+ free_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu));
put_online_cpus();
free_percpu(conf->percpu);
@@ -5557,15 +5577,7 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action,
switch (action) {
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
- if (conf->level == 6 && !percpu->spare_page)
- percpu->spare_page = alloc_page(GFP_KERNEL);
- if (!percpu->scribble)
- percpu->scribble = kmalloc(conf->scribble_len, GFP_KERNEL);
-
- if (!percpu->scribble ||
- (conf->level == 6 && !percpu->spare_page)) {
- safe_put_page(percpu->spare_page);
- kfree(percpu->scribble);
+ if (alloc_scratch_buffer(conf, percpu)) {
pr_err("%s: failed memory allocation for cpu%ld\n",
__func__, cpu);
return notifier_from_errno(-ENOMEM);
@@ -5573,10 +5585,7 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action,
break;
case CPU_DEAD:
case CPU_DEAD_FROZEN:
- safe_put_page(percpu->spare_page);
- kfree(percpu->scribble);
- percpu->spare_page = NULL;
- percpu->scribble = NULL;
+ free_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu));
break;
default:
break;
@@ -5588,40 +5597,29 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action,
static int raid5_alloc_percpu(struct r5conf *conf)
{
unsigned long cpu;
- struct page *spare_page;
- struct raid5_percpu __percpu *allcpus;
- void *scribble;
- int err;
+ int err = 0;
- allcpus = alloc_percpu(struct raid5_percpu);
- if (!allcpus)
+ conf->percpu = alloc_percpu(struct raid5_percpu);
+ if (!conf->percpu)
return -ENOMEM;
- conf->percpu = allcpus;
+
+#ifdef CONFIG_HOTPLUG_CPU
+ conf->cpu_notify.notifier_call = raid456_cpu_notify;
+ conf->cpu_notify.priority = 0;
+ err = register_cpu_notifier(&conf->cpu_notify);
+ if (err)
+ return err;
+#endif
get_online_cpus();
- err = 0;
for_each_present_cpu(cpu) {
- if (conf->level == 6) {
- spare_page = alloc_page(GFP_KERNEL);
- if (!spare_page) {
- err = -ENOMEM;
- break;
- }
- per_cpu_ptr(conf->percpu, cpu)->spare_page = spare_page;
- }
- scribble = kmalloc(conf->scribble_len, GFP_KERNEL);
- if (!scribble) {
- err = -ENOMEM;
+ err = alloc_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu));
+ if (err) {
+ pr_err("%s: failed memory allocation for cpu%ld\n",
+ __func__, cpu);
break;
}
- per_cpu_ptr(conf->percpu, cpu)->scribble = scribble;
}
-#ifdef CONFIG_HOTPLUG_CPU
- conf->cpu_notify.notifier_call = raid456_cpu_notify;
- conf->cpu_notify.priority = 0;
- if (err == 0)
- err = register_cpu_notifier(&conf->cpu_notify);
-#endif
put_online_cpus();
return err;
diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c
index 0bb4430535f9..2408d7e9451e 100644
--- a/drivers/media/common/siano/smsdvb-debugfs.c
+++ b/drivers/media/common/siano/smsdvb-debugfs.c
@@ -1,6 +1,6 @@
/***********************************************************************
*
- * Copyright(c) 2013 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright(c) 2013 Mauro Carvalho Chehab
*
* 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/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c
index b8c5cad78537..6d7c0c858bd0 100644
--- a/drivers/media/common/siano/smsir.c
+++ b/drivers/media/common/siano/smsir.c
@@ -88,7 +88,7 @@ int sms_ir_init(struct smscore_device_t *coredev)
dev->priv = coredev;
dev->driver_type = RC_DRIVER_IR_RAW;
- dev->allowed_protos = RC_BIT_ALL;
+ rc_set_allowed_protocols(dev, RC_BIT_ALL);
dev->map_name = sms_get_board(board_id)->rc_codes;
dev->driver_name = MODULE_NAME;
diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
index f19a2ccd1e4b..1bdc0e7e8b79 100644
--- a/drivers/media/dvb-core/dvb-usb-ids.h
+++ b/drivers/media/dvb-core/dvb-usb-ids.h
@@ -257,6 +257,7 @@
#define USB_PID_TERRATEC_T5 0x10a1
#define USB_PID_NOXON_DAB_STICK 0x00b3
#define USB_PID_NOXON_DAB_STICK_REV2 0x00e0
+#define USB_PID_NOXON_DAB_STICK_REV3 0x00b4
#define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e
#define USB_PID_PINNACLE_PCTV2000E 0x022c
#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index 1f925e856974..6ce435ac866f 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -1279,7 +1279,7 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
switch(tvp->cmd) {
case DTV_ENUM_DELSYS:
ncaps = 0;
- while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+ while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) {
tvp->u.buffer.data[ncaps] = fe->ops.delsys[ncaps];
ncaps++;
}
@@ -1596,7 +1596,7 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe,
* supported
*/
ncaps = 0;
- while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+ while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) {
if (fe->ops.delsys[ncaps] == desired_system) {
c->delivery_system = desired_system;
dev_dbg(fe->dvb->device,
@@ -1628,7 +1628,7 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe,
* of the desired system
*/
ncaps = 0;
- while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+ while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) {
if (dvbv3_type(fe->ops.delsys[ncaps]) == type)
delsys = fe->ops.delsys[ncaps];
ncaps++;
@@ -1703,7 +1703,7 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe)
* DVBv3 standard
*/
ncaps = 0;
- while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+ while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) {
if (dvbv3_type(fe->ops.delsys[ncaps]) != DVBV3_UNKNOWN) {
delsys = fe->ops.delsys[ncaps];
break;
@@ -1882,6 +1882,8 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
c->lna = tvp->u.data;
if (fe->ops.set_lna)
r = fe->ops.set_lna(fe);
+ if (r < 0)
+ c->lna = LNA_AUTO;
break;
default:
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index dd12a1ebda82..025fc5496bfc 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -441,7 +441,7 @@ config DVB_RTL2830
config DVB_RTL2832
tristate "Realtek RTL2832 DVB-T"
- depends on DVB_CORE && I2C
+ depends on DVB_CORE && I2C && I2C_MUX
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Say Y when you want to support this frontend.
@@ -650,6 +650,8 @@ config DVB_TUNER_DIB0090
comment "SEC control devices for DVB-S"
depends on DVB_CORE
+source "drivers/media/dvb-frontends/drx39xyj/Kconfig"
+
config DVB_LNBP21
tristate "LNBP21/LNBH24 SEC controllers"
depends on DVB_CORE && I2C
@@ -733,14 +735,6 @@ config DVB_IX2505V
help
A DVB-S tuner module. Say Y when you want to support this frontend.
-config DVB_IT913X_FE
- tristate "it913x frontend and it9137 tuner"
- depends on DVB_CORE && I2C
- default m if !MEDIA_SUBDRV_AUTOSELECT
- help
- A DVB-T tuner module.
- Say Y when you want to support this frontend.
-
config DVB_M88RS2000
tristate "M88RS2000 DVB-S demodulator and tuner"
depends on DVB_CORE && I2C
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
index 0c75a6aafb9d..282aba2fe8db 100644
--- a/drivers/media/dvb-frontends/Makefile
+++ b/drivers/media/dvb-frontends/Makefile
@@ -92,13 +92,13 @@ obj-$(CONFIG_DVB_HD29L2) += hd29l2.o
obj-$(CONFIG_DVB_DS3000) += ds3000.o
obj-$(CONFIG_DVB_TS2020) += ts2020.o
obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
+obj-$(CONFIG_DVB_DRX39XYJ) += drx39xyj/
obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o
obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
obj-$(CONFIG_DVB_STV0367) += stv0367.o
obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o
obj-$(CONFIG_DVB_DRXK) += drxk.o
obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o
-obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o
obj-$(CONFIG_DVB_A8293) += a8293.o
obj-$(CONFIG_DVB_TDA10071) += tda10071.o
obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c
index 65728c25ea05..be4bec2a9640 100644
--- a/drivers/media/dvb-frontends/af9033.c
+++ b/drivers/media/dvb-frontends/af9033.c
@@ -989,10 +989,62 @@ err:
return ret;
}
+static int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff)
+{
+ struct af9033_state *state = fe->demodulator_priv;
+ int ret;
+
+ dev_dbg(&state->i2c->dev, "%s: onoff=%d\n", __func__, onoff);
+
+ ret = af9033_wr_reg_mask(state, 0x80f993, onoff, 0x01);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, int onoff)
+{
+ struct af9033_state *state = fe->demodulator_priv;
+ int ret;
+ u8 wbuf[2] = {(pid >> 0) & 0xff, (pid >> 8) & 0xff};
+
+ dev_dbg(&state->i2c->dev, "%s: index=%d pid=%04x onoff=%d\n",
+ __func__, index, pid, onoff);
+
+ if (pid > 0x1fff)
+ return 0;
+
+ ret = af9033_wr_regs(state, 0x80f996, wbuf, 2);
+ if (ret < 0)
+ goto err;
+
+ ret = af9033_wr_reg(state, 0x80f994, onoff);
+ if (ret < 0)
+ goto err;
+
+ ret = af9033_wr_reg(state, 0x80f995, index);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
static struct dvb_frontend_ops af9033_ops;
struct dvb_frontend *af9033_attach(const struct af9033_config *config,
- struct i2c_adapter *i2c)
+ struct i2c_adapter *i2c,
+ struct af9033_ops *ops)
{
int ret;
struct af9033_state *state;
@@ -1067,6 +1119,11 @@ struct dvb_frontend *af9033_attach(const struct af9033_config *config,
memcpy(&state->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops));
state->fe.demodulator_priv = state;
+ if (ops) {
+ ops->pid_filter = af9033_pid_filter;
+ ops->pid_filter_ctrl = af9033_pid_filter_ctrl;
+ }
+
return &state->fe;
err:
diff --git a/drivers/media/dvb-frontends/af9033.h b/drivers/media/dvb-frontends/af9033.h
index c286e8f1ec02..539f4db678b8 100644
--- a/drivers/media/dvb-frontends/af9033.h
+++ b/drivers/media/dvb-frontends/af9033.h
@@ -78,16 +78,42 @@ struct af9033_config {
};
+struct af9033_ops {
+ int (*pid_filter_ctrl)(struct dvb_frontend *fe, int onoff);
+ int (*pid_filter)(struct dvb_frontend *fe, int index, u16 pid,
+ int onoff);
+};
+
+
#if IS_ENABLED(CONFIG_DVB_AF9033)
-extern struct dvb_frontend *af9033_attach(const struct af9033_config *config,
- struct i2c_adapter *i2c);
+extern
+struct dvb_frontend *af9033_attach(const struct af9033_config *config,
+ struct i2c_adapter *i2c,
+ struct af9033_ops *ops);
+
#else
-static inline struct dvb_frontend *af9033_attach(
- const struct af9033_config *config, struct i2c_adapter *i2c)
+static inline
+struct dvb_frontend *af9033_attach(const struct af9033_config *config,
+ struct i2c_adapter *i2c,
+ struct af9033_ops *ops)
{
pr_warn("%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
+
+static inline int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff)
+{
+ pr_warn("%s: driver disabled by Kconfig\n", __func__);
+ return -ENODEV;
+}
+
+static inline int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid,
+ int onoff)
+{
+ pr_warn("%s: driver disabled by Kconfig\n", __func__);
+ return -ENODEV;
+}
+
#endif
#endif /* AF9033_H */
diff --git a/drivers/media/dvb-frontends/drx39xyj/Kconfig b/drivers/media/dvb-frontends/drx39xyj/Kconfig
new file mode 100644
index 000000000000..15628eb5cf0c
--- /dev/null
+++ b/drivers/media/dvb-frontends/drx39xyj/Kconfig
@@ -0,0 +1,7 @@
+config DVB_DRX39XYJ
+ tristate "Micronas DRX-J demodulator"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+ to support this frontend.
diff --git a/drivers/media/dvb-frontends/drx39xyj/Makefile b/drivers/media/dvb-frontends/drx39xyj/Makefile
new file mode 100644
index 000000000000..672e07774955
--- /dev/null
+++ b/drivers/media/dvb-frontends/drx39xyj/Makefile
@@ -0,0 +1,6 @@
+drx39xyj-objs := drxj.o
+
+obj-$(CONFIG_DVB_DRX39XYJ) += drx39xyj.o
+
+ccflags-y += -I$(srctree)/drivers/media/dvb-core/
+ccflags-y += -I$(srctree)/drivers/media/tuners/
diff --git a/drivers/media/dvb-frontends/drx39xyj/bsp_i2c.h b/drivers/media/dvb-frontends/drx39xyj/bsp_i2c.h
new file mode 100644
index 000000000000..5b5421f70388
--- /dev/null
+++ b/drivers/media/dvb-frontends/drx39xyj/bsp_i2c.h
@@ -0,0 +1,139 @@
+/*
+ I2C API, implementation depends on board specifics
+
+ Copyright (c), 2004-2005,2007-2010 Trident Microsystems, Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Trident Microsystems nor Hauppauge Computer Works
+ nor the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ 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 HOLDER 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 module encapsulates I2C access.In some applications several devices
+ share one I2C bus. If these devices have the same I2C address some kind
+ off "switch" must be implemented to ensure error free communication with
+ one device. In case such a "switch" is used, the device ID can be used
+ to implement control over this "switch".
+*/
+
+#ifndef __BSPI2C_H__
+#define __BSPI2C_H__
+
+#include "bsp_types.h"
+
+/*
+ * This structure contains the I2C address, the device ID and a user_data pointer.
+ * The user_data pointer can be used for application specific purposes.
+ */
+struct i2c_device_addr {
+ u16 i2c_addr; /* The I2C address of the device. */
+ u16 i2c_dev_id; /* The device identifier. */
+ void *user_data; /* User data pointer */
+};
+
+
+/**
+* \def IS_I2C_10BIT( addr )
+* \brief Determine if I2C address 'addr' is a 10 bits address or not.
+* \param addr The I2C address.
+* \return int.
+* \retval 0 if address is not a 10 bits I2C address.
+* \retval 1 if address is a 10 bits I2C address.
+*/
+#define IS_I2C_10BIT(addr) \
+ (((addr) & 0xF8) == 0xF0)
+
+/*------------------------------------------------------------------------------
+Exported FUNCTIONS
+------------------------------------------------------------------------------*/
+
+/**
+* \fn drxbsp_i2c_init()
+* \brief Initialize I2C communication module.
+* \return drx_status_t Return status.
+* \retval 0 Initialization successful.
+* \retval -EIO Initialization failed.
+*/
+ drx_status_t drxbsp_i2c_init(void);
+
+/**
+* \fn drxbsp_i2c_term()
+* \brief Terminate I2C communication module.
+* \return drx_status_t Return status.
+* \retval 0 Termination successful.
+* \retval -EIO Termination failed.
+*/
+ drx_status_t drxbsp_i2c_term(void);
+
+/**
+* \fn drx_status_t drxbsp_i2c_write_read( struct i2c_device_addr *w_dev_addr,
+* u16 w_count,
+* u8 *wData,
+* struct i2c_device_addr *r_dev_addr,
+* u16 r_count,
+* u8 *r_data)
+* \brief Read and/or write count bytes from I2C bus, store them in data[].
+* \param w_dev_addr The device i2c address and the device ID to write to
+* \param w_count The number of bytes to write
+* \param wData The array to write the data to
+* \param r_dev_addr The device i2c address and the device ID to read from
+* \param r_count The number of bytes to read
+* \param r_data The array to read the data from
+* \return drx_status_t Return status.
+* \retval 0 Succes.
+* \retval -EIO Failure.
+* \retval -EINVAL Parameter 'wcount' is not zero but parameter
+* 'wdata' contains NULL.
+* Idem for 'rcount' and 'rdata'.
+* Both w_dev_addr and r_dev_addr are NULL.
+*
+* This function must implement an atomic write and/or read action on the I2C bus
+* No other process may use the I2C bus when this function is executing.
+* The critical section of this function runs from and including the I2C
+* write, up to and including the I2C read action.
+*
+* The device ID can be useful if several devices share an I2C address.
+* It can be used to control a "switch" on the I2C bus to the correct device.
+*/
+ drx_status_t drxbsp_i2c_write_read(struct i2c_device_addr *w_dev_addr,
+ u16 w_count,
+ u8 *w_data,
+ struct i2c_device_addr *r_dev_addr,
+ u16 r_count, u8 *r_data);
+
+/**
+* \fn drxbsp_i2c_error_text()
+* \brief Returns a human readable error.
+* Counter part of numerical drx_i2c_error_g.
+*
+* \return char* Pointer to human readable error text.
+*/
+ char *drxbsp_i2c_error_text(void);
+
+/**
+* \var drx_i2c_error_g;
+* \brief I2C specific error codes, platform dependent.
+*/
+ extern int drx_i2c_error_g;
+
+#endif /* __BSPI2C_H__ */
diff --git a/drivers/media/dvb-frontends/drx39xyj/drx39xxj.h b/drivers/media/dvb-frontends/drx39xyj/drx39xxj.h
new file mode 100644
index 000000000000..cfd0b96b6939
--- /dev/null
+++ b/drivers/media/dvb-frontends/drx39xyj/drx39xxj.h
@@ -0,0 +1,45 @@
+/*
+ * Driver for Micronas DRX39xx family (drx3933j)
+ *
+ * Written by Devin Heitmueller <devin.heitmueller@kernellabs.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., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef DRX39XXJ_H
+#define DRX39XXJ_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+#include "drx_driver.h"
+
+struct drx39xxj_state {
+ struct i2c_adapter *i2c;
+ struct drx_demod_instance *demod;
+ struct dvb_frontend frontend;
+ unsigned int i2c_gate_open:1;
+ const struct firmware *fw;
+};
+
+#if IS_ENABLED(CONFIG_DVB_DRX39XYJ)
+struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c) {
+ return NULL;
+};
+#endif
+
+#endif /* DVB_DUMMY_FE_H */
diff --git a/drivers/media/dvb-frontends/drx39xyj/drx_dap_fasi.h b/drivers/media/dvb-frontends/drx39xyj/drx_dap_fasi.h
new file mode 100644
index 000000000000..354ec07eae87
--- /dev/null
+++ b/drivers/media/dvb-frontends/drx39xyj/drx_dap_fasi.h
@@ -0,0 +1,256 @@
+/*
+ Copyright (c), 2004-2005,2007-2010 Trident Microsystems, Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Trident Microsystems nor Hauppauge Computer Works
+ nor the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ 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 HOLDER 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.
+*/
+
+/*******************************************************************************
+* FILENAME: $Id: drx_dap_fasi.h,v 1.5 2009/07/07 14:21:40 justin Exp $
+*
+* DESCRIPTION:
+* Part of DRX driver.
+* Data access protocol: Fast Access Sequential Interface (fasi)
+* Fast access, because of short addressing format (16 instead of 32 bits addr)
+* Sequential, because of I2C.
+*
+* USAGE:
+* Include.
+*
+* NOTES:
+*
+*
+*******************************************************************************/
+
+/*-------- compilation control switches --------------------------------------*/
+
+#ifndef __DRX_DAP_FASI_H__
+#define __DRX_DAP_FASI_H__
+
+/*-------- Required includes -------------------------------------------------*/
+
+#include "drx_driver.h"
+
+/*-------- Defines, configuring the API --------------------------------------*/
+
+/********************************************
+* Allowed address formats
+********************************************/
+
+/*
+* Comments about short/long addressing format:
+*
+* The DAP FASI offers long address format (4 bytes) and short address format
+* (2 bytes). The DAP can operate in 3 modes:
+* (1) only short
+* (2) only long
+* (3) both long and short but short preferred and long only when necesarry
+*
+* These modes must be selected compile time via compile switches.
+* Compile switch settings for the diffrent modes:
+* (1) DRXDAPFASI_LONG_ADDR_ALLOWED=0, DRXDAPFASI_SHORT_ADDR_ALLOWED=1
+* (2) DRXDAPFASI_LONG_ADDR_ALLOWED=1, DRXDAPFASI_SHORT_ADDR_ALLOWED=0
+* (3) DRXDAPFASI_LONG_ADDR_ALLOWED=1, DRXDAPFASI_SHORT_ADDR_ALLOWED=1
+*
+* The default setting will be (3) both long and short.
+* The default setting will need no compile switches.
+* The default setting must be overridden if compile switches are already
+* defined.
+*
+*/
+
+/* set default */
+#if !defined(DRXDAPFASI_LONG_ADDR_ALLOWED)
+#define DRXDAPFASI_LONG_ADDR_ALLOWED 1
+#endif
+
+/* set default */
+#if !defined(DRXDAPFASI_SHORT_ADDR_ALLOWED)
+#define DRXDAPFASI_SHORT_ADDR_ALLOWED 1
+#endif
+
+/* check */
+#if ((DRXDAPFASI_LONG_ADDR_ALLOWED == 0) && \
+ (DRXDAPFASI_SHORT_ADDR_ALLOWED == 0))
+#error At least one of short- or long-addressing format must be allowed.
+*; /* illegal statement to force compiler error */
+#endif
+
+/********************************************
+* Single/master multi master setting
+********************************************/
+/*
+* Comments about SINGLE MASTER/MULTI MASTER modes:
+*
+* Consider the two sides:1) the master and 2)the slave.
+*
+* Master:
+* Single/multimaster operation set via DRXDAP_SINGLE_MASTER compile switch
+* + single master mode means no use of repeated starts
+* + multi master mode means use of repeated starts
+* Default is single master.
+* Default can be overriden by setting the compile switch DRXDAP_SINGLE_MASTER.
+*
+* Slave:
+* Single/multi master selected via the flags in the FASI protocol.
+* + single master means remember memory address between i2c packets
+* + multimaster means flush memory address between i2c packets
+* Default is single master, DAP FASI changes multi-master setting silently
+* into single master setting. This cannot be overrriden.
+*
+*/
+/* set default */
+#ifndef DRXDAP_SINGLE_MASTER
+#define DRXDAP_SINGLE_MASTER 0
+#endif
+
+/********************************************
+* Chunk/mode checking
+********************************************/
+/*
+* Comments about DRXDAP_MAX_WCHUNKSIZE in single or multi master mode and
+* in combination with short and long addressing format. All text below
+* assumes long addressing format. The table also includes information
+* for short ADDRessing format.
+*
+* In single master mode, data can be written by sending the register address
+* first, then two or four bytes of data in the next packet.
+* Because the device address plus a register address equals five bytes,
+* the mimimum chunk size must be five.
+* If ten-bit I2C device addresses are used, the minimum chunk size must be six,
+* because the I2C device address will then occupy two bytes when writing.
+*
+* Data in single master mode is transferred as follows:
+* <S> <devW> a0 a1 a2 a3 <P>
+* <S> <devW> d0 d1 [d2 d3] <P>
+* ..
+* or
+* ..
+* <S> <devW> a0 a1 a2 a3 <P>
+* <S> <devR> --- <P>
+*
+* In multi-master mode, the data must immediately follow the address (an I2C
+* stop resets the internal address), and hence the minimum chunk size is
+* 1 <I2C address> + 4 (register address) + 2 (data to send) = 7 bytes (8 if
+* 10-bit I2C device addresses are used).
+*
+* The 7-bit or 10-bit i2c address parameters is a runtime parameter.
+* The other parameters can be limited via compile time switches.
+*
+*-------------------------------------------------------------------------------
+*
+* Minimum chunk size table (in bytes):
+*
+* +----------------+----------------+
+* | 7b i2c addr | 10b i2c addr |
+* +----------------+----------------+
+* | single | multi | single | multi |
+* ------+--------+-------+--------+-------+
+* short | 3 | 5 | 4 | 6 |
+* long | 5 | 7 | 6 | 8 |
+* ------+--------+-------+--------+-------+
+*
+*/
+
+/* set default */
+#if !defined(DRXDAP_MAX_WCHUNKSIZE)
+#define DRXDAP_MAX_WCHUNKSIZE 254
+#endif
+
+/* check */
+#if ((DRXDAPFASI_LONG_ADDR_ALLOWED == 0) && (DRXDAPFASI_SHORT_ADDR_ALLOWED == 1))
+#if DRXDAP_SINGLE_MASTER
+#define DRXDAP_MAX_WCHUNKSIZE_MIN 3
+#else
+#define DRXDAP_MAX_WCHUNKSIZE_MIN 5
+#endif
+#else
+#if DRXDAP_SINGLE_MASTER
+#define DRXDAP_MAX_WCHUNKSIZE_MIN 5
+#else
+#define DRXDAP_MAX_WCHUNKSIZE_MIN 7
+#endif
+#endif
+
+#if DRXDAP_MAX_WCHUNKSIZE < DRXDAP_MAX_WCHUNKSIZE_MIN
+#if ((DRXDAPFASI_LONG_ADDR_ALLOWED == 0) && (DRXDAPFASI_SHORT_ADDR_ALLOWED == 1))
+#if DRXDAP_SINGLE_MASTER
+#error DRXDAP_MAX_WCHUNKSIZE must be at least 3 in single master mode
+*; /* illegal statement to force compiler error */
+#else
+#error DRXDAP_MAX_WCHUNKSIZE must be at least 5 in multi master mode
+*; /* illegal statement to force compiler error */
+#endif
+#else
+#if DRXDAP_SINGLE_MASTER
+#error DRXDAP_MAX_WCHUNKSIZE must be at least 5 in single master mode
+*; /* illegal statement to force compiler error */
+#else
+#error DRXDAP_MAX_WCHUNKSIZE must be at least 7 in multi master mode
+*; /* illegal statement to force compiler error */
+#endif
+#endif
+#endif
+
+/* set default */
+#if !defined(DRXDAP_MAX_RCHUNKSIZE)
+#define DRXDAP_MAX_RCHUNKSIZE 254
+#endif
+
+/* check */
+#if DRXDAP_MAX_RCHUNKSIZE < 2
+#error DRXDAP_MAX_RCHUNKSIZE must be at least 2
+*; /* illegal statement to force compiler error */
+#endif
+
+/* check */
+#if DRXDAP_MAX_RCHUNKSIZE & 1
+#error DRXDAP_MAX_RCHUNKSIZE must be even
+*; /* illegal statement to force compiler error */
+#endif
+
+/*-------- Public API functions ----------------------------------------------*/
+
+extern struct drx_access_func drx_dap_fasi_funct_g;
+
+#define DRXDAP_FASI_RMW 0x10000000
+#define DRXDAP_FASI_BROADCAST 0x20000000
+#define DRXDAP_FASI_CLEARCRC 0x80000000
+#define DRXDAP_FASI_SINGLE_MASTER 0xC0000000
+#define DRXDAP_FASI_MULTI_MASTER 0x40000000
+#define DRXDAP_FASI_SMM_SWITCH 0x40000000 /* single/multi master switch */
+#define DRXDAP_FASI_MODEFLAGS 0xC0000000
+#define DRXDAP_FASI_FLAGS 0xF0000000
+
+#define DRXDAP_FASI_ADDR2BLOCK(addr) (((addr)>>22)&0x3F)
+#define DRXDAP_FASI_ADDR2BANK(addr) (((addr)>>16)&0x3F)
+#define DRXDAP_FASI_ADDR2OFFSET(addr) ((addr)&0x7FFF)
+
+#define DRXDAP_FASI_SHORT_FORMAT(addr) (((addr) & 0xFC30FF80) == 0)
+#define DRXDAP_FASI_LONG_FORMAT(addr) (((addr) & 0xFC30FF80) != 0)
+#define DRXDAP_FASI_OFFSET_TOO_LARGE(addr) (((addr) & 0x00008000) != 0)
+
+#endif /* __DRX_DAP_FASI_H__ */
diff --git a/drivers/media/dvb-frontends/drx39xyj/drx_driver.h b/drivers/media/dvb-frontends/drx39xyj/drx_driver.h
new file mode 100644
index 000000000000..9076bf21cc8a
--- /dev/null
+++ b/drivers/media/dvb-frontends/drx39xyj/drx_driver.h
@@ -0,0 +1,2343 @@
+/*
+ Copyright (c), 2004-2005,2007-2010 Trident Microsystems, Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Trident Microsystems nor Hauppauge Computer Works
+ nor the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ 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 HOLDER 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.
+*/
+
+#ifndef __DRXDRIVER_H__
+#define __DRXDRIVER_H__
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+
+/*
+ * This structure contains the I2C address, the device ID and a user_data pointer.
+ * The user_data pointer can be used for application specific purposes.
+ */
+struct i2c_device_addr {
+ u16 i2c_addr; /* The I2C address of the device. */
+ u16 i2c_dev_id; /* The device identifier. */
+ void *user_data; /* User data pointer */
+};
+
+/**
+* \def IS_I2C_10BIT( addr )
+* \brief Determine if I2C address 'addr' is a 10 bits address or not.
+* \param addr The I2C address.
+* \return int.
+* \retval 0 if address is not a 10 bits I2C address.
+* \retval 1 if address is a 10 bits I2C address.
+*/
+#define IS_I2C_10BIT(addr) \
+ (((addr) & 0xF8) == 0xF0)
+
+/*------------------------------------------------------------------------------
+Exported FUNCTIONS
+------------------------------------------------------------------------------*/
+
+/**
+* \fn drxbsp_i2c_init()
+* \brief Initialize I2C communication module.
+* \return int Return status.
+* \retval 0 Initialization successful.
+* \retval -EIO Initialization failed.
+*/
+int drxbsp_i2c_init(void);
+
+/**
+* \fn drxbsp_i2c_term()
+* \brief Terminate I2C communication module.
+* \return int Return status.
+* \retval 0 Termination successful.
+* \retval -EIO Termination failed.
+*/
+int drxbsp_i2c_term(void);
+
+/**
+* \fn int drxbsp_i2c_write_read( struct i2c_device_addr *w_dev_addr,
+* u16 w_count,
+* u8 * wData,
+* struct i2c_device_addr *r_dev_addr,
+* u16 r_count,
+* u8 * r_data)
+* \brief Read and/or write count bytes from I2C bus, store them in data[].
+* \param w_dev_addr The device i2c address and the device ID to write to
+* \param w_count The number of bytes to write
+* \param wData The array to write the data to
+* \param r_dev_addr The device i2c address and the device ID to read from
+* \param r_count The number of bytes to read
+* \param r_data The array to read the data from
+* \return int Return status.
+* \retval 0 Succes.
+* \retval -EIO Failure.
+* \retval -EINVAL Parameter 'wcount' is not zero but parameter
+* 'wdata' contains NULL.
+* Idem for 'rcount' and 'rdata'.
+* Both w_dev_addr and r_dev_addr are NULL.
+*
+* This function must implement an atomic write and/or read action on the I2C bus
+* No other process may use the I2C bus when this function is executing.
+* The critical section of this function runs from and including the I2C
+* write, up to and including the I2C read action.
+*
+* The device ID can be useful if several devices share an I2C address.
+* It can be used to control a "switch" on the I2C bus to the correct device.
+*/
+int drxbsp_i2c_write_read(struct i2c_device_addr *w_dev_addr,
+ u16 w_count,
+ u8 *wData,
+ struct i2c_device_addr *r_dev_addr,
+ u16 r_count, u8 *r_data);
+
+/**
+* \fn drxbsp_i2c_error_text()
+* \brief Returns a human readable error.
+* Counter part of numerical drx_i2c_error_g.
+*
+* \return char* Pointer to human readable error text.
+*/
+char *drxbsp_i2c_error_text(void);
+
+/**
+* \var drx_i2c_error_g;
+* \brief I2C specific error codes, platform dependent.
+*/
+extern int drx_i2c_error_g;
+
+#define TUNER_MODE_SUB0 0x0001 /* for sub-mode (e.g. RF-AGC setting) */
+#define TUNER_MODE_SUB1 0x0002 /* for sub-mode (e.g. RF-AGC setting) */
+#define TUNER_MODE_SUB2 0x0004 /* for sub-mode (e.g. RF-AGC setting) */
+#define TUNER_MODE_SUB3 0x0008 /* for sub-mode (e.g. RF-AGC setting) */
+#define TUNER_MODE_SUB4 0x0010 /* for sub-mode (e.g. RF-AGC setting) */
+#define TUNER_MODE_SUB5 0x0020 /* for sub-mode (e.g. RF-AGC setting) */
+#define TUNER_MODE_SUB6 0x0040 /* for sub-mode (e.g. RF-AGC setting) */
+#define TUNER_MODE_SUB7 0x0080 /* for sub-mode (e.g. RF-AGC setting) */
+
+#define TUNER_MODE_DIGITAL 0x0100 /* for digital channel (e.g. DVB-T) */
+#define TUNER_MODE_ANALOG 0x0200 /* for analog channel (e.g. PAL) */
+#define TUNER_MODE_SWITCH 0x0400 /* during channel switch & scanning */
+#define TUNER_MODE_LOCK 0x0800 /* after tuner has locked */
+#define TUNER_MODE_6MHZ 0x1000 /* for 6MHz bandwidth channels */
+#define TUNER_MODE_7MHZ 0x2000 /* for 7MHz bandwidth channels */
+#define TUNER_MODE_8MHZ 0x4000 /* for 8MHz bandwidth channels */
+
+#define TUNER_MODE_SUB_MAX 8
+#define TUNER_MODE_SUBALL (TUNER_MODE_SUB0 | TUNER_MODE_SUB1 | \
+ TUNER_MODE_SUB2 | TUNER_MODE_SUB3 | \
+ TUNER_MODE_SUB4 | TUNER_MODE_SUB5 | \
+ TUNER_MODE_SUB6 | TUNER_MODE_SUB7)
+
+
+enum tuner_lock_status {
+ TUNER_LOCKED,
+ TUNER_NOT_LOCKED
+};
+
+struct tuner_common {
+ char *name; /* Tuner brand & type name */
+ s32 min_freq_rf; /* Lowest RF input frequency, in kHz */
+ s32 max_freq_rf; /* Highest RF input frequency, in kHz */
+
+ u8 sub_mode; /* Index to sub-mode in use */
+ char ***sub_mode_descriptions; /* Pointer to description of sub-modes */
+ u8 sub_modes; /* Number of available sub-modes */
+
+ /* The following fields will be either 0, NULL or false and do not need
+ initialisation */
+ void *self_check; /* gives proof of initialization */
+ bool programmed; /* only valid if self_check is OK */
+ s32 r_ffrequency; /* only valid if programmed */
+ s32 i_ffrequency; /* only valid if programmed */
+
+ void *my_user_data; /* pointer to associated demod instance */
+ u16 my_capabilities; /* value for storing application flags */
+};
+
+struct tuner_instance;
+
+typedef int(*tuner_open_func_t) (struct tuner_instance *tuner);
+typedef int(*tuner_close_func_t) (struct tuner_instance *tuner);
+
+typedef int(*tuner_set_frequency_func_t) (struct tuner_instance *tuner,
+ u32 mode,
+ s32
+ frequency);
+
+typedef int(*tuner_get_frequency_func_t) (struct tuner_instance *tuner,
+ u32 mode,
+ s32 *
+ r_ffrequency,
+ s32 *
+ i_ffrequency);
+
+typedef int(*tuner_lock_status_func_t) (struct tuner_instance *tuner,
+ enum tuner_lock_status *
+ lock_stat);
+
+typedef int(*tune_ri2c_write_read_func_t) (struct tuner_instance *tuner,
+ struct i2c_device_addr *
+ w_dev_addr, u16 w_count,
+ u8 *wData,
+ struct i2c_device_addr *
+ r_dev_addr, u16 r_count,
+ u8 *r_data);
+
+struct tuner_ops {
+ tuner_open_func_t open_func;
+ tuner_close_func_t close_func;
+ tuner_set_frequency_func_t set_frequency_func;
+ tuner_get_frequency_func_t get_frequency_func;
+ tuner_lock_status_func_t lock_status_func;
+ tune_ri2c_write_read_func_t i2c_write_read_func;
+
+};
+
+struct tuner_instance {
+ struct i2c_device_addr my_i2c_dev_addr;
+ struct tuner_common *my_common_attr;
+ void *my_ext_attr;
+ struct tuner_ops *my_funct;
+};
+
+int drxbsp_tuner_set_frequency(struct tuner_instance *tuner,
+ u32 mode,
+ s32 frequency);
+
+int drxbsp_tuner_get_frequency(struct tuner_instance *tuner,
+ u32 mode,
+ s32 *r_ffrequency,
+ s32 *i_ffrequency);
+
+int drxbsp_tuner_default_i2c_write_read(struct tuner_instance *tuner,
+ struct i2c_device_addr *w_dev_addr,
+ u16 w_count,
+ u8 *wData,
+ struct i2c_device_addr *r_dev_addr,
+ u16 r_count, u8 *r_data);
+
+/**************
+*
+* This section configures the DRX Data Access Protocols (DAPs).
+*
+**************/
+
+/**
+* \def DRXDAP_SINGLE_MASTER
+* \brief Enable I2C single or I2C multimaster mode on host.
+*
+* Set to 1 to enable single master mode
+* Set to 0 to enable multi master mode
+*
+* The actual DAP implementation may be restricted to only one of the modes.
+* A compiler warning or error will be generated if the DAP implementation
+* overides or cannot handle the mode defined below.
+*
+*/
+#ifndef DRXDAP_SINGLE_MASTER
+#define DRXDAP_SINGLE_MASTER 1
+#endif
+
+/**
+* \def DRXDAP_MAX_WCHUNKSIZE
+* \brief Defines maximum chunksize of an i2c write action by host.
+*
+* This indicates the maximum size of data the I2C device driver is able to
+* write at a time. This includes I2C device address and register addressing.
+*
+* This maximum size may be restricted by the actual DAP implementation.
+* A compiler warning or error will be generated if the DAP implementation
+* overides or cannot handle the chunksize defined below.
+*
+* Beware that the DAP uses DRXDAP_MAX_WCHUNKSIZE to create a temporary data
+* buffer. Do not undefine or choose too large, unless your system is able to
+* handle a stack buffer of that size.
+*
+*/
+#ifndef DRXDAP_MAX_WCHUNKSIZE
+#define DRXDAP_MAX_WCHUNKSIZE 60
+#endif
+
+/**
+* \def DRXDAP_MAX_RCHUNKSIZE
+* \brief Defines maximum chunksize of an i2c read action by host.
+*
+* This indicates the maximum size of data the I2C device driver is able to read
+* at a time. Minimum value is 2. Also, the read chunk size must be even.
+*
+* This maximum size may be restricted by the actual DAP implementation.
+* A compiler warning or error will be generated if the DAP implementation
+* overides or cannot handle the chunksize defined below.
+*
+*/
+#ifndef DRXDAP_MAX_RCHUNKSIZE
+#define DRXDAP_MAX_RCHUNKSIZE 60
+#endif
+
+/**************
+*
+* This section describes drxdriver defines.
+*
+**************/
+
+/**
+* \def DRX_UNKNOWN
+* \brief Generic UNKNOWN value for DRX enumerated types.
+*
+* Used to indicate that the parameter value is unknown or not yet initalized.
+*/
+#ifndef DRX_UNKNOWN
+#define DRX_UNKNOWN (254)
+#endif
+
+/**
+* \def DRX_AUTO
+* \brief Generic AUTO value for DRX enumerated types.
+*
+* Used to instruct the driver to automatically determine the value of the
+* parameter.
+*/
+#ifndef DRX_AUTO
+#define DRX_AUTO (255)
+#endif
+
+/**************
+*
+* This section describes flag definitions for the device capbilities.
+*
+**************/
+
+/**
+* \brief LNA capability flag
+*
+* Device has a Low Noise Amplifier
+*
+*/
+#define DRX_CAPABILITY_HAS_LNA (1UL << 0)
+/**
+* \brief OOB-RX capability flag
+*
+* Device has OOB-RX
+*
+*/
+#define DRX_CAPABILITY_HAS_OOBRX (1UL << 1)
+/**
+* \brief ATV capability flag
+*
+* Device has ATV
+*
+*/
+#define DRX_CAPABILITY_HAS_ATV (1UL << 2)
+/**
+* \brief DVB-T capability flag
+*
+* Device has DVB-T
+*
+*/
+#define DRX_CAPABILITY_HAS_DVBT (1UL << 3)
+/**
+* \brief ITU-B capability flag
+*
+* Device has ITU-B
+*
+*/
+#define DRX_CAPABILITY_HAS_ITUB (1UL << 4)
+/**
+* \brief Audio capability flag
+*
+* Device has Audio
+*
+*/
+#define DRX_CAPABILITY_HAS_AUD (1UL << 5)
+/**
+* \brief SAW switch capability flag
+*
+* Device has SAW switch
+*
+*/
+#define DRX_CAPABILITY_HAS_SAWSW (1UL << 6)
+/**
+* \brief GPIO1 capability flag
+*
+* Device has GPIO1
+*
+*/
+#define DRX_CAPABILITY_HAS_GPIO1 (1UL << 7)
+/**
+* \brief GPIO2 capability flag
+*
+* Device has GPIO2
+*
+*/
+#define DRX_CAPABILITY_HAS_GPIO2 (1UL << 8)
+/**
+* \brief IRQN capability flag
+*
+* Device has IRQN
+*
+*/
+#define DRX_CAPABILITY_HAS_IRQN (1UL << 9)
+/**
+* \brief 8VSB capability flag
+*
+* Device has 8VSB
+*
+*/
+#define DRX_CAPABILITY_HAS_8VSB (1UL << 10)
+/**
+* \brief SMA-TX capability flag
+*
+* Device has SMATX
+*
+*/
+#define DRX_CAPABILITY_HAS_SMATX (1UL << 11)
+/**
+* \brief SMA-RX capability flag
+*
+* Device has SMARX
+*
+*/
+#define DRX_CAPABILITY_HAS_SMARX (1UL << 12)
+/**
+* \brief ITU-A/C capability flag
+*
+* Device has ITU-A/C
+*
+*/
+#define DRX_CAPABILITY_HAS_ITUAC (1UL << 13)
+
+/*-------------------------------------------------------------------------
+MACROS
+-------------------------------------------------------------------------*/
+/* Macros to stringify the version number */
+#define DRX_VERSIONSTRING(MAJOR, MINOR, PATCH) \
+ DRX_VERSIONSTRING_HELP(MAJOR)"." \
+ DRX_VERSIONSTRING_HELP(MINOR)"." \
+ DRX_VERSIONSTRING_HELP(PATCH)
+#define DRX_VERSIONSTRING_HELP(NUM) #NUM
+
+/**
+* \brief Macro to create byte array elements from 16 bit integers.
+* This macro is used to create byte arrays for block writes.
+* Block writes speed up I2C traffic between host and demod.
+* The macro takes care of the required byte order in a 16 bits word.
+* x->lowbyte(x), highbyte(x)
+*/
+#define DRX_16TO8(x) ((u8) (((u16)x) & 0xFF)), \
+ ((u8)((((u16)x)>>8)&0xFF))
+
+/**
+* \brief Macro to sign extend signed 9 bit value to signed 16 bit value
+*/
+#define DRX_S9TOS16(x) ((((u16)x)&0x100) ? ((s16)((u16)(x)|0xFF00)) : (x))
+
+/**
+* \brief Macro to sign extend signed 9 bit value to signed 16 bit value
+*/
+#define DRX_S24TODRXFREQ(x) ((((u32) x) & 0x00800000UL) ? \
+ ((s32) \
+ (((u32) x) | 0xFF000000)) : \
+ ((s32) x))
+
+/**
+* \brief Macro to convert 16 bit register value to a s32
+*/
+#define DRX_U16TODRXFREQ(x) ((x & 0x8000) ? \
+ ((s32) \
+ (((u32) x) | 0xFFFF0000)) : \
+ ((s32) x))
+
+/*-------------------------------------------------------------------------
+ENUM
+-------------------------------------------------------------------------*/
+
+/**
+* \enum enum drx_standard
+* \brief Modulation standards.
+*/
+enum drx_standard {
+ DRX_STANDARD_DVBT = 0, /**< Terrestrial DVB-T. */
+ DRX_STANDARD_8VSB, /**< Terrestrial 8VSB. */
+ DRX_STANDARD_NTSC, /**< Terrestrial\Cable analog NTSC. */
+ DRX_STANDARD_PAL_SECAM_BG,
+ /**< Terrestrial analog PAL/SECAM B/G */
+ DRX_STANDARD_PAL_SECAM_DK,
+ /**< Terrestrial analog PAL/SECAM D/K */
+ DRX_STANDARD_PAL_SECAM_I,
+ /**< Terrestrial analog PAL/SECAM I */
+ DRX_STANDARD_PAL_SECAM_L,
+ /**< Terrestrial analog PAL/SECAM L
+ with negative modulation */
+ DRX_STANDARD_PAL_SECAM_LP,
+ /**< Terrestrial analog PAL/SECAM L
+ with positive modulation */
+ DRX_STANDARD_ITU_A, /**< Cable ITU ANNEX A. */
+ DRX_STANDARD_ITU_B, /**< Cable ITU ANNEX B. */
+ DRX_STANDARD_ITU_C, /**< Cable ITU ANNEX C. */
+ DRX_STANDARD_ITU_D, /**< Cable ITU ANNEX D. */
+ DRX_STANDARD_FM, /**< Terrestrial\Cable FM radio */
+ DRX_STANDARD_DTMB, /**< Terrestrial DTMB standard (China)*/
+ DRX_STANDARD_UNKNOWN = DRX_UNKNOWN,
+ /**< Standard unknown. */
+ DRX_STANDARD_AUTO = DRX_AUTO
+ /**< Autodetect standard. */
+};
+
+/**
+* \enum enum drx_standard
+* \brief Modulation sub-standards.
+*/
+enum drx_substandard {
+ DRX_SUBSTANDARD_MAIN = 0, /**< Main subvariant of standard */
+ DRX_SUBSTANDARD_ATV_BG_SCANDINAVIA,
+ DRX_SUBSTANDARD_ATV_DK_POLAND,
+ DRX_SUBSTANDARD_ATV_DK_CHINA,
+ DRX_SUBSTANDARD_UNKNOWN = DRX_UNKNOWN,
+ /**< Sub-standard unknown. */
+ DRX_SUBSTANDARD_AUTO = DRX_AUTO
+ /**< Auto (default) sub-standard */
+};
+
+/**
+* \enum enum drx_bandwidth
+* \brief Channel bandwidth or channel spacing.
+*/
+enum drx_bandwidth {
+ DRX_BANDWIDTH_8MHZ = 0, /**< Bandwidth 8 MHz. */
+ DRX_BANDWIDTH_7MHZ, /**< Bandwidth 7 MHz. */
+ DRX_BANDWIDTH_6MHZ, /**< Bandwidth 6 MHz. */
+ DRX_BANDWIDTH_UNKNOWN = DRX_UNKNOWN,
+ /**< Bandwidth unknown. */
+ DRX_BANDWIDTH_AUTO = DRX_AUTO
+ /**< Auto Set Bandwidth */
+};
+
+/**
+* \enum enum drx_mirror
+* \brief Indicate if channel spectrum is mirrored or not.
+*/
+enum drx_mirror {
+ DRX_MIRROR_NO = 0, /**< Spectrum is not mirrored. */
+ DRX_MIRROR_YES, /**< Spectrum is mirrored. */
+ DRX_MIRROR_UNKNOWN = DRX_UNKNOWN,
+ /**< Unknown if spectrum is mirrored. */
+ DRX_MIRROR_AUTO = DRX_AUTO
+ /**< Autodetect if spectrum is mirrored. */
+};
+
+/**
+* \enum enum drx_modulation
+* \brief Constellation type of the channel.
+*/
+enum drx_modulation {
+ DRX_CONSTELLATION_BPSK = 0, /**< Modulation is BPSK. */
+ DRX_CONSTELLATION_QPSK, /**< Constellation is QPSK. */
+ DRX_CONSTELLATION_PSK8, /**< Constellation is PSK8. */
+ DRX_CONSTELLATION_QAM16, /**< Constellation is QAM16. */
+ DRX_CONSTELLATION_QAM32, /**< Constellation is QAM32. */
+ DRX_CONSTELLATION_QAM64, /**< Constellation is QAM64. */
+ DRX_CONSTELLATION_QAM128, /**< Constellation is QAM128. */
+ DRX_CONSTELLATION_QAM256, /**< Constellation is QAM256. */
+ DRX_CONSTELLATION_QAM512, /**< Constellation is QAM512. */
+ DRX_CONSTELLATION_QAM1024, /**< Constellation is QAM1024. */
+ DRX_CONSTELLATION_QPSK_NR, /**< Constellation is QPSK_NR */
+ DRX_CONSTELLATION_UNKNOWN = DRX_UNKNOWN,
+ /**< Constellation unknown. */
+ DRX_CONSTELLATION_AUTO = DRX_AUTO
+ /**< Autodetect constellation. */
+};
+
+/**
+* \enum enum drx_hierarchy
+* \brief Hierarchy of the channel.
+*/
+enum drx_hierarchy {
+ DRX_HIERARCHY_NONE = 0, /**< None hierarchical channel. */
+ DRX_HIERARCHY_ALPHA1, /**< Hierarchical channel, alpha=1. */
+ DRX_HIERARCHY_ALPHA2, /**< Hierarchical channel, alpha=2. */
+ DRX_HIERARCHY_ALPHA4, /**< Hierarchical channel, alpha=4. */
+ DRX_HIERARCHY_UNKNOWN = DRX_UNKNOWN,
+ /**< Hierarchy unknown. */
+ DRX_HIERARCHY_AUTO = DRX_AUTO
+ /**< Autodetect hierarchy. */
+};
+
+/**
+* \enum enum drx_priority
+* \brief Channel priority in case of hierarchical transmission.
+*/
+enum drx_priority {
+ DRX_PRIORITY_LOW = 0, /**< Low priority channel. */
+ DRX_PRIORITY_HIGH, /**< High priority channel. */
+ DRX_PRIORITY_UNKNOWN = DRX_UNKNOWN
+ /**< Priority unknown. */
+};
+
+/**
+* \enum enum drx_coderate
+* \brief Channel priority in case of hierarchical transmission.
+*/
+enum drx_coderate {
+ DRX_CODERATE_1DIV2 = 0, /**< Code rate 1/2nd. */
+ DRX_CODERATE_2DIV3, /**< Code rate 2/3nd. */
+ DRX_CODERATE_3DIV4, /**< Code rate 3/4nd. */
+ DRX_CODERATE_5DIV6, /**< Code rate 5/6nd. */
+ DRX_CODERATE_7DIV8, /**< Code rate 7/8nd. */
+ DRX_CODERATE_UNKNOWN = DRX_UNKNOWN,
+ /**< Code rate unknown. */
+ DRX_CODERATE_AUTO = DRX_AUTO
+ /**< Autodetect code rate. */
+};
+
+/**
+* \enum enum drx_guard
+* \brief Guard interval of a channel.
+*/
+enum drx_guard {
+ DRX_GUARD_1DIV32 = 0, /**< Guard interval 1/32nd. */
+ DRX_GUARD_1DIV16, /**< Guard interval 1/16th. */
+ DRX_GUARD_1DIV8, /**< Guard interval 1/8th. */
+ DRX_GUARD_1DIV4, /**< Guard interval 1/4th. */
+ DRX_GUARD_UNKNOWN = DRX_UNKNOWN,
+ /**< Guard interval unknown. */
+ DRX_GUARD_AUTO = DRX_AUTO
+ /**< Autodetect guard interval. */
+};
+
+/**
+* \enum enum drx_fft_mode
+* \brief FFT mode.
+*/
+enum drx_fft_mode {
+ DRX_FFTMODE_2K = 0, /**< 2K FFT mode. */
+ DRX_FFTMODE_4K, /**< 4K FFT mode. */
+ DRX_FFTMODE_8K, /**< 8K FFT mode. */
+ DRX_FFTMODE_UNKNOWN = DRX_UNKNOWN,
+ /**< FFT mode unknown. */
+ DRX_FFTMODE_AUTO = DRX_AUTO
+ /**< Autodetect FFT mode. */
+};
+
+/**
+* \enum enum drx_classification
+* \brief Channel classification.
+*/
+enum drx_classification {
+ DRX_CLASSIFICATION_GAUSS = 0, /**< Gaussion noise. */
+ DRX_CLASSIFICATION_HVY_GAUSS, /**< Heavy Gaussion noise. */
+ DRX_CLASSIFICATION_COCHANNEL, /**< Co-channel. */
+ DRX_CLASSIFICATION_STATIC, /**< Static echo. */
+ DRX_CLASSIFICATION_MOVING, /**< Moving echo. */
+ DRX_CLASSIFICATION_ZERODB, /**< Zero dB echo. */
+ DRX_CLASSIFICATION_UNKNOWN = DRX_UNKNOWN,
+ /**< Unknown classification */
+ DRX_CLASSIFICATION_AUTO = DRX_AUTO
+ /**< Autodetect classification. */
+};
+
+/**
+* /enum enum drx_interleave_mode
+* /brief Interleave modes
+*/
+enum drx_interleave_mode {
+ DRX_INTERLEAVEMODE_I128_J1 = 0,
+ DRX_INTERLEAVEMODE_I128_J1_V2,
+ DRX_INTERLEAVEMODE_I128_J2,
+ DRX_INTERLEAVEMODE_I64_J2,
+ DRX_INTERLEAVEMODE_I128_J3,
+ DRX_INTERLEAVEMODE_I32_J4,
+ DRX_INTERLEAVEMODE_I128_J4,
+ DRX_INTERLEAVEMODE_I16_J8,
+ DRX_INTERLEAVEMODE_I128_J5,
+ DRX_INTERLEAVEMODE_I8_J16,
+ DRX_INTERLEAVEMODE_I128_J6,
+ DRX_INTERLEAVEMODE_RESERVED_11,
+ DRX_INTERLEAVEMODE_I128_J7,
+ DRX_INTERLEAVEMODE_RESERVED_13,
+ DRX_INTERLEAVEMODE_I128_J8,
+ DRX_INTERLEAVEMODE_RESERVED_15,
+ DRX_INTERLEAVEMODE_I12_J17,
+ DRX_INTERLEAVEMODE_I5_J4,
+ DRX_INTERLEAVEMODE_B52_M240,
+ DRX_INTERLEAVEMODE_B52_M720,
+ DRX_INTERLEAVEMODE_B52_M48,
+ DRX_INTERLEAVEMODE_B52_M0,
+ DRX_INTERLEAVEMODE_UNKNOWN = DRX_UNKNOWN,
+ /**< Unknown interleave mode */
+ DRX_INTERLEAVEMODE_AUTO = DRX_AUTO
+ /**< Autodetect interleave mode */
+};
+
+/**
+* \enum enum drx_carrier_mode
+* \brief Channel Carrier Mode.
+*/
+enum drx_carrier_mode {
+ DRX_CARRIER_MULTI = 0, /**< Multi carrier mode */
+ DRX_CARRIER_SINGLE, /**< Single carrier mode */
+ DRX_CARRIER_UNKNOWN = DRX_UNKNOWN,
+ /**< Carrier mode unknown. */
+ DRX_CARRIER_AUTO = DRX_AUTO /**< Autodetect carrier mode */
+};
+
+/**
+* \enum enum drx_frame_mode
+* \brief Channel Frame Mode.
+*/
+enum drx_frame_mode {
+ DRX_FRAMEMODE_420 = 0, /**< 420 with variable PN */
+ DRX_FRAMEMODE_595, /**< 595 */
+ DRX_FRAMEMODE_945, /**< 945 with variable PN */
+ DRX_FRAMEMODE_420_FIXED_PN,
+ /**< 420 with fixed PN */
+ DRX_FRAMEMODE_945_FIXED_PN,
+ /**< 945 with fixed PN */
+ DRX_FRAMEMODE_UNKNOWN = DRX_UNKNOWN,
+ /**< Frame mode unknown. */
+ DRX_FRAMEMODE_AUTO = DRX_AUTO
+ /**< Autodetect frame mode */
+};
+
+/**
+* \enum enum drx_tps_frame
+* \brief Frame number in current super-frame.
+*/
+enum drx_tps_frame {
+ DRX_TPS_FRAME1 = 0, /**< TPS frame 1. */
+ DRX_TPS_FRAME2, /**< TPS frame 2. */
+ DRX_TPS_FRAME3, /**< TPS frame 3. */
+ DRX_TPS_FRAME4, /**< TPS frame 4. */
+ DRX_TPS_FRAME_UNKNOWN = DRX_UNKNOWN
+ /**< TPS frame unknown. */
+};
+
+/**
+* \enum enum drx_ldpc
+* \brief TPS LDPC .
+*/
+enum drx_ldpc {
+ DRX_LDPC_0_4 = 0, /**< LDPC 0.4 */
+ DRX_LDPC_0_6, /**< LDPC 0.6 */
+ DRX_LDPC_0_8, /**< LDPC 0.8 */
+ DRX_LDPC_UNKNOWN = DRX_UNKNOWN,
+ /**< LDPC unknown. */
+ DRX_LDPC_AUTO = DRX_AUTO /**< Autodetect LDPC */
+};
+
+/**
+* \enum enum drx_pilot_mode
+* \brief Pilot modes in DTMB.
+*/
+enum drx_pilot_mode {
+ DRX_PILOT_ON = 0, /**< Pilot On */
+ DRX_PILOT_OFF, /**< Pilot Off */
+ DRX_PILOT_UNKNOWN = DRX_UNKNOWN,
+ /**< Pilot unknown. */
+ DRX_PILOT_AUTO = DRX_AUTO /**< Autodetect Pilot */
+};
+
+/**
+ * enum drxu_code_action - indicate if firmware has to be uploaded or verified.
+ * @UCODE_UPLOAD: Upload the microcode image to device
+ * @UCODE_VERIFY: Compare microcode image with code on device
+ */
+enum drxu_code_action {
+ UCODE_UPLOAD,
+ UCODE_VERIFY
+};
+
+/**
+* \enum enum drx_lock_status * \brief Used to reflect current lock status of demodulator.
+*
+* The generic lock states have device dependent semantics.
+
+ DRX_NEVER_LOCK = 0,
+ **< Device will never lock on this signal *
+ DRX_NOT_LOCKED,
+ **< Device has no lock at all *
+ DRX_LOCK_STATE_1,
+ **< Generic lock state *
+ DRX_LOCK_STATE_2,
+ **< Generic lock state *
+ DRX_LOCK_STATE_3,
+ **< Generic lock state *
+ DRX_LOCK_STATE_4,
+ **< Generic lock state *
+ DRX_LOCK_STATE_5,
+ **< Generic lock state *
+ DRX_LOCK_STATE_6,
+ **< Generic lock state *
+ DRX_LOCK_STATE_7,
+ **< Generic lock state *
+ DRX_LOCK_STATE_8,
+ **< Generic lock state *
+ DRX_LOCK_STATE_9,
+ **< Generic lock state *
+ DRX_LOCKED **< Device is in lock *
+*/
+
+enum drx_lock_status {
+ DRX_NEVER_LOCK = 0,
+ DRX_NOT_LOCKED,
+ DRX_LOCK_STATE_1,
+ DRX_LOCK_STATE_2,
+ DRX_LOCK_STATE_3,
+ DRX_LOCK_STATE_4,
+ DRX_LOCK_STATE_5,
+ DRX_LOCK_STATE_6,
+ DRX_LOCK_STATE_7,
+ DRX_LOCK_STATE_8,
+ DRX_LOCK_STATE_9,
+ DRX_LOCKED
+};
+
+/**
+* \enum enum drx_uio* \brief Used to address a User IO (UIO).
+*/
+enum drx_uio {
+ DRX_UIO1,
+ DRX_UIO2,
+ DRX_UIO3,
+ DRX_UIO4,
+ DRX_UIO5,
+ DRX_UIO6,
+ DRX_UIO7,
+ DRX_UIO8,
+ DRX_UIO9,
+ DRX_UIO10,
+ DRX_UIO11,
+ DRX_UIO12,
+ DRX_UIO13,
+ DRX_UIO14,
+ DRX_UIO15,
+ DRX_UIO16,
+ DRX_UIO17,
+ DRX_UIO18,
+ DRX_UIO19,
+ DRX_UIO20,
+ DRX_UIO21,
+ DRX_UIO22,
+ DRX_UIO23,
+ DRX_UIO24,
+ DRX_UIO25,
+ DRX_UIO26,
+ DRX_UIO27,
+ DRX_UIO28,
+ DRX_UIO29,
+ DRX_UIO30,
+ DRX_UIO31,
+ DRX_UIO32,
+ DRX_UIO_MAX = DRX_UIO32
+};
+
+/**
+* \enum enum drxuio_mode * \brief Used to configure the modus oprandi of a UIO.
+*
+* DRX_UIO_MODE_FIRMWARE is an old uio mode.
+* It is replaced by the modes DRX_UIO_MODE_FIRMWARE0 .. DRX_UIO_MODE_FIRMWARE9.
+* To be backward compatible DRX_UIO_MODE_FIRMWARE is equivalent to
+* DRX_UIO_MODE_FIRMWARE0.
+*/
+enum drxuio_mode {
+ DRX_UIO_MODE_DISABLE = 0x01,
+ /**< not used, pin is configured as input */
+ DRX_UIO_MODE_READWRITE = 0x02,
+ /**< used for read/write by application */
+ DRX_UIO_MODE_FIRMWARE = 0x04,
+ /**< controlled by firmware, function 0 */
+ DRX_UIO_MODE_FIRMWARE0 = DRX_UIO_MODE_FIRMWARE,
+ /**< same as above */
+ DRX_UIO_MODE_FIRMWARE1 = 0x08,
+ /**< controlled by firmware, function 1 */
+ DRX_UIO_MODE_FIRMWARE2 = 0x10,
+ /**< controlled by firmware, function 2 */
+ DRX_UIO_MODE_FIRMWARE3 = 0x20,
+ /**< controlled by firmware, function 3 */
+ DRX_UIO_MODE_FIRMWARE4 = 0x40,
+ /**< controlled by firmware, function 4 */
+ DRX_UIO_MODE_FIRMWARE5 = 0x80
+ /**< controlled by firmware, function 5 */
+};
+
+/**
+* \enum enum drxoob_downstream_standard * \brief Used to select OOB standard.
+*
+* Based on ANSI 55-1 and 55-2
+*/
+enum drxoob_downstream_standard {
+ DRX_OOB_MODE_A = 0,
+ /**< ANSI 55-1 */
+ DRX_OOB_MODE_B_GRADE_A,
+ /**< ANSI 55-2 A */
+ DRX_OOB_MODE_B_GRADE_B
+ /**< ANSI 55-2 B */
+};
+
+/*-------------------------------------------------------------------------
+STRUCTS
+-------------------------------------------------------------------------*/
+
+/*============================================================================*/
+/*============================================================================*/
+/*== CTRL CFG related data structures ========================================*/
+/*============================================================================*/
+/*============================================================================*/
+
+#ifndef DRX_CFG_BASE
+#define DRX_CFG_BASE 0
+#endif
+
+#define DRX_CFG_MPEG_OUTPUT (DRX_CFG_BASE + 0) /* MPEG TS output */
+#define DRX_CFG_PKTERR (DRX_CFG_BASE + 1) /* Packet Error */
+#define DRX_CFG_SYMCLK_OFFS (DRX_CFG_BASE + 2) /* Symbol Clk Offset */
+#define DRX_CFG_SMA (DRX_CFG_BASE + 3) /* Smart Antenna */
+#define DRX_CFG_PINSAFE (DRX_CFG_BASE + 4) /* Pin safe mode */
+#define DRX_CFG_SUBSTANDARD (DRX_CFG_BASE + 5) /* substandard */
+#define DRX_CFG_AUD_VOLUME (DRX_CFG_BASE + 6) /* volume */
+#define DRX_CFG_AUD_RDS (DRX_CFG_BASE + 7) /* rds */
+#define DRX_CFG_AUD_AUTOSOUND (DRX_CFG_BASE + 8) /* ASS & ASC */
+#define DRX_CFG_AUD_ASS_THRES (DRX_CFG_BASE + 9) /* ASS Thresholds */
+#define DRX_CFG_AUD_DEVIATION (DRX_CFG_BASE + 10) /* Deviation */
+#define DRX_CFG_AUD_PRESCALE (DRX_CFG_BASE + 11) /* Prescale */
+#define DRX_CFG_AUD_MIXER (DRX_CFG_BASE + 12) /* Mixer */
+#define DRX_CFG_AUD_AVSYNC (DRX_CFG_BASE + 13) /* AVSync */
+#define DRX_CFG_AUD_CARRIER (DRX_CFG_BASE + 14) /* Audio carriers */
+#define DRX_CFG_I2S_OUTPUT (DRX_CFG_BASE + 15) /* I2S output */
+#define DRX_CFG_ATV_STANDARD (DRX_CFG_BASE + 16) /* ATV standard */
+#define DRX_CFG_SQI_SPEED (DRX_CFG_BASE + 17) /* SQI speed */
+#define DRX_CTRL_CFG_MAX (DRX_CFG_BASE + 18) /* never to be used */
+
+#define DRX_CFG_PINS_SAFE_MODE DRX_CFG_PINSAFE
+/*============================================================================*/
+/*============================================================================*/
+/*== CTRL related data structures ============================================*/
+/*============================================================================*/
+/*============================================================================*/
+
+/**
+ * struct drxu_code_info Parameters for microcode upload and verfiy.
+ *
+ * @mc_file: microcode file name
+ *
+ * Used by DRX_CTRL_LOAD_UCODE and DRX_CTRL_VERIFY_UCODE
+ */
+struct drxu_code_info {
+ char *mc_file;
+};
+
+/**
+* \struct drx_mc_version_rec_t
+* \brief Microcode version record
+* Version numbers are stored in BCD format, as usual:
+* o major number = bits 31-20 (first three nibbles of MSW)
+* o minor number = bits 19-16 (fourth nibble of MSW)
+* o patch number = bits 15-0 (remaining nibbles in LSW)
+*
+* The device type indicates for which the device is meant. It is based on the
+* JTAG ID, using everything except the bond ID and the metal fix.
+*
+* Special values:
+* - mc_dev_type == 0 => any device allowed
+* - mc_base_version == 0.0.0 => full microcode (mc_version is the version)
+* - mc_base_version != 0.0.0 => patch microcode, the base microcode version
+* (mc_version is the version)
+*/
+#define AUX_VER_RECORD 0x8000
+
+struct drx_mc_version_rec {
+ u16 aux_type; /* type of aux data - 0x8000 for version record */
+ u32 mc_dev_type; /* device type, based on JTAG ID */
+ u32 mc_version; /* version of microcode */
+ u32 mc_base_version; /* in case of patch: the original microcode version */
+};
+
+/*========================================*/
+
+/**
+* \struct drx_filter_info_t
+* \brief Parameters for loading filter coefficients
+*
+* Used by DRX_CTRL_LOAD_FILTER
+*/
+struct drx_filter_info {
+ u8 *data_re;
+ /**< pointer to coefficients for RE */
+ u8 *data_im;
+ /**< pointer to coefficients for IM */
+ u16 size_re;
+ /**< size of coefficients for RE */
+ u16 size_im;
+ /**< size of coefficients for IM */
+};
+
+/*========================================*/
+
+/**
+* \struct struct drx_channel * \brief The set of parameters describing a single channel.
+*
+* Used by DRX_CTRL_SET_CHANNEL and DRX_CTRL_GET_CHANNEL.
+* Only certain fields need to be used for a specfic standard.
+*
+*/
+struct drx_channel {
+ s32 frequency;
+ /**< frequency in kHz */
+ enum drx_bandwidth bandwidth;
+ /**< bandwidth */
+ enum drx_mirror mirror; /**< mirrored or not on RF */
+ enum drx_modulation constellation;
+ /**< constellation */
+ enum drx_hierarchy hierarchy;
+ /**< hierarchy */
+ enum drx_priority priority; /**< priority */
+ enum drx_coderate coderate; /**< coderate */
+ enum drx_guard guard; /**< guard interval */
+ enum drx_fft_mode fftmode; /**< fftmode */
+ enum drx_classification classification;
+ /**< classification */
+ u32 symbolrate;
+ /**< symbolrate in symbols/sec */
+ enum drx_interleave_mode interleavemode;
+ /**< interleaveMode QAM */
+ enum drx_ldpc ldpc; /**< ldpc */
+ enum drx_carrier_mode carrier; /**< carrier */
+ enum drx_frame_mode framemode;
+ /**< frame mode */
+ enum drx_pilot_mode pilot; /**< pilot mode */
+};
+
+/*========================================*/
+
+enum drx_cfg_sqi_speed {
+ DRX_SQI_SPEED_FAST = 0,
+ DRX_SQI_SPEED_MEDIUM,
+ DRX_SQI_SPEED_SLOW,
+ DRX_SQI_SPEED_UNKNOWN = DRX_UNKNOWN
+};
+
+/*========================================*/
+
+/**
+* \struct struct drx_complex * A complex number.
+*
+* Used by DRX_CTRL_CONSTEL.
+*/
+struct drx_complex {
+ s16 im;
+ /**< Imaginary part. */
+ s16 re;
+ /**< Real part. */
+};
+
+/*========================================*/
+
+/**
+* \struct struct drx_frequency_plan * Array element of a frequency plan.
+*
+* Used by DRX_CTRL_SCAN_INIT.
+*/
+struct drx_frequency_plan {
+ s32 first;
+ /**< First centre frequency in this band */
+ s32 last;
+ /**< Last centre frequency in this band */
+ s32 step;
+ /**< Stepping frequency in this band */
+ enum drx_bandwidth bandwidth;
+ /**< Bandwidth within this frequency band */
+ u16 ch_number;
+ /**< First channel number in this band, or first
+ index in ch_names */
+ char **ch_names;
+ /**< Optional list of channel names in this
+ band */
+};
+
+/*========================================*/
+
+/**
+* \struct struct drx_scan_param * Parameters for channel scan.
+*
+* Used by DRX_CTRL_SCAN_INIT.
+*/
+struct drx_scan_param {
+ struct drx_frequency_plan *frequency_plan;
+ /**< Frequency plan (array)*/
+ u16 frequency_plan_size; /**< Number of bands */
+ u32 num_tries; /**< Max channels tried */
+ s32 skip; /**< Minimum frequency step to take
+ after a channel is found */
+ void *ext_params; /**< Standard specific params */
+};
+
+/*========================================*/
+
+/**
+* \brief Scan commands.
+* Used by scanning algorithms.
+*/
+enum drx_scan_command {
+ DRX_SCAN_COMMAND_INIT = 0,/**< Initialize scanning */
+ DRX_SCAN_COMMAND_NEXT, /**< Next scan */
+ DRX_SCAN_COMMAND_STOP /**< Stop scanning */
+};
+
+/*========================================*/
+
+/**
+* \brief Inner scan function prototype.
+*/
+typedef int(*drx_scan_func_t) (void *scan_context,
+ enum drx_scan_command scan_command,
+ struct drx_channel *scan_channel,
+ bool *get_next_channel);
+
+/*========================================*/
+
+/**
+* \struct struct drxtps_info * TPS information, DVB-T specific.
+*
+* Used by DRX_CTRL_TPS_INFO.
+*/
+ struct drxtps_info {
+ enum drx_fft_mode fftmode; /**< Fft mode */
+ enum drx_guard guard; /**< Guard interval */
+ enum drx_modulation constellation;
+ /**< Constellation */
+ enum drx_hierarchy hierarchy;
+ /**< Hierarchy */
+ enum drx_coderate high_coderate;
+ /**< High code rate */
+ enum drx_coderate low_coderate;
+ /**< Low cod rate */
+ enum drx_tps_frame frame; /**< Tps frame */
+ u8 length; /**< Length */
+ u16 cell_id; /**< Cell id */
+ };
+
+/*========================================*/
+
+/**
+* \brief Power mode of device.
+*
+* Used by DRX_CTRL_SET_POWER_MODE.
+*/
+ enum drx_power_mode {
+ DRX_POWER_UP = 0,
+ /**< Generic , Power Up Mode */
+ DRX_POWER_MODE_1,
+ /**< Device specific , Power Up Mode */
+ DRX_POWER_MODE_2,
+ /**< Device specific , Power Up Mode */
+ DRX_POWER_MODE_3,
+ /**< Device specific , Power Up Mode */
+ DRX_POWER_MODE_4,
+ /**< Device specific , Power Up Mode */
+ DRX_POWER_MODE_5,
+ /**< Device specific , Power Up Mode */
+ DRX_POWER_MODE_6,
+ /**< Device specific , Power Up Mode */
+ DRX_POWER_MODE_7,
+ /**< Device specific , Power Up Mode */
+ DRX_POWER_MODE_8,
+ /**< Device specific , Power Up Mode */
+
+ DRX_POWER_MODE_9,
+ /**< Device specific , Power Down Mode */
+ DRX_POWER_MODE_10,
+ /**< Device specific , Power Down Mode */
+ DRX_POWER_MODE_11,
+ /**< Device specific , Power Down Mode */
+ DRX_POWER_MODE_12,
+ /**< Device specific , Power Down Mode */
+ DRX_POWER_MODE_13,
+ /**< Device specific , Power Down Mode */
+ DRX_POWER_MODE_14,
+ /**< Device specific , Power Down Mode */
+ DRX_POWER_MODE_15,
+ /**< Device specific , Power Down Mode */
+ DRX_POWER_MODE_16,
+ /**< Device specific , Power Down Mode */
+ DRX_POWER_DOWN = 255
+ /**< Generic , Power Down Mode */
+ };
+
+/*========================================*/
+
+/**
+* \enum enum drx_module * \brief Software module identification.
+*
+* Used by DRX_CTRL_VERSION.
+*/
+ enum drx_module {
+ DRX_MODULE_DEVICE,
+ DRX_MODULE_MICROCODE,
+ DRX_MODULE_DRIVERCORE,
+ DRX_MODULE_DEVICEDRIVER,
+ DRX_MODULE_DAP,
+ DRX_MODULE_BSP_I2C,
+ DRX_MODULE_BSP_TUNER,
+ DRX_MODULE_BSP_HOST,
+ DRX_MODULE_UNKNOWN
+ };
+
+/**
+* \enum struct drx_version * \brief Version information of one software module.
+*
+* Used by DRX_CTRL_VERSION.
+*/
+ struct drx_version {
+ enum drx_module module_type;
+ /**< Type identifier of the module */
+ char *module_name;
+ /**< Name or description of module */
+ u16 v_major; /**< Major version number */
+ u16 v_minor; /**< Minor version number */
+ u16 v_patch; /**< Patch version number */
+ char *v_string; /**< Version as text string */
+ };
+
+/**
+* \enum struct drx_version_list * \brief List element of NULL terminated, linked list for version information.
+*
+* Used by DRX_CTRL_VERSION.
+*/
+struct drx_version_list {
+ struct drx_version *version;/**< Version information */
+ struct drx_version_list *next;
+ /**< Next list element */
+};
+
+/*========================================*/
+
+/**
+* \brief Parameters needed to confiugure a UIO.
+*
+* Used by DRX_CTRL_UIO_CFG.
+*/
+ struct drxuio_cfg {
+ enum drx_uio uio;
+ /**< UIO identifier */
+ enum drxuio_mode mode;
+ /**< UIO operational mode */
+ };
+
+/*========================================*/
+
+/**
+* \brief Parameters needed to read from or write to a UIO.
+*
+* Used by DRX_CTRL_UIO_READ and DRX_CTRL_UIO_WRITE.
+*/
+ struct drxuio_data {
+ enum drx_uio uio;
+ /**< UIO identifier */
+ bool value;
+ /**< UIO value (true=1, false=0) */
+ };
+
+/*========================================*/
+
+/**
+* \brief Parameters needed to configure OOB.
+*
+* Used by DRX_CTRL_SET_OOB.
+*/
+ struct drxoob {
+ s32 frequency; /**< Frequency in kHz */
+ enum drxoob_downstream_standard standard;
+ /**< OOB standard */
+ bool spectrum_inverted; /**< If true, then spectrum
+ is inverted */
+ };
+
+/*========================================*/
+
+/**
+* \brief Metrics from OOB.
+*
+* Used by DRX_CTRL_GET_OOB.
+*/
+ struct drxoob_status {
+ s32 frequency; /**< Frequency in Khz */
+ enum drx_lock_status lock; /**< Lock status */
+ u32 mer; /**< MER */
+ s32 symbol_rate_offset; /**< Symbolrate offset in ppm */
+ };
+
+/*========================================*/
+
+/**
+* \brief Device dependent configuration data.
+*
+* Used by DRX_CTRL_SET_CFG and DRX_CTRL_GET_CFG.
+* A sort of nested drx_ctrl() functionality for device specific controls.
+*/
+ struct drx_cfg {
+ u32 cfg_type;
+ /**< Function identifier */
+ void *cfg_data;
+ /**< Function data */
+ };
+
+/*========================================*/
+
+/**
+* /struct DRXMpegStartWidth_t
+* MStart width [nr MCLK cycles] for serial MPEG output.
+*/
+
+ enum drxmpeg_str_width {
+ DRX_MPEG_STR_WIDTH_1,
+ DRX_MPEG_STR_WIDTH_8
+ };
+
+/* CTRL CFG MPEG ouput */
+/**
+* \struct struct drx_cfg_mpeg_output * \brief Configuartion parameters for MPEG output control.
+*
+* Used by DRX_CFG_MPEG_OUTPUT, in combination with DRX_CTRL_SET_CFG and
+* DRX_CTRL_GET_CFG.
+*/
+
+ struct drx_cfg_mpeg_output {
+ bool enable_mpeg_output;/**< If true, enable MPEG output */
+ bool insert_rs_byte; /**< If true, insert RS byte */
+ bool enable_parallel; /**< If true, parallel out otherwise
+ serial */
+ bool invert_data; /**< If true, invert DATA signals */
+ bool invert_err; /**< If true, invert ERR signal */
+ bool invert_str; /**< If true, invert STR signals */
+ bool invert_val; /**< If true, invert VAL signals */
+ bool invert_clk; /**< If true, invert CLK signals */
+ bool static_clk; /**< If true, static MPEG clockrate
+ will be used, otherwise clockrate
+ will adapt to the bitrate of the
+ TS */
+ u32 bitrate; /**< Maximum bitrate in b/s in case
+ static clockrate is selected */
+ enum drxmpeg_str_width width_str;
+ /**< MPEG start width */
+ };
+
+
+/*========================================*/
+
+/**
+* \struct struct drxi2c_data * \brief Data for I2C via 2nd or 3rd or etc I2C port.
+*
+* Used by DRX_CTRL_I2C_READWRITE.
+* If port_nr is equal to primairy port_nr BSPI2C will be used.
+*
+*/
+ struct drxi2c_data {
+ u16 port_nr; /**< I2C port number */
+ struct i2c_device_addr *w_dev_addr;
+ /**< Write device address */
+ u16 w_count; /**< Size of write data in bytes */
+ u8 *wData; /**< Pointer to write data */
+ struct i2c_device_addr *r_dev_addr;
+ /**< Read device address */
+ u16 r_count; /**< Size of data to read in bytes */
+ u8 *r_data; /**< Pointer to read buffer */
+ };
+
+/*========================================*/
+
+/**
+* \enum enum drx_aud_standard * \brief Audio standard identifier.
+*
+* Used by DRX_CTRL_SET_AUD.
+*/
+ enum drx_aud_standard {
+ DRX_AUD_STANDARD_BTSC, /**< set BTSC standard (USA) */
+ DRX_AUD_STANDARD_A2, /**< set A2-Korea FM Stereo */
+ DRX_AUD_STANDARD_EIAJ, /**< set to Japanese FM Stereo */
+ DRX_AUD_STANDARD_FM_STEREO,/**< set to FM-Stereo Radio */
+ DRX_AUD_STANDARD_M_MONO, /**< for 4.5 MHz mono detected */
+ DRX_AUD_STANDARD_D_K_MONO, /**< for 6.5 MHz mono detected */
+ DRX_AUD_STANDARD_BG_FM, /**< set BG_FM standard */
+ DRX_AUD_STANDARD_D_K1, /**< set D_K1 standard */
+ DRX_AUD_STANDARD_D_K2, /**< set D_K2 standard */
+ DRX_AUD_STANDARD_D_K3, /**< set D_K3 standard */
+ DRX_AUD_STANDARD_BG_NICAM_FM,
+ /**< set BG_NICAM_FM standard */
+ DRX_AUD_STANDARD_L_NICAM_AM,
+ /**< set L_NICAM_AM standard */
+ DRX_AUD_STANDARD_I_NICAM_FM,
+ /**< set I_NICAM_FM standard */
+ DRX_AUD_STANDARD_D_K_NICAM_FM,
+ /**< set D_K_NICAM_FM standard */
+ DRX_AUD_STANDARD_NOT_READY,/**< used to detect audio standard */
+ DRX_AUD_STANDARD_AUTO = DRX_AUTO,
+ /**< Automatic Standard Detection */
+ DRX_AUD_STANDARD_UNKNOWN = DRX_UNKNOWN
+ /**< used as auto and for readback */
+ };
+
+/* CTRL_AUD_GET_STATUS - struct drx_aud_status */
+/**
+* \enum enum drx_aud_nicam_status * \brief Status of NICAM carrier.
+*/
+ enum drx_aud_nicam_status {
+ DRX_AUD_NICAM_DETECTED = 0,
+ /**< NICAM carrier detected */
+ DRX_AUD_NICAM_NOT_DETECTED,
+ /**< NICAM carrier not detected */
+ DRX_AUD_NICAM_BAD /**< NICAM carrier bad quality */
+ };
+
+/**
+* \struct struct drx_aud_status * \brief Audio status characteristics.
+*/
+ struct drx_aud_status {
+ bool stereo; /**< stereo detection */
+ bool carrier_a; /**< carrier A detected */
+ bool carrier_b; /**< carrier B detected */
+ bool sap; /**< sap / bilingual detection */
+ bool rds; /**< RDS data array present */
+ enum drx_aud_nicam_status nicam_status;
+ /**< status of NICAM carrier */
+ s8 fm_ident; /**< FM Identification value */
+ };
+
+/* CTRL_AUD_READ_RDS - DRXRDSdata_t */
+
+/**
+* \struct DRXRDSdata_t
+* \brief Raw RDS data array.
+*/
+ struct drx_cfg_aud_rds {
+ bool valid; /**< RDS data validation */
+ u16 data[18]; /**< data from one RDS data array */
+ };
+
+/* DRX_CFG_AUD_VOLUME - struct drx_cfg_aud_volume - set/get */
+/**
+* \enum DRXAudAVCDecayTime_t
+* \brief Automatic volume control configuration.
+*/
+ enum drx_aud_avc_mode {
+ DRX_AUD_AVC_OFF, /**< Automatic volume control off */
+ DRX_AUD_AVC_DECAYTIME_8S, /**< level volume in 8 seconds */
+ DRX_AUD_AVC_DECAYTIME_4S, /**< level volume in 4 seconds */
+ DRX_AUD_AVC_DECAYTIME_2S, /**< level volume in 2 seconds */
+ DRX_AUD_AVC_DECAYTIME_20MS/**< level volume in 20 millisec */
+ };
+
+/**
+* /enum DRXAudMaxAVCGain_t
+* /brief Automatic volume control max gain in audio baseband.
+*/
+ enum drx_aud_avc_max_gain {
+ DRX_AUD_AVC_MAX_GAIN_0DB, /**< maximum AVC gain 0 dB */
+ DRX_AUD_AVC_MAX_GAIN_6DB, /**< maximum AVC gain 6 dB */
+ DRX_AUD_AVC_MAX_GAIN_12DB /**< maximum AVC gain 12 dB */
+ };
+
+/**
+* /enum DRXAudMaxAVCAtten_t
+* /brief Automatic volume control max attenuation in audio baseband.
+*/
+ enum drx_aud_avc_max_atten {
+ DRX_AUD_AVC_MAX_ATTEN_12DB,
+ /**< maximum AVC attenuation 12 dB */
+ DRX_AUD_AVC_MAX_ATTEN_18DB,
+ /**< maximum AVC attenuation 18 dB */
+ DRX_AUD_AVC_MAX_ATTEN_24DB/**< maximum AVC attenuation 24 dB */
+ };
+/**
+* \struct struct drx_cfg_aud_volume * \brief Audio volume configuration.
+*/
+ struct drx_cfg_aud_volume {
+ bool mute; /**< mute overrides volume setting */
+ s16 volume; /**< volume, range -114 to 12 dB */
+ enum drx_aud_avc_mode avc_mode; /**< AVC auto volume control mode */
+ u16 avc_ref_level; /**< AVC reference level */
+ enum drx_aud_avc_max_gain avc_max_gain;
+ /**< AVC max gain selection */
+ enum drx_aud_avc_max_atten avc_max_atten;
+ /**< AVC max attenuation selection */
+ s16 strength_left; /**< quasi-peak, left speaker */
+ s16 strength_right; /**< quasi-peak, right speaker */
+ };
+
+/* DRX_CFG_I2S_OUTPUT - struct drx_cfg_i2s_output - set/get */
+/**
+* \enum enum drxi2s_mode * \brief I2S output mode.
+*/
+ enum drxi2s_mode {
+ DRX_I2S_MODE_MASTER, /**< I2S is in master mode */
+ DRX_I2S_MODE_SLAVE /**< I2S is in slave mode */
+ };
+
+/**
+* \enum enum drxi2s_word_length * \brief Width of I2S data.
+*/
+ enum drxi2s_word_length {
+ DRX_I2S_WORDLENGTH_32 = 0,/**< I2S data is 32 bit wide */
+ DRX_I2S_WORDLENGTH_16 = 1 /**< I2S data is 16 bit wide */
+ };
+
+/**
+* \enum enum drxi2s_format * \brief Data wordstrobe alignment for I2S.
+*/
+ enum drxi2s_format {
+ DRX_I2S_FORMAT_WS_WITH_DATA,
+ /**< I2S data and wordstrobe are aligned */
+ DRX_I2S_FORMAT_WS_ADVANCED
+ /**< I2S data one cycle after wordstrobe */
+ };
+
+/**
+* \enum enum drxi2s_polarity * \brief Polarity of I2S data.
+*/
+ enum drxi2s_polarity {
+ DRX_I2S_POLARITY_RIGHT,/**< wordstrobe - right high, left low */
+ DRX_I2S_POLARITY_LEFT /**< wordstrobe - right low, left high */
+ };
+
+/**
+* \struct struct drx_cfg_i2s_output * \brief I2S output configuration.
+*/
+ struct drx_cfg_i2s_output {
+ bool output_enable; /**< I2S output enable */
+ u32 frequency; /**< range from 8000-48000 Hz */
+ enum drxi2s_mode mode; /**< I2S mode, master or slave */
+ enum drxi2s_word_length word_length;
+ /**< I2S wordlength, 16 or 32 bits */
+ enum drxi2s_polarity polarity;/**< I2S wordstrobe polarity */
+ enum drxi2s_format format; /**< I2S wordstrobe delay to data */
+ };
+
+/* ------------------------------expert interface-----------------------------*/
+/**
+* /enum enum drx_aud_fm_deemphasis * setting for FM-Deemphasis in audio demodulator.
+*
+*/
+ enum drx_aud_fm_deemphasis {
+ DRX_AUD_FM_DEEMPH_50US,
+ DRX_AUD_FM_DEEMPH_75US,
+ DRX_AUD_FM_DEEMPH_OFF
+ };
+
+/**
+* /enum DRXAudDeviation_t
+* setting for deviation mode in audio demodulator.
+*
+*/
+ enum drx_cfg_aud_deviation {
+ DRX_AUD_DEVIATION_NORMAL,
+ DRX_AUD_DEVIATION_HIGH
+ };
+
+/**
+* /enum enum drx_no_carrier_option * setting for carrier, mute/noise.
+*
+*/
+ enum drx_no_carrier_option {
+ DRX_NO_CARRIER_MUTE,
+ DRX_NO_CARRIER_NOISE
+ };
+
+/**
+* \enum DRXAudAutoSound_t
+* \brief Automatic Sound
+*/
+ enum drx_cfg_aud_auto_sound {
+ DRX_AUD_AUTO_SOUND_OFF = 0,
+ DRX_AUD_AUTO_SOUND_SELECT_ON_CHANGE_ON,
+ DRX_AUD_AUTO_SOUND_SELECT_ON_CHANGE_OFF
+ };
+
+/**
+* \enum DRXAudASSThres_t
+* \brief Automatic Sound Select Thresholds
+*/
+ struct drx_cfg_aud_ass_thres {
+ u16 a2; /* A2 Threshold for ASS configuration */
+ u16 btsc; /* BTSC Threshold for ASS configuration */
+ u16 nicam; /* Nicam Threshold for ASS configuration */
+ };
+
+/**
+* \struct struct drx_aud_carrier * \brief Carrier detection related parameters
+*/
+ struct drx_aud_carrier {
+ u16 thres; /* carrier detetcion threshold for primary carrier (A) */
+ enum drx_no_carrier_option opt; /* Mute or noise at no carrier detection (A) */
+ s32 shift; /* DC level of incoming signal (A) */
+ s32 dco; /* frequency adjustment (A) */
+ };
+
+/**
+* \struct struct drx_cfg_aud_carriers * \brief combining carrier A & B to one struct
+*/
+ struct drx_cfg_aud_carriers {
+ struct drx_aud_carrier a;
+ struct drx_aud_carrier b;
+ };
+
+/**
+* /enum enum drx_aud_i2s_src * Selection of audio source
+*/
+ enum drx_aud_i2s_src {
+ DRX_AUD_SRC_MONO,
+ DRX_AUD_SRC_STEREO_OR_AB,
+ DRX_AUD_SRC_STEREO_OR_A,
+ DRX_AUD_SRC_STEREO_OR_B};
+
+/**
+* \enum enum drx_aud_i2s_matrix * \brief Used for selecting I2S output.
+*/
+ enum drx_aud_i2s_matrix {
+ DRX_AUD_I2S_MATRIX_A_MONO,
+ /**< A sound only, stereo or mono */
+ DRX_AUD_I2S_MATRIX_B_MONO,
+ /**< B sound only, stereo or mono */
+ DRX_AUD_I2S_MATRIX_STEREO,
+ /**< A+B sound, transparant */
+ DRX_AUD_I2S_MATRIX_MONO /**< A+B mixed to mono sum, (L+R)/2 */};
+
+/**
+* /enum enum drx_aud_fm_matrix * setting for FM-Matrix in audio demodulator.
+*
+*/
+ enum drx_aud_fm_matrix {
+ DRX_AUD_FM_MATRIX_NO_MATRIX,
+ DRX_AUD_FM_MATRIX_GERMAN,
+ DRX_AUD_FM_MATRIX_KOREAN,
+ DRX_AUD_FM_MATRIX_SOUND_A,
+ DRX_AUD_FM_MATRIX_SOUND_B};
+
+/**
+* \struct DRXAudMatrices_t
+* \brief Mixer settings
+*/
+struct drx_cfg_aud_mixer {
+ enum drx_aud_i2s_src source_i2s;
+ enum drx_aud_i2s_matrix matrix_i2s;
+ enum drx_aud_fm_matrix matrix_fm;
+};
+
+/**
+* \enum DRXI2SVidSync_t
+* \brief Audio/video synchronization, interacts with I2S mode.
+* AUTO_1 and AUTO_2 are for automatic video standard detection with preference
+* for NTSC or Monochrome, because the frequencies are too close (59.94 & 60 Hz)
+*/
+ enum drx_cfg_aud_av_sync {
+ DRX_AUD_AVSYNC_OFF,/**< audio/video synchronization is off */
+ DRX_AUD_AVSYNC_NTSC,
+ /**< it is an NTSC system */
+ DRX_AUD_AVSYNC_MONOCHROME,
+ /**< it is a MONOCHROME system */
+ DRX_AUD_AVSYNC_PAL_SECAM
+ /**< it is a PAL/SECAM system */};
+
+/**
+* \struct struct drx_cfg_aud_prescale * \brief Prescalers
+*/
+struct drx_cfg_aud_prescale {
+ u16 fm_deviation;
+ s16 nicam_gain;
+};
+
+/**
+* \struct struct drx_aud_beep * \brief Beep
+*/
+struct drx_aud_beep {
+ s16 volume; /* dB */
+ u16 frequency; /* Hz */
+ bool mute;
+};
+
+/**
+* \enum enum drx_aud_btsc_detect * \brief BTSC detetcion mode
+*/
+ enum drx_aud_btsc_detect {
+ DRX_BTSC_STEREO,
+ DRX_BTSC_MONO_AND_SAP};
+
+/**
+* \struct struct drx_aud_data * \brief Audio data structure
+*/
+struct drx_aud_data {
+ /* audio storage */
+ bool audio_is_active;
+ enum drx_aud_standard audio_standard;
+ struct drx_cfg_i2s_output i2sdata;
+ struct drx_cfg_aud_volume volume;
+ enum drx_cfg_aud_auto_sound auto_sound;
+ struct drx_cfg_aud_ass_thres ass_thresholds;
+ struct drx_cfg_aud_carriers carriers;
+ struct drx_cfg_aud_mixer mixer;
+ enum drx_cfg_aud_deviation deviation;
+ enum drx_cfg_aud_av_sync av_sync;
+ struct drx_cfg_aud_prescale prescale;
+ enum drx_aud_fm_deemphasis deemph;
+ enum drx_aud_btsc_detect btsc_detect;
+ /* rds */
+ u16 rds_data_counter;
+ bool rds_data_present;
+};
+
+/**
+* \enum enum drx_qam_lock_range * \brief QAM lock range mode
+*/
+ enum drx_qam_lock_range {
+ DRX_QAM_LOCKRANGE_NORMAL,
+ DRX_QAM_LOCKRANGE_EXTENDED};
+
+/*============================================================================*/
+/*============================================================================*/
+/*== Data access structures ==================================================*/
+/*============================================================================*/
+/*============================================================================*/
+
+/* Address on device */
+ typedef u32 dr_xaddr_t, *pdr_xaddr_t;
+
+/* Protocol specific flags */
+ typedef u32 dr_xflags_t, *pdr_xflags_t;
+
+/* Write block of data to device */
+ typedef int(*drx_write_block_func_t) (struct i2c_device_addr *dev_addr, /* address of I2C device */
+ u32 addr, /* address of register/memory */
+ u16 datasize, /* size of data in bytes */
+ u8 *data, /* data to send */
+ u32 flags);
+
+/* Read block of data from device */
+ typedef int(*drx_read_block_func_t) (struct i2c_device_addr *dev_addr, /* address of I2C device */
+ u32 addr, /* address of register/memory */
+ u16 datasize, /* size of data in bytes */
+ u8 *data, /* receive buffer */
+ u32 flags);
+
+/* Write 8-bits value to device */
+ typedef int(*drx_write_reg8func_t) (struct i2c_device_addr *dev_addr, /* address of I2C device */
+ u32 addr, /* address of register/memory */
+ u8 data, /* data to send */
+ u32 flags);
+
+/* Read 8-bits value to device */
+ typedef int(*drx_read_reg8func_t) (struct i2c_device_addr *dev_addr, /* address of I2C device */
+ u32 addr, /* address of register/memory */
+ u8 *data, /* receive buffer */
+ u32 flags);
+
+/* Read modify write 8-bits value to device */
+ typedef int(*drx_read_modify_write_reg8func_t) (struct i2c_device_addr *dev_addr, /* address of I2C device */
+ u32 waddr, /* write address of register */
+ u32 raddr, /* read address of register */
+ u8 wdata, /* data to write */
+ u8 *rdata); /* data to read */
+
+/* Write 16-bits value to device */
+ typedef int(*drx_write_reg16func_t) (struct i2c_device_addr *dev_addr, /* address of I2C device */
+ u32 addr, /* address of register/memory */
+ u16 data, /* data to send */
+ u32 flags);
+
+/* Read 16-bits value to device */
+ typedef int(*drx_read_reg16func_t) (struct i2c_device_addr *dev_addr, /* address of I2C device */
+ u32 addr, /* address of register/memory */
+ u16 *data, /* receive buffer */
+ u32 flags);
+
+/* Read modify write 16-bits value to device */
+ typedef int(*drx_read_modify_write_reg16func_t) (struct i2c_device_addr *dev_addr, /* address of I2C device */
+ u32 waddr, /* write address of register */
+ u32 raddr, /* read address of register */
+ u16 wdata, /* data to write */
+ u16 *rdata); /* data to read */
+
+/* Write 32-bits value to device */
+ typedef int(*drx_write_reg32func_t) (struct i2c_device_addr *dev_addr, /* address of I2C device */
+ u32 addr, /* address of register/memory */
+ u32 data, /* data to send */
+ u32 flags);
+
+/* Read 32-bits value to device */
+ typedef int(*drx_read_reg32func_t) (struct i2c_device_addr *dev_addr, /* address of I2C device */
+ u32 addr, /* address of register/memory */
+ u32 *data, /* receive buffer */
+ u32 flags);
+
+/* Read modify write 32-bits value to device */
+ typedef int(*drx_read_modify_write_reg32func_t) (struct i2c_device_addr *dev_addr, /* address of I2C device */
+ u32 waddr, /* write address of register */
+ u32 raddr, /* read address of register */
+ u32 wdata, /* data to write */
+ u32 *rdata); /* data to read */
+
+/**
+* \struct struct drx_access_func * \brief Interface to an access protocol.
+*/
+struct drx_access_func {
+ drx_write_block_func_t write_block_func;
+ drx_read_block_func_t read_block_func;
+ drx_write_reg8func_t write_reg8func;
+ drx_read_reg8func_t read_reg8func;
+ drx_read_modify_write_reg8func_t read_modify_write_reg8func;
+ drx_write_reg16func_t write_reg16func;
+ drx_read_reg16func_t read_reg16func;
+ drx_read_modify_write_reg16func_t read_modify_write_reg16func;
+ drx_write_reg32func_t write_reg32func;
+ drx_read_reg32func_t read_reg32func;
+ drx_read_modify_write_reg32func_t read_modify_write_reg32func;
+};
+
+/* Register address and data for register dump function */
+struct drx_reg_dump {
+ u32 address;
+ u32 data;
+};
+
+/*============================================================================*/
+/*============================================================================*/
+/*== Demod instance data structures ==========================================*/
+/*============================================================================*/
+/*============================================================================*/
+
+/**
+* \struct struct drx_common_attr * \brief Set of common attributes, shared by all DRX devices.
+*/
+ struct drx_common_attr {
+ /* Microcode (firmware) attributes */
+ char *microcode_file; /**< microcode filename */
+ bool verify_microcode;
+ /**< Use microcode verify or not. */
+ struct drx_mc_version_rec mcversion;
+ /**< Version record of microcode from file */
+
+ /* Clocks and tuner attributes */
+ s32 intermediate_freq;
+ /**< IF,if tuner instance not used. (kHz)*/
+ s32 sys_clock_freq;
+ /**< Systemclock frequency. (kHz) */
+ s32 osc_clock_freq;
+ /**< Oscillator clock frequency. (kHz) */
+ s16 osc_clock_deviation;
+ /**< Oscillator clock deviation. (ppm) */
+ bool mirror_freq_spect;
+ /**< Mirror IF frequency spectrum or not.*/
+
+ /* Initial MPEG output attributes */
+ struct drx_cfg_mpeg_output mpeg_cfg;
+ /**< MPEG configuration */
+
+ bool is_opened; /**< if true instance is already opened. */
+
+ /* Channel scan */
+ struct drx_scan_param *scan_param;
+ /**< scan parameters */
+ u16 scan_freq_plan_index;
+ /**< next index in freq plan */
+ s32 scan_next_frequency;
+ /**< next freq to scan */
+ bool scan_ready; /**< scan ready flag */
+ u32 scan_max_channels;/**< number of channels in freqplan */
+ u32 scan_channels_scanned;
+ /**< number of channels scanned */
+ /* Channel scan - inner loop: demod related */
+ drx_scan_func_t scan_function;
+ /**< function to check channel */
+ /* Channel scan - inner loop: SYSObj related */
+ void *scan_context; /**< Context Pointer of SYSObj */
+ /* Channel scan - parameters for default DTV scan function in core driver */
+ u16 scan_demod_lock_timeout;
+ /**< millisecs to wait for lock */
+ enum drx_lock_status scan_desired_lock;
+ /**< lock requirement for channel found */
+ /* scan_active can be used by SetChannel to decide how to program the tuner,
+ fast or slow (but stable). Usually fast during scan. */
+ bool scan_active; /**< true when scan routines are active */
+
+ /* Power management */
+ enum drx_power_mode current_power_mode;
+ /**< current power management mode */
+
+ /* Tuner */
+ u8 tuner_port_nr; /**< nr of I2C port to wich tuner is */
+ s32 tuner_min_freq_rf;
+ /**< minimum RF input frequency, in kHz */
+ s32 tuner_max_freq_rf;
+ /**< maximum RF input frequency, in kHz */
+ bool tuner_rf_agc_pol; /**< if true invert RF AGC polarity */
+ bool tuner_if_agc_pol; /**< if true invert IF AGC polarity */
+ bool tuner_slow_mode; /**< if true invert IF AGC polarity */
+
+ struct drx_channel current_channel;
+ /**< current channel parameters */
+ enum drx_standard current_standard;
+ /**< current standard selection */
+ enum drx_standard prev_standard;
+ /**< previous standard selection */
+ enum drx_standard di_cache_standard;
+ /**< standard in DI cache if available */
+ bool use_bootloader; /**< use bootloader in open */
+ u32 capabilities; /**< capabilities flags */
+ u32 product_id; /**< product ID inc. metal fix number */};
+
+/*
+* Generic functions for DRX devices.
+*/
+
+struct drx_demod_instance;
+
+/**
+* \struct struct drx_demod_instance * \brief Top structure of demodulator instance.
+*/
+struct drx_demod_instance {
+ /**< data access protocol functions */
+ struct i2c_device_addr *my_i2c_dev_addr;
+ /**< i2c address and device identifier */
+ struct drx_common_attr *my_common_attr;
+ /**< common DRX attributes */
+ void *my_ext_attr; /**< device specific attributes */
+ /* generic demodulator data */
+
+ struct i2c_adapter *i2c;
+ const struct firmware *firmware;
+};
+
+/*-------------------------------------------------------------------------
+MACROS
+Conversion from enum values to human readable form.
+-------------------------------------------------------------------------*/
+
+/* standard */
+
+#define DRX_STR_STANDARD(x) ( \
+ (x == DRX_STANDARD_DVBT) ? "DVB-T" : \
+ (x == DRX_STANDARD_8VSB) ? "8VSB" : \
+ (x == DRX_STANDARD_NTSC) ? "NTSC" : \
+ (x == DRX_STANDARD_PAL_SECAM_BG) ? "PAL/SECAM B/G" : \
+ (x == DRX_STANDARD_PAL_SECAM_DK) ? "PAL/SECAM D/K" : \
+ (x == DRX_STANDARD_PAL_SECAM_I) ? "PAL/SECAM I" : \
+ (x == DRX_STANDARD_PAL_SECAM_L) ? "PAL/SECAM L" : \
+ (x == DRX_STANDARD_PAL_SECAM_LP) ? "PAL/SECAM LP" : \
+ (x == DRX_STANDARD_ITU_A) ? "ITU-A" : \
+ (x == DRX_STANDARD_ITU_B) ? "ITU-B" : \
+ (x == DRX_STANDARD_ITU_C) ? "ITU-C" : \
+ (x == DRX_STANDARD_ITU_D) ? "ITU-D" : \
+ (x == DRX_STANDARD_FM) ? "FM" : \
+ (x == DRX_STANDARD_DTMB) ? "DTMB" : \
+ (x == DRX_STANDARD_AUTO) ? "Auto" : \
+ (x == DRX_STANDARD_UNKNOWN) ? "Unknown" : \
+ "(Invalid)")
+
+/* channel */
+
+#define DRX_STR_BANDWIDTH(x) ( \
+ (x == DRX_BANDWIDTH_8MHZ) ? "8 MHz" : \
+ (x == DRX_BANDWIDTH_7MHZ) ? "7 MHz" : \
+ (x == DRX_BANDWIDTH_6MHZ) ? "6 MHz" : \
+ (x == DRX_BANDWIDTH_AUTO) ? "Auto" : \
+ (x == DRX_BANDWIDTH_UNKNOWN) ? "Unknown" : \
+ "(Invalid)")
+#define DRX_STR_FFTMODE(x) ( \
+ (x == DRX_FFTMODE_2K) ? "2k" : \
+ (x == DRX_FFTMODE_4K) ? "4k" : \
+ (x == DRX_FFTMODE_8K) ? "8k" : \
+ (x == DRX_FFTMODE_AUTO) ? "Auto" : \
+ (x == DRX_FFTMODE_UNKNOWN) ? "Unknown" : \
+ "(Invalid)")
+#define DRX_STR_GUARD(x) ( \
+ (x == DRX_GUARD_1DIV32) ? "1/32nd" : \
+ (x == DRX_GUARD_1DIV16) ? "1/16th" : \
+ (x == DRX_GUARD_1DIV8) ? "1/8th" : \
+ (x == DRX_GUARD_1DIV4) ? "1/4th" : \
+ (x == DRX_GUARD_AUTO) ? "Auto" : \
+ (x == DRX_GUARD_UNKNOWN) ? "Unknown" : \
+ "(Invalid)")
+#define DRX_STR_CONSTELLATION(x) ( \
+ (x == DRX_CONSTELLATION_BPSK) ? "BPSK" : \
+ (x == DRX_CONSTELLATION_QPSK) ? "QPSK" : \
+ (x == DRX_CONSTELLATION_PSK8) ? "PSK8" : \
+ (x == DRX_CONSTELLATION_QAM16) ? "QAM16" : \
+ (x == DRX_CONSTELLATION_QAM32) ? "QAM32" : \
+ (x == DRX_CONSTELLATION_QAM64) ? "QAM64" : \
+ (x == DRX_CONSTELLATION_QAM128) ? "QAM128" : \
+ (x == DRX_CONSTELLATION_QAM256) ? "QAM256" : \
+ (x == DRX_CONSTELLATION_QAM512) ? "QAM512" : \
+ (x == DRX_CONSTELLATION_QAM1024) ? "QAM1024" : \
+ (x == DRX_CONSTELLATION_QPSK_NR) ? "QPSK_NR" : \
+ (x == DRX_CONSTELLATION_AUTO) ? "Auto" : \
+ (x == DRX_CONSTELLATION_UNKNOWN) ? "Unknown" : \
+ "(Invalid)")
+#define DRX_STR_CODERATE(x) ( \
+ (x == DRX_CODERATE_1DIV2) ? "1/2nd" : \
+ (x == DRX_CODERATE_2DIV3) ? "2/3rd" : \
+ (x == DRX_CODERATE_3DIV4) ? "3/4th" : \
+ (x == DRX_CODERATE_5DIV6) ? "5/6th" : \
+ (x == DRX_CODERATE_7DIV8) ? "7/8th" : \
+ (x == DRX_CODERATE_AUTO) ? "Auto" : \
+ (x == DRX_CODERATE_UNKNOWN) ? "Unknown" : \
+ "(Invalid)")
+#define DRX_STR_HIERARCHY(x) ( \
+ (x == DRX_HIERARCHY_NONE) ? "None" : \
+ (x == DRX_HIERARCHY_ALPHA1) ? "Alpha=1" : \
+ (x == DRX_HIERARCHY_ALPHA2) ? "Alpha=2" : \
+ (x == DRX_HIERARCHY_ALPHA4) ? "Alpha=4" : \
+ (x == DRX_HIERARCHY_AUTO) ? "Auto" : \
+ (x == DRX_HIERARCHY_UNKNOWN) ? "Unknown" : \
+ "(Invalid)")
+#define DRX_STR_PRIORITY(x) ( \
+ (x == DRX_PRIORITY_LOW) ? "Low" : \
+ (x == DRX_PRIORITY_HIGH) ? "High" : \
+ (x == DRX_PRIORITY_UNKNOWN) ? "Unknown" : \
+ "(Invalid)")
+#define DRX_STR_MIRROR(x) ( \
+ (x == DRX_MIRROR_NO) ? "Normal" : \
+ (x == DRX_MIRROR_YES) ? "Mirrored" : \
+ (x == DRX_MIRROR_AUTO) ? "Auto" : \
+ (x == DRX_MIRROR_UNKNOWN) ? "Unknown" : \
+ "(Invalid)")
+#define DRX_STR_CLASSIFICATION(x) ( \
+ (x == DRX_CLASSIFICATION_GAUSS) ? "Gaussion" : \
+ (x == DRX_CLASSIFICATION_HVY_GAUSS) ? "Heavy Gaussion" : \
+ (x == DRX_CLASSIFICATION_COCHANNEL) ? "Co-channel" : \
+ (x == DRX_CLASSIFICATION_STATIC) ? "Static echo" : \
+ (x == DRX_CLASSIFICATION_MOVING) ? "Moving echo" : \
+ (x == DRX_CLASSIFICATION_ZERODB) ? "Zero dB echo" : \
+ (x == DRX_CLASSIFICATION_UNKNOWN) ? "Unknown" : \
+ (x == DRX_CLASSIFICATION_AUTO) ? "Auto" : \
+ "(Invalid)")
+
+#define DRX_STR_INTERLEAVEMODE(x) ( \
+ (x == DRX_INTERLEAVEMODE_I128_J1) ? "I128_J1" : \
+ (x == DRX_INTERLEAVEMODE_I128_J1_V2) ? "I128_J1_V2" : \
+ (x == DRX_INTERLEAVEMODE_I128_J2) ? "I128_J2" : \
+ (x == DRX_INTERLEAVEMODE_I64_J2) ? "I64_J2" : \
+ (x == DRX_INTERLEAVEMODE_I128_J3) ? "I128_J3" : \
+ (x == DRX_INTERLEAVEMODE_I32_J4) ? "I32_J4" : \
+ (x == DRX_INTERLEAVEMODE_I128_J4) ? "I128_J4" : \
+ (x == DRX_INTERLEAVEMODE_I16_J8) ? "I16_J8" : \
+ (x == DRX_INTERLEAVEMODE_I128_J5) ? "I128_J5" : \
+ (x == DRX_INTERLEAVEMODE_I8_J16) ? "I8_J16" : \
+ (x == DRX_INTERLEAVEMODE_I128_J6) ? "I128_J6" : \
+ (x == DRX_INTERLEAVEMODE_RESERVED_11) ? "Reserved 11" : \
+ (x == DRX_INTERLEAVEMODE_I128_J7) ? "I128_J7" : \
+ (x == DRX_INTERLEAVEMODE_RESERVED_13) ? "Reserved 13" : \
+ (x == DRX_INTERLEAVEMODE_I128_J8) ? "I128_J8" : \
+ (x == DRX_INTERLEAVEMODE_RESERVED_15) ? "Reserved 15" : \
+ (x == DRX_INTERLEAVEMODE_I12_J17) ? "I12_J17" : \
+ (x == DRX_INTERLEAVEMODE_I5_J4) ? "I5_J4" : \
+ (x == DRX_INTERLEAVEMODE_B52_M240) ? "B52_M240" : \
+ (x == DRX_INTERLEAVEMODE_B52_M720) ? "B52_M720" : \
+ (x == DRX_INTERLEAVEMODE_B52_M48) ? "B52_M48" : \
+ (x == DRX_INTERLEAVEMODE_B52_M0) ? "B52_M0" : \
+ (x == DRX_INTERLEAVEMODE_UNKNOWN) ? "Unknown" : \
+ (x == DRX_INTERLEAVEMODE_AUTO) ? "Auto" : \
+ "(Invalid)")
+
+#define DRX_STR_LDPC(x) ( \
+ (x == DRX_LDPC_0_4) ? "0.4" : \
+ (x == DRX_LDPC_0_6) ? "0.6" : \
+ (x == DRX_LDPC_0_8) ? "0.8" : \
+ (x == DRX_LDPC_AUTO) ? "Auto" : \
+ (x == DRX_LDPC_UNKNOWN) ? "Unknown" : \
+ "(Invalid)")
+
+#define DRX_STR_CARRIER(x) ( \
+ (x == DRX_CARRIER_MULTI) ? "Multi" : \
+ (x == DRX_CARRIER_SINGLE) ? "Single" : \
+ (x == DRX_CARRIER_AUTO) ? "Auto" : \
+ (x == DRX_CARRIER_UNKNOWN) ? "Unknown" : \
+ "(Invalid)")
+
+#define DRX_STR_FRAMEMODE(x) ( \
+ (x == DRX_FRAMEMODE_420) ? "420" : \
+ (x == DRX_FRAMEMODE_595) ? "595" : \
+ (x == DRX_FRAMEMODE_945) ? "945" : \
+ (x == DRX_FRAMEMODE_420_FIXED_PN) ? "420 with fixed PN" : \
+ (x == DRX_FRAMEMODE_945_FIXED_PN) ? "945 with fixed PN" : \
+ (x == DRX_FRAMEMODE_AUTO) ? "Auto" : \
+ (x == DRX_FRAMEMODE_UNKNOWN) ? "Unknown" : \
+ "(Invalid)")
+
+#define DRX_STR_PILOT(x) ( \
+ (x == DRX_PILOT_ON) ? "On" : \
+ (x == DRX_PILOT_OFF) ? "Off" : \
+ (x == DRX_PILOT_AUTO) ? "Auto" : \
+ (x == DRX_PILOT_UNKNOWN) ? "Unknown" : \
+ "(Invalid)")
+/* TPS */
+
+#define DRX_STR_TPS_FRAME(x) ( \
+ (x == DRX_TPS_FRAME1) ? "Frame1" : \
+ (x == DRX_TPS_FRAME2) ? "Frame2" : \
+ (x == DRX_TPS_FRAME3) ? "Frame3" : \
+ (x == DRX_TPS_FRAME4) ? "Frame4" : \
+ (x == DRX_TPS_FRAME_UNKNOWN) ? "Unknown" : \
+ "(Invalid)")
+
+/* lock status */
+
+#define DRX_STR_LOCKSTATUS(x) ( \
+ (x == DRX_NEVER_LOCK) ? "Never" : \
+ (x == DRX_NOT_LOCKED) ? "No" : \
+ (x == DRX_LOCKED) ? "Locked" : \
+ (x == DRX_LOCK_STATE_1) ? "Lock state 1" : \
+ (x == DRX_LOCK_STATE_2) ? "Lock state 2" : \
+ (x == DRX_LOCK_STATE_3) ? "Lock state 3" : \
+ (x == DRX_LOCK_STATE_4) ? "Lock state 4" : \
+ (x == DRX_LOCK_STATE_5) ? "Lock state 5" : \
+ (x == DRX_LOCK_STATE_6) ? "Lock state 6" : \
+ (x == DRX_LOCK_STATE_7) ? "Lock state 7" : \
+ (x == DRX_LOCK_STATE_8) ? "Lock state 8" : \
+ (x == DRX_LOCK_STATE_9) ? "Lock state 9" : \
+ "(Invalid)")
+
+/* version information , modules */
+#define DRX_STR_MODULE(x) ( \
+ (x == DRX_MODULE_DEVICE) ? "Device" : \
+ (x == DRX_MODULE_MICROCODE) ? "Microcode" : \
+ (x == DRX_MODULE_DRIVERCORE) ? "CoreDriver" : \
+ (x == DRX_MODULE_DEVICEDRIVER) ? "DeviceDriver" : \
+ (x == DRX_MODULE_BSP_I2C) ? "BSP I2C" : \
+ (x == DRX_MODULE_BSP_TUNER) ? "BSP Tuner" : \
+ (x == DRX_MODULE_BSP_HOST) ? "BSP Host" : \
+ (x == DRX_MODULE_DAP) ? "Data Access Protocol" : \
+ (x == DRX_MODULE_UNKNOWN) ? "Unknown" : \
+ "(Invalid)")
+
+#define DRX_STR_POWER_MODE(x) ( \
+ (x == DRX_POWER_UP) ? "DRX_POWER_UP " : \
+ (x == DRX_POWER_MODE_1) ? "DRX_POWER_MODE_1" : \
+ (x == DRX_POWER_MODE_2) ? "DRX_POWER_MODE_2" : \
+ (x == DRX_POWER_MODE_3) ? "DRX_POWER_MODE_3" : \
+ (x == DRX_POWER_MODE_4) ? "DRX_POWER_MODE_4" : \
+ (x == DRX_POWER_MODE_5) ? "DRX_POWER_MODE_5" : \
+ (x == DRX_POWER_MODE_6) ? "DRX_POWER_MODE_6" : \
+ (x == DRX_POWER_MODE_7) ? "DRX_POWER_MODE_7" : \
+ (x == DRX_POWER_MODE_8) ? "DRX_POWER_MODE_8" : \
+ (x == DRX_POWER_MODE_9) ? "DRX_POWER_MODE_9" : \
+ (x == DRX_POWER_MODE_10) ? "DRX_POWER_MODE_10" : \
+ (x == DRX_POWER_MODE_11) ? "DRX_POWER_MODE_11" : \
+ (x == DRX_POWER_MODE_12) ? "DRX_POWER_MODE_12" : \
+ (x == DRX_POWER_MODE_13) ? "DRX_POWER_MODE_13" : \
+ (x == DRX_POWER_MODE_14) ? "DRX_POWER_MODE_14" : \
+ (x == DRX_POWER_MODE_15) ? "DRX_POWER_MODE_15" : \
+ (x == DRX_POWER_MODE_16) ? "DRX_POWER_MODE_16" : \
+ (x == DRX_POWER_DOWN) ? "DRX_POWER_DOWN " : \
+ "(Invalid)")
+
+#define DRX_STR_OOB_STANDARD(x) ( \
+ (x == DRX_OOB_MODE_A) ? "ANSI 55-1 " : \
+ (x == DRX_OOB_MODE_B_GRADE_A) ? "ANSI 55-2 A" : \
+ (x == DRX_OOB_MODE_B_GRADE_B) ? "ANSI 55-2 B" : \
+ "(Invalid)")
+
+#define DRX_STR_AUD_STANDARD(x) ( \
+ (x == DRX_AUD_STANDARD_BTSC) ? "BTSC" : \
+ (x == DRX_AUD_STANDARD_A2) ? "A2" : \
+ (x == DRX_AUD_STANDARD_EIAJ) ? "EIAJ" : \
+ (x == DRX_AUD_STANDARD_FM_STEREO) ? "FM Stereo" : \
+ (x == DRX_AUD_STANDARD_AUTO) ? "Auto" : \
+ (x == DRX_AUD_STANDARD_M_MONO) ? "M-Standard Mono" : \
+ (x == DRX_AUD_STANDARD_D_K_MONO) ? "D/K Mono FM" : \
+ (x == DRX_AUD_STANDARD_BG_FM) ? "B/G-Dual Carrier FM (A2)" : \
+ (x == DRX_AUD_STANDARD_D_K1) ? "D/K1-Dual Carrier FM" : \
+ (x == DRX_AUD_STANDARD_D_K2) ? "D/K2-Dual Carrier FM" : \
+ (x == DRX_AUD_STANDARD_D_K3) ? "D/K3-Dual Carrier FM" : \
+ (x == DRX_AUD_STANDARD_BG_NICAM_FM) ? "B/G-NICAM-FM" : \
+ (x == DRX_AUD_STANDARD_L_NICAM_AM) ? "L-NICAM-AM" : \
+ (x == DRX_AUD_STANDARD_I_NICAM_FM) ? "I-NICAM-FM" : \
+ (x == DRX_AUD_STANDARD_D_K_NICAM_FM) ? "D/K-NICAM-FM" : \
+ (x == DRX_AUD_STANDARD_UNKNOWN) ? "Unknown" : \
+ "(Invalid)")
+#define DRX_STR_AUD_STEREO(x) ( \
+ (x == true) ? "Stereo" : \
+ (x == false) ? "Mono" : \
+ "(Invalid)")
+
+#define DRX_STR_AUD_SAP(x) ( \
+ (x == true) ? "Present" : \
+ (x == false) ? "Not present" : \
+ "(Invalid)")
+
+#define DRX_STR_AUD_CARRIER(x) ( \
+ (x == true) ? "Present" : \
+ (x == false) ? "Not present" : \
+ "(Invalid)")
+
+#define DRX_STR_AUD_RDS(x) ( \
+ (x == true) ? "Available" : \
+ (x == false) ? "Not Available" : \
+ "(Invalid)")
+
+#define DRX_STR_AUD_NICAM_STATUS(x) ( \
+ (x == DRX_AUD_NICAM_DETECTED) ? "Detected" : \
+ (x == DRX_AUD_NICAM_NOT_DETECTED) ? "Not detected" : \
+ (x == DRX_AUD_NICAM_BAD) ? "Bad" : \
+ "(Invalid)")
+
+#define DRX_STR_RDS_VALID(x) ( \
+ (x == true) ? "Valid" : \
+ (x == false) ? "Not Valid" : \
+ "(Invalid)")
+
+/*-------------------------------------------------------------------------
+Access macros
+-------------------------------------------------------------------------*/
+
+/**
+* \brief Create a compilable reference to the microcode attribute
+* \param d pointer to demod instance
+*
+* Used as main reference to an attribute field.
+* Used by both macro implementation and function implementation.
+* These macros are defined to avoid duplication of code in macro and function
+* definitions that handle access of demod common or extended attributes.
+*
+*/
+
+#define DRX_ATTR_MCRECORD(d) ((d)->my_common_attr->mcversion)
+#define DRX_ATTR_MIRRORFREQSPECT(d) ((d)->my_common_attr->mirror_freq_spect)
+#define DRX_ATTR_CURRENTPOWERMODE(d)((d)->my_common_attr->current_power_mode)
+#define DRX_ATTR_ISOPENED(d) ((d)->my_common_attr->is_opened)
+#define DRX_ATTR_USEBOOTLOADER(d) ((d)->my_common_attr->use_bootloader)
+#define DRX_ATTR_CURRENTSTANDARD(d) ((d)->my_common_attr->current_standard)
+#define DRX_ATTR_PREVSTANDARD(d) ((d)->my_common_attr->prev_standard)
+#define DRX_ATTR_CACHESTANDARD(d) ((d)->my_common_attr->di_cache_standard)
+#define DRX_ATTR_CURRENTCHANNEL(d) ((d)->my_common_attr->current_channel)
+#define DRX_ATTR_MICROCODE(d) ((d)->my_common_attr->microcode)
+#define DRX_ATTR_VERIFYMICROCODE(d) ((d)->my_common_attr->verify_microcode)
+#define DRX_ATTR_CAPABILITIES(d) ((d)->my_common_attr->capabilities)
+#define DRX_ATTR_PRODUCTID(d) ((d)->my_common_attr->product_id)
+#define DRX_ATTR_INTERMEDIATEFREQ(d) ((d)->my_common_attr->intermediate_freq)
+#define DRX_ATTR_SYSCLOCKFREQ(d) ((d)->my_common_attr->sys_clock_freq)
+#define DRX_ATTR_TUNERRFAGCPOL(d) ((d)->my_common_attr->tuner_rf_agc_pol)
+#define DRX_ATTR_TUNERIFAGCPOL(d) ((d)->my_common_attr->tuner_if_agc_pol)
+#define DRX_ATTR_TUNERSLOWMODE(d) ((d)->my_common_attr->tuner_slow_mode)
+#define DRX_ATTR_TUNERSPORTNR(d) ((d)->my_common_attr->tuner_port_nr)
+#define DRX_ATTR_I2CADDR(d) ((d)->my_i2c_dev_addr->i2c_addr)
+#define DRX_ATTR_I2CDEVID(d) ((d)->my_i2c_dev_addr->i2c_dev_id)
+#define DRX_ISMCVERTYPE(x) ((x) == AUX_VER_RECORD)
+
+/**************************/
+
+/* Macros with device-specific handling are converted to CFG functions */
+
+#define DRX_ACCESSMACRO_SET(demod, value, cfg_name, data_type) \
+ do { \
+ struct drx_cfg config; \
+ data_type cfg_data; \
+ config.cfg_type = cfg_name; \
+ config.cfg_data = &cfg_data; \
+ cfg_data = value; \
+ drx_ctrl(demod, DRX_CTRL_SET_CFG, &config); \
+ } while (0)
+
+#define DRX_ACCESSMACRO_GET(demod, value, cfg_name, data_type, error_value) \
+ do { \
+ int cfg_status; \
+ struct drx_cfg config; \
+ data_type cfg_data; \
+ config.cfg_type = cfg_name; \
+ config.cfg_data = &cfg_data; \
+ cfg_status = drx_ctrl(demod, DRX_CTRL_GET_CFG, &config); \
+ if (cfg_status == 0) { \
+ value = cfg_data; \
+ } else { \
+ value = (data_type)error_value; \
+ } \
+ } while (0)
+
+/* Configuration functions for usage by Access (XS) Macros */
+
+#ifndef DRX_XS_CFG_BASE
+#define DRX_XS_CFG_BASE (500)
+#endif
+
+#define DRX_XS_CFG_PRESET (DRX_XS_CFG_BASE + 0)
+#define DRX_XS_CFG_AUD_BTSC_DETECT (DRX_XS_CFG_BASE + 1)
+#define DRX_XS_CFG_QAM_LOCKRANGE (DRX_XS_CFG_BASE + 2)
+
+/* Access Macros with device-specific handling */
+
+#define DRX_SET_PRESET(d, x) \
+ DRX_ACCESSMACRO_SET((d), (x), DRX_XS_CFG_PRESET, char*)
+#define DRX_GET_PRESET(d, x) \
+ DRX_ACCESSMACRO_GET((d), (x), DRX_XS_CFG_PRESET, char*, "ERROR")
+
+#define DRX_SET_AUD_BTSC_DETECT(d, x) DRX_ACCESSMACRO_SET((d), (x), \
+ DRX_XS_CFG_AUD_BTSC_DETECT, enum drx_aud_btsc_detect)
+#define DRX_GET_AUD_BTSC_DETECT(d, x) DRX_ACCESSMACRO_GET((d), (x), \
+ DRX_XS_CFG_AUD_BTSC_DETECT, enum drx_aud_btsc_detect, DRX_UNKNOWN)
+
+#define DRX_SET_QAM_LOCKRANGE(d, x) DRX_ACCESSMACRO_SET((d), (x), \
+ DRX_XS_CFG_QAM_LOCKRANGE, enum drx_qam_lock_range)
+#define DRX_GET_QAM_LOCKRANGE(d, x) DRX_ACCESSMACRO_GET((d), (x), \
+ DRX_XS_CFG_QAM_LOCKRANGE, enum drx_qam_lock_range, DRX_UNKNOWN)
+
+/**
+* \brief Macro to check if std is an ATV standard
+* \retval true std is an ATV standard
+* \retval false std is an ATV standard
+*/
+#define DRX_ISATVSTD(std) (((std) == DRX_STANDARD_PAL_SECAM_BG) || \
+ ((std) == DRX_STANDARD_PAL_SECAM_DK) || \
+ ((std) == DRX_STANDARD_PAL_SECAM_I) || \
+ ((std) == DRX_STANDARD_PAL_SECAM_L) || \
+ ((std) == DRX_STANDARD_PAL_SECAM_LP) || \
+ ((std) == DRX_STANDARD_NTSC) || \
+ ((std) == DRX_STANDARD_FM))
+
+/**
+* \brief Macro to check if std is an QAM standard
+* \retval true std is an QAM standards
+* \retval false std is an QAM standards
+*/
+#define DRX_ISQAMSTD(std) (((std) == DRX_STANDARD_ITU_A) || \
+ ((std) == DRX_STANDARD_ITU_B) || \
+ ((std) == DRX_STANDARD_ITU_C) || \
+ ((std) == DRX_STANDARD_ITU_D))
+
+/**
+* \brief Macro to check if std is VSB standard
+* \retval true std is VSB standard
+* \retval false std is not VSB standard
+*/
+#define DRX_ISVSBSTD(std) ((std) == DRX_STANDARD_8VSB)
+
+/**
+* \brief Macro to check if std is DVBT standard
+* \retval true std is DVBT standard
+* \retval false std is not DVBT standard
+*/
+#define DRX_ISDVBTSTD(std) ((std) == DRX_STANDARD_DVBT)
+
+/*-------------------------------------------------------------------------
+THE END
+-------------------------------------------------------------------------*/
+#endif /* __DRXDRIVER_H__ */
diff --git a/drivers/media/dvb-frontends/drx39xyj/drx_driver_version.h b/drivers/media/dvb-frontends/drx39xyj/drx_driver_version.h
new file mode 100644
index 000000000000..ff05a4ffb190
--- /dev/null
+++ b/drivers/media/dvb-frontends/drx39xyj/drx_driver_version.h
@@ -0,0 +1,72 @@
+/*
+ *******************************************************************************
+ * WARNING - THIS FILE HAS BEEN GENERATED - DO NOT CHANGE
+ *
+ * Filename: drx_driver_version.h
+ * Generated on: Mon Jan 18 12:09:23 2010
+ * Generated by: IDF:x 1.3.0
+ * Generated from: ../../../device/drxj/version
+ * Output start: [entry point]
+ *
+ * filename last modified re-use
+ *
+ Copyright (c), 2004-2005,2007-2010 Trident Microsystems, Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Trident Microsystems nor Hauppauge Computer Works
+ nor the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ 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 HOLDER 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.
+*/
+
+/* -----------------------------------------------------
+ * version.idf Mon Jan 18 11:56:10 2010 -
+ *
+ */
+
+#ifndef __DRX_DRIVER_VERSION__H__
+#define __DRX_DRIVER_VERSION__H__ INCLUDED
+
+#ifdef _REGISTERTABLE_
+#include <registertable.h>
+ extern register_table_t drx_driver_version[];
+ extern register_table_info_t drx_driver_version_info[];
+#endif /* _REGISTERTABLE_ */
+
+/*
+ *==============================================================================
+ * VERSION
+ * version@/var/cvs/projects/drxj.cvsroot/hostcode/drxdriver/device/drxj
+ *==============================================================================
+ */
+
+#define VERSION__A 0x0
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 0
+#define VERSION_PATCH 56
+
+#endif /* __DRX_DRIVER_VERSION__H__ */
+/*
+ * End of file (drx_driver_version.h)
+ *******************************************************************************
+ */
diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c
new file mode 100644
index 000000000000..9482954fd453
--- /dev/null
+++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c
@@ -0,0 +1,12400 @@
+/*
+ Copyright (c), 2004-2005,2007-2010 Trident Microsystems, Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Trident Microsystems nor Hauppauge Computer Works
+ nor the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ 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 HOLDER 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.
+
+ DRXJ specific implementation of DRX driver
+ authors: Dragan Savic, Milos Nikolic, Mihajlo Katona, Tao Ding, Paul Janssen
+
+ The Linux DVB Driver for Micronas DRX39xx family (drx3933j) was
+ written by Devin Heitmueller <devin.heitmueller@kernellabs.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*-----------------------------------------------------------------------------
+INCLUDE FILES
+----------------------------------------------------------------------------*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "drx39xxj.h"
+
+#include "drxj.h"
+#include "drxj_map.h"
+
+/*============================================================================*/
+/*=== DEFINES ================================================================*/
+/*============================================================================*/
+
+#define DRX39XX_MAIN_FIRMWARE "dvb-fe-drxj-mc-1.0.8.fw"
+
+/**
+* \brief Maximum u32 value.
+*/
+#ifndef MAX_U32
+#define MAX_U32 ((u32) (0xFFFFFFFFL))
+#endif
+
+/* Customer configurable hardware settings, etc */
+#ifndef MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH
+#define MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH 0x02
+#endif
+
+#ifndef MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH
+#define MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH 0x02
+#endif
+
+#ifndef MPEG_OUTPUT_CLK_DRIVE_STRENGTH
+#define MPEG_OUTPUT_CLK_DRIVE_STRENGTH 0x06
+#endif
+
+#ifndef OOB_CRX_DRIVE_STRENGTH
+#define OOB_CRX_DRIVE_STRENGTH 0x02
+#endif
+
+#ifndef OOB_DRX_DRIVE_STRENGTH
+#define OOB_DRX_DRIVE_STRENGTH 0x02
+#endif
+/**** START DJCOMBO patches to DRXJ registermap constants *********************/
+/**** registermap 200706071303 from drxj **************************************/
+#define ATV_TOP_CR_AMP_TH_FM 0x0
+#define ATV_TOP_CR_AMP_TH_L 0xA
+#define ATV_TOP_CR_AMP_TH_LP 0xA
+#define ATV_TOP_CR_AMP_TH_BG 0x8
+#define ATV_TOP_CR_AMP_TH_DK 0x8
+#define ATV_TOP_CR_AMP_TH_I 0x8
+#define ATV_TOP_CR_CONT_CR_D_MN 0x18
+#define ATV_TOP_CR_CONT_CR_D_FM 0x0
+#define ATV_TOP_CR_CONT_CR_D_L 0x20
+#define ATV_TOP_CR_CONT_CR_D_LP 0x20
+#define ATV_TOP_CR_CONT_CR_D_BG 0x18
+#define ATV_TOP_CR_CONT_CR_D_DK 0x18
+#define ATV_TOP_CR_CONT_CR_D_I 0x18
+#define ATV_TOP_CR_CONT_CR_I_MN 0x80
+#define ATV_TOP_CR_CONT_CR_I_FM 0x0
+#define ATV_TOP_CR_CONT_CR_I_L 0x80
+#define ATV_TOP_CR_CONT_CR_I_LP 0x80
+#define ATV_TOP_CR_CONT_CR_I_BG 0x80
+#define ATV_TOP_CR_CONT_CR_I_DK 0x80
+#define ATV_TOP_CR_CONT_CR_I_I 0x80
+#define ATV_TOP_CR_CONT_CR_P_MN 0x4
+#define ATV_TOP_CR_CONT_CR_P_FM 0x0
+#define ATV_TOP_CR_CONT_CR_P_L 0x4
+#define ATV_TOP_CR_CONT_CR_P_LP 0x4
+#define ATV_TOP_CR_CONT_CR_P_BG 0x4
+#define ATV_TOP_CR_CONT_CR_P_DK 0x4
+#define ATV_TOP_CR_CONT_CR_P_I 0x4
+#define ATV_TOP_CR_OVM_TH_MN 0xA0
+#define ATV_TOP_CR_OVM_TH_FM 0x0
+#define ATV_TOP_CR_OVM_TH_L 0xA0
+#define ATV_TOP_CR_OVM_TH_LP 0xA0
+#define ATV_TOP_CR_OVM_TH_BG 0xA0
+#define ATV_TOP_CR_OVM_TH_DK 0xA0
+#define ATV_TOP_CR_OVM_TH_I 0xA0
+#define ATV_TOP_EQU0_EQU_C0_FM 0x0
+#define ATV_TOP_EQU0_EQU_C0_L 0x3
+#define ATV_TOP_EQU0_EQU_C0_LP 0x3
+#define ATV_TOP_EQU0_EQU_C0_BG 0x7
+#define ATV_TOP_EQU0_EQU_C0_DK 0x0
+#define ATV_TOP_EQU0_EQU_C0_I 0x3
+#define ATV_TOP_EQU1_EQU_C1_FM 0x0
+#define ATV_TOP_EQU1_EQU_C1_L 0x1F6
+#define ATV_TOP_EQU1_EQU_C1_LP 0x1F6
+#define ATV_TOP_EQU1_EQU_C1_BG 0x197
+#define ATV_TOP_EQU1_EQU_C1_DK 0x198
+#define ATV_TOP_EQU1_EQU_C1_I 0x1F6
+#define ATV_TOP_EQU2_EQU_C2_FM 0x0
+#define ATV_TOP_EQU2_EQU_C2_L 0x28
+#define ATV_TOP_EQU2_EQU_C2_LP 0x28
+#define ATV_TOP_EQU2_EQU_C2_BG 0xC5
+#define ATV_TOP_EQU2_EQU_C2_DK 0xB0
+#define ATV_TOP_EQU2_EQU_C2_I 0x28
+#define ATV_TOP_EQU3_EQU_C3_FM 0x0
+#define ATV_TOP_EQU3_EQU_C3_L 0x192
+#define ATV_TOP_EQU3_EQU_C3_LP 0x192
+#define ATV_TOP_EQU3_EQU_C3_BG 0x12E
+#define ATV_TOP_EQU3_EQU_C3_DK 0x18E
+#define ATV_TOP_EQU3_EQU_C3_I 0x192
+#define ATV_TOP_STD_MODE_MN 0x0
+#define ATV_TOP_STD_MODE_FM 0x1
+#define ATV_TOP_STD_MODE_L 0x0
+#define ATV_TOP_STD_MODE_LP 0x0
+#define ATV_TOP_STD_MODE_BG 0x0
+#define ATV_TOP_STD_MODE_DK 0x0
+#define ATV_TOP_STD_MODE_I 0x0
+#define ATV_TOP_STD_VID_POL_MN 0x0
+#define ATV_TOP_STD_VID_POL_FM 0x0
+#define ATV_TOP_STD_VID_POL_L 0x2
+#define ATV_TOP_STD_VID_POL_LP 0x2
+#define ATV_TOP_STD_VID_POL_BG 0x0
+#define ATV_TOP_STD_VID_POL_DK 0x0
+#define ATV_TOP_STD_VID_POL_I 0x0
+#define ATV_TOP_VID_AMP_MN 0x380
+#define ATV_TOP_VID_AMP_FM 0x0
+#define ATV_TOP_VID_AMP_L 0xF50
+#define ATV_TOP_VID_AMP_LP 0xF50
+#define ATV_TOP_VID_AMP_BG 0x380
+#define ATV_TOP_VID_AMP_DK 0x394
+#define ATV_TOP_VID_AMP_I 0x3D8
+#define IQM_CF_OUT_ENA_OFDM__M 0x4
+#define IQM_FS_ADJ_SEL_B_QAM 0x1
+#define IQM_FS_ADJ_SEL_B_OFF 0x0
+#define IQM_FS_ADJ_SEL_B_VSB 0x2
+#define IQM_RC_ADJ_SEL_B_OFF 0x0
+#define IQM_RC_ADJ_SEL_B_QAM 0x1
+#define IQM_RC_ADJ_SEL_B_VSB 0x2
+/**** END DJCOMBO patches to DRXJ registermap *********************************/
+
+#include "drx_driver_version.h"
+
+/* #define DRX_DEBUG */
+#ifdef DRX_DEBUG
+#include <stdio.h>
+#endif
+
+/*-----------------------------------------------------------------------------
+ENUMS
+----------------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------------
+DEFINES
+----------------------------------------------------------------------------*/
+#ifndef DRXJ_WAKE_UP_KEY
+#define DRXJ_WAKE_UP_KEY (demod->my_i2c_dev_addr->i2c_addr)
+#endif
+
+/**
+* \def DRXJ_DEF_I2C_ADDR
+* \brief Default I2C addres of a demodulator instance.
+*/
+#define DRXJ_DEF_I2C_ADDR (0x52)
+
+/**
+* \def DRXJ_DEF_DEMOD_DEV_ID
+* \brief Default device identifier of a demodultor instance.
+*/
+#define DRXJ_DEF_DEMOD_DEV_ID (1)
+
+/**
+* \def DRXJ_SCAN_TIMEOUT
+* \brief Timeout value for waiting on demod lock during channel scan (millisec).
+*/
+#define DRXJ_SCAN_TIMEOUT 1000
+
+/**
+* \def HI_I2C_DELAY
+* \brief HI timing delay for I2C timing (in nano seconds)
+*
+* Used to compute HI_CFG_DIV
+*/
+#define HI_I2C_DELAY 42
+
+/**
+* \def HI_I2C_BRIDGE_DELAY
+* \brief HI timing delay for I2C timing (in nano seconds)
+*
+* Used to compute HI_CFG_BDL
+*/
+#define HI_I2C_BRIDGE_DELAY 750
+
+/**
+* \brief Time Window for MER and SER Measurement in Units of Segment duration.
+*/
+#define VSB_TOP_MEASUREMENT_PERIOD 64
+#define SYMBOLS_PER_SEGMENT 832
+
+/**
+* \brief bit rate and segment rate constants used for SER and BER.
+*/
+/* values taken from the QAM microcode */
+#define DRXJ_QAM_SL_SIG_POWER_QAM_UNKNOWN 0
+#define DRXJ_QAM_SL_SIG_POWER_QPSK 32768
+#define DRXJ_QAM_SL_SIG_POWER_QAM8 24576
+#define DRXJ_QAM_SL_SIG_POWER_QAM16 40960
+#define DRXJ_QAM_SL_SIG_POWER_QAM32 20480
+#define DRXJ_QAM_SL_SIG_POWER_QAM64 43008
+#define DRXJ_QAM_SL_SIG_POWER_QAM128 20992
+#define DRXJ_QAM_SL_SIG_POWER_QAM256 43520
+/**
+* \brief Min supported symbolrates.
+*/
+#ifndef DRXJ_QAM_SYMBOLRATE_MIN
+#define DRXJ_QAM_SYMBOLRATE_MIN (520000)
+#endif
+
+/**
+* \brief Max supported symbolrates.
+*/
+#ifndef DRXJ_QAM_SYMBOLRATE_MAX
+#define DRXJ_QAM_SYMBOLRATE_MAX (7233000)
+#endif
+
+/**
+* \def DRXJ_QAM_MAX_WAITTIME
+* \brief Maximal wait time for QAM auto constellation in ms
+*/
+#ifndef DRXJ_QAM_MAX_WAITTIME
+#define DRXJ_QAM_MAX_WAITTIME 900
+#endif
+
+#ifndef DRXJ_QAM_FEC_LOCK_WAITTIME
+#define DRXJ_QAM_FEC_LOCK_WAITTIME 150
+#endif
+
+#ifndef DRXJ_QAM_DEMOD_LOCK_EXT_WAITTIME
+#define DRXJ_QAM_DEMOD_LOCK_EXT_WAITTIME 200
+#endif
+
+/**
+* \def SCU status and results
+* \brief SCU
+*/
+#define DRX_SCU_READY 0
+#define DRXJ_MAX_WAITTIME 100 /* ms */
+#define FEC_RS_MEASUREMENT_PERIOD 12894 /* 1 sec */
+#define FEC_RS_MEASUREMENT_PRESCALE 1 /* n sec */
+
+/**
+* \def DRX_AUD_MAX_DEVIATION
+* \brief Needed for calculation of prescale feature in AUD
+*/
+#ifndef DRXJ_AUD_MAX_FM_DEVIATION
+#define DRXJ_AUD_MAX_FM_DEVIATION 100 /* kHz */
+#endif
+
+/**
+* \brief Needed for calculation of NICAM prescale feature in AUD
+*/
+#ifndef DRXJ_AUD_MAX_NICAM_PRESCALE
+#define DRXJ_AUD_MAX_NICAM_PRESCALE (9) /* dB */
+#endif
+
+/**
+* \brief Needed for calculation of NICAM prescale feature in AUD
+*/
+#ifndef DRXJ_AUD_MAX_WAITTIME
+#define DRXJ_AUD_MAX_WAITTIME 250 /* ms */
+#endif
+
+/* ATV config changed flags */
+#define DRXJ_ATV_CHANGED_COEF (0x00000001UL)
+#define DRXJ_ATV_CHANGED_PEAK_FLT (0x00000008UL)
+#define DRXJ_ATV_CHANGED_NOISE_FLT (0x00000010UL)
+#define DRXJ_ATV_CHANGED_OUTPUT (0x00000020UL)
+#define DRXJ_ATV_CHANGED_SIF_ATT (0x00000040UL)
+
+/* UIO define */
+#define DRX_UIO_MODE_FIRMWARE_SMA DRX_UIO_MODE_FIRMWARE0
+#define DRX_UIO_MODE_FIRMWARE_SAW DRX_UIO_MODE_FIRMWARE1
+
+/*
+ * MICROCODE RELATED DEFINES
+ */
+
+/* Magic word for checking correct Endianess of microcode data */
+#define DRX_UCODE_MAGIC_WORD ((((u16)'H')<<8)+((u16)'L'))
+
+/* CRC flag in ucode header, flags field. */
+#define DRX_UCODE_CRC_FLAG (0x0001)
+
+/*
+ * Maximum size of buffer used to verify the microcode.
+ * Must be an even number
+ */
+#define DRX_UCODE_MAX_BUF_SIZE (DRXDAP_MAX_RCHUNKSIZE)
+
+#if DRX_UCODE_MAX_BUF_SIZE & 1
+#error DRX_UCODE_MAX_BUF_SIZE must be an even number
+#endif
+
+/*
+ * Power mode macros
+ */
+
+#define DRX_ISPOWERDOWNMODE(mode) ((mode == DRX_POWER_MODE_9) || \
+ (mode == DRX_POWER_MODE_10) || \
+ (mode == DRX_POWER_MODE_11) || \
+ (mode == DRX_POWER_MODE_12) || \
+ (mode == DRX_POWER_MODE_13) || \
+ (mode == DRX_POWER_MODE_14) || \
+ (mode == DRX_POWER_MODE_15) || \
+ (mode == DRX_POWER_MODE_16) || \
+ (mode == DRX_POWER_DOWN))
+
+/* Pin safe mode macro */
+#define DRXJ_PIN_SAFE_MODE 0x0000
+/*============================================================================*/
+/*=== GLOBAL VARIABLEs =======================================================*/
+/*============================================================================*/
+/**
+*/
+
+/**
+* \brief Temporary register definitions.
+* (register definitions that are not yet available in register master)
+*/
+
+/******************************************************************************/
+/* Audio block 0x103 is write only. To avoid shadowing in driver accessing */
+/* RAM adresses directly. This must be READ ONLY to avoid problems. */
+/* Writing to the interface adresses is more than only writing the RAM */
+/* locations */
+/******************************************************************************/
+/**
+* \brief RAM location of MODUS registers
+*/
+#define AUD_DEM_RAM_MODUS_HI__A 0x10204A3
+#define AUD_DEM_RAM_MODUS_HI__M 0xF000
+
+#define AUD_DEM_RAM_MODUS_LO__A 0x10204A4
+#define AUD_DEM_RAM_MODUS_LO__M 0x0FFF
+
+/**
+* \brief RAM location of I2S config registers
+*/
+#define AUD_DEM_RAM_I2S_CONFIG1__A 0x10204B1
+#define AUD_DEM_RAM_I2S_CONFIG2__A 0x10204B2
+
+/**
+* \brief RAM location of DCO config registers
+*/
+#define AUD_DEM_RAM_DCO_B_HI__A 0x1020461
+#define AUD_DEM_RAM_DCO_B_LO__A 0x1020462
+#define AUD_DEM_RAM_DCO_A_HI__A 0x1020463
+#define AUD_DEM_RAM_DCO_A_LO__A 0x1020464
+
+/**
+* \brief RAM location of Threshold registers
+*/
+#define AUD_DEM_RAM_NICAM_THRSHLD__A 0x102045A
+#define AUD_DEM_RAM_A2_THRSHLD__A 0x10204BB
+#define AUD_DEM_RAM_BTSC_THRSHLD__A 0x10204A6
+
+/**
+* \brief RAM location of Carrier Threshold registers
+*/
+#define AUD_DEM_RAM_CM_A_THRSHLD__A 0x10204AF
+#define AUD_DEM_RAM_CM_B_THRSHLD__A 0x10204B0
+
+/**
+* \brief FM Matrix register fix
+*/
+#ifdef AUD_DEM_WR_FM_MATRIX__A
+#undef AUD_DEM_WR_FM_MATRIX__A
+#endif
+#define AUD_DEM_WR_FM_MATRIX__A 0x105006F
+
+/*============================================================================*/
+/**
+* \brief Defines required for audio
+*/
+#define AUD_VOLUME_ZERO_DB 115
+#define AUD_VOLUME_DB_MIN -60
+#define AUD_VOLUME_DB_MAX 12
+#define AUD_CARRIER_STRENGTH_QP_0DB 0x4000
+#define AUD_CARRIER_STRENGTH_QP_0DB_LOG10T100 421
+#define AUD_MAX_AVC_REF_LEVEL 15
+#define AUD_I2S_FREQUENCY_MAX 48000UL
+#define AUD_I2S_FREQUENCY_MIN 12000UL
+#define AUD_RDS_ARRAY_SIZE 18
+
+/**
+* \brief Needed for calculation of prescale feature in AUD
+*/
+#ifndef DRX_AUD_MAX_FM_DEVIATION
+#define DRX_AUD_MAX_FM_DEVIATION (100) /* kHz */
+#endif
+
+/**
+* \brief Needed for calculation of NICAM prescale feature in AUD
+*/
+#ifndef DRX_AUD_MAX_NICAM_PRESCALE
+#define DRX_AUD_MAX_NICAM_PRESCALE (9) /* dB */
+#endif
+
+/*============================================================================*/
+/* Values for I2S Master/Slave pin configurations */
+#define SIO_PDR_I2S_CL_CFG_MODE__MASTER 0x0004
+#define SIO_PDR_I2S_CL_CFG_DRIVE__MASTER 0x0008
+#define SIO_PDR_I2S_CL_CFG_MODE__SLAVE 0x0004
+#define SIO_PDR_I2S_CL_CFG_DRIVE__SLAVE 0x0000
+
+#define SIO_PDR_I2S_DA_CFG_MODE__MASTER 0x0003
+#define SIO_PDR_I2S_DA_CFG_DRIVE__MASTER 0x0008
+#define SIO_PDR_I2S_DA_CFG_MODE__SLAVE 0x0003
+#define SIO_PDR_I2S_DA_CFG_DRIVE__SLAVE 0x0008
+
+#define SIO_PDR_I2S_WS_CFG_MODE__MASTER 0x0004
+#define SIO_PDR_I2S_WS_CFG_DRIVE__MASTER 0x0008
+#define SIO_PDR_I2S_WS_CFG_MODE__SLAVE 0x0004
+#define SIO_PDR_I2S_WS_CFG_DRIVE__SLAVE 0x0000
+
+/*============================================================================*/
+/*=== REGISTER ACCESS MACROS =================================================*/
+/*============================================================================*/
+
+/**
+* This macro is used to create byte arrays for block writes.
+* Block writes speed up I2C traffic between host and demod.
+* The macro takes care of the required byte order in a 16 bits word.
+* x -> lowbyte(x), highbyte(x)
+*/
+#define DRXJ_16TO8(x) ((u8) (((u16)x) & 0xFF)), \
+ ((u8)((((u16)x)>>8)&0xFF))
+/**
+* This macro is used to convert byte array to 16 bit register value for block read.
+* Block read speed up I2C traffic between host and demod.
+* The macro takes care of the required byte order in a 16 bits word.
+*/
+#define DRXJ_8TO16(x) ((u16) (x[0] | (x[1] << 8)))
+
+/*============================================================================*/
+/*=== MISC DEFINES ===========================================================*/
+/*============================================================================*/
+
+/*============================================================================*/
+/*=== HI COMMAND RELATED DEFINES =============================================*/
+/*============================================================================*/
+
+/**
+* \brief General maximum number of retries for ucode command interfaces
+*/
+#define DRXJ_MAX_RETRIES (100)
+
+/*============================================================================*/
+/*=== STANDARD RELATED MACROS ================================================*/
+/*============================================================================*/
+
+#define DRXJ_ISATVSTD(std) ((std == DRX_STANDARD_PAL_SECAM_BG) || \
+ (std == DRX_STANDARD_PAL_SECAM_DK) || \
+ (std == DRX_STANDARD_PAL_SECAM_I) || \
+ (std == DRX_STANDARD_PAL_SECAM_L) || \
+ (std == DRX_STANDARD_PAL_SECAM_LP) || \
+ (std == DRX_STANDARD_NTSC) || \
+ (std == DRX_STANDARD_FM))
+
+#define DRXJ_ISQAMSTD(std) ((std == DRX_STANDARD_ITU_A) || \
+ (std == DRX_STANDARD_ITU_B) || \
+ (std == DRX_STANDARD_ITU_C) || \
+ (std == DRX_STANDARD_ITU_D))
+
+/*-----------------------------------------------------------------------------
+GLOBAL VARIABLES
+----------------------------------------------------------------------------*/
+/*
+ * DRXJ DAP structures
+ */
+
+static int drxdap_fasi_read_block(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u16 datasize,
+ u8 *data, u32 flags);
+
+
+static int drxj_dap_read_modify_write_reg16(struct i2c_device_addr *dev_addr,
+ u32 waddr,
+ u32 raddr,
+ u16 wdata, u16 *rdata);
+
+static int drxj_dap_read_reg16(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u16 *data, u32 flags);
+
+static int drxdap_fasi_read_reg32(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u32 *data, u32 flags);
+
+static int drxdap_fasi_write_block(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u16 datasize,
+ u8 *data, u32 flags);
+
+static int drxj_dap_write_reg16(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u16 data, u32 flags);
+
+static int drxdap_fasi_write_reg32(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u32 data, u32 flags);
+
+static struct drxj_data drxj_data_g = {
+ false, /* has_lna : true if LNA (aka PGA) present */
+ false, /* has_oob : true if OOB supported */
+ false, /* has_ntsc: true if NTSC supported */
+ false, /* has_btsc: true if BTSC supported */
+ false, /* has_smatx: true if SMA_TX pin is available */
+ false, /* has_smarx: true if SMA_RX pin is available */
+ false, /* has_gpio : true if GPIO pin is available */
+ false, /* has_irqn : true if IRQN pin is available */
+ 0, /* mfx A1/A2/A... */
+
+ /* tuner settings */
+ false, /* tuner mirrors RF signal */
+ /* standard/channel settings */
+ DRX_STANDARD_UNKNOWN, /* current standard */
+ DRX_CONSTELLATION_AUTO, /* constellation */
+ 0, /* frequency in KHz */
+ DRX_BANDWIDTH_UNKNOWN, /* curr_bandwidth */
+ DRX_MIRROR_NO, /* mirror */
+
+ /* signal quality information: */
+ /* default values taken from the QAM Programming guide */
+ /* fec_bits_desired should not be less than 4000000 */
+ 4000000, /* fec_bits_desired */
+ 5, /* fec_vd_plen */
+ 4, /* qam_vd_prescale */
+ 0xFFFF, /* qamVDPeriod */
+ 204 * 8, /* fec_rs_plen annex A */
+ 1, /* fec_rs_prescale */
+ FEC_RS_MEASUREMENT_PERIOD, /* fec_rs_period */
+ true, /* reset_pkt_err_acc */
+ 0, /* pkt_err_acc_start */
+
+ /* HI configuration */
+ 0, /* hi_cfg_timing_div */
+ 0, /* hi_cfg_bridge_delay */
+ 0, /* hi_cfg_wake_up_key */
+ 0, /* hi_cfg_ctrl */
+ 0, /* HICfgTimeout */
+ /* UIO configuartion */
+ DRX_UIO_MODE_DISABLE, /* uio_sma_rx_mode */
+ DRX_UIO_MODE_DISABLE, /* uio_sma_tx_mode */
+ DRX_UIO_MODE_DISABLE, /* uioASELMode */
+ DRX_UIO_MODE_DISABLE, /* uio_irqn_mode */
+ /* FS setting */
+ 0UL, /* iqm_fs_rate_ofs */
+ false, /* pos_image */
+ /* RC setting */
+ 0UL, /* iqm_rc_rate_ofs */
+ /* AUD information */
+/* false, * flagSetAUDdone */
+/* false, * detectedRDS */
+/* true, * flagASDRequest */
+/* false, * flagHDevClear */
+/* false, * flagHDevSet */
+/* (u16) 0xFFF, * rdsLastCount */
+
+ /* ATV configuartion */
+ 0UL, /* flags cfg changes */
+ /* shadow of ATV_TOP_EQU0__A */
+ {-5,
+ ATV_TOP_EQU0_EQU_C0_FM,
+ ATV_TOP_EQU0_EQU_C0_L,
+ ATV_TOP_EQU0_EQU_C0_LP,
+ ATV_TOP_EQU0_EQU_C0_BG,
+ ATV_TOP_EQU0_EQU_C0_DK,
+ ATV_TOP_EQU0_EQU_C0_I},
+ /* shadow of ATV_TOP_EQU1__A */
+ {-50,
+ ATV_TOP_EQU1_EQU_C1_FM,
+ ATV_TOP_EQU1_EQU_C1_L,
+ ATV_TOP_EQU1_EQU_C1_LP,
+ ATV_TOP_EQU1_EQU_C1_BG,
+ ATV_TOP_EQU1_EQU_C1_DK,
+ ATV_TOP_EQU1_EQU_C1_I},
+ /* shadow of ATV_TOP_EQU2__A */
+ {210,
+ ATV_TOP_EQU2_EQU_C2_FM,
+ ATV_TOP_EQU2_EQU_C2_L,
+ ATV_TOP_EQU2_EQU_C2_LP,
+ ATV_TOP_EQU2_EQU_C2_BG,
+ ATV_TOP_EQU2_EQU_C2_DK,
+ ATV_TOP_EQU2_EQU_C2_I},
+ /* shadow of ATV_TOP_EQU3__A */
+ {-160,
+ ATV_TOP_EQU3_EQU_C3_FM,
+ ATV_TOP_EQU3_EQU_C3_L,
+ ATV_TOP_EQU3_EQU_C3_LP,
+ ATV_TOP_EQU3_EQU_C3_BG,
+ ATV_TOP_EQU3_EQU_C3_DK,
+ ATV_TOP_EQU3_EQU_C3_I},
+ false, /* flag: true=bypass */
+ ATV_TOP_VID_PEAK__PRE, /* shadow of ATV_TOP_VID_PEAK__A */
+ ATV_TOP_NOISE_TH__PRE, /* shadow of ATV_TOP_NOISE_TH__A */
+ true, /* flag CVBS ouput enable */
+ false, /* flag SIF ouput enable */
+ DRXJ_SIF_ATTENUATION_0DB, /* current SIF att setting */
+ { /* qam_rf_agc_cfg */
+ DRX_STANDARD_ITU_B, /* standard */
+ DRX_AGC_CTRL_AUTO, /* ctrl_mode */
+ 0, /* output_level */
+ 0, /* min_output_level */
+ 0xFFFF, /* max_output_level */
+ 0x0000, /* speed */
+ 0x0000, /* top */
+ 0x0000 /* c.o.c. */
+ },
+ { /* qam_if_agc_cfg */
+ DRX_STANDARD_ITU_B, /* standard */
+ DRX_AGC_CTRL_AUTO, /* ctrl_mode */
+ 0, /* output_level */
+ 0, /* min_output_level */
+ 0xFFFF, /* max_output_level */
+ 0x0000, /* speed */
+ 0x0000, /* top (don't care) */
+ 0x0000 /* c.o.c. (don't care) */
+ },
+ { /* vsb_rf_agc_cfg */
+ DRX_STANDARD_8VSB, /* standard */
+ DRX_AGC_CTRL_AUTO, /* ctrl_mode */
+ 0, /* output_level */
+ 0, /* min_output_level */
+ 0xFFFF, /* max_output_level */
+ 0x0000, /* speed */
+ 0x0000, /* top (don't care) */
+ 0x0000 /* c.o.c. (don't care) */
+ },
+ { /* vsb_if_agc_cfg */
+ DRX_STANDARD_8VSB, /* standard */
+ DRX_AGC_CTRL_AUTO, /* ctrl_mode */
+ 0, /* output_level */
+ 0, /* min_output_level */
+ 0xFFFF, /* max_output_level */
+ 0x0000, /* speed */
+ 0x0000, /* top (don't care) */
+ 0x0000 /* c.o.c. (don't care) */
+ },
+ 0, /* qam_pga_cfg */
+ 0, /* vsb_pga_cfg */
+ { /* qam_pre_saw_cfg */
+ DRX_STANDARD_ITU_B, /* standard */
+ 0, /* reference */
+ false /* use_pre_saw */
+ },
+ { /* vsb_pre_saw_cfg */
+ DRX_STANDARD_8VSB, /* standard */
+ 0, /* reference */
+ false /* use_pre_saw */
+ },
+
+ /* Version information */
+#ifndef _CH_
+ {
+ "01234567890", /* human readable version microcode */
+ "01234567890" /* human readable version device specific code */
+ },
+ {
+ { /* struct drx_version for microcode */
+ DRX_MODULE_UNKNOWN,
+ (char *)(NULL),
+ 0,
+ 0,
+ 0,
+ (char *)(NULL)
+ },
+ { /* struct drx_version for device specific code */
+ DRX_MODULE_UNKNOWN,
+ (char *)(NULL),
+ 0,
+ 0,
+ 0,
+ (char *)(NULL)
+ }
+ },
+ {
+ { /* struct drx_version_list for microcode */
+ (struct drx_version *) (NULL),
+ (struct drx_version_list *) (NULL)
+ },
+ { /* struct drx_version_list for device specific code */
+ (struct drx_version *) (NULL),
+ (struct drx_version_list *) (NULL)
+ }
+ },
+#endif
+ false, /* smart_ant_inverted */
+ /* Tracking filter setting for OOB */
+ {
+ 12000,
+ 9300,
+ 6600,
+ 5280,
+ 3700,
+ 3000,
+ 2000,
+ 0},
+ false, /* oob_power_on */
+ 0, /* mpeg_ts_static_bitrate */
+ false, /* disable_te_ihandling */
+ false, /* bit_reverse_mpeg_outout */
+ DRXJ_MPEGOUTPUT_CLOCK_RATE_AUTO, /* mpeg_output_clock_rate */
+ DRXJ_MPEG_START_WIDTH_1CLKCYC, /* mpeg_start_width */
+
+ /* Pre SAW & Agc configuration for ATV */
+ {
+ DRX_STANDARD_NTSC, /* standard */
+ 7, /* reference */
+ true /* use_pre_saw */
+ },
+ { /* ATV RF-AGC */
+ DRX_STANDARD_NTSC, /* standard */
+ DRX_AGC_CTRL_AUTO, /* ctrl_mode */
+ 0, /* output_level */
+ 0, /* min_output_level (d.c.) */
+ 0, /* max_output_level (d.c.) */
+ 3, /* speed */
+ 9500, /* top */
+ 4000 /* cut-off current */
+ },
+ { /* ATV IF-AGC */
+ DRX_STANDARD_NTSC, /* standard */
+ DRX_AGC_CTRL_AUTO, /* ctrl_mode */
+ 0, /* output_level */
+ 0, /* min_output_level (d.c.) */
+ 0, /* max_output_level (d.c.) */
+ 3, /* speed */
+ 2400, /* top */
+ 0 /* c.o.c. (d.c.) */
+ },
+ 140, /* ATV PGA config */
+ 0, /* curr_symbol_rate */
+
+ false, /* pdr_safe_mode */
+ SIO_PDR_GPIO_CFG__PRE, /* pdr_safe_restore_val_gpio */
+ SIO_PDR_VSYNC_CFG__PRE, /* pdr_safe_restore_val_v_sync */
+ SIO_PDR_SMA_RX_CFG__PRE, /* pdr_safe_restore_val_sma_rx */
+ SIO_PDR_SMA_TX_CFG__PRE, /* pdr_safe_restore_val_sma_tx */
+
+ 4, /* oob_pre_saw */
+ DRXJ_OOB_LO_POW_MINUS10DB, /* oob_lo_pow */
+ {
+ false /* aud_data, only first member */
+ },
+};
+
+/**
+* \var drxj_default_addr_g
+* \brief Default I2C address and device identifier.
+*/
+static struct i2c_device_addr drxj_default_addr_g = {
+ DRXJ_DEF_I2C_ADDR, /* i2c address */
+ DRXJ_DEF_DEMOD_DEV_ID /* device id */
+};
+
+/**
+* \var drxj_default_comm_attr_g
+* \brief Default common attributes of a drxj demodulator instance.
+*/
+static struct drx_common_attr drxj_default_comm_attr_g = {
+ NULL, /* ucode file */
+ true, /* ucode verify switch */
+ {0}, /* version record */
+
+ 44000, /* IF in kHz in case no tuner instance is used */
+ (151875 - 0), /* system clock frequency in kHz */
+ 0, /* oscillator frequency kHz */
+ 0, /* oscillator deviation in ppm, signed */
+ false, /* If true mirror frequency spectrum */
+ {
+ /* MPEG output configuration */
+ true, /* If true, enable MPEG ouput */
+ false, /* If true, insert RS byte */
+ false, /* If true, parallel out otherwise serial */
+ false, /* If true, invert DATA signals */
+ false, /* If true, invert ERR signal */
+ false, /* If true, invert STR signals */
+ false, /* If true, invert VAL signals */
+ false, /* If true, invert CLK signals */
+ true, /* If true, static MPEG clockrate will
+ be used, otherwise clockrate will
+ adapt to the bitrate of the TS */
+ 19392658UL, /* Maximum bitrate in b/s in case
+ static clockrate is selected */
+ DRX_MPEG_STR_WIDTH_1 /* MPEG Start width in clock cycles */
+ },
+ /* Initilisations below can be ommited, they require no user input and
+ are initialy 0, NULL or false. The compiler will initialize them to these
+ values when ommited. */
+ false, /* is_opened */
+
+ /* SCAN */
+ NULL, /* no scan params yet */
+ 0, /* current scan index */
+ 0, /* next scan frequency */
+ false, /* scan ready flag */
+ 0, /* max channels to scan */
+ 0, /* nr of channels scanned */
+ NULL, /* default scan function */
+ NULL, /* default context pointer */
+ 0, /* millisec to wait for demod lock */
+ DRXJ_DEMOD_LOCK, /* desired lock */
+ false,
+
+ /* Power management */
+ DRX_POWER_UP,
+
+ /* Tuner */
+ 1, /* nr of I2C port to wich tuner is */
+ 0L, /* minimum RF input frequency, in kHz */
+ 0L, /* maximum RF input frequency, in kHz */
+ false, /* Rf Agc Polarity */
+ false, /* If Agc Polarity */
+ false, /* tuner slow mode */
+
+ { /* current channel (all 0) */
+ 0UL /* channel.frequency */
+ },
+ DRX_STANDARD_UNKNOWN, /* current standard */
+ DRX_STANDARD_UNKNOWN, /* previous standard */
+ DRX_STANDARD_UNKNOWN, /* di_cache_standard */
+ false, /* use_bootloader */
+ 0UL, /* capabilities */
+ 0 /* mfx */
+};
+
+/**
+* \var drxj_default_demod_g
+* \brief Default drxj demodulator instance.
+*/
+static struct drx_demod_instance drxj_default_demod_g = {
+ &drxj_default_addr_g, /* i2c address & device id */
+ &drxj_default_comm_attr_g, /* demod common attributes */
+ &drxj_data_g /* demod device specific attributes */
+};
+
+/**
+* \brief Default audio data structure for DRK demodulator instance.
+*
+* This structure is DRXK specific.
+*
+*/
+static struct drx_aud_data drxj_default_aud_data_g = {
+ false, /* audio_is_active */
+ DRX_AUD_STANDARD_AUTO, /* audio_standard */
+
+ /* i2sdata */
+ {
+ false, /* output_enable */
+ 48000, /* frequency */
+ DRX_I2S_MODE_MASTER, /* mode */
+ DRX_I2S_WORDLENGTH_32, /* word_length */
+ DRX_I2S_POLARITY_RIGHT, /* polarity */
+ DRX_I2S_FORMAT_WS_WITH_DATA /* format */
+ },
+ /* volume */
+ {
+ true, /* mute; */
+ 0, /* volume */
+ DRX_AUD_AVC_OFF, /* avc_mode */
+ 0, /* avc_ref_level */
+ DRX_AUD_AVC_MAX_GAIN_12DB, /* avc_max_gain */
+ DRX_AUD_AVC_MAX_ATTEN_24DB, /* avc_max_atten */
+ 0, /* strength_left */
+ 0 /* strength_right */
+ },
+ DRX_AUD_AUTO_SOUND_SELECT_ON_CHANGE_ON, /* auto_sound */
+ /* ass_thresholds */
+ {
+ 440, /* A2 */
+ 12, /* BTSC */
+ 700, /* NICAM */
+ },
+ /* carrier */
+ {
+ /* a */
+ {
+ 42, /* thres */
+ DRX_NO_CARRIER_NOISE, /* opt */
+ 0, /* shift */
+ 0 /* dco */
+ },
+ /* b */
+ {
+ 42, /* thres */
+ DRX_NO_CARRIER_MUTE, /* opt */
+ 0, /* shift */
+ 0 /* dco */
+ },
+
+ },
+ /* mixer */
+ {
+ DRX_AUD_SRC_STEREO_OR_A, /* source_i2s */
+ DRX_AUD_I2S_MATRIX_STEREO, /* matrix_i2s */
+ DRX_AUD_FM_MATRIX_SOUND_A /* matrix_fm */
+ },
+ DRX_AUD_DEVIATION_NORMAL, /* deviation */
+ DRX_AUD_AVSYNC_OFF, /* av_sync */
+
+ /* prescale */
+ {
+ DRX_AUD_MAX_FM_DEVIATION, /* fm_deviation */
+ DRX_AUD_MAX_NICAM_PRESCALE /* nicam_gain */
+ },
+ DRX_AUD_FM_DEEMPH_75US, /* deemph */
+ DRX_BTSC_STEREO, /* btsc_detect */
+ 0, /* rds_data_counter */
+ false /* rds_data_present */
+};
+
+/*-----------------------------------------------------------------------------
+STRUCTURES
+----------------------------------------------------------------------------*/
+struct drxjeq_stat {
+ u16 eq_mse;
+ u8 eq_mode;
+ u8 eq_ctrl;
+ u8 eq_stat;
+};
+
+/* HI command */
+struct drxj_hi_cmd {
+ u16 cmd;
+ u16 param1;
+ u16 param2;
+ u16 param3;
+ u16 param4;
+ u16 param5;
+ u16 param6;
+};
+
+/*============================================================================*/
+/*=== MICROCODE RELATED STRUCTURES ===========================================*/
+/*============================================================================*/
+
+/**
+ * struct drxu_code_block_hdr - Structure of the microcode block headers
+ *
+ * @addr: Destination address of the data in this block
+ * @size: Size of the block data following this header counted in
+ * 16 bits words
+ * @CRC: CRC value of the data block, only valid if CRC flag is
+ * set.
+ */
+struct drxu_code_block_hdr {
+ u32 addr;
+ u16 size;
+ u16 flags;
+ u16 CRC;
+};
+
+/*-----------------------------------------------------------------------------
+FUNCTIONS
+----------------------------------------------------------------------------*/
+/* Some prototypes */
+static int
+hi_command(struct i2c_device_addr *dev_addr,
+ const struct drxj_hi_cmd *cmd, u16 *result);
+
+static int
+ctrl_lock_status(struct drx_demod_instance *demod, enum drx_lock_status *lock_stat);
+
+static int
+ctrl_power_mode(struct drx_demod_instance *demod, enum drx_power_mode *mode);
+
+static int power_down_aud(struct drx_demod_instance *demod);
+
+static int
+ctrl_set_cfg_pre_saw(struct drx_demod_instance *demod, struct drxj_cfg_pre_saw *pre_saw);
+
+static int
+ctrl_set_cfg_afe_gain(struct drx_demod_instance *demod, struct drxj_cfg_afe_gain *afe_gain);
+
+/*============================================================================*/
+/*============================================================================*/
+/*== HELPER FUNCTIONS ==*/
+/*============================================================================*/
+/*============================================================================*/
+
+
+/*============================================================================*/
+
+/*
+* \fn u32 frac28(u32 N, u32 D)
+* \brief Compute: (1<<28)*N/D
+* \param N 32 bits
+* \param D 32 bits
+* \return (1<<28)*N/D
+* This function is used to avoid floating-point calculations as they may
+* not be present on the target platform.
+
+* frac28 performs an unsigned 28/28 bits division to 32-bit fixed point
+* fraction used for setting the Frequency Shifter registers.
+* N and D can hold numbers up to width: 28-bits.
+* The 4 bits integer part and the 28 bits fractional part are calculated.
+
+* Usage condition: ((1<<28)*n)/d < ((1<<32)-1) => (n/d) < 15.999
+
+* N: 0...(1<<28)-1 = 268435454
+* D: 0...(1<<28)-1
+* Q: 0...(1<<32)-1
+*/
+static u32 frac28(u32 N, u32 D)
+{
+ int i = 0;
+ u32 Q1 = 0;
+ u32 R0 = 0;
+
+ R0 = (N % D) << 4; /* 32-28 == 4 shifts possible at max */
+ Q1 = N / D; /* integer part, only the 4 least significant bits
+ will be visible in the result */
+
+ /* division using radix 16, 7 nibbles in the result */
+ for (i = 0; i < 7; i++) {
+ Q1 = (Q1 << 4) | R0 / D;
+ R0 = (R0 % D) << 4;
+ }
+ /* rounding */
+ if ((R0 >> 3) >= D)
+ Q1++;
+
+ return Q1;
+}
+
+/**
+* \fn u32 log1_times100( u32 x)
+* \brief Compute: 100*log10(x)
+* \param x 32 bits
+* \return 100*log10(x)
+*
+* 100*log10(x)
+* = 100*(log2(x)/log2(10)))
+* = (100*(2^15)*log2(x))/((2^15)*log2(10))
+* = ((200*(2^15)*log2(x))/((2^15)*log2(10)))/2
+* = ((200*(2^15)*(log2(x/y)+log2(y)))/((2^15)*log2(10)))/2
+* = ((200*(2^15)*log2(x/y))+(200*(2^15)*log2(y)))/((2^15)*log2(10)))/2
+*
+* where y = 2^k and 1<= (x/y) < 2
+*/
+
+static u32 log1_times100(u32 x)
+{
+ static const u8 scale = 15;
+ static const u8 index_width = 5;
+ /*
+ log2lut[n] = (1<<scale) * 200 * log2( 1.0 + ( (1.0/(1<<INDEXWIDTH)) * n ))
+ 0 <= n < ((1<<INDEXWIDTH)+1)
+ */
+
+ static const u32 log2lut[] = {
+ 0, /* 0.000000 */
+ 290941, /* 290941.300628 */
+ 573196, /* 573196.476418 */
+ 847269, /* 847269.179851 */
+ 1113620, /* 1113620.489452 */
+ 1372674, /* 1372673.576986 */
+ 1624818, /* 1624817.752104 */
+ 1870412, /* 1870411.981536 */
+ 2109788, /* 2109787.962654 */
+ 2343253, /* 2343252.817465 */
+ 2571091, /* 2571091.461923 */
+ 2793569, /* 2793568.696416 */
+ 3010931, /* 3010931.055901 */
+ 3223408, /* 3223408.452106 */
+ 3431216, /* 3431215.635215 */
+ 3634553, /* 3634553.498355 */
+ 3833610, /* 3833610.244726 */
+ 4028562, /* 4028562.434393 */
+ 4219576, /* 4219575.925308 */
+ 4406807, /* 4406806.721144 */
+ 4590402, /* 4590401.736809 */
+ 4770499, /* 4770499.491025 */
+ 4947231, /* 4947230.734179 */
+ 5120719, /* 5120719.018555 */
+ 5291081, /* 5291081.217197 */
+ 5458428, /* 5458427.996830 */
+ 5622864, /* 5622864.249668 */
+ 5784489, /* 5784489.488298 */
+ 5943398, /* 5943398.207380 */
+ 6099680, /* 6099680.215452 */
+ 6253421, /* 6253420.939751 */
+ 6404702, /* 6404701.706649 */
+ 6553600, /* 6553600.000000 */
+ };
+
+ u8 i = 0;
+ u32 y = 0;
+ u32 d = 0;
+ u32 k = 0;
+ u32 r = 0;
+
+ if (x == 0)
+ return 0;
+
+ /* Scale x (normalize) */
+ /* computing y in log(x/y) = log(x) - log(y) */
+ if ((x & (((u32) (-1)) << (scale + 1))) == 0) {
+ for (k = scale; k > 0; k--) {
+ if (x & (((u32) 1) << scale))
+ break;
+ x <<= 1;
+ }
+ } else {
+ for (k = scale; k < 31; k++) {
+ if ((x & (((u32) (-1)) << (scale + 1))) == 0)
+ break;
+ x >>= 1;
+ }
+ }
+ /*
+ Now x has binary point between bit[scale] and bit[scale-1]
+ and 1.0 <= x < 2.0 */
+
+ /* correction for divison: log(x) = log(x/y)+log(y) */
+ y = k * ((((u32) 1) << scale) * 200);
+
+ /* remove integer part */
+ x &= ((((u32) 1) << scale) - 1);
+ /* get index */
+ i = (u8) (x >> (scale - index_width));
+ /* compute delta (x-a) */
+ d = x & ((((u32) 1) << (scale - index_width)) - 1);
+ /* compute log, multiplication ( d* (.. )) must be within range ! */
+ y += log2lut[i] +
+ ((d * (log2lut[i + 1] - log2lut[i])) >> (scale - index_width));
+ /* Conver to log10() */
+ y /= 108853; /* (log2(10) << scale) */
+ r = (y >> 1);
+ /* rounding */
+ if (y & ((u32)1))
+ r++;
+
+ return r;
+
+}
+
+/**
+* \fn u32 frac_times1e6( u16 N, u32 D)
+* \brief Compute: (N/D) * 1000000.
+* \param N nominator 16-bits.
+* \param D denominator 32-bits.
+* \return u32
+* \retval ((N/D) * 1000000), 32 bits
+*
+* No check on D=0!
+*/
+static u32 frac_times1e6(u32 N, u32 D)
+{
+ u32 remainder = 0;
+ u32 frac = 0;
+
+ /*
+ frac = (N * 1000000) / D
+ To let it fit in a 32 bits computation:
+ frac = (N * (1000000 >> 4)) / (D >> 4)
+ This would result in a problem in case D < 16 (div by 0).
+ So we do it more elaborate as shown below.
+ */
+ frac = (((u32) N) * (1000000 >> 4)) / D;
+ frac <<= 4;
+ remainder = (((u32) N) * (1000000 >> 4)) % D;
+ remainder <<= 4;
+ frac += remainder / D;
+ remainder = remainder % D;
+ if ((remainder * 2) > D)
+ frac++;
+
+ return frac;
+}
+
+/*============================================================================*/
+
+
+/**
+* \brief Values for NICAM prescaler gain. Computed from dB to integer
+* and rounded. For calc used formula: 16*10^(prescaleGain[dB]/20).
+*
+*/
+static const u16 nicam_presc_table_val[43] = {
+ 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4,
+ 5, 5, 6, 6, 7, 8, 9, 10, 11, 13, 14, 16,
+ 18, 20, 23, 25, 28, 32, 36, 40, 45,
+ 51, 57, 64, 71, 80, 90, 101, 113, 127
+};
+
+/*============================================================================*/
+/*== END HELPER FUNCTIONS ==*/
+/*============================================================================*/
+
+/*============================================================================*/
+/*============================================================================*/
+/*== DRXJ DAP FUNCTIONS ==*/
+/*============================================================================*/
+/*============================================================================*/
+
+/*
+ This layer takes care of some device specific register access protocols:
+ -conversion to short address format
+ -access to audio block
+ This layer is placed between the drx_dap_fasi and the rest of the drxj
+ specific implementation. This layer can use address map knowledge whereas
+ dap_fasi may not use memory map knowledge.
+
+ * For audio currently only 16 bits read and write register access is
+ supported. More is not needed. RMW and 32 or 8 bit access on audio
+ registers will have undefined behaviour. Flags (RMW, CRC reset, broadcast
+ single/multi master) will be ignored.
+
+ TODO: check ignoring single/multimaster is ok for AUD access ?
+*/
+
+#define DRXJ_ISAUDWRITE(addr) (((((addr)>>16)&1) == 1) ? true : false)
+#define DRXJ_DAP_AUDTRIF_TIMEOUT 80 /* millisec */
+/*============================================================================*/
+
+/**
+* \fn bool is_handled_by_aud_tr_if( u32 addr )
+* \brief Check if this address is handled by the audio token ring interface.
+* \param addr
+* \return bool
+* \retval true Yes, handled by audio token ring interface
+* \retval false No, not handled by audio token ring interface
+*
+*/
+static
+bool is_handled_by_aud_tr_if(u32 addr)
+{
+ bool retval = false;
+
+ if ((DRXDAP_FASI_ADDR2BLOCK(addr) == 4) &&
+ (DRXDAP_FASI_ADDR2BANK(addr) > 1) &&
+ (DRXDAP_FASI_ADDR2BANK(addr) < 6)) {
+ retval = true;
+ }
+
+ return retval;
+}
+
+/*============================================================================*/
+
+int drxbsp_i2c_write_read(struct i2c_device_addr *w_dev_addr,
+ u16 w_count,
+ u8 *wData,
+ struct i2c_device_addr *r_dev_addr,
+ u16 r_count, u8 *r_data)
+{
+ struct drx39xxj_state *state;
+ struct i2c_msg msg[2];
+ unsigned int num_msgs;
+
+ if (w_dev_addr == NULL) {
+ /* Read only */
+ state = r_dev_addr->user_data;
+ msg[0].addr = r_dev_addr->i2c_addr >> 1;
+ msg[0].flags = I2C_M_RD;
+ msg[0].buf = r_data;
+ msg[0].len = r_count;
+ num_msgs = 1;
+ } else if (r_dev_addr == NULL) {
+ /* Write only */
+ state = w_dev_addr->user_data;
+ msg[0].addr = w_dev_addr->i2c_addr >> 1;
+ msg[0].flags = 0;
+ msg[0].buf = wData;
+ msg[0].len = w_count;
+ num_msgs = 1;
+ } else {
+ /* Both write and read */
+ state = w_dev_addr->user_data;
+ msg[0].addr = w_dev_addr->i2c_addr >> 1;
+ msg[0].flags = 0;
+ msg[0].buf = wData;
+ msg[0].len = w_count;
+ msg[1].addr = r_dev_addr->i2c_addr >> 1;
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = r_data;
+ msg[1].len = r_count;
+ num_msgs = 2;
+ }
+
+ if (state->i2c == NULL) {
+ pr_err("i2c was zero, aborting\n");
+ return 0;
+ }
+ if (i2c_transfer(state->i2c, msg, num_msgs) != num_msgs) {
+ pr_warn("drx3933: I2C write/read failed\n");
+ return -EREMOTEIO;
+ }
+
+#ifdef DJH_DEBUG
+ if (w_dev_addr == NULL || r_dev_addr == NULL)
+ return 0;
+
+ state = w_dev_addr->user_data;
+
+ if (state->i2c == NULL)
+ return 0;
+
+ msg[0].addr = w_dev_addr->i2c_addr;
+ msg[0].flags = 0;
+ msg[0].buf = wData;
+ msg[0].len = w_count;
+ msg[1].addr = r_dev_addr->i2c_addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = r_data;
+ msg[1].len = r_count;
+ num_msgs = 2;
+
+ pr_debug("drx3933 i2c operation addr=%x i2c=%p, wc=%x rc=%x\n",
+ w_dev_addr->i2c_addr, state->i2c, w_count, r_count);
+
+ if (i2c_transfer(state->i2c, msg, 2) != 2) {
+ pr_warn("drx3933: I2C write/read failed\n");
+ return -EREMOTEIO;
+ }
+#endif
+ return 0;
+}
+
+/*============================================================================*/
+
+/******************************
+*
+* int drxdap_fasi_read_block (
+* struct i2c_device_addr *dev_addr, -- address of I2C device
+* u32 addr, -- address of chip register/memory
+* u16 datasize, -- number of bytes to read
+* u8 *data, -- data to receive
+* u32 flags) -- special device flags
+*
+* Read block data from chip address. Because the chip is word oriented,
+* the number of bytes to read must be even.
+*
+* Make sure that the buffer to receive the data is large enough.
+*
+* Although this function expects an even number of bytes, it is still byte
+* oriented, and the data read back is NOT translated to the endianness of
+* the target platform.
+*
+* Output:
+* - 0 if reading was successful
+* in that case: data read is in *data.
+* - -EIO if anything went wrong
+*
+******************************/
+
+static int drxdap_fasi_read_block(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u16 datasize,
+ u8 *data, u32 flags)
+{
+ u8 buf[4];
+ u16 bufx;
+ int rc;
+ u16 overhead_size = 0;
+
+ /* Check parameters ******************************************************* */
+ if (dev_addr == NULL)
+ return -EINVAL;
+
+ overhead_size = (IS_I2C_10BIT(dev_addr->i2c_addr) ? 2 : 1) +
+ (DRXDAP_FASI_LONG_FORMAT(addr) ? 4 : 2);
+
+ if ((DRXDAP_FASI_OFFSET_TOO_LARGE(addr)) ||
+ ((!(DRXDAPFASI_LONG_ADDR_ALLOWED)) &&
+ DRXDAP_FASI_LONG_FORMAT(addr)) ||
+ (overhead_size > (DRXDAP_MAX_WCHUNKSIZE)) ||
+ ((datasize != 0) && (data == NULL)) || ((datasize & 1) == 1)) {
+ return -EINVAL;
+ }
+
+ /* ReadModifyWrite & mode flag bits are not allowed */
+ flags &= (~DRXDAP_FASI_RMW & ~DRXDAP_FASI_MODEFLAGS);
+#if DRXDAP_SINGLE_MASTER
+ flags |= DRXDAP_FASI_SINGLE_MASTER;
+#endif
+
+ /* Read block from I2C **************************************************** */
+ do {
+ u16 todo = (datasize < DRXDAP_MAX_RCHUNKSIZE ?
+ datasize : DRXDAP_MAX_RCHUNKSIZE);
+
+ bufx = 0;
+
+ addr &= ~DRXDAP_FASI_FLAGS;
+ addr |= flags;
+
+#if ((DRXDAPFASI_LONG_ADDR_ALLOWED == 1) && (DRXDAPFASI_SHORT_ADDR_ALLOWED == 1))
+ /* short format address preferred but long format otherwise */
+ if (DRXDAP_FASI_LONG_FORMAT(addr)) {
+#endif
+#if (DRXDAPFASI_LONG_ADDR_ALLOWED == 1)
+ buf[bufx++] = (u8) (((addr << 1) & 0xFF) | 0x01);
+ buf[bufx++] = (u8) ((addr >> 16) & 0xFF);
+ buf[bufx++] = (u8) ((addr >> 24) & 0xFF);
+ buf[bufx++] = (u8) ((addr >> 7) & 0xFF);
+#endif
+#if ((DRXDAPFASI_LONG_ADDR_ALLOWED == 1) && (DRXDAPFASI_SHORT_ADDR_ALLOWED == 1))
+ } else {
+#endif
+#if (DRXDAPFASI_SHORT_ADDR_ALLOWED == 1)
+ buf[bufx++] = (u8) ((addr << 1) & 0xFF);
+ buf[bufx++] =
+ (u8) (((addr >> 16) & 0x0F) |
+ ((addr >> 18) & 0xF0));
+#endif
+#if ((DRXDAPFASI_LONG_ADDR_ALLOWED == 1) && (DRXDAPFASI_SHORT_ADDR_ALLOWED == 1))
+ }
+#endif
+
+#if DRXDAP_SINGLE_MASTER
+ /*
+ * In single master mode, split the read and write actions.
+ * No special action is needed for write chunks here.
+ */
+ rc = drxbsp_i2c_write_read(dev_addr, bufx, buf,
+ NULL, 0, NULL);
+ if (rc == 0)
+ rc = drxbsp_i2c_write_read(NULL, 0, NULL, dev_addr, todo, data);
+#else
+ /* In multi master mode, do everything in one RW action */
+ rc = drxbsp_i2c_write_read(dev_addr, bufx, buf, dev_addr, todo,
+ data);
+#endif
+ data += todo;
+ addr += (todo >> 1);
+ datasize -= todo;
+ } while (datasize && rc == 0);
+
+ return rc;
+}
+
+
+/******************************
+*
+* int drxdap_fasi_read_reg16 (
+* struct i2c_device_addr *dev_addr, -- address of I2C device
+* u32 addr, -- address of chip register/memory
+* u16 *data, -- data to receive
+* u32 flags) -- special device flags
+*
+* Read one 16-bit register or memory location. The data received back is
+* converted back to the target platform's endianness.
+*
+* Output:
+* - 0 if reading was successful
+* in that case: read data is at *data
+* - -EIO if anything went wrong
+*
+******************************/
+
+static int drxdap_fasi_read_reg16(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u16 *data, u32 flags)
+{
+ u8 buf[sizeof(*data)];
+ int rc;
+
+ if (!data)
+ return -EINVAL;
+
+ rc = drxdap_fasi_read_block(dev_addr, addr, sizeof(*data), buf, flags);
+ *data = buf[0] + (((u16) buf[1]) << 8);
+ return rc;
+}
+
+/******************************
+*
+* int drxdap_fasi_read_reg32 (
+* struct i2c_device_addr *dev_addr, -- address of I2C device
+* u32 addr, -- address of chip register/memory
+* u32 *data, -- data to receive
+* u32 flags) -- special device flags
+*
+* Read one 32-bit register or memory location. The data received back is
+* converted back to the target platform's endianness.
+*
+* Output:
+* - 0 if reading was successful
+* in that case: read data is at *data
+* - -EIO if anything went wrong
+*
+******************************/
+
+static int drxdap_fasi_read_reg32(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u32 *data, u32 flags)
+{
+ u8 buf[sizeof(*data)];
+ int rc;
+
+ if (!data)
+ return -EINVAL;
+
+ rc = drxdap_fasi_read_block(dev_addr, addr, sizeof(*data), buf, flags);
+ *data = (((u32) buf[0]) << 0) +
+ (((u32) buf[1]) << 8) +
+ (((u32) buf[2]) << 16) + (((u32) buf[3]) << 24);
+ return rc;
+}
+
+/******************************
+*
+* int drxdap_fasi_write_block (
+* struct i2c_device_addr *dev_addr, -- address of I2C device
+* u32 addr, -- address of chip register/memory
+* u16 datasize, -- number of bytes to read
+* u8 *data, -- data to receive
+* u32 flags) -- special device flags
+*
+* Write block data to chip address. Because the chip is word oriented,
+* the number of bytes to write must be even.
+*
+* Although this function expects an even number of bytes, it is still byte
+* oriented, and the data being written is NOT translated from the endianness of
+* the target platform.
+*
+* Output:
+* - 0 if writing was successful
+* - -EIO if anything went wrong
+*
+******************************/
+
+static int drxdap_fasi_write_block(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u16 datasize,
+ u8 *data, u32 flags)
+{
+ u8 buf[DRXDAP_MAX_WCHUNKSIZE];
+ int st = -EIO;
+ int first_err = 0;
+ u16 overhead_size = 0;
+ u16 block_size = 0;
+
+ /* Check parameters ******************************************************* */
+ if (dev_addr == NULL)
+ return -EINVAL;
+
+ overhead_size = (IS_I2C_10BIT(dev_addr->i2c_addr) ? 2 : 1) +
+ (DRXDAP_FASI_LONG_FORMAT(addr) ? 4 : 2);
+
+ if ((DRXDAP_FASI_OFFSET_TOO_LARGE(addr)) ||
+ ((!(DRXDAPFASI_LONG_ADDR_ALLOWED)) &&
+ DRXDAP_FASI_LONG_FORMAT(addr)) ||
+ (overhead_size > (DRXDAP_MAX_WCHUNKSIZE)) ||
+ ((datasize != 0) && (data == NULL)) || ((datasize & 1) == 1))
+ return -EINVAL;
+
+ flags &= DRXDAP_FASI_FLAGS;
+ flags &= ~DRXDAP_FASI_MODEFLAGS;
+#if DRXDAP_SINGLE_MASTER
+ flags |= DRXDAP_FASI_SINGLE_MASTER;
+#endif
+
+ /* Write block to I2C ***************************************************** */
+ block_size = ((DRXDAP_MAX_WCHUNKSIZE) - overhead_size) & ~1;
+ do {
+ u16 todo = 0;
+ u16 bufx = 0;
+
+ /* Buffer device address */
+ addr &= ~DRXDAP_FASI_FLAGS;
+ addr |= flags;
+#if (((DRXDAPFASI_LONG_ADDR_ALLOWED) == 1) && ((DRXDAPFASI_SHORT_ADDR_ALLOWED) == 1))
+ /* short format address preferred but long format otherwise */
+ if (DRXDAP_FASI_LONG_FORMAT(addr)) {
+#endif
+#if ((DRXDAPFASI_LONG_ADDR_ALLOWED) == 1)
+ buf[bufx++] = (u8) (((addr << 1) & 0xFF) | 0x01);
+ buf[bufx++] = (u8) ((addr >> 16) & 0xFF);
+ buf[bufx++] = (u8) ((addr >> 24) & 0xFF);
+ buf[bufx++] = (u8) ((addr >> 7) & 0xFF);
+#endif
+#if (((DRXDAPFASI_LONG_ADDR_ALLOWED) == 1) && ((DRXDAPFASI_SHORT_ADDR_ALLOWED) == 1))
+ } else {
+#endif
+#if ((DRXDAPFASI_SHORT_ADDR_ALLOWED) == 1)
+ buf[bufx++] = (u8) ((addr << 1) & 0xFF);
+ buf[bufx++] =
+ (u8) (((addr >> 16) & 0x0F) |
+ ((addr >> 18) & 0xF0));
+#endif
+#if (((DRXDAPFASI_LONG_ADDR_ALLOWED) == 1) && ((DRXDAPFASI_SHORT_ADDR_ALLOWED) == 1))
+ }
+#endif
+
+ /*
+ In single master mode block_size can be 0. In such a case this I2C
+ sequense will be visible: (1) write address {i2c addr,
+ 4 bytes chip address} (2) write data {i2c addr, 4 bytes data }
+ (3) write address (4) write data etc...
+ Addres must be rewriten because HI is reset after data transport and
+ expects an address.
+ */
+ todo = (block_size < datasize ? block_size : datasize);
+ if (todo == 0) {
+ u16 overhead_size_i2c_addr = 0;
+ u16 data_block_size = 0;
+
+ overhead_size_i2c_addr =
+ (IS_I2C_10BIT(dev_addr->i2c_addr) ? 2 : 1);
+ data_block_size =
+ (DRXDAP_MAX_WCHUNKSIZE - overhead_size_i2c_addr) & ~1;
+
+ /* write device address */
+ st = drxbsp_i2c_write_read(dev_addr,
+ (u16) (bufx),
+ buf,
+ (struct i2c_device_addr *)(NULL),
+ 0, (u8 *)(NULL));
+
+ if ((st != 0) && (first_err == 0)) {
+ /* at the end, return the first error encountered */
+ first_err = st;
+ }
+ bufx = 0;
+ todo =
+ (data_block_size <
+ datasize ? data_block_size : datasize);
+ }
+ memcpy(&buf[bufx], data, todo);
+ /* write (address if can do and) data */
+ st = drxbsp_i2c_write_read(dev_addr,
+ (u16) (bufx + todo),
+ buf,
+ (struct i2c_device_addr *)(NULL),
+ 0, (u8 *)(NULL));
+
+ if ((st != 0) && (first_err == 0)) {
+ /* at the end, return the first error encountered */
+ first_err = st;
+ }
+ datasize -= todo;
+ data += todo;
+ addr += (todo >> 1);
+ } while (datasize);
+
+ return first_err;
+}
+
+/******************************
+*
+* int drxdap_fasi_write_reg16 (
+* struct i2c_device_addr *dev_addr, -- address of I2C device
+* u32 addr, -- address of chip register/memory
+* u16 data, -- data to send
+* u32 flags) -- special device flags
+*
+* Write one 16-bit register or memory location. The data being written is
+* converted from the target platform's endianness to little endian.
+*
+* Output:
+* - 0 if writing was successful
+* - -EIO if anything went wrong
+*
+******************************/
+
+static int drxdap_fasi_write_reg16(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u16 data, u32 flags)
+{
+ u8 buf[sizeof(data)];
+
+ buf[0] = (u8) ((data >> 0) & 0xFF);
+ buf[1] = (u8) ((data >> 8) & 0xFF);
+
+ return drxdap_fasi_write_block(dev_addr, addr, sizeof(data), buf, flags);
+}
+
+/******************************
+*
+* int drxdap_fasi_read_modify_write_reg16 (
+* struct i2c_device_addr *dev_addr, -- address of I2C device
+* u32 waddr, -- address of chip register/memory
+* u32 raddr, -- chip address to read back from
+* u16 wdata, -- data to send
+* u16 *rdata) -- data to receive back
+*
+* Write 16-bit data, then read back the original contents of that location.
+* Requires long addressing format to be allowed.
+*
+* Before sending data, the data is converted to little endian. The
+* data received back is converted back to the target platform's endianness.
+*
+* WARNING: This function is only guaranteed to work if there is one
+* master on the I2C bus.
+*
+* Output:
+* - 0 if reading was successful
+* in that case: read back data is at *rdata
+* - -EIO if anything went wrong
+*
+******************************/
+
+static int drxdap_fasi_read_modify_write_reg16(struct i2c_device_addr *dev_addr,
+ u32 waddr,
+ u32 raddr,
+ u16 wdata, u16 *rdata)
+{
+ int rc = -EIO;
+
+#if (DRXDAPFASI_LONG_ADDR_ALLOWED == 1)
+ if (rdata == NULL)
+ return -EINVAL;
+
+ rc = drxdap_fasi_write_reg16(dev_addr, waddr, wdata, DRXDAP_FASI_RMW);
+ if (rc == 0)
+ rc = drxdap_fasi_read_reg16(dev_addr, raddr, rdata, 0);
+#endif
+
+ return rc;
+}
+
+/******************************
+*
+* int drxdap_fasi_write_reg32 (
+* struct i2c_device_addr *dev_addr, -- address of I2C device
+* u32 addr, -- address of chip register/memory
+* u32 data, -- data to send
+* u32 flags) -- special device flags
+*
+* Write one 32-bit register or memory location. The data being written is
+* converted from the target platform's endianness to little endian.
+*
+* Output:
+* - 0 if writing was successful
+* - -EIO if anything went wrong
+*
+******************************/
+
+static int drxdap_fasi_write_reg32(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u32 data, u32 flags)
+{
+ u8 buf[sizeof(data)];
+
+ buf[0] = (u8) ((data >> 0) & 0xFF);
+ buf[1] = (u8) ((data >> 8) & 0xFF);
+ buf[2] = (u8) ((data >> 16) & 0xFF);
+ buf[3] = (u8) ((data >> 24) & 0xFF);
+
+ return drxdap_fasi_write_block(dev_addr, addr, sizeof(data), buf, flags);
+}
+
+/*============================================================================*/
+
+/**
+* \fn int drxj_dap_rm_write_reg16short
+* \brief Read modify write 16 bits audio register using short format only.
+* \param dev_addr
+* \param waddr Address to write to
+* \param raddr Address to read from (usually SIO_HI_RA_RAM_S0_RMWBUF__A)
+* \param wdata Data to write
+* \param rdata Buffer for data to read
+* \return int
+* \retval 0 Succes
+* \retval -EIO Timeout, I2C error, illegal bank
+*
+* 16 bits register read modify write access using short addressing format only.
+* Requires knowledge of the registermap, thus device dependent.
+* Using DAP FASI directly to avoid endless recursion of RMWs to audio registers.
+*
+*/
+
+/* TODO correct define should be #if ( DRXDAPFASI_SHORT_ADDR_ALLOWED==1 )
+ See comments drxj_dap_read_modify_write_reg16 */
+#if (DRXDAPFASI_LONG_ADDR_ALLOWED == 0)
+static int drxj_dap_rm_write_reg16short(struct i2c_device_addr *dev_addr,
+ u32 waddr,
+ u32 raddr,
+ u16 wdata, u16 *rdata)
+{
+ int rc;
+
+ if (rdata == NULL)
+ return -EINVAL;
+
+ /* Set RMW flag */
+ rc = drxdap_fasi_write_reg16(dev_addr,
+ SIO_HI_RA_RAM_S0_FLG_ACC__A,
+ SIO_HI_RA_RAM_S0_FLG_ACC_S0_RWM__M,
+ 0x0000);
+ if (rc == 0) {
+ /* Write new data: triggers RMW */
+ rc = drxdap_fasi_write_reg16(dev_addr, waddr, wdata,
+ 0x0000);
+ }
+ if (rc == 0) {
+ /* Read old data */
+ rc = drxdap_fasi_read_reg16(dev_addr, raddr, rdata,
+ 0x0000);
+ }
+ if (rc == 0) {
+ /* Reset RMW flag */
+ rc = drxdap_fasi_write_reg16(dev_addr,
+ SIO_HI_RA_RAM_S0_FLG_ACC__A,
+ 0, 0x0000);
+ }
+
+ return rc;
+}
+#endif
+
+/*============================================================================*/
+
+static int drxj_dap_read_modify_write_reg16(struct i2c_device_addr *dev_addr,
+ u32 waddr,
+ u32 raddr,
+ u16 wdata, u16 *rdata)
+{
+ /* TODO: correct short/long addressing format decision,
+ now long format has higher prio then short because short also
+ needs virt bnks (not impl yet) for certain audio registers */
+#if (DRXDAPFASI_LONG_ADDR_ALLOWED == 1)
+ return drxdap_fasi_read_modify_write_reg16(dev_addr,
+ waddr,
+ raddr, wdata, rdata);
+#else
+ return drxj_dap_rm_write_reg16short(dev_addr, waddr, raddr, wdata, rdata);
+#endif
+}
+
+
+/*============================================================================*/
+
+/**
+* \fn int drxj_dap_read_aud_reg16
+* \brief Read 16 bits audio register
+* \param dev_addr
+* \param addr
+* \param data
+* \return int
+* \retval 0 Succes
+* \retval -EIO Timeout, I2C error, illegal bank
+*
+* 16 bits register read access via audio token ring interface.
+*
+*/
+static int drxj_dap_read_aud_reg16(struct i2c_device_addr *dev_addr,
+ u32 addr, u16 *data)
+{
+ u32 start_timer = 0;
+ u32 current_timer = 0;
+ u32 delta_timer = 0;
+ u16 tr_status = 0;
+ int stat = -EIO;
+
+ /* No read possible for bank 3, return with error */
+ if (DRXDAP_FASI_ADDR2BANK(addr) == 3) {
+ stat = -EINVAL;
+ } else {
+ const u32 write_bit = ((dr_xaddr_t) 1) << 16;
+
+ /* Force reset write bit */
+ addr &= (~write_bit);
+
+ /* Set up read */
+ start_timer = jiffies_to_msecs(jiffies);
+ do {
+ /* RMW to aud TR IF until request is granted or timeout */
+ stat = drxj_dap_read_modify_write_reg16(dev_addr,
+ addr,
+ SIO_HI_RA_RAM_S0_RMWBUF__A,
+ 0x0000, &tr_status);
+
+ if (stat != 0)
+ break;
+
+ current_timer = jiffies_to_msecs(jiffies);
+ delta_timer = current_timer - start_timer;
+ if (delta_timer > DRXJ_DAP_AUDTRIF_TIMEOUT) {
+ stat = -EIO;
+ break;
+ }
+
+ } while (((tr_status & AUD_TOP_TR_CTR_FIFO_LOCK__M) ==
+ AUD_TOP_TR_CTR_FIFO_LOCK_LOCKED) ||
+ ((tr_status & AUD_TOP_TR_CTR_FIFO_FULL__M) ==
+ AUD_TOP_TR_CTR_FIFO_FULL_FULL));
+ } /* if ( DRXDAP_FASI_ADDR2BANK(addr)!=3 ) */
+
+ /* Wait for read ready status or timeout */
+ if (stat == 0) {
+ start_timer = jiffies_to_msecs(jiffies);
+
+ while ((tr_status & AUD_TOP_TR_CTR_FIFO_RD_RDY__M) !=
+ AUD_TOP_TR_CTR_FIFO_RD_RDY_READY) {
+ stat = drxj_dap_read_reg16(dev_addr,
+ AUD_TOP_TR_CTR__A,
+ &tr_status, 0x0000);
+ if (stat != 0)
+ break;
+
+ current_timer = jiffies_to_msecs(jiffies);
+ delta_timer = current_timer - start_timer;
+ if (delta_timer > DRXJ_DAP_AUDTRIF_TIMEOUT) {
+ stat = -EIO;
+ break;
+ }
+ } /* while ( ... ) */
+ }
+
+ /* Read value */
+ if (stat == 0)
+ stat = drxj_dap_read_modify_write_reg16(dev_addr,
+ AUD_TOP_TR_RD_REG__A,
+ SIO_HI_RA_RAM_S0_RMWBUF__A,
+ 0x0000, data);
+ return stat;
+}
+
+/*============================================================================*/
+
+static int drxj_dap_read_reg16(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u16 *data, u32 flags)
+{
+ int stat = -EIO;
+
+ /* Check param */
+ if ((dev_addr == NULL) || (data == NULL))
+ return -EINVAL;
+
+ if (is_handled_by_aud_tr_if(addr))
+ stat = drxj_dap_read_aud_reg16(dev_addr, addr, data);
+ else
+ stat = drxdap_fasi_read_reg16(dev_addr, addr, data, flags);
+
+ return stat;
+}
+/*============================================================================*/
+
+/**
+* \fn int drxj_dap_write_aud_reg16
+* \brief Write 16 bits audio register
+* \param dev_addr
+* \param addr
+* \param data
+* \return int
+* \retval 0 Succes
+* \retval -EIO Timeout, I2C error, illegal bank
+*
+* 16 bits register write access via audio token ring interface.
+*
+*/
+static int drxj_dap_write_aud_reg16(struct i2c_device_addr *dev_addr,
+ u32 addr, u16 data)
+{
+ int stat = -EIO;
+
+ /* No write possible for bank 2, return with error */
+ if (DRXDAP_FASI_ADDR2BANK(addr) == 2) {
+ stat = -EINVAL;
+ } else {
+ u32 start_timer = 0;
+ u32 current_timer = 0;
+ u32 delta_timer = 0;
+ u16 tr_status = 0;
+ const u32 write_bit = ((dr_xaddr_t) 1) << 16;
+
+ /* Force write bit */
+ addr |= write_bit;
+ start_timer = jiffies_to_msecs(jiffies);
+ do {
+ /* RMW to aud TR IF until request is granted or timeout */
+ stat = drxj_dap_read_modify_write_reg16(dev_addr,
+ addr,
+ SIO_HI_RA_RAM_S0_RMWBUF__A,
+ data, &tr_status);
+ if (stat != 0)
+ break;
+
+ current_timer = jiffies_to_msecs(jiffies);
+ delta_timer = current_timer - start_timer;
+ if (delta_timer > DRXJ_DAP_AUDTRIF_TIMEOUT) {
+ stat = -EIO;
+ break;
+ }
+
+ } while (((tr_status & AUD_TOP_TR_CTR_FIFO_LOCK__M) ==
+ AUD_TOP_TR_CTR_FIFO_LOCK_LOCKED) ||
+ ((tr_status & AUD_TOP_TR_CTR_FIFO_FULL__M) ==
+ AUD_TOP_TR_CTR_FIFO_FULL_FULL));
+
+ } /* if ( DRXDAP_FASI_ADDR2BANK(addr)!=2 ) */
+
+ return stat;
+}
+
+/*============================================================================*/
+
+static int drxj_dap_write_reg16(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u16 data, u32 flags)
+{
+ int stat = -EIO;
+
+ /* Check param */
+ if (dev_addr == NULL)
+ return -EINVAL;
+
+ if (is_handled_by_aud_tr_if(addr))
+ stat = drxj_dap_write_aud_reg16(dev_addr, addr, data);
+ else
+ stat = drxdap_fasi_write_reg16(dev_addr,
+ addr, data, flags);
+
+ return stat;
+}
+
+/*============================================================================*/
+
+/* Free data ram in SIO HI */
+#define SIO_HI_RA_RAM_USR_BEGIN__A 0x420040
+#define SIO_HI_RA_RAM_USR_END__A 0x420060
+
+#define DRXJ_HI_ATOMIC_BUF_START (SIO_HI_RA_RAM_USR_BEGIN__A)
+#define DRXJ_HI_ATOMIC_BUF_END (SIO_HI_RA_RAM_USR_BEGIN__A + 7)
+#define DRXJ_HI_ATOMIC_READ SIO_HI_RA_RAM_PAR_3_ACP_RW_READ
+#define DRXJ_HI_ATOMIC_WRITE SIO_HI_RA_RAM_PAR_3_ACP_RW_WRITE
+
+/**
+* \fn int drxj_dap_atomic_read_write_block()
+* \brief Basic access routine for atomic read or write access
+* \param dev_addr pointer to i2c dev address
+* \param addr destination/source address
+* \param datasize size of data buffer in bytes
+* \param data pointer to data buffer
+* \return int
+* \retval 0 Succes
+* \retval -EIO Timeout, I2C error, illegal bank
+*
+*/
+static
+int drxj_dap_atomic_read_write_block(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u16 datasize,
+ u8 *data, bool read_flag)
+{
+ struct drxj_hi_cmd hi_cmd;
+ int rc;
+ u16 word;
+ u16 dummy = 0;
+ u16 i = 0;
+
+ /* Parameter check */
+ if (!data || !dev_addr || ((datasize % 2)) || ((datasize / 2) > 8))
+ return -EINVAL;
+
+ /* Set up HI parameters to read or write n bytes */
+ hi_cmd.cmd = SIO_HI_RA_RAM_CMD_ATOMIC_COPY;
+ hi_cmd.param1 =
+ (u16) ((DRXDAP_FASI_ADDR2BLOCK(DRXJ_HI_ATOMIC_BUF_START) << 6) +
+ DRXDAP_FASI_ADDR2BANK(DRXJ_HI_ATOMIC_BUF_START));
+ hi_cmd.param2 =
+ (u16) DRXDAP_FASI_ADDR2OFFSET(DRXJ_HI_ATOMIC_BUF_START);
+ hi_cmd.param3 = (u16) ((datasize / 2) - 1);
+ if (!read_flag)
+ hi_cmd.param3 |= DRXJ_HI_ATOMIC_WRITE;
+ else
+ hi_cmd.param3 |= DRXJ_HI_ATOMIC_READ;
+ hi_cmd.param4 = (u16) ((DRXDAP_FASI_ADDR2BLOCK(addr) << 6) +
+ DRXDAP_FASI_ADDR2BANK(addr));
+ hi_cmd.param5 = (u16) DRXDAP_FASI_ADDR2OFFSET(addr);
+
+ if (!read_flag) {
+ /* write data to buffer */
+ for (i = 0; i < (datasize / 2); i++) {
+
+ word = ((u16) data[2 * i]);
+ word += (((u16) data[(2 * i) + 1]) << 8);
+ drxj_dap_write_reg16(dev_addr,
+ (DRXJ_HI_ATOMIC_BUF_START + i),
+ word, 0);
+ }
+ }
+
+ rc = hi_command(dev_addr, &hi_cmd, &dummy);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ if (read_flag) {
+ /* read data from buffer */
+ for (i = 0; i < (datasize / 2); i++) {
+ drxj_dap_read_reg16(dev_addr,
+ (DRXJ_HI_ATOMIC_BUF_START + i),
+ &word, 0);
+ data[2 * i] = (u8) (word & 0xFF);
+ data[(2 * i) + 1] = (u8) (word >> 8);
+ }
+ }
+
+ return 0;
+
+rw_error:
+ return -EIO;
+
+}
+
+/*============================================================================*/
+
+/**
+* \fn int drxj_dap_atomic_read_reg32()
+* \brief Atomic read of 32 bits words
+*/
+static
+int drxj_dap_atomic_read_reg32(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u32 *data, u32 flags)
+{
+ u8 buf[sizeof(*data)];
+ int rc = -EIO;
+ u32 word = 0;
+
+ if (!data)
+ return -EINVAL;
+
+ rc = drxj_dap_atomic_read_write_block(dev_addr, addr,
+ sizeof(*data), buf, true);
+
+ if (rc < 0)
+ return 0;
+
+ word = (u32) buf[3];
+ word <<= 8;
+ word |= (u32) buf[2];
+ word <<= 8;
+ word |= (u32) buf[1];
+ word <<= 8;
+ word |= (u32) buf[0];
+
+ *data = word;
+
+ return rc;
+}
+
+/*============================================================================*/
+
+/*============================================================================*/
+/*== END DRXJ DAP FUNCTIONS ==*/
+/*============================================================================*/
+
+/*============================================================================*/
+/*============================================================================*/
+/*== HOST INTERFACE FUNCTIONS ==*/
+/*============================================================================*/
+/*============================================================================*/
+
+/**
+* \fn int hi_cfg_command()
+* \brief Configure HI with settings stored in the demod structure.
+* \param demod Demodulator.
+* \return int.
+*
+* This routine was created because to much orthogonal settings have
+* been put into one HI API function (configure). Especially the I2C bridge
+* enable/disable should not need re-configuration of the HI.
+*
+*/
+static int hi_cfg_command(const struct drx_demod_instance *demod)
+{
+ struct drxj_data *ext_attr = (struct drxj_data *) (NULL);
+ struct drxj_hi_cmd hi_cmd;
+ u16 result = 0;
+ int rc;
+
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+
+ hi_cmd.cmd = SIO_HI_RA_RAM_CMD_CONFIG;
+ hi_cmd.param1 = SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY;
+ hi_cmd.param2 = ext_attr->hi_cfg_timing_div;
+ hi_cmd.param3 = ext_attr->hi_cfg_bridge_delay;
+ hi_cmd.param4 = ext_attr->hi_cfg_wake_up_key;
+ hi_cmd.param5 = ext_attr->hi_cfg_ctrl;
+ hi_cmd.param6 = ext_attr->hi_cfg_transmit;
+
+ rc = hi_command(demod->my_i2c_dev_addr, &hi_cmd, &result);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Reset power down flag (set one call only) */
+ ext_attr->hi_cfg_ctrl &= (~(SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ));
+
+ return 0;
+
+rw_error:
+ return -EIO;
+}
+
+/**
+* \fn int hi_command()
+* \brief Configure HI with settings stored in the demod structure.
+* \param dev_addr I2C address.
+* \param cmd HI command.
+* \param result HI command result.
+* \return int.
+*
+* Sends command to HI
+*
+*/
+static int
+hi_command(struct i2c_device_addr *dev_addr, const struct drxj_hi_cmd *cmd, u16 *result)
+{
+ u16 wait_cmd = 0;
+ u16 nr_retries = 0;
+ bool powerdown_cmd = false;
+ int rc;
+
+ /* Write parameters */
+ switch (cmd->cmd) {
+
+ case SIO_HI_RA_RAM_CMD_CONFIG:
+ case SIO_HI_RA_RAM_CMD_ATOMIC_COPY:
+ rc = drxj_dap_write_reg16(dev_addr, SIO_HI_RA_RAM_PAR_6__A, cmd->param6, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_HI_RA_RAM_PAR_5__A, cmd->param5, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_HI_RA_RAM_PAR_4__A, cmd->param4, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_HI_RA_RAM_PAR_3__A, cmd->param3, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* fallthrough */
+ case SIO_HI_RA_RAM_CMD_BRDCTRL:
+ rc = drxj_dap_write_reg16(dev_addr, SIO_HI_RA_RAM_PAR_2__A, cmd->param2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_HI_RA_RAM_PAR_1__A, cmd->param1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* fallthrough */
+ case SIO_HI_RA_RAM_CMD_NULL:
+ /* No parameters */
+ break;
+
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ /* Write command */
+ rc = drxj_dap_write_reg16(dev_addr, SIO_HI_RA_RAM_CMD__A, cmd->cmd, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ if ((cmd->cmd) == SIO_HI_RA_RAM_CMD_RESET)
+ msleep(1);
+
+ /* Detect power down to ommit reading result */
+ powerdown_cmd = (bool) ((cmd->cmd == SIO_HI_RA_RAM_CMD_CONFIG) &&
+ (((cmd->
+ param5) & SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M)
+ == SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ));
+ if (!powerdown_cmd) {
+ /* Wait until command rdy */
+ do {
+ nr_retries++;
+ if (nr_retries > DRXJ_MAX_RETRIES) {
+ pr_err("timeout\n");
+ goto rw_error;
+ }
+
+ rc = drxj_dap_read_reg16(dev_addr, SIO_HI_RA_RAM_CMD__A, &wait_cmd, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ } while (wait_cmd != 0);
+
+ /* Read result */
+ rc = drxj_dap_read_reg16(dev_addr, SIO_HI_RA_RAM_RES__A, result, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ }
+ /* if ( powerdown_cmd == true ) */
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/**
+* \fn int init_hi( const struct drx_demod_instance *demod )
+* \brief Initialise and configurate HI.
+* \param demod pointer to demod data.
+* \return int Return status.
+* \retval 0 Success.
+* \retval -EIO Failure.
+*
+* Needs to know Psys (System Clock period) and Posc (Osc Clock period)
+* Need to store configuration in driver because of the way I2C
+* bridging is controlled.
+*
+*/
+static int init_hi(const struct drx_demod_instance *demod)
+{
+ struct drxj_data *ext_attr = (struct drxj_data *) (NULL);
+ struct drx_common_attr *common_attr = (struct drx_common_attr *) (NULL);
+ struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)(NULL);
+ int rc;
+
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+ common_attr = (struct drx_common_attr *) demod->my_common_attr;
+ dev_addr = demod->my_i2c_dev_addr;
+
+ /* PATCH for bug 5003, HI ucode v3.1.0 */
+ rc = drxj_dap_write_reg16(dev_addr, 0x4301D7, 0x801, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Timing div, 250ns/Psys */
+ /* Timing div, = ( delay (nano seconds) * sysclk (kHz) )/ 1000 */
+ ext_attr->hi_cfg_timing_div =
+ (u16) ((common_attr->sys_clock_freq / 1000) * HI_I2C_DELAY) / 1000;
+ /* Clipping */
+ if ((ext_attr->hi_cfg_timing_div) > SIO_HI_RA_RAM_PAR_2_CFG_DIV__M)
+ ext_attr->hi_cfg_timing_div = SIO_HI_RA_RAM_PAR_2_CFG_DIV__M;
+ /* Bridge delay, uses oscilator clock */
+ /* Delay = ( delay (nano seconds) * oscclk (kHz) )/ 1000 */
+ /* SDA brdige delay */
+ ext_attr->hi_cfg_bridge_delay =
+ (u16) ((common_attr->osc_clock_freq / 1000) * HI_I2C_BRIDGE_DELAY) /
+ 1000;
+ /* Clipping */
+ if ((ext_attr->hi_cfg_bridge_delay) > SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M)
+ ext_attr->hi_cfg_bridge_delay = SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M;
+ /* SCL bridge delay, same as SDA for now */
+ ext_attr->hi_cfg_bridge_delay += ((ext_attr->hi_cfg_bridge_delay) <<
+ SIO_HI_RA_RAM_PAR_3_CFG_DBL_SCL__B);
+ /* Wakeup key, setting the read flag (as suggest in the documentation) does
+ not always result into a working solution (barebones worked VI2C failed).
+ Not setting the bit works in all cases . */
+ ext_attr->hi_cfg_wake_up_key = DRXJ_WAKE_UP_KEY;
+ /* port/bridge/power down ctrl */
+ ext_attr->hi_cfg_ctrl = (SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE);
+ /* transit mode time out delay and watch dog divider */
+ ext_attr->hi_cfg_transmit = SIO_HI_RA_RAM_PAR_6__PRE;
+
+ rc = hi_cfg_command(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+
+rw_error:
+ return -EIO;
+}
+
+/*============================================================================*/
+/*== END HOST INTERFACE FUNCTIONS ==*/
+/*============================================================================*/
+
+/*============================================================================*/
+/*============================================================================*/
+/*== AUXILIARY FUNCTIONS ==*/
+/*============================================================================*/
+/*============================================================================*/
+
+/**
+* \fn int get_device_capabilities()
+* \brief Get and store device capabilities.
+* \param demod Pointer to demodulator instance.
+* \return int.
+* \return 0 Success
+* \retval -EIO Failure
+*
+* Depending on pulldowns on MDx pins the following internals are set:
+* * common_attr->osc_clock_freq
+* * ext_attr->has_lna
+* * ext_attr->has_ntsc
+* * ext_attr->has_btsc
+* * ext_attr->has_oob
+*
+*/
+static int get_device_capabilities(struct drx_demod_instance *demod)
+{
+ struct drx_common_attr *common_attr = (struct drx_common_attr *) (NULL);
+ struct drxj_data *ext_attr = (struct drxj_data *) NULL;
+ struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)(NULL);
+ u16 sio_pdr_ohw_cfg = 0;
+ u32 sio_top_jtagid_lo = 0;
+ u16 bid = 0;
+ int rc;
+
+ common_attr = (struct drx_common_attr *) demod->my_common_attr;
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+ dev_addr = demod->my_i2c_dev_addr;
+
+ rc = drxj_dap_write_reg16(dev_addr, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_read_reg16(dev_addr, SIO_PDR_OHW_CFG__A, &sio_pdr_ohw_cfg, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY__PRE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ switch ((sio_pdr_ohw_cfg & SIO_PDR_OHW_CFG_FREF_SEL__M)) {
+ case 0:
+ /* ignore (bypass ?) */
+ break;
+ case 1:
+ /* 27 MHz */
+ common_attr->osc_clock_freq = 27000;
+ break;
+ case 2:
+ /* 20.25 MHz */
+ common_attr->osc_clock_freq = 20250;
+ break;
+ case 3:
+ /* 4 MHz */
+ common_attr->osc_clock_freq = 4000;
+ break;
+ default:
+ return -EIO;
+ }
+
+ /*
+ Determine device capabilities
+ Based on pinning v47
+ */
+ rc = drxdap_fasi_read_reg32(dev_addr, SIO_TOP_JTAGID_LO__A, &sio_top_jtagid_lo, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ ext_attr->mfx = (u8) ((sio_top_jtagid_lo >> 29) & 0xF);
+
+ switch ((sio_top_jtagid_lo >> 12) & 0xFF) {
+ case 0x31:
+ rc = drxj_dap_write_reg16(dev_addr, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_read_reg16(dev_addr, SIO_PDR_UIO_IN_HI__A, &bid, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ bid = (bid >> 10) & 0xf;
+ rc = drxj_dap_write_reg16(dev_addr, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY__PRE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ ext_attr->has_lna = true;
+ ext_attr->has_ntsc = false;
+ ext_attr->has_btsc = false;
+ ext_attr->has_oob = false;
+ ext_attr->has_smatx = true;
+ ext_attr->has_smarx = false;
+ ext_attr->has_gpio = false;
+ ext_attr->has_irqn = false;
+ break;
+ case 0x33:
+ ext_attr->has_lna = false;
+ ext_attr->has_ntsc = false;
+ ext_attr->has_btsc = false;
+ ext_attr->has_oob = false;
+ ext_attr->has_smatx = true;
+ ext_attr->has_smarx = false;
+ ext_attr->has_gpio = false;
+ ext_attr->has_irqn = false;
+ break;
+ case 0x45:
+ ext_attr->has_lna = true;
+ ext_attr->has_ntsc = true;
+ ext_attr->has_btsc = false;
+ ext_attr->has_oob = false;
+ ext_attr->has_smatx = true;
+ ext_attr->has_smarx = true;
+ ext_attr->has_gpio = true;
+ ext_attr->has_irqn = false;
+ break;
+ case 0x46:
+ ext_attr->has_lna = false;
+ ext_attr->has_ntsc = true;
+ ext_attr->has_btsc = false;
+ ext_attr->has_oob = false;
+ ext_attr->has_smatx = true;
+ ext_attr->has_smarx = true;
+ ext_attr->has_gpio = true;
+ ext_attr->has_irqn = false;
+ break;
+ case 0x41:
+ ext_attr->has_lna = true;
+ ext_attr->has_ntsc = true;
+ ext_attr->has_btsc = true;
+ ext_attr->has_oob = false;
+ ext_attr->has_smatx = true;
+ ext_attr->has_smarx = true;
+ ext_attr->has_gpio = true;
+ ext_attr->has_irqn = false;
+ break;
+ case 0x43:
+ ext_attr->has_lna = false;
+ ext_attr->has_ntsc = true;
+ ext_attr->has_btsc = true;
+ ext_attr->has_oob = false;
+ ext_attr->has_smatx = true;
+ ext_attr->has_smarx = true;
+ ext_attr->has_gpio = true;
+ ext_attr->has_irqn = false;
+ break;
+ case 0x32:
+ ext_attr->has_lna = true;
+ ext_attr->has_ntsc = false;
+ ext_attr->has_btsc = false;
+ ext_attr->has_oob = true;
+ ext_attr->has_smatx = true;
+ ext_attr->has_smarx = true;
+ ext_attr->has_gpio = true;
+ ext_attr->has_irqn = true;
+ break;
+ case 0x34:
+ ext_attr->has_lna = false;
+ ext_attr->has_ntsc = true;
+ ext_attr->has_btsc = true;
+ ext_attr->has_oob = true;
+ ext_attr->has_smatx = true;
+ ext_attr->has_smarx = true;
+ ext_attr->has_gpio = true;
+ ext_attr->has_irqn = true;
+ break;
+ case 0x42:
+ ext_attr->has_lna = true;
+ ext_attr->has_ntsc = true;
+ ext_attr->has_btsc = true;
+ ext_attr->has_oob = true;
+ ext_attr->has_smatx = true;
+ ext_attr->has_smarx = true;
+ ext_attr->has_gpio = true;
+ ext_attr->has_irqn = true;
+ break;
+ case 0x44:
+ ext_attr->has_lna = false;
+ ext_attr->has_ntsc = true;
+ ext_attr->has_btsc = true;
+ ext_attr->has_oob = true;
+ ext_attr->has_smatx = true;
+ ext_attr->has_smarx = true;
+ ext_attr->has_gpio = true;
+ ext_attr->has_irqn = true;
+ break;
+ default:
+ /* Unknown device variant */
+ return -EIO;
+ break;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/**
+* \fn int power_up_device()
+* \brief Power up device.
+* \param demod Pointer to demodulator instance.
+* \return int.
+* \return 0 Success
+* \retval -EIO Failure, I2C or max retries reached
+*
+*/
+
+#ifndef DRXJ_MAX_RETRIES_POWERUP
+#define DRXJ_MAX_RETRIES_POWERUP 10
+#endif
+
+static int power_up_device(struct drx_demod_instance *demod)
+{
+ struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)(NULL);
+ u8 data = 0;
+ u16 retry_count = 0;
+ struct i2c_device_addr wake_up_addr;
+
+ dev_addr = demod->my_i2c_dev_addr;
+ wake_up_addr.i2c_addr = DRXJ_WAKE_UP_KEY;
+ wake_up_addr.i2c_dev_id = dev_addr->i2c_dev_id;
+ wake_up_addr.user_data = dev_addr->user_data;
+ /*
+ * I2C access may fail in this case: no ack
+ * dummy write must be used to wake uop device, dummy read must be used to
+ * reset HI state machine (avoiding actual writes)
+ */
+ do {
+ data = 0;
+ drxbsp_i2c_write_read(&wake_up_addr, 1, &data,
+ (struct i2c_device_addr *)(NULL), 0,
+ (u8 *)(NULL));
+ msleep(10);
+ retry_count++;
+ } while ((drxbsp_i2c_write_read
+ ((struct i2c_device_addr *) (NULL), 0, (u8 *)(NULL), dev_addr, 1,
+ &data)
+ != 0) && (retry_count < DRXJ_MAX_RETRIES_POWERUP));
+
+ /* Need some recovery time .... */
+ msleep(10);
+
+ if (retry_count == DRXJ_MAX_RETRIES_POWERUP)
+ return -EIO;
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/* MPEG Output Configuration Functions - begin */
+/*----------------------------------------------------------------------------*/
+/**
+* \fn int ctrl_set_cfg_mpeg_output()
+* \brief Set MPEG output configuration of the device.
+* \param devmod Pointer to demodulator instance.
+* \param cfg_data Pointer to mpeg output configuaration.
+* \return int.
+*
+* Configure MPEG output parameters.
+*
+*/
+static int
+ctrl_set_cfg_mpeg_output(struct drx_demod_instance *demod, struct drx_cfg_mpeg_output *cfg_data)
+{
+ struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)(NULL);
+ struct drxj_data *ext_attr = (struct drxj_data *) (NULL);
+ struct drx_common_attr *common_attr = (struct drx_common_attr *) (NULL);
+ int rc;
+ u16 fec_oc_reg_mode = 0;
+ u16 fec_oc_reg_ipr_mode = 0;
+ u16 fec_oc_reg_ipr_invert = 0;
+ u32 max_bit_rate = 0;
+ u32 rcn_rate = 0;
+ u32 nr_bits = 0;
+ u16 sio_pdr_md_cfg = 0;
+ /* data mask for the output data byte */
+ u16 invert_data_mask =
+ FEC_OC_IPR_INVERT_MD7__M | FEC_OC_IPR_INVERT_MD6__M |
+ FEC_OC_IPR_INVERT_MD5__M | FEC_OC_IPR_INVERT_MD4__M |
+ FEC_OC_IPR_INVERT_MD3__M | FEC_OC_IPR_INVERT_MD2__M |
+ FEC_OC_IPR_INVERT_MD1__M | FEC_OC_IPR_INVERT_MD0__M;
+
+ /* check arguments */
+ if ((demod == NULL) || (cfg_data == NULL))
+ return -EINVAL;
+
+ dev_addr = demod->my_i2c_dev_addr;
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+ common_attr = (struct drx_common_attr *) demod->my_common_attr;
+
+ if (cfg_data->enable_mpeg_output == true) {
+ /* quick and dirty patch to set MPEG incase current std is not
+ producing MPEG */
+ switch (ext_attr->standard) {
+ case DRX_STANDARD_8VSB:
+ case DRX_STANDARD_ITU_A:
+ case DRX_STANDARD_ITU_B:
+ case DRX_STANDARD_ITU_C:
+ break;
+ default:
+ return 0;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_OCR_INVERT__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ switch (ext_attr->standard) {
+ case DRX_STANDARD_8VSB:
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_FCT_USAGE__A, 7, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* 2048 bytes fifo ram */
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_TMD_CTL_UPD_RATE__A, 10, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_TMD_INT_UPD_RATE__A, 10, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_AVR_PARM_A__A, 5, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_AVR_PARM_B__A, 7, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_RCN_GAIN__A, 10, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* Low Water Mark for synchronization */
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_SNC_LWM__A, 3, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* High Water Mark for synchronization */
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_SNC_HWM__A, 5, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ case DRX_STANDARD_ITU_A:
+ case DRX_STANDARD_ITU_C:
+ switch (ext_attr->constellation) {
+ case DRX_CONSTELLATION_QAM256:
+ nr_bits = 8;
+ break;
+ case DRX_CONSTELLATION_QAM128:
+ nr_bits = 7;
+ break;
+ case DRX_CONSTELLATION_QAM64:
+ nr_bits = 6;
+ break;
+ case DRX_CONSTELLATION_QAM32:
+ nr_bits = 5;
+ break;
+ case DRX_CONSTELLATION_QAM16:
+ nr_bits = 4;
+ break;
+ default:
+ return -EIO;
+ } /* ext_attr->constellation */
+ /* max_bit_rate = symbol_rate * nr_bits * coef */
+ /* coef = 188/204 */
+ max_bit_rate =
+ (ext_attr->curr_symbol_rate / 8) * nr_bits * 188;
+ /* pass through b/c Annex A/c need following settings */
+ case DRX_STANDARD_ITU_B:
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_FCT_USAGE__A, FEC_OC_FCT_USAGE__PRE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_TMD_CTL_UPD_RATE__A, FEC_OC_TMD_CTL_UPD_RATE__PRE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_TMD_INT_UPD_RATE__A, 5, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_AVR_PARM_A__A, FEC_OC_AVR_PARM_A__PRE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_AVR_PARM_B__A, FEC_OC_AVR_PARM_B__PRE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (cfg_data->static_clk == true) {
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_RCN_GAIN__A, 0xD, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ } else {
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_RCN_GAIN__A, FEC_OC_RCN_GAIN__PRE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_SNC_LWM__A, 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_SNC_HWM__A, 12, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ default:
+ break;
+ } /* swtich (standard) */
+
+ /* Check insertion of the Reed-Solomon parity bytes */
+ rc = drxj_dap_read_reg16(dev_addr, FEC_OC_MODE__A, &fec_oc_reg_mode, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_read_reg16(dev_addr, FEC_OC_IPR_MODE__A, &fec_oc_reg_ipr_mode, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (cfg_data->insert_rs_byte == true) {
+ /* enable parity symbol forward */
+ fec_oc_reg_mode |= FEC_OC_MODE_PARITY__M;
+ /* MVAL disable during parity bytes */
+ fec_oc_reg_ipr_mode |= FEC_OC_IPR_MODE_MVAL_DIS_PAR__M;
+ switch (ext_attr->standard) {
+ case DRX_STANDARD_8VSB:
+ rcn_rate = 0x004854D3;
+ break;
+ case DRX_STANDARD_ITU_B:
+ fec_oc_reg_mode |= FEC_OC_MODE_TRANSPARENT__M;
+ switch (ext_attr->constellation) {
+ case DRX_CONSTELLATION_QAM256:
+ rcn_rate = 0x008945E7;
+ break;
+ case DRX_CONSTELLATION_QAM64:
+ rcn_rate = 0x005F64D4;
+ break;
+ default:
+ return -EIO;
+ }
+ break;
+ case DRX_STANDARD_ITU_A:
+ case DRX_STANDARD_ITU_C:
+ /* insert_rs_byte = true -> coef = 188/188 -> 1, RS bits are in MPEG output */
+ rcn_rate =
+ (frac28
+ (max_bit_rate,
+ (u32) (common_attr->sys_clock_freq / 8))) /
+ 188;
+ break;
+ default:
+ return -EIO;
+ } /* ext_attr->standard */
+ } else { /* insert_rs_byte == false */
+
+ /* disable parity symbol forward */
+ fec_oc_reg_mode &= (~FEC_OC_MODE_PARITY__M);
+ /* MVAL enable during parity bytes */
+ fec_oc_reg_ipr_mode &= (~FEC_OC_IPR_MODE_MVAL_DIS_PAR__M);
+ switch (ext_attr->standard) {
+ case DRX_STANDARD_8VSB:
+ rcn_rate = 0x0041605C;
+ break;
+ case DRX_STANDARD_ITU_B:
+ fec_oc_reg_mode &= (~FEC_OC_MODE_TRANSPARENT__M);
+ switch (ext_attr->constellation) {
+ case DRX_CONSTELLATION_QAM256:
+ rcn_rate = 0x0082D6A0;
+ break;
+ case DRX_CONSTELLATION_QAM64:
+ rcn_rate = 0x005AEC1A;
+ break;
+ default:
+ return -EIO;
+ }
+ break;
+ case DRX_STANDARD_ITU_A:
+ case DRX_STANDARD_ITU_C:
+ /* insert_rs_byte = false -> coef = 188/204, RS bits not in MPEG output */
+ rcn_rate =
+ (frac28
+ (max_bit_rate,
+ (u32) (common_attr->sys_clock_freq / 8))) /
+ 204;
+ break;
+ default:
+ return -EIO;
+ } /* ext_attr->standard */
+ }
+
+ if (cfg_data->enable_parallel == true) { /* MPEG data output is paralel -> clear ipr_mode[0] */
+ fec_oc_reg_ipr_mode &= (~(FEC_OC_IPR_MODE_SERIAL__M));
+ } else { /* MPEG data output is serial -> set ipr_mode[0] */
+ fec_oc_reg_ipr_mode |= FEC_OC_IPR_MODE_SERIAL__M;
+ }
+
+ /* Control slective inversion of output bits */
+ if (cfg_data->invert_data == true)
+ fec_oc_reg_ipr_invert |= invert_data_mask;
+ else
+ fec_oc_reg_ipr_invert &= (~(invert_data_mask));
+
+ if (cfg_data->invert_err == true)
+ fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MERR__M;
+ else
+ fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MERR__M));
+
+ if (cfg_data->invert_str == true)
+ fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MSTRT__M;
+ else
+ fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MSTRT__M));
+
+ if (cfg_data->invert_val == true)
+ fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MVAL__M;
+ else
+ fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MVAL__M));
+
+ if (cfg_data->invert_clk == true)
+ fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MCLK__M;
+ else
+ fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MCLK__M));
+
+
+ if (cfg_data->static_clk == true) { /* Static mode */
+ u32 dto_rate = 0;
+ u32 bit_rate = 0;
+ u16 fec_oc_dto_burst_len = 0;
+ u16 fec_oc_dto_period = 0;
+
+ fec_oc_dto_burst_len = FEC_OC_DTO_BURST_LEN__PRE;
+
+ switch (ext_attr->standard) {
+ case DRX_STANDARD_8VSB:
+ fec_oc_dto_period = 4;
+ if (cfg_data->insert_rs_byte == true)
+ fec_oc_dto_burst_len = 208;
+ break;
+ case DRX_STANDARD_ITU_A:
+ {
+ u32 symbol_rate_th = 6400000;
+ if (cfg_data->insert_rs_byte == true) {
+ fec_oc_dto_burst_len = 204;
+ symbol_rate_th = 5900000;
+ }
+ if (ext_attr->curr_symbol_rate >=
+ symbol_rate_th) {
+ fec_oc_dto_period = 0;
+ } else {
+ fec_oc_dto_period = 1;
+ }
+ }
+ break;
+ case DRX_STANDARD_ITU_B:
+ fec_oc_dto_period = 1;
+ if (cfg_data->insert_rs_byte == true)
+ fec_oc_dto_burst_len = 128;
+ break;
+ case DRX_STANDARD_ITU_C:
+ fec_oc_dto_period = 1;
+ if (cfg_data->insert_rs_byte == true)
+ fec_oc_dto_burst_len = 204;
+ break;
+ default:
+ return -EIO;
+ }
+ bit_rate =
+ common_attr->sys_clock_freq * 1000 / (fec_oc_dto_period +
+ 2);
+ dto_rate =
+ frac28(bit_rate, common_attr->sys_clock_freq * 1000);
+ dto_rate >>= 3;
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_DTO_RATE_HI__A, (u16)((dto_rate >> 16) & FEC_OC_DTO_RATE_HI__M), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_DTO_RATE_LO__A, (u16)(dto_rate & FEC_OC_DTO_RATE_LO_RATE_LO__M), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_DTO_MODE__A, FEC_OC_DTO_MODE_DYNAMIC__M | FEC_OC_DTO_MODE_OFFSET_ENABLE__M, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_FCT_MODE__A, FEC_OC_FCT_MODE_RAT_ENA__M | FEC_OC_FCT_MODE_VIRT_ENA__M, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_DTO_BURST_LEN__A, fec_oc_dto_burst_len, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (ext_attr->mpeg_output_clock_rate != DRXJ_MPEGOUTPUT_CLOCK_RATE_AUTO)
+ fec_oc_dto_period = ext_attr->mpeg_output_clock_rate - 1;
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_DTO_PERIOD__A, fec_oc_dto_period, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ } else { /* Dynamic mode */
+
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_DTO_MODE__A, FEC_OC_DTO_MODE_DYNAMIC__M, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_FCT_MODE__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ rc = drxdap_fasi_write_reg32(dev_addr, FEC_OC_RCN_CTL_RATE_LO__A, rcn_rate, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Write appropriate registers with requested configuration */
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_MODE__A, fec_oc_reg_mode, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_IPR_MODE__A, fec_oc_reg_ipr_mode, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_IPR_INVERT__A, fec_oc_reg_ipr_invert, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* enabling for both parallel and serial now */
+ /* Write magic word to enable pdr reg write */
+ rc = drxj_dap_write_reg16(dev_addr, SIO_TOP_COMM_KEY__A, 0xFABA, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* Set MPEG TS pads to outputmode */
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MSTRT_CFG__A, 0x0013, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MERR_CFG__A, 0x0013, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MCLK_CFG__A, MPEG_OUTPUT_CLK_DRIVE_STRENGTH << SIO_PDR_MCLK_CFG_DRIVE__B | 0x03 << SIO_PDR_MCLK_CFG_MODE__B, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MVAL_CFG__A, 0x0013, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ sio_pdr_md_cfg =
+ MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH <<
+ SIO_PDR_MD0_CFG_DRIVE__B | 0x03 << SIO_PDR_MD0_CFG_MODE__B;
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD0_CFG__A, sio_pdr_md_cfg, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (cfg_data->enable_parallel == true) { /* MPEG data output is paralel -> set MD1 to MD7 to output mode */
+ sio_pdr_md_cfg =
+ MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH <<
+ SIO_PDR_MD0_CFG_DRIVE__B | 0x03 <<
+ SIO_PDR_MD0_CFG_MODE__B;
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD0_CFG__A, sio_pdr_md_cfg, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD1_CFG__A, sio_pdr_md_cfg, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD2_CFG__A, sio_pdr_md_cfg, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD3_CFG__A, sio_pdr_md_cfg, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD4_CFG__A, sio_pdr_md_cfg, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD5_CFG__A, sio_pdr_md_cfg, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD6_CFG__A, sio_pdr_md_cfg, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD7_CFG__A, sio_pdr_md_cfg, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ } else { /* MPEG data output is serial -> set MD1 to MD7 to tri-state */
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD1_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD2_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD3_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD4_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD5_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD6_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD7_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+ /* Enable Monitor Bus output over MPEG pads and ctl input */
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MON_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* Write nomagic word to enable pdr reg write */
+ rc = drxj_dap_write_reg16(dev_addr, SIO_TOP_COMM_KEY__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ } else {
+ /* Write magic word to enable pdr reg write */
+ rc = drxj_dap_write_reg16(dev_addr, SIO_TOP_COMM_KEY__A, 0xFABA, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* Set MPEG TS pads to inputmode */
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MSTRT_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MERR_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MCLK_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MVAL_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD0_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD1_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD2_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD3_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD4_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD5_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD6_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MD7_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* Enable Monitor Bus output over MPEG pads and ctl input */
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_MON_CFG__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* Write nomagic word to enable pdr reg write */
+ rc = drxj_dap_write_reg16(dev_addr, SIO_TOP_COMM_KEY__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ /* save values for restore after re-acquire */
+ common_attr->mpeg_cfg.enable_mpeg_output = cfg_data->enable_mpeg_output;
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*----------------------------------------------------------------------------*/
+
+
+/*----------------------------------------------------------------------------*/
+/* MPEG Output Configuration Functions - end */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* miscellaneous configuartions - begin */
+/*----------------------------------------------------------------------------*/
+
+/**
+* \fn int set_mpegtei_handling()
+* \brief Activate MPEG TEI handling settings.
+* \param devmod Pointer to demodulator instance.
+* \return int.
+*
+* This routine should be called during a set channel of QAM/VSB
+*
+*/
+static int set_mpegtei_handling(struct drx_demod_instance *demod)
+{
+ struct drxj_data *ext_attr = (struct drxj_data *) (NULL);
+ struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)(NULL);
+ int rc;
+ u16 fec_oc_dpr_mode = 0;
+ u16 fec_oc_snc_mode = 0;
+ u16 fec_oc_ems_mode = 0;
+
+ dev_addr = demod->my_i2c_dev_addr;
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+
+ rc = drxj_dap_read_reg16(dev_addr, FEC_OC_DPR_MODE__A, &fec_oc_dpr_mode, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_read_reg16(dev_addr, FEC_OC_SNC_MODE__A, &fec_oc_snc_mode, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_read_reg16(dev_addr, FEC_OC_EMS_MODE__A, &fec_oc_ems_mode, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* reset to default, allow TEI bit to be changed */
+ fec_oc_dpr_mode &= (~FEC_OC_DPR_MODE_ERR_DISABLE__M);
+ fec_oc_snc_mode &= (~(FEC_OC_SNC_MODE_ERROR_CTL__M |
+ FEC_OC_SNC_MODE_CORR_DISABLE__M));
+ fec_oc_ems_mode &= (~FEC_OC_EMS_MODE_MODE__M);
+
+ if (ext_attr->disable_te_ihandling) {
+ /* do not change TEI bit */
+ fec_oc_dpr_mode |= FEC_OC_DPR_MODE_ERR_DISABLE__M;
+ fec_oc_snc_mode |= FEC_OC_SNC_MODE_CORR_DISABLE__M |
+ ((0x2) << (FEC_OC_SNC_MODE_ERROR_CTL__B));
+ fec_oc_ems_mode |= ((0x01) << (FEC_OC_EMS_MODE_MODE__B));
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_DPR_MODE__A, fec_oc_dpr_mode, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_SNC_MODE__A, fec_oc_snc_mode, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_EMS_MODE__A, fec_oc_ems_mode, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+* \fn int bit_reverse_mpeg_output()
+* \brief Set MPEG output bit-endian settings.
+* \param devmod Pointer to demodulator instance.
+* \return int.
+*
+* This routine should be called during a set channel of QAM/VSB
+*
+*/
+static int bit_reverse_mpeg_output(struct drx_demod_instance *demod)
+{
+ struct drxj_data *ext_attr = (struct drxj_data *) (NULL);
+ struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)(NULL);
+ int rc;
+ u16 fec_oc_ipr_mode = 0;
+
+ dev_addr = demod->my_i2c_dev_addr;
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+
+ rc = drxj_dap_read_reg16(dev_addr, FEC_OC_IPR_MODE__A, &fec_oc_ipr_mode, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* reset to default (normal bit order) */
+ fec_oc_ipr_mode &= (~FEC_OC_IPR_MODE_REVERSE_ORDER__M);
+
+ if (ext_attr->bit_reverse_mpeg_outout)
+ fec_oc_ipr_mode |= FEC_OC_IPR_MODE_REVERSE_ORDER__M;
+
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_IPR_MODE__A, fec_oc_ipr_mode, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+* \fn int set_mpeg_start_width()
+* \brief Set MPEG start width.
+* \param devmod Pointer to demodulator instance.
+* \return int.
+*
+* This routine should be called during a set channel of QAM/VSB
+*
+*/
+static int set_mpeg_start_width(struct drx_demod_instance *demod)
+{
+ struct drxj_data *ext_attr = (struct drxj_data *) (NULL);
+ struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)(NULL);
+ struct drx_common_attr *common_attr = (struct drx_common_attr *) NULL;
+ int rc;
+ u16 fec_oc_comm_mb = 0;
+
+ dev_addr = demod->my_i2c_dev_addr;
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+ common_attr = demod->my_common_attr;
+
+ if ((common_attr->mpeg_cfg.static_clk == true)
+ && (common_attr->mpeg_cfg.enable_parallel == false)) {
+ rc = drxj_dap_read_reg16(dev_addr, FEC_OC_COMM_MB__A, &fec_oc_comm_mb, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ fec_oc_comm_mb &= ~FEC_OC_COMM_MB_CTL_ON;
+ if (ext_attr->mpeg_start_width == DRXJ_MPEG_START_WIDTH_8CLKCYC)
+ fec_oc_comm_mb |= FEC_OC_COMM_MB_CTL_ON;
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_COMM_MB__A, fec_oc_comm_mb, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*----------------------------------------------------------------------------*/
+/* miscellaneous configuartions - end */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* UIO Configuration Functions - begin */
+/*----------------------------------------------------------------------------*/
+/**
+* \fn int ctrl_set_uio_cfg()
+* \brief Configure modus oprandi UIO.
+* \param demod Pointer to demodulator instance.
+* \param uio_cfg Pointer to a configuration setting for a certain UIO.
+* \return int.
+*/
+static int ctrl_set_uio_cfg(struct drx_demod_instance *demod, struct drxuio_cfg *uio_cfg)
+{
+ struct drxj_data *ext_attr = (struct drxj_data *) (NULL);
+ int rc;
+
+ if ((uio_cfg == NULL) || (demod == NULL))
+ return -EINVAL;
+
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+
+ /* Write magic word to enable pdr reg write */
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ switch (uio_cfg->uio) {
+ /*====================================================================*/
+ case DRX_UIO1:
+ /* DRX_UIO1: SMA_TX UIO-1 */
+ if (!ext_attr->has_smatx)
+ return -EIO;
+ switch (uio_cfg->mode) {
+ case DRX_UIO_MODE_FIRMWARE_SMA: /* falltrough */
+ case DRX_UIO_MODE_FIRMWARE_SAW: /* falltrough */
+ case DRX_UIO_MODE_READWRITE:
+ ext_attr->uio_sma_tx_mode = uio_cfg->mode;
+ break;
+ case DRX_UIO_MODE_DISABLE:
+ ext_attr->uio_sma_tx_mode = uio_cfg->mode;
+ /* pad configuration register is set 0 - input mode */
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_PDR_SMA_TX_CFG__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ default:
+ return -EINVAL;
+ } /* switch ( uio_cfg->mode ) */
+ break;
+ /*====================================================================*/
+ case DRX_UIO2:
+ /* DRX_UIO2: SMA_RX UIO-2 */
+ if (!ext_attr->has_smarx)
+ return -EIO;
+ switch (uio_cfg->mode) {
+ case DRX_UIO_MODE_FIRMWARE0: /* falltrough */
+ case DRX_UIO_MODE_READWRITE:
+ ext_attr->uio_sma_rx_mode = uio_cfg->mode;
+ break;
+ case DRX_UIO_MODE_DISABLE:
+ ext_attr->uio_sma_rx_mode = uio_cfg->mode;
+ /* pad configuration register is set 0 - input mode */
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_PDR_SMA_RX_CFG__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ default:
+ return -EINVAL;
+ break;
+ } /* switch ( uio_cfg->mode ) */
+ break;
+ /*====================================================================*/
+ case DRX_UIO3:
+ /* DRX_UIO3: GPIO UIO-3 */
+ if (!ext_attr->has_gpio)
+ return -EIO;
+ switch (uio_cfg->mode) {
+ case DRX_UIO_MODE_FIRMWARE0: /* falltrough */
+ case DRX_UIO_MODE_READWRITE:
+ ext_attr->uio_gpio_mode = uio_cfg->mode;
+ break;
+ case DRX_UIO_MODE_DISABLE:
+ ext_attr->uio_gpio_mode = uio_cfg->mode;
+ /* pad configuration register is set 0 - input mode */
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_PDR_GPIO_CFG__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ default:
+ return -EINVAL;
+ break;
+ } /* switch ( uio_cfg->mode ) */
+ break;
+ /*====================================================================*/
+ case DRX_UIO4:
+ /* DRX_UIO4: IRQN UIO-4 */
+ if (!ext_attr->has_irqn)
+ return -EIO;
+ switch (uio_cfg->mode) {
+ case DRX_UIO_MODE_READWRITE:
+ ext_attr->uio_irqn_mode = uio_cfg->mode;
+ break;
+ case DRX_UIO_MODE_DISABLE:
+ /* pad configuration register is set 0 - input mode */
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_PDR_IRQN_CFG__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ ext_attr->uio_irqn_mode = uio_cfg->mode;
+ break;
+ case DRX_UIO_MODE_FIRMWARE0: /* falltrough */
+ default:
+ return -EINVAL;
+ break;
+ } /* switch ( uio_cfg->mode ) */
+ break;
+ /*====================================================================*/
+ default:
+ return -EINVAL;
+ } /* switch ( uio_cfg->uio ) */
+
+ /* Write magic word to disable pdr reg write */
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_TOP_COMM_KEY__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/**
+* \fn int ctrl_uio_write()
+* \brief Write to a UIO.
+* \param demod Pointer to demodulator instance.
+* \param uio_data Pointer to data container for a certain UIO.
+* \return int.
+*/
+static int
+ctrl_uio_write(struct drx_demod_instance *demod, struct drxuio_data *uio_data)
+{
+ struct drxj_data *ext_attr = (struct drxj_data *) (NULL);
+ int rc;
+ u16 pin_cfg_value = 0;
+ u16 value = 0;
+
+ if ((uio_data == NULL) || (demod == NULL))
+ return -EINVAL;
+
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+
+ /* Write magic word to enable pdr reg write */
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ switch (uio_data->uio) {
+ /*====================================================================*/
+ case DRX_UIO1:
+ /* DRX_UIO1: SMA_TX UIO-1 */
+ if (!ext_attr->has_smatx)
+ return -EIO;
+ if ((ext_attr->uio_sma_tx_mode != DRX_UIO_MODE_READWRITE)
+ && (ext_attr->uio_sma_tx_mode != DRX_UIO_MODE_FIRMWARE_SAW)) {
+ return -EIO;
+ }
+ pin_cfg_value = 0;
+ /* io_pad_cfg register (8 bit reg.) MSB bit is 1 (default value) */
+ pin_cfg_value |= 0x0113;
+ /* io_pad_cfg_mode output mode is drive always */
+ /* io_pad_cfg_drive is set to power 2 (23 mA) */
+
+ /* write to io pad configuration register - output mode */
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_PDR_SMA_TX_CFG__A, pin_cfg_value, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* use corresponding bit in io data output registar */
+ rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, SIO_PDR_UIO_OUT_LO__A, &value, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (!uio_data->value)
+ value &= 0x7FFF; /* write zero to 15th bit - 1st UIO */
+ else
+ value |= 0x8000; /* write one to 15th bit - 1st UIO */
+
+ /* write back to io data output register */
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_PDR_UIO_OUT_LO__A, value, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ /*======================================================================*/
+ case DRX_UIO2:
+ /* DRX_UIO2: SMA_RX UIO-2 */
+ if (!ext_attr->has_smarx)
+ return -EIO;
+ if (ext_attr->uio_sma_rx_mode != DRX_UIO_MODE_READWRITE)
+ return -EIO;
+
+ pin_cfg_value = 0;
+ /* io_pad_cfg register (8 bit reg.) MSB bit is 1 (default value) */
+ pin_cfg_value |= 0x0113;
+ /* io_pad_cfg_mode output mode is drive always */
+ /* io_pad_cfg_drive is set to power 2 (23 mA) */
+
+ /* write to io pad configuration register - output mode */
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_PDR_SMA_RX_CFG__A, pin_cfg_value, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* use corresponding bit in io data output registar */
+ rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, SIO_PDR_UIO_OUT_LO__A, &value, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (!uio_data->value)
+ value &= 0xBFFF; /* write zero to 14th bit - 2nd UIO */
+ else
+ value |= 0x4000; /* write one to 14th bit - 2nd UIO */
+
+ /* write back to io data output register */
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_PDR_UIO_OUT_LO__A, value, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ /*====================================================================*/
+ case DRX_UIO3:
+ /* DRX_UIO3: ASEL UIO-3 */
+ if (!ext_attr->has_gpio)
+ return -EIO;
+ if (ext_attr->uio_gpio_mode != DRX_UIO_MODE_READWRITE)
+ return -EIO;
+
+ pin_cfg_value = 0;
+ /* io_pad_cfg register (8 bit reg.) MSB bit is 1 (default value) */
+ pin_cfg_value |= 0x0113;
+ /* io_pad_cfg_mode output mode is drive always */
+ /* io_pad_cfg_drive is set to power 2 (23 mA) */
+
+ /* write to io pad configuration register - output mode */
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_PDR_GPIO_CFG__A, pin_cfg_value, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* use corresponding bit in io data output registar */
+ rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, SIO_PDR_UIO_OUT_HI__A, &value, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (!uio_data->value)
+ value &= 0xFFFB; /* write zero to 2nd bit - 3rd UIO */
+ else
+ value |= 0x0004; /* write one to 2nd bit - 3rd UIO */
+
+ /* write back to io data output register */
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_PDR_UIO_OUT_HI__A, value, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ /*=====================================================================*/
+ case DRX_UIO4:
+ /* DRX_UIO4: IRQN UIO-4 */
+ if (!ext_attr->has_irqn)
+ return -EIO;
+
+ if (ext_attr->uio_irqn_mode != DRX_UIO_MODE_READWRITE)
+ return -EIO;
+
+ pin_cfg_value = 0;
+ /* io_pad_cfg register (8 bit reg.) MSB bit is 1 (default value) */
+ pin_cfg_value |= 0x0113;
+ /* io_pad_cfg_mode output mode is drive always */
+ /* io_pad_cfg_drive is set to power 2 (23 mA) */
+
+ /* write to io pad configuration register - output mode */
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_PDR_IRQN_CFG__A, pin_cfg_value, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* use corresponding bit in io data output registar */
+ rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, SIO_PDR_UIO_OUT_LO__A, &value, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (uio_data->value == false)
+ value &= 0xEFFF; /* write zero to 12th bit - 4th UIO */
+ else
+ value |= 0x1000; /* write one to 12th bit - 4th UIO */
+
+ /* write back to io data output register */
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_PDR_UIO_OUT_LO__A, value, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ /*=====================================================================*/
+ default:
+ return -EINVAL;
+ } /* switch ( uio_data->uio ) */
+
+ /* Write magic word to disable pdr reg write */
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_TOP_COMM_KEY__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*---------------------------------------------------------------------------*/
+/* UIO Configuration Functions - end */
+/*---------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* I2C Bridge Functions - begin */
+/*----------------------------------------------------------------------------*/
+/**
+* \fn int ctrl_i2c_bridge()
+* \brief Open or close the I2C switch to tuner.
+* \param demod Pointer to demodulator instance.
+* \param bridge_closed Pointer to bool indication if bridge is closed not.
+* \return int.
+
+*/
+static int
+ctrl_i2c_bridge(struct drx_demod_instance *demod, bool *bridge_closed)
+{
+ struct drxj_hi_cmd hi_cmd;
+ u16 result = 0;
+
+ /* check arguments */
+ if (bridge_closed == NULL)
+ return -EINVAL;
+
+ hi_cmd.cmd = SIO_HI_RA_RAM_CMD_BRDCTRL;
+ hi_cmd.param1 = SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY;
+ if (*bridge_closed)
+ hi_cmd.param2 = SIO_HI_RA_RAM_PAR_2_BRD_CFG_CLOSED;
+ else
+ hi_cmd.param2 = SIO_HI_RA_RAM_PAR_2_BRD_CFG_OPEN;
+
+ return hi_command(demod->my_i2c_dev_addr, &hi_cmd, &result);
+}
+
+/*----------------------------------------------------------------------------*/
+/* I2C Bridge Functions - end */
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* Smart antenna Functions - begin */
+/*----------------------------------------------------------------------------*/
+/**
+* \fn int smart_ant_init()
+* \brief Initialize Smart Antenna.
+* \param pointer to struct drx_demod_instance.
+* \return int.
+*
+*/
+static int smart_ant_init(struct drx_demod_instance *demod)
+{
+ struct drxj_data *ext_attr = NULL;
+ struct i2c_device_addr *dev_addr = NULL;
+ struct drxuio_cfg uio_cfg = { DRX_UIO1, DRX_UIO_MODE_FIRMWARE_SMA };
+ int rc;
+ u16 data = 0;
+
+ dev_addr = demod->my_i2c_dev_addr;
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+
+ /* Write magic word to enable pdr reg write */
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* init smart antenna */
+ rc = drxj_dap_read_reg16(dev_addr, SIO_SA_TX_COMMAND__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (ext_attr->smart_ant_inverted) {
+ rc = drxj_dap_write_reg16(dev_addr, SIO_SA_TX_COMMAND__A, (data | SIO_SA_TX_COMMAND_TX_INVERT__M) | SIO_SA_TX_COMMAND_TX_ENABLE__M, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ } else {
+ rc = drxj_dap_write_reg16(dev_addr, SIO_SA_TX_COMMAND__A, (data & (~SIO_SA_TX_COMMAND_TX_INVERT__M)) | SIO_SA_TX_COMMAND_TX_ENABLE__M, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ /* config SMA_TX pin to smart antenna mode */
+ rc = ctrl_set_uio_cfg(demod, &uio_cfg);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_PDR_SMA_TX_CFG__A, 0x13, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_PDR_SMA_TX_GPIO_FNC__A, 0x03, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Write magic word to disable pdr reg write */
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, SIO_TOP_COMM_KEY__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+static int scu_command(struct i2c_device_addr *dev_addr, struct drxjscu_cmd *cmd)
+{
+ int rc;
+ u16 cur_cmd = 0;
+ unsigned long timeout;
+
+ /* Check param */
+ if (cmd == NULL)
+ return -EINVAL;
+
+ /* Wait until SCU command interface is ready to receive command */
+ rc = drxj_dap_read_reg16(dev_addr, SCU_RAM_COMMAND__A, &cur_cmd, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (cur_cmd != DRX_SCU_READY)
+ return -EIO;
+
+ switch (cmd->parameter_len) {
+ case 5:
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_PARAM_4__A, *(cmd->parameter + 4), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* fallthrough */
+ case 4:
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_PARAM_3__A, *(cmd->parameter + 3), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* fallthrough */
+ case 3:
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_PARAM_2__A, *(cmd->parameter + 2), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* fallthrough */
+ case 2:
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_PARAM_1__A, *(cmd->parameter + 1), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* fallthrough */
+ case 1:
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_PARAM_0__A, *(cmd->parameter + 0), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* fallthrough */
+ case 0:
+ /* do nothing */
+ break;
+ default:
+ /* this number of parameters is not supported */
+ return -EIO;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_COMMAND__A, cmd->command, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Wait until SCU has processed command */
+ timeout = jiffies + msecs_to_jiffies(DRXJ_MAX_WAITTIME);
+ while (time_is_after_jiffies(timeout)) {
+ rc = drxj_dap_read_reg16(dev_addr, SCU_RAM_COMMAND__A, &cur_cmd, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (cur_cmd == DRX_SCU_READY)
+ break;
+ usleep_range(1000, 2000);
+ }
+
+ if (cur_cmd != DRX_SCU_READY)
+ return -EIO;
+
+ /* read results */
+ if ((cmd->result_len > 0) && (cmd->result != NULL)) {
+ s16 err;
+
+ switch (cmd->result_len) {
+ case 4:
+ rc = drxj_dap_read_reg16(dev_addr, SCU_RAM_PARAM_3__A, cmd->result + 3, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* fallthrough */
+ case 3:
+ rc = drxj_dap_read_reg16(dev_addr, SCU_RAM_PARAM_2__A, cmd->result + 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* fallthrough */
+ case 2:
+ rc = drxj_dap_read_reg16(dev_addr, SCU_RAM_PARAM_1__A, cmd->result + 1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* fallthrough */
+ case 1:
+ rc = drxj_dap_read_reg16(dev_addr, SCU_RAM_PARAM_0__A, cmd->result + 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* fallthrough */
+ case 0:
+ /* do nothing */
+ break;
+ default:
+ /* this number of parameters is not supported */
+ return -EIO;
+ }
+
+ /* Check if an error was reported by SCU */
+ err = cmd->result[0];
+
+ /* check a few fixed error codes */
+ if ((err == (s16) SCU_RAM_PARAM_0_RESULT_UNKSTD)
+ || (err == (s16) SCU_RAM_PARAM_0_RESULT_UNKCMD)
+ || (err == (s16) SCU_RAM_PARAM_0_RESULT_INVPAR)
+ || (err == (s16) SCU_RAM_PARAM_0_RESULT_SIZE)
+ ) {
+ return -EINVAL;
+ }
+ /* here it is assumed that negative means error, and positive no error */
+ else if (err < 0)
+ return -EIO;
+ else
+ return 0;
+ }
+
+ return 0;
+
+rw_error:
+ return -EIO;
+}
+
+/**
+* \fn int DRXJ_DAP_SCUAtomicReadWriteBlock()
+* \brief Basic access routine for SCU atomic read or write access
+* \param dev_addr pointer to i2c dev address
+* \param addr destination/source address
+* \param datasize size of data buffer in bytes
+* \param data pointer to data buffer
+* \return int
+* \retval 0 Succes
+* \retval -EIO Timeout, I2C error, illegal bank
+*
+*/
+#define ADDR_AT_SCU_SPACE(x) ((x - 0x82E000) * 2)
+static
+int drxj_dap_scu_atomic_read_write_block(struct i2c_device_addr *dev_addr, u32 addr, u16 datasize, /* max 30 bytes because the limit of SCU parameter */
+ u8 *data, bool read_flag)
+{
+ struct drxjscu_cmd scu_cmd;
+ int rc;
+ u16 set_param_parameters[15];
+ u16 cmd_result[15];
+
+ /* Parameter check */
+ if (!data || !dev_addr || (datasize % 2) || ((datasize / 2) > 16))
+ return -EINVAL;
+
+ set_param_parameters[1] = (u16) ADDR_AT_SCU_SPACE(addr);
+ if (read_flag) { /* read */
+ set_param_parameters[0] = ((~(0x0080)) & datasize);
+ scu_cmd.parameter_len = 2;
+ scu_cmd.result_len = datasize / 2 + 2;
+ } else {
+ int i = 0;
+
+ set_param_parameters[0] = 0x0080 | datasize;
+ for (i = 0; i < (datasize / 2); i++) {
+ set_param_parameters[i + 2] =
+ (data[2 * i] | (data[(2 * i) + 1] << 8));
+ }
+ scu_cmd.parameter_len = datasize / 2 + 2;
+ scu_cmd.result_len = 1;
+ }
+
+ scu_cmd.command =
+ SCU_RAM_COMMAND_STANDARD_TOP |
+ SCU_RAM_COMMAND_CMD_AUX_SCU_ATOMIC_ACCESS;
+ scu_cmd.result = cmd_result;
+ scu_cmd.parameter = set_param_parameters;
+ rc = scu_command(dev_addr, &scu_cmd);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ if (read_flag) {
+ int i = 0;
+ /* read data from buffer */
+ for (i = 0; i < (datasize / 2); i++) {
+ data[2 * i] = (u8) (scu_cmd.result[i + 2] & 0xFF);
+ data[(2 * i) + 1] = (u8) (scu_cmd.result[i + 2] >> 8);
+ }
+ }
+
+ return 0;
+
+rw_error:
+ return -EIO;
+
+}
+
+/*============================================================================*/
+
+/**
+* \fn int DRXJ_DAP_AtomicReadReg16()
+* \brief Atomic read of 16 bits words
+*/
+static
+int drxj_dap_scu_atomic_read_reg16(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u16 *data, u32 flags)
+{
+ u8 buf[2];
+ int rc = -EIO;
+ u16 word = 0;
+
+ if (!data)
+ return -EINVAL;
+
+ rc = drxj_dap_scu_atomic_read_write_block(dev_addr, addr, 2, buf, true);
+ if (rc < 0)
+ return rc;
+
+ word = (u16) (buf[0] + (buf[1] << 8));
+
+ *data = word;
+
+ return rc;
+}
+
+/*============================================================================*/
+/**
+* \fn int drxj_dap_scu_atomic_write_reg16()
+* \brief Atomic read of 16 bits words
+*/
+static
+int drxj_dap_scu_atomic_write_reg16(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u16 data, u32 flags)
+{
+ u8 buf[2];
+ int rc = -EIO;
+
+ buf[0] = (u8) (data & 0xff);
+ buf[1] = (u8) ((data >> 8) & 0xff);
+
+ rc = drxj_dap_scu_atomic_read_write_block(dev_addr, addr, 2, buf, false);
+
+ return rc;
+}
+
+/* -------------------------------------------------------------------------- */
+/**
+* \brief Measure result of ADC synchronisation
+* \param demod demod instance
+* \param count (returned) count
+* \return int.
+* \retval 0 Success
+* \retval -EIO Failure: I2C error
+*
+*/
+static int adc_sync_measurement(struct drx_demod_instance *demod, u16 *count)
+{
+ struct i2c_device_addr *dev_addr = NULL;
+ int rc;
+ u16 data = 0;
+
+ dev_addr = demod->my_i2c_dev_addr;
+
+ /* Start measurement */
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_COMM_EXEC__A, IQM_AF_COMM_EXEC_ACTIVE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_START_LOCK__A, 1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Wait at least 3*128*(1/sysclk) <<< 1 millisec */
+ msleep(1);
+
+ *count = 0;
+ rc = drxj_dap_read_reg16(dev_addr, IQM_AF_PHASE0__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (data == 127)
+ *count = *count + 1;
+ rc = drxj_dap_read_reg16(dev_addr, IQM_AF_PHASE1__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (data == 127)
+ *count = *count + 1;
+ rc = drxj_dap_read_reg16(dev_addr, IQM_AF_PHASE2__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (data == 127)
+ *count = *count + 1;
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/**
+* \brief Synchronize analog and digital clock domains
+* \param demod demod instance
+* \return int.
+* \retval 0 Success
+* \retval -EIO Failure: I2C error or failure to synchronize
+*
+* An IQM reset will also reset the results of this synchronization.
+* After an IQM reset this routine needs to be called again.
+*
+*/
+
+static int adc_synchronization(struct drx_demod_instance *demod)
+{
+ struct i2c_device_addr *dev_addr = NULL;
+ int rc;
+ u16 count = 0;
+
+ dev_addr = demod->my_i2c_dev_addr;
+
+ rc = adc_sync_measurement(demod, &count);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ if (count == 1) {
+ /* Try sampling on a diffrent edge */
+ u16 clk_neg = 0;
+
+ rc = drxj_dap_read_reg16(dev_addr, IQM_AF_CLKNEG__A, &clk_neg, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ clk_neg ^= IQM_AF_CLKNEG_CLKNEGDATA__M;
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_CLKNEG__A, clk_neg, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = adc_sync_measurement(demod, &count);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ /* TODO: implement fallback scenarios */
+ if (count < 2)
+ return -EIO;
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*============================================================================*/
+/*== END AUXILIARY FUNCTIONS ==*/
+/*============================================================================*/
+
+/*============================================================================*/
+/*============================================================================*/
+/*== 8VSB & QAM COMMON DATAPATH FUNCTIONS ==*/
+/*============================================================================*/
+/*============================================================================*/
+/**
+* \fn int init_agc ()
+* \brief Initialize AGC for all standards.
+* \param demod instance of demodulator.
+* \param channel pointer to channel data.
+* \return int.
+*/
+static int init_agc(struct drx_demod_instance *demod)
+{
+ struct i2c_device_addr *dev_addr = NULL;
+ struct drx_common_attr *common_attr = NULL;
+ struct drxj_data *ext_attr = NULL;
+ struct drxj_cfg_agc *p_agc_rf_settings = NULL;
+ struct drxj_cfg_agc *p_agc_if_settings = NULL;
+ int rc;
+ u16 ingain_tgt_max = 0;
+ u16 clp_dir_to = 0;
+ u16 sns_sum_max = 0;
+ u16 clp_sum_max = 0;
+ u16 sns_dir_to = 0;
+ u16 ki_innergain_min = 0;
+ u16 agc_ki = 0;
+ u16 ki_max = 0;
+ u16 if_iaccu_hi_tgt_min = 0;
+ u16 data = 0;
+ u16 agc_ki_dgain = 0;
+ u16 ki_min = 0;
+ u16 clp_ctrl_mode = 0;
+ u16 agc_rf = 0;
+ u16 agc_if = 0;
+
+ dev_addr = demod->my_i2c_dev_addr;
+ common_attr = (struct drx_common_attr *) demod->my_common_attr;
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+
+ switch (ext_attr->standard) {
+ case DRX_STANDARD_8VSB:
+ clp_sum_max = 1023;
+ clp_dir_to = (u16) (-9);
+ sns_sum_max = 1023;
+ sns_dir_to = (u16) (-9);
+ ki_innergain_min = (u16) (-32768);
+ ki_max = 0x032C;
+ agc_ki_dgain = 0xC;
+ if_iaccu_hi_tgt_min = 2047;
+ ki_min = 0x0117;
+ ingain_tgt_max = 16383;
+ clp_ctrl_mode = 0;
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_KI_MINGAIN__A, 0x7fff, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_KI_MAXGAIN__A, 0x0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_CLP_SUM__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_CLP_CYCCNT__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_CLP_DIR_WD__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_CLP_DIR_STP__A, 1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_SNS_SUM__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_SNS_CYCCNT__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_SNS_DIR_WD__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_SNS_DIR_STP__A, 1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_INGAIN__A, 1024, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_VSB_AGC_POW_TGT__A, 22600, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_INGAIN_TGT__A, 13200, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ p_agc_if_settings = &(ext_attr->vsb_if_agc_cfg);
+ p_agc_rf_settings = &(ext_attr->vsb_rf_agc_cfg);
+ break;
+#ifndef DRXJ_VSB_ONLY
+ case DRX_STANDARD_ITU_A:
+ case DRX_STANDARD_ITU_C:
+ case DRX_STANDARD_ITU_B:
+ ingain_tgt_max = 5119;
+ clp_sum_max = 1023;
+ clp_dir_to = (u16) (-5);
+ sns_sum_max = 127;
+ sns_dir_to = (u16) (-3);
+ ki_innergain_min = 0;
+ ki_max = 0x0657;
+ if_iaccu_hi_tgt_min = 2047;
+ agc_ki_dgain = 0x7;
+ ki_min = 0x0117;
+ clp_ctrl_mode = 0;
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_KI_MINGAIN__A, 0x7fff, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_KI_MAXGAIN__A, 0x0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_CLP_SUM__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_CLP_CYCCNT__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_CLP_DIR_WD__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_CLP_DIR_STP__A, 1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_SNS_SUM__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_SNS_CYCCNT__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_SNS_DIR_WD__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_SNS_DIR_STP__A, 1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ p_agc_if_settings = &(ext_attr->qam_if_agc_cfg);
+ p_agc_rf_settings = &(ext_attr->qam_rf_agc_cfg);
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_INGAIN_TGT__A, p_agc_if_settings->top, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_read_reg16(dev_addr, SCU_RAM_AGC_KI__A, &agc_ki, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ agc_ki &= 0xf000;
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_KI__A, agc_ki, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+#endif
+ default:
+ return -EINVAL;
+ }
+
+ /* for new AGC interface */
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_INGAIN_TGT_MIN__A, p_agc_if_settings->top, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_INGAIN__A, p_agc_if_settings->top, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* Gain fed from inner to outer AGC */
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_INGAIN_TGT_MAX__A, ingain_tgt_max, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_IF_IACCU_HI_TGT_MIN__A, if_iaccu_hi_tgt_min, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_IF_IACCU_HI__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* set to p_agc_settings->top before */
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_IF_IACCU_LO__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_RF_IACCU_HI__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_RF_IACCU_LO__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_RF_MAX__A, 32767, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_CLP_SUM_MAX__A, clp_sum_max, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_SNS_SUM_MAX__A, sns_sum_max, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_KI_INNERGAIN_MIN__A, ki_innergain_min, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_FAST_SNS_CTRL_DELAY__A, 50, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_KI_CYCLEN__A, 500, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_SNS_CYCLEN__A, 500, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_KI_MAXMINGAIN_TH__A, 20, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_KI_MIN__A, ki_min, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_KI_MAX__A, ki_max, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_KI_RED__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_CLP_SUM_MIN__A, 8, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_CLP_CYCLEN__A, 500, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_CLP_DIR_TO__A, clp_dir_to, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_SNS_SUM_MIN__A, 8, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_SNS_DIR_TO__A, sns_dir_to, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A, 50, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_CLP_CTRL_MODE__A, clp_ctrl_mode, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ agc_rf = 0x800 + p_agc_rf_settings->cut_off_current;
+ if (common_attr->tuner_rf_agc_pol == true)
+ agc_rf = 0x87ff - agc_rf;
+
+ agc_if = 0x800;
+ if (common_attr->tuner_if_agc_pol == true)
+ agc_rf = 0x87ff - agc_rf;
+
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_AGC_RF__A, agc_rf, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_AGC_IF__A, agc_if, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Set/restore Ki DGAIN factor */
+ rc = drxj_dap_read_reg16(dev_addr, SCU_RAM_AGC_KI__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ data &= ~SCU_RAM_AGC_KI_DGAIN__M;
+ data |= (agc_ki_dgain << SCU_RAM_AGC_KI_DGAIN__B);
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_AGC_KI__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/**
+* \fn int set_frequency ()
+* \brief Set frequency shift.
+* \param demod instance of demodulator.
+* \param channel pointer to channel data.
+* \param tuner_freq_offset residual frequency from tuner.
+* \return int.
+*/
+static int
+set_frequency(struct drx_demod_instance *demod,
+ struct drx_channel *channel, s32 tuner_freq_offset)
+{
+ struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
+ struct drxj_data *ext_attr = demod->my_ext_attr;
+ int rc;
+ s32 sampling_frequency = 0;
+ s32 frequency_shift = 0;
+ s32 if_freq_actual = 0;
+ s32 rf_freq_residual = -1 * tuner_freq_offset;
+ s32 adc_freq = 0;
+ s32 intermediate_freq = 0;
+ u32 iqm_fs_rate_ofs = 0;
+ bool adc_flip = true;
+ bool select_pos_image = false;
+ bool rf_mirror;
+ bool tuner_mirror;
+ bool image_to_select = true;
+ s32 fm_frequency_shift = 0;
+
+ rf_mirror = (ext_attr->mirror == DRX_MIRROR_YES) ? true : false;
+ tuner_mirror = demod->my_common_attr->mirror_freq_spect ? false : true;
+ /*
+ Program frequency shifter
+ No need to account for mirroring on RF
+ */
+ switch (ext_attr->standard) {
+ case DRX_STANDARD_ITU_A: /* fallthrough */
+ case DRX_STANDARD_ITU_C: /* fallthrough */
+ case DRX_STANDARD_PAL_SECAM_LP: /* fallthrough */
+ case DRX_STANDARD_8VSB:
+ select_pos_image = true;
+ break;
+ case DRX_STANDARD_FM:
+ /* After IQM FS sound carrier must appear at 4 Mhz in spect.
+ Sound carrier is already 3Mhz above centre frequency due
+ to tuner setting so now add an extra shift of 1MHz... */
+ fm_frequency_shift = 1000;
+ case DRX_STANDARD_ITU_B: /* fallthrough */
+ case DRX_STANDARD_NTSC: /* fallthrough */
+ case DRX_STANDARD_PAL_SECAM_BG: /* fallthrough */
+ case DRX_STANDARD_PAL_SECAM_DK: /* fallthrough */
+ case DRX_STANDARD_PAL_SECAM_I: /* fallthrough */
+ case DRX_STANDARD_PAL_SECAM_L:
+ select_pos_image = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+ intermediate_freq = demod->my_common_attr->intermediate_freq;
+ sampling_frequency = demod->my_common_attr->sys_clock_freq / 3;
+ if (tuner_mirror)
+ if_freq_actual = intermediate_freq + rf_freq_residual + fm_frequency_shift;
+ else
+ if_freq_actual = intermediate_freq - rf_freq_residual - fm_frequency_shift;
+ if (if_freq_actual > sampling_frequency / 2) {
+ /* adc mirrors */
+ adc_freq = sampling_frequency - if_freq_actual;
+ adc_flip = true;
+ } else {
+ /* adc doesn't mirror */
+ adc_freq = if_freq_actual;
+ adc_flip = false;
+ }
+
+ frequency_shift = adc_freq;
+ image_to_select =
+ (bool) (rf_mirror ^ tuner_mirror ^ adc_flip ^ select_pos_image);
+ iqm_fs_rate_ofs = frac28(frequency_shift, sampling_frequency);
+
+ if (image_to_select)
+ iqm_fs_rate_ofs = ~iqm_fs_rate_ofs + 1;
+
+ /* Program frequency shifter with tuner offset compensation */
+ /* frequency_shift += tuner_freq_offset; TODO */
+ rc = drxdap_fasi_write_reg32(dev_addr, IQM_FS_RATE_OFS_LO__A, iqm_fs_rate_ofs, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ ext_attr->iqm_fs_rate_ofs = iqm_fs_rate_ofs;
+ ext_attr->pos_image = (bool) (rf_mirror ^ tuner_mirror ^ select_pos_image);
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/**
+* \fn int get_acc_pkt_err()
+* \brief Retrieve signal strength for VSB and QAM.
+* \param demod Pointer to demod instance
+* \param packet_err Pointer to packet error
+* \return int.
+* \retval 0 sig_strength contains valid data.
+* \retval -EINVAL sig_strength is NULL.
+* \retval -EIO Erroneous data, sig_strength contains invalid data.
+*/
+#ifdef DRXJ_SIGNAL_ACCUM_ERR
+static int get_acc_pkt_err(struct drx_demod_instance *demod, u16 *packet_err)
+{
+ int rc;
+ static u16 pkt_err;
+ static u16 last_pkt_err;
+ u16 data = 0;
+ struct drxj_data *ext_attr = NULL;
+ struct i2c_device_addr *dev_addr = NULL;
+
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+ dev_addr = demod->my_i2c_dev_addr;
+
+ rc = drxj_dap_read_reg16(dev_addr, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (ext_attr->reset_pkt_err_acc) {
+ last_pkt_err = data;
+ pkt_err = 0;
+ ext_attr->reset_pkt_err_acc = false;
+ }
+
+ if (data < last_pkt_err) {
+ pkt_err += 0xffff - last_pkt_err;
+ pkt_err += data;
+ } else {
+ pkt_err += (data - last_pkt_err);
+ }
+ *packet_err = pkt_err;
+ last_pkt_err = data;
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+#endif
+
+
+/*============================================================================*/
+
+/**
+* \fn int set_agc_rf ()
+* \brief Configure RF AGC
+* \param demod instance of demodulator.
+* \param agc_settings AGC configuration structure
+* \return int.
+*/
+static int
+set_agc_rf(struct drx_demod_instance *demod, struct drxj_cfg_agc *agc_settings, bool atomic)
+{
+ struct i2c_device_addr *dev_addr = NULL;
+ struct drxj_data *ext_attr = NULL;
+ struct drxj_cfg_agc *p_agc_settings = NULL;
+ struct drx_common_attr *common_attr = NULL;
+ int rc;
+ drx_write_reg16func_t scu_wr16 = NULL;
+ drx_read_reg16func_t scu_rr16 = NULL;
+
+ common_attr = (struct drx_common_attr *) demod->my_common_attr;
+ dev_addr = demod->my_i2c_dev_addr;
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+
+ if (atomic) {
+ scu_rr16 = drxj_dap_scu_atomic_read_reg16;
+ scu_wr16 = drxj_dap_scu_atomic_write_reg16;
+ } else {
+ scu_rr16 = drxj_dap_read_reg16;
+ scu_wr16 = drxj_dap_write_reg16;
+ }
+
+ /* Configure AGC only if standard is currently active */
+ if ((ext_attr->standard == agc_settings->standard) ||
+ (DRXJ_ISQAMSTD(ext_attr->standard) &&
+ DRXJ_ISQAMSTD(agc_settings->standard)) ||
+ (DRXJ_ISATVSTD(ext_attr->standard) &&
+ DRXJ_ISATVSTD(agc_settings->standard))) {
+ u16 data = 0;
+
+ switch (agc_settings->ctrl_mode) {
+ case DRX_AGC_CTRL_AUTO:
+
+ /* Enable RF AGC DAC */
+ rc = drxj_dap_read_reg16(dev_addr, IQM_AF_STDBY__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ data |= IQM_AF_STDBY_STDBY_TAGC_RF_A2_ACTIVE;
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_STDBY__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Enable SCU RF AGC loop */
+ rc = (*scu_rr16)(dev_addr, SCU_RAM_AGC_KI__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ data &= ~SCU_RAM_AGC_KI_RF__M;
+ if (ext_attr->standard == DRX_STANDARD_8VSB)
+ data |= (2 << SCU_RAM_AGC_KI_RF__B);
+ else if (DRXJ_ISQAMSTD(ext_attr->standard))
+ data |= (5 << SCU_RAM_AGC_KI_RF__B);
+ else
+ data |= (4 << SCU_RAM_AGC_KI_RF__B);
+
+ if (common_attr->tuner_rf_agc_pol)
+ data |= SCU_RAM_AGC_KI_INV_RF_POL__M;
+ else
+ data &= ~SCU_RAM_AGC_KI_INV_RF_POL__M;
+ rc = (*scu_wr16)(dev_addr, SCU_RAM_AGC_KI__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Set speed ( using complementary reduction value ) */
+ rc = (*scu_rr16)(dev_addr, SCU_RAM_AGC_KI_RED__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ data &= ~SCU_RAM_AGC_KI_RED_RAGC_RED__M;
+ rc = (*scu_wr16)(dev_addr, SCU_RAM_AGC_KI_RED__A, (~(agc_settings->speed << SCU_RAM_AGC_KI_RED_RAGC_RED__B) & SCU_RAM_AGC_KI_RED_RAGC_RED__M) | data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ if (agc_settings->standard == DRX_STANDARD_8VSB)
+ p_agc_settings = &(ext_attr->vsb_if_agc_cfg);
+ else if (DRXJ_ISQAMSTD(agc_settings->standard))
+ p_agc_settings = &(ext_attr->qam_if_agc_cfg);
+ else if (DRXJ_ISATVSTD(agc_settings->standard))
+ p_agc_settings = &(ext_attr->atv_if_agc_cfg);
+ else
+ return -EINVAL;
+
+ /* Set TOP, only if IF-AGC is in AUTO mode */
+ if (p_agc_settings->ctrl_mode == DRX_AGC_CTRL_AUTO) {
+ rc = (*scu_wr16)(dev_addr, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, agc_settings->top, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = (*scu_wr16)(dev_addr, SCU_RAM_AGC_IF_IACCU_HI_TGT__A, agc_settings->top, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ /* Cut-Off current */
+ rc = (*scu_wr16)(dev_addr, SCU_RAM_AGC_RF_IACCU_HI_CO__A, agc_settings->cut_off_current, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ case DRX_AGC_CTRL_USER:
+
+ /* Enable RF AGC DAC */
+ rc = drxj_dap_read_reg16(dev_addr, IQM_AF_STDBY__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ data |= IQM_AF_STDBY_STDBY_TAGC_RF_A2_ACTIVE;
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_STDBY__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Disable SCU RF AGC loop */
+ rc = (*scu_rr16)(dev_addr, SCU_RAM_AGC_KI__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ data &= ~SCU_RAM_AGC_KI_RF__M;
+ if (common_attr->tuner_rf_agc_pol)
+ data |= SCU_RAM_AGC_KI_INV_RF_POL__M;
+ else
+ data &= ~SCU_RAM_AGC_KI_INV_RF_POL__M;
+ rc = (*scu_wr16)(dev_addr, SCU_RAM_AGC_KI__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Write value to output pin */
+ rc = (*scu_wr16)(dev_addr, SCU_RAM_AGC_RF_IACCU_HI__A, agc_settings->output_level, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ case DRX_AGC_CTRL_OFF:
+
+ /* Disable RF AGC DAC */
+ rc = drxj_dap_read_reg16(dev_addr, IQM_AF_STDBY__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ data &= (~IQM_AF_STDBY_STDBY_TAGC_RF_A2_ACTIVE);
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_STDBY__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Disable SCU RF AGC loop */
+ rc = (*scu_rr16)(dev_addr, SCU_RAM_AGC_KI__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ data &= ~SCU_RAM_AGC_KI_RF__M;
+ rc = (*scu_wr16)(dev_addr, SCU_RAM_AGC_KI__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ default:
+ return -EINVAL;
+ } /* switch ( agcsettings->ctrl_mode ) */
+ }
+
+ /* Store rf agc settings */
+ switch (agc_settings->standard) {
+ case DRX_STANDARD_8VSB:
+ ext_attr->vsb_rf_agc_cfg = *agc_settings;
+ break;
+#ifndef DRXJ_VSB_ONLY
+ case DRX_STANDARD_ITU_A:
+ case DRX_STANDARD_ITU_B:
+ case DRX_STANDARD_ITU_C:
+ ext_attr->qam_rf_agc_cfg = *agc_settings;
+ break;
+#endif
+ default:
+ return -EIO;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/**
+* \fn int set_agc_if ()
+* \brief Configure If AGC
+* \param demod instance of demodulator.
+* \param agc_settings AGC configuration structure
+* \return int.
+*/
+static int
+set_agc_if(struct drx_demod_instance *demod, struct drxj_cfg_agc *agc_settings, bool atomic)
+{
+ struct i2c_device_addr *dev_addr = NULL;
+ struct drxj_data *ext_attr = NULL;
+ struct drxj_cfg_agc *p_agc_settings = NULL;
+ struct drx_common_attr *common_attr = NULL;
+ drx_write_reg16func_t scu_wr16 = NULL;
+ drx_read_reg16func_t scu_rr16 = NULL;
+ int rc;
+
+ common_attr = (struct drx_common_attr *) demod->my_common_attr;
+ dev_addr = demod->my_i2c_dev_addr;
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+
+ if (atomic) {
+ scu_rr16 = drxj_dap_scu_atomic_read_reg16;
+ scu_wr16 = drxj_dap_scu_atomic_write_reg16;
+ } else {
+ scu_rr16 = drxj_dap_read_reg16;
+ scu_wr16 = drxj_dap_write_reg16;
+ }
+
+ /* Configure AGC only if standard is currently active */
+ if ((ext_attr->standard == agc_settings->standard) ||
+ (DRXJ_ISQAMSTD(ext_attr->standard) &&
+ DRXJ_ISQAMSTD(agc_settings->standard)) ||
+ (DRXJ_ISATVSTD(ext_attr->standard) &&
+ DRXJ_ISATVSTD(agc_settings->standard))) {
+ u16 data = 0;
+
+ switch (agc_settings->ctrl_mode) {
+ case DRX_AGC_CTRL_AUTO:
+ /* Enable IF AGC DAC */
+ rc = drxj_dap_read_reg16(dev_addr, IQM_AF_STDBY__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ data |= IQM_AF_STDBY_STDBY_TAGC_IF_A2_ACTIVE;
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_STDBY__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Enable SCU IF AGC loop */
+ rc = (*scu_rr16)(dev_addr, SCU_RAM_AGC_KI__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ data &= ~SCU_RAM_AGC_KI_IF_AGC_DISABLE__M;
+ data &= ~SCU_RAM_AGC_KI_IF__M;
+ if (ext_attr->standard == DRX_STANDARD_8VSB)
+ data |= (3 << SCU_RAM_AGC_KI_IF__B);
+ else if (DRXJ_ISQAMSTD(ext_attr->standard))
+ data |= (6 << SCU_RAM_AGC_KI_IF__B);
+ else
+ data |= (5 << SCU_RAM_AGC_KI_IF__B);
+
+ if (common_attr->tuner_if_agc_pol)
+ data |= SCU_RAM_AGC_KI_INV_IF_POL__M;
+ else
+ data &= ~SCU_RAM_AGC_KI_INV_IF_POL__M;
+ rc = (*scu_wr16)(dev_addr, SCU_RAM_AGC_KI__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Set speed (using complementary reduction value) */
+ rc = (*scu_rr16)(dev_addr, SCU_RAM_AGC_KI_RED__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ data &= ~SCU_RAM_AGC_KI_RED_IAGC_RED__M;
+ rc = (*scu_wr16) (dev_addr, SCU_RAM_AGC_KI_RED__A, (~(agc_settings->speed << SCU_RAM_AGC_KI_RED_IAGC_RED__B) & SCU_RAM_AGC_KI_RED_IAGC_RED__M) | data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ if (agc_settings->standard == DRX_STANDARD_8VSB)
+ p_agc_settings = &(ext_attr->vsb_rf_agc_cfg);
+ else if (DRXJ_ISQAMSTD(agc_settings->standard))
+ p_agc_settings = &(ext_attr->qam_rf_agc_cfg);
+ else if (DRXJ_ISATVSTD(agc_settings->standard))
+ p_agc_settings = &(ext_attr->atv_rf_agc_cfg);
+ else
+ return -EINVAL;
+
+ /* Restore TOP */
+ if (p_agc_settings->ctrl_mode == DRX_AGC_CTRL_AUTO) {
+ rc = (*scu_wr16)(dev_addr, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, p_agc_settings->top, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = (*scu_wr16)(dev_addr, SCU_RAM_AGC_IF_IACCU_HI_TGT__A, p_agc_settings->top, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ } else {
+ rc = (*scu_wr16)(dev_addr, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = (*scu_wr16)(dev_addr, SCU_RAM_AGC_IF_IACCU_HI_TGT__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+ break;
+
+ case DRX_AGC_CTRL_USER:
+
+ /* Enable IF AGC DAC */
+ rc = drxj_dap_read_reg16(dev_addr, IQM_AF_STDBY__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ data |= IQM_AF_STDBY_STDBY_TAGC_IF_A2_ACTIVE;
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_STDBY__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Disable SCU IF AGC loop */
+ rc = (*scu_rr16)(dev_addr, SCU_RAM_AGC_KI__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ data &= ~SCU_RAM_AGC_KI_IF_AGC_DISABLE__M;
+ data |= SCU_RAM_AGC_KI_IF_AGC_DISABLE__M;
+ if (common_attr->tuner_if_agc_pol)
+ data |= SCU_RAM_AGC_KI_INV_IF_POL__M;
+ else
+ data &= ~SCU_RAM_AGC_KI_INV_IF_POL__M;
+ rc = (*scu_wr16)(dev_addr, SCU_RAM_AGC_KI__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Write value to output pin */
+ rc = (*scu_wr16)(dev_addr, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, agc_settings->output_level, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+
+ case DRX_AGC_CTRL_OFF:
+
+ /* Disable If AGC DAC */
+ rc = drxj_dap_read_reg16(dev_addr, IQM_AF_STDBY__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ data &= (~IQM_AF_STDBY_STDBY_TAGC_IF_A2_ACTIVE);
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_STDBY__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Disable SCU IF AGC loop */
+ rc = (*scu_rr16)(dev_addr, SCU_RAM_AGC_KI__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ data &= ~SCU_RAM_AGC_KI_IF_AGC_DISABLE__M;
+ data |= SCU_RAM_AGC_KI_IF_AGC_DISABLE__M;
+ rc = (*scu_wr16)(dev_addr, SCU_RAM_AGC_KI__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ default:
+ return -EINVAL;
+ } /* switch ( agcsettings->ctrl_mode ) */
+
+ /* always set the top to support configurations without if-loop */
+ rc = (*scu_wr16) (dev_addr, SCU_RAM_AGC_INGAIN_TGT_MIN__A, agc_settings->top, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ /* Store if agc settings */
+ switch (agc_settings->standard) {
+ case DRX_STANDARD_8VSB:
+ ext_attr->vsb_if_agc_cfg = *agc_settings;
+ break;
+#ifndef DRXJ_VSB_ONLY
+ case DRX_STANDARD_ITU_A:
+ case DRX_STANDARD_ITU_B:
+ case DRX_STANDARD_ITU_C:
+ ext_attr->qam_if_agc_cfg = *agc_settings;
+ break;
+#endif
+ default:
+ return -EIO;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/**
+* \fn int set_iqm_af ()
+* \brief Configure IQM AF registers
+* \param demod instance of demodulator.
+* \param active
+* \return int.
+*/
+static int set_iqm_af(struct drx_demod_instance *demod, bool active)
+{
+ u16 data = 0;
+ struct i2c_device_addr *dev_addr = NULL;
+ int rc;
+
+ dev_addr = demod->my_i2c_dev_addr;
+
+ /* Configure IQM */
+ rc = drxj_dap_read_reg16(dev_addr, IQM_AF_STDBY__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (!active)
+ data &= ((~IQM_AF_STDBY_STDBY_ADC_A2_ACTIVE) & (~IQM_AF_STDBY_STDBY_AMP_A2_ACTIVE) & (~IQM_AF_STDBY_STDBY_PD_A2_ACTIVE) & (~IQM_AF_STDBY_STDBY_TAGC_IF_A2_ACTIVE) & (~IQM_AF_STDBY_STDBY_TAGC_RF_A2_ACTIVE));
+ else
+ data |= (IQM_AF_STDBY_STDBY_ADC_A2_ACTIVE | IQM_AF_STDBY_STDBY_AMP_A2_ACTIVE | IQM_AF_STDBY_STDBY_PD_A2_ACTIVE | IQM_AF_STDBY_STDBY_TAGC_IF_A2_ACTIVE | IQM_AF_STDBY_STDBY_TAGC_RF_A2_ACTIVE);
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_STDBY__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*============================================================================*/
+/*== END 8VSB & QAM COMMON DATAPATH FUNCTIONS ==*/
+/*============================================================================*/
+
+/*============================================================================*/
+/*============================================================================*/
+/*== 8VSB DATAPATH FUNCTIONS ==*/
+/*============================================================================*/
+/*============================================================================*/
+
+/**
+* \fn int power_down_vsb ()
+* \brief Powr down QAM related blocks.
+* \param demod instance of demodulator.
+* \param channel pointer to channel data.
+* \return int.
+*/
+static int power_down_vsb(struct drx_demod_instance *demod, bool primary)
+{
+ struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
+ struct drxjscu_cmd cmd_scu = { /* command */ 0,
+ /* parameter_len */ 0,
+ /* result_len */ 0,
+ /* *parameter */ NULL,
+ /* *result */ NULL
+ };
+ struct drx_cfg_mpeg_output cfg_mpeg_output;
+ int rc;
+ u16 cmd_result = 0;
+
+ /*
+ STOP demodulator
+ reset of FEC and VSB HW
+ */
+ cmd_scu.command = SCU_RAM_COMMAND_STANDARD_VSB |
+ SCU_RAM_COMMAND_CMD_DEMOD_STOP;
+ cmd_scu.parameter_len = 0;
+ cmd_scu.result_len = 1;
+ cmd_scu.parameter = NULL;
+ cmd_scu.result = &cmd_result;
+ rc = scu_command(dev_addr, &cmd_scu);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* stop all comm_exec */
+ rc = drxj_dap_write_reg16(dev_addr, FEC_COMM_EXEC__A, FEC_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, VSB_COMM_EXEC__A, VSB_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (primary) {
+ rc = drxj_dap_write_reg16(dev_addr, IQM_COMM_EXEC__A, IQM_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = set_iqm_af(demod, false);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ } else {
+ rc = drxj_dap_write_reg16(dev_addr, IQM_FS_COMM_EXEC__A, IQM_FS_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_FD_COMM_EXEC__A, IQM_FD_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_RC_COMM_EXEC__A, IQM_RC_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_RT_COMM_EXEC__A, IQM_RT_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_CF_COMM_EXEC__A, IQM_CF_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ cfg_mpeg_output.enable_mpeg_output = false;
+ rc = ctrl_set_cfg_mpeg_output(demod, &cfg_mpeg_output);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/**
+* \fn int set_vsb_leak_n_gain ()
+* \brief Set ATSC demod.
+* \param demod instance of demodulator.
+* \return int.
+*/
+static int set_vsb_leak_n_gain(struct drx_demod_instance *demod)
+{
+ struct i2c_device_addr *dev_addr = NULL;
+ int rc;
+
+ const u8 vsb_ffe_leak_gain_ram0[] = {
+ DRXJ_16TO8(0x8), /* FFETRAINLKRATIO1 */
+ DRXJ_16TO8(0x8), /* FFETRAINLKRATIO2 */
+ DRXJ_16TO8(0x8), /* FFETRAINLKRATIO3 */
+ DRXJ_16TO8(0xf), /* FFETRAINLKRATIO4 */
+ DRXJ_16TO8(0xf), /* FFETRAINLKRATIO5 */
+ DRXJ_16TO8(0xf), /* FFETRAINLKRATIO6 */
+ DRXJ_16TO8(0xf), /* FFETRAINLKRATIO7 */
+ DRXJ_16TO8(0xf), /* FFETRAINLKRATIO8 */
+ DRXJ_16TO8(0xf), /* FFETRAINLKRATIO9 */
+ DRXJ_16TO8(0x8), /* FFETRAINLKRATIO10 */
+ DRXJ_16TO8(0x8), /* FFETRAINLKRATIO11 */
+ DRXJ_16TO8(0x8), /* FFETRAINLKRATIO12 */
+ DRXJ_16TO8(0x10), /* FFERCA1TRAINLKRATIO1 */
+ DRXJ_16TO8(0x10), /* FFERCA1TRAINLKRATIO2 */
+ DRXJ_16TO8(0x10), /* FFERCA1TRAINLKRATIO3 */
+ DRXJ_16TO8(0x20), /* FFERCA1TRAINLKRATIO4 */
+ DRXJ_16TO8(0x20), /* FFERCA1TRAINLKRATIO5 */
+ DRXJ_16TO8(0x20), /* FFERCA1TRAINLKRATIO6 */
+ DRXJ_16TO8(0x20), /* FFERCA1TRAINLKRATIO7 */
+ DRXJ_16TO8(0x20), /* FFERCA1TRAINLKRATIO8 */
+ DRXJ_16TO8(0x20), /* FFERCA1TRAINLKRATIO9 */
+ DRXJ_16TO8(0x10), /* FFERCA1TRAINLKRATIO10 */
+ DRXJ_16TO8(0x10), /* FFERCA1TRAINLKRATIO11 */
+ DRXJ_16TO8(0x10), /* FFERCA1TRAINLKRATIO12 */
+ DRXJ_16TO8(0x10), /* FFERCA1DATALKRATIO1 */
+ DRXJ_16TO8(0x10), /* FFERCA1DATALKRATIO2 */
+ DRXJ_16TO8(0x10), /* FFERCA1DATALKRATIO3 */
+ DRXJ_16TO8(0x20), /* FFERCA1DATALKRATIO4 */
+ DRXJ_16TO8(0x20), /* FFERCA1DATALKRATIO5 */
+ DRXJ_16TO8(0x20), /* FFERCA1DATALKRATIO6 */
+ DRXJ_16TO8(0x20), /* FFERCA1DATALKRATIO7 */
+ DRXJ_16TO8(0x20), /* FFERCA1DATALKRATIO8 */
+ DRXJ_16TO8(0x20), /* FFERCA1DATALKRATIO9 */
+ DRXJ_16TO8(0x10), /* FFERCA1DATALKRATIO10 */
+ DRXJ_16TO8(0x10), /* FFERCA1DATALKRATIO11 */
+ DRXJ_16TO8(0x10), /* FFERCA1DATALKRATIO12 */
+ DRXJ_16TO8(0x10), /* FFERCA2TRAINLKRATIO1 */
+ DRXJ_16TO8(0x10), /* FFERCA2TRAINLKRATIO2 */
+ DRXJ_16TO8(0x10), /* FFERCA2TRAINLKRATIO3 */
+ DRXJ_16TO8(0x20), /* FFERCA2TRAINLKRATIO4 */
+ DRXJ_16TO8(0x20), /* FFERCA2TRAINLKRATIO5 */
+ DRXJ_16TO8(0x20), /* FFERCA2TRAINLKRATIO6 */
+ DRXJ_16TO8(0x20), /* FFERCA2TRAINLKRATIO7 */
+ DRXJ_16TO8(0x20), /* FFERCA2TRAINLKRATIO8 */
+ DRXJ_16TO8(0x20), /* FFERCA2TRAINLKRATIO9 */
+ DRXJ_16TO8(0x10), /* FFERCA2TRAINLKRATIO10 */
+ DRXJ_16TO8(0x10), /* FFERCA2TRAINLKRATIO11 */
+ DRXJ_16TO8(0x10), /* FFERCA2TRAINLKRATIO12 */
+ DRXJ_16TO8(0x10), /* FFERCA2DATALKRATIO1 */
+ DRXJ_16TO8(0x10), /* FFERCA2DATALKRATIO2 */
+ DRXJ_16TO8(0x10), /* FFERCA2DATALKRATIO3 */
+ DRXJ_16TO8(0x20), /* FFERCA2DATALKRATIO4 */
+ DRXJ_16TO8(0x20), /* FFERCA2DATALKRATIO5 */
+ DRXJ_16TO8(0x20), /* FFERCA2DATALKRATIO6 */
+ DRXJ_16TO8(0x20), /* FFERCA2DATALKRATIO7 */
+ DRXJ_16TO8(0x20), /* FFERCA2DATALKRATIO8 */
+ DRXJ_16TO8(0x20), /* FFERCA2DATALKRATIO9 */
+ DRXJ_16TO8(0x10), /* FFERCA2DATALKRATIO10 */
+ DRXJ_16TO8(0x10), /* FFERCA2DATALKRATIO11 */
+ DRXJ_16TO8(0x10), /* FFERCA2DATALKRATIO12 */
+ DRXJ_16TO8(0x07), /* FFEDDM1TRAINLKRATIO1 */
+ DRXJ_16TO8(0x07), /* FFEDDM1TRAINLKRATIO2 */
+ DRXJ_16TO8(0x07), /* FFEDDM1TRAINLKRATIO3 */
+ DRXJ_16TO8(0x0e), /* FFEDDM1TRAINLKRATIO4 */
+ DRXJ_16TO8(0x0e), /* FFEDDM1TRAINLKRATIO5 */
+ DRXJ_16TO8(0x0e), /* FFEDDM1TRAINLKRATIO6 */
+ DRXJ_16TO8(0x0e), /* FFEDDM1TRAINLKRATIO7 */
+ DRXJ_16TO8(0x0e), /* FFEDDM1TRAINLKRATIO8 */
+ DRXJ_16TO8(0x0e), /* FFEDDM1TRAINLKRATIO9 */
+ DRXJ_16TO8(0x07), /* FFEDDM1TRAINLKRATIO10 */
+ DRXJ_16TO8(0x07), /* FFEDDM1TRAINLKRATIO11 */
+ DRXJ_16TO8(0x07), /* FFEDDM1TRAINLKRATIO12 */
+ DRXJ_16TO8(0x07), /* FFEDDM1DATALKRATIO1 */
+ DRXJ_16TO8(0x07), /* FFEDDM1DATALKRATIO2 */
+ DRXJ_16TO8(0x07), /* FFEDDM1DATALKRATIO3 */
+ DRXJ_16TO8(0x0e), /* FFEDDM1DATALKRATIO4 */
+ DRXJ_16TO8(0x0e), /* FFEDDM1DATALKRATIO5 */
+ DRXJ_16TO8(0x0e), /* FFEDDM1DATALKRATIO6 */
+ DRXJ_16TO8(0x0e), /* FFEDDM1DATALKRATIO7 */
+ DRXJ_16TO8(0x0e), /* FFEDDM1DATALKRATIO8 */
+ DRXJ_16TO8(0x0e), /* FFEDDM1DATALKRATIO9 */
+ DRXJ_16TO8(0x07), /* FFEDDM1DATALKRATIO10 */
+ DRXJ_16TO8(0x07), /* FFEDDM1DATALKRATIO11 */
+ DRXJ_16TO8(0x07), /* FFEDDM1DATALKRATIO12 */
+ DRXJ_16TO8(0x06), /* FFEDDM2TRAINLKRATIO1 */
+ DRXJ_16TO8(0x06), /* FFEDDM2TRAINLKRATIO2 */
+ DRXJ_16TO8(0x06), /* FFEDDM2TRAINLKRATIO3 */
+ DRXJ_16TO8(0x0c), /* FFEDDM2TRAINLKRATIO4 */
+ DRXJ_16TO8(0x0c), /* FFEDDM2TRAINLKRATIO5 */
+ DRXJ_16TO8(0x0c), /* FFEDDM2TRAINLKRATIO6 */
+ DRXJ_16TO8(0x0c), /* FFEDDM2TRAINLKRATIO7 */
+ DRXJ_16TO8(0x0c), /* FFEDDM2TRAINLKRATIO8 */
+ DRXJ_16TO8(0x0c), /* FFEDDM2TRAINLKRATIO9 */
+ DRXJ_16TO8(0x06), /* FFEDDM2TRAINLKRATIO10 */
+ DRXJ_16TO8(0x06), /* FFEDDM2TRAINLKRATIO11 */
+ DRXJ_16TO8(0x06), /* FFEDDM2TRAINLKRATIO12 */
+ DRXJ_16TO8(0x06), /* FFEDDM2DATALKRATIO1 */
+ DRXJ_16TO8(0x06), /* FFEDDM2DATALKRATIO2 */
+ DRXJ_16TO8(0x06), /* FFEDDM2DATALKRATIO3 */
+ DRXJ_16TO8(0x0c), /* FFEDDM2DATALKRATIO4 */
+ DRXJ_16TO8(0x0c), /* FFEDDM2DATALKRATIO5 */
+ DRXJ_16TO8(0x0c), /* FFEDDM2DATALKRATIO6 */
+ DRXJ_16TO8(0x0c), /* FFEDDM2DATALKRATIO7 */
+ DRXJ_16TO8(0x0c), /* FFEDDM2DATALKRATIO8 */
+ DRXJ_16TO8(0x0c), /* FFEDDM2DATALKRATIO9 */
+ DRXJ_16TO8(0x06), /* FFEDDM2DATALKRATIO10 */
+ DRXJ_16TO8(0x06), /* FFEDDM2DATALKRATIO11 */
+ DRXJ_16TO8(0x06), /* FFEDDM2DATALKRATIO12 */
+ DRXJ_16TO8(0x2020), /* FIRTRAINGAIN1 */
+ DRXJ_16TO8(0x2020), /* FIRTRAINGAIN2 */
+ DRXJ_16TO8(0x2020), /* FIRTRAINGAIN3 */
+ DRXJ_16TO8(0x4040), /* FIRTRAINGAIN4 */
+ DRXJ_16TO8(0x4040), /* FIRTRAINGAIN5 */
+ DRXJ_16TO8(0x4040), /* FIRTRAINGAIN6 */
+ DRXJ_16TO8(0x4040), /* FIRTRAINGAIN7 */
+ DRXJ_16TO8(0x4040), /* FIRTRAINGAIN8 */
+ DRXJ_16TO8(0x4040), /* FIRTRAINGAIN9 */
+ DRXJ_16TO8(0x2020), /* FIRTRAINGAIN10 */
+ DRXJ_16TO8(0x2020), /* FIRTRAINGAIN11 */
+ DRXJ_16TO8(0x2020), /* FIRTRAINGAIN12 */
+ DRXJ_16TO8(0x0808), /* FIRRCA1GAIN1 */
+ DRXJ_16TO8(0x0808), /* FIRRCA1GAIN2 */
+ DRXJ_16TO8(0x0808), /* FIRRCA1GAIN3 */
+ DRXJ_16TO8(0x1010), /* FIRRCA1GAIN4 */
+ DRXJ_16TO8(0x1010), /* FIRRCA1GAIN5 */
+ DRXJ_16TO8(0x1010), /* FIRRCA1GAIN6 */
+ DRXJ_16TO8(0x1010), /* FIRRCA1GAIN7 */
+ DRXJ_16TO8(0x1010) /* FIRRCA1GAIN8 */
+ };
+
+ const u8 vsb_ffe_leak_gain_ram1[] = {
+ DRXJ_16TO8(0x1010), /* FIRRCA1GAIN9 */
+ DRXJ_16TO8(0x0808), /* FIRRCA1GAIN10 */
+ DRXJ_16TO8(0x0808), /* FIRRCA1GAIN11 */
+ DRXJ_16TO8(0x0808), /* FIRRCA1GAIN12 */
+ DRXJ_16TO8(0x0808), /* FIRRCA2GAIN1 */
+ DRXJ_16TO8(0x0808), /* FIRRCA2GAIN2 */
+ DRXJ_16TO8(0x0808), /* FIRRCA2GAIN3 */
+ DRXJ_16TO8(0x1010), /* FIRRCA2GAIN4 */
+ DRXJ_16TO8(0x1010), /* FIRRCA2GAIN5 */
+ DRXJ_16TO8(0x1010), /* FIRRCA2GAIN6 */
+ DRXJ_16TO8(0x1010), /* FIRRCA2GAIN7 */
+ DRXJ_16TO8(0x1010), /* FIRRCA2GAIN8 */
+ DRXJ_16TO8(0x1010), /* FIRRCA2GAIN9 */
+ DRXJ_16TO8(0x0808), /* FIRRCA2GAIN10 */
+ DRXJ_16TO8(0x0808), /* FIRRCA2GAIN11 */
+ DRXJ_16TO8(0x0808), /* FIRRCA2GAIN12 */
+ DRXJ_16TO8(0x0303), /* FIRDDM1GAIN1 */
+ DRXJ_16TO8(0x0303), /* FIRDDM1GAIN2 */
+ DRXJ_16TO8(0x0303), /* FIRDDM1GAIN3 */
+ DRXJ_16TO8(0x0606), /* FIRDDM1GAIN4 */
+ DRXJ_16TO8(0x0606), /* FIRDDM1GAIN5 */
+ DRXJ_16TO8(0x0606), /* FIRDDM1GAIN6 */
+ DRXJ_16TO8(0x0606), /* FIRDDM1GAIN7 */
+ DRXJ_16TO8(0x0606), /* FIRDDM1GAIN8 */
+ DRXJ_16TO8(0x0606), /* FIRDDM1GAIN9 */
+ DRXJ_16TO8(0x0303), /* FIRDDM1GAIN10 */
+ DRXJ_16TO8(0x0303), /* FIRDDM1GAIN11 */
+ DRXJ_16TO8(0x0303), /* FIRDDM1GAIN12 */
+ DRXJ_16TO8(0x0303), /* FIRDDM2GAIN1 */
+ DRXJ_16TO8(0x0303), /* FIRDDM2GAIN2 */
+ DRXJ_16TO8(0x0303), /* FIRDDM2GAIN3 */
+ DRXJ_16TO8(0x0505), /* FIRDDM2GAIN4 */
+ DRXJ_16TO8(0x0505), /* FIRDDM2GAIN5 */
+ DRXJ_16TO8(0x0505), /* FIRDDM2GAIN6 */
+ DRXJ_16TO8(0x0505), /* FIRDDM2GAIN7 */
+ DRXJ_16TO8(0x0505), /* FIRDDM2GAIN8 */
+ DRXJ_16TO8(0x0505), /* FIRDDM2GAIN9 */
+ DRXJ_16TO8(0x0303), /* FIRDDM2GAIN10 */
+ DRXJ_16TO8(0x0303), /* FIRDDM2GAIN11 */
+ DRXJ_16TO8(0x0303), /* FIRDDM2GAIN12 */
+ DRXJ_16TO8(0x001f), /* DFETRAINLKRATIO */
+ DRXJ_16TO8(0x01ff), /* DFERCA1TRAINLKRATIO */
+ DRXJ_16TO8(0x01ff), /* DFERCA1DATALKRATIO */
+ DRXJ_16TO8(0x004f), /* DFERCA2TRAINLKRATIO */
+ DRXJ_16TO8(0x004f), /* DFERCA2DATALKRATIO */
+ DRXJ_16TO8(0x01ff), /* DFEDDM1TRAINLKRATIO */
+ DRXJ_16TO8(0x01ff), /* DFEDDM1DATALKRATIO */
+ DRXJ_16TO8(0x0352), /* DFEDDM2TRAINLKRATIO */
+ DRXJ_16TO8(0x0352), /* DFEDDM2DATALKRATIO */
+ DRXJ_16TO8(0x0000), /* DFETRAINGAIN */
+ DRXJ_16TO8(0x2020), /* DFERCA1GAIN */
+ DRXJ_16TO8(0x1010), /* DFERCA2GAIN */
+ DRXJ_16TO8(0x1818), /* DFEDDM1GAIN */
+ DRXJ_16TO8(0x1212) /* DFEDDM2GAIN */
+ };
+
+ dev_addr = demod->my_i2c_dev_addr;
+ rc = drxdap_fasi_write_block(dev_addr, VSB_SYSCTRL_RAM0_FFETRAINLKRATIO1__A, sizeof(vsb_ffe_leak_gain_ram0), ((u8 *)vsb_ffe_leak_gain_ram0), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxdap_fasi_write_block(dev_addr, VSB_SYSCTRL_RAM1_FIRRCA1GAIN9__A, sizeof(vsb_ffe_leak_gain_ram1), ((u8 *)vsb_ffe_leak_gain_ram1), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/**
+* \fn int set_vsb()
+* \brief Set 8VSB demod.
+* \param demod instance of demodulator.
+* \return int.
+*
+*/
+static int set_vsb(struct drx_demod_instance *demod)
+{
+ struct i2c_device_addr *dev_addr = NULL;
+ int rc;
+ struct drx_common_attr *common_attr = NULL;
+ struct drxjscu_cmd cmd_scu;
+ struct drxj_data *ext_attr = NULL;
+ u16 cmd_result = 0;
+ u16 cmd_param = 0;
+ const u8 vsb_taps_re[] = {
+ DRXJ_16TO8(-2), /* re0 */
+ DRXJ_16TO8(4), /* re1 */
+ DRXJ_16TO8(1), /* re2 */
+ DRXJ_16TO8(-4), /* re3 */
+ DRXJ_16TO8(1), /* re4 */
+ DRXJ_16TO8(4), /* re5 */
+ DRXJ_16TO8(-3), /* re6 */
+ DRXJ_16TO8(-3), /* re7 */
+ DRXJ_16TO8(6), /* re8 */
+ DRXJ_16TO8(1), /* re9 */
+ DRXJ_16TO8(-9), /* re10 */
+ DRXJ_16TO8(3), /* re11 */
+ DRXJ_16TO8(12), /* re12 */
+ DRXJ_16TO8(-9), /* re13 */
+ DRXJ_16TO8(-15), /* re14 */
+ DRXJ_16TO8(17), /* re15 */
+ DRXJ_16TO8(19), /* re16 */
+ DRXJ_16TO8(-29), /* re17 */
+ DRXJ_16TO8(-22), /* re18 */
+ DRXJ_16TO8(45), /* re19 */
+ DRXJ_16TO8(25), /* re20 */
+ DRXJ_16TO8(-70), /* re21 */
+ DRXJ_16TO8(-28), /* re22 */
+ DRXJ_16TO8(111), /* re23 */
+ DRXJ_16TO8(30), /* re24 */
+ DRXJ_16TO8(-201), /* re25 */
+ DRXJ_16TO8(-31), /* re26 */
+ DRXJ_16TO8(629) /* re27 */
+ };
+
+ dev_addr = demod->my_i2c_dev_addr;
+ common_attr = (struct drx_common_attr *) demod->my_common_attr;
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+
+ /* stop all comm_exec */
+ rc = drxj_dap_write_reg16(dev_addr, FEC_COMM_EXEC__A, FEC_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, VSB_COMM_EXEC__A, VSB_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_FS_COMM_EXEC__A, IQM_FS_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_FD_COMM_EXEC__A, IQM_FD_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_RC_COMM_EXEC__A, IQM_RC_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_RT_COMM_EXEC__A, IQM_RT_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_CF_COMM_EXEC__A, IQM_CF_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* reset demodulator */
+ cmd_scu.command = SCU_RAM_COMMAND_STANDARD_VSB
+ | SCU_RAM_COMMAND_CMD_DEMOD_RESET;
+ cmd_scu.parameter_len = 0;
+ cmd_scu.result_len = 1;
+ cmd_scu.parameter = NULL;
+ cmd_scu.result = &cmd_result;
+ rc = scu_command(dev_addr, &cmd_scu);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_DCF_BYPASS__A, 1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_FS_ADJ_SEL__A, IQM_FS_ADJ_SEL_B_VSB, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_RC_ADJ_SEL__A, IQM_RC_ADJ_SEL_B_VSB, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ ext_attr->iqm_rc_rate_ofs = 0x00AD0D79;
+ rc = drxdap_fasi_write_reg32(dev_addr, IQM_RC_RATE_OFS_LO__A, ext_attr->iqm_rc_rate_ofs, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, VSB_TOP_CFAGC_GAINSHIFT__A, 4, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, VSB_TOP_CYGN1TRK__A, 1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, IQM_RC_CROUT_ENA__A, 1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_RC_STRETCH__A, 28, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_RT_ACTIVE__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_CF_SYMMETRIC__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_CF_MIDTAP__A, 3, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_CF_OUT_ENA__A, IQM_CF_OUT_ENA_VSB__M, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_CF_SCALE__A, 1393, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_CF_SCALE_SH__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_CF_POW_MEAS_LEN__A, 1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_RE0__A, sizeof(vsb_taps_re), ((u8 *)vsb_taps_re), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_IM0__A, sizeof(vsb_taps_re), ((u8 *)vsb_taps_re), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, VSB_TOP_BNTHRESH__A, 330, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* set higher threshold */
+ rc = drxj_dap_write_reg16(dev_addr, VSB_TOP_CLPLASTNUM__A, 90, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* burst detection on */
+ rc = drxj_dap_write_reg16(dev_addr, VSB_TOP_SNRTH_RCA1__A, 0x0042, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* drop thresholds by 1 dB */
+ rc = drxj_dap_write_reg16(dev_addr, VSB_TOP_SNRTH_RCA2__A, 0x0053, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* drop thresholds by 2 dB */
+ rc = drxj_dap_write_reg16(dev_addr, VSB_TOP_EQCTRL__A, 0x1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* cma on */
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_GPIO__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* GPIO */
+
+ /* Initialize the FEC Subsystem */
+ rc = drxj_dap_write_reg16(dev_addr, FEC_TOP_ANNEX__A, FEC_TOP_ANNEX_D, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ {
+ u16 fec_oc_snc_mode = 0;
+ rc = drxj_dap_read_reg16(dev_addr, FEC_OC_SNC_MODE__A, &fec_oc_snc_mode, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* output data even when not locked */
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_SNC_MODE__A, fec_oc_snc_mode | FEC_OC_SNC_MODE_UNLOCK_ENABLE__M, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ /* set clip */
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_CLP_LEN__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_CLP_TH__A, 470, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_SNS_LEN__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, VSB_TOP_SNRTH_PT__A, 0xD4, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* no transparent, no A&C framing; parity is set in mpegoutput */
+ {
+ u16 fec_oc_reg_mode = 0;
+ rc = drxj_dap_read_reg16(dev_addr, FEC_OC_MODE__A, &fec_oc_reg_mode, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_MODE__A, fec_oc_reg_mode & (~(FEC_OC_MODE_TRANSPARENT__M | FEC_OC_MODE_CLEAR__M | FEC_OC_MODE_RETAIN_FRAMING__M)), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, FEC_DI_TIMEOUT_LO__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* timeout counter for restarting */
+ rc = drxj_dap_write_reg16(dev_addr, FEC_DI_TIMEOUT_HI__A, 3, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_RS_MODE__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* bypass disabled */
+ /* initialize RS packet error measurement parameters */
+ rc = drxj_dap_write_reg16(dev_addr, FEC_RS_MEASUREMENT_PERIOD__A, FEC_RS_MEASUREMENT_PERIOD, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_RS_MEASUREMENT_PRESCALE__A, FEC_RS_MEASUREMENT_PRESCALE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* init measurement period of MER/SER */
+ rc = drxj_dap_write_reg16(dev_addr, VSB_TOP_MEASUREMENT_PERIOD__A, VSB_TOP_MEASUREMENT_PERIOD, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxdap_fasi_write_reg32(dev_addr, SCU_RAM_FEC_ACCUM_CW_CORRECTED_LO__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_FEC_MEAS_COUNT__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, VSB_TOP_CKGN1TRK__A, 128, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* B-Input to ADC, PGA+filter in standby */
+ if (!ext_attr->has_lna) {
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_AMUX__A, 0x02, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ /* turn on IQMAF. It has to be in front of setAgc**() */
+ rc = set_iqm_af(demod, true);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = adc_synchronization(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = init_agc(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = set_agc_if(demod, &(ext_attr->vsb_if_agc_cfg), false);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = set_agc_rf(demod, &(ext_attr->vsb_rf_agc_cfg), false);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ {
+ /* TODO fix this, store a struct drxj_cfg_afe_gain structure in struct drxj_data instead
+ of only the gain */
+ struct drxj_cfg_afe_gain vsb_pga_cfg = { DRX_STANDARD_8VSB, 0 };
+
+ vsb_pga_cfg.gain = ext_attr->vsb_pga_cfg;
+ rc = ctrl_set_cfg_afe_gain(demod, &vsb_pga_cfg);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+ rc = ctrl_set_cfg_pre_saw(demod, &(ext_attr->vsb_pre_saw_cfg));
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Mpeg output has to be in front of FEC active */
+ rc = set_mpegtei_handling(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = bit_reverse_mpeg_output(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = set_mpeg_start_width(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ {
+ /* TODO: move to set_standard after hardware reset value problem is solved */
+ /* Configure initial MPEG output */
+ struct drx_cfg_mpeg_output cfg_mpeg_output;
+
+ memcpy(&cfg_mpeg_output, &common_attr->mpeg_cfg, sizeof(cfg_mpeg_output));
+ cfg_mpeg_output.enable_mpeg_output = true;
+
+ rc = ctrl_set_cfg_mpeg_output(demod, &cfg_mpeg_output);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ /* TBD: what parameters should be set */
+ cmd_param = 0x00; /* Default mode AGC on, etc */
+ cmd_scu.command = SCU_RAM_COMMAND_STANDARD_VSB
+ | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM;
+ cmd_scu.parameter_len = 1;
+ cmd_scu.result_len = 1;
+ cmd_scu.parameter = &cmd_param;
+ cmd_scu.result = &cmd_result;
+ rc = scu_command(dev_addr, &cmd_scu);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, VSB_TOP_BEAGC_GAINSHIFT__A, 0x0004, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, VSB_TOP_SNRTH_PT__A, 0x00D2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, VSB_TOP_SYSSMTRNCTRL__A, VSB_TOP_SYSSMTRNCTRL__PRE | VSB_TOP_SYSSMTRNCTRL_NCOTIMEOUTCNTEN__M, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, VSB_TOP_BEDETCTRL__A, 0x142, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, VSB_TOP_LBAGCREFLVL__A, 640, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, VSB_TOP_CYGN1ACQ__A, 4, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, VSB_TOP_CYGN1TRK__A, 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, VSB_TOP_CYGN2TRK__A, 3, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* start demodulator */
+ cmd_scu.command = SCU_RAM_COMMAND_STANDARD_VSB
+ | SCU_RAM_COMMAND_CMD_DEMOD_START;
+ cmd_scu.parameter_len = 0;
+ cmd_scu.result_len = 1;
+ cmd_scu.parameter = NULL;
+ cmd_scu.result = &cmd_result;
+ rc = scu_command(dev_addr, &cmd_scu);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, IQM_COMM_EXEC__A, IQM_COMM_EXEC_ACTIVE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, VSB_COMM_EXEC__A, VSB_COMM_EXEC_ACTIVE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_COMM_EXEC__A, FEC_COMM_EXEC_ACTIVE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/**
+* \fn static short get_vsb_post_rs_pck_err(struct i2c_device_addr *dev_addr, u16 *PckErrs)
+* \brief Get the values of packet error in 8VSB mode
+* \return Error code
+*/
+static int get_vsb_post_rs_pck_err(struct i2c_device_addr *dev_addr,
+ u32 *pck_errs, u32 *pck_count)
+{
+ int rc;
+ u16 data = 0;
+ u16 period = 0;
+ u16 prescale = 0;
+ u16 packet_errors_mant = 0;
+ u16 packet_errors_exp = 0;
+
+ rc = drxj_dap_read_reg16(dev_addr, FEC_RS_NR_FAILURES__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ packet_errors_mant = data & FEC_RS_NR_FAILURES_FIXED_MANT__M;
+ packet_errors_exp = (data & FEC_RS_NR_FAILURES_EXP__M)
+ >> FEC_RS_NR_FAILURES_EXP__B;
+ period = FEC_RS_MEASUREMENT_PERIOD;
+ prescale = FEC_RS_MEASUREMENT_PRESCALE;
+ /* packet error rate = (error packet number) per second */
+ /* 77.3 us is time for per packet */
+ if (period * prescale == 0) {
+ pr_err("error: period and/or prescale is zero!\n");
+ return -EIO;
+ }
+ *pck_errs = packet_errors_mant * (1 << packet_errors_exp);
+ *pck_count = period * prescale * 77;
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/**
+* \fn static short GetVSBBer(struct i2c_device_addr *dev_addr, u32 *ber)
+* \brief Get the values of ber in VSB mode
+* \return Error code
+*/
+static int get_vs_bpost_viterbi_ber(struct i2c_device_addr *dev_addr,
+ u32 *ber, u32 *cnt)
+{
+ int rc;
+ u16 data = 0;
+ u16 period = 0;
+ u16 prescale = 0;
+ u16 bit_errors_mant = 0;
+ u16 bit_errors_exp = 0;
+
+ rc = drxj_dap_read_reg16(dev_addr, FEC_RS_NR_BIT_ERRORS__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ period = FEC_RS_MEASUREMENT_PERIOD;
+ prescale = FEC_RS_MEASUREMENT_PRESCALE;
+
+ bit_errors_mant = data & FEC_RS_NR_BIT_ERRORS_FIXED_MANT__M;
+ bit_errors_exp = (data & FEC_RS_NR_BIT_ERRORS_EXP__M)
+ >> FEC_RS_NR_BIT_ERRORS_EXP__B;
+
+ *cnt = period * prescale * 207 * ((bit_errors_exp > 2) ? 1 : 8);
+
+ if (((bit_errors_mant << bit_errors_exp) >> 3) > 68700)
+ *ber = (*cnt) * 26570;
+ else {
+ if (period * prescale == 0) {
+ pr_err("error: period and/or prescale is zero!\n");
+ return -EIO;
+ }
+ *ber = bit_errors_mant << ((bit_errors_exp > 2) ?
+ (bit_errors_exp - 3) : bit_errors_exp);
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/**
+* \fn static short get_vs_bpre_viterbi_ber(struct i2c_device_addr *dev_addr, u32 *ber)
+* \brief Get the values of ber in VSB mode
+* \return Error code
+*/
+static int get_vs_bpre_viterbi_ber(struct i2c_device_addr *dev_addr,
+ u32 *ber, u32 *cnt)
+{
+ u16 data = 0;
+ int rc;
+
+ rc = drxj_dap_read_reg16(dev_addr, VSB_TOP_NR_SYM_ERRS__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ return -EIO;
+ }
+ *ber = data;
+ *cnt = VSB_TOP_MEASUREMENT_PERIOD * SYMBOLS_PER_SEGMENT;
+
+ return 0;
+}
+
+/**
+* \fn static int get_vsbmer(struct i2c_device_addr *dev_addr, u16 *mer)
+* \brief Get the values of MER
+* \return Error code
+*/
+static int get_vsbmer(struct i2c_device_addr *dev_addr, u16 *mer)
+{
+ int rc;
+ u16 data_hi = 0;
+
+ rc = drxj_dap_read_reg16(dev_addr, VSB_TOP_ERR_ENERGY_H__A, &data_hi, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ *mer =
+ (u16) (log1_times100(21504) - log1_times100((data_hi << 6) / 52));
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+
+/*============================================================================*/
+/*== END 8VSB DATAPATH FUNCTIONS ==*/
+/*============================================================================*/
+
+/*============================================================================*/
+/*============================================================================*/
+/*== QAM DATAPATH FUNCTIONS ==*/
+/*============================================================================*/
+/*============================================================================*/
+
+/**
+* \fn int power_down_qam ()
+* \brief Powr down QAM related blocks.
+* \param demod instance of demodulator.
+* \param channel pointer to channel data.
+* \return int.
+*/
+static int power_down_qam(struct drx_demod_instance *demod, bool primary)
+{
+ struct drxjscu_cmd cmd_scu = { /* command */ 0,
+ /* parameter_len */ 0,
+ /* result_len */ 0,
+ /* *parameter */ NULL,
+ /* *result */ NULL
+ };
+ int rc;
+ struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
+ struct drx_cfg_mpeg_output cfg_mpeg_output;
+ struct drx_common_attr *common_attr = demod->my_common_attr;
+ u16 cmd_result = 0;
+
+ /*
+ STOP demodulator
+ resets IQM, QAM and FEC HW blocks
+ */
+ /* stop all comm_exec */
+ rc = drxj_dap_write_reg16(dev_addr, FEC_COMM_EXEC__A, FEC_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_COMM_EXEC__A, QAM_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ cmd_scu.command = SCU_RAM_COMMAND_STANDARD_QAM |
+ SCU_RAM_COMMAND_CMD_DEMOD_STOP;
+ cmd_scu.parameter_len = 0;
+ cmd_scu.result_len = 1;
+ cmd_scu.parameter = NULL;
+ cmd_scu.result = &cmd_result;
+ rc = scu_command(dev_addr, &cmd_scu);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ if (primary) {
+ rc = drxj_dap_write_reg16(dev_addr, IQM_COMM_EXEC__A, IQM_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = set_iqm_af(demod, false);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ } else {
+ rc = drxj_dap_write_reg16(dev_addr, IQM_FS_COMM_EXEC__A, IQM_FS_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_FD_COMM_EXEC__A, IQM_FD_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_RC_COMM_EXEC__A, IQM_RC_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_RT_COMM_EXEC__A, IQM_RT_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_CF_COMM_EXEC__A, IQM_CF_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ memcpy(&cfg_mpeg_output, &common_attr->mpeg_cfg, sizeof(cfg_mpeg_output));
+ cfg_mpeg_output.enable_mpeg_output = false;
+
+ rc = ctrl_set_cfg_mpeg_output(demod, &cfg_mpeg_output);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*============================================================================*/
+
+/**
+* \fn int set_qam_measurement ()
+* \brief Setup of the QAM Measuremnt intervals for signal quality
+* \param demod instance of demod.
+* \param constellation current constellation.
+* \return int.
+*
+* NOTE:
+* Take into account that for certain settings the errorcounters can overflow.
+* The implementation does not check this.
+*
+* TODO: overriding the ext_attr->fec_bits_desired by constellation dependent
+* constants to get a measurement period of approx. 1 sec. Remove fec_bits_desired
+* field ?
+*
+*/
+#ifndef DRXJ_VSB_ONLY
+static int
+set_qam_measurement(struct drx_demod_instance *demod,
+ enum drx_modulation constellation, u32 symbol_rate)
+{
+ struct i2c_device_addr *dev_addr = NULL; /* device address for I2C writes */
+ struct drxj_data *ext_attr = NULL; /* Global data container for DRXJ specif data */
+ int rc;
+ u32 fec_bits_desired = 0; /* BER accounting period */
+ u16 fec_rs_plen = 0; /* defines RS BER measurement period */
+ u16 fec_rs_prescale = 0; /* ReedSolomon Measurement Prescale */
+ u32 fec_rs_period = 0; /* Value for corresponding I2C register */
+ u32 fec_rs_bit_cnt = 0; /* Actual precise amount of bits */
+ u32 fec_oc_snc_fail_period = 0; /* Value for corresponding I2C register */
+ u32 qam_vd_period = 0; /* Value for corresponding I2C register */
+ u32 qam_vd_bit_cnt = 0; /* Actual precise amount of bits */
+ u16 fec_vd_plen = 0; /* no of trellis symbols: VD SER measur period */
+ u16 qam_vd_prescale = 0; /* Viterbi Measurement Prescale */
+
+ dev_addr = demod->my_i2c_dev_addr;
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+
+ fec_bits_desired = ext_attr->fec_bits_desired;
+ fec_rs_prescale = ext_attr->fec_rs_prescale;
+
+ switch (constellation) {
+ case DRX_CONSTELLATION_QAM16:
+ fec_bits_desired = 4 * symbol_rate;
+ break;
+ case DRX_CONSTELLATION_QAM32:
+ fec_bits_desired = 5 * symbol_rate;
+ break;
+ case DRX_CONSTELLATION_QAM64:
+ fec_bits_desired = 6 * symbol_rate;
+ break;
+ case DRX_CONSTELLATION_QAM128:
+ fec_bits_desired = 7 * symbol_rate;
+ break;
+ case DRX_CONSTELLATION_QAM256:
+ fec_bits_desired = 8 * symbol_rate;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Parameters for Reed-Solomon Decoder */
+ /* fecrs_period = (int)ceil(FEC_BITS_DESIRED/(fecrs_prescale*plen)) */
+ /* rs_bit_cnt = fecrs_period*fecrs_prescale*plen */
+ /* result is within 32 bit arithmetic -> */
+ /* no need for mult or frac functions */
+
+ /* TODO: use constant instead of calculation and remove the fec_rs_plen in ext_attr */
+ switch (ext_attr->standard) {
+ case DRX_STANDARD_ITU_A:
+ case DRX_STANDARD_ITU_C:
+ fec_rs_plen = 204 * 8;
+ break;
+ case DRX_STANDARD_ITU_B:
+ fec_rs_plen = 128 * 7;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ext_attr->fec_rs_plen = fec_rs_plen; /* for getSigQual */
+ fec_rs_bit_cnt = fec_rs_prescale * fec_rs_plen; /* temp storage */
+ if (fec_rs_bit_cnt == 0) {
+ pr_err("error: fec_rs_bit_cnt is zero!\n");
+ return -EIO;
+ }
+ fec_rs_period = fec_bits_desired / fec_rs_bit_cnt + 1; /* ceil */
+ if (ext_attr->standard != DRX_STANDARD_ITU_B)
+ fec_oc_snc_fail_period = fec_rs_period;
+
+ /* limit to max 16 bit value (I2C register width) if needed */
+ if (fec_rs_period > 0xFFFF)
+ fec_rs_period = 0xFFFF;
+
+ /* write corresponding registers */
+ switch (ext_attr->standard) {
+ case DRX_STANDARD_ITU_A:
+ case DRX_STANDARD_ITU_C:
+ break;
+ case DRX_STANDARD_ITU_B:
+ switch (constellation) {
+ case DRX_CONSTELLATION_QAM64:
+ fec_rs_period = 31581;
+ fec_oc_snc_fail_period = 17932;
+ break;
+ case DRX_CONSTELLATION_QAM256:
+ fec_rs_period = 45446;
+ fec_oc_snc_fail_period = 25805;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, FEC_OC_SNC_FAIL_PERIOD__A, (u16)fec_oc_snc_fail_period, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_RS_MEASUREMENT_PERIOD__A, (u16)fec_rs_period, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_RS_MEASUREMENT_PRESCALE__A, fec_rs_prescale, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ ext_attr->fec_rs_period = (u16) fec_rs_period;
+ ext_attr->fec_rs_prescale = fec_rs_prescale;
+ rc = drxdap_fasi_write_reg32(dev_addr, SCU_RAM_FEC_ACCUM_CW_CORRECTED_LO__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_FEC_MEAS_COUNT__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ if (ext_attr->standard == DRX_STANDARD_ITU_B) {
+ /* Parameters for Viterbi Decoder */
+ /* qamvd_period = (int)ceil(FEC_BITS_DESIRED/ */
+ /* (qamvd_prescale*plen*(qam_constellation+1))) */
+ /* vd_bit_cnt = qamvd_period*qamvd_prescale*plen */
+ /* result is within 32 bit arithmetic -> */
+ /* no need for mult or frac functions */
+
+ /* a(8 bit) * b(8 bit) = 16 bit result => mult32 not needed */
+ fec_vd_plen = ext_attr->fec_vd_plen;
+ qam_vd_prescale = ext_attr->qam_vd_prescale;
+ qam_vd_bit_cnt = qam_vd_prescale * fec_vd_plen; /* temp storage */
+
+ switch (constellation) {
+ case DRX_CONSTELLATION_QAM64:
+ /* a(16 bit) * b(4 bit) = 20 bit result => mult32 not needed */
+ qam_vd_period =
+ qam_vd_bit_cnt * (QAM_TOP_CONSTELLATION_QAM64 + 1)
+ * (QAM_TOP_CONSTELLATION_QAM64 + 1);
+ break;
+ case DRX_CONSTELLATION_QAM256:
+ /* a(16 bit) * b(5 bit) = 21 bit result => mult32 not needed */
+ qam_vd_period =
+ qam_vd_bit_cnt * (QAM_TOP_CONSTELLATION_QAM256 + 1)
+ * (QAM_TOP_CONSTELLATION_QAM256 + 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (qam_vd_period == 0) {
+ pr_err("error: qam_vd_period is zero!\n");
+ return -EIO;
+ }
+ qam_vd_period = fec_bits_desired / qam_vd_period;
+ /* limit to max 16 bit value (I2C register width) if needed */
+ if (qam_vd_period > 0xFFFF)
+ qam_vd_period = 0xFFFF;
+
+ /* a(16 bit) * b(16 bit) = 32 bit result => mult32 not needed */
+ qam_vd_bit_cnt *= qam_vd_period;
+
+ rc = drxj_dap_write_reg16(dev_addr, QAM_VD_MEASUREMENT_PERIOD__A, (u16)qam_vd_period, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_VD_MEASUREMENT_PRESCALE__A, qam_vd_prescale, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ ext_attr->qam_vd_period = (u16) qam_vd_period;
+ ext_attr->qam_vd_prescale = qam_vd_prescale;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*============================================================================*/
+
+/**
+* \fn int set_qam16 ()
+* \brief QAM16 specific setup
+* \param demod instance of demod.
+* \return int.
+*/
+static int set_qam16(struct drx_demod_instance *demod)
+{
+ struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
+ int rc;
+ const u8 qam_dq_qual_fun[] = {
+ DRXJ_16TO8(2), /* fun0 */
+ DRXJ_16TO8(2), /* fun1 */
+ DRXJ_16TO8(2), /* fun2 */
+ DRXJ_16TO8(2), /* fun3 */
+ DRXJ_16TO8(3), /* fun4 */
+ DRXJ_16TO8(3), /* fun5 */
+ };
+ const u8 qam_eq_cma_rad[] = {
+ DRXJ_16TO8(13517), /* RAD0 */
+ DRXJ_16TO8(13517), /* RAD1 */
+ DRXJ_16TO8(13517), /* RAD2 */
+ DRXJ_16TO8(13517), /* RAD3 */
+ DRXJ_16TO8(13517), /* RAD4 */
+ DRXJ_16TO8(13517), /* RAD5 */
+ };
+
+ rc = drxdap_fasi_write_block(dev_addr, QAM_DQ_QUAL_FUN0__A, sizeof(qam_dq_qual_fun), ((u8 *)qam_dq_qual_fun), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxdap_fasi_write_block(dev_addr, SCU_RAM_QAM_EQ_CMA_RAD0__A, sizeof(qam_eq_cma_rad), ((u8 *)qam_eq_cma_rad), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_RTH__A, 140, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_FTH__A, 50, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_PTH__A, 120, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_QTH__A, 230, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_CTH__A, 95, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_MTH__A, 105, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_RATE_LIM__A, 40, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_FREQ_LIM__A, 56, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_COUNT_LIM__A, 3, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, 16, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, 220, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, 25, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, 6, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16)(-24), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16)(-65), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16)(-127), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CA_FINE__A, 15, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CA_COARSE__A, 40, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CP_FINE__A, 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CP_MEDIUM__A, 20, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CP_COARSE__A, 255, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CI_FINE__A, 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CI_MEDIUM__A, 10, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CI_COARSE__A, 50, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EP_FINE__A, 12, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EP_COARSE__A, 24, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EI_FINE__A, 12, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EI_COARSE__A, 16, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF_FINE__A, 16, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF_MEDIUM__A, 32, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF_COARSE__A, 240, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF1_FINE__A, 5, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 15, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF1_COARSE__A, 32, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_SL_SIG_POWER__A, 40960, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*============================================================================*/
+
+/**
+* \fn int set_qam32 ()
+* \brief QAM32 specific setup
+* \param demod instance of demod.
+* \return int.
+*/
+static int set_qam32(struct drx_demod_instance *demod)
+{
+ struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
+ int rc;
+ const u8 qam_dq_qual_fun[] = {
+ DRXJ_16TO8(3), /* fun0 */
+ DRXJ_16TO8(3), /* fun1 */
+ DRXJ_16TO8(3), /* fun2 */
+ DRXJ_16TO8(3), /* fun3 */
+ DRXJ_16TO8(4), /* fun4 */
+ DRXJ_16TO8(4), /* fun5 */
+ };
+ const u8 qam_eq_cma_rad[] = {
+ DRXJ_16TO8(6707), /* RAD0 */
+ DRXJ_16TO8(6707), /* RAD1 */
+ DRXJ_16TO8(6707), /* RAD2 */
+ DRXJ_16TO8(6707), /* RAD3 */
+ DRXJ_16TO8(6707), /* RAD4 */
+ DRXJ_16TO8(6707), /* RAD5 */
+ };
+
+ rc = drxdap_fasi_write_block(dev_addr, QAM_DQ_QUAL_FUN0__A, sizeof(qam_dq_qual_fun), ((u8 *)qam_dq_qual_fun), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxdap_fasi_write_block(dev_addr, SCU_RAM_QAM_EQ_CMA_RAD0__A, sizeof(qam_eq_cma_rad), ((u8 *)qam_eq_cma_rad), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_RTH__A, 90, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_FTH__A, 50, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_PTH__A, 100, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_QTH__A, 170, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_CTH__A, 80, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_MTH__A, 100, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_RATE_LIM__A, 40, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_FREQ_LIM__A, 56, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_COUNT_LIM__A, 3, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, 12, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, 140, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16)(-8), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16)(-16), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16)(-26), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16)(-56), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16)(-86), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CA_FINE__A, 15, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CA_COARSE__A, 40, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CP_FINE__A, 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CP_MEDIUM__A, 20, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CP_COARSE__A, 255, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CI_FINE__A, 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CI_MEDIUM__A, 10, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CI_COARSE__A, 50, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EP_FINE__A, 12, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EP_COARSE__A, 24, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EI_FINE__A, 12, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EI_COARSE__A, 16, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF_FINE__A, 16, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF_MEDIUM__A, 32, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF_COARSE__A, 176, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF1_FINE__A, 5, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 15, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF1_COARSE__A, 8, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_SL_SIG_POWER__A, 20480, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*============================================================================*/
+
+/**
+* \fn int set_qam64 ()
+* \brief QAM64 specific setup
+* \param demod instance of demod.
+* \return int.
+*/
+static int set_qam64(struct drx_demod_instance *demod)
+{
+ struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
+ int rc;
+ const u8 qam_dq_qual_fun[] = { /* this is hw reset value. no necessary to re-write */
+ DRXJ_16TO8(4), /* fun0 */
+ DRXJ_16TO8(4), /* fun1 */
+ DRXJ_16TO8(4), /* fun2 */
+ DRXJ_16TO8(4), /* fun3 */
+ DRXJ_16TO8(6), /* fun4 */
+ DRXJ_16TO8(6), /* fun5 */
+ };
+ const u8 qam_eq_cma_rad[] = {
+ DRXJ_16TO8(13336), /* RAD0 */
+ DRXJ_16TO8(12618), /* RAD1 */
+ DRXJ_16TO8(11988), /* RAD2 */
+ DRXJ_16TO8(13809), /* RAD3 */
+ DRXJ_16TO8(13809), /* RAD4 */
+ DRXJ_16TO8(15609), /* RAD5 */
+ };
+
+ rc = drxdap_fasi_write_block(dev_addr, QAM_DQ_QUAL_FUN0__A, sizeof(qam_dq_qual_fun), ((u8 *)qam_dq_qual_fun), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxdap_fasi_write_block(dev_addr, SCU_RAM_QAM_EQ_CMA_RAD0__A, sizeof(qam_eq_cma_rad), ((u8 *)qam_eq_cma_rad), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_RTH__A, 105, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_FTH__A, 60, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_PTH__A, 100, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_QTH__A, 195, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_CTH__A, 80, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_MTH__A, 84, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_RATE_LIM__A, 40, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_FREQ_LIM__A, 32, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_COUNT_LIM__A, 3, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, 12, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, 141, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, 7, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16)(-15), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16)(-45), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16)(-80), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CA_FINE__A, 15, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CA_COARSE__A, 40, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CP_FINE__A, 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CP_MEDIUM__A, 30, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CP_COARSE__A, 255, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CI_FINE__A, 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CI_MEDIUM__A, 15, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CI_COARSE__A, 80, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EP_FINE__A, 12, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EP_COARSE__A, 24, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EI_FINE__A, 12, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EI_COARSE__A, 16, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF_FINE__A, 16, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF_MEDIUM__A, 48, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF_COARSE__A, 160, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF1_FINE__A, 5, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 15, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF1_COARSE__A, 32, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_SL_SIG_POWER__A, 43008, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*============================================================================*/
+
+/**
+* \fn int set_qam128 ()
+* \brief QAM128 specific setup
+* \param demod: instance of demod.
+* \return int.
+*/
+static int set_qam128(struct drx_demod_instance *demod)
+{
+ struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
+ int rc;
+ const u8 qam_dq_qual_fun[] = {
+ DRXJ_16TO8(6), /* fun0 */
+ DRXJ_16TO8(6), /* fun1 */
+ DRXJ_16TO8(6), /* fun2 */
+ DRXJ_16TO8(6), /* fun3 */
+ DRXJ_16TO8(9), /* fun4 */
+ DRXJ_16TO8(9), /* fun5 */
+ };
+ const u8 qam_eq_cma_rad[] = {
+ DRXJ_16TO8(6164), /* RAD0 */
+ DRXJ_16TO8(6598), /* RAD1 */
+ DRXJ_16TO8(6394), /* RAD2 */
+ DRXJ_16TO8(6409), /* RAD3 */
+ DRXJ_16TO8(6656), /* RAD4 */
+ DRXJ_16TO8(7238), /* RAD5 */
+ };
+
+ rc = drxdap_fasi_write_block(dev_addr, QAM_DQ_QUAL_FUN0__A, sizeof(qam_dq_qual_fun), ((u8 *)qam_dq_qual_fun), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxdap_fasi_write_block(dev_addr, SCU_RAM_QAM_EQ_CMA_RAD0__A, sizeof(qam_eq_cma_rad), ((u8 *)qam_eq_cma_rad), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_RTH__A, 50, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_FTH__A, 60, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_PTH__A, 100, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_QTH__A, 140, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_CTH__A, 80, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_MTH__A, 100, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_RATE_LIM__A, 40, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_FREQ_LIM__A, 32, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_COUNT_LIM__A, 3, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, 8, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, 65, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, 5, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, 3, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16)(-1), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, 12, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16)(-23), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CA_FINE__A, 15, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CA_COARSE__A, 40, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CP_FINE__A, 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CP_MEDIUM__A, 40, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CP_COARSE__A, 255, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CI_FINE__A, 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CI_MEDIUM__A, 20, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CI_COARSE__A, 80, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EP_FINE__A, 12, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EP_COARSE__A, 24, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EI_FINE__A, 12, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EI_COARSE__A, 16, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF_FINE__A, 16, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF_MEDIUM__A, 32, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF_COARSE__A, 144, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF1_FINE__A, 5, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 15, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF1_COARSE__A, 16, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_SL_SIG_POWER__A, 20992, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*============================================================================*/
+
+/**
+* \fn int set_qam256 ()
+* \brief QAM256 specific setup
+* \param demod: instance of demod.
+* \return int.
+*/
+static int set_qam256(struct drx_demod_instance *demod)
+{
+ struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
+ int rc;
+ const u8 qam_dq_qual_fun[] = {
+ DRXJ_16TO8(8), /* fun0 */
+ DRXJ_16TO8(8), /* fun1 */
+ DRXJ_16TO8(8), /* fun2 */
+ DRXJ_16TO8(8), /* fun3 */
+ DRXJ_16TO8(12), /* fun4 */
+ DRXJ_16TO8(12), /* fun5 */
+ };
+ const u8 qam_eq_cma_rad[] = {
+ DRXJ_16TO8(12345), /* RAD0 */
+ DRXJ_16TO8(12345), /* RAD1 */
+ DRXJ_16TO8(13626), /* RAD2 */
+ DRXJ_16TO8(12931), /* RAD3 */
+ DRXJ_16TO8(14719), /* RAD4 */
+ DRXJ_16TO8(15356), /* RAD5 */
+ };
+
+ rc = drxdap_fasi_write_block(dev_addr, QAM_DQ_QUAL_FUN0__A, sizeof(qam_dq_qual_fun), ((u8 *)qam_dq_qual_fun), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxdap_fasi_write_block(dev_addr, SCU_RAM_QAM_EQ_CMA_RAD0__A, sizeof(qam_eq_cma_rad), ((u8 *)qam_eq_cma_rad), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_RTH__A, 50, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_FTH__A, 60, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_PTH__A, 100, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_QTH__A, 150, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_CTH__A, 80, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_MTH__A, 110, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_RATE_LIM__A, 40, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_FREQ_LIM__A, 16, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_COUNT_LIM__A, 3, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, 8, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, 74, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, 18, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, 13, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, 7, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16)(-8), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CA_FINE__A, 15, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CA_COARSE__A, 40, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CP_FINE__A, 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CP_MEDIUM__A, 50, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CP_COARSE__A, 255, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CI_FINE__A, 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CI_MEDIUM__A, 25, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CI_COARSE__A, 80, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EP_FINE__A, 12, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EP_COARSE__A, 24, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EI_FINE__A, 12, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_EI_COARSE__A, 16, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF_FINE__A, 16, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF_MEDIUM__A, 48, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF_COARSE__A, 80, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF1_FINE__A, 5, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 15, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_LC_CF1_COARSE__A, 16, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_SL_SIG_POWER__A, 43520, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*============================================================================*/
+#define QAM_SET_OP_ALL 0x1
+#define QAM_SET_OP_CONSTELLATION 0x2
+#define QAM_SET_OP_SPECTRUM 0X4
+
+/**
+* \fn int set_qam ()
+* \brief Set QAM demod.
+* \param demod: instance of demod.
+* \param channel: pointer to channel data.
+* \return int.
+*/
+static int
+set_qam(struct drx_demod_instance *demod,
+ struct drx_channel *channel, s32 tuner_freq_offset, u32 op)
+{
+ struct i2c_device_addr *dev_addr = NULL;
+ struct drxj_data *ext_attr = NULL;
+ struct drx_common_attr *common_attr = NULL;
+ int rc;
+ u32 adc_frequency = 0;
+ u32 iqm_rc_rate = 0;
+ u16 cmd_result = 0;
+ u16 lc_symbol_freq = 0;
+ u16 iqm_rc_stretch = 0;
+ u16 set_env_parameters = 0;
+ u16 set_param_parameters[2] = { 0 };
+ struct drxjscu_cmd cmd_scu = { /* command */ 0,
+ /* parameter_len */ 0,
+ /* result_len */ 0,
+ /* parameter */ NULL,
+ /* result */ NULL
+ };
+ const u8 qam_a_taps[] = {
+ DRXJ_16TO8(-1), /* re0 */
+ DRXJ_16TO8(1), /* re1 */
+ DRXJ_16TO8(1), /* re2 */
+ DRXJ_16TO8(-1), /* re3 */
+ DRXJ_16TO8(-1), /* re4 */
+ DRXJ_16TO8(2), /* re5 */
+ DRXJ_16TO8(1), /* re6 */
+ DRXJ_16TO8(-2), /* re7 */
+ DRXJ_16TO8(0), /* re8 */
+ DRXJ_16TO8(3), /* re9 */
+ DRXJ_16TO8(-1), /* re10 */
+ DRXJ_16TO8(-3), /* re11 */
+ DRXJ_16TO8(4), /* re12 */
+ DRXJ_16TO8(1), /* re13 */
+ DRXJ_16TO8(-8), /* re14 */
+ DRXJ_16TO8(4), /* re15 */
+ DRXJ_16TO8(13), /* re16 */
+ DRXJ_16TO8(-13), /* re17 */
+ DRXJ_16TO8(-19), /* re18 */
+ DRXJ_16TO8(28), /* re19 */
+ DRXJ_16TO8(25), /* re20 */
+ DRXJ_16TO8(-53), /* re21 */
+ DRXJ_16TO8(-31), /* re22 */
+ DRXJ_16TO8(96), /* re23 */
+ DRXJ_16TO8(37), /* re24 */
+ DRXJ_16TO8(-190), /* re25 */
+ DRXJ_16TO8(-40), /* re26 */
+ DRXJ_16TO8(619) /* re27 */
+ };
+ const u8 qam_b64_taps[] = {
+ DRXJ_16TO8(0), /* re0 */
+ DRXJ_16TO8(-2), /* re1 */
+ DRXJ_16TO8(1), /* re2 */
+ DRXJ_16TO8(2), /* re3 */
+ DRXJ_16TO8(-2), /* re4 */
+ DRXJ_16TO8(0), /* re5 */
+ DRXJ_16TO8(4), /* re6 */
+ DRXJ_16TO8(-2), /* re7 */
+ DRXJ_16TO8(-4), /* re8 */
+ DRXJ_16TO8(4), /* re9 */
+ DRXJ_16TO8(3), /* re10 */
+ DRXJ_16TO8(-6), /* re11 */
+ DRXJ_16TO8(0), /* re12 */
+ DRXJ_16TO8(6), /* re13 */
+ DRXJ_16TO8(-5), /* re14 */
+ DRXJ_16TO8(-3), /* re15 */
+ DRXJ_16TO8(11), /* re16 */
+ DRXJ_16TO8(-4), /* re17 */
+ DRXJ_16TO8(-19), /* re18 */
+ DRXJ_16TO8(19), /* re19 */
+ DRXJ_16TO8(28), /* re20 */
+ DRXJ_16TO8(-45), /* re21 */
+ DRXJ_16TO8(-36), /* re22 */
+ DRXJ_16TO8(90), /* re23 */
+ DRXJ_16TO8(42), /* re24 */
+ DRXJ_16TO8(-185), /* re25 */
+ DRXJ_16TO8(-46), /* re26 */
+ DRXJ_16TO8(614) /* re27 */
+ };
+ const u8 qam_b256_taps[] = {
+ DRXJ_16TO8(-2), /* re0 */
+ DRXJ_16TO8(4), /* re1 */
+ DRXJ_16TO8(1), /* re2 */
+ DRXJ_16TO8(-4), /* re3 */
+ DRXJ_16TO8(0), /* re4 */
+ DRXJ_16TO8(4), /* re5 */
+ DRXJ_16TO8(-2), /* re6 */
+ DRXJ_16TO8(-4), /* re7 */
+ DRXJ_16TO8(5), /* re8 */
+ DRXJ_16TO8(2), /* re9 */
+ DRXJ_16TO8(-8), /* re10 */
+ DRXJ_16TO8(2), /* re11 */
+ DRXJ_16TO8(11), /* re12 */
+ DRXJ_16TO8(-8), /* re13 */
+ DRXJ_16TO8(-15), /* re14 */
+ DRXJ_16TO8(16), /* re15 */
+ DRXJ_16TO8(19), /* re16 */
+ DRXJ_16TO8(-27), /* re17 */
+ DRXJ_16TO8(-22), /* re18 */
+ DRXJ_16TO8(44), /* re19 */
+ DRXJ_16TO8(26), /* re20 */
+ DRXJ_16TO8(-69), /* re21 */
+ DRXJ_16TO8(-28), /* re22 */
+ DRXJ_16TO8(110), /* re23 */
+ DRXJ_16TO8(31), /* re24 */
+ DRXJ_16TO8(-201), /* re25 */
+ DRXJ_16TO8(-32), /* re26 */
+ DRXJ_16TO8(628) /* re27 */
+ };
+ const u8 qam_c_taps[] = {
+ DRXJ_16TO8(-3), /* re0 */
+ DRXJ_16TO8(3), /* re1 */
+ DRXJ_16TO8(2), /* re2 */
+ DRXJ_16TO8(-4), /* re3 */
+ DRXJ_16TO8(0), /* re4 */
+ DRXJ_16TO8(4), /* re5 */
+ DRXJ_16TO8(-1), /* re6 */
+ DRXJ_16TO8(-4), /* re7 */
+ DRXJ_16TO8(3), /* re8 */
+ DRXJ_16TO8(3), /* re9 */
+ DRXJ_16TO8(-5), /* re10 */
+ DRXJ_16TO8(0), /* re11 */
+ DRXJ_16TO8(9), /* re12 */
+ DRXJ_16TO8(-4), /* re13 */
+ DRXJ_16TO8(-12), /* re14 */
+ DRXJ_16TO8(10), /* re15 */
+ DRXJ_16TO8(16), /* re16 */
+ DRXJ_16TO8(-21), /* re17 */
+ DRXJ_16TO8(-20), /* re18 */
+ DRXJ_16TO8(37), /* re19 */
+ DRXJ_16TO8(25), /* re20 */
+ DRXJ_16TO8(-62), /* re21 */
+ DRXJ_16TO8(-28), /* re22 */
+ DRXJ_16TO8(105), /* re23 */
+ DRXJ_16TO8(31), /* re24 */
+ DRXJ_16TO8(-197), /* re25 */
+ DRXJ_16TO8(-33), /* re26 */
+ DRXJ_16TO8(626) /* re27 */
+ };
+
+ dev_addr = demod->my_i2c_dev_addr;
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+ common_attr = (struct drx_common_attr *) demod->my_common_attr;
+
+ if ((op & QAM_SET_OP_ALL) || (op & QAM_SET_OP_CONSTELLATION)) {
+ if (ext_attr->standard == DRX_STANDARD_ITU_B) {
+ switch (channel->constellation) {
+ case DRX_CONSTELLATION_QAM256:
+ iqm_rc_rate = 0x00AE3562;
+ lc_symbol_freq =
+ QAM_LC_SYMBOL_FREQ_FREQ_QAM_B_256;
+ channel->symbolrate = 5360537;
+ iqm_rc_stretch = IQM_RC_STRETCH_QAM_B_256;
+ break;
+ case DRX_CONSTELLATION_QAM64:
+ iqm_rc_rate = 0x00C05A0E;
+ lc_symbol_freq = 409;
+ channel->symbolrate = 5056941;
+ iqm_rc_stretch = IQM_RC_STRETCH_QAM_B_64;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ adc_frequency = (common_attr->sys_clock_freq * 1000) / 3;
+ if (channel->symbolrate == 0) {
+ pr_err("error: channel symbolrate is zero!\n");
+ return -EIO;
+ }
+ iqm_rc_rate =
+ (adc_frequency / channel->symbolrate) * (1 << 21) +
+ (frac28
+ ((adc_frequency % channel->symbolrate),
+ channel->symbolrate) >> 7) - (1 << 23);
+ lc_symbol_freq =
+ (u16) (frac28
+ (channel->symbolrate +
+ (adc_frequency >> 13),
+ adc_frequency) >> 16);
+ if (lc_symbol_freq > 511)
+ lc_symbol_freq = 511;
+
+ iqm_rc_stretch = 21;
+ }
+
+ if (ext_attr->standard == DRX_STANDARD_ITU_A) {
+ set_env_parameters = QAM_TOP_ANNEX_A; /* annex */
+ set_param_parameters[0] = channel->constellation; /* constellation */
+ set_param_parameters[1] = DRX_INTERLEAVEMODE_I12_J17; /* interleave mode */
+ } else if (ext_attr->standard == DRX_STANDARD_ITU_B) {
+ set_env_parameters = QAM_TOP_ANNEX_B; /* annex */
+ set_param_parameters[0] = channel->constellation; /* constellation */
+ set_param_parameters[1] = channel->interleavemode; /* interleave mode */
+ } else if (ext_attr->standard == DRX_STANDARD_ITU_C) {
+ set_env_parameters = QAM_TOP_ANNEX_C; /* annex */
+ set_param_parameters[0] = channel->constellation; /* constellation */
+ set_param_parameters[1] = DRX_INTERLEAVEMODE_I12_J17; /* interleave mode */
+ } else {
+ return -EINVAL;
+ }
+ }
+
+ if (op & QAM_SET_OP_ALL) {
+ /*
+ STEP 1: reset demodulator
+ resets IQM, QAM and FEC HW blocks
+ resets SCU variables
+ */
+ /* stop all comm_exec */
+ rc = drxj_dap_write_reg16(dev_addr, FEC_COMM_EXEC__A, FEC_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_COMM_EXEC__A, QAM_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_FS_COMM_EXEC__A, IQM_FS_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_FD_COMM_EXEC__A, IQM_FD_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_RC_COMM_EXEC__A, IQM_RC_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_RT_COMM_EXEC__A, IQM_RT_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_CF_COMM_EXEC__A, IQM_CF_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ cmd_scu.command = SCU_RAM_COMMAND_STANDARD_QAM |
+ SCU_RAM_COMMAND_CMD_DEMOD_RESET;
+ cmd_scu.parameter_len = 0;
+ cmd_scu.result_len = 1;
+ cmd_scu.parameter = NULL;
+ cmd_scu.result = &cmd_result;
+ rc = scu_command(dev_addr, &cmd_scu);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ if ((op & QAM_SET_OP_ALL) || (op & QAM_SET_OP_CONSTELLATION)) {
+ /*
+ STEP 2: configure demodulator
+ -set env
+ -set params (resets IQM,QAM,FEC HW; initializes some SCU variables )
+ */
+ cmd_scu.command = SCU_RAM_COMMAND_STANDARD_QAM |
+ SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV;
+ cmd_scu.parameter_len = 1;
+ cmd_scu.result_len = 1;
+ cmd_scu.parameter = &set_env_parameters;
+ cmd_scu.result = &cmd_result;
+ rc = scu_command(dev_addr, &cmd_scu);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ cmd_scu.command = SCU_RAM_COMMAND_STANDARD_QAM |
+ SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM;
+ cmd_scu.parameter_len = 2;
+ cmd_scu.result_len = 1;
+ cmd_scu.parameter = set_param_parameters;
+ cmd_scu.result = &cmd_result;
+ rc = scu_command(dev_addr, &cmd_scu);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* set symbol rate */
+ rc = drxdap_fasi_write_reg32(dev_addr, IQM_RC_RATE_OFS_LO__A, iqm_rc_rate, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ ext_attr->iqm_rc_rate_ofs = iqm_rc_rate;
+ rc = set_qam_measurement(demod, channel->constellation, channel->symbolrate);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+ /* STEP 3: enable the system in a mode where the ADC provides valid signal
+ setup constellation independent registers */
+ /* from qam_cmd.py script (qam_driver_b) */
+ /* TODO: remove re-writes of HW reset values */
+ if ((op & QAM_SET_OP_ALL) || (op & QAM_SET_OP_SPECTRUM)) {
+ rc = set_frequency(demod, channel, tuner_freq_offset);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ if ((op & QAM_SET_OP_ALL) || (op & QAM_SET_OP_CONSTELLATION)) {
+
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_SYMBOL_FREQ__A, lc_symbol_freq, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_RC_STRETCH__A, iqm_rc_stretch, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ if (op & QAM_SET_OP_ALL) {
+ if (!ext_attr->has_lna) {
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_AMUX__A, 0x02, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_CF_SYMMETRIC__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_CF_MIDTAP__A, 3, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_CF_OUT_ENA__A, IQM_CF_OUT_ENA_QAM__M, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_WR_RSV_0__A, 0x5f, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* scu temporary shut down agc */
+
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_SYNC_SEL__A, 3, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_CLP_LEN__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_CLP_TH__A, 448, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_SNS_LEN__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_PDREF__A, 4, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_STDBY__A, 0x10, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_PGA_GAIN__A, 11, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, IQM_CF_POW_MEAS_LEN__A, 1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_CF_SCALE_SH__A, IQM_CF_SCALE_SH__PRE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /*! reset default val ! */
+
+ rc = drxj_dap_write_reg16(dev_addr, QAM_SY_TIMEOUT__A, QAM_SY_TIMEOUT__PRE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /*! reset default val ! */
+ if (ext_attr->standard == DRX_STANDARD_ITU_B) {
+ rc = drxj_dap_write_reg16(dev_addr, QAM_SY_SYNC_LWM__A, QAM_SY_SYNC_LWM__PRE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /*! reset default val ! */
+ rc = drxj_dap_write_reg16(dev_addr, QAM_SY_SYNC_AWM__A, QAM_SY_SYNC_AWM__PRE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /*! reset default val ! */
+ rc = drxj_dap_write_reg16(dev_addr, QAM_SY_SYNC_HWM__A, QAM_SY_SYNC_HWM__PRE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /*! reset default val ! */
+ } else {
+ switch (channel->constellation) {
+ case DRX_CONSTELLATION_QAM16:
+ case DRX_CONSTELLATION_QAM64:
+ case DRX_CONSTELLATION_QAM256:
+ rc = drxj_dap_write_reg16(dev_addr, QAM_SY_SYNC_LWM__A, 0x03, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_SY_SYNC_AWM__A, 0x04, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_SY_SYNC_HWM__A, QAM_SY_SYNC_HWM__PRE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /*! reset default val ! */
+ break;
+ case DRX_CONSTELLATION_QAM32:
+ case DRX_CONSTELLATION_QAM128:
+ rc = drxj_dap_write_reg16(dev_addr, QAM_SY_SYNC_LWM__A, 0x03, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_SY_SYNC_AWM__A, 0x05, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_SY_SYNC_HWM__A, 0x06, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ default:
+ return -EIO;
+ } /* switch */
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_MODE__A, QAM_LC_MODE__PRE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /*! reset default val ! */
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_RATE_LIMIT__A, 3, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_LPF_FACTORP__A, 4, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_LPF_FACTORI__A, 4, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_MODE__A, 7, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_QUAL_TAB0__A, 1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_QUAL_TAB1__A, 1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_QUAL_TAB2__A, 1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_QUAL_TAB3__A, 1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_QUAL_TAB4__A, 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_QUAL_TAB5__A, 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_QUAL_TAB6__A, 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_QUAL_TAB8__A, 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_QUAL_TAB9__A, 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_QUAL_TAB10__A, 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_QUAL_TAB12__A, 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_QUAL_TAB15__A, 3, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_QUAL_TAB16__A, 3, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_QUAL_TAB20__A, 4, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_QUAL_TAB25__A, 4, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, IQM_FS_ADJ_SEL__A, 1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_RC_ADJ_SEL__A, 1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_CF_ADJ_SEL__A, 1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_CF_POW_MEAS_LEN__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_GPIO__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* No more resets of the IQM, current standard correctly set =>
+ now AGCs can be configured. */
+ /* turn on IQMAF. It has to be in front of setAgc**() */
+ rc = set_iqm_af(demod, true);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = adc_synchronization(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = init_agc(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = set_agc_if(demod, &(ext_attr->qam_if_agc_cfg), false);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = set_agc_rf(demod, &(ext_attr->qam_rf_agc_cfg), false);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ {
+ /* TODO fix this, store a struct drxj_cfg_afe_gain structure in struct drxj_data instead
+ of only the gain */
+ struct drxj_cfg_afe_gain qam_pga_cfg = { DRX_STANDARD_ITU_B, 0 };
+
+ qam_pga_cfg.gain = ext_attr->qam_pga_cfg;
+ rc = ctrl_set_cfg_afe_gain(demod, &qam_pga_cfg);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+ rc = ctrl_set_cfg_pre_saw(demod, &(ext_attr->qam_pre_saw_cfg));
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ if ((op & QAM_SET_OP_ALL) || (op & QAM_SET_OP_CONSTELLATION)) {
+ if (ext_attr->standard == DRX_STANDARD_ITU_A) {
+ rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_RE0__A, sizeof(qam_a_taps), ((u8 *)qam_a_taps), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_IM0__A, sizeof(qam_a_taps), ((u8 *)qam_a_taps), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ } else if (ext_attr->standard == DRX_STANDARD_ITU_B) {
+ switch (channel->constellation) {
+ case DRX_CONSTELLATION_QAM64:
+ rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_RE0__A, sizeof(qam_b64_taps), ((u8 *)qam_b64_taps), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_IM0__A, sizeof(qam_b64_taps), ((u8 *)qam_b64_taps), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ case DRX_CONSTELLATION_QAM256:
+ rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_RE0__A, sizeof(qam_b256_taps), ((u8 *)qam_b256_taps), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_IM0__A, sizeof(qam_b256_taps), ((u8 *)qam_b256_taps), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ default:
+ return -EIO;
+ }
+ } else if (ext_attr->standard == DRX_STANDARD_ITU_C) {
+ rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_RE0__A, sizeof(qam_c_taps), ((u8 *)qam_c_taps), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxdap_fasi_write_block(dev_addr, IQM_CF_TAP_IM0__A, sizeof(qam_c_taps), ((u8 *)qam_c_taps), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ /* SETP 4: constellation specific setup */
+ switch (channel->constellation) {
+ case DRX_CONSTELLATION_QAM16:
+ rc = set_qam16(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ case DRX_CONSTELLATION_QAM32:
+ rc = set_qam32(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ case DRX_CONSTELLATION_QAM64:
+ rc = set_qam64(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ case DRX_CONSTELLATION_QAM128:
+ rc = set_qam128(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ case DRX_CONSTELLATION_QAM256:
+ rc = set_qam256(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ default:
+ return -EIO;
+ } /* switch */
+ }
+
+ if ((op & QAM_SET_OP_ALL)) {
+ rc = drxj_dap_write_reg16(dev_addr, IQM_CF_SCALE_SH__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Mpeg output has to be in front of FEC active */
+ rc = set_mpegtei_handling(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = bit_reverse_mpeg_output(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = set_mpeg_start_width(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ {
+ /* TODO: move to set_standard after hardware reset value problem is solved */
+ /* Configure initial MPEG output */
+ struct drx_cfg_mpeg_output cfg_mpeg_output;
+
+ memcpy(&cfg_mpeg_output, &common_attr->mpeg_cfg, sizeof(cfg_mpeg_output));
+ cfg_mpeg_output.enable_mpeg_output = true;
+
+ rc = ctrl_set_cfg_mpeg_output(demod, &cfg_mpeg_output);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+ }
+
+ if ((op & QAM_SET_OP_ALL) || (op & QAM_SET_OP_CONSTELLATION)) {
+
+ /* STEP 5: start QAM demodulator (starts FEC, QAM and IQM HW) */
+ cmd_scu.command = SCU_RAM_COMMAND_STANDARD_QAM |
+ SCU_RAM_COMMAND_CMD_DEMOD_START;
+ cmd_scu.parameter_len = 0;
+ cmd_scu.result_len = 1;
+ cmd_scu.parameter = NULL;
+ cmd_scu.result = &cmd_result;
+ rc = scu_command(dev_addr, &cmd_scu);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, IQM_COMM_EXEC__A, IQM_COMM_EXEC_ACTIVE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_COMM_EXEC__A, QAM_COMM_EXEC_ACTIVE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, FEC_COMM_EXEC__A, FEC_COMM_EXEC_ACTIVE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*============================================================================*/
+static int ctrl_get_qam_sig_quality(struct drx_demod_instance *demod);
+
+static int qam_flip_spec(struct drx_demod_instance *demod, struct drx_channel *channel)
+{
+ struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
+ struct drxj_data *ext_attr = demod->my_ext_attr;
+ int rc;
+ u32 iqm_fs_rate_ofs = 0;
+ u32 iqm_fs_rate_lo = 0;
+ u16 qam_ctl_ena = 0;
+ u16 data = 0;
+ u16 equ_mode = 0;
+ u16 fsm_state = 0;
+ int i = 0;
+ int ofsofs = 0;
+
+ /* Silence the controlling of lc, equ, and the acquisition state machine */
+ rc = drxj_dap_read_reg16(dev_addr, SCU_RAM_QAM_CTL_ENA__A, &qam_ctl_ena, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_CTL_ENA__A, qam_ctl_ena & ~(SCU_RAM_QAM_CTL_ENA_ACQ__M | SCU_RAM_QAM_CTL_ENA_EQU__M | SCU_RAM_QAM_CTL_ENA_LC__M), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* freeze the frequency control loop */
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_CF__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_CF1__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_atomic_read_reg32(dev_addr, IQM_FS_RATE_OFS_LO__A, &iqm_fs_rate_ofs, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_atomic_read_reg32(dev_addr, IQM_FS_RATE_LO__A, &iqm_fs_rate_lo, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ ofsofs = iqm_fs_rate_lo - iqm_fs_rate_ofs;
+ iqm_fs_rate_ofs = ~iqm_fs_rate_ofs + 1;
+ iqm_fs_rate_ofs -= 2 * ofsofs;
+
+ /* freeze dq/fq updating */
+ rc = drxj_dap_read_reg16(dev_addr, QAM_DQ_MODE__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ data = (data & 0xfff9);
+ rc = drxj_dap_write_reg16(dev_addr, QAM_DQ_MODE__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_FQ_MODE__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* lc_cp / _ci / _ca */
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_CI__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_LC_EP__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_FQ_LA_FACTOR__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* flip the spec */
+ rc = drxdap_fasi_write_reg32(dev_addr, IQM_FS_RATE_OFS_LO__A, iqm_fs_rate_ofs, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ ext_attr->iqm_fs_rate_ofs = iqm_fs_rate_ofs;
+ ext_attr->pos_image = (ext_attr->pos_image) ? false : true;
+
+ /* freeze dq/fq updating */
+ rc = drxj_dap_read_reg16(dev_addr, QAM_DQ_MODE__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ equ_mode = data;
+ data = (data & 0xfff9);
+ rc = drxj_dap_write_reg16(dev_addr, QAM_DQ_MODE__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_FQ_MODE__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ for (i = 0; i < 28; i++) {
+ rc = drxj_dap_read_reg16(dev_addr, QAM_DQ_TAP_IM_EL0__A + (2 * i), &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_DQ_TAP_IM_EL0__A + (2 * i), -data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ for (i = 0; i < 24; i++) {
+ rc = drxj_dap_read_reg16(dev_addr, QAM_FQ_TAP_IM_EL0__A + (2 * i), &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_FQ_TAP_IM_EL0__A + (2 * i), -data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ data = equ_mode;
+ rc = drxj_dap_write_reg16(dev_addr, QAM_DQ_MODE__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, QAM_FQ_MODE__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_FSM_STATE_TGT__A, 4, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ i = 0;
+ while ((fsm_state != 4) && (i++ < 100)) {
+ rc = drxj_dap_read_reg16(dev_addr, SCU_RAM_QAM_FSM_STATE__A, &fsm_state, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_QAM_CTL_ENA__A, (qam_ctl_ena | 0x0016), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+
+}
+
+#define NO_LOCK 0x0
+#define DEMOD_LOCKED 0x1
+#define SYNC_FLIPPED 0x2
+#define SPEC_MIRRORED 0x4
+/**
+* \fn int qam64auto ()
+* \brief auto do sync pattern switching and mirroring.
+* \param demod: instance of demod.
+* \param channel: pointer to channel data.
+* \param tuner_freq_offset: tuner frequency offset.
+* \param lock_status: pointer to lock status.
+* \return int.
+*/
+static int
+qam64auto(struct drx_demod_instance *demod,
+ struct drx_channel *channel,
+ s32 tuner_freq_offset, enum drx_lock_status *lock_status)
+{
+ struct drxj_data *ext_attr = demod->my_ext_attr;
+ struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
+ struct drx39xxj_state *state = dev_addr->user_data;
+ struct dtv_frontend_properties *p = &state->frontend.dtv_property_cache;
+ int rc;
+ u32 lck_state = NO_LOCK;
+ u32 start_time = 0;
+ u32 d_locked_time = 0;
+ u32 timeout_ofs = 0;
+ u16 data = 0;
+
+ /* external attributes for storing aquired channel constellation */
+ *lock_status = DRX_NOT_LOCKED;
+ start_time = jiffies_to_msecs(jiffies);
+ lck_state = NO_LOCK;
+ do {
+ rc = ctrl_lock_status(demod, lock_status);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ switch (lck_state) {
+ case NO_LOCK:
+ if (*lock_status == DRXJ_DEMOD_LOCK) {
+ rc = ctrl_get_qam_sig_quality(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (p->cnr.stat[0].svalue > 20800) {
+ lck_state = DEMOD_LOCKED;
+ /* some delay to see if fec_lock possible TODO find the right value */
+ timeout_ofs += DRXJ_QAM_DEMOD_LOCK_EXT_WAITTIME; /* see something, waiting longer */
+ d_locked_time = jiffies_to_msecs(jiffies);
+ }
+ }
+ break;
+ case DEMOD_LOCKED:
+ if ((*lock_status == DRXJ_DEMOD_LOCK) && /* still demod_lock in 150ms */
+ ((jiffies_to_msecs(jiffies) - d_locked_time) >
+ DRXJ_QAM_FEC_LOCK_WAITTIME)) {
+ rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, QAM_SY_TIMEOUT__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, QAM_SY_TIMEOUT__A, data | 0x1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ lck_state = SYNC_FLIPPED;
+ msleep(10);
+ }
+ break;
+ case SYNC_FLIPPED:
+ if (*lock_status == DRXJ_DEMOD_LOCK) {
+ if (channel->mirror == DRX_MIRROR_AUTO) {
+ /* flip sync pattern back */
+ rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, QAM_SY_TIMEOUT__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, QAM_SY_TIMEOUT__A, data & 0xFFFE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* flip spectrum */
+ ext_attr->mirror = DRX_MIRROR_YES;
+ rc = qam_flip_spec(demod, channel);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ lck_state = SPEC_MIRRORED;
+ /* reset timer TODO: still need 500ms? */
+ start_time = d_locked_time =
+ jiffies_to_msecs(jiffies);
+ timeout_ofs = 0;
+ } else { /* no need to wait lock */
+
+ start_time =
+ jiffies_to_msecs(jiffies) -
+ DRXJ_QAM_MAX_WAITTIME - timeout_ofs;
+ }
+ }
+ break;
+ case SPEC_MIRRORED:
+ if ((*lock_status == DRXJ_DEMOD_LOCK) && /* still demod_lock in 150ms */
+ ((jiffies_to_msecs(jiffies) - d_locked_time) >
+ DRXJ_QAM_FEC_LOCK_WAITTIME)) {
+ rc = ctrl_get_qam_sig_quality(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (p->cnr.stat[0].svalue > 20800) {
+ rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, QAM_SY_TIMEOUT__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr, QAM_SY_TIMEOUT__A, data | 0x1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* no need to wait lock */
+ start_time =
+ jiffies_to_msecs(jiffies) -
+ DRXJ_QAM_MAX_WAITTIME - timeout_ofs;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ msleep(10);
+ } while
+ ((*lock_status != DRX_LOCKED) &&
+ (*lock_status != DRX_NEVER_LOCK) &&
+ ((jiffies_to_msecs(jiffies) - start_time) <
+ (DRXJ_QAM_MAX_WAITTIME + timeout_ofs))
+ );
+ /* Returning control to apllication ... */
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/**
+* \fn int qam256auto ()
+* \brief auto do sync pattern switching and mirroring.
+* \param demod: instance of demod.
+* \param channel: pointer to channel data.
+* \param tuner_freq_offset: tuner frequency offset.
+* \param lock_status: pointer to lock status.
+* \return int.
+*/
+static int
+qam256auto(struct drx_demod_instance *demod,
+ struct drx_channel *channel,
+ s32 tuner_freq_offset, enum drx_lock_status *lock_status)
+{
+ struct drxj_data *ext_attr = demod->my_ext_attr;
+ struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
+ struct drx39xxj_state *state = dev_addr->user_data;
+ struct dtv_frontend_properties *p = &state->frontend.dtv_property_cache;
+ int rc;
+ u32 lck_state = NO_LOCK;
+ u32 start_time = 0;
+ u32 d_locked_time = 0;
+ u32 timeout_ofs = DRXJ_QAM_DEMOD_LOCK_EXT_WAITTIME;
+
+ /* external attributes for storing aquired channel constellation */
+ *lock_status = DRX_NOT_LOCKED;
+ start_time = jiffies_to_msecs(jiffies);
+ lck_state = NO_LOCK;
+ do {
+ rc = ctrl_lock_status(demod, lock_status);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ switch (lck_state) {
+ case NO_LOCK:
+ if (*lock_status == DRXJ_DEMOD_LOCK) {
+ rc = ctrl_get_qam_sig_quality(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (p->cnr.stat[0].svalue > 26800) {
+ lck_state = DEMOD_LOCKED;
+ timeout_ofs += DRXJ_QAM_DEMOD_LOCK_EXT_WAITTIME; /* see something, wait longer */
+ d_locked_time = jiffies_to_msecs(jiffies);
+ }
+ }
+ break;
+ case DEMOD_LOCKED:
+ if (*lock_status == DRXJ_DEMOD_LOCK) {
+ if ((channel->mirror == DRX_MIRROR_AUTO) &&
+ ((jiffies_to_msecs(jiffies) - d_locked_time) >
+ DRXJ_QAM_FEC_LOCK_WAITTIME)) {
+ ext_attr->mirror = DRX_MIRROR_YES;
+ rc = qam_flip_spec(demod, channel);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ lck_state = SPEC_MIRRORED;
+ /* reset timer TODO: still need 300ms? */
+ start_time = jiffies_to_msecs(jiffies);
+ timeout_ofs = -DRXJ_QAM_MAX_WAITTIME / 2;
+ }
+ }
+ break;
+ case SPEC_MIRRORED:
+ break;
+ default:
+ break;
+ }
+ msleep(10);
+ } while
+ ((*lock_status < DRX_LOCKED) &&
+ (*lock_status != DRX_NEVER_LOCK) &&
+ ((jiffies_to_msecs(jiffies) - start_time) <
+ (DRXJ_QAM_MAX_WAITTIME + timeout_ofs)));
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/**
+* \fn int set_qam_channel ()
+* \brief Set QAM channel according to the requested constellation.
+* \param demod: instance of demod.
+* \param channel: pointer to channel data.
+* \return int.
+*/
+static int
+set_qam_channel(struct drx_demod_instance *demod,
+ struct drx_channel *channel, s32 tuner_freq_offset)
+{
+ struct drxj_data *ext_attr = NULL;
+ int rc;
+ enum drx_lock_status lock_status = DRX_NOT_LOCKED;
+ bool auto_flag = false;
+
+ /* external attributes for storing aquired channel constellation */
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+
+ /* set QAM channel constellation */
+ switch (channel->constellation) {
+ case DRX_CONSTELLATION_QAM16:
+ case DRX_CONSTELLATION_QAM32:
+ case DRX_CONSTELLATION_QAM128:
+ return -EINVAL;
+ case DRX_CONSTELLATION_QAM64:
+ case DRX_CONSTELLATION_QAM256:
+ if (ext_attr->standard != DRX_STANDARD_ITU_B)
+ return -EINVAL;
+
+ ext_attr->constellation = channel->constellation;
+ if (channel->mirror == DRX_MIRROR_AUTO)
+ ext_attr->mirror = DRX_MIRROR_NO;
+ else
+ ext_attr->mirror = channel->mirror;
+
+ rc = set_qam(demod, channel, tuner_freq_offset, QAM_SET_OP_ALL);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ if (channel->constellation == DRX_CONSTELLATION_QAM64)
+ rc = qam64auto(demod, channel, tuner_freq_offset,
+ &lock_status);
+ else
+ rc = qam256auto(demod, channel, tuner_freq_offset,
+ &lock_status);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ case DRX_CONSTELLATION_AUTO: /* for channel scan */
+ if (ext_attr->standard == DRX_STANDARD_ITU_B) {
+ u16 qam_ctl_ena = 0;
+
+ auto_flag = true;
+
+ /* try to lock default QAM constellation: QAM256 */
+ channel->constellation = DRX_CONSTELLATION_QAM256;
+ ext_attr->constellation = DRX_CONSTELLATION_QAM256;
+ if (channel->mirror == DRX_MIRROR_AUTO)
+ ext_attr->mirror = DRX_MIRROR_NO;
+ else
+ ext_attr->mirror = channel->mirror;
+ rc = set_qam(demod, channel, tuner_freq_offset,
+ QAM_SET_OP_ALL);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = qam256auto(demod, channel, tuner_freq_offset,
+ &lock_status);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ if (lock_status >= DRX_LOCKED) {
+ channel->constellation = DRX_CONSTELLATION_AUTO;
+ break;
+ }
+
+ /* QAM254 not locked. Try QAM64 constellation */
+ channel->constellation = DRX_CONSTELLATION_QAM64;
+ ext_attr->constellation = DRX_CONSTELLATION_QAM64;
+ if (channel->mirror == DRX_MIRROR_AUTO)
+ ext_attr->mirror = DRX_MIRROR_NO;
+ else
+ ext_attr->mirror = channel->mirror;
+
+ rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr,
+ SCU_RAM_QAM_CTL_ENA__A,
+ &qam_ctl_ena, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr,
+ SCU_RAM_QAM_CTL_ENA__A,
+ qam_ctl_ena & ~SCU_RAM_QAM_CTL_ENA_ACQ__M, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr,
+ SCU_RAM_QAM_FSM_STATE_TGT__A,
+ 0x2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* force to rate hunting */
+
+ rc = set_qam(demod, channel, tuner_freq_offset,
+ QAM_SET_OP_CONSTELLATION);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr,
+ SCU_RAM_QAM_CTL_ENA__A,
+ qam_ctl_ena, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = qam64auto(demod, channel, tuner_freq_offset,
+ &lock_status);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ channel->constellation = DRX_CONSTELLATION_AUTO;
+ } else if (ext_attr->standard == DRX_STANDARD_ITU_C) {
+ u16 qam_ctl_ena = 0;
+
+ channel->constellation = DRX_CONSTELLATION_QAM64;
+ ext_attr->constellation = DRX_CONSTELLATION_QAM64;
+ auto_flag = true;
+
+ if (channel->mirror == DRX_MIRROR_AUTO)
+ ext_attr->mirror = DRX_MIRROR_NO;
+ else
+ ext_attr->mirror = channel->mirror;
+ rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr,
+ SCU_RAM_QAM_CTL_ENA__A,
+ &qam_ctl_ena, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr,
+ SCU_RAM_QAM_CTL_ENA__A,
+ qam_ctl_ena & ~SCU_RAM_QAM_CTL_ENA_ACQ__M, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr,
+ SCU_RAM_QAM_FSM_STATE_TGT__A,
+ 0x2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* force to rate hunting */
+
+ rc = set_qam(demod, channel, tuner_freq_offset,
+ QAM_SET_OP_CONSTELLATION);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(demod->my_i2c_dev_addr,
+ SCU_RAM_QAM_CTL_ENA__A,
+ qam_ctl_ena, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = qam64auto(demod, channel, tuner_freq_offset,
+ &lock_status);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ channel->constellation = DRX_CONSTELLATION_AUTO;
+ } else {
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+rw_error:
+ /* restore starting value */
+ if (auto_flag)
+ channel->constellation = DRX_CONSTELLATION_AUTO;
+ return -EIO;
+}
+
+/*============================================================================*/
+
+/**
+* \fn static short get_qamrs_err_count(struct i2c_device_addr *dev_addr)
+* \brief Get RS error count in QAM mode (used for post RS BER calculation)
+* \return Error code
+*
+* precondition: measurement period & measurement prescale must be set
+*
+*/
+static int
+get_qamrs_err_count(struct i2c_device_addr *dev_addr,
+ struct drxjrs_errors *rs_errors)
+{
+ int rc;
+ u16 nr_bit_errors = 0,
+ nr_symbol_errors = 0,
+ nr_packet_errors = 0, nr_failures = 0, nr_snc_par_fail_count = 0;
+
+ /* check arguments */
+ if (dev_addr == NULL)
+ return -EINVAL;
+
+ /* all reported errors are received in the */
+ /* most recently finished measurment period */
+ /* no of pre RS bit errors */
+ rc = drxj_dap_read_reg16(dev_addr, FEC_RS_NR_BIT_ERRORS__A, &nr_bit_errors, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* no of symbol errors */
+ rc = drxj_dap_read_reg16(dev_addr, FEC_RS_NR_SYMBOL_ERRORS__A, &nr_symbol_errors, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* no of packet errors */
+ rc = drxj_dap_read_reg16(dev_addr, FEC_RS_NR_PACKET_ERRORS__A, &nr_packet_errors, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* no of failures to decode */
+ rc = drxj_dap_read_reg16(dev_addr, FEC_RS_NR_FAILURES__A, &nr_failures, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* no of post RS bit erros */
+ rc = drxj_dap_read_reg16(dev_addr, FEC_OC_SNC_FAIL_COUNT__A, &nr_snc_par_fail_count, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* TODO: NOTE */
+ /* These register values are fetched in non-atomic fashion */
+ /* It is possible that the read values contain unrelated information */
+
+ rs_errors->nr_bit_errors = nr_bit_errors & FEC_RS_NR_BIT_ERRORS__M;
+ rs_errors->nr_symbol_errors = nr_symbol_errors & FEC_RS_NR_SYMBOL_ERRORS__M;
+ rs_errors->nr_packet_errors = nr_packet_errors & FEC_RS_NR_PACKET_ERRORS__M;
+ rs_errors->nr_failures = nr_failures & FEC_RS_NR_FAILURES__M;
+ rs_errors->nr_snc_par_fail_count =
+ nr_snc_par_fail_count & FEC_OC_SNC_FAIL_COUNT__M;
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*============================================================================*/
+
+/**
+ * \fn int get_sig_strength()
+ * \brief Retrieve signal strength for VSB and QAM.
+ * \param demod Pointer to demod instance
+ * \param u16-t Pointer to signal strength data; range 0, .. , 100.
+ * \return int.
+ * \retval 0 sig_strength contains valid data.
+ * \retval -EINVAL sig_strength is NULL.
+ * \retval -EIO Erroneous data, sig_strength contains invalid data.
+ */
+#define DRXJ_AGC_TOP 0x2800
+#define DRXJ_AGC_SNS 0x1600
+#define DRXJ_RFAGC_MAX 0x3fff
+#define DRXJ_RFAGC_MIN 0x800
+
+static int get_sig_strength(struct drx_demod_instance *demod, u16 *sig_strength)
+{
+ struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
+ int rc;
+ u16 rf_gain = 0;
+ u16 if_gain = 0;
+ u16 if_agc_sns = 0;
+ u16 if_agc_top = 0;
+ u16 rf_agc_max = 0;
+ u16 rf_agc_min = 0;
+
+ rc = drxj_dap_read_reg16(dev_addr, IQM_AF_AGC_IF__A, &if_gain, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if_gain &= IQM_AF_AGC_IF__M;
+ rc = drxj_dap_read_reg16(dev_addr, IQM_AF_AGC_RF__A, &rf_gain, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rf_gain &= IQM_AF_AGC_RF__M;
+
+ if_agc_sns = DRXJ_AGC_SNS;
+ if_agc_top = DRXJ_AGC_TOP;
+ rf_agc_max = DRXJ_RFAGC_MAX;
+ rf_agc_min = DRXJ_RFAGC_MIN;
+
+ if (if_gain > if_agc_top) {
+ if (rf_gain > rf_agc_max)
+ *sig_strength = 100;
+ else if (rf_gain > rf_agc_min) {
+ if (rf_agc_max == rf_agc_min) {
+ pr_err("error: rf_agc_max == rf_agc_min\n");
+ return -EIO;
+ }
+ *sig_strength =
+ 75 + 25 * (rf_gain - rf_agc_min) / (rf_agc_max -
+ rf_agc_min);
+ } else
+ *sig_strength = 75;
+ } else if (if_gain > if_agc_sns) {
+ if (if_agc_top == if_agc_sns) {
+ pr_err("error: if_agc_top == if_agc_sns\n");
+ return -EIO;
+ }
+ *sig_strength =
+ 20 + 55 * (if_gain - if_agc_sns) / (if_agc_top - if_agc_sns);
+ } else {
+ if (!if_agc_sns) {
+ pr_err("error: if_agc_sns is zero!\n");
+ return -EIO;
+ }
+ *sig_strength = (20 * if_gain / if_agc_sns);
+ }
+
+ if (*sig_strength <= 7)
+ *sig_strength = 0;
+
+ return 0;
+ rw_error:
+ return -EIO;
+}
+
+/**
+* \fn int ctrl_get_qam_sig_quality()
+* \brief Retreive QAM signal quality from device.
+* \param devmod Pointer to demodulator instance.
+* \param sig_quality Pointer to signal quality data.
+* \return int.
+* \retval 0 sig_quality contains valid data.
+* \retval -EINVAL sig_quality is NULL.
+* \retval -EIO Erroneous data, sig_quality contains invalid data.
+
+* Pre-condition: Device must be started and in lock.
+*/
+static int
+ctrl_get_qam_sig_quality(struct drx_demod_instance *demod)
+{
+ struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
+ struct drxj_data *ext_attr = demod->my_ext_attr;
+ struct drx39xxj_state *state = dev_addr->user_data;
+ struct dtv_frontend_properties *p = &state->frontend.dtv_property_cache;
+ struct drxjrs_errors measuredrs_errors = { 0, 0, 0, 0, 0 };
+ enum drx_modulation constellation = ext_attr->constellation;
+ int rc;
+
+ u32 pre_bit_err_rs = 0; /* pre RedSolomon Bit Error Rate */
+ u32 post_bit_err_rs = 0; /* post RedSolomon Bit Error Rate */
+ u32 pkt_errs = 0; /* no of packet errors in RS */
+ u16 qam_sl_err_power = 0; /* accumulated error between raw and sliced symbols */
+ u16 qsym_err_vd = 0; /* quadrature symbol errors in QAM_VD */
+ u16 fec_oc_period = 0; /* SNC sync failure measurement period */
+ u16 fec_rs_prescale = 0; /* ReedSolomon Measurement Prescale */
+ u16 fec_rs_period = 0; /* Value for corresponding I2C register */
+ /* calculation constants */
+ u32 rs_bit_cnt = 0; /* RedSolomon Bit Count */
+ u32 qam_sl_sig_power = 0; /* used for MER, depends of QAM constellation */
+ /* intermediate results */
+ u32 e = 0; /* exponent value used for QAM BER/SER */
+ u32 m = 0; /* mantisa value used for QAM BER/SER */
+ u32 ber_cnt = 0; /* BER count */
+ /* signal quality info */
+ u32 qam_sl_mer = 0; /* QAM MER */
+ u32 qam_pre_rs_ber = 0; /* Pre RedSolomon BER */
+ u32 qam_post_rs_ber = 0; /* Post RedSolomon BER */
+ u32 qam_vd_ser = 0; /* ViterbiDecoder SER */
+ u16 qam_vd_prescale = 0; /* Viterbi Measurement Prescale */
+ u16 qam_vd_period = 0; /* Viterbi Measurement period */
+ u32 vd_bit_cnt = 0; /* ViterbiDecoder Bit Count */
+
+ p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+ /* read the physical registers */
+ /* Get the RS error data */
+ rc = get_qamrs_err_count(dev_addr, &measuredrs_errors);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* get the register value needed for MER */
+ rc = drxj_dap_read_reg16(dev_addr, QAM_SL_ERR_POWER__A, &qam_sl_err_power, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* get the register value needed for post RS BER */
+ rc = drxj_dap_read_reg16(dev_addr, FEC_OC_SNC_FAIL_PERIOD__A, &fec_oc_period, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* get constants needed for signal quality calculation */
+ fec_rs_period = ext_attr->fec_rs_period;
+ fec_rs_prescale = ext_attr->fec_rs_prescale;
+ rs_bit_cnt = fec_rs_period * fec_rs_prescale * ext_attr->fec_rs_plen;
+ qam_vd_period = ext_attr->qam_vd_period;
+ qam_vd_prescale = ext_attr->qam_vd_prescale;
+ vd_bit_cnt = qam_vd_period * qam_vd_prescale * ext_attr->fec_vd_plen;
+
+ /* DRXJ_QAM_SL_SIG_POWER_QAMxxx * 4 */
+ switch (constellation) {
+ case DRX_CONSTELLATION_QAM16:
+ qam_sl_sig_power = DRXJ_QAM_SL_SIG_POWER_QAM16 << 2;
+ break;
+ case DRX_CONSTELLATION_QAM32:
+ qam_sl_sig_power = DRXJ_QAM_SL_SIG_POWER_QAM32 << 2;
+ break;
+ case DRX_CONSTELLATION_QAM64:
+ qam_sl_sig_power = DRXJ_QAM_SL_SIG_POWER_QAM64 << 2;
+ break;
+ case DRX_CONSTELLATION_QAM128:
+ qam_sl_sig_power = DRXJ_QAM_SL_SIG_POWER_QAM128 << 2;
+ break;
+ case DRX_CONSTELLATION_QAM256:
+ qam_sl_sig_power = DRXJ_QAM_SL_SIG_POWER_QAM256 << 2;
+ break;
+ default:
+ return -EIO;
+ }
+
+ /* ------------------------------ */
+ /* MER Calculation */
+ /* ------------------------------ */
+ /* MER is good if it is above 27.5 for QAM256 or 21.5 for QAM64 */
+
+ /* 10.0*log10(qam_sl_sig_power * 4.0 / qam_sl_err_power); */
+ if (qam_sl_err_power == 0)
+ qam_sl_mer = 0;
+ else
+ qam_sl_mer = log1_times100(qam_sl_sig_power) - log1_times100((u32)qam_sl_err_power);
+
+ /* ----------------------------------------- */
+ /* Pre Viterbi Symbol Error Rate Calculation */
+ /* ----------------------------------------- */
+ /* pre viterbi SER is good if it is bellow 0.025 */
+
+ /* get the register value */
+ /* no of quadrature symbol errors */
+ rc = drxj_dap_read_reg16(dev_addr, QAM_VD_NR_QSYM_ERRORS__A, &qsym_err_vd, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* Extract the Exponent and the Mantisa */
+ /* of number of quadrature symbol errors */
+ e = (qsym_err_vd & QAM_VD_NR_QSYM_ERRORS_EXP__M) >>
+ QAM_VD_NR_QSYM_ERRORS_EXP__B;
+ m = (qsym_err_vd & QAM_VD_NR_SYMBOL_ERRORS_FIXED_MANT__M) >>
+ QAM_VD_NR_SYMBOL_ERRORS_FIXED_MANT__B;
+
+ if ((m << e) >> 3 > 549752)
+ qam_vd_ser = 500000 * vd_bit_cnt * ((e > 2) ? 1 : 8) / 8;
+ else
+ qam_vd_ser = m << ((e > 2) ? (e - 3) : e);
+
+ /* --------------------------------------- */
+ /* pre and post RedSolomon BER Calculation */
+ /* --------------------------------------- */
+ /* pre RS BER is good if it is below 3.5e-4 */
+
+ /* get the register values */
+ pre_bit_err_rs = (u32) measuredrs_errors.nr_bit_errors;
+ pkt_errs = post_bit_err_rs = (u32) measuredrs_errors.nr_snc_par_fail_count;
+
+ /* Extract the Exponent and the Mantisa of the */
+ /* pre Reed-Solomon bit error count */
+ e = (pre_bit_err_rs & FEC_RS_NR_BIT_ERRORS_EXP__M) >>
+ FEC_RS_NR_BIT_ERRORS_EXP__B;
+ m = (pre_bit_err_rs & FEC_RS_NR_BIT_ERRORS_FIXED_MANT__M) >>
+ FEC_RS_NR_BIT_ERRORS_FIXED_MANT__B;
+
+ ber_cnt = m << e;
+
+ /*qam_pre_rs_ber = frac_times1e6( ber_cnt, rs_bit_cnt ); */
+ if (m > (rs_bit_cnt >> (e + 1)) || (rs_bit_cnt >> e) == 0)
+ qam_pre_rs_ber = 500000 * rs_bit_cnt >> e;
+ else
+ qam_pre_rs_ber = ber_cnt;
+
+ /* post RS BER = 1000000* (11.17 * FEC_OC_SNC_FAIL_COUNT__A) / */
+ /* (1504.0 * FEC_OC_SNC_FAIL_PERIOD__A) */
+ /*
+ => c = (1000000*100*11.17)/1504 =
+ post RS BER = (( c* FEC_OC_SNC_FAIL_COUNT__A) /
+ (100 * FEC_OC_SNC_FAIL_PERIOD__A)
+ *100 and /100 is for more precision.
+ => (20 bits * 12 bits) /(16 bits * 7 bits) => safe in 32 bits computation
+
+ Precision errors still possible.
+ */
+ e = post_bit_err_rs * 742686;
+ m = fec_oc_period * 100;
+ if (fec_oc_period == 0)
+ qam_post_rs_ber = 0xFFFFFFFF;
+ else
+ qam_post_rs_ber = e / m;
+
+ /* fill signal quality data structure */
+ p->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ p->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ p->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ p->block_error.stat[0].scale = FE_SCALE_COUNTER;
+ p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+
+ p->cnr.stat[0].svalue = ((u16) qam_sl_mer) * 100;
+ if (ext_attr->standard == DRX_STANDARD_ITU_B) {
+ p->pre_bit_error.stat[0].uvalue += qam_vd_ser;
+ p->pre_bit_count.stat[0].uvalue += vd_bit_cnt * ((e > 2) ? 1 : 8) / 8;
+ } else {
+ p->pre_bit_error.stat[0].uvalue += qam_pre_rs_ber;
+ p->pre_bit_count.stat[0].uvalue += rs_bit_cnt >> e;
+ }
+
+ p->post_bit_error.stat[0].uvalue += qam_post_rs_ber;
+ p->post_bit_count.stat[0].uvalue += rs_bit_cnt >> e;
+
+ p->block_error.stat[0].uvalue += pkt_errs;
+
+#ifdef DRXJ_SIGNAL_ACCUM_ERR
+ rc = get_acc_pkt_err(demod, &sig_quality->packet_error);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+#endif
+
+ return 0;
+rw_error:
+ p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+ return -EIO;
+}
+
+#endif /* #ifndef DRXJ_VSB_ONLY */
+
+/*============================================================================*/
+/*== END QAM DATAPATH FUNCTIONS ==*/
+/*============================================================================*/
+
+/*============================================================================*/
+/*============================================================================*/
+/*== ATV DATAPATH FUNCTIONS ==*/
+/*============================================================================*/
+/*============================================================================*/
+
+/*
+ Implementation notes.
+
+ NTSC/FM AGCs
+
+ Four AGCs are used for NTSC:
+ (1) RF (used to attenuate the input signal in case of to much power)
+ (2) IF (used to attenuate the input signal in case of to much power)
+ (3) Video AGC (used to amplify the output signal in case input to low)
+ (4) SIF AGC (used to amplify the output signal in case input to low)
+
+ Video AGC is coupled to RF and IF. SIF AGC is not coupled. It is assumed
+ that the coupling between Video AGC and the RF and IF AGCs also works in
+ favor of the SIF AGC.
+
+ Three AGCs are used for FM:
+ (1) RF (used to attenuate the input signal in case of to much power)
+ (2) IF (used to attenuate the input signal in case of to much power)
+ (3) SIF AGC (used to amplify the output signal in case input to low)
+
+ The SIF AGC is now coupled to the RF/IF AGCs.
+ The SIF AGC is needed for both SIF ouput and the internal SIF signal to
+ the AUD block.
+
+ RF and IF AGCs DACs are part of AFE, Video and SIF AGC DACs are part of
+ the ATV block. The AGC control algorithms are all implemented in
+ microcode.
+
+ ATV SETTINGS
+
+ (Shadow settings will not be used for now, they will be implemented
+ later on because of the schedule)
+
+ Several HW/SCU "settings" can be used for ATV. The standard selection
+ will reset most of these settings. To avoid that the end user apllication
+ has to perform these settings each time the ATV or FM standards is
+ selected the driver will shadow these settings. This enables the end user
+ to perform the settings only once after a drx_open(). The driver must
+ write the shadow settings to HW/SCU incase:
+ ( setstandard FM/ATV) ||
+ ( settings have changed && FM/ATV standard is active)
+ The shadow settings will be stored in the device specific data container.
+ A set of flags will be defined to flag changes in shadow settings.
+ A routine will be implemented to write all changed shadow settings to
+ HW/SCU.
+
+ The "settings" will consist of: AGC settings, filter settings etc.
+
+ Disadvantage of use of shadow settings:
+ Direct changes in HW/SCU registers will not be reflected in the
+ shadow settings and these changes will be overwritten during a next
+ update. This can happen during evaluation. This will not be a problem
+ for normal customer usage.
+*/
+/* -------------------------------------------------------------------------- */
+
+/**
+* \fn int power_down_atv ()
+* \brief Power down ATV.
+* \param demod instance of demodulator
+* \param standard either NTSC or FM (sub strandard for ATV )
+* \return int.
+*
+* Stops and thus resets ATV and IQM block
+* SIF and CVBS ADC are powered down
+* Calls audio power down
+*/
+static int
+power_down_atv(struct drx_demod_instance *demod, enum drx_standard standard, bool primary)
+{
+ struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
+ struct drxjscu_cmd cmd_scu = { /* command */ 0,
+ /* parameter_len */ 0,
+ /* result_len */ 0,
+ /* *parameter */ NULL,
+ /* *result */ NULL
+ };
+ int rc;
+ u16 cmd_result = 0;
+
+ /* ATV NTSC */
+
+ /* Stop ATV SCU (will reset ATV and IQM hardware */
+ cmd_scu.command = SCU_RAM_COMMAND_STANDARD_ATV |
+ SCU_RAM_COMMAND_CMD_DEMOD_STOP;
+ cmd_scu.parameter_len = 0;
+ cmd_scu.result_len = 1;
+ cmd_scu.parameter = NULL;
+ cmd_scu.result = &cmd_result;
+ rc = scu_command(dev_addr, &cmd_scu);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* Disable ATV outputs (ATV reset enables CVBS, undo this) */
+ rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_STDBY__A, (ATV_TOP_STDBY_SIF_STDBY_STANDBY & (~ATV_TOP_STDBY_CVBS_STDBY_A2_ACTIVE)), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, ATV_COMM_EXEC__A, ATV_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (primary) {
+ rc = drxj_dap_write_reg16(dev_addr, IQM_COMM_EXEC__A, IQM_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = set_iqm_af(demod, false);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ } else {
+ rc = drxj_dap_write_reg16(dev_addr, IQM_FS_COMM_EXEC__A, IQM_FS_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_FD_COMM_EXEC__A, IQM_FD_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_RC_COMM_EXEC__A, IQM_RC_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_RT_COMM_EXEC__A, IQM_RT_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, IQM_CF_COMM_EXEC__A, IQM_CF_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+ rc = power_down_aud(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*============================================================================*/
+
+/**
+* \brief Power up AUD.
+* \param demod instance of demodulator
+* \return int.
+*
+*/
+static int power_down_aud(struct drx_demod_instance *demod)
+{
+ struct i2c_device_addr *dev_addr = NULL;
+ struct drxj_data *ext_attr = NULL;
+ int rc;
+
+ dev_addr = (struct i2c_device_addr *)demod->my_i2c_dev_addr;
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+
+ rc = drxj_dap_write_reg16(dev_addr, AUD_COMM_EXEC__A, AUD_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ ext_attr->aud_data.audio_is_active = false;
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/**
+* \fn int set_orx_nsu_aox()
+* \brief Configure OrxNsuAox for OOB
+* \param demod instance of demodulator.
+* \param active
+* \return int.
+*/
+static int set_orx_nsu_aox(struct drx_demod_instance *demod, bool active)
+{
+ struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
+ int rc;
+ u16 data = 0;
+
+ /* Configure NSU_AOX */
+ rc = drxj_dap_read_reg16(dev_addr, ORX_NSU_AOX_STDBY_W__A, &data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (!active)
+ data &= ((~ORX_NSU_AOX_STDBY_W_STDBYADC_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYAMP_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYBIAS_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYPLL_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYPD_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYTAGC_IF_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYTAGC_RF_A2_ON) & (~ORX_NSU_AOX_STDBY_W_STDBYFLT_A2_ON));
+ else
+ data |= (ORX_NSU_AOX_STDBY_W_STDBYADC_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYAMP_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYBIAS_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYPLL_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYPD_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYTAGC_IF_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYTAGC_RF_A2_ON | ORX_NSU_AOX_STDBY_W_STDBYFLT_A2_ON);
+ rc = drxj_dap_write_reg16(dev_addr, ORX_NSU_AOX_STDBY_W__A, data, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/**
+* \fn int ctrl_set_oob()
+* \brief Set OOB channel to be used.
+* \param demod instance of demodulator
+* \param oob_param OOB parameters for channel setting.
+* \frequency should be in KHz
+* \return int.
+*
+* Accepts only. Returns error otherwise.
+* Demapper value is written after scu_command START
+* because START command causes COMM_EXEC transition
+* from 0 to 1 which causes all registers to be
+* overwritten with initial value
+*
+*/
+
+/* Nyquist filter impulse response */
+#define IMPULSE_COSINE_ALPHA_0_3 {-3, -4, -1, 6, 10, 7, -5, -20, -25, -10, 29, 79, 123, 140} /*sqrt raised-cosine filter with alpha=0.3 */
+#define IMPULSE_COSINE_ALPHA_0_5 { 2, 0, -2, -2, 2, 5, 2, -10, -20, -14, 20, 74, 125, 145} /*sqrt raised-cosine filter with alpha=0.5 */
+#define IMPULSE_COSINE_ALPHA_RO_0_5 { 0, 0, 1, 2, 3, 0, -7, -15, -16, 0, 34, 77, 114, 128} /*full raised-cosine filter with alpha=0.5 (receiver only) */
+
+/* Coefficients for the nyquist fitler (total: 27 taps) */
+#define NYQFILTERLEN 27
+
+static int ctrl_set_oob(struct drx_demod_instance *demod, struct drxoob *oob_param)
+{
+ int rc;
+ s32 freq = 0; /* KHz */
+ struct i2c_device_addr *dev_addr = NULL;
+ struct drxj_data *ext_attr = NULL;
+ u16 i = 0;
+ bool mirror_freq_spect_oob = false;
+ u16 trk_filter_value = 0;
+ struct drxjscu_cmd scu_cmd;
+ u16 set_param_parameters[3];
+ u16 cmd_result[2] = { 0, 0 };
+ s16 nyquist_coeffs[4][(NYQFILTERLEN + 1) / 2] = {
+ IMPULSE_COSINE_ALPHA_0_3, /* Target Mode 0 */
+ IMPULSE_COSINE_ALPHA_0_3, /* Target Mode 1 */
+ IMPULSE_COSINE_ALPHA_0_5, /* Target Mode 2 */
+ IMPULSE_COSINE_ALPHA_RO_0_5 /* Target Mode 3 */
+ };
+ u8 mode_val[4] = { 2, 2, 0, 1 };
+ u8 pfi_coeffs[4][6] = {
+ {DRXJ_16TO8(-92), DRXJ_16TO8(-108), DRXJ_16TO8(100)}, /* TARGET_MODE = 0: PFI_A = -23/32; PFI_B = -54/32; PFI_C = 25/32; fg = 0.5 MHz (Att=26dB) */
+ {DRXJ_16TO8(-64), DRXJ_16TO8(-80), DRXJ_16TO8(80)}, /* TARGET_MODE = 1: PFI_A = -16/32; PFI_B = -40/32; PFI_C = 20/32; fg = 1.0 MHz (Att=28dB) */
+ {DRXJ_16TO8(-80), DRXJ_16TO8(-98), DRXJ_16TO8(92)}, /* TARGET_MODE = 2, 3: PFI_A = -20/32; PFI_B = -49/32; PFI_C = 23/32; fg = 0.8 MHz (Att=25dB) */
+ {DRXJ_16TO8(-80), DRXJ_16TO8(-98), DRXJ_16TO8(92)} /* TARGET_MODE = 2, 3: PFI_A = -20/32; PFI_B = -49/32; PFI_C = 23/32; fg = 0.8 MHz (Att=25dB) */
+ };
+ u16 mode_index;
+
+ dev_addr = demod->my_i2c_dev_addr;
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+ mirror_freq_spect_oob = ext_attr->mirror_freq_spect_oob;
+
+ /* Check parameters */
+ if (oob_param == NULL) {
+ /* power off oob module */
+ scu_cmd.command = SCU_RAM_COMMAND_STANDARD_OOB
+ | SCU_RAM_COMMAND_CMD_DEMOD_STOP;
+ scu_cmd.parameter_len = 0;
+ scu_cmd.result_len = 1;
+ scu_cmd.result = cmd_result;
+ rc = scu_command(dev_addr, &scu_cmd);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = set_orx_nsu_aox(demod, false);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, ORX_COMM_EXEC__A, ORX_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ ext_attr->oob_power_on = false;
+ return 0;
+ }
+
+ freq = oob_param->frequency;
+ if ((freq < 70000) || (freq > 130000))
+ return -EIO;
+ freq = (freq - 50000) / 50;
+
+ {
+ u16 index = 0;
+ u16 remainder = 0;
+ u16 *trk_filtercfg = ext_attr->oob_trk_filter_cfg;
+
+ index = (u16) ((freq - 400) / 200);
+ remainder = (u16) ((freq - 400) % 200);
+ trk_filter_value =
+ trk_filtercfg[index] - (trk_filtercfg[index] -
+ trk_filtercfg[index +
+ 1]) / 10 * remainder /
+ 20;
+ }
+
+ /*********/
+ /* Stop */
+ /*********/
+ rc = drxj_dap_write_reg16(dev_addr, ORX_COMM_EXEC__A, ORX_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ scu_cmd.command = SCU_RAM_COMMAND_STANDARD_OOB
+ | SCU_RAM_COMMAND_CMD_DEMOD_STOP;
+ scu_cmd.parameter_len = 0;
+ scu_cmd.result_len = 1;
+ scu_cmd.result = cmd_result;
+ rc = scu_command(dev_addr, &scu_cmd);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /*********/
+ /* Reset */
+ /*********/
+ scu_cmd.command = SCU_RAM_COMMAND_STANDARD_OOB
+ | SCU_RAM_COMMAND_CMD_DEMOD_RESET;
+ scu_cmd.parameter_len = 0;
+ scu_cmd.result_len = 1;
+ scu_cmd.result = cmd_result;
+ rc = scu_command(dev_addr, &scu_cmd);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /***********/
+ /* SET_ENV */
+ /***********/
+ /* set frequency, spectrum inversion and data rate */
+ scu_cmd.command = SCU_RAM_COMMAND_STANDARD_OOB
+ | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV;
+ scu_cmd.parameter_len = 3;
+ /* 1-data rate;2-frequency */
+ switch (oob_param->standard) {
+ case DRX_OOB_MODE_A:
+ if (
+ /* signal is transmitted inverted */
+ ((oob_param->spectrum_inverted == true) &&
+ /* and tuner is not mirroring the signal */
+ (!mirror_freq_spect_oob)) |
+ /* or */
+ /* signal is transmitted noninverted */
+ ((oob_param->spectrum_inverted == false) &&
+ /* and tuner is mirroring the signal */
+ (mirror_freq_spect_oob))
+ )
+ set_param_parameters[0] =
+ SCU_RAM_ORX_RF_RX_DATA_RATE_2048KBPS_INVSPEC;
+ else
+ set_param_parameters[0] =
+ SCU_RAM_ORX_RF_RX_DATA_RATE_2048KBPS_REGSPEC;
+ break;
+ case DRX_OOB_MODE_B_GRADE_A:
+ if (
+ /* signal is transmitted inverted */
+ ((oob_param->spectrum_inverted == true) &&
+ /* and tuner is not mirroring the signal */
+ (!mirror_freq_spect_oob)) |
+ /* or */
+ /* signal is transmitted noninverted */
+ ((oob_param->spectrum_inverted == false) &&
+ /* and tuner is mirroring the signal */
+ (mirror_freq_spect_oob))
+ )
+ set_param_parameters[0] =
+ SCU_RAM_ORX_RF_RX_DATA_RATE_1544KBPS_INVSPEC;
+ else
+ set_param_parameters[0] =
+ SCU_RAM_ORX_RF_RX_DATA_RATE_1544KBPS_REGSPEC;
+ break;
+ case DRX_OOB_MODE_B_GRADE_B:
+ default:
+ if (
+ /* signal is transmitted inverted */
+ ((oob_param->spectrum_inverted == true) &&
+ /* and tuner is not mirroring the signal */
+ (!mirror_freq_spect_oob)) |
+ /* or */
+ /* signal is transmitted noninverted */
+ ((oob_param->spectrum_inverted == false) &&
+ /* and tuner is mirroring the signal */
+ (mirror_freq_spect_oob))
+ )
+ set_param_parameters[0] =
+ SCU_RAM_ORX_RF_RX_DATA_RATE_3088KBPS_INVSPEC;
+ else
+ set_param_parameters[0] =
+ SCU_RAM_ORX_RF_RX_DATA_RATE_3088KBPS_REGSPEC;
+ break;
+ }
+ set_param_parameters[1] = (u16) (freq & 0xFFFF);
+ set_param_parameters[2] = trk_filter_value;
+ scu_cmd.parameter = set_param_parameters;
+ scu_cmd.result_len = 1;
+ scu_cmd.result = cmd_result;
+ mode_index = mode_val[(set_param_parameters[0] & 0xC0) >> 6];
+ rc = scu_command(dev_addr, &scu_cmd);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SIO_TOP_COMM_KEY__A, 0xFABA, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* Write magic word to enable pdr reg write */
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_OOB_CRX_CFG__A, OOB_CRX_DRIVE_STRENGTH << SIO_PDR_OOB_CRX_CFG_DRIVE__B | 0x03 << SIO_PDR_OOB_CRX_CFG_MODE__B, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_PDR_OOB_DRX_CFG__A, OOB_DRX_DRIVE_STRENGTH << SIO_PDR_OOB_DRX_CFG_DRIVE__B | 0x03 << SIO_PDR_OOB_DRX_CFG_MODE__B, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_TOP_COMM_KEY__A, 0x0000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ } /* Write magic word to disable pdr reg write */
+
+ rc = drxj_dap_write_reg16(dev_addr, ORX_TOP_COMM_KEY__A, 0, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, ORX_FWP_AAG_LEN_W__A, 16000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, ORX_FWP_AAG_THR_W__A, 40, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* ddc */
+ rc = drxj_dap_write_reg16(dev_addr, ORX_DDC_OFO_SET_W__A, ORX_DDC_OFO_SET_W__PRE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* nsu */
+ rc = drxj_dap_write_reg16(dev_addr, ORX_NSU_AOX_LOPOW_W__A, ext_attr->oob_lo_pow, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* initialization for target mode */
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_TARGET_MODE__A, SCU_RAM_ORX_TARGET_MODE_2048KBPS_SQRT, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_FREQ_GAIN_CORR__A, SCU_RAM_ORX_FREQ_GAIN_CORR_2048KBPS, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Reset bits for timing and freq. recovery */
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_RST_CPH__A, 0x0001, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_RST_CTI__A, 0x0002, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_RST_KRN__A, 0x0004, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_RST_KRP__A, 0x0008, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* AGN_LOCK = {2048>>3, -2048, 8, -8, 0, 1}; */
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_AGN_LOCK_TH__A, 2048 >> 3, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_AGN_LOCK_TOTH__A, (u16)(-2048), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_AGN_ONLOCK_TTH__A, 8, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_AGN_UNLOCK_TTH__A, (u16)(-8), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_AGN_LOCK_MASK__A, 1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* DGN_LOCK = {10, -2048, 8, -8, 0, 1<<1}; */
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_DGN_LOCK_TH__A, 10, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_DGN_LOCK_TOTH__A, (u16)(-2048), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_DGN_ONLOCK_TTH__A, 8, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_DGN_UNLOCK_TTH__A, (u16)(-8), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_DGN_LOCK_MASK__A, 1 << 1, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* FRQ_LOCK = {15,-2048, 8, -8, 0, 1<<2}; */
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_FRQ_LOCK_TH__A, 17, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_FRQ_LOCK_TOTH__A, (u16)(-2048), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_FRQ_ONLOCK_TTH__A, 8, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_FRQ_UNLOCK_TTH__A, (u16)(-8), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_FRQ_LOCK_MASK__A, 1 << 2, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* PHA_LOCK = {5000, -2048, 8, -8, 0, 1<<3}; */
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_PHA_LOCK_TH__A, 3000, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_PHA_LOCK_TOTH__A, (u16)(-2048), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_PHA_ONLOCK_TTH__A, 8, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_PHA_UNLOCK_TTH__A, (u16)(-8), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_PHA_LOCK_MASK__A, 1 << 3, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* TIM_LOCK = {300, -2048, 8, -8, 0, 1<<4}; */
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_TIM_LOCK_TH__A, 400, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_TIM_LOCK_TOTH__A, (u16)(-2048), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_TIM_ONLOCK_TTH__A, 8, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_TIM_UNLOCK_TTH__A, (u16)(-8), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_TIM_LOCK_MASK__A, 1 << 4, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* EQU_LOCK = {20, -2048, 8, -8, 0, 1<<5}; */
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_EQU_LOCK_TH__A, 20, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_EQU_LOCK_TOTH__A, (u16)(-2048), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_EQU_ONLOCK_TTH__A, 4, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_EQU_UNLOCK_TTH__A, (u16)(-4), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_ORX_EQU_LOCK_MASK__A, 1 << 5, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* PRE-Filter coefficients (PFI) */
+ rc = drxdap_fasi_write_block(dev_addr, ORX_FWP_PFI_A_W__A, sizeof(pfi_coeffs[mode_index]), ((u8 *)pfi_coeffs[mode_index]), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, ORX_TOP_MDE_W__A, mode_index, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* NYQUIST-Filter coefficients (NYQ) */
+ for (i = 0; i < (NYQFILTERLEN + 1) / 2; i++) {
+ rc = drxj_dap_write_reg16(dev_addr, ORX_FWP_NYQ_ADR_W__A, i, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, ORX_FWP_NYQ_COF_RW__A, nyquist_coeffs[mode_index][i], 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+ rc = drxj_dap_write_reg16(dev_addr, ORX_FWP_NYQ_ADR_W__A, 31, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, ORX_COMM_EXEC__A, ORX_COMM_EXEC_ACTIVE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /*********/
+ /* Start */
+ /*********/
+ scu_cmd.command = SCU_RAM_COMMAND_STANDARD_OOB
+ | SCU_RAM_COMMAND_CMD_DEMOD_START;
+ scu_cmd.parameter_len = 0;
+ scu_cmd.result_len = 1;
+ scu_cmd.result = cmd_result;
+ rc = scu_command(dev_addr, &scu_cmd);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = set_orx_nsu_aox(demod, true);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, ORX_NSU_AOX_STHR_W__A, ext_attr->oob_pre_saw, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ ext_attr->oob_power_on = true;
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*============================================================================*/
+/*== END OOB DATAPATH FUNCTIONS ==*/
+/*============================================================================*/
+
+/*=============================================================================
+ ===== MC command related functions ==========================================
+ ===========================================================================*/
+
+/*=============================================================================
+ ===== ctrl_set_channel() ==========================================================
+ ===========================================================================*/
+/**
+* \fn int ctrl_set_channel()
+* \brief Select a new transmission channel.
+* \param demod instance of demod.
+* \param channel Pointer to channel data.
+* \return int.
+*
+* In case the tuner module is not used and in case of NTSC/FM the pogrammer
+* must tune the tuner to the centre frequency of the NTSC/FM channel.
+*
+*/
+static int
+ctrl_set_channel(struct drx_demod_instance *demod, struct drx_channel *channel)
+{
+ int rc;
+ s32 tuner_freq_offset = 0;
+ struct drxj_data *ext_attr = NULL;
+ struct i2c_device_addr *dev_addr = NULL;
+ enum drx_standard standard = DRX_STANDARD_UNKNOWN;
+#ifndef DRXJ_VSB_ONLY
+ u32 min_symbol_rate = 0;
+ u32 max_symbol_rate = 0;
+ int bandwidth_temp = 0;
+ int bandwidth = 0;
+#endif
+ /*== check arguments ======================================================*/
+ if ((demod == NULL) || (channel == NULL))
+ return -EINVAL;
+
+ dev_addr = demod->my_i2c_dev_addr;
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+ standard = ext_attr->standard;
+
+ /* check valid standards */
+ switch (standard) {
+ case DRX_STANDARD_8VSB:
+#ifndef DRXJ_VSB_ONLY
+ case DRX_STANDARD_ITU_A:
+ case DRX_STANDARD_ITU_B:
+ case DRX_STANDARD_ITU_C:
+#endif /* DRXJ_VSB_ONLY */
+ break;
+ case DRX_STANDARD_UNKNOWN:
+ default:
+ return -EINVAL;
+ }
+
+ /* check bandwidth QAM annex B, NTSC and 8VSB */
+ if ((standard == DRX_STANDARD_ITU_B) ||
+ (standard == DRX_STANDARD_8VSB) ||
+ (standard == DRX_STANDARD_NTSC)) {
+ switch (channel->bandwidth) {
+ case DRX_BANDWIDTH_6MHZ:
+ case DRX_BANDWIDTH_UNKNOWN: /* fall through */
+ channel->bandwidth = DRX_BANDWIDTH_6MHZ;
+ break;
+ case DRX_BANDWIDTH_8MHZ: /* fall through */
+ case DRX_BANDWIDTH_7MHZ: /* fall through */
+ default:
+ return -EINVAL;
+ }
+ }
+
+ /* For QAM annex A and annex C:
+ -check symbolrate and constellation
+ -derive bandwidth from symbolrate (input bandwidth is ignored)
+ */
+#ifndef DRXJ_VSB_ONLY
+ if ((standard == DRX_STANDARD_ITU_A) ||
+ (standard == DRX_STANDARD_ITU_C)) {
+ struct drxuio_cfg uio_cfg = { DRX_UIO1, DRX_UIO_MODE_FIRMWARE_SAW };
+ int bw_rolloff_factor = 0;
+
+ bw_rolloff_factor = (standard == DRX_STANDARD_ITU_A) ? 115 : 113;
+ min_symbol_rate = DRXJ_QAM_SYMBOLRATE_MIN;
+ max_symbol_rate = DRXJ_QAM_SYMBOLRATE_MAX;
+ /* config SMA_TX pin to SAW switch mode */
+ rc = ctrl_set_uio_cfg(demod, &uio_cfg);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ if (channel->symbolrate < min_symbol_rate ||
+ channel->symbolrate > max_symbol_rate) {
+ return -EINVAL;
+ }
+
+ switch (channel->constellation) {
+ case DRX_CONSTELLATION_QAM16: /* fall through */
+ case DRX_CONSTELLATION_QAM32: /* fall through */
+ case DRX_CONSTELLATION_QAM64: /* fall through */
+ case DRX_CONSTELLATION_QAM128: /* fall through */
+ case DRX_CONSTELLATION_QAM256:
+ bandwidth_temp = channel->symbolrate * bw_rolloff_factor;
+ bandwidth = bandwidth_temp / 100;
+
+ if ((bandwidth_temp % 100) >= 50)
+ bandwidth++;
+
+ if (bandwidth <= 6100000) {
+ channel->bandwidth = DRX_BANDWIDTH_6MHZ;
+ } else if ((bandwidth > 6100000)
+ && (bandwidth <= 7100000)) {
+ channel->bandwidth = DRX_BANDWIDTH_7MHZ;
+ } else if (bandwidth > 7100000) {
+ channel->bandwidth = DRX_BANDWIDTH_8MHZ;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ /* For QAM annex B:
+ -check constellation
+ */
+ if (standard == DRX_STANDARD_ITU_B) {
+ switch (channel->constellation) {
+ case DRX_CONSTELLATION_AUTO:
+ case DRX_CONSTELLATION_QAM256:
+ case DRX_CONSTELLATION_QAM64:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (channel->interleavemode) {
+ case DRX_INTERLEAVEMODE_I128_J1:
+ case DRX_INTERLEAVEMODE_I128_J1_V2:
+ case DRX_INTERLEAVEMODE_I128_J2:
+ case DRX_INTERLEAVEMODE_I64_J2:
+ case DRX_INTERLEAVEMODE_I128_J3:
+ case DRX_INTERLEAVEMODE_I32_J4:
+ case DRX_INTERLEAVEMODE_I128_J4:
+ case DRX_INTERLEAVEMODE_I16_J8:
+ case DRX_INTERLEAVEMODE_I128_J5:
+ case DRX_INTERLEAVEMODE_I8_J16:
+ case DRX_INTERLEAVEMODE_I128_J6:
+ case DRX_INTERLEAVEMODE_I128_J7:
+ case DRX_INTERLEAVEMODE_I128_J8:
+ case DRX_INTERLEAVEMODE_I12_J17:
+ case DRX_INTERLEAVEMODE_I5_J4:
+ case DRX_INTERLEAVEMODE_B52_M240:
+ case DRX_INTERLEAVEMODE_B52_M720:
+ case DRX_INTERLEAVEMODE_UNKNOWN:
+ case DRX_INTERLEAVEMODE_AUTO:
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ if ((ext_attr->uio_sma_tx_mode) == DRX_UIO_MODE_FIRMWARE_SAW) {
+ /* SAW SW, user UIO is used for switchable SAW */
+ struct drxuio_data uio1 = { DRX_UIO1, false };
+
+ switch (channel->bandwidth) {
+ case DRX_BANDWIDTH_8MHZ:
+ uio1.value = true;
+ break;
+ case DRX_BANDWIDTH_7MHZ:
+ uio1.value = false;
+ break;
+ case DRX_BANDWIDTH_6MHZ:
+ uio1.value = false;
+ break;
+ case DRX_BANDWIDTH_UNKNOWN:
+ default:
+ return -EINVAL;
+ }
+
+ rc = ctrl_uio_write(demod, &uio1);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+#endif /* DRXJ_VSB_ONLY */
+ rc = drxj_dap_write_reg16(dev_addr, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ tuner_freq_offset = 0;
+
+ /*== Setup demod for specific standard ====================================*/
+ switch (standard) {
+ case DRX_STANDARD_8VSB:
+ if (channel->mirror == DRX_MIRROR_AUTO)
+ ext_attr->mirror = DRX_MIRROR_NO;
+ else
+ ext_attr->mirror = channel->mirror;
+ rc = set_vsb(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = set_frequency(demod, channel, tuner_freq_offset);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+#ifndef DRXJ_VSB_ONLY
+ case DRX_STANDARD_ITU_A: /* fallthrough */
+ case DRX_STANDARD_ITU_B: /* fallthrough */
+ case DRX_STANDARD_ITU_C:
+ rc = set_qam_channel(demod, channel, tuner_freq_offset);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+#endif
+ case DRX_STANDARD_UNKNOWN:
+ default:
+ return -EIO;
+ }
+
+ /* flag the packet error counter reset */
+ ext_attr->reset_pkt_err_acc = true;
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*=============================================================================
+ ===== SigQuality() ==========================================================
+ ===========================================================================*/
+
+/**
+* \fn int ctrl_sig_quality()
+* \brief Retreive signal quality form device.
+* \param devmod Pointer to demodulator instance.
+* \param sig_quality Pointer to signal quality data.
+* \return int.
+* \retval 0 sig_quality contains valid data.
+* \retval -EINVAL sig_quality is NULL.
+* \retval -EIO Erroneous data, sig_quality contains invalid data.
+
+*/
+static int
+ctrl_sig_quality(struct drx_demod_instance *demod,
+ enum drx_lock_status lock_status)
+{
+ struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
+ struct drxj_data *ext_attr = demod->my_ext_attr;
+ struct drx39xxj_state *state = dev_addr->user_data;
+ struct dtv_frontend_properties *p = &state->frontend.dtv_property_cache;
+ enum drx_standard standard = ext_attr->standard;
+ int rc;
+ u32 ber, cnt, err, pkt;
+ u16 mer, strength;
+
+ rc = get_sig_strength(demod, &strength);
+ if (rc < 0) {
+ pr_err("error getting signal strength %d\n", rc);
+ p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ } else {
+ p->strength.stat[0].scale = FE_SCALE_RELATIVE;
+ p->strength.stat[0].uvalue = 65535UL * strength/ 100;
+ }
+
+ switch (standard) {
+ case DRX_STANDARD_8VSB:
+#ifdef DRXJ_SIGNAL_ACCUM_ERR
+ rc = get_acc_pkt_err(demod, &pkt);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+#endif
+ if (lock_status != DRXJ_DEMOD_LOCK && lock_status != DRX_LOCKED) {
+ p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ } else {
+ rc = get_vsb_post_rs_pck_err(dev_addr, &err, &pkt);
+ if (rc != 0) {
+ pr_err("error %d getting UCB\n", rc);
+ p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ } else {
+ p->block_error.stat[0].scale = FE_SCALE_COUNTER;
+ p->block_error.stat[0].uvalue += err;
+ p->block_count.stat[0].scale = FE_SCALE_COUNTER;
+ p->block_count.stat[0].uvalue += pkt;
+ }
+
+ /* PostViterbi is compute in steps of 10^(-6) */
+ rc = get_vs_bpre_viterbi_ber(dev_addr, &ber, &cnt);
+ if (rc != 0) {
+ pr_err("error %d getting pre-ber\n", rc);
+ p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ } else {
+ p->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ p->pre_bit_error.stat[0].uvalue += ber;
+ p->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ p->pre_bit_count.stat[0].uvalue += cnt;
+ }
+
+ rc = get_vs_bpost_viterbi_ber(dev_addr, &ber, &cnt);
+ if (rc != 0) {
+ pr_err("error %d getting post-ber\n", rc);
+ p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ } else {
+ p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ p->post_bit_error.stat[0].uvalue += ber;
+ p->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ p->post_bit_count.stat[0].uvalue += cnt;
+ }
+ rc = get_vsbmer(dev_addr, &mer);
+ if (rc != 0) {
+ pr_err("error %d getting MER\n", rc);
+ p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ } else {
+ p->cnr.stat[0].svalue = mer * 100;
+ p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+ }
+ }
+ break;
+#ifndef DRXJ_VSB_ONLY
+ case DRX_STANDARD_ITU_A:
+ case DRX_STANDARD_ITU_B:
+ case DRX_STANDARD_ITU_C:
+ rc = ctrl_get_qam_sig_quality(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+#endif
+ default:
+ return -EIO;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*============================================================================*/
+
+/**
+* \fn int ctrl_lock_status()
+* \brief Retreive lock status .
+* \param dev_addr Pointer to demodulator device address.
+* \param lock_stat Pointer to lock status structure.
+* \return int.
+*
+*/
+static int
+ctrl_lock_status(struct drx_demod_instance *demod, enum drx_lock_status *lock_stat)
+{
+ enum drx_standard standard = DRX_STANDARD_UNKNOWN;
+ struct drxj_data *ext_attr = NULL;
+ struct i2c_device_addr *dev_addr = NULL;
+ struct drxjscu_cmd cmd_scu = { /* command */ 0,
+ /* parameter_len */ 0,
+ /* result_len */ 0,
+ /* *parameter */ NULL,
+ /* *result */ NULL
+ };
+ int rc;
+ u16 cmd_result[2] = { 0, 0 };
+ u16 demod_lock = SCU_RAM_PARAM_1_RES_DEMOD_GET_LOCK_DEMOD_LOCKED;
+
+ /* check arguments */
+ if ((demod == NULL) || (lock_stat == NULL))
+ return -EINVAL;
+
+ dev_addr = demod->my_i2c_dev_addr;
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+ standard = ext_attr->standard;
+
+ *lock_stat = DRX_NOT_LOCKED;
+
+ /* define the SCU command code */
+ switch (standard) {
+ case DRX_STANDARD_8VSB:
+ cmd_scu.command = SCU_RAM_COMMAND_STANDARD_VSB |
+ SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK;
+ demod_lock |= 0x6;
+ break;
+#ifndef DRXJ_VSB_ONLY
+ case DRX_STANDARD_ITU_A:
+ case DRX_STANDARD_ITU_B:
+ case DRX_STANDARD_ITU_C:
+ cmd_scu.command = SCU_RAM_COMMAND_STANDARD_QAM |
+ SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK;
+ break;
+#endif
+ case DRX_STANDARD_UNKNOWN: /* fallthrough */
+ default:
+ return -EIO;
+ }
+
+ /* define the SCU command paramters and execute the command */
+ cmd_scu.parameter_len = 0;
+ cmd_scu.result_len = 2;
+ cmd_scu.parameter = NULL;
+ cmd_scu.result = cmd_result;
+ rc = scu_command(dev_addr, &cmd_scu);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* set the lock status */
+ if (cmd_scu.result[1] < demod_lock) {
+ /* 0x0000 NOT LOCKED */
+ *lock_stat = DRX_NOT_LOCKED;
+ } else if (cmd_scu.result[1] < SCU_RAM_PARAM_1_RES_DEMOD_GET_LOCK_LOCKED) {
+ *lock_stat = DRXJ_DEMOD_LOCK;
+ } else if (cmd_scu.result[1] <
+ SCU_RAM_PARAM_1_RES_DEMOD_GET_LOCK_NEVER_LOCK) {
+ /* 0x8000 DEMOD + FEC LOCKED (system lock) */
+ *lock_stat = DRX_LOCKED;
+ } else {
+ /* 0xC000 NEVER LOCKED */
+ /* (system will never be able to lock to the signal) */
+ *lock_stat = DRX_NEVER_LOCK;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*============================================================================*/
+
+/**
+* \fn int ctrl_set_standard()
+* \brief Set modulation standard to be used.
+* \param standard Modulation standard.
+* \return int.
+*
+* Setup stuff for the desired demodulation standard.
+* Disable and power down the previous selected demodulation standard
+*
+*/
+static int
+ctrl_set_standard(struct drx_demod_instance *demod, enum drx_standard *standard)
+{
+ struct drxj_data *ext_attr = NULL;
+ int rc;
+ enum drx_standard prev_standard;
+
+ /* check arguments */
+ if ((standard == NULL) || (demod == NULL))
+ return -EINVAL;
+
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+ prev_standard = ext_attr->standard;
+
+ /*
+ Stop and power down previous standard
+ */
+ switch (prev_standard) {
+#ifndef DRXJ_VSB_ONLY
+ case DRX_STANDARD_ITU_A: /* fallthrough */
+ case DRX_STANDARD_ITU_B: /* fallthrough */
+ case DRX_STANDARD_ITU_C:
+ rc = power_down_qam(demod, false);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+#endif
+ case DRX_STANDARD_8VSB:
+ rc = power_down_vsb(demod, false);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ case DRX_STANDARD_UNKNOWN:
+ /* Do nothing */
+ break;
+ case DRX_STANDARD_AUTO: /* fallthrough */
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ Initialize channel independent registers
+ Power up new standard
+ */
+ ext_attr->standard = *standard;
+
+ switch (*standard) {
+#ifndef DRXJ_VSB_ONLY
+ case DRX_STANDARD_ITU_A: /* fallthrough */
+ case DRX_STANDARD_ITU_B: /* fallthrough */
+ case DRX_STANDARD_ITU_C:
+ do {
+ u16 dummy;
+ rc = drxj_dap_read_reg16(demod->my_i2c_dev_addr, SCU_RAM_VERSION_HI__A, &dummy, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ } while (0);
+ break;
+#endif
+ case DRX_STANDARD_8VSB:
+ rc = set_vsb_leak_n_gain(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ default:
+ ext_attr->standard = DRX_STANDARD_UNKNOWN;
+ return -EINVAL;
+ break;
+ }
+
+ return 0;
+rw_error:
+ /* Don't know what the standard is now ... try again */
+ ext_attr->standard = DRX_STANDARD_UNKNOWN;
+ return -EIO;
+}
+
+/*============================================================================*/
+
+static void drxj_reset_mode(struct drxj_data *ext_attr)
+{
+ /* Initialize default AFE configuartion for QAM */
+ if (ext_attr->has_lna) {
+ /* IF AGC off, PGA active */
+#ifndef DRXJ_VSB_ONLY
+ ext_attr->qam_if_agc_cfg.standard = DRX_STANDARD_ITU_B;
+ ext_attr->qam_if_agc_cfg.ctrl_mode = DRX_AGC_CTRL_OFF;
+ ext_attr->qam_pga_cfg = 140 + (11 * 13);
+#endif
+ ext_attr->vsb_if_agc_cfg.standard = DRX_STANDARD_8VSB;
+ ext_attr->vsb_if_agc_cfg.ctrl_mode = DRX_AGC_CTRL_OFF;
+ ext_attr->vsb_pga_cfg = 140 + (11 * 13);
+ } else {
+ /* IF AGC on, PGA not active */
+#ifndef DRXJ_VSB_ONLY
+ ext_attr->qam_if_agc_cfg.standard = DRX_STANDARD_ITU_B;
+ ext_attr->qam_if_agc_cfg.ctrl_mode = DRX_AGC_CTRL_AUTO;
+ ext_attr->qam_if_agc_cfg.min_output_level = 0;
+ ext_attr->qam_if_agc_cfg.max_output_level = 0x7FFF;
+ ext_attr->qam_if_agc_cfg.speed = 3;
+ ext_attr->qam_if_agc_cfg.top = 1297;
+ ext_attr->qam_pga_cfg = 140;
+#endif
+ ext_attr->vsb_if_agc_cfg.standard = DRX_STANDARD_8VSB;
+ ext_attr->vsb_if_agc_cfg.ctrl_mode = DRX_AGC_CTRL_AUTO;
+ ext_attr->vsb_if_agc_cfg.min_output_level = 0;
+ ext_attr->vsb_if_agc_cfg.max_output_level = 0x7FFF;
+ ext_attr->vsb_if_agc_cfg.speed = 3;
+ ext_attr->vsb_if_agc_cfg.top = 1024;
+ ext_attr->vsb_pga_cfg = 140;
+ }
+ /* TODO: remove min_output_level and max_output_level for both QAM and VSB after */
+ /* mc has not used them */
+#ifndef DRXJ_VSB_ONLY
+ ext_attr->qam_rf_agc_cfg.standard = DRX_STANDARD_ITU_B;
+ ext_attr->qam_rf_agc_cfg.ctrl_mode = DRX_AGC_CTRL_AUTO;
+ ext_attr->qam_rf_agc_cfg.min_output_level = 0;
+ ext_attr->qam_rf_agc_cfg.max_output_level = 0x7FFF;
+ ext_attr->qam_rf_agc_cfg.speed = 3;
+ ext_attr->qam_rf_agc_cfg.top = 9500;
+ ext_attr->qam_rf_agc_cfg.cut_off_current = 4000;
+ ext_attr->qam_pre_saw_cfg.standard = DRX_STANDARD_ITU_B;
+ ext_attr->qam_pre_saw_cfg.reference = 0x07;
+ ext_attr->qam_pre_saw_cfg.use_pre_saw = true;
+#endif
+ /* Initialize default AFE configuartion for VSB */
+ ext_attr->vsb_rf_agc_cfg.standard = DRX_STANDARD_8VSB;
+ ext_attr->vsb_rf_agc_cfg.ctrl_mode = DRX_AGC_CTRL_AUTO;
+ ext_attr->vsb_rf_agc_cfg.min_output_level = 0;
+ ext_attr->vsb_rf_agc_cfg.max_output_level = 0x7FFF;
+ ext_attr->vsb_rf_agc_cfg.speed = 3;
+ ext_attr->vsb_rf_agc_cfg.top = 9500;
+ ext_attr->vsb_rf_agc_cfg.cut_off_current = 4000;
+ ext_attr->vsb_pre_saw_cfg.standard = DRX_STANDARD_8VSB;
+ ext_attr->vsb_pre_saw_cfg.reference = 0x07;
+ ext_attr->vsb_pre_saw_cfg.use_pre_saw = true;
+}
+
+/**
+* \fn int ctrl_power_mode()
+* \brief Set the power mode of the device to the specified power mode
+* \param demod Pointer to demodulator instance.
+* \param mode Pointer to new power mode.
+* \return int.
+* \retval 0 Success
+* \retval -EIO I2C error or other failure
+* \retval -EINVAL Invalid mode argument.
+*
+*
+*/
+static int
+ctrl_power_mode(struct drx_demod_instance *demod, enum drx_power_mode *mode)
+{
+ struct drx_common_attr *common_attr = (struct drx_common_attr *) NULL;
+ struct drxj_data *ext_attr = (struct drxj_data *) NULL;
+ struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)NULL;
+ int rc;
+ u16 sio_cc_pwd_mode = 0;
+
+ common_attr = (struct drx_common_attr *) demod->my_common_attr;
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+ dev_addr = demod->my_i2c_dev_addr;
+
+ /* Check arguments */
+ if (mode == NULL)
+ return -EINVAL;
+
+ /* If already in requested power mode, do nothing */
+ if (common_attr->current_power_mode == *mode)
+ return 0;
+
+ switch (*mode) {
+ case DRX_POWER_UP:
+ case DRXJ_POWER_DOWN_MAIN_PATH:
+ sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_NONE;
+ break;
+ case DRXJ_POWER_DOWN_CORE:
+ sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_CLOCK;
+ break;
+ case DRXJ_POWER_DOWN_PLL:
+ sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_PLL;
+ break;
+ case DRX_POWER_DOWN:
+ sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_OSC;
+ break;
+ default:
+ /* Unknow sleep mode */
+ return -EINVAL;
+ break;
+ }
+
+ /* Check if device needs to be powered up */
+ if ((common_attr->current_power_mode != DRX_POWER_UP)) {
+ rc = power_up_device(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ if ((*mode == DRX_POWER_UP)) {
+ /* Restore analog & pin configuartion */
+
+ /* Initialize default AFE configuartion for VSB */
+ drxj_reset_mode(ext_attr);
+ } else {
+ /* Power down to requested mode */
+ /* Backup some register settings */
+ /* Set pins with possible pull-ups connected to them in input mode */
+ /* Analog power down */
+ /* ADC power down */
+ /* Power down device */
+ /* stop all comm_exec */
+ /*
+ Stop and power down previous standard
+ */
+
+ switch (ext_attr->standard) {
+ case DRX_STANDARD_ITU_A:
+ case DRX_STANDARD_ITU_B:
+ case DRX_STANDARD_ITU_C:
+ rc = power_down_qam(demod, true);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ case DRX_STANDARD_8VSB:
+ rc = power_down_vsb(demod, true);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ case DRX_STANDARD_PAL_SECAM_BG: /* fallthrough */
+ case DRX_STANDARD_PAL_SECAM_DK: /* fallthrough */
+ case DRX_STANDARD_PAL_SECAM_I: /* fallthrough */
+ case DRX_STANDARD_PAL_SECAM_L: /* fallthrough */
+ case DRX_STANDARD_PAL_SECAM_LP: /* fallthrough */
+ case DRX_STANDARD_NTSC: /* fallthrough */
+ case DRX_STANDARD_FM:
+ rc = power_down_atv(demod, ext_attr->standard, true);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ break;
+ case DRX_STANDARD_UNKNOWN:
+ /* Do nothing */
+ break;
+ case DRX_STANDARD_AUTO: /* fallthrough */
+ default:
+ return -EIO;
+ }
+ ext_attr->standard = DRX_STANDARD_UNKNOWN;
+ }
+
+ if (*mode != DRXJ_POWER_DOWN_MAIN_PATH) {
+ rc = drxj_dap_write_reg16(dev_addr, SIO_CC_PWD_MODE__A, sio_cc_pwd_mode, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ if ((*mode != DRX_POWER_UP)) {
+ /* Initialize HI, wakeup key especially before put IC to sleep */
+ rc = init_hi(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ ext_attr->hi_cfg_ctrl |= SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
+ rc = hi_cfg_command(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+ }
+
+ common_attr->current_power_mode = *mode;
+
+ return 0;
+rw_error:
+ return rc;
+}
+
+/*============================================================================*/
+/*== CTRL Set/Get Config related functions ===================================*/
+/*============================================================================*/
+
+/**
+* \fn int ctrl_set_cfg_pre_saw()
+* \brief Set Pre-saw reference.
+* \param demod demod instance
+* \param u16 *
+* \return int.
+*
+* Check arguments
+* Dispatch handling to standard specific function.
+*
+*/
+static int
+ctrl_set_cfg_pre_saw(struct drx_demod_instance *demod, struct drxj_cfg_pre_saw *pre_saw)
+{
+ struct i2c_device_addr *dev_addr = NULL;
+ struct drxj_data *ext_attr = NULL;
+ int rc;
+
+ dev_addr = demod->my_i2c_dev_addr;
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+
+ /* check arguments */
+ if ((pre_saw == NULL) || (pre_saw->reference > IQM_AF_PDREF__M)
+ ) {
+ return -EINVAL;
+ }
+
+ /* Only if standard is currently active */
+ if ((ext_attr->standard == pre_saw->standard) ||
+ (DRXJ_ISQAMSTD(ext_attr->standard) &&
+ DRXJ_ISQAMSTD(pre_saw->standard)) ||
+ (DRXJ_ISATVSTD(ext_attr->standard) &&
+ DRXJ_ISATVSTD(pre_saw->standard))) {
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_PDREF__A, pre_saw->reference, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ /* Store pre-saw settings */
+ switch (pre_saw->standard) {
+ case DRX_STANDARD_8VSB:
+ ext_attr->vsb_pre_saw_cfg = *pre_saw;
+ break;
+#ifndef DRXJ_VSB_ONLY
+ case DRX_STANDARD_ITU_A: /* fallthrough */
+ case DRX_STANDARD_ITU_B: /* fallthrough */
+ case DRX_STANDARD_ITU_C:
+ ext_attr->qam_pre_saw_cfg = *pre_saw;
+ break;
+#endif
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*============================================================================*/
+
+/**
+* \fn int ctrl_set_cfg_afe_gain()
+* \brief Set AFE Gain.
+* \param demod demod instance
+* \param u16 *
+* \return int.
+*
+* Check arguments
+* Dispatch handling to standard specific function.
+*
+*/
+static int
+ctrl_set_cfg_afe_gain(struct drx_demod_instance *demod, struct drxj_cfg_afe_gain *afe_gain)
+{
+ struct i2c_device_addr *dev_addr = NULL;
+ struct drxj_data *ext_attr = NULL;
+ int rc;
+ u8 gain = 0;
+
+ /* check arguments */
+ if (afe_gain == NULL)
+ return -EINVAL;
+
+ dev_addr = demod->my_i2c_dev_addr;
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+
+ switch (afe_gain->standard) {
+ case DRX_STANDARD_8VSB: /* fallthrough */
+#ifndef DRXJ_VSB_ONLY
+ case DRX_STANDARD_ITU_A: /* fallthrough */
+ case DRX_STANDARD_ITU_B: /* fallthrough */
+ case DRX_STANDARD_ITU_C:
+#endif
+ /* Do nothing */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* TODO PGA gain is also written by microcode (at least by QAM and VSB)
+ So I (PJ) think interface requires choice between auto, user mode */
+
+ if (afe_gain->gain >= 329)
+ gain = 15;
+ else if (afe_gain->gain <= 147)
+ gain = 0;
+ else
+ gain = (afe_gain->gain - 140 + 6) / 13;
+
+ /* Only if standard is currently active */
+ if (ext_attr->standard == afe_gain->standard) {
+ rc = drxj_dap_write_reg16(dev_addr, IQM_AF_PGA_GAIN__A, gain, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ }
+
+ /* Store AFE Gain settings */
+ switch (afe_gain->standard) {
+ case DRX_STANDARD_8VSB:
+ ext_attr->vsb_pga_cfg = gain * 13 + 140;
+ break;
+#ifndef DRXJ_VSB_ONLY
+ case DRX_STANDARD_ITU_A: /* fallthrough */
+ case DRX_STANDARD_ITU_B: /* fallthrough */
+ case DRX_STANDARD_ITU_C:
+ ext_attr->qam_pga_cfg = gain * 13 + 140;
+ break;
+#endif
+ default:
+ return -EIO;
+ }
+
+ return 0;
+rw_error:
+ return -EIO;
+}
+
+/*============================================================================*/
+
+
+/*=============================================================================
+===== EXPORTED FUNCTIONS ====================================================*/
+
+static int drx_ctrl_u_code(struct drx_demod_instance *demod,
+ struct drxu_code_info *mc_info,
+ enum drxu_code_action action);
+
+/**
+* \fn drxj_open()
+* \brief Open the demod instance, configure device, configure drxdriver
+* \return Status_t Return status.
+*
+* drxj_open() can be called with a NULL ucode image => no ucode upload.
+* This means that drxj_open() must NOT contain SCU commands or, in general,
+* rely on SCU or AUD ucode to be present.
+*
+*/
+
+static int drxj_open(struct drx_demod_instance *demod)
+{
+ struct i2c_device_addr *dev_addr = NULL;
+ struct drxj_data *ext_attr = NULL;
+ struct drx_common_attr *common_attr = NULL;
+ u32 driver_version = 0;
+ struct drxu_code_info ucode_info;
+ struct drx_cfg_mpeg_output cfg_mpeg_output;
+ int rc;
+ enum drx_power_mode power_mode = DRX_POWER_UP;
+
+ if ((demod == NULL) ||
+ (demod->my_common_attr == NULL) ||
+ (demod->my_ext_attr == NULL) ||
+ (demod->my_i2c_dev_addr == NULL) ||
+ (demod->my_common_attr->is_opened)) {
+ return -EINVAL;
+ }
+
+ /* Check arguments */
+ if (demod->my_ext_attr == NULL)
+ return -EINVAL;
+
+ dev_addr = demod->my_i2c_dev_addr;
+ ext_attr = (struct drxj_data *) demod->my_ext_attr;
+ common_attr = (struct drx_common_attr *) demod->my_common_attr;
+
+ rc = ctrl_power_mode(demod, &power_mode);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ if (power_mode != DRX_POWER_UP) {
+ rc = -EINVAL;
+ pr_err("failed to powerup device\n");
+ goto rw_error;
+ }
+
+ /* has to be in front of setIqmAf and setOrxNsuAox */
+ rc = get_device_capabilities(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /*
+ * Soft reset of sys- and osc-clockdomain
+ *
+ * HACK: On windows, it writes a 0x07 here, instead of just 0x03.
+ * As we didn't load the firmware here yet, we should do the same.
+ * Btw, this is coherent with DRX-K, where we send reset codes
+ * for modulation (OFTM, in DRX-k), SYS and OSC clock domains.
+ */
+ rc = drxj_dap_write_reg16(dev_addr, SIO_CC_SOFT_RST__A, (0x04 | SIO_CC_SOFT_RST_SYS__M | SIO_CC_SOFT_RST_OSC__M), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ msleep(1);
+
+ /* TODO first make sure that everything keeps working before enabling this */
+ /* PowerDownAnalogBlocks() */
+ rc = drxj_dap_write_reg16(dev_addr, ATV_TOP_STDBY__A, (~ATV_TOP_STDBY_CVBS_STDBY_A2_ACTIVE) | ATV_TOP_STDBY_SIF_STDBY_STANDBY, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = set_iqm_af(demod, false);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = set_orx_nsu_aox(demod, false);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = init_hi(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* disable mpegoutput pins */
+ memcpy(&cfg_mpeg_output, &common_attr->mpeg_cfg, sizeof(cfg_mpeg_output));
+ cfg_mpeg_output.enable_mpeg_output = false;
+
+ rc = ctrl_set_cfg_mpeg_output(demod, &cfg_mpeg_output);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* Stop AUD Inform SetAudio it will need to do all setting */
+ rc = power_down_aud(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ /* Stop SCU */
+ rc = drxj_dap_write_reg16(dev_addr, SCU_COMM_EXEC__A, SCU_COMM_EXEC_STOP, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Upload microcode */
+ if (common_attr->microcode_file != NULL) {
+ /* Dirty trick to use common ucode upload & verify,
+ pretend device is already open */
+ common_attr->is_opened = true;
+ ucode_info.mc_file = common_attr->microcode_file;
+
+ if (DRX_ISPOWERDOWNMODE(demod->my_common_attr->current_power_mode)) {
+ pr_err("Should powerup before loading the firmware.");
+ return -EINVAL;
+ }
+
+ rc = drx_ctrl_u_code(demod, &ucode_info, UCODE_UPLOAD);
+ if (rc != 0) {
+ pr_err("error %d while uploading the firmware\n", rc);
+ goto rw_error;
+ }
+ if (common_attr->verify_microcode == true) {
+ rc = drx_ctrl_u_code(demod, &ucode_info, UCODE_VERIFY);
+ if (rc != 0) {
+ pr_err("error %d while verifying the firmware\n",
+ rc);
+ goto rw_error;
+ }
+ }
+ common_attr->is_opened = false;
+ }
+
+ /* Run SCU for a little while to initialize microcode version numbers */
+ rc = drxj_dap_write_reg16(dev_addr, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Initialize scan timeout */
+ common_attr->scan_demod_lock_timeout = DRXJ_SCAN_TIMEOUT;
+ common_attr->scan_desired_lock = DRX_LOCKED;
+
+ drxj_reset_mode(ext_attr);
+ ext_attr->standard = DRX_STANDARD_UNKNOWN;
+
+ rc = smart_ant_init(demod);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* Stamp driver version number in SCU data RAM in BCD code
+ Done to enable field application engineers to retreive drxdriver version
+ via I2C from SCU RAM
+ */
+ driver_version = (VERSION_MAJOR / 100) % 10;
+ driver_version <<= 4;
+ driver_version += (VERSION_MAJOR / 10) % 10;
+ driver_version <<= 4;
+ driver_version += (VERSION_MAJOR % 10);
+ driver_version <<= 4;
+ driver_version += (VERSION_MINOR % 10);
+ driver_version <<= 4;
+ driver_version += (VERSION_PATCH / 1000) % 10;
+ driver_version <<= 4;
+ driver_version += (VERSION_PATCH / 100) % 10;
+ driver_version <<= 4;
+ driver_version += (VERSION_PATCH / 10) % 10;
+ driver_version <<= 4;
+ driver_version += (VERSION_PATCH % 10);
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_DRIVER_VER_HI__A, (u16)(driver_version >> 16), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_DRIVER_VER_LO__A, (u16)(driver_version & 0xFFFF), 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = ctrl_set_oob(demod, NULL);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ /* refresh the audio data structure with default */
+ ext_attr->aud_data = drxj_default_aud_data_g;
+
+ demod->my_common_attr->is_opened = true;
+ return 0;
+rw_error:
+ common_attr->is_opened = false;
+ return -EIO;
+}
+
+/*============================================================================*/
+/**
+* \fn drxj_close()
+* \brief Close the demod instance, power down the device
+* \return Status_t Return status.
+*
+*/
+static int drxj_close(struct drx_demod_instance *demod)
+{
+ struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
+ int rc;
+ enum drx_power_mode power_mode = DRX_POWER_UP;
+
+ if ((demod->my_common_attr == NULL) ||
+ (demod->my_ext_attr == NULL) ||
+ (demod->my_i2c_dev_addr == NULL) ||
+ (!demod->my_common_attr->is_opened)) {
+ return -EINVAL;
+ }
+
+ /* power up */
+ rc = ctrl_power_mode(demod, &power_mode);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ rc = drxj_dap_write_reg16(dev_addr, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE, 0);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+ power_mode = DRX_POWER_DOWN;
+ rc = ctrl_power_mode(demod, &power_mode);
+ if (rc != 0) {
+ pr_err("error %d\n", rc);
+ goto rw_error;
+ }
+
+ DRX_ATTR_ISOPENED(demod) = false;
+
+ return 0;
+rw_error:
+ DRX_ATTR_ISOPENED(demod) = false;
+
+ return -EIO;
+}
+
+/*
+ * Microcode related functions
+ */
+
+/**
+ * drx_u_code_compute_crc - Compute CRC of block of microcode data.
+ * @block_data: Pointer to microcode data.
+ * @nr_words: Size of microcode block (number of 16 bits words).
+ *
+ * returns The computed CRC residue.
+ */
+static u16 drx_u_code_compute_crc(u8 *block_data, u16 nr_words)
+{
+ u16 i = 0;
+ u16 j = 0;
+ u32 crc_word = 0;
+ u32 carry = 0;
+
+ while (i < nr_words) {
+ crc_word |= (u32)be16_to_cpu(*(u32 *)(block_data));
+ for (j = 0; j < 16; j++) {
+ crc_word <<= 1;
+ if (carry != 0)
+ crc_word ^= 0x80050000UL;
+ carry = crc_word & 0x80000000UL;
+ }
+ i++;
+ block_data += (sizeof(u16));
+ }
+ return (u16)(crc_word >> 16);
+}
+
+/**
+ * drx_check_firmware - checks if the loaded firmware is valid
+ *
+ * @demod: demod structure
+ * @mc_data: pointer to the start of the firmware
+ * @size: firmware size
+ */
+static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data,
+ unsigned size)
+{
+ struct drxu_code_block_hdr block_hdr;
+ int i;
+ unsigned count = 2 * sizeof(u16);
+ u32 mc_dev_type, mc_version, mc_base_version;
+ u16 mc_nr_of_blks = be16_to_cpu(*(u32 *)(mc_data + sizeof(u16)));
+
+ /*
+ * Scan microcode blocks first for version info
+ * and firmware check
+ */
+
+ /* Clear version block */
+ DRX_ATTR_MCRECORD(demod).aux_type = 0;
+ DRX_ATTR_MCRECORD(demod).mc_dev_type = 0;
+ DRX_ATTR_MCRECORD(demod).mc_version = 0;
+ DRX_ATTR_MCRECORD(demod).mc_base_version = 0;
+
+ for (i = 0; i < mc_nr_of_blks; i++) {
+ if (count + 3 * sizeof(u16) + sizeof(u32) > size)
+ goto eof;
+
+ /* Process block header */
+ block_hdr.addr = be32_to_cpu(*(u32 *)(mc_data + count));
+ count += sizeof(u32);
+ block_hdr.size = be16_to_cpu(*(u32 *)(mc_data + count));
+ count += sizeof(u16);
+ block_hdr.flags = be16_to_cpu(*(u32 *)(mc_data + count));
+ count += sizeof(u16);
+ block_hdr.CRC = be16_to_cpu(*(u32 *)(mc_data + count));
+ count += sizeof(u16);
+
+ pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n",
+ count, block_hdr.addr, block_hdr.size, block_hdr.flags,
+ block_hdr.CRC);
+
+ if (block_hdr.flags & 0x8) {
+ u8 *auxblk = ((void *)mc_data) + block_hdr.addr;
+ u16 auxtype;
+
+ if (block_hdr.addr + sizeof(u16) > size)
+ goto eof;
+
+ auxtype = be16_to_cpu(*(u32 *)(auxblk));
+
+ /* Aux block. Check type */
+ if (DRX_ISMCVERTYPE(auxtype)) {
+ if (block_hdr.addr + 2 * sizeof(u16) + 2 * sizeof (u32) > size)
+ goto eof;
+
+ auxblk += sizeof(u16);
+ mc_dev_type = be32_to_cpu(*(u32 *)(auxblk));
+ auxblk += sizeof(u32);
+ mc_version = be32_to_cpu(*(u32 *)(auxblk));
+ auxblk += sizeof(u32);
+ mc_base_version = be32_to_cpu(*(u32 *)(auxblk));
+
+ DRX_ATTR_MCRECORD(demod).aux_type = auxtype;
+ DRX_ATTR_MCRECORD(demod).mc_dev_type = mc_dev_type;
+ DRX_ATTR_MCRECORD(demod).mc_version = mc_version;
+ DRX_ATTR_MCRECORD(demod).mc_base_version = mc_base_version;
+
+ pr_info("Firmware dev %x, ver %x, base ver %x\n",
+ mc_dev_type, mc_version, mc_base_version);
+
+ }
+ } else if (count + block_hdr.size * sizeof(u16) > size)
+ goto eof;
+
+ count += block_hdr.size * sizeof(u16);
+ }
+ return 0;
+eof:
+ pr_err("Firmware is truncated at pos %u/%u\n", count, size);
+ return -EINVAL;
+}
+
+/**
+ * drx_ctrl_u_code - Handle microcode upload or verify.
+ * @dev_addr: Address of device.
+ * @mc_info: Pointer to information about microcode data.
+ * @action: Either UCODE_UPLOAD or UCODE_VERIFY
+ *
+ * This function returns:
+ * 0:
+ * - In case of UCODE_UPLOAD: code is successfully uploaded.
+ * - In case of UCODE_VERIFY: image on device is equal to
+ * image provided to this control function.
+ * -EIO:
+ * - In case of UCODE_UPLOAD: I2C error.
+ * - In case of UCODE_VERIFY: I2C error or image on device
+ * is not equal to image provided to this control function.
+ * -EINVAL:
+ * - Invalid arguments.
+ * - Provided image is corrupt
+ */
+static int drx_ctrl_u_code(struct drx_demod_instance *demod,
+ struct drxu_code_info *mc_info,
+ enum drxu_code_action action)
+{
+ struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
+ int rc;
+ u16 i = 0;
+ u16 mc_nr_of_blks = 0;
+ u16 mc_magic_word = 0;
+ const u8 *mc_data_init = NULL;
+ u8 *mc_data = NULL;
+ unsigned size;
+ char *mc_file;
+
+ /* Check arguments */
+ if (!mc_info || !mc_info->mc_file)
+ return -EINVAL;
+
+ mc_file = mc_info->mc_file;
+
+ if (!demod->firmware) {
+ const struct firmware *fw = NULL;
+
+ rc = request_firmware(&fw, mc_file, demod->i2c->dev.parent);
+ if (rc < 0) {
+ pr_err("Couldn't read firmware %s\n", mc_file);
+ return rc;
+ }
+ demod->firmware = fw;
+
+ if (demod->firmware->size < 2 * sizeof(u16)) {
+ rc = -EINVAL;
+ pr_err("Firmware is too short!\n");
+ goto release;
+ }
+
+ pr_info("Firmware %s, size %zu\n",
+ mc_file, demod->firmware->size);
+ }
+
+ mc_data_init = demod->firmware->data;
+ size = demod->firmware->size;
+
+ mc_data = (void *)mc_data_init;
+ /* Check data */
+ mc_magic_word = be16_to_cpu(*(u32 *)(mc_data));
+ mc_data += sizeof(u16);
+ mc_nr_of_blks = be16_to_cpu(*(u32 *)(mc_data));
+ mc_data += sizeof(u16);
+
+ if ((mc_magic_word != DRX_UCODE_MAGIC_WORD) || (mc_nr_of_blks == 0)) {
+ rc = -EINVAL;
+ pr_err("Firmware magic word doesn't match\n");
+ goto release;
+ }
+
+ if (action == UCODE_UPLOAD) {
+ rc = drx_check_firmware(demod, (u8 *)mc_data_init, size);
+ if (rc)
+ goto release;
+ pr_info("Uploading firmware %s\n", mc_file);
+ } else {
+ pr_info("Verifying if firmware upload was ok.\n");
+ }
+
+ /* Process microcode blocks */
+ for (i = 0; i < mc_nr_of_blks; i++) {
+ struct drxu_code_block_hdr block_hdr;
+ u16 mc_block_nr_bytes = 0;
+
+ /* Process block header */
+ block_hdr.addr = be32_to_cpu(*(u32 *)(mc_data));
+ mc_data += sizeof(u32);
+ block_hdr.size = be16_to_cpu(*(u32 *)(mc_data));
+ mc_data += sizeof(u16);
+ block_hdr.flags = be16_to_cpu(*(u32 *)(mc_data));
+ mc_data += sizeof(u16);
+ block_hdr.CRC = be16_to_cpu(*(u32 *)(mc_data));
+ mc_data += sizeof(u16);
+
+ pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n",
+ (unsigned)(mc_data - mc_data_init), block_hdr.addr,
+ block_hdr.size, block_hdr.flags, block_hdr.CRC);
+
+ /* Check block header on:
+ - data larger than 64Kb
+ - if CRC enabled check CRC
+ */
+ if ((block_hdr.size > 0x7FFF) ||
+ (((block_hdr.flags & DRX_UCODE_CRC_FLAG) != 0) &&
+ (block_hdr.CRC != drx_u_code_compute_crc(mc_data, block_hdr.size)))
+ ) {
+ /* Wrong data ! */
+ rc = -EINVAL;
+ pr_err("firmware CRC is wrong\n");
+ goto release;
+ }
+
+ if (!block_hdr.size)
+ continue;
+
+ mc_block_nr_bytes = block_hdr.size * ((u16) sizeof(u16));
+
+ /* Perform the desired action */
+ switch (action) {
+ case UCODE_UPLOAD: /* Upload microcode */
+ if (drxdap_fasi_write_block(dev_addr,
+ block_hdr.addr,
+ mc_block_nr_bytes,
+ mc_data, 0x0000)) {
+ rc = -EIO;
+ pr_err("error writing firmware at pos %u\n",
+ (unsigned)(mc_data - mc_data_init));
+ goto release;
+ }
+ break;
+ case UCODE_VERIFY: { /* Verify uploaded microcode */
+ int result = 0;
+ u8 mc_data_buffer[DRX_UCODE_MAX_BUF_SIZE];
+ u32 bytes_to_comp = 0;
+ u32 bytes_left = mc_block_nr_bytes;
+ u32 curr_addr = block_hdr.addr;
+ u8 *curr_ptr = mc_data;
+
+ while (bytes_left != 0) {
+ if (bytes_left > DRX_UCODE_MAX_BUF_SIZE)
+ bytes_to_comp = DRX_UCODE_MAX_BUF_SIZE;
+ else
+ bytes_to_comp = bytes_left;
+
+ if (drxdap_fasi_read_block(dev_addr,
+ curr_addr,
+ (u16)bytes_to_comp,
+ (u8 *)mc_data_buffer,
+ 0x0000)) {
+ pr_err("error reading firmware at pos %u\n",
+ (unsigned)(mc_data - mc_data_init));
+ return -EIO;
+ }
+
+ result = memcmp(curr_ptr, mc_data_buffer,
+ bytes_to_comp);
+
+ if (result) {
+ pr_err("error verifying firmware at pos %u\n",
+ (unsigned)(mc_data - mc_data_init));
+ return -EIO;
+ }
+
+ curr_addr += ((dr_xaddr_t)(bytes_to_comp / 2));
+ curr_ptr =&(curr_ptr[bytes_to_comp]);
+ bytes_left -=((u32) bytes_to_comp);
+ }
+ break;
+ }
+ default:
+ return -EINVAL;
+ break;
+
+ }
+ mc_data += mc_block_nr_bytes;
+ }
+
+ return 0;
+
+release:
+ release_firmware(demod->firmware);
+ demod->firmware = NULL;
+
+ return rc;
+}
+
+/*
+ * The Linux DVB Driver for Micronas DRX39xx family (drx3933j)
+ *
+ * Written by Devin Heitmueller <devin.heitmueller@kernellabs.com>
+ */
+
+static int drx39xxj_set_powerstate(struct dvb_frontend *fe, int enable)
+{
+ struct drx39xxj_state *state = fe->demodulator_priv;
+ struct drx_demod_instance *demod = state->demod;
+ int result;
+ enum drx_power_mode power_mode;
+
+ if (enable)
+ power_mode = DRX_POWER_UP;
+ else
+ power_mode = DRX_POWER_DOWN;
+
+ result = ctrl_power_mode(demod, &power_mode);
+ if (result != 0) {
+ pr_err("Power state change failed\n");
+ return 0;
+ }
+
+ return 0;
+}
+
+static int drx39xxj_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct drx39xxj_state *state = fe->demodulator_priv;
+ struct drx_demod_instance *demod = state->demod;
+ int result;
+ enum drx_lock_status lock_status;
+
+ *status = 0;
+
+ result = ctrl_lock_status(demod, &lock_status);
+ if (result != 0) {
+ pr_err("drx39xxj: could not get lock status!\n");
+ *status = 0;
+ }
+
+ switch (lock_status) {
+ case DRX_NEVER_LOCK:
+ *status = 0;
+ pr_err("drx says NEVER_LOCK\n");
+ break;
+ case DRX_NOT_LOCKED:
+ *status = 0;
+ break;
+ case DRX_LOCK_STATE_1:
+ case DRX_LOCK_STATE_2:
+ case DRX_LOCK_STATE_3:
+ case DRX_LOCK_STATE_4:
+ case DRX_LOCK_STATE_5:
+ case DRX_LOCK_STATE_6:
+ case DRX_LOCK_STATE_7:
+ case DRX_LOCK_STATE_8:
+ case DRX_LOCK_STATE_9:
+ *status = FE_HAS_SIGNAL
+ | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC;
+ break;
+ case DRX_LOCKED:
+ *status = FE_HAS_SIGNAL
+ | FE_HAS_CARRIER
+ | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+ break;
+ default:
+ pr_err("Lock state unknown %d\n", lock_status);
+ }
+ ctrl_sig_quality(demod, lock_status);
+
+ return 0;
+}
+
+static int drx39xxj_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
+ if (p->pre_bit_error.stat[0].scale == FE_SCALE_NOT_AVAILABLE) {
+ *ber = 0;
+ return 0;
+ }
+
+ if (!p->pre_bit_count.stat[0].uvalue) {
+ if (!p->pre_bit_error.stat[0].uvalue)
+ *ber = 0;
+ else
+ *ber = 1000000;
+ } else {
+ *ber = frac_times1e6(p->pre_bit_error.stat[0].uvalue,
+ p->pre_bit_count.stat[0].uvalue);
+ }
+ return 0;
+}
+
+static int drx39xxj_read_signal_strength(struct dvb_frontend *fe,
+ u16 *strength)
+{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
+ if (p->strength.stat[0].scale == FE_SCALE_NOT_AVAILABLE) {
+ *strength = 0;
+ return 0;
+ }
+
+ *strength = p->strength.stat[0].uvalue;
+ return 0;
+}
+
+static int drx39xxj_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ u64 tmp64;
+
+ if (p->cnr.stat[0].scale == FE_SCALE_NOT_AVAILABLE) {
+ *snr = 0;
+ return 0;
+ }
+
+ tmp64 = p->cnr.stat[0].svalue;
+ do_div(tmp64, 10);
+ *snr = tmp64;
+ return 0;
+}
+
+static int drx39xxj_read_ucblocks(struct dvb_frontend *fe, u32 *ucb)
+{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
+ if (p->block_error.stat[0].scale == FE_SCALE_NOT_AVAILABLE) {
+ *ucb = 0;
+ return 0;
+ }
+
+ *ucb = p->block_error.stat[0].uvalue;
+ return 0;
+}
+
+static int drx39xxj_set_frontend(struct dvb_frontend *fe)
+{
+#ifdef DJH_DEBUG
+ int i;
+#endif
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ struct drx39xxj_state *state = fe->demodulator_priv;
+ struct drx_demod_instance *demod = state->demod;
+ enum drx_standard standard = DRX_STANDARD_8VSB;
+ struct drx_channel channel;
+ int result;
+ struct drxuio_data uio_data;
+ static const struct drx_channel def_channel = {
+ /* frequency */ 0,
+ /* bandwidth */ DRX_BANDWIDTH_6MHZ,
+ /* mirror */ DRX_MIRROR_NO,
+ /* constellation */ DRX_CONSTELLATION_AUTO,
+ /* hierarchy */ DRX_HIERARCHY_UNKNOWN,
+ /* priority */ DRX_PRIORITY_UNKNOWN,
+ /* coderate */ DRX_CODERATE_UNKNOWN,
+ /* guard */ DRX_GUARD_UNKNOWN,
+ /* fftmode */ DRX_FFTMODE_UNKNOWN,
+ /* classification */ DRX_CLASSIFICATION_AUTO,
+ /* symbolrate */ 5057000,
+ /* interleavemode */ DRX_INTERLEAVEMODE_UNKNOWN,
+ /* ldpc */ DRX_LDPC_UNKNOWN,
+ /* carrier */ DRX_CARRIER_UNKNOWN,
+ /* frame mode */ DRX_FRAMEMODE_UNKNOWN
+ };
+ u32 constellation = DRX_CONSTELLATION_AUTO;
+
+ /* Bring the demod out of sleep */
+ drx39xxj_set_powerstate(fe, 1);
+
+ if (fe->ops.tuner_ops.set_params) {
+ u32 int_freq;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ /* Set tuner to desired frequency and standard */
+ fe->ops.tuner_ops.set_params(fe);
+
+ /* Use the tuner's IF */
+ if (fe->ops.tuner_ops.get_if_frequency) {
+ fe->ops.tuner_ops.get_if_frequency(fe, &int_freq);
+ demod->my_common_attr->intermediate_freq = int_freq / 1000;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+ switch (p->delivery_system) {
+ case SYS_ATSC:
+ standard = DRX_STANDARD_8VSB;
+ break;
+ case SYS_DVBC_ANNEX_B:
+ standard = DRX_STANDARD_ITU_B;
+
+ switch (p->modulation) {
+ case QAM_64:
+ constellation = DRX_CONSTELLATION_QAM64;
+ break;
+ case QAM_256:
+ constellation = DRX_CONSTELLATION_QAM256;
+ break;
+ default:
+ constellation = DRX_CONSTELLATION_AUTO;
+ break;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ /* Set the standard (will be powered up if necessary */
+ result = ctrl_set_standard(demod, &standard);
+ if (result != 0) {
+ pr_err("Failed to set standard! result=%02x\n",
+ result);
+ return -EINVAL;
+ }
+
+ /* set channel parameters */
+ channel = def_channel;
+ channel.frequency = p->frequency / 1000;
+ channel.bandwidth = DRX_BANDWIDTH_6MHZ;
+ channel.constellation = constellation;
+
+ /* program channel */
+ result = ctrl_set_channel(demod, &channel);
+ if (result != 0) {
+ pr_err("Failed to set channel!\n");
+ return -EINVAL;
+ }
+ /* Just for giggles, let's shut off the LNA again.... */
+ uio_data.uio = DRX_UIO1;
+ uio_data.value = false;
+ result = ctrl_uio_write(demod, &uio_data);
+ if (result != 0) {
+ pr_err("Failed to disable LNA!\n");
+ return 0;
+ }
+
+ /* After set_frontend, except for strength, stats aren't available */
+ p->strength.stat[0].scale = FE_SCALE_RELATIVE;
+
+ return 0;
+}
+
+static int drx39xxj_sleep(struct dvb_frontend *fe)
+{
+ /* power-down the demodulator */
+ return drx39xxj_set_powerstate(fe, 0);
+}
+
+static int drx39xxj_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ struct drx39xxj_state *state = fe->demodulator_priv;
+ struct drx_demod_instance *demod = state->demod;
+ bool i2c_gate_state;
+ int result;
+
+#ifdef DJH_DEBUG
+ pr_debug("i2c gate call: enable=%d state=%d\n", enable,
+ state->i2c_gate_open);
+#endif
+
+ if (enable)
+ i2c_gate_state = true;
+ else
+ i2c_gate_state = false;
+
+ if (state->i2c_gate_open == enable) {
+ /* We're already in the desired state */
+ return 0;
+ }
+
+ result = ctrl_i2c_bridge(demod, &i2c_gate_state);
+ if (result != 0) {
+ pr_err("drx39xxj: could not open i2c gate [%d]\n",
+ result);
+ dump_stack();
+ } else {
+ state->i2c_gate_open = enable;
+ }
+ return 0;
+}
+
+static int drx39xxj_init(struct dvb_frontend *fe)
+{
+ /* Bring the demod out of sleep */
+ drx39xxj_set_powerstate(fe, 1);
+
+ return 0;
+}
+
+static int drx39xxj_set_lna(struct dvb_frontend *fe)
+{
+ int result;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct drx39xxj_state *state = fe->demodulator_priv;
+ struct drx_demod_instance *demod = state->demod;
+ struct drxj_data *ext_attr = demod->my_ext_attr;
+ struct drxuio_cfg uio_cfg;
+ struct drxuio_data uio_data;
+
+ if (c->lna) {
+ if (!ext_attr->has_lna) {
+ pr_err("LNA is not supported on this device!\n");
+ return -EINVAL;
+
+ }
+ }
+
+ /* Turn off the LNA */
+ uio_cfg.uio = DRX_UIO1;
+ uio_cfg.mode = DRX_UIO_MODE_READWRITE;
+ /* Configure user-I/O #3: enable read/write */
+ result = ctrl_set_uio_cfg(demod, &uio_cfg);
+ if (result) {
+ pr_err("Failed to setup LNA GPIO!\n");
+ return result;
+ }
+
+ uio_data.uio = DRX_UIO1;
+ uio_data.value = c->lna;
+ result = ctrl_uio_write(demod, &uio_data);
+ if (result != 0) {
+ pr_err("Failed to %sable LNA!\n",
+ c->lna ? "en" : "dis");
+ return result;
+ }
+
+ return 0;
+}
+
+static int drx39xxj_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *tune)
+{
+ tune->min_delay_ms = 1000;
+ return 0;
+}
+
+static void drx39xxj_release(struct dvb_frontend *fe)
+{
+ struct drx39xxj_state *state = fe->demodulator_priv;
+ struct drx_demod_instance *demod = state->demod;
+
+ drxj_close(demod);
+
+ kfree(demod->my_ext_attr);
+ kfree(demod->my_common_attr);
+ kfree(demod->my_i2c_dev_addr);
+ if (demod->firmware)
+ release_firmware(demod->firmware);
+ kfree(demod);
+ kfree(state);
+}
+
+static struct dvb_frontend_ops drx39xxj_ops;
+
+struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c)
+{
+ struct drx39xxj_state *state = NULL;
+ struct i2c_device_addr *demod_addr = NULL;
+ struct drx_common_attr *demod_comm_attr = NULL;
+ struct drxj_data *demod_ext_attr = NULL;
+ struct drx_demod_instance *demod = NULL;
+ struct dtv_frontend_properties *p;
+ struct drxuio_cfg uio_cfg;
+ struct drxuio_data uio_data;
+ int result;
+
+ /* allocate memory for the internal state */
+ state = kzalloc(sizeof(struct drx39xxj_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ demod = kmalloc(sizeof(struct drx_demod_instance), GFP_KERNEL);
+ if (demod == NULL)
+ goto error;
+
+ demod_addr = kmalloc(sizeof(struct i2c_device_addr), GFP_KERNEL);
+ if (demod_addr == NULL)
+ goto error;
+ memcpy(demod_addr, &drxj_default_addr_g,
+ sizeof(struct i2c_device_addr));
+
+ demod_comm_attr = kmalloc(sizeof(struct drx_common_attr), GFP_KERNEL);
+ if (demod_comm_attr == NULL)
+ goto error;
+ memcpy(demod_comm_attr, &drxj_default_comm_attr_g,
+ sizeof(struct drx_common_attr));
+
+ demod_ext_attr = kmalloc(sizeof(struct drxj_data), GFP_KERNEL);
+ if (demod_ext_attr == NULL)
+ goto error;
+ memcpy(demod_ext_attr, &drxj_data_g, sizeof(struct drxj_data));
+
+ /* setup the state */
+ state->i2c = i2c;
+ state->demod = demod;
+
+ /* setup the demod data */
+ memcpy(demod, &drxj_default_demod_g, sizeof(struct drx_demod_instance));
+
+ demod->my_i2c_dev_addr = demod_addr;
+ demod->my_common_attr = demod_comm_attr;
+ demod->my_i2c_dev_addr->user_data = state;
+ demod->my_common_attr->microcode_file = DRX39XX_MAIN_FIRMWARE;
+ demod->my_common_attr->verify_microcode = true;
+ demod->my_common_attr->intermediate_freq = 5000;
+ demod->my_common_attr->current_power_mode = DRX_POWER_DOWN;
+ demod->my_ext_attr = demod_ext_attr;
+ ((struct drxj_data *)demod_ext_attr)->uio_sma_tx_mode = DRX_UIO_MODE_READWRITE;
+ demod->i2c = i2c;
+
+ result = drxj_open(demod);
+ if (result != 0) {
+ pr_err("DRX open failed! Aborting\n");
+ goto error;
+ }
+
+ /* Turn off the LNA */
+ uio_cfg.uio = DRX_UIO1;
+ uio_cfg.mode = DRX_UIO_MODE_READWRITE;
+ /* Configure user-I/O #3: enable read/write */
+ result = ctrl_set_uio_cfg(demod, &uio_cfg);
+ if (result) {
+ pr_err("Failed to setup LNA GPIO!\n");
+ goto error;
+ }
+
+ uio_data.uio = DRX_UIO1;
+ uio_data.value = false;
+ result = ctrl_uio_write(demod, &uio_data);
+ if (result != 0) {
+ pr_err("Failed to disable LNA!\n");
+ goto error;
+ }
+
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &drx39xxj_ops,
+ sizeof(struct dvb_frontend_ops));
+
+ state->frontend.demodulator_priv = state;
+
+ /* Initialize stats - needed for DVBv5 stats to work */
+ p = &state->frontend.dtv_property_cache;
+ p->strength.len = 1;
+ p->pre_bit_count.len = 1;
+ p->pre_bit_error.len = 1;
+ p->post_bit_count.len = 1;
+ p->post_bit_error.len = 1;
+ p->block_count.len = 1;
+ p->block_error.len = 1;
+ p->cnr.len = 1;
+
+ p->strength.stat[0].scale = FE_SCALE_RELATIVE;
+ p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+ return &state->frontend;
+
+error:
+ kfree(demod_ext_attr);
+ kfree(demod_comm_attr);
+ kfree(demod_addr);
+ kfree(demod);
+ kfree(state);
+
+ return NULL;
+}
+EXPORT_SYMBOL(drx39xxj_attach);
+
+static struct dvb_frontend_ops drx39xxj_ops = {
+ .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
+ .info = {
+ .name = "Micronas DRX39xxj family Frontend",
+ .frequency_stepsize = 62500,
+ .frequency_min = 51000000,
+ .frequency_max = 858000000,
+ .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+ },
+
+ .init = drx39xxj_init,
+ .i2c_gate_ctrl = drx39xxj_i2c_gate_ctrl,
+ .sleep = drx39xxj_sleep,
+ .set_frontend = drx39xxj_set_frontend,
+ .get_tune_settings = drx39xxj_get_tune_settings,
+ .read_status = drx39xxj_read_status,
+ .read_ber = drx39xxj_read_ber,
+ .read_signal_strength = drx39xxj_read_signal_strength,
+ .read_snr = drx39xxj_read_snr,
+ .read_ucblocks = drx39xxj_read_ucblocks,
+ .release = drx39xxj_release,
+ .set_lna = drx39xxj_set_lna,
+};
+
+MODULE_DESCRIPTION("Micronas DRX39xxj Frontend");
+MODULE_AUTHOR("Devin Heitmueller");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(DRX39XX_MAIN_FIRMWARE);
diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.h b/drivers/media/dvb-frontends/drx39xyj/drxj.h
new file mode 100644
index 000000000000..55ad535197d2
--- /dev/null
+++ b/drivers/media/dvb-frontends/drx39xyj/drxj.h
@@ -0,0 +1,650 @@
+
+/*
+ Copyright (c), 2004-2005,2007-2010 Trident Microsystems, Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Trident Microsystems nor Hauppauge Computer Works
+ nor the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ 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 HOLDER 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.
+
+ DRXJ specific header file
+
+ Authors: Dragan Savic, Milos Nikolic, Mihajlo Katona, Tao Ding, Paul Janssen
+*/
+
+#ifndef __DRXJ_H__
+#define __DRXJ_H__
+/*-------------------------------------------------------------------------
+INCLUDES
+-------------------------------------------------------------------------*/
+
+#include "drx_driver.h"
+#include "drx_dap_fasi.h"
+
+/* Check DRX-J specific dap condition */
+/* Multi master mode and short addr format only will not work.
+ RMW, CRC reset, broadcast and switching back to single master mode
+ cannot be done with short addr only in multi master mode. */
+#if ((DRXDAP_SINGLE_MASTER == 0) && (DRXDAPFASI_LONG_ADDR_ALLOWED == 0))
+#error "Multi master mode and short addressing only is an illegal combination"
+ *; /* Generate a fatal compiler error to make sure it stops here,
+ this is necesarry because not all compilers stop after a #error. */
+#endif
+
+/*-------------------------------------------------------------------------
+TYPEDEFS
+-------------------------------------------------------------------------*/
+/*============================================================================*/
+/*============================================================================*/
+/*== code support ============================================================*/
+/*============================================================================*/
+/*============================================================================*/
+
+/*============================================================================*/
+/*============================================================================*/
+/*== SCU cmd if =============================================================*/
+/*============================================================================*/
+/*============================================================================*/
+
+ struct drxjscu_cmd {
+ u16 command;
+ /**< Command number */
+ u16 parameter_len;
+ /**< Data length in byte */
+ u16 result_len;
+ /**< result length in byte */
+ u16 *parameter;
+ /**< General purpous param */
+ u16 *result;
+ /**< General purpous param */};
+
+/*============================================================================*/
+/*============================================================================*/
+/*== CTRL CFG related data structures ========================================*/
+/*============================================================================*/
+/*============================================================================*/
+
+/* extra intermediate lock state for VSB,QAM,NTSC */
+#define DRXJ_DEMOD_LOCK (DRX_LOCK_STATE_1)
+
+/* OOB lock states */
+#define DRXJ_OOB_AGC_LOCK (DRX_LOCK_STATE_1) /* analog gain control lock */
+#define DRXJ_OOB_SYNC_LOCK (DRX_LOCK_STATE_2) /* digital gain control lock */
+
+/* Intermediate powermodes for DRXJ */
+#define DRXJ_POWER_DOWN_MAIN_PATH DRX_POWER_MODE_8
+#define DRXJ_POWER_DOWN_CORE DRX_POWER_MODE_9
+#define DRXJ_POWER_DOWN_PLL DRX_POWER_MODE_10
+
+/* supstition for GPIO FNC mux */
+#define APP_O (0x0000)
+
+/*#define DRX_CTRL_BASE (0x0000)*/
+
+#define DRXJ_CTRL_CFG_BASE (0x1000)
+ enum drxj_cfg_type {
+ DRXJ_CFG_AGC_RF = DRXJ_CTRL_CFG_BASE,
+ DRXJ_CFG_AGC_IF,
+ DRXJ_CFG_AGC_INTERNAL,
+ DRXJ_CFG_PRE_SAW,
+ DRXJ_CFG_AFE_GAIN,
+ DRXJ_CFG_SYMBOL_CLK_OFFSET,
+ DRXJ_CFG_ACCUM_CR_RS_CW_ERR,
+ DRXJ_CFG_FEC_MERS_SEQ_COUNT,
+ DRXJ_CFG_OOB_MISC,
+ DRXJ_CFG_SMART_ANT,
+ DRXJ_CFG_OOB_PRE_SAW,
+ DRXJ_CFG_VSB_MISC,
+ DRXJ_CFG_RESET_PACKET_ERR,
+
+ /* ATV (FM) */
+ DRXJ_CFG_ATV_OUTPUT, /* also for FM (SIF control) but not likely */
+ DRXJ_CFG_ATV_MISC,
+ DRXJ_CFG_ATV_EQU_COEF,
+ DRXJ_CFG_ATV_AGC_STATUS, /* also for FM ( IF,RF, audioAGC ) */
+
+ DRXJ_CFG_MPEG_OUTPUT_MISC,
+ DRXJ_CFG_HW_CFG,
+ DRXJ_CFG_OOB_LO_POW,
+
+ DRXJ_CFG_MAX /* dummy, never to be used */};
+
+/**
+* /struct enum drxj_cfg_smart_ant_io * smart antenna i/o.
+*/
+enum drxj_cfg_smart_ant_io {
+ DRXJ_SMT_ANT_OUTPUT = 0,
+ DRXJ_SMT_ANT_INPUT
+};
+
+/**
+* /struct struct drxj_cfg_smart_ant * Set smart antenna.
+*/
+ struct drxj_cfg_smart_ant {
+ enum drxj_cfg_smart_ant_io io;
+ u16 ctrl_data;
+ };
+
+/**
+* /struct DRXJAGCSTATUS_t
+* AGC status information from the DRXJ-IQM-AF.
+*/
+struct drxj_agc_status {
+ u16 IFAGC;
+ u16 RFAGC;
+ u16 digital_agc;
+};
+
+/* DRXJ_CFG_AGC_RF, DRXJ_CFG_AGC_IF */
+
+/**
+* /struct enum drxj_agc_ctrl_mode * Available AGCs modes in the DRXJ.
+*/
+ enum drxj_agc_ctrl_mode {
+ DRX_AGC_CTRL_AUTO = 0,
+ DRX_AGC_CTRL_USER,
+ DRX_AGC_CTRL_OFF};
+
+/**
+* /struct struct drxj_cfg_agc * Generic interface for all AGCs present on the DRXJ.
+*/
+ struct drxj_cfg_agc {
+ enum drx_standard standard; /* standard for which these settings apply */
+ enum drxj_agc_ctrl_mode ctrl_mode; /* off, user, auto */
+ u16 output_level; /* range dependent on AGC */
+ u16 min_output_level; /* range dependent on AGC */
+ u16 max_output_level; /* range dependent on AGC */
+ u16 speed; /* range dependent on AGC */
+ u16 top; /* rf-agc take over point */
+ u16 cut_off_current; /* rf-agc is accelerated if output current
+ is below cut-off current */};
+
+/* DRXJ_CFG_PRE_SAW */
+
+/**
+* /struct struct drxj_cfg_pre_saw * Interface to configure pre SAW sense.
+*/
+ struct drxj_cfg_pre_saw {
+ enum drx_standard standard; /* standard to which these settings apply */
+ u16 reference; /* pre SAW reference value, range 0 .. 31 */
+ bool use_pre_saw; /* true algorithms must use pre SAW sense */};
+
+/* DRXJ_CFG_AFE_GAIN */
+
+/**
+* /struct struct drxj_cfg_afe_gain * Interface to configure gain of AFE (LNA + PGA).
+*/
+ struct drxj_cfg_afe_gain {
+ enum drx_standard standard; /* standard to which these settings apply */
+ u16 gain; /* gain in 0.1 dB steps, DRXJ range 140 .. 335 */};
+
+/**
+* /struct drxjrs_errors
+* Available failure information in DRXJ_FEC_RS.
+*
+* Container for errors that are received in the most recently finished measurment period
+*
+*/
+ struct drxjrs_errors {
+ u16 nr_bit_errors;
+ /**< no of pre RS bit errors */
+ u16 nr_symbol_errors;
+ /**< no of pre RS symbol errors */
+ u16 nr_packet_errors;
+ /**< no of pre RS packet errors */
+ u16 nr_failures;
+ /**< no of post RS failures to decode */
+ u16 nr_snc_par_fail_count;
+ /**< no of post RS bit erros */
+ };
+
+/**
+* /struct struct drxj_cfg_vsb_misc * symbol error rate
+*/
+ struct drxj_cfg_vsb_misc {
+ u32 symb_error;
+ /**< symbol error rate sps */};
+
+/**
+* /enum enum drxj_mpeg_output_clock_rate * Mpeg output clock rate.
+*
+*/
+ enum drxj_mpeg_start_width {
+ DRXJ_MPEG_START_WIDTH_1CLKCYC,
+ DRXJ_MPEG_START_WIDTH_8CLKCYC};
+
+/**
+* /enum enum drxj_mpeg_output_clock_rate * Mpeg output clock rate.
+*
+*/
+ enum drxj_mpeg_output_clock_rate {
+ DRXJ_MPEGOUTPUT_CLOCK_RATE_AUTO,
+ DRXJ_MPEGOUTPUT_CLOCK_RATE_75973K,
+ DRXJ_MPEGOUTPUT_CLOCK_RATE_50625K,
+ DRXJ_MPEGOUTPUT_CLOCK_RATE_37968K,
+ DRXJ_MPEGOUTPUT_CLOCK_RATE_30375K,
+ DRXJ_MPEGOUTPUT_CLOCK_RATE_25313K,
+ DRXJ_MPEGOUTPUT_CLOCK_RATE_21696K};
+
+/**
+* /struct DRXJCfgMisc_t
+* Change TEI bit of MPEG output
+* reverse MPEG output bit order
+* set MPEG output clock rate
+*/
+ struct drxj_cfg_mpeg_output_misc {
+ bool disable_tei_handling; /**< if true pass (not change) TEI bit */
+ bool bit_reverse_mpeg_outout; /**< if true, parallel: msb on MD0; serial: lsb out first */
+ enum drxj_mpeg_output_clock_rate mpeg_output_clock_rate;
+ /**< set MPEG output clock rate that overwirtes the derived one from symbol rate */
+ enum drxj_mpeg_start_width mpeg_start_width; /**< set MPEG output start width */};
+
+/**
+* /enum enum drxj_xtal_freq * Supported external crystal reference frequency.
+*/
+ enum drxj_xtal_freq {
+ DRXJ_XTAL_FREQ_RSVD,
+ DRXJ_XTAL_FREQ_27MHZ,
+ DRXJ_XTAL_FREQ_20P25MHZ,
+ DRXJ_XTAL_FREQ_4MHZ};
+
+/**
+* /enum enum drxj_xtal_freq * Supported external crystal reference frequency.
+*/
+ enum drxji2c_speed {
+ DRXJ_I2C_SPEED_400KBPS,
+ DRXJ_I2C_SPEED_100KBPS};
+
+/**
+* /struct struct drxj_cfg_hw_cfg * Get hw configuration, such as crystal reference frequency, I2C speed, etc...
+*/
+ struct drxj_cfg_hw_cfg {
+ enum drxj_xtal_freq xtal_freq;
+ /**< crystal reference frequency */
+ enum drxji2c_speed i2c_speed;
+ /**< 100 or 400 kbps */};
+
+/*
+ * DRXJ_CFG_ATV_MISC
+ */
+ struct drxj_cfg_atv_misc {
+ s16 peak_filter; /* -8 .. 15 */
+ u16 noise_filter; /* 0 .. 15 */};
+
+/*
+ * struct drxj_cfg_oob_misc */
+#define DRXJ_OOB_STATE_RESET 0x0
+#define DRXJ_OOB_STATE_AGN_HUNT 0x1
+#define DRXJ_OOB_STATE_DGN_HUNT 0x2
+#define DRXJ_OOB_STATE_AGC_HUNT 0x3
+#define DRXJ_OOB_STATE_FRQ_HUNT 0x4
+#define DRXJ_OOB_STATE_PHA_HUNT 0x8
+#define DRXJ_OOB_STATE_TIM_HUNT 0x10
+#define DRXJ_OOB_STATE_EQU_HUNT 0x20
+#define DRXJ_OOB_STATE_EQT_HUNT 0x30
+#define DRXJ_OOB_STATE_SYNC 0x40
+
+struct drxj_cfg_oob_misc {
+ struct drxj_agc_status agc;
+ bool eq_lock;
+ bool sym_timing_lock;
+ bool phase_lock;
+ bool freq_lock;
+ bool dig_gain_lock;
+ bool ana_gain_lock;
+ u8 state;
+};
+
+/*
+ * Index of in array of coef
+ */
+ enum drxj_cfg_oob_lo_power {
+ DRXJ_OOB_LO_POW_MINUS0DB = 0,
+ DRXJ_OOB_LO_POW_MINUS5DB,
+ DRXJ_OOB_LO_POW_MINUS10DB,
+ DRXJ_OOB_LO_POW_MINUS15DB,
+ DRXJ_OOB_LO_POW_MAX};
+
+/*
+ * DRXJ_CFG_ATV_EQU_COEF
+ */
+ struct drxj_cfg_atv_equ_coef {
+ s16 coef0; /* -256 .. 255 */
+ s16 coef1; /* -256 .. 255 */
+ s16 coef2; /* -256 .. 255 */
+ s16 coef3; /* -256 .. 255 */};
+
+/*
+ * Index of in array of coef
+ */
+ enum drxj_coef_array_index {
+ DRXJ_COEF_IDX_MN = 0,
+ DRXJ_COEF_IDX_FM,
+ DRXJ_COEF_IDX_L,
+ DRXJ_COEF_IDX_LP,
+ DRXJ_COEF_IDX_BG,
+ DRXJ_COEF_IDX_DK,
+ DRXJ_COEF_IDX_I,
+ DRXJ_COEF_IDX_MAX};
+
+/*
+ * DRXJ_CFG_ATV_OUTPUT
+ */
+
+/**
+* /enum DRXJAttenuation_t
+* Attenuation setting for SIF AGC.
+*
+*/
+ enum drxjsif_attenuation {
+ DRXJ_SIF_ATTENUATION_0DB,
+ DRXJ_SIF_ATTENUATION_3DB,
+ DRXJ_SIF_ATTENUATION_6DB,
+ DRXJ_SIF_ATTENUATION_9DB};
+
+/**
+* /struct struct drxj_cfg_atv_output * SIF attenuation setting.
+*
+*/
+struct drxj_cfg_atv_output {
+ bool enable_cvbs_output; /* true= enabled */
+ bool enable_sif_output; /* true= enabled */
+ enum drxjsif_attenuation sif_attenuation;
+};
+
+/*
+ DRXJ_CFG_ATV_AGC_STATUS (get only)
+*/
+/* TODO : AFE interface not yet finished, subject to change */
+ struct drxj_cfg_atv_agc_status {
+ u16 rf_agc_gain; /* 0 .. 877 uA */
+ u16 if_agc_gain; /* 0 .. 877 uA */
+ s16 video_agc_gain; /* -75 .. 1972 in 0.1 dB steps */
+ s16 audio_agc_gain; /* -4 .. 1020 in 0.1 dB steps */
+ u16 rf_agc_loop_gain; /* 0 .. 7 */
+ u16 if_agc_loop_gain; /* 0 .. 7 */
+ u16 video_agc_loop_gain; /* 0 .. 7 */};
+
+/*============================================================================*/
+/*============================================================================*/
+/*== CTRL related data structures ============================================*/
+/*============================================================================*/
+/*============================================================================*/
+
+/* NONE */
+
+/*============================================================================*/
+/*============================================================================*/
+
+/*========================================*/
+/**
+* /struct struct drxj_data * DRXJ specific attributes.
+*
+* Global data container for DRXJ specific data.
+*
+*/
+ struct drxj_data {
+ /* device capabilties (determined during drx_open()) */
+ bool has_lna; /**< true if LNA (aka PGA) present */
+ bool has_oob; /**< true if OOB supported */
+ bool has_ntsc; /**< true if NTSC supported */
+ bool has_btsc; /**< true if BTSC supported */
+ bool has_smatx; /**< true if mat_tx is available */
+ bool has_smarx; /**< true if mat_rx is available */
+ bool has_gpio; /**< true if GPIO is available */
+ bool has_irqn; /**< true if IRQN is available */
+ /* A1/A2/A... */
+ u8 mfx; /**< metal fix */
+
+ /* tuner settings */
+ bool mirror_freq_spect_oob;/**< tuner inversion (true = tuner mirrors the signal */
+
+ /* standard/channel settings */
+ enum drx_standard standard; /**< current standard information */
+ enum drx_modulation constellation;
+ /**< current constellation */
+ s32 frequency; /**< center signal frequency in KHz */
+ enum drx_bandwidth curr_bandwidth;
+ /**< current channel bandwidth */
+ enum drx_mirror mirror; /**< current channel mirror */
+
+ /* signal quality information */
+ u32 fec_bits_desired; /**< BER accounting period */
+ u16 fec_vd_plen; /**< no of trellis symbols: VD SER measurement period */
+ u16 qam_vd_prescale; /**< Viterbi Measurement Prescale */
+ u16 qam_vd_period; /**< Viterbi Measurement period */
+ u16 fec_rs_plen; /**< defines RS BER measurement period */
+ u16 fec_rs_prescale; /**< ReedSolomon Measurement Prescale */
+ u16 fec_rs_period; /**< ReedSolomon Measurement period */
+ bool reset_pkt_err_acc; /**< Set a flag to reset accumulated packet error */
+ u16 pkt_err_acc_start; /**< Set a flag to reset accumulated packet error */
+
+ /* HI configuration */
+ u16 hi_cfg_timing_div; /**< HI Configure() parameter 2 */
+ u16 hi_cfg_bridge_delay; /**< HI Configure() parameter 3 */
+ u16 hi_cfg_wake_up_key; /**< HI Configure() parameter 4 */
+ u16 hi_cfg_ctrl; /**< HI Configure() parameter 5 */
+ u16 hi_cfg_transmit; /**< HI Configure() parameter 6 */
+
+ /* UIO configuartion */
+ enum drxuio_mode uio_sma_rx_mode;/**< current mode of SmaRx pin */
+ enum drxuio_mode uio_sma_tx_mode;/**< current mode of SmaTx pin */
+ enum drxuio_mode uio_gpio_mode; /**< current mode of ASEL pin */
+ enum drxuio_mode uio_irqn_mode; /**< current mode of IRQN pin */
+
+ /* IQM fs frequecy shift and inversion */
+ u32 iqm_fs_rate_ofs; /**< frequency shifter setting after setchannel */
+ bool pos_image; /**< Ture: positive image */
+ /* IQM RC frequecy shift */
+ u32 iqm_rc_rate_ofs; /**< frequency shifter setting after setchannel */
+
+ /* ATV configuartion */
+ u32 atv_cfg_changed_flags; /**< flag: flags cfg changes */
+ s16 atv_top_equ0[DRXJ_COEF_IDX_MAX]; /**< shadow of ATV_TOP_EQU0__A */
+ s16 atv_top_equ1[DRXJ_COEF_IDX_MAX]; /**< shadow of ATV_TOP_EQU1__A */
+ s16 atv_top_equ2[DRXJ_COEF_IDX_MAX]; /**< shadow of ATV_TOP_EQU2__A */
+ s16 atv_top_equ3[DRXJ_COEF_IDX_MAX]; /**< shadow of ATV_TOP_EQU3__A */
+ bool phase_correction_bypass;/**< flag: true=bypass */
+ s16 atv_top_vid_peak; /**< shadow of ATV_TOP_VID_PEAK__A */
+ u16 atv_top_noise_th; /**< shadow of ATV_TOP_NOISE_TH__A */
+ bool enable_cvbs_output; /**< flag CVBS ouput enable */
+ bool enable_sif_output; /**< flag SIF ouput enable */
+ enum drxjsif_attenuation sif_attenuation;
+ /**< current SIF att setting */
+ /* Agc configuration for QAM and VSB */
+ struct drxj_cfg_agc qam_rf_agc_cfg; /**< qam RF AGC config */
+ struct drxj_cfg_agc qam_if_agc_cfg; /**< qam IF AGC config */
+ struct drxj_cfg_agc vsb_rf_agc_cfg; /**< vsb RF AGC config */
+ struct drxj_cfg_agc vsb_if_agc_cfg; /**< vsb IF AGC config */
+
+ /* PGA gain configuration for QAM and VSB */
+ u16 qam_pga_cfg; /**< qam PGA config */
+ u16 vsb_pga_cfg; /**< vsb PGA config */
+
+ /* Pre SAW configuration for QAM and VSB */
+ struct drxj_cfg_pre_saw qam_pre_saw_cfg;
+ /**< qam pre SAW config */
+ struct drxj_cfg_pre_saw vsb_pre_saw_cfg;
+ /**< qam pre SAW config */
+
+ /* Version information */
+ char v_text[2][12]; /**< allocated text versions */
+ struct drx_version v_version[2]; /**< allocated versions structs */
+ struct drx_version_list v_list_elements[2];
+ /**< allocated version list */
+
+ /* smart antenna configuration */
+ bool smart_ant_inverted;
+
+ /* Tracking filter setting for OOB */
+ u16 oob_trk_filter_cfg[8];
+ bool oob_power_on;
+
+ /* MPEG static bitrate setting */
+ u32 mpeg_ts_static_bitrate; /**< bitrate static MPEG output */
+ bool disable_te_ihandling; /**< MPEG TS TEI handling */
+ bool bit_reverse_mpeg_outout;/**< MPEG output bit order */
+ enum drxj_mpeg_output_clock_rate mpeg_output_clock_rate;
+ /**< MPEG output clock rate */
+ enum drxj_mpeg_start_width mpeg_start_width;
+ /**< MPEG Start width */
+
+ /* Pre SAW & Agc configuration for ATV */
+ struct drxj_cfg_pre_saw atv_pre_saw_cfg;
+ /**< atv pre SAW config */
+ struct drxj_cfg_agc atv_rf_agc_cfg; /**< atv RF AGC config */
+ struct drxj_cfg_agc atv_if_agc_cfg; /**< atv IF AGC config */
+ u16 atv_pga_cfg; /**< atv pga config */
+
+ u32 curr_symbol_rate;
+
+ /* pin-safe mode */
+ bool pdr_safe_mode; /**< PDR safe mode activated */
+ u16 pdr_safe_restore_val_gpio;
+ u16 pdr_safe_restore_val_v_sync;
+ u16 pdr_safe_restore_val_sma_rx;
+ u16 pdr_safe_restore_val_sma_tx;
+
+ /* OOB pre-saw value */
+ u16 oob_pre_saw;
+ enum drxj_cfg_oob_lo_power oob_lo_pow;
+
+ struct drx_aud_data aud_data;
+ /**< audio storage */};
+
+/*-------------------------------------------------------------------------
+Access MACROS
+-------------------------------------------------------------------------*/
+/**
+* \brief Compilable references to attributes
+* \param d pointer to demod instance
+*
+* Used as main reference to an attribute field.
+* Can be used by both macro implementation and function implementation.
+* These macros are defined to avoid duplication of code in macro and function
+* definitions that handle access of demod common or extended attributes.
+*
+*/
+
+#define DRXJ_ATTR_BTSC_DETECT(d) \
+ (((struct drxj_data *)(d)->my_ext_attr)->aud_data.btsc_detect)
+
+/*-------------------------------------------------------------------------
+DEFINES
+-------------------------------------------------------------------------*/
+
+/**
+* \def DRXJ_NTSC_CARRIER_FREQ_OFFSET
+* \brief Offset from picture carrier to centre frequency in kHz, in RF domain
+*
+* For NTSC standard.
+* NTSC channels are listed by their picture carrier frequency (Fpc).
+* The function DRX_CTRL_SET_CHANNEL requires the centre frequency as input.
+* In case the tuner module is not used the DRX-J requires that the tuner is
+* tuned to the centre frequency of the channel:
+*
+* Fcentre = Fpc + DRXJ_NTSC_CARRIER_FREQ_OFFSET
+*
+*/
+#define DRXJ_NTSC_CARRIER_FREQ_OFFSET ((s32)(1750))
+
+/**
+* \def DRXJ_PAL_SECAM_BG_CARRIER_FREQ_OFFSET
+* \brief Offset from picture carrier to centre frequency in kHz, in RF domain
+*
+* For PAL/SECAM - BG standard. This define is needed in case the tuner module
+* is NOT used. PAL/SECAM channels are listed by their picture carrier frequency (Fpc).
+* The DRX-J requires that the tuner is tuned to:
+* Fpc + DRXJ_PAL_SECAM_BG_CARRIER_FREQ_OFFSET
+*
+* In case the tuner module is used the drxdriver takes care of this.
+* In case the tuner module is NOT used the application programmer must take
+* care of this.
+*
+*/
+#define DRXJ_PAL_SECAM_BG_CARRIER_FREQ_OFFSET ((s32)(2375))
+
+/**
+* \def DRXJ_PAL_SECAM_DKIL_CARRIER_FREQ_OFFSET
+* \brief Offset from picture carrier to centre frequency in kHz, in RF domain
+*
+* For PAL/SECAM - DK, I, L standards. This define is needed in case the tuner module
+* is NOT used. PAL/SECAM channels are listed by their picture carrier frequency (Fpc).
+* The DRX-J requires that the tuner is tuned to:
+* Fpc + DRXJ_PAL_SECAM_DKIL_CARRIER_FREQ_OFFSET
+*
+* In case the tuner module is used the drxdriver takes care of this.
+* In case the tuner module is NOT used the application programmer must take
+* care of this.
+*
+*/
+#define DRXJ_PAL_SECAM_DKIL_CARRIER_FREQ_OFFSET ((s32)(2775))
+
+/**
+* \def DRXJ_PAL_SECAM_LP_CARRIER_FREQ_OFFSET
+* \brief Offset from picture carrier to centre frequency in kHz, in RF domain
+*
+* For PAL/SECAM - LP standard. This define is needed in case the tuner module
+* is NOT used. PAL/SECAM channels are listed by their picture carrier frequency (Fpc).
+* The DRX-J requires that the tuner is tuned to:
+* Fpc + DRXJ_PAL_SECAM_LP_CARRIER_FREQ_OFFSET
+*
+* In case the tuner module is used the drxdriver takes care of this.
+* In case the tuner module is NOT used the application programmer must take
+* care of this.
+*/
+#define DRXJ_PAL_SECAM_LP_CARRIER_FREQ_OFFSET ((s32)(-3255))
+
+/**
+* \def DRXJ_FM_CARRIER_FREQ_OFFSET
+* \brief Offset from sound carrier to centre frequency in kHz, in RF domain
+*
+* For FM standard.
+* FM channels are listed by their sound carrier frequency (Fsc).
+* The function DRX_CTRL_SET_CHANNEL requires the Ffm frequency (see below) as
+* input.
+* In case the tuner module is not used the DRX-J requires that the tuner is
+* tuned to the Ffm frequency of the channel.
+*
+* Ffm = Fsc + DRXJ_FM_CARRIER_FREQ_OFFSET
+*
+*/
+#define DRXJ_FM_CARRIER_FREQ_OFFSET ((s32)(-3000))
+
+/* Revision types -------------------------------------------------------*/
+
+#define DRXJ_TYPE_ID (0x3946000DUL)
+
+/* Macros ---------------------------------------------------------------*/
+
+/* Convert OOB lock status to string */
+#define DRXJ_STR_OOB_LOCKSTATUS(x) ( \
+ (x == DRX_NEVER_LOCK) ? "Never" : \
+ (x == DRX_NOT_LOCKED) ? "No" : \
+ (x == DRX_LOCKED) ? "Locked" : \
+ (x == DRX_LOCK_STATE_1) ? "AGC lock" : \
+ (x == DRX_LOCK_STATE_2) ? "sync lock" : \
+ "(Invalid)")
+
+#endif /* __DRXJ_H__ */
diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj_map.h b/drivers/media/dvb-frontends/drx39xyj/drxj_map.h
new file mode 100644
index 000000000000..0bbd4ae1f524
--- /dev/null
+++ b/drivers/media/dvb-frontends/drx39xyj/drxj_map.h
@@ -0,0 +1,15055 @@
+/*
+ Copyright (c), 2004-2005,2007-2010 Trident Microsystems, Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Trident Microsystems nor Hauppauge Computer Works
+ nor the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ 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 HOLDER 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.
+*/
+
+/*
+ ***********************************************************************************************************************
+ * WARNING - THIS FILE HAS BEEN GENERATED - DO NOT CHANGE
+ *
+ * Filename: drxj_map.h
+ * Generated on: Mon Jan 18 12:09:24 2010
+ * Generated by: IDF:x 1.3.0
+ * Generated from: reg_map
+ * Output start: [entry point]
+ *
+ * filename last modified re-use
+ * -----------------------------------------------------
+ * reg_map.1.tmp Mon Jan 18 12:09:24 2010 -
+ *
+ */
+
+#ifndef __DRXJ_MAP__H__
+#define __DRXJ_MAP__H__ INCLUDED
+
+#ifdef _REGISTERTABLE_
+#include <registertable.h>
+ extern register_table_t drxj_map[];
+ extern register_table_info_t drxj_map_info[];
+#endif
+
+#define ATV_COMM_EXEC__A 0xC00000
+#define ATV_COMM_EXEC__W 2
+#define ATV_COMM_EXEC__M 0x3
+#define ATV_COMM_EXEC__PRE 0x0
+#define ATV_COMM_EXEC_STOP 0x0
+#define ATV_COMM_EXEC_ACTIVE 0x1
+#define ATV_COMM_EXEC_HOLD 0x2
+
+#define ATV_COMM_STATE__A 0xC00001
+#define ATV_COMM_STATE__W 16
+#define ATV_COMM_STATE__M 0xFFFF
+#define ATV_COMM_STATE__PRE 0x0
+#define ATV_COMM_MB__A 0xC00002
+#define ATV_COMM_MB__W 16
+#define ATV_COMM_MB__M 0xFFFF
+#define ATV_COMM_MB__PRE 0x0
+#define ATV_COMM_INT_REQ__A 0xC00003
+#define ATV_COMM_INT_REQ__W 16
+#define ATV_COMM_INT_REQ__M 0xFFFF
+#define ATV_COMM_INT_REQ__PRE 0x0
+#define ATV_COMM_INT_REQ_COMM_INT_REQ__B 0
+#define ATV_COMM_INT_REQ_COMM_INT_REQ__W 1
+#define ATV_COMM_INT_REQ_COMM_INT_REQ__M 0x1
+#define ATV_COMM_INT_REQ_COMM_INT_REQ__PRE 0x0
+
+#define ATV_COMM_INT_STA__A 0xC00005
+#define ATV_COMM_INT_STA__W 16
+#define ATV_COMM_INT_STA__M 0xFFFF
+#define ATV_COMM_INT_STA__PRE 0x0
+#define ATV_COMM_INT_MSK__A 0xC00006
+#define ATV_COMM_INT_MSK__W 16
+#define ATV_COMM_INT_MSK__M 0xFFFF
+#define ATV_COMM_INT_MSK__PRE 0x0
+#define ATV_COMM_INT_STM__A 0xC00007
+#define ATV_COMM_INT_STM__W 16
+#define ATV_COMM_INT_STM__M 0xFFFF
+#define ATV_COMM_INT_STM__PRE 0x0
+
+#define ATV_COMM_KEY__A 0xC0000F
+#define ATV_COMM_KEY__W 16
+#define ATV_COMM_KEY__M 0xFFFF
+#define ATV_COMM_KEY__PRE 0x0
+#define ATV_COMM_KEY_KEY 0xFABA
+#define ATV_COMM_KEY_MIN 0x0
+#define ATV_COMM_KEY_MAX 0xFFFF
+
+#define ATV_TOP_COMM_EXEC__A 0xC10000
+#define ATV_TOP_COMM_EXEC__W 2
+#define ATV_TOP_COMM_EXEC__M 0x3
+#define ATV_TOP_COMM_EXEC__PRE 0x0
+#define ATV_TOP_COMM_EXEC_STOP 0x0
+#define ATV_TOP_COMM_EXEC_ACTIVE 0x1
+#define ATV_TOP_COMM_EXEC_HOLD 0x2
+
+#define ATV_TOP_COMM_STATE__A 0xC10001
+#define ATV_TOP_COMM_STATE__W 16
+#define ATV_TOP_COMM_STATE__M 0xFFFF
+#define ATV_TOP_COMM_STATE__PRE 0x0
+#define ATV_TOP_COMM_STATE_STATE__B 0
+#define ATV_TOP_COMM_STATE_STATE__W 16
+#define ATV_TOP_COMM_STATE_STATE__M 0xFFFF
+#define ATV_TOP_COMM_STATE_STATE__PRE 0x0
+
+#define ATV_TOP_COMM_MB__A 0xC10002
+#define ATV_TOP_COMM_MB__W 16
+#define ATV_TOP_COMM_MB__M 0xFFFF
+#define ATV_TOP_COMM_MB__PRE 0x0
+#define ATV_TOP_COMM_MB_CTL__B 0
+#define ATV_TOP_COMM_MB_CTL__W 1
+#define ATV_TOP_COMM_MB_CTL__M 0x1
+#define ATV_TOP_COMM_MB_CTL__PRE 0x0
+#define ATV_TOP_COMM_MB_OBS__B 1
+#define ATV_TOP_COMM_MB_OBS__W 1
+#define ATV_TOP_COMM_MB_OBS__M 0x2
+#define ATV_TOP_COMM_MB_OBS__PRE 0x0
+
+#define ATV_TOP_COMM_MB_MUX_CTRL__B 2
+#define ATV_TOP_COMM_MB_MUX_CTRL__W 4
+#define ATV_TOP_COMM_MB_MUX_CTRL__M 0x3C
+#define ATV_TOP_COMM_MB_MUX_CTRL__PRE 0x0
+#define ATV_TOP_COMM_MB_MUX_CTRL_PEAK_S 0x0
+#define ATV_TOP_COMM_MB_MUX_CTRL_VID_GAIN 0x4
+#define ATV_TOP_COMM_MB_MUX_CTRL_CORR_O 0x8
+#define ATV_TOP_COMM_MB_MUX_CTRL_CR_ROT_O 0xC
+#define ATV_TOP_COMM_MB_MUX_CTRL_CR_IIR_IQ 0x10
+#define ATV_TOP_COMM_MB_MUX_CTRL_VIDEO_O 0x14
+#define ATV_TOP_COMM_MB_MUX_CTRL_SIF_O 0x18
+#define ATV_TOP_COMM_MB_MUX_CTRL_SIF2025_O 0x1C
+#define ATV_TOP_COMM_MB_MUX_CTRL_POST_S 0x20
+
+#define ATV_TOP_COMM_MB_MUX_OBS__B 6
+#define ATV_TOP_COMM_MB_MUX_OBS__W 4
+#define ATV_TOP_COMM_MB_MUX_OBS__M 0x3C0
+#define ATV_TOP_COMM_MB_MUX_OBS__PRE 0x0
+#define ATV_TOP_COMM_MB_MUX_OBS_PEAK_S 0x0
+#define ATV_TOP_COMM_MB_MUX_OBS_VID_GAIN 0x40
+#define ATV_TOP_COMM_MB_MUX_OBS_CORR_O 0x80
+#define ATV_TOP_COMM_MB_MUX_OBS_CR_ROT_O 0xC0
+#define ATV_TOP_COMM_MB_MUX_OBS_CR_IIR_IQ 0x100
+#define ATV_TOP_COMM_MB_MUX_OBS_VIDEO_O 0x140
+#define ATV_TOP_COMM_MB_MUX_OBS_SIF_O 0x180
+#define ATV_TOP_COMM_MB_MUX_OBS_SIF2025_O 0x1C0
+#define ATV_TOP_COMM_MB_MUX_OBS_POST_S 0x200
+
+#define ATV_TOP_COMM_INT_REQ__A 0xC10003
+#define ATV_TOP_COMM_INT_REQ__W 16
+#define ATV_TOP_COMM_INT_REQ__M 0xFFFF
+#define ATV_TOP_COMM_INT_REQ__PRE 0x0
+#define ATV_TOP_COMM_INT_STA__A 0xC10005
+#define ATV_TOP_COMM_INT_STA__W 16
+#define ATV_TOP_COMM_INT_STA__M 0xFFFF
+#define ATV_TOP_COMM_INT_STA__PRE 0x0
+
+#define ATV_TOP_COMM_INT_STA_FAGC_STA__B 0
+#define ATV_TOP_COMM_INT_STA_FAGC_STA__W 1
+#define ATV_TOP_COMM_INT_STA_FAGC_STA__M 0x1
+#define ATV_TOP_COMM_INT_STA_FAGC_STA__PRE 0x0
+
+#define ATV_TOP_COMM_INT_STA_OVM_STA__B 1
+#define ATV_TOP_COMM_INT_STA_OVM_STA__W 1
+#define ATV_TOP_COMM_INT_STA_OVM_STA__M 0x2
+#define ATV_TOP_COMM_INT_STA_OVM_STA__PRE 0x0
+
+#define ATV_TOP_COMM_INT_STA_AMPTH_STA__B 2
+#define ATV_TOP_COMM_INT_STA_AMPTH_STA__W 1
+#define ATV_TOP_COMM_INT_STA_AMPTH_STA__M 0x4
+#define ATV_TOP_COMM_INT_STA_AMPTH_STA__PRE 0x0
+
+#define ATV_TOP_COMM_INT_MSK__A 0xC10006
+#define ATV_TOP_COMM_INT_MSK__W 16
+#define ATV_TOP_COMM_INT_MSK__M 0xFFFF
+#define ATV_TOP_COMM_INT_MSK__PRE 0x0
+
+#define ATV_TOP_COMM_INT_MSK_FAGC_MSK__B 0
+#define ATV_TOP_COMM_INT_MSK_FAGC_MSK__W 1
+#define ATV_TOP_COMM_INT_MSK_FAGC_MSK__M 0x1
+#define ATV_TOP_COMM_INT_MSK_FAGC_MSK__PRE 0x0
+
+#define ATV_TOP_COMM_INT_MSK_OVM_MSK__B 1
+#define ATV_TOP_COMM_INT_MSK_OVM_MSK__W 1
+#define ATV_TOP_COMM_INT_MSK_OVM_MSK__M 0x2
+#define ATV_TOP_COMM_INT_MSK_OVM_MSK__PRE 0x0
+
+#define ATV_TOP_COMM_INT_MSK_AMPTH_MSK__B 2
+#define ATV_TOP_COMM_INT_MSK_AMPTH_MSK__W 1
+#define ATV_TOP_COMM_INT_MSK_AMPTH_MSK__M 0x4
+#define ATV_TOP_COMM_INT_MSK_AMPTH_MSK__PRE 0x0
+
+#define ATV_TOP_COMM_INT_STM__A 0xC10007
+#define ATV_TOP_COMM_INT_STM__W 16
+#define ATV_TOP_COMM_INT_STM__M 0xFFFF
+#define ATV_TOP_COMM_INT_STM__PRE 0x0
+
+#define ATV_TOP_COMM_INT_STM_FAGC_STM__B 0
+#define ATV_TOP_COMM_INT_STM_FAGC_STM__W 1
+#define ATV_TOP_COMM_INT_STM_FAGC_STM__M 0x1
+#define ATV_TOP_COMM_INT_STM_FAGC_STM__PRE 0x0
+
+#define ATV_TOP_COMM_INT_STM_OVM_STM__B 1
+#define ATV_TOP_COMM_INT_STM_OVM_STM__W 1
+#define ATV_TOP_COMM_INT_STM_OVM_STM__M 0x2
+#define ATV_TOP_COMM_INT_STM_OVM_STM__PRE 0x0
+
+#define ATV_TOP_COMM_INT_STM_AMPTH_STM__B 2
+#define ATV_TOP_COMM_INT_STM_AMPTH_STM__W 1
+#define ATV_TOP_COMM_INT_STM_AMPTH_STM__M 0x4
+#define ATV_TOP_COMM_INT_STM_AMPTH_STM__PRE 0x0
+
+#define ATV_TOP_COMM_KEY__A 0xC1000F
+#define ATV_TOP_COMM_KEY__W 16
+#define ATV_TOP_COMM_KEY__M 0xFFFF
+#define ATV_TOP_COMM_KEY__PRE 0x0
+
+#define ATV_TOP_COMM_KEY_KEY__B 0
+#define ATV_TOP_COMM_KEY_KEY__W 16
+#define ATV_TOP_COMM_KEY_KEY__M 0xFFFF
+#define ATV_TOP_COMM_KEY_KEY__PRE 0x0
+#define ATV_TOP_COMM_KEY_KEY_KEY 0xFABA
+#define ATV_TOP_COMM_KEY_KEY_MIN 0x0
+#define ATV_TOP_COMM_KEY_KEY_MAX 0xFFFF
+
+#define ATV_TOP_CR_AMP_TH__A 0xC10010
+#define ATV_TOP_CR_AMP_TH__W 8
+#define ATV_TOP_CR_AMP_TH__M 0xFF
+#define ATV_TOP_CR_AMP_TH__PRE 0x8
+#define ATV_TOP_CR_AMP_TH_MN 0x8
+
+#define ATV_TOP_CR_CONT__A 0xC10011
+#define ATV_TOP_CR_CONT__W 9
+#define ATV_TOP_CR_CONT__M 0x1FF
+#define ATV_TOP_CR_CONT__PRE 0x9C
+
+#define ATV_TOP_CR_CONT_CR_P__B 0
+#define ATV_TOP_CR_CONT_CR_P__W 3
+#define ATV_TOP_CR_CONT_CR_P__M 0x7
+#define ATV_TOP_CR_CONT_CR_P__PRE 0x4
+#define ATV_TOP_CR_CONT_CR_P_MN 0x4
+#define ATV_TOP_CR_CONT_CR_P_FM 0x0
+
+#define ATV_TOP_CR_CONT_CR_D__B 3
+#define ATV_TOP_CR_CONT_CR_D__W 3
+#define ATV_TOP_CR_CONT_CR_D__M 0x38
+#define ATV_TOP_CR_CONT_CR_D__PRE 0x18
+#define ATV_TOP_CR_CONT_CR_D_MN 0x18
+#define ATV_TOP_CR_CONT_CR_D_FM 0x0
+
+#define ATV_TOP_CR_CONT_CR_I__B 6
+#define ATV_TOP_CR_CONT_CR_I__W 3
+#define ATV_TOP_CR_CONT_CR_I__M 0x1C0
+#define ATV_TOP_CR_CONT_CR_I__PRE 0x80
+#define ATV_TOP_CR_CONT_CR_I_MN 0x80
+#define ATV_TOP_CR_CONT_CR_I_FM 0x0
+
+#define ATV_TOP_CR_OVM_TH__A 0xC10012
+#define ATV_TOP_CR_OVM_TH__W 8
+#define ATV_TOP_CR_OVM_TH__M 0xFF
+#define ATV_TOP_CR_OVM_TH__PRE 0xA0
+#define ATV_TOP_CR_OVM_TH_MN 0xA0
+#define ATV_TOP_CR_OVM_TH_FM 0x0
+
+#define ATV_TOP_NOISE_TH__A 0xC10013
+#define ATV_TOP_NOISE_TH__W 4
+#define ATV_TOP_NOISE_TH__M 0xF
+#define ATV_TOP_NOISE_TH__PRE 0x8
+#define ATV_TOP_NOISE_TH_MN 0x8
+
+#define ATV_TOP_EQU0__A 0xC10014
+#define ATV_TOP_EQU0__W 9
+#define ATV_TOP_EQU0__M 0x1FF
+#define ATV_TOP_EQU0__PRE 0x1FB
+
+#define ATV_TOP_EQU0_EQU_C0__B 0
+#define ATV_TOP_EQU0_EQU_C0__W 9
+#define ATV_TOP_EQU0_EQU_C0__M 0x1FF
+#define ATV_TOP_EQU0_EQU_C0__PRE 0x1FB
+#define ATV_TOP_EQU0_EQU_C0_MN 0xFB
+
+#define ATV_TOP_EQU1__A 0xC10015
+#define ATV_TOP_EQU1__W 9
+#define ATV_TOP_EQU1__M 0x1FF
+#define ATV_TOP_EQU1__PRE 0x1CE
+
+#define ATV_TOP_EQU1_EQU_C1__B 0
+#define ATV_TOP_EQU1_EQU_C1__W 9
+#define ATV_TOP_EQU1_EQU_C1__M 0x1FF
+#define ATV_TOP_EQU1_EQU_C1__PRE 0x1CE
+#define ATV_TOP_EQU1_EQU_C1_MN 0xCE
+
+#define ATV_TOP_EQU2__A 0xC10016
+#define ATV_TOP_EQU2__W 9
+#define ATV_TOP_EQU2__M 0x1FF
+#define ATV_TOP_EQU2__PRE 0xD2
+
+#define ATV_TOP_EQU2_EQU_C2__B 0
+#define ATV_TOP_EQU2_EQU_C2__W 9
+#define ATV_TOP_EQU2_EQU_C2__M 0x1FF
+#define ATV_TOP_EQU2_EQU_C2__PRE 0xD2
+#define ATV_TOP_EQU2_EQU_C2_MN 0xD2
+
+#define ATV_TOP_EQU3__A 0xC10017
+#define ATV_TOP_EQU3__W 9
+#define ATV_TOP_EQU3__M 0x1FF
+#define ATV_TOP_EQU3__PRE 0x160
+
+#define ATV_TOP_EQU3_EQU_C3__B 0
+#define ATV_TOP_EQU3_EQU_C3__W 9
+#define ATV_TOP_EQU3_EQU_C3__M 0x1FF
+#define ATV_TOP_EQU3_EQU_C3__PRE 0x160
+#define ATV_TOP_EQU3_EQU_C3_MN 0x60
+
+#define ATV_TOP_ROT_MODE__A 0xC10018
+#define ATV_TOP_ROT_MODE__W 1
+#define ATV_TOP_ROT_MODE__M 0x1
+#define ATV_TOP_ROT_MODE__PRE 0x0
+#define ATV_TOP_ROT_MODE_AMPTH_DEPEND 0x0
+#define ATV_TOP_ROT_MODE_ALWAYS 0x1
+
+#define ATV_TOP_MOD_CONTROL__A 0xC10019
+#define ATV_TOP_MOD_CONTROL__W 12
+#define ATV_TOP_MOD_CONTROL__M 0xFFF
+#define ATV_TOP_MOD_CONTROL__PRE 0x5B1
+
+#define ATV_TOP_MOD_CONTROL_MOD_IR__B 0
+#define ATV_TOP_MOD_CONTROL_MOD_IR__W 3
+#define ATV_TOP_MOD_CONTROL_MOD_IR__M 0x7
+#define ATV_TOP_MOD_CONTROL_MOD_IR__PRE 0x1
+#define ATV_TOP_MOD_CONTROL_MOD_IR_MN 0x1
+#define ATV_TOP_MOD_CONTROL_MOD_IR_FM 0x0
+
+#define ATV_TOP_MOD_CONTROL_MOD_IF__B 3
+#define ATV_TOP_MOD_CONTROL_MOD_IF__W 4
+#define ATV_TOP_MOD_CONTROL_MOD_IF__M 0x78
+#define ATV_TOP_MOD_CONTROL_MOD_IF__PRE 0x30
+#define ATV_TOP_MOD_CONTROL_MOD_IF_MN 0x30
+#define ATV_TOP_MOD_CONTROL_MOD_IF_FM 0x0
+
+#define ATV_TOP_MOD_CONTROL_MOD_MODE__B 7
+#define ATV_TOP_MOD_CONTROL_MOD_MODE__W 1
+#define ATV_TOP_MOD_CONTROL_MOD_MODE__M 0x80
+#define ATV_TOP_MOD_CONTROL_MOD_MODE__PRE 0x80
+#define ATV_TOP_MOD_CONTROL_MOD_MODE_RISE 0x0
+#define ATV_TOP_MOD_CONTROL_MOD_MODE_RISE_FALL 0x80
+
+#define ATV_TOP_MOD_CONTROL_MOD_TH__B 8
+#define ATV_TOP_MOD_CONTROL_MOD_TH__W 4
+#define ATV_TOP_MOD_CONTROL_MOD_TH__M 0xF00
+#define ATV_TOP_MOD_CONTROL_MOD_TH__PRE 0x500
+#define ATV_TOP_MOD_CONTROL_MOD_TH_MN 0x500
+#define ATV_TOP_MOD_CONTROL_MOD_TH_FM 0x0
+
+#define ATV_TOP_STD__A 0xC1001A
+#define ATV_TOP_STD__W 2
+#define ATV_TOP_STD__M 0x3
+#define ATV_TOP_STD__PRE 0x0
+
+#define ATV_TOP_STD_MODE__B 0
+#define ATV_TOP_STD_MODE__W 1
+#define ATV_TOP_STD_MODE__M 0x1
+#define ATV_TOP_STD_MODE__PRE 0x0
+#define ATV_TOP_STD_MODE_MN 0x0
+#define ATV_TOP_STD_MODE_FM 0x1
+
+#define ATV_TOP_STD_VID_POL__B 1
+#define ATV_TOP_STD_VID_POL__W 1
+#define ATV_TOP_STD_VID_POL__M 0x2
+#define ATV_TOP_STD_VID_POL__PRE 0x0
+#define ATV_TOP_STD_VID_POL_NEG 0x0
+#define ATV_TOP_STD_VID_POL_POS 0x2
+
+#define ATV_TOP_VID_AMP__A 0xC1001B
+#define ATV_TOP_VID_AMP__W 12
+#define ATV_TOP_VID_AMP__M 0xFFF
+#define ATV_TOP_VID_AMP__PRE 0x380
+#define ATV_TOP_VID_AMP_MN 0x380
+#define ATV_TOP_VID_AMP_FM 0x0
+
+#define ATV_TOP_VID_PEAK__A 0xC1001C
+#define ATV_TOP_VID_PEAK__W 5
+#define ATV_TOP_VID_PEAK__M 0x1F
+#define ATV_TOP_VID_PEAK__PRE 0x1
+
+#define ATV_TOP_FAGC_TH__A 0xC1001D
+#define ATV_TOP_FAGC_TH__W 11
+#define ATV_TOP_FAGC_TH__M 0x7FF
+#define ATV_TOP_FAGC_TH__PRE 0x2B2
+#define ATV_TOP_FAGC_TH_MN 0x2B2
+
+#define ATV_TOP_SYNC_SLICE__A 0xC1001E
+#define ATV_TOP_SYNC_SLICE__W 11
+#define ATV_TOP_SYNC_SLICE__M 0x7FF
+#define ATV_TOP_SYNC_SLICE__PRE 0x243
+#define ATV_TOP_SYNC_SLICE_MN 0x243
+
+#define ATV_TOP_SIF_GAIN__A 0xC1001F
+#define ATV_TOP_SIF_GAIN__W 11
+#define ATV_TOP_SIF_GAIN__M 0x7FF
+#define ATV_TOP_SIF_GAIN__PRE 0x0
+
+#define ATV_TOP_SIF_TP__A 0xC10020
+#define ATV_TOP_SIF_TP__W 6
+#define ATV_TOP_SIF_TP__M 0x3F
+#define ATV_TOP_SIF_TP__PRE 0x0
+
+#define ATV_TOP_MOD_ACCU__A 0xC10021
+#define ATV_TOP_MOD_ACCU__W 10
+#define ATV_TOP_MOD_ACCU__M 0x3FF
+#define ATV_TOP_MOD_ACCU__PRE 0x0
+
+#define ATV_TOP_CR_FREQ__A 0xC10022
+#define ATV_TOP_CR_FREQ__W 8
+#define ATV_TOP_CR_FREQ__M 0xFF
+#define ATV_TOP_CR_FREQ__PRE 0x0
+
+#define ATV_TOP_CR_PHAD__A 0xC10023
+#define ATV_TOP_CR_PHAD__W 12
+#define ATV_TOP_CR_PHAD__M 0xFFF
+#define ATV_TOP_CR_PHAD__PRE 0x0
+
+#define ATV_TOP_AF_SIF_ATT__A 0xC10024
+#define ATV_TOP_AF_SIF_ATT__W 2
+#define ATV_TOP_AF_SIF_ATT__M 0x3
+#define ATV_TOP_AF_SIF_ATT__PRE 0x0
+#define ATV_TOP_AF_SIF_ATT_0DB 0x0
+#define ATV_TOP_AF_SIF_ATT_M3DB 0x1
+#define ATV_TOP_AF_SIF_ATT_M6DB 0x2
+#define ATV_TOP_AF_SIF_ATT_M9DB 0x3
+
+#define ATV_TOP_STDBY__A 0xC10025
+#define ATV_TOP_STDBY__W 2
+#define ATV_TOP_STDBY__M 0x3
+#define ATV_TOP_STDBY__PRE 0x1
+
+#define ATV_TOP_STDBY_SIF_STDBY__B 0
+#define ATV_TOP_STDBY_SIF_STDBY__W 1
+#define ATV_TOP_STDBY_SIF_STDBY__M 0x1
+#define ATV_TOP_STDBY_SIF_STDBY__PRE 0x1
+#define ATV_TOP_STDBY_SIF_STDBY_ACTIVE 0x0
+#define ATV_TOP_STDBY_SIF_STDBY_STANDBY 0x1
+
+#define ATV_TOP_STDBY_CVBS_STDBY__B 1
+#define ATV_TOP_STDBY_CVBS_STDBY__W 1
+#define ATV_TOP_STDBY_CVBS_STDBY__M 0x2
+#define ATV_TOP_STDBY_CVBS_STDBY__PRE 0x0
+#define ATV_TOP_STDBY_CVBS_STDBY_A1_ACTIVE 0x0
+#define ATV_TOP_STDBY_CVBS_STDBY_A1_STANDBY 0x2
+#define ATV_TOP_STDBY_CVBS_STDBY_A2_ACTIVE 0x2
+#define ATV_TOP_STDBY_CVBS_STDBY_A2_STANDBY 0x0
+
+#define ATV_TOP_OVERRIDE_SFR__A 0xC10026
+#define ATV_TOP_OVERRIDE_SFR__W 1
+#define ATV_TOP_OVERRIDE_SFR__M 0x1
+#define ATV_TOP_OVERRIDE_SFR__PRE 0x0
+#define ATV_TOP_OVERRIDE_SFR_ACTIVE 0x0
+#define ATV_TOP_OVERRIDE_SFR_OVERRIDE 0x1
+
+#define ATV_TOP_SFR_VID_GAIN__A 0xC10027
+#define ATV_TOP_SFR_VID_GAIN__W 16
+#define ATV_TOP_SFR_VID_GAIN__M 0xFFFF
+#define ATV_TOP_SFR_VID_GAIN__PRE 0x0
+
+#define ATV_TOP_SFR_AGC_RES__A 0xC10028
+#define ATV_TOP_SFR_AGC_RES__W 5
+#define ATV_TOP_SFR_AGC_RES__M 0x1F
+#define ATV_TOP_SFR_AGC_RES__PRE 0x0
+
+#define ATV_TOP_OVM_COMP__A 0xC10029
+#define ATV_TOP_OVM_COMP__W 12
+#define ATV_TOP_OVM_COMP__M 0xFFF
+#define ATV_TOP_OVM_COMP__PRE 0x0
+#define ATV_TOP_OUT_CONF__A 0xC1002A
+#define ATV_TOP_OUT_CONF__W 5
+#define ATV_TOP_OUT_CONF__M 0x1F
+#define ATV_TOP_OUT_CONF__PRE 0x0
+
+#define ATV_TOP_OUT_CONF_CVBS_DAC_SIGN__B 0
+#define ATV_TOP_OUT_CONF_CVBS_DAC_SIGN__W 1
+#define ATV_TOP_OUT_CONF_CVBS_DAC_SIGN__M 0x1
+#define ATV_TOP_OUT_CONF_CVBS_DAC_SIGN__PRE 0x0
+#define ATV_TOP_OUT_CONF_CVBS_DAC_SIGN_UNSIGNED 0x0
+#define ATV_TOP_OUT_CONF_CVBS_DAC_SIGN_SIGNED 0x1
+
+#define ATV_TOP_OUT_CONF_SIF_DAC_SIGN__B 1
+#define ATV_TOP_OUT_CONF_SIF_DAC_SIGN__W 1
+#define ATV_TOP_OUT_CONF_SIF_DAC_SIGN__M 0x2
+#define ATV_TOP_OUT_CONF_SIF_DAC_SIGN__PRE 0x0
+#define ATV_TOP_OUT_CONF_SIF_DAC_SIGN_UNSIGNED 0x0
+#define ATV_TOP_OUT_CONF_SIF_DAC_SIGN_SIGNED 0x2
+
+#define ATV_TOP_OUT_CONF_SIF20_SIGN__B 2
+#define ATV_TOP_OUT_CONF_SIF20_SIGN__W 1
+#define ATV_TOP_OUT_CONF_SIF20_SIGN__M 0x4
+#define ATV_TOP_OUT_CONF_SIF20_SIGN__PRE 0x0
+#define ATV_TOP_OUT_CONF_SIF20_SIGN_UNSIGNED 0x0
+#define ATV_TOP_OUT_CONF_SIF20_SIGN_SIGNED 0x4
+
+#define ATV_TOP_OUT_CONF_CVBS_DAC_BR__B 3
+#define ATV_TOP_OUT_CONF_CVBS_DAC_BR__W 1
+#define ATV_TOP_OUT_CONF_CVBS_DAC_BR__M 0x8
+#define ATV_TOP_OUT_CONF_CVBS_DAC_BR__PRE 0x0
+#define ATV_TOP_OUT_CONF_CVBS_DAC_BR_NORMAL 0x0
+#define ATV_TOP_OUT_CONF_CVBS_DAC_BR_BITREVERSED 0x8
+
+#define ATV_TOP_OUT_CONF_SIF_DAC_BR__B 4
+#define ATV_TOP_OUT_CONF_SIF_DAC_BR__W 1
+#define ATV_TOP_OUT_CONF_SIF_DAC_BR__M 0x10
+#define ATV_TOP_OUT_CONF_SIF_DAC_BR__PRE 0x0
+#define ATV_TOP_OUT_CONF_SIF_DAC_BR_NORMAL 0x0
+#define ATV_TOP_OUT_CONF_SIF_DAC_BR_BITREVERSED 0x10
+
+#define ATV_AFT_COMM_EXEC__A 0xFF0000
+#define ATV_AFT_COMM_EXEC__W 2
+#define ATV_AFT_COMM_EXEC__M 0x3
+#define ATV_AFT_COMM_EXEC__PRE 0x0
+#define ATV_AFT_COMM_EXEC_STOP 0x0
+#define ATV_AFT_COMM_EXEC_ACTIVE 0x1
+#define ATV_AFT_COMM_EXEC_HOLD 0x2
+
+#define ATV_AFT_TST__A 0xFF0010
+#define ATV_AFT_TST__W 4
+#define ATV_AFT_TST__M 0xF
+#define ATV_AFT_TST__PRE 0x0
+
+#define AUD_COMM_EXEC__A 0x1000000
+#define AUD_COMM_EXEC__W 2
+#define AUD_COMM_EXEC__M 0x3
+#define AUD_COMM_EXEC__PRE 0x0
+#define AUD_COMM_EXEC_STOP 0x0
+#define AUD_COMM_EXEC_ACTIVE 0x1
+
+#define AUD_COMM_MB__A 0x1000002
+#define AUD_COMM_MB__W 16
+#define AUD_COMM_MB__M 0xFFFF
+#define AUD_COMM_MB__PRE 0x0
+
+#define AUD_TOP_COMM_EXEC__A 0x1010000
+#define AUD_TOP_COMM_EXEC__W 2
+#define AUD_TOP_COMM_EXEC__M 0x3
+#define AUD_TOP_COMM_EXEC__PRE 0x0
+#define AUD_TOP_COMM_EXEC_STOP 0x0
+#define AUD_TOP_COMM_EXEC_ACTIVE 0x1
+
+#define AUD_TOP_COMM_MB__A 0x1010002
+#define AUD_TOP_COMM_MB__W 16
+#define AUD_TOP_COMM_MB__M 0xFFFF
+#define AUD_TOP_COMM_MB__PRE 0x0
+
+#define AUD_TOP_COMM_MB_CTL__B 0
+#define AUD_TOP_COMM_MB_CTL__W 1
+#define AUD_TOP_COMM_MB_CTL__M 0x1
+#define AUD_TOP_COMM_MB_CTL__PRE 0x0
+#define AUD_TOP_COMM_MB_CTL_CTR_OFF 0x0
+#define AUD_TOP_COMM_MB_CTL_CTR_ON 0x1
+
+#define AUD_TOP_COMM_MB_OBS__B 1
+#define AUD_TOP_COMM_MB_OBS__W 1
+#define AUD_TOP_COMM_MB_OBS__M 0x2
+#define AUD_TOP_COMM_MB_OBS__PRE 0x0
+#define AUD_TOP_COMM_MB_OBS_OBS_OFF 0x0
+#define AUD_TOP_COMM_MB_OBS_OBS_ON 0x2
+
+#define AUD_TOP_COMM_MB_MUX_CTRL__B 2
+#define AUD_TOP_COMM_MB_MUX_CTRL__W 4
+#define AUD_TOP_COMM_MB_MUX_CTRL__M 0x3C
+#define AUD_TOP_COMM_MB_MUX_CTRL__PRE 0x0
+#define AUD_TOP_COMM_MB_MUX_CTRL_DEMOD_TBO 0x0
+#define AUD_TOP_COMM_MB_MUX_CTRL_XDFP_IRQS 0x4
+#define AUD_TOP_COMM_MB_MUX_CTRL_OBSERVEPC 0x8
+#define AUD_TOP_COMM_MB_MUX_CTRL_SAOUT 0xC
+#define AUD_TOP_COMM_MB_MUX_CTRL_XDFP_SCHEQ 0x10
+
+#define AUD_TOP_COMM_MB_MUX_OBS__B 6
+#define AUD_TOP_COMM_MB_MUX_OBS__W 4
+#define AUD_TOP_COMM_MB_MUX_OBS__M 0x3C0
+#define AUD_TOP_COMM_MB_MUX_OBS__PRE 0x0
+#define AUD_TOP_COMM_MB_MUX_OBS_DEMOD_TBO 0x0
+#define AUD_TOP_COMM_MB_MUX_OBS_XDFP_IRQS 0x40
+#define AUD_TOP_COMM_MB_MUX_OBS_OBSERVEPC 0x80
+#define AUD_TOP_COMM_MB_MUX_OBS_SAOUT 0xC0
+#define AUD_TOP_COMM_MB_MUX_OBS_XDFP_SCHEQ 0x100
+
+#define AUD_TOP_TR_MDE__A 0x1010010
+#define AUD_TOP_TR_MDE__W 5
+#define AUD_TOP_TR_MDE__M 0x1F
+#define AUD_TOP_TR_MDE__PRE 0x18
+
+#define AUD_TOP_TR_MDE_FIFO_SIZE__B 0
+#define AUD_TOP_TR_MDE_FIFO_SIZE__W 4
+#define AUD_TOP_TR_MDE_FIFO_SIZE__M 0xF
+#define AUD_TOP_TR_MDE_FIFO_SIZE__PRE 0x8
+
+#define AUD_TOP_TR_MDE_RD_LOCK__B 4
+#define AUD_TOP_TR_MDE_RD_LOCK__W 1
+#define AUD_TOP_TR_MDE_RD_LOCK__M 0x10
+#define AUD_TOP_TR_MDE_RD_LOCK__PRE 0x10
+#define AUD_TOP_TR_MDE_RD_LOCK_NORMAL 0x0
+#define AUD_TOP_TR_MDE_RD_LOCK_LOCK 0x10
+
+#define AUD_TOP_TR_CTR__A 0x1010011
+#define AUD_TOP_TR_CTR__W 4
+#define AUD_TOP_TR_CTR__M 0xF
+#define AUD_TOP_TR_CTR__PRE 0x0
+
+#define AUD_TOP_TR_CTR_FIFO_RD_RDY__B 0
+#define AUD_TOP_TR_CTR_FIFO_RD_RDY__W 1
+#define AUD_TOP_TR_CTR_FIFO_RD_RDY__M 0x1
+#define AUD_TOP_TR_CTR_FIFO_RD_RDY__PRE 0x0
+#define AUD_TOP_TR_CTR_FIFO_RD_RDY_NOT_READY 0x0
+#define AUD_TOP_TR_CTR_FIFO_RD_RDY_READY 0x1
+
+#define AUD_TOP_TR_CTR_FIFO_EMPTY__B 1
+#define AUD_TOP_TR_CTR_FIFO_EMPTY__W 1
+#define AUD_TOP_TR_CTR_FIFO_EMPTY__M 0x2
+#define AUD_TOP_TR_CTR_FIFO_EMPTY__PRE 0x0
+#define AUD_TOP_TR_CTR_FIFO_EMPTY_NOT_EMPTY 0x0
+#define AUD_TOP_TR_CTR_FIFO_EMPTY_EMPTY 0x2
+
+#define AUD_TOP_TR_CTR_FIFO_LOCK__B 2
+#define AUD_TOP_TR_CTR_FIFO_LOCK__W 1
+#define AUD_TOP_TR_CTR_FIFO_LOCK__M 0x4
+#define AUD_TOP_TR_CTR_FIFO_LOCK__PRE 0x0
+#define AUD_TOP_TR_CTR_FIFO_LOCK_UNLOCKED 0x0
+#define AUD_TOP_TR_CTR_FIFO_LOCK_LOCKED 0x4
+
+#define AUD_TOP_TR_CTR_FIFO_FULL__B 3
+#define AUD_TOP_TR_CTR_FIFO_FULL__W 1
+#define AUD_TOP_TR_CTR_FIFO_FULL__M 0x8
+#define AUD_TOP_TR_CTR_FIFO_FULL__PRE 0x0
+#define AUD_TOP_TR_CTR_FIFO_FULL_EMPTY 0x0
+#define AUD_TOP_TR_CTR_FIFO_FULL_FULL 0x8
+
+#define AUD_TOP_TR_RD_REG__A 0x1010012
+#define AUD_TOP_TR_RD_REG__W 16
+#define AUD_TOP_TR_RD_REG__M 0xFFFF
+#define AUD_TOP_TR_RD_REG__PRE 0x0
+
+#define AUD_TOP_TR_RD_REG_RESULT__B 0
+#define AUD_TOP_TR_RD_REG_RESULT__W 16
+#define AUD_TOP_TR_RD_REG_RESULT__M 0xFFFF
+#define AUD_TOP_TR_RD_REG_RESULT__PRE 0x0
+
+#define AUD_TOP_TR_TIMER__A 0x1010013
+#define AUD_TOP_TR_TIMER__W 16
+#define AUD_TOP_TR_TIMER__M 0xFFFF
+#define AUD_TOP_TR_TIMER__PRE 0x0
+
+#define AUD_TOP_TR_TIMER_CYCLES__B 0
+#define AUD_TOP_TR_TIMER_CYCLES__W 16
+#define AUD_TOP_TR_TIMER_CYCLES__M 0xFFFF
+#define AUD_TOP_TR_TIMER_CYCLES__PRE 0x0
+
+#define AUD_TOP_DEMOD_TBO_SEL__A 0x1010014
+#define AUD_TOP_DEMOD_TBO_SEL__W 5
+#define AUD_TOP_DEMOD_TBO_SEL__M 0x1F
+#define AUD_TOP_DEMOD_TBO_SEL__PRE 0x0
+
+#define AUD_DEM_WR_MODUS__A 0x1030030
+#define AUD_DEM_WR_MODUS__W 16
+#define AUD_DEM_WR_MODUS__M 0xFFFF
+#define AUD_DEM_WR_MODUS__PRE 0x0
+
+#define AUD_DEM_WR_MODUS_MOD_ASS__B 0
+#define AUD_DEM_WR_MODUS_MOD_ASS__W 1
+#define AUD_DEM_WR_MODUS_MOD_ASS__M 0x1
+#define AUD_DEM_WR_MODUS_MOD_ASS__PRE 0x0
+#define AUD_DEM_WR_MODUS_MOD_ASS_OFF 0x0
+#define AUD_DEM_WR_MODUS_MOD_ASS_ON 0x1
+
+#define AUD_DEM_WR_MODUS_MOD_STATINTERR__B 1
+#define AUD_DEM_WR_MODUS_MOD_STATINTERR__W 1
+#define AUD_DEM_WR_MODUS_MOD_STATINTERR__M 0x2
+#define AUD_DEM_WR_MODUS_MOD_STATINTERR__PRE 0x0
+#define AUD_DEM_WR_MODUS_MOD_STATINTERR_DISABLE 0x0
+#define AUD_DEM_WR_MODUS_MOD_STATINTERR_ENABLE 0x2
+
+#define AUD_DEM_WR_MODUS_MOD_DIS_STD_CHG__B 2
+#define AUD_DEM_WR_MODUS_MOD_DIS_STD_CHG__W 1
+#define AUD_DEM_WR_MODUS_MOD_DIS_STD_CHG__M 0x4
+#define AUD_DEM_WR_MODUS_MOD_DIS_STD_CHG__PRE 0x0
+#define AUD_DEM_WR_MODUS_MOD_DIS_STD_CHG_ENABLED 0x0
+#define AUD_DEM_WR_MODUS_MOD_DIS_STD_CHG_DISABLED 0x4
+
+#define AUD_DEM_WR_MODUS_MOD_HDEV_A__B 8
+#define AUD_DEM_WR_MODUS_MOD_HDEV_A__W 1
+#define AUD_DEM_WR_MODUS_MOD_HDEV_A__M 0x100
+#define AUD_DEM_WR_MODUS_MOD_HDEV_A__PRE 0x0
+#define AUD_DEM_WR_MODUS_MOD_HDEV_A_NORMAL 0x0
+#define AUD_DEM_WR_MODUS_MOD_HDEV_A_HIGH_DEVIATION 0x100
+
+#define AUD_DEM_WR_MODUS_MOD_CM_A__B 9
+#define AUD_DEM_WR_MODUS_MOD_CM_A__W 1
+#define AUD_DEM_WR_MODUS_MOD_CM_A__M 0x200
+#define AUD_DEM_WR_MODUS_MOD_CM_A__PRE 0x0
+#define AUD_DEM_WR_MODUS_MOD_CM_A_MUTE 0x0
+#define AUD_DEM_WR_MODUS_MOD_CM_A_NOISE 0x200
+
+#define AUD_DEM_WR_MODUS_MOD_CM_B__B 10
+#define AUD_DEM_WR_MODUS_MOD_CM_B__W 1
+#define AUD_DEM_WR_MODUS_MOD_CM_B__M 0x400
+#define AUD_DEM_WR_MODUS_MOD_CM_B__PRE 0x0
+#define AUD_DEM_WR_MODUS_MOD_CM_B_MUTE 0x0
+#define AUD_DEM_WR_MODUS_MOD_CM_B_NOISE 0x400
+
+#define AUD_DEM_WR_MODUS_MOD_FMRADIO__B 11
+#define AUD_DEM_WR_MODUS_MOD_FMRADIO__W 1
+#define AUD_DEM_WR_MODUS_MOD_FMRADIO__M 0x800
+#define AUD_DEM_WR_MODUS_MOD_FMRADIO__PRE 0x0
+#define AUD_DEM_WR_MODUS_MOD_FMRADIO_US_75U 0x0
+#define AUD_DEM_WR_MODUS_MOD_FMRADIO_EU_50U 0x800
+
+#define AUD_DEM_WR_MODUS_MOD_6_5MHZ__B 12
+#define AUD_DEM_WR_MODUS_MOD_6_5MHZ__W 1
+#define AUD_DEM_WR_MODUS_MOD_6_5MHZ__M 0x1000
+#define AUD_DEM_WR_MODUS_MOD_6_5MHZ__PRE 0x0
+#define AUD_DEM_WR_MODUS_MOD_6_5MHZ_SECAM 0x0
+#define AUD_DEM_WR_MODUS_MOD_6_5MHZ_D_K 0x1000
+
+#define AUD_DEM_WR_MODUS_MOD_4_5MHZ__B 13
+#define AUD_DEM_WR_MODUS_MOD_4_5MHZ__W 2
+#define AUD_DEM_WR_MODUS_MOD_4_5MHZ__M 0x6000
+#define AUD_DEM_WR_MODUS_MOD_4_5MHZ__PRE 0x0
+#define AUD_DEM_WR_MODUS_MOD_4_5MHZ_M_KOREA 0x0
+#define AUD_DEM_WR_MODUS_MOD_4_5MHZ_M_BTSC 0x2000
+#define AUD_DEM_WR_MODUS_MOD_4_5MHZ_M_EIAJ 0x4000
+#define AUD_DEM_WR_MODUS_MOD_4_5MHZ_CHROMA 0x6000
+
+#define AUD_DEM_WR_MODUS_MOD_BTSC__B 15
+#define AUD_DEM_WR_MODUS_MOD_BTSC__W 1
+#define AUD_DEM_WR_MODUS_MOD_BTSC__M 0x8000
+#define AUD_DEM_WR_MODUS_MOD_BTSC__PRE 0x0
+#define AUD_DEM_WR_MODUS_MOD_BTSC_BTSC_STEREO 0x0
+#define AUD_DEM_WR_MODUS_MOD_BTSC_BTSC_SAP 0x8000
+
+#define AUD_DEM_WR_STANDARD_SEL__A 0x1030020
+#define AUD_DEM_WR_STANDARD_SEL__W 16
+#define AUD_DEM_WR_STANDARD_SEL__M 0xFFFF
+#define AUD_DEM_WR_STANDARD_SEL__PRE 0x0
+
+#define AUD_DEM_WR_STANDARD_SEL_STD_SEL__B 0
+#define AUD_DEM_WR_STANDARD_SEL_STD_SEL__W 12
+#define AUD_DEM_WR_STANDARD_SEL_STD_SEL__M 0xFFF
+#define AUD_DEM_WR_STANDARD_SEL_STD_SEL__PRE 0x0
+#define AUD_DEM_WR_STANDARD_SEL_STD_SEL_AUTO 0x1
+#define AUD_DEM_WR_STANDARD_SEL_STD_SEL_M_KOREA 0x2
+#define AUD_DEM_WR_STANDARD_SEL_STD_SEL_BG_FM 0x3
+#define AUD_DEM_WR_STANDARD_SEL_STD_SEL_D_K1 0x4
+#define AUD_DEM_WR_STANDARD_SEL_STD_SEL_D_K2 0x5
+#define AUD_DEM_WR_STANDARD_SEL_STD_SEL_D_K3 0x7
+#define AUD_DEM_WR_STANDARD_SEL_STD_SEL_BG_NICAM_FM 0x8
+#define AUD_DEM_WR_STANDARD_SEL_STD_SEL_L_NICAM_AM 0x9
+#define AUD_DEM_WR_STANDARD_SEL_STD_SEL_I_NICAM_FM 0xA
+#define AUD_DEM_WR_STANDARD_SEL_STD_SEL_D_K_NICAM_FM 0xB
+#define AUD_DEM_WR_STANDARD_SEL_STD_SEL_BTSC_STEREO 0x20
+#define AUD_DEM_WR_STANDARD_SEL_STD_SEL_BTSC_SAP 0x21
+#define AUD_DEM_WR_STANDARD_SEL_STD_SEL_EIA_J 0x30
+#define AUD_DEM_WR_STANDARD_SEL_STD_SEL_FM_RADIO 0x40
+
+#define AUD_DEM_RD_STANDARD_RES__A 0x102007E
+#define AUD_DEM_RD_STANDARD_RES__W 16
+#define AUD_DEM_RD_STANDARD_RES__M 0xFFFF
+#define AUD_DEM_RD_STANDARD_RES__PRE 0x0
+
+#define AUD_DEM_RD_STANDARD_RES_STD_RESULT__B 0
+#define AUD_DEM_RD_STANDARD_RES_STD_RESULT__W 16
+#define AUD_DEM_RD_STANDARD_RES_STD_RESULT__M 0xFFFF
+#define AUD_DEM_RD_STANDARD_RES_STD_RESULT__PRE 0x0
+#define AUD_DEM_RD_STANDARD_RES_STD_RESULT_NO_SOUND_STANDARD 0x0
+#define AUD_DEM_RD_STANDARD_RES_STD_RESULT_NTSC_M_DUAL_CARRIER_FM 0x2
+#define AUD_DEM_RD_STANDARD_RES_STD_RESULT_B_G_DUAL_CARRIER_FM 0x3
+#define AUD_DEM_RD_STANDARD_RES_STD_RESULT_D_K1_DUAL_CARRIER_FM 0x4
+#define AUD_DEM_RD_STANDARD_RES_STD_RESULT_D_K2_DUAL_CARRIER_FM 0x5
+#define AUD_DEM_RD_STANDARD_RES_STD_RESULT_D_K3_DUAL_CARRIER_FM 0x7
+#define AUD_DEM_RD_STANDARD_RES_STD_RESULT_B_G_NICAM_FM 0x8
+#define AUD_DEM_RD_STANDARD_RES_STD_RESULT_L_NICAM_AM 0x9
+#define AUD_DEM_RD_STANDARD_RES_STD_RESULT_I_NICAM_FM 0xA
+#define AUD_DEM_RD_STANDARD_RES_STD_RESULT_D_K_NICAM_FM 0xB
+#define AUD_DEM_RD_STANDARD_RES_STD_RESULT_BTSC_STEREO 0x20
+#define AUD_DEM_RD_STANDARD_RES_STD_RESULT_BTSC_MONO_SAP 0x21
+#define AUD_DEM_RD_STANDARD_RES_STD_RESULT_NTSC_EIA_J 0x30
+#define AUD_DEM_RD_STANDARD_RES_STD_RESULT_FM_RADIO 0x40
+#define AUD_DEM_RD_STANDARD_RES_STD_RESULT_DETECTION_STILL_ACTIVE 0x7FF
+
+#define AUD_DEM_RD_STATUS__A 0x1020200
+#define AUD_DEM_RD_STATUS__W 16
+#define AUD_DEM_RD_STATUS__M 0xFFFF
+#define AUD_DEM_RD_STATUS__PRE 0x0
+
+#define AUD_DEM_RD_STATUS_STAT_NEW_RDS__B 0
+#define AUD_DEM_RD_STATUS_STAT_NEW_RDS__W 1
+#define AUD_DEM_RD_STATUS_STAT_NEW_RDS__M 0x1
+#define AUD_DEM_RD_STATUS_STAT_NEW_RDS__PRE 0x0
+#define AUD_DEM_RD_STATUS_STAT_NEW_RDS_NO_RDS_DATA 0x0
+#define AUD_DEM_RD_STATUS_STAT_NEW_RDS_NEW_RDS_DATA 0x1
+
+#define AUD_DEM_RD_STATUS_STAT_CARR_A__B 1
+#define AUD_DEM_RD_STATUS_STAT_CARR_A__W 1
+#define AUD_DEM_RD_STATUS_STAT_CARR_A__M 0x2
+#define AUD_DEM_RD_STATUS_STAT_CARR_A__PRE 0x0
+#define AUD_DEM_RD_STATUS_STAT_CARR_A_DETECTED 0x0
+#define AUD_DEM_RD_STATUS_STAT_CARR_A_NOT_DETECTED 0x2
+
+#define AUD_DEM_RD_STATUS_STAT_CARR_B__B 2
+#define AUD_DEM_RD_STATUS_STAT_CARR_B__W 1
+#define AUD_DEM_RD_STATUS_STAT_CARR_B__M 0x4
+#define AUD_DEM_RD_STATUS_STAT_CARR_B__PRE 0x0
+#define AUD_DEM_RD_STATUS_STAT_CARR_B_DETECTED 0x0
+#define AUD_DEM_RD_STATUS_STAT_CARR_B_NOT_DETECTED 0x4
+
+#define AUD_DEM_RD_STATUS_STAT_NICAM__B 5
+#define AUD_DEM_RD_STATUS_STAT_NICAM__W 1
+#define AUD_DEM_RD_STATUS_STAT_NICAM__M 0x20
+#define AUD_DEM_RD_STATUS_STAT_NICAM__PRE 0x0
+#define AUD_DEM_RD_STATUS_STAT_NICAM_NO_NICAM 0x0
+#define AUD_DEM_RD_STATUS_STAT_NICAM_NICAM_DETECTED 0x20
+
+#define AUD_DEM_RD_STATUS_STAT_STEREO__B 6
+#define AUD_DEM_RD_STATUS_STAT_STEREO__W 1
+#define AUD_DEM_RD_STATUS_STAT_STEREO__M 0x40
+#define AUD_DEM_RD_STATUS_STAT_STEREO__PRE 0x0
+#define AUD_DEM_RD_STATUS_STAT_STEREO_NO_STEREO 0x0
+#define AUD_DEM_RD_STATUS_STAT_STEREO_STEREO 0x40
+
+#define AUD_DEM_RD_STATUS_STAT_INDEP_MONO__B 7
+#define AUD_DEM_RD_STATUS_STAT_INDEP_MONO__W 1
+#define AUD_DEM_RD_STATUS_STAT_INDEP_MONO__M 0x80
+#define AUD_DEM_RD_STATUS_STAT_INDEP_MONO__PRE 0x0
+#define AUD_DEM_RD_STATUS_STAT_INDEP_MONO_DEPENDENT_FM_MONO_PROGRAM 0x0
+#define AUD_DEM_RD_STATUS_STAT_INDEP_MONO_INDEPENDENT_FM_MONO_PROGRAM 0x80
+
+#define AUD_DEM_RD_STATUS_STAT_BIL_OR_SAP__B 8
+#define AUD_DEM_RD_STATUS_STAT_BIL_OR_SAP__W 1
+#define AUD_DEM_RD_STATUS_STAT_BIL_OR_SAP__M 0x100
+#define AUD_DEM_RD_STATUS_STAT_BIL_OR_SAP__PRE 0x0
+#define AUD_DEM_RD_STATUS_STAT_BIL_OR_SAP_NO_SAP 0x0
+#define AUD_DEM_RD_STATUS_STAT_BIL_OR_SAP_SAP 0x100
+
+#define AUD_DEM_RD_STATUS_BAD_NICAM__B 9
+#define AUD_DEM_RD_STATUS_BAD_NICAM__W 1
+#define AUD_DEM_RD_STATUS_BAD_NICAM__M 0x200
+#define AUD_DEM_RD_STATUS_BAD_NICAM__PRE 0x0
+#define AUD_DEM_RD_STATUS_BAD_NICAM_OK 0x0
+#define AUD_DEM_RD_STATUS_BAD_NICAM_BAD 0x200
+
+#define AUD_DEM_RD_RDS_ARRAY_CNT__A 0x102020F
+#define AUD_DEM_RD_RDS_ARRAY_CNT__W 12
+#define AUD_DEM_RD_RDS_ARRAY_CNT__M 0xFFF
+#define AUD_DEM_RD_RDS_ARRAY_CNT__PRE 0x0
+
+#define AUD_DEM_RD_RDS_ARRAY_CNT_RDS_ARRAY_CT__B 0
+#define AUD_DEM_RD_RDS_ARRAY_CNT_RDS_ARRAY_CT__W 12
+#define AUD_DEM_RD_RDS_ARRAY_CNT_RDS_ARRAY_CT__M 0xFFF
+#define AUD_DEM_RD_RDS_ARRAY_CNT_RDS_ARRAY_CT__PRE 0x0
+#define AUD_DEM_RD_RDS_ARRAY_CNT_RDS_ARRAY_CT_RDS_DATA_NOT_VALID 0xFFF
+
+#define AUD_DEM_RD_RDS_DATA__A 0x1020210
+#define AUD_DEM_RD_RDS_DATA__W 12
+#define AUD_DEM_RD_RDS_DATA__M 0xFFF
+#define AUD_DEM_RD_RDS_DATA__PRE 0x0
+
+#define AUD_DSP_WR_FM_PRESC__A 0x105000E
+#define AUD_DSP_WR_FM_PRESC__W 16
+#define AUD_DSP_WR_FM_PRESC__M 0xFFFF
+#define AUD_DSP_WR_FM_PRESC__PRE 0x0
+
+#define AUD_DSP_WR_FM_PRESC_FM_AM_PRESC__B 8
+#define AUD_DSP_WR_FM_PRESC_FM_AM_PRESC__W 8
+#define AUD_DSP_WR_FM_PRESC_FM_AM_PRESC__M 0xFF00
+#define AUD_DSP_WR_FM_PRESC_FM_AM_PRESC__PRE 0x0
+#define AUD_DSP_WR_FM_PRESC_FM_AM_PRESC_28_KHZ_FM_DEVIATION 0x7F00
+#define AUD_DSP_WR_FM_PRESC_FM_AM_PRESC_50_KHZ_FM_DEVIATION 0x4800
+#define AUD_DSP_WR_FM_PRESC_FM_AM_PRESC_75_KHZ_FM_DEVIATION 0x3000
+#define AUD_DSP_WR_FM_PRESC_FM_AM_PRESC_100_KHZ_FM_DEVIATION 0x2400
+#define AUD_DSP_WR_FM_PRESC_FM_AM_PRESC_150_KHZ_FM_DEVIATION 0x1800
+#define AUD_DSP_WR_FM_PRESC_FM_AM_PRESC_180_KHZ_FM_DEVIATION 0x1300
+#define AUD_DSP_WR_FM_PRESC_FM_AM_PRESC_380_KHZ_FM_DEVIATION 0x900
+
+#define AUD_DSP_WR_NICAM_PRESC__A 0x1050010
+#define AUD_DSP_WR_NICAM_PRESC__W 16
+#define AUD_DSP_WR_NICAM_PRESC__M 0xFFFF
+#define AUD_DSP_WR_NICAM_PRESC__PRE 0x0
+#define AUD_DSP_WR_VOLUME__A 0x1050000
+#define AUD_DSP_WR_VOLUME__W 16
+#define AUD_DSP_WR_VOLUME__M 0xFFFF
+#define AUD_DSP_WR_VOLUME__PRE 0x0
+
+#define AUD_DSP_WR_VOLUME_VOL_MAIN__B 8
+#define AUD_DSP_WR_VOLUME_VOL_MAIN__W 8
+#define AUD_DSP_WR_VOLUME_VOL_MAIN__M 0xFF00
+#define AUD_DSP_WR_VOLUME_VOL_MAIN__PRE 0x0
+
+#define AUD_DSP_WR_SRC_I2S_MATR__A 0x1050038
+#define AUD_DSP_WR_SRC_I2S_MATR__W 16
+#define AUD_DSP_WR_SRC_I2S_MATR__M 0xFFFF
+#define AUD_DSP_WR_SRC_I2S_MATR__PRE 0x0
+
+#define AUD_DSP_WR_SRC_I2S_MATR_SRC_I2S__B 8
+#define AUD_DSP_WR_SRC_I2S_MATR_SRC_I2S__W 8
+#define AUD_DSP_WR_SRC_I2S_MATR_SRC_I2S__M 0xFF00
+#define AUD_DSP_WR_SRC_I2S_MATR_SRC_I2S__PRE 0x0
+#define AUD_DSP_WR_SRC_I2S_MATR_SRC_I2S_MONO 0x0
+#define AUD_DSP_WR_SRC_I2S_MATR_SRC_I2S_STEREO_AB 0x100
+#define AUD_DSP_WR_SRC_I2S_MATR_SRC_I2S_STEREO_A 0x300
+#define AUD_DSP_WR_SRC_I2S_MATR_SRC_I2S_STEREO_B 0x400
+
+#define AUD_DSP_WR_SRC_I2S_MATR_MAT_I2S__B 0
+#define AUD_DSP_WR_SRC_I2S_MATR_MAT_I2S__W 8
+#define AUD_DSP_WR_SRC_I2S_MATR_MAT_I2S__M 0xFF
+#define AUD_DSP_WR_SRC_I2S_MATR_MAT_I2S__PRE 0x0
+#define AUD_DSP_WR_SRC_I2S_MATR_MAT_I2S_SOUND_A 0x0
+#define AUD_DSP_WR_SRC_I2S_MATR_MAT_I2S_SOUND_B 0x10
+#define AUD_DSP_WR_SRC_I2S_MATR_MAT_I2S_STEREO 0x20
+#define AUD_DSP_WR_SRC_I2S_MATR_MAT_I2S_MONO 0x30
+
+#define AUD_DSP_WR_AVC__A 0x1050029
+#define AUD_DSP_WR_AVC__W 16
+#define AUD_DSP_WR_AVC__M 0xFFFF
+#define AUD_DSP_WR_AVC__PRE 0x0
+
+#define AUD_DSP_WR_AVC_AVC_ON__B 14
+#define AUD_DSP_WR_AVC_AVC_ON__W 2
+#define AUD_DSP_WR_AVC_AVC_ON__M 0xC000
+#define AUD_DSP_WR_AVC_AVC_ON__PRE 0x0
+#define AUD_DSP_WR_AVC_AVC_ON_OFF 0x0
+#define AUD_DSP_WR_AVC_AVC_ON_ON 0xC000
+
+#define AUD_DSP_WR_AVC_AVC_DECAY__B 8
+#define AUD_DSP_WR_AVC_AVC_DECAY__W 4
+#define AUD_DSP_WR_AVC_AVC_DECAY__M 0xF00
+#define AUD_DSP_WR_AVC_AVC_DECAY__PRE 0x0
+#define AUD_DSP_WR_AVC_AVC_DECAY_8_SEC 0x800
+#define AUD_DSP_WR_AVC_AVC_DECAY_4_SEC 0x400
+#define AUD_DSP_WR_AVC_AVC_DECAY_2_SEC 0x200
+#define AUD_DSP_WR_AVC_AVC_DECAY_20_MSEC 0x100
+
+#define AUD_DSP_WR_AVC_AVC_REF_LEV__B 4
+#define AUD_DSP_WR_AVC_AVC_REF_LEV__W 4
+#define AUD_DSP_WR_AVC_AVC_REF_LEV__M 0xF0
+#define AUD_DSP_WR_AVC_AVC_REF_LEV__PRE 0x0
+
+#define AUD_DSP_WR_AVC_AVC_MAX_ATT__B 2
+#define AUD_DSP_WR_AVC_AVC_MAX_ATT__W 2
+#define AUD_DSP_WR_AVC_AVC_MAX_ATT__M 0xC
+#define AUD_DSP_WR_AVC_AVC_MAX_ATT__PRE 0x0
+#define AUD_DSP_WR_AVC_AVC_MAX_ATT_24DB 0x0
+#define AUD_DSP_WR_AVC_AVC_MAX_ATT_18DB 0x4
+#define AUD_DSP_WR_AVC_AVC_MAX_ATT_12DB 0x8
+
+#define AUD_DSP_WR_AVC_AVC_MAX_GAIN__B 0
+#define AUD_DSP_WR_AVC_AVC_MAX_GAIN__W 2
+#define AUD_DSP_WR_AVC_AVC_MAX_GAIN__M 0x3
+#define AUD_DSP_WR_AVC_AVC_MAX_GAIN__PRE 0x0
+#define AUD_DSP_WR_AVC_AVC_MAX_GAIN_6DB 0x0
+#define AUD_DSP_WR_AVC_AVC_MAX_GAIN_12DB 0x1
+#define AUD_DSP_WR_AVC_AVC_MAX_GAIN_0DB 0x3
+
+#define AUD_DSP_WR_QPEAK__A 0x105000C
+#define AUD_DSP_WR_QPEAK__W 16
+#define AUD_DSP_WR_QPEAK__M 0xFFFF
+#define AUD_DSP_WR_QPEAK__PRE 0x0
+
+#define AUD_DSP_WR_QPEAK_SRC_QP__B 8
+#define AUD_DSP_WR_QPEAK_SRC_QP__W 8
+#define AUD_DSP_WR_QPEAK_SRC_QP__M 0xFF00
+#define AUD_DSP_WR_QPEAK_SRC_QP__PRE 0x0
+#define AUD_DSP_WR_QPEAK_SRC_QP_MONO 0x0
+#define AUD_DSP_WR_QPEAK_SRC_QP_STEREO_AB 0x100
+#define AUD_DSP_WR_QPEAK_SRC_QP_STEREO_A 0x300
+#define AUD_DSP_WR_QPEAK_SRC_QP_STEREO_B 0x400
+
+#define AUD_DSP_WR_QPEAK_MAT_QP__B 0
+#define AUD_DSP_WR_QPEAK_MAT_QP__W 8
+#define AUD_DSP_WR_QPEAK_MAT_QP__M 0xFF
+#define AUD_DSP_WR_QPEAK_MAT_QP__PRE 0x0
+#define AUD_DSP_WR_QPEAK_MAT_QP_SOUND_A 0x0
+#define AUD_DSP_WR_QPEAK_MAT_QP_SOUND_B 0x10
+#define AUD_DSP_WR_QPEAK_MAT_QP_STEREO 0x20
+#define AUD_DSP_WR_QPEAK_MAT_QP_MONO 0x30
+
+#define AUD_DSP_RD_QPEAK_L__A 0x1040019
+#define AUD_DSP_RD_QPEAK_L__W 16
+#define AUD_DSP_RD_QPEAK_L__M 0xFFFF
+#define AUD_DSP_RD_QPEAK_L__PRE 0x0
+
+#define AUD_DSP_RD_QPEAK_R__A 0x104001A
+#define AUD_DSP_RD_QPEAK_R__W 16
+#define AUD_DSP_RD_QPEAK_R__M 0xFFFF
+#define AUD_DSP_RD_QPEAK_R__PRE 0x0
+
+#define AUD_DSP_WR_BEEPER__A 0x1050014
+#define AUD_DSP_WR_BEEPER__W 16
+#define AUD_DSP_WR_BEEPER__M 0xFFFF
+#define AUD_DSP_WR_BEEPER__PRE 0x0
+
+#define AUD_DSP_WR_BEEPER_BEEP_VOLUME__B 8
+#define AUD_DSP_WR_BEEPER_BEEP_VOLUME__W 7
+#define AUD_DSP_WR_BEEPER_BEEP_VOLUME__M 0x7F00
+#define AUD_DSP_WR_BEEPER_BEEP_VOLUME__PRE 0x0
+
+#define AUD_DSP_WR_BEEPER_BEEP_FREQUENCY__B 0
+#define AUD_DSP_WR_BEEPER_BEEP_FREQUENCY__W 7
+#define AUD_DSP_WR_BEEPER_BEEP_FREQUENCY__M 0x7F
+#define AUD_DSP_WR_BEEPER_BEEP_FREQUENCY__PRE 0x0
+
+#define AUD_DEM_WR_I2S_CONFIG2__A 0x1030050
+#define AUD_DEM_WR_I2S_CONFIG2__W 16
+#define AUD_DEM_WR_I2S_CONFIG2__M 0xFFFF
+#define AUD_DEM_WR_I2S_CONFIG2__PRE 0x0
+
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_CL_POL__B 6
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_CL_POL__W 1
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_CL_POL__M 0x40
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_CL_POL__PRE 0x0
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_CL_POL_NORMAL 0x0
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_CL_POL_INVERTED 0x40
+
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_ENABLE__B 4
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_ENABLE__W 1
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_ENABLE__M 0x10
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_ENABLE__PRE 0x0
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_ENABLE_DISABLE 0x0
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_ENABLE_ENABLE 0x10
+
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_SLV_MST__B 3
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_SLV_MST__W 1
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_SLV_MST__M 0x8
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_SLV_MST__PRE 0x0
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_SLV_MST_MASTER 0x0
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_SLV_MST_SLAVE 0x8
+
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_WS_POL__B 2
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_WS_POL__W 1
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_WS_POL__M 0x4
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_WS_POL__PRE 0x0
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_WS_POL_LEFT_LOW 0x0
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_WS_POL_LEFT_HIGH 0x4
+
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_WS_MODE__B 1
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_WS_MODE__W 1
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_WS_MODE__M 0x2
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_WS_MODE__PRE 0x0
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_WS_MODE_NO_DELAY 0x0
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_WS_MODE_DELAY 0x2
+
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_WORD_LEN__B 0
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_WORD_LEN__W 1
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_WORD_LEN__M 0x1
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_WORD_LEN__PRE 0x0
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_WORD_LEN_BIT_32 0x0
+#define AUD_DEM_WR_I2S_CONFIG2_I2S_WORD_LEN_BIT_16 0x1
+
+#define AUD_DSP_WR_I2S_OUT_FS__A 0x105002A
+#define AUD_DSP_WR_I2S_OUT_FS__W 16
+#define AUD_DSP_WR_I2S_OUT_FS__M 0xFFFF
+#define AUD_DSP_WR_I2S_OUT_FS__PRE 0x0
+
+#define AUD_DSP_WR_I2S_OUT_FS_FS_OUT__B 0
+#define AUD_DSP_WR_I2S_OUT_FS_FS_OUT__W 16
+#define AUD_DSP_WR_I2S_OUT_FS_FS_OUT__M 0xFFFF
+#define AUD_DSP_WR_I2S_OUT_FS_FS_OUT__PRE 0x0
+
+#define AUD_DSP_WR_AV_SYNC__A 0x105002B
+#define AUD_DSP_WR_AV_SYNC__W 16
+#define AUD_DSP_WR_AV_SYNC__M 0xFFFF
+#define AUD_DSP_WR_AV_SYNC__PRE 0x0
+
+#define AUD_DSP_WR_AV_SYNC_AV_ON__B 15
+#define AUD_DSP_WR_AV_SYNC_AV_ON__W 1
+#define AUD_DSP_WR_AV_SYNC_AV_ON__M 0x8000
+#define AUD_DSP_WR_AV_SYNC_AV_ON__PRE 0x0
+#define AUD_DSP_WR_AV_SYNC_AV_ON_DISABLE 0x0
+#define AUD_DSP_WR_AV_SYNC_AV_ON_ENABLE 0x8000
+
+#define AUD_DSP_WR_AV_SYNC_AV_AUTO_FREQ__B 14
+#define AUD_DSP_WR_AV_SYNC_AV_AUTO_FREQ__W 1
+#define AUD_DSP_WR_AV_SYNC_AV_AUTO_FREQ__M 0x4000
+#define AUD_DSP_WR_AV_SYNC_AV_AUTO_FREQ__PRE 0x0
+#define AUD_DSP_WR_AV_SYNC_AV_AUTO_FREQ_MONOCHROME 0x0
+#define AUD_DSP_WR_AV_SYNC_AV_AUTO_FREQ_NTSC 0x4000
+
+#define AUD_DSP_WR_AV_SYNC_AV_STD_SEL__B 0
+#define AUD_DSP_WR_AV_SYNC_AV_STD_SEL__W 2
+#define AUD_DSP_WR_AV_SYNC_AV_STD_SEL__M 0x3
+#define AUD_DSP_WR_AV_SYNC_AV_STD_SEL__PRE 0x0
+#define AUD_DSP_WR_AV_SYNC_AV_STD_SEL_AUTO 0x0
+#define AUD_DSP_WR_AV_SYNC_AV_STD_SEL_PAL_SECAM 0x1
+#define AUD_DSP_WR_AV_SYNC_AV_STD_SEL_NTSC 0x2
+#define AUD_DSP_WR_AV_SYNC_AV_STD_SEL_MONOCHROME 0x3
+
+#define AUD_DSP_RD_STATUS2__A 0x104007B
+#define AUD_DSP_RD_STATUS2__W 16
+#define AUD_DSP_RD_STATUS2__M 0xFFFF
+#define AUD_DSP_RD_STATUS2__PRE 0x0
+
+#define AUD_DSP_RD_STATUS2_AV_ACTIVE__B 15
+#define AUD_DSP_RD_STATUS2_AV_ACTIVE__W 1
+#define AUD_DSP_RD_STATUS2_AV_ACTIVE__M 0x8000
+#define AUD_DSP_RD_STATUS2_AV_ACTIVE__PRE 0x0
+#define AUD_DSP_RD_STATUS2_AV_ACTIVE_NO_SYNC 0x0
+#define AUD_DSP_RD_STATUS2_AV_ACTIVE_SYNC_ACTIVE 0x8000
+
+#define AUD_DSP_RD_XDFP_FW__A 0x104001D
+#define AUD_DSP_RD_XDFP_FW__W 16
+#define AUD_DSP_RD_XDFP_FW__M 0xFFFF
+#define AUD_DSP_RD_XDFP_FW__PRE 0x344
+
+#define AUD_DSP_RD_XDFP_FW_DSP_FW_REV__B 0
+#define AUD_DSP_RD_XDFP_FW_DSP_FW_REV__W 16
+#define AUD_DSP_RD_XDFP_FW_DSP_FW_REV__M 0xFFFF
+#define AUD_DSP_RD_XDFP_FW_DSP_FW_REV__PRE 0x344
+
+#define AUD_DSP_RD_XFP_FW__A 0x10404B8
+#define AUD_DSP_RD_XFP_FW__W 16
+#define AUD_DSP_RD_XFP_FW__M 0xFFFF
+#define AUD_DSP_RD_XFP_FW__PRE 0x42
+
+#define AUD_DSP_RD_XFP_FW_FP_FW_REV__B 0
+#define AUD_DSP_RD_XFP_FW_FP_FW_REV__W 16
+#define AUD_DSP_RD_XFP_FW_FP_FW_REV__M 0xFFFF
+#define AUD_DSP_RD_XFP_FW_FP_FW_REV__PRE 0x42
+
+#define AUD_DEM_WR_DCO_B_HI__A 0x103009B
+#define AUD_DEM_WR_DCO_B_HI__W 16
+#define AUD_DEM_WR_DCO_B_HI__M 0xFFFF
+#define AUD_DEM_WR_DCO_B_HI__PRE 0x0
+
+#define AUD_DEM_WR_DCO_B_LO__A 0x1030093
+#define AUD_DEM_WR_DCO_B_LO__W 16
+#define AUD_DEM_WR_DCO_B_LO__M 0xFFFF
+#define AUD_DEM_WR_DCO_B_LO__PRE 0x0
+
+#define AUD_DEM_WR_DCO_A_HI__A 0x10300AB
+#define AUD_DEM_WR_DCO_A_HI__W 16
+#define AUD_DEM_WR_DCO_A_HI__M 0xFFFF
+#define AUD_DEM_WR_DCO_A_HI__PRE 0x0
+
+#define AUD_DEM_WR_DCO_A_LO__A 0x10300A3
+#define AUD_DEM_WR_DCO_A_LO__W 16
+#define AUD_DEM_WR_DCO_A_LO__M 0xFFFF
+#define AUD_DEM_WR_DCO_A_LO__PRE 0x0
+#define AUD_DEM_WR_NICAM_THRSHLD__A 0x1030021
+#define AUD_DEM_WR_NICAM_THRSHLD__W 16
+#define AUD_DEM_WR_NICAM_THRSHLD__M 0xFFFF
+#define AUD_DEM_WR_NICAM_THRSHLD__PRE 0x2BC
+
+#define AUD_DEM_WR_NICAM_THRSHLD_NICAM_THLD__B 0
+#define AUD_DEM_WR_NICAM_THRSHLD_NICAM_THLD__W 12
+#define AUD_DEM_WR_NICAM_THRSHLD_NICAM_THLD__M 0xFFF
+#define AUD_DEM_WR_NICAM_THRSHLD_NICAM_THLD__PRE 0x2BC
+
+#define AUD_DEM_WR_A2_THRSHLD__A 0x1030022
+#define AUD_DEM_WR_A2_THRSHLD__W 16
+#define AUD_DEM_WR_A2_THRSHLD__M 0xFFFF
+#define AUD_DEM_WR_A2_THRSHLD__PRE 0x190
+
+#define AUD_DEM_WR_A2_THRSHLD_A2_THLD__B 0
+#define AUD_DEM_WR_A2_THRSHLD_A2_THLD__W 12
+#define AUD_DEM_WR_A2_THRSHLD_A2_THLD__M 0xFFF
+#define AUD_DEM_WR_A2_THRSHLD_A2_THLD__PRE 0x190
+
+#define AUD_DEM_WR_BTSC_THRSHLD__A 0x1030023
+#define AUD_DEM_WR_BTSC_THRSHLD__W 16
+#define AUD_DEM_WR_BTSC_THRSHLD__M 0xFFFF
+#define AUD_DEM_WR_BTSC_THRSHLD__PRE 0xC
+
+#define AUD_DEM_WR_BTSC_THRSHLD_BTSC_THLD__B 0
+#define AUD_DEM_WR_BTSC_THRSHLD_BTSC_THLD__W 12
+#define AUD_DEM_WR_BTSC_THRSHLD_BTSC_THLD__M 0xFFF
+#define AUD_DEM_WR_BTSC_THRSHLD_BTSC_THLD__PRE 0xC
+
+#define AUD_DEM_WR_CM_A_THRSHLD__A 0x1030024
+#define AUD_DEM_WR_CM_A_THRSHLD__W 16
+#define AUD_DEM_WR_CM_A_THRSHLD__M 0xFFFF
+#define AUD_DEM_WR_CM_A_THRSHLD__PRE 0x2A
+
+#define AUD_DEM_WR_CM_A_THRSHLD_CM_A_THLD__B 0
+#define AUD_DEM_WR_CM_A_THRSHLD_CM_A_THLD__W 12
+#define AUD_DEM_WR_CM_A_THRSHLD_CM_A_THLD__M 0xFFF
+#define AUD_DEM_WR_CM_A_THRSHLD_CM_A_THLD__PRE 0x2A
+
+#define AUD_DEM_WR_CM_B_THRSHLD__A 0x1030025
+#define AUD_DEM_WR_CM_B_THRSHLD__W 16
+#define AUD_DEM_WR_CM_B_THRSHLD__M 0xFFFF
+#define AUD_DEM_WR_CM_B_THRSHLD__PRE 0x2A
+
+#define AUD_DEM_WR_CM_B_THRSHLD_CM_B_THLD__B 0
+#define AUD_DEM_WR_CM_B_THRSHLD_CM_B_THLD__W 12
+#define AUD_DEM_WR_CM_B_THRSHLD_CM_B_THLD__M 0xFFF
+#define AUD_DEM_WR_CM_B_THRSHLD_CM_B_THLD__PRE 0x2A
+
+#define AUD_DEM_RD_NIC_C_AD_BITS__A 0x1020023
+#define AUD_DEM_RD_NIC_C_AD_BITS__W 16
+#define AUD_DEM_RD_NIC_C_AD_BITS__M 0xFFFF
+#define AUD_DEM_RD_NIC_C_AD_BITS__PRE 0x0
+
+#define AUD_DEM_RD_NIC_C_AD_BITS_NICAM_SYNC__B 0
+#define AUD_DEM_RD_NIC_C_AD_BITS_NICAM_SYNC__W 1
+#define AUD_DEM_RD_NIC_C_AD_BITS_NICAM_SYNC__M 0x1
+#define AUD_DEM_RD_NIC_C_AD_BITS_NICAM_SYNC__PRE 0x0
+#define AUD_DEM_RD_NIC_C_AD_BITS_NICAM_SYNC_NOT_SYNCED 0x0
+#define AUD_DEM_RD_NIC_C_AD_BITS_NICAM_SYNC_SYNCED 0x1
+
+#define AUD_DEM_RD_NIC_C_AD_BITS_C__B 1
+#define AUD_DEM_RD_NIC_C_AD_BITS_C__W 4
+#define AUD_DEM_RD_NIC_C_AD_BITS_C__M 0x1E
+#define AUD_DEM_RD_NIC_C_AD_BITS_C__PRE 0x0
+
+#define AUD_DEM_RD_NIC_C_AD_BITS_ADD_BIT_LO__B 5
+#define AUD_DEM_RD_NIC_C_AD_BITS_ADD_BIT_LO__W 3
+#define AUD_DEM_RD_NIC_C_AD_BITS_ADD_BIT_LO__M 0xE0
+#define AUD_DEM_RD_NIC_C_AD_BITS_ADD_BIT_LO__PRE 0x0
+
+#define AUD_DEM_RD_NIC_ADD_BITS_HI__A 0x1020038
+#define AUD_DEM_RD_NIC_ADD_BITS_HI__W 16
+#define AUD_DEM_RD_NIC_ADD_BITS_HI__M 0xFFFF
+#define AUD_DEM_RD_NIC_ADD_BITS_HI__PRE 0x0
+
+#define AUD_DEM_RD_NIC_ADD_BITS_HI_ADD_BIT_HI__B 0
+#define AUD_DEM_RD_NIC_ADD_BITS_HI_ADD_BIT_HI__W 8
+#define AUD_DEM_RD_NIC_ADD_BITS_HI_ADD_BIT_HI__M 0xFF
+#define AUD_DEM_RD_NIC_ADD_BITS_HI_ADD_BIT_HI__PRE 0x0
+
+#define AUD_DEM_RD_NIC_CIB__A 0x1020038
+#define AUD_DEM_RD_NIC_CIB__W 16
+#define AUD_DEM_RD_NIC_CIB__M 0xFFFF
+#define AUD_DEM_RD_NIC_CIB__PRE 0x0
+
+#define AUD_DEM_RD_NIC_CIB_CIB2__B 0
+#define AUD_DEM_RD_NIC_CIB_CIB2__W 1
+#define AUD_DEM_RD_NIC_CIB_CIB2__M 0x1
+#define AUD_DEM_RD_NIC_CIB_CIB2__PRE 0x0
+
+#define AUD_DEM_RD_NIC_CIB_CIB1__B 1
+#define AUD_DEM_RD_NIC_CIB_CIB1__W 1
+#define AUD_DEM_RD_NIC_CIB_CIB1__M 0x2
+#define AUD_DEM_RD_NIC_CIB_CIB1__PRE 0x0
+
+#define AUD_DEM_RD_NIC_ERROR_RATE__A 0x1020057
+#define AUD_DEM_RD_NIC_ERROR_RATE__W 16
+#define AUD_DEM_RD_NIC_ERROR_RATE__M 0xFFFF
+#define AUD_DEM_RD_NIC_ERROR_RATE__PRE 0x0
+
+#define AUD_DEM_RD_NIC_ERROR_RATE_ERROR_RATE__B 0
+#define AUD_DEM_RD_NIC_ERROR_RATE_ERROR_RATE__W 12
+#define AUD_DEM_RD_NIC_ERROR_RATE_ERROR_RATE__M 0xFFF
+#define AUD_DEM_RD_NIC_ERROR_RATE_ERROR_RATE__PRE 0x0
+
+#define AUD_DEM_WR_FM_DEEMPH__A 0x103000F
+#define AUD_DEM_WR_FM_DEEMPH__W 16
+#define AUD_DEM_WR_FM_DEEMPH__M 0xFFFF
+#define AUD_DEM_WR_FM_DEEMPH__PRE 0x0
+#define AUD_DEM_WR_FM_DEEMPH_50US 0x0
+#define AUD_DEM_WR_FM_DEEMPH_75US 0x1
+#define AUD_DEM_WR_FM_DEEMPH_OFF 0x3F
+
+#define AUD_DEM_WR_FM_MATRIX__A 0x103006F
+#define AUD_DEM_WR_FM_MATRIX__W 16
+#define AUD_DEM_WR_FM_MATRIX__M 0xFFFF
+#define AUD_DEM_WR_FM_MATRIX__PRE 0x0
+#define AUD_DEM_WR_FM_MATRIX_NO_MATRIX 0x0
+#define AUD_DEM_WR_FM_MATRIX_GERMAN_MATRIX 0x1
+#define AUD_DEM_WR_FM_MATRIX_KOREAN_MATRIX 0x2
+#define AUD_DEM_WR_FM_MATRIX_SOUND_A 0x3
+#define AUD_DEM_WR_FM_MATRIX_SOUND_B 0x4
+
+#define AUD_DSP_RD_FM_IDENT_VALUE__A 0x1040018
+#define AUD_DSP_RD_FM_IDENT_VALUE__W 16
+#define AUD_DSP_RD_FM_IDENT_VALUE__M 0xFFFF
+#define AUD_DSP_RD_FM_IDENT_VALUE__PRE 0x0
+
+#define AUD_DSP_RD_FM_IDENT_VALUE_FM_IDENT__B 8
+#define AUD_DSP_RD_FM_IDENT_VALUE_FM_IDENT__W 8
+#define AUD_DSP_RD_FM_IDENT_VALUE_FM_IDENT__M 0xFF00
+#define AUD_DSP_RD_FM_IDENT_VALUE_FM_IDENT__PRE 0x0
+
+#define AUD_DSP_RD_FM_DC_LEVEL_A__A 0x104001B
+#define AUD_DSP_RD_FM_DC_LEVEL_A__W 16
+#define AUD_DSP_RD_FM_DC_LEVEL_A__M 0xFFFF
+#define AUD_DSP_RD_FM_DC_LEVEL_A__PRE 0x0
+
+#define AUD_DSP_RD_FM_DC_LEVEL_A_FM_DC_LEV_A__B 0
+#define AUD_DSP_RD_FM_DC_LEVEL_A_FM_DC_LEV_A__W 16
+#define AUD_DSP_RD_FM_DC_LEVEL_A_FM_DC_LEV_A__M 0xFFFF
+#define AUD_DSP_RD_FM_DC_LEVEL_A_FM_DC_LEV_A__PRE 0x0
+
+#define AUD_DSP_RD_FM_DC_LEVEL_B__A 0x104001C
+#define AUD_DSP_RD_FM_DC_LEVEL_B__W 16
+#define AUD_DSP_RD_FM_DC_LEVEL_B__M 0xFFFF
+#define AUD_DSP_RD_FM_DC_LEVEL_B__PRE 0x0
+
+#define AUD_DSP_RD_FM_DC_LEVEL_B_FM_DC_LEV_B__B 0
+#define AUD_DSP_RD_FM_DC_LEVEL_B_FM_DC_LEV_B__W 16
+#define AUD_DSP_RD_FM_DC_LEVEL_B_FM_DC_LEV_B__M 0xFFFF
+#define AUD_DSP_RD_FM_DC_LEVEL_B_FM_DC_LEV_B__PRE 0x0
+
+#define AUD_DEM_WR_FM_DC_NOTCH_SW__A 0x1030017
+#define AUD_DEM_WR_FM_DC_NOTCH_SW__W 16
+#define AUD_DEM_WR_FM_DC_NOTCH_SW__M 0xFFFF
+#define AUD_DEM_WR_FM_DC_NOTCH_SW__PRE 0x0
+
+#define AUD_DEM_WR_FM_DC_NOTCH_SW_FM_DC_NO_SW__B 0
+#define AUD_DEM_WR_FM_DC_NOTCH_SW_FM_DC_NO_SW__W 16
+#define AUD_DEM_WR_FM_DC_NOTCH_SW_FM_DC_NO_SW__M 0xFFFF
+#define AUD_DEM_WR_FM_DC_NOTCH_SW_FM_DC_NO_SW__PRE 0x0
+#define AUD_DEM_WR_FM_DC_NOTCH_SW_FM_DC_NO_SW_ON 0x0
+#define AUD_DEM_WR_FM_DC_NOTCH_SW_FM_DC_NO_SW_OFF 0x3F
+
+#define AUD_DSP_WR_SYNC_OUT__A 0x1050026
+#define AUD_DSP_WR_SYNC_OUT__W 16
+#define AUD_DSP_WR_SYNC_OUT__M 0xFFFF
+#define AUD_DSP_WR_SYNC_OUT__PRE 0x0
+#define AUD_DSP_WR_SYNC_OUT_OFF 0x0
+#define AUD_DSP_WR_SYNC_OUT_SYNCHRONOUS 0x1
+
+#define AUD_XFP_DRAM_1K__A 0x1060000
+#define AUD_XFP_DRAM_1K__W 16
+#define AUD_XFP_DRAM_1K__M 0xFFFF
+#define AUD_XFP_DRAM_1K__PRE 0x0
+#define AUD_XFP_DRAM_1K_D__B 0
+#define AUD_XFP_DRAM_1K_D__W 16
+#define AUD_XFP_DRAM_1K_D__M 0xFFFF
+#define AUD_XFP_DRAM_1K_D__PRE 0x0
+
+#define AUD_XFP_PRAM_4K__A 0x1070000
+#define AUD_XFP_PRAM_4K__W 16
+#define AUD_XFP_PRAM_4K__M 0xFFFF
+#define AUD_XFP_PRAM_4K__PRE 0x0
+#define AUD_XFP_PRAM_4K_D__B 0
+#define AUD_XFP_PRAM_4K_D__W 16
+#define AUD_XFP_PRAM_4K_D__M 0xFFFF
+#define AUD_XFP_PRAM_4K_D__PRE 0x0
+
+#define AUD_XDFP_DRAM_1K__A 0x1080000
+#define AUD_XDFP_DRAM_1K__W 16
+#define AUD_XDFP_DRAM_1K__M 0xFFFF
+#define AUD_XDFP_DRAM_1K__PRE 0x0
+#define AUD_XDFP_DRAM_1K_D__B 0
+#define AUD_XDFP_DRAM_1K_D__W 16
+#define AUD_XDFP_DRAM_1K_D__M 0xFFFF
+#define AUD_XDFP_DRAM_1K_D__PRE 0x0
+
+#define AUD_XDFP_PRAM_4K__A 0x1090000
+#define AUD_XDFP_PRAM_4K__W 16
+#define AUD_XDFP_PRAM_4K__M 0xFFFF
+#define AUD_XDFP_PRAM_4K__PRE 0x0
+#define AUD_XDFP_PRAM_4K_D__B 0
+#define AUD_XDFP_PRAM_4K_D__W 16
+#define AUD_XDFP_PRAM_4K_D__M 0xFFFF
+#define AUD_XDFP_PRAM_4K_D__PRE 0x0
+
+#define FEC_COMM_EXEC__A 0x2400000
+#define FEC_COMM_EXEC__W 2
+#define FEC_COMM_EXEC__M 0x3
+#define FEC_COMM_EXEC__PRE 0x0
+#define FEC_COMM_EXEC_STOP 0x0
+#define FEC_COMM_EXEC_ACTIVE 0x1
+#define FEC_COMM_EXEC_HOLD 0x2
+
+#define FEC_COMM_MB__A 0x2400002
+#define FEC_COMM_MB__W 16
+#define FEC_COMM_MB__M 0xFFFF
+#define FEC_COMM_MB__PRE 0x0
+#define FEC_COMM_INT_REQ__A 0x2400003
+#define FEC_COMM_INT_REQ__W 16
+#define FEC_COMM_INT_REQ__M 0xFFFF
+#define FEC_COMM_INT_REQ__PRE 0x0
+#define FEC_COMM_INT_REQ_OC_REQ__B 0
+#define FEC_COMM_INT_REQ_OC_REQ__W 1
+#define FEC_COMM_INT_REQ_OC_REQ__M 0x1
+#define FEC_COMM_INT_REQ_OC_REQ__PRE 0x0
+#define FEC_COMM_INT_REQ_RS_REQ__B 1
+#define FEC_COMM_INT_REQ_RS_REQ__W 1
+#define FEC_COMM_INT_REQ_RS_REQ__M 0x2
+#define FEC_COMM_INT_REQ_RS_REQ__PRE 0x0
+#define FEC_COMM_INT_REQ_DI_REQ__B 2
+#define FEC_COMM_INT_REQ_DI_REQ__W 1
+#define FEC_COMM_INT_REQ_DI_REQ__M 0x4
+#define FEC_COMM_INT_REQ_DI_REQ__PRE 0x0
+
+#define FEC_COMM_INT_STA__A 0x2400005
+#define FEC_COMM_INT_STA__W 16
+#define FEC_COMM_INT_STA__M 0xFFFF
+#define FEC_COMM_INT_STA__PRE 0x0
+#define FEC_COMM_INT_MSK__A 0x2400006
+#define FEC_COMM_INT_MSK__W 16
+#define FEC_COMM_INT_MSK__M 0xFFFF
+#define FEC_COMM_INT_MSK__PRE 0x0
+#define FEC_COMM_INT_STM__A 0x2400007
+#define FEC_COMM_INT_STM__W 16
+#define FEC_COMM_INT_STM__M 0xFFFF
+#define FEC_COMM_INT_STM__PRE 0x0
+
+#define FEC_TOP_COMM_EXEC__A 0x2410000
+#define FEC_TOP_COMM_EXEC__W 2
+#define FEC_TOP_COMM_EXEC__M 0x3
+#define FEC_TOP_COMM_EXEC__PRE 0x0
+#define FEC_TOP_COMM_EXEC_STOP 0x0
+#define FEC_TOP_COMM_EXEC_ACTIVE 0x1
+#define FEC_TOP_COMM_EXEC_HOLD 0x2
+
+#define FEC_TOP_ANNEX__A 0x2410010
+#define FEC_TOP_ANNEX__W 2
+#define FEC_TOP_ANNEX__M 0x3
+#define FEC_TOP_ANNEX__PRE 0x0
+#define FEC_TOP_ANNEX_A 0x0
+#define FEC_TOP_ANNEX_B 0x1
+#define FEC_TOP_ANNEX_C 0x2
+#define FEC_TOP_ANNEX_D 0x3
+
+#define FEC_DI_COMM_EXEC__A 0x2420000
+#define FEC_DI_COMM_EXEC__W 2
+#define FEC_DI_COMM_EXEC__M 0x3
+#define FEC_DI_COMM_EXEC__PRE 0x0
+#define FEC_DI_COMM_EXEC_STOP 0x0
+#define FEC_DI_COMM_EXEC_ACTIVE 0x1
+#define FEC_DI_COMM_EXEC_HOLD 0x2
+
+#define FEC_DI_COMM_MB__A 0x2420002
+#define FEC_DI_COMM_MB__W 2
+#define FEC_DI_COMM_MB__M 0x3
+#define FEC_DI_COMM_MB__PRE 0x0
+#define FEC_DI_COMM_MB_CTL__B 0
+#define FEC_DI_COMM_MB_CTL__W 1
+#define FEC_DI_COMM_MB_CTL__M 0x1
+#define FEC_DI_COMM_MB_CTL__PRE 0x0
+#define FEC_DI_COMM_MB_CTL_OFF 0x0
+#define FEC_DI_COMM_MB_CTL_ON 0x1
+#define FEC_DI_COMM_MB_OBS__B 1
+#define FEC_DI_COMM_MB_OBS__W 1
+#define FEC_DI_COMM_MB_OBS__M 0x2
+#define FEC_DI_COMM_MB_OBS__PRE 0x0
+#define FEC_DI_COMM_MB_OBS_OFF 0x0
+#define FEC_DI_COMM_MB_OBS_ON 0x2
+
+#define FEC_DI_COMM_INT_REQ__A 0x2420003
+#define FEC_DI_COMM_INT_REQ__W 1
+#define FEC_DI_COMM_INT_REQ__M 0x1
+#define FEC_DI_COMM_INT_REQ__PRE 0x0
+#define FEC_DI_COMM_INT_STA__A 0x2420005
+#define FEC_DI_COMM_INT_STA__W 2
+#define FEC_DI_COMM_INT_STA__M 0x3
+#define FEC_DI_COMM_INT_STA__PRE 0x0
+
+#define FEC_DI_COMM_INT_STA_STAT_INT__B 0
+#define FEC_DI_COMM_INT_STA_STAT_INT__W 1
+#define FEC_DI_COMM_INT_STA_STAT_INT__M 0x1
+#define FEC_DI_COMM_INT_STA_STAT_INT__PRE 0x0
+
+#define FEC_DI_COMM_INT_STA_TIMEOUT_INT__B 1
+#define FEC_DI_COMM_INT_STA_TIMEOUT_INT__W 1
+#define FEC_DI_COMM_INT_STA_TIMEOUT_INT__M 0x2
+#define FEC_DI_COMM_INT_STA_TIMEOUT_INT__PRE 0x0
+
+#define FEC_DI_COMM_INT_MSK__A 0x2420006
+#define FEC_DI_COMM_INT_MSK__W 2
+#define FEC_DI_COMM_INT_MSK__M 0x3
+#define FEC_DI_COMM_INT_MSK__PRE 0x0
+#define FEC_DI_COMM_INT_MSK_STAT_INT__B 0
+#define FEC_DI_COMM_INT_MSK_STAT_INT__W 1
+#define FEC_DI_COMM_INT_MSK_STAT_INT__M 0x1
+#define FEC_DI_COMM_INT_MSK_STAT_INT__PRE 0x0
+#define FEC_DI_COMM_INT_MSK_TIMEOUT_INT__B 1
+#define FEC_DI_COMM_INT_MSK_TIMEOUT_INT__W 1
+#define FEC_DI_COMM_INT_MSK_TIMEOUT_INT__M 0x2
+#define FEC_DI_COMM_INT_MSK_TIMEOUT_INT__PRE 0x0
+
+#define FEC_DI_COMM_INT_STM__A 0x2420007
+#define FEC_DI_COMM_INT_STM__W 2
+#define FEC_DI_COMM_INT_STM__M 0x3
+#define FEC_DI_COMM_INT_STM__PRE 0x0
+#define FEC_DI_COMM_INT_STM_STAT_INT__B 0
+#define FEC_DI_COMM_INT_STM_STAT_INT__W 1
+#define FEC_DI_COMM_INT_STM_STAT_INT__M 0x1
+#define FEC_DI_COMM_INT_STM_STAT_INT__PRE 0x0
+#define FEC_DI_COMM_INT_STM_TIMEOUT_INT__B 1
+#define FEC_DI_COMM_INT_STM_TIMEOUT_INT__W 1
+#define FEC_DI_COMM_INT_STM_TIMEOUT_INT__M 0x2
+#define FEC_DI_COMM_INT_STM_TIMEOUT_INT__PRE 0x0
+
+#define FEC_DI_STATUS__A 0x2420010
+#define FEC_DI_STATUS__W 1
+#define FEC_DI_STATUS__M 0x1
+#define FEC_DI_STATUS__PRE 0x0
+#define FEC_DI_MODE__A 0x2420011
+#define FEC_DI_MODE__W 3
+#define FEC_DI_MODE__M 0x7
+#define FEC_DI_MODE__PRE 0x0
+
+#define FEC_DI_MODE_NO_SYNC__B 0
+#define FEC_DI_MODE_NO_SYNC__W 1
+#define FEC_DI_MODE_NO_SYNC__M 0x1
+#define FEC_DI_MODE_NO_SYNC__PRE 0x0
+
+#define FEC_DI_MODE_IGNORE_LOST_SYNC__B 1
+#define FEC_DI_MODE_IGNORE_LOST_SYNC__W 1
+#define FEC_DI_MODE_IGNORE_LOST_SYNC__M 0x2
+#define FEC_DI_MODE_IGNORE_LOST_SYNC__PRE 0x0
+
+#define FEC_DI_MODE_IGNORE_TIMEOUT__B 2
+#define FEC_DI_MODE_IGNORE_TIMEOUT__W 1
+#define FEC_DI_MODE_IGNORE_TIMEOUT__M 0x4
+#define FEC_DI_MODE_IGNORE_TIMEOUT__PRE 0x0
+
+#define FEC_DI_CONTROL_WORD__A 0x2420012
+#define FEC_DI_CONTROL_WORD__W 4
+#define FEC_DI_CONTROL_WORD__M 0xF
+#define FEC_DI_CONTROL_WORD__PRE 0x0
+
+#define FEC_DI_RESTART__A 0x2420013
+#define FEC_DI_RESTART__W 1
+#define FEC_DI_RESTART__M 0x1
+#define FEC_DI_RESTART__PRE 0x0
+
+#define FEC_DI_TIMEOUT_LO__A 0x2420014
+#define FEC_DI_TIMEOUT_LO__W 16
+#define FEC_DI_TIMEOUT_LO__M 0xFFFF
+#define FEC_DI_TIMEOUT_LO__PRE 0x0
+
+#define FEC_DI_TIMEOUT_HI__A 0x2420015
+#define FEC_DI_TIMEOUT_HI__W 8
+#define FEC_DI_TIMEOUT_HI__M 0xFF
+#define FEC_DI_TIMEOUT_HI__PRE 0xA
+
+#define FEC_RS_COMM_EXEC__A 0x2430000
+#define FEC_RS_COMM_EXEC__W 2
+#define FEC_RS_COMM_EXEC__M 0x3
+#define FEC_RS_COMM_EXEC__PRE 0x0
+#define FEC_RS_COMM_EXEC_STOP 0x0
+#define FEC_RS_COMM_EXEC_ACTIVE 0x1
+#define FEC_RS_COMM_EXEC_HOLD 0x2
+
+#define FEC_RS_COMM_MB__A 0x2430002
+#define FEC_RS_COMM_MB__W 2
+#define FEC_RS_COMM_MB__M 0x3
+#define FEC_RS_COMM_MB__PRE 0x0
+#define FEC_RS_COMM_MB_CTL__B 0
+#define FEC_RS_COMM_MB_CTL__W 1
+#define FEC_RS_COMM_MB_CTL__M 0x1
+#define FEC_RS_COMM_MB_CTL__PRE 0x0
+#define FEC_RS_COMM_MB_CTL_OFF 0x0
+#define FEC_RS_COMM_MB_CTL_ON 0x1
+#define FEC_RS_COMM_MB_OBS__B 1
+#define FEC_RS_COMM_MB_OBS__W 1
+#define FEC_RS_COMM_MB_OBS__M 0x2
+#define FEC_RS_COMM_MB_OBS__PRE 0x0
+#define FEC_RS_COMM_MB_OBS_OFF 0x0
+#define FEC_RS_COMM_MB_OBS_ON 0x2
+
+#define FEC_RS_COMM_INT_REQ__A 0x2430003
+#define FEC_RS_COMM_INT_REQ__W 1
+#define FEC_RS_COMM_INT_REQ__M 0x1
+#define FEC_RS_COMM_INT_REQ__PRE 0x0
+#define FEC_RS_COMM_INT_STA__A 0x2430005
+#define FEC_RS_COMM_INT_STA__W 2
+#define FEC_RS_COMM_INT_STA__M 0x3
+#define FEC_RS_COMM_INT_STA__PRE 0x0
+
+#define FEC_RS_COMM_INT_STA_FAILURE_INT__B 0
+#define FEC_RS_COMM_INT_STA_FAILURE_INT__W 1
+#define FEC_RS_COMM_INT_STA_FAILURE_INT__M 0x1
+#define FEC_RS_COMM_INT_STA_FAILURE_INT__PRE 0x0
+
+#define FEC_RS_COMM_INT_STA_MEASUREMENT_INT__B 1
+#define FEC_RS_COMM_INT_STA_MEASUREMENT_INT__W 1
+#define FEC_RS_COMM_INT_STA_MEASUREMENT_INT__M 0x2
+#define FEC_RS_COMM_INT_STA_MEASUREMENT_INT__PRE 0x0
+
+#define FEC_RS_COMM_INT_MSK__A 0x2430006
+#define FEC_RS_COMM_INT_MSK__W 2
+#define FEC_RS_COMM_INT_MSK__M 0x3
+#define FEC_RS_COMM_INT_MSK__PRE 0x0
+#define FEC_RS_COMM_INT_MSK_FAILURE_MSK__B 0
+#define FEC_RS_COMM_INT_MSK_FAILURE_MSK__W 1
+#define FEC_RS_COMM_INT_MSK_FAILURE_MSK__M 0x1
+#define FEC_RS_COMM_INT_MSK_FAILURE_MSK__PRE 0x0
+#define FEC_RS_COMM_INT_MSK_MEASUREMENT_MSK__B 1
+#define FEC_RS_COMM_INT_MSK_MEASUREMENT_MSK__W 1
+#define FEC_RS_COMM_INT_MSK_MEASUREMENT_MSK__M 0x2
+#define FEC_RS_COMM_INT_MSK_MEASUREMENT_MSK__PRE 0x0
+
+#define FEC_RS_COMM_INT_STM__A 0x2430007
+#define FEC_RS_COMM_INT_STM__W 2
+#define FEC_RS_COMM_INT_STM__M 0x3
+#define FEC_RS_COMM_INT_STM__PRE 0x0
+#define FEC_RS_COMM_INT_STM_FAILURE_MSK__B 0
+#define FEC_RS_COMM_INT_STM_FAILURE_MSK__W 1
+#define FEC_RS_COMM_INT_STM_FAILURE_MSK__M 0x1
+#define FEC_RS_COMM_INT_STM_FAILURE_MSK__PRE 0x0
+#define FEC_RS_COMM_INT_STM_MEASUREMENT_MSK__B 1
+#define FEC_RS_COMM_INT_STM_MEASUREMENT_MSK__W 1
+#define FEC_RS_COMM_INT_STM_MEASUREMENT_MSK__M 0x2
+#define FEC_RS_COMM_INT_STM_MEASUREMENT_MSK__PRE 0x0
+
+#define FEC_RS_STATUS__A 0x2430010
+#define FEC_RS_STATUS__W 1
+#define FEC_RS_STATUS__M 0x1
+#define FEC_RS_STATUS__PRE 0x0
+#define FEC_RS_MODE__A 0x2430011
+#define FEC_RS_MODE__W 1
+#define FEC_RS_MODE__M 0x1
+#define FEC_RS_MODE__PRE 0x0
+
+#define FEC_RS_MODE_BYPASS__B 0
+#define FEC_RS_MODE_BYPASS__W 1
+#define FEC_RS_MODE_BYPASS__M 0x1
+#define FEC_RS_MODE_BYPASS__PRE 0x0
+
+#define FEC_RS_MEASUREMENT_PERIOD__A 0x2430012
+#define FEC_RS_MEASUREMENT_PERIOD__W 16
+#define FEC_RS_MEASUREMENT_PERIOD__M 0xFFFF
+#define FEC_RS_MEASUREMENT_PERIOD__PRE 0x1171
+
+#define FEC_RS_MEASUREMENT_PERIOD_PERIOD__B 0
+#define FEC_RS_MEASUREMENT_PERIOD_PERIOD__W 16
+#define FEC_RS_MEASUREMENT_PERIOD_PERIOD__M 0xFFFF
+#define FEC_RS_MEASUREMENT_PERIOD_PERIOD__PRE 0x1171
+
+#define FEC_RS_MEASUREMENT_PRESCALE__A 0x2430013
+#define FEC_RS_MEASUREMENT_PRESCALE__W 16
+#define FEC_RS_MEASUREMENT_PRESCALE__M 0xFFFF
+#define FEC_RS_MEASUREMENT_PRESCALE__PRE 0x1
+
+#define FEC_RS_MEASUREMENT_PRESCALE_PRESCALE__B 0
+#define FEC_RS_MEASUREMENT_PRESCALE_PRESCALE__W 16
+#define FEC_RS_MEASUREMENT_PRESCALE_PRESCALE__M 0xFFFF
+#define FEC_RS_MEASUREMENT_PRESCALE_PRESCALE__PRE 0x1
+
+#define FEC_RS_NR_BIT_ERRORS__A 0x2430014
+#define FEC_RS_NR_BIT_ERRORS__W 16
+#define FEC_RS_NR_BIT_ERRORS__M 0xFFFF
+#define FEC_RS_NR_BIT_ERRORS__PRE 0xFFFF
+
+#define FEC_RS_NR_BIT_ERRORS_FIXED_MANT__B 0
+#define FEC_RS_NR_BIT_ERRORS_FIXED_MANT__W 12
+#define FEC_RS_NR_BIT_ERRORS_FIXED_MANT__M 0xFFF
+#define FEC_RS_NR_BIT_ERRORS_FIXED_MANT__PRE 0xFFF
+
+#define FEC_RS_NR_BIT_ERRORS_EXP__B 12
+#define FEC_RS_NR_BIT_ERRORS_EXP__W 4
+#define FEC_RS_NR_BIT_ERRORS_EXP__M 0xF000
+#define FEC_RS_NR_BIT_ERRORS_EXP__PRE 0xF000
+
+#define FEC_RS_NR_SYMBOL_ERRORS__A 0x2430015
+#define FEC_RS_NR_SYMBOL_ERRORS__W 16
+#define FEC_RS_NR_SYMBOL_ERRORS__M 0xFFFF
+#define FEC_RS_NR_SYMBOL_ERRORS__PRE 0xFFFF
+
+#define FEC_RS_NR_SYMBOL_ERRORS_FIXED_MANT__B 0
+#define FEC_RS_NR_SYMBOL_ERRORS_FIXED_MANT__W 12
+#define FEC_RS_NR_SYMBOL_ERRORS_FIXED_MANT__M 0xFFF
+#define FEC_RS_NR_SYMBOL_ERRORS_FIXED_MANT__PRE 0xFFF
+
+#define FEC_RS_NR_SYMBOL_ERRORS_EXP__B 12
+#define FEC_RS_NR_SYMBOL_ERRORS_EXP__W 4
+#define FEC_RS_NR_SYMBOL_ERRORS_EXP__M 0xF000
+#define FEC_RS_NR_SYMBOL_ERRORS_EXP__PRE 0xF000
+
+#define FEC_RS_NR_PACKET_ERRORS__A 0x2430016
+#define FEC_RS_NR_PACKET_ERRORS__W 16
+#define FEC_RS_NR_PACKET_ERRORS__M 0xFFFF
+#define FEC_RS_NR_PACKET_ERRORS__PRE 0xFFFF
+
+#define FEC_RS_NR_PACKET_ERRORS_FIXED_MANT__B 0
+#define FEC_RS_NR_PACKET_ERRORS_FIXED_MANT__W 12
+#define FEC_RS_NR_PACKET_ERRORS_FIXED_MANT__M 0xFFF
+#define FEC_RS_NR_PACKET_ERRORS_FIXED_MANT__PRE 0xFFF
+
+#define FEC_RS_NR_PACKET_ERRORS_EXP__B 12
+#define FEC_RS_NR_PACKET_ERRORS_EXP__W 4
+#define FEC_RS_NR_PACKET_ERRORS_EXP__M 0xF000
+#define FEC_RS_NR_PACKET_ERRORS_EXP__PRE 0xF000
+
+#define FEC_RS_NR_FAILURES__A 0x2430017
+#define FEC_RS_NR_FAILURES__W 16
+#define FEC_RS_NR_FAILURES__M 0xFFFF
+#define FEC_RS_NR_FAILURES__PRE 0x0
+
+#define FEC_RS_NR_FAILURES_FIXED_MANT__B 0
+#define FEC_RS_NR_FAILURES_FIXED_MANT__W 12
+#define FEC_RS_NR_FAILURES_FIXED_MANT__M 0xFFF
+#define FEC_RS_NR_FAILURES_FIXED_MANT__PRE 0x0
+
+#define FEC_RS_NR_FAILURES_EXP__B 12
+#define FEC_RS_NR_FAILURES_EXP__W 4
+#define FEC_RS_NR_FAILURES_EXP__M 0xF000
+#define FEC_RS_NR_FAILURES_EXP__PRE 0x0
+
+#define FEC_OC_COMM_EXEC__A 0x2440000
+#define FEC_OC_COMM_EXEC__W 2
+#define FEC_OC_COMM_EXEC__M 0x3
+#define FEC_OC_COMM_EXEC__PRE 0x0
+#define FEC_OC_COMM_EXEC_STOP 0x0
+#define FEC_OC_COMM_EXEC_ACTIVE 0x1
+#define FEC_OC_COMM_EXEC_HOLD 0x2
+
+#define FEC_OC_COMM_MB__A 0x2440002
+#define FEC_OC_COMM_MB__W 2
+#define FEC_OC_COMM_MB__M 0x3
+#define FEC_OC_COMM_MB__PRE 0x0
+#define FEC_OC_COMM_MB_CTL__B 0
+#define FEC_OC_COMM_MB_CTL__W 1
+#define FEC_OC_COMM_MB_CTL__M 0x1
+#define FEC_OC_COMM_MB_CTL__PRE 0x0
+#define FEC_OC_COMM_MB_CTL_OFF 0x0
+#define FEC_OC_COMM_MB_CTL_ON 0x1
+#define FEC_OC_COMM_MB_OBS__B 1
+#define FEC_OC_COMM_MB_OBS__W 1
+#define FEC_OC_COMM_MB_OBS__M 0x2
+#define FEC_OC_COMM_MB_OBS__PRE 0x0
+#define FEC_OC_COMM_MB_OBS_OFF 0x0
+#define FEC_OC_COMM_MB_OBS_ON 0x2
+
+#define FEC_OC_COMM_INT_REQ__A 0x2440003
+#define FEC_OC_COMM_INT_REQ__W 1
+#define FEC_OC_COMM_INT_REQ__M 0x1
+#define FEC_OC_COMM_INT_REQ__PRE 0x0
+#define FEC_OC_COMM_INT_STA__A 0x2440005
+#define FEC_OC_COMM_INT_STA__W 8
+#define FEC_OC_COMM_INT_STA__M 0xFF
+#define FEC_OC_COMM_INT_STA__PRE 0x0
+
+#define FEC_OC_COMM_INT_STA_DPR_LOCK_INT__B 0
+#define FEC_OC_COMM_INT_STA_DPR_LOCK_INT__W 1
+#define FEC_OC_COMM_INT_STA_DPR_LOCK_INT__M 0x1
+#define FEC_OC_COMM_INT_STA_DPR_LOCK_INT__PRE 0x0
+
+#define FEC_OC_COMM_INT_STA_SNC_LOCK_INT__B 1
+#define FEC_OC_COMM_INT_STA_SNC_LOCK_INT__W 1
+#define FEC_OC_COMM_INT_STA_SNC_LOCK_INT__M 0x2
+#define FEC_OC_COMM_INT_STA_SNC_LOCK_INT__PRE 0x0
+
+#define FEC_OC_COMM_INT_STA_SNC_LOST_INT__B 2
+#define FEC_OC_COMM_INT_STA_SNC_LOST_INT__W 1
+#define FEC_OC_COMM_INT_STA_SNC_LOST_INT__M 0x4
+#define FEC_OC_COMM_INT_STA_SNC_LOST_INT__PRE 0x0
+
+#define FEC_OC_COMM_INT_STA_SNC_PAR_INT__B 3
+#define FEC_OC_COMM_INT_STA_SNC_PAR_INT__W 1
+#define FEC_OC_COMM_INT_STA_SNC_PAR_INT__M 0x8
+#define FEC_OC_COMM_INT_STA_SNC_PAR_INT__PRE 0x0
+
+#define FEC_OC_COMM_INT_STA_FIFO_FULL_INT__B 4
+#define FEC_OC_COMM_INT_STA_FIFO_FULL_INT__W 1
+#define FEC_OC_COMM_INT_STA_FIFO_FULL_INT__M 0x10
+#define FEC_OC_COMM_INT_STA_FIFO_FULL_INT__PRE 0x0
+
+#define FEC_OC_COMM_INT_STA_FIFO_EMPTY_INT__B 5
+#define FEC_OC_COMM_INT_STA_FIFO_EMPTY_INT__W 1
+#define FEC_OC_COMM_INT_STA_FIFO_EMPTY_INT__M 0x20
+#define FEC_OC_COMM_INT_STA_FIFO_EMPTY_INT__PRE 0x0
+
+#define FEC_OC_COMM_INT_STA_OCR_ACQ_INT__B 6
+#define FEC_OC_COMM_INT_STA_OCR_ACQ_INT__W 1
+#define FEC_OC_COMM_INT_STA_OCR_ACQ_INT__M 0x40
+#define FEC_OC_COMM_INT_STA_OCR_ACQ_INT__PRE 0x0
+
+#define FEC_OC_COMM_INT_STA_STAT_CHG_INT__B 7
+#define FEC_OC_COMM_INT_STA_STAT_CHG_INT__W 1
+#define FEC_OC_COMM_INT_STA_STAT_CHG_INT__M 0x80
+#define FEC_OC_COMM_INT_STA_STAT_CHG_INT__PRE 0x0
+
+#define FEC_OC_COMM_INT_MSK__A 0x2440006
+#define FEC_OC_COMM_INT_MSK__W 8
+#define FEC_OC_COMM_INT_MSK__M 0xFF
+#define FEC_OC_COMM_INT_MSK__PRE 0x0
+#define FEC_OC_COMM_INT_MSK_DPR_LOCK_MSK__B 0
+#define FEC_OC_COMM_INT_MSK_DPR_LOCK_MSK__W 1
+#define FEC_OC_COMM_INT_MSK_DPR_LOCK_MSK__M 0x1
+#define FEC_OC_COMM_INT_MSK_DPR_LOCK_MSK__PRE 0x0
+#define FEC_OC_COMM_INT_MSK_SNC_LOCK_MSK__B 1
+#define FEC_OC_COMM_INT_MSK_SNC_LOCK_MSK__W 1
+#define FEC_OC_COMM_INT_MSK_SNC_LOCK_MSK__M 0x2
+#define FEC_OC_COMM_INT_MSK_SNC_LOCK_MSK__PRE 0x0
+#define FEC_OC_COMM_INT_MSK_SNC_LOST_MSK__B 2
+#define FEC_OC_COMM_INT_MSK_SNC_LOST_MSK__W 1
+#define FEC_OC_COMM_INT_MSK_SNC_LOST_MSK__M 0x4
+#define FEC_OC_COMM_INT_MSK_SNC_LOST_MSK__PRE 0x0
+#define FEC_OC_COMM_INT_MSK_SNC_PAR_MSK__B 3
+#define FEC_OC_COMM_INT_MSK_SNC_PAR_MSK__W 1
+#define FEC_OC_COMM_INT_MSK_SNC_PAR_MSK__M 0x8
+#define FEC_OC_COMM_INT_MSK_SNC_PAR_MSK__PRE 0x0
+#define FEC_OC_COMM_INT_MSK_FIFO_FULL_MSK__B 4
+#define FEC_OC_COMM_INT_MSK_FIFO_FULL_MSK__W 1
+#define FEC_OC_COMM_INT_MSK_FIFO_FULL_MSK__M 0x10
+#define FEC_OC_COMM_INT_MSK_FIFO_FULL_MSK__PRE 0x0
+#define FEC_OC_COMM_INT_MSK_FIFO_EMPTY_MSK__B 5
+#define FEC_OC_COMM_INT_MSK_FIFO_EMPTY_MSK__W 1
+#define FEC_OC_COMM_INT_MSK_FIFO_EMPTY_MSK__M 0x20
+#define FEC_OC_COMM_INT_MSK_FIFO_EMPTY_MSK__PRE 0x0
+#define FEC_OC_COMM_INT_MSK_OCR_ACQ_MSK__B 6
+#define FEC_OC_COMM_INT_MSK_OCR_ACQ_MSK__W 1
+#define FEC_OC_COMM_INT_MSK_OCR_ACQ_MSK__M 0x40
+#define FEC_OC_COMM_INT_MSK_OCR_ACQ_MSK__PRE 0x0
+#define FEC_OC_COMM_INT_MSK_STAT_CHG_MSK__B 7
+#define FEC_OC_COMM_INT_MSK_STAT_CHG_MSK__W 1
+#define FEC_OC_COMM_INT_MSK_STAT_CHG_MSK__M 0x80
+#define FEC_OC_COMM_INT_MSK_STAT_CHG_MSK__PRE 0x0
+
+#define FEC_OC_COMM_INT_STM__A 0x2440007
+#define FEC_OC_COMM_INT_STM__W 8
+#define FEC_OC_COMM_INT_STM__M 0xFF
+#define FEC_OC_COMM_INT_STM__PRE 0x0
+#define FEC_OC_COMM_INT_STM_DPR_LOCK_MSK__B 0
+#define FEC_OC_COMM_INT_STM_DPR_LOCK_MSK__W 1
+#define FEC_OC_COMM_INT_STM_DPR_LOCK_MSK__M 0x1
+#define FEC_OC_COMM_INT_STM_DPR_LOCK_MSK__PRE 0x0
+#define FEC_OC_COMM_INT_STM_SNC_LOCK_MSK__B 1
+#define FEC_OC_COMM_INT_STM_SNC_LOCK_MSK__W 1
+#define FEC_OC_COMM_INT_STM_SNC_LOCK_MSK__M 0x2
+#define FEC_OC_COMM_INT_STM_SNC_LOCK_MSK__PRE 0x0
+#define FEC_OC_COMM_INT_STM_SNC_LOST_MSK__B 2
+#define FEC_OC_COMM_INT_STM_SNC_LOST_MSK__W 1
+#define FEC_OC_COMM_INT_STM_SNC_LOST_MSK__M 0x4
+#define FEC_OC_COMM_INT_STM_SNC_LOST_MSK__PRE 0x0
+#define FEC_OC_COMM_INT_STM_SNC_PAR_MSK__B 3
+#define FEC_OC_COMM_INT_STM_SNC_PAR_MSK__W 1
+#define FEC_OC_COMM_INT_STM_SNC_PAR_MSK__M 0x8
+#define FEC_OC_COMM_INT_STM_SNC_PAR_MSK__PRE 0x0
+#define FEC_OC_COMM_INT_STM_FIFO_FULL_MSK__B 4
+#define FEC_OC_COMM_INT_STM_FIFO_FULL_MSK__W 1
+#define FEC_OC_COMM_INT_STM_FIFO_FULL_MSK__M 0x10
+#define FEC_OC_COMM_INT_STM_FIFO_FULL_MSK__PRE 0x0
+#define FEC_OC_COMM_INT_STM_FIFO_EMPTY_MSK__B 5
+#define FEC_OC_COMM_INT_STM_FIFO_EMPTY_MSK__W 1
+#define FEC_OC_COMM_INT_STM_FIFO_EMPTY_MSK__M 0x20
+#define FEC_OC_COMM_INT_STM_FIFO_EMPTY_MSK__PRE 0x0
+#define FEC_OC_COMM_INT_STM_OCR_ACQ_MSK__B 6
+#define FEC_OC_COMM_INT_STM_OCR_ACQ_MSK__W 1
+#define FEC_OC_COMM_INT_STM_OCR_ACQ_MSK__M 0x40
+#define FEC_OC_COMM_INT_STM_OCR_ACQ_MSK__PRE 0x0
+#define FEC_OC_COMM_INT_STM_STAT_CHG_MSK__B 7
+#define FEC_OC_COMM_INT_STM_STAT_CHG_MSK__W 1
+#define FEC_OC_COMM_INT_STM_STAT_CHG_MSK__M 0x80
+#define FEC_OC_COMM_INT_STM_STAT_CHG_MSK__PRE 0x0
+
+#define FEC_OC_STATUS__A 0x2440010
+#define FEC_OC_STATUS__W 5
+#define FEC_OC_STATUS__M 0x1F
+#define FEC_OC_STATUS__PRE 0x0
+
+#define FEC_OC_STATUS_DPR_STATUS__B 0
+#define FEC_OC_STATUS_DPR_STATUS__W 1
+#define FEC_OC_STATUS_DPR_STATUS__M 0x1
+#define FEC_OC_STATUS_DPR_STATUS__PRE 0x0
+
+#define FEC_OC_STATUS_SNC_STATUS__B 1
+#define FEC_OC_STATUS_SNC_STATUS__W 2
+#define FEC_OC_STATUS_SNC_STATUS__M 0x6
+#define FEC_OC_STATUS_SNC_STATUS__PRE 0x0
+
+#define FEC_OC_STATUS_FIFO_FULL__B 3
+#define FEC_OC_STATUS_FIFO_FULL__W 1
+#define FEC_OC_STATUS_FIFO_FULL__M 0x8
+#define FEC_OC_STATUS_FIFO_FULL__PRE 0x0
+
+#define FEC_OC_STATUS_FIFO_EMPTY__B 4
+#define FEC_OC_STATUS_FIFO_EMPTY__W 1
+#define FEC_OC_STATUS_FIFO_EMPTY__M 0x10
+#define FEC_OC_STATUS_FIFO_EMPTY__PRE 0x0
+
+#define FEC_OC_MODE__A 0x2440011
+#define FEC_OC_MODE__W 4
+#define FEC_OC_MODE__M 0xF
+#define FEC_OC_MODE__PRE 0x0
+
+#define FEC_OC_MODE_PARITY__B 0
+#define FEC_OC_MODE_PARITY__W 1
+#define FEC_OC_MODE_PARITY__M 0x1
+#define FEC_OC_MODE_PARITY__PRE 0x0
+
+#define FEC_OC_MODE_TRANSPARENT__B 1
+#define FEC_OC_MODE_TRANSPARENT__W 1
+#define FEC_OC_MODE_TRANSPARENT__M 0x2
+#define FEC_OC_MODE_TRANSPARENT__PRE 0x0
+
+#define FEC_OC_MODE_CLEAR__B 2
+#define FEC_OC_MODE_CLEAR__W 1
+#define FEC_OC_MODE_CLEAR__M 0x4
+#define FEC_OC_MODE_CLEAR__PRE 0x0
+
+#define FEC_OC_MODE_RETAIN_FRAMING__B 3
+#define FEC_OC_MODE_RETAIN_FRAMING__W 1
+#define FEC_OC_MODE_RETAIN_FRAMING__M 0x8
+#define FEC_OC_MODE_RETAIN_FRAMING__PRE 0x0
+
+#define FEC_OC_DPR_MODE__A 0x2440012
+#define FEC_OC_DPR_MODE__W 2
+#define FEC_OC_DPR_MODE__M 0x3
+#define FEC_OC_DPR_MODE__PRE 0x0
+
+#define FEC_OC_DPR_MODE_ERR_DISABLE__B 0
+#define FEC_OC_DPR_MODE_ERR_DISABLE__W 1
+#define FEC_OC_DPR_MODE_ERR_DISABLE__M 0x1
+#define FEC_OC_DPR_MODE_ERR_DISABLE__PRE 0x0
+
+#define FEC_OC_DPR_MODE_NOSYNC_ENABLE__B 1
+#define FEC_OC_DPR_MODE_NOSYNC_ENABLE__W 1
+#define FEC_OC_DPR_MODE_NOSYNC_ENABLE__M 0x2
+#define FEC_OC_DPR_MODE_NOSYNC_ENABLE__PRE 0x0
+
+#define FEC_OC_DPR_UNLOCK__A 0x2440013
+#define FEC_OC_DPR_UNLOCK__W 1
+#define FEC_OC_DPR_UNLOCK__M 0x1
+#define FEC_OC_DPR_UNLOCK__PRE 0x0
+#define FEC_OC_DTO_MODE__A 0x2440014
+#define FEC_OC_DTO_MODE__W 3
+#define FEC_OC_DTO_MODE__M 0x7
+#define FEC_OC_DTO_MODE__PRE 0x0
+
+#define FEC_OC_DTO_MODE_DYNAMIC__B 0
+#define FEC_OC_DTO_MODE_DYNAMIC__W 1
+#define FEC_OC_DTO_MODE_DYNAMIC__M 0x1
+#define FEC_OC_DTO_MODE_DYNAMIC__PRE 0x0
+
+#define FEC_OC_DTO_MODE_DUTY_CYCLE__B 1
+#define FEC_OC_DTO_MODE_DUTY_CYCLE__W 1
+#define FEC_OC_DTO_MODE_DUTY_CYCLE__M 0x2
+#define FEC_OC_DTO_MODE_DUTY_CYCLE__PRE 0x0
+
+#define FEC_OC_DTO_MODE_OFFSET_ENABLE__B 2
+#define FEC_OC_DTO_MODE_OFFSET_ENABLE__W 1
+#define FEC_OC_DTO_MODE_OFFSET_ENABLE__M 0x4
+#define FEC_OC_DTO_MODE_OFFSET_ENABLE__PRE 0x0
+
+#define FEC_OC_DTO_PERIOD__A 0x2440015
+#define FEC_OC_DTO_PERIOD__W 8
+#define FEC_OC_DTO_PERIOD__M 0xFF
+#define FEC_OC_DTO_PERIOD__PRE 0x0
+#define FEC_OC_DTO_RATE_LO__A 0x2440016
+#define FEC_OC_DTO_RATE_LO__W 16
+#define FEC_OC_DTO_RATE_LO__M 0xFFFF
+#define FEC_OC_DTO_RATE_LO__PRE 0x0
+
+#define FEC_OC_DTO_RATE_LO_RATE_LO__B 0
+#define FEC_OC_DTO_RATE_LO_RATE_LO__W 16
+#define FEC_OC_DTO_RATE_LO_RATE_LO__M 0xFFFF
+#define FEC_OC_DTO_RATE_LO_RATE_LO__PRE 0x0
+
+#define FEC_OC_DTO_RATE_HI__A 0x2440017
+#define FEC_OC_DTO_RATE_HI__W 10
+#define FEC_OC_DTO_RATE_HI__M 0x3FF
+#define FEC_OC_DTO_RATE_HI__PRE 0xC0
+
+#define FEC_OC_DTO_RATE_HI_RATE_HI__B 0
+#define FEC_OC_DTO_RATE_HI_RATE_HI__W 10
+#define FEC_OC_DTO_RATE_HI_RATE_HI__M 0x3FF
+#define FEC_OC_DTO_RATE_HI_RATE_HI__PRE 0xC0
+
+#define FEC_OC_DTO_BURST_LEN__A 0x2440018
+#define FEC_OC_DTO_BURST_LEN__W 8
+#define FEC_OC_DTO_BURST_LEN__M 0xFF
+#define FEC_OC_DTO_BURST_LEN__PRE 0xBC
+
+#define FEC_OC_DTO_BURST_LEN_BURST_LEN__B 0
+#define FEC_OC_DTO_BURST_LEN_BURST_LEN__W 8
+#define FEC_OC_DTO_BURST_LEN_BURST_LEN__M 0xFF
+#define FEC_OC_DTO_BURST_LEN_BURST_LEN__PRE 0xBC
+
+#define FEC_OC_FCT_MODE__A 0x244001A
+#define FEC_OC_FCT_MODE__W 2
+#define FEC_OC_FCT_MODE__M 0x3
+#define FEC_OC_FCT_MODE__PRE 0x0
+
+#define FEC_OC_FCT_MODE_RAT_ENA__B 0
+#define FEC_OC_FCT_MODE_RAT_ENA__W 1
+#define FEC_OC_FCT_MODE_RAT_ENA__M 0x1
+#define FEC_OC_FCT_MODE_RAT_ENA__PRE 0x0
+
+#define FEC_OC_FCT_MODE_VIRT_ENA__B 1
+#define FEC_OC_FCT_MODE_VIRT_ENA__W 1
+#define FEC_OC_FCT_MODE_VIRT_ENA__M 0x2
+#define FEC_OC_FCT_MODE_VIRT_ENA__PRE 0x0
+
+#define FEC_OC_FCT_USAGE__A 0x244001B
+#define FEC_OC_FCT_USAGE__W 3
+#define FEC_OC_FCT_USAGE__M 0x7
+#define FEC_OC_FCT_USAGE__PRE 0x2
+
+#define FEC_OC_FCT_USAGE_USAGE__B 0
+#define FEC_OC_FCT_USAGE_USAGE__W 3
+#define FEC_OC_FCT_USAGE_USAGE__M 0x7
+#define FEC_OC_FCT_USAGE_USAGE__PRE 0x2
+
+#define FEC_OC_FCT_OCCUPATION__A 0x244001C
+#define FEC_OC_FCT_OCCUPATION__W 12
+#define FEC_OC_FCT_OCCUPATION__M 0xFFF
+#define FEC_OC_FCT_OCCUPATION__PRE 0x0
+
+#define FEC_OC_FCT_OCCUPATION_OCCUPATION__B 0
+#define FEC_OC_FCT_OCCUPATION_OCCUPATION__W 12
+#define FEC_OC_FCT_OCCUPATION_OCCUPATION__M 0xFFF
+#define FEC_OC_FCT_OCCUPATION_OCCUPATION__PRE 0x0
+
+#define FEC_OC_TMD_MODE__A 0x244001E
+#define FEC_OC_TMD_MODE__W 3
+#define FEC_OC_TMD_MODE__M 0x7
+#define FEC_OC_TMD_MODE__PRE 0x4
+
+#define FEC_OC_TMD_MODE_MODE__B 0
+#define FEC_OC_TMD_MODE_MODE__W 3
+#define FEC_OC_TMD_MODE_MODE__M 0x7
+#define FEC_OC_TMD_MODE_MODE__PRE 0x4
+
+#define FEC_OC_TMD_COUNT__A 0x244001F
+#define FEC_OC_TMD_COUNT__W 10
+#define FEC_OC_TMD_COUNT__M 0x3FF
+#define FEC_OC_TMD_COUNT__PRE 0x1F4
+
+#define FEC_OC_TMD_COUNT_COUNT__B 0
+#define FEC_OC_TMD_COUNT_COUNT__W 10
+#define FEC_OC_TMD_COUNT_COUNT__M 0x3FF
+#define FEC_OC_TMD_COUNT_COUNT__PRE 0x1F4
+
+#define FEC_OC_TMD_HI_MARGIN__A 0x2440020
+#define FEC_OC_TMD_HI_MARGIN__W 11
+#define FEC_OC_TMD_HI_MARGIN__M 0x7FF
+#define FEC_OC_TMD_HI_MARGIN__PRE 0x200
+
+#define FEC_OC_TMD_HI_MARGIN_HI_MARGIN__B 0
+#define FEC_OC_TMD_HI_MARGIN_HI_MARGIN__W 11
+#define FEC_OC_TMD_HI_MARGIN_HI_MARGIN__M 0x7FF
+#define FEC_OC_TMD_HI_MARGIN_HI_MARGIN__PRE 0x200
+
+#define FEC_OC_TMD_LO_MARGIN__A 0x2440021
+#define FEC_OC_TMD_LO_MARGIN__W 11
+#define FEC_OC_TMD_LO_MARGIN__M 0x7FF
+#define FEC_OC_TMD_LO_MARGIN__PRE 0x100
+
+#define FEC_OC_TMD_LO_MARGIN_LO_MARGIN__B 0
+#define FEC_OC_TMD_LO_MARGIN_LO_MARGIN__W 11
+#define FEC_OC_TMD_LO_MARGIN_LO_MARGIN__M 0x7FF
+#define FEC_OC_TMD_LO_MARGIN_LO_MARGIN__PRE 0x100
+
+#define FEC_OC_TMD_CTL_UPD_RATE__A 0x2440022
+#define FEC_OC_TMD_CTL_UPD_RATE__W 4
+#define FEC_OC_TMD_CTL_UPD_RATE__M 0xF
+#define FEC_OC_TMD_CTL_UPD_RATE__PRE 0x1
+
+#define FEC_OC_TMD_CTL_UPD_RATE_RATE__B 0
+#define FEC_OC_TMD_CTL_UPD_RATE_RATE__W 4
+#define FEC_OC_TMD_CTL_UPD_RATE_RATE__M 0xF
+#define FEC_OC_TMD_CTL_UPD_RATE_RATE__PRE 0x1
+
+#define FEC_OC_TMD_INT_UPD_RATE__A 0x2440023
+#define FEC_OC_TMD_INT_UPD_RATE__W 4
+#define FEC_OC_TMD_INT_UPD_RATE__M 0xF
+#define FEC_OC_TMD_INT_UPD_RATE__PRE 0x4
+
+#define FEC_OC_TMD_INT_UPD_RATE_RATE__B 0
+#define FEC_OC_TMD_INT_UPD_RATE_RATE__W 4
+#define FEC_OC_TMD_INT_UPD_RATE_RATE__M 0xF
+#define FEC_OC_TMD_INT_UPD_RATE_RATE__PRE 0x4
+
+#define FEC_OC_AVR_PARM_A__A 0x2440026
+#define FEC_OC_AVR_PARM_A__W 4
+#define FEC_OC_AVR_PARM_A__M 0xF
+#define FEC_OC_AVR_PARM_A__PRE 0x6
+
+#define FEC_OC_AVR_PARM_A_PARM__B 0
+#define FEC_OC_AVR_PARM_A_PARM__W 4
+#define FEC_OC_AVR_PARM_A_PARM__M 0xF
+#define FEC_OC_AVR_PARM_A_PARM__PRE 0x6
+
+#define FEC_OC_AVR_PARM_B__A 0x2440027
+#define FEC_OC_AVR_PARM_B__W 4
+#define FEC_OC_AVR_PARM_B__M 0xF
+#define FEC_OC_AVR_PARM_B__PRE 0x4
+
+#define FEC_OC_AVR_PARM_B_PARM__B 0
+#define FEC_OC_AVR_PARM_B_PARM__W 4
+#define FEC_OC_AVR_PARM_B_PARM__M 0xF
+#define FEC_OC_AVR_PARM_B_PARM__PRE 0x4
+
+#define FEC_OC_AVR_AVG_LO__A 0x2440028
+#define FEC_OC_AVR_AVG_LO__W 16
+#define FEC_OC_AVR_AVG_LO__M 0xFFFF
+#define FEC_OC_AVR_AVG_LO__PRE 0x0
+
+#define FEC_OC_AVR_AVG_LO_AVG_LO__B 0
+#define FEC_OC_AVR_AVG_LO_AVG_LO__W 16
+#define FEC_OC_AVR_AVG_LO_AVG_LO__M 0xFFFF
+#define FEC_OC_AVR_AVG_LO_AVG_LO__PRE 0x0
+
+#define FEC_OC_AVR_AVG_HI__A 0x2440029
+#define FEC_OC_AVR_AVG_HI__W 6
+#define FEC_OC_AVR_AVG_HI__M 0x3F
+#define FEC_OC_AVR_AVG_HI__PRE 0x0
+
+#define FEC_OC_AVR_AVG_HI_AVG_HI__B 0
+#define FEC_OC_AVR_AVG_HI_AVG_HI__W 6
+#define FEC_OC_AVR_AVG_HI_AVG_HI__M 0x3F
+#define FEC_OC_AVR_AVG_HI_AVG_HI__PRE 0x0
+
+#define FEC_OC_RCN_MODE__A 0x244002C
+#define FEC_OC_RCN_MODE__W 5
+#define FEC_OC_RCN_MODE__M 0x1F
+#define FEC_OC_RCN_MODE__PRE 0x1F
+
+#define FEC_OC_RCN_MODE_MODE__B 0
+#define FEC_OC_RCN_MODE_MODE__W 5
+#define FEC_OC_RCN_MODE_MODE__M 0x1F
+#define FEC_OC_RCN_MODE_MODE__PRE 0x1F
+
+#define FEC_OC_RCN_OCC_SETTLE__A 0x244002D
+#define FEC_OC_RCN_OCC_SETTLE__W 11
+#define FEC_OC_RCN_OCC_SETTLE__M 0x7FF
+#define FEC_OC_RCN_OCC_SETTLE__PRE 0x180
+
+#define FEC_OC_RCN_OCC_SETTLE_LEVEL__B 0
+#define FEC_OC_RCN_OCC_SETTLE_LEVEL__W 11
+#define FEC_OC_RCN_OCC_SETTLE_LEVEL__M 0x7FF
+#define FEC_OC_RCN_OCC_SETTLE_LEVEL__PRE 0x180
+
+#define FEC_OC_RCN_GAIN__A 0x244002E
+#define FEC_OC_RCN_GAIN__W 4
+#define FEC_OC_RCN_GAIN__M 0xF
+#define FEC_OC_RCN_GAIN__PRE 0xC
+
+#define FEC_OC_RCN_GAIN_GAIN__B 0
+#define FEC_OC_RCN_GAIN_GAIN__W 4
+#define FEC_OC_RCN_GAIN_GAIN__M 0xF
+#define FEC_OC_RCN_GAIN_GAIN__PRE 0xC
+
+#define FEC_OC_RCN_CTL_RATE_LO__A 0x2440030
+#define FEC_OC_RCN_CTL_RATE_LO__W 16
+#define FEC_OC_RCN_CTL_RATE_LO__M 0xFFFF
+#define FEC_OC_RCN_CTL_RATE_LO__PRE 0x0
+
+#define FEC_OC_RCN_CTL_RATE_LO_CTL_LO__B 0
+#define FEC_OC_RCN_CTL_RATE_LO_CTL_LO__W 16
+#define FEC_OC_RCN_CTL_RATE_LO_CTL_LO__M 0xFFFF
+#define FEC_OC_RCN_CTL_RATE_LO_CTL_LO__PRE 0x0
+
+#define FEC_OC_RCN_CTL_RATE_HI__A 0x2440031
+#define FEC_OC_RCN_CTL_RATE_HI__W 8
+#define FEC_OC_RCN_CTL_RATE_HI__M 0xFF
+#define FEC_OC_RCN_CTL_RATE_HI__PRE 0xC0
+
+#define FEC_OC_RCN_CTL_RATE_HI_CTL_HI__B 0
+#define FEC_OC_RCN_CTL_RATE_HI_CTL_HI__W 8
+#define FEC_OC_RCN_CTL_RATE_HI_CTL_HI__M 0xFF
+#define FEC_OC_RCN_CTL_RATE_HI_CTL_HI__PRE 0xC0
+
+#define FEC_OC_RCN_CTL_STEP_LO__A 0x2440032
+#define FEC_OC_RCN_CTL_STEP_LO__W 16
+#define FEC_OC_RCN_CTL_STEP_LO__M 0xFFFF
+#define FEC_OC_RCN_CTL_STEP_LO__PRE 0x0
+
+#define FEC_OC_RCN_CTL_STEP_LO_CTL_LO__B 0
+#define FEC_OC_RCN_CTL_STEP_LO_CTL_LO__W 16
+#define FEC_OC_RCN_CTL_STEP_LO_CTL_LO__M 0xFFFF
+#define FEC_OC_RCN_CTL_STEP_LO_CTL_LO__PRE 0x0
+
+#define FEC_OC_RCN_CTL_STEP_HI__A 0x2440033
+#define FEC_OC_RCN_CTL_STEP_HI__W 8
+#define FEC_OC_RCN_CTL_STEP_HI__M 0xFF
+#define FEC_OC_RCN_CTL_STEP_HI__PRE 0x8
+
+#define FEC_OC_RCN_CTL_STEP_HI_CTL_HI__B 0
+#define FEC_OC_RCN_CTL_STEP_HI_CTL_HI__W 8
+#define FEC_OC_RCN_CTL_STEP_HI_CTL_HI__M 0xFF
+#define FEC_OC_RCN_CTL_STEP_HI_CTL_HI__PRE 0x8
+
+#define FEC_OC_RCN_DTO_OFS_LO__A 0x2440034
+#define FEC_OC_RCN_DTO_OFS_LO__W 16
+#define FEC_OC_RCN_DTO_OFS_LO__M 0xFFFF
+#define FEC_OC_RCN_DTO_OFS_LO__PRE 0x0
+
+#define FEC_OC_RCN_DTO_OFS_LO_OFS_LO__B 0
+#define FEC_OC_RCN_DTO_OFS_LO_OFS_LO__W 16
+#define FEC_OC_RCN_DTO_OFS_LO_OFS_LO__M 0xFFFF
+#define FEC_OC_RCN_DTO_OFS_LO_OFS_LO__PRE 0x0
+
+#define FEC_OC_RCN_DTO_OFS_HI__A 0x2440035
+#define FEC_OC_RCN_DTO_OFS_HI__W 8
+#define FEC_OC_RCN_DTO_OFS_HI__M 0xFF
+#define FEC_OC_RCN_DTO_OFS_HI__PRE 0x0
+
+#define FEC_OC_RCN_DTO_OFS_HI_OFS_HI__B 0
+#define FEC_OC_RCN_DTO_OFS_HI_OFS_HI__W 8
+#define FEC_OC_RCN_DTO_OFS_HI_OFS_HI__M 0xFF
+#define FEC_OC_RCN_DTO_OFS_HI_OFS_HI__PRE 0x0
+
+#define FEC_OC_RCN_DTO_RATE_LO__A 0x2440036
+#define FEC_OC_RCN_DTO_RATE_LO__W 16
+#define FEC_OC_RCN_DTO_RATE_LO__M 0xFFFF
+#define FEC_OC_RCN_DTO_RATE_LO__PRE 0x0
+
+#define FEC_OC_RCN_DTO_RATE_LO_OFS_LO__B 0
+#define FEC_OC_RCN_DTO_RATE_LO_OFS_LO__W 16
+#define FEC_OC_RCN_DTO_RATE_LO_OFS_LO__M 0xFFFF
+#define FEC_OC_RCN_DTO_RATE_LO_OFS_LO__PRE 0x0
+
+#define FEC_OC_RCN_DTO_RATE_HI__A 0x2440037
+#define FEC_OC_RCN_DTO_RATE_HI__W 8
+#define FEC_OC_RCN_DTO_RATE_HI__M 0xFF
+#define FEC_OC_RCN_DTO_RATE_HI__PRE 0x0
+
+#define FEC_OC_RCN_DTO_RATE_HI_OFS_HI__B 0
+#define FEC_OC_RCN_DTO_RATE_HI_OFS_HI__W 8
+#define FEC_OC_RCN_DTO_RATE_HI_OFS_HI__M 0xFF
+#define FEC_OC_RCN_DTO_RATE_HI_OFS_HI__PRE 0x0
+
+#define FEC_OC_RCN_RATE_CLIP_LO__A 0x2440038
+#define FEC_OC_RCN_RATE_CLIP_LO__W 16
+#define FEC_OC_RCN_RATE_CLIP_LO__M 0xFFFF
+#define FEC_OC_RCN_RATE_CLIP_LO__PRE 0x0
+
+#define FEC_OC_RCN_RATE_CLIP_LO_CLIP_LO__B 0
+#define FEC_OC_RCN_RATE_CLIP_LO_CLIP_LO__W 16
+#define FEC_OC_RCN_RATE_CLIP_LO_CLIP_LO__M 0xFFFF
+#define FEC_OC_RCN_RATE_CLIP_LO_CLIP_LO__PRE 0x0
+
+#define FEC_OC_RCN_RATE_CLIP_HI__A 0x2440039
+#define FEC_OC_RCN_RATE_CLIP_HI__W 8
+#define FEC_OC_RCN_RATE_CLIP_HI__M 0xFF
+#define FEC_OC_RCN_RATE_CLIP_HI__PRE 0xF0
+
+#define FEC_OC_RCN_RATE_CLIP_HI_CLIP_HI__B 0
+#define FEC_OC_RCN_RATE_CLIP_HI_CLIP_HI__W 8
+#define FEC_OC_RCN_RATE_CLIP_HI_CLIP_HI__M 0xFF
+#define FEC_OC_RCN_RATE_CLIP_HI_CLIP_HI__PRE 0xF0
+
+#define FEC_OC_RCN_DYN_RATE_LO__A 0x244003A
+#define FEC_OC_RCN_DYN_RATE_LO__W 16
+#define FEC_OC_RCN_DYN_RATE_LO__M 0xFFFF
+#define FEC_OC_RCN_DYN_RATE_LO__PRE 0x0
+
+#define FEC_OC_RCN_DYN_RATE_LO_RATE_LO__B 0
+#define FEC_OC_RCN_DYN_RATE_LO_RATE_LO__W 16
+#define FEC_OC_RCN_DYN_RATE_LO_RATE_LO__M 0xFFFF
+#define FEC_OC_RCN_DYN_RATE_LO_RATE_LO__PRE 0x0
+
+#define FEC_OC_RCN_DYN_RATE_HI__A 0x244003B
+#define FEC_OC_RCN_DYN_RATE_HI__W 8
+#define FEC_OC_RCN_DYN_RATE_HI__M 0xFF
+#define FEC_OC_RCN_DYN_RATE_HI__PRE 0x0
+
+#define FEC_OC_RCN_DYN_RATE_HI_RATE_HI__B 0
+#define FEC_OC_RCN_DYN_RATE_HI_RATE_HI__W 8
+#define FEC_OC_RCN_DYN_RATE_HI_RATE_HI__M 0xFF
+#define FEC_OC_RCN_DYN_RATE_HI_RATE_HI__PRE 0x0
+
+#define FEC_OC_SNC_MODE__A 0x2440040
+#define FEC_OC_SNC_MODE__W 4
+#define FEC_OC_SNC_MODE__M 0xF
+#define FEC_OC_SNC_MODE__PRE 0x0
+
+#define FEC_OC_SNC_MODE_UNLOCK_ENABLE__B 0
+#define FEC_OC_SNC_MODE_UNLOCK_ENABLE__W 1
+#define FEC_OC_SNC_MODE_UNLOCK_ENABLE__M 0x1
+#define FEC_OC_SNC_MODE_UNLOCK_ENABLE__PRE 0x0
+
+#define FEC_OC_SNC_MODE_ERROR_CTL__B 1
+#define FEC_OC_SNC_MODE_ERROR_CTL__W 2
+#define FEC_OC_SNC_MODE_ERROR_CTL__M 0x6
+#define FEC_OC_SNC_MODE_ERROR_CTL__PRE 0x0
+
+#define FEC_OC_SNC_MODE_CORR_DISABLE__B 3
+#define FEC_OC_SNC_MODE_CORR_DISABLE__W 1
+#define FEC_OC_SNC_MODE_CORR_DISABLE__M 0x8
+#define FEC_OC_SNC_MODE_CORR_DISABLE__PRE 0x0
+
+#define FEC_OC_SNC_LWM__A 0x2440041
+#define FEC_OC_SNC_LWM__W 4
+#define FEC_OC_SNC_LWM__M 0xF
+#define FEC_OC_SNC_LWM__PRE 0x3
+
+#define FEC_OC_SNC_LWM_MARK__B 0
+#define FEC_OC_SNC_LWM_MARK__W 4
+#define FEC_OC_SNC_LWM_MARK__M 0xF
+#define FEC_OC_SNC_LWM_MARK__PRE 0x3
+
+#define FEC_OC_SNC_HWM__A 0x2440042
+#define FEC_OC_SNC_HWM__W 4
+#define FEC_OC_SNC_HWM__M 0xF
+#define FEC_OC_SNC_HWM__PRE 0x5
+
+#define FEC_OC_SNC_HWM_MARK__B 0
+#define FEC_OC_SNC_HWM_MARK__W 4
+#define FEC_OC_SNC_HWM_MARK__M 0xF
+#define FEC_OC_SNC_HWM_MARK__PRE 0x5
+
+#define FEC_OC_SNC_UNLOCK__A 0x2440043
+#define FEC_OC_SNC_UNLOCK__W 1
+#define FEC_OC_SNC_UNLOCK__M 0x1
+#define FEC_OC_SNC_UNLOCK__PRE 0x0
+
+#define FEC_OC_SNC_UNLOCK_RESTART__B 0
+#define FEC_OC_SNC_UNLOCK_RESTART__W 1
+#define FEC_OC_SNC_UNLOCK_RESTART__M 0x1
+#define FEC_OC_SNC_UNLOCK_RESTART__PRE 0x0
+
+#define FEC_OC_SNC_LOCK_COUNT__A 0x2440044
+#define FEC_OC_SNC_LOCK_COUNT__W 12
+#define FEC_OC_SNC_LOCK_COUNT__M 0xFFF
+#define FEC_OC_SNC_LOCK_COUNT__PRE 0x0
+
+#define FEC_OC_SNC_LOCK_COUNT_COUNT__B 0
+#define FEC_OC_SNC_LOCK_COUNT_COUNT__W 12
+#define FEC_OC_SNC_LOCK_COUNT_COUNT__M 0xFFF
+#define FEC_OC_SNC_LOCK_COUNT_COUNT__PRE 0x0
+
+#define FEC_OC_SNC_FAIL_COUNT__A 0x2440045
+#define FEC_OC_SNC_FAIL_COUNT__W 12
+#define FEC_OC_SNC_FAIL_COUNT__M 0xFFF
+#define FEC_OC_SNC_FAIL_COUNT__PRE 0x0
+
+#define FEC_OC_SNC_FAIL_COUNT_COUNT__B 0
+#define FEC_OC_SNC_FAIL_COUNT_COUNT__W 12
+#define FEC_OC_SNC_FAIL_COUNT_COUNT__M 0xFFF
+#define FEC_OC_SNC_FAIL_COUNT_COUNT__PRE 0x0
+
+#define FEC_OC_SNC_FAIL_PERIOD__A 0x2440046
+#define FEC_OC_SNC_FAIL_PERIOD__W 16
+#define FEC_OC_SNC_FAIL_PERIOD__M 0xFFFF
+#define FEC_OC_SNC_FAIL_PERIOD__PRE 0x1171
+
+#define FEC_OC_SNC_FAIL_PERIOD_PERIOD__B 0
+#define FEC_OC_SNC_FAIL_PERIOD_PERIOD__W 16
+#define FEC_OC_SNC_FAIL_PERIOD_PERIOD__M 0xFFFF
+#define FEC_OC_SNC_FAIL_PERIOD_PERIOD__PRE 0x1171
+
+#define FEC_OC_EMS_MODE__A 0x2440047
+#define FEC_OC_EMS_MODE__W 2
+#define FEC_OC_EMS_MODE__M 0x3
+#define FEC_OC_EMS_MODE__PRE 0x0
+
+#define FEC_OC_EMS_MODE_MODE__B 0
+#define FEC_OC_EMS_MODE_MODE__W 2
+#define FEC_OC_EMS_MODE_MODE__M 0x3
+#define FEC_OC_EMS_MODE_MODE__PRE 0x0
+
+#define FEC_OC_IPR_MODE__A 0x2440048
+#define FEC_OC_IPR_MODE__W 12
+#define FEC_OC_IPR_MODE__M 0xFFF
+#define FEC_OC_IPR_MODE__PRE 0x0
+
+#define FEC_OC_IPR_MODE_SERIAL__B 0
+#define FEC_OC_IPR_MODE_SERIAL__W 1
+#define FEC_OC_IPR_MODE_SERIAL__M 0x1
+#define FEC_OC_IPR_MODE_SERIAL__PRE 0x0
+
+#define FEC_OC_IPR_MODE_REVERSE_ORDER__B 1
+#define FEC_OC_IPR_MODE_REVERSE_ORDER__W 1
+#define FEC_OC_IPR_MODE_REVERSE_ORDER__M 0x2
+#define FEC_OC_IPR_MODE_REVERSE_ORDER__PRE 0x0
+
+#define FEC_OC_IPR_MODE_MCLK_DIS_DAT_ABS__B 2
+#define FEC_OC_IPR_MODE_MCLK_DIS_DAT_ABS__W 1
+#define FEC_OC_IPR_MODE_MCLK_DIS_DAT_ABS__M 0x4
+#define FEC_OC_IPR_MODE_MCLK_DIS_DAT_ABS__PRE 0x0
+
+#define FEC_OC_IPR_MODE_MCLK_DIS_PAR__B 3
+#define FEC_OC_IPR_MODE_MCLK_DIS_PAR__W 1
+#define FEC_OC_IPR_MODE_MCLK_DIS_PAR__M 0x8
+#define FEC_OC_IPR_MODE_MCLK_DIS_PAR__PRE 0x0
+
+#define FEC_OC_IPR_MODE_MVAL_DIS_PAR__B 4
+#define FEC_OC_IPR_MODE_MVAL_DIS_PAR__W 1
+#define FEC_OC_IPR_MODE_MVAL_DIS_PAR__M 0x10
+#define FEC_OC_IPR_MODE_MVAL_DIS_PAR__PRE 0x0
+
+#define FEC_OC_IPR_MODE_MERR_DIS_PAR__B 5
+#define FEC_OC_IPR_MODE_MERR_DIS_PAR__W 1
+#define FEC_OC_IPR_MODE_MERR_DIS_PAR__M 0x20
+#define FEC_OC_IPR_MODE_MERR_DIS_PAR__PRE 0x0
+
+#define FEC_OC_IPR_MODE_MD_DIS_PAR__B 6
+#define FEC_OC_IPR_MODE_MD_DIS_PAR__W 1
+#define FEC_OC_IPR_MODE_MD_DIS_PAR__M 0x40
+#define FEC_OC_IPR_MODE_MD_DIS_PAR__PRE 0x0
+
+#define FEC_OC_IPR_MODE_MCLK_DIS_ERR__B 7
+#define FEC_OC_IPR_MODE_MCLK_DIS_ERR__W 1
+#define FEC_OC_IPR_MODE_MCLK_DIS_ERR__M 0x80
+#define FEC_OC_IPR_MODE_MCLK_DIS_ERR__PRE 0x0
+
+#define FEC_OC_IPR_MODE_MVAL_DIS_ERR__B 8
+#define FEC_OC_IPR_MODE_MVAL_DIS_ERR__W 1
+#define FEC_OC_IPR_MODE_MVAL_DIS_ERR__M 0x100
+#define FEC_OC_IPR_MODE_MVAL_DIS_ERR__PRE 0x0
+
+#define FEC_OC_IPR_MODE_MERR_DIS_ERR__B 9
+#define FEC_OC_IPR_MODE_MERR_DIS_ERR__W 1
+#define FEC_OC_IPR_MODE_MERR_DIS_ERR__M 0x200
+#define FEC_OC_IPR_MODE_MERR_DIS_ERR__PRE 0x0
+
+#define FEC_OC_IPR_MODE_MD_DIS_ERR__B 10
+#define FEC_OC_IPR_MODE_MD_DIS_ERR__W 1
+#define FEC_OC_IPR_MODE_MD_DIS_ERR__M 0x400
+#define FEC_OC_IPR_MODE_MD_DIS_ERR__PRE 0x0
+
+#define FEC_OC_IPR_MODE_MSTRT_DIS_ERR__B 11
+#define FEC_OC_IPR_MODE_MSTRT_DIS_ERR__W 1
+#define FEC_OC_IPR_MODE_MSTRT_DIS_ERR__M 0x800
+#define FEC_OC_IPR_MODE_MSTRT_DIS_ERR__PRE 0x0
+
+#define FEC_OC_IPR_INVERT__A 0x2440049
+#define FEC_OC_IPR_INVERT__W 12
+#define FEC_OC_IPR_INVERT__M 0xFFF
+#define FEC_OC_IPR_INVERT__PRE 0x0
+
+#define FEC_OC_IPR_INVERT_MD0__B 0
+#define FEC_OC_IPR_INVERT_MD0__W 1
+#define FEC_OC_IPR_INVERT_MD0__M 0x1
+#define FEC_OC_IPR_INVERT_MD0__PRE 0x0
+
+#define FEC_OC_IPR_INVERT_MD1__B 1
+#define FEC_OC_IPR_INVERT_MD1__W 1
+#define FEC_OC_IPR_INVERT_MD1__M 0x2
+#define FEC_OC_IPR_INVERT_MD1__PRE 0x0
+
+#define FEC_OC_IPR_INVERT_MD2__B 2
+#define FEC_OC_IPR_INVERT_MD2__W 1
+#define FEC_OC_IPR_INVERT_MD2__M 0x4
+#define FEC_OC_IPR_INVERT_MD2__PRE 0x0
+
+#define FEC_OC_IPR_INVERT_MD3__B 3
+#define FEC_OC_IPR_INVERT_MD3__W 1
+#define FEC_OC_IPR_INVERT_MD3__M 0x8
+#define FEC_OC_IPR_INVERT_MD3__PRE 0x0
+
+#define FEC_OC_IPR_INVERT_MD4__B 4
+#define FEC_OC_IPR_INVERT_MD4__W 1
+#define FEC_OC_IPR_INVERT_MD4__M 0x10
+#define FEC_OC_IPR_INVERT_MD4__PRE 0x0
+
+#define FEC_OC_IPR_INVERT_MD5__B 5
+#define FEC_OC_IPR_INVERT_MD5__W 1
+#define FEC_OC_IPR_INVERT_MD5__M 0x20
+#define FEC_OC_IPR_INVERT_MD5__PRE 0x0
+
+#define FEC_OC_IPR_INVERT_MD6__B 6
+#define FEC_OC_IPR_INVERT_MD6__W 1
+#define FEC_OC_IPR_INVERT_MD6__M 0x40
+#define FEC_OC_IPR_INVERT_MD6__PRE 0x0
+
+#define FEC_OC_IPR_INVERT_MD7__B 7
+#define FEC_OC_IPR_INVERT_MD7__W 1
+#define FEC_OC_IPR_INVERT_MD7__M 0x80
+#define FEC_OC_IPR_INVERT_MD7__PRE 0x0
+
+#define FEC_OC_IPR_INVERT_MERR__B 8
+#define FEC_OC_IPR_INVERT_MERR__W 1
+#define FEC_OC_IPR_INVERT_MERR__M 0x100
+#define FEC_OC_IPR_INVERT_MERR__PRE 0x0
+
+#define FEC_OC_IPR_INVERT_MSTRT__B 9
+#define FEC_OC_IPR_INVERT_MSTRT__W 1
+#define FEC_OC_IPR_INVERT_MSTRT__M 0x200
+#define FEC_OC_IPR_INVERT_MSTRT__PRE 0x0
+
+#define FEC_OC_IPR_INVERT_MVAL__B 10
+#define FEC_OC_IPR_INVERT_MVAL__W 1
+#define FEC_OC_IPR_INVERT_MVAL__M 0x400
+#define FEC_OC_IPR_INVERT_MVAL__PRE 0x0
+
+#define FEC_OC_IPR_INVERT_MCLK__B 11
+#define FEC_OC_IPR_INVERT_MCLK__W 1
+#define FEC_OC_IPR_INVERT_MCLK__M 0x800
+#define FEC_OC_IPR_INVERT_MCLK__PRE 0x0
+
+#define FEC_OC_OCR_MODE__A 0x2440050
+#define FEC_OC_OCR_MODE__W 4
+#define FEC_OC_OCR_MODE__M 0xF
+#define FEC_OC_OCR_MODE__PRE 0x0
+
+#define FEC_OC_OCR_MODE_MB_SELECT__B 0
+#define FEC_OC_OCR_MODE_MB_SELECT__W 1
+#define FEC_OC_OCR_MODE_MB_SELECT__M 0x1
+#define FEC_OC_OCR_MODE_MB_SELECT__PRE 0x0
+
+#define FEC_OC_OCR_MODE_GRAB_ENABLE__B 1
+#define FEC_OC_OCR_MODE_GRAB_ENABLE__W 1
+#define FEC_OC_OCR_MODE_GRAB_ENABLE__M 0x2
+#define FEC_OC_OCR_MODE_GRAB_ENABLE__PRE 0x0
+
+#define FEC_OC_OCR_MODE_GRAB_SELECT__B 2
+#define FEC_OC_OCR_MODE_GRAB_SELECT__W 1
+#define FEC_OC_OCR_MODE_GRAB_SELECT__M 0x4
+#define FEC_OC_OCR_MODE_GRAB_SELECT__PRE 0x0
+
+#define FEC_OC_OCR_MODE_GRAB_COUNTED__B 3
+#define FEC_OC_OCR_MODE_GRAB_COUNTED__W 1
+#define FEC_OC_OCR_MODE_GRAB_COUNTED__M 0x8
+#define FEC_OC_OCR_MODE_GRAB_COUNTED__PRE 0x0
+
+#define FEC_OC_OCR_RATE__A 0x2440051
+#define FEC_OC_OCR_RATE__W 4
+#define FEC_OC_OCR_RATE__M 0xF
+#define FEC_OC_OCR_RATE__PRE 0x0
+
+#define FEC_OC_OCR_RATE_RATE__B 0
+#define FEC_OC_OCR_RATE_RATE__W 4
+#define FEC_OC_OCR_RATE_RATE__M 0xF
+#define FEC_OC_OCR_RATE_RATE__PRE 0x0
+
+#define FEC_OC_OCR_INVERT__A 0x2440052
+#define FEC_OC_OCR_INVERT__W 12
+#define FEC_OC_OCR_INVERT__M 0xFFF
+#define FEC_OC_OCR_INVERT__PRE 0x800
+
+#define FEC_OC_OCR_INVERT_INVERT__B 0
+#define FEC_OC_OCR_INVERT_INVERT__W 12
+#define FEC_OC_OCR_INVERT_INVERT__M 0xFFF
+#define FEC_OC_OCR_INVERT_INVERT__PRE 0x800
+
+#define FEC_OC_OCR_GRAB_COUNT__A 0x2440053
+#define FEC_OC_OCR_GRAB_COUNT__W 16
+#define FEC_OC_OCR_GRAB_COUNT__M 0xFFFF
+#define FEC_OC_OCR_GRAB_COUNT__PRE 0x0
+
+#define FEC_OC_OCR_GRAB_COUNT_COUNT__B 0
+#define FEC_OC_OCR_GRAB_COUNT_COUNT__W 16
+#define FEC_OC_OCR_GRAB_COUNT_COUNT__M 0xFFFF
+#define FEC_OC_OCR_GRAB_COUNT_COUNT__PRE 0x0
+
+#define FEC_OC_OCR_GRAB_SYNC__A 0x2440054
+#define FEC_OC_OCR_GRAB_SYNC__W 8
+#define FEC_OC_OCR_GRAB_SYNC__M 0xFF
+#define FEC_OC_OCR_GRAB_SYNC__PRE 0x0
+
+#define FEC_OC_OCR_GRAB_SYNC_BYTE_SEL__B 0
+#define FEC_OC_OCR_GRAB_SYNC_BYTE_SEL__W 3
+#define FEC_OC_OCR_GRAB_SYNC_BYTE_SEL__M 0x7
+#define FEC_OC_OCR_GRAB_SYNC_BYTE_SEL__PRE 0x0
+
+#define FEC_OC_OCR_GRAB_SYNC_BIT_SEL__B 3
+#define FEC_OC_OCR_GRAB_SYNC_BIT_SEL__W 4
+#define FEC_OC_OCR_GRAB_SYNC_BIT_SEL__M 0x78
+#define FEC_OC_OCR_GRAB_SYNC_BIT_SEL__PRE 0x0
+
+#define FEC_OC_OCR_GRAB_SYNC_VALUE_SEL__B 7
+#define FEC_OC_OCR_GRAB_SYNC_VALUE_SEL__W 1
+#define FEC_OC_OCR_GRAB_SYNC_VALUE_SEL__M 0x80
+#define FEC_OC_OCR_GRAB_SYNC_VALUE_SEL__PRE 0x0
+
+#define FEC_OC_OCR_GRAB_RD0__A 0x2440055
+#define FEC_OC_OCR_GRAB_RD0__W 10
+#define FEC_OC_OCR_GRAB_RD0__M 0x3FF
+#define FEC_OC_OCR_GRAB_RD0__PRE 0x0
+
+#define FEC_OC_OCR_GRAB_RD0_DATA__B 0
+#define FEC_OC_OCR_GRAB_RD0_DATA__W 10
+#define FEC_OC_OCR_GRAB_RD0_DATA__M 0x3FF
+#define FEC_OC_OCR_GRAB_RD0_DATA__PRE 0x0
+
+#define FEC_OC_OCR_GRAB_RD1__A 0x2440056
+#define FEC_OC_OCR_GRAB_RD1__W 10
+#define FEC_OC_OCR_GRAB_RD1__M 0x3FF
+#define FEC_OC_OCR_GRAB_RD1__PRE 0x0
+
+#define FEC_OC_OCR_GRAB_RD1_DATA__B 0
+#define FEC_OC_OCR_GRAB_RD1_DATA__W 10
+#define FEC_OC_OCR_GRAB_RD1_DATA__M 0x3FF
+#define FEC_OC_OCR_GRAB_RD1_DATA__PRE 0x0
+
+#define FEC_OC_OCR_GRAB_RD2__A 0x2440057
+#define FEC_OC_OCR_GRAB_RD2__W 10
+#define FEC_OC_OCR_GRAB_RD2__M 0x3FF
+#define FEC_OC_OCR_GRAB_RD2__PRE 0x0
+
+#define FEC_OC_OCR_GRAB_RD2_DATA__B 0
+#define FEC_OC_OCR_GRAB_RD2_DATA__W 10
+#define FEC_OC_OCR_GRAB_RD2_DATA__M 0x3FF
+#define FEC_OC_OCR_GRAB_RD2_DATA__PRE 0x0
+
+#define FEC_OC_OCR_GRAB_RD3__A 0x2440058
+#define FEC_OC_OCR_GRAB_RD3__W 10
+#define FEC_OC_OCR_GRAB_RD3__M 0x3FF
+#define FEC_OC_OCR_GRAB_RD3__PRE 0x0
+
+#define FEC_OC_OCR_GRAB_RD3_DATA__B 0
+#define FEC_OC_OCR_GRAB_RD3_DATA__W 10
+#define FEC_OC_OCR_GRAB_RD3_DATA__M 0x3FF
+#define FEC_OC_OCR_GRAB_RD3_DATA__PRE 0x0
+
+#define FEC_OC_OCR_GRAB_RD4__A 0x2440059
+#define FEC_OC_OCR_GRAB_RD4__W 10
+#define FEC_OC_OCR_GRAB_RD4__M 0x3FF
+#define FEC_OC_OCR_GRAB_RD4__PRE 0x0
+
+#define FEC_OC_OCR_GRAB_RD4_DATA__B 0
+#define FEC_OC_OCR_GRAB_RD4_DATA__W 10
+#define FEC_OC_OCR_GRAB_RD4_DATA__M 0x3FF
+#define FEC_OC_OCR_GRAB_RD4_DATA__PRE 0x0
+
+#define FEC_OC_OCR_GRAB_RD5__A 0x244005A
+#define FEC_OC_OCR_GRAB_RD5__W 10
+#define FEC_OC_OCR_GRAB_RD5__M 0x3FF
+#define FEC_OC_OCR_GRAB_RD5__PRE 0x0
+
+#define FEC_OC_OCR_GRAB_RD5_DATA__B 0
+#define FEC_OC_OCR_GRAB_RD5_DATA__W 10
+#define FEC_OC_OCR_GRAB_RD5_DATA__M 0x3FF
+#define FEC_OC_OCR_GRAB_RD5_DATA__PRE 0x0
+
+#define FEC_DI_RAM__A 0x2450000
+
+#define FEC_RS_RAM__A 0x2460000
+
+#define FEC_OC_RAM__A 0x2470000
+
+#define IQM_COMM_EXEC__A 0x1800000
+#define IQM_COMM_EXEC__W 2
+#define IQM_COMM_EXEC__M 0x3
+#define IQM_COMM_EXEC__PRE 0x0
+#define IQM_COMM_EXEC_STOP 0x0
+#define IQM_COMM_EXEC_ACTIVE 0x1
+#define IQM_COMM_EXEC_HOLD 0x2
+
+#define IQM_COMM_MB__A 0x1800002
+#define IQM_COMM_MB__W 16
+#define IQM_COMM_MB__M 0xFFFF
+#define IQM_COMM_MB__PRE 0x0
+#define IQM_COMM_INT_REQ__A 0x1800003
+#define IQM_COMM_INT_REQ__W 2
+#define IQM_COMM_INT_REQ__M 0x3
+#define IQM_COMM_INT_REQ__PRE 0x0
+
+#define IQM_COMM_INT_REQ_AF_REQ__B 0
+#define IQM_COMM_INT_REQ_AF_REQ__W 1
+#define IQM_COMM_INT_REQ_AF_REQ__M 0x1
+#define IQM_COMM_INT_REQ_AF_REQ__PRE 0x0
+
+#define IQM_COMM_INT_REQ_CF_REQ__B 1
+#define IQM_COMM_INT_REQ_CF_REQ__W 1
+#define IQM_COMM_INT_REQ_CF_REQ__M 0x2
+#define IQM_COMM_INT_REQ_CF_REQ__PRE 0x0
+
+#define IQM_COMM_INT_STA__A 0x1800005
+#define IQM_COMM_INT_STA__W 16
+#define IQM_COMM_INT_STA__M 0xFFFF
+#define IQM_COMM_INT_STA__PRE 0x0
+#define IQM_COMM_INT_MSK__A 0x1800006
+#define IQM_COMM_INT_MSK__W 16
+#define IQM_COMM_INT_MSK__M 0xFFFF
+#define IQM_COMM_INT_MSK__PRE 0x0
+#define IQM_COMM_INT_STM__A 0x1800007
+#define IQM_COMM_INT_STM__W 16
+#define IQM_COMM_INT_STM__M 0xFFFF
+#define IQM_COMM_INT_STM__PRE 0x0
+
+#define IQM_FS_COMM_EXEC__A 0x1820000
+#define IQM_FS_COMM_EXEC__W 2
+#define IQM_FS_COMM_EXEC__M 0x3
+#define IQM_FS_COMM_EXEC__PRE 0x0
+#define IQM_FS_COMM_EXEC_STOP 0x0
+#define IQM_FS_COMM_EXEC_ACTIVE 0x1
+#define IQM_FS_COMM_EXEC_HOLD 0x2
+
+#define IQM_FS_COMM_MB__A 0x1820002
+#define IQM_FS_COMM_MB__W 2
+#define IQM_FS_COMM_MB__M 0x3
+#define IQM_FS_COMM_MB__PRE 0x0
+#define IQM_FS_COMM_MB_CTL__B 0
+#define IQM_FS_COMM_MB_CTL__W 1
+#define IQM_FS_COMM_MB_CTL__M 0x1
+#define IQM_FS_COMM_MB_CTL__PRE 0x0
+#define IQM_FS_COMM_MB_CTL_CTL_OFF 0x0
+#define IQM_FS_COMM_MB_CTL_CTL_ON 0x1
+#define IQM_FS_COMM_MB_OBS__B 1
+#define IQM_FS_COMM_MB_OBS__W 1
+#define IQM_FS_COMM_MB_OBS__M 0x2
+#define IQM_FS_COMM_MB_OBS__PRE 0x0
+#define IQM_FS_COMM_MB_OBS_OBS_OFF 0x0
+#define IQM_FS_COMM_MB_OBS_OBS_ON 0x2
+
+#define IQM_FS_RATE_OFS_LO__A 0x1820010
+#define IQM_FS_RATE_OFS_LO__W 16
+#define IQM_FS_RATE_OFS_LO__M 0xFFFF
+#define IQM_FS_RATE_OFS_LO__PRE 0x0
+#define IQM_FS_RATE_OFS_HI__A 0x1820011
+#define IQM_FS_RATE_OFS_HI__W 12
+#define IQM_FS_RATE_OFS_HI__M 0xFFF
+#define IQM_FS_RATE_OFS_HI__PRE 0x0
+#define IQM_FS_RATE_LO__A 0x1820012
+#define IQM_FS_RATE_LO__W 16
+#define IQM_FS_RATE_LO__M 0xFFFF
+#define IQM_FS_RATE_LO__PRE 0x0
+#define IQM_FS_RATE_HI__A 0x1820013
+#define IQM_FS_RATE_HI__W 12
+#define IQM_FS_RATE_HI__M 0xFFF
+#define IQM_FS_RATE_HI__PRE 0x0
+
+#define IQM_FS_ADJ_SEL__A 0x1820014
+#define IQM_FS_ADJ_SEL__W 2
+#define IQM_FS_ADJ_SEL__M 0x3
+#define IQM_FS_ADJ_SEL__PRE 0x0
+#define IQM_FS_ADJ_SEL_OFF 0x0
+#define IQM_FS_ADJ_SEL_QAM 0x1
+#define IQM_FS_ADJ_SEL_VSB 0x2
+
+#define IQM_FD_COMM_EXEC__A 0x1830000
+#define IQM_FD_COMM_EXEC__W 2
+#define IQM_FD_COMM_EXEC__M 0x3
+#define IQM_FD_COMM_EXEC__PRE 0x0
+#define IQM_FD_COMM_EXEC_STOP 0x0
+#define IQM_FD_COMM_EXEC_ACTIVE 0x1
+#define IQM_FD_COMM_EXEC_HOLD 0x2
+
+#define IQM_FD_COMM_MB__A 0x1830002
+#define IQM_FD_COMM_MB__W 2
+#define IQM_FD_COMM_MB__M 0x3
+#define IQM_FD_COMM_MB__PRE 0x0
+#define IQM_FD_COMM_MB_CTL__B 0
+#define IQM_FD_COMM_MB_CTL__W 1
+#define IQM_FD_COMM_MB_CTL__M 0x1
+#define IQM_FD_COMM_MB_CTL__PRE 0x0
+#define IQM_FD_COMM_MB_CTL_CTL_OFF 0x0
+#define IQM_FD_COMM_MB_CTL_CTL_ON 0x1
+#define IQM_FD_COMM_MB_OBS__B 1
+#define IQM_FD_COMM_MB_OBS__W 1
+#define IQM_FD_COMM_MB_OBS__M 0x2
+#define IQM_FD_COMM_MB_OBS__PRE 0x0
+#define IQM_FD_COMM_MB_OBS_OBS_OFF 0x0
+#define IQM_FD_COMM_MB_OBS_OBS_ON 0x2
+
+#define IQM_RC_COMM_EXEC__A 0x1840000
+#define IQM_RC_COMM_EXEC__W 2
+#define IQM_RC_COMM_EXEC__M 0x3
+#define IQM_RC_COMM_EXEC__PRE 0x0
+#define IQM_RC_COMM_EXEC_STOP 0x0
+#define IQM_RC_COMM_EXEC_ACTIVE 0x1
+#define IQM_RC_COMM_EXEC_HOLD 0x2
+
+#define IQM_RC_COMM_MB__A 0x1840002
+#define IQM_RC_COMM_MB__W 2
+#define IQM_RC_COMM_MB__M 0x3
+#define IQM_RC_COMM_MB__PRE 0x0
+#define IQM_RC_COMM_MB_CTL__B 0
+#define IQM_RC_COMM_MB_CTL__W 1
+#define IQM_RC_COMM_MB_CTL__M 0x1
+#define IQM_RC_COMM_MB_CTL__PRE 0x0
+#define IQM_RC_COMM_MB_CTL_CTL_OFF 0x0
+#define IQM_RC_COMM_MB_CTL_CTL_ON 0x1
+#define IQM_RC_COMM_MB_OBS__B 1
+#define IQM_RC_COMM_MB_OBS__W 1
+#define IQM_RC_COMM_MB_OBS__M 0x2
+#define IQM_RC_COMM_MB_OBS__PRE 0x0
+#define IQM_RC_COMM_MB_OBS_OBS_OFF 0x0
+#define IQM_RC_COMM_MB_OBS_OBS_ON 0x2
+
+#define IQM_RC_RATE_OFS_LO__A 0x1840010
+#define IQM_RC_RATE_OFS_LO__W 16
+#define IQM_RC_RATE_OFS_LO__M 0xFFFF
+#define IQM_RC_RATE_OFS_LO__PRE 0x0
+#define IQM_RC_RATE_OFS_HI__A 0x1840011
+#define IQM_RC_RATE_OFS_HI__W 8
+#define IQM_RC_RATE_OFS_HI__M 0xFF
+#define IQM_RC_RATE_OFS_HI__PRE 0x0
+#define IQM_RC_RATE_LO__A 0x1840012
+#define IQM_RC_RATE_LO__W 16
+#define IQM_RC_RATE_LO__M 0xFFFF
+#define IQM_RC_RATE_LO__PRE 0x0
+#define IQM_RC_RATE_HI__A 0x1840013
+#define IQM_RC_RATE_HI__W 8
+#define IQM_RC_RATE_HI__M 0xFF
+#define IQM_RC_RATE_HI__PRE 0x0
+
+#define IQM_RC_ADJ_SEL__A 0x1840014
+#define IQM_RC_ADJ_SEL__W 2
+#define IQM_RC_ADJ_SEL__M 0x3
+#define IQM_RC_ADJ_SEL__PRE 0x0
+#define IQM_RC_ADJ_SEL_OFF 0x0
+#define IQM_RC_ADJ_SEL_QAM 0x1
+#define IQM_RC_ADJ_SEL_VSB 0x2
+
+#define IQM_RC_CROUT_ENA__A 0x1840015
+#define IQM_RC_CROUT_ENA__W 1
+#define IQM_RC_CROUT_ENA__M 0x1
+#define IQM_RC_CROUT_ENA__PRE 0x0
+
+#define IQM_RC_CROUT_ENA_ENA__B 0
+#define IQM_RC_CROUT_ENA_ENA__W 1
+#define IQM_RC_CROUT_ENA_ENA__M 0x1
+#define IQM_RC_CROUT_ENA_ENA__PRE 0x0
+
+#define IQM_RC_STRETCH__A 0x1840016
+#define IQM_RC_STRETCH__W 5
+#define IQM_RC_STRETCH__M 0x1F
+#define IQM_RC_STRETCH__PRE 0x0
+#define IQM_RC_STRETCH_QAM_B_64 0x1E
+#define IQM_RC_STRETCH_QAM_B_256 0x1C
+#define IQM_RC_STRETCH_ATV 0xF
+
+#define IQM_RT_COMM_EXEC__A 0x1850000
+#define IQM_RT_COMM_EXEC__W 2
+#define IQM_RT_COMM_EXEC__M 0x3
+#define IQM_RT_COMM_EXEC__PRE 0x0
+#define IQM_RT_COMM_EXEC_STOP 0x0
+#define IQM_RT_COMM_EXEC_ACTIVE 0x1
+#define IQM_RT_COMM_EXEC_HOLD 0x2
+
+#define IQM_RT_COMM_MB__A 0x1850002
+#define IQM_RT_COMM_MB__W 2
+#define IQM_RT_COMM_MB__M 0x3
+#define IQM_RT_COMM_MB__PRE 0x0
+#define IQM_RT_COMM_MB_CTL__B 0
+#define IQM_RT_COMM_MB_CTL__W 1
+#define IQM_RT_COMM_MB_CTL__M 0x1
+#define IQM_RT_COMM_MB_CTL__PRE 0x0
+#define IQM_RT_COMM_MB_CTL_CTL_OFF 0x0
+#define IQM_RT_COMM_MB_CTL_CTL_ON 0x1
+#define IQM_RT_COMM_MB_OBS__B 1
+#define IQM_RT_COMM_MB_OBS__W 1
+#define IQM_RT_COMM_MB_OBS__M 0x2
+#define IQM_RT_COMM_MB_OBS__PRE 0x0
+#define IQM_RT_COMM_MB_OBS_OBS_OFF 0x0
+#define IQM_RT_COMM_MB_OBS_OBS_ON 0x2
+
+#define IQM_RT_ACTIVE__A 0x1850010
+#define IQM_RT_ACTIVE__W 2
+#define IQM_RT_ACTIVE__M 0x3
+#define IQM_RT_ACTIVE__PRE 0x0
+
+#define IQM_RT_ACTIVE_ACTIVE_RT__B 0
+#define IQM_RT_ACTIVE_ACTIVE_RT__W 1
+#define IQM_RT_ACTIVE_ACTIVE_RT__M 0x1
+#define IQM_RT_ACTIVE_ACTIVE_RT__PRE 0x0
+#define IQM_RT_ACTIVE_ACTIVE_RT_ATV_FCR_OFF 0x0
+#define IQM_RT_ACTIVE_ACTIVE_RT_ATV_FCR_ON 0x1
+
+#define IQM_RT_ACTIVE_ACTIVE_CR__B 1
+#define IQM_RT_ACTIVE_ACTIVE_CR__W 1
+#define IQM_RT_ACTIVE_ACTIVE_CR__M 0x2
+#define IQM_RT_ACTIVE_ACTIVE_CR__PRE 0x0
+#define IQM_RT_ACTIVE_ACTIVE_CR_ATV_CR_OFF 0x0
+#define IQM_RT_ACTIVE_ACTIVE_CR_ATV_CR_ON 0x2
+
+#define IQM_RT_LO_INCR__A 0x1850011
+#define IQM_RT_LO_INCR__W 12
+#define IQM_RT_LO_INCR__M 0xFFF
+#define IQM_RT_LO_INCR__PRE 0x588
+#define IQM_RT_LO_INCR_FM 0x0
+#define IQM_RT_LO_INCR_MN 0x588
+
+#define IQM_RT_ROT_BP__A 0x1850012
+#define IQM_RT_ROT_BP__W 2
+#define IQM_RT_ROT_BP__M 0x3
+#define IQM_RT_ROT_BP__PRE 0x0
+
+#define IQM_RT_ROT_BP_ROT_OFF__B 0
+#define IQM_RT_ROT_BP_ROT_OFF__W 1
+#define IQM_RT_ROT_BP_ROT_OFF__M 0x1
+#define IQM_RT_ROT_BP_ROT_OFF__PRE 0x0
+#define IQM_RT_ROT_BP_ROT_OFF_ACTIVE 0x0
+#define IQM_RT_ROT_BP_ROT_OFF_OFF 0x1
+
+#define IQM_RT_ROT_BP_ROT_BPF__B 1
+#define IQM_RT_ROT_BP_ROT_BPF__W 1
+#define IQM_RT_ROT_BP_ROT_BPF__M 0x2
+#define IQM_RT_ROT_BP_ROT_BPF__PRE 0x0
+
+#define IQM_RT_LP_BP__A 0x1850013
+#define IQM_RT_LP_BP__W 1
+#define IQM_RT_LP_BP__M 0x1
+#define IQM_RT_LP_BP__PRE 0x0
+
+#define IQM_RT_DELAY__A 0x1850014
+#define IQM_RT_DELAY__W 7
+#define IQM_RT_DELAY__M 0x7F
+#define IQM_RT_DELAY__PRE 0x45
+
+#define IQM_CF_COMM_EXEC__A 0x1860000
+#define IQM_CF_COMM_EXEC__W 2
+#define IQM_CF_COMM_EXEC__M 0x3
+#define IQM_CF_COMM_EXEC__PRE 0x0
+#define IQM_CF_COMM_EXEC_STOP 0x0
+#define IQM_CF_COMM_EXEC_ACTIVE 0x1
+#define IQM_CF_COMM_EXEC_HOLD 0x2
+
+#define IQM_CF_COMM_MB__A 0x1860002
+#define IQM_CF_COMM_MB__W 2
+#define IQM_CF_COMM_MB__M 0x3
+#define IQM_CF_COMM_MB__PRE 0x0
+#define IQM_CF_COMM_MB_CTL__B 0
+#define IQM_CF_COMM_MB_CTL__W 1
+#define IQM_CF_COMM_MB_CTL__M 0x1
+#define IQM_CF_COMM_MB_CTL__PRE 0x0
+#define IQM_CF_COMM_MB_CTL_CTL_OFF 0x0
+#define IQM_CF_COMM_MB_CTL_CTL_ON 0x1
+#define IQM_CF_COMM_MB_OBS__B 1
+#define IQM_CF_COMM_MB_OBS__W 1
+#define IQM_CF_COMM_MB_OBS__M 0x2
+#define IQM_CF_COMM_MB_OBS__PRE 0x0
+#define IQM_CF_COMM_MB_OBS_OBS_OFF 0x0
+#define IQM_CF_COMM_MB_OBS_OBS_ON 0x2
+
+#define IQM_CF_COMM_INT_REQ__A 0x1860003
+#define IQM_CF_COMM_INT_REQ__W 1
+#define IQM_CF_COMM_INT_REQ__M 0x1
+#define IQM_CF_COMM_INT_REQ__PRE 0x0
+#define IQM_CF_COMM_INT_STA__A 0x1860005
+#define IQM_CF_COMM_INT_STA__W 1
+#define IQM_CF_COMM_INT_STA__M 0x1
+#define IQM_CF_COMM_INT_STA__PRE 0x0
+#define IQM_CF_COMM_INT_STA_PM__B 0
+#define IQM_CF_COMM_INT_STA_PM__W 1
+#define IQM_CF_COMM_INT_STA_PM__M 0x1
+#define IQM_CF_COMM_INT_STA_PM__PRE 0x0
+
+#define IQM_CF_COMM_INT_MSK__A 0x1860006
+#define IQM_CF_COMM_INT_MSK__W 1
+#define IQM_CF_COMM_INT_MSK__M 0x1
+#define IQM_CF_COMM_INT_MSK__PRE 0x0
+#define IQM_CF_COMM_INT_MSK_PM__B 0
+#define IQM_CF_COMM_INT_MSK_PM__W 1
+#define IQM_CF_COMM_INT_MSK_PM__M 0x1
+#define IQM_CF_COMM_INT_MSK_PM__PRE 0x0
+
+#define IQM_CF_COMM_INT_STM__A 0x1860007
+#define IQM_CF_COMM_INT_STM__W 1
+#define IQM_CF_COMM_INT_STM__M 0x1
+#define IQM_CF_COMM_INT_STM__PRE 0x0
+#define IQM_CF_COMM_INT_STM_PM__B 0
+#define IQM_CF_COMM_INT_STM_PM__W 1
+#define IQM_CF_COMM_INT_STM_PM__M 0x1
+#define IQM_CF_COMM_INT_STM_PM__PRE 0x0
+
+#define IQM_CF_SYMMETRIC__A 0x1860010
+#define IQM_CF_SYMMETRIC__W 2
+#define IQM_CF_SYMMETRIC__M 0x3
+#define IQM_CF_SYMMETRIC__PRE 0x0
+
+#define IQM_CF_SYMMETRIC_RE__B 0
+#define IQM_CF_SYMMETRIC_RE__W 1
+#define IQM_CF_SYMMETRIC_RE__M 0x1
+#define IQM_CF_SYMMETRIC_RE__PRE 0x0
+
+#define IQM_CF_SYMMETRIC_IM__B 1
+#define IQM_CF_SYMMETRIC_IM__W 1
+#define IQM_CF_SYMMETRIC_IM__M 0x2
+#define IQM_CF_SYMMETRIC_IM__PRE 0x0
+
+#define IQM_CF_MIDTAP__A 0x1860011
+#define IQM_CF_MIDTAP__W 2
+#define IQM_CF_MIDTAP__M 0x3
+#define IQM_CF_MIDTAP__PRE 0x3
+
+#define IQM_CF_MIDTAP_RE__B 0
+#define IQM_CF_MIDTAP_RE__W 1
+#define IQM_CF_MIDTAP_RE__M 0x1
+#define IQM_CF_MIDTAP_RE__PRE 0x1
+
+#define IQM_CF_MIDTAP_IM__B 1
+#define IQM_CF_MIDTAP_IM__W 1
+#define IQM_CF_MIDTAP_IM__M 0x2
+#define IQM_CF_MIDTAP_IM__PRE 0x2
+
+#define IQM_CF_OUT_ENA__A 0x1860012
+#define IQM_CF_OUT_ENA__W 3
+#define IQM_CF_OUT_ENA__M 0x7
+#define IQM_CF_OUT_ENA__PRE 0x0
+
+#define IQM_CF_OUT_ENA_ATV__B 0
+#define IQM_CF_OUT_ENA_ATV__W 1
+#define IQM_CF_OUT_ENA_ATV__M 0x1
+#define IQM_CF_OUT_ENA_ATV__PRE 0x0
+
+#define IQM_CF_OUT_ENA_QAM__B 1
+#define IQM_CF_OUT_ENA_QAM__W 1
+#define IQM_CF_OUT_ENA_QAM__M 0x2
+#define IQM_CF_OUT_ENA_QAM__PRE 0x0
+
+#define IQM_CF_OUT_ENA_VSB__B 2
+#define IQM_CF_OUT_ENA_VSB__W 1
+#define IQM_CF_OUT_ENA_VSB__M 0x4
+#define IQM_CF_OUT_ENA_VSB__PRE 0x0
+
+#define IQM_CF_ADJ_SEL__A 0x1860013
+#define IQM_CF_ADJ_SEL__W 2
+#define IQM_CF_ADJ_SEL__M 0x3
+#define IQM_CF_ADJ_SEL__PRE 0x0
+#define IQM_CF_SCALE__A 0x1860014
+#define IQM_CF_SCALE__W 14
+#define IQM_CF_SCALE__M 0x3FFF
+#define IQM_CF_SCALE__PRE 0x400
+
+#define IQM_CF_SCALE_SH__A 0x1860015
+#define IQM_CF_SCALE_SH__W 2
+#define IQM_CF_SCALE_SH__M 0x3
+#define IQM_CF_SCALE_SH__PRE 0x0
+
+#define IQM_CF_AMP__A 0x1860016
+#define IQM_CF_AMP__W 14
+#define IQM_CF_AMP__M 0x3FFF
+#define IQM_CF_AMP__PRE 0x0
+
+#define IQM_CF_POW_MEAS_LEN__A 0x1860017
+#define IQM_CF_POW_MEAS_LEN__W 3
+#define IQM_CF_POW_MEAS_LEN__M 0x7
+#define IQM_CF_POW_MEAS_LEN__PRE 0x2
+#define IQM_CF_POW_MEAS_LEN_QAM_B_64 0x1
+#define IQM_CF_POW_MEAS_LEN_QAM_B_256 0x1
+
+#define IQM_CF_POW__A 0x1860018
+#define IQM_CF_POW__W 16
+#define IQM_CF_POW__M 0xFFFF
+#define IQM_CF_POW__PRE 0x2
+#define IQM_CF_TAP_RE0__A 0x1860020
+#define IQM_CF_TAP_RE0__W 7
+#define IQM_CF_TAP_RE0__M 0x7F
+#define IQM_CF_TAP_RE0__PRE 0x2
+#define IQM_CF_TAP_RE1__A 0x1860021
+#define IQM_CF_TAP_RE1__W 7
+#define IQM_CF_TAP_RE1__M 0x7F
+#define IQM_CF_TAP_RE1__PRE 0x2
+#define IQM_CF_TAP_RE2__A 0x1860022
+#define IQM_CF_TAP_RE2__W 7
+#define IQM_CF_TAP_RE2__M 0x7F
+#define IQM_CF_TAP_RE2__PRE 0x2
+#define IQM_CF_TAP_RE3__A 0x1860023
+#define IQM_CF_TAP_RE3__W 7
+#define IQM_CF_TAP_RE3__M 0x7F
+#define IQM_CF_TAP_RE3__PRE 0x2
+#define IQM_CF_TAP_RE4__A 0x1860024
+#define IQM_CF_TAP_RE4__W 7
+#define IQM_CF_TAP_RE4__M 0x7F
+#define IQM_CF_TAP_RE4__PRE 0x2
+#define IQM_CF_TAP_RE5__A 0x1860025
+#define IQM_CF_TAP_RE5__W 7
+#define IQM_CF_TAP_RE5__M 0x7F
+#define IQM_CF_TAP_RE5__PRE 0x2
+#define IQM_CF_TAP_RE6__A 0x1860026
+#define IQM_CF_TAP_RE6__W 7
+#define IQM_CF_TAP_RE6__M 0x7F
+#define IQM_CF_TAP_RE6__PRE 0x2
+#define IQM_CF_TAP_RE7__A 0x1860027
+#define IQM_CF_TAP_RE7__W 9
+#define IQM_CF_TAP_RE7__M 0x1FF
+#define IQM_CF_TAP_RE7__PRE 0x2
+#define IQM_CF_TAP_RE8__A 0x1860028
+#define IQM_CF_TAP_RE8__W 9
+#define IQM_CF_TAP_RE8__M 0x1FF
+#define IQM_CF_TAP_RE8__PRE 0x2
+#define IQM_CF_TAP_RE9__A 0x1860029
+#define IQM_CF_TAP_RE9__W 9
+#define IQM_CF_TAP_RE9__M 0x1FF
+#define IQM_CF_TAP_RE9__PRE 0x2
+#define IQM_CF_TAP_RE10__A 0x186002A
+#define IQM_CF_TAP_RE10__W 9
+#define IQM_CF_TAP_RE10__M 0x1FF
+#define IQM_CF_TAP_RE10__PRE 0x2
+#define IQM_CF_TAP_RE11__A 0x186002B
+#define IQM_CF_TAP_RE11__W 9
+#define IQM_CF_TAP_RE11__M 0x1FF
+#define IQM_CF_TAP_RE11__PRE 0x2
+#define IQM_CF_TAP_RE12__A 0x186002C
+#define IQM_CF_TAP_RE12__W 9
+#define IQM_CF_TAP_RE12__M 0x1FF
+#define IQM_CF_TAP_RE12__PRE 0x2
+#define IQM_CF_TAP_RE13__A 0x186002D
+#define IQM_CF_TAP_RE13__W 9
+#define IQM_CF_TAP_RE13__M 0x1FF
+#define IQM_CF_TAP_RE13__PRE 0x2
+#define IQM_CF_TAP_RE14__A 0x186002E
+#define IQM_CF_TAP_RE14__W 9
+#define IQM_CF_TAP_RE14__M 0x1FF
+#define IQM_CF_TAP_RE14__PRE 0x2
+#define IQM_CF_TAP_RE15__A 0x186002F
+#define IQM_CF_TAP_RE15__W 9
+#define IQM_CF_TAP_RE15__M 0x1FF
+#define IQM_CF_TAP_RE15__PRE 0x2
+#define IQM_CF_TAP_RE16__A 0x1860030
+#define IQM_CF_TAP_RE16__W 9
+#define IQM_CF_TAP_RE16__M 0x1FF
+#define IQM_CF_TAP_RE16__PRE 0x2
+#define IQM_CF_TAP_RE17__A 0x1860031
+#define IQM_CF_TAP_RE17__W 9
+#define IQM_CF_TAP_RE17__M 0x1FF
+#define IQM_CF_TAP_RE17__PRE 0x2
+#define IQM_CF_TAP_RE18__A 0x1860032
+#define IQM_CF_TAP_RE18__W 9
+#define IQM_CF_TAP_RE18__M 0x1FF
+#define IQM_CF_TAP_RE18__PRE 0x2
+#define IQM_CF_TAP_RE19__A 0x1860033
+#define IQM_CF_TAP_RE19__W 9
+#define IQM_CF_TAP_RE19__M 0x1FF
+#define IQM_CF_TAP_RE19__PRE 0x2
+#define IQM_CF_TAP_RE20__A 0x1860034
+#define IQM_CF_TAP_RE20__W 9
+#define IQM_CF_TAP_RE20__M 0x1FF
+#define IQM_CF_TAP_RE20__PRE 0x2
+#define IQM_CF_TAP_RE21__A 0x1860035
+#define IQM_CF_TAP_RE21__W 11
+#define IQM_CF_TAP_RE21__M 0x7FF
+#define IQM_CF_TAP_RE21__PRE 0x2
+#define IQM_CF_TAP_RE22__A 0x1860036
+#define IQM_CF_TAP_RE22__W 11
+#define IQM_CF_TAP_RE22__M 0x7FF
+#define IQM_CF_TAP_RE22__PRE 0x2
+#define IQM_CF_TAP_RE23__A 0x1860037
+#define IQM_CF_TAP_RE23__W 11
+#define IQM_CF_TAP_RE23__M 0x7FF
+#define IQM_CF_TAP_RE23__PRE 0x2
+#define IQM_CF_TAP_RE24__A 0x1860038
+#define IQM_CF_TAP_RE24__W 11
+#define IQM_CF_TAP_RE24__M 0x7FF
+#define IQM_CF_TAP_RE24__PRE 0x2
+#define IQM_CF_TAP_RE25__A 0x1860039
+#define IQM_CF_TAP_RE25__W 11
+#define IQM_CF_TAP_RE25__M 0x7FF
+#define IQM_CF_TAP_RE25__PRE 0x2
+#define IQM_CF_TAP_RE26__A 0x186003A
+#define IQM_CF_TAP_RE26__W 11
+#define IQM_CF_TAP_RE26__M 0x7FF
+#define IQM_CF_TAP_RE26__PRE 0x2
+#define IQM_CF_TAP_RE27__A 0x186003B
+#define IQM_CF_TAP_RE27__W 11
+#define IQM_CF_TAP_RE27__M 0x7FF
+#define IQM_CF_TAP_RE27__PRE 0x2
+#define IQM_CF_TAP_IM0__A 0x1860040
+#define IQM_CF_TAP_IM0__W 7
+#define IQM_CF_TAP_IM0__M 0x7F
+#define IQM_CF_TAP_IM0__PRE 0x2
+#define IQM_CF_TAP_IM1__A 0x1860041
+#define IQM_CF_TAP_IM1__W 7
+#define IQM_CF_TAP_IM1__M 0x7F
+#define IQM_CF_TAP_IM1__PRE 0x2
+#define IQM_CF_TAP_IM2__A 0x1860042
+#define IQM_CF_TAP_IM2__W 7
+#define IQM_CF_TAP_IM2__M 0x7F
+#define IQM_CF_TAP_IM2__PRE 0x2
+#define IQM_CF_TAP_IM3__A 0x1860043
+#define IQM_CF_TAP_IM3__W 7
+#define IQM_CF_TAP_IM3__M 0x7F
+#define IQM_CF_TAP_IM3__PRE 0x2
+#define IQM_CF_TAP_IM4__A 0x1860044
+#define IQM_CF_TAP_IM4__W 7
+#define IQM_CF_TAP_IM4__M 0x7F
+#define IQM_CF_TAP_IM4__PRE 0x2
+#define IQM_CF_TAP_IM5__A 0x1860045
+#define IQM_CF_TAP_IM5__W 7
+#define IQM_CF_TAP_IM5__M 0x7F
+#define IQM_CF_TAP_IM5__PRE 0x2
+#define IQM_CF_TAP_IM6__A 0x1860046
+#define IQM_CF_TAP_IM6__W 7
+#define IQM_CF_TAP_IM6__M 0x7F
+#define IQM_CF_TAP_IM6__PRE 0x2
+#define IQM_CF_TAP_IM7__A 0x1860047
+#define IQM_CF_TAP_IM7__W 9
+#define IQM_CF_TAP_IM7__M 0x1FF
+#define IQM_CF_TAP_IM7__PRE 0x2
+#define IQM_CF_TAP_IM8__A 0x1860048
+#define IQM_CF_TAP_IM8__W 9
+#define IQM_CF_TAP_IM8__M 0x1FF
+#define IQM_CF_TAP_IM8__PRE 0x2
+#define IQM_CF_TAP_IM9__A 0x1860049
+#define IQM_CF_TAP_IM9__W 9
+#define IQM_CF_TAP_IM9__M 0x1FF
+#define IQM_CF_TAP_IM9__PRE 0x2
+#define IQM_CF_TAP_IM10__A 0x186004A
+#define IQM_CF_TAP_IM10__W 9
+#define IQM_CF_TAP_IM10__M 0x1FF
+#define IQM_CF_TAP_IM10__PRE 0x2
+#define IQM_CF_TAP_IM11__A 0x186004B
+#define IQM_CF_TAP_IM11__W 9
+#define IQM_CF_TAP_IM11__M 0x1FF
+#define IQM_CF_TAP_IM11__PRE 0x2
+#define IQM_CF_TAP_IM12__A 0x186004C
+#define IQM_CF_TAP_IM12__W 9
+#define IQM_CF_TAP_IM12__M 0x1FF
+#define IQM_CF_TAP_IM12__PRE 0x2
+#define IQM_CF_TAP_IM13__A 0x186004D
+#define IQM_CF_TAP_IM13__W 9
+#define IQM_CF_TAP_IM13__M 0x1FF
+#define IQM_CF_TAP_IM13__PRE 0x2
+#define IQM_CF_TAP_IM14__A 0x186004E
+#define IQM_CF_TAP_IM14__W 9
+#define IQM_CF_TAP_IM14__M 0x1FF
+#define IQM_CF_TAP_IM14__PRE 0x2
+#define IQM_CF_TAP_IM15__A 0x186004F
+#define IQM_CF_TAP_IM15__W 9
+#define IQM_CF_TAP_IM15__M 0x1FF
+#define IQM_CF_TAP_IM15__PRE 0x2
+#define IQM_CF_TAP_IM16__A 0x1860050
+#define IQM_CF_TAP_IM16__W 9
+#define IQM_CF_TAP_IM16__M 0x1FF
+#define IQM_CF_TAP_IM16__PRE 0x2
+#define IQM_CF_TAP_IM17__A 0x1860051
+#define IQM_CF_TAP_IM17__W 9
+#define IQM_CF_TAP_IM17__M 0x1FF
+#define IQM_CF_TAP_IM17__PRE 0x2
+#define IQM_CF_TAP_IM18__A 0x1860052
+#define IQM_CF_TAP_IM18__W 9
+#define IQM_CF_TAP_IM18__M 0x1FF
+#define IQM_CF_TAP_IM18__PRE 0x2
+#define IQM_CF_TAP_IM19__A 0x1860053
+#define IQM_CF_TAP_IM19__W 9
+#define IQM_CF_TAP_IM19__M 0x1FF
+#define IQM_CF_TAP_IM19__PRE 0x2
+#define IQM_CF_TAP_IM20__A 0x1860054
+#define IQM_CF_TAP_IM20__W 9
+#define IQM_CF_TAP_IM20__M 0x1FF
+#define IQM_CF_TAP_IM20__PRE 0x2
+#define IQM_CF_TAP_IM21__A 0x1860055
+#define IQM_CF_TAP_IM21__W 11
+#define IQM_CF_TAP_IM21__M 0x7FF
+#define IQM_CF_TAP_IM21__PRE 0x2
+#define IQM_CF_TAP_IM22__A 0x1860056
+#define IQM_CF_TAP_IM22__W 11
+#define IQM_CF_TAP_IM22__M 0x7FF
+#define IQM_CF_TAP_IM22__PRE 0x2
+#define IQM_CF_TAP_IM23__A 0x1860057
+#define IQM_CF_TAP_IM23__W 11
+#define IQM_CF_TAP_IM23__M 0x7FF
+#define IQM_CF_TAP_IM23__PRE 0x2
+#define IQM_CF_TAP_IM24__A 0x1860058
+#define IQM_CF_TAP_IM24__W 11
+#define IQM_CF_TAP_IM24__M 0x7FF
+#define IQM_CF_TAP_IM24__PRE 0x2
+#define IQM_CF_TAP_IM25__A 0x1860059
+#define IQM_CF_TAP_IM25__W 11
+#define IQM_CF_TAP_IM25__M 0x7FF
+#define IQM_CF_TAP_IM25__PRE 0x2
+#define IQM_CF_TAP_IM26__A 0x186005A
+#define IQM_CF_TAP_IM26__W 11
+#define IQM_CF_TAP_IM26__M 0x7FF
+#define IQM_CF_TAP_IM26__PRE 0x2
+#define IQM_CF_TAP_IM27__A 0x186005B
+#define IQM_CF_TAP_IM27__W 11
+#define IQM_CF_TAP_IM27__M 0x7FF
+#define IQM_CF_TAP_IM27__PRE 0x2
+
+#define IQM_AF_COMM_EXEC__A 0x1870000
+#define IQM_AF_COMM_EXEC__W 2
+#define IQM_AF_COMM_EXEC__M 0x3
+#define IQM_AF_COMM_EXEC__PRE 0x0
+#define IQM_AF_COMM_EXEC_STOP 0x0
+#define IQM_AF_COMM_EXEC_ACTIVE 0x1
+#define IQM_AF_COMM_EXEC_HOLD 0x2
+
+#define IQM_AF_COMM_MB__A 0x1870002
+#define IQM_AF_COMM_MB__W 8
+#define IQM_AF_COMM_MB__M 0xFF
+#define IQM_AF_COMM_MB__PRE 0x0
+#define IQM_AF_COMM_MB_CTL__B 0
+#define IQM_AF_COMM_MB_CTL__W 1
+#define IQM_AF_COMM_MB_CTL__M 0x1
+#define IQM_AF_COMM_MB_CTL__PRE 0x0
+#define IQM_AF_COMM_MB_CTL_CTL_OFF 0x0
+#define IQM_AF_COMM_MB_CTL_CTL_ON 0x1
+#define IQM_AF_COMM_MB_OBS__B 1
+#define IQM_AF_COMM_MB_OBS__W 1
+#define IQM_AF_COMM_MB_OBS__M 0x2
+#define IQM_AF_COMM_MB_OBS__PRE 0x0
+#define IQM_AF_COMM_MB_OBS_OBS_OFF 0x0
+#define IQM_AF_COMM_MB_OBS_OBS_ON 0x2
+#define IQM_AF_COMM_MB_MUX_CTRL__B 2
+#define IQM_AF_COMM_MB_MUX_CTRL__W 3
+#define IQM_AF_COMM_MB_MUX_CTRL__M 0x1C
+#define IQM_AF_COMM_MB_MUX_CTRL__PRE 0x0
+#define IQM_AF_COMM_MB_MUX_CTRL_AF_DATA_INPUT 0x0
+#define IQM_AF_COMM_MB_MUX_CTRL_SENSE_INPUT 0x4
+#define IQM_AF_COMM_MB_MUX_CTRL_AF_DATA_OUTPUT 0x8
+#define IQM_AF_COMM_MB_MUX_CTRL_IF_AGC_OUTPUT 0xC
+#define IQM_AF_COMM_MB_MUX_CTRL_RF_AGC_OUTPUT 0x10
+#define IQM_AF_COMM_MB_MUX_OBS__B 5
+#define IQM_AF_COMM_MB_MUX_OBS__W 3
+#define IQM_AF_COMM_MB_MUX_OBS__M 0xE0
+#define IQM_AF_COMM_MB_MUX_OBS__PRE 0x0
+#define IQM_AF_COMM_MB_MUX_OBS_AF_DATA_INPUT 0x0
+#define IQM_AF_COMM_MB_MUX_OBS_SENSE_INPUT 0x20
+#define IQM_AF_COMM_MB_MUX_OBS_AF_DATA_OUTPUT 0x40
+#define IQM_AF_COMM_MB_MUX_OBS_IF_AGC_OUTPUT 0x60
+#define IQM_AF_COMM_MB_MUX_OBS_RF_AGC_OUTPUT 0x80
+
+#define IQM_AF_COMM_INT_REQ__A 0x1870003
+#define IQM_AF_COMM_INT_REQ__W 1
+#define IQM_AF_COMM_INT_REQ__M 0x1
+#define IQM_AF_COMM_INT_REQ__PRE 0x0
+#define IQM_AF_COMM_INT_STA__A 0x1870005
+#define IQM_AF_COMM_INT_STA__W 2
+#define IQM_AF_COMM_INT_STA__M 0x3
+#define IQM_AF_COMM_INT_STA__PRE 0x0
+#define IQM_AF_COMM_INT_STA_CLP_INT_STA__B 0
+#define IQM_AF_COMM_INT_STA_CLP_INT_STA__W 1
+#define IQM_AF_COMM_INT_STA_CLP_INT_STA__M 0x1
+#define IQM_AF_COMM_INT_STA_CLP_INT_STA__PRE 0x0
+#define IQM_AF_COMM_INT_STA_SNS_INT_STA__B 1
+#define IQM_AF_COMM_INT_STA_SNS_INT_STA__W 1
+#define IQM_AF_COMM_INT_STA_SNS_INT_STA__M 0x2
+#define IQM_AF_COMM_INT_STA_SNS_INT_STA__PRE 0x0
+
+#define IQM_AF_COMM_INT_MSK__A 0x1870006
+#define IQM_AF_COMM_INT_MSK__W 2
+#define IQM_AF_COMM_INT_MSK__M 0x3
+#define IQM_AF_COMM_INT_MSK__PRE 0x0
+#define IQM_AF_COMM_INT_MSK_CLP_INT_MSK__B 0
+#define IQM_AF_COMM_INT_MSK_CLP_INT_MSK__W 1
+#define IQM_AF_COMM_INT_MSK_CLP_INT_MSK__M 0x1
+#define IQM_AF_COMM_INT_MSK_CLP_INT_MSK__PRE 0x0
+#define IQM_AF_COMM_INT_MSK_SNS_INT_MSK__B 1
+#define IQM_AF_COMM_INT_MSK_SNS_INT_MSK__W 1
+#define IQM_AF_COMM_INT_MSK_SNS_INT_MSK__M 0x2
+#define IQM_AF_COMM_INT_MSK_SNS_INT_MSK__PRE 0x0
+
+#define IQM_AF_COMM_INT_STM__A 0x1870007
+#define IQM_AF_COMM_INT_STM__W 2
+#define IQM_AF_COMM_INT_STM__M 0x3
+#define IQM_AF_COMM_INT_STM__PRE 0x0
+#define IQM_AF_COMM_INT_STM_CLP_INT_STA__B 0
+#define IQM_AF_COMM_INT_STM_CLP_INT_STA__W 1
+#define IQM_AF_COMM_INT_STM_CLP_INT_STA__M 0x1
+#define IQM_AF_COMM_INT_STM_CLP_INT_STA__PRE 0x0
+#define IQM_AF_COMM_INT_STM_SNS_INT_STA__B 1
+#define IQM_AF_COMM_INT_STM_SNS_INT_STA__W 1
+#define IQM_AF_COMM_INT_STM_SNS_INT_STA__M 0x2
+#define IQM_AF_COMM_INT_STM_SNS_INT_STA__PRE 0x0
+
+#define IQM_AF_FDB_SEL__A 0x1870010
+#define IQM_AF_FDB_SEL__W 1
+#define IQM_AF_FDB_SEL__M 0x1
+#define IQM_AF_FDB_SEL__PRE 0x0
+
+#define IQM_AF_INVEXT__A 0x1870011
+#define IQM_AF_INVEXT__W 1
+#define IQM_AF_INVEXT__M 0x1
+#define IQM_AF_INVEXT__PRE 0x0
+#define IQM_AF_CLKNEG__A 0x1870012
+#define IQM_AF_CLKNEG__W 2
+#define IQM_AF_CLKNEG__M 0x3
+#define IQM_AF_CLKNEG__PRE 0x0
+
+#define IQM_AF_CLKNEG_CLKNEGPEAK__B 0
+#define IQM_AF_CLKNEG_CLKNEGPEAK__W 1
+#define IQM_AF_CLKNEG_CLKNEGPEAK__M 0x1
+#define IQM_AF_CLKNEG_CLKNEGPEAK__PRE 0x0
+#define IQM_AF_CLKNEG_CLKNEGPEAK_CLK_ADC_PEAK_POS 0x0
+#define IQM_AF_CLKNEG_CLKNEGPEAK_CLK_ADC_PEAK_NEG 0x1
+
+#define IQM_AF_CLKNEG_CLKNEGDATA__B 1
+#define IQM_AF_CLKNEG_CLKNEGDATA__W 1
+#define IQM_AF_CLKNEG_CLKNEGDATA__M 0x2
+#define IQM_AF_CLKNEG_CLKNEGDATA__PRE 0x0
+#define IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS 0x0
+#define IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_NEG 0x2
+
+#define IQM_AF_MON_IN_MUX__A 0x1870013
+#define IQM_AF_MON_IN_MUX__W 2
+#define IQM_AF_MON_IN_MUX__M 0x3
+#define IQM_AF_MON_IN_MUX__PRE 0x0
+
+#define IQM_AF_MON_IN5__A 0x1870014
+#define IQM_AF_MON_IN5__W 10
+#define IQM_AF_MON_IN5__M 0x3FF
+#define IQM_AF_MON_IN5__PRE 0x0
+
+#define IQM_AF_MON_IN4__A 0x1870015
+#define IQM_AF_MON_IN4__W 10
+#define IQM_AF_MON_IN4__M 0x3FF
+#define IQM_AF_MON_IN4__PRE 0x0
+
+#define IQM_AF_MON_IN3__A 0x1870016
+#define IQM_AF_MON_IN3__W 10
+#define IQM_AF_MON_IN3__M 0x3FF
+#define IQM_AF_MON_IN3__PRE 0x0
+
+#define IQM_AF_MON_IN2__A 0x1870017
+#define IQM_AF_MON_IN2__W 10
+#define IQM_AF_MON_IN2__M 0x3FF
+#define IQM_AF_MON_IN2__PRE 0x0
+
+#define IQM_AF_MON_IN1__A 0x1870018
+#define IQM_AF_MON_IN1__W 10
+#define IQM_AF_MON_IN1__M 0x3FF
+#define IQM_AF_MON_IN1__PRE 0x0
+
+#define IQM_AF_MON_IN0__A 0x1870019
+#define IQM_AF_MON_IN0__W 10
+#define IQM_AF_MON_IN0__M 0x3FF
+#define IQM_AF_MON_IN0__PRE 0x0
+
+#define IQM_AF_MON_IN_VAL__A 0x187001A
+#define IQM_AF_MON_IN_VAL__W 1
+#define IQM_AF_MON_IN_VAL__M 0x1
+#define IQM_AF_MON_IN_VAL__PRE 0x0
+
+#define IQM_AF_START_LOCK__A 0x187001B
+#define IQM_AF_START_LOCK__W 1
+#define IQM_AF_START_LOCK__M 0x1
+#define IQM_AF_START_LOCK__PRE 0x0
+
+#define IQM_AF_PHASE0__A 0x187001C
+#define IQM_AF_PHASE0__W 7
+#define IQM_AF_PHASE0__M 0x7F
+#define IQM_AF_PHASE0__PRE 0x0
+
+#define IQM_AF_PHASE1__A 0x187001D
+#define IQM_AF_PHASE1__W 7
+#define IQM_AF_PHASE1__M 0x7F
+#define IQM_AF_PHASE1__PRE 0x0
+
+#define IQM_AF_PHASE2__A 0x187001E
+#define IQM_AF_PHASE2__W 7
+#define IQM_AF_PHASE2__M 0x7F
+#define IQM_AF_PHASE2__PRE 0x0
+
+#define IQM_AF_SCU_PHASE__A 0x187001F
+#define IQM_AF_SCU_PHASE__W 2
+#define IQM_AF_SCU_PHASE__M 0x3
+#define IQM_AF_SCU_PHASE__PRE 0x0
+
+#define IQM_AF_SYNC_SEL__A 0x1870020
+#define IQM_AF_SYNC_SEL__W 2
+#define IQM_AF_SYNC_SEL__M 0x3
+#define IQM_AF_SYNC_SEL__PRE 0x0
+#define IQM_AF_ADC_CONF__A 0x1870021
+#define IQM_AF_ADC_CONF__W 4
+#define IQM_AF_ADC_CONF__M 0xF
+#define IQM_AF_ADC_CONF__PRE 0x0
+
+#define IQM_AF_ADC_CONF_ADC_SIGN__B 0
+#define IQM_AF_ADC_CONF_ADC_SIGN__W 1
+#define IQM_AF_ADC_CONF_ADC_SIGN__M 0x1
+#define IQM_AF_ADC_CONF_ADC_SIGN__PRE 0x0
+#define IQM_AF_ADC_CONF_ADC_SIGN_ADC_SIGNED 0x0
+#define IQM_AF_ADC_CONF_ADC_SIGN_ADC_UNSIGNED 0x1
+
+#define IQM_AF_ADC_CONF_BITREVERSE_ADC__B 1
+#define IQM_AF_ADC_CONF_BITREVERSE_ADC__W 1
+#define IQM_AF_ADC_CONF_BITREVERSE_ADC__M 0x2
+#define IQM_AF_ADC_CONF_BITREVERSE_ADC__PRE 0x0
+#define IQM_AF_ADC_CONF_BITREVERSE_ADC_ADC_NORMAL 0x0
+#define IQM_AF_ADC_CONF_BITREVERSE_ADC_ADC_BITREVERSED 0x2
+
+#define IQM_AF_ADC_CONF_BITREVERSE_NSSI__B 2
+#define IQM_AF_ADC_CONF_BITREVERSE_NSSI__W 1
+#define IQM_AF_ADC_CONF_BITREVERSE_NSSI__M 0x4
+#define IQM_AF_ADC_CONF_BITREVERSE_NSSI__PRE 0x0
+#define IQM_AF_ADC_CONF_BITREVERSE_NSSI_IFAGC_DAC_NORMAL 0x0
+#define IQM_AF_ADC_CONF_BITREVERSE_NSSI_IFAGC_DAC_BITREVERSED 0x4
+
+#define IQM_AF_ADC_CONF_BITREVERSE_NSSR__B 3
+#define IQM_AF_ADC_CONF_BITREVERSE_NSSR__W 1
+#define IQM_AF_ADC_CONF_BITREVERSE_NSSR__M 0x8
+#define IQM_AF_ADC_CONF_BITREVERSE_NSSR__PRE 0x0
+#define IQM_AF_ADC_CONF_BITREVERSE_NSSR_RFAGC_DAC_NORMAL 0x0
+#define IQM_AF_ADC_CONF_BITREVERSE_NSSR_RFAGC_DAC_BITREVERSED 0x8
+
+#define IQM_AF_CLP_CLIP__A 0x1870022
+#define IQM_AF_CLP_CLIP__W 16
+#define IQM_AF_CLP_CLIP__M 0xFFFF
+#define IQM_AF_CLP_CLIP__PRE 0x0
+
+#define IQM_AF_CLP_LEN__A 0x1870023
+#define IQM_AF_CLP_LEN__W 16
+#define IQM_AF_CLP_LEN__M 0xFFFF
+#define IQM_AF_CLP_LEN__PRE 0x0
+#define IQM_AF_CLP_LEN_QAM_B_64 0x400
+#define IQM_AF_CLP_LEN_QAM_B_256 0x400
+#define IQM_AF_CLP_LEN_ATV 0x0
+
+#define IQM_AF_CLP_TH__A 0x1870024
+#define IQM_AF_CLP_TH__W 9
+#define IQM_AF_CLP_TH__M 0x1FF
+#define IQM_AF_CLP_TH__PRE 0x0
+#define IQM_AF_CLP_TH_QAM_B_64 0x80
+#define IQM_AF_CLP_TH_QAM_B_256 0x80
+#define IQM_AF_CLP_TH_ATV 0x1C0
+
+#define IQM_AF_DCF_BYPASS__A 0x1870025
+#define IQM_AF_DCF_BYPASS__W 1
+#define IQM_AF_DCF_BYPASS__M 0x1
+#define IQM_AF_DCF_BYPASS__PRE 0x0
+#define IQM_AF_DCF_BYPASS_ACTIVE 0x0
+#define IQM_AF_DCF_BYPASS_BYPASS 0x1
+
+#define IQM_AF_SNS_LEN__A 0x1870026
+#define IQM_AF_SNS_LEN__W 16
+#define IQM_AF_SNS_LEN__M 0xFFFF
+#define IQM_AF_SNS_LEN__PRE 0x0
+#define IQM_AF_SNS_LEN_QAM_B_64 0x400
+#define IQM_AF_SNS_LEN_QAM_B_256 0x400
+#define IQM_AF_SNS_LEN_ATV 0x0
+
+#define IQM_AF_SNS_SENSE__A 0x1870027
+#define IQM_AF_SNS_SENSE__W 16
+#define IQM_AF_SNS_SENSE__M 0xFFFF
+#define IQM_AF_SNS_SENSE__PRE 0x0
+
+#define IQM_AF_AGC_IF__A 0x1870028
+#define IQM_AF_AGC_IF__W 15
+#define IQM_AF_AGC_IF__M 0x7FFF
+#define IQM_AF_AGC_IF__PRE 0x0
+
+#define IQM_AF_AGC_RF__A 0x1870029
+#define IQM_AF_AGC_RF__W 15
+#define IQM_AF_AGC_RF__M 0x7FFF
+#define IQM_AF_AGC_RF__PRE 0x0
+
+#define IQM_AF_PGA_GAIN__A 0x187002A
+#define IQM_AF_PGA_GAIN__W 4
+#define IQM_AF_PGA_GAIN__M 0xF
+#define IQM_AF_PGA_GAIN__PRE 0x0
+
+#define IQM_AF_PDREF__A 0x187002B
+#define IQM_AF_PDREF__W 5
+#define IQM_AF_PDREF__M 0x1F
+#define IQM_AF_PDREF__PRE 0x0
+#define IQM_AF_PDREF_QAM_B_64 0xF
+#define IQM_AF_PDREF_QAM_B_256 0xF
+#define IQM_AF_PDREF_ATV 0xF
+
+#define IQM_AF_STDBY__A 0x187002C
+#define IQM_AF_STDBY__W 6
+#define IQM_AF_STDBY__M 0x3F
+#define IQM_AF_STDBY__PRE 0x0
+
+#define IQM_AF_STDBY_STDBY_BIAS__B 0
+#define IQM_AF_STDBY_STDBY_BIAS__W 1
+#define IQM_AF_STDBY_STDBY_BIAS__M 0x1
+#define IQM_AF_STDBY_STDBY_BIAS__PRE 0x0
+#define IQM_AF_STDBY_STDBY_BIAS_ACTIVE 0x0
+#define IQM_AF_STDBY_STDBY_BIAS_STANDBY 0x1
+
+#define IQM_AF_STDBY_STDBY_ADC__B 1
+#define IQM_AF_STDBY_STDBY_ADC__W 1
+#define IQM_AF_STDBY_STDBY_ADC__M 0x2
+#define IQM_AF_STDBY_STDBY_ADC__PRE 0x0
+#define IQM_AF_STDBY_STDBY_ADC_A1_ACTIVE 0x0
+#define IQM_AF_STDBY_STDBY_ADC_A1_STANDBY 0x2
+#define IQM_AF_STDBY_STDBY_ADC_A2_ACTIVE 0x2
+#define IQM_AF_STDBY_STDBY_ADC_A2_STANDBY 0x0
+
+#define IQM_AF_STDBY_STDBY_AMP__B 2
+#define IQM_AF_STDBY_STDBY_AMP__W 1
+#define IQM_AF_STDBY_STDBY_AMP__M 0x4
+#define IQM_AF_STDBY_STDBY_AMP__PRE 0x0
+#define IQM_AF_STDBY_STDBY_AMP_A1_ACTIVE 0x0
+#define IQM_AF_STDBY_STDBY_AMP_A1_STANDBY 0x4
+#define IQM_AF_STDBY_STDBY_AMP_A2_ACTIVE 0x4
+#define IQM_AF_STDBY_STDBY_AMP_A2_STANDBY 0x0
+
+#define IQM_AF_STDBY_STDBY_PD__B 3
+#define IQM_AF_STDBY_STDBY_PD__W 1
+#define IQM_AF_STDBY_STDBY_PD__M 0x8
+#define IQM_AF_STDBY_STDBY_PD__PRE 0x0
+#define IQM_AF_STDBY_STDBY_PD_A1_ACTIVE 0x0
+#define IQM_AF_STDBY_STDBY_PD_A1_STANDBY 0x8
+#define IQM_AF_STDBY_STDBY_PD_A2_ACTIVE 0x8
+#define IQM_AF_STDBY_STDBY_PD_A2_STANDBY 0x0
+
+#define IQM_AF_STDBY_STDBY_TAGC_IF__B 4
+#define IQM_AF_STDBY_STDBY_TAGC_IF__W 1
+#define IQM_AF_STDBY_STDBY_TAGC_IF__M 0x10
+#define IQM_AF_STDBY_STDBY_TAGC_IF__PRE 0x0
+#define IQM_AF_STDBY_STDBY_TAGC_IF_A1_ACTIVE 0x0
+#define IQM_AF_STDBY_STDBY_TAGC_IF_A1_STANDBY 0x10
+#define IQM_AF_STDBY_STDBY_TAGC_IF_A2_ACTIVE 0x10
+#define IQM_AF_STDBY_STDBY_TAGC_IF_A2_STANDBY 0x0
+
+#define IQM_AF_STDBY_STDBY_TAGC_RF__B 5
+#define IQM_AF_STDBY_STDBY_TAGC_RF__W 1
+#define IQM_AF_STDBY_STDBY_TAGC_RF__M 0x20
+#define IQM_AF_STDBY_STDBY_TAGC_RF__PRE 0x0
+#define IQM_AF_STDBY_STDBY_TAGC_RF_A1_ACTIVE 0x0
+#define IQM_AF_STDBY_STDBY_TAGC_RF_A1_STANDBY 0x20
+#define IQM_AF_STDBY_STDBY_TAGC_RF_A2_ACTIVE 0x20
+#define IQM_AF_STDBY_STDBY_TAGC_RF_A2_STANDBY 0x0
+
+#define IQM_AF_AMUX__A 0x187002D
+#define IQM_AF_AMUX__W 2
+#define IQM_AF_AMUX__M 0x3
+#define IQM_AF_AMUX__PRE 0x0
+
+#define IQM_AF_TST_AFEMAIN__A 0x187002E
+#define IQM_AF_TST_AFEMAIN__W 8
+#define IQM_AF_TST_AFEMAIN__M 0xFF
+#define IQM_AF_TST_AFEMAIN__PRE 0x0
+
+#define IQM_RT_RAM__A 0x1880000
+
+#define IQM_RT_RAM_DLY__B 0
+#define IQM_RT_RAM_DLY__W 13
+#define IQM_RT_RAM_DLY__M 0x1FFF
+#define IQM_RT_RAM_DLY__PRE 0x0
+
+#define ORX_COMM_EXEC__A 0x2000000
+#define ORX_COMM_EXEC__W 2
+#define ORX_COMM_EXEC__M 0x3
+#define ORX_COMM_EXEC__PRE 0x0
+#define ORX_COMM_EXEC_STOP 0x0
+#define ORX_COMM_EXEC_ACTIVE 0x1
+#define ORX_COMM_EXEC_HOLD 0x2
+
+#define ORX_COMM_STATE__A 0x2000001
+#define ORX_COMM_STATE__W 16
+#define ORX_COMM_STATE__M 0xFFFF
+#define ORX_COMM_STATE__PRE 0x0
+#define ORX_COMM_MB__A 0x2000002
+#define ORX_COMM_MB__W 16
+#define ORX_COMM_MB__M 0xFFFF
+#define ORX_COMM_MB__PRE 0x0
+#define ORX_COMM_INT_REQ__A 0x2000003
+#define ORX_COMM_INT_REQ__W 16
+#define ORX_COMM_INT_REQ__M 0xFFFF
+#define ORX_COMM_INT_REQ__PRE 0x0
+#define ORX_COMM_INT_REQ_EQU_REQ__B 0
+#define ORX_COMM_INT_REQ_EQU_REQ__W 1
+#define ORX_COMM_INT_REQ_EQU_REQ__M 0x1
+#define ORX_COMM_INT_REQ_EQU_REQ__PRE 0x0
+#define ORX_COMM_INT_REQ_DDC_REQ__B 1
+#define ORX_COMM_INT_REQ_DDC_REQ__W 1
+#define ORX_COMM_INT_REQ_DDC_REQ__M 0x2
+#define ORX_COMM_INT_REQ_DDC_REQ__PRE 0x0
+#define ORX_COMM_INT_REQ_FWP_REQ__B 2
+#define ORX_COMM_INT_REQ_FWP_REQ__W 1
+#define ORX_COMM_INT_REQ_FWP_REQ__M 0x4
+#define ORX_COMM_INT_REQ_FWP_REQ__PRE 0x0
+#define ORX_COMM_INT_REQ_CON_REQ__B 3
+#define ORX_COMM_INT_REQ_CON_REQ__W 1
+#define ORX_COMM_INT_REQ_CON_REQ__M 0x8
+#define ORX_COMM_INT_REQ_CON_REQ__PRE 0x0
+#define ORX_COMM_INT_REQ_NSU_REQ__B 4
+#define ORX_COMM_INT_REQ_NSU_REQ__W 1
+#define ORX_COMM_INT_REQ_NSU_REQ__M 0x10
+#define ORX_COMM_INT_REQ_NSU_REQ__PRE 0x0
+
+#define ORX_COMM_INT_STA__A 0x2000005
+#define ORX_COMM_INT_STA__W 16
+#define ORX_COMM_INT_STA__M 0xFFFF
+#define ORX_COMM_INT_STA__PRE 0x0
+#define ORX_COMM_INT_MSK__A 0x2000006
+#define ORX_COMM_INT_MSK__W 16
+#define ORX_COMM_INT_MSK__M 0xFFFF
+#define ORX_COMM_INT_MSK__PRE 0x0
+#define ORX_COMM_INT_STM__A 0x2000007
+#define ORX_COMM_INT_STM__W 16
+#define ORX_COMM_INT_STM__M 0xFFFF
+#define ORX_COMM_INT_STM__PRE 0x0
+
+#define ORX_TOP_COMM_EXEC__A 0x2010000
+#define ORX_TOP_COMM_EXEC__W 2
+#define ORX_TOP_COMM_EXEC__M 0x3
+#define ORX_TOP_COMM_EXEC__PRE 0x0
+#define ORX_TOP_COMM_EXEC_STOP 0x0
+#define ORX_TOP_COMM_EXEC_ACTIVE 0x1
+#define ORX_TOP_COMM_EXEC_HOLD 0x2
+
+#define ORX_TOP_COMM_KEY__A 0x201000F
+#define ORX_TOP_COMM_KEY__W 16
+#define ORX_TOP_COMM_KEY__M 0xFFFF
+#define ORX_TOP_COMM_KEY__PRE 0x0
+#define ORX_TOP_COMM_KEY_KEY 0xFABA
+
+#define ORX_TOP_MDE_W__A 0x2010010
+#define ORX_TOP_MDE_W__W 2
+#define ORX_TOP_MDE_W__M 0x3
+#define ORX_TOP_MDE_W__PRE 0x2
+#define ORX_TOP_MDE_W_RATE_1544KBPS 0x0
+#define ORX_TOP_MDE_W_RATE_3088KBPS 0x1
+#define ORX_TOP_MDE_W_RATE_2048KBPS_SQRT 0x2
+#define ORX_TOP_MDE_W_RATE_2048KBPS_RO 0x3
+
+#define ORX_TOP_AIF_CTRL_W__A 0x2010011
+#define ORX_TOP_AIF_CTRL_W__W 3
+#define ORX_TOP_AIF_CTRL_W__M 0x7
+#define ORX_TOP_AIF_CTRL_W__PRE 0x0
+#define ORX_TOP_AIF_CTRL_W_NEG_CLK_EDGE__B 0
+#define ORX_TOP_AIF_CTRL_W_NEG_CLK_EDGE__W 1
+#define ORX_TOP_AIF_CTRL_W_NEG_CLK_EDGE__M 0x1
+#define ORX_TOP_AIF_CTRL_W_NEG_CLK_EDGE__PRE 0x0
+#define ORX_TOP_AIF_CTRL_W_NEG_CLK_EDGE_ADC_SAMPL_ON_POS_CLK_EDGE 0x0
+#define ORX_TOP_AIF_CTRL_W_NEG_CLK_EDGE_ADC_SAMPL_ON_NEG_CLK_EDGE 0x1
+#define ORX_TOP_AIF_CTRL_W_BIT_REVERSE__B 1
+#define ORX_TOP_AIF_CTRL_W_BIT_REVERSE__W 1
+#define ORX_TOP_AIF_CTRL_W_BIT_REVERSE__M 0x2
+#define ORX_TOP_AIF_CTRL_W_BIT_REVERSE__PRE 0x0
+#define ORX_TOP_AIF_CTRL_W_BIT_REVERSE_REGULAR_BIT_ORDER_ADC 0x0
+#define ORX_TOP_AIF_CTRL_W_BIT_REVERSE_REVERSAL_BIT_ORDER_ADC 0x2
+#define ORX_TOP_AIF_CTRL_W_INV_MSB__B 2
+#define ORX_TOP_AIF_CTRL_W_INV_MSB__W 1
+#define ORX_TOP_AIF_CTRL_W_INV_MSB__M 0x4
+#define ORX_TOP_AIF_CTRL_W_INV_MSB__PRE 0x0
+#define ORX_TOP_AIF_CTRL_W_INV_MSB_NO_MSB_INVERSION_ADC 0x0
+#define ORX_TOP_AIF_CTRL_W_INV_MSB_MSB_INVERSION_ADC 0x4
+
+#define ORX_FWP_COMM_EXEC__A 0x2020000
+#define ORX_FWP_COMM_EXEC__W 2
+#define ORX_FWP_COMM_EXEC__M 0x3
+#define ORX_FWP_COMM_EXEC__PRE 0x0
+#define ORX_FWP_COMM_EXEC_STOP 0x0
+#define ORX_FWP_COMM_EXEC_ACTIVE 0x1
+#define ORX_FWP_COMM_EXEC_HOLD 0x2
+
+#define ORX_FWP_COMM_MB__A 0x2020002
+#define ORX_FWP_COMM_MB__W 8
+#define ORX_FWP_COMM_MB__M 0xFF
+#define ORX_FWP_COMM_MB__PRE 0x0
+#define ORX_FWP_COMM_MB_CTL__B 0
+#define ORX_FWP_COMM_MB_CTL__W 1
+#define ORX_FWP_COMM_MB_CTL__M 0x1
+#define ORX_FWP_COMM_MB_CTL__PRE 0x0
+#define ORX_FWP_COMM_MB_CTL_OFF 0x0
+#define ORX_FWP_COMM_MB_CTL_ON 0x1
+#define ORX_FWP_COMM_MB_OBS__B 1
+#define ORX_FWP_COMM_MB_OBS__W 1
+#define ORX_FWP_COMM_MB_OBS__M 0x2
+#define ORX_FWP_COMM_MB_OBS__PRE 0x0
+#define ORX_FWP_COMM_MB_OBS_OFF 0x0
+#define ORX_FWP_COMM_MB_OBS_ON 0x2
+
+#define ORX_FWP_COMM_MB_CTL_MUX__B 2
+#define ORX_FWP_COMM_MB_CTL_MUX__W 3
+#define ORX_FWP_COMM_MB_CTL_MUX__M 0x1C
+#define ORX_FWP_COMM_MB_CTL_MUX__PRE 0x0
+
+#define ORX_FWP_COMM_MB_OBS_MUX__B 5
+#define ORX_FWP_COMM_MB_OBS_MUX__W 3
+#define ORX_FWP_COMM_MB_OBS_MUX__M 0xE0
+#define ORX_FWP_COMM_MB_OBS_MUX__PRE 0x0
+
+#define ORX_FWP_AAG_LEN_W__A 0x2020010
+#define ORX_FWP_AAG_LEN_W__W 16
+#define ORX_FWP_AAG_LEN_W__M 0xFFFF
+#define ORX_FWP_AAG_LEN_W__PRE 0x800
+
+#define ORX_FWP_AAG_THR_W__A 0x2020011
+#define ORX_FWP_AAG_THR_W__W 8
+#define ORX_FWP_AAG_THR_W__M 0xFF
+#define ORX_FWP_AAG_THR_W__PRE 0x50
+
+#define ORX_FWP_AAG_THR_CNT_R__A 0x2020012
+#define ORX_FWP_AAG_THR_CNT_R__W 16
+#define ORX_FWP_AAG_THR_CNT_R__M 0xFFFF
+#define ORX_FWP_AAG_THR_CNT_R__PRE 0x0
+
+#define ORX_FWP_AAG_SNS_CNT_R__A 0x2020013
+#define ORX_FWP_AAG_SNS_CNT_R__W 16
+#define ORX_FWP_AAG_SNS_CNT_R__M 0xFFFF
+#define ORX_FWP_AAG_SNS_CNT_R__PRE 0x0
+
+#define ORX_FWP_PFI_A_W__A 0x2020014
+#define ORX_FWP_PFI_A_W__W 8
+#define ORX_FWP_PFI_A_W__M 0xFF
+#define ORX_FWP_PFI_A_W__PRE 0xB0
+#define ORX_FWP_PFI_A_W_RATE_2048KBPS 0xB0
+#define ORX_FWP_PFI_A_W_RATE_1544KBPS 0xA4
+#define ORX_FWP_PFI_A_W_RATE_3088KBPS 0xC0
+
+#define ORX_FWP_PFI_B_W__A 0x2020015
+#define ORX_FWP_PFI_B_W__W 8
+#define ORX_FWP_PFI_B_W__M 0xFF
+#define ORX_FWP_PFI_B_W__PRE 0x9E
+#define ORX_FWP_PFI_B_W_RATE_2048KBPS 0x9E
+#define ORX_FWP_PFI_B_W_RATE_1544KBPS 0x94
+#define ORX_FWP_PFI_B_W_RATE_3088KBPS 0xB0
+
+#define ORX_FWP_PFI_C_W__A 0x2020016
+#define ORX_FWP_PFI_C_W__W 8
+#define ORX_FWP_PFI_C_W__M 0xFF
+#define ORX_FWP_PFI_C_W__PRE 0x5C
+#define ORX_FWP_PFI_C_W_RATE_2048KBPS 0x5C
+#define ORX_FWP_PFI_C_W_RATE_1544KBPS 0x64
+#define ORX_FWP_PFI_C_W_RATE_3088KBPS 0x50
+
+#define ORX_FWP_KR1_AMP_R__A 0x2020017
+#define ORX_FWP_KR1_AMP_R__W 9
+#define ORX_FWP_KR1_AMP_R__M 0x1FF
+#define ORX_FWP_KR1_AMP_R__PRE 0x0
+
+#define ORX_FWP_KR1_LDT_W__A 0x2020018
+#define ORX_FWP_KR1_LDT_W__W 3
+#define ORX_FWP_KR1_LDT_W__M 0x7
+#define ORX_FWP_KR1_LDT_W__PRE 0x2
+#define ORX_FWP_SRC_DGN_W__A 0x2020019
+#define ORX_FWP_SRC_DGN_W__W 16
+#define ORX_FWP_SRC_DGN_W__M 0xFFFF
+#define ORX_FWP_SRC_DGN_W__PRE 0x1FF
+
+#define ORX_FWP_SRC_DGN_W_MANT__B 0
+#define ORX_FWP_SRC_DGN_W_MANT__W 9
+#define ORX_FWP_SRC_DGN_W_MANT__M 0x1FF
+#define ORX_FWP_SRC_DGN_W_MANT__PRE 0x1FF
+
+#define ORX_FWP_SRC_DGN_W_EXP__B 12
+#define ORX_FWP_SRC_DGN_W_EXP__W 4
+#define ORX_FWP_SRC_DGN_W_EXP__M 0xF000
+#define ORX_FWP_SRC_DGN_W_EXP__PRE 0x0
+
+#define ORX_FWP_NYQ_ADR_W__A 0x202001A
+#define ORX_FWP_NYQ_ADR_W__W 5
+#define ORX_FWP_NYQ_ADR_W__M 0x1F
+#define ORX_FWP_NYQ_ADR_W__PRE 0x1F
+
+#define ORX_FWP_NYQ_COF_RW__A 0x202001B
+#define ORX_FWP_NYQ_COF_RW__W 10
+#define ORX_FWP_NYQ_COF_RW__M 0x3FF
+#define ORX_FWP_NYQ_COF_RW__PRE 0x0
+
+#define ORX_FWP_IQM_FRQ_W__A 0x202001C
+#define ORX_FWP_IQM_FRQ_W__W 16
+#define ORX_FWP_IQM_FRQ_W__M 0xFFFF
+#define ORX_FWP_IQM_FRQ_W__PRE 0x4301
+
+#define ORX_EQU_COMM_EXEC__A 0x2030000
+#define ORX_EQU_COMM_EXEC__W 2
+#define ORX_EQU_COMM_EXEC__M 0x3
+#define ORX_EQU_COMM_EXEC__PRE 0x0
+#define ORX_EQU_COMM_EXEC_STOP 0x0
+#define ORX_EQU_COMM_EXEC_ACTIVE 0x1
+#define ORX_EQU_COMM_EXEC_HOLD 0x2
+
+#define ORX_EQU_COMM_MB__A 0x2030002
+#define ORX_EQU_COMM_MB__W 8
+#define ORX_EQU_COMM_MB__M 0xFF
+#define ORX_EQU_COMM_MB__PRE 0x0
+#define ORX_EQU_COMM_MB_CTL__B 0
+#define ORX_EQU_COMM_MB_CTL__W 1
+#define ORX_EQU_COMM_MB_CTL__M 0x1
+#define ORX_EQU_COMM_MB_CTL__PRE 0x0
+#define ORX_EQU_COMM_MB_CTL_OFF 0x0
+#define ORX_EQU_COMM_MB_CTL_ON 0x1
+#define ORX_EQU_COMM_MB_OBS__B 1
+#define ORX_EQU_COMM_MB_OBS__W 1
+#define ORX_EQU_COMM_MB_OBS__M 0x2
+#define ORX_EQU_COMM_MB_OBS__PRE 0x0
+#define ORX_EQU_COMM_MB_OBS_OFF 0x0
+#define ORX_EQU_COMM_MB_OBS_ON 0x2
+
+#define ORX_EQU_COMM_MB_CTL_MUX__B 2
+#define ORX_EQU_COMM_MB_CTL_MUX__W 3
+#define ORX_EQU_COMM_MB_CTL_MUX__M 0x1C
+#define ORX_EQU_COMM_MB_CTL_MUX__PRE 0x0
+
+#define ORX_EQU_COMM_MB_OBS_MUX__B 5
+#define ORX_EQU_COMM_MB_OBS_MUX__W 3
+#define ORX_EQU_COMM_MB_OBS_MUX__M 0xE0
+#define ORX_EQU_COMM_MB_OBS_MUX__PRE 0x0
+
+#define ORX_EQU_COMM_INT_REQ__A 0x2030003
+#define ORX_EQU_COMM_INT_REQ__W 1
+#define ORX_EQU_COMM_INT_REQ__M 0x1
+#define ORX_EQU_COMM_INT_REQ__PRE 0x0
+#define ORX_EQU_COMM_INT_STA__A 0x2030005
+#define ORX_EQU_COMM_INT_STA__W 2
+#define ORX_EQU_COMM_INT_STA__M 0x3
+#define ORX_EQU_COMM_INT_STA__PRE 0x0
+
+#define ORX_EQU_COMM_INT_STA_FFF_READ__B 0
+#define ORX_EQU_COMM_INT_STA_FFF_READ__W 1
+#define ORX_EQU_COMM_INT_STA_FFF_READ__M 0x1
+#define ORX_EQU_COMM_INT_STA_FFF_READ__PRE 0x0
+
+#define ORX_EQU_COMM_INT_STA_FBF_READ__B 1
+#define ORX_EQU_COMM_INT_STA_FBF_READ__W 1
+#define ORX_EQU_COMM_INT_STA_FBF_READ__M 0x2
+#define ORX_EQU_COMM_INT_STA_FBF_READ__PRE 0x0
+
+#define ORX_EQU_COMM_INT_MSK__A 0x2030006
+#define ORX_EQU_COMM_INT_MSK__W 2
+#define ORX_EQU_COMM_INT_MSK__M 0x3
+#define ORX_EQU_COMM_INT_MSK__PRE 0x0
+#define ORX_EQU_COMM_INT_MSK_FFF_READ__B 0
+#define ORX_EQU_COMM_INT_MSK_FFF_READ__W 1
+#define ORX_EQU_COMM_INT_MSK_FFF_READ__M 0x1
+#define ORX_EQU_COMM_INT_MSK_FFF_READ__PRE 0x0
+#define ORX_EQU_COMM_INT_MSK_FBF_READ__B 1
+#define ORX_EQU_COMM_INT_MSK_FBF_READ__W 1
+#define ORX_EQU_COMM_INT_MSK_FBF_READ__M 0x2
+#define ORX_EQU_COMM_INT_MSK_FBF_READ__PRE 0x0
+
+#define ORX_EQU_COMM_INT_STM__A 0x2030007
+#define ORX_EQU_COMM_INT_STM__W 2
+#define ORX_EQU_COMM_INT_STM__M 0x3
+#define ORX_EQU_COMM_INT_STM__PRE 0x0
+#define ORX_EQU_COMM_INT_STM_FFF_READ__B 0
+#define ORX_EQU_COMM_INT_STM_FFF_READ__W 1
+#define ORX_EQU_COMM_INT_STM_FFF_READ__M 0x1
+#define ORX_EQU_COMM_INT_STM_FFF_READ__PRE 0x0
+#define ORX_EQU_COMM_INT_STM_FBF_READ__B 1
+#define ORX_EQU_COMM_INT_STM_FBF_READ__W 1
+#define ORX_EQU_COMM_INT_STM_FBF_READ__M 0x2
+#define ORX_EQU_COMM_INT_STM_FBF_READ__PRE 0x0
+
+#define ORX_EQU_FFF_SCL_W__A 0x2030010
+#define ORX_EQU_FFF_SCL_W__W 1
+#define ORX_EQU_FFF_SCL_W__M 0x1
+#define ORX_EQU_FFF_SCL_W__PRE 0x0
+#define ORX_EQU_FFF_SCL_W_SCALE_GAIN_1 0x0
+#define ORX_EQU_FFF_SCL_W_SCALE_GAIN_2 0x1
+
+#define ORX_EQU_FFF_UPD_W__A 0x2030011
+#define ORX_EQU_FFF_UPD_W__W 1
+#define ORX_EQU_FFF_UPD_W__M 0x1
+#define ORX_EQU_FFF_UPD_W__PRE 0x0
+#define ORX_EQU_FFF_UPD_W_NO_UPDATE 0x0
+#define ORX_EQU_FFF_UPD_W_LMS_UPDATE 0x1
+
+#define ORX_EQU_FFF_STP_W__A 0x2030012
+#define ORX_EQU_FFF_STP_W__W 3
+#define ORX_EQU_FFF_STP_W__M 0x7
+#define ORX_EQU_FFF_STP_W__PRE 0x2
+
+#define ORX_EQU_FFF_LEA_W__A 0x2030013
+#define ORX_EQU_FFF_LEA_W__W 4
+#define ORX_EQU_FFF_LEA_W__M 0xF
+#define ORX_EQU_FFF_LEA_W__PRE 0x4
+
+#define ORX_EQU_FFF_RWT_W__A 0x2030014
+#define ORX_EQU_FFF_RWT_W__W 2
+#define ORX_EQU_FFF_RWT_W__M 0x3
+#define ORX_EQU_FFF_RWT_W__PRE 0x0
+
+#define ORX_EQU_FFF_C0RE_RW__A 0x2030015
+#define ORX_EQU_FFF_C0RE_RW__W 12
+#define ORX_EQU_FFF_C0RE_RW__M 0xFFF
+#define ORX_EQU_FFF_C0RE_RW__PRE 0x0
+
+#define ORX_EQU_FFF_C0IM_RW__A 0x2030016
+#define ORX_EQU_FFF_C0IM_RW__W 12
+#define ORX_EQU_FFF_C0IM_RW__M 0xFFF
+#define ORX_EQU_FFF_C0IM_RW__PRE 0x0
+
+#define ORX_EQU_FFF_C1RE_RW__A 0x2030017
+#define ORX_EQU_FFF_C1RE_RW__W 12
+#define ORX_EQU_FFF_C1RE_RW__M 0xFFF
+#define ORX_EQU_FFF_C1RE_RW__PRE 0x0
+
+#define ORX_EQU_FFF_C1IM_RW__A 0x2030018
+#define ORX_EQU_FFF_C1IM_RW__W 12
+#define ORX_EQU_FFF_C1IM_RW__M 0xFFF
+#define ORX_EQU_FFF_C1IM_RW__PRE 0x0
+
+#define ORX_EQU_FFF_C2RE_RW__A 0x2030019
+#define ORX_EQU_FFF_C2RE_RW__W 12
+#define ORX_EQU_FFF_C2RE_RW__M 0xFFF
+#define ORX_EQU_FFF_C2RE_RW__PRE 0x0
+
+#define ORX_EQU_FFF_C2IM_RW__A 0x203001A
+#define ORX_EQU_FFF_C2IM_RW__W 12
+#define ORX_EQU_FFF_C2IM_RW__M 0xFFF
+#define ORX_EQU_FFF_C2IM_RW__PRE 0x0
+
+#define ORX_EQU_FFF_C3RE_RW__A 0x203001B
+#define ORX_EQU_FFF_C3RE_RW__W 12
+#define ORX_EQU_FFF_C3RE_RW__M 0xFFF
+#define ORX_EQU_FFF_C3RE_RW__PRE 0x0
+
+#define ORX_EQU_FFF_C3IM_RW__A 0x203001C
+#define ORX_EQU_FFF_C3IM_RW__W 12
+#define ORX_EQU_FFF_C3IM_RW__M 0xFFF
+#define ORX_EQU_FFF_C3IM_RW__PRE 0x0
+
+#define ORX_EQU_FFF_C4RE_RW__A 0x203001D
+#define ORX_EQU_FFF_C4RE_RW__W 12
+#define ORX_EQU_FFF_C4RE_RW__M 0xFFF
+#define ORX_EQU_FFF_C4RE_RW__PRE 0x400
+
+#define ORX_EQU_FFF_C4IM_RW__A 0x203001E
+#define ORX_EQU_FFF_C4IM_RW__W 12
+#define ORX_EQU_FFF_C4IM_RW__M 0xFFF
+#define ORX_EQU_FFF_C4IM_RW__PRE 0x0
+
+#define ORX_EQU_FFF_C5RE_RW__A 0x203001F
+#define ORX_EQU_FFF_C5RE_RW__W 12
+#define ORX_EQU_FFF_C5RE_RW__M 0xFFF
+#define ORX_EQU_FFF_C5RE_RW__PRE 0x0
+
+#define ORX_EQU_FFF_C5IM_RW__A 0x2030020
+#define ORX_EQU_FFF_C5IM_RW__W 12
+#define ORX_EQU_FFF_C5IM_RW__M 0xFFF
+#define ORX_EQU_FFF_C5IM_RW__PRE 0x0
+
+#define ORX_EQU_FFF_C6RE_RW__A 0x2030021
+#define ORX_EQU_FFF_C6RE_RW__W 12
+#define ORX_EQU_FFF_C6RE_RW__M 0xFFF
+#define ORX_EQU_FFF_C6RE_RW__PRE 0x0
+
+#define ORX_EQU_FFF_C6IM_RW__A 0x2030022
+#define ORX_EQU_FFF_C6IM_RW__W 12
+#define ORX_EQU_FFF_C6IM_RW__M 0xFFF
+#define ORX_EQU_FFF_C6IM_RW__PRE 0x0
+
+#define ORX_EQU_FFF_C7RE_RW__A 0x2030023
+#define ORX_EQU_FFF_C7RE_RW__W 12
+#define ORX_EQU_FFF_C7RE_RW__M 0xFFF
+#define ORX_EQU_FFF_C7RE_RW__PRE 0x0
+
+#define ORX_EQU_FFF_C7IM_RW__A 0x2030024
+#define ORX_EQU_FFF_C7IM_RW__W 12
+#define ORX_EQU_FFF_C7IM_RW__M 0xFFF
+#define ORX_EQU_FFF_C7IM_RW__PRE 0x0
+
+#define ORX_EQU_FFF_C8RE_RW__A 0x2030025
+#define ORX_EQU_FFF_C8RE_RW__W 12
+#define ORX_EQU_FFF_C8RE_RW__M 0xFFF
+#define ORX_EQU_FFF_C8RE_RW__PRE 0x0
+
+#define ORX_EQU_FFF_C8IM_RW__A 0x2030026
+#define ORX_EQU_FFF_C8IM_RW__W 12
+#define ORX_EQU_FFF_C8IM_RW__M 0xFFF
+#define ORX_EQU_FFF_C8IM_RW__PRE 0x0
+
+#define ORX_EQU_FFF_C9RE_RW__A 0x2030027
+#define ORX_EQU_FFF_C9RE_RW__W 12
+#define ORX_EQU_FFF_C9RE_RW__M 0xFFF
+#define ORX_EQU_FFF_C9RE_RW__PRE 0x0
+
+#define ORX_EQU_FFF_C9IM_RW__A 0x2030028
+#define ORX_EQU_FFF_C9IM_RW__W 12
+#define ORX_EQU_FFF_C9IM_RW__M 0xFFF
+#define ORX_EQU_FFF_C9IM_RW__PRE 0x0
+
+#define ORX_EQU_FFF_C10RE_RW__A 0x2030029
+#define ORX_EQU_FFF_C10RE_RW__W 12
+#define ORX_EQU_FFF_C10RE_RW__M 0xFFF
+#define ORX_EQU_FFF_C10RE_RW__PRE 0x0
+
+#define ORX_EQU_FFF_C10IM_RW__A 0x203002A
+#define ORX_EQU_FFF_C10IM_RW__W 12
+#define ORX_EQU_FFF_C10IM_RW__M 0xFFF
+#define ORX_EQU_FFF_C10IM_RW__PRE 0x0
+
+#define ORX_EQU_MXB_SEL_W__A 0x203002B
+#define ORX_EQU_MXB_SEL_W__W 1
+#define ORX_EQU_MXB_SEL_W__M 0x1
+#define ORX_EQU_MXB_SEL_W__PRE 0x0
+#define ORX_EQU_MXB_SEL_W_UNDECIDED_SYMBOLS 0x0
+#define ORX_EQU_MXB_SEL_W_DECIDED_SYMBOLS 0x1
+
+#define ORX_EQU_FBF_UPD_W__A 0x203002C
+#define ORX_EQU_FBF_UPD_W__W 1
+#define ORX_EQU_FBF_UPD_W__M 0x1
+#define ORX_EQU_FBF_UPD_W__PRE 0x0
+#define ORX_EQU_FBF_UPD_W_NO_UPDATE 0x0
+#define ORX_EQU_FBF_UPD_W_LMS_UPDATE 0x1
+
+#define ORX_EQU_FBF_STP_W__A 0x203002D
+#define ORX_EQU_FBF_STP_W__W 3
+#define ORX_EQU_FBF_STP_W__M 0x7
+#define ORX_EQU_FBF_STP_W__PRE 0x2
+
+#define ORX_EQU_FBF_LEA_W__A 0x203002E
+#define ORX_EQU_FBF_LEA_W__W 4
+#define ORX_EQU_FBF_LEA_W__M 0xF
+#define ORX_EQU_FBF_LEA_W__PRE 0x4
+
+#define ORX_EQU_FBF_RWT_W__A 0x203002F
+#define ORX_EQU_FBF_RWT_W__W 2
+#define ORX_EQU_FBF_RWT_W__M 0x3
+#define ORX_EQU_FBF_RWT_W__PRE 0x0
+
+#define ORX_EQU_FBF_C0RE_RW__A 0x2030030
+#define ORX_EQU_FBF_C0RE_RW__W 12
+#define ORX_EQU_FBF_C0RE_RW__M 0xFFF
+#define ORX_EQU_FBF_C0RE_RW__PRE 0x0
+
+#define ORX_EQU_FBF_C0IM_RW__A 0x2030031
+#define ORX_EQU_FBF_C0IM_RW__W 12
+#define ORX_EQU_FBF_C0IM_RW__M 0xFFF
+#define ORX_EQU_FBF_C0IM_RW__PRE 0x0
+
+#define ORX_EQU_FBF_C1RE_RW__A 0x2030032
+#define ORX_EQU_FBF_C1RE_RW__W 12
+#define ORX_EQU_FBF_C1RE_RW__M 0xFFF
+#define ORX_EQU_FBF_C1RE_RW__PRE 0x0
+
+#define ORX_EQU_FBF_C1IM_RW__A 0x2030033
+#define ORX_EQU_FBF_C1IM_RW__W 12
+#define ORX_EQU_FBF_C1IM_RW__M 0xFFF
+#define ORX_EQU_FBF_C1IM_RW__PRE 0x0
+
+#define ORX_EQU_FBF_C2RE_RW__A 0x2030034
+#define ORX_EQU_FBF_C2RE_RW__W 12
+#define ORX_EQU_FBF_C2RE_RW__M 0xFFF
+#define ORX_EQU_FBF_C2RE_RW__PRE 0x0
+
+#define ORX_EQU_FBF_C2IM_RW__A 0x2030035
+#define ORX_EQU_FBF_C2IM_RW__W 12
+#define ORX_EQU_FBF_C2IM_RW__M 0xFFF
+#define ORX_EQU_FBF_C2IM_RW__PRE 0x0
+
+#define ORX_EQU_FBF_C3RE_RW__A 0x2030036
+#define ORX_EQU_FBF_C3RE_RW__W 12
+#define ORX_EQU_FBF_C3RE_RW__M 0xFFF
+#define ORX_EQU_FBF_C3RE_RW__PRE 0x0
+
+#define ORX_EQU_FBF_C3IM_RW__A 0x2030037
+#define ORX_EQU_FBF_C3IM_RW__W 12
+#define ORX_EQU_FBF_C3IM_RW__M 0xFFF
+#define ORX_EQU_FBF_C3IM_RW__PRE 0x0
+
+#define ORX_EQU_FBF_C4RE_RW__A 0x2030038
+#define ORX_EQU_FBF_C4RE_RW__W 12
+#define ORX_EQU_FBF_C4RE_RW__M 0xFFF
+#define ORX_EQU_FBF_C4RE_RW__PRE 0x0
+
+#define ORX_EQU_FBF_C4IM_RW__A 0x2030039
+#define ORX_EQU_FBF_C4IM_RW__W 12
+#define ORX_EQU_FBF_C4IM_RW__M 0xFFF
+#define ORX_EQU_FBF_C4IM_RW__PRE 0x0
+
+#define ORX_EQU_FBF_C5RE_RW__A 0x203003A
+#define ORX_EQU_FBF_C5RE_RW__W 12
+#define ORX_EQU_FBF_C5RE_RW__M 0xFFF
+#define ORX_EQU_FBF_C5RE_RW__PRE 0x0
+
+#define ORX_EQU_FBF_C5IM_RW__A 0x203003B
+#define ORX_EQU_FBF_C5IM_RW__W 12
+#define ORX_EQU_FBF_C5IM_RW__M 0xFFF
+#define ORX_EQU_FBF_C5IM_RW__PRE 0x0
+
+#define ORX_EQU_ERR_SEL_W__A 0x203003C
+#define ORX_EQU_ERR_SEL_W__W 1
+#define ORX_EQU_ERR_SEL_W__M 0x1
+#define ORX_EQU_ERR_SEL_W__PRE 0x0
+#define ORX_EQU_ERR_SEL_W_CMA_ERROR 0x0
+#define ORX_EQU_ERR_SEL_W_DDA_ERROR 0x1
+
+#define ORX_EQU_ERR_TIS_W__A 0x203003D
+#define ORX_EQU_ERR_TIS_W__W 1
+#define ORX_EQU_ERR_TIS_W__M 0x1
+#define ORX_EQU_ERR_TIS_W__PRE 0x0
+#define ORX_EQU_ERR_TIS_W_CMA_SIGNALS 0x0
+#define ORX_EQU_ERR_TIS_W_DDA_SIGNALS 0x1
+
+#define ORX_EQU_ERR_EDI_R__A 0x203003E
+#define ORX_EQU_ERR_EDI_R__W 5
+#define ORX_EQU_ERR_EDI_R__M 0x1F
+#define ORX_EQU_ERR_EDI_R__PRE 0xF
+
+#define ORX_EQU_ERR_EDQ_R__A 0x203003F
+#define ORX_EQU_ERR_EDQ_R__W 5
+#define ORX_EQU_ERR_EDQ_R__M 0x1F
+#define ORX_EQU_ERR_EDQ_R__PRE 0xF
+
+#define ORX_EQU_ERR_ECI_R__A 0x2030040
+#define ORX_EQU_ERR_ECI_R__W 5
+#define ORX_EQU_ERR_ECI_R__M 0x1F
+#define ORX_EQU_ERR_ECI_R__PRE 0xF
+
+#define ORX_EQU_ERR_ECQ_R__A 0x2030041
+#define ORX_EQU_ERR_ECQ_R__W 5
+#define ORX_EQU_ERR_ECQ_R__M 0x1F
+#define ORX_EQU_ERR_ECQ_R__PRE 0xF
+
+#define ORX_EQU_MER_MER_R__A 0x2030042
+#define ORX_EQU_MER_MER_R__W 6
+#define ORX_EQU_MER_MER_R__M 0x3F
+#define ORX_EQU_MER_MER_R__PRE 0x3F
+
+#define ORX_EQU_MER_LDT_W__A 0x2030043
+#define ORX_EQU_MER_LDT_W__W 3
+#define ORX_EQU_MER_LDT_W__M 0x7
+#define ORX_EQU_MER_LDT_W__PRE 0x4
+
+#define ORX_EQU_SYN_LEN_W__A 0x2030044
+#define ORX_EQU_SYN_LEN_W__W 16
+#define ORX_EQU_SYN_LEN_W__M 0xFFFF
+#define ORX_EQU_SYN_LEN_W__PRE 0x0
+
+#define ORX_DDC_COMM_EXEC__A 0x2040000
+#define ORX_DDC_COMM_EXEC__W 2
+#define ORX_DDC_COMM_EXEC__M 0x3
+#define ORX_DDC_COMM_EXEC__PRE 0x0
+#define ORX_DDC_COMM_EXEC_STOP 0x0
+#define ORX_DDC_COMM_EXEC_ACTIVE 0x1
+#define ORX_DDC_COMM_EXEC_HOLD 0x2
+
+#define ORX_DDC_COMM_MB__A 0x2040002
+#define ORX_DDC_COMM_MB__W 6
+#define ORX_DDC_COMM_MB__M 0x3F
+#define ORX_DDC_COMM_MB__PRE 0x0
+#define ORX_DDC_COMM_MB_CTL__B 0
+#define ORX_DDC_COMM_MB_CTL__W 1
+#define ORX_DDC_COMM_MB_CTL__M 0x1
+#define ORX_DDC_COMM_MB_CTL__PRE 0x0
+#define ORX_DDC_COMM_MB_CTL_OFF 0x0
+#define ORX_DDC_COMM_MB_CTL_ON 0x1
+#define ORX_DDC_COMM_MB_OBS__B 1
+#define ORX_DDC_COMM_MB_OBS__W 1
+#define ORX_DDC_COMM_MB_OBS__M 0x2
+#define ORX_DDC_COMM_MB_OBS__PRE 0x0
+#define ORX_DDC_COMM_MB_OBS_OFF 0x0
+#define ORX_DDC_COMM_MB_OBS_ON 0x2
+
+#define ORX_DDC_COMM_MB_CTL_MUX__B 2
+#define ORX_DDC_COMM_MB_CTL_MUX__W 2
+#define ORX_DDC_COMM_MB_CTL_MUX__M 0xC
+#define ORX_DDC_COMM_MB_CTL_MUX__PRE 0x0
+
+#define ORX_DDC_COMM_MB_OBS_MUX__B 4
+#define ORX_DDC_COMM_MB_OBS_MUX__W 2
+#define ORX_DDC_COMM_MB_OBS_MUX__M 0x30
+#define ORX_DDC_COMM_MB_OBS_MUX__PRE 0x0
+
+#define ORX_DDC_COMM_INT_REQ__A 0x2040003
+#define ORX_DDC_COMM_INT_REQ__W 1
+#define ORX_DDC_COMM_INT_REQ__M 0x1
+#define ORX_DDC_COMM_INT_REQ__PRE 0x0
+#define ORX_DDC_COMM_INT_STA__A 0x2040005
+#define ORX_DDC_COMM_INT_STA__W 1
+#define ORX_DDC_COMM_INT_STA__M 0x1
+#define ORX_DDC_COMM_INT_STA__PRE 0x0
+#define ORX_DDC_COMM_INT_MSK__A 0x2040006
+#define ORX_DDC_COMM_INT_MSK__W 1
+#define ORX_DDC_COMM_INT_MSK__M 0x1
+#define ORX_DDC_COMM_INT_MSK__PRE 0x0
+#define ORX_DDC_COMM_INT_STM__A 0x2040007
+#define ORX_DDC_COMM_INT_STM__W 1
+#define ORX_DDC_COMM_INT_STM__M 0x1
+#define ORX_DDC_COMM_INT_STM__PRE 0x0
+#define ORX_DDC_DEC_MAP_W__A 0x2040010
+#define ORX_DDC_DEC_MAP_W__W 9
+#define ORX_DDC_DEC_MAP_W__M 0x1FF
+#define ORX_DDC_DEC_MAP_W__PRE 0x178
+
+#define ORX_DDC_DEC_MAP_W_QUADR0__B 0
+#define ORX_DDC_DEC_MAP_W_QUADR0__W 2
+#define ORX_DDC_DEC_MAP_W_QUADR0__M 0x3
+#define ORX_DDC_DEC_MAP_W_QUADR0__PRE 0x0
+#define ORX_DDC_DEC_MAP_W_QUADR0_ROTATE_DEFAULT 0x0
+#define ORX_DDC_DEC_MAP_W_QUADR0_ROTATE_ALTERNATE 0x0
+
+#define ORX_DDC_DEC_MAP_W_QUADR1__B 2
+#define ORX_DDC_DEC_MAP_W_QUADR1__W 2
+#define ORX_DDC_DEC_MAP_W_QUADR1__M 0xC
+#define ORX_DDC_DEC_MAP_W_QUADR1__PRE 0x8
+#define ORX_DDC_DEC_MAP_W_QUADR1_ROTATE_DEFAULT 0x8
+#define ORX_DDC_DEC_MAP_W_QUADR1_ROTATE_ALTERNATE 0x4
+
+#define ORX_DDC_DEC_MAP_W_QUADR2__B 4
+#define ORX_DDC_DEC_MAP_W_QUADR2__W 2
+#define ORX_DDC_DEC_MAP_W_QUADR2__M 0x30
+#define ORX_DDC_DEC_MAP_W_QUADR2__PRE 0x30
+#define ORX_DDC_DEC_MAP_W_QUADR2_ROTATE_DEFAULT 0x30
+#define ORX_DDC_DEC_MAP_W_QUADR2_ROTATE_ALTERNATE 0x30
+
+#define ORX_DDC_DEC_MAP_W_QUADR3__B 6
+#define ORX_DDC_DEC_MAP_W_QUADR3__W 2
+#define ORX_DDC_DEC_MAP_W_QUADR3__M 0xC0
+#define ORX_DDC_DEC_MAP_W_QUADR3__PRE 0x40
+#define ORX_DDC_DEC_MAP_W_QUADR3_ROTATE_DEFAULT 0x40
+#define ORX_DDC_DEC_MAP_W_QUADR3_ROTATE_ALTERNATE 0x80
+#define ORX_DDC_DEC_MAP_W_DIFF_DECOD__B 8
+#define ORX_DDC_DEC_MAP_W_DIFF_DECOD__W 1
+#define ORX_DDC_DEC_MAP_W_DIFF_DECOD__M 0x100
+#define ORX_DDC_DEC_MAP_W_DIFF_DECOD__PRE 0x100
+#define ORX_DDC_DEC_MAP_W_DIFF_DECOD_COHERENT_DECODING 0x0
+#define ORX_DDC_DEC_MAP_W_DIFF_DECOD_DIFF_DECODING 0x100
+
+#define ORX_DDC_OFO_SET_W__A 0x2040011
+#define ORX_DDC_OFO_SET_W__W 16
+#define ORX_DDC_OFO_SET_W__M 0xFFFF
+#define ORX_DDC_OFO_SET_W__PRE 0x1402
+
+#define ORX_DDC_OFO_SET_W_PHASE__B 0
+#define ORX_DDC_OFO_SET_W_PHASE__W 7
+#define ORX_DDC_OFO_SET_W_PHASE__M 0x7F
+#define ORX_DDC_OFO_SET_W_PHASE__PRE 0x2
+
+#define ORX_DDC_OFO_SET_W_CRXHITIME__B 7
+#define ORX_DDC_OFO_SET_W_CRXHITIME__W 7
+#define ORX_DDC_OFO_SET_W_CRXHITIME__M 0x3F80
+#define ORX_DDC_OFO_SET_W_CRXHITIME__PRE 0x1400
+
+#define ORX_DDC_OFO_SET_W_CRXINV__B 14
+#define ORX_DDC_OFO_SET_W_CRXINV__W 1
+#define ORX_DDC_OFO_SET_W_CRXINV__M 0x4000
+#define ORX_DDC_OFO_SET_W_CRXINV__PRE 0x0
+
+#define ORX_DDC_OFO_SET_W_DISABLE__B 15
+#define ORX_DDC_OFO_SET_W_DISABLE__W 1
+#define ORX_DDC_OFO_SET_W_DISABLE__M 0x8000
+#define ORX_DDC_OFO_SET_W_DISABLE__PRE 0x0
+
+#define ORX_CON_COMM_EXEC__A 0x2050000
+#define ORX_CON_COMM_EXEC__W 2
+#define ORX_CON_COMM_EXEC__M 0x3
+#define ORX_CON_COMM_EXEC__PRE 0x0
+#define ORX_CON_COMM_EXEC_STOP 0x0
+#define ORX_CON_COMM_EXEC_ACTIVE 0x1
+#define ORX_CON_COMM_EXEC_HOLD 0x2
+
+#define ORX_CON_LDT_W__A 0x2050010
+#define ORX_CON_LDT_W__W 3
+#define ORX_CON_LDT_W__M 0x7
+#define ORX_CON_LDT_W__PRE 0x3
+
+#define ORX_CON_LDT_W_CON_LDT_W__B 0
+#define ORX_CON_LDT_W_CON_LDT_W__W 3
+#define ORX_CON_LDT_W_CON_LDT_W__M 0x7
+#define ORX_CON_LDT_W_CON_LDT_W__PRE 0x3
+
+#define ORX_CON_RST_W__A 0x2050011
+#define ORX_CON_RST_W__W 4
+#define ORX_CON_RST_W__M 0xF
+#define ORX_CON_RST_W__PRE 0x0
+
+#define ORX_CON_RST_W_CPH__B 0
+#define ORX_CON_RST_W_CPH__W 1
+#define ORX_CON_RST_W_CPH__M 0x1
+#define ORX_CON_RST_W_CPH__PRE 0x0
+
+#define ORX_CON_RST_W_CTI__B 1
+#define ORX_CON_RST_W_CTI__W 1
+#define ORX_CON_RST_W_CTI__M 0x2
+#define ORX_CON_RST_W_CTI__PRE 0x0
+
+#define ORX_CON_RST_W_KRN__B 2
+#define ORX_CON_RST_W_KRN__W 1
+#define ORX_CON_RST_W_KRN__M 0x4
+#define ORX_CON_RST_W_KRN__PRE 0x0
+
+#define ORX_CON_RST_W_KRP__B 3
+#define ORX_CON_RST_W_KRP__W 1
+#define ORX_CON_RST_W_KRP__M 0x8
+#define ORX_CON_RST_W_KRP__PRE 0x0
+
+#define ORX_CON_CPH_PHI_R__A 0x2050012
+#define ORX_CON_CPH_PHI_R__W 16
+#define ORX_CON_CPH_PHI_R__M 0xFFFF
+#define ORX_CON_CPH_PHI_R__PRE 0x0
+
+#define ORX_CON_CPH_FRQ_R__A 0x2050013
+#define ORX_CON_CPH_FRQ_R__W 16
+#define ORX_CON_CPH_FRQ_R__M 0xFFFF
+#define ORX_CON_CPH_FRQ_R__PRE 0x0
+
+#define ORX_CON_CPH_AMP_R__A 0x2050014
+#define ORX_CON_CPH_AMP_R__W 16
+#define ORX_CON_CPH_AMP_R__M 0xFFFF
+#define ORX_CON_CPH_AMP_R__PRE 0x0
+
+#define ORX_CON_CPH_KDF_W__A 0x2050015
+#define ORX_CON_CPH_KDF_W__W 4
+#define ORX_CON_CPH_KDF_W__M 0xF
+#define ORX_CON_CPH_KDF_W__PRE 0x0
+
+#define ORX_CON_CPH_KPF_W__A 0x2050016
+#define ORX_CON_CPH_KPF_W__W 4
+#define ORX_CON_CPH_KPF_W__M 0xF
+#define ORX_CON_CPH_KPF_W__PRE 0x0
+
+#define ORX_CON_CPH_KIF_W__A 0x2050017
+#define ORX_CON_CPH_KIF_W__W 4
+#define ORX_CON_CPH_KIF_W__M 0xF
+#define ORX_CON_CPH_KIF_W__PRE 0x0
+#define ORX_CON_CPH_APT_W__A 0x2050018
+#define ORX_CON_CPH_APT_W__W 16
+#define ORX_CON_CPH_APT_W__M 0xFFFF
+#define ORX_CON_CPH_APT_W__PRE 0x804
+
+#define ORX_CON_CPH_APT_W_PTH__B 0
+#define ORX_CON_CPH_APT_W_PTH__W 8
+#define ORX_CON_CPH_APT_W_PTH__M 0xFF
+#define ORX_CON_CPH_APT_W_PTH__PRE 0x4
+
+#define ORX_CON_CPH_APT_W_ATH__B 8
+#define ORX_CON_CPH_APT_W_ATH__W 8
+#define ORX_CON_CPH_APT_W_ATH__M 0xFF00
+#define ORX_CON_CPH_APT_W_ATH__PRE 0x800
+
+#define ORX_CON_CPH_WLC_W__A 0x2050019
+#define ORX_CON_CPH_WLC_W__W 8
+#define ORX_CON_CPH_WLC_W__M 0xFF
+#define ORX_CON_CPH_WLC_W__PRE 0x81
+
+#define ORX_CON_CPH_WLC_W_LATC__B 0
+#define ORX_CON_CPH_WLC_W_LATC__W 4
+#define ORX_CON_CPH_WLC_W_LATC__M 0xF
+#define ORX_CON_CPH_WLC_W_LATC__PRE 0x1
+
+#define ORX_CON_CPH_WLC_W_WLIM__B 4
+#define ORX_CON_CPH_WLC_W_WLIM__W 4
+#define ORX_CON_CPH_WLC_W_WLIM__M 0xF0
+#define ORX_CON_CPH_WLC_W_WLIM__PRE 0x80
+
+#define ORX_CON_CPH_DLY_W__A 0x205001A
+#define ORX_CON_CPH_DLY_W__W 3
+#define ORX_CON_CPH_DLY_W__M 0x7
+#define ORX_CON_CPH_DLY_W__PRE 0x4
+
+#define ORX_CON_CPH_TCL_W__A 0x205001B
+#define ORX_CON_CPH_TCL_W__W 3
+#define ORX_CON_CPH_TCL_W__M 0x7
+#define ORX_CON_CPH_TCL_W__PRE 0x3
+
+#define ORX_CON_KRP_AMP_R__A 0x205001C
+#define ORX_CON_KRP_AMP_R__W 9
+#define ORX_CON_KRP_AMP_R__M 0x1FF
+#define ORX_CON_KRP_AMP_R__PRE 0x0
+
+#define ORX_CON_KRN_AMP_R__A 0x205001D
+#define ORX_CON_KRN_AMP_R__W 9
+#define ORX_CON_KRN_AMP_R__M 0x1FF
+#define ORX_CON_KRN_AMP_R__PRE 0x0
+
+#define ORX_CON_CTI_DTI_R__A 0x205001E
+#define ORX_CON_CTI_DTI_R__W 16
+#define ORX_CON_CTI_DTI_R__M 0xFFFF
+#define ORX_CON_CTI_DTI_R__PRE 0x0
+
+#define ORX_CON_CTI_KDT_W__A 0x205001F
+#define ORX_CON_CTI_KDT_W__W 4
+#define ORX_CON_CTI_KDT_W__M 0xF
+#define ORX_CON_CTI_KDT_W__PRE 0x4
+
+#define ORX_CON_CTI_KPT_W__A 0x2050020
+#define ORX_CON_CTI_KPT_W__W 4
+#define ORX_CON_CTI_KPT_W__M 0xF
+#define ORX_CON_CTI_KPT_W__PRE 0x3
+
+#define ORX_CON_CTI_KIT_W__A 0x2050021
+#define ORX_CON_CTI_KIT_W__W 4
+#define ORX_CON_CTI_KIT_W__M 0xF
+#define ORX_CON_CTI_KIT_W__PRE 0xB
+
+#define ORX_CON_CTI_TAT_W__A 0x2050022
+#define ORX_CON_CTI_TAT_W__W 4
+#define ORX_CON_CTI_TAT_W__M 0xF
+#define ORX_CON_CTI_TAT_W__PRE 0x3
+
+#define ORX_NSU_COMM_EXEC__A 0x2060000
+#define ORX_NSU_COMM_EXEC__W 2
+#define ORX_NSU_COMM_EXEC__M 0x3
+#define ORX_NSU_COMM_EXEC__PRE 0x0
+#define ORX_NSU_COMM_EXEC_STOP 0x0
+#define ORX_NSU_COMM_EXEC_ACTIVE 0x1
+#define ORX_NSU_COMM_EXEC_HOLD 0x2
+
+#define ORX_NSU_AOX_STDBY_W__A 0x2060010
+#define ORX_NSU_AOX_STDBY_W__W 8
+#define ORX_NSU_AOX_STDBY_W__M 0xFF
+#define ORX_NSU_AOX_STDBY_W__PRE 0x0
+
+#define ORX_NSU_AOX_STDBY_W_STDBYADC__B 0
+#define ORX_NSU_AOX_STDBY_W_STDBYADC__W 1
+#define ORX_NSU_AOX_STDBY_W_STDBYADC__M 0x1
+#define ORX_NSU_AOX_STDBY_W_STDBYADC__PRE 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYADC_A1_ON 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYADC_A1_OFF 0x1
+#define ORX_NSU_AOX_STDBY_W_STDBYADC_A2_OFF 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYADC_A2_ON 0x1
+
+#define ORX_NSU_AOX_STDBY_W_STDBYAMP__B 1
+#define ORX_NSU_AOX_STDBY_W_STDBYAMP__W 1
+#define ORX_NSU_AOX_STDBY_W_STDBYAMP__M 0x2
+#define ORX_NSU_AOX_STDBY_W_STDBYAMP__PRE 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYAMP_A1_ON 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYAMP_A1_OFF 0x2
+#define ORX_NSU_AOX_STDBY_W_STDBYAMP_A2_OFF 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYAMP_A2_ON 0x2
+
+#define ORX_NSU_AOX_STDBY_W_STDBYBIAS__B 2
+#define ORX_NSU_AOX_STDBY_W_STDBYBIAS__W 1
+#define ORX_NSU_AOX_STDBY_W_STDBYBIAS__M 0x4
+#define ORX_NSU_AOX_STDBY_W_STDBYBIAS__PRE 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYBIAS_A1_ON 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYBIAS_A1_OFF 0x4
+#define ORX_NSU_AOX_STDBY_W_STDBYBIAS_A2_OFF 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYBIAS_A2_ON 0x4
+
+#define ORX_NSU_AOX_STDBY_W_STDBYPLL__B 3
+#define ORX_NSU_AOX_STDBY_W_STDBYPLL__W 1
+#define ORX_NSU_AOX_STDBY_W_STDBYPLL__M 0x8
+#define ORX_NSU_AOX_STDBY_W_STDBYPLL__PRE 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYPLL_A1_ON 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYPLL_A1_OFF 0x8
+#define ORX_NSU_AOX_STDBY_W_STDBYPLL_A2_OFF 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYPLL_A2_ON 0x8
+
+#define ORX_NSU_AOX_STDBY_W_STDBYPD__B 4
+#define ORX_NSU_AOX_STDBY_W_STDBYPD__W 1
+#define ORX_NSU_AOX_STDBY_W_STDBYPD__M 0x10
+#define ORX_NSU_AOX_STDBY_W_STDBYPD__PRE 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYPD_A1_ON 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYPD_A1_OFF 0x10
+#define ORX_NSU_AOX_STDBY_W_STDBYPD_A2_OFF 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYPD_A2_ON 0x10
+
+#define ORX_NSU_AOX_STDBY_W_STDBYTAGC_IF__B 5
+#define ORX_NSU_AOX_STDBY_W_STDBYTAGC_IF__W 1
+#define ORX_NSU_AOX_STDBY_W_STDBYTAGC_IF__M 0x20
+#define ORX_NSU_AOX_STDBY_W_STDBYTAGC_IF__PRE 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYTAGC_IF_A1_ON 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYTAGC_IF_A1_OFF 0x20
+#define ORX_NSU_AOX_STDBY_W_STDBYTAGC_IF_A2_OFF 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYTAGC_IF_A2_ON 0x20
+
+#define ORX_NSU_AOX_STDBY_W_STDBYTAGC_RF__B 6
+#define ORX_NSU_AOX_STDBY_W_STDBYTAGC_RF__W 1
+#define ORX_NSU_AOX_STDBY_W_STDBYTAGC_RF__M 0x40
+#define ORX_NSU_AOX_STDBY_W_STDBYTAGC_RF__PRE 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYTAGC_RF_A1_ON 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYTAGC_RF_A1_OFF 0x40
+#define ORX_NSU_AOX_STDBY_W_STDBYTAGC_RF_A2_OFF 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYTAGC_RF_A2_ON 0x40
+
+#define ORX_NSU_AOX_STDBY_W_STDBYFLT__B 7
+#define ORX_NSU_AOX_STDBY_W_STDBYFLT__W 1
+#define ORX_NSU_AOX_STDBY_W_STDBYFLT__M 0x80
+#define ORX_NSU_AOX_STDBY_W_STDBYFLT__PRE 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYFLT_A1_ON 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYFLT_A1_OFF 0x80
+#define ORX_NSU_AOX_STDBY_W_STDBYFLT_A2_OFF 0x0
+#define ORX_NSU_AOX_STDBY_W_STDBYFLT_A2_ON 0x80
+
+#define ORX_NSU_AOX_LOFRQ_W__A 0x2060011
+#define ORX_NSU_AOX_LOFRQ_W__W 16
+#define ORX_NSU_AOX_LOFRQ_W__M 0xFFFF
+#define ORX_NSU_AOX_LOFRQ_W__PRE 0x0
+#define ORX_NSU_AOX_LOMDE_W__A 0x2060012
+#define ORX_NSU_AOX_LOMDE_W__W 16
+#define ORX_NSU_AOX_LOMDE_W__M 0xFFFF
+#define ORX_NSU_AOX_LOMDE_W__PRE 0x0
+
+#define ORX_NSU_AOX_LOMDE_W_AOX_LOFRQ_EXT__B 0
+#define ORX_NSU_AOX_LOMDE_W_AOX_LOFRQ_EXT__W 8
+#define ORX_NSU_AOX_LOMDE_W_AOX_LOFRQ_EXT__M 0xFF
+#define ORX_NSU_AOX_LOMDE_W_AOX_LOFRQ_EXT__PRE 0x0
+
+#define ORX_NSU_AOX_LOMDE_W_RESET_VCO__B 13
+#define ORX_NSU_AOX_LOMDE_W_RESET_VCO__W 1
+#define ORX_NSU_AOX_LOMDE_W_RESET_VCO__M 0x2000
+#define ORX_NSU_AOX_LOMDE_W_RESET_VCO__PRE 0x0
+
+#define ORX_NSU_AOX_LOMDE_W_PLL_DIV__B 14
+#define ORX_NSU_AOX_LOMDE_W_PLL_DIV__W 2
+#define ORX_NSU_AOX_LOMDE_W_PLL_DIV__M 0xC000
+#define ORX_NSU_AOX_LOMDE_W_PLL_DIV__PRE 0x0
+
+#define ORX_NSU_AOX_LOPOW_W__A 0x2060013
+#define ORX_NSU_AOX_LOPOW_W__W 2
+#define ORX_NSU_AOX_LOPOW_W__M 0x3
+#define ORX_NSU_AOX_LOPOW_W__PRE 0x0
+#define ORX_NSU_AOX_LOPOW_W_POWER_MINUS0DB 0x0
+#define ORX_NSU_AOX_LOPOW_W_POWER_MINUS5DB 0x1
+#define ORX_NSU_AOX_LOPOW_W_POWER_MINUS10DB 0x2
+#define ORX_NSU_AOX_LOPOW_W_POWER_MINUS15DB 0x3
+
+#define ORX_NSU_AOX_STHR_W__A 0x2060014
+#define ORX_NSU_AOX_STHR_W__W 5
+#define ORX_NSU_AOX_STHR_W__M 0x1F
+#define ORX_NSU_AOX_STHR_W__PRE 0x0
+
+#define ORX_NSU_TUN_RFGAIN_W__A 0x2060015
+#define ORX_NSU_TUN_RFGAIN_W__W 15
+#define ORX_NSU_TUN_RFGAIN_W__M 0x7FFF
+#define ORX_NSU_TUN_RFGAIN_W__PRE 0x0
+
+#define ORX_NSU_TUN_IFGAIN_W__A 0x2060016
+#define ORX_NSU_TUN_IFGAIN_W__W 15
+#define ORX_NSU_TUN_IFGAIN_W__M 0x7FFF
+#define ORX_NSU_TUN_IFGAIN_W__PRE 0x0
+
+#define ORX_NSU_TUN_BPF_W__A 0x2060017
+#define ORX_NSU_TUN_BPF_W__W 15
+#define ORX_NSU_TUN_BPF_W__M 0x7FFF
+#define ORX_NSU_TUN_BPF_W__PRE 0x1F9
+#define ORX_NSU_NSS_BITSWAP_W__A 0x2060018
+#define ORX_NSU_NSS_BITSWAP_W__W 3
+#define ORX_NSU_NSS_BITSWAP_W__M 0x7
+#define ORX_NSU_NSS_BITSWAP_W__PRE 0x0
+
+#define ORX_NSU_NSS_BITSWAP_W_BITSWAP_NS0_RF__B 0
+#define ORX_NSU_NSS_BITSWAP_W_BITSWAP_NS0_RF__W 1
+#define ORX_NSU_NSS_BITSWAP_W_BITSWAP_NS0_RF__M 0x1
+#define ORX_NSU_NSS_BITSWAP_W_BITSWAP_NS0_RF__PRE 0x0
+
+#define ORX_NSU_NSS_BITSWAP_W_BITSWAP_NS1_IF__B 1
+#define ORX_NSU_NSS_BITSWAP_W_BITSWAP_NS1_IF__W 1
+#define ORX_NSU_NSS_BITSWAP_W_BITSWAP_NS1_IF__M 0x2
+#define ORX_NSU_NSS_BITSWAP_W_BITSWAP_NS1_IF__PRE 0x0
+
+#define ORX_NSU_NSS_BITSWAP_W_BITSWAP_NS2_BP__B 2
+#define ORX_NSU_NSS_BITSWAP_W_BITSWAP_NS2_BP__W 1
+#define ORX_NSU_NSS_BITSWAP_W_BITSWAP_NS2_BP__M 0x4
+#define ORX_NSU_NSS_BITSWAP_W_BITSWAP_NS2_BP__PRE 0x0
+
+#define ORX_TST_COMM_EXEC__A 0x23F0000
+#define ORX_TST_COMM_EXEC__W 2
+#define ORX_TST_COMM_EXEC__M 0x3
+#define ORX_TST_COMM_EXEC__PRE 0x0
+#define ORX_TST_COMM_EXEC_STOP 0x0
+#define ORX_TST_COMM_EXEC_ACTIVE 0x1
+#define ORX_TST_COMM_EXEC_HOLD 0x2
+
+#define ORX_TST_AOX_TST_W__A 0x23F0010
+#define ORX_TST_AOX_TST_W__W 8
+#define ORX_TST_AOX_TST_W__M 0xFF
+#define ORX_TST_AOX_TST_W__PRE 0x0
+
+#define QAM_COMM_EXEC__A 0x1400000
+#define QAM_COMM_EXEC__W 2
+#define QAM_COMM_EXEC__M 0x3
+#define QAM_COMM_EXEC__PRE 0x0
+#define QAM_COMM_EXEC_STOP 0x0
+#define QAM_COMM_EXEC_ACTIVE 0x1
+#define QAM_COMM_EXEC_HOLD 0x2
+
+#define QAM_COMM_MB__A 0x1400002
+#define QAM_COMM_MB__W 16
+#define QAM_COMM_MB__M 0xFFFF
+#define QAM_COMM_MB__PRE 0x0
+#define QAM_COMM_INT_REQ__A 0x1400003
+#define QAM_COMM_INT_REQ__W 16
+#define QAM_COMM_INT_REQ__M 0xFFFF
+#define QAM_COMM_INT_REQ__PRE 0x0
+
+#define QAM_COMM_INT_REQ_SL_REQ__B 0
+#define QAM_COMM_INT_REQ_SL_REQ__W 1
+#define QAM_COMM_INT_REQ_SL_REQ__M 0x1
+#define QAM_COMM_INT_REQ_SL_REQ__PRE 0x0
+
+#define QAM_COMM_INT_REQ_LC_REQ__B 1
+#define QAM_COMM_INT_REQ_LC_REQ__W 1
+#define QAM_COMM_INT_REQ_LC_REQ__M 0x2
+#define QAM_COMM_INT_REQ_LC_REQ__PRE 0x0
+
+#define QAM_COMM_INT_REQ_VD_REQ__B 2
+#define QAM_COMM_INT_REQ_VD_REQ__W 1
+#define QAM_COMM_INT_REQ_VD_REQ__M 0x4
+#define QAM_COMM_INT_REQ_VD_REQ__PRE 0x0
+
+#define QAM_COMM_INT_REQ_SY_REQ__B 3
+#define QAM_COMM_INT_REQ_SY_REQ__W 1
+#define QAM_COMM_INT_REQ_SY_REQ__M 0x8
+#define QAM_COMM_INT_REQ_SY_REQ__PRE 0x0
+
+#define QAM_COMM_INT_STA__A 0x1400005
+#define QAM_COMM_INT_STA__W 16
+#define QAM_COMM_INT_STA__M 0xFFFF
+#define QAM_COMM_INT_STA__PRE 0x0
+#define QAM_COMM_INT_MSK__A 0x1400006
+#define QAM_COMM_INT_MSK__W 16
+#define QAM_COMM_INT_MSK__M 0xFFFF
+#define QAM_COMM_INT_MSK__PRE 0x0
+#define QAM_COMM_INT_STM__A 0x1400007
+#define QAM_COMM_INT_STM__W 16
+#define QAM_COMM_INT_STM__M 0xFFFF
+#define QAM_COMM_INT_STM__PRE 0x0
+
+#define QAM_TOP_COMM_EXEC__A 0x1410000
+#define QAM_TOP_COMM_EXEC__W 2
+#define QAM_TOP_COMM_EXEC__M 0x3
+#define QAM_TOP_COMM_EXEC__PRE 0x0
+#define QAM_TOP_COMM_EXEC_STOP 0x0
+#define QAM_TOP_COMM_EXEC_ACTIVE 0x1
+#define QAM_TOP_COMM_EXEC_HOLD 0x2
+
+#define QAM_TOP_ANNEX__A 0x1410010
+#define QAM_TOP_ANNEX__W 2
+#define QAM_TOP_ANNEX__M 0x3
+#define QAM_TOP_ANNEX__PRE 0x1
+#define QAM_TOP_ANNEX_A 0x0
+#define QAM_TOP_ANNEX_B 0x1
+#define QAM_TOP_ANNEX_C 0x2
+#define QAM_TOP_ANNEX_D 0x3
+
+#define QAM_TOP_CONSTELLATION__A 0x1410011
+#define QAM_TOP_CONSTELLATION__W 3
+#define QAM_TOP_CONSTELLATION__M 0x7
+#define QAM_TOP_CONSTELLATION__PRE 0x5
+#define QAM_TOP_CONSTELLATION_NONE 0x0
+#define QAM_TOP_CONSTELLATION_QPSK 0x1
+#define QAM_TOP_CONSTELLATION_QAM8 0x2
+#define QAM_TOP_CONSTELLATION_QAM16 0x3
+#define QAM_TOP_CONSTELLATION_QAM32 0x4
+#define QAM_TOP_CONSTELLATION_QAM64 0x5
+#define QAM_TOP_CONSTELLATION_QAM128 0x6
+#define QAM_TOP_CONSTELLATION_QAM256 0x7
+
+#define QAM_FQ_COMM_EXEC__A 0x1420000
+#define QAM_FQ_COMM_EXEC__W 2
+#define QAM_FQ_COMM_EXEC__M 0x3
+#define QAM_FQ_COMM_EXEC__PRE 0x0
+#define QAM_FQ_COMM_EXEC_STOP 0x0
+#define QAM_FQ_COMM_EXEC_ACTIVE 0x1
+#define QAM_FQ_COMM_EXEC_HOLD 0x2
+
+#define QAM_FQ_MODE__A 0x1420010
+#define QAM_FQ_MODE__W 3
+#define QAM_FQ_MODE__M 0x7
+#define QAM_FQ_MODE__PRE 0x0
+
+#define QAM_FQ_MODE_TAPRESET__B 0
+#define QAM_FQ_MODE_TAPRESET__W 1
+#define QAM_FQ_MODE_TAPRESET__M 0x1
+#define QAM_FQ_MODE_TAPRESET__PRE 0x0
+#define QAM_FQ_MODE_TAPRESET_RST 0x1
+
+#define QAM_FQ_MODE_TAPLMS__B 1
+#define QAM_FQ_MODE_TAPLMS__W 1
+#define QAM_FQ_MODE_TAPLMS__M 0x2
+#define QAM_FQ_MODE_TAPLMS__PRE 0x0
+#define QAM_FQ_MODE_TAPLMS_UPD 0x2
+
+#define QAM_FQ_MODE_TAPDRAIN__B 2
+#define QAM_FQ_MODE_TAPDRAIN__W 1
+#define QAM_FQ_MODE_TAPDRAIN__M 0x4
+#define QAM_FQ_MODE_TAPDRAIN__PRE 0x0
+#define QAM_FQ_MODE_TAPDRAIN_DRAIN 0x4
+
+#define QAM_FQ_MU_FACTOR__A 0x1420011
+#define QAM_FQ_MU_FACTOR__W 3
+#define QAM_FQ_MU_FACTOR__M 0x7
+#define QAM_FQ_MU_FACTOR__PRE 0x0
+
+#define QAM_FQ_LA_FACTOR__A 0x1420012
+#define QAM_FQ_LA_FACTOR__W 4
+#define QAM_FQ_LA_FACTOR__M 0xF
+#define QAM_FQ_LA_FACTOR__PRE 0xC
+#define QAM_FQ_CENTTAP_IDX__A 0x1420016
+#define QAM_FQ_CENTTAP_IDX__W 5
+#define QAM_FQ_CENTTAP_IDX__M 0x1F
+#define QAM_FQ_CENTTAP_IDX__PRE 0x13
+
+#define QAM_FQ_CENTTAP_IDX_IDX__B 0
+#define QAM_FQ_CENTTAP_IDX_IDX__W 5
+#define QAM_FQ_CENTTAP_IDX_IDX__M 0x1F
+#define QAM_FQ_CENTTAP_IDX_IDX__PRE 0x13
+
+#define QAM_FQ_CENTTAP_VALUE__A 0x1420017
+#define QAM_FQ_CENTTAP_VALUE__W 12
+#define QAM_FQ_CENTTAP_VALUE__M 0xFFF
+#define QAM_FQ_CENTTAP_VALUE__PRE 0x600
+
+#define QAM_FQ_CENTTAP_VALUE_TAP__B 0
+#define QAM_FQ_CENTTAP_VALUE_TAP__W 12
+#define QAM_FQ_CENTTAP_VALUE_TAP__M 0xFFF
+#define QAM_FQ_CENTTAP_VALUE_TAP__PRE 0x600
+
+#define QAM_FQ_TAP_RE_EL0__A 0x1420020
+#define QAM_FQ_TAP_RE_EL0__W 12
+#define QAM_FQ_TAP_RE_EL0__M 0xFFF
+#define QAM_FQ_TAP_RE_EL0__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL0_TAP__B 0
+#define QAM_FQ_TAP_RE_EL0_TAP__W 12
+#define QAM_FQ_TAP_RE_EL0_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL0_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL0__A 0x1420021
+#define QAM_FQ_TAP_IM_EL0__W 12
+#define QAM_FQ_TAP_IM_EL0__M 0xFFF
+#define QAM_FQ_TAP_IM_EL0__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL0_TAP__B 0
+#define QAM_FQ_TAP_IM_EL0_TAP__W 12
+#define QAM_FQ_TAP_IM_EL0_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL0_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL1__A 0x1420022
+#define QAM_FQ_TAP_RE_EL1__W 12
+#define QAM_FQ_TAP_RE_EL1__M 0xFFF
+#define QAM_FQ_TAP_RE_EL1__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL1_TAP__B 0
+#define QAM_FQ_TAP_RE_EL1_TAP__W 12
+#define QAM_FQ_TAP_RE_EL1_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL1_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL1__A 0x1420023
+#define QAM_FQ_TAP_IM_EL1__W 12
+#define QAM_FQ_TAP_IM_EL1__M 0xFFF
+#define QAM_FQ_TAP_IM_EL1__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL1_TAP__B 0
+#define QAM_FQ_TAP_IM_EL1_TAP__W 12
+#define QAM_FQ_TAP_IM_EL1_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL1_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL2__A 0x1420024
+#define QAM_FQ_TAP_RE_EL2__W 12
+#define QAM_FQ_TAP_RE_EL2__M 0xFFF
+#define QAM_FQ_TAP_RE_EL2__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL2_TAP__B 0
+#define QAM_FQ_TAP_RE_EL2_TAP__W 12
+#define QAM_FQ_TAP_RE_EL2_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL2_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL2__A 0x1420025
+#define QAM_FQ_TAP_IM_EL2__W 12
+#define QAM_FQ_TAP_IM_EL2__M 0xFFF
+#define QAM_FQ_TAP_IM_EL2__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL2_TAP__B 0
+#define QAM_FQ_TAP_IM_EL2_TAP__W 12
+#define QAM_FQ_TAP_IM_EL2_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL2_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL3__A 0x1420026
+#define QAM_FQ_TAP_RE_EL3__W 12
+#define QAM_FQ_TAP_RE_EL3__M 0xFFF
+#define QAM_FQ_TAP_RE_EL3__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL3_TAP__B 0
+#define QAM_FQ_TAP_RE_EL3_TAP__W 12
+#define QAM_FQ_TAP_RE_EL3_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL3_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL3__A 0x1420027
+#define QAM_FQ_TAP_IM_EL3__W 12
+#define QAM_FQ_TAP_IM_EL3__M 0xFFF
+#define QAM_FQ_TAP_IM_EL3__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL3_TAP__B 0
+#define QAM_FQ_TAP_IM_EL3_TAP__W 12
+#define QAM_FQ_TAP_IM_EL3_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL3_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL4__A 0x1420028
+#define QAM_FQ_TAP_RE_EL4__W 12
+#define QAM_FQ_TAP_RE_EL4__M 0xFFF
+#define QAM_FQ_TAP_RE_EL4__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL4_TAP__B 0
+#define QAM_FQ_TAP_RE_EL4_TAP__W 12
+#define QAM_FQ_TAP_RE_EL4_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL4_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL4__A 0x1420029
+#define QAM_FQ_TAP_IM_EL4__W 12
+#define QAM_FQ_TAP_IM_EL4__M 0xFFF
+#define QAM_FQ_TAP_IM_EL4__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL4_TAP__B 0
+#define QAM_FQ_TAP_IM_EL4_TAP__W 12
+#define QAM_FQ_TAP_IM_EL4_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL4_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL5__A 0x142002A
+#define QAM_FQ_TAP_RE_EL5__W 12
+#define QAM_FQ_TAP_RE_EL5__M 0xFFF
+#define QAM_FQ_TAP_RE_EL5__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL5_TAP__B 0
+#define QAM_FQ_TAP_RE_EL5_TAP__W 12
+#define QAM_FQ_TAP_RE_EL5_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL5_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL5__A 0x142002B
+#define QAM_FQ_TAP_IM_EL5__W 12
+#define QAM_FQ_TAP_IM_EL5__M 0xFFF
+#define QAM_FQ_TAP_IM_EL5__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL5_TAP__B 0
+#define QAM_FQ_TAP_IM_EL5_TAP__W 12
+#define QAM_FQ_TAP_IM_EL5_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL5_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL6__A 0x142002C
+#define QAM_FQ_TAP_RE_EL6__W 12
+#define QAM_FQ_TAP_RE_EL6__M 0xFFF
+#define QAM_FQ_TAP_RE_EL6__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL6_TAP__B 0
+#define QAM_FQ_TAP_RE_EL6_TAP__W 12
+#define QAM_FQ_TAP_RE_EL6_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL6_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL6__A 0x142002D
+#define QAM_FQ_TAP_IM_EL6__W 12
+#define QAM_FQ_TAP_IM_EL6__M 0xFFF
+#define QAM_FQ_TAP_IM_EL6__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL6_TAP__B 0
+#define QAM_FQ_TAP_IM_EL6_TAP__W 12
+#define QAM_FQ_TAP_IM_EL6_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL6_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL7__A 0x142002E
+#define QAM_FQ_TAP_RE_EL7__W 12
+#define QAM_FQ_TAP_RE_EL7__M 0xFFF
+#define QAM_FQ_TAP_RE_EL7__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL7_TAP__B 0
+#define QAM_FQ_TAP_RE_EL7_TAP__W 12
+#define QAM_FQ_TAP_RE_EL7_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL7_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL7__A 0x142002F
+#define QAM_FQ_TAP_IM_EL7__W 12
+#define QAM_FQ_TAP_IM_EL7__M 0xFFF
+#define QAM_FQ_TAP_IM_EL7__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL7_TAP__B 0
+#define QAM_FQ_TAP_IM_EL7_TAP__W 12
+#define QAM_FQ_TAP_IM_EL7_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL7_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL8__A 0x1420030
+#define QAM_FQ_TAP_RE_EL8__W 12
+#define QAM_FQ_TAP_RE_EL8__M 0xFFF
+#define QAM_FQ_TAP_RE_EL8__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL8_TAP__B 0
+#define QAM_FQ_TAP_RE_EL8_TAP__W 12
+#define QAM_FQ_TAP_RE_EL8_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL8_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL8__A 0x1420031
+#define QAM_FQ_TAP_IM_EL8__W 12
+#define QAM_FQ_TAP_IM_EL8__M 0xFFF
+#define QAM_FQ_TAP_IM_EL8__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL8_TAP__B 0
+#define QAM_FQ_TAP_IM_EL8_TAP__W 12
+#define QAM_FQ_TAP_IM_EL8_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL8_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL9__A 0x1420032
+#define QAM_FQ_TAP_RE_EL9__W 12
+#define QAM_FQ_TAP_RE_EL9__M 0xFFF
+#define QAM_FQ_TAP_RE_EL9__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL9_TAP__B 0
+#define QAM_FQ_TAP_RE_EL9_TAP__W 12
+#define QAM_FQ_TAP_RE_EL9_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL9_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL9__A 0x1420033
+#define QAM_FQ_TAP_IM_EL9__W 12
+#define QAM_FQ_TAP_IM_EL9__M 0xFFF
+#define QAM_FQ_TAP_IM_EL9__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL9_TAP__B 0
+#define QAM_FQ_TAP_IM_EL9_TAP__W 12
+#define QAM_FQ_TAP_IM_EL9_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL9_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL10__A 0x1420034
+#define QAM_FQ_TAP_RE_EL10__W 12
+#define QAM_FQ_TAP_RE_EL10__M 0xFFF
+#define QAM_FQ_TAP_RE_EL10__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL10_TAP__B 0
+#define QAM_FQ_TAP_RE_EL10_TAP__W 12
+#define QAM_FQ_TAP_RE_EL10_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL10_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL10__A 0x1420035
+#define QAM_FQ_TAP_IM_EL10__W 12
+#define QAM_FQ_TAP_IM_EL10__M 0xFFF
+#define QAM_FQ_TAP_IM_EL10__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL10_TAP__B 0
+#define QAM_FQ_TAP_IM_EL10_TAP__W 12
+#define QAM_FQ_TAP_IM_EL10_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL10_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL11__A 0x1420036
+#define QAM_FQ_TAP_RE_EL11__W 12
+#define QAM_FQ_TAP_RE_EL11__M 0xFFF
+#define QAM_FQ_TAP_RE_EL11__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL11_TAP__B 0
+#define QAM_FQ_TAP_RE_EL11_TAP__W 12
+#define QAM_FQ_TAP_RE_EL11_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL11_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL11__A 0x1420037
+#define QAM_FQ_TAP_IM_EL11__W 12
+#define QAM_FQ_TAP_IM_EL11__M 0xFFF
+#define QAM_FQ_TAP_IM_EL11__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL11_TAP__B 0
+#define QAM_FQ_TAP_IM_EL11_TAP__W 12
+#define QAM_FQ_TAP_IM_EL11_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL11_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL12__A 0x1420038
+#define QAM_FQ_TAP_RE_EL12__W 12
+#define QAM_FQ_TAP_RE_EL12__M 0xFFF
+#define QAM_FQ_TAP_RE_EL12__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL12_TAP__B 0
+#define QAM_FQ_TAP_RE_EL12_TAP__W 12
+#define QAM_FQ_TAP_RE_EL12_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL12_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL12__A 0x1420039
+#define QAM_FQ_TAP_IM_EL12__W 12
+#define QAM_FQ_TAP_IM_EL12__M 0xFFF
+#define QAM_FQ_TAP_IM_EL12__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL12_TAP__B 0
+#define QAM_FQ_TAP_IM_EL12_TAP__W 12
+#define QAM_FQ_TAP_IM_EL12_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL12_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL13__A 0x142003A
+#define QAM_FQ_TAP_RE_EL13__W 12
+#define QAM_FQ_TAP_RE_EL13__M 0xFFF
+#define QAM_FQ_TAP_RE_EL13__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL13_TAP__B 0
+#define QAM_FQ_TAP_RE_EL13_TAP__W 12
+#define QAM_FQ_TAP_RE_EL13_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL13_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL13__A 0x142003B
+#define QAM_FQ_TAP_IM_EL13__W 12
+#define QAM_FQ_TAP_IM_EL13__M 0xFFF
+#define QAM_FQ_TAP_IM_EL13__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL13_TAP__B 0
+#define QAM_FQ_TAP_IM_EL13_TAP__W 12
+#define QAM_FQ_TAP_IM_EL13_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL13_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL14__A 0x142003C
+#define QAM_FQ_TAP_RE_EL14__W 12
+#define QAM_FQ_TAP_RE_EL14__M 0xFFF
+#define QAM_FQ_TAP_RE_EL14__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL14_TAP__B 0
+#define QAM_FQ_TAP_RE_EL14_TAP__W 12
+#define QAM_FQ_TAP_RE_EL14_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL14_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL14__A 0x142003D
+#define QAM_FQ_TAP_IM_EL14__W 12
+#define QAM_FQ_TAP_IM_EL14__M 0xFFF
+#define QAM_FQ_TAP_IM_EL14__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL14_TAP__B 0
+#define QAM_FQ_TAP_IM_EL14_TAP__W 12
+#define QAM_FQ_TAP_IM_EL14_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL14_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL15__A 0x142003E
+#define QAM_FQ_TAP_RE_EL15__W 12
+#define QAM_FQ_TAP_RE_EL15__M 0xFFF
+#define QAM_FQ_TAP_RE_EL15__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL15_TAP__B 0
+#define QAM_FQ_TAP_RE_EL15_TAP__W 12
+#define QAM_FQ_TAP_RE_EL15_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL15_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL15__A 0x142003F
+#define QAM_FQ_TAP_IM_EL15__W 12
+#define QAM_FQ_TAP_IM_EL15__M 0xFFF
+#define QAM_FQ_TAP_IM_EL15__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL15_TAP__B 0
+#define QAM_FQ_TAP_IM_EL15_TAP__W 12
+#define QAM_FQ_TAP_IM_EL15_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL15_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL16__A 0x1420040
+#define QAM_FQ_TAP_RE_EL16__W 12
+#define QAM_FQ_TAP_RE_EL16__M 0xFFF
+#define QAM_FQ_TAP_RE_EL16__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL16_TAP__B 0
+#define QAM_FQ_TAP_RE_EL16_TAP__W 12
+#define QAM_FQ_TAP_RE_EL16_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL16_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL16__A 0x1420041
+#define QAM_FQ_TAP_IM_EL16__W 12
+#define QAM_FQ_TAP_IM_EL16__M 0xFFF
+#define QAM_FQ_TAP_IM_EL16__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL16_TAP__B 0
+#define QAM_FQ_TAP_IM_EL16_TAP__W 12
+#define QAM_FQ_TAP_IM_EL16_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL16_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL17__A 0x1420042
+#define QAM_FQ_TAP_RE_EL17__W 12
+#define QAM_FQ_TAP_RE_EL17__M 0xFFF
+#define QAM_FQ_TAP_RE_EL17__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL17_TAP__B 0
+#define QAM_FQ_TAP_RE_EL17_TAP__W 12
+#define QAM_FQ_TAP_RE_EL17_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL17_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL17__A 0x1420043
+#define QAM_FQ_TAP_IM_EL17__W 12
+#define QAM_FQ_TAP_IM_EL17__M 0xFFF
+#define QAM_FQ_TAP_IM_EL17__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL17_TAP__B 0
+#define QAM_FQ_TAP_IM_EL17_TAP__W 12
+#define QAM_FQ_TAP_IM_EL17_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL17_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL18__A 0x1420044
+#define QAM_FQ_TAP_RE_EL18__W 12
+#define QAM_FQ_TAP_RE_EL18__M 0xFFF
+#define QAM_FQ_TAP_RE_EL18__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL18_TAP__B 0
+#define QAM_FQ_TAP_RE_EL18_TAP__W 12
+#define QAM_FQ_TAP_RE_EL18_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL18_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL18__A 0x1420045
+#define QAM_FQ_TAP_IM_EL18__W 12
+#define QAM_FQ_TAP_IM_EL18__M 0xFFF
+#define QAM_FQ_TAP_IM_EL18__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL18_TAP__B 0
+#define QAM_FQ_TAP_IM_EL18_TAP__W 12
+#define QAM_FQ_TAP_IM_EL18_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL18_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL19__A 0x1420046
+#define QAM_FQ_TAP_RE_EL19__W 12
+#define QAM_FQ_TAP_RE_EL19__M 0xFFF
+#define QAM_FQ_TAP_RE_EL19__PRE 0x600
+
+#define QAM_FQ_TAP_RE_EL19_TAP__B 0
+#define QAM_FQ_TAP_RE_EL19_TAP__W 12
+#define QAM_FQ_TAP_RE_EL19_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL19_TAP__PRE 0x600
+
+#define QAM_FQ_TAP_IM_EL19__A 0x1420047
+#define QAM_FQ_TAP_IM_EL19__W 12
+#define QAM_FQ_TAP_IM_EL19__M 0xFFF
+#define QAM_FQ_TAP_IM_EL19__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL19_TAP__B 0
+#define QAM_FQ_TAP_IM_EL19_TAP__W 12
+#define QAM_FQ_TAP_IM_EL19_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL19_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL20__A 0x1420048
+#define QAM_FQ_TAP_RE_EL20__W 12
+#define QAM_FQ_TAP_RE_EL20__M 0xFFF
+#define QAM_FQ_TAP_RE_EL20__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL20_TAP__B 0
+#define QAM_FQ_TAP_RE_EL20_TAP__W 12
+#define QAM_FQ_TAP_RE_EL20_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL20_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL20__A 0x1420049
+#define QAM_FQ_TAP_IM_EL20__W 12
+#define QAM_FQ_TAP_IM_EL20__M 0xFFF
+#define QAM_FQ_TAP_IM_EL20__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL20_TAP__B 0
+#define QAM_FQ_TAP_IM_EL20_TAP__W 12
+#define QAM_FQ_TAP_IM_EL20_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL20_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL21__A 0x142004A
+#define QAM_FQ_TAP_RE_EL21__W 12
+#define QAM_FQ_TAP_RE_EL21__M 0xFFF
+#define QAM_FQ_TAP_RE_EL21__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL21_TAP__B 0
+#define QAM_FQ_TAP_RE_EL21_TAP__W 12
+#define QAM_FQ_TAP_RE_EL21_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL21_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL21__A 0x142004B
+#define QAM_FQ_TAP_IM_EL21__W 12
+#define QAM_FQ_TAP_IM_EL21__M 0xFFF
+#define QAM_FQ_TAP_IM_EL21__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL21_TAP__B 0
+#define QAM_FQ_TAP_IM_EL21_TAP__W 12
+#define QAM_FQ_TAP_IM_EL21_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL21_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL22__A 0x142004C
+#define QAM_FQ_TAP_RE_EL22__W 12
+#define QAM_FQ_TAP_RE_EL22__M 0xFFF
+#define QAM_FQ_TAP_RE_EL22__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL22_TAP__B 0
+#define QAM_FQ_TAP_RE_EL22_TAP__W 12
+#define QAM_FQ_TAP_RE_EL22_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL22_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL22__A 0x142004D
+#define QAM_FQ_TAP_IM_EL22__W 12
+#define QAM_FQ_TAP_IM_EL22__M 0xFFF
+#define QAM_FQ_TAP_IM_EL22__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL22_TAP__B 0
+#define QAM_FQ_TAP_IM_EL22_TAP__W 12
+#define QAM_FQ_TAP_IM_EL22_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL22_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL23__A 0x142004E
+#define QAM_FQ_TAP_RE_EL23__W 12
+#define QAM_FQ_TAP_RE_EL23__M 0xFFF
+#define QAM_FQ_TAP_RE_EL23__PRE 0x2
+
+#define QAM_FQ_TAP_RE_EL23_TAP__B 0
+#define QAM_FQ_TAP_RE_EL23_TAP__W 12
+#define QAM_FQ_TAP_RE_EL23_TAP__M 0xFFF
+#define QAM_FQ_TAP_RE_EL23_TAP__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL23__A 0x142004F
+#define QAM_FQ_TAP_IM_EL23__W 12
+#define QAM_FQ_TAP_IM_EL23__M 0xFFF
+#define QAM_FQ_TAP_IM_EL23__PRE 0x2
+
+#define QAM_FQ_TAP_IM_EL23_TAP__B 0
+#define QAM_FQ_TAP_IM_EL23_TAP__W 12
+#define QAM_FQ_TAP_IM_EL23_TAP__M 0xFFF
+#define QAM_FQ_TAP_IM_EL23_TAP__PRE 0x2
+
+#define QAM_SL_COMM_EXEC__A 0x1430000
+#define QAM_SL_COMM_EXEC__W 2
+#define QAM_SL_COMM_EXEC__M 0x3
+#define QAM_SL_COMM_EXEC__PRE 0x0
+#define QAM_SL_COMM_EXEC_STOP 0x0
+#define QAM_SL_COMM_EXEC_ACTIVE 0x1
+#define QAM_SL_COMM_EXEC_HOLD 0x2
+
+#define QAM_SL_COMM_MB__A 0x1430002
+#define QAM_SL_COMM_MB__W 4
+#define QAM_SL_COMM_MB__M 0xF
+#define QAM_SL_COMM_MB__PRE 0x0
+#define QAM_SL_COMM_MB_CTL__B 0
+#define QAM_SL_COMM_MB_CTL__W 1
+#define QAM_SL_COMM_MB_CTL__M 0x1
+#define QAM_SL_COMM_MB_CTL__PRE 0x0
+#define QAM_SL_COMM_MB_CTL_OFF 0x0
+#define QAM_SL_COMM_MB_CTL_ON 0x1
+#define QAM_SL_COMM_MB_OBS__B 1
+#define QAM_SL_COMM_MB_OBS__W 1
+#define QAM_SL_COMM_MB_OBS__M 0x2
+#define QAM_SL_COMM_MB_OBS__PRE 0x0
+#define QAM_SL_COMM_MB_OBS_OFF 0x0
+#define QAM_SL_COMM_MB_OBS_ON 0x2
+#define QAM_SL_COMM_MB_MUX_OBS__B 2
+#define QAM_SL_COMM_MB_MUX_OBS__W 2
+#define QAM_SL_COMM_MB_MUX_OBS__M 0xC
+#define QAM_SL_COMM_MB_MUX_OBS__PRE 0x0
+#define QAM_SL_COMM_MB_MUX_OBS_CONST_CORR 0x0
+#define QAM_SL_COMM_MB_MUX_OBS_CONST2LC_O 0x4
+#define QAM_SL_COMM_MB_MUX_OBS_CONST2DQ_O 0x8
+#define QAM_SL_COMM_MB_MUX_OBS_VDEC_O 0xC
+
+#define QAM_SL_COMM_INT_REQ__A 0x1430003
+#define QAM_SL_COMM_INT_REQ__W 1
+#define QAM_SL_COMM_INT_REQ__M 0x1
+#define QAM_SL_COMM_INT_REQ__PRE 0x0
+#define QAM_SL_COMM_INT_STA__A 0x1430005
+#define QAM_SL_COMM_INT_STA__W 2
+#define QAM_SL_COMM_INT_STA__M 0x3
+#define QAM_SL_COMM_INT_STA__PRE 0x0
+
+#define QAM_SL_COMM_INT_STA_MED_ERR_INT__B 0
+#define QAM_SL_COMM_INT_STA_MED_ERR_INT__W 1
+#define QAM_SL_COMM_INT_STA_MED_ERR_INT__M 0x1
+#define QAM_SL_COMM_INT_STA_MED_ERR_INT__PRE 0x0
+
+#define QAM_SL_COMM_INT_STA_MER_INT__B 1
+#define QAM_SL_COMM_INT_STA_MER_INT__W 1
+#define QAM_SL_COMM_INT_STA_MER_INT__M 0x2
+#define QAM_SL_COMM_INT_STA_MER_INT__PRE 0x0
+
+#define QAM_SL_COMM_INT_MSK__A 0x1430006
+#define QAM_SL_COMM_INT_MSK__W 2
+#define QAM_SL_COMM_INT_MSK__M 0x3
+#define QAM_SL_COMM_INT_MSK__PRE 0x0
+#define QAM_SL_COMM_INT_MSK_MED_ERR_MSK__B 0
+#define QAM_SL_COMM_INT_MSK_MED_ERR_MSK__W 1
+#define QAM_SL_COMM_INT_MSK_MED_ERR_MSK__M 0x1
+#define QAM_SL_COMM_INT_MSK_MED_ERR_MSK__PRE 0x0
+#define QAM_SL_COMM_INT_MSK_MER_MSK__B 1
+#define QAM_SL_COMM_INT_MSK_MER_MSK__W 1
+#define QAM_SL_COMM_INT_MSK_MER_MSK__M 0x2
+#define QAM_SL_COMM_INT_MSK_MER_MSK__PRE 0x0
+
+#define QAM_SL_COMM_INT_STM__A 0x1430007
+#define QAM_SL_COMM_INT_STM__W 2
+#define QAM_SL_COMM_INT_STM__M 0x3
+#define QAM_SL_COMM_INT_STM__PRE 0x0
+#define QAM_SL_COMM_INT_STM_MED_ERR_STM__B 0
+#define QAM_SL_COMM_INT_STM_MED_ERR_STM__W 1
+#define QAM_SL_COMM_INT_STM_MED_ERR_STM__M 0x1
+#define QAM_SL_COMM_INT_STM_MED_ERR_STM__PRE 0x0
+#define QAM_SL_COMM_INT_STM_MER_STM__B 1
+#define QAM_SL_COMM_INT_STM_MER_STM__W 1
+#define QAM_SL_COMM_INT_STM_MER_STM__M 0x2
+#define QAM_SL_COMM_INT_STM_MER_STM__PRE 0x0
+
+#define QAM_SL_MODE__A 0x1430010
+#define QAM_SL_MODE__W 11
+#define QAM_SL_MODE__M 0x7FF
+#define QAM_SL_MODE__PRE 0x0
+
+#define QAM_SL_MODE_SLICER4LC__B 0
+#define QAM_SL_MODE_SLICER4LC__W 2
+#define QAM_SL_MODE_SLICER4LC__M 0x3
+#define QAM_SL_MODE_SLICER4LC__PRE 0x0
+#define QAM_SL_MODE_SLICER4LC_RECT 0x0
+#define QAM_SL_MODE_SLICER4LC_ONET 0x1
+#define QAM_SL_MODE_SLICER4LC_RAD 0x2
+
+#define QAM_SL_MODE_SLICER4DQ__B 2
+#define QAM_SL_MODE_SLICER4DQ__W 2
+#define QAM_SL_MODE_SLICER4DQ__M 0xC
+#define QAM_SL_MODE_SLICER4DQ__PRE 0x0
+#define QAM_SL_MODE_SLICER4DQ_RECT 0x0
+#define QAM_SL_MODE_SLICER4DQ_ONET 0x4
+#define QAM_SL_MODE_SLICER4DQ_RAD 0x8
+
+#define QAM_SL_MODE_SLICER4VD__B 4
+#define QAM_SL_MODE_SLICER4VD__W 2
+#define QAM_SL_MODE_SLICER4VD__M 0x30
+#define QAM_SL_MODE_SLICER4VD__PRE 0x0
+#define QAM_SL_MODE_SLICER4VD_RECT 0x0
+#define QAM_SL_MODE_SLICER4VD_ONET 0x10
+#define QAM_SL_MODE_SLICER4VD_RAD 0x20
+
+#define QAM_SL_MODE_ROT_DIS__B 6
+#define QAM_SL_MODE_ROT_DIS__W 1
+#define QAM_SL_MODE_ROT_DIS__M 0x40
+#define QAM_SL_MODE_ROT_DIS__PRE 0x0
+
+#define QAM_SL_MODE_DQROT_DIS__B 7
+#define QAM_SL_MODE_DQROT_DIS__W 1
+#define QAM_SL_MODE_DQROT_DIS__M 0x80
+#define QAM_SL_MODE_DQROT_DIS__PRE 0x0
+
+#define QAM_SL_MODE_DFE_DIS__B 8
+#define QAM_SL_MODE_DFE_DIS__W 1
+#define QAM_SL_MODE_DFE_DIS__M 0x100
+#define QAM_SL_MODE_DFE_DIS__PRE 0x0
+
+#define QAM_SL_MODE_RADIUS_MIX__B 9
+#define QAM_SL_MODE_RADIUS_MIX__W 1
+#define QAM_SL_MODE_RADIUS_MIX__M 0x200
+#define QAM_SL_MODE_RADIUS_MIX__PRE 0x0
+
+#define QAM_SL_MODE_TILT_COMP__B 10
+#define QAM_SL_MODE_TILT_COMP__W 1
+#define QAM_SL_MODE_TILT_COMP__M 0x400
+#define QAM_SL_MODE_TILT_COMP__PRE 0x0
+
+#define QAM_SL_K_FACTOR__A 0x1430011
+#define QAM_SL_K_FACTOR__W 4
+#define QAM_SL_K_FACTOR__M 0xF
+#define QAM_SL_K_FACTOR__PRE 0x0
+#define QAM_SL_MEDIAN__A 0x1430012
+#define QAM_SL_MEDIAN__W 14
+#define QAM_SL_MEDIAN__M 0x3FFF
+#define QAM_SL_MEDIAN__PRE 0x0
+
+#define QAM_SL_MEDIAN_LENGTH__B 0
+#define QAM_SL_MEDIAN_LENGTH__W 2
+#define QAM_SL_MEDIAN_LENGTH__M 0x3
+#define QAM_SL_MEDIAN_LENGTH__PRE 0x0
+
+#define QAM_SL_MEDIAN_CORRECT__B 2
+#define QAM_SL_MEDIAN_CORRECT__W 4
+#define QAM_SL_MEDIAN_CORRECT__M 0x3C
+#define QAM_SL_MEDIAN_CORRECT__PRE 0x0
+
+#define QAM_SL_MEDIAN_TOLERANCE__B 6
+#define QAM_SL_MEDIAN_TOLERANCE__W 7
+#define QAM_SL_MEDIAN_TOLERANCE__M 0x1FC0
+#define QAM_SL_MEDIAN_TOLERANCE__PRE 0x0
+
+#define QAM_SL_MEDIAN_FAST__B 13
+#define QAM_SL_MEDIAN_FAST__W 1
+#define QAM_SL_MEDIAN_FAST__M 0x2000
+#define QAM_SL_MEDIAN_FAST__PRE 0x0
+
+#define QAM_SL_ALPHA__A 0x1430013
+#define QAM_SL_ALPHA__W 3
+#define QAM_SL_ALPHA__M 0x7
+#define QAM_SL_ALPHA__PRE 0x0
+
+#define QAM_SL_PHASELIMIT__A 0x1430014
+#define QAM_SL_PHASELIMIT__W 9
+#define QAM_SL_PHASELIMIT__M 0x1FF
+#define QAM_SL_PHASELIMIT__PRE 0x0
+#define QAM_SL_MTA_LENGTH__A 0x1430015
+#define QAM_SL_MTA_LENGTH__W 2
+#define QAM_SL_MTA_LENGTH__M 0x3
+#define QAM_SL_MTA_LENGTH__PRE 0x1
+
+#define QAM_SL_MTA_LENGTH_LENGTH__B 0
+#define QAM_SL_MTA_LENGTH_LENGTH__W 2
+#define QAM_SL_MTA_LENGTH_LENGTH__M 0x3
+#define QAM_SL_MTA_LENGTH_LENGTH__PRE 0x1
+
+#define QAM_SL_MEDIAN_ERROR__A 0x1430016
+#define QAM_SL_MEDIAN_ERROR__W 10
+#define QAM_SL_MEDIAN_ERROR__M 0x3FF
+#define QAM_SL_MEDIAN_ERROR__PRE 0x0
+
+#define QAM_SL_MEDIAN_ERROR_MEDIAN_ERR__B 0
+#define QAM_SL_MEDIAN_ERROR_MEDIAN_ERR__W 10
+#define QAM_SL_MEDIAN_ERROR_MEDIAN_ERR__M 0x3FF
+#define QAM_SL_MEDIAN_ERROR_MEDIAN_ERR__PRE 0x0
+
+#define QAM_SL_ERR_POWER__A 0x1430017
+#define QAM_SL_ERR_POWER__W 16
+#define QAM_SL_ERR_POWER__M 0xFFFF
+#define QAM_SL_ERR_POWER__PRE 0x0
+
+#define QAM_DQ_COMM_EXEC__A 0x1440000
+#define QAM_DQ_COMM_EXEC__W 2
+#define QAM_DQ_COMM_EXEC__M 0x3
+#define QAM_DQ_COMM_EXEC__PRE 0x0
+#define QAM_DQ_COMM_EXEC_STOP 0x0
+#define QAM_DQ_COMM_EXEC_ACTIVE 0x1
+#define QAM_DQ_COMM_EXEC_HOLD 0x2
+
+#define QAM_DQ_MODE__A 0x1440010
+#define QAM_DQ_MODE__W 5
+#define QAM_DQ_MODE__M 0x1F
+#define QAM_DQ_MODE__PRE 0x0
+
+#define QAM_DQ_MODE_TAPRESET__B 0
+#define QAM_DQ_MODE_TAPRESET__W 1
+#define QAM_DQ_MODE_TAPRESET__M 0x1
+#define QAM_DQ_MODE_TAPRESET__PRE 0x0
+#define QAM_DQ_MODE_TAPRESET_RST 0x1
+
+#define QAM_DQ_MODE_TAPLMS__B 1
+#define QAM_DQ_MODE_TAPLMS__W 1
+#define QAM_DQ_MODE_TAPLMS__M 0x2
+#define QAM_DQ_MODE_TAPLMS__PRE 0x0
+#define QAM_DQ_MODE_TAPLMS_UPD 0x2
+
+#define QAM_DQ_MODE_TAPDRAIN__B 2
+#define QAM_DQ_MODE_TAPDRAIN__W 1
+#define QAM_DQ_MODE_TAPDRAIN__M 0x4
+#define QAM_DQ_MODE_TAPDRAIN__PRE 0x0
+#define QAM_DQ_MODE_TAPDRAIN_DRAIN 0x4
+
+#define QAM_DQ_MODE_FB__B 3
+#define QAM_DQ_MODE_FB__W 2
+#define QAM_DQ_MODE_FB__M 0x18
+#define QAM_DQ_MODE_FB__PRE 0x0
+#define QAM_DQ_MODE_FB_CMA 0x0
+#define QAM_DQ_MODE_FB_RADIUS 0x8
+#define QAM_DQ_MODE_FB_DFB 0x10
+#define QAM_DQ_MODE_FB_TRELLIS 0x18
+
+#define QAM_DQ_MU_FACTOR__A 0x1440011
+#define QAM_DQ_MU_FACTOR__W 3
+#define QAM_DQ_MU_FACTOR__M 0x7
+#define QAM_DQ_MU_FACTOR__PRE 0x0
+
+#define QAM_DQ_LA_FACTOR__A 0x1440012
+#define QAM_DQ_LA_FACTOR__W 4
+#define QAM_DQ_LA_FACTOR__M 0xF
+#define QAM_DQ_LA_FACTOR__PRE 0xC
+
+#define QAM_DQ_CMA_RATIO__A 0x1440013
+#define QAM_DQ_CMA_RATIO__W 14
+#define QAM_DQ_CMA_RATIO__M 0x3FFF
+#define QAM_DQ_CMA_RATIO__PRE 0x3CF9
+#define QAM_DQ_CMA_RATIO_QPSK 0x2000
+#define QAM_DQ_CMA_RATIO_QAM16 0x34CD
+#define QAM_DQ_CMA_RATIO_QAM64 0x3A00
+#define QAM_DQ_CMA_RATIO_QAM256 0x3B4D
+#define QAM_DQ_CMA_RATIO_QAM1024 0x3BA0
+
+#define QAM_DQ_QUAL_RADSEL__A 0x1440014
+#define QAM_DQ_QUAL_RADSEL__W 3
+#define QAM_DQ_QUAL_RADSEL__M 0x7
+#define QAM_DQ_QUAL_RADSEL__PRE 0x0
+
+#define QAM_DQ_QUAL_RADSEL_BIT__B 0
+#define QAM_DQ_QUAL_RADSEL_BIT__W 3
+#define QAM_DQ_QUAL_RADSEL_BIT__M 0x7
+#define QAM_DQ_QUAL_RADSEL_BIT__PRE 0x0
+#define QAM_DQ_QUAL_RADSEL_BIT_PURE_RADIUS 0x0
+#define QAM_DQ_QUAL_RADSEL_BIT_PURE_CMA 0x6
+
+#define QAM_DQ_QUAL_ENA__A 0x1440015
+#define QAM_DQ_QUAL_ENA__W 1
+#define QAM_DQ_QUAL_ENA__M 0x1
+#define QAM_DQ_QUAL_ENA__PRE 0x0
+
+#define QAM_DQ_QUAL_ENA_ENA__B 0
+#define QAM_DQ_QUAL_ENA_ENA__W 1
+#define QAM_DQ_QUAL_ENA_ENA__M 0x1
+#define QAM_DQ_QUAL_ENA_ENA__PRE 0x0
+#define QAM_DQ_QUAL_ENA_ENA_QUAL_WEIGHTING 0x1
+
+#define QAM_DQ_QUAL_FUN0__A 0x1440018
+#define QAM_DQ_QUAL_FUN0__W 6
+#define QAM_DQ_QUAL_FUN0__M 0x3F
+#define QAM_DQ_QUAL_FUN0__PRE 0x4
+
+#define QAM_DQ_QUAL_FUN0_BIT__B 0
+#define QAM_DQ_QUAL_FUN0_BIT__W 6
+#define QAM_DQ_QUAL_FUN0_BIT__M 0x3F
+#define QAM_DQ_QUAL_FUN0_BIT__PRE 0x4
+
+#define QAM_DQ_QUAL_FUN1__A 0x1440019
+#define QAM_DQ_QUAL_FUN1__W 6
+#define QAM_DQ_QUAL_FUN1__M 0x3F
+#define QAM_DQ_QUAL_FUN1__PRE 0x4
+
+#define QAM_DQ_QUAL_FUN1_BIT__B 0
+#define QAM_DQ_QUAL_FUN1_BIT__W 6
+#define QAM_DQ_QUAL_FUN1_BIT__M 0x3F
+#define QAM_DQ_QUAL_FUN1_BIT__PRE 0x4
+
+#define QAM_DQ_QUAL_FUN2__A 0x144001A
+#define QAM_DQ_QUAL_FUN2__W 6
+#define QAM_DQ_QUAL_FUN2__M 0x3F
+#define QAM_DQ_QUAL_FUN2__PRE 0x4
+
+#define QAM_DQ_QUAL_FUN2_BIT__B 0
+#define QAM_DQ_QUAL_FUN2_BIT__W 6
+#define QAM_DQ_QUAL_FUN2_BIT__M 0x3F
+#define QAM_DQ_QUAL_FUN2_BIT__PRE 0x4
+
+#define QAM_DQ_QUAL_FUN3__A 0x144001B
+#define QAM_DQ_QUAL_FUN3__W 6
+#define QAM_DQ_QUAL_FUN3__M 0x3F
+#define QAM_DQ_QUAL_FUN3__PRE 0x4
+
+#define QAM_DQ_QUAL_FUN3_BIT__B 0
+#define QAM_DQ_QUAL_FUN3_BIT__W 6
+#define QAM_DQ_QUAL_FUN3_BIT__M 0x3F
+#define QAM_DQ_QUAL_FUN3_BIT__PRE 0x4
+
+#define QAM_DQ_QUAL_FUN4__A 0x144001C
+#define QAM_DQ_QUAL_FUN4__W 6
+#define QAM_DQ_QUAL_FUN4__M 0x3F
+#define QAM_DQ_QUAL_FUN4__PRE 0x6
+
+#define QAM_DQ_QUAL_FUN4_BIT__B 0
+#define QAM_DQ_QUAL_FUN4_BIT__W 6
+#define QAM_DQ_QUAL_FUN4_BIT__M 0x3F
+#define QAM_DQ_QUAL_FUN4_BIT__PRE 0x6
+
+#define QAM_DQ_QUAL_FUN5__A 0x144001D
+#define QAM_DQ_QUAL_FUN5__W 6
+#define QAM_DQ_QUAL_FUN5__M 0x3F
+#define QAM_DQ_QUAL_FUN5__PRE 0x6
+
+#define QAM_DQ_QUAL_FUN5_BIT__B 0
+#define QAM_DQ_QUAL_FUN5_BIT__W 6
+#define QAM_DQ_QUAL_FUN5_BIT__M 0x3F
+#define QAM_DQ_QUAL_FUN5_BIT__PRE 0x6
+
+#define QAM_DQ_RAW_LIM__A 0x144001E
+#define QAM_DQ_RAW_LIM__W 5
+#define QAM_DQ_RAW_LIM__M 0x1F
+#define QAM_DQ_RAW_LIM__PRE 0x1F
+
+#define QAM_DQ_RAW_LIM_BIT__B 0
+#define QAM_DQ_RAW_LIM_BIT__W 5
+#define QAM_DQ_RAW_LIM_BIT__M 0x1F
+#define QAM_DQ_RAW_LIM_BIT__PRE 0x1F
+
+#define QAM_DQ_TAP_RE_EL0__A 0x1440020
+#define QAM_DQ_TAP_RE_EL0__W 12
+#define QAM_DQ_TAP_RE_EL0__M 0xFFF
+#define QAM_DQ_TAP_RE_EL0__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL0_TAP__B 0
+#define QAM_DQ_TAP_RE_EL0_TAP__W 12
+#define QAM_DQ_TAP_RE_EL0_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL0_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL0__A 0x1440021
+#define QAM_DQ_TAP_IM_EL0__W 12
+#define QAM_DQ_TAP_IM_EL0__M 0xFFF
+#define QAM_DQ_TAP_IM_EL0__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL0_TAP__B 0
+#define QAM_DQ_TAP_IM_EL0_TAP__W 12
+#define QAM_DQ_TAP_IM_EL0_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL0_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL1__A 0x1440022
+#define QAM_DQ_TAP_RE_EL1__W 12
+#define QAM_DQ_TAP_RE_EL1__M 0xFFF
+#define QAM_DQ_TAP_RE_EL1__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL1_TAP__B 0
+#define QAM_DQ_TAP_RE_EL1_TAP__W 12
+#define QAM_DQ_TAP_RE_EL1_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL1_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL1__A 0x1440023
+#define QAM_DQ_TAP_IM_EL1__W 12
+#define QAM_DQ_TAP_IM_EL1__M 0xFFF
+#define QAM_DQ_TAP_IM_EL1__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL1_TAP__B 0
+#define QAM_DQ_TAP_IM_EL1_TAP__W 12
+#define QAM_DQ_TAP_IM_EL1_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL1_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL2__A 0x1440024
+#define QAM_DQ_TAP_RE_EL2__W 12
+#define QAM_DQ_TAP_RE_EL2__M 0xFFF
+#define QAM_DQ_TAP_RE_EL2__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL2_TAP__B 0
+#define QAM_DQ_TAP_RE_EL2_TAP__W 12
+#define QAM_DQ_TAP_RE_EL2_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL2_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL2__A 0x1440025
+#define QAM_DQ_TAP_IM_EL2__W 12
+#define QAM_DQ_TAP_IM_EL2__M 0xFFF
+#define QAM_DQ_TAP_IM_EL2__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL2_TAP__B 0
+#define QAM_DQ_TAP_IM_EL2_TAP__W 12
+#define QAM_DQ_TAP_IM_EL2_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL2_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL3__A 0x1440026
+#define QAM_DQ_TAP_RE_EL3__W 12
+#define QAM_DQ_TAP_RE_EL3__M 0xFFF
+#define QAM_DQ_TAP_RE_EL3__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL3_TAP__B 0
+#define QAM_DQ_TAP_RE_EL3_TAP__W 12
+#define QAM_DQ_TAP_RE_EL3_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL3_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL3__A 0x1440027
+#define QAM_DQ_TAP_IM_EL3__W 12
+#define QAM_DQ_TAP_IM_EL3__M 0xFFF
+#define QAM_DQ_TAP_IM_EL3__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL3_TAP__B 0
+#define QAM_DQ_TAP_IM_EL3_TAP__W 12
+#define QAM_DQ_TAP_IM_EL3_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL3_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL4__A 0x1440028
+#define QAM_DQ_TAP_RE_EL4__W 12
+#define QAM_DQ_TAP_RE_EL4__M 0xFFF
+#define QAM_DQ_TAP_RE_EL4__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL4_TAP__B 0
+#define QAM_DQ_TAP_RE_EL4_TAP__W 12
+#define QAM_DQ_TAP_RE_EL4_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL4_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL4__A 0x1440029
+#define QAM_DQ_TAP_IM_EL4__W 12
+#define QAM_DQ_TAP_IM_EL4__M 0xFFF
+#define QAM_DQ_TAP_IM_EL4__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL4_TAP__B 0
+#define QAM_DQ_TAP_IM_EL4_TAP__W 12
+#define QAM_DQ_TAP_IM_EL4_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL4_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL5__A 0x144002A
+#define QAM_DQ_TAP_RE_EL5__W 12
+#define QAM_DQ_TAP_RE_EL5__M 0xFFF
+#define QAM_DQ_TAP_RE_EL5__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL5_TAP__B 0
+#define QAM_DQ_TAP_RE_EL5_TAP__W 12
+#define QAM_DQ_TAP_RE_EL5_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL5_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL5__A 0x144002B
+#define QAM_DQ_TAP_IM_EL5__W 12
+#define QAM_DQ_TAP_IM_EL5__M 0xFFF
+#define QAM_DQ_TAP_IM_EL5__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL5_TAP__B 0
+#define QAM_DQ_TAP_IM_EL5_TAP__W 12
+#define QAM_DQ_TAP_IM_EL5_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL5_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL6__A 0x144002C
+#define QAM_DQ_TAP_RE_EL6__W 12
+#define QAM_DQ_TAP_RE_EL6__M 0xFFF
+#define QAM_DQ_TAP_RE_EL6__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL6_TAP__B 0
+#define QAM_DQ_TAP_RE_EL6_TAP__W 12
+#define QAM_DQ_TAP_RE_EL6_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL6_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL6__A 0x144002D
+#define QAM_DQ_TAP_IM_EL6__W 12
+#define QAM_DQ_TAP_IM_EL6__M 0xFFF
+#define QAM_DQ_TAP_IM_EL6__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL6_TAP__B 0
+#define QAM_DQ_TAP_IM_EL6_TAP__W 12
+#define QAM_DQ_TAP_IM_EL6_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL6_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL7__A 0x144002E
+#define QAM_DQ_TAP_RE_EL7__W 12
+#define QAM_DQ_TAP_RE_EL7__M 0xFFF
+#define QAM_DQ_TAP_RE_EL7__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL7_TAP__B 0
+#define QAM_DQ_TAP_RE_EL7_TAP__W 12
+#define QAM_DQ_TAP_RE_EL7_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL7_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL7__A 0x144002F
+#define QAM_DQ_TAP_IM_EL7__W 12
+#define QAM_DQ_TAP_IM_EL7__M 0xFFF
+#define QAM_DQ_TAP_IM_EL7__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL7_TAP__B 0
+#define QAM_DQ_TAP_IM_EL7_TAP__W 12
+#define QAM_DQ_TAP_IM_EL7_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL7_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL8__A 0x1440030
+#define QAM_DQ_TAP_RE_EL8__W 12
+#define QAM_DQ_TAP_RE_EL8__M 0xFFF
+#define QAM_DQ_TAP_RE_EL8__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL8_TAP__B 0
+#define QAM_DQ_TAP_RE_EL8_TAP__W 12
+#define QAM_DQ_TAP_RE_EL8_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL8_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL8__A 0x1440031
+#define QAM_DQ_TAP_IM_EL8__W 12
+#define QAM_DQ_TAP_IM_EL8__M 0xFFF
+#define QAM_DQ_TAP_IM_EL8__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL8_TAP__B 0
+#define QAM_DQ_TAP_IM_EL8_TAP__W 12
+#define QAM_DQ_TAP_IM_EL8_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL8_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL9__A 0x1440032
+#define QAM_DQ_TAP_RE_EL9__W 12
+#define QAM_DQ_TAP_RE_EL9__M 0xFFF
+#define QAM_DQ_TAP_RE_EL9__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL9_TAP__B 0
+#define QAM_DQ_TAP_RE_EL9_TAP__W 12
+#define QAM_DQ_TAP_RE_EL9_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL9_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL9__A 0x1440033
+#define QAM_DQ_TAP_IM_EL9__W 12
+#define QAM_DQ_TAP_IM_EL9__M 0xFFF
+#define QAM_DQ_TAP_IM_EL9__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL9_TAP__B 0
+#define QAM_DQ_TAP_IM_EL9_TAP__W 12
+#define QAM_DQ_TAP_IM_EL9_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL9_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL10__A 0x1440034
+#define QAM_DQ_TAP_RE_EL10__W 12
+#define QAM_DQ_TAP_RE_EL10__M 0xFFF
+#define QAM_DQ_TAP_RE_EL10__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL10_TAP__B 0
+#define QAM_DQ_TAP_RE_EL10_TAP__W 12
+#define QAM_DQ_TAP_RE_EL10_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL10_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL10__A 0x1440035
+#define QAM_DQ_TAP_IM_EL10__W 12
+#define QAM_DQ_TAP_IM_EL10__M 0xFFF
+#define QAM_DQ_TAP_IM_EL10__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL10_TAP__B 0
+#define QAM_DQ_TAP_IM_EL10_TAP__W 12
+#define QAM_DQ_TAP_IM_EL10_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL10_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL11__A 0x1440036
+#define QAM_DQ_TAP_RE_EL11__W 12
+#define QAM_DQ_TAP_RE_EL11__M 0xFFF
+#define QAM_DQ_TAP_RE_EL11__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL11_TAP__B 0
+#define QAM_DQ_TAP_RE_EL11_TAP__W 12
+#define QAM_DQ_TAP_RE_EL11_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL11_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL11__A 0x1440037
+#define QAM_DQ_TAP_IM_EL11__W 12
+#define QAM_DQ_TAP_IM_EL11__M 0xFFF
+#define QAM_DQ_TAP_IM_EL11__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL11_TAP__B 0
+#define QAM_DQ_TAP_IM_EL11_TAP__W 12
+#define QAM_DQ_TAP_IM_EL11_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL11_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL12__A 0x1440038
+#define QAM_DQ_TAP_RE_EL12__W 12
+#define QAM_DQ_TAP_RE_EL12__M 0xFFF
+#define QAM_DQ_TAP_RE_EL12__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL12_TAP__B 0
+#define QAM_DQ_TAP_RE_EL12_TAP__W 12
+#define QAM_DQ_TAP_RE_EL12_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL12_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL12__A 0x1440039
+#define QAM_DQ_TAP_IM_EL12__W 12
+#define QAM_DQ_TAP_IM_EL12__M 0xFFF
+#define QAM_DQ_TAP_IM_EL12__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL12_TAP__B 0
+#define QAM_DQ_TAP_IM_EL12_TAP__W 12
+#define QAM_DQ_TAP_IM_EL12_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL12_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL13__A 0x144003A
+#define QAM_DQ_TAP_RE_EL13__W 12
+#define QAM_DQ_TAP_RE_EL13__M 0xFFF
+#define QAM_DQ_TAP_RE_EL13__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL13_TAP__B 0
+#define QAM_DQ_TAP_RE_EL13_TAP__W 12
+#define QAM_DQ_TAP_RE_EL13_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL13_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL13__A 0x144003B
+#define QAM_DQ_TAP_IM_EL13__W 12
+#define QAM_DQ_TAP_IM_EL13__M 0xFFF
+#define QAM_DQ_TAP_IM_EL13__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL13_TAP__B 0
+#define QAM_DQ_TAP_IM_EL13_TAP__W 12
+#define QAM_DQ_TAP_IM_EL13_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL13_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL14__A 0x144003C
+#define QAM_DQ_TAP_RE_EL14__W 12
+#define QAM_DQ_TAP_RE_EL14__M 0xFFF
+#define QAM_DQ_TAP_RE_EL14__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL14_TAP__B 0
+#define QAM_DQ_TAP_RE_EL14_TAP__W 12
+#define QAM_DQ_TAP_RE_EL14_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL14_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL14__A 0x144003D
+#define QAM_DQ_TAP_IM_EL14__W 12
+#define QAM_DQ_TAP_IM_EL14__M 0xFFF
+#define QAM_DQ_TAP_IM_EL14__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL14_TAP__B 0
+#define QAM_DQ_TAP_IM_EL14_TAP__W 12
+#define QAM_DQ_TAP_IM_EL14_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL14_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL15__A 0x144003E
+#define QAM_DQ_TAP_RE_EL15__W 12
+#define QAM_DQ_TAP_RE_EL15__M 0xFFF
+#define QAM_DQ_TAP_RE_EL15__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL15_TAP__B 0
+#define QAM_DQ_TAP_RE_EL15_TAP__W 12
+#define QAM_DQ_TAP_RE_EL15_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL15_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL15__A 0x144003F
+#define QAM_DQ_TAP_IM_EL15__W 12
+#define QAM_DQ_TAP_IM_EL15__M 0xFFF
+#define QAM_DQ_TAP_IM_EL15__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL15_TAP__B 0
+#define QAM_DQ_TAP_IM_EL15_TAP__W 12
+#define QAM_DQ_TAP_IM_EL15_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL15_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL16__A 0x1440040
+#define QAM_DQ_TAP_RE_EL16__W 12
+#define QAM_DQ_TAP_RE_EL16__M 0xFFF
+#define QAM_DQ_TAP_RE_EL16__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL16_TAP__B 0
+#define QAM_DQ_TAP_RE_EL16_TAP__W 12
+#define QAM_DQ_TAP_RE_EL16_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL16_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL16__A 0x1440041
+#define QAM_DQ_TAP_IM_EL16__W 12
+#define QAM_DQ_TAP_IM_EL16__M 0xFFF
+#define QAM_DQ_TAP_IM_EL16__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL16_TAP__B 0
+#define QAM_DQ_TAP_IM_EL16_TAP__W 12
+#define QAM_DQ_TAP_IM_EL16_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL16_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL17__A 0x1440042
+#define QAM_DQ_TAP_RE_EL17__W 12
+#define QAM_DQ_TAP_RE_EL17__M 0xFFF
+#define QAM_DQ_TAP_RE_EL17__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL17_TAP__B 0
+#define QAM_DQ_TAP_RE_EL17_TAP__W 12
+#define QAM_DQ_TAP_RE_EL17_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL17_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL17__A 0x1440043
+#define QAM_DQ_TAP_IM_EL17__W 12
+#define QAM_DQ_TAP_IM_EL17__M 0xFFF
+#define QAM_DQ_TAP_IM_EL17__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL17_TAP__B 0
+#define QAM_DQ_TAP_IM_EL17_TAP__W 12
+#define QAM_DQ_TAP_IM_EL17_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL17_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL18__A 0x1440044
+#define QAM_DQ_TAP_RE_EL18__W 12
+#define QAM_DQ_TAP_RE_EL18__M 0xFFF
+#define QAM_DQ_TAP_RE_EL18__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL18_TAP__B 0
+#define QAM_DQ_TAP_RE_EL18_TAP__W 12
+#define QAM_DQ_TAP_RE_EL18_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL18_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL18__A 0x1440045
+#define QAM_DQ_TAP_IM_EL18__W 12
+#define QAM_DQ_TAP_IM_EL18__M 0xFFF
+#define QAM_DQ_TAP_IM_EL18__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL18_TAP__B 0
+#define QAM_DQ_TAP_IM_EL18_TAP__W 12
+#define QAM_DQ_TAP_IM_EL18_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL18_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL19__A 0x1440046
+#define QAM_DQ_TAP_RE_EL19__W 12
+#define QAM_DQ_TAP_RE_EL19__M 0xFFF
+#define QAM_DQ_TAP_RE_EL19__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL19_TAP__B 0
+#define QAM_DQ_TAP_RE_EL19_TAP__W 12
+#define QAM_DQ_TAP_RE_EL19_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL19_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL19__A 0x1440047
+#define QAM_DQ_TAP_IM_EL19__W 12
+#define QAM_DQ_TAP_IM_EL19__M 0xFFF
+#define QAM_DQ_TAP_IM_EL19__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL19_TAP__B 0
+#define QAM_DQ_TAP_IM_EL19_TAP__W 12
+#define QAM_DQ_TAP_IM_EL19_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL19_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL20__A 0x1440048
+#define QAM_DQ_TAP_RE_EL20__W 12
+#define QAM_DQ_TAP_RE_EL20__M 0xFFF
+#define QAM_DQ_TAP_RE_EL20__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL20_TAP__B 0
+#define QAM_DQ_TAP_RE_EL20_TAP__W 12
+#define QAM_DQ_TAP_RE_EL20_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL20_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL20__A 0x1440049
+#define QAM_DQ_TAP_IM_EL20__W 12
+#define QAM_DQ_TAP_IM_EL20__M 0xFFF
+#define QAM_DQ_TAP_IM_EL20__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL20_TAP__B 0
+#define QAM_DQ_TAP_IM_EL20_TAP__W 12
+#define QAM_DQ_TAP_IM_EL20_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL20_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL21__A 0x144004A
+#define QAM_DQ_TAP_RE_EL21__W 12
+#define QAM_DQ_TAP_RE_EL21__M 0xFFF
+#define QAM_DQ_TAP_RE_EL21__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL21_TAP__B 0
+#define QAM_DQ_TAP_RE_EL21_TAP__W 12
+#define QAM_DQ_TAP_RE_EL21_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL21_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL21__A 0x144004B
+#define QAM_DQ_TAP_IM_EL21__W 12
+#define QAM_DQ_TAP_IM_EL21__M 0xFFF
+#define QAM_DQ_TAP_IM_EL21__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL21_TAP__B 0
+#define QAM_DQ_TAP_IM_EL21_TAP__W 12
+#define QAM_DQ_TAP_IM_EL21_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL21_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL22__A 0x144004C
+#define QAM_DQ_TAP_RE_EL22__W 12
+#define QAM_DQ_TAP_RE_EL22__M 0xFFF
+#define QAM_DQ_TAP_RE_EL22__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL22_TAP__B 0
+#define QAM_DQ_TAP_RE_EL22_TAP__W 12
+#define QAM_DQ_TAP_RE_EL22_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL22_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL22__A 0x144004D
+#define QAM_DQ_TAP_IM_EL22__W 12
+#define QAM_DQ_TAP_IM_EL22__M 0xFFF
+#define QAM_DQ_TAP_IM_EL22__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL22_TAP__B 0
+#define QAM_DQ_TAP_IM_EL22_TAP__W 12
+#define QAM_DQ_TAP_IM_EL22_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL22_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL23__A 0x144004E
+#define QAM_DQ_TAP_RE_EL23__W 12
+#define QAM_DQ_TAP_RE_EL23__M 0xFFF
+#define QAM_DQ_TAP_RE_EL23__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL23_TAP__B 0
+#define QAM_DQ_TAP_RE_EL23_TAP__W 12
+#define QAM_DQ_TAP_RE_EL23_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL23_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL23__A 0x144004F
+#define QAM_DQ_TAP_IM_EL23__W 12
+#define QAM_DQ_TAP_IM_EL23__M 0xFFF
+#define QAM_DQ_TAP_IM_EL23__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL23_TAP__B 0
+#define QAM_DQ_TAP_IM_EL23_TAP__W 12
+#define QAM_DQ_TAP_IM_EL23_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL23_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL24__A 0x1440050
+#define QAM_DQ_TAP_RE_EL24__W 12
+#define QAM_DQ_TAP_RE_EL24__M 0xFFF
+#define QAM_DQ_TAP_RE_EL24__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL24_TAP__B 0
+#define QAM_DQ_TAP_RE_EL24_TAP__W 12
+#define QAM_DQ_TAP_RE_EL24_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL24_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL24__A 0x1440051
+#define QAM_DQ_TAP_IM_EL24__W 12
+#define QAM_DQ_TAP_IM_EL24__M 0xFFF
+#define QAM_DQ_TAP_IM_EL24__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL24_TAP__B 0
+#define QAM_DQ_TAP_IM_EL24_TAP__W 12
+#define QAM_DQ_TAP_IM_EL24_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL24_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL25__A 0x1440052
+#define QAM_DQ_TAP_RE_EL25__W 12
+#define QAM_DQ_TAP_RE_EL25__M 0xFFF
+#define QAM_DQ_TAP_RE_EL25__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL25_TAP__B 0
+#define QAM_DQ_TAP_RE_EL25_TAP__W 12
+#define QAM_DQ_TAP_RE_EL25_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL25_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL25__A 0x1440053
+#define QAM_DQ_TAP_IM_EL25__W 12
+#define QAM_DQ_TAP_IM_EL25__M 0xFFF
+#define QAM_DQ_TAP_IM_EL25__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL25_TAP__B 0
+#define QAM_DQ_TAP_IM_EL25_TAP__W 12
+#define QAM_DQ_TAP_IM_EL25_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL25_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL26__A 0x1440054
+#define QAM_DQ_TAP_RE_EL26__W 12
+#define QAM_DQ_TAP_RE_EL26__M 0xFFF
+#define QAM_DQ_TAP_RE_EL26__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL26_TAP__B 0
+#define QAM_DQ_TAP_RE_EL26_TAP__W 12
+#define QAM_DQ_TAP_RE_EL26_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL26_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL26__A 0x1440055
+#define QAM_DQ_TAP_IM_EL26__W 12
+#define QAM_DQ_TAP_IM_EL26__M 0xFFF
+#define QAM_DQ_TAP_IM_EL26__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL26_TAP__B 0
+#define QAM_DQ_TAP_IM_EL26_TAP__W 12
+#define QAM_DQ_TAP_IM_EL26_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL26_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL27__A 0x1440056
+#define QAM_DQ_TAP_RE_EL27__W 12
+#define QAM_DQ_TAP_RE_EL27__M 0xFFF
+#define QAM_DQ_TAP_RE_EL27__PRE 0x2
+
+#define QAM_DQ_TAP_RE_EL27_TAP__B 0
+#define QAM_DQ_TAP_RE_EL27_TAP__W 12
+#define QAM_DQ_TAP_RE_EL27_TAP__M 0xFFF
+#define QAM_DQ_TAP_RE_EL27_TAP__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL27__A 0x1440057
+#define QAM_DQ_TAP_IM_EL27__W 12
+#define QAM_DQ_TAP_IM_EL27__M 0xFFF
+#define QAM_DQ_TAP_IM_EL27__PRE 0x2
+
+#define QAM_DQ_TAP_IM_EL27_TAP__B 0
+#define QAM_DQ_TAP_IM_EL27_TAP__W 12
+#define QAM_DQ_TAP_IM_EL27_TAP__M 0xFFF
+#define QAM_DQ_TAP_IM_EL27_TAP__PRE 0x2
+
+#define QAM_LC_COMM_EXEC__A 0x1450000
+#define QAM_LC_COMM_EXEC__W 2
+#define QAM_LC_COMM_EXEC__M 0x3
+#define QAM_LC_COMM_EXEC__PRE 0x0
+#define QAM_LC_COMM_EXEC_STOP 0x0
+#define QAM_LC_COMM_EXEC_ACTIVE 0x1
+#define QAM_LC_COMM_EXEC_HOLD 0x2
+
+#define QAM_LC_COMM_MB__A 0x1450002
+#define QAM_LC_COMM_MB__W 2
+#define QAM_LC_COMM_MB__M 0x3
+#define QAM_LC_COMM_MB__PRE 0x0
+#define QAM_LC_COMM_MB_CTL__B 0
+#define QAM_LC_COMM_MB_CTL__W 1
+#define QAM_LC_COMM_MB_CTL__M 0x1
+#define QAM_LC_COMM_MB_CTL__PRE 0x0
+#define QAM_LC_COMM_MB_CTL_OFF 0x0
+#define QAM_LC_COMM_MB_CTL_ON 0x1
+#define QAM_LC_COMM_MB_OBS__B 1
+#define QAM_LC_COMM_MB_OBS__W 1
+#define QAM_LC_COMM_MB_OBS__M 0x2
+#define QAM_LC_COMM_MB_OBS__PRE 0x0
+#define QAM_LC_COMM_MB_OBS_OFF 0x0
+#define QAM_LC_COMM_MB_OBS_ON 0x2
+
+#define QAM_LC_COMM_INT_REQ__A 0x1450003
+#define QAM_LC_COMM_INT_REQ__W 1
+#define QAM_LC_COMM_INT_REQ__M 0x1
+#define QAM_LC_COMM_INT_REQ__PRE 0x0
+#define QAM_LC_COMM_INT_STA__A 0x1450005
+#define QAM_LC_COMM_INT_STA__W 3
+#define QAM_LC_COMM_INT_STA__M 0x7
+#define QAM_LC_COMM_INT_STA__PRE 0x0
+
+#define QAM_LC_COMM_INT_STA_READY__B 0
+#define QAM_LC_COMM_INT_STA_READY__W 1
+#define QAM_LC_COMM_INT_STA_READY__M 0x1
+#define QAM_LC_COMM_INT_STA_READY__PRE 0x0
+
+#define QAM_LC_COMM_INT_STA_OVERFLOW__B 1
+#define QAM_LC_COMM_INT_STA_OVERFLOW__W 1
+#define QAM_LC_COMM_INT_STA_OVERFLOW__M 0x2
+#define QAM_LC_COMM_INT_STA_OVERFLOW__PRE 0x0
+
+#define QAM_LC_COMM_INT_STA_FREQ_WRAP__B 2
+#define QAM_LC_COMM_INT_STA_FREQ_WRAP__W 1
+#define QAM_LC_COMM_INT_STA_FREQ_WRAP__M 0x4
+#define QAM_LC_COMM_INT_STA_FREQ_WRAP__PRE 0x0
+
+#define QAM_LC_COMM_INT_MSK__A 0x1450006
+#define QAM_LC_COMM_INT_MSK__W 3
+#define QAM_LC_COMM_INT_MSK__M 0x7
+#define QAM_LC_COMM_INT_MSK__PRE 0x0
+#define QAM_LC_COMM_INT_MSK_READY__B 0
+#define QAM_LC_COMM_INT_MSK_READY__W 1
+#define QAM_LC_COMM_INT_MSK_READY__M 0x1
+#define QAM_LC_COMM_INT_MSK_READY__PRE 0x0
+#define QAM_LC_COMM_INT_MSK_OVERFLOW__B 1
+#define QAM_LC_COMM_INT_MSK_OVERFLOW__W 1
+#define QAM_LC_COMM_INT_MSK_OVERFLOW__M 0x2
+#define QAM_LC_COMM_INT_MSK_OVERFLOW__PRE 0x0
+#define QAM_LC_COMM_INT_MSK_FREQ_WRAP__B 2
+#define QAM_LC_COMM_INT_MSK_FREQ_WRAP__W 1
+#define QAM_LC_COMM_INT_MSK_FREQ_WRAP__M 0x4
+#define QAM_LC_COMM_INT_MSK_FREQ_WRAP__PRE 0x0
+
+#define QAM_LC_COMM_INT_STM__A 0x1450007
+#define QAM_LC_COMM_INT_STM__W 3
+#define QAM_LC_COMM_INT_STM__M 0x7
+#define QAM_LC_COMM_INT_STM__PRE 0x0
+#define QAM_LC_COMM_INT_STM_READY__B 0
+#define QAM_LC_COMM_INT_STM_READY__W 1
+#define QAM_LC_COMM_INT_STM_READY__M 0x1
+#define QAM_LC_COMM_INT_STM_READY__PRE 0x0
+#define QAM_LC_COMM_INT_STM_OVERFLOW__B 1
+#define QAM_LC_COMM_INT_STM_OVERFLOW__W 1
+#define QAM_LC_COMM_INT_STM_OVERFLOW__M 0x2
+#define QAM_LC_COMM_INT_STM_OVERFLOW__PRE 0x0
+#define QAM_LC_COMM_INT_STM_FREQ_WRAP__B 2
+#define QAM_LC_COMM_INT_STM_FREQ_WRAP__W 1
+#define QAM_LC_COMM_INT_STM_FREQ_WRAP__M 0x4
+#define QAM_LC_COMM_INT_STM_FREQ_WRAP__PRE 0x0
+
+#define QAM_LC_MODE__A 0x1450010
+#define QAM_LC_MODE__W 3
+#define QAM_LC_MODE__M 0x7
+#define QAM_LC_MODE__PRE 0x7
+
+#define QAM_LC_MODE_ENABLE_A__B 0
+#define QAM_LC_MODE_ENABLE_A__W 1
+#define QAM_LC_MODE_ENABLE_A__M 0x1
+#define QAM_LC_MODE_ENABLE_A__PRE 0x1
+
+#define QAM_LC_MODE_ENABLE_F__B 1
+#define QAM_LC_MODE_ENABLE_F__W 1
+#define QAM_LC_MODE_ENABLE_F__M 0x2
+#define QAM_LC_MODE_ENABLE_F__PRE 0x2
+
+#define QAM_LC_MODE_ENABLE_R__B 2
+#define QAM_LC_MODE_ENABLE_R__W 1
+#define QAM_LC_MODE_ENABLE_R__M 0x4
+#define QAM_LC_MODE_ENABLE_R__PRE 0x4
+
+#define QAM_LC_CA__A 0x1450011
+#define QAM_LC_CA__W 6
+#define QAM_LC_CA__M 0x3F
+#define QAM_LC_CA__PRE 0x28
+
+#define QAM_LC_CA_COEF__B 0
+#define QAM_LC_CA_COEF__W 6
+#define QAM_LC_CA_COEF__M 0x3F
+#define QAM_LC_CA_COEF__PRE 0x28
+
+#define QAM_LC_CF__A 0x1450012
+#define QAM_LC_CF__W 8
+#define QAM_LC_CF__M 0xFF
+#define QAM_LC_CF__PRE 0x8C
+
+#define QAM_LC_CF_COEF__B 0
+#define QAM_LC_CF_COEF__W 8
+#define QAM_LC_CF_COEF__M 0xFF
+#define QAM_LC_CF_COEF__PRE 0x8C
+
+#define QAM_LC_CF1__A 0x1450013
+#define QAM_LC_CF1__W 8
+#define QAM_LC_CF1__M 0xFF
+#define QAM_LC_CF1__PRE 0x1E
+
+#define QAM_LC_CF1_COEF__B 0
+#define QAM_LC_CF1_COEF__W 8
+#define QAM_LC_CF1_COEF__M 0xFF
+#define QAM_LC_CF1_COEF__PRE 0x1E
+
+#define QAM_LC_CP__A 0x1450014
+#define QAM_LC_CP__W 8
+#define QAM_LC_CP__M 0xFF
+#define QAM_LC_CP__PRE 0x78
+
+#define QAM_LC_CP_COEF__B 0
+#define QAM_LC_CP_COEF__W 8
+#define QAM_LC_CP_COEF__M 0xFF
+#define QAM_LC_CP_COEF__PRE 0x78
+
+#define QAM_LC_CI__A 0x1450015
+#define QAM_LC_CI__W 8
+#define QAM_LC_CI__M 0xFF
+#define QAM_LC_CI__PRE 0x46
+
+#define QAM_LC_CI_COEF__B 0
+#define QAM_LC_CI_COEF__W 8
+#define QAM_LC_CI_COEF__M 0xFF
+#define QAM_LC_CI_COEF__PRE 0x46
+
+#define QAM_LC_EP__A 0x1450016
+#define QAM_LC_EP__W 6
+#define QAM_LC_EP__M 0x3F
+#define QAM_LC_EP__PRE 0x0
+
+#define QAM_LC_EP_COEF__B 0
+#define QAM_LC_EP_COEF__W 6
+#define QAM_LC_EP_COEF__M 0x3F
+#define QAM_LC_EP_COEF__PRE 0x0
+
+#define QAM_LC_EI__A 0x1450017
+#define QAM_LC_EI__W 6
+#define QAM_LC_EI__M 0x3F
+#define QAM_LC_EI__PRE 0x0
+
+#define QAM_LC_EI_COEF__B 0
+#define QAM_LC_EI_COEF__W 6
+#define QAM_LC_EI_COEF__M 0x3F
+#define QAM_LC_EI_COEF__PRE 0x0
+
+#define QAM_LC_QUAL_TAB0__A 0x1450018
+#define QAM_LC_QUAL_TAB0__W 5
+#define QAM_LC_QUAL_TAB0__M 0x1F
+#define QAM_LC_QUAL_TAB0__PRE 0x1
+
+#define QAM_LC_QUAL_TAB0_VALUE__B 0
+#define QAM_LC_QUAL_TAB0_VALUE__W 5
+#define QAM_LC_QUAL_TAB0_VALUE__M 0x1F
+#define QAM_LC_QUAL_TAB0_VALUE__PRE 0x1
+
+#define QAM_LC_QUAL_TAB1__A 0x1450019
+#define QAM_LC_QUAL_TAB1__W 5
+#define QAM_LC_QUAL_TAB1__M 0x1F
+#define QAM_LC_QUAL_TAB1__PRE 0x1
+
+#define QAM_LC_QUAL_TAB1_VALUE__B 0
+#define QAM_LC_QUAL_TAB1_VALUE__W 5
+#define QAM_LC_QUAL_TAB1_VALUE__M 0x1F
+#define QAM_LC_QUAL_TAB1_VALUE__PRE 0x1
+
+#define QAM_LC_QUAL_TAB2__A 0x145001A
+#define QAM_LC_QUAL_TAB2__W 5
+#define QAM_LC_QUAL_TAB2__M 0x1F
+#define QAM_LC_QUAL_TAB2__PRE 0x1
+
+#define QAM_LC_QUAL_TAB2_VALUE__B 0
+#define QAM_LC_QUAL_TAB2_VALUE__W 5
+#define QAM_LC_QUAL_TAB2_VALUE__M 0x1F
+#define QAM_LC_QUAL_TAB2_VALUE__PRE 0x1
+
+#define QAM_LC_QUAL_TAB3__A 0x145001B
+#define QAM_LC_QUAL_TAB3__W 5
+#define QAM_LC_QUAL_TAB3__M 0x1F
+#define QAM_LC_QUAL_TAB3__PRE 0x1
+
+#define QAM_LC_QUAL_TAB3_VALUE__B 0
+#define QAM_LC_QUAL_TAB3_VALUE__W 5
+#define QAM_LC_QUAL_TAB3_VALUE__M 0x1F
+#define QAM_LC_QUAL_TAB3_VALUE__PRE 0x1
+
+#define QAM_LC_QUAL_TAB4__A 0x145001C
+#define QAM_LC_QUAL_TAB4__W 5
+#define QAM_LC_QUAL_TAB4__M 0x1F
+#define QAM_LC_QUAL_TAB4__PRE 0x1
+
+#define QAM_LC_QUAL_TAB4_VALUE__B 0
+#define QAM_LC_QUAL_TAB4_VALUE__W 5
+#define QAM_LC_QUAL_TAB4_VALUE__M 0x1F
+#define QAM_LC_QUAL_TAB4_VALUE__PRE 0x1
+
+#define QAM_LC_QUAL_TAB5__A 0x145001D
+#define QAM_LC_QUAL_TAB5__W 5
+#define QAM_LC_QUAL_TAB5__M 0x1F
+#define QAM_LC_QUAL_TAB5__PRE 0x1
+
+#define QAM_LC_QUAL_TAB5_VALUE__B 0
+#define QAM_LC_QUAL_TAB5_VALUE__W 5
+#define QAM_LC_QUAL_TAB5_VALUE__M 0x1F
+#define QAM_LC_QUAL_TAB5_VALUE__PRE 0x1
+
+#define QAM_LC_QUAL_TAB6__A 0x145001E
+#define QAM_LC_QUAL_TAB6__W 5
+#define QAM_LC_QUAL_TAB6__M 0x1F
+#define QAM_LC_QUAL_TAB6__PRE 0x1
+
+#define QAM_LC_QUAL_TAB6_VALUE__B 0
+#define QAM_LC_QUAL_TAB6_VALUE__W 5
+#define QAM_LC_QUAL_TAB6_VALUE__M 0x1F
+#define QAM_LC_QUAL_TAB6_VALUE__PRE 0x1
+
+#define QAM_LC_QUAL_TAB8__A 0x145001F
+#define QAM_LC_QUAL_TAB8__W 5
+#define QAM_LC_QUAL_TAB8__M 0x1F
+#define QAM_LC_QUAL_TAB8__PRE 0x1
+
+#define QAM_LC_QUAL_TAB8_VALUE__B 0
+#define QAM_LC_QUAL_TAB8_VALUE__W 5
+#define QAM_LC_QUAL_TAB8_VALUE__M 0x1F
+#define QAM_LC_QUAL_TAB8_VALUE__PRE 0x1
+
+#define QAM_LC_QUAL_TAB9__A 0x1450020
+#define QAM_LC_QUAL_TAB9__W 5
+#define QAM_LC_QUAL_TAB9__M 0x1F
+#define QAM_LC_QUAL_TAB9__PRE 0x1
+
+#define QAM_LC_QUAL_TAB9_VALUE__B 0
+#define QAM_LC_QUAL_TAB9_VALUE__W 5
+#define QAM_LC_QUAL_TAB9_VALUE__M 0x1F
+#define QAM_LC_QUAL_TAB9_VALUE__PRE 0x1
+
+#define QAM_LC_QUAL_TAB10__A 0x1450021
+#define QAM_LC_QUAL_TAB10__W 5
+#define QAM_LC_QUAL_TAB10__M 0x1F
+#define QAM_LC_QUAL_TAB10__PRE 0x1
+
+#define QAM_LC_QUAL_TAB10_VALUE__B 0
+#define QAM_LC_QUAL_TAB10_VALUE__W 5
+#define QAM_LC_QUAL_TAB10_VALUE__M 0x1F
+#define QAM_LC_QUAL_TAB10_VALUE__PRE 0x1
+
+#define QAM_LC_QUAL_TAB12__A 0x1450022
+#define QAM_LC_QUAL_TAB12__W 5
+#define QAM_LC_QUAL_TAB12__M 0x1F
+#define QAM_LC_QUAL_TAB12__PRE 0x1
+
+#define QAM_LC_QUAL_TAB12_VALUE__B 0
+#define QAM_LC_QUAL_TAB12_VALUE__W 5
+#define QAM_LC_QUAL_TAB12_VALUE__M 0x1F
+#define QAM_LC_QUAL_TAB12_VALUE__PRE 0x1
+
+#define QAM_LC_QUAL_TAB15__A 0x1450023
+#define QAM_LC_QUAL_TAB15__W 5
+#define QAM_LC_QUAL_TAB15__M 0x1F
+#define QAM_LC_QUAL_TAB15__PRE 0x1
+
+#define QAM_LC_QUAL_TAB15_VALUE__B 0
+#define QAM_LC_QUAL_TAB15_VALUE__W 5
+#define QAM_LC_QUAL_TAB15_VALUE__M 0x1F
+#define QAM_LC_QUAL_TAB15_VALUE__PRE 0x1
+
+#define QAM_LC_QUAL_TAB16__A 0x1450024
+#define QAM_LC_QUAL_TAB16__W 5
+#define QAM_LC_QUAL_TAB16__M 0x1F
+#define QAM_LC_QUAL_TAB16__PRE 0x1
+
+#define QAM_LC_QUAL_TAB16_VALUE__B 0
+#define QAM_LC_QUAL_TAB16_VALUE__W 5
+#define QAM_LC_QUAL_TAB16_VALUE__M 0x1F
+#define QAM_LC_QUAL_TAB16_VALUE__PRE 0x1
+
+#define QAM_LC_QUAL_TAB20__A 0x1450025
+#define QAM_LC_QUAL_TAB20__W 5
+#define QAM_LC_QUAL_TAB20__M 0x1F
+#define QAM_LC_QUAL_TAB20__PRE 0x1
+
+#define QAM_LC_QUAL_TAB20_VALUE__B 0
+#define QAM_LC_QUAL_TAB20_VALUE__W 5
+#define QAM_LC_QUAL_TAB20_VALUE__M 0x1F
+#define QAM_LC_QUAL_TAB20_VALUE__PRE 0x1
+
+#define QAM_LC_QUAL_TAB25__A 0x1450026
+#define QAM_LC_QUAL_TAB25__W 5
+#define QAM_LC_QUAL_TAB25__M 0x1F
+#define QAM_LC_QUAL_TAB25__PRE 0x1
+
+#define QAM_LC_QUAL_TAB25_VALUE__B 0
+#define QAM_LC_QUAL_TAB25_VALUE__W 5
+#define QAM_LC_QUAL_TAB25_VALUE__M 0x1F
+#define QAM_LC_QUAL_TAB25_VALUE__PRE 0x1
+
+#define QAM_LC_EQ_TIMING__A 0x1450027
+#define QAM_LC_EQ_TIMING__W 10
+#define QAM_LC_EQ_TIMING__M 0x3FF
+#define QAM_LC_EQ_TIMING__PRE 0x0
+
+#define QAM_LC_EQ_TIMING_OFFS__B 0
+#define QAM_LC_EQ_TIMING_OFFS__W 10
+#define QAM_LC_EQ_TIMING_OFFS__M 0x3FF
+#define QAM_LC_EQ_TIMING_OFFS__PRE 0x0
+
+#define QAM_LC_LPF_FACTORP__A 0x1450028
+#define QAM_LC_LPF_FACTORP__W 3
+#define QAM_LC_LPF_FACTORP__M 0x7
+#define QAM_LC_LPF_FACTORP__PRE 0x3
+
+#define QAM_LC_LPF_FACTORP_FACTOR__B 0
+#define QAM_LC_LPF_FACTORP_FACTOR__W 3
+#define QAM_LC_LPF_FACTORP_FACTOR__M 0x7
+#define QAM_LC_LPF_FACTORP_FACTOR__PRE 0x3
+
+#define QAM_LC_LPF_FACTORI__A 0x1450029
+#define QAM_LC_LPF_FACTORI__W 3
+#define QAM_LC_LPF_FACTORI__M 0x7
+#define QAM_LC_LPF_FACTORI__PRE 0x3
+
+#define QAM_LC_LPF_FACTORI_FACTOR__B 0
+#define QAM_LC_LPF_FACTORI_FACTOR__W 3
+#define QAM_LC_LPF_FACTORI_FACTOR__M 0x7
+#define QAM_LC_LPF_FACTORI_FACTOR__PRE 0x3
+
+#define QAM_LC_RATE_LIMIT__A 0x145002A
+#define QAM_LC_RATE_LIMIT__W 2
+#define QAM_LC_RATE_LIMIT__M 0x3
+#define QAM_LC_RATE_LIMIT__PRE 0x3
+
+#define QAM_LC_RATE_LIMIT_LIMIT__B 0
+#define QAM_LC_RATE_LIMIT_LIMIT__W 2
+#define QAM_LC_RATE_LIMIT_LIMIT__M 0x3
+#define QAM_LC_RATE_LIMIT_LIMIT__PRE 0x3
+
+#define QAM_LC_SYMBOL_FREQ__A 0x145002B
+#define QAM_LC_SYMBOL_FREQ__W 10
+#define QAM_LC_SYMBOL_FREQ__M 0x3FF
+#define QAM_LC_SYMBOL_FREQ__PRE 0x199
+
+#define QAM_LC_SYMBOL_FREQ_FREQ__B 0
+#define QAM_LC_SYMBOL_FREQ_FREQ__W 10
+#define QAM_LC_SYMBOL_FREQ_FREQ__M 0x3FF
+#define QAM_LC_SYMBOL_FREQ_FREQ__PRE 0x199
+#define QAM_LC_SYMBOL_FREQ_FREQ_QAM_B_64 0x197
+#define QAM_LC_SYMBOL_FREQ_FREQ_QAM_B_256 0x1B2
+
+#define QAM_LC_MTA_LENGTH__A 0x145002C
+#define QAM_LC_MTA_LENGTH__W 2
+#define QAM_LC_MTA_LENGTH__M 0x3
+#define QAM_LC_MTA_LENGTH__PRE 0x2
+
+#define QAM_LC_MTA_LENGTH_LENGTH__B 0
+#define QAM_LC_MTA_LENGTH_LENGTH__W 2
+#define QAM_LC_MTA_LENGTH_LENGTH__M 0x3
+#define QAM_LC_MTA_LENGTH_LENGTH__PRE 0x2
+
+#define QAM_LC_AMP_ACCU__A 0x145002D
+#define QAM_LC_AMP_ACCU__W 14
+#define QAM_LC_AMP_ACCU__M 0x3FFF
+#define QAM_LC_AMP_ACCU__PRE 0x600
+
+#define QAM_LC_AMP_ACCU_ACCU__B 0
+#define QAM_LC_AMP_ACCU_ACCU__W 14
+#define QAM_LC_AMP_ACCU_ACCU__M 0x3FFF
+#define QAM_LC_AMP_ACCU_ACCU__PRE 0x600
+
+#define QAM_LC_FREQ_ACCU__A 0x145002E
+#define QAM_LC_FREQ_ACCU__W 10
+#define QAM_LC_FREQ_ACCU__M 0x3FF
+#define QAM_LC_FREQ_ACCU__PRE 0x0
+
+#define QAM_LC_FREQ_ACCU_ACCU__B 0
+#define QAM_LC_FREQ_ACCU_ACCU__W 10
+#define QAM_LC_FREQ_ACCU_ACCU__M 0x3FF
+#define QAM_LC_FREQ_ACCU_ACCU__PRE 0x0
+
+#define QAM_LC_RATE_ACCU__A 0x145002F
+#define QAM_LC_RATE_ACCU__W 10
+#define QAM_LC_RATE_ACCU__M 0x3FF
+#define QAM_LC_RATE_ACCU__PRE 0x0
+
+#define QAM_LC_RATE_ACCU_ACCU__B 0
+#define QAM_LC_RATE_ACCU_ACCU__W 10
+#define QAM_LC_RATE_ACCU_ACCU__M 0x3FF
+#define QAM_LC_RATE_ACCU_ACCU__PRE 0x0
+
+#define QAM_LC_AMPLITUDE__A 0x1450030
+#define QAM_LC_AMPLITUDE__W 10
+#define QAM_LC_AMPLITUDE__M 0x3FF
+#define QAM_LC_AMPLITUDE__PRE 0x0
+
+#define QAM_LC_AMPLITUDE_SIZE__B 0
+#define QAM_LC_AMPLITUDE_SIZE__W 10
+#define QAM_LC_AMPLITUDE_SIZE__M 0x3FF
+#define QAM_LC_AMPLITUDE_SIZE__PRE 0x0
+
+#define QAM_LC_RAD_ERROR__A 0x1450031
+#define QAM_LC_RAD_ERROR__W 10
+#define QAM_LC_RAD_ERROR__M 0x3FF
+#define QAM_LC_RAD_ERROR__PRE 0x0
+
+#define QAM_LC_RAD_ERROR_SIZE__B 0
+#define QAM_LC_RAD_ERROR_SIZE__W 10
+#define QAM_LC_RAD_ERROR_SIZE__M 0x3FF
+#define QAM_LC_RAD_ERROR_SIZE__PRE 0x0
+
+#define QAM_LC_FREQ_OFFS__A 0x1450032
+#define QAM_LC_FREQ_OFFS__W 10
+#define QAM_LC_FREQ_OFFS__M 0x3FF
+#define QAM_LC_FREQ_OFFS__PRE 0x0
+
+#define QAM_LC_FREQ_OFFS_OFFS__B 0
+#define QAM_LC_FREQ_OFFS_OFFS__W 10
+#define QAM_LC_FREQ_OFFS_OFFS__M 0x3FF
+#define QAM_LC_FREQ_OFFS_OFFS__PRE 0x0
+
+#define QAM_LC_PHASE_ERROR__A 0x1450033
+#define QAM_LC_PHASE_ERROR__W 10
+#define QAM_LC_PHASE_ERROR__M 0x3FF
+#define QAM_LC_PHASE_ERROR__PRE 0x0
+
+#define QAM_LC_PHASE_ERROR_SIZE__B 0
+#define QAM_LC_PHASE_ERROR_SIZE__W 10
+#define QAM_LC_PHASE_ERROR_SIZE__M 0x3FF
+#define QAM_LC_PHASE_ERROR_SIZE__PRE 0x0
+
+#define QAM_VD_COMM_EXEC__A 0x1460000
+#define QAM_VD_COMM_EXEC__W 2
+#define QAM_VD_COMM_EXEC__M 0x3
+#define QAM_VD_COMM_EXEC__PRE 0x0
+#define QAM_VD_COMM_EXEC_STOP 0x0
+#define QAM_VD_COMM_EXEC_ACTIVE 0x1
+#define QAM_VD_COMM_EXEC_HOLD 0x2
+
+#define QAM_VD_COMM_MB__A 0x1460002
+#define QAM_VD_COMM_MB__W 2
+#define QAM_VD_COMM_MB__M 0x3
+#define QAM_VD_COMM_MB__PRE 0x0
+#define QAM_VD_COMM_MB_CTL__B 0
+#define QAM_VD_COMM_MB_CTL__W 1
+#define QAM_VD_COMM_MB_CTL__M 0x1
+#define QAM_VD_COMM_MB_CTL__PRE 0x0
+#define QAM_VD_COMM_MB_CTL_OFF 0x0
+#define QAM_VD_COMM_MB_CTL_ON 0x1
+#define QAM_VD_COMM_MB_OBS__B 1
+#define QAM_VD_COMM_MB_OBS__W 1
+#define QAM_VD_COMM_MB_OBS__M 0x2
+#define QAM_VD_COMM_MB_OBS__PRE 0x0
+#define QAM_VD_COMM_MB_OBS_OFF 0x0
+#define QAM_VD_COMM_MB_OBS_ON 0x2
+
+#define QAM_VD_COMM_INT_REQ__A 0x1460003
+#define QAM_VD_COMM_INT_REQ__W 1
+#define QAM_VD_COMM_INT_REQ__M 0x1
+#define QAM_VD_COMM_INT_REQ__PRE 0x0
+#define QAM_VD_COMM_INT_STA__A 0x1460005
+#define QAM_VD_COMM_INT_STA__W 2
+#define QAM_VD_COMM_INT_STA__M 0x3
+#define QAM_VD_COMM_INT_STA__PRE 0x0
+
+#define QAM_VD_COMM_INT_STA_LOCK_INT__B 0
+#define QAM_VD_COMM_INT_STA_LOCK_INT__W 1
+#define QAM_VD_COMM_INT_STA_LOCK_INT__M 0x1
+#define QAM_VD_COMM_INT_STA_LOCK_INT__PRE 0x0
+
+#define QAM_VD_COMM_INT_STA_PERIOD_INT__B 1
+#define QAM_VD_COMM_INT_STA_PERIOD_INT__W 1
+#define QAM_VD_COMM_INT_STA_PERIOD_INT__M 0x2
+#define QAM_VD_COMM_INT_STA_PERIOD_INT__PRE 0x0
+
+#define QAM_VD_COMM_INT_MSK__A 0x1460006
+#define QAM_VD_COMM_INT_MSK__W 2
+#define QAM_VD_COMM_INT_MSK__M 0x3
+#define QAM_VD_COMM_INT_MSK__PRE 0x0
+#define QAM_VD_COMM_INT_MSK_LOCK_INT__B 0
+#define QAM_VD_COMM_INT_MSK_LOCK_INT__W 1
+#define QAM_VD_COMM_INT_MSK_LOCK_INT__M 0x1
+#define QAM_VD_COMM_INT_MSK_LOCK_INT__PRE 0x0
+#define QAM_VD_COMM_INT_MSK_PERIOD_INT__B 1
+#define QAM_VD_COMM_INT_MSK_PERIOD_INT__W 1
+#define QAM_VD_COMM_INT_MSK_PERIOD_INT__M 0x2
+#define QAM_VD_COMM_INT_MSK_PERIOD_INT__PRE 0x0
+
+#define QAM_VD_COMM_INT_STM__A 0x1460007
+#define QAM_VD_COMM_INT_STM__W 2
+#define QAM_VD_COMM_INT_STM__M 0x3
+#define QAM_VD_COMM_INT_STM__PRE 0x0
+#define QAM_VD_COMM_INT_STM_LOCK_INT__B 0
+#define QAM_VD_COMM_INT_STM_LOCK_INT__W 1
+#define QAM_VD_COMM_INT_STM_LOCK_INT__M 0x1
+#define QAM_VD_COMM_INT_STM_LOCK_INT__PRE 0x0
+#define QAM_VD_COMM_INT_STM_PERIOD_INT__B 1
+#define QAM_VD_COMM_INT_STM_PERIOD_INT__W 1
+#define QAM_VD_COMM_INT_STM_PERIOD_INT__M 0x2
+#define QAM_VD_COMM_INT_STM_PERIOD_INT__PRE 0x0
+
+#define QAM_VD_STATUS__A 0x1460010
+#define QAM_VD_STATUS__W 1
+#define QAM_VD_STATUS__M 0x1
+#define QAM_VD_STATUS__PRE 0x0
+
+#define QAM_VD_STATUS_LOCK__B 0
+#define QAM_VD_STATUS_LOCK__W 1
+#define QAM_VD_STATUS_LOCK__M 0x1
+#define QAM_VD_STATUS_LOCK__PRE 0x0
+
+#define QAM_VD_UNLOCK_CONTROL__A 0x1460011
+#define QAM_VD_UNLOCK_CONTROL__W 1
+#define QAM_VD_UNLOCK_CONTROL__M 0x1
+#define QAM_VD_UNLOCK_CONTROL__PRE 0x0
+
+#define QAM_VD_UNLOCK_CONTROL_UNLOCK_CTRL__B 0
+#define QAM_VD_UNLOCK_CONTROL_UNLOCK_CTRL__W 1
+#define QAM_VD_UNLOCK_CONTROL_UNLOCK_CTRL__M 0x1
+#define QAM_VD_UNLOCK_CONTROL_UNLOCK_CTRL__PRE 0x0
+
+#define QAM_VD_MIN_VOTING_ROUNDS__A 0x1460012
+#define QAM_VD_MIN_VOTING_ROUNDS__W 6
+#define QAM_VD_MIN_VOTING_ROUNDS__M 0x3F
+#define QAM_VD_MIN_VOTING_ROUNDS__PRE 0x10
+
+#define QAM_VD_MIN_VOTING_ROUNDS_ROUNDS__B 0
+#define QAM_VD_MIN_VOTING_ROUNDS_ROUNDS__W 6
+#define QAM_VD_MIN_VOTING_ROUNDS_ROUNDS__M 0x3F
+#define QAM_VD_MIN_VOTING_ROUNDS_ROUNDS__PRE 0x10
+
+#define QAM_VD_MAX_VOTING_ROUNDS__A 0x1460013
+#define QAM_VD_MAX_VOTING_ROUNDS__W 6
+#define QAM_VD_MAX_VOTING_ROUNDS__M 0x3F
+#define QAM_VD_MAX_VOTING_ROUNDS__PRE 0x10
+
+#define QAM_VD_MAX_VOTING_ROUNDS_ROUNDS__B 0
+#define QAM_VD_MAX_VOTING_ROUNDS_ROUNDS__W 6
+#define QAM_VD_MAX_VOTING_ROUNDS_ROUNDS__M 0x3F
+#define QAM_VD_MAX_VOTING_ROUNDS_ROUNDS__PRE 0x10
+
+#define QAM_VD_TRACEBACK_DEPTH__A 0x1460014
+#define QAM_VD_TRACEBACK_DEPTH__W 5
+#define QAM_VD_TRACEBACK_DEPTH__M 0x1F
+#define QAM_VD_TRACEBACK_DEPTH__PRE 0x10
+
+#define QAM_VD_TRACEBACK_DEPTH_LENGTH__B 0
+#define QAM_VD_TRACEBACK_DEPTH_LENGTH__W 5
+#define QAM_VD_TRACEBACK_DEPTH_LENGTH__M 0x1F
+#define QAM_VD_TRACEBACK_DEPTH_LENGTH__PRE 0x10
+
+#define QAM_VD_UNLOCK__A 0x1460015
+#define QAM_VD_UNLOCK__W 1
+#define QAM_VD_UNLOCK__M 0x1
+#define QAM_VD_UNLOCK__PRE 0x0
+#define QAM_VD_MEASUREMENT_PERIOD__A 0x1460016
+#define QAM_VD_MEASUREMENT_PERIOD__W 16
+#define QAM_VD_MEASUREMENT_PERIOD__M 0xFFFF
+#define QAM_VD_MEASUREMENT_PERIOD__PRE 0x8236
+
+#define QAM_VD_MEASUREMENT_PERIOD_PERIOD__B 0
+#define QAM_VD_MEASUREMENT_PERIOD_PERIOD__W 16
+#define QAM_VD_MEASUREMENT_PERIOD_PERIOD__M 0xFFFF
+#define QAM_VD_MEASUREMENT_PERIOD_PERIOD__PRE 0x8236
+
+#define QAM_VD_MEASUREMENT_PRESCALE__A 0x1460017
+#define QAM_VD_MEASUREMENT_PRESCALE__W 16
+#define QAM_VD_MEASUREMENT_PRESCALE__M 0xFFFF
+#define QAM_VD_MEASUREMENT_PRESCALE__PRE 0x4
+
+#define QAM_VD_MEASUREMENT_PRESCALE_PRESCALE__B 0
+#define QAM_VD_MEASUREMENT_PRESCALE_PRESCALE__W 16
+#define QAM_VD_MEASUREMENT_PRESCALE_PRESCALE__M 0xFFFF
+#define QAM_VD_MEASUREMENT_PRESCALE_PRESCALE__PRE 0x4
+
+#define QAM_VD_DELTA_PATH_METRIC__A 0x1460018
+#define QAM_VD_DELTA_PATH_METRIC__W 16
+#define QAM_VD_DELTA_PATH_METRIC__M 0xFFFF
+#define QAM_VD_DELTA_PATH_METRIC__PRE 0xFFFF
+
+#define QAM_VD_DELTA_PATH_METRIC_FIXED_MANT__B 0
+#define QAM_VD_DELTA_PATH_METRIC_FIXED_MANT__W 12
+#define QAM_VD_DELTA_PATH_METRIC_FIXED_MANT__M 0xFFF
+#define QAM_VD_DELTA_PATH_METRIC_FIXED_MANT__PRE 0xFFF
+
+#define QAM_VD_DELTA_PATH_METRIC_EXP__B 12
+#define QAM_VD_DELTA_PATH_METRIC_EXP__W 4
+#define QAM_VD_DELTA_PATH_METRIC_EXP__M 0xF000
+#define QAM_VD_DELTA_PATH_METRIC_EXP__PRE 0xF000
+
+#define QAM_VD_NR_QSYM_ERRORS__A 0x1460019
+#define QAM_VD_NR_QSYM_ERRORS__W 16
+#define QAM_VD_NR_QSYM_ERRORS__M 0xFFFF
+#define QAM_VD_NR_QSYM_ERRORS__PRE 0xFFFF
+
+#define QAM_VD_NR_QSYM_ERRORS_FIXED_MANT__B 0
+#define QAM_VD_NR_QSYM_ERRORS_FIXED_MANT__W 12
+#define QAM_VD_NR_QSYM_ERRORS_FIXED_MANT__M 0xFFF
+#define QAM_VD_NR_QSYM_ERRORS_FIXED_MANT__PRE 0xFFF
+
+#define QAM_VD_NR_QSYM_ERRORS_EXP__B 12
+#define QAM_VD_NR_QSYM_ERRORS_EXP__W 4
+#define QAM_VD_NR_QSYM_ERRORS_EXP__M 0xF000
+#define QAM_VD_NR_QSYM_ERRORS_EXP__PRE 0xF000
+
+#define QAM_VD_NR_SYMBOL_ERRORS__A 0x146001A
+#define QAM_VD_NR_SYMBOL_ERRORS__W 16
+#define QAM_VD_NR_SYMBOL_ERRORS__M 0xFFFF
+#define QAM_VD_NR_SYMBOL_ERRORS__PRE 0xFFFF
+
+#define QAM_VD_NR_SYMBOL_ERRORS_FIXED_MANT__B 0
+#define QAM_VD_NR_SYMBOL_ERRORS_FIXED_MANT__W 12
+#define QAM_VD_NR_SYMBOL_ERRORS_FIXED_MANT__M 0xFFF
+#define QAM_VD_NR_SYMBOL_ERRORS_FIXED_MANT__PRE 0xFFF
+
+#define QAM_VD_NR_SYMBOL_ERRORS_EXP__B 12
+#define QAM_VD_NR_SYMBOL_ERRORS_EXP__W 4
+#define QAM_VD_NR_SYMBOL_ERRORS_EXP__M 0xF000
+#define QAM_VD_NR_SYMBOL_ERRORS_EXP__PRE 0xF000
+
+#define QAM_VD_RELOCK_COUNT__A 0x146001B
+#define QAM_VD_RELOCK_COUNT__W 16
+#define QAM_VD_RELOCK_COUNT__M 0xFFFF
+#define QAM_VD_RELOCK_COUNT__PRE 0x0
+
+#define QAM_VD_RELOCK_COUNT_COUNT__B 0
+#define QAM_VD_RELOCK_COUNT_COUNT__W 8
+#define QAM_VD_RELOCK_COUNT_COUNT__M 0xFF
+#define QAM_VD_RELOCK_COUNT_COUNT__PRE 0x0
+
+#define QAM_SY_COMM_EXEC__A 0x1470000
+#define QAM_SY_COMM_EXEC__W 2
+#define QAM_SY_COMM_EXEC__M 0x3
+#define QAM_SY_COMM_EXEC__PRE 0x0
+#define QAM_SY_COMM_EXEC_STOP 0x0
+#define QAM_SY_COMM_EXEC_ACTIVE 0x1
+#define QAM_SY_COMM_EXEC_HOLD 0x2
+
+#define QAM_SY_COMM_MB__A 0x1470002
+#define QAM_SY_COMM_MB__W 2
+#define QAM_SY_COMM_MB__M 0x3
+#define QAM_SY_COMM_MB__PRE 0x0
+#define QAM_SY_COMM_MB_CTL__B 0
+#define QAM_SY_COMM_MB_CTL__W 1
+#define QAM_SY_COMM_MB_CTL__M 0x1
+#define QAM_SY_COMM_MB_CTL__PRE 0x0
+#define QAM_SY_COMM_MB_CTL_OFF 0x0
+#define QAM_SY_COMM_MB_CTL_ON 0x1
+#define QAM_SY_COMM_MB_OBS__B 1
+#define QAM_SY_COMM_MB_OBS__W 1
+#define QAM_SY_COMM_MB_OBS__M 0x2
+#define QAM_SY_COMM_MB_OBS__PRE 0x0
+#define QAM_SY_COMM_MB_OBS_OFF 0x0
+#define QAM_SY_COMM_MB_OBS_ON 0x2
+
+#define QAM_SY_COMM_INT_REQ__A 0x1470003
+#define QAM_SY_COMM_INT_REQ__W 1
+#define QAM_SY_COMM_INT_REQ__M 0x1
+#define QAM_SY_COMM_INT_REQ__PRE 0x0
+#define QAM_SY_COMM_INT_STA__A 0x1470005
+#define QAM_SY_COMM_INT_STA__W 4
+#define QAM_SY_COMM_INT_STA__M 0xF
+#define QAM_SY_COMM_INT_STA__PRE 0x0
+
+#define QAM_SY_COMM_INT_STA_LOCK_INT__B 0
+#define QAM_SY_COMM_INT_STA_LOCK_INT__W 1
+#define QAM_SY_COMM_INT_STA_LOCK_INT__M 0x1
+#define QAM_SY_COMM_INT_STA_LOCK_INT__PRE 0x0
+
+#define QAM_SY_COMM_INT_STA_UNLOCK_INT__B 1
+#define QAM_SY_COMM_INT_STA_UNLOCK_INT__W 1
+#define QAM_SY_COMM_INT_STA_UNLOCK_INT__M 0x2
+#define QAM_SY_COMM_INT_STA_UNLOCK_INT__PRE 0x0
+
+#define QAM_SY_COMM_INT_STA_TIMEOUT_INT__B 2
+#define QAM_SY_COMM_INT_STA_TIMEOUT_INT__W 1
+#define QAM_SY_COMM_INT_STA_TIMEOUT_INT__M 0x4
+#define QAM_SY_COMM_INT_STA_TIMEOUT_INT__PRE 0x0
+
+#define QAM_SY_COMM_INT_STA_CTL_WORD_INT__B 3
+#define QAM_SY_COMM_INT_STA_CTL_WORD_INT__W 1
+#define QAM_SY_COMM_INT_STA_CTL_WORD_INT__M 0x8
+#define QAM_SY_COMM_INT_STA_CTL_WORD_INT__PRE 0x0
+
+#define QAM_SY_COMM_INT_MSK__A 0x1470006
+#define QAM_SY_COMM_INT_MSK__W 4
+#define QAM_SY_COMM_INT_MSK__M 0xF
+#define QAM_SY_COMM_INT_MSK__PRE 0x0
+#define QAM_SY_COMM_INT_MSK_LOCK_MSK__B 0
+#define QAM_SY_COMM_INT_MSK_LOCK_MSK__W 1
+#define QAM_SY_COMM_INT_MSK_LOCK_MSK__M 0x1
+#define QAM_SY_COMM_INT_MSK_LOCK_MSK__PRE 0x0
+#define QAM_SY_COMM_INT_MSK_UNLOCK_MSK__B 1
+#define QAM_SY_COMM_INT_MSK_UNLOCK_MSK__W 1
+#define QAM_SY_COMM_INT_MSK_UNLOCK_MSK__M 0x2
+#define QAM_SY_COMM_INT_MSK_UNLOCK_MSK__PRE 0x0
+#define QAM_SY_COMM_INT_MSK_TIMEOUT_MSK__B 2
+#define QAM_SY_COMM_INT_MSK_TIMEOUT_MSK__W 1
+#define QAM_SY_COMM_INT_MSK_TIMEOUT_MSK__M 0x4
+#define QAM_SY_COMM_INT_MSK_TIMEOUT_MSK__PRE 0x0
+#define QAM_SY_COMM_INT_MSK_CTL_WORD_MSK__B 3
+#define QAM_SY_COMM_INT_MSK_CTL_WORD_MSK__W 1
+#define QAM_SY_COMM_INT_MSK_CTL_WORD_MSK__M 0x8
+#define QAM_SY_COMM_INT_MSK_CTL_WORD_MSK__PRE 0x0
+
+#define QAM_SY_COMM_INT_STM__A 0x1470007
+#define QAM_SY_COMM_INT_STM__W 4
+#define QAM_SY_COMM_INT_STM__M 0xF
+#define QAM_SY_COMM_INT_STM__PRE 0x0
+#define QAM_SY_COMM_INT_STM_LOCK_MSK__B 0
+#define QAM_SY_COMM_INT_STM_LOCK_MSK__W 1
+#define QAM_SY_COMM_INT_STM_LOCK_MSK__M 0x1
+#define QAM_SY_COMM_INT_STM_LOCK_MSK__PRE 0x0
+#define QAM_SY_COMM_INT_STM_UNLOCK_MSK__B 1
+#define QAM_SY_COMM_INT_STM_UNLOCK_MSK__W 1
+#define QAM_SY_COMM_INT_STM_UNLOCK_MSK__M 0x2
+#define QAM_SY_COMM_INT_STM_UNLOCK_MSK__PRE 0x0
+#define QAM_SY_COMM_INT_STM_TIMEOUT_MSK__B 2
+#define QAM_SY_COMM_INT_STM_TIMEOUT_MSK__W 1
+#define QAM_SY_COMM_INT_STM_TIMEOUT_MSK__M 0x4
+#define QAM_SY_COMM_INT_STM_TIMEOUT_MSK__PRE 0x0
+#define QAM_SY_COMM_INT_STM_CTL_WORD_MSK__B 3
+#define QAM_SY_COMM_INT_STM_CTL_WORD_MSK__W 1
+#define QAM_SY_COMM_INT_STM_CTL_WORD_MSK__M 0x8
+#define QAM_SY_COMM_INT_STM_CTL_WORD_MSK__PRE 0x0
+
+#define QAM_SY_STATUS__A 0x1470010
+#define QAM_SY_STATUS__W 2
+#define QAM_SY_STATUS__M 0x3
+#define QAM_SY_STATUS__PRE 0x0
+
+#define QAM_SY_STATUS_SYNC_STATE__B 0
+#define QAM_SY_STATUS_SYNC_STATE__W 2
+#define QAM_SY_STATUS_SYNC_STATE__M 0x3
+#define QAM_SY_STATUS_SYNC_STATE__PRE 0x0
+
+#define QAM_SY_TIMEOUT__A 0x1470011
+#define QAM_SY_TIMEOUT__W 16
+#define QAM_SY_TIMEOUT__M 0xFFFF
+#define QAM_SY_TIMEOUT__PRE 0x3A98
+
+#define QAM_SY_SYNC_LWM__A 0x1470012
+#define QAM_SY_SYNC_LWM__W 4
+#define QAM_SY_SYNC_LWM__M 0xF
+#define QAM_SY_SYNC_LWM__PRE 0x2
+
+#define QAM_SY_SYNC_AWM__A 0x1470013
+#define QAM_SY_SYNC_AWM__W 4
+#define QAM_SY_SYNC_AWM__M 0xF
+#define QAM_SY_SYNC_AWM__PRE 0x3
+
+#define QAM_SY_SYNC_HWM__A 0x1470014
+#define QAM_SY_SYNC_HWM__W 4
+#define QAM_SY_SYNC_HWM__M 0xF
+#define QAM_SY_SYNC_HWM__PRE 0x5
+
+#define QAM_SY_UNLOCK__A 0x1470015
+#define QAM_SY_UNLOCK__W 1
+#define QAM_SY_UNLOCK__M 0x1
+#define QAM_SY_UNLOCK__PRE 0x0
+#define QAM_SY_CONTROL_WORD__A 0x1470016
+#define QAM_SY_CONTROL_WORD__W 4
+#define QAM_SY_CONTROL_WORD__M 0xF
+#define QAM_SY_CONTROL_WORD__PRE 0x0
+
+#define QAM_SY_CONTROL_WORD_CTRL_WORD__B 0
+#define QAM_SY_CONTROL_WORD_CTRL_WORD__W 4
+#define QAM_SY_CONTROL_WORD_CTRL_WORD__M 0xF
+#define QAM_SY_CONTROL_WORD_CTRL_WORD__PRE 0x0
+
+#define QAM_VD_ISS_RAM__A 0x1480000
+
+#define QAM_VD_QSS_RAM__A 0x1490000
+
+#define QAM_VD_SYM_RAM__A 0x14A0000
+
+#define SCU_COMM_EXEC__A 0x800000
+#define SCU_COMM_EXEC__W 2
+#define SCU_COMM_EXEC__M 0x3
+#define SCU_COMM_EXEC__PRE 0x0
+#define SCU_COMM_EXEC_STOP 0x0
+#define SCU_COMM_EXEC_ACTIVE 0x1
+#define SCU_COMM_EXEC_HOLD 0x2
+
+#define SCU_COMM_STATE__A 0x800001
+#define SCU_COMM_STATE__W 16
+#define SCU_COMM_STATE__M 0xFFFF
+#define SCU_COMM_STATE__PRE 0x0
+
+#define SCU_COMM_STATE_COMM_STATE__B 0
+#define SCU_COMM_STATE_COMM_STATE__W 16
+#define SCU_COMM_STATE_COMM_STATE__M 0xFFFF
+#define SCU_COMM_STATE_COMM_STATE__PRE 0x0
+
+#define SCU_TOP_COMM_EXEC__A 0x810000
+#define SCU_TOP_COMM_EXEC__W 2
+#define SCU_TOP_COMM_EXEC__M 0x3
+#define SCU_TOP_COMM_EXEC__PRE 0x0
+#define SCU_TOP_COMM_EXEC_STOP 0x0
+#define SCU_TOP_COMM_EXEC_ACTIVE 0x1
+#define SCU_TOP_COMM_EXEC_HOLD 0x2
+
+#define SCU_TOP_COMM_STATE__A 0x810001
+#define SCU_TOP_COMM_STATE__W 16
+#define SCU_TOP_COMM_STATE__M 0xFFFF
+#define SCU_TOP_COMM_STATE__PRE 0x0
+#define SCU_TOP_MWAIT_CTR__A 0x810010
+#define SCU_TOP_MWAIT_CTR__W 2
+#define SCU_TOP_MWAIT_CTR__M 0x3
+#define SCU_TOP_MWAIT_CTR__PRE 0x0
+
+#define SCU_TOP_MWAIT_CTR_MWAIT_SEL__B 0
+#define SCU_TOP_MWAIT_CTR_MWAIT_SEL__W 1
+#define SCU_TOP_MWAIT_CTR_MWAIT_SEL__M 0x1
+#define SCU_TOP_MWAIT_CTR_MWAIT_SEL__PRE 0x0
+#define SCU_TOP_MWAIT_CTR_MWAIT_SEL_TR_MW_OFF 0x0
+#define SCU_TOP_MWAIT_CTR_MWAIT_SEL_TR_MW_ON 0x1
+
+#define SCU_TOP_MWAIT_CTR_READY_DIS__B 1
+#define SCU_TOP_MWAIT_CTR_READY_DIS__W 1
+#define SCU_TOP_MWAIT_CTR_READY_DIS__M 0x2
+#define SCU_TOP_MWAIT_CTR_READY_DIS__PRE 0x0
+#define SCU_TOP_MWAIT_CTR_READY_DIS_NMI_ON 0x0
+#define SCU_TOP_MWAIT_CTR_READY_DIS_NMI_OFF 0x2
+
+#define SCU_LOW_RAM__A 0x820000
+
+#define SCU_LOW_RAM_LOW__B 0
+#define SCU_LOW_RAM_LOW__W 16
+#define SCU_LOW_RAM_LOW__M 0xFFFF
+#define SCU_LOW_RAM_LOW__PRE 0x0
+
+#define SCU_HIGH_RAM__A 0x830000
+
+#define SCU_HIGH_RAM_HIGH__B 0
+#define SCU_HIGH_RAM_HIGH__W 16
+#define SCU_HIGH_RAM_HIGH__M 0xFFFF
+#define SCU_HIGH_RAM_HIGH__PRE 0x0
+
+#define SCU_RAM_AGC_RF_MAX__A 0x831E96
+#define SCU_RAM_AGC_RF_MAX__W 15
+#define SCU_RAM_AGC_RF_MAX__M 0x7FFF
+#define SCU_RAM_AGC_RF_MAX__PRE 0x0
+
+#define SCU_RAM_AGC_FAST_SNS_CTRL_DELAY__A 0x831E97
+#define SCU_RAM_AGC_FAST_SNS_CTRL_DELAY__W 16
+#define SCU_RAM_AGC_FAST_SNS_CTRL_DELAY__M 0xFFFF
+#define SCU_RAM_AGC_FAST_SNS_CTRL_DELAY__PRE 0x0
+
+#define SCU_RAM_AGC_KI_CYCCNT__A 0x831E98
+#define SCU_RAM_AGC_KI_CYCCNT__W 16
+#define SCU_RAM_AGC_KI_CYCCNT__M 0xFFFF
+#define SCU_RAM_AGC_KI_CYCCNT__PRE 0x0
+
+#define SCU_RAM_AGC_KI_CYCLEN__A 0x831E99
+#define SCU_RAM_AGC_KI_CYCLEN__W 16
+#define SCU_RAM_AGC_KI_CYCLEN__M 0xFFFF
+#define SCU_RAM_AGC_KI_CYCLEN__PRE 0x0
+
+#define SCU_RAM_AGC_SNS_CYCLEN__A 0x831E9A
+#define SCU_RAM_AGC_SNS_CYCLEN__W 16
+#define SCU_RAM_AGC_SNS_CYCLEN__M 0xFFFF
+#define SCU_RAM_AGC_SNS_CYCLEN__PRE 0x0
+
+#define SCU_RAM_AGC_RF_SNS_DEV_MAX__A 0x831E9B
+#define SCU_RAM_AGC_RF_SNS_DEV_MAX__W 16
+#define SCU_RAM_AGC_RF_SNS_DEV_MAX__M 0xFFFF
+#define SCU_RAM_AGC_RF_SNS_DEV_MAX__PRE 0x0
+
+#define SCU_RAM_AGC_RF_SNS_DEV_MIN__A 0x831E9C
+#define SCU_RAM_AGC_RF_SNS_DEV_MIN__W 16
+#define SCU_RAM_AGC_RF_SNS_DEV_MIN__M 0xFFFF
+#define SCU_RAM_AGC_RF_SNS_DEV_MIN__PRE 0x0
+#define SCU_RAM_AGC_KI__A 0x831E9D
+#define SCU_RAM_AGC_KI__W 15
+#define SCU_RAM_AGC_KI__M 0x7FFF
+#define SCU_RAM_AGC_KI__PRE 0x0
+
+#define SCU_RAM_AGC_KI_DGAIN__B 0
+#define SCU_RAM_AGC_KI_DGAIN__W 4
+#define SCU_RAM_AGC_KI_DGAIN__M 0xF
+#define SCU_RAM_AGC_KI_DGAIN__PRE 0x0
+
+#define SCU_RAM_AGC_KI_RF__B 4
+#define SCU_RAM_AGC_KI_RF__W 4
+#define SCU_RAM_AGC_KI_RF__M 0xF0
+#define SCU_RAM_AGC_KI_RF__PRE 0x0
+
+#define SCU_RAM_AGC_KI_IF__B 8
+#define SCU_RAM_AGC_KI_IF__W 4
+#define SCU_RAM_AGC_KI_IF__M 0xF00
+#define SCU_RAM_AGC_KI_IF__PRE 0x0
+
+#define SCU_RAM_AGC_KI_IF_AGC_DISABLE__B 12
+#define SCU_RAM_AGC_KI_IF_AGC_DISABLE__W 1
+#define SCU_RAM_AGC_KI_IF_AGC_DISABLE__M 0x1000
+#define SCU_RAM_AGC_KI_IF_AGC_DISABLE__PRE 0x0
+
+#define SCU_RAM_AGC_KI_INV_IF_POL__B 13
+#define SCU_RAM_AGC_KI_INV_IF_POL__W 1
+#define SCU_RAM_AGC_KI_INV_IF_POL__M 0x2000
+#define SCU_RAM_AGC_KI_INV_IF_POL__PRE 0x0
+
+#define SCU_RAM_AGC_KI_INV_RF_POL__B 14
+#define SCU_RAM_AGC_KI_INV_RF_POL__W 1
+#define SCU_RAM_AGC_KI_INV_RF_POL__M 0x4000
+#define SCU_RAM_AGC_KI_INV_RF_POL__PRE 0x0
+
+#define SCU_RAM_AGC_KI_RED__A 0x831E9E
+#define SCU_RAM_AGC_KI_RED__W 6
+#define SCU_RAM_AGC_KI_RED__M 0x3F
+#define SCU_RAM_AGC_KI_RED__PRE 0x0
+
+#define SCU_RAM_AGC_KI_RED_INNER_RED__B 0
+#define SCU_RAM_AGC_KI_RED_INNER_RED__W 2
+#define SCU_RAM_AGC_KI_RED_INNER_RED__M 0x3
+#define SCU_RAM_AGC_KI_RED_INNER_RED__PRE 0x0
+
+#define SCU_RAM_AGC_KI_RED_RAGC_RED__B 2
+#define SCU_RAM_AGC_KI_RED_RAGC_RED__W 2
+#define SCU_RAM_AGC_KI_RED_RAGC_RED__M 0xC
+#define SCU_RAM_AGC_KI_RED_RAGC_RED__PRE 0x0
+
+#define SCU_RAM_AGC_KI_RED_IAGC_RED__B 4
+#define SCU_RAM_AGC_KI_RED_IAGC_RED__W 2
+#define SCU_RAM_AGC_KI_RED_IAGC_RED__M 0x30
+#define SCU_RAM_AGC_KI_RED_IAGC_RED__PRE 0x0
+
+#define SCU_RAM_AGC_KI_INNERGAIN_MIN__A 0x831E9F
+#define SCU_RAM_AGC_KI_INNERGAIN_MIN__W 16
+#define SCU_RAM_AGC_KI_INNERGAIN_MIN__M 0xFFFF
+#define SCU_RAM_AGC_KI_INNERGAIN_MIN__PRE 0x0
+
+#define SCU_RAM_AGC_KI_MINGAIN__A 0x831EA0
+#define SCU_RAM_AGC_KI_MINGAIN__W 16
+#define SCU_RAM_AGC_KI_MINGAIN__M 0xFFFF
+#define SCU_RAM_AGC_KI_MINGAIN__PRE 0x0
+
+#define SCU_RAM_AGC_KI_MAXGAIN__A 0x831EA1
+#define SCU_RAM_AGC_KI_MAXGAIN__W 16
+#define SCU_RAM_AGC_KI_MAXGAIN__M 0xFFFF
+#define SCU_RAM_AGC_KI_MAXGAIN__PRE 0x0
+
+#define SCU_RAM_AGC_KI_MAXMINGAIN_TH__A 0x831EA2
+#define SCU_RAM_AGC_KI_MAXMINGAIN_TH__W 16
+#define SCU_RAM_AGC_KI_MAXMINGAIN_TH__M 0xFFFF
+#define SCU_RAM_AGC_KI_MAXMINGAIN_TH__PRE 0x0
+#define SCU_RAM_AGC_KI_MIN__A 0x831EA3
+#define SCU_RAM_AGC_KI_MIN__W 12
+#define SCU_RAM_AGC_KI_MIN__M 0xFFF
+#define SCU_RAM_AGC_KI_MIN__PRE 0x0
+
+#define SCU_RAM_AGC_KI_MIN_DGAIN__B 0
+#define SCU_RAM_AGC_KI_MIN_DGAIN__W 4
+#define SCU_RAM_AGC_KI_MIN_DGAIN__M 0xF
+#define SCU_RAM_AGC_KI_MIN_DGAIN__PRE 0x0
+
+#define SCU_RAM_AGC_KI_MIN_RF__B 4
+#define SCU_RAM_AGC_KI_MIN_RF__W 4
+#define SCU_RAM_AGC_KI_MIN_RF__M 0xF0
+#define SCU_RAM_AGC_KI_MIN_RF__PRE 0x0
+
+#define SCU_RAM_AGC_KI_MIN_IF__B 8
+#define SCU_RAM_AGC_KI_MIN_IF__W 4
+#define SCU_RAM_AGC_KI_MIN_IF__M 0xF00
+#define SCU_RAM_AGC_KI_MIN_IF__PRE 0x0
+
+#define SCU_RAM_AGC_KI_MAX__A 0x831EA4
+#define SCU_RAM_AGC_KI_MAX__W 12
+#define SCU_RAM_AGC_KI_MAX__M 0xFFF
+#define SCU_RAM_AGC_KI_MAX__PRE 0x0
+
+#define SCU_RAM_AGC_KI_MAX_DGAIN__B 0
+#define SCU_RAM_AGC_KI_MAX_DGAIN__W 4
+#define SCU_RAM_AGC_KI_MAX_DGAIN__M 0xF
+#define SCU_RAM_AGC_KI_MAX_DGAIN__PRE 0x0
+
+#define SCU_RAM_AGC_KI_MAX_RF__B 4
+#define SCU_RAM_AGC_KI_MAX_RF__W 4
+#define SCU_RAM_AGC_KI_MAX_RF__M 0xF0
+#define SCU_RAM_AGC_KI_MAX_RF__PRE 0x0
+
+#define SCU_RAM_AGC_KI_MAX_IF__B 8
+#define SCU_RAM_AGC_KI_MAX_IF__W 4
+#define SCU_RAM_AGC_KI_MAX_IF__M 0xF00
+#define SCU_RAM_AGC_KI_MAX_IF__PRE 0x0
+
+#define SCU_RAM_AGC_CLP_SUM__A 0x831EA5
+#define SCU_RAM_AGC_CLP_SUM__W 16
+#define SCU_RAM_AGC_CLP_SUM__M 0xFFFF
+#define SCU_RAM_AGC_CLP_SUM__PRE 0x0
+
+#define SCU_RAM_AGC_CLP_SUM_MIN__A 0x831EA6
+#define SCU_RAM_AGC_CLP_SUM_MIN__W 16
+#define SCU_RAM_AGC_CLP_SUM_MIN__M 0xFFFF
+#define SCU_RAM_AGC_CLP_SUM_MIN__PRE 0x0
+
+#define SCU_RAM_AGC_CLP_SUM_MAX__A 0x831EA7
+#define SCU_RAM_AGC_CLP_SUM_MAX__W 16
+#define SCU_RAM_AGC_CLP_SUM_MAX__M 0xFFFF
+#define SCU_RAM_AGC_CLP_SUM_MAX__PRE 0x0
+
+#define SCU_RAM_AGC_CLP_CYCLEN__A 0x831EA8
+#define SCU_RAM_AGC_CLP_CYCLEN__W 16
+#define SCU_RAM_AGC_CLP_CYCLEN__M 0xFFFF
+#define SCU_RAM_AGC_CLP_CYCLEN__PRE 0x0
+
+#define SCU_RAM_AGC_CLP_CYCCNT__A 0x831EA9
+#define SCU_RAM_AGC_CLP_CYCCNT__W 16
+#define SCU_RAM_AGC_CLP_CYCCNT__M 0xFFFF
+#define SCU_RAM_AGC_CLP_CYCCNT__PRE 0x0
+
+#define SCU_RAM_AGC_CLP_DIR_TO__A 0x831EAA
+#define SCU_RAM_AGC_CLP_DIR_TO__W 8
+#define SCU_RAM_AGC_CLP_DIR_TO__M 0xFF
+#define SCU_RAM_AGC_CLP_DIR_TO__PRE 0x0
+
+#define SCU_RAM_AGC_CLP_DIR_WD__A 0x831EAB
+#define SCU_RAM_AGC_CLP_DIR_WD__W 8
+#define SCU_RAM_AGC_CLP_DIR_WD__M 0xFF
+#define SCU_RAM_AGC_CLP_DIR_WD__PRE 0x0
+
+#define SCU_RAM_AGC_CLP_DIR_STP__A 0x831EAC
+#define SCU_RAM_AGC_CLP_DIR_STP__W 16
+#define SCU_RAM_AGC_CLP_DIR_STP__M 0xFFFF
+#define SCU_RAM_AGC_CLP_DIR_STP__PRE 0x0
+
+#define SCU_RAM_AGC_SNS_SUM__A 0x831EAD
+#define SCU_RAM_AGC_SNS_SUM__W 16
+#define SCU_RAM_AGC_SNS_SUM__M 0xFFFF
+#define SCU_RAM_AGC_SNS_SUM__PRE 0x0
+
+#define SCU_RAM_AGC_SNS_SUM_MIN__A 0x831EAE
+#define SCU_RAM_AGC_SNS_SUM_MIN__W 16
+#define SCU_RAM_AGC_SNS_SUM_MIN__M 0xFFFF
+#define SCU_RAM_AGC_SNS_SUM_MIN__PRE 0x0
+
+#define SCU_RAM_AGC_SNS_SUM_MAX__A 0x831EAF
+#define SCU_RAM_AGC_SNS_SUM_MAX__W 16
+#define SCU_RAM_AGC_SNS_SUM_MAX__M 0xFFFF
+#define SCU_RAM_AGC_SNS_SUM_MAX__PRE 0x0
+
+#define SCU_RAM_AGC_SNS_CYCCNT__A 0x831EB0
+#define SCU_RAM_AGC_SNS_CYCCNT__W 16
+#define SCU_RAM_AGC_SNS_CYCCNT__M 0xFFFF
+#define SCU_RAM_AGC_SNS_CYCCNT__PRE 0x0
+
+#define SCU_RAM_AGC_SNS_DIR_TO__A 0x831EB1
+#define SCU_RAM_AGC_SNS_DIR_TO__W 8
+#define SCU_RAM_AGC_SNS_DIR_TO__M 0xFF
+#define SCU_RAM_AGC_SNS_DIR_TO__PRE 0x0
+
+#define SCU_RAM_AGC_SNS_DIR_WD__A 0x831EB2
+#define SCU_RAM_AGC_SNS_DIR_WD__W 8
+#define SCU_RAM_AGC_SNS_DIR_WD__M 0xFF
+#define SCU_RAM_AGC_SNS_DIR_WD__PRE 0x0
+
+#define SCU_RAM_AGC_SNS_DIR_STP__A 0x831EB3
+#define SCU_RAM_AGC_SNS_DIR_STP__W 16
+#define SCU_RAM_AGC_SNS_DIR_STP__M 0xFFFF
+#define SCU_RAM_AGC_SNS_DIR_STP__PRE 0x0
+
+#define SCU_RAM_AGC_INGAIN__A 0x831EB4
+#define SCU_RAM_AGC_INGAIN__W 16
+#define SCU_RAM_AGC_INGAIN__M 0xFFFF
+#define SCU_RAM_AGC_INGAIN__PRE 0x0
+
+#define SCU_RAM_AGC_INGAIN_TGT__A 0x831EB5
+#define SCU_RAM_AGC_INGAIN_TGT__W 15
+#define SCU_RAM_AGC_INGAIN_TGT__M 0x7FFF
+#define SCU_RAM_AGC_INGAIN_TGT__PRE 0x0
+
+#define SCU_RAM_AGC_INGAIN_TGT_MIN__A 0x831EB6
+#define SCU_RAM_AGC_INGAIN_TGT_MIN__W 15
+#define SCU_RAM_AGC_INGAIN_TGT_MIN__M 0x7FFF
+#define SCU_RAM_AGC_INGAIN_TGT_MIN__PRE 0x0
+
+#define SCU_RAM_AGC_INGAIN_TGT_MAX__A 0x831EB7
+#define SCU_RAM_AGC_INGAIN_TGT_MAX__W 15
+#define SCU_RAM_AGC_INGAIN_TGT_MAX__M 0x7FFF
+#define SCU_RAM_AGC_INGAIN_TGT_MAX__PRE 0x0
+
+#define SCU_RAM_AGC_IF_IACCU_HI__A 0x831EB8
+#define SCU_RAM_AGC_IF_IACCU_HI__W 16
+#define SCU_RAM_AGC_IF_IACCU_HI__M 0xFFFF
+#define SCU_RAM_AGC_IF_IACCU_HI__PRE 0x0
+
+#define SCU_RAM_AGC_IF_IACCU_LO__A 0x831EB9
+#define SCU_RAM_AGC_IF_IACCU_LO__W 8
+#define SCU_RAM_AGC_IF_IACCU_LO__M 0xFF
+#define SCU_RAM_AGC_IF_IACCU_LO__PRE 0x0
+
+#define SCU_RAM_AGC_IF_IACCU_HI_TGT__A 0x831EBA
+#define SCU_RAM_AGC_IF_IACCU_HI_TGT__W 15
+#define SCU_RAM_AGC_IF_IACCU_HI_TGT__M 0x7FFF
+#define SCU_RAM_AGC_IF_IACCU_HI_TGT__PRE 0x0
+
+#define SCU_RAM_AGC_IF_IACCU_HI_TGT_MIN__A 0x831EBB
+#define SCU_RAM_AGC_IF_IACCU_HI_TGT_MIN__W 15
+#define SCU_RAM_AGC_IF_IACCU_HI_TGT_MIN__M 0x7FFF
+#define SCU_RAM_AGC_IF_IACCU_HI_TGT_MIN__PRE 0x0
+
+#define SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A 0x831EBC
+#define SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__W 15
+#define SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__M 0x7FFF
+#define SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__PRE 0x0
+
+#define SCU_RAM_AGC_RF_IACCU_HI__A 0x831EBD
+#define SCU_RAM_AGC_RF_IACCU_HI__W 16
+#define SCU_RAM_AGC_RF_IACCU_HI__M 0xFFFF
+#define SCU_RAM_AGC_RF_IACCU_HI__PRE 0x0
+
+#define SCU_RAM_AGC_RF_IACCU_LO__A 0x831EBE
+#define SCU_RAM_AGC_RF_IACCU_LO__W 8
+#define SCU_RAM_AGC_RF_IACCU_LO__M 0xFF
+#define SCU_RAM_AGC_RF_IACCU_LO__PRE 0x0
+
+#define SCU_RAM_AGC_RF_IACCU_HI_CO__A 0x831EBF
+#define SCU_RAM_AGC_RF_IACCU_HI_CO__W 16
+#define SCU_RAM_AGC_RF_IACCU_HI_CO__M 0xFFFF
+#define SCU_RAM_AGC_RF_IACCU_HI_CO__PRE 0x0
+
+#define SCU_RAM_SP__A 0x831EC0
+#define SCU_RAM_SP__W 16
+#define SCU_RAM_SP__M 0xFFFF
+#define SCU_RAM_SP__PRE 0x0
+
+#define SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A 0x831EC1
+#define SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__W 16
+#define SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__M 0xFFFF
+#define SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__PRE 0x0
+
+#define SCU_RAM_AGC_KI_MIN_IFGAIN__A 0x831EC2
+#define SCU_RAM_AGC_KI_MIN_IFGAIN__W 16
+#define SCU_RAM_AGC_KI_MIN_IFGAIN__M 0xFFFF
+#define SCU_RAM_AGC_KI_MIN_IFGAIN__PRE 0x0
+
+#define SCU_RAM_AGC_KI_MAX_IFGAIN__A 0x831EC3
+#define SCU_RAM_AGC_KI_MAX_IFGAIN__W 16
+#define SCU_RAM_AGC_KI_MAX_IFGAIN__M 0xFFFF
+#define SCU_RAM_AGC_KI_MAX_IFGAIN__PRE 0x0
+
+#define SCU_RAM_FEC_MEAS_COUNT__A 0x831EC4
+#define SCU_RAM_FEC_MEAS_COUNT__W 16
+#define SCU_RAM_FEC_MEAS_COUNT__M 0xFFFF
+#define SCU_RAM_FEC_MEAS_COUNT__PRE 0x0
+
+#define SCU_RAM_FEC_ACCUM_CW_CORRECTED_LO__A 0x831EC5
+#define SCU_RAM_FEC_ACCUM_CW_CORRECTED_LO__W 16
+#define SCU_RAM_FEC_ACCUM_CW_CORRECTED_LO__M 0xFFFF
+#define SCU_RAM_FEC_ACCUM_CW_CORRECTED_LO__PRE 0x0
+
+#define SCU_RAM_FEC_ACCUM_CW_CORRECTED_HI__A 0x831EC6
+#define SCU_RAM_FEC_ACCUM_CW_CORRECTED_HI__W 16
+#define SCU_RAM_FEC_ACCUM_CW_CORRECTED_HI__M 0xFFFF
+#define SCU_RAM_FEC_ACCUM_CW_CORRECTED_HI__PRE 0x0
+#define SCU_RAM_GPIO__A 0x831EC7
+#define SCU_RAM_GPIO__W 1
+#define SCU_RAM_GPIO__M 0x1
+#define SCU_RAM_GPIO__PRE 0x0
+
+#define SCU_RAM_GPIO_HW_LOCK_IND__B 0
+#define SCU_RAM_GPIO_HW_LOCK_IND__W 1
+#define SCU_RAM_GPIO_HW_LOCK_IND__M 0x1
+#define SCU_RAM_GPIO_HW_LOCK_IND__PRE 0x0
+#define SCU_RAM_GPIO_HW_LOCK_IND_DISABLE 0x0
+#define SCU_RAM_GPIO_HW_LOCK_IND_ENABLE 0x1
+
+#define SCU_RAM_AGC_CLP_CTRL_MODE__A 0x831EC8
+#define SCU_RAM_AGC_CLP_CTRL_MODE__W 8
+#define SCU_RAM_AGC_CLP_CTRL_MODE__M 0xFF
+#define SCU_RAM_AGC_CLP_CTRL_MODE__PRE 0x0
+
+#define SCU_RAM_AGC_CLP_CTRL_MODE_NARROW_POW__B 0
+#define SCU_RAM_AGC_CLP_CTRL_MODE_NARROW_POW__W 1
+#define SCU_RAM_AGC_CLP_CTRL_MODE_NARROW_POW__M 0x1
+#define SCU_RAM_AGC_CLP_CTRL_MODE_NARROW_POW__PRE 0x0
+#define SCU_RAM_AGC_CLP_CTRL_MODE_NARROW_POW_false 0x0
+#define SCU_RAM_AGC_CLP_CTRL_MODE_NARROW_POW_true 0x1
+
+#define SCU_RAM_AGC_CLP_CTRL_MODE_FAST_CLP_BP__B 1
+#define SCU_RAM_AGC_CLP_CTRL_MODE_FAST_CLP_BP__W 1
+#define SCU_RAM_AGC_CLP_CTRL_MODE_FAST_CLP_BP__M 0x2
+#define SCU_RAM_AGC_CLP_CTRL_MODE_FAST_CLP_BP__PRE 0x0
+#define SCU_RAM_AGC_CLP_CTRL_MODE_FAST_CLP_BP_FCC_ENABLE 0x0
+#define SCU_RAM_AGC_CLP_CTRL_MODE_FAST_CLP_BP_FCC_DISABLE 0x2
+
+#define SCU_RAM_AGC_CLP_CTRL_MODE_FAST_CLP_DEC__B 2
+#define SCU_RAM_AGC_CLP_CTRL_MODE_FAST_CLP_DEC__W 1
+#define SCU_RAM_AGC_CLP_CTRL_MODE_FAST_CLP_DEC__M 0x4
+#define SCU_RAM_AGC_CLP_CTRL_MODE_FAST_CLP_DEC__PRE 0x0
+#define SCU_RAM_AGC_CLP_CTRL_MODE_FAST_CLP_DEC_DEC_DISABLE 0x0
+#define SCU_RAM_AGC_CLP_CTRL_MODE_FAST_CLP_DEC_DEC_ENABLE 0x4
+
+#define SCU_RAM_AGC_KI_MIN_RFGAIN__A 0x831EC9
+#define SCU_RAM_AGC_KI_MIN_RFGAIN__W 16
+#define SCU_RAM_AGC_KI_MIN_RFGAIN__M 0xFFFF
+#define SCU_RAM_AGC_KI_MIN_RFGAIN__PRE 0x0
+
+#define SCU_RAM_AGC_KI_MAX_RFGAIN__A 0x831ECA
+#define SCU_RAM_AGC_KI_MAX_RFGAIN__W 16
+#define SCU_RAM_AGC_KI_MAX_RFGAIN__M 0xFFFF
+#define SCU_RAM_AGC_KI_MAX_RFGAIN__PRE 0x0
+
+#define SCU_RAM_FEC_ACCUM_PKT_FAILURES__A 0x831ECB
+#define SCU_RAM_FEC_ACCUM_PKT_FAILURES__W 16
+#define SCU_RAM_FEC_ACCUM_PKT_FAILURES__M 0xFFFF
+#define SCU_RAM_FEC_ACCUM_PKT_FAILURES__PRE 0x0
+
+#define SCU_RAM_INHIBIT_1__A 0x831ECC
+#define SCU_RAM_INHIBIT_1__W 16
+#define SCU_RAM_INHIBIT_1__M 0xFFFF
+#define SCU_RAM_INHIBIT_1__PRE 0x0
+
+#define SCU_RAM_HTOL_BUF_0__A 0x831ECD
+#define SCU_RAM_HTOL_BUF_0__W 16
+#define SCU_RAM_HTOL_BUF_0__M 0xFFFF
+#define SCU_RAM_HTOL_BUF_0__PRE 0x0
+
+#define SCU_RAM_HTOL_BUF_1__A 0x831ECE
+#define SCU_RAM_HTOL_BUF_1__W 16
+#define SCU_RAM_HTOL_BUF_1__M 0xFFFF
+#define SCU_RAM_HTOL_BUF_1__PRE 0x0
+
+#define SCU_RAM_INHIBIT_2__A 0x831ECF
+#define SCU_RAM_INHIBIT_2__W 16
+#define SCU_RAM_INHIBIT_2__M 0xFFFF
+#define SCU_RAM_INHIBIT_2__PRE 0x0
+
+#define SCU_RAM_TR_SHORT_BUF_0__A 0x831ED0
+#define SCU_RAM_TR_SHORT_BUF_0__W 16
+#define SCU_RAM_TR_SHORT_BUF_0__M 0xFFFF
+#define SCU_RAM_TR_SHORT_BUF_0__PRE 0x0
+
+#define SCU_RAM_TR_SHORT_BUF_1__A 0x831ED1
+#define SCU_RAM_TR_SHORT_BUF_1__W 16
+#define SCU_RAM_TR_SHORT_BUF_1__M 0xFFFF
+#define SCU_RAM_TR_SHORT_BUF_1__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_0__A 0x831ED2
+#define SCU_RAM_TR_LONG_BUF_0__W 16
+#define SCU_RAM_TR_LONG_BUF_0__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_0__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_1__A 0x831ED3
+#define SCU_RAM_TR_LONG_BUF_1__W 16
+#define SCU_RAM_TR_LONG_BUF_1__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_1__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_2__A 0x831ED4
+#define SCU_RAM_TR_LONG_BUF_2__W 16
+#define SCU_RAM_TR_LONG_BUF_2__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_2__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_3__A 0x831ED5
+#define SCU_RAM_TR_LONG_BUF_3__W 16
+#define SCU_RAM_TR_LONG_BUF_3__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_3__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_4__A 0x831ED6
+#define SCU_RAM_TR_LONG_BUF_4__W 16
+#define SCU_RAM_TR_LONG_BUF_4__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_4__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_5__A 0x831ED7
+#define SCU_RAM_TR_LONG_BUF_5__W 16
+#define SCU_RAM_TR_LONG_BUF_5__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_5__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_6__A 0x831ED8
+#define SCU_RAM_TR_LONG_BUF_6__W 16
+#define SCU_RAM_TR_LONG_BUF_6__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_6__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_7__A 0x831ED9
+#define SCU_RAM_TR_LONG_BUF_7__W 16
+#define SCU_RAM_TR_LONG_BUF_7__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_7__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_8__A 0x831EDA
+#define SCU_RAM_TR_LONG_BUF_8__W 16
+#define SCU_RAM_TR_LONG_BUF_8__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_8__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_9__A 0x831EDB
+#define SCU_RAM_TR_LONG_BUF_9__W 16
+#define SCU_RAM_TR_LONG_BUF_9__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_9__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_10__A 0x831EDC
+#define SCU_RAM_TR_LONG_BUF_10__W 16
+#define SCU_RAM_TR_LONG_BUF_10__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_10__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_11__A 0x831EDD
+#define SCU_RAM_TR_LONG_BUF_11__W 16
+#define SCU_RAM_TR_LONG_BUF_11__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_11__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_12__A 0x831EDE
+#define SCU_RAM_TR_LONG_BUF_12__W 16
+#define SCU_RAM_TR_LONG_BUF_12__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_12__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_13__A 0x831EDF
+#define SCU_RAM_TR_LONG_BUF_13__W 16
+#define SCU_RAM_TR_LONG_BUF_13__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_13__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_14__A 0x831EE0
+#define SCU_RAM_TR_LONG_BUF_14__W 16
+#define SCU_RAM_TR_LONG_BUF_14__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_14__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_15__A 0x831EE1
+#define SCU_RAM_TR_LONG_BUF_15__W 16
+#define SCU_RAM_TR_LONG_BUF_15__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_15__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_16__A 0x831EE2
+#define SCU_RAM_TR_LONG_BUF_16__W 16
+#define SCU_RAM_TR_LONG_BUF_16__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_16__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_17__A 0x831EE3
+#define SCU_RAM_TR_LONG_BUF_17__W 16
+#define SCU_RAM_TR_LONG_BUF_17__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_17__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_18__A 0x831EE4
+#define SCU_RAM_TR_LONG_BUF_18__W 16
+#define SCU_RAM_TR_LONG_BUF_18__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_18__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_19__A 0x831EE5
+#define SCU_RAM_TR_LONG_BUF_19__W 16
+#define SCU_RAM_TR_LONG_BUF_19__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_19__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_20__A 0x831EE6
+#define SCU_RAM_TR_LONG_BUF_20__W 16
+#define SCU_RAM_TR_LONG_BUF_20__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_20__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_21__A 0x831EE7
+#define SCU_RAM_TR_LONG_BUF_21__W 16
+#define SCU_RAM_TR_LONG_BUF_21__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_21__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_22__A 0x831EE8
+#define SCU_RAM_TR_LONG_BUF_22__W 16
+#define SCU_RAM_TR_LONG_BUF_22__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_22__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_23__A 0x831EE9
+#define SCU_RAM_TR_LONG_BUF_23__W 16
+#define SCU_RAM_TR_LONG_BUF_23__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_23__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_24__A 0x831EEA
+#define SCU_RAM_TR_LONG_BUF_24__W 16
+#define SCU_RAM_TR_LONG_BUF_24__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_24__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_25__A 0x831EEB
+#define SCU_RAM_TR_LONG_BUF_25__W 16
+#define SCU_RAM_TR_LONG_BUF_25__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_25__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_26__A 0x831EEC
+#define SCU_RAM_TR_LONG_BUF_26__W 16
+#define SCU_RAM_TR_LONG_BUF_26__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_26__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_27__A 0x831EED
+#define SCU_RAM_TR_LONG_BUF_27__W 16
+#define SCU_RAM_TR_LONG_BUF_27__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_27__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_28__A 0x831EEE
+#define SCU_RAM_TR_LONG_BUF_28__W 16
+#define SCU_RAM_TR_LONG_BUF_28__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_28__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_29__A 0x831EEF
+#define SCU_RAM_TR_LONG_BUF_29__W 16
+#define SCU_RAM_TR_LONG_BUF_29__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_29__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_30__A 0x831EF0
+#define SCU_RAM_TR_LONG_BUF_30__W 16
+#define SCU_RAM_TR_LONG_BUF_30__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_30__PRE 0x0
+
+#define SCU_RAM_TR_LONG_BUF_31__A 0x831EF1
+#define SCU_RAM_TR_LONG_BUF_31__W 16
+#define SCU_RAM_TR_LONG_BUF_31__M 0xFFFF
+#define SCU_RAM_TR_LONG_BUF_31__PRE 0x0
+#define SCU_RAM_ATV_AMS_MAX__A 0x831EF2
+#define SCU_RAM_ATV_AMS_MAX__W 11
+#define SCU_RAM_ATV_AMS_MAX__M 0x7FF
+#define SCU_RAM_ATV_AMS_MAX__PRE 0x0
+
+#define SCU_RAM_ATV_AMS_MAX_AMS_MAX__B 0
+#define SCU_RAM_ATV_AMS_MAX_AMS_MAX__W 11
+#define SCU_RAM_ATV_AMS_MAX_AMS_MAX__M 0x7FF
+#define SCU_RAM_ATV_AMS_MAX_AMS_MAX__PRE 0x0
+
+#define SCU_RAM_ATV_AMS_MIN__A 0x831EF3
+#define SCU_RAM_ATV_AMS_MIN__W 11
+#define SCU_RAM_ATV_AMS_MIN__M 0x7FF
+#define SCU_RAM_ATV_AMS_MIN__PRE 0x0
+
+#define SCU_RAM_ATV_AMS_MIN_AMS_MIN__B 0
+#define SCU_RAM_ATV_AMS_MIN_AMS_MIN__W 11
+#define SCU_RAM_ATV_AMS_MIN_AMS_MIN__M 0x7FF
+#define SCU_RAM_ATV_AMS_MIN_AMS_MIN__PRE 0x0
+
+#define SCU_RAM_ATV_FIELD_CNT__A 0x831EF4
+#define SCU_RAM_ATV_FIELD_CNT__W 9
+#define SCU_RAM_ATV_FIELD_CNT__M 0x1FF
+#define SCU_RAM_ATV_FIELD_CNT__PRE 0x0
+
+#define SCU_RAM_ATV_FIELD_CNT_FIELD_CNT__B 0
+#define SCU_RAM_ATV_FIELD_CNT_FIELD_CNT__W 9
+#define SCU_RAM_ATV_FIELD_CNT_FIELD_CNT__M 0x1FF
+#define SCU_RAM_ATV_FIELD_CNT_FIELD_CNT__PRE 0x0
+
+#define SCU_RAM_ATV_AAGC_FAST__A 0x831EF5
+#define SCU_RAM_ATV_AAGC_FAST__W 1
+#define SCU_RAM_ATV_AAGC_FAST__M 0x1
+#define SCU_RAM_ATV_AAGC_FAST__PRE 0x0
+
+#define SCU_RAM_ATV_AAGC_FAST_AAGC_FAST__B 0
+#define SCU_RAM_ATV_AAGC_FAST_AAGC_FAST__W 1
+#define SCU_RAM_ATV_AAGC_FAST_AAGC_FAST__M 0x1
+#define SCU_RAM_ATV_AAGC_FAST_AAGC_FAST__PRE 0x0
+#define SCU_RAM_ATV_AAGC_FAST_AAGC_FAST_OFF 0x0
+#define SCU_RAM_ATV_AAGC_FAST_AAGC_FAST_ON 0x1
+
+#define SCU_RAM_ATV_AAGC_LP2__A 0x831EF6
+#define SCU_RAM_ATV_AAGC_LP2__W 16
+#define SCU_RAM_ATV_AAGC_LP2__M 0xFFFF
+#define SCU_RAM_ATV_AAGC_LP2__PRE 0x0
+
+#define SCU_RAM_ATV_AAGC_LP2_AAGC_LP2__B 0
+#define SCU_RAM_ATV_AAGC_LP2_AAGC_LP2__W 16
+#define SCU_RAM_ATV_AAGC_LP2_AAGC_LP2__M 0xFFFF
+#define SCU_RAM_ATV_AAGC_LP2_AAGC_LP2__PRE 0x0
+
+#define SCU_RAM_ATV_BP_LVL__A 0x831EF7
+#define SCU_RAM_ATV_BP_LVL__W 11
+#define SCU_RAM_ATV_BP_LVL__M 0x7FF
+#define SCU_RAM_ATV_BP_LVL__PRE 0x0
+
+#define SCU_RAM_ATV_BP_LVL_BP_LVL__B 0
+#define SCU_RAM_ATV_BP_LVL_BP_LVL__W 11
+#define SCU_RAM_ATV_BP_LVL_BP_LVL__M 0x7FF
+#define SCU_RAM_ATV_BP_LVL_BP_LVL__PRE 0x0
+
+#define SCU_RAM_ATV_BP_RELY__A 0x831EF8
+#define SCU_RAM_ATV_BP_RELY__W 8
+#define SCU_RAM_ATV_BP_RELY__M 0xFF
+#define SCU_RAM_ATV_BP_RELY__PRE 0x0
+
+#define SCU_RAM_ATV_BP_RELY_BP_RELY__B 0
+#define SCU_RAM_ATV_BP_RELY_BP_RELY__W 8
+#define SCU_RAM_ATV_BP_RELY_BP_RELY__M 0xFF
+#define SCU_RAM_ATV_BP_RELY_BP_RELY__PRE 0x0
+
+#define SCU_RAM_ATV_BP_MTA__A 0x831EF9
+#define SCU_RAM_ATV_BP_MTA__W 14
+#define SCU_RAM_ATV_BP_MTA__M 0x3FFF
+#define SCU_RAM_ATV_BP_MTA__PRE 0x0
+
+#define SCU_RAM_ATV_BP_MTA_BP_MTA__B 0
+#define SCU_RAM_ATV_BP_MTA_BP_MTA__W 14
+#define SCU_RAM_ATV_BP_MTA_BP_MTA__M 0x3FFF
+#define SCU_RAM_ATV_BP_MTA_BP_MTA__PRE 0x0
+
+#define SCU_RAM_ATV_BP_REF__A 0x831EFA
+#define SCU_RAM_ATV_BP_REF__W 11
+#define SCU_RAM_ATV_BP_REF__M 0x7FF
+#define SCU_RAM_ATV_BP_REF__PRE 0x0
+
+#define SCU_RAM_ATV_BP_REF_BP_REF__B 0
+#define SCU_RAM_ATV_BP_REF_BP_REF__W 11
+#define SCU_RAM_ATV_BP_REF_BP_REF__M 0x7FF
+#define SCU_RAM_ATV_BP_REF_BP_REF__PRE 0x0
+
+#define SCU_RAM_ATV_BP_REF_MIN__A 0x831EFB
+#define SCU_RAM_ATV_BP_REF_MIN__W 11
+#define SCU_RAM_ATV_BP_REF_MIN__M 0x7FF
+#define SCU_RAM_ATV_BP_REF_MIN__PRE 0x0
+
+#define SCU_RAM_ATV_BP_REF_MIN_BP_REF_MIN__B 0
+#define SCU_RAM_ATV_BP_REF_MIN_BP_REF_MIN__W 11
+#define SCU_RAM_ATV_BP_REF_MIN_BP_REF_MIN__M 0x7FF
+#define SCU_RAM_ATV_BP_REF_MIN_BP_REF_MIN__PRE 0x0
+
+#define SCU_RAM_ATV_BP_REF_MAX__A 0x831EFC
+#define SCU_RAM_ATV_BP_REF_MAX__W 11
+#define SCU_RAM_ATV_BP_REF_MAX__M 0x7FF
+#define SCU_RAM_ATV_BP_REF_MAX__PRE 0x0
+
+#define SCU_RAM_ATV_BP_REF_MAX_BP_REF_MAX__B 0
+#define SCU_RAM_ATV_BP_REF_MAX_BP_REF_MAX__W 11
+#define SCU_RAM_ATV_BP_REF_MAX_BP_REF_MAX__M 0x7FF
+#define SCU_RAM_ATV_BP_REF_MAX_BP_REF_MAX__PRE 0x0
+
+#define SCU_RAM_ATV_BP_CNT__A 0x831EFD
+#define SCU_RAM_ATV_BP_CNT__W 8
+#define SCU_RAM_ATV_BP_CNT__M 0xFF
+#define SCU_RAM_ATV_BP_CNT__PRE 0x0
+
+#define SCU_RAM_ATV_BP_CNT_BP_CNT__B 0
+#define SCU_RAM_ATV_BP_CNT_BP_CNT__W 8
+#define SCU_RAM_ATV_BP_CNT_BP_CNT__M 0xFF
+#define SCU_RAM_ATV_BP_CNT_BP_CNT__PRE 0x0
+
+#define SCU_RAM_ATV_BP_XD_CNT__A 0x831EFE
+#define SCU_RAM_ATV_BP_XD_CNT__W 12
+#define SCU_RAM_ATV_BP_XD_CNT__M 0xFFF
+#define SCU_RAM_ATV_BP_XD_CNT__PRE 0x0
+
+#define SCU_RAM_ATV_BP_XD_CNT_BP_XD_CNT__B 0
+#define SCU_RAM_ATV_BP_XD_CNT_BP_XD_CNT__W 12
+#define SCU_RAM_ATV_BP_XD_CNT_BP_XD_CNT__M 0xFFF
+#define SCU_RAM_ATV_BP_XD_CNT_BP_XD_CNT__PRE 0x0
+
+#define SCU_RAM_ATV_PAGC_KI_MIN__A 0x831EFF
+#define SCU_RAM_ATV_PAGC_KI_MIN__W 12
+#define SCU_RAM_ATV_PAGC_KI_MIN__M 0xFFF
+#define SCU_RAM_ATV_PAGC_KI_MIN__PRE 0x0
+
+#define SCU_RAM_ATV_PAGC_KI_MIN_PAGC_KI_MIN__B 0
+#define SCU_RAM_ATV_PAGC_KI_MIN_PAGC_KI_MIN__W 12
+#define SCU_RAM_ATV_PAGC_KI_MIN_PAGC_KI_MIN__M 0xFFF
+#define SCU_RAM_ATV_PAGC_KI_MIN_PAGC_KI_MIN__PRE 0x0
+
+#define SCU_RAM_ATV_BPC_KI_MIN__A 0x831F00
+#define SCU_RAM_ATV_BPC_KI_MIN__W 12
+#define SCU_RAM_ATV_BPC_KI_MIN__M 0xFFF
+#define SCU_RAM_ATV_BPC_KI_MIN__PRE 0x0
+
+#define SCU_RAM_ATV_BPC_KI_MIN_BPC_KI_MIN__B 0
+#define SCU_RAM_ATV_BPC_KI_MIN_BPC_KI_MIN__W 12
+#define SCU_RAM_ATV_BPC_KI_MIN_BPC_KI_MIN__M 0xFFF
+#define SCU_RAM_ATV_BPC_KI_MIN_BPC_KI_MIN__PRE 0x0
+
+#define SCU_RAM_ORX_RF_RX_FREQUENCY_VALUE__A 0x831F01
+#define SCU_RAM_ORX_RF_RX_FREQUENCY_VALUE__W 16
+#define SCU_RAM_ORX_RF_RX_FREQUENCY_VALUE__M 0xFFFF
+#define SCU_RAM_ORX_RF_RX_FREQUENCY_VALUE__PRE 0x0
+
+#define SCU_RAM_ORX_RF_RX_DATA_RATE__A 0x831F02
+#define SCU_RAM_ORX_RF_RX_DATA_RATE__W 8
+#define SCU_RAM_ORX_RF_RX_DATA_RATE__M 0xFF
+#define SCU_RAM_ORX_RF_RX_DATA_RATE__PRE 0x0
+#define SCU_RAM_ORX_RF_RX_DATA_RATE_2048KBPS_REGSPEC 0x0
+#define SCU_RAM_ORX_RF_RX_DATA_RATE_2048KBPS_INVSPEC 0x1
+#define SCU_RAM_ORX_RF_RX_DATA_RATE_2048KBPS_REGSPEC_ALT 0x40
+#define SCU_RAM_ORX_RF_RX_DATA_RATE_2048KBPS_INVSPEC_ALT 0x41
+#define SCU_RAM_ORX_RF_RX_DATA_RATE_1544KBPS_REGSPEC 0x80
+#define SCU_RAM_ORX_RF_RX_DATA_RATE_1544KBPS_INVSPEC 0x81
+#define SCU_RAM_ORX_RF_RX_DATA_RATE_3088KBPS_REGSPEC 0xC0
+#define SCU_RAM_ORX_RF_RX_DATA_RATE_3088KBPS_INVSPEC 0xC1
+
+#define SCU_RAM_ORX_SCU_STATE__A 0x831F03
+#define SCU_RAM_ORX_SCU_STATE__W 8
+#define SCU_RAM_ORX_SCU_STATE__M 0xFF
+#define SCU_RAM_ORX_SCU_STATE__PRE 0x0
+#define SCU_RAM_ORX_SCU_STATE_RESET 0x0
+#define SCU_RAM_ORX_SCU_STATE_AGN_HUNT 0x1
+#define SCU_RAM_ORX_SCU_STATE_DGN_HUNT 0x2
+#define SCU_RAM_ORX_SCU_STATE_AGC_HUNT 0x3
+#define SCU_RAM_ORX_SCU_STATE_FRQ_HUNT 0x4
+#define SCU_RAM_ORX_SCU_STATE_PHA_HUNT 0x8
+#define SCU_RAM_ORX_SCU_STATE_TIM_HUNT 0x10
+#define SCU_RAM_ORX_SCU_STATE_EQU_HUNT 0x20
+#define SCU_RAM_ORX_SCU_STATE_EQT_HUNT 0x30
+#define SCU_RAM_ORX_SCU_STATE_SYNC 0x40
+
+#define SCU_RAM_ORX_SCU_LOCK__A 0x831F04
+#define SCU_RAM_ORX_SCU_LOCK__W 16
+#define SCU_RAM_ORX_SCU_LOCK__M 0xFFFF
+#define SCU_RAM_ORX_SCU_LOCK__PRE 0x0
+
+#define SCU_RAM_ORX_TARGET_MODE__A 0x831F05
+#define SCU_RAM_ORX_TARGET_MODE__W 2
+#define SCU_RAM_ORX_TARGET_MODE__M 0x3
+#define SCU_RAM_ORX_TARGET_MODE__PRE 0x0
+#define SCU_RAM_ORX_TARGET_MODE_1544KBPS 0x0
+#define SCU_RAM_ORX_TARGET_MODE_3088KBPS 0x1
+#define SCU_RAM_ORX_TARGET_MODE_2048KBPS_SQRT 0x2
+#define SCU_RAM_ORX_TARGET_MODE_2048KBPS_RO 0x3
+
+#define SCU_RAM_ORX_MER_MIN_DB__A 0x831F06
+#define SCU_RAM_ORX_MER_MIN_DB__W 8
+#define SCU_RAM_ORX_MER_MIN_DB__M 0xFF
+#define SCU_RAM_ORX_MER_MIN_DB__PRE 0x0
+
+#define SCU_RAM_ORX_RF_GAIN__A 0x831F07
+#define SCU_RAM_ORX_RF_GAIN__W 16
+#define SCU_RAM_ORX_RF_GAIN__M 0xFFFF
+#define SCU_RAM_ORX_RF_GAIN__PRE 0x0
+
+#define SCU_RAM_ORX_RF_GAIN_MIN__A 0x831F08
+#define SCU_RAM_ORX_RF_GAIN_MIN__W 16
+#define SCU_RAM_ORX_RF_GAIN_MIN__M 0xFFFF
+#define SCU_RAM_ORX_RF_GAIN_MIN__PRE 0x0
+
+#define SCU_RAM_ORX_RF_GAIN_MAX__A 0x831F09
+#define SCU_RAM_ORX_RF_GAIN_MAX__W 16
+#define SCU_RAM_ORX_RF_GAIN_MAX__M 0xFFFF
+#define SCU_RAM_ORX_RF_GAIN_MAX__PRE 0x0
+
+#define SCU_RAM_ORX_IF_GAIN__A 0x831F0A
+#define SCU_RAM_ORX_IF_GAIN__W 16
+#define SCU_RAM_ORX_IF_GAIN__M 0xFFFF
+#define SCU_RAM_ORX_IF_GAIN__PRE 0x0
+
+#define SCU_RAM_ORX_IF_GAIN_MIN__A 0x831F0B
+#define SCU_RAM_ORX_IF_GAIN_MIN__W 16
+#define SCU_RAM_ORX_IF_GAIN_MIN__M 0xFFFF
+#define SCU_RAM_ORX_IF_GAIN_MIN__PRE 0x0
+
+#define SCU_RAM_ORX_IF_GAIN_MAX__A 0x831F0C
+#define SCU_RAM_ORX_IF_GAIN_MAX__W 16
+#define SCU_RAM_ORX_IF_GAIN_MAX__M 0xFFFF
+#define SCU_RAM_ORX_IF_GAIN_MAX__PRE 0x0
+
+#define SCU_RAM_ORX_AGN_HEADR__A 0x831F0D
+#define SCU_RAM_ORX_AGN_HEADR__W 16
+#define SCU_RAM_ORX_AGN_HEADR__M 0xFFFF
+#define SCU_RAM_ORX_AGN_HEADR__PRE 0x0
+
+#define SCU_RAM_ORX_AGN_HEADR_STP__A 0x831F0E
+#define SCU_RAM_ORX_AGN_HEADR_STP__W 8
+#define SCU_RAM_ORX_AGN_HEADR_STP__M 0xFF
+#define SCU_RAM_ORX_AGN_HEADR_STP__PRE 0x0
+
+#define SCU_RAM_ORX_AGN_KI__A 0x831F0F
+#define SCU_RAM_ORX_AGN_KI__W 8
+#define SCU_RAM_ORX_AGN_KI__M 0xFF
+#define SCU_RAM_ORX_AGN_KI__PRE 0x0
+
+#define SCU_RAM_ORX_AGN_LOCK_TH__A 0x831F10
+#define SCU_RAM_ORX_AGN_LOCK_TH__W 16
+#define SCU_RAM_ORX_AGN_LOCK_TH__M 0xFFFF
+#define SCU_RAM_ORX_AGN_LOCK_TH__PRE 0x0
+
+#define SCU_RAM_ORX_AGN_LOCK_WD__A 0x831F11
+#define SCU_RAM_ORX_AGN_LOCK_WD__W 16
+#define SCU_RAM_ORX_AGN_LOCK_WD__M 0xFFFF
+#define SCU_RAM_ORX_AGN_LOCK_WD__PRE 0x0
+
+#define SCU_RAM_ORX_AGN_ONLOCK_TTH__A 0x831F12
+#define SCU_RAM_ORX_AGN_ONLOCK_TTH__W 16
+#define SCU_RAM_ORX_AGN_ONLOCK_TTH__M 0xFFFF
+#define SCU_RAM_ORX_AGN_ONLOCK_TTH__PRE 0x0
+
+#define SCU_RAM_ORX_AGN_UNLOCK_TTH__A 0x831F13
+#define SCU_RAM_ORX_AGN_UNLOCK_TTH__W 16
+#define SCU_RAM_ORX_AGN_UNLOCK_TTH__M 0xFFFF
+#define SCU_RAM_ORX_AGN_UNLOCK_TTH__PRE 0x0
+
+#define SCU_RAM_ORX_AGN_LOCK_TOTH__A 0x831F14
+#define SCU_RAM_ORX_AGN_LOCK_TOTH__W 16
+#define SCU_RAM_ORX_AGN_LOCK_TOTH__M 0xFFFF
+#define SCU_RAM_ORX_AGN_LOCK_TOTH__PRE 0x0
+
+#define SCU_RAM_ORX_AGN_LOCK_MASK__A 0x831F15
+#define SCU_RAM_ORX_AGN_LOCK_MASK__W 8
+#define SCU_RAM_ORX_AGN_LOCK_MASK__M 0xFF
+#define SCU_RAM_ORX_AGN_LOCK_MASK__PRE 0x0
+
+#define SCU_RAM_ORX_DGN__A 0x831F16
+#define SCU_RAM_ORX_DGN__W 16
+#define SCU_RAM_ORX_DGN__M 0xFFFF
+#define SCU_RAM_ORX_DGN__PRE 0x0
+
+#define SCU_RAM_ORX_DGN_MIN__A 0x831F17
+#define SCU_RAM_ORX_DGN_MIN__W 16
+#define SCU_RAM_ORX_DGN_MIN__M 0xFFFF
+#define SCU_RAM_ORX_DGN_MIN__PRE 0x0
+
+#define SCU_RAM_ORX_DGN_MAX__A 0x831F18
+#define SCU_RAM_ORX_DGN_MAX__W 16
+#define SCU_RAM_ORX_DGN_MAX__M 0xFFFF
+#define SCU_RAM_ORX_DGN_MAX__PRE 0x0
+
+#define SCU_RAM_ORX_DGN_AMP__A 0x831F19
+#define SCU_RAM_ORX_DGN_AMP__W 16
+#define SCU_RAM_ORX_DGN_AMP__M 0xFFFF
+#define SCU_RAM_ORX_DGN_AMP__PRE 0x0
+
+#define SCU_RAM_ORX_DGN_AMPTARGET__A 0x831F1A
+#define SCU_RAM_ORX_DGN_AMPTARGET__W 16
+#define SCU_RAM_ORX_DGN_AMPTARGET__M 0xFFFF
+#define SCU_RAM_ORX_DGN_AMPTARGET__PRE 0x0
+
+#define SCU_RAM_ORX_DGN_KI__A 0x831F1B
+#define SCU_RAM_ORX_DGN_KI__W 8
+#define SCU_RAM_ORX_DGN_KI__M 0xFF
+#define SCU_RAM_ORX_DGN_KI__PRE 0x0
+
+#define SCU_RAM_ORX_DGN_LOCK_TH__A 0x831F1C
+#define SCU_RAM_ORX_DGN_LOCK_TH__W 16
+#define SCU_RAM_ORX_DGN_LOCK_TH__M 0xFFFF
+#define SCU_RAM_ORX_DGN_LOCK_TH__PRE 0x0
+
+#define SCU_RAM_ORX_DGN_LOCK_WD__A 0x831F1D
+#define SCU_RAM_ORX_DGN_LOCK_WD__W 16
+#define SCU_RAM_ORX_DGN_LOCK_WD__M 0xFFFF
+#define SCU_RAM_ORX_DGN_LOCK_WD__PRE 0x0
+
+#define SCU_RAM_ORX_DGN_ONLOCK_TTH__A 0x831F1E
+#define SCU_RAM_ORX_DGN_ONLOCK_TTH__W 16
+#define SCU_RAM_ORX_DGN_ONLOCK_TTH__M 0xFFFF
+#define SCU_RAM_ORX_DGN_ONLOCK_TTH__PRE 0x0
+
+#define SCU_RAM_ORX_DGN_UNLOCK_TTH__A 0x831F1F
+#define SCU_RAM_ORX_DGN_UNLOCK_TTH__W 16
+#define SCU_RAM_ORX_DGN_UNLOCK_TTH__M 0xFFFF
+#define SCU_RAM_ORX_DGN_UNLOCK_TTH__PRE 0x0
+
+#define SCU_RAM_ORX_DGN_LOCK_TOTH__A 0x831F20
+#define SCU_RAM_ORX_DGN_LOCK_TOTH__W 16
+#define SCU_RAM_ORX_DGN_LOCK_TOTH__M 0xFFFF
+#define SCU_RAM_ORX_DGN_LOCK_TOTH__PRE 0x0
+
+#define SCU_RAM_ORX_DGN_LOCK_MASK__A 0x831F21
+#define SCU_RAM_ORX_DGN_LOCK_MASK__W 8
+#define SCU_RAM_ORX_DGN_LOCK_MASK__M 0xFF
+#define SCU_RAM_ORX_DGN_LOCK_MASK__PRE 0x0
+
+#define SCU_RAM_ORX_FREQ_GAIN_CORR__A 0x831F22
+#define SCU_RAM_ORX_FREQ_GAIN_CORR__W 8
+#define SCU_RAM_ORX_FREQ_GAIN_CORR__M 0xFF
+#define SCU_RAM_ORX_FREQ_GAIN_CORR__PRE 0x0
+#define SCU_RAM_ORX_FREQ_GAIN_CORR_1544KBPS 0x60
+#define SCU_RAM_ORX_FREQ_GAIN_CORR_2048KBPS 0x80
+#define SCU_RAM_ORX_FREQ_GAIN_CORR_3088KBPS 0xC0
+
+#define SCU_RAM_ORX_FRQ_OFFSET__A 0x831F23
+#define SCU_RAM_ORX_FRQ_OFFSET__W 16
+#define SCU_RAM_ORX_FRQ_OFFSET__M 0xFFFF
+#define SCU_RAM_ORX_FRQ_OFFSET__PRE 0x0
+
+#define SCU_RAM_ORX_FRQ_OFFSET_MAX__A 0x831F24
+#define SCU_RAM_ORX_FRQ_OFFSET_MAX__W 15
+#define SCU_RAM_ORX_FRQ_OFFSET_MAX__M 0x7FFF
+#define SCU_RAM_ORX_FRQ_OFFSET_MAX__PRE 0x0
+
+#define SCU_RAM_ORX_FRQ_KI__A 0x831F25
+#define SCU_RAM_ORX_FRQ_KI__W 8
+#define SCU_RAM_ORX_FRQ_KI__M 0xFF
+#define SCU_RAM_ORX_FRQ_KI__PRE 0x0
+
+#define SCU_RAM_ORX_FRQ_DIFF__A 0x831F26
+#define SCU_RAM_ORX_FRQ_DIFF__W 16
+#define SCU_RAM_ORX_FRQ_DIFF__M 0xFFFF
+#define SCU_RAM_ORX_FRQ_DIFF__PRE 0x0
+
+#define SCU_RAM_ORX_FRQ_LOCK_TH__A 0x831F27
+#define SCU_RAM_ORX_FRQ_LOCK_TH__W 16
+#define SCU_RAM_ORX_FRQ_LOCK_TH__M 0xFFFF
+#define SCU_RAM_ORX_FRQ_LOCK_TH__PRE 0x0
+
+#define SCU_RAM_ORX_FRQ_LOCK_WD__A 0x831F28
+#define SCU_RAM_ORX_FRQ_LOCK_WD__W 16
+#define SCU_RAM_ORX_FRQ_LOCK_WD__M 0xFFFF
+#define SCU_RAM_ORX_FRQ_LOCK_WD__PRE 0x0
+
+#define SCU_RAM_ORX_FRQ_ONLOCK_TTH__A 0x831F29
+#define SCU_RAM_ORX_FRQ_ONLOCK_TTH__W 16
+#define SCU_RAM_ORX_FRQ_ONLOCK_TTH__M 0xFFFF
+#define SCU_RAM_ORX_FRQ_ONLOCK_TTH__PRE 0x0
+
+#define SCU_RAM_ORX_FRQ_UNLOCK_TTH__A 0x831F2A
+#define SCU_RAM_ORX_FRQ_UNLOCK_TTH__W 16
+#define SCU_RAM_ORX_FRQ_UNLOCK_TTH__M 0xFFFF
+#define SCU_RAM_ORX_FRQ_UNLOCK_TTH__PRE 0x0
+
+#define SCU_RAM_ORX_FRQ_LOCK_TOTH__A 0x831F2B
+#define SCU_RAM_ORX_FRQ_LOCK_TOTH__W 16
+#define SCU_RAM_ORX_FRQ_LOCK_TOTH__M 0xFFFF
+#define SCU_RAM_ORX_FRQ_LOCK_TOTH__PRE 0x0
+
+#define SCU_RAM_ORX_FRQ_LOCK_MASK__A 0x831F2C
+#define SCU_RAM_ORX_FRQ_LOCK_MASK__W 8
+#define SCU_RAM_ORX_FRQ_LOCK_MASK__M 0xFF
+#define SCU_RAM_ORX_FRQ_LOCK_MASK__PRE 0x0
+
+#define SCU_RAM_ORX_PHA_DIFF__A 0x831F2D
+#define SCU_RAM_ORX_PHA_DIFF__W 16
+#define SCU_RAM_ORX_PHA_DIFF__M 0xFFFF
+#define SCU_RAM_ORX_PHA_DIFF__PRE 0x0
+
+#define SCU_RAM_ORX_PHA_LOCK_TH__A 0x831F2E
+#define SCU_RAM_ORX_PHA_LOCK_TH__W 16
+#define SCU_RAM_ORX_PHA_LOCK_TH__M 0xFFFF
+#define SCU_RAM_ORX_PHA_LOCK_TH__PRE 0x0
+
+#define SCU_RAM_ORX_PHA_LOCK_WD__A 0x831F2F
+#define SCU_RAM_ORX_PHA_LOCK_WD__W 16
+#define SCU_RAM_ORX_PHA_LOCK_WD__M 0xFFFF
+#define SCU_RAM_ORX_PHA_LOCK_WD__PRE 0x0
+
+#define SCU_RAM_ORX_PHA_ONLOCK_TTH__A 0x831F30
+#define SCU_RAM_ORX_PHA_ONLOCK_TTH__W 16
+#define SCU_RAM_ORX_PHA_ONLOCK_TTH__M 0xFFFF
+#define SCU_RAM_ORX_PHA_ONLOCK_TTH__PRE 0x0
+
+#define SCU_RAM_ORX_PHA_UNLOCK_TTH__A 0x831F31
+#define SCU_RAM_ORX_PHA_UNLOCK_TTH__W 16
+#define SCU_RAM_ORX_PHA_UNLOCK_TTH__M 0xFFFF
+#define SCU_RAM_ORX_PHA_UNLOCK_TTH__PRE 0x0
+
+#define SCU_RAM_ORX_PHA_LOCK_TOTH__A 0x831F32
+#define SCU_RAM_ORX_PHA_LOCK_TOTH__W 16
+#define SCU_RAM_ORX_PHA_LOCK_TOTH__M 0xFFFF
+#define SCU_RAM_ORX_PHA_LOCK_TOTH__PRE 0x0
+
+#define SCU_RAM_ORX_PHA_LOCK_MASK__A 0x831F33
+#define SCU_RAM_ORX_PHA_LOCK_MASK__W 8
+#define SCU_RAM_ORX_PHA_LOCK_MASK__M 0xFF
+#define SCU_RAM_ORX_PHA_LOCK_MASK__PRE 0x0
+
+#define SCU_RAM_ORX_TIM_OFFSET__A 0x831F34
+#define SCU_RAM_ORX_TIM_OFFSET__W 16
+#define SCU_RAM_ORX_TIM_OFFSET__M 0xFFFF
+#define SCU_RAM_ORX_TIM_OFFSET__PRE 0x0
+
+#define SCU_RAM_ORX_TIM_DIFF__A 0x831F35
+#define SCU_RAM_ORX_TIM_DIFF__W 16
+#define SCU_RAM_ORX_TIM_DIFF__M 0xFFFF
+#define SCU_RAM_ORX_TIM_DIFF__PRE 0x0
+
+#define SCU_RAM_ORX_TIM_LOCK_TH__A 0x831F36
+#define SCU_RAM_ORX_TIM_LOCK_TH__W 16
+#define SCU_RAM_ORX_TIM_LOCK_TH__M 0xFFFF
+#define SCU_RAM_ORX_TIM_LOCK_TH__PRE 0x0
+
+#define SCU_RAM_ORX_TIM_LOCK_WD__A 0x831F37
+#define SCU_RAM_ORX_TIM_LOCK_WD__W 16
+#define SCU_RAM_ORX_TIM_LOCK_WD__M 0xFFFF
+#define SCU_RAM_ORX_TIM_LOCK_WD__PRE 0x0
+
+#define SCU_RAM_ORX_TIM_ONLOCK_TTH__A 0x831F38
+#define SCU_RAM_ORX_TIM_ONLOCK_TTH__W 16
+#define SCU_RAM_ORX_TIM_ONLOCK_TTH__M 0xFFFF
+#define SCU_RAM_ORX_TIM_ONLOCK_TTH__PRE 0x0
+
+#define SCU_RAM_ORX_TIM_UNLOCK_TTH__A 0x831F39
+#define SCU_RAM_ORX_TIM_UNLOCK_TTH__W 16
+#define SCU_RAM_ORX_TIM_UNLOCK_TTH__M 0xFFFF
+#define SCU_RAM_ORX_TIM_UNLOCK_TTH__PRE 0x0
+
+#define SCU_RAM_ORX_TIM_LOCK_TOTH__A 0x831F3A
+#define SCU_RAM_ORX_TIM_LOCK_TOTH__W 16
+#define SCU_RAM_ORX_TIM_LOCK_TOTH__M 0xFFFF
+#define SCU_RAM_ORX_TIM_LOCK_TOTH__PRE 0x0
+
+#define SCU_RAM_ORX_TIM_LOCK_MASK__A 0x831F3B
+#define SCU_RAM_ORX_TIM_LOCK_MASK__W 8
+#define SCU_RAM_ORX_TIM_LOCK_MASK__M 0xFF
+#define SCU_RAM_ORX_TIM_LOCK_MASK__PRE 0x0
+
+#define SCU_RAM_ORX_EQU_DIFF__A 0x831F3C
+#define SCU_RAM_ORX_EQU_DIFF__W 16
+#define SCU_RAM_ORX_EQU_DIFF__M 0xFFFF
+#define SCU_RAM_ORX_EQU_DIFF__PRE 0x0
+
+#define SCU_RAM_ORX_EQU_LOCK_TH__A 0x831F3D
+#define SCU_RAM_ORX_EQU_LOCK_TH__W 16
+#define SCU_RAM_ORX_EQU_LOCK_TH__M 0xFFFF
+#define SCU_RAM_ORX_EQU_LOCK_TH__PRE 0x0
+
+#define SCU_RAM_ORX_EQU_LOCK_WD__A 0x831F3E
+#define SCU_RAM_ORX_EQU_LOCK_WD__W 16
+#define SCU_RAM_ORX_EQU_LOCK_WD__M 0xFFFF
+#define SCU_RAM_ORX_EQU_LOCK_WD__PRE 0x0
+
+#define SCU_RAM_ORX_EQU_ONLOCK_TTH__A 0x831F3F
+#define SCU_RAM_ORX_EQU_ONLOCK_TTH__W 16
+#define SCU_RAM_ORX_EQU_ONLOCK_TTH__M 0xFFFF
+#define SCU_RAM_ORX_EQU_ONLOCK_TTH__PRE 0x0
+
+#define SCU_RAM_ORX_EQU_UNLOCK_TTH__A 0x831F40
+#define SCU_RAM_ORX_EQU_UNLOCK_TTH__W 16
+#define SCU_RAM_ORX_EQU_UNLOCK_TTH__M 0xFFFF
+#define SCU_RAM_ORX_EQU_UNLOCK_TTH__PRE 0x0
+
+#define SCU_RAM_ORX_EQU_LOCK_TOTH__A 0x831F41
+#define SCU_RAM_ORX_EQU_LOCK_TOTH__W 16
+#define SCU_RAM_ORX_EQU_LOCK_TOTH__M 0xFFFF
+#define SCU_RAM_ORX_EQU_LOCK_TOTH__PRE 0x0
+
+#define SCU_RAM_ORX_EQU_LOCK_MASK__A 0x831F42
+#define SCU_RAM_ORX_EQU_LOCK_MASK__W 8
+#define SCU_RAM_ORX_EQU_LOCK_MASK__M 0xFF
+#define SCU_RAM_ORX_EQU_LOCK_MASK__PRE 0x0
+
+#define SCU_RAM_ORX_FLT_FRQ__A 0x831F43
+#define SCU_RAM_ORX_FLT_FRQ__W 16
+#define SCU_RAM_ORX_FLT_FRQ__M 0xFFFF
+#define SCU_RAM_ORX_FLT_FRQ__PRE 0x0
+#define SCU_RAM_ORX_RST_CPH__A 0x831F44
+#define SCU_RAM_ORX_RST_CPH__W 4
+#define SCU_RAM_ORX_RST_CPH__M 0xF
+#define SCU_RAM_ORX_RST_CPH__PRE 0x0
+
+#define SCU_RAM_ORX_RST_CPH_RST_CPH__B 0
+#define SCU_RAM_ORX_RST_CPH_RST_CPH__W 4
+#define SCU_RAM_ORX_RST_CPH_RST_CPH__M 0xF
+#define SCU_RAM_ORX_RST_CPH_RST_CPH__PRE 0x0
+
+#define SCU_RAM_ORX_RST_CTI__A 0x831F45
+#define SCU_RAM_ORX_RST_CTI__W 4
+#define SCU_RAM_ORX_RST_CTI__M 0xF
+#define SCU_RAM_ORX_RST_CTI__PRE 0x0
+
+#define SCU_RAM_ORX_RST_CTI_RST_CTI__B 0
+#define SCU_RAM_ORX_RST_CTI_RST_CTI__W 4
+#define SCU_RAM_ORX_RST_CTI_RST_CTI__M 0xF
+#define SCU_RAM_ORX_RST_CTI_RST_CTI__PRE 0x0
+
+#define SCU_RAM_ORX_RST_KRN__A 0x831F46
+#define SCU_RAM_ORX_RST_KRN__W 4
+#define SCU_RAM_ORX_RST_KRN__M 0xF
+#define SCU_RAM_ORX_RST_KRN__PRE 0x0
+
+#define SCU_RAM_ORX_RST_KRN_RST_KRN__B 0
+#define SCU_RAM_ORX_RST_KRN_RST_KRN__W 4
+#define SCU_RAM_ORX_RST_KRN_RST_KRN__M 0xF
+#define SCU_RAM_ORX_RST_KRN_RST_KRN__PRE 0x0
+
+#define SCU_RAM_ORX_RST_KRP__A 0x831F47
+#define SCU_RAM_ORX_RST_KRP__W 4
+#define SCU_RAM_ORX_RST_KRP__M 0xF
+#define SCU_RAM_ORX_RST_KRP__PRE 0x0
+
+#define SCU_RAM_ORX_RST_KRP_RST_KRP__B 0
+#define SCU_RAM_ORX_RST_KRP_RST_KRP__W 4
+#define SCU_RAM_ORX_RST_KRP_RST_KRP__M 0xF
+#define SCU_RAM_ORX_RST_KRP_RST_KRP__PRE 0x0
+
+#define SCU_RAM_ATV_STANDARD__A 0x831F48
+#define SCU_RAM_ATV_STANDARD__W 12
+#define SCU_RAM_ATV_STANDARD__M 0xFFF
+#define SCU_RAM_ATV_STANDARD__PRE 0x0
+
+#define SCU_RAM_ATV_STANDARD_STANDARD__B 0
+#define SCU_RAM_ATV_STANDARD_STANDARD__W 12
+#define SCU_RAM_ATV_STANDARD_STANDARD__M 0xFFF
+#define SCU_RAM_ATV_STANDARD_STANDARD__PRE 0x0
+#define SCU_RAM_ATV_STANDARD_STANDARD_MN 0x2
+#define SCU_RAM_ATV_STANDARD_STANDARD_B 0x103
+#define SCU_RAM_ATV_STANDARD_STANDARD_G 0x3
+#define SCU_RAM_ATV_STANDARD_STANDARD_DK 0x4
+#define SCU_RAM_ATV_STANDARD_STANDARD_L 0x9
+#define SCU_RAM_ATV_STANDARD_STANDARD_LP 0x109
+#define SCU_RAM_ATV_STANDARD_STANDARD_I 0xA
+#define SCU_RAM_ATV_STANDARD_STANDARD_FM 0x40
+
+#define SCU_RAM_ATV_DETECT__A 0x831F49
+#define SCU_RAM_ATV_DETECT__W 1
+#define SCU_RAM_ATV_DETECT__M 0x1
+#define SCU_RAM_ATV_DETECT__PRE 0x0
+
+#define SCU_RAM_ATV_DETECT_DETECT__B 0
+#define SCU_RAM_ATV_DETECT_DETECT__W 1
+#define SCU_RAM_ATV_DETECT_DETECT__M 0x1
+#define SCU_RAM_ATV_DETECT_DETECT__PRE 0x0
+#define SCU_RAM_ATV_DETECT_DETECT_false 0x0
+#define SCU_RAM_ATV_DETECT_DETECT_true 0x1
+
+#define SCU_RAM_ATV_DETECT_TH__A 0x831F4A
+#define SCU_RAM_ATV_DETECT_TH__W 8
+#define SCU_RAM_ATV_DETECT_TH__M 0xFF
+#define SCU_RAM_ATV_DETECT_TH__PRE 0x0
+
+#define SCU_RAM_ATV_DETECT_TH_DETECT_TH__B 0
+#define SCU_RAM_ATV_DETECT_TH_DETECT_TH__W 8
+#define SCU_RAM_ATV_DETECT_TH_DETECT_TH__M 0xFF
+#define SCU_RAM_ATV_DETECT_TH_DETECT_TH__PRE 0x0
+
+#define SCU_RAM_ATV_LOCK__A 0x831F4B
+#define SCU_RAM_ATV_LOCK__W 2
+#define SCU_RAM_ATV_LOCK__M 0x3
+#define SCU_RAM_ATV_LOCK__PRE 0x0
+
+#define SCU_RAM_ATV_LOCK_CR_LOCK_BIT__B 0
+#define SCU_RAM_ATV_LOCK_CR_LOCK_BIT__W 1
+#define SCU_RAM_ATV_LOCK_CR_LOCK_BIT__M 0x1
+#define SCU_RAM_ATV_LOCK_CR_LOCK_BIT__PRE 0x0
+#define SCU_RAM_ATV_LOCK_CR_LOCK_BIT_NO_LOCK 0x0
+#define SCU_RAM_ATV_LOCK_CR_LOCK_BIT_LOCK 0x1
+
+#define SCU_RAM_ATV_LOCK_SYNC_FLAG__B 1
+#define SCU_RAM_ATV_LOCK_SYNC_FLAG__W 1
+#define SCU_RAM_ATV_LOCK_SYNC_FLAG__M 0x2
+#define SCU_RAM_ATV_LOCK_SYNC_FLAG__PRE 0x0
+#define SCU_RAM_ATV_LOCK_SYNC_FLAG_NO_SYNC 0x0
+#define SCU_RAM_ATV_LOCK_SYNC_FLAG_SYNC 0x2
+
+#define SCU_RAM_ATV_CR_LOCK__A 0x831F4C
+#define SCU_RAM_ATV_CR_LOCK__W 11
+#define SCU_RAM_ATV_CR_LOCK__M 0x7FF
+#define SCU_RAM_ATV_CR_LOCK__PRE 0x0
+
+#define SCU_RAM_ATV_CR_LOCK_CR_LOCK__B 0
+#define SCU_RAM_ATV_CR_LOCK_CR_LOCK__W 11
+#define SCU_RAM_ATV_CR_LOCK_CR_LOCK__M 0x7FF
+#define SCU_RAM_ATV_CR_LOCK_CR_LOCK__PRE 0x0
+
+#define SCU_RAM_ATV_AGC_MODE__A 0x831F4D
+#define SCU_RAM_ATV_AGC_MODE__W 8
+#define SCU_RAM_ATV_AGC_MODE__M 0xFF
+#define SCU_RAM_ATV_AGC_MODE__PRE 0x0
+
+#define SCU_RAM_ATV_AGC_MODE_VAGC_VEL__B 2
+#define SCU_RAM_ATV_AGC_MODE_VAGC_VEL__W 1
+#define SCU_RAM_ATV_AGC_MODE_VAGC_VEL__M 0x4
+#define SCU_RAM_ATV_AGC_MODE_VAGC_VEL__PRE 0x0
+#define SCU_RAM_ATV_AGC_MODE_VAGC_VEL_AGC_FAST 0x0
+#define SCU_RAM_ATV_AGC_MODE_VAGC_VEL_AGC_SLOW 0x4
+
+#define SCU_RAM_ATV_AGC_MODE_BP_EN__B 3
+#define SCU_RAM_ATV_AGC_MODE_BP_EN__W 1
+#define SCU_RAM_ATV_AGC_MODE_BP_EN__M 0x8
+#define SCU_RAM_ATV_AGC_MODE_BP_EN__PRE 0x0
+#define SCU_RAM_ATV_AGC_MODE_BP_EN_BPC_DISABLE 0x0
+#define SCU_RAM_ATV_AGC_MODE_BP_EN_BPC_ENABLE 0x8
+
+#define SCU_RAM_ATV_AGC_MODE_SIF_STD__B 4
+#define SCU_RAM_ATV_AGC_MODE_SIF_STD__W 2
+#define SCU_RAM_ATV_AGC_MODE_SIF_STD__M 0x30
+#define SCU_RAM_ATV_AGC_MODE_SIF_STD__PRE 0x0
+#define SCU_RAM_ATV_AGC_MODE_SIF_STD_SIF_AGC_OFF 0x0
+#define SCU_RAM_ATV_AGC_MODE_SIF_STD_SIF_AGC_FM 0x10
+#define SCU_RAM_ATV_AGC_MODE_SIF_STD_SIF_AGC_AM 0x20
+
+#define SCU_RAM_ATV_AGC_MODE_FAST_VAGC_EN__B 6
+#define SCU_RAM_ATV_AGC_MODE_FAST_VAGC_EN__W 1
+#define SCU_RAM_ATV_AGC_MODE_FAST_VAGC_EN__M 0x40
+#define SCU_RAM_ATV_AGC_MODE_FAST_VAGC_EN__PRE 0x0
+#define SCU_RAM_ATV_AGC_MODE_FAST_VAGC_EN_FAGC_DISABLE 0x0
+#define SCU_RAM_ATV_AGC_MODE_FAST_VAGC_EN_FAGC_ENABLE 0x40
+
+#define SCU_RAM_ATV_AGC_MODE_MOD_WA_BP__B 7
+#define SCU_RAM_ATV_AGC_MODE_MOD_WA_BP__W 1
+#define SCU_RAM_ATV_AGC_MODE_MOD_WA_BP__M 0x80
+#define SCU_RAM_ATV_AGC_MODE_MOD_WA_BP__PRE 0x0
+#define SCU_RAM_ATV_AGC_MODE_MOD_WA_BP_MWA_ENABLE 0x0
+#define SCU_RAM_ATV_AGC_MODE_MOD_WA_BP_MWA_DISABLE 0x80
+
+#define SCU_RAM_ATV_RSV_01__A 0x831F4E
+#define SCU_RAM_ATV_RSV_01__W 16
+#define SCU_RAM_ATV_RSV_01__M 0xFFFF
+#define SCU_RAM_ATV_RSV_01__PRE 0x0
+
+#define SCU_RAM_ATV_RSV_02__A 0x831F4F
+#define SCU_RAM_ATV_RSV_02__W 16
+#define SCU_RAM_ATV_RSV_02__M 0xFFFF
+#define SCU_RAM_ATV_RSV_02__PRE 0x0
+
+#define SCU_RAM_ATV_RSV_03__A 0x831F50
+#define SCU_RAM_ATV_RSV_03__W 16
+#define SCU_RAM_ATV_RSV_03__M 0xFFFF
+#define SCU_RAM_ATV_RSV_03__PRE 0x0
+
+#define SCU_RAM_ATV_RSV_04__A 0x831F51
+#define SCU_RAM_ATV_RSV_04__W 16
+#define SCU_RAM_ATV_RSV_04__M 0xFFFF
+#define SCU_RAM_ATV_RSV_04__PRE 0x0
+#define SCU_RAM_ATV_FAGC_TH_RED__A 0x831F52
+#define SCU_RAM_ATV_FAGC_TH_RED__W 8
+#define SCU_RAM_ATV_FAGC_TH_RED__M 0xFF
+#define SCU_RAM_ATV_FAGC_TH_RED__PRE 0x0
+
+#define SCU_RAM_ATV_FAGC_TH_RED_FAGC_TH_RED__B 0
+#define SCU_RAM_ATV_FAGC_TH_RED_FAGC_TH_RED__W 8
+#define SCU_RAM_ATV_FAGC_TH_RED_FAGC_TH_RED__M 0xFF
+#define SCU_RAM_ATV_FAGC_TH_RED_FAGC_TH_RED__PRE 0x0
+
+#define SCU_RAM_ATV_AMS_MAX_REF__A 0x831F53
+#define SCU_RAM_ATV_AMS_MAX_REF__W 11
+#define SCU_RAM_ATV_AMS_MAX_REF__M 0x7FF
+#define SCU_RAM_ATV_AMS_MAX_REF__PRE 0x0
+
+#define SCU_RAM_ATV_AMS_MAX_REF_AMS_MAX_REF__B 0
+#define SCU_RAM_ATV_AMS_MAX_REF_AMS_MAX_REF__W 11
+#define SCU_RAM_ATV_AMS_MAX_REF_AMS_MAX_REF__M 0x7FF
+#define SCU_RAM_ATV_AMS_MAX_REF_AMS_MAX_REF__PRE 0x0
+#define SCU_RAM_ATV_AMS_MAX_REF_AMS_MAX_REF_BG_MN 0x2BC
+#define SCU_RAM_ATV_AMS_MAX_REF_AMS_MAX_REF_DK 0x2D0
+#define SCU_RAM_ATV_AMS_MAX_REF_AMS_MAX_REF_I 0x314
+#define SCU_RAM_ATV_AMS_MAX_REF_AMS_MAX_REF_LLP 0x28A
+
+#define SCU_RAM_ATV_ACT_AMX__A 0x831F54
+#define SCU_RAM_ATV_ACT_AMX__W 11
+#define SCU_RAM_ATV_ACT_AMX__M 0x7FF
+#define SCU_RAM_ATV_ACT_AMX__PRE 0x0
+
+#define SCU_RAM_ATV_ACT_AMX_ACT_AMX__B 0
+#define SCU_RAM_ATV_ACT_AMX_ACT_AMX__W 11
+#define SCU_RAM_ATV_ACT_AMX_ACT_AMX__M 0x7FF
+#define SCU_RAM_ATV_ACT_AMX_ACT_AMX__PRE 0x0
+
+#define SCU_RAM_ATV_ACT_AMI__A 0x831F55
+#define SCU_RAM_ATV_ACT_AMI__W 11
+#define SCU_RAM_ATV_ACT_AMI__M 0x7FF
+#define SCU_RAM_ATV_ACT_AMI__PRE 0x0
+
+#define SCU_RAM_ATV_ACT_AMI_ACT_AMI__B 0
+#define SCU_RAM_ATV_ACT_AMI_ACT_AMI__W 11
+#define SCU_RAM_ATV_ACT_AMI_ACT_AMI__M 0x7FF
+#define SCU_RAM_ATV_ACT_AMI_ACT_AMI__PRE 0x0
+
+#define SCU_RAM_ATV_RSV_05__A 0x831F56
+#define SCU_RAM_ATV_RSV_05__W 16
+#define SCU_RAM_ATV_RSV_05__M 0xFFFF
+#define SCU_RAM_ATV_RSV_05__PRE 0x0
+
+#define SCU_RAM_ATV_RSV_06__A 0x831F57
+#define SCU_RAM_ATV_RSV_06__W 16
+#define SCU_RAM_ATV_RSV_06__M 0xFFFF
+#define SCU_RAM_ATV_RSV_06__PRE 0x0
+
+#define SCU_RAM_ATV_RSV_07__A 0x831F58
+#define SCU_RAM_ATV_RSV_07__W 16
+#define SCU_RAM_ATV_RSV_07__M 0xFFFF
+#define SCU_RAM_ATV_RSV_07__PRE 0x0
+
+#define SCU_RAM_ATV_RSV_08__A 0x831F59
+#define SCU_RAM_ATV_RSV_08__W 16
+#define SCU_RAM_ATV_RSV_08__M 0xFFFF
+#define SCU_RAM_ATV_RSV_08__PRE 0x0
+
+#define SCU_RAM_ATV_RSV_09__A 0x831F5A
+#define SCU_RAM_ATV_RSV_09__W 16
+#define SCU_RAM_ATV_RSV_09__M 0xFFFF
+#define SCU_RAM_ATV_RSV_09__PRE 0x0
+
+#define SCU_RAM_ATV_RSV_10__A 0x831F5B
+#define SCU_RAM_ATV_RSV_10__W 16
+#define SCU_RAM_ATV_RSV_10__M 0xFFFF
+#define SCU_RAM_ATV_RSV_10__PRE 0x0
+
+#define SCU_RAM_ATV_RSV_11__A 0x831F5C
+#define SCU_RAM_ATV_RSV_11__W 16
+#define SCU_RAM_ATV_RSV_11__M 0xFFFF
+#define SCU_RAM_ATV_RSV_11__PRE 0x0
+
+#define SCU_RAM_ATV_RSV_12__A 0x831F5D
+#define SCU_RAM_ATV_RSV_12__W 16
+#define SCU_RAM_ATV_RSV_12__M 0xFFFF
+#define SCU_RAM_ATV_RSV_12__PRE 0x0
+#define SCU_RAM_ATV_VID_GAIN_HI__A 0x831F5E
+#define SCU_RAM_ATV_VID_GAIN_HI__W 16
+#define SCU_RAM_ATV_VID_GAIN_HI__M 0xFFFF
+#define SCU_RAM_ATV_VID_GAIN_HI__PRE 0x0
+
+#define SCU_RAM_ATV_VID_GAIN_HI_VID_GAIN_HI__B 0
+#define SCU_RAM_ATV_VID_GAIN_HI_VID_GAIN_HI__W 16
+#define SCU_RAM_ATV_VID_GAIN_HI_VID_GAIN_HI__M 0xFFFF
+#define SCU_RAM_ATV_VID_GAIN_HI_VID_GAIN_HI__PRE 0x0
+
+#define SCU_RAM_ATV_VID_GAIN_LO__A 0x831F5F
+#define SCU_RAM_ATV_VID_GAIN_LO__W 8
+#define SCU_RAM_ATV_VID_GAIN_LO__M 0xFF
+#define SCU_RAM_ATV_VID_GAIN_LO__PRE 0x0
+
+#define SCU_RAM_ATV_VID_GAIN_LO_VID_GAIN_LO__B 0
+#define SCU_RAM_ATV_VID_GAIN_LO_VID_GAIN_LO__W 8
+#define SCU_RAM_ATV_VID_GAIN_LO_VID_GAIN_LO__M 0xFF
+#define SCU_RAM_ATV_VID_GAIN_LO_VID_GAIN_LO__PRE 0x0
+
+#define SCU_RAM_ATV_RSV_13__A 0x831F60
+#define SCU_RAM_ATV_RSV_13__W 16
+#define SCU_RAM_ATV_RSV_13__M 0xFFFF
+#define SCU_RAM_ATV_RSV_13__PRE 0x0
+
+#define SCU_RAM_ATV_RSV_14__A 0x831F61
+#define SCU_RAM_ATV_RSV_14__W 16
+#define SCU_RAM_ATV_RSV_14__M 0xFFFF
+#define SCU_RAM_ATV_RSV_14__PRE 0x0
+
+#define SCU_RAM_ATV_RSV_15__A 0x831F62
+#define SCU_RAM_ATV_RSV_15__W 16
+#define SCU_RAM_ATV_RSV_15__M 0xFFFF
+#define SCU_RAM_ATV_RSV_15__PRE 0x0
+
+#define SCU_RAM_ATV_RSV_16__A 0x831F63
+#define SCU_RAM_ATV_RSV_16__W 16
+#define SCU_RAM_ATV_RSV_16__M 0xFFFF
+#define SCU_RAM_ATV_RSV_16__PRE 0x0
+#define SCU_RAM_ATV_AAGC_CNT__A 0x831F64
+#define SCU_RAM_ATV_AAGC_CNT__W 8
+#define SCU_RAM_ATV_AAGC_CNT__M 0xFF
+#define SCU_RAM_ATV_AAGC_CNT__PRE 0x0
+
+#define SCU_RAM_ATV_AAGC_CNT_AAGC_CNT__B 0
+#define SCU_RAM_ATV_AAGC_CNT_AAGC_CNT__W 8
+#define SCU_RAM_ATV_AAGC_CNT_AAGC_CNT__M 0xFF
+#define SCU_RAM_ATV_AAGC_CNT_AAGC_CNT__PRE 0x0
+
+#define SCU_RAM_ATV_SIF_GAIN__A 0x831F65
+#define SCU_RAM_ATV_SIF_GAIN__W 11
+#define SCU_RAM_ATV_SIF_GAIN__M 0x7FF
+#define SCU_RAM_ATV_SIF_GAIN__PRE 0x0
+
+#define SCU_RAM_ATV_SIF_GAIN_SIF_GAIN__B 0
+#define SCU_RAM_ATV_SIF_GAIN_SIF_GAIN__W 11
+#define SCU_RAM_ATV_SIF_GAIN_SIF_GAIN__M 0x7FF
+#define SCU_RAM_ATV_SIF_GAIN_SIF_GAIN__PRE 0x0
+
+#define SCU_RAM_ATV_RSV_17__A 0x831F66
+#define SCU_RAM_ATV_RSV_17__W 16
+#define SCU_RAM_ATV_RSV_17__M 0xFFFF
+#define SCU_RAM_ATV_RSV_17__PRE 0x0
+
+#define SCU_RAM_ATV_RSV_18__A 0x831F67
+#define SCU_RAM_ATV_RSV_18__W 16
+#define SCU_RAM_ATV_RSV_18__M 0xFFFF
+#define SCU_RAM_ATV_RSV_18__PRE 0x0
+
+#define SCU_RAM_ATV_RATE_OFS__A 0x831F68
+#define SCU_RAM_ATV_RATE_OFS__W 12
+#define SCU_RAM_ATV_RATE_OFS__M 0xFFF
+#define SCU_RAM_ATV_RATE_OFS__PRE 0x0
+
+#define SCU_RAM_ATV_LO_INCR__A 0x831F69
+#define SCU_RAM_ATV_LO_INCR__W 12
+#define SCU_RAM_ATV_LO_INCR__M 0xFFF
+#define SCU_RAM_ATV_LO_INCR__PRE 0x0
+
+#define SCU_RAM_ATV_IIR_CRIT__A 0x831F6A
+#define SCU_RAM_ATV_IIR_CRIT__W 12
+#define SCU_RAM_ATV_IIR_CRIT__M 0xFFF
+#define SCU_RAM_ATV_IIR_CRIT__PRE 0x0
+
+#define SCU_RAM_ATV_DEF_RATE_OFS__A 0x831F6B
+#define SCU_RAM_ATV_DEF_RATE_OFS__W 12
+#define SCU_RAM_ATV_DEF_RATE_OFS__M 0xFFF
+#define SCU_RAM_ATV_DEF_RATE_OFS__PRE 0x0
+
+#define SCU_RAM_ATV_DEF_LO_INCR__A 0x831F6C
+#define SCU_RAM_ATV_DEF_LO_INCR__W 12
+#define SCU_RAM_ATV_DEF_LO_INCR__M 0xFFF
+#define SCU_RAM_ATV_DEF_LO_INCR__PRE 0x0
+
+#define SCU_RAM_ATV_ENABLE_IIR_WA__A 0x831F6D
+#define SCU_RAM_ATV_ENABLE_IIR_WA__W 1
+#define SCU_RAM_ATV_ENABLE_IIR_WA__M 0x1
+#define SCU_RAM_ATV_ENABLE_IIR_WA__PRE 0x0
+
+#define SCU_RAM_ATV_MOD_CONTROL__A 0x831F6E
+#define SCU_RAM_ATV_MOD_CONTROL__W 12
+#define SCU_RAM_ATV_MOD_CONTROL__M 0xFFF
+#define SCU_RAM_ATV_MOD_CONTROL__PRE 0x0
+
+#define SCU_RAM_ATV_PAGC_KI_MAX__A 0x831F6F
+#define SCU_RAM_ATV_PAGC_KI_MAX__W 12
+#define SCU_RAM_ATV_PAGC_KI_MAX__M 0xFFF
+#define SCU_RAM_ATV_PAGC_KI_MAX__PRE 0x0
+
+#define SCU_RAM_ATV_BPC_KI_MAX__A 0x831F70
+#define SCU_RAM_ATV_BPC_KI_MAX__W 12
+#define SCU_RAM_ATV_BPC_KI_MAX__M 0xFFF
+#define SCU_RAM_ATV_BPC_KI_MAX__PRE 0x0
+
+#define SCU_RAM_ATV_NAGC_KI_MAX__A 0x831F71
+#define SCU_RAM_ATV_NAGC_KI_MAX__W 12
+#define SCU_RAM_ATV_NAGC_KI_MAX__M 0xFFF
+#define SCU_RAM_ATV_NAGC_KI_MAX__PRE 0x0
+#define SCU_RAM_ATV_NAGC_KI_MIN__A 0x831F72
+#define SCU_RAM_ATV_NAGC_KI_MIN__W 12
+#define SCU_RAM_ATV_NAGC_KI_MIN__M 0xFFF
+#define SCU_RAM_ATV_NAGC_KI_MIN__PRE 0x0
+
+#define SCU_RAM_ATV_NAGC_KI_MIN_NAGC_KI_MIN__B 0
+#define SCU_RAM_ATV_NAGC_KI_MIN_NAGC_KI_MIN__W 12
+#define SCU_RAM_ATV_NAGC_KI_MIN_NAGC_KI_MIN__M 0xFFF
+#define SCU_RAM_ATV_NAGC_KI_MIN_NAGC_KI_MIN__PRE 0x0
+
+#define SCU_RAM_ATV_KI_CHANGE_TH__A 0x831F73
+#define SCU_RAM_ATV_KI_CHANGE_TH__W 8
+#define SCU_RAM_ATV_KI_CHANGE_TH__M 0xFF
+#define SCU_RAM_ATV_KI_CHANGE_TH__PRE 0x0
+
+#define SCU_RAM_ATV_KI_CHANGE_TH_KI_CHANGE_TH__B 0
+#define SCU_RAM_ATV_KI_CHANGE_TH_KI_CHANGE_TH__W 8
+#define SCU_RAM_ATV_KI_CHANGE_TH_KI_CHANGE_TH__M 0xFF
+#define SCU_RAM_ATV_KI_CHANGE_TH_KI_CHANGE_TH__PRE 0x0
+#define SCU_RAM_ATV_KI_CHANGE_TH_KI_CHANGE_TH_NEG_MOD 0x14
+#define SCU_RAM_ATV_KI_CHANGE_TH_KI_CHANGE_TH_POS_MOD 0x28
+
+#define SCU_RAM_QAM_PARAM_ANNEX__A 0x831F74
+#define SCU_RAM_QAM_PARAM_ANNEX__W 2
+#define SCU_RAM_QAM_PARAM_ANNEX__M 0x3
+#define SCU_RAM_QAM_PARAM_ANNEX__PRE 0x0
+
+#define SCU_RAM_QAM_PARAM_ANNEX_BIT__B 0
+#define SCU_RAM_QAM_PARAM_ANNEX_BIT__W 2
+#define SCU_RAM_QAM_PARAM_ANNEX_BIT__M 0x3
+#define SCU_RAM_QAM_PARAM_ANNEX_BIT__PRE 0x0
+#define SCU_RAM_QAM_PARAM_ANNEX_BIT_ANNEX_A 0x0
+#define SCU_RAM_QAM_PARAM_ANNEX_BIT_ANNEX_B 0x1
+#define SCU_RAM_QAM_PARAM_ANNEX_BIT_ANNEX_C 0x2
+#define SCU_RAM_QAM_PARAM_ANNEX_BIT_ANNEX_D 0x3
+
+#define SCU_RAM_QAM_PARAM_CONSTELLATION__A 0x831F75
+#define SCU_RAM_QAM_PARAM_CONSTELLATION__W 3
+#define SCU_RAM_QAM_PARAM_CONSTELLATION__M 0x7
+#define SCU_RAM_QAM_PARAM_CONSTELLATION__PRE 0x0
+
+#define SCU_RAM_QAM_PARAM_CONSTELLATION_BIT__B 0
+#define SCU_RAM_QAM_PARAM_CONSTELLATION_BIT__W 3
+#define SCU_RAM_QAM_PARAM_CONSTELLATION_BIT__M 0x7
+#define SCU_RAM_QAM_PARAM_CONSTELLATION_BIT__PRE 0x0
+#define SCU_RAM_QAM_PARAM_CONSTELLATION_BIT_UNKNOWN 0x0
+#define SCU_RAM_QAM_PARAM_CONSTELLATION_BIT_QAM_16 0x3
+#define SCU_RAM_QAM_PARAM_CONSTELLATION_BIT_QAM_32 0x4
+#define SCU_RAM_QAM_PARAM_CONSTELLATION_BIT_QAM_64 0x5
+#define SCU_RAM_QAM_PARAM_CONSTELLATION_BIT_QAM_128 0x6
+#define SCU_RAM_QAM_PARAM_CONSTELLATION_BIT_QAM_256 0x7
+
+#define SCU_RAM_QAM_PARAM_INTERLEAVE__A 0x831F76
+#define SCU_RAM_QAM_PARAM_INTERLEAVE__W 8
+#define SCU_RAM_QAM_PARAM_INTERLEAVE__M 0xFF
+#define SCU_RAM_QAM_PARAM_INTERLEAVE__PRE 0x0
+
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT__B 0
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT__W 8
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT__M 0xFF
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT__PRE 0x0
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT_I128_J1 0x0
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT_I128_J1_V2 0x1
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT_I128_J2 0x2
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT_I64_J2 0x3
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT_I128_J3 0x4
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT_I32_J4 0x5
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT_I128_J4 0x6
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT_I16_J8 0x7
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT_I128_J5 0x8
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT_I8_J16 0x9
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT_I128_J6 0xA
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT_I128_J7 0xC
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT_I128_J8 0xE
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT_I12_J17 0x10
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT_I5_J4 0x11
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT_UNKNOWN 0xFE
+#define SCU_RAM_QAM_PARAM_INTERLEAVE_BIT_AUTO 0xFF
+
+#define SCU_RAM_QAM_PARAM_SYM_RCRATE_HI__A 0x831F77
+#define SCU_RAM_QAM_PARAM_SYM_RCRATE_HI__W 16
+#define SCU_RAM_QAM_PARAM_SYM_RCRATE_HI__M 0xFFFF
+#define SCU_RAM_QAM_PARAM_SYM_RCRATE_HI__PRE 0x0
+
+#define SCU_RAM_QAM_PARAM_SYM_RCRATE_HI_BIT__B 0
+#define SCU_RAM_QAM_PARAM_SYM_RCRATE_HI_BIT__W 16
+#define SCU_RAM_QAM_PARAM_SYM_RCRATE_HI_BIT__M 0xFFFF
+#define SCU_RAM_QAM_PARAM_SYM_RCRATE_HI_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_PARAM_SYM_RCRATE_LO__A 0x831F78
+#define SCU_RAM_QAM_PARAM_SYM_RCRATE_LO__W 16
+#define SCU_RAM_QAM_PARAM_SYM_RCRATE_LO__M 0xFFFF
+#define SCU_RAM_QAM_PARAM_SYM_RCRATE_LO__PRE 0x0
+
+#define SCU_RAM_QAM_PARAM_SYM_RCRATE_LO_BIT__B 0
+#define SCU_RAM_QAM_PARAM_SYM_RCRATE_LO_BIT__W 16
+#define SCU_RAM_QAM_PARAM_SYM_RCRATE_LO_BIT__M 0xFFFF
+#define SCU_RAM_QAM_PARAM_SYM_RCRATE_LO_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_EQ_CENTERTAP__A 0x831F79
+#define SCU_RAM_QAM_EQ_CENTERTAP__W 16
+#define SCU_RAM_QAM_EQ_CENTERTAP__M 0xFFFF
+#define SCU_RAM_QAM_EQ_CENTERTAP__PRE 0x0
+
+#define SCU_RAM_QAM_EQ_CENTERTAP_BIT__B 0
+#define SCU_RAM_QAM_EQ_CENTERTAP_BIT__W 8
+#define SCU_RAM_QAM_EQ_CENTERTAP_BIT__M 0xFF
+#define SCU_RAM_QAM_EQ_CENTERTAP_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_WR_RSV_0__A 0x831F7A
+#define SCU_RAM_QAM_WR_RSV_0__W 16
+#define SCU_RAM_QAM_WR_RSV_0__M 0xFFFF
+#define SCU_RAM_QAM_WR_RSV_0__PRE 0x0
+
+#define SCU_RAM_QAM_WR_RSV_0_BIT__B 0
+#define SCU_RAM_QAM_WR_RSV_0_BIT__W 16
+#define SCU_RAM_QAM_WR_RSV_0_BIT__M 0xFFFF
+#define SCU_RAM_QAM_WR_RSV_0_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_PARAM_ALT_RCRATE_HI__A 0x831F7B
+#define SCU_RAM_QAM_PARAM_ALT_RCRATE_HI__W 16
+#define SCU_RAM_QAM_PARAM_ALT_RCRATE_HI__M 0xFFFF
+#define SCU_RAM_QAM_PARAM_ALT_RCRATE_HI__PRE 0x0
+
+#define SCU_RAM_QAM_PARAM_ALT_RCRATE_HI_BIT__B 0
+#define SCU_RAM_QAM_PARAM_ALT_RCRATE_HI_BIT__W 16
+#define SCU_RAM_QAM_PARAM_ALT_RCRATE_HI_BIT__M 0xFFFF
+#define SCU_RAM_QAM_PARAM_ALT_RCRATE_HI_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_PARAM_ALT_RCRATE_LO__A 0x831F7C
+#define SCU_RAM_QAM_PARAM_ALT_RCRATE_LO__W 16
+#define SCU_RAM_QAM_PARAM_ALT_RCRATE_LO__M 0xFFFF
+#define SCU_RAM_QAM_PARAM_ALT_RCRATE_LO__PRE 0x0
+
+#define SCU_RAM_QAM_PARAM_ALT_RCRATE_LO_BIT__B 0
+#define SCU_RAM_QAM_PARAM_ALT_RCRATE_LO_BIT__W 16
+#define SCU_RAM_QAM_PARAM_ALT_RCRATE_LO_BIT__M 0xFFFF
+#define SCU_RAM_QAM_PARAM_ALT_RCRATE_LO_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_WR_RSV_5__A 0x831F7D
+#define SCU_RAM_QAM_WR_RSV_5__W 16
+#define SCU_RAM_QAM_WR_RSV_5__M 0xFFFF
+#define SCU_RAM_QAM_WR_RSV_5__PRE 0x0
+
+#define SCU_RAM_QAM_WR_RSV_5_BIT__B 0
+#define SCU_RAM_QAM_WR_RSV_5_BIT__W 16
+#define SCU_RAM_QAM_WR_RSV_5_BIT__M 0xFFFF
+#define SCU_RAM_QAM_WR_RSV_5_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_WR_RSV_6__A 0x831F7E
+#define SCU_RAM_QAM_WR_RSV_6__W 16
+#define SCU_RAM_QAM_WR_RSV_6__M 0xFFFF
+#define SCU_RAM_QAM_WR_RSV_6__PRE 0x0
+
+#define SCU_RAM_QAM_WR_RSV_6_BIT__B 0
+#define SCU_RAM_QAM_WR_RSV_6_BIT__W 16
+#define SCU_RAM_QAM_WR_RSV_6_BIT__M 0xFFFF
+#define SCU_RAM_QAM_WR_RSV_6_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_WR_RSV_7__A 0x831F7F
+#define SCU_RAM_QAM_WR_RSV_7__W 16
+#define SCU_RAM_QAM_WR_RSV_7__M 0xFFFF
+#define SCU_RAM_QAM_WR_RSV_7__PRE 0x0
+
+#define SCU_RAM_QAM_WR_RSV_7_BIT__B 0
+#define SCU_RAM_QAM_WR_RSV_7_BIT__W 16
+#define SCU_RAM_QAM_WR_RSV_7_BIT__M 0xFFFF
+#define SCU_RAM_QAM_WR_RSV_7_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_WR_RSV_8__A 0x831F80
+#define SCU_RAM_QAM_WR_RSV_8__W 16
+#define SCU_RAM_QAM_WR_RSV_8__M 0xFFFF
+#define SCU_RAM_QAM_WR_RSV_8__PRE 0x0
+
+#define SCU_RAM_QAM_WR_RSV_8_BIT__B 0
+#define SCU_RAM_QAM_WR_RSV_8_BIT__W 16
+#define SCU_RAM_QAM_WR_RSV_8_BIT__M 0xFFFF
+#define SCU_RAM_QAM_WR_RSV_8_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_WR_RSV_9__A 0x831F81
+#define SCU_RAM_QAM_WR_RSV_9__W 16
+#define SCU_RAM_QAM_WR_RSV_9__M 0xFFFF
+#define SCU_RAM_QAM_WR_RSV_9__PRE 0x0
+
+#define SCU_RAM_QAM_WR_RSV_9_BIT__B 0
+#define SCU_RAM_QAM_WR_RSV_9_BIT__W 16
+#define SCU_RAM_QAM_WR_RSV_9_BIT__M 0xFFFF
+#define SCU_RAM_QAM_WR_RSV_9_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_WR_RSV_10__A 0x831F82
+#define SCU_RAM_QAM_WR_RSV_10__W 16
+#define SCU_RAM_QAM_WR_RSV_10__M 0xFFFF
+#define SCU_RAM_QAM_WR_RSV_10__PRE 0x0
+
+#define SCU_RAM_QAM_WR_RSV_10_BIT__B 0
+#define SCU_RAM_QAM_WR_RSV_10_BIT__W 16
+#define SCU_RAM_QAM_WR_RSV_10_BIT__M 0xFFFF
+#define SCU_RAM_QAM_WR_RSV_10_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_FMHUM_TO__A 0x831F83
+#define SCU_RAM_QAM_FSM_FMHUM_TO__W 16
+#define SCU_RAM_QAM_FSM_FMHUM_TO__M 0xFFFF
+#define SCU_RAM_QAM_FSM_FMHUM_TO__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_FMHUM_TO_BIT__B 0
+#define SCU_RAM_QAM_FSM_FMHUM_TO_BIT__W 16
+#define SCU_RAM_QAM_FSM_FMHUM_TO_BIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_FMHUM_TO_BIT__PRE 0x0
+#define SCU_RAM_QAM_FSM_FMHUM_TO_BIT_NO_FMHUM_TO 0x0
+
+#define SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A 0x831F84
+#define SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__W 16
+#define SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_MEDIAN_AV_MULT_BIT__B 0
+#define SCU_RAM_QAM_FSM_MEDIAN_AV_MULT_BIT__W 16
+#define SCU_RAM_QAM_FSM_MEDIAN_AV_MULT_BIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_MEDIAN_AV_MULT_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A 0x831F85
+#define SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__W 16
+#define SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT_BIT__B 0
+#define SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT_BIT__W 16
+#define SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT_BIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A 0x831F86
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET1__W 16
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET1__M 0xFFFF
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET1__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET1_BIT__B 0
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET1_BIT__W 16
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET1_BIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET1_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A 0x831F87
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET2__W 16
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET2__M 0xFFFF
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET2__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET2_BIT__B 0
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET2_BIT__W 16
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET2_BIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET2_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A 0x831F88
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET3__W 16
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET3__M 0xFFFF
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET3__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET3_BIT__B 0
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET3_BIT__W 16
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET3_BIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET3_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A 0x831F89
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET4__W 16
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET4__M 0xFFFF
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET4__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET4_BIT__B 0
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET4_BIT__W 16
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET4_BIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET4_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A 0x831F8A
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET5__W 16
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET5__M 0xFFFF
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET5__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET5_BIT__B 0
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET5_BIT__W 16
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET5_BIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_LCAVG_OFFSET5_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_STATE_TGT__A 0x831F8B
+#define SCU_RAM_QAM_FSM_STATE_TGT__W 4
+#define SCU_RAM_QAM_FSM_STATE_TGT__M 0xF
+#define SCU_RAM_QAM_FSM_STATE_TGT__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_STATE_TGT_BIT__B 0
+#define SCU_RAM_QAM_FSM_STATE_TGT_BIT__W 4
+#define SCU_RAM_QAM_FSM_STATE_TGT_BIT__M 0xF
+#define SCU_RAM_QAM_FSM_STATE_TGT_BIT__PRE 0x0
+#define SCU_RAM_QAM_FSM_STATE_TGT_BIT_HUNTING_AMP 0x0
+#define SCU_RAM_QAM_FSM_STATE_TGT_BIT_HUNTING_RATE 0x1
+#define SCU_RAM_QAM_FSM_STATE_TGT_BIT_HUNTING_FREQ 0x2
+#define SCU_RAM_QAM_FSM_STATE_TGT_BIT_HUNTING_UPRIGHT 0x3
+#define SCU_RAM_QAM_FSM_STATE_TGT_BIT_HUNTING_PHASE 0x4
+#define SCU_RAM_QAM_FSM_STATE_TGT_BIT_TRACKING_PHNOISE 0x5
+#define SCU_RAM_QAM_FSM_STATE_TGT_BIT_TRACKING 0x6
+#define SCU_RAM_QAM_FSM_STATE_TGT_BIT_TRACKING_BURST 0x7
+
+#define SCU_RAM_QAM_FSM_LOCK_OVERRIDE__A 0x831F8C
+#define SCU_RAM_QAM_FSM_LOCK_OVERRIDE__W 9
+#define SCU_RAM_QAM_FSM_LOCK_OVERRIDE__M 0x1FF
+#define SCU_RAM_QAM_FSM_LOCK_OVERRIDE__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_LOCK_OVERRIDE_LCK_AMP__B 0
+#define SCU_RAM_QAM_FSM_LOCK_OVERRIDE_LCK_AMP__W 1
+#define SCU_RAM_QAM_FSM_LOCK_OVERRIDE_LCK_AMP__M 0x1
+#define SCU_RAM_QAM_FSM_LOCK_OVERRIDE_LCK_AMP__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_ATH__A 0x831F8D
+#define SCU_RAM_QAM_FSM_ATH__W 16
+#define SCU_RAM_QAM_FSM_ATH__M 0xFFFF
+#define SCU_RAM_QAM_FSM_ATH__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_ATH_BIT__B 0
+#define SCU_RAM_QAM_FSM_ATH_BIT__W 16
+#define SCU_RAM_QAM_FSM_ATH_BIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_ATH_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_RTH__A 0x831F8E
+#define SCU_RAM_QAM_FSM_RTH__W 16
+#define SCU_RAM_QAM_FSM_RTH__M 0xFFFF
+#define SCU_RAM_QAM_FSM_RTH__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_RTH_BIT__B 0
+#define SCU_RAM_QAM_FSM_RTH_BIT__W 16
+#define SCU_RAM_QAM_FSM_RTH_BIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_RTH_BIT__PRE 0x0
+#define SCU_RAM_QAM_FSM_RTH_BIT_QAM_16 0x8C
+#define SCU_RAM_QAM_FSM_RTH_BIT_QAM_32 0x50
+#define SCU_RAM_QAM_FSM_RTH_BIT_QAM_64 0x4E
+#define SCU_RAM_QAM_FSM_RTH_BIT_QAM_128 0x32
+#define SCU_RAM_QAM_FSM_RTH_BIT_QAM_256 0x2D
+
+#define SCU_RAM_QAM_FSM_FTH__A 0x831F8F
+#define SCU_RAM_QAM_FSM_FTH__W 16
+#define SCU_RAM_QAM_FSM_FTH__M 0xFFFF
+#define SCU_RAM_QAM_FSM_FTH__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_FTH_BIT__B 0
+#define SCU_RAM_QAM_FSM_FTH_BIT__W 16
+#define SCU_RAM_QAM_FSM_FTH_BIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_FTH_BIT__PRE 0x0
+#define SCU_RAM_QAM_FSM_FTH_BIT_QAM_16 0x32
+#define SCU_RAM_QAM_FSM_FTH_BIT_QAM_32 0x1E
+#define SCU_RAM_QAM_FSM_FTH_BIT_QAM_64 0x1E
+#define SCU_RAM_QAM_FSM_FTH_BIT_QAM_128 0x14
+#define SCU_RAM_QAM_FSM_FTH_BIT_QAM_256 0x14
+
+#define SCU_RAM_QAM_FSM_PTH__A 0x831F90
+#define SCU_RAM_QAM_FSM_PTH__W 16
+#define SCU_RAM_QAM_FSM_PTH__M 0xFFFF
+#define SCU_RAM_QAM_FSM_PTH__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_PTH_BIT__B 0
+#define SCU_RAM_QAM_FSM_PTH_BIT__W 16
+#define SCU_RAM_QAM_FSM_PTH_BIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_PTH_BIT__PRE 0x0
+#define SCU_RAM_QAM_FSM_PTH_BIT_QAM_16 0xC8
+#define SCU_RAM_QAM_FSM_PTH_BIT_QAM_32 0x96
+#define SCU_RAM_QAM_FSM_PTH_BIT_QAM_64 0x8C
+#define SCU_RAM_QAM_FSM_PTH_BIT_QAM_128 0x64
+#define SCU_RAM_QAM_FSM_PTH_BIT_QAM_256 0x64
+
+#define SCU_RAM_QAM_FSM_MTH__A 0x831F91
+#define SCU_RAM_QAM_FSM_MTH__W 16
+#define SCU_RAM_QAM_FSM_MTH__M 0xFFFF
+#define SCU_RAM_QAM_FSM_MTH__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_MTH_BIT__B 0
+#define SCU_RAM_QAM_FSM_MTH_BIT__W 16
+#define SCU_RAM_QAM_FSM_MTH_BIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_MTH_BIT__PRE 0x0
+#define SCU_RAM_QAM_FSM_MTH_BIT_QAM_16 0x5A
+#define SCU_RAM_QAM_FSM_MTH_BIT_QAM_32 0x50
+#define SCU_RAM_QAM_FSM_MTH_BIT_QAM_64 0x46
+#define SCU_RAM_QAM_FSM_MTH_BIT_QAM_128 0x3C
+#define SCU_RAM_QAM_FSM_MTH_BIT_QAM_256 0x50
+
+#define SCU_RAM_QAM_FSM_CTH__A 0x831F92
+#define SCU_RAM_QAM_FSM_CTH__W 16
+#define SCU_RAM_QAM_FSM_CTH__M 0xFFFF
+#define SCU_RAM_QAM_FSM_CTH__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_CTH_BIT__B 0
+#define SCU_RAM_QAM_FSM_CTH_BIT__W 16
+#define SCU_RAM_QAM_FSM_CTH_BIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_CTH_BIT__PRE 0x0
+#define SCU_RAM_QAM_FSM_CTH_BIT_QAM_16 0xA0
+#define SCU_RAM_QAM_FSM_CTH_BIT_QAM_32 0x8C
+#define SCU_RAM_QAM_FSM_CTH_BIT_QAM_64 0x8C
+#define SCU_RAM_QAM_FSM_CTH_BIT_QAM_128 0x8C
+#define SCU_RAM_QAM_FSM_CTH_BIT_QAM_256 0x8C
+
+#define SCU_RAM_QAM_FSM_QTH__A 0x831F93
+#define SCU_RAM_QAM_FSM_QTH__W 16
+#define SCU_RAM_QAM_FSM_QTH__M 0xFFFF
+#define SCU_RAM_QAM_FSM_QTH__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_QTH_BIT__B 0
+#define SCU_RAM_QAM_FSM_QTH_BIT__W 16
+#define SCU_RAM_QAM_FSM_QTH_BIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_QTH_BIT__PRE 0x0
+#define SCU_RAM_QAM_FSM_QTH_BIT_QAM_16 0xE6
+#define SCU_RAM_QAM_FSM_QTH_BIT_QAM_32 0xAA
+#define SCU_RAM_QAM_FSM_QTH_BIT_QAM_64 0xC3
+#define SCU_RAM_QAM_FSM_QTH_BIT_QAM_128 0x8C
+#define SCU_RAM_QAM_FSM_QTH_BIT_QAM_256 0x96
+
+#define SCU_RAM_QAM_FSM_RATE_LIM__A 0x831F94
+#define SCU_RAM_QAM_FSM_RATE_LIM__W 16
+#define SCU_RAM_QAM_FSM_RATE_LIM__M 0xFFFF
+#define SCU_RAM_QAM_FSM_RATE_LIM__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_RATE_LIM_BIT__B 0
+#define SCU_RAM_QAM_FSM_RATE_LIM_BIT__W 16
+#define SCU_RAM_QAM_FSM_RATE_LIM_BIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_RATE_LIM_BIT__PRE 0x0
+#define SCU_RAM_QAM_FSM_RATE_LIM_BIT_QAM_16 0x46
+#define SCU_RAM_QAM_FSM_RATE_LIM_BIT_QAM_32 0x46
+#define SCU_RAM_QAM_FSM_RATE_LIM_BIT_QAM_64 0x46
+#define SCU_RAM_QAM_FSM_RATE_LIM_BIT_QAM_128 0x46
+#define SCU_RAM_QAM_FSM_RATE_LIM_BIT_QAM_256 0x46
+
+#define SCU_RAM_QAM_FSM_FREQ_LIM__A 0x831F95
+#define SCU_RAM_QAM_FSM_FREQ_LIM__W 16
+#define SCU_RAM_QAM_FSM_FREQ_LIM__M 0xFFFF
+#define SCU_RAM_QAM_FSM_FREQ_LIM__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_FREQ_LIM_BIT__B 0
+#define SCU_RAM_QAM_FSM_FREQ_LIM_BIT__W 16
+#define SCU_RAM_QAM_FSM_FREQ_LIM_BIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_FREQ_LIM_BIT__PRE 0x0
+#define SCU_RAM_QAM_FSM_FREQ_LIM_BIT_QAM_16 0x1E
+#define SCU_RAM_QAM_FSM_FREQ_LIM_BIT_QAM_32 0x14
+#define SCU_RAM_QAM_FSM_FREQ_LIM_BIT_QAM_64 0x28
+#define SCU_RAM_QAM_FSM_FREQ_LIM_BIT_QAM_128 0x8
+#define SCU_RAM_QAM_FSM_FREQ_LIM_BIT_QAM_256 0x28
+
+#define SCU_RAM_QAM_FSM_COUNT_LIM__A 0x831F96
+#define SCU_RAM_QAM_FSM_COUNT_LIM__W 16
+#define SCU_RAM_QAM_FSM_COUNT_LIM__M 0xFFFF
+#define SCU_RAM_QAM_FSM_COUNT_LIM__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_COUNT_LIM_BIT__B 0
+#define SCU_RAM_QAM_FSM_COUNT_LIM_BIT__W 16
+#define SCU_RAM_QAM_FSM_COUNT_LIM_BIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_COUNT_LIM_BIT__PRE 0x0
+#define SCU_RAM_QAM_FSM_COUNT_LIM_BIT_QAM_16 0x4
+#define SCU_RAM_QAM_FSM_COUNT_LIM_BIT_QAM_32 0x6
+#define SCU_RAM_QAM_FSM_COUNT_LIM_BIT_QAM_64 0x6
+#define SCU_RAM_QAM_FSM_COUNT_LIM_BIT_QAM_128 0x7
+#define SCU_RAM_QAM_FSM_COUNT_LIM_BIT_QAM_256 0x6
+
+#define SCU_RAM_QAM_LC_CA_COARSE__A 0x831F97
+#define SCU_RAM_QAM_LC_CA_COARSE__W 16
+#define SCU_RAM_QAM_LC_CA_COARSE__M 0xFFFF
+#define SCU_RAM_QAM_LC_CA_COARSE__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CA_COARSE_BIT__B 0
+#define SCU_RAM_QAM_LC_CA_COARSE_BIT__W 8
+#define SCU_RAM_QAM_LC_CA_COARSE_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_CA_COARSE_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CA_MEDIUM__A 0x831F98
+#define SCU_RAM_QAM_LC_CA_MEDIUM__W 16
+#define SCU_RAM_QAM_LC_CA_MEDIUM__M 0xFFFF
+#define SCU_RAM_QAM_LC_CA_MEDIUM__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CA_MEDIUM_BIT__B 0
+#define SCU_RAM_QAM_LC_CA_MEDIUM_BIT__W 8
+#define SCU_RAM_QAM_LC_CA_MEDIUM_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_CA_MEDIUM_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CA_FINE__A 0x831F99
+#define SCU_RAM_QAM_LC_CA_FINE__W 16
+#define SCU_RAM_QAM_LC_CA_FINE__M 0xFFFF
+#define SCU_RAM_QAM_LC_CA_FINE__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CA_FINE_BIT__B 0
+#define SCU_RAM_QAM_LC_CA_FINE_BIT__W 8
+#define SCU_RAM_QAM_LC_CA_FINE_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_CA_FINE_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CP_COARSE__A 0x831F9A
+#define SCU_RAM_QAM_LC_CP_COARSE__W 16
+#define SCU_RAM_QAM_LC_CP_COARSE__M 0xFFFF
+#define SCU_RAM_QAM_LC_CP_COARSE__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CP_COARSE_BIT__B 0
+#define SCU_RAM_QAM_LC_CP_COARSE_BIT__W 8
+#define SCU_RAM_QAM_LC_CP_COARSE_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_CP_COARSE_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CP_MEDIUM__A 0x831F9B
+#define SCU_RAM_QAM_LC_CP_MEDIUM__W 16
+#define SCU_RAM_QAM_LC_CP_MEDIUM__M 0xFFFF
+#define SCU_RAM_QAM_LC_CP_MEDIUM__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CP_MEDIUM_BIT__B 0
+#define SCU_RAM_QAM_LC_CP_MEDIUM_BIT__W 8
+#define SCU_RAM_QAM_LC_CP_MEDIUM_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_CP_MEDIUM_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CP_FINE__A 0x831F9C
+#define SCU_RAM_QAM_LC_CP_FINE__W 16
+#define SCU_RAM_QAM_LC_CP_FINE__M 0xFFFF
+#define SCU_RAM_QAM_LC_CP_FINE__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CP_FINE_BIT__B 0
+#define SCU_RAM_QAM_LC_CP_FINE_BIT__W 8
+#define SCU_RAM_QAM_LC_CP_FINE_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_CP_FINE_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CI_COARSE__A 0x831F9D
+#define SCU_RAM_QAM_LC_CI_COARSE__W 16
+#define SCU_RAM_QAM_LC_CI_COARSE__M 0xFFFF
+#define SCU_RAM_QAM_LC_CI_COARSE__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CI_COARSE_BIT__B 0
+#define SCU_RAM_QAM_LC_CI_COARSE_BIT__W 8
+#define SCU_RAM_QAM_LC_CI_COARSE_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_CI_COARSE_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CI_MEDIUM__A 0x831F9E
+#define SCU_RAM_QAM_LC_CI_MEDIUM__W 16
+#define SCU_RAM_QAM_LC_CI_MEDIUM__M 0xFFFF
+#define SCU_RAM_QAM_LC_CI_MEDIUM__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CI_MEDIUM_BIT__B 0
+#define SCU_RAM_QAM_LC_CI_MEDIUM_BIT__W 8
+#define SCU_RAM_QAM_LC_CI_MEDIUM_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_CI_MEDIUM_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CI_FINE__A 0x831F9F
+#define SCU_RAM_QAM_LC_CI_FINE__W 16
+#define SCU_RAM_QAM_LC_CI_FINE__M 0xFFFF
+#define SCU_RAM_QAM_LC_CI_FINE__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CI_FINE_BIT__B 0
+#define SCU_RAM_QAM_LC_CI_FINE_BIT__W 8
+#define SCU_RAM_QAM_LC_CI_FINE_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_CI_FINE_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LC_EP_COARSE__A 0x831FA0
+#define SCU_RAM_QAM_LC_EP_COARSE__W 16
+#define SCU_RAM_QAM_LC_EP_COARSE__M 0xFFFF
+#define SCU_RAM_QAM_LC_EP_COARSE__PRE 0x0
+
+#define SCU_RAM_QAM_LC_EP_COARSE_BIT__B 0
+#define SCU_RAM_QAM_LC_EP_COARSE_BIT__W 8
+#define SCU_RAM_QAM_LC_EP_COARSE_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_EP_COARSE_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LC_EP_MEDIUM__A 0x831FA1
+#define SCU_RAM_QAM_LC_EP_MEDIUM__W 16
+#define SCU_RAM_QAM_LC_EP_MEDIUM__M 0xFFFF
+#define SCU_RAM_QAM_LC_EP_MEDIUM__PRE 0x0
+
+#define SCU_RAM_QAM_LC_EP_MEDIUM_BIT__B 0
+#define SCU_RAM_QAM_LC_EP_MEDIUM_BIT__W 8
+#define SCU_RAM_QAM_LC_EP_MEDIUM_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_EP_MEDIUM_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LC_EP_FINE__A 0x831FA2
+#define SCU_RAM_QAM_LC_EP_FINE__W 16
+#define SCU_RAM_QAM_LC_EP_FINE__M 0xFFFF
+#define SCU_RAM_QAM_LC_EP_FINE__PRE 0x0
+
+#define SCU_RAM_QAM_LC_EP_FINE_BIT__B 0
+#define SCU_RAM_QAM_LC_EP_FINE_BIT__W 8
+#define SCU_RAM_QAM_LC_EP_FINE_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_EP_FINE_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LC_EI_COARSE__A 0x831FA3
+#define SCU_RAM_QAM_LC_EI_COARSE__W 16
+#define SCU_RAM_QAM_LC_EI_COARSE__M 0xFFFF
+#define SCU_RAM_QAM_LC_EI_COARSE__PRE 0x0
+
+#define SCU_RAM_QAM_LC_EI_COARSE_BIT__B 0
+#define SCU_RAM_QAM_LC_EI_COARSE_BIT__W 8
+#define SCU_RAM_QAM_LC_EI_COARSE_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_EI_COARSE_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LC_EI_MEDIUM__A 0x831FA4
+#define SCU_RAM_QAM_LC_EI_MEDIUM__W 16
+#define SCU_RAM_QAM_LC_EI_MEDIUM__M 0xFFFF
+#define SCU_RAM_QAM_LC_EI_MEDIUM__PRE 0x0
+
+#define SCU_RAM_QAM_LC_EI_MEDIUM_BIT__B 0
+#define SCU_RAM_QAM_LC_EI_MEDIUM_BIT__W 8
+#define SCU_RAM_QAM_LC_EI_MEDIUM_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_EI_MEDIUM_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LC_EI_FINE__A 0x831FA5
+#define SCU_RAM_QAM_LC_EI_FINE__W 16
+#define SCU_RAM_QAM_LC_EI_FINE__M 0xFFFF
+#define SCU_RAM_QAM_LC_EI_FINE__PRE 0x0
+
+#define SCU_RAM_QAM_LC_EI_FINE_BIT__B 0
+#define SCU_RAM_QAM_LC_EI_FINE_BIT__W 8
+#define SCU_RAM_QAM_LC_EI_FINE_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_EI_FINE_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CF_COARSE__A 0x831FA6
+#define SCU_RAM_QAM_LC_CF_COARSE__W 16
+#define SCU_RAM_QAM_LC_CF_COARSE__M 0xFFFF
+#define SCU_RAM_QAM_LC_CF_COARSE__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CF_COARSE_BIT__B 0
+#define SCU_RAM_QAM_LC_CF_COARSE_BIT__W 8
+#define SCU_RAM_QAM_LC_CF_COARSE_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_CF_COARSE_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CF_MEDIUM__A 0x831FA7
+#define SCU_RAM_QAM_LC_CF_MEDIUM__W 16
+#define SCU_RAM_QAM_LC_CF_MEDIUM__M 0xFFFF
+#define SCU_RAM_QAM_LC_CF_MEDIUM__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CF_MEDIUM_BIT__B 0
+#define SCU_RAM_QAM_LC_CF_MEDIUM_BIT__W 8
+#define SCU_RAM_QAM_LC_CF_MEDIUM_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_CF_MEDIUM_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CF_FINE__A 0x831FA8
+#define SCU_RAM_QAM_LC_CF_FINE__W 16
+#define SCU_RAM_QAM_LC_CF_FINE__M 0xFFFF
+#define SCU_RAM_QAM_LC_CF_FINE__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CF_FINE_BIT__B 0
+#define SCU_RAM_QAM_LC_CF_FINE_BIT__W 8
+#define SCU_RAM_QAM_LC_CF_FINE_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_CF_FINE_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CF1_COARSE__A 0x831FA9
+#define SCU_RAM_QAM_LC_CF1_COARSE__W 16
+#define SCU_RAM_QAM_LC_CF1_COARSE__M 0xFFFF
+#define SCU_RAM_QAM_LC_CF1_COARSE__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CF1_COARSE_BIT__B 0
+#define SCU_RAM_QAM_LC_CF1_COARSE_BIT__W 8
+#define SCU_RAM_QAM_LC_CF1_COARSE_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_CF1_COARSE_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CF1_MEDIUM__A 0x831FAA
+#define SCU_RAM_QAM_LC_CF1_MEDIUM__W 16
+#define SCU_RAM_QAM_LC_CF1_MEDIUM__M 0xFFFF
+#define SCU_RAM_QAM_LC_CF1_MEDIUM__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CF1_MEDIUM_BIT__B 0
+#define SCU_RAM_QAM_LC_CF1_MEDIUM_BIT__W 8
+#define SCU_RAM_QAM_LC_CF1_MEDIUM_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_CF1_MEDIUM_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CF1_FINE__A 0x831FAB
+#define SCU_RAM_QAM_LC_CF1_FINE__W 16
+#define SCU_RAM_QAM_LC_CF1_FINE__M 0xFFFF
+#define SCU_RAM_QAM_LC_CF1_FINE__PRE 0x0
+
+#define SCU_RAM_QAM_LC_CF1_FINE_BIT__B 0
+#define SCU_RAM_QAM_LC_CF1_FINE_BIT__W 8
+#define SCU_RAM_QAM_LC_CF1_FINE_BIT__M 0xFF
+#define SCU_RAM_QAM_LC_CF1_FINE_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_SL_SIG_POWER__A 0x831FAC
+#define SCU_RAM_QAM_SL_SIG_POWER__W 16
+#define SCU_RAM_QAM_SL_SIG_POWER__M 0xFFFF
+#define SCU_RAM_QAM_SL_SIG_POWER__PRE 0x0
+
+#define SCU_RAM_QAM_SL_SIG_POWER_BIT__B 0
+#define SCU_RAM_QAM_SL_SIG_POWER_BIT__W 16
+#define SCU_RAM_QAM_SL_SIG_POWER_BIT__M 0xFFFF
+#define SCU_RAM_QAM_SL_SIG_POWER_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_EQ_CMA_RAD0__A 0x831FAD
+#define SCU_RAM_QAM_EQ_CMA_RAD0__W 14
+#define SCU_RAM_QAM_EQ_CMA_RAD0__M 0x3FFF
+#define SCU_RAM_QAM_EQ_CMA_RAD0__PRE 0x0
+
+#define SCU_RAM_QAM_EQ_CMA_RAD0_BIT__B 0
+#define SCU_RAM_QAM_EQ_CMA_RAD0_BIT__W 14
+#define SCU_RAM_QAM_EQ_CMA_RAD0_BIT__M 0x3FFF
+#define SCU_RAM_QAM_EQ_CMA_RAD0_BIT__PRE 0x0
+#define SCU_RAM_QAM_EQ_CMA_RAD0_BIT_QAM_16 0x34CD
+#define SCU_RAM_QAM_EQ_CMA_RAD0_BIT_QAM_32 0x1A33
+#define SCU_RAM_QAM_EQ_CMA_RAD0_BIT_QAM_64 0x3418
+#define SCU_RAM_QAM_EQ_CMA_RAD0_BIT_QAM_128 0x1814
+#define SCU_RAM_QAM_EQ_CMA_RAD0_BIT_QAM_256 0x2CEE
+
+#define SCU_RAM_QAM_EQ_CMA_RAD1__A 0x831FAE
+#define SCU_RAM_QAM_EQ_CMA_RAD1__W 14
+#define SCU_RAM_QAM_EQ_CMA_RAD1__M 0x3FFF
+#define SCU_RAM_QAM_EQ_CMA_RAD1__PRE 0x0
+
+#define SCU_RAM_QAM_EQ_CMA_RAD1_BIT__B 0
+#define SCU_RAM_QAM_EQ_CMA_RAD1_BIT__W 14
+#define SCU_RAM_QAM_EQ_CMA_RAD1_BIT__M 0x3FFF
+#define SCU_RAM_QAM_EQ_CMA_RAD1_BIT__PRE 0x0
+#define SCU_RAM_QAM_EQ_CMA_RAD1_BIT_QAM_16 0x34CD
+#define SCU_RAM_QAM_EQ_CMA_RAD1_BIT_QAM_32 0x1A33
+#define SCU_RAM_QAM_EQ_CMA_RAD1_BIT_QAM_64 0x314A
+#define SCU_RAM_QAM_EQ_CMA_RAD1_BIT_QAM_128 0x19C6
+#define SCU_RAM_QAM_EQ_CMA_RAD1_BIT_QAM_256 0x2F34
+
+#define SCU_RAM_QAM_EQ_CMA_RAD2__A 0x831FAF
+#define SCU_RAM_QAM_EQ_CMA_RAD2__W 14
+#define SCU_RAM_QAM_EQ_CMA_RAD2__M 0x3FFF
+#define SCU_RAM_QAM_EQ_CMA_RAD2__PRE 0x0
+
+#define SCU_RAM_QAM_EQ_CMA_RAD2_BIT__B 0
+#define SCU_RAM_QAM_EQ_CMA_RAD2_BIT__W 14
+#define SCU_RAM_QAM_EQ_CMA_RAD2_BIT__M 0x3FFF
+#define SCU_RAM_QAM_EQ_CMA_RAD2_BIT__PRE 0x0
+#define SCU_RAM_QAM_EQ_CMA_RAD2_BIT_QAM_16 0x34CD
+#define SCU_RAM_QAM_EQ_CMA_RAD2_BIT_QAM_32 0x1A33
+#define SCU_RAM_QAM_EQ_CMA_RAD2_BIT_QAM_64 0x2ED4
+#define SCU_RAM_QAM_EQ_CMA_RAD2_BIT_QAM_128 0x18FA
+#define SCU_RAM_QAM_EQ_CMA_RAD2_BIT_QAM_256 0x30FF
+
+#define SCU_RAM_QAM_EQ_CMA_RAD3__A 0x831FB0
+#define SCU_RAM_QAM_EQ_CMA_RAD3__W 14
+#define SCU_RAM_QAM_EQ_CMA_RAD3__M 0x3FFF
+#define SCU_RAM_QAM_EQ_CMA_RAD3__PRE 0x0
+
+#define SCU_RAM_QAM_EQ_CMA_RAD3_BIT__B 0
+#define SCU_RAM_QAM_EQ_CMA_RAD3_BIT__W 14
+#define SCU_RAM_QAM_EQ_CMA_RAD3_BIT__M 0x3FFF
+#define SCU_RAM_QAM_EQ_CMA_RAD3_BIT__PRE 0x0
+#define SCU_RAM_QAM_EQ_CMA_RAD3_BIT_QAM_16 0x34CD
+#define SCU_RAM_QAM_EQ_CMA_RAD3_BIT_QAM_32 0x1A33
+#define SCU_RAM_QAM_EQ_CMA_RAD3_BIT_QAM_64 0x35F1
+#define SCU_RAM_QAM_EQ_CMA_RAD3_BIT_QAM_128 0x1909
+#define SCU_RAM_QAM_EQ_CMA_RAD3_BIT_QAM_256 0x3283
+
+#define SCU_RAM_QAM_EQ_CMA_RAD4__A 0x831FB1
+#define SCU_RAM_QAM_EQ_CMA_RAD4__W 14
+#define SCU_RAM_QAM_EQ_CMA_RAD4__M 0x3FFF
+#define SCU_RAM_QAM_EQ_CMA_RAD4__PRE 0x0
+
+#define SCU_RAM_QAM_EQ_CMA_RAD4_BIT__B 0
+#define SCU_RAM_QAM_EQ_CMA_RAD4_BIT__W 14
+#define SCU_RAM_QAM_EQ_CMA_RAD4_BIT__M 0x3FFF
+#define SCU_RAM_QAM_EQ_CMA_RAD4_BIT__PRE 0x0
+#define SCU_RAM_QAM_EQ_CMA_RAD4_BIT_QAM_16 0x34CD
+#define SCU_RAM_QAM_EQ_CMA_RAD4_BIT_QAM_32 0x1A33
+#define SCU_RAM_QAM_EQ_CMA_RAD4_BIT_QAM_64 0x35F1
+#define SCU_RAM_QAM_EQ_CMA_RAD4_BIT_QAM_128 0x1A00
+#define SCU_RAM_QAM_EQ_CMA_RAD4_BIT_QAM_256 0x353D
+
+#define SCU_RAM_QAM_EQ_CMA_RAD5__A 0x831FB2
+#define SCU_RAM_QAM_EQ_CMA_RAD5__W 14
+#define SCU_RAM_QAM_EQ_CMA_RAD5__M 0x3FFF
+#define SCU_RAM_QAM_EQ_CMA_RAD5__PRE 0x0
+
+#define SCU_RAM_QAM_EQ_CMA_RAD5_BIT__B 0
+#define SCU_RAM_QAM_EQ_CMA_RAD5_BIT__W 14
+#define SCU_RAM_QAM_EQ_CMA_RAD5_BIT__M 0x3FFF
+#define SCU_RAM_QAM_EQ_CMA_RAD5_BIT__PRE 0x0
+#define SCU_RAM_QAM_EQ_CMA_RAD5_BIT_QAM_16 0x34CD
+#define SCU_RAM_QAM_EQ_CMA_RAD5_BIT_QAM_32 0x1A33
+#define SCU_RAM_QAM_EQ_CMA_RAD5_BIT_QAM_64 0x3CF9
+#define SCU_RAM_QAM_EQ_CMA_RAD5_BIT_QAM_128 0x1C46
+#define SCU_RAM_QAM_EQ_CMA_RAD5_BIT_QAM_256 0x3C19
+
+#define SCU_RAM_QAM_CTL_ENA__A 0x831FB3
+#define SCU_RAM_QAM_CTL_ENA__W 16
+#define SCU_RAM_QAM_CTL_ENA__M 0xFFFF
+#define SCU_RAM_QAM_CTL_ENA__PRE 0x0
+
+#define SCU_RAM_QAM_CTL_ENA_AMP__B 0
+#define SCU_RAM_QAM_CTL_ENA_AMP__W 1
+#define SCU_RAM_QAM_CTL_ENA_AMP__M 0x1
+#define SCU_RAM_QAM_CTL_ENA_AMP__PRE 0x0
+
+#define SCU_RAM_QAM_CTL_ENA_ACQ__B 1
+#define SCU_RAM_QAM_CTL_ENA_ACQ__W 1
+#define SCU_RAM_QAM_CTL_ENA_ACQ__M 0x2
+#define SCU_RAM_QAM_CTL_ENA_ACQ__PRE 0x0
+
+#define SCU_RAM_QAM_CTL_ENA_EQU__B 2
+#define SCU_RAM_QAM_CTL_ENA_EQU__W 1
+#define SCU_RAM_QAM_CTL_ENA_EQU__M 0x4
+#define SCU_RAM_QAM_CTL_ENA_EQU__PRE 0x0
+
+#define SCU_RAM_QAM_CTL_ENA_SLC__B 3
+#define SCU_RAM_QAM_CTL_ENA_SLC__W 1
+#define SCU_RAM_QAM_CTL_ENA_SLC__M 0x8
+#define SCU_RAM_QAM_CTL_ENA_SLC__PRE 0x0
+
+#define SCU_RAM_QAM_CTL_ENA_LC__B 4
+#define SCU_RAM_QAM_CTL_ENA_LC__W 1
+#define SCU_RAM_QAM_CTL_ENA_LC__M 0x10
+#define SCU_RAM_QAM_CTL_ENA_LC__PRE 0x0
+
+#define SCU_RAM_QAM_CTL_ENA_AGC__B 5
+#define SCU_RAM_QAM_CTL_ENA_AGC__W 1
+#define SCU_RAM_QAM_CTL_ENA_AGC__M 0x20
+#define SCU_RAM_QAM_CTL_ENA_AGC__PRE 0x0
+
+#define SCU_RAM_QAM_CTL_ENA_FEC__B 6
+#define SCU_RAM_QAM_CTL_ENA_FEC__W 1
+#define SCU_RAM_QAM_CTL_ENA_FEC__M 0x40
+#define SCU_RAM_QAM_CTL_ENA_FEC__PRE 0x0
+
+#define SCU_RAM_QAM_CTL_ENA_AXIS__B 7
+#define SCU_RAM_QAM_CTL_ENA_AXIS__W 1
+#define SCU_RAM_QAM_CTL_ENA_AXIS__M 0x80
+#define SCU_RAM_QAM_CTL_ENA_AXIS__PRE 0x0
+
+#define SCU_RAM_QAM_CTL_ENA_FMHUM__B 8
+#define SCU_RAM_QAM_CTL_ENA_FMHUM__W 1
+#define SCU_RAM_QAM_CTL_ENA_FMHUM__M 0x100
+#define SCU_RAM_QAM_CTL_ENA_FMHUM__PRE 0x0
+
+#define SCU_RAM_QAM_CTL_ENA_EQTIME__B 9
+#define SCU_RAM_QAM_CTL_ENA_EQTIME__W 1
+#define SCU_RAM_QAM_CTL_ENA_EQTIME__M 0x200
+#define SCU_RAM_QAM_CTL_ENA_EQTIME__PRE 0x0
+
+#define SCU_RAM_QAM_CTL_ENA_EXTLCK__B 10
+#define SCU_RAM_QAM_CTL_ENA_EXTLCK__W 1
+#define SCU_RAM_QAM_CTL_ENA_EXTLCK__M 0x400
+#define SCU_RAM_QAM_CTL_ENA_EXTLCK__PRE 0x0
+
+#define SCU_RAM_QAM_WR_RSV_1__A 0x831FB4
+#define SCU_RAM_QAM_WR_RSV_1__W 16
+#define SCU_RAM_QAM_WR_RSV_1__M 0xFFFF
+#define SCU_RAM_QAM_WR_RSV_1__PRE 0x0
+
+#define SCU_RAM_QAM_WR_RSV_1_BIT__B 0
+#define SCU_RAM_QAM_WR_RSV_1_BIT__W 16
+#define SCU_RAM_QAM_WR_RSV_1_BIT__M 0xFFFF
+#define SCU_RAM_QAM_WR_RSV_1_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_WR_RSV_2__A 0x831FB5
+#define SCU_RAM_QAM_WR_RSV_2__W 16
+#define SCU_RAM_QAM_WR_RSV_2__M 0xFFFF
+#define SCU_RAM_QAM_WR_RSV_2__PRE 0x0
+
+#define SCU_RAM_QAM_WR_RSV_2_BIT__B 0
+#define SCU_RAM_QAM_WR_RSV_2_BIT__W 16
+#define SCU_RAM_QAM_WR_RSV_2_BIT__M 0xFFFF
+#define SCU_RAM_QAM_WR_RSV_2_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_WR_RSV_3__A 0x831FB6
+#define SCU_RAM_QAM_WR_RSV_3__W 16
+#define SCU_RAM_QAM_WR_RSV_3__M 0xFFFF
+#define SCU_RAM_QAM_WR_RSV_3__PRE 0x0
+
+#define SCU_RAM_QAM_WR_RSV_3_BIT__B 0
+#define SCU_RAM_QAM_WR_RSV_3_BIT__W 16
+#define SCU_RAM_QAM_WR_RSV_3_BIT__M 0xFFFF
+#define SCU_RAM_QAM_WR_RSV_3_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_ACTIVE_CONSTELLATION__A 0x831FB7
+#define SCU_RAM_QAM_ACTIVE_CONSTELLATION__W 3
+#define SCU_RAM_QAM_ACTIVE_CONSTELLATION__M 0x7
+#define SCU_RAM_QAM_ACTIVE_CONSTELLATION__PRE 0x0
+
+#define SCU_RAM_QAM_ACTIVE_CONSTELLATION_BIT__B 0
+#define SCU_RAM_QAM_ACTIVE_CONSTELLATION_BIT__W 3
+#define SCU_RAM_QAM_ACTIVE_CONSTELLATION_BIT__M 0x7
+#define SCU_RAM_QAM_ACTIVE_CONSTELLATION_BIT__PRE 0x0
+#define SCU_RAM_QAM_ACTIVE_CONSTELLATION_BIT_UNKNOWN 0x0
+#define SCU_RAM_QAM_ACTIVE_CONSTELLATION_BIT_QAM_16 0x3
+#define SCU_RAM_QAM_ACTIVE_CONSTELLATION_BIT_QAM_32 0x4
+#define SCU_RAM_QAM_ACTIVE_CONSTELLATION_BIT_QAM_64 0x5
+#define SCU_RAM_QAM_ACTIVE_CONSTELLATION_BIT_QAM_128 0x6
+#define SCU_RAM_QAM_ACTIVE_CONSTELLATION_BIT_QAM_256 0x7
+
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE__A 0x831FB8
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE__W 8
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE__M 0xFF
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE__PRE 0x0
+
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE_BIT__B 0
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE_BIT__W 8
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE_BIT__M 0xFF
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE_BIT__PRE 0x0
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE_BIT_I128_J1 0x0
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE_BIT_I128_J1_V2 0x1
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE_BIT_I128_J2 0x2
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE_BIT_I64_J2 0x3
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE_BIT_I128_J3 0x4
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE_BIT_I32_J4 0x5
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE_BIT_I128_J4 0x6
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE_BIT_I16_J8 0x7
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE_BIT_I128_J5 0x8
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE_BIT_I8_J16 0x9
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE_BIT_I128_J6 0xA
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE_BIT_I128_J7 0xC
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE_BIT_I128_J8 0xE
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE_BIT_I12_J17 0x10
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE_BIT_I5_J4 0x11
+#define SCU_RAM_QAM_ACTIVE_INTERLEAVE_BIT_UNKNOWN 0xFE
+
+#define SCU_RAM_QAM_RD_RSV_4__A 0x831FB9
+#define SCU_RAM_QAM_RD_RSV_4__W 16
+#define SCU_RAM_QAM_RD_RSV_4__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_4__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_4_BIT__B 0
+#define SCU_RAM_QAM_RD_RSV_4_BIT__W 16
+#define SCU_RAM_QAM_RD_RSV_4_BIT__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_4_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_LOCKED__A 0x831FBA
+#define SCU_RAM_QAM_LOCKED__W 16
+#define SCU_RAM_QAM_LOCKED__M 0xFFFF
+#define SCU_RAM_QAM_LOCKED__PRE 0x0
+
+#define SCU_RAM_QAM_LOCKED_INTLEVEL__B 0
+#define SCU_RAM_QAM_LOCKED_INTLEVEL__W 8
+#define SCU_RAM_QAM_LOCKED_INTLEVEL__M 0xFF
+#define SCU_RAM_QAM_LOCKED_INTLEVEL__PRE 0x0
+#define SCU_RAM_QAM_LOCKED_INTLEVEL_NOT_LOCKED 0x0
+#define SCU_RAM_QAM_LOCKED_INTLEVEL_AMP_OK 0x1
+#define SCU_RAM_QAM_LOCKED_INTLEVEL_RATE_OK 0x2
+#define SCU_RAM_QAM_LOCKED_INTLEVEL_FREQ_OK 0x3
+#define SCU_RAM_QAM_LOCKED_INTLEVEL_UPRIGHT_OK 0x4
+#define SCU_RAM_QAM_LOCKED_INTLEVEL_PHNOISE_OK 0x5
+#define SCU_RAM_QAM_LOCKED_INTLEVEL_TRACK_OK 0x6
+#define SCU_RAM_QAM_LOCKED_INTLEVEL_IMPNOISE_OK 0x7
+
+#define SCU_RAM_QAM_LOCKED_LOCKED__B 8
+#define SCU_RAM_QAM_LOCKED_LOCKED__W 8
+#define SCU_RAM_QAM_LOCKED_LOCKED__M 0xFF00
+#define SCU_RAM_QAM_LOCKED_LOCKED__PRE 0x0
+#define SCU_RAM_QAM_LOCKED_LOCKED_NOT_LOCKED 0x0
+#define SCU_RAM_QAM_LOCKED_LOCKED_DEMOD_LOCKED 0x4000
+#define SCU_RAM_QAM_LOCKED_LOCKED_LOCKED 0x8000
+#define SCU_RAM_QAM_LOCKED_LOCKED_NEVER_LOCK 0xC000
+
+#define SCU_RAM_QAM_EVENTS_OCC_HI__A 0x831FBB
+#define SCU_RAM_QAM_EVENTS_OCC_HI__W 16
+#define SCU_RAM_QAM_EVENTS_OCC_HI__M 0xFFFF
+#define SCU_RAM_QAM_EVENTS_OCC_HI__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_HI_PREBER__B 0
+#define SCU_RAM_QAM_EVENTS_OCC_HI_PREBER__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_HI_PREBER__M 0x1
+#define SCU_RAM_QAM_EVENTS_OCC_HI_PREBER__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_HI_PACKET_FAIL__B 1
+#define SCU_RAM_QAM_EVENTS_OCC_HI_PACKET_FAIL__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_HI_PACKET_FAIL__M 0x2
+#define SCU_RAM_QAM_EVENTS_OCC_HI_PACKET_FAIL__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_HI_PRBS__B 2
+#define SCU_RAM_QAM_EVENTS_OCC_HI_PRBS__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_HI_PRBS__M 0x4
+#define SCU_RAM_QAM_EVENTS_OCC_HI_PRBS__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_HI_OC_LOCK_IN__B 3
+#define SCU_RAM_QAM_EVENTS_OCC_HI_OC_LOCK_IN__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_HI_OC_LOCK_IN__M 0x8
+#define SCU_RAM_QAM_EVENTS_OCC_HI_OC_LOCK_IN__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_HI_OC_LOCK_OUT__B 4
+#define SCU_RAM_QAM_EVENTS_OCC_HI_OC_LOCK_OUT__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_HI_OC_LOCK_OUT__M 0x10
+#define SCU_RAM_QAM_EVENTS_OCC_HI_OC_LOCK_OUT__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_HI_POSTBER__B 5
+#define SCU_RAM_QAM_EVENTS_OCC_HI_POSTBER__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_HI_POSTBER__M 0x20
+#define SCU_RAM_QAM_EVENTS_OCC_HI_POSTBER__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_HI_FIFO_FULL__B 6
+#define SCU_RAM_QAM_EVENTS_OCC_HI_FIFO_FULL__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_HI_FIFO_FULL__M 0x40
+#define SCU_RAM_QAM_EVENTS_OCC_HI_FIFO_FULL__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_HI_FIFO_EMPTY__B 7
+#define SCU_RAM_QAM_EVENTS_OCC_HI_FIFO_EMPTY__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_HI_FIFO_EMPTY__M 0x80
+#define SCU_RAM_QAM_EVENTS_OCC_HI_FIFO_EMPTY__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_HI_OC_GRAB__B 8
+#define SCU_RAM_QAM_EVENTS_OCC_HI_OC_GRAB__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_HI_OC_GRAB__M 0x100
+#define SCU_RAM_QAM_EVENTS_OCC_HI_OC_GRAB__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_HI_OC_CHANGE__B 9
+#define SCU_RAM_QAM_EVENTS_OCC_HI_OC_CHANGE__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_HI_OC_CHANGE__M 0x200
+#define SCU_RAM_QAM_EVENTS_OCC_HI_OC_CHANGE__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_HI_LCK_CHG__B 10
+#define SCU_RAM_QAM_EVENTS_OCC_HI_LCK_CHG__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_HI_LCK_CHG__M 0x400
+#define SCU_RAM_QAM_EVENTS_OCC_HI_LCK_CHG__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_HI_FSM_CHG__B 11
+#define SCU_RAM_QAM_EVENTS_OCC_HI_FSM_CHG__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_HI_FSM_CHG__M 0x800
+#define SCU_RAM_QAM_EVENTS_OCC_HI_FSM_CHG__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_HI_RSV__B 12
+#define SCU_RAM_QAM_EVENTS_OCC_HI_RSV__W 4
+#define SCU_RAM_QAM_EVENTS_OCC_HI_RSV__M 0xF000
+#define SCU_RAM_QAM_EVENTS_OCC_HI_RSV__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_LO__A 0x831FBC
+#define SCU_RAM_QAM_EVENTS_OCC_LO__W 16
+#define SCU_RAM_QAM_EVENTS_OCC_LO__M 0xFFFF
+#define SCU_RAM_QAM_EVENTS_OCC_LO__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_LO_TIMER__B 0
+#define SCU_RAM_QAM_EVENTS_OCC_LO_TIMER__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_LO_TIMER__M 0x1
+#define SCU_RAM_QAM_EVENTS_OCC_LO_TIMER__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_LO_CLIP__B 1
+#define SCU_RAM_QAM_EVENTS_OCC_LO_CLIP__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_LO_CLIP__M 0x2
+#define SCU_RAM_QAM_EVENTS_OCC_LO_CLIP__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SENSE__B 2
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SENSE__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SENSE__M 0x4
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SENSE__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_LO_POWER__B 3
+#define SCU_RAM_QAM_EVENTS_OCC_LO_POWER__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_LO_POWER__M 0x8
+#define SCU_RAM_QAM_EVENTS_OCC_LO_POWER__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_LO_MEDIAN__B 4
+#define SCU_RAM_QAM_EVENTS_OCC_LO_MEDIAN__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_LO_MEDIAN__M 0x10
+#define SCU_RAM_QAM_EVENTS_OCC_LO_MEDIAN__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_LO_MER__B 5
+#define SCU_RAM_QAM_EVENTS_OCC_LO_MER__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_LO_MER__M 0x20
+#define SCU_RAM_QAM_EVENTS_OCC_LO_MER__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_LO_LOOP__B 6
+#define SCU_RAM_QAM_EVENTS_OCC_LO_LOOP__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_LO_LOOP__M 0x40
+#define SCU_RAM_QAM_EVENTS_OCC_LO_LOOP__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_LO_FREQWRAP__B 7
+#define SCU_RAM_QAM_EVENTS_OCC_LO_FREQWRAP__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_LO_FREQWRAP__M 0x80
+#define SCU_RAM_QAM_EVENTS_OCC_LO_FREQWRAP__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SER__B 8
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SER__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SER__M 0x100
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SER__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_LO_VD_LOCK_IN__B 9
+#define SCU_RAM_QAM_EVENTS_OCC_LO_VD_LOCK_IN__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_LO_VD_LOCK_IN__M 0x200
+#define SCU_RAM_QAM_EVENTS_OCC_LO_VD_LOCK_IN__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SY_LOCK_IN__B 10
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SY_LOCK_IN__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SY_LOCK_IN__M 0x400
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SY_LOCK_IN__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SY_LOCK_OUT__B 11
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SY_LOCK_OUT__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SY_LOCK_OUT__M 0x800
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SY_LOCK_OUT__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SY_TIME_OUT__B 12
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SY_TIME_OUT__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SY_TIME_OUT__M 0x1000
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SY_TIME_OUT__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SYNCWORD__B 13
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SYNCWORD__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SYNCWORD__M 0x2000
+#define SCU_RAM_QAM_EVENTS_OCC_LO_SYNCWORD__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_LO_DI_LOCK_IN__B 14
+#define SCU_RAM_QAM_EVENTS_OCC_LO_DI_LOCK_IN__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_LO_DI_LOCK_IN__M 0x4000
+#define SCU_RAM_QAM_EVENTS_OCC_LO_DI_LOCK_IN__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_OCC_LO_DI_LOCK_OUT__B 15
+#define SCU_RAM_QAM_EVENTS_OCC_LO_DI_LOCK_OUT__W 1
+#define SCU_RAM_QAM_EVENTS_OCC_LO_DI_LOCK_OUT__M 0x8000
+#define SCU_RAM_QAM_EVENTS_OCC_LO_DI_LOCK_OUT__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_SCHED_HI__A 0x831FBD
+#define SCU_RAM_QAM_EVENTS_SCHED_HI__W 16
+#define SCU_RAM_QAM_EVENTS_SCHED_HI__M 0xFFFF
+#define SCU_RAM_QAM_EVENTS_SCHED_HI__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_SCHED_HI_BIT__B 0
+#define SCU_RAM_QAM_EVENTS_SCHED_HI_BIT__W 16
+#define SCU_RAM_QAM_EVENTS_SCHED_HI_BIT__M 0xFFFF
+#define SCU_RAM_QAM_EVENTS_SCHED_HI_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_SCHED_LO__A 0x831FBE
+#define SCU_RAM_QAM_EVENTS_SCHED_LO__W 16
+#define SCU_RAM_QAM_EVENTS_SCHED_LO__M 0xFFFF
+#define SCU_RAM_QAM_EVENTS_SCHED_LO__PRE 0x0
+
+#define SCU_RAM_QAM_EVENTS_SCHED_LO_BIT__B 0
+#define SCU_RAM_QAM_EVENTS_SCHED_LO_BIT__W 16
+#define SCU_RAM_QAM_EVENTS_SCHED_LO_BIT__M 0xFFFF
+#define SCU_RAM_QAM_EVENTS_SCHED_LO_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_TASKLETS_SCHED__A 0x831FBF
+#define SCU_RAM_QAM_TASKLETS_SCHED__W 16
+#define SCU_RAM_QAM_TASKLETS_SCHED__M 0xFFFF
+#define SCU_RAM_QAM_TASKLETS_SCHED__PRE 0x0
+
+#define SCU_RAM_QAM_TASKLETS_SCHED_BIT__B 0
+#define SCU_RAM_QAM_TASKLETS_SCHED_BIT__W 16
+#define SCU_RAM_QAM_TASKLETS_SCHED_BIT__M 0xFFFF
+#define SCU_RAM_QAM_TASKLETS_SCHED_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_TASKLETS_RUN__A 0x831FC0
+#define SCU_RAM_QAM_TASKLETS_RUN__W 16
+#define SCU_RAM_QAM_TASKLETS_RUN__M 0xFFFF
+#define SCU_RAM_QAM_TASKLETS_RUN__PRE 0x0
+
+#define SCU_RAM_QAM_TASKLETS_RUN_BIT__B 0
+#define SCU_RAM_QAM_TASKLETS_RUN_BIT__W 16
+#define SCU_RAM_QAM_TASKLETS_RUN_BIT__M 0xFFFF
+#define SCU_RAM_QAM_TASKLETS_RUN_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_ACTIVE_SYM_RCRATE_HI__A 0x831FC1
+#define SCU_RAM_QAM_ACTIVE_SYM_RCRATE_HI__W 16
+#define SCU_RAM_QAM_ACTIVE_SYM_RCRATE_HI__M 0xFFFF
+#define SCU_RAM_QAM_ACTIVE_SYM_RCRATE_HI__PRE 0x0
+
+#define SCU_RAM_QAM_ACTIVE_SYM_RCRATE_HI_BIT__B 0
+#define SCU_RAM_QAM_ACTIVE_SYM_RCRATE_HI_BIT__W 16
+#define SCU_RAM_QAM_ACTIVE_SYM_RCRATE_HI_BIT__M 0xFFFF
+#define SCU_RAM_QAM_ACTIVE_SYM_RCRATE_HI_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_ACTIVE_SYM_RCRATE_LO__A 0x831FC2
+#define SCU_RAM_QAM_ACTIVE_SYM_RCRATE_LO__W 16
+#define SCU_RAM_QAM_ACTIVE_SYM_RCRATE_LO__M 0xFFFF
+#define SCU_RAM_QAM_ACTIVE_SYM_RCRATE_LO__PRE 0x0
+
+#define SCU_RAM_QAM_ACTIVE_SYM_RCRATE_LO_BIT__B 0
+#define SCU_RAM_QAM_ACTIVE_SYM_RCRATE_LO_BIT__W 16
+#define SCU_RAM_QAM_ACTIVE_SYM_RCRATE_LO_BIT__M 0xFFFF
+#define SCU_RAM_QAM_ACTIVE_SYM_RCRATE_LO_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_5__A 0x831FC3
+#define SCU_RAM_QAM_RD_RSV_5__W 16
+#define SCU_RAM_QAM_RD_RSV_5__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_5__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_5_BIT__B 0
+#define SCU_RAM_QAM_RD_RSV_5_BIT__W 16
+#define SCU_RAM_QAM_RD_RSV_5_BIT__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_5_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_6__A 0x831FC4
+#define SCU_RAM_QAM_RD_RSV_6__W 16
+#define SCU_RAM_QAM_RD_RSV_6__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_6__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_6_BIT__B 0
+#define SCU_RAM_QAM_RD_RSV_6_BIT__W 16
+#define SCU_RAM_QAM_RD_RSV_6_BIT__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_6_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_7__A 0x831FC5
+#define SCU_RAM_QAM_RD_RSV_7__W 16
+#define SCU_RAM_QAM_RD_RSV_7__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_7__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_7_BIT__B 0
+#define SCU_RAM_QAM_RD_RSV_7_BIT__W 16
+#define SCU_RAM_QAM_RD_RSV_7_BIT__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_7_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_8__A 0x831FC6
+#define SCU_RAM_QAM_RD_RSV_8__W 16
+#define SCU_RAM_QAM_RD_RSV_8__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_8__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_8_BIT__B 0
+#define SCU_RAM_QAM_RD_RSV_8_BIT__W 16
+#define SCU_RAM_QAM_RD_RSV_8_BIT__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_8_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_9__A 0x831FC7
+#define SCU_RAM_QAM_RD_RSV_9__W 16
+#define SCU_RAM_QAM_RD_RSV_9__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_9__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_9_BIT__B 0
+#define SCU_RAM_QAM_RD_RSV_9_BIT__W 16
+#define SCU_RAM_QAM_RD_RSV_9_BIT__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_9_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_10__A 0x831FC8
+#define SCU_RAM_QAM_RD_RSV_10__W 16
+#define SCU_RAM_QAM_RD_RSV_10__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_10__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_10_BIT__B 0
+#define SCU_RAM_QAM_RD_RSV_10_BIT__W 16
+#define SCU_RAM_QAM_RD_RSV_10_BIT__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_10_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_AGC_TPOW_OFFS__A 0x831FC9
+#define SCU_RAM_QAM_AGC_TPOW_OFFS__W 16
+#define SCU_RAM_QAM_AGC_TPOW_OFFS__M 0xFFFF
+#define SCU_RAM_QAM_AGC_TPOW_OFFS__PRE 0x0
+
+#define SCU_RAM_QAM_AGC_TPOW_OFFS_BIT__B 0
+#define SCU_RAM_QAM_AGC_TPOW_OFFS_BIT__W 16
+#define SCU_RAM_QAM_AGC_TPOW_OFFS_BIT__M 0xFFFF
+#define SCU_RAM_QAM_AGC_TPOW_OFFS_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_STATE__A 0x831FCA
+#define SCU_RAM_QAM_FSM_STATE__W 4
+#define SCU_RAM_QAM_FSM_STATE__M 0xF
+#define SCU_RAM_QAM_FSM_STATE__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_STATE_BIT__B 0
+#define SCU_RAM_QAM_FSM_STATE_BIT__W 4
+#define SCU_RAM_QAM_FSM_STATE_BIT__M 0xF
+#define SCU_RAM_QAM_FSM_STATE_BIT__PRE 0x0
+#define SCU_RAM_QAM_FSM_STATE_BIT_HUNTING_AMP 0x0
+#define SCU_RAM_QAM_FSM_STATE_BIT_HUNTING_RATE 0x1
+#define SCU_RAM_QAM_FSM_STATE_BIT_HUNTING_FREQ 0x2
+#define SCU_RAM_QAM_FSM_STATE_BIT_HUNTING_UPRIGHT 0x3
+#define SCU_RAM_QAM_FSM_STATE_BIT_HUNTING_PHASE 0x4
+#define SCU_RAM_QAM_FSM_STATE_BIT_TRACKING_PHNOISE 0x5
+#define SCU_RAM_QAM_FSM_STATE_BIT_TRACKING 0x6
+#define SCU_RAM_QAM_FSM_STATE_BIT_TRACKING_BURST 0x7
+
+#define SCU_RAM_QAM_FSM_STATE_NEW__A 0x831FCB
+#define SCU_RAM_QAM_FSM_STATE_NEW__W 4
+#define SCU_RAM_QAM_FSM_STATE_NEW__M 0xF
+#define SCU_RAM_QAM_FSM_STATE_NEW__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_STATE_NEW_BIT__B 0
+#define SCU_RAM_QAM_FSM_STATE_NEW_BIT__W 4
+#define SCU_RAM_QAM_FSM_STATE_NEW_BIT__M 0xF
+#define SCU_RAM_QAM_FSM_STATE_NEW_BIT__PRE 0x0
+#define SCU_RAM_QAM_FSM_STATE_NEW_BIT_HUNTING_AMP 0x0
+#define SCU_RAM_QAM_FSM_STATE_NEW_BIT_HUNTING_RATE 0x1
+#define SCU_RAM_QAM_FSM_STATE_NEW_BIT_HUNTING_FREQ 0x2
+#define SCU_RAM_QAM_FSM_STATE_NEW_BIT_HUNTING_UPRIGHT 0x3
+#define SCU_RAM_QAM_FSM_STATE_NEW_BIT_HUNTING_PHASE 0x4
+#define SCU_RAM_QAM_FSM_STATE_NEW_BIT_TRACKING_PHNOISE 0x5
+#define SCU_RAM_QAM_FSM_STATE_NEW_BIT_TRACKING 0x6
+#define SCU_RAM_QAM_FSM_STATE_NEW_BIT_TRACKING_BURST 0x7
+
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS__A 0x831FCC
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS__W 9
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS__M 0x1FF
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_AMP__B 0
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_AMP__W 1
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_AMP__M 0x1
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_AMP__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_RATEVAR__B 1
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_RATEVAR__W 1
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_RATEVAR__M 0x2
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_RATEVAR__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_RADIUS__B 2
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_RADIUS__W 1
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_RADIUS__M 0x4
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_RADIUS__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_FREQ__B 3
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_FREQ__W 1
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_FREQ__M 0x8
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_FREQ__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_FREQVAR__B 4
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_FREQVAR__W 1
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_FREQVAR__M 0x10
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_FREQVAR__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_CPHASE__B 5
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_CPHASE__W 1
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_CPHASE__M 0x20
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_CPHASE__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_UPRIGHT__B 6
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_UPRIGHT__W 1
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_UPRIGHT__M 0x40
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_UPRIGHT__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_PHASE__B 7
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_PHASE__W 1
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_PHASE__M 0x80
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_PHASE__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_MEDIAN__B 8
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_MEDIAN__W 1
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_MEDIAN__M 0x100
+#define SCU_RAM_QAM_FSM_LOCK_FLAGS_LCK_MEDIAN__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_RATE_VARIATION__A 0x831FCD
+#define SCU_RAM_QAM_FSM_RATE_VARIATION__W 16
+#define SCU_RAM_QAM_FSM_RATE_VARIATION__M 0xFFFF
+#define SCU_RAM_QAM_FSM_RATE_VARIATION__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_RATE_VARIATION_BIT__B 0
+#define SCU_RAM_QAM_FSM_RATE_VARIATION_BIT__W 16
+#define SCU_RAM_QAM_FSM_RATE_VARIATION_BIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_RATE_VARIATION_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_FREQ_VARIATION__A 0x831FCE
+#define SCU_RAM_QAM_FSM_FREQ_VARIATION__W 16
+#define SCU_RAM_QAM_FSM_FREQ_VARIATION__M 0xFFFF
+#define SCU_RAM_QAM_FSM_FREQ_VARIATION__PRE 0x0
+
+#define SCU_RAM_QAM_FSM_FREQ_VARIATION_BIT__B 0
+#define SCU_RAM_QAM_FSM_FREQ_VARIATION_BIT__W 16
+#define SCU_RAM_QAM_FSM_FREQ_VARIATION_BIT__M 0xFFFF
+#define SCU_RAM_QAM_FSM_FREQ_VARIATION_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_ERR_STATE__A 0x831FCF
+#define SCU_RAM_QAM_ERR_STATE__W 4
+#define SCU_RAM_QAM_ERR_STATE__M 0xF
+#define SCU_RAM_QAM_ERR_STATE__PRE 0x0
+
+#define SCU_RAM_QAM_ERR_STATE_BIT__B 0
+#define SCU_RAM_QAM_ERR_STATE_BIT__W 4
+#define SCU_RAM_QAM_ERR_STATE_BIT__M 0xF
+#define SCU_RAM_QAM_ERR_STATE_BIT__PRE 0x0
+#define SCU_RAM_QAM_ERR_STATE_BIT_HUNTING_AMP 0x0
+#define SCU_RAM_QAM_ERR_STATE_BIT_HUNTING_RATE 0x1
+#define SCU_RAM_QAM_ERR_STATE_BIT_HUNTING_FREQ 0x2
+#define SCU_RAM_QAM_ERR_STATE_BIT_HUNTING_UPRIGHT 0x3
+#define SCU_RAM_QAM_ERR_STATE_BIT_HUNTING_PHASE 0x4
+#define SCU_RAM_QAM_ERR_STATE_BIT_TRACKING_PHNOISE 0x5
+#define SCU_RAM_QAM_ERR_STATE_BIT_TRACKING 0x6
+#define SCU_RAM_QAM_ERR_STATE_BIT_TRACKING_BURST 0x7
+
+#define SCU_RAM_QAM_ERR_LOCK_FLAGS__A 0x831FD0
+#define SCU_RAM_QAM_ERR_LOCK_FLAGS__W 9
+#define SCU_RAM_QAM_ERR_LOCK_FLAGS__M 0x1FF
+#define SCU_RAM_QAM_ERR_LOCK_FLAGS__PRE 0x0
+
+#define SCU_RAM_QAM_ERR_LOCK_FLAGS_LCK_AMP__B 0
+#define SCU_RAM_QAM_ERR_LOCK_FLAGS_LCK_AMP__W 1
+#define SCU_RAM_QAM_ERR_LOCK_FLAGS_LCK_AMP__M 0x1
+#define SCU_RAM_QAM_ERR_LOCK_FLAGS_LCK_AMP__PRE 0x0
+
+#define SCU_RAM_QAM_EQ_LOCK__A 0x831FD1
+#define SCU_RAM_QAM_EQ_LOCK__W 1
+#define SCU_RAM_QAM_EQ_LOCK__M 0x1
+#define SCU_RAM_QAM_EQ_LOCK__PRE 0x0
+
+#define SCU_RAM_QAM_EQ_LOCK_BIT__B 0
+#define SCU_RAM_QAM_EQ_LOCK_BIT__W 1
+#define SCU_RAM_QAM_EQ_LOCK_BIT__M 0x1
+#define SCU_RAM_QAM_EQ_LOCK_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_EQ_STATE__A 0x831FD2
+#define SCU_RAM_QAM_EQ_STATE__W 16
+#define SCU_RAM_QAM_EQ_STATE__M 0xFFFF
+#define SCU_RAM_QAM_EQ_STATE__PRE 0x0
+
+#define SCU_RAM_QAM_EQ_STATE_BIT__B 0
+#define SCU_RAM_QAM_EQ_STATE_BIT__W 16
+#define SCU_RAM_QAM_EQ_STATE_BIT__M 0xFFFF
+#define SCU_RAM_QAM_EQ_STATE_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_0__A 0x831FD3
+#define SCU_RAM_QAM_RD_RSV_0__W 16
+#define SCU_RAM_QAM_RD_RSV_0__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_0__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_0_BIT__B 0
+#define SCU_RAM_QAM_RD_RSV_0_BIT__W 16
+#define SCU_RAM_QAM_RD_RSV_0_BIT__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_0_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_1__A 0x831FD4
+#define SCU_RAM_QAM_RD_RSV_1__W 16
+#define SCU_RAM_QAM_RD_RSV_1__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_1__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_1_BIT__B 0
+#define SCU_RAM_QAM_RD_RSV_1_BIT__W 16
+#define SCU_RAM_QAM_RD_RSV_1_BIT__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_1_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_2__A 0x831FD5
+#define SCU_RAM_QAM_RD_RSV_2__W 16
+#define SCU_RAM_QAM_RD_RSV_2__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_2__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_2_BIT__B 0
+#define SCU_RAM_QAM_RD_RSV_2_BIT__W 16
+#define SCU_RAM_QAM_RD_RSV_2_BIT__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_2_BIT__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_3__A 0x831FD6
+#define SCU_RAM_QAM_RD_RSV_3__W 16
+#define SCU_RAM_QAM_RD_RSV_3__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_3__PRE 0x0
+
+#define SCU_RAM_QAM_RD_RSV_3_BIT__B 0
+#define SCU_RAM_QAM_RD_RSV_3_BIT__W 16
+#define SCU_RAM_QAM_RD_RSV_3_BIT__M 0xFFFF
+#define SCU_RAM_QAM_RD_RSV_3_BIT__PRE 0x0
+
+#define SCU_RAM_VSB_CTL_MODE__A 0x831FD7
+#define SCU_RAM_VSB_CTL_MODE__W 2
+#define SCU_RAM_VSB_CTL_MODE__M 0x3
+#define SCU_RAM_VSB_CTL_MODE__PRE 0x0
+
+#define SCU_RAM_VSB_CTL_MODE_VSB_CTL_MODE_AGC__B 0
+#define SCU_RAM_VSB_CTL_MODE_VSB_CTL_MODE_AGC__W 1
+#define SCU_RAM_VSB_CTL_MODE_VSB_CTL_MODE_AGC__M 0x1
+#define SCU_RAM_VSB_CTL_MODE_VSB_CTL_MODE_AGC__PRE 0x0
+#define SCU_RAM_VSB_CTL_MODE_VSB_CTL_MODE_AGC_OFF 0x0
+#define SCU_RAM_VSB_CTL_MODE_VSB_CTL_MODE_AGC_ON 0x1
+
+#define SCU_RAM_VSB_CTL_MODE_VSB_CTL_MODE_MON__B 1
+#define SCU_RAM_VSB_CTL_MODE_VSB_CTL_MODE_MON__W 1
+#define SCU_RAM_VSB_CTL_MODE_VSB_CTL_MODE_MON__M 0x2
+#define SCU_RAM_VSB_CTL_MODE_VSB_CTL_MODE_MON__PRE 0x0
+#define SCU_RAM_VSB_CTL_MODE_VSB_CTL_MODE_MON_OFF 0x0
+#define SCU_RAM_VSB_CTL_MODE_VSB_CTL_MODE_MON_ON 0x2
+
+#define SCU_RAM_VSB_NOTCH_THRESHOLD__A 0x831FD8
+#define SCU_RAM_VSB_NOTCH_THRESHOLD__W 16
+#define SCU_RAM_VSB_NOTCH_THRESHOLD__M 0xFFFF
+#define SCU_RAM_VSB_NOTCH_THRESHOLD__PRE 0x0
+
+#define SCU_RAM_VSB_RSV_0__A 0x831FD9
+#define SCU_RAM_VSB_RSV_0__W 16
+#define SCU_RAM_VSB_RSV_0__M 0xFFFF
+#define SCU_RAM_VSB_RSV_0__PRE 0x0
+
+#define SCU_RAM_VSB_RSV_1__A 0x831FDA
+#define SCU_RAM_VSB_RSV_1__W 16
+#define SCU_RAM_VSB_RSV_1__M 0xFFFF
+#define SCU_RAM_VSB_RSV_1__PRE 0x0
+
+#define SCU_RAM_VSB_RSV_2__A 0x831FDB
+#define SCU_RAM_VSB_RSV_2__W 16
+#define SCU_RAM_VSB_RSV_2__M 0xFFFF
+#define SCU_RAM_VSB_RSV_2__PRE 0x0
+
+#define SCU_RAM_VSB_RSV_3__A 0x831FDC
+#define SCU_RAM_VSB_RSV_3__W 16
+#define SCU_RAM_VSB_RSV_3__M 0xFFFF
+#define SCU_RAM_VSB_RSV_3__PRE 0x0
+
+#define SCU_RAM_VSB_RSV_4__A 0x831FDD
+#define SCU_RAM_VSB_RSV_4__W 16
+#define SCU_RAM_VSB_RSV_4__M 0xFFFF
+#define SCU_RAM_VSB_RSV_4__PRE 0x0
+
+#define SCU_RAM_VSB_RSV_5__A 0x831FDE
+#define SCU_RAM_VSB_RSV_5__W 16
+#define SCU_RAM_VSB_RSV_5__M 0xFFFF
+#define SCU_RAM_VSB_RSV_5__PRE 0x0
+
+#define SCU_RAM_VSB_RSV_6__A 0x831FDF
+#define SCU_RAM_VSB_RSV_6__W 16
+#define SCU_RAM_VSB_RSV_6__M 0xFFFF
+#define SCU_RAM_VSB_RSV_6__PRE 0x0
+
+#define SCU_RAM_VSB_RSV_7__A 0x831FE0
+#define SCU_RAM_VSB_RSV_7__W 16
+#define SCU_RAM_VSB_RSV_7__M 0xFFFF
+#define SCU_RAM_VSB_RSV_7__PRE 0x0
+
+#define SCU_RAM_VSB_RSV_8__A 0x831FE1
+#define SCU_RAM_VSB_RSV_8__W 16
+#define SCU_RAM_VSB_RSV_8__M 0xFFFF
+#define SCU_RAM_VSB_RSV_8__PRE 0x0
+
+#define SCU_RAM_VSB_RSV_9__A 0x831FE2
+#define SCU_RAM_VSB_RSV_9__W 16
+#define SCU_RAM_VSB_RSV_9__M 0xFFFF
+#define SCU_RAM_VSB_RSV_9__PRE 0x0
+
+#define SCU_RAM_VSB_RSV_10__A 0x831FE3
+#define SCU_RAM_VSB_RSV_10__W 16
+#define SCU_RAM_VSB_RSV_10__M 0xFFFF
+#define SCU_RAM_VSB_RSV_10__PRE 0x0
+
+#define SCU_RAM_VSB_RSV_11__A 0x831FE4
+#define SCU_RAM_VSB_RSV_11__W 16
+#define SCU_RAM_VSB_RSV_11__M 0xFFFF
+#define SCU_RAM_VSB_RSV_11__PRE 0x0
+
+#define SCU_RAM_VSB_RSV_12__A 0x831FE5
+#define SCU_RAM_VSB_RSV_12__W 16
+#define SCU_RAM_VSB_RSV_12__M 0xFFFF
+#define SCU_RAM_VSB_RSV_12__PRE 0x0
+
+#define SCU_RAM_VSB_RSV_13__A 0x831FE6
+#define SCU_RAM_VSB_RSV_13__W 16
+#define SCU_RAM_VSB_RSV_13__M 0xFFFF
+#define SCU_RAM_VSB_RSV_13__PRE 0x0
+
+#define SCU_RAM_VSB_AGC_POW_TGT__A 0x831FE7
+#define SCU_RAM_VSB_AGC_POW_TGT__W 15
+#define SCU_RAM_VSB_AGC_POW_TGT__M 0x7FFF
+#define SCU_RAM_VSB_AGC_POW_TGT__PRE 0x0
+
+#define SCU_RAM_VSB_OUTER_LOOP_CYCLE__A 0x831FE8
+#define SCU_RAM_VSB_OUTER_LOOP_CYCLE__W 8
+#define SCU_RAM_VSB_OUTER_LOOP_CYCLE__M 0xFF
+#define SCU_RAM_VSB_OUTER_LOOP_CYCLE__PRE 0x0
+
+#define SCU_RAM_VSB_FIELD_NUMBER__A 0x831FE9
+#define SCU_RAM_VSB_FIELD_NUMBER__W 9
+#define SCU_RAM_VSB_FIELD_NUMBER__M 0x1FF
+#define SCU_RAM_VSB_FIELD_NUMBER__PRE 0x0
+
+#define SCU_RAM_VSB_SEGMENT_NUMBER__A 0x831FEA
+#define SCU_RAM_VSB_SEGMENT_NUMBER__W 10
+#define SCU_RAM_VSB_SEGMENT_NUMBER__M 0x3FF
+#define SCU_RAM_VSB_SEGMENT_NUMBER__PRE 0x0
+
+#define SCU_RAM_DRIVER_VER_HI__A 0x831FEB
+#define SCU_RAM_DRIVER_VER_HI__W 16
+#define SCU_RAM_DRIVER_VER_HI__M 0xFFFF
+#define SCU_RAM_DRIVER_VER_HI__PRE 0x0
+
+#define SCU_RAM_DRIVER_VER_LO__A 0x831FEC
+#define SCU_RAM_DRIVER_VER_LO__W 16
+#define SCU_RAM_DRIVER_VER_LO__M 0xFFFF
+#define SCU_RAM_DRIVER_VER_LO__PRE 0x0
+
+#define SCU_RAM_PARAM_15__A 0x831FED
+#define SCU_RAM_PARAM_15__W 16
+#define SCU_RAM_PARAM_15__M 0xFFFF
+#define SCU_RAM_PARAM_15__PRE 0x0
+
+#define SCU_RAM_PARAM_14__A 0x831FEE
+#define SCU_RAM_PARAM_14__W 16
+#define SCU_RAM_PARAM_14__M 0xFFFF
+#define SCU_RAM_PARAM_14__PRE 0x0
+
+#define SCU_RAM_PARAM_13__A 0x831FEF
+#define SCU_RAM_PARAM_13__W 16
+#define SCU_RAM_PARAM_13__M 0xFFFF
+#define SCU_RAM_PARAM_13__PRE 0x0
+
+#define SCU_RAM_PARAM_12__A 0x831FF0
+#define SCU_RAM_PARAM_12__W 16
+#define SCU_RAM_PARAM_12__M 0xFFFF
+#define SCU_RAM_PARAM_12__PRE 0x0
+
+#define SCU_RAM_PARAM_11__A 0x831FF1
+#define SCU_RAM_PARAM_11__W 16
+#define SCU_RAM_PARAM_11__M 0xFFFF
+#define SCU_RAM_PARAM_11__PRE 0x0
+
+#define SCU_RAM_PARAM_10__A 0x831FF2
+#define SCU_RAM_PARAM_10__W 16
+#define SCU_RAM_PARAM_10__M 0xFFFF
+#define SCU_RAM_PARAM_10__PRE 0x0
+
+#define SCU_RAM_PARAM_9__A 0x831FF3
+#define SCU_RAM_PARAM_9__W 16
+#define SCU_RAM_PARAM_9__M 0xFFFF
+#define SCU_RAM_PARAM_9__PRE 0x0
+
+#define SCU_RAM_PARAM_8__A 0x831FF4
+#define SCU_RAM_PARAM_8__W 16
+#define SCU_RAM_PARAM_8__M 0xFFFF
+#define SCU_RAM_PARAM_8__PRE 0x0
+
+#define SCU_RAM_PARAM_7__A 0x831FF5
+#define SCU_RAM_PARAM_7__W 16
+#define SCU_RAM_PARAM_7__M 0xFFFF
+#define SCU_RAM_PARAM_7__PRE 0x0
+
+#define SCU_RAM_PARAM_6__A 0x831FF6
+#define SCU_RAM_PARAM_6__W 16
+#define SCU_RAM_PARAM_6__M 0xFFFF
+#define SCU_RAM_PARAM_6__PRE 0x0
+
+#define SCU_RAM_PARAM_5__A 0x831FF7
+#define SCU_RAM_PARAM_5__W 16
+#define SCU_RAM_PARAM_5__M 0xFFFF
+#define SCU_RAM_PARAM_5__PRE 0x0
+
+#define SCU_RAM_PARAM_4__A 0x831FF8
+#define SCU_RAM_PARAM_4__W 16
+#define SCU_RAM_PARAM_4__M 0xFFFF
+#define SCU_RAM_PARAM_4__PRE 0x0
+
+#define SCU_RAM_PARAM_3__A 0x831FF9
+#define SCU_RAM_PARAM_3__W 16
+#define SCU_RAM_PARAM_3__M 0xFFFF
+#define SCU_RAM_PARAM_3__PRE 0x0
+
+#define SCU_RAM_PARAM_2__A 0x831FFA
+#define SCU_RAM_PARAM_2__W 16
+#define SCU_RAM_PARAM_2__M 0xFFFF
+#define SCU_RAM_PARAM_2__PRE 0x0
+
+#define SCU_RAM_PARAM_1__A 0x831FFB
+#define SCU_RAM_PARAM_1__W 16
+#define SCU_RAM_PARAM_1__M 0xFFFF
+#define SCU_RAM_PARAM_1__PRE 0x0
+#define SCU_RAM_PARAM_1_RES_DEMOD_GET_LOCK_NOT_LOCKED 0x0
+#define SCU_RAM_PARAM_1_RES_DEMOD_GET_LOCK_DEMOD_LOCKED 0x4000
+#define SCU_RAM_PARAM_1_RES_DEMOD_GET_LOCK_LOCKED 0x8000
+#define SCU_RAM_PARAM_1_RES_DEMOD_GET_LOCK_NEVER_LOCK 0xC000
+
+#define SCU_RAM_PARAM_0__A 0x831FFC
+#define SCU_RAM_PARAM_0__W 16
+#define SCU_RAM_PARAM_0__M 0xFFFF
+#define SCU_RAM_PARAM_0__PRE 0x0
+#define SCU_RAM_PARAM_0_ATV_DEMOD_SETENV_MN_STANDARD 0x2
+#define SCU_RAM_PARAM_0_ATV_DEMOD_SETENV_B_STANDARD 0x103
+#define SCU_RAM_PARAM_0_ATV_DEMOD_SETENV_G_STANDARD 0x3
+#define SCU_RAM_PARAM_0_ATV_DEMOD_SETENV_DK_STANDARD 0x4
+#define SCU_RAM_PARAM_0_ATV_DEMOD_SETENV_L_STANDARD 0x9
+#define SCU_RAM_PARAM_0_ATV_DEMOD_SETENV_LP_STANDARD 0x109
+#define SCU_RAM_PARAM_0_ATV_DEMOD_SETENV_I_STANDARD 0xA
+#define SCU_RAM_PARAM_0_ATV_DEMOD_SETENV_FM_STANDARD 0x40
+#define SCU_RAM_PARAM_0_QAM_DEMOD_SETENV_ANNEX_A 0x0
+#define SCU_RAM_PARAM_0_QAM_DEMOD_SETENV_ANNEX_B 0x1
+#define SCU_RAM_PARAM_0_QAM_DEMOD_SETENV_ANNEX_C 0x2
+#define SCU_RAM_PARAM_0_QAM_DEMOD_SETENV_ANNEX_D 0x3
+#define SCU_RAM_PARAM_0_RESULT_OK 0x0
+#define SCU_RAM_PARAM_0_RESULT_UNKCMD 0xFFFF
+#define SCU_RAM_PARAM_0_RESULT_UNKSTD 0xFFFE
+#define SCU_RAM_PARAM_0_RESULT_INVPAR 0xFFFD
+#define SCU_RAM_PARAM_0_RESULT_SIZE 0xFFFC
+
+#define SCU_RAM_COMMAND__A 0x831FFD
+#define SCU_RAM_COMMAND__W 16
+#define SCU_RAM_COMMAND__M 0xFFFF
+#define SCU_RAM_COMMAND__PRE 0x0
+#define SCU_RAM_COMMAND_CMD_DEMOD_RESET 0x1
+#define SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV 0x2
+#define SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM 0x3
+#define SCU_RAM_COMMAND_CMD_DEMOD_START 0x4
+#define SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK 0x5
+#define SCU_RAM_COMMAND_CMD_DEMOD_GET_PARAM 0x6
+#define SCU_RAM_COMMAND_CMD_DEMOD_HOLD 0x7
+#define SCU_RAM_COMMAND_CMD_DEMOD_RESUME 0x8
+#define SCU_RAM_COMMAND_CMD_DEMOD_STOP 0x9
+#define SCU_RAM_COMMAND_CMD_STD_QAM_IRQ_ACTIVATE 0x80
+#define SCU_RAM_COMMAND_CMD_STD_QAM_IRQ_INACTIVATE 0x81
+#define SCU_RAM_COMMAND_CMD_STD_QAM_IRQ_SIGNAL 0x82
+#define SCU_RAM_COMMAND_CMD_STD_QAM_IRQ_MONITOR 0x83
+#define SCU_RAM_COMMAND_CMD_STD_QAM_TSK_ENABLE 0x84
+#define SCU_RAM_COMMAND_CMD_STD_QAM_FSM_SET_STATE 0x85
+#define SCU_RAM_COMMAND_CMD_DEBUG_GET_IRQ_REGS 0x80
+#define SCU_RAM_COMMAND_CMD_DEBUG_HTOL 0x81
+#define SCU_RAM_COMMAND_CMD_DEBUG_GET_STACK_POINTER 0x82
+#define SCU_RAM_COMMAND_CMD_DEBUG_START_STACK_CHECK 0x83
+#define SCU_RAM_COMMAND_CMD_DEBUG_STOP_STACK_CHECK 0x84
+#define SCU_RAM_COMMAND_CMD_ADMIN_NOP 0xFF
+#define SCU_RAM_COMMAND_CMD_ADMIN_GET_VERSION 0xFE
+#define SCU_RAM_COMMAND_CMD_ADMIN_GET_JTAG_VERSION 0xFD
+#define SCU_RAM_COMMAND_CMD_AUX_SCU_ATOMIC_ACCESS 0xC0
+
+#define SCU_RAM_COMMAND_STANDARD__B 8
+#define SCU_RAM_COMMAND_STANDARD__W 8
+#define SCU_RAM_COMMAND_STANDARD__M 0xFF00
+#define SCU_RAM_COMMAND_STANDARD__PRE 0x0
+#define SCU_RAM_COMMAND_STANDARD_ATV 0x100
+#define SCU_RAM_COMMAND_STANDARD_QAM 0x200
+#define SCU_RAM_COMMAND_STANDARD_VSB 0x300
+#define SCU_RAM_COMMAND_STANDARD_OFDM 0x400
+#define SCU_RAM_COMMAND_STANDARD_OOB 0x8000
+#define SCU_RAM_COMMAND_STANDARD_TOP 0xFF00
+
+#define SCU_RAM_VERSION_HI__A 0x831FFE
+#define SCU_RAM_VERSION_HI__W 16
+#define SCU_RAM_VERSION_HI__M 0xFFFF
+#define SCU_RAM_VERSION_HI__PRE 0x0
+
+#define SCU_RAM_VERSION_HI_VER_MAJOR_N3__B 12
+#define SCU_RAM_VERSION_HI_VER_MAJOR_N3__W 4
+#define SCU_RAM_VERSION_HI_VER_MAJOR_N3__M 0xF000
+#define SCU_RAM_VERSION_HI_VER_MAJOR_N3__PRE 0x0
+
+#define SCU_RAM_VERSION_HI_VER_MAJOR_N2__B 8
+#define SCU_RAM_VERSION_HI_VER_MAJOR_N2__W 4
+#define SCU_RAM_VERSION_HI_VER_MAJOR_N2__M 0xF00
+#define SCU_RAM_VERSION_HI_VER_MAJOR_N2__PRE 0x0
+
+#define SCU_RAM_VERSION_HI_VER_MAJOR_N1__B 4
+#define SCU_RAM_VERSION_HI_VER_MAJOR_N1__W 4
+#define SCU_RAM_VERSION_HI_VER_MAJOR_N1__M 0xF0
+#define SCU_RAM_VERSION_HI_VER_MAJOR_N1__PRE 0x0
+
+#define SCU_RAM_VERSION_HI_VER_MINOR_N1__B 0
+#define SCU_RAM_VERSION_HI_VER_MINOR_N1__W 4
+#define SCU_RAM_VERSION_HI_VER_MINOR_N1__M 0xF
+#define SCU_RAM_VERSION_HI_VER_MINOR_N1__PRE 0x0
+
+#define SCU_RAM_VERSION_LO__A 0x831FFF
+#define SCU_RAM_VERSION_LO__W 16
+#define SCU_RAM_VERSION_LO__M 0xFFFF
+#define SCU_RAM_VERSION_LO__PRE 0x0
+
+#define SCU_RAM_VERSION_LO_VER_PATCH_N4__B 12
+#define SCU_RAM_VERSION_LO_VER_PATCH_N4__W 4
+#define SCU_RAM_VERSION_LO_VER_PATCH_N4__M 0xF000
+#define SCU_RAM_VERSION_LO_VER_PATCH_N4__PRE 0x0
+
+#define SCU_RAM_VERSION_LO_VER_PATCH_N3__B 8
+#define SCU_RAM_VERSION_LO_VER_PATCH_N3__W 4
+#define SCU_RAM_VERSION_LO_VER_PATCH_N3__M 0xF00
+#define SCU_RAM_VERSION_LO_VER_PATCH_N3__PRE 0x0
+
+#define SCU_RAM_VERSION_LO_VER_PATCH_N2__B 4
+#define SCU_RAM_VERSION_LO_VER_PATCH_N2__W 4
+#define SCU_RAM_VERSION_LO_VER_PATCH_N2__M 0xF0
+#define SCU_RAM_VERSION_LO_VER_PATCH_N2__PRE 0x0
+
+#define SCU_RAM_VERSION_LO_VER_PATCH_N1__B 0
+#define SCU_RAM_VERSION_LO_VER_PATCH_N1__W 4
+#define SCU_RAM_VERSION_LO_VER_PATCH_N1__M 0xF
+#define SCU_RAM_VERSION_LO_VER_PATCH_N1__PRE 0x0
+
+#define SIO_COMM_EXEC__A 0x400000
+#define SIO_COMM_EXEC__W 2
+#define SIO_COMM_EXEC__M 0x3
+#define SIO_COMM_EXEC__PRE 0x0
+#define SIO_COMM_EXEC_STOP 0x0
+#define SIO_COMM_EXEC_ACTIVE 0x1
+#define SIO_COMM_EXEC_HOLD 0x2
+
+#define SIO_COMM_STATE__A 0x400001
+#define SIO_COMM_STATE__W 16
+#define SIO_COMM_STATE__M 0xFFFF
+#define SIO_COMM_STATE__PRE 0x0
+#define SIO_COMM_MB__A 0x400002
+#define SIO_COMM_MB__W 16
+#define SIO_COMM_MB__M 0xFFFF
+#define SIO_COMM_MB__PRE 0x0
+#define SIO_COMM_INT_REQ__A 0x400003
+#define SIO_COMM_INT_REQ__W 16
+#define SIO_COMM_INT_REQ__M 0xFFFF
+#define SIO_COMM_INT_REQ__PRE 0x0
+
+#define SIO_COMM_INT_REQ_HI_REQ__B 0
+#define SIO_COMM_INT_REQ_HI_REQ__W 1
+#define SIO_COMM_INT_REQ_HI_REQ__M 0x1
+#define SIO_COMM_INT_REQ_HI_REQ__PRE 0x0
+
+#define SIO_COMM_INT_REQ_SA_REQ__B 1
+#define SIO_COMM_INT_REQ_SA_REQ__W 1
+#define SIO_COMM_INT_REQ_SA_REQ__M 0x2
+#define SIO_COMM_INT_REQ_SA_REQ__PRE 0x0
+
+#define SIO_COMM_INT_STA__A 0x400005
+#define SIO_COMM_INT_STA__W 16
+#define SIO_COMM_INT_STA__M 0xFFFF
+#define SIO_COMM_INT_STA__PRE 0x0
+#define SIO_COMM_INT_MSK__A 0x400006
+#define SIO_COMM_INT_MSK__W 16
+#define SIO_COMM_INT_MSK__M 0xFFFF
+#define SIO_COMM_INT_MSK__PRE 0x0
+#define SIO_COMM_INT_STM__A 0x400007
+#define SIO_COMM_INT_STM__W 16
+#define SIO_COMM_INT_STM__M 0xFFFF
+#define SIO_COMM_INT_STM__PRE 0x0
+
+#define SIO_TOP_COMM_EXEC__A 0x410000
+#define SIO_TOP_COMM_EXEC__W 2
+#define SIO_TOP_COMM_EXEC__M 0x3
+#define SIO_TOP_COMM_EXEC__PRE 0x0
+#define SIO_TOP_COMM_EXEC_STOP 0x0
+#define SIO_TOP_COMM_EXEC_ACTIVE 0x1
+#define SIO_TOP_COMM_EXEC_HOLD 0x2
+
+#define SIO_TOP_COMM_KEY__A 0x41000F
+#define SIO_TOP_COMM_KEY__W 16
+#define SIO_TOP_COMM_KEY__M 0xFFFF
+#define SIO_TOP_COMM_KEY__PRE 0x0
+#define SIO_TOP_COMM_KEY_KEY 0xFABA
+
+#define SIO_TOP_JTAGID_LO__A 0x410012
+#define SIO_TOP_JTAGID_LO__W 16
+#define SIO_TOP_JTAGID_LO__M 0xFFFF
+#define SIO_TOP_JTAGID_LO__PRE 0x0
+
+#define SIO_TOP_JTAGID_HI__A 0x410013
+#define SIO_TOP_JTAGID_HI__W 16
+#define SIO_TOP_JTAGID_HI__M 0xFFFF
+#define SIO_TOP_JTAGID_HI__PRE 0x0
+
+#define SIO_HI_RA_RAM_S0_FLG_SMM__A 0x420010
+#define SIO_HI_RA_RAM_S0_FLG_SMM__W 1
+#define SIO_HI_RA_RAM_S0_FLG_SMM__M 0x1
+#define SIO_HI_RA_RAM_S0_FLG_SMM__PRE 0x0
+
+#define SIO_HI_RA_RAM_S0_DEV_ID__A 0x420011
+#define SIO_HI_RA_RAM_S0_DEV_ID__W 7
+#define SIO_HI_RA_RAM_S0_DEV_ID__M 0x7F
+#define SIO_HI_RA_RAM_S0_DEV_ID__PRE 0x52
+
+#define SIO_HI_RA_RAM_S0_FLG_CRC__A 0x420012
+#define SIO_HI_RA_RAM_S0_FLG_CRC__W 1
+#define SIO_HI_RA_RAM_S0_FLG_CRC__M 0x1
+#define SIO_HI_RA_RAM_S0_FLG_CRC__PRE 0x0
+#define SIO_HI_RA_RAM_S0_FLG_ACC__A 0x420013
+#define SIO_HI_RA_RAM_S0_FLG_ACC__W 4
+#define SIO_HI_RA_RAM_S0_FLG_ACC__M 0xF
+#define SIO_HI_RA_RAM_S0_FLG_ACC__PRE 0x0
+
+#define SIO_HI_RA_RAM_S0_FLG_ACC_S0_RWM__B 0
+#define SIO_HI_RA_RAM_S0_FLG_ACC_S0_RWM__W 2
+#define SIO_HI_RA_RAM_S0_FLG_ACC_S0_RWM__M 0x3
+#define SIO_HI_RA_RAM_S0_FLG_ACC_S0_RWM__PRE 0x0
+
+#define SIO_HI_RA_RAM_S0_FLG_ACC_S0_SLV_BRC__B 2
+#define SIO_HI_RA_RAM_S0_FLG_ACC_S0_SLV_BRC__W 1
+#define SIO_HI_RA_RAM_S0_FLG_ACC_S0_SLV_BRC__M 0x4
+#define SIO_HI_RA_RAM_S0_FLG_ACC_S0_SLV_BRC__PRE 0x0
+
+#define SIO_HI_RA_RAM_S0_FLG_ACC_S0_SLV_SWP__B 3
+#define SIO_HI_RA_RAM_S0_FLG_ACC_S0_SLV_SWP__W 1
+#define SIO_HI_RA_RAM_S0_FLG_ACC_S0_SLV_SWP__M 0x8
+#define SIO_HI_RA_RAM_S0_FLG_ACC_S0_SLV_SWP__PRE 0x0
+
+#define SIO_HI_RA_RAM_S0_STATE__A 0x420014
+#define SIO_HI_RA_RAM_S0_STATE__W 1
+#define SIO_HI_RA_RAM_S0_STATE__M 0x1
+#define SIO_HI_RA_RAM_S0_STATE__PRE 0x0
+
+#define SIO_HI_RA_RAM_S0_STATE_S0_SLV_STA__B 0
+#define SIO_HI_RA_RAM_S0_STATE_S0_SLV_STA__W 1
+#define SIO_HI_RA_RAM_S0_STATE_S0_SLV_STA__M 0x1
+#define SIO_HI_RA_RAM_S0_STATE_S0_SLV_STA__PRE 0x0
+
+#define SIO_HI_RA_RAM_S0_BLK_BNK__A 0x420015
+#define SIO_HI_RA_RAM_S0_BLK_BNK__W 12
+#define SIO_HI_RA_RAM_S0_BLK_BNK__M 0xFFF
+#define SIO_HI_RA_RAM_S0_BLK_BNK__PRE 0x82
+
+#define SIO_HI_RA_RAM_S0_BLK_BNK_S0_SLV_BNK__B 0
+#define SIO_HI_RA_RAM_S0_BLK_BNK_S0_SLV_BNK__W 6
+#define SIO_HI_RA_RAM_S0_BLK_BNK_S0_SLV_BNK__M 0x3F
+#define SIO_HI_RA_RAM_S0_BLK_BNK_S0_SLV_BNK__PRE 0x2
+
+#define SIO_HI_RA_RAM_S0_BLK_BNK_S0_SLV_BLK__B 6
+#define SIO_HI_RA_RAM_S0_BLK_BNK_S0_SLV_BLK__W 6
+#define SIO_HI_RA_RAM_S0_BLK_BNK_S0_SLV_BLK__M 0xFC0
+#define SIO_HI_RA_RAM_S0_BLK_BNK_S0_SLV_BLK__PRE 0x80
+
+#define SIO_HI_RA_RAM_S0_ADDR__A 0x420016
+#define SIO_HI_RA_RAM_S0_ADDR__W 16
+#define SIO_HI_RA_RAM_S0_ADDR__M 0xFFFF
+#define SIO_HI_RA_RAM_S0_ADDR__PRE 0x0
+
+#define SIO_HI_RA_RAM_S0_ADDR_S0_SLV_ADDR__B 0
+#define SIO_HI_RA_RAM_S0_ADDR_S0_SLV_ADDR__W 16
+#define SIO_HI_RA_RAM_S0_ADDR_S0_SLV_ADDR__M 0xFFFF
+#define SIO_HI_RA_RAM_S0_ADDR_S0_SLV_ADDR__PRE 0x0
+
+#define SIO_HI_RA_RAM_S0_CRC__A 0x420017
+#define SIO_HI_RA_RAM_S0_CRC__W 16
+#define SIO_HI_RA_RAM_S0_CRC__M 0xFFFF
+#define SIO_HI_RA_RAM_S0_CRC__PRE 0x0
+
+#define SIO_HI_RA_RAM_S0_BUFFER__A 0x420018
+#define SIO_HI_RA_RAM_S0_BUFFER__W 16
+#define SIO_HI_RA_RAM_S0_BUFFER__M 0xFFFF
+#define SIO_HI_RA_RAM_S0_BUFFER__PRE 0x0
+
+#define SIO_HI_RA_RAM_S0_RMWBUF__A 0x420019
+#define SIO_HI_RA_RAM_S0_RMWBUF__W 16
+#define SIO_HI_RA_RAM_S0_RMWBUF__M 0xFFFF
+#define SIO_HI_RA_RAM_S0_RMWBUF__PRE 0x0
+
+#define SIO_HI_RA_RAM_S0_FLG_VB__A 0x42001A
+#define SIO_HI_RA_RAM_S0_FLG_VB__W 1
+#define SIO_HI_RA_RAM_S0_FLG_VB__M 0x1
+#define SIO_HI_RA_RAM_S0_FLG_VB__PRE 0x0
+
+#define SIO_HI_RA_RAM_S0_TEMP0__A 0x42001B
+#define SIO_HI_RA_RAM_S0_TEMP0__W 16
+#define SIO_HI_RA_RAM_S0_TEMP0__M 0xFFFF
+#define SIO_HI_RA_RAM_S0_TEMP0__PRE 0x0
+
+#define SIO_HI_RA_RAM_S0_TEMP1__A 0x42001C
+#define SIO_HI_RA_RAM_S0_TEMP1__W 16
+#define SIO_HI_RA_RAM_S0_TEMP1__M 0xFFFF
+#define SIO_HI_RA_RAM_S0_TEMP1__PRE 0x0
+
+#define SIO_HI_RA_RAM_S0_OFFSET__A 0x42001D
+#define SIO_HI_RA_RAM_S0_OFFSET__W 16
+#define SIO_HI_RA_RAM_S0_OFFSET__M 0xFFFF
+#define SIO_HI_RA_RAM_S0_OFFSET__PRE 0x0
+
+#define SIO_HI_RA_RAM_S1_FLG_SMM__A 0x420020
+#define SIO_HI_RA_RAM_S1_FLG_SMM__W 1
+#define SIO_HI_RA_RAM_S1_FLG_SMM__M 0x1
+#define SIO_HI_RA_RAM_S1_FLG_SMM__PRE 0x0
+
+#define SIO_HI_RA_RAM_S1_DEV_ID__A 0x420021
+#define SIO_HI_RA_RAM_S1_DEV_ID__W 7
+#define SIO_HI_RA_RAM_S1_DEV_ID__M 0x7F
+#define SIO_HI_RA_RAM_S1_DEV_ID__PRE 0x52
+
+#define SIO_HI_RA_RAM_S1_FLG_CRC__A 0x420022
+#define SIO_HI_RA_RAM_S1_FLG_CRC__W 1
+#define SIO_HI_RA_RAM_S1_FLG_CRC__M 0x1
+#define SIO_HI_RA_RAM_S1_FLG_CRC__PRE 0x0
+#define SIO_HI_RA_RAM_S1_FLG_ACC__A 0x420023
+#define SIO_HI_RA_RAM_S1_FLG_ACC__W 4
+#define SIO_HI_RA_RAM_S1_FLG_ACC__M 0xF
+#define SIO_HI_RA_RAM_S1_FLG_ACC__PRE 0x0
+
+#define SIO_HI_RA_RAM_S1_FLG_ACC_S1_RWM__B 0
+#define SIO_HI_RA_RAM_S1_FLG_ACC_S1_RWM__W 2
+#define SIO_HI_RA_RAM_S1_FLG_ACC_S1_RWM__M 0x3
+#define SIO_HI_RA_RAM_S1_FLG_ACC_S1_RWM__PRE 0x0
+
+#define SIO_HI_RA_RAM_S1_FLG_ACC_S1_SLV_BRC__B 2
+#define SIO_HI_RA_RAM_S1_FLG_ACC_S1_SLV_BRC__W 1
+#define SIO_HI_RA_RAM_S1_FLG_ACC_S1_SLV_BRC__M 0x4
+#define SIO_HI_RA_RAM_S1_FLG_ACC_S1_SLV_BRC__PRE 0x0
+
+#define SIO_HI_RA_RAM_S1_FLG_ACC_S1_SLV_SWP__B 3
+#define SIO_HI_RA_RAM_S1_FLG_ACC_S1_SLV_SWP__W 1
+#define SIO_HI_RA_RAM_S1_FLG_ACC_S1_SLV_SWP__M 0x8
+#define SIO_HI_RA_RAM_S1_FLG_ACC_S1_SLV_SWP__PRE 0x0
+
+#define SIO_HI_RA_RAM_S1_STATE__A 0x420024
+#define SIO_HI_RA_RAM_S1_STATE__W 1
+#define SIO_HI_RA_RAM_S1_STATE__M 0x1
+#define SIO_HI_RA_RAM_S1_STATE__PRE 0x0
+
+#define SIO_HI_RA_RAM_S1_STATE_S1_SLV_STA__B 0
+#define SIO_HI_RA_RAM_S1_STATE_S1_SLV_STA__W 1
+#define SIO_HI_RA_RAM_S1_STATE_S1_SLV_STA__M 0x1
+#define SIO_HI_RA_RAM_S1_STATE_S1_SLV_STA__PRE 0x0
+
+#define SIO_HI_RA_RAM_S1_BLK_BNK__A 0x420025
+#define SIO_HI_RA_RAM_S1_BLK_BNK__W 12
+#define SIO_HI_RA_RAM_S1_BLK_BNK__M 0xFFF
+#define SIO_HI_RA_RAM_S1_BLK_BNK__PRE 0x82
+
+#define SIO_HI_RA_RAM_S1_BLK_BNK_S1_SLV_BNK__B 0
+#define SIO_HI_RA_RAM_S1_BLK_BNK_S1_SLV_BNK__W 6
+#define SIO_HI_RA_RAM_S1_BLK_BNK_S1_SLV_BNK__M 0x3F
+#define SIO_HI_RA_RAM_S1_BLK_BNK_S1_SLV_BNK__PRE 0x2
+
+#define SIO_HI_RA_RAM_S1_BLK_BNK_S1_SLV_BLK__B 6
+#define SIO_HI_RA_RAM_S1_BLK_BNK_S1_SLV_BLK__W 6
+#define SIO_HI_RA_RAM_S1_BLK_BNK_S1_SLV_BLK__M 0xFC0
+#define SIO_HI_RA_RAM_S1_BLK_BNK_S1_SLV_BLK__PRE 0x80
+
+#define SIO_HI_RA_RAM_S1_ADDR__A 0x420026
+#define SIO_HI_RA_RAM_S1_ADDR__W 16
+#define SIO_HI_RA_RAM_S1_ADDR__M 0xFFFF
+#define SIO_HI_RA_RAM_S1_ADDR__PRE 0x0
+
+#define SIO_HI_RA_RAM_S1_ADDR_S1_SLV_ADDR__B 0
+#define SIO_HI_RA_RAM_S1_ADDR_S1_SLV_ADDR__W 16
+#define SIO_HI_RA_RAM_S1_ADDR_S1_SLV_ADDR__M 0xFFFF
+#define SIO_HI_RA_RAM_S1_ADDR_S1_SLV_ADDR__PRE 0x0
+
+#define SIO_HI_RA_RAM_S1_CRC__A 0x420027
+#define SIO_HI_RA_RAM_S1_CRC__W 16
+#define SIO_HI_RA_RAM_S1_CRC__M 0xFFFF
+#define SIO_HI_RA_RAM_S1_CRC__PRE 0x0
+
+#define SIO_HI_RA_RAM_S1_BUFFER__A 0x420028
+#define SIO_HI_RA_RAM_S1_BUFFER__W 16
+#define SIO_HI_RA_RAM_S1_BUFFER__M 0xFFFF
+#define SIO_HI_RA_RAM_S1_BUFFER__PRE 0x0
+
+#define SIO_HI_RA_RAM_S1_RMWBUF__A 0x420029
+#define SIO_HI_RA_RAM_S1_RMWBUF__W 16
+#define SIO_HI_RA_RAM_S1_RMWBUF__M 0xFFFF
+#define SIO_HI_RA_RAM_S1_RMWBUF__PRE 0x0
+
+#define SIO_HI_RA_RAM_S1_FLG_VB__A 0x42002A
+#define SIO_HI_RA_RAM_S1_FLG_VB__W 1
+#define SIO_HI_RA_RAM_S1_FLG_VB__M 0x1
+#define SIO_HI_RA_RAM_S1_FLG_VB__PRE 0x0
+
+#define SIO_HI_RA_RAM_S1_TEMP0__A 0x42002B
+#define SIO_HI_RA_RAM_S1_TEMP0__W 16
+#define SIO_HI_RA_RAM_S1_TEMP0__M 0xFFFF
+#define SIO_HI_RA_RAM_S1_TEMP0__PRE 0x0
+
+#define SIO_HI_RA_RAM_S1_TEMP1__A 0x42002C
+#define SIO_HI_RA_RAM_S1_TEMP1__W 16
+#define SIO_HI_RA_RAM_S1_TEMP1__M 0xFFFF
+#define SIO_HI_RA_RAM_S1_TEMP1__PRE 0x0
+
+#define SIO_HI_RA_RAM_S1_OFFSET__A 0x42002D
+#define SIO_HI_RA_RAM_S1_OFFSET__W 16
+#define SIO_HI_RA_RAM_S1_OFFSET__M 0xFFFF
+#define SIO_HI_RA_RAM_S1_OFFSET__PRE 0x0
+#define SIO_HI_RA_RAM_SEMA__A 0x420030
+#define SIO_HI_RA_RAM_SEMA__W 1
+#define SIO_HI_RA_RAM_SEMA__M 0x1
+#define SIO_HI_RA_RAM_SEMA__PRE 0x0
+#define SIO_HI_RA_RAM_SEMA_FREE 0x0
+#define SIO_HI_RA_RAM_SEMA_BUSY 0x1
+
+#define SIO_HI_RA_RAM_RES__A 0x420031
+#define SIO_HI_RA_RAM_RES__W 3
+#define SIO_HI_RA_RAM_RES__M 0x7
+#define SIO_HI_RA_RAM_RES__PRE 0x0
+#define SIO_HI_RA_RAM_RES_OK 0x0
+#define SIO_HI_RA_RAM_RES_ERROR 0x1
+#define SIO_HI_RA_RAM_RES_I2C_START_FOUND 0x1
+#define SIO_HI_RA_RAM_RES_I2C_STOP_FOUND 0x2
+#define SIO_HI_RA_RAM_RES_I2C_ARB_LOST 0x3
+#define SIO_HI_RA_RAM_RES_I2C_ERROR 0x4
+
+#define SIO_HI_RA_RAM_CMD__A 0x420032
+#define SIO_HI_RA_RAM_CMD__W 4
+#define SIO_HI_RA_RAM_CMD__M 0xF
+#define SIO_HI_RA_RAM_CMD__PRE 0x0
+#define SIO_HI_RA_RAM_CMD_NULL 0x0
+#define SIO_HI_RA_RAM_CMD_UIO 0x1
+#define SIO_HI_RA_RAM_CMD_RESET 0x2
+#define SIO_HI_RA_RAM_CMD_CONFIG 0x3
+#define SIO_HI_RA_RAM_CMD_INTERNAL_TRANSFER 0x4
+#define SIO_HI_RA_RAM_CMD_I2C_TRANSMIT 0x5
+#define SIO_HI_RA_RAM_CMD_EXEC 0x6
+#define SIO_HI_RA_RAM_CMD_BRDCTRL 0x7
+#define SIO_HI_RA_RAM_CMD_ATOMIC_COPY 0x8
+
+#define SIO_HI_RA_RAM_PAR_1__A 0x420033
+#define SIO_HI_RA_RAM_PAR_1__W 16
+#define SIO_HI_RA_RAM_PAR_1__M 0xFFFF
+#define SIO_HI_RA_RAM_PAR_1__PRE 0x0
+#define SIO_HI_RA_RAM_PAR_1_PAR1__B 0
+#define SIO_HI_RA_RAM_PAR_1_PAR1__W 16
+#define SIO_HI_RA_RAM_PAR_1_PAR1__M 0xFFFF
+#define SIO_HI_RA_RAM_PAR_1_PAR1__PRE 0x0
+#define SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY 0x3945
+
+#define SIO_HI_RA_RAM_PAR_1_ITX_SRC_BNK__B 0
+#define SIO_HI_RA_RAM_PAR_1_ITX_SRC_BNK__W 6
+#define SIO_HI_RA_RAM_PAR_1_ITX_SRC_BNK__M 0x3F
+#define SIO_HI_RA_RAM_PAR_1_ITX_SRC_BNK__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_1_ITX_SRC_BLK__B 6
+#define SIO_HI_RA_RAM_PAR_1_ITX_SRC_BLK__W 6
+#define SIO_HI_RA_RAM_PAR_1_ITX_SRC_BLK__M 0xFC0
+#define SIO_HI_RA_RAM_PAR_1_ITX_SRC_BLK__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_1_I2CTX_PORT__B 0
+#define SIO_HI_RA_RAM_PAR_1_I2CTX_PORT__W 1
+#define SIO_HI_RA_RAM_PAR_1_I2CTX_PORT__M 0x1
+#define SIO_HI_RA_RAM_PAR_1_I2CTX_PORT__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_1_I2CTX_TOE__B 1
+#define SIO_HI_RA_RAM_PAR_1_I2CTX_TOE__W 1
+#define SIO_HI_RA_RAM_PAR_1_I2CTX_TOE__M 0x2
+#define SIO_HI_RA_RAM_PAR_1_I2CTX_TOE__PRE 0x0
+#define SIO_HI_RA_RAM_PAR_1_I2CTX_TOE_DISABLE 0x0
+#define SIO_HI_RA_RAM_PAR_1_I2CTX_TOE_ENABLE 0x2
+
+#define SIO_HI_RA_RAM_PAR_1_EXEC_FUNC__B 0
+#define SIO_HI_RA_RAM_PAR_1_EXEC_FUNC__W 10
+#define SIO_HI_RA_RAM_PAR_1_EXEC_FUNC__M 0x3FF
+#define SIO_HI_RA_RAM_PAR_1_EXEC_FUNC__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_1_ACP_INT_BNK__B 0
+#define SIO_HI_RA_RAM_PAR_1_ACP_INT_BNK__W 6
+#define SIO_HI_RA_RAM_PAR_1_ACP_INT_BNK__M 0x3F
+#define SIO_HI_RA_RAM_PAR_1_ACP_INT_BNK__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_1_ACP_INT_BLK__B 6
+#define SIO_HI_RA_RAM_PAR_1_ACP_INT_BLK__W 6
+#define SIO_HI_RA_RAM_PAR_1_ACP_INT_BLK__M 0xFC0
+#define SIO_HI_RA_RAM_PAR_1_ACP_INT_BLK__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_2__A 0x420034
+#define SIO_HI_RA_RAM_PAR_2__W 16
+#define SIO_HI_RA_RAM_PAR_2__M 0xFFFF
+#define SIO_HI_RA_RAM_PAR_2__PRE 0x0
+#define SIO_HI_RA_RAM_PAR_2_PAR2__B 0
+#define SIO_HI_RA_RAM_PAR_2_PAR2__W 16
+#define SIO_HI_RA_RAM_PAR_2_PAR2__M 0xFFFF
+#define SIO_HI_RA_RAM_PAR_2_PAR2__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_2_CFG_DIV__B 0
+#define SIO_HI_RA_RAM_PAR_2_CFG_DIV__W 7
+#define SIO_HI_RA_RAM_PAR_2_CFG_DIV__M 0x7F
+#define SIO_HI_RA_RAM_PAR_2_CFG_DIV__PRE 0x25
+
+#define SIO_HI_RA_RAM_PAR_2_ITX_SRC_OFF__B 0
+#define SIO_HI_RA_RAM_PAR_2_ITX_SRC_OFF__W 16
+#define SIO_HI_RA_RAM_PAR_2_ITX_SRC_OFF__M 0xFFFF
+#define SIO_HI_RA_RAM_PAR_2_ITX_SRC_OFF__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_2_I2CTX_BUF__B 0
+#define SIO_HI_RA_RAM_PAR_2_I2CTX_BUF__W 16
+#define SIO_HI_RA_RAM_PAR_2_I2CTX_BUF__M 0xFFFF
+#define SIO_HI_RA_RAM_PAR_2_I2CTX_BUF__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_2_BRD_CFG__B 2
+#define SIO_HI_RA_RAM_PAR_2_BRD_CFG__W 1
+#define SIO_HI_RA_RAM_PAR_2_BRD_CFG__M 0x4
+#define SIO_HI_RA_RAM_PAR_2_BRD_CFG__PRE 0x0
+#define SIO_HI_RA_RAM_PAR_2_BRD_CFG_OPEN 0x0
+#define SIO_HI_RA_RAM_PAR_2_BRD_CFG_CLOSED 0x4
+
+#define SIO_HI_RA_RAM_PAR_2_ACP_INT_OFF__B 0
+#define SIO_HI_RA_RAM_PAR_2_ACP_INT_OFF__W 16
+#define SIO_HI_RA_RAM_PAR_2_ACP_INT_OFF__M 0xFFFF
+#define SIO_HI_RA_RAM_PAR_2_ACP_INT_OFF__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_3__A 0x420035
+#define SIO_HI_RA_RAM_PAR_3__W 16
+#define SIO_HI_RA_RAM_PAR_3__M 0xFFFF
+#define SIO_HI_RA_RAM_PAR_3__PRE 0x0
+#define SIO_HI_RA_RAM_PAR_3_PAR3__B 0
+#define SIO_HI_RA_RAM_PAR_3_PAR3__W 16
+#define SIO_HI_RA_RAM_PAR_3_PAR3__M 0xFFFF
+#define SIO_HI_RA_RAM_PAR_3_PAR3__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__B 0
+#define SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__W 7
+#define SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M 0x7F
+#define SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__PRE 0x3F
+
+#define SIO_HI_RA_RAM_PAR_3_CFG_DBL_SCL__B 7
+#define SIO_HI_RA_RAM_PAR_3_CFG_DBL_SCL__W 7
+#define SIO_HI_RA_RAM_PAR_3_CFG_DBL_SCL__M 0x3F80
+#define SIO_HI_RA_RAM_PAR_3_CFG_DBL_SCL__PRE 0x1F80
+
+#define SIO_HI_RA_RAM_PAR_3_ITX_LEN__B 0
+#define SIO_HI_RA_RAM_PAR_3_ITX_LEN__W 16
+#define SIO_HI_RA_RAM_PAR_3_ITX_LEN__M 0xFFFF
+#define SIO_HI_RA_RAM_PAR_3_ITX_LEN__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_3_ACP_LEN__B 0
+#define SIO_HI_RA_RAM_PAR_3_ACP_LEN__W 3
+#define SIO_HI_RA_RAM_PAR_3_ACP_LEN__M 0x7
+#define SIO_HI_RA_RAM_PAR_3_ACP_LEN__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_3_ACP_RW__B 3
+#define SIO_HI_RA_RAM_PAR_3_ACP_RW__W 1
+#define SIO_HI_RA_RAM_PAR_3_ACP_RW__M 0x8
+#define SIO_HI_RA_RAM_PAR_3_ACP_RW__PRE 0x0
+#define SIO_HI_RA_RAM_PAR_3_ACP_RW_READ 0x0
+#define SIO_HI_RA_RAM_PAR_3_ACP_RW_WRITE 0x8
+
+#define SIO_HI_RA_RAM_PAR_4__A 0x420036
+#define SIO_HI_RA_RAM_PAR_4__W 16
+#define SIO_HI_RA_RAM_PAR_4__M 0xFFFF
+#define SIO_HI_RA_RAM_PAR_4__PRE 0x0
+#define SIO_HI_RA_RAM_PAR_4_PAR4__B 0
+#define SIO_HI_RA_RAM_PAR_4_PAR4__W 16
+#define SIO_HI_RA_RAM_PAR_4_PAR4__M 0xFFFF
+#define SIO_HI_RA_RAM_PAR_4_PAR4__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_4_CFG_WUP__B 0
+#define SIO_HI_RA_RAM_PAR_4_CFG_WUP__W 8
+#define SIO_HI_RA_RAM_PAR_4_CFG_WUP__M 0xFF
+#define SIO_HI_RA_RAM_PAR_4_CFG_WUP__PRE 0xC1
+
+#define SIO_HI_RA_RAM_PAR_4_ITX_DST_BNK__B 0
+#define SIO_HI_RA_RAM_PAR_4_ITX_DST_BNK__W 6
+#define SIO_HI_RA_RAM_PAR_4_ITX_DST_BNK__M 0x3F
+#define SIO_HI_RA_RAM_PAR_4_ITX_DST_BNK__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_4_ITX_DST_BLK__B 6
+#define SIO_HI_RA_RAM_PAR_4_ITX_DST_BLK__W 6
+#define SIO_HI_RA_RAM_PAR_4_ITX_DST_BLK__M 0xFC0
+#define SIO_HI_RA_RAM_PAR_4_ITX_DST_BLK__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_4_ACP_EXT_BNK__B 0
+#define SIO_HI_RA_RAM_PAR_4_ACP_EXT_BNK__W 6
+#define SIO_HI_RA_RAM_PAR_4_ACP_EXT_BNK__M 0x3F
+#define SIO_HI_RA_RAM_PAR_4_ACP_EXT_BNK__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_4_ACP_EXT_BLK__B 6
+#define SIO_HI_RA_RAM_PAR_4_ACP_EXT_BLK__W 6
+#define SIO_HI_RA_RAM_PAR_4_ACP_EXT_BLK__M 0xFC0
+#define SIO_HI_RA_RAM_PAR_4_ACP_EXT_BLK__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_5__A 0x420037
+#define SIO_HI_RA_RAM_PAR_5__W 16
+#define SIO_HI_RA_RAM_PAR_5__M 0xFFFF
+#define SIO_HI_RA_RAM_PAR_5__PRE 0x0
+#define SIO_HI_RA_RAM_PAR_5_PAR5__B 0
+#define SIO_HI_RA_RAM_PAR_5_PAR5__W 16
+#define SIO_HI_RA_RAM_PAR_5_PAR5__M 0xFFFF
+#define SIO_HI_RA_RAM_PAR_5_PAR5__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_5_CFG_SLV0__B 0
+#define SIO_HI_RA_RAM_PAR_5_CFG_SLV0__W 1
+#define SIO_HI_RA_RAM_PAR_5_CFG_SLV0__M 0x1
+#define SIO_HI_RA_RAM_PAR_5_CFG_SLV0__PRE 0x0
+#define SIO_HI_RA_RAM_PAR_5_CFG_SLV0_NO_SLAVE 0x0
+#define SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE 0x1
+
+#define SIO_HI_RA_RAM_PAR_5_CFG_SLV1__B 1
+#define SIO_HI_RA_RAM_PAR_5_CFG_SLV1__W 1
+#define SIO_HI_RA_RAM_PAR_5_CFG_SLV1__M 0x2
+#define SIO_HI_RA_RAM_PAR_5_CFG_SLV1__PRE 0x0
+#define SIO_HI_RA_RAM_PAR_5_CFG_SLV1_NO_SLAVE 0x0
+#define SIO_HI_RA_RAM_PAR_5_CFG_SLV1_SLAVE 0x2
+
+#define SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__B 3
+#define SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__W 1
+#define SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M 0x8
+#define SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__PRE 0x0
+#define SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_AWAKE 0x0
+#define SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ 0x8
+
+#define SIO_HI_RA_RAM_PAR_5_CFG_BDGST__B 5
+#define SIO_HI_RA_RAM_PAR_5_CFG_BDGST__W 1
+#define SIO_HI_RA_RAM_PAR_5_CFG_BDGST__M 0x20
+#define SIO_HI_RA_RAM_PAR_5_CFG_BDGST__PRE 0x0
+#define SIO_HI_RA_RAM_PAR_5_CFG_BDGST_DISABLE 0x0
+#define SIO_HI_RA_RAM_PAR_5_CFG_BDGST_ENABLE 0x20
+
+#define SIO_HI_RA_RAM_PAR_5_ITX_DST_OFF__B 0
+#define SIO_HI_RA_RAM_PAR_5_ITX_DST_OFF__W 16
+#define SIO_HI_RA_RAM_PAR_5_ITX_DST_OFF__M 0xFFFF
+#define SIO_HI_RA_RAM_PAR_5_ITX_DST_OFF__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_5_ACP_EXT_OFF__B 0
+#define SIO_HI_RA_RAM_PAR_5_ACP_EXT_OFF__W 16
+#define SIO_HI_RA_RAM_PAR_5_ACP_EXT_OFF__M 0xFFFF
+#define SIO_HI_RA_RAM_PAR_5_ACP_EXT_OFF__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_6__A 0x420038
+#define SIO_HI_RA_RAM_PAR_6__W 16
+#define SIO_HI_RA_RAM_PAR_6__M 0xFFFF
+#define SIO_HI_RA_RAM_PAR_6__PRE 0x95FF
+#define SIO_HI_RA_RAM_PAR_6_PAR6__B 0
+#define SIO_HI_RA_RAM_PAR_6_PAR6__W 16
+#define SIO_HI_RA_RAM_PAR_6_PAR6__M 0xFFFF
+#define SIO_HI_RA_RAM_PAR_6_PAR6__PRE 0x0
+
+#define SIO_HI_RA_RAM_PAR_6_CFG_TOD__B 0
+#define SIO_HI_RA_RAM_PAR_6_CFG_TOD__W 8
+#define SIO_HI_RA_RAM_PAR_6_CFG_TOD__M 0xFF
+#define SIO_HI_RA_RAM_PAR_6_CFG_TOD__PRE 0xFF
+
+#define SIO_HI_RA_RAM_PAR_6_CFG_WDD__B 8
+#define SIO_HI_RA_RAM_PAR_6_CFG_WDD__W 8
+#define SIO_HI_RA_RAM_PAR_6_CFG_WDD__M 0xFF00
+#define SIO_HI_RA_RAM_PAR_6_CFG_WDD__PRE 0x9500
+
+#define SIO_HI_RA_RAM_AB_TEMP__A 0x42006E
+#define SIO_HI_RA_RAM_AB_TEMP__W 16
+#define SIO_HI_RA_RAM_AB_TEMP__M 0xFFFF
+#define SIO_HI_RA_RAM_AB_TEMP__PRE 0x0
+
+#define SIO_HI_RA_RAM_I2C_CTL__A 0x42006F
+#define SIO_HI_RA_RAM_I2C_CTL__W 16
+#define SIO_HI_RA_RAM_I2C_CTL__M 0xFFFF
+#define SIO_HI_RA_RAM_I2C_CTL__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_ENTRY0__A 0x420070
+#define SIO_HI_RA_RAM_VB_ENTRY0__W 16
+#define SIO_HI_RA_RAM_VB_ENTRY0__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_ENTRY0__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_ENTRY0_HI_MAP_BNK__B 0
+#define SIO_HI_RA_RAM_VB_ENTRY0_HI_MAP_BNK__W 4
+#define SIO_HI_RA_RAM_VB_ENTRY0_HI_MAP_BNK__M 0xF
+#define SIO_HI_RA_RAM_VB_ENTRY0_HI_MAP_BNK__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_ENTRY0_HI_MAP_BLK__B 4
+#define SIO_HI_RA_RAM_VB_ENTRY0_HI_MAP_BLK__W 4
+#define SIO_HI_RA_RAM_VB_ENTRY0_HI_MAP_BLK__M 0xF0
+#define SIO_HI_RA_RAM_VB_ENTRY0_HI_MAP_BLK__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_ENTRY0_HI_VIRT_BNK__B 8
+#define SIO_HI_RA_RAM_VB_ENTRY0_HI_VIRT_BNK__W 4
+#define SIO_HI_RA_RAM_VB_ENTRY0_HI_VIRT_BNK__M 0xF00
+#define SIO_HI_RA_RAM_VB_ENTRY0_HI_VIRT_BNK__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_ENTRY0_HI_VIRT_BLK__B 12
+#define SIO_HI_RA_RAM_VB_ENTRY0_HI_VIRT_BLK__W 4
+#define SIO_HI_RA_RAM_VB_ENTRY0_HI_VIRT_BLK__M 0xF000
+#define SIO_HI_RA_RAM_VB_ENTRY0_HI_VIRT_BLK__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_OFFSET0__A 0x420071
+#define SIO_HI_RA_RAM_VB_OFFSET0__W 16
+#define SIO_HI_RA_RAM_VB_OFFSET0__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_OFFSET0__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_OFFSET0_HI_MAP_OFF0__B 0
+#define SIO_HI_RA_RAM_VB_OFFSET0_HI_MAP_OFF0__W 16
+#define SIO_HI_RA_RAM_VB_OFFSET0_HI_MAP_OFF0__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_OFFSET0_HI_MAP_OFF0__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_ENTRY1__A 0x420072
+#define SIO_HI_RA_RAM_VB_ENTRY1__W 16
+#define SIO_HI_RA_RAM_VB_ENTRY1__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_ENTRY1__PRE 0x0
+#define SIO_HI_RA_RAM_VB_OFFSET1__A 0x420073
+#define SIO_HI_RA_RAM_VB_OFFSET1__W 16
+#define SIO_HI_RA_RAM_VB_OFFSET1__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_OFFSET1__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_OFFSET1_HI_MAP_OFF__B 0
+#define SIO_HI_RA_RAM_VB_OFFSET1_HI_MAP_OFF__W 16
+#define SIO_HI_RA_RAM_VB_OFFSET1_HI_MAP_OFF__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_OFFSET1_HI_MAP_OFF__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_ENTRY2__A 0x420074
+#define SIO_HI_RA_RAM_VB_ENTRY2__W 16
+#define SIO_HI_RA_RAM_VB_ENTRY2__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_ENTRY2__PRE 0x0
+#define SIO_HI_RA_RAM_VB_OFFSET2__A 0x420075
+#define SIO_HI_RA_RAM_VB_OFFSET2__W 16
+#define SIO_HI_RA_RAM_VB_OFFSET2__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_OFFSET2__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_OFFSET2_HI_MAP_OFF__B 0
+#define SIO_HI_RA_RAM_VB_OFFSET2_HI_MAP_OFF__W 16
+#define SIO_HI_RA_RAM_VB_OFFSET2_HI_MAP_OFF__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_OFFSET2_HI_MAP_OFF__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_ENTRY3__A 0x420076
+#define SIO_HI_RA_RAM_VB_ENTRY3__W 16
+#define SIO_HI_RA_RAM_VB_ENTRY3__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_ENTRY3__PRE 0x0
+#define SIO_HI_RA_RAM_VB_OFFSET3__A 0x420077
+#define SIO_HI_RA_RAM_VB_OFFSET3__W 16
+#define SIO_HI_RA_RAM_VB_OFFSET3__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_OFFSET3__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_OFFSET3_HI_MAP_OFF__B 0
+#define SIO_HI_RA_RAM_VB_OFFSET3_HI_MAP_OFF__W 16
+#define SIO_HI_RA_RAM_VB_OFFSET3_HI_MAP_OFF__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_OFFSET3_HI_MAP_OFF__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_ENTRY4__A 0x420078
+#define SIO_HI_RA_RAM_VB_ENTRY4__W 16
+#define SIO_HI_RA_RAM_VB_ENTRY4__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_ENTRY4__PRE 0x0
+#define SIO_HI_RA_RAM_VB_OFFSET4__A 0x420079
+#define SIO_HI_RA_RAM_VB_OFFSET4__W 16
+#define SIO_HI_RA_RAM_VB_OFFSET4__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_OFFSET4__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_OFFSET4_HI_MAP_OFF__B 0
+#define SIO_HI_RA_RAM_VB_OFFSET4_HI_MAP_OFF__W 16
+#define SIO_HI_RA_RAM_VB_OFFSET4_HI_MAP_OFF__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_OFFSET4_HI_MAP_OFF__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_ENTRY5__A 0x42007A
+#define SIO_HI_RA_RAM_VB_ENTRY5__W 16
+#define SIO_HI_RA_RAM_VB_ENTRY5__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_ENTRY5__PRE 0x0
+#define SIO_HI_RA_RAM_VB_OFFSET5__A 0x42007B
+#define SIO_HI_RA_RAM_VB_OFFSET5__W 16
+#define SIO_HI_RA_RAM_VB_OFFSET5__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_OFFSET5__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_OFFSET5_HI_MAP_OFF__B 0
+#define SIO_HI_RA_RAM_VB_OFFSET5_HI_MAP_OFF__W 16
+#define SIO_HI_RA_RAM_VB_OFFSET5_HI_MAP_OFF__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_OFFSET5_HI_MAP_OFF__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_ENTRY6__A 0x42007C
+#define SIO_HI_RA_RAM_VB_ENTRY6__W 16
+#define SIO_HI_RA_RAM_VB_ENTRY6__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_ENTRY6__PRE 0x0
+#define SIO_HI_RA_RAM_VB_OFFSET6__A 0x42007D
+#define SIO_HI_RA_RAM_VB_OFFSET6__W 16
+#define SIO_HI_RA_RAM_VB_OFFSET6__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_OFFSET6__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_OFFSET6_HI_MAP_OFF__B 0
+#define SIO_HI_RA_RAM_VB_OFFSET6_HI_MAP_OFF__W 16
+#define SIO_HI_RA_RAM_VB_OFFSET6_HI_MAP_OFF__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_OFFSET6_HI_MAP_OFF__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_ENTRY7__A 0x42007E
+#define SIO_HI_RA_RAM_VB_ENTRY7__W 16
+#define SIO_HI_RA_RAM_VB_ENTRY7__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_ENTRY7__PRE 0x0
+#define SIO_HI_RA_RAM_VB_OFFSET7__A 0x42007F
+#define SIO_HI_RA_RAM_VB_OFFSET7__W 16
+#define SIO_HI_RA_RAM_VB_OFFSET7__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_OFFSET7__PRE 0x0
+
+#define SIO_HI_RA_RAM_VB_OFFSET7_HI_MAP_OFF__B 0
+#define SIO_HI_RA_RAM_VB_OFFSET7_HI_MAP_OFF__W 16
+#define SIO_HI_RA_RAM_VB_OFFSET7_HI_MAP_OFF__M 0xFFFF
+#define SIO_HI_RA_RAM_VB_OFFSET7_HI_MAP_OFF__PRE 0x0
+
+#define SIO_HI_IF_RAM_TRP_BPT_0__A 0x430000
+#define SIO_HI_IF_RAM_TRP_BPT_0__W 12
+#define SIO_HI_IF_RAM_TRP_BPT_0__M 0xFFF
+#define SIO_HI_IF_RAM_TRP_BPT_0__PRE 0x0
+#define SIO_HI_IF_RAM_TRP_BPT_1__A 0x430001
+#define SIO_HI_IF_RAM_TRP_BPT_1__W 12
+#define SIO_HI_IF_RAM_TRP_BPT_1__M 0xFFF
+#define SIO_HI_IF_RAM_TRP_BPT_1__PRE 0x0
+#define SIO_HI_IF_RAM_TRP_STK_0__A 0x430002
+#define SIO_HI_IF_RAM_TRP_STK_0__W 12
+#define SIO_HI_IF_RAM_TRP_STK_0__M 0xFFF
+#define SIO_HI_IF_RAM_TRP_STK_0__PRE 0x0
+#define SIO_HI_IF_RAM_TRP_STK_1__A 0x430003
+#define SIO_HI_IF_RAM_TRP_STK_1__W 12
+#define SIO_HI_IF_RAM_TRP_STK_1__M 0xFFF
+#define SIO_HI_IF_RAM_TRP_STK_1__PRE 0x0
+#define SIO_HI_IF_RAM_FUN_BASE__A 0x430300
+#define SIO_HI_IF_RAM_FUN_BASE__W 12
+#define SIO_HI_IF_RAM_FUN_BASE__M 0xFFF
+#define SIO_HI_IF_RAM_FUN_BASE__PRE 0x0
+
+#define SIO_HI_IF_COMM_EXEC__A 0x440000
+#define SIO_HI_IF_COMM_EXEC__W 2
+#define SIO_HI_IF_COMM_EXEC__M 0x3
+#define SIO_HI_IF_COMM_EXEC__PRE 0x0
+#define SIO_HI_IF_COMM_EXEC_STOP 0x0
+#define SIO_HI_IF_COMM_EXEC_ACTIVE 0x1
+#define SIO_HI_IF_COMM_EXEC_HOLD 0x2
+#define SIO_HI_IF_COMM_EXEC_STEP 0x3
+
+#define SIO_HI_IF_COMM_STATE__A 0x440001
+#define SIO_HI_IF_COMM_STATE__W 10
+#define SIO_HI_IF_COMM_STATE__M 0x3FF
+#define SIO_HI_IF_COMM_STATE__PRE 0x0
+#define SIO_HI_IF_COMM_INT_REQ__A 0x440003
+#define SIO_HI_IF_COMM_INT_REQ__W 1
+#define SIO_HI_IF_COMM_INT_REQ__M 0x1
+#define SIO_HI_IF_COMM_INT_REQ__PRE 0x0
+#define SIO_HI_IF_COMM_INT_STA__A 0x440005
+#define SIO_HI_IF_COMM_INT_STA__W 1
+#define SIO_HI_IF_COMM_INT_STA__M 0x1
+#define SIO_HI_IF_COMM_INT_STA__PRE 0x0
+#define SIO_HI_IF_COMM_INT_STA_STAT__B 0
+#define SIO_HI_IF_COMM_INT_STA_STAT__W 1
+#define SIO_HI_IF_COMM_INT_STA_STAT__M 0x1
+#define SIO_HI_IF_COMM_INT_STA_STAT__PRE 0x0
+
+#define SIO_HI_IF_COMM_INT_MSK__A 0x440006
+#define SIO_HI_IF_COMM_INT_MSK__W 1
+#define SIO_HI_IF_COMM_INT_MSK__M 0x1
+#define SIO_HI_IF_COMM_INT_MSK__PRE 0x0
+#define SIO_HI_IF_COMM_INT_MSK_STAT__B 0
+#define SIO_HI_IF_COMM_INT_MSK_STAT__W 1
+#define SIO_HI_IF_COMM_INT_MSK_STAT__M 0x1
+#define SIO_HI_IF_COMM_INT_MSK_STAT__PRE 0x0
+
+#define SIO_HI_IF_COMM_INT_STM__A 0x440007
+#define SIO_HI_IF_COMM_INT_STM__W 1
+#define SIO_HI_IF_COMM_INT_STM__M 0x1
+#define SIO_HI_IF_COMM_INT_STM__PRE 0x0
+#define SIO_HI_IF_COMM_INT_STM_STAT__B 0
+#define SIO_HI_IF_COMM_INT_STM_STAT__W 1
+#define SIO_HI_IF_COMM_INT_STM_STAT__M 0x1
+#define SIO_HI_IF_COMM_INT_STM_STAT__PRE 0x0
+
+#define SIO_HI_IF_STK_0__A 0x440010
+#define SIO_HI_IF_STK_0__W 10
+#define SIO_HI_IF_STK_0__M 0x3FF
+#define SIO_HI_IF_STK_0__PRE 0x2
+
+#define SIO_HI_IF_STK_0_ADDR__B 0
+#define SIO_HI_IF_STK_0_ADDR__W 10
+#define SIO_HI_IF_STK_0_ADDR__M 0x3FF
+#define SIO_HI_IF_STK_0_ADDR__PRE 0x2
+
+#define SIO_HI_IF_STK_1__A 0x440011
+#define SIO_HI_IF_STK_1__W 10
+#define SIO_HI_IF_STK_1__M 0x3FF
+#define SIO_HI_IF_STK_1__PRE 0x2
+#define SIO_HI_IF_STK_1_ADDR__B 0
+#define SIO_HI_IF_STK_1_ADDR__W 10
+#define SIO_HI_IF_STK_1_ADDR__M 0x3FF
+#define SIO_HI_IF_STK_1_ADDR__PRE 0x2
+
+#define SIO_HI_IF_STK_2__A 0x440012
+#define SIO_HI_IF_STK_2__W 10
+#define SIO_HI_IF_STK_2__M 0x3FF
+#define SIO_HI_IF_STK_2__PRE 0x2
+#define SIO_HI_IF_STK_2_ADDR__B 0
+#define SIO_HI_IF_STK_2_ADDR__W 10
+#define SIO_HI_IF_STK_2_ADDR__M 0x3FF
+#define SIO_HI_IF_STK_2_ADDR__PRE 0x2
+
+#define SIO_HI_IF_STK_3__A 0x440013
+#define SIO_HI_IF_STK_3__W 10
+#define SIO_HI_IF_STK_3__M 0x3FF
+#define SIO_HI_IF_STK_3__PRE 0x2
+
+#define SIO_HI_IF_STK_3_ADDR__B 0
+#define SIO_HI_IF_STK_3_ADDR__W 10
+#define SIO_HI_IF_STK_3_ADDR__M 0x3FF
+#define SIO_HI_IF_STK_3_ADDR__PRE 0x2
+
+#define SIO_HI_IF_BPT_IDX__A 0x44001F
+#define SIO_HI_IF_BPT_IDX__W 1
+#define SIO_HI_IF_BPT_IDX__M 0x1
+#define SIO_HI_IF_BPT_IDX__PRE 0x0
+
+#define SIO_HI_IF_BPT_IDX_ADDR__B 0
+#define SIO_HI_IF_BPT_IDX_ADDR__W 1
+#define SIO_HI_IF_BPT_IDX_ADDR__M 0x1
+#define SIO_HI_IF_BPT_IDX_ADDR__PRE 0x0
+
+#define SIO_HI_IF_BPT__A 0x440020
+#define SIO_HI_IF_BPT__W 10
+#define SIO_HI_IF_BPT__M 0x3FF
+#define SIO_HI_IF_BPT__PRE 0x2
+
+#define SIO_HI_IF_BPT_ADDR__B 0
+#define SIO_HI_IF_BPT_ADDR__W 10
+#define SIO_HI_IF_BPT_ADDR__M 0x3FF
+#define SIO_HI_IF_BPT_ADDR__PRE 0x2
+
+#define SIO_CC_COMM_EXEC__A 0x450000
+#define SIO_CC_COMM_EXEC__W 2
+#define SIO_CC_COMM_EXEC__M 0x3
+#define SIO_CC_COMM_EXEC__PRE 0x0
+#define SIO_CC_COMM_EXEC_STOP 0x0
+#define SIO_CC_COMM_EXEC_ACTIVE 0x1
+#define SIO_CC_COMM_EXEC_HOLD 0x2
+
+#define SIO_CC_PLL_MODE__A 0x450010
+#define SIO_CC_PLL_MODE__W 6
+#define SIO_CC_PLL_MODE__M 0x3F
+#define SIO_CC_PLL_MODE__PRE 0x0
+
+#define SIO_CC_PLL_MODE_FREF_SEL__B 0
+#define SIO_CC_PLL_MODE_FREF_SEL__W 2
+#define SIO_CC_PLL_MODE_FREF_SEL__M 0x3
+#define SIO_CC_PLL_MODE_FREF_SEL__PRE 0x0
+#define SIO_CC_PLL_MODE_FREF_SEL_OHW 0x0
+#define SIO_CC_PLL_MODE_FREF_SEL_27_00 0x1
+#define SIO_CC_PLL_MODE_FREF_SEL_20_25 0x2
+#define SIO_CC_PLL_MODE_FREF_SEL_4_00 0x3
+
+#define SIO_CC_PLL_MODE_LOCKSEL__B 2
+#define SIO_CC_PLL_MODE_LOCKSEL__W 2
+#define SIO_CC_PLL_MODE_LOCKSEL__M 0xC
+#define SIO_CC_PLL_MODE_LOCKSEL__PRE 0x0
+
+#define SIO_CC_PLL_MODE_BYPASS__B 4
+#define SIO_CC_PLL_MODE_BYPASS__W 2
+#define SIO_CC_PLL_MODE_BYPASS__M 0x30
+#define SIO_CC_PLL_MODE_BYPASS__PRE 0x0
+#define SIO_CC_PLL_MODE_BYPASS_OHW 0x0
+#define SIO_CC_PLL_MODE_BYPASS_OFF 0x10
+#define SIO_CC_PLL_MODE_BYPASS_ON 0x20
+
+#define SIO_CC_PLL_TEST__A 0x450011
+#define SIO_CC_PLL_TEST__W 8
+#define SIO_CC_PLL_TEST__M 0xFF
+#define SIO_CC_PLL_TEST__PRE 0x0
+
+#define SIO_CC_PLL_LOCK__A 0x450012
+#define SIO_CC_PLL_LOCK__W 1
+#define SIO_CC_PLL_LOCK__M 0x1
+#define SIO_CC_PLL_LOCK__PRE 0x0
+#define SIO_CC_CLK_MODE__A 0x450014
+#define SIO_CC_CLK_MODE__W 5
+#define SIO_CC_CLK_MODE__M 0x1F
+#define SIO_CC_CLK_MODE__PRE 0x0
+
+#define SIO_CC_CLK_MODE_DELAY__B 0
+#define SIO_CC_CLK_MODE_DELAY__W 4
+#define SIO_CC_CLK_MODE_DELAY__M 0xF
+#define SIO_CC_CLK_MODE_DELAY__PRE 0x0
+
+#define SIO_CC_CLK_MODE_INVERT__B 4
+#define SIO_CC_CLK_MODE_INVERT__W 1
+#define SIO_CC_CLK_MODE_INVERT__M 0x10
+#define SIO_CC_CLK_MODE_INVERT__PRE 0x0
+
+#define SIO_CC_PWD_MODE__A 0x450015
+#define SIO_CC_PWD_MODE__W 3
+#define SIO_CC_PWD_MODE__M 0x7
+#define SIO_CC_PWD_MODE__PRE 0x0
+
+#define SIO_CC_PWD_MODE_LEVEL__B 0
+#define SIO_CC_PWD_MODE_LEVEL__W 2
+#define SIO_CC_PWD_MODE_LEVEL__M 0x3
+#define SIO_CC_PWD_MODE_LEVEL__PRE 0x0
+#define SIO_CC_PWD_MODE_LEVEL_NONE 0x0
+#define SIO_CC_PWD_MODE_LEVEL_CLOCK 0x1
+#define SIO_CC_PWD_MODE_LEVEL_PLL 0x2
+#define SIO_CC_PWD_MODE_LEVEL_OSC 0x3
+
+#define SIO_CC_PWD_MODE_USE_LOCK__B 2
+#define SIO_CC_PWD_MODE_USE_LOCK__W 1
+#define SIO_CC_PWD_MODE_USE_LOCK__M 0x4
+#define SIO_CC_PWD_MODE_USE_LOCK__PRE 0x0
+
+#define SIO_CC_SOFT_RST__A 0x450016
+#define SIO_CC_SOFT_RST__W 2
+#define SIO_CC_SOFT_RST__M 0x3
+#define SIO_CC_SOFT_RST__PRE 0x0
+
+#define SIO_CC_SOFT_RST_SYS__B 0
+#define SIO_CC_SOFT_RST_SYS__W 1
+#define SIO_CC_SOFT_RST_SYS__M 0x1
+#define SIO_CC_SOFT_RST_SYS__PRE 0x0
+
+#define SIO_CC_SOFT_RST_OSC__B 1
+#define SIO_CC_SOFT_RST_OSC__W 1
+#define SIO_CC_SOFT_RST_OSC__M 0x2
+#define SIO_CC_SOFT_RST_OSC__PRE 0x0
+
+#define SIO_CC_UPDATE__A 0x450017
+#define SIO_CC_UPDATE__W 16
+#define SIO_CC_UPDATE__M 0xFFFF
+#define SIO_CC_UPDATE__PRE 0x0
+#define SIO_CC_UPDATE_KEY 0xFABA
+
+#define SIO_SA_COMM_EXEC__A 0x460000
+#define SIO_SA_COMM_EXEC__W 2
+#define SIO_SA_COMM_EXEC__M 0x3
+#define SIO_SA_COMM_EXEC__PRE 0x0
+#define SIO_SA_COMM_EXEC_STOP 0x0
+#define SIO_SA_COMM_EXEC_ACTIVE 0x1
+#define SIO_SA_COMM_EXEC_HOLD 0x2
+
+#define SIO_SA_COMM_INT_REQ__A 0x460003
+#define SIO_SA_COMM_INT_REQ__W 1
+#define SIO_SA_COMM_INT_REQ__M 0x1
+#define SIO_SA_COMM_INT_REQ__PRE 0x0
+#define SIO_SA_COMM_INT_STA__A 0x460005
+#define SIO_SA_COMM_INT_STA__W 4
+#define SIO_SA_COMM_INT_STA__M 0xF
+#define SIO_SA_COMM_INT_STA__PRE 0x0
+
+#define SIO_SA_COMM_INT_STA_TR_END_INT_STA__B 0
+#define SIO_SA_COMM_INT_STA_TR_END_INT_STA__W 1
+#define SIO_SA_COMM_INT_STA_TR_END_INT_STA__M 0x1
+#define SIO_SA_COMM_INT_STA_TR_END_INT_STA__PRE 0x0
+
+#define SIO_SA_COMM_INT_STA_TR_BUFF_EMPTY_INT__B 1
+#define SIO_SA_COMM_INT_STA_TR_BUFF_EMPTY_INT__W 1
+#define SIO_SA_COMM_INT_STA_TR_BUFF_EMPTY_INT__M 0x2
+#define SIO_SA_COMM_INT_STA_TR_BUFF_EMPTY_INT__PRE 0x0
+
+#define SIO_SA_COMM_INT_STA_RX_END_INT_STA__B 2
+#define SIO_SA_COMM_INT_STA_RX_END_INT_STA__W 1
+#define SIO_SA_COMM_INT_STA_RX_END_INT_STA__M 0x4
+#define SIO_SA_COMM_INT_STA_RX_END_INT_STA__PRE 0x0
+
+#define SIO_SA_COMM_INT_STA_RX_BUFF_FULL_INT__B 3
+#define SIO_SA_COMM_INT_STA_RX_BUFF_FULL_INT__W 1
+#define SIO_SA_COMM_INT_STA_RX_BUFF_FULL_INT__M 0x8
+#define SIO_SA_COMM_INT_STA_RX_BUFF_FULL_INT__PRE 0x0
+
+#define SIO_SA_COMM_INT_MSK__A 0x460006
+#define SIO_SA_COMM_INT_MSK__W 4
+#define SIO_SA_COMM_INT_MSK__M 0xF
+#define SIO_SA_COMM_INT_MSK__PRE 0x0
+
+#define SIO_SA_COMM_INT_MSK_TR_END_INT_MASK__B 0
+#define SIO_SA_COMM_INT_MSK_TR_END_INT_MASK__W 1
+#define SIO_SA_COMM_INT_MSK_TR_END_INT_MASK__M 0x1
+#define SIO_SA_COMM_INT_MSK_TR_END_INT_MASK__PRE 0x0
+
+#define SIO_SA_COMM_INT_MSK_TR_BUFF_EMPTY_MASK__B 1
+#define SIO_SA_COMM_INT_MSK_TR_BUFF_EMPTY_MASK__W 1
+#define SIO_SA_COMM_INT_MSK_TR_BUFF_EMPTY_MASK__M 0x2
+#define SIO_SA_COMM_INT_MSK_TR_BUFF_EMPTY_MASK__PRE 0x0
+
+#define SIO_SA_COMM_INT_MSK_RX_END_INT_MASK__B 2
+#define SIO_SA_COMM_INT_MSK_RX_END_INT_MASK__W 1
+#define SIO_SA_COMM_INT_MSK_RX_END_INT_MASK__M 0x4
+#define SIO_SA_COMM_INT_MSK_RX_END_INT_MASK__PRE 0x0
+
+#define SIO_SA_COMM_INT_MSK_RX_BUFF_FULL_MASK__B 3
+#define SIO_SA_COMM_INT_MSK_RX_BUFF_FULL_MASK__W 1
+#define SIO_SA_COMM_INT_MSK_RX_BUFF_FULL_MASK__M 0x8
+#define SIO_SA_COMM_INT_MSK_RX_BUFF_FULL_MASK__PRE 0x0
+
+#define SIO_SA_COMM_INT_STM__A 0x460007
+#define SIO_SA_COMM_INT_STM__W 4
+#define SIO_SA_COMM_INT_STM__M 0xF
+#define SIO_SA_COMM_INT_STM__PRE 0x0
+
+#define SIO_SA_COMM_INT_STM_TR_END_INT_MASK__B 0
+#define SIO_SA_COMM_INT_STM_TR_END_INT_MASK__W 1
+#define SIO_SA_COMM_INT_STM_TR_END_INT_MASK__M 0x1
+#define SIO_SA_COMM_INT_STM_TR_END_INT_MASK__PRE 0x0
+
+#define SIO_SA_COMM_INT_STM_TR_BUFF_EMPTY_MASK__B 1
+#define SIO_SA_COMM_INT_STM_TR_BUFF_EMPTY_MASK__W 1
+#define SIO_SA_COMM_INT_STM_TR_BUFF_EMPTY_MASK__M 0x2
+#define SIO_SA_COMM_INT_STM_TR_BUFF_EMPTY_MASK__PRE 0x0
+
+#define SIO_SA_COMM_INT_STM_RX_END_INT_MASK__B 2
+#define SIO_SA_COMM_INT_STM_RX_END_INT_MASK__W 1
+#define SIO_SA_COMM_INT_STM_RX_END_INT_MASK__M 0x4
+#define SIO_SA_COMM_INT_STM_RX_END_INT_MASK__PRE 0x0
+
+#define SIO_SA_COMM_INT_STM_RX_BUFF_FULL_MASK__B 3
+#define SIO_SA_COMM_INT_STM_RX_BUFF_FULL_MASK__W 1
+#define SIO_SA_COMM_INT_STM_RX_BUFF_FULL_MASK__M 0x8
+#define SIO_SA_COMM_INT_STM_RX_BUFF_FULL_MASK__PRE 0x0
+
+#define SIO_SA_PRESCALER__A 0x460010
+#define SIO_SA_PRESCALER__W 13
+#define SIO_SA_PRESCALER__M 0x1FFF
+#define SIO_SA_PRESCALER__PRE 0x18B7
+#define SIO_SA_TX_DATA0__A 0x460011
+#define SIO_SA_TX_DATA0__W 16
+#define SIO_SA_TX_DATA0__M 0xFFFF
+#define SIO_SA_TX_DATA0__PRE 0x0
+#define SIO_SA_TX_DATA1__A 0x460012
+#define SIO_SA_TX_DATA1__W 16
+#define SIO_SA_TX_DATA1__M 0xFFFF
+#define SIO_SA_TX_DATA1__PRE 0x0
+#define SIO_SA_TX_DATA2__A 0x460013
+#define SIO_SA_TX_DATA2__W 16
+#define SIO_SA_TX_DATA2__M 0xFFFF
+#define SIO_SA_TX_DATA2__PRE 0x0
+#define SIO_SA_TX_DATA3__A 0x460014
+#define SIO_SA_TX_DATA3__W 16
+#define SIO_SA_TX_DATA3__M 0xFFFF
+#define SIO_SA_TX_DATA3__PRE 0x0
+#define SIO_SA_TX_LENGTH__A 0x460015
+#define SIO_SA_TX_LENGTH__W 6
+#define SIO_SA_TX_LENGTH__M 0x3F
+#define SIO_SA_TX_LENGTH__PRE 0x0
+#define SIO_SA_TX_COMMAND__A 0x460016
+#define SIO_SA_TX_COMMAND__W 2
+#define SIO_SA_TX_COMMAND__M 0x3
+#define SIO_SA_TX_COMMAND__PRE 0x3
+
+#define SIO_SA_TX_COMMAND_TX_INVERT__B 0
+#define SIO_SA_TX_COMMAND_TX_INVERT__W 1
+#define SIO_SA_TX_COMMAND_TX_INVERT__M 0x1
+#define SIO_SA_TX_COMMAND_TX_INVERT__PRE 0x1
+
+#define SIO_SA_TX_COMMAND_TX_ENABLE__B 1
+#define SIO_SA_TX_COMMAND_TX_ENABLE__W 1
+#define SIO_SA_TX_COMMAND_TX_ENABLE__M 0x2
+#define SIO_SA_TX_COMMAND_TX_ENABLE__PRE 0x2
+
+#define SIO_SA_TX_STATUS__A 0x460017
+#define SIO_SA_TX_STATUS__W 2
+#define SIO_SA_TX_STATUS__M 0x3
+#define SIO_SA_TX_STATUS__PRE 0x0
+
+#define SIO_SA_TX_STATUS_BUSY__B 0
+#define SIO_SA_TX_STATUS_BUSY__W 1
+#define SIO_SA_TX_STATUS_BUSY__M 0x1
+#define SIO_SA_TX_STATUS_BUSY__PRE 0x0
+
+#define SIO_SA_TX_STATUS_BUFF_FULL__B 1
+#define SIO_SA_TX_STATUS_BUFF_FULL__W 1
+#define SIO_SA_TX_STATUS_BUFF_FULL__M 0x2
+#define SIO_SA_TX_STATUS_BUFF_FULL__PRE 0x0
+
+#define SIO_SA_RX_DATA0__A 0x460018
+#define SIO_SA_RX_DATA0__W 16
+#define SIO_SA_RX_DATA0__M 0xFFFF
+#define SIO_SA_RX_DATA0__PRE 0x0
+#define SIO_SA_RX_DATA1__A 0x460019
+#define SIO_SA_RX_DATA1__W 16
+#define SIO_SA_RX_DATA1__M 0xFFFF
+#define SIO_SA_RX_DATA1__PRE 0x0
+#define SIO_SA_RX_LENGTH__A 0x46001A
+#define SIO_SA_RX_LENGTH__W 6
+#define SIO_SA_RX_LENGTH__M 0x3F
+#define SIO_SA_RX_LENGTH__PRE 0x0
+#define SIO_SA_RX_COMMAND__A 0x46001B
+#define SIO_SA_RX_COMMAND__W 1
+#define SIO_SA_RX_COMMAND__M 0x1
+#define SIO_SA_RX_COMMAND__PRE 0x1
+
+#define SIO_SA_RX_COMMAND_RX_INVERT__B 0
+#define SIO_SA_RX_COMMAND_RX_INVERT__W 1
+#define SIO_SA_RX_COMMAND_RX_INVERT__M 0x1
+#define SIO_SA_RX_COMMAND_RX_INVERT__PRE 0x1
+
+#define SIO_SA_RX_STATUS__A 0x46001C
+#define SIO_SA_RX_STATUS__W 2
+#define SIO_SA_RX_STATUS__M 0x3
+#define SIO_SA_RX_STATUS__PRE 0x0
+
+#define SIO_SA_RX_STATUS_BUSY__B 0
+#define SIO_SA_RX_STATUS_BUSY__W 1
+#define SIO_SA_RX_STATUS_BUSY__M 0x1
+#define SIO_SA_RX_STATUS_BUSY__PRE 0x0
+
+#define SIO_SA_RX_STATUS_BUFF_FULL__B 1
+#define SIO_SA_RX_STATUS_BUFF_FULL__W 1
+#define SIO_SA_RX_STATUS_BUFF_FULL__M 0x2
+#define SIO_SA_RX_STATUS_BUFF_FULL__PRE 0x0
+
+#define SIO_PDR_COMM_EXEC__A 0x7F0000
+#define SIO_PDR_COMM_EXEC__W 2
+#define SIO_PDR_COMM_EXEC__M 0x3
+#define SIO_PDR_COMM_EXEC__PRE 0x0
+#define SIO_PDR_COMM_EXEC_STOP 0x0
+#define SIO_PDR_COMM_EXEC_ACTIVE 0x1
+#define SIO_PDR_COMM_EXEC_HOLD 0x2
+
+#define SIO_PDR_MON_CFG__A 0x7F0010
+#define SIO_PDR_MON_CFG__W 2
+#define SIO_PDR_MON_CFG__M 0x3
+#define SIO_PDR_MON_CFG__PRE 0x0
+
+#define SIO_PDR_MON_CFG_OSEL__B 0
+#define SIO_PDR_MON_CFG_OSEL__W 1
+#define SIO_PDR_MON_CFG_OSEL__M 0x1
+#define SIO_PDR_MON_CFG_OSEL__PRE 0x0
+
+#define SIO_PDR_MON_CFG_IACT__B 1
+#define SIO_PDR_MON_CFG_IACT__W 1
+#define SIO_PDR_MON_CFG_IACT__M 0x2
+#define SIO_PDR_MON_CFG_IACT__PRE 0x0
+
+#define SIO_PDR_FDB_CFG__A 0x7F0011
+#define SIO_PDR_FDB_CFG__W 2
+#define SIO_PDR_FDB_CFG__M 0x3
+#define SIO_PDR_FDB_CFG__PRE 0x0
+#define SIO_PDR_FDB_CFG_SEL__B 0
+#define SIO_PDR_FDB_CFG_SEL__W 2
+#define SIO_PDR_FDB_CFG_SEL__M 0x3
+#define SIO_PDR_FDB_CFG_SEL__PRE 0x0
+
+#define SIO_PDR_SMA_RX_SEL__A 0x7F0012
+#define SIO_PDR_SMA_RX_SEL__W 4
+#define SIO_PDR_SMA_RX_SEL__M 0xF
+#define SIO_PDR_SMA_RX_SEL__PRE 0x0
+#define SIO_PDR_SMA_RX_SEL_SEL__B 0
+#define SIO_PDR_SMA_RX_SEL_SEL__W 4
+#define SIO_PDR_SMA_RX_SEL_SEL__M 0xF
+#define SIO_PDR_SMA_RX_SEL_SEL__PRE 0x0
+
+#define SIO_PDR_SMA_TX_SILENT__A 0x7F0013
+#define SIO_PDR_SMA_TX_SILENT__W 1
+#define SIO_PDR_SMA_TX_SILENT__M 0x1
+#define SIO_PDR_SMA_TX_SILENT__PRE 0x0
+#define SIO_PDR_UIO_IN_LO__A 0x7F0014
+#define SIO_PDR_UIO_IN_LO__W 16
+#define SIO_PDR_UIO_IN_LO__M 0xFFFF
+#define SIO_PDR_UIO_IN_LO__PRE 0x0
+#define SIO_PDR_UIO_IN_LO_DATA__B 0
+#define SIO_PDR_UIO_IN_LO_DATA__W 16
+#define SIO_PDR_UIO_IN_LO_DATA__M 0xFFFF
+#define SIO_PDR_UIO_IN_LO_DATA__PRE 0x0
+
+#define SIO_PDR_UIO_IN_HI__A 0x7F0015
+#define SIO_PDR_UIO_IN_HI__W 14
+#define SIO_PDR_UIO_IN_HI__M 0x3FFF
+#define SIO_PDR_UIO_IN_HI__PRE 0x0
+#define SIO_PDR_UIO_IN_HI_DATA__B 0
+#define SIO_PDR_UIO_IN_HI_DATA__W 14
+#define SIO_PDR_UIO_IN_HI_DATA__M 0x3FFF
+#define SIO_PDR_UIO_IN_HI_DATA__PRE 0x0
+
+#define SIO_PDR_UIO_OUT_LO__A 0x7F0016
+#define SIO_PDR_UIO_OUT_LO__W 16
+#define SIO_PDR_UIO_OUT_LO__M 0xFFFF
+#define SIO_PDR_UIO_OUT_LO__PRE 0x0
+#define SIO_PDR_UIO_OUT_LO_DATA__B 0
+#define SIO_PDR_UIO_OUT_LO_DATA__W 16
+#define SIO_PDR_UIO_OUT_LO_DATA__M 0xFFFF
+#define SIO_PDR_UIO_OUT_LO_DATA__PRE 0x0
+
+#define SIO_PDR_UIO_OUT_HI__A 0x7F0017
+#define SIO_PDR_UIO_OUT_HI__W 14
+#define SIO_PDR_UIO_OUT_HI__M 0x3FFF
+#define SIO_PDR_UIO_OUT_HI__PRE 0x0
+#define SIO_PDR_UIO_OUT_HI_DATA__B 0
+#define SIO_PDR_UIO_OUT_HI_DATA__W 14
+#define SIO_PDR_UIO_OUT_HI_DATA__M 0x3FFF
+#define SIO_PDR_UIO_OUT_HI_DATA__PRE 0x0
+
+#define SIO_PDR_PWM1_MODE__A 0x7F0018
+#define SIO_PDR_PWM1_MODE__W 2
+#define SIO_PDR_PWM1_MODE__M 0x3
+#define SIO_PDR_PWM1_MODE__PRE 0x0
+#define SIO_PDR_PWM1_PRESCALE__A 0x7F0019
+#define SIO_PDR_PWM1_PRESCALE__W 6
+#define SIO_PDR_PWM1_PRESCALE__M 0x3F
+#define SIO_PDR_PWM1_PRESCALE__PRE 0x0
+#define SIO_PDR_PWM1_VALUE__A 0x7F001A
+#define SIO_PDR_PWM1_VALUE__W 11
+#define SIO_PDR_PWM1_VALUE__M 0x7FF
+#define SIO_PDR_PWM1_VALUE__PRE 0x0
+#define SIO_PDR_PWM2_MODE__A 0x7F001C
+#define SIO_PDR_PWM2_MODE__W 2
+#define SIO_PDR_PWM2_MODE__M 0x3
+#define SIO_PDR_PWM2_MODE__PRE 0x0
+#define SIO_PDR_PWM2_PRESCALE__A 0x7F001D
+#define SIO_PDR_PWM2_PRESCALE__W 6
+#define SIO_PDR_PWM2_PRESCALE__M 0x3F
+#define SIO_PDR_PWM2_PRESCALE__PRE 0x0
+#define SIO_PDR_PWM2_VALUE__A 0x7F001E
+#define SIO_PDR_PWM2_VALUE__W 11
+#define SIO_PDR_PWM2_VALUE__M 0x7FF
+#define SIO_PDR_PWM2_VALUE__PRE 0x0
+#define SIO_PDR_OHW_CFG__A 0x7F001F
+#define SIO_PDR_OHW_CFG__W 7
+#define SIO_PDR_OHW_CFG__M 0x7F
+#define SIO_PDR_OHW_CFG__PRE 0x0
+
+#define SIO_PDR_OHW_CFG_FREF_SEL__B 0
+#define SIO_PDR_OHW_CFG_FREF_SEL__W 2
+#define SIO_PDR_OHW_CFG_FREF_SEL__M 0x3
+#define SIO_PDR_OHW_CFG_FREF_SEL__PRE 0x0
+
+#define SIO_PDR_OHW_CFG_BYPASS__B 2
+#define SIO_PDR_OHW_CFG_BYPASS__W 1
+#define SIO_PDR_OHW_CFG_BYPASS__M 0x4
+#define SIO_PDR_OHW_CFG_BYPASS__PRE 0x0
+
+#define SIO_PDR_OHW_CFG_ASEL__B 3
+#define SIO_PDR_OHW_CFG_ASEL__W 3
+#define SIO_PDR_OHW_CFG_ASEL__M 0x38
+#define SIO_PDR_OHW_CFG_ASEL__PRE 0x0
+
+#define SIO_PDR_OHW_CFG_SPEED__B 6
+#define SIO_PDR_OHW_CFG_SPEED__W 1
+#define SIO_PDR_OHW_CFG_SPEED__M 0x40
+#define SIO_PDR_OHW_CFG_SPEED__PRE 0x0
+
+#define SIO_PDR_I2S_WS_CFG__A 0x7F0020
+#define SIO_PDR_I2S_WS_CFG__W 9
+#define SIO_PDR_I2S_WS_CFG__M 0x1FF
+#define SIO_PDR_I2S_WS_CFG__PRE 0x10
+#define SIO_PDR_I2S_WS_CFG_MODE__B 0
+#define SIO_PDR_I2S_WS_CFG_MODE__W 3
+#define SIO_PDR_I2S_WS_CFG_MODE__M 0x7
+#define SIO_PDR_I2S_WS_CFG_MODE__PRE 0x0
+#define SIO_PDR_I2S_WS_CFG_DRIVE__B 3
+#define SIO_PDR_I2S_WS_CFG_DRIVE__W 3
+#define SIO_PDR_I2S_WS_CFG_DRIVE__M 0x38
+#define SIO_PDR_I2S_WS_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_I2S_WS_CFG_KEEP__B 6
+#define SIO_PDR_I2S_WS_CFG_KEEP__W 2
+#define SIO_PDR_I2S_WS_CFG_KEEP__M 0xC0
+#define SIO_PDR_I2S_WS_CFG_KEEP__PRE 0x0
+#define SIO_PDR_I2S_WS_CFG_UIO__B 8
+#define SIO_PDR_I2S_WS_CFG_UIO__W 1
+#define SIO_PDR_I2S_WS_CFG_UIO__M 0x100
+#define SIO_PDR_I2S_WS_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_GPIO_CFG__A 0x7F0021
+#define SIO_PDR_GPIO_CFG__W 9
+#define SIO_PDR_GPIO_CFG__M 0x1FF
+#define SIO_PDR_GPIO_CFG__PRE 0x10
+#define SIO_PDR_GPIO_CFG_MODE__B 0
+#define SIO_PDR_GPIO_CFG_MODE__W 3
+#define SIO_PDR_GPIO_CFG_MODE__M 0x7
+#define SIO_PDR_GPIO_CFG_MODE__PRE 0x0
+#define SIO_PDR_GPIO_CFG_DRIVE__B 3
+#define SIO_PDR_GPIO_CFG_DRIVE__W 3
+#define SIO_PDR_GPIO_CFG_DRIVE__M 0x38
+#define SIO_PDR_GPIO_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_GPIO_CFG_KEEP__B 6
+#define SIO_PDR_GPIO_CFG_KEEP__W 2
+#define SIO_PDR_GPIO_CFG_KEEP__M 0xC0
+#define SIO_PDR_GPIO_CFG_KEEP__PRE 0x0
+#define SIO_PDR_GPIO_CFG_UIO__B 8
+#define SIO_PDR_GPIO_CFG_UIO__W 1
+#define SIO_PDR_GPIO_CFG_UIO__M 0x100
+#define SIO_PDR_GPIO_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_IRQN_CFG__A 0x7F0022
+#define SIO_PDR_IRQN_CFG__W 9
+#define SIO_PDR_IRQN_CFG__M 0x1FF
+#define SIO_PDR_IRQN_CFG__PRE 0x10
+#define SIO_PDR_IRQN_CFG_MODE__B 0
+#define SIO_PDR_IRQN_CFG_MODE__W 3
+#define SIO_PDR_IRQN_CFG_MODE__M 0x7
+#define SIO_PDR_IRQN_CFG_MODE__PRE 0x0
+#define SIO_PDR_IRQN_CFG_DRIVE__B 3
+#define SIO_PDR_IRQN_CFG_DRIVE__W 3
+#define SIO_PDR_IRQN_CFG_DRIVE__M 0x38
+#define SIO_PDR_IRQN_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_IRQN_CFG_KEEP__B 6
+#define SIO_PDR_IRQN_CFG_KEEP__W 2
+#define SIO_PDR_IRQN_CFG_KEEP__M 0xC0
+#define SIO_PDR_IRQN_CFG_KEEP__PRE 0x0
+#define SIO_PDR_IRQN_CFG_UIO__B 8
+#define SIO_PDR_IRQN_CFG_UIO__W 1
+#define SIO_PDR_IRQN_CFG_UIO__M 0x100
+#define SIO_PDR_IRQN_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_OOB_CRX_CFG__A 0x7F0023
+#define SIO_PDR_OOB_CRX_CFG__W 9
+#define SIO_PDR_OOB_CRX_CFG__M 0x1FF
+#define SIO_PDR_OOB_CRX_CFG__PRE 0x10
+#define SIO_PDR_OOB_CRX_CFG_MODE__B 0
+#define SIO_PDR_OOB_CRX_CFG_MODE__W 3
+#define SIO_PDR_OOB_CRX_CFG_MODE__M 0x7
+#define SIO_PDR_OOB_CRX_CFG_MODE__PRE 0x0
+#define SIO_PDR_OOB_CRX_CFG_DRIVE__B 3
+#define SIO_PDR_OOB_CRX_CFG_DRIVE__W 3
+#define SIO_PDR_OOB_CRX_CFG_DRIVE__M 0x38
+#define SIO_PDR_OOB_CRX_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_OOB_CRX_CFG_KEEP__B 6
+#define SIO_PDR_OOB_CRX_CFG_KEEP__W 2
+#define SIO_PDR_OOB_CRX_CFG_KEEP__M 0xC0
+#define SIO_PDR_OOB_CRX_CFG_KEEP__PRE 0x0
+#define SIO_PDR_OOB_CRX_CFG_UIO__B 8
+#define SIO_PDR_OOB_CRX_CFG_UIO__W 1
+#define SIO_PDR_OOB_CRX_CFG_UIO__M 0x100
+#define SIO_PDR_OOB_CRX_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_OOB_DRX_CFG__A 0x7F0024
+#define SIO_PDR_OOB_DRX_CFG__W 9
+#define SIO_PDR_OOB_DRX_CFG__M 0x1FF
+#define SIO_PDR_OOB_DRX_CFG__PRE 0x10
+#define SIO_PDR_OOB_DRX_CFG_MODE__B 0
+#define SIO_PDR_OOB_DRX_CFG_MODE__W 3
+#define SIO_PDR_OOB_DRX_CFG_MODE__M 0x7
+#define SIO_PDR_OOB_DRX_CFG_MODE__PRE 0x0
+#define SIO_PDR_OOB_DRX_CFG_DRIVE__B 3
+#define SIO_PDR_OOB_DRX_CFG_DRIVE__W 3
+#define SIO_PDR_OOB_DRX_CFG_DRIVE__M 0x38
+#define SIO_PDR_OOB_DRX_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_OOB_DRX_CFG_KEEP__B 6
+#define SIO_PDR_OOB_DRX_CFG_KEEP__W 2
+#define SIO_PDR_OOB_DRX_CFG_KEEP__M 0xC0
+#define SIO_PDR_OOB_DRX_CFG_KEEP__PRE 0x0
+#define SIO_PDR_OOB_DRX_CFG_UIO__B 8
+#define SIO_PDR_OOB_DRX_CFG_UIO__W 1
+#define SIO_PDR_OOB_DRX_CFG_UIO__M 0x100
+#define SIO_PDR_OOB_DRX_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_MSTRT_CFG__A 0x7F0025
+#define SIO_PDR_MSTRT_CFG__W 9
+#define SIO_PDR_MSTRT_CFG__M 0x1FF
+#define SIO_PDR_MSTRT_CFG__PRE 0x50
+#define SIO_PDR_MSTRT_CFG_MODE__B 0
+#define SIO_PDR_MSTRT_CFG_MODE__W 3
+#define SIO_PDR_MSTRT_CFG_MODE__M 0x7
+#define SIO_PDR_MSTRT_CFG_MODE__PRE 0x0
+#define SIO_PDR_MSTRT_CFG_DRIVE__B 3
+#define SIO_PDR_MSTRT_CFG_DRIVE__W 3
+#define SIO_PDR_MSTRT_CFG_DRIVE__M 0x38
+#define SIO_PDR_MSTRT_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_MSTRT_CFG_KEEP__B 6
+#define SIO_PDR_MSTRT_CFG_KEEP__W 2
+#define SIO_PDR_MSTRT_CFG_KEEP__M 0xC0
+#define SIO_PDR_MSTRT_CFG_KEEP__PRE 0x40
+#define SIO_PDR_MSTRT_CFG_UIO__B 8
+#define SIO_PDR_MSTRT_CFG_UIO__W 1
+#define SIO_PDR_MSTRT_CFG_UIO__M 0x100
+#define SIO_PDR_MSTRT_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_MERR_CFG__A 0x7F0026
+#define SIO_PDR_MERR_CFG__W 9
+#define SIO_PDR_MERR_CFG__M 0x1FF
+#define SIO_PDR_MERR_CFG__PRE 0x50
+#define SIO_PDR_MERR_CFG_MODE__B 0
+#define SIO_PDR_MERR_CFG_MODE__W 3
+#define SIO_PDR_MERR_CFG_MODE__M 0x7
+#define SIO_PDR_MERR_CFG_MODE__PRE 0x0
+#define SIO_PDR_MERR_CFG_DRIVE__B 3
+#define SIO_PDR_MERR_CFG_DRIVE__W 3
+#define SIO_PDR_MERR_CFG_DRIVE__M 0x38
+#define SIO_PDR_MERR_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_MERR_CFG_KEEP__B 6
+#define SIO_PDR_MERR_CFG_KEEP__W 2
+#define SIO_PDR_MERR_CFG_KEEP__M 0xC0
+#define SIO_PDR_MERR_CFG_KEEP__PRE 0x40
+#define SIO_PDR_MERR_CFG_UIO__B 8
+#define SIO_PDR_MERR_CFG_UIO__W 1
+#define SIO_PDR_MERR_CFG_UIO__M 0x100
+#define SIO_PDR_MERR_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_MCLK_CFG__A 0x7F0028
+#define SIO_PDR_MCLK_CFG__W 9
+#define SIO_PDR_MCLK_CFG__M 0x1FF
+#define SIO_PDR_MCLK_CFG__PRE 0x50
+#define SIO_PDR_MCLK_CFG_MODE__B 0
+#define SIO_PDR_MCLK_CFG_MODE__W 3
+#define SIO_PDR_MCLK_CFG_MODE__M 0x7
+#define SIO_PDR_MCLK_CFG_MODE__PRE 0x0
+#define SIO_PDR_MCLK_CFG_DRIVE__B 3
+#define SIO_PDR_MCLK_CFG_DRIVE__W 3
+#define SIO_PDR_MCLK_CFG_DRIVE__M 0x38
+#define SIO_PDR_MCLK_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_MCLK_CFG_KEEP__B 6
+#define SIO_PDR_MCLK_CFG_KEEP__W 2
+#define SIO_PDR_MCLK_CFG_KEEP__M 0xC0
+#define SIO_PDR_MCLK_CFG_KEEP__PRE 0x40
+#define SIO_PDR_MCLK_CFG_UIO__B 8
+#define SIO_PDR_MCLK_CFG_UIO__W 1
+#define SIO_PDR_MCLK_CFG_UIO__M 0x100
+#define SIO_PDR_MCLK_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_MVAL_CFG__A 0x7F0029
+#define SIO_PDR_MVAL_CFG__W 9
+#define SIO_PDR_MVAL_CFG__M 0x1FF
+#define SIO_PDR_MVAL_CFG__PRE 0x50
+#define SIO_PDR_MVAL_CFG_MODE__B 0
+#define SIO_PDR_MVAL_CFG_MODE__W 3
+#define SIO_PDR_MVAL_CFG_MODE__M 0x7
+#define SIO_PDR_MVAL_CFG_MODE__PRE 0x0
+#define SIO_PDR_MVAL_CFG_DRIVE__B 3
+#define SIO_PDR_MVAL_CFG_DRIVE__W 3
+#define SIO_PDR_MVAL_CFG_DRIVE__M 0x38
+#define SIO_PDR_MVAL_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_MVAL_CFG_KEEP__B 6
+#define SIO_PDR_MVAL_CFG_KEEP__W 2
+#define SIO_PDR_MVAL_CFG_KEEP__M 0xC0
+#define SIO_PDR_MVAL_CFG_KEEP__PRE 0x40
+#define SIO_PDR_MVAL_CFG_UIO__B 8
+#define SIO_PDR_MVAL_CFG_UIO__W 1
+#define SIO_PDR_MVAL_CFG_UIO__M 0x100
+#define SIO_PDR_MVAL_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_MD0_CFG__A 0x7F002A
+#define SIO_PDR_MD0_CFG__W 9
+#define SIO_PDR_MD0_CFG__M 0x1FF
+#define SIO_PDR_MD0_CFG__PRE 0x50
+#define SIO_PDR_MD0_CFG_MODE__B 0
+#define SIO_PDR_MD0_CFG_MODE__W 3
+#define SIO_PDR_MD0_CFG_MODE__M 0x7
+#define SIO_PDR_MD0_CFG_MODE__PRE 0x0
+#define SIO_PDR_MD0_CFG_DRIVE__B 3
+#define SIO_PDR_MD0_CFG_DRIVE__W 3
+#define SIO_PDR_MD0_CFG_DRIVE__M 0x38
+#define SIO_PDR_MD0_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_MD0_CFG_KEEP__B 6
+#define SIO_PDR_MD0_CFG_KEEP__W 2
+#define SIO_PDR_MD0_CFG_KEEP__M 0xC0
+#define SIO_PDR_MD0_CFG_KEEP__PRE 0x40
+#define SIO_PDR_MD0_CFG_UIO__B 8
+#define SIO_PDR_MD0_CFG_UIO__W 1
+#define SIO_PDR_MD0_CFG_UIO__M 0x100
+#define SIO_PDR_MD0_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_MD1_CFG__A 0x7F002B
+#define SIO_PDR_MD1_CFG__W 9
+#define SIO_PDR_MD1_CFG__M 0x1FF
+#define SIO_PDR_MD1_CFG__PRE 0x50
+#define SIO_PDR_MD1_CFG_MODE__B 0
+#define SIO_PDR_MD1_CFG_MODE__W 3
+#define SIO_PDR_MD1_CFG_MODE__M 0x7
+#define SIO_PDR_MD1_CFG_MODE__PRE 0x0
+#define SIO_PDR_MD1_CFG_DRIVE__B 3
+#define SIO_PDR_MD1_CFG_DRIVE__W 3
+#define SIO_PDR_MD1_CFG_DRIVE__M 0x38
+#define SIO_PDR_MD1_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_MD1_CFG_KEEP__B 6
+#define SIO_PDR_MD1_CFG_KEEP__W 2
+#define SIO_PDR_MD1_CFG_KEEP__M 0xC0
+#define SIO_PDR_MD1_CFG_KEEP__PRE 0x40
+#define SIO_PDR_MD1_CFG_UIO__B 8
+#define SIO_PDR_MD1_CFG_UIO__W 1
+#define SIO_PDR_MD1_CFG_UIO__M 0x100
+#define SIO_PDR_MD1_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_MD2_CFG__A 0x7F002C
+#define SIO_PDR_MD2_CFG__W 9
+#define SIO_PDR_MD2_CFG__M 0x1FF
+#define SIO_PDR_MD2_CFG__PRE 0x50
+#define SIO_PDR_MD2_CFG_MODE__B 0
+#define SIO_PDR_MD2_CFG_MODE__W 3
+#define SIO_PDR_MD2_CFG_MODE__M 0x7
+#define SIO_PDR_MD2_CFG_MODE__PRE 0x0
+#define SIO_PDR_MD2_CFG_DRIVE__B 3
+#define SIO_PDR_MD2_CFG_DRIVE__W 3
+#define SIO_PDR_MD2_CFG_DRIVE__M 0x38
+#define SIO_PDR_MD2_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_MD2_CFG_KEEP__B 6
+#define SIO_PDR_MD2_CFG_KEEP__W 2
+#define SIO_PDR_MD2_CFG_KEEP__M 0xC0
+#define SIO_PDR_MD2_CFG_KEEP__PRE 0x40
+#define SIO_PDR_MD2_CFG_UIO__B 8
+#define SIO_PDR_MD2_CFG_UIO__W 1
+#define SIO_PDR_MD2_CFG_UIO__M 0x100
+#define SIO_PDR_MD2_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_MD3_CFG__A 0x7F002D
+#define SIO_PDR_MD3_CFG__W 9
+#define SIO_PDR_MD3_CFG__M 0x1FF
+#define SIO_PDR_MD3_CFG__PRE 0x50
+#define SIO_PDR_MD3_CFG_MODE__B 0
+#define SIO_PDR_MD3_CFG_MODE__W 3
+#define SIO_PDR_MD3_CFG_MODE__M 0x7
+#define SIO_PDR_MD3_CFG_MODE__PRE 0x0
+#define SIO_PDR_MD3_CFG_DRIVE__B 3
+#define SIO_PDR_MD3_CFG_DRIVE__W 3
+#define SIO_PDR_MD3_CFG_DRIVE__M 0x38
+#define SIO_PDR_MD3_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_MD3_CFG_KEEP__B 6
+#define SIO_PDR_MD3_CFG_KEEP__W 2
+#define SIO_PDR_MD3_CFG_KEEP__M 0xC0
+#define SIO_PDR_MD3_CFG_KEEP__PRE 0x40
+#define SIO_PDR_MD3_CFG_UIO__B 8
+#define SIO_PDR_MD3_CFG_UIO__W 1
+#define SIO_PDR_MD3_CFG_UIO__M 0x100
+#define SIO_PDR_MD3_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_MD4_CFG__A 0x7F002F
+#define SIO_PDR_MD4_CFG__W 9
+#define SIO_PDR_MD4_CFG__M 0x1FF
+#define SIO_PDR_MD4_CFG__PRE 0x50
+#define SIO_PDR_MD4_CFG_MODE__B 0
+#define SIO_PDR_MD4_CFG_MODE__W 3
+#define SIO_PDR_MD4_CFG_MODE__M 0x7
+#define SIO_PDR_MD4_CFG_MODE__PRE 0x0
+#define SIO_PDR_MD4_CFG_DRIVE__B 3
+#define SIO_PDR_MD4_CFG_DRIVE__W 3
+#define SIO_PDR_MD4_CFG_DRIVE__M 0x38
+#define SIO_PDR_MD4_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_MD4_CFG_KEEP__B 6
+#define SIO_PDR_MD4_CFG_KEEP__W 2
+#define SIO_PDR_MD4_CFG_KEEP__M 0xC0
+#define SIO_PDR_MD4_CFG_KEEP__PRE 0x40
+#define SIO_PDR_MD4_CFG_UIO__B 8
+#define SIO_PDR_MD4_CFG_UIO__W 1
+#define SIO_PDR_MD4_CFG_UIO__M 0x100
+#define SIO_PDR_MD4_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_MD5_CFG__A 0x7F0030
+#define SIO_PDR_MD5_CFG__W 9
+#define SIO_PDR_MD5_CFG__M 0x1FF
+#define SIO_PDR_MD5_CFG__PRE 0x50
+#define SIO_PDR_MD5_CFG_MODE__B 0
+#define SIO_PDR_MD5_CFG_MODE__W 3
+#define SIO_PDR_MD5_CFG_MODE__M 0x7
+#define SIO_PDR_MD5_CFG_MODE__PRE 0x0
+#define SIO_PDR_MD5_CFG_DRIVE__B 3
+#define SIO_PDR_MD5_CFG_DRIVE__W 3
+#define SIO_PDR_MD5_CFG_DRIVE__M 0x38
+#define SIO_PDR_MD5_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_MD5_CFG_KEEP__B 6
+#define SIO_PDR_MD5_CFG_KEEP__W 2
+#define SIO_PDR_MD5_CFG_KEEP__M 0xC0
+#define SIO_PDR_MD5_CFG_KEEP__PRE 0x40
+#define SIO_PDR_MD5_CFG_UIO__B 8
+#define SIO_PDR_MD5_CFG_UIO__W 1
+#define SIO_PDR_MD5_CFG_UIO__M 0x100
+#define SIO_PDR_MD5_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_MD6_CFG__A 0x7F0031
+#define SIO_PDR_MD6_CFG__W 9
+#define SIO_PDR_MD6_CFG__M 0x1FF
+#define SIO_PDR_MD6_CFG__PRE 0x50
+#define SIO_PDR_MD6_CFG_MODE__B 0
+#define SIO_PDR_MD6_CFG_MODE__W 3
+#define SIO_PDR_MD6_CFG_MODE__M 0x7
+#define SIO_PDR_MD6_CFG_MODE__PRE 0x0
+#define SIO_PDR_MD6_CFG_DRIVE__B 3
+#define SIO_PDR_MD6_CFG_DRIVE__W 3
+#define SIO_PDR_MD6_CFG_DRIVE__M 0x38
+#define SIO_PDR_MD6_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_MD6_CFG_KEEP__B 6
+#define SIO_PDR_MD6_CFG_KEEP__W 2
+#define SIO_PDR_MD6_CFG_KEEP__M 0xC0
+#define SIO_PDR_MD6_CFG_KEEP__PRE 0x40
+#define SIO_PDR_MD6_CFG_UIO__B 8
+#define SIO_PDR_MD6_CFG_UIO__W 1
+#define SIO_PDR_MD6_CFG_UIO__M 0x100
+#define SIO_PDR_MD6_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_MD7_CFG__A 0x7F0032
+#define SIO_PDR_MD7_CFG__W 9
+#define SIO_PDR_MD7_CFG__M 0x1FF
+#define SIO_PDR_MD7_CFG__PRE 0x50
+#define SIO_PDR_MD7_CFG_MODE__B 0
+#define SIO_PDR_MD7_CFG_MODE__W 3
+#define SIO_PDR_MD7_CFG_MODE__M 0x7
+#define SIO_PDR_MD7_CFG_MODE__PRE 0x0
+#define SIO_PDR_MD7_CFG_DRIVE__B 3
+#define SIO_PDR_MD7_CFG_DRIVE__W 3
+#define SIO_PDR_MD7_CFG_DRIVE__M 0x38
+#define SIO_PDR_MD7_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_MD7_CFG_KEEP__B 6
+#define SIO_PDR_MD7_CFG_KEEP__W 2
+#define SIO_PDR_MD7_CFG_KEEP__M 0xC0
+#define SIO_PDR_MD7_CFG_KEEP__PRE 0x40
+#define SIO_PDR_MD7_CFG_UIO__B 8
+#define SIO_PDR_MD7_CFG_UIO__W 1
+#define SIO_PDR_MD7_CFG_UIO__M 0x100
+#define SIO_PDR_MD7_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_I2C_SCL1_CFG__A 0x7F0033
+#define SIO_PDR_I2C_SCL1_CFG__W 9
+#define SIO_PDR_I2C_SCL1_CFG__M 0x1FF
+#define SIO_PDR_I2C_SCL1_CFG__PRE 0x11
+#define SIO_PDR_I2C_SCL1_CFG_MODE__B 0
+#define SIO_PDR_I2C_SCL1_CFG_MODE__W 3
+#define SIO_PDR_I2C_SCL1_CFG_MODE__M 0x7
+#define SIO_PDR_I2C_SCL1_CFG_MODE__PRE 0x1
+#define SIO_PDR_I2C_SCL1_CFG_DRIVE__B 3
+#define SIO_PDR_I2C_SCL1_CFG_DRIVE__W 3
+#define SIO_PDR_I2C_SCL1_CFG_DRIVE__M 0x38
+#define SIO_PDR_I2C_SCL1_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_I2C_SCL1_CFG_KEEP__B 6
+#define SIO_PDR_I2C_SCL1_CFG_KEEP__W 2
+#define SIO_PDR_I2C_SCL1_CFG_KEEP__M 0xC0
+#define SIO_PDR_I2C_SCL1_CFG_KEEP__PRE 0x0
+#define SIO_PDR_I2C_SCL1_CFG_UIO__B 8
+#define SIO_PDR_I2C_SCL1_CFG_UIO__W 1
+#define SIO_PDR_I2C_SCL1_CFG_UIO__M 0x100
+#define SIO_PDR_I2C_SCL1_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_I2C_SDA1_CFG__A 0x7F0034
+#define SIO_PDR_I2C_SDA1_CFG__W 9
+#define SIO_PDR_I2C_SDA1_CFG__M 0x1FF
+#define SIO_PDR_I2C_SDA1_CFG__PRE 0x11
+#define SIO_PDR_I2C_SDA1_CFG_MODE__B 0
+#define SIO_PDR_I2C_SDA1_CFG_MODE__W 3
+#define SIO_PDR_I2C_SDA1_CFG_MODE__M 0x7
+#define SIO_PDR_I2C_SDA1_CFG_MODE__PRE 0x1
+#define SIO_PDR_I2C_SDA1_CFG_DRIVE__B 3
+#define SIO_PDR_I2C_SDA1_CFG_DRIVE__W 3
+#define SIO_PDR_I2C_SDA1_CFG_DRIVE__M 0x38
+#define SIO_PDR_I2C_SDA1_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_I2C_SDA1_CFG_KEEP__B 6
+#define SIO_PDR_I2C_SDA1_CFG_KEEP__W 2
+#define SIO_PDR_I2C_SDA1_CFG_KEEP__M 0xC0
+#define SIO_PDR_I2C_SDA1_CFG_KEEP__PRE 0x0
+#define SIO_PDR_I2C_SDA1_CFG_UIO__B 8
+#define SIO_PDR_I2C_SDA1_CFG_UIO__W 1
+#define SIO_PDR_I2C_SDA1_CFG_UIO__M 0x100
+#define SIO_PDR_I2C_SDA1_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_VSYNC_CFG__A 0x7F0036
+#define SIO_PDR_VSYNC_CFG__W 9
+#define SIO_PDR_VSYNC_CFG__M 0x1FF
+#define SIO_PDR_VSYNC_CFG__PRE 0x10
+#define SIO_PDR_VSYNC_CFG_MODE__B 0
+#define SIO_PDR_VSYNC_CFG_MODE__W 3
+#define SIO_PDR_VSYNC_CFG_MODE__M 0x7
+#define SIO_PDR_VSYNC_CFG_MODE__PRE 0x0
+#define SIO_PDR_VSYNC_CFG_DRIVE__B 3
+#define SIO_PDR_VSYNC_CFG_DRIVE__W 3
+#define SIO_PDR_VSYNC_CFG_DRIVE__M 0x38
+#define SIO_PDR_VSYNC_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_VSYNC_CFG_KEEP__B 6
+#define SIO_PDR_VSYNC_CFG_KEEP__W 2
+#define SIO_PDR_VSYNC_CFG_KEEP__M 0xC0
+#define SIO_PDR_VSYNC_CFG_KEEP__PRE 0x0
+#define SIO_PDR_VSYNC_CFG_UIO__B 8
+#define SIO_PDR_VSYNC_CFG_UIO__W 1
+#define SIO_PDR_VSYNC_CFG_UIO__M 0x100
+#define SIO_PDR_VSYNC_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_SMA_RX_CFG__A 0x7F0037
+#define SIO_PDR_SMA_RX_CFG__W 9
+#define SIO_PDR_SMA_RX_CFG__M 0x1FF
+#define SIO_PDR_SMA_RX_CFG__PRE 0x10
+#define SIO_PDR_SMA_RX_CFG_MODE__B 0
+#define SIO_PDR_SMA_RX_CFG_MODE__W 3
+#define SIO_PDR_SMA_RX_CFG_MODE__M 0x7
+#define SIO_PDR_SMA_RX_CFG_MODE__PRE 0x0
+#define SIO_PDR_SMA_RX_CFG_DRIVE__B 3
+#define SIO_PDR_SMA_RX_CFG_DRIVE__W 3
+#define SIO_PDR_SMA_RX_CFG_DRIVE__M 0x38
+#define SIO_PDR_SMA_RX_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_SMA_RX_CFG_KEEP__B 6
+#define SIO_PDR_SMA_RX_CFG_KEEP__W 2
+#define SIO_PDR_SMA_RX_CFG_KEEP__M 0xC0
+#define SIO_PDR_SMA_RX_CFG_KEEP__PRE 0x0
+#define SIO_PDR_SMA_RX_CFG_UIO__B 8
+#define SIO_PDR_SMA_RX_CFG_UIO__W 1
+#define SIO_PDR_SMA_RX_CFG_UIO__M 0x100
+#define SIO_PDR_SMA_RX_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_SMA_TX_CFG__A 0x7F0038
+#define SIO_PDR_SMA_TX_CFG__W 9
+#define SIO_PDR_SMA_TX_CFG__M 0x1FF
+#define SIO_PDR_SMA_TX_CFG__PRE 0x90
+#define SIO_PDR_SMA_TX_CFG_MODE__B 0
+#define SIO_PDR_SMA_TX_CFG_MODE__W 3
+#define SIO_PDR_SMA_TX_CFG_MODE__M 0x7
+#define SIO_PDR_SMA_TX_CFG_MODE__PRE 0x0
+#define SIO_PDR_SMA_TX_CFG_DRIVE__B 3
+#define SIO_PDR_SMA_TX_CFG_DRIVE__W 3
+#define SIO_PDR_SMA_TX_CFG_DRIVE__M 0x38
+#define SIO_PDR_SMA_TX_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_SMA_TX_CFG_KEEP__B 6
+#define SIO_PDR_SMA_TX_CFG_KEEP__W 2
+#define SIO_PDR_SMA_TX_CFG_KEEP__M 0xC0
+#define SIO_PDR_SMA_TX_CFG_KEEP__PRE 0x80
+#define SIO_PDR_SMA_TX_CFG_UIO__B 8
+#define SIO_PDR_SMA_TX_CFG_UIO__W 1
+#define SIO_PDR_SMA_TX_CFG_UIO__M 0x100
+#define SIO_PDR_SMA_TX_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_I2C_SDA2_CFG__A 0x7F003F
+#define SIO_PDR_I2C_SDA2_CFG__W 9
+#define SIO_PDR_I2C_SDA2_CFG__M 0x1FF
+#define SIO_PDR_I2C_SDA2_CFG__PRE 0x11
+#define SIO_PDR_I2C_SDA2_CFG_MODE__B 0
+#define SIO_PDR_I2C_SDA2_CFG_MODE__W 3
+#define SIO_PDR_I2C_SDA2_CFG_MODE__M 0x7
+#define SIO_PDR_I2C_SDA2_CFG_MODE__PRE 0x1
+#define SIO_PDR_I2C_SDA2_CFG_DRIVE__B 3
+#define SIO_PDR_I2C_SDA2_CFG_DRIVE__W 3
+#define SIO_PDR_I2C_SDA2_CFG_DRIVE__M 0x38
+#define SIO_PDR_I2C_SDA2_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_I2C_SDA2_CFG_KEEP__B 6
+#define SIO_PDR_I2C_SDA2_CFG_KEEP__W 2
+#define SIO_PDR_I2C_SDA2_CFG_KEEP__M 0xC0
+#define SIO_PDR_I2C_SDA2_CFG_KEEP__PRE 0x0
+#define SIO_PDR_I2C_SDA2_CFG_UIO__B 8
+#define SIO_PDR_I2C_SDA2_CFG_UIO__W 1
+#define SIO_PDR_I2C_SDA2_CFG_UIO__M 0x100
+#define SIO_PDR_I2C_SDA2_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_I2C_SCL2_CFG__A 0x7F0040
+#define SIO_PDR_I2C_SCL2_CFG__W 9
+#define SIO_PDR_I2C_SCL2_CFG__M 0x1FF
+#define SIO_PDR_I2C_SCL2_CFG__PRE 0x11
+#define SIO_PDR_I2C_SCL2_CFG_MODE__B 0
+#define SIO_PDR_I2C_SCL2_CFG_MODE__W 3
+#define SIO_PDR_I2C_SCL2_CFG_MODE__M 0x7
+#define SIO_PDR_I2C_SCL2_CFG_MODE__PRE 0x1
+#define SIO_PDR_I2C_SCL2_CFG_DRIVE__B 3
+#define SIO_PDR_I2C_SCL2_CFG_DRIVE__W 3
+#define SIO_PDR_I2C_SCL2_CFG_DRIVE__M 0x38
+#define SIO_PDR_I2C_SCL2_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_I2C_SCL2_CFG_KEEP__B 6
+#define SIO_PDR_I2C_SCL2_CFG_KEEP__W 2
+#define SIO_PDR_I2C_SCL2_CFG_KEEP__M 0xC0
+#define SIO_PDR_I2C_SCL2_CFG_KEEP__PRE 0x0
+#define SIO_PDR_I2C_SCL2_CFG_UIO__B 8
+#define SIO_PDR_I2C_SCL2_CFG_UIO__W 1
+#define SIO_PDR_I2C_SCL2_CFG_UIO__M 0x100
+#define SIO_PDR_I2C_SCL2_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_I2S_CL_CFG__A 0x7F0041
+#define SIO_PDR_I2S_CL_CFG__W 9
+#define SIO_PDR_I2S_CL_CFG__M 0x1FF
+#define SIO_PDR_I2S_CL_CFG__PRE 0x10
+#define SIO_PDR_I2S_CL_CFG_MODE__B 0
+#define SIO_PDR_I2S_CL_CFG_MODE__W 3
+#define SIO_PDR_I2S_CL_CFG_MODE__M 0x7
+#define SIO_PDR_I2S_CL_CFG_MODE__PRE 0x0
+#define SIO_PDR_I2S_CL_CFG_DRIVE__B 3
+#define SIO_PDR_I2S_CL_CFG_DRIVE__W 3
+#define SIO_PDR_I2S_CL_CFG_DRIVE__M 0x38
+#define SIO_PDR_I2S_CL_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_I2S_CL_CFG_KEEP__B 6
+#define SIO_PDR_I2S_CL_CFG_KEEP__W 2
+#define SIO_PDR_I2S_CL_CFG_KEEP__M 0xC0
+#define SIO_PDR_I2S_CL_CFG_KEEP__PRE 0x0
+#define SIO_PDR_I2S_CL_CFG_UIO__B 8
+#define SIO_PDR_I2S_CL_CFG_UIO__W 1
+#define SIO_PDR_I2S_CL_CFG_UIO__M 0x100
+#define SIO_PDR_I2S_CL_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_I2S_DA_CFG__A 0x7F0042
+#define SIO_PDR_I2S_DA_CFG__W 9
+#define SIO_PDR_I2S_DA_CFG__M 0x1FF
+#define SIO_PDR_I2S_DA_CFG__PRE 0x10
+#define SIO_PDR_I2S_DA_CFG_MODE__B 0
+#define SIO_PDR_I2S_DA_CFG_MODE__W 3
+#define SIO_PDR_I2S_DA_CFG_MODE__M 0x7
+#define SIO_PDR_I2S_DA_CFG_MODE__PRE 0x0
+#define SIO_PDR_I2S_DA_CFG_DRIVE__B 3
+#define SIO_PDR_I2S_DA_CFG_DRIVE__W 3
+#define SIO_PDR_I2S_DA_CFG_DRIVE__M 0x38
+#define SIO_PDR_I2S_DA_CFG_DRIVE__PRE 0x10
+#define SIO_PDR_I2S_DA_CFG_KEEP__B 6
+#define SIO_PDR_I2S_DA_CFG_KEEP__W 2
+#define SIO_PDR_I2S_DA_CFG_KEEP__M 0xC0
+#define SIO_PDR_I2S_DA_CFG_KEEP__PRE 0x0
+#define SIO_PDR_I2S_DA_CFG_UIO__B 8
+#define SIO_PDR_I2S_DA_CFG_UIO__W 1
+#define SIO_PDR_I2S_DA_CFG_UIO__M 0x100
+#define SIO_PDR_I2S_DA_CFG_UIO__PRE 0x0
+
+#define SIO_PDR_GPIO_GPIO_FNC__A 0x7F0050
+#define SIO_PDR_GPIO_GPIO_FNC__W 2
+#define SIO_PDR_GPIO_GPIO_FNC__M 0x3
+#define SIO_PDR_GPIO_GPIO_FNC__PRE 0x0
+#define SIO_PDR_GPIO_GPIO_FNC_SEL__B 0
+#define SIO_PDR_GPIO_GPIO_FNC_SEL__W 2
+#define SIO_PDR_GPIO_GPIO_FNC_SEL__M 0x3
+#define SIO_PDR_GPIO_GPIO_FNC_SEL__PRE 0x0
+
+#define SIO_PDR_IRQN_GPIO_FNC__A 0x7F0051
+#define SIO_PDR_IRQN_GPIO_FNC__W 2
+#define SIO_PDR_IRQN_GPIO_FNC__M 0x3
+#define SIO_PDR_IRQN_GPIO_FNC__PRE 0x0
+#define SIO_PDR_IRQN_GPIO_FNC_SEL__B 0
+#define SIO_PDR_IRQN_GPIO_FNC_SEL__W 2
+#define SIO_PDR_IRQN_GPIO_FNC_SEL__M 0x3
+#define SIO_PDR_IRQN_GPIO_FNC_SEL__PRE 0x0
+
+#define SIO_PDR_MSTRT_GPIO_FNC__A 0x7F0052
+#define SIO_PDR_MSTRT_GPIO_FNC__W 2
+#define SIO_PDR_MSTRT_GPIO_FNC__M 0x3
+#define SIO_PDR_MSTRT_GPIO_FNC__PRE 0x0
+#define SIO_PDR_MSTRT_GPIO_FNC_SEL__B 0
+#define SIO_PDR_MSTRT_GPIO_FNC_SEL__W 2
+#define SIO_PDR_MSTRT_GPIO_FNC_SEL__M 0x3
+#define SIO_PDR_MSTRT_GPIO_FNC_SEL__PRE 0x0
+
+#define SIO_PDR_MERR_GPIO_FNC__A 0x7F0053
+#define SIO_PDR_MERR_GPIO_FNC__W 2
+#define SIO_PDR_MERR_GPIO_FNC__M 0x3
+#define SIO_PDR_MERR_GPIO_FNC__PRE 0x0
+#define SIO_PDR_MERR_GPIO_FNC_SEL__B 0
+#define SIO_PDR_MERR_GPIO_FNC_SEL__W 2
+#define SIO_PDR_MERR_GPIO_FNC_SEL__M 0x3
+#define SIO_PDR_MERR_GPIO_FNC_SEL__PRE 0x0
+
+#define SIO_PDR_MCLK_GPIO_FNC__A 0x7F0054
+#define SIO_PDR_MCLK_GPIO_FNC__W 2
+#define SIO_PDR_MCLK_GPIO_FNC__M 0x3
+#define SIO_PDR_MCLK_GPIO_FNC__PRE 0x0
+#define SIO_PDR_MCLK_GPIO_FNC_SEL__B 0
+#define SIO_PDR_MCLK_GPIO_FNC_SEL__W 2
+#define SIO_PDR_MCLK_GPIO_FNC_SEL__M 0x3
+#define SIO_PDR_MCLK_GPIO_FNC_SEL__PRE 0x0
+
+#define SIO_PDR_MVAL_GPIO_FNC__A 0x7F0055
+#define SIO_PDR_MVAL_GPIO_FNC__W 2
+#define SIO_PDR_MVAL_GPIO_FNC__M 0x3
+#define SIO_PDR_MVAL_GPIO_FNC__PRE 0x0
+#define SIO_PDR_MVAL_GPIO_FNC_SEL__B 0
+#define SIO_PDR_MVAL_GPIO_FNC_SEL__W 2
+#define SIO_PDR_MVAL_GPIO_FNC_SEL__M 0x3
+#define SIO_PDR_MVAL_GPIO_FNC_SEL__PRE 0x0
+
+#define SIO_PDR_MD0_GPIO_FNC__A 0x7F0056
+#define SIO_PDR_MD0_GPIO_FNC__W 2
+#define SIO_PDR_MD0_GPIO_FNC__M 0x3
+#define SIO_PDR_MD0_GPIO_FNC__PRE 0x0
+#define SIO_PDR_MD0_GPIO_FNC_SEL__B 0
+#define SIO_PDR_MD0_GPIO_FNC_SEL__W 2
+#define SIO_PDR_MD0_GPIO_FNC_SEL__M 0x3
+#define SIO_PDR_MD0_GPIO_FNC_SEL__PRE 0x0
+
+#define SIO_PDR_MD1_GPIO_FNC__A 0x7F0057
+#define SIO_PDR_MD1_GPIO_FNC__W 2
+#define SIO_PDR_MD1_GPIO_FNC__M 0x3
+#define SIO_PDR_MD1_GPIO_FNC__PRE 0x0
+#define SIO_PDR_MD1_GPIO_FNC_SEL__B 0
+#define SIO_PDR_MD1_GPIO_FNC_SEL__W 2
+#define SIO_PDR_MD1_GPIO_FNC_SEL__M 0x3
+#define SIO_PDR_MD1_GPIO_FNC_SEL__PRE 0x0
+
+#define SIO_PDR_MD2_GPIO_FNC__A 0x7F0058
+#define SIO_PDR_MD2_GPIO_FNC__W 2
+#define SIO_PDR_MD2_GPIO_FNC__M 0x3
+#define SIO_PDR_MD2_GPIO_FNC__PRE 0x0
+#define SIO_PDR_MD2_GPIO_FNC_SEL__B 0
+#define SIO_PDR_MD2_GPIO_FNC_SEL__W 2
+#define SIO_PDR_MD2_GPIO_FNC_SEL__M 0x3
+#define SIO_PDR_MD2_GPIO_FNC_SEL__PRE 0x0
+
+#define SIO_PDR_MD3_GPIO_FNC__A 0x7F0059
+#define SIO_PDR_MD3_GPIO_FNC__W 2
+#define SIO_PDR_MD3_GPIO_FNC__M 0x3
+#define SIO_PDR_MD3_GPIO_FNC__PRE 0x0
+#define SIO_PDR_MD3_GPIO_FNC_SEL__B 0
+#define SIO_PDR_MD3_GPIO_FNC_SEL__W 2
+#define SIO_PDR_MD3_GPIO_FNC_SEL__M 0x3
+#define SIO_PDR_MD3_GPIO_FNC_SEL__PRE 0x0
+
+#define SIO_PDR_MD4_GPIO_FNC__A 0x7F005A
+#define SIO_PDR_MD4_GPIO_FNC__W 2
+#define SIO_PDR_MD4_GPIO_FNC__M 0x3
+#define SIO_PDR_MD4_GPIO_FNC__PRE 0x0
+#define SIO_PDR_MD4_GPIO_FNC_SEL__B 0
+#define SIO_PDR_MD4_GPIO_FNC_SEL__W 2
+#define SIO_PDR_MD4_GPIO_FNC_SEL__M 0x3
+#define SIO_PDR_MD4_GPIO_FNC_SEL__PRE 0x0
+
+#define SIO_PDR_MD5_GPIO_FNC__A 0x7F005B
+#define SIO_PDR_MD5_GPIO_FNC__W 2
+#define SIO_PDR_MD5_GPIO_FNC__M 0x3
+#define SIO_PDR_MD5_GPIO_FNC__PRE 0x0
+#define SIO_PDR_MD5_GPIO_FNC_SEL__B 0
+#define SIO_PDR_MD5_GPIO_FNC_SEL__W 2
+#define SIO_PDR_MD5_GPIO_FNC_SEL__M 0x3
+#define SIO_PDR_MD5_GPIO_FNC_SEL__PRE 0x0
+
+#define SIO_PDR_MD6_GPIO_FNC__A 0x7F005C
+#define SIO_PDR_MD6_GPIO_FNC__W 2
+#define SIO_PDR_MD6_GPIO_FNC__M 0x3
+#define SIO_PDR_MD6_GPIO_FNC__PRE 0x0
+#define SIO_PDR_MD6_GPIO_FNC_SEL__B 0
+#define SIO_PDR_MD6_GPIO_FNC_SEL__W 2
+#define SIO_PDR_MD6_GPIO_FNC_SEL__M 0x3
+#define SIO_PDR_MD6_GPIO_FNC_SEL__PRE 0x0
+
+#define SIO_PDR_MD7_GPIO_FNC__A 0x7F005D
+#define SIO_PDR_MD7_GPIO_FNC__W 2
+#define SIO_PDR_MD7_GPIO_FNC__M 0x3
+#define SIO_PDR_MD7_GPIO_FNC__PRE 0x0
+#define SIO_PDR_MD7_GPIO_FNC_SEL__B 0
+#define SIO_PDR_MD7_GPIO_FNC_SEL__W 2
+#define SIO_PDR_MD7_GPIO_FNC_SEL__M 0x3
+#define SIO_PDR_MD7_GPIO_FNC_SEL__PRE 0x0
+
+#define SIO_PDR_SMA_RX_GPIO_FNC__A 0x7F005E
+#define SIO_PDR_SMA_RX_GPIO_FNC__W 2
+#define SIO_PDR_SMA_RX_GPIO_FNC__M 0x3
+#define SIO_PDR_SMA_RX_GPIO_FNC__PRE 0x0
+#define SIO_PDR_SMA_RX_GPIO_FNC_SEL__B 0
+#define SIO_PDR_SMA_RX_GPIO_FNC_SEL__W 2
+#define SIO_PDR_SMA_RX_GPIO_FNC_SEL__M 0x3
+#define SIO_PDR_SMA_RX_GPIO_FNC_SEL__PRE 0x0
+
+#define SIO_PDR_SMA_TX_GPIO_FNC__A 0x7F005F
+#define SIO_PDR_SMA_TX_GPIO_FNC__W 2
+#define SIO_PDR_SMA_TX_GPIO_FNC__M 0x3
+#define SIO_PDR_SMA_TX_GPIO_FNC__PRE 0x0
+#define SIO_PDR_SMA_TX_GPIO_FNC_SEL__B 0
+#define SIO_PDR_SMA_TX_GPIO_FNC_SEL__W 2
+#define SIO_PDR_SMA_TX_GPIO_FNC_SEL__M 0x3
+#define SIO_PDR_SMA_TX_GPIO_FNC_SEL__PRE 0x0
+
+#define VSB_COMM_EXEC__A 0x1C00000
+#define VSB_COMM_EXEC__W 2
+#define VSB_COMM_EXEC__M 0x3
+#define VSB_COMM_EXEC__PRE 0x0
+#define VSB_COMM_EXEC_STOP 0x0
+#define VSB_COMM_EXEC_ACTIVE 0x1
+#define VSB_COMM_EXEC_HOLD 0x2
+
+#define VSB_COMM_MB__A 0x1C00002
+#define VSB_COMM_MB__W 16
+#define VSB_COMM_MB__M 0xFFFF
+#define VSB_COMM_MB__PRE 0x0
+#define VSB_COMM_INT_REQ__A 0x1C00003
+#define VSB_COMM_INT_REQ__W 1
+#define VSB_COMM_INT_REQ__M 0x1
+#define VSB_COMM_INT_REQ__PRE 0x0
+
+#define VSB_COMM_INT_REQ_TOP_INT_REQ__B 0
+#define VSB_COMM_INT_REQ_TOP_INT_REQ__W 1
+#define VSB_COMM_INT_REQ_TOP_INT_REQ__M 0x1
+#define VSB_COMM_INT_REQ_TOP_INT_REQ__PRE 0x0
+
+#define VSB_COMM_INT_STA__A 0x1C00005
+#define VSB_COMM_INT_STA__W 16
+#define VSB_COMM_INT_STA__M 0xFFFF
+#define VSB_COMM_INT_STA__PRE 0x0
+
+#define VSB_COMM_INT_MSK__A 0x1C00006
+#define VSB_COMM_INT_MSK__W 16
+#define VSB_COMM_INT_MSK__M 0xFFFF
+#define VSB_COMM_INT_MSK__PRE 0x0
+
+#define VSB_COMM_INT_STM__A 0x1C00007
+#define VSB_COMM_INT_STM__W 16
+#define VSB_COMM_INT_STM__M 0xFFFF
+#define VSB_COMM_INT_STM__PRE 0x0
+
+#define VSB_TOP_COMM_EXEC__A 0x1C10000
+#define VSB_TOP_COMM_EXEC__W 2
+#define VSB_TOP_COMM_EXEC__M 0x3
+#define VSB_TOP_COMM_EXEC__PRE 0x0
+#define VSB_TOP_COMM_EXEC_STOP 0x0
+#define VSB_TOP_COMM_EXEC_ACTIVE 0x1
+#define VSB_TOP_COMM_EXEC_HOLD 0x2
+
+#define VSB_TOP_COMM_MB__A 0x1C10002
+#define VSB_TOP_COMM_MB__W 10
+#define VSB_TOP_COMM_MB__M 0x3FF
+#define VSB_TOP_COMM_MB__PRE 0x0
+
+#define VSB_TOP_COMM_MB_CTL__B 0
+#define VSB_TOP_COMM_MB_CTL__W 1
+#define VSB_TOP_COMM_MB_CTL__M 0x1
+#define VSB_TOP_COMM_MB_CTL__PRE 0x0
+#define VSB_TOP_COMM_MB_CTL_CTL_OFF 0x0
+#define VSB_TOP_COMM_MB_CTL_CTL_ON 0x1
+
+#define VSB_TOP_COMM_MB_OBS__B 1
+#define VSB_TOP_COMM_MB_OBS__W 1
+#define VSB_TOP_COMM_MB_OBS__M 0x2
+#define VSB_TOP_COMM_MB_OBS__PRE 0x0
+#define VSB_TOP_COMM_MB_OBS_OBS_OFF 0x0
+#define VSB_TOP_COMM_MB_OBS_OBS_ON 0x2
+
+#define VSB_TOP_COMM_MB_MUX_CTL__B 2
+#define VSB_TOP_COMM_MB_MUX_CTL__W 4
+#define VSB_TOP_COMM_MB_MUX_CTL__M 0x3C
+#define VSB_TOP_COMM_MB_MUX_CTL__PRE 0x0
+
+#define VSB_TOP_COMM_MB_MUX_OBS__B 6
+#define VSB_TOP_COMM_MB_MUX_OBS__W 4
+#define VSB_TOP_COMM_MB_MUX_OBS__M 0x3C0
+#define VSB_TOP_COMM_MB_MUX_OBS__PRE 0x0
+#define VSB_TOP_COMM_MB_MUX_OBS_VSB_FEC 0x0
+#define VSB_TOP_COMM_MB_MUX_OBS_VSB_IQM 0x40
+#define VSB_TOP_COMM_MB_MUX_OBS_VSB_IQM_AMPLITUDE 0x80
+#define VSB_TOP_COMM_MB_MUX_OBS_VSB_TCMEQ_1 0xC0
+#define VSB_TOP_COMM_MB_MUX_OBS_VSB_TCMEQ_2 0x100
+#define VSB_TOP_COMM_MB_MUX_OBS_VSB_FFE_1 0x140
+#define VSB_TOP_COMM_MB_MUX_OBS_VSB_FFE_2 0x180
+#define VSB_TOP_COMM_MB_MUX_OBS_VSB_DFE_1 0x1C0
+#define VSB_TOP_COMM_MB_MUX_OBS_VSB_DFE_2 0x200
+
+#define VSB_TOP_COMM_INT_REQ__A 0x1C10003
+#define VSB_TOP_COMM_INT_REQ__W 1
+#define VSB_TOP_COMM_INT_REQ__M 0x1
+#define VSB_TOP_COMM_INT_REQ__PRE 0x0
+#define VSB_TOP_COMM_INT_STA__A 0x1C10005
+#define VSB_TOP_COMM_INT_STA__W 6
+#define VSB_TOP_COMM_INT_STA__M 0x3F
+#define VSB_TOP_COMM_INT_STA__PRE 0x0
+
+#define VSB_TOP_COMM_INT_STA_FIELD_INT_STA__B 0
+#define VSB_TOP_COMM_INT_STA_FIELD_INT_STA__W 1
+#define VSB_TOP_COMM_INT_STA_FIELD_INT_STA__M 0x1
+#define VSB_TOP_COMM_INT_STA_FIELD_INT_STA__PRE 0x0
+
+#define VSB_TOP_COMM_INT_STA_LOCK_STA__B 1
+#define VSB_TOP_COMM_INT_STA_LOCK_STA__W 1
+#define VSB_TOP_COMM_INT_STA_LOCK_STA__M 0x2
+#define VSB_TOP_COMM_INT_STA_LOCK_STA__PRE 0x0
+
+#define VSB_TOP_COMM_INT_STA_UNLOCK_STA__B 2
+#define VSB_TOP_COMM_INT_STA_UNLOCK_STA__W 1
+#define VSB_TOP_COMM_INT_STA_UNLOCK_STA__M 0x4
+#define VSB_TOP_COMM_INT_STA_UNLOCK_STA__PRE 0x0
+
+#define VSB_TOP_COMM_INT_STA_TAPREADER_STA__B 3
+#define VSB_TOP_COMM_INT_STA_TAPREADER_STA__W 1
+#define VSB_TOP_COMM_INT_STA_TAPREADER_STA__M 0x8
+#define VSB_TOP_COMM_INT_STA_TAPREADER_STA__PRE 0x0
+
+#define VSB_TOP_COMM_INT_STA_SEGSYNCINTR_STA__B 4
+#define VSB_TOP_COMM_INT_STA_SEGSYNCINTR_STA__W 1
+#define VSB_TOP_COMM_INT_STA_SEGSYNCINTR_STA__M 0x10
+#define VSB_TOP_COMM_INT_STA_SEGSYNCINTR_STA__PRE 0x0
+
+#define VSB_TOP_COMM_INT_STA_MERSER_STA__B 5
+#define VSB_TOP_COMM_INT_STA_MERSER_STA__W 1
+#define VSB_TOP_COMM_INT_STA_MERSER_STA__M 0x20
+#define VSB_TOP_COMM_INT_STA_MERSER_STA__PRE 0x0
+
+#define VSB_TOP_COMM_INT_MSK__A 0x1C10006
+#define VSB_TOP_COMM_INT_MSK__W 6
+#define VSB_TOP_COMM_INT_MSK__M 0x3F
+#define VSB_TOP_COMM_INT_MSK__PRE 0x0
+
+#define VSB_TOP_COMM_INT_MSK_FIELD_INT_MSK__B 0
+#define VSB_TOP_COMM_INT_MSK_FIELD_INT_MSK__W 1
+#define VSB_TOP_COMM_INT_MSK_FIELD_INT_MSK__M 0x1
+#define VSB_TOP_COMM_INT_MSK_FIELD_INT_MSK__PRE 0x0
+
+#define VSB_TOP_COMM_INT_MSK_LOCK_MSK__B 1
+#define VSB_TOP_COMM_INT_MSK_LOCK_MSK__W 1
+#define VSB_TOP_COMM_INT_MSK_LOCK_MSK__M 0x2
+#define VSB_TOP_COMM_INT_MSK_LOCK_MSK__PRE 0x0
+
+#define VSB_TOP_COMM_INT_MSK_UNLOCK_MSK__B 2
+#define VSB_TOP_COMM_INT_MSK_UNLOCK_MSK__W 1
+#define VSB_TOP_COMM_INT_MSK_UNLOCK_MSK__M 0x4
+#define VSB_TOP_COMM_INT_MSK_UNLOCK_MSK__PRE 0x0
+
+#define VSB_TOP_COMM_INT_MSK_TAPREADER_MSK__B 3
+#define VSB_TOP_COMM_INT_MSK_TAPREADER_MSK__W 1
+#define VSB_TOP_COMM_INT_MSK_TAPREADER_MSK__M 0x8
+#define VSB_TOP_COMM_INT_MSK_TAPREADER_MSK__PRE 0x0
+
+#define VSB_TOP_COMM_INT_MSK_SEGSYNCINTR_MSK__B 4
+#define VSB_TOP_COMM_INT_MSK_SEGSYNCINTR_MSK__W 1
+#define VSB_TOP_COMM_INT_MSK_SEGSYNCINTR_MSK__M 0x10
+#define VSB_TOP_COMM_INT_MSK_SEGSYNCINTR_MSK__PRE 0x0
+
+#define VSB_TOP_COMM_INT_MSK_MERSER_MSK__B 5
+#define VSB_TOP_COMM_INT_MSK_MERSER_MSK__W 1
+#define VSB_TOP_COMM_INT_MSK_MERSER_MSK__M 0x20
+#define VSB_TOP_COMM_INT_MSK_MERSER_MSK__PRE 0x0
+
+#define VSB_TOP_COMM_INT_STM__A 0x1C10007
+#define VSB_TOP_COMM_INT_STM__W 6
+#define VSB_TOP_COMM_INT_STM__M 0x3F
+#define VSB_TOP_COMM_INT_STM__PRE 0x0
+
+#define VSB_TOP_COMM_INT_STM_FIELD_INT_STM__B 0
+#define VSB_TOP_COMM_INT_STM_FIELD_INT_STM__W 1
+#define VSB_TOP_COMM_INT_STM_FIELD_INT_STM__M 0x1
+#define VSB_TOP_COMM_INT_STM_FIELD_INT_STM__PRE 0x0
+
+#define VSB_TOP_COMM_INT_STM_LOCK_STM__B 1
+#define VSB_TOP_COMM_INT_STM_LOCK_STM__W 1
+#define VSB_TOP_COMM_INT_STM_LOCK_STM__M 0x2
+#define VSB_TOP_COMM_INT_STM_LOCK_STM__PRE 0x0
+
+#define VSB_TOP_COMM_INT_STM_UNLOCK_STM__B 2
+#define VSB_TOP_COMM_INT_STM_UNLOCK_STM__W 1
+#define VSB_TOP_COMM_INT_STM_UNLOCK_STM__M 0x4
+#define VSB_TOP_COMM_INT_STM_UNLOCK_STM__PRE 0x0
+
+#define VSB_TOP_COMM_INT_STM_TAPREADER_STM__B 3
+#define VSB_TOP_COMM_INT_STM_TAPREADER_STM__W 1
+#define VSB_TOP_COMM_INT_STM_TAPREADER_STM__M 0x8
+#define VSB_TOP_COMM_INT_STM_TAPREADER_STM__PRE 0x0
+
+#define VSB_TOP_COMM_INT_STM_SEGSYNCINTR_STM__B 4
+#define VSB_TOP_COMM_INT_STM_SEGSYNCINTR_STM__W 1
+#define VSB_TOP_COMM_INT_STM_SEGSYNCINTR_STM__M 0x10
+#define VSB_TOP_COMM_INT_STM_SEGSYNCINTR_STM__PRE 0x0
+
+#define VSB_TOP_COMM_INT_STM_MERSER_STM__B 5
+#define VSB_TOP_COMM_INT_STM_MERSER_STM__W 1
+#define VSB_TOP_COMM_INT_STM_MERSER_STM__M 0x20
+#define VSB_TOP_COMM_INT_STM_MERSER_STM__PRE 0x0
+
+#define VSB_TOP_CKGN1ACQ__A 0x1C10010
+#define VSB_TOP_CKGN1ACQ__W 8
+#define VSB_TOP_CKGN1ACQ__M 0xFF
+#define VSB_TOP_CKGN1ACQ__PRE 0x4
+
+#define VSB_TOP_CKGN1TRK__A 0x1C10011
+#define VSB_TOP_CKGN1TRK__W 8
+#define VSB_TOP_CKGN1TRK__M 0xFF
+#define VSB_TOP_CKGN1TRK__PRE 0x0
+
+#define VSB_TOP_CKGN2ACQ__A 0x1C10012
+#define VSB_TOP_CKGN2ACQ__W 8
+#define VSB_TOP_CKGN2ACQ__M 0xFF
+#define VSB_TOP_CKGN2ACQ__PRE 0x2
+
+#define VSB_TOP_CKGN2TRK__A 0x1C10013
+#define VSB_TOP_CKGN2TRK__W 8
+#define VSB_TOP_CKGN2TRK__M 0xFF
+#define VSB_TOP_CKGN2TRK__PRE 0x1
+
+#define VSB_TOP_CKGN3__A 0x1C10014
+#define VSB_TOP_CKGN3__W 8
+#define VSB_TOP_CKGN3__M 0xFF
+#define VSB_TOP_CKGN3__PRE 0x5
+
+#define VSB_TOP_CYGN1ACQ__A 0x1C10015
+#define VSB_TOP_CYGN1ACQ__W 8
+#define VSB_TOP_CYGN1ACQ__M 0xFF
+#define VSB_TOP_CYGN1ACQ__PRE 0x3
+
+#define VSB_TOP_CYGN1TRK__A 0x1C10016
+#define VSB_TOP_CYGN1TRK__W 8
+#define VSB_TOP_CYGN1TRK__M 0xFF
+#define VSB_TOP_CYGN1TRK__PRE 0x0
+
+#define VSB_TOP_CYGN2ACQ__A 0x1C10017
+#define VSB_TOP_CYGN2ACQ__W 8
+#define VSB_TOP_CYGN2ACQ__M 0xFF
+#define VSB_TOP_CYGN2ACQ__PRE 0x3
+
+#define VSB_TOP_CYGN2TRK__A 0x1C10018
+#define VSB_TOP_CYGN2TRK__W 8
+#define VSB_TOP_CYGN2TRK__M 0xFF
+#define VSB_TOP_CYGN2TRK__PRE 0x2
+
+#define VSB_TOP_CYGN3__A 0x1C10019
+#define VSB_TOP_CYGN3__W 8
+#define VSB_TOP_CYGN3__M 0xFF
+#define VSB_TOP_CYGN3__PRE 0x6
+#define VSB_TOP_SYNCCTRLWORD__A 0x1C1001A
+#define VSB_TOP_SYNCCTRLWORD__W 5
+#define VSB_TOP_SYNCCTRLWORD__M 0x1F
+#define VSB_TOP_SYNCCTRLWORD__PRE 0x0
+
+#define VSB_TOP_SYNCCTRLWORD_PRST__B 0
+#define VSB_TOP_SYNCCTRLWORD_PRST__W 1
+#define VSB_TOP_SYNCCTRLWORD_PRST__M 0x1
+#define VSB_TOP_SYNCCTRLWORD_PRST__PRE 0x0
+
+#define VSB_TOP_SYNCCTRLWORD_DCFREEZ__B 1
+#define VSB_TOP_SYNCCTRLWORD_DCFREEZ__W 1
+#define VSB_TOP_SYNCCTRLWORD_DCFREEZ__M 0x2
+#define VSB_TOP_SYNCCTRLWORD_DCFREEZ__PRE 0x0
+
+#define VSB_TOP_SYNCCTRLWORD_INVCNST__B 2
+#define VSB_TOP_SYNCCTRLWORD_INVCNST__W 1
+#define VSB_TOP_SYNCCTRLWORD_INVCNST__M 0x4
+#define VSB_TOP_SYNCCTRLWORD_INVCNST__PRE 0x0
+
+#define VSB_TOP_SYNCCTRLWORD_CPUAGCRST__B 3
+#define VSB_TOP_SYNCCTRLWORD_CPUAGCRST__W 1
+#define VSB_TOP_SYNCCTRLWORD_CPUAGCRST__M 0x8
+#define VSB_TOP_SYNCCTRLWORD_CPUAGCRST__PRE 0x0
+
+#define VSB_TOP_SYNCCTRLWORD_AGCIGNOREFS__B 4
+#define VSB_TOP_SYNCCTRLWORD_AGCIGNOREFS__W 1
+#define VSB_TOP_SYNCCTRLWORD_AGCIGNOREFS__M 0x10
+#define VSB_TOP_SYNCCTRLWORD_AGCIGNOREFS__PRE 0x0
+
+#define VSB_TOP_MAINSMUP__A 0x1C1001B
+#define VSB_TOP_MAINSMUP__W 8
+#define VSB_TOP_MAINSMUP__M 0xFF
+#define VSB_TOP_MAINSMUP__PRE 0xFF
+
+#define VSB_TOP_EQSMUP__A 0x1C1001C
+#define VSB_TOP_EQSMUP__W 8
+#define VSB_TOP_EQSMUP__M 0xFF
+#define VSB_TOP_EQSMUP__PRE 0xFF
+#define VSB_TOP_SYSMUXCTRL__A 0x1C1001D
+#define VSB_TOP_SYSMUXCTRL__W 13
+#define VSB_TOP_SYSMUXCTRL__M 0x1FFF
+#define VSB_TOP_SYSMUXCTRL__PRE 0x0
+
+#define VSB_TOP_SYSMUXCTRL_CYLK_STATIC__B 0
+#define VSB_TOP_SYSMUXCTRL_CYLK_STATIC__W 1
+#define VSB_TOP_SYSMUXCTRL_CYLK_STATIC__M 0x1
+#define VSB_TOP_SYSMUXCTRL_CYLK_STATIC__PRE 0x0
+
+#define VSB_TOP_SYSMUXCTRL_CYLK_SEL_STATIC__B 1
+#define VSB_TOP_SYSMUXCTRL_CYLK_SEL_STATIC__W 1
+#define VSB_TOP_SYSMUXCTRL_CYLK_SEL_STATIC__M 0x2
+#define VSB_TOP_SYSMUXCTRL_CYLK_SEL_STATIC__PRE 0x0
+
+#define VSB_TOP_SYSMUXCTRL_CTCALDONE_STATIC__B 2
+#define VSB_TOP_SYSMUXCTRL_CTCALDONE_STATIC__W 1
+#define VSB_TOP_SYSMUXCTRL_CTCALDONE_STATIC__M 0x4
+#define VSB_TOP_SYSMUXCTRL_CTCALDONE_STATIC__PRE 0x0
+
+#define VSB_TOP_SYSMUXCTRL_CTCALDONE_SEL_STATIC__B 3
+#define VSB_TOP_SYSMUXCTRL_CTCALDONE_SEL_STATIC__W 1
+#define VSB_TOP_SYSMUXCTRL_CTCALDONE_SEL_STATIC__M 0x8
+#define VSB_TOP_SYSMUXCTRL_CTCALDONE_SEL_STATIC__PRE 0x0
+
+#define VSB_TOP_SYSMUXCTRL_FRAMELOCK_STATIC__B 4
+#define VSB_TOP_SYSMUXCTRL_FRAMELOCK_STATIC__W 1
+#define VSB_TOP_SYSMUXCTRL_FRAMELOCK_STATIC__M 0x10
+#define VSB_TOP_SYSMUXCTRL_FRAMELOCK_STATIC__PRE 0x0
+
+#define VSB_TOP_SYSMUXCTRL_FRAMELOCK_SEL_STATIC__B 5
+#define VSB_TOP_SYSMUXCTRL_FRAMELOCK_SEL_STATIC__W 1
+#define VSB_TOP_SYSMUXCTRL_FRAMELOCK_SEL_STATIC__M 0x20
+#define VSB_TOP_SYSMUXCTRL_FRAMELOCK_SEL_STATIC__PRE 0x0
+
+#define VSB_TOP_SYSMUXCTRL_FRAMESYNC_STATIC__B 6
+#define VSB_TOP_SYSMUXCTRL_FRAMESYNC_STATIC__W 1
+#define VSB_TOP_SYSMUXCTRL_FRAMESYNC_STATIC__M 0x40
+#define VSB_TOP_SYSMUXCTRL_FRAMESYNC_STATIC__PRE 0x0
+
+#define VSB_TOP_SYSMUXCTRL_FRAMESYNC_SEL_STATIC__B 7
+#define VSB_TOP_SYSMUXCTRL_FRAMESYNC_SEL_STATIC__W 1
+#define VSB_TOP_SYSMUXCTRL_FRAMESYNC_SEL_STATIC__M 0x80
+#define VSB_TOP_SYSMUXCTRL_FRAMESYNC_SEL_STATIC__PRE 0x0
+
+#define VSB_TOP_SYSMUXCTRL_SNROVTH_STATIC__B 8
+#define VSB_TOP_SYSMUXCTRL_SNROVTH_STATIC__W 4
+#define VSB_TOP_SYSMUXCTRL_SNROVTH_STATIC__M 0xF00
+#define VSB_TOP_SYSMUXCTRL_SNROVTH_STATIC__PRE 0x0
+
+#define VSB_TOP_SYSMUXCTRL_SNROVTH_SEL_STATIC__B 12
+#define VSB_TOP_SYSMUXCTRL_SNROVTH_SEL_STATIC__W 1
+#define VSB_TOP_SYSMUXCTRL_SNROVTH_SEL_STATIC__M 0x1000
+#define VSB_TOP_SYSMUXCTRL_SNROVTH_SEL_STATIC__PRE 0x0
+
+#define VSB_TOP_SNRTH_RCA1__A 0x1C1001E
+#define VSB_TOP_SNRTH_RCA1__W 8
+#define VSB_TOP_SNRTH_RCA1__M 0xFF
+#define VSB_TOP_SNRTH_RCA1__PRE 0x53
+
+#define VSB_TOP_SNRTH_RCA1_DN__B 0
+#define VSB_TOP_SNRTH_RCA1_DN__W 4
+#define VSB_TOP_SNRTH_RCA1_DN__M 0xF
+#define VSB_TOP_SNRTH_RCA1_DN__PRE 0x3
+
+#define VSB_TOP_SNRTH_RCA1_UP__B 4
+#define VSB_TOP_SNRTH_RCA1_UP__W 4
+#define VSB_TOP_SNRTH_RCA1_UP__M 0xF0
+#define VSB_TOP_SNRTH_RCA1_UP__PRE 0x50
+
+#define VSB_TOP_SNRTH_RCA2__A 0x1C1001F
+#define VSB_TOP_SNRTH_RCA2__W 8
+#define VSB_TOP_SNRTH_RCA2__M 0xFF
+#define VSB_TOP_SNRTH_RCA2__PRE 0x75
+
+#define VSB_TOP_SNRTH_RCA2_DN__B 0
+#define VSB_TOP_SNRTH_RCA2_DN__W 4
+#define VSB_TOP_SNRTH_RCA2_DN__M 0xF
+#define VSB_TOP_SNRTH_RCA2_DN__PRE 0x5
+
+#define VSB_TOP_SNRTH_RCA2_UP__B 4
+#define VSB_TOP_SNRTH_RCA2_UP__W 4
+#define VSB_TOP_SNRTH_RCA2_UP__M 0xF0
+#define VSB_TOP_SNRTH_RCA2_UP__PRE 0x70
+
+#define VSB_TOP_SNRTH_DDM1__A 0x1C10020
+#define VSB_TOP_SNRTH_DDM1__W 8
+#define VSB_TOP_SNRTH_DDM1__M 0xFF
+#define VSB_TOP_SNRTH_DDM1__PRE 0xCA
+
+#define VSB_TOP_SNRTH_DDM1_DN__B 0
+#define VSB_TOP_SNRTH_DDM1_DN__W 4
+#define VSB_TOP_SNRTH_DDM1_DN__M 0xF
+#define VSB_TOP_SNRTH_DDM1_DN__PRE 0xA
+
+#define VSB_TOP_SNRTH_DDM1_UP__B 4
+#define VSB_TOP_SNRTH_DDM1_UP__W 4
+#define VSB_TOP_SNRTH_DDM1_UP__M 0xF0
+#define VSB_TOP_SNRTH_DDM1_UP__PRE 0xC0
+
+#define VSB_TOP_SNRTH_DDM2__A 0x1C10021
+#define VSB_TOP_SNRTH_DDM2__W 8
+#define VSB_TOP_SNRTH_DDM2__M 0xFF
+#define VSB_TOP_SNRTH_DDM2__PRE 0xCA
+
+#define VSB_TOP_SNRTH_DDM2_DN__B 0
+#define VSB_TOP_SNRTH_DDM2_DN__W 4
+#define VSB_TOP_SNRTH_DDM2_DN__M 0xF
+#define VSB_TOP_SNRTH_DDM2_DN__PRE 0xA
+
+#define VSB_TOP_SNRTH_DDM2_UP__B 4
+#define VSB_TOP_SNRTH_DDM2_UP__W 4
+#define VSB_TOP_SNRTH_DDM2_UP__M 0xF0
+#define VSB_TOP_SNRTH_DDM2_UP__PRE 0xC0
+
+#define VSB_TOP_SNRTH_PT__A 0x1C10022
+#define VSB_TOP_SNRTH_PT__W 8
+#define VSB_TOP_SNRTH_PT__M 0xFF
+#define VSB_TOP_SNRTH_PT__PRE 0xD8
+
+#define VSB_TOP_SNRTH_PT_DN__B 0
+#define VSB_TOP_SNRTH_PT_DN__W 4
+#define VSB_TOP_SNRTH_PT_DN__M 0xF
+#define VSB_TOP_SNRTH_PT_DN__PRE 0x8
+
+#define VSB_TOP_SNRTH_PT_UP__B 4
+#define VSB_TOP_SNRTH_PT_UP__W 4
+#define VSB_TOP_SNRTH_PT_UP__M 0xF0
+#define VSB_TOP_SNRTH_PT_UP__PRE 0xD0
+
+#define VSB_TOP_CYSMSTATES__A 0x1C10023
+#define VSB_TOP_CYSMSTATES__W 8
+#define VSB_TOP_CYSMSTATES__M 0xFF
+#define VSB_TOP_CYSMSTATES__PRE 0x0
+
+#define VSB_TOP_CYSMSTATES_SYSST__B 0
+#define VSB_TOP_CYSMSTATES_SYSST__W 4
+#define VSB_TOP_CYSMSTATES_SYSST__M 0xF
+#define VSB_TOP_CYSMSTATES_SYSST__PRE 0x0
+
+#define VSB_TOP_CYSMSTATES_EQST__B 4
+#define VSB_TOP_CYSMSTATES_EQST__W 4
+#define VSB_TOP_CYSMSTATES_EQST__M 0xF0
+#define VSB_TOP_CYSMSTATES_EQST__PRE 0x0
+
+#define VSB_TOP_SMALL_NOTCH_CONTROL__A 0x1C10024
+#define VSB_TOP_SMALL_NOTCH_CONTROL__W 8
+#define VSB_TOP_SMALL_NOTCH_CONTROL__M 0xFF
+#define VSB_TOP_SMALL_NOTCH_CONTROL__PRE 0x0
+
+#define VSB_TOP_SMALL_NOTCH_CONTROL_GO__B 0
+#define VSB_TOP_SMALL_NOTCH_CONTROL_GO__W 1
+#define VSB_TOP_SMALL_NOTCH_CONTROL_GO__M 0x1
+#define VSB_TOP_SMALL_NOTCH_CONTROL_GO__PRE 0x0
+
+#define VSB_TOP_SMALL_NOTCH_CONTROL_BYPASS1__B 1
+#define VSB_TOP_SMALL_NOTCH_CONTROL_BYPASS1__W 1
+#define VSB_TOP_SMALL_NOTCH_CONTROL_BYPASS1__M 0x2
+#define VSB_TOP_SMALL_NOTCH_CONTROL_BYPASS1__PRE 0x0
+
+#define VSB_TOP_SMALL_NOTCH_CONTROL_BYPASS2__B 2
+#define VSB_TOP_SMALL_NOTCH_CONTROL_BYPASS2__W 1
+#define VSB_TOP_SMALL_NOTCH_CONTROL_BYPASS2__M 0x4
+#define VSB_TOP_SMALL_NOTCH_CONTROL_BYPASS2__PRE 0x0
+
+#define VSB_TOP_SMALL_NOTCH_CONTROL_SPARE__B 3
+#define VSB_TOP_SMALL_NOTCH_CONTROL_SPARE__W 4
+#define VSB_TOP_SMALL_NOTCH_CONTROL_SPARE__M 0x78
+#define VSB_TOP_SMALL_NOTCH_CONTROL_SPARE__PRE 0x0
+
+#define VSB_TOP_SMALL_NOTCH_CONTROL_SOFT_RESET__B 7
+#define VSB_TOP_SMALL_NOTCH_CONTROL_SOFT_RESET__W 1
+#define VSB_TOP_SMALL_NOTCH_CONTROL_SOFT_RESET__M 0x80
+#define VSB_TOP_SMALL_NOTCH_CONTROL_SOFT_RESET__PRE 0x0
+
+#define VSB_TOP_TAPREADCYC__A 0x1C10025
+#define VSB_TOP_TAPREADCYC__W 9
+#define VSB_TOP_TAPREADCYC__M 0x1FF
+#define VSB_TOP_TAPREADCYC__PRE 0x1
+
+#define VSB_TOP_VALIDPKLVL__A 0x1C10026
+#define VSB_TOP_VALIDPKLVL__W 13
+#define VSB_TOP_VALIDPKLVL__M 0x1FFF
+#define VSB_TOP_VALIDPKLVL__PRE 0x100
+
+#define VSB_TOP_CENTROID_FINE_DELAY__A 0x1C10027
+#define VSB_TOP_CENTROID_FINE_DELAY__W 10
+#define VSB_TOP_CENTROID_FINE_DELAY__M 0x3FF
+#define VSB_TOP_CENTROID_FINE_DELAY__PRE 0xFF
+
+#define VSB_TOP_CENTROID_SMACH_DELAY__A 0x1C10028
+#define VSB_TOP_CENTROID_SMACH_DELAY__W 10
+#define VSB_TOP_CENTROID_SMACH_DELAY__M 0x3FF
+#define VSB_TOP_CENTROID_SMACH_DELAY__PRE 0x1FF
+
+#define VSB_TOP_SNR__A 0x1C10029
+#define VSB_TOP_SNR__W 14
+#define VSB_TOP_SNR__M 0x3FFF
+#define VSB_TOP_SNR__PRE 0x0
+#define VSB_TOP_LOCKSTATUS__A 0x1C1002A
+#define VSB_TOP_LOCKSTATUS__W 7
+#define VSB_TOP_LOCKSTATUS__M 0x7F
+#define VSB_TOP_LOCKSTATUS__PRE 0x0
+
+#define VSB_TOP_LOCKSTATUS_VSBMODE__B 0
+#define VSB_TOP_LOCKSTATUS_VSBMODE__W 4
+#define VSB_TOP_LOCKSTATUS_VSBMODE__M 0xF
+#define VSB_TOP_LOCKSTATUS_VSBMODE__PRE 0x0
+
+#define VSB_TOP_LOCKSTATUS_FRMLOCK__B 4
+#define VSB_TOP_LOCKSTATUS_FRMLOCK__W 1
+#define VSB_TOP_LOCKSTATUS_FRMLOCK__M 0x10
+#define VSB_TOP_LOCKSTATUS_FRMLOCK__PRE 0x0
+
+#define VSB_TOP_LOCKSTATUS_CYLOCK__B 5
+#define VSB_TOP_LOCKSTATUS_CYLOCK__W 1
+#define VSB_TOP_LOCKSTATUS_CYLOCK__M 0x20
+#define VSB_TOP_LOCKSTATUS_CYLOCK__PRE 0x0
+
+#define VSB_TOP_LOCKSTATUS_DDMON__B 6
+#define VSB_TOP_LOCKSTATUS_DDMON__W 1
+#define VSB_TOP_LOCKSTATUS_DDMON__M 0x40
+#define VSB_TOP_LOCKSTATUS_DDMON__PRE 0x0
+
+#define VSB_TOP_CTST__A 0x1C1002B
+#define VSB_TOP_CTST__W 4
+#define VSB_TOP_CTST__M 0xF
+#define VSB_TOP_CTST__PRE 0x0
+#define VSB_TOP_EQSMRSTCTRL__A 0x1C1002C
+#define VSB_TOP_EQSMRSTCTRL__W 7
+#define VSB_TOP_EQSMRSTCTRL__M 0x7F
+#define VSB_TOP_EQSMRSTCTRL__PRE 0x0
+
+#define VSB_TOP_EQSMRSTCTRL_RCAON__B 0
+#define VSB_TOP_EQSMRSTCTRL_RCAON__W 1
+#define VSB_TOP_EQSMRSTCTRL_RCAON__M 0x1
+#define VSB_TOP_EQSMRSTCTRL_RCAON__PRE 0x0
+
+#define VSB_TOP_EQSMRSTCTRL_DFEON__B 1
+#define VSB_TOP_EQSMRSTCTRL_DFEON__W 1
+#define VSB_TOP_EQSMRSTCTRL_DFEON__M 0x2
+#define VSB_TOP_EQSMRSTCTRL_DFEON__PRE 0x0
+
+#define VSB_TOP_EQSMRSTCTRL_DDMEN1__B 2
+#define VSB_TOP_EQSMRSTCTRL_DDMEN1__W 1
+#define VSB_TOP_EQSMRSTCTRL_DDMEN1__M 0x4
+#define VSB_TOP_EQSMRSTCTRL_DDMEN1__PRE 0x0
+
+#define VSB_TOP_EQSMRSTCTRL_DDMEN2__B 3
+#define VSB_TOP_EQSMRSTCTRL_DDMEN2__W 1
+#define VSB_TOP_EQSMRSTCTRL_DDMEN2__M 0x8
+#define VSB_TOP_EQSMRSTCTRL_DDMEN2__PRE 0x0
+
+#define VSB_TOP_EQSMRSTCTRL_DIGIAGCON__B 4
+#define VSB_TOP_EQSMRSTCTRL_DIGIAGCON__W 1
+#define VSB_TOP_EQSMRSTCTRL_DIGIAGCON__M 0x10
+#define VSB_TOP_EQSMRSTCTRL_DIGIAGCON__PRE 0x0
+
+#define VSB_TOP_EQSMRSTCTRL_PARAINITEN__B 5
+#define VSB_TOP_EQSMRSTCTRL_PARAINITEN__W 1
+#define VSB_TOP_EQSMRSTCTRL_PARAINITEN__M 0x20
+#define VSB_TOP_EQSMRSTCTRL_PARAINITEN__PRE 0x0
+
+#define VSB_TOP_EQSMRSTCTRL_TIMEOUTFRMCNTEN__B 6
+#define VSB_TOP_EQSMRSTCTRL_TIMEOUTFRMCNTEN__W 1
+#define VSB_TOP_EQSMRSTCTRL_TIMEOUTFRMCNTEN__M 0x40
+#define VSB_TOP_EQSMRSTCTRL_TIMEOUTFRMCNTEN__PRE 0x0
+
+#define VSB_TOP_EQSMTRNCTRL__A 0x1C1002D
+#define VSB_TOP_EQSMTRNCTRL__W 7
+#define VSB_TOP_EQSMTRNCTRL__M 0x7F
+#define VSB_TOP_EQSMTRNCTRL__PRE 0x40
+
+#define VSB_TOP_EQSMTRNCTRL_RCAON__B 0
+#define VSB_TOP_EQSMTRNCTRL_RCAON__W 1
+#define VSB_TOP_EQSMTRNCTRL_RCAON__M 0x1
+#define VSB_TOP_EQSMTRNCTRL_RCAON__PRE 0x0
+
+#define VSB_TOP_EQSMTRNCTRL_DFEON__B 1
+#define VSB_TOP_EQSMTRNCTRL_DFEON__W 1
+#define VSB_TOP_EQSMTRNCTRL_DFEON__M 0x2
+#define VSB_TOP_EQSMTRNCTRL_DFEON__PRE 0x0
+
+#define VSB_TOP_EQSMTRNCTRL_DDMEN1__B 2
+#define VSB_TOP_EQSMTRNCTRL_DDMEN1__W 1
+#define VSB_TOP_EQSMTRNCTRL_DDMEN1__M 0x4
+#define VSB_TOP_EQSMTRNCTRL_DDMEN1__PRE 0x0
+
+#define VSB_TOP_EQSMTRNCTRL_DDMEN2__B 3
+#define VSB_TOP_EQSMTRNCTRL_DDMEN2__W 1
+#define VSB_TOP_EQSMTRNCTRL_DDMEN2__M 0x8
+#define VSB_TOP_EQSMTRNCTRL_DDMEN2__PRE 0x0
+
+#define VSB_TOP_EQSMTRNCTRL_DIGIAGCON__B 4
+#define VSB_TOP_EQSMTRNCTRL_DIGIAGCON__W 1
+#define VSB_TOP_EQSMTRNCTRL_DIGIAGCON__M 0x10
+#define VSB_TOP_EQSMTRNCTRL_DIGIAGCON__PRE 0x0
+
+#define VSB_TOP_EQSMTRNCTRL_PARAINITEN__B 5
+#define VSB_TOP_EQSMTRNCTRL_PARAINITEN__W 1
+#define VSB_TOP_EQSMTRNCTRL_PARAINITEN__M 0x20
+#define VSB_TOP_EQSMTRNCTRL_PARAINITEN__PRE 0x0
+
+#define VSB_TOP_EQSMTRNCTRL_TIMEOUTFRMCNTEN__B 6
+#define VSB_TOP_EQSMTRNCTRL_TIMEOUTFRMCNTEN__W 1
+#define VSB_TOP_EQSMTRNCTRL_TIMEOUTFRMCNTEN__M 0x40
+#define VSB_TOP_EQSMTRNCTRL_TIMEOUTFRMCNTEN__PRE 0x40
+
+#define VSB_TOP_EQSMRCA1CTRL__A 0x1C1002E
+#define VSB_TOP_EQSMRCA1CTRL__W 7
+#define VSB_TOP_EQSMRCA1CTRL__M 0x7F
+#define VSB_TOP_EQSMRCA1CTRL__PRE 0x1
+
+#define VSB_TOP_EQSMRCA1CTRL_RCAON__B 0
+#define VSB_TOP_EQSMRCA1CTRL_RCAON__W 1
+#define VSB_TOP_EQSMRCA1CTRL_RCAON__M 0x1
+#define VSB_TOP_EQSMRCA1CTRL_RCAON__PRE 0x1
+
+#define VSB_TOP_EQSMRCA1CTRL_DFEON__B 1
+#define VSB_TOP_EQSMRCA1CTRL_DFEON__W 1
+#define VSB_TOP_EQSMRCA1CTRL_DFEON__M 0x2
+#define VSB_TOP_EQSMRCA1CTRL_DFEON__PRE 0x0
+
+#define VSB_TOP_EQSMRCA1CTRL_DDMEN1__B 2
+#define VSB_TOP_EQSMRCA1CTRL_DDMEN1__W 1
+#define VSB_TOP_EQSMRCA1CTRL_DDMEN1__M 0x4
+#define VSB_TOP_EQSMRCA1CTRL_DDMEN1__PRE 0x0
+
+#define VSB_TOP_EQSMRCA1CTRL_DDMEN2__B 3
+#define VSB_TOP_EQSMRCA1CTRL_DDMEN2__W 1
+#define VSB_TOP_EQSMRCA1CTRL_DDMEN2__M 0x8
+#define VSB_TOP_EQSMRCA1CTRL_DDMEN2__PRE 0x0
+
+#define VSB_TOP_EQSMRCA1CTRL_DIGIAGCON__B 4
+#define VSB_TOP_EQSMRCA1CTRL_DIGIAGCON__W 1
+#define VSB_TOP_EQSMRCA1CTRL_DIGIAGCON__M 0x10
+#define VSB_TOP_EQSMRCA1CTRL_DIGIAGCON__PRE 0x0
+
+#define VSB_TOP_EQSMRCA1CTRL_PARAINITEN__B 5
+#define VSB_TOP_EQSMRCA1CTRL_PARAINITEN__W 1
+#define VSB_TOP_EQSMRCA1CTRL_PARAINITEN__M 0x20
+#define VSB_TOP_EQSMRCA1CTRL_PARAINITEN__PRE 0x0
+
+#define VSB_TOP_EQSMRCA1CTRL_TIMEOUTFRMCNTEN__B 6
+#define VSB_TOP_EQSMRCA1CTRL_TIMEOUTFRMCNTEN__W 1
+#define VSB_TOP_EQSMRCA1CTRL_TIMEOUTFRMCNTEN__M 0x40
+#define VSB_TOP_EQSMRCA1CTRL_TIMEOUTFRMCNTEN__PRE 0x0
+
+#define VSB_TOP_EQSMRCA2CTRL__A 0x1C1002F
+#define VSB_TOP_EQSMRCA2CTRL__W 7
+#define VSB_TOP_EQSMRCA2CTRL__M 0x7F
+#define VSB_TOP_EQSMRCA2CTRL__PRE 0x3
+
+#define VSB_TOP_EQSMRCA2CTRL_RCAON__B 0
+#define VSB_TOP_EQSMRCA2CTRL_RCAON__W 1
+#define VSB_TOP_EQSMRCA2CTRL_RCAON__M 0x1
+#define VSB_TOP_EQSMRCA2CTRL_RCAON__PRE 0x1
+
+#define VSB_TOP_EQSMRCA2CTRL_DFEON__B 1
+#define VSB_TOP_EQSMRCA2CTRL_DFEON__W 1
+#define VSB_TOP_EQSMRCA2CTRL_DFEON__M 0x2
+#define VSB_TOP_EQSMRCA2CTRL_DFEON__PRE 0x2
+
+#define VSB_TOP_EQSMRCA2CTRL_DDMEN1__B 2
+#define VSB_TOP_EQSMRCA2CTRL_DDMEN1__W 1
+#define VSB_TOP_EQSMRCA2CTRL_DDMEN1__M 0x4
+#define VSB_TOP_EQSMRCA2CTRL_DDMEN1__PRE 0x0
+
+#define VSB_TOP_EQSMRCA2CTRL_DDMEN2__B 3
+#define VSB_TOP_EQSMRCA2CTRL_DDMEN2__W 1
+#define VSB_TOP_EQSMRCA2CTRL_DDMEN2__M 0x8
+#define VSB_TOP_EQSMRCA2CTRL_DDMEN2__PRE 0x0
+
+#define VSB_TOP_EQSMRCA2CTRL_DIGIAGCON__B 4
+#define VSB_TOP_EQSMRCA2CTRL_DIGIAGCON__W 1
+#define VSB_TOP_EQSMRCA2CTRL_DIGIAGCON__M 0x10
+#define VSB_TOP_EQSMRCA2CTRL_DIGIAGCON__PRE 0x0
+
+#define VSB_TOP_EQSMRCA2CTRL_PARAINITEN__B 5
+#define VSB_TOP_EQSMRCA2CTRL_PARAINITEN__W 1
+#define VSB_TOP_EQSMRCA2CTRL_PARAINITEN__M 0x20
+#define VSB_TOP_EQSMRCA2CTRL_PARAINITEN__PRE 0x0
+
+#define VSB_TOP_EQSMRCA2CTRL_TIMEOUTFRMCNTEN__B 6
+#define VSB_TOP_EQSMRCA2CTRL_TIMEOUTFRMCNTEN__W 1
+#define VSB_TOP_EQSMRCA2CTRL_TIMEOUTFRMCNTEN__M 0x40
+#define VSB_TOP_EQSMRCA2CTRL_TIMEOUTFRMCNTEN__PRE 0x0
+
+#define VSB_TOP_EQSMDDM1CTRL__A 0x1C10030
+#define VSB_TOP_EQSMDDM1CTRL__W 7
+#define VSB_TOP_EQSMDDM1CTRL__M 0x7F
+#define VSB_TOP_EQSMDDM1CTRL__PRE 0x6
+
+#define VSB_TOP_EQSMDDM1CTRL_RCAON__B 0
+#define VSB_TOP_EQSMDDM1CTRL_RCAON__W 1
+#define VSB_TOP_EQSMDDM1CTRL_RCAON__M 0x1
+#define VSB_TOP_EQSMDDM1CTRL_RCAON__PRE 0x0
+
+#define VSB_TOP_EQSMDDM1CTRL_DFEON__B 1
+#define VSB_TOP_EQSMDDM1CTRL_DFEON__W 1
+#define VSB_TOP_EQSMDDM1CTRL_DFEON__M 0x2
+#define VSB_TOP_EQSMDDM1CTRL_DFEON__PRE 0x2
+
+#define VSB_TOP_EQSMDDM1CTRL_DDMEN1__B 2
+#define VSB_TOP_EQSMDDM1CTRL_DDMEN1__W 1
+#define VSB_TOP_EQSMDDM1CTRL_DDMEN1__M 0x4
+#define VSB_TOP_EQSMDDM1CTRL_DDMEN1__PRE 0x4
+
+#define VSB_TOP_EQSMDDM1CTRL_DDMEN2__B 3
+#define VSB_TOP_EQSMDDM1CTRL_DDMEN2__W 1
+#define VSB_TOP_EQSMDDM1CTRL_DDMEN2__M 0x8
+#define VSB_TOP_EQSMDDM1CTRL_DDMEN2__PRE 0x0
+
+#define VSB_TOP_EQSMDDM1CTRL_DIGIAGCON__B 4
+#define VSB_TOP_EQSMDDM1CTRL_DIGIAGCON__W 1
+#define VSB_TOP_EQSMDDM1CTRL_DIGIAGCON__M 0x10
+#define VSB_TOP_EQSMDDM1CTRL_DIGIAGCON__PRE 0x0
+
+#define VSB_TOP_EQSMDDM1CTRL_PARAINITEN__B 5
+#define VSB_TOP_EQSMDDM1CTRL_PARAINITEN__W 1
+#define VSB_TOP_EQSMDDM1CTRL_PARAINITEN__M 0x20
+#define VSB_TOP_EQSMDDM1CTRL_PARAINITEN__PRE 0x0
+
+#define VSB_TOP_EQSMDDM1CTRL_TIMEOUTFRMCNTEN__B 6
+#define VSB_TOP_EQSMDDM1CTRL_TIMEOUTFRMCNTEN__W 1
+#define VSB_TOP_EQSMDDM1CTRL_TIMEOUTFRMCNTEN__M 0x40
+#define VSB_TOP_EQSMDDM1CTRL_TIMEOUTFRMCNTEN__PRE 0x0
+
+#define VSB_TOP_EQSMDDM2CTRL__A 0x1C10031
+#define VSB_TOP_EQSMDDM2CTRL__W 7
+#define VSB_TOP_EQSMDDM2CTRL__M 0x7F
+#define VSB_TOP_EQSMDDM2CTRL__PRE 0x1E
+
+#define VSB_TOP_EQSMDDM2CTRL_RCAON__B 0
+#define VSB_TOP_EQSMDDM2CTRL_RCAON__W 1
+#define VSB_TOP_EQSMDDM2CTRL_RCAON__M 0x1
+#define VSB_TOP_EQSMDDM2CTRL_RCAON__PRE 0x0
+
+#define VSB_TOP_EQSMDDM2CTRL_DFEON__B 1
+#define VSB_TOP_EQSMDDM2CTRL_DFEON__W 1
+#define VSB_TOP_EQSMDDM2CTRL_DFEON__M 0x2
+#define VSB_TOP_EQSMDDM2CTRL_DFEON__PRE 0x2
+
+#define VSB_TOP_EQSMDDM2CTRL_DDMEN1__B 2
+#define VSB_TOP_EQSMDDM2CTRL_DDMEN1__W 1
+#define VSB_TOP_EQSMDDM2CTRL_DDMEN1__M 0x4
+#define VSB_TOP_EQSMDDM2CTRL_DDMEN1__PRE 0x4
+
+#define VSB_TOP_EQSMDDM2CTRL_DDMEN2__B 3
+#define VSB_TOP_EQSMDDM2CTRL_DDMEN2__W 1
+#define VSB_TOP_EQSMDDM2CTRL_DDMEN2__M 0x8
+#define VSB_TOP_EQSMDDM2CTRL_DDMEN2__PRE 0x8
+
+#define VSB_TOP_EQSMDDM2CTRL_DIGIAGCON__B 4
+#define VSB_TOP_EQSMDDM2CTRL_DIGIAGCON__W 1
+#define VSB_TOP_EQSMDDM2CTRL_DIGIAGCON__M 0x10
+#define VSB_TOP_EQSMDDM2CTRL_DIGIAGCON__PRE 0x10
+
+#define VSB_TOP_EQSMDDM2CTRL_PARAINITEN__B 5
+#define VSB_TOP_EQSMDDM2CTRL_PARAINITEN__W 1
+#define VSB_TOP_EQSMDDM2CTRL_PARAINITEN__M 0x20
+#define VSB_TOP_EQSMDDM2CTRL_PARAINITEN__PRE 0x0
+
+#define VSB_TOP_EQSMDDM2CTRL_TIMEOUTFRMCNTEN__B 6
+#define VSB_TOP_EQSMDDM2CTRL_TIMEOUTFRMCNTEN__W 1
+#define VSB_TOP_EQSMDDM2CTRL_TIMEOUTFRMCNTEN__M 0x40
+#define VSB_TOP_EQSMDDM2CTRL_TIMEOUTFRMCNTEN__PRE 0x0
+
+#define VSB_TOP_SYSSMRSTCTRL__A 0x1C10032
+#define VSB_TOP_SYSSMRSTCTRL__W 11
+#define VSB_TOP_SYSSMRSTCTRL__M 0x7FF
+#define VSB_TOP_SYSSMRSTCTRL__PRE 0x7F9
+
+#define VSB_TOP_SYSSMRSTCTRL_RSTCTCAL__B 0
+#define VSB_TOP_SYSSMRSTCTRL_RSTCTCAL__W 1
+#define VSB_TOP_SYSSMRSTCTRL_RSTCTCAL__M 0x1
+#define VSB_TOP_SYSSMRSTCTRL_RSTCTCAL__PRE 0x1
+
+#define VSB_TOP_SYSSMRSTCTRL_CTCALEN__B 1
+#define VSB_TOP_SYSSMRSTCTRL_CTCALEN__W 1
+#define VSB_TOP_SYSSMRSTCTRL_CTCALEN__M 0x2
+#define VSB_TOP_SYSSMRSTCTRL_CTCALEN__PRE 0x0
+
+#define VSB_TOP_SYSSMRSTCTRL_STARTTRN__B 2
+#define VSB_TOP_SYSSMRSTCTRL_STARTTRN__W 1
+#define VSB_TOP_SYSSMRSTCTRL_STARTTRN__M 0x4
+#define VSB_TOP_SYSSMRSTCTRL_STARTTRN__PRE 0x0
+
+#define VSB_TOP_SYSSMRSTCTRL_RSTFRMSYNCDET__B 3
+#define VSB_TOP_SYSSMRSTCTRL_RSTFRMSYNCDET__W 1
+#define VSB_TOP_SYSSMRSTCTRL_RSTFRMSYNCDET__M 0x8
+#define VSB_TOP_SYSSMRSTCTRL_RSTFRMSYNCDET__PRE 0x8
+
+#define VSB_TOP_SYSSMRSTCTRL_RSTCYDET__B 4
+#define VSB_TOP_SYSSMRSTCTRL_RSTCYDET__W 1
+#define VSB_TOP_SYSSMRSTCTRL_RSTCYDET__M 0x10
+#define VSB_TOP_SYSSMRSTCTRL_RSTCYDET__PRE 0x10
+
+#define VSB_TOP_SYSSMRSTCTRL_RSTDCRMV__B 5
+#define VSB_TOP_SYSSMRSTCTRL_RSTDCRMV__W 1
+#define VSB_TOP_SYSSMRSTCTRL_RSTDCRMV__M 0x20
+#define VSB_TOP_SYSSMRSTCTRL_RSTDCRMV__PRE 0x20
+
+#define VSB_TOP_SYSSMRSTCTRL_RSTEQSIG__B 6
+#define VSB_TOP_SYSSMRSTCTRL_RSTEQSIG__W 1
+#define VSB_TOP_SYSSMRSTCTRL_RSTEQSIG__M 0x40
+#define VSB_TOP_SYSSMRSTCTRL_RSTEQSIG__PRE 0x40
+
+#define VSB_TOP_SYSSMRSTCTRL_CKFRZ__B 7
+#define VSB_TOP_SYSSMRSTCTRL_CKFRZ__W 1
+#define VSB_TOP_SYSSMRSTCTRL_CKFRZ__M 0x80
+#define VSB_TOP_SYSSMRSTCTRL_CKFRZ__PRE 0x80
+
+#define VSB_TOP_SYSSMRSTCTRL_CKBWSW__B 8
+#define VSB_TOP_SYSSMRSTCTRL_CKBWSW__W 1
+#define VSB_TOP_SYSSMRSTCTRL_CKBWSW__M 0x100
+#define VSB_TOP_SYSSMRSTCTRL_CKBWSW__PRE 0x100
+
+#define VSB_TOP_SYSSMRSTCTRL_NCOBWSW__B 9
+#define VSB_TOP_SYSSMRSTCTRL_NCOBWSW__W 1
+#define VSB_TOP_SYSSMRSTCTRL_NCOBWSW__M 0x200
+#define VSB_TOP_SYSSMRSTCTRL_NCOBWSW__PRE 0x200
+
+#define VSB_TOP_SYSSMRSTCTRL_NCOTIMEOUTCNTEN__B 10
+#define VSB_TOP_SYSSMRSTCTRL_NCOTIMEOUTCNTEN__W 1
+#define VSB_TOP_SYSSMRSTCTRL_NCOTIMEOUTCNTEN__M 0x400
+#define VSB_TOP_SYSSMRSTCTRL_NCOTIMEOUTCNTEN__PRE 0x400
+
+#define VSB_TOP_SYSSMCYCTRL__A 0x1C10033
+#define VSB_TOP_SYSSMCYCTRL__W 11
+#define VSB_TOP_SYSSMCYCTRL__M 0x7FF
+#define VSB_TOP_SYSSMCYCTRL__PRE 0x4E9
+
+#define VSB_TOP_SYSSMCYCTRL_RSTCTCAL__B 0
+#define VSB_TOP_SYSSMCYCTRL_RSTCTCAL__W 1
+#define VSB_TOP_SYSSMCYCTRL_RSTCTCAL__M 0x1
+#define VSB_TOP_SYSSMCYCTRL_RSTCTCAL__PRE 0x1
+
+#define VSB_TOP_SYSSMCYCTRL_CTCALEN__B 1
+#define VSB_TOP_SYSSMCYCTRL_CTCALEN__W 1
+#define VSB_TOP_SYSSMCYCTRL_CTCALEN__M 0x2
+#define VSB_TOP_SYSSMCYCTRL_CTCALEN__PRE 0x0
+
+#define VSB_TOP_SYSSMCYCTRL_STARTTRN__B 2
+#define VSB_TOP_SYSSMCYCTRL_STARTTRN__W 1
+#define VSB_TOP_SYSSMCYCTRL_STARTTRN__M 0x4
+#define VSB_TOP_SYSSMCYCTRL_STARTTRN__PRE 0x0
+
+#define VSB_TOP_SYSSMCYCTRL_RSTFRMSYNCDET__B 3
+#define VSB_TOP_SYSSMCYCTRL_RSTFRMSYNCDET__W 1
+#define VSB_TOP_SYSSMCYCTRL_RSTFRMSYNCDET__M 0x8
+#define VSB_TOP_SYSSMCYCTRL_RSTFRMSYNCDET__PRE 0x8
+
+#define VSB_TOP_SYSSMCYCTRL_RSTCYDET__B 4
+#define VSB_TOP_SYSSMCYCTRL_RSTCYDET__W 1
+#define VSB_TOP_SYSSMCYCTRL_RSTCYDET__M 0x10
+#define VSB_TOP_SYSSMCYCTRL_RSTCYDET__PRE 0x0
+
+#define VSB_TOP_SYSSMCYCTRL_RSTDCRMV__B 5
+#define VSB_TOP_SYSSMCYCTRL_RSTDCRMV__W 1
+#define VSB_TOP_SYSSMCYCTRL_RSTDCRMV__M 0x20
+#define VSB_TOP_SYSSMCYCTRL_RSTDCRMV__PRE 0x20
+
+#define VSB_TOP_SYSSMCYCTRL_RSTEQSIG__B 6
+#define VSB_TOP_SYSSMCYCTRL_RSTEQSIG__W 1
+#define VSB_TOP_SYSSMCYCTRL_RSTEQSIG__M 0x40
+#define VSB_TOP_SYSSMCYCTRL_RSTEQSIG__PRE 0x40
+
+#define VSB_TOP_SYSSMCYCTRL_CKFRZ__B 7
+#define VSB_TOP_SYSSMCYCTRL_CKFRZ__W 1
+#define VSB_TOP_SYSSMCYCTRL_CKFRZ__M 0x80
+#define VSB_TOP_SYSSMCYCTRL_CKFRZ__PRE 0x80
+
+#define VSB_TOP_SYSSMCYCTRL_CKBWSW__B 8
+#define VSB_TOP_SYSSMCYCTRL_CKBWSW__W 1
+#define VSB_TOP_SYSSMCYCTRL_CKBWSW__M 0x100
+#define VSB_TOP_SYSSMCYCTRL_CKBWSW__PRE 0x0
+
+#define VSB_TOP_SYSSMCYCTRL_NCOBWSW__B 9
+#define VSB_TOP_SYSSMCYCTRL_NCOBWSW__W 1
+#define VSB_TOP_SYSSMCYCTRL_NCOBWSW__M 0x200
+#define VSB_TOP_SYSSMCYCTRL_NCOBWSW__PRE 0x0
+
+#define VSB_TOP_SYSSMCYCTRL_NCOTIMEOUTCNTEN__B 10
+#define VSB_TOP_SYSSMCYCTRL_NCOTIMEOUTCNTEN__W 1
+#define VSB_TOP_SYSSMCYCTRL_NCOTIMEOUTCNTEN__M 0x400
+#define VSB_TOP_SYSSMCYCTRL_NCOTIMEOUTCNTEN__PRE 0x400
+
+#define VSB_TOP_SYSSMTRNCTRL__A 0x1C10034
+#define VSB_TOP_SYSSMTRNCTRL__W 11
+#define VSB_TOP_SYSSMTRNCTRL__M 0x7FF
+#define VSB_TOP_SYSSMTRNCTRL__PRE 0x204
+
+#define VSB_TOP_SYSSMTRNCTRL_RSTCTCAL__B 0
+#define VSB_TOP_SYSSMTRNCTRL_RSTCTCAL__W 1
+#define VSB_TOP_SYSSMTRNCTRL_RSTCTCAL__M 0x1
+#define VSB_TOP_SYSSMTRNCTRL_RSTCTCAL__PRE 0x0
+
+#define VSB_TOP_SYSSMTRNCTRL_CTCALEN__B 1
+#define VSB_TOP_SYSSMTRNCTRL_CTCALEN__W 1
+#define VSB_TOP_SYSSMTRNCTRL_CTCALEN__M 0x2
+#define VSB_TOP_SYSSMTRNCTRL_CTCALEN__PRE 0x0
+
+#define VSB_TOP_SYSSMTRNCTRL_STARTTRN__B 2
+#define VSB_TOP_SYSSMTRNCTRL_STARTTRN__W 1
+#define VSB_TOP_SYSSMTRNCTRL_STARTTRN__M 0x4
+#define VSB_TOP_SYSSMTRNCTRL_STARTTRN__PRE 0x4
+
+#define VSB_TOP_SYSSMTRNCTRL_RSTFRMSYNCDET__B 3
+#define VSB_TOP_SYSSMTRNCTRL_RSTFRMSYNCDET__W 1
+#define VSB_TOP_SYSSMTRNCTRL_RSTFRMSYNCDET__M 0x8
+#define VSB_TOP_SYSSMTRNCTRL_RSTFRMSYNCDET__PRE 0x0
+
+#define VSB_TOP_SYSSMTRNCTRL_RSTCYDET__B 4
+#define VSB_TOP_SYSSMTRNCTRL_RSTCYDET__W 1
+#define VSB_TOP_SYSSMTRNCTRL_RSTCYDET__M 0x10
+#define VSB_TOP_SYSSMTRNCTRL_RSTCYDET__PRE 0x0
+
+#define VSB_TOP_SYSSMTRNCTRL_RSTDCRMV__B 5
+#define VSB_TOP_SYSSMTRNCTRL_RSTDCRMV__W 1
+#define VSB_TOP_SYSSMTRNCTRL_RSTDCRMV__M 0x20
+#define VSB_TOP_SYSSMTRNCTRL_RSTDCRMV__PRE 0x0
+
+#define VSB_TOP_SYSSMTRNCTRL_RSTEQSIG__B 6
+#define VSB_TOP_SYSSMTRNCTRL_RSTEQSIG__W 1
+#define VSB_TOP_SYSSMTRNCTRL_RSTEQSIG__M 0x40
+#define VSB_TOP_SYSSMTRNCTRL_RSTEQSIG__PRE 0x0
+
+#define VSB_TOP_SYSSMTRNCTRL_CKFRZ__B 7
+#define VSB_TOP_SYSSMTRNCTRL_CKFRZ__W 1
+#define VSB_TOP_SYSSMTRNCTRL_CKFRZ__M 0x80
+#define VSB_TOP_SYSSMTRNCTRL_CKFRZ__PRE 0x0
+
+#define VSB_TOP_SYSSMTRNCTRL_CKBWSW__B 8
+#define VSB_TOP_SYSSMTRNCTRL_CKBWSW__W 1
+#define VSB_TOP_SYSSMTRNCTRL_CKBWSW__M 0x100
+#define VSB_TOP_SYSSMTRNCTRL_CKBWSW__PRE 0x0
+
+#define VSB_TOP_SYSSMTRNCTRL_NCOBWSW__B 9
+#define VSB_TOP_SYSSMTRNCTRL_NCOBWSW__W 1
+#define VSB_TOP_SYSSMTRNCTRL_NCOBWSW__M 0x200
+#define VSB_TOP_SYSSMTRNCTRL_NCOBWSW__PRE 0x200
+
+#define VSB_TOP_SYSSMTRNCTRL_NCOTIMEOUTCNTEN__B 10
+#define VSB_TOP_SYSSMTRNCTRL_NCOTIMEOUTCNTEN__W 1
+#define VSB_TOP_SYSSMTRNCTRL_NCOTIMEOUTCNTEN__M 0x400
+#define VSB_TOP_SYSSMTRNCTRL_NCOTIMEOUTCNTEN__PRE 0x0
+
+#define VSB_TOP_SYSSMEQCTRL__A 0x1C10035
+#define VSB_TOP_SYSSMEQCTRL__W 11
+#define VSB_TOP_SYSSMEQCTRL__M 0x7FF
+#define VSB_TOP_SYSSMEQCTRL__PRE 0x304
+
+#define VSB_TOP_SYSSMEQCTRL_RSTCTCAL__B 0
+#define VSB_TOP_SYSSMEQCTRL_RSTCTCAL__W 1
+#define VSB_TOP_SYSSMEQCTRL_RSTCTCAL__M 0x1
+#define VSB_TOP_SYSSMEQCTRL_RSTCTCAL__PRE 0x0
+
+#define VSB_TOP_SYSSMEQCTRL_CTCALEN__B 1
+#define VSB_TOP_SYSSMEQCTRL_CTCALEN__W 1
+#define VSB_TOP_SYSSMEQCTRL_CTCALEN__M 0x2
+#define VSB_TOP_SYSSMEQCTRL_CTCALEN__PRE 0x0
+
+#define VSB_TOP_SYSSMEQCTRL_STARTTRN__B 2
+#define VSB_TOP_SYSSMEQCTRL_STARTTRN__W 1
+#define VSB_TOP_SYSSMEQCTRL_STARTTRN__M 0x4
+#define VSB_TOP_SYSSMEQCTRL_STARTTRN__PRE 0x4
+
+#define VSB_TOP_SYSSMEQCTRL_RSTFRMSYNCDET__B 3
+#define VSB_TOP_SYSSMEQCTRL_RSTFRMSYNCDET__W 1
+#define VSB_TOP_SYSSMEQCTRL_RSTFRMSYNCDET__M 0x8
+#define VSB_TOP_SYSSMEQCTRL_RSTFRMSYNCDET__PRE 0x0
+
+#define VSB_TOP_SYSSMEQCTRL_RSTCYDET__B 4
+#define VSB_TOP_SYSSMEQCTRL_RSTCYDET__W 1
+#define VSB_TOP_SYSSMEQCTRL_RSTCYDET__M 0x10
+#define VSB_TOP_SYSSMEQCTRL_RSTCYDET__PRE 0x0
+
+#define VSB_TOP_SYSSMEQCTRL_RSTDCRMV__B 5
+#define VSB_TOP_SYSSMEQCTRL_RSTDCRMV__W 1
+#define VSB_TOP_SYSSMEQCTRL_RSTDCRMV__M 0x20
+#define VSB_TOP_SYSSMEQCTRL_RSTDCRMV__PRE 0x0
+
+#define VSB_TOP_SYSSMEQCTRL_RSTEQSIG__B 6
+#define VSB_TOP_SYSSMEQCTRL_RSTEQSIG__W 1
+#define VSB_TOP_SYSSMEQCTRL_RSTEQSIG__M 0x40
+#define VSB_TOP_SYSSMEQCTRL_RSTEQSIG__PRE 0x0
+
+#define VSB_TOP_SYSSMEQCTRL_CKFRZ__B 7
+#define VSB_TOP_SYSSMEQCTRL_CKFRZ__W 1
+#define VSB_TOP_SYSSMEQCTRL_CKFRZ__M 0x80
+#define VSB_TOP_SYSSMEQCTRL_CKFRZ__PRE 0x0
+
+#define VSB_TOP_SYSSMEQCTRL_CKBWSW__B 8
+#define VSB_TOP_SYSSMEQCTRL_CKBWSW__W 1
+#define VSB_TOP_SYSSMEQCTRL_CKBWSW__M 0x100
+#define VSB_TOP_SYSSMEQCTRL_CKBWSW__PRE 0x100
+
+#define VSB_TOP_SYSSMEQCTRL_NCOBWSW__B 9
+#define VSB_TOP_SYSSMEQCTRL_NCOBWSW__W 1
+#define VSB_TOP_SYSSMEQCTRL_NCOBWSW__M 0x200
+#define VSB_TOP_SYSSMEQCTRL_NCOBWSW__PRE 0x200
+
+#define VSB_TOP_SYSSMEQCTRL_NCOTIMEOUTCNTEN__B 10
+#define VSB_TOP_SYSSMEQCTRL_NCOTIMEOUTCNTEN__W 1
+#define VSB_TOP_SYSSMEQCTRL_NCOTIMEOUTCNTEN__M 0x400
+#define VSB_TOP_SYSSMEQCTRL_NCOTIMEOUTCNTEN__PRE 0x0
+
+#define VSB_TOP_SYSSMAGCCTRL__A 0x1C10036
+#define VSB_TOP_SYSSMAGCCTRL__W 11
+#define VSB_TOP_SYSSMAGCCTRL__M 0x7FF
+#define VSB_TOP_SYSSMAGCCTRL__PRE 0xF9
+
+#define VSB_TOP_SYSSMAGCCTRL_RSTCTCAL__B 0
+#define VSB_TOP_SYSSMAGCCTRL_RSTCTCAL__W 1
+#define VSB_TOP_SYSSMAGCCTRL_RSTCTCAL__M 0x1
+#define VSB_TOP_SYSSMAGCCTRL_RSTCTCAL__PRE 0x1
+
+#define VSB_TOP_SYSSMAGCCTRL_CTCALEN__B 1
+#define VSB_TOP_SYSSMAGCCTRL_CTCALEN__W 1
+#define VSB_TOP_SYSSMAGCCTRL_CTCALEN__M 0x2
+#define VSB_TOP_SYSSMAGCCTRL_CTCALEN__PRE 0x0
+
+#define VSB_TOP_SYSSMAGCCTRL_STARTTRN__B 2
+#define VSB_TOP_SYSSMAGCCTRL_STARTTRN__W 1
+#define VSB_TOP_SYSSMAGCCTRL_STARTTRN__M 0x4
+#define VSB_TOP_SYSSMAGCCTRL_STARTTRN__PRE 0x0
+
+#define VSB_TOP_SYSSMAGCCTRL_RSTFRMSYNCDET__B 3
+#define VSB_TOP_SYSSMAGCCTRL_RSTFRMSYNCDET__W 1
+#define VSB_TOP_SYSSMAGCCTRL_RSTFRMSYNCDET__M 0x8
+#define VSB_TOP_SYSSMAGCCTRL_RSTFRMSYNCDET__PRE 0x8
+
+#define VSB_TOP_SYSSMAGCCTRL_RSTCYDET__B 4
+#define VSB_TOP_SYSSMAGCCTRL_RSTCYDET__W 1
+#define VSB_TOP_SYSSMAGCCTRL_RSTCYDET__M 0x10
+#define VSB_TOP_SYSSMAGCCTRL_RSTCYDET__PRE 0x10
+
+#define VSB_TOP_SYSSMAGCCTRL_RSTDCRMV__B 5
+#define VSB_TOP_SYSSMAGCCTRL_RSTDCRMV__W 1
+#define VSB_TOP_SYSSMAGCCTRL_RSTDCRMV__M 0x20
+#define VSB_TOP_SYSSMAGCCTRL_RSTDCRMV__PRE 0x20
+
+#define VSB_TOP_SYSSMAGCCTRL_RSTEQSIG__B 6
+#define VSB_TOP_SYSSMAGCCTRL_RSTEQSIG__W 1
+#define VSB_TOP_SYSSMAGCCTRL_RSTEQSIG__M 0x40
+#define VSB_TOP_SYSSMAGCCTRL_RSTEQSIG__PRE 0x40
+
+#define VSB_TOP_SYSSMAGCCTRL_CKFRZ__B 7
+#define VSB_TOP_SYSSMAGCCTRL_CKFRZ__W 1
+#define VSB_TOP_SYSSMAGCCTRL_CKFRZ__M 0x80
+#define VSB_TOP_SYSSMAGCCTRL_CKFRZ__PRE 0x80
+
+#define VSB_TOP_SYSSMAGCCTRL_CKBWSW__B 8
+#define VSB_TOP_SYSSMAGCCTRL_CKBWSW__W 1
+#define VSB_TOP_SYSSMAGCCTRL_CKBWSW__M 0x100
+#define VSB_TOP_SYSSMAGCCTRL_CKBWSW__PRE 0x0
+
+#define VSB_TOP_SYSSMAGCCTRL_NCOBWSW__B 9
+#define VSB_TOP_SYSSMAGCCTRL_NCOBWSW__W 1
+#define VSB_TOP_SYSSMAGCCTRL_NCOBWSW__M 0x200
+#define VSB_TOP_SYSSMAGCCTRL_NCOBWSW__PRE 0x0
+
+#define VSB_TOP_SYSSMAGCCTRL_NCOTIMEOUTCNTEN__B 10
+#define VSB_TOP_SYSSMAGCCTRL_NCOTIMEOUTCNTEN__W 1
+#define VSB_TOP_SYSSMAGCCTRL_NCOTIMEOUTCNTEN__M 0x400
+#define VSB_TOP_SYSSMAGCCTRL_NCOTIMEOUTCNTEN__PRE 0x0
+
+#define VSB_TOP_SYSSMCTCTRL__A 0x1C10037
+#define VSB_TOP_SYSSMCTCTRL__W 11
+#define VSB_TOP_SYSSMCTCTRL__M 0x7FF
+#define VSB_TOP_SYSSMCTCTRL__PRE 0x4A
+
+#define VSB_TOP_SYSSMCTCTRL_RSTCTCAL__B 0
+#define VSB_TOP_SYSSMCTCTRL_RSTCTCAL__W 1
+#define VSB_TOP_SYSSMCTCTRL_RSTCTCAL__M 0x1
+#define VSB_TOP_SYSSMCTCTRL_RSTCTCAL__PRE 0x0
+
+#define VSB_TOP_SYSSMCTCTRL_CTCALEN__B 1
+#define VSB_TOP_SYSSMCTCTRL_CTCALEN__W 1
+#define VSB_TOP_SYSSMCTCTRL_CTCALEN__M 0x2
+#define VSB_TOP_SYSSMCTCTRL_CTCALEN__PRE 0x2
+
+#define VSB_TOP_SYSSMCTCTRL_STARTTRN__B 2
+#define VSB_TOP_SYSSMCTCTRL_STARTTRN__W 1
+#define VSB_TOP_SYSSMCTCTRL_STARTTRN__M 0x4
+#define VSB_TOP_SYSSMCTCTRL_STARTTRN__PRE 0x0
+
+#define VSB_TOP_SYSSMCTCTRL_RSTFRMSYNCDET__B 3
+#define VSB_TOP_SYSSMCTCTRL_RSTFRMSYNCDET__W 1
+#define VSB_TOP_SYSSMCTCTRL_RSTFRMSYNCDET__M 0x8
+#define VSB_TOP_SYSSMCTCTRL_RSTFRMSYNCDET__PRE 0x8
+
+#define VSB_TOP_SYSSMCTCTRL_RSTCYDET__B 4
+#define VSB_TOP_SYSSMCTCTRL_RSTCYDET__W 1
+#define VSB_TOP_SYSSMCTCTRL_RSTCYDET__M 0x10
+#define VSB_TOP_SYSSMCTCTRL_RSTCYDET__PRE 0x0
+
+#define VSB_TOP_SYSSMCTCTRL_RSTDCRMV__B 5
+#define VSB_TOP_SYSSMCTCTRL_RSTDCRMV__W 1
+#define VSB_TOP_SYSSMCTCTRL_RSTDCRMV__M 0x20
+#define VSB_TOP_SYSSMCTCTRL_RSTDCRMV__PRE 0x0
+
+#define VSB_TOP_SYSSMCTCTRL_RSTEQSIG__B 6
+#define VSB_TOP_SYSSMCTCTRL_RSTEQSIG__W 1
+#define VSB_TOP_SYSSMCTCTRL_RSTEQSIG__M 0x40
+#define VSB_TOP_SYSSMCTCTRL_RSTEQSIG__PRE 0x40
+
+#define VSB_TOP_SYSSMCTCTRL_CKFRZ__B 7
+#define VSB_TOP_SYSSMCTCTRL_CKFRZ__W 1
+#define VSB_TOP_SYSSMCTCTRL_CKFRZ__M 0x80
+#define VSB_TOP_SYSSMCTCTRL_CKFRZ__PRE 0x0
+
+#define VSB_TOP_SYSSMCTCTRL_CKBWSW__B 8
+#define VSB_TOP_SYSSMCTCTRL_CKBWSW__W 1
+#define VSB_TOP_SYSSMCTCTRL_CKBWSW__M 0x100
+#define VSB_TOP_SYSSMCTCTRL_CKBWSW__PRE 0x0
+
+#define VSB_TOP_SYSSMCTCTRL_NCOBWSW__B 9
+#define VSB_TOP_SYSSMCTCTRL_NCOBWSW__W 1
+#define VSB_TOP_SYSSMCTCTRL_NCOBWSW__M 0x200
+#define VSB_TOP_SYSSMCTCTRL_NCOBWSW__PRE 0x0
+
+#define VSB_TOP_SYSSMCTCTRL_NCOTIMEOUTCNTEN__B 10
+#define VSB_TOP_SYSSMCTCTRL_NCOTIMEOUTCNTEN__W 1
+#define VSB_TOP_SYSSMCTCTRL_NCOTIMEOUTCNTEN__M 0x400
+#define VSB_TOP_SYSSMCTCTRL_NCOTIMEOUTCNTEN__PRE 0x0
+
+#define VSB_TOP_EQCTRL__A 0x1C10038
+#define VSB_TOP_EQCTRL__W 10
+#define VSB_TOP_EQCTRL__M 0x3FF
+#define VSB_TOP_EQCTRL__PRE 0x6
+
+#define VSB_TOP_EQCTRL_STASSIGNEN__B 0
+#define VSB_TOP_EQCTRL_STASSIGNEN__W 1
+#define VSB_TOP_EQCTRL_STASSIGNEN__M 0x1
+#define VSB_TOP_EQCTRL_STASSIGNEN__PRE 0x0
+
+#define VSB_TOP_EQCTRL_ORCANCMAEN__B 1
+#define VSB_TOP_EQCTRL_ORCANCMAEN__W 1
+#define VSB_TOP_EQCTRL_ORCANCMAEN__M 0x2
+#define VSB_TOP_EQCTRL_ORCANCMAEN__PRE 0x2
+
+#define VSB_TOP_EQCTRL_ODAGCGO__B 2
+#define VSB_TOP_EQCTRL_ODAGCGO__W 1
+#define VSB_TOP_EQCTRL_ODAGCGO__M 0x4
+#define VSB_TOP_EQCTRL_ODAGCGO__PRE 0x4
+
+#define VSB_TOP_EQCTRL_OPTGAIN__B 3
+#define VSB_TOP_EQCTRL_OPTGAIN__W 3
+#define VSB_TOP_EQCTRL_OPTGAIN__M 0x38
+#define VSB_TOP_EQCTRL_OPTGAIN__PRE 0x0
+
+#define VSB_TOP_EQCTRL_TAPRAMWRTEN__B 6
+#define VSB_TOP_EQCTRL_TAPRAMWRTEN__W 1
+#define VSB_TOP_EQCTRL_TAPRAMWRTEN__M 0x40
+#define VSB_TOP_EQCTRL_TAPRAMWRTEN__PRE 0x0
+
+#define VSB_TOP_EQCTRL_CMAGAIN__B 7
+#define VSB_TOP_EQCTRL_CMAGAIN__W 3
+#define VSB_TOP_EQCTRL_CMAGAIN__M 0x380
+#define VSB_TOP_EQCTRL_CMAGAIN__PRE 0x0
+
+#define VSB_TOP_PREEQAGCCTRL__A 0x1C10039
+#define VSB_TOP_PREEQAGCCTRL__W 5
+#define VSB_TOP_PREEQAGCCTRL__M 0x1F
+#define VSB_TOP_PREEQAGCCTRL__PRE 0x10
+
+#define VSB_TOP_PREEQAGCCTRL_PREEQAGCBWSEL__B 0
+#define VSB_TOP_PREEQAGCCTRL_PREEQAGCBWSEL__W 4
+#define VSB_TOP_PREEQAGCCTRL_PREEQAGCBWSEL__M 0xF
+#define VSB_TOP_PREEQAGCCTRL_PREEQAGCBWSEL__PRE 0x0
+
+#define VSB_TOP_PREEQAGCCTRL_PREEQAGCFRZ__B 4
+#define VSB_TOP_PREEQAGCCTRL_PREEQAGCFRZ__W 1
+#define VSB_TOP_PREEQAGCCTRL_PREEQAGCFRZ__M 0x10
+#define VSB_TOP_PREEQAGCCTRL_PREEQAGCFRZ__PRE 0x10
+
+#define VSB_TOP_PREEQAGCPWRREFLVLHI__A 0x1C1003A
+#define VSB_TOP_PREEQAGCPWRREFLVLHI__W 8
+#define VSB_TOP_PREEQAGCPWRREFLVLHI__M 0xFF
+#define VSB_TOP_PREEQAGCPWRREFLVLHI__PRE 0x0
+
+#define VSB_TOP_PREEQAGCPWRREFLVLLO__A 0x1C1003B
+#define VSB_TOP_PREEQAGCPWRREFLVLLO__W 16
+#define VSB_TOP_PREEQAGCPWRREFLVLLO__M 0xFFFF
+#define VSB_TOP_PREEQAGCPWRREFLVLLO__PRE 0x1D66
+
+#define VSB_TOP_CORINGSEL__A 0x1C1003C
+#define VSB_TOP_CORINGSEL__W 8
+#define VSB_TOP_CORINGSEL__M 0xFF
+#define VSB_TOP_CORINGSEL__PRE 0x3
+#define VSB_TOP_BEDETCTRL__A 0x1C1003D
+#define VSB_TOP_BEDETCTRL__W 9
+#define VSB_TOP_BEDETCTRL__M 0x1FF
+#define VSB_TOP_BEDETCTRL__PRE 0x145
+
+#define VSB_TOP_BEDETCTRL_MIXRATIO__B 0
+#define VSB_TOP_BEDETCTRL_MIXRATIO__W 3
+#define VSB_TOP_BEDETCTRL_MIXRATIO__M 0x7
+#define VSB_TOP_BEDETCTRL_MIXRATIO__PRE 0x5
+
+#define VSB_TOP_BEDETCTRL_CYOFFSEL__B 3
+#define VSB_TOP_BEDETCTRL_CYOFFSEL__W 1
+#define VSB_TOP_BEDETCTRL_CYOFFSEL__M 0x8
+#define VSB_TOP_BEDETCTRL_CYOFFSEL__PRE 0x0
+
+#define VSB_TOP_BEDETCTRL_DATAOFFSEL__B 4
+#define VSB_TOP_BEDETCTRL_DATAOFFSEL__W 1
+#define VSB_TOP_BEDETCTRL_DATAOFFSEL__M 0x10
+#define VSB_TOP_BEDETCTRL_DATAOFFSEL__PRE 0x0
+
+#define VSB_TOP_BEDETCTRL_BYPASS_DSQ__B 5
+#define VSB_TOP_BEDETCTRL_BYPASS_DSQ__W 1
+#define VSB_TOP_BEDETCTRL_BYPASS_DSQ__M 0x20
+#define VSB_TOP_BEDETCTRL_BYPASS_DSQ__PRE 0x0
+
+#define VSB_TOP_BEDETCTRL_BYPASS_PSQ__B 6
+#define VSB_TOP_BEDETCTRL_BYPASS_PSQ__W 1
+#define VSB_TOP_BEDETCTRL_BYPASS_PSQ__M 0x40
+#define VSB_TOP_BEDETCTRL_BYPASS_PSQ__PRE 0x40
+
+#define VSB_TOP_BEDETCTRL_BYPASS_CSQ__B 7
+#define VSB_TOP_BEDETCTRL_BYPASS_CSQ__W 1
+#define VSB_TOP_BEDETCTRL_BYPASS_CSQ__M 0x80
+#define VSB_TOP_BEDETCTRL_BYPASS_CSQ__PRE 0x0
+
+#define VSB_TOP_BEDETCTRL_BYPASS_DMP__B 8
+#define VSB_TOP_BEDETCTRL_BYPASS_DMP__W 1
+#define VSB_TOP_BEDETCTRL_BYPASS_DMP__M 0x100
+#define VSB_TOP_BEDETCTRL_BYPASS_DMP__PRE 0x100
+
+#define VSB_TOP_LBAGCREFLVL__A 0x1C1003E
+#define VSB_TOP_LBAGCREFLVL__W 12
+#define VSB_TOP_LBAGCREFLVL__M 0xFFF
+#define VSB_TOP_LBAGCREFLVL__PRE 0x200
+
+#define VSB_TOP_UBAGCREFLVL__A 0x1C1003F
+#define VSB_TOP_UBAGCREFLVL__W 12
+#define VSB_TOP_UBAGCREFLVL__M 0xFFF
+#define VSB_TOP_UBAGCREFLVL__PRE 0x400
+
+#define VSB_TOP_NOTCH1_BIN_NUM__A 0x1C10040
+#define VSB_TOP_NOTCH1_BIN_NUM__W 11
+#define VSB_TOP_NOTCH1_BIN_NUM__M 0x7FF
+#define VSB_TOP_NOTCH1_BIN_NUM__PRE 0xB2
+
+#define VSB_TOP_NOTCH2_BIN_NUM__A 0x1C10041
+#define VSB_TOP_NOTCH2_BIN_NUM__W 11
+#define VSB_TOP_NOTCH2_BIN_NUM__M 0x7FF
+#define VSB_TOP_NOTCH2_BIN_NUM__PRE 0x40B
+
+#define VSB_TOP_NOTCH_START_BIN_NUM__A 0x1C10042
+#define VSB_TOP_NOTCH_START_BIN_NUM__W 11
+#define VSB_TOP_NOTCH_START_BIN_NUM__M 0x7FF
+#define VSB_TOP_NOTCH_START_BIN_NUM__PRE 0x7C0
+
+#define VSB_TOP_NOTCH_STOP_BIN_NUM__A 0x1C10043
+#define VSB_TOP_NOTCH_STOP_BIN_NUM__W 11
+#define VSB_TOP_NOTCH_STOP_BIN_NUM__M 0x7FF
+#define VSB_TOP_NOTCH_STOP_BIN_NUM__PRE 0x43F
+
+#define VSB_TOP_NOTCH_TEST_DURATION__A 0x1C10044
+#define VSB_TOP_NOTCH_TEST_DURATION__W 11
+#define VSB_TOP_NOTCH_TEST_DURATION__M 0x7FF
+#define VSB_TOP_NOTCH_TEST_DURATION__PRE 0x7FF
+
+#define VSB_TOP_RESULT_LARGE_PEAK_BIN__A 0x1C10045
+#define VSB_TOP_RESULT_LARGE_PEAK_BIN__W 11
+#define VSB_TOP_RESULT_LARGE_PEAK_BIN__M 0x7FF
+#define VSB_TOP_RESULT_LARGE_PEAK_BIN__PRE 0x0
+
+#define VSB_TOP_RESULT_LARGE_PEAK_VALUE__A 0x1C10046
+#define VSB_TOP_RESULT_LARGE_PEAK_VALUE__W 16
+#define VSB_TOP_RESULT_LARGE_PEAK_VALUE__M 0xFFFF
+#define VSB_TOP_RESULT_LARGE_PEAK_VALUE__PRE 0x0
+
+#define VSB_TOP_RESULT_SMALL_PEAK_BIN__A 0x1C10047
+#define VSB_TOP_RESULT_SMALL_PEAK_BIN__W 11
+#define VSB_TOP_RESULT_SMALL_PEAK_BIN__M 0x7FF
+#define VSB_TOP_RESULT_SMALL_PEAK_BIN__PRE 0x0
+
+#define VSB_TOP_RESULT_SMALL_PEAK_VALUE__A 0x1C10048
+#define VSB_TOP_RESULT_SMALL_PEAK_VALUE__W 16
+#define VSB_TOP_RESULT_SMALL_PEAK_VALUE__M 0xFFFF
+#define VSB_TOP_RESULT_SMALL_PEAK_VALUE__PRE 0x0
+
+#define VSB_TOP_NOTCH_SWEEP_RUNNING__A 0x1C10049
+#define VSB_TOP_NOTCH_SWEEP_RUNNING__W 1
+#define VSB_TOP_NOTCH_SWEEP_RUNNING__M 0x1
+#define VSB_TOP_NOTCH_SWEEP_RUNNING__PRE 0x0
+
+#define VSB_TOP_PREEQDAGCRATIO__A 0x1C1004A
+#define VSB_TOP_PREEQDAGCRATIO__W 13
+#define VSB_TOP_PREEQDAGCRATIO__M 0x1FFF
+#define VSB_TOP_PREEQDAGCRATIO__PRE 0x0
+#define VSB_TOP_AGC_TRUNCCTRL__A 0x1C1004B
+#define VSB_TOP_AGC_TRUNCCTRL__W 4
+#define VSB_TOP_AGC_TRUNCCTRL__M 0xF
+#define VSB_TOP_AGC_TRUNCCTRL__PRE 0xF
+
+#define VSB_TOP_AGC_TRUNCCTRL_TRUNC_LSB__B 0
+#define VSB_TOP_AGC_TRUNCCTRL_TRUNC_LSB__W 2
+#define VSB_TOP_AGC_TRUNCCTRL_TRUNC_LSB__M 0x3
+#define VSB_TOP_AGC_TRUNCCTRL_TRUNC_LSB__PRE 0x3
+
+#define VSB_TOP_AGC_TRUNCCTRL_TRUNC_12N__B 2
+#define VSB_TOP_AGC_TRUNCCTRL_TRUNC_12N__W 1
+#define VSB_TOP_AGC_TRUNCCTRL_TRUNC_12N__M 0x4
+#define VSB_TOP_AGC_TRUNCCTRL_TRUNC_12N__PRE 0x4
+
+#define VSB_TOP_AGC_TRUNCCTRL_TRUNC_EN__B 3
+#define VSB_TOP_AGC_TRUNCCTRL_TRUNC_EN__W 1
+#define VSB_TOP_AGC_TRUNCCTRL_TRUNC_EN__M 0x8
+#define VSB_TOP_AGC_TRUNCCTRL_TRUNC_EN__PRE 0x8
+
+#define VSB_TOP_BEAGC_DEADZONEINIT__A 0x1C1004C
+#define VSB_TOP_BEAGC_DEADZONEINIT__W 8
+#define VSB_TOP_BEAGC_DEADZONEINIT__M 0xFF
+#define VSB_TOP_BEAGC_DEADZONEINIT__PRE 0x50
+
+#define VSB_TOP_BEAGC_REFLEVEL__A 0x1C1004D
+#define VSB_TOP_BEAGC_REFLEVEL__W 9
+#define VSB_TOP_BEAGC_REFLEVEL__M 0x1FF
+#define VSB_TOP_BEAGC_REFLEVEL__PRE 0xAE
+
+#define VSB_TOP_BEAGC_GAINSHIFT__A 0x1C1004E
+#define VSB_TOP_BEAGC_GAINSHIFT__W 3
+#define VSB_TOP_BEAGC_GAINSHIFT__M 0x7
+#define VSB_TOP_BEAGC_GAINSHIFT__PRE 0x3
+
+#define VSB_TOP_BEAGC_REGINIT__A 0x1C1004F
+#define VSB_TOP_BEAGC_REGINIT__W 15
+#define VSB_TOP_BEAGC_REGINIT__M 0x7FFF
+#define VSB_TOP_BEAGC_REGINIT__PRE 0x40
+
+#define VSB_TOP_BEAGC_REGINIT_BEAGC_RST__B 14
+#define VSB_TOP_BEAGC_REGINIT_BEAGC_RST__W 1
+#define VSB_TOP_BEAGC_REGINIT_BEAGC_RST__M 0x4000
+#define VSB_TOP_BEAGC_REGINIT_BEAGC_RST__PRE 0x0
+
+#define VSB_TOP_BEAGC_SCALE__A 0x1C10050
+#define VSB_TOP_BEAGC_SCALE__W 14
+#define VSB_TOP_BEAGC_SCALE__M 0x3FFF
+#define VSB_TOP_BEAGC_SCALE__PRE 0x0
+
+#define VSB_TOP_CFAGC_DEADZONEINIT__A 0x1C10051
+#define VSB_TOP_CFAGC_DEADZONEINIT__W 8
+#define VSB_TOP_CFAGC_DEADZONEINIT__M 0xFF
+#define VSB_TOP_CFAGC_DEADZONEINIT__PRE 0x50
+
+#define VSB_TOP_CFAGC_REFLEVEL__A 0x1C10052
+#define VSB_TOP_CFAGC_REFLEVEL__W 9
+#define VSB_TOP_CFAGC_REFLEVEL__M 0x1FF
+#define VSB_TOP_CFAGC_REFLEVEL__PRE 0xAE
+
+#define VSB_TOP_CFAGC_GAINSHIFT__A 0x1C10053
+#define VSB_TOP_CFAGC_GAINSHIFT__W 3
+#define VSB_TOP_CFAGC_GAINSHIFT__M 0x7
+#define VSB_TOP_CFAGC_GAINSHIFT__PRE 0x3
+
+#define VSB_TOP_CFAGC_REGINIT__A 0x1C10054
+#define VSB_TOP_CFAGC_REGINIT__W 15
+#define VSB_TOP_CFAGC_REGINIT__M 0x7FFF
+#define VSB_TOP_CFAGC_REGINIT__PRE 0x80
+
+#define VSB_TOP_CFAGC_REGINIT_CFAGC_RST__B 14
+#define VSB_TOP_CFAGC_REGINIT_CFAGC_RST__W 1
+#define VSB_TOP_CFAGC_REGINIT_CFAGC_RST__M 0x4000
+#define VSB_TOP_CFAGC_REGINIT_CFAGC_RST__PRE 0x0
+
+#define VSB_TOP_CFAGC_SCALE__A 0x1C10055
+#define VSB_TOP_CFAGC_SCALE__W 14
+#define VSB_TOP_CFAGC_SCALE__M 0x3FFF
+#define VSB_TOP_CFAGC_SCALE__PRE 0x0
+
+#define VSB_TOP_CKTRKONCTL__A 0x1C10056
+#define VSB_TOP_CKTRKONCTL__W 2
+#define VSB_TOP_CKTRKONCTL__M 0x3
+#define VSB_TOP_CKTRKONCTL__PRE 0x0
+
+#define VSB_TOP_CYTRKONCTL__A 0x1C10057
+#define VSB_TOP_CYTRKONCTL__W 2
+#define VSB_TOP_CYTRKONCTL__M 0x3
+#define VSB_TOP_CYTRKONCTL__PRE 0x0
+
+#define VSB_TOP_PTONCTL__A 0x1C10058
+#define VSB_TOP_PTONCTL__W 2
+#define VSB_TOP_PTONCTL__M 0x3
+#define VSB_TOP_PTONCTL__PRE 0x0
+
+#define VSB_TOP_NOTCH_SCALE_1__A 0x1C10059
+#define VSB_TOP_NOTCH_SCALE_1__W 8
+#define VSB_TOP_NOTCH_SCALE_1__M 0xFF
+#define VSB_TOP_NOTCH_SCALE_1__PRE 0xA
+
+#define VSB_TOP_NOTCH_SCALE_2__A 0x1C1005A
+#define VSB_TOP_NOTCH_SCALE_2__W 8
+#define VSB_TOP_NOTCH_SCALE_2__M 0xFF
+#define VSB_TOP_NOTCH_SCALE_2__PRE 0xA
+
+#define VSB_TOP_FIRSTLARGFFETAP__A 0x1C1005B
+#define VSB_TOP_FIRSTLARGFFETAP__W 12
+#define VSB_TOP_FIRSTLARGFFETAP__M 0xFFF
+#define VSB_TOP_FIRSTLARGFFETAP__PRE 0x0
+
+#define VSB_TOP_FIRSTLARGFFETAPADDR__A 0x1C1005C
+#define VSB_TOP_FIRSTLARGFFETAPADDR__W 11
+#define VSB_TOP_FIRSTLARGFFETAPADDR__M 0x7FF
+#define VSB_TOP_FIRSTLARGFFETAPADDR__PRE 0x0
+
+#define VSB_TOP_SECONDLARGFFETAP__A 0x1C1005D
+#define VSB_TOP_SECONDLARGFFETAP__W 12
+#define VSB_TOP_SECONDLARGFFETAP__M 0xFFF
+#define VSB_TOP_SECONDLARGFFETAP__PRE 0x0
+
+#define VSB_TOP_SECONDLARGFFETAPADDR__A 0x1C1005E
+#define VSB_TOP_SECONDLARGFFETAPADDR__W 11
+#define VSB_TOP_SECONDLARGFFETAPADDR__M 0x7FF
+#define VSB_TOP_SECONDLARGFFETAPADDR__PRE 0x0
+
+#define VSB_TOP_FIRSTLARGDFETAP__A 0x1C1005F
+#define VSB_TOP_FIRSTLARGDFETAP__W 12
+#define VSB_TOP_FIRSTLARGDFETAP__M 0xFFF
+#define VSB_TOP_FIRSTLARGDFETAP__PRE 0x0
+
+#define VSB_TOP_FIRSTLARGDFETAPADDR__A 0x1C10060
+#define VSB_TOP_FIRSTLARGDFETAPADDR__W 11
+#define VSB_TOP_FIRSTLARGDFETAPADDR__M 0x7FF
+#define VSB_TOP_FIRSTLARGDFETAPADDR__PRE 0x0
+
+#define VSB_TOP_SECONDLARGDFETAP__A 0x1C10061
+#define VSB_TOP_SECONDLARGDFETAP__W 12
+#define VSB_TOP_SECONDLARGDFETAP__M 0xFFF
+#define VSB_TOP_SECONDLARGDFETAP__PRE 0x0
+
+#define VSB_TOP_SECONDLARGDFETAPADDR__A 0x1C10062
+#define VSB_TOP_SECONDLARGDFETAPADDR__W 11
+#define VSB_TOP_SECONDLARGDFETAPADDR__M 0x7FF
+#define VSB_TOP_SECONDLARGDFETAPADDR__PRE 0x0
+
+#define VSB_TOP_PARAOWDBUS__A 0x1C10063
+#define VSB_TOP_PARAOWDBUS__W 12
+#define VSB_TOP_PARAOWDBUS__M 0xFFF
+#define VSB_TOP_PARAOWDBUS__PRE 0x0
+#define VSB_TOP_PARAOWCTRL__A 0x1C10064
+#define VSB_TOP_PARAOWCTRL__W 7
+#define VSB_TOP_PARAOWCTRL__M 0x7F
+#define VSB_TOP_PARAOWCTRL__PRE 0x0
+
+#define VSB_TOP_PARAOWCTRL_PARAOWABUS__B 0
+#define VSB_TOP_PARAOWCTRL_PARAOWABUS__W 6
+#define VSB_TOP_PARAOWCTRL_PARAOWABUS__M 0x3F
+#define VSB_TOP_PARAOWCTRL_PARAOWABUS__PRE 0x0
+
+#define VSB_TOP_PARAOWCTRL_PARAOWEN__B 6
+#define VSB_TOP_PARAOWCTRL_PARAOWEN__W 1
+#define VSB_TOP_PARAOWCTRL_PARAOWEN__M 0x40
+#define VSB_TOP_PARAOWCTRL_PARAOWEN__PRE 0x0
+
+#define VSB_TOP_CURRENTSEGLOCAT__A 0x1C10065
+#define VSB_TOP_CURRENTSEGLOCAT__W 10
+#define VSB_TOP_CURRENTSEGLOCAT__M 0x3FF
+#define VSB_TOP_CURRENTSEGLOCAT__PRE 0x0
+
+#define VSB_TOP_MEASUREMENT_PERIOD__A 0x1C10066
+#define VSB_TOP_MEASUREMENT_PERIOD__W 16
+#define VSB_TOP_MEASUREMENT_PERIOD__M 0xFFFF
+#define VSB_TOP_MEASUREMENT_PERIOD__PRE 0x0
+
+#define VSB_TOP_NR_SYM_ERRS__A 0x1C10067
+#define VSB_TOP_NR_SYM_ERRS__W 16
+#define VSB_TOP_NR_SYM_ERRS__M 0xFFFF
+#define VSB_TOP_NR_SYM_ERRS__PRE 0xFFFF
+
+#define VSB_TOP_ERR_ENERGY_L__A 0x1C10068
+#define VSB_TOP_ERR_ENERGY_L__W 16
+#define VSB_TOP_ERR_ENERGY_L__M 0xFFFF
+#define VSB_TOP_ERR_ENERGY_L__PRE 0xFFFF
+
+#define VSB_TOP_ERR_ENERGY_H__A 0x1C10069
+#define VSB_TOP_ERR_ENERGY_H__W 16
+#define VSB_TOP_ERR_ENERGY_H__M 0xFFFF
+#define VSB_TOP_ERR_ENERGY_H__PRE 0xFFFF
+
+#define VSB_TOP_SLICER_SEL_8LEV__A 0x1C1006A
+#define VSB_TOP_SLICER_SEL_8LEV__W 1
+#define VSB_TOP_SLICER_SEL_8LEV__M 0x1
+#define VSB_TOP_SLICER_SEL_8LEV__PRE 0x1
+
+#define VSB_TOP_BNFIELD__A 0x1C1006B
+#define VSB_TOP_BNFIELD__W 3
+#define VSB_TOP_BNFIELD__M 0x7
+#define VSB_TOP_BNFIELD__PRE 0x3
+
+#define VSB_TOP_CLPLASTNUM__A 0x1C1006C
+#define VSB_TOP_CLPLASTNUM__W 8
+#define VSB_TOP_CLPLASTNUM__M 0xFF
+#define VSB_TOP_CLPLASTNUM__PRE 0x0
+
+#define VSB_TOP_BNSQERR__A 0x1C1006D
+#define VSB_TOP_BNSQERR__W 16
+#define VSB_TOP_BNSQERR__M 0xFFFF
+#define VSB_TOP_BNSQERR__PRE 0x1AD
+
+#define VSB_TOP_BNTHRESH__A 0x1C1006E
+#define VSB_TOP_BNTHRESH__W 9
+#define VSB_TOP_BNTHRESH__M 0x1FF
+#define VSB_TOP_BNTHRESH__PRE 0x120
+
+#define VSB_TOP_BNCLPNUM__A 0x1C1006F
+#define VSB_TOP_BNCLPNUM__W 16
+#define VSB_TOP_BNCLPNUM__M 0xFFFF
+#define VSB_TOP_BNCLPNUM__PRE 0x0
+#define VSB_TOP_PHASELOCKCTRL__A 0x1C10070
+#define VSB_TOP_PHASELOCKCTRL__W 7
+#define VSB_TOP_PHASELOCKCTRL__M 0x7F
+#define VSB_TOP_PHASELOCKCTRL__PRE 0x0
+
+#define VSB_TOP_PHASELOCKCTRL_DFORCEPOLARITY__B 0
+#define VSB_TOP_PHASELOCKCTRL_DFORCEPOLARITY__W 1
+#define VSB_TOP_PHASELOCKCTRL_DFORCEPOLARITY__M 0x1
+#define VSB_TOP_PHASELOCKCTRL_DFORCEPOLARITY__PRE 0x0
+
+#define VSB_TOP_PHASELOCKCTRL_DFORCEPLL__B 1
+#define VSB_TOP_PHASELOCKCTRL_DFORCEPLL__W 1
+#define VSB_TOP_PHASELOCKCTRL_DFORCEPLL__M 0x2
+#define VSB_TOP_PHASELOCKCTRL_DFORCEPLL__PRE 0x0
+
+#define VSB_TOP_PHASELOCKCTRL_PFORCEPOLARITY__B 2
+#define VSB_TOP_PHASELOCKCTRL_PFORCEPOLARITY__W 1
+#define VSB_TOP_PHASELOCKCTRL_PFORCEPOLARITY__M 0x4
+#define VSB_TOP_PHASELOCKCTRL_PFORCEPOLARITY__PRE 0x0
+
+#define VSB_TOP_PHASELOCKCTRL_PFORCEPLL__B 3
+#define VSB_TOP_PHASELOCKCTRL_PFORCEPLL__W 1
+#define VSB_TOP_PHASELOCKCTRL_PFORCEPLL__M 0x8
+#define VSB_TOP_PHASELOCKCTRL_PFORCEPLL__PRE 0x0
+
+#define VSB_TOP_PHASELOCKCTRL_CFORCEPOLARITY__B 4
+#define VSB_TOP_PHASELOCKCTRL_CFORCEPOLARITY__W 1
+#define VSB_TOP_PHASELOCKCTRL_CFORCEPOLARITY__M 0x10
+#define VSB_TOP_PHASELOCKCTRL_CFORCEPOLARITY__PRE 0x0
+
+#define VSB_TOP_PHASELOCKCTRL_CFORCEPLL__B 5
+#define VSB_TOP_PHASELOCKCTRL_CFORCEPLL__W 1
+#define VSB_TOP_PHASELOCKCTRL_CFORCEPLL__M 0x20
+#define VSB_TOP_PHASELOCKCTRL_CFORCEPLL__PRE 0x0
+
+#define VSB_TOP_PHASELOCKCTRL_IQSWITCH__B 6
+#define VSB_TOP_PHASELOCKCTRL_IQSWITCH__W 1
+#define VSB_TOP_PHASELOCKCTRL_IQSWITCH__M 0x40
+#define VSB_TOP_PHASELOCKCTRL_IQSWITCH__PRE 0x0
+
+#define VSB_TOP_DLOCKACCUM__A 0x1C10071
+#define VSB_TOP_DLOCKACCUM__W 16
+#define VSB_TOP_DLOCKACCUM__M 0xFFFF
+#define VSB_TOP_DLOCKACCUM__PRE 0x0
+
+#define VSB_TOP_PLOCKACCUM__A 0x1C10072
+#define VSB_TOP_PLOCKACCUM__W 16
+#define VSB_TOP_PLOCKACCUM__M 0xFFFF
+#define VSB_TOP_PLOCKACCUM__PRE 0x0
+
+#define VSB_TOP_CLOCKACCUM__A 0x1C10073
+#define VSB_TOP_CLOCKACCUM__W 16
+#define VSB_TOP_CLOCKACCUM__M 0xFFFF
+#define VSB_TOP_CLOCKACCUM__PRE 0x0
+
+#define VSB_TOP_DCRMVACUMI__A 0x1C10074
+#define VSB_TOP_DCRMVACUMI__W 10
+#define VSB_TOP_DCRMVACUMI__M 0x3FF
+#define VSB_TOP_DCRMVACUMI__PRE 0x0
+
+#define VSB_TOP_DCRMVACUMQ__A 0x1C10075
+#define VSB_TOP_DCRMVACUMQ__W 10
+#define VSB_TOP_DCRMVACUMQ__M 0x3FF
+#define VSB_TOP_DCRMVACUMQ__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO1__A 0x1C20000
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO1__W 12
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO1__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO2__A 0x1C20001
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO2__W 12
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO2__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO3__A 0x1C20002
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO3__W 12
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO3__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO4__A 0x1C20003
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO4__W 12
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO4__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO5__A 0x1C20004
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO5__W 12
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO5__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO6__A 0x1C20005
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO6__W 12
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO6__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO7__A 0x1C20006
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO7__W 12
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO7__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO8__A 0x1C20007
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO8__W 12
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO8__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO9__A 0x1C20008
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO9__W 12
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO9__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO10__A 0x1C20009
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO10__W 12
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO10__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO11__A 0x1C2000A
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO11__W 12
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO11__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO12__A 0x1C2000B
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO12__W 12
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO12__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFETRAINLKRATIO12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO1__A 0x1C2000C
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO1__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO1__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO2__A 0x1C2000D
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO2__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO2__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO3__A 0x1C2000E
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO3__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO3__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO4__A 0x1C2000F
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO4__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO4__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO5__A 0x1C20010
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO5__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO5__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO6__A 0x1C20011
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO6__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO6__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO7__A 0x1C20012
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO7__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO7__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO8__A 0x1C20013
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO8__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO8__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO9__A 0x1C20014
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO9__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO9__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO10__A 0x1C20015
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO10__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO10__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO11__A 0x1C20016
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO11__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO11__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO12__A 0x1C20017
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO12__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO12__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1TRAINLKRATIO12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO1__A 0x1C20018
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO1__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO1__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO2__A 0x1C20019
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO2__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO2__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO3__A 0x1C2001A
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO3__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO3__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO4__A 0x1C2001B
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO4__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO4__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO5__A 0x1C2001C
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO5__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO5__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO6__A 0x1C2001D
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO6__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO6__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO7__A 0x1C2001E
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO7__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO7__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO8__A 0x1C2001F
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO8__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO8__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO9__A 0x1C20020
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO9__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO9__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO10__A 0x1C20021
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO10__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO10__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO11__A 0x1C20022
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO11__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO11__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO12__A 0x1C20023
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO12__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO12__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA1DATALKRATIO12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO1__A 0x1C20024
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO1__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO1__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO2__A 0x1C20025
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO2__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO2__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO3__A 0x1C20026
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO3__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO3__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO4__A 0x1C20027
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO4__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO4__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO5__A 0x1C20028
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO5__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO5__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO6__A 0x1C20029
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO6__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO6__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO7__A 0x1C2002A
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO7__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO7__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO8__A 0x1C2002B
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO8__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO8__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO9__A 0x1C2002C
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO9__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO9__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO10__A 0x1C2002D
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO10__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO10__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO11__A 0x1C2002E
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO11__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO11__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO12__A 0x1C2002F
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO12__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO12__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2TRAINLKRATIO12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO1__A 0x1C20030
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO1__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO1__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO2__A 0x1C20031
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO2__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO2__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO3__A 0x1C20032
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO3__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO3__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO4__A 0x1C20033
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO4__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO4__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO5__A 0x1C20034
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO5__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO5__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO6__A 0x1C20035
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO6__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO6__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO7__A 0x1C20036
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO7__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO7__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO8__A 0x1C20037
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO8__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO8__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO9__A 0x1C20038
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO9__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO9__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO10__A 0x1C20039
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO10__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO10__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO11__A 0x1C2003A
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO11__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO11__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO12__A 0x1C2003B
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO12__W 12
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO12__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFERCA2DATALKRATIO12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO1__A 0x1C2003C
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO1__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO1__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO2__A 0x1C2003D
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO2__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO2__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO3__A 0x1C2003E
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO3__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO3__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO4__A 0x1C2003F
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO4__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO4__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO5__A 0x1C20040
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO5__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO5__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO6__A 0x1C20041
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO6__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO6__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO7__A 0x1C20042
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO7__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO7__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO8__A 0x1C20043
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO8__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO8__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO9__A 0x1C20044
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO9__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO9__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO10__A 0x1C20045
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO10__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO10__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO11__A 0x1C20046
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO11__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO11__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO12__A 0x1C20047
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO12__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO12__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1TRAINLKRATIO12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO1__A 0x1C20048
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO1__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO1__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO2__A 0x1C20049
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO2__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO2__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO3__A 0x1C2004A
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO3__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO3__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO4__A 0x1C2004B
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO4__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO4__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO5__A 0x1C2004C
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO5__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO5__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO6__A 0x1C2004D
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO6__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO6__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO7__A 0x1C2004E
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO7__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO7__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO8__A 0x1C2004F
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO8__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO8__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO9__A 0x1C20050
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO9__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO9__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO10__A 0x1C20051
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO10__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO10__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO11__A 0x1C20052
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO11__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO11__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO12__A 0x1C20053
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO12__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO12__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM1DATALKRATIO12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO1__A 0x1C20054
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO1__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO1__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO2__A 0x1C20055
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO2__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO2__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO3__A 0x1C20056
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO3__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO3__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO4__A 0x1C20057
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO4__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO4__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO5__A 0x1C20058
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO5__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO5__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO6__A 0x1C20059
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO6__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO6__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO7__A 0x1C2005A
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO7__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO7__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO8__A 0x1C2005B
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO8__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO8__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO9__A 0x1C2005C
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO9__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO9__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO10__A 0x1C2005D
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO10__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO10__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO11__A 0x1C2005E
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO11__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO11__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO12__A 0x1C2005F
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO12__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO12__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2TRAINLKRATIO12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO1__A 0x1C20060
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO1__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO1__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO2__A 0x1C20061
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO2__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO2__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO3__A 0x1C20062
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO3__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO3__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO4__A 0x1C20063
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO4__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO4__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO5__A 0x1C20064
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO5__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO5__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO6__A 0x1C20065
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO6__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO6__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO7__A 0x1C20066
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO7__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO7__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO8__A 0x1C20067
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO8__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO8__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO9__A 0x1C20068
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO9__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO9__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO10__A 0x1C20069
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO10__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO10__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO11__A 0x1C2006A
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO11__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO11__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO12__A 0x1C2006B
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO12__W 12
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO12__M 0xFFF
+#define VSB_SYSCTRL_RAM0_FFEDDM2DATALKRATIO12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN1__A 0x1C2006C
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN1__W 7
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN1__M 0x7F
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN2__A 0x1C2006D
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN2__W 7
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN2__M 0x7F
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN3__A 0x1C2006E
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN3__W 7
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN3__M 0x7F
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN4__A 0x1C2006F
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN4__W 7
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN4__M 0x7F
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN5__A 0x1C20070
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN5__W 7
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN5__M 0x7F
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN6__A 0x1C20071
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN6__W 7
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN6__M 0x7F
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN7__A 0x1C20072
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN7__W 7
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN7__M 0x7F
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN8__A 0x1C20073
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN8__W 7
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN8__M 0x7F
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN9__A 0x1C20074
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN9__W 7
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN9__M 0x7F
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN10__A 0x1C20075
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN10__W 7
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN10__M 0x7F
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN11__A 0x1C20076
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN11__W 7
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN11__M 0x7F
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN12__A 0x1C20077
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN12__W 7
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN12__M 0x7F
+#define VSB_SYSCTRL_RAM0_FIRTRAINGAIN12__PRE 0x0
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN1__A 0x1C20078
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN1__W 15
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN1__M 0x7FFF
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN1_FIRRCA1TRAINGAIN1__B 0
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN1_FIRRCA1TRAINGAIN1__W 7
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN1_FIRRCA1TRAINGAIN1__M 0x7F
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN1_FIRRCA1TRAINGAIN1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN1_FIRRCA1DATAGAIN1__B 8
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN1_FIRRCA1DATAGAIN1__W 7
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN1_FIRRCA1DATAGAIN1__M 0x7F00
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN1_FIRRCA1DATAGAIN1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN2__A 0x1C20079
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN2__W 15
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN2__M 0x7FFF
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN2_FIRRCA1TRAINGAIN2__B 0
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN2_FIRRCA1TRAINGAIN2__W 7
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN2_FIRRCA1TRAINGAIN2__M 0x7F
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN2_FIRRCA1TRAINGAIN2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN2_FIRRCA1DATAGAIN2__B 8
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN2_FIRRCA1DATAGAIN2__W 7
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN2_FIRRCA1DATAGAIN2__M 0x7F00
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN2_FIRRCA1DATAGAIN2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN3__A 0x1C2007A
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN3__W 15
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN3__M 0x7FFF
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN3_FIRRCA1TRAINGAIN3__B 0
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN3_FIRRCA1TRAINGAIN3__W 7
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN3_FIRRCA1TRAINGAIN3__M 0x7F
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN3_FIRRCA1TRAINGAIN3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN3_FIRRCA1DATAGAIN3__B 8
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN3_FIRRCA1DATAGAIN3__W 7
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN3_FIRRCA1DATAGAIN3__M 0x7F00
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN3_FIRRCA1DATAGAIN3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN4__A 0x1C2007B
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN4__W 15
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN4__M 0x7FFF
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN4_FIRRCA1TRAINGAIN4__B 0
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN4_FIRRCA1TRAINGAIN4__W 7
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN4_FIRRCA1TRAINGAIN4__M 0x7F
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN4_FIRRCA1TRAINGAIN4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN4_FIRRCA1DATAGAIN4__B 8
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN4_FIRRCA1DATAGAIN4__W 7
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN4_FIRRCA1DATAGAIN4__M 0x7F00
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN4_FIRRCA1DATAGAIN4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN5__A 0x1C2007C
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN5__W 15
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN5__M 0x7FFF
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN5_FIRRCA1TRAINGAIN5__B 0
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN5_FIRRCA1TRAINGAIN5__W 7
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN5_FIRRCA1TRAINGAIN5__M 0x7F
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN5_FIRRCA1TRAINGAIN5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN5_FIRRCA1DATAGAIN5__B 8
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN5_FIRRCA1DATAGAIN5__W 7
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN5_FIRRCA1DATAGAIN5__M 0x7F00
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN5_FIRRCA1DATAGAIN5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN6__A 0x1C2007D
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN6__W 15
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN6__M 0x7FFF
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN6_FIRRCA1TRAINGAIN6__B 0
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN6_FIRRCA1TRAINGAIN6__W 7
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN6_FIRRCA1TRAINGAIN6__M 0x7F
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN6_FIRRCA1TRAINGAIN6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN6_FIRRCA1DATAGAIN6__B 8
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN6_FIRRCA1DATAGAIN6__W 7
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN6_FIRRCA1DATAGAIN6__M 0x7F00
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN6_FIRRCA1DATAGAIN6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN7__A 0x1C2007E
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN7__W 15
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN7__M 0x7FFF
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN7_FIRRCA1TRAINGAIN7__B 0
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN7_FIRRCA1TRAINGAIN7__W 7
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN7_FIRRCA1TRAINGAIN7__M 0x7F
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN7_FIRRCA1TRAINGAIN7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN7_FIRRCA1DATAGAIN7__B 8
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN7_FIRRCA1DATAGAIN7__W 7
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN7_FIRRCA1DATAGAIN7__M 0x7F00
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN7_FIRRCA1DATAGAIN7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN8__A 0x1C2007F
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN8__W 15
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN8__M 0x7FFF
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN8_FIRRCA1TRAINGAIN8__B 0
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN8_FIRRCA1TRAINGAIN8__W 7
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN8_FIRRCA1TRAINGAIN8__M 0x7F
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN8_FIRRCA1TRAINGAIN8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN8_FIRRCA1DATAGAIN8__B 8
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN8_FIRRCA1DATAGAIN8__W 7
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN8_FIRRCA1DATAGAIN8__M 0x7F00
+#define VSB_SYSCTRL_RAM0_FIRRCA1GAIN8_FIRRCA1DATAGAIN8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN9__A 0x1C30000
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN9__W 15
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN9__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN9_FIRRCA1TRAINGAIN9__B 0
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN9_FIRRCA1TRAINGAIN9__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN9_FIRRCA1TRAINGAIN9__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN9_FIRRCA1TRAINGAIN9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN9_FIRRCA1DATAGAIN9__B 8
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN9_FIRRCA1DATAGAIN9__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN9_FIRRCA1DATAGAIN9__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN9_FIRRCA1DATAGAIN9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN10__A 0x1C30001
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN10__W 15
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN10__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN10_FIRRCA1TRAINGAIN10__B 0
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN10_FIRRCA1TRAINGAIN10__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN10_FIRRCA1TRAINGAIN10__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN10_FIRRCA1TRAINGAIN10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN10_FIRRCA1DATAGAIN10__B 8
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN10_FIRRCA1DATAGAIN10__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN10_FIRRCA1DATAGAIN10__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN10_FIRRCA1DATAGAIN10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN11__A 0x1C30002
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN11__W 15
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN11__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN11_FIRRCA1TRAINGAIN11__B 0
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN11_FIRRCA1TRAINGAIN11__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN11_FIRRCA1TRAINGAIN11__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN11_FIRRCA1TRAINGAIN11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN11_FIRRCA1DATAGAIN11__B 8
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN11_FIRRCA1DATAGAIN11__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN11_FIRRCA1DATAGAIN11__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN11_FIRRCA1DATAGAIN11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN12__A 0x1C30003
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN12__W 15
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN12__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN12_FIRRCA1TRAINGAIN12__B 0
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN12_FIRRCA1TRAINGAIN12__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN12_FIRRCA1TRAINGAIN12__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN12_FIRRCA1TRAINGAIN12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN12_FIRRCA1DATAGAIN12__B 8
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN12_FIRRCA1DATAGAIN12__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN12_FIRRCA1DATAGAIN12__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRRCA1GAIN12_FIRRCA1DATAGAIN12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN1__A 0x1C30004
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN1__W 15
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN1__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN1_FIRRCA2TRAINGAIN1__B 0
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN1_FIRRCA2TRAINGAIN1__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN1_FIRRCA2TRAINGAIN1__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN1_FIRRCA2TRAINGAIN1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN1_FIRRCA2DATAGAIN1__B 8
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN1_FIRRCA2DATAGAIN1__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN1_FIRRCA2DATAGAIN1__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN1_FIRRCA2DATAGAIN1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN2__A 0x1C30005
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN2__W 15
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN2__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN2_FIRRCA2TRAINGAIN2__B 0
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN2_FIRRCA2TRAINGAIN2__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN2_FIRRCA2TRAINGAIN2__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN2_FIRRCA2TRAINGAIN2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN2_FIRRCA2DATAGAIN2__B 8
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN2_FIRRCA2DATAGAIN2__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN2_FIRRCA2DATAGAIN2__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN2_FIRRCA2DATAGAIN2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN3__A 0x1C30006
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN3__W 15
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN3__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN3_FIRRCA2TRAINGAIN3__B 0
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN3_FIRRCA2TRAINGAIN3__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN3_FIRRCA2TRAINGAIN3__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN3_FIRRCA2TRAINGAIN3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN3_FIRRCA2DATAGAIN3__B 8
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN3_FIRRCA2DATAGAIN3__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN3_FIRRCA2DATAGAIN3__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN3_FIRRCA2DATAGAIN3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN4__A 0x1C30007
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN4__W 15
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN4__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN4_FIRRCA2TRAINGAIN4__B 0
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN4_FIRRCA2TRAINGAIN4__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN4_FIRRCA2TRAINGAIN4__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN4_FIRRCA2TRAINGAIN4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN4_FIRRCA2DATAGAIN4__B 8
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN4_FIRRCA2DATAGAIN4__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN4_FIRRCA2DATAGAIN4__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN4_FIRRCA2DATAGAIN4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN5__A 0x1C30008
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN5__W 15
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN5__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN5_FIRRCA2TRAINGAIN5__B 0
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN5_FIRRCA2TRAINGAIN5__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN5_FIRRCA2TRAINGAIN5__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN5_FIRRCA2TRAINGAIN5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN5_FIRRCA2DATAGAIN5__B 8
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN5_FIRRCA2DATAGAIN5__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN5_FIRRCA2DATAGAIN5__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN5_FIRRCA2DATAGAIN5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN6__A 0x1C30009
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN6__W 15
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN6__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN6_FIRRCA2TRAINGAIN6__B 0
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN6_FIRRCA2TRAINGAIN6__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN6_FIRRCA2TRAINGAIN6__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN6_FIRRCA2TRAINGAIN6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN6_FIRRCA2DATAGAIN6__B 8
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN6_FIRRCA2DATAGAIN6__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN6_FIRRCA2DATAGAIN6__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN6_FIRRCA2DATAGAIN6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN7__A 0x1C3000A
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN7__W 15
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN7__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN7_FIRRCA2TRAINGAIN7__B 0
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN7_FIRRCA2TRAINGAIN7__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN7_FIRRCA2TRAINGAIN7__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN7_FIRRCA2TRAINGAIN7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN7_FIRRCA2DATAGAIN7__B 8
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN7_FIRRCA2DATAGAIN7__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN7_FIRRCA2DATAGAIN7__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN7_FIRRCA2DATAGAIN7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN8__A 0x1C3000B
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN8__W 15
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN8__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN8_FIRRCA2TRAINGAIN8__B 0
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN8_FIRRCA2TRAINGAIN8__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN8_FIRRCA2TRAINGAIN8__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN8_FIRRCA2TRAINGAIN8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN8_FIRRCA2DATAGAIN8__B 8
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN8_FIRRCA2DATAGAIN8__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN8_FIRRCA2DATAGAIN8__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN8_FIRRCA2DATAGAIN8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN9__A 0x1C3000C
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN9__W 15
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN9__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN9_FIRRCA2TRAINGAIN9__B 0
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN9_FIRRCA2TRAINGAIN9__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN9_FIRRCA2TRAINGAIN9__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN9_FIRRCA2TRAINGAIN9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN9_FIRRCA2DATAGAIN9__B 8
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN9_FIRRCA2DATAGAIN9__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN9_FIRRCA2DATAGAIN9__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN9_FIRRCA2DATAGAIN9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN10__A 0x1C3000D
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN10__W 15
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN10__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN10_FIRRCA2TRAINGAIN10__B 0
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN10_FIRRCA2TRAINGAIN10__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN10_FIRRCA2TRAINGAIN10__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN10_FIRRCA2TRAINGAIN10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN10_FIRRCA2DATAGAIN10__B 8
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN10_FIRRCA2DATAGAIN10__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN10_FIRRCA2DATAGAIN10__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN10_FIRRCA2DATAGAIN10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN11__A 0x1C3000E
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN11__W 15
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN11__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN11_FIRRCA2TRAINGAIN11__B 0
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN11_FIRRCA2TRAINGAIN11__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN11_FIRRCA2TRAINGAIN11__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN11_FIRRCA2TRAINGAIN11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN11_FIRRCA2DATAGAIN11__B 8
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN11_FIRRCA2DATAGAIN11__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN11_FIRRCA2DATAGAIN11__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN11_FIRRCA2DATAGAIN11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN12__A 0x1C3000F
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN12__W 15
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN12__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN12_FIRRCA2TRAINGAIN12__B 0
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN12_FIRRCA2TRAINGAIN12__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN12_FIRRCA2TRAINGAIN12__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN12_FIRRCA2TRAINGAIN12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN12_FIRRCA2DATAGAIN12__B 8
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN12_FIRRCA2DATAGAIN12__W 7
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN12_FIRRCA2DATAGAIN12__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRRCA2GAIN12_FIRRCA2DATAGAIN12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN1__A 0x1C30010
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN1__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN1__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN1_FIRDDM1TRAINGAIN1__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN1_FIRDDM1TRAINGAIN1__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN1_FIRDDM1TRAINGAIN1__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN1_FIRDDM1TRAINGAIN1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN1_FIRDDM1DATAGAIN1__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN1_FIRDDM1DATAGAIN1__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN1_FIRDDM1DATAGAIN1__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN1_FIRDDM1DATAGAIN1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN2__A 0x1C30011
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN2__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN2__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN2_FIRDDM1TRAINGAIN2__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN2_FIRDDM1TRAINGAIN2__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN2_FIRDDM1TRAINGAIN2__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN2_FIRDDM1TRAINGAIN2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN2_FIRDDM1DATAGAIN2__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN2_FIRDDM1DATAGAIN2__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN2_FIRDDM1DATAGAIN2__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN2_FIRDDM1DATAGAIN2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN3__A 0x1C30012
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN3__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN3__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN3_FIRDDM1TRAINGAIN3__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN3_FIRDDM1TRAINGAIN3__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN3_FIRDDM1TRAINGAIN3__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN3_FIRDDM1TRAINGAIN3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN3_FIRDDM1DATAGAIN3__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN3_FIRDDM1DATAGAIN3__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN3_FIRDDM1DATAGAIN3__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN3_FIRDDM1DATAGAIN3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN4__A 0x1C30013
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN4__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN4__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN4_FIRDDM1TRAINGAIN4__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN4_FIRDDM1TRAINGAIN4__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN4_FIRDDM1TRAINGAIN4__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN4_FIRDDM1TRAINGAIN4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN4_FIRDDM1DATAGAIN4__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN4_FIRDDM1DATAGAIN4__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN4_FIRDDM1DATAGAIN4__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN4_FIRDDM1DATAGAIN4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN5__A 0x1C30014
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN5__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN5__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN5_FIRDDM1TRAINGAIN5__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN5_FIRDDM1TRAINGAIN5__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN5_FIRDDM1TRAINGAIN5__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN5_FIRDDM1TRAINGAIN5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN5_FIRDDM1DATAGAIN5__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN5_FIRDDM1DATAGAIN5__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN5_FIRDDM1DATAGAIN5__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN5_FIRDDM1DATAGAIN5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN6__A 0x1C30015
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN6__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN6__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN6_FIRDDM1TRAINGAIN6__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN6_FIRDDM1TRAINGAIN6__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN6_FIRDDM1TRAINGAIN6__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN6_FIRDDM1TRAINGAIN6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN6_FIRDDM1DATAGAIN6__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN6_FIRDDM1DATAGAIN6__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN6_FIRDDM1DATAGAIN6__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN6_FIRDDM1DATAGAIN6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN7__A 0x1C30016
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN7__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN7__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN7_FIRDDM1TRAINGAIN7__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN7_FIRDDM1TRAINGAIN7__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN7_FIRDDM1TRAINGAIN7__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN7_FIRDDM1TRAINGAIN7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN7_FIRDDM1DATAGAIN7__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN7_FIRDDM1DATAGAIN7__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN7_FIRDDM1DATAGAIN7__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN7_FIRDDM1DATAGAIN7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN8__A 0x1C30017
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN8__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN8__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN8_FIRDDM1TRAINGAIN8__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN8_FIRDDM1TRAINGAIN8__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN8_FIRDDM1TRAINGAIN8__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN8_FIRDDM1TRAINGAIN8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN8_FIRDDM1DATAGAIN8__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN8_FIRDDM1DATAGAIN8__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN8_FIRDDM1DATAGAIN8__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN8_FIRDDM1DATAGAIN8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN9__A 0x1C30018
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN9__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN9__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN9_FIRDDM1TRAINGAIN9__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN9_FIRDDM1TRAINGAIN9__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN9_FIRDDM1TRAINGAIN9__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN9_FIRDDM1TRAINGAIN9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN9_FIRDDM1DATAGAIN9__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN9_FIRDDM1DATAGAIN9__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN9_FIRDDM1DATAGAIN9__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN9_FIRDDM1DATAGAIN9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN10__A 0x1C30019
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN10__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN10__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN10_FIRDDM1TRAINGAIN10__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN10_FIRDDM1TRAINGAIN10__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN10_FIRDDM1TRAINGAIN10__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN10_FIRDDM1TRAINGAIN10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN10_FIRDDM1DATAGAIN10__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN10_FIRDDM1DATAGAIN10__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN10_FIRDDM1DATAGAIN10__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN10_FIRDDM1DATAGAIN10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN11__A 0x1C3001A
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN11__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN11__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN11_FIRDDM1TRAINGAIN11__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN11_FIRDDM1TRAINGAIN11__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN11_FIRDDM1TRAINGAIN11__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN11_FIRDDM1TRAINGAIN11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN11_FIRDDM1DATAGAIN11__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN11_FIRDDM1DATAGAIN11__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN11_FIRDDM1DATAGAIN11__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN11_FIRDDM1DATAGAIN11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN12__A 0x1C3001B
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN12__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN12__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN12_FIRDDM1TRAINGAIN12__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN12_FIRDDM1TRAINGAIN12__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN12_FIRDDM1TRAINGAIN12__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN12_FIRDDM1TRAINGAIN12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN12_FIRDDM1DATAGAIN12__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN12_FIRDDM1DATAGAIN12__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN12_FIRDDM1DATAGAIN12__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM1GAIN12_FIRDDM1DATAGAIN12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN1__A 0x1C3001C
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN1__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN1__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN1_FIRDDM2TRAINGAIN1__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN1_FIRDDM2TRAINGAIN1__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN1_FIRDDM2TRAINGAIN1__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN1_FIRDDM2TRAINGAIN1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN1_FIRDDM2DATAGAIN1__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN1_FIRDDM2DATAGAIN1__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN1_FIRDDM2DATAGAIN1__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN1_FIRDDM2DATAGAIN1__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN2__A 0x1C3001D
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN2__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN2__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN2_FIRDDM2TRAINGAIN2__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN2_FIRDDM2TRAINGAIN2__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN2_FIRDDM2TRAINGAIN2__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN2_FIRDDM2TRAINGAIN2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN2_FIRDDM2DATAGAIN2__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN2_FIRDDM2DATAGAIN2__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN2_FIRDDM2DATAGAIN2__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN2_FIRDDM2DATAGAIN2__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN3__A 0x1C3001E
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN3__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN3__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN3_FIRDDM2TRAINGAIN3__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN3_FIRDDM2TRAINGAIN3__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN3_FIRDDM2TRAINGAIN3__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN3_FIRDDM2TRAINGAIN3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN3_FIRDDM2DATAGAIN3__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN3_FIRDDM2DATAGAIN3__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN3_FIRDDM2DATAGAIN3__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN3_FIRDDM2DATAGAIN3__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN4__A 0x1C3001F
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN4__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN4__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN4_FIRDDM2TRAINGAIN4__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN4_FIRDDM2TRAINGAIN4__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN4_FIRDDM2TRAINGAIN4__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN4_FIRDDM2TRAINGAIN4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN4_FIRDDM2DATAGAIN4__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN4_FIRDDM2DATAGAIN4__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN4_FIRDDM2DATAGAIN4__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN4_FIRDDM2DATAGAIN4__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN5__A 0x1C30020
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN5__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN5__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN5_FIRDDM2TRAINGAIN5__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN5_FIRDDM2TRAINGAIN5__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN5_FIRDDM2TRAINGAIN5__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN5_FIRDDM2TRAINGAIN5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN5_FIRDDM2DATAGAIN5__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN5_FIRDDM2DATAGAIN5__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN5_FIRDDM2DATAGAIN5__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN5_FIRDDM2DATAGAIN5__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN6__A 0x1C30021
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN6__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN6__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN6_FIRDDM2TRAINGAIN6__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN6_FIRDDM2TRAINGAIN6__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN6_FIRDDM2TRAINGAIN6__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN6_FIRDDM2TRAINGAIN6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN6_FIRDDM2DATAGAIN6__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN6_FIRDDM2DATAGAIN6__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN6_FIRDDM2DATAGAIN6__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN6_FIRDDM2DATAGAIN6__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN7__A 0x1C30022
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN7__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN7__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN7_FIRDDM2TRAINGAIN7__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN7_FIRDDM2TRAINGAIN7__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN7_FIRDDM2TRAINGAIN7__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN7_FIRDDM2TRAINGAIN7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN7_FIRDDM2DATAGAIN7__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN7_FIRDDM2DATAGAIN7__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN7_FIRDDM2DATAGAIN7__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN7_FIRDDM2DATAGAIN7__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN8__A 0x1C30023
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN8__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN8__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN8_FIRDDM2TRAINGAIN8__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN8_FIRDDM2TRAINGAIN8__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN8_FIRDDM2TRAINGAIN8__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN8_FIRDDM2TRAINGAIN8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN8_FIRDDM2DATAGAIN8__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN8_FIRDDM2DATAGAIN8__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN8_FIRDDM2DATAGAIN8__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN8_FIRDDM2DATAGAIN8__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN9__A 0x1C30024
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN9__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN9__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN9_FIRDDM2TRAINGAIN9__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN9_FIRDDM2TRAINGAIN9__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN9_FIRDDM2TRAINGAIN9__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN9_FIRDDM2TRAINGAIN9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN9_FIRDDM2DATAGAIN9__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN9_FIRDDM2DATAGAIN9__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN9_FIRDDM2DATAGAIN9__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN9_FIRDDM2DATAGAIN9__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN10__A 0x1C30025
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN10__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN10__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN10_FIRDDM2TRAINGAIN10__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN10_FIRDDM2TRAINGAIN10__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN10_FIRDDM2TRAINGAIN10__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN10_FIRDDM2TRAINGAIN10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN10_FIRDDM2DATAGAIN10__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN10_FIRDDM2DATAGAIN10__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN10_FIRDDM2DATAGAIN10__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN10_FIRDDM2DATAGAIN10__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN11__A 0x1C30026
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN11__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN11__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN11_FIRDDM2TRAINGAIN11__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN11_FIRDDM2TRAINGAIN11__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN11_FIRDDM2TRAINGAIN11__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN11_FIRDDM2TRAINGAIN11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN11_FIRDDM2DATAGAIN11__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN11_FIRDDM2DATAGAIN11__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN11_FIRDDM2DATAGAIN11__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN11_FIRDDM2DATAGAIN11__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN12__A 0x1C30027
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN12__W 15
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN12__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN12_FIRDDM2TRAINGAIN12__B 0
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN12_FIRDDM2TRAINGAIN12__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN12_FIRDDM2TRAINGAIN12__M 0x7F
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN12_FIRDDM2TRAINGAIN12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN12_FIRDDM2DATAGAIN12__B 8
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN12_FIRDDM2DATAGAIN12__W 7
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN12_FIRDDM2DATAGAIN12__M 0x7F00
+#define VSB_SYSCTRL_RAM1_FIRDDM2GAIN12_FIRDDM2DATAGAIN12__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFETRAINLKRATIO__A 0x1C30028
+#define VSB_SYSCTRL_RAM1_DFETRAINLKRATIO__W 12
+#define VSB_SYSCTRL_RAM1_DFETRAINLKRATIO__M 0xFFF
+#define VSB_SYSCTRL_RAM1_DFETRAINLKRATIO__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFERCA1TRAINLKRATIO__A 0x1C30029
+#define VSB_SYSCTRL_RAM1_DFERCA1TRAINLKRATIO__W 12
+#define VSB_SYSCTRL_RAM1_DFERCA1TRAINLKRATIO__M 0xFFF
+#define VSB_SYSCTRL_RAM1_DFERCA1TRAINLKRATIO__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFERCA1DATALKRATIO__A 0x1C3002A
+#define VSB_SYSCTRL_RAM1_DFERCA1DATALKRATIO__W 12
+#define VSB_SYSCTRL_RAM1_DFERCA1DATALKRATIO__M 0xFFF
+#define VSB_SYSCTRL_RAM1_DFERCA1DATALKRATIO__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFERCA2TRAINLKRATIO__A 0x1C3002B
+#define VSB_SYSCTRL_RAM1_DFERCA2TRAINLKRATIO__W 12
+#define VSB_SYSCTRL_RAM1_DFERCA2TRAINLKRATIO__M 0xFFF
+#define VSB_SYSCTRL_RAM1_DFERCA2TRAINLKRATIO__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFERCA2DATALKRATIO__A 0x1C3002C
+#define VSB_SYSCTRL_RAM1_DFERCA2DATALKRATIO__W 12
+#define VSB_SYSCTRL_RAM1_DFERCA2DATALKRATIO__M 0xFFF
+#define VSB_SYSCTRL_RAM1_DFERCA2DATALKRATIO__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFEDDM1TRAINLKRATIO__A 0x1C3002D
+#define VSB_SYSCTRL_RAM1_DFEDDM1TRAINLKRATIO__W 12
+#define VSB_SYSCTRL_RAM1_DFEDDM1TRAINLKRATIO__M 0xFFF
+#define VSB_SYSCTRL_RAM1_DFEDDM1TRAINLKRATIO__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFEDDM1DATALKRATIO__A 0x1C3002E
+#define VSB_SYSCTRL_RAM1_DFEDDM1DATALKRATIO__W 12
+#define VSB_SYSCTRL_RAM1_DFEDDM1DATALKRATIO__M 0xFFF
+#define VSB_SYSCTRL_RAM1_DFEDDM1DATALKRATIO__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFEDDM2TRAINLKRATIO__A 0x1C3002F
+#define VSB_SYSCTRL_RAM1_DFEDDM2TRAINLKRATIO__W 12
+#define VSB_SYSCTRL_RAM1_DFEDDM2TRAINLKRATIO__M 0xFFF
+#define VSB_SYSCTRL_RAM1_DFEDDM2TRAINLKRATIO__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFEDDM2DATALKRATIO__A 0x1C30030
+#define VSB_SYSCTRL_RAM1_DFEDDM2DATALKRATIO__W 12
+#define VSB_SYSCTRL_RAM1_DFEDDM2DATALKRATIO__M 0xFFF
+#define VSB_SYSCTRL_RAM1_DFEDDM2DATALKRATIO__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFETRAINGAIN__A 0x1C30031
+#define VSB_SYSCTRL_RAM1_DFETRAINGAIN__W 7
+#define VSB_SYSCTRL_RAM1_DFETRAINGAIN__M 0x7F
+#define VSB_SYSCTRL_RAM1_DFETRAINGAIN__PRE 0x0
+#define VSB_SYSCTRL_RAM1_DFERCA1GAIN__A 0x1C30032
+#define VSB_SYSCTRL_RAM1_DFERCA1GAIN__W 15
+#define VSB_SYSCTRL_RAM1_DFERCA1GAIN__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_DFERCA1GAIN__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFERCA1GAIN_DFERCA1TRAINGAIN__B 0
+#define VSB_SYSCTRL_RAM1_DFERCA1GAIN_DFERCA1TRAINGAIN__W 7
+#define VSB_SYSCTRL_RAM1_DFERCA1GAIN_DFERCA1TRAINGAIN__M 0x7F
+#define VSB_SYSCTRL_RAM1_DFERCA1GAIN_DFERCA1TRAINGAIN__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFERCA1GAIN_DFERCA1DATAGAIN__B 8
+#define VSB_SYSCTRL_RAM1_DFERCA1GAIN_DFERCA1DATAGAIN__W 7
+#define VSB_SYSCTRL_RAM1_DFERCA1GAIN_DFERCA1DATAGAIN__M 0x7F00
+#define VSB_SYSCTRL_RAM1_DFERCA1GAIN_DFERCA1DATAGAIN__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFERCA2GAIN__A 0x1C30033
+#define VSB_SYSCTRL_RAM1_DFERCA2GAIN__W 15
+#define VSB_SYSCTRL_RAM1_DFERCA2GAIN__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_DFERCA2GAIN__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFERCA2GAIN_DFERCA2TRAINGAIN__B 0
+#define VSB_SYSCTRL_RAM1_DFERCA2GAIN_DFERCA2TRAINGAIN__W 7
+#define VSB_SYSCTRL_RAM1_DFERCA2GAIN_DFERCA2TRAINGAIN__M 0x7F
+#define VSB_SYSCTRL_RAM1_DFERCA2GAIN_DFERCA2TRAINGAIN__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFERCA2GAIN_DFERCA2DATAGAIN__B 8
+#define VSB_SYSCTRL_RAM1_DFERCA2GAIN_DFERCA2DATAGAIN__W 7
+#define VSB_SYSCTRL_RAM1_DFERCA2GAIN_DFERCA2DATAGAIN__M 0x7F00
+#define VSB_SYSCTRL_RAM1_DFERCA2GAIN_DFERCA2DATAGAIN__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFEDDM1GAIN__A 0x1C30034
+#define VSB_SYSCTRL_RAM1_DFEDDM1GAIN__W 15
+#define VSB_SYSCTRL_RAM1_DFEDDM1GAIN__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_DFEDDM1GAIN__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFEDDM1GAIN_DFEDDM1TRAINGAIN__B 0
+#define VSB_SYSCTRL_RAM1_DFEDDM1GAIN_DFEDDM1TRAINGAIN__W 7
+#define VSB_SYSCTRL_RAM1_DFEDDM1GAIN_DFEDDM1TRAINGAIN__M 0x7F
+#define VSB_SYSCTRL_RAM1_DFEDDM1GAIN_DFEDDM1TRAINGAIN__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFEDDM1GAIN_DFEDDM1DATAGAIN__B 8
+#define VSB_SYSCTRL_RAM1_DFEDDM1GAIN_DFEDDM1DATAGAIN__W 7
+#define VSB_SYSCTRL_RAM1_DFEDDM1GAIN_DFEDDM1DATAGAIN__M 0x7F00
+#define VSB_SYSCTRL_RAM1_DFEDDM1GAIN_DFEDDM1DATAGAIN__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFEDDM2GAIN__A 0x1C30035
+#define VSB_SYSCTRL_RAM1_DFEDDM2GAIN__W 15
+#define VSB_SYSCTRL_RAM1_DFEDDM2GAIN__M 0x7FFF
+#define VSB_SYSCTRL_RAM1_DFEDDM2GAIN__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFEDDM2GAIN_DFEDDM2TRAINGAIN__B 0
+#define VSB_SYSCTRL_RAM1_DFEDDM2GAIN_DFEDDM2TRAINGAIN__W 7
+#define VSB_SYSCTRL_RAM1_DFEDDM2GAIN_DFEDDM2TRAINGAIN__M 0x7F
+#define VSB_SYSCTRL_RAM1_DFEDDM2GAIN_DFEDDM2TRAINGAIN__PRE 0x0
+
+#define VSB_SYSCTRL_RAM1_DFEDDM2GAIN_DFEDDM2DATAGAIN__B 8
+#define VSB_SYSCTRL_RAM1_DFEDDM2GAIN_DFEDDM2DATAGAIN__W 7
+#define VSB_SYSCTRL_RAM1_DFEDDM2GAIN_DFEDDM2DATAGAIN__M 0x7F00
+#define VSB_SYSCTRL_RAM1_DFEDDM2GAIN_DFEDDM2DATAGAIN__PRE 0x0
+
+#define VSB_TCMEQ_RAM__A 0x1C40000
+
+#define VSB_TCMEQ_RAM_TCMEQ_RAM__B 0
+#define VSB_TCMEQ_RAM_TCMEQ_RAM__W 16
+#define VSB_TCMEQ_RAM_TCMEQ_RAM__M 0xFFFF
+#define VSB_TCMEQ_RAM_TCMEQ_RAM__PRE 0x0
+
+#define VSB_FCPRE_RAM__A 0x1C50000
+
+#define VSB_FCPRE_RAM_FCPRE_RAM__B 0
+#define VSB_FCPRE_RAM_FCPRE_RAM__W 16
+#define VSB_FCPRE_RAM_FCPRE_RAM__M 0xFFFF
+#define VSB_FCPRE_RAM_FCPRE_RAM__PRE 0x0
+
+#define VSB_EQTAP_RAM__A 0x1C60000
+
+#define VSB_EQTAP_RAM_EQTAP_RAM__B 0
+#define VSB_EQTAP_RAM_EQTAP_RAM__W 12
+#define VSB_EQTAP_RAM_EQTAP_RAM__M 0xFFF
+#define VSB_EQTAP_RAM_EQTAP_RAM__PRE 0x0
+
+#endif
diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c
index 959ae36403b8..5b87ece69414 100644
--- a/drivers/media/dvb-frontends/drxd_hard.c
+++ b/drivers/media/dvb-frontends/drxd_hard.c
@@ -2688,11 +2688,11 @@ static int DRXD_init(struct drxd_state *state, const u8 *fw, u32 fw_size)
status = EnableAndResetMB(state);
if (status < 0)
break;
- if (state->type_A)
+ if (state->type_A) {
status = ResetCEFR(state);
if (status < 0)
break;
-
+ }
if (fw) {
status = DownloadMicrocode(state, fw, fw_size);
if (status < 0)
diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c
index 1e344b033277..335daeff91b9 100644
--- a/drivers/media/dvb-frontends/ds3000.c
+++ b/drivers/media/dvb-frontends/ds3000.c
@@ -616,7 +616,7 @@ static int ds3000_read_snr(struct dvb_frontend *fe, u16 *snr)
snr_reading = dvbs2_noise_reading / tmp;
if (snr_reading > 80)
snr_reading = 80;
- *snr = -(dvbs2_snr_tab[snr_reading] / 1000);
+ *snr = -(dvbs2_snr_tab[snr_reading - 1] / 1000);
}
dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
snr_reading, *snr);
diff --git a/drivers/media/dvb-frontends/it913x-fe-priv.h b/drivers/media/dvb-frontends/it913x-fe-priv.h
deleted file mode 100644
index eb6fd8aebdb3..000000000000
--- a/drivers/media/dvb-frontends/it913x-fe-priv.h
+++ /dev/null
@@ -1,1051 +0,0 @@
-
-struct it913xset { u32 pro;
- u32 address;
- u8 reg[15];
- u8 count;
-};
-
-struct adctable { u32 adcFrequency;
- u32 bandwidth;
- u32 coeff_1_2048;
- u32 coeff_1_4096;
- u32 coeff_1_8191;
- u32 coeff_1_8192;
- u32 coeff_1_8193;
- u32 coeff_2_2k;
- u32 coeff_2_4k;
- u32 coeff_2_8k;
- u16 bfsfcw_fftinx_ratio;
- u16 fftinx_bfsfcw_ratio;
-};
-
-/* clock and coeff tables only table 3 is used with IT9137*/
-/* TODO other tables relate AF9035 may be removed */
-static struct adctable tab1[] = {
- { 20156250, 6000000,
- 0x02b8ba6e, 0x015c5d37, 0x00ae340d, 0x00ae2e9b, 0x00ae292a,
- 0x015c5d37, 0x00ae2e9b, 0x0057174e, 0x02f1, 0x015c },
- { 20156250, 7000000,
- 0x032cd980, 0x01966cc0, 0x00cb3cba, 0x00cb3660, 0x00cb3007,
- 0x01966cc0, 0x00cb3660, 0x00659b30, 0x0285, 0x0196 },
- { 20156250, 8000000,
- 0x03a0f893, 0x01d07c49, 0x00e84567, 0x00e83e25, 0x00e836e3,
- 0x01d07c49, 0x00e83e25, 0x00741f12, 0x0234, 0x01d0 },
- { 20156250, 5000000,
- 0x02449b5c, 0x01224dae, 0x00912b60, 0x009126d7, 0x0091224e,
- 0x01224dae, 0x009126d7, 0x0048936b, 0x0387, 0x0122 }
-};
-
-static struct adctable tab2[] = {
- { 20187500, 6000000,
- 0x02b7a654, 0x015bd32a, 0x00adef04, 0x00ade995, 0x00ade426,
- 0x015bd32a, 0x00ade995, 0x0056f4ca, 0x02f2, 0x015c },
- { 20187500, 7000000,
- 0x032b9761, 0x0195cbb1, 0x00caec30, 0x00cae5d8, 0x00cadf81,
- 0x0195cbb1, 0x00cae5d8, 0x006572ec, 0x0286, 0x0196 },
- { 20187500, 8000000,
- 0x039f886f, 0x01cfc438, 0x00e7e95b, 0x00e7e21c, 0x00e7dadd,
- 0x01cfc438, 0x00e7e21c, 0x0073f10e, 0x0235, 0x01d0 },
- { 20187500, 5000000,
- 0x0243b546, 0x0121daa3, 0x0090f1d9, 0x0090ed51, 0x0090e8ca,
- 0x0121daa3, 0x0090ed51, 0x004876a9, 0x0388, 0x0122 }
-
-};
-
-static struct adctable tab3[] = {
- { 20250000, 6000000,
- 0x02b580ad, 0x015ac057, 0x00ad6597, 0x00ad602b, 0x00ad5ac1,
- 0x015ac057, 0x00ad602b, 0x0056b016, 0x02f4, 0x015b },
- { 20250000, 7000000,
- 0x03291620, 0x01948b10, 0x00ca4bda, 0x00ca4588, 0x00ca3f36,
- 0x01948b10, 0x00ca4588, 0x006522c4, 0x0288, 0x0195 },
- { 20250000, 8000000,
- 0x039cab92, 0x01ce55c9, 0x00e7321e, 0x00e72ae4, 0x00e723ab,
- 0x01ce55c9, 0x00e72ae4, 0x00739572, 0x0237, 0x01ce },
- { 20250000, 5000000,
- 0x0241eb3b, 0x0120f59e, 0x00907f53, 0x00907acf, 0x0090764b,
- 0x0120f59e, 0x00907acf, 0x00483d67, 0x038b, 0x0121 }
-
-};
-
-static struct adctable tab4[] = {
- { 20583333, 6000000,
- 0x02aa4598, 0x015522cc, 0x00aa96bb, 0x00aa9166, 0x00aa8c12,
- 0x015522cc, 0x00aa9166, 0x005548b3, 0x0300, 0x0155 },
- { 20583333, 7000000,
- 0x031bfbdc, 0x018dfdee, 0x00c7052f, 0x00c6fef7, 0x00c6f8bf,
- 0x018dfdee, 0x00c6fef7, 0x00637f7b, 0x0293, 0x018e },
- { 20583333, 8000000,
- 0x038db21f, 0x01c6d910, 0x00e373a3, 0x00e36c88, 0x00e3656d,
- 0x01c6d910, 0x00e36c88, 0x0071b644, 0x0240, 0x01c7 },
- { 20583333, 5000000,
- 0x02388f54, 0x011c47aa, 0x008e2846, 0x008e23d5, 0x008e1f64,
- 0x011c47aa, 0x008e23d5, 0x004711ea, 0x039a, 0x011c }
-
-};
-
-static struct adctable tab5[] = {
- { 20416667, 6000000,
- 0x02afd765, 0x0157ebb3, 0x00abfb39, 0x00abf5d9, 0x00abf07a,
- 0x0157ebb3, 0x00abf5d9, 0x0055faed, 0x02fa, 0x0158 },
- { 20416667, 7000000,
- 0x03227b4b, 0x01913da6, 0x00c8a518, 0x00c89ed3, 0x00c8988e,
- 0x01913da6, 0x00c89ed3, 0x00644f69, 0x028d, 0x0191 },
- { 20416667, 8000000,
- 0x03951f32, 0x01ca8f99, 0x00e54ef7, 0x00e547cc, 0x00e540a2,
- 0x01ca8f99, 0x00e547cc, 0x0072a3e6, 0x023c, 0x01cb },
- { 20416667, 5000000,
- 0x023d337f, 0x011e99c0, 0x008f515a, 0x008f4ce0, 0x008f4865,
- 0x011e99c0, 0x008f4ce0, 0x0047a670, 0x0393, 0x011f }
-
-};
-
-static struct adctable tab6[] = {
- { 20480000, 6000000,
- 0x02adb6db, 0x0156db6e, 0x00ab7312, 0x00ab6db7, 0x00ab685c,
- 0x0156db6e, 0x00ab6db7, 0x0055b6db, 0x02fd, 0x0157 },
- { 20480000, 7000000,
- 0x03200000, 0x01900000, 0x00c80640, 0x00c80000, 0x00c7f9c0,
- 0x01900000, 0x00c80000, 0x00640000, 0x028f, 0x0190 },
- { 20480000, 8000000,
- 0x03924925, 0x01c92492, 0x00e4996e, 0x00e49249, 0x00e48b25,
- 0x01c92492, 0x00e49249, 0x00724925, 0x023d, 0x01c9 },
- { 20480000, 5000000,
- 0x023b6db7, 0x011db6db, 0x008edfe5, 0x008edb6e, 0x008ed6f7,
- 0x011db6db, 0x008edb6e, 0x00476db7, 0x0396, 0x011e }
-};
-
-static struct adctable tab7[] = {
- { 20500000, 6000000,
- 0x02ad0b99, 0x015685cc, 0x00ab4840, 0x00ab42e6, 0x00ab3d8c,
- 0x015685cc, 0x00ab42e6, 0x0055a173, 0x02fd, 0x0157 },
- { 20500000, 7000000,
- 0x031f3832, 0x018f9c19, 0x00c7d44b, 0x00c7ce0c, 0x00c7c7ce,
- 0x018f9c19, 0x00c7ce0c, 0x0063e706, 0x0290, 0x0190 },
- { 20500000, 8000000,
- 0x039164cb, 0x01c8b266, 0x00e46056, 0x00e45933, 0x00e45210,
- 0x01c8b266, 0x00e45933, 0x00722c99, 0x023e, 0x01c9 },
- { 20500000, 5000000,
- 0x023adeff, 0x011d6f80, 0x008ebc36, 0x008eb7c0, 0x008eb34a,
- 0x011d6f80, 0x008eb7c0, 0x00475be0, 0x0396, 0x011d }
-
-};
-
-static struct adctable tab8[] = {
- { 20625000, 6000000,
- 0x02a8e4bd, 0x0154725e, 0x00aa3e81, 0x00aa392f, 0x00aa33de,
- 0x0154725e, 0x00aa392f, 0x00551c98, 0x0302, 0x0154 },
- { 20625000, 7000000,
- 0x031a6032, 0x018d3019, 0x00c69e41, 0x00c6980c, 0x00c691d8,
- 0x018d3019, 0x00c6980c, 0x00634c06, 0x0294, 0x018d },
- { 20625000, 8000000,
- 0x038bdba6, 0x01c5edd3, 0x00e2fe02, 0x00e2f6ea, 0x00e2efd2,
- 0x01c5edd3, 0x00e2f6ea, 0x00717b75, 0x0242, 0x01c6 },
- { 20625000, 5000000,
- 0x02376948, 0x011bb4a4, 0x008ddec1, 0x008dda52, 0x008dd5e3,
- 0x011bb4a4, 0x008dda52, 0x0046ed29, 0x039c, 0x011c }
-
-};
-
-struct table {
- u32 xtal;
- struct adctable *table;
-};
-
-static struct table fe_clockTable[] = {
- {12000000, tab3}, /* 12.00MHz */
- {20480000, tab6}, /* 20.48MHz */
- {36000000, tab3}, /* 36.00MHz */
- {30000000, tab1}, /* 30.00MHz */
- {26000000, tab4}, /* 26.00MHz */
- {28000000, tab5}, /* 28.00MHz */
- {32000000, tab7}, /* 32.00MHz */
- {34000000, tab2}, /* 34.00MHz */
- {24000000, tab1}, /* 24.00MHz */
- {22000000, tab8}, /* 22.00MHz */
-};
-
-/* fe get */
-fe_code_rate_t fe_code[] = {
- FEC_1_2,
- FEC_2_3,
- FEC_3_4,
- FEC_5_6,
- FEC_7_8,
- FEC_NONE,
-};
-
-fe_guard_interval_t fe_gi[] = {
- GUARD_INTERVAL_1_32,
- GUARD_INTERVAL_1_16,
- GUARD_INTERVAL_1_8,
- GUARD_INTERVAL_1_4,
-};
-
-fe_hierarchy_t fe_hi[] = {
- HIERARCHY_NONE,
- HIERARCHY_1,
- HIERARCHY_2,
- HIERARCHY_4,
-};
-
-fe_transmit_mode_t fe_mode[] = {
- TRANSMISSION_MODE_2K,
- TRANSMISSION_MODE_8K,
- TRANSMISSION_MODE_4K,
-};
-
-fe_modulation_t fe_con[] = {
- QPSK,
- QAM_16,
- QAM_64,
-};
-
-enum {
- PRIORITY_HIGH = 0, /* High-priority stream */
- PRIORITY_LOW, /* Low-priority stream */
-};
-
-/* Standard demodulator functions */
-static struct it913xset set_solo_fe[] = {
- {PRO_LINK, GPIOH5_EN, {0x01}, 0x01},
- {PRO_LINK, GPIOH5_ON, {0x01}, 0x01},
- {PRO_LINK, GPIOH5_O, {0x00}, 0x01},
- {PRO_LINK, GPIOH5_O, {0x01}, 0x01},
- {PRO_LINK, DVBT_INTEN, {0x04}, 0x01},
- {PRO_LINK, DVBT_ENABLE, {0x05}, 0x01},
- {PRO_DMOD, MP2IF_MPEG_PAR_MODE, {0x00}, 0x01},
- {PRO_LINK, HOSTB_MPEG_SER_MODE, {0x00}, 0x01},
- {PRO_LINK, HOSTB_MPEG_PAR_MODE, {0x00}, 0x01},
- {PRO_DMOD, DCA_UPPER_CHIP, {0x00}, 0x01},
- {PRO_LINK, HOSTB_DCA_UPPER, {0x00}, 0x01},
- {PRO_DMOD, DCA_LOWER_CHIP, {0x00}, 0x01},
- {PRO_LINK, HOSTB_DCA_LOWER, {0x00}, 0x01},
- {PRO_DMOD, DCA_PLATCH, {0x00}, 0x01},
- {PRO_DMOD, DCA_FPGA_LATCH, {0x00}, 0x01},
- {PRO_DMOD, DCA_STAND_ALONE, {0x01}, 0x01},
- {PRO_DMOD, DCA_ENABLE, {0x00}, 0x01},
- {PRO_DMOD, MP2IF_MPEG_PAR_MODE, {0x00}, 0x01},
- {PRO_DMOD, BFS_FCW, {0x00, 0x00, 0x00}, 0x03},
- {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
-};
-
-
-static struct it913xset init_1[] = {
- {PRO_LINK, LOCK3_OUT, {0x01}, 0x01},
- {PRO_LINK, PADMISCDRSR, {0x01}, 0x01},
- {PRO_LINK, PADMISCDR2, {0x00}, 0x01},
- {PRO_DMOD, 0xec57, {0x00, 0x00}, 0x02},
- {PRO_LINK, PADMISCDR4, {0x00}, 0x01}, /* Power up */
- {PRO_LINK, PADMISCDR8, {0x00}, 0x01},
- {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
-};
-
-
-/* Version 1 types */
-static struct it913xset it9135_v1[] = {
- {PRO_DMOD, 0x0051, {0x01}, 0x01},
- {PRO_DMOD, 0x0070, {0x0a}, 0x01},
- {PRO_DMOD, 0x007e, {0x04}, 0x01},
- {PRO_DMOD, 0x0081, {0x0a}, 0x01},
- {PRO_DMOD, 0x008a, {0x01}, 0x01},
- {PRO_DMOD, 0x008e, {0x01}, 0x01},
- {PRO_DMOD, 0x0092, {0x06}, 0x01},
- {PRO_DMOD, 0x0099, {0x01}, 0x01},
- {PRO_DMOD, 0x009f, {0xe1}, 0x01},
- {PRO_DMOD, 0x00a0, {0xcf}, 0x01},
- {PRO_DMOD, 0x00a3, {0x01}, 0x01},
- {PRO_DMOD, 0x00a5, {0x01}, 0x01},
- {PRO_DMOD, 0x00a6, {0x01}, 0x01},
- {PRO_DMOD, 0x00a9, {0x00}, 0x01},
- {PRO_DMOD, 0x00aa, {0x01}, 0x01},
- {PRO_DMOD, 0x00b0, {0x01}, 0x01},
- {PRO_DMOD, 0x00c2, {0x05}, 0x01},
- {PRO_DMOD, 0x00c6, {0x19}, 0x01},
- {PRO_DMOD, 0xf000, {0x0f}, 0x01},
- {PRO_DMOD, 0xf016, {0x10}, 0x01},
- {PRO_DMOD, 0xf017, {0x04}, 0x01},
- {PRO_DMOD, 0xf018, {0x05}, 0x01},
- {PRO_DMOD, 0xf019, {0x04}, 0x01},
- {PRO_DMOD, 0xf01a, {0x05}, 0x01},
- {PRO_DMOD, 0xf021, {0x03}, 0x01},
- {PRO_DMOD, 0xf022, {0x0a}, 0x01},
- {PRO_DMOD, 0xf023, {0x0a}, 0x01},
- {PRO_DMOD, 0xf02b, {0x00}, 0x01},
- {PRO_DMOD, 0xf02c, {0x01}, 0x01},
- {PRO_DMOD, 0xf064, {0x03}, 0x01},
- {PRO_DMOD, 0xf065, {0xf9}, 0x01},
- {PRO_DMOD, 0xf066, {0x03}, 0x01},
- {PRO_DMOD, 0xf067, {0x01}, 0x01},
- {PRO_DMOD, 0xf06f, {0xe0}, 0x01},
- {PRO_DMOD, 0xf070, {0x03}, 0x01},
- {PRO_DMOD, 0xf072, {0x0f}, 0x01},
- {PRO_DMOD, 0xf073, {0x03}, 0x01},
- {PRO_DMOD, 0xf078, {0x00}, 0x01},
- {PRO_DMOD, 0xf087, {0x00}, 0x01},
- {PRO_DMOD, 0xf09b, {0x3f}, 0x01},
- {PRO_DMOD, 0xf09c, {0x00}, 0x01},
- {PRO_DMOD, 0xf09d, {0x20}, 0x01},
- {PRO_DMOD, 0xf09e, {0x00}, 0x01},
- {PRO_DMOD, 0xf09f, {0x0c}, 0x01},
- {PRO_DMOD, 0xf0a0, {0x00}, 0x01},
- {PRO_DMOD, 0xf130, {0x04}, 0x01},
- {PRO_DMOD, 0xf132, {0x04}, 0x01},
- {PRO_DMOD, 0xf144, {0x1a}, 0x01},
- {PRO_DMOD, 0xf146, {0x00}, 0x01},
- {PRO_DMOD, 0xf14a, {0x01}, 0x01},
- {PRO_DMOD, 0xf14c, {0x00}, 0x01},
- {PRO_DMOD, 0xf14d, {0x00}, 0x01},
- {PRO_DMOD, 0xf14f, {0x04}, 0x01},
- {PRO_DMOD, 0xf158, {0x7f}, 0x01},
- {PRO_DMOD, 0xf15a, {0x00}, 0x01},
- {PRO_DMOD, 0xf15b, {0x08}, 0x01},
- {PRO_DMOD, 0xf15d, {0x03}, 0x01},
- {PRO_DMOD, 0xf15e, {0x05}, 0x01},
- {PRO_DMOD, 0xf163, {0x05}, 0x01},
- {PRO_DMOD, 0xf166, {0x01}, 0x01},
- {PRO_DMOD, 0xf167, {0x40}, 0x01},
- {PRO_DMOD, 0xf168, {0x0f}, 0x01},
- {PRO_DMOD, 0xf17a, {0x00}, 0x01},
- {PRO_DMOD, 0xf17b, {0x00}, 0x01},
- {PRO_DMOD, 0xf183, {0x01}, 0x01},
- {PRO_DMOD, 0xf19d, {0x40}, 0x01},
- {PRO_DMOD, 0xf1bc, {0x36}, 0x01},
- {PRO_DMOD, 0xf1bd, {0x00}, 0x01},
- {PRO_DMOD, 0xf1cb, {0xa0}, 0x01},
- {PRO_DMOD, 0xf1cc, {0x01}, 0x01},
- {PRO_DMOD, 0xf204, {0x10}, 0x01},
- {PRO_DMOD, 0xf214, {0x00}, 0x01},
- {PRO_DMOD, 0xf40e, {0x0a}, 0x01},
- {PRO_DMOD, 0xf40f, {0x40}, 0x01},
- {PRO_DMOD, 0xf410, {0x08}, 0x01},
- {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
- {PRO_DMOD, 0xf561, {0x15}, 0x01},
- {PRO_DMOD, 0xf562, {0x20}, 0x01},
- {PRO_DMOD, 0xf5df, {0xfb}, 0x01},
- {PRO_DMOD, 0xf5e0, {0x00}, 0x01},
- {PRO_DMOD, 0xf5e3, {0x09}, 0x01},
- {PRO_DMOD, 0xf5e4, {0x01}, 0x01},
- {PRO_DMOD, 0xf5e5, {0x01}, 0x01},
- {PRO_DMOD, 0xf5f8, {0x01}, 0x01},
- {PRO_DMOD, 0xf5fd, {0x01}, 0x01},
- {PRO_DMOD, 0xf600, {0x05}, 0x01},
- {PRO_DMOD, 0xf601, {0x08}, 0x01},
- {PRO_DMOD, 0xf602, {0x0b}, 0x01},
- {PRO_DMOD, 0xf603, {0x0e}, 0x01},
- {PRO_DMOD, 0xf604, {0x11}, 0x01},
- {PRO_DMOD, 0xf605, {0x14}, 0x01},
- {PRO_DMOD, 0xf606, {0x17}, 0x01},
- {PRO_DMOD, 0xf607, {0x1f}, 0x01},
- {PRO_DMOD, 0xf60e, {0x00}, 0x01},
- {PRO_DMOD, 0xf60f, {0x04}, 0x01},
- {PRO_DMOD, 0xf610, {0x32}, 0x01},
- {PRO_DMOD, 0xf611, {0x10}, 0x01},
- {PRO_DMOD, 0xf707, {0xfc}, 0x01},
- {PRO_DMOD, 0xf708, {0x00}, 0x01},
- {PRO_DMOD, 0xf709, {0x37}, 0x01},
- {PRO_DMOD, 0xf70a, {0x00}, 0x01},
- {PRO_DMOD, 0xf78b, {0x01}, 0x01},
- {PRO_DMOD, 0xf80f, {0x40}, 0x01},
- {PRO_DMOD, 0xf810, {0x54}, 0x01},
- {PRO_DMOD, 0xf811, {0x5a}, 0x01},
- {PRO_DMOD, 0xf905, {0x01}, 0x01},
- {PRO_DMOD, 0xfb06, {0x03}, 0x01},
- {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
- {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
-};
-
-static struct it913xset it9135_38[] = {
- {PRO_DMOD, 0x0043, {0x00}, 0x01},
- {PRO_DMOD, 0x0046, {0x38}, 0x01},
- {PRO_DMOD, 0x0051, {0x01}, 0x01},
- {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
- {PRO_DMOD, 0x0068, {0x0a}, 0x01},
- {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
- {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xc8, 0x01}, 0x05},
- {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02},
- {PRO_DMOD, 0x0081, { 0x0a, 0x12, 0x02, 0x0a, 0x03, 0xc8, 0xb8,
- 0xd0, 0xc3, 0x01}, 0x0a},
- {PRO_DMOD, 0x008e, {0x01}, 0x01},
- {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
- {PRO_DMOD, 0x0099, {0x01}, 0x01},
- {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
- {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
- {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04},
- {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
- {PRO_DMOD, 0x00b0, {0x01}, 0x01},
- {PRO_DMOD, 0x00b3, {0x02, 0x32}, 0x02},
- {PRO_DMOD, 0x00b6, {0x14}, 0x01},
- {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03},
- {PRO_DMOD, 0x00c4, {0x00}, 0x01},
- {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
- {PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03},
- {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03},
- {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
- {PRO_DMOD, 0x00fc, { 0x02, 0x02, 0x02, 0x09, 0x50, 0x7b, 0x77,
- 0x00, 0x02, 0xc8, 0x05, 0x7b}, 0x0c},
- {PRO_DMOD, 0x0109, {0x02}, 0x01},
- {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04},
- {PRO_DMOD, 0x011a, {0xc8, 0x7b, 0x8a, 0xa0}, 0x04},
- {PRO_DMOD, 0x0122, {0x02, 0x18, 0xc3}, 0x03},
- {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02},
- {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
- {PRO_DMOD, 0x0137, {0x01, 0x00, 0x07, 0x00, 0x06}, 0x05},
- {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc8, 0x59}, 0x05},
- {PRO_DMOD, 0xf000, {0x0f}, 0x01},
- {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05},
- {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05},
- {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04},
- {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
- {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
- {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
- {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
- {PRO_DMOD, 0xf085, {0x00, 0x02, 0x00}, 0x03},
- {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
- {PRO_DMOD, 0xf130, {0x04}, 0x01},
- {PRO_DMOD, 0xf132, {0x04}, 0x01},
- {PRO_DMOD, 0xf144, {0x1a}, 0x01},
- {PRO_DMOD, 0xf146, {0x00}, 0x01},
- {PRO_DMOD, 0xf14a, {0x01}, 0x01},
- {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
- {PRO_DMOD, 0xf14f, {0x04}, 0x01},
- {PRO_DMOD, 0xf158, {0x7f}, 0x01},
- {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
- {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
- {PRO_DMOD, 0xf163, {0x05}, 0x01},
- {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
- {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
- {PRO_DMOD, 0xf183, {0x01}, 0x01},
- {PRO_DMOD, 0xf19d, {0x40}, 0x01},
- {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
- {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
- {PRO_DMOD, 0xf204, {0x10}, 0x01},
- {PRO_DMOD, 0xf214, {0x00}, 0x01},
- {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
- {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
- {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
- {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
- {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
- {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
- {PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02},
- {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
- {PRO_DMOD, 0xf5f8, {0x01}, 0x01},
- {PRO_DMOD, 0xf5fd, {0x01}, 0x01},
- {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
- 0x1f}, 0x08},
- {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
- {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
- {PRO_DMOD, 0xf78b, {0x01}, 0x01},
- {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
- {PRO_DMOD, 0xf905, {0x01}, 0x01},
- {PRO_DMOD, 0xfb06, {0x03}, 0x01},
- {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
- {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
-};
-
-static struct it913xset it9135_51[] = {
- {PRO_DMOD, 0x0043, {0x00}, 0x01},
- {PRO_DMOD, 0x0046, {0x51}, 0x01},
- {PRO_DMOD, 0x0051, {0x01}, 0x01},
- {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
- {PRO_DMOD, 0x0068, {0x0a}, 0x01},
- {PRO_DMOD, 0x0070, {0x0a, 0x06, 0x02}, 0x03},
- {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xc8, 0x01}, 0x05},
- {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02},
- {PRO_DMOD, 0x0081, { 0x0a, 0x12, 0x02, 0x0a, 0x03, 0xc0, 0x96,
- 0xcf, 0xc3, 0x01}, 0x0a},
- {PRO_DMOD, 0x008e, {0x01}, 0x01},
- {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
- {PRO_DMOD, 0x0099, {0x01}, 0x01},
- {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
- {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
- {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04},
- {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
- {PRO_DMOD, 0x00b0, {0x01}, 0x01},
- {PRO_DMOD, 0x00b3, {0x02, 0x3c}, 0x02},
- {PRO_DMOD, 0x00b6, {0x14}, 0x01},
- {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03},
- {PRO_DMOD, 0x00c4, {0x00}, 0x01},
- {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
- {PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03},
- {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03},
- {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
- {PRO_DMOD, 0x00fc, { 0x03, 0x02, 0x02, 0x09, 0x50, 0x7a, 0x77,
- 0x01, 0x02, 0xb0, 0x02, 0x7a}, 0x0c},
- {PRO_DMOD, 0x0109, {0x02}, 0x01},
- {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04},
- {PRO_DMOD, 0x011a, {0xc0, 0x7a, 0xac, 0x8c}, 0x04},
- {PRO_DMOD, 0x0122, {0x02, 0x70, 0xa4}, 0x03},
- {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02},
- {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
- {PRO_DMOD, 0x0137, {0x01, 0x00, 0x07, 0x00, 0x06}, 0x05},
- {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc0, 0x59}, 0x05},
- {PRO_DMOD, 0xf000, {0x0f}, 0x01},
- {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05},
- {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05},
- {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04},
- {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
- {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
- {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
- {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
- {PRO_DMOD, 0xf085, {0xc0, 0x01, 0x00}, 0x03},
- {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
- {PRO_DMOD, 0xf130, {0x04}, 0x01},
- {PRO_DMOD, 0xf132, {0x04}, 0x01},
- {PRO_DMOD, 0xf144, {0x1a}, 0x01},
- {PRO_DMOD, 0xf146, {0x00}, 0x01},
- {PRO_DMOD, 0xf14a, {0x01}, 0x01},
- {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
- {PRO_DMOD, 0xf14f, {0x04}, 0x01},
- {PRO_DMOD, 0xf158, {0x7f}, 0x01},
- {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
- {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
- {PRO_DMOD, 0xf163, {0x05}, 0x01},
- {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
- {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
- {PRO_DMOD, 0xf183, {0x01}, 0x01},
- {PRO_DMOD, 0xf19d, {0x40}, 0x01},
- {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
- {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
- {PRO_DMOD, 0xf204, {0x10}, 0x01},
- {PRO_DMOD, 0xf214, {0x00}, 0x01},
- {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
- {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
- {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
- {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
- {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
- {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
- {PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02},
- {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
- {PRO_DMOD, 0xf5f8, {0x01}, 0x01},
- {PRO_DMOD, 0xf5fd, {0x01}, 0x01},
- {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
- 0x1f}, 0x08},
- {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
- {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
- {PRO_DMOD, 0xf78b, {0x01}, 0x01},
- {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
- {PRO_DMOD, 0xf905, {0x01}, 0x01},
- {PRO_DMOD, 0xfb06, {0x03}, 0x01},
- {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
- {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
-};
-
-static struct it913xset it9135_52[] = {
- {PRO_DMOD, 0x0043, {0x00}, 0x01},
- {PRO_DMOD, 0x0046, {0x52}, 0x01},
- {PRO_DMOD, 0x0051, {0x01}, 0x01},
- {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
- {PRO_DMOD, 0x0068, {0x10}, 0x01},
- {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
- {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xa0, 0x01}, 0x05},
- {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02},
- {PRO_DMOD, 0x0081, { 0x0a, 0x12, 0x03, 0x0a, 0x03, 0xb3, 0x97,
- 0xc0, 0x9e, 0x01}, 0x0a},
- {PRO_DMOD, 0x008e, {0x01}, 0x01},
- {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
- {PRO_DMOD, 0x0099, {0x01}, 0x01},
- {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
- {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
- {PRO_DMOD, 0x00a3, {0x01, 0x5c, 0x01, 0x01}, 0x04},
- {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
- {PRO_DMOD, 0x00b0, {0x01}, 0x01},
- {PRO_DMOD, 0x00b3, {0x02, 0x3c}, 0x02},
- {PRO_DMOD, 0x00b6, {0x14}, 0x01},
- {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03},
- {PRO_DMOD, 0x00c4, {0x00}, 0x01},
- {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
- {PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03},
- {PRO_DMOD, 0x00f3, {0x05, 0x91, 0x8c}, 0x03},
- {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
- {PRO_DMOD, 0x00fc, { 0x03, 0x02, 0x02, 0x09, 0x50, 0x74, 0x77,
- 0x02, 0x02, 0xae, 0x02, 0x6e}, 0x0c},
- {PRO_DMOD, 0x0109, {0x02}, 0x01},
- {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04},
- {PRO_DMOD, 0x011a, {0xcd, 0x62, 0xa4, 0x8c}, 0x04},
- {PRO_DMOD, 0x0122, {0x03, 0x18, 0x9e}, 0x03},
- {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02},
- {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
- {PRO_DMOD, 0x0137, {0x00, 0x00, 0x07, 0x00, 0x06}, 0x05},
- {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xb6, 0x59}, 0x05},
- {PRO_DMOD, 0xf000, {0x0f}, 0x01},
- {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05},
- {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05},
- {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04},
- {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
- {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
- {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
- {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
- {PRO_DMOD, 0xf085, {0xc0, 0x01, 0x00}, 0x03},
- {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
- {PRO_DMOD, 0xf130, {0x04}, 0x01},
- {PRO_DMOD, 0xf132, {0x04}, 0x01},
- {PRO_DMOD, 0xf144, {0x1a}, 0x01},
- {PRO_DMOD, 0xf146, {0x00}, 0x01},
- {PRO_DMOD, 0xf14a, {0x01}, 0x01},
- {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
- {PRO_DMOD, 0xf14f, {0x04}, 0x01},
- {PRO_DMOD, 0xf158, {0x7f}, 0x01},
- {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
- {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
- {PRO_DMOD, 0xf163, {0x05}, 0x01},
- {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
- {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
- {PRO_DMOD, 0xf183, {0x01}, 0x01},
- {PRO_DMOD, 0xf19d, {0x40}, 0x01},
- {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
- {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
- {PRO_DMOD, 0xf204, {0x10}, 0x01},
- {PRO_DMOD, 0xf214, {0x00}, 0x01},
- {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
- {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
- {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
- {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
- {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
- {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
- {PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02},
- {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
- {PRO_DMOD, 0xf5f8, {0x01}, 0x01},
- {PRO_DMOD, 0xf5fd, {0x01}, 0x01},
- {PRO_DMOD, 0xf600, {0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
- 0x1f}, 0x08},
- {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
- {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
- {PRO_DMOD, 0xf78b, {0x01}, 0x01},
- {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
- {PRO_DMOD, 0xf905, {0x01}, 0x01},
- {PRO_DMOD, 0xfb06, {0x03}, 0x01},
- {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
- {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
-};
-
-/* Version 2 types */
-static struct it913xset it9135_v2[] = {
- {PRO_DMOD, 0x0051, {0x01}, 0x01},
- {PRO_DMOD, 0x0070, {0x0a}, 0x01},
- {PRO_DMOD, 0x007e, {0x04}, 0x01},
- {PRO_DMOD, 0x0081, {0x0a}, 0x01},
- {PRO_DMOD, 0x008a, {0x01}, 0x01},
- {PRO_DMOD, 0x008e, {0x01}, 0x01},
- {PRO_DMOD, 0x0092, {0x06}, 0x01},
- {PRO_DMOD, 0x0099, {0x01}, 0x01},
- {PRO_DMOD, 0x009f, {0xe1}, 0x01},
- {PRO_DMOD, 0x00a0, {0xcf}, 0x01},
- {PRO_DMOD, 0x00a3, {0x01}, 0x01},
- {PRO_DMOD, 0x00a5, {0x01}, 0x01},
- {PRO_DMOD, 0x00a6, {0x01}, 0x01},
- {PRO_DMOD, 0x00a9, {0x00}, 0x01},
- {PRO_DMOD, 0x00aa, {0x01}, 0x01},
- {PRO_DMOD, 0x00b0, {0x01}, 0x01},
- {PRO_DMOD, 0x00c2, {0x05}, 0x01},
- {PRO_DMOD, 0x00c6, {0x19}, 0x01},
- {PRO_DMOD, 0xf000, {0x0f}, 0x01},
- {PRO_DMOD, 0xf02b, {0x00}, 0x01},
- {PRO_DMOD, 0xf064, {0x03}, 0x01},
- {PRO_DMOD, 0xf065, {0xf9}, 0x01},
- {PRO_DMOD, 0xf066, {0x03}, 0x01},
- {PRO_DMOD, 0xf067, {0x01}, 0x01},
- {PRO_DMOD, 0xf06f, {0xe0}, 0x01},
- {PRO_DMOD, 0xf070, {0x03}, 0x01},
- {PRO_DMOD, 0xf072, {0x0f}, 0x01},
- {PRO_DMOD, 0xf073, {0x03}, 0x01},
- {PRO_DMOD, 0xf078, {0x00}, 0x01},
- {PRO_DMOD, 0xf087, {0x00}, 0x01},
- {PRO_DMOD, 0xf09b, {0x3f}, 0x01},
- {PRO_DMOD, 0xf09c, {0x00}, 0x01},
- {PRO_DMOD, 0xf09d, {0x20}, 0x01},
- {PRO_DMOD, 0xf09e, {0x00}, 0x01},
- {PRO_DMOD, 0xf09f, {0x0c}, 0x01},
- {PRO_DMOD, 0xf0a0, {0x00}, 0x01},
- {PRO_DMOD, 0xf130, {0x04}, 0x01},
- {PRO_DMOD, 0xf132, {0x04}, 0x01},
- {PRO_DMOD, 0xf144, {0x1a}, 0x01},
- {PRO_DMOD, 0xf146, {0x00}, 0x01},
- {PRO_DMOD, 0xf14a, {0x01}, 0x01},
- {PRO_DMOD, 0xf14c, {0x00}, 0x01},
- {PRO_DMOD, 0xf14d, {0x00}, 0x01},
- {PRO_DMOD, 0xf14f, {0x04}, 0x01},
- {PRO_DMOD, 0xf158, {0x7f}, 0x01},
- {PRO_DMOD, 0xf15a, {0x00}, 0x01},
- {PRO_DMOD, 0xf15b, {0x08}, 0x01},
- {PRO_DMOD, 0xf15d, {0x03}, 0x01},
- {PRO_DMOD, 0xf15e, {0x05}, 0x01},
- {PRO_DMOD, 0xf163, {0x05}, 0x01},
- {PRO_DMOD, 0xf166, {0x01}, 0x01},
- {PRO_DMOD, 0xf167, {0x40}, 0x01},
- {PRO_DMOD, 0xf168, {0x0f}, 0x01},
- {PRO_DMOD, 0xf17a, {0x00}, 0x01},
- {PRO_DMOD, 0xf17b, {0x00}, 0x01},
- {PRO_DMOD, 0xf183, {0x01}, 0x01},
- {PRO_DMOD, 0xf19d, {0x40}, 0x01},
- {PRO_DMOD, 0xf1bc, {0x36}, 0x01},
- {PRO_DMOD, 0xf1bd, {0x00}, 0x01},
- {PRO_DMOD, 0xf1cb, {0xa0}, 0x01},
- {PRO_DMOD, 0xf1cc, {0x01}, 0x01},
- {PRO_DMOD, 0xf204, {0x10}, 0x01},
- {PRO_DMOD, 0xf214, {0x00}, 0x01},
- {PRO_DMOD, 0xf40e, {0x0a}, 0x01},
- {PRO_DMOD, 0xf40f, {0x40}, 0x01},
- {PRO_DMOD, 0xf410, {0x08}, 0x01},
- {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
- {PRO_DMOD, 0xf561, {0x15}, 0x01},
- {PRO_DMOD, 0xf562, {0x20}, 0x01},
- {PRO_DMOD, 0xf5e3, {0x09}, 0x01},
- {PRO_DMOD, 0xf5e4, {0x01}, 0x01},
- {PRO_DMOD, 0xf5e5, {0x01}, 0x01},
- {PRO_DMOD, 0xf600, {0x05}, 0x01},
- {PRO_DMOD, 0xf601, {0x08}, 0x01},
- {PRO_DMOD, 0xf602, {0x0b}, 0x01},
- {PRO_DMOD, 0xf603, {0x0e}, 0x01},
- {PRO_DMOD, 0xf604, {0x11}, 0x01},
- {PRO_DMOD, 0xf605, {0x14}, 0x01},
- {PRO_DMOD, 0xf606, {0x17}, 0x01},
- {PRO_DMOD, 0xf607, {0x1f}, 0x01},
- {PRO_DMOD, 0xf60e, {0x00}, 0x01},
- {PRO_DMOD, 0xf60f, {0x04}, 0x01},
- {PRO_DMOD, 0xf610, {0x32}, 0x01},
- {PRO_DMOD, 0xf611, {0x10}, 0x01},
- {PRO_DMOD, 0xf707, {0xfc}, 0x01},
- {PRO_DMOD, 0xf708, {0x00}, 0x01},
- {PRO_DMOD, 0xf709, {0x37}, 0x01},
- {PRO_DMOD, 0xf70a, {0x00}, 0x01},
- {PRO_DMOD, 0xf78b, {0x01}, 0x01},
- {PRO_DMOD, 0xf80f, {0x40}, 0x01},
- {PRO_DMOD, 0xf810, {0x54}, 0x01},
- {PRO_DMOD, 0xf811, {0x5a}, 0x01},
- {PRO_DMOD, 0xf905, {0x01}, 0x01},
- {PRO_DMOD, 0xfb06, {0x03}, 0x01},
- {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
- {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
-};
-
-static struct it913xset it9135_60[] = {
- {PRO_DMOD, 0x0043, {0x00}, 0x01},
- {PRO_DMOD, 0x0046, {0x60}, 0x01},
- {PRO_DMOD, 0x0051, {0x01}, 0x01},
- {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
- {PRO_DMOD, 0x0068, {0x0a}, 0x01},
- {PRO_DMOD, 0x006a, {0x03}, 0x01},
- {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
- {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x8c, 0x01}, 0x05},
- {PRO_DMOD, 0x007e, {0x04}, 0x01},
- {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02},
- {PRO_DMOD, 0x0084, {0x0a, 0x33, 0xbe, 0xa0, 0xc6, 0xb6, 0x01}, 0x07},
- {PRO_DMOD, 0x008e, {0x01}, 0x01},
- {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
- {PRO_DMOD, 0x0099, {0x01}, 0x01},
- {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
- {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
- {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04},
- {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
- {PRO_DMOD, 0x00b0, {0x01}, 0x01},
- {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02},
- {PRO_DMOD, 0x00b6, {0x14}, 0x01},
- {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05},
- {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
- {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04},
- {PRO_DMOD, 0x00f3, {0x05, 0xa0, 0x8c}, 0x03},
- {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
- {PRO_DMOD, 0x00fc, { 0x03, 0x03, 0x02, 0x0a, 0x50, 0x7b, 0x8c,
- 0x00, 0x02, 0xbe, 0x00}, 0x0b},
- {PRO_DMOD, 0x0109, {0x02}, 0x01},
- {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02},
- {PRO_DMOD, 0x011a, {0xbe}, 0x01},
- {PRO_DMOD, 0x0124, {0xae}, 0x01},
- {PRO_DMOD, 0x0127, {0x00}, 0x01},
- {PRO_DMOD, 0x012a, {0x56, 0x50, 0x47, 0x42}, 0x04},
- {PRO_DMOD, 0x0137, {0x00}, 0x01},
- {PRO_DMOD, 0x013b, {0x08}, 0x01},
- {PRO_DMOD, 0x013f, {0x5b}, 0x01},
- {PRO_DMOD, 0x0141, { 0x59, 0xf9, 0x19, 0x19, 0x8c, 0x8c, 0x8c,
- 0x6e, 0x8c, 0x50, 0x8c, 0x8c, 0xac, 0xc6,
- 0x33}, 0x0f},
- {PRO_DMOD, 0x0151, {0x28}, 0x01},
- {PRO_DMOD, 0x0153, {0xbc}, 0x01},
- {PRO_DMOD, 0x0178, {0x09}, 0x01},
- {PRO_DMOD, 0x0181, {0x94, 0x6e}, 0x02},
- {PRO_DMOD, 0x0185, {0x24}, 0x01},
- {PRO_DMOD, 0x0187, {0x00, 0x00, 0xbe, 0x02, 0x80}, 0x05},
- {PRO_DMOD, 0xed02, {0xff}, 0x01},
- {PRO_DMOD, 0xee42, {0xff}, 0x01},
- {PRO_DMOD, 0xee82, {0xff}, 0x01},
- {PRO_DMOD, 0xf000, {0x0f}, 0x01},
- {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02},
- {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03},
- {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
- {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
- {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
- {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
- {PRO_DMOD, 0xf087, {0x00}, 0x01},
- {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
- {PRO_DMOD, 0xf130, {0x04}, 0x01},
- {PRO_DMOD, 0xf132, {0x04}, 0x01},
- {PRO_DMOD, 0xf144, {0x1a}, 0x01},
- {PRO_DMOD, 0xf146, {0x00}, 0x01},
- {PRO_DMOD, 0xf14a, {0x01}, 0x01},
- {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
- {PRO_DMOD, 0xf14f, {0x04}, 0x01},
- {PRO_DMOD, 0xf158, {0x7f}, 0x01},
- {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
- {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
- {PRO_DMOD, 0xf163, {0x05}, 0x01},
- {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
- {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
- {PRO_DMOD, 0xf183, {0x01}, 0x01},
- {PRO_DMOD, 0xf19d, {0x40}, 0x01},
- {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
- {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
- {PRO_DMOD, 0xf204, {0x10}, 0x01},
- {PRO_DMOD, 0xf214, {0x00}, 0x01},
- {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
- {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
- {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
- {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
- {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
- {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
- {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
- {PRO_DMOD, 0xf600, {0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17
- , 0x1f}, 0x08},
- {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
- {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
- {PRO_DMOD, 0xf78b, {0x01}, 0x01},
- {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
- {PRO_DMOD, 0xf905, {0x01}, 0x01},
- {PRO_DMOD, 0xfb06, {0x03}, 0x01},
- {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
- {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
-};
-
-static struct it913xset it9135_61[] = {
- {PRO_DMOD, 0x0043, {0x00}, 0x01},
- {PRO_DMOD, 0x0046, {0x61}, 0x01},
- {PRO_DMOD, 0x0051, {0x01}, 0x01},
- {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
- {PRO_DMOD, 0x0068, {0x06}, 0x01},
- {PRO_DMOD, 0x006a, {0x03}, 0x01},
- {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
- {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x90, 0x01}, 0x05},
- {PRO_DMOD, 0x007e, {0x04}, 0x01},
- {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02},
- {PRO_DMOD, 0x0084, {0x0a, 0x33, 0xbc, 0x9c, 0xcc, 0xa8, 0x01}, 0x07},
- {PRO_DMOD, 0x008e, {0x01}, 0x01},
- {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
- {PRO_DMOD, 0x0099, {0x01}, 0x01},
- {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
- {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
- {PRO_DMOD, 0x00a3, {0x01, 0x5c, 0x01, 0x01}, 0x04},
- {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
- {PRO_DMOD, 0x00b0, {0x01}, 0x01},
- {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02},
- {PRO_DMOD, 0x00b6, {0x14}, 0x01},
- {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05},
- {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
- {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04},
- {PRO_DMOD, 0x00f3, {0x05, 0xa0, 0x8c}, 0x03},
- {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
- {PRO_DMOD, 0x00fc, { 0x03, 0x03, 0x02, 0x08, 0x50, 0x7b, 0x8c,
- 0x01, 0x02, 0xc8, 0x00}, 0x0b},
- {PRO_DMOD, 0x0109, {0x02}, 0x01},
- {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02},
- {PRO_DMOD, 0x011a, {0xc6}, 0x01},
- {PRO_DMOD, 0x0124, {0xa8}, 0x01},
- {PRO_DMOD, 0x0127, {0x00}, 0x01},
- {PRO_DMOD, 0x012a, {0x59, 0x50, 0x47, 0x42}, 0x04},
- {PRO_DMOD, 0x0137, {0x00}, 0x01},
- {PRO_DMOD, 0x013b, {0x05}, 0x01},
- {PRO_DMOD, 0x013f, {0x5b}, 0x01},
- {PRO_DMOD, 0x0141, { 0x59, 0xf9, 0x59, 0x59, 0x8c, 0x8c, 0x8c,
- 0x7b, 0x8c, 0x50, 0x8c, 0x8c, 0xa8, 0xc6,
- 0x33}, 0x0f},
- {PRO_DMOD, 0x0151, {0x28}, 0x01},
- {PRO_DMOD, 0x0153, {0xcc}, 0x01},
- {PRO_DMOD, 0x0178, {0x09}, 0x01},
- {PRO_DMOD, 0x0181, {0x9c, 0x76}, 0x02},
- {PRO_DMOD, 0x0185, {0x28}, 0x01},
- {PRO_DMOD, 0x0187, {0x01, 0x00, 0xaa, 0x02, 0x80}, 0x05},
- {PRO_DMOD, 0xed02, {0xff}, 0x01},
- {PRO_DMOD, 0xee42, {0xff}, 0x01},
- {PRO_DMOD, 0xee82, {0xff}, 0x01},
- {PRO_DMOD, 0xf000, {0x0f}, 0x01},
- {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02},
- {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03},
- {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
- {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
- {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
- {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
- {PRO_DMOD, 0xf087, {0x00}, 0x01},
- {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
- {PRO_DMOD, 0xf130, {0x04}, 0x01},
- {PRO_DMOD, 0xf132, {0x04}, 0x01},
- {PRO_DMOD, 0xf144, {0x1a}, 0x01},
- {PRO_DMOD, 0xf146, {0x00}, 0x01},
- {PRO_DMOD, 0xf14a, {0x01}, 0x01},
- {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
- {PRO_DMOD, 0xf14f, {0x04}, 0x01},
- {PRO_DMOD, 0xf158, {0x7f}, 0x01},
- {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
- {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
- {PRO_DMOD, 0xf163, {0x05}, 0x01},
- {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
- {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
- {PRO_DMOD, 0xf183, {0x01}, 0x01},
- {PRO_DMOD, 0xf19d, {0x40}, 0x01},
- {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
- {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
- {PRO_DMOD, 0xf204, {0x10}, 0x01},
- {PRO_DMOD, 0xf214, {0x00}, 0x01},
- {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
- {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
- {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
- {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
- {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
- {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
- {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
- {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
- 0x1f}, 0x08},
- {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
- {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
- {PRO_DMOD, 0xf78b, {0x01}, 0x01},
- {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
- {PRO_DMOD, 0xf905, {0x01}, 0x01},
- {PRO_DMOD, 0xfb06, {0x03}, 0x01},
- {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
- {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
-};
-
-static struct it913xset it9135_62[] = {
- {PRO_DMOD, 0x0043, {0x00}, 0x01},
- {PRO_DMOD, 0x0046, {0x62}, 0x01},
- {PRO_DMOD, 0x0051, {0x01}, 0x01},
- {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
- {PRO_DMOD, 0x0068, {0x0a}, 0x01},
- {PRO_DMOD, 0x006a, {0x03}, 0x01},
- {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
- {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x8c, 0x01}, 0x05},
- {PRO_DMOD, 0x007e, {0x04}, 0x01},
- {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02},
- {PRO_DMOD, 0x0084, { 0x0a, 0x33, 0xb8, 0x9c, 0xb2, 0xa6, 0x01},
- 0x07},
- {PRO_DMOD, 0x008e, {0x01}, 0x01},
- {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
- {PRO_DMOD, 0x0099, {0x01}, 0x01},
- {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
- {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
- {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04},
- {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
- {PRO_DMOD, 0x00b0, {0x01}, 0x01},
- {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02},
- {PRO_DMOD, 0x00b6, {0x14}, 0x01},
- {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05},
- {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
- {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04},
- {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03},
- {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
- {PRO_DMOD, 0x00fc, { 0x02, 0x03, 0x02, 0x09, 0x50, 0x6e, 0x8c,
- 0x02, 0x02, 0xc2, 0x00}, 0x0b},
- {PRO_DMOD, 0x0109, {0x02}, 0x01},
- {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02},
- {PRO_DMOD, 0x011a, {0xb8}, 0x01},
- {PRO_DMOD, 0x0124, {0xa8}, 0x01},
- {PRO_DMOD, 0x0127, {0x00}, 0x01},
- {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
- {PRO_DMOD, 0x0137, {0x00}, 0x01},
- {PRO_DMOD, 0x013b, {0x05}, 0x01},
- {PRO_DMOD, 0x013f, {0x5b}, 0x01},
- {PRO_DMOD, 0x0141, { 0x59, 0xf9, 0x59, 0x19, 0x8c, 0x8c, 0x8c,
- 0x7b, 0x8c, 0x50, 0x70, 0x8c, 0x96, 0xd0,
- 0x33}, 0x0f},
- {PRO_DMOD, 0x0151, {0x28}, 0x01},
- {PRO_DMOD, 0x0153, {0xb2}, 0x01},
- {PRO_DMOD, 0x0178, {0x09}, 0x01},
- {PRO_DMOD, 0x0181, {0x9c, 0x6e}, 0x02},
- {PRO_DMOD, 0x0185, {0x24}, 0x01},
- {PRO_DMOD, 0x0187, {0x00, 0x00, 0xb8, 0x02, 0x80}, 0x05},
- {PRO_DMOD, 0xed02, {0xff}, 0x01},
- {PRO_DMOD, 0xee42, {0xff}, 0x01},
- {PRO_DMOD, 0xee82, {0xff}, 0x01},
- {PRO_DMOD, 0xf000, {0x0f}, 0x01},
- {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02},
- {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03},
- {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
- {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
- {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
- {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
- {PRO_DMOD, 0xf087, {0x00}, 0x01},
- {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
- {PRO_DMOD, 0xf130, {0x04}, 0x01},
- {PRO_DMOD, 0xf132, {0x04}, 0x01},
- {PRO_DMOD, 0xf144, {0x1a}, 0x01},
- {PRO_DMOD, 0xf146, {0x00}, 0x01},
- {PRO_DMOD, 0xf14a, {0x01}, 0x01},
- {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
- {PRO_DMOD, 0xf14f, {0x04}, 0x01},
- {PRO_DMOD, 0xf158, {0x7f}, 0x01},
- {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
- {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
- {PRO_DMOD, 0xf163, {0x05}, 0x01},
- {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
- {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
- {PRO_DMOD, 0xf183, {0x01}, 0x01},
- {PRO_DMOD, 0xf19d, {0x40}, 0x01},
- {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
- {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
- {PRO_DMOD, 0xf204, {0x10}, 0x01},
- {PRO_DMOD, 0xf214, {0x00}, 0x01},
- {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
- {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
- {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
- {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
- {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
- {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
- {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
- {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
- 0x1f}, 0x08},
- {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
- {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
- {PRO_DMOD, 0xf78b, {0x01}, 0x01},
- {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
- {PRO_DMOD, 0xf905, {0x01}, 0x01},
- {PRO_DMOD, 0xfb06, {0x03}, 0x01},
- {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
- {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
-};
-
-/* Tuner setting scripts (still keeping it9137) */
-static struct it913xset it9137_tuner_off[] = {
- {PRO_DMOD, 0xfba8, {0x01}, 0x01}, /* Tuner Clock Off */
- {PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */
- {PRO_DMOD, 0xec02, {0x3f, 0x1f, 0x3f, 0x3f}, 0x04},
- {PRO_DMOD, 0xec06, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}, 0x0c},
- {PRO_DMOD, 0xec12, {0x00, 0x00, 0x00, 0x00}, 0x04},
- {PRO_DMOD, 0xec17, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00}, 0x09},
- {PRO_DMOD, 0xec22, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00}, 0x0a},
- {PRO_DMOD, 0xec20, {0x00}, 0x01},
- {PRO_DMOD, 0xec3f, {0x01}, 0x01},
- {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
-};
-
-static struct it913xset set_it9135_template[] = {
- {PRO_DMOD, 0xee06, {0x00}, 0x01},
- {PRO_DMOD, 0xec56, {0x00}, 0x01},
- {PRO_DMOD, 0xec4c, {0x00}, 0x01},
- {PRO_DMOD, 0xec4d, {0x00}, 0x01},
- {PRO_DMOD, 0xec4e, {0x00}, 0x01},
- {PRO_DMOD, 0x011e, {0x00}, 0x01}, /* Older Devices */
- {PRO_DMOD, 0x011f, {0x00}, 0x01},
- {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
-};
-
-static struct it913xset set_it9137_template[] = {
- {PRO_DMOD, 0xee06, {0x00}, 0x01},
- {PRO_DMOD, 0xec56, {0x00}, 0x01},
- {PRO_DMOD, 0xec4c, {0x00}, 0x01},
- {PRO_DMOD, 0xec4d, {0x00}, 0x01},
- {PRO_DMOD, 0xec4e, {0x00}, 0x01},
- {PRO_DMOD, 0xec4f, {0x00}, 0x01},
- {PRO_DMOD, 0xec50, {0x00}, 0x01},
- {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
-};
diff --git a/drivers/media/dvb-frontends/it913x-fe.c b/drivers/media/dvb-frontends/it913x-fe.c
deleted file mode 100644
index 6e1c6eb340b7..000000000000
--- a/drivers/media/dvb-frontends/it913x-fe.c
+++ /dev/null
@@ -1,1045 +0,0 @@
-/*
- * Driver for it913x-fe Frontend
- *
- * with support for on chip it9137 integral tuner
- *
- * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
- * IT9137 Copyright (C) ITE Tech Inc.
- *
- * 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/init.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-
-#include "dvb_frontend.h"
-#include "it913x-fe.h"
-#include "it913x-fe-priv.h"
-
-static int it913x_debug;
-
-module_param_named(debug, it913x_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
-
-#define dprintk(level, args...) do { \
- if (level & it913x_debug) \
- printk(KERN_DEBUG "it913x-fe: " args); \
-} while (0)
-
-#define deb_info(args...) dprintk(0x01, args)
-#define debug_data_snipet(level, name, p) \
- dprintk(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \
- *p, *(p+1), *(p+2), *(p+3), *(p+4), \
- *(p+5), *(p+6), *(p+7));
-#define info(format, arg...) \
- printk(KERN_INFO "it913x-fe: " format "\n" , ## arg)
-
-struct it913x_fe_state {
- struct dvb_frontend frontend;
- struct i2c_adapter *i2c_adap;
- struct ite_config *config;
- u8 i2c_addr;
- u32 frequency;
- fe_modulation_t constellation;
- fe_transmit_mode_t transmission_mode;
- u8 priority;
- u32 crystalFrequency;
- u32 adcFrequency;
- u8 tuner_type;
- struct adctable *table;
- fe_status_t it913x_status;
- u16 tun_xtal;
- u8 tun_fdiv;
- u8 tun_clk_mode;
- u32 tun_fn_min;
- u32 ucblocks;
-};
-
-static int it913x_read_reg(struct it913x_fe_state *state,
- u32 reg, u8 *data, u8 count)
-{
- int ret;
- u8 pro = PRO_DMOD; /* All reads from demodulator */
- u8 b[4];
- struct i2c_msg msg[2] = {
- { .addr = state->i2c_addr + (pro << 1), .flags = 0,
- .buf = b, .len = sizeof(b) },
- { .addr = state->i2c_addr + (pro << 1), .flags = I2C_M_RD,
- .buf = data, .len = count }
- };
- b[0] = (u8) reg >> 24;
- b[1] = (u8)(reg >> 16) & 0xff;
- b[2] = (u8)(reg >> 8) & 0xff;
- b[3] = (u8) reg & 0xff;
-
- ret = i2c_transfer(state->i2c_adap, msg, 2);
-
- return ret;
-}
-
-static int it913x_read_reg_u8(struct it913x_fe_state *state, u32 reg)
-{
- int ret;
- u8 b[1];
- ret = it913x_read_reg(state, reg, &b[0], sizeof(b));
- return (ret < 0) ? -ENODEV : b[0];
-}
-
-static int it913x_write(struct it913x_fe_state *state,
- u8 pro, u32 reg, u8 buf[], u8 count)
-{
- u8 b[256];
- struct i2c_msg msg[1] = {
- { .addr = state->i2c_addr + (pro << 1), .flags = 0,
- .buf = b, .len = count + 4 }
- };
- int ret;
-
- b[0] = (u8) reg >> 24;
- b[1] = (u8)(reg >> 16) & 0xff;
- b[2] = (u8)(reg >> 8) & 0xff;
- b[3] = (u8) reg & 0xff;
- memcpy(&b[4], buf, count);
-
- ret = i2c_transfer(state->i2c_adap, msg, 1);
-
- if (ret < 0)
- return -EIO;
-
- return 0;
-}
-
-static int it913x_write_reg(struct it913x_fe_state *state,
- u8 pro, u32 reg, u32 data)
-{
- int ret;
- u8 b[4];
- u8 s;
-
- b[0] = data >> 24;
- b[1] = (data >> 16) & 0xff;
- b[2] = (data >> 8) & 0xff;
- b[3] = data & 0xff;
- /* expand write as needed */
- if (data < 0x100)
- s = 3;
- else if (data < 0x1000)
- s = 2;
- else if (data < 0x100000)
- s = 1;
- else
- s = 0;
-
- ret = it913x_write(state, pro, reg, &b[s], sizeof(b) - s);
-
- return ret;
-}
-
-static int it913x_fe_script_loader(struct it913x_fe_state *state,
- struct it913xset *loadscript)
-{
- int ret, i;
- if (loadscript == NULL)
- return -EINVAL;
-
- for (i = 0; i < 1000; ++i) {
- if (loadscript[i].pro == 0xff)
- break;
- ret = it913x_write(state, loadscript[i].pro,
- loadscript[i].address,
- loadscript[i].reg, loadscript[i].count);
- if (ret < 0)
- return -ENODEV;
- }
- return 0;
-}
-
-static int it913x_init_tuner(struct it913x_fe_state *state)
-{
- int ret, i, reg;
- u8 val, nv_val;
- u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2};
- u8 b[2];
-
- reg = it913x_read_reg_u8(state, 0xec86);
- switch (reg) {
- case 0:
- state->tun_clk_mode = reg;
- state->tun_xtal = 2000;
- state->tun_fdiv = 3;
- val = 16;
- break;
- case -ENODEV:
- return -ENODEV;
- case 1:
- default:
- state->tun_clk_mode = reg;
- state->tun_xtal = 640;
- state->tun_fdiv = 1;
- val = 6;
- break;
- }
-
- reg = it913x_read_reg_u8(state, 0xed03);
-
- if (reg < 0)
- return -ENODEV;
- else if (reg < ARRAY_SIZE(nv))
- nv_val = nv[reg];
- else
- nv_val = 2;
-
- for (i = 0; i < 50; i++) {
- ret = it913x_read_reg(state, 0xed23, &b[0], sizeof(b));
- reg = (b[1] << 8) + b[0];
- if (reg > 0)
- break;
- if (ret < 0)
- return -ENODEV;
- udelay(2000);
- }
- state->tun_fn_min = state->tun_xtal * reg;
- state->tun_fn_min /= (state->tun_fdiv * nv_val);
- deb_info("Tuner fn_min %d", state->tun_fn_min);
-
- if (state->config->chip_ver > 1)
- msleep(50);
- else {
- for (i = 0; i < 50; i++) {
- reg = it913x_read_reg_u8(state, 0xec82);
- if (reg > 0)
- break;
- if (reg < 0)
- return -ENODEV;
- udelay(2000);
- }
- }
-
- return it913x_write_reg(state, PRO_DMOD, 0xed81, val);
-}
-
-static int it9137_set_tuner(struct it913x_fe_state *state,
- u32 bandwidth, u32 frequency_m)
-{
- struct it913xset *set_tuner = set_it9137_template;
- int ret, reg;
- u32 frequency = frequency_m / 1000;
- u32 freq, temp_f, tmp;
- u16 iqik_m_cal;
- u16 n_div;
- u8 n;
- u8 l_band;
- u8 lna_band;
- u8 bw;
-
- if (state->config->firmware_ver == 1)
- set_tuner = set_it9135_template;
- else
- set_tuner = set_it9137_template;
-
- deb_info("Tuner Frequency %d Bandwidth %d", frequency, bandwidth);
-
- if (frequency >= 51000 && frequency <= 440000) {
- l_band = 0;
- lna_band = 0;
- } else if (frequency > 440000 && frequency <= 484000) {
- l_band = 1;
- lna_band = 1;
- } else if (frequency > 484000 && frequency <= 533000) {
- l_band = 1;
- lna_band = 2;
- } else if (frequency > 533000 && frequency <= 587000) {
- l_band = 1;
- lna_band = 3;
- } else if (frequency > 587000 && frequency <= 645000) {
- l_band = 1;
- lna_band = 4;
- } else if (frequency > 645000 && frequency <= 710000) {
- l_band = 1;
- lna_band = 5;
- } else if (frequency > 710000 && frequency <= 782000) {
- l_band = 1;
- lna_band = 6;
- } else if (frequency > 782000 && frequency <= 860000) {
- l_band = 1;
- lna_band = 7;
- } else if (frequency > 1450000 && frequency <= 1492000) {
- l_band = 1;
- lna_band = 0;
- } else if (frequency > 1660000 && frequency <= 1685000) {
- l_band = 1;
- lna_band = 1;
- } else
- return -EINVAL;
- set_tuner[0].reg[0] = lna_band;
-
- switch (bandwidth) {
- case 5000000:
- bw = 0;
- break;
- case 6000000:
- bw = 2;
- break;
- case 7000000:
- bw = 4;
- break;
- default:
- case 8000000:
- bw = 6;
- break;
- }
-
- set_tuner[1].reg[0] = bw;
- set_tuner[2].reg[0] = 0xa0 | (l_band << 3);
-
- if (frequency > 53000 && frequency <= 74000) {
- n_div = 48;
- n = 0;
- } else if (frequency > 74000 && frequency <= 111000) {
- n_div = 32;
- n = 1;
- } else if (frequency > 111000 && frequency <= 148000) {
- n_div = 24;
- n = 2;
- } else if (frequency > 148000 && frequency <= 222000) {
- n_div = 16;
- n = 3;
- } else if (frequency > 222000 && frequency <= 296000) {
- n_div = 12;
- n = 4;
- } else if (frequency > 296000 && frequency <= 445000) {
- n_div = 8;
- n = 5;
- } else if (frequency > 445000 && frequency <= state->tun_fn_min) {
- n_div = 6;
- n = 6;
- } else if (frequency > state->tun_fn_min && frequency <= 950000) {
- n_div = 4;
- n = 7;
- } else if (frequency > 1450000 && frequency <= 1680000) {
- n_div = 2;
- n = 0;
- } else
- return -EINVAL;
-
- reg = it913x_read_reg_u8(state, 0xed81);
- iqik_m_cal = (u16)reg * n_div;
-
- if (reg < 0x20) {
- if (state->tun_clk_mode == 0)
- iqik_m_cal = (iqik_m_cal * 9) >> 5;
- else
- iqik_m_cal >>= 1;
- } else {
- iqik_m_cal = 0x40 - iqik_m_cal;
- if (state->tun_clk_mode == 0)
- iqik_m_cal = ~((iqik_m_cal * 9) >> 5);
- else
- iqik_m_cal = ~(iqik_m_cal >> 1);
- }
-
- temp_f = frequency * (u32)n_div * (u32)state->tun_fdiv;
- freq = temp_f / state->tun_xtal;
- tmp = freq * state->tun_xtal;
-
- if ((temp_f - tmp) >= (state->tun_xtal >> 1))
- freq++;
-
- freq += (u32) n << 13;
- /* Frequency OMEGA_IQIK_M_CAL_MID*/
- temp_f = freq + (u32)iqik_m_cal;
-
- set_tuner[3].reg[0] = temp_f & 0xff;
- set_tuner[4].reg[0] = (temp_f >> 8) & 0xff;
-
- deb_info("High Frequency = %04x", temp_f);
-
- /* Lower frequency */
- set_tuner[5].reg[0] = freq & 0xff;
- set_tuner[6].reg[0] = (freq >> 8) & 0xff;
-
- deb_info("low Frequency = %04x", freq);
-
- ret = it913x_fe_script_loader(state, set_tuner);
-
- return (ret < 0) ? -ENODEV : 0;
-}
-
-static int it913x_fe_select_bw(struct it913x_fe_state *state,
- u32 bandwidth, u32 adcFrequency)
-{
- int ret, i;
- u8 buffer[256];
- u32 coeff[8];
- u16 bfsfcw_fftinx_ratio;
- u16 fftinx_bfsfcw_ratio;
- u8 count;
- u8 bw;
- u8 adcmultiplier;
-
- deb_info("Bandwidth %d Adc %d", bandwidth, adcFrequency);
-
- switch (bandwidth) {
- case 5000000:
- bw = 3;
- break;
- case 6000000:
- bw = 0;
- break;
- case 7000000:
- bw = 1;
- break;
- default:
- case 8000000:
- bw = 2;
- break;
- }
- ret = it913x_write_reg(state, PRO_DMOD, REG_BW, bw);
-
- if (state->table == NULL)
- return -EINVAL;
-
- /* In write order */
- coeff[0] = state->table[bw].coeff_1_2048;
- coeff[1] = state->table[bw].coeff_2_2k;
- coeff[2] = state->table[bw].coeff_1_8191;
- coeff[3] = state->table[bw].coeff_1_8192;
- coeff[4] = state->table[bw].coeff_1_8193;
- coeff[5] = state->table[bw].coeff_2_8k;
- coeff[6] = state->table[bw].coeff_1_4096;
- coeff[7] = state->table[bw].coeff_2_4k;
- bfsfcw_fftinx_ratio = state->table[bw].bfsfcw_fftinx_ratio;
- fftinx_bfsfcw_ratio = state->table[bw].fftinx_bfsfcw_ratio;
-
- /* ADC multiplier */
- ret = it913x_read_reg_u8(state, ADC_X_2);
- if (ret < 0)
- return -EINVAL;
-
- adcmultiplier = ret;
-
- count = 0;
-
- /* Build Buffer for COEFF Registers */
- for (i = 0; i < 8; i++) {
- if (adcmultiplier == 1)
- coeff[i] /= 2;
- buffer[count++] = (coeff[i] >> 24) & 0x3;
- buffer[count++] = (coeff[i] >> 16) & 0xff;
- buffer[count++] = (coeff[i] >> 8) & 0xff;
- buffer[count++] = coeff[i] & 0xff;
- }
-
- /* bfsfcw_fftinx_ratio register 0x21-0x22 */
- buffer[count++] = bfsfcw_fftinx_ratio & 0xff;
- buffer[count++] = (bfsfcw_fftinx_ratio >> 8) & 0xff;
- /* fftinx_bfsfcw_ratio register 0x23-0x24 */
- buffer[count++] = fftinx_bfsfcw_ratio & 0xff;
- buffer[count++] = (fftinx_bfsfcw_ratio >> 8) & 0xff;
- /* start at COEFF_1_2048 and write through to fftinx_bfsfcw_ratio*/
- ret = it913x_write(state, PRO_DMOD, COEFF_1_2048, buffer, count);
-
- for (i = 0; i < 42; i += 8)
- debug_data_snipet(0x1, "Buffer", &buffer[i]);
-
- return ret;
-}
-
-
-
-static int it913x_fe_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
- struct it913x_fe_state *state = fe->demodulator_priv;
- int ret, i;
- fe_status_t old_status = state->it913x_status;
- *status = 0;
-
- if (state->it913x_status == 0) {
- ret = it913x_read_reg_u8(state, EMPTY_CHANNEL_STATUS);
- if (ret == 0x1) {
- *status |= FE_HAS_SIGNAL;
- for (i = 0; i < 40; i++) {
- ret = it913x_read_reg_u8(state, MP2IF_SYNC_LK);
- if (ret == 0x1)
- break;
- msleep(25);
- }
- if (ret == 0x1)
- *status |= FE_HAS_CARRIER
- | FE_HAS_VITERBI
- | FE_HAS_SYNC;
- state->it913x_status = *status;
- }
- }
-
- if (state->it913x_status & FE_HAS_SYNC) {
- ret = it913x_read_reg_u8(state, TPSD_LOCK);
- if (ret == 0x1)
- *status |= FE_HAS_LOCK
- | state->it913x_status;
- else
- state->it913x_status = 0;
- if (old_status != state->it913x_status)
- ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, ret);
- }
-
- return 0;
-}
-
-/* FEC values based on fe_code_rate_t non supported values 0*/
-int it913x_qpsk_pval[] = {0, -93, -91, -90, 0, -89, -88};
-int it913x_16qam_pval[] = {0, -87, -85, -84, 0, -83, -82};
-int it913x_64qam_pval[] = {0, -82, -80, -78, 0, -77, -76};
-
-static int it913x_get_signal_strength(struct dvb_frontend *fe)
-{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
- struct it913x_fe_state *state = fe->demodulator_priv;
- u8 code_rate;
- int ret, temp;
- u8 lna_gain_os;
-
- ret = it913x_read_reg_u8(state, VAR_P_INBAND);
- if (ret < 0)
- return ret;
-
- /* VHF/UHF gain offset */
- if (state->frequency < 300000000)
- lna_gain_os = 7;
- else
- lna_gain_os = 14;
-
- temp = (ret - 100) - lna_gain_os;
-
- if (state->priority == PRIORITY_HIGH)
- code_rate = p->code_rate_HP;
- else
- code_rate = p->code_rate_LP;
-
- if (code_rate >= ARRAY_SIZE(it913x_qpsk_pval))
- return -EINVAL;
-
- deb_info("Reg VAR_P_INBAND:%d Calc Offset Value:%d", ret, temp);
-
- /* Apply FEC offset values*/
- switch (p->modulation) {
- case QPSK:
- temp -= it913x_qpsk_pval[code_rate];
- break;
- case QAM_16:
- temp -= it913x_16qam_pval[code_rate];
- break;
- case QAM_64:
- temp -= it913x_64qam_pval[code_rate];
- break;
- default:
- return -EINVAL;
- }
-
- if (temp < -15)
- ret = 0;
- else if ((-15 <= temp) && (temp < 0))
- ret = (2 * (temp + 15)) / 3;
- else if ((0 <= temp) && (temp < 20))
- ret = 4 * temp + 10;
- else if ((20 <= temp) && (temp < 35))
- ret = (2 * (temp - 20)) / 3 + 90;
- else if (temp >= 35)
- ret = 100;
-
- deb_info("Signal Strength :%d", ret);
-
- return ret;
-}
-
-static int it913x_fe_read_signal_strength(struct dvb_frontend *fe,
- u16 *strength)
-{
- struct it913x_fe_state *state = fe->demodulator_priv;
- int ret = 0;
- if (state->config->read_slevel) {
- if (state->it913x_status & FE_HAS_SIGNAL)
- ret = it913x_read_reg_u8(state, SIGNAL_LEVEL);
- } else
- ret = it913x_get_signal_strength(fe);
-
- if (ret >= 0)
- *strength = (u16)((u32)ret * 0xffff / 0x64);
-
- return (ret < 0) ? -ENODEV : 0;
-}
-
-static int it913x_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
- struct it913x_fe_state *state = fe->demodulator_priv;
- int ret;
- u8 reg[3];
- u32 snr_val, snr_min, snr_max;
- u32 temp;
-
- ret = it913x_read_reg(state, 0x2c, reg, sizeof(reg));
-
- snr_val = (u32)(reg[2] << 16) | (reg[1] << 8) | reg[0];
-
- ret |= it913x_read_reg(state, 0xf78b, reg, 1);
- if (reg[0])
- snr_val /= reg[0];
-
- if (state->transmission_mode == TRANSMISSION_MODE_2K)
- snr_val *= 4;
- else if (state->transmission_mode == TRANSMISSION_MODE_4K)
- snr_val *= 2;
-
- if (state->constellation == QPSK) {
- snr_min = 0xb4711;
- snr_max = 0x191451;
- } else if (state->constellation == QAM_16) {
- snr_min = 0x4f0d5;
- snr_max = 0xc7925;
- } else if (state->constellation == QAM_64) {
- snr_min = 0x256d0;
- snr_max = 0x626be;
- } else
- return -EINVAL;
-
- if (snr_val < snr_min)
- *snr = 0;
- else if (snr_val < snr_max) {
- temp = (snr_val - snr_min) >> 5;
- temp *= 0xffff;
- temp /= (snr_max - snr_min) >> 5;
- *snr = (u16)temp;
- } else
- *snr = 0xffff;
-
- return (ret < 0) ? -ENODEV : 0;
-}
-
-static int it913x_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
- struct it913x_fe_state *state = fe->demodulator_priv;
- u8 reg[5];
- /* Read Aborted Packets and Pre-Viterbi error rate 5 bytes */
- it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg));
- state->ucblocks += (u32)(reg[1] << 8) | reg[0];
- *ber = (u32)(reg[4] << 16) | (reg[3] << 8) | reg[2];
- return 0;
-}
-
-static int it913x_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
- struct it913x_fe_state *state = fe->demodulator_priv;
- int ret;
- u8 reg[2];
- /* Aborted Packets */
- ret = it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg));
- state->ucblocks += (u32)(reg[1] << 8) | reg[0];
- *ucblocks = state->ucblocks;
- return ret;
-}
-
-static int it913x_fe_get_frontend(struct dvb_frontend *fe)
-{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
- struct it913x_fe_state *state = fe->demodulator_priv;
- u8 reg[8];
-
- it913x_read_reg(state, REG_TPSD_TX_MODE, reg, sizeof(reg));
-
- if (reg[3] < 3)
- p->modulation = fe_con[reg[3]];
-
- if (reg[0] < 3)
- p->transmission_mode = fe_mode[reg[0]];
-
- if (reg[1] < 4)
- p->guard_interval = fe_gi[reg[1]];
-
- if (reg[2] < 4)
- p->hierarchy = fe_hi[reg[2]];
-
- state->priority = reg[5];
-
- p->code_rate_HP = (reg[6] < 6) ? fe_code[reg[6]] : FEC_NONE;
- p->code_rate_LP = (reg[7] < 6) ? fe_code[reg[7]] : FEC_NONE;
-
- /* Update internal state to reflect the autodetected props */
- state->constellation = p->modulation;
- state->transmission_mode = p->transmission_mode;
-
- return 0;
-}
-
-static int it913x_fe_set_frontend(struct dvb_frontend *fe)
-{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
- struct it913x_fe_state *state = fe->demodulator_priv;
- int i;
- u8 empty_ch, last_ch;
-
- state->it913x_status = 0;
-
- /* Set bw*/
- it913x_fe_select_bw(state, p->bandwidth_hz,
- state->adcFrequency);
-
- /* Training Mode Off */
- it913x_write_reg(state, PRO_LINK, TRAINING_MODE, 0x0);
-
- /* Clear Empty Channel */
- it913x_write_reg(state, PRO_DMOD, EMPTY_CHANNEL_STATUS, 0x0);
-
- /* Clear bits */
- it913x_write_reg(state, PRO_DMOD, MP2IF_SYNC_LK, 0x0);
- /* LED on */
- it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1);
- /* Select Band*/
- if ((p->frequency >= 51000000) && (p->frequency <= 230000000))
- i = 0;
- else if ((p->frequency >= 350000000) && (p->frequency <= 900000000))
- i = 1;
- else if ((p->frequency >= 1450000000) && (p->frequency <= 1680000000))
- i = 2;
- else
- return -EOPNOTSUPP;
-
- it913x_write_reg(state, PRO_DMOD, FREE_BAND, i);
-
- deb_info("Frontend Set Tuner Type %02x", state->tuner_type);
- switch (state->tuner_type) {
- case IT9135_38:
- case IT9135_51:
- case IT9135_52:
- case IT9135_60:
- case IT9135_61:
- case IT9135_62:
- it9137_set_tuner(state,
- p->bandwidth_hz, p->frequency);
- break;
- default:
- if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
- }
- break;
- }
- /* LED off */
- it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0);
- /* Trigger ofsm */
- it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0);
- last_ch = 2;
- for (i = 0; i < 40; ++i) {
- empty_ch = it913x_read_reg_u8(state, EMPTY_CHANNEL_STATUS);
- if (last_ch == 1 && empty_ch == 1)
- break;
- if (last_ch == 2 && empty_ch == 2)
- return 0;
- last_ch = empty_ch;
- msleep(25);
- }
- for (i = 0; i < 40; ++i) {
- if (it913x_read_reg_u8(state, D_TPSD_LOCK) == 1)
- break;
- msleep(25);
- }
-
- state->frequency = p->frequency;
- return 0;
-}
-
-static int it913x_fe_suspend(struct it913x_fe_state *state)
-{
- int ret, i;
- u8 b;
-
- ret = it913x_write_reg(state, PRO_DMOD, SUSPEND_FLAG, 0x1);
-
- ret |= it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0);
-
- for (i = 0; i < 128; i++) {
- ret = it913x_read_reg(state, SUSPEND_FLAG, &b, 1);
- if (ret < 0)
- return -ENODEV;
- if (b == 0)
- break;
-
- }
-
- ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x8);
- /* Turn LED off */
- ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0);
-
- ret |= it913x_fe_script_loader(state, it9137_tuner_off);
-
- return (ret < 0) ? -ENODEV : 0;
-}
-
-/* Power sequence */
-/* Power Up Tuner on -> Frontend suspend off -> Tuner clk on */
-/* Power Down Frontend suspend on -> Tuner clk off -> Tuner off */
-
-static int it913x_fe_sleep(struct dvb_frontend *fe)
-{
- struct it913x_fe_state *state = fe->demodulator_priv;
- return it913x_fe_suspend(state);
-}
-
-static u32 compute_div(u32 a, u32 b, u32 x)
-{
- u32 res = 0;
- u32 c = 0;
- u32 i = 0;
-
- if (a > b) {
- c = a / b;
- a = a - c * b;
- }
-
- for (i = 0; i < x; i++) {
- if (a >= b) {
- res += 1;
- a -= b;
- }
- a <<= 1;
- res <<= 1;
- }
-
- res = (c << x) + res;
-
- return res;
-}
-
-static int it913x_fe_start(struct it913x_fe_state *state)
-{
- struct it913xset *set_lna;
- struct it913xset *set_mode;
- int ret;
- u8 adf = (state->config->adf & 0xf);
- u32 adc, xtal;
- u8 b[4];
-
- if (state->config->chip_ver == 1)
- ret = it913x_init_tuner(state);
-
- info("ADF table value :%02x", adf);
-
- if (adf < 10) {
- state->crystalFrequency = fe_clockTable[adf].xtal ;
- state->table = fe_clockTable[adf].table;
- state->adcFrequency = state->table->adcFrequency;
-
- adc = compute_div(state->adcFrequency, 1000000ul, 19ul);
- xtal = compute_div(state->crystalFrequency, 1000000ul, 19ul);
-
- } else
- return -EINVAL;
-
- /* Set LED indicator on GPIOH3 */
- ret = it913x_write_reg(state, PRO_LINK, GPIOH3_EN, 0x1);
- ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_ON, 0x1);
- ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1);
-
- ret |= it913x_write_reg(state, PRO_LINK, 0xf641, state->tuner_type);
- ret |= it913x_write_reg(state, PRO_DMOD, 0xf5ca, 0x01);
- ret |= it913x_write_reg(state, PRO_DMOD, 0xf715, 0x01);
-
- b[0] = xtal & 0xff;
- b[1] = (xtal >> 8) & 0xff;
- b[2] = (xtal >> 16) & 0xff;
- b[3] = (xtal >> 24);
- ret |= it913x_write(state, PRO_DMOD, XTAL_CLK, b , 4);
-
- b[0] = adc & 0xff;
- b[1] = (adc >> 8) & 0xff;
- b[2] = (adc >> 16) & 0xff;
- ret |= it913x_write(state, PRO_DMOD, ADC_FREQ, b, 3);
-
- if (state->config->adc_x2)
- ret |= it913x_write_reg(state, PRO_DMOD, ADC_X_2, 0x01);
- b[0] = 0;
- b[1] = 0;
- b[2] = 0;
- ret |= it913x_write(state, PRO_DMOD, 0x0029, b, 3);
-
- info("Crystal Frequency :%d Adc Frequency :%d ADC X2: %02x",
- state->crystalFrequency, state->adcFrequency,
- state->config->adc_x2);
- deb_info("Xtal value :%04x Adc value :%04x", xtal, adc);
-
- if (ret < 0)
- return -ENODEV;
-
- /* v1 or v2 tuner script */
- if (state->config->chip_ver > 1)
- ret = it913x_fe_script_loader(state, it9135_v2);
- else
- ret = it913x_fe_script_loader(state, it9135_v1);
- if (ret < 0)
- return ret;
-
- /* LNA Scripts */
- switch (state->tuner_type) {
- case IT9135_51:
- set_lna = it9135_51;
- break;
- case IT9135_52:
- set_lna = it9135_52;
- break;
- case IT9135_60:
- set_lna = it9135_60;
- break;
- case IT9135_61:
- set_lna = it9135_61;
- break;
- case IT9135_62:
- set_lna = it9135_62;
- break;
- case IT9135_38:
- default:
- set_lna = it9135_38;
- }
- info("Tuner LNA type :%02x", state->tuner_type);
-
- ret = it913x_fe_script_loader(state, set_lna);
- if (ret < 0)
- return ret;
-
- if (state->config->chip_ver == 2) {
- ret = it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x1);
- ret |= it913x_write_reg(state, PRO_LINK, PADODPU, 0x0);
- ret |= it913x_write_reg(state, PRO_LINK, AGC_O_D, 0x0);
- ret |= it913x_init_tuner(state);
- }
- if (ret < 0)
- return -ENODEV;
-
- /* Always solo frontend */
- set_mode = set_solo_fe;
- ret |= it913x_fe_script_loader(state, set_mode);
-
- ret |= it913x_fe_suspend(state);
- return (ret < 0) ? -ENODEV : 0;
-}
-
-static int it913x_fe_init(struct dvb_frontend *fe)
-{
- struct it913x_fe_state *state = fe->demodulator_priv;
- int ret = 0;
- /* Power Up Tuner - common all versions */
- ret = it913x_write_reg(state, PRO_DMOD, 0xec40, 0x1);
-
- ret |= it913x_fe_script_loader(state, init_1);
-
- ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x0);
-
- ret |= it913x_write_reg(state, PRO_DMOD, 0xfba8, 0x0);
-
- return (ret < 0) ? -ENODEV : 0;
-}
-
-static void it913x_fe_release(struct dvb_frontend *fe)
-{
- struct it913x_fe_state *state = fe->demodulator_priv;
- kfree(state);
-}
-
-static struct dvb_frontend_ops it913x_fe_ofdm_ops;
-
-struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap,
- u8 i2c_addr, struct ite_config *config)
-{
- struct it913x_fe_state *state = NULL;
- int ret;
-
- /* allocate memory for the internal state */
- state = kzalloc(sizeof(struct it913x_fe_state), GFP_KERNEL);
- if (state == NULL)
- return NULL;
- if (config == NULL)
- goto error;
-
- state->i2c_adap = i2c_adap;
- state->i2c_addr = i2c_addr;
- state->config = config;
-
- switch (state->config->tuner_id_0) {
- case IT9135_51:
- case IT9135_52:
- case IT9135_60:
- case IT9135_61:
- case IT9135_62:
- state->tuner_type = state->config->tuner_id_0;
- break;
- default:
- case IT9135_38:
- state->tuner_type = IT9135_38;
- }
-
- ret = it913x_fe_start(state);
- if (ret < 0)
- goto error;
-
-
- /* create dvb_frontend */
- memcpy(&state->frontend.ops, &it913x_fe_ofdm_ops,
- sizeof(struct dvb_frontend_ops));
- state->frontend.demodulator_priv = state;
-
- return &state->frontend;
-error:
- kfree(state);
- return NULL;
-}
-EXPORT_SYMBOL(it913x_fe_attach);
-
-static struct dvb_frontend_ops it913x_fe_ofdm_ops = {
- .delsys = { SYS_DVBT },
- .info = {
- .name = "it913x-fe DVB-T",
- .frequency_min = 51000000,
- .frequency_max = 1680000000,
- .frequency_stepsize = 62500,
- .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
- FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
- FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO |
- FE_CAN_GUARD_INTERVAL_AUTO |
- FE_CAN_HIERARCHY_AUTO,
- },
-
- .release = it913x_fe_release,
-
- .init = it913x_fe_init,
- .sleep = it913x_fe_sleep,
-
- .set_frontend = it913x_fe_set_frontend,
- .get_frontend = it913x_fe_get_frontend,
-
- .read_status = it913x_fe_read_status,
- .read_signal_strength = it913x_fe_read_signal_strength,
- .read_snr = it913x_fe_read_snr,
- .read_ber = it913x_fe_read_ber,
- .read_ucblocks = it913x_fe_read_ucblocks,
-};
-
-MODULE_DESCRIPTION("it913x Frontend and it9137 tuner");
-MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
-MODULE_VERSION("1.15");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/it913x-fe.h b/drivers/media/dvb-frontends/it913x-fe.h
deleted file mode 100644
index df0ad4207343..000000000000
--- a/drivers/media/dvb-frontends/it913x-fe.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Driver for it913x Frontend
- *
- *
- * 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.=
- */
-
-#ifndef IT913X_FE_H
-#define IT913X_FE_H
-
-#include <linux/kconfig.h>
-#include <linux/dvb/frontend.h>
-#include "dvb_frontend.h"
-
-struct ite_config {
- u8 chip_ver;
- u16 chip_type;
- u32 firmware;
- u8 firmware_ver;
- u8 adc_x2;
- u8 tuner_id_0;
- u8 tuner_id_1;
- u8 dual_mode;
- u8 adf;
- /* option to read SIGNAL_LEVEL */
- u8 read_slevel;
-};
-
-#if IS_ENABLED(CONFIG_DVB_IT913X_FE)
-extern struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap,
- u8 i2c_addr, struct ite_config *config);
-#else
-static inline struct dvb_frontend *it913x_fe_attach(
- struct i2c_adapter *i2c_adap,
- u8 i2c_addr, struct ite_config *config)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return NULL;
-}
-#endif /* CONFIG_IT913X_FE */
-#define I2C_BASE_ADDR 0x10
-#define DEV_0 0x0
-#define DEV_1 0x10
-#define PRO_LINK 0x0
-#define PRO_DMOD 0x1
-#define DEV_0_DMOD (PRO_DMOD << 0x7)
-#define DEV_1_DMOD (DEV_0_DMOD | DEV_1)
-#define CHIP2_I2C_ADDR 0x3a
-
-#define AFE_MEM0 0xfb24
-
-#define MP2_SW_RST 0xf99d
-#define MP2IF2_SW_RST 0xf9a4
-
-#define PADODPU 0xd827
-#define THIRDODPU 0xd828
-#define AGC_O_D 0xd829
-
-#define EP0_TX_EN 0xdd11
-#define EP0_TX_NAK 0xdd13
-#define EP4_TX_LEN_LSB 0xdd88
-#define EP4_TX_LEN_MSB 0xdd89
-#define EP4_MAX_PKT 0xdd0c
-#define EP5_TX_LEN_LSB 0xdd8a
-#define EP5_TX_LEN_MSB 0xdd8b
-#define EP5_MAX_PKT 0xdd0d
-
-#define IO_MUX_POWER_CLK 0xd800
-#define CLK_O_EN 0xd81a
-#define I2C_CLK 0xf103
-#define I2C_CLK_100 0x7
-#define I2C_CLK_400 0x1a
-
-#define D_TPSD_LOCK 0xf5a9
-#define MP2IF2_EN 0xf9a3
-#define MP2IF_SERIAL 0xf985
-#define TSIS_ENABLE 0xf9cd
-#define MP2IF2_HALF_PSB 0xf9a5
-#define MP2IF_STOP_EN 0xf9b5
-#define MPEG_FULL_SPEED 0xf990
-#define TOP_HOSTB_SER_MODE 0xd91c
-
-#define PID_RST 0xf992
-#define PID_EN 0xf993
-#define PID_INX_EN 0xf994
-#define PID_INX 0xf995
-#define PID_LSB 0xf996
-#define PID_MSB 0xf997
-
-#define MP2IF_MPEG_PAR_MODE 0xf986
-#define DCA_UPPER_CHIP 0xf731
-#define DCA_LOWER_CHIP 0xf732
-#define DCA_PLATCH 0xf730
-#define DCA_FPGA_LATCH 0xf778
-#define DCA_STAND_ALONE 0xf73c
-#define DCA_ENABLE 0xf776
-
-#define DVBT_INTEN 0xf41f
-#define DVBT_ENABLE 0xf41a
-#define HOSTB_DCA_LOWER 0xd91f
-#define HOSTB_MPEG_PAR_MODE 0xd91b
-#define HOSTB_MPEG_SER_MODE 0xd91c
-#define HOSTB_MPEG_SER_DO7 0xd91d
-#define HOSTB_DCA_UPPER 0xd91e
-#define PADMISCDR2 0xd830
-#define PADMISCDR4 0xd831
-#define PADMISCDR8 0xd832
-#define PADMISCDRSR 0xd833
-#define LOCK3_OUT 0xd8fd
-
-#define GPIOH1_O 0xd8af
-#define GPIOH1_EN 0xd8b0
-#define GPIOH1_ON 0xd8b1
-#define GPIOH3_O 0xd8b3
-#define GPIOH3_EN 0xd8b4
-#define GPIOH3_ON 0xd8b5
-#define GPIOH5_O 0xd8bb
-#define GPIOH5_EN 0xd8bc
-#define GPIOH5_ON 0xd8bd
-
-#define AFE_MEM0 0xfb24
-
-#define REG_TPSD_TX_MODE 0xf900
-#define REG_TPSD_GI 0xf901
-#define REG_TPSD_HIER 0xf902
-#define REG_TPSD_CONST 0xf903
-#define REG_BW 0xf904
-#define REG_PRIV 0xf905
-#define REG_TPSD_HP_CODE 0xf906
-#define REG_TPSD_LP_CODE 0xf907
-
-#define MP2IF_SYNC_LK 0xf999
-#define ADC_FREQ 0xf1cd
-
-#define TRIGGER_OFSM 0x0000
-/* COEFF Registers start at 0x0001 to 0x0020 */
-#define COEFF_1_2048 0x0001
-#define XTAL_CLK 0x0025
-#define BFS_FCW 0x0029
-
-/* Error Regs */
-#define RSD_ABORT_PKT_LSB 0x0032
-#define RSD_ABORT_PKT_MSB 0x0033
-#define RSD_BIT_ERR_0_7 0x0034
-#define RSD_BIT_ERR_8_15 0x0035
-#define RSD_BIT_ERR_23_16 0x0036
-#define RSD_BIT_COUNT_LSB 0x0037
-#define RSD_BIT_COUNT_MSB 0x0038
-
-#define TPSD_LOCK 0x003c
-#define TRAINING_MODE 0x0040
-#define ADC_X_2 0x0045
-#define TUNER_ID 0x0046
-#define EMPTY_CHANNEL_STATUS 0x0047
-#define SIGNAL_LEVEL 0x0048
-#define SIGNAL_QUALITY 0x0049
-#define EST_SIGNAL_LEVEL 0x004a
-#define FREE_BAND 0x004b
-#define SUSPEND_FLAG 0x004c
-#define VAR_P_INBAND 0x00f7
-
-/* Build in tuner types */
-#define IT9137 0x38
-#define IT9135_38 0x38
-#define IT9135_51 0x51
-#define IT9135_52 0x52
-#define IT9135_60 0x60
-#define IT9135_61 0x61
-#define IT9135_62 0x62
-
-enum {
- CMD_DEMOD_READ = 0,
- CMD_DEMOD_WRITE,
- CMD_TUNER_READ,
- CMD_TUNER_WRITE,
- CMD_REG_EEPROM_READ,
- CMD_REG_EEPROM_WRITE,
- CMD_DATA_READ,
- CMD_VAR_READ = 8,
- CMD_VAR_WRITE,
- CMD_PLATFORM_GET,
- CMD_PLATFORM_SET,
- CMD_IP_CACHE,
- CMD_IP_ADD,
- CMD_IP_REMOVE,
- CMD_PID_ADD,
- CMD_PID_REMOVE,
- CMD_SIPSI_GET,
- CMD_SIPSI_MPE_RESET,
- CMD_H_PID_ADD = 0x15,
- CMD_H_PID_REMOVE,
- CMD_ABORT,
- CMD_IR_GET,
- CMD_IR_SET,
- CMD_FW_DOWNLOAD = 0x21,
- CMD_QUERYINFO,
- CMD_BOOT,
- CMD_FW_DOWNLOAD_BEGIN,
- CMD_FW_DOWNLOAD_END,
- CMD_RUN_CODE,
- CMD_SCATTER_READ = 0x28,
- CMD_SCATTER_WRITE,
- CMD_GENERIC_READ,
- CMD_GENERIC_WRITE
-};
-
-enum {
- READ_LONG,
- WRITE_LONG,
- READ_SHORT,
- WRITE_SHORT,
- READ_DATA,
- WRITE_DATA,
- WRITE_CMD,
-};
-
-enum {
- IT9135_AUTO = 0,
- IT9137_FW,
- IT9135_V1_FW,
- IT9135_V2_FW,
-};
-
-#endif /* IT913X_FE_H */
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
index b8a7897e7bd8..2ef8ce13fb60 100644
--- a/drivers/media/dvb-frontends/m88ds3103.c
+++ b/drivers/media/dvb-frontends/m88ds3103.c
@@ -271,6 +271,13 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
ret = fe->ops.tuner_ops.get_frequency(fe, &tuner_frequency);
if (ret)
goto err;
+ } else {
+ /*
+ * Use nominal target frequency as tuner driver does not provide
+ * actual frequency used. Carrier offset calculation is not
+ * valid.
+ */
+ tuner_frequency = c->frequency;
}
/* reset */
@@ -428,18 +435,10 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
goto err;
switch (target_mclk) {
- case 72000:
- u8tmp1 = 0x00; /* 0b00 */
- u8tmp2 = 0x03; /* 0b11 */
- break;
case 96000:
u8tmp1 = 0x02; /* 0b10 */
u8tmp2 = 0x01; /* 0b01 */
break;
- case 115200:
- u8tmp1 = 0x01; /* 0b01 */
- u8tmp2 = 0x01; /* 0b01 */
- break;
case 144000:
u8tmp1 = 0x00; /* 0b00 */
u8tmp2 = 0x01; /* 0b01 */
@@ -448,10 +447,6 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
u8tmp1 = 0x03; /* 0b11 */
u8tmp2 = 0x00; /* 0b00 */
break;
- default:
- dev_dbg(&priv->i2c->dev, "%s: invalid target_mclk\n", __func__);
- ret = -EINVAL;
- goto err;
}
ret = m88ds3103_wr_reg_mask(priv, 0x22, u8tmp1 << 6, 0xc0);
@@ -711,9 +706,6 @@ static int m88ds3103_get_frontend(struct dvb_frontend *fe)
case 1:
c->inversion = INVERSION_ON;
break;
- default:
- dev_dbg(&priv->i2c->dev, "%s: invalid inversion\n",
- __func__);
}
switch ((buf[1] >> 5) & 0x07) {
@@ -793,9 +785,6 @@ static int m88ds3103_get_frontend(struct dvb_frontend *fe)
case 1:
c->pilot = PILOT_ON;
break;
- default:
- dev_dbg(&priv->i2c->dev, "%s: invalid pilot\n",
- __func__);
}
switch ((buf[0] >> 6) & 0x07) {
@@ -823,9 +812,6 @@ static int m88ds3103_get_frontend(struct dvb_frontend *fe)
case 1:
c->inversion = INVERSION_ON;
break;
- default:
- dev_dbg(&priv->i2c->dev, "%s: invalid inversion\n",
- __func__);
}
switch ((buf[2] >> 0) & 0x03) {
@@ -958,7 +944,7 @@ static int m88ds3103_set_tone(struct dvb_frontend *fe,
switch (fe_sec_tone_mode) {
case SEC_TONE_ON:
tone = 0;
- reg_a1_mask = 0x87;
+ reg_a1_mask = 0x47;
break;
case SEC_TONE_OFF:
tone = 1;
diff --git a/drivers/media/dvb-frontends/m88rs2000.c b/drivers/media/dvb-frontends/m88rs2000.c
index b2351466b0da..32cffca14d0b 100644
--- a/drivers/media/dvb-frontends/m88rs2000.c
+++ b/drivers/media/dvb-frontends/m88rs2000.c
@@ -715,6 +715,22 @@ static int m88rs2000_get_frontend(struct dvb_frontend *fe)
return 0;
}
+static int m88rs2000_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *tune)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+ if (c->symbol_rate > 3000000)
+ tune->min_delay_ms = 2000;
+ else
+ tune->min_delay_ms = 3000;
+
+ tune->step_size = c->symbol_rate / 16000;
+ tune->max_drift = c->symbol_rate / 2000;
+
+ return 0;
+}
+
static int m88rs2000_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct m88rs2000_state *state = fe->demodulator_priv;
@@ -746,7 +762,7 @@ static struct dvb_frontend_ops m88rs2000_ops = {
.symbol_rate_tolerance = 500, /* ppm */
.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
- FE_CAN_QPSK |
+ FE_CAN_QPSK | FE_CAN_INVERSION_AUTO |
FE_CAN_FEC_AUTO
},
@@ -766,6 +782,7 @@ static struct dvb_frontend_ops m88rs2000_ops = {
.set_frontend = m88rs2000_set_frontend,
.get_frontend = m88rs2000_get_frontend,
+ .get_tune_settings = m88rs2000_get_tune_settings,
};
struct dvb_frontend *m88rs2000_attach(const struct m88rs2000_config *config,
diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c
index 2c7217fb1415..2f458bb188c7 100644
--- a/drivers/media/dvb-frontends/mb86a20s.c
+++ b/drivers/media/dvb-frontends/mb86a20s.c
@@ -1,7 +1,7 @@
/*
* Fujitu mb86a20s ISDB-T/ISDB-Tsb Module driver
*
- * Copyright (C) 2010-2013 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2010-2013 Mauro Carvalho Chehab
* Copyright (C) 2009-2010 Douglas Landgraf <dougsland@redhat.com>
*
* This program is free software; you can redistribute it and/or
@@ -2156,5 +2156,5 @@ static struct dvb_frontend_ops mb86a20s_ops = {
};
MODULE_DESCRIPTION("DVB Frontend module for Fujitsu mb86A20s hardware");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/mb86a20s.h b/drivers/media/dvb-frontends/mb86a20s.h
index 6627a3976087..cbeb941fba7c 100644
--- a/drivers/media/dvb-frontends/mb86a20s.h
+++ b/drivers/media/dvb-frontends/mb86a20s.h
@@ -1,7 +1,7 @@
/*
* Fujitsu mb86a20s driver
*
- * Copyright (C) 2010 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2010 Mauro Carvalho Chehab
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index ff73da9365e3..fdbed35c87fa 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -24,11 +24,6 @@
/* Max transfer size done by I2C transfer functions */
#define MAX_XFER_SIZE 64
-
-int rtl2832_debug;
-module_param_named(debug, rtl2832_debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
#define REG_MASK(b) (BIT(b + 1) - 1)
static const struct rtl2832_reg_entry registers[] = {
@@ -185,12 +180,13 @@ static int rtl2832_wr(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
buf[0] = reg;
memcpy(&buf[1], val, len);
- ret = i2c_transfer(priv->i2c, msg, 1);
+ ret = i2c_transfer(priv->i2c_adapter, msg, 1);
if (ret == 1) {
ret = 0;
} else {
- dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \
- "len=%d\n", KBUILD_MODNAME, ret, reg, len);
+ dev_warn(&priv->i2c->dev,
+ "%s: i2c wr failed=%d reg=%02x len=%d\n",
+ KBUILD_MODNAME, ret, reg, len);
ret = -EREMOTEIO;
}
return ret;
@@ -214,12 +210,13 @@ static int rtl2832_rd(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
}
};
- ret = i2c_transfer(priv->i2c, msg, 2);
+ ret = i2c_transfer(priv->i2c_adapter, msg, 2);
if (ret == 2) {
ret = 0;
} else {
- dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \
- "len=%d\n", KBUILD_MODNAME, ret, reg, len);
+ dev_warn(&priv->i2c->dev,
+ "%s: i2c rd failed=%d reg=%02x len=%d\n",
+ KBUILD_MODNAME, ret, reg, len);
ret = -EREMOTEIO;
}
return ret;
@@ -417,7 +414,7 @@ static int rtl2832_set_if(struct dvb_frontend *fe, u32 if_freq)
ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq);
- return (ret);
+ return ret;
}
static int rtl2832_init(struct dvb_frontend *fe)
@@ -514,15 +511,10 @@ static int rtl2832_init(struct dvb_frontend *fe)
goto err;
}
- if (!fe->ops.tuner_ops.get_if_frequency) {
- ret = rtl2832_set_if(fe, priv->cfg.if_dvbt);
- if (ret)
- goto err;
- }
-
/*
* r820t NIM code does a software reset here at the demod -
- * may not be needed, as there's already a software reset at set_params()
+ * may not be needed, as there's already a software reset at
+ * set_params()
*/
#if 1
/* soft reset */
@@ -599,9 +591,9 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe)
};
- dev_dbg(&priv->i2c->dev, "%s: frequency=%d bandwidth_hz=%d " \
- "inversion=%d\n", __func__, c->frequency,
- c->bandwidth_hz, c->inversion);
+ dev_dbg(&priv->i2c->dev,
+ "%s: frequency=%d bandwidth_hz=%d inversion=%d\n",
+ __func__, c->frequency, c->bandwidth_hz, c->inversion);
/* program tuner */
if (fe->ops.tuner_ops.set_params)
@@ -899,9 +891,149 @@ static void rtl2832_release(struct dvb_frontend *fe)
struct rtl2832_priv *priv = fe->demodulator_priv;
dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
+ cancel_delayed_work_sync(&priv->i2c_gate_work);
+ i2c_del_mux_adapter(priv->i2c_adapter_tuner);
+ i2c_del_mux_adapter(priv->i2c_adapter);
kfree(priv);
}
+/*
+ * Delay mechanism to avoid unneeded I2C gate open / close. Gate close is
+ * delayed here a little bit in order to see if there is sequence of I2C
+ * messages sent to same I2C bus.
+ * We must use unlocked version of __i2c_transfer() in order to avoid deadlock
+ * as lock is already taken by calling muxed i2c_transfer().
+ */
+static void rtl2832_i2c_gate_work(struct work_struct *work)
+{
+ struct rtl2832_priv *priv = container_of(work,
+ struct rtl2832_priv, i2c_gate_work.work);
+ struct i2c_adapter *adap = priv->i2c;
+ int ret;
+ u8 buf[2];
+ struct i2c_msg msg[1] = {
+ {
+ .addr = priv->cfg.i2c_addr,
+ .flags = 0,
+ .len = sizeof(buf),
+ .buf = buf,
+ }
+ };
+
+ /* select reg bank 1 */
+ buf[0] = 0x00;
+ buf[1] = 0x01;
+ ret = __i2c_transfer(adap, msg, 1);
+ if (ret != 1)
+ goto err;
+
+ priv->page = 1;
+
+ /* close I2C repeater gate */
+ buf[0] = 0x01;
+ buf[1] = 0x10;
+ ret = __i2c_transfer(adap, msg, 1);
+ if (ret != 1)
+ goto err;
+
+ priv->i2c_gate_state = 0;
+
+ return;
+err:
+ dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+
+ return;
+}
+
+static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id)
+{
+ struct rtl2832_priv *priv = mux_priv;
+ int ret;
+ u8 buf[2], val;
+ struct i2c_msg msg[1] = {
+ {
+ .addr = priv->cfg.i2c_addr,
+ .flags = 0,
+ .len = sizeof(buf),
+ .buf = buf,
+ }
+ };
+ struct i2c_msg msg_rd[2] = {
+ {
+ .addr = priv->cfg.i2c_addr,
+ .flags = 0,
+ .len = 1,
+ .buf = "\x01",
+ }, {
+ .addr = priv->cfg.i2c_addr,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = &val,
+ }
+ };
+
+ /* terminate possible gate closing */
+ cancel_delayed_work_sync(&priv->i2c_gate_work);
+
+ if (priv->i2c_gate_state == chan_id)
+ return 0;
+
+ /* select reg bank 1 */
+ buf[0] = 0x00;
+ buf[1] = 0x01;
+ ret = __i2c_transfer(adap, msg, 1);
+ if (ret != 1)
+ goto err;
+
+ priv->page = 1;
+
+ /* we must read that register, otherwise there will be errors */
+ ret = __i2c_transfer(adap, msg_rd, 2);
+ if (ret != 2)
+ goto err;
+
+ /* open or close I2C repeater gate */
+ buf[0] = 0x01;
+ if (chan_id == 1)
+ buf[1] = 0x18; /* open */
+ else
+ buf[1] = 0x10; /* close */
+
+ ret = __i2c_transfer(adap, msg, 1);
+ if (ret != 1)
+ goto err;
+
+ priv->i2c_gate_state = chan_id;
+
+ return 0;
+err:
+ dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+
+ return -EREMOTEIO;
+}
+
+static int rtl2832_deselect(struct i2c_adapter *adap, void *mux_priv,
+ u32 chan_id)
+{
+ struct rtl2832_priv *priv = mux_priv;
+ schedule_delayed_work(&priv->i2c_gate_work, usecs_to_jiffies(100));
+ return 0;
+}
+
+struct i2c_adapter *rtl2832_get_i2c_adapter(struct dvb_frontend *fe)
+{
+ struct rtl2832_priv *priv = fe->demodulator_priv;
+ return priv->i2c_adapter_tuner;
+}
+EXPORT_SYMBOL(rtl2832_get_i2c_adapter);
+
+struct i2c_adapter *rtl2832_get_private_i2c_adapter(struct dvb_frontend *fe)
+{
+ struct rtl2832_priv *priv = fe->demodulator_priv;
+ return priv->i2c_adapter;
+}
+EXPORT_SYMBOL(rtl2832_get_private_i2c_adapter);
+
struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg,
struct i2c_adapter *i2c)
{
@@ -920,12 +1052,25 @@ struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg,
priv->i2c = i2c;
priv->tuner = cfg->tuner;
memcpy(&priv->cfg, cfg, sizeof(struct rtl2832_config));
+ INIT_DELAYED_WORK(&priv->i2c_gate_work, rtl2832_i2c_gate_work);
+
+ /* create muxed i2c adapter for demod itself */
+ priv->i2c_adapter = i2c_add_mux_adapter(i2c, &i2c->dev, priv, 0, 0, 0,
+ rtl2832_select, NULL);
+ if (priv->i2c_adapter == NULL)
+ goto err;
/* check if the demod is there */
ret = rtl2832_rd_reg(priv, 0x00, 0x0, &tmp);
if (ret)
goto err;
+ /* create muxed i2c adapter for demod tuner bus */
+ priv->i2c_adapter_tuner = i2c_add_mux_adapter(i2c, &i2c->dev, priv,
+ 0, 1, 0, rtl2832_select, rtl2832_deselect);
+ if (priv->i2c_adapter_tuner == NULL)
+ goto err;
+
/* create dvb_frontend */
memcpy(&priv->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops));
priv->fe.demodulator_priv = priv;
@@ -936,6 +1081,8 @@ struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg,
return &priv->fe;
err:
dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret);
+ if (priv && priv->i2c_adapter)
+ i2c_del_mux_adapter(priv->i2c_adapter);
kfree(priv);
return NULL;
}
diff --git a/drivers/media/dvb-frontends/rtl2832.h b/drivers/media/dvb-frontends/rtl2832.h
index 2cfbb6a97061..cb3b6b0775b8 100644
--- a/drivers/media/dvb-frontends/rtl2832.h
+++ b/drivers/media/dvb-frontends/rtl2832.h
@@ -38,13 +38,6 @@ struct rtl2832_config {
u32 xtal;
/*
- * IFs for all used modes.
- * Hz
- * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000
- */
- u32 if_dvbt;
-
- /*
* tuner
* XXX: This must be keep sync with dvb_usb_rtl28xxu demod driver.
*/
@@ -58,11 +51,21 @@ struct rtl2832_config {
};
#if IS_ENABLED(CONFIG_DVB_RTL2832)
-extern struct dvb_frontend *rtl2832_attach(
+struct dvb_frontend *rtl2832_attach(
const struct rtl2832_config *cfg,
struct i2c_adapter *i2c
);
+
+extern struct i2c_adapter *rtl2832_get_i2c_adapter(
+ struct dvb_frontend *fe
+);
+
+extern struct i2c_adapter *rtl2832_get_private_i2c_adapter(
+ struct dvb_frontend *fe
+);
+
#else
+
static inline struct dvb_frontend *rtl2832_attach(
const struct rtl2832_config *config,
struct i2c_adapter *i2c
@@ -71,6 +74,21 @@ static inline struct dvb_frontend *rtl2832_attach(
pr_warn("%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
+
+static inline struct i2c_adapter *rtl2832_get_i2c_adapter(
+ struct dvb_frontend *fe
+)
+{
+ return NULL;
+}
+
+static inline struct i2c_adapter *rtl2832_get_private_i2c_adapter(
+ struct dvb_frontend *fe
+)
+{
+ return NULL;
+}
+
#endif
diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h
index b5f2b80092ee..ae469f032fe6 100644
--- a/drivers/media/dvb-frontends/rtl2832_priv.h
+++ b/drivers/media/dvb-frontends/rtl2832_priv.h
@@ -23,9 +23,12 @@
#include "dvb_frontend.h"
#include "rtl2832.h"
+#include <linux/i2c-mux.h>
struct rtl2832_priv {
struct i2c_adapter *i2c;
+ struct i2c_adapter *i2c_adapter;
+ struct i2c_adapter *i2c_adapter_tuner;
struct dvb_frontend fe;
struct rtl2832_config cfg;
@@ -34,6 +37,7 @@ struct rtl2832_priv {
u8 tuner;
u8 page; /* active register page */
+ struct delayed_work i2c_gate_work;
};
struct rtl2832_reg_entry {
@@ -267,7 +271,7 @@ static const struct rtl2832_reg_value rtl2832_tuner_init_tua9001[] = {
{DVBT_OPT_ADC_IQ, 0x1},
{DVBT_AD_AVI, 0x0},
{DVBT_AD_AVQ, 0x0},
- {DVBT_SPEC_INV, 0x0},
+ {DVBT_SPEC_INV, 0x0},
};
static const struct rtl2832_reg_value rtl2832_tuner_init_fc0012[] = {
@@ -301,7 +305,7 @@ static const struct rtl2832_reg_value rtl2832_tuner_init_fc0012[] = {
{DVBT_GI_PGA_STATE, 0x0},
{DVBT_EN_AGC_PGA, 0x1},
{DVBT_IF_AGC_MAN, 0x0},
- {DVBT_SPEC_INV, 0x0},
+ {DVBT_SPEC_INV, 0x0},
};
static const struct rtl2832_reg_value rtl2832_tuner_init_e4000[] = {
@@ -339,32 +343,32 @@ static const struct rtl2832_reg_value rtl2832_tuner_init_e4000[] = {
{DVBT_REG_MONSEL, 0x1},
{DVBT_REG_MON, 0x1},
{DVBT_REG_4MSEL, 0x0},
- {DVBT_SPEC_INV, 0x0},
+ {DVBT_SPEC_INV, 0x0},
};
static const struct rtl2832_reg_value rtl2832_tuner_init_r820t[] = {
- {DVBT_DAGC_TRG_VAL, 0x39},
- {DVBT_AGC_TARG_VAL_0, 0x0},
- {DVBT_AGC_TARG_VAL_8_1, 0x40},
- {DVBT_AAGC_LOOP_GAIN, 0x16},
- {DVBT_LOOP_GAIN2_3_0, 0x8},
- {DVBT_LOOP_GAIN2_4, 0x1},
- {DVBT_LOOP_GAIN3, 0x18},
- {DVBT_VTOP1, 0x35},
- {DVBT_VTOP2, 0x21},
- {DVBT_VTOP3, 0x21},
- {DVBT_KRF1, 0x0},
- {DVBT_KRF2, 0x40},
- {DVBT_KRF3, 0x10},
- {DVBT_KRF4, 0x10},
- {DVBT_IF_AGC_MIN, 0x80},
- {DVBT_IF_AGC_MAX, 0x7f},
- {DVBT_RF_AGC_MIN, 0x80},
- {DVBT_RF_AGC_MAX, 0x7f},
- {DVBT_POLAR_RF_AGC, 0x0},
- {DVBT_POLAR_IF_AGC, 0x0},
- {DVBT_AD7_SETTING, 0xe9f4},
- {DVBT_SPEC_INV, 0x1},
+ {DVBT_DAGC_TRG_VAL, 0x39},
+ {DVBT_AGC_TARG_VAL_0, 0x0},
+ {DVBT_AGC_TARG_VAL_8_1, 0x40},
+ {DVBT_AAGC_LOOP_GAIN, 0x16},
+ {DVBT_LOOP_GAIN2_3_0, 0x8},
+ {DVBT_LOOP_GAIN2_4, 0x1},
+ {DVBT_LOOP_GAIN3, 0x18},
+ {DVBT_VTOP1, 0x35},
+ {DVBT_VTOP2, 0x21},
+ {DVBT_VTOP3, 0x21},
+ {DVBT_KRF1, 0x0},
+ {DVBT_KRF2, 0x40},
+ {DVBT_KRF3, 0x10},
+ {DVBT_KRF4, 0x10},
+ {DVBT_IF_AGC_MIN, 0x80},
+ {DVBT_IF_AGC_MAX, 0x7f},
+ {DVBT_RF_AGC_MIN, 0x80},
+ {DVBT_RF_AGC_MAX, 0x7f},
+ {DVBT_POLAR_RF_AGC, 0x0},
+ {DVBT_POLAR_IF_AGC, 0x0},
+ {DVBT_AD7_SETTING, 0xe9f4},
+ {DVBT_SPEC_INV, 0x1},
};
#endif /* RTL2832_PRIV_H */
diff --git a/drivers/media/dvb-frontends/s921.c b/drivers/media/dvb-frontends/s921.c
index a271ac3eaec0..69862e1fd9e9 100644
--- a/drivers/media/dvb-frontends/s921.c
+++ b/drivers/media/dvb-frontends/s921.c
@@ -2,7 +2,7 @@
* Sharp VA3A5JZ921 One Seg Broadcast Module driver
* This device is labeled as just S. 921 at the top of the frontend can
*
- * Copyright (C) 2009-2010 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2009-2010 Mauro Carvalho Chehab
* Copyright (C) 2009-2010 Douglas Landgraf <dougsland@redhat.com>
*
* Developed for Leadership SBTVD 1seg device sold in Brazil
@@ -539,6 +539,6 @@ static struct dvb_frontend_ops s921_ops = {
};
MODULE_DESCRIPTION("DVB Frontend module for Sharp S921 hardware");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_AUTHOR("Douglas Landgraf <dougsland@redhat.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/s921.h b/drivers/media/dvb-frontends/s921.h
index 8d5e2a6e187c..9b20c9e0eb88 100644
--- a/drivers/media/dvb-frontends/s921.h
+++ b/drivers/media/dvb-frontends/s921.h
@@ -1,7 +1,7 @@
/*
* Sharp s921 driver
*
- * Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2009 Mauro Carvalho Chehab
* Copyright (C) 2009 Douglas Landgraf <dougsland@redhat.com>
*
* This program is free software; you can redistribute it and/or
diff --git a/drivers/media/dvb-frontends/stb6100.c b/drivers/media/dvb-frontends/stb6100.c
index cea175d19890..4ef8a5c7003e 100644
--- a/drivers/media/dvb-frontends/stb6100.c
+++ b/drivers/media/dvb-frontends/stb6100.c
@@ -193,7 +193,7 @@ static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int st
.len = len + 1
};
- if (1 + len > sizeof(buf)) {
+ if (1 + len > sizeof(cmdbuf)) {
printk(KERN_WARNING
"%s: i2c wr: len=%d is too big!\n",
KBUILD_MODNAME, len);
diff --git a/drivers/media/dvb-frontends/stv0900_sw.c b/drivers/media/dvb-frontends/stv0900_sw.c
index 0a40edfad739..4ce1d260b3eb 100644
--- a/drivers/media/dvb-frontends/stv0900_sw.c
+++ b/drivers/media/dvb-frontends/stv0900_sw.c
@@ -1081,7 +1081,7 @@ static int stv0900_wait_for_lock(struct stv0900_internal *intp,
lock = stv0900_get_demod_lock(intp, demod, dmd_timeout);
if (lock)
- lock = lock && stv0900_get_fec_lock(intp, demod, fec_timeout);
+ lock = stv0900_get_fec_lock(intp, demod, fec_timeout);
if (lock) {
lock = 0;
diff --git a/drivers/media/dvb-frontends/tda10071.c b/drivers/media/dvb-frontends/tda10071.c
index 8ad3a57cf640..522fe00f5eee 100644
--- a/drivers/media/dvb-frontends/tda10071.c
+++ b/drivers/media/dvb-frontends/tda10071.c
@@ -42,8 +42,8 @@ static int tda10071_wr_regs(struct tda10071_priv *priv, u8 reg, u8 *val,
if (1 + len > sizeof(buf)) {
dev_warn(&priv->i2c->dev,
- "%s: i2c wr reg=%04x: len=%d is too big!\n",
- KBUILD_MODNAME, reg, len);
+ "%s: i2c wr reg=%04x: len=%d is too big!\n",
+ KBUILD_MODNAME, reg, len);
return -EINVAL;
}
@@ -54,8 +54,9 @@ static int tda10071_wr_regs(struct tda10071_priv *priv, u8 reg, u8 *val,
if (ret == 1) {
ret = 0;
} else {
- dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \
- "len=%d\n", KBUILD_MODNAME, ret, reg, len);
+ dev_warn(&priv->i2c->dev,
+ "%s: i2c wr failed=%d reg=%02x len=%d\n",
+ KBUILD_MODNAME, ret, reg, len);
ret = -EREMOTEIO;
}
return ret;
@@ -83,8 +84,8 @@ static int tda10071_rd_regs(struct tda10071_priv *priv, u8 reg, u8 *val,
if (len > sizeof(buf)) {
dev_warn(&priv->i2c->dev,
- "%s: i2c wr reg=%04x: len=%d is too big!\n",
- KBUILD_MODNAME, reg, len);
+ "%s: i2c wr reg=%04x: len=%d is too big!\n",
+ KBUILD_MODNAME, reg, len);
return -EINVAL;
}
@@ -93,8 +94,9 @@ static int tda10071_rd_regs(struct tda10071_priv *priv, u8 reg, u8 *val,
memcpy(val, buf, len);
ret = 0;
} else {
- dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \
- "len=%d\n", KBUILD_MODNAME, ret, reg, len);
+ dev_warn(&priv->i2c->dev,
+ "%s: i2c rd failed=%d reg=%02x len=%d\n",
+ KBUILD_MODNAME, ret, reg, len);
ret = -EREMOTEIO;
}
return ret;
@@ -491,10 +493,9 @@ static int tda10071_read_status(struct dvb_frontend *fe, fe_status_t *status)
if (ret)
goto error;
- if (tmp & 0x01) /* tuner PLL */
- *status |= FE_HAS_SIGNAL;
+ /* 0x39[0] tuner PLL */
if (tmp & 0x02) /* demod PLL */
- *status |= FE_HAS_CARRIER;
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
if (tmp & 0x04) /* viterbi or LDPC*/
*status |= FE_HAS_VITERBI;
if (tmp & 0x08) /* RS or BCH */
@@ -668,11 +669,11 @@ static int tda10071_set_frontend(struct dvb_frontend *fe)
int ret, i;
u8 mode, rolloff, pilot, inversion, div;
- dev_dbg(&priv->i2c->dev, "%s: delivery_system=%d modulation=%d " \
- "frequency=%d symbol_rate=%d inversion=%d pilot=%d " \
- "rolloff=%d\n", __func__, c->delivery_system, c->modulation,
- c->frequency, c->symbol_rate, c->inversion, c->pilot,
- c->rolloff);
+ dev_dbg(&priv->i2c->dev,
+ "%s: delivery_system=%d modulation=%d frequency=%d symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n",
+ __func__, c->delivery_system, c->modulation,
+ c->frequency, c->symbol_rate, c->inversion, c->pilot,
+ c->rolloff);
priv->delivery_system = SYS_UNDEFINED;
@@ -952,10 +953,8 @@ static int tda10071_init(struct dvb_frontend *fe)
/* request the firmware, this will block and timeout */
ret = request_firmware(&fw, fw_file, priv->i2c->dev.parent);
if (ret) {
- dev_err(&priv->i2c->dev, "%s: did not find the " \
- "firmware file. (%s) Please see " \
- "linux/Documentation/dvb/ for more " \
- "details on firmware-problems. (%d)\n",
+ dev_err(&priv->i2c->dev,
+ "%s: did not find the firmware file. (%s) Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)\n",
KBUILD_MODNAME, fw_file, ret);
goto error;
}
@@ -985,11 +984,12 @@ static int tda10071_init(struct dvb_frontend *fe)
if (ret)
goto error_release_firmware;
- dev_info(&priv->i2c->dev, "%s: found a '%s' in cold state, " \
- "will try to load a firmware\n", KBUILD_MODNAME,
- tda10071_ops.info.name);
- dev_info(&priv->i2c->dev, "%s: downloading firmware from " \
- "file '%s'\n", KBUILD_MODNAME, fw_file);
+ dev_info(&priv->i2c->dev,
+ "%s: found a '%s' in cold state, will try to load a firmware\n",
+ KBUILD_MODNAME, tda10071_ops.info.name);
+ dev_info(&priv->i2c->dev,
+ "%s: downloading firmware from file '%s'\n",
+ KBUILD_MODNAME, fw_file);
/* do not download last byte */
fw_size = fw->size - 1;
@@ -1003,11 +1003,10 @@ static int tda10071_init(struct dvb_frontend *fe)
ret = tda10071_wr_regs(priv, 0xfa,
(u8 *) &fw->data[fw_size - remaining], len);
if (ret) {
- dev_err(&priv->i2c->dev, "%s: firmware " \
- "download failed=%d\n",
+ dev_err(&priv->i2c->dev,
+ "%s: firmware download failed=%d\n",
KBUILD_MODNAME, ret);
- if (ret)
- goto error_release_firmware;
+ goto error_release_firmware;
}
}
release_firmware(fw);
@@ -1069,12 +1068,17 @@ static int tda10071_init(struct dvb_frontend *fe)
if (ret)
goto error;
+ if (priv->cfg.tuner_i2c_addr)
+ tmp = priv->cfg.tuner_i2c_addr;
+ else
+ tmp = 0x14;
+
cmd.args[0] = CMD_TUNER_INIT;
cmd.args[1] = 0x00;
cmd.args[2] = 0x00;
cmd.args[3] = 0x00;
cmd.args[4] = 0x00;
- cmd.args[5] = (priv->cfg.tuner_i2c_addr) ? priv->cfg.tuner_i2c_addr : 0x14;
+ cmd.args[5] = tmp;
cmd.args[6] = 0x00;
cmd.args[7] = 0x03;
cmd.args[8] = 0x02;
@@ -1214,14 +1218,14 @@ struct dvb_frontend *tda10071_attach(const struct tda10071_config *config,
/* make sure demod i2c address is specified */
if (!config->demod_i2c_addr) {
- dev_dbg(&i2c->dev, "%s: invalid demod i2c address!\n", __func__);
+ dev_dbg(&i2c->dev, "%s: invalid demod i2c address\n", __func__);
ret = -EINVAL;
goto error;
}
/* make sure tuner i2c address is specified */
if (!config->tuner_i2c_addr) {
- dev_dbg(&i2c->dev, "%s: invalid tuner i2c address!\n", __func__);
+ dev_dbg(&i2c->dev, "%s: invalid tuner i2c address\n", __func__);
ret = -EINVAL;
goto error;
}
diff --git a/drivers/media/dvb-frontends/tda10071.h b/drivers/media/dvb-frontends/tda10071.h
index f9542f68fe78..331b5a819383 100644
--- a/drivers/media/dvb-frontends/tda10071.h
+++ b/drivers/media/dvb-frontends/tda10071.h
@@ -79,7 +79,7 @@ extern struct dvb_frontend *tda10071_attach(
static inline struct dvb_frontend *tda10071_attach(
const struct tda10071_config *config, struct i2c_adapter *i2c)
{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 4aa9c5311cc5..c930be30eb7e 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -196,7 +196,7 @@ config VIDEO_ADV7183
config VIDEO_ADV7604
tristate "Analog Devices ADV7604 decoder"
- depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
+ depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER
---help---
Support for the Analog Devices ADV7604 video decoder.
@@ -208,7 +208,7 @@ config VIDEO_ADV7604
config VIDEO_ADV7842
tristate "Analog Devices ADV7842 decoder"
- depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
+ depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER
---help---
Support for the Analog Devices ADV7842 video decoder.
@@ -431,7 +431,7 @@ config VIDEO_ADV7393
config VIDEO_ADV7511
tristate "Analog Devices ADV7511 encoder"
- depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
+ depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER
---help---
Support for the Analog Devices ADV7511 video encoder.
@@ -629,6 +629,15 @@ config VIDEO_LM3560
This is a driver for the lm3560 dual flash controllers. It controls
flash, torch LEDs.
+config VIDEO_LM3646
+ tristate "LM3646 dual flash driver support"
+ depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER
+ depends on MEDIA_CAMERA_SUPPORT
+ select REGMAP_I2C
+ ---help---
+ This is a driver for the lm3646 dual flash controllers. It controls
+ flash, torch LEDs.
+
comment "Video improvement chips"
config VIDEO_UPD64031A
@@ -659,6 +668,7 @@ comment "Audio/Video compression chips"
config VIDEO_SAA6752HS
tristate "Philips SAA6752HS MPEG-2 Audio/Video Encoder"
depends on VIDEO_V4L2 && I2C
+ select CRC32
---help---
Support for the Philips SAA6752HS MPEG-2 video and MPEG-audio/AC-3
audio encoder with multiplexer.
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 48888ae876fb..01b6bfc0db5b 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -72,6 +72,7 @@ obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3/
obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o
obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o
obj-$(CONFIG_VIDEO_LM3560) += lm3560.o
+obj-$(CONFIG_VIDEO_LM3646) += lm3646.o
obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o
obj-$(CONFIG_VIDEO_AK881X) += ak881x.o
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c
index 83225d6a0dd9..1b7ecfd88673 100644
--- a/drivers/media/i2c/ad9389b.c
+++ b/drivers/media/i2c/ad9389b.c
@@ -573,7 +573,7 @@ static const struct v4l2_subdev_core_ops ad9389b_core_ops = {
/* ------------------------------ PAD OPS ------------------------------ */
-static int ad9389b_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
+static int ad9389b_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
{
struct ad9389b_state *state = get_ad9389b_state(sd);
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index d7d99f1c69e4..5e638b159452 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -123,11 +123,11 @@
struct adv7180_state {
struct v4l2_ctrl_handler ctrl_hdl;
struct v4l2_subdev sd;
- struct work_struct work;
struct mutex mutex; /* mutual excl. when accessing chip */
int irq;
v4l2_std_id curr_norm;
bool autodetect;
+ bool powered;
u8 input;
};
#define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \
@@ -312,6 +312,37 @@ out:
return ret;
}
+static int adv7180_set_power(struct adv7180_state *state,
+ struct i2c_client *client, bool on)
+{
+ u8 val;
+
+ if (on)
+ val = ADV7180_PWR_MAN_ON;
+ else
+ val = ADV7180_PWR_MAN_OFF;
+
+ return i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG, val);
+}
+
+static int adv7180_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct adv7180_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ ret = mutex_lock_interruptible(&state->mutex);
+ if (ret)
+ return ret;
+
+ ret = adv7180_set_power(state, client, on);
+ if (ret == 0)
+ state->powered = on;
+
+ mutex_unlock(&state->mutex);
+ return ret;
+}
+
static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd = to_adv7180_sd(ctrl);
@@ -442,6 +473,7 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = {
static const struct v4l2_subdev_core_ops adv7180_core_ops = {
.s_std = adv7180_s_std,
+ .s_power = adv7180_s_power,
};
static const struct v4l2_subdev_ops adv7180_ops = {
@@ -449,10 +481,9 @@ static const struct v4l2_subdev_ops adv7180_ops = {
.video = &adv7180_video_ops,
};
-static void adv7180_work(struct work_struct *work)
+static irqreturn_t adv7180_irq(int irq, void *devid)
{
- struct adv7180_state *state = container_of(work, struct adv7180_state,
- work);
+ struct adv7180_state *state = devid;
struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
u8 isr3;
@@ -468,17 +499,6 @@ static void adv7180_work(struct work_struct *work)
__adv7180_status(client, NULL, &state->curr_norm);
mutex_unlock(&state->mutex);
- enable_irq(state->irq);
-}
-
-static irqreturn_t adv7180_irq(int irq, void *devid)
-{
- struct adv7180_state *state = devid;
-
- schedule_work(&state->work);
-
- disable_irq_nosync(state->irq);
-
return IRQ_HANDLED;
}
@@ -533,48 +553,52 @@ static int init_device(struct i2c_client *client, struct adv7180_state *state)
/* register for interrupts */
if (state->irq > 0) {
- ret = request_irq(state->irq, adv7180_irq, 0, KBUILD_MODNAME,
- state);
+ ret = request_threaded_irq(state->irq, NULL, adv7180_irq,
+ IRQF_ONESHOT, KBUILD_MODNAME, state);
if (ret)
return ret;
ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
ADV7180_ADI_CTRL_IRQ_SPACE);
if (ret < 0)
- return ret;
+ goto err;
/* config the Interrupt pin to be active low */
ret = i2c_smbus_write_byte_data(client, ADV7180_ICONF1_ADI,
ADV7180_ICONF1_ACTIVE_LOW |
ADV7180_ICONF1_PSYNC_ONLY);
if (ret < 0)
- return ret;
+ goto err;
ret = i2c_smbus_write_byte_data(client, ADV7180_IMR1_ADI, 0);
if (ret < 0)
- return ret;
+ goto err;
ret = i2c_smbus_write_byte_data(client, ADV7180_IMR2_ADI, 0);
if (ret < 0)
- return ret;
+ goto err;
/* enable AD change interrupts interrupts */
ret = i2c_smbus_write_byte_data(client, ADV7180_IMR3_ADI,
ADV7180_IRQ3_AD_CHANGE);
if (ret < 0)
- return ret;
+ goto err;
ret = i2c_smbus_write_byte_data(client, ADV7180_IMR4_ADI, 0);
if (ret < 0)
- return ret;
+ goto err;
ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
0);
if (ret < 0)
- return ret;
+ goto err;
}
return 0;
+
+err:
+ free_irq(state->irq, state);
+ return ret;
}
static int adv7180_probe(struct i2c_client *client,
@@ -598,9 +622,9 @@ static int adv7180_probe(struct i2c_client *client,
}
state->irq = client->irq;
- INIT_WORK(&state->work, adv7180_work);
mutex_init(&state->mutex);
state->autodetect = true;
+ state->powered = true;
state->input = 0;
sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
@@ -611,15 +635,21 @@ static int adv7180_probe(struct i2c_client *client,
ret = init_device(client, state);
if (ret)
goto err_free_ctrl;
+
+ ret = v4l2_async_register_subdev(sd);
+ if (ret)
+ goto err_free_irq;
+
return 0;
+err_free_irq:
+ if (state->irq > 0)
+ free_irq(client->irq, state);
err_free_ctrl:
adv7180_exit_controls(state);
err_unreg_subdev:
mutex_destroy(&state->mutex);
- v4l2_device_unregister_subdev(sd);
err:
- printk(KERN_ERR KBUILD_MODNAME ": Failed to probe: %d\n", ret);
return ret;
}
@@ -628,20 +658,14 @@ static int adv7180_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct adv7180_state *state = to_state(sd);
- if (state->irq > 0) {
+ v4l2_async_unregister_subdev(sd);
+
+ if (state->irq > 0)
free_irq(client->irq, state);
- if (cancel_work_sync(&state->work)) {
- /*
- * Work was pending, therefore we need to enable
- * IRQ here to balance the disable_irq() done in the
- * interrupt handler.
- */
- enable_irq(state->irq);
- }
- }
- mutex_destroy(&state->mutex);
v4l2_device_unregister_subdev(sd);
+ adv7180_exit_controls(state);
+ mutex_destroy(&state->mutex);
return 0;
}
@@ -654,13 +678,10 @@ static const struct i2c_device_id adv7180_id[] = {
static int adv7180_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
- int ret;
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct adv7180_state *state = to_state(sd);
- ret = i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG,
- ADV7180_PWR_MAN_OFF);
- if (ret < 0)
- return ret;
- return 0;
+ return adv7180_set_power(state, client, false);
}
static int adv7180_resume(struct device *dev)
@@ -670,10 +691,11 @@ static int adv7180_resume(struct device *dev)
struct adv7180_state *state = to_state(sd);
int ret;
- ret = i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG,
- ADV7180_PWR_MAN_ON);
- if (ret < 0)
- return ret;
+ if (state->powered) {
+ ret = adv7180_set_power(state, client, true);
+ if (ret)
+ return ret;
+ }
ret = init_device(client, state);
if (ret < 0)
return ret;
diff --git a/drivers/media/i2c/adv7343.c b/drivers/media/i2c/adv7343.c
index d4e15a617c3b..9d38f7b36cd1 100644
--- a/drivers/media/i2c/adv7343.c
+++ b/drivers/media/i2c/adv7343.c
@@ -26,12 +26,12 @@
#include <linux/videodev2.h>
#include <linux/uaccess.h>
#include <linux/of.h>
+#include <linux/of_graph.h>
#include <media/adv7343.h>
#include <media/v4l2-async.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
-#include <media/v4l2-of.h>
#include "adv7343_regs.h"
@@ -410,7 +410,7 @@ adv7343_get_pdata(struct i2c_client *client)
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
return client->dev.platform_data;
- np = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
+ np = of_graph_get_next_endpoint(client->dev.of_node, NULL);
if (!np)
return NULL;
diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
index ee618942cb8e..942ca4b99297 100644
--- a/drivers/media/i2c/adv7511.c
+++ b/drivers/media/i2c/adv7511.c
@@ -597,7 +597,7 @@ static int adv7511_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
return 0;
}
-static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
+static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
{
struct adv7511_state *state = get_adv7511_state(sd);
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 71c8570bd9ea..98cc5407f1b1 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -1658,7 +1658,7 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
return 0;
}
-static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
+static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
{
struct adv7604_state *state = to_state(sd);
u8 *data = NULL;
@@ -1728,7 +1728,7 @@ static int get_edid_spa_location(const u8 *edid)
return -1;
}
-static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
+static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
{
struct adv7604_state *state = to_state(sd);
int spa_loc;
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index 9bbd6656fb8f..636ac08925f6 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -546,6 +546,14 @@ static void main_reset(struct v4l2_subdev *sd)
/* ----------------------------------------------------------------------- */
+static inline bool is_analog_input(struct v4l2_subdev *sd)
+{
+ struct adv7842_state *state = to_state(sd);
+
+ return ((state->mode == ADV7842_MODE_RGB) ||
+ (state->mode == ADV7842_MODE_COMP));
+}
+
static inline bool is_digital_input(struct v4l2_subdev *sd)
{
struct adv7842_state *state = to_state(sd);
@@ -1027,12 +1035,72 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd,
cp_write(sd, 0xac, (height & 0x0f) << 4);
}
+static void adv7842_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 offset_a, u16 offset_b, u16 offset_c)
+{
+ struct adv7842_state *state = to_state(sd);
+ u8 offset_buf[4];
+
+ if (auto_offset) {
+ offset_a = 0x3ff;
+ offset_b = 0x3ff;
+ offset_c = 0x3ff;
+ }
+
+ v4l2_dbg(2, debug, sd, "%s: %s offset: a = 0x%x, b = 0x%x, c = 0x%x\n",
+ __func__, auto_offset ? "Auto" : "Manual",
+ offset_a, offset_b, offset_c);
+
+ offset_buf[0]= (cp_read(sd, 0x77) & 0xc0) | ((offset_a & 0x3f0) >> 4);
+ offset_buf[1] = ((offset_a & 0x00f) << 4) | ((offset_b & 0x3c0) >> 6);
+ offset_buf[2] = ((offset_b & 0x03f) << 2) | ((offset_c & 0x300) >> 8);
+ offset_buf[3] = offset_c & 0x0ff;
+
+ /* Registers must be written in this order with no i2c access in between */
+ if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x77, 4, offset_buf))
+ v4l2_err(sd, "%s: i2c error writing to CP reg 0x77, 0x78, 0x79, 0x7a\n", __func__);
+}
+
+static void adv7842_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, u16 gain_b, u16 gain_c)
+{
+ struct adv7842_state *state = to_state(sd);
+ u8 gain_buf[4];
+ u8 gain_man = 1;
+ u8 agc_mode_man = 1;
+
+ if (auto_gain) {
+ gain_man = 0;
+ agc_mode_man = 0;
+ gain_a = 0x100;
+ gain_b = 0x100;
+ gain_c = 0x100;
+ }
+
+ v4l2_dbg(2, debug, sd, "%s: %s gain: a = 0x%x, b = 0x%x, c = 0x%x\n",
+ __func__, auto_gain ? "Auto" : "Manual",
+ gain_a, gain_b, gain_c);
+
+ gain_buf[0] = ((gain_man << 7) | (agc_mode_man << 6) | ((gain_a & 0x3f0) >> 4));
+ gain_buf[1] = (((gain_a & 0x00f) << 4) | ((gain_b & 0x3c0) >> 6));
+ gain_buf[2] = (((gain_b & 0x03f) << 2) | ((gain_c & 0x300) >> 8));
+ gain_buf[3] = ((gain_c & 0x0ff));
+
+ /* Registers must be written in this order with no i2c access in between */
+ if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x73, 4, gain_buf))
+ v4l2_err(sd, "%s: i2c error writing to CP reg 0x73, 0x74, 0x75, 0x76\n", __func__);
+}
+
static void set_rgb_quantization_range(struct v4l2_subdev *sd)
{
struct adv7842_state *state = to_state(sd);
+ bool rgb_output = io_read(sd, 0x02) & 0x02;
+ bool hdmi_signal = hdmi_read(sd, 0x05) & 0x80;
+
+ v4l2_dbg(2, debug, sd, "%s: RGB quantization range: %d, RGB out: %d, HDMI: %d\n",
+ __func__, state->rgb_quantization_range,
+ rgb_output, hdmi_signal);
- v4l2_dbg(2, debug, sd, "%s: rgb_quantization_range = %d\n",
- __func__, state->rgb_quantization_range);
+ adv7842_set_gain(sd, true, 0x0, 0x0, 0x0);
+ adv7842_set_offset(sd, true, 0x0, 0x0, 0x0);
switch (state->rgb_quantization_range) {
case V4L2_DV_RGB_RANGE_AUTO:
@@ -1050,7 +1118,7 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)
break;
}
- if (hdmi_read(sd, 0x05) & 0x80) {
+ if (hdmi_signal) {
/* Receiving HDMI signal
* Set automode */
io_write_and_or(sd, 0x02, 0x0f, 0xf0);
@@ -1066,24 +1134,45 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)
} else {
/* RGB full range (0-255) */
io_write_and_or(sd, 0x02, 0x0f, 0x10);
+
+ if (is_digital_input(sd) && rgb_output) {
+ adv7842_set_offset(sd, false, 0x40, 0x40, 0x40);
+ } else {
+ adv7842_set_gain(sd, false, 0xe0, 0xe0, 0xe0);
+ adv7842_set_offset(sd, false, 0x70, 0x70, 0x70);
+ }
}
break;
case V4L2_DV_RGB_RANGE_LIMITED:
if (state->mode == ADV7842_MODE_COMP) {
/* YCrCb limited range (16-235) */
io_write_and_or(sd, 0x02, 0x0f, 0x20);
- } else {
- /* RGB limited range (16-235) */
- io_write_and_or(sd, 0x02, 0x0f, 0x00);
+ break;
}
+
+ /* RGB limited range (16-235) */
+ io_write_and_or(sd, 0x02, 0x0f, 0x00);
+
break;
case V4L2_DV_RGB_RANGE_FULL:
if (state->mode == ADV7842_MODE_COMP) {
/* YCrCb full range (0-255) */
io_write_and_or(sd, 0x02, 0x0f, 0x60);
+ break;
+ }
+
+ /* RGB full range (0-255) */
+ io_write_and_or(sd, 0x02, 0x0f, 0x10);
+
+ if (is_analog_input(sd) || hdmi_signal)
+ break;
+
+ /* Adjust gain/offset for DVI-D signals only */
+ if (rgb_output) {
+ adv7842_set_offset(sd, false, 0x40, 0x40, 0x40);
} else {
- /* RGB full range (0-255) */
- io_write_and_or(sd, 0x02, 0x0f, 0x10);
+ adv7842_set_gain(sd, false, 0xe0, 0xe0, 0xe0);
+ adv7842_set_offset(sd, false, 0x70, 0x70, 0x70);
}
break;
}
@@ -1360,12 +1449,11 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd,
bt->width = (hdmi_read(sd, 0x07) & 0x0f) * 256 + hdmi_read(sd, 0x08);
bt->height = (hdmi_read(sd, 0x09) & 0x0f) * 256 + hdmi_read(sd, 0x0a);
- freq = (hdmi_read(sd, 0x06) * 1000000) +
- ((hdmi_read(sd, 0x3b) & 0x30) >> 4) * 250000;
-
+ freq = ((hdmi_read(sd, 0x51) << 1) + (hdmi_read(sd, 0x52) >> 7)) * 1000000;
+ freq += ((hdmi_read(sd, 0x52) & 0x7f) * 7813);
if (is_hdmi(sd)) {
/* adjust for deep color mode */
- freq = freq * 8 / (((hdmi_read(sd, 0x0b) & 0xc0) >> 5) + 8);
+ freq = freq * 8 / (((hdmi_read(sd, 0x0b) & 0xc0) >> 6) * 2 + 8);
}
bt->pixelclock = freq;
bt->hfrontporch = (hdmi_read(sd, 0x20) & 0x03) * 256 +
@@ -1717,8 +1805,8 @@ static void select_input(struct v4l2_subdev *sd,
* (rev. 2.5, June 2010)" p. 17. */
afe_write(sd, 0x12, 0xfb); /* ADC noise shaping filter controls */
afe_write(sd, 0x0c, 0x0d); /* CP core gain controls */
- cp_write(sd, 0x3e, 0x80); /* CP core pre-gain control,
- enable color control */
+ cp_write(sd, 0x3e, 0x00); /* CP core pre-gain control */
+
/* CP coast control */
cp_write(sd, 0xc3, 0x33); /* Component mode */
@@ -1926,7 +2014,7 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
return 0;
}
-static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
+static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
{
struct adv7842_state *state = to_state(sd);
u8 *data = NULL;
@@ -1966,7 +2054,7 @@ static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi
return 0;
}
-static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *e)
+static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
{
struct adv7842_state *state = to_state(sd);
int err = 0;
@@ -2103,7 +2191,8 @@ static void print_avi_infoframe(struct v4l2_subdev *sd)
{
int i;
uint8_t buf[14];
- uint8_t avi_inf_len;
+ u8 avi_len;
+ u8 avi_ver;
struct avi_info_frame avi;
if (!(hdmi_read(sd, 0x05) & 0x80)) {
@@ -2116,18 +2205,20 @@ static void print_avi_infoframe(struct v4l2_subdev *sd)
}
if (io_read(sd, 0x88) & 0x10) {
- /* Note: the ADV7842 calculated incorrect checksums for InfoFrames
- with a length of 14 or 15. See the ADV7842 Register Settings
- Recommendations document for more details. */
- v4l2_info(sd, "AVI infoframe checksum error\n");
- return;
+ v4l2_info(sd, "AVI infoframe checksum error has occurred earlier\n");
+ io_write(sd, 0x8a, 0x10); /* clear AVI_INF_CKS_ERR_RAW */
+ if (io_read(sd, 0x88) & 0x10) {
+ v4l2_info(sd, "AVI infoframe checksum error still present\n");
+ io_write(sd, 0x8a, 0x10); /* clear AVI_INF_CKS_ERR_RAW */
+ }
}
- avi_inf_len = infoframe_read(sd, 0xe2);
+ avi_len = infoframe_read(sd, 0xe2);
+ avi_ver = infoframe_read(sd, 0xe1);
v4l2_info(sd, "AVI infoframe version %d (%d byte)\n",
- infoframe_read(sd, 0xe1), avi_inf_len);
+ avi_ver, avi_len);
- if (infoframe_read(sd, 0xe1) != 0x02)
+ if (avi_ver != 0x02)
return;
for (i = 0; i < 14; i++)
@@ -2602,9 +2693,15 @@ static int adv7842_core_init(struct v4l2_subdev *sd)
/* disable I2C access to internal EDID ram from HDMI DDC ports */
rep_write_and_or(sd, 0x77, 0xf3, 0x00);
- hdmi_write(sd, 0x69, 0xa3); /* HPA manual */
- /* HPA disable on port A and B */
- io_write_and_or(sd, 0x20, 0xcf, 0x00);
+ if (pdata->hpa_auto) {
+ /* HPA auto, HPA 0.5s after Edid set and Cable detect */
+ hdmi_write(sd, 0x69, 0x5c);
+ } else {
+ /* HPA manual */
+ hdmi_write(sd, 0x69, 0xa3);
+ /* HPA disable on port A and B */
+ io_write_and_or(sd, 0x20, 0xcf, 0x00);
+ }
/* LLC */
io_write(sd, 0x19, 0x80 | pdata->llc_dll_phase);
diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c
index 99ee456700f4..c8fe1358ec9e 100644
--- a/drivers/media/i2c/ir-kbd-i2c.c
+++ b/drivers/media/i2c/ir-kbd-i2c.c
@@ -431,8 +431,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
* Initialize the other fields of rc_dev
*/
rc->map_name = ir->ir_codes;
- rc->allowed_protos = rc_type;
- rc->enabled_protocols = rc_type;
+ rc_set_allowed_protocols(rc, rc_type);
+ rc_set_enabled_protocols(rc, rc_type);
if (!rc->driver_name)
rc->driver_name = MODULE_NAME;
diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c
index d98ca3aebe23..c23de593c17d 100644
--- a/drivers/media/i2c/lm3560.c
+++ b/drivers/media/i2c/lm3560.c
@@ -15,12 +15,6 @@
* WITHOUT 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/delay.h>
@@ -42,7 +36,7 @@
#define REG_FLAG 0xd0
#define REG_CONFIG1 0xe0
-/* Fault Mask */
+/* fault mask */
#define FAULT_TIMEOUT (1<<0)
#define FAULT_OVERTEMP (1<<1)
#define FAULT_SHORT_CIRCUIT (1<<2)
@@ -53,7 +47,8 @@ enum led_enable {
MODE_FLASH = 0x3,
};
-/* struct lm3560_flash
+/**
+ * struct lm3560_flash
*
* @pdata: platform data
* @regmap: reg. map for i2c
@@ -98,7 +93,7 @@ static int lm3560_mode_ctrl(struct lm3560_flash *flash)
return rval;
}
-/* led1/2 enable/disable */
+/* led1/2 enable/disable */
static int lm3560_enable_ctrl(struct lm3560_flash *flash,
enum lm3560_led_id led_no, bool on)
{
@@ -168,7 +163,7 @@ static int lm3560_flash_brt_ctrl(struct lm3560_flash *flash,
return rval;
}
-/* V4L2 controls */
+/* v4l2 controls */
static int lm3560_get_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no)
{
struct lm3560_flash *flash = to_lm3560_flash(ctrl, led_no);
@@ -297,6 +292,7 @@ static int lm3560_init_controls(struct lm3560_flash *flash,
const struct v4l2_ctrl_ops *ops = &lm3560_led_ctrl_ops[led_no];
v4l2_ctrl_handler_init(hdl, 8);
+
/* flash mode */
v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_FLASH_LED_MODE,
V4L2_FLASH_LED_MODE_TORCH, ~0x7,
@@ -309,6 +305,7 @@ static int lm3560_init_controls(struct lm3560_flash *flash,
/* flash strobe */
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE, 0, 0, 0, 0);
+
/* flash strobe stop */
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0);
@@ -395,7 +392,7 @@ static int lm3560_init_device(struct lm3560_flash *flash)
rval = lm3560_mode_ctrl(flash);
if (rval < 0)
return rval;
- /* Reset faults */
+ /* reset faults */
rval = regmap_read(flash->regmap, REG_FLAG, &reg_val);
return rval;
}
@@ -419,8 +416,7 @@ static int lm3560_probe(struct i2c_client *client,
/* if there is no platform data, use chip default value */
if (pdata == NULL) {
- pdata =
- kzalloc(sizeof(struct lm3560_platform_data), GFP_KERNEL);
+ pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
if (pdata == NULL)
return -ENODEV;
pdata->peak = LM3560_PEAK_3600mA;
diff --git a/drivers/media/i2c/lm3646.c b/drivers/media/i2c/lm3646.c
new file mode 100644
index 000000000000..626fb4679c02
--- /dev/null
+++ b/drivers/media/i2c/lm3646.c
@@ -0,0 +1,414 @@
+/*
+ * drivers/media/i2c/lm3646.c
+ * General device driver for TI lm3646, Dual FLASH LED Driver
+ *
+ * Copyright (C) 2014 Texas Instruments
+ *
+ * Contact: Daniel Jeong <gshark.jeong@gmail.com>
+ * Ldd-Mlp <ldd-mlp@list.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 as published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/videodev2.h>
+#include <media/lm3646.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+
+/* registers definitions */
+#define REG_ENABLE 0x01
+#define REG_TORCH_BR 0x05
+#define REG_FLASH_BR 0x05
+#define REG_FLASH_TOUT 0x04
+#define REG_FLAG 0x08
+#define REG_STROBE_SRC 0x06
+#define REG_LED1_FLASH_BR 0x06
+#define REG_LED1_TORCH_BR 0x07
+
+#define MASK_ENABLE 0x03
+#define MASK_TORCH_BR 0x70
+#define MASK_FLASH_BR 0x0F
+#define MASK_FLASH_TOUT 0x07
+#define MASK_FLAG 0xFF
+#define MASK_STROBE_SRC 0x80
+
+/* Fault Mask */
+#define FAULT_TIMEOUT (1<<0)
+#define FAULT_SHORT_CIRCUIT (1<<1)
+#define FAULT_UVLO (1<<2)
+#define FAULT_IVFM (1<<3)
+#define FAULT_OCP (1<<4)
+#define FAULT_OVERTEMP (1<<5)
+#define FAULT_NTC_TRIP (1<<6)
+#define FAULT_OVP (1<<7)
+
+enum led_mode {
+ MODE_SHDN = 0x0,
+ MODE_TORCH = 0x2,
+ MODE_FLASH = 0x3,
+};
+
+/*
+ * struct lm3646_flash
+ *
+ * @pdata: platform data
+ * @regmap: reg. map for i2c
+ * @lock: muxtex for serial access.
+ * @led_mode: V4L2 LED mode
+ * @ctrls_led: V4L2 contols
+ * @subdev_led: V4L2 subdev
+ * @mode_reg : mode register value
+ */
+struct lm3646_flash {
+ struct device *dev;
+ struct lm3646_platform_data *pdata;
+ struct regmap *regmap;
+
+ struct v4l2_ctrl_handler ctrls_led;
+ struct v4l2_subdev subdev_led;
+
+ u8 mode_reg;
+};
+
+#define to_lm3646_flash(_ctrl) \
+ container_of(_ctrl->handler, struct lm3646_flash, ctrls_led)
+
+/* enable mode control */
+static int lm3646_mode_ctrl(struct lm3646_flash *flash,
+ enum v4l2_flash_led_mode led_mode)
+{
+ switch (led_mode) {
+ case V4L2_FLASH_LED_MODE_NONE:
+ return regmap_write(flash->regmap,
+ REG_ENABLE, flash->mode_reg | MODE_SHDN);
+ case V4L2_FLASH_LED_MODE_TORCH:
+ return regmap_write(flash->regmap,
+ REG_ENABLE, flash->mode_reg | MODE_TORCH);
+ case V4L2_FLASH_LED_MODE_FLASH:
+ return regmap_write(flash->regmap,
+ REG_ENABLE, flash->mode_reg | MODE_FLASH);
+ }
+ return -EINVAL;
+}
+
+/* V4L2 controls */
+static int lm3646_get_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct lm3646_flash *flash = to_lm3646_flash(ctrl);
+ unsigned int reg_val;
+ int rval;
+
+ if (ctrl->id != V4L2_CID_FLASH_FAULT)
+ return -EINVAL;
+
+ rval = regmap_read(flash->regmap, REG_FLAG, &reg_val);
+ if (rval < 0)
+ return rval;
+
+ ctrl->val = 0;
+ if (reg_val & FAULT_TIMEOUT)
+ ctrl->val |= V4L2_FLASH_FAULT_TIMEOUT;
+ if (reg_val & FAULT_SHORT_CIRCUIT)
+ ctrl->val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
+ if (reg_val & FAULT_UVLO)
+ ctrl->val |= V4L2_FLASH_FAULT_UNDER_VOLTAGE;
+ if (reg_val & FAULT_IVFM)
+ ctrl->val |= V4L2_FLASH_FAULT_INPUT_VOLTAGE;
+ if (reg_val & FAULT_OCP)
+ ctrl->val |= V4L2_FLASH_FAULT_OVER_CURRENT;
+ if (reg_val & FAULT_OVERTEMP)
+ ctrl->val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
+ if (reg_val & FAULT_NTC_TRIP)
+ ctrl->val |= V4L2_FLASH_FAULT_LED_OVER_TEMPERATURE;
+ if (reg_val & FAULT_OVP)
+ ctrl->val |= V4L2_FLASH_FAULT_OVER_VOLTAGE;
+
+ return 0;
+}
+
+static int lm3646_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct lm3646_flash *flash = to_lm3646_flash(ctrl);
+ unsigned int reg_val;
+ int rval = -EINVAL;
+
+ switch (ctrl->id) {
+ case V4L2_CID_FLASH_LED_MODE:
+
+ if (ctrl->val != V4L2_FLASH_LED_MODE_FLASH)
+ return lm3646_mode_ctrl(flash, ctrl->val);
+ /* switch to SHDN mode before flash strobe on */
+ return lm3646_mode_ctrl(flash, V4L2_FLASH_LED_MODE_NONE);
+
+ case V4L2_CID_FLASH_STROBE_SOURCE:
+ return regmap_update_bits(flash->regmap,
+ REG_STROBE_SRC, MASK_STROBE_SRC,
+ (ctrl->val) << 7);
+
+ case V4L2_CID_FLASH_STROBE:
+
+ /* read and check current mode of chip to start flash */
+ rval = regmap_read(flash->regmap, REG_ENABLE, &reg_val);
+ if (rval < 0 || ((reg_val & MASK_ENABLE) != MODE_SHDN))
+ return rval;
+ /* flash on */
+ return lm3646_mode_ctrl(flash, V4L2_FLASH_LED_MODE_FLASH);
+
+ case V4L2_CID_FLASH_STROBE_STOP:
+
+ /*
+ * flash mode will be turned automatically
+ * from FLASH mode to SHDN mode after flash duration timeout
+ * read and check current mode of chip to stop flash
+ */
+ rval = regmap_read(flash->regmap, REG_ENABLE, &reg_val);
+ if (rval < 0)
+ return rval;
+ if ((reg_val & MASK_ENABLE) == MODE_FLASH)
+ return lm3646_mode_ctrl(flash,
+ V4L2_FLASH_LED_MODE_NONE);
+ return rval;
+
+ case V4L2_CID_FLASH_TIMEOUT:
+ return regmap_update_bits(flash->regmap,
+ REG_FLASH_TOUT, MASK_FLASH_TOUT,
+ LM3646_FLASH_TOUT_ms_TO_REG
+ (ctrl->val));
+
+ case V4L2_CID_FLASH_INTENSITY:
+ return regmap_update_bits(flash->regmap,
+ REG_FLASH_BR, MASK_FLASH_BR,
+ LM3646_TOTAL_FLASH_BRT_uA_TO_REG
+ (ctrl->val));
+
+ case V4L2_CID_FLASH_TORCH_INTENSITY:
+ return regmap_update_bits(flash->regmap,
+ REG_TORCH_BR, MASK_TORCH_BR,
+ LM3646_TOTAL_TORCH_BRT_uA_TO_REG
+ (ctrl->val) << 4);
+ }
+
+ return -EINVAL;
+}
+
+static const struct v4l2_ctrl_ops lm3646_led_ctrl_ops = {
+ .g_volatile_ctrl = lm3646_get_ctrl,
+ .s_ctrl = lm3646_set_ctrl,
+};
+
+static int lm3646_init_controls(struct lm3646_flash *flash)
+{
+ struct v4l2_ctrl *fault;
+ struct v4l2_ctrl_handler *hdl = &flash->ctrls_led;
+ const struct v4l2_ctrl_ops *ops = &lm3646_led_ctrl_ops;
+
+ v4l2_ctrl_handler_init(hdl, 8);
+ /* flash mode */
+ v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_FLASH_LED_MODE,
+ V4L2_FLASH_LED_MODE_TORCH, ~0x7,
+ V4L2_FLASH_LED_MODE_NONE);
+
+ /* flash source */
+ v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_FLASH_STROBE_SOURCE,
+ 0x1, ~0x3, V4L2_FLASH_STROBE_SOURCE_SOFTWARE);
+
+ /* flash strobe */
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE, 0, 0, 0, 0);
+ /* flash strobe stop */
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0);
+
+ /* flash strobe timeout */
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_TIMEOUT,
+ LM3646_FLASH_TOUT_MIN,
+ LM3646_FLASH_TOUT_MAX,
+ LM3646_FLASH_TOUT_STEP, flash->pdata->flash_timeout);
+
+ /* max flash current */
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_INTENSITY,
+ LM3646_TOTAL_FLASH_BRT_MIN,
+ LM3646_TOTAL_FLASH_BRT_MAX,
+ LM3646_TOTAL_FLASH_BRT_STEP,
+ LM3646_TOTAL_FLASH_BRT_MAX);
+
+ /* max torch current */
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_TORCH_INTENSITY,
+ LM3646_TOTAL_TORCH_BRT_MIN,
+ LM3646_TOTAL_TORCH_BRT_MAX,
+ LM3646_TOTAL_TORCH_BRT_STEP,
+ LM3646_TOTAL_TORCH_BRT_MAX);
+
+ /* fault */
+ fault = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_FAULT, 0,
+ V4L2_FLASH_FAULT_OVER_VOLTAGE
+ | V4L2_FLASH_FAULT_OVER_TEMPERATURE
+ | V4L2_FLASH_FAULT_SHORT_CIRCUIT
+ | V4L2_FLASH_FAULT_TIMEOUT, 0, 0);
+ if (fault != NULL)
+ fault->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+ if (hdl->error)
+ return hdl->error;
+
+ flash->subdev_led.ctrl_handler = hdl;
+ return 0;
+}
+
+/* initialize device */
+static const struct v4l2_subdev_ops lm3646_ops = {
+ .core = NULL,
+};
+
+static const struct regmap_config lm3646_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xFF,
+};
+
+static int lm3646_subdev_init(struct lm3646_flash *flash)
+{
+ struct i2c_client *client = to_i2c_client(flash->dev);
+ int rval;
+
+ v4l2_i2c_subdev_init(&flash->subdev_led, client, &lm3646_ops);
+ flash->subdev_led.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ strcpy(flash->subdev_led.name, LM3646_NAME);
+ rval = lm3646_init_controls(flash);
+ if (rval)
+ goto err_out;
+ rval = media_entity_init(&flash->subdev_led.entity, 0, NULL, 0);
+ if (rval < 0)
+ goto err_out;
+ flash->subdev_led.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH;
+ return rval;
+
+err_out:
+ v4l2_ctrl_handler_free(&flash->ctrls_led);
+ return rval;
+}
+
+static int lm3646_init_device(struct lm3646_flash *flash)
+{
+ unsigned int reg_val;
+ int rval;
+
+ /* read the value of mode register to reduce redundant i2c accesses */
+ rval = regmap_read(flash->regmap, REG_ENABLE, &reg_val);
+ if (rval < 0)
+ return rval;
+ flash->mode_reg = reg_val & 0xfc;
+
+ /* output disable */
+ rval = lm3646_mode_ctrl(flash, V4L2_FLASH_LED_MODE_NONE);
+ if (rval < 0)
+ return rval;
+
+ /*
+ * LED1 flash current setting
+ * LED2 flash current = Total(Max) flash current - LED1 flash current
+ */
+ rval = regmap_update_bits(flash->regmap,
+ REG_LED1_FLASH_BR, 0x7F,
+ LM3646_LED1_FLASH_BRT_uA_TO_REG
+ (flash->pdata->led1_flash_brt));
+
+ if (rval < 0)
+ return rval;
+
+ /*
+ * LED1 torch current setting
+ * LED2 torch current = Total(Max) torch current - LED1 torch current
+ */
+ rval = regmap_update_bits(flash->regmap,
+ REG_LED1_TORCH_BR, 0x7F,
+ LM3646_LED1_TORCH_BRT_uA_TO_REG
+ (flash->pdata->led1_torch_brt));
+ if (rval < 0)
+ return rval;
+
+ /* Reset flag register */
+ return regmap_read(flash->regmap, REG_FLAG, &reg_val);
+}
+
+static int lm3646_probe(struct i2c_client *client,
+ const struct i2c_device_id *devid)
+{
+ struct lm3646_flash *flash;
+ struct lm3646_platform_data *pdata = dev_get_platdata(&client->dev);
+ int rval;
+
+ flash = devm_kzalloc(&client->dev, sizeof(*flash), GFP_KERNEL);
+ if (flash == NULL)
+ return -ENOMEM;
+
+ flash->regmap = devm_regmap_init_i2c(client, &lm3646_regmap);
+ if (IS_ERR(flash->regmap))
+ return PTR_ERR(flash->regmap);
+
+ /* check device tree if there is no platform data */
+ if (pdata == NULL) {
+ pdata = devm_kzalloc(&client->dev,
+ sizeof(struct lm3646_platform_data),
+ GFP_KERNEL);
+ if (pdata == NULL)
+ return -ENOMEM;
+ /* use default data in case of no platform data */
+ pdata->flash_timeout = LM3646_FLASH_TOUT_MAX;
+ pdata->led1_torch_brt = LM3646_LED1_TORCH_BRT_MAX;
+ pdata->led1_flash_brt = LM3646_LED1_FLASH_BRT_MAX;
+ }
+ flash->pdata = pdata;
+ flash->dev = &client->dev;
+
+ rval = lm3646_subdev_init(flash);
+ if (rval < 0)
+ return rval;
+
+ rval = lm3646_init_device(flash);
+ if (rval < 0)
+ return rval;
+
+ i2c_set_clientdata(client, flash);
+
+ return 0;
+}
+
+static int lm3646_remove(struct i2c_client *client)
+{
+ struct lm3646_flash *flash = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(&flash->subdev_led);
+ v4l2_ctrl_handler_free(&flash->ctrls_led);
+ media_entity_cleanup(&flash->subdev_led.entity);
+
+ return 0;
+}
+
+static const struct i2c_device_id lm3646_id_table[] = {
+ {LM3646_NAME, 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, lm3646_id_table);
+
+static struct i2c_driver lm3646_i2c_driver = {
+ .driver = {
+ .name = LM3646_NAME,
+ },
+ .probe = lm3646_probe,
+ .remove = lm3646_remove,
+ .id_table = lm3646_id_table,
+};
+
+module_i2c_driver(lm3646_i2c_driver);
+
+MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
+MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>");
+MODULE_DESCRIPTION("Texas Instruments LM3646 Dual Flash LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index e5ddf47030fd..33daace81297 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
+#include <linux/of_graph.h>
#include <linux/pm.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -29,7 +30,6 @@
#include <media/mt9p031.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-of.h>
#include <media/v4l2-subdev.h>
#include "aptina-pll.h"
@@ -78,6 +78,9 @@
#define MT9P031_PLL_CONFIG_1 0x11
#define MT9P031_PLL_CONFIG_2 0x12
#define MT9P031_PIXEL_CLOCK_CONTROL 0x0a
+#define MT9P031_PIXEL_CLOCK_INVERT (1 << 15)
+#define MT9P031_PIXEL_CLOCK_SHIFT(n) ((n) << 8)
+#define MT9P031_PIXEL_CLOCK_DIVIDE(n) ((n) << 0)
#define MT9P031_FRAME_RESTART 0x0b
#define MT9P031_SHUTTER_DELAY 0x0c
#define MT9P031_RST 0x0d
@@ -130,6 +133,8 @@ struct mt9p031 {
enum mt9p031_model model;
struct aptina_pll pll;
+ unsigned int clk_div;
+ bool use_pll;
int reset;
struct v4l2_ctrl_handler ctrls;
@@ -198,6 +203,11 @@ static int mt9p031_reset(struct mt9p031 *mt9p031)
if (ret < 0)
return ret;
+ ret = mt9p031_write(client, MT9P031_PIXEL_CLOCK_CONTROL,
+ MT9P031_PIXEL_CLOCK_DIVIDE(mt9p031->clk_div));
+ if (ret < 0)
+ return ret;
+
return mt9p031_set_output_control(mt9p031, MT9P031_OUTPUT_CONTROL_CEN,
0);
}
@@ -222,15 +232,34 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031)
struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
struct mt9p031_platform_data *pdata = mt9p031->pdata;
+ int ret;
mt9p031->clk = devm_clk_get(&client->dev, NULL);
if (IS_ERR(mt9p031->clk))
return PTR_ERR(mt9p031->clk);
- clk_set_rate(mt9p031->clk, pdata->ext_freq);
+ ret = clk_set_rate(mt9p031->clk, pdata->ext_freq);
+ if (ret < 0)
+ return ret;
+
+ /* If the external clock frequency is out of bounds for the PLL use the
+ * pixel clock divider only and disable the PLL.
+ */
+ if (pdata->ext_freq > limits.ext_clock_max) {
+ unsigned int div;
+
+ div = DIV_ROUND_UP(pdata->ext_freq, pdata->target_freq);
+ div = roundup_pow_of_two(div) / 2;
+
+ mt9p031->clk_div = max_t(unsigned int, div, 64);
+ mt9p031->use_pll = false;
+
+ return 0;
+ }
mt9p031->pll.ext_clock = pdata->ext_freq;
mt9p031->pll.pix_clock = pdata->target_freq;
+ mt9p031->use_pll = true;
return aptina_pll_calculate(&client->dev, &limits, &mt9p031->pll);
}
@@ -240,6 +269,9 @@ static int mt9p031_pll_enable(struct mt9p031 *mt9p031)
struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
int ret;
+ if (!mt9p031->use_pll)
+ return 0;
+
ret = mt9p031_write(client, MT9P031_PLL_CONTROL,
MT9P031_PLL_CONTROL_PWRON);
if (ret < 0)
@@ -265,6 +297,9 @@ static inline int mt9p031_pll_disable(struct mt9p031 *mt9p031)
{
struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+ if (!mt9p031->use_pll)
+ return 0;
+
return mt9p031_write(client, MT9P031_PLL_CONTROL,
MT9P031_PLL_CONTROL_PWROFF);
}
@@ -285,9 +320,15 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031)
if (ret < 0)
return ret;
- /* Emable clock */
- if (mt9p031->clk)
- clk_prepare_enable(mt9p031->clk);
+ /* Enable clock */
+ if (mt9p031->clk) {
+ ret = clk_prepare_enable(mt9p031->clk);
+ if (ret) {
+ regulator_bulk_disable(ARRAY_SIZE(mt9p031->regulators),
+ mt9p031->regulators);
+ return ret;
+ }
+ }
/* Now RESET_BAR must be high */
if (gpio_is_valid(mt9p031->reset)) {
@@ -943,7 +984,7 @@ mt9p031_get_pdata(struct i2c_client *client)
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
return client->dev.platform_data;
- np = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
+ np = of_graph_get_next_endpoint(client->dev.of_node, NULL);
if (!np)
return NULL;
diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c
index d41c70eaf838..422e068f5f1b 100644
--- a/drivers/media/i2c/mt9t001.c
+++ b/drivers/media/i2c/mt9t001.c
@@ -12,9 +12,11 @@
* published by the Free Software Foundation.
*/
+#include <linux/clk.h>
#include <linux/i2c.h>
-#include <linux/module.h>
#include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <linux/v4l2-mediabus.h>
@@ -55,6 +57,7 @@
#define MT9T001_OUTPUT_CONTROL_SYNC (1 << 0)
#define MT9T001_OUTPUT_CONTROL_CHIP_ENABLE (1 << 1)
#define MT9T001_OUTPUT_CONTROL_TEST_DATA (1 << 6)
+#define MT9T001_OUTPUT_CONTROL_DEF 0x0002
#define MT9T001_SHUTTER_WIDTH_HIGH 0x08
#define MT9T001_SHUTTER_WIDTH_LOW 0x09
#define MT9T001_SHUTTER_WIDTH_MIN 1
@@ -116,6 +119,12 @@ struct mt9t001 {
struct v4l2_subdev subdev;
struct media_pad pad;
+ struct clk *clk;
+ struct regulator_bulk_data regulators[2];
+
+ struct mutex power_lock; /* lock to protect power_count */
+ int power_count;
+
struct v4l2_mbus_framefmt format;
struct v4l2_rect crop;
@@ -159,6 +168,77 @@ static int mt9t001_set_output_control(struct mt9t001 *mt9t001, u16 clear,
return 0;
}
+static int mt9t001_reset(struct mt9t001 *mt9t001)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9t001->subdev);
+ int ret;
+
+ /* Reset the chip and stop data read out */
+ ret = mt9t001_write(client, MT9T001_RESET, 1);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9t001_write(client, MT9T001_RESET, 0);
+ if (ret < 0)
+ return ret;
+
+ mt9t001->output_control = MT9T001_OUTPUT_CONTROL_DEF;
+
+ return mt9t001_set_output_control(mt9t001,
+ MT9T001_OUTPUT_CONTROL_CHIP_ENABLE,
+ 0);
+}
+
+static int mt9t001_power_on(struct mt9t001 *mt9t001)
+{
+ int ret;
+
+ /* Bring up the supplies */
+ ret = regulator_bulk_enable(ARRAY_SIZE(mt9t001->regulators),
+ mt9t001->regulators);
+ if (ret < 0)
+ return ret;
+
+ /* Enable clock */
+ ret = clk_prepare_enable(mt9t001->clk);
+ if (ret < 0)
+ regulator_bulk_disable(ARRAY_SIZE(mt9t001->regulators),
+ mt9t001->regulators);
+
+ return ret;
+}
+
+static void mt9t001_power_off(struct mt9t001 *mt9t001)
+{
+ regulator_bulk_disable(ARRAY_SIZE(mt9t001->regulators),
+ mt9t001->regulators);
+
+ clk_disable_unprepare(mt9t001->clk);
+}
+
+static int __mt9t001_set_power(struct mt9t001 *mt9t001, bool on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9t001->subdev);
+ int ret;
+
+ if (!on) {
+ mt9t001_power_off(mt9t001);
+ return 0;
+ }
+
+ ret = mt9t001_power_on(mt9t001);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9t001_reset(mt9t001);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to reset the camera\n");
+ return ret;
+ }
+
+ return v4l2_ctrl_handler_setup(&mt9t001->ctrls);
+}
+
/* -----------------------------------------------------------------------------
* V4L2 subdev video operations
*/
@@ -195,6 +275,7 @@ static int mt9t001_s_stream(struct v4l2_subdev *subdev, int enable)
{
const u16 mode = MT9T001_OUTPUT_CONTROL_CHIP_ENABLE;
struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct mt9t001_platform_data *pdata = client->dev.platform_data;
struct mt9t001 *mt9t001 = to_mt9t001(subdev);
struct v4l2_mbus_framefmt *format = &mt9t001->format;
struct v4l2_rect *crop = &mt9t001->crop;
@@ -205,6 +286,14 @@ static int mt9t001_s_stream(struct v4l2_subdev *subdev, int enable)
if (!enable)
return mt9t001_set_output_control(mt9t001, mode, 0);
+ /* Configure the pixel clock polarity */
+ if (pdata->clk_pol) {
+ ret = mt9t001_write(client, MT9T001_PIXEL_CLOCK,
+ MT9T001_PIXEL_CLOCK_INVERT);
+ if (ret < 0)
+ return ret;
+ }
+
/* Configure the window size and row/column bin */
hratio = DIV_ROUND_CLOSEST(crop->width, format->width);
vratio = DIV_ROUND_CLOSEST(crop->height, format->height);
@@ -630,9 +719,67 @@ static const struct v4l2_ctrl_config mt9t001_gains[] = {
};
/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+static int mt9t001_set_power(struct v4l2_subdev *subdev, int on)
+{
+ struct mt9t001 *mt9t001 = to_mt9t001(subdev);
+ int ret = 0;
+
+ mutex_lock(&mt9t001->power_lock);
+
+ /* If the power count is modified from 0 to != 0 or from != 0 to 0,
+ * update the power state.
+ */
+ if (mt9t001->power_count == !on) {
+ ret = __mt9t001_set_power(mt9t001, !!on);
+ if (ret < 0)
+ goto out;
+ }
+
+ /* Update the power count. */
+ mt9t001->power_count += on ? 1 : -1;
+ WARN_ON(mt9t001->power_count < 0);
+
+out:
+ mutex_unlock(&mt9t001->power_lock);
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
* V4L2 subdev internal operations
*/
+static int mt9t001_registered(struct v4l2_subdev *subdev)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct mt9t001 *mt9t001 = to_mt9t001(subdev);
+ s32 data;
+ int ret;
+
+ ret = mt9t001_power_on(mt9t001);
+ if (ret < 0) {
+ dev_err(&client->dev, "MT9T001 power up failed\n");
+ return ret;
+ }
+
+ /* Read out the chip version register */
+ data = mt9t001_read(client, MT9T001_CHIP_VERSION);
+ mt9t001_power_off(mt9t001);
+
+ if (data != MT9T001_CHIP_ID) {
+ dev_err(&client->dev,
+ "MT9T001 not detected, wrong version 0x%04x\n", data);
+ return -ENODEV;
+ }
+
+ dev_info(&client->dev, "MT9T001 detected at address 0x%02x\n",
+ client->addr);
+
+ return 0;
+}
+
static int mt9t001_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
{
struct v4l2_mbus_framefmt *format;
@@ -651,9 +798,18 @@ static int mt9t001_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
format->field = V4L2_FIELD_NONE;
format->colorspace = V4L2_COLORSPACE_SRGB;
- return 0;
+ return mt9t001_set_power(subdev, 1);
+}
+
+static int mt9t001_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ return mt9t001_set_power(subdev, 0);
}
+static struct v4l2_subdev_core_ops mt9t001_subdev_core_ops = {
+ .s_power = mt9t001_set_power,
+};
+
static struct v4l2_subdev_video_ops mt9t001_subdev_video_ops = {
.s_stream = mt9t001_s_stream,
};
@@ -668,58 +824,17 @@ static struct v4l2_subdev_pad_ops mt9t001_subdev_pad_ops = {
};
static struct v4l2_subdev_ops mt9t001_subdev_ops = {
+ .core = &mt9t001_subdev_core_ops,
.video = &mt9t001_subdev_video_ops,
.pad = &mt9t001_subdev_pad_ops,
};
static struct v4l2_subdev_internal_ops mt9t001_subdev_internal_ops = {
+ .registered = mt9t001_registered,
.open = mt9t001_open,
+ .close = mt9t001_close,
};
-static int mt9t001_video_probe(struct i2c_client *client)
-{
- struct mt9t001_platform_data *pdata = client->dev.platform_data;
- s32 data;
- int ret;
-
- dev_info(&client->dev, "Probing MT9T001 at address 0x%02x\n",
- client->addr);
-
- /* Reset the chip and stop data read out */
- ret = mt9t001_write(client, MT9T001_RESET, 1);
- if (ret < 0)
- return ret;
-
- ret = mt9t001_write(client, MT9T001_RESET, 0);
- if (ret < 0)
- return ret;
-
- ret = mt9t001_write(client, MT9T001_OUTPUT_CONTROL, 0);
- if (ret < 0)
- return ret;
-
- /* Configure the pixel clock polarity */
- if (pdata->clk_pol) {
- ret = mt9t001_write(client, MT9T001_PIXEL_CLOCK,
- MT9T001_PIXEL_CLOCK_INVERT);
- if (ret < 0)
- return ret;
- }
-
- /* Read and check the sensor version */
- data = mt9t001_read(client, MT9T001_CHIP_VERSION);
- if (data != MT9T001_CHIP_ID) {
- dev_err(&client->dev, "MT9T001 not detected, wrong version "
- "0x%04x\n", data);
- return -ENODEV;
- }
-
- dev_info(&client->dev, "MT9T001 detected at address 0x%02x\n",
- client->addr);
-
- return ret;
-}
-
static int mt9t001_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
@@ -740,14 +855,28 @@ static int mt9t001_probe(struct i2c_client *client,
return -EIO;
}
- ret = mt9t001_video_probe(client);
- if (ret < 0)
- return ret;
-
mt9t001 = devm_kzalloc(&client->dev, sizeof(*mt9t001), GFP_KERNEL);
if (!mt9t001)
return -ENOMEM;
+ mutex_init(&mt9t001->power_lock);
+ mt9t001->output_control = MT9T001_OUTPUT_CONTROL_DEF;
+
+ mt9t001->regulators[0].supply = "vdd";
+ mt9t001->regulators[1].supply = "vaa";
+
+ ret = devm_regulator_bulk_get(&client->dev, 2, mt9t001->regulators);
+ if (ret < 0) {
+ dev_err(&client->dev, "Unable to get regulators\n");
+ return ret;
+ }
+
+ mt9t001->clk = devm_clk_get(&client->dev, NULL);
+ if (IS_ERR(mt9t001->clk)) {
+ dev_err(&client->dev, "Unable to get clock\n");
+ return PTR_ERR(mt9t001->clk);
+ }
+
v4l2_ctrl_handler_init(&mt9t001->ctrls, ARRAY_SIZE(mt9t001_ctrls) +
ARRAY_SIZE(mt9t001_gains) + 4);
diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c
index f74698cf14c9..47e475319a24 100644
--- a/drivers/media/i2c/mt9v011.c
+++ b/drivers/media/i2c/mt9v011.c
@@ -1,7 +1,7 @@
/*
* mt9v011 -Micron 1/4-Inch VGA Digital Image Sensor
*
- * Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.com)
+ * Copyright (c) 2009 Mauro Carvalho Chehab
* This code is placed under the terms of the GNU General Public License v2
*/
@@ -16,7 +16,7 @@
#include <media/mt9v011.h>
MODULE_DESCRIPTION("Micron mt9v011 sensor driver");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_LICENSE("GPL");
static int debug;
diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c
index 36c504b78f2c..40172b8d8ea2 100644
--- a/drivers/media/i2c/mt9v032.c
+++ b/drivers/media/i2c/mt9v032.c
@@ -317,8 +317,14 @@ static int mt9v032_power_on(struct mt9v032 *mt9v032)
struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
int ret;
- clk_set_rate(mt9v032->clk, mt9v032->sysclk);
- clk_prepare_enable(mt9v032->clk);
+ ret = clk_set_rate(mt9v032->clk, mt9v032->sysclk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_prepare_enable(mt9v032->clk);
+ if (ret)
+ return ret;
+
udelay(1);
/* Reset the chip and stop data read out */
diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
index 77e10e0fd8d6..2d768ef67cc5 100644
--- a/drivers/media/i2c/s5k5baf.c
+++ b/drivers/media/i2c/s5k5baf.c
@@ -21,6 +21,7 @@
#include <linux/media.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
+#include <linux/of_graph.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -1855,7 +1856,7 @@ static int s5k5baf_parse_device_node(struct s5k5baf *state, struct device *dev)
if (ret < 0)
return ret;
- node_ep = v4l2_of_get_next_endpoint(node, NULL);
+ node_ep = of_graph_get_next_endpoint(node, NULL);
if (!node_ep) {
dev_err(dev, "no endpoint defined at node %s\n",
node->full_name);
diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c
index ae9432637fcb..118f8ee88465 100644
--- a/drivers/media/i2c/sr030pc30.c
+++ b/drivers/media/i2c/sr030pc30.c
@@ -8,7 +8,7 @@
* and HeungJun Kim <riverful.kim@samsung.com>.
*
* Based on mt9v011 Micron Digital Image Sensor driver
- * Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.com)
+ * Copyright (c) 2009 Mauro Carvalho Chehab
*
* 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/media/i2c/ths8200.c b/drivers/media/i2c/ths8200.c
index 04139eec8c4e..f72561e79739 100644
--- a/drivers/media/i2c/ths8200.c
+++ b/drivers/media/i2c/ths8200.c
@@ -217,8 +217,8 @@ static void ths8200_core_init(struct v4l2_subdev *sd)
/* Disable embedded syncs on the output by setting
* the amplitude to zero for all channels.
*/
- ths8200_write(sd, THS8200_DTG1_Y_SYNC_MSB, 0x2a);
- ths8200_write(sd, THS8200_DTG1_CBCR_SYNC_MSB, 0x2a);
+ ths8200_write(sd, THS8200_DTG1_Y_SYNC_MSB, 0x00);
+ ths8200_write(sd, THS8200_DTG1_CBCR_SYNC_MSB, 0x00);
}
static void ths8200_setup(struct v4l2_subdev *sd, struct v4l2_bt_timings *bt)
@@ -318,15 +318,15 @@ static void ths8200_setup(struct v4l2_subdev *sd, struct v4l2_bt_timings *bt)
(htotal(bt) >> 8) & 0x1f);
ths8200_write(sd, THS8200_DTG2_HLENGTH_HDLY_LSB, htotal(bt));
- /* v sync width transmitted */
- ths8200_write(sd, THS8200_DTG2_VLENGTH1_LSB, (bt->vsync) & 0xff);
+ /* v sync width transmitted (must add 1 to get correct output) */
+ ths8200_write(sd, THS8200_DTG2_VLENGTH1_LSB, (bt->vsync + 1) & 0xff);
ths8200_write_and_or(sd, THS8200_DTG2_VLENGTH1_MSB_VDLY1_MSB, 0x3f,
- ((bt->vsync) >> 2) & 0xc0);
+ ((bt->vsync + 1) >> 2) & 0xc0);
- /* The pixel value v sync is asserted on */
+ /* The pixel value v sync is asserted on (must add 1 to get correct output) */
ths8200_write_and_or(sd, THS8200_DTG2_VLENGTH1_MSB_VDLY1_MSB, 0xf8,
- (vtotal(bt)>>8) & 0x7);
- ths8200_write(sd, THS8200_DTG2_VDLY1_LSB, vtotal(bt));
+ ((vtotal(bt) + 1) >> 8) & 0x7);
+ ths8200_write(sd, THS8200_DTG2_VDLY1_LSB, vtotal(bt) + 1);
/* For progressive video vlength2 must be set to all 0 and vdly2 must
* be set to all 1.
@@ -336,11 +336,11 @@ static void ths8200_setup(struct v4l2_subdev *sd, struct v4l2_bt_timings *bt)
ths8200_write(sd, THS8200_DTG2_VDLY2_LSB, 0xff);
/* Internal delay factors to synchronize the sync pulses and the data */
- /* Experimental values delays (hor 4, ver 1) */
- ths8200_write(sd, THS8200_DTG2_HS_IN_DLY_MSB, (htotal(bt)>>8) & 0x1f);
- ths8200_write(sd, THS8200_DTG2_HS_IN_DLY_LSB, (htotal(bt) - 4) & 0xff);
+ /* Experimental values delays (hor 0, ver 0) */
+ ths8200_write(sd, THS8200_DTG2_HS_IN_DLY_MSB, 0);
+ ths8200_write(sd, THS8200_DTG2_HS_IN_DLY_LSB, 0);
ths8200_write(sd, THS8200_DTG2_VS_IN_DLY_MSB, 0);
- ths8200_write(sd, THS8200_DTG2_VS_IN_DLY_LSB, 1);
+ ths8200_write(sd, THS8200_DTG2_VS_IN_DLY_LSB, 0);
/* Polarity of received and transmitted sync signals */
if (bt->polarities & V4L2_DV_HSYNC_POS_POL) {
@@ -356,7 +356,7 @@ static void ths8200_setup(struct v4l2_subdev *sd, struct v4l2_bt_timings *bt)
/* Timing of video input bus is derived from HS, VS, and FID dedicated
* inputs
*/
- ths8200_write(sd, THS8200_DTG2_CNTL, 0x47 | polarity);
+ ths8200_write(sd, THS8200_DTG2_CNTL, 0x44 | polarity);
/* leave reset */
ths8200_s_stream(sd, true);
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
index 83d85df4853a..ca001178c5bf 100644
--- a/drivers/media/i2c/tvp514x.c
+++ b/drivers/media/i2c/tvp514x.c
@@ -36,6 +36,7 @@
#include <linux/module.h>
#include <linux/v4l2-mediabus.h>
#include <linux/of.h>
+#include <linux/of_graph.h>
#include <media/v4l2-async.h>
#include <media/v4l2-device.h>
@@ -1068,7 +1069,7 @@ tvp514x_get_pdata(struct i2c_client *client)
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
return client->dev.platform_data;
- endpoint = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
+ endpoint = of_graph_get_next_endpoint(client->dev.of_node, NULL);
if (!endpoint)
return NULL;
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 542d2528b3f9..4fd3688e1164 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -16,9 +16,9 @@
#include "tvp5150_reg.h"
-#define TVP5150_H_MAX 720
-#define TVP5150_V_MAX_525_60 480
-#define TVP5150_V_MAX_OTHERS 576
+#define TVP5150_H_MAX 720U
+#define TVP5150_V_MAX_525_60 480U
+#define TVP5150_V_MAX_OTHERS 576U
#define TVP5150_MAX_CROP_LEFT 511
#define TVP5150_MAX_CROP_TOP 127
#define TVP5150_CROP_SHIFT 2
@@ -29,7 +29,7 @@ MODULE_LICENSE("GPL");
static int debug;
-module_param(debug, int, 0);
+module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-2)");
struct tvp5150 {
diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c
index 912e1cccdd1c..c4e1e2cb3094 100644
--- a/drivers/media/i2c/tvp7002.c
+++ b/drivers/media/i2c/tvp7002.c
@@ -30,6 +30,7 @@
#include <linux/videodev2.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_graph.h>
#include <linux/v4l2-dv-timings.h>
#include <media/tvp7002.h>
#include <media/v4l2-async.h>
@@ -957,7 +958,7 @@ tvp7002_get_pdata(struct i2c_client *client)
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
return client->dev.platform_data;
- endpoint = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
+ endpoint = of_graph_get_next_endpoint(client->dev.of_node, NULL);
if (!endpoint)
return NULL;
diff --git a/drivers/media/parport/bw-qcam.c b/drivers/media/parport/bw-qcam.c
index d12bd33f39cb..8a0e84c7d495 100644
--- a/drivers/media/parport/bw-qcam.c
+++ b/drivers/media/parport/bw-qcam.c
@@ -667,13 +667,16 @@ static void buffer_queue(struct vb2_buffer *vb)
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
}
-static int buffer_finish(struct vb2_buffer *vb)
+static void buffer_finish(struct vb2_buffer *vb)
{
struct qcam *qcam = vb2_get_drv_priv(vb->vb2_queue);
void *vbuf = vb2_plane_vaddr(vb, 0);
int size = vb->vb2_queue->plane_sizes[0];
int len;
+ if (!vb2_is_streaming(vb->vb2_queue))
+ return;
+
mutex_lock(&qcam->lock);
parport_claim_or_block(qcam->pdev);
@@ -691,7 +694,6 @@ static int buffer_finish(struct vb2_buffer *vb)
if (len != size)
vb->state = VB2_BUF_STATE_ERROR;
vb2_set_plane_payload(vb, 0, len);
- return 0;
}
static struct vb2_ops qcam_video_qops = {
@@ -965,7 +967,7 @@ static struct qcam *qcam_init(struct parport *port)
q->drv_priv = qcam;
q->ops = &qcam_video_qops;
q->mem_ops = &vb2_vmalloc_memops;
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
err = vb2_queue_init(q);
if (err < 0) {
v4l2_err(v4l2_dev, "couldn't init vb2_queue for %s.\n", port->name);
diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c
index 6662b495b22c..d06963b3dcf3 100644
--- a/drivers/media/pci/bt8xx/bttv-cards.c
+++ b/drivers/media/pci/bt8xx/bttv-cards.c
@@ -2855,7 +2855,22 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
},
-
+ [BTTV_BOARD_KWORLD_VSTREAM_XPERT] = {
+ /* Pojar George <geoubuntu@gmail.com> */
+ .name = "Kworld V-Stream Xpert TV PVR878",
+ .video_inputs = 3,
+ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x001c0007,
+ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 1, 2, 2 },
+ .gpiomute = 3,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TENA_9533_DI,
+ .tuner_addr = ADDR_UNSET,
+ .has_remote = 1,
+ .has_radio = 1,
+ },
};
static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c
index f36821367d8d..5930bce16658 100644
--- a/drivers/media/pci/bt8xx/bttv-input.c
+++ b/drivers/media/pci/bt8xx/bttv-input.c
@@ -483,6 +483,7 @@ int bttv_input_init(struct bttv *btv)
case BTTV_BOARD_ASKEY_CPH03X:
case BTTV_BOARD_CONCEPTRONIC_CTVFMI2:
case BTTV_BOARD_CONTVFMI:
+ case BTTV_BOARD_KWORLD_VSTREAM_XPERT:
ir_codes = RC_MAP_PIXELVIEW;
ir->mask_keycode = 0x001F00;
ir->mask_keyup = 0x006000;
diff --git a/drivers/media/pci/bt8xx/bttv.h b/drivers/media/pci/bt8xx/bttv.h
index df578efe03c9..bb5da349a46e 100644
--- a/drivers/media/pci/bt8xx/bttv.h
+++ b/drivers/media/pci/bt8xx/bttv.h
@@ -188,6 +188,7 @@
#define BTTV_BOARD_ADLINK_MPG24 0xa2
#define BTTV_BOARD_BT848_CAP_14 0xa3
#define BTTV_BOARD_CYBERVISION_CV06 0xa4
+#define BTTV_BOARD_KWORLD_VSTREAM_XPERT 0xa5
/* more card-specific defines */
#define PT2254_L_CHANNEL 0x10
diff --git a/drivers/media/pci/cx18/cx18-alsa-main.c b/drivers/media/pci/cx18/cx18-alsa-main.c
index b2c8c3439fea..ea272bcb38df 100644
--- a/drivers/media/pci/cx18/cx18-alsa-main.c
+++ b/drivers/media/pci/cx18/cx18-alsa-main.c
@@ -145,11 +145,12 @@ static int snd_cx18_init(struct v4l2_device *v4l2_dev)
/* This is a no-op for us. We'll use the cx->instance */
/* (2) Create a card instance */
- ret = snd_card_create(SNDRV_DEFAULT_IDX1, /* use first available id */
- SNDRV_DEFAULT_STR1, /* xid from end of shortname*/
- THIS_MODULE, 0, &sc);
+ ret = snd_card_new(&cx->pci_dev->dev,
+ SNDRV_DEFAULT_IDX1, /* use first available id */
+ SNDRV_DEFAULT_STR1, /* xid from end of shortname*/
+ THIS_MODULE, 0, &sc);
if (ret) {
- CX18_ALSA_ERR("%s: snd_card_create() failed with err %d\n",
+ CX18_ALSA_ERR("%s: snd_card_new() failed with err %d\n",
__func__, ret);
goto err_exit;
}
diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c
index c6c9bd58f8be..554798dcedd0 100644
--- a/drivers/media/pci/cx23885/cx23885-alsa.c
+++ b/drivers/media/pci/cx23885/cx23885-alsa.c
@@ -489,7 +489,8 @@ struct cx23885_audio_dev *cx23885_audio_register(struct cx23885_dev *dev)
return NULL;
}
- err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ err = snd_card_new(&dev->pci->dev,
+ SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
THIS_MODULE, sizeof(struct cx23885_audio_dev), &card);
if (err < 0)
goto error;
@@ -500,8 +501,6 @@ struct cx23885_audio_dev *cx23885_audio_register(struct cx23885_dev *dev)
chip->card = card;
spin_lock_init(&chip->lock);
- snd_card_set_dev(card, &dev->pci->dev);
-
err = snd_cx23885_pcm(chip, 0, "CX23885 Digital");
if (err < 0)
goto error;
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
index 05492053b473..4be01b3bd4f5 100644
--- a/drivers/media/pci/cx23885/cx23885-dvb.c
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -473,6 +473,7 @@ static struct ds3000_config tevii_ds3000_config = {
static struct ts2020_config tevii_ts2020_config = {
.tuner_address = 0x60,
.clk_out_div = 1,
+ .frequency_div = 1146000,
};
static struct cx24116_config dvbworld_cx24116_config = {
diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c
index 8a49e7c9eddd..097d0a0b5f57 100644
--- a/drivers/media/pci/cx23885/cx23885-input.c
+++ b/drivers/media/pci/cx23885/cx23885-input.c
@@ -346,7 +346,7 @@ int cx23885_input_init(struct cx23885_dev *dev)
}
rc->dev.parent = &dev->pci->dev;
rc->driver_type = driver_type;
- rc->allowed_protos = allowed_protos;
+ rc_set_allowed_protocols(rc, allowed_protos);
rc->priv = kernel_ir;
rc->open = cx23885_input_ir_open;
rc->close = cx23885_input_ir_close;
diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c
index b1e08c3e55cd..2dd5bcaa7e53 100644
--- a/drivers/media/pci/cx25821/cx25821-alsa.c
+++ b/drivers/media/pci/cx25821/cx25821-alsa.c
@@ -645,8 +645,9 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
return -ENOENT;
}
- err = snd_card_create(index[devno], id[devno], THIS_MODULE,
- sizeof(struct cx25821_audio_dev), &card);
+ err = snd_card_new(&dev->pci->dev, index[devno], id[devno],
+ THIS_MODULE,
+ sizeof(struct cx25821_audio_dev), &card);
if (err < 0) {
pr_info("DEBUG ERROR: cannot create snd_card_new in %s\n",
__func__);
@@ -682,8 +683,6 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
goto error;
}
- snd_card_set_dev(card, &chip->pci->dev);
-
strcpy(card->shortname, "cx25821");
sprintf(card->longname, "%s at 0x%lx irq %d", chip->dev->name,
chip->iobase, chip->irq);
diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c
index d014206e7176..a72579a9f67f 100644
--- a/drivers/media/pci/cx88/cx88-alsa.c
+++ b/drivers/media/pci/cx88/cx88-alsa.c
@@ -852,8 +852,6 @@ static int snd_cx88_create(struct snd_card *card, struct pci_dev *pci,
chip->irq = pci->irq;
synchronize_irq(chip->irq);
- snd_card_set_dev(card, &pci->dev);
-
*rchip = chip;
*core_ptr = core;
@@ -876,8 +874,8 @@ static int cx88_audio_initdev(struct pci_dev *pci,
return (-ENOENT);
}
- err = snd_card_create(index[devno], id[devno], THIS_MODULE,
- sizeof(snd_cx88_card_t), &card);
+ err = snd_card_new(&pci->dev, index[devno], id[devno], THIS_MODULE,
+ sizeof(snd_cx88_card_t), &card);
if (err < 0)
return err;
diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
index f29e18c72f44..f991696a6c59 100644
--- a/drivers/media/pci/cx88/cx88-input.c
+++ b/drivers/media/pci/cx88/cx88-input.c
@@ -469,7 +469,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
dev->timeout = 10 * 1000 * 1000; /* 10 ms */
} else {
dev->driver_type = RC_DRIVER_SCANCODE;
- dev->allowed_protos = rc_type;
+ rc_set_allowed_protocols(dev, rc_type);
}
ir->core = core;
diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index 9375f30d9a81..fb52bda8d45f 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -876,10 +876,8 @@ static int dvb_input_attach(struct ddb_input *input)
return -ENODEV;
if (tuner_attach_tda18271(input) < 0)
return -ENODEV;
- if (input->fe) {
- if (dvb_register_frontend(adap, input->fe) < 0)
- return -ENODEV;
- }
+ if (dvb_register_frontend(adap, input->fe) < 0)
+ return -ENODEV;
if (input->fe2) {
if (dvb_register_frontend(adap, input->fe2) < 0)
return -ENODEV;
diff --git a/drivers/media/pci/ivtv/ivtv-alsa-main.c b/drivers/media/pci/ivtv/ivtv-alsa-main.c
index e970cface70e..39b52929755a 100644
--- a/drivers/media/pci/ivtv/ivtv-alsa-main.c
+++ b/drivers/media/pci/ivtv/ivtv-alsa-main.c
@@ -145,11 +145,12 @@ static int snd_ivtv_init(struct v4l2_device *v4l2_dev)
/* This is a no-op for us. We'll use the itv->instance */
/* (2) Create a card instance */
- ret = snd_card_create(SNDRV_DEFAULT_IDX1, /* use first available id */
- SNDRV_DEFAULT_STR1, /* xid from end of shortname*/
- THIS_MODULE, 0, &sc);
+ ret = snd_card_new(&itv->pdev->dev,
+ SNDRV_DEFAULT_IDX1, /* use first available id */
+ SNDRV_DEFAULT_STR1, /* xid from end of shortname*/
+ THIS_MODULE, 0, &sc);
if (ret) {
- IVTV_ALSA_ERR("%s: snd_card_create() failed with err %d\n",
+ IVTV_ALSA_ERR("%s: snd_card_new() failed with err %d\n",
__func__, ret);
goto err_exit;
}
diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c
index dd67c8a400cc..e04a4d5d6672 100644
--- a/drivers/media/pci/saa7134/saa7134-alsa.c
+++ b/drivers/media/pci/saa7134/saa7134-alsa.c
@@ -1072,8 +1072,8 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
if (!enable[devnum])
return -ENODEV;
- err = snd_card_create(index[devnum], id[devnum], THIS_MODULE,
- sizeof(snd_card_saa7134_t), &card);
+ err = snd_card_new(&dev->pci->dev, index[devnum], id[devnum],
+ THIS_MODULE, sizeof(snd_card_saa7134_t), &card);
if (err < 0)
return err;
@@ -1115,8 +1115,6 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
if ((err = snd_card_saa7134_pcm(chip, 0)) < 0)
goto __nodev;
- snd_card_set_dev(card, &chip->pci->dev);
-
/* End of "creation" */
strcpy(card->shortname, "SAA7134");
diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c
index c9b2350e92c8..6e4bdb90aa92 100644
--- a/drivers/media/pci/saa7134/saa7134-cards.c
+++ b/drivers/media/pci/saa7134/saa7134-cards.c
@@ -8045,8 +8045,8 @@ int saa7134_board_init2(struct saa7134_dev *dev)
break;
} /* switch() */
- /* initialize tuner */
- if (TUNER_ABSENT != dev->tuner_type) {
+ /* initialize tuner (don't do this when resuming) */
+ if (!dev->insuspend && TUNER_ABSENT != dev->tuner_type) {
int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
/* Note: radio tuner address is always filled in,
diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c
index e5cfb6cfa18d..bb11443ed63e 100644
--- a/drivers/media/pci/sta2x11/sta2x11_vip.c
+++ b/drivers/media/pci/sta2x11/sta2x11_vip.c
@@ -327,7 +327,7 @@ static void buffer_queue(struct vb2_buffer *vb)
}
spin_unlock(&vip->lock);
}
-static int buffer_finish(struct vb2_buffer *vb)
+static void buffer_finish(struct vb2_buffer *vb)
{
struct sta2x11_vip *vip = vb2_get_drv_priv(vb->vb2_queue);
struct vip_buffer *vip_buf = to_vip_buffer(vb);
@@ -337,9 +337,8 @@ static int buffer_finish(struct vb2_buffer *vb)
list_del_init(&vip_buf->list);
spin_unlock(&vip->lock);
- vip_active_buf_next(vip);
-
- return 0;
+ if (vb2_is_streaming(vb->vb2_queue))
+ vip_active_buf_next(vip);
}
static int start_streaming(struct vb2_queue *vq, unsigned int count)
diff --git a/drivers/media/pci/ttpci/av7110_hw.c b/drivers/media/pci/ttpci/av7110_hw.c
index 6299d5dadb82..300bd3c94738 100644
--- a/drivers/media/pci/ttpci/av7110_hw.c
+++ b/drivers/media/pci/ttpci/av7110_hw.c
@@ -501,7 +501,7 @@ int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
// dprintk(4, "%p\n", av7110);
- if (2 + num > sizeof(buf)) {
+ if (2 + num > ARRAY_SIZE(buf)) {
printk(KERN_WARNING
"%s: %s len=%d is too big!\n",
KBUILD_MODNAME, __func__, num);
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index b2a4403940c5..c137abfa0c54 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -36,7 +36,7 @@ source "drivers/media/platform/blackfin/Kconfig"
config VIDEO_SH_VOU
tristate "SuperH VOU video output driver"
depends on MEDIA_CAMERA_SUPPORT
- depends on VIDEO_DEV && I2C
+ depends on VIDEO_DEV && I2C && HAS_DMA
depends on ARCH_SHMOBILE || COMPILE_TEST
select VIDEOBUF_DMA_CONTIG
help
diff --git a/drivers/media/platform/arv.c b/drivers/media/platform/arv.c
index e346d32d08ce..e9410e41ae0c 100644
--- a/drivers/media/platform/arv.c
+++ b/drivers/media/platform/arv.c
@@ -109,7 +109,7 @@ extern struct cpuinfo_m32r boot_cpu_data;
struct ar {
struct v4l2_device v4l2_dev;
struct video_device vdev;
- unsigned int start_capture; /* duaring capture in INT. mode. */
+ int start_capture; /* duaring capture in INT. mode. */
#if USE_INT
unsigned char *line_buff; /* DMA line buffer */
#endif
@@ -307,11 +307,11 @@ static ssize_t ar_read(struct file *file, char *buf, size_t count, loff_t *ppos)
/*
* Okay, kick AR LSI to invoke an interrupt
*/
- ar->start_capture = 0;
+ ar->start_capture = -1;
ar_outl(arvcr1 | ARVCR1_HIEN, ARVCR1);
local_irq_restore(flags);
/* .... AR interrupts .... */
- interruptible_sleep_on(&ar->wait);
+ wait_event_interruptible(ar->wait, ar->start_capture == 0);
if (signal_pending(current)) {
printk(KERN_ERR "arv: interrupted while get frame data.\n");
ret = -EINTR;
diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c
index 281916591437..200bec91182e 100644
--- a/drivers/media/platform/blackfin/bfin_capture.c
+++ b/drivers/media/platform/blackfin/bfin_capture.c
@@ -997,7 +997,7 @@ static int bcap_probe(struct platform_device *pdev)
q->buf_struct_size = sizeof(struct bcap_buffer);
q->ops = &bcap_video_qops;
q->mem_ops = &vb2_dma_contig_memops;
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
ret = vb2_queue_init(q);
if (ret)
diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c
index 61f3dbcc259f..3e5199ee5d25 100644
--- a/drivers/media/platform/coda.c
+++ b/drivers/media/platform/coda.c
@@ -2428,7 +2428,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &coda_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
- src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -2440,7 +2440,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &coda_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
- dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
return vb2_queue_init(dst_vq);
}
@@ -2829,6 +2829,9 @@ static void coda_finish_encode(struct coda_ctx *ctx)
}
dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
+ dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+ dst_buf->v4l2_buf.flags |=
+ src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c
index b02aba488826..b4f12d00be05 100644
--- a/drivers/media/platform/davinci/vpbe_display.c
+++ b/drivers/media/platform/davinci/vpbe_display.c
@@ -341,14 +341,8 @@ static int vpbe_start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct vpbe_fh *fh = vb2_get_drv_priv(vq);
struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
int ret;
- /* If buffer queue is empty, return error */
- if (list_empty(&layer->dma_queue)) {
- v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n");
- return -ENOBUFS;
- }
/* Get the next frame from the buffer queue */
layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next,
struct vpbe_disp_buffer, list);
@@ -1415,7 +1409,8 @@ static int vpbe_display_reqbufs(struct file *file, void *priv,
q->ops = &video_qops;
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct vpbe_disp_buffer);
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->min_buffers_needed = 1;
ret = vb2_queue_init(q);
if (ret) {
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
index 735ec47601a9..756da78bac23 100644
--- a/drivers/media/platform/davinci/vpif_capture.c
+++ b/drivers/media/platform/davinci/vpif_capture.c
@@ -272,13 +272,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
unsigned long flags;
int ret;
- /* If buffer queue is empty, return error */
spin_lock_irqsave(&common->irqlock, flags);
- if (list_empty(&common->dma_queue)) {
- spin_unlock_irqrestore(&common->irqlock, flags);
- vpif_dbg(1, debug, "buffer queue is empty\n");
- return -ENOBUFS;
- }
/* Get the next frame from the buffer queue */
common->cur_frm = common->next_frm = list_entry(common->dma_queue.next,
@@ -1023,7 +1017,8 @@ static int vpif_reqbufs(struct file *file, void *priv,
q->ops = &video_qops;
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct vpif_cap_buffer);
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->min_buffers_needed = 1;
ret = vb2_queue_init(q);
if (ret) {
diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c
index 9d115cdc6bdb..0ac841e35aa4 100644
--- a/drivers/media/platform/davinci/vpif_display.c
+++ b/drivers/media/platform/davinci/vpif_display.c
@@ -234,13 +234,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
unsigned long flags;
int ret;
- /* If buffer queue is empty, return error */
spin_lock_irqsave(&common->irqlock, flags);
- if (list_empty(&common->dma_queue)) {
- spin_unlock_irqrestore(&common->irqlock, flags);
- vpif_err("buffer queue is empty\n");
- return -ENOBUFS;
- }
/* Get the next frame from the buffer queue */
common->next_frm = common->cur_frm =
@@ -983,7 +977,8 @@ static int vpif_reqbufs(struct file *file, void *priv,
q->ops = &video_qops;
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct vpif_disp_buffer);
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->min_buffers_needed = 1;
ret = vb2_queue_init(q);
if (ret) {
diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c
index 810c3e13970c..d0ea94f58d6f 100644
--- a/drivers/media/platform/exynos-gsc/gsc-m2m.c
+++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c
@@ -88,8 +88,12 @@ void gsc_m2m_job_finish(struct gsc_ctx *ctx, int vb_state)
dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
if (src_vb && dst_vb) {
- src_vb->v4l2_buf.timestamp = dst_vb->v4l2_buf.timestamp;
- src_vb->v4l2_buf.timecode = dst_vb->v4l2_buf.timecode;
+ dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp;
+ dst_vb->v4l2_buf.timecode = src_vb->v4l2_buf.timecode;
+ dst_vb->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+ dst_vb->v4l2_buf.flags |=
+ src_vb->v4l2_buf.flags
+ & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
v4l2_m2m_buf_done(src_vb, vb_state);
v4l2_m2m_buf_done(dst_vb, vb_state);
@@ -590,7 +594,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->ops = &gsc_m2m_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
- src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -603,7 +607,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->ops = &gsc_m2m_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
- dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
return vb2_queue_init(dst_vq);
}
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c
index 8a712ca91d11..92ae812abce2 100644
--- a/drivers/media/platform/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/exynos4-is/fimc-capture.c
@@ -1782,7 +1782,7 @@ static int fimc_register_capture_device(struct fimc_dev *fimc,
q->ops = &fimc_capture_qops;
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct fimc_vid_buffer);
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->lock = &fimc->lock;
ret = vb2_queue_init(q);
diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c
index 13a4228952e3..9bdfa4599bc3 100644
--- a/drivers/media/platform/exynos4-is/fimc-is.c
+++ b/drivers/media/platform/exynos4-is/fimc-is.c
@@ -24,13 +24,13 @@
#include <linux/i2c.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
+#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/videodev2.h>
-#include <media/v4l2-of.h>
#include <media/videobuf2-dma-contig.h>
#include "media-dev.h"
@@ -167,10 +167,10 @@ static int fimc_is_parse_sensor_config(struct fimc_is_sensor *sensor,
u32 tmp = 0;
int ret;
- np = v4l2_of_get_next_endpoint(np, NULL);
+ np = of_graph_get_next_endpoint(np, NULL);
if (!np)
return -ENXIO;
- np = v4l2_of_get_remote_port(np);
+ np = of_graph_get_remote_port(np);
if (!np)
return -ENXIO;
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c
index 779ec3cd259d..3ad660b55b6b 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite.c
@@ -1313,7 +1313,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct flite_buffer);
q->drv_priv = fimc;
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->lock = &fimc->lock;
ret = vb2_queue_init(q);
diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c
index 9da95bd14820..36971d915b53 100644
--- a/drivers/media/platform/exynos4-is/fimc-m2m.c
+++ b/drivers/media/platform/exynos4-is/fimc-m2m.c
@@ -134,6 +134,9 @@ static void fimc_device_run(void *priv)
goto dma_unlock;
dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp;
+ dst_vb->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+ dst_vb->v4l2_buf.flags |=
+ src_vb->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
/* Reconfigure hardware if the context has changed. */
if (fimc->m2m.ctx != ctx) {
@@ -557,7 +560,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->ops = &fimc_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
- src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
src_vq->lock = &ctx->fimc_dev->lock;
ret = vb2_queue_init(src_vq);
@@ -570,7 +573,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->ops = &fimc_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
- dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
dst_vq->lock = &ctx->fimc_dev->lock;
return vb2_queue_init(dst_vq);
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index c1bce170df6f..04d6ecdd314c 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -20,6 +20,7 @@
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_device.h>
+#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/types.h>
@@ -468,12 +469,12 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
return 0;
v4l2_of_parse_endpoint(ep, &endpoint);
- if (WARN_ON(endpoint.port == 0) || index >= FIMC_MAX_SENSORS)
+ if (WARN_ON(endpoint.base.port == 0) || index >= FIMC_MAX_SENSORS)
return -EINVAL;
- pd->mux_id = (endpoint.port - 1) & 0x1;
+ pd->mux_id = (endpoint.base.port - 1) & 0x1;
- rem = v4l2_of_get_remote_port_parent(ep);
+ rem = of_graph_get_remote_port_parent(ep);
of_node_put(ep);
if (rem == NULL) {
v4l2_info(&fmd->v4l2_dev, "Remote device at %s not found\n",
@@ -493,13 +494,13 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
return -EINVAL;
}
- if (fimc_input_is_parallel(endpoint.port)) {
+ if (fimc_input_is_parallel(endpoint.base.port)) {
if (endpoint.bus_type == V4L2_MBUS_PARALLEL)
pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_601;
else
pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_656;
pd->flags = endpoint.bus.parallel.flags;
- } else if (fimc_input_is_mipi_csi(endpoint.port)) {
+ } else if (fimc_input_is_mipi_csi(endpoint.base.port)) {
/*
* MIPI CSI-2: only input mux selection and
* the sensor's clock frequency is needed.
@@ -507,7 +508,7 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
pd->sensor_bus_type = FIMC_BUS_TYPE_MIPI_CSI2;
} else {
v4l2_err(&fmd->v4l2_dev, "Wrong port id (%u) at node %s\n",
- endpoint.port, rem->full_name);
+ endpoint.base.port, rem->full_name);
}
/*
* For FIMC-IS handled sensors, that are placed under i2c-isp device
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c
index f3c3591fdc5d..3678ba59725c 100644
--- a/drivers/media/platform/exynos4-is/mipi-csis.c
+++ b/drivers/media/platform/exynos4-is/mipi-csis.c
@@ -20,6 +20,7 @@
#include <linux/memory.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_graph.h>
#include <linux/phy/phy.h>
#include <linux/platform_data/mipi-csis.h>
#include <linux/platform_device.h>
@@ -762,7 +763,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev,
&state->max_num_lanes))
return -EINVAL;
- node = v4l2_of_get_next_endpoint(node, NULL);
+ node = of_graph_get_next_endpoint(node, NULL);
if (!node) {
dev_err(&pdev->dev, "No port node at %s\n",
pdev->dev.of_node->full_name);
@@ -771,7 +772,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev,
/* Get port node and validate MIPI-CSI channel id. */
v4l2_of_parse_endpoint(node, &endpoint);
- state->index = endpoint.port - FIMC_INPUT_MIPI_CSI2_0;
+ state->index = endpoint.base.port - FIMC_INPUT_MIPI_CSI2_0;
if (state->index < 0 || state->index >= CSIS_MAX_ENTITIES)
return -ENXIO;
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c
index 6bb86b581a34..c21d14fd61db 100644
--- a/drivers/media/platform/m2m-deinterlace.c
+++ b/drivers/media/platform/m2m-deinterlace.c
@@ -207,8 +207,11 @@ static void dma_callback(void *data)
src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
- src_vb->v4l2_buf.timestamp = dst_vb->v4l2_buf.timestamp;
- src_vb->v4l2_buf.timecode = dst_vb->v4l2_buf.timecode;
+ dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp;
+ dst_vb->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+ dst_vb->v4l2_buf.flags |=
+ src_vb->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+ dst_vb->v4l2_buf.timecode = src_vb->v4l2_buf.timecode;
v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
@@ -868,7 +871,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &deinterlace_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
- src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
q_data[V4L2_M2M_SRC].fmt = &formats[0];
q_data[V4L2_M2M_SRC].width = 640;
q_data[V4L2_M2M_SRC].height = 480;
@@ -885,7 +888,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &deinterlace_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
- dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
q_data[V4L2_M2M_DST].fmt = &formats[0];
q_data[V4L2_M2M_DST].width = 640;
q_data[V4L2_M2M_DST].height = 480;
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c
index 32fab30a9105..8b34c485be79 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.c
+++ b/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -1238,7 +1238,7 @@ static int mcam_vb_sg_buf_prepare(struct vb2_buffer *vb)
return 0;
}
-static int mcam_vb_sg_buf_finish(struct vb2_buffer *vb)
+static void mcam_vb_sg_buf_finish(struct vb2_buffer *vb)
{
struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
struct sg_table *sg_table = vb2_dma_sg_plane_desc(vb, 0);
@@ -1246,7 +1246,6 @@ static int mcam_vb_sg_buf_finish(struct vb2_buffer *vb)
if (sg_table)
dma_unmap_sg(cam->dev, sg_table->sgl,
sg_table->nents, DMA_FROM_DEVICE);
- return 0;
}
static void mcam_vb_sg_buf_cleanup(struct vb2_buffer *vb)
diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c
index 08e24379b794..4f3096b17066 100644
--- a/drivers/media/platform/mem2mem_testdev.c
+++ b/drivers/media/platform/mem2mem_testdev.c
@@ -60,9 +60,7 @@ MODULE_PARM_DESC(debug, "activates debug info");
#define MEM2MEM_VID_MEM_LIMIT (16 * 1024 * 1024)
/* Default transaction time in msec */
-#define MEM2MEM_DEF_TRANSTIME 1000
-/* Default number of buffers per transaction */
-#define MEM2MEM_DEF_TRANSLEN 1
+#define MEM2MEM_DEF_TRANSTIME 40
#define MEM2MEM_COLOR_STEP (0xff >> 4)
#define MEM2MEM_NUM_TILES 8
@@ -114,6 +112,7 @@ struct m2mtest_q_data {
unsigned int width;
unsigned int height;
unsigned int sizeimage;
+ unsigned int sequence;
struct m2mtest_fmt *fmt;
};
@@ -236,9 +235,21 @@ static int device_process(struct m2mtest_ctx *ctx,
bytes_left = bytesperline - tile_w * MEM2MEM_NUM_TILES;
w = 0;
+ out_vb->v4l2_buf.sequence = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE)->sequence++;
+ in_vb->v4l2_buf.sequence = q_data->sequence++;
memcpy(&out_vb->v4l2_buf.timestamp,
&in_vb->v4l2_buf.timestamp,
sizeof(struct timeval));
+ if (in_vb->v4l2_buf.flags & V4L2_BUF_FLAG_TIMECODE)
+ memcpy(&out_vb->v4l2_buf.timecode, &in_vb->v4l2_buf.timecode,
+ sizeof(struct v4l2_timecode));
+ out_vb->v4l2_buf.field = in_vb->v4l2_buf.field;
+ out_vb->v4l2_buf.flags = in_vb->v4l2_buf.flags &
+ (V4L2_BUF_FLAG_TIMECODE |
+ V4L2_BUF_FLAG_KEYFRAME |
+ V4L2_BUF_FLAG_PFRAME |
+ V4L2_BUF_FLAG_BFRAME |
+ V4L2_BUF_FLAG_TSTAMP_SRC_MASK);
switch (ctx->mode) {
case MEM2MEM_HFLIP | MEM2MEM_VFLIP:
@@ -505,19 +516,8 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_try_fmt(struct v4l2_format *f, struct m2mtest_fmt *fmt)
{
- enum v4l2_field field;
-
- field = f->fmt.pix.field;
-
- if (field == V4L2_FIELD_ANY)
- field = V4L2_FIELD_NONE;
- else if (V4L2_FIELD_NONE != field)
- return -EINVAL;
-
/* V4L2 specification suggests the driver corrects the format struct
* if any of the dimensions is unsupported */
- f->fmt.pix.field = field;
-
if (f->fmt.pix.height < MIN_H)
f->fmt.pix.height = MIN_H;
else if (f->fmt.pix.height > MAX_H)
@@ -531,6 +531,8 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct m2mtest_fmt *fmt)
f->fmt.pix.width &= ~DIM_ALIGN_MASK;
f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ f->fmt.pix.priv = 0;
return 0;
}
@@ -542,7 +544,11 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct m2mtest_ctx *ctx = file2ctx(file);
fmt = find_format(f);
- if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
+ if (!fmt) {
+ f->fmt.pix.pixelformat = formats[0].fourcc;
+ fmt = find_format(f);
+ }
+ if (!(fmt->types & MEM2MEM_CAPTURE)) {
v4l2_err(&ctx->dev->v4l2_dev,
"Fourcc format (0x%08x) invalid.\n",
f->fmt.pix.pixelformat);
@@ -560,7 +566,11 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
struct m2mtest_ctx *ctx = file2ctx(file);
fmt = find_format(f);
- if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
+ if (!fmt) {
+ f->fmt.pix.pixelformat = formats[0].fourcc;
+ fmt = find_format(f);
+ }
+ if (!(fmt->types & MEM2MEM_OUTPUT)) {
v4l2_err(&ctx->dev->v4l2_dev,
"Fourcc format (0x%08x) invalid.\n",
f->fmt.pix.pixelformat);
@@ -740,6 +750,15 @@ static int m2mtest_buf_prepare(struct vb2_buffer *vb)
dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
q_data = get_q_data(ctx, vb->vb2_queue->type);
+ if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
+ if (vb->v4l2_buf.field == V4L2_FIELD_ANY)
+ vb->v4l2_buf.field = V4L2_FIELD_NONE;
+ if (vb->v4l2_buf.field != V4L2_FIELD_NONE) {
+ dprintk(ctx->dev, "%s field isn't supported\n",
+ __func__);
+ return -EINVAL;
+ }
+ }
if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
dprintk(ctx->dev, "%s data will not fit into plane (%lu < %lu)\n",
@@ -755,13 +774,45 @@ static int m2mtest_buf_prepare(struct vb2_buffer *vb)
static void m2mtest_buf_queue(struct vb2_buffer *vb)
{
struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
}
+static int m2mtest_start_streaming(struct vb2_queue *q, unsigned count)
+{
+ struct m2mtest_ctx *ctx = vb2_get_drv_priv(q);
+ struct m2mtest_q_data *q_data = get_q_data(ctx, q->type);
+
+ q_data->sequence = 0;
+ return 0;
+}
+
+static int m2mtest_stop_streaming(struct vb2_queue *q)
+{
+ struct m2mtest_ctx *ctx = vb2_get_drv_priv(q);
+ struct vb2_buffer *vb;
+ unsigned long flags;
+
+ for (;;) {
+ if (V4L2_TYPE_IS_OUTPUT(q->type))
+ vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ else
+ vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+ if (vb == NULL)
+ return 0;
+ spin_lock_irqsave(&ctx->dev->irqlock, flags);
+ v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);
+ spin_unlock_irqrestore(&ctx->dev->irqlock, flags);
+ }
+ return 0;
+}
+
static struct vb2_ops m2mtest_qops = {
.queue_setup = m2mtest_queue_setup,
.buf_prepare = m2mtest_buf_prepare,
.buf_queue = m2mtest_buf_queue,
+ .start_streaming = m2mtest_start_streaming,
+ .stop_streaming = m2mtest_stop_streaming,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
};
@@ -772,12 +823,12 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds
int ret;
src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
src_vq->drv_priv = ctx;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &m2mtest_qops;
src_vq->mem_ops = &vb2_vmalloc_memops;
- src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
src_vq->lock = &ctx->dev->dev_mutex;
ret = vb2_queue_init(src_vq);
@@ -785,12 +836,12 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds
return ret;
dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
dst_vq->drv_priv = ctx;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &m2mtest_qops;
dst_vq->mem_ops = &vb2_vmalloc_memops;
- dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
dst_vq->lock = &ctx->dev->dev_mutex;
return vb2_queue_init(dst_vq);
@@ -801,10 +852,10 @@ static const struct v4l2_ctrl_config m2mtest_ctrl_trans_time_msec = {
.id = V4L2_CID_TRANS_TIME_MSEC,
.name = "Transaction Time (msec)",
.type = V4L2_CTRL_TYPE_INTEGER,
- .def = 1001,
+ .def = MEM2MEM_DEF_TRANSTIME,
.min = 1,
.max = 10001,
- .step = 100,
+ .step = 1,
};
static const struct v4l2_ctrl_config m2mtest_ctrl_trans_num_bufs = {
diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c
index c690435853bd..0b7480e82142 100644
--- a/drivers/media/platform/mx2_emmaprp.c
+++ b/drivers/media/platform/mx2_emmaprp.c
@@ -377,8 +377,13 @@ static irqreturn_t emmaprp_irq(int irq_emma, void *data)
src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
- src_vb->v4l2_buf.timestamp = dst_vb->v4l2_buf.timestamp;
- src_vb->v4l2_buf.timecode = dst_vb->v4l2_buf.timecode;
+ dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp;
+ dst_vb->v4l2_buf.flags &=
+ ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+ dst_vb->v4l2_buf.flags |=
+ src_vb->v4l2_buf.flags
+ & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+ dst_vb->v4l2_buf.timecode = src_vb->v4l2_buf.timecode;
spin_lock_irqsave(&pcdev->irqlock, flags);
v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
@@ -766,7 +771,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &emmaprp_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
- src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -778,7 +783,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &emmaprp_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
- dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
return vb2_queue_init(dst_vq);
}
diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c
index dfd0a21a0658..9a726eacb29b 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -601,6 +601,7 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus)
switch (cur_display->type) {
case OMAP_DISPLAY_TYPE_DSI:
case OMAP_DISPLAY_TYPE_DPI:
+ case OMAP_DISPLAY_TYPE_DVI:
if (mgr_id == OMAP_DSS_CHANNEL_LCD)
irq = DISPC_IRQ_VSYNC;
else if (mgr_id == OMAP_DSS_CHANNEL_LCD2)
diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c
index cf1c437a8687..62e7e5783ce8 100644
--- a/drivers/media/platform/omap/omap_vout_vrfb.c
+++ b/drivers/media/platform/omap/omap_vout_vrfb.c
@@ -270,7 +270,8 @@ int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, 0x20, 0);
omap_start_dma(tx->dma_ch);
- interruptible_sleep_on_timeout(&tx->wait, VRFB_TX_TIMEOUT);
+ wait_event_interruptible_timeout(tx->wait, tx->tx_status == 1,
+ VRFB_TX_TIMEOUT);
if (tx->tx_status == 0) {
omap_stop_dma(tx->dma_ch);
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 5807185262fe..06a0df434249 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -391,7 +391,7 @@ static void isp_disable_interrupts(struct isp_device *isp)
* @isp: OMAP3 ISP device
* @idle: Consider idle state.
*
- * Set the power settings for the ISP and SBL bus and cConfigure the HS/VS
+ * Set the power settings for the ISP and SBL bus and configure the HS/VS
* interrupt source.
*
* We need to configure the HS/VS interrupt source before interrupts get
@@ -588,9 +588,6 @@ static void isp_isr_sbl(struct isp_device *isp)
* @_isp: Pointer to the OMAP3 ISP device
*
* Handles the corresponding callback if plugged in.
- *
- * Returns IRQ_HANDLED when IRQ was correctly handled, or IRQ_NONE when the
- * IRQ wasn't handled.
*/
static irqreturn_t isp_isr(int irq, void *_isp)
{
@@ -1420,7 +1417,7 @@ int omap3isp_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait,
}
/*
- * omap3isp_module_sync_is_stopped - Helper to verify if module was stopping
+ * omap3isp_module_sync_is_stopping - Helper to verify if module was stopping
* @wait: ISP submodule's wait queue for streamoff/interrupt synchronization
* @stopping: flag which tells module wants to stop
*
diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h
index 081f5ec5a663..6d5e69711907 100644
--- a/drivers/media/platform/omap3isp/isp.h
+++ b/drivers/media/platform/omap3isp/isp.h
@@ -265,7 +265,7 @@ void omap3isp_unregister_entities(struct platform_device *pdev);
/*
* isp_reg_readl - Read value of an OMAP3 ISP register
- * @dev: Device pointer specific to the OMAP3 ISP.
+ * @isp: Device pointer specific to the OMAP3 ISP.
* @isp_mmio_range: Range to which the register offset refers to.
* @reg_offset: Register offset to read from.
*
@@ -280,7 +280,7 @@ u32 isp_reg_readl(struct isp_device *isp, enum isp_mem_resources isp_mmio_range,
/*
* isp_reg_writel - Write value to an OMAP3 ISP register
- * @dev: Device pointer specific to the OMAP3 ISP.
+ * @isp: Device pointer specific to the OMAP3 ISP.
* @reg_value: 32 bit value to write to the register.
* @isp_mmio_range: Range to which the register offset refers to.
* @reg_offset: Register offset to write into.
@@ -293,8 +293,8 @@ void isp_reg_writel(struct isp_device *isp, u32 reg_value,
}
/*
- * isp_reg_and - Clear individual bits in an OMAP3 ISP register
- * @dev: Device pointer specific to the OMAP3 ISP.
+ * isp_reg_clr - Clear individual bits in an OMAP3 ISP register
+ * @isp: Device pointer specific to the OMAP3 ISP.
* @mmio_range: Range to which the register offset refers to.
* @reg: Register offset to work on.
* @clr_bits: 32 bit value which would be cleared in the register.
@@ -310,7 +310,7 @@ void isp_reg_clr(struct isp_device *isp, enum isp_mem_resources mmio_range,
/*
* isp_reg_set - Set individual bits in an OMAP3 ISP register
- * @dev: Device pointer specific to the OMAP3 ISP.
+ * @isp: Device pointer specific to the OMAP3 ISP.
* @mmio_range: Range to which the register offset refers to.
* @reg: Register offset to work on.
* @set_bits: 32 bit value which would be set in the register.
@@ -326,7 +326,7 @@ void isp_reg_set(struct isp_device *isp, enum isp_mem_resources mmio_range,
/*
* isp_reg_clr_set - Clear and set invidial bits in an OMAP3 ISP register
- * @dev: Device pointer specific to the OMAP3 ISP.
+ * @isp: Device pointer specific to the OMAP3 ISP.
* @mmio_range: Range to which the register offset refers to.
* @reg: Register offset to work on.
* @clr_bits: 32 bit value which would be cleared in the register.
diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c
index 5db2c88b9ad8..4d920c800ff5 100644
--- a/drivers/media/platform/omap3isp/ispccdc.c
+++ b/drivers/media/platform/omap3isp/ispccdc.c
@@ -293,7 +293,7 @@ static int __ccdc_lsc_enable(struct isp_ccdc_device *ccdc, int enable)
isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC,
ISPCCDC_LSC_CONFIG, ISPCCDC_LSC_ENABLE);
ccdc->lsc.state = LSC_STATE_STOPPED;
- dev_warn(to_device(ccdc), "LSC prefecth timeout\n");
+ dev_warn(to_device(ccdc), "LSC prefetch timeout\n");
return -ETIMEDOUT;
}
ccdc->lsc.state = LSC_STATE_RUNNING;
@@ -674,7 +674,7 @@ static void ccdc_config_imgattr(struct isp_ccdc_device *ccdc, u32 colptn)
/*
* ccdc_config - Set CCDC configuration from userspace
* @ccdc: Pointer to ISP CCDC device.
- * @userspace_add: Structure containing CCDC configuration sent from userspace.
+ * @ccdc_struct: Structure containing CCDC configuration sent from userspace.
*
* Returns 0 if successful, -EINVAL if the pointer to the configuration
* structure is null, or the copy_from_user function fails to copy user space
@@ -793,7 +793,7 @@ static void ccdc_apply_controls(struct isp_ccdc_device *ccdc)
/*
* omap3isp_ccdc_restore_context - Restore values of the CCDC module registers
- * @dev: Pointer to ISP device
+ * @isp: Pointer to ISP device
*/
void omap3isp_ccdc_restore_context(struct isp_device *isp)
{
@@ -2525,7 +2525,7 @@ error_video:
/*
* omap3isp_ccdc_init - CCDC module initialization.
- * @dev: Device pointer specific to the OMAP3 ISP.
+ * @isp: Device pointer specific to the OMAP3 ISP.
*
* TODO: Get the initialisation values from platform data.
*
@@ -2564,7 +2564,7 @@ int omap3isp_ccdc_init(struct isp_device *isp)
/*
* omap3isp_ccdc_cleanup - CCDC module cleanup.
- * @dev: Device pointer specific to the OMAP3 ISP.
+ * @isp: Device pointer specific to the OMAP3 ISP.
*/
void omap3isp_ccdc_cleanup(struct isp_device *isp)
{
diff --git a/drivers/media/platform/omap3isp/ispccdc.h b/drivers/media/platform/omap3isp/ispccdc.h
index a5da9e19edbf..9d24e4107864 100644
--- a/drivers/media/platform/omap3isp/ispccdc.h
+++ b/drivers/media/platform/omap3isp/ispccdc.h
@@ -63,12 +63,6 @@ struct ispccdc_lsc_config_req {
/*
* ispccdc_lsc - CCDC LSC parameters
- * @update_config: Set when user changes config
- * @request_enable: Whether LSC is requested to be enabled
- * @config: LSC config set by user
- * @update_table: Set when user provides a new LSC table to table_new
- * @table_new: LSC table set by user, ISP address
- * @table_inuse: LSC table currently in use, ISP address
*/
struct ispccdc_lsc {
enum ispccdc_lsc_state state;
diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c
index e84fe0543e47..b30b67d22a58 100644
--- a/drivers/media/platform/omap3isp/ispccp2.c
+++ b/drivers/media/platform/omap3isp/ispccp2.c
@@ -211,7 +211,7 @@ static void ccp2_mem_enable(struct isp_ccp2_device *ccp2, u8 enable)
/*
* ccp2_phyif_config - Initialize CCP2 phy interface config
* @ccp2: Pointer to ISP CCP2 device
- * @config: CCP2 platform data
+ * @pdata: CCP2 platform data
*
* Configure the CCP2 physical interface module from platform data.
*
@@ -518,7 +518,7 @@ static void ccp2_mem_configure(struct isp_ccp2_device *ccp2,
ISPCCP2_LCM_IRQSTATUS_EOF_IRQ,
OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_IRQSTATUS);
- /* Enable LCM interupts */
+ /* Enable LCM interrupts */
isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_IRQENABLE,
ISPCCP2_LCM_IRQSTATUS_EOF_IRQ |
ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ);
@@ -1096,7 +1096,7 @@ static int ccp2_init_entities(struct isp_ccp2_device *ccp2)
* implementation we use a fixed 32 bytes alignment regardless of the
* input format and width. If strict 128 bits alignment support is
* required ispvideo will need to be made aware of this special dual
- * alignement requirements.
+ * alignment requirements.
*/
ccp2->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
ccp2->video_in.bpl_alignment = 32;
diff --git a/drivers/media/platform/omap3isp/isphist.c b/drivers/media/platform/omap3isp/isphist.c
index e070c24048ef..06a5f8164eaa 100644
--- a/drivers/media/platform/omap3isp/isphist.c
+++ b/drivers/media/platform/omap3isp/isphist.c
@@ -299,7 +299,7 @@ static u32 hist_get_buf_size(struct omap3isp_hist_config *conf)
/*
* hist_validate_params - Helper function to check user given params.
- * @user_cfg: Pointer to user configuration structure.
+ * @new_conf: Pointer to user configuration structure.
*
* Returns 0 on success configuration.
*/
@@ -351,7 +351,7 @@ static int hist_validate_params(struct ispstat *hist, void *new_conf)
buf_size = hist_get_buf_size(user_cfg);
if (buf_size > user_cfg->buf_size)
- /* User's buf_size request wasn't enoght */
+ /* User's buf_size request wasn't enough */
user_cfg->buf_size = buf_size;
else if (user_cfg->buf_size > OMAP3ISP_HIST_MAX_BUF_SIZE)
user_cfg->buf_size = OMAP3ISP_HIST_MAX_BUF_SIZE;
diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c
index 1c776c1186f1..395b2b068c75 100644
--- a/drivers/media/platform/omap3isp/isppreview.c
+++ b/drivers/media/platform/omap3isp/isppreview.c
@@ -122,7 +122,7 @@ static struct omap3isp_prev_csc flr_prev_csc = {
#define PREV_MAX_OUT_WIDTH_REV_15 4096
/*
- * Coeficient Tables for the submodules in Preview.
+ * Coefficient Tables for the submodules in Preview.
* Array is initialised with the values from.the tables text file.
*/
@@ -971,7 +971,8 @@ static void preview_setup_hw(struct isp_prev_device *prev, u32 update,
/*
* preview_config_ycpos - Configure byte layout of YUV image.
- * @mode: Indicates the required byte layout.
+ * @prev: pointer to previewer private structure
+ * @pixelcode: pixel code
*/
static void
preview_config_ycpos(struct isp_prev_device *prev,
@@ -1079,6 +1080,7 @@ static void preview_config_input_format(struct isp_prev_device *prev,
*/
static void preview_config_input_size(struct isp_prev_device *prev, u32 active)
{
+ const struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK];
struct isp_device *isp = to_isp_device(prev);
unsigned int sph = prev->crop.left;
unsigned int eph = prev->crop.left + prev->crop.width - 1;
@@ -1086,6 +1088,14 @@ static void preview_config_input_size(struct isp_prev_device *prev, u32 active)
unsigned int elv = prev->crop.top + prev->crop.height - 1;
u32 features;
+ if (format->code != V4L2_MBUS_FMT_Y8_1X8 &&
+ format->code != V4L2_MBUS_FMT_Y10_1X10) {
+ sph -= 2;
+ eph += 2;
+ slv -= 2;
+ elv += 2;
+ }
+
features = (prev->params.params[0].features & active)
| (prev->params.params[1].features & ~active);
@@ -1363,8 +1373,8 @@ static void preview_init_params(struct isp_prev_device *prev)
}
/*
- * preview_max_out_width - Handle previewer hardware ouput limitations
- * @isp_revision : ISP revision
+ * preview_max_out_width - Handle previewer hardware output limitations
+ * @prev: pointer to previewer private structure
* returns maximum width output for current isp revision
*/
static unsigned int preview_max_out_width(struct isp_prev_device *prev)
@@ -1610,7 +1620,7 @@ static const struct v4l2_ctrl_ops preview_ctrl_ops = {
/*
* preview_ioctl - Handle preview module private ioctl's
- * @prev: pointer to preview context structure
+ * @sd: pointer to v4l2 subdev structure
* @cmd: configuration command
* @arg: configuration argument
* return -EINVAL or zero on success
@@ -2341,7 +2351,7 @@ error_video_in:
/*
* omap3isp_preview_init - Previewer initialization.
- * @dev : Pointer to ISP device
+ * @isp : Pointer to ISP device
* return -ENOMEM or zero on success
*/
int omap3isp_preview_init(struct isp_device *isp)
diff --git a/drivers/media/platform/omap3isp/ispqueue.c b/drivers/media/platform/omap3isp/ispqueue.c
index 5f0f8fab1d17..a5e65858e799 100644
--- a/drivers/media/platform/omap3isp/ispqueue.c
+++ b/drivers/media/platform/omap3isp/ispqueue.c
@@ -597,7 +597,7 @@ static int isp_video_buffer_wait(struct isp_video_buffer *buf, int nonblocking)
* isp_video_queue_free - Free video buffers memory
*
* Buffers can only be freed if the queue isn't streaming and if no buffer is
- * mapped to userspace. Return -EBUSY if those conditions aren't statisfied.
+ * mapped to userspace. Return -EBUSY if those conditions aren't satisfied.
*
* This function must be called with the queue lock held.
*/
diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c
index 0d36b8bc9f98..86369df81d74 100644
--- a/drivers/media/platform/omap3isp/ispresizer.c
+++ b/drivers/media/platform/omap3isp/ispresizer.c
@@ -206,7 +206,7 @@ static void resizer_set_bilinear(struct isp_res_device *res,
/*
* resizer_set_ycpos - Luminance and chrominance order
* @res: Device context.
- * @order: order type.
+ * @pixelcode: pixel code.
*/
static void resizer_set_ycpos(struct isp_res_device *res,
enum v4l2_mbus_pixelcode pixelcode)
@@ -918,8 +918,8 @@ static void resizer_calc_ratios(struct isp_res_device *res,
/*
* resizer_set_crop_params - Setup hardware with cropping parameters
* @res : resizer private structure
- * @crop_rect : current crop rectangle
- * @ratio : resizer ratios
+ * @input : format on sink pad
+ * @output : format on source pad
* return none
*/
static void resizer_set_crop_params(struct isp_res_device *res,
diff --git a/drivers/media/platform/omap3isp/ispresizer.h b/drivers/media/platform/omap3isp/ispresizer.h
index 70c1c0e1bbdf..9b01e9047c15 100644
--- a/drivers/media/platform/omap3isp/ispresizer.h
+++ b/drivers/media/platform/omap3isp/ispresizer.h
@@ -30,12 +30,12 @@
#include <linux/types.h>
/*
- * Constants for filter coefficents count
+ * Constants for filter coefficients count
*/
#define COEFF_CNT 32
/*
- * struct isprsz_coef - Structure for resizer filter coeffcients.
+ * struct isprsz_coef - Structure for resizer filter coefficients.
* @h_filter_coef_4tap: Horizontal filter coefficients for 8-phase/4-tap
* mode (.5x-4x)
* @v_filter_coef_4tap: Vertical filter coefficients for 8-phase/4-tap
diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c
index a75407c3a726..5707f85c4cc4 100644
--- a/drivers/media/platform/omap3isp/ispstat.c
+++ b/drivers/media/platform/omap3isp/ispstat.c
@@ -144,7 +144,7 @@ static int isp_stat_buf_check_magic(struct ispstat *stat,
for (w = buf->virt_addr + buf_size, end = w + MAGIC_SIZE;
w < end; w++) {
if (unlikely(*w != MAGIC_NUM)) {
- dev_dbg(stat->isp->dev, "%s: endding magic check does "
+ dev_dbg(stat->isp->dev, "%s: ending magic check does "
"not match.\n", stat->subdev.name);
return -EINVAL;
}
@@ -841,7 +841,7 @@ int omap3isp_stat_s_stream(struct v4l2_subdev *subdev, int enable)
if (enable) {
/*
* Only set enable PCR bit if the module was previously
- * enabled through ioct.
+ * enabled through ioctl.
*/
isp_stat_try_enable(stat);
} else {
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index 856fdf554035..85b4036ba5e4 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -333,7 +333,7 @@ isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh)
/*
* ispmmu_vmap - Wrapper for Virtual memory mapping of a scatter gather list
- * @dev: Device pointer specific to the OMAP3 ISP.
+ * @isp: Device pointer specific to the OMAP3 ISP.
* @sglist: Pointer to source Scatter gather list to allocate.
* @sglen: Number of elements of the scatter-gatter list.
*
@@ -363,7 +363,7 @@ ispmmu_vmap(struct isp_device *isp, const struct scatterlist *sglist, int sglen)
/*
* ispmmu_vunmap - Unmap a device address from the ISP MMU
- * @dev: Device pointer specific to the OMAP3 ISP.
+ * @isp: Device pointer specific to the OMAP3 ISP.
* @da: Device address generated from a ispmmu_vmap call.
*/
static void ispmmu_vunmap(struct isp_device *isp, dma_addr_t da)
@@ -886,7 +886,11 @@ static int isp_video_check_external_subdevs(struct isp_video *video,
struct v4l2_ext_controls ctrls;
struct v4l2_ext_control ctrl;
unsigned int i;
- int ret = 0;
+ int ret;
+
+ /* Memory-to-memory pipelines have no external subdev. */
+ if (pipe->input != NULL)
+ return 0;
for (i = 0; i < ARRAY_SIZE(ents); i++) {
/* Is the entity part of the pipeline? */
@@ -905,7 +909,7 @@ static int isp_video_check_external_subdevs(struct isp_video *video,
if (!source) {
dev_warn(isp->dev, "can't find source, failing now\n");
- return ret;
+ return -EINVAL;
}
if (media_entity_type(source) != MEDIA_ENT_T_V4L2_SUBDEV)
diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c
index 40b298ab87f1..4e4d1631e042 100644
--- a/drivers/media/platform/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/s3c-camif/camif-capture.c
@@ -1160,7 +1160,7 @@ int s3c_camif_register_video_node(struct camif_dev *camif, int idx)
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct camif_buffer);
q->drv_priv = vp;
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
ret = vb2_queue_init(q);
if (ret)
@@ -1592,26 +1592,27 @@ int s3c_camif_create_subdev(struct camif_dev *camif)
ARRAY_SIZE(s3c_camif_test_pattern_menu) - 1, 0, 0,
s3c_camif_test_pattern_menu);
- camif->ctrl_colorfx = v4l2_ctrl_new_std_menu(handler,
+ if (camif->variant->has_img_effect) {
+ camif->ctrl_colorfx = v4l2_ctrl_new_std_menu(handler,
&s3c_camif_subdev_ctrl_ops,
V4L2_CID_COLORFX, V4L2_COLORFX_SET_CBCR,
~0x981f, V4L2_COLORFX_NONE);
- camif->ctrl_colorfx_cbcr = v4l2_ctrl_new_std(handler,
+ camif->ctrl_colorfx_cbcr = v4l2_ctrl_new_std(handler,
&s3c_camif_subdev_ctrl_ops,
V4L2_CID_COLORFX_CBCR, 0, 0xffff, 1, 0);
+ }
+
if (handler->error) {
v4l2_ctrl_handler_free(handler);
media_entity_cleanup(&sd->entity);
return handler->error;
}
- v4l2_ctrl_auto_cluster(2, &camif->ctrl_colorfx,
+ if (camif->variant->has_img_effect)
+ v4l2_ctrl_auto_cluster(2, &camif->ctrl_colorfx,
V4L2_COLORFX_SET_CBCR, false);
- if (!camif->variant->has_img_effect) {
- camif->ctrl_colorfx->flags |= V4L2_CTRL_FLAG_DISABLED;
- camif->ctrl_colorfx_cbcr->flags |= V4L2_CTRL_FLAG_DISABLED;
- }
+
sd->ctrl_handler = handler;
v4l2_set_subdevdata(sd, camif);
diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c
index 0fcf7d75e841..357af1ebaeda 100644
--- a/drivers/media/platform/s5p-g2d/g2d.c
+++ b/drivers/media/platform/s5p-g2d/g2d.c
@@ -157,7 +157,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->ops = &g2d_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
- src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
src_vq->lock = &ctx->dev->mutex;
ret = vb2_queue_init(src_vq);
@@ -170,7 +170,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->ops = &g2d_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
- dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
dst_vq->lock = &ctx->dev->mutex;
return vb2_queue_init(dst_vq);
@@ -560,6 +560,9 @@ static irqreturn_t g2d_isr(int irq, void *prv)
dst->v4l2_buf.timecode = src->v4l2_buf.timecode;
dst->v4l2_buf.timestamp = src->v4l2_buf.timestamp;
+ dst->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+ dst->v4l2_buf.flags |=
+ src->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE);
v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 7d68d0b9966a..8a18972012f7 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -1701,7 +1701,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &s5p_jpeg_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
- src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
src_vq->lock = &ctx->jpeg->lock;
ret = vb2_queue_init(src_vq);
@@ -1714,7 +1714,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &s5p_jpeg_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
- dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
dst_vq->lock = &ctx->jpeg->lock;
return vb2_queue_init(dst_vq);
@@ -1766,6 +1766,9 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
+ dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+ dst_buf->v4l2_buf.flags |=
+ src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
v4l2_m2m_buf_done(src_buf, state);
if (curr_ctx->mode == S5P_JPEG_ENCODE)
diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h
index 2398cdf61341..8d0b686d9adb 100644
--- a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h
+++ b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h
@@ -229,6 +229,7 @@
#define S5P_FIMV_E_PADDING_CTRL_V6 0xf7a4
#define S5P_FIMV_E_MV_HOR_RANGE_V6 0xf7ac
#define S5P_FIMV_E_MV_VER_RANGE_V6 0xf7b0
+#define S5P_FIMV_E_MV_RANGE_V6_MASK 0x3fff
#define S5P_FIMV_E_VBV_BUFFER_SIZE_V6 0xf84c
#define S5P_FIMV_E_VBV_INIT_DELAY_V6 0xf850
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
index e2aac592d29f..89356ae90238 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -232,6 +232,11 @@ static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx)
src_buf->b->v4l2_buf.timecode;
dst_buf->b->v4l2_buf.timestamp =
src_buf->b->v4l2_buf.timestamp;
+ dst_buf->b->v4l2_buf.flags &=
+ ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+ dst_buf->b->v4l2_buf.flags |=
+ src_buf->b->v4l2_buf.flags
+ & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
switch (frame_type) {
case S5P_FIMV_DECODE_FRAME_I_FRAME:
dst_buf->b->v4l2_buf.flags |=
@@ -794,7 +799,7 @@ static int s5p_mfc_open(struct file *file)
goto err_queue_init;
}
q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(q);
if (ret) {
mfc_err("Failed to initialize videobuf2 queue(capture)\n");
@@ -816,7 +821,7 @@ static int s5p_mfc_open(struct file *file)
goto err_queue_init;
}
q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(q);
if (ret) {
mfc_err("Failed to initialize videobuf2 queue(output)\n");
@@ -1147,9 +1152,9 @@ static int s5p_mfc_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto err_dec_alloc;
}
- vfd->fops = &s5p_mfc_fops,
+ vfd->fops = &s5p_mfc_fops;
vfd->ioctl_ops = get_dec_v4l2_ioctl_ops();
- vfd->release = video_device_release,
+ vfd->release = video_device_release;
vfd->lock = &dev->mfc_mutex;
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->vfl_dir = VFL_DIR_M2M;
@@ -1172,9 +1177,9 @@ static int s5p_mfc_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto err_enc_alloc;
}
- vfd->fops = &s5p_mfc_fops,
+ vfd->fops = &s5p_mfc_fops;
vfd->ioctl_ops = get_enc_v4l2_ioctl_ops();
- vfd->release = video_device_release,
+ vfd->release = video_device_release;
vfd->lock = &dev->mfc_mutex;
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->vfl_dir = VFL_DIR_M2M;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
index f723f1f2f578..5c28cc3e699b 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
@@ -426,6 +426,8 @@ struct s5p_mfc_vp8_enc_params {
struct s5p_mfc_enc_params {
u16 width;
u16 height;
+ u32 mv_h_range;
+ u32 mv_v_range;
u16 gop_size;
enum v4l2_mpeg_video_multi_slice_mode slice_mode;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
index 2475a3c9a0a6..ee05f2dd439b 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
@@ -44,8 +44,6 @@ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev)
return -ENOMEM;
}
- dev->bank1 = dev->bank1;
-
if (HAS_PORTNUM(dev) && IS_TWOPORT(dev)) {
bank2_virt = dma_alloc_coherent(dev->mem_dev_r, 1 << MFC_BASE_ALIGN_ORDER,
&bank2_dma_addr, GFP_KERNEL);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
index 91b6e020ddf3..df83cd157bab 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
@@ -208,6 +208,24 @@ static struct mfc_control controls[] = {
.default_value = 0,
},
{
+ .id = V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Horizontal MV Search Range",
+ .minimum = 16,
+ .maximum = 128,
+ .step = 16,
+ .default_value = 32,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Vertical MV Search Range",
+ .minimum = 16,
+ .maximum = 128,
+ .step = 16,
+ .default_value = 32,
+ },
+ {
.id = V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
@@ -1417,6 +1435,12 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_MPEG_VIDEO_VBV_SIZE:
p->vbv_size = ctrl->val;
break;
+ case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE:
+ p->mv_h_range = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE:
+ p->mv_v_range = ctrl->val;
+ break;
case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:
p->codec.h264.cpb_size = ctrl->val;
break;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
index f6ff2dbf3a1d..f64621ae9b5a 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
@@ -727,14 +727,10 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6);
/* setting for MV range [16, 256] */
- reg = 0;
- reg &= ~(0x3FFF);
- reg = 256;
+ reg = (p->mv_h_range & S5P_FIMV_E_MV_RANGE_V6_MASK);
WRITEL(reg, S5P_FIMV_E_MV_HOR_RANGE_V6);
- reg = 0;
- reg &= ~(0x3FFF);
- reg = 256;
+ reg = (p->mv_v_range & S5P_FIMV_E_MV_RANGE_V6_MASK);
WRITEL(reg, S5P_FIMV_E_MV_VER_RANGE_V6);
WRITEL(0x0, S5P_FIMV_E_FRAME_INSERTION_V6);
diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c
index c5059ba0d733..a1ce55fd30f3 100644
--- a/drivers/media/platform/s5p-tv/mixer_video.c
+++ b/drivers/media/platform/s5p-tv/mixer_video.c
@@ -946,11 +946,6 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
mxr_dbg(mdev, "%s\n", __func__);
- if (count == 0) {
- mxr_dbg(mdev, "no output buffers queued\n");
- return -ENOBUFS;
- }
-
/* block any changes in output configuration */
mxr_output_get(mdev);
@@ -1124,6 +1119,7 @@ struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
.drv_priv = layer,
.buf_struct_size = sizeof(struct mxr_buffer),
.ops = &mxr_video_qops,
+ .min_buffers_needed = 1,
.mem_ops = &vb2_dma_contig_memops,
};
diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c
index 4835173d7f80..f0b6c900034d 100644
--- a/drivers/media/platform/soc_camera/atmel-isi.c
+++ b/drivers/media/platform/soc_camera/atmel-isi.c
@@ -472,7 +472,7 @@ static int isi_camera_init_videobuf(struct vb2_queue *q,
q->buf_struct_size = sizeof(struct frame_buffer);
q->ops = &isi_video_qops;
q->mem_ops = &vb2_dma_contig_memops;
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
return vb2_queue_init(q);
}
diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c
index d73abca9c6ee..3e844803bdca 100644
--- a/drivers/media/platform/soc_camera/mx2_camera.c
+++ b/drivers/media/platform/soc_camera/mx2_camera.c
@@ -794,7 +794,7 @@ static int mx2_camera_init_videobuf(struct vb2_queue *q,
q->ops = &mx2_videobuf_ops;
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct mx2_buffer);
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
return vb2_queue_init(q);
}
diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c
index f975b7008692..9ed81ac6881c 100644
--- a/drivers/media/platform/soc_camera/mx3_camera.c
+++ b/drivers/media/platform/soc_camera/mx3_camera.c
@@ -453,7 +453,7 @@ static int mx3_camera_init_videobuf(struct vb2_queue *q,
q->ops = &mx3_videobuf_ops;
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct mx3_camera_buffer);
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
return vb2_queue_init(q);
}
diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c
index 3b1c05a72d00..704eee766487 100644
--- a/drivers/media/platform/soc_camera/rcar_vin.c
+++ b/drivers/media/platform/soc_camera/rcar_vin.c
@@ -68,6 +68,8 @@
#define VNMC_YCAL (1 << 19)
#define VNMC_INF_YUV8_BT656 (0 << 16)
#define VNMC_INF_YUV8_BT601 (1 << 16)
+#define VNMC_INF_YUV10_BT656 (2 << 16)
+#define VNMC_INF_YUV10_BT601 (3 << 16)
#define VNMC_INF_YUV16 (5 << 16)
#define VNMC_VUP (1 << 10)
#define VNMC_IM_ODD (0 << 3)
@@ -275,6 +277,12 @@ static int rcar_vin_setup(struct rcar_vin_priv *priv)
/* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */
vnmc |= priv->pdata->flags & RCAR_VIN_BT656 ?
VNMC_INF_YUV8_BT656 : VNMC_INF_YUV8_BT601;
+ break;
+ case V4L2_MBUS_FMT_YUYV10_2X10:
+ /* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */
+ vnmc |= priv->pdata->flags & RCAR_VIN_BT656 ?
+ VNMC_INF_YUV10_BT656 : VNMC_INF_YUV10_BT601;
+ break;
default:
break;
}
@@ -1003,6 +1011,7 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx,
switch (code) {
case V4L2_MBUS_FMT_YUYV8_1X16:
case V4L2_MBUS_FMT_YUYV8_2X8:
+ case V4L2_MBUS_FMT_YUYV10_2X10:
if (cam->extra_fmt)
break;
@@ -1360,7 +1369,7 @@ static int rcar_vin_init_videobuf2(struct vb2_queue *vq,
vq->ops = &rcar_vin_vb2_ops;
vq->mem_ops = &vb2_dma_contig_memops;
vq->buf_struct_size = sizeof(struct rcar_vin_buffer);
- vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
return vb2_queue_init(vq);
}
diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
index 150bd4df413c..3e75a469cd49 100644
--- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
@@ -1665,7 +1665,7 @@ static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q,
q->ops = &sh_mobile_ceu_videobuf_ops;
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct sh_mobile_ceu_buffer);
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
return vb2_queue_init(q);
}
diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c
index 1296c5386231..7a77a5b7a075 100644
--- a/drivers/media/platform/ti-vpe/vpe.c
+++ b/drivers/media/platform/ti-vpe/vpe.c
@@ -1278,6 +1278,8 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data)
d_buf = &d_vb->v4l2_buf;
d_buf->timestamp = s_buf->timestamp;
+ d_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+ d_buf->flags |= s_buf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
if (s_buf->flags & V4L2_BUF_FLAG_TIMECODE) {
d_buf->flags |= V4L2_BUF_FLAG_TIMECODE;
d_buf->timecode = s_buf->timecode;
@@ -1770,7 +1772,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &vpe_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
- src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -1783,7 +1785,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &vpe_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
- dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
return vb2_queue_init(dst_vq);
}
diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c
index 2d4e73b45c5e..3890f4f42a78 100644
--- a/drivers/media/platform/vivi.c
+++ b/drivers/media/platform/vivi.c
@@ -70,10 +70,6 @@ static unsigned debug;
module_param(debug, uint, 0644);
MODULE_PARM_DESC(debug, "activates debug info");
-static unsigned int vid_limit = 16;
-module_param(vid_limit, uint, 0644);
-MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
-
/* Global font descriptor */
static const u8 *font8x16;
@@ -191,7 +187,6 @@ struct vivi_buffer {
/* common v4l buffer stuff -- must be first */
struct vb2_buffer vb;
struct list_head list;
- const struct vivi_fmt *fmt;
};
struct vivi_dmaqueue {
@@ -254,7 +249,7 @@ struct vivi_dev {
struct v4l2_fract timeperframe;
unsigned int width, height;
struct vb2_queue vb_vidq;
- unsigned int field_count;
+ unsigned int seq_count;
u8 bars[9][3];
u8 line[MAX_WIDTH * 8] __attribute__((__aligned__(4)));
@@ -675,8 +670,7 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
dev->mv_count += 2;
buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
- dev->field_count++;
- buf->vb.v4l2_buf.sequence = dev->field_count >> 1;
+ buf->vb.v4l2_buf.sequence = dev->seq_count++;
v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
}
@@ -818,19 +812,15 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
struct vivi_dev *dev = vb2_get_drv_priv(vq);
unsigned long size;
- if (fmt)
+ size = dev->width * dev->height * dev->pixelsize;
+ if (fmt) {
+ if (fmt->fmt.pix.sizeimage < size)
+ return -EINVAL;
size = fmt->fmt.pix.sizeimage;
- else
- size = dev->width * dev->height * dev->pixelsize;
-
- if (size == 0)
- return -EINVAL;
-
- if (0 == *nbuffers)
- *nbuffers = 32;
-
- while (size * *nbuffers > vid_limit * 1024 * 1024)
- (*nbuffers)--;
+ /* check against insane over 8K resolution buffers */
+ if (size > 7680 * 4320 * dev->pixelsize)
+ return -EINVAL;
+ }
*nplanes = 1;
@@ -876,8 +866,6 @@ static int buffer_prepare(struct vb2_buffer *vb)
vb2_set_plane_payload(&buf->vb, 0, size);
- buf->fmt = dev->fmt;
-
precalculate_bars(dev);
precalculate_line(dev);
@@ -901,8 +889,20 @@ static void buffer_queue(struct vb2_buffer *vb)
static int start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct vivi_dev *dev = vb2_get_drv_priv(vq);
+ int err;
+
dprintk(dev, 1, "%s\n", __func__);
- return vivi_start_generating(dev);
+ dev->seq_count = 0;
+ err = vivi_start_generating(dev);
+ if (err) {
+ struct vivi_buffer *buf, *tmp;
+
+ list_for_each_entry_safe(buf, tmp, &dev->vidq.active, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+ }
+ }
+ return err;
}
/* abort streaming and wait for last buffer */
@@ -1121,7 +1121,11 @@ static int vidioc_enum_frameintervals(struct file *file, void *priv,
if (!fmt)
return -EINVAL;
- /* regarding width & height - we support any */
+ /* check for valid width/height */
+ if (fival->width < 48 || fival->width > MAX_WIDTH || (fival->width & 3))
+ return -EINVAL;
+ if (fival->height < 32 || fival->height > MAX_HEIGHT)
+ return -EINVAL;
fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
@@ -1439,7 +1443,7 @@ static int __init vivi_create_instance(int inst)
q->buf_struct_size = sizeof(struct vivi_buffer);
q->ops = &vivi_video_qops;
q->mem_ops = &vb2_vmalloc_memops;
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
ret = vb2_queue_init(q);
if (ret)
diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h
index 94d1b02680c5..0313210c6e9e 100644
--- a/drivers/media/platform/vsp1/vsp1.h
+++ b/drivers/media/platform/vsp1/vsp1.h
@@ -1,7 +1,7 @@
/*
* vsp1.h -- R-Car VSP1 Driver
*
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index 0df0a994e575..2f74f0e0ddf5 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -1,7 +1,7 @@
/*
* vsp1_drv.c -- R-Car VSP1 Driver
*
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index 0226e47df6d9..3fc9e4266caf 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -1,7 +1,7 @@
/*
* vsp1_entity.c -- R-Car VSP1 Base Entity
*
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index e152798d7f38..f6fd6988aeb0 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -1,7 +1,7 @@
/*
* vsp1_entity.h -- R-Car VSP1 Base Entity
*
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index 74a32e69ef10..135a78957014 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -1,7 +1,7 @@
/*
* vsp1_lif.c -- R-Car VSP1 LCD Controller Interface
*
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
diff --git a/drivers/media/platform/vsp1/vsp1_lif.h b/drivers/media/platform/vsp1/vsp1_lif.h
index 89b93af56fdc..7b35879028de 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.h
+++ b/drivers/media/platform/vsp1/vsp1_lif.h
@@ -1,7 +1,7 @@
/*
* vsp1_lif.h -- R-Car VSP1 LCD Controller Interface
*
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index bce2be5466b9..2b04d0f95c62 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -1,7 +1,7 @@
/*
* vsp1_rpf.c -- R-Car VSP1 Read Pixel Formatter
*
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index 782f770daee5..ec3dab6a9b9b 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -1,7 +1,7 @@
/*
* vsp1_rwpf.c -- R-Car VSP1 Read and Write Pixel Formatters
*
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 6cbdb547470b..5c5ee81bbeae 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -1,7 +1,7 @@
/*
* vsp1_rwpf.h -- R-Car VSP1 Read and Write Pixel Formatters
*
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index 0e50b37f060d..622342ac7770 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -1,7 +1,7 @@
/*
* vsp1_uds.c -- R-Car VSP1 Up and Down Scaler
*
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
diff --git a/drivers/media/platform/vsp1/vsp1_uds.h b/drivers/media/platform/vsp1/vsp1_uds.h
index 972a285abdb9..479d12df1180 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.h
+++ b/drivers/media/platform/vsp1/vsp1_uds.h
@@ -1,7 +1,7 @@
/*
* vsp1_uds.h -- R-Car VSP1 Up and Down Scaler
*
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index b4687a834f85..b48f135ffc01 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -1,7 +1,7 @@
/*
* vsp1_video.c -- R-Car VSP1 Video Node
*
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
@@ -1051,7 +1051,7 @@ int vsp1_video_init(struct vsp1_video *video, struct vsp1_entity *rwpf)
video->queue.buf_struct_size = sizeof(struct vsp1_video_buffer);
video->queue.ops = &vsp1_video_queue_qops;
video->queue.mem_ops = &vb2_dma_contig_memops;
- video->queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ video->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(&video->queue);
if (ret < 0) {
dev_err(video->vsp1->dev, "failed to initialize vb2 queue\n");
diff --git a/drivers/media/platform/vsp1/vsp1_video.h b/drivers/media/platform/vsp1/vsp1_video.h
index d8612a378345..53e4b3745940 100644
--- a/drivers/media/platform/vsp1/vsp1_video.h
+++ b/drivers/media/platform/vsp1/vsp1_video.h
@@ -1,7 +1,7 @@
/*
* vsp1_video.h -- R-Car VSP1 Video Node
*
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 7baed81ff005..11a61c601da0 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -1,7 +1,7 @@
/*
* vsp1_wpf.c -- R-Car VSP1 Write Pixel Formatter
*
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 545c04cf7226..d719e59e2179 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -270,6 +270,16 @@ reset_rds:
outb(inb(dev->io + 1) & 0x7f, dev->io + 1);
}
+static bool cadet_has_rds_data(struct cadet *dev)
+{
+ bool result;
+
+ mutex_lock(&dev->lock);
+ result = dev->rdsin != dev->rdsout;
+ mutex_unlock(&dev->lock);
+ return result;
+}
+
static void cadet_handler(unsigned long data)
{
@@ -279,13 +289,12 @@ static void cadet_handler(unsigned long data)
if (mutex_trylock(&dev->lock)) {
outb(0x3, dev->io); /* Select RDS Decoder Control */
if ((inb(dev->io + 1) & 0x20) != 0)
- printk(KERN_CRIT "cadet: RDS fifo overflow\n");
+ pr_err("cadet: RDS fifo overflow\n");
outb(0x80, dev->io); /* Select RDS fifo */
+
while ((inb(dev->io) & 0x80) != 0) {
dev->rdsbuf[dev->rdsin] = inb(dev->io + 1);
- if (dev->rdsin + 1 == dev->rdsout)
- printk(KERN_WARNING "cadet: RDS buffer overflow\n");
- else
+ if (dev->rdsin + 1 != dev->rdsout)
dev->rdsin++;
}
mutex_unlock(&dev->lock);
@@ -294,7 +303,7 @@ static void cadet_handler(unsigned long data)
/*
* Service pending read
*/
- if (dev->rdsin != dev->rdsout)
+ if (cadet_has_rds_data(dev))
wake_up_interruptible(&dev->read_queue);
/*
@@ -327,22 +336,21 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo
mutex_lock(&dev->lock);
if (dev->rdsstat == 0)
cadet_start_rds(dev);
- if (dev->rdsin == dev->rdsout) {
- if (file->f_flags & O_NONBLOCK) {
- i = -EWOULDBLOCK;
- goto unlock;
- }
- mutex_unlock(&dev->lock);
- interruptible_sleep_on(&dev->read_queue);
- mutex_lock(&dev->lock);
- }
+ mutex_unlock(&dev->lock);
+
+ if (!cadet_has_rds_data(dev) && (file->f_flags & O_NONBLOCK))
+ return -EWOULDBLOCK;
+ i = wait_event_interruptible(dev->read_queue, cadet_has_rds_data(dev));
+ if (i)
+ return i;
+
+ mutex_lock(&dev->lock);
while (i < count && dev->rdsin != dev->rdsout)
readbuf[i++] = dev->rdsbuf[dev->rdsout++];
+ mutex_unlock(&dev->lock);
if (i && copy_to_user(data, readbuf, i))
- i = -EFAULT;
-unlock:
- mutex_unlock(&dev->lock);
+ return -EFAULT;
return i;
}
@@ -352,7 +360,7 @@ static int vidioc_querycap(struct file *file, void *priv,
{
strlcpy(v->driver, "ADS Cadet", sizeof(v->driver));
strlcpy(v->card, "ADS Cadet", sizeof(v->card));
- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
+ strlcpy(v->bus_info, "ISA:radio-cadet", sizeof(v->bus_info));
v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE;
v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -491,7 +499,7 @@ static unsigned int cadet_poll(struct file *file, struct poll_table_struct *wait
cadet_start_rds(dev);
mutex_unlock(&dev->lock);
}
- if (dev->rdsin != dev->rdsout)
+ if (cadet_has_rds_data(dev))
res |= POLLIN | POLLRDNORM;
return res;
}
diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c
index fa3964022b96..3d127825eceb 100644
--- a/drivers/media/radio/radio-keene.c
+++ b/drivers/media/radio/radio-keene.c
@@ -416,22 +416,5 @@ static struct usb_driver usb_keene_driver = {
.reset_resume = usb_keene_resume,
};
-static int __init keene_init(void)
-{
- int retval = usb_register(&usb_keene_driver);
-
- if (retval)
- pr_err(KBUILD_MODNAME
- ": usb_register failed. Error number %d\n", retval);
-
- return retval;
-}
-
-static void __exit keene_exit(void)
-{
- usb_deregister(&usb_keene_driver);
-}
-
-module_init(keene_init);
-module_exit(keene_exit);
+module_usb_driver(usb_keene_driver);
diff --git a/drivers/media/radio/si4713/Kconfig b/drivers/media/radio/si4713/Kconfig
index a7c3ba85d12b..9c8b887cff75 100644
--- a/drivers/media/radio/si4713/Kconfig
+++ b/drivers/media/radio/si4713/Kconfig
@@ -1,7 +1,7 @@
config USB_SI4713
tristate "Silicon Labs Si4713 FM Radio Transmitter support with USB"
- depends on USB && RADIO_SI4713
- select SI4713
+ depends on USB && I2C && RADIO_SI4713
+ select I2C_SI4713
---help---
This is a driver for USB devices with the Silicon Labs SI4713
chip. Currently these devices are known to work.
@@ -16,7 +16,7 @@ config USB_SI4713
config PLATFORM_SI4713
tristate "Silicon Labs Si4713 FM Radio Transmitter support with I2C"
depends on I2C && RADIO_SI4713
- select SI4713
+ select I2C_SI4713
---help---
This is a driver for I2C devices with the Silicon Labs SI4713
chip.
diff --git a/drivers/media/radio/si4713/radio-usb-si4713.c b/drivers/media/radio/si4713/radio-usb-si4713.c
index 779855b74bcd..86502b2786d0 100644
--- a/drivers/media/radio/si4713/radio-usb-si4713.c
+++ b/drivers/media/radio/si4713/radio-usb-si4713.c
@@ -223,7 +223,7 @@ struct si4713_start_seq_table {
* (0x03): Get serial number of the board (Response : CB000-00-00)
* (0x06, 0x03, 0x03, 0x08, 0x01, 0x0f) : Get Component revision
*/
-static struct si4713_start_seq_table start_seq[] = {
+static const struct si4713_start_seq_table start_seq[] = {
{ 1, { 0x03 } },
{ 2, { 0x32, 0x7f } },
@@ -261,7 +261,7 @@ static int si4713_start_seq(struct si4713_usb_device *radio)
for (i = 0; i < ARRAY_SIZE(start_seq); i++) {
int len = start_seq[i].len;
- u8 *payload = start_seq[i].payload;
+ const u8 *payload = start_seq[i].payload;
memcpy(radio->buffer + 1, payload, len);
memset(radio->buffer + len + 1, 0, BUFFER_LENGTH - 1 - len);
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 904f11367c29..8fbd377e6311 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -106,6 +106,15 @@ config IR_SANYO_DECODER
uses the Sanyo protocol (Sanyo, Aiwa, Chinon remotes),
and you need software decoding support.
+config IR_SHARP_DECODER
+ tristate "Enable IR raw decoder for the Sharp protocol"
+ depends on RC_CORE
+ default y
+
+ ---help---
+ Enable this option if you have an infrared remote control which
+ uses the Sharp protocol, and you need software decoding support.
+
config IR_MCE_KBD_DECODER
tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol"
depends on RC_CORE
@@ -300,6 +309,8 @@ config IR_RX51
The driver uses omap DM timers for generating the carrier
wave and pulses.
+source "drivers/media/rc/img-ir/Kconfig"
+
config RC_LOOPBACK
tristate "Remote Control Loopback Driver"
depends on RC_CORE
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index f4eb32c0a455..f8b54ff46601 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o
obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o
+obj-$(CONFIG_IR_SHARP_DECODER) += ir-sharp-decoder.o
obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o
obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
@@ -31,3 +32,4 @@ obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o
obj-$(CONFIG_IR_IGUANA) += iguanair.o
obj-$(CONFIG_IR_TTUSBIR) += ttusbir.o
obj-$(CONFIG_RC_ST) += st_rc.o
+obj-$(CONFIG_IR_IMG) += img-ir/
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index 4d6a63fe6c5e..2df7c5516013 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -784,7 +784,7 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote)
rdev->priv = ati_remote;
rdev->driver_type = RC_DRIVER_SCANCODE;
- rdev->allowed_protos = RC_BIT_OTHER;
+ rc_set_allowed_protocols(rdev, RC_BIT_OTHER);
rdev->driver_name = "ati_remote";
rdev->open = ati_remote_rc_open;
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index c1444f84717d..fc9d23f2ed3f 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -1059,7 +1059,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
learning_mode_force = false;
rdev->driver_type = RC_DRIVER_IR_RAW;
- rdev->allowed_protos = RC_BIT_ALL;
+ rc_set_allowed_protocols(rdev, RC_BIT_ALL);
rdev->priv = dev;
rdev->open = ene_open;
rdev->close = ene_close;
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index d6fa441655d2..46b66e59438f 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -541,7 +541,7 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id
/* Set up the rc device */
rdev->priv = fintek;
rdev->driver_type = RC_DRIVER_IR_RAW;
- rdev->allowed_protos = RC_BIT_ALL;
+ rc_set_allowed_protocols(rdev, RC_BIT_ALL);
rdev->open = fintek_open;
rdev->close = fintek_close;
rdev->input_name = FINTEK_DESCRIPTION;
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 80c611c2e8c2..29b5f89813b4 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -145,9 +145,9 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
rcdev->dev.parent = &pdev->dev;
rcdev->driver_name = GPIO_IR_DRIVER_NAME;
if (pdata->allowed_protos)
- rcdev->allowed_protos = pdata->allowed_protos;
+ rc_set_allowed_protocols(rcdev, pdata->allowed_protos);
else
- rcdev->allowed_protos = RC_BIT_ALL;
+ rc_set_allowed_protocols(rcdev, RC_BIT_ALL);
rcdev->map_name = pdata->map_name ?: RC_MAP_EMPTY;
gpio_dev->rcdev = rcdev;
diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
index fdae05c4f377..627ddfd61980 100644
--- a/drivers/media/rc/iguanair.c
+++ b/drivers/media/rc/iguanair.c
@@ -286,10 +286,10 @@ static int iguanair_receiver(struct iguanair *ir, bool enable)
}
/*
- * The iguana ir creates the carrier by busy spinning after each pulse or
- * space. This is counted in CPU cycles, with the CPU running at 24MHz. It is
+ * The iguanair creates the carrier by busy spinning after each half period.
+ * This is counted in CPU cycles, with the CPU running at 24MHz. It is
* broken down into 7-cycles and 4-cyles delays, with a preference for
- * 4-cycle delays.
+ * 4-cycle delays, minus the overhead of the loop itself (cycle_overhead).
*/
static int iguanair_set_tx_carrier(struct rc_dev *dev, uint32_t carrier)
{
@@ -316,7 +316,14 @@ static int iguanair_set_tx_carrier(struct rc_dev *dev, uint32_t carrier)
sevens = (4 - cycles) & 3;
fours = (cycles - sevens * 7) / 4;
- /* magic happens here */
+ /*
+ * The firmware interprets these values as a relative offset
+ * for a branch. Immediately following the branches, there
+ * 4 instructions of 7 cycles (2 bytes each) and 110
+ * instructions of 4 cycles (1 byte each). A relative branch
+ * of 0 will execute all of them, branch further for less
+ * cycle burning.
+ */
ir->packet->busy7 = (4 - sevens) * 2;
ir->packet->busy4 = 110 - fours;
}
@@ -357,20 +364,14 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
rc = -EINVAL;
goto out;
}
- while (periods > 127) {
- ir->packet->payload[size++] = 127 | space;
- periods -= 127;
+ while (periods) {
+ unsigned p = min(periods, 127u);
+ ir->packet->payload[size++] = p | space;
+ periods -= p;
}
-
- ir->packet->payload[size++] = periods | space;
space ^= 0x80;
}
- if (count == 0) {
- rc = -EINVAL;
- goto out;
- }
-
ir->packet->header.start = 0;
ir->packet->header.direction = DIR_OUT;
ir->packet->header.cmd = CMD_SEND;
@@ -494,7 +495,7 @@ static int iguanair_probe(struct usb_interface *intf,
usb_to_input_id(ir->udev, &rc->input_id);
rc->dev.parent = &intf->dev;
rc->driver_type = RC_DRIVER_IR_RAW;
- rc->allowed_protos = RC_BIT_ALL;
+ rc_set_allowed_protocols(rc, RC_BIT_ALL);
rc->priv = ir;
rc->open = iguanair_open;
rc->close = iguanair_close;
diff --git a/drivers/media/rc/img-ir/Kconfig b/drivers/media/rc/img-ir/Kconfig
new file mode 100644
index 000000000000..03ba9fc170fb
--- /dev/null
+++ b/drivers/media/rc/img-ir/Kconfig
@@ -0,0 +1,61 @@
+config IR_IMG
+ tristate "ImgTec IR Decoder"
+ depends on RC_CORE
+ select IR_IMG_HW if !IR_IMG_RAW
+ help
+ Say Y or M here if you want to use the ImgTec infrared decoder
+ functionality found in SoCs such as TZ1090.
+
+config IR_IMG_RAW
+ bool "Raw decoder"
+ depends on IR_IMG
+ help
+ Say Y here to enable the raw mode driver which passes raw IR signal
+ changes to the IR raw decoders for software decoding. This is much
+ less reliable (due to lack of timestamps) and consumes more
+ processing power than using hardware decode, but can be useful for
+ testing, debug, and to make more protocols available.
+
+config IR_IMG_HW
+ bool "Hardware decoder"
+ depends on IR_IMG
+ help
+ Say Y here to enable the hardware decode driver which decodes the IR
+ signals in hardware. This is more reliable, consumes less processing
+ power since only a single interrupt is received for each scancode,
+ and allows an IR scancode to be used as a wake event.
+
+config IR_IMG_NEC
+ bool "NEC protocol support"
+ depends on IR_IMG_HW
+ help
+ Say Y here to enable support for the NEC, extended NEC, and 32-bit
+ NEC protocols in the ImgTec infrared decoder block.
+
+config IR_IMG_JVC
+ bool "JVC protocol support"
+ depends on IR_IMG_HW
+ help
+ Say Y here to enable support for the JVC protocol in the ImgTec
+ infrared decoder block.
+
+config IR_IMG_SONY
+ bool "Sony protocol support"
+ depends on IR_IMG_HW
+ help
+ Say Y here to enable support for the Sony protocol in the ImgTec
+ infrared decoder block.
+
+config IR_IMG_SHARP
+ bool "Sharp protocol support"
+ depends on IR_IMG_HW
+ help
+ Say Y here to enable support for the Sharp protocol in the ImgTec
+ infrared decoder block.
+
+config IR_IMG_SANYO
+ bool "Sanyo protocol support"
+ depends on IR_IMG_HW
+ help
+ Say Y here to enable support for the Sanyo protocol (used by Sanyo,
+ Aiwa, Chinon remotes) in the ImgTec infrared decoder block.
diff --git a/drivers/media/rc/img-ir/Makefile b/drivers/media/rc/img-ir/Makefile
new file mode 100644
index 000000000000..92a459d99509
--- /dev/null
+++ b/drivers/media/rc/img-ir/Makefile
@@ -0,0 +1,11 @@
+img-ir-y := img-ir-core.o
+img-ir-$(CONFIG_IR_IMG_RAW) += img-ir-raw.o
+img-ir-$(CONFIG_IR_IMG_HW) += img-ir-hw.o
+img-ir-$(CONFIG_IR_IMG_NEC) += img-ir-nec.o
+img-ir-$(CONFIG_IR_IMG_JVC) += img-ir-jvc.o
+img-ir-$(CONFIG_IR_IMG_SONY) += img-ir-sony.o
+img-ir-$(CONFIG_IR_IMG_SHARP) += img-ir-sharp.o
+img-ir-$(CONFIG_IR_IMG_SANYO) += img-ir-sanyo.o
+img-ir-objs := $(img-ir-y)
+
+obj-$(CONFIG_IR_IMG) += img-ir.o
diff --git a/drivers/media/rc/img-ir/img-ir-core.c b/drivers/media/rc/img-ir/img-ir-core.c
new file mode 100644
index 000000000000..6b7834834fb8
--- /dev/null
+++ b/drivers/media/rc/img-ir/img-ir-core.c
@@ -0,0 +1,176 @@
+/*
+ * ImgTec IR Decoder found in PowerDown Controller.
+ *
+ * Copyright 2010-2014 Imagination Technologies Ltd.
+ *
+ * This contains core img-ir code for setting up the driver. The two interfaces
+ * (raw and hardware decode) are handled separately.
+ */
+
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include "img-ir.h"
+
+static irqreturn_t img_ir_isr(int irq, void *dev_id)
+{
+ struct img_ir_priv *priv = dev_id;
+ u32 irq_status;
+
+ spin_lock(&priv->lock);
+ /* we have to clear irqs before reading */
+ irq_status = img_ir_read(priv, IMG_IR_IRQ_STATUS);
+ img_ir_write(priv, IMG_IR_IRQ_CLEAR, irq_status);
+
+ /* don't handle valid data irqs if we're only interested in matches */
+ irq_status &= img_ir_read(priv, IMG_IR_IRQ_ENABLE);
+
+ /* hand off edge interrupts to raw decode handler */
+ if (irq_status & IMG_IR_IRQ_EDGE && img_ir_raw_enabled(&priv->raw))
+ img_ir_isr_raw(priv, irq_status);
+
+ /* hand off hardware match interrupts to hardware decode handler */
+ if (irq_status & (IMG_IR_IRQ_DATA_MATCH |
+ IMG_IR_IRQ_DATA_VALID |
+ IMG_IR_IRQ_DATA2_VALID) &&
+ img_ir_hw_enabled(&priv->hw))
+ img_ir_isr_hw(priv, irq_status);
+
+ spin_unlock(&priv->lock);
+ return IRQ_HANDLED;
+}
+
+static void img_ir_setup(struct img_ir_priv *priv)
+{
+ /* start off with interrupts disabled */
+ img_ir_write(priv, IMG_IR_IRQ_ENABLE, 0);
+
+ img_ir_setup_raw(priv);
+ img_ir_setup_hw(priv);
+
+ if (!IS_ERR(priv->clk))
+ clk_prepare_enable(priv->clk);
+}
+
+static void img_ir_ident(struct img_ir_priv *priv)
+{
+ u32 core_rev = img_ir_read(priv, IMG_IR_CORE_REV);
+
+ dev_info(priv->dev,
+ "IMG IR Decoder (%d.%d.%d.%d) probed successfully\n",
+ (core_rev & IMG_IR_DESIGNER) >> IMG_IR_DESIGNER_SHIFT,
+ (core_rev & IMG_IR_MAJOR_REV) >> IMG_IR_MAJOR_REV_SHIFT,
+ (core_rev & IMG_IR_MINOR_REV) >> IMG_IR_MINOR_REV_SHIFT,
+ (core_rev & IMG_IR_MAINT_REV) >> IMG_IR_MAINT_REV_SHIFT);
+ dev_info(priv->dev, "Modes:%s%s\n",
+ img_ir_hw_enabled(&priv->hw) ? " hardware" : "",
+ img_ir_raw_enabled(&priv->raw) ? " raw" : "");
+}
+
+static int img_ir_probe(struct platform_device *pdev)
+{
+ struct img_ir_priv *priv;
+ struct resource *res_regs;
+ int irq, error, error2;
+
+ /* Get resources from platform device */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "cannot find IRQ resource\n");
+ return irq;
+ }
+
+ /* Private driver data */
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&pdev->dev, "cannot allocate device data\n");
+ return -ENOMEM;
+ }
+ platform_set_drvdata(pdev, priv);
+ priv->dev = &pdev->dev;
+ spin_lock_init(&priv->lock);
+
+ /* Ioremap the registers */
+ res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->reg_base = devm_ioremap_resource(&pdev->dev, res_regs);
+ if (IS_ERR(priv->reg_base))
+ return PTR_ERR(priv->reg_base);
+
+ /* Get core clock */
+ priv->clk = devm_clk_get(&pdev->dev, "core");
+ if (IS_ERR(priv->clk))
+ dev_warn(&pdev->dev, "cannot get core clock resource\n");
+ /*
+ * The driver doesn't need to know about the system ("sys") or power
+ * modulation ("mod") clocks yet
+ */
+
+ /* Set up raw & hw decoder */
+ error = img_ir_probe_raw(priv);
+ error2 = img_ir_probe_hw(priv);
+ if (error && error2)
+ return (error == -ENODEV) ? error2 : error;
+
+ /* Get the IRQ */
+ priv->irq = irq;
+ error = request_irq(priv->irq, img_ir_isr, 0, "img-ir", priv);
+ if (error) {
+ dev_err(&pdev->dev, "cannot register IRQ %u\n",
+ priv->irq);
+ error = -EIO;
+ goto err_irq;
+ }
+
+ img_ir_ident(priv);
+ img_ir_setup(priv);
+
+ return 0;
+
+err_irq:
+ img_ir_remove_hw(priv);
+ img_ir_remove_raw(priv);
+ return error;
+}
+
+static int img_ir_remove(struct platform_device *pdev)
+{
+ struct img_ir_priv *priv = platform_get_drvdata(pdev);
+
+ free_irq(priv->irq, img_ir_isr);
+ img_ir_remove_hw(priv);
+ img_ir_remove_raw(priv);
+
+ if (!IS_ERR(priv->clk))
+ clk_disable_unprepare(priv->clk);
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(img_ir_pmops, img_ir_suspend, img_ir_resume);
+
+static const struct of_device_id img_ir_match[] = {
+ { .compatible = "img,ir-rev1" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, img_ir_match);
+
+static struct platform_driver img_ir_driver = {
+ .driver = {
+ .name = "img-ir",
+ .owner = THIS_MODULE,
+ .of_match_table = img_ir_match,
+ .pm = &img_ir_pmops,
+ },
+ .probe = img_ir_probe,
+ .remove = img_ir_remove,
+};
+
+module_platform_driver(img_ir_driver);
+
+MODULE_AUTHOR("Imagination Technologies Ltd.");
+MODULE_DESCRIPTION("ImgTec IR");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c
new file mode 100644
index 000000000000..579a52b3edce
--- /dev/null
+++ b/drivers/media/rc/img-ir/img-ir-hw.c
@@ -0,0 +1,1053 @@
+/*
+ * ImgTec IR Hardware Decoder found in PowerDown Controller.
+ *
+ * Copyright 2010-2014 Imagination Technologies Ltd.
+ *
+ * This ties into the input subsystem using the RC-core. Protocol support is
+ * provided in separate modules which provide the parameters and scancode
+ * translation functions to set up the hardware decoder and interpret the
+ * resulting input.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <media/rc-core.h>
+#include "img-ir.h"
+
+/* Decoders lock (only modified to preprocess them) */
+static DEFINE_SPINLOCK(img_ir_decoders_lock);
+
+extern struct img_ir_decoder img_ir_nec;
+extern struct img_ir_decoder img_ir_jvc;
+extern struct img_ir_decoder img_ir_sony;
+extern struct img_ir_decoder img_ir_sharp;
+extern struct img_ir_decoder img_ir_sanyo;
+
+static bool img_ir_decoders_preprocessed;
+static struct img_ir_decoder *img_ir_decoders[] = {
+#ifdef CONFIG_IR_IMG_NEC
+ &img_ir_nec,
+#endif
+#ifdef CONFIG_IR_IMG_JVC
+ &img_ir_jvc,
+#endif
+#ifdef CONFIG_IR_IMG_SONY
+ &img_ir_sony,
+#endif
+#ifdef CONFIG_IR_IMG_SHARP
+ &img_ir_sharp,
+#endif
+#ifdef CONFIG_IR_IMG_SANYO
+ &img_ir_sanyo,
+#endif
+ NULL
+};
+
+#define IMG_IR_F_FILTER BIT(RC_FILTER_NORMAL) /* enable filtering */
+#define IMG_IR_F_WAKE BIT(RC_FILTER_WAKEUP) /* enable waking */
+
+/* code type quirks */
+
+#define IMG_IR_QUIRK_CODE_BROKEN 0x1 /* Decode is broken */
+#define IMG_IR_QUIRK_CODE_LEN_INCR 0x2 /* Bit length needs increment */
+
+/* functions for preprocessing timings, ensuring max is set */
+
+static void img_ir_timing_preprocess(struct img_ir_timing_range *range,
+ unsigned int unit)
+{
+ if (range->max < range->min)
+ range->max = range->min;
+ if (unit) {
+ /* multiply by unit and convert to microseconds */
+ range->min = (range->min*unit)/1000;
+ range->max = (range->max*unit + 999)/1000; /* round up */
+ }
+}
+
+static void img_ir_symbol_timing_preprocess(struct img_ir_symbol_timing *timing,
+ unsigned int unit)
+{
+ img_ir_timing_preprocess(&timing->pulse, unit);
+ img_ir_timing_preprocess(&timing->space, unit);
+}
+
+static void img_ir_timings_preprocess(struct img_ir_timings *timings,
+ unsigned int unit)
+{
+ img_ir_symbol_timing_preprocess(&timings->ldr, unit);
+ img_ir_symbol_timing_preprocess(&timings->s00, unit);
+ img_ir_symbol_timing_preprocess(&timings->s01, unit);
+ img_ir_symbol_timing_preprocess(&timings->s10, unit);
+ img_ir_symbol_timing_preprocess(&timings->s11, unit);
+ /* default s10 and s11 to s00 and s01 if no leader */
+ if (unit)
+ /* multiply by unit and convert to microseconds (round up) */
+ timings->ft.ft_min = (timings->ft.ft_min*unit + 999)/1000;
+}
+
+/* functions for filling empty fields with defaults */
+
+static void img_ir_timing_defaults(struct img_ir_timing_range *range,
+ struct img_ir_timing_range *defaults)
+{
+ if (!range->min)
+ range->min = defaults->min;
+ if (!range->max)
+ range->max = defaults->max;
+}
+
+static void img_ir_symbol_timing_defaults(struct img_ir_symbol_timing *timing,
+ struct img_ir_symbol_timing *defaults)
+{
+ img_ir_timing_defaults(&timing->pulse, &defaults->pulse);
+ img_ir_timing_defaults(&timing->space, &defaults->space);
+}
+
+static void img_ir_timings_defaults(struct img_ir_timings *timings,
+ struct img_ir_timings *defaults)
+{
+ img_ir_symbol_timing_defaults(&timings->ldr, &defaults->ldr);
+ img_ir_symbol_timing_defaults(&timings->s00, &defaults->s00);
+ img_ir_symbol_timing_defaults(&timings->s01, &defaults->s01);
+ img_ir_symbol_timing_defaults(&timings->s10, &defaults->s10);
+ img_ir_symbol_timing_defaults(&timings->s11, &defaults->s11);
+ if (!timings->ft.ft_min)
+ timings->ft.ft_min = defaults->ft.ft_min;
+}
+
+/* functions for converting timings to register values */
+
+/**
+ * img_ir_control() - Convert control struct to control register value.
+ * @control: Control data
+ *
+ * Returns: The control register value equivalent of @control.
+ */
+static u32 img_ir_control(const struct img_ir_control *control)
+{
+ u32 ctrl = control->code_type << IMG_IR_CODETYPE_SHIFT;
+ if (control->decoden)
+ ctrl |= IMG_IR_DECODEN;
+ if (control->hdrtog)
+ ctrl |= IMG_IR_HDRTOG;
+ if (control->ldrdec)
+ ctrl |= IMG_IR_LDRDEC;
+ if (control->decodinpol)
+ ctrl |= IMG_IR_DECODINPOL;
+ if (control->bitorien)
+ ctrl |= IMG_IR_BITORIEN;
+ if (control->d1validsel)
+ ctrl |= IMG_IR_D1VALIDSEL;
+ if (control->bitinv)
+ ctrl |= IMG_IR_BITINV;
+ if (control->decodend2)
+ ctrl |= IMG_IR_DECODEND2;
+ if (control->bitoriend2)
+ ctrl |= IMG_IR_BITORIEND2;
+ if (control->bitinvd2)
+ ctrl |= IMG_IR_BITINVD2;
+ return ctrl;
+}
+
+/**
+ * img_ir_timing_range_convert() - Convert microsecond range.
+ * @out: Output timing range in clock cycles with a shift.
+ * @in: Input timing range in microseconds.
+ * @tolerance: Tolerance as a fraction of 128 (roughly percent).
+ * @clock_hz: IR clock rate in Hz.
+ * @shift: Shift of output units.
+ *
+ * Converts min and max from microseconds to IR clock cycles, applies a
+ * tolerance, and shifts for the register, rounding in the right direction.
+ * Note that in and out can safely be the same object.
+ */
+static void img_ir_timing_range_convert(struct img_ir_timing_range *out,
+ const struct img_ir_timing_range *in,
+ unsigned int tolerance,
+ unsigned long clock_hz,
+ unsigned int shift)
+{
+ unsigned int min = in->min;
+ unsigned int max = in->max;
+ /* add a tolerance */
+ min = min - (min*tolerance >> 7);
+ max = max + (max*tolerance >> 7);
+ /* convert from microseconds into clock cycles */
+ min = min*clock_hz / 1000000;
+ max = (max*clock_hz + 999999) / 1000000; /* round up */
+ /* apply shift and copy to output */
+ out->min = min >> shift;
+ out->max = (max + ((1 << shift) - 1)) >> shift; /* round up */
+}
+
+/**
+ * img_ir_symbol_timing() - Convert symbol timing struct to register value.
+ * @timing: Symbol timing data
+ * @tolerance: Timing tolerance where 0-128 represents 0-100%
+ * @clock_hz: Frequency of source clock in Hz
+ * @pd_shift: Shift to apply to symbol period
+ * @w_shift: Shift to apply to symbol width
+ *
+ * Returns: Symbol timing register value based on arguments.
+ */
+static u32 img_ir_symbol_timing(const struct img_ir_symbol_timing *timing,
+ unsigned int tolerance,
+ unsigned long clock_hz,
+ unsigned int pd_shift,
+ unsigned int w_shift)
+{
+ struct img_ir_timing_range hw_pulse, hw_period;
+ /* we calculate period in hw_period, then convert in place */
+ hw_period.min = timing->pulse.min + timing->space.min;
+ hw_period.max = timing->pulse.max + timing->space.max;
+ img_ir_timing_range_convert(&hw_period, &hw_period,
+ tolerance, clock_hz, pd_shift);
+ img_ir_timing_range_convert(&hw_pulse, &timing->pulse,
+ tolerance, clock_hz, w_shift);
+ /* construct register value */
+ return (hw_period.max << IMG_IR_PD_MAX_SHIFT) |
+ (hw_period.min << IMG_IR_PD_MIN_SHIFT) |
+ (hw_pulse.max << IMG_IR_W_MAX_SHIFT) |
+ (hw_pulse.min << IMG_IR_W_MIN_SHIFT);
+}
+
+/**
+ * img_ir_free_timing() - Convert free time timing struct to register value.
+ * @timing: Free symbol timing data
+ * @clock_hz: Source clock frequency in Hz
+ *
+ * Returns: Free symbol timing register value.
+ */
+static u32 img_ir_free_timing(const struct img_ir_free_timing *timing,
+ unsigned long clock_hz)
+{
+ unsigned int minlen, maxlen, ft_min;
+ /* minlen is only 5 bits, and round minlen to multiple of 2 */
+ if (timing->minlen < 30)
+ minlen = timing->minlen & -2;
+ else
+ minlen = 30;
+ /* maxlen has maximum value of 48, and round maxlen to multiple of 2 */
+ if (timing->maxlen < 48)
+ maxlen = (timing->maxlen + 1) & -2;
+ else
+ maxlen = 48;
+ /* convert and shift ft_min, rounding upwards */
+ ft_min = (timing->ft_min*clock_hz + 999999) / 1000000;
+ ft_min = (ft_min + 7) >> 3;
+ /* construct register value */
+ return (maxlen << IMG_IR_MAXLEN_SHIFT) |
+ (minlen << IMG_IR_MINLEN_SHIFT) |
+ (ft_min << IMG_IR_FT_MIN_SHIFT);
+}
+
+/**
+ * img_ir_free_timing_dynamic() - Update free time register value.
+ * @st_ft: Static free time register value from img_ir_free_timing.
+ * @filter: Current filter which may additionally restrict min/max len.
+ *
+ * Returns: Updated free time register value based on the current filter.
+ */
+static u32 img_ir_free_timing_dynamic(u32 st_ft, struct img_ir_filter *filter)
+{
+ unsigned int minlen, maxlen, newminlen, newmaxlen;
+
+ /* round minlen, maxlen to multiple of 2 */
+ newminlen = filter->minlen & -2;
+ newmaxlen = (filter->maxlen + 1) & -2;
+ /* extract min/max len from register */
+ minlen = (st_ft & IMG_IR_MINLEN) >> IMG_IR_MINLEN_SHIFT;
+ maxlen = (st_ft & IMG_IR_MAXLEN) >> IMG_IR_MAXLEN_SHIFT;
+ /* if the new values are more restrictive, update the register value */
+ if (newminlen > minlen) {
+ st_ft &= ~IMG_IR_MINLEN;
+ st_ft |= newminlen << IMG_IR_MINLEN_SHIFT;
+ }
+ if (newmaxlen < maxlen) {
+ st_ft &= ~IMG_IR_MAXLEN;
+ st_ft |= newmaxlen << IMG_IR_MAXLEN_SHIFT;
+ }
+ return st_ft;
+}
+
+/**
+ * img_ir_timings_convert() - Convert timings to register values
+ * @regs: Output timing register values
+ * @timings: Input timing data
+ * @tolerance: Timing tolerance where 0-128 represents 0-100%
+ * @clock_hz: Source clock frequency in Hz
+ */
+static void img_ir_timings_convert(struct img_ir_timing_regvals *regs,
+ const struct img_ir_timings *timings,
+ unsigned int tolerance,
+ unsigned int clock_hz)
+{
+ /* leader symbol timings are divided by 16 */
+ regs->ldr = img_ir_symbol_timing(&timings->ldr, tolerance, clock_hz,
+ 4, 4);
+ /* other symbol timings, pd fields only are divided by 2 */
+ regs->s00 = img_ir_symbol_timing(&timings->s00, tolerance, clock_hz,
+ 1, 0);
+ regs->s01 = img_ir_symbol_timing(&timings->s01, tolerance, clock_hz,
+ 1, 0);
+ regs->s10 = img_ir_symbol_timing(&timings->s10, tolerance, clock_hz,
+ 1, 0);
+ regs->s11 = img_ir_symbol_timing(&timings->s11, tolerance, clock_hz,
+ 1, 0);
+ regs->ft = img_ir_free_timing(&timings->ft, clock_hz);
+}
+
+/**
+ * img_ir_decoder_preprocess() - Preprocess timings in decoder.
+ * @decoder: Decoder to be preprocessed.
+ *
+ * Ensures that the symbol timing ranges are valid with respect to ordering, and
+ * does some fixed conversion on them.
+ */
+static void img_ir_decoder_preprocess(struct img_ir_decoder *decoder)
+{
+ /* default tolerance */
+ if (!decoder->tolerance)
+ decoder->tolerance = 10; /* percent */
+ /* and convert tolerance to fraction out of 128 */
+ decoder->tolerance = decoder->tolerance * 128 / 100;
+
+ /* fill in implicit fields */
+ img_ir_timings_preprocess(&decoder->timings, decoder->unit);
+
+ /* do the same for repeat timings if applicable */
+ if (decoder->repeat) {
+ img_ir_timings_preprocess(&decoder->rtimings, decoder->unit);
+ img_ir_timings_defaults(&decoder->rtimings, &decoder->timings);
+ }
+}
+
+/**
+ * img_ir_decoder_convert() - Generate internal timings in decoder.
+ * @decoder: Decoder to be converted to internal timings.
+ * @timings: Timing register values.
+ * @clock_hz: IR clock rate in Hz.
+ *
+ * Fills out the repeat timings and timing register values for a specific clock
+ * rate.
+ */
+static void img_ir_decoder_convert(const struct img_ir_decoder *decoder,
+ struct img_ir_reg_timings *reg_timings,
+ unsigned int clock_hz)
+{
+ /* calculate control value */
+ reg_timings->ctrl = img_ir_control(&decoder->control);
+
+ /* fill in implicit fields and calculate register values */
+ img_ir_timings_convert(&reg_timings->timings, &decoder->timings,
+ decoder->tolerance, clock_hz);
+
+ /* do the same for repeat timings if applicable */
+ if (decoder->repeat)
+ img_ir_timings_convert(&reg_timings->rtimings,
+ &decoder->rtimings, decoder->tolerance,
+ clock_hz);
+}
+
+/**
+ * img_ir_write_timings() - Write timings to the hardware now
+ * @priv: IR private data
+ * @regs: Timing register values to write
+ * @type: RC filter type (RC_FILTER_*)
+ *
+ * Write timing register values @regs to the hardware, taking into account the
+ * current filter which may impose restrictions on the length of the expected
+ * data.
+ */
+static void img_ir_write_timings(struct img_ir_priv *priv,
+ struct img_ir_timing_regvals *regs,
+ enum rc_filter_type type)
+{
+ struct img_ir_priv_hw *hw = &priv->hw;
+
+ /* filter may be more restrictive to minlen, maxlen */
+ u32 ft = regs->ft;
+ if (hw->flags & BIT(type))
+ ft = img_ir_free_timing_dynamic(regs->ft, &hw->filters[type]);
+ /* write to registers */
+ img_ir_write(priv, IMG_IR_LEAD_SYMB_TIMING, regs->ldr);
+ img_ir_write(priv, IMG_IR_S00_SYMB_TIMING, regs->s00);
+ img_ir_write(priv, IMG_IR_S01_SYMB_TIMING, regs->s01);
+ img_ir_write(priv, IMG_IR_S10_SYMB_TIMING, regs->s10);
+ img_ir_write(priv, IMG_IR_S11_SYMB_TIMING, regs->s11);
+ img_ir_write(priv, IMG_IR_FREE_SYMB_TIMING, ft);
+ dev_dbg(priv->dev, "timings: ldr=%#x, s=[%#x, %#x, %#x, %#x], ft=%#x\n",
+ regs->ldr, regs->s00, regs->s01, regs->s10, regs->s11, ft);
+}
+
+static void img_ir_write_filter(struct img_ir_priv *priv,
+ struct img_ir_filter *filter)
+{
+ if (filter) {
+ dev_dbg(priv->dev, "IR filter=%016llx & %016llx\n",
+ (unsigned long long)filter->data,
+ (unsigned long long)filter->mask);
+ img_ir_write(priv, IMG_IR_IRQ_MSG_DATA_LW, (u32)filter->data);
+ img_ir_write(priv, IMG_IR_IRQ_MSG_DATA_UP, (u32)(filter->data
+ >> 32));
+ img_ir_write(priv, IMG_IR_IRQ_MSG_MASK_LW, (u32)filter->mask);
+ img_ir_write(priv, IMG_IR_IRQ_MSG_MASK_UP, (u32)(filter->mask
+ >> 32));
+ } else {
+ dev_dbg(priv->dev, "IR clearing filter\n");
+ img_ir_write(priv, IMG_IR_IRQ_MSG_MASK_LW, 0);
+ img_ir_write(priv, IMG_IR_IRQ_MSG_MASK_UP, 0);
+ }
+}
+
+/* caller must have lock */
+static void _img_ir_set_filter(struct img_ir_priv *priv,
+ struct img_ir_filter *filter)
+{
+ struct img_ir_priv_hw *hw = &priv->hw;
+ u32 irq_en, irq_on;
+
+ irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE);
+ if (filter) {
+ /* Only use the match interrupt */
+ hw->filters[RC_FILTER_NORMAL] = *filter;
+ hw->flags |= IMG_IR_F_FILTER;
+ irq_on = IMG_IR_IRQ_DATA_MATCH;
+ irq_en &= ~(IMG_IR_IRQ_DATA_VALID | IMG_IR_IRQ_DATA2_VALID);
+ } else {
+ /* Only use the valid interrupt */
+ hw->flags &= ~IMG_IR_F_FILTER;
+ irq_en &= ~IMG_IR_IRQ_DATA_MATCH;
+ irq_on = IMG_IR_IRQ_DATA_VALID | IMG_IR_IRQ_DATA2_VALID;
+ }
+ irq_en |= irq_on;
+
+ img_ir_write_filter(priv, filter);
+ /* clear any interrupts we're enabling so we don't handle old ones */
+ img_ir_write(priv, IMG_IR_IRQ_CLEAR, irq_on);
+ img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en);
+}
+
+/* caller must have lock */
+static void _img_ir_set_wake_filter(struct img_ir_priv *priv,
+ struct img_ir_filter *filter)
+{
+ struct img_ir_priv_hw *hw = &priv->hw;
+ if (filter) {
+ /* Enable wake, and copy filter for later */
+ hw->filters[RC_FILTER_WAKEUP] = *filter;
+ hw->flags |= IMG_IR_F_WAKE;
+ } else {
+ /* Disable wake */
+ hw->flags &= ~IMG_IR_F_WAKE;
+ }
+}
+
+/* Callback for setting scancode filter */
+static int img_ir_set_filter(struct rc_dev *dev, enum rc_filter_type type,
+ struct rc_scancode_filter *sc_filter)
+{
+ struct img_ir_priv *priv = dev->priv;
+ struct img_ir_priv_hw *hw = &priv->hw;
+ struct img_ir_filter filter, *filter_ptr = &filter;
+ int ret = 0;
+
+ dev_dbg(priv->dev, "IR scancode %sfilter=%08x & %08x\n",
+ type == RC_FILTER_WAKEUP ? "wake " : "",
+ sc_filter->data,
+ sc_filter->mask);
+
+ spin_lock_irq(&priv->lock);
+
+ /* filtering can always be disabled */
+ if (!sc_filter->mask) {
+ filter_ptr = NULL;
+ goto set_unlock;
+ }
+
+ /* current decoder must support scancode filtering */
+ if (!hw->decoder || !hw->decoder->filter) {
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ /* convert scancode filter to raw filter */
+ filter.minlen = 0;
+ filter.maxlen = ~0;
+ ret = hw->decoder->filter(sc_filter, &filter, hw->enabled_protocols);
+ if (ret)
+ goto unlock;
+ dev_dbg(priv->dev, "IR raw %sfilter=%016llx & %016llx\n",
+ type == RC_FILTER_WAKEUP ? "wake " : "",
+ (unsigned long long)filter.data,
+ (unsigned long long)filter.mask);
+
+set_unlock:
+ /* apply raw filters */
+ switch (type) {
+ case RC_FILTER_NORMAL:
+ _img_ir_set_filter(priv, filter_ptr);
+ break;
+ case RC_FILTER_WAKEUP:
+ _img_ir_set_wake_filter(priv, filter_ptr);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+unlock:
+ spin_unlock_irq(&priv->lock);
+ return ret;
+}
+
+/**
+ * img_ir_set_decoder() - Set the current decoder.
+ * @priv: IR private data.
+ * @decoder: Decoder to use with immediate effect.
+ * @proto: Protocol bitmap (or 0 to use decoder->type).
+ */
+static void img_ir_set_decoder(struct img_ir_priv *priv,
+ const struct img_ir_decoder *decoder,
+ u64 proto)
+{
+ struct img_ir_priv_hw *hw = &priv->hw;
+ struct rc_dev *rdev = hw->rdev;
+ u32 ir_status, irq_en;
+ spin_lock_irq(&priv->lock);
+
+ /* switch off and disable interrupts */
+ img_ir_write(priv, IMG_IR_CONTROL, 0);
+ irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE);
+ img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en & IMG_IR_IRQ_EDGE);
+ img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_ALL & ~IMG_IR_IRQ_EDGE);
+
+ /* ack any data already detected */
+ ir_status = img_ir_read(priv, IMG_IR_STATUS);
+ if (ir_status & (IMG_IR_RXDVAL | IMG_IR_RXDVALD2)) {
+ ir_status &= ~(IMG_IR_RXDVAL | IMG_IR_RXDVALD2);
+ img_ir_write(priv, IMG_IR_STATUS, ir_status);
+ img_ir_read(priv, IMG_IR_DATA_LW);
+ img_ir_read(priv, IMG_IR_DATA_UP);
+ }
+
+ /* stop the end timer and switch back to normal mode */
+ del_timer_sync(&hw->end_timer);
+ hw->mode = IMG_IR_M_NORMAL;
+
+ /* clear the wakeup scancode filter */
+ rdev->scancode_filters[RC_FILTER_WAKEUP].data = 0;
+ rdev->scancode_filters[RC_FILTER_WAKEUP].mask = 0;
+
+ /* clear raw filters */
+ _img_ir_set_filter(priv, NULL);
+ _img_ir_set_wake_filter(priv, NULL);
+
+ /* clear the enabled protocols */
+ hw->enabled_protocols = 0;
+
+ /* switch decoder */
+ hw->decoder = decoder;
+ if (!decoder)
+ goto unlock;
+
+ /* set the enabled protocols */
+ if (!proto)
+ proto = decoder->type;
+ hw->enabled_protocols = proto;
+
+ /* write the new timings */
+ img_ir_decoder_convert(decoder, &hw->reg_timings, hw->clk_hz);
+ img_ir_write_timings(priv, &hw->reg_timings.timings, RC_FILTER_NORMAL);
+
+ /* set up and enable */
+ img_ir_write(priv, IMG_IR_CONTROL, hw->reg_timings.ctrl);
+
+
+unlock:
+ spin_unlock_irq(&priv->lock);
+}
+
+/**
+ * img_ir_decoder_compatable() - Find whether a decoder will work with a device.
+ * @priv: IR private data.
+ * @dec: Decoder to check.
+ *
+ * Returns: true if @dec is compatible with the device @priv refers to.
+ */
+static bool img_ir_decoder_compatible(struct img_ir_priv *priv,
+ const struct img_ir_decoder *dec)
+{
+ unsigned int ct;
+
+ /* don't accept decoders using code types which aren't supported */
+ ct = dec->control.code_type;
+ if (priv->hw.ct_quirks[ct] & IMG_IR_QUIRK_CODE_BROKEN)
+ return false;
+
+ return true;
+}
+
+/**
+ * img_ir_allowed_protos() - Get allowed protocols from global decoder list.
+ * @priv: IR private data.
+ *
+ * Returns: Mask of protocols supported by the device @priv refers to.
+ */
+static u64 img_ir_allowed_protos(struct img_ir_priv *priv)
+{
+ u64 protos = 0;
+ struct img_ir_decoder **decp;
+
+ for (decp = img_ir_decoders; *decp; ++decp) {
+ const struct img_ir_decoder *dec = *decp;
+ if (img_ir_decoder_compatible(priv, dec))
+ protos |= dec->type;
+ }
+ return protos;
+}
+
+/* Callback for changing protocol using sysfs */
+static int img_ir_change_protocol(struct rc_dev *dev, u64 *ir_type)
+{
+ struct img_ir_priv *priv = dev->priv;
+ struct img_ir_priv_hw *hw = &priv->hw;
+ struct rc_dev *rdev = hw->rdev;
+ struct img_ir_decoder **decp;
+ u64 wakeup_protocols;
+
+ if (!*ir_type) {
+ /* disable all protocols */
+ img_ir_set_decoder(priv, NULL, 0);
+ goto success;
+ }
+ for (decp = img_ir_decoders; *decp; ++decp) {
+ const struct img_ir_decoder *dec = *decp;
+ if (!img_ir_decoder_compatible(priv, dec))
+ continue;
+ if (*ir_type & dec->type) {
+ *ir_type &= dec->type;
+ img_ir_set_decoder(priv, dec, *ir_type);
+ goto success;
+ }
+ }
+ return -EINVAL;
+
+success:
+ /*
+ * Only allow matching wakeup protocols for now, and only if filtering
+ * is supported.
+ */
+ wakeup_protocols = *ir_type;
+ if (!hw->decoder || !hw->decoder->filter)
+ wakeup_protocols = 0;
+ rc_set_allowed_wakeup_protocols(rdev, wakeup_protocols);
+ rc_set_enabled_wakeup_protocols(rdev, wakeup_protocols);
+ return 0;
+}
+
+/* Changes ir-core protocol device attribute */
+static void img_ir_set_protocol(struct img_ir_priv *priv, u64 proto)
+{
+ struct rc_dev *rdev = priv->hw.rdev;
+
+ spin_lock_irq(&rdev->rc_map.lock);
+ rdev->rc_map.rc_type = __ffs64(proto);
+ spin_unlock_irq(&rdev->rc_map.lock);
+
+ mutex_lock(&rdev->lock);
+ rc_set_enabled_protocols(rdev, proto);
+ rc_set_allowed_wakeup_protocols(rdev, proto);
+ rc_set_enabled_wakeup_protocols(rdev, proto);
+ mutex_unlock(&rdev->lock);
+}
+
+/* Set up IR decoders */
+static void img_ir_init_decoders(void)
+{
+ struct img_ir_decoder **decp;
+
+ spin_lock(&img_ir_decoders_lock);
+ if (!img_ir_decoders_preprocessed) {
+ for (decp = img_ir_decoders; *decp; ++decp)
+ img_ir_decoder_preprocess(*decp);
+ img_ir_decoders_preprocessed = true;
+ }
+ spin_unlock(&img_ir_decoders_lock);
+}
+
+#ifdef CONFIG_PM_SLEEP
+/**
+ * img_ir_enable_wake() - Switch to wake mode.
+ * @priv: IR private data.
+ *
+ * Returns: non-zero if the IR can wake the system.
+ */
+static int img_ir_enable_wake(struct img_ir_priv *priv)
+{
+ struct img_ir_priv_hw *hw = &priv->hw;
+ int ret = 0;
+
+ spin_lock_irq(&priv->lock);
+ if (hw->flags & IMG_IR_F_WAKE) {
+ /* interrupt only on a match */
+ hw->suspend_irqen = img_ir_read(priv, IMG_IR_IRQ_ENABLE);
+ img_ir_write(priv, IMG_IR_IRQ_ENABLE, IMG_IR_IRQ_DATA_MATCH);
+ img_ir_write_filter(priv, &hw->filters[RC_FILTER_WAKEUP]);
+ img_ir_write_timings(priv, &hw->reg_timings.timings,
+ RC_FILTER_WAKEUP);
+ hw->mode = IMG_IR_M_WAKE;
+ ret = 1;
+ }
+ spin_unlock_irq(&priv->lock);
+ return ret;
+}
+
+/**
+ * img_ir_disable_wake() - Switch out of wake mode.
+ * @priv: IR private data
+ *
+ * Returns: 1 if the hardware should be allowed to wake from a sleep state.
+ * 0 otherwise.
+ */
+static int img_ir_disable_wake(struct img_ir_priv *priv)
+{
+ struct img_ir_priv_hw *hw = &priv->hw;
+ int ret = 0;
+
+ spin_lock_irq(&priv->lock);
+ if (hw->flags & IMG_IR_F_WAKE) {
+ /* restore normal filtering */
+ if (hw->flags & IMG_IR_F_FILTER) {
+ img_ir_write(priv, IMG_IR_IRQ_ENABLE,
+ (hw->suspend_irqen & IMG_IR_IRQ_EDGE) |
+ IMG_IR_IRQ_DATA_MATCH);
+ img_ir_write_filter(priv,
+ &hw->filters[RC_FILTER_NORMAL]);
+ } else {
+ img_ir_write(priv, IMG_IR_IRQ_ENABLE,
+ (hw->suspend_irqen & IMG_IR_IRQ_EDGE) |
+ IMG_IR_IRQ_DATA_VALID |
+ IMG_IR_IRQ_DATA2_VALID);
+ img_ir_write_filter(priv, NULL);
+ }
+ img_ir_write_timings(priv, &hw->reg_timings.timings,
+ RC_FILTER_NORMAL);
+ hw->mode = IMG_IR_M_NORMAL;
+ ret = 1;
+ }
+ spin_unlock_irq(&priv->lock);
+ return ret;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+/* lock must be held */
+static void img_ir_begin_repeat(struct img_ir_priv *priv)
+{
+ struct img_ir_priv_hw *hw = &priv->hw;
+ if (hw->mode == IMG_IR_M_NORMAL) {
+ /* switch to repeat timings */
+ img_ir_write(priv, IMG_IR_CONTROL, 0);
+ hw->mode = IMG_IR_M_REPEATING;
+ img_ir_write_timings(priv, &hw->reg_timings.rtimings,
+ RC_FILTER_NORMAL);
+ img_ir_write(priv, IMG_IR_CONTROL, hw->reg_timings.ctrl);
+ }
+}
+
+/* lock must be held */
+static void img_ir_end_repeat(struct img_ir_priv *priv)
+{
+ struct img_ir_priv_hw *hw = &priv->hw;
+ if (hw->mode == IMG_IR_M_REPEATING) {
+ /* switch to normal timings */
+ img_ir_write(priv, IMG_IR_CONTROL, 0);
+ hw->mode = IMG_IR_M_NORMAL;
+ img_ir_write_timings(priv, &hw->reg_timings.timings,
+ RC_FILTER_NORMAL);
+ img_ir_write(priv, IMG_IR_CONTROL, hw->reg_timings.ctrl);
+ }
+}
+
+/* lock must be held */
+static void img_ir_handle_data(struct img_ir_priv *priv, u32 len, u64 raw)
+{
+ struct img_ir_priv_hw *hw = &priv->hw;
+ const struct img_ir_decoder *dec = hw->decoder;
+ int ret = IMG_IR_SCANCODE;
+ int scancode;
+ if (dec->scancode)
+ ret = dec->scancode(len, raw, &scancode, hw->enabled_protocols);
+ else if (len >= 32)
+ scancode = (u32)raw;
+ else if (len < 32)
+ scancode = (u32)raw & ((1 << len)-1);
+ dev_dbg(priv->dev, "data (%u bits) = %#llx\n",
+ len, (unsigned long long)raw);
+ if (ret == IMG_IR_SCANCODE) {
+ dev_dbg(priv->dev, "decoded scan code %#x\n", scancode);
+ rc_keydown(hw->rdev, scancode, 0);
+ img_ir_end_repeat(priv);
+ } else if (ret == IMG_IR_REPEATCODE) {
+ if (hw->mode == IMG_IR_M_REPEATING) {
+ dev_dbg(priv->dev, "decoded repeat code\n");
+ rc_repeat(hw->rdev);
+ } else {
+ dev_dbg(priv->dev, "decoded unexpected repeat code, ignoring\n");
+ }
+ } else {
+ dev_dbg(priv->dev, "decode failed (%d)\n", ret);
+ return;
+ }
+
+
+ if (dec->repeat) {
+ unsigned long interval;
+
+ img_ir_begin_repeat(priv);
+
+ /* update timer, but allowing for 1/8th tolerance */
+ interval = dec->repeat + (dec->repeat >> 3);
+ mod_timer(&hw->end_timer,
+ jiffies + msecs_to_jiffies(interval));
+ }
+}
+
+/* timer function to end waiting for repeat. */
+static void img_ir_end_timer(unsigned long arg)
+{
+ struct img_ir_priv *priv = (struct img_ir_priv *)arg;
+
+ spin_lock_irq(&priv->lock);
+ img_ir_end_repeat(priv);
+ spin_unlock_irq(&priv->lock);
+}
+
+#ifdef CONFIG_COMMON_CLK
+static void img_ir_change_frequency(struct img_ir_priv *priv,
+ struct clk_notifier_data *change)
+{
+ struct img_ir_priv_hw *hw = &priv->hw;
+
+ dev_dbg(priv->dev, "clk changed %lu HZ -> %lu HZ\n",
+ change->old_rate, change->new_rate);
+
+ spin_lock_irq(&priv->lock);
+ if (hw->clk_hz == change->new_rate)
+ goto unlock;
+ hw->clk_hz = change->new_rate;
+ /* refresh current timings */
+ if (hw->decoder) {
+ img_ir_decoder_convert(hw->decoder, &hw->reg_timings,
+ hw->clk_hz);
+ switch (hw->mode) {
+ case IMG_IR_M_NORMAL:
+ img_ir_write_timings(priv, &hw->reg_timings.timings,
+ RC_FILTER_NORMAL);
+ break;
+ case IMG_IR_M_REPEATING:
+ img_ir_write_timings(priv, &hw->reg_timings.rtimings,
+ RC_FILTER_NORMAL);
+ break;
+#ifdef CONFIG_PM_SLEEP
+ case IMG_IR_M_WAKE:
+ img_ir_write_timings(priv, &hw->reg_timings.timings,
+ RC_FILTER_WAKEUP);
+ break;
+#endif
+ }
+ }
+unlock:
+ spin_unlock_irq(&priv->lock);
+}
+
+static int img_ir_clk_notify(struct notifier_block *self, unsigned long action,
+ void *data)
+{
+ struct img_ir_priv *priv = container_of(self, struct img_ir_priv,
+ hw.clk_nb);
+ switch (action) {
+ case POST_RATE_CHANGE:
+ img_ir_change_frequency(priv, data);
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_OK;
+}
+#endif /* CONFIG_COMMON_CLK */
+
+/* called with priv->lock held */
+void img_ir_isr_hw(struct img_ir_priv *priv, u32 irq_status)
+{
+ struct img_ir_priv_hw *hw = &priv->hw;
+ u32 ir_status, len, lw, up;
+ unsigned int ct;
+
+ /* use the current decoder */
+ if (!hw->decoder)
+ return;
+
+ ir_status = img_ir_read(priv, IMG_IR_STATUS);
+ if (!(ir_status & (IMG_IR_RXDVAL | IMG_IR_RXDVALD2)))
+ return;
+ ir_status &= ~(IMG_IR_RXDVAL | IMG_IR_RXDVALD2);
+ img_ir_write(priv, IMG_IR_STATUS, ir_status);
+
+ len = (ir_status & IMG_IR_RXDLEN) >> IMG_IR_RXDLEN_SHIFT;
+ /* some versions report wrong length for certain code types */
+ ct = hw->decoder->control.code_type;
+ if (hw->ct_quirks[ct] & IMG_IR_QUIRK_CODE_LEN_INCR)
+ ++len;
+
+ lw = img_ir_read(priv, IMG_IR_DATA_LW);
+ up = img_ir_read(priv, IMG_IR_DATA_UP);
+ img_ir_handle_data(priv, len, (u64)up << 32 | lw);
+}
+
+void img_ir_setup_hw(struct img_ir_priv *priv)
+{
+ struct img_ir_decoder **decp;
+
+ if (!priv->hw.rdev)
+ return;
+
+ /* Use the first available decoder (or disable stuff if NULL) */
+ for (decp = img_ir_decoders; *decp; ++decp) {
+ const struct img_ir_decoder *dec = *decp;
+ if (img_ir_decoder_compatible(priv, dec)) {
+ img_ir_set_protocol(priv, dec->type);
+ img_ir_set_decoder(priv, dec, 0);
+ return;
+ }
+ }
+ img_ir_set_decoder(priv, NULL, 0);
+}
+
+/**
+ * img_ir_probe_hw_caps() - Probe capabilities of the hardware.
+ * @priv: IR private data.
+ */
+static void img_ir_probe_hw_caps(struct img_ir_priv *priv)
+{
+ struct img_ir_priv_hw *hw = &priv->hw;
+ /*
+ * When a version of the block becomes available without these quirks,
+ * they'll have to depend on the core revision.
+ */
+ hw->ct_quirks[IMG_IR_CODETYPE_PULSELEN]
+ |= IMG_IR_QUIRK_CODE_LEN_INCR;
+ hw->ct_quirks[IMG_IR_CODETYPE_BIPHASE]
+ |= IMG_IR_QUIRK_CODE_BROKEN;
+ hw->ct_quirks[IMG_IR_CODETYPE_2BITPULSEPOS]
+ |= IMG_IR_QUIRK_CODE_BROKEN;
+}
+
+int img_ir_probe_hw(struct img_ir_priv *priv)
+{
+ struct img_ir_priv_hw *hw = &priv->hw;
+ struct rc_dev *rdev;
+ int error;
+
+ /* Ensure hardware decoders have been preprocessed */
+ img_ir_init_decoders();
+
+ /* Probe hardware capabilities */
+ img_ir_probe_hw_caps(priv);
+
+ /* Set up the end timer */
+ setup_timer(&hw->end_timer, img_ir_end_timer, (unsigned long)priv);
+
+ /* Register a clock notifier */
+ if (!IS_ERR(priv->clk)) {
+ hw->clk_hz = clk_get_rate(priv->clk);
+#ifdef CONFIG_COMMON_CLK
+ hw->clk_nb.notifier_call = img_ir_clk_notify;
+ error = clk_notifier_register(priv->clk, &hw->clk_nb);
+ if (error)
+ dev_warn(priv->dev,
+ "failed to register clock notifier\n");
+#endif
+ } else {
+ hw->clk_hz = 32768;
+ }
+
+ /* Allocate hardware decoder */
+ hw->rdev = rdev = rc_allocate_device();
+ if (!rdev) {
+ dev_err(priv->dev, "cannot allocate input device\n");
+ error = -ENOMEM;
+ goto err_alloc_rc;
+ }
+ rdev->priv = priv;
+ rdev->map_name = RC_MAP_EMPTY;
+ rc_set_allowed_protocols(rdev, img_ir_allowed_protos(priv));
+ rdev->input_name = "IMG Infrared Decoder";
+ rdev->s_filter = img_ir_set_filter;
+
+ /* Register hardware decoder */
+ error = rc_register_device(rdev);
+ if (error) {
+ dev_err(priv->dev, "failed to register IR input device\n");
+ goto err_register_rc;
+ }
+
+ /*
+ * Set this after rc_register_device as no protocols have been
+ * registered yet.
+ */
+ rdev->change_protocol = img_ir_change_protocol;
+
+ device_init_wakeup(priv->dev, 1);
+
+ return 0;
+
+err_register_rc:
+ img_ir_set_decoder(priv, NULL, 0);
+ hw->rdev = NULL;
+ rc_free_device(rdev);
+err_alloc_rc:
+#ifdef CONFIG_COMMON_CLK
+ if (!IS_ERR(priv->clk))
+ clk_notifier_unregister(priv->clk, &hw->clk_nb);
+#endif
+ return error;
+}
+
+void img_ir_remove_hw(struct img_ir_priv *priv)
+{
+ struct img_ir_priv_hw *hw = &priv->hw;
+ struct rc_dev *rdev = hw->rdev;
+ if (!rdev)
+ return;
+ img_ir_set_decoder(priv, NULL, 0);
+ hw->rdev = NULL;
+ rc_unregister_device(rdev);
+#ifdef CONFIG_COMMON_CLK
+ if (!IS_ERR(priv->clk))
+ clk_notifier_unregister(priv->clk, &hw->clk_nb);
+#endif
+}
+
+#ifdef CONFIG_PM_SLEEP
+int img_ir_suspend(struct device *dev)
+{
+ struct img_ir_priv *priv = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev) && img_ir_enable_wake(priv))
+ enable_irq_wake(priv->irq);
+ return 0;
+}
+
+int img_ir_resume(struct device *dev)
+{
+ struct img_ir_priv *priv = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev) && img_ir_disable_wake(priv))
+ disable_irq_wake(priv->irq);
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
diff --git a/drivers/media/rc/img-ir/img-ir-hw.h b/drivers/media/rc/img-ir/img-ir-hw.h
new file mode 100644
index 000000000000..6c9a94a81190
--- /dev/null
+++ b/drivers/media/rc/img-ir/img-ir-hw.h
@@ -0,0 +1,269 @@
+/*
+ * ImgTec IR Hardware Decoder found in PowerDown Controller.
+ *
+ * Copyright 2010-2014 Imagination Technologies Ltd.
+ */
+
+#ifndef _IMG_IR_HW_H_
+#define _IMG_IR_HW_H_
+
+#include <linux/kernel.h>
+#include <media/rc-core.h>
+
+/* constants */
+
+#define IMG_IR_CODETYPE_PULSELEN 0x0 /* Sony */
+#define IMG_IR_CODETYPE_PULSEDIST 0x1 /* NEC, Toshiba, Micom, Sharp */
+#define IMG_IR_CODETYPE_BIPHASE 0x2 /* RC-5/6 */
+#define IMG_IR_CODETYPE_2BITPULSEPOS 0x3 /* RC-MM */
+
+
+/* Timing information */
+
+/**
+ * struct img_ir_control - Decoder control settings
+ * @decoden: Primary decoder enable
+ * @code_type: Decode type (see IMG_IR_CODETYPE_*)
+ * @hdrtog: Detect header toggle symbol after leader symbol
+ * @ldrdec: Don't discard leader if maximum width reached
+ * @decodinpol: Decoder input polarity (1=active high)
+ * @bitorien: Bit orientation (1=MSB first)
+ * @d1validsel: Decoder 2 takes over if it detects valid data
+ * @bitinv: Bit inversion switch (1=don't invert)
+ * @decodend2: Secondary decoder enable (no leader symbol)
+ * @bitoriend2: Bit orientation (1=MSB first)
+ * @bitinvd2: Secondary decoder bit inversion switch (1=don't invert)
+ */
+struct img_ir_control {
+ unsigned decoden:1;
+ unsigned code_type:2;
+ unsigned hdrtog:1;
+ unsigned ldrdec:1;
+ unsigned decodinpol:1;
+ unsigned bitorien:1;
+ unsigned d1validsel:1;
+ unsigned bitinv:1;
+ unsigned decodend2:1;
+ unsigned bitoriend2:1;
+ unsigned bitinvd2:1;
+};
+
+/**
+ * struct img_ir_timing_range - range of timing values
+ * @min: Minimum timing value
+ * @max: Maximum timing value (if < @min, this will be set to @min during
+ * preprocessing step, so it is normally not explicitly initialised
+ * and is taken care of by the tolerance)
+ */
+struct img_ir_timing_range {
+ u16 min;
+ u16 max;
+};
+
+/**
+ * struct img_ir_symbol_timing - timing data for a symbol
+ * @pulse: Timing range for the length of the pulse in this symbol
+ * @space: Timing range for the length of the space in this symbol
+ */
+struct img_ir_symbol_timing {
+ struct img_ir_timing_range pulse;
+ struct img_ir_timing_range space;
+};
+
+/**
+ * struct img_ir_free_timing - timing data for free time symbol
+ * @minlen: Minimum number of bits of data
+ * @maxlen: Maximum number of bits of data
+ * @ft_min: Minimum free time after message
+ */
+struct img_ir_free_timing {
+ /* measured in bits */
+ u8 minlen;
+ u8 maxlen;
+ u16 ft_min;
+};
+
+/**
+ * struct img_ir_timings - Timing values.
+ * @ldr: Leader symbol timing data
+ * @s00: Zero symbol timing data for primary decoder
+ * @s01: One symbol timing data for primary decoder
+ * @s10: Zero symbol timing data for secondary (no leader symbol) decoder
+ * @s11: One symbol timing data for secondary (no leader symbol) decoder
+ * @ft: Free time symbol timing data
+ */
+struct img_ir_timings {
+ struct img_ir_symbol_timing ldr, s00, s01, s10, s11;
+ struct img_ir_free_timing ft;
+};
+
+/**
+ * struct img_ir_filter - Filter IR events.
+ * @data: Data to match.
+ * @mask: Mask of bits to compare.
+ * @minlen: Additional minimum number of bits.
+ * @maxlen: Additional maximum number of bits.
+ */
+struct img_ir_filter {
+ u64 data;
+ u64 mask;
+ u8 minlen;
+ u8 maxlen;
+};
+
+/**
+ * struct img_ir_timing_regvals - Calculated timing register values.
+ * @ldr: Leader symbol timing register value
+ * @s00: Zero symbol timing register value for primary decoder
+ * @s01: One symbol timing register value for primary decoder
+ * @s10: Zero symbol timing register value for secondary decoder
+ * @s11: One symbol timing register value for secondary decoder
+ * @ft: Free time symbol timing register value
+ */
+struct img_ir_timing_regvals {
+ u32 ldr, s00, s01, s10, s11, ft;
+};
+
+#define IMG_IR_SCANCODE 0 /* new scancode */
+#define IMG_IR_REPEATCODE 1 /* repeat the previous code */
+
+/**
+ * struct img_ir_decoder - Decoder settings for an IR protocol.
+ * @type: Protocol types bitmap.
+ * @tolerance: Timing tolerance as a percentage (default 10%).
+ * @unit: Unit of timings in nanoseconds (default 1 us).
+ * @timings: Primary timings
+ * @rtimings: Additional override timings while waiting for repeats.
+ * @repeat: Maximum repeat interval (always in milliseconds).
+ * @control: Control flags.
+ *
+ * @scancode: Pointer to function to convert the IR data into a scancode (it
+ * must be safe to execute in interrupt context).
+ * Returns IMG_IR_SCANCODE to emit new scancode.
+ * Returns IMG_IR_REPEATCODE to repeat previous code.
+ * Returns -errno (e.g. -EINVAL) on error.
+ * @filter: Pointer to function to convert scancode filter to raw hardware
+ * filter. The minlen and maxlen fields will have been initialised
+ * to the maximum range.
+ */
+struct img_ir_decoder {
+ /* core description */
+ u64 type;
+ unsigned int tolerance;
+ unsigned int unit;
+ struct img_ir_timings timings;
+ struct img_ir_timings rtimings;
+ unsigned int repeat;
+ struct img_ir_control control;
+
+ /* scancode logic */
+ int (*scancode)(int len, u64 raw, int *scancode, u64 protocols);
+ int (*filter)(const struct rc_scancode_filter *in,
+ struct img_ir_filter *out, u64 protocols);
+};
+
+/**
+ * struct img_ir_reg_timings - Reg values for decoder timings at clock rate.
+ * @ctrl: Processed control register value.
+ * @timings: Processed primary timings.
+ * @rtimings: Processed repeat timings.
+ */
+struct img_ir_reg_timings {
+ u32 ctrl;
+ struct img_ir_timing_regvals timings;
+ struct img_ir_timing_regvals rtimings;
+};
+
+int img_ir_register_decoder(struct img_ir_decoder *dec);
+void img_ir_unregister_decoder(struct img_ir_decoder *dec);
+
+struct img_ir_priv;
+
+#ifdef CONFIG_IR_IMG_HW
+
+enum img_ir_mode {
+ IMG_IR_M_NORMAL,
+ IMG_IR_M_REPEATING,
+#ifdef CONFIG_PM_SLEEP
+ IMG_IR_M_WAKE,
+#endif
+};
+
+/**
+ * struct img_ir_priv_hw - Private driver data for hardware decoder.
+ * @ct_quirks: Quirk bits for each code type.
+ * @rdev: Remote control device
+ * @clk_nb: Notifier block for clock notify events.
+ * @end_timer: Timer until repeat timeout.
+ * @decoder: Current decoder settings.
+ * @enabled_protocols: Currently enabled protocols.
+ * @clk_hz: Current core clock rate in Hz.
+ * @reg_timings: Timing reg values for decoder at clock rate.
+ * @flags: IMG_IR_F_*.
+ * @filters: HW filters (derived from scancode filters).
+ * @mode: Current decode mode.
+ * @suspend_irqen: Saved IRQ enable mask over suspend.
+ */
+struct img_ir_priv_hw {
+ unsigned int ct_quirks[4];
+ struct rc_dev *rdev;
+ struct notifier_block clk_nb;
+ struct timer_list end_timer;
+ const struct img_ir_decoder *decoder;
+ u64 enabled_protocols;
+ unsigned long clk_hz;
+ struct img_ir_reg_timings reg_timings;
+ unsigned int flags;
+ struct img_ir_filter filters[RC_FILTER_MAX];
+
+ enum img_ir_mode mode;
+ u32 suspend_irqen;
+};
+
+static inline bool img_ir_hw_enabled(struct img_ir_priv_hw *hw)
+{
+ return hw->rdev;
+};
+
+void img_ir_isr_hw(struct img_ir_priv *priv, u32 irq_status);
+void img_ir_setup_hw(struct img_ir_priv *priv);
+int img_ir_probe_hw(struct img_ir_priv *priv);
+void img_ir_remove_hw(struct img_ir_priv *priv);
+
+#ifdef CONFIG_PM_SLEEP
+int img_ir_suspend(struct device *dev);
+int img_ir_resume(struct device *dev);
+#else
+#define img_ir_suspend NULL
+#define img_ir_resume NULL
+#endif
+
+#else
+
+struct img_ir_priv_hw {
+};
+
+static inline bool img_ir_hw_enabled(struct img_ir_priv_hw *hw)
+{
+ return false;
+};
+static inline void img_ir_isr_hw(struct img_ir_priv *priv, u32 irq_status)
+{
+}
+static inline void img_ir_setup_hw(struct img_ir_priv *priv)
+{
+}
+static inline int img_ir_probe_hw(struct img_ir_priv *priv)
+{
+ return -ENODEV;
+}
+static inline void img_ir_remove_hw(struct img_ir_priv *priv)
+{
+}
+
+#define img_ir_suspend NULL
+#define img_ir_resume NULL
+
+#endif /* CONFIG_IR_IMG_HW */
+
+#endif /* _IMG_IR_HW_H_ */
diff --git a/drivers/media/rc/img-ir/img-ir-jvc.c b/drivers/media/rc/img-ir/img-ir-jvc.c
new file mode 100644
index 000000000000..10209d200efb
--- /dev/null
+++ b/drivers/media/rc/img-ir/img-ir-jvc.c
@@ -0,0 +1,81 @@
+/*
+ * ImgTec IR Decoder setup for JVC protocol.
+ *
+ * Copyright 2012-2014 Imagination Technologies Ltd.
+ */
+
+#include "img-ir-hw.h"
+
+/* Convert JVC data to a scancode */
+static int img_ir_jvc_scancode(int len, u64 raw, int *scancode, u64 protocols)
+{
+ unsigned int cust, data;
+
+ if (len != 16)
+ return -EINVAL;
+
+ cust = (raw >> 0) & 0xff;
+ data = (raw >> 8) & 0xff;
+
+ *scancode = cust << 8 | data;
+ return IMG_IR_SCANCODE;
+}
+
+/* Convert JVC scancode to JVC data filter */
+static int img_ir_jvc_filter(const struct rc_scancode_filter *in,
+ struct img_ir_filter *out, u64 protocols)
+{
+ unsigned int cust, data;
+ unsigned int cust_m, data_m;
+
+ cust = (in->data >> 8) & 0xff;
+ cust_m = (in->mask >> 8) & 0xff;
+ data = (in->data >> 0) & 0xff;
+ data_m = (in->mask >> 0) & 0xff;
+
+ out->data = cust | data << 8;
+ out->mask = cust_m | data_m << 8;
+
+ return 0;
+}
+
+/*
+ * JVC decoder
+ * See also http://www.sbprojects.com/knowledge/ir/jvc.php
+ * http://support.jvc.com/consumer/support/documents/RemoteCodes.pdf
+ */
+struct img_ir_decoder img_ir_jvc = {
+ .type = RC_BIT_JVC,
+ .control = {
+ .decoden = 1,
+ .code_type = IMG_IR_CODETYPE_PULSEDIST,
+ },
+ /* main timings */
+ .unit = 527500, /* 527.5 us */
+ .timings = {
+ /* leader symbol */
+ .ldr = {
+ .pulse = { 16 /* 8.44 ms */ },
+ .space = { 8 /* 4.22 ms */ },
+ },
+ /* 0 symbol */
+ .s00 = {
+ .pulse = { 1 /* 527.5 us +-60 us */ },
+ .space = { 1 /* 527.5 us */ },
+ },
+ /* 1 symbol */
+ .s01 = {
+ .pulse = { 1 /* 527.5 us +-60 us */ },
+ .space = { 3 /* 1.5825 ms +-40 us */ },
+ },
+ /* free time */
+ .ft = {
+ .minlen = 16,
+ .maxlen = 16,
+ .ft_min = 10, /* 5.275 ms */
+ },
+ },
+ /* scancode logic */
+ .scancode = img_ir_jvc_scancode,
+ .filter = img_ir_jvc_filter,
+};
diff --git a/drivers/media/rc/img-ir/img-ir-nec.c b/drivers/media/rc/img-ir/img-ir-nec.c
new file mode 100644
index 000000000000..e7a731bc3a9b
--- /dev/null
+++ b/drivers/media/rc/img-ir/img-ir-nec.c
@@ -0,0 +1,148 @@
+/*
+ * ImgTec IR Decoder setup for NEC protocol.
+ *
+ * Copyright 2010-2014 Imagination Technologies Ltd.
+ */
+
+#include "img-ir-hw.h"
+
+/* Convert NEC data to a scancode */
+static int img_ir_nec_scancode(int len, u64 raw, int *scancode, u64 protocols)
+{
+ unsigned int addr, addr_inv, data, data_inv;
+ /* a repeat code has no data */
+ if (!len)
+ return IMG_IR_REPEATCODE;
+ if (len != 32)
+ return -EINVAL;
+ /* raw encoding: ddDDaaAA */
+ addr = (raw >> 0) & 0xff;
+ addr_inv = (raw >> 8) & 0xff;
+ data = (raw >> 16) & 0xff;
+ data_inv = (raw >> 24) & 0xff;
+ if ((data_inv ^ data) != 0xff) {
+ /* 32-bit NEC (used by Apple and TiVo remotes) */
+ /* scan encoding: aaAAddDD */
+ *scancode = addr_inv << 24 |
+ addr << 16 |
+ data_inv << 8 |
+ data;
+ } else if ((addr_inv ^ addr) != 0xff) {
+ /* Extended NEC */
+ /* scan encoding: AAaaDD */
+ *scancode = addr << 16 |
+ addr_inv << 8 |
+ data;
+ } else {
+ /* Normal NEC */
+ /* scan encoding: AADD */
+ *scancode = addr << 8 |
+ data;
+ }
+ return IMG_IR_SCANCODE;
+}
+
+/* Convert NEC scancode to NEC data filter */
+static int img_ir_nec_filter(const struct rc_scancode_filter *in,
+ struct img_ir_filter *out, u64 protocols)
+{
+ unsigned int addr, addr_inv, data, data_inv;
+ unsigned int addr_m, addr_inv_m, data_m, data_inv_m;
+
+ data = in->data & 0xff;
+ data_m = in->mask & 0xff;
+
+ if ((in->data | in->mask) & 0xff000000) {
+ /* 32-bit NEC (used by Apple and TiVo remotes) */
+ /* scan encoding: aaAAddDD */
+ addr_inv = (in->data >> 24) & 0xff;
+ addr_inv_m = (in->mask >> 24) & 0xff;
+ addr = (in->data >> 16) & 0xff;
+ addr_m = (in->mask >> 16) & 0xff;
+ data_inv = (in->data >> 8) & 0xff;
+ data_inv_m = (in->mask >> 8) & 0xff;
+ } else if ((in->data | in->mask) & 0x00ff0000) {
+ /* Extended NEC */
+ /* scan encoding AAaaDD */
+ addr = (in->data >> 16) & 0xff;
+ addr_m = (in->mask >> 16) & 0xff;
+ addr_inv = (in->data >> 8) & 0xff;
+ addr_inv_m = (in->mask >> 8) & 0xff;
+ data_inv = data ^ 0xff;
+ data_inv_m = data_m;
+ } else {
+ /* Normal NEC */
+ /* scan encoding: AADD */
+ addr = (in->data >> 8) & 0xff;
+ addr_m = (in->mask >> 8) & 0xff;
+ addr_inv = addr ^ 0xff;
+ addr_inv_m = addr_m;
+ data_inv = data ^ 0xff;
+ data_inv_m = data_m;
+ }
+
+ /* raw encoding: ddDDaaAA */
+ out->data = data_inv << 24 |
+ data << 16 |
+ addr_inv << 8 |
+ addr;
+ out->mask = data_inv_m << 24 |
+ data_m << 16 |
+ addr_inv_m << 8 |
+ addr_m;
+ return 0;
+}
+
+/*
+ * NEC decoder
+ * See also http://www.sbprojects.com/knowledge/ir/nec.php
+ * http://wiki.altium.com/display/ADOH/NEC+Infrared+Transmission+Protocol
+ */
+struct img_ir_decoder img_ir_nec = {
+ .type = RC_BIT_NEC,
+ .control = {
+ .decoden = 1,
+ .code_type = IMG_IR_CODETYPE_PULSEDIST,
+ },
+ /* main timings */
+ .unit = 562500, /* 562.5 us */
+ .timings = {
+ /* leader symbol */
+ .ldr = {
+ .pulse = { 16 /* 9ms */ },
+ .space = { 8 /* 4.5ms */ },
+ },
+ /* 0 symbol */
+ .s00 = {
+ .pulse = { 1 /* 562.5 us */ },
+ .space = { 1 /* 562.5 us */ },
+ },
+ /* 1 symbol */
+ .s01 = {
+ .pulse = { 1 /* 562.5 us */ },
+ .space = { 3 /* 1687.5 us */ },
+ },
+ /* free time */
+ .ft = {
+ .minlen = 32,
+ .maxlen = 32,
+ .ft_min = 10, /* 5.625 ms */
+ },
+ },
+ /* repeat codes */
+ .repeat = 108, /* 108 ms */
+ .rtimings = {
+ /* leader symbol */
+ .ldr = {
+ .space = { 4 /* 2.25 ms */ },
+ },
+ /* free time */
+ .ft = {
+ .minlen = 0, /* repeat code has no data */
+ .maxlen = 0,
+ },
+ },
+ /* scancode logic */
+ .scancode = img_ir_nec_scancode,
+ .filter = img_ir_nec_filter,
+};
diff --git a/drivers/media/rc/img-ir/img-ir-raw.c b/drivers/media/rc/img-ir/img-ir-raw.c
new file mode 100644
index 000000000000..cfb01d9e571a
--- /dev/null
+++ b/drivers/media/rc/img-ir/img-ir-raw.c
@@ -0,0 +1,151 @@
+/*
+ * ImgTec IR Raw Decoder found in PowerDown Controller.
+ *
+ * Copyright 2010-2014 Imagination Technologies Ltd.
+ *
+ * This ties into the input subsystem using the RC-core in raw mode. Raw IR
+ * signal edges are reported and decoded by generic software decoders.
+ */
+
+#include <linux/spinlock.h>
+#include <media/rc-core.h>
+#include "img-ir.h"
+
+#define ECHO_TIMEOUT_MS 150 /* ms between echos */
+
+/* must be called with priv->lock held */
+static void img_ir_refresh_raw(struct img_ir_priv *priv, u32 irq_status)
+{
+ struct img_ir_priv_raw *raw = &priv->raw;
+ struct rc_dev *rc_dev = priv->raw.rdev;
+ int multiple;
+ u32 ir_status;
+
+ /* find whether both rise and fall was detected */
+ multiple = ((irq_status & IMG_IR_IRQ_EDGE) == IMG_IR_IRQ_EDGE);
+ /*
+ * If so, we need to see if the level has actually changed.
+ * If it's just noise that we didn't have time to process,
+ * there's no point reporting it.
+ */
+ ir_status = img_ir_read(priv, IMG_IR_STATUS) & IMG_IR_IRRXD;
+ if (multiple && ir_status == raw->last_status)
+ return;
+ raw->last_status = ir_status;
+
+ /* report the edge to the IR raw decoders */
+ if (ir_status) /* low */
+ ir_raw_event_store_edge(rc_dev, IR_SPACE);
+ else /* high */
+ ir_raw_event_store_edge(rc_dev, IR_PULSE);
+ ir_raw_event_handle(rc_dev);
+}
+
+/* called with priv->lock held */
+void img_ir_isr_raw(struct img_ir_priv *priv, u32 irq_status)
+{
+ struct img_ir_priv_raw *raw = &priv->raw;
+
+ /* check not removing */
+ if (!raw->rdev)
+ return;
+
+ img_ir_refresh_raw(priv, irq_status);
+
+ /* start / push back the echo timer */
+ mod_timer(&raw->timer, jiffies + msecs_to_jiffies(ECHO_TIMEOUT_MS));
+}
+
+/*
+ * Echo timer callback function.
+ * The raw decoders expect to get a final sample even if there are no edges, in
+ * order to be assured of the final space. If there are no edges for a certain
+ * time we use this timer to emit a final sample to satisfy them.
+ */
+static void img_ir_echo_timer(unsigned long arg)
+{
+ struct img_ir_priv *priv = (struct img_ir_priv *)arg;
+
+ spin_lock_irq(&priv->lock);
+
+ /* check not removing */
+ if (priv->raw.rdev)
+ /*
+ * It's safe to pass irq_status=0 since it's only used to check
+ * for double edges.
+ */
+ img_ir_refresh_raw(priv, 0);
+
+ spin_unlock_irq(&priv->lock);
+}
+
+void img_ir_setup_raw(struct img_ir_priv *priv)
+{
+ u32 irq_en;
+
+ if (!priv->raw.rdev)
+ return;
+
+ /* clear and enable edge interrupts */
+ spin_lock_irq(&priv->lock);
+ irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE);
+ irq_en |= IMG_IR_IRQ_EDGE;
+ img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE);
+ img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en);
+ spin_unlock_irq(&priv->lock);
+}
+
+int img_ir_probe_raw(struct img_ir_priv *priv)
+{
+ struct img_ir_priv_raw *raw = &priv->raw;
+ struct rc_dev *rdev;
+ int error;
+
+ /* Set up the echo timer */
+ setup_timer(&raw->timer, img_ir_echo_timer, (unsigned long)priv);
+
+ /* Allocate raw decoder */
+ raw->rdev = rdev = rc_allocate_device();
+ if (!rdev) {
+ dev_err(priv->dev, "cannot allocate raw input device\n");
+ return -ENOMEM;
+ }
+ rdev->priv = priv;
+ rdev->map_name = RC_MAP_EMPTY;
+ rdev->input_name = "IMG Infrared Decoder Raw";
+ rdev->driver_type = RC_DRIVER_IR_RAW;
+
+ /* Register raw decoder */
+ error = rc_register_device(rdev);
+ if (error) {
+ dev_err(priv->dev, "failed to register raw IR input device\n");
+ rc_free_device(rdev);
+ raw->rdev = NULL;
+ return error;
+ }
+
+ return 0;
+}
+
+void img_ir_remove_raw(struct img_ir_priv *priv)
+{
+ struct img_ir_priv_raw *raw = &priv->raw;
+ struct rc_dev *rdev = raw->rdev;
+ u32 irq_en;
+
+ if (!rdev)
+ return;
+
+ /* switch off and disable raw (edge) interrupts */
+ spin_lock_irq(&priv->lock);
+ raw->rdev = NULL;
+ irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE);
+ irq_en &= ~IMG_IR_IRQ_EDGE;
+ img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en);
+ img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE);
+ spin_unlock_irq(&priv->lock);
+
+ rc_unregister_device(rdev);
+
+ del_timer_sync(&raw->timer);
+}
diff --git a/drivers/media/rc/img-ir/img-ir-raw.h b/drivers/media/rc/img-ir/img-ir-raw.h
new file mode 100644
index 000000000000..9802ffd51b9a
--- /dev/null
+++ b/drivers/media/rc/img-ir/img-ir-raw.h
@@ -0,0 +1,60 @@
+/*
+ * ImgTec IR Raw Decoder found in PowerDown Controller.
+ *
+ * Copyright 2010-2014 Imagination Technologies Ltd.
+ */
+
+#ifndef _IMG_IR_RAW_H_
+#define _IMG_IR_RAW_H_
+
+struct img_ir_priv;
+
+#ifdef CONFIG_IR_IMG_RAW
+
+/**
+ * struct img_ir_priv_raw - Private driver data for raw decoder.
+ * @rdev: Raw remote control device
+ * @timer: Timer to echo samples to keep soft decoders happy.
+ * @last_status: Last raw status bits.
+ */
+struct img_ir_priv_raw {
+ struct rc_dev *rdev;
+ struct timer_list timer;
+ u32 last_status;
+};
+
+static inline bool img_ir_raw_enabled(struct img_ir_priv_raw *raw)
+{
+ return raw->rdev;
+};
+
+void img_ir_isr_raw(struct img_ir_priv *priv, u32 irq_status);
+void img_ir_setup_raw(struct img_ir_priv *priv);
+int img_ir_probe_raw(struct img_ir_priv *priv);
+void img_ir_remove_raw(struct img_ir_priv *priv);
+
+#else
+
+struct img_ir_priv_raw {
+};
+static inline bool img_ir_raw_enabled(struct img_ir_priv_raw *raw)
+{
+ return false;
+};
+static inline void img_ir_isr_raw(struct img_ir_priv *priv, u32 irq_status)
+{
+}
+static inline void img_ir_setup_raw(struct img_ir_priv *priv)
+{
+}
+static inline int img_ir_probe_raw(struct img_ir_priv *priv)
+{
+ return -ENODEV;
+}
+static inline void img_ir_remove_raw(struct img_ir_priv *priv)
+{
+}
+
+#endif /* CONFIG_IR_IMG_RAW */
+
+#endif /* _IMG_IR_RAW_H_ */
diff --git a/drivers/media/rc/img-ir/img-ir-sanyo.c b/drivers/media/rc/img-ir/img-ir-sanyo.c
new file mode 100644
index 000000000000..c2c763e08a41
--- /dev/null
+++ b/drivers/media/rc/img-ir/img-ir-sanyo.c
@@ -0,0 +1,122 @@
+/*
+ * ImgTec IR Decoder setup for Sanyo protocol.
+ *
+ * Copyright 2012-2014 Imagination Technologies Ltd.
+ *
+ * From ir-sanyo-decoder.c:
+ *
+ * This protocol uses the NEC protocol timings. However, data is formatted as:
+ * 13 bits Custom Code
+ * 13 bits NOT(Custom Code)
+ * 8 bits Key data
+ * 8 bits NOT(Key data)
+ *
+ * According with LIRC, this protocol is used on Sanyo, Aiwa and Chinon
+ * Information for this protocol is available at the Sanyo LC7461 datasheet.
+ */
+
+#include "img-ir-hw.h"
+
+/* Convert Sanyo data to a scancode */
+static int img_ir_sanyo_scancode(int len, u64 raw, int *scancode, u64 protocols)
+{
+ unsigned int addr, addr_inv, data, data_inv;
+ /* a repeat code has no data */
+ if (!len)
+ return IMG_IR_REPEATCODE;
+ if (len != 42)
+ return -EINVAL;
+ addr = (raw >> 0) & 0x1fff;
+ addr_inv = (raw >> 13) & 0x1fff;
+ data = (raw >> 26) & 0xff;
+ data_inv = (raw >> 34) & 0xff;
+ /* Validate data */
+ if ((data_inv ^ data) != 0xff)
+ return -EINVAL;
+ /* Validate address */
+ if ((addr_inv ^ addr) != 0x1fff)
+ return -EINVAL;
+
+ /* Normal Sanyo */
+ *scancode = addr << 8 | data;
+ return IMG_IR_SCANCODE;
+}
+
+/* Convert Sanyo scancode to Sanyo data filter */
+static int img_ir_sanyo_filter(const struct rc_scancode_filter *in,
+ struct img_ir_filter *out, u64 protocols)
+{
+ unsigned int addr, addr_inv, data, data_inv;
+ unsigned int addr_m, data_m;
+
+ data = in->data & 0xff;
+ data_m = in->mask & 0xff;
+ data_inv = data ^ 0xff;
+
+ if (in->data & 0xff700000)
+ return -EINVAL;
+
+ addr = (in->data >> 8) & 0x1fff;
+ addr_m = (in->mask >> 8) & 0x1fff;
+ addr_inv = addr ^ 0x1fff;
+
+ out->data = (u64)data_inv << 34 |
+ (u64)data << 26 |
+ addr_inv << 13 |
+ addr;
+ out->mask = (u64)data_m << 34 |
+ (u64)data_m << 26 |
+ addr_m << 13 |
+ addr_m;
+ return 0;
+}
+
+/* Sanyo decoder */
+struct img_ir_decoder img_ir_sanyo = {
+ .type = RC_BIT_SANYO,
+ .control = {
+ .decoden = 1,
+ .code_type = IMG_IR_CODETYPE_PULSEDIST,
+ },
+ /* main timings */
+ .unit = 562500, /* 562.5 us */
+ .timings = {
+ /* leader symbol */
+ .ldr = {
+ .pulse = { 16 /* 9ms */ },
+ .space = { 8 /* 4.5ms */ },
+ },
+ /* 0 symbol */
+ .s00 = {
+ .pulse = { 1 /* 562.5 us */ },
+ .space = { 1 /* 562.5 us */ },
+ },
+ /* 1 symbol */
+ .s01 = {
+ .pulse = { 1 /* 562.5 us */ },
+ .space = { 3 /* 1687.5 us */ },
+ },
+ /* free time */
+ .ft = {
+ .minlen = 42,
+ .maxlen = 42,
+ .ft_min = 10, /* 5.625 ms */
+ },
+ },
+ /* repeat codes */
+ .repeat = 108, /* 108 ms */
+ .rtimings = {
+ /* leader symbol */
+ .ldr = {
+ .space = { 4 /* 2.25 ms */ },
+ },
+ /* free time */
+ .ft = {
+ .minlen = 0, /* repeat code has no data */
+ .maxlen = 0,
+ },
+ },
+ /* scancode logic */
+ .scancode = img_ir_sanyo_scancode,
+ .filter = img_ir_sanyo_filter,
+};
diff --git a/drivers/media/rc/img-ir/img-ir-sharp.c b/drivers/media/rc/img-ir/img-ir-sharp.c
new file mode 100644
index 000000000000..3397cc5a6794
--- /dev/null
+++ b/drivers/media/rc/img-ir/img-ir-sharp.c
@@ -0,0 +1,99 @@
+/*
+ * ImgTec IR Decoder setup for Sharp protocol.
+ *
+ * Copyright 2012-2014 Imagination Technologies Ltd.
+ */
+
+#include "img-ir-hw.h"
+
+/* Convert Sharp data to a scancode */
+static int img_ir_sharp_scancode(int len, u64 raw, int *scancode, u64 protocols)
+{
+ unsigned int addr, cmd, exp, chk;
+
+ if (len != 15)
+ return -EINVAL;
+
+ addr = (raw >> 0) & 0x1f;
+ cmd = (raw >> 5) & 0xff;
+ exp = (raw >> 13) & 0x1;
+ chk = (raw >> 14) & 0x1;
+
+ /* validate data */
+ if (!exp)
+ return -EINVAL;
+ if (chk)
+ /* probably the second half of the message */
+ return -EINVAL;
+
+ *scancode = addr << 8 | cmd;
+ return IMG_IR_SCANCODE;
+}
+
+/* Convert Sharp scancode to Sharp data filter */
+static int img_ir_sharp_filter(const struct rc_scancode_filter *in,
+ struct img_ir_filter *out, u64 protocols)
+{
+ unsigned int addr, cmd, exp = 0, chk = 0;
+ unsigned int addr_m, cmd_m, exp_m = 0, chk_m = 0;
+
+ addr = (in->data >> 8) & 0x1f;
+ addr_m = (in->mask >> 8) & 0x1f;
+ cmd = (in->data >> 0) & 0xff;
+ cmd_m = (in->mask >> 0) & 0xff;
+ if (cmd_m) {
+ /* if filtering commands, we can only match the first part */
+ exp = 1;
+ exp_m = 1;
+ chk = 0;
+ chk_m = 1;
+ }
+
+ out->data = addr |
+ cmd << 5 |
+ exp << 13 |
+ chk << 14;
+ out->mask = addr_m |
+ cmd_m << 5 |
+ exp_m << 13 |
+ chk_m << 14;
+
+ return 0;
+}
+
+/*
+ * Sharp decoder
+ * See also http://www.sbprojects.com/knowledge/ir/sharp.php
+ */
+struct img_ir_decoder img_ir_sharp = {
+ .type = RC_BIT_SHARP,
+ .control = {
+ .decoden = 0,
+ .decodend2 = 1,
+ .code_type = IMG_IR_CODETYPE_PULSEDIST,
+ .d1validsel = 1,
+ },
+ /* main timings */
+ .tolerance = 20, /* 20% */
+ .timings = {
+ /* 0 symbol */
+ .s10 = {
+ .pulse = { 320 /* 320 us */ },
+ .space = { 680 /* 1 ms period */ },
+ },
+ /* 1 symbol */
+ .s11 = {
+ .pulse = { 320 /* 320 us */ },
+ .space = { 1680 /* 2 ms period */ },
+ },
+ /* free time */
+ .ft = {
+ .minlen = 15,
+ .maxlen = 15,
+ .ft_min = 5000, /* 5 ms */
+ },
+ },
+ /* scancode logic */
+ .scancode = img_ir_sharp_scancode,
+ .filter = img_ir_sharp_filter,
+};
diff --git a/drivers/media/rc/img-ir/img-ir-sony.c b/drivers/media/rc/img-ir/img-ir-sony.c
new file mode 100644
index 000000000000..993409a51a71
--- /dev/null
+++ b/drivers/media/rc/img-ir/img-ir-sony.c
@@ -0,0 +1,145 @@
+/*
+ * ImgTec IR Decoder setup for Sony (SIRC) protocol.
+ *
+ * Copyright 2012-2014 Imagination Technologies Ltd.
+ */
+
+#include "img-ir-hw.h"
+
+/* Convert Sony data to a scancode */
+static int img_ir_sony_scancode(int len, u64 raw, int *scancode, u64 protocols)
+{
+ unsigned int dev, subdev, func;
+
+ switch (len) {
+ case 12:
+ if (!(protocols & RC_BIT_SONY12))
+ return -EINVAL;
+ func = raw & 0x7f; /* first 7 bits */
+ raw >>= 7;
+ dev = raw & 0x1f; /* next 5 bits */
+ subdev = 0;
+ break;
+ case 15:
+ if (!(protocols & RC_BIT_SONY15))
+ return -EINVAL;
+ func = raw & 0x7f; /* first 7 bits */
+ raw >>= 7;
+ dev = raw & 0xff; /* next 8 bits */
+ subdev = 0;
+ break;
+ case 20:
+ if (!(protocols & RC_BIT_SONY20))
+ return -EINVAL;
+ func = raw & 0x7f; /* first 7 bits */
+ raw >>= 7;
+ dev = raw & 0x1f; /* next 5 bits */
+ raw >>= 5;
+ subdev = raw & 0xff; /* next 8 bits */
+ break;
+ default:
+ return -EINVAL;
+ }
+ *scancode = dev << 16 | subdev << 8 | func;
+ return IMG_IR_SCANCODE;
+}
+
+/* Convert NEC scancode to NEC data filter */
+static int img_ir_sony_filter(const struct rc_scancode_filter *in,
+ struct img_ir_filter *out, u64 protocols)
+{
+ unsigned int dev, subdev, func;
+ unsigned int dev_m, subdev_m, func_m;
+ unsigned int len = 0;
+
+ dev = (in->data >> 16) & 0xff;
+ dev_m = (in->mask >> 16) & 0xff;
+ subdev = (in->data >> 8) & 0xff;
+ subdev_m = (in->mask >> 8) & 0xff;
+ func = (in->data >> 0) & 0x7f;
+ func_m = (in->mask >> 0) & 0x7f;
+
+ if (subdev & subdev_m) {
+ /* can't encode subdev and higher device bits */
+ if (dev & dev_m & 0xe0)
+ return -EINVAL;
+ /* subdevice (extended) bits only in 20 bit encoding */
+ if (!(protocols & RC_BIT_SONY20))
+ return -EINVAL;
+ len = 20;
+ dev_m &= 0x1f;
+ } else if (dev & dev_m & 0xe0) {
+ /* upper device bits only in 15 bit encoding */
+ if (!(protocols & RC_BIT_SONY15))
+ return -EINVAL;
+ len = 15;
+ subdev_m = 0;
+ } else {
+ /*
+ * The hardware mask cannot distinguish high device bits and low
+ * extended bits, so logically AND those bits of the masks
+ * together.
+ */
+ subdev_m &= (dev_m >> 5) | 0xf8;
+ dev_m &= 0x1f;
+ }
+
+ /* ensure there aren't any bits straying between fields */
+ dev &= dev_m;
+ subdev &= subdev_m;
+
+ /* write the hardware filter */
+ out->data = func |
+ dev << 7 |
+ subdev << 15;
+ out->mask = func_m |
+ dev_m << 7 |
+ subdev_m << 15;
+
+ if (len) {
+ out->minlen = len;
+ out->maxlen = len;
+ }
+ return 0;
+}
+
+/*
+ * Sony SIRC decoder
+ * See also http://www.sbprojects.com/knowledge/ir/sirc.php
+ * http://picprojects.org.uk/projects/sirc/sonysirc.pdf
+ */
+struct img_ir_decoder img_ir_sony = {
+ .type = RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20,
+ .control = {
+ .decoden = 1,
+ .code_type = IMG_IR_CODETYPE_PULSELEN,
+ },
+ /* main timings */
+ .unit = 600000, /* 600 us */
+ .timings = {
+ /* leader symbol */
+ .ldr = {
+ .pulse = { 4 /* 2.4 ms */ },
+ .space = { 1 /* 600 us */ },
+ },
+ /* 0 symbol */
+ .s00 = {
+ .pulse = { 1 /* 600 us */ },
+ .space = { 1 /* 600 us */ },
+ },
+ /* 1 symbol */
+ .s01 = {
+ .pulse = { 2 /* 1.2 ms */ },
+ .space = { 1 /* 600 us */ },
+ },
+ /* free time */
+ .ft = {
+ .minlen = 12,
+ .maxlen = 20,
+ .ft_min = 10, /* 6 ms */
+ },
+ },
+ /* scancode logic */
+ .scancode = img_ir_sony_scancode,
+ .filter = img_ir_sony_filter,
+};
diff --git a/drivers/media/rc/img-ir/img-ir.h b/drivers/media/rc/img-ir/img-ir.h
new file mode 100644
index 000000000000..afb189394af9
--- /dev/null
+++ b/drivers/media/rc/img-ir/img-ir.h
@@ -0,0 +1,166 @@
+/*
+ * ImgTec IR Decoder found in PowerDown Controller.
+ *
+ * Copyright 2010-2014 Imagination Technologies Ltd.
+ */
+
+#ifndef _IMG_IR_H_
+#define _IMG_IR_H_
+
+#include <linux/io.h>
+#include <linux/spinlock.h>
+
+#include "img-ir-raw.h"
+#include "img-ir-hw.h"
+
+/* registers */
+
+/* relative to the start of the IR block of registers */
+#define IMG_IR_CONTROL 0x00
+#define IMG_IR_STATUS 0x04
+#define IMG_IR_DATA_LW 0x08
+#define IMG_IR_DATA_UP 0x0c
+#define IMG_IR_LEAD_SYMB_TIMING 0x10
+#define IMG_IR_S00_SYMB_TIMING 0x14
+#define IMG_IR_S01_SYMB_TIMING 0x18
+#define IMG_IR_S10_SYMB_TIMING 0x1c
+#define IMG_IR_S11_SYMB_TIMING 0x20
+#define IMG_IR_FREE_SYMB_TIMING 0x24
+#define IMG_IR_POW_MOD_PARAMS 0x28
+#define IMG_IR_POW_MOD_ENABLE 0x2c
+#define IMG_IR_IRQ_MSG_DATA_LW 0x30
+#define IMG_IR_IRQ_MSG_DATA_UP 0x34
+#define IMG_IR_IRQ_MSG_MASK_LW 0x38
+#define IMG_IR_IRQ_MSG_MASK_UP 0x3c
+#define IMG_IR_IRQ_ENABLE 0x40
+#define IMG_IR_IRQ_STATUS 0x44
+#define IMG_IR_IRQ_CLEAR 0x48
+#define IMG_IR_IRCORE_ID 0xf0
+#define IMG_IR_CORE_REV 0xf4
+#define IMG_IR_CORE_DES1 0xf8
+#define IMG_IR_CORE_DES2 0xfc
+
+
+/* field masks */
+
+/* IMG_IR_CONTROL */
+#define IMG_IR_DECODEN 0x40000000
+#define IMG_IR_CODETYPE 0x30000000
+#define IMG_IR_CODETYPE_SHIFT 28
+#define IMG_IR_HDRTOG 0x08000000
+#define IMG_IR_LDRDEC 0x04000000
+#define IMG_IR_DECODINPOL 0x02000000 /* active high */
+#define IMG_IR_BITORIEN 0x01000000 /* MSB first */
+#define IMG_IR_D1VALIDSEL 0x00008000
+#define IMG_IR_BITINV 0x00000040 /* don't invert */
+#define IMG_IR_DECODEND2 0x00000010
+#define IMG_IR_BITORIEND2 0x00000002 /* MSB first */
+#define IMG_IR_BITINVD2 0x00000001 /* don't invert */
+
+/* IMG_IR_STATUS */
+#define IMG_IR_RXDVALD2 0x00001000
+#define IMG_IR_IRRXD 0x00000400
+#define IMG_IR_TOGSTATE 0x00000200
+#define IMG_IR_RXDVAL 0x00000040
+#define IMG_IR_RXDLEN 0x0000003f
+#define IMG_IR_RXDLEN_SHIFT 0
+
+/* IMG_IR_LEAD_SYMB_TIMING, IMG_IR_Sxx_SYMB_TIMING */
+#define IMG_IR_PD_MAX 0xff000000
+#define IMG_IR_PD_MAX_SHIFT 24
+#define IMG_IR_PD_MIN 0x00ff0000
+#define IMG_IR_PD_MIN_SHIFT 16
+#define IMG_IR_W_MAX 0x0000ff00
+#define IMG_IR_W_MAX_SHIFT 8
+#define IMG_IR_W_MIN 0x000000ff
+#define IMG_IR_W_MIN_SHIFT 0
+
+/* IMG_IR_FREE_SYMB_TIMING */
+#define IMG_IR_MAXLEN 0x0007e000
+#define IMG_IR_MAXLEN_SHIFT 13
+#define IMG_IR_MINLEN 0x00001f00
+#define IMG_IR_MINLEN_SHIFT 8
+#define IMG_IR_FT_MIN 0x000000ff
+#define IMG_IR_FT_MIN_SHIFT 0
+
+/* IMG_IR_POW_MOD_PARAMS */
+#define IMG_IR_PERIOD_LEN 0x3f000000
+#define IMG_IR_PERIOD_LEN_SHIFT 24
+#define IMG_IR_PERIOD_DUTY 0x003f0000
+#define IMG_IR_PERIOD_DUTY_SHIFT 16
+#define IMG_IR_STABLE_STOP 0x00003f00
+#define IMG_IR_STABLE_STOP_SHIFT 8
+#define IMG_IR_STABLE_START 0x0000003f
+#define IMG_IR_STABLE_START_SHIFT 0
+
+/* IMG_IR_POW_MOD_ENABLE */
+#define IMG_IR_POWER_OUT_EN 0x00000002
+#define IMG_IR_POWER_MOD_EN 0x00000001
+
+/* IMG_IR_IRQ_ENABLE, IMG_IR_IRQ_STATUS, IMG_IR_IRQ_CLEAR */
+#define IMG_IR_IRQ_DEC2_ERR 0x00000080
+#define IMG_IR_IRQ_DEC_ERR 0x00000040
+#define IMG_IR_IRQ_ACT_LEVEL 0x00000020
+#define IMG_IR_IRQ_FALL_EDGE 0x00000010
+#define IMG_IR_IRQ_RISE_EDGE 0x00000008
+#define IMG_IR_IRQ_DATA_MATCH 0x00000004
+#define IMG_IR_IRQ_DATA2_VALID 0x00000002
+#define IMG_IR_IRQ_DATA_VALID 0x00000001
+#define IMG_IR_IRQ_ALL 0x000000ff
+#define IMG_IR_IRQ_EDGE (IMG_IR_IRQ_FALL_EDGE | IMG_IR_IRQ_RISE_EDGE)
+
+/* IMG_IR_CORE_ID */
+#define IMG_IR_CORE_ID 0x00ff0000
+#define IMG_IR_CORE_ID_SHIFT 16
+#define IMG_IR_CORE_CONFIG 0x0000ffff
+#define IMG_IR_CORE_CONFIG_SHIFT 0
+
+/* IMG_IR_CORE_REV */
+#define IMG_IR_DESIGNER 0xff000000
+#define IMG_IR_DESIGNER_SHIFT 24
+#define IMG_IR_MAJOR_REV 0x00ff0000
+#define IMG_IR_MAJOR_REV_SHIFT 16
+#define IMG_IR_MINOR_REV 0x0000ff00
+#define IMG_IR_MINOR_REV_SHIFT 8
+#define IMG_IR_MAINT_REV 0x000000ff
+#define IMG_IR_MAINT_REV_SHIFT 0
+
+struct device;
+struct clk;
+
+/**
+ * struct img_ir_priv - Private driver data.
+ * @dev: Platform device.
+ * @irq: IRQ number.
+ * @clk: Input clock.
+ * @reg_base: Iomem base address of IR register block.
+ * @lock: Protects IR registers and variables in this struct.
+ * @raw: Driver data for raw decoder.
+ * @hw: Driver data for hardware decoder.
+ */
+struct img_ir_priv {
+ struct device *dev;
+ int irq;
+ struct clk *clk;
+ void __iomem *reg_base;
+ spinlock_t lock;
+
+ struct img_ir_priv_raw raw;
+ struct img_ir_priv_hw hw;
+};
+
+/* Hardware access */
+
+static inline void img_ir_write(struct img_ir_priv *priv,
+ unsigned int reg_offs, unsigned int data)
+{
+ iowrite32(data, priv->reg_base + reg_offs);
+}
+
+static inline unsigned int img_ir_read(struct img_ir_priv *priv,
+ unsigned int reg_offs)
+{
+ return ioread32(priv->reg_base + reg_offs);
+}
+
+#endif /* _IMG_IR_H_ */
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 822b9f47ca72..6f24e77b1488 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -1017,7 +1017,7 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_type)
unsigned char ir_proto_packet[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 };
- if (*rc_type && !(*rc_type & rc->allowed_protos))
+ if (*rc_type && !rc_protocols_allowed(rc, *rc_type))
dev_warn(dev, "Looks like you're trying to use an IR protocol "
"this device does not support\n");
@@ -1867,7 +1867,8 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
rdev->priv = ictx;
rdev->driver_type = RC_DRIVER_SCANCODE;
- rdev->allowed_protos = RC_BIT_OTHER | RC_BIT_RC6_MCE; /* iMON PAD or MCE */
+ /* iMON PAD or MCE */
+ rc_set_allowed_protocols(rdev, RC_BIT_OTHER | RC_BIT_RC6_MCE);
rdev->change_protocol = imon_ir_change_protocol;
rdev->driver_name = MOD_NAME;
@@ -1880,7 +1881,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
if (ictx->product == 0xffdc) {
imon_get_ffdc_type(ictx);
- rdev->allowed_protos = ictx->rc_type;
+ rc_set_allowed_protocols(rdev, ictx->rc_type);
}
imon_set_display_type(ictx);
diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c
index 3948138ca870..4ea62a1dcfda 100644
--- a/drivers/media/rc/ir-jvc-decoder.c
+++ b/drivers/media/rc/ir-jvc-decoder.c
@@ -47,7 +47,7 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
struct jvc_dec *data = &dev->raw->jvc;
- if (!(dev->enabled_protocols & RC_BIT_JVC))
+ if (!rc_protocols_enabled(dev, RC_BIT_JVC))
return 0;
if (!is_timing_event(ev)) {
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index ed2c8a1ed8ca..d731da6c414d 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -35,7 +35,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
struct lirc_codec *lirc = &dev->raw->lirc;
int sample;
- if (!(dev->enabled_protocols & RC_BIT_LIRC))
+ if (!rc_protocols_enabled(dev, RC_BIT_LIRC))
return 0;
if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf)
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
index 9f3c9b59f30c..0c55f794c8cf 100644
--- a/drivers/media/rc/ir-mce_kbd-decoder.c
+++ b/drivers/media/rc/ir-mce_kbd-decoder.c
@@ -216,7 +216,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
unsigned long delay;
- if (!(dev->enabled_protocols & RC_BIT_MCE_KBD))
+ if (!rc_protocols_enabled(dev, RC_BIT_MCE_KBD))
return 0;
if (!is_timing_event(ev)) {
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 9a9009411439..9de1791d2494 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -1,6 +1,6 @@
/* ir-nec-decoder.c - handle NEC IR Pulse/Space protocol
*
- * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -52,7 +52,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
u8 address, not_address, command, not_command;
bool send_32bits = false;
- if (!(dev->enabled_protocols & RC_BIT_NEC))
+ if (!rc_protocols_enabled(dev, RC_BIT_NEC))
return 0;
if (!is_timing_event(ev)) {
@@ -172,7 +172,10 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
if (send_32bits) {
/* NEC transport, but modified protocol, used by at
* least Apple and TiVo remotes */
- scancode = data->bits;
+ scancode = not_address << 24 |
+ address << 16 |
+ not_command << 8 |
+ command;
IR_dprintk(1, "NEC (modified) scancode 0x%08x\n", scancode);
} else if ((address ^ not_address) != 0xff) {
/* Extended NEC */
@@ -222,6 +225,6 @@ module_init(ir_nec_decode_init);
module_exit(ir_nec_decode_exit);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
MODULE_DESCRIPTION("NEC IR protocol decoder");
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index 5c42750c7b71..763c9d131d0f 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -1,6 +1,6 @@
/* ir-raw.c - handle IR pulse/space events
*
- * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -256,7 +256,7 @@ int ir_raw_event_register(struct rc_dev *dev)
return -ENOMEM;
dev->raw->dev = dev;
- dev->enabled_protocols = ~0;
+ rc_set_enabled_protocols(dev, ~0);
rc = kfifo_alloc(&dev->raw->kfifo,
sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE,
GFP_KERNEL);
@@ -352,6 +352,7 @@ void ir_raw_init(void)
load_jvc_decode();
load_sony_decode();
load_sanyo_decode();
+ load_sharp_decode();
load_mce_kbd_decode();
load_lirc_codec();
diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
index 4e53a319c5d8..4295d9b250c8 100644
--- a/drivers/media/rc/ir-rc5-decoder.c
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -1,6 +1,6 @@
/* ir-rc5-decoder.c - handle RC5(x) IR Pulse/Space protocol
*
- * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -52,7 +52,7 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
u8 toggle;
u32 scancode;
- if (!(dev->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X)))
+ if (!rc_protocols_enabled(dev, RC_BIT_RC5 | RC_BIT_RC5X))
return 0;
if (!is_timing_event(ev)) {
@@ -128,7 +128,7 @@ again:
if (data->wanted_bits == RC5X_NBITS) {
/* RC5X */
u8 xdata, command, system;
- if (!(dev->enabled_protocols & RC_BIT_RC5X)) {
+ if (!rc_protocols_enabled(dev, RC_BIT_RC5X)) {
data->state = STATE_INACTIVE;
return 0;
}
@@ -145,7 +145,7 @@ again:
} else {
/* RC5 */
u8 command, system;
- if (!(dev->enabled_protocols & RC_BIT_RC5)) {
+ if (!rc_protocols_enabled(dev, RC_BIT_RC5)) {
data->state = STATE_INACTIVE;
return 0;
}
@@ -193,6 +193,6 @@ module_init(ir_rc5_decode_init);
module_exit(ir_rc5_decode_exit);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
MODULE_DESCRIPTION("RC5(x) IR protocol decoder");
diff --git a/drivers/media/rc/ir-rc5-sz-decoder.c b/drivers/media/rc/ir-rc5-sz-decoder.c
index 865fe84fd854..dc18b7434db8 100644
--- a/drivers/media/rc/ir-rc5-sz-decoder.c
+++ b/drivers/media/rc/ir-rc5-sz-decoder.c
@@ -1,6 +1,6 @@
/* ir-rc5-sz-decoder.c - handle RC5 Streamzap IR Pulse/Space protocol
*
- * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2010 by Mauro Carvalho Chehab
* Copyright (C) 2010 by Jarod Wilson <jarod@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -48,7 +48,7 @@ static int ir_rc5_sz_decode(struct rc_dev *dev, struct ir_raw_event ev)
u8 toggle, command, system;
u32 scancode;
- if (!(dev->enabled_protocols & RC_BIT_RC5_SZ))
+ if (!rc_protocols_enabled(dev, RC_BIT_RC5_SZ))
return 0;
if (!is_timing_event(ev)) {
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index 7cba7d33a3fa..cfbd64e3999c 100644
--- a/drivers/media/rc/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -89,9 +89,9 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
u8 toggle;
- if (!(dev->enabled_protocols &
- (RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 |
- RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE)))
+ if (!rc_protocols_enabled(dev, RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 |
+ RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 |
+ RC_BIT_RC6_MCE))
return 0;
if (!is_timing_event(ev)) {
diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
index 0a06205b5677..eb715f04dc27 100644
--- a/drivers/media/rc/ir-sanyo-decoder.c
+++ b/drivers/media/rc/ir-sanyo-decoder.c
@@ -1,6 +1,6 @@
/* ir-sanyo-decoder.c - handle SANYO IR Pulse/Space protocol
*
- * Copyright (C) 2011 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2011 by Mauro Carvalho Chehab
*
* 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
@@ -58,7 +58,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
u8 address, command, not_command;
- if (!(dev->enabled_protocols & RC_BIT_SANYO))
+ if (!rc_protocols_enabled(dev, RC_BIT_SANYO))
return 0;
if (!is_timing_event(ev)) {
@@ -200,6 +200,6 @@ module_init(ir_sanyo_decode_init);
module_exit(ir_sanyo_decode_exit);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
MODULE_DESCRIPTION("SANYO IR protocol decoder");
diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c
new file mode 100644
index 000000000000..66d20394ceaa
--- /dev/null
+++ b/drivers/media/rc/ir-sharp-decoder.c
@@ -0,0 +1,200 @@
+/* ir-sharp-decoder.c - handle Sharp IR Pulse/Space protocol
+ *
+ * Copyright (C) 2013-2014 Imagination Technologies Ltd.
+ *
+ * Based on NEC decoder:
+ * Copyright (C) 2010 by Mauro Carvalho Chehab
+ *
+ * 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.
+ */
+
+#include <linux/bitrev.h>
+#include <linux/module.h>
+#include "rc-core-priv.h"
+
+#define SHARP_NBITS 15
+#define SHARP_UNIT 40000 /* ns */
+#define SHARP_BIT_PULSE (8 * SHARP_UNIT) /* 320us */
+#define SHARP_BIT_0_PERIOD (25 * SHARP_UNIT) /* 1ms (680us space) */
+#define SHARP_BIT_1_PERIOD (50 * SHARP_UNIT) /* 2ms (1680ms space) */
+#define SHARP_ECHO_SPACE (1000 * SHARP_UNIT) /* 40 ms */
+#define SHARP_TRAILER_SPACE (125 * SHARP_UNIT) /* 5 ms (even longer) */
+
+enum sharp_state {
+ STATE_INACTIVE,
+ STATE_BIT_PULSE,
+ STATE_BIT_SPACE,
+ STATE_TRAILER_PULSE,
+ STATE_ECHO_SPACE,
+ STATE_TRAILER_SPACE,
+};
+
+/**
+ * ir_sharp_decode() - Decode one Sharp pulse or space
+ * @dev: the struct rc_dev descriptor of the device
+ * @duration: the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This function returns -EINVAL if the pulse violates the state machine
+ */
+static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
+{
+ struct sharp_dec *data = &dev->raw->sharp;
+ u32 msg, echo, address, command, scancode;
+
+ if (!rc_protocols_enabled(dev, RC_BIT_SHARP))
+ return 0;
+
+ if (!is_timing_event(ev)) {
+ if (ev.reset)
+ data->state = STATE_INACTIVE;
+ return 0;
+ }
+
+ IR_dprintk(2, "Sharp decode started at state %d (%uus %s)\n",
+ data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+
+ switch (data->state) {
+
+ case STATE_INACTIVE:
+ if (!ev.pulse)
+ break;
+
+ if (!eq_margin(ev.duration, SHARP_BIT_PULSE,
+ SHARP_BIT_PULSE / 2))
+ break;
+
+ data->count = 0;
+ data->pulse_len = ev.duration;
+ data->state = STATE_BIT_SPACE;
+ return 0;
+
+ case STATE_BIT_PULSE:
+ if (!ev.pulse)
+ break;
+
+ if (!eq_margin(ev.duration, SHARP_BIT_PULSE,
+ SHARP_BIT_PULSE / 2))
+ break;
+
+ data->pulse_len = ev.duration;
+ data->state = STATE_BIT_SPACE;
+ return 0;
+
+ case STATE_BIT_SPACE:
+ if (ev.pulse)
+ break;
+
+ data->bits <<= 1;
+ if (eq_margin(data->pulse_len + ev.duration, SHARP_BIT_1_PERIOD,
+ SHARP_BIT_PULSE * 2))
+ data->bits |= 1;
+ else if (!eq_margin(data->pulse_len + ev.duration,
+ SHARP_BIT_0_PERIOD, SHARP_BIT_PULSE * 2))
+ break;
+ data->count++;
+
+ if (data->count == SHARP_NBITS ||
+ data->count == SHARP_NBITS * 2)
+ data->state = STATE_TRAILER_PULSE;
+ else
+ data->state = STATE_BIT_PULSE;
+
+ return 0;
+
+ case STATE_TRAILER_PULSE:
+ if (!ev.pulse)
+ break;
+
+ if (!eq_margin(ev.duration, SHARP_BIT_PULSE,
+ SHARP_BIT_PULSE / 2))
+ break;
+
+ if (data->count == SHARP_NBITS) {
+ /* exp,chk bits should be 1,0 */
+ if ((data->bits & 0x3) != 0x2)
+ break;
+ data->state = STATE_ECHO_SPACE;
+ } else {
+ data->state = STATE_TRAILER_SPACE;
+ }
+ return 0;
+
+ case STATE_ECHO_SPACE:
+ if (ev.pulse)
+ break;
+
+ if (!eq_margin(ev.duration, SHARP_ECHO_SPACE,
+ SHARP_ECHO_SPACE / 4))
+ break;
+
+ data->state = STATE_BIT_PULSE;
+
+ return 0;
+
+ case STATE_TRAILER_SPACE:
+ if (ev.pulse)
+ break;
+
+ if (!geq_margin(ev.duration, SHARP_TRAILER_SPACE,
+ SHARP_BIT_PULSE / 2))
+ break;
+
+ /* Validate - command, ext, chk should be inverted in 2nd */
+ msg = (data->bits >> 15) & 0x7fff;
+ echo = data->bits & 0x7fff;
+ if ((msg ^ echo) != 0x3ff) {
+ IR_dprintk(1,
+ "Sharp checksum error: received 0x%04x, 0x%04x\n",
+ msg, echo);
+ break;
+ }
+
+ address = bitrev8((msg >> 7) & 0xf8);
+ command = bitrev8((msg >> 2) & 0xff);
+
+ scancode = address << 8 | command;
+ IR_dprintk(1, "Sharp scancode 0x%04x\n", scancode);
+
+ rc_keydown(dev, scancode, 0);
+ data->state = STATE_INACTIVE;
+ return 0;
+ }
+
+ IR_dprintk(1, "Sharp decode failed at count %d state %d (%uus %s)\n",
+ data->count, data->state, TO_US(ev.duration),
+ TO_STR(ev.pulse));
+ data->state = STATE_INACTIVE;
+ return -EINVAL;
+}
+
+static struct ir_raw_handler sharp_handler = {
+ .protocols = RC_BIT_SHARP,
+ .decode = ir_sharp_decode,
+};
+
+static int __init ir_sharp_decode_init(void)
+{
+ ir_raw_handler_register(&sharp_handler);
+
+ pr_info("IR Sharp protocol handler initialized\n");
+ return 0;
+}
+
+static void __exit ir_sharp_decode_exit(void)
+{
+ ir_raw_handler_unregister(&sharp_handler);
+}
+
+module_init(ir_sharp_decode_init);
+module_exit(ir_sharp_decode_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("James Hogan <james.hogan@imgtec.com>");
+MODULE_DESCRIPTION("Sharp IR protocol decoder");
diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c
index 29ab9c2db060..599c19a73360 100644
--- a/drivers/media/rc/ir-sony-decoder.c
+++ b/drivers/media/rc/ir-sony-decoder.c
@@ -45,8 +45,8 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
u8 device, subdevice, function;
- if (!(dev->enabled_protocols &
- (RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20)))
+ if (!rc_protocols_enabled(dev, RC_BIT_SONY12 | RC_BIT_SONY15 |
+ RC_BIT_SONY20))
return 0;
if (!is_timing_event(ev)) {
@@ -124,7 +124,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
switch (data->count) {
case 12:
- if (!(dev->enabled_protocols & RC_BIT_SONY12)) {
+ if (!rc_protocols_enabled(dev, RC_BIT_SONY12)) {
data->state = STATE_INACTIVE;
return 0;
}
@@ -133,7 +133,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
function = bitrev8((data->bits >> 4) & 0xFE);
break;
case 15:
- if (!(dev->enabled_protocols & RC_BIT_SONY15)) {
+ if (!rc_protocols_enabled(dev, RC_BIT_SONY15)) {
data->state = STATE_INACTIVE;
return 0;
}
@@ -142,7 +142,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
function = bitrev8((data->bits >> 7) & 0xFE);
break;
case 20:
- if (!(dev->enabled_protocols & RC_BIT_SONY20)) {
+ if (!rc_protocols_enabled(dev, RC_BIT_SONY20)) {
data->state = STATE_INACTIVE;
return 0;
}
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index 63b42252166a..ab24cc6d3655 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -1563,7 +1563,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
/* set up ir-core props */
rdev->priv = itdev;
rdev->driver_type = RC_DRIVER_IR_RAW;
- rdev->allowed_protos = RC_BIT_ALL;
+ rc_set_allowed_protocols(rdev, RC_BIT_ALL);
rdev->open = ite_open;
rdev->close = ite_close;
rdev->s_idle = ite_s_idle;
diff --git a/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c
index b0e42df7ff82..01d901fbfc8b 100644
--- a/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c
+++ b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -87,4 +87,4 @@ module_init(init_rc_map_adstech_dvb_t_pci)
module_exit(exit_rc_map_adstech_dvb_t_pci)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-apac-viewcomp.c b/drivers/media/rc/keymaps/rc-apac-viewcomp.c
index 8c92ff95f94d..bf9efa007e1c 100644
--- a/drivers/media/rc/keymaps/rc-apac-viewcomp.c
+++ b/drivers/media/rc/keymaps/rc-apac-viewcomp.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -78,4 +78,4 @@ module_init(init_rc_map_apac_viewcomp)
module_exit(exit_rc_map_apac_viewcomp)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-asus-pc39.c b/drivers/media/rc/keymaps/rc-asus-pc39.c
index 2caf2117759b..9e674ba5dd4f 100644
--- a/drivers/media/rc/keymaps/rc-asus-pc39.c
+++ b/drivers/media/rc/keymaps/rc-asus-pc39.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -89,4 +89,4 @@ module_init(init_rc_map_asus_pc39)
module_exit(exit_rc_map_asus_pc39)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-asus-ps3-100.c b/drivers/media/rc/keymaps/rc-asus-ps3-100.c
index ba76609c5936..e45de35f528f 100644
--- a/drivers/media/rc/keymaps/rc-asus-ps3-100.c
+++ b/drivers/media/rc/keymaps/rc-asus-ps3-100.c
@@ -1,6 +1,6 @@
/* asus-ps3-100.h - Keytable for asus_ps3_100 Remote Controller
*
- * Copyright (c) 2012 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2012 by Mauro Carvalho Chehab
*
* Based on a previous patch from Remi Schwartz <remi.schwartz@gmail.com>
*
@@ -88,4 +88,4 @@ module_init(init_rc_map_asus_ps3_100)
module_exit(exit_rc_map_asus_ps3_100)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c b/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c
index 2031224a2027..91392d4cfd6d 100644
--- a/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c
+++ b/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -67,4 +67,4 @@ module_init(init_rc_map_ati_tv_wonder_hd_600)
module_exit(exit_rc_map_ati_tv_wonder_hd_600)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-avermedia-a16d.c b/drivers/media/rc/keymaps/rc-avermedia-a16d.c
index 894939ac17f2..ff30a71d623e 100644
--- a/drivers/media/rc/keymaps/rc-avermedia-a16d.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-a16d.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -73,4 +73,4 @@ module_init(init_rc_map_avermedia_a16d)
module_exit(exit_rc_map_avermedia_a16d)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c
index d2aaf5b9e39f..d7471a6de9b4 100644
--- a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -95,4 +95,4 @@ module_init(init_rc_map_avermedia_cardbus)
module_exit(exit_rc_map_avermedia_cardbus)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c
index dc2baf062398..e2417d6331fe 100644
--- a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -76,4 +76,4 @@ module_init(init_rc_map_avermedia_dvbt)
module_exit(exit_rc_map_avermedia_dvbt)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-avermedia-m135a.c b/drivers/media/rc/keymaps/rc-avermedia-m135a.c
index 04269d31fa19..843598a5f1b5 100644
--- a/drivers/media/rc/keymaps/rc-avermedia-m135a.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-m135a.c
@@ -1,6 +1,6 @@
/* avermedia-m135a.c - Keytable for Avermedia M135A Remote Controllers
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
* Copyright (c) 2010 by Herton Ronaldo Krzesinski <herton@mandriva.com.br>
*
* This program is free software; you can redistribute it and/or modify
@@ -145,4 +145,4 @@ module_init(init_rc_map_avermedia_m135a)
module_exit(exit_rc_map_avermedia_m135a)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c
index e83b1a1939bf..b24e7481ac21 100644
--- a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c
@@ -93,4 +93,4 @@ module_init(init_rc_map_avermedia_m733a_rm_k6)
module_exit(exit_rc_map_avermedia_m733a_rm_k6)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-avermedia.c b/drivers/media/rc/keymaps/rc-avermedia.c
index c6063dfcd507..3f68fbecc188 100644
--- a/drivers/media/rc/keymaps/rc-avermedia.c
+++ b/drivers/media/rc/keymaps/rc-avermedia.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -84,4 +84,4 @@ module_init(init_rc_map_avermedia)
module_exit(exit_rc_map_avermedia)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-avertv-303.c b/drivers/media/rc/keymaps/rc-avertv-303.c
index 14f78451e64e..c35bc5b835c4 100644
--- a/drivers/media/rc/keymaps/rc-avertv-303.c
+++ b/drivers/media/rc/keymaps/rc-avertv-303.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -83,4 +83,4 @@ module_init(init_rc_map_avertv_303)
module_exit(exit_rc_map_avertv_303)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-behold-columbus.c b/drivers/media/rc/keymaps/rc-behold-columbus.c
index 086b4b1f19e1..1fc344e9daa7 100644
--- a/drivers/media/rc/keymaps/rc-behold-columbus.c
+++ b/drivers/media/rc/keymaps/rc-behold-columbus.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -106,4 +106,4 @@ module_init(init_rc_map_behold_columbus)
module_exit(exit_rc_map_behold_columbus)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-behold.c b/drivers/media/rc/keymaps/rc-behold.c
index 0877e3480941..d6519f8ac95a 100644
--- a/drivers/media/rc/keymaps/rc-behold.c
+++ b/drivers/media/rc/keymaps/rc-behold.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -139,4 +139,4 @@ module_init(init_rc_map_behold)
module_exit(exit_rc_map_behold)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-budget-ci-old.c b/drivers/media/rc/keymaps/rc-budget-ci-old.c
index 8311e092c098..b196a5f436a3 100644
--- a/drivers/media/rc/keymaps/rc-budget-ci-old.c
+++ b/drivers/media/rc/keymaps/rc-budget-ci-old.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -91,4 +91,4 @@ module_init(init_rc_map_budget_ci_old)
module_exit(exit_rc_map_budget_ci_old)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-cinergy-1400.c b/drivers/media/rc/keymaps/rc-cinergy-1400.c
index 0c87fbaf99ab..a099c080bf8c 100644
--- a/drivers/media/rc/keymaps/rc-cinergy-1400.c
+++ b/drivers/media/rc/keymaps/rc-cinergy-1400.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -82,4 +82,4 @@ module_init(init_rc_map_cinergy_1400)
module_exit(exit_rc_map_cinergy_1400)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-cinergy.c b/drivers/media/rc/keymaps/rc-cinergy.c
index 309e9e3fb6f3..b0f4328bdd6f 100644
--- a/drivers/media/rc/keymaps/rc-cinergy.c
+++ b/drivers/media/rc/keymaps/rc-cinergy.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -76,4 +76,4 @@ module_init(init_rc_map_cinergy)
module_exit(exit_rc_map_cinergy)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-dib0700-nec.c b/drivers/media/rc/keymaps/rc-dib0700-nec.c
index 492a05ade7e1..a0fa543c9f9e 100644
--- a/drivers/media/rc/keymaps/rc-dib0700-nec.c
+++ b/drivers/media/rc/keymaps/rc-dib0700-nec.c
@@ -1,6 +1,6 @@
/* rc-dvb0700-big.c - Keytable for devices in dvb0700
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* TODO: This table is a real mess, as it merges RC codes from several
* devices into a big table. It also has both RC-5 and NEC codes inside.
@@ -122,4 +122,4 @@ module_init(init_rc_map)
module_exit(exit_rc_map)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-dib0700-rc5.c b/drivers/media/rc/keymaps/rc-dib0700-rc5.c
index 454ea596a7ee..907941145eb7 100644
--- a/drivers/media/rc/keymaps/rc-dib0700-rc5.c
+++ b/drivers/media/rc/keymaps/rc-dib0700-rc5.c
@@ -1,6 +1,6 @@
/* rc-dvb0700-big.c - Keytable for devices in dvb0700
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* TODO: This table is a real mess, as it merges RC codes from several
* devices into a big table. It also has both RC-5 and NEC codes inside.
@@ -233,4 +233,4 @@ module_init(init_rc_map)
module_exit(exit_rc_map)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-dm1105-nec.c b/drivers/media/rc/keymaps/rc-dm1105-nec.c
index 67fc9fb0c007..46e7ae414cc8 100644
--- a/drivers/media/rc/keymaps/rc-dm1105-nec.c
+++ b/drivers/media/rc/keymaps/rc-dm1105-nec.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -74,4 +74,4 @@ module_init(init_rc_map_dm1105_nec)
module_exit(exit_rc_map_dm1105_nec)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c
index 91ea91de9179..d2826b46fea2 100644
--- a/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c
+++ b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -76,4 +76,4 @@ module_init(init_rc_map_dntv_live_dvb_t)
module_exit(exit_rc_map_dntv_live_dvb_t)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c
index fd680d4d3eb6..0d74769467b5 100644
--- a/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c
+++ b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -95,4 +95,4 @@ module_init(init_rc_map_dntv_live_dvbt_pro)
module_exit(exit_rc_map_dntv_live_dvbt_pro)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-em-terratec.c b/drivers/media/rc/keymaps/rc-em-terratec.c
index d1fcd64c0f90..7f1e06be175b 100644
--- a/drivers/media/rc/keymaps/rc-em-terratec.c
+++ b/drivers/media/rc/keymaps/rc-em-terratec.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -67,4 +67,4 @@ module_init(init_rc_map_em_terratec)
module_exit(exit_rc_map_em_terratec)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c
index 2fe45e41fe49..4fc3904daf06 100644
--- a/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c
+++ b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -79,4 +79,4 @@ module_init(init_rc_map_encore_enltv_fm53)
module_exit(exit_rc_map_encore_enltv_fm53)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-encore-enltv.c b/drivers/media/rc/keymaps/rc-encore-enltv.c
index 223de75a6d1c..f1914e23d203 100644
--- a/drivers/media/rc/keymaps/rc-encore-enltv.c
+++ b/drivers/media/rc/keymaps/rc-encore-enltv.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -110,4 +110,4 @@ module_init(init_rc_map_encore_enltv)
module_exit(exit_rc_map_encore_enltv)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-encore-enltv2.c b/drivers/media/rc/keymaps/rc-encore-enltv2.c
index 669cbff22b7e..9c6c55240d18 100644
--- a/drivers/media/rc/keymaps/rc-encore-enltv2.c
+++ b/drivers/media/rc/keymaps/rc-encore-enltv2.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -88,4 +88,4 @@ module_init(init_rc_map_encore_enltv2)
module_exit(exit_rc_map_encore_enltv2)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-evga-indtube.c b/drivers/media/rc/keymaps/rc-evga-indtube.c
index 2c647fc25916..2370d2a3deb6 100644
--- a/drivers/media/rc/keymaps/rc-evga-indtube.c
+++ b/drivers/media/rc/keymaps/rc-evga-indtube.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -59,4 +59,4 @@ module_init(init_rc_map_evga_indtube)
module_exit(exit_rc_map_evga_indtube)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-eztv.c b/drivers/media/rc/keymaps/rc-eztv.c
index 76921445c1d9..b5c96ed84376 100644
--- a/drivers/media/rc/keymaps/rc-eztv.c
+++ b/drivers/media/rc/keymaps/rc-eztv.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -94,4 +94,4 @@ module_init(init_rc_map_eztv)
module_exit(exit_rc_map_eztv)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-flydvb.c b/drivers/media/rc/keymaps/rc-flydvb.c
index 3a6bba311b08..25cb89fac03c 100644
--- a/drivers/media/rc/keymaps/rc-flydvb.c
+++ b/drivers/media/rc/keymaps/rc-flydvb.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -75,4 +75,4 @@ module_init(init_rc_map_flydvb)
module_exit(exit_rc_map_flydvb)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-flyvideo.c b/drivers/media/rc/keymaps/rc-flyvideo.c
index bf9da584643b..e71377dd0534 100644
--- a/drivers/media/rc/keymaps/rc-flyvideo.c
+++ b/drivers/media/rc/keymaps/rc-flyvideo.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -68,4 +68,4 @@ module_init(init_rc_map_flyvideo)
module_exit(exit_rc_map_flyvideo)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c
index 2f0970fe7832..cf0608dc83d5 100644
--- a/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c
+++ b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -96,4 +96,4 @@ module_init(init_rc_map_fusionhdtv_mce)
module_exit(exit_rc_map_fusionhdtv_mce)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-gadmei-rm008z.c b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c
index 0e98ec467c34..03575bdb2eca 100644
--- a/drivers/media/rc/keymaps/rc-gadmei-rm008z.c
+++ b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -79,4 +79,4 @@ module_init(init_rc_map_gadmei_rm008z)
module_exit(exit_rc_map_gadmei_rm008z)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c
index a2e2faa1d1b3..b2ab13b0dcb1 100644
--- a/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c
+++ b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -82,4 +82,4 @@ module_init(init_rc_map_genius_tvgo_a11mce)
module_exit(exit_rc_map_genius_tvgo_a11mce)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-gotview7135.c b/drivers/media/rc/keymaps/rc-gotview7135.c
index 864614e19314..229a36ac7f0a 100644
--- a/drivers/media/rc/keymaps/rc-gotview7135.c
+++ b/drivers/media/rc/keymaps/rc-gotview7135.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -77,4 +77,4 @@ module_init(init_rc_map_gotview7135)
module_exit(exit_rc_map_gotview7135)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-hauppauge.c b/drivers/media/rc/keymaps/rc-hauppauge.c
index 929bbbc16393..36d57f7c532b 100644
--- a/drivers/media/rc/keymaps/rc-hauppauge.c
+++ b/drivers/media/rc/keymaps/rc-hauppauge.c
@@ -8,7 +8,7 @@
* - Hauppauge Black;
* - DSR-0112 remote bundled with Haupauge MiniStick.
*
- * Copyright (c) 2010-2011 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010-2011 by Mauro Carvalho Chehab
*
* 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
@@ -290,4 +290,4 @@ module_init(init_rc_map_rc5_hauppauge_new)
module_exit(exit_rc_map_rc5_hauppauge_new)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-iodata-bctv7e.c b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c
index 34540dfc3df5..9ee154cb0c6b 100644
--- a/drivers/media/rc/keymaps/rc-iodata-bctv7e.c
+++ b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -86,4 +86,4 @@ module_init(init_rc_map_iodata_bctv7e)
module_exit(exit_rc_map_iodata_bctv7e)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-kaiomy.c b/drivers/media/rc/keymaps/rc-kaiomy.c
index 4264a787c150..60803a732c08 100644
--- a/drivers/media/rc/keymaps/rc-kaiomy.c
+++ b/drivers/media/rc/keymaps/rc-kaiomy.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -85,4 +85,4 @@ module_init(init_rc_map_kaiomy)
module_exit(exit_rc_map_kaiomy)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-kworld-315u.c b/drivers/media/rc/keymaps/rc-kworld-315u.c
index e48cd267dda6..ba087eed1ed9 100644
--- a/drivers/media/rc/keymaps/rc-kworld-315u.c
+++ b/drivers/media/rc/keymaps/rc-kworld-315u.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -81,4 +81,4 @@ module_init(init_rc_map_kworld_315u)
module_exit(exit_rc_map_kworld_315u)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-kworld-pc150u.c b/drivers/media/rc/keymaps/rc-kworld-pc150u.c
index 233bb5ee087f..b92e571f4def 100644
--- a/drivers/media/rc/keymaps/rc-kworld-pc150u.c
+++ b/drivers/media/rc/keymaps/rc-kworld-pc150u.c
@@ -4,7 +4,7 @@
*
* Copyright (c) 2010 by Kyle Strickland
* (based on kworld-plus-tv-analog.c by
- * Mauro Carvalho Chehab <mchehab@redhat.com>)
+ * Mauro Carvalho Chehab)
*
* 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/media/rc/keymaps/rc-kworld-plus-tv-analog.c b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c
index 32998d6b787d..edc868564f99 100644
--- a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c
+++ b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -97,4 +97,4 @@ module_init(init_rc_map_kworld_plus_tv_analog)
module_exit(exit_rc_map_kworld_plus_tv_analog)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-manli.c b/drivers/media/rc/keymaps/rc-manli.c
index e7038bb71bf6..92424ef2aaa6 100644
--- a/drivers/media/rc/keymaps/rc-manli.c
+++ b/drivers/media/rc/keymaps/rc-manli.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -132,4 +132,4 @@ module_init(init_rc_map_manli)
module_exit(exit_rc_map_manli)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c
index c393d8a50bca..fd7a55c56167 100644
--- a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c
+++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -121,4 +121,4 @@ module_init(init_rc_map_msi_tvanywhere_plus)
module_exit(exit_rc_map_msi_tvanywhere_plus)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c
index a7003d3a3c8a..4233a8d4d63e 100644
--- a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c
+++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -67,4 +67,4 @@ module_init(init_rc_map_msi_tvanywhere)
module_exit(exit_rc_map_msi_tvanywhere)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-nebula.c b/drivers/media/rc/keymaps/rc-nebula.c
index 3f0ddd7afd30..8ec881adb7cf 100644
--- a/drivers/media/rc/keymaps/rc-nebula.c
+++ b/drivers/media/rc/keymaps/rc-nebula.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -94,4 +94,4 @@ module_init(init_rc_map_nebula)
module_exit(exit_rc_map_nebula)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c
index 8d4dae2e2ece..292bbad35d21 100644
--- a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c
+++ b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -14,7 +14,7 @@
#include <linux/module.h>
/* Terratec Cinergy Hybrid T USB XS FM
- Mauro Carvalho Chehab <mchehab@redhat.com>
+ Mauro Carvalho Chehab
*/
static struct rc_map_table nec_terratec_cinergy_xs[] = {
@@ -155,4 +155,4 @@ module_init(init_rc_map_nec_terratec_cinergy_xs)
module_exit(exit_rc_map_nec_terratec_cinergy_xs)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-norwood.c b/drivers/media/rc/keymaps/rc-norwood.c
index 9e65f07157ab..ca1b82a2c54f 100644
--- a/drivers/media/rc/keymaps/rc-norwood.c
+++ b/drivers/media/rc/keymaps/rc-norwood.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -83,4 +83,4 @@ module_init(init_rc_map_norwood)
module_exit(exit_rc_map_norwood)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-npgtech.c b/drivers/media/rc/keymaps/rc-npgtech.c
index 65d0cfc3c33b..1fb946024512 100644
--- a/drivers/media/rc/keymaps/rc-npgtech.c
+++ b/drivers/media/rc/keymaps/rc-npgtech.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -78,4 +78,4 @@ module_init(init_rc_map_npgtech)
module_exit(exit_rc_map_npgtech)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-pctv-sedna.c b/drivers/media/rc/keymaps/rc-pctv-sedna.c
index bf2cbdfe2e32..5ef01ab3fd50 100644
--- a/drivers/media/rc/keymaps/rc-pctv-sedna.c
+++ b/drivers/media/rc/keymaps/rc-pctv-sedna.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -78,4 +78,4 @@ module_init(init_rc_map_pctv_sedna)
module_exit(exit_rc_map_pctv_sedna)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-pinnacle-color.c b/drivers/media/rc/keymaps/rc-pinnacle-color.c
index b46cd8fe6438..a218b471a4ca 100644
--- a/drivers/media/rc/keymaps/rc-pinnacle-color.c
+++ b/drivers/media/rc/keymaps/rc-pinnacle-color.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -92,4 +92,4 @@ module_init(init_rc_map_pinnacle_color)
module_exit(exit_rc_map_pinnacle_color)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-pinnacle-grey.c b/drivers/media/rc/keymaps/rc-pinnacle-grey.c
index d525df9ad868..4a3f467a47a2 100644
--- a/drivers/media/rc/keymaps/rc-pinnacle-grey.c
+++ b/drivers/media/rc/keymaps/rc-pinnacle-grey.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -87,4 +87,4 @@ module_init(init_rc_map_pinnacle_grey)
module_exit(exit_rc_map_pinnacle_grey)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c
index a4603d035374..e89cc10b68bf 100644
--- a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c
+++ b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -68,4 +68,4 @@ module_init(init_rc_map_pinnacle_pctv_hd)
module_exit(exit_rc_map_pinnacle_pctv_hd)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-pixelview-002t.c b/drivers/media/rc/keymaps/rc-pixelview-002t.c
index 33eb64333c6f..d967c3816fdc 100644
--- a/drivers/media/rc/keymaps/rc-pixelview-002t.c
+++ b/drivers/media/rc/keymaps/rc-pixelview-002t.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -75,4 +75,4 @@ module_init(init_rc_map_pixelview)
module_exit(exit_rc_map_pixelview)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-pixelview-mk12.c b/drivers/media/rc/keymaps/rc-pixelview-mk12.c
index 21f4dd25c2ec..224d0efaa6e5 100644
--- a/drivers/media/rc/keymaps/rc-pixelview-mk12.c
+++ b/drivers/media/rc/keymaps/rc-pixelview-mk12.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -81,4 +81,4 @@ module_init(init_rc_map_pixelview)
module_exit(exit_rc_map_pixelview)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-pixelview-new.c b/drivers/media/rc/keymaps/rc-pixelview-new.c
index f944ad2cac2b..781d788d6b6d 100644
--- a/drivers/media/rc/keymaps/rc-pixelview-new.c
+++ b/drivers/media/rc/keymaps/rc-pixelview-new.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -81,4 +81,4 @@ module_init(init_rc_map_pixelview_new)
module_exit(exit_rc_map_pixelview_new)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-pixelview.c b/drivers/media/rc/keymaps/rc-pixelview.c
index a6020eea7b95..39e6feaa35a3 100644
--- a/drivers/media/rc/keymaps/rc-pixelview.c
+++ b/drivers/media/rc/keymaps/rc-pixelview.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -80,4 +80,4 @@ module_init(init_rc_map_pixelview)
module_exit(exit_rc_map_pixelview)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-powercolor-real-angel.c b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c
index e74c571a5e44..e96fa3ab9f4b 100644
--- a/drivers/media/rc/keymaps/rc-powercolor-real-angel.c
+++ b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -79,4 +79,4 @@ module_init(init_rc_map_powercolor_real_angel)
module_exit(exit_rc_map_powercolor_real_angel)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-proteus-2309.c b/drivers/media/rc/keymaps/rc-proteus-2309.c
index adee8035ce96..eef626ee02df 100644
--- a/drivers/media/rc/keymaps/rc-proteus-2309.c
+++ b/drivers/media/rc/keymaps/rc-proteus-2309.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -67,4 +67,4 @@ module_init(init_rc_map_proteus_2309)
module_exit(exit_rc_map_proteus_2309)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-purpletv.c b/drivers/media/rc/keymaps/rc-purpletv.c
index 722597a20e4a..cec6fe466829 100644
--- a/drivers/media/rc/keymaps/rc-purpletv.c
+++ b/drivers/media/rc/keymaps/rc-purpletv.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -79,4 +79,4 @@ module_init(init_rc_map_purpletv)
module_exit(exit_rc_map_purpletv)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-pv951.c b/drivers/media/rc/keymaps/rc-pv951.c
index 0105d63c07a9..5ac89ce8c053 100644
--- a/drivers/media/rc/keymaps/rc-pv951.c
+++ b/drivers/media/rc/keymaps/rc-pv951.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -76,4 +76,4 @@ module_init(init_rc_map_pv951)
module_exit(exit_rc_map_pv951)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c
index 073694d50f49..9f778bd091db 100644
--- a/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c
+++ b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -76,4 +76,4 @@ module_init(init_rc_map_real_audio_220_32_keys)
module_exit(exit_rc_map_real_audio_220_32_keys)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-tbs-nec.c b/drivers/media/rc/keymaps/rc-tbs-nec.c
index 5039be782bc5..24ce2a252502 100644
--- a/drivers/media/rc/keymaps/rc-tbs-nec.c
+++ b/drivers/media/rc/keymaps/rc-tbs-nec.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -73,4 +73,4 @@ module_init(init_rc_map_tbs_nec)
module_exit(exit_rc_map_tbs_nec)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c
index 53629fb0151f..97eb83ab5a35 100644
--- a/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c
+++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -90,4 +90,4 @@ module_init(init_rc_map_terratec_cinergy_xs)
module_exit(exit_rc_map_terratec_cinergy_xs)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-tevii-nec.c b/drivers/media/rc/keymaps/rc-tevii-nec.c
index f2c3b75d8580..38e0c0875596 100644
--- a/drivers/media/rc/keymaps/rc-tevii-nec.c
+++ b/drivers/media/rc/keymaps/rc-tevii-nec.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -86,4 +86,4 @@ module_init(init_rc_map_tevii_nec)
module_exit(exit_rc_map_tevii_nec)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-tivo.c b/drivers/media/rc/keymaps/rc-tivo.c
index 454e06295692..5cc1b456e329 100644
--- a/drivers/media/rc/keymaps/rc-tivo.c
+++ b/drivers/media/rc/keymaps/rc-tivo.c
@@ -15,62 +15,62 @@
* Initial mapping is for the TiVo remote included in the Nero LiquidTV bundle,
* which also ships with a TiVo-branded IR transceiver, supported by the mceusb
* driver. Note that the remote uses an NEC-ish protocol, but instead of having
- * a command/not_command pair, it has a vendor ID of 0xa10c, but some keys, the
+ * a command/not_command pair, it has a vendor ID of 0x3085, but some keys, the
* NEC extended checksums do pass, so the table presently has the intended
* values and the checksum-passed versions for those keys.
*/
static struct rc_map_table tivo[] = {
- { 0xa10c900f, KEY_MEDIA }, /* TiVo Button */
- { 0xa10c0807, KEY_POWER2 }, /* TV Power */
- { 0xa10c8807, KEY_TV }, /* Live TV/Swap */
- { 0xa10c2c03, KEY_VIDEO_NEXT }, /* TV Input */
- { 0xa10cc807, KEY_INFO },
- { 0xa10cfa05, KEY_CYCLEWINDOWS }, /* Window */
+ { 0x3085f009, KEY_MEDIA }, /* TiVo Button */
+ { 0x3085e010, KEY_POWER2 }, /* TV Power */
+ { 0x3085e011, KEY_TV }, /* Live TV/Swap */
+ { 0x3085c034, KEY_VIDEO_NEXT }, /* TV Input */
+ { 0x3085e013, KEY_INFO },
+ { 0x3085a05f, KEY_CYCLEWINDOWS }, /* Window */
{ 0x0085305f, KEY_CYCLEWINDOWS },
- { 0xa10c6c03, KEY_EPG }, /* Guide */
+ { 0x3085c036, KEY_EPG }, /* Guide */
- { 0xa10c2807, KEY_UP },
- { 0xa10c6807, KEY_DOWN },
- { 0xa10ce807, KEY_LEFT },
- { 0xa10ca807, KEY_RIGHT },
+ { 0x3085e014, KEY_UP },
+ { 0x3085e016, KEY_DOWN },
+ { 0x3085e017, KEY_LEFT },
+ { 0x3085e015, KEY_RIGHT },
- { 0xa10c1807, KEY_SCROLLDOWN }, /* Red Thumbs Down */
- { 0xa10c9807, KEY_SELECT },
- { 0xa10c5807, KEY_SCROLLUP }, /* Green Thumbs Up */
+ { 0x3085e018, KEY_SCROLLDOWN }, /* Red Thumbs Down */
+ { 0x3085e019, KEY_SELECT },
+ { 0x3085e01a, KEY_SCROLLUP }, /* Green Thumbs Up */
- { 0xa10c3807, KEY_VOLUMEUP },
- { 0xa10cb807, KEY_VOLUMEDOWN },
- { 0xa10cd807, KEY_MUTE },
- { 0xa10c040b, KEY_RECORD },
- { 0xa10c7807, KEY_CHANNELUP },
- { 0xa10cf807, KEY_CHANNELDOWN },
+ { 0x3085e01c, KEY_VOLUMEUP },
+ { 0x3085e01d, KEY_VOLUMEDOWN },
+ { 0x3085e01b, KEY_MUTE },
+ { 0x3085d020, KEY_RECORD },
+ { 0x3085e01e, KEY_CHANNELUP },
+ { 0x3085e01f, KEY_CHANNELDOWN },
{ 0x0085301f, KEY_CHANNELDOWN },
- { 0xa10c840b, KEY_PLAY },
- { 0xa10cc40b, KEY_PAUSE },
- { 0xa10ca40b, KEY_SLOW },
- { 0xa10c440b, KEY_REWIND },
- { 0xa10c240b, KEY_FASTFORWARD },
- { 0xa10c640b, KEY_PREVIOUS },
- { 0xa10ce40b, KEY_NEXT }, /* ->| */
+ { 0x3085d021, KEY_PLAY },
+ { 0x3085d023, KEY_PAUSE },
+ { 0x3085d025, KEY_SLOW },
+ { 0x3085d022, KEY_REWIND },
+ { 0x3085d024, KEY_FASTFORWARD },
+ { 0x3085d026, KEY_PREVIOUS },
+ { 0x3085d027, KEY_NEXT }, /* ->| */
- { 0xa10c220d, KEY_ZOOM }, /* Aspect */
- { 0xa10c120d, KEY_STOP },
- { 0xa10c520d, KEY_DVD }, /* DVD Menu */
+ { 0x3085b044, KEY_ZOOM }, /* Aspect */
+ { 0x3085b048, KEY_STOP },
+ { 0x3085b04a, KEY_DVD }, /* DVD Menu */
- { 0xa10c140b, KEY_NUMERIC_1 },
- { 0xa10c940b, KEY_NUMERIC_2 },
- { 0xa10c540b, KEY_NUMERIC_3 },
- { 0xa10cd40b, KEY_NUMERIC_4 },
- { 0xa10c340b, KEY_NUMERIC_5 },
- { 0xa10cb40b, KEY_NUMERIC_6 },
- { 0xa10c740b, KEY_NUMERIC_7 },
- { 0xa10cf40b, KEY_NUMERIC_8 },
+ { 0x3085d028, KEY_NUMERIC_1 },
+ { 0x3085d029, KEY_NUMERIC_2 },
+ { 0x3085d02a, KEY_NUMERIC_3 },
+ { 0x3085d02b, KEY_NUMERIC_4 },
+ { 0x3085d02c, KEY_NUMERIC_5 },
+ { 0x3085d02d, KEY_NUMERIC_6 },
+ { 0x3085d02e, KEY_NUMERIC_7 },
+ { 0x3085d02f, KEY_NUMERIC_8 },
{ 0x0085302f, KEY_NUMERIC_8 },
- { 0xa10c0c03, KEY_NUMERIC_9 },
- { 0xa10c8c03, KEY_NUMERIC_0 },
- { 0xa10ccc03, KEY_ENTER },
- { 0xa10c4c03, KEY_CLEAR },
+ { 0x3085c030, KEY_NUMERIC_9 },
+ { 0x3085c031, KEY_NUMERIC_0 },
+ { 0x3085c033, KEY_ENTER },
+ { 0x3085c032, KEY_CLEAR },
};
static struct rc_map_list tivo_map = {
diff --git a/drivers/media/rc/keymaps/rc-tt-1500.c b/drivers/media/rc/keymaps/rc-tt-1500.c
index 80217ffc91db..c766d3b2b6b0 100644
--- a/drivers/media/rc/keymaps/rc-tt-1500.c
+++ b/drivers/media/rc/keymaps/rc-tt-1500.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -80,4 +80,4 @@ module_init(init_rc_map_tt_1500)
module_exit(exit_rc_map_tt_1500)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-videomate-s350.c b/drivers/media/rc/keymaps/rc-videomate-s350.c
index 8bfc3e8d909d..8a354775a2d8 100644
--- a/drivers/media/rc/keymaps/rc-videomate-s350.c
+++ b/drivers/media/rc/keymaps/rc-videomate-s350.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -83,4 +83,4 @@ module_init(init_rc_map_videomate_s350)
module_exit(exit_rc_map_videomate_s350)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c
index 390ce9431b35..eb0cda7766c4 100644
--- a/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c
+++ b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -85,4 +85,4 @@ module_init(init_rc_map_videomate_tv_pvr)
module_exit(exit_rc_map_videomate_tv_pvr)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c
index 2852bf705064..c1dd598e828e 100644
--- a/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c
+++ b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -80,4 +80,4 @@ module_init(init_rc_map_winfast_usbii_deluxe)
module_exit(exit_rc_map_winfast_usbii_deluxe)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-winfast.c b/drivers/media/rc/keymaps/rc-winfast.c
index 2df1cba23600..8a779da1e973 100644
--- a/drivers/media/rc/keymaps/rc-winfast.c
+++ b/drivers/media/rc/keymaps/rc-winfast.c
@@ -2,7 +2,7 @@
*
* keymap imported from ir-keymaps.c
*
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -100,4 +100,4 @@ module_init(init_rc_map_winfast)
module_exit(exit_rc_map_winfast)
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index a25bb1581e46..5d8f3d40d820 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -84,7 +84,7 @@
#define MCE_PORT_IR 0x4 /* (0x4 << 5) | MCE_CMD = 0x9f */
#define MCE_PORT_SYS 0x7 /* (0x7 << 5) | MCE_CMD = 0xff */
#define MCE_PORT_SER 0x6 /* 0xc0 thru 0xdf flush & 0x1f bytes */
-#define MCE_PORT_MASK 0xe0 /* Mask out command bits */
+#define MCE_PORT_MASK 0xe0 /* Mask out command bits */
/* Command port headers */
#define MCE_CMD_PORT_IR 0x9f /* IR-related cmd/rsp */
@@ -153,19 +153,6 @@
#define MCE_COMMAND_IRDATA 0x80
#define MCE_PACKET_LENGTH_MASK 0x1f /* Packet length mask */
-/* module parameters */
-#ifdef CONFIG_USB_DEBUG
-static bool debug = 1;
-#else
-static bool debug;
-#endif
-
-#define mce_dbg(dev, fmt, ...) \
- do { \
- if (debug) \
- dev_info(dev, fmt, ## __VA_ARGS__); \
- } while (0)
-
/* general constants */
#define SEND_FLAG_IN_PROGRESS 1
#define SEND_FLAG_COMPLETE 2
@@ -541,16 +528,13 @@ static int mceusb_cmd_datasize(u8 cmd, u8 subcmd)
static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
int offset, int len, bool out)
{
- char codes[USB_BUFLEN * 3 + 1];
- char inout[9];
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
+ char *inout;
u8 cmd, subcmd, data1, data2, data3, data4;
struct device *dev = ir->dev;
- int i, start, skip = 0;
+ int start, skip = 0;
u32 carrier, period;
- if (!debug)
- return;
-
/* skip meaningless 0xb1 0x60 header bytes on orig receiver */
if (ir->flags.microsoft_gen1 && !out && !offset)
skip = 2;
@@ -558,16 +542,10 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
if (len <= skip)
return;
- for (i = 0; i < len && i < USB_BUFLEN; i++)
- snprintf(codes + i * 3, 4, "%02x ", buf[i + offset] & 0xff);
-
- dev_info(dev, "%sx data: %s(length=%d)\n",
- (out ? "t" : "r"), codes, len);
+ dev_dbg(dev, "%cx data: %*ph (length=%d)",
+ (out ? 't' : 'r'), min(len, USB_BUFLEN), buf, len);
- if (out)
- strcpy(inout, "Request\0");
- else
- strcpy(inout, "Got\0");
+ inout = out ? "Request" : "Got";
start = offset + skip;
cmd = buf[start] & 0xff;
@@ -583,50 +561,50 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
break;
if ((subcmd == MCE_CMD_PORT_SYS) &&
(data1 == MCE_CMD_RESUME))
- dev_info(dev, "Device resume requested\n");
+ dev_dbg(dev, "Device resume requested");
else
- dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
+ dev_dbg(dev, "Unknown command 0x%02x 0x%02x",
cmd, subcmd);
break;
case MCE_CMD_PORT_SYS:
switch (subcmd) {
case MCE_RSP_EQEMVER:
if (!out)
- dev_info(dev, "Emulator interface version %x\n",
+ dev_dbg(dev, "Emulator interface version %x",
data1);
break;
case MCE_CMD_G_REVISION:
if (len == 2)
- dev_info(dev, "Get hw/sw rev?\n");
+ dev_dbg(dev, "Get hw/sw rev?");
else
- dev_info(dev, "hw/sw rev 0x%02x 0x%02x "
- "0x%02x 0x%02x\n", data1, data2,
+ dev_dbg(dev, "hw/sw rev 0x%02x 0x%02x 0x%02x 0x%02x",
+ data1, data2,
buf[start + 4], buf[start + 5]);
break;
case MCE_CMD_RESUME:
- dev_info(dev, "Device resume requested\n");
+ dev_dbg(dev, "Device resume requested");
break;
case MCE_RSP_CMD_ILLEGAL:
- dev_info(dev, "Illegal PORT_SYS command\n");
+ dev_dbg(dev, "Illegal PORT_SYS command");
break;
case MCE_RSP_EQWAKEVERSION:
if (!out)
- dev_info(dev, "Wake version, proto: 0x%02x, "
+ dev_dbg(dev, "Wake version, proto: 0x%02x, "
"payload: 0x%02x, address: 0x%02x, "
- "version: 0x%02x\n",
+ "version: 0x%02x",
data1, data2, data3, data4);
break;
case MCE_RSP_GETPORTSTATUS:
if (!out)
/* We use data1 + 1 here, to match hw labels */
- dev_info(dev, "TX port %d: blaster is%s connected\n",
+ dev_dbg(dev, "TX port %d: blaster is%s connected",
data1 + 1, data4 ? " not" : "");
break;
case MCE_CMD_FLASHLED:
- dev_info(dev, "Attempting to flash LED\n");
+ dev_dbg(dev, "Attempting to flash LED");
break;
default:
- dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
+ dev_dbg(dev, "Unknown command 0x%02x 0x%02x",
cmd, subcmd);
break;
}
@@ -634,13 +612,13 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
case MCE_CMD_PORT_IR:
switch (subcmd) {
case MCE_CMD_SIG_END:
- dev_info(dev, "End of signal\n");
+ dev_dbg(dev, "End of signal");
break;
case MCE_CMD_PING:
- dev_info(dev, "Ping\n");
+ dev_dbg(dev, "Ping");
break;
case MCE_CMD_UNKNOWN:
- dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n",
+ dev_dbg(dev, "Resp to 9f 05 of 0x%02x 0x%02x",
data1, data2);
break;
case MCE_RSP_EQIRCFS:
@@ -649,51 +627,51 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
if (!period)
break;
carrier = (1000 * 1000) / period;
- dev_info(dev, "%s carrier of %u Hz (period %uus)\n",
+ dev_dbg(dev, "%s carrier of %u Hz (period %uus)",
inout, carrier, period);
break;
case MCE_CMD_GETIRCFS:
- dev_info(dev, "Get carrier mode and freq\n");
+ dev_dbg(dev, "Get carrier mode and freq");
break;
case MCE_RSP_EQIRTXPORTS:
- dev_info(dev, "%s transmit blaster mask of 0x%02x\n",
+ dev_dbg(dev, "%s transmit blaster mask of 0x%02x",
inout, data1);
break;
case MCE_RSP_EQIRTIMEOUT:
/* value is in units of 50us, so x*50/1000 ms */
period = ((data1 << 8) | data2) * MCE_TIME_UNIT / 1000;
- dev_info(dev, "%s receive timeout of %d ms\n",
+ dev_dbg(dev, "%s receive timeout of %d ms",
inout, period);
break;
case MCE_CMD_GETIRTIMEOUT:
- dev_info(dev, "Get receive timeout\n");
+ dev_dbg(dev, "Get receive timeout");
break;
case MCE_CMD_GETIRTXPORTS:
- dev_info(dev, "Get transmit blaster mask\n");
+ dev_dbg(dev, "Get transmit blaster mask");
break;
case MCE_RSP_EQIRRXPORTEN:
- dev_info(dev, "%s %s-range receive sensor in use\n",
+ dev_dbg(dev, "%s %s-range receive sensor in use",
inout, data1 == 0x02 ? "short" : "long");
break;
case MCE_CMD_GETIRRXPORTEN:
/* aka MCE_RSP_EQIRRXCFCNT */
if (out)
- dev_info(dev, "Get receive sensor\n");
+ dev_dbg(dev, "Get receive sensor");
else if (ir->learning_enabled)
- dev_info(dev, "RX pulse count: %d\n",
+ dev_dbg(dev, "RX pulse count: %d",
((data1 << 8) | data2));
break;
case MCE_RSP_EQIRNUMPORTS:
if (out)
break;
- dev_info(dev, "Num TX ports: %x, num RX ports: %x\n",
+ dev_dbg(dev, "Num TX ports: %x, num RX ports: %x",
data1, data2);
break;
case MCE_RSP_CMD_ILLEGAL:
- dev_info(dev, "Illegal PORT_IR command\n");
+ dev_dbg(dev, "Illegal PORT_IR command");
break;
default:
- dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
+ dev_dbg(dev, "Unknown command 0x%02x 0x%02x",
cmd, subcmd);
break;
}
@@ -703,10 +681,11 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
}
if (cmd == MCE_IRDATA_TRAILER)
- dev_info(dev, "End of raw IR data\n");
+ dev_dbg(dev, "End of raw IR data");
else if ((cmd != MCE_CMD_PORT_IR) &&
((cmd & MCE_PORT_MASK) == MCE_COMMAND_IRDATA))
- dev_info(dev, "Raw IR data, %d pulse/space samples\n", ir->rem);
+ dev_dbg(dev, "Raw IR data, %d pulse/space samples", ir->rem);
+#endif
}
static void mce_async_callback(struct urb *urb)
@@ -718,10 +697,25 @@ static void mce_async_callback(struct urb *urb)
return;
ir = urb->context;
- if (ir) {
+
+ switch (urb->status) {
+ /* success */
+ case 0:
len = urb->actual_length;
mceusb_dev_printdata(ir, urb->transfer_buffer, 0, len, true);
+ break;
+
+ case -ECONNRESET:
+ case -ENOENT:
+ case -EILSEQ:
+ case -ESHUTDOWN:
+ break;
+
+ case -EPIPE:
+ default:
+ dev_err(ir->dev, "Error: request urb status = %d", urb->status);
+ break;
}
/* the transfer buffer and urb were allocated in mce_request_packet */
@@ -770,17 +764,17 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data,
return;
}
- mce_dbg(dev, "receive request called (size=%#x)\n", size);
+ dev_dbg(dev, "receive request called (size=%#x)", size);
async_urb->transfer_buffer_length = size;
async_urb->dev = ir->usbdev;
res = usb_submit_urb(async_urb, GFP_ATOMIC);
if (res) {
- mce_dbg(dev, "receive request FAILED! (res=%d)\n", res);
+ dev_err(dev, "receive request FAILED! (res=%d)", res);
return;
}
- mce_dbg(dev, "receive request complete (res=%d)\n", res);
+ dev_dbg(dev, "receive request complete (res=%d)", res);
}
static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size)
@@ -895,8 +889,7 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier)
ir->carrier = carrier;
cmdbuf[2] = MCE_CMD_SIG_END;
cmdbuf[3] = MCE_IRDATA_TRAILER;
- mce_dbg(ir->dev, "%s: disabling carrier "
- "modulation\n", __func__);
+ dev_dbg(ir->dev, "disabling carrier modulation");
mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
return carrier;
}
@@ -907,8 +900,8 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier)
ir->carrier = carrier;
cmdbuf[2] = prescaler;
cmdbuf[3] = divisor;
- mce_dbg(ir->dev, "%s: requesting %u HZ "
- "carrier\n", __func__, carrier);
+ dev_dbg(ir->dev, "requesting %u HZ carrier",
+ carrier);
/* Transmit new carrier to mce device */
mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
@@ -998,7 +991,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
* US_TO_NS(MCE_TIME_UNIT);
- mce_dbg(ir->dev, "Storing %s with duration %d\n",
+ dev_dbg(ir->dev, "Storing %s with duration %d",
rawir.pulse ? "pulse" : "space",
rawir.duration);
@@ -1032,7 +1025,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
ir->parser_state = CMD_HEADER;
}
if (event) {
- mce_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n");
+ dev_dbg(ir->dev, "processed IR data");
ir_raw_event_handle(ir->rc);
}
}
@@ -1055,7 +1048,7 @@ static void mceusb_dev_recv(struct urb *urb)
if (ir->send_flags == RECV_FLAG_IN_PROGRESS) {
ir->send_flags = SEND_FLAG_COMPLETE;
- mce_dbg(ir->dev, "setup answer received %d bytes\n",
+ dev_dbg(ir->dev, "setup answer received %d bytes\n",
buf_len);
}
@@ -1067,13 +1060,14 @@ static void mceusb_dev_recv(struct urb *urb)
case -ECONNRESET:
case -ENOENT:
+ case -EILSEQ:
case -ESHUTDOWN:
usb_unlink_urb(urb);
return;
case -EPIPE:
default:
- mce_dbg(ir->dev, "Error: urb status = %d\n", urb->status);
+ dev_err(ir->dev, "Error: urb status = %d", urb->status);
break;
}
@@ -1095,7 +1089,7 @@ static void mceusb_gen1_init(struct mceusb_dev *ir)
data = kzalloc(USB_CTRL_MSG_SZ, GFP_KERNEL);
if (!data) {
- dev_err(dev, "%s: memory allocation failed!\n", __func__);
+ dev_err(dev, "%s: memory allocation failed!", __func__);
return;
}
@@ -1106,28 +1100,28 @@ static void mceusb_gen1_init(struct mceusb_dev *ir)
ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0,
data, USB_CTRL_MSG_SZ, HZ * 3);
- mce_dbg(dev, "%s - ret = %d\n", __func__, ret);
- mce_dbg(dev, "%s - data[0] = %d, data[1] = %d\n",
- __func__, data[0], data[1]);
+ dev_dbg(dev, "set address - ret = %d", ret);
+ dev_dbg(dev, "set address - data[0] = %d, data[1] = %d",
+ data[0], data[1]);
/* set feature: bit rate 38400 bps */
ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
USB_REQ_SET_FEATURE, USB_TYPE_VENDOR,
0xc04e, 0x0000, NULL, 0, HZ * 3);
- mce_dbg(dev, "%s - ret = %d\n", __func__, ret);
+ dev_dbg(dev, "set feature - ret = %d", ret);
/* bRequest 4: set char length to 8 bits */
ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
4, USB_TYPE_VENDOR,
0x0808, 0x0000, NULL, 0, HZ * 3);
- mce_dbg(dev, "%s - retB = %d\n", __func__, ret);
+ dev_dbg(dev, "set char length - retB = %d", ret);
/* bRequest 2: set handshaking to use DTR/DSR */
ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
2, USB_TYPE_VENDOR,
0x0000, 0x0100, NULL, 0, HZ * 3);
- mce_dbg(dev, "%s - retC = %d\n", __func__, ret);
+ dev_dbg(dev, "set handshake - retC = %d", ret);
/* device resume */
mce_async_out(ir, DEVICE_RESUME, sizeof(DEVICE_RESUME));
@@ -1198,7 +1192,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
rc = rc_allocate_device();
if (!rc) {
- dev_err(dev, "remote dev allocation failed\n");
+ dev_err(dev, "remote dev allocation failed");
goto out;
}
@@ -1217,7 +1211,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
rc->dev.parent = dev;
rc->priv = ir;
rc->driver_type = RC_DRIVER_IR_RAW;
- rc->allowed_protos = RC_BIT_ALL;
+ rc_set_allowed_protocols(rc, RC_BIT_ALL);
rc->timeout = MS_TO_NS(100);
if (!ir->flags.no_tx) {
rc->s_tx_mask = mceusb_set_tx_mask;
@@ -1230,7 +1224,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
ret = rc_register_device(rc);
if (ret < 0) {
- dev_err(dev, "remote dev registration failed\n");
+ dev_err(dev, "remote dev registration failed");
goto out;
}
@@ -1258,7 +1252,7 @@ static int mceusb_dev_probe(struct usb_interface *intf,
bool tx_mask_normal;
int ir_intfnum;
- mce_dbg(&intf->dev, "%s called\n", __func__);
+ dev_dbg(&intf->dev, "%s called", __func__);
idesc = intf->cur_altsetting;
@@ -1286,8 +1280,7 @@ static int mceusb_dev_probe(struct usb_interface *intf,
ep_in = ep;
ep_in->bmAttributes = USB_ENDPOINT_XFER_INT;
ep_in->bInterval = 1;
- mce_dbg(&intf->dev, "acceptable inbound endpoint "
- "found\n");
+ dev_dbg(&intf->dev, "acceptable inbound endpoint found");
}
if ((ep_out == NULL)
@@ -1301,12 +1294,11 @@ static int mceusb_dev_probe(struct usb_interface *intf,
ep_out = ep;
ep_out->bmAttributes = USB_ENDPOINT_XFER_INT;
ep_out->bInterval = 1;
- mce_dbg(&intf->dev, "acceptable outbound endpoint "
- "found\n");
+ dev_dbg(&intf->dev, "acceptable outbound endpoint found");
}
}
if (ep_in == NULL) {
- mce_dbg(&intf->dev, "inbound and/or endpoint not found\n");
+ dev_dbg(&intf->dev, "inbound and/or endpoint not found");
return -ENODEV;
}
@@ -1357,7 +1349,7 @@ static int mceusb_dev_probe(struct usb_interface *intf,
ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/* flush buffers on the device */
- mce_dbg(&intf->dev, "Flushing receive buffers\n");
+ dev_dbg(&intf->dev, "Flushing receive buffers\n");
mce_flush_rx_buffer(ir, maxp);
/* figure out which firmware/emulator version this hardware has */
@@ -1382,10 +1374,9 @@ static int mceusb_dev_probe(struct usb_interface *intf,
device_set_wakeup_capable(ir->dev, true);
device_set_wakeup_enable(ir->dev, true);
- dev_info(&intf->dev, "Registered %s with mce emulator interface "
- "version %x\n", name, ir->emver);
- dev_info(&intf->dev, "%x tx ports (0x%x cabled) and "
- "%x rx sensors (0x%x active)\n",
+ dev_info(&intf->dev, "Registered %s with mce emulator interface version %x",
+ name, ir->emver);
+ dev_info(&intf->dev, "%x tx ports (0x%x cabled) and %x rx sensors (0x%x active)",
ir->num_txports, ir->txports_cabled,
ir->num_rxports, ir->rxports_active);
@@ -1399,7 +1390,7 @@ urb_in_alloc_fail:
buf_in_alloc_fail:
kfree(ir);
mem_alloc_fail:
- dev_err(&intf->dev, "%s: device setup failed!\n", __func__);
+ dev_err(&intf->dev, "%s: device setup failed!", __func__);
return -ENOMEM;
}
@@ -1427,7 +1418,7 @@ static void mceusb_dev_disconnect(struct usb_interface *intf)
static int mceusb_dev_suspend(struct usb_interface *intf, pm_message_t message)
{
struct mceusb_dev *ir = usb_get_intfdata(intf);
- dev_info(ir->dev, "suspend\n");
+ dev_info(ir->dev, "suspend");
usb_kill_urb(ir->urb_in);
return 0;
}
@@ -1435,7 +1426,7 @@ static int mceusb_dev_suspend(struct usb_interface *intf, pm_message_t message)
static int mceusb_dev_resume(struct usb_interface *intf)
{
struct mceusb_dev *ir = usb_get_intfdata(intf);
- dev_info(ir->dev, "resume\n");
+ dev_info(ir->dev, "resume");
if (usb_submit_urb(ir->urb_in, GFP_ATOMIC))
return -EIO;
return 0;
@@ -1457,6 +1448,3 @@ MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(usb, mceusb_dev_table);
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index 21ee0dc1b7ec..d244e1a83f43 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -330,9 +330,6 @@ static void nvt_cir_wake_ldev_init(struct nvt_dev *nvt)
/* Enable CIR Wake via PSOUT# (Pin60) */
nvt_set_reg_bit(nvt, CIR_WAKE_ENABLE_BIT, CR_ACPI_CIR_WAKE);
- /* enable cir interrupt of mouse/keyboard IRQ event */
- nvt_set_reg_bit(nvt, CIR_INTR_MOUSE_IRQ_BIT, CR_ACPI_IRQ_EVENTS);
-
/* enable pme interrupt of cir wakeup event */
nvt_set_reg_bit(nvt, PME_INTR_CIR_PASS_BIT, CR_ACPI_IRQ_EVENTS2);
@@ -456,7 +453,6 @@ static void nvt_enable_wake(struct nvt_dev *nvt)
nvt_select_logical_dev(nvt, LOGICAL_DEV_ACPI);
nvt_set_reg_bit(nvt, CIR_WAKE_ENABLE_BIT, CR_ACPI_CIR_WAKE);
- nvt_set_reg_bit(nvt, CIR_INTR_MOUSE_IRQ_BIT, CR_ACPI_IRQ_EVENTS);
nvt_set_reg_bit(nvt, PME_INTR_CIR_PASS_BIT, CR_ACPI_IRQ_EVENTS2);
nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE);
@@ -989,6 +985,12 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
goto exit_free_dev_rdev;
ret = -ENODEV;
+ /* activate pnp device */
+ if (pnp_activate_dev(pdev) < 0) {
+ dev_err(&pdev->dev, "Could not activate PNP device!\n");
+ goto exit_free_dev_rdev;
+ }
+
/* validate pnp resources */
if (!pnp_port_valid(pdev, 0) ||
pnp_port_len(pdev, 0) < CIR_IOREG_LENGTH) {
@@ -1042,7 +1044,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
/* Set up the rc device */
rdev->priv = nvt;
rdev->driver_type = RC_DRIVER_IR_RAW;
- rdev->allowed_protos = RC_BIT_ALL;
+ rc_set_allowed_protocols(rdev, RC_BIT_ALL);
rdev->open = nvt_open;
rdev->close = nvt_close;
rdev->tx_ir = nvt_tx_ir;
diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h
index 07e83108df0f..e1cf23c3875b 100644
--- a/drivers/media/rc/nuvoton-cir.h
+++ b/drivers/media/rc/nuvoton-cir.h
@@ -363,7 +363,6 @@ struct nvt_dev {
#define LOGICAL_DEV_ENABLE 0x01
#define CIR_WAKE_ENABLE_BIT 0x08
-#define CIR_INTR_MOUSE_IRQ_BIT 0x80
#define PME_INTR_CIR_PASS_BIT 0x08
/* w83677hg CIR pin config */
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 70a180bb0bd0..da536c93c978 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -1,7 +1,7 @@
/*
* Remote Controller core raw events header
*
- * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2010 by Mauro Carvalho Chehab
*
* 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
@@ -88,6 +88,12 @@ struct ir_raw_event_ctrl {
unsigned count;
u64 bits;
} sanyo;
+ struct sharp_dec {
+ int state;
+ unsigned count;
+ u32 bits;
+ unsigned int pulse_len;
+ } sharp;
struct mce_kbd_dec {
struct input_dev *idev;
struct timer_list rx_timeout;
@@ -204,6 +210,13 @@ static inline void load_sony_decode(void) { }
static inline void load_sanyo_decode(void) { }
#endif
+/* from ir-sharp-decoder.c */
+#ifdef CONFIG_IR_SHARP_DECODER_MODULE
+#define load_sharp_decode() request_module_nowait("ir-sharp-decoder")
+#else
+static inline void load_sharp_decode(void) { }
+#endif
+
/* from ir-mce_kbd-decoder.c */
#ifdef CONFIG_IR_MCE_KBD_DECODER_MODULE
#define load_mce_kbd_decode() request_module_nowait("ir-mce_kbd-decoder")
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index 53d02827a472..0a88e0cf964f 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -195,7 +195,7 @@ static int __init loop_init(void)
rc->map_name = RC_MAP_EMPTY;
rc->priv = &loopdev;
rc->driver_type = RC_DRIVER_IR_RAW;
- rc->allowed_protos = RC_BIT_ALL;
+ rc_set_allowed_protocols(rc, RC_BIT_ALL);
rc->timeout = 100 * 1000 * 1000; /* 100 ms */
rc->min_timeout = 1;
rc->max_timeout = UINT_MAX;
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 02e2f38c9c85..99697aae92ff 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1,6 +1,6 @@
/* rc-main.c - Remote Controller core module
*
- * Copyright (C) 2009-2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2009-2010 by Mauro Carvalho Chehab
*
* 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
@@ -24,7 +24,7 @@
/* Bitmap to store allocated device numbers from 0 to IRRCV_NUM_DEVICES - 1 */
#define IRRCV_NUM_DEVICES 256
-DECLARE_BITMAP(ir_core_dev_number, IRRCV_NUM_DEVICES);
+static DECLARE_BITMAP(ir_core_dev_number, IRRCV_NUM_DEVICES);
/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
#define IR_TAB_MIN_SIZE 256
@@ -62,7 +62,7 @@ struct rc_map *rc_map_get(const char *name)
map = seek_rc_map(name);
#ifdef MODULE
if (!map) {
- int rc = request_module(name);
+ int rc = request_module("%s", name);
if (rc < 0) {
printk(KERN_ERR "Couldn't load IR keymap %s\n", name);
return NULL;
@@ -633,6 +633,7 @@ EXPORT_SYMBOL_GPL(rc_repeat);
static void ir_do_keydown(struct rc_dev *dev, int scancode,
u32 keycode, u8 toggle)
{
+ struct rc_scancode_filter *filter;
bool new_event = !dev->keypressed ||
dev->last_scancode != scancode ||
dev->last_toggle != toggle;
@@ -640,6 +641,11 @@ static void ir_do_keydown(struct rc_dev *dev, int scancode,
if (new_event && dev->keypressed)
ir_do_keyup(dev, false);
+ /* Generic scancode filtering */
+ filter = &dev->scancode_filters[RC_FILTER_NORMAL];
+ if (filter->mask && ((scancode ^ filter->data) & filter->mask))
+ return;
+
input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
if (new_event && keycode != KEY_RESERVED) {
@@ -653,9 +659,10 @@ static void ir_do_keydown(struct rc_dev *dev, int scancode,
"key 0x%04x, scancode 0x%04x\n",
dev->input_name, keycode, scancode);
input_report_key(dev->input_dev, keycode, 1);
+
+ led_trigger_event(led_feedback, LED_FULL);
}
- led_trigger_event(led_feedback, LED_FULL);
input_sync(dev->input_dev);
}
@@ -790,18 +797,44 @@ static struct {
RC_BIT_SONY20, "sony" },
{ RC_BIT_RC5_SZ, "rc-5-sz" },
{ RC_BIT_SANYO, "sanyo" },
+ { RC_BIT_SHARP, "sharp" },
{ RC_BIT_MCE_KBD, "mce_kbd" },
{ RC_BIT_LIRC, "lirc" },
};
/**
- * show_protocols() - shows the current IR protocol(s)
+ * struct rc_filter_attribute - Device attribute relating to a filter type.
+ * @attr: Device attribute.
+ * @type: Filter type.
+ * @mask: false for filter value, true for filter mask.
+ */
+struct rc_filter_attribute {
+ struct device_attribute attr;
+ enum rc_filter_type type;
+ bool mask;
+};
+#define to_rc_filter_attr(a) container_of(a, struct rc_filter_attribute, attr)
+
+#define RC_PROTO_ATTR(_name, _mode, _show, _store, _type) \
+ struct rc_filter_attribute dev_attr_##_name = { \
+ .attr = __ATTR(_name, _mode, _show, _store), \
+ .type = (_type), \
+ }
+#define RC_FILTER_ATTR(_name, _mode, _show, _store, _type, _mask) \
+ struct rc_filter_attribute dev_attr_##_name = { \
+ .attr = __ATTR(_name, _mode, _show, _store), \
+ .type = (_type), \
+ .mask = (_mask), \
+ }
+
+/**
+ * show_protocols() - shows the current/wakeup IR protocol(s)
* @device: the device descriptor
* @mattr: the device attribute struct (unused)
* @buf: a pointer to the output buffer
*
* This routine is a callback routine for input read the IR protocol type(s).
- * it is trigged by reading /sys/class/rc/rc?/protocols.
+ * it is trigged by reading /sys/class/rc/rc?/[wakeup_]protocols.
* It returns the protocol names of supported protocols.
* Enabled protocols are printed in brackets.
*
@@ -812,6 +845,7 @@ static ssize_t show_protocols(struct device *device,
struct device_attribute *mattr, char *buf)
{
struct rc_dev *dev = to_rc_dev(device);
+ struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr);
u64 allowed, enabled;
char *tmp = buf;
int i;
@@ -822,9 +856,10 @@ static ssize_t show_protocols(struct device *device,
mutex_lock(&dev->lock);
- enabled = dev->enabled_protocols;
- if (dev->driver_type == RC_DRIVER_SCANCODE)
- allowed = dev->allowed_protos;
+ enabled = dev->enabled_protocols[fattr->type];
+ if (dev->driver_type == RC_DRIVER_SCANCODE ||
+ fattr->type == RC_FILTER_WAKEUP)
+ allowed = dev->allowed_protocols[fattr->type];
else if (dev->raw)
allowed = ir_raw_get_allowed_protocols();
else {
@@ -856,14 +891,14 @@ static ssize_t show_protocols(struct device *device,
}
/**
- * store_protocols() - changes the current IR protocol(s)
+ * store_protocols() - changes the current/wakeup IR protocol(s)
* @device: the device descriptor
* @mattr: the device attribute struct (unused)
* @buf: a pointer to the input buffer
* @len: length of the input buffer
*
* This routine is for changing the IR protocol type.
- * It is trigged by writing to /sys/class/rc/rc?/protocols.
+ * It is trigged by writing to /sys/class/rc/rc?/[wakeup_]protocols.
* Writing "+proto" will add a protocol to the list of enabled protocols.
* Writing "-proto" will remove a protocol from the list of enabled protocols.
* Writing "proto" will enable only "proto".
@@ -880,12 +915,15 @@ static ssize_t store_protocols(struct device *device,
size_t len)
{
struct rc_dev *dev = to_rc_dev(device);
+ struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr);
bool enable, disable;
const char *tmp;
- u64 type;
+ u64 old_type, type;
u64 mask;
int rc, i, count = 0;
ssize_t ret;
+ int (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
+ struct rc_scancode_filter local_filter, *filter;
/* Device is being removed */
if (!dev)
@@ -898,7 +936,8 @@ static ssize_t store_protocols(struct device *device,
ret = -EINVAL;
goto out;
}
- type = dev->enabled_protocols;
+ old_type = dev->enabled_protocols[fattr->type];
+ type = old_type;
while ((tmp = strsep((char **) &data, " \n")) != NULL) {
if (!*tmp)
@@ -946,8 +985,10 @@ static ssize_t store_protocols(struct device *device,
goto out;
}
- if (dev->change_protocol) {
- rc = dev->change_protocol(dev, &type);
+ change_protocol = (fattr->type == RC_FILTER_NORMAL)
+ ? dev->change_protocol : dev->change_wakeup_protocol;
+ if (change_protocol) {
+ rc = change_protocol(dev, &type);
if (rc < 0) {
IR_dprintk(1, "Error setting protocols to 0x%llx\n",
(long long)type);
@@ -956,10 +997,40 @@ static ssize_t store_protocols(struct device *device,
}
}
- dev->enabled_protocols = type;
+ dev->enabled_protocols[fattr->type] = type;
IR_dprintk(1, "Current protocol(s): 0x%llx\n",
(long long)type);
+ /*
+ * If the protocol is changed the filter needs updating.
+ * Try setting the same filter with the new protocol (if any).
+ * Fall back to clearing the filter.
+ */
+ filter = &dev->scancode_filters[fattr->type];
+ if (old_type != type && filter->mask) {
+ local_filter = *filter;
+ if (!type) {
+ /* no protocol => clear filter */
+ ret = -1;
+ } else if (!dev->s_filter) {
+ /* generic filtering => accept any filter */
+ ret = 0;
+ } else {
+ /* hardware filtering => try setting, otherwise clear */
+ ret = dev->s_filter(dev, fattr->type, &local_filter);
+ }
+ if (ret < 0) {
+ /* clear the filter */
+ local_filter.data = 0;
+ local_filter.mask = 0;
+ if (dev->s_filter)
+ dev->s_filter(dev, fattr->type, &local_filter);
+ }
+
+ /* commit the new filter */
+ *filter = local_filter;
+ }
+
ret = len;
out:
@@ -967,6 +1038,115 @@ out:
return ret;
}
+/**
+ * show_filter() - shows the current scancode filter value or mask
+ * @device: the device descriptor
+ * @attr: the device attribute struct
+ * @buf: a pointer to the output buffer
+ *
+ * This routine is a callback routine to read a scancode filter value or mask.
+ * It is trigged by reading /sys/class/rc/rc?/[wakeup_]filter[_mask].
+ * It prints the current scancode filter value or mask of the appropriate filter
+ * type in hexadecimal into @buf and returns the size of the buffer.
+ *
+ * Bits of the filter value corresponding to set bits in the filter mask are
+ * compared against input scancodes and non-matching scancodes are discarded.
+ *
+ * dev->lock is taken to guard against races between device registration,
+ * store_filter and show_filter.
+ */
+static ssize_t show_filter(struct device *device,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct rc_dev *dev = to_rc_dev(device);
+ struct rc_filter_attribute *fattr = to_rc_filter_attr(attr);
+ u32 val;
+
+ /* Device is being removed */
+ if (!dev)
+ return -EINVAL;
+
+ mutex_lock(&dev->lock);
+ if (fattr->mask)
+ val = dev->scancode_filters[fattr->type].mask;
+ else
+ val = dev->scancode_filters[fattr->type].data;
+ mutex_unlock(&dev->lock);
+
+ return sprintf(buf, "%#x\n", val);
+}
+
+/**
+ * store_filter() - changes the scancode filter value
+ * @device: the device descriptor
+ * @attr: the device attribute struct
+ * @buf: a pointer to the input buffer
+ * @len: length of the input buffer
+ *
+ * This routine is for changing a scancode filter value or mask.
+ * It is trigged by writing to /sys/class/rc/rc?/[wakeup_]filter[_mask].
+ * Returns -EINVAL if an invalid filter value for the current protocol was
+ * specified or if scancode filtering is not supported by the driver, otherwise
+ * returns @len.
+ *
+ * Bits of the filter value corresponding to set bits in the filter mask are
+ * compared against input scancodes and non-matching scancodes are discarded.
+ *
+ * dev->lock is taken to guard against races between device registration,
+ * store_filter and show_filter.
+ */
+static ssize_t store_filter(struct device *device,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct rc_dev *dev = to_rc_dev(device);
+ struct rc_filter_attribute *fattr = to_rc_filter_attr(attr);
+ struct rc_scancode_filter local_filter, *filter;
+ int ret;
+ unsigned long val;
+
+ /* Device is being removed */
+ if (!dev)
+ return -EINVAL;
+
+ ret = kstrtoul(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+
+ /* Scancode filter not supported (but still accept 0) */
+ if (!dev->s_filter && fattr->type != RC_FILTER_NORMAL)
+ return val ? -EINVAL : count;
+
+ mutex_lock(&dev->lock);
+
+ /* Tell the driver about the new filter */
+ filter = &dev->scancode_filters[fattr->type];
+ local_filter = *filter;
+ if (fattr->mask)
+ local_filter.mask = val;
+ else
+ local_filter.data = val;
+ if (!dev->enabled_protocols[fattr->type] && local_filter.mask) {
+ /* refuse to set a filter unless a protocol is enabled */
+ ret = -EINVAL;
+ goto unlock;
+ }
+ if (dev->s_filter) {
+ ret = dev->s_filter(dev, fattr->type, &local_filter);
+ if (ret < 0)
+ goto unlock;
+ }
+
+ /* Success, commit the new filter */
+ *filter = local_filter;
+
+unlock:
+ mutex_unlock(&dev->lock);
+ return (ret < 0) ? ret : count;
+}
+
static void rc_dev_release(struct device *device)
{
}
@@ -996,11 +1176,26 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
/*
* Static device attribute struct with the sysfs attributes for IR's
*/
-static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR,
- show_protocols, store_protocols);
+static RC_PROTO_ATTR(protocols, S_IRUGO | S_IWUSR,
+ show_protocols, store_protocols, RC_FILTER_NORMAL);
+static RC_PROTO_ATTR(wakeup_protocols, S_IRUGO | S_IWUSR,
+ show_protocols, store_protocols, RC_FILTER_WAKEUP);
+static RC_FILTER_ATTR(filter, S_IRUGO|S_IWUSR,
+ show_filter, store_filter, RC_FILTER_NORMAL, false);
+static RC_FILTER_ATTR(filter_mask, S_IRUGO|S_IWUSR,
+ show_filter, store_filter, RC_FILTER_NORMAL, true);
+static RC_FILTER_ATTR(wakeup_filter, S_IRUGO|S_IWUSR,
+ show_filter, store_filter, RC_FILTER_WAKEUP, false);
+static RC_FILTER_ATTR(wakeup_filter_mask, S_IRUGO|S_IWUSR,
+ show_filter, store_filter, RC_FILTER_WAKEUP, true);
static struct attribute *rc_dev_attrs[] = {
- &dev_attr_protocols.attr,
+ &dev_attr_protocols.attr.attr,
+ &dev_attr_wakeup_protocols.attr.attr,
+ &dev_attr_filter.attr.attr,
+ &dev_attr_filter_mask.attr.attr,
+ &dev_attr_wakeup_filter.attr.attr,
+ &dev_attr_wakeup_filter_mask.attr.attr,
NULL,
};
@@ -1091,14 +1286,6 @@ int rc_register_device(struct rc_dev *dev)
if (dev->close)
dev->input_dev->close = ir_close;
- /*
- * Take the lock here, as the device sysfs node will appear
- * when device_add() is called, which may trigger an ir-keytable udev
- * rule, which will in turn call show_protocols and access
- * dev->enabled_protocols before it has been initialized.
- */
- mutex_lock(&dev->lock);
-
do {
devno = find_first_zero_bit(ir_core_dev_number,
IRRCV_NUM_DEVICES);
@@ -1107,6 +1294,14 @@ int rc_register_device(struct rc_dev *dev)
return -ENOMEM;
} while (test_and_set_bit(devno, ir_core_dev_number));
+ /*
+ * Take the lock here, as the device sysfs node will appear
+ * when device_add() is called, which may trigger an ir-keytable udev
+ * rule, which will in turn call show_protocols and access
+ * dev->enabled_protocols before it has been initialized.
+ */
+ mutex_lock(&dev->lock);
+
dev->devno = devno;
dev_set_name(&dev->dev, "rc%ld", dev->devno);
dev_set_drvdata(&dev->dev, dev);
@@ -1172,7 +1367,7 @@ int rc_register_device(struct rc_dev *dev)
rc = dev->change_protocol(dev, &rc_type);
if (rc < 0)
goto out_raw;
- dev->enabled_protocols = rc_type;
+ dev->enabled_protocols[RC_FILTER_NORMAL] = rc_type;
}
mutex_unlock(&dev->lock);
@@ -1260,5 +1455,5 @@ int rc_core_debug; /* ir_debug level (0,1,2) */
EXPORT_SYMBOL_GPL(rc_core_debug);
module_param_named(debug, rc_core_debug, int, 0644);
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index a5d4f883d053..47cd373e2295 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -922,7 +922,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
rc->dev.parent = dev;
rc->priv = rr3;
rc->driver_type = RC_DRIVER_IR_RAW;
- rc->allowed_protos = RC_BIT_ALL;
+ rc_set_allowed_protocols(rc, RC_BIT_ALL);
rc->timeout = US_TO_NS(2750);
rc->tx_ir = redrat3_transmit_ir;
rc->s_tx_carrier = redrat3_set_tx_carrier;
diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c
index 8f0cddb9e8f2..22e4c1f28ab4 100644
--- a/drivers/media/rc/st_rc.c
+++ b/drivers/media/rc/st_rc.c
@@ -287,7 +287,7 @@ static int st_rc_probe(struct platform_device *pdev)
st_rc_hardware_init(rc_dev);
rdev->driver_type = RC_DRIVER_IR_RAW;
- rdev->allowed_protos = RC_BIT_ALL;
+ rc_set_allowed_protocols(rdev, RC_BIT_ALL);
/* rx sampling rate is 10Mhz */
rdev->rx_resolution = 100;
rdev->timeout = US_TO_NS(MAX_SYMB_TIME);
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
index d7b11e6a9982..f4e0bc3d382c 100644
--- a/drivers/media/rc/streamzap.c
+++ b/drivers/media/rc/streamzap.c
@@ -322,7 +322,7 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz)
rdev->dev.parent = dev;
rdev->priv = sz;
rdev->driver_type = RC_DRIVER_IR_RAW;
- rdev->allowed_protos = RC_BIT_ALL;
+ rc_set_allowed_protocols(rdev, RC_BIT_ALL);
rdev->driver_name = DRIVER_NAME;
rdev->map_name = RC_MAP_STREAMZAP;
diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c
index d8de2056a4f6..c5be38e2a2fe 100644
--- a/drivers/media/rc/ttusbir.c
+++ b/drivers/media/rc/ttusbir.c
@@ -318,7 +318,7 @@ static int ttusbir_probe(struct usb_interface *intf,
usb_to_input_id(tt->udev, &rc->input_id);
rc->dev.parent = &intf->dev;
rc->driver_type = RC_DRIVER_IR_RAW;
- rc->allowed_protos = RC_BIT_ALL;
+ rc_set_allowed_protocols(rc, RC_BIT_ALL);
rc->priv = tt;
rc->driver_name = DRIVER_NAME;
rc->map_name = RC_MAP_TT_1500;
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index 904baf4eec28..a8b981f5ce2e 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -1082,7 +1082,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
data->dev->dev.parent = &device->dev;
data->dev->timeout = MS_TO_NS(100);
data->dev->rx_resolution = US_TO_NS(2);
- data->dev->allowed_protos = RC_BIT_ALL;
+ rc_set_allowed_protocols(data->dev, RC_BIT_ALL);
err = rc_register_device(data->dev);
if (err)
diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig
index ba2e365296cf..a1284889cd15 100644
--- a/drivers/media/tuners/Kconfig
+++ b/drivers/media/tuners/Kconfig
@@ -204,6 +204,7 @@ config MEDIA_TUNER_TDA18212
config MEDIA_TUNER_E4000
tristate "Elonics E4000 silicon tuner"
depends on MEDIA_SUPPORT && I2C
+ select REGMAP_I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Elonics E4000 silicon tuner driver.
diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c
index 40c1da707d15..90d93348f20c 100644
--- a/drivers/media/tuners/e4000.c
+++ b/drivers/media/tuners/e4000.c
@@ -21,220 +21,113 @@
#include "e4000_priv.h"
#include <linux/math64.h>
-/* Max transfer size done by I2C transfer functions */
-#define MAX_XFER_SIZE 64
-
-/* write multiple registers */
-static int e4000_wr_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len)
-{
- int ret;
- u8 buf[MAX_XFER_SIZE];
- struct i2c_msg msg[1] = {
- {
- .addr = priv->cfg->i2c_addr,
- .flags = 0,
- .len = 1 + len,
- .buf = buf,
- }
- };
-
- if (1 + len > sizeof(buf)) {
- dev_warn(&priv->i2c->dev,
- "%s: i2c wr reg=%04x: len=%d is too big!\n",
- KBUILD_MODNAME, reg, len);
- return -EINVAL;
- }
-
- buf[0] = reg;
- memcpy(&buf[1], val, len);
-
- ret = i2c_transfer(priv->i2c, msg, 1);
- if (ret == 1) {
- ret = 0;
- } else {
- dev_warn(&priv->i2c->dev,
- "%s: i2c wr failed=%d reg=%02x len=%d\n",
- KBUILD_MODNAME, ret, reg, len);
- ret = -EREMOTEIO;
- }
- return ret;
-}
-
-/* read multiple registers */
-static int e4000_rd_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len)
-{
- int ret;
- u8 buf[MAX_XFER_SIZE];
- struct i2c_msg msg[2] = {
- {
- .addr = priv->cfg->i2c_addr,
- .flags = 0,
- .len = 1,
- .buf = &reg,
- }, {
- .addr = priv->cfg->i2c_addr,
- .flags = I2C_M_RD,
- .len = len,
- .buf = buf,
- }
- };
-
- if (len > sizeof(buf)) {
- dev_warn(&priv->i2c->dev,
- "%s: i2c rd reg=%04x: len=%d is too big!\n",
- KBUILD_MODNAME, reg, len);
- return -EINVAL;
- }
-
- ret = i2c_transfer(priv->i2c, msg, 2);
- if (ret == 2) {
- memcpy(val, buf, len);
- ret = 0;
- } else {
- dev_warn(&priv->i2c->dev,
- "%s: i2c rd failed=%d reg=%02x len=%d\n",
- KBUILD_MODNAME, ret, reg, len);
- ret = -EREMOTEIO;
- }
-
- return ret;
-}
-
-/* write single register */
-static int e4000_wr_reg(struct e4000_priv *priv, u8 reg, u8 val)
-{
- return e4000_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register */
-static int e4000_rd_reg(struct e4000_priv *priv, u8 reg, u8 *val)
-{
- return e4000_rd_regs(priv, reg, val, 1);
-}
-
static int e4000_init(struct dvb_frontend *fe)
{
- struct e4000_priv *priv = fe->tuner_priv;
+ struct e4000 *s = fe->tuner_priv;
int ret;
- dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
+ dev_dbg(&s->client->dev, "%s:\n", __func__);
/* dummy I2C to ensure I2C wakes up */
- ret = e4000_wr_reg(priv, 0x02, 0x40);
+ ret = regmap_write(s->regmap, 0x02, 0x40);
/* reset */
- ret = e4000_wr_reg(priv, 0x00, 0x01);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x00, 0x01);
+ if (ret)
goto err;
/* disable output clock */
- ret = e4000_wr_reg(priv, 0x06, 0x00);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x06, 0x00);
+ if (ret)
goto err;
- ret = e4000_wr_reg(priv, 0x7a, 0x96);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x7a, 0x96);
+ if (ret)
goto err;
/* configure gains */
- ret = e4000_wr_regs(priv, 0x7e, "\x01\xfe", 2);
- if (ret < 0)
+ ret = regmap_bulk_write(s->regmap, 0x7e, "\x01\xfe", 2);
+ if (ret)
goto err;
- ret = e4000_wr_reg(priv, 0x82, 0x00);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x82, 0x00);
+ if (ret)
goto err;
- ret = e4000_wr_reg(priv, 0x24, 0x05);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x24, 0x05);
+ if (ret)
goto err;
- ret = e4000_wr_regs(priv, 0x87, "\x20\x01", 2);
- if (ret < 0)
+ ret = regmap_bulk_write(s->regmap, 0x87, "\x20\x01", 2);
+ if (ret)
goto err;
- ret = e4000_wr_regs(priv, 0x9f, "\x7f\x07", 2);
- if (ret < 0)
+ ret = regmap_bulk_write(s->regmap, 0x9f, "\x7f\x07", 2);
+ if (ret)
goto err;
/* DC offset control */
- ret = e4000_wr_reg(priv, 0x2d, 0x1f);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x2d, 0x1f);
+ if (ret)
goto err;
- ret = e4000_wr_regs(priv, 0x70, "\x01\x01", 2);
- if (ret < 0)
+ ret = regmap_bulk_write(s->regmap, 0x70, "\x01\x01", 2);
+ if (ret)
goto err;
/* gain control */
- ret = e4000_wr_reg(priv, 0x1a, 0x17);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x1a, 0x17);
+ if (ret)
goto err;
- ret = e4000_wr_reg(priv, 0x1f, 0x1a);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x1f, 0x1a);
+ if (ret)
goto err;
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
-
- return 0;
+ s->active = true;
err:
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
+ if (ret)
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
static int e4000_sleep(struct dvb_frontend *fe)
{
- struct e4000_priv *priv = fe->tuner_priv;
+ struct e4000 *s = fe->tuner_priv;
int ret;
- dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
+ dev_dbg(&s->client->dev, "%s:\n", __func__);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
+ s->active = false;
- ret = e4000_wr_reg(priv, 0x00, 0x00);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x00, 0x00);
+ if (ret)
goto err;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
-
- return 0;
err:
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
+ if (ret)
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
static int e4000_set_params(struct dvb_frontend *fe)
{
- struct e4000_priv *priv = fe->tuner_priv;
+ struct e4000 *s = fe->tuner_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret, i, sigma_delta;
- unsigned int f_vco;
+ unsigned int pll_n, pll_f;
+ u64 f_vco;
u8 buf[5], i_data[4], q_data[4];
- dev_dbg(&priv->i2c->dev,
- "%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n",
+ dev_dbg(&s->client->dev,
+ "%s: delivery_system=%d frequency=%u bandwidth_hz=%u\n",
__func__, c->delivery_system, c->frequency,
c->bandwidth_hz);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
/* gain control manual */
- ret = e4000_wr_reg(priv, 0x1a, 0x00);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x1a, 0x00);
+ if (ret)
goto err;
/* PLL */
@@ -248,23 +141,21 @@ static int e4000_set_params(struct dvb_frontend *fe)
goto err;
}
- /*
- * Note: Currently f_vco overflows when c->frequency is 1 073 741 824 Hz
- * or more.
- */
- f_vco = c->frequency * e4000_pll_lut[i].mul;
- sigma_delta = div_u64(0x10000ULL * (f_vco % priv->cfg->clock), priv->cfg->clock);
- buf[0] = f_vco / priv->cfg->clock;
+ f_vco = 1ull * c->frequency * e4000_pll_lut[i].mul;
+ pll_n = div_u64_rem(f_vco, s->clock, &pll_f);
+ sigma_delta = div_u64(0x10000ULL * pll_f, s->clock);
+ buf[0] = pll_n;
buf[1] = (sigma_delta >> 0) & 0xff;
buf[2] = (sigma_delta >> 8) & 0xff;
buf[3] = 0x00;
buf[4] = e4000_pll_lut[i].div;
- dev_dbg(&priv->i2c->dev, "%s: f_vco=%u pll div=%d sigma_delta=%04x\n",
+ dev_dbg(&s->client->dev,
+ "%s: f_vco=%llu pll div=%d sigma_delta=%04x\n",
__func__, f_vco, buf[0], sigma_delta);
- ret = e4000_wr_regs(priv, 0x09, buf, 5);
- if (ret < 0)
+ ret = regmap_bulk_write(s->regmap, 0x09, buf, 5);
+ if (ret)
goto err;
/* LNA filter (RF filter) */
@@ -278,8 +169,8 @@ static int e4000_set_params(struct dvb_frontend *fe)
goto err;
}
- ret = e4000_wr_reg(priv, 0x10, e400_lna_filter_lut[i].val);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x10, e400_lna_filter_lut[i].val);
+ if (ret)
goto err;
/* IF filters */
@@ -296,8 +187,8 @@ static int e4000_set_params(struct dvb_frontend *fe)
buf[0] = e4000_if_filter_lut[i].reg11_val;
buf[1] = e4000_if_filter_lut[i].reg12_val;
- ret = e4000_wr_regs(priv, 0x11, buf, 2);
- if (ret < 0)
+ ret = regmap_bulk_write(s->regmap, 0x11, buf, 2);
+ if (ret)
goto err;
/* frequency band */
@@ -311,34 +202,34 @@ static int e4000_set_params(struct dvb_frontend *fe)
goto err;
}
- ret = e4000_wr_reg(priv, 0x07, e4000_band_lut[i].reg07_val);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x07, e4000_band_lut[i].reg07_val);
+ if (ret)
goto err;
- ret = e4000_wr_reg(priv, 0x78, e4000_band_lut[i].reg78_val);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x78, e4000_band_lut[i].reg78_val);
+ if (ret)
goto err;
/* DC offset */
for (i = 0; i < 4; i++) {
if (i == 0)
- ret = e4000_wr_regs(priv, 0x15, "\x00\x7e\x24", 3);
+ ret = regmap_bulk_write(s->regmap, 0x15, "\x00\x7e\x24", 3);
else if (i == 1)
- ret = e4000_wr_regs(priv, 0x15, "\x00\x7f", 2);
+ ret = regmap_bulk_write(s->regmap, 0x15, "\x00\x7f", 2);
else if (i == 2)
- ret = e4000_wr_regs(priv, 0x15, "\x01", 1);
+ ret = regmap_bulk_write(s->regmap, 0x15, "\x01", 1);
else
- ret = e4000_wr_regs(priv, 0x16, "\x7e", 1);
+ ret = regmap_bulk_write(s->regmap, 0x16, "\x7e", 1);
- if (ret < 0)
+ if (ret)
goto err;
- ret = e4000_wr_reg(priv, 0x29, 0x01);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x29, 0x01);
+ if (ret)
goto err;
- ret = e4000_rd_regs(priv, 0x2a, buf, 3);
- if (ret < 0)
+ ret = regmap_bulk_read(s->regmap, 0x2a, buf, 3);
+ if (ret)
goto err;
i_data[i] = (((buf[2] >> 0) & 0x3) << 6) | (buf[0] & 0x3f);
@@ -348,53 +239,226 @@ static int e4000_set_params(struct dvb_frontend *fe)
swap(q_data[2], q_data[3]);
swap(i_data[2], i_data[3]);
- ret = e4000_wr_regs(priv, 0x50, q_data, 4);
- if (ret < 0)
+ ret = regmap_bulk_write(s->regmap, 0x50, q_data, 4);
+ if (ret)
goto err;
- ret = e4000_wr_regs(priv, 0x60, i_data, 4);
- if (ret < 0)
+ ret = regmap_bulk_write(s->regmap, 0x60, i_data, 4);
+ if (ret)
goto err;
/* gain control auto */
- ret = e4000_wr_reg(priv, 0x1a, 0x17);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x1a, 0x17);
+ if (ret)
goto err;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
-
- return 0;
err:
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
+ if (ret)
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
static int e4000_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
{
- struct e4000_priv *priv = fe->tuner_priv;
+ struct e4000 *s = fe->tuner_priv;
- dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
+ dev_dbg(&s->client->dev, "%s:\n", __func__);
*frequency = 0; /* Zero-IF */
return 0;
}
-static int e4000_release(struct dvb_frontend *fe)
+#if IS_ENABLED(CONFIG_VIDEO_V4L2)
+static int e4000_set_lna_gain(struct dvb_frontend *fe)
{
- struct e4000_priv *priv = fe->tuner_priv;
+ struct e4000 *s = fe->tuner_priv;
+ int ret;
+ u8 u8tmp;
+
+ dev_dbg(&s->client->dev, "%s: lna auto=%d->%d val=%d->%d\n",
+ __func__, s->lna_gain_auto->cur.val,
+ s->lna_gain_auto->val, s->lna_gain->cur.val,
+ s->lna_gain->val);
+
+ if (s->lna_gain_auto->val && s->if_gain_auto->cur.val)
+ u8tmp = 0x17;
+ else if (s->lna_gain_auto->val)
+ u8tmp = 0x19;
+ else if (s->if_gain_auto->cur.val)
+ u8tmp = 0x16;
+ else
+ u8tmp = 0x10;
+
+ ret = regmap_write(s->regmap, 0x1a, u8tmp);
+ if (ret)
+ goto err;
+
+ if (s->lna_gain_auto->val == false) {
+ ret = regmap_write(s->regmap, 0x14, s->lna_gain->val);
+ if (ret)
+ goto err;
+ }
+err:
+ if (ret)
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
- dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
+ return ret;
+}
- kfree(fe->tuner_priv);
+static int e4000_set_mixer_gain(struct dvb_frontend *fe)
+{
+ struct e4000 *s = fe->tuner_priv;
+ int ret;
+ u8 u8tmp;
- return 0;
+ dev_dbg(&s->client->dev, "%s: mixer auto=%d->%d val=%d->%d\n",
+ __func__, s->mixer_gain_auto->cur.val,
+ s->mixer_gain_auto->val, s->mixer_gain->cur.val,
+ s->mixer_gain->val);
+
+ if (s->mixer_gain_auto->val)
+ u8tmp = 0x15;
+ else
+ u8tmp = 0x14;
+
+ ret = regmap_write(s->regmap, 0x20, u8tmp);
+ if (ret)
+ goto err;
+
+ if (s->mixer_gain_auto->val == false) {
+ ret = regmap_write(s->regmap, 0x15, s->mixer_gain->val);
+ if (ret)
+ goto err;
+ }
+err:
+ if (ret)
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+
+ return ret;
}
+static int e4000_set_if_gain(struct dvb_frontend *fe)
+{
+ struct e4000 *s = fe->tuner_priv;
+ int ret;
+ u8 buf[2];
+ u8 u8tmp;
+
+ dev_dbg(&s->client->dev, "%s: if auto=%d->%d val=%d->%d\n",
+ __func__, s->if_gain_auto->cur.val,
+ s->if_gain_auto->val, s->if_gain->cur.val,
+ s->if_gain->val);
+
+ if (s->if_gain_auto->val && s->lna_gain_auto->cur.val)
+ u8tmp = 0x17;
+ else if (s->lna_gain_auto->cur.val)
+ u8tmp = 0x19;
+ else if (s->if_gain_auto->val)
+ u8tmp = 0x16;
+ else
+ u8tmp = 0x10;
+
+ ret = regmap_write(s->regmap, 0x1a, u8tmp);
+ if (ret)
+ goto err;
+
+ if (s->if_gain_auto->val == false) {
+ buf[0] = e4000_if_gain_lut[s->if_gain->val].reg16_val;
+ buf[1] = e4000_if_gain_lut[s->if_gain->val].reg17_val;
+ ret = regmap_bulk_write(s->regmap, 0x16, buf, 2);
+ if (ret)
+ goto err;
+ }
+err:
+ if (ret)
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int e4000_pll_lock(struct dvb_frontend *fe)
+{
+ struct e4000 *s = fe->tuner_priv;
+ int ret;
+ unsigned int utmp;
+
+ ret = regmap_read(s->regmap, 0x07, &utmp);
+ if (ret)
+ goto err;
+
+ s->pll_lock->val = (utmp & 0x01);
+err:
+ if (ret)
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct e4000 *s = container_of(ctrl->handler, struct e4000, hdl);
+ int ret;
+
+ if (s->active == false)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_RF_TUNER_PLL_LOCK:
+ ret = e4000_pll_lock(s->fe);
+ break;
+ default:
+ dev_dbg(&s->client->dev, "%s: unknown ctrl: id=%d name=%s\n",
+ __func__, ctrl->id, ctrl->name);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int e4000_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct e4000 *s = container_of(ctrl->handler, struct e4000, hdl);
+ struct dvb_frontend *fe = s->fe;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret;
+
+ if (s->active == false)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:
+ case V4L2_CID_RF_TUNER_BANDWIDTH:
+ c->bandwidth_hz = s->bandwidth->val;
+ ret = e4000_set_params(s->fe);
+ break;
+ case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO:
+ case V4L2_CID_RF_TUNER_LNA_GAIN:
+ ret = e4000_set_lna_gain(s->fe);
+ break;
+ case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO:
+ case V4L2_CID_RF_TUNER_MIXER_GAIN:
+ ret = e4000_set_mixer_gain(s->fe);
+ break;
+ case V4L2_CID_RF_TUNER_IF_GAIN_AUTO:
+ case V4L2_CID_RF_TUNER_IF_GAIN:
+ ret = e4000_set_if_gain(s->fe);
+ break;
+ default:
+ dev_dbg(&s->client->dev, "%s: unknown ctrl: id=%d name=%s\n",
+ __func__, ctrl->id, ctrl->name);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops e4000_ctrl_ops = {
+ .g_volatile_ctrl = e4000_g_volatile_ctrl,
+ .s_ctrl = e4000_s_ctrl,
+};
+#endif
+
static const struct dvb_tuner_ops e4000_tuner_ops = {
.info = {
.name = "Elonics E4000",
@@ -402,8 +466,6 @@ static const struct dvb_tuner_ops e4000_tuner_ops = {
.frequency_max = 862000000,
},
- .release = e4000_release,
-
.init = e4000_init,
.sleep = e4000_sleep,
.set_params = e4000_set_params,
@@ -411,62 +473,148 @@ static const struct dvb_tuner_ops e4000_tuner_ops = {
.get_if_frequency = e4000_get_if_frequency,
};
-struct dvb_frontend *e4000_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c, const struct e4000_config *cfg)
+/*
+ * Use V4L2 subdev to carry V4L2 control handler, even we don't implement
+ * subdev itself, just to avoid reinventing the wheel.
+ */
+static int e4000_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- struct e4000_priv *priv;
+ struct e4000_config *cfg = client->dev.platform_data;
+ struct dvb_frontend *fe = cfg->fe;
+ struct e4000 *s;
int ret;
- u8 chip_id;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
+ unsigned int utmp;
+ static const struct regmap_config regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xff,
+ };
- priv = kzalloc(sizeof(struct e4000_priv), GFP_KERNEL);
- if (!priv) {
+ s = kzalloc(sizeof(struct e4000), GFP_KERNEL);
+ if (!s) {
ret = -ENOMEM;
- dev_err(&i2c->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+ dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
goto err;
}
- priv->cfg = cfg;
- priv->i2c = i2c;
+ s->clock = cfg->clock;
+ s->client = client;
+ s->fe = cfg->fe;
+ s->regmap = devm_regmap_init_i2c(client, &regmap_config);
+ if (IS_ERR(s->regmap)) {
+ ret = PTR_ERR(s->regmap);
+ goto err;
+ }
/* check if the tuner is there */
- ret = e4000_rd_reg(priv, 0x02, &chip_id);
- if (ret < 0)
+ ret = regmap_read(s->regmap, 0x02, &utmp);
+ if (ret)
goto err;
- dev_dbg(&priv->i2c->dev, "%s: chip_id=%02x\n", __func__, chip_id);
+ dev_dbg(&s->client->dev, "%s: chip id=%02x\n", __func__, utmp);
- if (chip_id != 0x40)
+ if (utmp != 0x40) {
+ ret = -ENODEV;
goto err;
+ }
/* put sleep as chip seems to be in normal mode by default */
- ret = e4000_wr_reg(priv, 0x00, 0x00);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x00, 0x00);
+ if (ret)
goto err;
- dev_info(&priv->i2c->dev,
+#if IS_ENABLED(CONFIG_VIDEO_V4L2)
+ /* Register controls */
+ v4l2_ctrl_handler_init(&s->hdl, 9);
+ s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops,
+ V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
+ s->bandwidth = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops,
+ V4L2_CID_RF_TUNER_BANDWIDTH, 4300000, 11000000, 100000, 4300000);
+ v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false);
+ s->lna_gain_auto = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops,
+ V4L2_CID_RF_TUNER_LNA_GAIN_AUTO, 0, 1, 1, 1);
+ s->lna_gain = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops,
+ V4L2_CID_RF_TUNER_LNA_GAIN, 0, 15, 1, 10);
+ v4l2_ctrl_auto_cluster(2, &s->lna_gain_auto, 0, false);
+ s->mixer_gain_auto = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops,
+ V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO, 0, 1, 1, 1);
+ s->mixer_gain = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops,
+ V4L2_CID_RF_TUNER_MIXER_GAIN, 0, 1, 1, 1);
+ v4l2_ctrl_auto_cluster(2, &s->mixer_gain_auto, 0, false);
+ s->if_gain_auto = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops,
+ V4L2_CID_RF_TUNER_IF_GAIN_AUTO, 0, 1, 1, 1);
+ s->if_gain = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops,
+ V4L2_CID_RF_TUNER_IF_GAIN, 0, 54, 1, 0);
+ v4l2_ctrl_auto_cluster(2, &s->if_gain_auto, 0, false);
+ s->pll_lock = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops,
+ V4L2_CID_RF_TUNER_PLL_LOCK, 0, 1, 1, 0);
+ if (s->hdl.error) {
+ ret = s->hdl.error;
+ dev_err(&s->client->dev, "Could not initialize controls\n");
+ v4l2_ctrl_handler_free(&s->hdl);
+ goto err;
+ }
+
+ s->sd.ctrl_handler = &s->hdl;
+#endif
+
+ dev_info(&s->client->dev,
"%s: Elonics E4000 successfully identified\n",
KBUILD_MODNAME);
- fe->tuner_priv = priv;
+ fe->tuner_priv = s;
memcpy(&fe->ops.tuner_ops, &e4000_tuner_ops,
sizeof(struct dvb_tuner_ops));
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
+ v4l2_set_subdevdata(&s->sd, client);
+ i2c_set_clientdata(client, &s->sd);
- return fe;
+ return 0;
err:
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
+ if (ret) {
+ dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
+ kfree(s);
+ }
+
+ return ret;
+}
+
+static int e4000_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct e4000 *s = container_of(sd, struct e4000, sd);
+ struct dvb_frontend *fe = s->fe;
+
+ dev_dbg(&client->dev, "%s:\n", __func__);
- dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret);
- kfree(priv);
- return NULL;
+#if IS_ENABLED(CONFIG_VIDEO_V4L2)
+ v4l2_ctrl_handler_free(&s->hdl);
+#endif
+ memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
+ fe->tuner_priv = NULL;
+ kfree(s);
+
+ return 0;
}
-EXPORT_SYMBOL(e4000_attach);
+
+static const struct i2c_device_id e4000_id[] = {
+ {"e4000", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, e4000_id);
+
+static struct i2c_driver e4000_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "e4000",
+ },
+ .probe = e4000_probe,
+ .remove = e4000_remove,
+ .id_table = e4000_id,
+};
+
+module_i2c_driver(e4000_driver);
MODULE_DESCRIPTION("Elonics E4000 silicon tuner driver");
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/tuners/e4000.h b/drivers/media/tuners/e4000.h
index 25ee7c07abff..e74b8b2f2fc3 100644
--- a/drivers/media/tuners/e4000.h
+++ b/drivers/media/tuners/e4000.h
@@ -24,12 +24,15 @@
#include <linux/kconfig.h>
#include "dvb_frontend.h"
+/*
+ * I2C address
+ * 0x64, 0x65, 0x66, 0x67
+ */
struct e4000_config {
/*
- * I2C address
- * 0x64, 0x65, 0x66, 0x67
+ * frontend
*/
- u8 i2c_addr;
+ struct dvb_frontend *fe;
/*
* clock
@@ -37,16 +40,4 @@ struct e4000_config {
u32 clock;
};
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_E4000)
-extern struct dvb_frontend *e4000_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c, const struct e4000_config *cfg);
-#else
-static inline struct dvb_frontend *e4000_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c, const struct e4000_config *cfg)
-{
- dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__);
- return NULL;
-}
-#endif
-
#endif
diff --git a/drivers/media/tuners/e4000_priv.h b/drivers/media/tuners/e4000_priv.h
index a3855053e78f..cb0070483e65 100644
--- a/drivers/media/tuners/e4000_priv.h
+++ b/drivers/media/tuners/e4000_priv.h
@@ -22,10 +22,29 @@
#define E4000_PRIV_H
#include "e4000.h"
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+#include <linux/regmap.h>
-struct e4000_priv {
- const struct e4000_config *cfg;
- struct i2c_adapter *i2c;
+struct e4000 {
+ struct i2c_client *client;
+ struct regmap *regmap;
+ u32 clock;
+ struct dvb_frontend *fe;
+ struct v4l2_subdev sd;
+ bool active;
+
+ /* Controls */
+ struct v4l2_ctrl_handler hdl;
+ struct v4l2_ctrl *bandwidth_auto;
+ struct v4l2_ctrl *bandwidth;
+ struct v4l2_ctrl *lna_gain_auto;
+ struct v4l2_ctrl *lna_gain;
+ struct v4l2_ctrl *mixer_gain_auto;
+ struct v4l2_ctrl *mixer_gain;
+ struct v4l2_ctrl *if_gain_auto;
+ struct v4l2_ctrl *if_gain;
+ struct v4l2_ctrl *pll_lock;
};
struct e4000_pll {
@@ -144,4 +163,67 @@ static const struct e4000_if_filter e4000_if_filter_lut[] = {
{ 0xffffffff, 0x00, 0x20 },
};
+struct e4000_if_gain {
+ u8 reg16_val;
+ u8 reg17_val;
+};
+
+static const struct e4000_if_gain e4000_if_gain_lut[] = {
+ {0x00, 0x00},
+ {0x20, 0x00},
+ {0x40, 0x00},
+ {0x02, 0x00},
+ {0x22, 0x00},
+ {0x42, 0x00},
+ {0x04, 0x00},
+ {0x24, 0x00},
+ {0x44, 0x00},
+ {0x01, 0x00},
+ {0x21, 0x00},
+ {0x41, 0x00},
+ {0x03, 0x00},
+ {0x23, 0x00},
+ {0x43, 0x00},
+ {0x05, 0x00},
+ {0x25, 0x00},
+ {0x45, 0x00},
+ {0x07, 0x00},
+ {0x27, 0x00},
+ {0x47, 0x00},
+ {0x0f, 0x00},
+ {0x2f, 0x00},
+ {0x4f, 0x00},
+ {0x17, 0x00},
+ {0x37, 0x00},
+ {0x57, 0x00},
+ {0x1f, 0x00},
+ {0x3f, 0x00},
+ {0x5f, 0x00},
+ {0x1f, 0x01},
+ {0x3f, 0x01},
+ {0x5f, 0x01},
+ {0x1f, 0x02},
+ {0x3f, 0x02},
+ {0x5f, 0x02},
+ {0x1f, 0x03},
+ {0x3f, 0x03},
+ {0x5f, 0x03},
+ {0x1f, 0x04},
+ {0x3f, 0x04},
+ {0x5f, 0x04},
+ {0x1f, 0x0c},
+ {0x3f, 0x0c},
+ {0x5f, 0x0c},
+ {0x1f, 0x14},
+ {0x3f, 0x14},
+ {0x5f, 0x14},
+ {0x1f, 0x1c},
+ {0x3f, 0x1c},
+ {0x5f, 0x1c},
+ {0x1f, 0x24},
+ {0x3f, 0x24},
+ {0x5f, 0x24},
+ {0x7f, 0x24},
+};
+
#endif
diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c
index 20cca405bf45..f640dcf4a81d 100644
--- a/drivers/media/tuners/mt2063.c
+++ b/drivers/media/tuners/mt2063.c
@@ -1,7 +1,7 @@
/*
* Driver for mt2063 Micronas tuner
*
- * Copyright (c) 2011 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2011 Mauro Carvalho Chehab
*
* This driver came from a driver originally written by:
* Henry Wang <Henry.wang@AzureWave.com>
@@ -2298,6 +2298,6 @@ static int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe)
}
#endif
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_DESCRIPTION("MT2063 Silicon tuner");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c
index d9ee43fae62d..319adc4f0561 100644
--- a/drivers/media/tuners/r820t.c
+++ b/drivers/media/tuners/r820t.c
@@ -1,7 +1,7 @@
/*
* Rafael Micro R820T driver
*
- * Copyright (C) 2013 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2013 Mauro Carvalho Chehab
*
* This driver was written from scratch, based on an existing driver
* that it is part of rtl-sdr git tree, released under GPLv2:
@@ -2351,5 +2351,5 @@ err_no_gate:
EXPORT_SYMBOL_GPL(r820t_attach);
MODULE_DESCRIPTION("Rafael Micro r820t silicon tuner driver");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/tda18212.c b/drivers/media/tuners/tda18212.c
index abe256e1f843..05a4ac9edb6b 100644
--- a/drivers/media/tuners/tda18212.c
+++ b/drivers/media/tuners/tda18212.c
@@ -150,6 +150,8 @@ static int tda18212_set_params(struct dvb_frontend *fe)
#define DVBT2_8 5
#define DVBC_6 6
#define DVBC_8 7
+ #define ATSC_VSB 8
+ #define ATSC_QAM 9
static const u8 bw_params[][3] = {
/* reg: 0f 13 23 */
[DVBT_6] = { 0xb3, 0x20, 0x03 },
@@ -160,6 +162,8 @@ static int tda18212_set_params(struct dvb_frontend *fe)
[DVBT2_8] = { 0xbc, 0x22, 0x01 },
[DVBC_6] = { 0x92, 0x50, 0x03 },
[DVBC_8] = { 0x92, 0x53, 0x03 },
+ [ATSC_VSB] = { 0x7d, 0x20, 0x63 },
+ [ATSC_QAM] = { 0x7d, 0x20, 0x63 },
};
dev_dbg(&priv->i2c->dev,
@@ -171,6 +175,14 @@ static int tda18212_set_params(struct dvb_frontend *fe)
fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
switch (c->delivery_system) {
+ case SYS_ATSC:
+ if_khz = priv->cfg->if_atsc_vsb;
+ i = ATSC_VSB;
+ break;
+ case SYS_DVBC_ANNEX_B:
+ if_khz = priv->cfg->if_atsc_qam;
+ i = ATSC_QAM;
+ break;
case SYS_DVBT:
switch (c->bandwidth_hz) {
case 6000000:
diff --git a/drivers/media/tuners/tda18212.h b/drivers/media/tuners/tda18212.h
index 7e0d503baf05..c36b49e4b274 100644
--- a/drivers/media/tuners/tda18212.h
+++ b/drivers/media/tuners/tda18212.h
@@ -35,6 +35,8 @@ struct tda18212_config {
u16 if_dvbt2_7;
u16 if_dvbt2_8;
u16 if_dvbc;
+ u16 if_atsc_vsb;
+ u16 if_atsc_qam;
};
#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA18212)
diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c
index cca508d4aafb..76a816511f2f 100644
--- a/drivers/media/tuners/tuner-xc2028.c
+++ b/drivers/media/tuners/tuner-xc2028.c
@@ -1107,6 +1107,9 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
offset += 200000;
}
#endif
+ default:
+ tuner_err("Unsupported tuner type %d.\n", new_type);
+ break;
}
div = (freq - offset + DIV / 2) / DIV;
diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c
index dd32decb237d..7fdadf9bc90b 100644
--- a/drivers/media/usb/au0828/au0828-cards.c
+++ b/drivers/media/usb/au0828/au0828-cards.c
@@ -108,7 +108,7 @@ struct au0828_board au0828_boards[] = {
.name = "DViCO FusionHDTV USB",
.tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
- .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
+ .i2c_clk_divider = AU0828_I2C_CLK_20KHZ,
},
[AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
.name = "Hauppauge Woodbury",
@@ -270,18 +270,25 @@ void au0828_gpio_setup(struct au0828_dev *dev)
* 9 - XC5000 Tuner
*/
- /* Into reset */
+ /* Set relevant GPIOs as outputs (leave the EEPROM W/P
+ as an input since we will never touch it and it has
+ a pullup) */
au0828_write(dev, REG_003, 0x02);
au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
+
+ /* Into reset */
au0828_write(dev, REG_001, 0x0);
au0828_write(dev, REG_000, 0x0);
- msleep(100);
+ msleep(50);
- /* Out of reset (leave the cs5340 in reset until needed) */
- au0828_write(dev, REG_003, 0x02);
- au0828_write(dev, REG_001, 0x02);
- au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
- au0828_write(dev, REG_000, 0x80 | 0x40 | 0x20);
+ /* Bring power supply out of reset */
+ au0828_write(dev, REG_000, 0x80);
+ msleep(50);
+
+ /* Bring xc5000 and au8522 out of reset (leave the
+ cs5340 in reset until needed) */
+ au0828_write(dev, REG_001, 0x02); /* xc5000 */
+ au0828_write(dev, REG_000, 0x80 | 0x20); /* PS + au8522 */
msleep(250);
break;
diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c
index 81a1d971d797..9b925874d392 100644
--- a/drivers/media/usb/cx231xx/cx231xx-audio.c
+++ b/drivers/media/usb/cx231xx/cx231xx-audio.c
@@ -665,8 +665,8 @@ static int cx231xx_audio_init(struct cx231xx *dev)
cx231xx_info("cx231xx-audio.c: probing for cx231xx "
"non standard usbaudio\n");
- err = snd_card_create(index[devnr], "Cx231xx Audio", THIS_MODULE,
- 0, &card);
+ err = snd_card_new(&dev->udev->dev, index[devnr], "Cx231xx Audio",
+ THIS_MODULE, 0, &card);
if (err < 0)
return err;
@@ -682,7 +682,6 @@ static int cx231xx_audio_init(struct cx231xx *dev)
pcm->info_flags = 0;
pcm->private_data = dev;
strcpy(pcm->name, "Conexant cx231xx Capture");
- snd_card_set_dev(card, &dev->udev->dev);
strcpy(card->driver, "Cx231xx-Audio");
strcpy(card->shortname, "Cx231xx Audio");
strcpy(card->longname, "Conexant cx231xx Audio");
diff --git a/drivers/media/usb/cx231xx/cx231xx-input.c b/drivers/media/usb/cx231xx/cx231xx-input.c
index 0f7b42446826..46d52fac8680 100644
--- a/drivers/media/usb/cx231xx/cx231xx-input.c
+++ b/drivers/media/usb/cx231xx/cx231xx-input.c
@@ -1,7 +1,7 @@
/*
* cx231xx IR glue driver
*
- * Copyright (C) 2010 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2010 Mauro Carvalho Chehab
*
* Polaris (cx231xx) has its support for IR's with a design close to MCE.
* however, a few designs are using an external I2C chip for IR, instead
diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig
index 2059d0c86ad3..037e519bbaa2 100644
--- a/drivers/media/usb/dvb-usb-v2/Kconfig
+++ b/drivers/media/usb/dvb-usb-v2/Kconfig
@@ -100,13 +100,6 @@ config DVB_USB_GL861
Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0
receiver with USB ID 0db0:5581.
-config DVB_USB_IT913X
- tristate "ITE IT913X DVB-T USB2.0 support"
- depends on DVB_USB_V2
- select DVB_IT913X_FE
- help
- Say Y here to support the ITE IT913X DVB-T USB2.0
-
config DVB_USB_LME2510
tristate "LME DM04/QQBOX DVB-S USB2.0 support"
depends on DVB_USB_V2
@@ -133,7 +126,7 @@ config DVB_USB_MXL111SF
config DVB_USB_RTL28XXU
tristate "Realtek RTL28xxU DVB USB support"
- depends on DVB_USB_V2
+ depends on DVB_USB_V2 && I2C_MUX
select DVB_RTL2830
select DVB_RTL2832
select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/usb/dvb-usb-v2/Makefile b/drivers/media/usb/dvb-usb-v2/Makefile
index 2c06714b9ef0..7407b8338ccf 100644
--- a/drivers/media/usb/dvb-usb-v2/Makefile
+++ b/drivers/media/usb/dvb-usb-v2/Makefile
@@ -22,9 +22,6 @@ obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o
dvb-usb-ec168-objs := ec168.o
obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
-dvb-usb-it913x-objs := it913x.o
-obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o
-
dvb-usb-lmedm04-objs := lmedm04.o
obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o
@@ -44,3 +41,4 @@ ccflags-y += -I$(srctree)/drivers/media/dvb-core
ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
ccflags-y += -I$(srctree)/drivers/media/tuners
ccflags-y += -I$(srctree)/drivers/media/common
+ccflags-y += -I$(srctree)/drivers/staging/media/rtl2832u_sdr
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
index 8ede8ea762e6..021e4d35e4d7 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.c
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -575,6 +575,10 @@ static int af9035_download_firmware(struct dvb_usb_device *d,
if (ret < 0)
goto err;
+ /* use default I2C address if eeprom has no address set */
+ if (!tmp)
+ tmp = 0x3a;
+
if (state->chip_type == 0x9135) {
ret = af9035_wr_reg(d, 0x004bfb, tmp);
if (ret < 0)
@@ -637,6 +641,7 @@ static int af9035_read_config(struct dvb_usb_device *d)
/* demod I2C "address" */
state->af9033_config[0].i2c_addr = 0x38;
+ state->af9033_config[1].i2c_addr = 0x3a;
state->af9033_config[0].adc_multiplier = AF9033_ADC_MULTIPLIER_2X;
state->af9033_config[1].adc_multiplier = AF9033_ADC_MULTIPLIER_2X;
state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB;
@@ -684,7 +689,9 @@ static int af9035_read_config(struct dvb_usb_device *d)
if (ret < 0)
goto err;
- state->af9033_config[1].i2c_addr = tmp;
+ if (tmp)
+ state->af9033_config[1].i2c_addr = tmp;
+
dev_dbg(&d->udev->dev, "%s: 2nd demod I2C addr=%02x\n",
__func__, tmp);
}
@@ -938,12 +945,7 @@ static int af9035_frontend_callback(void *adapter_priv, int component,
static int af9035_get_adapter_count(struct dvb_usb_device *d)
{
struct state *state = d_to_priv(d);
-
- /* disable 2nd adapter as we don't have PID filters implemented */
- if (d->udev->speed == USB_SPEED_FULL)
- return 1;
- else
- return state->dual_mode + 1;
+ return state->dual_mode + 1;
}
static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
@@ -961,7 +963,7 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
/* attach demodulator */
adap->fe[0] = dvb_attach(af9033_attach, &state->af9033_config[adap->id],
- &d->i2c_adap);
+ &d->i2c_adap, &state->ops);
if (adap->fe[0] == NULL) {
ret = -ENODEV;
goto err;
@@ -1369,58 +1371,19 @@ static int af9035_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
return 0;
}
-/*
- * FIXME: PID filter is property of demodulator and should be moved to the
- * correct driver. Also we support only adapter #0 PID filter and will
- * disable adapter #1 if USB1.1 is used.
- */
static int af9035_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
- struct dvb_usb_device *d = adap_to_d(adap);
- int ret;
-
- dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
-
- ret = af9035_wr_reg_mask(d, 0x80f993, onoff, 0x01);
- if (ret < 0)
- goto err;
-
- return 0;
-
-err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ struct state *state = adap_to_priv(adap);
- return ret;
+ return state->ops.pid_filter_ctrl(adap->fe[0], onoff);
}
static int af9035_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
int onoff)
{
- struct dvb_usb_device *d = adap_to_d(adap);
- int ret;
- u8 wbuf[2] = {(pid >> 0) & 0xff, (pid >> 8) & 0xff};
-
- dev_dbg(&d->udev->dev, "%s: index=%d pid=%04x onoff=%d\n",
- __func__, index, pid, onoff);
-
- ret = af9035_wr_regs(d, 0x80f996, wbuf, 2);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg(d, 0x80f994, onoff);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg(d, 0x80f995, index);
- if (ret < 0)
- goto err;
-
- return 0;
-
-err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ struct state *state = adap_to_priv(adap);
- return ret;
+ return state->ops.pid_filter(adap->fe[0], index, pid, onoff);
}
static int af9035_probe(struct usb_interface *intf,
@@ -1494,6 +1457,13 @@ static const struct dvb_usb_device_properties af9035_props = {
.stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188),
}, {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+ .pid_filter_count = 32,
+ .pid_filter_ctrl = af9035_pid_filter_ctrl,
+ .pid_filter = af9035_pid_filter,
+
.stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188),
},
},
@@ -1528,12 +1498,30 @@ static const struct usb_device_id af9035_id_table[] = {
{ DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00aa,
&af9035_props, "TerraTec Cinergy T Stick (rev. 2)", NULL) },
/* IT9135 devices */
-#if 0
- { DVB_USB_DEVICE(0x048d, 0x9135,
- &af9035_props, "IT9135 reference design", NULL) },
- { DVB_USB_DEVICE(0x048d, 0x9006,
- &af9035_props, "IT9135 reference design", NULL) },
-#endif
+ { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135,
+ &af9035_props, "ITE 9135 Generic", RC_MAP_IT913X_V1) },
+ { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9005,
+ &af9035_props, "ITE 9135(9005) Generic", RC_MAP_IT913X_V2) },
+ { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9006,
+ &af9035_props, "ITE 9135(9006) Generic", RC_MAP_IT913X_V1) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_1835,
+ &af9035_props, "Avermedia A835B(1835)", RC_MAP_IT913X_V2) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_2835,
+ &af9035_props, "Avermedia A835B(2835)", RC_MAP_IT913X_V2) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_3835,
+ &af9035_props, "Avermedia A835B(3835)", RC_MAP_IT913X_V2) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_4835,
+ &af9035_props, "Avermedia A835B(4835)", RC_MAP_IT913X_V2) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_H335,
+ &af9035_props, "Avermedia H335", RC_MAP_IT913X_V2) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09,
+ &af9035_props, "Kworld UB499-2T T09", RC_MAP_IT913X_V1) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22_IT9137,
+ &af9035_props, "Sveon STV22 Dual DVB-T HDTV",
+ RC_MAP_IT913X_V1) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2,
+ &af9035_props, "Digital Dual TV Receiver CTVDIGDUAL_V2",
+ RC_MAP_IT913X_V1) },
/* XXX: that same ID [0ccd:0099] is used by af9015 driver too */
{ DVB_USB_DEVICE(USB_VID_TERRATEC, 0x0099,
&af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)", NULL) },
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h
index a1c68d829b8c..c21902fdd4c4 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.h
+++ b/drivers/media/usb/dvb-usb-v2/af9035.h
@@ -62,6 +62,8 @@ struct state {
u8 dual_mode:1;
u16 eeprom_addr;
struct af9033_config af9033_config[2];
+
+ struct af9033_ops ops;
};
static const u32 clock_lut_af9035[] = {
diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c
index c1051c347744..c3c4b98733bf 100644
--- a/drivers/media/usb/dvb-usb-v2/az6007.c
+++ b/drivers/media/usb/dvb-usb-v2/az6007.c
@@ -7,7 +7,7 @@
* http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz
* The original driver's license is GPL, as declared with MODULE_LICENSE()
*
- * Copyright (c) 2010-2012 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010-2012 Mauro Carvalho Chehab
* Driver modified by in order to work with upstream drxk driver, and
* tons of bugs got fixed, and converted to use dvb-usb-v2.
*
@@ -975,7 +975,7 @@ static struct usb_driver az6007_usb_driver = {
module_usb_driver(az6007_usb_driver);
MODULE_AUTHOR("Henry Wang <Henry.wang@AzureWave.com>");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones");
MODULE_VERSION("2.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
index 8a054d66e708..de02db802ace 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -164,7 +164,7 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d)
dev->driver_name = (char *) d->props->driver_name;
dev->map_name = d->rc.map_name;
dev->driver_type = d->rc.driver_type;
- dev->allowed_protos = d->rc.allowed_protos;
+ rc_set_allowed_protocols(dev, d->rc.allowed_protos);
dev->change_protocol = d->rc.change_protocol;
dev->priv = d;
diff --git a/drivers/media/usb/dvb-usb-v2/it913x.c b/drivers/media/usb/dvb-usb-v2/it913x.c
deleted file mode 100644
index fe95a586dd5d..000000000000
--- a/drivers/media/usb/dvb-usb-v2/it913x.c
+++ /dev/null
@@ -1,828 +0,0 @@
-/*
- * DVB USB compliant linux driver for ITE IT9135 and IT9137
- *
- * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
- * IT9135 (C) ITE Tech Inc.
- * IT9137 (C) ITE Tech 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.
- *
- * You 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.
- *
- *
- * see Documentation/dvb/README.dvb-usb for more information
- * see Documentation/dvb/it9137.txt for firmware information
- *
- */
-#define DVB_USB_LOG_PREFIX "it913x"
-
-#include <linux/usb.h>
-#include <linux/usb/input.h>
-#include <media/rc-core.h>
-
-#include "dvb_usb.h"
-#include "it913x-fe.h"
-
-/* debug */
-static int dvb_usb_it913x_debug;
-#define it_debug(var, level, args...) \
- do { if ((var & level)) pr_debug(DVB_USB_LOG_PREFIX": " args); \
-} while (0)
-#define deb_info(level, args...) it_debug(dvb_usb_it913x_debug, level, args)
-#define info(args...) pr_info(DVB_USB_LOG_PREFIX": " args)
-
-module_param_named(debug, dvb_usb_it913x_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
-
-static int dvb_usb_it913x_firmware;
-module_param_named(firmware, dvb_usb_it913x_firmware, int, 0644);
-MODULE_PARM_DESC(firmware, "set firmware 0=auto "\
- "1=IT9137 2=IT9135 V1 3=IT9135 V2");
-#define FW_IT9137 "dvb-usb-it9137-01.fw"
-#define FW_IT9135_V1 "dvb-usb-it9135-01.fw"
-#define FW_IT9135_V2 "dvb-usb-it9135-02.fw"
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-struct it913x_state {
- struct ite_config it913x_config;
- u8 pid_filter_onoff;
- bool proprietary_ir;
- int cmd_counter;
-};
-
-static u16 check_sum(u8 *p, u8 len)
-{
- u16 sum = 0;
- u8 i = 1;
- while (i < len)
- sum += (i++ & 1) ? (*p++) << 8 : *p++;
- return ~sum;
-}
-
-static int it913x_io(struct dvb_usb_device *d, u8 mode, u8 pro,
- u8 cmd, u32 reg, u8 addr, u8 *data, u8 len)
-{
- struct it913x_state *st = d->priv;
- int ret = 0, i, buf_size = 1;
- u8 *buff;
- u8 rlen;
- u16 chk_sum;
-
- buff = kzalloc(256, GFP_KERNEL);
- if (!buff) {
- info("USB Buffer Failed");
- return -ENOMEM;
- }
-
- buff[buf_size++] = pro;
- buff[buf_size++] = cmd;
- buff[buf_size++] = st->cmd_counter;
-
- switch (mode) {
- case READ_LONG:
- case WRITE_LONG:
- buff[buf_size++] = len;
- buff[buf_size++] = 2;
- buff[buf_size++] = (reg >> 24);
- buff[buf_size++] = (reg >> 16) & 0xff;
- buff[buf_size++] = (reg >> 8) & 0xff;
- buff[buf_size++] = reg & 0xff;
- break;
- case READ_SHORT:
- buff[buf_size++] = addr;
- break;
- case WRITE_SHORT:
- buff[buf_size++] = len;
- buff[buf_size++] = addr;
- buff[buf_size++] = (reg >> 8) & 0xff;
- buff[buf_size++] = reg & 0xff;
- break;
- case READ_DATA:
- case WRITE_DATA:
- break;
- case WRITE_CMD:
- mode = 7;
- break;
- default:
- kfree(buff);
- return -EINVAL;
- }
-
- if (mode & 1) {
- for (i = 0; i < len ; i++)
- buff[buf_size++] = data[i];
- }
- chk_sum = check_sum(&buff[1], buf_size);
-
- buff[buf_size++] = chk_sum >> 8;
- buff[0] = buf_size;
- buff[buf_size++] = (chk_sum & 0xff);
-
- ret = dvb_usbv2_generic_rw(d, buff, buf_size, buff, (mode & 1) ?
- 5 : len + 5);
- if (ret < 0)
- goto error;
-
- rlen = (mode & 0x1) ? 0x1 : len;
-
- if (mode & 1)
- ret = buff[2];
- else
- memcpy(data, &buff[3], rlen);
-
- st->cmd_counter++;
-
-error: kfree(buff);
-
- return ret;
-}
-
-static int it913x_wr_reg(struct dvb_usb_device *d, u8 pro, u32 reg , u8 data)
-{
- int ret;
- u8 b[1];
- b[0] = data;
- ret = it913x_io(d, WRITE_LONG, pro,
- CMD_DEMOD_WRITE, reg, 0, b, sizeof(b));
-
- return ret;
-}
-
-static int it913x_read_reg(struct dvb_usb_device *d, u32 reg)
-{
- int ret;
- u8 data[1];
-
- ret = it913x_io(d, READ_LONG, DEV_0,
- CMD_DEMOD_READ, reg, 0, &data[0], sizeof(data));
-
- return (ret < 0) ? ret : data[0];
-}
-
-static int it913x_query(struct dvb_usb_device *d, u8 pro)
-{
- struct it913x_state *st = d->priv;
- int ret, i;
- u8 data[4];
- u8 ver;
-
- for (i = 0; i < 5; i++) {
- ret = it913x_io(d, READ_LONG, pro, CMD_DEMOD_READ,
- 0x1222, 0, &data[0], 3);
- ver = data[0];
- if (ver > 0 && ver < 3)
- break;
- msleep(100);
- }
-
- if (ver < 1 || ver > 2) {
- info("Failed to identify chip version applying 1");
- st->it913x_config.chip_ver = 0x1;
- st->it913x_config.chip_type = 0x9135;
- return 0;
- }
-
- st->it913x_config.chip_ver = ver;
- st->it913x_config.chip_type = (u16)(data[2] << 8) + data[1];
-
- info("Chip Version=%02x Chip Type=%04x", st->it913x_config.chip_ver,
- st->it913x_config.chip_type);
-
- ret = it913x_io(d, READ_SHORT, pro,
- CMD_QUERYINFO, 0, 0x1, &data[0], 4);
-
- st->it913x_config.firmware = (data[0] << 24) | (data[1] << 16) |
- (data[2] << 8) | data[3];
-
- return ret;
-}
-
-static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
- struct dvb_usb_device *d = adap_to_d(adap);
- struct it913x_state *st = adap_to_priv(adap);
- int ret;
- u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
-
- mutex_lock(&d->i2c_mutex);
-
- deb_info(1, "PID_C (%02x)", onoff);
-
- st->pid_filter_onoff = adap->pid_filtering;
- ret = it913x_wr_reg(d, pro, PID_EN, st->pid_filter_onoff);
-
- mutex_unlock(&d->i2c_mutex);
- return ret;
-}
-
-static int it913x_pid_filter(struct dvb_usb_adapter *adap,
- int index, u16 pid, int onoff)
-{
- struct dvb_usb_device *d = adap_to_d(adap);
- struct it913x_state *st = adap_to_priv(adap);
- int ret;
- u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
-
- mutex_lock(&d->i2c_mutex);
-
- deb_info(1, "PID_F (%02x)", onoff);
-
- ret = it913x_wr_reg(d, pro, PID_LSB, (u8)(pid & 0xff));
-
- ret |= it913x_wr_reg(d, pro, PID_MSB, (u8)(pid >> 8));
-
- ret |= it913x_wr_reg(d, pro, PID_INX_EN, (u8)onoff);
-
- ret |= it913x_wr_reg(d, pro, PID_INX, (u8)(index & 0x1f));
-
- if (d->udev->speed == USB_SPEED_HIGH && pid == 0x2000) {
- ret |= it913x_wr_reg(d , pro, PID_EN, !onoff);
- st->pid_filter_onoff = !onoff;
- } else
- st->pid_filter_onoff =
- adap->pid_filtering;
-
- mutex_unlock(&d->i2c_mutex);
- return 0;
-}
-
-
-static int it913x_return_status(struct dvb_usb_device *d)
-{
- struct it913x_state *st = d->priv;
- int ret = it913x_query(d, DEV_0);
- if (st->it913x_config.firmware > 0)
- info("Firmware Version %d", st->it913x_config.firmware);
-
- return ret;
-}
-
-static int it913x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- int num)
-{
- struct dvb_usb_device *d = i2c_get_adapdata(adap);
- static u8 data[256];
- int ret;
- u32 reg;
- u8 pro;
-
- mutex_lock(&d->i2c_mutex);
-
- deb_info(2, "num of messages %d address %02x", num, msg[0].addr);
-
- pro = (msg[0].addr & 0x2) ? DEV_0_DMOD : 0x0;
- pro |= (msg[0].addr & 0x20) ? DEV_1 : DEV_0;
- memcpy(data, msg[0].buf, msg[0].len);
- reg = (data[0] << 24) + (data[1] << 16) +
- (data[2] << 8) + data[3];
- if (num == 2) {
- ret = it913x_io(d, READ_LONG, pro,
- CMD_DEMOD_READ, reg, 0, data, msg[1].len);
- memcpy(msg[1].buf, data, msg[1].len);
- } else
- ret = it913x_io(d, WRITE_LONG, pro, CMD_DEMOD_WRITE,
- reg, 0, &data[4], msg[0].len - 4);
-
- mutex_unlock(&d->i2c_mutex);
-
- return ret;
-}
-
-static u32 it913x_i2c_func(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm it913x_i2c_algo = {
- .master_xfer = it913x_i2c_xfer,
- .functionality = it913x_i2c_func,
-};
-
-/* Callbacks for DVB USB */
-#if IS_ENABLED(CONFIG_RC_CORE)
-static int it913x_rc_query(struct dvb_usb_device *d)
-{
- u8 ibuf[4];
- int ret;
- u32 key;
- /* Avoid conflict with frontends*/
- mutex_lock(&d->i2c_mutex);
-
- ret = it913x_io(d, READ_LONG, PRO_LINK, CMD_IR_GET,
- 0, 0, &ibuf[0], sizeof(ibuf));
-
- if ((ibuf[2] + ibuf[3]) == 0xff) {
- key = ibuf[2];
- key += ibuf[0] << 16;
- key += ibuf[1] << 8;
- deb_info(1, "NEC Extended Key =%08x", key);
- if (d->rc_dev != NULL)
- rc_keydown(d->rc_dev, key, 0);
- }
-
- mutex_unlock(&d->i2c_mutex);
-
- return ret;
-}
-
-static int it913x_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
-{
- struct it913x_state *st = d->priv;
-
- if (st->proprietary_ir == false) {
- rc->map_name = NULL;
- return 0;
- }
-
- rc->allowed_protos = RC_BIT_NEC;
- rc->query = it913x_rc_query;
- rc->interval = 250;
-
- return 0;
-}
-#else
- #define it913x_get_rc_config NULL
-#endif
-
-/* Firmware sets raw */
-static const char fw_it9135_v1[] = FW_IT9135_V1;
-static const char fw_it9135_v2[] = FW_IT9135_V2;
-static const char fw_it9137[] = FW_IT9137;
-
-static void ite_get_firmware_name(struct dvb_usb_device *d,
- const char **name)
-{
- struct it913x_state *st = d->priv;
- int sw;
- /* auto switch */
- if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_KWORLD_2)
- sw = IT9137_FW;
- else if (st->it913x_config.chip_ver == 1)
- sw = IT9135_V1_FW;
- else
- sw = IT9135_V2_FW;
-
- /* force switch */
- if (dvb_usb_it913x_firmware != IT9135_AUTO)
- sw = dvb_usb_it913x_firmware;
-
- switch (sw) {
- case IT9135_V1_FW:
- st->it913x_config.firmware_ver = 1;
- st->it913x_config.adc_x2 = 1;
- st->it913x_config.read_slevel = false;
- *name = fw_it9135_v1;
- break;
- case IT9135_V2_FW:
- st->it913x_config.firmware_ver = 1;
- st->it913x_config.adc_x2 = 1;
- st->it913x_config.read_slevel = false;
- *name = fw_it9135_v2;
- switch (st->it913x_config.tuner_id_0) {
- case IT9135_61:
- case IT9135_62:
- break;
- default:
- info("Unknown tuner ID applying default 0x60");
- case IT9135_60:
- st->it913x_config.tuner_id_0 = IT9135_60;
- }
- break;
- case IT9137_FW:
- default:
- st->it913x_config.firmware_ver = 0;
- st->it913x_config.adc_x2 = 0;
- st->it913x_config.read_slevel = true;
- *name = fw_it9137;
- }
-
- return;
-}
-
-#define TS_MPEG_PKT_SIZE 188
-#define EP_LOW 21
-#define TS_BUFFER_SIZE_PID (EP_LOW*TS_MPEG_PKT_SIZE)
-#define EP_HIGH 348
-#define TS_BUFFER_SIZE_MAX (EP_HIGH*TS_MPEG_PKT_SIZE)
-
-static int it913x_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
- struct usb_data_stream_properties *stream)
-{
- struct dvb_usb_adapter *adap = fe_to_adap(fe);
- if (adap->pid_filtering)
- stream->u.bulk.buffersize = TS_BUFFER_SIZE_PID;
- else
- stream->u.bulk.buffersize = TS_BUFFER_SIZE_MAX;
-
- return 0;
-}
-
-static int it913x_select_config(struct dvb_usb_device *d)
-{
- struct it913x_state *st = d->priv;
- int ret, reg;
-
- ret = it913x_return_status(d);
- if (ret < 0)
- return ret;
-
- if (st->it913x_config.chip_ver == 0x02
- && st->it913x_config.chip_type == 0x9135)
- reg = it913x_read_reg(d, 0x461d);
- else
- reg = it913x_read_reg(d, 0x461b);
-
- if (reg < 0)
- return reg;
-
- if (reg == 0) {
- st->it913x_config.dual_mode = 0;
- st->it913x_config.tuner_id_0 = IT9135_38;
- st->proprietary_ir = true;
- } else {
- /* TS mode */
- reg = it913x_read_reg(d, 0x49c5);
- if (reg < 0)
- return reg;
- st->it913x_config.dual_mode = reg;
-
- /* IR mode type */
- reg = it913x_read_reg(d, 0x49ac);
- if (reg < 0)
- return reg;
- if (reg == 5) {
- info("Remote propriety (raw) mode");
- st->proprietary_ir = true;
- } else if (reg == 1) {
- info("Remote HID mode NOT SUPPORTED");
- st->proprietary_ir = false;
- }
-
- /* Tuner_id */
- reg = it913x_read_reg(d, 0x49d0);
- if (reg < 0)
- return reg;
- st->it913x_config.tuner_id_0 = reg;
- }
-
- info("Dual mode=%x Tuner Type=%x", st->it913x_config.dual_mode,
- st->it913x_config.tuner_id_0);
-
- return ret;
-}
-
-static int it913x_streaming_ctrl(struct dvb_frontend *fe, int onoff)
-{
- struct dvb_usb_adapter *adap = fe_to_adap(fe);
- struct dvb_usb_device *d = adap_to_d(adap);
- struct it913x_state *st = fe_to_priv(fe);
- int ret = 0;
- u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
-
- deb_info(1, "STM (%02x)", onoff);
-
- if (!onoff) {
- mutex_lock(&d->i2c_mutex);
-
- ret = it913x_wr_reg(d, pro, PID_RST, 0x1);
-
- mutex_unlock(&d->i2c_mutex);
- st->pid_filter_onoff =
- adap->pid_filtering;
-
- }
-
- return ret;
-}
-
-static int it913x_identify_state(struct dvb_usb_device *d, const char **name)
-{
- struct it913x_state *st = d->priv;
- int ret;
- u8 reg;
-
- /* Read and select config */
- ret = it913x_select_config(d);
- if (ret < 0)
- return ret;
-
- ite_get_firmware_name(d, name);
-
- if (st->it913x_config.firmware > 0)
- return WARM;
-
- if (st->it913x_config.dual_mode) {
- st->it913x_config.tuner_id_1 = it913x_read_reg(d, 0x49e0);
- ret = it913x_wr_reg(d, DEV_0, GPIOH1_EN, 0x1);
- ret |= it913x_wr_reg(d, DEV_0, GPIOH1_ON, 0x1);
- ret |= it913x_wr_reg(d, DEV_0, GPIOH1_O, 0x1);
- msleep(50);
- ret |= it913x_wr_reg(d, DEV_0, GPIOH1_O, 0x0);
- msleep(50);
- reg = it913x_read_reg(d, GPIOH1_O);
- if (reg == 0) {
- ret |= it913x_wr_reg(d, DEV_0, GPIOH1_O, 0x1);
- ret |= it913x_return_status(d);
- if (ret != 0)
- ret = it913x_wr_reg(d, DEV_0,
- GPIOH1_O, 0x0);
- }
- }
-
- reg = it913x_read_reg(d, IO_MUX_POWER_CLK);
-
- if (st->it913x_config.dual_mode) {
- ret |= it913x_wr_reg(d, DEV_0, 0x4bfb, CHIP2_I2C_ADDR);
- if (st->it913x_config.firmware_ver == 1)
- ret |= it913x_wr_reg(d, DEV_0, 0xcfff, 0x1);
- else
- ret |= it913x_wr_reg(d, DEV_0, CLK_O_EN, 0x1);
- } else {
- ret |= it913x_wr_reg(d, DEV_0, 0x4bfb, 0x0);
- if (st->it913x_config.firmware_ver == 1)
- ret |= it913x_wr_reg(d, DEV_0, 0xcfff, 0x0);
- else
- ret |= it913x_wr_reg(d, DEV_0, CLK_O_EN, 0x0);
- }
-
- ret |= it913x_wr_reg(d, DEV_0, I2C_CLK, I2C_CLK_100);
-
- return (ret < 0) ? ret : COLD;
-}
-
-static int it913x_download_firmware(struct dvb_usb_device *d,
- const struct firmware *fw)
-{
- struct it913x_state *st = d->priv;
- int ret = 0, i = 0, pos = 0;
- u8 packet_size, min_pkt;
- u8 *fw_data;
-
- ret = it913x_wr_reg(d, DEV_0, I2C_CLK, I2C_CLK_100);
-
- info("FRM Starting Firmware Download");
-
- /* Multi firmware loader */
- /* This uses scatter write firmware headers */
- /* The firmware must start with 03 XX 00 */
- /* and be the extact firmware length */
-
- if (st->it913x_config.chip_ver == 2)
- min_pkt = 0x11;
- else
- min_pkt = 0x19;
-
- while (i <= fw->size) {
- if (((fw->data[i] == 0x3) && (fw->data[i + 2] == 0x0))
- || (i == fw->size)) {
- packet_size = i - pos;
- if ((packet_size > min_pkt) || (i == fw->size)) {
- fw_data = (u8 *)(fw->data + pos);
- pos += packet_size;
- if (packet_size > 0) {
- ret = it913x_io(d, WRITE_DATA,
- DEV_0, CMD_SCATTER_WRITE, 0,
- 0, fw_data, packet_size);
- if (ret < 0)
- break;
- }
- udelay(1000);
- }
- }
- i++;
- }
-
- if (ret < 0)
- info("FRM Firmware Download Failed (%d)" , ret);
- else
- info("FRM Firmware Download Completed - Resetting Device");
-
- msleep(30);
-
- ret = it913x_io(d, WRITE_CMD, DEV_0, CMD_BOOT, 0, 0, NULL, 0);
- if (ret < 0)
- info("FRM Device not responding to reboot");
-
- ret = it913x_return_status(d);
- if (st->it913x_config.firmware == 0) {
- info("FRM Failed to reboot device");
- return -ENODEV;
- }
-
- msleep(30);
-
- ret = it913x_wr_reg(d, DEV_0, I2C_CLK, I2C_CLK_400);
-
- msleep(30);
-
- /* Tuner function */
- if (st->it913x_config.dual_mode)
- ret |= it913x_wr_reg(d, DEV_0_DMOD , 0xec4c, 0xa0);
- else
- ret |= it913x_wr_reg(d, DEV_0_DMOD , 0xec4c, 0x68);
-
- if ((st->it913x_config.chip_ver == 1) &&
- (st->it913x_config.chip_type == 0x9135)) {
- ret |= it913x_wr_reg(d, DEV_0, PADODPU, 0x0);
- ret |= it913x_wr_reg(d, DEV_0, AGC_O_D, 0x0);
- if (st->it913x_config.dual_mode) {
- ret |= it913x_wr_reg(d, DEV_1, PADODPU, 0x0);
- ret |= it913x_wr_reg(d, DEV_1, AGC_O_D, 0x0);
- }
- }
-
- return (ret < 0) ? -ENODEV : 0;
-}
-
-static int it913x_name(struct dvb_usb_adapter *adap)
-{
- struct dvb_usb_device *d = adap_to_d(adap);
- const char *desc = d->name;
- char *fe_name[] = {"_1", "_2", "_3", "_4"};
- char *name = adap->fe[0]->ops.info.name;
-
- strlcpy(name, desc, 128);
- strlcat(name, fe_name[adap->id], 128);
-
- return 0;
-}
-
-static int it913x_frontend_attach(struct dvb_usb_adapter *adap)
-{
- struct dvb_usb_device *d = adap_to_d(adap);
- struct it913x_state *st = d->priv;
- int ret = 0;
- u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5);
- u16 ep_size = (adap->pid_filtering) ? TS_BUFFER_SIZE_PID / 4 :
- TS_BUFFER_SIZE_MAX / 4;
- u8 pkt_size = 0x80;
-
- if (d->udev->speed != USB_SPEED_HIGH)
- pkt_size = 0x10;
-
- st->it913x_config.adf = it913x_read_reg(d, IO_MUX_POWER_CLK);
-
- adap->fe[0] = dvb_attach(it913x_fe_attach,
- &d->i2c_adap, adap_addr, &st->it913x_config);
-
- if (adap->id == 0 && adap->fe[0]) {
- it913x_wr_reg(d, DEV_0_DMOD, MP2_SW_RST, 0x1);
- it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_SW_RST, 0x1);
- it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x0f);
- it913x_wr_reg(d, DEV_0, EP0_TX_NAK, 0x1b);
- if (st->proprietary_ir == false) /* Enable endpoint 3 */
- it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x3f);
- else
- it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x2f);
- it913x_wr_reg(d, DEV_0, EP4_TX_LEN_LSB,
- ep_size & 0xff);
- it913x_wr_reg(d, DEV_0, EP4_TX_LEN_MSB, ep_size >> 8);
- ret = it913x_wr_reg(d, DEV_0, EP4_MAX_PKT, pkt_size);
- } else if (adap->id == 1 && adap->fe[0]) {
- if (st->proprietary_ir == false)
- it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x7f);
- else
- it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x6f);
- it913x_wr_reg(d, DEV_0, EP5_TX_LEN_LSB,
- ep_size & 0xff);
- it913x_wr_reg(d, DEV_0, EP5_TX_LEN_MSB, ep_size >> 8);
- it913x_wr_reg(d, DEV_0, EP5_MAX_PKT, pkt_size);
- it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_EN, 0x1);
- it913x_wr_reg(d, DEV_1_DMOD, MP2IF_SERIAL, 0x1);
- it913x_wr_reg(d, DEV_1, TOP_HOSTB_SER_MODE, 0x1);
- it913x_wr_reg(d, DEV_0_DMOD, TSIS_ENABLE, 0x1);
- it913x_wr_reg(d, DEV_0_DMOD, MP2_SW_RST, 0x0);
- it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_SW_RST, 0x0);
- it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_HALF_PSB, 0x0);
- it913x_wr_reg(d, DEV_0_DMOD, MP2IF_STOP_EN, 0x1);
- it913x_wr_reg(d, DEV_1_DMOD, MPEG_FULL_SPEED, 0x0);
- ret = it913x_wr_reg(d, DEV_1_DMOD, MP2IF_STOP_EN, 0x0);
- } else
- return -ENODEV;
-
- ret |= it913x_name(adap);
-
- return ret;
-}
-
-/* DVB USB Driver */
-static int it913x_get_adapter_count(struct dvb_usb_device *d)
-{
- struct it913x_state *st = d->priv;
- if (st->it913x_config.dual_mode)
- return 2;
- return 1;
-}
-
-static struct dvb_usb_device_properties it913x_properties = {
- .driver_name = KBUILD_MODNAME,
- .owner = THIS_MODULE,
- .bInterfaceNumber = 0,
- .generic_bulk_ctrl_endpoint = 0x02,
- .generic_bulk_ctrl_endpoint_response = 0x81,
-
- .adapter_nr = adapter_nr,
- .size_of_priv = sizeof(struct it913x_state),
-
- .identify_state = it913x_identify_state,
- .i2c_algo = &it913x_i2c_algo,
-
- .download_firmware = it913x_download_firmware,
-
- .frontend_attach = it913x_frontend_attach,
- .get_rc_config = it913x_get_rc_config,
- .get_stream_config = it913x_get_stream_config,
- .get_adapter_count = it913x_get_adapter_count,
- .streaming_ctrl = it913x_streaming_ctrl,
-
-
- .adapter = {
- {
- .caps = DVB_USB_ADAP_HAS_PID_FILTER|
- DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
- .pid_filter_count = 32,
- .pid_filter = it913x_pid_filter,
- .pid_filter_ctrl = it913x_pid_filter_ctrl,
- .stream =
- DVB_USB_STREAM_BULK(0x84, 10, TS_BUFFER_SIZE_MAX),
- },
- {
- .caps = DVB_USB_ADAP_HAS_PID_FILTER|
- DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
- .pid_filter_count = 32,
- .pid_filter = it913x_pid_filter,
- .pid_filter_ctrl = it913x_pid_filter_ctrl,
- .stream =
- DVB_USB_STREAM_BULK(0x85, 10, TS_BUFFER_SIZE_MAX),
- }
- }
-};
-
-static const struct usb_device_id it913x_id_table[] = {
- { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09,
- &it913x_properties, "Kworld UB499-2T T09(IT9137)",
- RC_MAP_IT913X_V1) },
- { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135,
- &it913x_properties, "ITE 9135 Generic",
- RC_MAP_IT913X_V1) },
- { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22_IT9137,
- &it913x_properties, "Sveon STV22 Dual DVB-T HDTV(IT9137)",
- RC_MAP_IT913X_V1) },
- { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9005,
- &it913x_properties, "ITE 9135(9005) Generic",
- RC_MAP_IT913X_V2) },
- { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9006,
- &it913x_properties, "ITE 9135(9006) Generic",
- RC_MAP_IT913X_V1) },
- { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_1835,
- &it913x_properties, "Avermedia A835B(1835)",
- RC_MAP_IT913X_V2) },
- { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_2835,
- &it913x_properties, "Avermedia A835B(2835)",
- RC_MAP_IT913X_V2) },
- { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_3835,
- &it913x_properties, "Avermedia A835B(3835)",
- RC_MAP_IT913X_V2) },
- { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_4835,
- &it913x_properties, "Avermedia A835B(4835)",
- RC_MAP_IT913X_V2) },
- { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2,
- &it913x_properties, "Digital Dual TV Receiver CTVDIGDUAL_V2",
- RC_MAP_IT913X_V1) },
- { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_H335,
- &it913x_properties, "Avermedia H335",
- RC_MAP_IT913X_V2) },
- {} /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, it913x_id_table);
-
-static struct usb_driver it913x_driver = {
- .name = KBUILD_MODNAME,
- .probe = dvb_usbv2_probe,
- .disconnect = dvb_usbv2_disconnect,
- .suspend = dvb_usbv2_suspend,
- .resume = dvb_usbv2_resume,
- .id_table = it913x_id_table,
-};
-
-module_usb_driver(it913x_driver);
-
-MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
-MODULE_DESCRIPTION("it913x USB 2 Driver");
-MODULE_VERSION("1.33");
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(FW_IT9135_V1);
-MODULE_FIRMWARE(FW_IT9135_V2);
-MODULE_FIRMWARE(FW_IT9137);
-
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index fda5c64ba0e8..c83c16cece01 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -24,6 +24,7 @@
#include "rtl2830.h"
#include "rtl2832.h"
+#include "rtl2832_sdr.h"
#include "qt1010.h"
#include "mt2060.h"
@@ -35,6 +36,9 @@
#include "tua9001.h"
#include "r820t.h"
+static int rtl28xxu_disable_rc;
+module_param_named(disable_rc, rtl28xxu_disable_rc, int, 0644);
+MODULE_PARM_DESC(disable_rc, "disable RTL2832U remote controller");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req)
@@ -513,7 +517,7 @@ err:
return ret;
}
-static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = {
+static const struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
.ts_mode = 0,
@@ -524,7 +528,7 @@ static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = {
};
-static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = {
+static const struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
.ts_mode = 0,
@@ -534,7 +538,7 @@ static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = {
.agc_targ_val = 0x2d,
};
-static struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = {
+static const struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
.ts_mode = 0,
@@ -548,7 +552,7 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
{
struct dvb_usb_device *d = adap_to_d(adap);
struct rtl28xxu_priv *priv = d_to_priv(d);
- struct rtl2830_config *rtl2830_config;
+ const struct rtl2830_config *rtl2830_config;
int ret;
dev_dbg(&d->udev->dev, "%s:\n", __func__);
@@ -583,33 +587,31 @@ err:
return ret;
}
-static struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = {
+static const struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
- .if_dvbt = 0,
.tuner = TUNER_RTL2832_FC0012
};
-static struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = {
+static const struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
- .if_dvbt = 0,
.tuner = TUNER_RTL2832_FC0013
};
-static struct rtl2832_config rtl28xxu_rtl2832_tua9001_config = {
+static const struct rtl2832_config rtl28xxu_rtl2832_tua9001_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
.tuner = TUNER_RTL2832_TUA9001,
};
-static struct rtl2832_config rtl28xxu_rtl2832_e4000_config = {
+static const struct rtl2832_config rtl28xxu_rtl2832_e4000_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
.tuner = TUNER_RTL2832_E4000,
};
-static struct rtl2832_config rtl28xxu_rtl2832_r820t_config = {
+static const struct rtl2832_config rtl28xxu_rtl2832_r820t_config = {
.i2c_addr = 0x10,
.xtal = 28800000,
.tuner = TUNER_RTL2832_R820T,
@@ -733,7 +735,7 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
int ret;
struct dvb_usb_device *d = adap_to_d(adap);
struct rtl28xxu_priv *priv = d_to_priv(d);
- struct rtl2832_config *rtl2832_config;
+ const struct rtl2832_config *rtl2832_config;
dev_dbg(&d->udev->dev, "%s:\n", __func__);
@@ -772,6 +774,9 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
goto err;
}
+ /* RTL2832 I2C repeater */
+ priv->demod_i2c_adapter = rtl2832_get_i2c_adapter(adap->fe[0]);
+
/* set fe callback */
adap->fe[0]->callback = rtl2832u_frontend_callback;
@@ -851,11 +856,6 @@ err:
return ret;
}
-static const struct e4000_config rtl2832u_e4000_config = {
- .i2c_addr = 0x64,
- .clock = 28800000,
-};
-
static const struct fc2580_config rtl2832u_fc2580_config = {
.i2c_addr = 0x56,
.clock = 16384000,
@@ -889,10 +889,14 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
int ret;
struct dvb_usb_device *d = adap_to_d(adap);
struct rtl28xxu_priv *priv = d_to_priv(d);
- struct dvb_frontend *fe;
+ struct dvb_frontend *fe = NULL;
+ struct i2c_board_info info;
+ struct i2c_client *client;
dev_dbg(&d->udev->dev, "%s:\n", __func__);
+ memset(&info, 0, sizeof(struct i2c_board_info));
+
switch (priv->tuner) {
case TUNER_RTL2832_FC0012:
fe = dvb_attach(fc0012_attach, adap->fe[0],
@@ -902,7 +906,10 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
* that to the tuner driver */
adap->fe[0]->ops.read_signal_strength =
adap->fe[0]->ops.tuner_ops.get_rf_strength;
- return 0;
+
+ /* attach SDR */
+ dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
+ &rtl28xxu_rtl2832_fc0012_config, NULL);
break;
case TUNER_RTL2832_FC0013:
fe = dvb_attach(fc0013_attach, adap->fe[0],
@@ -911,10 +918,43 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
/* fc0013 also supports signal strength reading */
adap->fe[0]->ops.read_signal_strength =
adap->fe[0]->ops.tuner_ops.get_rf_strength;
- return 0;
- case TUNER_RTL2832_E4000:
- fe = dvb_attach(e4000_attach, adap->fe[0], &d->i2c_adap,
- &rtl2832u_e4000_config);
+
+ /* attach SDR */
+ dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
+ &rtl28xxu_rtl2832_fc0013_config, NULL);
+ break;
+ case TUNER_RTL2832_E4000: {
+ struct v4l2_subdev *sd;
+ struct i2c_adapter *i2c_adap_internal =
+ rtl2832_get_private_i2c_adapter(adap->fe[0]);
+ struct e4000_config e4000_config = {
+ .fe = adap->fe[0],
+ .clock = 28800000,
+ };
+
+ strlcpy(info.type, "e4000", I2C_NAME_SIZE);
+ info.addr = 0x64;
+ info.platform_data = &e4000_config;
+
+ request_module(info.type);
+ client = i2c_new_device(priv->demod_i2c_adapter, &info);
+ if (client == NULL || client->dev.driver == NULL)
+ break;
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ break;
+ }
+
+ priv->client = client;
+ sd = i2c_get_clientdata(client);
+ i2c_set_adapdata(i2c_adap_internal, d);
+
+ /* attach SDR */
+ dvb_attach(rtl2832_sdr_attach, adap->fe[0],
+ i2c_adap_internal,
+ &rtl28xxu_rtl2832_e4000_config, sd);
+ }
break;
case TUNER_RTL2832_FC2580:
fe = dvb_attach(fc2580_attach, adap->fe[0], &d->i2c_adap,
@@ -940,6 +980,10 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
/* Use tuner to get the signal strength */
adap->fe[0]->ops.read_signal_strength =
adap->fe[0]->ops.tuner_ops.get_rf_strength;
+
+ /* attach SDR */
+ dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
+ &rtl28xxu_rtl2832_r820t_config, NULL);
break;
case TUNER_RTL2832_R828D:
/* power off mn88472 demod on GPIO0 */
@@ -963,12 +1007,11 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
adap->fe[0]->ops.tuner_ops.get_rf_strength;
break;
default:
- fe = NULL;
dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME,
priv->tuner);
}
- if (fe == NULL) {
+ if (fe == NULL && priv->client == NULL) {
ret = -ENODEV;
goto err;
}
@@ -1013,6 +1056,22 @@ err:
return ret;
}
+static void rtl28xxu_exit(struct dvb_usb_device *d)
+{
+ struct rtl28xxu_priv *priv = d->priv;
+ struct i2c_client *client = priv->client;
+
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ /* remove I2C tuner */
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+
+ return;
+}
+
static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff)
{
int ret;
@@ -1322,6 +1381,10 @@ err:
static int rtl2832u_get_rc_config(struct dvb_usb_device *d,
struct dvb_usb_rc *rc)
{
+ /* disable IR interrupts in order to avoid SDR sample loss */
+ if (rtl28xxu_disable_rc)
+ return rtl28xx_wr_reg(d, IR_RX_IE, 0x00);
+
/* load empty to enable rc */
if (!rc->map_name)
rc->map_name = RC_MAP_EMPTY;
@@ -1371,6 +1434,7 @@ static const struct dvb_usb_device_properties rtl2832u_props = {
.frontend_attach = rtl2832u_frontend_attach,
.tuner_attach = rtl2832u_tuner_attach,
.init = rtl28xxu_init,
+ .exit = rtl28xxu_exit,
.get_rc_config = rtl2832u_get_rc_config,
.num_adapters = 1,
@@ -1382,6 +1446,7 @@ static const struct dvb_usb_device_properties rtl2832u_props = {
};
static const struct usb_device_id rtl28xxu_id_table[] = {
+ /* RTL2831U devices: */
{ DVB_USB_DEVICE(USB_VID_REALTEK, USB_PID_REALTEK_RTL2831U,
&rtl2831u_props, "Realtek RTL2831U reference design", NULL) },
{ DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT,
@@ -1389,6 +1454,7 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
{ DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2,
&rtl2831u_props, "Freecom USB2.0 DVB-T", NULL) },
+ /* RTL2832U devices: */
{ DVB_USB_DEVICE(USB_VID_REALTEK, 0x2832,
&rtl2832u_props, "Realtek RTL2832U reference design", NULL) },
{ DVB_USB_DEVICE(USB_VID_REALTEK, 0x2838,
@@ -1401,6 +1467,8 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
&rtl2832u_props, "TerraTec NOXON DAB Stick", NULL) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK_REV2,
&rtl2832u_props, "TerraTec NOXON DAB Stick (rev 2)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK_REV3,
+ &rtl2832u_props, "TerraTec NOXON DAB Stick (rev 3)", NULL) },
{ DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_TREKSTOR_TERRES_2_0,
&rtl2832u_props, "Trekstor DVB-T Stick Terres 2.0", NULL) },
{ DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1101,
@@ -1429,9 +1497,14 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
&rtl2832u_props, "Leadtek WinFast DTV Dongle mini", NULL) },
{ DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_CPYTO_REDI_PC50A,
&rtl2832u_props, "Crypto ReDi PC 50 A", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KYE, 0x707f,
+ &rtl2832u_props, "Genius TVGo DVB-T03", NULL) },
+ /* RTL2832P devices: */
{ DVB_USB_DEVICE(USB_VID_HANFTEK, 0x0131,
&rtl2832u_props, "Astrometa DVB-T2", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KYE, 0x707f,
+ &rtl2832u_props, "Genius TVGo DVB-T03", NULL) },
{ }
};
MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table);
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
index 2142bcb41b41..a26cab10f382 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
@@ -55,7 +55,9 @@ struct rtl28xxu_priv {
u8 tuner;
char *tuner_name;
u8 page; /* integrated demod active register page */
+ struct i2c_adapter *demod_i2c_adapter;
bool rc_active;
+ struct i2c_client *client;
};
enum rtl28xxu_chip_id {
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-remote.c b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
index 41bacff24960..4058aea9272f 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
@@ -272,7 +272,7 @@ static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d)
dev->driver_name = d->props.rc.core.module_name;
dev->map_name = d->props.rc.core.rc_codes;
dev->change_protocol = d->props.rc.core.change_protocol;
- dev->allowed_protos = d->props.rc.core.allowed_protos;
+ rc_set_allowed_protocols(dev, d->props.rc.core.allowed_protos);
dev->driver_type = d->props.rc.core.driver_type;
usb_to_input_id(d->udev, &dev->input_id);
dev->input_name = "IR-receiver inside an USB DVB receiver";
diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
index a1fccf3096de..d23a912096f7 100644
--- a/drivers/media/usb/em28xx/Kconfig
+++ b/drivers/media/usb/em28xx/Kconfig
@@ -53,8 +53,10 @@ config VIDEO_EM28XX_DVB
select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT
select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_DRX39XYJ if MEDIA_SUBDRV_AUTOSELECT
---help---
This adds support for DVB cards based on the
Empiatech em28xx chips.
diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index 05e9bd11a3ff..342490f44ed2 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -252,7 +252,7 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
{
struct em28xx *dev = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- int ret = 0;
+ int nonblock, ret = 0;
if (!dev) {
em28xx_err("BUG: em28xx can't find device struct."
@@ -265,45 +265,48 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
dprintk("opening device and trying to acquire exclusive lock\n");
+ nonblock = !!(substream->f_flags & O_NONBLOCK);
+ if (nonblock) {
+ if (!mutex_trylock(&dev->lock))
+ return -EAGAIN;
+ } else
+ mutex_lock(&dev->lock);
+
runtime->hw = snd_em28xx_hw_capture;
- if ((dev->alt == 0 || dev->is_audio_only) && dev->adev.users == 0) {
- int nonblock = !!(substream->f_flags & O_NONBLOCK);
-
- if (nonblock) {
- if (!mutex_trylock(&dev->lock))
- return -EAGAIN;
- } else
- mutex_lock(&dev->lock);
- if (dev->is_audio_only)
- /* vendor audio is on a separate interface */
- dev->alt = 1;
- else
- /* vendor audio is on the same interface as video */
- dev->alt = 7;
- /*
- * FIXME: The intention seems to be to select the alt
- * setting with the largest wMaxPacketSize for the video
- * endpoint.
- * At least dev->alt should be used instead, but we
- * should probably not touch it at all if it is
- * already >0, because wMaxPacketSize of the audio
- * endpoints seems to be the same for all.
- */
-
- dprintk("changing alternate number on interface %d to %d\n",
- dev->ifnum, dev->alt);
- usb_set_interface(dev->udev, dev->ifnum, dev->alt);
+
+ if (dev->adev.users == 0) {
+ if (dev->alt == 0 || dev->is_audio_only) {
+ if (dev->is_audio_only)
+ /* audio is on a separate interface */
+ dev->alt = 1;
+ else
+ /* audio is on the same interface as video */
+ dev->alt = 7;
+ /*
+ * FIXME: The intention seems to be to select
+ * the alt setting with the largest
+ * wMaxPacketSize for the video endpoint.
+ * At least dev->alt should be used instead, but
+ * we should probably not touch it at all if it
+ * is already >0, because wMaxPacketSize of the
+ * audio endpoints seems to be the same for all.
+ */
+ dprintk("changing alternate number on interface %d to %d\n",
+ dev->ifnum, dev->alt);
+ usb_set_interface(dev->udev, dev->ifnum, dev->alt);
+ }
/* Sets volume, mute, etc */
dev->mute = 0;
ret = em28xx_audio_analog_set(dev);
if (ret < 0)
goto err;
-
- dev->adev.users++;
- mutex_unlock(&dev->lock);
}
+ kref_get(&dev->ref);
+ dev->adev.users++;
+ mutex_unlock(&dev->lock);
+
/* Dynamically adjust the period size */
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
@@ -341,6 +344,7 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
substream->runtime->dma_area = NULL;
}
mutex_unlock(&dev->lock);
+ kref_put(&dev->ref, em28xx_free_device);
return 0;
}
@@ -895,13 +899,15 @@ static int em28xx_audio_init(struct em28xx *dev)
em28xx_info("Binding audio extension\n");
+ kref_get(&dev->ref);
+
printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
"Rechberger\n");
printk(KERN_INFO
"em28xx-audio.c: Copyright (C) 2007-2014 Mauro Carvalho Chehab\n");
- err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
- &card);
+ err = snd_card_new(&dev->udev->dev, index[devnr], "Em28xx Audio",
+ THIS_MODULE, 0, &card);
if (err < 0)
return err;
@@ -918,7 +924,6 @@ static int em28xx_audio_init(struct em28xx *dev)
pcm->private_data = dev;
strcpy(pcm->name, "Empia 28xx Capture");
- snd_card_set_dev(card, &dev->udev->dev);
strcpy(card->driver, "Em28xx-Audio");
strcpy(card->shortname, "Em28xx Audio");
strcpy(card->longname, "Empia Em28xx Audio");
@@ -967,7 +972,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
if (dev == NULL)
return 0;
- if (dev->has_alsa_audio != 1) {
+ if (!dev->has_alsa_audio) {
/* This device does not support the extension (in this case
the device is expecting the snd-usb-audio module or
doesn't have analog audio support at all) */
@@ -986,6 +991,35 @@ static int em28xx_audio_fini(struct em28xx *dev)
dev->adev.sndcard = NULL;
}
+ kref_put(&dev->ref, em28xx_free_device);
+ return 0;
+}
+
+static int em28xx_audio_suspend(struct em28xx *dev)
+{
+ if (dev == NULL)
+ return 0;
+
+ if (!dev->has_alsa_audio)
+ return 0;
+
+ em28xx_info("Suspending audio extension");
+ em28xx_deinit_isoc_audio(dev);
+ atomic_set(&dev->stream_started, 0);
+ return 0;
+}
+
+static int em28xx_audio_resume(struct em28xx *dev)
+{
+ if (dev == NULL)
+ return 0;
+
+ if (!dev->has_alsa_audio)
+ return 0;
+
+ em28xx_info("Resuming audio extension");
+ /* Nothing to do other than schedule_work() ?? */
+ schedule_work(&dev->wq_trigger);
return 0;
}
@@ -994,6 +1028,8 @@ static struct em28xx_ops audio_ops = {
.name = "Em28xx Audio Extension",
.init = em28xx_audio_init,
.fini = em28xx_audio_fini,
+ .suspend = em28xx_audio_suspend,
+ .resume = em28xx_audio_resume,
};
static int __init em28xx_alsa_register(void)
@@ -1008,7 +1044,7 @@ static void __exit em28xx_alsa_unregister(void)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_DESCRIPTION(DRIVER_DESC " - audio interface");
MODULE_VERSION(EM28XX_VERSION);
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
index c29f5c4e7b40..505e0505be04 100644
--- a/drivers/media/usb/em28xx/em28xx-camera.c
+++ b/drivers/media/usb/em28xx/em28xx-camera.c
@@ -120,7 +120,7 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev)
reg = 0x00;
ret = i2c_master_send(&client, &reg, 1);
if (ret < 0) {
- if (ret != -ENODEV)
+ if (ret != -ENXIO)
em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
client.addr << 1, ret);
continue;
@@ -218,7 +218,7 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev)
reg = 0x1c;
ret = i2c_smbus_read_byte_data(&client, reg);
if (ret < 0) {
- if (ret != -ENODEV)
+ if (ret != -ENXIO)
em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
client.addr << 1, ret);
continue;
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 4d97a76cc3b0..50aa5a5317f2 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -66,7 +66,7 @@ MODULE_PARM_DESC(usb_xfer_mode,
/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS - 1 */
-DECLARE_BITMAP(em28xx_devused, EM28XX_MAXBOARDS);
+static DECLARE_BITMAP(em28xx_devused, EM28XX_MAXBOARDS);
struct em28xx_hash_table {
unsigned long hash;
@@ -189,6 +189,14 @@ static struct em28xx_reg_seq kworld_a340_digital[] = {
{ -1, -1, -1, -1},
};
+static struct em28xx_reg_seq kworld_ub435q_v3_digital[] = {
+ {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xfe, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xbe, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xfe, 0xff, 100},
+ { -1, -1, -1, -1},
+};
+
/* Pinnacle Hybrid Pro eb1a:2881 */
static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = {
{EM2820_R08_GPIO_CTRL, 0xfd, ~EM_GPIO_4, 10},
@@ -214,6 +222,17 @@ static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = {
{ -1, -1, -1, -1},
};
+/* PCTV HD Mini (80e) GPIOs
+ 0-5: not used
+ 6: demod reset, active low
+ 7: LED on, active high */
+static struct em28xx_reg_seq em2874_pctv_80e_digital[] = {
+ {EM28XX_R06_I2C_CLK, 0x45, 0xff, 10}, /*400 KHz*/
+ {EM2874_R80_GPIO_P0_CTRL, 0x00, 0xff, 100},/*Demod reset*/
+ {EM2874_R80_GPIO_P0_CTRL, 0x40, 0xff, 10},
+ { -1, -1, -1, -1},
+};
+
/* eb1a:2868 Reddo DVB-C USB TV Box
GPIO4 - CU1216L NIM
Other GPIOs seems to be don't care. */
@@ -497,6 +516,27 @@ static struct em28xx_led speedlink_vad_laplace_leds[] = {
{-1, 0, 0, 0},
};
+static struct em28xx_led kworld_ub435q_v3_leds[] = {
+ {
+ .role = EM28XX_LED_DIGITAL_CAPTURING,
+ .gpio_reg = EM2874_R80_GPIO_P0_CTRL,
+ .gpio_mask = 0x80,
+ .inverted = 1,
+ },
+ {-1, 0, 0, 0},
+};
+
+static struct em28xx_led pctv_80e_leds[] = {
+ {
+ .role = EM28XX_LED_DIGITAL_CAPTURING,
+ .gpio_reg = EM2874_R80_GPIO_P0_CTRL,
+ .gpio_mask = 0x80,
+ .inverted = 0,
+ },
+ {-1, 0, 0, 0},
+};
+
+
/*
* Board definitions
*/
@@ -2128,6 +2168,29 @@ struct em28xx_board em28xx_boards[] = {
.tuner_gpio = default_tuner_gpio,
.def_i2c_bus = 1,
},
+ /*
+ * 1b80:e34c KWorld USB ATSC TV Stick UB435-Q V3
+ * Empia EM2874B + LG DT3305 + NXP TDA18271HDC2
+ */
+ [EM2874_BOARD_KWORLD_UB435Q_V3] = {
+ .name = "KWorld USB ATSC TV Stick UB435-Q V3",
+ .tuner_type = TUNER_ABSENT,
+ .has_dvb = 1,
+ .tuner_gpio = kworld_ub435q_v3_digital,
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ,
+ .leds = kworld_ub435q_v3_leds,
+ },
+ [EM2874_BOARD_PCTV_HD_MINI_80E] = {
+ .name = "Pinnacle PCTV HD Mini",
+ .tuner_type = TUNER_ABSENT,
+ .has_dvb = 1,
+ .dvb_gpio = em2874_pctv_80e_digital,
+ .decoder = EM28XX_NODECODER,
+ .ir_codes = RC_MAP_PINNACLE_PCTV_HD,
+ .leds = pctv_80e_leds,
+ },
/* 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam
* Empia EM2765 + OmniVision OV2640 */
[EM2765_BOARD_SPEEDLINK_VAD_LAPLACE] = {
@@ -2290,6 +2353,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO_330E },
{ USB_DEVICE(0x2304, 0x0227),
.driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO },
+ { USB_DEVICE(0x2304, 0x023f),
+ .driver_info = EM2874_BOARD_PCTV_HD_MINI_80E },
{ USB_DEVICE(0x0413, 0x6023),
.driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII },
{ USB_DEVICE(0x093b, 0xa003),
@@ -2304,6 +2369,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2870_BOARD_KWORLD_A340 },
{ USB_DEVICE(0x1b80, 0xe346),
.driver_info = EM2874_BOARD_KWORLD_UB435Q_V2 },
+ { USB_DEVICE(0x1b80, 0xe34c),
+ .driver_info = EM2874_BOARD_KWORLD_UB435Q_V3 },
{ USB_DEVICE(0x2013, 0x024f),
.driver_info = EM28174_BOARD_PCTV_290E },
{ USB_DEVICE(0x2013, 0x024c),
@@ -2872,7 +2939,7 @@ static void flush_request_modules(struct em28xx *dev)
* unregisters the v4l2,i2c and usb devices
* called when the device gets disconnected or at module unload
*/
-void em28xx_release_resources(struct em28xx *dev)
+static void em28xx_release_resources(struct em28xx *dev)
{
/*FIXME: I2C IR should be disconnected */
@@ -2889,7 +2956,27 @@ void em28xx_release_resources(struct em28xx *dev)
mutex_unlock(&dev->lock);
};
-EXPORT_SYMBOL_GPL(em28xx_release_resources);
+
+/**
+ * em28xx_free_device() - Free em28xx device
+ *
+ * @ref: struct kref for em28xx device
+ *
+ * This is called when all extensions and em28xx core unregisters a device
+ */
+void em28xx_free_device(struct kref *ref)
+{
+ struct em28xx *dev = kref_to_dev(ref);
+
+ em28xx_info("Freeing device\n");
+
+ if (!dev->disconnected)
+ em28xx_release_resources(dev);
+
+ kfree(dev->alt_max_pkt_size_isoc);
+ kfree(dev);
+}
+EXPORT_SYMBOL_GPL(em28xx_free_device);
/*
* em28xx_init_dev()
@@ -3331,8 +3418,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
if (has_video) {
if (!dev->analog_ep_isoc || (try_bulk && dev->analog_ep_bulk))
dev->analog_xfer_bulk = 1;
- em28xx_info("analog set to %s mode.\n",
- dev->analog_xfer_bulk ? "bulk" : "isoc");
+ em28xx_info("analog set to %s mode.\n",
+ dev->analog_xfer_bulk ? "bulk" : "isoc");
}
if (has_dvb) {
if (!dev->dvb_ep_isoc || (try_bulk && dev->dvb_ep_bulk))
@@ -3342,6 +3429,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
dev->dvb_xfer_bulk ? "bulk" : "isoc");
}
+ kref_init(&dev->ref);
+
request_modules(dev);
/* Should be the last thing to do, to avoid newer udev's to
@@ -3386,17 +3475,39 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
em28xx_close_extension(dev);
em28xx_release_resources(dev);
+ kref_put(&dev->ref, em28xx_free_device);
+}
- if (!dev->users) {
- kfree(dev->alt_max_pkt_size_isoc);
- kfree(dev);
- }
+static int em28xx_usb_suspend(struct usb_interface *interface,
+ pm_message_t message)
+{
+ struct em28xx *dev;
+
+ dev = usb_get_intfdata(interface);
+ if (!dev)
+ return 0;
+ em28xx_suspend_extension(dev);
+ return 0;
+}
+
+static int em28xx_usb_resume(struct usb_interface *interface)
+{
+ struct em28xx *dev;
+
+ dev = usb_get_intfdata(interface);
+ if (!dev)
+ return 0;
+ em28xx_resume_extension(dev);
+ return 0;
}
static struct usb_driver em28xx_usb_driver = {
.name = "em28xx",
.probe = em28xx_usb_probe,
.disconnect = em28xx_usb_disconnect,
+ .suspend = em28xx_usb_suspend,
+ .resume = em28xx_usb_resume,
+ .reset_resume = em28xx_usb_resume,
.id_table = em28xx_id_table,
};
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index 898fb9bd88a2..523d7e92bf47 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -619,6 +619,7 @@ EXPORT_SYMBOL_GPL(em28xx_find_led);
int em28xx_capture_start(struct em28xx *dev, int start)
{
int rc;
+ const struct em28xx_led *led = NULL;
if (dev->chip_id == CHIP_ID_EM2874 ||
dev->chip_id == CHIP_ID_EM2884 ||
@@ -643,6 +644,8 @@ int em28xx_capture_start(struct em28xx *dev, int start)
/* Enable video capture */
rc = em28xx_write_reg(dev, 0x48, 0x00);
+ if (rc < 0)
+ return rc;
if (dev->mode == EM28XX_ANALOG_MODE)
rc = em28xx_write_reg(dev,
@@ -650,6 +653,8 @@ int em28xx_capture_start(struct em28xx *dev, int start)
else
rc = em28xx_write_reg(dev,
EM28XX_R12_VINENABLE, 0x37);
+ if (rc < 0)
+ return rc;
msleep(6);
} else {
@@ -658,19 +663,16 @@ int em28xx_capture_start(struct em28xx *dev, int start)
}
}
- if (rc < 0)
- return rc;
-
- /* Switch (explicitly controlled) analog capturing LED on/off */
- if (dev->mode == EM28XX_ANALOG_MODE) {
- const struct em28xx_led *led;
+ if (dev->mode == EM28XX_ANALOG_MODE)
led = em28xx_find_led(dev, EM28XX_LED_ANALOG_CAPTURING);
- if (led)
- em28xx_write_reg_bits(dev, led->gpio_reg,
- (!start ^ led->inverted) ?
- ~led->gpio_mask : led->gpio_mask,
- led->gpio_mask);
- }
+ else
+ led = em28xx_find_led(dev, EM28XX_LED_DIGITAL_CAPTURING);
+
+ if (led)
+ em28xx_write_reg_bits(dev, led->gpio_reg,
+ (!start ^ led->inverted) ?
+ ~led->gpio_mask : led->gpio_mask,
+ led->gpio_mask);
return rc;
}
@@ -1106,3 +1108,31 @@ void em28xx_close_extension(struct em28xx *dev)
list_del(&dev->devlist);
mutex_unlock(&em28xx_devlist_mutex);
}
+
+int em28xx_suspend_extension(struct em28xx *dev)
+{
+ const struct em28xx_ops *ops = NULL;
+
+ em28xx_info("Suspending extensions");
+ mutex_lock(&em28xx_devlist_mutex);
+ list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+ if (ops->suspend)
+ ops->suspend(dev);
+ }
+ mutex_unlock(&em28xx_devlist_mutex);
+ return 0;
+}
+
+int em28xx_resume_extension(struct em28xx *dev)
+{
+ const struct em28xx_ops *ops = NULL;
+
+ em28xx_info("Resuming extensions");
+ mutex_lock(&em28xx_devlist_mutex);
+ list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+ if (ops->resume)
+ ops->resume(dev);
+ }
+ mutex_unlock(&em28xx_devlist_mutex);
+ return 0;
+}
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index a0a669e81362..f599b18ef7ca 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -41,6 +41,7 @@
#include "mt352.h"
#include "mt352_priv.h" /* FIXME */
#include "tda1002x.h"
+#include "drx39xyj/drx39xxj.h"
#include "tda18271.h"
#include "s921.h"
#include "drxd.h"
@@ -48,6 +49,7 @@
#include "tda18271c2dd.h"
#include "drxk.h"
#include "tda10071.h"
+#include "tda18212.h"
#include "a8293.h"
#include "qt1010.h"
#include "mb86a20s.h"
@@ -161,6 +163,8 @@ static inline int em28xx_dvb_urb_data_copy(struct em28xx *dev, struct urb *urb)
if (urb->status != -EPROTO)
continue;
}
+ if (!urb->actual_length)
+ continue;
dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
urb->actual_length);
} else {
@@ -170,6 +174,8 @@ static inline int em28xx_dvb_urb_data_copy(struct em28xx *dev, struct urb *urb)
if (urb->iso_frame_desc[i].status != -EPROTO)
continue;
}
+ if (!urb->iso_frame_desc[i].actual_length)
+ continue;
dvb_dmx_swfilter(&dev->dvb->demux,
urb->transfer_buffer +
urb->iso_frame_desc[i].offset,
@@ -208,10 +214,10 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
if (rc < 0)
return rc;
- dprintk(1, "Using %d buffers each with %d x %d bytes\n",
+ dprintk(1, "Using %d buffers each with %d x %d bytes, alternate %d\n",
EM28XX_DVB_NUM_BUFS,
packet_multiplier,
- dvb_max_packet_size);
+ dvb_max_packet_size, dvb_alt);
return em28xx_init_usb_xfer(dev, EM28XX_DIGITAL_MODE,
dev->dvb_xfer_bulk,
@@ -315,6 +321,18 @@ static struct lgdt3305_config em2874_lgdt3305_dev = {
.qam_if_khz = 4000,
};
+static struct lgdt3305_config em2874_lgdt3305_nogate_dev = {
+ .i2c_addr = 0x0e,
+ .demod_chip = LGDT3305,
+ .spectral_inversion = 1,
+ .deny_i2c_rptr = 1,
+ .mpeg_mode = LGDT3305_MPEG_SERIAL,
+ .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE,
+ .tpvalid_polarity = LGDT3305_TP_VALID_HIGH,
+ .vsb_if_khz = 3600,
+ .qam_if_khz = 3600,
+};
+
static struct s921_config sharp_isdbt = {
.demod_address = 0x30 >> 1
};
@@ -351,6 +369,12 @@ static struct tda18271_config kworld_ub435q_v2_config = {
.gate = TDA18271_GATE_DIGITAL,
};
+static struct tda18212_config kworld_ub435q_v3_config = {
+ .i2c_address = 0x60,
+ .if_atsc_vsb = 3600,
+ .if_atsc_qam = 3600,
+};
+
static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = {
.demod_address = (0x1e >> 1),
.no_tuner = 1,
@@ -693,7 +717,8 @@ static void pctv_520e_init(struct em28xx *dev)
static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- struct em28xx *dev = fe->dvb->priv;
+ struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv;
+ struct em28xx *dev = i2c_bus->dev;
#ifdef CONFIG_GPIOLIB
struct em28xx_dvb *dvb = dev->dvb;
int ret;
@@ -817,6 +842,20 @@ static const struct m88ds3103_config pctv_461e_m88ds3103_config = {
.agc = 0x99,
};
+
+static struct tda18271_std_map drx_j_std_map = {
+ .atsc_6 = { .if_freq = 5000, .agc_mode = 3, .std = 0, .if_lvl = 1,
+ .rfagc_top = 0x37, },
+ .qam_6 = { .if_freq = 5380, .agc_mode = 3, .std = 3, .if_lvl = 1,
+ .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config pinnacle_80e_dvb_config = {
+ .std_map = &drx_j_std_map,
+ .gate = TDA18271_GATE_DIGITAL,
+ .role = TDA18271_MASTER,
+};
+
/* ------------------------------------------------------------------ */
static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev)
@@ -1005,7 +1044,6 @@ static int em28xx_dvb_init(struct em28xx *dev)
em28xx_info("Binding DVB extension\n");
dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
-
if (dvb == NULL) {
em28xx_info("em28xx_dvb: memory allocation failed\n");
return -ENOMEM;
@@ -1370,10 +1408,40 @@ static int em28xx_dvb_init(struct em28xx *dev)
goto out_free;
}
break;
+ case EM2874_BOARD_KWORLD_UB435Q_V3:
+ dvb->fe[0] = dvb_attach(lgdt3305_attach,
+ &em2874_lgdt3305_nogate_dev,
+ &dev->i2c_adap[dev->def_i2c_bus]);
+ if (!dvb->fe[0]) {
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ /* Attach the demodulator. */
+ if (!dvb_attach(tda18212_attach, dvb->fe[0],
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &kworld_ub435q_v3_config)) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ break;
+ case EM2874_BOARD_PCTV_HD_MINI_80E:
+ dvb->fe[0] = dvb_attach(drx39xxj_attach, &dev->i2c_adap[dev->def_i2c_bus]);
+ if (dvb->fe[0] != NULL) {
+ dvb->fe[0] = dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &pinnacle_80e_dvb_config);
+ if (!dvb->fe[0]) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ }
+ break;
case EM28178_BOARD_PCTV_461E:
{
/* demod I2C adapter */
struct i2c_adapter *i2c_adapter;
+ struct i2c_client *client;
struct i2c_board_info info;
struct m88ts2022_config m88ts2022_config = {
.clock = 27000000,
@@ -1396,7 +1464,19 @@ static int em28xx_dvb_init(struct em28xx *dev)
info.addr = 0x60;
info.platform_data = &m88ts2022_config;
request_module("m88ts2022");
- dvb->i2c_client_tuner = i2c_new_device(i2c_adapter, &info);
+ client = i2c_new_device(i2c_adapter, &info);
+ if (client == NULL || client->dev.driver == NULL) {
+ dvb_frontend_detach(dvb->fe[0]);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ dvb_frontend_detach(dvb->fe[0]);
+ result = -ENODEV;
+ goto out_free;
+ }
/* delegate signal strength measurement to tuner */
dvb->fe[0]->ops.read_signal_strength =
@@ -1406,10 +1486,14 @@ static int em28xx_dvb_init(struct em28xx *dev)
if (!dvb_attach(a8293_attach, dvb->fe[0],
&dev->i2c_adap[dev->def_i2c_bus],
&em28xx_a8293_config)) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
dvb_frontend_detach(dvb->fe[0]);
result = -ENODEV;
goto out_free;
}
+
+ dvb->i2c_client_tuner = client;
}
break;
default:
@@ -1437,6 +1521,9 @@ static int em28xx_dvb_init(struct em28xx *dev)
dvb->adapter.mfe_shared = mfe_shared;
em28xx_info("DVB extension successfully initialized\n");
+
+ kref_get(&dev->ref);
+
ret:
em28xx_set_mode(dev, EM28XX_SUSPEND);
mutex_unlock(&dev->lock);
@@ -1457,6 +1544,9 @@ static inline void prevent_sleep(struct dvb_frontend_ops *ops)
static int em28xx_dvb_fini(struct em28xx *dev)
{
+ struct em28xx_dvb *dvb;
+ struct i2c_client *client;
+
if (dev->is_audio_only) {
/* Shouldn't initialize IR for this interface */
return 0;
@@ -1467,23 +1557,96 @@ static int em28xx_dvb_fini(struct em28xx *dev)
return 0;
}
+ if (!dev->dvb)
+ return 0;
+
em28xx_info("Closing DVB extension");
+ dvb = dev->dvb;
+ client = dvb->i2c_client_tuner;
+
+ em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE);
+
+ if (dev->disconnected) {
+ /* We cannot tell the device to sleep
+ * once it has been unplugged. */
+ if (dvb->fe[0])
+ prevent_sleep(&dvb->fe[0]->ops);
+ if (dvb->fe[1])
+ prevent_sleep(&dvb->fe[1]->ops);
+ }
+
+ /* remove I2C tuner */
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+
+ em28xx_unregister_dvb(dvb);
+ kfree(dvb);
+ dev->dvb = NULL;
+ kref_put(&dev->ref, em28xx_free_device);
+
+ return 0;
+}
+
+static int em28xx_dvb_suspend(struct em28xx *dev)
+{
+ int ret = 0;
+
+ if (dev->is_audio_only)
+ return 0;
+
+ if (!dev->board.has_dvb)
+ return 0;
+
+ em28xx_info("Suspending DVB extension");
if (dev->dvb) {
struct em28xx_dvb *dvb = dev->dvb;
- em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE);
+ if (dvb->fe[0]) {
+ ret = dvb_frontend_suspend(dvb->fe[0]);
+ em28xx_info("fe0 suspend %d", ret);
+ }
+ if (dvb->fe[1]) {
+ dvb_frontend_suspend(dvb->fe[1]);
+ em28xx_info("fe1 suspend %d", ret);
+ }
+ }
+
+ return 0;
+}
+
+static int em28xx_dvb_resume(struct em28xx *dev)
+{
+ int ret = 0;
- if (dev->disconnected) {
- /* We cannot tell the device to sleep
- * once it has been unplugged. */
- if (dvb->fe[0])
- prevent_sleep(&dvb->fe[0]->ops);
- if (dvb->fe[1])
- prevent_sleep(&dvb->fe[1]->ops);
+ if (dev->is_audio_only)
+ return 0;
+
+ if (!dev->board.has_dvb)
+ return 0;
+
+ em28xx_info("Resuming DVB extension");
+ if (dev->dvb) {
+ struct em28xx_dvb *dvb = dev->dvb;
+ struct i2c_client *client = dvb->i2c_client_tuner;
+
+ if (dvb->fe[0]) {
+ ret = dvb_frontend_resume(dvb->fe[0]);
+ em28xx_info("fe0 resume %d", ret);
+ }
+
+ if (dvb->fe[1]) {
+ ret = dvb_frontend_resume(dvb->fe[1]);
+ em28xx_info("fe1 resume %d", ret);
+ }
+ /* remove I2C tuner */
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
}
- i2c_release_client(dvb->i2c_client_tuner);
em28xx_unregister_dvb(dvb);
kfree(dvb);
dev->dvb = NULL;
@@ -1497,6 +1660,8 @@ static struct em28xx_ops dvb_ops = {
.name = "Em28xx dvb Extension",
.init = em28xx_dvb_init,
.fini = em28xx_dvb_fini,
+ .suspend = em28xx_dvb_suspend,
+ .resume = em28xx_dvb_resume,
};
static int __init em28xx_dvb_register(void)
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index 7e1724076ac4..ba6433c3a643 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -81,7 +81,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
return len;
if (ret == 0x94 + len - 1) {
if (i2c_debug == 1)
- em28xx_warn("R05 returned 0x%02x: I2C timeout",
+ em28xx_warn("R05 returned 0x%02x: I2C ACK error\n",
ret);
return -ENXIO;
}
@@ -128,7 +128,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
break;
if (ret == 0x94 + len - 1) {
if (i2c_debug == 1)
- em28xx_warn("R05 returned 0x%02x: I2C timeout",
+ em28xx_warn("R05 returned 0x%02x: I2C ACK error\n",
ret);
return -ENXIO;
}
@@ -210,7 +210,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
return len;
if (ret == 0x10) {
if (i2c_debug == 1)
- em28xx_warn("I2C transfer timeout on writing to addr 0x%02x",
+ em28xx_warn("I2C ACK error on writing to addr 0x%02x\n",
addr);
return -ENXIO;
}
@@ -226,10 +226,18 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
* (even with high payload) ...
*/
}
- if (i2c_debug)
- em28xx_warn("write to i2c device at 0x%x timed out (status=%i)\n",
- addr, ret);
- return -ETIMEDOUT;
+
+ if (ret == 0x02 || ret == 0x04) {
+ /* NOTE: these errors seem to be related to clock stretching */
+ if (i2c_debug)
+ em28xx_warn("write to i2c device at 0x%x timed out (status=%i)\n",
+ addr, ret);
+ return -ETIMEDOUT;
+ }
+
+ em28xx_warn("write to i2c device at 0x%x failed with unknown error (status=%i)\n",
+ addr, ret);
+ return -EIO;
}
/*
@@ -274,13 +282,22 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
}
if (ret == 0x10) {
if (i2c_debug == 1)
- em28xx_warn("I2C transfer timeout on writing to addr 0x%02x",
+ em28xx_warn("I2C ACK error on writing to addr 0x%02x\n",
addr);
return -ENXIO;
}
- em28xx_warn("unknown i2c error (status=%i)\n", ret);
- return -ETIMEDOUT;
+ if (ret == 0x02 || ret == 0x04) {
+ /* NOTE: these errors seem to be related to clock stretching */
+ if (i2c_debug)
+ em28xx_warn("write to i2c device at 0x%x timed out (status=%i)\n",
+ addr, ret);
+ return -ETIMEDOUT;
+ }
+
+ em28xx_warn("write to i2c device at 0x%x failed with unknown error (status=%i)\n",
+ addr, ret);
+ return -EIO;
}
/*
@@ -337,7 +354,7 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
return len;
else if (ret > 0) {
if (i2c_debug == 1)
- em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout",
+ em28xx_warn("Bus B R08 returned 0x%02x: I2C ACK error\n",
ret);
return -ENXIO;
}
@@ -392,7 +409,7 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
return len;
else if (ret > 0) {
if (i2c_debug == 1)
- em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout",
+ em28xx_warn("Bus B R08 returned 0x%02x: I2C ACK error\n",
ret);
return -ENXIO;
}
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 18f65d89d4bc..56ef49df4f8d 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -676,6 +676,8 @@ static int em28xx_ir_init(struct em28xx *dev)
return 0;
}
+ kref_get(&dev->ref);
+
if (dev->board.buttons)
em28xx_init_buttons(dev);
@@ -725,7 +727,7 @@ static int em28xx_ir_init(struct em28xx *dev)
case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
rc->map_name = RC_MAP_HAUPPAUGE;
ir->get_key_i2c = em28xx_get_key_em_haup;
- rc->allowed_protos = RC_BIT_RC5;
+ rc_set_allowed_protocols(rc, RC_BIT_RC5);
break;
case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
rc->map_name = RC_MAP_WINFAST_USBII_DELUXE;
@@ -741,7 +743,7 @@ static int em28xx_ir_init(struct em28xx *dev)
switch (dev->chip_id) {
case CHIP_ID_EM2860:
case CHIP_ID_EM2883:
- rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC;
+ rc_set_allowed_protocols(rc, RC_BIT_RC5 | RC_BIT_NEC);
ir->get_key = default_polling_getkey;
break;
case CHIP_ID_EM2884:
@@ -749,8 +751,8 @@ static int em28xx_ir_init(struct em28xx *dev)
case CHIP_ID_EM28174:
case CHIP_ID_EM28178:
ir->get_key = em2874_polling_getkey;
- rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC |
- RC_BIT_RC6_0;
+ rc_set_allowed_protocols(rc, RC_BIT_RC5 | RC_BIT_NEC |
+ RC_BIT_RC6_0);
break;
default:
err = -ENODEV;
@@ -816,7 +818,7 @@ static int em28xx_ir_fini(struct em28xx *dev)
/* skip detach on non attached boards */
if (!ir)
- return 0;
+ goto ref_put;
if (ir->rc)
rc_unregister_device(ir->rc);
@@ -824,6 +826,45 @@ static int em28xx_ir_fini(struct em28xx *dev)
/* done */
kfree(ir);
dev->ir = NULL;
+
+ref_put:
+ kref_put(&dev->ref, em28xx_free_device);
+
+ return 0;
+}
+
+static int em28xx_ir_suspend(struct em28xx *dev)
+{
+ struct em28xx_IR *ir = dev->ir;
+
+ if (dev->is_audio_only)
+ return 0;
+
+ em28xx_info("Suspending input extension");
+ if (ir)
+ cancel_delayed_work_sync(&ir->work);
+ cancel_delayed_work_sync(&dev->buttons_query_work);
+ /* is canceling delayed work sufficient or does the rc event
+ kthread needs stopping? kthread is stopped in
+ ir_raw_event_unregister() */
+ return 0;
+}
+
+static int em28xx_ir_resume(struct em28xx *dev)
+{
+ struct em28xx_IR *ir = dev->ir;
+
+ if (dev->is_audio_only)
+ return 0;
+
+ em28xx_info("Resuming input extension");
+ /* if suspend calls ir_raw_event_unregister(), the should call
+ ir_raw_event_register() */
+ if (ir)
+ schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
+ if (dev->num_button_polling_addresses)
+ schedule_delayed_work(&dev->buttons_query_work,
+ msecs_to_jiffies(dev->button_polling_interval));
return 0;
}
@@ -832,6 +873,8 @@ static struct em28xx_ops rc_ops = {
.name = "Em28xx Input Extension",
.init = em28xx_ir_init,
.fini = em28xx_ir_fini,
+ .suspend = em28xx_ir_suspend,
+ .resume = em28xx_ir_resume,
};
static int __init em28xx_rc_register(void)
@@ -845,7 +888,7 @@ static void __exit em28xx_rc_unregister(void)
}
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_DESCRIPTION(DRIVER_DESC " - input interface");
MODULE_VERSION(EM28XX_VERSION);
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index c3c928937dcd..0856e5d367b6 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1029,7 +1029,7 @@ static int em28xx_vb2_setup(struct em28xx *dev)
q = &dev->vb_vidq;
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->drv_priv = dev;
q->buf_struct_size = sizeof(struct em28xx_buffer);
q->ops = &em28xx_video_qops;
@@ -1043,7 +1043,7 @@ static int em28xx_vb2_setup(struct em28xx *dev)
q = &dev->vb_vbiq;
q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR;
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->drv_priv = dev;
q->buf_struct_size = sizeof(struct em28xx_buffer);
q->ops = &em28xx_vbi_qops;
@@ -1837,7 +1837,6 @@ static int em28xx_v4l2_open(struct file *filp)
video_device_node_name(vdev), v4l2_type_names[fh_type],
dev->users);
-
if (mutex_lock_interruptible(&dev->lock))
return -ERESTARTSYS;
fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
@@ -1869,6 +1868,7 @@ static int em28xx_v4l2_open(struct file *filp)
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
}
+ kref_get(&dev->ref);
dev->users++;
mutex_unlock(&dev->lock);
@@ -1918,18 +1918,43 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
video_unregister_device(dev->vdev);
}
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
+ v4l2_device_unregister(&dev->v4l2_dev);
+
if (dev->clk) {
v4l2_clk_unregister_fixed(dev->clk);
dev->clk = NULL;
}
- v4l2_ctrl_handler_free(&dev->ctrl_handler);
- v4l2_device_unregister(&dev->v4l2_dev);
-
- if (dev->users)
- em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n");
mutex_unlock(&dev->lock);
+ kref_put(&dev->ref, em28xx_free_device);
+
+ return 0;
+}
+
+static int em28xx_v4l2_suspend(struct em28xx *dev)
+{
+ if (dev->is_audio_only)
+ return 0;
+ if (!dev->has_video)
+ return 0;
+
+ em28xx_info("Suspending video extension");
+ em28xx_stop_urbs(dev);
+ return 0;
+}
+
+static int em28xx_v4l2_resume(struct em28xx *dev)
+{
+ if (dev->is_audio_only)
+ return 0;
+
+ if (!dev->has_video)
+ return 0;
+
+ em28xx_info("Resuming video extension");
+ /* what do we do here */
return 0;
}
@@ -1950,11 +1975,9 @@ static int em28xx_v4l2_close(struct file *filp)
mutex_lock(&dev->lock);
if (dev->users == 1) {
- /* free the remaining resources if device is disconnected */
- if (dev->disconnected) {
- kfree(dev->alt_max_pkt_size_isoc);
+ /* No sense to try to write to the device */
+ if (dev->disconnected)
goto exit;
- }
/* Save some power by putting tuner to sleep */
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
@@ -1975,6 +1998,8 @@ static int em28xx_v4l2_close(struct file *filp)
exit:
dev->users--;
mutex_unlock(&dev->lock);
+ kref_put(&dev->ref, em28xx_free_device);
+
return 0;
}
@@ -2273,7 +2298,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
}
em28xx_tuner_setup(dev);
- em28xx_init_camera(dev);
+ if (dev->em28xx_sensor != EM28XX_NOSENSOR)
+ em28xx_init_camera(dev);
/* Configure audio */
ret = em28xx_audio_setup(dev);
@@ -2488,6 +2514,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
em28xx_info("V4L2 extension successfully initialized\n");
+ kref_get(&dev->ref);
+
mutex_unlock(&dev->lock);
return 0;
@@ -2504,6 +2532,8 @@ static struct em28xx_ops v4l2_ops = {
.name = "Em28xx v4l2 Extension",
.init = em28xx_v4l2_init,
.fini = em28xx_v4l2_fini,
+ .suspend = em28xx_v4l2_suspend,
+ .resume = em28xx_v4l2_resume,
};
static int __init em28xx_video_register(void)
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 32d8a4bb7961..2051fc9fb932 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -32,6 +32,7 @@
#include <linux/workqueue.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
+#include <linux/kref.h>
#include <linux/videodev2.h>
#include <media/videobuf2-vmalloc.h>
@@ -104,6 +105,7 @@
#define EM2882_BOARD_PINNACLE_HYBRID_PRO_330E 56
#define EM2883_BOARD_KWORLD_HYBRID_330U 57
#define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58
+#define EM2874_BOARD_PCTV_HD_MINI_80E 59
#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 60
#define EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2 61
#define EM2820_BOARD_GADMEI_TVR200 62
@@ -137,6 +139,7 @@
#define EM2874_BOARD_KWORLD_UB435Q_V2 90
#define EM2765_BOARD_SPEEDLINK_VAD_LAPLACE 91
#define EM28178_BOARD_PCTV_461E 92
+#define EM2874_BOARD_KWORLD_UB435Q_V3 93
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
@@ -399,6 +402,7 @@ enum em28xx_adecoder {
enum em28xx_led_role {
EM28XX_LED_ANALOG_CAPTURING = 0,
+ EM28XX_LED_DIGITAL_CAPTURING,
EM28XX_LED_ILLUMINATION,
EM28XX_NUM_LED_ROLES, /* must be the last */
};
@@ -533,9 +537,10 @@ struct em28xx_i2c_bus {
enum em28xx_i2c_algo_type algo_type;
};
-
/* main device struct */
struct em28xx {
+ struct kref ref;
+
/* generic device properties */
char name[30]; /* name (including minor) of the device */
int model; /* index in the device_data struct */
@@ -707,12 +712,16 @@ struct em28xx {
struct em28xx_dvb *dvb;
};
+#define kref_to_dev(d) container_of(d, struct em28xx, ref)
+
struct em28xx_ops {
struct list_head next;
char *name;
int id;
int (*init)(struct em28xx *);
int (*fini)(struct em28xx *);
+ int (*suspend)(struct em28xx *);
+ int (*resume)(struct em28xx *);
};
/* Provided by em28xx-i2c.c */
@@ -758,13 +767,15 @@ int em28xx_register_extension(struct em28xx_ops *dev);
void em28xx_unregister_extension(struct em28xx_ops *dev);
void em28xx_init_extension(struct em28xx *dev);
void em28xx_close_extension(struct em28xx *dev);
+int em28xx_suspend_extension(struct em28xx *dev);
+int em28xx_resume_extension(struct em28xx *dev);
/* Provided by em28xx-cards.c */
extern struct em28xx_board em28xx_boards[];
extern struct usb_device_id em28xx_id_table[];
int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
-void em28xx_release_resources(struct em28xx *dev);
+void em28xx_free_device(struct kref *ref);
/* Provided by em28xx-camera.c */
int em28xx_detect_sensor(struct em28xx *dev);
diff --git a/drivers/media/usb/gspca/kinect.c b/drivers/media/usb/gspca/kinect.c
index 3773a8a745df..081f05162809 100644
--- a/drivers/media/usb/gspca/kinect.c
+++ b/drivers/media/usb/gspca/kinect.c
@@ -155,10 +155,11 @@ static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf,
do {
actual_len = kinect_read(udev, ibuf, 0x200);
} while (actual_len == 0);
- PDEBUG(D_USBO, "Control reply: %d", res);
+ PDEBUG(D_USBO, "Control reply: %d", actual_len);
if (actual_len < sizeof(*rhdr)) {
- pr_err("send_cmd: Input control transfer failed (%d)\n", res);
- return res;
+ pr_err("send_cmd: Input control transfer failed (%d)\n",
+ actual_len);
+ return actual_len < 0 ? actual_len : -EREMOTEIO;
}
actual_len -= sizeof(*rhdr);
diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c
index 2a38621cf718..41a9a892f79c 100644
--- a/drivers/media/usb/gspca/sn9c20x.c
+++ b/drivers/media/usb/gspca/sn9c20x.c
@@ -2359,6 +2359,7 @@ static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)},
{USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)},
{USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)},
+ {USB_DEVICE(0x0458, 0x7045), SN9C20X(MT9M112, 0x5d, LED_REVERSE)},
{USB_DEVICE(0x0458, 0x704a), SN9C20X(MT9M112, 0x5d, 0)},
{USB_DEVICE(0x0458, 0x704c), SN9C20X(MT9M112, 0x5d, 0)},
{USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)},
diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c
index bf3e5c317a26..e60cbb3aa609 100644
--- a/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c
@@ -178,7 +178,7 @@ static int vv6410_stop(struct sd *sd)
PDEBUG(D_STREAM, "Halting stream");
- return (err < 0) ? err : 0;
+ return 0;
}
static int vv6410_dump(struct sd *sd)
diff --git a/drivers/media/usb/gspca/topro.c b/drivers/media/usb/gspca/topro.c
index 640c2fe760b3..5fcd1eec2004 100644
--- a/drivers/media/usb/gspca/topro.c
+++ b/drivers/media/usb/gspca/topro.c
@@ -4631,8 +4631,16 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
}
data++;
len--;
+ if (len < 2) {
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ return;
+ }
if (*data == 0xff && data[1] == 0xd8) {
/*fixme: there may be information in the 4 high bits*/
+ if (len < 7) {
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ return;
+ }
if ((data[6] & 0x0f) != sd->quality)
set_dqt(gspca_dev, data[6] & 0x0f);
gspca_frame_add(gspca_dev, FIRST_PACKET,
@@ -4672,7 +4680,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_dev->last_packet_type = DISCARD_PACKET;
break;
case 0xcc:
- if (data[1] != 0xff || data[2] != 0xd8)
+ if (len >= 3 && (data[1] != 0xff || data[2] != 0xd8))
gspca_frame_add(gspca_dev, INTER_PACKET,
data + 1, len - 1);
else
diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c
index abf365ab025d..84a6720b1d00 100644
--- a/drivers/media/usb/pwc/pwc-if.c
+++ b/drivers/media/usb/pwc/pwc-if.c
@@ -614,17 +614,20 @@ static int buffer_prepare(struct vb2_buffer *vb)
return 0;
}
-static int buffer_finish(struct vb2_buffer *vb)
+static void buffer_finish(struct vb2_buffer *vb)
{
struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue);
struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
- /*
- * Application has called dqbuf and is getting back a buffer we've
- * filled, take the pwc data we've stored in buf->data and decompress
- * it into a usable format, storing the result in the vb2_buffer
- */
- return pwc_decompress(pdev, buf);
+ if (vb->state == VB2_BUF_STATE_DONE) {
+ /*
+ * Application has called dqbuf and is getting back a buffer
+ * we've filled, take the pwc data we've stored in buf->data
+ * and decompress it into a usable format, storing the result
+ * in the vb2_buffer.
+ */
+ pwc_decompress(pdev, buf);
+ }
}
static void buffer_cleanup(struct vb2_buffer *vb)
@@ -1001,7 +1004,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->vb_queue.buf_struct_size = sizeof(struct pwc_frame_buf);
pdev->vb_queue.ops = &pwc_vb_queue_ops;
pdev->vb_queue.mem_ops = &vb2_vmalloc_memops;
- pdev->vb_queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ pdev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
rc = vb2_queue_init(&pdev->vb_queue);
if (rc < 0) {
PWC_ERROR("Oops, could not initialize vb2 queue.\n");
diff --git a/drivers/media/usb/s2255/Kconfig b/drivers/media/usb/s2255/Kconfig
index 7e8ee1f864ab..8c3fceef9a09 100644
--- a/drivers/media/usb/s2255/Kconfig
+++ b/drivers/media/usb/s2255/Kconfig
@@ -1,7 +1,7 @@
config USB_S2255
tristate "USB Sensoray 2255 video capture device"
depends on VIDEO_V4L2
- select VIDEOBUF_VMALLOC
+ select VIDEOBUF2_VMALLOC
default n
help
Say Y here if you want support for the Sensoray 2255 USB device.
diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c
index 6bc9b8e19e20..1d4ba2b80490 100644
--- a/drivers/media/usb/s2255/s2255drv.c
+++ b/drivers/media/usb/s2255/s2255drv.c
@@ -1,7 +1,7 @@
/*
* s2255drv.c - a driver for the Sensoray 2255 USB video capture device
*
- * Copyright (C) 2007-2013 by Sensoray Company Inc.
+ * Copyright (C) 2007-2014 by Sensoray Company Inc.
* Dean Anderson
*
* Some video buffer code based on vivi driver:
@@ -45,14 +45,14 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/usb.h>
-#include <media/videobuf-vmalloc.h>
+#include <media/videobuf2-vmalloc.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
-#define S2255_VERSION "1.23.1"
+#define S2255_VERSION "1.25.1"
#define FIRMWARE_FILE_NAME "f2255usb.bin"
/* default JPEG quality */
@@ -69,7 +69,7 @@
#define S2255_DSP_BOOTTIME 800
/* maximum time to wait for firmware to load (ms) */
#define S2255_LOAD_TIMEOUT (5000 + S2255_DSP_BOOTTIME)
-#define S2255_DEF_BUFS 16
+#define S2255_MIN_BUFS 2
#define S2255_SETMODE_TIMEOUT 500
#define S2255_VIDSTATUS_TIMEOUT 350
#define S2255_MARKER_FRAME cpu_to_le32(0x2255DA4AL)
@@ -178,11 +178,6 @@ struct s2255_bufferi {
DEF_FDEC, DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, \
DEF_HUE, 0, DEF_USB_BLOCK, 0}
-struct s2255_dmaqueue {
- struct list_head active;
- struct s2255_dev *dev;
-};
-
/* for firmware loading, fw_state */
#define S2255_FW_NOTLOADED 0
#define S2255_FW_LOADED_DSPWAIT 1
@@ -217,12 +212,14 @@ struct s2255_pipeinfo {
struct s2255_fmt; /*forward declaration */
struct s2255_dev;
-struct s2255_channel {
+/* 2255 video channel */
+struct s2255_vc {
+ struct s2255_dev *dev;
struct video_device vdev;
struct v4l2_ctrl_handler hdl;
struct v4l2_ctrl *jpegqual_ctrl;
int resources;
- struct s2255_dmaqueue vidq;
+ struct list_head buf_list;
struct s2255_bufferi buffer;
struct s2255_mode mode;
v4l2_std_id std;
@@ -232,8 +229,6 @@ struct s2255_channel {
struct v4l2_captureparm cap_parm;
int cur_frame;
int last_frame;
-
- int b_acquire;
/* allocated image size */
unsigned long req_image_size;
/* received packet size */
@@ -252,17 +247,22 @@ struct s2255_channel {
int vidstatus_ready;
unsigned int width;
unsigned int height;
+ enum v4l2_field field;
const struct s2255_fmt *fmt;
int idx; /* channel number on device, 0-3 */
+ struct vb2_queue vb_vidq;
+ struct mutex vb_lock; /* streaming lock */
+ spinlock_t qlock;
};
struct s2255_dev {
- struct s2255_channel channel[MAX_CHANNELS];
- struct v4l2_device v4l2_dev;
+ struct s2255_vc vc[MAX_CHANNELS];
+ struct v4l2_device v4l2_dev;
atomic_t num_channels;
int frames;
struct mutex lock; /* channels[].vdev.lock */
+ struct mutex cmdlock; /* protects cmdbuf */
struct usb_device *udev;
struct usb_interface *interface;
u8 read_endpoint;
@@ -272,10 +272,11 @@ struct s2255_dev {
u32 cc; /* current channel */
int frame_ready;
int chn_ready;
- spinlock_t slock;
/* dsp firmware version (f2255usb.bin) */
int dsp_fw_ver;
u16 pid; /* product id */
+#define S2255_CMDBUF_SIZE 512
+ __le32 *cmdbuf;
};
static inline struct s2255_dev *to_s2255_dev(struct v4l2_device *v4l2_dev)
@@ -292,19 +293,10 @@ struct s2255_fmt {
/* buffer for one video frame */
struct s2255_buffer {
/* common v4l buffer stuff -- must be first */
- struct videobuf_buffer vb;
- const struct s2255_fmt *fmt;
+ struct vb2_buffer vb;
+ struct list_head list;
};
-struct s2255_fh {
- /* this must be the first field in this struct */
- struct v4l2_fh fh;
- struct s2255_dev *dev;
- struct videobuf_queue vb_vidq;
- enum v4l2_buf_type type;
- struct s2255_channel *channel;
- int resources;
-};
/* current cypress EEPROM firmware version */
#define S2255_CUR_USB_FWVER ((3 << 8) | 12)
@@ -352,15 +344,14 @@ struct s2255_fh {
static unsigned long G_chnmap[MAX_CHANNELS] = {3, 2, 1, 0};
static int debug;
-static int *s2255_debug = &debug;
static int s2255_start_readpipe(struct s2255_dev *dev);
static void s2255_stop_readpipe(struct s2255_dev *dev);
-static int s2255_start_acquire(struct s2255_channel *channel);
-static int s2255_stop_acquire(struct s2255_channel *channel);
-static void s2255_fillbuff(struct s2255_channel *chn, struct s2255_buffer *buf,
+static int s2255_start_acquire(struct s2255_vc *vc);
+static int s2255_stop_acquire(struct s2255_vc *vc);
+static void s2255_fillbuff(struct s2255_vc *vc, struct s2255_buffer *buf,
int jpgsize);
-static int s2255_set_mode(struct s2255_channel *chan, struct s2255_mode *mode);
+static int s2255_set_mode(struct s2255_vc *vc, struct s2255_mode *mode);
static int s2255_board_shutdown(struct s2255_dev *dev);
static void s2255_fwload_start(struct s2255_dev *dev, int reset);
static void s2255_destroy(struct s2255_dev *dev);
@@ -373,19 +364,11 @@ static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req,
#define s2255_dev_err(dev, fmt, arg...) \
dev_err(dev, S2255_DRIVER_NAME " - " fmt, ##arg)
-#define dprintk(level, fmt, arg...) \
- do { \
- if (*s2255_debug >= (level)) { \
- printk(KERN_DEBUG S2255_DRIVER_NAME \
- ": " fmt, ##arg); \
- } \
- } while (0)
+#define dprintk(dev, level, fmt, arg...) \
+ v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
static struct usb_driver s2255_driver;
-/* Declare static vars that will be used as parameters */
-static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
-
/* start video number */
static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
@@ -394,8 +377,6 @@ static int jpeg_enable = 1;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level(0-100) default 0");
-module_param(vid_limit, int, 0644);
-MODULE_PARM_DESC(vid_limit, "video memory limit(Mb)");
module_param(video_nr, int, 0644);
MODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)");
module_param(jpeg_enable, int, 0644);
@@ -444,27 +425,27 @@ static const struct s2255_fmt formats[] = {
}
};
-static int norm_maxw(struct s2255_channel *channel)
+static int norm_maxw(struct s2255_vc *vc)
{
- return (channel->std & V4L2_STD_525_60) ?
+ return (vc->std & V4L2_STD_525_60) ?
LINE_SZ_4CIFS_NTSC : LINE_SZ_4CIFS_PAL;
}
-static int norm_maxh(struct s2255_channel *channel)
+static int norm_maxh(struct s2255_vc *vc)
{
- return (channel->std & V4L2_STD_525_60) ?
+ return (vc->std & V4L2_STD_525_60) ?
(NUM_LINES_1CIFS_NTSC * 2) : (NUM_LINES_1CIFS_PAL * 2);
}
-static int norm_minw(struct s2255_channel *channel)
+static int norm_minw(struct s2255_vc *vc)
{
- return (channel->std & V4L2_STD_525_60) ?
+ return (vc->std & V4L2_STD_525_60) ?
LINE_SZ_1CIFS_NTSC : LINE_SZ_1CIFS_PAL;
}
-static int norm_minh(struct s2255_channel *channel)
+static int norm_minh(struct s2255_vc *vc)
{
- return (channel->std & V4L2_STD_525_60) ?
+ return (vc->std & V4L2_STD_525_60) ?
(NUM_LINES_1CIFS_NTSC) : (NUM_LINES_1CIFS_PAL);
}
@@ -498,7 +479,7 @@ static void planar422p_to_yuv_packed(const unsigned char *in,
static void s2255_reset_dsppower(struct s2255_dev *dev)
{
s2255_vendor_req(dev, 0x40, 0x0000, 0x0001, NULL, 0, 1);
- msleep(10);
+ msleep(20);
s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1);
msleep(600);
s2255_vendor_req(dev, 0x10, 0x0000, 0x0000, NULL, 0, 1);
@@ -510,9 +491,8 @@ static void s2255_reset_dsppower(struct s2255_dev *dev)
static void s2255_timer(unsigned long user_data)
{
struct s2255_fw *data = (struct s2255_fw *)user_data;
- dprintk(100, "%s\n", __func__);
if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) {
- printk(KERN_ERR "s2255: can't submit urb\n");
+ pr_err("s2255: can't submit urb\n");
atomic_set(&data->fw_state, S2255_FW_FAILED);
/* wake up anything waiting for the firmware */
wake_up(&data->wait_fw);
@@ -532,7 +512,6 @@ static void s2255_fwchunk_complete(struct urb *urb)
struct s2255_fw *data = urb->context;
struct usb_device *udev = urb->dev;
int len;
- dprintk(100, "%s: udev %p urb %p", __func__, udev, urb);
if (urb->status) {
dev_err(&udev->dev, "URB failed with status %d\n", urb->status);
atomic_set(&data->fw_state, S2255_FW_FAILED);
@@ -559,9 +538,6 @@ static void s2255_fwchunk_complete(struct urb *urb)
if (len < CHUNK_SIZE)
memset(data->pfw_data, 0, CHUNK_SIZE);
- dprintk(100, "completed len %d, loaded %d \n", len,
- data->fw_loaded);
-
memcpy(data->pfw_data,
(char *) data->fw->data + data->fw_loaded, len);
@@ -576,36 +552,32 @@ static void s2255_fwchunk_complete(struct urb *urb)
return;
}
data->fw_loaded += len;
- } else {
+ } else
atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT);
- dprintk(100, "%s: firmware upload complete\n", __func__);
- }
return;
}
-static int s2255_got_frame(struct s2255_channel *channel, int jpgsize)
+static int s2255_got_frame(struct s2255_vc *vc, int jpgsize)
{
- struct s2255_dmaqueue *dma_q = &channel->vidq;
struct s2255_buffer *buf;
- struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+ struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
unsigned long flags = 0;
int rc = 0;
- spin_lock_irqsave(&dev->slock, flags);
- if (list_empty(&dma_q->active)) {
- dprintk(1, "No active queue to serve\n");
+ spin_lock_irqsave(&vc->qlock, flags);
+ if (list_empty(&vc->buf_list)) {
+ dprintk(dev, 1, "No active queue to serve\n");
rc = -1;
goto unlock;
}
- buf = list_entry(dma_q->active.next,
- struct s2255_buffer, vb.queue);
- list_del(&buf->vb.queue);
- v4l2_get_timestamp(&buf->vb.ts);
- s2255_fillbuff(channel, buf, jpgsize);
- wake_up(&buf->vb.done);
- dprintk(2, "%s: [buf/i] [%p/%d]\n", __func__, buf, buf->vb.i);
+ buf = list_entry(vc->buf_list.next,
+ struct s2255_buffer, list);
+ list_del(&buf->list);
+ v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+ s2255_fillbuff(vc, buf, jpgsize);
+ dprintk(dev, 2, "%s: [buf] [%p]\n", __func__, buf);
unlock:
- spin_unlock_irqrestore(&dev->slock, flags);
+ spin_unlock_irqrestore(&vc->qlock, flags);
return rc;
}
@@ -615,9 +587,9 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc)
for (i = 0; i < ARRAY_SIZE(formats); i++) {
if (-1 == formats[i].fourcc)
continue;
- if (!jpeg_enable && ((formats[i].fourcc == V4L2_PIX_FMT_JPEG) ||
- (formats[i].fourcc == V4L2_PIX_FMT_MJPEG)))
- continue;
+ if (!jpeg_enable && ((formats[i].fourcc == V4L2_PIX_FMT_JPEG) ||
+ (formats[i].fourcc == V4L2_PIX_FMT_MJPEG)))
+ continue;
if (formats[i].fourcc == fourcc)
return formats + i;
}
@@ -632,56 +604,56 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc)
* http://v4l.videotechnology.com/
*
*/
-static void s2255_fillbuff(struct s2255_channel *channel,
+static void s2255_fillbuff(struct s2255_vc *vc,
struct s2255_buffer *buf, int jpgsize)
{
int pos = 0;
const char *tmpbuf;
- char *vbuf = videobuf_to_vmalloc(&buf->vb);
+ char *vbuf = vb2_plane_vaddr(&buf->vb, 0);
unsigned long last_frame;
+ struct s2255_dev *dev = vc->dev;
if (!vbuf)
return;
- last_frame = channel->last_frame;
+ last_frame = vc->last_frame;
if (last_frame != -1) {
tmpbuf =
- (const char *)channel->buffer.frame[last_frame].lpvbits;
- switch (buf->fmt->fourcc) {
+ (const char *)vc->buffer.frame[last_frame].lpvbits;
+ switch (vc->fmt->fourcc) {
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
planar422p_to_yuv_packed((const unsigned char *)tmpbuf,
- vbuf, buf->vb.width,
- buf->vb.height,
- buf->fmt->fourcc);
+ vbuf, vc->width,
+ vc->height,
+ vc->fmt->fourcc);
break;
case V4L2_PIX_FMT_GREY:
- memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height);
+ memcpy(vbuf, tmpbuf, vc->width * vc->height);
break;
case V4L2_PIX_FMT_JPEG:
case V4L2_PIX_FMT_MJPEG:
- buf->vb.size = jpgsize;
- memcpy(vbuf, tmpbuf, buf->vb.size);
+ buf->vb.v4l2_buf.length = jpgsize;
+ memcpy(vbuf, tmpbuf, jpgsize);
break;
case V4L2_PIX_FMT_YUV422P:
memcpy(vbuf, tmpbuf,
- buf->vb.width * buf->vb.height * 2);
+ vc->width * vc->height * 2);
break;
default:
- printk(KERN_DEBUG "s2255: unknown format?\n");
+ pr_info("s2255: unknown format?\n");
}
- channel->last_frame = -1;
+ vc->last_frame = -1;
} else {
- printk(KERN_ERR "s2255: =======no frame\n");
+ pr_err("s2255: =======no frame\n");
return;
-
}
- dprintk(2, "s2255fill at : Buffer 0x%08lx size= %d\n",
+ dprintk(dev, 2, "s2255fill at : Buffer 0x%08lx size= %d\n",
(unsigned long)vbuf, pos);
/* tell v4l buffer was filled */
-
- buf->vb.field_count = channel->frame_count * 2;
- v4l2_get_timestamp(&buf->vb.ts);
- buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.v4l2_buf.field = vc->field;
+ buf->vb.v4l2_buf.sequence = vc->frame_count;
+ v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
}
@@ -689,144 +661,82 @@ static void s2255_fillbuff(struct s2255_channel *channel,
Videobuf operations
------------------------------------------------------------------*/
-static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- struct s2255_fh *fh = vq->priv_data;
- struct s2255_channel *channel = fh->channel;
- *size = channel->width * channel->height * (channel->fmt->depth >> 3);
-
- if (0 == *count)
- *count = S2255_DEF_BUFS;
-
- if (*size * *count > vid_limit * 1024 * 1024)
- *count = (vid_limit * 1024 * 1024) / *size;
-
+ struct s2255_vc *vc = vb2_get_drv_priv(vq);
+ if (*nbuffers < S2255_MIN_BUFS)
+ *nbuffers = S2255_MIN_BUFS;
+ *nplanes = 1;
+ sizes[0] = vc->width * vc->height * (vc->fmt->depth >> 3);
return 0;
}
-static void free_buffer(struct videobuf_queue *vq, struct s2255_buffer *buf)
-{
- dprintk(4, "%s\n", __func__);
-
- videobuf_vmalloc_free(&buf->vb);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
- enum v4l2_field field)
+static int buffer_prepare(struct vb2_buffer *vb)
{
- struct s2255_fh *fh = vq->priv_data;
- struct s2255_channel *channel = fh->channel;
+ struct s2255_vc *vc = vb2_get_drv_priv(vb->vb2_queue);
struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
- int rc;
- int w = channel->width;
- int h = channel->height;
- dprintk(4, "%s, field=%d\n", __func__, field);
- if (channel->fmt == NULL)
+ int w = vc->width;
+ int h = vc->height;
+ unsigned long size;
+
+ dprintk(vc->dev, 4, "%s\n", __func__);
+ if (vc->fmt == NULL)
return -EINVAL;
- if ((w < norm_minw(channel)) ||
- (w > norm_maxw(channel)) ||
- (h < norm_minh(channel)) ||
- (h > norm_maxh(channel))) {
- dprintk(4, "invalid buffer prepare\n");
+ if ((w < norm_minw(vc)) ||
+ (w > norm_maxw(vc)) ||
+ (h < norm_minh(vc)) ||
+ (h > norm_maxh(vc))) {
+ dprintk(vc->dev, 4, "invalid buffer prepare\n");
return -EINVAL;
}
- buf->vb.size = w * h * (channel->fmt->depth >> 3);
- if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) {
- dprintk(4, "invalid buffer prepare\n");
+ size = w * h * (vc->fmt->depth >> 3);
+ if (vb2_plane_size(vb, 0) < size) {
+ dprintk(vc->dev, 4, "invalid buffer prepare\n");
return -EINVAL;
}
- buf->fmt = channel->fmt;
- buf->vb.width = w;
- buf->vb.height = h;
- buf->vb.field = field;
-
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- rc = videobuf_iolock(vq, &buf->vb, NULL);
- if (rc < 0)
- goto fail;
- }
-
- buf->vb.state = VIDEOBUF_PREPARED;
+ vb2_set_plane_payload(&buf->vb, 0, size);
return 0;
-fail:
- free_buffer(vq, buf);
- return rc;
}
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+static void buffer_queue(struct vb2_buffer *vb)
{
struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
- struct s2255_fh *fh = vq->priv_data;
- struct s2255_channel *channel = fh->channel;
- struct s2255_dmaqueue *vidq = &channel->vidq;
- dprintk(1, "%s\n", __func__);
- buf->vb.state = VIDEOBUF_QUEUED;
- list_add_tail(&buf->vb.queue, &vidq->active);
+ struct s2255_vc *vc = vb2_get_drv_priv(vb->vb2_queue);
+ unsigned long flags = 0;
+ dprintk(vc->dev, 1, "%s\n", __func__);
+ spin_lock_irqsave(&vc->qlock, flags);
+ list_add_tail(&buf->list, &vc->buf_list);
+ spin_unlock_irqrestore(&vc->qlock, flags);
}
-static void buffer_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
- struct s2255_fh *fh = vq->priv_data;
- dprintk(4, "%s %d\n", __func__, fh->channel->idx);
- free_buffer(vq, buf);
-}
+static int start_streaming(struct vb2_queue *vq, unsigned int count);
+static int stop_streaming(struct vb2_queue *vq);
-static struct videobuf_queue_ops s2255_video_qops = {
- .buf_setup = buffer_setup,
+static struct vb2_ops s2255_video_qops = {
+ .queue_setup = queue_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
- .buf_release = buffer_release,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
-
-static int res_get(struct s2255_fh *fh)
-{
- struct s2255_channel *channel = fh->channel;
- /* is it free? */
- if (channel->resources)
- return 0; /* no, someone else uses it */
- /* it's free, grab it */
- channel->resources = 1;
- fh->resources = 1;
- dprintk(1, "s2255: res: get\n");
- return 1;
-}
-
-static int res_locked(struct s2255_fh *fh)
-{
- return fh->channel->resources;
-}
-
-static int res_check(struct s2255_fh *fh)
-{
- return fh->resources;
-}
-
-
-static void res_free(struct s2255_fh *fh)
-{
- struct s2255_channel *channel = fh->channel;
- channel->resources = 0;
- fh->resources = 0;
- dprintk(1, "res: put\n");
-}
-
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct s2255_fh *fh = file->private_data;
- struct s2255_dev *dev = fh->dev;
+ struct s2255_vc *vc = video_drvdata(file);
+ struct s2255_dev *dev = vc->dev;
strlcpy(cap->driver, "s2255", sizeof(cap->driver));
strlcpy(cap->card, "s2255", sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -841,7 +751,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) ||
(formats[index].fourcc == V4L2_PIX_FMT_MJPEG)))
return -EINVAL;
- dprintk(4, "name %s\n", formats[index].name);
strlcpy(f->description, formats[index].name, sizeof(f->description));
f->pixelformat = formats[index].fourcc;
return 0;
@@ -850,19 +759,18 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
- int is_ntsc = channel->std & V4L2_STD_525_60;
+ struct s2255_vc *vc = video_drvdata(file);
+ int is_ntsc = vc->std & V4L2_STD_525_60;
- f->fmt.pix.width = channel->width;
- f->fmt.pix.height = channel->height;
+ f->fmt.pix.width = vc->width;
+ f->fmt.pix.height = vc->height;
if (f->fmt.pix.height >=
(is_ntsc ? NUM_LINES_1CIFS_NTSC : NUM_LINES_1CIFS_PAL) * 2)
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
else
f->fmt.pix.field = V4L2_FIELD_TOP;
- f->fmt.pix.pixelformat = channel->fmt->fourcc;
- f->fmt.pix.bytesperline = f->fmt.pix.width * (channel->fmt->depth >> 3);
+ f->fmt.pix.pixelformat = vc->fmt->fourcc;
+ f->fmt.pix.bytesperline = f->fmt.pix.width * (vc->fmt->depth >> 3);
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
f->fmt.pix.priv = 0;
@@ -874,9 +782,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
{
const struct s2255_fmt *fmt;
enum v4l2_field field;
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
- int is_ntsc = channel->std & V4L2_STD_525_60;
+ struct s2255_vc *vc = video_drvdata(file);
+ int is_ntsc = vc->std & V4L2_STD_525_60;
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
@@ -885,7 +792,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
field = f->fmt.pix.field;
- dprintk(50, "%s NTSC: %d suggested width: %d, height: %d\n",
+ dprintk(vc->dev, 50, "%s NTSC: %d suggested width: %d, height: %d\n",
__func__, is_ntsc, f->fmt.pix.width, f->fmt.pix.height);
if (is_ntsc) {
/* NTSC */
@@ -927,7 +834,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
f->fmt.pix.priv = 0;
- dprintk(50, "%s: set width %d height %d field %d\n", __func__,
+ dprintk(vc->dev, 50, "%s: set width %d height %d field %d\n", __func__,
f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
return 0;
}
@@ -935,14 +842,13 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
+ struct s2255_vc *vc = video_drvdata(file);
const struct s2255_fmt *fmt;
- struct videobuf_queue *q = &fh->vb_vidq;
+ struct vb2_queue *q = &vc->vb_vidq;
struct s2255_mode mode;
int ret;
- ret = vidioc_try_fmt_vid_cap(file, fh, f);
+ ret = vidioc_try_fmt_vid_cap(file, vc, f);
if (ret < 0)
return ret;
@@ -952,28 +858,19 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
if (fmt == NULL)
return -EINVAL;
- mutex_lock(&q->vb_lock);
-
- if (videobuf_queue_is_busy(&fh->vb_vidq)) {
- dprintk(1, "queue busy\n");
- ret = -EBUSY;
- goto out_s_fmt;
+ if (vb2_is_busy(q)) {
+ dprintk(vc->dev, 1, "queue busy\n");
+ return -EBUSY;
}
- if (res_locked(fh)) {
- dprintk(1, "%s: channel busy\n", __func__);
- ret = -EBUSY;
- goto out_s_fmt;
- }
- mode = channel->mode;
- channel->fmt = fmt;
- channel->width = f->fmt.pix.width;
- channel->height = f->fmt.pix.height;
- fh->vb_vidq.field = f->fmt.pix.field;
- fh->type = f->type;
- if (channel->width > norm_minw(channel)) {
- if (channel->height > norm_minh(channel)) {
- if (channel->cap_parm.capturemode &
+ mode = vc->mode;
+ vc->fmt = fmt;
+ vc->width = f->fmt.pix.width;
+ vc->height = f->fmt.pix.height;
+ vc->field = f->fmt.pix.field;
+ if (vc->width > norm_minw(vc)) {
+ if (vc->height > norm_minh(vc)) {
+ if (vc->cap_parm.capturemode &
V4L2_MODE_HIGHQUALITY)
mode.scale = SCALE_4CIFSI;
else
@@ -985,7 +882,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
mode.scale = SCALE_1CIFS;
}
/* color mode */
- switch (channel->fmt->fourcc) {
+ switch (vc->fmt->fourcc) {
case V4L2_PIX_FMT_GREY:
mode.color &= ~MASK_COLOR;
mode.color |= COLOR_Y8;
@@ -994,7 +891,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
case V4L2_PIX_FMT_MJPEG:
mode.color &= ~MASK_COLOR;
mode.color |= COLOR_JPG;
- mode.color |= (channel->jpegqual << 8);
+ mode.color |= (vc->jpegqual << 8);
break;
case V4L2_PIX_FMT_YUV422P:
mode.color &= ~MASK_COLOR;
@@ -1007,52 +904,17 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
mode.color |= COLOR_YUVPK;
break;
}
- if ((mode.color & MASK_COLOR) != (channel->mode.color & MASK_COLOR))
+ if ((mode.color & MASK_COLOR) != (vc->mode.color & MASK_COLOR))
mode.restart = 1;
- else if (mode.scale != channel->mode.scale)
+ else if (mode.scale != vc->mode.scale)
mode.restart = 1;
- else if (mode.format != channel->mode.format)
+ else if (mode.format != vc->mode.format)
mode.restart = 1;
- channel->mode = mode;
- (void) s2255_set_mode(channel, &mode);
- ret = 0;
-out_s_fmt:
- mutex_unlock(&q->vb_lock);
- return ret;
-}
-
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p)
-{
- int rc;
- struct s2255_fh *fh = priv;
- rc = videobuf_reqbufs(&fh->vb_vidq, p);
- return rc;
-}
-
-static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- int rc;
- struct s2255_fh *fh = priv;
- rc = videobuf_querybuf(&fh->vb_vidq, p);
- return rc;
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- int rc;
- struct s2255_fh *fh = priv;
- rc = videobuf_qbuf(&fh->vb_vidq, p);
- return rc;
+ vc->mode = mode;
+ (void) s2255_set_mode(vc, &mode);
+ return 0;
}
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- int rc;
- struct s2255_fh *fh = priv;
- rc = videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK);
- return rc;
-}
/* write to the configuration pipe, synchronously */
static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf,
@@ -1150,201 +1012,166 @@ static void s2255_print_cfg(struct s2255_dev *sdev, struct s2255_mode *mode)
* When the restart parameter is set, we sleep for ONE frame to allow the
* DSP time to get the new frame
*/
-static int s2255_set_mode(struct s2255_channel *channel,
+static int s2255_set_mode(struct s2255_vc *vc,
struct s2255_mode *mode)
{
int res;
- __le32 *buffer;
unsigned long chn_rev;
- struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+ struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
int i;
+ __le32 *buffer = dev->cmdbuf;
- chn_rev = G_chnmap[channel->idx];
- dprintk(3, "%s channel: %d\n", __func__, channel->idx);
+ mutex_lock(&dev->cmdlock);
+ chn_rev = G_chnmap[vc->idx];
+ dprintk(dev, 3, "%s channel: %d\n", __func__, vc->idx);
/* if JPEG, set the quality */
if ((mode->color & MASK_COLOR) == COLOR_JPG) {
mode->color &= ~MASK_COLOR;
mode->color |= COLOR_JPG;
mode->color &= ~MASK_JPG_QUALITY;
- mode->color |= (channel->jpegqual << 8);
+ mode->color |= (vc->jpegqual << 8);
}
/* save the mode */
- channel->mode = *mode;
- channel->req_image_size = get_transfer_size(mode);
- dprintk(1, "%s: reqsize %ld\n", __func__, channel->req_image_size);
- buffer = kzalloc(512, GFP_KERNEL);
- if (buffer == NULL) {
- dev_err(&dev->udev->dev, "out of mem\n");
- return -ENOMEM;
- }
+ vc->mode = *mode;
+ vc->req_image_size = get_transfer_size(mode);
+ dprintk(dev, 1, "%s: reqsize %ld\n", __func__, vc->req_image_size);
/* set the mode */
buffer[0] = IN_DATA_TOKEN;
buffer[1] = (__le32) cpu_to_le32(chn_rev);
buffer[2] = CMD_SET_MODE;
for (i = 0; i < sizeof(struct s2255_mode) / sizeof(u32); i++)
- buffer[3 + i] = cpu_to_le32(((u32 *)&channel->mode)[i]);
- channel->setmode_ready = 0;
+ buffer[3 + i] = cpu_to_le32(((u32 *)&vc->mode)[i]);
+ vc->setmode_ready = 0;
res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
if (debug)
s2255_print_cfg(dev, mode);
- kfree(buffer);
/* wait at least 3 frames before continuing */
if (mode->restart) {
- wait_event_timeout(channel->wait_setmode,
- (channel->setmode_ready != 0),
+ wait_event_timeout(vc->wait_setmode,
+ (vc->setmode_ready != 0),
msecs_to_jiffies(S2255_SETMODE_TIMEOUT));
- if (channel->setmode_ready != 1) {
- printk(KERN_DEBUG "s2255: no set mode response\n");
+ if (vc->setmode_ready != 1) {
+ dprintk(dev, 0, "s2255: no set mode response\n");
res = -EFAULT;
}
}
/* clear the restart flag */
- channel->mode.restart = 0;
- dprintk(1, "%s chn %d, result: %d\n", __func__, channel->idx, res);
+ vc->mode.restart = 0;
+ dprintk(dev, 1, "%s chn %d, result: %d\n", __func__, vc->idx, res);
+ mutex_unlock(&dev->cmdlock);
return res;
}
-static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus)
+static int s2255_cmd_status(struct s2255_vc *vc, u32 *pstatus)
{
int res;
- __le32 *buffer;
u32 chn_rev;
- struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
- chn_rev = G_chnmap[channel->idx];
- dprintk(4, "%s chan %d\n", __func__, channel->idx);
- buffer = kzalloc(512, GFP_KERNEL);
- if (buffer == NULL) {
- dev_err(&dev->udev->dev, "out of mem\n");
- return -ENOMEM;
- }
+ struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
+ __le32 *buffer = dev->cmdbuf;
+
+ mutex_lock(&dev->cmdlock);
+ chn_rev = G_chnmap[vc->idx];
+ dprintk(dev, 4, "%s chan %d\n", __func__, vc->idx);
/* form the get vid status command */
buffer[0] = IN_DATA_TOKEN;
buffer[1] = (__le32) cpu_to_le32(chn_rev);
buffer[2] = CMD_STATUS;
*pstatus = 0;
- channel->vidstatus_ready = 0;
+ vc->vidstatus_ready = 0;
res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
- kfree(buffer);
- wait_event_timeout(channel->wait_vidstatus,
- (channel->vidstatus_ready != 0),
+ wait_event_timeout(vc->wait_vidstatus,
+ (vc->vidstatus_ready != 0),
msecs_to_jiffies(S2255_VIDSTATUS_TIMEOUT));
- if (channel->vidstatus_ready != 1) {
- printk(KERN_DEBUG "s2255: no vidstatus response\n");
+ if (vc->vidstatus_ready != 1) {
+ dprintk(dev, 0, "s2255: no vidstatus response\n");
res = -EFAULT;
}
- *pstatus = channel->vidstatus;
- dprintk(4, "%s, vid status %d\n", __func__, *pstatus);
+ *pstatus = vc->vidstatus;
+ dprintk(dev, 4, "%s, vid status %d\n", __func__, *pstatus);
+ mutex_unlock(&dev->cmdlock);
return res;
}
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
{
- int res;
- struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
- struct s2255_channel *channel = fh->channel;
+ struct s2255_vc *vc = vb2_get_drv_priv(vq);
int j;
- dprintk(4, "%s\n", __func__);
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- dev_err(&dev->udev->dev, "invalid fh type0\n");
- return -EINVAL;
- }
- if (i != fh->type) {
- dev_err(&dev->udev->dev, "invalid fh type1\n");
- return -EINVAL;
- }
- if (!res_get(fh)) {
- s2255_dev_err(&dev->udev->dev, "stream busy\n");
- return -EBUSY;
- }
- channel->last_frame = -1;
- channel->bad_payload = 0;
- channel->cur_frame = 0;
- channel->frame_count = 0;
+ vc->last_frame = -1;
+ vc->bad_payload = 0;
+ vc->cur_frame = 0;
+ vc->frame_count = 0;
for (j = 0; j < SYS_FRAMES; j++) {
- channel->buffer.frame[j].ulState = S2255_READ_IDLE;
- channel->buffer.frame[j].cur_size = 0;
+ vc->buffer.frame[j].ulState = S2255_READ_IDLE;
+ vc->buffer.frame[j].cur_size = 0;
}
- res = videobuf_streamon(&fh->vb_vidq);
- if (res == 0) {
- s2255_start_acquire(channel);
- channel->b_acquire = 1;
- } else
- res_free(fh);
-
- return res;
+ return s2255_start_acquire(vc);
}
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+/* abort streaming and wait for last buffer */
+static int stop_streaming(struct vb2_queue *vq)
{
- struct s2255_fh *fh = priv;
- dprintk(4, "%s\n, channel: %d", __func__, fh->channel->idx);
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- printk(KERN_ERR "invalid fh type0\n");
- return -EINVAL;
+ struct s2255_vc *vc = vb2_get_drv_priv(vq);
+ struct s2255_buffer *buf, *node;
+ unsigned long flags;
+ (void) s2255_stop_acquire(vc);
+ spin_lock_irqsave(&vc->qlock, flags);
+ list_for_each_entry_safe(buf, node, &vc->buf_list, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ dprintk(vc->dev, 2, "[%p/%d] done\n",
+ buf, buf->vb.v4l2_buf.index);
}
- if (i != fh->type) {
- printk(KERN_ERR "invalid type i\n");
- return -EINVAL;
- }
- s2255_stop_acquire(fh->channel);
- videobuf_streamoff(&fh->vb_vidq);
- res_free(fh);
+ spin_unlock_irqrestore(&vc->qlock, flags);
return 0;
}
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id i)
{
- struct s2255_fh *fh = priv;
+ struct s2255_vc *vc = video_drvdata(file);
struct s2255_mode mode;
- struct videobuf_queue *q = &fh->vb_vidq;
- struct s2255_channel *channel = fh->channel;
- int ret = 0;
+ struct vb2_queue *q = &vc->vb_vidq;
- mutex_lock(&q->vb_lock);
- if (res_locked(fh)) {
- dprintk(1, "can't change standard after started\n");
- ret = -EBUSY;
- goto out_s_std;
- }
- mode = fh->channel->mode;
+ /*
+ * Changing the standard implies a format change, which is not allowed
+ * while buffers for use with streaming have already been allocated.
+ */
+ if (vb2_is_busy(q))
+ return -EBUSY;
+
+ mode = vc->mode;
if (i & V4L2_STD_525_60) {
- dprintk(4, "%s 60 Hz\n", __func__);
+ dprintk(vc->dev, 4, "%s 60 Hz\n", __func__);
/* if changing format, reset frame decimation/intervals */
if (mode.format != FORMAT_NTSC) {
mode.restart = 1;
mode.format = FORMAT_NTSC;
mode.fdec = FDEC_1;
- channel->width = LINE_SZ_4CIFS_NTSC;
- channel->height = NUM_LINES_4CIFS_NTSC * 2;
+ vc->width = LINE_SZ_4CIFS_NTSC;
+ vc->height = NUM_LINES_4CIFS_NTSC * 2;
}
} else if (i & V4L2_STD_625_50) {
- dprintk(4, "%s 50 Hz\n", __func__);
+ dprintk(vc->dev, 4, "%s 50 Hz\n", __func__);
if (mode.format != FORMAT_PAL) {
mode.restart = 1;
mode.format = FORMAT_PAL;
mode.fdec = FDEC_1;
- channel->width = LINE_SZ_4CIFS_PAL;
- channel->height = NUM_LINES_4CIFS_PAL * 2;
+ vc->width = LINE_SZ_4CIFS_PAL;
+ vc->height = NUM_LINES_4CIFS_PAL * 2;
}
- } else {
- ret = -EINVAL;
- goto out_s_std;
- }
- fh->channel->std = i;
+ } else
+ return -EINVAL;
+ vc->std = i;
if (mode.restart)
- s2255_set_mode(fh->channel, &mode);
-out_s_std:
- mutex_unlock(&q->vb_lock);
- return ret;
+ s2255_set_mode(vc, &mode);
+ return 0;
}
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *i)
{
- struct s2255_fh *fh = priv;
+ struct s2255_vc *vc = video_drvdata(file);
- *i = fh->channel->std;
+ *i = vc->std;
return 0;
}
@@ -1358,10 +1185,10 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *i)
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *inp)
{
- struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
- struct s2255_channel *channel = fh->channel;
+ struct s2255_vc *vc = video_drvdata(file);
+ struct s2255_dev *dev = vc->dev;
u32 status = 0;
+
if (inp->index != 0)
return -EINVAL;
inp->type = V4L2_INPUT_TYPE_CAMERA;
@@ -1369,8 +1196,9 @@ static int vidioc_enum_input(struct file *file, void *priv,
inp->status = 0;
if (dev->dsp_fw_ver >= S2255_MIN_DSP_STATUS) {
int rc;
- rc = s2255_cmd_status(fh->channel, &status);
- dprintk(4, "s2255_cmd_status rc: %d status %x\n", rc, status);
+ rc = s2255_cmd_status(vc, &status);
+ dprintk(dev, 4, "s2255_cmd_status rc: %d status %x\n",
+ rc, status);
if (rc == 0)
inp->status = (status & 0x01) ? 0
: V4L2_IN_ST_NO_SIGNAL;
@@ -1381,7 +1209,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
strlcpy(inp->name, "Composite", sizeof(inp->name));
break;
case 0x2257:
- strlcpy(inp->name, (channel->idx < 2) ? "Composite" : "S-Video",
+ strlcpy(inp->name, (vc->idx < 2) ? "Composite" : "S-Video",
sizeof(inp->name));
break;
}
@@ -1402,13 +1230,10 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
static int s2255_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct s2255_channel *channel =
- container_of(ctrl->handler, struct s2255_channel, hdl);
+ struct s2255_vc *vc =
+ container_of(ctrl->handler, struct s2255_vc, hdl);
struct s2255_mode mode;
-
- mode = channel->mode;
- dprintk(4, "%s\n", __func__);
-
+ mode = vc->mode;
/* update the mode to the corresponding value */
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
@@ -1428,7 +1253,7 @@ static int s2255_s_ctrl(struct v4l2_ctrl *ctrl)
mode.color |= !ctrl->val << 16;
break;
case V4L2_CID_JPEG_COMPRESSION_QUALITY:
- channel->jpegqual = ctrl->val;
+ vc->jpegqual = ctrl->val;
return 0;
default:
return -EINVAL;
@@ -1438,48 +1263,48 @@ static int s2255_s_ctrl(struct v4l2_ctrl *ctrl)
some V4L programs restart stream unnecessarily
after a s_crtl.
*/
- s2255_set_mode(channel, &mode);
+ s2255_set_mode(vc, &mode);
return 0;
}
static int vidioc_g_jpegcomp(struct file *file, void *priv,
struct v4l2_jpegcompression *jc)
{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
+ struct s2255_vc *vc = video_drvdata(file);
memset(jc, 0, sizeof(*jc));
- jc->quality = channel->jpegqual;
- dprintk(2, "%s: quality %d\n", __func__, jc->quality);
+ jc->quality = vc->jpegqual;
+ dprintk(vc->dev, 2, "%s: quality %d\n", __func__, jc->quality);
return 0;
}
static int vidioc_s_jpegcomp(struct file *file, void *priv,
const struct v4l2_jpegcompression *jc)
{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
+ struct s2255_vc *vc = video_drvdata(file);
+
if (jc->quality < 0 || jc->quality > 100)
return -EINVAL;
- v4l2_ctrl_s_ctrl(channel->jpegqual_ctrl, jc->quality);
- dprintk(2, "%s: quality %d\n", __func__, jc->quality);
+ v4l2_ctrl_s_ctrl(vc->jpegqual_ctrl, jc->quality);
+ dprintk(vc->dev, 2, "%s: quality %d\n", __func__, jc->quality);
return 0;
}
static int vidioc_g_parm(struct file *file, void *priv,
struct v4l2_streamparm *sp)
{
- struct s2255_fh *fh = priv;
__u32 def_num, def_dem;
- struct s2255_channel *channel = fh->channel;
+ struct s2255_vc *vc = video_drvdata(file);
+
if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
- sp->parm.capture.capturemode = channel->cap_parm.capturemode;
- def_num = (channel->mode.format == FORMAT_NTSC) ? 1001 : 1000;
- def_dem = (channel->mode.format == FORMAT_NTSC) ? 30000 : 25000;
+ sp->parm.capture.capturemode = vc->cap_parm.capturemode;
+ sp->parm.capture.readbuffers = S2255_MIN_BUFS;
+ def_num = (vc->mode.format == FORMAT_NTSC) ? 1001 : 1000;
+ def_dem = (vc->mode.format == FORMAT_NTSC) ? 30000 : 25000;
sp->parm.capture.timeperframe.denominator = def_dem;
- switch (channel->mode.fdec) {
+ switch (vc->mode.fdec) {
default:
case FDEC_1:
sp->parm.capture.timeperframe.numerator = def_num;
@@ -1494,7 +1319,8 @@ static int vidioc_g_parm(struct file *file, void *priv,
sp->parm.capture.timeperframe.numerator = def_num * 5;
break;
}
- dprintk(4, "%s capture mode, %d timeperframe %d/%d\n", __func__,
+ dprintk(vc->dev, 4, "%s capture mode, %d timeperframe %d/%d\n",
+ __func__,
sp->parm.capture.capturemode,
sp->parm.capture.timeperframe.numerator,
sp->parm.capture.timeperframe.denominator);
@@ -1504,17 +1330,16 @@ static int vidioc_g_parm(struct file *file, void *priv,
static int vidioc_s_parm(struct file *file, void *priv,
struct v4l2_streamparm *sp)
{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
+ struct s2255_vc *vc = video_drvdata(file);
struct s2255_mode mode;
int fdec = FDEC_1;
__u32 def_num, def_dem;
if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- mode = channel->mode;
+ mode = vc->mode;
/* high quality capture mode requires a stream restart */
- if (channel->cap_parm.capturemode
- != sp->parm.capture.capturemode && res_locked(fh))
+ if ((vc->cap_parm.capturemode != sp->parm.capture.capturemode)
+ && vb2_is_streaming(&vc->vb_vidq))
return -EBUSY;
def_num = (mode.format == FORMAT_NTSC) ? 1001 : 1000;
def_dem = (mode.format == FORMAT_NTSC) ? 30000 : 25000;
@@ -1534,8 +1359,9 @@ static int vidioc_s_parm(struct file *file, void *priv,
}
mode.fdec = fdec;
sp->parm.capture.timeperframe.denominator = def_dem;
- s2255_set_mode(channel, &mode);
- dprintk(4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n",
+ sp->parm.capture.readbuffers = S2255_MIN_BUFS;
+ s2255_set_mode(vc, &mode);
+ dprintk(vc->dev, 4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n",
__func__,
sp->parm.capture.capturemode,
sp->parm.capture.timeperframe.numerator,
@@ -1558,9 +1384,8 @@ static const struct v4l2_frmsize_discrete pal_sizes[] = {
static int vidioc_enum_framesizes(struct file *file, void *priv,
struct v4l2_frmsizeenum *fe)
{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
- int is_ntsc = channel->std & V4L2_STD_525_60;
+ struct s2255_vc *vc = video_drvdata(file);
+ int is_ntsc = vc->std & V4L2_STD_525_60;
const struct s2255_fmt *fmt;
if (fe->index >= NUM_SIZE_ENUMS)
@@ -1577,11 +1402,10 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
static int vidioc_enum_frameintervals(struct file *file, void *priv,
struct v4l2_frmivalenum *fe)
{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
+ struct s2255_vc *vc = video_drvdata(file);
const struct s2255_fmt *fmt;
const struct v4l2_frmsize_discrete *sizes;
- int is_ntsc = channel->std & V4L2_STD_525_60;
+ int is_ntsc = vc->std & V4L2_STD_525_60;
#define NUM_FRAME_ENUMS 4
int frm_dec[NUM_FRAME_ENUMS] = {1, 2, 3, 5};
int i;
@@ -1604,21 +1428,24 @@ static int vidioc_enum_frameintervals(struct file *file, void *priv,
fe->type = V4L2_FRMIVAL_TYPE_DISCRETE;
fe->discrete.denominator = is_ntsc ? 30000 : 25000;
fe->discrete.numerator = (is_ntsc ? 1001 : 1000) * frm_dec[fe->index];
- dprintk(4, "%s discrete %d/%d\n", __func__, fe->discrete.numerator,
+ dprintk(vc->dev, 4, "%s discrete %d/%d\n", __func__,
+ fe->discrete.numerator,
fe->discrete.denominator);
return 0;
}
-static int __s2255_open(struct file *file)
+static int s2255_open(struct file *file)
{
- struct video_device *vdev = video_devdata(file);
- struct s2255_channel *channel = video_drvdata(file);
- struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
- struct s2255_fh *fh;
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ struct s2255_vc *vc = video_drvdata(file);
+ struct s2255_dev *dev = vc->dev;
int state;
- dprintk(1, "s2255: open called (dev=%s)\n",
- video_device_node_name(vdev));
+ int rc = 0;
+
+ rc = v4l2_fh_open(file);
+ if (rc != 0)
+ return rc;
+
+ dprintk(dev, 1, "s2255: %s\n", __func__);
state = atomic_read(&dev->fw_data->fw_state);
switch (state) {
case S2255_FW_DISCONNECTING:
@@ -1640,7 +1467,7 @@ static int __s2255_open(struct file *file)
case S2255_FW_LOADED_DSPWAIT:
/* give S2255_LOAD_TIMEOUT time for firmware to load in case
driver loaded and then device immediately opened */
- printk(KERN_INFO "%s waiting for firmware load\n", __func__);
+ pr_info("%s waiting for firmware load\n", __func__);
wait_event_timeout(dev->fw_data->wait_fw,
((atomic_read(&dev->fw_data->fw_state)
== S2255_FW_SUCCESS) ||
@@ -1659,16 +1486,15 @@ static int __s2255_open(struct file *file)
case S2255_FW_SUCCESS:
break;
case S2255_FW_FAILED:
- printk(KERN_INFO "2255 firmware load failed.\n");
+ pr_info("2255 firmware load failed.\n");
return -ENODEV;
case S2255_FW_DISCONNECTING:
- printk(KERN_INFO "%s: disconnecting\n", __func__);
+ pr_info("%s: disconnecting\n", __func__);
return -ENODEV;
case S2255_FW_LOADED_DSPWAIT:
case S2255_FW_NOTLOADED:
- printk(KERN_INFO "%s: firmware not loaded yet"
- "please try again later\n",
- __func__);
+ pr_info("%s: firmware not loaded, please retry\n",
+ __func__);
/*
* Timeout on firmware load means device unusable.
* Set firmware failure state.
@@ -1678,71 +1504,21 @@ static int __s2255_open(struct file *file)
S2255_FW_FAILED);
return -EAGAIN;
default:
- printk(KERN_INFO "%s: unknown state\n", __func__);
+ pr_info("%s: unknown state\n", __func__);
return -EFAULT;
}
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh)
- return -ENOMEM;
- v4l2_fh_init(&fh->fh, vdev);
- v4l2_fh_add(&fh->fh);
- file->private_data = &fh->fh;
- fh->dev = dev;
- fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fh->channel = channel;
- if (!channel->configured) {
+ if (!vc->configured) {
/* configure channel to default state */
- channel->fmt = &formats[0];
- s2255_set_mode(channel, &channel->mode);
- channel->configured = 1;
- }
- dprintk(1, "%s: dev=%s type=%s\n", __func__,
- video_device_node_name(vdev), v4l2_type_names[type]);
- dprintk(2, "%s: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", __func__,
- (unsigned long)fh, (unsigned long)dev,
- (unsigned long)&channel->vidq);
- dprintk(4, "%s: list_empty active=%d\n", __func__,
- list_empty(&channel->vidq.active));
- videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops,
- NULL, &dev->slock,
- fh->type,
- V4L2_FIELD_INTERLACED,
- sizeof(struct s2255_buffer),
- fh, vdev->lock);
+ vc->fmt = &formats[0];
+ s2255_set_mode(vc, &vc->mode);
+ vc->configured = 1;
+ }
return 0;
}
-static int s2255_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- int ret;
-
- if (mutex_lock_interruptible(vdev->lock))
- return -ERESTARTSYS;
- ret = __s2255_open(file);
- mutex_unlock(vdev->lock);
- return ret;
-}
-
-static unsigned int s2255_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct s2255_fh *fh = file->private_data;
- struct s2255_dev *dev = fh->dev;
- int rc = v4l2_ctrl_poll(file, wait);
-
- dprintk(100, "%s\n", __func__);
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
- return POLLERR;
- mutex_lock(&dev->lock);
- rc |= videobuf_poll_stream(file, &fh->vb_vidq, wait);
- mutex_unlock(&dev->lock);
- return rc;
-}
-
static void s2255_destroy(struct s2255_dev *dev)
{
+ dprintk(dev, 1, "%s", __func__);
/* board shutdown stops the read pipe if it is running */
s2255_board_shutdown(dev);
/* make sure firmware still not trying to load */
@@ -1760,62 +1536,18 @@ static void s2255_destroy(struct s2255_dev *dev)
mutex_destroy(&dev->lock);
usb_put_dev(dev->udev);
v4l2_device_unregister(&dev->v4l2_dev);
- dprintk(1, "%s", __func__);
+ kfree(dev->cmdbuf);
kfree(dev);
}
-static int s2255_release(struct file *file)
-{
- struct s2255_fh *fh = file->private_data;
- struct s2255_dev *dev = fh->dev;
- struct video_device *vdev = video_devdata(file);
- struct s2255_channel *channel = fh->channel;
- if (!dev)
- return -ENODEV;
- mutex_lock(&dev->lock);
- /* turn off stream */
- if (res_check(fh)) {
- if (channel->b_acquire)
- s2255_stop_acquire(fh->channel);
- videobuf_streamoff(&fh->vb_vidq);
- res_free(fh);
- }
- videobuf_mmap_free(&fh->vb_vidq);
- mutex_unlock(&dev->lock);
- dprintk(1, "%s (dev=%s)\n", __func__, video_device_node_name(vdev));
- v4l2_fh_del(&fh->fh);
- v4l2_fh_exit(&fh->fh);
- kfree(fh);
- return 0;
-}
-
-static int s2255_mmap_v4l(struct file *file, struct vm_area_struct *vma)
-{
- struct s2255_fh *fh = file->private_data;
- struct s2255_dev *dev;
- int ret;
-
- if (!fh)
- return -ENODEV;
- dev = fh->dev;
- dprintk(4, "%s, vma=0x%08lx\n", __func__, (unsigned long)vma);
- if (mutex_lock_interruptible(&dev->lock))
- return -ERESTARTSYS;
- ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
- mutex_unlock(&dev->lock);
- dprintk(4, "%s vma start=0x%08lx, size=%ld, ret=%d\n", __func__,
- (unsigned long)vma->vm_start,
- (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
- return ret;
-}
-
static const struct v4l2_file_operations s2255_fops_v4l = {
.owner = THIS_MODULE,
.open = s2255_open,
- .release = s2255_release,
- .poll = s2255_poll,
+ .release = vb2_fop_release,
+ .poll = vb2_fop_poll,
.unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
- .mmap = s2255_mmap_v4l,
+ .mmap = vb2_fop_mmap,
+ .read = vb2_fop_read,
};
static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
@@ -1824,17 +1556,17 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
.vidioc_s_std = vidioc_s_std,
.vidioc_g_std = vidioc_g_std,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_s_jpegcomp = vidioc_s_jpegcomp,
.vidioc_g_jpegcomp = vidioc_g_jpegcomp,
.vidioc_s_parm = vidioc_s_parm,
@@ -1849,13 +1581,14 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
static void s2255_video_device_release(struct video_device *vdev)
{
struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
- struct s2255_channel *channel =
- container_of(vdev, struct s2255_channel, vdev);
+ struct s2255_vc *vc =
+ container_of(vdev, struct s2255_vc, vdev);
- v4l2_ctrl_handler_free(&channel->hdl);
- dprintk(4, "%s, chnls: %d\n", __func__,
+ dprintk(dev, 4, "%s, chnls: %d\n", __func__,
atomic_read(&dev->num_channels));
+ v4l2_ctrl_handler_free(&vc->hdl);
+
if (atomic_dec_and_test(&dev->num_channels))
s2255_destroy(dev);
return;
@@ -1888,52 +1621,70 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
int ret;
int i;
int cur_nr = video_nr;
- struct s2255_channel *channel;
+ struct s2255_vc *vc;
+ struct vb2_queue *q;
+
ret = v4l2_device_register(&dev->interface->dev, &dev->v4l2_dev);
if (ret)
return ret;
/* initialize all video 4 linux */
/* register 4 video devices */
for (i = 0; i < MAX_CHANNELS; i++) {
- channel = &dev->channel[i];
- INIT_LIST_HEAD(&channel->vidq.active);
+ vc = &dev->vc[i];
+ INIT_LIST_HEAD(&vc->buf_list);
- v4l2_ctrl_handler_init(&channel->hdl, 6);
- v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
+ v4l2_ctrl_handler_init(&vc->hdl, 6);
+ v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops,
V4L2_CID_BRIGHTNESS, -127, 127, 1, DEF_BRIGHT);
- v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
+ v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops,
V4L2_CID_CONTRAST, 0, 255, 1, DEF_CONTRAST);
- v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
+ v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops,
V4L2_CID_SATURATION, 0, 255, 1, DEF_SATURATION);
- v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
+ v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops,
V4L2_CID_HUE, 0, 255, 1, DEF_HUE);
- channel->jpegqual_ctrl = v4l2_ctrl_new_std(&channel->hdl,
+ vc->jpegqual_ctrl = v4l2_ctrl_new_std(&vc->hdl,
&s2255_ctrl_ops,
V4L2_CID_JPEG_COMPRESSION_QUALITY,
0, 100, 1, S2255_DEF_JPEG_QUAL);
if (dev->dsp_fw_ver >= S2255_MIN_DSP_COLORFILTER &&
- (dev->pid != 0x2257 || channel->idx <= 1))
- v4l2_ctrl_new_custom(&channel->hdl, &color_filter_ctrl, NULL);
- if (channel->hdl.error) {
- ret = channel->hdl.error;
- v4l2_ctrl_handler_free(&channel->hdl);
+ (dev->pid != 0x2257 || vc->idx <= 1))
+ v4l2_ctrl_new_custom(&vc->hdl, &color_filter_ctrl,
+ NULL);
+ if (vc->hdl.error) {
+ ret = vc->hdl.error;
+ v4l2_ctrl_handler_free(&vc->hdl);
dev_err(&dev->udev->dev, "couldn't register control\n");
break;
}
- channel->vidq.dev = dev;
- /* register 4 video devices */
- channel->vdev = template;
- channel->vdev.ctrl_handler = &channel->hdl;
- channel->vdev.lock = &dev->lock;
- channel->vdev.v4l2_dev = &dev->v4l2_dev;
- set_bit(V4L2_FL_USE_FH_PRIO, &channel->vdev.flags);
- video_set_drvdata(&channel->vdev, channel);
+ q = &vc->vb_vidq;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_READ | VB2_USERPTR;
+ q->drv_priv = vc;
+ q->lock = &vc->vb_lock;
+ q->buf_struct_size = sizeof(struct s2255_buffer);
+ q->mem_ops = &vb2_vmalloc_memops;
+ q->ops = &s2255_video_qops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ ret = vb2_queue_init(q);
+ if (ret != 0) {
+ dev_err(&dev->udev->dev,
+ "%s vb2_queue_init 0x%x\n", __func__, ret);
+ break;
+ }
+ /* register video devices */
+ vc->vdev = template;
+ vc->vdev.queue = q;
+ vc->vdev.ctrl_handler = &vc->hdl;
+ vc->vdev.lock = &dev->lock;
+ vc->vdev.v4l2_dev = &dev->v4l2_dev;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vc->vdev.flags);
+ video_set_drvdata(&vc->vdev, vc);
if (video_nr == -1)
- ret = video_register_device(&channel->vdev,
+ ret = video_register_device(&vc->vdev,
VFL_TYPE_GRABBER,
video_nr);
else
- ret = video_register_device(&channel->vdev,
+ ret = video_register_device(&vc->vdev,
VFL_TYPE_GRABBER,
cur_nr + i);
@@ -1944,18 +1695,18 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
}
atomic_inc(&dev->num_channels);
v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
- video_device_node_name(&channel->vdev));
+ video_device_node_name(&vc->vdev));
}
- printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %s\n",
- S2255_VERSION);
+ pr_info("Sensoray 2255 V4L driver Revision: %s\n",
+ S2255_VERSION);
/* if no channels registered, return error and probe will fail*/
if (atomic_read(&dev->num_channels) == 0) {
v4l2_device_unregister(&dev->v4l2_dev);
return ret;
}
if (atomic_read(&dev->num_channels) != MAX_CHANNELS)
- printk(KERN_WARNING "s2255: Not all channels available.\n");
+ pr_warn("s2255: Not all channels available.\n");
return 0;
}
@@ -1981,11 +1732,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
s32 idx = -1;
struct s2255_framei *frm;
unsigned char *pdata;
- struct s2255_channel *channel;
- dprintk(100, "buffer to user\n");
- channel = &dev->channel[dev->cc];
- idx = channel->cur_frame;
- frm = &channel->buffer.frame[idx];
+ struct s2255_vc *vc;
+ dprintk(dev, 100, "buffer to user\n");
+ vc = &dev->vc[dev->cc];
+ idx = vc->cur_frame;
+ frm = &vc->buffer.frame[idx];
if (frm->ulState == S2255_READ_IDLE) {
int jj;
unsigned int cc;
@@ -1997,28 +1748,27 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
for (jj = 0; jj < (pipe_info->cur_transfer_size - 12); jj++) {
switch (*pdword) {
case S2255_MARKER_FRAME:
- dprintk(4, "found frame marker at offset:"
- " %d [%x %x]\n", jj, pdata[0],
- pdata[1]);
+ dprintk(dev, 4, "marker @ offset: %d [%x %x]\n",
+ jj, pdata[0], pdata[1]);
offset = jj + PREFIX_SIZE;
bframe = 1;
cc = le32_to_cpu(pdword[1]);
if (cc >= MAX_CHANNELS) {
- printk(KERN_ERR
- "bad channel\n");
+ dprintk(dev, 0,
+ "bad channel\n");
return -EINVAL;
}
/* reverse it */
dev->cc = G_chnmap[cc];
- channel = &dev->channel[dev->cc];
+ vc = &dev->vc[dev->cc];
payload = le32_to_cpu(pdword[3]);
- if (payload > channel->req_image_size) {
- channel->bad_payload++;
+ if (payload > vc->req_image_size) {
+ vc->bad_payload++;
/* discard the bad frame */
return -EINVAL;
}
- channel->pkt_size = payload;
- channel->jpg_size = le32_to_cpu(pdword[4]);
+ vc->pkt_size = payload;
+ vc->jpg_size = le32_to_cpu(pdword[4]);
break;
case S2255_MARKER_RESPONSE:
@@ -2029,34 +1779,34 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
cc = G_chnmap[le32_to_cpu(pdword[1])];
if (cc >= MAX_CHANNELS)
break;
- channel = &dev->channel[cc];
+ vc = &dev->vc[cc];
switch (pdword[2]) {
case S2255_RESPONSE_SETMODE:
/* check if channel valid */
/* set mode ready */
- channel->setmode_ready = 1;
- wake_up(&channel->wait_setmode);
- dprintk(5, "setmode ready %d\n", cc);
+ vc->setmode_ready = 1;
+ wake_up(&vc->wait_setmode);
+ dprintk(dev, 5, "setmode rdy %d\n", cc);
break;
case S2255_RESPONSE_FW:
dev->chn_ready |= (1 << cc);
if ((dev->chn_ready & 0x0f) != 0x0f)
break;
/* all channels ready */
- printk(KERN_INFO "s2255: fw loaded\n");
+ pr_info("s2255: fw loaded\n");
atomic_set(&dev->fw_data->fw_state,
S2255_FW_SUCCESS);
wake_up(&dev->fw_data->wait_fw);
break;
case S2255_RESPONSE_STATUS:
- channel->vidstatus = le32_to_cpu(pdword[3]);
- channel->vidstatus_ready = 1;
- wake_up(&channel->wait_vidstatus);
- dprintk(5, "got vidstatus %x chan %d\n",
+ vc->vidstatus = le32_to_cpu(pdword[3]);
+ vc->vidstatus_ready = 1;
+ wake_up(&vc->wait_vidstatus);
+ dprintk(dev, 5, "vstat %x chan %d\n",
le32_to_cpu(pdword[3]), cc);
break;
default:
- printk(KERN_INFO "s2255 unknown resp\n");
+ pr_info("s2255 unknown resp\n");
}
default:
pdata++;
@@ -2068,11 +1818,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
if (!bframe)
return -EINVAL;
}
- channel = &dev->channel[dev->cc];
- idx = channel->cur_frame;
- frm = &channel->buffer.frame[idx];
+ vc = &dev->vc[dev->cc];
+ idx = vc->cur_frame;
+ frm = &vc->buffer.frame[idx];
/* search done. now find out if should be acquiring on this channel */
- if (!channel->b_acquire) {
+ if (!vb2_is_streaming(&vc->vb_vidq)) {
/* we found a frame, but this channel is turned off */
frm->ulState = S2255_READ_IDLE;
return -EINVAL;
@@ -2088,7 +1838,7 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
if (frm->lpvbits == NULL) {
- dprintk(1, "s2255 frame buffer == NULL.%p %p %d %d",
+ dprintk(dev, 1, "s2255 frame buffer == NULL.%p %p %d %d",
frm, dev, dev->cc, idx);
return -ENOMEM;
}
@@ -2097,28 +1847,28 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
copy_size = (pipe_info->cur_transfer_size - offset);
- size = channel->pkt_size - PREFIX_SIZE;
+ size = vc->pkt_size - PREFIX_SIZE;
/* sanity check on pdest */
- if ((copy_size + frm->cur_size) < channel->req_image_size)
+ if ((copy_size + frm->cur_size) < vc->req_image_size)
memcpy(pdest, psrc, copy_size);
frm->cur_size += copy_size;
- dprintk(4, "cur_size size %lu size %lu \n", frm->cur_size, size);
+ dprintk(dev, 4, "cur_size: %lu, size: %lu\n", frm->cur_size, size);
if (frm->cur_size >= size) {
- dprintk(2, "****************[%d]Buffer[%d]full*************\n",
+ dprintk(dev, 2, "******[%d]Buffer[%d]full*******\n",
dev->cc, idx);
- channel->last_frame = channel->cur_frame;
- channel->cur_frame++;
+ vc->last_frame = vc->cur_frame;
+ vc->cur_frame++;
/* end of system frame ring buffer, start at zero */
- if ((channel->cur_frame == SYS_FRAMES) ||
- (channel->cur_frame == channel->buffer.dwFrames))
- channel->cur_frame = 0;
+ if ((vc->cur_frame == SYS_FRAMES) ||
+ (vc->cur_frame == vc->buffer.dwFrames))
+ vc->cur_frame = 0;
/* frame ready */
- if (channel->b_acquire)
- s2255_got_frame(channel, channel->jpg_size);
- channel->frame_count++;
+ if (vb2_is_streaming(&vc->vb_vidq))
+ s2255_got_frame(vc, vc->jpg_size);
+ vc->frame_count++;
frm->ulState = S2255_READ_IDLE;
frm->cur_size = 0;
@@ -2131,7 +1881,7 @@ static void s2255_read_video_callback(struct s2255_dev *dev,
struct s2255_pipeinfo *pipe_info)
{
int res;
- dprintk(50, "callback read video \n");
+ dprintk(dev, 50, "callback read video\n");
if (dev->cc >= MAX_CHANNELS) {
dev->cc = 0;
@@ -2141,9 +1891,9 @@ static void s2255_read_video_callback(struct s2255_dev *dev,
/* otherwise copy to the system buffers */
res = save_frame(dev, pipe_info);
if (res != 0)
- dprintk(4, "s2255: read callback failed\n");
+ dprintk(dev, 4, "s2255: read callback failed\n");
- dprintk(50, "callback read video done\n");
+ dprintk(dev, 50, "callback read video done\n");
return;
}
@@ -2181,9 +1931,9 @@ static int s2255_get_fx2fw(struct s2255_dev *dev)
ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, transBuffer, 2,
S2255_VR_IN);
if (ret < 0)
- dprintk(2, "get fw error: %x\n", ret);
+ dprintk(dev, 2, "get fw error: %x\n", ret);
fw = transBuffer[0] + (transBuffer[1] << 8);
- dprintk(2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]);
+ dprintk(dev, 2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]);
return fw;
}
@@ -2191,12 +1941,11 @@ static int s2255_get_fx2fw(struct s2255_dev *dev)
* Create the system ring buffer to copy frames into from the
* usb read pipe.
*/
-static int s2255_create_sys_buffers(struct s2255_channel *channel)
+static int s2255_create_sys_buffers(struct s2255_vc *vc)
{
unsigned long i;
unsigned long reqsize;
- dprintk(1, "create sys buffers\n");
- channel->buffer.dwFrames = SYS_FRAMES;
+ vc->buffer.dwFrames = SYS_FRAMES;
/* always allocate maximum size(PAL) for system buffers */
reqsize = SYS_FRAMES_MAXSIZE;
@@ -2205,40 +1954,33 @@ static int s2255_create_sys_buffers(struct s2255_channel *channel)
for (i = 0; i < SYS_FRAMES; i++) {
/* allocate the frames */
- channel->buffer.frame[i].lpvbits = vmalloc(reqsize);
- dprintk(1, "valloc %p chan %d, idx %lu, pdata %p\n",
- &channel->buffer.frame[i], channel->idx, i,
- channel->buffer.frame[i].lpvbits);
- channel->buffer.frame[i].size = reqsize;
- if (channel->buffer.frame[i].lpvbits == NULL) {
- printk(KERN_INFO "out of memory. using less frames\n");
- channel->buffer.dwFrames = i;
+ vc->buffer.frame[i].lpvbits = vmalloc(reqsize);
+ vc->buffer.frame[i].size = reqsize;
+ if (vc->buffer.frame[i].lpvbits == NULL) {
+ pr_info("out of memory. using less frames\n");
+ vc->buffer.dwFrames = i;
break;
}
}
/* make sure internal states are set */
for (i = 0; i < SYS_FRAMES; i++) {
- channel->buffer.frame[i].ulState = 0;
- channel->buffer.frame[i].cur_size = 0;
+ vc->buffer.frame[i].ulState = 0;
+ vc->buffer.frame[i].cur_size = 0;
}
- channel->cur_frame = 0;
- channel->last_frame = -1;
+ vc->cur_frame = 0;
+ vc->last_frame = -1;
return 0;
}
-static int s2255_release_sys_buffers(struct s2255_channel *channel)
+static int s2255_release_sys_buffers(struct s2255_vc *vc)
{
unsigned long i;
- dprintk(1, "release sys buffers\n");
for (i = 0; i < SYS_FRAMES; i++) {
- if (channel->buffer.frame[i].lpvbits) {
- dprintk(1, "vfree %p\n",
- channel->buffer.frame[i].lpvbits);
- vfree(channel->buffer.frame[i].lpvbits);
- }
- channel->buffer.frame[i].lpvbits = NULL;
+ if (vc->buffer.frame[i].lpvbits)
+ vfree(vc->buffer.frame[i].lpvbits);
+ vc->buffer.frame[i].lpvbits = NULL;
}
return 0;
}
@@ -2249,7 +1991,7 @@ static int s2255_board_init(struct s2255_dev *dev)
int fw_ver;
int j;
struct s2255_pipeinfo *pipe = &dev->pipe;
- dprintk(4, "board init: %p", dev);
+ dprintk(dev, 4, "board init: %p", dev);
memset(pipe, 0, sizeof(*pipe));
pipe->dev = dev;
pipe->cur_transfer_size = S2255_USB_XFER_SIZE;
@@ -2258,54 +2000,53 @@ static int s2255_board_init(struct s2255_dev *dev)
pipe->transfer_buffer = kzalloc(pipe->max_transfer_size,
GFP_KERNEL);
if (pipe->transfer_buffer == NULL) {
- dprintk(1, "out of memory!\n");
+ dprintk(dev, 1, "out of memory!\n");
return -ENOMEM;
}
/* query the firmware */
fw_ver = s2255_get_fx2fw(dev);
- printk(KERN_INFO "s2255: usb firmware version %d.%d\n",
- (fw_ver >> 8) & 0xff,
- fw_ver & 0xff);
+ pr_info("s2255: usb firmware version %d.%d\n",
+ (fw_ver >> 8) & 0xff,
+ fw_ver & 0xff);
if (fw_ver < S2255_CUR_USB_FWVER)
- printk(KERN_INFO "s2255: newer USB firmware available\n");
+ pr_info("s2255: newer USB firmware available\n");
for (j = 0; j < MAX_CHANNELS; j++) {
- struct s2255_channel *channel = &dev->channel[j];
- channel->b_acquire = 0;
- channel->mode = mode_def;
+ struct s2255_vc *vc = &dev->vc[j];
+ vc->mode = mode_def;
if (dev->pid == 0x2257 && j > 1)
- channel->mode.color |= (1 << 16);
- channel->jpegqual = S2255_DEF_JPEG_QUAL;
- channel->width = LINE_SZ_4CIFS_NTSC;
- channel->height = NUM_LINES_4CIFS_NTSC * 2;
- channel->std = V4L2_STD_NTSC_M;
- channel->fmt = &formats[0];
- channel->mode.restart = 1;
- channel->req_image_size = get_transfer_size(&mode_def);
- channel->frame_count = 0;
+ vc->mode.color |= (1 << 16);
+ vc->jpegqual = S2255_DEF_JPEG_QUAL;
+ vc->width = LINE_SZ_4CIFS_NTSC;
+ vc->height = NUM_LINES_4CIFS_NTSC * 2;
+ vc->std = V4L2_STD_NTSC_M;
+ vc->fmt = &formats[0];
+ vc->mode.restart = 1;
+ vc->req_image_size = get_transfer_size(&mode_def);
+ vc->frame_count = 0;
/* create the system buffers */
- s2255_create_sys_buffers(channel);
+ s2255_create_sys_buffers(vc);
}
/* start read pipe */
s2255_start_readpipe(dev);
- dprintk(1, "%s: success\n", __func__);
+ dprintk(dev, 1, "%s: success\n", __func__);
return 0;
}
static int s2255_board_shutdown(struct s2255_dev *dev)
{
u32 i;
- dprintk(1, "%s: dev: %p", __func__, dev);
+ dprintk(dev, 1, "%s: dev: %p", __func__, dev);
for (i = 0; i < MAX_CHANNELS; i++) {
- if (dev->channel[i].b_acquire)
- s2255_stop_acquire(&dev->channel[i]);
+ if (vb2_is_streaming(&dev->vc[i].vb_vidq))
+ s2255_stop_acquire(&dev->vc[i]);
}
s2255_stop_readpipe(dev);
for (i = 0; i < MAX_CHANNELS; i++)
- s2255_release_sys_buffers(&dev->channel[i]);
+ s2255_release_sys_buffers(&dev->vc[i]);
/* release transfer buffer */
kfree(dev->pipe.transfer_buffer);
return 0;
@@ -2318,13 +2059,10 @@ static void read_pipe_completion(struct urb *purb)
int status;
int pipe;
pipe_info = purb->context;
- dprintk(100, "%s: urb:%p, status %d\n", __func__, purb,
- purb->status);
if (pipe_info == NULL) {
dev_err(&purb->dev->dev, "no context!\n");
return;
}
-
dev = pipe_info->dev;
if (dev == NULL) {
dev_err(&purb->dev->dev, "no context!\n");
@@ -2333,13 +2071,13 @@ static void read_pipe_completion(struct urb *purb)
status = purb->status;
/* if shutting down, do not resubmit, exit immediately */
if (status == -ESHUTDOWN) {
- dprintk(2, "%s: err shutdown\n", __func__);
+ dprintk(dev, 2, "%s: err shutdown\n", __func__);
pipe_info->err_count++;
return;
}
if (pipe_info->state == 0) {
- dprintk(2, "%s: exiting USB pipe", __func__);
+ dprintk(dev, 2, "%s: exiting USB pipe", __func__);
return;
}
@@ -2347,7 +2085,7 @@ static void read_pipe_completion(struct urb *purb)
s2255_read_video_callback(dev, pipe_info);
else {
pipe_info->err_count++;
- dprintk(1, "%s: failed URB %d\n", __func__, status);
+ dprintk(dev, 1, "%s: failed URB %d\n", __func__, status);
}
pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint);
@@ -2359,11 +2097,10 @@ static void read_pipe_completion(struct urb *purb)
read_pipe_completion, pipe_info);
if (pipe_info->state != 0) {
- if (usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC)) {
+ if (usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC))
dev_err(&dev->udev->dev, "error submitting urb\n");
- }
} else {
- dprintk(2, "%s :complete state 0\n", __func__);
+ dprintk(dev, 2, "%s :complete state 0\n", __func__);
}
return;
}
@@ -2374,7 +2111,7 @@ static int s2255_start_readpipe(struct s2255_dev *dev)
int retval;
struct s2255_pipeinfo *pipe_info = &dev->pipe;
pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint);
- dprintk(2, "%s: IN %d\n", __func__, dev->read_endpoint);
+ dprintk(dev, 2, "%s: IN %d\n", __func__, dev->read_endpoint);
pipe_info->state = 1;
pipe_info->err_count = 0;
pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -2391,70 +2128,64 @@ static int s2255_start_readpipe(struct s2255_dev *dev)
read_pipe_completion, pipe_info);
retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
if (retval) {
- printk(KERN_ERR "s2255: start read pipe failed\n");
+ pr_err("s2255: start read pipe failed\n");
return retval;
}
return 0;
}
/* starts acquisition process */
-static int s2255_start_acquire(struct s2255_channel *channel)
+static int s2255_start_acquire(struct s2255_vc *vc)
{
- unsigned char *buffer;
int res;
unsigned long chn_rev;
int j;
- struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
- chn_rev = G_chnmap[channel->idx];
- buffer = kzalloc(512, GFP_KERNEL);
- if (buffer == NULL) {
- dev_err(&dev->udev->dev, "out of mem\n");
- return -ENOMEM;
- }
-
- channel->last_frame = -1;
- channel->bad_payload = 0;
- channel->cur_frame = 0;
+ struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
+ __le32 *buffer = dev->cmdbuf;
+
+ mutex_lock(&dev->cmdlock);
+ chn_rev = G_chnmap[vc->idx];
+ vc->last_frame = -1;
+ vc->bad_payload = 0;
+ vc->cur_frame = 0;
for (j = 0; j < SYS_FRAMES; j++) {
- channel->buffer.frame[j].ulState = 0;
- channel->buffer.frame[j].cur_size = 0;
+ vc->buffer.frame[j].ulState = 0;
+ vc->buffer.frame[j].cur_size = 0;
}
/* send the start command */
- *(__le32 *) buffer = IN_DATA_TOKEN;
- *((__le32 *) buffer + 1) = (__le32) cpu_to_le32(chn_rev);
- *((__le32 *) buffer + 2) = CMD_START;
+ buffer[0] = IN_DATA_TOKEN;
+ buffer[1] = (__le32) cpu_to_le32(chn_rev);
+ buffer[2] = CMD_START;
res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
if (res != 0)
dev_err(&dev->udev->dev, "CMD_START error\n");
- dprintk(2, "start acquire exit[%d] %d \n", channel->idx, res);
- kfree(buffer);
- return 0;
+ dprintk(dev, 2, "start acquire exit[%d] %d\n", vc->idx, res);
+ mutex_unlock(&dev->cmdlock);
+ return res;
}
-static int s2255_stop_acquire(struct s2255_channel *channel)
+static int s2255_stop_acquire(struct s2255_vc *vc)
{
- unsigned char *buffer;
int res;
unsigned long chn_rev;
- struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
- chn_rev = G_chnmap[channel->idx];
- buffer = kzalloc(512, GFP_KERNEL);
- if (buffer == NULL) {
- dev_err(&dev->udev->dev, "out of mem\n");
- return -ENOMEM;
- }
+ struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
+ __le32 *buffer = dev->cmdbuf;
+
+ mutex_lock(&dev->cmdlock);
+ chn_rev = G_chnmap[vc->idx];
/* send the stop command */
- *(__le32 *) buffer = IN_DATA_TOKEN;
- *((__le32 *) buffer + 1) = (__le32) cpu_to_le32(chn_rev);
- *((__le32 *) buffer + 2) = CMD_STOP;
+ buffer[0] = IN_DATA_TOKEN;
+ buffer[1] = (__le32) cpu_to_le32(chn_rev);
+ buffer[2] = CMD_STOP;
+
res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
if (res != 0)
dev_err(&dev->udev->dev, "CMD_STOP error\n");
- kfree(buffer);
- channel->b_acquire = 0;
- dprintk(4, "%s: chn %d, res %d\n", __func__, channel->idx, res);
+
+ dprintk(dev, 4, "%s: chn %d, res %d\n", __func__, vc->idx, res);
+ mutex_unlock(&dev->cmdlock);
return res;
}
@@ -2469,7 +2200,7 @@ static void s2255_stop_readpipe(struct s2255_dev *dev)
usb_free_urb(pipe->stream_urb);
pipe->stream_urb = NULL;
}
- dprintk(4, "%s", __func__);
+ dprintk(dev, 4, "%s", __func__);
return;
}
@@ -2501,19 +2232,27 @@ static int s2255_probe(struct usb_interface *interface,
int retval = -ENOMEM;
__le32 *pdata;
int fw_size;
- dprintk(2, "%s\n", __func__);
+
/* allocate memory for our device state and initialize it to zero */
dev = kzalloc(sizeof(struct s2255_dev), GFP_KERNEL);
if (dev == NULL) {
s2255_dev_err(&interface->dev, "out of memory\n");
return -ENOMEM;
}
+
+ dev->cmdbuf = kzalloc(S2255_CMDBUF_SIZE, GFP_KERNEL);
+ if (dev->cmdbuf == NULL) {
+ s2255_dev_err(&interface->dev, "out of memory\n");
+ return -ENOMEM;
+ }
+
atomic_set(&dev->num_channels, 0);
dev->pid = le16_to_cpu(id->idProduct);
dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL);
if (!dev->fw_data)
goto errorFWDATA1;
mutex_init(&dev->lock);
+ mutex_init(&dev->cmdlock);
/* grab usb_device and save it */
dev->udev = usb_get_dev(interface_to_usbdev(interface));
if (dev->udev == NULL) {
@@ -2521,12 +2260,13 @@ static int s2255_probe(struct usb_interface *interface,
retval = -ENODEV;
goto errorUDEV;
}
- dprintk(1, "dev: %p, udev %p interface %p\n", dev,
- dev->udev, interface);
+ dev_dbg(&interface->dev, "dev: %p, udev %p interface %p\n",
+ dev, dev->udev, interface);
dev->interface = interface;
/* set up the endpoint information */
iface_desc = interface->cur_altsetting;
- dprintk(1, "num endpoints %d\n", iface_desc->desc.bNumEndpoints);
+ dev_dbg(&interface->dev, "num EP: %d\n",
+ iface_desc->desc.bNumEndpoints);
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
if (!dev->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) {
@@ -2544,10 +2284,13 @@ static int s2255_probe(struct usb_interface *interface,
dev->timer.data = (unsigned long)dev->fw_data;
init_waitqueue_head(&dev->fw_data->wait_fw);
for (i = 0; i < MAX_CHANNELS; i++) {
- struct s2255_channel *channel = &dev->channel[i];
- dev->channel[i].idx = i;
- init_waitqueue_head(&channel->wait_setmode);
- init_waitqueue_head(&channel->wait_vidstatus);
+ struct s2255_vc *vc = &dev->vc[i];
+ vc->idx = i;
+ vc->dev = dev;
+ init_waitqueue_head(&vc->wait_setmode);
+ init_waitqueue_head(&vc->wait_vidstatus);
+ spin_lock_init(&vc->qlock);
+ mutex_init(&vc->vb_lock);
}
dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -2564,7 +2307,7 @@ static int s2255_probe(struct usb_interface *interface,
/* load the first chunk */
if (request_firmware(&dev->fw_data->fw,
FIRMWARE_FILE_NAME, &dev->udev->dev)) {
- printk(KERN_ERR "sensoray 2255 failed to get firmware\n");
+ dev_err(&interface->dev, "sensoray 2255 failed to get firmware\n");
goto errorREQFW;
}
/* check the firmware is valid */
@@ -2572,28 +2315,27 @@ static int s2255_probe(struct usb_interface *interface,
pdata = (__le32 *) &dev->fw_data->fw->data[fw_size - 8];
if (*pdata != S2255_FW_MARKER) {
- printk(KERN_INFO "Firmware invalid.\n");
+ dev_err(&interface->dev, "Firmware invalid.\n");
retval = -ENODEV;
goto errorFWMARKER;
} else {
/* make sure firmware is the latest */
__le32 *pRel;
pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4];
- printk(KERN_INFO "s2255 dsp fw version %x\n", le32_to_cpu(*pRel));
+ pr_info("s2255 dsp fw version %x\n", le32_to_cpu(*pRel));
dev->dsp_fw_ver = le32_to_cpu(*pRel);
if (dev->dsp_fw_ver < S2255_CUR_DSP_FWVER)
- printk(KERN_INFO "s2255: f2255usb.bin out of date.\n");
+ pr_info("s2255: f2255usb.bin out of date.\n");
if (dev->pid == 0x2257 &&
dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
- printk(KERN_WARNING "s2255: 2257 requires firmware %d"
- " or above.\n", S2255_MIN_DSP_COLORFILTER);
+ pr_warn("2257 needs firmware %d or above.\n",
+ S2255_MIN_DSP_COLORFILTER);
}
usb_reset_device(dev->udev);
/* load 2255 board specific */
retval = s2255_board_init(dev);
if (retval)
goto errorBOARDINIT;
- spin_lock_init(&dev->slock);
s2255_fwload_start(dev, 0);
/* loads v4l specific */
retval = s2255_probe_v4l(dev);
@@ -2617,8 +2359,9 @@ errorUDEV:
kfree(dev->fw_data);
mutex_destroy(&dev->lock);
errorFWDATA1:
+ kfree(dev->cmdbuf);
kfree(dev);
- printk(KERN_WARNING "Sensoray 2255 driver load failed: 0x%x\n", retval);
+ pr_warn("Sensoray 2255 driver load failed: 0x%x\n", retval);
return retval;
}
@@ -2635,15 +2378,15 @@ static void s2255_disconnect(struct usb_interface *interface)
atomic_inc(&dev->num_channels);
/* unregister each video device. */
for (i = 0; i < channels; i++)
- video_unregister_device(&dev->channel[i].vdev);
+ video_unregister_device(&dev->vc[i].vdev);
/* wake up any of our timers */
atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
wake_up(&dev->fw_data->wait_fw);
for (i = 0; i < MAX_CHANNELS; i++) {
- dev->channel[i].setmode_ready = 1;
- wake_up(&dev->channel[i].wait_setmode);
- dev->channel[i].vidstatus_ready = 1;
- wake_up(&dev->channel[i].wait_vidstatus);
+ dev->vc[i].setmode_ready = 1;
+ wake_up(&dev->vc[i].wait_setmode);
+ dev->vc[i].vidstatus_ready = 1;
+ wake_up(&dev->vc[i].wait_vidstatus);
}
if (atomic_dec_and_test(&dev->num_channels))
s2255_destroy(dev);
diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c
index 05bd91a60c09..1836a416d806 100644
--- a/drivers/media/usb/siano/smsusb.c
+++ b/drivers/media/usb/siano/smsusb.c
@@ -653,6 +653,8 @@ static const struct usb_device_id smsusb_id_table[] = {
.driver_info = SMS1XXX_BOARD_ZTE_DVB_DATA_CARD },
{ USB_DEVICE(0x19D2, 0x0078),
.driver_info = SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD },
+ { USB_DEVICE(0x3275, 0x0080),
+ .driver_info = SMS1XXX_BOARD_SIANO_RIO },
{ } /* Terminating entry */
};
diff --git a/drivers/media/usb/stk1160/stk1160-ac97.c b/drivers/media/usb/stk1160/stk1160-ac97.c
index c8583c262c3d..c46c8be89602 100644
--- a/drivers/media/usb/stk1160/stk1160-ac97.c
+++ b/drivers/media/usb/stk1160/stk1160-ac97.c
@@ -98,13 +98,11 @@ int stk1160_ac97_register(struct stk1160 *dev)
* Just want a card to access ac96 controls,
* the actual capture interface will be handled by snd-usb-audio
*/
- rc = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
- THIS_MODULE, 0, &card);
+ rc = snd_card_new(dev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, 0, &card);
if (rc < 0)
return rc;
- snd_card_set_dev(card, dev->dev);
-
/* TODO: I'm not sure where should I get these names :-( */
snprintf(card->shortname, sizeof(card->shortname),
"stk1160-mixer");
diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c
index c45c9881bb5f..37bc00f418f1 100644
--- a/drivers/media/usb/stk1160/stk1160-v4l.c
+++ b/drivers/media/usb/stk1160/stk1160-v4l.c
@@ -641,7 +641,7 @@ int stk1160_vb2_setup(struct stk1160 *dev)
q->buf_struct_size = sizeof(struct stk1160_buffer);
q->ops = &stk1160_video_qops;
q->mem_ops = &vb2_vmalloc_memops;
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
rc = vb2_queue_init(q);
if (rc < 0)
diff --git a/drivers/media/usb/tlg2300/pd-alsa.c b/drivers/media/usb/tlg2300/pd-alsa.c
index 3f3e141f70fb..dd8fe100590f 100644
--- a/drivers/media/usb/tlg2300/pd-alsa.c
+++ b/drivers/media/usb/tlg2300/pd-alsa.c
@@ -300,7 +300,8 @@ int poseidon_audio_init(struct poseidon *p)
struct snd_pcm *pcm;
int ret;
- ret = snd_card_create(-1, "Telegent", THIS_MODULE, 0, &card);
+ ret = snd_card_new(&p->interface->dev, -1, "Telegent",
+ THIS_MODULE, 0, &card);
if (ret != 0)
return ret;
diff --git a/drivers/media/usb/tm6000/tm6000-alsa.c b/drivers/media/usb/tm6000/tm6000-alsa.c
index 813c1ec53608..74e5697d8678 100644
--- a/drivers/media/usb/tm6000/tm6000-alsa.c
+++ b/drivers/media/usb/tm6000/tm6000-alsa.c
@@ -1,7 +1,7 @@
/*
*
* Support for audio capture for tm5600/6000/6010
- * (c) 2007-2008 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * (c) 2007-2008 Mauro Carvalho Chehab
*
* Based on cx88-alsa.c
*
@@ -56,7 +56,7 @@ MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s).");
****************************************************************************/
MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Trident,tm5600},"
"{{Trident,tm6000},"
@@ -431,7 +431,8 @@ static int tm6000_audio_init(struct tm6000_core *dev)
if (!enable[devnr])
return -ENOENT;
- rc = snd_card_create(index[devnr], "tm6000", THIS_MODULE, 0, &card);
+ rc = snd_card_new(&dev->udev->dev, index[devnr], "tm6000",
+ THIS_MODULE, 0, &card);
if (rc < 0) {
snd_printk(KERN_ERR "cannot create card instance %d\n", devnr);
return rc;
@@ -445,7 +446,6 @@ static int tm6000_audio_init(struct tm6000_core *dev)
le16_to_cpu(dev->udev->descriptor.idVendor),
le16_to_cpu(dev->udev->descriptor.idProduct));
snd_component_add(card, component);
- snd_card_set_dev(card, &dev->udev->dev);
chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL);
if (!chip) {
diff --git a/drivers/media/usb/tm6000/tm6000-dvb.c b/drivers/media/usb/tm6000/tm6000-dvb.c
index 9fc1e940a82b..095f5db1a790 100644
--- a/drivers/media/usb/tm6000/tm6000-dvb.c
+++ b/drivers/media/usb/tm6000/tm6000-dvb.c
@@ -32,7 +32,7 @@
#include "xc5000.h"
MODULE_DESCRIPTION("DVB driver extension module for tm5600/6000/6010 based TV cards");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Trident, tm5600},"
diff --git a/drivers/media/usb/tm6000/tm6000-input.c b/drivers/media/usb/tm6000/tm6000-input.c
index 8a6bbf1d80e1..d1af5438c168 100644
--- a/drivers/media/usb/tm6000/tm6000-input.c
+++ b/drivers/media/usb/tm6000/tm6000-input.c
@@ -422,7 +422,7 @@ int tm6000_ir_init(struct tm6000_core *dev)
ir->rc = rc;
/* input setup */
- rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC;
+ rc_set_allowed_protocols(rc, RC_BIT_RC5 | RC_BIT_NEC);
/* Neded, in order to support NEC remotes with 24 or 32 bits */
rc->scanmask = 0xffff;
rc->priv = ir;
diff --git a/drivers/media/usb/tm6000/tm6000-stds.c b/drivers/media/usb/tm6000/tm6000-stds.c
index 5e28d6a2412f..93a4b2434b6e 100644
--- a/drivers/media/usb/tm6000/tm6000-stds.c
+++ b/drivers/media/usb/tm6000/tm6000-stds.c
@@ -1,7 +1,7 @@
/*
* tm6000-stds.c - driver for TM5600/TM6000/TM6010 USB video capture devices
*
- * Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2007 Mauro Carvalho Chehab
*
* 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/media/usb/usbtv/Makefile b/drivers/media/usb/usbtv/Makefile
index 28b872fa94e1..775316a88ea6 100644
--- a/drivers/media/usb/usbtv/Makefile
+++ b/drivers/media/usb/usbtv/Makefile
@@ -1 +1,4 @@
+usbtv-y := usbtv-core.o \
+ usbtv-video.o
+
obj-$(CONFIG_VIDEO_USBTV) += usbtv.o
diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c
new file mode 100644
index 000000000000..2f87ddfa469f
--- /dev/null
+++ b/drivers/media/usb/usbtv/usbtv-core.c
@@ -0,0 +1,134 @@
+/*
+ * Fushicai USBTV007 Video Grabber Driver
+ *
+ * Product web site:
+ * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html
+ *
+ * Following LWN articles were very useful in construction of this driver:
+ * Video4Linux2 API series: http://lwn.net/Articles/203924/
+ * videobuf2 API explanation: http://lwn.net/Articles/447435/
+ * Thanks go to Jonathan Corbet for providing this quality documentation.
+ * He is awesome.
+ *
+ * Copyright (c) 2013 Lubomir Rintel
+ * All rights reserved.
+ * No physical hardware was harmed running Windows during the
+ * reverse-engineering activity
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ */
+
+#include "usbtv.h"
+
+int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size)
+{
+ int ret;
+ int pipe = usb_rcvctrlpipe(usbtv->udev, 0);
+ int i;
+
+ for (i = 0; i < size; i++) {
+ u16 index = regs[i][0];
+ u16 value = regs[i][1];
+
+ ret = usb_control_msg(usbtv->udev, pipe, USBTV_REQUEST_REG,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0, 0);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int usbtv_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ int ret;
+ int size;
+ struct device *dev = &intf->dev;
+ struct usbtv *usbtv;
+
+ /* Checks that the device is what we think it is. */
+ if (intf->num_altsetting != 2)
+ return -ENODEV;
+ if (intf->altsetting[1].desc.bNumEndpoints != 4)
+ return -ENODEV;
+
+ /* Packet size is split into 11 bits of base size and count of
+ * extra multiplies of it.*/
+ size = usb_endpoint_maxp(&intf->altsetting[1].endpoint[0].desc);
+ size = (size & 0x07ff) * (((size & 0x1800) >> 11) + 1);
+
+ /* Device structure */
+ usbtv = kzalloc(sizeof(struct usbtv), GFP_KERNEL);
+ if (usbtv == NULL)
+ return -ENOMEM;
+ usbtv->dev = dev;
+ usbtv->udev = usb_get_dev(interface_to_usbdev(intf));
+
+ usbtv->iso_size = size;
+
+ usb_set_intfdata(intf, usbtv);
+
+ ret = usbtv_video_init(usbtv);
+ if (ret < 0)
+ goto usbtv_video_fail;
+
+ /* for simplicity we exploit the v4l2_device reference counting */
+ v4l2_device_get(&usbtv->v4l2_dev);
+
+ dev_info(dev, "Fushicai USBTV007 Video Grabber\n");
+ return 0;
+
+usbtv_video_fail:
+ kfree(usbtv);
+
+ return ret;
+}
+
+static void usbtv_disconnect(struct usb_interface *intf)
+{
+ struct usbtv *usbtv = usb_get_intfdata(intf);
+ usb_set_intfdata(intf, NULL);
+
+ if (!usbtv)
+ return;
+
+ usbtv_video_free(usbtv);
+
+ usb_put_dev(usbtv->udev);
+ usbtv->udev = NULL;
+
+ /* the usbtv structure will be deallocated when v4l2 will be
+ done using it */
+ v4l2_device_put(&usbtv->v4l2_dev);
+}
+
+static struct usb_device_id usbtv_id_table[] = {
+ { USB_DEVICE(0x1b71, 0x3002) },
+ {}
+};
+MODULE_DEVICE_TABLE(usb, usbtv_id_table);
+
+MODULE_AUTHOR("Lubomir Rintel");
+MODULE_DESCRIPTION("Fushicai USBTV007 Video Grabber Driver");
+MODULE_LICENSE("Dual BSD/GPL");
+
+static struct usb_driver usbtv_usb_driver = {
+ .name = "usbtv",
+ .id_table = usbtv_id_table,
+ .probe = usbtv_probe,
+ .disconnect = usbtv_disconnect,
+};
+
+module_usb_driver(usbtv_usb_driver);
diff --git a/drivers/media/usb/usbtv/usbtv.c b/drivers/media/usb/usbtv/usbtv-video.c
index 6222a4ab1e00..20365bd69d05 100644
--- a/drivers/media/usb/usbtv/usbtv.c
+++ b/drivers/media/usb/usbtv/usbtv-video.c
@@ -28,45 +28,10 @@
* GNU General Public License ("GPL").
*/
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-
-#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-core.h>
-#include <media/videobuf2-vmalloc.h>
-
-/* Hardware. */
-#define USBTV_VIDEO_ENDP 0x81
-#define USBTV_BASE 0xc000
-#define USBTV_REQUEST_REG 12
-
-/* Number of concurrent isochronous urbs submitted.
- * Higher numbers was seen to overly saturate the USB bus. */
-#define USBTV_ISOC_TRANSFERS 16
-#define USBTV_ISOC_PACKETS 8
-
-#define USBTV_CHUNK_SIZE 256
-#define USBTV_CHUNK 240
-
-/* Chunk header. */
-#define USBTV_MAGIC_OK(chunk) ((be32_to_cpu(chunk[0]) & 0xff000000) \
- == 0x88000000)
-#define USBTV_FRAME_ID(chunk) ((be32_to_cpu(chunk[0]) & 0x00ff0000) >> 16)
-#define USBTV_ODD(chunk) ((be32_to_cpu(chunk[0]) & 0x0000f000) >> 15)
-#define USBTV_CHUNK_NO(chunk) (be32_to_cpu(chunk[0]) & 0x00000fff)
-
-#define USBTV_TV_STD (V4L2_STD_525_60 | V4L2_STD_PAL)
-
-/* parameters for supported TV norms */
-struct usbtv_norm_params {
- v4l2_std_id norm;
- int cap_width, cap_height;
-};
+
+#include "usbtv.h"
static struct usbtv_norm_params norm_params[] = {
{
@@ -81,43 +46,6 @@ static struct usbtv_norm_params norm_params[] = {
}
};
-/* A single videobuf2 frame buffer. */
-struct usbtv_buf {
- struct vb2_buffer vb;
- struct list_head list;
-};
-
-/* Per-device structure. */
-struct usbtv {
- struct device *dev;
- struct usb_device *udev;
- struct v4l2_device v4l2_dev;
- struct video_device vdev;
- struct vb2_queue vb2q;
- struct mutex v4l2_lock;
- struct mutex vb2q_lock;
-
- /* List of videobuf2 buffers protected by a lock. */
- spinlock_t buflock;
- struct list_head bufs;
-
- /* Number of currently processed frame, useful find
- * out when a new one begins. */
- u32 frame_id;
- int chunks_done;
-
- enum {
- USBTV_COMPOSITE_INPUT,
- USBTV_SVIDEO_INPUT,
- } input;
- v4l2_std_id norm;
- int width, height;
- int n_chunks;
- int iso_size;
- unsigned int sequence;
- struct urb *isoc_urbs[USBTV_ISOC_TRANSFERS];
-};
-
static int usbtv_configure_for_norm(struct usbtv *usbtv, v4l2_std_id norm)
{
int i, ret = 0;
@@ -142,26 +70,6 @@ static int usbtv_configure_for_norm(struct usbtv *usbtv, v4l2_std_id norm)
return ret;
}
-static int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size)
-{
- int ret;
- int pipe = usb_rcvctrlpipe(usbtv->udev, 0);
- int i;
-
- for (i = 0; i < size; i++) {
- u16 index = regs[i][0];
- u16 value = regs[i][1];
-
- ret = usb_control_msg(usbtv->udev, pipe, USBTV_REQUEST_REG,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value, index, NULL, 0, 0);
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
-
static int usbtv_select_input(struct usbtv *usbtv, int input)
{
int ret;
@@ -560,12 +468,6 @@ start_fail:
return ret;
}
-struct usb_device_id usbtv_id_table[] = {
- { USB_DEVICE(0x1b71, 0x3002) },
- {}
-};
-MODULE_DEVICE_TABLE(usb, usbtv_id_table);
-
static int usbtv_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
@@ -660,7 +562,7 @@ static int usbtv_s_input(struct file *file, void *priv, unsigned int i)
return usbtv_select_input(usbtv, i);
}
-struct v4l2_ioctl_ops usbtv_ioctl_ops = {
+static struct v4l2_ioctl_ops usbtv_ioctl_ops = {
.vidioc_querycap = usbtv_querycap,
.vidioc_enum_input = usbtv_enum_input,
.vidioc_enum_fmt_vid_cap = usbtv_enum_fmt_vid_cap,
@@ -682,7 +584,7 @@ struct v4l2_ioctl_ops usbtv_ioctl_ops = {
.vidioc_streamoff = vb2_ioctl_streamoff,
};
-struct v4l2_file_operations usbtv_fops = {
+static struct v4l2_file_operations usbtv_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = video_ioctl2,
.mmap = vb2_fop_mmap,
@@ -743,7 +645,7 @@ static int usbtv_stop_streaming(struct vb2_queue *vq)
return 0;
}
-struct vb2_ops usbtv_vb2_ops = {
+static struct vb2_ops usbtv_vb2_ops = {
.queue_setup = usbtv_queue_setup,
.buf_queue = usbtv_buf_queue,
.start_streaming = usbtv_start_streaming,
@@ -759,33 +661,9 @@ static void usbtv_release(struct v4l2_device *v4l2_dev)
kfree(usbtv);
}
-static int usbtv_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
+int usbtv_video_init(struct usbtv *usbtv)
{
int ret;
- int size;
- struct device *dev = &intf->dev;
- struct usbtv *usbtv;
-
- /* Checks that the device is what we think it is. */
- if (intf->num_altsetting != 2)
- return -ENODEV;
- if (intf->altsetting[1].desc.bNumEndpoints != 4)
- return -ENODEV;
-
- /* Packet size is split into 11 bits of base size and count of
- * extra multiplies of it.*/
- size = usb_endpoint_maxp(&intf->altsetting[1].endpoint[0].desc);
- size = (size & 0x07ff) * (((size & 0x1800) >> 11) + 1);
-
- /* Device structure */
- usbtv = kzalloc(sizeof(struct usbtv), GFP_KERNEL);
- if (usbtv == NULL)
- return -ENOMEM;
- usbtv->dev = dev;
- usbtv->udev = usb_get_dev(interface_to_usbdev(intf));
-
- usbtv->iso_size = size;
(void)usbtv_configure_for_norm(usbtv, V4L2_STD_525_60);
@@ -801,24 +679,22 @@ static int usbtv_probe(struct usb_interface *intf,
usbtv->vb2q.buf_struct_size = sizeof(struct usbtv_buf);
usbtv->vb2q.ops = &usbtv_vb2_ops;
usbtv->vb2q.mem_ops = &vb2_vmalloc_memops;
- usbtv->vb2q.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ usbtv->vb2q.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
usbtv->vb2q.lock = &usbtv->vb2q_lock;
ret = vb2_queue_init(&usbtv->vb2q);
if (ret < 0) {
- dev_warn(dev, "Could not initialize videobuf2 queue\n");
- goto usbtv_fail;
+ dev_warn(usbtv->dev, "Could not initialize videobuf2 queue\n");
+ return ret;
}
/* v4l2 structure */
usbtv->v4l2_dev.release = usbtv_release;
- ret = v4l2_device_register(dev, &usbtv->v4l2_dev);
+ ret = v4l2_device_register(usbtv->dev, &usbtv->v4l2_dev);
if (ret < 0) {
- dev_warn(dev, "Could not register v4l2 device\n");
+ dev_warn(usbtv->dev, "Could not register v4l2 device\n");
goto v4l2_fail;
}
- usb_set_intfdata(intf, usbtv);
-
/* Video structure */
strlcpy(usbtv->vdev.name, "usbtv", sizeof(usbtv->vdev.name));
usbtv->vdev.v4l2_dev = &usbtv->v4l2_dev;
@@ -832,52 +708,31 @@ static int usbtv_probe(struct usb_interface *intf,
video_set_drvdata(&usbtv->vdev, usbtv);
ret = video_register_device(&usbtv->vdev, VFL_TYPE_GRABBER, -1);
if (ret < 0) {
- dev_warn(dev, "Could not register video device\n");
+ dev_warn(usbtv->dev, "Could not register video device\n");
goto vdev_fail;
}
- dev_info(dev, "Fushicai USBTV007 Video Grabber\n");
return 0;
vdev_fail:
v4l2_device_unregister(&usbtv->v4l2_dev);
v4l2_fail:
vb2_queue_release(&usbtv->vb2q);
-usbtv_fail:
- kfree(usbtv);
return ret;
}
-static void usbtv_disconnect(struct usb_interface *intf)
+void usbtv_video_free(struct usbtv *usbtv)
{
- struct usbtv *usbtv = usb_get_intfdata(intf);
-
mutex_lock(&usbtv->vb2q_lock);
mutex_lock(&usbtv->v4l2_lock);
usbtv_stop(usbtv);
- usb_set_intfdata(intf, NULL);
video_unregister_device(&usbtv->vdev);
v4l2_device_disconnect(&usbtv->v4l2_dev);
- usb_put_dev(usbtv->udev);
- usbtv->udev = NULL;
mutex_unlock(&usbtv->v4l2_lock);
mutex_unlock(&usbtv->vb2q_lock);
v4l2_device_put(&usbtv->v4l2_dev);
}
-
-MODULE_AUTHOR("Lubomir Rintel");
-MODULE_DESCRIPTION("Fushicai USBTV007 Video Grabber Driver");
-MODULE_LICENSE("Dual BSD/GPL");
-
-struct usb_driver usbtv_usb_driver = {
- .name = "usbtv",
- .id_table = usbtv_id_table,
- .probe = usbtv_probe,
- .disconnect = usbtv_disconnect,
-};
-
-module_usb_driver(usbtv_usb_driver);
diff --git a/drivers/media/usb/usbtv/usbtv.h b/drivers/media/usb/usbtv/usbtv.h
new file mode 100644
index 000000000000..cb1d388cc647
--- /dev/null
+++ b/drivers/media/usb/usbtv/usbtv.h
@@ -0,0 +1,99 @@
+/*
+ * Fushicai USBTV007 Video Grabber Driver
+ *
+ * Copyright (c) 2013 Lubomir Rintel
+ * All rights reserved.
+ * No physical hardware was harmed running Windows during the
+ * reverse-engineering activity
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <media/v4l2-device.h>
+#include <media/videobuf2-vmalloc.h>
+
+/* Hardware. */
+#define USBTV_VIDEO_ENDP 0x81
+#define USBTV_BASE 0xc000
+#define USBTV_REQUEST_REG 12
+
+/* Number of concurrent isochronous urbs submitted.
+ * Higher numbers was seen to overly saturate the USB bus. */
+#define USBTV_ISOC_TRANSFERS 16
+#define USBTV_ISOC_PACKETS 8
+
+#define USBTV_CHUNK_SIZE 256
+#define USBTV_CHUNK 240
+
+/* Chunk header. */
+#define USBTV_MAGIC_OK(chunk) ((be32_to_cpu(chunk[0]) & 0xff000000) \
+ == 0x88000000)
+#define USBTV_FRAME_ID(chunk) ((be32_to_cpu(chunk[0]) & 0x00ff0000) >> 16)
+#define USBTV_ODD(chunk) ((be32_to_cpu(chunk[0]) & 0x0000f000) >> 15)
+#define USBTV_CHUNK_NO(chunk) (be32_to_cpu(chunk[0]) & 0x00000fff)
+
+#define USBTV_TV_STD (V4L2_STD_525_60 | V4L2_STD_PAL)
+
+/* parameters for supported TV norms */
+struct usbtv_norm_params {
+ v4l2_std_id norm;
+ int cap_width, cap_height;
+};
+
+/* A single videobuf2 frame buffer. */
+struct usbtv_buf {
+ struct vb2_buffer vb;
+ struct list_head list;
+};
+
+/* Per-device structure. */
+struct usbtv {
+ struct device *dev;
+ struct usb_device *udev;
+
+ /* video */
+ struct v4l2_device v4l2_dev;
+ struct video_device vdev;
+ struct vb2_queue vb2q;
+ struct mutex v4l2_lock;
+ struct mutex vb2q_lock;
+
+ /* List of videobuf2 buffers protected by a lock. */
+ spinlock_t buflock;
+ struct list_head bufs;
+
+ /* Number of currently processed frame, useful find
+ * out when a new one begins. */
+ u32 frame_id;
+ int chunks_done;
+
+ enum {
+ USBTV_COMPOSITE_INPUT,
+ USBTV_SVIDEO_INPUT,
+ } input;
+ v4l2_std_id norm;
+ int width, height;
+ int n_chunks;
+ int iso_size;
+ unsigned int sequence;
+ struct urb *isoc_urbs[USBTV_ISOC_TRANSFERS];
+};
+
+int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size);
+
+int usbtv_video_init(struct usbtv *usbtv);
+void usbtv_video_free(struct usbtv *usbtv);
diff --git a/drivers/media/usb/usbvision/usbvision.h b/drivers/media/usb/usbvision/usbvision.h
index 8a25876d72c6..a0c73cf1517c 100644
--- a/drivers/media/usb/usbvision/usbvision.h
+++ b/drivers/media/usb/usbvision/usbvision.h
@@ -203,14 +203,6 @@ enum {
mr = LIMIT_RGB(mm_r); \
}
-/* Debugging aid */
-#define USBVISION_SAY_AND_WAIT(what) { \
- wait_queue_head_t wq; \
- init_waitqueue_head(&wq); \
- printk(KERN_INFO "Say: %s\n", what); \
- interruptible_sleep_on_timeout(&wq, HZ * 3); \
-}
-
/*
* This macro checks if usbvision is still operational. The 'usbvision'
* pointer must be valid, usbvision->dev must be valid, we are not
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index c3bb2502225b..ad47c5cb539a 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -108,11 +108,31 @@ static struct uvc_format_desc uvc_fmts[] = {
.fcc = V4L2_PIX_FMT_Y16,
},
{
- .name = "RGB Bayer",
+ .name = "BGGR Bayer (BY8 )",
.guid = UVC_GUID_FORMAT_BY8,
.fcc = V4L2_PIX_FMT_SBGGR8,
},
{
+ .name = "BGGR Bayer (BA81)",
+ .guid = UVC_GUID_FORMAT_BA81,
+ .fcc = V4L2_PIX_FMT_SBGGR8,
+ },
+ {
+ .name = "GBRG Bayer (GBRG)",
+ .guid = UVC_GUID_FORMAT_GBRG,
+ .fcc = V4L2_PIX_FMT_SGBRG8,
+ },
+ {
+ .name = "GRBG Bayer (GRBG)",
+ .guid = UVC_GUID_FORMAT_GRBG,
+ .fcc = V4L2_PIX_FMT_SGRBG8,
+ },
+ {
+ .name = "RGGB Bayer (RGGB)",
+ .guid = UVC_GUID_FORMAT_RGGB,
+ .fcc = V4L2_PIX_FMT_SRGGB8,
+ },
+ {
.name = "RGB565",
.guid = UVC_GUID_FORMAT_RGBP,
.fcc = V4L2_PIX_FMT_RGB565,
@@ -925,7 +945,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
case UVC_VC_HEADER:
n = buflen >= 12 ? buffer[11] : 0;
- if (buflen < 12 || buflen < 12 + n) {
+ if (buflen < 12 + n) {
uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
"interface %d HEADER error\n", udev->devnum,
alts->desc.bInterfaceNumber);
diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
index cd962be860ca..6e92d2080255 100644
--- a/drivers/media/usb/uvc/uvc_queue.c
+++ b/drivers/media/usb/uvc/uvc_queue.c
@@ -48,12 +48,14 @@ static int uvc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
struct uvc_streaming *stream =
container_of(queue, struct uvc_streaming, queue);
- if (*nbuffers > UVC_MAX_VIDEO_BUFFERS)
- *nbuffers = UVC_MAX_VIDEO_BUFFERS;
+ /* Make sure the image size is large enough. */
+ if (fmt && fmt->fmt.pix.sizeimage < stream->ctrl.dwMaxVideoFrameSize)
+ return -EINVAL;
*nplanes = 1;
- sizes[0] = stream->ctrl.dwMaxVideoFrameSize;
+ sizes[0] = fmt ? fmt->fmt.pix.sizeimage
+ : stream->ctrl.dwMaxVideoFrameSize;
return 0;
}
@@ -104,15 +106,15 @@ static void uvc_buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&queue->irqlock, flags);
}
-static int uvc_buffer_finish(struct vb2_buffer *vb)
+static void uvc_buffer_finish(struct vb2_buffer *vb)
{
struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
struct uvc_streaming *stream =
container_of(queue, struct uvc_streaming, queue);
struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
- uvc_video_clock_update(stream, &vb->v4l2_buf, buf);
- return 0;
+ if (vb->state == VB2_BUF_STATE_DONE)
+ uvc_video_clock_update(stream, &vb->v4l2_buf, buf);
}
static void uvc_wait_prepare(struct vb2_queue *vq)
@@ -149,7 +151,8 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
queue->queue.buf_struct_size = sizeof(struct uvc_buffer);
queue->queue.ops = &uvc_queue_qops;
queue->queue.mem_ops = &vb2_vmalloc_memops;
- queue->queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC
+ | V4L2_BUF_FLAG_TSTAMP_SRC_SOE;
ret = vb2_queue_init(&queue->queue);
if (ret)
return ret;
@@ -196,6 +199,18 @@ int uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
return ret;
}
+int uvc_create_buffers(struct uvc_video_queue *queue,
+ struct v4l2_create_buffers *cb)
+{
+ int ret;
+
+ mutex_lock(&queue->mutex);
+ ret = vb2_create_bufs(&queue->queue, cb);
+ mutex_unlock(&queue->mutex);
+
+ return ret;
+}
+
int uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
{
int ret;
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 3afff92804d3..378ae02e593b 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -1000,6 +1000,17 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return uvc_query_buffer(&stream->queue, buf);
}
+ case VIDIOC_CREATE_BUFS:
+ {
+ struct v4l2_create_buffers *cb = arg;
+
+ ret = uvc_acquire_privileges(handle);
+ if (ret < 0)
+ return ret;
+
+ return uvc_create_buffers(&stream->queue, cb);
+ }
+
case VIDIOC_QBUF:
if (!uvc_has_privileges(handle))
return -EBUSY;
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index 898c208889cd..8d52baf5952b 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -1453,6 +1453,9 @@ static unsigned int uvc_endpoint_max_bpi(struct usb_device *dev,
case USB_SPEED_HIGH:
psize = usb_endpoint_maxp(&ep->desc);
return (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+ case USB_SPEED_WIRELESS:
+ psize = usb_endpoint_maxp(&ep->desc);
+ return psize;
default:
psize = usb_endpoint_maxp(&ep->desc);
return psize & 0x07ff;
@@ -1847,7 +1850,25 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable)
if (!enable) {
uvc_uninit_video(stream, 1);
- usb_set_interface(stream->dev->udev, stream->intfnum, 0);
+ if (stream->intf->num_altsetting > 1) {
+ usb_set_interface(stream->dev->udev,
+ stream->intfnum, 0);
+ } else {
+ /* UVC doesn't specify how to inform a bulk-based device
+ * when the video stream is stopped. Windows sends a
+ * CLEAR_FEATURE(HALT) request to the video streaming
+ * bulk endpoint, mimic the same behaviour.
+ */
+ unsigned int epnum = stream->header.bEndpointAddress
+ & USB_ENDPOINT_NUMBER_MASK;
+ unsigned int dir = stream->header.bEndpointAddress
+ & USB_ENDPOINT_DIR_MASK;
+ unsigned int pipe;
+
+ pipe = usb_sndbulkpipe(stream->dev->udev, epnum) | dir;
+ usb_clear_halt(stream->dev->udev, pipe);
+ }
+
uvc_queue_enable(&stream->queue, 0);
uvc_video_clock_cleanup(stream);
return 0;
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 9e35982d099a..b1f69a6d4068 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -94,6 +94,18 @@
#define UVC_GUID_FORMAT_BY8 \
{ 'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_BA81 \
+ { 'B', 'A', '8', '1', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_GBRG \
+ { 'G', 'B', 'R', 'G', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_GRBG \
+ { 'G', 'R', 'B', 'G', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_RGGB \
+ { 'R', 'G', 'G', 'B', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
#define UVC_GUID_FORMAT_RGBP \
{ 'R', 'G', 'B', 'P', 0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
@@ -115,8 +127,6 @@
#define UVC_URBS 5
/* Maximum number of packets per URB. */
#define UVC_MAX_PACKETS 32
-/* Maximum number of video buffers. */
-#define UVC_MAX_VIDEO_BUFFERS 32
/* Maximum status buffer size in bytes of interrupt URB. */
#define UVC_MAX_STATUS_SIZE 16
@@ -616,6 +626,8 @@ extern int uvc_alloc_buffers(struct uvc_video_queue *queue,
extern void uvc_free_buffers(struct uvc_video_queue *queue);
extern int uvc_query_buffer(struct uvc_video_queue *queue,
struct v4l2_buffer *v4l2_buf);
+extern int uvc_create_buffers(struct uvc_video_queue *queue,
+ struct v4l2_create_buffers *v4l2_cb);
extern int uvc_queue_buffer(struct uvc_video_queue *queue,
struct v4l2_buffer *v4l2_buf);
extern int uvc_dequeue_buffer(struct uvc_video_queue *queue,
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index 8f7a6a454a4c..04b2daf567be 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -733,14 +733,14 @@ static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *u
copy_to_user(&up->u, &kp->u, sizeof(kp->u)) ||
put_user(kp->pending, &up->pending) ||
put_user(kp->sequence, &up->sequence) ||
- put_compat_timespec(&kp->timestamp, &up->timestamp) ||
+ compat_put_timespec(&kp->timestamp, &up->timestamp) ||
put_user(kp->id, &up->id) ||
copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
return -EFAULT;
return 0;
}
-struct v4l2_subdev_edid32 {
+struct v4l2_edid32 {
__u32 pad;
__u32 start_block;
__u32 blocks;
@@ -748,11 +748,11 @@ struct v4l2_subdev_edid32 {
compat_caddr_t edid;
};
-static int get_v4l2_subdev_edid32(struct v4l2_subdev_edid *kp, struct v4l2_subdev_edid32 __user *up)
+static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
{
u32 tmp;
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_subdev_edid32)) ||
+ if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) ||
get_user(kp->pad, &up->pad) ||
get_user(kp->start_block, &up->start_block) ||
get_user(kp->blocks, &up->blocks) ||
@@ -763,11 +763,11 @@ static int get_v4l2_subdev_edid32(struct v4l2_subdev_edid *kp, struct v4l2_subde
return 0;
}
-static int put_v4l2_subdev_edid32(struct v4l2_subdev_edid *kp, struct v4l2_subdev_edid32 __user *up)
+static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
{
u32 tmp = (u32)((unsigned long)kp->edid);
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_subdev_edid32)) ||
+ if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) ||
put_user(kp->pad, &up->pad) ||
put_user(kp->start_block, &up->start_block) ||
put_user(kp->blocks, &up->blocks) ||
@@ -787,8 +787,8 @@ static int put_v4l2_subdev_edid32(struct v4l2_subdev_edid *kp, struct v4l2_subde
#define VIDIOC_DQBUF32 _IOWR('V', 17, struct v4l2_buffer32)
#define VIDIOC_ENUMSTD32 _IOWR('V', 25, struct v4l2_standard32)
#define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32)
-#define VIDIOC_SUBDEV_G_EDID32 _IOWR('V', 63, struct v4l2_subdev_edid32)
-#define VIDIOC_SUBDEV_S_EDID32 _IOWR('V', 64, struct v4l2_subdev_edid32)
+#define VIDIOC_G_EDID32 _IOWR('V', 40, struct v4l2_edid32)
+#define VIDIOC_S_EDID32 _IOWR('V', 41, struct v4l2_edid32)
#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32)
#define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32)
#define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32)
@@ -816,7 +816,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
struct v4l2_ext_controls v2ecs;
struct v4l2_event v2ev;
struct v4l2_create_buffers v2crt;
- struct v4l2_subdev_edid v2edid;
+ struct v4l2_edid v2edid;
unsigned long vx;
int vi;
} karg;
@@ -849,8 +849,8 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break;
case VIDIOC_PREPARE_BUF32: cmd = VIDIOC_PREPARE_BUF; break;
- case VIDIOC_SUBDEV_G_EDID32: cmd = VIDIOC_SUBDEV_G_EDID; break;
- case VIDIOC_SUBDEV_S_EDID32: cmd = VIDIOC_SUBDEV_S_EDID; break;
+ case VIDIOC_G_EDID32: cmd = VIDIOC_G_EDID; break;
+ case VIDIOC_S_EDID32: cmd = VIDIOC_S_EDID; break;
}
switch (cmd) {
@@ -868,9 +868,9 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
compatible_arg = 0;
break;
- case VIDIOC_SUBDEV_G_EDID:
- case VIDIOC_SUBDEV_S_EDID:
- err = get_v4l2_subdev_edid32(&karg.v2edid, up);
+ case VIDIOC_G_EDID:
+ case VIDIOC_S_EDID:
+ err = get_v4l2_edid32(&karg.v2edid, up);
compatible_arg = 0;
break;
@@ -966,9 +966,9 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
err = put_v4l2_event32(&karg.v2ev, up);
break;
- case VIDIOC_SUBDEV_G_EDID:
- case VIDIOC_SUBDEV_S_EDID:
- err = put_v4l2_subdev_edid32(&karg.v2edid, up);
+ case VIDIOC_G_EDID:
+ case VIDIOC_S_EDID:
+ err = put_v4l2_edid32(&karg.v2edid, up);
break;
case VIDIOC_G_FMT:
@@ -1006,103 +1006,14 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
if (!file->f_op->unlocked_ioctl)
return ret;
- switch (cmd) {
- case VIDIOC_QUERYCAP:
- case VIDIOC_RESERVED:
- case VIDIOC_ENUM_FMT:
- case VIDIOC_G_FMT32:
- case VIDIOC_S_FMT32:
- case VIDIOC_REQBUFS:
- case VIDIOC_QUERYBUF32:
- case VIDIOC_G_FBUF32:
- case VIDIOC_S_FBUF32:
- case VIDIOC_OVERLAY32:
- case VIDIOC_QBUF32:
- case VIDIOC_EXPBUF:
- case VIDIOC_DQBUF32:
- case VIDIOC_STREAMON32:
- case VIDIOC_STREAMOFF32:
- case VIDIOC_G_PARM:
- case VIDIOC_S_PARM:
- case VIDIOC_G_STD:
- case VIDIOC_S_STD:
- case VIDIOC_ENUMSTD32:
- case VIDIOC_ENUMINPUT32:
- case VIDIOC_G_CTRL:
- case VIDIOC_S_CTRL:
- case VIDIOC_G_TUNER:
- case VIDIOC_S_TUNER:
- case VIDIOC_G_AUDIO:
- case VIDIOC_S_AUDIO:
- case VIDIOC_QUERYCTRL:
- case VIDIOC_QUERYMENU:
- case VIDIOC_G_INPUT32:
- case VIDIOC_S_INPUT32:
- case VIDIOC_G_OUTPUT32:
- case VIDIOC_S_OUTPUT32:
- case VIDIOC_ENUMOUTPUT:
- case VIDIOC_G_AUDOUT:
- case VIDIOC_S_AUDOUT:
- case VIDIOC_G_MODULATOR:
- case VIDIOC_S_MODULATOR:
- case VIDIOC_S_FREQUENCY:
- case VIDIOC_G_FREQUENCY:
- case VIDIOC_CROPCAP:
- case VIDIOC_G_CROP:
- case VIDIOC_S_CROP:
- case VIDIOC_G_SELECTION:
- case VIDIOC_S_SELECTION:
- case VIDIOC_G_JPEGCOMP:
- case VIDIOC_S_JPEGCOMP:
- case VIDIOC_QUERYSTD:
- case VIDIOC_TRY_FMT32:
- case VIDIOC_ENUMAUDIO:
- case VIDIOC_ENUMAUDOUT:
- case VIDIOC_G_PRIORITY:
- case VIDIOC_S_PRIORITY:
- case VIDIOC_G_SLICED_VBI_CAP:
- case VIDIOC_LOG_STATUS:
- case VIDIOC_G_EXT_CTRLS32:
- case VIDIOC_S_EXT_CTRLS32:
- case VIDIOC_TRY_EXT_CTRLS32:
- case VIDIOC_ENUM_FRAMESIZES:
- case VIDIOC_ENUM_FRAMEINTERVALS:
- case VIDIOC_G_ENC_INDEX:
- case VIDIOC_ENCODER_CMD:
- case VIDIOC_TRY_ENCODER_CMD:
- case VIDIOC_DECODER_CMD:
- case VIDIOC_TRY_DECODER_CMD:
- case VIDIOC_DBG_S_REGISTER:
- case VIDIOC_DBG_G_REGISTER:
- case VIDIOC_S_HW_FREQ_SEEK:
- case VIDIOC_S_DV_TIMINGS:
- case VIDIOC_G_DV_TIMINGS:
- case VIDIOC_DQEVENT:
- case VIDIOC_DQEVENT32:
- case VIDIOC_SUBSCRIBE_EVENT:
- case VIDIOC_UNSUBSCRIBE_EVENT:
- case VIDIOC_CREATE_BUFS32:
- case VIDIOC_PREPARE_BUF32:
- case VIDIOC_ENUM_DV_TIMINGS:
- case VIDIOC_QUERY_DV_TIMINGS:
- case VIDIOC_DV_TIMINGS_CAP:
- case VIDIOC_ENUM_FREQ_BANDS:
- case VIDIOC_SUBDEV_G_EDID32:
- case VIDIOC_SUBDEV_S_EDID32:
+ if (_IOC_TYPE(cmd) == 'V' && _IOC_NR(cmd) < BASE_VIDIOC_PRIVATE)
ret = do_video_ioctl(file, cmd, arg);
- break;
+ else if (vdev->fops->compat_ioctl32)
+ ret = vdev->fops->compat_ioctl32(file, cmd, arg);
- default:
- if (vdev->fops->compat_ioctl32)
- ret = vdev->fops->compat_ioctl32(file, cmd, arg);
-
- if (ret == -ENOIOCTLCMD)
- printk(KERN_WARNING "compat_ioctl32: "
- "unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
- _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd),
- cmd);
- break;
- }
+ if (ret == -ENOIOCTLCMD)
+ pr_warn("compat_ioctl32: unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
+ _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd);
return ret;
}
EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32);
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 6ff002bd5909..55c683254102 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -735,6 +735,8 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_VIDEO_DEC_PTS: return "Video Decoder PTS";
case V4L2_CID_MPEG_VIDEO_DEC_FRAME: return "Video Decoder Frame Count";
case V4L2_CID_MPEG_VIDEO_VBV_DELAY: return "Initial Delay for VBV Control";
+ case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE: return "Horizontal MV Search Range";
+ case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE: return "Vertical MV Search Range";
case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: return "Repeat Sequence Header";
/* VPX controls */
@@ -857,6 +859,17 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_FM_RX_CLASS: return "FM Radio Receiver Controls";
case V4L2_CID_TUNE_DEEMPHASIS: return "De-Emphasis";
case V4L2_CID_RDS_RECEPTION: return "RDS Reception";
+
+ case V4L2_CID_RF_TUNER_CLASS: return "RF Tuner Controls";
+ case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO: return "LNA Gain, Auto";
+ case V4L2_CID_RF_TUNER_LNA_GAIN: return "LNA Gain";
+ case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: return "Mixer Gain, Auto";
+ case V4L2_CID_RF_TUNER_MIXER_GAIN: return "Mixer Gain";
+ case V4L2_CID_RF_TUNER_IF_GAIN_AUTO: return "IF Gain, Auto";
+ case V4L2_CID_RF_TUNER_IF_GAIN: return "IF Gain";
+ case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: return "Bandwidth, Auto";
+ case V4L2_CID_RF_TUNER_BANDWIDTH: return "Bandwidth";
+ case V4L2_CID_RF_TUNER_PLL_LOCK: return "PLL Lock";
default:
return NULL;
}
@@ -906,10 +919,19 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_WIDE_DYNAMIC_RANGE:
case V4L2_CID_IMAGE_STABILIZATION:
case V4L2_CID_RDS_RECEPTION:
+ case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO:
+ case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO:
+ case V4L2_CID_RF_TUNER_IF_GAIN_AUTO:
+ case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:
+ case V4L2_CID_RF_TUNER_PLL_LOCK:
*type = V4L2_CTRL_TYPE_BOOLEAN;
*min = 0;
*max = *step = 1;
break;
+ case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE:
+ case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE:
+ *type = V4L2_CTRL_TYPE_INTEGER;
+ break;
case V4L2_CID_PAN_RESET:
case V4L2_CID_TILT_RESET:
case V4L2_CID_FLASH_STROBE:
@@ -991,6 +1013,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_IMAGE_PROC_CLASS:
case V4L2_CID_DV_CLASS:
case V4L2_CID_FM_RX_CLASS:
+ case V4L2_CID_RF_TUNER_CLASS:
*type = V4L2_CTRL_TYPE_CTRL_CLASS;
/* You can neither read not write these */
*flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
@@ -1063,6 +1086,10 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_PILOT_TONE_FREQUENCY:
case V4L2_CID_TUNE_POWER_LEVEL:
case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
+ case V4L2_CID_RF_TUNER_LNA_GAIN:
+ case V4L2_CID_RF_TUNER_MIXER_GAIN:
+ case V4L2_CID_RF_TUNER_IF_GAIN:
+ case V4L2_CID_RF_TUNER_BANDWIDTH:
*flags |= V4L2_CTRL_FLAG_SLIDER;
break;
case V4L2_CID_PAN_RELATIVE:
@@ -1081,6 +1108,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_DV_RX_POWER_PRESENT:
*flags |= V4L2_CTRL_FLAG_READ_ONLY;
break;
+ case V4L2_CID_RF_TUNER_PLL_LOCK:
+ *flags |= V4L2_CTRL_FLAG_VOLATILE;
+ break;
}
}
EXPORT_SYMBOL(v4l2_ctrl_fill);
@@ -1921,7 +1951,8 @@ void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls)
int i;
/* The first control is the master control and it must not be NULL */
- BUG_ON(ncontrols == 0 || controls[0] == NULL);
+ if (WARN_ON(ncontrols == 0 || controls[0] == NULL))
+ return;
for (i = 0; i < ncontrols; i++) {
if (controls[i]) {
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index 0a30dbf3d05c..634d863c05b4 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -554,6 +554,7 @@ static void determine_valid_ioctls(struct video_device *vdev)
bool is_vid = vdev->vfl_type == VFL_TYPE_GRABBER;
bool is_vbi = vdev->vfl_type == VFL_TYPE_VBI;
bool is_radio = vdev->vfl_type == VFL_TYPE_RADIO;
+ bool is_sdr = vdev->vfl_type == VFL_TYPE_SDR;
bool is_rx = vdev->vfl_dir != VFL_DIR_TX;
bool is_tx = vdev->vfl_dir != VFL_DIR_RX;
@@ -662,9 +663,20 @@ static void determine_valid_ioctls(struct video_device *vdev)
ops->vidioc_try_fmt_sliced_vbi_out)))
set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls);
SET_VALID_IOCTL(ops, VIDIOC_G_SLICED_VBI_CAP, vidioc_g_sliced_vbi_cap);
+ } else if (is_sdr) {
+ /* SDR specific ioctls */
+ if (ops->vidioc_enum_fmt_sdr_cap)
+ set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls);
+ if (ops->vidioc_g_fmt_sdr_cap)
+ set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls);
+ if (ops->vidioc_s_fmt_sdr_cap)
+ set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls);
+ if (ops->vidioc_try_fmt_sdr_cap)
+ set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls);
}
- if (!is_radio) {
- /* ioctls valid for video or vbi */
+
+ if (is_vid || is_vbi || is_sdr) {
+ /* ioctls valid for video, vbi or sdr */
SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs);
SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf);
SET_VALID_IOCTL(ops, VIDIOC_QBUF, vidioc_qbuf);
@@ -672,6 +684,10 @@ static void determine_valid_ioctls(struct video_device *vdev)
SET_VALID_IOCTL(ops, VIDIOC_DQBUF, vidioc_dqbuf);
SET_VALID_IOCTL(ops, VIDIOC_CREATE_BUFS, vidioc_create_bufs);
SET_VALID_IOCTL(ops, VIDIOC_PREPARE_BUF, vidioc_prepare_buf);
+ }
+
+ if (is_vid || is_vbi) {
+ /* ioctls valid for video or vbi */
if (ops->vidioc_s_std)
set_bit(_IOC_NR(VIDIOC_ENUMSTD), valid_ioctls);
SET_VALID_IOCTL(ops, VIDIOC_S_STD, vidioc_s_std);
@@ -685,6 +701,7 @@ static void determine_valid_ioctls(struct video_device *vdev)
SET_VALID_IOCTL(ops, VIDIOC_G_AUDIO, vidioc_g_audio);
SET_VALID_IOCTL(ops, VIDIOC_S_AUDIO, vidioc_s_audio);
SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings);
+ SET_VALID_IOCTL(ops, VIDIOC_S_EDID, vidioc_s_edid);
}
if (is_tx) {
SET_VALID_IOCTL(ops, VIDIOC_ENUMOUTPUT, vidioc_enum_output);
@@ -710,9 +727,10 @@ static void determine_valid_ioctls(struct video_device *vdev)
SET_VALID_IOCTL(ops, VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings);
SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings);
SET_VALID_IOCTL(ops, VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap);
+ SET_VALID_IOCTL(ops, VIDIOC_G_EDID, vidioc_g_edid);
}
- if (is_tx) {
- /* transmitter only ioctls */
+ if (is_tx && (is_radio || is_sdr)) {
+ /* radio transmitter only ioctls */
SET_VALID_IOCTL(ops, VIDIOC_G_MODULATOR, vidioc_g_modulator);
SET_VALID_IOCTL(ops, VIDIOC_S_MODULATOR, vidioc_s_modulator);
}
@@ -758,6 +776,8 @@ static void determine_valid_ioctls(struct video_device *vdev)
* %VFL_TYPE_RADIO - A radio card
*
* %VFL_TYPE_SUBDEV - A subdevice
+ *
+ * %VFL_TYPE_SDR - Software Defined Radio
*/
int __video_register_device(struct video_device *vdev, int type, int nr,
int warn_if_nr_in_use, struct module *owner)
@@ -797,6 +817,10 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
case VFL_TYPE_SUBDEV:
name_base = "v4l-subdev";
break;
+ case VFL_TYPE_SDR:
+ /* Use device name 'swradio' because 'sdr' was already taken. */
+ name_base = "swradio";
+ break;
default:
printk(KERN_ERR "%s called with unknown type: %d\n",
__func__, type);
diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c
index f7902fe8a526..48b20dfcc4d0 100644
--- a/drivers/media/v4l2-core/v4l2-dv-timings.c
+++ b/drivers/media/v4l2-core/v4l2-dv-timings.c
@@ -26,6 +26,10 @@
#include <linux/v4l2-dv-timings.h>
#include <media/v4l2-dv-timings.h>
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_DESCRIPTION("V4L2 DV Timings Helper Functions");
+MODULE_LICENSE("GPL");
+
const struct v4l2_dv_timings v4l2_dv_timings_presets[] = {
V4L2_DV_BT_CEA_640X480P59_94,
V4L2_DV_BT_CEA_720X480I59_94,
@@ -324,6 +328,10 @@ EXPORT_SYMBOL_GPL(v4l2_print_dv_timings);
* This function will attempt to detect if the given values correspond to a
* valid CVT format. If so, then it will return true, and fmt will be filled
* in with the found CVT timings.
+ *
+ * TODO: VESA defined a new version 2 of their reduced blanking
+ * formula. Support for that is currently missing in this CVT
+ * detection function.
*/
bool v4l2_detect_cvt(unsigned frame_height, unsigned hfreq, unsigned vsync,
u32 polarities, struct v4l2_dv_timings *fmt)
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 707aef705a47..d9113cc71c77 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -152,6 +152,7 @@ const char *v4l2_type_names[] = {
[V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "vid-out-overlay",
[V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE] = "vid-cap-mplane",
[V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE] = "vid-out-mplane",
+ [V4L2_BUF_TYPE_SDR_CAPTURE] = "sdr-cap",
};
EXPORT_SYMBOL(v4l2_type_names);
@@ -245,6 +246,7 @@ static void v4l_print_format(const void *arg, bool write_only)
const struct v4l2_vbi_format *vbi;
const struct v4l2_sliced_vbi_format *sliced;
const struct v4l2_window *win;
+ const struct v4l2_sdr_format *sdr;
unsigned i;
pr_cont("type=%s", prt_names(p->type, v4l2_type_names));
@@ -318,6 +320,14 @@ static void v4l_print_format(const void *arg, bool write_only)
sliced->service_lines[0][i],
sliced->service_lines[1][i]);
break;
+ case V4L2_BUF_TYPE_SDR_CAPTURE:
+ sdr = &p->fmt.sdr;
+ pr_cont(", pixelformat=%c%c%c%c\n",
+ (sdr->pixelformat >> 0) & 0xff,
+ (sdr->pixelformat >> 8) & 0xff,
+ (sdr->pixelformat >> 16) & 0xff,
+ (sdr->pixelformat >> 24) & 0xff);
+ break;
}
}
@@ -834,6 +844,14 @@ static void v4l_print_freq_band(const void *arg, bool write_only)
p->rangehigh, p->modulation);
}
+static void v4l_print_edid(const void *arg, bool write_only)
+{
+ const struct v4l2_edid *p = arg;
+
+ pr_cont("pad=%u, start_block=%u, blocks=%u\n",
+ p->pad, p->start_block, p->blocks);
+}
+
static void v4l_print_u32(const void *arg, bool write_only)
{
pr_cont("value=%u\n", *(const u32 *)arg);
@@ -881,6 +899,7 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type)
const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
bool is_vbi = vfd->vfl_type == VFL_TYPE_VBI;
+ bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
@@ -930,6 +949,10 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type)
if (is_vbi && is_tx && ops->vidioc_g_fmt_sliced_vbi_out)
return 0;
break;
+ case V4L2_BUF_TYPE_SDR_CAPTURE:
+ if (is_sdr && is_rx && ops->vidioc_g_fmt_sdr_cap)
+ return 0;
+ break;
default:
break;
}
@@ -1049,6 +1072,10 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops,
if (unlikely(!is_tx || !ops->vidioc_enum_fmt_vid_out_mplane))
break;
return ops->vidioc_enum_fmt_vid_out_mplane(file, fh, arg);
+ case V4L2_BUF_TYPE_SDR_CAPTURE:
+ if (unlikely(!is_rx || !ops->vidioc_enum_fmt_sdr_cap))
+ break;
+ return ops->vidioc_enum_fmt_sdr_cap(file, fh, arg);
}
return -EINVAL;
}
@@ -1059,6 +1086,7 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
struct v4l2_format *p = arg;
struct video_device *vfd = video_devdata(file);
bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
+ bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
@@ -1103,6 +1131,10 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
if (unlikely(!is_tx || is_vid || !ops->vidioc_g_fmt_sliced_vbi_out))
break;
return ops->vidioc_g_fmt_sliced_vbi_out(file, fh, arg);
+ case V4L2_BUF_TYPE_SDR_CAPTURE:
+ if (unlikely(!is_rx || !is_sdr || !ops->vidioc_g_fmt_sdr_cap))
+ break;
+ return ops->vidioc_g_fmt_sdr_cap(file, fh, arg);
}
return -EINVAL;
}
@@ -1113,6 +1145,7 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
struct v4l2_format *p = arg;
struct video_device *vfd = video_devdata(file);
bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
+ bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
@@ -1167,6 +1200,11 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
break;
CLEAR_AFTER_FIELD(p, fmt.sliced);
return ops->vidioc_s_fmt_sliced_vbi_out(file, fh, arg);
+ case V4L2_BUF_TYPE_SDR_CAPTURE:
+ if (unlikely(!is_rx || !is_sdr || !ops->vidioc_s_fmt_sdr_cap))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.sdr);
+ return ops->vidioc_s_fmt_sdr_cap(file, fh, arg);
}
return -EINVAL;
}
@@ -1177,6 +1215,7 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,
struct v4l2_format *p = arg;
struct video_device *vfd = video_devdata(file);
bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
+ bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
@@ -1231,6 +1270,11 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,
break;
CLEAR_AFTER_FIELD(p, fmt.sliced);
return ops->vidioc_try_fmt_sliced_vbi_out(file, fh, arg);
+ case V4L2_BUF_TYPE_SDR_CAPTURE:
+ if (unlikely(!is_rx || !is_sdr || !ops->vidioc_try_fmt_sdr_cap))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.sdr);
+ return ops->vidioc_try_fmt_sdr_cap(file, fh, arg);
}
return -EINVAL;
}
@@ -1291,8 +1335,11 @@ static int v4l_g_frequency(const struct v4l2_ioctl_ops *ops,
struct video_device *vfd = video_devdata(file);
struct v4l2_frequency *p = arg;
- p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
- V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+ if (vfd->vfl_type == VFL_TYPE_SDR)
+ p->type = V4L2_TUNER_ADC;
+ else
+ p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
+ V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
return ops->vidioc_g_frequency(file, fh, p);
}
@@ -1303,10 +1350,15 @@ static int v4l_s_frequency(const struct v4l2_ioctl_ops *ops,
const struct v4l2_frequency *p = arg;
enum v4l2_tuner_type type;
- type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
- V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
- if (p->type != type)
- return -EINVAL;
+ if (vfd->vfl_type == VFL_TYPE_SDR) {
+ if (p->type != V4L2_TUNER_ADC && p->type != V4L2_TUNER_RF)
+ return -EINVAL;
+ } else {
+ type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
+ V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+ if (type != p->type)
+ return -EINVAL;
+ }
return ops->vidioc_s_frequency(file, fh, p);
}
@@ -1386,6 +1438,10 @@ static int v4l_s_hw_freq_seek(const struct v4l2_ioctl_ops *ops,
struct v4l2_hw_freq_seek *p = arg;
enum v4l2_tuner_type type;
+ /* s_hw_freq_seek is not supported for SDR for now */
+ if (vfd->vfl_type == VFL_TYPE_SDR)
+ return -EINVAL;
+
type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
if (p->type != type)
@@ -1885,11 +1941,16 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops,
enum v4l2_tuner_type type;
int err;
- type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
- V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
-
- if (type != p->type)
- return -EINVAL;
+ if (vfd->vfl_type == VFL_TYPE_SDR) {
+ if (p->type != V4L2_TUNER_ADC && p->type != V4L2_TUNER_RF)
+ return -EINVAL;
+ type = p->type;
+ } else {
+ type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
+ V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+ if (type != p->type)
+ return -EINVAL;
+ }
if (ops->vidioc_enum_freq_bands)
return ops->vidioc_enum_freq_bands(file, fh, p);
if (is_valid_ioctl(vfd, VIDIOC_G_TUNER)) {
@@ -2009,6 +2070,8 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {
IOCTL_INFO_FNC(VIDIOC_QUERYMENU, v4l_querymenu, v4l_print_querymenu, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_querymenu, index)),
IOCTL_INFO_STD(VIDIOC_G_INPUT, vidioc_g_input, v4l_print_u32, 0),
IOCTL_INFO_FNC(VIDIOC_S_INPUT, v4l_s_input, v4l_print_u32, INFO_FL_PRIO),
+ IOCTL_INFO_STD(VIDIOC_G_EDID, vidioc_g_edid, v4l_print_edid, INFO_FL_CLEAR(v4l2_edid, edid)),
+ IOCTL_INFO_STD(VIDIOC_S_EDID, vidioc_s_edid, v4l_print_edid, INFO_FL_PRIO | INFO_FL_CLEAR(v4l2_edid, edid)),
IOCTL_INFO_STD(VIDIOC_G_OUTPUT, vidioc_g_output, v4l_print_u32, 0),
IOCTL_INFO_FNC(VIDIOC_S_OUTPUT, v4l_s_output, v4l_print_u32, INFO_FL_PRIO),
IOCTL_INFO_FNC(VIDIOC_ENUMOUTPUT, v4l_enumoutput, v4l_print_enumoutput, INFO_FL_CLEAR(v4l2_output, index)),
@@ -2221,9 +2284,9 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
break;
}
- case VIDIOC_SUBDEV_G_EDID:
- case VIDIOC_SUBDEV_S_EDID: {
- struct v4l2_subdev_edid *edid = parg;
+ case VIDIOC_G_EDID:
+ case VIDIOC_S_EDID: {
+ struct v4l2_edid *edid = parg;
if (edid->blocks) {
if (edid->blocks > 256) {
diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c
index 42e3e8a5e361..b4ed9a955fbe 100644
--- a/drivers/media/v4l2-core/v4l2-of.c
+++ b/drivers/media/v4l2-core/v4l2-of.c
@@ -127,17 +127,9 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node,
int v4l2_of_parse_endpoint(const struct device_node *node,
struct v4l2_of_endpoint *endpoint)
{
- struct device_node *port_node = of_get_parent(node);
-
- memset(endpoint, 0, offsetof(struct v4l2_of_endpoint, head));
-
- endpoint->local_node = node;
- /*
- * It doesn't matter whether the two calls below succeed.
- * If they don't then the default value 0 is used.
- */
- of_property_read_u32(port_node, "reg", &endpoint->port);
- of_property_read_u32(node, "reg", &endpoint->id);
+ of_graph_parse_endpoint(node, &endpoint->base);
+ endpoint->bus_type = 0;
+ memset(&endpoint->bus, 0, sizeof(endpoint->bus));
v4l2_of_parse_csi_bus(node, endpoint);
/*
@@ -147,125 +139,6 @@ int v4l2_of_parse_endpoint(const struct device_node *node,
if (endpoint->bus.mipi_csi2.flags == 0)
v4l2_of_parse_parallel_bus(node, endpoint);
- of_node_put(port_node);
-
return 0;
}
EXPORT_SYMBOL(v4l2_of_parse_endpoint);
-
-/**
- * v4l2_of_get_next_endpoint() - get next endpoint node
- * @parent: pointer to the parent device node
- * @prev: previous endpoint node, or NULL to get first
- *
- * Return: An 'endpoint' node pointer with refcount incremented. Refcount
- * of the passed @prev node is not decremented, the caller have to use
- * of_node_put() on it when done.
- */
-struct device_node *v4l2_of_get_next_endpoint(const struct device_node *parent,
- struct device_node *prev)
-{
- struct device_node *endpoint;
- struct device_node *port = NULL;
-
- if (!parent)
- return NULL;
-
- if (!prev) {
- struct device_node *node;
- /*
- * It's the first call, we have to find a port subnode
- * within this node or within an optional 'ports' node.
- */
- node = of_get_child_by_name(parent, "ports");
- if (node)
- parent = node;
-
- port = of_get_child_by_name(parent, "port");
-
- if (port) {
- /* Found a port, get an endpoint. */
- endpoint = of_get_next_child(port, NULL);
- of_node_put(port);
- } else {
- endpoint = NULL;
- }
-
- if (!endpoint)
- pr_err("%s(): no endpoint nodes specified for %s\n",
- __func__, parent->full_name);
- of_node_put(node);
- } else {
- port = of_get_parent(prev);
- if (!port)
- /* Hm, has someone given us the root node ?... */
- return NULL;
-
- /* Avoid dropping prev node refcount to 0. */
- of_node_get(prev);
- endpoint = of_get_next_child(port, prev);
- if (endpoint) {
- of_node_put(port);
- return endpoint;
- }
-
- /* No more endpoints under this port, try the next one. */
- do {
- port = of_get_next_child(parent, port);
- if (!port)
- return NULL;
- } while (of_node_cmp(port->name, "port"));
-
- /* Pick up the first endpoint in this port. */
- endpoint = of_get_next_child(port, NULL);
- of_node_put(port);
- }
-
- return endpoint;
-}
-EXPORT_SYMBOL(v4l2_of_get_next_endpoint);
-
-/**
- * v4l2_of_get_remote_port_parent() - get remote port's parent node
- * @node: pointer to a local endpoint device_node
- *
- * Return: Remote device node associated with remote endpoint node linked
- * to @node. Use of_node_put() on it when done.
- */
-struct device_node *v4l2_of_get_remote_port_parent(
- const struct device_node *node)
-{
- struct device_node *np;
- unsigned int depth;
-
- /* Get remote endpoint node. */
- np = of_parse_phandle(node, "remote-endpoint", 0);
-
- /* Walk 3 levels up only if there is 'ports' node. */
- for (depth = 3; depth && np; depth--) {
- np = of_get_next_parent(np);
- if (depth == 2 && of_node_cmp(np->name, "ports"))
- break;
- }
- return np;
-}
-EXPORT_SYMBOL(v4l2_of_get_remote_port_parent);
-
-/**
- * v4l2_of_get_remote_port() - get remote port node
- * @node: pointer to a local endpoint device_node
- *
- * Return: Remote port node associated with remote endpoint node linked
- * to @node. Use of_node_put() on it when done.
- */
-struct device_node *v4l2_of_get_remote_port(const struct device_node *node)
-{
- struct device_node *np;
-
- /* Get remote endpoint node. */
- np = of_parse_phandle(node, "remote-endpoint", 0);
- if (!np)
- return NULL;
- return of_get_next_parent(np);
-}
-EXPORT_SYMBOL(v4l2_of_get_remote_port);
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 996c248dea42..aea84ac5688a 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -349,10 +349,10 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
sd, pad, set_selection, subdev_fh, sel);
}
- case VIDIOC_SUBDEV_G_EDID:
+ case VIDIOC_G_EDID:
return v4l2_subdev_call(sd, pad, get_edid, arg);
- case VIDIOC_SUBDEV_S_EDID:
+ case VIDIOC_S_EDID:
return v4l2_subdev_call(sd, pad, set_edid, arg);
#endif
default:
@@ -368,6 +368,17 @@ static long subdev_ioctl(struct file *file, unsigned int cmd,
return video_usercopy(file, cmd, arg, subdev_do_ioctl);
}
+#ifdef CONFIG_COMPAT
+static long subdev_compat_ioctl32(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+
+ return v4l2_subdev_call(sd, core, compat_ioctl32, cmd, arg);
+}
+#endif
+
static unsigned int subdev_poll(struct file *file, poll_table *wait)
{
struct video_device *vdev = video_devdata(file);
@@ -389,6 +400,9 @@ const struct v4l2_file_operations v4l2_subdev_fops = {
.owner = THIS_MODULE,
.open = subdev_open,
.unlocked_ioctl = subdev_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl32 = subdev_compat_ioctl32,
+#endif
.release = subdev_close,
.poll = subdev_poll,
};
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index a127925c9d61..f9059bb73840 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -33,17 +33,74 @@ module_param(debug, int, 0644);
printk(KERN_DEBUG "vb2: " fmt, ## arg); \
} while (0)
-#define call_memop(q, op, args...) \
- (((q)->mem_ops->op) ? \
- ((q)->mem_ops->op(args)) : 0)
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+
+/*
+ * If advanced debugging is on, then count how often each op is called,
+ * which can either be per-buffer or per-queue.
+ *
+ * If the op failed then the 'fail_' variant is called to decrease the
+ * counter. That makes it easy to check that the 'init' and 'cleanup'
+ * (and variations thereof) stay balanced.
+ */
+
+#define call_memop(vb, op, args...) \
+({ \
+ struct vb2_queue *_q = (vb)->vb2_queue; \
+ dprintk(2, "call_memop(%p, %d, %s)%s\n", \
+ _q, (vb)->v4l2_buf.index, #op, \
+ _q->mem_ops->op ? "" : " (nop)"); \
+ (vb)->cnt_mem_ ## op++; \
+ _q->mem_ops->op ? _q->mem_ops->op(args) : 0; \
+})
+#define fail_memop(vb, op) ((vb)->cnt_mem_ ## op--)
+
+#define call_qop(q, op, args...) \
+({ \
+ dprintk(2, "call_qop(%p, %s)%s\n", q, #op, \
+ (q)->ops->op ? "" : " (nop)"); \
+ (q)->cnt_ ## op++; \
+ (q)->ops->op ? (q)->ops->op(args) : 0; \
+})
+#define fail_qop(q, op) ((q)->cnt_ ## op--)
+
+#define call_vb_qop(vb, op, args...) \
+({ \
+ struct vb2_queue *_q = (vb)->vb2_queue; \
+ dprintk(2, "call_vb_qop(%p, %d, %s)%s\n", \
+ _q, (vb)->v4l2_buf.index, #op, \
+ _q->ops->op ? "" : " (nop)"); \
+ (vb)->cnt_ ## op++; \
+ _q->ops->op ? _q->ops->op(args) : 0; \
+})
+#define fail_vb_qop(vb, op) ((vb)->cnt_ ## op--)
+
+#else
+
+#define call_memop(vb, op, args...) \
+ ((vb)->vb2_queue->mem_ops->op ? (vb)->vb2_queue->mem_ops->op(args) : 0)
+#define fail_memop(vb, op)
#define call_qop(q, op, args...) \
- (((q)->ops->op) ? ((q)->ops->op(args)) : 0)
+ ((q)->ops->op ? (q)->ops->op(args) : 0)
+#define fail_qop(q, op)
+#define call_vb_qop(vb, op, args...) \
+ ((vb)->vb2_queue->ops->op ? (vb)->vb2_queue->ops->op(args) : 0)
+#define fail_vb_qop(vb, op)
+
+#endif
+
+/* Flags that are set by the vb2 core */
#define V4L2_BUFFER_MASK_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \
V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR | \
V4L2_BUF_FLAG_PREPARED | \
V4L2_BUF_FLAG_TIMESTAMP_MASK)
+/* Output buffer flags that should be passed on to the driver */
+#define V4L2_BUFFER_OUT_FLAGS (V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME | \
+ V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_TIMECODE)
+
+static void __vb2_queue_cancel(struct vb2_queue *q);
/**
* __vb2_buf_mem_alloc() - allocate video memory for the given buffer
@@ -61,7 +118,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
for (plane = 0; plane < vb->num_planes; ++plane) {
unsigned long size = PAGE_ALIGN(q->plane_sizes[plane]);
- mem_priv = call_memop(q, alloc, q->alloc_ctx[plane],
+ mem_priv = call_memop(vb, alloc, q->alloc_ctx[plane],
size, q->gfp_flags);
if (IS_ERR_OR_NULL(mem_priv))
goto free;
@@ -73,9 +130,10 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
return 0;
free:
+ fail_memop(vb, alloc);
/* Free already allocated memory if one of the allocations failed */
for (; plane > 0; --plane) {
- call_memop(q, put, vb->planes[plane - 1].mem_priv);
+ call_memop(vb, put, vb->planes[plane - 1].mem_priv);
vb->planes[plane - 1].mem_priv = NULL;
}
@@ -87,11 +145,10 @@ free:
*/
static void __vb2_buf_mem_free(struct vb2_buffer *vb)
{
- struct vb2_queue *q = vb->vb2_queue;
unsigned int plane;
for (plane = 0; plane < vb->num_planes; ++plane) {
- call_memop(q, put, vb->planes[plane].mem_priv);
+ call_memop(vb, put, vb->planes[plane].mem_priv);
vb->planes[plane].mem_priv = NULL;
dprintk(3, "Freed plane %d of buffer %d\n", plane,
vb->v4l2_buf.index);
@@ -104,12 +161,11 @@ static void __vb2_buf_mem_free(struct vb2_buffer *vb)
*/
static void __vb2_buf_userptr_put(struct vb2_buffer *vb)
{
- struct vb2_queue *q = vb->vb2_queue;
unsigned int plane;
for (plane = 0; plane < vb->num_planes; ++plane) {
if (vb->planes[plane].mem_priv)
- call_memop(q, put_userptr, vb->planes[plane].mem_priv);
+ call_memop(vb, put_userptr, vb->planes[plane].mem_priv);
vb->planes[plane].mem_priv = NULL;
}
}
@@ -118,15 +174,15 @@ static void __vb2_buf_userptr_put(struct vb2_buffer *vb)
* __vb2_plane_dmabuf_put() - release memory associated with
* a DMABUF shared plane
*/
-static void __vb2_plane_dmabuf_put(struct vb2_queue *q, struct vb2_plane *p)
+static void __vb2_plane_dmabuf_put(struct vb2_buffer *vb, struct vb2_plane *p)
{
if (!p->mem_priv)
return;
if (p->dbuf_mapped)
- call_memop(q, unmap_dmabuf, p->mem_priv);
+ call_memop(vb, unmap_dmabuf, p->mem_priv);
- call_memop(q, detach_dmabuf, p->mem_priv);
+ call_memop(vb, detach_dmabuf, p->mem_priv);
dma_buf_put(p->dbuf);
memset(p, 0, sizeof(*p));
}
@@ -137,11 +193,10 @@ static void __vb2_plane_dmabuf_put(struct vb2_queue *q, struct vb2_plane *p)
*/
static void __vb2_buf_dmabuf_put(struct vb2_buffer *vb)
{
- struct vb2_queue *q = vb->vb2_queue;
unsigned int plane;
for (plane = 0; plane < vb->num_planes; ++plane)
- __vb2_plane_dmabuf_put(q, &vb->planes[plane]);
+ __vb2_plane_dmabuf_put(vb, &vb->planes[plane]);
}
/**
@@ -246,10 +301,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory,
* callback, if given. An error in initialization
* results in queue setup failure.
*/
- ret = call_qop(q, buf_init, vb);
+ ret = call_vb_qop(vb, buf_init, vb);
if (ret) {
dprintk(1, "Buffer %d %p initialization"
" failed\n", buffer, vb);
+ fail_vb_qop(vb, buf_init);
__vb2_buf_mem_free(vb);
kfree(vb);
break;
@@ -321,18 +377,79 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
}
/* Call driver-provided cleanup function for each buffer, if provided */
- if (q->ops->buf_cleanup) {
- for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
- ++buffer) {
- if (NULL == q->bufs[buffer])
- continue;
- q->ops->buf_cleanup(q->bufs[buffer]);
- }
+ for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
+ ++buffer) {
+ struct vb2_buffer *vb = q->bufs[buffer];
+
+ if (vb && vb->planes[0].mem_priv)
+ call_vb_qop(vb, buf_cleanup, vb);
}
/* Release video buffer memory */
__vb2_free_mem(q, buffers);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ /*
+ * Check that all the calls were balances during the life-time of this
+ * queue. If not (or if the debug level is 1 or up), then dump the
+ * counters to the kernel log.
+ */
+ if (q->num_buffers) {
+ bool unbalanced = q->cnt_start_streaming != q->cnt_stop_streaming ||
+ q->cnt_wait_prepare != q->cnt_wait_finish;
+
+ if (unbalanced || debug) {
+ pr_info("vb2: counters for queue %p:%s\n", q,
+ unbalanced ? " UNBALANCED!" : "");
+ pr_info("vb2: setup: %u start_streaming: %u stop_streaming: %u\n",
+ q->cnt_queue_setup, q->cnt_start_streaming,
+ q->cnt_stop_streaming);
+ pr_info("vb2: wait_prepare: %u wait_finish: %u\n",
+ q->cnt_wait_prepare, q->cnt_wait_finish);
+ }
+ q->cnt_queue_setup = 0;
+ q->cnt_wait_prepare = 0;
+ q->cnt_wait_finish = 0;
+ q->cnt_start_streaming = 0;
+ q->cnt_stop_streaming = 0;
+ }
+ for (buffer = 0; buffer < q->num_buffers; ++buffer) {
+ struct vb2_buffer *vb = q->bufs[buffer];
+ bool unbalanced = vb->cnt_mem_alloc != vb->cnt_mem_put ||
+ vb->cnt_mem_prepare != vb->cnt_mem_finish ||
+ vb->cnt_mem_get_userptr != vb->cnt_mem_put_userptr ||
+ vb->cnt_mem_attach_dmabuf != vb->cnt_mem_detach_dmabuf ||
+ vb->cnt_mem_map_dmabuf != vb->cnt_mem_unmap_dmabuf ||
+ vb->cnt_buf_queue != vb->cnt_buf_done ||
+ vb->cnt_buf_prepare != vb->cnt_buf_finish ||
+ vb->cnt_buf_init != vb->cnt_buf_cleanup;
+
+ if (unbalanced || debug) {
+ pr_info("vb2: counters for queue %p, buffer %d:%s\n",
+ q, buffer, unbalanced ? " UNBALANCED!" : "");
+ pr_info("vb2: buf_init: %u buf_cleanup: %u buf_prepare: %u buf_finish: %u\n",
+ vb->cnt_buf_init, vb->cnt_buf_cleanup,
+ vb->cnt_buf_prepare, vb->cnt_buf_finish);
+ pr_info("vb2: buf_queue: %u buf_done: %u\n",
+ vb->cnt_buf_queue, vb->cnt_buf_done);
+ pr_info("vb2: alloc: %u put: %u prepare: %u finish: %u mmap: %u\n",
+ vb->cnt_mem_alloc, vb->cnt_mem_put,
+ vb->cnt_mem_prepare, vb->cnt_mem_finish,
+ vb->cnt_mem_mmap);
+ pr_info("vb2: get_userptr: %u put_userptr: %u\n",
+ vb->cnt_mem_get_userptr, vb->cnt_mem_put_userptr);
+ pr_info("vb2: attach_dmabuf: %u detach_dmabuf: %u map_dmabuf: %u unmap_dmabuf: %u\n",
+ vb->cnt_mem_attach_dmabuf, vb->cnt_mem_detach_dmabuf,
+ vb->cnt_mem_map_dmabuf, vb->cnt_mem_unmap_dmabuf);
+ pr_info("vb2: get_dmabuf: %u num_users: %u vaddr: %u cookie: %u\n",
+ vb->cnt_mem_get_dmabuf,
+ vb->cnt_mem_num_users,
+ vb->cnt_mem_vaddr,
+ vb->cnt_mem_cookie);
+ }
+ }
+#endif
+
/* Free videobuf buffers */
for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
++buffer) {
@@ -341,9 +458,10 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
}
q->num_buffers -= buffers;
- if (!q->num_buffers)
+ if (!q->num_buffers) {
q->memory = 0;
- INIT_LIST_HEAD(&q->queued_list);
+ INIT_LIST_HEAD(&q->queued_list);
+ }
return 0;
}
@@ -424,7 +542,7 @@ static bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb)
* case anyway. If num_users() returns more than 1,
* we are not the only user of the plane's memory.
*/
- if (mem_priv && call_memop(q, num_users, mem_priv) > 1)
+ if (mem_priv && call_memop(vb, num_users, mem_priv) > 1)
return true;
}
return false;
@@ -484,7 +602,16 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
* Clear any buffer state related flags.
*/
b->flags &= ~V4L2_BUFFER_MASK_FLAGS;
- b->flags |= q->timestamp_type;
+ b->flags |= q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK;
+ if ((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) !=
+ V4L2_BUF_FLAG_TIMESTAMP_COPY) {
+ /*
+ * For non-COPY timestamps, drop timestamp source bits
+ * and obtain the timestamp source from the queue.
+ */
+ b->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+ b->flags |= q->timestamp_flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+ }
switch (vb->state) {
case VB2_BUF_STATE_QUEUED:
@@ -677,6 +804,12 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
return -EBUSY;
}
+ /*
+ * Call queue_cancel to clean up any buffers in the PREPARED or
+ * QUEUED state which is possible if buffers were prepared or
+ * queued without ever calling STREAMON.
+ */
+ __vb2_queue_cancel(q);
ret = __vb2_queue_free(q, q->num_buffers);
if (ret)
return ret;
@@ -693,6 +826,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
* Make sure the requested values and current defaults are sane.
*/
num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME);
+ num_buffers = max_t(unsigned int, req->count, q->min_buffers_needed);
memset(q->plane_sizes, 0, sizeof(q->plane_sizes));
memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
q->memory = req->memory;
@@ -703,26 +837,35 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
*/
ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes,
q->plane_sizes, q->alloc_ctx);
- if (ret)
+ if (ret) {
+ fail_qop(q, queue_setup);
return ret;
+ }
/* Finally, allocate buffers and video memory */
- ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes);
- if (ret == 0) {
+ allocated_buffers = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes);
+ if (allocated_buffers == 0) {
dprintk(1, "Memory allocation failed\n");
return -ENOMEM;
}
- allocated_buffers = ret;
+ /*
+ * There is no point in continuing if we can't allocate the minimum
+ * number of buffers needed by this vb2_queue.
+ */
+ if (allocated_buffers < q->min_buffers_needed)
+ ret = -ENOMEM;
/*
* Check if driver can handle the allocated number of buffers.
*/
- if (allocated_buffers < num_buffers) {
+ if (!ret && allocated_buffers < num_buffers) {
num_buffers = allocated_buffers;
ret = call_qop(q, queue_setup, q, NULL, &num_buffers,
&num_planes, q->plane_sizes, q->alloc_ctx);
+ if (ret)
+ fail_qop(q, queue_setup);
if (!ret && allocated_buffers < num_buffers)
ret = -ENOMEM;
@@ -736,6 +879,10 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
q->num_buffers = allocated_buffers;
if (ret < 0) {
+ /*
+ * Note: __vb2_queue_free() will subtract 'allocated_buffers'
+ * from q->num_buffers.
+ */
__vb2_queue_free(q, allocated_buffers);
return ret;
}
@@ -803,24 +950,24 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create
*/
ret = call_qop(q, queue_setup, q, &create->format, &num_buffers,
&num_planes, q->plane_sizes, q->alloc_ctx);
- if (ret)
+ if (ret) {
+ fail_qop(q, queue_setup);
return ret;
+ }
/* Finally, allocate buffers and video memory */
- ret = __vb2_queue_alloc(q, create->memory, num_buffers,
+ allocated_buffers = __vb2_queue_alloc(q, create->memory, num_buffers,
num_planes);
- if (ret == 0) {
+ if (allocated_buffers == 0) {
dprintk(1, "Memory allocation failed\n");
return -ENOMEM;
}
- allocated_buffers = ret;
-
/*
* Check if driver can handle the so far allocated number of buffers.
*/
- if (ret < num_buffers) {
- num_buffers = ret;
+ if (allocated_buffers < num_buffers) {
+ num_buffers = allocated_buffers;
/*
* q->num_buffers contains the total number of buffers, that the
@@ -828,6 +975,8 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create
*/
ret = call_qop(q, queue_setup, q, &create->format, &num_buffers,
&num_planes, q->plane_sizes, q->alloc_ctx);
+ if (ret)
+ fail_qop(q, queue_setup);
if (!ret && allocated_buffers < num_buffers)
ret = -ENOMEM;
@@ -841,6 +990,10 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create
q->num_buffers += allocated_buffers;
if (ret < 0) {
+ /*
+ * Note: __vb2_queue_free() will subtract 'allocated_buffers'
+ * from q->num_buffers.
+ */
__vb2_queue_free(q, allocated_buffers);
return -ENOMEM;
}
@@ -882,12 +1035,10 @@ EXPORT_SYMBOL_GPL(vb2_create_bufs);
*/
void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no)
{
- struct vb2_queue *q = vb->vb2_queue;
-
if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv)
return NULL;
- return call_memop(q, vaddr, vb->planes[plane_no].mem_priv);
+ return call_memop(vb, vaddr, vb->planes[plane_no].mem_priv);
}
EXPORT_SYMBOL_GPL(vb2_plane_vaddr);
@@ -905,12 +1056,10 @@ EXPORT_SYMBOL_GPL(vb2_plane_vaddr);
*/
void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no)
{
- struct vb2_queue *q = vb->vb2_queue;
-
if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv)
return NULL;
- return call_memop(q, cookie, vb->planes[plane_no].mem_priv);
+ return call_memop(vb, cookie, vb->planes[plane_no].mem_priv);
}
EXPORT_SYMBOL_GPL(vb2_plane_cookie);
@@ -918,13 +1067,20 @@ EXPORT_SYMBOL_GPL(vb2_plane_cookie);
* vb2_buffer_done() - inform videobuf that an operation on a buffer is finished
* @vb: vb2_buffer returned from the driver
* @state: either VB2_BUF_STATE_DONE if the operation finished successfully
- * or VB2_BUF_STATE_ERROR if the operation finished with an error
+ * or VB2_BUF_STATE_ERROR if the operation finished with an error.
+ * If start_streaming fails then it should return buffers with state
+ * VB2_BUF_STATE_QUEUED to put them back into the queue.
*
* This function should be called by the driver after a hardware operation on
* a buffer is finished and the buffer may be returned to userspace. The driver
* cannot use this buffer anymore until it is queued back to it by videobuf
* by the means of buf_queue callback. Only buffers previously queued to the
* driver by buf_queue can be passed to this function.
+ *
+ * While streaming a buffer can only be returned in state DONE or ERROR.
+ * The start_streaming op can also return them in case the DMA engine cannot
+ * be started for some reason. In that case the buffers should be returned with
+ * state QUEUED.
*/
void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
{
@@ -932,26 +1088,43 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
unsigned long flags;
unsigned int plane;
- if (vb->state != VB2_BUF_STATE_ACTIVE)
+ if (WARN_ON(vb->state != VB2_BUF_STATE_ACTIVE))
return;
- if (state != VB2_BUF_STATE_DONE && state != VB2_BUF_STATE_ERROR)
- return;
+ if (!q->start_streaming_called) {
+ if (WARN_ON(state != VB2_BUF_STATE_QUEUED))
+ state = VB2_BUF_STATE_QUEUED;
+ } else if (!WARN_ON(!q->start_streaming_called)) {
+ if (WARN_ON(state != VB2_BUF_STATE_DONE &&
+ state != VB2_BUF_STATE_ERROR))
+ state = VB2_BUF_STATE_ERROR;
+ }
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ /*
+ * Although this is not a callback, it still does have to balance
+ * with the buf_queue op. So update this counter manually.
+ */
+ vb->cnt_buf_done++;
+#endif
dprintk(4, "Done processing on buffer %d, state: %d\n",
vb->v4l2_buf.index, state);
/* sync buffers */
for (plane = 0; plane < vb->num_planes; ++plane)
- call_memop(q, finish, vb->planes[plane].mem_priv);
+ call_memop(vb, finish, vb->planes[plane].mem_priv);
/* Add the buffer to the done buffers list */
spin_lock_irqsave(&q->done_lock, flags);
vb->state = state;
- list_add_tail(&vb->done_entry, &q->done_list);
- atomic_dec(&q->queued_count);
+ if (state != VB2_BUF_STATE_QUEUED)
+ list_add_tail(&vb->done_entry, &q->done_list);
+ atomic_dec(&q->owned_by_drv_count);
spin_unlock_irqrestore(&q->done_lock, flags);
+ if (state == VB2_BUF_STATE_QUEUED)
+ return;
+
/* Inform any processes that may be waiting for buffers */
wake_up(&q->done_wq);
}
@@ -1025,9 +1198,31 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b
}
- vb->v4l2_buf.field = b->field;
- vb->v4l2_buf.timestamp = b->timestamp;
+ /* Zero flags that the vb2 core handles */
vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_MASK_FLAGS;
+ if ((vb->vb2_queue->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) !=
+ V4L2_BUF_FLAG_TIMESTAMP_COPY || !V4L2_TYPE_IS_OUTPUT(b->type)) {
+ /*
+ * Non-COPY timestamps and non-OUTPUT queues will get
+ * their timestamp and timestamp source flags from the
+ * queue.
+ */
+ vb->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+ }
+
+ if (V4L2_TYPE_IS_OUTPUT(b->type)) {
+ /*
+ * For output buffers mask out the timecode flag:
+ * this will be handled later in vb2_internal_qbuf().
+ * The 'field' is valid metadata for this output buffer
+ * and so that needs to be copied here.
+ */
+ vb->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TIMECODE;
+ vb->v4l2_buf.field = b->field;
+ } else {
+ /* Zero any output buffer flags as this is a capture buffer */
+ vb->v4l2_buf.flags &= ~V4L2_BUFFER_OUT_FLAGS;
+ }
}
/**
@@ -1041,6 +1236,7 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
unsigned int plane;
int ret;
int write = !V4L2_TYPE_IS_OUTPUT(q->type);
+ bool reacquired = vb->planes[0].mem_priv == NULL;
/* Copy relevant information provided by the userspace */
__fill_vb2_buffer(vb, b, planes);
@@ -1066,20 +1262,25 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
}
/* Release previously acquired memory if present */
- if (vb->planes[plane].mem_priv)
- call_memop(q, put_userptr, vb->planes[plane].mem_priv);
+ if (vb->planes[plane].mem_priv) {
+ if (!reacquired) {
+ reacquired = true;
+ call_vb_qop(vb, buf_cleanup, vb);
+ }
+ call_memop(vb, put_userptr, vb->planes[plane].mem_priv);
+ }
vb->planes[plane].mem_priv = NULL;
- vb->v4l2_planes[plane].m.userptr = 0;
- vb->v4l2_planes[plane].length = 0;
+ memset(&vb->v4l2_planes[plane], 0, sizeof(struct v4l2_plane));
/* Acquire each plane's memory */
- mem_priv = call_memop(q, get_userptr, q->alloc_ctx[plane],
+ mem_priv = call_memop(vb, get_userptr, q->alloc_ctx[plane],
planes[plane].m.userptr,
planes[plane].length, write);
if (IS_ERR_OR_NULL(mem_priv)) {
dprintk(1, "qbuf: failed acquiring userspace "
"memory for plane %d\n", plane);
+ fail_memop(vb, get_userptr);
ret = mem_priv ? PTR_ERR(mem_priv) : -EINVAL;
goto err;
}
@@ -1087,28 +1288,40 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
}
/*
- * Call driver-specific initialization on the newly acquired buffer,
- * if provided.
- */
- ret = call_qop(q, buf_init, vb);
- if (ret) {
- dprintk(1, "qbuf: buffer initialization failed\n");
- goto err;
- }
-
- /*
* Now that everything is in order, copy relevant information
* provided by userspace.
*/
for (plane = 0; plane < vb->num_planes; ++plane)
vb->v4l2_planes[plane] = planes[plane];
+ if (reacquired) {
+ /*
+ * One or more planes changed, so we must call buf_init to do
+ * the driver-specific initialization on the newly acquired
+ * buffer, if provided.
+ */
+ ret = call_vb_qop(vb, buf_init, vb);
+ if (ret) {
+ dprintk(1, "qbuf: buffer initialization failed\n");
+ fail_vb_qop(vb, buf_init);
+ goto err;
+ }
+ }
+
+ ret = call_vb_qop(vb, buf_prepare, vb);
+ if (ret) {
+ dprintk(1, "qbuf: buffer preparation failed\n");
+ fail_vb_qop(vb, buf_prepare);
+ call_vb_qop(vb, buf_cleanup, vb);
+ goto err;
+ }
+
return 0;
err:
/* In case of errors, release planes that were already acquired */
for (plane = 0; plane < vb->num_planes; ++plane) {
if (vb->planes[plane].mem_priv)
- call_memop(q, put_userptr, vb->planes[plane].mem_priv);
+ call_memop(vb, put_userptr, vb->planes[plane].mem_priv);
vb->planes[plane].mem_priv = NULL;
vb->v4l2_planes[plane].m.userptr = 0;
vb->v4l2_planes[plane].length = 0;
@@ -1122,8 +1335,13 @@ err:
*/
static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b)
{
+ int ret;
+
__fill_vb2_buffer(vb, b, vb->v4l2_planes);
- return 0;
+ ret = call_vb_qop(vb, buf_prepare, vb);
+ if (ret)
+ fail_vb_qop(vb, buf_prepare);
+ return ret;
}
/**
@@ -1137,6 +1355,7 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
unsigned int plane;
int ret;
int write = !V4L2_TYPE_IS_OUTPUT(q->type);
+ bool reacquired = vb->planes[0].mem_priv == NULL;
/* Copy relevant information provided by the userspace */
__fill_vb2_buffer(vb, b, planes);
@@ -1172,15 +1391,21 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
dprintk(1, "qbuf: buffer for plane %d changed\n", plane);
+ if (!reacquired) {
+ reacquired = true;
+ call_vb_qop(vb, buf_cleanup, vb);
+ }
+
/* Release previously acquired memory if present */
- __vb2_plane_dmabuf_put(q, &vb->planes[plane]);
+ __vb2_plane_dmabuf_put(vb, &vb->planes[plane]);
memset(&vb->v4l2_planes[plane], 0, sizeof(struct v4l2_plane));
/* Acquire each plane's memory */
- mem_priv = call_memop(q, attach_dmabuf, q->alloc_ctx[plane],
+ mem_priv = call_memop(vb, attach_dmabuf, q->alloc_ctx[plane],
dbuf, planes[plane].length, write);
if (IS_ERR(mem_priv)) {
dprintk(1, "qbuf: failed to attach dmabuf\n");
+ fail_memop(vb, attach_dmabuf);
ret = PTR_ERR(mem_priv);
dma_buf_put(dbuf);
goto err;
@@ -1195,32 +1420,44 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
* the buffer(s)..
*/
for (plane = 0; plane < vb->num_planes; ++plane) {
- ret = call_memop(q, map_dmabuf, vb->planes[plane].mem_priv);
+ ret = call_memop(vb, map_dmabuf, vb->planes[plane].mem_priv);
if (ret) {
dprintk(1, "qbuf: failed to map dmabuf for plane %d\n",
plane);
+ fail_memop(vb, map_dmabuf);
goto err;
}
vb->planes[plane].dbuf_mapped = 1;
}
/*
- * Call driver-specific initialization on the newly acquired buffer,
- * if provided.
- */
- ret = call_qop(q, buf_init, vb);
- if (ret) {
- dprintk(1, "qbuf: buffer initialization failed\n");
- goto err;
- }
-
- /*
* Now that everything is in order, copy relevant information
* provided by userspace.
*/
for (plane = 0; plane < vb->num_planes; ++plane)
vb->v4l2_planes[plane] = planes[plane];
+ if (reacquired) {
+ /*
+ * Call driver-specific initialization on the newly acquired buffer,
+ * if provided.
+ */
+ ret = call_vb_qop(vb, buf_init, vb);
+ if (ret) {
+ dprintk(1, "qbuf: buffer initialization failed\n");
+ fail_vb_qop(vb, buf_init);
+ goto err;
+ }
+ }
+
+ ret = call_vb_qop(vb, buf_prepare, vb);
+ if (ret) {
+ dprintk(1, "qbuf: buffer preparation failed\n");
+ fail_vb_qop(vb, buf_prepare);
+ call_vb_qop(vb, buf_cleanup, vb);
+ goto err;
+ }
+
return 0;
err:
/* In case of errors, release planes that were already acquired */
@@ -1238,13 +1475,13 @@ static void __enqueue_in_driver(struct vb2_buffer *vb)
unsigned int plane;
vb->state = VB2_BUF_STATE_ACTIVE;
- atomic_inc(&q->queued_count);
+ atomic_inc(&q->owned_by_drv_count);
/* sync buffers */
for (plane = 0; plane < vb->num_planes; ++plane)
- call_memop(q, prepare, vb->planes[plane].mem_priv);
+ call_memop(vb, prepare, vb->planes[plane].mem_priv);
- q->ops->buf_queue(vb);
+ call_vb_qop(vb, buf_queue, vb);
}
static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
@@ -1261,6 +1498,10 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
}
vb->state = VB2_BUF_STATE_PREPARING;
+ vb->v4l2_buf.timestamp.tv_sec = 0;
+ vb->v4l2_buf.timestamp.tv_usec = 0;
+ vb->v4l2_buf.sequence = 0;
+
switch (q->memory) {
case V4L2_MEMORY_MMAP:
ret = __qbuf_mmap(vb, b);
@@ -1295,8 +1536,6 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
ret = -EINVAL;
}
- if (!ret)
- ret = call_qop(q, buf_prepare, vb);
if (ret)
dprintk(1, "qbuf: buffer preparation failed: %d\n", ret);
vb->state = ret ? VB2_BUF_STATE_DEQUEUED : VB2_BUF_STATE_PREPARED;
@@ -1382,32 +1621,49 @@ EXPORT_SYMBOL_GPL(vb2_prepare_buf);
* vb2_start_streaming() - Attempt to start streaming.
* @q: videobuf2 queue
*
- * If there are not enough buffers, then retry_start_streaming is set to
- * 1 and 0 is returned. The next time a buffer is queued and
- * retry_start_streaming is 1, this function will be called again to
- * retry starting the DMA engine.
+ * Attempt to start streaming. When this function is called there must be
+ * at least q->min_buffers_needed buffers queued up (i.e. the minimum
+ * number of buffers required for the DMA engine to function). If the
+ * @start_streaming op fails it is supposed to return all the driver-owned
+ * buffers back to vb2 in state QUEUED. Check if that happened and if
+ * not warn and reclaim them forcefully.
*/
static int vb2_start_streaming(struct vb2_queue *q)
{
+ struct vb2_buffer *vb;
int ret;
- /* Tell the driver to start streaming */
- ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count));
-
/*
- * If there are not enough buffers queued to start streaming, then
- * the start_streaming operation will return -ENOBUFS and you have to
- * retry when the next buffer is queued.
+ * If any buffers were queued before streamon,
+ * we can now pass them to driver for processing.
*/
- if (ret == -ENOBUFS) {
- dprintk(1, "qbuf: not enough buffers, retry when more buffers are queued.\n");
- q->retry_start_streaming = 1;
+ list_for_each_entry(vb, &q->queued_list, queued_entry)
+ __enqueue_in_driver(vb);
+
+ /* Tell the driver to start streaming */
+ ret = call_qop(q, start_streaming, q,
+ atomic_read(&q->owned_by_drv_count));
+ q->start_streaming_called = ret == 0;
+ if (!ret)
return 0;
+
+ fail_qop(q, start_streaming);
+ dprintk(1, "qbuf: driver refused to start streaming\n");
+ if (WARN_ON(atomic_read(&q->owned_by_drv_count))) {
+ unsigned i;
+
+ /*
+ * Forcefully reclaim buffers if the driver did not
+ * correctly return them to vb2.
+ */
+ for (i = 0; i < q->num_buffers; ++i) {
+ vb = q->bufs[i];
+ if (vb->state == VB2_BUF_STATE_ACTIVE)
+ vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED);
+ }
+ /* Must be zero now */
+ WARN_ON(atomic_read(&q->owned_by_drv_count));
}
- if (ret)
- dprintk(1, "qbuf: driver refused to start streaming\n");
- else
- q->retry_start_streaming = 0;
return ret;
}
@@ -1420,11 +1676,6 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
return ret;
vb = q->bufs[b->index];
- if (vb->state != VB2_BUF_STATE_DEQUEUED) {
- dprintk(1, "%s(): invalid buffer state %d\n", __func__,
- vb->state);
- return -EINVAL;
- }
switch (vb->state) {
case VB2_BUF_STATE_DEQUEUED:
@@ -1438,7 +1689,8 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
dprintk(1, "qbuf: buffer still being prepared\n");
return -EINVAL;
default:
- dprintk(1, "qbuf: buffer already in use\n");
+ dprintk(1, "%s(): invalid buffer state %d\n", __func__,
+ vb->state);
return -EINVAL;
}
@@ -1447,19 +1699,39 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
* dequeued in dqbuf.
*/
list_add_tail(&vb->queued_entry, &q->queued_list);
+ q->queued_count++;
vb->state = VB2_BUF_STATE_QUEUED;
+ if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+ /*
+ * For output buffers copy the timestamp if needed,
+ * and the timecode field and flag if needed.
+ */
+ if ((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) ==
+ V4L2_BUF_FLAG_TIMESTAMP_COPY)
+ vb->v4l2_buf.timestamp = b->timestamp;
+ vb->v4l2_buf.flags |= b->flags & V4L2_BUF_FLAG_TIMECODE;
+ if (b->flags & V4L2_BUF_FLAG_TIMECODE)
+ vb->v4l2_buf.timecode = b->timecode;
+ }
/*
* If already streaming, give the buffer to driver for processing.
* If not, the buffer will be given to driver on next streamon.
*/
- if (q->streaming)
+ if (q->start_streaming_called)
__enqueue_in_driver(vb);
/* Fill buffer information for the userspace */
__fill_v4l2_buffer(vb, b);
- if (q->retry_start_streaming) {
+ /*
+ * If streamon has been called, and we haven't yet called
+ * start_streaming() since not enough buffers were queued, and
+ * we now have reached the minimum number of queued buffers,
+ * then we can finally call start_streaming().
+ */
+ if (q->streaming && !q->start_streaming_called &&
+ q->queued_count >= q->min_buffers_needed) {
ret = vb2_start_streaming(q);
if (ret)
return ret;
@@ -1614,8 +1886,8 @@ int vb2_wait_for_all_buffers(struct vb2_queue *q)
return -EINVAL;
}
- if (!q->retry_start_streaming)
- wait_event(q->done_wq, !atomic_read(&q->queued_count));
+ if (q->start_streaming_called)
+ wait_event(q->done_wq, !atomic_read(&q->owned_by_drv_count));
return 0;
}
EXPORT_SYMBOL_GPL(vb2_wait_for_all_buffers);
@@ -1639,7 +1911,7 @@ static void __vb2_dqbuf(struct vb2_buffer *vb)
for (i = 0; i < vb->num_planes; ++i) {
if (!vb->planes[i].dbuf_mapped)
continue;
- call_memop(q, unmap_dmabuf, vb->planes[i].mem_priv);
+ call_memop(vb, unmap_dmabuf, vb->planes[i].mem_priv);
vb->planes[i].dbuf_mapped = 0;
}
}
@@ -1657,12 +1929,6 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n
if (ret < 0)
return ret;
- ret = call_qop(q, buf_finish, vb);
- if (ret) {
- dprintk(1, "dqbuf: buffer finish failed\n");
- return ret;
- }
-
switch (vb->state) {
case VB2_BUF_STATE_DONE:
dprintk(3, "dqbuf: Returning done buffer\n");
@@ -1675,10 +1941,13 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n
return -EINVAL;
}
+ call_vb_qop(vb, buf_finish, vb);
+
/* Fill buffer information for the userspace */
__fill_v4l2_buffer(vb, b);
/* Remove from videobuf queue */
list_del(&vb->queued_entry);
+ q->queued_count--;
/* go back to dequeued state */
__vb2_dqbuf(vb);
@@ -1729,18 +1998,23 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
{
unsigned int i;
- if (q->retry_start_streaming) {
- q->retry_start_streaming = 0;
- q->streaming = 0;
- }
-
/*
* Tell driver to stop all transactions and release all queued
* buffers.
*/
- if (q->streaming)
+ if (q->start_streaming_called)
call_qop(q, stop_streaming, q);
q->streaming = 0;
+ q->start_streaming_called = 0;
+ q->queued_count = 0;
+
+ if (WARN_ON(atomic_read(&q->owned_by_drv_count))) {
+ for (i = 0; i < q->num_buffers; ++i)
+ if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE)
+ vb2_buffer_done(q->bufs[i], VB2_BUF_STATE_ERROR);
+ /* Must be zero now */
+ WARN_ON(atomic_read(&q->owned_by_drv_count));
+ }
/*
* Remove all buffers from videobuf's list...
@@ -1751,19 +2025,31 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
* has not already dequeued before initiating cancel.
*/
INIT_LIST_HEAD(&q->done_list);
- atomic_set(&q->queued_count, 0);
+ atomic_set(&q->owned_by_drv_count, 0);
wake_up_all(&q->done_wq);
/*
* Reinitialize all buffers for next use.
+ * Make sure to call buf_finish for any queued buffers. Normally
+ * that's done in dqbuf, but that's not going to happen when we
+ * cancel the whole queue. Note: this code belongs here, not in
+ * __vb2_dqbuf() since in vb2_internal_dqbuf() there is a critical
+ * call to __fill_v4l2_buffer() after buf_finish(). That order can't
+ * be changed, so we can't move the buf_finish() to __vb2_dqbuf().
*/
- for (i = 0; i < q->num_buffers; ++i)
- __vb2_dqbuf(q->bufs[i]);
+ for (i = 0; i < q->num_buffers; ++i) {
+ struct vb2_buffer *vb = q->bufs[i];
+
+ if (vb->state != VB2_BUF_STATE_DEQUEUED) {
+ vb->state = VB2_BUF_STATE_PREPARED;
+ call_vb_qop(vb, buf_finish, vb);
+ }
+ __vb2_dqbuf(vb);
+ }
}
static int vb2_internal_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
{
- struct vb2_buffer *vb;
int ret;
if (type != q->type) {
@@ -1781,18 +2067,26 @@ static int vb2_internal_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
return -EINVAL;
}
+ if (!q->num_buffers) {
+ dprintk(1, "streamon: no buffers have been allocated\n");
+ return -EINVAL;
+ }
+ if (q->num_buffers < q->min_buffers_needed) {
+ dprintk(1, "streamon: need at least %u allocated buffers\n",
+ q->min_buffers_needed);
+ return -EINVAL;
+ }
+
/*
- * If any buffers were queued before streamon,
- * we can now pass them to driver for processing.
+ * Tell driver to start streaming provided sufficient buffers
+ * are available.
*/
- list_for_each_entry(vb, &q->queued_list, queued_entry)
- __enqueue_in_driver(vb);
-
- /* Tell driver to start streaming. */
- ret = vb2_start_streaming(q);
- if (ret) {
- __vb2_queue_cancel(q);
- return ret;
+ if (q->queued_count >= q->min_buffers_needed) {
+ ret = vb2_start_streaming(q);
+ if (ret) {
+ __vb2_queue_cancel(q);
+ return ret;
+ }
}
q->streaming = 1;
@@ -1831,14 +2125,14 @@ static int vb2_internal_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
return -EINVAL;
}
- if (!q->streaming) {
- dprintk(3, "streamoff successful: not streaming\n");
- return 0;
- }
-
/*
* Cancel will pause streaming and remove all buffers from the driver
* and videobuf, effectively returning control over them to userspace.
+ *
+ * Note that we do this even if q->streaming == 0: if you prepare or
+ * queue buffers, and then call streamoff without ever having called
+ * streamon, you would still expect those buffers to be returned to
+ * their normal dequeued state.
*/
__vb2_queue_cancel(q);
@@ -1950,10 +2244,11 @@ int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb)
vb_plane = &vb->planes[eb->plane];
- dbuf = call_memop(q, get_dmabuf, vb_plane->mem_priv, eb->flags & O_ACCMODE);
+ dbuf = call_memop(vb, get_dmabuf, vb_plane->mem_priv, eb->flags & O_ACCMODE);
if (IS_ERR_OR_NULL(dbuf)) {
dprintk(1, "Failed to export buffer %d, plane %d\n",
eb->index, eb->plane);
+ fail_memop(vb, get_dmabuf);
return -EINVAL;
}
@@ -2045,9 +2340,11 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
return -EINVAL;
}
- ret = call_memop(q, mmap, vb->planes[plane].mem_priv, vma);
- if (ret)
+ ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma);
+ if (ret) {
+ fail_memop(vb, mmap);
return ret;
+ }
dprintk(3, "Buffer %d, plane %d successfully mapped\n", buffer, plane);
return 0;
@@ -2200,11 +2497,14 @@ int vb2_queue_init(struct vb2_queue *q)
WARN_ON(!q->io_modes) ||
WARN_ON(!q->ops->queue_setup) ||
WARN_ON(!q->ops->buf_queue) ||
- WARN_ON(q->timestamp_type & ~V4L2_BUF_FLAG_TIMESTAMP_MASK))
+ WARN_ON(q->timestamp_flags &
+ ~(V4L2_BUF_FLAG_TIMESTAMP_MASK |
+ V4L2_BUF_FLAG_TSTAMP_SRC_MASK)))
return -EINVAL;
/* Warn that the driver should choose an appropriate timestamp type */
- WARN_ON(q->timestamp_type == V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN);
+ WARN_ON((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) ==
+ V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN);
INIT_LIST_HEAD(&q->queued_list);
INIT_LIST_HEAD(&q->done_list);
@@ -2251,6 +2551,22 @@ struct vb2_fileio_buf {
/**
* struct vb2_fileio_data - queue context used by file io emulator
*
+ * @cur_index: the index of the buffer currently being read from or
+ * written to. If equal to q->num_buffers then a new buffer
+ * must be dequeued.
+ * @initial_index: in the read() case all buffers are queued up immediately
+ * in __vb2_init_fileio() and __vb2_perform_fileio() just cycles
+ * buffers. However, in the write() case no buffers are initially
+ * queued, instead whenever a buffer is full it is queued up by
+ * __vb2_perform_fileio(). Only once all available buffers have
+ * been queued up will __vb2_perform_fileio() start to dequeue
+ * buffers. This means that initially __vb2_perform_fileio()
+ * needs to know what buffer index to use when it is queuing up
+ * the buffers for the first time. That initial index is stored
+ * in this field. Once it is equal to q->num_buffers all
+ * available buffers have been queued and __vb2_perform_fileio()
+ * should start the normal dequeue/queue cycle.
+ *
* vb2 provides a compatibility layer and emulator of file io (read and
* write) calls on top of streaming API. For proper operation it required
* this structure to save the driver state between each call of the read
@@ -2260,7 +2576,8 @@ struct vb2_fileio_data {
struct v4l2_requestbuffers req;
struct v4l2_buffer b;
struct vb2_fileio_buf bufs[VIDEO_MAX_FRAME];
- unsigned int index;
+ unsigned int cur_index;
+ unsigned int initial_index;
unsigned int q_count;
unsigned int dq_count;
unsigned int flags;
@@ -2280,9 +2597,9 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
/*
* Sanity check
*/
- if ((read && !(q->io_modes & VB2_READ)) ||
- (!read && !(q->io_modes & VB2_WRITE)))
- BUG();
+ if (WARN_ON((read && !(q->io_modes & VB2_READ)) ||
+ (!read && !(q->io_modes & VB2_WRITE))))
+ return -EINVAL;
/*
* Check if device supports mapping buffers to kernel virtual space.
@@ -2360,7 +2677,12 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
goto err_reqbufs;
fileio->bufs[i].queued = 1;
}
- fileio->index = q->num_buffers;
+ /*
+ * All buffers have been queued, so mark that by setting
+ * initial_index to q->num_buffers
+ */
+ fileio->initial_index = q->num_buffers;
+ fileio->cur_index = q->num_buffers;
}
/*
@@ -2439,7 +2761,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
/*
* Check if we need to dequeue the buffer.
*/
- index = fileio->index;
+ index = fileio->cur_index;
if (index >= q->num_buffers) {
/*
* Call vb2_dqbuf to get buffer back.
@@ -2453,7 +2775,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
return ret;
fileio->dq_count += 1;
- index = fileio->b.index;
+ fileio->cur_index = index = fileio->b.index;
buf = &fileio->bufs[index];
/*
@@ -2529,8 +2851,20 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
buf->queued = 1;
buf->size = vb2_plane_size(q->bufs[index], 0);
fileio->q_count += 1;
- if (fileio->index < q->num_buffers)
- fileio->index++;
+ /*
+ * If we are queuing up buffers for the first time, then
+ * increase initial_index by one.
+ */
+ if (fileio->initial_index < q->num_buffers)
+ fileio->initial_index++;
+ /*
+ * The next buffer to use is either a buffer that's going to be
+ * queued for the first time (initial_index < q->num_buffers)
+ * or it is equal to q->num_buffers, meaning that the next
+ * time we need to dequeue a buffer since we've now queued up
+ * all the 'first time' buffers.
+ */
+ fileio->cur_index = fileio->initial_index;
}
/*
diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index 33d3871d1e13..880be0782dd9 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -719,7 +719,7 @@ static int vb2_dc_map_dmabuf(void *mem_priv)
/* get the associated scatterlist for this buffer */
sgt = dma_buf_map_attachment(buf->db_attach, buf->dma_dir);
- if (IS_ERR_OR_NULL(sgt)) {
+ if (IS_ERR(sgt)) {
pr_err("Error getting dmabuf scatterlist\n");
return -EINVAL;
}
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index 29a11db365bc..c59e9c96e86d 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -7,6 +7,17 @@ menuconfig MEMORY
if MEMORY
+config TI_AEMIF
+ tristate "Texas Instruments AEMIF driver"
+ depends on (ARCH_DAVINCI || ARCH_KEYSTONE) && OF
+ help
+ This driver is for the AEMIF module available in Texas Instruments
+ SoCs. AEMIF stands for Asynchronous External Memory Interface and
+ is intended to provide a glue-less interface to a variety of
+ asynchronuous memory devices like ASRAM, NOR and NAND memory. A total
+ of 256M bytes of any of these memories can be accessed at a given
+ time via four chip selects with 64M byte access per chip select.
+
config TI_EMIF
tristate "Texas Instruments EMIF driver"
depends on ARCH_OMAP2PLUS
@@ -50,4 +61,8 @@ config TEGRA30_MC
analysis, especially for IOMMU/SMMU(System Memory Management
Unit) module.
+config FSL_IFC
+ bool
+ depends on FSL_SOC
+
endif
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index 969d923dad93..71160a2b7313 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -5,7 +5,9 @@
ifeq ($(CONFIG_DDR),y)
obj-$(CONFIG_OF) += of_memory.o
endif
+obj-$(CONFIG_TI_AEMIF) += ti-aemif.o
obj-$(CONFIG_TI_EMIF) += emif.o
+obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o
obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o
obj-$(CONFIG_TEGRA30_MC) += tegra30-mc.o
diff --git a/arch/powerpc/sysdev/fsl_ifc.c b/drivers/memory/fsl_ifc.c
index fbc885b31946..3d5d792d5cb2 100644
--- a/arch/powerpc/sysdev/fsl_ifc.c
+++ b/drivers/memory/fsl_ifc.c
@@ -29,8 +29,8 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/fsl_ifc.h>
#include <asm/prom.h>
-#include <asm/fsl_ifc.h>
struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev;
EXPORT_SYMBOL(fsl_ifc_ctrl_dev);
@@ -298,7 +298,11 @@ static struct platform_driver fsl_ifc_ctrl_driver = {
.remove = fsl_ifc_ctrl_remove,
};
-module_platform_driver(fsl_ifc_ctrl_driver);
+static int __init fsl_ifc_init(void)
+{
+ return platform_driver_register(&fsl_ifc_ctrl_driver);
+}
+subsys_initcall(fsl_ifc_init);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Freescale Semiconductor");
diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c
new file mode 100644
index 000000000000..d3df7602f406
--- /dev/null
+++ b/drivers/memory/ti-aemif.c
@@ -0,0 +1,427 @@
+/*
+ * TI AEMIF driver
+ *
+ * Copyright (C) 2010 - 2013 Texas Instruments Incorporated. http://www.ti.com/
+ *
+ * Authors:
+ * Murali Karicheri <m-karicheri2@ti.com>
+ * Ivan Khoronzhuk <ivan.khoronzhuk@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 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+#define TA_SHIFT 2
+#define RHOLD_SHIFT 4
+#define RSTROBE_SHIFT 7
+#define RSETUP_SHIFT 13
+#define WHOLD_SHIFT 17
+#define WSTROBE_SHIFT 20
+#define WSETUP_SHIFT 26
+#define EW_SHIFT 30
+#define SS_SHIFT 31
+
+#define TA(x) ((x) << TA_SHIFT)
+#define RHOLD(x) ((x) << RHOLD_SHIFT)
+#define RSTROBE(x) ((x) << RSTROBE_SHIFT)
+#define RSETUP(x) ((x) << RSETUP_SHIFT)
+#define WHOLD(x) ((x) << WHOLD_SHIFT)
+#define WSTROBE(x) ((x) << WSTROBE_SHIFT)
+#define WSETUP(x) ((x) << WSETUP_SHIFT)
+#define EW(x) ((x) << EW_SHIFT)
+#define SS(x) ((x) << SS_SHIFT)
+
+#define ASIZE_MAX 0x1
+#define TA_MAX 0x3
+#define RHOLD_MAX 0x7
+#define RSTROBE_MAX 0x3f
+#define RSETUP_MAX 0xf
+#define WHOLD_MAX 0x7
+#define WSTROBE_MAX 0x3f
+#define WSETUP_MAX 0xf
+#define EW_MAX 0x1
+#define SS_MAX 0x1
+#define NUM_CS 4
+
+#define TA_VAL(x) (((x) & TA(TA_MAX)) >> TA_SHIFT)
+#define RHOLD_VAL(x) (((x) & RHOLD(RHOLD_MAX)) >> RHOLD_SHIFT)
+#define RSTROBE_VAL(x) (((x) & RSTROBE(RSTROBE_MAX)) >> RSTROBE_SHIFT)
+#define RSETUP_VAL(x) (((x) & RSETUP(RSETUP_MAX)) >> RSETUP_SHIFT)
+#define WHOLD_VAL(x) (((x) & WHOLD(WHOLD_MAX)) >> WHOLD_SHIFT)
+#define WSTROBE_VAL(x) (((x) & WSTROBE(WSTROBE_MAX)) >> WSTROBE_SHIFT)
+#define WSETUP_VAL(x) (((x) & WSETUP(WSETUP_MAX)) >> WSETUP_SHIFT)
+#define EW_VAL(x) (((x) & EW(EW_MAX)) >> EW_SHIFT)
+#define SS_VAL(x) (((x) & SS(SS_MAX)) >> SS_SHIFT)
+
+#define NRCSR_OFFSET 0x00
+#define AWCCR_OFFSET 0x04
+#define A1CR_OFFSET 0x10
+
+#define ACR_ASIZE_MASK 0x3
+#define ACR_EW_MASK BIT(30)
+#define ACR_SS_MASK BIT(31)
+#define ASIZE_16BIT 1
+
+#define CONFIG_MASK (TA(TA_MAX) | \
+ RHOLD(RHOLD_MAX) | \
+ RSTROBE(RSTROBE_MAX) | \
+ RSETUP(RSETUP_MAX) | \
+ WHOLD(WHOLD_MAX) | \
+ WSTROBE(WSTROBE_MAX) | \
+ WSETUP(WSETUP_MAX) | \
+ EW(EW_MAX) | SS(SS_MAX) | \
+ ASIZE_MAX)
+
+/**
+ * struct aemif_cs_data: structure to hold cs parameters
+ * @cs: chip-select number
+ * @wstrobe: write strobe width, ns
+ * @rstrobe: read strobe width, ns
+ * @wsetup: write setup width, ns
+ * @whold: write hold width, ns
+ * @rsetup: read setup width, ns
+ * @rhold: read hold width, ns
+ * @ta: minimum turn around time, ns
+ * @enable_ss: enable/disable select strobe mode
+ * @enable_ew: enable/disable extended wait mode
+ * @asize: width of the asynchronous device's data bus
+ */
+struct aemif_cs_data {
+ u8 cs;
+ u16 wstrobe;
+ u16 rstrobe;
+ u8 wsetup;
+ u8 whold;
+ u8 rsetup;
+ u8 rhold;
+ u8 ta;
+ u8 enable_ss;
+ u8 enable_ew;
+ u8 asize;
+};
+
+/**
+ * struct aemif_device: structure to hold device data
+ * @base: base address of AEMIF registers
+ * @clk: source clock
+ * @clk_rate: clock's rate in kHz
+ * @num_cs: number of assigned chip-selects
+ * @cs_offset: start number of cs nodes
+ * @cs_data: array of chip-select settings
+ */
+struct aemif_device {
+ void __iomem *base;
+ struct clk *clk;
+ unsigned long clk_rate;
+ u8 num_cs;
+ int cs_offset;
+ struct aemif_cs_data cs_data[NUM_CS];
+};
+
+/**
+ * aemif_calc_rate - calculate timing data.
+ * @pdev: platform device to calculate for
+ * @wanted: The cycle time needed in nanoseconds.
+ * @clk: The input clock rate in kHz.
+ * @max: The maximum divider value that can be programmed.
+ *
+ * On success, returns the calculated timing value minus 1 for easy
+ * programming into AEMIF timing registers, else negative errno.
+ */
+static int aemif_calc_rate(struct platform_device *pdev, int wanted,
+ unsigned long clk, int max)
+{
+ int result;
+
+ result = DIV_ROUND_UP((wanted * clk), NSEC_PER_MSEC) - 1;
+
+ dev_dbg(&pdev->dev, "%s: result %d from %ld, %d\n", __func__, result,
+ clk, wanted);
+
+ /* It is generally OK to have a more relaxed timing than requested... */
+ if (result < 0)
+ result = 0;
+
+ /* ... But configuring tighter timings is not an option. */
+ else if (result > max)
+ result = -EINVAL;
+
+ return result;
+}
+
+/**
+ * aemif_config_abus - configure async bus parameters
+ * @pdev: platform device to configure for
+ * @csnum: aemif chip select number
+ *
+ * This function programs the given timing values (in real clock) into the
+ * AEMIF registers taking the AEMIF clock into account.
+ *
+ * This function does not use any locking while programming the AEMIF
+ * because it is expected that there is only one user of a given
+ * chip-select.
+ *
+ * Returns 0 on success, else negative errno.
+ */
+static int aemif_config_abus(struct platform_device *pdev, int csnum)
+{
+ struct aemif_device *aemif = platform_get_drvdata(pdev);
+ struct aemif_cs_data *data = &aemif->cs_data[csnum];
+ int ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup;
+ unsigned long clk_rate = aemif->clk_rate;
+ unsigned offset;
+ u32 set, val;
+
+ offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4;
+
+ ta = aemif_calc_rate(pdev, data->ta, clk_rate, TA_MAX);
+ rhold = aemif_calc_rate(pdev, data->rhold, clk_rate, RHOLD_MAX);
+ rstrobe = aemif_calc_rate(pdev, data->rstrobe, clk_rate, RSTROBE_MAX);
+ rsetup = aemif_calc_rate(pdev, data->rsetup, clk_rate, RSETUP_MAX);
+ whold = aemif_calc_rate(pdev, data->whold, clk_rate, WHOLD_MAX);
+ wstrobe = aemif_calc_rate(pdev, data->wstrobe, clk_rate, WSTROBE_MAX);
+ wsetup = aemif_calc_rate(pdev, data->wsetup, clk_rate, WSETUP_MAX);
+
+ if (ta < 0 || rhold < 0 || rstrobe < 0 || rsetup < 0 ||
+ whold < 0 || wstrobe < 0 || wsetup < 0) {
+ dev_err(&pdev->dev, "%s: cannot get suitable timings\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ set = TA(ta) | RHOLD(rhold) | RSTROBE(rstrobe) | RSETUP(rsetup) |
+ WHOLD(whold) | WSTROBE(wstrobe) | WSETUP(wsetup);
+
+ set |= (data->asize & ACR_ASIZE_MASK);
+ if (data->enable_ew)
+ set |= ACR_EW_MASK;
+ if (data->enable_ss)
+ set |= ACR_SS_MASK;
+
+ val = readl(aemif->base + offset);
+ val &= ~CONFIG_MASK;
+ val |= set;
+ writel(val, aemif->base + offset);
+
+ return 0;
+}
+
+static inline int aemif_cycles_to_nsec(int val, unsigned long clk_rate)
+{
+ return ((val + 1) * NSEC_PER_MSEC) / clk_rate;
+}
+
+/**
+ * aemif_get_hw_params - function to read hw register values
+ * @pdev: platform device to read for
+ * @csnum: aemif chip select number
+ *
+ * This function reads the defaults from the registers and update
+ * the timing values. Required for get/set commands and also for
+ * the case when driver needs to use defaults in hardware.
+ */
+static void aemif_get_hw_params(struct platform_device *pdev, int csnum)
+{
+ struct aemif_device *aemif = platform_get_drvdata(pdev);
+ struct aemif_cs_data *data = &aemif->cs_data[csnum];
+ unsigned long clk_rate = aemif->clk_rate;
+ u32 val, offset;
+
+ offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4;
+ val = readl(aemif->base + offset);
+
+ data->ta = aemif_cycles_to_nsec(TA_VAL(val), clk_rate);
+ data->rhold = aemif_cycles_to_nsec(RHOLD_VAL(val), clk_rate);
+ data->rstrobe = aemif_cycles_to_nsec(RSTROBE_VAL(val), clk_rate);
+ data->rsetup = aemif_cycles_to_nsec(RSETUP_VAL(val), clk_rate);
+ data->whold = aemif_cycles_to_nsec(WHOLD_VAL(val), clk_rate);
+ data->wstrobe = aemif_cycles_to_nsec(WSTROBE_VAL(val), clk_rate);
+ data->wsetup = aemif_cycles_to_nsec(WSETUP_VAL(val), clk_rate);
+ data->enable_ew = EW_VAL(val);
+ data->enable_ss = SS_VAL(val);
+ data->asize = val & ASIZE_MAX;
+}
+
+/**
+ * of_aemif_parse_abus_config - parse CS configuration from DT
+ * @pdev: platform device to parse for
+ * @np: device node ptr
+ *
+ * This function update the emif async bus configuration based on the values
+ * configured in a cs device binding node.
+ */
+static int of_aemif_parse_abus_config(struct platform_device *pdev,
+ struct device_node *np)
+{
+ struct aemif_device *aemif = platform_get_drvdata(pdev);
+ struct aemif_cs_data *data;
+ u32 cs;
+ u32 val;
+
+ if (of_property_read_u32(np, "ti,cs-chipselect", &cs)) {
+ dev_dbg(&pdev->dev, "cs property is required");
+ return -EINVAL;
+ }
+
+ if (cs - aemif->cs_offset >= NUM_CS || cs < aemif->cs_offset) {
+ dev_dbg(&pdev->dev, "cs number is incorrect %d", cs);
+ return -EINVAL;
+ }
+
+ if (aemif->num_cs >= NUM_CS) {
+ dev_dbg(&pdev->dev, "cs count is more than %d", NUM_CS);
+ return -EINVAL;
+ }
+
+ data = &aemif->cs_data[aemif->num_cs];
+ data->cs = cs;
+
+ /* read the current value in the hw register */
+ aemif_get_hw_params(pdev, aemif->num_cs++);
+
+ /* override the values from device node */
+ if (!of_property_read_u32(np, "ti,cs-min-turnaround-ns", &val))
+ data->ta = val;
+
+ if (!of_property_read_u32(np, "ti,cs-read-hold-ns", &val))
+ data->rhold = val;
+
+ if (!of_property_read_u32(np, "ti,cs-read-strobe-ns", &val))
+ data->rstrobe = val;
+
+ if (!of_property_read_u32(np, "ti,cs-read-setup-ns", &val))
+ data->rsetup = val;
+
+ if (!of_property_read_u32(np, "ti,cs-write-hold-ns", &val))
+ data->whold = val;
+
+ if (!of_property_read_u32(np, "ti,cs-write-strobe-ns", &val))
+ data->wstrobe = val;
+
+ if (!of_property_read_u32(np, "ti,cs-write-setup-ns", &val))
+ data->wsetup = val;
+
+ if (!of_property_read_u32(np, "ti,cs-bus-width", &val))
+ if (val == 16)
+ data->asize = 1;
+ data->enable_ew = of_property_read_bool(np, "ti,cs-extended-wait-mode");
+ data->enable_ss = of_property_read_bool(np, "ti,cs-select-strobe-mode");
+ return 0;
+}
+
+static const struct of_device_id aemif_of_match[] = {
+ { .compatible = "ti,davinci-aemif", },
+ { .compatible = "ti,da850-aemif", },
+ {},
+};
+
+static int aemif_probe(struct platform_device *pdev)
+{
+ int i;
+ int ret = -ENODEV;
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *child_np;
+ struct aemif_device *aemif;
+
+ if (np == NULL)
+ return 0;
+
+ aemif = devm_kzalloc(dev, sizeof(*aemif), GFP_KERNEL);
+ if (!aemif)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, aemif);
+
+ aemif->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(aemif->clk)) {
+ dev_err(dev, "cannot get clock 'aemif'\n");
+ return PTR_ERR(aemif->clk);
+ }
+
+ clk_prepare_enable(aemif->clk);
+ aemif->clk_rate = clk_get_rate(aemif->clk) / MSEC_PER_SEC;
+
+ if (of_device_is_compatible(np, "ti,da850-aemif"))
+ aemif->cs_offset = 2;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ aemif->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(aemif->base)) {
+ ret = PTR_ERR(aemif->base);
+ goto error;
+ }
+
+ /*
+ * For every controller device node, there is a cs device node that
+ * describe the bus configuration parameters. This functions iterate
+ * over these nodes and update the cs data array.
+ */
+ for_each_available_child_of_node(np, child_np) {
+ ret = of_aemif_parse_abus_config(pdev, child_np);
+ if (ret < 0)
+ goto error;
+ }
+
+ for (i = 0; i < aemif->num_cs; i++) {
+ ret = aemif_config_abus(pdev, i);
+ if (ret < 0) {
+ dev_err(dev, "Error configuring chip select %d\n",
+ aemif->cs_data[i].cs);
+ goto error;
+ }
+ }
+
+ /*
+ * Create a child devices explicitly from here to
+ * guarantee that the child will be probed after the AEMIF timing
+ * parameters are set.
+ */
+ for_each_available_child_of_node(np, child_np) {
+ ret = of_platform_populate(child_np, NULL, NULL, dev);
+ if (ret < 0)
+ goto error;
+ }
+
+ return 0;
+error:
+ clk_disable_unprepare(aemif->clk);
+ return ret;
+}
+
+static int aemif_remove(struct platform_device *pdev)
+{
+ struct aemif_device *aemif = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(aemif->clk);
+ return 0;
+}
+
+static struct platform_driver aemif_driver = {
+ .probe = aemif_probe,
+ .remove = aemif_remove,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(aemif_of_match),
+ },
+};
+
+module_platform_driver(aemif_driver);
+
+MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
+MODULE_AUTHOR("Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>");
+MODULE_DESCRIPTION("Texas Instruments AEMIF driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" KBUILD_MODNAME);
diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c
index a60c188c2bd9..04bd3b6de401 100644
--- a/drivers/message/i2o/i2o_config.c
+++ b/drivers/message/i2o/i2o_config.c
@@ -754,19 +754,19 @@ static long i2o_cfg_compat_ioctl(struct file *file, unsigned cmd,
unsigned long arg)
{
int ret;
- mutex_lock(&i2o_cfg_mutex);
switch (cmd) {
case I2OGETIOPS:
ret = i2o_cfg_ioctl(file, cmd, arg);
break;
case I2OPASSTHRU32:
+ mutex_lock(&i2o_cfg_mutex);
ret = i2o_cfg_passthru32(file, cmd, arg);
+ mutex_unlock(&i2o_cfg_mutex);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
- mutex_unlock(&i2o_cfg_mutex);
return ret;
}
diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c
index a8c08f332da0..92752fb5b2d3 100644
--- a/drivers/message/i2o/iop.c
+++ b/drivers/message/i2o/iop.c
@@ -652,6 +652,44 @@ static int i2o_iop_activate(struct i2o_controller *c)
return i2o_hrt_get(c);
};
+static void i2o_res_alloc(struct i2o_controller *c, unsigned long flags)
+{
+ i2o_status_block *sb = c->status_block.virt;
+ struct resource *res = &c->mem_resource;
+ resource_size_t size, align;
+ int err;
+
+ res->name = c->pdev->bus->name;
+ res->flags = flags;
+ res->start = 0;
+ res->end = 0;
+ osm_info("%s: requires private memory resources.\n", c->name);
+
+ if (flags & IORESOURCE_MEM) {
+ size = sb->desired_mem_size;
+ align = 1 << 20; /* unspecified, use 1Mb and play safe */
+ } else {
+ size = sb->desired_io_size;
+ align = 1 << 12; /* unspecified, use 4Kb and play safe */
+ }
+
+ err = pci_bus_alloc_resource(c->pdev->bus, res, size, align, 0, 0,
+ NULL, NULL);
+ if (err < 0)
+ return;
+
+ if (flags & IORESOURCE_MEM) {
+ c->mem_alloc = 1;
+ sb->current_mem_size = resource_size(res);
+ sb->current_mem_base = res->start;
+ } else if (flags & IORESOURCE_IO) {
+ c->io_alloc = 1;
+ sb->current_io_size = resource_size(res);
+ sb->current_io_base = res->start;
+ }
+ osm_info("%s: allocated PCI space %pR\n", c->name, res);
+}
+
/**
* i2o_iop_systab_set - Set the I2O System Table of the specified IOP
* @c: I2O controller to which the system table should be send
@@ -665,52 +703,13 @@ static int i2o_iop_systab_set(struct i2o_controller *c)
struct i2o_message *msg;
i2o_status_block *sb = c->status_block.virt;
struct device *dev = &c->pdev->dev;
- struct resource *root;
int rc;
- if (sb->current_mem_size < sb->desired_mem_size) {
- struct resource *res = &c->mem_resource;
- res->name = c->pdev->bus->name;
- res->flags = IORESOURCE_MEM;
- res->start = 0;
- res->end = 0;
- osm_info("%s: requires private memory resources.\n", c->name);
- root = pci_find_parent_resource(c->pdev, res);
- if (root == NULL)
- osm_warn("%s: Can't find parent resource!\n", c->name);
- if (root && allocate_resource(root, res, sb->desired_mem_size, sb->desired_mem_size, sb->desired_mem_size, 1 << 20, /* Unspecified, so use 1Mb and play safe */
- NULL, NULL) >= 0) {
- c->mem_alloc = 1;
- sb->current_mem_size = resource_size(res);
- sb->current_mem_base = res->start;
- osm_info("%s: allocated %llu bytes of PCI memory at "
- "0x%016llX.\n", c->name,
- (unsigned long long)resource_size(res),
- (unsigned long long)res->start);
- }
- }
+ if (sb->current_mem_size < sb->desired_mem_size)
+ i2o_res_alloc(c, IORESOURCE_MEM);
- if (sb->current_io_size < sb->desired_io_size) {
- struct resource *res = &c->io_resource;
- res->name = c->pdev->bus->name;
- res->flags = IORESOURCE_IO;
- res->start = 0;
- res->end = 0;
- osm_info("%s: requires private memory resources.\n", c->name);
- root = pci_find_parent_resource(c->pdev, res);
- if (root == NULL)
- osm_warn("%s: Can't find parent resource!\n", c->name);
- if (root && allocate_resource(root, res, sb->desired_io_size, sb->desired_io_size, sb->desired_io_size, 1 << 20, /* Unspecified, so use 1Mb and play safe */
- NULL, NULL) >= 0) {
- c->io_alloc = 1;
- sb->current_io_size = resource_size(res);
- sb->current_mem_base = res->start;
- osm_info("%s: allocated %llu bytes of PCI I/O at "
- "0x%016llX.\n", c->name,
- (unsigned long long)resource_size(res),
- (unsigned long long)res->start);
- }
- }
+ if (sb->current_io_size < sb->desired_io_size)
+ i2o_res_alloc(c, IORESOURCE_IO);
msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
if (IS_ERR(msg))
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index a45aab9f6bb1..1c3ae57082ed 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -251,8 +251,6 @@ static int arizona_apply_hardware_patch(struct arizona* arizona)
unsigned int fll, sysclk;
int ret, err;
- regcache_cache_bypass(arizona->regmap, true);
-
/* Cache existing FLL and SYSCLK settings */
ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &fll);
if (ret != 0) {
@@ -322,8 +320,6 @@ err_fll:
err);
}
- regcache_cache_bypass(arizona->regmap, false);
-
if (ret != 0)
return ret;
else
diff --git a/drivers/mfd/da9055-i2c.c b/drivers/mfd/da9055-i2c.c
index 13af7e50021e..8103e4362132 100644
--- a/drivers/mfd/da9055-i2c.c
+++ b/drivers/mfd/da9055-i2c.c
@@ -53,17 +53,25 @@ static int da9055_i2c_remove(struct i2c_client *i2c)
return 0;
}
+/*
+ * DO NOT change the device Ids. The naming is intentionally specific as both
+ * the PMIC and CODEC parts of this chip are instantiated separately as I2C
+ * devices (both have configurable I2C addresses, and are to all intents and
+ * purposes separate). As a result there are specific DA9055 ids for PMIC
+ * and CODEC, which must be different to operate together.
+ */
static struct i2c_device_id da9055_i2c_id[] = {
- {"da9055", 0},
+ {"da9055-pmic", 0},
{ }
};
+MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
static struct i2c_driver da9055_i2c_driver = {
.probe = da9055_i2c_probe,
.remove = da9055_i2c_remove,
.id_table = da9055_i2c_id,
.driver = {
- .name = "da9055",
+ .name = "da9055-pmic",
.owner = THIS_MODULE,
},
};
diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c
index ac514fb2b877..71aa14a6bfbb 100644
--- a/drivers/mfd/max14577.c
+++ b/drivers/mfd/max14577.c
@@ -173,6 +173,7 @@ static const struct i2c_device_id max14577_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, max14577_i2c_id);
+#ifdef CONFIG_PM_SLEEP
static int max14577_suspend(struct device *dev)
{
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
@@ -208,6 +209,7 @@ static int max14577_resume(struct device *dev)
return 0;
}
+#endif /* CONFIG_PM_SLEEP */
static struct of_device_id max14577_dt_match[] = {
{ .compatible = "maxim,max14577", },
diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c
index be88a3bf7b85..5adede0fb04c 100644
--- a/drivers/mfd/max8997.c
+++ b/drivers/mfd/max8997.c
@@ -164,15 +164,15 @@ static struct max8997_platform_data *max8997_i2c_parse_dt_pdata(
return pd;
}
-static inline int max8997_i2c_get_driver_data(struct i2c_client *i2c,
+static inline unsigned long max8997_i2c_get_driver_data(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) {
const struct of_device_id *match;
match = of_match_node(max8997_pmic_dt_match, i2c->dev.of_node);
- return (int)match->data;
+ return (unsigned long)match->data;
}
- return (int)id->driver_data;
+ return id->driver_data;
}
static int max8997_i2c_probe(struct i2c_client *i2c,
diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c
index 612ca404e150..5d5e186b5d8b 100644
--- a/drivers/mfd/max8998.c
+++ b/drivers/mfd/max8998.c
@@ -169,16 +169,16 @@ static struct max8998_platform_data *max8998_i2c_parse_dt_pdata(
return pd;
}
-static inline int max8998_i2c_get_driver_data(struct i2c_client *i2c,
+static inline unsigned long max8998_i2c_get_driver_data(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) {
const struct of_device_id *match;
match = of_match_node(max8998_dt_match, i2c->dev.of_node);
- return (int)(long)match->data;
+ return (unsigned long)match->data;
}
- return (int)id->driver_data;
+ return id->driver_data;
}
static int max8998_i2c_probe(struct i2c_client *i2c,
diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c
index a139798b8065..281a82747275 100644
--- a/drivers/mfd/sec-core.c
+++ b/drivers/mfd/sec-core.c
@@ -26,7 +26,9 @@
#include <linux/mfd/samsung/core.h>
#include <linux/mfd/samsung/irq.h>
#include <linux/mfd/samsung/rtc.h>
+#include <linux/mfd/samsung/s2mpa01.h>
#include <linux/mfd/samsung/s2mps11.h>
+#include <linux/mfd/samsung/s2mps14.h>
#include <linux/mfd/samsung/s5m8763.h>
#include <linux/mfd/samsung/s5m8767.h>
#include <linux/regmap.h>
@@ -69,18 +71,53 @@ static const struct mfd_cell s2mps11_devs[] = {
}
};
+static const struct mfd_cell s2mps14_devs[] = {
+ {
+ .name = "s2mps14-pmic",
+ }, {
+ .name = "s2mps14-rtc",
+ }, {
+ .name = "s2mps14-clk",
+ }
+};
+
+static const struct mfd_cell s2mpa01_devs[] = {
+ {
+ .name = "s2mpa01-pmic",
+ },
+};
+
#ifdef CONFIG_OF
static struct of_device_id sec_dt_match[] = {
{ .compatible = "samsung,s5m8767-pmic",
.data = (void *)S5M8767X,
- },
- { .compatible = "samsung,s2mps11-pmic",
+ }, {
+ .compatible = "samsung,s2mps11-pmic",
.data = (void *)S2MPS11X,
+ }, {
+ .compatible = "samsung,s2mps14-pmic",
+ .data = (void *)S2MPS14X,
+ }, {
+ .compatible = "samsung,s2mpa01-pmic",
+ .data = (void *)S2MPA01,
+ }, {
+ /* Sentinel */
},
- {},
};
#endif
+static bool s2mpa01_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case S2MPA01_REG_INT1M:
+ case S2MPA01_REG_INT2M:
+ case S2MPA01_REG_INT3M:
+ return false;
+ default:
+ return true;
+ }
+}
+
static bool s2mps11_volatile(struct device *dev, unsigned int reg)
{
switch (reg) {
@@ -111,6 +148,15 @@ static const struct regmap_config sec_regmap_config = {
.val_bits = 8,
};
+static const struct regmap_config s2mpa01_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = S2MPA01_REG_LDO_OVCB4,
+ .volatile_reg = s2mpa01_volatile,
+ .cache_type = REGCACHE_FLAT,
+};
+
static const struct regmap_config s2mps11_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -120,6 +166,15 @@ static const struct regmap_config s2mps11_regmap_config = {
.cache_type = REGCACHE_FLAT,
};
+static const struct regmap_config s2mps14_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = S2MPS14_REG_LDODSCH3,
+ .volatile_reg = s2mps11_volatile,
+ .cache_type = REGCACHE_FLAT,
+};
+
static const struct regmap_config s5m8763_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -138,9 +193,18 @@ static const struct regmap_config s5m8767_regmap_config = {
.cache_type = REGCACHE_FLAT,
};
-static const struct regmap_config sec_rtc_regmap_config = {
+static const struct regmap_config s5m_rtc_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = SEC_RTC_REG_MAX,
+};
+
+static const struct regmap_config s2mps14_rtc_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
+
+ .max_register = S2MPS_RTC_REG_MAX,
};
#ifdef CONFIG_OF
@@ -180,24 +244,24 @@ static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata(
}
#endif
-static inline int sec_i2c_get_driver_data(struct i2c_client *i2c,
+static inline unsigned long sec_i2c_get_driver_data(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
#ifdef CONFIG_OF
if (i2c->dev.of_node) {
const struct of_device_id *match;
match = of_match_node(sec_dt_match, i2c->dev.of_node);
- return (int)match->data;
+ return (unsigned long)match->data;
}
#endif
- return (int)id->driver_data;
+ return id->driver_data;
}
static int sec_pmic_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev);
- const struct regmap_config *regmap;
+ const struct regmap_config *regmap, *regmap_rtc;
struct sec_pmic_dev *sec_pmic;
int ret;
@@ -229,17 +293,34 @@ static int sec_pmic_probe(struct i2c_client *i2c,
}
switch (sec_pmic->device_type) {
+ case S2MPA01:
+ regmap = &s2mpa01_regmap_config;
+ break;
case S2MPS11X:
regmap = &s2mps11_regmap_config;
+ /*
+ * The rtc-s5m driver does not support S2MPS11 and there
+ * is no mfd_cell for S2MPS11 RTC device.
+ * However we must pass something to devm_regmap_init_i2c()
+ * so use S5M-like regmap config even though it wouldn't work.
+ */
+ regmap_rtc = &s5m_rtc_regmap_config;
+ break;
+ case S2MPS14X:
+ regmap = &s2mps14_regmap_config;
+ regmap_rtc = &s2mps14_rtc_regmap_config;
break;
case S5M8763X:
regmap = &s5m8763_regmap_config;
+ regmap_rtc = &s5m_rtc_regmap_config;
break;
case S5M8767X:
regmap = &s5m8767_regmap_config;
+ regmap_rtc = &s5m_rtc_regmap_config;
break;
default:
regmap = &sec_regmap_config;
+ regmap_rtc = &s5m_rtc_regmap_config;
break;
}
@@ -252,10 +333,13 @@ static int sec_pmic_probe(struct i2c_client *i2c,
}
sec_pmic->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
+ if (!sec_pmic->rtc) {
+ dev_err(&i2c->dev, "Failed to allocate I2C for RTC\n");
+ return -ENODEV;
+ }
i2c_set_clientdata(sec_pmic->rtc, sec_pmic);
- sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc,
- &sec_rtc_regmap_config);
+ sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc, regmap_rtc);
if (IS_ERR(sec_pmic->regmap_rtc)) {
ret = PTR_ERR(sec_pmic->regmap_rtc);
dev_err(&i2c->dev, "Failed to allocate RTC register map: %d\n",
@@ -283,10 +367,18 @@ static int sec_pmic_probe(struct i2c_client *i2c,
ret = mfd_add_devices(sec_pmic->dev, -1, s5m8767_devs,
ARRAY_SIZE(s5m8767_devs), NULL, 0, NULL);
break;
+ case S2MPA01:
+ ret = mfd_add_devices(sec_pmic->dev, -1, s2mpa01_devs,
+ ARRAY_SIZE(s2mpa01_devs), NULL, 0, NULL);
+ break;
case S2MPS11X:
ret = mfd_add_devices(sec_pmic->dev, -1, s2mps11_devs,
ARRAY_SIZE(s2mps11_devs), NULL, 0, NULL);
break;
+ case S2MPS14X:
+ ret = mfd_add_devices(sec_pmic->dev, -1, s2mps14_devs,
+ ARRAY_SIZE(s2mps14_devs), NULL, 0, NULL);
+ break;
default:
/* If this happens the probe function is problem */
BUG();
@@ -315,6 +407,7 @@ static int sec_pmic_remove(struct i2c_client *i2c)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
static int sec_pmic_suspend(struct device *dev)
{
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
@@ -349,6 +442,7 @@ static int sec_pmic_resume(struct device *dev)
return 0;
}
+#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, sec_pmic_suspend, sec_pmic_resume);
diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c
index 4de494f51d40..64e7913aadc6 100644
--- a/drivers/mfd/sec-irq.c
+++ b/drivers/mfd/sec-irq.c
@@ -1,7 +1,7 @@
/*
* sec-irq.c
*
- * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd
* http://www.samsung.com
*
* This program is free software; you can redistribute it and/or modify it
@@ -19,6 +19,7 @@
#include <linux/mfd/samsung/core.h>
#include <linux/mfd/samsung/irq.h>
#include <linux/mfd/samsung/s2mps11.h>
+#include <linux/mfd/samsung/s2mps14.h>
#include <linux/mfd/samsung/s5m8763.h>
#include <linux/mfd/samsung/s5m8767.h>
@@ -59,13 +60,13 @@ static const struct regmap_irq s2mps11_irqs[] = {
.reg_offset = 1,
.mask = S2MPS11_IRQ_RTC60S_MASK,
},
- [S2MPS11_IRQ_RTCA1] = {
+ [S2MPS11_IRQ_RTCA0] = {
.reg_offset = 1,
- .mask = S2MPS11_IRQ_RTCA1_MASK,
+ .mask = S2MPS11_IRQ_RTCA0_MASK,
},
- [S2MPS11_IRQ_RTCA2] = {
+ [S2MPS11_IRQ_RTCA1] = {
.reg_offset = 1,
- .mask = S2MPS11_IRQ_RTCA2_MASK,
+ .mask = S2MPS11_IRQ_RTCA1_MASK,
},
[S2MPS11_IRQ_SMPL] = {
.reg_offset = 1,
@@ -89,6 +90,76 @@ static const struct regmap_irq s2mps11_irqs[] = {
},
};
+static const struct regmap_irq s2mps14_irqs[] = {
+ [S2MPS14_IRQ_PWRONF] = {
+ .reg_offset = 0,
+ .mask = S2MPS11_IRQ_PWRONF_MASK,
+ },
+ [S2MPS14_IRQ_PWRONR] = {
+ .reg_offset = 0,
+ .mask = S2MPS11_IRQ_PWRONR_MASK,
+ },
+ [S2MPS14_IRQ_JIGONBF] = {
+ .reg_offset = 0,
+ .mask = S2MPS11_IRQ_JIGONBF_MASK,
+ },
+ [S2MPS14_IRQ_JIGONBR] = {
+ .reg_offset = 0,
+ .mask = S2MPS11_IRQ_JIGONBR_MASK,
+ },
+ [S2MPS14_IRQ_ACOKBF] = {
+ .reg_offset = 0,
+ .mask = S2MPS11_IRQ_ACOKBF_MASK,
+ },
+ [S2MPS14_IRQ_ACOKBR] = {
+ .reg_offset = 0,
+ .mask = S2MPS11_IRQ_ACOKBR_MASK,
+ },
+ [S2MPS14_IRQ_PWRON1S] = {
+ .reg_offset = 0,
+ .mask = S2MPS11_IRQ_PWRON1S_MASK,
+ },
+ [S2MPS14_IRQ_MRB] = {
+ .reg_offset = 0,
+ .mask = S2MPS11_IRQ_MRB_MASK,
+ },
+ [S2MPS14_IRQ_RTC60S] = {
+ .reg_offset = 1,
+ .mask = S2MPS11_IRQ_RTC60S_MASK,
+ },
+ [S2MPS14_IRQ_RTCA1] = {
+ .reg_offset = 1,
+ .mask = S2MPS11_IRQ_RTCA1_MASK,
+ },
+ [S2MPS14_IRQ_RTCA0] = {
+ .reg_offset = 1,
+ .mask = S2MPS11_IRQ_RTCA0_MASK,
+ },
+ [S2MPS14_IRQ_SMPL] = {
+ .reg_offset = 1,
+ .mask = S2MPS11_IRQ_SMPL_MASK,
+ },
+ [S2MPS14_IRQ_RTC1S] = {
+ .reg_offset = 1,
+ .mask = S2MPS11_IRQ_RTC1S_MASK,
+ },
+ [S2MPS14_IRQ_WTSR] = {
+ .reg_offset = 1,
+ .mask = S2MPS11_IRQ_WTSR_MASK,
+ },
+ [S2MPS14_IRQ_INT120C] = {
+ .reg_offset = 2,
+ .mask = S2MPS11_IRQ_INT120C_MASK,
+ },
+ [S2MPS14_IRQ_INT140C] = {
+ .reg_offset = 2,
+ .mask = S2MPS11_IRQ_INT140C_MASK,
+ },
+ [S2MPS14_IRQ_TSD] = {
+ .reg_offset = 2,
+ .mask = S2MPS14_IRQ_TSD_MASK,
+ },
+};
static const struct regmap_irq s5m8767_irqs[] = {
[S5M8767_IRQ_PWRR] = {
@@ -246,6 +317,16 @@ static const struct regmap_irq_chip s2mps11_irq_chip = {
.ack_base = S2MPS11_REG_INT1,
};
+static const struct regmap_irq_chip s2mps14_irq_chip = {
+ .name = "s2mps14",
+ .irqs = s2mps14_irqs,
+ .num_irqs = ARRAY_SIZE(s2mps14_irqs),
+ .num_regs = 3,
+ .status_base = S2MPS14_REG_INT1,
+ .mask_base = S2MPS14_REG_INT1M,
+ .ack_base = S2MPS14_REG_INT1,
+};
+
static const struct regmap_irq_chip s5m8767_irq_chip = {
.name = "s5m8767",
.irqs = s5m8767_irqs,
@@ -297,6 +378,12 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic)
sec_pmic->irq_base, &s2mps11_irq_chip,
&sec_pmic->irq_data);
break;
+ case S2MPS14X:
+ ret = regmap_add_irq_chip(sec_pmic->regmap_pmic, sec_pmic->irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ sec_pmic->irq_base, &s2mps14_irq_chip,
+ &sec_pmic->irq_data);
+ break;
default:
dev_err(sec_pmic->dev, "Unknown device type %d\n",
sec_pmic->device_type);
diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c
index 966cf65c5c36..3cc4c7084b92 100644
--- a/drivers/mfd/tps65217.c
+++ b/drivers/mfd/tps65217.c
@@ -158,7 +158,7 @@ static int tps65217_probe(struct i2c_client *client,
{
struct tps65217 *tps;
unsigned int version;
- unsigned int chip_id = ids->driver_data;
+ unsigned long chip_id = ids->driver_data;
const struct of_device_id *match;
bool status_off = false;
int ret;
@@ -170,7 +170,7 @@ static int tps65217_probe(struct i2c_client *client,
"Failed to find matching dt id\n");
return -EINVAL;
}
- chip_id = (unsigned int)(unsigned long)match->data;
+ chip_id = (unsigned long)match->data;
status_off = of_property_read_bool(client->dev.of_node,
"ti,pmic-shutdown-controller");
}
diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c
index 1e9a4b2102f9..bffc584e4a43 100644
--- a/drivers/mfd/wm5102-tables.c
+++ b/drivers/mfd/wm5102-tables.c
@@ -80,8 +80,7 @@ static const struct reg_default wm5102_revb_patch[] = {
int wm5102_patch(struct arizona *arizona)
{
const struct reg_default *wm5102_patch;
- int ret = 0;
- int i, patch_size;
+ int patch_size;
switch (arizona->rev) {
case 0:
@@ -92,21 +91,9 @@ int wm5102_patch(struct arizona *arizona)
patch_size = ARRAY_SIZE(wm5102_revb_patch);
}
- regcache_cache_bypass(arizona->regmap, true);
-
- for (i = 0; i < patch_size; i++) {
- ret = regmap_write(arizona->regmap, wm5102_patch[i].reg,
- wm5102_patch[i].def);
- if (ret != 0) {
- dev_err(arizona->dev, "Failed to write %x = %x: %d\n",
- wm5102_patch[i].reg, wm5102_patch[i].def, ret);
- goto out;
- }
- }
-
-out:
- regcache_cache_bypass(arizona->regmap, false);
- return ret;
+ return regmap_multi_reg_write_bypassed(arizona->regmap,
+ wm5102_patch,
+ patch_size);
}
static const struct regmap_irq wm5102_aod_irqs[ARIZONA_NUM_IRQ] = {
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index ba04f1bc70eb..e6fab94e2c8a 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -636,7 +636,7 @@ static int wm8994_i2c_probe(struct i2c_client *i2c,
if (i2c->dev.of_node) {
of_id = of_match_device(wm8994_of_match, &i2c->dev);
if (of_id)
- wm8994->type = (int)of_id->data;
+ wm8994->type = (enum wm8994_type)of_id->data;
} else {
wm8994->type = id->driver_data;
}
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 6cb388e8fb7d..1cb74085e410 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -235,7 +235,7 @@ config SGI_XP
config CS5535_MFGPT
tristate "CS5535/CS5536 Geode Multi-Function General Purpose Timer (MFGPT) support"
- depends on PCI && X86 && MFD_CS5535
+ depends on MFD_CS5535
default n
help
This driver provides access to MFGPT functionality for other
@@ -526,4 +526,5 @@ source "drivers/misc/mei/Kconfig"
source "drivers/misc/vmw_vmci/Kconfig"
source "drivers/misc/mic/Kconfig"
source "drivers/misc/genwqe/Kconfig"
+source "drivers/misc/echo/Kconfig"
endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 99b9424ce31d..7eb4b69580c0 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -54,3 +54,4 @@ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o
obj-$(CONFIG_SRAM) += sram.o
obj-y += mic/
obj-$(CONFIG_GENWQE) += genwqe/
+obj-$(CONFIG_ECHO) += echo/
diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c
index d3eee113baeb..a43053daad0e 100644
--- a/drivers/misc/ad525x_dpot.c
+++ b/drivers/misc/ad525x_dpot.c
@@ -72,7 +72,6 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
diff --git a/drivers/misc/apds9802als.c b/drivers/misc/apds9802als.c
index 0c6e037153d2..c6cc3dc8ae1f 100644
--- a/drivers/misc/apds9802als.c
+++ b/drivers/misc/apds9802als.c
@@ -22,7 +22,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/err.h>
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c
index 5be808406edc..22de13727641 100644
--- a/drivers/misc/atmel-ssc.c
+++ b/drivers/misc/atmel-ssc.c
@@ -150,6 +150,12 @@ static int ssc_probe(struct platform_device *pdev)
return -ENODEV;
ssc->pdata = (struct atmel_ssc_platform_data *)plat_dat;
+ if (pdev->dev.of_node) {
+ struct device_node *np = pdev->dev.of_node;
+ ssc->clk_from_rk_pin =
+ of_property_read_bool(np, "atmel,clk-from-rk-pin");
+ }
+
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ssc->regs = devm_ioremap_resource(&pdev->dev, regs);
if (IS_ERR(ssc->regs))
diff --git a/drivers/misc/bmp085.c b/drivers/misc/bmp085.c
index 820e53d0048f..9b313f7810f5 100644
--- a/drivers/misc/bmp085.c
+++ b/drivers/misc/bmp085.c
@@ -47,7 +47,6 @@
#include <linux/module.h>
#include <linux/device.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/of.h>
#include "bmp085.h"
diff --git a/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c
index 9e2b985293fc..14d90eae605b 100644
--- a/drivers/misc/carma/carma-fpga.c
+++ b/drivers/misc/carma/carma-fpga.c
@@ -101,7 +101,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/poll.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kref.h>
#include <linux/io.h>
diff --git a/drivers/misc/ds1682.c b/drivers/misc/ds1682.c
index 154b02e5094f..6a672f9ef522 100644
--- a/drivers/misc/ds1682.c
+++ b/drivers/misc/ds1682.c
@@ -32,7 +32,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/string.h>
#include <linux/list.h>
diff --git a/drivers/staging/echo/Kconfig b/drivers/misc/echo/Kconfig
index f1d41ea9cd48..f1d41ea9cd48 100644
--- a/drivers/staging/echo/Kconfig
+++ b/drivers/misc/echo/Kconfig
diff --git a/drivers/staging/echo/Makefile b/drivers/misc/echo/Makefile
index 7d4caac12a8d..7d4caac12a8d 100644
--- a/drivers/staging/echo/Makefile
+++ b/drivers/misc/echo/Makefile
diff --git a/drivers/staging/echo/echo.c b/drivers/misc/echo/echo.c
index 9597e9523cac..9597e9523cac 100644
--- a/drivers/staging/echo/echo.c
+++ b/drivers/misc/echo/echo.c
diff --git a/drivers/staging/echo/echo.h b/drivers/misc/echo/echo.h
index 9b08c63e6369..9b08c63e6369 100644
--- a/drivers/staging/echo/echo.h
+++ b/drivers/misc/echo/echo.h
diff --git a/drivers/staging/echo/fir.h b/drivers/misc/echo/fir.h
index 7b9fabf1fea5..7b9fabf1fea5 100644
--- a/drivers/staging/echo/fir.h
+++ b/drivers/misc/echo/fir.h
diff --git a/drivers/staging/echo/oslec.h b/drivers/misc/echo/oslec.h
index f4175360ce27..f4175360ce27 100644
--- a/drivers/staging/echo/oslec.h
+++ b/drivers/misc/echo/oslec.h
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index 4f3bca1003a1..634f72929e12 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -10,7 +10,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
diff --git a/drivers/misc/eeprom/eeprom.c b/drivers/misc/eeprom/eeprom.c
index f0fa4e8ca124..33f8673d23a6 100644
--- a/drivers/misc/eeprom/eeprom.c
+++ b/drivers/misc/eeprom/eeprom.c
@@ -17,7 +17,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c
index 78e55b501c94..9ebeacdb8ec4 100644
--- a/drivers/misc/eeprom/eeprom_93xx46.c
+++ b/drivers/misc/eeprom/eeprom_93xx46.c
@@ -11,7 +11,6 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
diff --git a/drivers/misc/eeprom/max6875.c b/drivers/misc/eeprom/max6875.c
index e36157d5d3ab..580ff9df5529 100644
--- a/drivers/misc/eeprom/max6875.c
+++ b/drivers/misc/eeprom/max6875.c
@@ -27,7 +27,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
diff --git a/drivers/misc/eeprom/sunxi_sid.c b/drivers/misc/eeprom/sunxi_sid.c
index 9c34e5704304..3f2b625b2032 100644
--- a/drivers/misc/eeprom/sunxi_sid.c
+++ b/drivers/misc/eeprom/sunxi_sid.c
@@ -21,7 +21,6 @@
#include <linux/err.h>
#include <linux/export.h>
#include <linux/fs.h>
-#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
@@ -96,7 +95,7 @@ static int sunxi_sid_remove(struct platform_device *pdev)
}
static const struct of_device_id sunxi_sid_of_match[] = {
- { .compatible = "allwinner,sun4i-sid", .data = (void *)16},
+ { .compatible = "allwinner,sun4i-a10-sid", .data = (void *)16},
{ .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512},
{/* sentinel */},
};
diff --git a/drivers/misc/genwqe/card_debugfs.c b/drivers/misc/genwqe/card_debugfs.c
index 3bfdc07a7248..50d2096ea1c7 100644
--- a/drivers/misc/genwqe/card_debugfs.c
+++ b/drivers/misc/genwqe/card_debugfs.c
@@ -26,7 +26,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c
index 8f8a6b327cdb..2c2c9cc75231 100644
--- a/drivers/misc/genwqe/card_dev.c
+++ b/drivers/misc/genwqe/card_dev.c
@@ -787,6 +787,7 @@ static int genwqe_pin_mem(struct genwqe_file *cfile, struct genwqe_mem *m)
if (rc != 0) {
dev_err(&pci_dev->dev,
"[%s] genwqe_user_vmap rc=%d\n", __func__, rc);
+ kfree(dma_map);
return rc;
}
diff --git a/drivers/misc/hmc6352.c b/drivers/misc/hmc6352.c
index 170bd3daf336..90520d76633f 100644
--- a/drivers/misc/hmc6352.c
+++ b/drivers/misc/hmc6352.c
@@ -22,7 +22,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/err.h>
diff --git a/drivers/misc/isl29003.c b/drivers/misc/isl29003.c
index e3183f26216b..12c30b486b27 100644
--- a/drivers/misc/isl29003.c
+++ b/drivers/misc/isl29003.c
@@ -26,7 +26,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
diff --git a/drivers/misc/isl29020.c b/drivers/misc/isl29020.c
index b7f84dacf822..4a9c50a43afb 100644
--- a/drivers/misc/isl29020.c
+++ b/drivers/misc/isl29020.c
@@ -23,7 +23,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/err.h>
diff --git a/drivers/misc/lattice-ecp3-config.c b/drivers/misc/lattice-ecp3-config.c
index 61fbe6acabef..0a1565e63c71 100644
--- a/drivers/misc/lattice-ecp3-config.c
+++ b/drivers/misc/lattice-ecp3-config.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/spi/spi.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c
index 036effe9a795..3ef4627f9cb1 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d.c
@@ -23,7 +23,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/dmi.h>
#include <linux/module.h>
#include <linux/types.h>
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
index 7c97550240f1..d324f8a97b88 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
@@ -26,7 +26,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_spi.c b/drivers/misc/lis3lv02d/lis3lv02d_spi.c
index 9aa2bd2a71ae..bd06d0cfac45 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d_spi.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d_spi.c
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/err.h>
#include <linux/input.h>
#include <linux/interrupt.h>
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c
index 49c7a23f02fc..d66a2f24f6b3 100644
--- a/drivers/misc/lkdtm.c
+++ b/drivers/misc/lkdtm.c
@@ -30,6 +30,7 @@
*
* See Documentation/fault-injection/provoke-crashes.txt for instructions
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/fs.h>
@@ -45,6 +46,7 @@
#include <linux/debugfs.h>
#include <linux/vmalloc.h>
#include <linux/mman.h>
+#include <asm/cacheflush.h>
#ifdef CONFIG_IDE
#include <linux/ide.h>
@@ -101,6 +103,7 @@ enum ctype {
CT_EXEC_USERSPACE,
CT_ACCESS_USERSPACE,
CT_WRITE_RO,
+ CT_WRITE_KERN,
};
static char* cp_name[] = {
@@ -137,6 +140,7 @@ static char* cp_type[] = {
"EXEC_USERSPACE",
"ACCESS_USERSPACE",
"WRITE_RO",
+ "WRITE_KERN",
};
static struct jprobe lkdtm;
@@ -316,6 +320,13 @@ static void do_nothing(void)
return;
}
+/* Must immediately follow do_nothing for size calculuations to work out. */
+static void do_overwritten(void)
+{
+ pr_info("do_overwritten wasn't overwritten!\n");
+ return;
+}
+
static noinline void corrupt_stack(void)
{
/* Use default char array length that triggers stack protection. */
@@ -328,7 +339,12 @@ static void execute_location(void *dst)
{
void (*func)(void) = dst;
+ pr_info("attempting ok execution at %p\n", do_nothing);
+ do_nothing();
+
memcpy(dst, do_nothing, EXEC_SIZE);
+ flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE);
+ pr_info("attempting bad execution at %p\n", func);
func();
}
@@ -337,8 +353,13 @@ static void execute_user_location(void *dst)
/* Intentionally crossing kernel/user memory boundary. */
void (*func)(void) = dst;
+ pr_info("attempting ok execution at %p\n", do_nothing);
+ do_nothing();
+
if (copy_to_user((void __user *)dst, do_nothing, EXEC_SIZE))
return;
+ flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE);
+ pr_info("attempting bad execution at %p\n", func);
func();
}
@@ -463,8 +484,12 @@ static void lkdtm_do_action(enum ctype which)
}
ptr = (unsigned long *)user_addr;
+
+ pr_info("attempting bad read at %p\n", ptr);
tmp = *ptr;
tmp += 0xc0dec0de;
+
+ pr_info("attempting bad write at %p\n", ptr);
*ptr = tmp;
vm_munmap(user_addr, PAGE_SIZE);
@@ -475,10 +500,28 @@ static void lkdtm_do_action(enum ctype which)
unsigned long *ptr;
ptr = (unsigned long *)&rodata;
+
+ pr_info("attempting bad write at %p\n", ptr);
*ptr ^= 0xabcd1234;
break;
}
+ case CT_WRITE_KERN: {
+ size_t size;
+ unsigned char *ptr;
+
+ size = (unsigned long)do_overwritten -
+ (unsigned long)do_nothing;
+ ptr = (unsigned char *)do_overwritten;
+
+ pr_info("attempting bad %zu byte write at %p\n", size, ptr);
+ memcpy(ptr, (unsigned char *)do_nothing, size);
+ flush_icache_range((unsigned long)ptr,
+ (unsigned long)(ptr + size));
+
+ do_overwritten();
+ break;
+ }
case CT_NONE:
default:
break;
@@ -493,8 +536,8 @@ static void lkdtm_handler(void)
spin_lock_irqsave(&count_lock, flags);
count--;
- printk(KERN_INFO "lkdtm: Crash point %s of type %s hit, trigger in %d rounds\n",
- cp_name_to_str(cpoint), cp_type_to_str(cptype), count);
+ pr_info("Crash point %s of type %s hit, trigger in %d rounds\n",
+ cp_name_to_str(cpoint), cp_type_to_str(cptype), count);
if (count == 0) {
do_it = true;
@@ -551,18 +594,18 @@ static int lkdtm_register_cpoint(enum cname which)
lkdtm.kp.symbol_name = "generic_ide_ioctl";
lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl;
#else
- printk(KERN_INFO "lkdtm: Crash point not available\n");
+ pr_info("Crash point not available\n");
return -EINVAL;
#endif
break;
default:
- printk(KERN_INFO "lkdtm: Invalid Crash Point\n");
+ pr_info("Invalid Crash Point\n");
return -EINVAL;
}
cpoint = which;
if ((ret = register_jprobe(&lkdtm)) < 0) {
- printk(KERN_INFO "lkdtm: Couldn't register jprobe\n");
+ pr_info("Couldn't register jprobe\n");
cpoint = CN_INVALID;
}
@@ -709,8 +752,7 @@ static ssize_t direct_entry(struct file *f, const char __user *user_buf,
if (type == CT_NONE)
return -EINVAL;
- printk(KERN_INFO "lkdtm: Performing direct entry %s\n",
- cp_type_to_str(type));
+ pr_info("Performing direct entry %s\n", cp_type_to_str(type));
lkdtm_do_action(type);
*off += count;
@@ -772,7 +814,7 @@ static int __init lkdtm_module_init(void)
/* Register debugfs interface */
lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL);
if (!lkdtm_debugfs_root) {
- printk(KERN_ERR "lkdtm: creating root dir failed\n");
+ pr_err("creating root dir failed\n");
return -ENODEV;
}
@@ -787,28 +829,26 @@ static int __init lkdtm_module_init(void)
de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root,
NULL, &cur->fops);
if (de == NULL) {
- printk(KERN_ERR "lkdtm: could not create %s\n",
- cur->name);
+ pr_err("could not create %s\n", cur->name);
goto out_err;
}
}
if (lkdtm_parse_commandline() == -EINVAL) {
- printk(KERN_INFO "lkdtm: Invalid command\n");
+ pr_info("Invalid command\n");
goto out_err;
}
if (cpoint != CN_INVALID && cptype != CT_NONE) {
ret = lkdtm_register_cpoint(cpoint);
if (ret < 0) {
- printk(KERN_INFO "lkdtm: Invalid crash point %d\n",
- cpoint);
+ pr_info("Invalid crash point %d\n", cpoint);
goto out_err;
}
- printk(KERN_INFO "lkdtm: Crash point %s of type %s registered\n",
- cpoint_name, cpoint_type);
+ pr_info("Crash point %s of type %s registered\n",
+ cpoint_name, cpoint_type);
} else {
- printk(KERN_INFO "lkdtm: No crash points registered, enable through debugfs\n");
+ pr_info("No crash points registered, enable through debugfs\n");
}
return 0;
@@ -823,7 +863,7 @@ static void __exit lkdtm_module_exit(void)
debugfs_remove_recursive(lkdtm_debugfs_root);
unregister_jprobe(&lkdtm);
- printk(KERN_INFO "lkdtm: Crash point unregistered\n");
+ pr_info("Crash point unregistered\n");
}
module_init(lkdtm_module_init);
diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig
index c76fa31e9bf6..d23384dde73b 100644
--- a/drivers/misc/mei/Kconfig
+++ b/drivers/misc/mei/Kconfig
@@ -34,3 +34,12 @@ config INTEL_MEI_ME
82Q33 Express
82X38/X48 Express
+config INTEL_MEI_TXE
+ tristate "Intel Trusted Execution Environment with ME Interface"
+ select INTEL_MEI
+ depends on X86 && PCI && WATCHDOG_CORE
+ help
+ MEI Support for Trusted Execution Environment device on Intel SoCs
+
+ Supported SoCs:
+ Intel Bay Trail
diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile
index 08698a466268..8ebc6cda1373 100644
--- a/drivers/misc/mei/Makefile
+++ b/drivers/misc/mei/Makefile
@@ -1,6 +1,6 @@
#
# Makefile - Intel Management Engine Interface (Intel MEI) Linux driver
-# Copyright (c) 2010-2011, Intel Corporation.
+# Copyright (c) 2010-2014, Intel Corporation.
#
obj-$(CONFIG_INTEL_MEI) += mei.o
mei-objs := init.o
@@ -17,3 +17,7 @@ mei-$(CONFIG_DEBUG_FS) += debugfs.o
obj-$(CONFIG_INTEL_MEI_ME) += mei-me.o
mei-me-objs := pci-me.o
mei-me-objs += hw-me.o
+
+obj-$(CONFIG_INTEL_MEI_TXE) += mei-txe.o
+mei-txe-objs := pci-txe.o
+mei-txe-objs += hw-txe.o
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 2fad84432829..b8deb3455480 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -21,7 +21,6 @@
#include <linux/fcntl.h>
#include <linux/aio.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/list.h>
@@ -35,7 +34,6 @@
#include "mei_dev.h"
#include "hbm.h"
-#include "hw-me.h"
#include "client.h"
const uuid_le mei_amthif_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,
@@ -79,10 +77,9 @@ int mei_amthif_host_init(struct mei_device *dev)
i = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
if (i < 0) {
- ret = i;
dev_info(&dev->pdev->dev,
- "amthif: failed to find the client %d\n", ret);
- return ret;
+ "amthif: failed to find the client %d\n", i);
+ return -ENOTTY;
}
cl->me_client_id = dev->me_clients[i].client_id;
@@ -116,14 +113,11 @@ int mei_amthif_host_init(struct mei_device *dev)
cl->state = MEI_FILE_CONNECTING;
- if (mei_hbm_cl_connect_req(dev, cl)) {
- dev_dbg(&dev->pdev->dev, "amthif: Failed to connect to ME client\n");
- cl->state = MEI_FILE_DISCONNECTED;
- cl->host_client_id = 0;
- } else {
- cl->timer_count = MEI_CONNECT_TIMEOUT;
- }
- return 0;
+ ret = mei_cl_connect(cl, NULL);
+
+ dev->iamthif_state = MEI_IAMTHIF_IDLE;
+
+ return ret;
}
/**
@@ -137,14 +131,12 @@ int mei_amthif_host_init(struct mei_device *dev)
struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
struct file *file)
{
- struct mei_cl_cb *pos = NULL;
- struct mei_cl_cb *next = NULL;
+ struct mei_cl_cb *cb;
- list_for_each_entry_safe(pos, next,
- &dev->amthif_rd_complete_list.list, list) {
- if (pos->cl && pos->cl == &dev->iamthif_cl &&
- pos->file_object == file)
- return pos;
+ list_for_each_entry(cb, &dev->amthif_rd_complete_list.list, list) {
+ if (cb->cl && cb->cl == &dev->iamthif_cl &&
+ cb->file_object == file)
+ return cb;
}
return NULL;
}
@@ -180,14 +172,13 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
/* Only possible if we are in timeout */
if (!cl || cl != &dev->iamthif_cl) {
dev_dbg(&dev->pdev->dev, "bad file ext.\n");
- return -ETIMEDOUT;
+ return -ETIME;
}
i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id);
-
if (i < 0) {
dev_dbg(&dev->pdev->dev, "amthif client not found.\n");
- return -ENODEV;
+ return -ENOTTY;
}
dev_dbg(&dev->pdev->dev, "checking amthif data\n");
cb = mei_amthif_find_read_list_entry(dev, file);
@@ -228,7 +219,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
dev_dbg(&dev->pdev->dev, "amthif Time out\n");
/* 15 sec for the message has expired */
list_del(&cb->list);
- rets = -ETIMEDOUT;
+ rets = -ETIME;
goto free;
}
}
@@ -253,9 +244,10 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
* the buf_idx may point beyond */
length = min_t(size_t, length, (cb->buf_idx - *offset));
- if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length))
+ if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) {
+ dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n");
rets = -EFAULT;
- else {
+ } else {
rets = length;
if ((*offset + length) < cb->buf_idx) {
*offset += length;
@@ -302,9 +294,8 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
if (ret < 0)
return ret;
- if (ret && dev->hbuf_is_ready) {
+ if (ret && mei_hbuf_acquire(dev)) {
ret = 0;
- dev->hbuf_is_ready = false;
if (cb->request_buffer.size > mei_hbuf_max_len(dev)) {
mei_hdr.length = mei_hbuf_max_len(dev);
mei_hdr.msg_complete = 0;
@@ -336,10 +327,6 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
list_add_tail(&cb->list, &dev->write_list.list);
}
} else {
- if (!dev->hbuf_is_ready)
- dev_dbg(&dev->pdev->dev, "host buffer is not empty");
-
- dev_dbg(&dev->pdev->dev, "No flow control credentials, so add iamthif cb to write list.\n");
list_add_tail(&cb->list, &dev->write_list.list);
}
return 0;
@@ -365,7 +352,7 @@ int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb)
if (ret)
return ret;
- cb->fop_type = MEI_FOP_IOCTL;
+ cb->fop_type = MEI_FOP_WRITE;
if (!list_empty(&dev->amthif_cmd_list.list) ||
dev->iamthif_state != MEI_IAMTHIF_IDLE) {
@@ -447,23 +434,23 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
/**
- * mei_amthif_irq_write_completed - processes completed iamthif operation.
+ * mei_amthif_irq_write - write iamthif command in irq thread context.
*
* @dev: the device structure.
- * @slots: free slots.
* @cb_pos: callback block.
* @cl: private data of the file object.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise, error.
*/
-int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
- s32 *slots, struct mei_cl_cb *cmpl_list)
+int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
+ struct mei_cl_cb *cmpl_list)
{
struct mei_device *dev = cl->dev;
struct mei_msg_hdr mei_hdr;
size_t len = dev->iamthif_msg_buf_size - dev->iamthif_msg_buf_index;
u32 msg_slots = mei_data2slots(len);
+ int slots;
int rets;
rets = mei_cl_flow_ctrl_creds(cl);
@@ -480,13 +467,15 @@ int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
mei_hdr.reserved = 0;
mei_hdr.internal = 0;
- if (*slots >= msg_slots) {
+ slots = mei_hbuf_empty_slots(dev);
+
+ if (slots >= msg_slots) {
mei_hdr.length = len;
mei_hdr.msg_complete = 1;
/* Split the message only if we can write the whole host buffer */
- } else if (*slots == dev->hbuf_depth) {
- msg_slots = *slots;
- len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
+ } else if (slots == dev->hbuf_depth) {
+ msg_slots = slots;
+ len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
mei_hdr.length = len;
mei_hdr.msg_complete = 0;
} else {
@@ -496,7 +485,6 @@ int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr));
- *slots -= msg_slots;
rets = mei_write_message(dev, &mei_hdr,
dev->iamthif_msg_buf + dev->iamthif_msg_buf_index);
if (rets) {
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 4bc7d620d695..ddc5ac92a200 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -26,7 +26,6 @@
#include <linux/mei_cl_bus.h>
#include "mei_dev.h"
-#include "hw-me.h"
#include "client.h"
#define to_mei_cl_driver(d) container_of(d, struct mei_cl_driver, driver)
@@ -145,9 +144,9 @@ static struct device_type mei_cl_device_type = {
static struct mei_cl *mei_bus_find_mei_cl_by_uuid(struct mei_device *dev,
uuid_le uuid)
{
- struct mei_cl *cl, *next;
+ struct mei_cl *cl;
- list_for_each_entry_safe(cl, next, &dev->device_list, device_link) {
+ list_for_each_entry(cl, &dev->device_list, device_link) {
if (!uuid_le_cmp(uuid, cl->device_uuid))
return cl;
}
@@ -524,6 +523,22 @@ void mei_cl_bus_rx_event(struct mei_cl *cl)
schedule_work(&device->event_work);
}
+void mei_cl_bus_remove_devices(struct mei_device *dev)
+{
+ struct mei_cl *cl, *next;
+
+ mutex_lock(&dev->device_lock);
+ list_for_each_entry_safe(cl, next, &dev->device_list, device_link) {
+ if (cl->device)
+ mei_cl_remove_device(cl->device);
+
+ list_del(&cl->device_link);
+ mei_cl_unlink(cl);
+ kfree(cl);
+ }
+ mutex_unlock(&dev->device_lock);
+}
+
int __init mei_cl_bus_init(void)
{
return bus_register(&mei_cl_bus_type);
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 1ee2b9492a82..8c078b808cd3 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -29,20 +29,21 @@
* mei_me_cl_by_uuid - locate index of me client
*
* @dev: mei device
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
* returns me client index or -ENOENT if not found
*/
int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *uuid)
{
- int i, res = -ENOENT;
+ int i;
for (i = 0; i < dev->me_clients_num; ++i)
if (uuid_le_cmp(*uuid,
- dev->me_clients[i].props.protocol_name) == 0) {
- res = i;
- break;
- }
+ dev->me_clients[i].props.protocol_name) == 0)
+ return i;
- return res;
+ return -ENOENT;
}
@@ -60,37 +61,79 @@ int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *uuid)
int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
{
int i;
+
for (i = 0; i < dev->me_clients_num; i++)
if (dev->me_clients[i].client_id == client_id)
- break;
- if (WARN_ON(dev->me_clients[i].client_id != client_id))
- return -ENOENT;
+ return i;
- if (i == dev->me_clients_num)
- return -ENOENT;
-
- return i;
+ return -ENOENT;
}
/**
- * mei_io_list_flush - removes list entry belonging to cl.
+ * mei_cl_cmp_id - tells if the clients are the same
*
- * @list: An instance of our list structure
- * @cl: host client
+ * @cl1: host client 1
+ * @cl2: host client 2
+ *
+ * returns true - if the clients has same host and me ids
+ * false - otherwise
+ */
+static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
+ const struct mei_cl *cl2)
+{
+ return cl1 && cl2 &&
+ (cl1->host_client_id == cl2->host_client_id) &&
+ (cl1->me_client_id == cl2->me_client_id);
+}
+
+/**
+ * mei_io_list_flush - removes cbs belonging to cl.
+ *
+ * @list: an instance of our list structure
+ * @cl: host client, can be NULL for flushing the whole list
+ * @free: whether to free the cbs
*/
-void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
+static void __mei_io_list_flush(struct mei_cl_cb *list,
+ struct mei_cl *cl, bool free)
{
struct mei_cl_cb *cb;
struct mei_cl_cb *next;
+ /* enable removing everything if no cl is specified */
list_for_each_entry_safe(cb, next, &list->list, list) {
- if (cb->cl && mei_cl_cmp_id(cl, cb->cl))
+ if (!cl || (cb->cl && mei_cl_cmp_id(cl, cb->cl))) {
list_del(&cb->list);
+ if (free)
+ mei_io_cb_free(cb);
+ }
}
}
/**
+ * mei_io_list_flush - removes list entry belonging to cl.
+ *
+ * @list: An instance of our list structure
+ * @cl: host client
+ */
+static inline void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
+{
+ __mei_io_list_flush(list, cl, false);
+}
+
+
+/**
+ * mei_io_list_free - removes cb belonging to cl and free them
+ *
+ * @list: An instance of our list structure
+ * @cl: host client
+ */
+static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl)
+{
+ __mei_io_list_flush(list, cl, true);
+}
+
+/**
* mei_io_cb_free - free mei_cb_private related memory
*
* @cb: mei callback struct
@@ -196,8 +239,8 @@ int mei_cl_flush_queues(struct mei_cl *cl)
cl_dbg(dev, cl, "remove list entry belonging to cl\n");
mei_io_list_flush(&cl->dev->read_list, cl);
- mei_io_list_flush(&cl->dev->write_list, cl);
- mei_io_list_flush(&cl->dev->write_waiting_list, cl);
+ mei_io_list_free(&cl->dev->write_list, cl);
+ mei_io_list_free(&cl->dev->write_waiting_list, cl);
mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
@@ -254,10 +297,9 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev)
struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
{
struct mei_device *dev = cl->dev;
- struct mei_cl_cb *cb = NULL;
- struct mei_cl_cb *next = NULL;
+ struct mei_cl_cb *cb;
- list_for_each_entry_safe(cb, next, &dev->read_list.list, list)
+ list_for_each_entry(cb, &dev->read_list.list, list)
if (mei_cl_cmp_id(cl, cb->cl))
return cb;
return NULL;
@@ -375,6 +417,23 @@ void mei_host_client_init(struct work_struct *work)
mutex_unlock(&dev->device_lock);
}
+/**
+ * mei_hbuf_acquire: try to acquire host buffer
+ *
+ * @dev: the device structure
+ * returns true if host buffer was acquired
+ */
+bool mei_hbuf_acquire(struct mei_device *dev)
+{
+ if (!dev->hbuf_is_ready) {
+ dev_dbg(&dev->pdev->dev, "hbuf is not ready\n");
+ return false;
+ }
+
+ dev->hbuf_is_ready = false;
+
+ return true;
+}
/**
* mei_cl_disconnect - disconnect host client from the me one
@@ -406,8 +465,7 @@ int mei_cl_disconnect(struct mei_cl *cl)
return -ENOMEM;
cb->fop_type = MEI_FOP_CLOSE;
- if (dev->hbuf_is_ready) {
- dev->hbuf_is_ready = false;
+ if (mei_hbuf_acquire(dev)) {
if (mei_hbm_cl_disconnect_req(dev, cl)) {
rets = -ENODEV;
cl_err(dev, cl, "failed to disconnect.\n");
@@ -461,17 +519,17 @@ free:
bool mei_cl_is_other_connecting(struct mei_cl *cl)
{
struct mei_device *dev;
- struct mei_cl *pos;
- struct mei_cl *next;
+ struct mei_cl *ocl; /* the other client */
if (WARN_ON(!cl || !cl->dev))
return false;
dev = cl->dev;
- list_for_each_entry_safe(pos, next, &dev->file_list, link) {
- if ((pos->state == MEI_FILE_CONNECTING) &&
- (pos != cl) && cl->me_client_id == pos->me_client_id)
+ list_for_each_entry(ocl, &dev->file_list, link) {
+ if (ocl->state == MEI_FILE_CONNECTING &&
+ ocl != cl &&
+ cl->me_client_id == ocl->me_client_id)
return true;
}
@@ -505,11 +563,10 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
goto out;
}
- cb->fop_type = MEI_FOP_IOCTL;
-
- if (dev->hbuf_is_ready && !mei_cl_is_other_connecting(cl)) {
- dev->hbuf_is_ready = false;
+ cb->fop_type = MEI_FOP_CONNECT;
+ /* run hbuf acquire last so we don't have to undo */
+ if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
if (mei_hbm_cl_connect_req(dev, cl)) {
rets = -ENODEV;
goto out;
@@ -521,18 +578,19 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
}
mutex_unlock(&dev->device_lock);
- rets = wait_event_timeout(dev->wait_recvd_msg,
- (cl->state == MEI_FILE_CONNECTED ||
- cl->state == MEI_FILE_DISCONNECTED),
- mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
+ wait_event_timeout(dev->wait_recvd_msg,
+ (cl->state == MEI_FILE_CONNECTED ||
+ cl->state == MEI_FILE_DISCONNECTED),
+ mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
mutex_lock(&dev->device_lock);
if (cl->state != MEI_FILE_CONNECTED) {
- rets = -EFAULT;
+ /* something went really wrong */
+ if (!cl->status)
+ cl->status = -EFAULT;
mei_io_list_flush(&dev->ctrl_rd_list, cl);
mei_io_list_flush(&dev->ctrl_wr_list, cl);
- goto out;
}
rets = cl->status;
@@ -554,7 +612,8 @@ out:
int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
{
struct mei_device *dev;
- int i;
+ struct mei_me_client *me_cl;
+ int id;
if (WARN_ON(!cl || !cl->dev))
return -EINVAL;
@@ -567,19 +626,19 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
if (cl->mei_flow_ctrl_creds > 0)
return 1;
- for (i = 0; i < dev->me_clients_num; i++) {
- struct mei_me_client *me_cl = &dev->me_clients[i];
- if (me_cl->client_id == cl->me_client_id) {
- if (me_cl->mei_flow_ctrl_creds) {
- if (WARN_ON(me_cl->props.single_recv_buf == 0))
- return -EINVAL;
- return 1;
- } else {
- return 0;
- }
- }
+ id = mei_me_cl_by_id(dev, cl->me_client_id);
+ if (id < 0) {
+ cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
+ return id;
}
- return -ENOENT;
+
+ me_cl = &dev->me_clients[id];
+ if (me_cl->mei_flow_ctrl_creds) {
+ if (WARN_ON(me_cl->props.single_recv_buf == 0))
+ return -EINVAL;
+ return 1;
+ }
+ return 0;
}
/**
@@ -595,32 +654,31 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
{
struct mei_device *dev;
- int i;
+ struct mei_me_client *me_cl;
+ int id;
if (WARN_ON(!cl || !cl->dev))
return -EINVAL;
dev = cl->dev;
- if (!dev->me_clients_num)
- return -ENOENT;
+ id = mei_me_cl_by_id(dev, cl->me_client_id);
+ if (id < 0) {
+ cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
+ return id;
+ }
- for (i = 0; i < dev->me_clients_num; i++) {
- struct mei_me_client *me_cl = &dev->me_clients[i];
- if (me_cl->client_id == cl->me_client_id) {
- if (me_cl->props.single_recv_buf != 0) {
- if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
- return -EINVAL;
- dev->me_clients[i].mei_flow_ctrl_creds--;
- } else {
- if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
- return -EINVAL;
- cl->mei_flow_ctrl_creds--;
- }
- return 0;
- }
+ me_cl = &dev->me_clients[id];
+ if (me_cl->props.single_recv_buf != 0) {
+ if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
+ return -EINVAL;
+ me_cl->mei_flow_ctrl_creds--;
+ } else {
+ if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
+ return -EINVAL;
+ cl->mei_flow_ctrl_creds--;
}
- return -ENOENT;
+ return 0;
}
/**
@@ -652,7 +710,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
i = mei_me_cl_by_id(dev, cl->me_client_id);
if (i < 0) {
cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
- return -ENODEV;
+ return -ENOTTY;
}
cb = mei_io_cb_init(cl, NULL);
@@ -666,9 +724,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
goto err;
cb->fop_type = MEI_FOP_READ;
- cl->read_cb = cb;
- if (dev->hbuf_is_ready) {
- dev->hbuf_is_ready = false;
+ if (mei_hbuf_acquire(dev)) {
if (mei_hbm_cl_flow_control_req(dev, cl)) {
cl_err(dev, cl, "flow control send failed\n");
rets = -ENODEV;
@@ -678,6 +734,9 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
} else {
list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
}
+
+ cl->read_cb = cb;
+
return rets;
err:
mei_io_cb_free(cb);
@@ -685,27 +744,26 @@ err:
}
/**
- * mei_cl_irq_write_complete - write a message to device
+ * mei_cl_irq_write - write a message to device
* from the interrupt thread context
*
* @cl: client
* @cb: callback block.
- * @slots: free slots.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise error.
*/
-int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
- s32 *slots, struct mei_cl_cb *cmpl_list)
+int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
+ struct mei_cl_cb *cmpl_list)
{
struct mei_device *dev;
struct mei_msg_data *buf;
struct mei_msg_hdr mei_hdr;
size_t len;
u32 msg_slots;
+ int slots;
int rets;
-
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
@@ -722,6 +780,7 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
return 0;
}
+ slots = mei_hbuf_empty_slots(dev);
len = buf->size - cb->buf_idx;
msg_slots = mei_data2slots(len);
@@ -730,13 +789,13 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
mei_hdr.reserved = 0;
mei_hdr.internal = cb->internal;
- if (*slots >= msg_slots) {
+ if (slots >= msg_slots) {
mei_hdr.length = len;
mei_hdr.msg_complete = 1;
/* Split the message only if we can write the whole host buffer */
- } else if (*slots == dev->hbuf_depth) {
- msg_slots = *slots;
- len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
+ } else if (slots == dev->hbuf_depth) {
+ msg_slots = slots;
+ len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
mei_hdr.length = len;
mei_hdr.msg_complete = 0;
} else {
@@ -747,7 +806,6 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
cl_dbg(dev, cl, "buf: size = %d idx = %lu\n",
cb->request_buffer.size, cb->buf_idx);
- *slots -= msg_slots;
rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
if (rets) {
cl->status = rets;
@@ -800,21 +858,29 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
cb->fop_type = MEI_FOP_WRITE;
+ cb->buf_idx = 0;
+ cl->writing_state = MEI_IDLE;
+
+ mei_hdr.host_addr = cl->host_client_id;
+ mei_hdr.me_addr = cl->me_client_id;
+ mei_hdr.reserved = 0;
+ mei_hdr.msg_complete = 0;
+ mei_hdr.internal = cb->internal;
rets = mei_cl_flow_ctrl_creds(cl);
if (rets < 0)
goto err;
- /* Host buffer is not ready, we queue the request */
- if (rets == 0 || !dev->hbuf_is_ready) {
- cb->buf_idx = 0;
- /* unseting complete will enqueue the cb for write */
- mei_hdr.msg_complete = 0;
+ if (rets == 0) {
+ cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
+ rets = buf->size;
+ goto out;
+ }
+ if (!mei_hbuf_acquire(dev)) {
+ cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n");
rets = buf->size;
goto out;
}
-
- dev->hbuf_is_ready = false;
/* Check for a maximum length */
if (buf->size > mei_hbuf_max_len(dev)) {
@@ -825,12 +891,6 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
mei_hdr.msg_complete = 1;
}
- mei_hdr.host_addr = cl->host_client_id;
- mei_hdr.me_addr = cl->me_client_id;
- mei_hdr.reserved = 0;
- mei_hdr.internal = cb->internal;
-
-
rets = mei_write_message(dev, &mei_hdr, buf->data);
if (rets)
goto err;
@@ -838,13 +898,12 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
cl->writing_state = MEI_WRITING;
cb->buf_idx = mei_hdr.length;
- rets = buf->size;
out:
if (mei_hdr.msg_complete) {
- if (mei_cl_flow_ctrl_reduce(cl)) {
- rets = -ENODEV;
+ rets = mei_cl_flow_ctrl_reduce(cl);
+ if (rets < 0)
goto err;
- }
+
list_add_tail(&cb->list, &dev->write_waiting_list.list);
} else {
list_add_tail(&cb->list, &dev->write_list.list);
@@ -854,15 +913,18 @@ out:
if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
mutex_unlock(&dev->device_lock);
- if (wait_event_interruptible(cl->tx_wait,
- cl->writing_state == MEI_WRITE_COMPLETE)) {
- if (signal_pending(current))
- rets = -EINTR;
- else
- rets = -ERESTARTSYS;
- }
+ rets = wait_event_interruptible(cl->tx_wait,
+ cl->writing_state == MEI_WRITE_COMPLETE);
mutex_lock(&dev->device_lock);
+ /* wait_event_interruptible returns -ERESTARTSYS */
+ if (rets) {
+ if (signal_pending(current))
+ rets = -EINTR;
+ goto err;
+ }
}
+
+ rets = buf->size;
err:
return rets;
}
@@ -903,12 +965,11 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
void mei_cl_all_disconnect(struct mei_device *dev)
{
- struct mei_cl *cl, *next;
+ struct mei_cl *cl;
- list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+ list_for_each_entry(cl, &dev->file_list, link) {
cl->state = MEI_FILE_DISCONNECTED;
cl->mei_flow_ctrl_creds = 0;
- cl->read_cb = NULL;
cl->timer_count = 0;
}
}
@@ -921,8 +982,8 @@ void mei_cl_all_disconnect(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) {
+ struct mei_cl *cl;
+ list_for_each_entry(cl, &dev->file_list, link) {
if (waitqueue_active(&cl->rx_wait)) {
cl_dbg(dev, cl, "Waking up reading client!\n");
wake_up_interruptible(&cl->rx_wait);
@@ -941,12 +1002,8 @@ void mei_cl_all_wakeup(struct mei_device *dev)
*/
void mei_cl_all_write_clear(struct mei_device *dev)
{
- struct mei_cl_cb *cb, *next;
-
- list_for_each_entry_safe(cb, next, &dev->write_list.list, list) {
- list_del(&cb->list);
- mei_io_cb_free(cb);
- }
+ mei_io_list_free(&dev->write_list, NULL);
+ mei_io_list_free(&dev->write_waiting_list, NULL);
}
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index c8396e582f1c..96d5de0389f9 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -45,8 +45,6 @@ static inline void mei_io_list_init(struct mei_cl_cb *list)
{
INIT_LIST_HEAD(&list->list);
}
-void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl);
-
/*
* MEI Host Client Functions
*/
@@ -61,22 +59,6 @@ int mei_cl_unlink(struct mei_cl *cl);
int mei_cl_flush_queues(struct mei_cl *cl);
struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl);
-/**
- * mei_cl_cmp_id - tells if file private data have same id
- *
- * @fe1: private data of 1. file object
- * @fe2: private data of 2. file object
- *
- * returns true - if ids are the same and not NULL
- */
-static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
- const struct mei_cl *cl2)
-{
- return cl1 && cl2 &&
- (cl1->host_client_id == cl2->host_client_id) &&
- (cl1->me_client_id == cl2->me_client_id);
-}
-
int mei_cl_flow_ctrl_creds(struct mei_cl *cl);
@@ -86,15 +68,15 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl);
*/
static inline bool mei_cl_is_connected(struct mei_cl *cl)
{
- return (cl->dev &&
+ return cl->dev &&
cl->dev->dev_state == MEI_DEV_ENABLED &&
- cl->state == MEI_FILE_CONNECTED);
+ cl->state == MEI_FILE_CONNECTED;
}
static inline bool mei_cl_is_transitioning(struct mei_cl *cl)
{
- return (MEI_FILE_INITIALIZING == cl->state ||
+ return MEI_FILE_INITIALIZING == cl->state ||
MEI_FILE_DISCONNECTED == cl->state ||
- MEI_FILE_DISCONNECTING == cl->state);
+ MEI_FILE_DISCONNECTING == cl->state;
}
bool mei_cl_is_other_connecting(struct mei_cl *cl);
@@ -102,8 +84,8 @@ int mei_cl_disconnect(struct mei_cl *cl);
int mei_cl_connect(struct mei_cl *cl, struct file *file);
int mei_cl_read_start(struct mei_cl *cl, size_t length);
int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking);
-int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
- s32 *slots, struct mei_cl_cb *cmpl_list);
+int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
+ struct mei_cl_cb *cmpl_list);
void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb);
diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c
index a3ae154444b2..ced5b777c70f 100644
--- a/drivers/misc/mei/debugfs.c
+++ b/drivers/misc/mei/debugfs.c
@@ -75,6 +75,54 @@ static const struct file_operations mei_dbgfs_fops_meclients = {
.llseek = generic_file_llseek,
};
+static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ struct mei_device *dev = fp->private_data;
+ struct mei_cl *cl;
+ const size_t bufsz = 1024;
+ char *buf;
+ int i = 0;
+ int pos = 0;
+ int ret;
+
+ if (!dev)
+ return -ENODEV;
+
+ buf = kzalloc(bufsz, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ " |me|host|state|rd|wr|\n");
+
+ mutex_lock(&dev->device_lock);
+
+ /* if the driver is not enabled the list won't b consitent */
+ if (dev->dev_state != MEI_DEV_ENABLED)
+ goto out;
+
+ list_for_each_entry(cl, &dev->file_list, link) {
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "%2d|%2d|%4d|%5d|%2d|%2d|\n",
+ i, cl->me_client_id, cl->host_client_id, cl->state,
+ cl->reading_state, cl->writing_state);
+ i++;
+ }
+out:
+ mutex_unlock(&dev->device_lock);
+ ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
+
+static const struct file_operations mei_dbgfs_fops_active = {
+ .open = simple_open,
+ .read = mei_dbgfs_read_active,
+ .llseek = generic_file_llseek,
+};
+
static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
@@ -128,6 +176,12 @@ int mei_dbgfs_register(struct mei_device *dev, const char *name)
dev_err(&dev->pdev->dev, "meclients: registration failed\n");
goto err;
}
+ f = debugfs_create_file("active", S_IRUSR, dir,
+ dev, &mei_dbgfs_fops_active);
+ if (!f) {
+ dev_err(&dev->pdev->dev, "meclients: registration failed\n");
+ goto err;
+ }
f = debugfs_create_file("devstate", S_IRUSR, dir,
dev, &mei_dbgfs_fops_devstate);
if (!f) {
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 28cd74c073b9..4960288e543a 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -21,7 +21,41 @@
#include "mei_dev.h"
#include "hbm.h"
-#include "hw-me.h"
+#include "client.h"
+
+static const char *mei_cl_conn_status_str(enum mei_cl_connect_status status)
+{
+#define MEI_CL_CS(status) case MEI_CL_CONN_##status: return #status
+ switch (status) {
+ MEI_CL_CS(SUCCESS);
+ MEI_CL_CS(NOT_FOUND);
+ MEI_CL_CS(ALREADY_STARTED);
+ MEI_CL_CS(OUT_OF_RESOURCES);
+ MEI_CL_CS(MESSAGE_SMALL);
+ default: return "unknown";
+ }
+#undef MEI_CL_CCS
+}
+
+/**
+ * mei_cl_conn_status_to_errno - convert client connect response
+ * status to error code
+ *
+ * @status: client connect response status
+ *
+ * returns corresponding error code
+ */
+static int mei_cl_conn_status_to_errno(enum mei_cl_connect_status status)
+{
+ switch (status) {
+ case MEI_CL_CONN_SUCCESS: return 0;
+ case MEI_CL_CONN_NOT_FOUND: return -ENOTTY;
+ case MEI_CL_CONN_ALREADY_STARTED: return -EBUSY;
+ case MEI_CL_CONN_OUT_OF_RESOURCES: return -EBUSY;
+ case MEI_CL_CONN_MESSAGE_SMALL: return -EINVAL;
+ default: return -EINVAL;
+ }
+}
/**
* mei_hbm_me_cl_allocate - allocates storage for me clients
@@ -100,33 +134,6 @@ bool mei_hbm_cl_addr_equal(struct mei_cl *cl, void *buf)
/**
- * is_treat_specially_client - checks if the message belongs
- * to the file private data.
- *
- * @cl: private data of the file object
- * @rs: connect response bus message
- *
- */
-static bool is_treat_specially_client(struct mei_cl *cl,
- struct hbm_client_connect_response *rs)
-{
- if (mei_hbm_cl_addr_equal(cl, rs)) {
- if (!rs->status) {
- cl->state = MEI_FILE_CONNECTED;
- cl->status = 0;
-
- } else {
- cl->state = MEI_FILE_DISCONNECTED;
- cl->status = -ENODEV;
- }
- cl->timer_count = 0;
-
- return true;
- }
- return false;
-}
-
-/**
* mei_hbm_idle - set hbm to idle state
*
* @dev: the device structure
@@ -147,13 +154,13 @@ int mei_hbm_start_wait(struct mei_device *dev)
ret = wait_event_interruptible_timeout(dev->wait_recvd_msg,
dev->hbm_state == MEI_HBM_IDLE ||
dev->hbm_state >= MEI_HBM_STARTED,
- mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
+ mei_secs_to_jiffies(MEI_HBM_TIMEOUT));
mutex_lock(&dev->device_lock);
if (ret <= 0 && (dev->hbm_state <= MEI_HBM_START)) {
dev->hbm_state = MEI_HBM_IDLE;
dev_err(&dev->pdev->dev, "waiting for mei start failed\n");
- return -ETIMEDOUT;
+ return -ETIME;
}
return 0;
}
@@ -283,17 +290,18 @@ static int mei_hbm_prop_req(struct mei_device *dev)
}
/**
- * mei_hbm_stop_req_prepare - prepare stop request message
+ * mei_hbm_stop_req - send stop request message
*
* @dev - mei device
- * @mei_hdr - mei message header
- * @data - hbm message body buffer
+ * @cl: client info
+ *
+ * This function returns -EIO on write failure
*/
-static void mei_hbm_stop_req_prepare(struct mei_device *dev,
- struct mei_msg_hdr *mei_hdr, unsigned char *data)
+static int mei_hbm_stop_req(struct mei_device *dev)
{
+ struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
struct hbm_host_stop_request *req =
- (struct hbm_host_stop_request *)data;
+ (struct hbm_host_stop_request *)dev->wr_msg.data;
const size_t len = sizeof(struct hbm_host_stop_request);
mei_hbm_hdr(mei_hdr, len);
@@ -301,6 +309,8 @@ static void mei_hbm_stop_req_prepare(struct mei_device *dev,
memset(req, 0, len);
req->hbm_cmd = HOST_STOP_REQ_CMD;
req->reason = DRIVER_STOP_REQUEST;
+
+ return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
}
/**
@@ -319,8 +329,7 @@ int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
mei_hbm_hdr(mei_hdr, len);
mei_hbm_cl_hdr(cl, MEI_FLOW_CONTROL_CMD, dev->wr_msg.data, len);
- dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n",
- cl->host_client_id, cl->me_client_id);
+ cl_dbg(dev, cl, "sending flow control\n");
return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
}
@@ -330,27 +339,34 @@ int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
*
* @dev: the device structure
* @flow: flow control.
+ *
+ * return 0 on success, < 0 otherwise
*/
-static void mei_hbm_add_single_flow_creds(struct mei_device *dev,
+static int mei_hbm_add_single_flow_creds(struct mei_device *dev,
struct hbm_flow_control *flow)
{
- struct mei_me_client *client;
- int i;
-
- for (i = 0; i < dev->me_clients_num; i++) {
- client = &dev->me_clients[i];
- if (client && flow->me_addr == client->client_id) {
- if (client->props.single_recv_buf) {
- client->mei_flow_ctrl_creds++;
- dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
- flow->me_addr);
- dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
- client->mei_flow_ctrl_creds);
- } else {
- BUG(); /* error in flow control */
- }
- }
+ struct mei_me_client *me_cl;
+ int id;
+
+ id = mei_me_cl_by_id(dev, flow->me_addr);
+ if (id < 0) {
+ dev_err(&dev->pdev->dev, "no such me client %d\n",
+ flow->me_addr);
+ return id;
}
+
+ me_cl = &dev->me_clients[id];
+ if (me_cl->props.single_recv_buf) {
+ me_cl->mei_flow_ctrl_creds++;
+ dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
+ flow->me_addr);
+ dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
+ me_cl->mei_flow_ctrl_creds);
+ } else {
+ BUG(); /* error in flow control */
+ }
+
+ return 0;
}
/**
@@ -362,8 +378,7 @@ static void mei_hbm_add_single_flow_creds(struct mei_device *dev,
static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
struct hbm_flow_control *flow_control)
{
- struct mei_cl *cl = NULL;
- struct mei_cl *next = NULL;
+ struct mei_cl *cl;
if (!flow_control->host_addr) {
/* single receive buffer */
@@ -372,7 +387,7 @@ static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
}
/* normal connection */
- list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+ list_for_each_entry(cl, &dev->file_list, link) {
if (mei_hbm_cl_addr_equal(cl, flow_control)) {
cl->mei_flow_ctrl_creds++;
dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d.\n",
@@ -405,6 +420,25 @@ int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)
}
/**
+ * mei_hbm_cl_disconnect_rsp - sends disconnect respose to the FW
+ *
+ * @dev: the device structure
+ * @cl: a client to disconnect from
+ *
+ * This function returns -EIO on write failure
+ */
+int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl)
+{
+ struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
+ const size_t len = sizeof(struct hbm_client_connect_response);
+
+ mei_hbm_hdr(mei_hdr, len);
+ mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD, dev->wr_msg.data, len);
+
+ return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
+}
+
+/**
* mei_hbm_cl_disconnect_res - disconnect response from ME
*
* @dev: the device structure
@@ -414,29 +448,23 @@ static void mei_hbm_cl_disconnect_res(struct mei_device *dev,
struct hbm_client_connect_response *rs)
{
struct mei_cl *cl;
- struct mei_cl_cb *pos = NULL, *next = NULL;
-
- dev_dbg(&dev->pdev->dev,
- "disconnect_response:\n"
- "ME Client = %d\n"
- "Host Client = %d\n"
- "Status = %d\n",
- rs->me_addr,
- rs->host_addr,
- rs->status);
-
- list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
- cl = pos->cl;
-
- if (!cl) {
- list_del(&pos->list);
+ struct mei_cl_cb *cb, *next;
+
+ dev_dbg(&dev->pdev->dev, "hbm: disconnect response cl:host=%02d me=%02d status=%d\n",
+ rs->me_addr, rs->host_addr, rs->status);
+
+ list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list.list, list) {
+ cl = cb->cl;
+
+ /* this should not happen */
+ if (WARN_ON(!cl)) {
+ list_del(&cb->list);
return;
}
- dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n");
if (mei_hbm_cl_addr_equal(cl, rs)) {
- list_del(&pos->list);
- if (!rs->status)
+ list_del(&cb->list);
+ if (rs->status == MEI_CL_DISCONN_SUCCESS)
cl->state = MEI_FILE_DISCONNECTED;
cl->status = 0;
@@ -476,46 +504,41 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev,
{
struct mei_cl *cl;
- struct mei_cl_cb *pos = NULL, *next = NULL;
+ struct mei_cl_cb *cb, *next;
- dev_dbg(&dev->pdev->dev,
- "connect_response:\n"
- "ME Client = %d\n"
- "Host Client = %d\n"
- "Status = %d\n",
- rs->me_addr,
- rs->host_addr,
- rs->status);
+ dev_dbg(&dev->pdev->dev, "hbm: connect response cl:host=%02d me=%02d status=%s\n",
+ rs->me_addr, rs->host_addr,
+ mei_cl_conn_status_str(rs->status));
- /* if WD or iamthif client treat specially */
+ cl = NULL;
- if (is_treat_specially_client(&dev->wd_cl, rs)) {
- dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n");
- mei_watchdog_register(dev);
+ list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list.list, list) {
- return;
- }
+ cl = cb->cl;
+ /* this should not happen */
+ if (WARN_ON(!cl)) {
+ list_del_init(&cb->list);
+ continue;
+ }
- if (is_treat_specially_client(&dev->iamthif_cl, rs)) {
- dev->iamthif_state = MEI_IAMTHIF_IDLE;
- return;
- }
- list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
+ if (cb->fop_type != MEI_FOP_CONNECT)
+ continue;
- cl = pos->cl;
- if (!cl) {
- list_del(&pos->list);
- return;
- }
- if (pos->fop_type == MEI_FOP_IOCTL) {
- if (is_treat_specially_client(cl, rs)) {
- list_del(&pos->list);
- cl->status = 0;
- cl->timer_count = 0;
- break;
- }
+ if (mei_hbm_cl_addr_equal(cl, rs)) {
+ list_del(&cb->list);
+ break;
}
}
+
+ if (!cl)
+ return;
+
+ cl->timer_count = 0;
+ if (rs->status == MEI_CL_CONN_SUCCESS)
+ cl->state = MEI_FILE_CONNECTED;
+ else
+ cl->state = MEI_FILE_DISCONNECTED;
+ cl->status = mei_cl_conn_status_to_errno(rs->status);
}
@@ -525,32 +548,34 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev,
*
* @dev: the device structure.
* @disconnect_req: disconnect request bus message from the me
+ *
+ * returns -ENOMEM on allocation failure
*/
-static void mei_hbm_fw_disconnect_req(struct mei_device *dev,
+static int mei_hbm_fw_disconnect_req(struct mei_device *dev,
struct hbm_client_connect_request *disconnect_req)
{
- struct mei_cl *cl, *next;
- const size_t len = sizeof(struct hbm_client_connect_response);
+ struct mei_cl *cl;
+ struct mei_cl_cb *cb;
- list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+ list_for_each_entry(cl, &dev->file_list, link) {
if (mei_hbm_cl_addr_equal(cl, disconnect_req)) {
dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
disconnect_req->host_addr,
disconnect_req->me_addr);
cl->state = MEI_FILE_DISCONNECTED;
cl->timer_count = 0;
- if (cl == &dev->wd_cl)
- dev->wd_pending = false;
- else if (cl == &dev->iamthif_cl)
- dev->iamthif_timer = 0;
-
- /* prepare disconnect response */
- mei_hbm_hdr(&dev->wr_ext_msg.hdr, len);
- mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD,
- dev->wr_ext_msg.data, len);
+
+ cb = mei_io_cb_init(cl, NULL);
+ if (!cb)
+ return -ENOMEM;
+ cb->fop_type = MEI_FOP_DISCONNECT_RSP;
+ cl_dbg(dev, cl, "add disconnect response as first\n");
+ list_add(&cb->list, &dev->ctrl_wr_list.list);
+
break;
}
}
+ return 0;
}
@@ -629,10 +654,7 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
dev_warn(&dev->pdev->dev, "hbm: start: version mismatch - stopping the driver.\n");
dev->hbm_state = MEI_HBM_STOPPED;
- mei_hbm_stop_req_prepare(dev, &dev->wr_msg.hdr,
- dev->wr_msg.data);
- if (mei_write_message(dev, &dev->wr_msg.hdr,
- dev->wr_msg.data)) {
+ if (mei_hbm_stop_req(dev)) {
dev_err(&dev->pdev->dev, "hbm: start: failed to send stop request\n");
return -EIO;
}
@@ -778,10 +800,11 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
case ME_STOP_REQ_CMD:
dev_dbg(&dev->pdev->dev, "hbm: stop request: message received\n");
-
dev->hbm_state = MEI_HBM_STOPPED;
- mei_hbm_stop_req_prepare(dev, &dev->wr_ext_msg.hdr,
- dev->wr_ext_msg.data);
+ if (mei_hbm_stop_req(dev)) {
+ dev_err(&dev->pdev->dev, "hbm: start: failed to send stop request\n");
+ return -EIO;
+ }
break;
default:
BUG();
diff --git a/drivers/misc/mei/hbm.h b/drivers/misc/mei/hbm.h
index 5f92188a5cd7..20e8782711c0 100644
--- a/drivers/misc/mei/hbm.h
+++ b/drivers/misc/mei/hbm.h
@@ -54,6 +54,7 @@ int mei_hbm_start_req(struct mei_device *dev);
int mei_hbm_start_wait(struct mei_device *dev);
int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl);
int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl);
+int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl);
int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl);
bool mei_hbm_version_is_supported(struct mei_device *dev);
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 6f656c053b14..8dbdaaef1af5 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -20,10 +20,10 @@
#include <linux/interrupt.h>
#include "mei_dev.h"
-#include "hw-me.h"
-
#include "hbm.h"
+#include "hw-me.h"
+#include "hw-me-regs.h"
/**
* mei_me_reg_read - Reads 32bit data from the mei device
@@ -240,11 +240,11 @@ static int mei_me_hw_ready_wait(struct mei_device *dev)
mutex_unlock(&dev->device_lock);
err = wait_event_interruptible_timeout(dev->wait_hw_ready,
dev->recvd_hw_ready,
- mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
+ mei_secs_to_jiffies(MEI_HW_READY_TIMEOUT));
mutex_lock(&dev->device_lock);
if (!err && !dev->recvd_hw_ready) {
if (!err)
- err = -ETIMEDOUT;
+ err = -ETIME;
dev_err(&dev->pdev->dev,
"wait hw ready failed. status = %d\n", err);
return err;
@@ -303,7 +303,7 @@ static bool mei_me_hbuf_is_empty(struct mei_device *dev)
*
* @dev: the device structure
*
- * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise empty slots count
+ * returns -EOVERFLOW if overflow, otherwise empty slots count
*/
static int mei_me_hbuf_empty_slots(struct mei_device *dev)
{
@@ -326,7 +326,7 @@ static size_t mei_me_hbuf_max_len(const struct mei_device *dev)
/**
- * mei_write_message - writes a message to mei device.
+ * mei_me_write_message - writes a message to mei device.
*
* @dev: the device structure
* @header: mei HECI header of message
@@ -354,7 +354,7 @@ static int mei_me_write_message(struct mei_device *dev,
dw_cnt = mei_data2slots(length);
if (empty_slots < 0 || dw_cnt > empty_slots)
- return -EIO;
+ return -EMSGSIZE;
mei_me_reg_write(hw, H_CB_WW, *((u32 *) header));
@@ -381,7 +381,7 @@ static int mei_me_write_message(struct mei_device *dev,
*
* @dev: the device structure
*
- * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise filled slots count
+ * returns -EOVERFLOW if overflow, otherwise filled slots count
*/
static int mei_me_count_full_read_slots(struct mei_device *dev)
{
@@ -505,17 +505,25 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
/* check slots available for reading */
slots = mei_count_full_read_slots(dev);
while (slots > 0) {
- /* we have urgent data to send so break the read */
- if (dev->wr_ext_msg.hdr.length)
- break;
dev_dbg(&dev->pdev->dev, "slots to read = %08x\n", slots);
rets = mei_irq_read_handler(dev, &complete_list, &slots);
+ /* There is a race between ME write and interrupt delivery:
+ * Not all data is always available immediately after the
+ * interrupt, so try to read again on the next interrupt.
+ */
+ if (rets == -ENODATA)
+ break;
+
if (rets && dev->dev_state != MEI_DEV_RESETTING) {
+ dev_err(&dev->pdev->dev, "mei_irq_read_handler ret = %d.\n",
+ rets);
schedule_work(&dev->reset_work);
goto end;
}
}
+ dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
+
rets = mei_irq_write_handler(dev, &complete_list);
dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h
index 80bd829fbd9a..893d5119fa9b 100644
--- a/drivers/misc/mei/hw-me.h
+++ b/drivers/misc/mei/hw-me.h
@@ -20,6 +20,7 @@
#define _MEI_INTERFACE_H_
#include <linux/mei.h>
+#include <linux/irqreturn.h>
#include "mei_dev.h"
#include "client.h"
diff --git a/drivers/misc/mei/hw-txe-regs.h b/drivers/misc/mei/hw-txe-regs.h
new file mode 100644
index 000000000000..7283c24c1af1
--- /dev/null
+++ b/drivers/misc/mei/hw-txe-regs.h
@@ -0,0 +1,294 @@
+/******************************************************************************
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Intel MEI Interface Header
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2013 - 2014 Intel 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.
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING
+ *
+ * Contact Information:
+ * Intel Corporation.
+ * linux-mei@linux.intel.com
+ * http://www.intel.com
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *****************************************************************************/
+#ifndef _MEI_HW_TXE_REGS_H_
+#define _MEI_HW_TXE_REGS_H_
+
+#include "hw.h"
+
+#define SEC_ALIVENESS_TIMER_TIMEOUT (5 * MSEC_PER_SEC)
+#define SEC_ALIVENESS_WAIT_TIMEOUT (1 * MSEC_PER_SEC)
+#define SEC_RESET_WAIT_TIMEOUT (1 * MSEC_PER_SEC)
+#define SEC_READY_WAIT_TIMEOUT (5 * MSEC_PER_SEC)
+#define START_MESSAGE_RESPONSE_WAIT_TIMEOUT (5 * MSEC_PER_SEC)
+#define RESET_CANCEL_WAIT_TIMEOUT (1 * MSEC_PER_SEC)
+
+enum {
+ SEC_BAR,
+ BRIDGE_BAR,
+
+ NUM_OF_MEM_BARS
+};
+
+/* SeC FW Status Register
+ *
+ * FW uses this register in order to report its status to host.
+ * This register resides in PCI-E config space.
+ */
+#define PCI_CFG_TXE_FW_STS0 0x40
+# define PCI_CFG_TXE_FW_STS0_WRK_ST_MSK 0x0000000F
+# define PCI_CFG_TXE_FW_STS0_OP_ST_MSK 0x000001C0
+# define PCI_CFG_TXE_FW_STS0_FW_INIT_CMPLT 0x00000200
+# define PCI_CFG_TXE_FW_STS0_ERR_CODE_MSK 0x0000F000
+# define PCI_CFG_TXE_FW_STS0_OP_MODE_MSK 0x000F0000
+# define PCI_CFG_TXE_FW_STS0_RST_CNT_MSK 0x00F00000
+
+
+#define IPC_BASE_ADDR 0x80400 /* SeC IPC Base Address */
+
+/* IPC Input Doorbell Register */
+#define SEC_IPC_INPUT_DOORBELL_REG (0x0000 + IPC_BASE_ADDR)
+
+/* IPC Input Status Register
+ * This register indicates whether or not processing of
+ * the most recent command has been completed by the SEC
+ * New commands and payloads should not be written by the Host
+ * until this indicates that the previous command has been processed.
+ */
+#define SEC_IPC_INPUT_STATUS_REG (0x0008 + IPC_BASE_ADDR)
+# define SEC_IPC_INPUT_STATUS_RDY BIT(0)
+
+/* IPC Host Interrupt Status Register */
+#define SEC_IPC_HOST_INT_STATUS_REG (0x0010 + IPC_BASE_ADDR)
+#define SEC_IPC_HOST_INT_STATUS_OUT_DB BIT(0)
+#define SEC_IPC_HOST_INT_STATUS_IN_RDY BIT(1)
+#define SEC_IPC_HOST_INT_STATUS_HDCP_M0_RCVD BIT(5)
+#define SEC_IPC_HOST_INT_STATUS_ILL_MEM_ACCESS BIT(17)
+#define SEC_IPC_HOST_INT_STATUS_AES_HKEY_ERR BIT(18)
+#define SEC_IPC_HOST_INT_STATUS_DES_HKEY_ERR BIT(19)
+#define SEC_IPC_HOST_INT_STATUS_TMRMTB_OVERFLOW BIT(21)
+
+/* Convenient mask for pending interrupts */
+#define SEC_IPC_HOST_INT_STATUS_PENDING \
+ (SEC_IPC_HOST_INT_STATUS_OUT_DB| \
+ SEC_IPC_HOST_INT_STATUS_IN_RDY)
+
+/* IPC Host Interrupt Mask Register */
+#define SEC_IPC_HOST_INT_MASK_REG (0x0014 + IPC_BASE_ADDR)
+
+# define SEC_IPC_HOST_INT_MASK_OUT_DB BIT(0) /* Output Doorbell Int Mask */
+# define SEC_IPC_HOST_INT_MASK_IN_RDY BIT(1) /* Input Ready Int Mask */
+
+/* IPC Input Payload RAM */
+#define SEC_IPC_INPUT_PAYLOAD_REG (0x0100 + IPC_BASE_ADDR)
+/* IPC Shared Payload RAM */
+#define IPC_SHARED_PAYLOAD_REG (0x0200 + IPC_BASE_ADDR)
+
+/* SeC Address Translation Table Entry 2 - Ctrl
+ *
+ * This register resides also in SeC's PCI-E Memory space.
+ */
+#define SATT2_CTRL_REG 0x1040
+# define SATT2_CTRL_VALID_MSK BIT(0)
+# define SATT2_CTRL_BR_BASE_ADDR_REG_SHIFT 8
+# define SATT2_CTRL_BRIDGE_HOST_EN_MSK BIT(12)
+
+/* SATT Table Entry 2 SAP Base Address Register */
+#define SATT2_SAP_BA_REG 0x1044
+/* SATT Table Entry 2 SAP Size Register. */
+#define SATT2_SAP_SIZE_REG 0x1048
+ /* SATT Table Entry 2 SAP Bridge Address - LSB Register */
+#define SATT2_BRG_BA_LSB_REG 0x104C
+
+/* Host High-level Interrupt Status Register */
+#define HHISR_REG 0x2020
+/* Host High-level Interrupt Enable Register
+ *
+ * Resides in PCI memory space. This is the top hierarchy for
+ * interrupts from SeC to host, aggregating both interrupts that
+ * arrive through HICR registers as well as interrupts
+ * that arrive via IPC.
+ */
+#define HHIER_REG 0x2024
+#define IPC_HHIER_SEC BIT(0)
+#define IPC_HHIER_BRIDGE BIT(1)
+#define IPC_HHIER_MSK (IPC_HHIER_SEC | IPC_HHIER_BRIDGE)
+
+/* Host High-level Interrupt Mask Register.
+ *
+ * Resides in PCI memory space.
+ * This is the top hierarchy for masking interrupts from SeC to host.
+ */
+#define HHIMR_REG 0x2028
+#define IPC_HHIMR_SEC BIT(0)
+#define IPC_HHIMR_BRIDGE BIT(1)
+
+/* Host High-level IRQ Status Register */
+#define HHIRQSR_REG 0x202C
+
+/* Host Interrupt Cause Register 0 - SeC IPC Readiness
+ *
+ * This register is both an ICR to Host from PCI Memory Space
+ * and it is also exposed in the SeC memory space.
+ * This register is used by SeC's IPC driver in order
+ * to synchronize with host about IPC interface state.
+ */
+#define HICR_SEC_IPC_READINESS_REG 0x2040
+#define HICR_SEC_IPC_READINESS_HOST_RDY BIT(0)
+#define HICR_SEC_IPC_READINESS_SEC_RDY BIT(1)
+#define HICR_SEC_IPC_READINESS_SYS_RDY \
+ (HICR_SEC_IPC_READINESS_HOST_RDY | \
+ HICR_SEC_IPC_READINESS_SEC_RDY)
+#define HICR_SEC_IPC_READINESS_RDY_CLR BIT(2)
+
+/* Host Interrupt Cause Register 1 - Aliveness Response */
+/* This register is both an ICR to Host from PCI Memory Space
+ * and it is also exposed in the SeC memory space.
+ * The register may be used by SeC to ACK a host request for aliveness.
+ */
+#define HICR_HOST_ALIVENESS_RESP_REG 0x2044
+#define HICR_HOST_ALIVENESS_RESP_ACK BIT(0)
+
+/* Host Interrupt Cause Register 2 - SeC IPC Output Doorbell */
+#define HICR_SEC_IPC_OUTPUT_DOORBELL_REG 0x2048
+
+/* Host Interrupt Status Register.
+ *
+ * Resides in PCI memory space.
+ * This is the main register involved in generating interrupts
+ * from SeC to host via HICRs.
+ * The interrupt generation rules are as follows:
+ * An interrupt will be generated whenever for any i,
+ * there is a transition from a state where at least one of
+ * the following conditions did not hold, to a state where
+ * ALL the following conditions hold:
+ * A) HISR.INT[i]_STS == 1.
+ * B) HIER.INT[i]_EN == 1.
+ */
+#define HISR_REG 0x2060
+#define HISR_INT_0_STS BIT(0)
+#define HISR_INT_1_STS BIT(1)
+#define HISR_INT_2_STS BIT(2)
+#define HISR_INT_3_STS BIT(3)
+#define HISR_INT_4_STS BIT(4)
+#define HISR_INT_5_STS BIT(5)
+#define HISR_INT_6_STS BIT(6)
+#define HISR_INT_7_STS BIT(7)
+#define HISR_INT_STS_MSK \
+ (HISR_INT_0_STS | HISR_INT_1_STS | HISR_INT_2_STS)
+
+/* Host Interrupt Enable Register. Resides in PCI memory space. */
+#define HIER_REG 0x2064
+#define HIER_INT_0_EN BIT(0)
+#define HIER_INT_1_EN BIT(1)
+#define HIER_INT_2_EN BIT(2)
+#define HIER_INT_3_EN BIT(3)
+#define HIER_INT_4_EN BIT(4)
+#define HIER_INT_5_EN BIT(5)
+#define HIER_INT_6_EN BIT(6)
+#define HIER_INT_7_EN BIT(7)
+
+#define HIER_INT_EN_MSK \
+ (HIER_INT_0_EN | HIER_INT_1_EN | HIER_INT_2_EN)
+
+
+/* SEC Memory Space IPC output payload.
+ *
+ * This register is part of the output payload which SEC provides to host.
+ */
+#define BRIDGE_IPC_OUTPUT_PAYLOAD_REG 0x20C0
+
+/* SeC Interrupt Cause Register - Host Aliveness Request
+ * This register is both an ICR to SeC and it is also exposed
+ * in the host-visible PCI memory space.
+ * The register is used by host to request SeC aliveness.
+ */
+#define SICR_HOST_ALIVENESS_REQ_REG 0x214C
+#define SICR_HOST_ALIVENESS_REQ_REQUESTED BIT(0)
+
+
+/* SeC Interrupt Cause Register - Host IPC Readiness
+ *
+ * This register is both an ICR to SeC and it is also exposed
+ * in the host-visible PCI memory space.
+ * This register is used by the host's SeC driver uses in order
+ * to synchronize with SeC about IPC interface state.
+ */
+#define SICR_HOST_IPC_READINESS_REQ_REG 0x2150
+
+
+#define SICR_HOST_IPC_READINESS_HOST_RDY BIT(0)
+#define SICR_HOST_IPC_READINESS_SEC_RDY BIT(1)
+#define SICR_HOST_IPC_READINESS_SYS_RDY \
+ (SICR_HOST_IPC_READINESS_HOST_RDY | \
+ SICR_HOST_IPC_READINESS_SEC_RDY)
+#define SICR_HOST_IPC_READINESS_RDY_CLR BIT(2)
+
+/* SeC Interrupt Cause Register - SeC IPC Output Status
+ *
+ * This register indicates whether or not processing of the most recent
+ * command has been completed by the Host.
+ * New commands and payloads should not be written by SeC until this
+ * register indicates that the previous command has been processed.
+ */
+#define SICR_SEC_IPC_OUTPUT_STATUS_REG 0x2154
+# define SEC_IPC_OUTPUT_STATUS_RDY BIT(0)
+
+
+
+/* MEI IPC Message payload size 64 bytes */
+#define PAYLOAD_SIZE 64
+
+/* MAX size for SATT range 32MB */
+#define SATT_RANGE_MAX (32 << 20)
+
+
+#endif /* _MEI_HW_TXE_REGS_H_ */
+
diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c
new file mode 100644
index 000000000000..f60182a52f96
--- /dev/null
+++ b/drivers/misc/mei/hw-txe.c
@@ -0,0 +1,1107 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2013-2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/jiffies.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/irqreturn.h>
+
+#include <linux/mei.h>
+
+#include "mei_dev.h"
+#include "hw-txe.h"
+#include "client.h"
+#include "hbm.h"
+
+/**
+ * mei_txe_reg_read - Reads 32bit data from the device
+ *
+ * @base_addr: registers base address
+ * @offset: register offset
+ *
+ */
+static inline u32 mei_txe_reg_read(void __iomem *base_addr,
+ unsigned long offset)
+{
+ return ioread32(base_addr + offset);
+}
+
+/**
+ * mei_txe_reg_write - Writes 32bit data to the device
+ *
+ * @base_addr: registers base address
+ * @offset: register offset
+ * @value: the value to write
+ */
+static inline void mei_txe_reg_write(void __iomem *base_addr,
+ unsigned long offset, u32 value)
+{
+ iowrite32(value, base_addr + offset);
+}
+
+/**
+ * mei_txe_sec_reg_read_silent - Reads 32bit data from the SeC BAR
+ *
+ * @dev: the device structure
+ * @offset: register offset
+ *
+ * Doesn't check for aliveness while Reads 32bit data from the SeC BAR
+ */
+static inline u32 mei_txe_sec_reg_read_silent(struct mei_txe_hw *hw,
+ unsigned long offset)
+{
+ return mei_txe_reg_read(hw->mem_addr[SEC_BAR], offset);
+}
+
+/**
+ * mei_txe_sec_reg_read - Reads 32bit data from the SeC BAR
+ *
+ * @dev: the device structure
+ * @offset: register offset
+ *
+ * Reads 32bit data from the SeC BAR and shout loud if aliveness is not set
+ */
+static inline u32 mei_txe_sec_reg_read(struct mei_txe_hw *hw,
+ unsigned long offset)
+{
+ WARN(!hw->aliveness, "sec read: aliveness not asserted\n");
+ return mei_txe_sec_reg_read_silent(hw, offset);
+}
+/**
+ * mei_txe_sec_reg_write_silent - Writes 32bit data to the SeC BAR
+ * doesn't check for aliveness
+ *
+ * @dev: the device structure
+ * @offset: register offset
+ * @value: value to write
+ *
+ * Doesn't check for aliveness while writes 32bit data from to the SeC BAR
+ */
+static inline void mei_txe_sec_reg_write_silent(struct mei_txe_hw *hw,
+ unsigned long offset, u32 value)
+{
+ mei_txe_reg_write(hw->mem_addr[SEC_BAR], offset, value);
+}
+
+/**
+ * mei_txe_sec_reg_write - Writes 32bit data to the SeC BAR
+ *
+ * @dev: the device structure
+ * @offset: register offset
+ * @value: value to write
+ *
+ * Writes 32bit data from the SeC BAR and shout loud if aliveness is not set
+ */
+static inline void mei_txe_sec_reg_write(struct mei_txe_hw *hw,
+ unsigned long offset, u32 value)
+{
+ WARN(!hw->aliveness, "sec write: aliveness not asserted\n");
+ mei_txe_sec_reg_write_silent(hw, offset, value);
+}
+/**
+ * mei_txe_br_reg_read - Reads 32bit data from the Bridge BAR
+ *
+ * @hw: the device structure
+ * @offset: offset from which to read the data
+ *
+ */
+static inline u32 mei_txe_br_reg_read(struct mei_txe_hw *hw,
+ unsigned long offset)
+{
+ return mei_txe_reg_read(hw->mem_addr[BRIDGE_BAR], offset);
+}
+
+/**
+ * mei_txe_br_reg_write - Writes 32bit data to the Bridge BAR
+ *
+ * @hw: the device structure
+ * @offset: offset from which to write the data
+ * @value: the byte to write
+ */
+static inline void mei_txe_br_reg_write(struct mei_txe_hw *hw,
+ unsigned long offset, u32 value)
+{
+ mei_txe_reg_write(hw->mem_addr[BRIDGE_BAR], offset, value);
+}
+
+/**
+ * mei_txe_aliveness_set - request for aliveness change
+ *
+ * @dev: the device structure
+ * @req: requested aliveness value
+ *
+ * Request for aliveness change and returns true if the change is
+ * really needed and false if aliveness is already
+ * in the requested state
+ * Requires device lock to be held
+ */
+static bool mei_txe_aliveness_set(struct mei_device *dev, u32 req)
+{
+
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ bool do_req = hw->aliveness != req;
+
+ dev_dbg(&dev->pdev->dev, "Aliveness current=%d request=%d\n",
+ hw->aliveness, req);
+ if (do_req) {
+ hw->recvd_aliveness = false;
+ mei_txe_br_reg_write(hw, SICR_HOST_ALIVENESS_REQ_REG, req);
+ }
+ return do_req;
+}
+
+
+/**
+ * mei_txe_aliveness_req_get - get aliveness requested register value
+ *
+ * @dev: the device structure
+ *
+ * Extract HICR_HOST_ALIVENESS_RESP_ACK bit from
+ * from HICR_HOST_ALIVENESS_REQ register value
+ */
+static u32 mei_txe_aliveness_req_get(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ u32 reg;
+ reg = mei_txe_br_reg_read(hw, SICR_HOST_ALIVENESS_REQ_REG);
+ return reg & SICR_HOST_ALIVENESS_REQ_REQUESTED;
+}
+
+/**
+ * mei_txe_aliveness_get - get aliveness response register value
+ * @dev: the device structure
+ *
+ * Extract HICR_HOST_ALIVENESS_RESP_ACK bit
+ * from HICR_HOST_ALIVENESS_RESP register value
+ */
+static u32 mei_txe_aliveness_get(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ u32 reg;
+ reg = mei_txe_br_reg_read(hw, HICR_HOST_ALIVENESS_RESP_REG);
+ return reg & HICR_HOST_ALIVENESS_RESP_ACK;
+}
+
+/**
+ * mei_txe_aliveness_poll - waits for aliveness to settle
+ *
+ * @dev: the device structure
+ * @expected: expected aliveness value
+ *
+ * Polls for HICR_HOST_ALIVENESS_RESP.ALIVENESS_RESP to be set
+ * returns > 0 if the expected value was received, -ETIME otherwise
+ */
+static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ int t = 0;
+
+ do {
+ hw->aliveness = mei_txe_aliveness_get(dev);
+ if (hw->aliveness == expected) {
+ dev_dbg(&dev->pdev->dev,
+ "aliveness settled after %d msecs\n", t);
+ return t;
+ }
+ mutex_unlock(&dev->device_lock);
+ msleep(MSEC_PER_SEC / 5);
+ mutex_lock(&dev->device_lock);
+ t += MSEC_PER_SEC / 5;
+ } while (t < SEC_ALIVENESS_WAIT_TIMEOUT);
+
+ dev_err(&dev->pdev->dev, "aliveness timed out\n");
+ return -ETIME;
+}
+
+/**
+ * mei_txe_aliveness_wait - waits for aliveness to settle
+ *
+ * @dev: the device structure
+ * @expected: expected aliveness value
+ *
+ * Waits for HICR_HOST_ALIVENESS_RESP.ALIVENESS_RESP to be set
+ * returns returns 0 on success and < 0 otherwise
+ */
+static int mei_txe_aliveness_wait(struct mei_device *dev, u32 expected)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ const unsigned long timeout =
+ msecs_to_jiffies(SEC_ALIVENESS_WAIT_TIMEOUT);
+ long err;
+ int ret;
+
+ hw->aliveness = mei_txe_aliveness_get(dev);
+ if (hw->aliveness == expected)
+ return 0;
+
+ mutex_unlock(&dev->device_lock);
+ err = wait_event_timeout(hw->wait_aliveness,
+ hw->recvd_aliveness, timeout);
+ mutex_lock(&dev->device_lock);
+
+ hw->aliveness = mei_txe_aliveness_get(dev);
+ ret = hw->aliveness == expected ? 0 : -ETIME;
+
+ if (ret)
+ dev_err(&dev->pdev->dev, "aliveness timed out");
+ else
+ dev_dbg(&dev->pdev->dev, "aliveness settled after %d msecs\n",
+ jiffies_to_msecs(timeout - err));
+ hw->recvd_aliveness = false;
+ return ret;
+}
+
+/**
+ * mei_txe_aliveness_set_sync - sets an wait for aliveness to complete
+ *
+ * @dev: the device structure
+ *
+ * returns returns 0 on success and < 0 otherwise
+ */
+int mei_txe_aliveness_set_sync(struct mei_device *dev, u32 req)
+{
+ if (mei_txe_aliveness_set(dev, req))
+ return mei_txe_aliveness_wait(dev, req);
+ return 0;
+}
+
+/**
+ * mei_txe_input_ready_interrupt_enable - sets the Input Ready Interrupt
+ *
+ * @dev: the device structure
+ */
+static void mei_txe_input_ready_interrupt_enable(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ u32 hintmsk;
+ /* Enable the SEC_IPC_HOST_INT_MASK_IN_RDY interrupt */
+ hintmsk = mei_txe_sec_reg_read(hw, SEC_IPC_HOST_INT_MASK_REG);
+ hintmsk |= SEC_IPC_HOST_INT_MASK_IN_RDY;
+ mei_txe_sec_reg_write(hw, SEC_IPC_HOST_INT_MASK_REG, hintmsk);
+}
+
+/**
+ * mei_txe_input_doorbell_set
+ * - Sets bit 0 in SEC_IPC_INPUT_DOORBELL.IPC_INPUT_DOORBELL.
+ * @dev: the device structure
+ */
+static void mei_txe_input_doorbell_set(struct mei_txe_hw *hw)
+{
+ /* Clear the interrupt cause */
+ clear_bit(TXE_INTR_IN_READY_BIT, &hw->intr_cause);
+ mei_txe_sec_reg_write(hw, SEC_IPC_INPUT_DOORBELL_REG, 1);
+}
+
+/**
+ * mei_txe_output_ready_set - Sets the SICR_SEC_IPC_OUTPUT_STATUS bit to 1
+ *
+ * @dev: the device structure
+ */
+static void mei_txe_output_ready_set(struct mei_txe_hw *hw)
+{
+ mei_txe_br_reg_write(hw,
+ SICR_SEC_IPC_OUTPUT_STATUS_REG,
+ SEC_IPC_OUTPUT_STATUS_RDY);
+}
+
+/**
+ * mei_txe_is_input_ready - check if TXE is ready for receiving data
+ *
+ * @dev: the device structure
+ */
+static bool mei_txe_is_input_ready(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ u32 status;
+ status = mei_txe_sec_reg_read(hw, SEC_IPC_INPUT_STATUS_REG);
+ return !!(SEC_IPC_INPUT_STATUS_RDY & status);
+}
+
+/**
+ * mei_txe_intr_clear - clear all interrupts
+ *
+ * @dev: the device structure
+ */
+static inline void mei_txe_intr_clear(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ mei_txe_sec_reg_write_silent(hw, SEC_IPC_HOST_INT_STATUS_REG,
+ SEC_IPC_HOST_INT_STATUS_PENDING);
+ mei_txe_br_reg_write(hw, HISR_REG, HISR_INT_STS_MSK);
+ mei_txe_br_reg_write(hw, HHISR_REG, IPC_HHIER_MSK);
+}
+
+/**
+ * mei_txe_intr_disable - disable all interrupts
+ *
+ * @dev: the device structure
+ */
+static void mei_txe_intr_disable(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ mei_txe_br_reg_write(hw, HHIER_REG, 0);
+ mei_txe_br_reg_write(hw, HIER_REG, 0);
+}
+/**
+ * mei_txe_intr_disable - enable all interrupts
+ *
+ * @dev: the device structure
+ */
+static void mei_txe_intr_enable(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ mei_txe_br_reg_write(hw, HHIER_REG, IPC_HHIER_MSK);
+ mei_txe_br_reg_write(hw, HIER_REG, HIER_INT_EN_MSK);
+}
+
+/**
+ * mei_txe_pending_interrupts - check if there are pending interrupts
+ * only Aliveness, Input ready, and output doorbell are of relevance
+ *
+ * @dev: the device structure
+ *
+ * Checks if there are pending interrupts
+ * only Aliveness, Readiness, Input ready, and Output doorbell are relevant
+ */
+static bool mei_txe_pending_interrupts(struct mei_device *dev)
+{
+
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ bool ret = (hw->intr_cause & (TXE_INTR_READINESS |
+ TXE_INTR_ALIVENESS |
+ TXE_INTR_IN_READY |
+ TXE_INTR_OUT_DB));
+
+ if (ret) {
+ dev_dbg(&dev->pdev->dev,
+ "Pending Interrupts InReady=%01d Readiness=%01d, Aliveness=%01d, OutDoor=%01d\n",
+ !!(hw->intr_cause & TXE_INTR_IN_READY),
+ !!(hw->intr_cause & TXE_INTR_READINESS),
+ !!(hw->intr_cause & TXE_INTR_ALIVENESS),
+ !!(hw->intr_cause & TXE_INTR_OUT_DB));
+ }
+ return ret;
+}
+
+/**
+ * mei_txe_input_payload_write - write a dword to the host buffer
+ * at offset idx
+ *
+ * @dev: the device structure
+ * @idx: index in the host buffer
+ * @value: value
+ */
+static void mei_txe_input_payload_write(struct mei_device *dev,
+ unsigned long idx, u32 value)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ mei_txe_sec_reg_write(hw, SEC_IPC_INPUT_PAYLOAD_REG +
+ (idx * sizeof(u32)), value);
+}
+
+/**
+ * mei_txe_out_data_read - read dword from the device buffer
+ * at offset idx
+ *
+ * @dev: the device structure
+ * @idx: index in the device buffer
+ *
+ * returns register value at index
+ */
+static u32 mei_txe_out_data_read(const struct mei_device *dev,
+ unsigned long idx)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ return mei_txe_br_reg_read(hw,
+ BRIDGE_IPC_OUTPUT_PAYLOAD_REG + (idx * sizeof(u32)));
+}
+
+/* Readiness */
+
+/**
+ * mei_txe_readiness_set_host_rdy
+ *
+ * @dev: the device structure
+ */
+static void mei_txe_readiness_set_host_rdy(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ mei_txe_br_reg_write(hw,
+ SICR_HOST_IPC_READINESS_REQ_REG,
+ SICR_HOST_IPC_READINESS_HOST_RDY);
+}
+
+/**
+ * mei_txe_readiness_clear
+ *
+ * @dev: the device structure
+ */
+static void mei_txe_readiness_clear(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ mei_txe_br_reg_write(hw, SICR_HOST_IPC_READINESS_REQ_REG,
+ SICR_HOST_IPC_READINESS_RDY_CLR);
+}
+/**
+ * mei_txe_readiness_get - Reads and returns
+ * the HICR_SEC_IPC_READINESS register value
+ *
+ * @dev: the device structure
+ */
+static u32 mei_txe_readiness_get(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ return mei_txe_br_reg_read(hw, HICR_SEC_IPC_READINESS_REG);
+}
+
+
+/**
+ * mei_txe_readiness_is_sec_rdy - check readiness
+ * for HICR_SEC_IPC_READINESS_SEC_RDY
+ *
+ * @readiness - cached readiness state
+ */
+static inline bool mei_txe_readiness_is_sec_rdy(u32 readiness)
+{
+ return !!(readiness & HICR_SEC_IPC_READINESS_SEC_RDY);
+}
+
+/**
+ * mei_txe_hw_is_ready - check if the hw is ready
+ *
+ * @dev: the device structure
+ */
+static bool mei_txe_hw_is_ready(struct mei_device *dev)
+{
+ u32 readiness = mei_txe_readiness_get(dev);
+ return mei_txe_readiness_is_sec_rdy(readiness);
+}
+
+/**
+ * mei_txe_host_is_ready - check if the host is ready
+ *
+ * @dev: the device structure
+ */
+static inline bool mei_txe_host_is_ready(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ u32 reg = mei_txe_br_reg_read(hw, HICR_SEC_IPC_READINESS_REG);
+ return !!(reg & HICR_SEC_IPC_READINESS_HOST_RDY);
+}
+
+/**
+ * mei_txe_readiness_wait - wait till readiness settles
+ *
+ * @dev: the device structure
+ *
+ * returns 0 on success and -ETIME on timeout
+ */
+static int mei_txe_readiness_wait(struct mei_device *dev)
+{
+ if (mei_txe_hw_is_ready(dev))
+ return 0;
+
+ mutex_unlock(&dev->device_lock);
+ wait_event_timeout(dev->wait_hw_ready, dev->recvd_hw_ready,
+ msecs_to_jiffies(SEC_RESET_WAIT_TIMEOUT));
+ mutex_lock(&dev->device_lock);
+ if (!dev->recvd_hw_ready) {
+ dev_err(&dev->pdev->dev, "wait for readiness failed\n");
+ return -ETIME;
+ }
+
+ dev->recvd_hw_ready = false;
+ return 0;
+}
+
+/**
+ * mei_txe_hw_config - configure hardware at the start of the devices
+ *
+ * @dev: the device structure
+ *
+ * Configure hardware at the start of the device should be done only
+ * once at the device probe time
+ */
+static void mei_txe_hw_config(struct mei_device *dev)
+{
+
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ /* Doesn't change in runtime */
+ dev->hbuf_depth = PAYLOAD_SIZE / 4;
+
+ hw->aliveness = mei_txe_aliveness_get(dev);
+ hw->readiness = mei_txe_readiness_get(dev);
+
+ dev_dbg(&dev->pdev->dev, "aliveness_resp = 0x%08x, readiness = 0x%08x.\n",
+ hw->aliveness, hw->readiness);
+}
+
+
+/**
+ * mei_txe_write - writes a message to device.
+ *
+ * @dev: the device structure
+ * @header: header of message
+ * @buf: message buffer will be written
+ * returns 1 if success, 0 - otherwise.
+ */
+
+static int mei_txe_write(struct mei_device *dev,
+ struct mei_msg_hdr *header, unsigned char *buf)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ unsigned long rem;
+ unsigned long length;
+ int slots = dev->hbuf_depth;
+ u32 *reg_buf = (u32 *)buf;
+ u32 dw_cnt;
+ int i;
+
+ if (WARN_ON(!header || !buf))
+ return -EINVAL;
+
+ length = header->length;
+
+ dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
+
+ dw_cnt = mei_data2slots(length);
+ if (dw_cnt > slots)
+ return -EMSGSIZE;
+
+ if (WARN(!hw->aliveness, "txe write: aliveness not asserted\n"))
+ return -EAGAIN;
+
+ /* Enable Input Ready Interrupt. */
+ mei_txe_input_ready_interrupt_enable(dev);
+
+ if (!mei_txe_is_input_ready(dev)) {
+ dev_err(&dev->pdev->dev, "Input is not ready");
+ return -EAGAIN;
+ }
+
+ mei_txe_input_payload_write(dev, 0, *((u32 *)header));
+
+ for (i = 0; i < length / 4; i++)
+ mei_txe_input_payload_write(dev, i + 1, reg_buf[i]);
+
+ rem = length & 0x3;
+ if (rem > 0) {
+ u32 reg = 0;
+ memcpy(&reg, &buf[length - rem], rem);
+ mei_txe_input_payload_write(dev, i + 1, reg);
+ }
+
+ /* after each write the whole buffer is consumed */
+ hw->slots = 0;
+
+ /* Set Input-Doorbell */
+ mei_txe_input_doorbell_set(hw);
+
+ return 0;
+}
+
+/**
+ * mei_txe_hbuf_max_len - mimics the me hbuf circular buffer
+ *
+ * @dev: the device structure
+ *
+ * returns the PAYLOAD_SIZE - 4
+ */
+static size_t mei_txe_hbuf_max_len(const struct mei_device *dev)
+{
+ return PAYLOAD_SIZE - sizeof(struct mei_msg_hdr);
+}
+
+/**
+ * mei_txe_hbuf_empty_slots - mimics the me hbuf circular buffer
+ *
+ * @dev: the device structure
+ *
+ * returns always hbuf_depth
+ */
+static int mei_txe_hbuf_empty_slots(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ return hw->slots;
+}
+
+/**
+ * mei_txe_count_full_read_slots - mimics the me device circular buffer
+ *
+ * @dev: the device structure
+ *
+ * returns always buffer size in dwords count
+ */
+static int mei_txe_count_full_read_slots(struct mei_device *dev)
+{
+ /* read buffers has static size */
+ return PAYLOAD_SIZE / 4;
+}
+
+/**
+ * mei_txe_read_hdr - read message header which is always in 4 first bytes
+ *
+ * @dev: the device structure
+ *
+ * returns mei message header
+ */
+
+static u32 mei_txe_read_hdr(const struct mei_device *dev)
+{
+ return mei_txe_out_data_read(dev, 0);
+}
+/**
+ * mei_txe_read - reads a message from the txe device.
+ *
+ * @dev: the device structure
+ * @buf: message buffer will be written
+ * @len: message size will be read
+ *
+ * returns -EINVAL on error wrong argument and 0 on success
+ */
+static int mei_txe_read(struct mei_device *dev,
+ unsigned char *buf, unsigned long len)
+{
+
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ u32 i;
+ u32 *reg_buf = (u32 *)buf;
+ u32 rem = len & 0x3;
+
+ if (WARN_ON(!buf || !len))
+ return -EINVAL;
+
+ dev_dbg(&dev->pdev->dev,
+ "buffer-length = %lu buf[0]0x%08X\n",
+ len, mei_txe_out_data_read(dev, 0));
+
+ for (i = 0; i < len / 4; i++) {
+ /* skip header: index starts from 1 */
+ u32 reg = mei_txe_out_data_read(dev, i + 1);
+ dev_dbg(&dev->pdev->dev, "buf[%d] = 0x%08X\n", i, reg);
+ *reg_buf++ = reg;
+ }
+
+ if (rem) {
+ u32 reg = mei_txe_out_data_read(dev, i + 1);
+ memcpy(reg_buf, &reg, rem);
+ }
+
+ mei_txe_output_ready_set(hw);
+ return 0;
+}
+
+/**
+ * mei_txe_hw_reset - resets host and fw.
+ *
+ * @dev: the device structure
+ * @intr_enable: if interrupt should be enabled after reset.
+ *
+ * returns 0 on success and < 0 in case of error
+ */
+static int mei_txe_hw_reset(struct mei_device *dev, bool intr_enable)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+
+ u32 aliveness_req;
+ /*
+ * read input doorbell to ensure consistency between Bridge and SeC
+ * return value might be garbage return
+ */
+ (void)mei_txe_sec_reg_read_silent(hw, SEC_IPC_INPUT_DOORBELL_REG);
+
+ aliveness_req = mei_txe_aliveness_req_get(dev);
+ hw->aliveness = mei_txe_aliveness_get(dev);
+
+ /* Disable interrupts in this stage we will poll */
+ mei_txe_intr_disable(dev);
+
+ /*
+ * If Aliveness Request and Aliveness Response are not equal then
+ * wait for them to be equal
+ * Since we might have interrupts disabled - poll for it
+ */
+ if (aliveness_req != hw->aliveness)
+ if (mei_txe_aliveness_poll(dev, aliveness_req) < 0) {
+ dev_err(&dev->pdev->dev,
+ "wait for aliveness settle failed ... bailing out\n");
+ return -EIO;
+ }
+
+ /*
+ * If Aliveness Request and Aliveness Response are set then clear them
+ */
+ if (aliveness_req) {
+ mei_txe_aliveness_set(dev, 0);
+ if (mei_txe_aliveness_poll(dev, 0) < 0) {
+ dev_err(&dev->pdev->dev,
+ "wait for aliveness failed ... bailing out\n");
+ return -EIO;
+ }
+ }
+
+ /*
+ * Set rediness RDY_CLR bit
+ */
+ mei_txe_readiness_clear(dev);
+
+ return 0;
+}
+
+/**
+ * mei_txe_hw_start - start the hardware after reset
+ *
+ * @dev: the device structure
+ *
+ * returns 0 on success and < 0 in case of error
+ */
+static int mei_txe_hw_start(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ int ret;
+
+ u32 hisr;
+
+ /* bring back interrupts */
+ mei_txe_intr_enable(dev);
+
+ ret = mei_txe_readiness_wait(dev);
+ if (ret < 0) {
+ dev_err(&dev->pdev->dev, "wating for readiness failed\n");
+ return ret;
+ }
+
+ /*
+ * If HISR.INT2_STS interrupt status bit is set then clear it.
+ */
+ hisr = mei_txe_br_reg_read(hw, HISR_REG);
+ if (hisr & HISR_INT_2_STS)
+ mei_txe_br_reg_write(hw, HISR_REG, HISR_INT_2_STS);
+
+ /* Clear the interrupt cause of OutputDoorbell */
+ clear_bit(TXE_INTR_OUT_DB_BIT, &hw->intr_cause);
+
+ ret = mei_txe_aliveness_set_sync(dev, 1);
+ if (ret < 0) {
+ dev_err(&dev->pdev->dev, "wait for aliveness failed ... bailing out\n");
+ return ret;
+ }
+
+ /* enable input ready interrupts:
+ * SEC_IPC_HOST_INT_MASK.IPC_INPUT_READY_INT_MASK
+ */
+ mei_txe_input_ready_interrupt_enable(dev);
+
+
+ /* Set the SICR_SEC_IPC_OUTPUT_STATUS.IPC_OUTPUT_READY bit */
+ mei_txe_output_ready_set(hw);
+
+ /* Set bit SICR_HOST_IPC_READINESS.HOST_RDY
+ */
+ mei_txe_readiness_set_host_rdy(dev);
+
+ return 0;
+}
+
+/**
+ * mei_txe_check_and_ack_intrs - translate multi BAR interrupt into
+ * single bit mask and acknowledge the interrupts
+ *
+ * @dev: the device structure
+ * @do_ack: acknowledge interrupts
+ */
+static bool mei_txe_check_and_ack_intrs(struct mei_device *dev, bool do_ack)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ u32 hisr;
+ u32 hhisr;
+ u32 ipc_isr;
+ u32 aliveness;
+ bool generated;
+
+ /* read interrupt registers */
+ hhisr = mei_txe_br_reg_read(hw, HHISR_REG);
+ generated = (hhisr & IPC_HHIER_MSK);
+ if (!generated)
+ goto out;
+
+ hisr = mei_txe_br_reg_read(hw, HISR_REG);
+
+ aliveness = mei_txe_aliveness_get(dev);
+ if (hhisr & IPC_HHIER_SEC && aliveness)
+ ipc_isr = mei_txe_sec_reg_read_silent(hw,
+ SEC_IPC_HOST_INT_STATUS_REG);
+ else
+ ipc_isr = 0;
+
+ generated = generated ||
+ (hisr & HISR_INT_STS_MSK) ||
+ (ipc_isr & SEC_IPC_HOST_INT_STATUS_PENDING);
+
+ if (generated && do_ack) {
+ /* Save the interrupt causes */
+ hw->intr_cause |= hisr & HISR_INT_STS_MSK;
+ if (ipc_isr & SEC_IPC_HOST_INT_STATUS_IN_RDY)
+ hw->intr_cause |= TXE_INTR_IN_READY;
+
+
+ mei_txe_intr_disable(dev);
+ /* Clear the interrupts in hierarchy:
+ * IPC and Bridge, than the High Level */
+ mei_txe_sec_reg_write_silent(hw,
+ SEC_IPC_HOST_INT_STATUS_REG, ipc_isr);
+ mei_txe_br_reg_write(hw, HISR_REG, hisr);
+ mei_txe_br_reg_write(hw, HHISR_REG, hhisr);
+ }
+
+out:
+ return generated;
+}
+
+/**
+ * mei_txe_irq_quick_handler - The ISR of the MEI device
+ *
+ * @irq: The irq number
+ * @dev_id: pointer to the device structure
+ *
+ * returns irqreturn_t
+ */
+irqreturn_t mei_txe_irq_quick_handler(int irq, void *dev_id)
+{
+ struct mei_device *dev = dev_id;
+
+ if (mei_txe_check_and_ack_intrs(dev, true))
+ return IRQ_WAKE_THREAD;
+ return IRQ_NONE;
+}
+
+
+/**
+ * mei_txe_irq_thread_handler - txe interrupt thread
+ *
+ * @irq: The irq number
+ * @dev_id: pointer to the device structure
+ *
+ * returns irqreturn_t
+ *
+ */
+irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
+{
+ struct mei_device *dev = (struct mei_device *) dev_id;
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ struct mei_cl_cb complete_list;
+ s32 slots;
+ int rets = 0;
+
+ dev_dbg(&dev->pdev->dev, "irq thread: Interrupt Registers HHISR|HISR|SEC=%02X|%04X|%02X\n",
+ mei_txe_br_reg_read(hw, HHISR_REG),
+ mei_txe_br_reg_read(hw, HISR_REG),
+ mei_txe_sec_reg_read_silent(hw, SEC_IPC_HOST_INT_STATUS_REG));
+
+
+ /* initialize our complete list */
+ mutex_lock(&dev->device_lock);
+ mei_io_list_init(&complete_list);
+
+ if (pci_dev_msi_enabled(dev->pdev))
+ mei_txe_check_and_ack_intrs(dev, true);
+
+ /* show irq events */
+ mei_txe_pending_interrupts(dev);
+
+ hw->aliveness = mei_txe_aliveness_get(dev);
+ hw->readiness = mei_txe_readiness_get(dev);
+
+ /* Readiness:
+ * Detection of TXE driver going through reset
+ * or TXE driver resetting the HECI interface.
+ */
+ if (test_and_clear_bit(TXE_INTR_READINESS_BIT, &hw->intr_cause)) {
+ dev_dbg(&dev->pdev->dev, "Readiness Interrupt was received...\n");
+
+ /* Check if SeC is going through reset */
+ if (mei_txe_readiness_is_sec_rdy(hw->readiness)) {
+ dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
+ dev->recvd_hw_ready = true;
+ } else {
+ dev->recvd_hw_ready = false;
+ if (dev->dev_state != MEI_DEV_RESETTING) {
+
+ dev_warn(&dev->pdev->dev, "FW not ready: resetting.\n");
+ schedule_work(&dev->reset_work);
+ goto end;
+
+ }
+ }
+ wake_up(&dev->wait_hw_ready);
+ }
+
+ /************************************************************/
+ /* Check interrupt cause:
+ * Aliveness: Detection of SeC acknowledge of host request that
+ * it remain alive or host cancellation of that request.
+ */
+
+ if (test_and_clear_bit(TXE_INTR_ALIVENESS_BIT, &hw->intr_cause)) {
+ /* Clear the interrupt cause */
+ dev_dbg(&dev->pdev->dev,
+ "Aliveness Interrupt: Status: %d\n", hw->aliveness);
+ hw->recvd_aliveness = true;
+ if (waitqueue_active(&hw->wait_aliveness))
+ wake_up(&hw->wait_aliveness);
+ }
+
+
+ /* Output Doorbell:
+ * Detection of SeC having sent output to host
+ */
+ slots = mei_count_full_read_slots(dev);
+ if (test_and_clear_bit(TXE_INTR_OUT_DB_BIT, &hw->intr_cause)) {
+ /* Read from TXE */
+ rets = mei_irq_read_handler(dev, &complete_list, &slots);
+ if (rets && dev->dev_state != MEI_DEV_RESETTING) {
+ dev_err(&dev->pdev->dev,
+ "mei_irq_read_handler ret = %d.\n", rets);
+
+ schedule_work(&dev->reset_work);
+ goto end;
+ }
+ }
+ /* Input Ready: Detection if host can write to SeC */
+ if (test_and_clear_bit(TXE_INTR_IN_READY_BIT, &hw->intr_cause)) {
+ dev->hbuf_is_ready = true;
+ hw->slots = dev->hbuf_depth;
+ }
+
+ if (hw->aliveness && dev->hbuf_is_ready) {
+ /* get the real register value */
+ dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
+ rets = mei_irq_write_handler(dev, &complete_list);
+ if (rets && rets != -EMSGSIZE)
+ dev_err(&dev->pdev->dev, "mei_irq_write_handler ret = %d.\n",
+ rets);
+ dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
+ }
+
+ mei_irq_compl_handler(dev, &complete_list);
+
+end:
+ dev_dbg(&dev->pdev->dev, "interrupt thread end ret = %d\n", rets);
+
+ mutex_unlock(&dev->device_lock);
+
+ mei_enable_interrupts(dev);
+ return IRQ_HANDLED;
+}
+
+static const struct mei_hw_ops mei_txe_hw_ops = {
+
+ .host_is_ready = mei_txe_host_is_ready,
+
+ .hw_is_ready = mei_txe_hw_is_ready,
+ .hw_reset = mei_txe_hw_reset,
+ .hw_config = mei_txe_hw_config,
+ .hw_start = mei_txe_hw_start,
+
+ .intr_clear = mei_txe_intr_clear,
+ .intr_enable = mei_txe_intr_enable,
+ .intr_disable = mei_txe_intr_disable,
+
+ .hbuf_free_slots = mei_txe_hbuf_empty_slots,
+ .hbuf_is_ready = mei_txe_is_input_ready,
+ .hbuf_max_len = mei_txe_hbuf_max_len,
+
+ .write = mei_txe_write,
+
+ .rdbuf_full_slots = mei_txe_count_full_read_slots,
+ .read_hdr = mei_txe_read_hdr,
+
+ .read = mei_txe_read,
+
+};
+
+/**
+ * mei_txe_dev_init - allocates and initializes txe hardware specific structure
+ *
+ * @pdev - pci device
+ * returns struct mei_device * on success or NULL;
+ *
+ */
+struct mei_device *mei_txe_dev_init(struct pci_dev *pdev)
+{
+ struct mei_device *dev;
+ struct mei_txe_hw *hw;
+
+ dev = kzalloc(sizeof(struct mei_device) +
+ sizeof(struct mei_txe_hw), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ mei_device_init(dev);
+
+ hw = to_txe_hw(dev);
+
+ init_waitqueue_head(&hw->wait_aliveness);
+
+ dev->ops = &mei_txe_hw_ops;
+
+ dev->pdev = pdev;
+ return dev;
+}
+
+/**
+ * mei_txe_setup_satt2 - SATT2 configuration for DMA support.
+ *
+ * @dev: the device structure
+ * @addr: physical address start of the range
+ * @range: physical range size
+ */
+int mei_txe_setup_satt2(struct mei_device *dev, phys_addr_t addr, u32 range)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+
+ u32 lo32 = lower_32_bits(addr);
+ u32 hi32 = upper_32_bits(addr);
+ u32 ctrl;
+
+ /* SATT is limited to 36 Bits */
+ if (hi32 & ~0xF)
+ return -EINVAL;
+
+ /* SATT has to be 16Byte aligned */
+ if (lo32 & 0xF)
+ return -EINVAL;
+
+ /* SATT range has to be 4Bytes aligned */
+ if (range & 0x4)
+ return -EINVAL;
+
+ /* SATT is limited to 32 MB range*/
+ if (range > SATT_RANGE_MAX)
+ return -EINVAL;
+
+ ctrl = SATT2_CTRL_VALID_MSK;
+ ctrl |= hi32 << SATT2_CTRL_BR_BASE_ADDR_REG_SHIFT;
+
+ mei_txe_br_reg_write(hw, SATT2_SAP_SIZE_REG, range);
+ mei_txe_br_reg_write(hw, SATT2_BRG_BA_LSB_REG, lo32);
+ mei_txe_br_reg_write(hw, SATT2_CTRL_REG, ctrl);
+ dev_dbg(&dev->pdev->dev, "SATT2: SAP_SIZE_OFFSET=0x%08X, BRG_BA_LSB_OFFSET=0x%08X, CTRL_OFFSET=0x%08X\n",
+ range, lo32, ctrl);
+
+ return 0;
+}
diff --git a/drivers/misc/mei/hw-txe.h b/drivers/misc/mei/hw-txe.h
new file mode 100644
index 000000000000..0812d98633a4
--- /dev/null
+++ b/drivers/misc/mei/hw-txe.h
@@ -0,0 +1,74 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2013-2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef _MEI_HW_TXE_H_
+#define _MEI_HW_TXE_H_
+
+#include <linux/irqreturn.h>
+
+#include "hw.h"
+#include "hw-txe-regs.h"
+
+/* Flatten Hierarchy interrupt cause */
+#define TXE_INTR_READINESS_BIT 0 /* HISR_INT_0_STS */
+#define TXE_INTR_READINESS HISR_INT_0_STS
+#define TXE_INTR_ALIVENESS_BIT 1 /* HISR_INT_1_STS */
+#define TXE_INTR_ALIVENESS HISR_INT_1_STS
+#define TXE_INTR_OUT_DB_BIT 2 /* HISR_INT_2_STS */
+#define TXE_INTR_OUT_DB HISR_INT_2_STS
+#define TXE_INTR_IN_READY_BIT 8 /* beyond HISR */
+#define TXE_INTR_IN_READY BIT(8)
+
+/**
+ * struct mei_txe_hw - txe hardware specifics
+ *
+ * @mem_addr: SeC and BRIDGE bars
+ * @aliveness: aliveness (power gating) state of the hardware
+ * @readiness: readiness state of the hardware
+ * @wait_aliveness: aliveness wait queue
+ * @recvd_aliveness: aliveness interrupt was recived
+ * @intr_cause: translated interrupt cause
+ */
+struct mei_txe_hw {
+ void __iomem *mem_addr[NUM_OF_MEM_BARS];
+ u32 aliveness;
+ u32 readiness;
+ u32 slots;
+
+ wait_queue_head_t wait_aliveness;
+ bool recvd_aliveness;
+
+ unsigned long intr_cause;
+};
+
+#define to_txe_hw(dev) (struct mei_txe_hw *)((dev)->hw)
+
+static inline struct mei_device *hw_txe_to_mei(struct mei_txe_hw *hw)
+{
+ return container_of((void *)hw, struct mei_device, hw);
+}
+
+struct mei_device *mei_txe_dev_init(struct pci_dev *pdev);
+
+irqreturn_t mei_txe_irq_quick_handler(int irq, void *dev_id);
+irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id);
+
+int mei_txe_aliveness_set_sync(struct mei_device *dev, u32 req);
+
+int mei_txe_setup_satt2(struct mei_device *dev, phys_addr_t addr, u32 range);
+
+
+#endif /* _MEI_HW_TXE_H_ */
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index dd44e33ad2b6..6b476ab49b2e 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -22,7 +22,7 @@
/*
* Timeouts in Seconds
*/
-#define MEI_INTEROP_TIMEOUT 7 /* Timeout on ready message */
+#define MEI_HW_READY_TIMEOUT 2 /* Timeout on ready message */
#define MEI_CONNECT_TIMEOUT 3 /* HPS: at least 2 seconds */
#define MEI_CL_CONNECT_TIMEOUT 15 /* HPS: Client Connect Timeout */
@@ -31,13 +31,13 @@
#define MEI_IAMTHIF_STALL_TIMER 12 /* HPS */
#define MEI_IAMTHIF_READ_TIMER 10 /* HPS */
+#define MEI_HBM_TIMEOUT 1 /* 1 second */
/*
* MEI Version
*/
#define HBM_MINOR_VERSION 0
#define HBM_MAJOR_VERSION 1
-#define HBM_TIMEOUT 1 /* 1 second */
/* Host bus message command opcode */
#define MEI_HBM_CMD_OP_MSK 0x7f
@@ -89,19 +89,19 @@ enum mei_stop_reason_types {
* Client Connect Status
* used by hbm_client_connect_response.status
*/
-enum client_connect_status_types {
- CCS_SUCCESS = 0x00,
- CCS_NOT_FOUND = 0x01,
- CCS_ALREADY_STARTED = 0x02,
- CCS_OUT_OF_RESOURCES = 0x03,
- CCS_MESSAGE_SMALL = 0x04
+enum mei_cl_connect_status {
+ MEI_CL_CONN_SUCCESS = 0x00,
+ MEI_CL_CONN_NOT_FOUND = 0x01,
+ MEI_CL_CONN_ALREADY_STARTED = 0x02,
+ MEI_CL_CONN_OUT_OF_RESOURCES = 0x03,
+ MEI_CL_CONN_MESSAGE_SMALL = 0x04
};
/*
* Client Disconnect Status
*/
-enum client_disconnect_status_types {
- CDS_SUCCESS = 0x00
+enum mei_cl_disconnect_status {
+ MEI_CL_DISCONN_SUCCESS = 0x00
};
/*
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index cdd31c2a2a2b..4460975c0eef 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -116,7 +116,6 @@ int mei_reset(struct mei_device *dev)
mei_cl_unlink(&dev->wd_cl);
mei_cl_unlink(&dev->iamthif_cl);
mei_amthif_reset_params(dev);
- memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg));
}
@@ -126,7 +125,6 @@ int mei_reset(struct mei_device *dev)
if (ret) {
dev_err(&dev->pdev->dev, "hw_reset failed ret = %d\n", ret);
- dev->dev_state = MEI_DEV_DISABLED;
return ret;
}
@@ -139,7 +137,6 @@ int mei_reset(struct mei_device *dev)
ret = mei_hw_start(dev);
if (ret) {
dev_err(&dev->pdev->dev, "hw_start failed ret = %d\n", ret);
- dev->dev_state = MEI_DEV_DISABLED;
return ret;
}
@@ -149,7 +146,7 @@ int mei_reset(struct mei_device *dev)
ret = mei_hbm_start_req(dev);
if (ret) {
dev_err(&dev->pdev->dev, "hbm_start failed ret = %d\n", ret);
- dev->dev_state = MEI_DEV_DISABLED;
+ dev->dev_state = MEI_DEV_RESETTING;
return ret;
}
@@ -166,6 +163,7 @@ EXPORT_SYMBOL_GPL(mei_reset);
*/
int mei_start(struct mei_device *dev)
{
+ int ret;
mutex_lock(&dev->device_lock);
/* acknowledge interrupt and stop interrupts */
@@ -175,10 +173,18 @@ int mei_start(struct mei_device *dev)
dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
- dev->dev_state = MEI_DEV_INITIALIZING;
dev->reset_count = 0;
- mei_reset(dev);
+ do {
+ dev->dev_state = MEI_DEV_INITIALIZING;
+ ret = mei_reset(dev);
+
+ if (ret == -ENODEV || dev->dev_state == MEI_DEV_DISABLED) {
+ dev_err(&dev->pdev->dev, "reset failed ret = %d", ret);
+ goto err;
+ }
+ } while (ret);
+ /* we cannot start the device w/o hbm start message completed */
if (dev->dev_state == MEI_DEV_DISABLED) {
dev_err(&dev->pdev->dev, "reset failed");
goto err;
@@ -238,27 +244,40 @@ int mei_restart(struct mei_device *dev)
mutex_unlock(&dev->device_lock);
- if (err || dev->dev_state == MEI_DEV_DISABLED)
+ if (err == -ENODEV || dev->dev_state == MEI_DEV_DISABLED) {
+ dev_err(&dev->pdev->dev, "device disabled = %d\n", err);
return -ENODEV;
+ }
+
+ /* try to start again */
+ if (err)
+ schedule_work(&dev->reset_work);
+
return 0;
}
EXPORT_SYMBOL_GPL(mei_restart);
-
static void mei_reset_work(struct work_struct *work)
{
struct mei_device *dev =
container_of(work, struct mei_device, reset_work);
+ int ret;
mutex_lock(&dev->device_lock);
- mei_reset(dev);
+ ret = mei_reset(dev);
mutex_unlock(&dev->device_lock);
- if (dev->dev_state == MEI_DEV_DISABLED)
- dev_err(&dev->pdev->dev, "reset failed");
+ if (dev->dev_state == MEI_DEV_DISABLED) {
+ dev_err(&dev->pdev->dev, "device disabled = %d\n", ret);
+ return;
+ }
+
+ /* retry reset in case of failure */
+ if (ret)
+ schedule_work(&dev->reset_work);
}
void mei_stop(struct mei_device *dev)
@@ -269,6 +288,8 @@ void mei_stop(struct mei_device *dev)
mei_nfc_host_exit(dev);
+ mei_cl_bus_remove_devices(dev);
+
mutex_lock(&dev->device_lock);
mei_wd_stop(dev);
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index f0fbb5179f80..29b5af8efb71 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -26,7 +26,6 @@
#include "mei_dev.h"
#include "hbm.h"
-#include "hw-me.h"
#include "client.h"
@@ -161,29 +160,63 @@ static int mei_cl_irq_read_msg(struct mei_device *dev,
}
/**
+ * mei_cl_irq_disconnect_rsp - send disconnection response message
+ *
+ * @cl: client
+ * @cb: callback block.
+ * @cmpl_list: complete list.
+ *
+ * returns 0, OK; otherwise, error.
+ */
+static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb,
+ struct mei_cl_cb *cmpl_list)
+{
+ struct mei_device *dev = cl->dev;
+ u32 msg_slots;
+ int slots;
+ int ret;
+
+ slots = mei_hbuf_empty_slots(dev);
+ msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_response));
+
+ if (slots < msg_slots)
+ return -EMSGSIZE;
+
+ ret = mei_hbm_cl_disconnect_rsp(dev, cl);
+
+ cl->state = MEI_FILE_DISCONNECTED;
+ cl->status = 0;
+ list_del(&cb->list);
+ mei_io_cb_free(cb);
+
+ return ret;
+}
+
+
+
+/**
* mei_cl_irq_close - processes close related operation from
* interrupt thread context - send disconnect request
*
* @cl: client
* @cb: callback block.
- * @slots: free slots.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise, error.
*/
static int mei_cl_irq_close(struct mei_cl *cl, struct mei_cl_cb *cb,
- s32 *slots, struct mei_cl_cb *cmpl_list)
+ struct mei_cl_cb *cmpl_list)
{
struct mei_device *dev = cl->dev;
+ u32 msg_slots;
+ int slots;
- u32 msg_slots =
- mei_data2slots(sizeof(struct hbm_client_connect_request));
+ msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request));
+ slots = mei_hbuf_empty_slots(dev);
- if (*slots < msg_slots)
+ if (slots < msg_slots)
return -EMSGSIZE;
- *slots -= msg_slots;
-
if (mei_hbm_cl_disconnect_req(dev, cl)) {
cl->status = 0;
cb->buf_idx = 0;
@@ -207,27 +240,23 @@ static int mei_cl_irq_close(struct mei_cl *cl, struct mei_cl_cb *cb,
*
* @cl: client
* @cb: callback block.
- * @slots: free slots.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise, error.
*/
static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
- s32 *slots, struct mei_cl_cb *cmpl_list)
+ struct mei_cl_cb *cmpl_list)
{
struct mei_device *dev = cl->dev;
- u32 msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));
-
+ u32 msg_slots;
+ int slots;
int ret;
+ msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));
+ slots = mei_hbuf_empty_slots(dev);
- if (*slots < msg_slots) {
- /* return the cancel routine */
- list_del(&cb->list);
+ if (slots < msg_slots)
return -EMSGSIZE;
- }
-
- *slots -= msg_slots;
ret = mei_hbm_cl_flow_control_req(dev, cl);
if (ret) {
@@ -244,32 +273,30 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
/**
- * mei_cl_irq_ioctl - processes client ioctl related operation from the
- * interrupt thread context - send connection request
+ * mei_cl_irq_connect - send connect request in irq_thread context
*
* @cl: client
* @cb: callback block.
- * @slots: free slots.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise, error.
*/
-static int mei_cl_irq_ioctl(struct mei_cl *cl, struct mei_cl_cb *cb,
- s32 *slots, struct mei_cl_cb *cmpl_list)
+static int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
+ struct mei_cl_cb *cmpl_list)
{
struct mei_device *dev = cl->dev;
+ u32 msg_slots;
+ int slots;
int ret;
- u32 msg_slots =
- mei_data2slots(sizeof(struct hbm_client_connect_request));
+ msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request));
+ slots = mei_hbuf_empty_slots(dev);
- if (*slots < msg_slots) {
- /* return the cancel routine */
- list_del(&cb->list);
- return -EMSGSIZE;
- }
+ if (mei_cl_is_other_connecting(cl))
+ return 0;
- *slots -= msg_slots;
+ if (slots < msg_slots)
+ return -EMSGSIZE;
cl->state = MEI_FILE_CONNECTING;
@@ -323,7 +350,7 @@ int mei_irq_read_handler(struct mei_device *dev,
dev_err(&dev->pdev->dev, "less data available than length=%08x.\n",
*slots);
/* we can't read the message */
- ret = -ERANGE;
+ ret = -ENODATA;
goto end;
}
@@ -409,10 +436,10 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
s32 slots;
int ret;
- if (!mei_hbuf_is_ready(dev)) {
- dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n");
+
+ if (!mei_hbuf_acquire(dev))
return 0;
- }
+
slots = mei_hbuf_empty_slots(dev);
if (slots <= 0)
return -EMSGSIZE;
@@ -447,29 +474,16 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
if (dev->wd_state == MEI_WD_STOPPING) {
dev->wd_state = MEI_WD_IDLE;
- wake_up_interruptible(&dev->wait_stop_wd);
+ wake_up(&dev->wait_stop_wd);
}
- if (dev->wr_ext_msg.hdr.length) {
- mei_write_message(dev, &dev->wr_ext_msg.hdr,
- dev->wr_ext_msg.data);
- slots -= mei_data2slots(dev->wr_ext_msg.hdr.length);
- dev->wr_ext_msg.hdr.length = 0;
- }
- if (dev->dev_state == MEI_DEV_ENABLED) {
+ if (mei_cl_is_connected(&dev->wd_cl)) {
if (dev->wd_pending &&
mei_cl_flow_ctrl_creds(&dev->wd_cl) > 0) {
- if (mei_wd_send(dev))
- dev_dbg(&dev->pdev->dev, "wd send failed.\n");
- else if (mei_cl_flow_ctrl_reduce(&dev->wd_cl))
- return -ENODEV;
-
+ ret = mei_wd_send(dev);
+ if (ret)
+ return ret;
dev->wd_pending = false;
-
- if (dev->wd_state == MEI_WD_RUNNING)
- slots -= mei_data2slots(MEI_WD_START_MSG_SIZE);
- else
- slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE);
}
}
@@ -484,28 +498,31 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
switch (cb->fop_type) {
case MEI_FOP_CLOSE:
/* send disconnect message */
- ret = mei_cl_irq_close(cl, cb, &slots, cmpl_list);
+ ret = mei_cl_irq_close(cl, cb, cmpl_list);
if (ret)
return ret;
break;
case MEI_FOP_READ:
/* send flow control message */
- ret = mei_cl_irq_read(cl, cb, &slots, cmpl_list);
+ ret = mei_cl_irq_read(cl, cb, cmpl_list);
if (ret)
return ret;
break;
- case MEI_FOP_IOCTL:
+ case MEI_FOP_CONNECT:
/* connect message */
- if (mei_cl_is_other_connecting(cl))
- continue;
- ret = mei_cl_irq_ioctl(cl, cb, &slots, cmpl_list);
+ ret = mei_cl_irq_connect(cl, cb, cmpl_list);
if (ret)
return ret;
break;
-
+ case MEI_FOP_DISCONNECT_RSP:
+ /* send disconnect resp */
+ ret = mei_cl_irq_disconnect_rsp(cl, cb, cmpl_list);
+ if (ret)
+ return ret;
+ break;
default:
BUG();
}
@@ -518,11 +535,9 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
if (cl == NULL)
continue;
if (cl == &dev->iamthif_cl)
- ret = mei_amthif_irq_write_complete(cl, cb,
- &slots, cmpl_list);
+ ret = mei_amthif_irq_write(cl, cb, cmpl_list);
else
- ret = mei_cl_irq_write_complete(cl, cb,
- &slots, cmpl_list);
+ ret = mei_cl_irq_write(cl, cb, cmpl_list);
if (ret)
return ret;
}
@@ -541,8 +556,7 @@ EXPORT_SYMBOL_GPL(mei_irq_write_handler);
void mei_timer(struct work_struct *work)
{
unsigned long timeout;
- struct mei_cl *cl_pos = NULL;
- struct mei_cl *cl_next = NULL;
+ struct mei_cl *cl;
struct mei_cl_cb *cb_pos = NULL;
struct mei_cl_cb *cb_next = NULL;
@@ -570,9 +584,9 @@ void mei_timer(struct work_struct *work)
goto out;
/*** connect/disconnect timeouts ***/
- list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
- if (cl_pos->timer_count) {
- if (--cl_pos->timer_count == 0) {
+ list_for_each_entry(cl, &dev->file_list, link) {
+ if (cl->timer_count) {
+ if (--cl->timer_count == 0) {
dev_err(&dev->pdev->dev, "timer: connect/disconnect timeout.\n");
mei_reset(dev);
goto out;
@@ -580,6 +594,9 @@ void mei_timer(struct work_struct *work)
}
}
+ if (!mei_cl_is_connected(&dev->iamthif_cl))
+ goto out;
+
if (dev->iamthif_stall_timer) {
if (--dev->iamthif_stall_timer == 0) {
dev_err(&dev->pdev->dev, "timer: amthif hanged.\n");
@@ -619,10 +636,10 @@ void mei_timer(struct work_struct *work)
list_for_each_entry_safe(cb_pos, cb_next,
&dev->amthif_rd_complete_list.list, list) {
- cl_pos = cb_pos->file_object->private_data;
+ cl = cb_pos->file_object->private_data;
/* Finding the AMTHI entry. */
- if (cl_pos == &dev->iamthif_cl)
+ if (cl == &dev->iamthif_cl)
list_del(&cb_pos->list);
}
mei_io_cb_free(dev->iamthif_current_cb);
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 5424f8ff3f7f..b35594dbf52f 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -13,9 +13,6 @@
* more details.
*
*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -40,7 +37,6 @@
#include <linux/mei.h>
#include "mei_dev.h"
-#include "hw-me.h"
#include "client.h"
/**
@@ -129,17 +125,11 @@ static int mei_release(struct inode *inode, struct file *file)
}
if (cl->state == MEI_FILE_CONNECTED) {
cl->state = MEI_FILE_DISCONNECTING;
- dev_dbg(&dev->pdev->dev,
- "disconnecting client host client = %d, "
- "ME client = %d\n",
- cl->host_client_id,
- cl->me_client_id);
+ cl_dbg(dev, cl, "disconnecting\n");
rets = mei_cl_disconnect(cl);
}
mei_cl_flush_queues(cl);
- dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n",
- cl->host_client_id,
- cl->me_client_id);
+ cl_dbg(dev, cl, "removing\n");
mei_cl_unlink(cl);
@@ -284,6 +274,7 @@ copy_buffer:
length = min_t(size_t, length, cb->buf_idx - *offset);
if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) {
+ dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n");
rets = -EFAULT;
goto free;
}
@@ -340,7 +331,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
id = mei_me_cl_by_id(dev, cl->me_client_id);
if (id < 0) {
- rets = -ENODEV;
+ rets = -ENOTTY;
goto out;
}
@@ -404,7 +395,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
rets = copy_from_user(write_cb->request_buffer.data, ubuf, length);
if (rets) {
- dev_err(&dev->pdev->dev, "failed to copy data from userland\n");
+ dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n");
rets = -EFAULT;
goto out;
}
@@ -471,7 +462,7 @@ static int mei_ioctl_connect_client(struct file *file,
if (i < 0 || dev->me_clients[i].props.fixed_address) {
dev_dbg(&dev->pdev->dev, "Cannot connect to FW Client UUID = %pUl\n",
&data->in_client_uuid);
- rets = -ENODEV;
+ rets = -ENOTTY;
goto end;
}
@@ -569,7 +560,7 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
dev_dbg(&dev->pdev->dev, "copy connect data from user\n");
if (copy_from_user(connect_data, (char __user *)data,
sizeof(struct mei_connect_client_data))) {
- dev_err(&dev->pdev->dev, "failed to copy data from userland\n");
+ dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n");
rets = -EFAULT;
goto out;
}
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index f7de95b4cdd9..94a516716d22 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -24,7 +24,6 @@
#include <linux/mei_cl_bus.h>
#include "hw.h"
-#include "hw-me-regs.h"
#include "hbm.h"
/*
@@ -130,16 +129,18 @@ enum mei_wd_states {
/**
* enum mei_cb_file_ops - file operation associated with the callback
- * @MEI_FOP_READ - read
- * @MEI_FOP_WRITE - write
- * @MEI_FOP_IOCTL - ioctl
- * @MEI_FOP_OPEN - open
- * @MEI_FOP_CLOSE - close
+ * @MEI_FOP_READ - read
+ * @MEI_FOP_WRITE - write
+ * @MEI_FOP_CONNECT - connect
+ * @MEI_FOP_DISCONNECT_RSP - disconnect response
+ * @MEI_FOP_OPEN - open
+ * @MEI_FOP_CLOSE - close
*/
enum mei_cb_file_ops {
MEI_FOP_READ = 0,
MEI_FOP_WRITE,
- MEI_FOP_IOCTL,
+ MEI_FOP_CONNECT,
+ MEI_FOP_DISCONNECT_RSP,
MEI_FOP_OPEN,
MEI_FOP_CLOSE
};
@@ -236,20 +237,20 @@ struct mei_cl {
*/
struct mei_hw_ops {
- bool (*host_is_ready) (struct mei_device *dev);
+ bool (*host_is_ready)(struct mei_device *dev);
- bool (*hw_is_ready) (struct mei_device *dev);
- int (*hw_reset) (struct mei_device *dev, bool enable);
- int (*hw_start) (struct mei_device *dev);
- void (*hw_config) (struct mei_device *dev);
+ bool (*hw_is_ready)(struct mei_device *dev);
+ int (*hw_reset)(struct mei_device *dev, bool enable);
+ int (*hw_start)(struct mei_device *dev);
+ void (*hw_config)(struct mei_device *dev);
- void (*intr_clear) (struct mei_device *dev);
- void (*intr_enable) (struct mei_device *dev);
- void (*intr_disable) (struct mei_device *dev);
+ void (*intr_clear)(struct mei_device *dev);
+ void (*intr_enable)(struct mei_device *dev);
+ void (*intr_disable)(struct mei_device *dev);
- int (*hbuf_free_slots) (struct mei_device *dev);
- bool (*hbuf_is_ready) (struct mei_device *dev);
- size_t (*hbuf_max_len) (const struct mei_device *dev);
+ int (*hbuf_free_slots)(struct mei_device *dev);
+ bool (*hbuf_is_ready)(struct mei_device *dev);
+ size_t (*hbuf_max_len)(const struct mei_device *dev);
int (*write)(struct mei_device *dev,
struct mei_msg_hdr *hdr,
@@ -258,7 +259,7 @@ struct mei_hw_ops {
int (*rdbuf_full_slots)(struct mei_device *dev);
u32 (*read_hdr)(const struct mei_device *dev);
- int (*read) (struct mei_device *dev,
+ int (*read)(struct mei_device *dev,
unsigned char *buf, unsigned long len);
};
@@ -294,6 +295,7 @@ int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length);
int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length);
int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
void mei_cl_bus_rx_event(struct mei_cl *cl);
+void mei_cl_bus_remove_devices(struct mei_device *dev);
int mei_cl_bus_init(void);
void mei_cl_bus_exit(void);
@@ -339,7 +341,6 @@ struct mei_cl_device {
* @hbuf_depth - depth of hardware host/write buffer is slots
* @hbuf_is_ready - query if the host host/write buffer is ready
* @wr_msg - the buffer for hbm control messages
- * @wr_ext_msg - the buffer for hbm control responses (set in read cycle)
*/
struct mei_device {
struct pci_dev *pdev; /* pointer to pci device struct */
@@ -394,11 +395,6 @@ struct mei_device {
unsigned char data[128];
} wr_msg;
- struct {
- struct mei_msg_hdr hdr;
- unsigned char data[4]; /* All HBM messages are 4 bytes */
- } wr_ext_msg; /* for control responses */
-
struct hbm_version version;
struct mei_me_client *me_clients; /* Note: memory has to be allocated */
@@ -518,8 +514,8 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
void mei_amthif_run_next_cmd(struct mei_device *dev);
-int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
- s32 *slots, struct mei_cl_cb *cmpl_list);
+int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
+ struct mei_cl_cb *cmpl_list);
void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb);
int mei_amthif_irq_read_msg(struct mei_device *dev,
@@ -546,7 +542,7 @@ int mei_wd_host_init(struct mei_device *dev);
* once we got connection to the WD Client
* @dev - mei device
*/
-void mei_watchdog_register(struct mei_device *dev);
+int mei_watchdog_register(struct mei_device *dev);
/*
* mei_watchdog_unregister - Unregistering watchdog interface
* @dev - mei device
@@ -633,6 +629,8 @@ static inline int mei_count_full_read_slots(struct mei_device *dev)
return dev->ops->rdbuf_full_slots(dev);
}
+bool mei_hbuf_acquire(struct mei_device *dev);
+
#if IS_ENABLED(CONFIG_DEBUG_FS)
int mei_dbgfs_register(struct mei_device *dev, const char *name);
void mei_dbgfs_deregister(struct mei_device *dev);
diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
index a58320c0c049..3095fc514a65 100644
--- a/drivers/misc/mei/nfc.c
+++ b/drivers/misc/mei/nfc.c
@@ -364,7 +364,7 @@ static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
if (!wait_event_interruptible_timeout(ndev->send_wq,
ndev->recv_req_id == ndev->req_id, HZ)) {
dev_err(&dev->pdev->dev, "NFC MEI command timeout\n");
- err = -ETIMEDOUT;
+ err = -ETIME;
} else {
ndev->req_id++;
}
@@ -502,7 +502,7 @@ int mei_nfc_host_init(struct mei_device *dev)
i = mei_me_cl_by_uuid(dev, &mei_nfc_info_guid);
if (i < 0) {
dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
- ret = -ENOENT;
+ ret = -ENOTTY;
goto err;
}
@@ -520,7 +520,7 @@ int mei_nfc_host_init(struct mei_device *dev)
i = mei_me_cl_by_uuid(dev, &mei_nfc_guid);
if (i < 0) {
dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
- ret = -ENOENT;
+ ret = -ENOTTY;
goto err;
}
@@ -552,13 +552,7 @@ err:
void mei_nfc_host_exit(struct mei_device *dev)
{
struct mei_nfc_dev *ndev = &nfc_dev;
-
cancel_work_sync(&ndev->init_work);
+}
- mutex_lock(&dev->device_lock);
- if (ndev->cl && ndev->cl->device)
- mei_cl_remove_device(ndev->cl->device);
- mei_nfc_free(ndev);
- mutex_unlock(&dev->device_lock);
-}
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index ddadd08956f4..1c8fd3a3e135 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -13,9 +13,6 @@
* more details.
*
*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -27,7 +24,6 @@
#include <linux/aio.h>
#include <linux/pci.h>
#include <linux/poll.h>
-#include <linux/init.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/sched.h>
@@ -40,11 +36,12 @@
#include <linux/mei.h>
#include "mei_dev.h"
-#include "hw-me.h"
#include "client.h"
+#include "hw-me-regs.h"
+#include "hw-me.h"
/* mei_pci_tbl - PCI Device ID Table */
-static DEFINE_PCI_DEVICE_TABLE(mei_me_pci_tbl) = {
+static const struct pci_device_id mei_me_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82946GZ)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G35)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82Q965)},
@@ -270,7 +267,7 @@ static void mei_me_remove(struct pci_dev *pdev)
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int mei_me_pci_suspend(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
@@ -330,11 +327,12 @@ static int mei_me_pci_resume(struct device *device)
return 0;
}
+
static SIMPLE_DEV_PM_OPS(mei_me_pm_ops, mei_me_pci_suspend, mei_me_pci_resume);
#define MEI_ME_PM_OPS (&mei_me_pm_ops)
#else
#define MEI_ME_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
/*
* PCI driver structure
*/
diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c
new file mode 100644
index 000000000000..ad3adb009a1e
--- /dev/null
+++ b/drivers/misc/mei/pci-txe.c
@@ -0,0 +1,293 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2013-2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/uuid.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+
+#include <linux/mei.h>
+
+
+#include "mei_dev.h"
+#include "hw-txe.h"
+
+static const struct pci_device_id mei_txe_pci_tbl[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0F18)}, /* Baytrail */
+ {0, }
+};
+MODULE_DEVICE_TABLE(pci, mei_txe_pci_tbl);
+
+
+static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw)
+{
+ int i;
+ for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) {
+ if (hw->mem_addr[i]) {
+ pci_iounmap(pdev, hw->mem_addr[i]);
+ hw->mem_addr[i] = NULL;
+ }
+ }
+}
+/**
+ * mei_probe - Device Initialization Routine
+ *
+ * @pdev: PCI device structure
+ * @ent: entry in mei_txe_pci_tbl
+ *
+ * returns 0 on success, <0 on failure.
+ */
+static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct mei_device *dev;
+ struct mei_txe_hw *hw;
+ int err;
+ int i;
+
+ /* enable pci dev */
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to enable pci device.\n");
+ goto end;
+ }
+ /* set PCI host mastering */
+ pci_set_master(pdev);
+ /* pci request regions for mei driver */
+ err = pci_request_regions(pdev, KBUILD_MODNAME);
+ if (err) {
+ dev_err(&pdev->dev, "failed to get pci regions.\n");
+ goto disable_device;
+ }
+
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
+ if (err) {
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (err) {
+ dev_err(&pdev->dev, "No suitable DMA available.\n");
+ goto release_regions;
+ }
+ }
+
+ /* allocates and initializes the mei dev structure */
+ dev = mei_txe_dev_init(pdev);
+ if (!dev) {
+ err = -ENOMEM;
+ goto release_regions;
+ }
+ hw = to_txe_hw(dev);
+
+ /* mapping IO device memory */
+ for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) {
+ hw->mem_addr[i] = pci_iomap(pdev, i, 0);
+ if (!hw->mem_addr[i]) {
+ dev_err(&pdev->dev, "mapping I/O device memory failure.\n");
+ err = -ENOMEM;
+ goto free_device;
+ }
+ }
+
+
+ pci_enable_msi(pdev);
+
+ /* clear spurious interrupts */
+ mei_clear_interrupts(dev);
+
+ /* request and enable interrupt */
+ if (pci_dev_msi_enabled(pdev))
+ err = request_threaded_irq(pdev->irq,
+ NULL,
+ mei_txe_irq_thread_handler,
+ IRQF_ONESHOT, KBUILD_MODNAME, dev);
+ else
+ err = request_threaded_irq(pdev->irq,
+ mei_txe_irq_quick_handler,
+ mei_txe_irq_thread_handler,
+ IRQF_SHARED, KBUILD_MODNAME, dev);
+ if (err) {
+ dev_err(&pdev->dev, "mei: request_threaded_irq failure. irq = %d\n",
+ pdev->irq);
+ goto free_device;
+ }
+
+ if (mei_start(dev)) {
+ dev_err(&pdev->dev, "init hw failure.\n");
+ err = -ENODEV;
+ goto release_irq;
+ }
+
+ err = mei_register(dev);
+ if (err)
+ goto release_irq;
+
+ pci_set_drvdata(pdev, dev);
+
+ return 0;
+
+release_irq:
+
+ mei_cancel_work(dev);
+
+ /* disable interrupts */
+ mei_disable_interrupts(dev);
+
+ free_irq(pdev->irq, dev);
+ pci_disable_msi(pdev);
+
+free_device:
+ mei_txe_pci_iounmap(pdev, hw);
+
+ kfree(dev);
+release_regions:
+ pci_release_regions(pdev);
+disable_device:
+ pci_disable_device(pdev);
+end:
+ dev_err(&pdev->dev, "initialization failed.\n");
+ return err;
+}
+
+/**
+ * mei_remove - Device Removal Routine
+ *
+ * @pdev: PCI device structure
+ *
+ * mei_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.
+ */
+static void mei_txe_remove(struct pci_dev *pdev)
+{
+ struct mei_device *dev;
+ struct mei_txe_hw *hw;
+
+ dev = pci_get_drvdata(pdev);
+ if (!dev) {
+ dev_err(&pdev->dev, "mei: dev =NULL\n");
+ return;
+ }
+
+ hw = to_txe_hw(dev);
+
+ mei_stop(dev);
+
+ /* disable interrupts */
+ mei_disable_interrupts(dev);
+ free_irq(pdev->irq, dev);
+ pci_disable_msi(pdev);
+
+ pci_set_drvdata(pdev, NULL);
+
+ mei_txe_pci_iounmap(pdev, hw);
+
+ mei_deregister(dev);
+
+ kfree(dev);
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+
+#ifdef CONFIG_PM_SLEEP
+static int mei_txe_pci_suspend(struct device *device)
+{
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct mei_device *dev = pci_get_drvdata(pdev);
+
+ if (!dev)
+ return -ENODEV;
+
+ dev_dbg(&pdev->dev, "suspend\n");
+
+ mei_stop(dev);
+
+ mei_disable_interrupts(dev);
+
+ free_irq(pdev->irq, dev);
+ pci_disable_msi(pdev);
+
+ return 0;
+}
+
+static int mei_txe_pci_resume(struct device *device)
+{
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct mei_device *dev;
+ int err;
+
+ dev = pci_get_drvdata(pdev);
+ if (!dev)
+ return -ENODEV;
+
+ pci_enable_msi(pdev);
+
+ mei_clear_interrupts(dev);
+
+ /* request and enable interrupt */
+ if (pci_dev_msi_enabled(pdev))
+ err = request_threaded_irq(pdev->irq,
+ NULL,
+ mei_txe_irq_thread_handler,
+ IRQF_ONESHOT, KBUILD_MODNAME, dev);
+ else
+ err = request_threaded_irq(pdev->irq,
+ mei_txe_irq_quick_handler,
+ mei_txe_irq_thread_handler,
+ IRQF_SHARED, KBUILD_MODNAME, dev);
+ if (err) {
+ dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n",
+ pdev->irq);
+ return err;
+ }
+
+ err = mei_restart(dev);
+
+ return err;
+}
+
+static SIMPLE_DEV_PM_OPS(mei_txe_pm_ops,
+ mei_txe_pci_suspend,
+ mei_txe_pci_resume);
+
+#define MEI_TXE_PM_OPS (&mei_txe_pm_ops)
+#else
+#define MEI_TXE_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+/*
+ * PCI driver structure
+ */
+static struct pci_driver mei_txe_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = mei_txe_pci_tbl,
+ .probe = mei_txe_probe,
+ .remove = mei_txe_remove,
+ .shutdown = mei_txe_remove,
+ .driver.pm = MEI_TXE_PM_OPS,
+};
+
+module_pci_driver(mei_txe_driver);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Intel(R) Trusted Execution Environment Interface");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
index f70945ed96f6..ebf1cbc198fd 100644
--- a/drivers/misc/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -25,7 +25,6 @@
#include "mei_dev.h"
#include "hbm.h"
-#include "hw-me.h"
#include "client.h"
static const u8 mei_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 };
@@ -53,7 +52,7 @@ static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
*
* @dev: the device structure
*
- * returns -ENENT if wd client cannot be found
+ * returns -ENOTTY if wd client cannot be found
* -EIO if write has failed
* 0 on success
*/
@@ -73,7 +72,7 @@ int mei_wd_host_init(struct mei_device *dev)
id = mei_me_cl_by_uuid(dev, &mei_wd_guid);
if (id < 0) {
dev_info(&dev->pdev->dev, "wd: failed to find the client\n");
- return id;
+ return -ENOTTY;
}
cl->me_client_id = dev->me_clients[id].client_id;
@@ -87,15 +86,20 @@ int mei_wd_host_init(struct mei_device *dev)
cl->state = MEI_FILE_CONNECTING;
- if (mei_hbm_cl_connect_req(dev, cl)) {
- dev_err(&dev->pdev->dev, "wd: failed to connect to the client\n");
- cl->state = MEI_FILE_DISCONNECTED;
- cl->host_client_id = 0;
- return -EIO;
+ ret = mei_cl_connect(cl, NULL);
+
+ if (ret) {
+ dev_err(&dev->pdev->dev, "wd: failed to connect = %d\n", ret);
+ mei_cl_unlink(cl);
+ return ret;
}
- cl->timer_count = MEI_CONNECT_TIMEOUT;
- return 0;
+ ret = mei_watchdog_register(dev);
+ if (ret) {
+ mei_cl_disconnect(cl);
+ mei_cl_unlink(cl);
+ }
+ return ret;
}
/**
@@ -106,13 +110,16 @@ int mei_wd_host_init(struct mei_device *dev)
* returns 0 if success,
* -EIO when message send fails
* -EINVAL when invalid message is to be sent
+ * -ENODEV on flow control failure
*/
int mei_wd_send(struct mei_device *dev)
{
+ struct mei_cl *cl = &dev->wd_cl;
struct mei_msg_hdr hdr;
+ int ret;
- hdr.host_addr = dev->wd_cl.host_client_id;
- hdr.me_addr = dev->wd_cl.me_client_id;
+ hdr.host_addr = cl->host_client_id;
+ hdr.me_addr = cl->me_client_id;
hdr.msg_complete = 1;
hdr.reserved = 0;
hdr.internal = 0;
@@ -121,10 +128,24 @@ int mei_wd_send(struct mei_device *dev)
hdr.length = MEI_WD_START_MSG_SIZE;
else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_HDR_SIZE))
hdr.length = MEI_WD_STOP_MSG_SIZE;
- else
+ else {
+ dev_err(&dev->pdev->dev, "wd: invalid message is to be sent, aborting\n");
return -EINVAL;
+ }
- return mei_write_message(dev, &hdr, dev->wd_data);
+ ret = mei_write_message(dev, &hdr, dev->wd_data);
+ if (ret) {
+ dev_err(&dev->pdev->dev, "wd: write message failed\n");
+ return ret;
+ }
+
+ ret = mei_cl_flow_ctrl_reduce(cl);
+ if (ret) {
+ dev_err(&dev->pdev->dev, "wd: flow_ctrl_reduce failed.\n");
+ return ret;
+ }
+
+ return 0;
}
/**
@@ -133,9 +154,11 @@ int mei_wd_send(struct mei_device *dev)
* @dev: the device structure
* @preserve: indicate if to keep the timeout value
*
- * returns 0 if success,
- * -EIO when message send fails
+ * returns 0 if success
+ * on error:
+ * -EIO when message send fails
* -EINVAL when invalid message is to be sent
+ * -ETIME on message timeout
*/
int mei_wd_stop(struct mei_device *dev)
{
@@ -151,20 +174,12 @@ int mei_wd_stop(struct mei_device *dev)
ret = mei_cl_flow_ctrl_creds(&dev->wd_cl);
if (ret < 0)
- goto out;
-
- if (ret && dev->hbuf_is_ready) {
- ret = 0;
- dev->hbuf_is_ready = false;
-
- if (!mei_wd_send(dev)) {
- ret = mei_cl_flow_ctrl_reduce(&dev->wd_cl);
- if (ret)
- goto out;
- } else {
- dev_err(&dev->pdev->dev, "wd: send stop failed\n");
- }
+ goto err;
+ if (ret && mei_hbuf_acquire(dev)) {
+ ret = mei_wd_send(dev);
+ if (ret)
+ goto err;
dev->wd_pending = false;
} else {
dev->wd_pending = true;
@@ -172,21 +187,21 @@ int mei_wd_stop(struct mei_device *dev)
mutex_unlock(&dev->device_lock);
- ret = wait_event_interruptible_timeout(dev->wait_stop_wd,
- dev->wd_state == MEI_WD_IDLE,
- msecs_to_jiffies(MEI_WD_STOP_TIMEOUT));
+ ret = wait_event_timeout(dev->wait_stop_wd,
+ dev->wd_state == MEI_WD_IDLE,
+ msecs_to_jiffies(MEI_WD_STOP_TIMEOUT));
mutex_lock(&dev->device_lock);
- if (dev->wd_state == MEI_WD_IDLE) {
- dev_dbg(&dev->pdev->dev, "wd: stop completed ret=%d.\n", ret);
- ret = 0;
- } else {
- if (!ret)
- ret = -ETIMEDOUT;
+ if (dev->wd_state != MEI_WD_IDLE) {
+ /* timeout */
+ ret = -ETIME;
dev_warn(&dev->pdev->dev,
"wd: stop failed to complete ret=%d.\n", ret);
+ goto err;
}
-
-out:
+ dev_dbg(&dev->pdev->dev, "wd: stop completed after %u msec\n",
+ MEI_WD_STOP_TIMEOUT - jiffies_to_msecs(ret));
+ return 0;
+err:
return ret;
}
@@ -260,8 +275,8 @@ static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
*/
static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
{
- int ret = 0;
struct mei_device *dev;
+ int ret;
dev = watchdog_get_drvdata(wd_dev);
if (!dev)
@@ -277,25 +292,18 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
dev->wd_state = MEI_WD_RUNNING;
+ ret = mei_cl_flow_ctrl_creds(&dev->wd_cl);
+ if (ret < 0)
+ goto end;
/* Check if we can send the ping to HW*/
- if (dev->hbuf_is_ready && mei_cl_flow_ctrl_creds(&dev->wd_cl) > 0) {
+ if (ret && mei_hbuf_acquire(dev)) {
- dev->hbuf_is_ready = false;
dev_dbg(&dev->pdev->dev, "wd: sending ping\n");
- if (mei_wd_send(dev)) {
- dev_err(&dev->pdev->dev, "wd: send failed.\n");
- ret = -EIO;
+ ret = mei_wd_send(dev);
+ if (ret)
goto end;
- }
-
- if (mei_cl_flow_ctrl_reduce(&dev->wd_cl)) {
- dev_err(&dev->pdev->dev,
- "wd: mei_cl_flow_ctrl_reduce() failed.\n");
- ret = -EIO;
- goto end;
- }
-
+ dev->wd_pending = false;
} else {
dev->wd_pending = true;
}
@@ -363,17 +371,25 @@ static struct watchdog_device amt_wd_dev = {
};
-void mei_watchdog_register(struct mei_device *dev)
+int mei_watchdog_register(struct mei_device *dev)
{
- if (watchdog_register_device(&amt_wd_dev)) {
- dev_err(&dev->pdev->dev,
- "wd: unable to register watchdog device.\n");
- return;
+
+ int ret;
+
+ /* unlock to perserve correct locking order */
+ mutex_unlock(&dev->device_lock);
+ ret = watchdog_register_device(&amt_wd_dev);
+ mutex_lock(&dev->device_lock);
+ if (ret) {
+ dev_err(&dev->pdev->dev, "wd: unable to register watchdog device = %d.\n",
+ ret);
+ return ret;
}
dev_dbg(&dev->pdev->dev,
"wd: successfully register watchdog interface.\n");
watchdog_set_drvdata(&amt_wd_dev, dev);
+ return 0;
}
void mei_watchdog_unregister(struct mei_device *dev)
diff --git a/drivers/misc/mic/Kconfig b/drivers/misc/mic/Kconfig
index e42b331edbc6..462a5b1d8651 100644
--- a/drivers/misc/mic/Kconfig
+++ b/drivers/misc/mic/Kconfig
@@ -4,7 +4,6 @@ config INTEL_MIC_HOST
tristate "Intel MIC Host Driver"
depends on 64BIT && PCI && X86
select VHOST_RING
- default N
help
This enables Host Driver support for the Intel Many Integrated
Core (MIC) family of PCIe form factor coprocessor devices that
@@ -25,7 +24,6 @@ config INTEL_MIC_CARD
tristate "Intel MIC Card Driver"
depends on 64BIT && X86
select VIRTIO
- default N
help
This enables card driver support for the Intel Many Integrated
Core (MIC) device family. The card driver communicates shutdown/
diff --git a/drivers/misc/mic/card/mic_device.h b/drivers/misc/mic/card/mic_device.h
index 347b9b3b7916..306f502be95e 100644
--- a/drivers/misc/mic/card/mic_device.h
+++ b/drivers/misc/mic/card/mic_device.h
@@ -29,6 +29,7 @@
#include <linux/workqueue.h>
#include <linux/io.h>
+#include <linux/irqreturn.h>
/**
* struct mic_intr_info - Contains h/w specific interrupt sources info
diff --git a/drivers/misc/mic/host/mic_device.h b/drivers/misc/mic/host/mic_device.h
index 1a6edce2ecde..0398c696d257 100644
--- a/drivers/misc/mic/host/mic_device.h
+++ b/drivers/misc/mic/host/mic_device.h
@@ -24,6 +24,7 @@
#include <linux/cdev.h>
#include <linux/idr.h>
#include <linux/notifier.h>
+#include <linux/irqreturn.h>
#include "mic_intr.h"
diff --git a/drivers/misc/mic/host/mic_intr.c b/drivers/misc/mic/host/mic_intr.c
index f9c29bc918bc..dbc5afde1392 100644
--- a/drivers/misc/mic/host/mic_intr.c
+++ b/drivers/misc/mic/host/mic_intr.c
@@ -194,7 +194,7 @@ static int mic_setup_msix(struct mic_device *mdev, struct pci_dev *pdev)
for (i = 0; i < MIC_MIN_MSIX; i++)
mdev->irq_info.msix_entries[i].entry = i;
- rc = pci_enable_msix(pdev, mdev->irq_info.msix_entries,
+ rc = pci_enable_msix_exact(pdev, mdev->irq_info.msix_entries,
MIC_MIN_MSIX);
if (rc) {
dev_dbg(&pdev->dev, "Error enabling MSIx. rc = %d\n", rc);
diff --git a/drivers/misc/mic/host/mic_virtio.c b/drivers/misc/mic/host/mic_virtio.c
index 752ff873f891..7e1ef0ebbb80 100644
--- a/drivers/misc/mic/host/mic_virtio.c
+++ b/drivers/misc/mic/host/mic_virtio.c
@@ -156,7 +156,8 @@ static int mic_vringh_copy(struct mic_vdev *mvdev, struct vringh_kiov *iov,
static int _mic_virtio_copy(struct mic_vdev *mvdev,
struct mic_copy_desc *copy)
{
- int ret = 0, iovcnt = copy->iovcnt;
+ int ret = 0;
+ u32 iovcnt = copy->iovcnt;
struct iovec iov;
struct iovec __user *u_iov = copy->iov;
void __user *ubuf = NULL;
diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c
index a5925f7f17f6..956597321d2a 100644
--- a/drivers/misc/pch_phub.c
+++ b/drivers/misc/pch_phub.c
@@ -636,6 +636,7 @@ static ssize_t store_pch_mac(struct device *dev, struct device_attribute *attr,
u8 mac[ETH_ALEN];
ssize_t rom_size;
struct pch_phub_reg *chip = dev_get_drvdata(dev);
+ int ret;
if (!mac_pton(buf, mac))
return -EINVAL;
@@ -644,8 +645,10 @@ static ssize_t store_pch_mac(struct device *dev, struct device_attribute *attr,
if (!chip->pch_phub_extrom_base_address)
return -ENOMEM;
- pch_phub_write_gbe_mac_addr(chip, mac);
+ ret = pch_phub_write_gbe_mac_addr(chip, mac);
pci_unmap_rom(chip->pdev, chip->pch_phub_extrom_base_address);
+ if (ret)
+ return ret;
return count;
}
diff --git a/drivers/misc/sgi-gru/grukdump.c b/drivers/misc/sgi-gru/grukdump.c
index 9b2062d17327..2bef3f76032a 100644
--- a/drivers/misc/sgi-gru/grukdump.c
+++ b/drivers/misc/sgi-gru/grukdump.c
@@ -139,8 +139,11 @@ static int gru_dump_context(struct gru_state *gru, int ctxnum,
ubuf += sizeof(hdr);
ubufcch = ubuf;
- if (gru_user_copy_handle(&ubuf, cch))
- goto fail;
+ if (gru_user_copy_handle(&ubuf, cch)) {
+ if (cch_locked)
+ unlock_cch_handle(cch);
+ return -EFAULT;
+ }
if (cch_locked)
ubufcch->delresp = 0;
bytes = sizeof(hdr) + GRU_CACHE_LINE_BYTES;
@@ -179,10 +182,6 @@ static int gru_dump_context(struct gru_state *gru, int ctxnum,
ret = -EFAULT;
return ret ? ret : bytes;
-
-fail:
- unlock_cch_handle(cch);
- return -EFAULT;
}
int gru_dump_chiplet_request(unsigned long arg)
diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c
index b9e2000969f0..95c894482fdd 100644
--- a/drivers/misc/sgi-xp/xpc_uv.c
+++ b/drivers/misc/sgi-xp/xpc_uv.c
@@ -240,7 +240,7 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name,
nid = cpu_to_node(cpu);
page = alloc_pages_exact_node(nid,
- GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+ GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
pg_order);
if (page == NULL) {
dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d "
diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c
index afe66571ce0b..21181fa243df 100644
--- a/drivers/misc/sram.c
+++ b/drivers/misc/sram.c
@@ -24,6 +24,9 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/list.h>
+#include <linux/list_sort.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -36,14 +39,35 @@ struct sram_dev {
struct clk *clk;
};
+struct sram_reserve {
+ struct list_head list;
+ u32 start;
+ u32 size;
+};
+
+static int sram_reserve_cmp(void *priv, struct list_head *a,
+ struct list_head *b)
+{
+ struct sram_reserve *ra = list_entry(a, struct sram_reserve, list);
+ struct sram_reserve *rb = list_entry(b, struct sram_reserve, list);
+
+ return ra->start - rb->start;
+}
+
static int sram_probe(struct platform_device *pdev)
{
void __iomem *virt_base;
struct sram_dev *sram;
struct resource *res;
- unsigned long size;
+ struct device_node *np = pdev->dev.of_node, *child;
+ unsigned long size, cur_start, cur_size;
+ struct sram_reserve *rblocks, *block;
+ struct list_head reserve_list;
+ unsigned int nblocks;
int ret;
+ INIT_LIST_HEAD(&reserve_list);
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
virt_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(virt_base))
@@ -65,19 +89,106 @@ static int sram_probe(struct platform_device *pdev)
if (!sram->pool)
return -ENOMEM;
- ret = gen_pool_add_virt(sram->pool, (unsigned long)virt_base,
- res->start, size, -1);
- if (ret < 0) {
- if (sram->clk)
- clk_disable_unprepare(sram->clk);
- return ret;
+ /*
+ * We need an additional block to mark the end of the memory region
+ * after the reserved blocks from the dt are processed.
+ */
+ nblocks = (np) ? of_get_available_child_count(np) + 1 : 1;
+ rblocks = kmalloc((nblocks) * sizeof(*rblocks), GFP_KERNEL);
+ if (!rblocks) {
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+
+ block = &rblocks[0];
+ for_each_available_child_of_node(np, child) {
+ struct resource child_res;
+
+ ret = of_address_to_resource(child, 0, &child_res);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "could not get address for node %s\n",
+ child->full_name);
+ goto err_chunks;
+ }
+
+ if (child_res.start < res->start || child_res.end > res->end) {
+ dev_err(&pdev->dev,
+ "reserved block %s outside the sram area\n",
+ child->full_name);
+ ret = -EINVAL;
+ goto err_chunks;
+ }
+
+ block->start = child_res.start - res->start;
+ block->size = resource_size(&child_res);
+ list_add_tail(&block->list, &reserve_list);
+
+ dev_dbg(&pdev->dev, "found reserved block 0x%x-0x%x\n",
+ block->start,
+ block->start + block->size);
+
+ block++;
+ }
+
+ /* the last chunk marks the end of the region */
+ rblocks[nblocks - 1].start = size;
+ rblocks[nblocks - 1].size = 0;
+ list_add_tail(&rblocks[nblocks - 1].list, &reserve_list);
+
+ list_sort(NULL, &reserve_list, sram_reserve_cmp);
+
+ cur_start = 0;
+
+ list_for_each_entry(block, &reserve_list, list) {
+ /* can only happen if sections overlap */
+ if (block->start < cur_start) {
+ dev_err(&pdev->dev,
+ "block at 0x%x starts after current offset 0x%lx\n",
+ block->start, cur_start);
+ ret = -EINVAL;
+ goto err_chunks;
+ }
+
+ /* current start is in a reserved block, so continue after it */
+ if (block->start == cur_start) {
+ cur_start = block->start + block->size;
+ continue;
+ }
+
+ /*
+ * allocate the space between the current starting
+ * address and the following reserved block, or the
+ * end of the region.
+ */
+ cur_size = block->start - cur_start;
+
+ dev_dbg(&pdev->dev, "adding chunk 0x%lx-0x%lx\n",
+ cur_start, cur_start + cur_size);
+ ret = gen_pool_add_virt(sram->pool,
+ (unsigned long)virt_base + cur_start,
+ res->start + cur_start, cur_size, -1);
+ if (ret < 0)
+ goto err_chunks;
+
+ /* next allocation after this reserved block */
+ cur_start = block->start + block->size;
}
+ kfree(rblocks);
+
platform_set_drvdata(pdev, sram);
dev_dbg(&pdev->dev, "SRAM pool: %ld KiB @ 0x%p\n", size / 1024, virt_base);
return 0;
+
+err_chunks:
+ kfree(rblocks);
+err_alloc:
+ if (sram->clk)
+ clk_disable_unprepare(sram->clk);
+ return ret;
}
static int sram_remove(struct platform_device *pdev)
@@ -87,8 +198,6 @@ static int sram_remove(struct platform_device *pdev)
if (gen_pool_avail(sram->pool) < gen_pool_size(sram->pool))
dev_dbg(&pdev->dev, "removed while SRAM allocated\n");
- gen_pool_destroy(sram->pool);
-
if (sram->clk)
clk_disable_unprepare(sram->clk);
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index 3aed525e55b4..1972d57aadb3 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -22,7 +22,6 @@
#define pr_fmt(fmt) "(stc): " fmt
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/tty.h>
#include <linux/seq_file.h>
diff --git a/drivers/misc/ti_dac7512.c b/drivers/misc/ti_dac7512.c
index 83da711ce9f1..cb0289b44a17 100644
--- a/drivers/misc/ti_dac7512.c
+++ b/drivers/misc/ti_dac7512.c
@@ -20,7 +20,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/spi/spi.h>
#include <linux/of.h>
diff --git a/drivers/misc/tsl2550.c b/drivers/misc/tsl2550.c
index 5bc10fa193de..b00335652e52 100644
--- a/drivers/misc/tsl2550.c
+++ b/drivers/misc/tsl2550.c
@@ -20,7 +20,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c
index d35cda06b5e8..e0d5017785e5 100644
--- a/drivers/misc/vmw_vmci/vmci_guest.c
+++ b/drivers/misc/vmw_vmci/vmci_guest.c
@@ -383,11 +383,12 @@ static int vmci_enable_msix(struct pci_dev *pdev,
vmci_dev->msix_entries[i].vector = i;
}
- result = pci_enable_msix(pdev, vmci_dev->msix_entries, VMCI_MAX_INTRS);
+ result = pci_enable_msix_exact(pdev,
+ vmci_dev->msix_entries, VMCI_MAX_INTRS);
if (result == 0)
vmci_dev->exclusive_vectors = true;
- else if (result > 0)
- result = pci_enable_msix(pdev, vmci_dev->msix_entries, 1);
+ else if (result == -ENOSPC)
+ result = pci_enable_msix_exact(pdev, vmci_dev->msix_entries, 1);
return result;
}
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 357bbc54fe4b..3e049c13429c 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -197,7 +197,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
- limit = dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
+ limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
mq->card = card;
mq->queue = blk_init_queue(mmc_request_fn, lock);
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 49bc403e31f0..114f6bdfbef3 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -337,7 +337,7 @@ int mmc_of_parse(struct mmc_host *host)
break;
default:
dev_err(host->parent,
- "Invalid \"bus-width\" value %ud!\n", bus_width);
+ "Invalid \"bus-width\" value %u!\n", bus_width);
return -EINVAL;
}
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 55cd110a49c4..c204b7d1532c 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -2607,7 +2607,7 @@ int dw_mci_probe(struct dw_mci *host)
tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
host->card_workqueue = alloc_workqueue("dw-mci-card",
- WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1);
+ WQ_MEM_RECLAIM, 1);
if (!host->card_workqueue) {
ret = -ENOMEM;
goto err_dmaunmap;
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 90ff447bf043..a4bee41ad5cb 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -428,6 +428,7 @@ config MTD_NAND_FSL_IFC
tristate "NAND support for Freescale IFC controller"
depends on MTD_NAND && FSL_SOC
select FSL_IFC
+ select MEMORY
help
Various Freescale chips e.g P1010, include a NAND Flash machine
with built-in hardware ECC capabilities.
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index 90ca7e75d6f0..50d9161c4faf 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -30,7 +30,7 @@
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand_ecc.h>
-#include <asm/fsl_ifc.h>
+#include <linux/fsl_ifc.h>
#define FSL_IFC_V1_1_0 0x01010000
#define ERR_BYTE 0xFF /* Value returned for read
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 59eba5d2c685..9715a7ba164a 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1584,7 +1584,7 @@ read_retry:
}
if (mtd->ecc_stats.failed - ecc_failures) {
- if (retry_mode + 1 <= chip->read_retries) {
+ if (retry_mode + 1 < chip->read_retries) {
retry_mode++;
ret = nand_setup_read_retry(mtd,
retry_mode);
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index ef4190a02b7b..bf642ceef681 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -1633,6 +1633,7 @@ static int omap_nand_probe(struct platform_device *pdev)
int i;
dma_cap_mask_t mask;
unsigned sig;
+ unsigned oob_index;
struct resource *res;
struct mtd_part_parser_data ppdata = {};
@@ -1826,11 +1827,14 @@ static int omap_nand_probe(struct platform_device *pdev)
(mtd->writesize /
nand_chip->ecc.size);
if (nand_chip->options & NAND_BUSWIDTH_16)
- ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
+ oob_index = BADBLOCK_MARKER_LENGTH;
else
- ecclayout->eccpos[0] = 1;
- ecclayout->oobfree->offset = ecclayout->eccpos[0] +
- ecclayout->eccbytes;
+ oob_index = 1;
+ for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
+ ecclayout->eccpos[i] = oob_index;
+ /* no reserved-marker in ecclayout for this ecc-scheme */
+ ecclayout->oobfree->offset =
+ ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
break;
case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
@@ -1847,9 +1851,15 @@ static int omap_nand_probe(struct platform_device *pdev)
ecclayout->eccbytes = nand_chip->ecc.bytes *
(mtd->writesize /
nand_chip->ecc.size);
- ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
- ecclayout->oobfree->offset = ecclayout->eccpos[0] +
- ecclayout->eccbytes;
+ oob_index = BADBLOCK_MARKER_LENGTH;
+ for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) {
+ ecclayout->eccpos[i] = oob_index;
+ if (((i + 1) % nand_chip->ecc.bytes) == 0)
+ oob_index++;
+ }
+ /* include reserved-marker in ecclayout->oobfree calculation */
+ ecclayout->oobfree->offset = 1 +
+ ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
/* software bch library is used for locating errors */
nand_chip->ecc.priv = nand_bch_init(mtd,
nand_chip->ecc.size,
@@ -1883,9 +1893,12 @@ static int omap_nand_probe(struct platform_device *pdev)
ecclayout->eccbytes = nand_chip->ecc.bytes *
(mtd->writesize /
nand_chip->ecc.size);
- ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
- ecclayout->oobfree->offset = ecclayout->eccpos[0] +
- ecclayout->eccbytes;
+ oob_index = BADBLOCK_MARKER_LENGTH;
+ for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
+ ecclayout->eccpos[i] = oob_index;
+ /* reserved marker already included in ecclayout->eccbytes */
+ ecclayout->oobfree->offset =
+ ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
/* This ECC scheme requires ELM H/W block */
if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) {
pr_err("nand: error: could not initialize ELM\n");
@@ -1913,9 +1926,15 @@ static int omap_nand_probe(struct platform_device *pdev)
ecclayout->eccbytes = nand_chip->ecc.bytes *
(mtd->writesize /
nand_chip->ecc.size);
- ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
- ecclayout->oobfree->offset = ecclayout->eccpos[0] +
- ecclayout->eccbytes;
+ oob_index = BADBLOCK_MARKER_LENGTH;
+ for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) {
+ ecclayout->eccpos[i] = oob_index;
+ if (((i + 1) % nand_chip->ecc.bytes) == 0)
+ oob_index++;
+ }
+ /* include reserved-marker in ecclayout->oobfree calculation */
+ ecclayout->oobfree->offset = 1 +
+ ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
/* software bch library is used for locating errors */
nand_chip->ecc.priv = nand_bch_init(mtd,
nand_chip->ecc.size,
@@ -1956,9 +1975,12 @@ static int omap_nand_probe(struct platform_device *pdev)
ecclayout->eccbytes = nand_chip->ecc.bytes *
(mtd->writesize /
nand_chip->ecc.size);
- ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
- ecclayout->oobfree->offset = ecclayout->eccpos[0] +
- ecclayout->eccbytes;
+ oob_index = BADBLOCK_MARKER_LENGTH;
+ for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
+ ecclayout->eccpos[i] = oob_index;
+ /* reserved marker already included in ecclayout->eccbytes */
+ ecclayout->oobfree->offset =
+ ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
break;
#else
pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
@@ -1972,11 +1994,8 @@ static int omap_nand_probe(struct platform_device *pdev)
goto return_error;
}
- /* populate remaining ECC layout data */
- ecclayout->oobfree->length = mtd->oobsize - (BADBLOCK_MARKER_LENGTH +
- ecclayout->eccbytes);
- for (i = 1; i < ecclayout->eccbytes; i++)
- ecclayout->eccpos[i] = ecclayout->eccpos[0] + i;
+ /* all OOB bytes from oobfree->offset till end off OOB are free */
+ ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset;
/* check if NAND device's OOB is enough to store ECC signatures */
if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) {
pr_err("not enough OOB bytes required = %d, available=%d\n",
diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c
index d72783dd7b96..c0670237e7a2 100644
--- a/drivers/mtd/nand/sh_flctl.c
+++ b/drivers/mtd/nand/sh_flctl.c
@@ -897,7 +897,7 @@ static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
if (!flctl->qos_request) {
ret = dev_pm_qos_add_request(&flctl->pdev->dev,
&flctl->pm_qos,
- DEV_PM_QOS_LATENCY,
+ DEV_PM_QOS_RESUME_LATENCY,
100);
if (ret < 0)
dev_err(&flctl->pdev->dev,
diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
index 36663af56d89..f0855ce08ed9 100644
--- a/drivers/mtd/ubi/Kconfig
+++ b/drivers/mtd/ubi/Kconfig
@@ -87,4 +87,20 @@ config MTD_UBI_GLUEBI
work on top of UBI. Do not enable this unless you use legacy
software.
+config MTD_UBI_BLOCK
+ bool "Read-only block devices on top of UBI volumes"
+ default n
+ depends on BLOCK
+ help
+ This option enables read-only UBI block devices support. UBI block
+ devices will be layered on top of UBI volumes, which means that the
+ UBI driver will transparently handle things like bad eraseblocks and
+ bit-flips. You can put any block-oriented file system on top of UBI
+ volumes in read-only mode (e.g., ext4), but it is probably most
+ practical for read-only file systems, like squashfs.
+
+ When selected, this feature will be built in the UBI driver.
+
+ If in doubt, say "N".
+
endif # MTD_UBI
diff --git a/drivers/mtd/ubi/Makefile b/drivers/mtd/ubi/Makefile
index b46b0c978581..4e3c3d70d8c3 100644
--- a/drivers/mtd/ubi/Makefile
+++ b/drivers/mtd/ubi/Makefile
@@ -3,5 +3,6 @@ obj-$(CONFIG_MTD_UBI) += ubi.o
ubi-y += vtbl.o vmt.o upd.o build.o cdev.o kapi.o eba.o io.o wl.o attach.o
ubi-y += misc.o debug.o
ubi-$(CONFIG_MTD_UBI_FASTMAP) += fastmap.o
+ubi-$(CONFIG_MTD_UBI_BLOCK) += block.o
obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
new file mode 100644
index 000000000000..7ff473c871a9
--- /dev/null
+++ b/drivers/mtd/ubi/block.c
@@ -0,0 +1,647 @@
+/*
+ * Copyright (c) 2014 Ezequiel Garcia
+ * Copyright (c) 2011 Free Electrons
+ *
+ * Driver parameter handling strongly based on drivers/mtd/ubi/build.c
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (c) Nokia Corporation, 2007
+ * Authors: Artem Bityutskiy, Frank Haverkamp
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ */
+
+/*
+ * Read-only block devices on top of UBI volumes
+ *
+ * A simple implementation to allow a block device to be layered on top of a
+ * UBI volume. The implementation is provided by creating a static 1-to-1
+ * mapping between the block device and the UBI volume.
+ *
+ * The addressed byte is obtained from the addressed block sector, which is
+ * mapped linearly into the corresponding LEB:
+ *
+ * LEB number = addressed byte / LEB size
+ *
+ * This feature is compiled in the UBI core, and adds a 'block' parameter
+ * to allow early creation of block devices on top of UBI volumes. Runtime
+ * block creation/removal for UBI volumes is provided through two UBI ioctls:
+ * UBI_IOCVOLCRBLK and UBI_IOCVOLRMBLK.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/mtd/ubi.h>
+#include <linux/workqueue.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <asm/div64.h>
+
+#include "ubi-media.h"
+#include "ubi.h"
+
+/* Maximum number of supported devices */
+#define UBIBLOCK_MAX_DEVICES 32
+
+/* Maximum length of the 'block=' parameter */
+#define UBIBLOCK_PARAM_LEN 63
+
+/* Maximum number of comma-separated items in the 'block=' parameter */
+#define UBIBLOCK_PARAM_COUNT 2
+
+struct ubiblock_param {
+ int ubi_num;
+ int vol_id;
+ char name[UBIBLOCK_PARAM_LEN+1];
+};
+
+/* Numbers of elements set in the @ubiblock_param array */
+static int ubiblock_devs __initdata;
+
+/* MTD devices specification parameters */
+static struct ubiblock_param ubiblock_param[UBIBLOCK_MAX_DEVICES] __initdata;
+
+struct ubiblock {
+ struct ubi_volume_desc *desc;
+ int ubi_num;
+ int vol_id;
+ int refcnt;
+ int leb_size;
+
+ struct gendisk *gd;
+ struct request_queue *rq;
+
+ struct workqueue_struct *wq;
+ struct work_struct work;
+
+ struct mutex dev_mutex;
+ spinlock_t queue_lock;
+ struct list_head list;
+};
+
+/* Linked list of all ubiblock instances */
+static LIST_HEAD(ubiblock_devices);
+static DEFINE_MUTEX(devices_mutex);
+static int ubiblock_major;
+
+static int __init ubiblock_set_param(const char *val,
+ const struct kernel_param *kp)
+{
+ int i, ret;
+ size_t len;
+ struct ubiblock_param *param;
+ char buf[UBIBLOCK_PARAM_LEN];
+ char *pbuf = &buf[0];
+ char *tokens[UBIBLOCK_PARAM_COUNT];
+
+ if (!val)
+ return -EINVAL;
+
+ len = strnlen(val, UBIBLOCK_PARAM_LEN);
+ if (len == 0) {
+ ubi_warn("block: empty 'block=' parameter - ignored\n");
+ return 0;
+ }
+
+ if (len == UBIBLOCK_PARAM_LEN) {
+ ubi_err("block: parameter \"%s\" is too long, max. is %d\n",
+ val, UBIBLOCK_PARAM_LEN);
+ return -EINVAL;
+ }
+
+ strcpy(buf, val);
+
+ /* Get rid of the final newline */
+ if (buf[len - 1] == '\n')
+ buf[len - 1] = '\0';
+
+ for (i = 0; i < UBIBLOCK_PARAM_COUNT; i++)
+ tokens[i] = strsep(&pbuf, ",");
+
+ param = &ubiblock_param[ubiblock_devs];
+ if (tokens[1]) {
+ /* Two parameters: can be 'ubi, vol_id' or 'ubi, vol_name' */
+ ret = kstrtoint(tokens[0], 10, &param->ubi_num);
+ if (ret < 0)
+ return -EINVAL;
+
+ /* Second param can be a number or a name */
+ ret = kstrtoint(tokens[1], 10, &param->vol_id);
+ if (ret < 0) {
+ param->vol_id = -1;
+ strcpy(param->name, tokens[1]);
+ }
+
+ } else {
+ /* One parameter: must be device path */
+ strcpy(param->name, tokens[0]);
+ param->ubi_num = -1;
+ param->vol_id = -1;
+ }
+
+ ubiblock_devs++;
+
+ return 0;
+}
+
+static struct kernel_param_ops ubiblock_param_ops = {
+ .set = ubiblock_set_param,
+};
+module_param_cb(block, &ubiblock_param_ops, NULL, 0);
+MODULE_PARM_DESC(block, "Attach block devices to UBI volumes. Parameter format: block=<path|dev,num|dev,name>.\n"
+ "Multiple \"block\" parameters may be specified.\n"
+ "UBI volumes may be specified by their number, name, or path to the device node.\n"
+ "Examples\n"
+ "Using the UBI volume path:\n"
+ "ubi.block=/dev/ubi0_0\n"
+ "Using the UBI device, and the volume name:\n"
+ "ubi.block=0,rootfs\n"
+ "Using both UBI device number and UBI volume number:\n"
+ "ubi.block=0,0\n");
+
+static struct ubiblock *find_dev_nolock(int ubi_num, int vol_id)
+{
+ struct ubiblock *dev;
+
+ list_for_each_entry(dev, &ubiblock_devices, list)
+ if (dev->ubi_num == ubi_num && dev->vol_id == vol_id)
+ return dev;
+ return NULL;
+}
+
+static int ubiblock_read_to_buf(struct ubiblock *dev, char *buffer,
+ int leb, int offset, int len)
+{
+ int ret;
+
+ ret = ubi_read(dev->desc, leb, buffer, offset, len);
+ if (ret) {
+ ubi_err("%s ubi_read error %d",
+ dev->gd->disk_name, ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int ubiblock_read(struct ubiblock *dev, char *buffer,
+ sector_t sec, int len)
+{
+ int ret, leb, offset;
+ int bytes_left = len;
+ int to_read = len;
+ u64 pos = sec << 9;
+
+ /* Get LEB:offset address to read from */
+ offset = do_div(pos, dev->leb_size);
+ leb = pos;
+
+ while (bytes_left) {
+ /*
+ * We can only read one LEB at a time. Therefore if the read
+ * length is larger than one LEB size, we split the operation.
+ */
+ if (offset + to_read > dev->leb_size)
+ to_read = dev->leb_size - offset;
+
+ ret = ubiblock_read_to_buf(dev, buffer, leb, offset, to_read);
+ if (ret)
+ return ret;
+
+ buffer += to_read;
+ bytes_left -= to_read;
+ to_read = bytes_left;
+ leb += 1;
+ offset = 0;
+ }
+ return 0;
+}
+
+static int do_ubiblock_request(struct ubiblock *dev, struct request *req)
+{
+ int len, ret;
+ sector_t sec;
+
+ if (req->cmd_type != REQ_TYPE_FS)
+ return -EIO;
+
+ if (blk_rq_pos(req) + blk_rq_cur_sectors(req) >
+ get_capacity(req->rq_disk))
+ return -EIO;
+
+ if (rq_data_dir(req) != READ)
+ return -ENOSYS; /* Write not implemented */
+
+ sec = blk_rq_pos(req);
+ len = blk_rq_cur_bytes(req);
+
+ /*
+ * Let's prevent the device from being removed while we're doing I/O
+ * work. Notice that this means we serialize all the I/O operations,
+ * but it's probably of no impact given the NAND core serializes
+ * flash access anyway.
+ */
+ mutex_lock(&dev->dev_mutex);
+ ret = ubiblock_read(dev, req->buffer, sec, len);
+ mutex_unlock(&dev->dev_mutex);
+
+ return ret;
+}
+
+static void ubiblock_do_work(struct work_struct *work)
+{
+ struct ubiblock *dev =
+ container_of(work, struct ubiblock, work);
+ struct request_queue *rq = dev->rq;
+ struct request *req;
+ int res;
+
+ spin_lock_irq(rq->queue_lock);
+
+ req = blk_fetch_request(rq);
+ while (req) {
+
+ spin_unlock_irq(rq->queue_lock);
+ res = do_ubiblock_request(dev, req);
+ spin_lock_irq(rq->queue_lock);
+
+ /*
+ * If we're done with this request,
+ * we need to fetch a new one
+ */
+ if (!__blk_end_request_cur(req, res))
+ req = blk_fetch_request(rq);
+ }
+
+ spin_unlock_irq(rq->queue_lock);
+}
+
+static void ubiblock_request(struct request_queue *rq)
+{
+ struct ubiblock *dev;
+ struct request *req;
+
+ dev = rq->queuedata;
+
+ if (!dev)
+ while ((req = blk_fetch_request(rq)) != NULL)
+ __blk_end_request_all(req, -ENODEV);
+ else
+ queue_work(dev->wq, &dev->work);
+}
+
+static int ubiblock_open(struct block_device *bdev, fmode_t mode)
+{
+ struct ubiblock *dev = bdev->bd_disk->private_data;
+ int ret;
+
+ mutex_lock(&dev->dev_mutex);
+ if (dev->refcnt > 0) {
+ /*
+ * The volume is already open, just increase the reference
+ * counter.
+ */
+ goto out_done;
+ }
+
+ /*
+ * We want users to be aware they should only mount us as read-only.
+ * It's just a paranoid check, as write requests will get rejected
+ * in any case.
+ */
+ if (mode & FMODE_WRITE) {
+ ret = -EPERM;
+ goto out_unlock;
+ }
+
+ dev->desc = ubi_open_volume(dev->ubi_num, dev->vol_id, UBI_READONLY);
+ if (IS_ERR(dev->desc)) {
+ ubi_err("%s failed to open ubi volume %d_%d",
+ dev->gd->disk_name, dev->ubi_num, dev->vol_id);
+ ret = PTR_ERR(dev->desc);
+ dev->desc = NULL;
+ goto out_unlock;
+ }
+
+out_done:
+ dev->refcnt++;
+ mutex_unlock(&dev->dev_mutex);
+ return 0;
+
+out_unlock:
+ mutex_unlock(&dev->dev_mutex);
+ return ret;
+}
+
+static void ubiblock_release(struct gendisk *gd, fmode_t mode)
+{
+ struct ubiblock *dev = gd->private_data;
+
+ mutex_lock(&dev->dev_mutex);
+ dev->refcnt--;
+ if (dev->refcnt == 0) {
+ ubi_close_volume(dev->desc);
+ dev->desc = NULL;
+ }
+ mutex_unlock(&dev->dev_mutex);
+}
+
+static int ubiblock_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+ /* Some tools might require this information */
+ geo->heads = 1;
+ geo->cylinders = 1;
+ geo->sectors = get_capacity(bdev->bd_disk);
+ geo->start = 0;
+ return 0;
+}
+
+static const struct block_device_operations ubiblock_ops = {
+ .owner = THIS_MODULE,
+ .open = ubiblock_open,
+ .release = ubiblock_release,
+ .getgeo = ubiblock_getgeo,
+};
+
+int ubiblock_create(struct ubi_volume_info *vi)
+{
+ struct ubiblock *dev;
+ struct gendisk *gd;
+ int disk_capacity;
+ int ret;
+
+ /* Check that the volume isn't already handled */
+ mutex_lock(&devices_mutex);
+ if (find_dev_nolock(vi->ubi_num, vi->vol_id)) {
+ mutex_unlock(&devices_mutex);
+ return -EEXIST;
+ }
+ mutex_unlock(&devices_mutex);
+
+ dev = kzalloc(sizeof(struct ubiblock), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ mutex_init(&dev->dev_mutex);
+
+ dev->ubi_num = vi->ubi_num;
+ dev->vol_id = vi->vol_id;
+ dev->leb_size = vi->usable_leb_size;
+
+ /* Initialize the gendisk of this ubiblock device */
+ gd = alloc_disk(1);
+ if (!gd) {
+ ubi_err("block: alloc_disk failed");
+ ret = -ENODEV;
+ goto out_free_dev;
+ }
+
+ gd->fops = &ubiblock_ops;
+ gd->major = ubiblock_major;
+ gd->first_minor = dev->ubi_num * UBI_MAX_VOLUMES + dev->vol_id;
+ gd->private_data = dev;
+ sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id);
+ disk_capacity = (vi->size * vi->usable_leb_size) >> 9;
+ set_capacity(gd, disk_capacity);
+ dev->gd = gd;
+
+ spin_lock_init(&dev->queue_lock);
+ dev->rq = blk_init_queue(ubiblock_request, &dev->queue_lock);
+ if (!dev->rq) {
+ ubi_err("block: blk_init_queue failed");
+ ret = -ENODEV;
+ goto out_put_disk;
+ }
+
+ dev->rq->queuedata = dev;
+ dev->gd->queue = dev->rq;
+
+ /*
+ * Create one workqueue per volume (per registered block device).
+ * Rembember workqueues are cheap, they're not threads.
+ */
+ dev->wq = alloc_workqueue(gd->disk_name, 0, 0);
+ if (!dev->wq)
+ goto out_free_queue;
+ INIT_WORK(&dev->work, ubiblock_do_work);
+
+ mutex_lock(&devices_mutex);
+ list_add_tail(&dev->list, &ubiblock_devices);
+ mutex_unlock(&devices_mutex);
+
+ /* Must be the last step: anyone can call file ops from now on */
+ add_disk(dev->gd);
+ ubi_msg("%s created from ubi%d:%d(%s)",
+ dev->gd->disk_name, dev->ubi_num, dev->vol_id, vi->name);
+ return 0;
+
+out_free_queue:
+ blk_cleanup_queue(dev->rq);
+out_put_disk:
+ put_disk(dev->gd);
+out_free_dev:
+ kfree(dev);
+
+ return ret;
+}
+
+static void ubiblock_cleanup(struct ubiblock *dev)
+{
+ del_gendisk(dev->gd);
+ blk_cleanup_queue(dev->rq);
+ ubi_msg("%s released", dev->gd->disk_name);
+ put_disk(dev->gd);
+}
+
+int ubiblock_remove(struct ubi_volume_info *vi)
+{
+ struct ubiblock *dev;
+
+ mutex_lock(&devices_mutex);
+ dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
+ if (!dev) {
+ mutex_unlock(&devices_mutex);
+ return -ENODEV;
+ }
+
+ /* Found a device, let's lock it so we can check if it's busy */
+ mutex_lock(&dev->dev_mutex);
+ if (dev->refcnt > 0) {
+ mutex_unlock(&dev->dev_mutex);
+ mutex_unlock(&devices_mutex);
+ return -EBUSY;
+ }
+
+ /* Remove from device list */
+ list_del(&dev->list);
+ mutex_unlock(&devices_mutex);
+
+ /* Flush pending work and stop this workqueue */
+ destroy_workqueue(dev->wq);
+
+ ubiblock_cleanup(dev);
+ mutex_unlock(&dev->dev_mutex);
+ kfree(dev);
+ return 0;
+}
+
+static void ubiblock_resize(struct ubi_volume_info *vi)
+{
+ struct ubiblock *dev;
+ int disk_capacity;
+
+ /*
+ * Need to lock the device list until we stop using the device,
+ * otherwise the device struct might get released in
+ * 'ubiblock_remove()'.
+ */
+ mutex_lock(&devices_mutex);
+ dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
+ if (!dev) {
+ mutex_unlock(&devices_mutex);
+ return;
+ }
+
+ mutex_lock(&dev->dev_mutex);
+ disk_capacity = (vi->size * vi->usable_leb_size) >> 9;
+ set_capacity(dev->gd, disk_capacity);
+ ubi_msg("%s resized to %d LEBs", dev->gd->disk_name, vi->size);
+ mutex_unlock(&dev->dev_mutex);
+ mutex_unlock(&devices_mutex);
+}
+
+static int ubiblock_notify(struct notifier_block *nb,
+ unsigned long notification_type, void *ns_ptr)
+{
+ struct ubi_notification *nt = ns_ptr;
+
+ switch (notification_type) {
+ case UBI_VOLUME_ADDED:
+ /*
+ * We want to enforce explicit block device creation for
+ * volumes, so when a volume is added we do nothing.
+ */
+ break;
+ case UBI_VOLUME_REMOVED:
+ ubiblock_remove(&nt->vi);
+ break;
+ case UBI_VOLUME_RESIZED:
+ ubiblock_resize(&nt->vi);
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block ubiblock_notifier = {
+ .notifier_call = ubiblock_notify,
+};
+
+static struct ubi_volume_desc * __init
+open_volume_desc(const char *name, int ubi_num, int vol_id)
+{
+ if (ubi_num == -1)
+ /* No ubi num, name must be a vol device path */
+ return ubi_open_volume_path(name, UBI_READONLY);
+ else if (vol_id == -1)
+ /* No vol_id, must be vol_name */
+ return ubi_open_volume_nm(ubi_num, name, UBI_READONLY);
+ else
+ return ubi_open_volume(ubi_num, vol_id, UBI_READONLY);
+}
+
+static int __init ubiblock_create_from_param(void)
+{
+ int i, ret;
+ struct ubiblock_param *p;
+ struct ubi_volume_desc *desc;
+ struct ubi_volume_info vi;
+
+ for (i = 0; i < ubiblock_devs; i++) {
+ p = &ubiblock_param[i];
+
+ desc = open_volume_desc(p->name, p->ubi_num, p->vol_id);
+ if (IS_ERR(desc)) {
+ ubi_err("block: can't open volume, err=%ld\n",
+ PTR_ERR(desc));
+ ret = PTR_ERR(desc);
+ break;
+ }
+
+ ubi_get_volume_info(desc, &vi);
+ ubi_close_volume(desc);
+
+ ret = ubiblock_create(&vi);
+ if (ret) {
+ ubi_err("block: can't add '%s' volume, err=%d\n",
+ vi.name, ret);
+ break;
+ }
+ }
+ return ret;
+}
+
+static void ubiblock_remove_all(void)
+{
+ struct ubiblock *next;
+ struct ubiblock *dev;
+
+ list_for_each_entry_safe(dev, next, &ubiblock_devices, list) {
+ /* Flush pending work and stop workqueue */
+ destroy_workqueue(dev->wq);
+ /* The module is being forcefully removed */
+ WARN_ON(dev->desc);
+ /* Remove from device list */
+ list_del(&dev->list);
+ ubiblock_cleanup(dev);
+ kfree(dev);
+ }
+}
+
+int __init ubiblock_init(void)
+{
+ int ret;
+
+ ubiblock_major = register_blkdev(0, "ubiblock");
+ if (ubiblock_major < 0)
+ return ubiblock_major;
+
+ /* Attach block devices from 'block=' module param */
+ ret = ubiblock_create_from_param();
+ if (ret)
+ goto err_remove;
+
+ /*
+ * Block devices are only created upon user requests, so we ignore
+ * existing volumes.
+ */
+ ret = ubi_register_volume_notifier(&ubiblock_notifier, 1);
+ if (ret)
+ goto err_unreg;
+ return 0;
+
+err_unreg:
+ unregister_blkdev(ubiblock_major, "ubiblock");
+err_remove:
+ ubiblock_remove_all();
+ return ret;
+}
+
+void __exit ubiblock_exit(void)
+{
+ ubi_unregister_volume_notifier(&ubiblock_notifier);
+ ubiblock_remove_all();
+ unregister_blkdev(ubiblock_major, "ubiblock");
+}
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 57deae961429..6e30a3c280d0 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -1298,6 +1298,15 @@ static int __init ubi_init(void)
}
}
+ err = ubiblock_init();
+ if (err) {
+ ubi_err("block: cannot initialize, error %d", err);
+
+ /* See comment above re-ubi_is_module(). */
+ if (ubi_is_module())
+ goto out_detach;
+ }
+
return 0;
out_detach:
@@ -1326,6 +1335,8 @@ static void __exit ubi_exit(void)
{
int i;
+ ubiblock_exit();
+
for (i = 0; i < UBI_MAX_DEVICES; i++)
if (ubi_devices[i]) {
mutex_lock(&ubi_devices_mutex);
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 8ca49f2043e4..f54562a5998e 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -561,6 +561,26 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
break;
}
+ /* Create a R/O block device on top of the UBI volume */
+ case UBI_IOCVOLCRBLK:
+ {
+ struct ubi_volume_info vi;
+
+ ubi_get_volume_info(desc, &vi);
+ err = ubiblock_create(&vi);
+ break;
+ }
+
+ /* Remove the R/O block device */
+ case UBI_IOCVOLRMBLK:
+ {
+ struct ubi_volume_info vi;
+
+ ubi_get_volume_info(desc, &vi);
+ err = ubiblock_remove(&vi);
+ break;
+ }
+
default:
err = -ENOTTY;
break;
diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
index ead861307b3c..c5dad652614d 100644
--- a/drivers/mtd/ubi/fastmap.c
+++ b/drivers/mtd/ubi/fastmap.c
@@ -463,8 +463,8 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai,
}
}
if (found_orphan) {
- kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
list_del(&tmp_aeb->u.list);
+ kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
}
new_aeb = kmem_cache_alloc(ai->aeb_slab_cache,
@@ -846,16 +846,16 @@ fail_bad:
ret = UBI_BAD_FASTMAP;
fail:
list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &used, u.list) {
- kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
list_del(&tmp_aeb->u.list);
+ kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
}
list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &eba_orphans, u.list) {
- kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
list_del(&tmp_aeb->u.list);
+ kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
}
list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &free, u.list) {
- kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
list_del(&tmp_aeb->u.list);
+ kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
}
return ret;
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 8ea6297a208f..0ba8b0a28838 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -864,6 +864,26 @@ int ubi_update_fastmap(struct ubi_device *ubi);
int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai,
int fm_anchor);
+/* block.c */
+#ifdef CONFIG_MTD_UBI_BLOCK
+int ubiblock_init(void);
+void ubiblock_exit(void);
+int ubiblock_create(struct ubi_volume_info *vi);
+int ubiblock_remove(struct ubi_volume_info *vi);
+#else
+static inline int ubiblock_init(void) { return 0; }
+static inline void ubiblock_exit(void) {}
+static inline int ubiblock_create(struct ubi_volume_info *vi)
+{
+ return -ENOSYS;
+}
+static inline int ubiblock_remove(struct ubi_volume_info *vi)
+{
+ return -ENOSYS;
+}
+#endif
+
+
/*
* ubi_rb_for_each_entry - walk an RB-tree.
* @rb: a pointer to type 'struct rb_node' to use as a loop counter
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index f342278539d5..89402c3b64f8 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -139,7 +139,7 @@ config MACVTAP
This adds a specialized tap character device driver that is based
on the MAC-VLAN network interface, called macvtap. A macvtap device
can be added in the same way as a macvlan device, using 'type
- macvlan', and then be accessed through the tap user space interface.
+ macvtap', and then be accessed through the tap user space interface.
To compile this driver as a module, choose M here: the module
will be called macvtap.
@@ -177,11 +177,6 @@ config NETCONSOLE_DYNAMIC
config NETPOLL
def_bool NETCONSOLE
-config NETPOLL_TRAP
- bool "Netpoll traffic trapping"
- default n
- depends on NETPOLL
-
config NET_POLL_CONTROLLER
def_bool NETPOLL
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index cce1f1bf90b4..b667a51ed215 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -181,7 +181,7 @@ static inline int __agg_has_partner(struct aggregator *agg)
*/
static inline void __disable_port(struct port *port)
{
- bond_set_slave_inactive_flags(port->slave);
+ bond_set_slave_inactive_flags(port->slave, BOND_SLAVE_NOTIFY_LATER);
}
/**
@@ -193,7 +193,7 @@ static inline void __enable_port(struct port *port)
struct slave *slave = port->slave;
if ((slave->link == BOND_LINK_UP) && IS_UP(slave->dev))
- bond_set_slave_active_flags(slave);
+ bond_set_slave_active_flags(slave, BOND_SLAVE_NOTIFY_LATER);
}
/**
@@ -768,11 +768,11 @@ static int ad_lacpdu_send(struct port *port)
lacpdu_header = (struct lacpdu_header *)skb_put(skb, length);
- memcpy(lacpdu_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN);
+ ether_addr_copy(lacpdu_header->hdr.h_dest, lacpdu_mcast_addr);
/* Note: source address is set to be the member's PERMANENT address,
* because we use it to identify loopback lacpdus in receive.
*/
- memcpy(lacpdu_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN);
+ ether_addr_copy(lacpdu_header->hdr.h_source, slave->perm_hwaddr);
lacpdu_header->hdr.h_proto = PKT_TYPE_LACPDU;
lacpdu_header->lacpdu = port->lacpdu;
@@ -810,11 +810,11 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker)
marker_header = (struct bond_marker_header *)skb_put(skb, length);
- memcpy(marker_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN);
+ ether_addr_copy(marker_header->hdr.h_dest, lacpdu_mcast_addr);
/* Note: source address is set to be the member's PERMANENT address,
* because we use it to identify loopback MARKERs in receive.
*/
- memcpy(marker_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN);
+ ether_addr_copy(marker_header->hdr.h_source, slave->perm_hwaddr);
marker_header->hdr.h_proto = PKT_TYPE_LACPDU;
marker_header->marker = *marker;
@@ -1079,7 +1079,8 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
/* detect loopback situation */
if (MAC_ADDRESS_EQUAL(&(lacpdu->actor_system),
&(port->actor_system))) {
- pr_err("%s: An illegal loopback occurred on adapter (%s).\nCheck the configuration to verify that all adapters are connected to 802.3ad compliant switch ports\n",
+ pr_err("%s: An illegal loopback occurred on adapter (%s)\n"
+ "Check the configuration to verify that all adapters are connected to 802.3ad compliant switch ports\n",
port->slave->bond->dev->name,
port->slave->dev->name);
return;
@@ -1283,11 +1284,11 @@ static void ad_port_selection_logic(struct port *port)
/* meaning: the port was related to an aggregator
* but was not on the aggregator port list
*/
- pr_warn("%s: Warning: Port %d (on %s) was related to aggregator %d but was not on its port list\n",
- port->slave->bond->dev->name,
- port->actor_port_number,
- port->slave->dev->name,
- port->aggregator->aggregator_identifier);
+ pr_warn_ratelimited("%s: Warning: Port %d (on %s) was related to aggregator %d but was not on its port list\n",
+ port->slave->bond->dev->name,
+ port->actor_port_number,
+ port->slave->dev->name,
+ port->aggregator->aggregator_identifier);
}
}
/* search on all aggregators for a suitable aggregator for this port */
@@ -1444,9 +1445,9 @@ static struct aggregator *ad_agg_selection_test(struct aggregator *best,
break;
default:
- pr_warn("%s: Impossible agg select mode %d\n",
- curr->slave->bond->dev->name,
- __get_agg_selection_mode(curr->lag_ports));
+ pr_warn_ratelimited("%s: Impossible agg select mode %d\n",
+ curr->slave->bond->dev->name,
+ __get_agg_selection_mode(curr->lag_ports));
break;
}
@@ -1559,9 +1560,9 @@ static void ad_agg_selection_logic(struct aggregator *agg)
/* check if any partner replys */
if (best->is_individual) {
- pr_warn("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n",
- best->slave ?
- best->slave->bond->dev->name : "NULL");
+ pr_warn_ratelimited("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n",
+ best->slave ?
+ best->slave->bond->dev->name : "NULL");
}
best->is_active = 1;
@@ -1796,8 +1797,6 @@ void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout)
BOND_AD_INFO(bond).agg_select_timer = timeout;
}
-static u16 aggregator_identifier;
-
/**
* bond_3ad_initialize - initialize a bond's 802.3ad parameters and structures
* @bond: bonding struct to work on
@@ -1811,7 +1810,7 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution)
if (!MAC_ADDRESS_EQUAL(&(BOND_AD_INFO(bond).system.sys_mac_addr),
bond->dev->dev_addr)) {
- aggregator_identifier = 0;
+ BOND_AD_INFO(bond).aggregator_identifier = 0;
BOND_AD_INFO(bond).system.sys_priority = 0xFFFF;
BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr);
@@ -1880,7 +1879,7 @@ void bond_3ad_bind_slave(struct slave *slave)
ad_initialize_agg(aggregator);
aggregator->aggregator_mac_address = *((struct mac_addr *)bond->dev->dev_addr);
- aggregator->aggregator_identifier = (++aggregator_identifier);
+ aggregator->aggregator_identifier = ++BOND_AD_INFO(bond).aggregator_identifier;
aggregator->slave = slave;
aggregator->is_active = 0;
aggregator->num_of_ports = 0;
@@ -1950,7 +1949,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
* new aggregator
*/
if ((new_aggregator) && ((!new_aggregator->lag_ports) || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator))) {
- pr_debug("Some port(s) related to LAG %d - replaceing with LAG %d\n",
+ pr_debug("Some port(s) related to LAG %d - replacing with LAG %d\n",
aggregator->aggregator_identifier,
new_aggregator->aggregator_identifier);
@@ -2064,6 +2063,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
struct list_head *iter;
struct slave *slave;
struct port *port;
+ bool should_notify_rtnl = BOND_SLAVE_NOTIFY_LATER;
read_lock(&bond->lock);
rcu_read_lock();
@@ -2081,8 +2081,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
/* select the active aggregator for the bond */
if (port) {
if (!port->slave) {
- pr_warn("%s: Warning: bond's first port is uninitialized\n",
- bond->dev->name);
+ pr_warn_ratelimited("%s: Warning: bond's first port is uninitialized\n",
+ bond->dev->name);
goto re_arm;
}
@@ -2096,8 +2096,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
bond_for_each_slave_rcu(bond, slave, iter) {
port = &(SLAVE_AD_INFO(slave).port);
if (!port->slave) {
- pr_warn("%s: Warning: Found an uninitialized port\n",
- bond->dev->name);
+ pr_warn_ratelimited("%s: Warning: Found an uninitialized port\n",
+ bond->dev->name);
goto re_arm;
}
@@ -2121,8 +2121,19 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
}
re_arm:
+ bond_for_each_slave_rcu(bond, slave, iter) {
+ if (slave->should_notify) {
+ should_notify_rtnl = BOND_SLAVE_NOTIFY_NOW;
+ break;
+ }
+ }
rcu_read_unlock();
read_unlock(&bond->lock);
+
+ if (should_notify_rtnl && rtnl_trylock()) {
+ bond_slave_state_notify(bond);
+ rtnl_unlock();
+ }
queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
}
@@ -2147,8 +2158,8 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave,
port = &(SLAVE_AD_INFO(slave).port);
if (!port->slave) {
- pr_warn("%s: Warning: port of slave %s is uninitialized\n",
- slave->dev->name, slave->bond->dev->name);
+ pr_warn_ratelimited("%s: Warning: port of slave %s is uninitialized\n",
+ slave->dev->name, slave->bond->dev->name);
return ret;
}
@@ -2300,9 +2311,9 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
port->actor_oper_port_key = (port->actor_admin_port_key &=
~AD_SPEED_KEY_BITS);
}
- pr_debug("Port %d changed link status to %s",
- port->actor_port_number,
- (link == BOND_LINK_UP) ? "UP" : "DOWN");
+ pr_debug("Port %d changed link status to %s\n",
+ port->actor_port_number,
+ link == BOND_LINK_UP ? "UP" : "DOWN");
/* there is no need to reselect a new aggregator, just signal the
* state machines to reinitialize
*/
@@ -2380,17 +2391,16 @@ int __bond_3ad_get_active_agg_info(struct bonding *bond,
}
}
- if (aggregator) {
- ad_info->aggregator_id = aggregator->aggregator_identifier;
- ad_info->ports = aggregator->num_of_ports;
- ad_info->actor_key = aggregator->actor_oper_aggregator_key;
- ad_info->partner_key = aggregator->partner_oper_aggregator_key;
- memcpy(ad_info->partner_system,
- aggregator->partner_system.mac_addr_value, ETH_ALEN);
- return 0;
- }
+ if (!aggregator)
+ return -1;
- return -1;
+ ad_info->aggregator_id = aggregator->aggregator_identifier;
+ ad_info->ports = aggregator->num_of_ports;
+ ad_info->actor_key = aggregator->actor_oper_aggregator_key;
+ ad_info->partner_key = aggregator->partner_oper_aggregator_key;
+ ether_addr_copy(ad_info->partner_system,
+ aggregator->partner_system.mac_addr_value);
+ return 0;
}
/* Wrapper used to hold bond->lock so no slave manipulation can occur */
@@ -2469,7 +2479,7 @@ out:
return NETDEV_TX_OK;
err_free:
/* no suitable interface, frame not sent */
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
goto out;
}
diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h
index 13dc9d3c5e34..bb03b1df2f3e 100644
--- a/drivers/net/bonding/bond_3ad.h
+++ b/drivers/net/bonding/bond_3ad.h
@@ -28,7 +28,7 @@
#include <linux/netdevice.h>
#include <linux/if_ether.h>
-// General definitions
+/* General definitions */
#define PKT_TYPE_LACPDU cpu_to_be16(ETH_P_SLOW)
#define AD_TIMER_INTERVAL 100 /*msec*/
@@ -47,54 +47,54 @@ enum {
BOND_AD_COUNT = 2,
};
-// rx machine states(43.4.11 in the 802.3ad standard)
+/* rx machine states(43.4.11 in the 802.3ad standard) */
typedef enum {
AD_RX_DUMMY,
- AD_RX_INITIALIZE, // rx Machine
- AD_RX_PORT_DISABLED, // rx Machine
- AD_RX_LACP_DISABLED, // rx Machine
- AD_RX_EXPIRED, // rx Machine
- AD_RX_DEFAULTED, // rx Machine
- AD_RX_CURRENT // rx Machine
+ AD_RX_INITIALIZE, /* rx Machine */
+ AD_RX_PORT_DISABLED, /* rx Machine */
+ AD_RX_LACP_DISABLED, /* rx Machine */
+ AD_RX_EXPIRED, /* rx Machine */
+ AD_RX_DEFAULTED, /* rx Machine */
+ AD_RX_CURRENT /* rx Machine */
} rx_states_t;
-// periodic machine states(43.4.12 in the 802.3ad standard)
+/* periodic machine states(43.4.12 in the 802.3ad standard) */
typedef enum {
AD_PERIODIC_DUMMY,
- AD_NO_PERIODIC, // periodic machine
- AD_FAST_PERIODIC, // periodic machine
- AD_SLOW_PERIODIC, // periodic machine
- AD_PERIODIC_TX // periodic machine
+ AD_NO_PERIODIC, /* periodic machine */
+ AD_FAST_PERIODIC, /* periodic machine */
+ AD_SLOW_PERIODIC, /* periodic machine */
+ AD_PERIODIC_TX /* periodic machine */
} periodic_states_t;
-// mux machine states(43.4.13 in the 802.3ad standard)
+/* mux machine states(43.4.13 in the 802.3ad standard) */
typedef enum {
AD_MUX_DUMMY,
- AD_MUX_DETACHED, // mux machine
- AD_MUX_WAITING, // mux machine
- AD_MUX_ATTACHED, // mux machine
- AD_MUX_COLLECTING_DISTRIBUTING // mux machine
+ AD_MUX_DETACHED, /* mux machine */
+ AD_MUX_WAITING, /* mux machine */
+ AD_MUX_ATTACHED, /* mux machine */
+ AD_MUX_COLLECTING_DISTRIBUTING /* mux machine */
} mux_states_t;
-// tx machine states(43.4.15 in the 802.3ad standard)
+/* tx machine states(43.4.15 in the 802.3ad standard) */
typedef enum {
AD_TX_DUMMY,
- AD_TRANSMIT // tx Machine
+ AD_TRANSMIT /* tx Machine */
} tx_states_t;
-// rx indication types
+/* rx indication types */
typedef enum {
- AD_TYPE_LACPDU = 1, // type lacpdu
- AD_TYPE_MARKER // type marker
+ AD_TYPE_LACPDU = 1, /* type lacpdu */
+ AD_TYPE_MARKER /* type marker */
} pdu_type_t;
-// rx marker indication types
+/* rx marker indication types */
typedef enum {
- AD_MARKER_INFORMATION_SUBTYPE = 1, // marker imformation subtype
- AD_MARKER_RESPONSE_SUBTYPE // marker response subtype
+ AD_MARKER_INFORMATION_SUBTYPE = 1, /* marker imformation subtype */
+ AD_MARKER_RESPONSE_SUBTYPE /* marker response subtype */
} bond_marker_subtype_t;
-// timers types(43.4.9 in the 802.3ad standard)
+/* timers types(43.4.9 in the 802.3ad standard) */
typedef enum {
AD_CURRENT_WHILE_TIMER,
AD_ACTOR_CHURN_TIMER,
@@ -105,35 +105,35 @@ typedef enum {
#pragma pack(1)
-// Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard)
+/* Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard) */
typedef struct lacpdu {
- u8 subtype; // = LACP(= 0x01)
+ u8 subtype; /* = LACP(= 0x01) */
u8 version_number;
- u8 tlv_type_actor_info; // = actor information(type/length/value)
- u8 actor_information_length; // = 20
+ u8 tlv_type_actor_info; /* = actor information(type/length/value) */
+ u8 actor_information_length; /* = 20 */
__be16 actor_system_priority;
struct mac_addr actor_system;
__be16 actor_key;
__be16 actor_port_priority;
__be16 actor_port;
u8 actor_state;
- u8 reserved_3_1[3]; // = 0
- u8 tlv_type_partner_info; // = partner information
- u8 partner_information_length; // = 20
+ u8 reserved_3_1[3]; /* = 0 */
+ u8 tlv_type_partner_info; /* = partner information */
+ u8 partner_information_length; /* = 20 */
__be16 partner_system_priority;
struct mac_addr partner_system;
__be16 partner_key;
__be16 partner_port_priority;
__be16 partner_port;
u8 partner_state;
- u8 reserved_3_2[3]; // = 0
- u8 tlv_type_collector_info; // = collector information
- u8 collector_information_length; // = 16
+ u8 reserved_3_2[3]; /* = 0 */
+ u8 tlv_type_collector_info; /* = collector information */
+ u8 collector_information_length;/* = 16 */
__be16 collector_max_delay;
u8 reserved_12[12];
- u8 tlv_type_terminator; // = terminator
- u8 terminator_length; // = 0
- u8 reserved_50[50]; // = 0
+ u8 tlv_type_terminator; /* = terminator */
+ u8 terminator_length; /* = 0 */
+ u8 reserved_50[50]; /* = 0 */
} __packed lacpdu_t;
typedef struct lacpdu_header {
@@ -141,20 +141,20 @@ typedef struct lacpdu_header {
struct lacpdu lacpdu;
} __packed lacpdu_header_t;
-// Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard)
+/* Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard) */
typedef struct bond_marker {
- u8 subtype; // = 0x02 (marker PDU)
- u8 version_number; // = 0x01
- u8 tlv_type; // = 0x01 (marker information)
- // = 0x02 (marker response information)
- u8 marker_length; // = 0x16
- u16 requester_port; // The number assigned to the port by the requester
- struct mac_addr requester_system; // The requester's system id
- u32 requester_transaction_id; // The transaction id allocated by the requester,
- u16 pad; // = 0
- u8 tlv_type_terminator; // = 0x00
- u8 terminator_length; // = 0x00
- u8 reserved_90[90]; // = 0
+ u8 subtype; /* = 0x02 (marker PDU) */
+ u8 version_number; /* = 0x01 */
+ u8 tlv_type; /* = 0x01 (marker information) */
+ /* = 0x02 (marker response information) */
+ u8 marker_length; /* = 0x16 */
+ u16 requester_port; /* The number assigned to the port by the requester */
+ struct mac_addr requester_system; /* The requester's system id */
+ u32 requester_transaction_id; /* The transaction id allocated by the requester, */
+ u16 pad; /* = 0 */
+ u8 tlv_type_terminator; /* = 0x00 */
+ u8 terminator_length; /* = 0x00 */
+ u8 reserved_90[90]; /* = 0 */
} __packed bond_marker_t;
typedef struct bond_marker_header {
@@ -173,7 +173,7 @@ struct port;
#pragma pack(8)
#endif
-// aggregator structure(43.4.5 in the 802.3ad standard)
+/* aggregator structure(43.4.5 in the 802.3ad standard) */
typedef struct aggregator {
struct mac_addr aggregator_mac_address;
u16 aggregator_identifier;
@@ -183,12 +183,12 @@ typedef struct aggregator {
struct mac_addr partner_system;
u16 partner_system_priority;
u16 partner_oper_aggregator_key;
- u16 receive_state; // BOOLEAN
- u16 transmit_state; // BOOLEAN
+ u16 receive_state; /* BOOLEAN */
+ u16 transmit_state; /* BOOLEAN */
struct port *lag_ports;
- // ****** PRIVATE PARAMETERS ******
- struct slave *slave; // pointer to the bond slave that this aggregator belongs to
- u16 is_active; // BOOLEAN. Indicates if this aggregator is active
+ /* ****** PRIVATE PARAMETERS ****** */
+ struct slave *slave; /* pointer to the bond slave that this aggregator belongs to */
+ u16 is_active; /* BOOLEAN. Indicates if this aggregator is active */
u16 num_of_ports;
} aggregator_t;
@@ -201,12 +201,12 @@ struct port_params {
u16 port_state;
};
-// port structure(43.4.6 in the 802.3ad standard)
+/* port structure(43.4.6 in the 802.3ad standard) */
typedef struct port {
u16 actor_port_number;
u16 actor_port_priority;
- struct mac_addr actor_system; // This parameter is added here although it is not specified in the standard, just for simplification
- u16 actor_system_priority; // This parameter is added here although it is not specified in the standard, just for simplification
+ struct mac_addr actor_system; /* This parameter is added here although it is not specified in the standard, just for simplification */
+ u16 actor_system_priority; /* This parameter is added here although it is not specified in the standard, just for simplification */
u16 actor_port_aggregator_identifier;
bool ntt;
u16 actor_admin_port_key;
@@ -219,24 +219,24 @@ typedef struct port {
bool is_enabled;
- // ****** PRIVATE PARAMETERS ******
- u16 sm_vars; // all state machines variables for this port
- rx_states_t sm_rx_state; // state machine rx state
- u16 sm_rx_timer_counter; // state machine rx timer counter
- periodic_states_t sm_periodic_state;// state machine periodic state
- u16 sm_periodic_timer_counter; // state machine periodic timer counter
- mux_states_t sm_mux_state; // state machine mux state
- u16 sm_mux_timer_counter; // state machine mux timer counter
- tx_states_t sm_tx_state; // state machine tx state
- u16 sm_tx_timer_counter; // state machine tx timer counter(allways on - enter to transmit state 3 time per second)
- struct slave *slave; // pointer to the bond slave that this port belongs to
- struct aggregator *aggregator; // pointer to an aggregator that this port related to
- struct port *next_port_in_aggregator; // Next port on the linked list of the parent aggregator
- u32 transaction_id; // continuous number for identification of Marker PDU's;
- struct lacpdu lacpdu; // the lacpdu that will be sent for this port
+ /* ****** PRIVATE PARAMETERS ****** */
+ u16 sm_vars; /* all state machines variables for this port */
+ rx_states_t sm_rx_state; /* state machine rx state */
+ u16 sm_rx_timer_counter; /* state machine rx timer counter */
+ periodic_states_t sm_periodic_state; /* state machine periodic state */
+ u16 sm_periodic_timer_counter; /* state machine periodic timer counter */
+ mux_states_t sm_mux_state; /* state machine mux state */
+ u16 sm_mux_timer_counter; /* state machine mux timer counter */
+ tx_states_t sm_tx_state; /* state machine tx state */
+ u16 sm_tx_timer_counter; /* state machine tx timer counter(allways on - enter to transmit state 3 time per second) */
+ struct slave *slave; /* pointer to the bond slave that this port belongs to */
+ struct aggregator *aggregator; /* pointer to an aggregator that this port related to */
+ struct port *next_port_in_aggregator; /* Next port on the linked list of the parent aggregator */
+ u32 transaction_id; /* continuous number for identification of Marker PDU's; */
+ struct lacpdu lacpdu; /* the lacpdu that will be sent for this port */
} port_t;
-// system structure
+/* system structure */
struct ad_system {
u16 sys_priority;
struct mac_addr sys_mac_addr;
@@ -246,26 +246,26 @@ struct ad_system {
#pragma pack()
#endif
-// ================= AD Exported structures to the main bonding code ==================
+/* ========== AD Exported structures to the main bonding code ========== */
#define BOND_AD_INFO(bond) ((bond)->ad_info)
#define SLAVE_AD_INFO(slave) ((slave)->ad_info)
struct ad_bond_info {
- struct ad_system system; /* 802.3ad system structure */
- u32 agg_select_timer; // Timer to select aggregator after all adapter's hand shakes
+ struct ad_system system; /* 802.3ad system structure */
+ u32 agg_select_timer; /* Timer to select aggregator after all adapter's hand shakes */
+ u16 aggregator_identifier;
};
struct ad_slave_info {
- struct aggregator aggregator; // 802.3ad aggregator structure
- struct port port; // 802.3ad port structure
- spinlock_t state_machine_lock; /* mutex state machines vs.
- incoming LACPDU */
+ struct aggregator aggregator; /* 802.3ad aggregator structure */
+ struct port port; /* 802.3ad port structure */
+ spinlock_t state_machine_lock; /* mutex state machines vs. incoming LACPDU */
u16 id;
};
-// ================= AD Exported functions to the main bonding code ==================
+/* ========== AD Exported functions to the main bonding code ========== */
void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution);
-void bond_3ad_bind_slave(struct slave *slave);
+void bond_3ad_bind_slave(struct slave *slave);
void bond_3ad_unbind_slave(struct slave *slave);
void bond_3ad_state_machine_handler(struct work_struct *);
void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout);
@@ -280,5 +280,5 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
struct slave *slave);
int bond_3ad_set_carrier(struct bonding *bond);
void bond_3ad_update_lacp_rate(struct bonding *bond);
-#endif //__BOND_3AD_H__
+#endif /* __BOND_3AD_H__ */
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index a2c47476804d..9f69e818b000 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -93,9 +93,8 @@ static inline u8 _simple_hash(const u8 *hash_start, int hash_size)
int i;
u8 hash = 0;
- for (i = 0; i < hash_size; i++) {
+ for (i = 0; i < hash_size; i++)
hash ^= hash_start[i];
- }
return hash;
}
@@ -190,9 +189,8 @@ static int tlb_initialize(struct bonding *bond)
bond_info->tx_hashtbl = new_hashtbl;
- for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) {
+ for (i = 0; i < TLB_HASH_TABLE_SIZE; i++)
tlb_init_table_entry(&bond_info->tx_hashtbl[i], 0);
- }
_unlock_tx_hashtbl_bh(bond);
@@ -264,9 +262,8 @@ static struct slave *__tlb_choose_channel(struct bonding *bond, u32 hash_index,
hash_table[hash_index].next = next_index;
hash_table[hash_index].prev = TLB_NULL_INDEX;
- if (next_index != TLB_NULL_INDEX) {
+ if (next_index != TLB_NULL_INDEX)
hash_table[next_index].prev = hash_index;
- }
slave_info->head = hash_index;
slave_info->load +=
@@ -274,9 +271,8 @@ static struct slave *__tlb_choose_channel(struct bonding *bond, u32 hash_index,
}
}
- if (assigned_slave) {
+ if (assigned_slave)
hash_table[hash_index].tx_bytes += skb_len;
- }
return assigned_slave;
}
@@ -329,7 +325,7 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)
_lock_rx_hashtbl_bh(bond);
- hash_index = _simple_hash((u8*)&(arp->ip_src), sizeof(arp->ip_src));
+ hash_index = _simple_hash((u8 *)&(arp->ip_src), sizeof(arp->ip_src));
client_info = &(bond_info->rx_hashtbl[hash_index]);
if ((client_info->assigned) &&
@@ -337,7 +333,7 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)
(client_info->ip_dst == arp->ip_src) &&
(!ether_addr_equal_64bits(client_info->mac_dst, arp->mac_src))) {
/* update the clients MAC address */
- memcpy(client_info->mac_dst, arp->mac_src, ETH_ALEN);
+ ether_addr_copy(client_info->mac_dst, arp->mac_src);
client_info->ntt = 1;
bond_info->rx_ntt = 1;
}
@@ -451,9 +447,8 @@ static struct slave *__rlb_next_rx_slave(struct bonding *bond)
*/
static void rlb_teach_disabled_mac_on_primary(struct bonding *bond, u8 addr[])
{
- if (!bond->curr_active_slave) {
+ if (!bond->curr_active_slave)
return;
- }
if (!bond->alb_info.primary_is_promisc) {
if (!dev_set_promiscuity(bond->curr_active_slave->dev, 1))
@@ -513,9 +508,8 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave)
write_lock_bh(&bond->curr_slave_lock);
- if (slave != bond->curr_active_slave) {
+ if (slave != bond->curr_active_slave)
rlb_teach_disabled_mac_on_primary(bond, slave->dev->dev_addr);
- }
write_unlock_bh(&bond->curr_slave_lock);
}
@@ -524,9 +518,8 @@ static void rlb_update_client(struct rlb_client_info *client_info)
{
int i;
- if (!client_info->slave) {
+ if (!client_info->slave)
return;
- }
for (i = 0; i < RLB_ARP_BURST_SIZE; i++) {
struct sk_buff *skb;
@@ -574,9 +567,8 @@ static void rlb_update_rx_clients(struct bonding *bond)
client_info = &(bond_info->rx_hashtbl[hash_index]);
if (client_info->ntt) {
rlb_update_client(client_info);
- if (bond_info->rlb_update_retry_counter == 0) {
+ if (bond_info->rlb_update_retry_counter == 0)
client_info->ntt = 0;
- }
}
}
@@ -610,10 +602,10 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla
}
}
- // update the team's flag only after the whole iteration
+ /* update the team's flag only after the whole iteration */
if (ntt) {
bond_info->rx_ntt = 1;
- //fasten the change
+ /* fasten the change */
bond_info->rlb_update_retry_counter = RLB_UPDATE_RETRY;
}
@@ -677,9 +669,9 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
/* the entry is already assigned to this client */
if (!ether_addr_equal_64bits(arp->mac_dst, mac_bcast)) {
/* update mac address from arp */
- memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN);
+ ether_addr_copy(client_info->mac_dst, arp->mac_dst);
}
- memcpy(client_info->mac_src, arp->mac_src, ETH_ALEN);
+ ether_addr_copy(client_info->mac_src, arp->mac_src);
assigned_slave = client_info->slave;
if (assigned_slave) {
@@ -719,8 +711,8 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
* will be updated with clients actual unicast mac address
* upon receiving an arp reply.
*/
- memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN);
- memcpy(client_info->mac_src, arp->mac_src, ETH_ALEN);
+ ether_addr_copy(client_info->mac_dst, arp->mac_dst);
+ ether_addr_copy(client_info->mac_src, arp->mac_src);
client_info->slave = assigned_slave;
if (!ether_addr_equal_64bits(client_info->mac_dst, mac_bcast)) {
@@ -730,7 +722,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
client_info->ntt = 0;
}
- if (!vlan_get_tag(skb, &client_info->vlan_id))
+ if (vlan_get_tag(skb, &client_info->vlan_id))
client_info->vlan_id = 0;
if (!client_info->assigned) {
@@ -770,9 +762,8 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
* rx channel
*/
tx_slave = rlb_choose_channel(skb, bond);
- if (tx_slave) {
- memcpy(arp->mac_src,tx_slave->dev->dev_addr, ETH_ALEN);
- }
+ if (tx_slave)
+ ether_addr_copy(arp->mac_src, tx_slave->dev->dev_addr);
pr_debug("Server sent ARP Reply packet\n");
} else if (arp->op_code == htons(ARPOP_REQUEST)) {
/* Create an entry in the rx_hashtbl for this client as a
@@ -824,9 +815,8 @@ static void rlb_rebalance(struct bonding *bond)
}
/* update the team's flag only after the whole iteration */
- if (ntt) {
+ if (ntt)
bond_info->rx_ntt = 1;
- }
_unlock_rx_hashtbl_bh(bond);
}
@@ -923,7 +913,7 @@ static void rlb_src_link(struct bonding *bond, u32 ip_src_hash, u32 ip_dst_hash)
static void rlb_purge_src_ip(struct bonding *bond, struct arp_pkt *arp)
{
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
- u32 ip_src_hash = _simple_hash((u8*)&(arp->ip_src), sizeof(arp->ip_src));
+ u32 ip_src_hash = _simple_hash((u8 *)&(arp->ip_src), sizeof(arp->ip_src));
u32 index;
_lock_rx_hashtbl_bh(bond);
@@ -957,9 +947,8 @@ static int rlb_initialize(struct bonding *bond)
bond_info->rx_hashtbl_used_head = RLB_NULL_INDEX;
- for (i = 0; i < RLB_HASH_TABLE_SIZE; i++) {
+ for (i = 0; i < RLB_HASH_TABLE_SIZE; i++)
rlb_init_table_entry(bond_info->rx_hashtbl + i);
- }
_unlock_rx_hashtbl_bh(bond);
@@ -1014,9 +1003,9 @@ static void alb_send_lp_vid(struct slave *slave, u8 mac_addr[],
char *data;
memset(&pkt, 0, size);
- memcpy(pkt.mac_dst, mac_addr, ETH_ALEN);
- memcpy(pkt.mac_src, mac_addr, ETH_ALEN);
- pkt.type = cpu_to_be16(ETH_P_LOOP);
+ ether_addr_copy(pkt.mac_dst, mac_addr);
+ ether_addr_copy(pkt.mac_src, mac_addr);
+ pkt.type = cpu_to_be16(ETH_P_LOOPBACK);
skb = dev_alloc_skb(size);
if (!skb)
@@ -1097,7 +1086,7 @@ static void alb_swap_mac_addr(struct slave *slave1, struct slave *slave2)
{
u8 tmp_mac_addr[ETH_ALEN];
- memcpy(tmp_mac_addr, slave1->dev->dev_addr, ETH_ALEN);
+ ether_addr_copy(tmp_mac_addr, slave1->dev->dev_addr);
alb_set_slave_mac_addr(slave1, slave2->dev->dev_addr);
alb_set_slave_mac_addr(slave2, tmp_mac_addr);
@@ -1254,9 +1243,9 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
if (free_mac_slave) {
alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr);
- pr_warning("%s: Warning: the hw address of slave %s is in use by the bond; giving it the hw address of %s\n",
- bond->dev->name, slave->dev->name,
- free_mac_slave->dev->name);
+ pr_warn("%s: Warning: the hw address of slave %s is in use by the bond; giving it the hw address of %s\n",
+ bond->dev->name, slave->dev->name,
+ free_mac_slave->dev->name);
} else if (has_bond_addr) {
pr_err("%s: Error: the hw address of slave %s is in use by the bond; couldn't find a slave with a free hw address to give it (this should not have happened)\n",
@@ -1294,12 +1283,12 @@ static int alb_set_mac_address(struct bonding *bond, void *addr)
bond_for_each_slave(bond, slave, iter) {
/* save net_device's current hw address */
- memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
+ ether_addr_copy(tmp_addr, slave->dev->dev_addr);
res = dev_set_mac_address(slave->dev, addr);
/* restore net_device's hw address */
- memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN);
+ ether_addr_copy(slave->dev->dev_addr, tmp_addr);
if (res)
goto unwind;
@@ -1315,9 +1304,9 @@ unwind:
bond_for_each_slave(bond, rollback_slave, iter) {
if (rollback_slave == slave)
break;
- memcpy(tmp_addr, rollback_slave->dev->dev_addr, ETH_ALEN);
+ ether_addr_copy(tmp_addr, rollback_slave->dev->dev_addr);
dev_set_mac_address(rollback_slave->dev, &sa);
- memcpy(rollback_slave->dev->dev_addr, tmp_addr, ETH_ALEN);
+ ether_addr_copy(rollback_slave->dev->dev_addr, tmp_addr);
}
return res;
@@ -1330,9 +1319,8 @@ int bond_alb_initialize(struct bonding *bond, int rlb_enabled)
int res;
res = tlb_initialize(bond);
- if (res) {
+ if (res)
return res;
- }
if (rlb_enabled) {
bond->alb_info.rlb_enabled = 1;
@@ -1355,9 +1343,8 @@ void bond_alb_deinitialize(struct bonding *bond)
tlb_deinitialize(bond);
- if (bond_info->rlb_enabled) {
+ if (bond_info->rlb_enabled)
rlb_deinitialize(bond);
- }
}
int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
@@ -1436,14 +1423,13 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
break;
}
- hash_start = (char*)eth_data->h_dest;
+ hash_start = (char *)eth_data->h_dest;
hash_size = ETH_ALEN;
break;
case ETH_P_ARP:
do_tx_balance = 0;
- if (bond_info->rlb_enabled) {
+ if (bond_info->rlb_enabled)
tx_slave = rlb_arp_xmit(skb, bond);
- }
break;
default:
do_tx_balance = 0;
@@ -1463,23 +1449,22 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
if (tx_slave && SLAVE_IS_OK(tx_slave)) {
if (tx_slave != rcu_dereference(bond->curr_active_slave)) {
- memcpy(eth_data->h_source,
- tx_slave->dev->dev_addr,
- ETH_ALEN);
+ ether_addr_copy(eth_data->h_source,
+ tx_slave->dev->dev_addr);
}
bond_dev_queue_xmit(bond, skb, tx_slave->dev);
goto out;
- } else {
- if (tx_slave) {
- _lock_tx_hashtbl(bond);
- __tlb_clear_slave(bond, tx_slave, 0);
- _unlock_tx_hashtbl(bond);
- }
+ }
+
+ if (tx_slave) {
+ _lock_tx_hashtbl(bond);
+ __tlb_clear_slave(bond, tx_slave, 0);
+ _unlock_tx_hashtbl(bond);
}
/* no suitable interface, frame not sent */
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
out:
return NETDEV_TX_OK;
}
@@ -1577,11 +1562,10 @@ void bond_alb_monitor(struct work_struct *work)
--bond_info->rlb_update_delay_counter;
} else {
rlb_update_rx_clients(bond);
- if (bond_info->rlb_update_retry_counter) {
+ if (bond_info->rlb_update_retry_counter)
--bond_info->rlb_update_retry_counter;
- } else {
+ else
bond_info->rx_ntt = 0;
- }
}
}
}
@@ -1598,23 +1582,20 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave)
int res;
res = alb_set_slave_mac_addr(slave, slave->perm_hwaddr);
- if (res) {
+ if (res)
return res;
- }
res = alb_handle_addr_collision_on_attach(bond, slave);
- if (res) {
+ if (res)
return res;
- }
tlb_init_slave(slave);
/* order a rebalance ASAP */
bond->alb_info.tx_rebalance_counter = BOND_TLB_REBALANCE_TICKS;
- if (bond->alb_info.rlb_enabled) {
+ if (bond->alb_info.rlb_enabled)
bond->alb_info.rlb_rebalance = 1;
- }
return 0;
}
@@ -1645,9 +1626,8 @@ void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char
if (link == BOND_LINK_DOWN) {
tlb_clear_slave(bond, slave, 0);
- if (bond->alb_info.rlb_enabled) {
+ if (bond->alb_info.rlb_enabled)
rlb_clear_slave(bond, slave);
- }
} else if (link == BOND_LINK_UP) {
/* order a rebalance ASAP */
bond_info->tx_rebalance_counter = BOND_TLB_REBALANCE_TICKS;
@@ -1723,14 +1703,14 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
struct sockaddr sa;
u8 tmp_addr[ETH_ALEN];
- memcpy(tmp_addr, new_slave->dev->dev_addr, ETH_ALEN);
+ ether_addr_copy(tmp_addr, new_slave->dev->dev_addr);
memcpy(sa.sa_data, bond->dev->dev_addr, bond->dev->addr_len);
sa.sa_family = bond->dev->type;
/* we don't care if it can't change its mac, best effort */
dev_set_mac_address(new_slave->dev, &sa);
- memcpy(new_slave->dev->dev_addr, tmp_addr, ETH_ALEN);
+ ether_addr_copy(new_slave->dev->dev_addr, tmp_addr);
}
/* curr_active_slave must be set before calling alb_swap_mac_addr */
@@ -1759,14 +1739,12 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
struct slave *swap_slave;
int res;
- if (!is_valid_ether_addr(sa->sa_data)) {
+ if (!is_valid_ether_addr(sa->sa_data))
return -EADDRNOTAVAIL;
- }
res = alb_set_mac_address(bond, addr);
- if (res) {
+ if (res)
return res;
- }
memcpy(bond_dev->dev_addr, sa->sa_data, bond_dev->addr_len);
@@ -1774,9 +1752,8 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
* Otherwise we'll need to pass the new address to it and handle
* duplications.
*/
- if (!bond->curr_active_slave) {
+ if (!bond->curr_active_slave)
return 0;
- }
swap_slave = bond_slave_has_mac(bond, bond_dev->dev_addr);
@@ -1800,8 +1777,7 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id)
{
- if (bond->alb_info.rlb_enabled) {
+ if (bond->alb_info.rlb_enabled)
rlb_clear_vlan(bond, vlan_id);
- }
}
diff --git a/drivers/net/bonding/bond_debugfs.c b/drivers/net/bonding/bond_debugfs.c
index 5fc4c2351478..2d3f7fa541ff 100644
--- a/drivers/net/bonding/bond_debugfs.c
+++ b/drivers/net/bonding/bond_debugfs.c
@@ -69,7 +69,7 @@ void bond_debug_register(struct bonding *bond)
debugfs_create_dir(bond->dev->name, bonding_debug_root);
if (!bond->debug_dir) {
- pr_warning("%s: Warning: failed to register to debugfs\n",
+ pr_warn("%s: Warning: failed to register to debugfs\n",
bond->dev->name);
return;
}
@@ -98,9 +98,8 @@ void bond_debug_reregister(struct bonding *bond)
if (d) {
bond->debug_dir = d;
} else {
- pr_warning("%s: Warning: failed to reregister, "
- "so just unregister old one\n",
- bond->dev->name);
+ pr_warn("%s: Warning: failed to reregister, so just unregister old one\n",
+ bond->dev->name);
bond_debug_unregister(bond);
}
}
@@ -110,8 +109,7 @@ void bond_create_debugfs(void)
bonding_debug_root = debugfs_create_dir("bonding", NULL);
if (!bonding_debug_root) {
- pr_warning("Warning: Cannot create bonding directory"
- " in debugfs\n");
+ pr_warn("Warning: Cannot create bonding directory in debugfs\n");
}
}
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 4c08018d7333..95a6ca7d9e51 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -673,12 +673,12 @@ static void bond_do_fail_over_mac(struct bonding *bond,
write_unlock_bh(&bond->curr_slave_lock);
if (old_active) {
- memcpy(tmp_mac, new_active->dev->dev_addr, ETH_ALEN);
- memcpy(saddr.sa_data, old_active->dev->dev_addr,
- ETH_ALEN);
+ ether_addr_copy(tmp_mac, new_active->dev->dev_addr);
+ ether_addr_copy(saddr.sa_data,
+ old_active->dev->dev_addr);
saddr.sa_family = new_active->dev->type;
} else {
- memcpy(saddr.sa_data, bond->dev->dev_addr, ETH_ALEN);
+ ether_addr_copy(saddr.sa_data, bond->dev->dev_addr);
saddr.sa_family = bond->dev->type;
}
@@ -692,7 +692,7 @@ static void bond_do_fail_over_mac(struct bonding *bond,
if (!old_active)
goto out;
- memcpy(saddr.sa_data, tmp_mac, ETH_ALEN);
+ ether_addr_copy(saddr.sa_data, tmp_mac);
saddr.sa_family = old_active->dev->type;
rv = dev_set_mac_address(old_active->dev, &saddr);
@@ -798,11 +798,11 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
return;
if (new_active) {
- new_active->jiffies = jiffies;
+ new_active->last_link_up = jiffies;
if (new_active->link == BOND_LINK_BACK) {
if (USES_PRIMARY(bond->params.mode)) {
- pr_info("%s: making interface %s the new active one %d ms earlier.\n",
+ pr_info("%s: making interface %s the new active one %d ms earlier\n",
bond->dev->name, new_active->dev->name,
(bond->params.updelay - new_active->delay) * bond->params.miimon);
}
@@ -817,7 +817,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP);
} else {
if (USES_PRIMARY(bond->params.mode)) {
- pr_info("%s: making interface %s the new active one.\n",
+ pr_info("%s: making interface %s the new active one\n",
bond->dev->name, new_active->dev->name);
}
}
@@ -829,21 +829,25 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
if (bond_is_lb(bond)) {
bond_alb_handle_active_change(bond, new_active);
if (old_active)
- bond_set_slave_inactive_flags(old_active);
+ bond_set_slave_inactive_flags(old_active,
+ BOND_SLAVE_NOTIFY_NOW);
if (new_active)
- bond_set_slave_active_flags(new_active);
+ bond_set_slave_active_flags(new_active,
+ BOND_SLAVE_NOTIFY_NOW);
} else {
rcu_assign_pointer(bond->curr_active_slave, new_active);
}
if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
if (old_active)
- bond_set_slave_inactive_flags(old_active);
+ bond_set_slave_inactive_flags(old_active,
+ BOND_SLAVE_NOTIFY_NOW);
if (new_active) {
bool should_notify_peers = false;
- bond_set_slave_active_flags(new_active);
+ bond_set_slave_active_flags(new_active,
+ BOND_SLAVE_NOTIFY_NOW);
if (bond->params.fail_over_mac)
bond_do_fail_over_mac(bond, new_active,
@@ -906,7 +910,7 @@ void bond_select_active_slave(struct bonding *bond)
pr_info("%s: first active interface up!\n",
bond->dev->name);
} else {
- pr_info("%s: now running without any active interface !\n",
+ pr_info("%s: now running without any active interface!\n",
bond->dev->name);
}
}
@@ -918,12 +922,12 @@ static inline int slave_enable_netpoll(struct slave *slave)
struct netpoll *np;
int err = 0;
- np = kzalloc(sizeof(*np), GFP_ATOMIC);
+ np = kzalloc(sizeof(*np), GFP_KERNEL);
err = -ENOMEM;
if (!np)
goto out;
- err = __netpoll_setup(np, slave->dev, GFP_ATOMIC);
+ err = __netpoll_setup(np, slave->dev);
if (err) {
kfree(np);
goto out;
@@ -942,14 +946,6 @@ static inline void slave_disable_netpoll(struct slave *slave)
slave->np = NULL;
__netpoll_free_async(np);
}
-static inline bool slave_dev_support_netpoll(struct net_device *slave_dev)
-{
- if (slave_dev->priv_flags & IFF_DISABLE_NETPOLL)
- return false;
- if (!slave_dev->netdev_ops->ndo_poll_controller)
- return false;
- return true;
-}
static void bond_poll_controller(struct net_device *bond_dev)
{
@@ -966,7 +962,7 @@ static void bond_netpoll_cleanup(struct net_device *bond_dev)
slave_disable_netpoll(slave);
}
-static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni, gfp_t gfp)
+static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
{
struct bonding *bond = netdev_priv(dev);
struct list_head *iter;
@@ -1115,9 +1111,6 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
slave = bond_slave_get_rcu(skb->dev);
bond = slave->bond;
- if (bond->params.arp_interval)
- slave->dev->last_rx = jiffies;
-
recv_probe = ACCESS_ONCE(bond->recv_probe);
if (recv_probe) {
ret = recv_probe(skb, bond, slave);
@@ -1142,7 +1135,7 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
kfree_skb(skb);
return RX_HANDLER_CONSUMED;
}
- memcpy(eth_hdr(skb)->h_dest, bond->dev->dev_addr, ETH_ALEN);
+ ether_addr_copy(eth_hdr(skb)->h_dest, bond->dev->dev_addr);
}
return ret;
@@ -1183,16 +1176,21 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
if (!bond->params.use_carrier &&
slave_dev->ethtool_ops->get_link == NULL &&
slave_ops->ndo_do_ioctl == NULL) {
- pr_warning("%s: Warning: no link monitoring support for %s\n",
- bond_dev->name, slave_dev->name);
+ pr_warn("%s: Warning: no link monitoring support for %s\n",
+ bond_dev->name, slave_dev->name);
}
/* already enslaved */
if (slave_dev->flags & IFF_SLAVE) {
- pr_debug("Error, Device was already enslaved\n");
+ pr_debug("Error: Device was already enslaved\n");
return -EBUSY;
}
+ if (bond_dev == slave_dev) {
+ pr_err("%s: cannot enslave bond to itself.\n", bond_dev->name);
+ return -EPERM;
+ }
+
/* vlan challenged mutual exclusion */
/* no need to lock since we're protected by rtnl_lock */
if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) {
@@ -1202,9 +1200,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
bond_dev->name, slave_dev->name, bond_dev->name);
return -EPERM;
} else {
- pr_warning("%s: Warning: enslaved VLAN challenged slave %s. Adding VLANs will be blocked as long as %s is part of bond %s\n",
- bond_dev->name, slave_dev->name,
- slave_dev->name, bond_dev->name);
+ pr_warn("%s: Warning: enslaved VLAN challenged slave %s. Adding VLANs will be blocked as long as %s is part of bond %s\n",
+ bond_dev->name, slave_dev->name,
+ slave_dev->name, bond_dev->name);
}
} else {
pr_debug("%s: ! NETIF_F_VLAN_CHALLENGED\n", slave_dev->name);
@@ -1217,7 +1215,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
* enslaving it; the old ifenslave will not.
*/
if ((slave_dev->flags & IFF_UP)) {
- pr_err("%s is up. This may be due to an out of date ifenslave.\n",
+ pr_err("%s is up - this may be due to an out of date ifenslave\n",
slave_dev->name);
res = -EPERM;
goto err_undo_flags;
@@ -1261,20 +1259,23 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
bond_dev);
}
} else if (bond_dev->type != slave_dev->type) {
- pr_err("%s ether type (%d) is different from other slaves (%d), can not enslave it.\n",
- slave_dev->name,
- slave_dev->type, bond_dev->type);
+ pr_err("%s ether type (%d) is different from other slaves (%d), can not enslave it\n",
+ slave_dev->name, slave_dev->type, bond_dev->type);
res = -EINVAL;
goto err_undo_flags;
}
if (slave_ops->ndo_set_mac_address == NULL) {
if (!bond_has_slaves(bond)) {
- pr_warning("%s: Warning: The first slave device specified does not support setting the MAC address. Setting fail_over_mac to active.",
- bond_dev->name);
- bond->params.fail_over_mac = BOND_FOM_ACTIVE;
+ pr_warn("%s: Warning: The first slave device specified does not support setting the MAC address\n",
+ bond_dev->name);
+ if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
+ bond->params.fail_over_mac = BOND_FOM_ACTIVE;
+ pr_warn("%s: Setting fail_over_mac to active for active-backup mode\n",
+ bond_dev->name);
+ }
} else if (bond->params.fail_over_mac != BOND_FOM_ACTIVE) {
- pr_err("%s: Error: The slave device specified does not support setting the MAC address, but fail_over_mac is not set to active.\n",
+ pr_err("%s: Error: The slave device specified does not support setting the MAC address, but fail_over_mac is not set to active\n",
bond_dev->name);
res = -EOPNOTSUPP;
goto err_undo_flags;
@@ -1313,9 +1314,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
* that need it, and for restoring it upon release, and then
* set it to the master's address
*/
- memcpy(new_slave->perm_hwaddr, slave_dev->dev_addr, ETH_ALEN);
+ ether_addr_copy(new_slave->perm_hwaddr, slave_dev->dev_addr);
- if (!bond->params.fail_over_mac) {
+ if (!bond->params.fail_over_mac ||
+ bond->params.mode != BOND_MODE_ACTIVEBACKUP) {
/*
* Set slave to master's mac address. The application already
* set the master's mac address to that of the first slave
@@ -1396,10 +1398,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
bond_update_speed_duplex(new_slave);
- new_slave->last_arp_rx = jiffies -
+ new_slave->last_rx = jiffies -
(msecs_to_jiffies(bond->params.arp_interval) + 1);
for (i = 0; i < BOND_MAX_ARP_TARGETS; i++)
- new_slave->target_last_arp_rx[i] = new_slave->last_arp_rx;
+ new_slave->target_last_arp_rx[i] = new_slave->last_rx;
if (bond->params.miimon && !bond->params.use_carrier) {
link_reporting = bond_check_dev_link(bond, slave_dev, 1);
@@ -1414,12 +1416,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
* supported); thus, we don't need to change
* the messages for netif_carrier.
*/
- pr_warning("%s: Warning: MII and ETHTOOL support not available for interface %s, and arp_interval/arp_ip_target module parameters not specified, thus bonding will not detect link failures! see bonding.txt for details.\n",
- bond_dev->name, slave_dev->name);
+ pr_warn("%s: Warning: MII and ETHTOOL support not available for interface %s, and arp_interval/arp_ip_target module parameters not specified, thus bonding will not detect link failures! see bonding.txt for details\n",
+ bond_dev->name, slave_dev->name);
} else if (link_reporting == -1) {
/* unable get link status using mii/ethtool */
- pr_warning("%s: Warning: can't get link status from interface %s; the network driver associated with this interface does not support MII or ETHTOOL link status reporting, thus miimon has no effect on this interface.\n",
- bond_dev->name, slave_dev->name);
+ pr_warn("%s: Warning: can't get link status from interface %s; the network driver associated with this interface does not support MII or ETHTOOL link status reporting, thus miimon has no effect on this interface\n",
+ bond_dev->name, slave_dev->name);
}
}
@@ -1443,10 +1445,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
}
if (new_slave->link != BOND_LINK_DOWN)
- new_slave->jiffies = jiffies;
+ new_slave->last_link_up = jiffies;
pr_debug("Initial state of slave_dev is BOND_LINK_%s\n",
- new_slave->link == BOND_LINK_DOWN ? "DOWN" :
- (new_slave->link == BOND_LINK_UP ? "UP" : "BACK"));
+ new_slave->link == BOND_LINK_DOWN ? "DOWN" :
+ (new_slave->link == BOND_LINK_UP ? "UP" : "BACK"));
if (USES_PRIMARY(bond->params.mode) && bond->params.primary[0]) {
/* if there is a primary slave, remember it */
@@ -1458,14 +1460,15 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
switch (bond->params.mode) {
case BOND_MODE_ACTIVEBACKUP:
- bond_set_slave_inactive_flags(new_slave);
+ bond_set_slave_inactive_flags(new_slave,
+ BOND_SLAVE_NOTIFY_NOW);
break;
case BOND_MODE_8023AD:
/* in 802.3ad mode, the internal mechanism
* will activate the slaves in the selected
* aggregator
*/
- bond_set_slave_inactive_flags(new_slave);
+ bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW);
/* if this is the first slave */
if (!prev_slave) {
SLAVE_AD_INFO(new_slave).id = 1;
@@ -1483,7 +1486,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
case BOND_MODE_TLB:
case BOND_MODE_ALB:
bond_set_active_slave(new_slave);
- bond_set_slave_inactive_flags(new_slave);
+ bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW);
break;
default:
pr_debug("This slave is always active in trunk mode\n");
@@ -1505,10 +1508,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
slave_dev->npinfo = bond->dev->npinfo;
if (slave_dev->npinfo) {
if (slave_enable_netpoll(new_slave)) {
- read_unlock(&bond->lock);
- pr_info("Error, %s: master_dev is using netpoll, "
- "but new slave device does not support netpoll.\n",
- bond_dev->name);
+ pr_info("Error, %s: master_dev is using netpoll, but new slave device does not support netpoll\n",
+ bond_dev->name);
res = -EBUSY;
goto err_detach;
}
@@ -1539,15 +1540,17 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
bond_set_carrier(bond);
if (USES_PRIMARY(bond->params.mode)) {
+ block_netpoll_tx();
write_lock_bh(&bond->curr_slave_lock);
bond_select_active_slave(bond);
write_unlock_bh(&bond->curr_slave_lock);
+ unblock_netpoll_tx();
}
- pr_info("%s: enslaving %s as a%s interface with a%s link.\n",
+ pr_info("%s: Enslaving %s as %s interface with %s link\n",
bond_dev->name, slave_dev->name,
- bond_is_active_slave(new_slave) ? "n active" : " backup",
- new_slave->link != BOND_LINK_DOWN ? "n up" : " down");
+ bond_is_active_slave(new_slave) ? "an active" : "a backup",
+ new_slave->link != BOND_LINK_DOWN ? "an up" : "a down");
/* enslave is successful */
return 0;
@@ -1567,10 +1570,12 @@ err_detach:
if (bond->primary_slave == new_slave)
bond->primary_slave = NULL;
if (bond->curr_active_slave == new_slave) {
+ block_netpoll_tx();
write_lock_bh(&bond->curr_slave_lock);
bond_change_active_slave(bond, NULL);
bond_select_active_slave(bond);
write_unlock_bh(&bond->curr_slave_lock);
+ unblock_netpoll_tx();
}
slave_disable_netpoll(new_slave);
@@ -1579,12 +1584,13 @@ err_close:
dev_close(slave_dev);
err_restore_mac:
- if (!bond->params.fail_over_mac) {
+ if (!bond->params.fail_over_mac ||
+ bond->params.mode != BOND_MODE_ACTIVEBACKUP) {
/* XXX TODO - fom follow mode needs to change master's
* MAC if this slave's MAC is in use by the bond, or at
* least print a warning.
*/
- memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN);
+ ether_addr_copy(addr.sa_data, new_slave->perm_hwaddr);
addr.sa_family = slave_dev->type;
dev_set_mac_address(slave_dev, &addr);
}
@@ -1629,7 +1635,7 @@ static int __bond_release_one(struct net_device *bond_dev,
/* slave is not a slave or master is not master of this slave */
if (!(slave_dev->flags & IFF_SLAVE) ||
!netdev_has_upper_dev(slave_dev, bond_dev)) {
- pr_err("%s: Error: cannot release %s.\n",
+ pr_err("%s: Error: cannot release %s\n",
bond_dev->name, slave_dev->name);
return -EINVAL;
}
@@ -1645,9 +1651,6 @@ static int __bond_release_one(struct net_device *bond_dev,
return -EINVAL;
}
- /* release the slave from its bond */
- bond->slave_cnt--;
-
bond_sysfs_slave_del(slave);
bond_upper_dev_unlink(bond_dev, slave_dev);
@@ -1663,7 +1666,7 @@ static int __bond_release_one(struct net_device *bond_dev,
write_unlock_bh(&bond->lock);
- pr_info("%s: releasing %s interface %s\n",
+ pr_info("%s: Releasing %s interface %s\n",
bond_dev->name,
bond_is_active_slave(slave) ? "active" : "backup",
slave_dev->name);
@@ -1672,13 +1675,14 @@ static int __bond_release_one(struct net_device *bond_dev,
bond->current_arp_slave = NULL;
- if (!all && !bond->params.fail_over_mac) {
+ if (!all && (!bond->params.fail_over_mac ||
+ bond->params.mode != BOND_MODE_ACTIVEBACKUP)) {
if (ether_addr_equal_64bits(bond_dev->dev_addr, slave->perm_hwaddr) &&
bond_has_slaves(bond))
- pr_warn("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s. Set the HWaddr of %s to a different address to avoid conflicts.\n",
- bond_dev->name, slave_dev->name,
- slave->perm_hwaddr,
- bond_dev->name, slave_dev->name);
+ pr_warn("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s - set the HWaddr of %s to a different address to avoid conflicts\n",
+ bond_dev->name, slave_dev->name,
+ slave->perm_hwaddr,
+ bond_dev->name, slave_dev->name);
}
if (bond->primary_slave == slave)
@@ -1719,15 +1723,16 @@ static int __bond_release_one(struct net_device *bond_dev,
eth_hw_addr_random(bond_dev);
if (vlan_uses_dev(bond_dev)) {
- pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
- bond_dev->name, bond_dev->name);
- pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n",
- bond_dev->name);
+ pr_warn("%s: Warning: clearing HW address of %s while it still has VLANs\n",
+ bond_dev->name, bond_dev->name);
+ pr_warn("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs\n",
+ bond_dev->name);
}
}
unblock_netpoll_tx();
synchronize_rcu();
+ bond->slave_cnt--;
if (!bond_has_slaves(bond)) {
call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev);
@@ -1737,7 +1742,7 @@ static int __bond_release_one(struct net_device *bond_dev,
bond_compute_features(bond);
if (!(bond_dev->features & NETIF_F_VLAN_CHALLENGED) &&
(old_features & NETIF_F_VLAN_CHALLENGED))
- pr_info("%s: last VLAN challenged slave %s left bond %s. VLAN blocking is removed\n",
+ pr_info("%s: last VLAN challenged slave %s left bond %s - VLAN blocking is removed\n",
bond_dev->name, slave_dev->name, bond_dev->name);
/* must do this from outside any spinlocks */
@@ -1769,9 +1774,10 @@ static int __bond_release_one(struct net_device *bond_dev,
/* close slave before restoring its mac address */
dev_close(slave_dev);
- if (bond->params.fail_over_mac != BOND_FOM_ACTIVE) {
+ if (bond->params.fail_over_mac != BOND_FOM_ACTIVE ||
+ bond->params.mode != BOND_MODE_ACTIVEBACKUP) {
/* restore original ("permanent") mac address */
- memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
+ ether_addr_copy(addr.sa_data, slave->perm_hwaddr);
addr.sa_family = slave_dev->type;
dev_set_mac_address(slave_dev, &addr);
}
@@ -1804,7 +1810,7 @@ static int bond_release_and_destroy(struct net_device *bond_dev,
ret = bond_release(bond_dev, slave_dev);
if (ret == 0 && !bond_has_slaves(bond)) {
bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
- pr_info("%s: destroying bond %s.\n",
+ pr_info("%s: Destroying bond %s\n",
bond_dev->name, bond_dev->name);
unregister_netdevice(bond_dev);
}
@@ -1818,9 +1824,7 @@ static int bond_info_query(struct net_device *bond_dev, struct ifbond *info)
info->bond_mode = bond->params.mode;
info->miimon = bond->params.miimon;
- read_lock(&bond->lock);
info->num_slaves = bond->slave_cnt;
- read_unlock(&bond->lock);
return 0;
}
@@ -1832,7 +1836,6 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
int i = 0, res = -ENODEV;
struct slave *slave;
- read_lock(&bond->lock);
bond_for_each_slave(bond, slave, iter) {
if (i++ == (int)info->slave_id) {
res = 0;
@@ -1843,7 +1846,6 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
break;
}
}
- read_unlock(&bond->lock);
return res;
}
@@ -1873,7 +1875,7 @@ static int bond_miimon_inspect(struct bonding *bond)
slave->link = BOND_LINK_FAIL;
slave->delay = bond->params.downdelay;
if (slave->delay) {
- pr_info("%s: link status down for %sinterface %s, disabling it in %d ms.\n",
+ pr_info("%s: link status down for %sinterface %s, disabling it in %d ms\n",
bond->dev->name,
(bond->params.mode ==
BOND_MODE_ACTIVEBACKUP) ?
@@ -1889,8 +1891,8 @@ static int bond_miimon_inspect(struct bonding *bond)
* recovered before downdelay expired
*/
slave->link = BOND_LINK_UP;
- slave->jiffies = jiffies;
- pr_info("%s: link status up again after %d ms for interface %s.\n",
+ slave->last_link_up = jiffies;
+ pr_info("%s: link status up again after %d ms for interface %s\n",
bond->dev->name,
(bond->params.downdelay - slave->delay) *
bond->params.miimon,
@@ -1915,7 +1917,7 @@ static int bond_miimon_inspect(struct bonding *bond)
slave->delay = bond->params.updelay;
if (slave->delay) {
- pr_info("%s: link status up for interface %s, enabling it in %d ms.\n",
+ pr_info("%s: link status up for interface %s, enabling it in %d ms\n",
bond->dev->name, slave->dev->name,
ignore_updelay ? 0 :
bond->params.updelay *
@@ -1925,7 +1927,7 @@ static int bond_miimon_inspect(struct bonding *bond)
case BOND_LINK_BACK:
if (!link_state) {
slave->link = BOND_LINK_DOWN;
- pr_info("%s: link status down again after %d ms for interface %s.\n",
+ pr_info("%s: link status down again after %d ms for interface %s\n",
bond->dev->name,
(bond->params.updelay - slave->delay) *
bond->params.miimon,
@@ -1964,7 +1966,7 @@ static void bond_miimon_commit(struct bonding *bond)
case BOND_LINK_UP:
slave->link = BOND_LINK_UP;
- slave->jiffies = jiffies;
+ slave->last_link_up = jiffies;
if (bond->params.mode == BOND_MODE_8023AD) {
/* prevent it from being the active one */
@@ -1977,7 +1979,7 @@ static void bond_miimon_commit(struct bonding *bond)
bond_set_backup_slave(slave);
}
- pr_info("%s: link status definitely up for interface %s, %u Mbps %s duplex.\n",
+ pr_info("%s: link status definitely up for interface %s, %u Mbps %s duplex\n",
bond->dev->name, slave->dev->name,
slave->speed == SPEED_UNKNOWN ? 0 : slave->speed,
slave->duplex ? "full" : "half");
@@ -2004,7 +2006,8 @@ static void bond_miimon_commit(struct bonding *bond)
if (bond->params.mode == BOND_MODE_ACTIVEBACKUP ||
bond->params.mode == BOND_MODE_8023AD)
- bond_set_slave_inactive_flags(slave);
+ bond_set_slave_inactive_flags(slave,
+ BOND_SLAVE_NOTIFY_NOW);
pr_info("%s: link status definitely down for interface %s, disabling it\n",
bond->dev->name, slave->dev->name);
@@ -2121,24 +2124,40 @@ static bool bond_has_this_ip(struct bonding *bond, __be32 ip)
* switches in VLAN mode (especially if ports are configured as
* "native" to a VLAN) might not pass non-tagged frames.
*/
-static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ip, __be32 src_ip, unsigned short vlan_id)
+static void bond_arp_send(struct net_device *slave_dev, int arp_op,
+ __be32 dest_ip, __be32 src_ip,
+ struct bond_vlan_tag *inner,
+ struct bond_vlan_tag *outer)
{
struct sk_buff *skb;
- pr_debug("arp %d on slave %s: dst %pI4 src %pI4 vid %d\n", arp_op,
- slave_dev->name, &dest_ip, &src_ip, vlan_id);
+ pr_debug("arp %d on slave %s: dst %pI4 src %pI4\n",
+ arp_op, slave_dev->name, &dest_ip, &src_ip);
skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip,
NULL, slave_dev->dev_addr, NULL);
if (!skb) {
- pr_err("ARP packet allocation failed\n");
+ net_err_ratelimited("ARP packet allocation failed\n");
return;
}
- if (vlan_id) {
- skb = vlan_put_tag(skb, htons(ETH_P_8021Q), vlan_id);
+ if (outer->vlan_id) {
+ if (inner->vlan_id) {
+ pr_debug("inner tag: proto %X vid %X\n",
+ ntohs(inner->vlan_proto), inner->vlan_id);
+ skb = __vlan_put_tag(skb, inner->vlan_proto,
+ inner->vlan_id);
+ if (!skb) {
+ net_err_ratelimited("failed to insert inner VLAN tag\n");
+ return;
+ }
+ }
+
+ pr_debug("outer reg: proto %X vid %X\n",
+ ntohs(outer->vlan_proto), outer->vlan_id);
+ skb = vlan_put_tag(skb, outer->vlan_proto, outer->vlan_id);
if (!skb) {
- pr_err("failed to insert VLAN tag\n");
+ net_err_ratelimited("failed to insert outer VLAN tag\n");
return;
}
}
@@ -2151,23 +2170,32 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
struct net_device *upper, *vlan_upper;
struct list_head *iter, *vlan_iter;
struct rtable *rt;
+ struct bond_vlan_tag inner, outer;
__be32 *targets = bond->params.arp_targets, addr;
- int i, vlan_id;
+ int i;
for (i = 0; i < BOND_MAX_ARP_TARGETS && targets[i]; i++) {
pr_debug("basa: target %pI4\n", &targets[i]);
+ inner.vlan_proto = 0;
+ inner.vlan_id = 0;
+ outer.vlan_proto = 0;
+ outer.vlan_id = 0;
/* Find out through which dev should the packet go */
rt = ip_route_output(dev_net(bond->dev), targets[i], 0,
RTO_ONLINK, 0);
if (IS_ERR(rt)) {
- pr_debug("%s: no route to arp_ip_target %pI4\n",
- bond->dev->name, &targets[i]);
+ /* there's no route to target - try to send arp
+ * probe to generate any traffic (arp_validate=0)
+ */
+ if (bond->params.arp_validate)
+ net_warn_ratelimited("%s: no route to arp_ip_target %pI4 and arp_validate is set\n",
+ bond->dev->name,
+ &targets[i]);
+ bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], 0, &inner, &outer);
continue;
}
- vlan_id = 0;
-
/* bond device itself */
if (rt->dst.dev == bond->dev)
goto found;
@@ -2177,17 +2205,30 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
* found we verify its upper dev list, searching for the
* rt->dst.dev. If found we save the tag of the vlan and
* proceed to send the packet.
- *
- * TODO: QinQ?
*/
netdev_for_each_all_upper_dev_rcu(bond->dev, vlan_upper,
vlan_iter) {
if (!is_vlan_dev(vlan_upper))
continue;
+
+ if (vlan_upper == rt->dst.dev) {
+ outer.vlan_proto = vlan_dev_vlan_proto(vlan_upper);
+ outer.vlan_id = vlan_dev_vlan_id(vlan_upper);
+ rcu_read_unlock();
+ goto found;
+ }
netdev_for_each_all_upper_dev_rcu(vlan_upper, upper,
iter) {
if (upper == rt->dst.dev) {
- vlan_id = vlan_dev_vlan_id(vlan_upper);
+ /* If the upper dev is a vlan dev too,
+ * set the vlan tag to inner tag.
+ */
+ if (is_vlan_dev(upper)) {
+ inner.vlan_proto = vlan_dev_vlan_proto(upper);
+ inner.vlan_id = vlan_dev_vlan_id(upper);
+ }
+ outer.vlan_proto = vlan_dev_vlan_proto(vlan_upper);
+ outer.vlan_id = vlan_dev_vlan_id(vlan_upper);
rcu_read_unlock();
goto found;
}
@@ -2200,10 +2241,6 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
*/
netdev_for_each_all_upper_dev_rcu(bond->dev, upper, iter) {
if (upper == rt->dst.dev) {
- /* if it's a vlan - get its VID */
- if (is_vlan_dev(upper))
- vlan_id = vlan_dev_vlan_id(upper);
-
rcu_read_unlock();
goto found;
}
@@ -2222,7 +2259,7 @@ found:
addr = bond_confirm_addr(rt->dst.dev, targets[i], 0);
ip_rt_put(rt);
bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
- addr, vlan_id);
+ addr, &inner, &outer);
}
}
@@ -2240,7 +2277,7 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32
pr_debug("bva: sip %pI4 not found in targets\n", &sip);
return;
}
- slave->last_arp_rx = jiffies;
+ slave->last_rx = jiffies;
slave->target_last_arp_rx[i] = jiffies;
}
@@ -2248,17 +2285,19 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
struct slave *slave)
{
struct arphdr *arp = (struct arphdr *)skb->data;
+ struct slave *curr_active_slave;
unsigned char *arp_ptr;
__be32 sip, tip;
- int alen;
+ int alen, is_arp = skb->protocol == __cpu_to_be16(ETH_P_ARP);
- if (skb->protocol != __cpu_to_be16(ETH_P_ARP))
+ if (!slave_do_arp_validate(bond, slave)) {
+ if ((slave_do_arp_validate_only(bond, slave) && is_arp) ||
+ !slave_do_arp_validate_only(bond, slave))
+ slave->last_rx = jiffies;
return RX_HANDLER_ANOTHER;
-
- read_lock(&bond->lock);
-
- if (!slave_do_arp_validate(bond, slave))
- goto out_unlock;
+ } else if (!is_arp) {
+ return RX_HANDLER_ANOTHER;
+ }
alen = arp_hdr_len(bond->dev);
@@ -2292,6 +2331,8 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
bond->params.arp_validate, slave_do_arp_validate(bond, slave),
&sip, &tip);
+ curr_active_slave = rcu_dereference(bond->curr_active_slave);
+
/*
* Backup slaves won't see the ARP reply, but do come through
* here for each ARP probe (so we swap the sip/tip to validate
@@ -2305,15 +2346,15 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
* is done to avoid endless looping when we can't reach the
* arp_ip_target and fool ourselves with our own arp requests.
*/
+
if (bond_is_active_slave(slave))
bond_validate_arp(bond, slave, sip, tip);
- else if (bond->curr_active_slave &&
- time_after(slave_last_rx(bond, bond->curr_active_slave),
- bond->curr_active_slave->jiffies))
+ else if (curr_active_slave &&
+ time_after(slave_last_rx(bond, curr_active_slave),
+ curr_active_slave->last_link_up))
bond_validate_arp(bond, slave, tip, sip);
out_unlock:
- read_unlock(&bond->lock);
if (arp != (struct arphdr *)skb->data)
kfree(arp);
return RX_HANDLER_ANOTHER;
@@ -2356,9 +2397,9 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
oldcurrent = ACCESS_ONCE(bond->curr_active_slave);
/* see if any of the previous devices are up now (i.e. they have
* xmt and rcv traffic). the curr_active_slave does not come into
- * the picture unless it is null. also, slave->jiffies is not needed
- * here because we send an arp on each slave and give a slave as
- * long as it needs to get the tx/rx within the delta.
+ * the picture unless it is null. also, slave->last_link_up is not
+ * needed here because we send an arp on each slave and give a slave
+ * as long as it needs to get the tx/rx within the delta.
* TODO: what about up/down delay in arp mode? it wasn't here before
* so it can wait
*/
@@ -2367,7 +2408,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
if (slave->link != BOND_LINK_UP) {
if (bond_time_in_interval(bond, trans_start, 1) &&
- bond_time_in_interval(bond, slave->dev->last_rx, 1)) {
+ bond_time_in_interval(bond, slave->last_rx, 1)) {
slave->link = BOND_LINK_UP;
slave_state_changed = 1;
@@ -2378,7 +2419,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
* is closed.
*/
if (!oldcurrent) {
- pr_info("%s: link status definitely up for interface %s, ",
+ pr_info("%s: link status definitely up for interface %s\n",
bond->dev->name,
slave->dev->name);
do_failover = 1;
@@ -2396,7 +2437,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
* if we don't know our ip yet
*/
if (!bond_time_in_interval(bond, trans_start, 2) ||
- !bond_time_in_interval(bond, slave->dev->last_rx, 2)) {
+ !bond_time_in_interval(bond, slave->last_rx, 2)) {
slave->link = BOND_LINK_DOWN;
slave_state_changed = 1;
@@ -2404,9 +2445,8 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
if (slave->link_failure_count < UINT_MAX)
slave->link_failure_count++;
- pr_info("%s: interface %s is now down.\n",
- bond->dev->name,
- slave->dev->name);
+ pr_info("%s: interface %s is now down\n",
+ bond->dev->name, slave->dev->name);
if (slave == oldcurrent)
do_failover = 1;
@@ -2485,7 +2525,7 @@ static int bond_ab_arp_inspect(struct bonding *bond)
* active. This avoids bouncing, as the last receive
* times need a full ARP monitor cycle to be updated.
*/
- if (bond_time_in_interval(bond, slave->jiffies, 2))
+ if (bond_time_in_interval(bond, slave->last_link_up, 2))
continue;
/*
@@ -2551,11 +2591,12 @@ static void bond_ab_arp_commit(struct bonding *bond)
slave->link = BOND_LINK_UP;
if (bond->current_arp_slave) {
bond_set_slave_inactive_flags(
- bond->current_arp_slave);
+ bond->current_arp_slave,
+ BOND_SLAVE_NOTIFY_NOW);
bond->current_arp_slave = NULL;
}
- pr_info("%s: link status definitely up for interface %s.\n",
+ pr_info("%s: link status definitely up for interface %s\n",
bond->dev->name, slave->dev->name);
if (!bond->curr_active_slave ||
@@ -2571,7 +2612,8 @@ static void bond_ab_arp_commit(struct bonding *bond)
slave->link_failure_count++;
slave->link = BOND_LINK_DOWN;
- bond_set_slave_inactive_flags(slave);
+ bond_set_slave_inactive_flags(slave,
+ BOND_SLAVE_NOTIFY_NOW);
pr_info("%s: link status definitely down for interface %s, disabling it\n",
bond->dev->name, slave->dev->name);
@@ -2604,17 +2646,17 @@ do_failover:
/*
* Send ARP probes for active-backup mode ARP monitor.
+ *
+ * Called with rcu_read_lock hold.
*/
static bool bond_ab_arp_probe(struct bonding *bond)
{
struct slave *slave, *before = NULL, *new_slave = NULL,
- *curr_arp_slave, *curr_active_slave;
+ *curr_arp_slave = rcu_dereference(bond->current_arp_slave),
+ *curr_active_slave = rcu_dereference(bond->curr_active_slave);
struct list_head *iter;
bool found = false;
-
- rcu_read_lock();
- curr_arp_slave = rcu_dereference(bond->current_arp_slave);
- curr_active_slave = rcu_dereference(bond->curr_active_slave);
+ bool should_notify_rtnl = BOND_SLAVE_NOTIFY_LATER;
if (curr_arp_slave && curr_active_slave)
pr_info("PROBE: c_arp %s && cas %s BAD\n",
@@ -2623,32 +2665,23 @@ static bool bond_ab_arp_probe(struct bonding *bond)
if (curr_active_slave) {
bond_arp_send_all(bond, curr_active_slave);
- rcu_read_unlock();
- return true;
+ return should_notify_rtnl;
}
- rcu_read_unlock();
/* if we don't have a curr_active_slave, search for the next available
* backup slave from the current_arp_slave and make it the candidate
* for becoming the curr_active_slave
*/
- if (!rtnl_trylock())
- return false;
- /* curr_arp_slave might have gone away */
- curr_arp_slave = ACCESS_ONCE(bond->current_arp_slave);
-
if (!curr_arp_slave) {
- curr_arp_slave = bond_first_slave(bond);
- if (!curr_arp_slave) {
- rtnl_unlock();
- return true;
- }
+ curr_arp_slave = bond_first_slave_rcu(bond);
+ if (!curr_arp_slave)
+ return should_notify_rtnl;
}
- bond_set_slave_inactive_flags(curr_arp_slave);
+ bond_set_slave_inactive_flags(curr_arp_slave, BOND_SLAVE_NOTIFY_LATER);
- bond_for_each_slave(bond, slave, iter) {
+ bond_for_each_slave_rcu(bond, slave, iter) {
if (!found && !before && IS_UP(slave->dev))
before = slave;
@@ -2666,9 +2699,10 @@ static bool bond_ab_arp_probe(struct bonding *bond)
if (slave->link_failure_count < UINT_MAX)
slave->link_failure_count++;
- bond_set_slave_inactive_flags(slave);
+ bond_set_slave_inactive_flags(slave,
+ BOND_SLAVE_NOTIFY_LATER);
- pr_info("%s: backup interface %s is now down.\n",
+ pr_info("%s: backup interface %s is now down\n",
bond->dev->name, slave->dev->name);
}
if (slave == curr_arp_slave)
@@ -2678,26 +2712,31 @@ static bool bond_ab_arp_probe(struct bonding *bond)
if (!new_slave && before)
new_slave = before;
- if (!new_slave) {
- rtnl_unlock();
- return true;
- }
+ if (!new_slave)
+ goto check_state;
new_slave->link = BOND_LINK_BACK;
- bond_set_slave_active_flags(new_slave);
+ bond_set_slave_active_flags(new_slave, BOND_SLAVE_NOTIFY_LATER);
bond_arp_send_all(bond, new_slave);
- new_slave->jiffies = jiffies;
+ new_slave->last_link_up = jiffies;
rcu_assign_pointer(bond->current_arp_slave, new_slave);
- rtnl_unlock();
- return true;
+check_state:
+ bond_for_each_slave_rcu(bond, slave, iter) {
+ if (slave->should_notify) {
+ should_notify_rtnl = BOND_SLAVE_NOTIFY_NOW;
+ break;
+ }
+ }
+ return should_notify_rtnl;
}
static void bond_activebackup_arp_mon(struct work_struct *work)
{
struct bonding *bond = container_of(work, struct bonding,
arp_work.work);
- bool should_notify_peers = false, should_commit = false;
+ bool should_notify_peers = false;
+ bool should_notify_rtnl = false;
int delta_in_ticks;
delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
@@ -2706,11 +2745,12 @@ static void bond_activebackup_arp_mon(struct work_struct *work)
goto re_arm;
rcu_read_lock();
+
should_notify_peers = bond_should_notify_peers(bond);
- should_commit = bond_ab_arp_inspect(bond);
- rcu_read_unlock();
- if (should_commit) {
+ if (bond_ab_arp_inspect(bond)) {
+ rcu_read_unlock();
+
/* Race avoidance with bond_close flush of workqueue */
if (!rtnl_trylock()) {
delta_in_ticks = 1;
@@ -2719,23 +2759,28 @@ static void bond_activebackup_arp_mon(struct work_struct *work)
}
bond_ab_arp_commit(bond);
+
rtnl_unlock();
+ rcu_read_lock();
}
- if (!bond_ab_arp_probe(bond)) {
- /* rtnl locking failed, re-arm */
- delta_in_ticks = 1;
- should_notify_peers = false;
- }
+ should_notify_rtnl = bond_ab_arp_probe(bond);
+ rcu_read_unlock();
re_arm:
if (bond->params.arp_interval)
queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
- if (should_notify_peers) {
+ if (should_notify_peers || should_notify_rtnl) {
if (!rtnl_trylock())
return;
- call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, bond->dev);
+
+ if (should_notify_peers)
+ call_netdevice_notifiers(NETDEV_NOTIFY_PEERS,
+ bond->dev);
+ if (should_notify_rtnl)
+ bond_slave_state_notify(bond);
+
rtnl_unlock();
}
}
@@ -2854,12 +2899,15 @@ static int bond_slave_netdev_event(unsigned long event,
break;
}
- pr_info("%s: Primary slave changed to %s, reselecting active slave.\n",
- bond->dev->name, bond->primary_slave ? slave_dev->name :
- "none");
+ pr_info("%s: Primary slave changed to %s, reselecting active slave\n",
+ bond->dev->name,
+ bond->primary_slave ? slave_dev->name : "none");
+
+ block_netpoll_tx();
write_lock_bh(&bond->curr_slave_lock);
bond_select_active_slave(bond);
write_unlock_bh(&bond->curr_slave_lock);
+ unblock_netpoll_tx();
break;
case NETDEV_FEAT_CHANGE:
bond_compute_features(bond);
@@ -2889,8 +2937,7 @@ static int bond_netdev_event(struct notifier_block *this,
struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
pr_debug("event_dev: %s, event: %lx\n",
- event_dev ? event_dev->name : "None",
- event);
+ event_dev ? event_dev->name : "None", event);
if (!(event_dev->priv_flags & IFF_BONDING))
return NOTIFY_DONE;
@@ -2939,7 +2986,7 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb,
fk->ports = 0;
noff = skb_network_offset(skb);
if (skb->protocol == htons(ETH_P_IP)) {
- if (!pskb_may_pull(skb, noff + sizeof(*iph)))
+ if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph))))
return false;
iph = ip_hdr(skb);
fk->src = iph->saddr;
@@ -2948,7 +2995,7 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb,
if (!ip_is_fragment(iph))
proto = iph->protocol;
} else if (skb->protocol == htons(ETH_P_IPV6)) {
- if (!pskb_may_pull(skb, noff + sizeof(*iph6)))
+ if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph6))))
return false;
iph6 = ipv6_hdr(skb);
fk->src = (__force __be32)ipv6_addr_hash(&iph6->saddr);
@@ -3032,9 +3079,11 @@ static int bond_open(struct net_device *bond_dev)
bond_for_each_slave(bond, slave, iter) {
if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
&& (slave != bond->curr_active_slave)) {
- bond_set_slave_inactive_flags(slave);
+ bond_set_slave_inactive_flags(slave,
+ BOND_SLAVE_NOTIFY_NOW);
} else {
- bond_set_slave_active_flags(slave);
+ bond_set_slave_active_flags(slave,
+ BOND_SLAVE_NOTIFY_NOW);
}
}
read_unlock(&bond->curr_slave_lock);
@@ -3057,8 +3106,7 @@ static int bond_open(struct net_device *bond_dev)
if (bond->params.arp_interval) { /* arp interval, in milliseconds. */
queue_delayed_work(bond->wq, &bond->arp_work, 0);
- if (bond->params.arp_validate)
- bond->recv_probe = bond_arp_rcv;
+ bond->recv_probe = bond_arp_rcv;
}
if (bond->params.mode == BOND_MODE_8023AD) {
@@ -3345,8 +3393,8 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
struct list_head *iter;
int res = 0;
- pr_debug("bond=%p, name=%s, new_mtu=%d\n", bond,
- (bond_dev ? bond_dev->name : "None"), new_mtu);
+ pr_debug("bond=%p, name=%s, new_mtu=%d\n",
+ bond, bond_dev ? bond_dev->name : "None", new_mtu);
/* Can't hold bond->lock with bh disabled here since
* some base drivers panic. On the other hand we can't
@@ -3365,8 +3413,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
bond_for_each_slave(bond, slave, iter) {
pr_debug("s %p c_m %p\n",
- slave,
- slave->dev->netdev_ops->ndo_change_mtu);
+ slave, slave->dev->netdev_ops->ndo_change_mtu);
res = dev_set_mtu(slave->dev, new_mtu);
@@ -3431,7 +3478,8 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
/* If fail_over_mac is enabled, do nothing and return success.
* Returning an error causes ifenslave to fail.
*/
- if (bond->params.fail_over_mac)
+ if (bond->params.fail_over_mac &&
+ bond->params.mode == BOND_MODE_ACTIVEBACKUP)
return 0;
if (!is_valid_ether_addr(sa->sa_data))
@@ -3453,15 +3501,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
*/
bond_for_each_slave(bond, slave, iter) {
- const struct net_device_ops *slave_ops = slave->dev->netdev_ops;
pr_debug("slave %p %s\n", slave, slave->dev->name);
-
- if (slave_ops->ndo_set_mac_address == NULL) {
- res = -EOPNOTSUPP;
- pr_debug("EOPNOTSUPP %s\n", slave->dev->name);
- goto unwind;
- }
-
res = dev_set_mac_address(slave->dev, addr);
if (res) {
/* TODO: consider downing the slave
@@ -3537,7 +3577,7 @@ static void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int sl
}
}
/* no slave that can tx has been found */
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
/**
@@ -3613,7 +3653,7 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d
if (slave)
bond_dev_queue_xmit(bond, skb, slave->dev);
else
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -3645,8 +3685,8 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
if (!skb2) {
- pr_err("%s: Error: bond_xmit_broadcast(): skb_clone() failed\n",
- bond_dev->name);
+ net_err_ratelimited("%s: Error: %s: skb_clone() failed\n",
+ bond_dev->name, __func__);
continue;
}
/* bond_dev_queue_xmit always returns 0 */
@@ -3656,7 +3696,7 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
if (slave && IS_UP(slave->dev) && slave->link == BOND_LINK_UP)
bond_dev_queue_xmit(bond, skb, slave->dev);
else
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -3692,7 +3732,7 @@ static inline int bond_slave_override(struct bonding *bond,
static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv, select_queue_fallback_t fallback)
{
/*
* This helper function exists to help dev_pick_tx get the correct
@@ -3743,7 +3783,7 @@ static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev
pr_err("%s: Error: Unknown bonding mode %d\n",
dev->name, bond->params.mode);
WARN_ON_ONCE(1);
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
}
@@ -3757,14 +3797,14 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
* If we risk deadlock from transmitting this in the
* netpoll path, tell netpoll to queue the frame for later tx
*/
- if (is_netpoll_tx_blocked(dev))
+ if (unlikely(is_netpoll_tx_blocked(dev)))
return NETDEV_TX_BUSY;
rcu_read_lock();
if (bond_has_slaves(bond))
ret = __bond_start_xmit(skb, dev);
else
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
rcu_read_unlock();
return ret;
@@ -3927,7 +3967,7 @@ static void bond_uninit(struct net_device *bond_dev)
/* Release the bonded slaves */
bond_for_each_slave(bond, slave, iter)
__bond_release_one(bond_dev, slave->dev, true);
- pr_info("%s: released all slaves\n", bond_dev->name);
+ pr_info("%s: Released all slaves\n", bond_dev->name);
list_del(&bond->bond_list);
@@ -3936,56 +3976,11 @@ static void bond_uninit(struct net_device *bond_dev)
/*------------------------- Module initialization ---------------------------*/
-int bond_parm_tbl_lookup(int mode, const struct bond_parm_tbl *tbl)
-{
- int i;
-
- for (i = 0; tbl[i].modename; i++)
- if (mode == tbl[i].mode)
- return tbl[i].mode;
-
- return -1;
-}
-
-static int bond_parm_tbl_lookup_name(const char *modename,
- const struct bond_parm_tbl *tbl)
-{
- int i;
-
- for (i = 0; tbl[i].modename; i++)
- if (strcmp(modename, tbl[i].modename) == 0)
- return tbl[i].mode;
-
- return -1;
-}
-
-/*
- * Convert string input module parms. Accept either the
- * number of the mode or its string name. A bit complicated because
- * some mode names are substrings of other names, and calls from sysfs
- * may have whitespace in the name (trailing newlines, for example).
- */
-int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl)
-{
- int modeint;
- char *p, modestr[BOND_MAX_MODENAME_LEN + 1];
-
- for (p = (char *)buf; *p; p++)
- if (!(isdigit(*p) || isspace(*p)))
- break;
-
- if (*p && sscanf(buf, "%20s", modestr) != 0)
- return bond_parm_tbl_lookup_name(modestr, tbl);
- else if (sscanf(buf, "%d", &modeint) != 0)
- return bond_parm_tbl_lookup(modeint, tbl);
-
- return -1;
-}
-
static int bond_check_params(struct bond_params *params)
{
int arp_validate_value, fail_over_mac_value, primary_reselect_value, i;
- struct bond_opt_value newval, *valptr;
+ struct bond_opt_value newval;
+ const struct bond_opt_value *valptr;
int arp_all_targets_value;
/*
@@ -4005,7 +4000,7 @@ static int bond_check_params(struct bond_params *params)
if ((bond_mode != BOND_MODE_XOR) &&
(bond_mode != BOND_MODE_8023AD)) {
pr_info("xmit_hash_policy param is irrelevant in mode %s\n",
- bond_mode_name(bond_mode));
+ bond_mode_name(bond_mode));
} else {
bond_opt_initstr(&newval, xmit_hash_policy);
valptr = bond_opt_parse(bond_opt_get(BOND_OPT_XMIT_HASH),
@@ -4046,74 +4041,71 @@ static int bond_check_params(struct bond_params *params)
}
params->ad_select = valptr->value;
if (bond_mode != BOND_MODE_8023AD)
- pr_warning("ad_select param only affects 802.3ad mode\n");
+ pr_warn("ad_select param only affects 802.3ad mode\n");
} else {
params->ad_select = BOND_AD_STABLE;
}
if (max_bonds < 0) {
- pr_warning("Warning: max_bonds (%d) not in range %d-%d, so it was reset to BOND_DEFAULT_MAX_BONDS (%d)\n",
- max_bonds, 0, INT_MAX, BOND_DEFAULT_MAX_BONDS);
+ pr_warn("Warning: max_bonds (%d) not in range %d-%d, so it was reset to BOND_DEFAULT_MAX_BONDS (%d)\n",
+ max_bonds, 0, INT_MAX, BOND_DEFAULT_MAX_BONDS);
max_bonds = BOND_DEFAULT_MAX_BONDS;
}
if (miimon < 0) {
- pr_warning("Warning: miimon module parameter (%d), not in range 0-%d, so it was reset to 0\n",
- miimon, INT_MAX);
+ pr_warn("Warning: miimon module parameter (%d), not in range 0-%d, so it was reset to 0\n",
+ miimon, INT_MAX);
miimon = 0;
}
if (updelay < 0) {
- pr_warning("Warning: updelay module parameter (%d), not in range 0-%d, so it was reset to 0\n",
- updelay, INT_MAX);
+ pr_warn("Warning: updelay module parameter (%d), not in range 0-%d, so it was reset to 0\n",
+ updelay, INT_MAX);
updelay = 0;
}
if (downdelay < 0) {
- pr_warning("Warning: downdelay module parameter (%d), not in range 0-%d, so it was reset to 0\n",
- downdelay, INT_MAX);
+ pr_warn("Warning: downdelay module parameter (%d), not in range 0-%d, so it was reset to 0\n",
+ downdelay, INT_MAX);
downdelay = 0;
}
if ((use_carrier != 0) && (use_carrier != 1)) {
- pr_warning("Warning: use_carrier module parameter (%d), not of valid value (0/1), so it was set to 1\n",
- use_carrier);
+ pr_warn("Warning: use_carrier module parameter (%d), not of valid value (0/1), so it was set to 1\n",
+ use_carrier);
use_carrier = 1;
}
if (num_peer_notif < 0 || num_peer_notif > 255) {
- pr_warning("Warning: num_grat_arp/num_unsol_na (%d) not in range 0-255 so it was reset to 1\n",
- num_peer_notif);
+ pr_warn("Warning: num_grat_arp/num_unsol_na (%d) not in range 0-255 so it was reset to 1\n",
+ num_peer_notif);
num_peer_notif = 1;
}
/* reset values for 802.3ad/TLB/ALB */
if (BOND_NO_USES_ARP(bond_mode)) {
if (!miimon) {
- pr_warning("Warning: miimon must be specified, otherwise bonding will not detect link failure, speed and duplex which are essential for 802.3ad operation\n");
- pr_warning("Forcing miimon to 100msec\n");
+ pr_warn("Warning: miimon must be specified, otherwise bonding will not detect link failure, speed and duplex which are essential for 802.3ad operation\n");
+ pr_warn("Forcing miimon to 100msec\n");
miimon = BOND_DEFAULT_MIIMON;
}
}
if (tx_queues < 1 || tx_queues > 255) {
- pr_warning("Warning: tx_queues (%d) should be between "
- "1 and 255, resetting to %d\n",
- tx_queues, BOND_DEFAULT_TX_QUEUES);
+ pr_warn("Warning: tx_queues (%d) should be between 1 and 255, resetting to %d\n",
+ tx_queues, BOND_DEFAULT_TX_QUEUES);
tx_queues = BOND_DEFAULT_TX_QUEUES;
}
if ((all_slaves_active != 0) && (all_slaves_active != 1)) {
- pr_warning("Warning: all_slaves_active module parameter (%d), "
- "not of valid value (0/1), so it was set to "
- "0\n", all_slaves_active);
+ pr_warn("Warning: all_slaves_active module parameter (%d), not of valid value (0/1), so it was set to 0\n",
+ all_slaves_active);
all_slaves_active = 0;
}
if (resend_igmp < 0 || resend_igmp > 255) {
- pr_warning("Warning: resend_igmp (%d) should be between "
- "0 and 255, resetting to %d\n",
- resend_igmp, BOND_DEFAULT_RESEND_IGMP);
+ pr_warn("Warning: resend_igmp (%d) should be between 0 and 255, resetting to %d\n",
+ resend_igmp, BOND_DEFAULT_RESEND_IGMP);
resend_igmp = BOND_DEFAULT_RESEND_IGMP;
}
@@ -4134,37 +4126,36 @@ static int bond_check_params(struct bond_params *params)
/* just warn the user the up/down delay will have
* no effect since miimon is zero...
*/
- pr_warning("Warning: miimon module parameter not set and updelay (%d) or downdelay (%d) module parameter is set; updelay and downdelay have no effect unless miimon is set\n",
- updelay, downdelay);
+ pr_warn("Warning: miimon module parameter not set and updelay (%d) or downdelay (%d) module parameter is set; updelay and downdelay have no effect unless miimon is set\n",
+ updelay, downdelay);
}
} else {
/* don't allow arp monitoring */
if (arp_interval) {
- pr_warning("Warning: miimon (%d) and arp_interval (%d) can't be used simultaneously, disabling ARP monitoring\n",
- miimon, arp_interval);
+ pr_warn("Warning: miimon (%d) and arp_interval (%d) can't be used simultaneously, disabling ARP monitoring\n",
+ miimon, arp_interval);
arp_interval = 0;
}
if ((updelay % miimon) != 0) {
- pr_warning("Warning: updelay (%d) is not a multiple of miimon (%d), updelay rounded to %d ms\n",
- updelay, miimon,
- (updelay / miimon) * miimon);
+ pr_warn("Warning: updelay (%d) is not a multiple of miimon (%d), updelay rounded to %d ms\n",
+ updelay, miimon, (updelay / miimon) * miimon);
}
updelay /= miimon;
if ((downdelay % miimon) != 0) {
- pr_warning("Warning: downdelay (%d) is not a multiple of miimon (%d), downdelay rounded to %d ms\n",
- downdelay, miimon,
- (downdelay / miimon) * miimon);
+ pr_warn("Warning: downdelay (%d) is not a multiple of miimon (%d), downdelay rounded to %d ms\n",
+ downdelay, miimon,
+ (downdelay / miimon) * miimon);
}
downdelay /= miimon;
}
if (arp_interval < 0) {
- pr_warning("Warning: arp_interval module parameter (%d) , not in range 0-%d, so it was reset to 0\n",
- arp_interval, INT_MAX);
+ pr_warn("Warning: arp_interval module parameter (%d), not in range 0-%d, so it was reset to 0\n",
+ arp_interval, INT_MAX);
arp_interval = 0;
}
@@ -4175,30 +4166,26 @@ static int bond_check_params(struct bond_params *params)
__be32 ip;
if (!in4_pton(arp_ip_target[i], -1, (u8 *)&ip, -1, NULL) ||
IS_IP_TARGET_UNUSABLE_ADDRESS(ip)) {
- pr_warning("Warning: bad arp_ip_target module parameter (%s), ARP monitoring will not be performed\n",
- arp_ip_target[i]);
+ pr_warn("Warning: bad arp_ip_target module parameter (%s), ARP monitoring will not be performed\n",
+ arp_ip_target[i]);
arp_interval = 0;
} else {
if (bond_get_targets_ip(arp_target, ip) == -1)
arp_target[arp_ip_count++] = ip;
else
- pr_warning("Warning: duplicate address %pI4 in arp_ip_target, skipping\n",
- &ip);
+ pr_warn("Warning: duplicate address %pI4 in arp_ip_target, skipping\n",
+ &ip);
}
}
if (arp_interval && !arp_ip_count) {
/* don't allow arping if no arp_ip_target given... */
- pr_warning("Warning: arp_interval module parameter (%d) specified without providing an arp_ip_target parameter, arp_interval was reset to 0\n",
- arp_interval);
+ pr_warn("Warning: arp_interval module parameter (%d) specified without providing an arp_ip_target parameter, arp_interval was reset to 0\n",
+ arp_interval);
arp_interval = 0;
}
if (arp_validate) {
- if (bond_mode != BOND_MODE_ACTIVEBACKUP) {
- pr_err("arp_validate only supported in active-backup mode\n");
- return -EINVAL;
- }
if (!arp_interval) {
pr_err("arp_validate requires arp_interval\n");
return -EINVAL;
@@ -4240,23 +4227,23 @@ static int bond_check_params(struct bond_params *params)
arp_interval, valptr->string, arp_ip_count);
for (i = 0; i < arp_ip_count; i++)
- pr_info(" %s", arp_ip_target[i]);
+ pr_cont(" %s", arp_ip_target[i]);
- pr_info("\n");
+ pr_cont("\n");
} else if (max_bonds) {
/* miimon and arp_interval not set, we need one so things
* work as expected, see bonding.txt for details
*/
- pr_debug("Warning: either miimon or arp_interval and arp_ip_target module parameters must be specified, otherwise bonding will not detect link failures! see bonding.txt for details.\n");
+ pr_debug("Warning: either miimon or arp_interval and arp_ip_target module parameters must be specified, otherwise bonding will not detect link failures! see bonding.txt for details\n");
}
if (primary && !USES_PRIMARY(bond_mode)) {
/* currently, using a primary only makes sense
* in active backup, TLB or ALB modes
*/
- pr_warning("Warning: %s primary device specified but has no effect in %s mode\n",
- primary, bond_mode_name(bond_mode));
+ pr_warn("Warning: %s primary device specified but has no effect in %s mode\n",
+ primary, bond_mode_name(bond_mode));
primary = NULL;
}
@@ -4285,14 +4272,14 @@ static int bond_check_params(struct bond_params *params)
}
fail_over_mac_value = valptr->value;
if (bond_mode != BOND_MODE_ACTIVEBACKUP)
- pr_warning("Warning: fail_over_mac only affects active-backup mode.\n");
+ pr_warn("Warning: fail_over_mac only affects active-backup mode\n");
} else {
fail_over_mac_value = BOND_FOM_NONE;
}
if (lp_interval == 0) {
- pr_warning("Warning: ip_interval must be between 1 and %d, so it was reset to %d\n",
- INT_MAX, BOND_ALB_DEFAULT_LP_INTERVAL);
+ pr_warn("Warning: ip_interval must be between 1 and %d, so it was reset to %d\n",
+ INT_MAX, BOND_ALB_DEFAULT_LP_INTERVAL);
lp_interval = BOND_ALB_DEFAULT_LP_INTERVAL;
}
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
index 70651f8e8e3b..f847e165d252 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -181,7 +181,7 @@ static int bond_changelink(struct net_device *bond_dev,
int arp_interval = nla_get_u32(data[IFLA_BOND_ARP_INTERVAL]);
if (arp_interval && miimon) {
- pr_err("%s: ARP monitoring cannot be used with MII monitoring.\n",
+ pr_err("%s: ARP monitoring cannot be used with MII monitoring\n",
bond->dev->name);
return -EINVAL;
}
@@ -199,7 +199,7 @@ static int bond_changelink(struct net_device *bond_dev,
nla_for_each_nested(attr, data[IFLA_BOND_ARP_IP_TARGET], rem) {
__be32 target = nla_get_be32(attr);
- bond_opt_initval(&newval, target);
+ bond_opt_initval(&newval, (__force u64)target);
err = __bond_opt_set(bond, BOND_OPT_ARP_TARGETS,
&newval);
if (err)
@@ -207,7 +207,7 @@ static int bond_changelink(struct net_device *bond_dev,
i++;
}
if (i == 0 && bond->params.arp_interval)
- pr_warn("%s: removing last arp target with arp_interval on\n",
+ pr_warn("%s: Removing last arp target with arp_interval on\n",
bond->dev->name);
if (err)
return err;
@@ -216,7 +216,7 @@ static int bond_changelink(struct net_device *bond_dev,
int arp_validate = nla_get_u32(data[IFLA_BOND_ARP_VALIDATE]);
if (arp_validate && miimon) {
- pr_err("%s: ARP validating cannot be used with MII monitoring.\n",
+ pr_err("%s: ARP validating cannot be used with MII monitoring\n",
bond->dev->name);
return -EINVAL;
}
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index 11cb943222d5..724e30fa20b9 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -14,13 +14,65 @@
#include <linux/errno.h>
#include <linux/if.h>
#include <linux/netdevice.h>
-#include <linux/rwlock.h>
+#include <linux/spinlock.h>
#include <linux/rcupdate.h>
#include <linux/ctype.h>
#include <linux/inet.h>
#include "bonding.h"
-static struct bond_opt_value bond_mode_tbl[] = {
+static int bond_option_active_slave_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_miimon_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_updelay_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_downdelay_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_use_carrier_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_arp_interval_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target);
+static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target);
+static int bond_option_arp_ip_targets_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_arp_validate_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_arp_all_targets_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_primary_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_primary_reselect_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_fail_over_mac_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_xmit_hash_policy_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_resend_igmp_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_num_peer_notif_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_all_slaves_active_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_min_links_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_lp_interval_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_pps_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_lacp_rate_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_ad_select_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_queue_id_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_mode_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_slaves_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+
+
+static const struct bond_opt_value bond_mode_tbl[] = {
{ "balance-rr", BOND_MODE_ROUNDROBIN, BOND_VALFLAG_DEFAULT},
{ "active-backup", BOND_MODE_ACTIVEBACKUP, 0},
{ "balance-xor", BOND_MODE_XOR, 0},
@@ -31,13 +83,13 @@ static struct bond_opt_value bond_mode_tbl[] = {
{ NULL, -1, 0},
};
-static struct bond_opt_value bond_pps_tbl[] = {
+static const struct bond_opt_value bond_pps_tbl[] = {
{ "default", 1, BOND_VALFLAG_DEFAULT},
{ "maxval", USHRT_MAX, BOND_VALFLAG_MAX},
{ NULL, -1, 0},
};
-static struct bond_opt_value bond_xmit_hashtype_tbl[] = {
+static const struct bond_opt_value bond_xmit_hashtype_tbl[] = {
{ "layer2", BOND_XMIT_POLICY_LAYER2, BOND_VALFLAG_DEFAULT},
{ "layer3+4", BOND_XMIT_POLICY_LAYER34, 0},
{ "layer2+3", BOND_XMIT_POLICY_LAYER23, 0},
@@ -46,84 +98,88 @@ static struct bond_opt_value bond_xmit_hashtype_tbl[] = {
{ NULL, -1, 0},
};
-static struct bond_opt_value bond_arp_validate_tbl[] = {
- { "none", BOND_ARP_VALIDATE_NONE, BOND_VALFLAG_DEFAULT},
- { "active", BOND_ARP_VALIDATE_ACTIVE, 0},
- { "backup", BOND_ARP_VALIDATE_BACKUP, 0},
- { "all", BOND_ARP_VALIDATE_ALL, 0},
- { NULL, -1, 0},
+static const struct bond_opt_value bond_arp_validate_tbl[] = {
+ { "none", BOND_ARP_VALIDATE_NONE, BOND_VALFLAG_DEFAULT},
+ { "active", BOND_ARP_VALIDATE_ACTIVE, 0},
+ { "backup", BOND_ARP_VALIDATE_BACKUP, 0},
+ { "all", BOND_ARP_VALIDATE_ALL, 0},
+ { "filter", BOND_ARP_FILTER, 0},
+ { "filter_active", BOND_ARP_FILTER_ACTIVE, 0},
+ { "filter_backup", BOND_ARP_FILTER_BACKUP, 0},
+ { NULL, -1, 0},
};
-static struct bond_opt_value bond_arp_all_targets_tbl[] = {
+static const struct bond_opt_value bond_arp_all_targets_tbl[] = {
{ "any", BOND_ARP_TARGETS_ANY, BOND_VALFLAG_DEFAULT},
{ "all", BOND_ARP_TARGETS_ALL, 0},
{ NULL, -1, 0},
};
-static struct bond_opt_value bond_fail_over_mac_tbl[] = {
+static const struct bond_opt_value bond_fail_over_mac_tbl[] = {
{ "none", BOND_FOM_NONE, BOND_VALFLAG_DEFAULT},
{ "active", BOND_FOM_ACTIVE, 0},
{ "follow", BOND_FOM_FOLLOW, 0},
{ NULL, -1, 0},
};
-static struct bond_opt_value bond_intmax_tbl[] = {
+static const struct bond_opt_value bond_intmax_tbl[] = {
{ "off", 0, BOND_VALFLAG_DEFAULT},
{ "maxval", INT_MAX, BOND_VALFLAG_MAX},
};
-static struct bond_opt_value bond_lacp_rate_tbl[] = {
+static const struct bond_opt_value bond_lacp_rate_tbl[] = {
{ "slow", AD_LACP_SLOW, 0},
{ "fast", AD_LACP_FAST, 0},
{ NULL, -1, 0},
};
-static struct bond_opt_value bond_ad_select_tbl[] = {
+static const struct bond_opt_value bond_ad_select_tbl[] = {
{ "stable", BOND_AD_STABLE, BOND_VALFLAG_DEFAULT},
{ "bandwidth", BOND_AD_BANDWIDTH, 0},
{ "count", BOND_AD_COUNT, 0},
{ NULL, -1, 0},
};
-static struct bond_opt_value bond_num_peer_notif_tbl[] = {
+static const struct bond_opt_value bond_num_peer_notif_tbl[] = {
{ "off", 0, 0},
{ "maxval", 255, BOND_VALFLAG_MAX},
{ "default", 1, BOND_VALFLAG_DEFAULT},
{ NULL, -1, 0}
};
-static struct bond_opt_value bond_primary_reselect_tbl[] = {
+static const struct bond_opt_value bond_primary_reselect_tbl[] = {
{ "always", BOND_PRI_RESELECT_ALWAYS, BOND_VALFLAG_DEFAULT},
{ "better", BOND_PRI_RESELECT_BETTER, 0},
{ "failure", BOND_PRI_RESELECT_FAILURE, 0},
{ NULL, -1},
};
-static struct bond_opt_value bond_use_carrier_tbl[] = {
+static const struct bond_opt_value bond_use_carrier_tbl[] = {
{ "off", 0, 0},
{ "on", 1, BOND_VALFLAG_DEFAULT},
{ NULL, -1, 0}
};
-static struct bond_opt_value bond_all_slaves_active_tbl[] = {
+static const struct bond_opt_value bond_all_slaves_active_tbl[] = {
{ "off", 0, BOND_VALFLAG_DEFAULT},
{ "on", 1, 0},
{ NULL, -1, 0}
};
-static struct bond_opt_value bond_resend_igmp_tbl[] = {
+static const struct bond_opt_value bond_resend_igmp_tbl[] = {
{ "off", 0, 0},
{ "maxval", 255, BOND_VALFLAG_MAX},
{ "default", 1, BOND_VALFLAG_DEFAULT},
{ NULL, -1, 0}
};
-static struct bond_opt_value bond_lp_interval_tbl[] = {
+static const struct bond_opt_value bond_lp_interval_tbl[] = {
{ "minval", 1, BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT},
{ "maxval", INT_MAX, BOND_VALFLAG_MAX},
+ { NULL, -1, 0},
};
-static struct bond_option bond_opts[] = {
+static const struct bond_option bond_opts[] = {
[BOND_OPT_MODE] = {
.id = BOND_OPT_MODE,
.name = "mode",
@@ -151,7 +207,8 @@ static struct bond_option bond_opts[] = {
.id = BOND_OPT_ARP_VALIDATE,
.name = "arp_validate",
.desc = "validate src/dst of ARP probes",
- .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ACTIVEBACKUP)),
+ .unsuppmodes = BIT(BOND_MODE_8023AD) | BIT(BOND_MODE_TLB) |
+ BIT(BOND_MODE_ALB),
.values = bond_arp_validate_tbl,
.set = bond_option_arp_validate_set
},
@@ -311,9 +368,9 @@ static struct bond_option bond_opts[] = {
};
/* Searches for a value in opt's values[] table */
-struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val)
+const struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val)
{
- struct bond_option *opt;
+ const struct bond_option *opt;
int i;
opt = bond_opt_get(option);
@@ -327,7 +384,7 @@ struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val)
}
/* Searches for a value in opt's values[] table which matches the flagmask */
-static struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt,
+static const struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt,
u32 flagmask)
{
int i;
@@ -344,7 +401,7 @@ static struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt,
*/
static bool bond_opt_check_range(const struct bond_option *opt, u64 val)
{
- struct bond_opt_value *minval, *maxval;
+ const struct bond_opt_value *minval, *maxval;
minval = bond_opt_get_flags(opt, BOND_VALFLAG_MIN);
maxval = bond_opt_get_flags(opt, BOND_VALFLAG_MAX);
@@ -364,11 +421,12 @@ static bool bond_opt_check_range(const struct bond_option *opt, u64 val)
* or the struct_opt_value that matched. It also strips the new line from
* @val->string if it's present.
*/
-struct bond_opt_value *bond_opt_parse(const struct bond_option *opt,
- struct bond_opt_value *val)
+const struct bond_opt_value *bond_opt_parse(const struct bond_option *opt,
+ struct bond_opt_value *val)
{
char *p, valstr[BOND_OPT_MAX_NAMELEN + 1] = { 0, };
- struct bond_opt_value *tbl, *ret = NULL;
+ const struct bond_opt_value *tbl;
+ const struct bond_opt_value *ret = NULL;
bool checkval;
int i, rv;
@@ -447,7 +505,7 @@ static int bond_opt_check_deps(struct bonding *bond,
static void bond_opt_dep_print(struct bonding *bond,
const struct bond_option *opt)
{
- struct bond_opt_value *modeval;
+ const struct bond_opt_value *modeval;
struct bond_params *params;
params = &bond->params;
@@ -460,9 +518,9 @@ static void bond_opt_dep_print(struct bonding *bond,
static void bond_opt_error_interpret(struct bonding *bond,
const struct bond_option *opt,
- int error, struct bond_opt_value *val)
+ int error, const struct bond_opt_value *val)
{
- struct bond_opt_value *minval, *maxval;
+ const struct bond_opt_value *minval, *maxval;
char *p;
switch (error) {
@@ -473,10 +531,10 @@ static void bond_opt_error_interpret(struct bonding *bond,
p = strchr(val->string, '\n');
if (p)
*p = '\0';
- pr_err("%s: option %s: invalid value (%s).\n",
+ pr_err("%s: option %s: invalid value (%s)\n",
bond->dev->name, opt->name, val->string);
} else {
- pr_err("%s: option %s: invalid value (%llu).\n",
+ pr_err("%s: option %s: invalid value (%llu)\n",
bond->dev->name, opt->name, val->value);
}
}
@@ -484,7 +542,7 @@ static void bond_opt_error_interpret(struct bonding *bond,
maxval = bond_opt_get_flags(opt, BOND_VALFLAG_MAX);
if (!maxval)
break;
- pr_err("%s: option %s: allowed values %llu - %llu.\n",
+ pr_err("%s: option %s: allowed values %llu - %llu\n",
bond->dev->name, opt->name, minval ? minval->value : 0,
maxval->value);
break;
@@ -492,11 +550,11 @@ static void bond_opt_error_interpret(struct bonding *bond,
bond_opt_dep_print(bond, opt);
break;
case -ENOTEMPTY:
- pr_err("%s: option %s: unable to set because the bond device has slaves.\n",
+ pr_err("%s: option %s: unable to set because the bond device has slaves\n",
bond->dev->name, opt->name);
break;
case -EBUSY:
- pr_err("%s: option %s: unable to set because the bond device is up.\n",
+ pr_err("%s: option %s: unable to set because the bond device is up\n",
bond->dev->name, opt->name);
break;
default:
@@ -517,7 +575,7 @@ static void bond_opt_error_interpret(struct bonding *bond,
int __bond_opt_set(struct bonding *bond,
unsigned int option, struct bond_opt_value *val)
{
- struct bond_opt_value *retval = NULL;
+ const struct bond_opt_value *retval = NULL;
const struct bond_option *opt;
int ret = -ENOENT;
@@ -572,7 +630,7 @@ int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf)
* This function checks if option is valid and if so returns a pointer
* to its entry in the bond_opts[] option array.
*/
-struct bond_option *bond_opt_get(unsigned int option)
+const struct bond_option *bond_opt_get(unsigned int option)
{
if (!BOND_OPT_VALID(option))
return NULL;
@@ -580,7 +638,7 @@ struct bond_option *bond_opt_get(unsigned int option)
return &bond_opts[option];
}
-int bond_option_mode_set(struct bonding *bond, struct bond_opt_value *newval)
+int bond_option_mode_set(struct bonding *bond, const struct bond_opt_value *newval)
{
if (BOND_NO_USES_ARP(newval->value) && bond->params.arp_interval) {
pr_info("%s: %s mode is incompatible with arp monitoring, start mii monitoring\n",
@@ -589,7 +647,7 @@ int bond_option_mode_set(struct bonding *bond, struct bond_opt_value *newval)
bond->params.arp_interval = 0;
/* set miimon to default value */
bond->params.miimon = BOND_DEFAULT_MIIMON;
- pr_info("%s: Setting MII monitoring interval to %d.\n",
+ pr_info("%s: Setting MII monitoring interval to %d\n",
bond->dev->name, bond->params.miimon);
}
@@ -618,8 +676,8 @@ struct net_device *bond_option_active_slave_get(struct bonding *bond)
return __bond_option_active_slave_get(bond, bond->curr_active_slave);
}
-int bond_option_active_slave_set(struct bonding *bond,
- struct bond_opt_value *newval)
+static int bond_option_active_slave_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
char ifname[IFNAMSIZ] = { 0, };
struct net_device *slave_dev;
@@ -636,13 +694,13 @@ int bond_option_active_slave_set(struct bonding *bond,
if (slave_dev) {
if (!netif_is_bond_slave(slave_dev)) {
- pr_err("Device %s is not bonding slave.\n",
+ pr_err("Device %s is not bonding slave\n",
slave_dev->name);
return -EINVAL;
}
if (bond->dev != netdev_master_upper_dev_get(slave_dev)) {
- pr_err("%s: Device %s is not our slave.\n",
+ pr_err("%s: Device %s is not our slave\n",
bond->dev->name, slave_dev->name);
return -EINVAL;
}
@@ -653,9 +711,8 @@ int bond_option_active_slave_set(struct bonding *bond,
/* check to see if we are clearing active */
if (!slave_dev) {
- pr_info("%s: Clearing current active slave.\n",
- bond->dev->name);
- rcu_assign_pointer(bond->curr_active_slave, NULL);
+ pr_info("%s: Clearing current active slave\n", bond->dev->name);
+ RCU_INIT_POINTER(bond->curr_active_slave, NULL);
bond_select_active_slave(bond);
} else {
struct slave *old_active = bond->curr_active_slave;
@@ -665,16 +722,16 @@ int bond_option_active_slave_set(struct bonding *bond,
if (new_active == old_active) {
/* do nothing */
- pr_info("%s: %s is already the current active slave.\n",
+ pr_info("%s: %s is already the current active slave\n",
bond->dev->name, new_active->dev->name);
} else {
if (old_active && (new_active->link == BOND_LINK_UP) &&
IS_UP(new_active->dev)) {
- pr_info("%s: Setting %s as active slave.\n",
+ pr_info("%s: Setting %s as active slave\n",
bond->dev->name, new_active->dev->name);
bond_change_active_slave(bond, new_active);
} else {
- pr_err("%s: Could not set %s as active slave; either %s is down or the link is down.\n",
+ pr_err("%s: Could not set %s as active slave; either %s is down or the link is down\n",
bond->dev->name, new_active->dev->name,
new_active->dev->name);
ret = -EINVAL;
@@ -688,21 +745,22 @@ int bond_option_active_slave_set(struct bonding *bond,
return ret;
}
-int bond_option_miimon_set(struct bonding *bond, struct bond_opt_value *newval)
+static int bond_option_miimon_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
- pr_info("%s: Setting MII monitoring interval to %llu.\n",
+ pr_info("%s: Setting MII monitoring interval to %llu\n",
bond->dev->name, newval->value);
bond->params.miimon = newval->value;
if (bond->params.updelay)
- pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value.\n",
+ pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value\n",
bond->dev->name,
bond->params.updelay * bond->params.miimon);
if (bond->params.downdelay)
- pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value.\n",
+ pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value\n",
bond->dev->name,
bond->params.downdelay * bond->params.miimon);
if (newval->value && bond->params.arp_interval) {
- pr_info("%s: MII monitoring cannot be used with ARP monitoring. Disabling ARP monitoring...\n",
+ pr_info("%s: MII monitoring cannot be used with ARP monitoring - disabling ARP monitoring...\n",
bond->dev->name);
bond->params.arp_interval = 0;
if (bond->params.arp_validate)
@@ -725,7 +783,8 @@ int bond_option_miimon_set(struct bonding *bond, struct bond_opt_value *newval)
return 0;
}
-int bond_option_updelay_set(struct bonding *bond, struct bond_opt_value *newval)
+static int bond_option_updelay_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
int value = newval->value;
@@ -742,15 +801,14 @@ int bond_option_updelay_set(struct bonding *bond, struct bond_opt_value *newval)
bond->params.miimon);
}
bond->params.updelay = value / bond->params.miimon;
- pr_info("%s: Setting up delay to %d.\n",
- bond->dev->name,
- bond->params.updelay * bond->params.miimon);
+ pr_info("%s: Setting up delay to %d\n",
+ bond->dev->name, bond->params.updelay * bond->params.miimon);
return 0;
}
-int bond_option_downdelay_set(struct bonding *bond,
- struct bond_opt_value *newval)
+static int bond_option_downdelay_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
int value = newval->value;
@@ -767,37 +825,36 @@ int bond_option_downdelay_set(struct bonding *bond,
bond->params.miimon);
}
bond->params.downdelay = value / bond->params.miimon;
- pr_info("%s: Setting down delay to %d.\n",
- bond->dev->name,
- bond->params.downdelay * bond->params.miimon);
+ pr_info("%s: Setting down delay to %d\n",
+ bond->dev->name, bond->params.downdelay * bond->params.miimon);
return 0;
}
-int bond_option_use_carrier_set(struct bonding *bond,
- struct bond_opt_value *newval)
+static int bond_option_use_carrier_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
- pr_info("%s: Setting use_carrier to %llu.\n",
+ pr_info("%s: Setting use_carrier to %llu\n",
bond->dev->name, newval->value);
bond->params.use_carrier = newval->value;
return 0;
}
-int bond_option_arp_interval_set(struct bonding *bond,
- struct bond_opt_value *newval)
+static int bond_option_arp_interval_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
- pr_info("%s: Setting ARP monitoring interval to %llu.\n",
+ pr_info("%s: Setting ARP monitoring interval to %llu\n",
bond->dev->name, newval->value);
bond->params.arp_interval = newval->value;
if (newval->value) {
if (bond->params.miimon) {
- pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring.\n",
+ pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring\n",
bond->dev->name, bond->dev->name);
bond->params.miimon = 0;
}
if (!bond->params.arp_targets[0])
- pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified.\n",
+ pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified\n",
bond->dev->name);
}
if (bond->dev->flags & IFF_UP) {
@@ -812,8 +869,7 @@ int bond_option_arp_interval_set(struct bonding *bond,
cancel_delayed_work_sync(&bond->arp_work);
} else {
/* arp_validate can be set only in active-backup mode */
- if (bond->params.arp_validate)
- bond->recv_probe = bond_arp_rcv;
+ bond->recv_probe = bond_arp_rcv;
cancel_delayed_work_sync(&bond->mii_work);
queue_delayed_work(bond->wq, &bond->arp_work, 0);
}
@@ -856,19 +912,18 @@ static int _bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
ind = bond_get_targets_ip(targets, 0); /* first free slot */
if (ind == -1) {
- pr_err("%s: ARP target table is full!\n",
- bond->dev->name);
+ pr_err("%s: ARP target table is full!\n", bond->dev->name);
return -EINVAL;
}
- pr_info("%s: adding ARP target %pI4.\n", bond->dev->name, &target);
+ pr_info("%s: Adding ARP target %pI4\n", bond->dev->name, &target);
_bond_options_arp_ip_target_set(bond, ind, target, jiffies);
return 0;
}
-int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
+static int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
{
int ret;
@@ -880,7 +935,7 @@ int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
return ret;
}
-int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
+static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
{
__be32 *targets = bond->params.arp_targets;
struct list_head *iter;
@@ -896,17 +951,16 @@ int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
ind = bond_get_targets_ip(targets, target);
if (ind == -1) {
- pr_err("%s: unable to remove nonexistent ARP target %pI4.\n",
+ pr_err("%s: unable to remove nonexistent ARP target %pI4\n",
bond->dev->name, &target);
return -EINVAL;
}
if (ind == 0 && !targets[1] && bond->params.arp_interval)
- pr_warn("%s: removing last arp target with arp_interval on\n",
+ pr_warn("%s: Removing last arp target with arp_interval on\n",
bond->dev->name);
- pr_info("%s: removing ARP target %pI4.\n", bond->dev->name,
- &target);
+ pr_info("%s: Removing ARP target %pI4\n", bond->dev->name, &target);
/* not to race with bond_arp_rcv */
write_lock_bh(&bond->lock);
@@ -937,8 +991,8 @@ void bond_option_arp_ip_targets_clear(struct bonding *bond)
write_unlock_bh(&bond->lock);
}
-int bond_option_arp_ip_targets_set(struct bonding *bond,
- struct bond_opt_value *newval)
+static int bond_option_arp_ip_targets_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
int ret = -EPERM;
__be32 target;
@@ -954,7 +1008,7 @@ int bond_option_arp_ip_targets_set(struct bonding *bond,
else if (newval->string[0] == '-')
ret = bond_option_arp_ip_target_rem(bond, target);
else
- pr_err("no command found in arp_ip_targets file for bond %s. Use +<addr> or -<addr>.\n",
+ pr_err("no command found in arp_ip_targets file for bond %s - use +<addr> or -<addr>\n",
bond->dev->name);
} else {
target = newval->value;
@@ -964,10 +1018,10 @@ int bond_option_arp_ip_targets_set(struct bonding *bond,
return ret;
}
-int bond_option_arp_validate_set(struct bonding *bond,
- struct bond_opt_value *newval)
+static int bond_option_arp_validate_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
- pr_info("%s: setting arp_validate to %s (%llu).\n",
+ pr_info("%s: Setting arp_validate to %s (%llu)\n",
bond->dev->name, newval->string, newval->value);
if (bond->dev->flags & IFF_UP) {
@@ -981,17 +1035,18 @@ int bond_option_arp_validate_set(struct bonding *bond,
return 0;
}
-int bond_option_arp_all_targets_set(struct bonding *bond,
- struct bond_opt_value *newval)
+static int bond_option_arp_all_targets_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
- pr_info("%s: setting arp_all_targets to %s (%llu).\n",
+ pr_info("%s: Setting arp_all_targets to %s (%llu)\n",
bond->dev->name, newval->string, newval->value);
bond->params.arp_all_targets = newval->value;
return 0;
}
-int bond_option_primary_set(struct bonding *bond, struct bond_opt_value *newval)
+static int bond_option_primary_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
char *p, *primary = newval->string;
struct list_head *iter;
@@ -1006,8 +1061,7 @@ int bond_option_primary_set(struct bonding *bond, struct bond_opt_value *newval)
*p = '\0';
/* check to see if we are clearing primary */
if (!strlen(primary)) {
- pr_info("%s: Setting primary slave to None.\n",
- bond->dev->name);
+ pr_info("%s: Setting primary slave to None\n", bond->dev->name);
bond->primary_slave = NULL;
memset(bond->params.primary, 0, sizeof(bond->params.primary));
bond_select_active_slave(bond);
@@ -1016,7 +1070,7 @@ int bond_option_primary_set(struct bonding *bond, struct bond_opt_value *newval)
bond_for_each_slave(bond, slave, iter) {
if (strncmp(slave->dev->name, primary, IFNAMSIZ) == 0) {
- pr_info("%s: Setting %s as primary slave.\n",
+ pr_info("%s: Setting %s as primary slave\n",
bond->dev->name, slave->dev->name);
bond->primary_slave = slave;
strcpy(bond->params.primary, slave->dev->name);
@@ -1026,15 +1080,14 @@ int bond_option_primary_set(struct bonding *bond, struct bond_opt_value *newval)
}
if (bond->primary_slave) {
- pr_info("%s: Setting primary slave to None.\n",
- bond->dev->name);
+ pr_info("%s: Setting primary slave to None\n", bond->dev->name);
bond->primary_slave = NULL;
bond_select_active_slave(bond);
}
strncpy(bond->params.primary, primary, IFNAMSIZ);
bond->params.primary[IFNAMSIZ - 1] = 0;
- pr_info("%s: Recording %s as primary, but it has not been enslaved to %s yet.\n",
+ pr_info("%s: Recording %s as primary, but it has not been enslaved to %s yet\n",
bond->dev->name, primary, bond->dev->name);
out:
@@ -1045,10 +1098,10 @@ out:
return 0;
}
-int bond_option_primary_reselect_set(struct bonding *bond,
- struct bond_opt_value *newval)
+static int bond_option_primary_reselect_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
- pr_info("%s: setting primary_reselect to %s (%llu).\n",
+ pr_info("%s: Setting primary_reselect to %s (%llu)\n",
bond->dev->name, newval->string, newval->value);
bond->params.primary_reselect = newval->value;
@@ -1061,46 +1114,46 @@ int bond_option_primary_reselect_set(struct bonding *bond,
return 0;
}
-int bond_option_fail_over_mac_set(struct bonding *bond,
- struct bond_opt_value *newval)
+static int bond_option_fail_over_mac_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
- pr_info("%s: Setting fail_over_mac to %s (%llu).\n",
+ pr_info("%s: Setting fail_over_mac to %s (%llu)\n",
bond->dev->name, newval->string, newval->value);
bond->params.fail_over_mac = newval->value;
return 0;
}
-int bond_option_xmit_hash_policy_set(struct bonding *bond,
- struct bond_opt_value *newval)
+static int bond_option_xmit_hash_policy_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
- pr_info("%s: setting xmit hash policy to %s (%llu).\n",
+ pr_info("%s: Setting xmit hash policy to %s (%llu)\n",
bond->dev->name, newval->string, newval->value);
bond->params.xmit_policy = newval->value;
return 0;
}
-int bond_option_resend_igmp_set(struct bonding *bond,
- struct bond_opt_value *newval)
+static int bond_option_resend_igmp_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
- pr_info("%s: Setting resend_igmp to %llu.\n",
+ pr_info("%s: Setting resend_igmp to %llu\n",
bond->dev->name, newval->value);
bond->params.resend_igmp = newval->value;
return 0;
}
-int bond_option_num_peer_notif_set(struct bonding *bond,
- struct bond_opt_value *newval)
+static int bond_option_num_peer_notif_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
bond->params.num_peer_notif = newval->value;
return 0;
}
-int bond_option_all_slaves_active_set(struct bonding *bond,
- struct bond_opt_value *newval)
+static int bond_option_all_slaves_active_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
struct list_head *iter;
struct slave *slave;
@@ -1120,8 +1173,8 @@ int bond_option_all_slaves_active_set(struct bonding *bond,
return 0;
}
-int bond_option_min_links_set(struct bonding *bond,
- struct bond_opt_value *newval)
+static int bond_option_min_links_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
pr_info("%s: Setting min links value to %llu\n",
bond->dev->name, newval->value);
@@ -1130,15 +1183,16 @@ int bond_option_min_links_set(struct bonding *bond,
return 0;
}
-int bond_option_lp_interval_set(struct bonding *bond,
- struct bond_opt_value *newval)
+static int bond_option_lp_interval_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
bond->params.lp_interval = newval->value;
return 0;
}
-int bond_option_pps_set(struct bonding *bond, struct bond_opt_value *newval)
+static int bond_option_pps_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
bond->params.packets_per_slave = newval->value;
if (newval->value > 0) {
@@ -1155,10 +1209,10 @@ int bond_option_pps_set(struct bonding *bond, struct bond_opt_value *newval)
return 0;
}
-int bond_option_lacp_rate_set(struct bonding *bond,
- struct bond_opt_value *newval)
+static int bond_option_lacp_rate_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
- pr_info("%s: Setting LACP rate to %s (%llu).\n",
+ pr_info("%s: Setting LACP rate to %s (%llu)\n",
bond->dev->name, newval->string, newval->value);
bond->params.lacp_fast = newval->value;
bond_3ad_update_lacp_rate(bond);
@@ -1166,18 +1220,18 @@ int bond_option_lacp_rate_set(struct bonding *bond,
return 0;
}
-int bond_option_ad_select_set(struct bonding *bond,
- struct bond_opt_value *newval)
+static int bond_option_ad_select_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
- pr_info("%s: Setting ad_select to %s (%llu).\n",
+ pr_info("%s: Setting ad_select to %s (%llu)\n",
bond->dev->name, newval->string, newval->value);
bond->params.ad_select = newval->value;
return 0;
}
-int bond_option_queue_id_set(struct bonding *bond,
- struct bond_opt_value *newval)
+static int bond_option_queue_id_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
struct slave *slave, *update_slave;
struct net_device *sdev;
@@ -1199,8 +1253,7 @@ int bond_option_queue_id_set(struct bonding *bond,
goto err_no_cmd;
/* Check buffer length, valid ifname and queue id */
- if (strlen(newval->string) > IFNAMSIZ ||
- !dev_valid_name(newval->string) ||
+ if (!dev_valid_name(newval->string) ||
qid > bond->dev->real_num_tx_queues)
goto err_no_cmd;
@@ -1232,14 +1285,14 @@ out:
return ret;
err_no_cmd:
- pr_info("invalid input for queue_id set for %s.\n",
- bond->dev->name);
+ pr_info("invalid input for queue_id set for %s\n", bond->dev->name);
ret = -EPERM;
goto out;
}
-int bond_option_slaves_set(struct bonding *bond, struct bond_opt_value *newval)
+static int bond_option_slaves_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
{
char command[IFNAMSIZ + 1] = { 0, };
struct net_device *dev;
@@ -1254,7 +1307,7 @@ int bond_option_slaves_set(struct bonding *bond, struct bond_opt_value *newval)
dev = __dev_get_by_name(dev_net(bond->dev), ifname);
if (!dev) {
- pr_info("%s: Interface %s does not exist!\n",
+ pr_info("%s: interface %s does not exist!\n",
bond->dev->name, ifname);
ret = -ENODEV;
goto out;
@@ -1262,12 +1315,12 @@ int bond_option_slaves_set(struct bonding *bond, struct bond_opt_value *newval)
switch (command[0]) {
case '+':
- pr_info("%s: Adding slave %s.\n", bond->dev->name, dev->name);
+ pr_info("%s: Adding slave %s\n", bond->dev->name, dev->name);
ret = bond_enslave(bond->dev, dev);
break;
case '-':
- pr_info("%s: Removing slave %s.\n", bond->dev->name, dev->name);
+ pr_info("%s: Removing slave %s\n", bond->dev->name, dev->name);
ret = bond_release(bond->dev, dev);
break;
@@ -1279,7 +1332,7 @@ out:
return ret;
err_no_cmd:
- pr_err("no command found in slaves file for bond %s. Use +ifname or -ifname.\n",
+ pr_err("no command found in slaves file for bond %s - use +ifname or -ifname\n",
bond->dev->name);
ret = -EPERM;
goto out;
diff --git a/drivers/net/bonding/bond_options.h b/drivers/net/bonding/bond_options.h
index 433d37f6940b..12be9e1bfb0c 100644
--- a/drivers/net/bonding/bond_options.h
+++ b/drivers/net/bonding/bond_options.h
@@ -81,8 +81,8 @@ struct bonding;
struct bond_option {
int id;
- char *name;
- char *desc;
+ const char *name;
+ const char *desc;
u32 flags;
/* unsuppmodes is used to denote modes in which the option isn't
@@ -92,18 +92,19 @@ struct bond_option {
/* supported values which this option can have, can be a subset of
* BOND_OPTVAL_RANGE's value range
*/
- struct bond_opt_value *values;
+ const struct bond_opt_value *values;
- int (*set)(struct bonding *bond, struct bond_opt_value *val);
+ int (*set)(struct bonding *bond, const struct bond_opt_value *val);
};
int __bond_opt_set(struct bonding *bond, unsigned int option,
struct bond_opt_value *val);
int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf);
-struct bond_opt_value *bond_opt_parse(const struct bond_option *opt,
- struct bond_opt_value *val);
-struct bond_option *bond_opt_get(unsigned int option);
-struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val);
+
+const struct bond_opt_value *bond_opt_parse(const struct bond_option *opt,
+ struct bond_opt_value *val);
+const struct bond_option *bond_opt_get(unsigned int option);
+const struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val);
/* This helper is used to initialize a bond_opt_value structure for parameter
* passing. There should be either a valid string or value, but not both.
@@ -122,49 +123,6 @@ static inline void __bond_opt_init(struct bond_opt_value *optval,
#define bond_opt_initval(optval, value) __bond_opt_init(optval, NULL, value)
#define bond_opt_initstr(optval, str) __bond_opt_init(optval, str, ULLONG_MAX)
-int bond_option_mode_set(struct bonding *bond, struct bond_opt_value *newval);
-int bond_option_pps_set(struct bonding *bond, struct bond_opt_value *newval);
-int bond_option_xmit_hash_policy_set(struct bonding *bond,
- struct bond_opt_value *newval);
-int bond_option_arp_validate_set(struct bonding *bond,
- struct bond_opt_value *newval);
-int bond_option_arp_all_targets_set(struct bonding *bond,
- struct bond_opt_value *newval);
-int bond_option_fail_over_mac_set(struct bonding *bond,
- struct bond_opt_value *newval);
-int bond_option_arp_interval_set(struct bonding *bond,
- struct bond_opt_value *newval);
-int bond_option_arp_ip_targets_set(struct bonding *bond,
- struct bond_opt_value *newval);
void bond_option_arp_ip_targets_clear(struct bonding *bond);
-int bond_option_downdelay_set(struct bonding *bond,
- struct bond_opt_value *newval);
-int bond_option_updelay_set(struct bonding *bond,
- struct bond_opt_value *newval);
-int bond_option_lacp_rate_set(struct bonding *bond,
- struct bond_opt_value *newval);
-int bond_option_min_links_set(struct bonding *bond,
- struct bond_opt_value *newval);
-int bond_option_ad_select_set(struct bonding *bond,
- struct bond_opt_value *newval);
-int bond_option_num_peer_notif_set(struct bonding *bond,
- struct bond_opt_value *newval);
-int bond_option_miimon_set(struct bonding *bond, struct bond_opt_value *newval);
-int bond_option_primary_set(struct bonding *bond,
- struct bond_opt_value *newval);
-int bond_option_primary_reselect_set(struct bonding *bond,
- struct bond_opt_value *newval);
-int bond_option_use_carrier_set(struct bonding *bond,
- struct bond_opt_value *newval);
-int bond_option_active_slave_set(struct bonding *bond,
- struct bond_opt_value *newval);
-int bond_option_queue_id_set(struct bonding *bond,
- struct bond_opt_value *newval);
-int bond_option_all_slaves_active_set(struct bonding *bond,
- struct bond_opt_value *newval);
-int bond_option_resend_igmp_set(struct bonding *bond,
- struct bond_opt_value *newval);
-int bond_option_lp_interval_set(struct bonding *bond,
- struct bond_opt_value *newval);
-int bond_option_slaves_set(struct bonding *bond, struct bond_opt_value *newval);
+
#endif /* _BOND_OPTIONS_H */
diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
index 3ac20e78eafc..013fdd0f45e9 100644
--- a/drivers/net/bonding/bond_procfs.c
+++ b/drivers/net/bonding/bond_procfs.c
@@ -65,13 +65,11 @@ static void bond_info_seq_stop(struct seq_file *seq, void *v)
static void bond_info_show_master(struct seq_file *seq)
{
struct bonding *bond = seq->private;
- struct bond_opt_value *optval;
+ const struct bond_opt_value *optval;
struct slave *curr;
int i;
- read_lock(&bond->curr_slave_lock);
- curr = bond->curr_active_slave;
- read_unlock(&bond->curr_slave_lock);
+ curr = rcu_dereference(bond->curr_active_slave);
seq_printf(seq, "Bonding Mode: %s",
bond_mode_name(bond->params.mode));
@@ -254,8 +252,8 @@ void bond_create_proc_entry(struct bonding *bond)
S_IRUGO, bn->proc_dir,
&bond_info_fops, bond);
if (bond->proc_entry == NULL)
- pr_warning("Warning: Cannot create /proc/net/%s/%s\n",
- DRV_NAME, bond_dev->name);
+ pr_warn("Warning: Cannot create /proc/net/%s/%s\n",
+ DRV_NAME, bond_dev->name);
else
memcpy(bond->proc_file_name, bond_dev->name, IFNAMSIZ);
}
@@ -281,8 +279,8 @@ void __net_init bond_create_proc_dir(struct bond_net *bn)
if (!bn->proc_dir) {
bn->proc_dir = proc_mkdir(DRV_NAME, bn->net->proc_net);
if (!bn->proc_dir)
- pr_warning("Warning: cannot create /proc/net/%s\n",
- DRV_NAME);
+ pr_warn("Warning: Cannot create /proc/net/%s\n",
+ DRV_NAME);
}
}
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 643fcc110299..0e8b268da0a0 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -117,9 +117,9 @@ static ssize_t bonding_store_bonds(struct class *cls,
rv = bond_create(bn->net, ifname);
if (rv) {
if (rv == -EEXIST)
- pr_info("%s already exists.\n", ifname);
+ pr_info("%s already exists\n", ifname);
else
- pr_info("%s creation failed.\n", ifname);
+ pr_info("%s creation failed\n", ifname);
res = rv;
}
} else if (command[0] == '-') {
@@ -144,7 +144,7 @@ static ssize_t bonding_store_bonds(struct class *cls,
return res;
err_no_cmd:
- pr_err("no command found in bonding_masters. Use +ifname or -ifname.\n");
+ pr_err("no command found in bonding_masters - use +ifname or -ifname\n");
return -EPERM;
}
@@ -220,7 +220,7 @@ static ssize_t bonding_show_mode(struct device *d,
struct device_attribute *attr, char *buf)
{
struct bonding *bond = to_bond(d);
- struct bond_opt_value *val;
+ const struct bond_opt_value *val;
val = bond_opt_get_val(BOND_OPT_MODE, bond->params.mode);
@@ -251,7 +251,7 @@ static ssize_t bonding_show_xmit_hash(struct device *d,
char *buf)
{
struct bonding *bond = to_bond(d);
- struct bond_opt_value *val;
+ const struct bond_opt_value *val;
val = bond_opt_get_val(BOND_OPT_XMIT_HASH, bond->params.xmit_policy);
@@ -282,7 +282,7 @@ static ssize_t bonding_show_arp_validate(struct device *d,
char *buf)
{
struct bonding *bond = to_bond(d);
- struct bond_opt_value *val;
+ const struct bond_opt_value *val;
val = bond_opt_get_val(BOND_OPT_ARP_VALIDATE,
bond->params.arp_validate);
@@ -314,7 +314,7 @@ static ssize_t bonding_show_arp_all_targets(struct device *d,
char *buf)
{
struct bonding *bond = to_bond(d);
- struct bond_opt_value *val;
+ const struct bond_opt_value *val;
val = bond_opt_get_val(BOND_OPT_ARP_ALL_TARGETS,
bond->params.arp_all_targets);
@@ -348,7 +348,7 @@ static ssize_t bonding_show_fail_over_mac(struct device *d,
char *buf)
{
struct bonding *bond = to_bond(d);
- struct bond_opt_value *val;
+ const struct bond_opt_value *val;
val = bond_opt_get_val(BOND_OPT_FAIL_OVER_MAC,
bond->params.fail_over_mac);
@@ -505,7 +505,7 @@ static ssize_t bonding_show_lacp(struct device *d,
char *buf)
{
struct bonding *bond = to_bond(d);
- struct bond_opt_value *val;
+ const struct bond_opt_value *val;
val = bond_opt_get_val(BOND_OPT_LACP_RATE, bond->params.lacp_fast);
@@ -558,7 +558,7 @@ static ssize_t bonding_show_ad_select(struct device *d,
char *buf)
{
struct bonding *bond = to_bond(d);
- struct bond_opt_value *val;
+ const struct bond_opt_value *val;
val = bond_opt_get_val(BOND_OPT_AD_SELECT, bond->params.ad_select);
@@ -686,7 +686,7 @@ static ssize_t bonding_show_primary_reselect(struct device *d,
char *buf)
{
struct bonding *bond = to_bond(d);
- struct bond_opt_value *val;
+ const struct bond_opt_value *val;
val = bond_opt_get_val(BOND_OPT_PRIMARY_RESELECT,
bond->params.primary_reselect);
@@ -1135,7 +1135,7 @@ int bond_create_sysfs(struct bond_net *bn)
/* Is someone being kinky and naming a device bonding_master? */
if (__dev_get_by_name(bn->net,
class_attr_bonding_masters.attr.name))
- pr_err("network device named %s already exists in sysfs",
+ pr_err("network device named %s already exists in sysfs\n",
class_attr_bonding_masters.attr.name);
ret = 0;
}
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 86ccfb9f71cc..b8bdd0acc8f3 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -188,14 +188,16 @@ struct slave {
struct net_device *dev; /* first - useful for panic debug */
struct bonding *bond; /* our master */
int delay;
- unsigned long jiffies;
- unsigned long last_arp_rx;
+ /* all three in jiffies */
+ unsigned long last_link_up;
+ unsigned long last_rx;
unsigned long target_last_arp_rx[BOND_MAX_ARP_TARGETS];
s8 link; /* one of BOND_LINK_XXXX */
s8 new_link;
u8 backup:1, /* indicates backup slave. Value corresponds with
BOND_STATE_ACTIVE and BOND_STATE_BACKUP */
- inactive:1; /* indicates inactive slave */
+ inactive:1, /* indicates inactive slave */
+ should_notify:1; /* indicateds whether the state changed */
u8 duplex;
u32 original_mtu;
u32 link_failure_count;
@@ -264,6 +266,11 @@ struct bonding {
#define bond_slave_get_rtnl(dev) \
((struct slave *) rtnl_dereference(dev->rx_handler_data))
+struct bond_vlan_tag {
+ __be16 vlan_proto;
+ unsigned short vlan_id;
+};
+
/**
* Returns NULL if the net_device does not belong to any of the bond's slaves
*
@@ -291,7 +298,7 @@ static inline void bond_set_active_slave(struct slave *slave)
{
if (slave->backup) {
slave->backup = 0;
- rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_KERNEL);
+ rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC);
}
}
@@ -299,7 +306,25 @@ static inline void bond_set_backup_slave(struct slave *slave)
{
if (!slave->backup) {
slave->backup = 1;
- rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_KERNEL);
+ rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC);
+ }
+}
+
+static inline void bond_set_slave_state(struct slave *slave,
+ int slave_state, bool notify)
+{
+ if (slave->backup == slave_state)
+ return;
+
+ slave->backup = slave_state;
+ if (notify) {
+ rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC);
+ slave->should_notify = 0;
+ } else {
+ if (slave->should_notify)
+ slave->should_notify = 0;
+ else
+ slave->should_notify = 1;
}
}
@@ -316,6 +341,19 @@ static inline void bond_slave_state_change(struct bonding *bond)
}
}
+static inline void bond_slave_state_notify(struct bonding *bond)
+{
+ struct list_head *iter;
+ struct slave *tmp;
+
+ bond_for_each_slave(bond, tmp, iter) {
+ if (tmp->should_notify) {
+ rtmsg_ifinfo(RTM_NEWLINK, tmp->dev, 0, GFP_ATOMIC);
+ tmp->should_notify = 0;
+ }
+ }
+}
+
static inline int bond_slave_state(struct slave *slave)
{
return slave->backup;
@@ -342,6 +380,14 @@ static inline bool bond_is_active_slave(struct slave *slave)
#define BOND_ARP_VALIDATE_BACKUP (1 << BOND_STATE_BACKUP)
#define BOND_ARP_VALIDATE_ALL (BOND_ARP_VALIDATE_ACTIVE | \
BOND_ARP_VALIDATE_BACKUP)
+#define BOND_ARP_FILTER (BOND_ARP_VALIDATE_ALL + 1)
+#define BOND_ARP_FILTER_ACTIVE (BOND_ARP_VALIDATE_ACTIVE | \
+ BOND_ARP_FILTER)
+#define BOND_ARP_FILTER_BACKUP (BOND_ARP_VALIDATE_BACKUP | \
+ BOND_ARP_FILTER)
+
+#define BOND_SLAVE_NOTIFY_NOW true
+#define BOND_SLAVE_NOTIFY_LATER false
static inline int slave_do_arp_validate(struct bonding *bond,
struct slave *slave)
@@ -349,6 +395,12 @@ static inline int slave_do_arp_validate(struct bonding *bond,
return bond->params.arp_validate & (1 << bond_slave_state(slave));
}
+static inline int slave_do_arp_validate_only(struct bonding *bond,
+ struct slave *slave)
+{
+ return bond->params.arp_validate & BOND_ARP_FILTER;
+}
+
/* Get the oldest arp which we've received on this slave for bond's
* arp_targets.
*/
@@ -368,14 +420,10 @@ static inline unsigned long slave_oldest_target_arp_rx(struct bonding *bond,
static inline unsigned long slave_last_rx(struct bonding *bond,
struct slave *slave)
{
- if (slave_do_arp_validate(bond, slave)) {
- if (bond->params.arp_all_targets == BOND_ARP_TARGETS_ALL)
- return slave_oldest_target_arp_rx(bond, slave);
- else
- return slave->last_arp_rx;
- }
+ if (bond->params.arp_all_targets == BOND_ARP_TARGETS_ALL)
+ return slave_oldest_target_arp_rx(bond, slave);
- return slave->dev->last_rx;
+ return slave->last_rx;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -394,17 +442,19 @@ static inline void bond_netpoll_send_skb(const struct slave *slave,
}
#endif
-static inline void bond_set_slave_inactive_flags(struct slave *slave)
+static inline void bond_set_slave_inactive_flags(struct slave *slave,
+ bool notify)
{
if (!bond_is_lb(slave->bond))
- bond_set_backup_slave(slave);
+ bond_set_slave_state(slave, BOND_STATE_BACKUP, notify);
if (!slave->bond->params.all_slaves_active)
slave->inactive = 1;
}
-static inline void bond_set_slave_active_flags(struct slave *slave)
+static inline void bond_set_slave_active_flags(struct slave *slave,
+ bool notify)
{
- bond_set_active_slave(slave);
+ bond_set_slave_state(slave, BOND_STATE_ACTIVE, notify);
slave->inactive = 0;
}
@@ -450,8 +500,6 @@ void bond_sysfs_slave_del(struct slave *slave);
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev);
int bond_release(struct net_device *bond_dev, struct net_device *slave_dev);
int bond_xmit_hash(struct bonding *bond, struct sk_buff *skb, int count);
-int bond_parse_parm(const char *mode_arg, const struct bond_parm_tbl *tbl);
-int bond_parm_tbl_lookup(int mode, const struct bond_parm_tbl *tbl);
void bond_select_active_slave(struct bonding *bond);
void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
void bond_create_debugfs(void);
@@ -464,8 +512,6 @@ void bond_setup(struct net_device *bond_dev);
unsigned int bond_get_num_tx_queues(void);
int bond_netlink_init(void);
void bond_netlink_fini(void);
-int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target);
-int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target);
struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond);
struct net_device *bond_option_active_slave_get(struct bonding *bond);
const char *bond_slave_link_status(s8 link);
diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c
index 88a6a5810ec6..fc73865bb83a 100644
--- a/drivers/net/caif/caif_serial.c
+++ b/drivers/net/caif/caif_serial.c
@@ -204,7 +204,6 @@ static void ldisc_receive(struct tty_struct *tty, const u8 *data,
skb->protocol = htons(ETH_P_CAIF);
skb_reset_mac_header(skb);
- skb->dev = ser->dev;
debugfs_rx(ser, data, count);
/* Push received packet up the stack. */
ret = netif_rx_ni(skb);
diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c
index 155db68e13ba..ff54c0eb2052 100644
--- a/drivers/net/caif/caif_spi.c
+++ b/drivers/net/caif/caif_spi.c
@@ -554,7 +554,6 @@ int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len)
skb->protocol = htons(ETH_P_CAIF);
skb_reset_mac_header(skb);
- skb->dev = cfspi->ndev;
/*
* Push received packet up the stack.
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index d447b881bbde..9e7d95dae2c7 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -104,7 +104,7 @@ config CAN_JANZ_ICAN3
config CAN_FLEXCAN
tristate "Support for Freescale FLEXCAN based chips"
- depends on (ARM && CPU_LITTLE_ENDIAN) || PPC
+ depends on ARM || PPC
---help---
Say Y here if you want to support for Freescale FlexCAN.
diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
index 6efe27458116..f07fa89b5fd5 100644
--- a/drivers/net/can/at91_can.c
+++ b/drivers/net/can/at91_can.c
@@ -420,7 +420,11 @@ static void at91_chip_start(struct net_device *dev)
at91_transceiver_switch(priv, 1);
/* enable chip */
- at91_write(priv, AT91_MR, AT91_MR_CANEN);
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+ reg_mr = AT91_MR_CANEN | AT91_MR_ABM;
+ else
+ reg_mr = AT91_MR_CANEN;
+ at91_write(priv, AT91_MR, reg_mr);
priv->can.state = CAN_STATE_ERROR_ACTIVE;
@@ -1190,6 +1194,7 @@ static const struct net_device_ops at91_netdev_ops = {
.ndo_open = at91_open,
.ndo_stop = at91_close,
.ndo_start_xmit = at91_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
static ssize_t at91_sysfs_show_mb0_id(struct device *dev,
@@ -1341,7 +1346,8 @@ static int at91_can_probe(struct platform_device *pdev)
priv->can.bittiming_const = &at91_bittiming_const;
priv->can.do_set_mode = at91_set_mode;
priv->can.do_get_berr_counter = at91_get_berr_counter;
- priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
+ CAN_CTRLMODE_LISTENONLY;
priv->dev = dev;
priv->reg_base = addr;
priv->devtype_data = *devtype_data;
diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c
index 8d2b89a12e09..543ecceb33e9 100644
--- a/drivers/net/can/bfin_can.c
+++ b/drivers/net/can/bfin_can.c
@@ -528,6 +528,7 @@ static const struct net_device_ops bfin_can_netdev_ops = {
.ndo_open = bfin_can_open,
.ndo_stop = bfin_can_close,
.ndo_start_xmit = bfin_can_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
static int bfin_can_probe(struct platform_device *pdev)
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c
index 951bfede8f3d..a5c8dcfa8357 100644
--- a/drivers/net/can/c_can/c_can.c
+++ b/drivers/net/can/c_can/c_can.c
@@ -114,6 +114,14 @@
IF_COMM_CONTROL | IF_COMM_TXRQST | \
IF_COMM_DATAA | IF_COMM_DATAB)
+/* For the low buffers we clear the interrupt bit, but keep newdat */
+#define IF_COMM_RCV_LOW (IF_COMM_MASK | IF_COMM_ARB | \
+ IF_COMM_CONTROL | IF_COMM_CLR_INT_PND | \
+ IF_COMM_DATAA | IF_COMM_DATAB)
+
+/* For the high buffers we clear the interrupt bit and newdat */
+#define IF_COMM_RCV_HIGH (IF_COMM_RCV_LOW | IF_COMM_TXRQST)
+
/* IFx arbitration */
#define IF_ARB_MSGVAL BIT(15)
#define IF_ARB_MSGXTD BIT(14)
@@ -122,7 +130,6 @@
/* IFx message control */
#define IF_MCONT_NEWDAT BIT(15)
#define IF_MCONT_MSGLST BIT(14)
-#define IF_MCONT_CLR_MSGLST (0 << 14)
#define IF_MCONT_INTPND BIT(13)
#define IF_MCONT_UMASK BIT(12)
#define IF_MCONT_TXIE BIT(11)
@@ -133,31 +140,10 @@
#define IF_MCONT_DLC_MASK 0xf
/*
- * IFx register masks:
- * allow easy operation on 16-bit registers when the
- * argument is 32-bit instead
+ * Use IF1 for RX and IF2 for TX
*/
-#define IFX_WRITE_LOW_16BIT(x) ((x) & 0xFFFF)
-#define IFX_WRITE_HIGH_16BIT(x) (((x) & 0xFFFF0000) >> 16)
-
-/* message object split */
-#define C_CAN_NO_OF_OBJECTS 32
-#define C_CAN_MSG_OBJ_RX_NUM 16
-#define C_CAN_MSG_OBJ_TX_NUM 16
-
-#define C_CAN_MSG_OBJ_RX_FIRST 1
-#define C_CAN_MSG_OBJ_RX_LAST (C_CAN_MSG_OBJ_RX_FIRST + \
- C_CAN_MSG_OBJ_RX_NUM - 1)
-
-#define C_CAN_MSG_OBJ_TX_FIRST (C_CAN_MSG_OBJ_RX_LAST + 1)
-#define C_CAN_MSG_OBJ_TX_LAST (C_CAN_MSG_OBJ_TX_FIRST + \
- C_CAN_MSG_OBJ_TX_NUM - 1)
-
-#define C_CAN_MSG_OBJ_RX_SPLIT 9
-#define C_CAN_MSG_RX_LOW_LAST (C_CAN_MSG_OBJ_RX_SPLIT - 1)
-
-#define C_CAN_NEXT_MSG_OBJ_MASK (C_CAN_MSG_OBJ_TX_NUM - 1)
-#define RECEIVE_OBJECT_BITS 0x0000ffff
+#define IF_RX 0
+#define IF_TX 1
/* status interrupt */
#define STATUS_INTERRUPT 0x8000
@@ -246,10 +232,9 @@ static inline int get_tx_next_msg_obj(const struct c_can_priv *priv)
C_CAN_MSG_OBJ_TX_FIRST;
}
-static inline int get_tx_echo_msg_obj(const struct c_can_priv *priv)
+static inline int get_tx_echo_msg_obj(int txecho)
{
- return (priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) +
- C_CAN_MSG_OBJ_TX_FIRST;
+ return (txecho & C_CAN_NEXT_MSG_OBJ_MASK) + C_CAN_MSG_OBJ_TX_FIRST;
}
static u32 c_can_read_reg32(struct c_can_priv *priv, enum reg index)
@@ -366,18 +351,6 @@ static void c_can_write_msg_object(struct net_device *dev,
c_can_object_put(dev, iface, objno, IF_COMM_ALL);
}
-static inline void c_can_mark_rx_msg_obj(struct net_device *dev,
- int iface, int ctrl_mask,
- int obj)
-{
- struct c_can_priv *priv = netdev_priv(dev);
-
- priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
- ctrl_mask & ~(IF_MCONT_MSGLST | IF_MCONT_INTPND));
- c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
-
-}
-
static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device *dev,
int iface,
int ctrl_mask)
@@ -387,45 +360,27 @@ static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device *dev,
for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_MSG_RX_LOW_LAST; i++) {
priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
- ctrl_mask & ~(IF_MCONT_MSGLST |
- IF_MCONT_INTPND | IF_MCONT_NEWDAT));
+ ctrl_mask & ~IF_MCONT_NEWDAT);
c_can_object_put(dev, iface, i, IF_COMM_CONTROL);
}
}
-static inline void c_can_activate_rx_msg_obj(struct net_device *dev,
- int iface, int ctrl_mask,
- int obj)
-{
- struct c_can_priv *priv = netdev_priv(dev);
-
- priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
- ctrl_mask & ~(IF_MCONT_MSGLST |
- IF_MCONT_INTPND | IF_MCONT_NEWDAT));
- c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
-}
-
-static void c_can_handle_lost_msg_obj(struct net_device *dev,
- int iface, int objno)
+static int c_can_handle_lost_msg_obj(struct net_device *dev,
+ int iface, int objno, u32 ctrl)
{
- struct c_can_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
- struct sk_buff *skb;
+ struct c_can_priv *priv = netdev_priv(dev);
struct can_frame *frame;
+ struct sk_buff *skb;
- netdev_err(dev, "msg lost in buffer %d\n", objno);
-
- c_can_object_get(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST);
-
- priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
- IF_MCONT_CLR_MSGLST);
-
- c_can_object_put(dev, 0, objno, IF_COMM_CONTROL);
+ ctrl &= ~(IF_MCONT_MSGLST | IF_MCONT_INTPND | IF_MCONT_NEWDAT);
+ priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), ctrl);
+ c_can_object_put(dev, iface, objno, IF_COMM_CONTROL);
/* create an error msg */
skb = alloc_can_err_skb(dev, &frame);
if (unlikely(!skb))
- return;
+ return 0;
frame->can_id |= CAN_ERR_CRTL;
frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
@@ -433,6 +388,7 @@ static void c_can_handle_lost_msg_obj(struct net_device *dev,
stats->rx_over_errors++;
netif_receive_skb(skb);
+ return 1;
}
static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl)
@@ -477,9 +433,6 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl)
stats->rx_packets++;
stats->rx_bytes += frame->can_dlc;
-
- can_led_event(dev, CAN_LED_EVENT_RX);
-
return 0;
}
@@ -548,10 +501,12 @@ static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
+ spin_lock_bh(&priv->xmit_lock);
msg_obj_no = get_tx_next_msg_obj(priv);
/* prepare message object for transmission */
- c_can_write_msg_object(dev, 0, frame, msg_obj_no);
+ c_can_write_msg_object(dev, IF_TX, frame, msg_obj_no);
+ priv->dlc[msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST] = frame->can_dlc;
can_put_echo_skb(skb, dev, msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
/*
@@ -562,10 +517,26 @@ static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
if (c_can_is_next_tx_obj_busy(priv, get_tx_next_msg_obj(priv)) ||
(priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) == 0)
netif_stop_queue(dev);
+ spin_unlock_bh(&priv->xmit_lock);
return NETDEV_TX_OK;
}
+static int c_can_wait_for_ctrl_init(struct net_device *dev,
+ struct c_can_priv *priv, u32 init)
+{
+ int retry = 0;
+
+ while (init != (priv->read_reg(priv, C_CAN_CTRL_REG) & CONTROL_INIT)) {
+ udelay(10);
+ if (retry++ > 1000) {
+ netdev_err(dev, "CCTRL: set CONTROL_INIT failed\n");
+ return -EIO;
+ }
+ }
+ return 0;
+}
+
static int c_can_set_bittiming(struct net_device *dev)
{
unsigned int reg_btr, reg_brpe, ctrl_save;
@@ -573,6 +544,7 @@ static int c_can_set_bittiming(struct net_device *dev)
u32 ten_bit_brp;
struct c_can_priv *priv = netdev_priv(dev);
const struct can_bittiming *bt = &priv->can.bittiming;
+ int res;
/* c_can provides a 6-bit brp and 4-bit brpe fields */
ten_bit_brp = bt->brp - 1;
@@ -590,13 +562,17 @@ static int c_can_set_bittiming(struct net_device *dev)
"setting BTR=%04x BRPE=%04x\n", reg_btr, reg_brpe);
ctrl_save = priv->read_reg(priv, C_CAN_CTRL_REG);
- priv->write_reg(priv, C_CAN_CTRL_REG,
- ctrl_save | CONTROL_CCE | CONTROL_INIT);
+ ctrl_save &= ~CONTROL_INIT;
+ priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_CCE | CONTROL_INIT);
+ res = c_can_wait_for_ctrl_init(dev, priv, CONTROL_INIT);
+ if (res)
+ return res;
+
priv->write_reg(priv, C_CAN_BTR_REG, reg_btr);
priv->write_reg(priv, C_CAN_BRPEXT_REG, reg_brpe);
priv->write_reg(priv, C_CAN_CTRL_REG, ctrl_save);
- return 0;
+ return c_can_wait_for_ctrl_init(dev, priv, 0);
}
/*
@@ -614,14 +590,14 @@ static void c_can_configure_msg_objects(struct net_device *dev)
/* first invalidate all message objects */
for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_NO_OF_OBJECTS; i++)
- c_can_inval_msg_object(dev, 0, i);
+ c_can_inval_msg_object(dev, IF_RX, i);
/* setup receive message objects */
for (i = C_CAN_MSG_OBJ_RX_FIRST; i < C_CAN_MSG_OBJ_RX_LAST; i++)
- c_can_setup_receive_object(dev, 0, i, 0, 0,
+ c_can_setup_receive_object(dev, IF_RX, i, 0, 0,
(IF_MCONT_RXIE | IF_MCONT_UMASK) & ~IF_MCONT_EOB);
- c_can_setup_receive_object(dev, 0, C_CAN_MSG_OBJ_RX_LAST, 0, 0,
+ c_can_setup_receive_object(dev, IF_RX, C_CAN_MSG_OBJ_RX_LAST, 0, 0,
IF_MCONT_EOB | IF_MCONT_RXIE | IF_MCONT_UMASK);
}
@@ -631,7 +607,7 @@ static void c_can_configure_msg_objects(struct net_device *dev)
* - set operating mode
* - configure message objects
*/
-static void c_can_chip_config(struct net_device *dev)
+static int c_can_chip_config(struct net_device *dev)
{
struct c_can_priv *priv = netdev_priv(dev);
@@ -668,15 +644,18 @@ static void c_can_chip_config(struct net_device *dev)
priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
/* set bittiming params */
- c_can_set_bittiming(dev);
+ return c_can_set_bittiming(dev);
}
-static void c_can_start(struct net_device *dev)
+static int c_can_start(struct net_device *dev)
{
struct c_can_priv *priv = netdev_priv(dev);
+ int err;
/* basic c_can configuration */
- c_can_chip_config(dev);
+ err = c_can_chip_config(dev);
+ if (err)
+ return err;
priv->can.state = CAN_STATE_ERROR_ACTIVE;
@@ -685,6 +664,8 @@ static void c_can_start(struct net_device *dev)
/* enable status change, error and module interrupts */
c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
+
+ return 0;
}
static void c_can_stop(struct net_device *dev)
@@ -700,9 +681,13 @@ static void c_can_stop(struct net_device *dev)
static int c_can_set_mode(struct net_device *dev, enum can_mode mode)
{
+ int err;
+
switch (mode) {
case CAN_MODE_START:
- c_can_start(dev);
+ err = c_can_start(dev);
+ if (err)
+ return err;
netif_wake_queue(dev);
break;
default:
@@ -740,8 +725,6 @@ static int c_can_get_berr_counter(const struct net_device *dev,
}
/*
- * theory of operation:
- *
* priv->tx_echo holds the number of the oldest can_frame put for
* transmission into the hardware, but not yet ACKed by the CAN tx
* complete IRQ.
@@ -752,33 +735,113 @@ static int c_can_get_berr_counter(const struct net_device *dev,
*/
static void c_can_do_tx(struct net_device *dev)
{
- u32 val;
- u32 msg_obj_no;
struct c_can_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
+ u32 val, obj, pkts = 0, bytes = 0;
- for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) {
- msg_obj_no = get_tx_echo_msg_obj(priv);
+ spin_lock_bh(&priv->xmit_lock);
+
+ for (; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) {
+ obj = get_tx_echo_msg_obj(priv->tx_echo);
val = c_can_read_reg32(priv, C_CAN_TXRQST1_REG);
- if (!(val & (1 << (msg_obj_no - 1)))) {
- can_get_echo_skb(dev,
- msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
- c_can_object_get(dev, 0, msg_obj_no, IF_COMM_ALL);
- stats->tx_bytes += priv->read_reg(priv,
- C_CAN_IFACE(MSGCTRL_REG, 0))
- & IF_MCONT_DLC_MASK;
- stats->tx_packets++;
- can_led_event(dev, CAN_LED_EVENT_TX);
- c_can_inval_msg_object(dev, 0, msg_obj_no);
- } else {
+
+ if (val & (1 << (obj - 1)))
break;
- }
+
+ can_get_echo_skb(dev, obj - C_CAN_MSG_OBJ_TX_FIRST);
+ bytes += priv->dlc[obj - C_CAN_MSG_OBJ_TX_FIRST];
+ pkts++;
+ c_can_inval_msg_object(dev, IF_TX, obj);
}
/* restart queue if wrap-up or if queue stalled on last pkt */
if (((priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) != 0) ||
((priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) == 0))
netif_wake_queue(dev);
+
+ spin_unlock_bh(&priv->xmit_lock);
+
+ if (pkts) {
+ stats->tx_bytes += bytes;
+ stats->tx_packets += pkts;
+ can_led_event(dev, CAN_LED_EVENT_TX);
+ }
+}
+
+/*
+ * If we have a gap in the pending bits, that means we either
+ * raced with the hardware or failed to readout all upper
+ * objects in the last run due to quota limit.
+ */
+static u32 c_can_adjust_pending(u32 pend)
+{
+ u32 weight, lasts;
+
+ if (pend == RECEIVE_OBJECT_BITS)
+ return pend;
+
+ /*
+ * If the last set bit is larger than the number of pending
+ * bits we have a gap.
+ */
+ weight = hweight32(pend);
+ lasts = fls(pend);
+
+ /* If the bits are linear, nothing to do */
+ if (lasts == weight)
+ return pend;
+
+ /*
+ * Find the first set bit after the gap. We walk backwards
+ * from the last set bit.
+ */
+ for (lasts--; pend & (1 << (lasts - 1)); lasts--);
+
+ return pend & ~((1 << lasts) - 1);
+}
+
+static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
+ u32 pend, int quota)
+{
+ u32 pkts = 0, ctrl, obj, mcmd;
+
+ while ((obj = ffs(pend)) && quota > 0) {
+ pend &= ~BIT(obj - 1);
+
+ mcmd = obj < C_CAN_MSG_RX_LOW_LAST ?
+ IF_COMM_RCV_LOW : IF_COMM_RCV_HIGH;
+
+ c_can_object_get(dev, IF_RX, obj, mcmd);
+ ctrl = priv->read_reg(priv, C_CAN_IFACE(MSGCTRL_REG, IF_RX));
+
+ if (ctrl & IF_MCONT_MSGLST) {
+ int n = c_can_handle_lost_msg_obj(dev, IF_RX, obj, ctrl);
+
+ pkts += n;
+ quota -= n;
+ continue;
+ }
+
+ /*
+ * This really should not happen, but this covers some
+ * odd HW behaviour. Do not remove that unless you
+ * want to brick your machine.
+ */
+ if (!(ctrl & IF_MCONT_NEWDAT))
+ continue;
+
+ /* read the data from the message object */
+ c_can_read_msg_object(dev, IF_RX, ctrl);
+
+ if (obj == C_CAN_MSG_RX_LOW_LAST)
+ /* activate all lower message objects */
+ c_can_activate_all_lower_rx_msg_obj(dev, IF_RX, ctrl);
+
+ pkts++;
+ quota--;
+ }
+
+ return pkts;
}
/*
@@ -805,10 +868,8 @@ static void c_can_do_tx(struct net_device *dev)
*/
static int c_can_do_rx_poll(struct net_device *dev, int quota)
{
- u32 num_rx_pkts = 0;
- unsigned int msg_obj, msg_ctrl_save;
struct c_can_priv *priv = netdev_priv(dev);
- u16 val;
+ u32 pkts = 0, pend = 0, toread, n;
/*
* It is faster to read only one 16bit register. This is only possible
@@ -817,49 +878,31 @@ static int c_can_do_rx_poll(struct net_device *dev, int quota)
BUILD_BUG_ON_MSG(C_CAN_MSG_OBJ_RX_LAST > 16,
"Implementation does not support more message objects than 16");
- while (quota > 0 && (val = priv->read_reg(priv, C_CAN_INTPND1_REG))) {
- while ((msg_obj = ffs(val)) && quota > 0) {
- val &= ~BIT(msg_obj - 1);
-
- c_can_object_get(dev, 0, msg_obj, IF_COMM_ALL &
- ~IF_COMM_TXRQST);
- msg_ctrl_save = priv->read_reg(priv,
- C_CAN_IFACE(MSGCTRL_REG, 0));
-
- if (msg_ctrl_save & IF_MCONT_MSGLST) {
- c_can_handle_lost_msg_obj(dev, 0, msg_obj);
- num_rx_pkts++;
- quota--;
- continue;
- }
-
- if (msg_ctrl_save & IF_MCONT_EOB)
- return num_rx_pkts;
-
- if (!(msg_ctrl_save & IF_MCONT_NEWDAT))
- continue;
-
- /* read the data from the message object */
- c_can_read_msg_object(dev, 0, msg_ctrl_save);
-
- if (msg_obj < C_CAN_MSG_RX_LOW_LAST)
- c_can_mark_rx_msg_obj(dev, 0,
- msg_ctrl_save, msg_obj);
- else if (msg_obj > C_CAN_MSG_RX_LOW_LAST)
- /* activate this msg obj */
- c_can_activate_rx_msg_obj(dev, 0,
- msg_ctrl_save, msg_obj);
- else if (msg_obj == C_CAN_MSG_RX_LOW_LAST)
- /* activate all lower message objects */
- c_can_activate_all_lower_rx_msg_obj(dev,
- 0, msg_ctrl_save);
-
- num_rx_pkts++;
- quota--;
+ while (quota > 0) {
+ if (!pend) {
+ pend = priv->read_reg(priv, C_CAN_INTPND1_REG);
+ if (!pend)
+ break;
+ /*
+ * If the pending field has a gap, handle the
+ * bits above the gap first.
+ */
+ toread = c_can_adjust_pending(pend);
+ } else {
+ toread = pend;
}
+ /* Remove the bits from pend */
+ pend &= ~toread;
+ /* Read the objects */
+ n = c_can_read_objects(dev, priv, toread, quota);
+ pkts += n;
+ quota -= n;
}
- return num_rx_pkts;
+ if (pkts)
+ can_led_event(dev, CAN_LED_EVENT_RX);
+
+ return pkts;
}
static inline int c_can_has_and_handle_berr(struct c_can_priv *priv)
@@ -1133,17 +1176,20 @@ static int c_can_open(struct net_device *dev)
goto exit_irq_fail;
}
- napi_enable(&priv->napi);
+ /* start the c_can controller */
+ err = c_can_start(dev);
+ if (err)
+ goto exit_start_fail;
can_led_event(dev, CAN_LED_EVENT_OPEN);
- /* start the c_can controller */
- c_can_start(dev);
-
+ napi_enable(&priv->napi);
netif_start_queue(dev);
return 0;
+exit_start_fail:
+ free_irq(dev->irq, dev);
exit_irq_fail:
close_candev(dev);
exit_open_fail:
@@ -1180,6 +1226,7 @@ struct net_device *alloc_c_can_dev(void)
return NULL;
priv = netdev_priv(dev);
+ spin_lock_init(&priv->xmit_lock);
netif_napi_add(dev, &priv->napi, c_can_poll, C_CAN_NAPI_WEIGHT);
priv->dev = dev;
@@ -1260,15 +1307,16 @@ int c_can_power_up(struct net_device *dev)
if (time_after(jiffies, time_out))
return -ETIMEDOUT;
- c_can_start(dev);
-
- return 0;
+ return c_can_start(dev);
}
EXPORT_SYMBOL_GPL(c_can_power_up);
#endif
void free_c_can_dev(struct net_device *dev)
{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ netif_napi_del(&priv->napi);
free_candev(dev);
}
EXPORT_SYMBOL_GPL(free_c_can_dev);
@@ -1277,6 +1325,7 @@ static const struct net_device_ops c_can_netdev_ops = {
.ndo_open = c_can_open,
.ndo_stop = c_can_close,
.ndo_start_xmit = c_can_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
int register_c_can_dev(struct net_device *dev)
diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h
index d2e1c21b143f..faa8404162b3 100644
--- a/drivers/net/can/c_can/c_can.h
+++ b/drivers/net/can/c_can/c_can.h
@@ -22,6 +22,33 @@
#ifndef C_CAN_H
#define C_CAN_H
+/*
+ * IFx register masks:
+ * allow easy operation on 16-bit registers when the
+ * argument is 32-bit instead
+ */
+#define IFX_WRITE_LOW_16BIT(x) ((x) & 0xFFFF)
+#define IFX_WRITE_HIGH_16BIT(x) (((x) & 0xFFFF0000) >> 16)
+
+/* message object split */
+#define C_CAN_NO_OF_OBJECTS 32
+#define C_CAN_MSG_OBJ_RX_NUM 16
+#define C_CAN_MSG_OBJ_TX_NUM 16
+
+#define C_CAN_MSG_OBJ_RX_FIRST 1
+#define C_CAN_MSG_OBJ_RX_LAST (C_CAN_MSG_OBJ_RX_FIRST + \
+ C_CAN_MSG_OBJ_RX_NUM - 1)
+
+#define C_CAN_MSG_OBJ_TX_FIRST (C_CAN_MSG_OBJ_RX_LAST + 1)
+#define C_CAN_MSG_OBJ_TX_LAST (C_CAN_MSG_OBJ_TX_FIRST + \
+ C_CAN_MSG_OBJ_TX_NUM - 1)
+
+#define C_CAN_MSG_OBJ_RX_SPLIT 9
+#define C_CAN_MSG_RX_LOW_LAST (C_CAN_MSG_OBJ_RX_SPLIT - 1)
+
+#define C_CAN_NEXT_MSG_OBJ_MASK (C_CAN_MSG_OBJ_TX_NUM - 1)
+#define RECEIVE_OBJECT_BITS 0x0000ffff
+
enum reg {
C_CAN_CTRL_REG = 0,
C_CAN_CTRL_EX_REG,
@@ -156,6 +183,7 @@ struct c_can_priv {
struct napi_struct napi;
struct net_device *dev;
struct device *device;
+ spinlock_t xmit_lock;
int tx_object;
int current_status;
int last_status;
@@ -172,6 +200,7 @@ struct c_can_priv {
u32 __iomem *raminit_ctrlreg;
unsigned int instance;
void (*raminit) (const struct c_can_priv *priv, bool enable);
+ u32 dlc[C_CAN_MSG_OBJ_TX_NUM];
};
struct net_device *alloc_c_can_dev(void);
diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c
index d66ac265269c..806d92753427 100644
--- a/drivers/net/can/c_can/c_can_platform.c
+++ b/drivers/net/can/c_can/c_can_platform.c
@@ -37,8 +37,10 @@
#include "c_can.h"
-#define CAN_RAMINIT_START_MASK(i) (1 << (i))
-
+#define CAN_RAMINIT_START_MASK(i) (0x001 << (i))
+#define CAN_RAMINIT_DONE_MASK(i) (0x100 << (i))
+#define CAN_RAMINIT_ALL_MASK(i) (0x101 << (i))
+static DEFINE_SPINLOCK(raminit_lock);
/*
* 16-bit c_can registers can be arranged differently in the memory
* architecture of different implementations. For example: 16-bit
@@ -69,16 +71,41 @@ static void c_can_plat_write_reg_aligned_to_32bit(struct c_can_priv *priv,
writew(val, priv->base + 2 * priv->regs[index]);
}
+static void c_can_hw_raminit_wait(const struct c_can_priv *priv, u32 mask,
+ u32 val)
+{
+ /* We look only at the bits of our instance. */
+ val &= mask;
+ while ((readl(priv->raminit_ctrlreg) & mask) != val)
+ udelay(1);
+}
+
static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable)
{
- u32 val;
-
- val = readl(priv->raminit_ctrlreg);
- if (enable)
- val |= CAN_RAMINIT_START_MASK(priv->instance);
- else
- val &= ~CAN_RAMINIT_START_MASK(priv->instance);
- writel(val, priv->raminit_ctrlreg);
+ u32 mask = CAN_RAMINIT_ALL_MASK(priv->instance);
+ u32 ctrl;
+
+ spin_lock(&raminit_lock);
+
+ ctrl = readl(priv->raminit_ctrlreg);
+ /* We clear the done and start bit first. The start bit is
+ * looking at the 0 -> transition, but is not self clearing;
+ * And we clear the init done bit as well.
+ */
+ ctrl &= ~CAN_RAMINIT_START_MASK(priv->instance);
+ ctrl |= CAN_RAMINIT_DONE_MASK(priv->instance);
+ writel(ctrl, priv->raminit_ctrlreg);
+ ctrl &= ~CAN_RAMINIT_DONE_MASK(priv->instance);
+ c_can_hw_raminit_wait(priv, ctrl, mask);
+
+ if (enable) {
+ /* Set start bit and wait for the done bit. */
+ ctrl |= CAN_RAMINIT_START_MASK(priv->instance);
+ writel(ctrl, priv->raminit_ctrlreg);
+ ctrl |= CAN_RAMINIT_DONE_MASK(priv->instance);
+ c_can_hw_raminit_wait(priv, ctrl, mask);
+ }
+ spin_unlock(&raminit_lock);
}
static struct platform_device_id c_can_id_table[] = {
diff --git a/drivers/net/can/cc770/cc770.c b/drivers/net/can/cc770/cc770.c
index 0f12abf6591c..d8379278d648 100644
--- a/drivers/net/can/cc770/cc770.c
+++ b/drivers/net/can/cc770/cc770.c
@@ -823,6 +823,7 @@ static const struct net_device_ops cc770_netdev_ops = {
.ndo_open = cc770_open,
.ndo_stop = cc770_close,
.ndo_start_xmit = cc770_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
int register_cc770dev(struct net_device *dev)
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
index 13a909822e25..c7a260478749 100644
--- a/drivers/net/can/dev.c
+++ b/drivers/net/can/dev.c
@@ -99,10 +99,10 @@ static int can_update_spt(const struct can_bittiming_const *btc,
return 1000 * (tseg + 1 - *tseg2) / (tseg + 1);
}
-static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
+static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
+ const struct can_bittiming_const *btc)
{
struct can_priv *priv = netdev_priv(dev);
- const struct can_bittiming_const *btc = priv->bittiming_const;
long rate, best_rate = 0;
long best_error = 1000000000, error = 0;
int best_tseg = 0, best_brp = 0, brp = 0;
@@ -110,9 +110,6 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
int spt_error = 1000, spt = 0, sampl_pt;
u64 v64;
- if (!priv->bittiming_const)
- return -ENOTSUPP;
-
/* Use CIA recommended sample points */
if (bt->sample_point) {
sampl_pt = bt->sample_point;
@@ -204,7 +201,8 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
return 0;
}
#else /* !CONFIG_CAN_CALC_BITTIMING */
-static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
+static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
+ const struct can_bittiming_const *btc)
{
netdev_err(dev, "bit-timing calculation not available\n");
return -EINVAL;
@@ -217,16 +215,13 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
* prescaler value brp. You can find more information in the header
* file linux/can/netlink.h.
*/
-static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt)
+static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt,
+ const struct can_bittiming_const *btc)
{
struct can_priv *priv = netdev_priv(dev);
- const struct can_bittiming_const *btc = priv->bittiming_const;
int tseg1, alltseg;
u64 brp64;
- if (!priv->bittiming_const)
- return -ENOTSUPP;
-
tseg1 = bt->prop_seg + bt->phase_seg1;
if (!bt->sjw)
bt->sjw = 1;
@@ -254,26 +249,29 @@ static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt)
return 0;
}
-static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt)
+static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt,
+ const struct can_bittiming_const *btc)
{
- struct can_priv *priv = netdev_priv(dev);
int err;
/* Check if the CAN device has bit-timing parameters */
- if (priv->bittiming_const) {
+ if (!btc)
+ return -ENOTSUPP;
- /* Non-expert mode? Check if the bitrate has been pre-defined */
- if (!bt->tq)
- /* Determine bit-timing parameters */
- err = can_calc_bittiming(dev, bt);
- else
- /* Check bit-timing params and calculate proper brp */
- err = can_fixup_bittiming(dev, bt);
- if (err)
- return err;
- }
+ /*
+ * Depending on the given can_bittiming parameter structure the CAN
+ * timing parameters are calculated based on the provided bitrate OR
+ * alternatively the CAN timing parameters (tq, prop_seg, etc.) are
+ * provided directly which are then checked and fixed up.
+ */
+ if (!bt->tq && bt->bitrate)
+ err = can_calc_bittiming(dev, bt, btc);
+ else if (bt->tq && !bt->bitrate)
+ err = can_fixup_bittiming(dev, bt, btc);
+ else
+ err = -EINVAL;
- return 0;
+ return err;
}
/*
@@ -317,28 +315,20 @@ void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
BUG_ON(idx >= priv->echo_skb_max);
/* check flag whether this packet has to be looped back */
- if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK) {
+ if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK ||
+ (skb->protocol != htons(ETH_P_CAN) &&
+ skb->protocol != htons(ETH_P_CANFD))) {
kfree_skb(skb);
return;
}
if (!priv->echo_skb[idx]) {
- struct sock *srcsk = skb->sk;
- if (atomic_read(&skb->users) != 1) {
- struct sk_buff *old_skb = skb;
-
- skb = skb_clone(old_skb, GFP_ATOMIC);
- kfree_skb(old_skb);
- if (!skb)
- return;
- } else
- skb_orphan(skb);
-
- skb->sk = srcsk;
+ skb = can_create_echo_skb(skb);
+ if (!skb)
+ return;
/* make settings for echo to reduce code in irq context */
- skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY;
skb->dev = dev;
@@ -521,6 +511,30 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
}
EXPORT_SYMBOL_GPL(alloc_can_skb);
+struct sk_buff *alloc_canfd_skb(struct net_device *dev,
+ struct canfd_frame **cfd)
+{
+ struct sk_buff *skb;
+
+ skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
+ sizeof(struct canfd_frame));
+ if (unlikely(!skb))
+ return NULL;
+
+ skb->protocol = htons(ETH_P_CANFD);
+ skb->pkt_type = PACKET_BROADCAST;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ can_skb_reserve(skb);
+ can_skb_prv(skb)->ifindex = dev->ifindex;
+
+ *cfd = (struct canfd_frame *)skb_put(skb, sizeof(struct canfd_frame));
+ memset(*cfd, 0, sizeof(struct canfd_frame));
+
+ return skb;
+}
+EXPORT_SYMBOL_GPL(alloc_canfd_skb);
+
struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf)
{
struct sk_buff *skb;
@@ -581,6 +595,39 @@ void free_candev(struct net_device *dev)
EXPORT_SYMBOL_GPL(free_candev);
/*
+ * changing MTU and control mode for CAN/CANFD devices
+ */
+int can_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct can_priv *priv = netdev_priv(dev);
+
+ /* Do not allow changing the MTU while running */
+ if (dev->flags & IFF_UP)
+ return -EBUSY;
+
+ /* allow change of MTU according to the CANFD ability of the device */
+ switch (new_mtu) {
+ case CAN_MTU:
+ priv->ctrlmode &= ~CAN_CTRLMODE_FD;
+ break;
+
+ case CANFD_MTU:
+ if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD))
+ return -EINVAL;
+
+ priv->ctrlmode |= CAN_CTRLMODE_FD;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ dev->mtu = new_mtu;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(can_change_mtu);
+
+/*
* Common open function when the device gets opened.
*
* This function should be called in the open function of the device
@@ -590,11 +637,19 @@ int open_candev(struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
- if (!priv->bittiming.tq && !priv->bittiming.bitrate) {
+ if (!priv->bittiming.bitrate) {
netdev_err(dev, "bit-timing not yet defined\n");
return -EINVAL;
}
+ /* For CAN FD the data bitrate has to be >= the arbitration bitrate */
+ if ((priv->ctrlmode & CAN_CTRLMODE_FD) &&
+ (!priv->data_bittiming.bitrate ||
+ (priv->data_bittiming.bitrate < priv->bittiming.bitrate))) {
+ netdev_err(dev, "incorrect/missing data bit-timing\n");
+ return -EINVAL;
+ }
+
/* Switch carrier on if device was stopped while in bus-off state */
if (!netif_carrier_ok(dev))
netif_carrier_on(dev);
@@ -633,6 +688,10 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
= { .len = sizeof(struct can_bittiming_const) },
[IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) },
[IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) },
+ [IFLA_CAN_DATA_BITTIMING]
+ = { .len = sizeof(struct can_bittiming) },
+ [IFLA_CAN_DATA_BITTIMING_CONST]
+ = { .len = sizeof(struct can_bittiming_const) },
};
static int can_changelink(struct net_device *dev,
@@ -651,9 +710,7 @@ static int can_changelink(struct net_device *dev,
if (dev->flags & IFF_UP)
return -EBUSY;
memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
- if ((!bt.bitrate && !bt.tq) || (bt.bitrate && bt.tq))
- return -EINVAL;
- err = can_get_bittiming(dev, &bt);
+ err = can_get_bittiming(dev, &bt, priv->bittiming_const);
if (err)
return err;
memcpy(&priv->bittiming, &bt, sizeof(bt));
@@ -677,6 +734,12 @@ static int can_changelink(struct net_device *dev,
return -EOPNOTSUPP;
priv->ctrlmode &= ~cm->mask;
priv->ctrlmode |= cm->flags;
+
+ /* CAN_CTRLMODE_FD can only be set when driver supports FD */
+ if (priv->ctrlmode & CAN_CTRLMODE_FD)
+ dev->mtu = CANFD_MTU;
+ else
+ dev->mtu = CAN_MTU;
}
if (data[IFLA_CAN_RESTART_MS]) {
@@ -695,6 +758,27 @@ static int can_changelink(struct net_device *dev,
return err;
}
+ if (data[IFLA_CAN_DATA_BITTIMING]) {
+ struct can_bittiming dbt;
+
+ /* Do not allow changing bittiming while running */
+ if (dev->flags & IFF_UP)
+ return -EBUSY;
+ memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]),
+ sizeof(dbt));
+ err = can_get_bittiming(dev, &dbt, priv->data_bittiming_const);
+ if (err)
+ return err;
+ memcpy(&priv->data_bittiming, &dbt, sizeof(dbt));
+
+ if (priv->do_set_data_bittiming) {
+ /* Finally, set the bit-timing registers */
+ err = priv->do_set_data_bittiming(dev);
+ if (err)
+ return err;
+ }
+ }
+
return 0;
}
@@ -703,7 +787,8 @@ static size_t can_get_size(const struct net_device *dev)
struct can_priv *priv = netdev_priv(dev);
size_t size = 0;
- size += nla_total_size(sizeof(struct can_bittiming)); /* IFLA_CAN_BITTIMING */
+ if (priv->bittiming.bitrate) /* IFLA_CAN_BITTIMING */
+ size += nla_total_size(sizeof(struct can_bittiming));
if (priv->bittiming_const) /* IFLA_CAN_BITTIMING_CONST */
size += nla_total_size(sizeof(struct can_bittiming_const));
size += nla_total_size(sizeof(struct can_clock)); /* IFLA_CAN_CLOCK */
@@ -712,6 +797,10 @@ static size_t can_get_size(const struct net_device *dev)
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */
if (priv->do_get_berr_counter) /* IFLA_CAN_BERR_COUNTER */
size += nla_total_size(sizeof(struct can_berr_counter));
+ if (priv->data_bittiming.bitrate) /* IFLA_CAN_DATA_BITTIMING */
+ size += nla_total_size(sizeof(struct can_bittiming));
+ if (priv->data_bittiming_const) /* IFLA_CAN_DATA_BITTIMING_CONST */
+ size += nla_total_size(sizeof(struct can_bittiming_const));
return size;
}
@@ -725,19 +814,34 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
if (priv->do_get_state)
priv->do_get_state(dev, &state);
- if (nla_put(skb, IFLA_CAN_BITTIMING,
- sizeof(priv->bittiming), &priv->bittiming) ||
+
+ if ((priv->bittiming.bitrate &&
+ nla_put(skb, IFLA_CAN_BITTIMING,
+ sizeof(priv->bittiming), &priv->bittiming)) ||
+
(priv->bittiming_const &&
nla_put(skb, IFLA_CAN_BITTIMING_CONST,
sizeof(*priv->bittiming_const), priv->bittiming_const)) ||
+
nla_put(skb, IFLA_CAN_CLOCK, sizeof(cm), &priv->clock) ||
nla_put_u32(skb, IFLA_CAN_STATE, state) ||
nla_put(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm) ||
nla_put_u32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms) ||
+
(priv->do_get_berr_counter &&
!priv->do_get_berr_counter(dev, &bec) &&
- nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)))
+ nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) ||
+
+ (priv->data_bittiming.bitrate &&
+ nla_put(skb, IFLA_CAN_DATA_BITTIMING,
+ sizeof(priv->data_bittiming), &priv->data_bittiming)) ||
+
+ (priv->data_bittiming_const &&
+ nla_put(skb, IFLA_CAN_DATA_BITTIMING_CONST,
+ sizeof(*priv->data_bittiming_const),
+ priv->data_bittiming_const)))
return -EMSGSIZE;
+
return 0;
}
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index aaed97bee471..f425ec2c7839 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -144,6 +144,8 @@
#define FLEXCAN_MB_CODE_MASK (0xf0ffffff)
+#define FLEXCAN_TIMEOUT_US (50)
+
/*
* FLEXCAN hardware feature flags
*
@@ -235,9 +237,12 @@ static const struct can_bittiming_const flexcan_bittiming_const = {
};
/*
- * Abstract off the read/write for arm versus ppc.
+ * Abstract off the read/write for arm versus ppc. This
+ * assumes that PPC uses big-endian registers and everything
+ * else uses little-endian registers, independent of CPU
+ * endianess.
*/
-#if defined(__BIG_ENDIAN)
+#if defined(CONFIG_PPC)
static inline u32 flexcan_read(void __iomem *addr)
{
return in_be32(addr);
@@ -259,6 +264,22 @@ static inline void flexcan_write(u32 val, void __iomem *addr)
}
#endif
+static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv)
+{
+ if (!priv->reg_xceiver)
+ return 0;
+
+ return regulator_enable(priv->reg_xceiver);
+}
+
+static inline int flexcan_transceiver_disable(const struct flexcan_priv *priv)
+{
+ if (!priv->reg_xceiver)
+ return 0;
+
+ return regulator_disable(priv->reg_xceiver);
+}
+
static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv,
u32 reg_esr)
{
@@ -266,26 +287,95 @@ static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv,
(reg_esr & FLEXCAN_ESR_ERR_BUS);
}
-static inline void flexcan_chip_enable(struct flexcan_priv *priv)
+static int flexcan_chip_enable(struct flexcan_priv *priv)
{
struct flexcan_regs __iomem *regs = priv->base;
+ unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
u32 reg;
reg = flexcan_read(&regs->mcr);
reg &= ~FLEXCAN_MCR_MDIS;
flexcan_write(reg, &regs->mcr);
- udelay(10);
+ while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+ usleep_range(10, 20);
+
+ if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK)
+ return -ETIMEDOUT;
+
+ return 0;
}
-static inline void flexcan_chip_disable(struct flexcan_priv *priv)
+static int flexcan_chip_disable(struct flexcan_priv *priv)
{
struct flexcan_regs __iomem *regs = priv->base;
+ unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
u32 reg;
reg = flexcan_read(&regs->mcr);
reg |= FLEXCAN_MCR_MDIS;
flexcan_write(reg, &regs->mcr);
+
+ while (timeout-- && !(flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+ usleep_range(10, 20);
+
+ if (!(flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int flexcan_chip_freeze(struct flexcan_priv *priv)
+{
+ struct flexcan_regs __iomem *regs = priv->base;
+ unsigned int timeout = 1000 * 1000 * 10 / priv->can.bittiming.bitrate;
+ u32 reg;
+
+ reg = flexcan_read(&regs->mcr);
+ reg |= FLEXCAN_MCR_HALT;
+ flexcan_write(reg, &regs->mcr);
+
+ while (timeout-- && !(flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
+ usleep_range(100, 200);
+
+ if (!(flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int flexcan_chip_unfreeze(struct flexcan_priv *priv)
+{
+ struct flexcan_regs __iomem *regs = priv->base;
+ unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
+ u32 reg;
+
+ reg = flexcan_read(&regs->mcr);
+ reg &= ~FLEXCAN_MCR_HALT;
+ flexcan_write(reg, &regs->mcr);
+
+ while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
+ usleep_range(10, 20);
+
+ if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int flexcan_chip_softreset(struct flexcan_priv *priv)
+{
+ struct flexcan_regs __iomem *regs = priv->base;
+ unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
+
+ flexcan_write(FLEXCAN_MCR_SOFTRST, &regs->mcr);
+ while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_SOFTRST))
+ usleep_range(10, 20);
+
+ if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_SOFTRST)
+ return -ETIMEDOUT;
+
+ return 0;
}
static int flexcan_get_berr_counter(const struct net_device *dev,
@@ -706,19 +796,14 @@ static int flexcan_chip_start(struct net_device *dev)
u32 reg_mcr, reg_ctrl;
/* enable module */
- flexcan_chip_enable(priv);
+ err = flexcan_chip_enable(priv);
+ if (err)
+ return err;
/* soft reset */
- flexcan_write(FLEXCAN_MCR_SOFTRST, &regs->mcr);
- udelay(10);
-
- reg_mcr = flexcan_read(&regs->mcr);
- if (reg_mcr & FLEXCAN_MCR_SOFTRST) {
- netdev_err(dev, "Failed to softreset can module (mcr=0x%08x)\n",
- reg_mcr);
- err = -ENODEV;
- goto out;
- }
+ err = flexcan_chip_softreset(priv);
+ if (err)
+ goto out_chip_disable;
flexcan_set_bittiming(dev);
@@ -785,16 +870,14 @@ static int flexcan_chip_start(struct net_device *dev)
if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES)
flexcan_write(0x0, &regs->rxfgmask);
- if (priv->reg_xceiver) {
- err = regulator_enable(priv->reg_xceiver);
- if (err)
- goto out;
- }
+ err = flexcan_transceiver_enable(priv);
+ if (err)
+ goto out_chip_disable;
/* synchronize with the can bus */
- reg_mcr = flexcan_read(&regs->mcr);
- reg_mcr &= ~FLEXCAN_MCR_HALT;
- flexcan_write(reg_mcr, &regs->mcr);
+ err = flexcan_chip_unfreeze(priv);
+ if (err)
+ goto out_transceiver_disable;
priv->can.state = CAN_STATE_ERROR_ACTIVE;
@@ -807,7 +890,9 @@ static int flexcan_chip_start(struct net_device *dev)
return 0;
- out:
+ out_transceiver_disable:
+ flexcan_transceiver_disable(priv);
+ out_chip_disable:
flexcan_chip_disable(priv);
return err;
}
@@ -822,18 +907,17 @@ static void flexcan_chip_stop(struct net_device *dev)
{
struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->base;
- u32 reg;
+
+ /* freeze + disable module */
+ flexcan_chip_freeze(priv);
+ flexcan_chip_disable(priv);
/* Disable all interrupts */
flexcan_write(0, &regs->imask1);
+ flexcan_write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
+ &regs->ctrl);
- /* Disable + halt module */
- reg = flexcan_read(&regs->mcr);
- reg |= FLEXCAN_MCR_MDIS | FLEXCAN_MCR_HALT;
- flexcan_write(reg, &regs->mcr);
-
- if (priv->reg_xceiver)
- regulator_disable(priv->reg_xceiver);
+ flexcan_transceiver_disable(priv);
priv->can.state = CAN_STATE_STOPPED;
return;
@@ -863,7 +947,7 @@ static int flexcan_open(struct net_device *dev)
/* start chip and queuing */
err = flexcan_chip_start(dev);
if (err)
- goto out_close;
+ goto out_free_irq;
can_led_event(dev, CAN_LED_EVENT_OPEN);
@@ -872,6 +956,8 @@ static int flexcan_open(struct net_device *dev)
return 0;
+ out_free_irq:
+ free_irq(dev->irq, dev);
out_close:
close_candev(dev);
out_disable_per:
@@ -925,6 +1011,7 @@ static const struct net_device_ops flexcan_netdev_ops = {
.ndo_open = flexcan_open,
.ndo_stop = flexcan_close,
.ndo_start_xmit = flexcan_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
static int register_flexcandev(struct net_device *dev)
@@ -942,12 +1029,16 @@ static int register_flexcandev(struct net_device *dev)
goto out_disable_ipg;
/* select "bus clock", chip must be disabled */
- flexcan_chip_disable(priv);
+ err = flexcan_chip_disable(priv);
+ if (err)
+ goto out_disable_per;
reg = flexcan_read(&regs->ctrl);
reg |= FLEXCAN_CTRL_CLK_SRC;
flexcan_write(reg, &regs->ctrl);
- flexcan_chip_enable(priv);
+ err = flexcan_chip_enable(priv);
+ if (err)
+ goto out_chip_disable;
/* set freeze, halt and activate FIFO, restrict register access */
reg = flexcan_read(&regs->mcr);
@@ -964,14 +1055,15 @@ static int register_flexcandev(struct net_device *dev)
if (!(reg & FLEXCAN_MCR_FEN)) {
netdev_err(dev, "Could not enable RX FIFO, unsupported core\n");
err = -ENODEV;
- goto out_disable_per;
+ goto out_chip_disable;
}
err = register_candev(dev);
- out_disable_per:
/* disable core and turn off clocks */
+ out_chip_disable:
flexcan_chip_disable(priv);
+ out_disable_per:
clk_disable_unprepare(priv->clk_per);
out_disable_ipg:
clk_disable_unprepare(priv->clk_ipg);
@@ -1041,9 +1133,9 @@ static int flexcan_probe(struct platform_device *pdev)
of_id = of_match_device(flexcan_of_match, &pdev->dev);
if (of_id) {
devtype_data = of_id->data;
- } else if (pdev->id_entry->driver_data) {
+ } else if (platform_get_device_id(pdev)->driver_data) {
devtype_data = (struct flexcan_devtype_data *)
- pdev->id_entry->driver_data;
+ platform_get_device_id(pdev)->driver_data;
} else {
return -ENODEV;
}
@@ -1101,21 +1193,24 @@ static int flexcan_probe(struct platform_device *pdev)
static int flexcan_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
+ struct flexcan_priv *priv = netdev_priv(dev);
unregister_flexcandev(dev);
-
+ netif_napi_del(&priv->napi);
free_candev(dev);
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int flexcan_suspend(struct device *device)
+static int __maybe_unused flexcan_suspend(struct device *device)
{
struct net_device *dev = dev_get_drvdata(device);
struct flexcan_priv *priv = netdev_priv(dev);
+ int err;
- flexcan_chip_disable(priv);
+ err = flexcan_chip_disable(priv);
+ if (err)
+ return err;
if (netif_running(dev)) {
netif_stop_queue(dev);
@@ -1126,7 +1221,7 @@ static int flexcan_suspend(struct device *device)
return 0;
}
-static int flexcan_resume(struct device *device)
+static int __maybe_unused flexcan_resume(struct device *device)
{
struct net_device *dev = dev_get_drvdata(device);
struct flexcan_priv *priv = netdev_priv(dev);
@@ -1136,11 +1231,8 @@ static int flexcan_resume(struct device *device)
netif_device_attach(dev);
netif_start_queue(dev);
}
- flexcan_chip_enable(priv);
-
- return 0;
+ return flexcan_chip_enable(priv);
}
-#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(flexcan_pm_ops, flexcan_suspend, flexcan_resume);
diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index ab506d6cab37..3fd9fd942c6e 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -1578,6 +1578,7 @@ static const struct net_device_ops grcan_netdev_ops = {
.ndo_open = grcan_open,
.ndo_stop = grcan_close,
.ndo_start_xmit = grcan_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
static int grcan_setup_netdev(struct platform_device *ofdev,
diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c
index e24e6690d672..2382c04dc780 100644
--- a/drivers/net/can/janz-ican3.c
+++ b/drivers/net/can/janz-ican3.c
@@ -18,6 +18,7 @@
#include <linux/netdevice.h>
#include <linux/can.h>
#include <linux/can/dev.h>
+#include <linux/can/skb.h>
#include <linux/can/error.h>
#include <linux/mfd/janz.h>
@@ -197,9 +198,6 @@ struct ican3_dev {
struct net_device *ndev;
struct napi_struct napi;
- /* Device for printing */
- struct device *dev;
-
/* module number */
unsigned int num;
@@ -294,7 +292,7 @@ static int ican3_old_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg)
xord = locl ^ peer;
if ((xord & MSYNC_RB_MASK) == 0x00) {
- dev_dbg(mod->dev, "no mbox for reading\n");
+ netdev_dbg(mod->ndev, "no mbox for reading\n");
return -ENOMEM;
}
@@ -339,7 +337,7 @@ static int ican3_old_send_msg(struct ican3_dev *mod, struct ican3_msg *msg)
xord = locl ^ peer;
if ((xord & MSYNC_WB_MASK) == MSYNC_WB_MASK) {
- dev_err(mod->dev, "no mbox for writing\n");
+ netdev_err(mod->ndev, "no mbox for writing\n");
return -ENOMEM;
}
@@ -541,7 +539,7 @@ static int ican3_new_send_msg(struct ican3_dev *mod, struct ican3_msg *msg)
memcpy_fromio(&desc, desc_addr, sizeof(desc));
if (!(desc.control & DESC_VALID)) {
- dev_dbg(mod->dev, "%s: no free buffers\n", __func__);
+ netdev_dbg(mod->ndev, "%s: no free buffers\n", __func__);
return -ENOMEM;
}
@@ -572,7 +570,7 @@ static int ican3_new_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg)
memcpy_fromio(&desc, desc_addr, sizeof(desc));
if (!(desc.control & DESC_VALID)) {
- dev_dbg(mod->dev, "%s: no buffers to recv\n", __func__);
+ netdev_dbg(mod->ndev, "%s: no buffers to recv\n", __func__);
return -ENOMEM;
}
@@ -882,7 +880,7 @@ static void can_frame_to_ican3(struct ican3_dev *mod,
*/
static void ican3_handle_idvers(struct ican3_dev *mod, struct ican3_msg *msg)
{
- dev_dbg(mod->dev, "IDVERS response: %s\n", msg->data);
+ netdev_dbg(mod->ndev, "IDVERS response: %s\n", msg->data);
}
static void ican3_handle_msglost(struct ican3_dev *mod, struct ican3_msg *msg)
@@ -898,7 +896,7 @@ static void ican3_handle_msglost(struct ican3_dev *mod, struct ican3_msg *msg)
* error frame for userspace
*/
if (msg->spec == MSG_MSGLOST) {
- dev_err(mod->dev, "lost %d control messages\n", msg->data[0]);
+ netdev_err(mod->ndev, "lost %d control messages\n", msg->data[0]);
return;
}
@@ -938,13 +936,13 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
/* we can only handle the SJA1000 part */
if (msg->data[1] != CEVTIND_CHIP_SJA1000) {
- dev_err(mod->dev, "unable to handle errors on non-SJA1000\n");
+ netdev_err(mod->ndev, "unable to handle errors on non-SJA1000\n");
return -ENODEV;
}
/* check the message length for sanity */
if (le16_to_cpu(msg->len) < 6) {
- dev_err(mod->dev, "error message too short\n");
+ netdev_err(mod->ndev, "error message too short\n");
return -EINVAL;
}
@@ -966,7 +964,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
*/
if (isrc == CEVTIND_BEI) {
int ret;
- dev_dbg(mod->dev, "bus error interrupt\n");
+ netdev_dbg(mod->ndev, "bus error interrupt\n");
/* TX error */
if (!(ecc & ECC_DIR)) {
@@ -982,7 +980,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
*/
ret = ican3_set_buserror(mod, 1);
if (ret) {
- dev_err(mod->dev, "unable to re-enable bus-error\n");
+ netdev_err(mod->ndev, "unable to re-enable bus-error\n");
return ret;
}
@@ -997,7 +995,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
/* data overrun interrupt */
if (isrc == CEVTIND_DOI || isrc == CEVTIND_LOST) {
- dev_dbg(mod->dev, "data overrun interrupt\n");
+ netdev_dbg(mod->ndev, "data overrun interrupt\n");
cf->can_id |= CAN_ERR_CRTL;
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
stats->rx_over_errors++;
@@ -1006,7 +1004,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
/* error warning + passive interrupt */
if (isrc == CEVTIND_EI) {
- dev_dbg(mod->dev, "error warning + passive interrupt\n");
+ netdev_dbg(mod->ndev, "error warning + passive interrupt\n");
if (status & SR_BS) {
state = CAN_STATE_BUS_OFF;
cf->can_id |= CAN_ERR_BUSOFF;
@@ -1087,7 +1085,7 @@ static void ican3_handle_inquiry(struct ican3_dev *mod, struct ican3_msg *msg)
complete(&mod->termination_comp);
break;
default:
- dev_err(mod->dev, "received an unknown inquiry response\n");
+ netdev_err(mod->ndev, "received an unknown inquiry response\n");
break;
}
}
@@ -1095,7 +1093,7 @@ static void ican3_handle_inquiry(struct ican3_dev *mod, struct ican3_msg *msg)
static void ican3_handle_unknown_message(struct ican3_dev *mod,
struct ican3_msg *msg)
{
- dev_warn(mod->dev, "received unknown message: spec 0x%.2x length %d\n",
+ netdev_warn(mod->ndev, "received unknown message: spec 0x%.2x length %d\n",
msg->spec, le16_to_cpu(msg->len));
}
@@ -1104,7 +1102,7 @@ static void ican3_handle_unknown_message(struct ican3_dev *mod,
*/
static void ican3_handle_message(struct ican3_dev *mod, struct ican3_msg *msg)
{
- dev_dbg(mod->dev, "%s: modno %d spec 0x%.2x len %d bytes\n", __func__,
+ netdev_dbg(mod->ndev, "%s: modno %d spec 0x%.2x len %d bytes\n", __func__,
mod->num, msg->spec, le16_to_cpu(msg->len));
switch (msg->spec) {
@@ -1133,20 +1131,9 @@ static void ican3_handle_message(struct ican3_dev *mod, struct ican3_msg *msg)
*/
static void ican3_put_echo_skb(struct ican3_dev *mod, struct sk_buff *skb)
{
- struct sock *srcsk = skb->sk;
-
- if (atomic_read(&skb->users) != 1) {
- struct sk_buff *old_skb = skb;
-
- skb = skb_clone(old_skb, GFP_ATOMIC);
- kfree_skb(old_skb);
- if (!skb)
- return;
- } else {
- skb_orphan(skb);
- }
-
- skb->sk = srcsk;
+ skb = can_create_echo_skb(skb);
+ if (!skb)
+ return;
/* save this skb for tx interrupt echo handling */
skb_queue_tail(&mod->echoq, skb);
@@ -1322,7 +1309,7 @@ static int ican3_napi(struct napi_struct *napi, int budget)
/* process all communication messages */
while (true) {
- struct ican3_msg msg;
+ struct ican3_msg uninitialized_var(msg);
ret = ican3_recv_msg(mod, &msg);
if (ret)
break;
@@ -1416,7 +1403,7 @@ static int ican3_reset_module(struct ican3_dev *mod)
msleep(10);
} while (time_before(jiffies, start + HZ / 4));
- dev_err(mod->dev, "failed to reset CAN module\n");
+ netdev_err(mod->ndev, "failed to reset CAN module\n");
return -ETIMEDOUT;
}
@@ -1435,7 +1422,7 @@ static int ican3_startup_module(struct ican3_dev *mod)
ret = ican3_reset_module(mod);
if (ret) {
- dev_err(mod->dev, "unable to reset module\n");
+ netdev_err(mod->ndev, "unable to reset module\n");
return ret;
}
@@ -1444,41 +1431,41 @@ static int ican3_startup_module(struct ican3_dev *mod)
ret = ican3_msg_connect(mod);
if (ret) {
- dev_err(mod->dev, "unable to connect to module\n");
+ netdev_err(mod->ndev, "unable to connect to module\n");
return ret;
}
ican3_init_new_host_interface(mod);
ret = ican3_msg_newhostif(mod);
if (ret) {
- dev_err(mod->dev, "unable to switch to new-style interface\n");
+ netdev_err(mod->ndev, "unable to switch to new-style interface\n");
return ret;
}
/* default to "termination on" */
ret = ican3_set_termination(mod, true);
if (ret) {
- dev_err(mod->dev, "unable to enable termination\n");
+ netdev_err(mod->ndev, "unable to enable termination\n");
return ret;
}
/* default to "bus errors enabled" */
ret = ican3_set_buserror(mod, 1);
if (ret) {
- dev_err(mod->dev, "unable to set bus-error\n");
+ netdev_err(mod->ndev, "unable to set bus-error\n");
return ret;
}
ican3_init_fast_host_interface(mod);
ret = ican3_msg_fasthostif(mod);
if (ret) {
- dev_err(mod->dev, "unable to switch to fast host interface\n");
+ netdev_err(mod->ndev, "unable to switch to fast host interface\n");
return ret;
}
ret = ican3_set_id_filter(mod, true);
if (ret) {
- dev_err(mod->dev, "unable to set acceptance filter\n");
+ netdev_err(mod->ndev, "unable to set acceptance filter\n");
return ret;
}
@@ -1497,14 +1484,14 @@ static int ican3_open(struct net_device *ndev)
/* open the CAN layer */
ret = open_candev(ndev);
if (ret) {
- dev_err(mod->dev, "unable to start CAN layer\n");
+ netdev_err(mod->ndev, "unable to start CAN layer\n");
return ret;
}
/* bring the bus online */
ret = ican3_set_bus_state(mod, true);
if (ret) {
- dev_err(mod->dev, "unable to set bus-on\n");
+ netdev_err(mod->ndev, "unable to set bus-on\n");
close_candev(ndev);
return ret;
}
@@ -1528,7 +1515,7 @@ static int ican3_stop(struct net_device *ndev)
/* bring the bus offline, stop receiving packets */
ret = ican3_set_bus_state(mod, false);
if (ret) {
- dev_err(mod->dev, "unable to set bus-off\n");
+ netdev_err(mod->ndev, "unable to set bus-off\n");
return ret;
}
@@ -1555,7 +1542,7 @@ static int ican3_xmit(struct sk_buff *skb, struct net_device *ndev)
/* check that we can actually transmit */
if (!ican3_txok(mod)) {
- dev_err(mod->dev, "BUG: no free descriptors\n");
+ netdev_err(mod->ndev, "BUG: no free descriptors\n");
spin_unlock_irqrestore(&mod->lock, flags);
return NETDEV_TX_BUSY;
}
@@ -1607,6 +1594,7 @@ static const struct net_device_ops ican3_netdev_ops = {
.ndo_open = ican3_open,
.ndo_stop = ican3_stop,
.ndo_start_xmit = ican3_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
/*
@@ -1667,7 +1655,7 @@ static int ican3_set_mode(struct net_device *ndev, enum can_mode mode)
/* bring the bus online */
ret = ican3_set_bus_state(mod, true);
if (ret) {
- dev_err(mod->dev, "unable to set bus-on\n");
+ netdev_err(ndev, "unable to set bus-on\n");
return ret;
}
@@ -1692,7 +1680,7 @@ static int ican3_get_berr_counter(const struct net_device *ndev,
ret = wait_for_completion_timeout(&mod->buserror_comp, HZ);
if (ret == 0) {
- dev_info(mod->dev, "%s timed out\n", __func__);
+ netdev_info(mod->ndev, "%s timed out\n", __func__);
return -ETIMEDOUT;
}
@@ -1718,7 +1706,7 @@ static ssize_t ican3_sysfs_show_term(struct device *dev,
ret = wait_for_completion_timeout(&mod->termination_comp, HZ);
if (ret == 0) {
- dev_info(mod->dev, "%s timed out\n", __func__);
+ netdev_info(mod->ndev, "%s timed out\n", __func__);
return -ETIMEDOUT;
}
@@ -1788,7 +1776,6 @@ static int ican3_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ndev);
mod = netdev_priv(ndev);
mod->ndev = ndev;
- mod->dev = &pdev->dev;
mod->num = pdata->modno;
netif_napi_add(ndev, &mod->napi, ican3_napi, ICAN3_RX_BUFFERS);
skb_queue_head_init(&mod->echoq);
diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c
index cdb9808d12db..28c11f815245 100644
--- a/drivers/net/can/mcp251x.c
+++ b/drivers/net/can/mcp251x.c
@@ -601,10 +601,10 @@ static int mcp251x_do_set_bittiming(struct net_device *net)
(bt->prop_seg - 1));
mcp251x_write_bits(spi, CNF3, CNF3_PHSEG2_MASK,
(bt->phase_seg2 - 1));
- dev_info(&spi->dev, "CNF: 0x%02x 0x%02x 0x%02x\n",
- mcp251x_read_reg(spi, CNF1),
- mcp251x_read_reg(spi, CNF2),
- mcp251x_read_reg(spi, CNF3));
+ dev_dbg(&spi->dev, "CNF: 0x%02x 0x%02x 0x%02x\n",
+ mcp251x_read_reg(spi, CNF1),
+ mcp251x_read_reg(spi, CNF2),
+ mcp251x_read_reg(spi, CNF3));
return 0;
}
@@ -672,7 +672,7 @@ static int mcp251x_hw_probe(struct spi_device *spi)
static int mcp251x_power_enable(struct regulator *reg, int enable)
{
- if (IS_ERR(reg))
+ if (IS_ERR_OR_NULL(reg))
return 0;
if (enable)
@@ -996,6 +996,7 @@ static const struct net_device_ops mcp251x_netdev_ops = {
.ndo_open = mcp251x_open,
.ndo_stop = mcp251x_stop,
.ndo_start_xmit = mcp251x_hard_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
static const struct of_device_id mcp251x_of_match[] = {
@@ -1155,8 +1156,6 @@ static int mcp251x_can_probe(struct spi_device *spi)
devm_can_led_init(net);
- dev_info(&spi->dev, "probed\n");
-
return ret;
error_probe:
@@ -1197,9 +1196,7 @@ static int mcp251x_can_remove(struct spi_device *spi)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-
-static int mcp251x_can_suspend(struct device *dev)
+static int __maybe_unused mcp251x_can_suspend(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct mcp251x_priv *priv = spi_get_drvdata(spi);
@@ -1221,7 +1218,7 @@ static int mcp251x_can_suspend(struct device *dev)
priv->after_suspend = AFTER_SUSPEND_DOWN;
}
- if (!IS_ERR(priv->power)) {
+ if (!IS_ERR_OR_NULL(priv->power)) {
regulator_disable(priv->power);
priv->after_suspend |= AFTER_SUSPEND_POWER;
}
@@ -1229,7 +1226,7 @@ static int mcp251x_can_suspend(struct device *dev)
return 0;
}
-static int mcp251x_can_resume(struct device *dev)
+static int __maybe_unused mcp251x_can_resume(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct mcp251x_priv *priv = spi_get_drvdata(spi);
@@ -1249,7 +1246,6 @@ static int mcp251x_can_resume(struct device *dev)
enable_irq(spi->irq);
return 0;
}
-#endif
static SIMPLE_DEV_PM_OPS(mcp251x_can_pm_ops, mcp251x_can_suspend,
mcp251x_can_resume);
diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c
index b9f3faabb0f3..e0c9be5e2ab7 100644
--- a/drivers/net/can/mscan/mscan.c
+++ b/drivers/net/can/mscan/mscan.c
@@ -647,9 +647,10 @@ static int mscan_close(struct net_device *dev)
}
static const struct net_device_ops mscan_netdev_ops = {
- .ndo_open = mscan_open,
- .ndo_stop = mscan_close,
- .ndo_start_xmit = mscan_start_xmit,
+ .ndo_open = mscan_open,
+ .ndo_stop = mscan_close,
+ .ndo_start_xmit = mscan_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
int register_mscandev(struct net_device *dev, int mscan_clksrc)
diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c
index 6c077eb87b5e..6472562efedc 100644
--- a/drivers/net/can/pch_can.c
+++ b/drivers/net/can/pch_can.c
@@ -950,6 +950,7 @@ static const struct net_device_ops pch_can_netdev_ops = {
.ndo_open = pch_can_open,
.ndo_stop = pch_close,
.ndo_start_xmit = pch_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
static void pch_can_remove(struct pci_dev *pdev)
diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
index ff2ba86cd4a4..4b18b8765523 100644
--- a/drivers/net/can/sja1000/Kconfig
+++ b/drivers/net/can/sja1000/Kconfig
@@ -17,16 +17,9 @@ config CAN_SJA1000_PLATFORM
the "platform bus" (Linux abstraction for directly to the
processor attached devices). Which can be found on various
boards from Phytec (http://www.phytec.de) like the PCM027,
- PCM038.
-
-config CAN_SJA1000_OF_PLATFORM
- tristate "Generic OF Platform Bus based SJA1000 driver"
- depends on OF
- ---help---
- This driver adds support for the SJA1000 chips connected to
- the OpenFirmware "platform bus" found on embedded systems with
- OpenFirmware bindings, e.g. if you have a PowerPC based system
- you may want to enable this option.
+ PCM038. It also provides the OpenFirmware "platform bus" found
+ on embedded systems with OpenFirmware bindings, e.g. if you
+ have a PowerPC based system you may want to enable this option.
config CAN_EMS_PCMCIA
tristate "EMS CPC-CARD Card"
diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile
index b3d05cbfec36..531d5fcc97e5 100644
--- a/drivers/net/can/sja1000/Makefile
+++ b/drivers/net/can/sja1000/Makefile
@@ -5,7 +5,6 @@
obj-$(CONFIG_CAN_SJA1000) += sja1000.o
obj-$(CONFIG_CAN_SJA1000_ISA) += sja1000_isa.o
obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o
-obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
obj-$(CONFIG_CAN_EMS_PCMCIA) += ems_pcmcia.o
obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o
obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o
diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c
index d790b874ca79..fd13dbf07d9c 100644
--- a/drivers/net/can/sja1000/ems_pci.c
+++ b/drivers/net/can/sja1000/ems_pci.c
@@ -323,6 +323,7 @@ static int ems_pci_add_card(struct pci_dev *pdev,
priv->cdr = EMS_PCI_CDR;
SET_NETDEV_DEV(dev, &pdev->dev);
+ dev->dev_id = i;
if (card->version == 1)
/* reset int flag of pita */
diff --git a/drivers/net/can/sja1000/ems_pcmcia.c b/drivers/net/can/sja1000/ems_pcmcia.c
index 9e535f2ef52b..381de998d2f1 100644
--- a/drivers/net/can/sja1000/ems_pcmcia.c
+++ b/drivers/net/can/sja1000/ems_pcmcia.c
@@ -211,6 +211,7 @@ static int ems_pcmcia_add_card(struct pcmcia_device *pdev, unsigned long base)
priv = netdev_priv(dev);
priv->priv = card;
SET_NETDEV_DEV(dev, &pdev->dev);
+ dev->dev_id = i;
priv->irq_flags = IRQF_SHARED;
dev->irq = pdev->irq;
diff --git a/drivers/net/can/sja1000/kvaser_pci.c b/drivers/net/can/sja1000/kvaser_pci.c
index c96eb14699d5..23b8e1324e25 100644
--- a/drivers/net/can/sja1000/kvaser_pci.c
+++ b/drivers/net/can/sja1000/kvaser_pci.c
@@ -270,6 +270,7 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel,
priv->reg_base, board->conf_addr, dev->irq);
SET_NETDEV_DEV(dev, &pdev->dev);
+ dev->dev_id = channel;
/* Register SJA1000 device */
err = register_sja1000dev(dev);
diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c
index 065ca49eb45e..c540e3d12e3d 100644
--- a/drivers/net/can/sja1000/peak_pci.c
+++ b/drivers/net/can/sja1000/peak_pci.c
@@ -642,6 +642,7 @@ static int peak_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
icr |= chan->icr_mask;
SET_NETDEV_DEV(dev, &pdev->dev);
+ dev->dev_id = i;
/* Create chain of SJA1000 devices */
chan->prev_dev = pci_get_drvdata(pdev);
diff --git a/drivers/net/can/sja1000/peak_pcmcia.c b/drivers/net/can/sja1000/peak_pcmcia.c
index f7ad754dd2aa..dd56133cc461 100644
--- a/drivers/net/can/sja1000/peak_pcmcia.c
+++ b/drivers/net/can/sja1000/peak_pcmcia.c
@@ -550,6 +550,7 @@ static int pcan_add_channels(struct pcan_pccard *card)
priv = netdev_priv(netdev);
priv->priv = card;
SET_NETDEV_DEV(netdev, &pdev->dev);
+ netdev->dev_id = i;
priv->irq_flags = IRQF_SHARED;
netdev->irq = pdev->irq;
diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c
index fbb61a0d901f..ec39b7cb2287 100644
--- a/drivers/net/can/sja1000/plx_pci.c
+++ b/drivers/net/can/sja1000/plx_pci.c
@@ -587,6 +587,7 @@ static int plx_pci_add_card(struct pci_dev *pdev,
priv->cdr = ci->cdr;
SET_NETDEV_DEV(dev, &pdev->dev);
+ dev->dev_id = i;
/* Register SJA1000 device */
err = register_sja1000dev(dev);
diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c
index f17c3018b7c7..f31499a32d7d 100644
--- a/drivers/net/can/sja1000/sja1000.c
+++ b/drivers/net/can/sja1000/sja1000.c
@@ -106,8 +106,7 @@ static int sja1000_probe_chip(struct net_device *dev)
struct sja1000_priv *priv = netdev_priv(dev);
if (priv->reg_base && sja1000_is_absent(priv)) {
- printk(KERN_INFO "%s: probing @0x%lX failed\n",
- DRV_NAME, dev->base_addr);
+ netdev_err(dev, "probing failed\n");
return 0;
}
return -1;
@@ -643,9 +642,10 @@ void free_sja1000dev(struct net_device *dev)
EXPORT_SYMBOL_GPL(free_sja1000dev);
static const struct net_device_ops sja1000_netdev_ops = {
- .ndo_open = sja1000_open,
- .ndo_stop = sja1000_close,
- .ndo_start_xmit = sja1000_start_xmit,
+ .ndo_open = sja1000_open,
+ .ndo_stop = sja1000_close,
+ .ndo_start_xmit = sja1000_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
int register_sja1000dev(struct net_device *dev)
diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c
deleted file mode 100644
index 2f6e24534231..000000000000
--- a/drivers/net/can/sja1000/sja1000_of_platform.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Driver for SJA1000 CAN controllers on the OpenFirmware platform bus
- *
- * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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, see <http://www.gnu.org/licenses/>.
- */
-
-/* This is a generic driver for SJA1000 chips on the OpenFirmware platform
- * bus found on embedded PowerPC systems. You need a SJA1000 CAN node
- * definition in your flattened device tree source (DTS) file similar to:
- *
- * can@3,100 {
- * compatible = "nxp,sja1000";
- * reg = <3 0x100 0x80>;
- * interrupts = <2 0>;
- * interrupt-parent = <&mpic>;
- * nxp,external-clock-frequency = <16000000>;
- * };
- *
- * See "Documentation/devicetree/bindings/net/can/sja1000.txt" for further
- * information.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/can/dev.h>
-
-#include <linux/of_platform.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-
-#include "sja1000.h"
-
-#define DRV_NAME "sja1000_of_platform"
-
-MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
-MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the OF platform bus");
-MODULE_LICENSE("GPL v2");
-
-#define SJA1000_OFP_CAN_CLOCK (16000000 / 2)
-
-#define SJA1000_OFP_OCR OCR_TX0_PULLDOWN
-#define SJA1000_OFP_CDR (CDR_CBP | CDR_CLK_OFF)
-
-static u8 sja1000_ofp_read_reg(const struct sja1000_priv *priv, int reg)
-{
- return ioread8(priv->reg_base + reg);
-}
-
-static void sja1000_ofp_write_reg(const struct sja1000_priv *priv,
- int reg, u8 val)
-{
- iowrite8(val, priv->reg_base + reg);
-}
-
-static int sja1000_ofp_remove(struct platform_device *ofdev)
-{
- struct net_device *dev = platform_get_drvdata(ofdev);
- struct sja1000_priv *priv = netdev_priv(dev);
- struct device_node *np = ofdev->dev.of_node;
- struct resource res;
-
- unregister_sja1000dev(dev);
- free_sja1000dev(dev);
- iounmap(priv->reg_base);
- irq_dispose_mapping(dev->irq);
-
- of_address_to_resource(np, 0, &res);
- release_mem_region(res.start, resource_size(&res));
-
- return 0;
-}
-
-static int sja1000_ofp_probe(struct platform_device *ofdev)
-{
- struct device_node *np = ofdev->dev.of_node;
- struct net_device *dev;
- struct sja1000_priv *priv;
- struct resource res;
- u32 prop;
- int err, irq, res_size;
- void __iomem *base;
-
- err = of_address_to_resource(np, 0, &res);
- if (err) {
- dev_err(&ofdev->dev, "invalid address\n");
- return err;
- }
-
- res_size = resource_size(&res);
-
- if (!request_mem_region(res.start, res_size, DRV_NAME)) {
- dev_err(&ofdev->dev, "couldn't request %pR\n", &res);
- return -EBUSY;
- }
-
- base = ioremap_nocache(res.start, res_size);
- if (!base) {
- dev_err(&ofdev->dev, "couldn't ioremap %pR\n", &res);
- err = -ENOMEM;
- goto exit_release_mem;
- }
-
- irq = irq_of_parse_and_map(np, 0);
- if (irq == 0) {
- dev_err(&ofdev->dev, "no irq found\n");
- err = -ENODEV;
- goto exit_unmap_mem;
- }
-
- dev = alloc_sja1000dev(0);
- if (!dev) {
- err = -ENOMEM;
- goto exit_dispose_irq;
- }
-
- priv = netdev_priv(dev);
-
- priv->read_reg = sja1000_ofp_read_reg;
- priv->write_reg = sja1000_ofp_write_reg;
-
- err = of_property_read_u32(np, "nxp,external-clock-frequency", &prop);
- if (!err)
- priv->can.clock.freq = prop / 2;
- else
- priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */
-
- err = of_property_read_u32(np, "nxp,tx-output-mode", &prop);
- if (!err)
- priv->ocr |= prop & OCR_MODE_MASK;
- else
- priv->ocr |= OCR_MODE_NORMAL; /* default */
-
- err = of_property_read_u32(np, "nxp,tx-output-config", &prop);
- if (!err)
- priv->ocr |= (prop << OCR_TX_SHIFT) & OCR_TX_MASK;
- else
- priv->ocr |= OCR_TX0_PULLDOWN; /* default */
-
- err = of_property_read_u32(np, "nxp,clock-out-frequency", &prop);
- if (!err && prop) {
- u32 divider = priv->can.clock.freq * 2 / prop;
-
- if (divider > 1)
- priv->cdr |= divider / 2 - 1;
- else
- priv->cdr |= CDR_CLKOUT_MASK;
- } else {
- priv->cdr |= CDR_CLK_OFF; /* default */
- }
-
- if (!of_property_read_bool(np, "nxp,no-comparator-bypass"))
- priv->cdr |= CDR_CBP; /* default */
-
- priv->irq_flags = IRQF_SHARED;
- priv->reg_base = base;
-
- dev->irq = irq;
-
- dev_info(&ofdev->dev,
- "reg_base=0x%p irq=%d clock=%d ocr=0x%02x cdr=0x%02x\n",
- priv->reg_base, dev->irq, priv->can.clock.freq,
- priv->ocr, priv->cdr);
-
- platform_set_drvdata(ofdev, dev);
- SET_NETDEV_DEV(dev, &ofdev->dev);
-
- err = register_sja1000dev(dev);
- if (err) {
- dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
- DRV_NAME, err);
- goto exit_free_sja1000;
- }
-
- return 0;
-
-exit_free_sja1000:
- free_sja1000dev(dev);
-exit_dispose_irq:
- irq_dispose_mapping(irq);
-exit_unmap_mem:
- iounmap(base);
-exit_release_mem:
- release_mem_region(res.start, res_size);
-
- return err;
-}
-
-static struct of_device_id sja1000_ofp_table[] = {
- {.compatible = "nxp,sja1000"},
- {},
-};
-MODULE_DEVICE_TABLE(of, sja1000_ofp_table);
-
-static struct platform_driver sja1000_ofp_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = DRV_NAME,
- .of_match_table = sja1000_ofp_table,
- },
- .probe = sja1000_ofp_probe,
- .remove = sja1000_ofp_remove,
-};
-
-module_platform_driver(sja1000_ofp_driver);
diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c
index 943df645b459..95a844a7ee7b 100644
--- a/drivers/net/can/sja1000/sja1000_platform.c
+++ b/drivers/net/can/sja1000/sja1000_platform.c
@@ -26,12 +26,16 @@
#include <linux/can/dev.h>
#include <linux/can/platform/sja1000.h>
#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
#include "sja1000.h"
#define DRV_NAME "sja1000_platform"
+#define SP_CAN_CLOCK (16000000 / 2)
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus");
MODULE_ALIAS("platform:" DRV_NAME);
MODULE_LICENSE("GPL v2");
@@ -66,59 +70,16 @@ static void sp_write_reg32(const struct sja1000_priv *priv, int reg, u8 val)
iowrite8(val, priv->reg_base + reg * 4);
}
-static int sp_probe(struct platform_device *pdev)
+static void sp_populate(struct sja1000_priv *priv,
+ struct sja1000_platform_data *pdata,
+ unsigned long resource_mem_flags)
{
- int err;
- void __iomem *addr;
- struct net_device *dev;
- struct sja1000_priv *priv;
- struct resource *res_mem, *res_irq;
- struct sja1000_platform_data *pdata;
-
- pdata = dev_get_platdata(&pdev->dev);
- if (!pdata) {
- dev_err(&pdev->dev, "No platform data provided!\n");
- err = -ENODEV;
- goto exit;
- }
-
- res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res_mem || !res_irq) {
- err = -ENODEV;
- goto exit;
- }
-
- if (!request_mem_region(res_mem->start, resource_size(res_mem),
- DRV_NAME)) {
- err = -EBUSY;
- goto exit;
- }
-
- addr = ioremap_nocache(res_mem->start, resource_size(res_mem));
- if (!addr) {
- err = -ENOMEM;
- goto exit_release;
- }
-
- dev = alloc_sja1000dev(0);
- if (!dev) {
- err = -ENOMEM;
- goto exit_iounmap;
- }
- priv = netdev_priv(dev);
-
- dev->irq = res_irq->start;
- priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK;
- if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE)
- priv->irq_flags |= IRQF_SHARED;
- priv->reg_base = addr;
/* The CAN clock frequency is half the oscillator clock frequency */
priv->can.clock.freq = pdata->osc_freq / 2;
priv->ocr = pdata->ocr;
priv->cdr = pdata->cdr;
- switch (res_mem->flags & IORESOURCE_MEM_TYPE_MASK) {
+ switch (resource_mem_flags & IORESOURCE_MEM_TYPE_MASK) {
case IORESOURCE_MEM_32BIT:
priv->read_reg = sp_read_reg32;
priv->write_reg = sp_write_reg32;
@@ -133,6 +94,124 @@ static int sp_probe(struct platform_device *pdev)
priv->write_reg = sp_write_reg8;
break;
}
+}
+
+static void sp_populate_of(struct sja1000_priv *priv, struct device_node *of)
+{
+ int err;
+ u32 prop;
+
+ err = of_property_read_u32(of, "reg-io-width", &prop);
+ if (err)
+ prop = 1; /* 8 bit is default */
+
+ switch (prop) {
+ case 4:
+ priv->read_reg = sp_read_reg32;
+ priv->write_reg = sp_write_reg32;
+ break;
+ case 2:
+ priv->read_reg = sp_read_reg16;
+ priv->write_reg = sp_write_reg16;
+ break;
+ case 1: /* fallthrough */
+ default:
+ priv->read_reg = sp_read_reg8;
+ priv->write_reg = sp_write_reg8;
+ }
+
+ err = of_property_read_u32(of, "nxp,external-clock-frequency", &prop);
+ if (!err)
+ priv->can.clock.freq = prop / 2;
+ else
+ priv->can.clock.freq = SP_CAN_CLOCK; /* default */
+
+ err = of_property_read_u32(of, "nxp,tx-output-mode", &prop);
+ if (!err)
+ priv->ocr |= prop & OCR_MODE_MASK;
+ else
+ priv->ocr |= OCR_MODE_NORMAL; /* default */
+
+ err = of_property_read_u32(of, "nxp,tx-output-config", &prop);
+ if (!err)
+ priv->ocr |= (prop << OCR_TX_SHIFT) & OCR_TX_MASK;
+ else
+ priv->ocr |= OCR_TX0_PULLDOWN; /* default */
+
+ err = of_property_read_u32(of, "nxp,clock-out-frequency", &prop);
+ if (!err && prop) {
+ u32 divider = priv->can.clock.freq * 2 / prop;
+
+ if (divider > 1)
+ priv->cdr |= divider / 2 - 1;
+ else
+ priv->cdr |= CDR_CLKOUT_MASK;
+ } else {
+ priv->cdr |= CDR_CLK_OFF; /* default */
+ }
+
+ if (!of_property_read_bool(of, "nxp,no-comparator-bypass"))
+ priv->cdr |= CDR_CBP; /* default */
+}
+
+static int sp_probe(struct platform_device *pdev)
+{
+ int err, irq = 0;
+ void __iomem *addr;
+ struct net_device *dev;
+ struct sja1000_priv *priv;
+ struct resource *res_mem, *res_irq = NULL;
+ struct sja1000_platform_data *pdata;
+ struct device_node *of = pdev->dev.of_node;
+
+ pdata = dev_get_platdata(&pdev->dev);
+ if (!pdata && !of) {
+ dev_err(&pdev->dev, "No platform data provided!\n");
+ return -ENODEV;
+ }
+
+ res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res_mem)
+ return -ENODEV;
+
+ if (!devm_request_mem_region(&pdev->dev, res_mem->start,
+ resource_size(res_mem), DRV_NAME))
+ return -EBUSY;
+
+ addr = devm_ioremap_nocache(&pdev->dev, res_mem->start,
+ resource_size(res_mem));
+ if (!addr)
+ return -ENOMEM;
+
+ if (of)
+ irq = irq_of_parse_and_map(of, 0);
+ else
+ res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+
+ if (!irq && !res_irq)
+ return -ENODEV;
+
+ dev = alloc_sja1000dev(0);
+ if (!dev)
+ return -ENOMEM;
+ priv = netdev_priv(dev);
+
+ if (res_irq) {
+ irq = res_irq->start;
+ priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK;
+ if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE)
+ priv->irq_flags |= IRQF_SHARED;
+ } else {
+ priv->irq_flags = IRQF_SHARED;
+ }
+
+ dev->irq = irq;
+ priv->reg_base = addr;
+
+ if (of)
+ sp_populate_of(priv, of);
+ else
+ sp_populate(priv, pdata, res_mem->flags);
platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
@@ -150,39 +229,32 @@ static int sp_probe(struct platform_device *pdev)
exit_free:
free_sja1000dev(dev);
- exit_iounmap:
- iounmap(addr);
- exit_release:
- release_mem_region(res_mem->start, resource_size(res_mem));
- exit:
return err;
}
static int sp_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
- struct sja1000_priv *priv = netdev_priv(dev);
- struct resource *res;
unregister_sja1000dev(dev);
-
- if (priv->reg_base)
- iounmap(priv->reg_base);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
-
free_sja1000dev(dev);
return 0;
}
+static struct of_device_id sp_of_table[] = {
+ {.compatible = "nxp,sja1000"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, sp_of_table);
+
static struct platform_driver sp_driver = {
.probe = sp_probe,
.remove = sp_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
+ .of_match_table = sp_of_table,
},
};
diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
index 3fcdae266377..f5b16e0e3a12 100644
--- a/drivers/net/can/slcan.c
+++ b/drivers/net/can/slcan.c
@@ -411,10 +411,16 @@ static void slc_free_netdev(struct net_device *dev)
slcan_devs[i] = NULL;
}
+static int slcan_change_mtu(struct net_device *dev, int new_mtu)
+{
+ return -EINVAL;
+}
+
static const struct net_device_ops slc_netdev_ops = {
.ndo_open = slc_open,
.ndo_stop = slc_close,
.ndo_start_xmit = slc_xmit,
+ .ndo_change_mtu = slcan_change_mtu,
};
static void slc_setup(struct net_device *dev)
diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c
index 9ea0dcde94ce..7d8c8f3672dd 100644
--- a/drivers/net/can/softing/softing_main.c
+++ b/drivers/net/can/softing/softing_main.c
@@ -628,6 +628,7 @@ static const struct net_device_ops softing_netdev_ops = {
.ndo_open = softing_netdev_open,
.ndo_stop = softing_netdev_stop,
.ndo_start_xmit = softing_netdev_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
static const struct can_bittiming_const softing_btr_const = {
@@ -832,6 +833,7 @@ static int softing_pdev_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto netdev_failed;
}
+ netdev->dev_id = j;
priv = netdev_priv(card->net[j]);
priv->index = j;
ret = softing_netdev_register(netdev);
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index 2c62fe6c8fa9..258b9c4856ec 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -871,6 +871,7 @@ static const struct net_device_ops ti_hecc_netdev_ops = {
.ndo_open = ti_hecc_open,
.ndo_stop = ti_hecc_close,
.ndo_start_xmit = ti_hecc_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
static int ti_hecc_probe(struct platform_device *pdev)
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index 52c42fd49510..00f2534dde73 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -883,6 +883,7 @@ static const struct net_device_ops ems_usb_netdev_ops = {
.ndo_open = ems_usb_open,
.ndo_stop = ems_usb_close,
.ndo_start_xmit = ems_usb_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
static const struct can_bittiming_const ems_usb_bittiming_const = {
diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c
index 7fbe85935f1d..b7c9e8b11460 100644
--- a/drivers/net/can/usb/esd_usb2.c
+++ b/drivers/net/can/usb/esd_usb2.c
@@ -888,6 +888,7 @@ static const struct net_device_ops esd_usb2_netdev_ops = {
.ndo_open = esd_usb2_open,
.ndo_stop = esd_usb2_close,
.ndo_start_xmit = esd_usb2_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
static const struct can_bittiming_const esd_usb2_bittiming_const = {
@@ -1024,6 +1025,7 @@ static int esd_usb2_probe_one_net(struct usb_interface *intf, int index)
netdev->netdev_ops = &esd_usb2_netdev_ops;
SET_NETDEV_DEV(netdev, &intf->dev);
+ netdev->dev_id = index;
err = register_candev(netdev);
if (err) {
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 6c859bba8b65..4ca46edc061d 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -473,6 +473,8 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev)
return err;
dev->nchannels = msg.u.cardinfo.nchannels;
+ if (dev->nchannels > MAX_NET_DEVICES)
+ return -EINVAL;
return 0;
}
@@ -1386,6 +1388,7 @@ static const struct net_device_ops kvaser_usb_netdev_ops = {
.ndo_open = kvaser_usb_open,
.ndo_stop = kvaser_usb_close,
.ndo_start_xmit = kvaser_usb_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
static const struct can_bittiming_const kvaser_usb_bittiming_const = {
@@ -1527,6 +1530,7 @@ static int kvaser_usb_init_one(struct usb_interface *intf,
netdev->netdev_ops = &kvaser_usb_netdev_ops;
SET_NETDEV_DEV(netdev, &intf->dev);
+ netdev->dev_id = channel;
dev->nets[channel] = priv;
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
index 0b7a4c3b01a2..644e6ab8a489 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
@@ -702,6 +702,7 @@ static const struct net_device_ops peak_usb_netdev_ops = {
.ndo_open = peak_usb_ndo_open,
.ndo_stop = peak_usb_ndo_stop,
.ndo_start_xmit = peak_usb_ndo_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
/*
@@ -769,6 +770,7 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter,
usb_set_intfdata(intf, dev);
SET_NETDEV_DEV(netdev, &intf->dev);
+ netdev->dev_id = ctrl_idx;
err = register_candev(netdev);
if (err) {
diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c
index a0fa1fd5092b..ef674ecb82f8 100644
--- a/drivers/net/can/usb/usb_8dev.c
+++ b/drivers/net/can/usb/usb_8dev.c
@@ -697,8 +697,8 @@ static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
nofreecontext:
- usb_unanchor_urb(urb);
usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);
+ usb_free_urb(urb);
netdev_warn(netdev, "couldn't find free context");
@@ -887,6 +887,7 @@ static const struct net_device_ops usb_8dev_netdev_ops = {
.ndo_open = usb_8dev_open,
.ndo_stop = usb_8dev_close,
.ndo_start_xmit = usb_8dev_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
static const struct can_bittiming_const usb_8dev_bittiming_const = {
diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
index 0a2a5ee79a17..4e94057ef5cf 100644
--- a/drivers/net/can/vcan.c
+++ b/drivers/net/can/vcan.c
@@ -46,6 +46,7 @@
#include <linux/if_ether.h>
#include <linux/can.h>
#include <linux/can/dev.h>
+#include <linux/can/skb.h>
#include <linux/slab.h>
#include <net/rtnetlink.h>
@@ -109,25 +110,23 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
stats->rx_packets++;
stats->rx_bytes += cfd->len;
}
- kfree_skb(skb);
+ consume_skb(skb);
return NETDEV_TX_OK;
}
/* perform standard echo handling for CAN network interfaces */
if (loop) {
- struct sock *srcsk = skb->sk;
- skb = skb_share_check(skb, GFP_ATOMIC);
+ skb = can_create_echo_skb(skb);
if (!skb)
return NETDEV_TX_OK;
/* receive with packet counting */
- skb->sk = srcsk;
vcan_rx(skb, dev);
} else {
/* no looped packets => no counting */
- kfree_skb(skb);
+ consume_skb(skb);
}
return NETDEV_TX_OK;
}
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index bd8f84b0b894..0932ffbf381b 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -63,10 +63,10 @@ static struct rtnl_link_stats64 *dummy_get_stats64(struct net_device *dev,
dstats = per_cpu_ptr(dev->dstats, i);
do {
- start = u64_stats_fetch_begin_bh(&dstats->syncp);
+ start = u64_stats_fetch_begin_irq(&dstats->syncp);
tbytes = dstats->tx_bytes;
tpackets = dstats->tx_packets;
- } while (u64_stats_fetch_retry_bh(&dstats->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&dstats->syncp, start));
stats->tx_bytes += tbytes;
stats->tx_packets += tpackets;
}
@@ -88,16 +88,10 @@ static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev)
static int dummy_dev_init(struct net_device *dev)
{
- int i;
- dev->dstats = alloc_percpu(struct pcpu_dstats);
+ dev->dstats = netdev_alloc_pcpu_stats(struct pcpu_dstats);
if (!dev->dstats)
return -ENOMEM;
- for_each_possible_cpu(i) {
- struct pcpu_dstats *dstats;
- dstats = per_cpu_ptr(dev->dstats, i);
- u64_stats_init(&dstats->syncp);
- }
return 0;
}
diff --git a/drivers/net/ethernet/3com/3c509.c b/drivers/net/ethernet/3com/3c509.c
index c53384d41c96..35df0b9e6848 100644
--- a/drivers/net/ethernet/3com/3c509.c
+++ b/drivers/net/ethernet/3com/3c509.c
@@ -749,7 +749,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&lp->lock, flags);
- dev_kfree_skb (skb);
+ dev_consume_skb_any (skb);
/* Clear the Tx status stack. */
{
diff --git a/drivers/net/ethernet/3com/3c589_cs.c b/drivers/net/ethernet/3com/3c589_cs.c
index 5992860a39c9..063557e037f2 100644
--- a/drivers/net/ethernet/3com/3c589_cs.c
+++ b/drivers/net/ethernet/3com/3c589_cs.c
@@ -1,23 +1,24 @@
-/*======================================================================
-
- A PCMCIA ethernet driver for the 3com 3c589 card.
-
- Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
-
- 3c589_cs.c 1.162 2001/10/13 00:08:50
-
- The network driver code is based on Donald Becker's 3c589 code:
-
- Written 1994 by Donald Becker.
- Copyright 1993 United States Government as represented by the
- Director, National Security Agency. This software may be used and
- distributed according to the terms of the GNU General Public License,
- incorporated herein by reference.
- Donald Becker may be reached at becker@scyld.com
-
- Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk>
-
-======================================================================*/
+/* ======================================================================
+ *
+ * A PCMCIA ethernet driver for the 3com 3c589 card.
+ *
+ * Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
+ *
+ * 3c589_cs.c 1.162 2001/10/13 00:08:50
+ *
+ * The network driver code is based on Donald Becker's 3c589 code:
+ *
+ * Written 1994 by Donald Becker.
+ * Copyright 1993 United States Government as represented by the
+ * Director, National Security Agency. This software may be used and
+ * distributed according to the terms of the GNU General Public License,
+ * incorporated herein by reference.
+ * Donald Becker may be reached at becker@scyld.com
+ *
+ * Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk>
+ *
+ * ======================================================================
+ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -41,18 +42,20 @@
#include <linux/ioport.h>
#include <linux/bitops.h>
#include <linux/jiffies.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ciscode.h>
#include <pcmcia/ds.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
/* To minimize the size of the driver source I only define operating
- constants if they are used several times. You'll need the manual
- if you want to understand driver details. */
+ * constants if they are used several times. You'll need the manual
+ * if you want to understand driver details.
+ */
+
/* Offsets from base I/O address. */
#define EL3_DATA 0x00
#define EL3_TIMER 0x0a
@@ -65,7 +68,9 @@
#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
/* The top five bits written to EL3_CMD are a command, the lower
- 11 bits are the parameter, if applicable. */
+ * 11 bits are the parameter, if applicable.
+ */
+
enum c509cmd {
TotalReset = 0<<11,
SelectWindow = 1<<11,
@@ -190,138 +195,142 @@ static const struct net_device_ops el3_netdev_ops = {
static int tc589_probe(struct pcmcia_device *link)
{
- struct el3_private *lp;
- struct net_device *dev;
+ struct el3_private *lp;
+ struct net_device *dev;
- dev_dbg(&link->dev, "3c589_attach()\n");
+ dev_dbg(&link->dev, "3c589_attach()\n");
- /* Create new ethernet device */
- dev = alloc_etherdev(sizeof(struct el3_private));
- if (!dev)
- return -ENOMEM;
- lp = netdev_priv(dev);
- link->priv = dev;
- lp->p_dev = link;
+ /* Create new ethernet device */
+ dev = alloc_etherdev(sizeof(struct el3_private));
+ if (!dev)
+ return -ENOMEM;
+ lp = netdev_priv(dev);
+ link->priv = dev;
+ lp->p_dev = link;
- spin_lock_init(&lp->lock);
- link->resource[0]->end = 16;
- link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
+ spin_lock_init(&lp->lock);
+ link->resource[0]->end = 16;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
- link->config_flags |= CONF_ENABLE_IRQ;
- link->config_index = 1;
+ link->config_flags |= CONF_ENABLE_IRQ;
+ link->config_index = 1;
- dev->netdev_ops = &el3_netdev_ops;
- dev->watchdog_timeo = TX_TIMEOUT;
+ dev->netdev_ops = &el3_netdev_ops;
+ dev->watchdog_timeo = TX_TIMEOUT;
- SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
+ SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
- return tc589_config(link);
+ return tc589_config(link);
}
static void tc589_detach(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
+ struct net_device *dev = link->priv;
- dev_dbg(&link->dev, "3c589_detach\n");
+ dev_dbg(&link->dev, "3c589_detach\n");
- unregister_netdev(dev);
+ unregister_netdev(dev);
- tc589_release(link);
+ tc589_release(link);
- free_netdev(dev);
+ free_netdev(dev);
} /* tc589_detach */
static int tc589_config(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- __be16 *phys_addr;
- int ret, i, j, multi = 0, fifo;
- unsigned int ioaddr;
- static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
- u8 *buf;
- size_t len;
-
- dev_dbg(&link->dev, "3c589_config\n");
-
- phys_addr = (__be16 *)dev->dev_addr;
- /* Is this a 3c562? */
- if (link->manf_id != MANFID_3COM)
- dev_info(&link->dev, "hmmm, is this really a 3Com card??\n");
- multi = (link->card_id == PRODID_3COM_3C562);
-
- link->io_lines = 16;
-
- /* For the 3c562, the base address must be xx00-xx7f */
- for (i = j = 0; j < 0x400; j += 0x10) {
- if (multi && (j & 0x80)) continue;
- link->resource[0]->start = j ^ 0x300;
- i = pcmcia_request_io(link);
- if (i == 0)
- break;
- }
- if (i != 0)
- goto failed;
-
- ret = pcmcia_request_irq(link, el3_interrupt);
- if (ret)
- goto failed;
-
- ret = pcmcia_enable_device(link);
- if (ret)
- goto failed;
-
- dev->irq = link->irq;
- dev->base_addr = link->resource[0]->start;
- ioaddr = dev->base_addr;
- EL3WINDOW(0);
-
- /* The 3c589 has an extra EEPROM for configuration info, including
- the hardware address. The 3c562 puts the address in the CIS. */
- len = pcmcia_get_tuple(link, 0x88, &buf);
- if (buf && len >= 6) {
- for (i = 0; i < 3; i++)
- phys_addr[i] = htons(le16_to_cpu(buf[i*2]));
- kfree(buf);
- } else {
- kfree(buf); /* 0 < len < 6 */
- for (i = 0; i < 3; i++)
- phys_addr[i] = htons(read_eeprom(ioaddr, i));
- if (phys_addr[0] == htons(0x6060)) {
- dev_err(&link->dev, "IO port conflict at 0x%03lx-0x%03lx\n",
- dev->base_addr, dev->base_addr+15);
- goto failed;
+ struct net_device *dev = link->priv;
+ __be16 *phys_addr;
+ int ret, i, j, multi = 0, fifo;
+ unsigned int ioaddr;
+ static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
+ u8 *buf;
+ size_t len;
+
+ dev_dbg(&link->dev, "3c589_config\n");
+
+ phys_addr = (__be16 *)dev->dev_addr;
+ /* Is this a 3c562? */
+ if (link->manf_id != MANFID_3COM)
+ dev_info(&link->dev, "hmmm, is this really a 3Com card??\n");
+ multi = (link->card_id == PRODID_3COM_3C562);
+
+ link->io_lines = 16;
+
+ /* For the 3c562, the base address must be xx00-xx7f */
+ for (i = j = 0; j < 0x400; j += 0x10) {
+ if (multi && (j & 0x80))
+ continue;
+ link->resource[0]->start = j ^ 0x300;
+ i = pcmcia_request_io(link);
+ if (i == 0)
+ break;
}
- }
-
- /* The address and resource configuration register aren't loaded from
- the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. */
- outw(0x3f00, ioaddr + 8);
- fifo = inl(ioaddr);
-
- /* The if_port symbol can be set when the module is loaded */
- if ((if_port >= 0) && (if_port <= 3))
- dev->if_port = if_port;
- else
- dev_err(&link->dev, "invalid if_port requested\n");
-
- SET_NETDEV_DEV(dev, &link->dev);
-
- if (register_netdev(dev) != 0) {
- dev_err(&link->dev, "register_netdev() failed\n");
- goto failed;
- }
-
- netdev_info(dev, "3Com 3c%s, io %#3lx, irq %d, hw_addr %pM\n",
- (multi ? "562" : "589"), dev->base_addr, dev->irq,
- dev->dev_addr);
- netdev_info(dev, " %dK FIFO split %s Rx:Tx, %s xcvr\n",
- (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3],
- if_names[dev->if_port]);
- return 0;
+ if (i != 0)
+ goto failed;
+
+ ret = pcmcia_request_irq(link, el3_interrupt);
+ if (ret)
+ goto failed;
+
+ ret = pcmcia_enable_device(link);
+ if (ret)
+ goto failed;
+
+ dev->irq = link->irq;
+ dev->base_addr = link->resource[0]->start;
+ ioaddr = dev->base_addr;
+ EL3WINDOW(0);
+
+ /* The 3c589 has an extra EEPROM for configuration info, including
+ * the hardware address. The 3c562 puts the address in the CIS.
+ */
+ len = pcmcia_get_tuple(link, 0x88, &buf);
+ if (buf && len >= 6) {
+ for (i = 0; i < 3; i++)
+ phys_addr[i] = htons(le16_to_cpu(buf[i*2]));
+ kfree(buf);
+ } else {
+ kfree(buf); /* 0 < len < 6 */
+ for (i = 0; i < 3; i++)
+ phys_addr[i] = htons(read_eeprom(ioaddr, i));
+ if (phys_addr[0] == htons(0x6060)) {
+ dev_err(&link->dev, "IO port conflict at 0x%03lx-0x%03lx\n",
+ dev->base_addr, dev->base_addr+15);
+ goto failed;
+ }
+ }
+
+ /* The address and resource configuration register aren't loaded from
+ * the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version.
+ */
+
+ outw(0x3f00, ioaddr + 8);
+ fifo = inl(ioaddr);
+
+ /* The if_port symbol can be set when the module is loaded */
+ if ((if_port >= 0) && (if_port <= 3))
+ dev->if_port = if_port;
+ else
+ dev_err(&link->dev, "invalid if_port requested\n");
+
+ SET_NETDEV_DEV(dev, &link->dev);
+
+ if (register_netdev(dev) != 0) {
+ dev_err(&link->dev, "register_netdev() failed\n");
+ goto failed;
+ }
+
+ netdev_info(dev, "3Com 3c%s, io %#3lx, irq %d, hw_addr %pM\n",
+ (multi ? "562" : "589"), dev->base_addr, dev->irq,
+ dev->dev_addr);
+ netdev_info(dev, " %dK FIFO split %s Rx:Tx, %s xcvr\n",
+ (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3],
+ if_names[dev->if_port]);
+ return 0;
failed:
- tc589_release(link);
- return -ENODEV;
+ tc589_release(link);
+ return -ENODEV;
} /* tc589_config */
static void tc589_release(struct pcmcia_device *link)
@@ -353,113 +362,120 @@ static int tc589_resume(struct pcmcia_device *link)
/*====================================================================*/
-/*
- Use this for commands that may take time to finish
-*/
+/* Use this for commands that may take time to finish */
+
static void tc589_wait_for_completion(struct net_device *dev, int cmd)
{
- int i = 100;
- outw(cmd, dev->base_addr + EL3_CMD);
- while (--i > 0)
- if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break;
- if (i == 0)
- netdev_warn(dev, "command 0x%04x did not complete!\n", cmd);
+ int i = 100;
+ outw(cmd, dev->base_addr + EL3_CMD);
+ while (--i > 0)
+ if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000))
+ break;
+ if (i == 0)
+ netdev_warn(dev, "command 0x%04x did not complete!\n", cmd);
}
-/*
- Read a word from the EEPROM using the regular EEPROM access register.
- Assume that we are in register window zero.
-*/
+/* Read a word from the EEPROM using the regular EEPROM access register.
+ * Assume that we are in register window zero.
+ */
+
static u16 read_eeprom(unsigned int ioaddr, int index)
{
- int i;
- outw(EEPROM_READ + index, ioaddr + 10);
- /* Reading the eeprom takes 162 us */
- for (i = 1620; i >= 0; i--)
- if ((inw(ioaddr + 10) & EEPROM_BUSY) == 0)
- break;
- return inw(ioaddr + 12);
+ int i;
+ outw(EEPROM_READ + index, ioaddr + 10);
+ /* Reading the eeprom takes 162 us */
+ for (i = 1620; i >= 0; i--)
+ if ((inw(ioaddr + 10) & EEPROM_BUSY) == 0)
+ break;
+ return inw(ioaddr + 12);
}
-/*
- Set transceiver type, perhaps to something other than what the user
- specified in dev->if_port.
-*/
+/* Set transceiver type, perhaps to something other than what the user
+ * specified in dev->if_port.
+ */
+
static void tc589_set_xcvr(struct net_device *dev, int if_port)
{
- struct el3_private *lp = netdev_priv(dev);
- unsigned int ioaddr = dev->base_addr;
-
- EL3WINDOW(0);
- switch (if_port) {
- case 0: case 1: outw(0, ioaddr + 6); break;
- case 2: outw(3<<14, ioaddr + 6); break;
- case 3: outw(1<<14, ioaddr + 6); break;
- }
- /* On PCMCIA, this just turns on the LED */
- outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD);
- /* 10baseT interface, enable link beat and jabber check. */
- EL3WINDOW(4);
- outw(MEDIA_LED | ((if_port < 2) ? MEDIA_TP : 0), ioaddr + WN4_MEDIA);
- EL3WINDOW(1);
- if (if_port == 2)
- lp->media_status = ((dev->if_port == 0) ? 0x8000 : 0x4000);
- else
- lp->media_status = ((dev->if_port == 0) ? 0x4010 : 0x8800);
+ struct el3_private *lp = netdev_priv(dev);
+ unsigned int ioaddr = dev->base_addr;
+
+ EL3WINDOW(0);
+ switch (if_port) {
+ case 0:
+ case 1:
+ outw(0, ioaddr + 6);
+ break;
+ case 2:
+ outw(3<<14, ioaddr + 6);
+ break;
+ case 3:
+ outw(1<<14, ioaddr + 6);
+ break;
+ }
+ /* On PCMCIA, this just turns on the LED */
+ outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD);
+ /* 10baseT interface, enable link beat and jabber check. */
+ EL3WINDOW(4);
+ outw(MEDIA_LED | ((if_port < 2) ? MEDIA_TP : 0), ioaddr + WN4_MEDIA);
+ EL3WINDOW(1);
+ if (if_port == 2)
+ lp->media_status = ((dev->if_port == 0) ? 0x8000 : 0x4000);
+ else
+ lp->media_status = ((dev->if_port == 0) ? 0x4010 : 0x8800);
}
static void dump_status(struct net_device *dev)
{
- unsigned int ioaddr = dev->base_addr;
- EL3WINDOW(1);
- netdev_info(dev, " irq status %04x, rx status %04x, tx status %02x tx free %04x\n",
- inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS),
- inb(ioaddr+TX_STATUS), inw(ioaddr+TX_FREE));
- EL3WINDOW(4);
- netdev_info(dev, " diagnostics: fifo %04x net %04x ethernet %04x media %04x\n",
- inw(ioaddr+0x04), inw(ioaddr+0x06), inw(ioaddr+0x08),
- inw(ioaddr+0x0a));
- EL3WINDOW(1);
+ unsigned int ioaddr = dev->base_addr;
+ EL3WINDOW(1);
+ netdev_info(dev, " irq status %04x, rx status %04x, tx status %02x tx free %04x\n",
+ inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS),
+ inb(ioaddr+TX_STATUS), inw(ioaddr+TX_FREE));
+ EL3WINDOW(4);
+ netdev_info(dev, " diagnostics: fifo %04x net %04x ethernet %04x media %04x\n",
+ inw(ioaddr+0x04), inw(ioaddr+0x06), inw(ioaddr+0x08),
+ inw(ioaddr+0x0a));
+ EL3WINDOW(1);
}
/* Reset and restore all of the 3c589 registers. */
static void tc589_reset(struct net_device *dev)
{
- unsigned int ioaddr = dev->base_addr;
- int i;
-
- EL3WINDOW(0);
- outw(0x0001, ioaddr + 4); /* Activate board. */
- outw(0x3f00, ioaddr + 8); /* Set the IRQ line. */
-
- /* Set the station address in window 2. */
- EL3WINDOW(2);
- for (i = 0; i < 6; i++)
- outb(dev->dev_addr[i], ioaddr + i);
-
- tc589_set_xcvr(dev, dev->if_port);
-
- /* Switch to the stats window, and clear all stats by reading. */
- outw(StatsDisable, ioaddr + EL3_CMD);
- EL3WINDOW(6);
- for (i = 0; i < 9; i++)
- inb(ioaddr+i);
- inw(ioaddr + 10);
- inw(ioaddr + 12);
-
- /* Switch to register set 1 for normal use. */
- EL3WINDOW(1);
-
- set_rx_mode(dev);
- outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
- outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
- outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
- /* Allow status bits to be seen. */
- outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
- /* Ack all pending events, and set active indicator mask. */
- outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
+ unsigned int ioaddr = dev->base_addr;
+ int i;
+
+ EL3WINDOW(0);
+ outw(0x0001, ioaddr + 4); /* Activate board. */
+ outw(0x3f00, ioaddr + 8); /* Set the IRQ line. */
+
+ /* Set the station address in window 2. */
+ EL3WINDOW(2);
+ for (i = 0; i < 6; i++)
+ outb(dev->dev_addr[i], ioaddr + i);
+
+ tc589_set_xcvr(dev, dev->if_port);
+
+ /* Switch to the stats window, and clear all stats by reading. */
+ outw(StatsDisable, ioaddr + EL3_CMD);
+ EL3WINDOW(6);
+ for (i = 0; i < 9; i++)
+ inb(ioaddr+i);
+ inw(ioaddr + 10);
+ inw(ioaddr + 12);
+
+ /* Switch to register set 1 for normal use. */
+ EL3WINDOW(1);
+
+ set_rx_mode(dev);
+ outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
+ outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
+ outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
+ /* Allow status bits to be seen. */
+ outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
+ /* Ack all pending events, and set active indicator mask. */
+ outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
ioaddr + EL3_CMD);
- outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
+ outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
| AdapterFailure, ioaddr + EL3_CMD);
}
@@ -478,381 +494,406 @@ static const struct ethtool_ops netdev_ethtool_ops = {
static int el3_config(struct net_device *dev, struct ifmap *map)
{
- if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
- if (map->port <= 3) {
- dev->if_port = map->port;
- netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
- tc589_set_xcvr(dev, dev->if_port);
- } else
- return -EINVAL;
- }
- return 0;
+ if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
+ if (map->port <= 3) {
+ dev->if_port = map->port;
+ netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
+ tc589_set_xcvr(dev, dev->if_port);
+ } else {
+ return -EINVAL;
+ }
+ }
+ return 0;
}
static int el3_open(struct net_device *dev)
{
- struct el3_private *lp = netdev_priv(dev);
- struct pcmcia_device *link = lp->p_dev;
+ struct el3_private *lp = netdev_priv(dev);
+ struct pcmcia_device *link = lp->p_dev;
- if (!pcmcia_dev_present(link))
- return -ENODEV;
+ if (!pcmcia_dev_present(link))
+ return -ENODEV;
- link->open++;
- netif_start_queue(dev);
+ link->open++;
+ netif_start_queue(dev);
- tc589_reset(dev);
- init_timer(&lp->media);
- lp->media.function = media_check;
- lp->media.data = (unsigned long) dev;
- lp->media.expires = jiffies + HZ;
- add_timer(&lp->media);
+ tc589_reset(dev);
+ init_timer(&lp->media);
+ lp->media.function = media_check;
+ lp->media.data = (unsigned long) dev;
+ lp->media.expires = jiffies + HZ;
+ add_timer(&lp->media);
- dev_dbg(&link->dev, "%s: opened, status %4.4x.\n",
+ dev_dbg(&link->dev, "%s: opened, status %4.4x.\n",
dev->name, inw(dev->base_addr + EL3_STATUS));
- return 0;
+ return 0;
}
static void el3_tx_timeout(struct net_device *dev)
{
- unsigned int ioaddr = dev->base_addr;
-
- netdev_warn(dev, "Transmit timed out!\n");
- dump_status(dev);
- dev->stats.tx_errors++;
- dev->trans_start = jiffies; /* prevent tx timeout */
- /* Issue TX_RESET and TX_START commands. */
- tc589_wait_for_completion(dev, TxReset);
- outw(TxEnable, ioaddr + EL3_CMD);
- netif_wake_queue(dev);
+ unsigned int ioaddr = dev->base_addr;
+
+ netdev_warn(dev, "Transmit timed out!\n");
+ dump_status(dev);
+ dev->stats.tx_errors++;
+ dev->trans_start = jiffies; /* prevent tx timeout */
+ /* Issue TX_RESET and TX_START commands. */
+ tc589_wait_for_completion(dev, TxReset);
+ outw(TxEnable, ioaddr + EL3_CMD);
+ netif_wake_queue(dev);
}
static void pop_tx_status(struct net_device *dev)
{
- unsigned int ioaddr = dev->base_addr;
- int i;
-
- /* Clear the Tx status stack. */
- for (i = 32; i > 0; i--) {
- u_char tx_status = inb(ioaddr + TX_STATUS);
- if (!(tx_status & 0x84)) break;
- /* reset transmitter on jabber error or underrun */
- if (tx_status & 0x30)
- tc589_wait_for_completion(dev, TxReset);
- if (tx_status & 0x38) {
- netdev_dbg(dev, "transmit error: status 0x%02x\n", tx_status);
- outw(TxEnable, ioaddr + EL3_CMD);
- dev->stats.tx_aborted_errors++;
+ unsigned int ioaddr = dev->base_addr;
+ int i;
+
+ /* Clear the Tx status stack. */
+ for (i = 32; i > 0; i--) {
+ u_char tx_status = inb(ioaddr + TX_STATUS);
+ if (!(tx_status & 0x84))
+ break;
+ /* reset transmitter on jabber error or underrun */
+ if (tx_status & 0x30)
+ tc589_wait_for_completion(dev, TxReset);
+ if (tx_status & 0x38) {
+ netdev_dbg(dev, "transmit error: status 0x%02x\n", tx_status);
+ outw(TxEnable, ioaddr + EL3_CMD);
+ dev->stats.tx_aborted_errors++;
+ }
+ outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
}
- outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
- }
}
static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
- unsigned int ioaddr = dev->base_addr;
- struct el3_private *priv = netdev_priv(dev);
- unsigned long flags;
+ unsigned int ioaddr = dev->base_addr;
+ struct el3_private *priv = netdev_priv(dev);
+ unsigned long flags;
- netdev_dbg(dev, "el3_start_xmit(length = %ld) called, status %4.4x.\n",
+ netdev_dbg(dev, "el3_start_xmit(length = %ld) called, status %4.4x.\n",
(long)skb->len, inw(ioaddr + EL3_STATUS));
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->lock, flags);
- dev->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
- /* Put out the doubleword header... */
- outw(skb->len, ioaddr + TX_FIFO);
- outw(0x00, ioaddr + TX_FIFO);
- /* ... and the packet rounded to a doubleword. */
- outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
+ /* Put out the doubleword header... */
+ outw(skb->len, ioaddr + TX_FIFO);
+ outw(0x00, ioaddr + TX_FIFO);
+ /* ... and the packet rounded to a doubleword. */
+ outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
- if (inw(ioaddr + TX_FREE) <= 1536) {
- netif_stop_queue(dev);
- /* Interrupt us when the FIFO has room for max-sized packet. */
- outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
- }
+ if (inw(ioaddr + TX_FREE) <= 1536) {
+ netif_stop_queue(dev);
+ /* Interrupt us when the FIFO has room for max-sized packet. */
+ outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
+ }
- pop_tx_status(dev);
- spin_unlock_irqrestore(&priv->lock, flags);
- dev_kfree_skb(skb);
+ pop_tx_status(dev);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ dev_kfree_skb(skb);
- return NETDEV_TX_OK;
+ return NETDEV_TX_OK;
}
/* The EL3 interrupt handler. */
static irqreturn_t el3_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *) dev_id;
- struct el3_private *lp = netdev_priv(dev);
- unsigned int ioaddr;
- __u16 status;
- int i = 0, handled = 1;
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct el3_private *lp = netdev_priv(dev);
+ unsigned int ioaddr;
+ __u16 status;
+ int i = 0, handled = 1;
- if (!netif_device_present(dev))
- return IRQ_NONE;
+ if (!netif_device_present(dev))
+ return IRQ_NONE;
- ioaddr = dev->base_addr;
+ ioaddr = dev->base_addr;
- netdev_dbg(dev, "interrupt, status %4.4x.\n", inw(ioaddr + EL3_STATUS));
+ netdev_dbg(dev, "interrupt, status %4.4x.\n", inw(ioaddr + EL3_STATUS));
- spin_lock(&lp->lock);
- while ((status = inw(ioaddr + EL3_STATUS)) &
+ spin_lock(&lp->lock);
+ while ((status = inw(ioaddr + EL3_STATUS)) &
(IntLatch | RxComplete | StatsFull)) {
- if ((status & 0xe000) != 0x2000) {
- netdev_dbg(dev, "interrupt from dead card\n");
- handled = 0;
- break;
- }
- if (status & RxComplete)
- el3_rx(dev);
- if (status & TxAvailable) {
- netdev_dbg(dev, " TX room bit was handled.\n");
- /* There's room in the FIFO for a full-sized packet. */
- outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
- netif_wake_queue(dev);
- }
- if (status & TxComplete)
- pop_tx_status(dev);
- if (status & (AdapterFailure | RxEarly | StatsFull)) {
- /* Handle all uncommon interrupts. */
- if (status & StatsFull) /* Empty statistics. */
- update_stats(dev);
- if (status & RxEarly) { /* Rx early is unused. */
- el3_rx(dev);
- outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
- }
- if (status & AdapterFailure) {
- u16 fifo_diag;
- EL3WINDOW(4);
- fifo_diag = inw(ioaddr + 4);
- EL3WINDOW(1);
- netdev_warn(dev, "adapter failure, FIFO diagnostic register %04x.\n",
+ if ((status & 0xe000) != 0x2000) {
+ netdev_dbg(dev, "interrupt from dead card\n");
+ handled = 0;
+ break;
+ }
+ if (status & RxComplete)
+ el3_rx(dev);
+ if (status & TxAvailable) {
+ netdev_dbg(dev, " TX room bit was handled.\n");
+ /* There's room in the FIFO for a full-sized packet. */
+ outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
+ netif_wake_queue(dev);
+ }
+ if (status & TxComplete)
+ pop_tx_status(dev);
+ if (status & (AdapterFailure | RxEarly | StatsFull)) {
+ /* Handle all uncommon interrupts. */
+ if (status & StatsFull) /* Empty statistics. */
+ update_stats(dev);
+ if (status & RxEarly) {
+ /* Rx early is unused. */
+ el3_rx(dev);
+ outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
+ }
+ if (status & AdapterFailure) {
+ u16 fifo_diag;
+ EL3WINDOW(4);
+ fifo_diag = inw(ioaddr + 4);
+ EL3WINDOW(1);
+ netdev_warn(dev, "adapter failure, FIFO diagnostic register %04x.\n",
fifo_diag);
- if (fifo_diag & 0x0400) {
- /* Tx overrun */
- tc589_wait_for_completion(dev, TxReset);
- outw(TxEnable, ioaddr + EL3_CMD);
+ if (fifo_diag & 0x0400) {
+ /* Tx overrun */
+ tc589_wait_for_completion(dev, TxReset);
+ outw(TxEnable, ioaddr + EL3_CMD);
+ }
+ if (fifo_diag & 0x2000) {
+ /* Rx underrun */
+ tc589_wait_for_completion(dev, RxReset);
+ set_rx_mode(dev);
+ outw(RxEnable, ioaddr + EL3_CMD);
+ }
+ outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
+ }
}
- if (fifo_diag & 0x2000) {
- /* Rx underrun */
- tc589_wait_for_completion(dev, RxReset);
- set_rx_mode(dev);
- outw(RxEnable, ioaddr + EL3_CMD);
+ if (++i > 10) {
+ netdev_err(dev, "infinite loop in interrupt, status %4.4x.\n",
+ status);
+ /* Clear all interrupts */
+ outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
+ break;
}
- outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
- }
+ /* Acknowledge the IRQ. */
+ outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
}
- if (++i > 10) {
- netdev_err(dev, "infinite loop in interrupt, status %4.4x.\n",
- status);
- /* Clear all interrupts */
- outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
- break;
- }
- /* Acknowledge the IRQ. */
- outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
- }
- lp->last_irq = jiffies;
- spin_unlock(&lp->lock);
- netdev_dbg(dev, "exiting interrupt, status %4.4x.\n",
- inw(ioaddr + EL3_STATUS));
- return IRQ_RETVAL(handled);
+ lp->last_irq = jiffies;
+ spin_unlock(&lp->lock);
+ netdev_dbg(dev, "exiting interrupt, status %4.4x.\n",
+ inw(ioaddr + EL3_STATUS));
+ return IRQ_RETVAL(handled);
}
static void media_check(unsigned long arg)
{
- struct net_device *dev = (struct net_device *)(arg);
- struct el3_private *lp = netdev_priv(dev);
- unsigned int ioaddr = dev->base_addr;
- u16 media, errs;
- unsigned long flags;
+ struct net_device *dev = (struct net_device *)(arg);
+ struct el3_private *lp = netdev_priv(dev);
+ unsigned int ioaddr = dev->base_addr;
+ u16 media, errs;
+ unsigned long flags;
- if (!netif_device_present(dev)) goto reschedule;
+ if (!netif_device_present(dev))
+ goto reschedule;
- /* Check for pending interrupt with expired latency timer: with
- this, we can limp along even if the interrupt is blocked */
- if ((inw(ioaddr + EL3_STATUS) & IntLatch) &&
+ /* Check for pending interrupt with expired latency timer: with
+ * this, we can limp along even if the interrupt is blocked
+ */
+ if ((inw(ioaddr + EL3_STATUS) & IntLatch) &&
(inb(ioaddr + EL3_TIMER) == 0xff)) {
- if (!lp->fast_poll)
- netdev_warn(dev, "interrupt(s) dropped!\n");
-
- local_irq_save(flags);
- el3_interrupt(dev->irq, dev);
- local_irq_restore(flags);
-
- lp->fast_poll = HZ;
- }
- if (lp->fast_poll) {
- lp->fast_poll--;
- lp->media.expires = jiffies + HZ/100;
- add_timer(&lp->media);
- return;
- }
-
- /* lp->lock guards the EL3 window. Window should always be 1 except
- when the lock is held */
- spin_lock_irqsave(&lp->lock, flags);
- EL3WINDOW(4);
- media = inw(ioaddr+WN4_MEDIA) & 0xc810;
-
- /* Ignore collisions unless we've had no irq's recently */
- if (time_before(jiffies, lp->last_irq + HZ)) {
- media &= ~0x0010;
- } else {
- /* Try harder to detect carrier errors */
- EL3WINDOW(6);
- outw(StatsDisable, ioaddr + EL3_CMD);
- errs = inb(ioaddr + 0);
- outw(StatsEnable, ioaddr + EL3_CMD);
- dev->stats.tx_carrier_errors += errs;
- if (errs || (lp->media_status & 0x0010)) media |= 0x0010;
- }
+ if (!lp->fast_poll)
+ netdev_warn(dev, "interrupt(s) dropped!\n");
+
+ local_irq_save(flags);
+ el3_interrupt(dev->irq, dev);
+ local_irq_restore(flags);
+
+ lp->fast_poll = HZ;
+ }
+ if (lp->fast_poll) {
+ lp->fast_poll--;
+ lp->media.expires = jiffies + HZ/100;
+ add_timer(&lp->media);
+ return;
+ }
+
+ /* lp->lock guards the EL3 window. Window should always be 1 except
+ * when the lock is held
+ */
+
+ spin_lock_irqsave(&lp->lock, flags);
+ EL3WINDOW(4);
+ media = inw(ioaddr+WN4_MEDIA) & 0xc810;
+
+ /* Ignore collisions unless we've had no irq's recently */
+ if (time_before(jiffies, lp->last_irq + HZ)) {
+ media &= ~0x0010;
+ } else {
+ /* Try harder to detect carrier errors */
+ EL3WINDOW(6);
+ outw(StatsDisable, ioaddr + EL3_CMD);
+ errs = inb(ioaddr + 0);
+ outw(StatsEnable, ioaddr + EL3_CMD);
+ dev->stats.tx_carrier_errors += errs;
+ if (errs || (lp->media_status & 0x0010))
+ media |= 0x0010;
+ }
- if (media != lp->media_status) {
- if ((media & lp->media_status & 0x8000) &&
- ((lp->media_status ^ media) & 0x0800))
+ if (media != lp->media_status) {
+ if ((media & lp->media_status & 0x8000) &&
+ ((lp->media_status ^ media) & 0x0800))
netdev_info(dev, "%s link beat\n",
- (lp->media_status & 0x0800 ? "lost" : "found"));
- else if ((media & lp->media_status & 0x4000) &&
+ (lp->media_status & 0x0800 ? "lost" : "found"));
+ else if ((media & lp->media_status & 0x4000) &&
((lp->media_status ^ media) & 0x0010))
netdev_info(dev, "coax cable %s\n",
- (lp->media_status & 0x0010 ? "ok" : "problem"));
- if (dev->if_port == 0) {
- if (media & 0x8000) {
- if (media & 0x0800)
- netdev_info(dev, "flipped to 10baseT\n");
- else
+ (lp->media_status & 0x0010 ? "ok" : "problem"));
+ if (dev->if_port == 0) {
+ if (media & 0x8000) {
+ if (media & 0x0800)
+ netdev_info(dev, "flipped to 10baseT\n");
+ else
tc589_set_xcvr(dev, 2);
- } else if (media & 0x4000) {
- if (media & 0x0010)
- tc589_set_xcvr(dev, 1);
- else
- netdev_info(dev, "flipped to 10base2\n");
- }
+ } else if (media & 0x4000) {
+ if (media & 0x0010)
+ tc589_set_xcvr(dev, 1);
+ else
+ netdev_info(dev, "flipped to 10base2\n");
+ }
+ }
+ lp->media_status = media;
}
- lp->media_status = media;
- }
- EL3WINDOW(1);
- spin_unlock_irqrestore(&lp->lock, flags);
+ EL3WINDOW(1);
+ spin_unlock_irqrestore(&lp->lock, flags);
reschedule:
- lp->media.expires = jiffies + HZ;
- add_timer(&lp->media);
+ lp->media.expires = jiffies + HZ;
+ add_timer(&lp->media);
}
static struct net_device_stats *el3_get_stats(struct net_device *dev)
{
- struct el3_private *lp = netdev_priv(dev);
- unsigned long flags;
- struct pcmcia_device *link = lp->p_dev;
+ struct el3_private *lp = netdev_priv(dev);
+ unsigned long flags;
+ struct pcmcia_device *link = lp->p_dev;
- if (pcmcia_dev_present(link)) {
- spin_lock_irqsave(&lp->lock, flags);
- update_stats(dev);
- spin_unlock_irqrestore(&lp->lock, flags);
- }
- return &dev->stats;
+ if (pcmcia_dev_present(link)) {
+ spin_lock_irqsave(&lp->lock, flags);
+ update_stats(dev);
+ spin_unlock_irqrestore(&lp->lock, flags);
+ }
+ return &dev->stats;
}
-/*
- Update statistics. We change to register window 6, so this should be run
- single-threaded if the device is active. This is expected to be a rare
- operation, and it's simpler for the rest of the driver to assume that
- window 1 is always valid rather than use a special window-state variable.
-
- Caller must hold the lock for this
+/* Update statistics. We change to register window 6, so this should be run
+* single-threaded if the device is active. This is expected to be a rare
+* operation, and it's simpler for the rest of the driver to assume that
+* window 1 is always valid rather than use a special window-state variable.
+*
+* Caller must hold the lock for this
*/
+
static void update_stats(struct net_device *dev)
{
- unsigned int ioaddr = dev->base_addr;
-
- netdev_dbg(dev, "updating the statistics.\n");
- /* Turn off statistics updates while reading. */
- outw(StatsDisable, ioaddr + EL3_CMD);
- /* Switch to the stats window, and read everything. */
- EL3WINDOW(6);
- dev->stats.tx_carrier_errors += inb(ioaddr + 0);
- dev->stats.tx_heartbeat_errors += inb(ioaddr + 1);
- /* Multiple collisions. */ inb(ioaddr + 2);
- dev->stats.collisions += inb(ioaddr + 3);
- dev->stats.tx_window_errors += inb(ioaddr + 4);
- dev->stats.rx_fifo_errors += inb(ioaddr + 5);
- dev->stats.tx_packets += inb(ioaddr + 6);
- /* Rx packets */ inb(ioaddr + 7);
- /* Tx deferrals */ inb(ioaddr + 8);
- /* Rx octets */ inw(ioaddr + 10);
- /* Tx octets */ inw(ioaddr + 12);
-
- /* Back to window 1, and turn statistics back on. */
- EL3WINDOW(1);
- outw(StatsEnable, ioaddr + EL3_CMD);
+ unsigned int ioaddr = dev->base_addr;
+
+ netdev_dbg(dev, "updating the statistics.\n");
+ /* Turn off statistics updates while reading. */
+ outw(StatsDisable, ioaddr + EL3_CMD);
+ /* Switch to the stats window, and read everything. */
+ EL3WINDOW(6);
+ dev->stats.tx_carrier_errors += inb(ioaddr + 0);
+ dev->stats.tx_heartbeat_errors += inb(ioaddr + 1);
+ /* Multiple collisions. */
+ inb(ioaddr + 2);
+ dev->stats.collisions += inb(ioaddr + 3);
+ dev->stats.tx_window_errors += inb(ioaddr + 4);
+ dev->stats.rx_fifo_errors += inb(ioaddr + 5);
+ dev->stats.tx_packets += inb(ioaddr + 6);
+ /* Rx packets */
+ inb(ioaddr + 7);
+ /* Tx deferrals */
+ inb(ioaddr + 8);
+ /* Rx octets */
+ inw(ioaddr + 10);
+ /* Tx octets */
+ inw(ioaddr + 12);
+
+ /* Back to window 1, and turn statistics back on. */
+ EL3WINDOW(1);
+ outw(StatsEnable, ioaddr + EL3_CMD);
}
static int el3_rx(struct net_device *dev)
{
- unsigned int ioaddr = dev->base_addr;
- int worklimit = 32;
- short rx_status;
+ unsigned int ioaddr = dev->base_addr;
+ int worklimit = 32;
+ short rx_status;
- netdev_dbg(dev, "in rx_packet(), status %4.4x, rx_status %4.4x.\n",
+ netdev_dbg(dev, "in rx_packet(), status %4.4x, rx_status %4.4x.\n",
inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));
- while (!((rx_status = inw(ioaddr + RX_STATUS)) & 0x8000) &&
+ while (!((rx_status = inw(ioaddr + RX_STATUS)) & 0x8000) &&
worklimit > 0) {
- worklimit--;
- if (rx_status & 0x4000) { /* Error, update stats. */
- short error = rx_status & 0x3800;
- dev->stats.rx_errors++;
- switch (error) {
- case 0x0000: dev->stats.rx_over_errors++; break;
- case 0x0800: dev->stats.rx_length_errors++; break;
- case 0x1000: dev->stats.rx_frame_errors++; break;
- case 0x1800: dev->stats.rx_length_errors++; break;
- case 0x2000: dev->stats.rx_frame_errors++; break;
- case 0x2800: dev->stats.rx_crc_errors++; break;
- }
- } else {
- short pkt_len = rx_status & 0x7ff;
- struct sk_buff *skb;
-
- skb = netdev_alloc_skb(dev, pkt_len + 5);
-
- netdev_dbg(dev, " Receiving packet size %d status %4.4x.\n",
+ worklimit--;
+ if (rx_status & 0x4000) { /* Error, update stats. */
+ short error = rx_status & 0x3800;
+ dev->stats.rx_errors++;
+ switch (error) {
+ case 0x0000:
+ dev->stats.rx_over_errors++;
+ break;
+ case 0x0800:
+ dev->stats.rx_length_errors++;
+ break;
+ case 0x1000:
+ dev->stats.rx_frame_errors++;
+ break;
+ case 0x1800:
+ dev->stats.rx_length_errors++;
+ break;
+ case 0x2000:
+ dev->stats.rx_frame_errors++;
+ break;
+ case 0x2800:
+ dev->stats.rx_crc_errors++;
+ break;
+ }
+ } else {
+ short pkt_len = rx_status & 0x7ff;
+ struct sk_buff *skb;
+
+ skb = netdev_alloc_skb(dev, pkt_len + 5);
+
+ netdev_dbg(dev, " Receiving packet size %d status %4.4x.\n",
pkt_len, rx_status);
- if (skb != NULL) {
- skb_reserve(skb, 2);
- insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
+ if (skb != NULL) {
+ skb_reserve(skb, 2);
+ insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
(pkt_len+3)>>2);
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
- } else {
- netdev_dbg(dev, "couldn't allocate a sk_buff of size %d.\n",
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
+ } else {
+ netdev_dbg(dev, "couldn't allocate a sk_buff of size %d.\n",
pkt_len);
- dev->stats.rx_dropped++;
- }
+ dev->stats.rx_dropped++;
+ }
+ }
+ /* Pop the top of the Rx FIFO */
+ tc589_wait_for_completion(dev, RxDiscard);
}
- /* Pop the top of the Rx FIFO */
- tc589_wait_for_completion(dev, RxDiscard);
- }
- if (worklimit == 0)
- netdev_warn(dev, "too much work in el3_rx!\n");
- return 0;
+ if (worklimit == 0)
+ netdev_warn(dev, "too much work in el3_rx!\n");
+ return 0;
}
static void set_rx_mode(struct net_device *dev)
{
- unsigned int ioaddr = dev->base_addr;
- u16 opts = SetRxFilter | RxStation | RxBroadcast;
-
- if (dev->flags & IFF_PROMISC)
- opts |= RxMulticast | RxProm;
- else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI))
- opts |= RxMulticast;
- outw(opts, ioaddr + EL3_CMD);
+ unsigned int ioaddr = dev->base_addr;
+ u16 opts = SetRxFilter | RxStation | RxBroadcast;
+
+ if (dev->flags & IFF_PROMISC)
+ opts |= RxMulticast | RxProm;
+ else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI))
+ opts |= RxMulticast;
+ outw(opts, ioaddr + EL3_CMD);
}
static void set_multicast_list(struct net_device *dev)
@@ -867,44 +908,44 @@ static void set_multicast_list(struct net_device *dev)
static int el3_close(struct net_device *dev)
{
- struct el3_private *lp = netdev_priv(dev);
- struct pcmcia_device *link = lp->p_dev;
- unsigned int ioaddr = dev->base_addr;
-
- dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name);
+ struct el3_private *lp = netdev_priv(dev);
+ struct pcmcia_device *link = lp->p_dev;
+ unsigned int ioaddr = dev->base_addr;
+
+ dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name);
+
+ if (pcmcia_dev_present(link)) {
+ /* Turn off statistics ASAP. We update dev->stats below. */
+ outw(StatsDisable, ioaddr + EL3_CMD);
+
+ /* Disable the receiver and transmitter. */
+ outw(RxDisable, ioaddr + EL3_CMD);
+ outw(TxDisable, ioaddr + EL3_CMD);
+
+ if (dev->if_port == 2)
+ /* Turn off thinnet power. Green! */
+ outw(StopCoax, ioaddr + EL3_CMD);
+ else if (dev->if_port == 1) {
+ /* Disable link beat and jabber */
+ EL3WINDOW(4);
+ outw(0, ioaddr + WN4_MEDIA);
+ }
- if (pcmcia_dev_present(link)) {
- /* Turn off statistics ASAP. We update dev->stats below. */
- outw(StatsDisable, ioaddr + EL3_CMD);
+ /* Switching back to window 0 disables the IRQ. */
+ EL3WINDOW(0);
+ /* But we explicitly zero the IRQ line select anyway. */
+ outw(0x0f00, ioaddr + WN0_IRQ);
- /* Disable the receiver and transmitter. */
- outw(RxDisable, ioaddr + EL3_CMD);
- outw(TxDisable, ioaddr + EL3_CMD);
-
- if (dev->if_port == 2)
- /* Turn off thinnet power. Green! */
- outw(StopCoax, ioaddr + EL3_CMD);
- else if (dev->if_port == 1) {
- /* Disable link beat and jabber */
- EL3WINDOW(4);
- outw(0, ioaddr + WN4_MEDIA);
+ /* Check if the card still exists */
+ if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000)
+ update_stats(dev);
}
- /* Switching back to window 0 disables the IRQ. */
- EL3WINDOW(0);
- /* But we explicitly zero the IRQ line select anyway. */
- outw(0x0f00, ioaddr + WN0_IRQ);
-
- /* Check if the card still exists */
- if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000)
- update_stats(dev);
- }
-
- link->open--;
- netif_stop_queue(dev);
- del_timer_sync(&lp->media);
+ link->open--;
+ netif_stop_queue(dev);
+ del_timer_sync(&lp->media);
- return 0;
+ return 0;
}
static const struct pcmcia_device_id tc589_ids[] = {
diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c
index 0f4241c6e97e..61477b8e8d24 100644
--- a/drivers/net/ethernet/3com/3c59x.c
+++ b/drivers/net/ethernet/3com/3c59x.c
@@ -2086,7 +2086,7 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* ... and the packet rounded to a doubleword. */
skb_tx_timestamp(skb);
iowrite32_rep(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
- dev_kfree_skb (skb);
+ dev_consume_skb_any (skb);
if (ioread16(ioaddr + TxFree) > 1536) {
netif_start_queue (dev); /* AKPM: redundant? */
} else {
@@ -3294,7 +3294,6 @@ static int __init vortex_init(void)
static void __exit vortex_eisa_cleanup(void)
{
- struct vortex_private *vp;
void __iomem *ioaddr;
#ifdef CONFIG_EISA
@@ -3303,7 +3302,6 @@ static void __exit vortex_eisa_cleanup(void)
#endif
if (compaq_net_device) {
- vp = netdev_priv(compaq_net_device);
ioaddr = ioport_map(compaq_net_device->base_addr,
VORTEX_TOTAL_SIZE);
diff --git a/drivers/net/ethernet/8390/lib8390.c b/drivers/net/ethernet/8390/lib8390.c
index d2cd80444ade..599311f0e05c 100644
--- a/drivers/net/ethernet/8390/lib8390.c
+++ b/drivers/net/ethernet/8390/lib8390.c
@@ -404,7 +404,7 @@ static netdev_tx_t __ei_start_xmit(struct sk_buff *skb,
spin_unlock(&ei_local->page_lock);
enable_irq_lockdep_irqrestore(dev->irq, &flags);
skb_tx_timestamp(skb);
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
dev->stats.tx_bytes += send_length;
return NETDEV_TX_OK;
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index 506b0248c400..39b26fe28d10 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -22,6 +22,7 @@ source "drivers/net/ethernet/adaptec/Kconfig"
source "drivers/net/ethernet/aeroflex/Kconfig"
source "drivers/net/ethernet/allwinner/Kconfig"
source "drivers/net/ethernet/alteon/Kconfig"
+source "drivers/net/ethernet/altera/Kconfig"
source "drivers/net/ethernet/amd/Kconfig"
source "drivers/net/ethernet/apple/Kconfig"
source "drivers/net/ethernet/arc/Kconfig"
@@ -149,6 +150,7 @@ config S6GMAC
To compile this driver as a module, choose M here. The module
will be called s6gmac.
+source "drivers/net/ethernet/samsung/Kconfig"
source "drivers/net/ethernet/seeq/Kconfig"
source "drivers/net/ethernet/silan/Kconfig"
source "drivers/net/ethernet/sis/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index c0b8789952e7..545d0b3b9cb4 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_NET_VENDOR_ADAPTEC) += adaptec/
obj-$(CONFIG_GRETH) += aeroflex/
obj-$(CONFIG_NET_VENDOR_ALLWINNER) += allwinner/
obj-$(CONFIG_NET_VENDOR_ALTEON) += alteon/
+obj-$(CONFIG_ALTERA_TSE) += altera/
obj-$(CONFIG_NET_VENDOR_AMD) += amd/
obj-$(CONFIG_NET_VENDOR_APPLE) += apple/
obj-$(CONFIG_NET_VENDOR_ARC) += arc/
@@ -60,6 +61,7 @@ obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/
obj-$(CONFIG_SH_ETH) += renesas/
obj-$(CONFIG_NET_VENDOR_RDC) += rdc/
obj-$(CONFIG_S6GMAC) += s6gmac.o
+obj-$(CONFIG_NET_VENDOR_SAMSUNG) += samsung/
obj-$(CONFIG_NET_VENDOR_SEEQ) += seeq/
obj-$(CONFIG_NET_VENDOR_SILAN) += silan/
obj-$(CONFIG_NET_VENDOR_SIS) += sis/
diff --git a/drivers/net/ethernet/adi/bfin_mac.c b/drivers/net/ethernet/adi/bfin_mac.c
index c0f68dcd1dc1..7ae74d450e8f 100644
--- a/drivers/net/ethernet/adi/bfin_mac.c
+++ b/drivers/net/ethernet/adi/bfin_mac.c
@@ -307,11 +307,6 @@ static int bfin_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
return bfin_mdio_poll();
}
-static int bfin_mdiobus_reset(struct mii_bus *bus)
-{
- return 0;
-}
-
static void bfin_mac_adjust_link(struct net_device *dev)
{
struct bfin_mac_local *lp = netdev_priv(dev);
@@ -1040,6 +1035,7 @@ static struct ptp_clock_info bfin_ptp_caps = {
.n_alarm = 0,
.n_ext_ts = 0,
.n_per_out = 0,
+ .n_pins = 0,
.pps = 0,
.adjfreq = bfin_ptp_adjfreq,
.adjtime = bfin_ptp_adjtime,
@@ -1086,7 +1082,7 @@ static inline void _tx_reclaim_skb(void)
tx_list_head->desc_a.config &= ~DMAEN;
tx_list_head->status.status_word = 0;
if (tx_list_head->skb) {
- dev_kfree_skb(tx_list_head->skb);
+ dev_consume_skb_any(tx_list_head->skb);
tx_list_head->skb = NULL;
}
tx_list_head = tx_list_head->next;
@@ -1823,7 +1819,6 @@ static int bfin_mii_bus_probe(struct platform_device *pdev)
goto out_err_alloc;
miibus->read = bfin_mdiobus_read;
miibus->write = bfin_mdiobus_write;
- miibus->reset = bfin_mdiobus_reset;
miibus->parent = &pdev->dev;
miibus->name = "bfin_mii_bus";
diff --git a/drivers/net/ethernet/aeroflex/greth.c b/drivers/net/ethernet/aeroflex/greth.c
index c5d75e7aeeb6..23578dfee249 100644
--- a/drivers/net/ethernet/aeroflex/greth.c
+++ b/drivers/net/ethernet/aeroflex/greth.c
@@ -1213,11 +1213,6 @@ static int greth_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
return 0;
}
-static int greth_mdio_reset(struct mii_bus *bus)
-{
- return 0;
-}
-
static void greth_link_change(struct net_device *dev)
{
struct greth_private *greth = netdev_priv(dev);
@@ -1332,7 +1327,6 @@ static int greth_mdio_init(struct greth_private *greth)
snprintf(greth->mdio->id, MII_BUS_ID_SIZE, "%s-%d", greth->mdio->name, greth->irq);
greth->mdio->read = greth_mdio_read;
greth->mdio->write = greth_mdio_write;
- greth->mdio->reset = greth_mdio_reset;
greth->mdio->priv = greth;
greth->mdio->irq = greth->mdio_irqs;
diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c b/drivers/net/ethernet/allwinner/sun4i-emac.c
index 0cc21437478c..fcaeeb8a4929 100644
--- a/drivers/net/ethernet/allwinner/sun4i-emac.c
+++ b/drivers/net/ethernet/allwinner/sun4i-emac.c
@@ -476,7 +476,7 @@ static int emac_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&db->lock, flags);
/* free this SKB */
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -929,6 +929,9 @@ static int emac_resume(struct platform_device *dev)
}
static const struct of_device_id emac_of_match[] = {
+ {.compatible = "allwinner,sun4i-a10-emac",},
+
+ /* Deprecated */
{.compatible = "allwinner,sun4i-emac",},
{},
};
diff --git a/drivers/net/ethernet/altera/Kconfig b/drivers/net/ethernet/altera/Kconfig
new file mode 100644
index 000000000000..80c1ab74a4b8
--- /dev/null
+++ b/drivers/net/ethernet/altera/Kconfig
@@ -0,0 +1,8 @@
+config ALTERA_TSE
+ tristate "Altera Triple-Speed Ethernet MAC support"
+ select PHYLIB
+ ---help---
+ This driver supports the Altera Triple-Speed (TSE) Ethernet MAC.
+
+ To compile this driver as a module, choose M here. The module
+ will be called alteratse.
diff --git a/drivers/net/ethernet/altera/Makefile b/drivers/net/ethernet/altera/Makefile
new file mode 100644
index 000000000000..d4a187e45369
--- /dev/null
+++ b/drivers/net/ethernet/altera/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Altera device drivers.
+#
+
+obj-$(CONFIG_ALTERA_TSE) += altera_tse.o
+altera_tse-objs := altera_tse_main.o altera_tse_ethtool.o \
+altera_msgdma.o altera_sgdma.o altera_utils.o
diff --git a/drivers/net/ethernet/altera/altera_msgdma.c b/drivers/net/ethernet/altera/altera_msgdma.c
new file mode 100644
index 000000000000..3df18669ea30
--- /dev/null
+++ b/drivers/net/ethernet/altera/altera_msgdma.c
@@ -0,0 +1,202 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/netdevice.h>
+#include "altera_utils.h"
+#include "altera_tse.h"
+#include "altera_msgdmahw.h"
+
+/* No initialization work to do for MSGDMA */
+int msgdma_initialize(struct altera_tse_private *priv)
+{
+ return 0;
+}
+
+void msgdma_uninitialize(struct altera_tse_private *priv)
+{
+}
+
+void msgdma_reset(struct altera_tse_private *priv)
+{
+ int counter;
+ struct msgdma_csr *txcsr =
+ (struct msgdma_csr *)priv->tx_dma_csr;
+ struct msgdma_csr *rxcsr =
+ (struct msgdma_csr *)priv->rx_dma_csr;
+
+ /* Reset Rx mSGDMA */
+ iowrite32(MSGDMA_CSR_STAT_MASK, &rxcsr->status);
+ iowrite32(MSGDMA_CSR_CTL_RESET, &rxcsr->control);
+
+ counter = 0;
+ while (counter++ < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) {
+ if (tse_bit_is_clear(&rxcsr->status,
+ MSGDMA_CSR_STAT_RESETTING))
+ break;
+ udelay(1);
+ }
+
+ if (counter >= ALTERA_TSE_SW_RESET_WATCHDOG_CNTR)
+ netif_warn(priv, drv, priv->dev,
+ "TSE Rx mSGDMA resetting bit never cleared!\n");
+
+ /* clear all status bits */
+ iowrite32(MSGDMA_CSR_STAT_MASK, &rxcsr->status);
+
+ /* Reset Tx mSGDMA */
+ iowrite32(MSGDMA_CSR_STAT_MASK, &txcsr->status);
+ iowrite32(MSGDMA_CSR_CTL_RESET, &txcsr->control);
+
+ counter = 0;
+ while (counter++ < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) {
+ if (tse_bit_is_clear(&txcsr->status,
+ MSGDMA_CSR_STAT_RESETTING))
+ break;
+ udelay(1);
+ }
+
+ if (counter >= ALTERA_TSE_SW_RESET_WATCHDOG_CNTR)
+ netif_warn(priv, drv, priv->dev,
+ "TSE Tx mSGDMA resetting bit never cleared!\n");
+
+ /* clear all status bits */
+ iowrite32(MSGDMA_CSR_STAT_MASK, &txcsr->status);
+}
+
+void msgdma_disable_rxirq(struct altera_tse_private *priv)
+{
+ struct msgdma_csr *csr = priv->rx_dma_csr;
+ tse_clear_bit(&csr->control, MSGDMA_CSR_CTL_GLOBAL_INTR);
+}
+
+void msgdma_enable_rxirq(struct altera_tse_private *priv)
+{
+ struct msgdma_csr *csr = priv->rx_dma_csr;
+ tse_set_bit(&csr->control, MSGDMA_CSR_CTL_GLOBAL_INTR);
+}
+
+void msgdma_disable_txirq(struct altera_tse_private *priv)
+{
+ struct msgdma_csr *csr = priv->tx_dma_csr;
+ tse_clear_bit(&csr->control, MSGDMA_CSR_CTL_GLOBAL_INTR);
+}
+
+void msgdma_enable_txirq(struct altera_tse_private *priv)
+{
+ struct msgdma_csr *csr = priv->tx_dma_csr;
+ tse_set_bit(&csr->control, MSGDMA_CSR_CTL_GLOBAL_INTR);
+}
+
+void msgdma_clear_rxirq(struct altera_tse_private *priv)
+{
+ struct msgdma_csr *csr = priv->rx_dma_csr;
+ iowrite32(MSGDMA_CSR_STAT_IRQ, &csr->status);
+}
+
+void msgdma_clear_txirq(struct altera_tse_private *priv)
+{
+ struct msgdma_csr *csr = priv->tx_dma_csr;
+ iowrite32(MSGDMA_CSR_STAT_IRQ, &csr->status);
+}
+
+/* return 0 to indicate transmit is pending */
+int msgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *buffer)
+{
+ struct msgdma_extended_desc *desc = priv->tx_dma_desc;
+
+ iowrite32(lower_32_bits(buffer->dma_addr), &desc->read_addr_lo);
+ iowrite32(upper_32_bits(buffer->dma_addr), &desc->read_addr_hi);
+ iowrite32(0, &desc->write_addr_lo);
+ iowrite32(0, &desc->write_addr_hi);
+ iowrite32(buffer->len, &desc->len);
+ iowrite32(0, &desc->burst_seq_num);
+ iowrite32(MSGDMA_DESC_TX_STRIDE, &desc->stride);
+ iowrite32(MSGDMA_DESC_CTL_TX_SINGLE, &desc->control);
+ return 0;
+}
+
+u32 msgdma_tx_completions(struct altera_tse_private *priv)
+{
+ u32 ready = 0;
+ u32 inuse;
+ u32 status;
+ struct msgdma_csr *txcsr =
+ (struct msgdma_csr *)priv->tx_dma_csr;
+
+ /* Get number of sent descriptors */
+ inuse = ioread32(&txcsr->rw_fill_level) & 0xffff;
+
+ if (inuse) { /* Tx FIFO is not empty */
+ ready = priv->tx_prod - priv->tx_cons - inuse - 1;
+ } else {
+ /* Check for buffered last packet */
+ status = ioread32(&txcsr->status);
+ if (status & MSGDMA_CSR_STAT_BUSY)
+ ready = priv->tx_prod - priv->tx_cons - 1;
+ else
+ ready = priv->tx_prod - priv->tx_cons;
+ }
+ return ready;
+}
+
+/* Put buffer to the mSGDMA RX FIFO
+ */
+int msgdma_add_rx_desc(struct altera_tse_private *priv,
+ struct tse_buffer *rxbuffer)
+{
+ struct msgdma_extended_desc *desc = priv->rx_dma_desc;
+ u32 len = priv->rx_dma_buf_sz;
+ dma_addr_t dma_addr = rxbuffer->dma_addr;
+ u32 control = (MSGDMA_DESC_CTL_END_ON_EOP
+ | MSGDMA_DESC_CTL_END_ON_LEN
+ | MSGDMA_DESC_CTL_TR_COMP_IRQ
+ | MSGDMA_DESC_CTL_EARLY_IRQ
+ | MSGDMA_DESC_CTL_TR_ERR_IRQ
+ | MSGDMA_DESC_CTL_GO);
+
+ iowrite32(0, &desc->read_addr_lo);
+ iowrite32(0, &desc->read_addr_hi);
+ iowrite32(lower_32_bits(dma_addr), &desc->write_addr_lo);
+ iowrite32(upper_32_bits(dma_addr), &desc->write_addr_hi);
+ iowrite32(len, &desc->len);
+ iowrite32(0, &desc->burst_seq_num);
+ iowrite32(0x00010001, &desc->stride);
+ iowrite32(control, &desc->control);
+ return 1;
+}
+
+/* status is returned on upper 16 bits,
+ * length is returned in lower 16 bits
+ */
+u32 msgdma_rx_status(struct altera_tse_private *priv)
+{
+ u32 rxstatus = 0;
+ u32 pktlength;
+ u32 pktstatus;
+ struct msgdma_csr *rxcsr =
+ (struct msgdma_csr *)priv->rx_dma_csr;
+ struct msgdma_response *rxresp =
+ (struct msgdma_response *)priv->rx_dma_resp;
+
+ if (ioread32(&rxcsr->resp_fill_level) & 0xffff) {
+ pktlength = ioread32(&rxresp->bytes_transferred);
+ pktstatus = ioread32(&rxresp->status);
+ rxstatus = pktstatus;
+ rxstatus = rxstatus << 16;
+ rxstatus |= (pktlength & 0xffff);
+ }
+ return rxstatus;
+}
diff --git a/drivers/net/ethernet/altera/altera_msgdma.h b/drivers/net/ethernet/altera/altera_msgdma.h
new file mode 100644
index 000000000000..7f0f5bf2bba2
--- /dev/null
+++ b/drivers/net/ethernet/altera/altera_msgdma.h
@@ -0,0 +1,34 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ALTERA_MSGDMA_H__
+#define __ALTERA_MSGDMA_H__
+
+void msgdma_reset(struct altera_tse_private *);
+void msgdma_enable_txirq(struct altera_tse_private *);
+void msgdma_enable_rxirq(struct altera_tse_private *);
+void msgdma_disable_rxirq(struct altera_tse_private *);
+void msgdma_disable_txirq(struct altera_tse_private *);
+void msgdma_clear_rxirq(struct altera_tse_private *);
+void msgdma_clear_txirq(struct altera_tse_private *);
+u32 msgdma_tx_completions(struct altera_tse_private *);
+int msgdma_add_rx_desc(struct altera_tse_private *, struct tse_buffer *);
+int msgdma_tx_buffer(struct altera_tse_private *, struct tse_buffer *);
+u32 msgdma_rx_status(struct altera_tse_private *);
+int msgdma_initialize(struct altera_tse_private *);
+void msgdma_uninitialize(struct altera_tse_private *);
+
+#endif /* __ALTERA_MSGDMA_H__ */
diff --git a/drivers/net/ethernet/altera/altera_msgdmahw.h b/drivers/net/ethernet/altera/altera_msgdmahw.h
new file mode 100644
index 000000000000..d7b59ba4019c
--- /dev/null
+++ b/drivers/net/ethernet/altera/altera_msgdmahw.h
@@ -0,0 +1,167 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ALTERA_MSGDMAHW_H__
+#define __ALTERA_MSGDMAHW_H__
+
+/* mSGDMA standard descriptor format
+ */
+struct msgdma_desc {
+ u32 read_addr; /* data buffer source address */
+ u32 write_addr; /* data buffer destination address */
+ u32 len; /* the number of bytes to transfer per descriptor */
+ u32 control; /* characteristics of the transfer */
+};
+
+/* mSGDMA extended descriptor format
+ */
+struct msgdma_extended_desc {
+ u32 read_addr_lo; /* data buffer source address low bits */
+ u32 write_addr_lo; /* data buffer destination address low bits */
+ u32 len; /* the number of bytes to transfer
+ * per descriptor
+ */
+ u32 burst_seq_num; /* bit 31:24 write burst
+ * bit 23:16 read burst
+ * bit 15:0 sequence number
+ */
+ u32 stride; /* bit 31:16 write stride
+ * bit 15:0 read stride
+ */
+ u32 read_addr_hi; /* data buffer source address high bits */
+ u32 write_addr_hi; /* data buffer destination address high bits */
+ u32 control; /* characteristics of the transfer */
+};
+
+/* mSGDMA descriptor control field bit definitions
+ */
+#define MSGDMA_DESC_CTL_SET_CH(x) ((x) & 0xff)
+#define MSGDMA_DESC_CTL_GEN_SOP BIT(8)
+#define MSGDMA_DESC_CTL_GEN_EOP BIT(9)
+#define MSGDMA_DESC_CTL_PARK_READS BIT(10)
+#define MSGDMA_DESC_CTL_PARK_WRITES BIT(11)
+#define MSGDMA_DESC_CTL_END_ON_EOP BIT(12)
+#define MSGDMA_DESC_CTL_END_ON_LEN BIT(13)
+#define MSGDMA_DESC_CTL_TR_COMP_IRQ BIT(14)
+#define MSGDMA_DESC_CTL_EARLY_IRQ BIT(15)
+#define MSGDMA_DESC_CTL_TR_ERR_IRQ (0xff << 16)
+#define MSGDMA_DESC_CTL_EARLY_DONE BIT(24)
+/* Writing ‘1’ to the ‘go’ bit commits the entire descriptor into the
+ * descriptor FIFO(s)
+ */
+#define MSGDMA_DESC_CTL_GO BIT(31)
+
+/* Tx buffer control flags
+ */
+#define MSGDMA_DESC_CTL_TX_FIRST (MSGDMA_DESC_CTL_GEN_SOP | \
+ MSGDMA_DESC_CTL_TR_ERR_IRQ | \
+ MSGDMA_DESC_CTL_GO)
+
+#define MSGDMA_DESC_CTL_TX_MIDDLE (MSGDMA_DESC_CTL_TR_ERR_IRQ | \
+ MSGDMA_DESC_CTL_GO)
+
+#define MSGDMA_DESC_CTL_TX_LAST (MSGDMA_DESC_CTL_GEN_EOP | \
+ MSGDMA_DESC_CTL_TR_COMP_IRQ | \
+ MSGDMA_DESC_CTL_TR_ERR_IRQ | \
+ MSGDMA_DESC_CTL_GO)
+
+#define MSGDMA_DESC_CTL_TX_SINGLE (MSGDMA_DESC_CTL_GEN_SOP | \
+ MSGDMA_DESC_CTL_GEN_EOP | \
+ MSGDMA_DESC_CTL_TR_COMP_IRQ | \
+ MSGDMA_DESC_CTL_TR_ERR_IRQ | \
+ MSGDMA_DESC_CTL_GO)
+
+#define MSGDMA_DESC_CTL_RX_SINGLE (MSGDMA_DESC_CTL_END_ON_EOP | \
+ MSGDMA_DESC_CTL_END_ON_LEN | \
+ MSGDMA_DESC_CTL_TR_COMP_IRQ | \
+ MSGDMA_DESC_CTL_EARLY_IRQ | \
+ MSGDMA_DESC_CTL_TR_ERR_IRQ | \
+ MSGDMA_DESC_CTL_GO)
+
+/* mSGDMA extended descriptor stride definitions
+ */
+#define MSGDMA_DESC_TX_STRIDE (0x00010001)
+#define MSGDMA_DESC_RX_STRIDE (0x00010001)
+
+/* mSGDMA dispatcher control and status register map
+ */
+struct msgdma_csr {
+ u32 status; /* Read/Clear */
+ u32 control; /* Read/Write */
+ u32 rw_fill_level; /* bit 31:16 - write fill level
+ * bit 15:0 - read fill level
+ */
+ u32 resp_fill_level; /* bit 15:0 */
+ u32 rw_seq_num; /* bit 31:16 - write sequence number
+ * bit 15:0 - read sequence number
+ */
+ u32 pad[3]; /* reserved */
+};
+
+/* mSGDMA CSR status register bit definitions
+ */
+#define MSGDMA_CSR_STAT_BUSY BIT(0)
+#define MSGDMA_CSR_STAT_DESC_BUF_EMPTY BIT(1)
+#define MSGDMA_CSR_STAT_DESC_BUF_FULL BIT(2)
+#define MSGDMA_CSR_STAT_RESP_BUF_EMPTY BIT(3)
+#define MSGDMA_CSR_STAT_RESP_BUF_FULL BIT(4)
+#define MSGDMA_CSR_STAT_STOPPED BIT(5)
+#define MSGDMA_CSR_STAT_RESETTING BIT(6)
+#define MSGDMA_CSR_STAT_STOPPED_ON_ERR BIT(7)
+#define MSGDMA_CSR_STAT_STOPPED_ON_EARLY BIT(8)
+#define MSGDMA_CSR_STAT_IRQ BIT(9)
+#define MSGDMA_CSR_STAT_MASK 0x3FF
+#define MSGDMA_CSR_STAT_MASK_WITHOUT_IRQ 0x1FF
+
+#define MSGDMA_CSR_STAT_BUSY_GET(v) GET_BIT_VALUE(v, 0)
+#define MSGDMA_CSR_STAT_DESC_BUF_EMPTY_GET(v) GET_BIT_VALUE(v, 1)
+#define MSGDMA_CSR_STAT_DESC_BUF_FULL_GET(v) GET_BIT_VALUE(v, 2)
+#define MSGDMA_CSR_STAT_RESP_BUF_EMPTY_GET(v) GET_BIT_VALUE(v, 3)
+#define MSGDMA_CSR_STAT_RESP_BUF_FULL_GET(v) GET_BIT_VALUE(v, 4)
+#define MSGDMA_CSR_STAT_STOPPED_GET(v) GET_BIT_VALUE(v, 5)
+#define MSGDMA_CSR_STAT_RESETTING_GET(v) GET_BIT_VALUE(v, 6)
+#define MSGDMA_CSR_STAT_STOPPED_ON_ERR_GET(v) GET_BIT_VALUE(v, 7)
+#define MSGDMA_CSR_STAT_STOPPED_ON_EARLY_GET(v) GET_BIT_VALUE(v, 8)
+#define MSGDMA_CSR_STAT_IRQ_GET(v) GET_BIT_VALUE(v, 9)
+
+/* mSGDMA CSR control register bit definitions
+ */
+#define MSGDMA_CSR_CTL_STOP BIT(0)
+#define MSGDMA_CSR_CTL_RESET BIT(1)
+#define MSGDMA_CSR_CTL_STOP_ON_ERR BIT(2)
+#define MSGDMA_CSR_CTL_STOP_ON_EARLY BIT(3)
+#define MSGDMA_CSR_CTL_GLOBAL_INTR BIT(4)
+#define MSGDMA_CSR_CTL_STOP_DESCS BIT(5)
+
+/* mSGDMA CSR fill level bits
+ */
+#define MSGDMA_CSR_WR_FILL_LEVEL_GET(v) (((v) & 0xffff0000) >> 16)
+#define MSGDMA_CSR_RD_FILL_LEVEL_GET(v) ((v) & 0x0000ffff)
+#define MSGDMA_CSR_RESP_FILL_LEVEL_GET(v) ((v) & 0x0000ffff)
+
+/* mSGDMA response register map
+ */
+struct msgdma_response {
+ u32 bytes_transferred;
+ u32 status;
+};
+
+/* mSGDMA response register bit definitions
+ */
+#define MSGDMA_RESP_EARLY_TERM BIT(8)
+#define MSGDMA_RESP_ERR_MASK 0xFF
+
+#endif /* __ALTERA_MSGDMA_H__*/
diff --git a/drivers/net/ethernet/altera/altera_sgdma.c b/drivers/net/ethernet/altera/altera_sgdma.c
new file mode 100644
index 000000000000..0ee96639ae44
--- /dev/null
+++ b/drivers/net/ethernet/altera/altera_sgdma.c
@@ -0,0 +1,509 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/list.h>
+#include "altera_utils.h"
+#include "altera_tse.h"
+#include "altera_sgdmahw.h"
+#include "altera_sgdma.h"
+
+static void sgdma_descrip(struct sgdma_descrip *desc,
+ struct sgdma_descrip *ndesc,
+ dma_addr_t ndesc_phys,
+ dma_addr_t raddr,
+ dma_addr_t waddr,
+ u16 length,
+ int generate_eop,
+ int rfixed,
+ int wfixed);
+
+static int sgdma_async_write(struct altera_tse_private *priv,
+ struct sgdma_descrip *desc);
+
+static int sgdma_async_read(struct altera_tse_private *priv);
+
+static dma_addr_t
+sgdma_txphysaddr(struct altera_tse_private *priv,
+ struct sgdma_descrip *desc);
+
+static dma_addr_t
+sgdma_rxphysaddr(struct altera_tse_private *priv,
+ struct sgdma_descrip *desc);
+
+static int sgdma_txbusy(struct altera_tse_private *priv);
+
+static int sgdma_rxbusy(struct altera_tse_private *priv);
+
+static void
+queue_tx(struct altera_tse_private *priv, struct tse_buffer *buffer);
+
+static void
+queue_rx(struct altera_tse_private *priv, struct tse_buffer *buffer);
+
+static struct tse_buffer *
+dequeue_tx(struct altera_tse_private *priv);
+
+static struct tse_buffer *
+dequeue_rx(struct altera_tse_private *priv);
+
+static struct tse_buffer *
+queue_rx_peekhead(struct altera_tse_private *priv);
+
+int sgdma_initialize(struct altera_tse_private *priv)
+{
+ priv->txctrlreg = SGDMA_CTRLREG_ILASTD;
+
+ priv->rxctrlreg = SGDMA_CTRLREG_IDESCRIP |
+ SGDMA_CTRLREG_ILASTD;
+
+ INIT_LIST_HEAD(&priv->txlisthd);
+ INIT_LIST_HEAD(&priv->rxlisthd);
+
+ priv->rxdescphys = (dma_addr_t) 0;
+ priv->txdescphys = (dma_addr_t) 0;
+
+ priv->rxdescphys = dma_map_single(priv->device, priv->rx_dma_desc,
+ priv->rxdescmem, DMA_BIDIRECTIONAL);
+
+ if (dma_mapping_error(priv->device, priv->rxdescphys)) {
+ sgdma_uninitialize(priv);
+ netdev_err(priv->dev, "error mapping rx descriptor memory\n");
+ return -EINVAL;
+ }
+
+ priv->txdescphys = dma_map_single(priv->device, priv->tx_dma_desc,
+ priv->txdescmem, DMA_TO_DEVICE);
+
+ if (dma_mapping_error(priv->device, priv->txdescphys)) {
+ sgdma_uninitialize(priv);
+ netdev_err(priv->dev, "error mapping tx descriptor memory\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void sgdma_uninitialize(struct altera_tse_private *priv)
+{
+ if (priv->rxdescphys)
+ dma_unmap_single(priv->device, priv->rxdescphys,
+ priv->rxdescmem, DMA_BIDIRECTIONAL);
+
+ if (priv->txdescphys)
+ dma_unmap_single(priv->device, priv->txdescphys,
+ priv->txdescmem, DMA_TO_DEVICE);
+}
+
+/* This function resets the SGDMA controller and clears the
+ * descriptor memory used for transmits and receives.
+ */
+void sgdma_reset(struct altera_tse_private *priv)
+{
+ u32 *ptxdescripmem = (u32 *)priv->tx_dma_desc;
+ u32 txdescriplen = priv->txdescmem;
+ u32 *prxdescripmem = (u32 *)priv->rx_dma_desc;
+ u32 rxdescriplen = priv->rxdescmem;
+ struct sgdma_csr *ptxsgdma = (struct sgdma_csr *)priv->tx_dma_csr;
+ struct sgdma_csr *prxsgdma = (struct sgdma_csr *)priv->rx_dma_csr;
+
+ /* Initialize descriptor memory to 0 */
+ memset(ptxdescripmem, 0, txdescriplen);
+ memset(prxdescripmem, 0, rxdescriplen);
+
+ iowrite32(SGDMA_CTRLREG_RESET, &ptxsgdma->control);
+ iowrite32(0, &ptxsgdma->control);
+
+ iowrite32(SGDMA_CTRLREG_RESET, &prxsgdma->control);
+ iowrite32(0, &prxsgdma->control);
+}
+
+void sgdma_enable_rxirq(struct altera_tse_private *priv)
+{
+ struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr;
+ priv->rxctrlreg |= SGDMA_CTRLREG_INTEN;
+ tse_set_bit(&csr->control, SGDMA_CTRLREG_INTEN);
+}
+
+void sgdma_enable_txirq(struct altera_tse_private *priv)
+{
+ struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr;
+ priv->txctrlreg |= SGDMA_CTRLREG_INTEN;
+ tse_set_bit(&csr->control, SGDMA_CTRLREG_INTEN);
+}
+
+/* for SGDMA, RX interrupts remain enabled after enabling */
+void sgdma_disable_rxirq(struct altera_tse_private *priv)
+{
+}
+
+/* for SGDMA, TX interrupts remain enabled after enabling */
+void sgdma_disable_txirq(struct altera_tse_private *priv)
+{
+}
+
+void sgdma_clear_rxirq(struct altera_tse_private *priv)
+{
+ struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr;
+ tse_set_bit(&csr->control, SGDMA_CTRLREG_CLRINT);
+}
+
+void sgdma_clear_txirq(struct altera_tse_private *priv)
+{
+ struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr;
+ tse_set_bit(&csr->control, SGDMA_CTRLREG_CLRINT);
+}
+
+/* transmits buffer through SGDMA. Returns number of buffers
+ * transmitted, 0 if not possible.
+ *
+ * tx_lock is held by the caller
+ */
+int sgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *buffer)
+{
+ int pktstx = 0;
+ struct sgdma_descrip *descbase =
+ (struct sgdma_descrip *)priv->tx_dma_desc;
+
+ struct sgdma_descrip *cdesc = &descbase[0];
+ struct sgdma_descrip *ndesc = &descbase[1];
+
+ /* wait 'til the tx sgdma is ready for the next transmit request */
+ if (sgdma_txbusy(priv))
+ return 0;
+
+ sgdma_descrip(cdesc, /* current descriptor */
+ ndesc, /* next descriptor */
+ sgdma_txphysaddr(priv, ndesc),
+ buffer->dma_addr, /* address of packet to xmit */
+ 0, /* write addr 0 for tx dma */
+ buffer->len, /* length of packet */
+ SGDMA_CONTROL_EOP, /* Generate EOP */
+ 0, /* read fixed */
+ SGDMA_CONTROL_WR_FIXED); /* Generate SOP */
+
+ pktstx = sgdma_async_write(priv, cdesc);
+
+ /* enqueue the request to the pending transmit queue */
+ queue_tx(priv, buffer);
+
+ return 1;
+}
+
+
+/* tx_lock held to protect access to queued tx list
+ */
+u32 sgdma_tx_completions(struct altera_tse_private *priv)
+{
+ u32 ready = 0;
+ struct sgdma_descrip *desc = (struct sgdma_descrip *)priv->tx_dma_desc;
+
+ if (!sgdma_txbusy(priv) &&
+ ((desc->control & SGDMA_CONTROL_HW_OWNED) == 0) &&
+ (dequeue_tx(priv))) {
+ ready = 1;
+ }
+
+ return ready;
+}
+
+int sgdma_add_rx_desc(struct altera_tse_private *priv,
+ struct tse_buffer *rxbuffer)
+{
+ queue_rx(priv, rxbuffer);
+ return sgdma_async_read(priv);
+}
+
+/* status is returned on upper 16 bits,
+ * length is returned in lower 16 bits
+ */
+u32 sgdma_rx_status(struct altera_tse_private *priv)
+{
+ struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr;
+ struct sgdma_descrip *base = (struct sgdma_descrip *)priv->rx_dma_desc;
+ struct sgdma_descrip *desc = NULL;
+ int pktsrx;
+ unsigned int rxstatus = 0;
+ unsigned int pktlength = 0;
+ unsigned int pktstatus = 0;
+ struct tse_buffer *rxbuffer = NULL;
+
+ dma_sync_single_for_cpu(priv->device,
+ priv->rxdescphys,
+ priv->rxdescmem,
+ DMA_BIDIRECTIONAL);
+
+ desc = &base[0];
+ if ((ioread32(&csr->status) & SGDMA_STSREG_EOP) ||
+ (desc->status & SGDMA_STATUS_EOP)) {
+ pktlength = desc->bytes_xferred;
+ pktstatus = desc->status & 0x3f;
+ rxstatus = pktstatus;
+ rxstatus = rxstatus << 16;
+ rxstatus |= (pktlength & 0xffff);
+
+ desc->status = 0;
+
+ rxbuffer = dequeue_rx(priv);
+ if (rxbuffer == NULL)
+ netdev_err(priv->dev,
+ "sgdma rx and rx queue empty!\n");
+
+ /* kick the rx sgdma after reaping this descriptor */
+ pktsrx = sgdma_async_read(priv);
+ }
+
+ return rxstatus;
+}
+
+
+/* Private functions */
+static void sgdma_descrip(struct sgdma_descrip *desc,
+ struct sgdma_descrip *ndesc,
+ dma_addr_t ndesc_phys,
+ dma_addr_t raddr,
+ dma_addr_t waddr,
+ u16 length,
+ int generate_eop,
+ int rfixed,
+ int wfixed)
+{
+ /* Clear the next descriptor as not owned by hardware */
+ u32 ctrl = ndesc->control;
+ ctrl &= ~SGDMA_CONTROL_HW_OWNED;
+ ndesc->control = ctrl;
+
+ ctrl = 0;
+ ctrl = SGDMA_CONTROL_HW_OWNED;
+ ctrl |= generate_eop;
+ ctrl |= rfixed;
+ ctrl |= wfixed;
+
+ /* Channel is implicitly zero, initialized to 0 by default */
+
+ desc->raddr = raddr;
+ desc->waddr = waddr;
+ desc->next = lower_32_bits(ndesc_phys);
+ desc->control = ctrl;
+ desc->status = 0;
+ desc->rburst = 0;
+ desc->wburst = 0;
+ desc->bytes = length;
+ desc->bytes_xferred = 0;
+}
+
+/* If hardware is busy, don't restart async read.
+ * if status register is 0 - meaning initial state, restart async read,
+ * probably for the first time when populating a receive buffer.
+ * If read status indicate not busy and a status, restart the async
+ * DMA read.
+ */
+static int sgdma_async_read(struct altera_tse_private *priv)
+{
+ struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr;
+ struct sgdma_descrip *descbase =
+ (struct sgdma_descrip *)priv->rx_dma_desc;
+
+ struct sgdma_descrip *cdesc = &descbase[0];
+ struct sgdma_descrip *ndesc = &descbase[1];
+
+ unsigned int sts = ioread32(&csr->status);
+ struct tse_buffer *rxbuffer = NULL;
+
+ if (!sgdma_rxbusy(priv)) {
+ rxbuffer = queue_rx_peekhead(priv);
+ if (rxbuffer == NULL)
+ return 0;
+
+ sgdma_descrip(cdesc, /* current descriptor */
+ ndesc, /* next descriptor */
+ sgdma_rxphysaddr(priv, ndesc),
+ 0, /* read addr 0 for rx dma */
+ rxbuffer->dma_addr, /* write addr for rx dma */
+ 0, /* read 'til EOP */
+ 0, /* EOP: NA for rx dma */
+ 0, /* read fixed: NA for rx dma */
+ 0); /* SOP: NA for rx DMA */
+
+ /* clear control and status */
+ iowrite32(0, &csr->control);
+
+ /* If status available, clear those bits */
+ if (sts & 0xf)
+ iowrite32(0xf, &csr->status);
+
+ dma_sync_single_for_device(priv->device,
+ priv->rxdescphys,
+ priv->rxdescmem,
+ DMA_BIDIRECTIONAL);
+
+ iowrite32(lower_32_bits(sgdma_rxphysaddr(priv, cdesc)),
+ &csr->next_descrip);
+
+ iowrite32((priv->rxctrlreg | SGDMA_CTRLREG_START),
+ &csr->control);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static int sgdma_async_write(struct altera_tse_private *priv,
+ struct sgdma_descrip *desc)
+{
+ struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr;
+
+ if (sgdma_txbusy(priv))
+ return 0;
+
+ /* clear control and status */
+ iowrite32(0, &csr->control);
+ iowrite32(0x1f, &csr->status);
+
+ dma_sync_single_for_device(priv->device, priv->txdescphys,
+ priv->txdescmem, DMA_TO_DEVICE);
+
+ iowrite32(lower_32_bits(sgdma_txphysaddr(priv, desc)),
+ &csr->next_descrip);
+
+ iowrite32((priv->txctrlreg | SGDMA_CTRLREG_START),
+ &csr->control);
+
+ return 1;
+}
+
+static dma_addr_t
+sgdma_txphysaddr(struct altera_tse_private *priv,
+ struct sgdma_descrip *desc)
+{
+ dma_addr_t paddr = priv->txdescmem_busaddr;
+ uintptr_t offs = (uintptr_t)desc - (uintptr_t)priv->tx_dma_desc;
+ return (dma_addr_t)((uintptr_t)paddr + offs);
+}
+
+static dma_addr_t
+sgdma_rxphysaddr(struct altera_tse_private *priv,
+ struct sgdma_descrip *desc)
+{
+ dma_addr_t paddr = priv->rxdescmem_busaddr;
+ uintptr_t offs = (uintptr_t)desc - (uintptr_t)priv->rx_dma_desc;
+ return (dma_addr_t)((uintptr_t)paddr + offs);
+}
+
+#define list_remove_head(list, entry, type, member) \
+ do { \
+ entry = NULL; \
+ if (!list_empty(list)) { \
+ entry = list_entry((list)->next, type, member); \
+ list_del_init(&entry->member); \
+ } \
+ } while (0)
+
+#define list_peek_head(list, entry, type, member) \
+ do { \
+ entry = NULL; \
+ if (!list_empty(list)) { \
+ entry = list_entry((list)->next, type, member); \
+ } \
+ } while (0)
+
+/* adds a tse_buffer to the tail of a tx buffer list.
+ * assumes the caller is managing and holding a mutual exclusion
+ * primitive to avoid simultaneous pushes/pops to the list.
+ */
+static void
+queue_tx(struct altera_tse_private *priv, struct tse_buffer *buffer)
+{
+ list_add_tail(&buffer->lh, &priv->txlisthd);
+}
+
+
+/* adds a tse_buffer to the tail of a rx buffer list
+ * assumes the caller is managing and holding a mutual exclusion
+ * primitive to avoid simultaneous pushes/pops to the list.
+ */
+static void
+queue_rx(struct altera_tse_private *priv, struct tse_buffer *buffer)
+{
+ list_add_tail(&buffer->lh, &priv->rxlisthd);
+}
+
+/* dequeues a tse_buffer from the transmit buffer list, otherwise
+ * returns NULL if empty.
+ * assumes the caller is managing and holding a mutual exclusion
+ * primitive to avoid simultaneous pushes/pops to the list.
+ */
+static struct tse_buffer *
+dequeue_tx(struct altera_tse_private *priv)
+{
+ struct tse_buffer *buffer = NULL;
+ list_remove_head(&priv->txlisthd, buffer, struct tse_buffer, lh);
+ return buffer;
+}
+
+/* dequeues a tse_buffer from the receive buffer list, otherwise
+ * returns NULL if empty
+ * assumes the caller is managing and holding a mutual exclusion
+ * primitive to avoid simultaneous pushes/pops to the list.
+ */
+static struct tse_buffer *
+dequeue_rx(struct altera_tse_private *priv)
+{
+ struct tse_buffer *buffer = NULL;
+ list_remove_head(&priv->rxlisthd, buffer, struct tse_buffer, lh);
+ return buffer;
+}
+
+/* dequeues a tse_buffer from the receive buffer list, otherwise
+ * returns NULL if empty
+ * assumes the caller is managing and holding a mutual exclusion
+ * primitive to avoid simultaneous pushes/pops to the list while the
+ * head is being examined.
+ */
+static struct tse_buffer *
+queue_rx_peekhead(struct altera_tse_private *priv)
+{
+ struct tse_buffer *buffer = NULL;
+ list_peek_head(&priv->rxlisthd, buffer, struct tse_buffer, lh);
+ return buffer;
+}
+
+/* check and return rx sgdma status without polling
+ */
+static int sgdma_rxbusy(struct altera_tse_private *priv)
+{
+ struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr;
+ return ioread32(&csr->status) & SGDMA_STSREG_BUSY;
+}
+
+/* waits for the tx sgdma to finish it's current operation, returns 0
+ * when it transitions to nonbusy, returns 1 if the operation times out
+ */
+static int sgdma_txbusy(struct altera_tse_private *priv)
+{
+ int delay = 0;
+ struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr;
+
+ /* if DMA is busy, wait for current transactino to finish */
+ while ((ioread32(&csr->status) & SGDMA_STSREG_BUSY) && (delay++ < 100))
+ udelay(1);
+
+ if (ioread32(&csr->status) & SGDMA_STSREG_BUSY) {
+ netdev_err(priv->dev, "timeout waiting for tx dma\n");
+ return 1;
+ }
+ return 0;
+}
diff --git a/drivers/net/ethernet/altera/altera_sgdma.h b/drivers/net/ethernet/altera/altera_sgdma.h
new file mode 100644
index 000000000000..07d471729dc4
--- /dev/null
+++ b/drivers/net/ethernet/altera/altera_sgdma.h
@@ -0,0 +1,35 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ALTERA_SGDMA_H__
+#define __ALTERA_SGDMA_H__
+
+void sgdma_reset(struct altera_tse_private *);
+void sgdma_enable_txirq(struct altera_tse_private *);
+void sgdma_enable_rxirq(struct altera_tse_private *);
+void sgdma_disable_rxirq(struct altera_tse_private *);
+void sgdma_disable_txirq(struct altera_tse_private *);
+void sgdma_clear_rxirq(struct altera_tse_private *);
+void sgdma_clear_txirq(struct altera_tse_private *);
+int sgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *);
+u32 sgdma_tx_completions(struct altera_tse_private *);
+int sgdma_add_rx_desc(struct altera_tse_private *priv, struct tse_buffer *);
+void sgdma_status(struct altera_tse_private *);
+u32 sgdma_rx_status(struct altera_tse_private *);
+int sgdma_initialize(struct altera_tse_private *);
+void sgdma_uninitialize(struct altera_tse_private *);
+
+#endif /* __ALTERA_SGDMA_H__ */
diff --git a/drivers/net/ethernet/altera/altera_sgdmahw.h b/drivers/net/ethernet/altera/altera_sgdmahw.h
new file mode 100644
index 000000000000..ba3334f35383
--- /dev/null
+++ b/drivers/net/ethernet/altera/altera_sgdmahw.h
@@ -0,0 +1,124 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ALTERA_SGDMAHW_H__
+#define __ALTERA_SGDMAHW_H__
+
+/* SGDMA descriptor structure */
+struct sgdma_descrip {
+ unsigned int raddr; /* address of data to be read */
+ unsigned int pad1;
+ unsigned int waddr;
+ unsigned int pad2;
+ unsigned int next;
+ unsigned int pad3;
+ unsigned short bytes;
+ unsigned char rburst;
+ unsigned char wburst;
+ unsigned short bytes_xferred; /* 16 bits, bytes xferred */
+
+ /* bit 0: error
+ * bit 1: length error
+ * bit 2: crc error
+ * bit 3: truncated error
+ * bit 4: phy error
+ * bit 5: collision error
+ * bit 6: reserved
+ * bit 7: status eop for recv case
+ */
+ unsigned char status;
+
+ /* bit 0: eop
+ * bit 1: read_fixed
+ * bit 2: write fixed
+ * bits 3,4,5,6: Channel (always 0)
+ * bit 7: hardware owned
+ */
+ unsigned char control;
+} __packed;
+
+
+#define SGDMA_STATUS_ERR BIT(0)
+#define SGDMA_STATUS_LENGTH_ERR BIT(1)
+#define SGDMA_STATUS_CRC_ERR BIT(2)
+#define SGDMA_STATUS_TRUNC_ERR BIT(3)
+#define SGDMA_STATUS_PHY_ERR BIT(4)
+#define SGDMA_STATUS_COLL_ERR BIT(5)
+#define SGDMA_STATUS_EOP BIT(7)
+
+#define SGDMA_CONTROL_EOP BIT(0)
+#define SGDMA_CONTROL_RD_FIXED BIT(1)
+#define SGDMA_CONTROL_WR_FIXED BIT(2)
+
+/* Channel is always 0, so just zero initialize it */
+
+#define SGDMA_CONTROL_HW_OWNED BIT(7)
+
+/* SGDMA register space */
+struct sgdma_csr {
+ /* bit 0: error
+ * bit 1: eop
+ * bit 2: descriptor completed
+ * bit 3: chain completed
+ * bit 4: busy
+ * remainder reserved
+ */
+ u32 status;
+ u32 pad1[3];
+
+ /* bit 0: interrupt on error
+ * bit 1: interrupt on eop
+ * bit 2: interrupt after every descriptor
+ * bit 3: interrupt after last descrip in a chain
+ * bit 4: global interrupt enable
+ * bit 5: starts descriptor processing
+ * bit 6: stop core on dma error
+ * bit 7: interrupt on max descriptors
+ * bits 8-15: max descriptors to generate interrupt
+ * bit 16: Software reset
+ * bit 17: clears owned by hardware if 0, does not clear otherwise
+ * bit 18: enables descriptor polling mode
+ * bit 19-26: clocks before polling again
+ * bit 27-30: reserved
+ * bit 31: clear interrupt
+ */
+ u32 control;
+ u32 pad2[3];
+ u32 next_descrip;
+ u32 pad3[3];
+};
+
+
+#define SGDMA_STSREG_ERR BIT(0) /* Error */
+#define SGDMA_STSREG_EOP BIT(1) /* EOP */
+#define SGDMA_STSREG_DESCRIP BIT(2) /* Descriptor completed */
+#define SGDMA_STSREG_CHAIN BIT(3) /* Chain completed */
+#define SGDMA_STSREG_BUSY BIT(4) /* Controller busy */
+
+#define SGDMA_CTRLREG_IOE BIT(0) /* Interrupt on error */
+#define SGDMA_CTRLREG_IOEOP BIT(1) /* Interrupt on EOP */
+#define SGDMA_CTRLREG_IDESCRIP BIT(2) /* Interrupt after every descriptor */
+#define SGDMA_CTRLREG_ILASTD BIT(3) /* Interrupt after last descriptor */
+#define SGDMA_CTRLREG_INTEN BIT(4) /* Global Interrupt enable */
+#define SGDMA_CTRLREG_START BIT(5) /* starts descriptor processing */
+#define SGDMA_CTRLREG_STOPERR BIT(6) /* stop on dma error */
+#define SGDMA_CTRLREG_INTMAX BIT(7) /* Interrupt on max descriptors */
+#define SGDMA_CTRLREG_RESET BIT(16)/* Software reset */
+#define SGDMA_CTRLREG_COBHW BIT(17)/* Clears owned by hardware */
+#define SGDMA_CTRLREG_POLL BIT(18)/* enables descriptor polling mode */
+#define SGDMA_CTRLREG_CLRINT BIT(31)/* Clears interrupt */
+
+#endif /* __ALTERA_SGDMAHW_H__ */
diff --git a/drivers/net/ethernet/altera/altera_tse.h b/drivers/net/ethernet/altera/altera_tse.h
new file mode 100644
index 000000000000..8feeed05de0e
--- /dev/null
+++ b/drivers/net/ethernet/altera/altera_tse.h
@@ -0,0 +1,486 @@
+/* Altera Triple-Speed Ethernet MAC driver
+ * Copyright (C) 2008-2014 Altera Corporation. All rights reserved
+ *
+ * Contributors:
+ * Dalon Westergreen
+ * Thomas Chou
+ * Ian Abbott
+ * Yuriy Kozlov
+ * Tobias Klauser
+ * Andriy Smolskyy
+ * Roman Bulgakov
+ * Dmytro Mytarchuk
+ * Matthew Gerlach
+ *
+ * Original driver contributed by SLS.
+ * Major updates contributed by GlobalLogic
+ *
+ * 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/>.
+ */
+
+#ifndef __ALTERA_TSE_H__
+#define __ALTERA_TSE_H__
+
+#define ALTERA_TSE_RESOURCE_NAME "altera_tse"
+
+#include <linux/bitops.h>
+#include <linux/if_vlan.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+
+#define ALTERA_TSE_SW_RESET_WATCHDOG_CNTR 10000
+#define ALTERA_TSE_MAC_FIFO_WIDTH 4 /* TX/RX FIFO width in
+ * bytes
+ */
+/* Rx FIFO default settings */
+#define ALTERA_TSE_RX_SECTION_EMPTY 16
+#define ALTERA_TSE_RX_SECTION_FULL 0
+#define ALTERA_TSE_RX_ALMOST_EMPTY 8
+#define ALTERA_TSE_RX_ALMOST_FULL 8
+
+/* Tx FIFO default settings */
+#define ALTERA_TSE_TX_SECTION_EMPTY 16
+#define ALTERA_TSE_TX_SECTION_FULL 0
+#define ALTERA_TSE_TX_ALMOST_EMPTY 8
+#define ALTERA_TSE_TX_ALMOST_FULL 3
+
+/* MAC function configuration default settings */
+#define ALTERA_TSE_TX_IPG_LENGTH 12
+
+#define GET_BIT_VALUE(v, bit) (((v) >> (bit)) & 0x1)
+
+/* MAC Command_Config Register Bit Definitions
+ */
+#define MAC_CMDCFG_TX_ENA BIT(0)
+#define MAC_CMDCFG_RX_ENA BIT(1)
+#define MAC_CMDCFG_XON_GEN BIT(2)
+#define MAC_CMDCFG_ETH_SPEED BIT(3)
+#define MAC_CMDCFG_PROMIS_EN BIT(4)
+#define MAC_CMDCFG_PAD_EN BIT(5)
+#define MAC_CMDCFG_CRC_FWD BIT(6)
+#define MAC_CMDCFG_PAUSE_FWD BIT(7)
+#define MAC_CMDCFG_PAUSE_IGNORE BIT(8)
+#define MAC_CMDCFG_TX_ADDR_INS BIT(9)
+#define MAC_CMDCFG_HD_ENA BIT(10)
+#define MAC_CMDCFG_EXCESS_COL BIT(11)
+#define MAC_CMDCFG_LATE_COL BIT(12)
+#define MAC_CMDCFG_SW_RESET BIT(13)
+#define MAC_CMDCFG_MHASH_SEL BIT(14)
+#define MAC_CMDCFG_LOOP_ENA BIT(15)
+#define MAC_CMDCFG_TX_ADDR_SEL(v) (((v) & 0x7) << 16)
+#define MAC_CMDCFG_MAGIC_ENA BIT(19)
+#define MAC_CMDCFG_SLEEP BIT(20)
+#define MAC_CMDCFG_WAKEUP BIT(21)
+#define MAC_CMDCFG_XOFF_GEN BIT(22)
+#define MAC_CMDCFG_CNTL_FRM_ENA BIT(23)
+#define MAC_CMDCFG_NO_LGTH_CHECK BIT(24)
+#define MAC_CMDCFG_ENA_10 BIT(25)
+#define MAC_CMDCFG_RX_ERR_DISC BIT(26)
+#define MAC_CMDCFG_DISABLE_READ_TIMEOUT BIT(27)
+#define MAC_CMDCFG_CNT_RESET BIT(31)
+
+#define MAC_CMDCFG_TX_ENA_GET(v) GET_BIT_VALUE(v, 0)
+#define MAC_CMDCFG_RX_ENA_GET(v) GET_BIT_VALUE(v, 1)
+#define MAC_CMDCFG_XON_GEN_GET(v) GET_BIT_VALUE(v, 2)
+#define MAC_CMDCFG_ETH_SPEED_GET(v) GET_BIT_VALUE(v, 3)
+#define MAC_CMDCFG_PROMIS_EN_GET(v) GET_BIT_VALUE(v, 4)
+#define MAC_CMDCFG_PAD_EN_GET(v) GET_BIT_VALUE(v, 5)
+#define MAC_CMDCFG_CRC_FWD_GET(v) GET_BIT_VALUE(v, 6)
+#define MAC_CMDCFG_PAUSE_FWD_GET(v) GET_BIT_VALUE(v, 7)
+#define MAC_CMDCFG_PAUSE_IGNORE_GET(v) GET_BIT_VALUE(v, 8)
+#define MAC_CMDCFG_TX_ADDR_INS_GET(v) GET_BIT_VALUE(v, 9)
+#define MAC_CMDCFG_HD_ENA_GET(v) GET_BIT_VALUE(v, 10)
+#define MAC_CMDCFG_EXCESS_COL_GET(v) GET_BIT_VALUE(v, 11)
+#define MAC_CMDCFG_LATE_COL_GET(v) GET_BIT_VALUE(v, 12)
+#define MAC_CMDCFG_SW_RESET_GET(v) GET_BIT_VALUE(v, 13)
+#define MAC_CMDCFG_MHASH_SEL_GET(v) GET_BIT_VALUE(v, 14)
+#define MAC_CMDCFG_LOOP_ENA_GET(v) GET_BIT_VALUE(v, 15)
+#define MAC_CMDCFG_TX_ADDR_SEL_GET(v) (((v) >> 16) & 0x7)
+#define MAC_CMDCFG_MAGIC_ENA_GET(v) GET_BIT_VALUE(v, 19)
+#define MAC_CMDCFG_SLEEP_GET(v) GET_BIT_VALUE(v, 20)
+#define MAC_CMDCFG_WAKEUP_GET(v) GET_BIT_VALUE(v, 21)
+#define MAC_CMDCFG_XOFF_GEN_GET(v) GET_BIT_VALUE(v, 22)
+#define MAC_CMDCFG_CNTL_FRM_ENA_GET(v) GET_BIT_VALUE(v, 23)
+#define MAC_CMDCFG_NO_LGTH_CHECK_GET(v) GET_BIT_VALUE(v, 24)
+#define MAC_CMDCFG_ENA_10_GET(v) GET_BIT_VALUE(v, 25)
+#define MAC_CMDCFG_RX_ERR_DISC_GET(v) GET_BIT_VALUE(v, 26)
+#define MAC_CMDCFG_DISABLE_READ_TIMEOUT_GET(v) GET_BIT_VALUE(v, 27)
+#define MAC_CMDCFG_CNT_RESET_GET(v) GET_BIT_VALUE(v, 31)
+
+/* MDIO registers within MAC register Space
+ */
+struct altera_tse_mdio {
+ u32 control; /* PHY device operation control register */
+ u32 status; /* PHY device operation status register */
+ u32 phy_id1; /* Bits 31:16 of PHY identifier */
+ u32 phy_id2; /* Bits 15:0 of PHY identifier */
+ u32 auto_negotiation_advertisement; /* Auto-negotiation
+ * advertisement
+ * register
+ */
+ u32 remote_partner_base_page_ability;
+
+ u32 reg6;
+ u32 reg7;
+ u32 reg8;
+ u32 reg9;
+ u32 rega;
+ u32 regb;
+ u32 regc;
+ u32 regd;
+ u32 rege;
+ u32 regf;
+ u32 reg10;
+ u32 reg11;
+ u32 reg12;
+ u32 reg13;
+ u32 reg14;
+ u32 reg15;
+ u32 reg16;
+ u32 reg17;
+ u32 reg18;
+ u32 reg19;
+ u32 reg1a;
+ u32 reg1b;
+ u32 reg1c;
+ u32 reg1d;
+ u32 reg1e;
+ u32 reg1f;
+};
+
+/* MAC register Space. Note that some of these registers may or may not be
+ * present depending upon options chosen by the user when the core was
+ * configured and built. Please consult the Altera Triple Speed Ethernet User
+ * Guide for details.
+ */
+struct altera_tse_mac {
+ /* Bits 15:0: MegaCore function revision (0x0800). Bit 31:16: Customer
+ * specific revision
+ */
+ u32 megacore_revision;
+ /* Provides a memory location for user applications to test the device
+ * memory operation.
+ */
+ u32 scratch_pad;
+ /* The host processor uses this register to control and configure the
+ * MAC block
+ */
+ u32 command_config;
+ /* 32-bit primary MAC address word 0 bits 0 to 31 of the primary
+ * MAC address
+ */
+ u32 mac_addr_0;
+ /* 32-bit primary MAC address word 1 bits 32 to 47 of the primary
+ * MAC address
+ */
+ u32 mac_addr_1;
+ /* 14-bit maximum frame length. The MAC receive logic */
+ u32 frm_length;
+ /* The pause quanta is used in each pause frame sent to a remote
+ * Ethernet device, in increments of 512 Ethernet bit times
+ */
+ u32 pause_quanta;
+ /* 12-bit receive FIFO section-empty threshold */
+ u32 rx_section_empty;
+ /* 12-bit receive FIFO section-full threshold */
+ u32 rx_section_full;
+ /* 12-bit transmit FIFO section-empty threshold */
+ u32 tx_section_empty;
+ /* 12-bit transmit FIFO section-full threshold */
+ u32 tx_section_full;
+ /* 12-bit receive FIFO almost-empty threshold */
+ u32 rx_almost_empty;
+ /* 12-bit receive FIFO almost-full threshold */
+ u32 rx_almost_full;
+ /* 12-bit transmit FIFO almost-empty threshold */
+ u32 tx_almost_empty;
+ /* 12-bit transmit FIFO almost-full threshold */
+ u32 tx_almost_full;
+ /* MDIO address of PHY Device 0. Bits 0 to 4 hold a 5-bit PHY address */
+ u32 mdio_phy0_addr;
+ /* MDIO address of PHY Device 1. Bits 0 to 4 hold a 5-bit PHY address */
+ u32 mdio_phy1_addr;
+
+ /* Bit[15:0]—16-bit holdoff quanta */
+ u32 holdoff_quant;
+
+ /* only if 100/1000 BaseX PCS, reserved otherwise */
+ u32 reserved1[5];
+
+ /* Minimum IPG between consecutive transmit frame in terms of bytes */
+ u32 tx_ipg_length;
+
+ /* IEEE 802.3 oEntity Managed Object Support */
+
+ /* The MAC addresses */
+ u32 mac_id_1;
+ u32 mac_id_2;
+
+ /* Number of frames transmitted without error including pause frames */
+ u32 frames_transmitted_ok;
+ /* Number of frames received without error including pause frames */
+ u32 frames_received_ok;
+ /* Number of frames received with a CRC error */
+ u32 frames_check_sequence_errors;
+ /* Frame received with an alignment error */
+ u32 alignment_errors;
+ /* Sum of payload and padding octets of frames transmitted without
+ * error
+ */
+ u32 octets_transmitted_ok;
+ /* Sum of payload and padding octets of frames received without error */
+ u32 octets_received_ok;
+
+ /* IEEE 802.3 oPausedEntity Managed Object Support */
+
+ /* Number of transmitted pause frames */
+ u32 tx_pause_mac_ctrl_frames;
+ /* Number of Received pause frames */
+ u32 rx_pause_mac_ctrl_frames;
+
+ /* IETF MIB (MIB-II) Object Support */
+
+ /* Number of frames received with error */
+ u32 if_in_errors;
+ /* Number of frames transmitted with error */
+ u32 if_out_errors;
+ /* Number of valid received unicast frames */
+ u32 if_in_ucast_pkts;
+ /* Number of valid received multicasts frames (without pause) */
+ u32 if_in_multicast_pkts;
+ /* Number of valid received broadcast frames */
+ u32 if_in_broadcast_pkts;
+ u32 if_out_discards;
+ /* The number of valid unicast frames transmitted */
+ u32 if_out_ucast_pkts;
+ /* The number of valid multicast frames transmitted,
+ * excluding pause frames
+ */
+ u32 if_out_multicast_pkts;
+ u32 if_out_broadcast_pkts;
+
+ /* IETF RMON MIB Object Support */
+
+ /* Counts the number of dropped packets due to internal errors
+ * of the MAC client.
+ */
+ u32 ether_stats_drop_events;
+ /* Total number of bytes received. Good and bad frames. */
+ u32 ether_stats_octets;
+ /* Total number of packets received. Counts good and bad packets. */
+ u32 ether_stats_pkts;
+ /* Number of packets received with less than 64 bytes. */
+ u32 ether_stats_undersize_pkts;
+ /* The number of frames received that are longer than the
+ * value configured in the frm_length register
+ */
+ u32 ether_stats_oversize_pkts;
+ /* Number of received packet with 64 bytes */
+ u32 ether_stats_pkts_64_octets;
+ /* Frames (good and bad) with 65 to 127 bytes */
+ u32 ether_stats_pkts_65to127_octets;
+ /* Frames (good and bad) with 128 to 255 bytes */
+ u32 ether_stats_pkts_128to255_octets;
+ /* Frames (good and bad) with 256 to 511 bytes */
+ u32 ether_stats_pkts_256to511_octets;
+ /* Frames (good and bad) with 512 to 1023 bytes */
+ u32 ether_stats_pkts_512to1023_octets;
+ /* Frames (good and bad) with 1024 to 1518 bytes */
+ u32 ether_stats_pkts_1024to1518_octets;
+
+ /* Any frame length from 1519 to the maximum length configured in the
+ * frm_length register, if it is greater than 1518
+ */
+ u32 ether_stats_pkts_1519tox_octets;
+ /* Too long frames with CRC error */
+ u32 ether_stats_jabbers;
+ /* Too short frames with CRC error */
+ u32 ether_stats_fragments;
+
+ u32 reserved2;
+
+ /* FIFO control register */
+ u32 tx_cmd_stat;
+ u32 rx_cmd_stat;
+
+ /* Extended Statistics Counters */
+ u32 msb_octets_transmitted_ok;
+ u32 msb_octets_received_ok;
+ u32 msb_ether_stats_octets;
+
+ u32 reserved3;
+
+ /* Multicast address resolution table, mapped in the controller address
+ * space
+ */
+ u32 hash_table[64];
+
+ /* Registers 0 to 31 within PHY device 0/1 connected to the MDIO PHY
+ * management interface
+ */
+ struct altera_tse_mdio mdio_phy0;
+ struct altera_tse_mdio mdio_phy1;
+
+ /* 4 Supplemental MAC Addresses */
+ u32 supp_mac_addr_0_0;
+ u32 supp_mac_addr_0_1;
+ u32 supp_mac_addr_1_0;
+ u32 supp_mac_addr_1_1;
+ u32 supp_mac_addr_2_0;
+ u32 supp_mac_addr_2_1;
+ u32 supp_mac_addr_3_0;
+ u32 supp_mac_addr_3_1;
+
+ u32 reserved4[8];
+
+ /* IEEE 1588v2 Feature */
+ u32 tx_period;
+ u32 tx_adjust_fns;
+ u32 tx_adjust_ns;
+ u32 rx_period;
+ u32 rx_adjust_fns;
+ u32 rx_adjust_ns;
+
+ u32 reserved5[42];
+};
+
+/* Transmit and Receive Command Registers Bit Definitions
+ */
+#define ALTERA_TSE_TX_CMD_STAT_OMIT_CRC BIT(17)
+#define ALTERA_TSE_TX_CMD_STAT_TX_SHIFT16 BIT(18)
+#define ALTERA_TSE_RX_CMD_STAT_RX_SHIFT16 BIT(25)
+
+/* Wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer
+ */
+struct tse_buffer {
+ struct list_head lh;
+ struct sk_buff *skb;
+ dma_addr_t dma_addr;
+ u32 len;
+ int mapped_as_page;
+};
+
+struct altera_tse_private;
+
+#define ALTERA_DTYPE_SGDMA 1
+#define ALTERA_DTYPE_MSGDMA 2
+
+/* standard DMA interface for SGDMA and MSGDMA */
+struct altera_dmaops {
+ int altera_dtype;
+ int dmamask;
+ void (*reset_dma)(struct altera_tse_private *);
+ void (*enable_txirq)(struct altera_tse_private *);
+ void (*enable_rxirq)(struct altera_tse_private *);
+ void (*disable_txirq)(struct altera_tse_private *);
+ void (*disable_rxirq)(struct altera_tse_private *);
+ void (*clear_txirq)(struct altera_tse_private *);
+ void (*clear_rxirq)(struct altera_tse_private *);
+ int (*tx_buffer)(struct altera_tse_private *, struct tse_buffer *);
+ u32 (*tx_completions)(struct altera_tse_private *);
+ int (*add_rx_desc)(struct altera_tse_private *, struct tse_buffer *);
+ u32 (*get_rx_status)(struct altera_tse_private *);
+ int (*init_dma)(struct altera_tse_private *);
+ void (*uninit_dma)(struct altera_tse_private *);
+};
+
+/* This structure is private to each device.
+ */
+struct altera_tse_private {
+ struct net_device *dev;
+ struct device *device;
+ struct napi_struct napi;
+
+ /* MAC address space */
+ struct altera_tse_mac __iomem *mac_dev;
+
+ /* TSE Revision */
+ u32 revision;
+
+ /* mSGDMA Rx Dispatcher address space */
+ void __iomem *rx_dma_csr;
+ void __iomem *rx_dma_desc;
+ void __iomem *rx_dma_resp;
+
+ /* mSGDMA Tx Dispatcher address space */
+ void __iomem *tx_dma_csr;
+ void __iomem *tx_dma_desc;
+
+ /* Rx buffers queue */
+ struct tse_buffer *rx_ring;
+ u32 rx_cons;
+ u32 rx_prod;
+ u32 rx_ring_size;
+ u32 rx_dma_buf_sz;
+
+ /* Tx ring buffer */
+ struct tse_buffer *tx_ring;
+ u32 tx_prod;
+ u32 tx_cons;
+ u32 tx_ring_size;
+
+ /* Interrupts */
+ u32 tx_irq;
+ u32 rx_irq;
+
+ /* RX/TX MAC FIFO configs */
+ u32 tx_fifo_depth;
+ u32 rx_fifo_depth;
+ u32 max_mtu;
+
+ /* Hash filter settings */
+ u32 hash_filter;
+ u32 added_unicast;
+
+ /* Descriptor memory info for managing SGDMA */
+ u32 txdescmem;
+ u32 rxdescmem;
+ dma_addr_t rxdescmem_busaddr;
+ dma_addr_t txdescmem_busaddr;
+ u32 txctrlreg;
+ u32 rxctrlreg;
+ dma_addr_t rxdescphys;
+ dma_addr_t txdescphys;
+
+ struct list_head txlisthd;
+ struct list_head rxlisthd;
+
+ /* MAC command_config register protection */
+ spinlock_t mac_cfg_lock;
+ /* Tx path protection */
+ spinlock_t tx_lock;
+ /* Rx DMA & interrupt control protection */
+ spinlock_t rxdma_irq_lock;
+
+ /* PHY */
+ int phy_addr; /* PHY's MDIO address, -1 for autodetection */
+ phy_interface_t phy_iface;
+ struct mii_bus *mdio;
+ struct phy_device *phydev;
+ int oldspeed;
+ int oldduplex;
+ int oldlink;
+
+ /* ethtool msglvl option */
+ u32 msg_enable;
+
+ struct altera_dmaops *dmaops;
+};
+
+/* Function prototypes
+ */
+void altera_tse_set_ethtool_ops(struct net_device *);
+
+#endif /* __ALTERA_TSE_H__ */
diff --git a/drivers/net/ethernet/altera/altera_tse_ethtool.c b/drivers/net/ethernet/altera/altera_tse_ethtool.c
new file mode 100644
index 000000000000..319ca74f5e74
--- /dev/null
+++ b/drivers/net/ethernet/altera/altera_tse_ethtool.c
@@ -0,0 +1,235 @@
+/* Ethtool support for Altera Triple-Speed Ethernet MAC driver
+ * Copyright (C) 2008-2014 Altera Corporation. All rights reserved
+ *
+ * Contributors:
+ * Dalon Westergreen
+ * Thomas Chou
+ * Ian Abbott
+ * Yuriy Kozlov
+ * Tobias Klauser
+ * Andriy Smolskyy
+ * Roman Bulgakov
+ * Dmytro Mytarchuk
+ *
+ * Original driver contributed by SLS.
+ * Major updates contributed by GlobalLogic
+ *
+ * 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/ethtool.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+
+#include "altera_tse.h"
+
+#define TSE_STATS_LEN 31
+#define TSE_NUM_REGS 128
+
+static char const stat_gstrings[][ETH_GSTRING_LEN] = {
+ "tx_packets",
+ "rx_packets",
+ "rx_crc_errors",
+ "rx_align_errors",
+ "tx_bytes",
+ "rx_bytes",
+ "tx_pause",
+ "rx_pause",
+ "rx_errors",
+ "tx_errors",
+ "rx_unicast",
+ "rx_multicast",
+ "rx_broadcast",
+ "tx_discards",
+ "tx_unicast",
+ "tx_multicast",
+ "tx_broadcast",
+ "ether_drops",
+ "rx_total_bytes",
+ "rx_total_packets",
+ "rx_undersize",
+ "rx_oversize",
+ "rx_64_bytes",
+ "rx_65_127_bytes",
+ "rx_128_255_bytes",
+ "rx_256_511_bytes",
+ "rx_512_1023_bytes",
+ "rx_1024_1518_bytes",
+ "rx_gte_1519_bytes",
+ "rx_jabbers",
+ "rx_runts",
+};
+
+static void tse_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ struct altera_tse_private *priv = netdev_priv(dev);
+ u32 rev = ioread32(&priv->mac_dev->megacore_revision);
+
+ strcpy(info->driver, "Altera TSE MAC IP Driver");
+ strcpy(info->version, "v8.0");
+ snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "v%d.%d",
+ rev & 0xFFFF, (rev & 0xFFFF0000) >> 16);
+ sprintf(info->bus_info, "platform");
+}
+
+/* Fill in a buffer with the strings which correspond to the
+ * stats
+ */
+static void tse_gstrings(struct net_device *dev, u32 stringset, u8 *buf)
+{
+ memcpy(buf, stat_gstrings, TSE_STATS_LEN * ETH_GSTRING_LEN);
+}
+
+static void tse_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
+ u64 *buf)
+{
+ struct altera_tse_private *priv = netdev_priv(dev);
+ struct altera_tse_mac *mac = priv->mac_dev;
+ u64 ext;
+
+ buf[0] = ioread32(&mac->frames_transmitted_ok);
+ buf[1] = ioread32(&mac->frames_received_ok);
+ buf[2] = ioread32(&mac->frames_check_sequence_errors);
+ buf[3] = ioread32(&mac->alignment_errors);
+
+ /* Extended aOctetsTransmittedOK counter */
+ ext = (u64) ioread32(&mac->msb_octets_transmitted_ok) << 32;
+ ext |= ioread32(&mac->octets_transmitted_ok);
+ buf[4] = ext;
+
+ /* Extended aOctetsReceivedOK counter */
+ ext = (u64) ioread32(&mac->msb_octets_received_ok) << 32;
+ ext |= ioread32(&mac->octets_received_ok);
+ buf[5] = ext;
+
+ buf[6] = ioread32(&mac->tx_pause_mac_ctrl_frames);
+ buf[7] = ioread32(&mac->rx_pause_mac_ctrl_frames);
+ buf[8] = ioread32(&mac->if_in_errors);
+ buf[9] = ioread32(&mac->if_out_errors);
+ buf[10] = ioread32(&mac->if_in_ucast_pkts);
+ buf[11] = ioread32(&mac->if_in_multicast_pkts);
+ buf[12] = ioread32(&mac->if_in_broadcast_pkts);
+ buf[13] = ioread32(&mac->if_out_discards);
+ buf[14] = ioread32(&mac->if_out_ucast_pkts);
+ buf[15] = ioread32(&mac->if_out_multicast_pkts);
+ buf[16] = ioread32(&mac->if_out_broadcast_pkts);
+ buf[17] = ioread32(&mac->ether_stats_drop_events);
+
+ /* Extended etherStatsOctets counter */
+ ext = (u64) ioread32(&mac->msb_ether_stats_octets) << 32;
+ ext |= ioread32(&mac->ether_stats_octets);
+ buf[18] = ext;
+
+ buf[19] = ioread32(&mac->ether_stats_pkts);
+ buf[20] = ioread32(&mac->ether_stats_undersize_pkts);
+ buf[21] = ioread32(&mac->ether_stats_oversize_pkts);
+ buf[22] = ioread32(&mac->ether_stats_pkts_64_octets);
+ buf[23] = ioread32(&mac->ether_stats_pkts_65to127_octets);
+ buf[24] = ioread32(&mac->ether_stats_pkts_128to255_octets);
+ buf[25] = ioread32(&mac->ether_stats_pkts_256to511_octets);
+ buf[26] = ioread32(&mac->ether_stats_pkts_512to1023_octets);
+ buf[27] = ioread32(&mac->ether_stats_pkts_1024to1518_octets);
+ buf[28] = ioread32(&mac->ether_stats_pkts_1519tox_octets);
+ buf[29] = ioread32(&mac->ether_stats_jabbers);
+ buf[30] = ioread32(&mac->ether_stats_fragments);
+}
+
+static int tse_sset_count(struct net_device *dev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return TSE_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static u32 tse_get_msglevel(struct net_device *dev)
+{
+ struct altera_tse_private *priv = netdev_priv(dev);
+ return priv->msg_enable;
+}
+
+static void tse_set_msglevel(struct net_device *dev, uint32_t data)
+{
+ struct altera_tse_private *priv = netdev_priv(dev);
+ priv->msg_enable = data;
+}
+
+static int tse_reglen(struct net_device *dev)
+{
+ return TSE_NUM_REGS * sizeof(u32);
+}
+
+static void tse_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+ void *regbuf)
+{
+ int i;
+ struct altera_tse_private *priv = netdev_priv(dev);
+ u32 *tse_mac_regs = (u32 *)priv->mac_dev;
+ u32 *buf = regbuf;
+
+ /* Set version to a known value, so ethtool knows
+ * how to do any special formatting of this data.
+ * This version number will need to change if and
+ * when this register table is changed.
+ */
+
+ regs->version = 1;
+
+ for (i = 0; i < TSE_NUM_REGS; i++)
+ buf[i] = ioread32(&tse_mac_regs[i]);
+}
+
+static int tse_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct altera_tse_private *priv = netdev_priv(dev);
+ struct phy_device *phydev = priv->phydev;
+
+ if (phydev == NULL)
+ return -ENODEV;
+
+ return phy_ethtool_gset(phydev, cmd);
+}
+
+static int tse_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct altera_tse_private *priv = netdev_priv(dev);
+ struct phy_device *phydev = priv->phydev;
+
+ if (phydev == NULL)
+ return -ENODEV;
+
+ return phy_ethtool_sset(phydev, cmd);
+}
+
+static const struct ethtool_ops tse_ethtool_ops = {
+ .get_drvinfo = tse_get_drvinfo,
+ .get_regs_len = tse_reglen,
+ .get_regs = tse_get_regs,
+ .get_link = ethtool_op_get_link,
+ .get_settings = tse_get_settings,
+ .set_settings = tse_set_settings,
+ .get_strings = tse_gstrings,
+ .get_sset_count = tse_sset_count,
+ .get_ethtool_stats = tse_fill_stats,
+ .get_msglevel = tse_get_msglevel,
+ .set_msglevel = tse_set_msglevel,
+};
+
+void altera_tse_set_ethtool_ops(struct net_device *netdev)
+{
+ SET_ETHTOOL_OPS(netdev, &tse_ethtool_ops);
+}
diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c
new file mode 100644
index 000000000000..c70a29e0b9f7
--- /dev/null
+++ b/drivers/net/ethernet/altera/altera_tse_main.c
@@ -0,0 +1,1543 @@
+/* Altera Triple-Speed Ethernet MAC driver
+ * Copyright (C) 2008-2014 Altera Corporation. All rights reserved
+ *
+ * Contributors:
+ * Dalon Westergreen
+ * Thomas Chou
+ * Ian Abbott
+ * Yuriy Kozlov
+ * Tobias Klauser
+ * Andriy Smolskyy
+ * Roman Bulgakov
+ * Dmytro Mytarchuk
+ * Matthew Gerlach
+ *
+ * Original driver contributed by SLS.
+ * Major updates contributed by GlobalLogic
+ *
+ * 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/atomic.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of_device.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/of_platform.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/skbuff.h>
+#include <asm/cacheflush.h>
+
+#include "altera_utils.h"
+#include "altera_tse.h"
+#include "altera_sgdma.h"
+#include "altera_msgdma.h"
+
+static atomic_t instance_count = ATOMIC_INIT(~0);
+/* Module parameters */
+static int debug = -1;
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Message Level (-1: default, 0: no output, 16: all)");
+
+static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
+ NETIF_MSG_LINK | NETIF_MSG_IFUP |
+ NETIF_MSG_IFDOWN);
+
+#define RX_DESCRIPTORS 64
+static int dma_rx_num = RX_DESCRIPTORS;
+module_param(dma_rx_num, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dma_rx_num, "Number of descriptors in the RX list");
+
+#define TX_DESCRIPTORS 64
+static int dma_tx_num = TX_DESCRIPTORS;
+module_param(dma_tx_num, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dma_tx_num, "Number of descriptors in the TX list");
+
+
+#define POLL_PHY (-1)
+
+/* Make sure DMA buffer size is larger than the max frame size
+ * plus some alignment offset and a VLAN header. If the max frame size is
+ * 1518, a VLAN header would be additional 4 bytes and additional
+ * headroom for alignment is 2 bytes, 2048 is just fine.
+ */
+#define ALTERA_RXDMABUFFER_SIZE 2048
+
+/* Allow network stack to resume queueing packets after we've
+ * finished transmitting at least 1/4 of the packets in the queue.
+ */
+#define TSE_TX_THRESH(x) (x->tx_ring_size / 4)
+
+#define TXQUEUESTOP_THRESHHOLD 2
+
+static struct of_device_id altera_tse_ids[];
+
+static inline u32 tse_tx_avail(struct altera_tse_private *priv)
+{
+ return priv->tx_cons + priv->tx_ring_size - priv->tx_prod - 1;
+}
+
+/* MDIO specific functions
+ */
+static int altera_tse_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+ struct altera_tse_mac *mac = (struct altera_tse_mac *)bus->priv;
+ unsigned int *mdio_regs = (unsigned int *)&mac->mdio_phy0;
+ u32 data;
+
+ /* set MDIO address */
+ iowrite32((mii_id & 0x1f), &mac->mdio_phy0_addr);
+
+ /* get the data */
+ data = ioread32(&mdio_regs[regnum]) & 0xffff;
+ return data;
+}
+
+static int altera_tse_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
+ u16 value)
+{
+ struct altera_tse_mac *mac = (struct altera_tse_mac *)bus->priv;
+ unsigned int *mdio_regs = (unsigned int *)&mac->mdio_phy0;
+
+ /* set MDIO address */
+ iowrite32((mii_id & 0x1f), &mac->mdio_phy0_addr);
+
+ /* write the data */
+ iowrite32((u32) value, &mdio_regs[regnum]);
+ return 0;
+}
+
+static int altera_tse_mdio_create(struct net_device *dev, unsigned int id)
+{
+ struct altera_tse_private *priv = netdev_priv(dev);
+ int ret;
+ int i;
+ struct device_node *mdio_node = NULL;
+ struct mii_bus *mdio = NULL;
+ struct device_node *child_node = NULL;
+
+ for_each_child_of_node(priv->device->of_node, child_node) {
+ if (of_device_is_compatible(child_node, "altr,tse-mdio")) {
+ mdio_node = child_node;
+ break;
+ }
+ }
+
+ if (mdio_node) {
+ netdev_dbg(dev, "FOUND MDIO subnode\n");
+ } else {
+ netdev_dbg(dev, "NO MDIO subnode\n");
+ return 0;
+ }
+
+ mdio = mdiobus_alloc();
+ if (mdio == NULL) {
+ netdev_err(dev, "Error allocating MDIO bus\n");
+ return -ENOMEM;
+ }
+
+ mdio->name = ALTERA_TSE_RESOURCE_NAME;
+ mdio->read = &altera_tse_mdio_read;
+ mdio->write = &altera_tse_mdio_write;
+ snprintf(mdio->id, MII_BUS_ID_SIZE, "%s-%u", mdio->name, id);
+
+ mdio->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
+ if (mdio->irq == NULL) {
+ ret = -ENOMEM;
+ goto out_free_mdio;
+ }
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ mdio->irq[i] = PHY_POLL;
+
+ mdio->priv = priv->mac_dev;
+ mdio->parent = priv->device;
+
+ ret = of_mdiobus_register(mdio, mdio_node);
+ if (ret != 0) {
+ netdev_err(dev, "Cannot register MDIO bus %s\n",
+ mdio->id);
+ goto out_free_mdio_irq;
+ }
+
+ if (netif_msg_drv(priv))
+ netdev_info(dev, "MDIO bus %s: created\n", mdio->id);
+
+ priv->mdio = mdio;
+ return 0;
+out_free_mdio_irq:
+ kfree(mdio->irq);
+out_free_mdio:
+ mdiobus_free(mdio);
+ mdio = NULL;
+ return ret;
+}
+
+static void altera_tse_mdio_destroy(struct net_device *dev)
+{
+ struct altera_tse_private *priv = netdev_priv(dev);
+
+ if (priv->mdio == NULL)
+ return;
+
+ if (netif_msg_drv(priv))
+ netdev_info(dev, "MDIO bus %s: removed\n",
+ priv->mdio->id);
+
+ mdiobus_unregister(priv->mdio);
+ kfree(priv->mdio->irq);
+ mdiobus_free(priv->mdio);
+ priv->mdio = NULL;
+}
+
+static int tse_init_rx_buffer(struct altera_tse_private *priv,
+ struct tse_buffer *rxbuffer, int len)
+{
+ rxbuffer->skb = netdev_alloc_skb_ip_align(priv->dev, len);
+ if (!rxbuffer->skb)
+ return -ENOMEM;
+
+ rxbuffer->dma_addr = dma_map_single(priv->device, rxbuffer->skb->data,
+ len,
+ DMA_FROM_DEVICE);
+
+ if (dma_mapping_error(priv->device, rxbuffer->dma_addr)) {
+ netdev_err(priv->dev, "%s: DMA mapping error\n", __func__);
+ dev_kfree_skb_any(rxbuffer->skb);
+ return -EINVAL;
+ }
+ rxbuffer->len = len;
+ return 0;
+}
+
+static void tse_free_rx_buffer(struct altera_tse_private *priv,
+ struct tse_buffer *rxbuffer)
+{
+ struct sk_buff *skb = rxbuffer->skb;
+ dma_addr_t dma_addr = rxbuffer->dma_addr;
+
+ if (skb != NULL) {
+ if (dma_addr)
+ dma_unmap_single(priv->device, dma_addr,
+ rxbuffer->len,
+ DMA_FROM_DEVICE);
+ dev_kfree_skb_any(skb);
+ rxbuffer->skb = NULL;
+ rxbuffer->dma_addr = 0;
+ }
+}
+
+/* Unmap and free Tx buffer resources
+ */
+static void tse_free_tx_buffer(struct altera_tse_private *priv,
+ struct tse_buffer *buffer)
+{
+ if (buffer->dma_addr) {
+ if (buffer->mapped_as_page)
+ dma_unmap_page(priv->device, buffer->dma_addr,
+ buffer->len, DMA_TO_DEVICE);
+ else
+ dma_unmap_single(priv->device, buffer->dma_addr,
+ buffer->len, DMA_TO_DEVICE);
+ buffer->dma_addr = 0;
+ }
+ if (buffer->skb) {
+ dev_kfree_skb_any(buffer->skb);
+ buffer->skb = NULL;
+ }
+}
+
+static int alloc_init_skbufs(struct altera_tse_private *priv)
+{
+ unsigned int rx_descs = priv->rx_ring_size;
+ unsigned int tx_descs = priv->tx_ring_size;
+ int ret = -ENOMEM;
+ int i;
+
+ /* Create Rx ring buffer */
+ priv->rx_ring = kcalloc(rx_descs, sizeof(struct tse_buffer),
+ GFP_KERNEL);
+ if (!priv->rx_ring)
+ goto err_rx_ring;
+
+ /* Create Tx ring buffer */
+ priv->tx_ring = kcalloc(tx_descs, sizeof(struct tse_buffer),
+ GFP_KERNEL);
+ if (!priv->tx_ring)
+ goto err_tx_ring;
+
+ priv->tx_cons = 0;
+ priv->tx_prod = 0;
+
+ /* Init Rx ring */
+ for (i = 0; i < rx_descs; i++) {
+ ret = tse_init_rx_buffer(priv, &priv->rx_ring[i],
+ priv->rx_dma_buf_sz);
+ if (ret)
+ goto err_init_rx_buffers;
+ }
+
+ priv->rx_cons = 0;
+ priv->rx_prod = 0;
+
+ return 0;
+err_init_rx_buffers:
+ while (--i >= 0)
+ tse_free_rx_buffer(priv, &priv->rx_ring[i]);
+ kfree(priv->tx_ring);
+err_tx_ring:
+ kfree(priv->rx_ring);
+err_rx_ring:
+ return ret;
+}
+
+static void free_skbufs(struct net_device *dev)
+{
+ struct altera_tse_private *priv = netdev_priv(dev);
+ unsigned int rx_descs = priv->rx_ring_size;
+ unsigned int tx_descs = priv->tx_ring_size;
+ int i;
+
+ /* Release the DMA TX/RX socket buffers */
+ for (i = 0; i < rx_descs; i++)
+ tse_free_rx_buffer(priv, &priv->rx_ring[i]);
+ for (i = 0; i < tx_descs; i++)
+ tse_free_tx_buffer(priv, &priv->tx_ring[i]);
+
+
+ kfree(priv->tx_ring);
+}
+
+/* Reallocate the skb for the reception process
+ */
+static inline void tse_rx_refill(struct altera_tse_private *priv)
+{
+ unsigned int rxsize = priv->rx_ring_size;
+ unsigned int entry;
+ int ret;
+
+ for (; priv->rx_cons - priv->rx_prod > 0;
+ priv->rx_prod++) {
+ entry = priv->rx_prod % rxsize;
+ if (likely(priv->rx_ring[entry].skb == NULL)) {
+ ret = tse_init_rx_buffer(priv, &priv->rx_ring[entry],
+ priv->rx_dma_buf_sz);
+ if (unlikely(ret != 0))
+ break;
+ priv->dmaops->add_rx_desc(priv, &priv->rx_ring[entry]);
+ }
+ }
+}
+
+/* Pull out the VLAN tag and fix up the packet
+ */
+static inline void tse_rx_vlan(struct net_device *dev, struct sk_buff *skb)
+{
+ struct ethhdr *eth_hdr;
+ u16 vid;
+ if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
+ !__vlan_get_tag(skb, &vid)) {
+ eth_hdr = (struct ethhdr *)skb->data;
+ memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2);
+ skb_pull(skb, VLAN_HLEN);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
+ }
+}
+
+/* Receive a packet: retrieve and pass over to upper levels
+ */
+static int tse_rx(struct altera_tse_private *priv, int limit)
+{
+ unsigned int count = 0;
+ unsigned int next_entry;
+ struct sk_buff *skb;
+ unsigned int entry = priv->rx_cons % priv->rx_ring_size;
+ u32 rxstatus;
+ u16 pktlength;
+ u16 pktstatus;
+
+ while ((rxstatus = priv->dmaops->get_rx_status(priv)) != 0) {
+ pktstatus = rxstatus >> 16;
+ pktlength = rxstatus & 0xffff;
+
+ if ((pktstatus & 0xFF) || (pktlength == 0))
+ netdev_err(priv->dev,
+ "RCV pktstatus %08X pktlength %08X\n",
+ pktstatus, pktlength);
+
+ count++;
+ next_entry = (++priv->rx_cons) % priv->rx_ring_size;
+
+ skb = priv->rx_ring[entry].skb;
+ if (unlikely(!skb)) {
+ netdev_err(priv->dev,
+ "%s: Inconsistent Rx descriptor chain\n",
+ __func__);
+ priv->dev->stats.rx_dropped++;
+ break;
+ }
+ priv->rx_ring[entry].skb = NULL;
+
+ skb_put(skb, pktlength);
+
+ /* make cache consistent with receive packet buffer */
+ dma_sync_single_for_cpu(priv->device,
+ priv->rx_ring[entry].dma_addr,
+ priv->rx_ring[entry].len,
+ DMA_FROM_DEVICE);
+
+ dma_unmap_single(priv->device, priv->rx_ring[entry].dma_addr,
+ priv->rx_ring[entry].len, DMA_FROM_DEVICE);
+
+ if (netif_msg_pktdata(priv)) {
+ netdev_info(priv->dev, "frame received %d bytes\n",
+ pktlength);
+ print_hex_dump(KERN_ERR, "data: ", DUMP_PREFIX_OFFSET,
+ 16, 1, skb->data, pktlength, true);
+ }
+
+ tse_rx_vlan(priv->dev, skb);
+
+ skb->protocol = eth_type_trans(skb, priv->dev);
+ skb_checksum_none_assert(skb);
+
+ napi_gro_receive(&priv->napi, skb);
+
+ priv->dev->stats.rx_packets++;
+ priv->dev->stats.rx_bytes += pktlength;
+
+ entry = next_entry;
+ }
+
+ tse_rx_refill(priv);
+ return count;
+}
+
+/* Reclaim resources after transmission completes
+ */
+static int tse_tx_complete(struct altera_tse_private *priv)
+{
+ unsigned int txsize = priv->tx_ring_size;
+ u32 ready;
+ unsigned int entry;
+ struct tse_buffer *tx_buff;
+ int txcomplete = 0;
+
+ spin_lock(&priv->tx_lock);
+
+ ready = priv->dmaops->tx_completions(priv);
+
+ /* Free sent buffers */
+ while (ready && (priv->tx_cons != priv->tx_prod)) {
+ entry = priv->tx_cons % txsize;
+ tx_buff = &priv->tx_ring[entry];
+
+ if (netif_msg_tx_done(priv))
+ netdev_dbg(priv->dev, "%s: curr %d, dirty %d\n",
+ __func__, priv->tx_prod, priv->tx_cons);
+
+ if (likely(tx_buff->skb))
+ priv->dev->stats.tx_packets++;
+
+ tse_free_tx_buffer(priv, tx_buff);
+ priv->tx_cons++;
+
+ txcomplete++;
+ ready--;
+ }
+
+ if (unlikely(netif_queue_stopped(priv->dev) &&
+ tse_tx_avail(priv) > TSE_TX_THRESH(priv))) {
+ netif_tx_lock(priv->dev);
+ if (netif_queue_stopped(priv->dev) &&
+ tse_tx_avail(priv) > TSE_TX_THRESH(priv)) {
+ if (netif_msg_tx_done(priv))
+ netdev_dbg(priv->dev, "%s: restart transmit\n",
+ __func__);
+ netif_wake_queue(priv->dev);
+ }
+ netif_tx_unlock(priv->dev);
+ }
+
+ spin_unlock(&priv->tx_lock);
+ return txcomplete;
+}
+
+/* NAPI polling function
+ */
+static int tse_poll(struct napi_struct *napi, int budget)
+{
+ struct altera_tse_private *priv =
+ container_of(napi, struct altera_tse_private, napi);
+ int rxcomplete = 0;
+ int txcomplete = 0;
+ unsigned long int flags;
+
+ txcomplete = tse_tx_complete(priv);
+
+ rxcomplete = tse_rx(priv, budget);
+
+ if (rxcomplete >= budget || txcomplete > 0)
+ return rxcomplete;
+
+ napi_gro_flush(napi, false);
+ __napi_complete(napi);
+
+ netdev_dbg(priv->dev,
+ "NAPI Complete, did %d packets with budget %d\n",
+ txcomplete+rxcomplete, budget);
+
+ spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
+ priv->dmaops->enable_rxirq(priv);
+ priv->dmaops->enable_txirq(priv);
+ spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
+ return rxcomplete + txcomplete;
+}
+
+/* DMA TX & RX FIFO interrupt routing
+ */
+static irqreturn_t altera_isr(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct altera_tse_private *priv;
+ unsigned long int flags;
+
+
+ if (unlikely(!dev)) {
+ pr_err("%s: invalid dev pointer\n", __func__);
+ return IRQ_NONE;
+ }
+ priv = netdev_priv(dev);
+
+ /* turn off desc irqs and enable napi rx */
+ spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
+
+ if (likely(napi_schedule_prep(&priv->napi))) {
+ priv->dmaops->disable_rxirq(priv);
+ priv->dmaops->disable_txirq(priv);
+ __napi_schedule(&priv->napi);
+ }
+
+ /* reset IRQs */
+ priv->dmaops->clear_rxirq(priv);
+ priv->dmaops->clear_txirq(priv);
+
+ spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+/* Transmit a packet (called by the kernel). Dispatches
+ * either the SGDMA method for transmitting or the
+ * MSGDMA method, assumes no scatter/gather support,
+ * implying an assumption that there's only one
+ * physically contiguous fragment starting at
+ * skb->data, for length of skb_headlen(skb).
+ */
+static int tse_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct altera_tse_private *priv = netdev_priv(dev);
+ unsigned int txsize = priv->tx_ring_size;
+ unsigned int entry;
+ struct tse_buffer *buffer = NULL;
+ int nfrags = skb_shinfo(skb)->nr_frags;
+ unsigned int nopaged_len = skb_headlen(skb);
+ enum netdev_tx ret = NETDEV_TX_OK;
+ dma_addr_t dma_addr;
+ int txcomplete = 0;
+
+ spin_lock_bh(&priv->tx_lock);
+
+ if (unlikely(tse_tx_avail(priv) < nfrags + 1)) {
+ if (!netif_queue_stopped(dev)) {
+ netif_stop_queue(dev);
+ /* This is a hard error, log it. */
+ netdev_err(priv->dev,
+ "%s: Tx list full when queue awake\n",
+ __func__);
+ }
+ ret = NETDEV_TX_BUSY;
+ goto out;
+ }
+
+ /* Map the first skb fragment */
+ entry = priv->tx_prod % txsize;
+ buffer = &priv->tx_ring[entry];
+
+ dma_addr = dma_map_single(priv->device, skb->data, nopaged_len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(priv->device, dma_addr)) {
+ netdev_err(priv->dev, "%s: DMA mapping error\n", __func__);
+ ret = NETDEV_TX_OK;
+ goto out;
+ }
+
+ buffer->skb = skb;
+ buffer->dma_addr = dma_addr;
+ buffer->len = nopaged_len;
+
+ /* Push data out of the cache hierarchy into main memory */
+ dma_sync_single_for_device(priv->device, buffer->dma_addr,
+ buffer->len, DMA_TO_DEVICE);
+
+ txcomplete = priv->dmaops->tx_buffer(priv, buffer);
+
+ skb_tx_timestamp(skb);
+
+ priv->tx_prod++;
+ dev->stats.tx_bytes += skb->len;
+
+ if (unlikely(tse_tx_avail(priv) <= TXQUEUESTOP_THRESHHOLD)) {
+ if (netif_msg_hw(priv))
+ netdev_dbg(priv->dev, "%s: stop transmitted packets\n",
+ __func__);
+ netif_stop_queue(dev);
+ }
+
+out:
+ spin_unlock_bh(&priv->tx_lock);
+
+ return ret;
+}
+
+/* Called every time the controller might need to be made
+ * aware of new link state. The PHY code conveys this
+ * information through variables in the phydev structure, and this
+ * function converts those variables into the appropriate
+ * register values, and can bring down the device if needed.
+ */
+static void altera_tse_adjust_link(struct net_device *dev)
+{
+ struct altera_tse_private *priv = netdev_priv(dev);
+ struct phy_device *phydev = priv->phydev;
+ int new_state = 0;
+
+ /* only change config if there is a link */
+ spin_lock(&priv->mac_cfg_lock);
+ if (phydev->link) {
+ /* Read old config */
+ u32 cfg_reg = ioread32(&priv->mac_dev->command_config);
+
+ /* Check duplex */
+ if (phydev->duplex != priv->oldduplex) {
+ new_state = 1;
+ if (!(phydev->duplex))
+ cfg_reg |= MAC_CMDCFG_HD_ENA;
+ else
+ cfg_reg &= ~MAC_CMDCFG_HD_ENA;
+
+ netdev_dbg(priv->dev, "%s: Link duplex = 0x%x\n",
+ dev->name, phydev->duplex);
+
+ priv->oldduplex = phydev->duplex;
+ }
+
+ /* Check speed */
+ if (phydev->speed != priv->oldspeed) {
+ new_state = 1;
+ switch (phydev->speed) {
+ case 1000:
+ cfg_reg |= MAC_CMDCFG_ETH_SPEED;
+ cfg_reg &= ~MAC_CMDCFG_ENA_10;
+ break;
+ case 100:
+ cfg_reg &= ~MAC_CMDCFG_ETH_SPEED;
+ cfg_reg &= ~MAC_CMDCFG_ENA_10;
+ break;
+ case 10:
+ cfg_reg &= ~MAC_CMDCFG_ETH_SPEED;
+ cfg_reg |= MAC_CMDCFG_ENA_10;
+ break;
+ default:
+ if (netif_msg_link(priv))
+ netdev_warn(dev, "Speed (%d) is not 10/100/1000!\n",
+ phydev->speed);
+ break;
+ }
+ priv->oldspeed = phydev->speed;
+ }
+ iowrite32(cfg_reg, &priv->mac_dev->command_config);
+
+ if (!priv->oldlink) {
+ new_state = 1;
+ priv->oldlink = 1;
+ }
+ } else if (priv->oldlink) {
+ new_state = 1;
+ priv->oldlink = 0;
+ priv->oldspeed = 0;
+ priv->oldduplex = -1;
+ }
+
+ if (new_state && netif_msg_link(priv))
+ phy_print_status(phydev);
+
+ spin_unlock(&priv->mac_cfg_lock);
+}
+static struct phy_device *connect_local_phy(struct net_device *dev)
+{
+ struct altera_tse_private *priv = netdev_priv(dev);
+ struct phy_device *phydev = NULL;
+ char phy_id_fmt[MII_BUS_ID_SIZE + 3];
+ int ret;
+
+ if (priv->phy_addr != POLL_PHY) {
+ snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT,
+ priv->mdio->id, priv->phy_addr);
+
+ netdev_dbg(dev, "trying to attach to %s\n", phy_id_fmt);
+
+ phydev = phy_connect(dev, phy_id_fmt, &altera_tse_adjust_link,
+ priv->phy_iface);
+ if (IS_ERR(phydev))
+ netdev_err(dev, "Could not attach to PHY\n");
+
+ } else {
+ phydev = phy_find_first(priv->mdio);
+ if (phydev == NULL) {
+ netdev_err(dev, "No PHY found\n");
+ return phydev;
+ }
+
+ ret = phy_connect_direct(dev, phydev, &altera_tse_adjust_link,
+ priv->phy_iface);
+ if (ret != 0) {
+ netdev_err(dev, "Could not attach to PHY\n");
+ phydev = NULL;
+ }
+ }
+ return phydev;
+}
+
+/* Initialize driver's PHY state, and attach to the PHY
+ */
+static int init_phy(struct net_device *dev)
+{
+ struct altera_tse_private *priv = netdev_priv(dev);
+ struct phy_device *phydev;
+ struct device_node *phynode;
+
+ priv->oldlink = 0;
+ priv->oldspeed = 0;
+ priv->oldduplex = -1;
+
+ phynode = of_parse_phandle(priv->device->of_node, "phy-handle", 0);
+
+ if (!phynode) {
+ netdev_dbg(dev, "no phy-handle found\n");
+ if (!priv->mdio) {
+ netdev_err(dev,
+ "No phy-handle nor local mdio specified\n");
+ return -ENODEV;
+ }
+ phydev = connect_local_phy(dev);
+ } else {
+ netdev_dbg(dev, "phy-handle found\n");
+ phydev = of_phy_connect(dev, phynode,
+ &altera_tse_adjust_link, 0, priv->phy_iface);
+ }
+
+ if (!phydev) {
+ netdev_err(dev, "Could not find the PHY\n");
+ return -ENODEV;
+ }
+
+ /* Stop Advertising 1000BASE Capability if interface is not GMII
+ * Note: Checkpatch throws CHECKs for the camel case defines below,
+ * it's ok to ignore.
+ */
+ if ((priv->phy_iface == PHY_INTERFACE_MODE_MII) ||
+ (priv->phy_iface == PHY_INTERFACE_MODE_RMII))
+ phydev->advertising &= ~(SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full);
+
+ /* Broken HW is sometimes missing the pull-up resistor on the
+ * MDIO line, which results in reads to non-existent devices returning
+ * 0 rather than 0xffff. Catch this here and treat 0 as a non-existent
+ * device as well.
+ * Note: phydev->phy_id is the result of reading the UID PHY registers.
+ */
+ if (phydev->phy_id == 0) {
+ netdev_err(dev, "Bad PHY UID 0x%08x\n", phydev->phy_id);
+ phy_disconnect(phydev);
+ return -ENODEV;
+ }
+
+ netdev_dbg(dev, "attached to PHY %d UID 0x%08x Link = %d\n",
+ phydev->addr, phydev->phy_id, phydev->link);
+
+ priv->phydev = phydev;
+ return 0;
+}
+
+static void tse_update_mac_addr(struct altera_tse_private *priv, u8 *addr)
+{
+ struct altera_tse_mac *mac = priv->mac_dev;
+ u32 msb;
+ u32 lsb;
+
+ msb = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
+ lsb = ((addr[5] << 8) | addr[4]) & 0xffff;
+
+ /* Set primary MAC address */
+ iowrite32(msb, &mac->mac_addr_0);
+ iowrite32(lsb, &mac->mac_addr_1);
+}
+
+/* MAC software reset.
+ * When reset is triggered, the MAC function completes the current
+ * transmission or reception, and subsequently disables the transmit and
+ * receive logic, flushes the receive FIFO buffer, and resets the statistics
+ * counters.
+ */
+static int reset_mac(struct altera_tse_private *priv)
+{
+ void __iomem *cmd_cfg_reg = &priv->mac_dev->command_config;
+ int counter;
+ u32 dat;
+
+ dat = ioread32(cmd_cfg_reg);
+ dat &= ~(MAC_CMDCFG_TX_ENA | MAC_CMDCFG_RX_ENA);
+ dat |= MAC_CMDCFG_SW_RESET | MAC_CMDCFG_CNT_RESET;
+ iowrite32(dat, cmd_cfg_reg);
+
+ counter = 0;
+ while (counter++ < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) {
+ if (tse_bit_is_clear(cmd_cfg_reg, MAC_CMDCFG_SW_RESET))
+ break;
+ udelay(1);
+ }
+
+ if (counter >= ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) {
+ dat = ioread32(cmd_cfg_reg);
+ dat &= ~MAC_CMDCFG_SW_RESET;
+ iowrite32(dat, cmd_cfg_reg);
+ return -1;
+ }
+ return 0;
+}
+
+/* Initialize MAC core registers
+*/
+static int init_mac(struct altera_tse_private *priv)
+{
+ struct altera_tse_mac *mac = priv->mac_dev;
+ unsigned int cmd = 0;
+ u32 frm_length;
+
+ /* Setup Rx FIFO */
+ iowrite32(priv->rx_fifo_depth - ALTERA_TSE_RX_SECTION_EMPTY,
+ &mac->rx_section_empty);
+ iowrite32(ALTERA_TSE_RX_SECTION_FULL, &mac->rx_section_full);
+ iowrite32(ALTERA_TSE_RX_ALMOST_EMPTY, &mac->rx_almost_empty);
+ iowrite32(ALTERA_TSE_RX_ALMOST_FULL, &mac->rx_almost_full);
+
+ /* Setup Tx FIFO */
+ iowrite32(priv->tx_fifo_depth - ALTERA_TSE_TX_SECTION_EMPTY,
+ &mac->tx_section_empty);
+ iowrite32(ALTERA_TSE_TX_SECTION_FULL, &mac->tx_section_full);
+ iowrite32(ALTERA_TSE_TX_ALMOST_EMPTY, &mac->tx_almost_empty);
+ iowrite32(ALTERA_TSE_TX_ALMOST_FULL, &mac->tx_almost_full);
+
+ /* MAC Address Configuration */
+ tse_update_mac_addr(priv, priv->dev->dev_addr);
+
+ /* MAC Function Configuration */
+ frm_length = ETH_HLEN + priv->dev->mtu + ETH_FCS_LEN;
+ iowrite32(frm_length, &mac->frm_length);
+ iowrite32(ALTERA_TSE_TX_IPG_LENGTH, &mac->tx_ipg_length);
+
+ /* Disable RX/TX shift 16 for alignment of all received frames on 16-bit
+ * start address
+ */
+ tse_clear_bit(&mac->rx_cmd_stat, ALTERA_TSE_RX_CMD_STAT_RX_SHIFT16);
+ tse_clear_bit(&mac->tx_cmd_stat, ALTERA_TSE_TX_CMD_STAT_TX_SHIFT16 |
+ ALTERA_TSE_TX_CMD_STAT_OMIT_CRC);
+
+ /* Set the MAC options */
+ cmd = ioread32(&mac->command_config);
+ cmd |= MAC_CMDCFG_PAD_EN; /* Padding Removal on Receive */
+ cmd &= ~MAC_CMDCFG_CRC_FWD; /* CRC Removal */
+ cmd |= MAC_CMDCFG_RX_ERR_DISC; /* Automatically discard frames
+ * with CRC errors
+ */
+ cmd |= MAC_CMDCFG_CNTL_FRM_ENA;
+ cmd &= ~MAC_CMDCFG_TX_ENA;
+ cmd &= ~MAC_CMDCFG_RX_ENA;
+ iowrite32(cmd, &mac->command_config);
+
+ if (netif_msg_hw(priv))
+ dev_dbg(priv->device,
+ "MAC post-initialization: CMD_CONFIG = 0x%08x\n", cmd);
+
+ return 0;
+}
+
+/* Start/stop MAC transmission logic
+ */
+static void tse_set_mac(struct altera_tse_private *priv, bool enable)
+{
+ struct altera_tse_mac *mac = priv->mac_dev;
+ u32 value = ioread32(&mac->command_config);
+
+ if (enable)
+ value |= MAC_CMDCFG_TX_ENA | MAC_CMDCFG_RX_ENA;
+ else
+ value &= ~(MAC_CMDCFG_TX_ENA | MAC_CMDCFG_RX_ENA);
+
+ iowrite32(value, &mac->command_config);
+}
+
+/* Change the MTU
+ */
+static int tse_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct altera_tse_private *priv = netdev_priv(dev);
+ unsigned int max_mtu = priv->max_mtu;
+ unsigned int min_mtu = ETH_ZLEN + ETH_FCS_LEN;
+
+ if (netif_running(dev)) {
+ netdev_err(dev, "must be stopped to change its MTU\n");
+ return -EBUSY;
+ }
+
+ if ((new_mtu < min_mtu) || (new_mtu > max_mtu)) {
+ netdev_err(dev, "invalid MTU, max MTU is: %u\n", max_mtu);
+ return -EINVAL;
+ }
+
+ dev->mtu = new_mtu;
+ netdev_update_features(dev);
+
+ return 0;
+}
+
+static void altera_tse_set_mcfilter(struct net_device *dev)
+{
+ struct altera_tse_private *priv = netdev_priv(dev);
+ struct altera_tse_mac *mac = priv->mac_dev;
+ int i;
+ struct netdev_hw_addr *ha;
+
+ /* clear the hash filter */
+ for (i = 0; i < 64; i++)
+ iowrite32(0, &(mac->hash_table[i]));
+
+ netdev_for_each_mc_addr(ha, dev) {
+ unsigned int hash = 0;
+ int mac_octet;
+
+ for (mac_octet = 5; mac_octet >= 0; mac_octet--) {
+ unsigned char xor_bit = 0;
+ unsigned char octet = ha->addr[mac_octet];
+ unsigned int bitshift;
+
+ for (bitshift = 0; bitshift < 8; bitshift++)
+ xor_bit ^= ((octet >> bitshift) & 0x01);
+
+ hash = (hash << 1) | xor_bit;
+ }
+ iowrite32(1, &(mac->hash_table[hash]));
+ }
+}
+
+
+static void altera_tse_set_mcfilterall(struct net_device *dev)
+{
+ struct altera_tse_private *priv = netdev_priv(dev);
+ struct altera_tse_mac *mac = priv->mac_dev;
+ int i;
+
+ /* set the hash filter */
+ for (i = 0; i < 64; i++)
+ iowrite32(1, &(mac->hash_table[i]));
+}
+
+/* Set or clear the multicast filter for this adaptor
+ */
+static void tse_set_rx_mode_hashfilter(struct net_device *dev)
+{
+ struct altera_tse_private *priv = netdev_priv(dev);
+ struct altera_tse_mac *mac = priv->mac_dev;
+
+ spin_lock(&priv->mac_cfg_lock);
+
+ if (dev->flags & IFF_PROMISC)
+ tse_set_bit(&mac->command_config, MAC_CMDCFG_PROMIS_EN);
+
+ if (dev->flags & IFF_ALLMULTI)
+ altera_tse_set_mcfilterall(dev);
+ else
+ altera_tse_set_mcfilter(dev);
+
+ spin_unlock(&priv->mac_cfg_lock);
+}
+
+/* Set or clear the multicast filter for this adaptor
+ */
+static void tse_set_rx_mode(struct net_device *dev)
+{
+ struct altera_tse_private *priv = netdev_priv(dev);
+ struct altera_tse_mac *mac = priv->mac_dev;
+
+ spin_lock(&priv->mac_cfg_lock);
+
+ if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
+ !netdev_mc_empty(dev) || !netdev_uc_empty(dev))
+ tse_set_bit(&mac->command_config, MAC_CMDCFG_PROMIS_EN);
+ else
+ tse_clear_bit(&mac->command_config, MAC_CMDCFG_PROMIS_EN);
+
+ spin_unlock(&priv->mac_cfg_lock);
+}
+
+/* Open and initialize the interface
+ */
+static int tse_open(struct net_device *dev)
+{
+ struct altera_tse_private *priv = netdev_priv(dev);
+ int ret = 0;
+ int i;
+ unsigned long int flags;
+
+ /* Reset and configure TSE MAC and probe associated PHY */
+ ret = priv->dmaops->init_dma(priv);
+ if (ret != 0) {
+ netdev_err(dev, "Cannot initialize DMA\n");
+ goto phy_error;
+ }
+
+ if (netif_msg_ifup(priv))
+ netdev_warn(dev, "device MAC address %pM\n",
+ dev->dev_addr);
+
+ if ((priv->revision < 0xd00) || (priv->revision > 0xe00))
+ netdev_warn(dev, "TSE revision %x\n", priv->revision);
+
+ spin_lock(&priv->mac_cfg_lock);
+ ret = reset_mac(priv);
+ if (ret)
+ netdev_err(dev, "Cannot reset MAC core (error: %d)\n", ret);
+
+ ret = init_mac(priv);
+ spin_unlock(&priv->mac_cfg_lock);
+ if (ret) {
+ netdev_err(dev, "Cannot init MAC core (error: %d)\n", ret);
+ goto alloc_skbuf_error;
+ }
+
+ priv->dmaops->reset_dma(priv);
+
+ /* Create and initialize the TX/RX descriptors chains. */
+ priv->rx_ring_size = dma_rx_num;
+ priv->tx_ring_size = dma_tx_num;
+ ret = alloc_init_skbufs(priv);
+ if (ret) {
+ netdev_err(dev, "DMA descriptors initialization failed\n");
+ goto alloc_skbuf_error;
+ }
+
+
+ /* Register RX interrupt */
+ ret = request_irq(priv->rx_irq, altera_isr, IRQF_SHARED,
+ dev->name, dev);
+ if (ret) {
+ netdev_err(dev, "Unable to register RX interrupt %d\n",
+ priv->rx_irq);
+ goto init_error;
+ }
+
+ /* Register TX interrupt */
+ ret = request_irq(priv->tx_irq, altera_isr, IRQF_SHARED,
+ dev->name, dev);
+ if (ret) {
+ netdev_err(dev, "Unable to register TX interrupt %d\n",
+ priv->tx_irq);
+ goto tx_request_irq_error;
+ }
+
+ /* Enable DMA interrupts */
+ spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
+ priv->dmaops->enable_rxirq(priv);
+ priv->dmaops->enable_txirq(priv);
+
+ /* Setup RX descriptor chain */
+ for (i = 0; i < priv->rx_ring_size; i++)
+ priv->dmaops->add_rx_desc(priv, &priv->rx_ring[i]);
+
+ spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
+
+ /* Start MAC Rx/Tx */
+ spin_lock(&priv->mac_cfg_lock);
+ tse_set_mac(priv, true);
+ spin_unlock(&priv->mac_cfg_lock);
+
+ if (priv->phydev)
+ phy_start(priv->phydev);
+
+ napi_enable(&priv->napi);
+ netif_start_queue(dev);
+
+ return 0;
+
+tx_request_irq_error:
+ free_irq(priv->rx_irq, dev);
+init_error:
+ free_skbufs(dev);
+alloc_skbuf_error:
+ if (priv->phydev) {
+ phy_disconnect(priv->phydev);
+ priv->phydev = NULL;
+ }
+phy_error:
+ return ret;
+}
+
+/* Stop TSE MAC interface and put the device in an inactive state
+ */
+static int tse_shutdown(struct net_device *dev)
+{
+ struct altera_tse_private *priv = netdev_priv(dev);
+ int ret;
+ unsigned long int flags;
+
+ /* Stop and disconnect the PHY */
+ if (priv->phydev) {
+ phy_stop(priv->phydev);
+ phy_disconnect(priv->phydev);
+ priv->phydev = NULL;
+ }
+
+ netif_stop_queue(dev);
+ napi_disable(&priv->napi);
+
+ /* Disable DMA interrupts */
+ spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
+ priv->dmaops->disable_rxirq(priv);
+ priv->dmaops->disable_txirq(priv);
+ spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
+
+ /* Free the IRQ lines */
+ free_irq(priv->rx_irq, dev);
+ free_irq(priv->tx_irq, dev);
+
+ /* disable and reset the MAC, empties fifo */
+ spin_lock(&priv->mac_cfg_lock);
+ spin_lock(&priv->tx_lock);
+
+ ret = reset_mac(priv);
+ if (ret)
+ netdev_err(dev, "Cannot reset MAC core (error: %d)\n", ret);
+ priv->dmaops->reset_dma(priv);
+ free_skbufs(dev);
+
+ spin_unlock(&priv->tx_lock);
+ spin_unlock(&priv->mac_cfg_lock);
+
+ priv->dmaops->uninit_dma(priv);
+
+ return 0;
+}
+
+static struct net_device_ops altera_tse_netdev_ops = {
+ .ndo_open = tse_open,
+ .ndo_stop = tse_shutdown,
+ .ndo_start_xmit = tse_start_xmit,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_set_rx_mode = tse_set_rx_mode,
+ .ndo_change_mtu = tse_change_mtu,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+
+static int request_and_map(struct platform_device *pdev, const char *name,
+ struct resource **res, void __iomem **ptr)
+{
+ struct resource *region;
+ struct device *device = &pdev->dev;
+
+ *res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+ if (*res == NULL) {
+ dev_err(device, "resource %s not defined\n", name);
+ return -ENODEV;
+ }
+
+ region = devm_request_mem_region(device, (*res)->start,
+ resource_size(*res), dev_name(device));
+ if (region == NULL) {
+ dev_err(device, "unable to request %s\n", name);
+ return -EBUSY;
+ }
+
+ *ptr = devm_ioremap_nocache(device, region->start,
+ resource_size(region));
+ if (*ptr == NULL) {
+ dev_err(device, "ioremap_nocache of %s failed!", name);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/* Probe Altera TSE MAC device
+ */
+static int altera_tse_probe(struct platform_device *pdev)
+{
+ struct net_device *ndev;
+ int ret = -ENODEV;
+ struct resource *control_port;
+ struct resource *dma_res;
+ struct altera_tse_private *priv;
+ const unsigned char *macaddr;
+ struct device_node *np = pdev->dev.of_node;
+ void __iomem *descmap;
+ const struct of_device_id *of_id = NULL;
+
+ ndev = alloc_etherdev(sizeof(struct altera_tse_private));
+ if (!ndev) {
+ dev_err(&pdev->dev, "Could not allocate network device\n");
+ return -ENODEV;
+ }
+
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ priv = netdev_priv(ndev);
+ priv->device = &pdev->dev;
+ priv->dev = ndev;
+ priv->msg_enable = netif_msg_init(debug, default_msg_level);
+
+ of_id = of_match_device(altera_tse_ids, &pdev->dev);
+
+ if (of_id)
+ priv->dmaops = (struct altera_dmaops *)of_id->data;
+
+
+ if (priv->dmaops &&
+ priv->dmaops->altera_dtype == ALTERA_DTYPE_SGDMA) {
+ /* Get the mapped address to the SGDMA descriptor memory */
+ ret = request_and_map(pdev, "s1", &dma_res, &descmap);
+ if (ret)
+ goto out_free;
+
+ /* Start of that memory is for transmit descriptors */
+ priv->tx_dma_desc = descmap;
+
+ /* First half is for tx descriptors, other half for tx */
+ priv->txdescmem = resource_size(dma_res)/2;
+
+ priv->txdescmem_busaddr = (dma_addr_t)dma_res->start;
+
+ priv->rx_dma_desc = (void __iomem *)((uintptr_t)(descmap +
+ priv->txdescmem));
+ priv->rxdescmem = resource_size(dma_res)/2;
+ priv->rxdescmem_busaddr = dma_res->start;
+ priv->rxdescmem_busaddr += priv->txdescmem;
+
+ if (upper_32_bits(priv->rxdescmem_busaddr)) {
+ dev_dbg(priv->device,
+ "SGDMA bus addresses greater than 32-bits\n");
+ goto out_free;
+ }
+ if (upper_32_bits(priv->txdescmem_busaddr)) {
+ dev_dbg(priv->device,
+ "SGDMA bus addresses greater than 32-bits\n");
+ goto out_free;
+ }
+ } else if (priv->dmaops &&
+ priv->dmaops->altera_dtype == ALTERA_DTYPE_MSGDMA) {
+ ret = request_and_map(pdev, "rx_resp", &dma_res,
+ &priv->rx_dma_resp);
+ if (ret)
+ goto out_free;
+
+ ret = request_and_map(pdev, "tx_desc", &dma_res,
+ &priv->tx_dma_desc);
+ if (ret)
+ goto out_free;
+
+ priv->txdescmem = resource_size(dma_res);
+ priv->txdescmem_busaddr = dma_res->start;
+
+ ret = request_and_map(pdev, "rx_desc", &dma_res,
+ &priv->rx_dma_desc);
+ if (ret)
+ goto out_free;
+
+ priv->rxdescmem = resource_size(dma_res);
+ priv->rxdescmem_busaddr = dma_res->start;
+
+ } else {
+ goto out_free;
+ }
+
+ if (!dma_set_mask(priv->device, DMA_BIT_MASK(priv->dmaops->dmamask)))
+ dma_set_coherent_mask(priv->device,
+ DMA_BIT_MASK(priv->dmaops->dmamask));
+ else if (!dma_set_mask(priv->device, DMA_BIT_MASK(32)))
+ dma_set_coherent_mask(priv->device, DMA_BIT_MASK(32));
+ else
+ goto out_free;
+
+ /* MAC address space */
+ ret = request_and_map(pdev, "control_port", &control_port,
+ (void __iomem **)&priv->mac_dev);
+ if (ret)
+ goto out_free;
+
+ /* xSGDMA Rx Dispatcher address space */
+ ret = request_and_map(pdev, "rx_csr", &dma_res,
+ &priv->rx_dma_csr);
+ if (ret)
+ goto out_free;
+
+
+ /* xSGDMA Tx Dispatcher address space */
+ ret = request_and_map(pdev, "tx_csr", &dma_res,
+ &priv->tx_dma_csr);
+ if (ret)
+ goto out_free;
+
+
+ /* Rx IRQ */
+ priv->rx_irq = platform_get_irq_byname(pdev, "rx_irq");
+ if (priv->rx_irq == -ENXIO) {
+ dev_err(&pdev->dev, "cannot obtain Rx IRQ\n");
+ ret = -ENXIO;
+ goto out_free;
+ }
+
+ /* Tx IRQ */
+ priv->tx_irq = platform_get_irq_byname(pdev, "tx_irq");
+ if (priv->tx_irq == -ENXIO) {
+ dev_err(&pdev->dev, "cannot obtain Tx IRQ\n");
+ ret = -ENXIO;
+ goto out_free;
+ }
+
+ /* get FIFO depths from device tree */
+ if (of_property_read_u32(pdev->dev.of_node, "rx-fifo-depth",
+ &priv->rx_fifo_depth)) {
+ dev_err(&pdev->dev, "cannot obtain rx-fifo-depth\n");
+ ret = -ENXIO;
+ goto out_free;
+ }
+
+ if (of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth",
+ &priv->rx_fifo_depth)) {
+ dev_err(&pdev->dev, "cannot obtain tx-fifo-depth\n");
+ ret = -ENXIO;
+ goto out_free;
+ }
+
+ /* get hash filter settings for this instance */
+ priv->hash_filter =
+ of_property_read_bool(pdev->dev.of_node,
+ "altr,has-hash-multicast-filter");
+
+ /* get supplemental address settings for this instance */
+ priv->added_unicast =
+ of_property_read_bool(pdev->dev.of_node,
+ "altr,has-supplementary-unicast");
+
+ /* Max MTU is 1500, ETH_DATA_LEN */
+ priv->max_mtu = ETH_DATA_LEN;
+
+ /* Get the max mtu from the device tree. Note that the
+ * "max-frame-size" parameter is actually max mtu. Definition
+ * in the ePAPR v1.1 spec and usage differ, so go with usage.
+ */
+ of_property_read_u32(pdev->dev.of_node, "max-frame-size",
+ &priv->max_mtu);
+
+ /* The DMA buffer size already accounts for an alignment bias
+ * to avoid unaligned access exceptions for the NIOS processor,
+ */
+ priv->rx_dma_buf_sz = ALTERA_RXDMABUFFER_SIZE;
+
+ /* get default MAC address from device tree */
+ macaddr = of_get_mac_address(pdev->dev.of_node);
+ if (macaddr)
+ ether_addr_copy(ndev->dev_addr, macaddr);
+ else
+ eth_hw_addr_random(ndev);
+
+ priv->phy_iface = of_get_phy_mode(np);
+
+ /* try to get PHY address from device tree, use PHY autodetection if
+ * no valid address is given
+ */
+ if (of_property_read_u32(pdev->dev.of_node, "phy-addr",
+ &priv->phy_addr)) {
+ priv->phy_addr = POLL_PHY;
+ }
+
+ if (!((priv->phy_addr == POLL_PHY) ||
+ ((priv->phy_addr >= 0) && (priv->phy_addr < PHY_MAX_ADDR)))) {
+ dev_err(&pdev->dev, "invalid phy-addr specified %d\n",
+ priv->phy_addr);
+ goto out_free;
+ }
+
+ /* Create/attach to MDIO bus */
+ ret = altera_tse_mdio_create(ndev,
+ atomic_add_return(1, &instance_count));
+
+ if (ret)
+ goto out_free;
+
+ /* initialize netdev */
+ ether_setup(ndev);
+ ndev->mem_start = control_port->start;
+ ndev->mem_end = control_port->end;
+ ndev->netdev_ops = &altera_tse_netdev_ops;
+ altera_tse_set_ethtool_ops(ndev);
+
+ altera_tse_netdev_ops.ndo_set_rx_mode = tse_set_rx_mode;
+
+ if (priv->hash_filter)
+ altera_tse_netdev_ops.ndo_set_rx_mode =
+ tse_set_rx_mode_hashfilter;
+
+ /* Scatter/gather IO is not supported,
+ * so it is turned off
+ */
+ ndev->hw_features &= ~NETIF_F_SG;
+ ndev->features |= ndev->hw_features | NETIF_F_HIGHDMA;
+
+ /* VLAN offloading of tagging, stripping and filtering is not
+ * supported by hardware, but driver will accommodate the
+ * extra 4-byte VLAN tag for processing by upper layers
+ */
+ ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;
+
+ /* setup NAPI interface */
+ netif_napi_add(ndev, &priv->napi, tse_poll, NAPI_POLL_WEIGHT);
+
+ spin_lock_init(&priv->mac_cfg_lock);
+ spin_lock_init(&priv->tx_lock);
+ spin_lock_init(&priv->rxdma_irq_lock);
+
+ ret = register_netdev(ndev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register TSE net device\n");
+ goto out_free_mdio;
+ }
+
+ platform_set_drvdata(pdev, ndev);
+
+ priv->revision = ioread32(&priv->mac_dev->megacore_revision);
+
+ if (netif_msg_probe(priv))
+ dev_info(&pdev->dev, "Altera TSE MAC version %d.%d at 0x%08lx irq %d/%d\n",
+ (priv->revision >> 8) & 0xff,
+ priv->revision & 0xff,
+ (unsigned long) control_port->start, priv->rx_irq,
+ priv->tx_irq);
+
+ ret = init_phy(ndev);
+ if (ret != 0) {
+ netdev_err(ndev, "Cannot attach to PHY (error: %d)\n", ret);
+ goto out_free_mdio;
+ }
+ return 0;
+
+out_free_mdio:
+ altera_tse_mdio_destroy(ndev);
+out_free:
+ free_netdev(ndev);
+ return ret;
+}
+
+/* Remove Altera TSE MAC device
+ */
+static int altera_tse_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ altera_tse_mdio_destroy(ndev);
+ unregister_netdev(ndev);
+ free_netdev(ndev);
+
+ return 0;
+}
+
+struct altera_dmaops altera_dtype_sgdma = {
+ .altera_dtype = ALTERA_DTYPE_SGDMA,
+ .dmamask = 32,
+ .reset_dma = sgdma_reset,
+ .enable_txirq = sgdma_enable_txirq,
+ .enable_rxirq = sgdma_enable_rxirq,
+ .disable_txirq = sgdma_disable_txirq,
+ .disable_rxirq = sgdma_disable_rxirq,
+ .clear_txirq = sgdma_clear_txirq,
+ .clear_rxirq = sgdma_clear_rxirq,
+ .tx_buffer = sgdma_tx_buffer,
+ .tx_completions = sgdma_tx_completions,
+ .add_rx_desc = sgdma_add_rx_desc,
+ .get_rx_status = sgdma_rx_status,
+ .init_dma = sgdma_initialize,
+ .uninit_dma = sgdma_uninitialize,
+};
+
+struct altera_dmaops altera_dtype_msgdma = {
+ .altera_dtype = ALTERA_DTYPE_MSGDMA,
+ .dmamask = 64,
+ .reset_dma = msgdma_reset,
+ .enable_txirq = msgdma_enable_txirq,
+ .enable_rxirq = msgdma_enable_rxirq,
+ .disable_txirq = msgdma_disable_txirq,
+ .disable_rxirq = msgdma_disable_rxirq,
+ .clear_txirq = msgdma_clear_txirq,
+ .clear_rxirq = msgdma_clear_rxirq,
+ .tx_buffer = msgdma_tx_buffer,
+ .tx_completions = msgdma_tx_completions,
+ .add_rx_desc = msgdma_add_rx_desc,
+ .get_rx_status = msgdma_rx_status,
+ .init_dma = msgdma_initialize,
+ .uninit_dma = msgdma_uninitialize,
+};
+
+static struct of_device_id altera_tse_ids[] = {
+ { .compatible = "altr,tse-msgdma-1.0", .data = &altera_dtype_msgdma, },
+ { .compatible = "altr,tse-1.0", .data = &altera_dtype_sgdma, },
+ { .compatible = "ALTR,tse-1.0", .data = &altera_dtype_sgdma, },
+ {},
+};
+MODULE_DEVICE_TABLE(of, altera_tse_ids);
+
+static struct platform_driver altera_tse_driver = {
+ .probe = altera_tse_probe,
+ .remove = altera_tse_remove,
+ .suspend = NULL,
+ .resume = NULL,
+ .driver = {
+ .name = ALTERA_TSE_RESOURCE_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = altera_tse_ids,
+ },
+};
+
+module_platform_driver(altera_tse_driver);
+
+MODULE_AUTHOR("Altera Corporation");
+MODULE_DESCRIPTION("Altera Triple Speed Ethernet MAC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/altera/altera_utils.c b/drivers/net/ethernet/altera/altera_utils.c
new file mode 100644
index 000000000000..70fa13f486b2
--- /dev/null
+++ b/drivers/net/ethernet/altera/altera_utils.c
@@ -0,0 +1,44 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "altera_tse.h"
+#include "altera_utils.h"
+
+void tse_set_bit(void __iomem *ioaddr, u32 bit_mask)
+{
+ u32 value = ioread32(ioaddr);
+ value |= bit_mask;
+ iowrite32(value, ioaddr);
+}
+
+void tse_clear_bit(void __iomem *ioaddr, u32 bit_mask)
+{
+ u32 value = ioread32(ioaddr);
+ value &= ~bit_mask;
+ iowrite32(value, ioaddr);
+}
+
+int tse_bit_is_set(void __iomem *ioaddr, u32 bit_mask)
+{
+ u32 value = ioread32(ioaddr);
+ return (value & bit_mask) ? 1 : 0;
+}
+
+int tse_bit_is_clear(void __iomem *ioaddr, u32 bit_mask)
+{
+ u32 value = ioread32(ioaddr);
+ return (value & bit_mask) ? 0 : 1;
+}
diff --git a/drivers/net/ethernet/altera/altera_utils.h b/drivers/net/ethernet/altera/altera_utils.h
new file mode 100644
index 000000000000..ce1db36d3583
--- /dev/null
+++ b/drivers/net/ethernet/altera/altera_utils.h
@@ -0,0 +1,27 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+
+#ifndef __ALTERA_UTILS_H__
+#define __ALTERA_UTILS_H__
+
+void tse_set_bit(void __iomem *ioaddr, u32 bit_mask);
+void tse_clear_bit(void __iomem *ioaddr, u32 bit_mask);
+int tse_bit_is_set(void __iomem *ioaddr, u32 bit_mask);
+int tse_bit_is_clear(void __iomem *ioaddr, u32 bit_mask);
+
+#endif /* __ALTERA_UTILS_H__*/
diff --git a/drivers/net/ethernet/amd/7990.c b/drivers/net/ethernet/amd/7990.c
index 18e542f7853d..98a10d555b79 100644
--- a/drivers/net/ethernet/amd/7990.c
+++ b/drivers/net/ethernet/amd/7990.c
@@ -578,7 +578,7 @@ int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
outs++;
/* Kick the lance: transmit now */
WRITERDP(lp, LE_C0_INEA | LE_C0_TDMD);
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
spin_lock_irqsave(&lp->devlock, flags);
if (TX_BUFFS_AVAIL)
diff --git a/drivers/net/ethernet/amd/am79c961a.c b/drivers/net/ethernet/amd/am79c961a.c
index 9793767996a2..87e727b921dc 100644
--- a/drivers/net/ethernet/amd/am79c961a.c
+++ b/drivers/net/ethernet/amd/am79c961a.c
@@ -472,7 +472,7 @@ am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
if (am_readword(dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN)
netif_stop_queue(dev);
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c
index 2061b471fd16..26efaaa5e73f 100644
--- a/drivers/net/ethernet/amd/amd8111e.c
+++ b/drivers/net/ethernet/amd/amd8111e.c
@@ -720,6 +720,9 @@ static int amd8111e_rx_poll(struct napi_struct *napi, int budget)
int rx_pkt_limit = budget;
unsigned long flags;
+ if (rx_pkt_limit <= 0)
+ goto rx_not_empty;
+
do{
/* process receive packets until we use the quota*/
/* If we own the next entry, it's a new packet. Send it up. */
diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c
index 9339cccfe05a..e7cc9174e364 100644
--- a/drivers/net/ethernet/amd/pcnet32.c
+++ b/drivers/net/ethernet/amd/pcnet32.c
@@ -549,35 +549,35 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
struct pcnet32_rx_head *new_rx_ring;
struct sk_buff **new_skb_list;
int new, overlap;
+ unsigned int entries = 1 << size;
new_rx_ring = pci_alloc_consistent(lp->pci_dev,
sizeof(struct pcnet32_rx_head) *
- (1 << size),
+ entries,
&new_ring_dma_addr);
if (new_rx_ring == NULL) {
netif_err(lp, drv, dev, "Consistent memory allocation failed\n");
return;
}
- memset(new_rx_ring, 0, sizeof(struct pcnet32_rx_head) * (1 << size));
+ memset(new_rx_ring, 0, sizeof(struct pcnet32_rx_head) * entries);
- new_dma_addr_list = kcalloc(1 << size, sizeof(dma_addr_t), GFP_ATOMIC);
+ new_dma_addr_list = kcalloc(entries, sizeof(dma_addr_t), GFP_ATOMIC);
if (!new_dma_addr_list)
goto free_new_rx_ring;
- new_skb_list = kcalloc(1 << size, sizeof(struct sk_buff *),
- GFP_ATOMIC);
+ new_skb_list = kcalloc(entries, sizeof(struct sk_buff *), GFP_ATOMIC);
if (!new_skb_list)
goto free_new_lists;
/* first copy the current receive buffers */
- overlap = min(size, lp->rx_ring_size);
+ overlap = min(entries, lp->rx_ring_size);
for (new = 0; new < overlap; new++) {
new_rx_ring[new] = lp->rx_ring[new];
new_dma_addr_list[new] = lp->rx_dma_addr[new];
new_skb_list[new] = lp->rx_skbuff[new];
}
/* now allocate any new buffers needed */
- for (; new < size; new++) {
+ for (; new < entries; new++) {
struct sk_buff *rx_skbuff;
new_skb_list[new] = netdev_alloc_skb(dev, PKT_BUF_SKB);
rx_skbuff = new_skb_list[new];
@@ -592,6 +592,13 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
new_dma_addr_list[new] =
pci_map_single(lp->pci_dev, rx_skbuff->data,
PKT_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(lp->pci_dev,
+ new_dma_addr_list[new])) {
+ netif_err(lp, drv, dev, "%s dma mapping failed\n",
+ __func__);
+ dev_kfree_skb(new_skb_list[new]);
+ goto free_all_new;
+ }
new_rx_ring[new].base = cpu_to_le32(new_dma_addr_list[new]);
new_rx_ring[new].buf_length = cpu_to_le16(NEG_BUF_SIZE);
new_rx_ring[new].status = cpu_to_le16(0x8000);
@@ -599,8 +606,12 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
/* and free any unneeded buffers */
for (; new < lp->rx_ring_size; new++) {
if (lp->rx_skbuff[new]) {
- pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[new],
- PKT_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ if (!pci_dma_mapping_error(lp->pci_dev,
+ lp->rx_dma_addr[new]))
+ pci_unmap_single(lp->pci_dev,
+ lp->rx_dma_addr[new],
+ PKT_BUF_SIZE,
+ PCI_DMA_FROMDEVICE);
dev_kfree_skb(lp->rx_skbuff[new]);
}
}
@@ -612,7 +623,7 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
lp->rx_ring_size, lp->rx_ring,
lp->rx_ring_dma_addr);
- lp->rx_ring_size = (1 << size);
+ lp->rx_ring_size = entries;
lp->rx_mod_mask = lp->rx_ring_size - 1;
lp->rx_len_bits = (size << 4);
lp->rx_ring = new_rx_ring;
@@ -624,8 +635,12 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
free_all_new:
while (--new >= lp->rx_ring_size) {
if (new_skb_list[new]) {
- pci_unmap_single(lp->pci_dev, new_dma_addr_list[new],
- PKT_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ if (!pci_dma_mapping_error(lp->pci_dev,
+ new_dma_addr_list[new]))
+ pci_unmap_single(lp->pci_dev,
+ new_dma_addr_list[new],
+ PKT_BUF_SIZE,
+ PCI_DMA_FROMDEVICE);
dev_kfree_skb(new_skb_list[new]);
}
}
@@ -634,8 +649,7 @@ free_new_lists:
kfree(new_dma_addr_list);
free_new_rx_ring:
pci_free_consistent(lp->pci_dev,
- sizeof(struct pcnet32_rx_head) *
- (1 << size),
+ sizeof(struct pcnet32_rx_head) * entries,
new_rx_ring,
new_ring_dma_addr);
}
@@ -650,8 +664,12 @@ static void pcnet32_purge_rx_ring(struct net_device *dev)
lp->rx_ring[i].status = 0; /* CPU owns buffer */
wmb(); /* Make sure adapter sees owner change */
if (lp->rx_skbuff[i]) {
- pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
- PKT_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ if (!pci_dma_mapping_error(lp->pci_dev,
+ lp->rx_dma_addr[i]))
+ pci_unmap_single(lp->pci_dev,
+ lp->rx_dma_addr[i],
+ PKT_BUF_SIZE,
+ PCI_DMA_FROMDEVICE);
dev_kfree_skb_any(lp->rx_skbuff[i]);
}
lp->rx_skbuff[i] = NULL;
@@ -930,6 +948,12 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
lp->tx_dma_addr[x] =
pci_map_single(lp->pci_dev, skb->data, skb->len,
PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(lp->pci_dev, lp->tx_dma_addr[x])) {
+ netif_printk(lp, hw, KERN_DEBUG, dev,
+ "DMA mapping error at line: %d!\n",
+ __LINE__);
+ goto clean_up;
+ }
lp->tx_ring[x].base = cpu_to_le32(lp->tx_dma_addr[x]);
wmb(); /* Make sure owner changes after all others are visible */
lp->tx_ring[x].status = cpu_to_le16(status);
@@ -1142,24 +1166,36 @@ static void pcnet32_rx_entry(struct net_device *dev,
if (pkt_len > rx_copybreak) {
struct sk_buff *newskb;
+ dma_addr_t new_dma_addr;
newskb = netdev_alloc_skb(dev, PKT_BUF_SKB);
+ /*
+ * map the new buffer, if mapping fails, drop the packet and
+ * reuse the old buffer
+ */
if (newskb) {
skb_reserve(newskb, NET_IP_ALIGN);
- skb = lp->rx_skbuff[entry];
- pci_unmap_single(lp->pci_dev,
- lp->rx_dma_addr[entry],
- PKT_BUF_SIZE,
- PCI_DMA_FROMDEVICE);
- skb_put(skb, pkt_len);
- lp->rx_skbuff[entry] = newskb;
- lp->rx_dma_addr[entry] =
- pci_map_single(lp->pci_dev,
- newskb->data,
- PKT_BUF_SIZE,
- PCI_DMA_FROMDEVICE);
- rxp->base = cpu_to_le32(lp->rx_dma_addr[entry]);
- rx_in_place = 1;
+ new_dma_addr = pci_map_single(lp->pci_dev,
+ newskb->data,
+ PKT_BUF_SIZE,
+ PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(lp->pci_dev, new_dma_addr)) {
+ netif_err(lp, rx_err, dev,
+ "DMA mapping error.\n");
+ dev_kfree_skb(newskb);
+ skb = NULL;
+ } else {
+ skb = lp->rx_skbuff[entry];
+ pci_unmap_single(lp->pci_dev,
+ lp->rx_dma_addr[entry],
+ PKT_BUF_SIZE,
+ PCI_DMA_FROMDEVICE);
+ skb_put(skb, pkt_len);
+ lp->rx_skbuff[entry] = newskb;
+ lp->rx_dma_addr[entry] = new_dma_addr;
+ rxp->base = cpu_to_le32(new_dma_addr);
+ rx_in_place = 1;
+ }
} else
skb = NULL;
} else
@@ -2229,9 +2265,12 @@ static void pcnet32_purge_tx_ring(struct net_device *dev)
lp->tx_ring[i].status = 0; /* CPU owns buffer */
wmb(); /* Make sure adapter sees owner change */
if (lp->tx_skbuff[i]) {
- pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i],
- lp->tx_skbuff[i]->len,
- PCI_DMA_TODEVICE);
+ if (!pci_dma_mapping_error(lp->pci_dev,
+ lp->tx_dma_addr[i]))
+ pci_unmap_single(lp->pci_dev,
+ lp->tx_dma_addr[i],
+ lp->tx_skbuff[i]->len,
+ PCI_DMA_TODEVICE);
dev_kfree_skb_any(lp->tx_skbuff[i]);
}
lp->tx_skbuff[i] = NULL;
@@ -2264,10 +2303,19 @@ static int pcnet32_init_ring(struct net_device *dev)
}
rmb();
- if (lp->rx_dma_addr[i] == 0)
+ if (lp->rx_dma_addr[i] == 0) {
lp->rx_dma_addr[i] =
pci_map_single(lp->pci_dev, rx_skbuff->data,
PKT_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(lp->pci_dev,
+ lp->rx_dma_addr[i])) {
+ /* there is not much we can do at this point */
+ netif_err(lp, drv, dev,
+ "%s pci dma mapping error\n",
+ __func__);
+ return -1;
+ }
+ }
lp->rx_ring[i].base = cpu_to_le32(lp->rx_dma_addr[i]);
lp->rx_ring[i].buf_length = cpu_to_le16(NEG_BUF_SIZE);
wmb(); /* Make sure owner changes after all others are visible */
@@ -2397,9 +2445,14 @@ static netdev_tx_t pcnet32_start_xmit(struct sk_buff *skb,
lp->tx_ring[entry].misc = 0x00000000;
- lp->tx_skbuff[entry] = skb;
lp->tx_dma_addr[entry] =
pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(lp->pci_dev, lp->tx_dma_addr[entry])) {
+ dev_kfree_skb_any(skb);
+ dev->stats.tx_dropped++;
+ goto drop_packet;
+ }
+ lp->tx_skbuff[entry] = skb;
lp->tx_ring[entry].base = cpu_to_le32(lp->tx_dma_addr[entry]);
wmb(); /* Make sure owner changes after all others are visible */
lp->tx_ring[entry].status = cpu_to_le16(status);
@@ -2414,6 +2467,7 @@ static netdev_tx_t pcnet32_start_xmit(struct sk_buff *skb,
lp->tx_full = 1;
netif_stop_queue(dev);
}
+drop_packet:
spin_unlock_irqrestore(&lp->lock, flags);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c
index e92ffd6e1c15..17bb9ce96260 100644
--- a/drivers/net/ethernet/atheros/alx/main.c
+++ b/drivers/net/ethernet/atheros/alx/main.c
@@ -535,7 +535,7 @@ static int alx_alloc_descriptors(struct alx_priv *alx)
if (!alx->descmem.virt)
goto out_free;
- alx->txq.tpd = (void *)alx->descmem.virt;
+ alx->txq.tpd = alx->descmem.virt;
alx->txq.tpd_dma = alx->descmem.dma;
/* alignment requirement for next block */
@@ -1097,7 +1097,7 @@ static netdev_tx_t alx_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
drop:
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -1248,19 +1248,13 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
* shared register for the high 32 bits, so only a single, aligned,
* 4 GB physical address range can be used for descriptors.
*/
- if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) &&
- !dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) {
+ if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) {
dev_dbg(&pdev->dev, "DMA to 64-BIT addresses\n");
} else {
- err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (err) {
- err = dma_set_coherent_mask(&pdev->dev,
- DMA_BIT_MASK(32));
- if (err) {
- dev_err(&pdev->dev,
- "No usable DMA config, aborting\n");
- goto out_pci_disable;
- }
+ dev_err(&pdev->dev, "No usable DMA config, aborting\n");
+ goto out_pci_disable;
}
}
@@ -1292,6 +1286,7 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
alx = netdev_priv(netdev);
spin_lock_init(&alx->hw.mdio_lock);
spin_lock_init(&alx->irq_lock);
+ spin_lock_init(&alx->stats_lock);
alx->dev = netdev;
alx->hw.pdev = pdev;
alx->msg_enable = NETIF_MSG_LINK | NETIF_MSG_HW | NETIF_MSG_IFUP |
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index 4d3258dd0a88..e11bf18fbbd1 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -832,7 +832,7 @@ static int atl1c_sw_init(struct atl1c_adapter *adapter)
}
static inline void atl1c_clean_buffer(struct pci_dev *pdev,
- struct atl1c_buffer *buffer_info, int in_irq)
+ struct atl1c_buffer *buffer_info)
{
u16 pci_driection;
if (buffer_info->flags & ATL1C_BUFFER_FREE)
@@ -850,12 +850,8 @@ static inline void atl1c_clean_buffer(struct pci_dev *pdev,
pci_unmap_page(pdev, buffer_info->dma,
buffer_info->length, pci_driection);
}
- if (buffer_info->skb) {
- if (in_irq)
- dev_kfree_skb_irq(buffer_info->skb);
- else
- dev_kfree_skb(buffer_info->skb);
- }
+ if (buffer_info->skb)
+ dev_consume_skb_any(buffer_info->skb);
buffer_info->dma = 0;
buffer_info->skb = NULL;
ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_FREE);
@@ -875,7 +871,7 @@ static void atl1c_clean_tx_ring(struct atl1c_adapter *adapter,
ring_count = tpd_ring->count;
for (index = 0; index < ring_count; index++) {
buffer_info = &tpd_ring->buffer_info[index];
- atl1c_clean_buffer(pdev, buffer_info, 0);
+ atl1c_clean_buffer(pdev, buffer_info);
}
/* Zero out Tx-buffers */
@@ -899,7 +895,7 @@ static void atl1c_clean_rx_ring(struct atl1c_adapter *adapter)
for (j = 0; j < rfd_ring->count; j++) {
buffer_info = &rfd_ring->buffer_info[j];
- atl1c_clean_buffer(pdev, buffer_info, 0);
+ atl1c_clean_buffer(pdev, buffer_info);
}
/* zero out the descriptor ring */
memset(rfd_ring->desc, 0, rfd_ring->size);
@@ -1562,7 +1558,7 @@ static bool atl1c_clean_tx_irq(struct atl1c_adapter *adapter,
while (next_to_clean != hw_next_to_clean) {
buffer_info = &tpd_ring->buffer_info[next_to_clean];
- atl1c_clean_buffer(pdev, buffer_info, 1);
+ atl1c_clean_buffer(pdev, buffer_info);
if (++next_to_clean == tpd_ring->count)
next_to_clean = 0;
atomic_set(&tpd_ring->next_to_clean, next_to_clean);
@@ -1977,17 +1973,17 @@ static int atl1c_tso_csum(struct atl1c_adapter *adapter,
enum atl1c_trans_queue type)
{
struct pci_dev *pdev = adapter->pdev;
+ unsigned short offload_type;
u8 hdr_len;
u32 real_len;
- unsigned short offload_type;
- int err;
if (skb_is_gso(skb)) {
- if (skb_header_cloned(skb)) {
- err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
- if (unlikely(err))
- return -1;
- }
+ int err;
+
+ err = skb_cow_head(skb, 0);
+ if (err < 0)
+ return err;
+
offload_type = skb_shinfo(skb)->gso_type;
if (offload_type & SKB_GSO_TCPV4) {
@@ -2085,7 +2081,7 @@ static void atl1c_tx_rollback(struct atl1c_adapter *adpt,
while (index != tpd_ring->next_to_use) {
tpd = ATL1C_TPD_DESC(tpd_ring, index);
buffer_info = &tpd_ring->buffer_info[index];
- atl1c_clean_buffer(adpt->pdev, buffer_info, 0);
+ atl1c_clean_buffer(adpt->pdev, buffer_info);
memset(tpd, 0, sizeof(struct atl1c_tpd_desc));
if (++index == tpd_ring->count)
index = 0;
@@ -2258,7 +2254,7 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb,
/* roll back tpd/buffer */
atl1c_tx_rollback(adapter, tpd, type);
spin_unlock_irqrestore(&adapter->tx_lock, flags);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
} else {
atl1c_tx_queue(adapter, skb, tpd, type);
spin_unlock_irqrestore(&adapter->tx_lock, flags);
diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
index d5c2d3e912e5..4345332533ad 100644
--- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
@@ -1641,17 +1641,17 @@ static u16 atl1e_cal_tdp_req(const struct sk_buff *skb)
static int atl1e_tso_csum(struct atl1e_adapter *adapter,
struct sk_buff *skb, struct atl1e_tpd_desc *tpd)
{
+ unsigned short offload_type;
u8 hdr_len;
u32 real_len;
- unsigned short offload_type;
- int err;
if (skb_is_gso(skb)) {
- if (skb_header_cloned(skb)) {
- err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
- if (unlikely(err))
- return -1;
- }
+ int err;
+
+ err = skb_cow_head(skb, 0);
+ if (err < 0)
+ return err;
+
offload_type = skb_shinfo(skb)->gso_type;
if (offload_type & SKB_GSO_TCPV4) {
@@ -2436,7 +2436,7 @@ err_reset:
err_register:
err_sw_init:
err_eeprom:
- iounmap(adapter->hw.hw_addr);
+ pci_iounmap(pdev, adapter->hw.hw_addr);
err_init_netdev:
err_ioremap:
free_netdev(netdev);
@@ -2474,7 +2474,7 @@ static void atl1e_remove(struct pci_dev *pdev)
unregister_netdev(netdev);
atl1e_free_ring_resources(adapter);
atl1e_force_ps(&adapter->hw);
- iounmap(adapter->hw.hw_addr);
+ pci_iounmap(pdev, adapter->hw.hw_addr);
pci_release_regions(pdev);
free_netdev(netdev);
pci_disable_device(pdev);
diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c
index 287272dd69da..dfd0e91fa726 100644
--- a/drivers/net/ethernet/atheros/atlx/atl1.c
+++ b/drivers/net/ethernet/atheros/atlx/atl1.c
@@ -2118,18 +2118,17 @@ static u16 atl1_tpd_avail(struct atl1_tpd_ring *tpd_ring)
}
static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb,
- struct tx_packet_desc *ptpd)
+ struct tx_packet_desc *ptpd)
{
u8 hdr_len, ip_off;
u32 real_len;
- int err;
if (skb_shinfo(skb)->gso_size) {
- if (skb_header_cloned(skb)) {
- err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
- if (unlikely(err))
- return -1;
- }
+ int err;
+
+ err = skb_cow_head(skb, 0);
+ if (err < 0)
+ return err;
if (skb->protocol == htons(ETH_P_IP)) {
struct iphdr *iph = ip_hdr(skb);
@@ -2175,7 +2174,7 @@ static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb,
return 3;
}
}
- return false;
+ return 0;
}
static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb,
diff --git a/drivers/net/ethernet/atheros/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c
index 265ce1b752ed..78befb522a52 100644
--- a/drivers/net/ethernet/atheros/atlx/atl2.c
+++ b/drivers/net/ethernet/atheros/atlx/atl2.c
@@ -55,6 +55,7 @@ static const char atl2_driver_name[] = "atl2";
static const char atl2_driver_string[] = "Atheros(R) L2 Ethernet Driver";
static const char atl2_copyright[] = "Copyright (c) 2007 Atheros Corporation.";
static const char atl2_driver_version[] = ATL2_DRV_VERSION;
+static const struct ethtool_ops atl2_ethtool_ops;
MODULE_AUTHOR("Atheros Corporation <xiong.huang@atheros.com>, Chris Snook <csnook@redhat.com>");
MODULE_DESCRIPTION("Atheros Fast Ethernet Network Driver");
@@ -71,8 +72,6 @@ static DEFINE_PCI_DEVICE_TABLE(atl2_pci_tbl) = {
};
MODULE_DEVICE_TABLE(pci, atl2_pci_tbl);
-static void atl2_set_ethtool_ops(struct net_device *netdev);
-
static void atl2_check_options(struct atl2_adapter *adapter);
/**
@@ -1397,7 +1396,7 @@ static int atl2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
atl2_setup_pcicmd(pdev);
netdev->netdev_ops = &atl2_netdev_ops;
- atl2_set_ethtool_ops(netdev);
+ SET_ETHTOOL_OPS(netdev, &atl2_ethtool_ops);
netdev->watchdog_timeo = 5 * HZ;
strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
@@ -2105,11 +2104,6 @@ static const struct ethtool_ops atl2_ethtool_ops = {
.set_eeprom = atl2_set_eeprom,
};
-static void atl2_set_ethtool_ops(struct net_device *netdev)
-{
- SET_ETHTOOL_OPS(netdev, &atl2_ethtool_ops);
-}
-
#define LBYTESWAP(a) ((((a) & 0x00ff00ff) << 8) | \
(((a) & 0xff00ff00) >> 8))
#define LONGSWAP(a) ((LBYTESWAP(a) << 16) | (LBYTESWAP(a) >> 16))
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index 3f97d9fd0a71..85dbddd03722 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -60,6 +60,17 @@ config BCM63XX_ENET
This driver supports the ethernet MACs in the Broadcom 63xx
MIPS chipset family (BCM63XX).
+config BCMGENET
+ tristate "Broadcom GENET internal MAC support"
+ depends on OF
+ select MII
+ select PHYLIB
+ select FIXED_PHY if BCMGENET=y
+ select BCM7XXX_PHY
+ help
+ This driver supports the built-in Ethernet MACs found in the
+ Broadcom BCM7xxx Set Top Box family chipset.
+
config BNX2
tristate "Broadcom NetXtremeII support"
depends on PCI
diff --git a/drivers/net/ethernet/broadcom/Makefile b/drivers/net/ethernet/broadcom/Makefile
index 68efa1a3fb88..fd639a0d4c7d 100644
--- a/drivers/net/ethernet/broadcom/Makefile
+++ b/drivers/net/ethernet/broadcom/Makefile
@@ -4,6 +4,7 @@
obj-$(CONFIG_B44) += b44.o
obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o
+obj-$(CONFIG_BCMGENET) += genet/
obj-$(CONFIG_BNX2) += bnx2.o
obj-$(CONFIG_CNIC) += cnic.o
obj-$(CONFIG_BNX2X) += bnx2x/
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 1f7b5aa114fa..05ba62589017 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -1484,6 +1484,10 @@ static int b44_open(struct net_device *dev)
add_timer(&bp->timer);
b44_enable_ints(bp);
+
+ if (bp->flags & B44_FLAG_EXTERNAL_PHY)
+ phy_start(bp->phydev);
+
netif_start_queue(dev);
out:
return err;
@@ -1646,6 +1650,9 @@ static int b44_close(struct net_device *dev)
netif_stop_queue(dev);
+ if (bp->flags & B44_FLAG_EXTERNAL_PHY)
+ phy_stop(bp->phydev);
+
napi_disable(&bp->napi);
del_timer_sync(&bp->timer);
@@ -1678,7 +1685,7 @@ static struct rtnl_link_stats64 *b44_get_stats64(struct net_device *dev,
unsigned int start;
do {
- start = u64_stats_fetch_begin_bh(&hwstat->syncp);
+ start = u64_stats_fetch_begin_irq(&hwstat->syncp);
/* Convert HW stats into rtnl_link_stats64 stats. */
nstat->rx_packets = hwstat->rx_pkts;
@@ -1712,7 +1719,7 @@ static struct rtnl_link_stats64 *b44_get_stats64(struct net_device *dev,
/* Carrier lost counter seems to be broken for some devices */
nstat->tx_carrier_errors = hwstat->tx_carrier_lost;
#endif
- } while (u64_stats_fetch_retry_bh(&hwstat->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&hwstat->syncp, start));
return nstat;
}
@@ -2066,12 +2073,12 @@ static void b44_get_ethtool_stats(struct net_device *dev,
do {
data_src = &hwstat->tx_good_octets;
data_dst = data;
- start = u64_stats_fetch_begin_bh(&hwstat->syncp);
+ start = u64_stats_fetch_begin_irq(&hwstat->syncp);
for (i = 0; i < ARRAY_SIZE(b44_gstrings); i++)
*data_dst++ = *data_src++;
- } while (u64_stats_fetch_retry_bh(&hwstat->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&hwstat->syncp, start));
}
static void b44_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -2222,7 +2229,12 @@ static void b44_adjust_link(struct net_device *dev)
}
if (status_changed) {
- b44_check_phy(bp);
+ u32 val = br32(bp, B44_TX_CTRL);
+ if (bp->flags & B44_FLAG_FULL_DUPLEX)
+ val |= TX_CTRL_DUPLEX;
+ else
+ val &= ~TX_CTRL_DUPLEX;
+ bw32(bp, B44_TX_CTRL, val);
phy_print_status(phydev);
}
}
diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
index b9a5fb6400d3..a7d11f5565d6 100644
--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
@@ -1722,9 +1722,6 @@ static const struct net_device_ops bcm_enet_ops = {
.ndo_set_rx_mode = bcm_enet_set_multicast_list,
.ndo_do_ioctl = bcm_enet_ioctl,
.ndo_change_mtu = bcm_enet_change_mtu,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = bcm_enet_netpoll,
-#endif
};
/*
diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c
index 9d2dedadf2df..a8efb18e42fa 100644
--- a/drivers/net/ethernet/broadcom/bnx2.c
+++ b/drivers/net/ethernet/broadcom/bnx2.c
@@ -85,7 +85,7 @@ MODULE_FIRMWARE(FW_RV2P_FILE_09_Ax);
static int disable_msi = 0;
-module_param(disable_msi, int, 0);
+module_param(disable_msi, int, S_IRUGO);
MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
typedef enum {
@@ -2507,6 +2507,7 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent)
bp->fw_wr_seq++;
msg_data |= bp->fw_wr_seq;
+ bp->fw_last_msg = msg_data;
bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
@@ -2885,7 +2886,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
sw_cons = BNX2_NEXT_TX_BD(sw_cons);
tx_bytes += skb->len;
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
tx_pkt++;
if (tx_pkt == budget)
break;
@@ -3132,6 +3133,9 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
struct l2_fhdr *rx_hdr;
int rx_pkt = 0, pg_ring_used = 0;
+ if (budget <= 0)
+ return rx_pkt;
+
hw_cons = bnx2_get_hw_rx_cons(bnapi);
sw_cons = rxr->rx_cons;
sw_prod = rxr->rx_prod;
@@ -4000,8 +4004,23 @@ bnx2_setup_wol(struct bnx2 *bp)
wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
}
- if (!(bp->flags & BNX2_FLAG_NO_WOL))
- bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, 1, 0);
+ if (!(bp->flags & BNX2_FLAG_NO_WOL)) {
+ u32 val;
+
+ wol_msg |= BNX2_DRV_MSG_DATA_WAIT3;
+ if (bp->fw_last_msg || BNX2_CHIP(bp) != BNX2_CHIP_5709) {
+ bnx2_fw_sync(bp, wol_msg, 1, 0);
+ return;
+ }
+ /* Tell firmware not to power down the PHY yet, otherwise
+ * the chip will take a long time to respond to MMIO reads.
+ */
+ val = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
+ bnx2_shmem_wr(bp, BNX2_PORT_FEATURE,
+ val | BNX2_PORT_FEATURE_ASF_ENABLED);
+ bnx2_fw_sync(bp, wol_msg, 1, 0);
+ bnx2_shmem_wr(bp, BNX2_PORT_FEATURE, val);
+ }
}
@@ -4033,9 +4052,22 @@ bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
if (bp->wol)
pci_set_power_state(bp->pdev, PCI_D3hot);
- } else {
- pci_set_power_state(bp->pdev, PCI_D3hot);
+ break;
+
}
+ if (!bp->fw_last_msg && BNX2_CHIP(bp) == BNX2_CHIP_5709) {
+ u32 val;
+
+ /* Tell firmware not to power down the PHY yet,
+ * otherwise the other port may not respond to
+ * MMIO reads.
+ */
+ val = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
+ val &= ~BNX2_CONDITION_PM_STATE_MASK;
+ val |= BNX2_CONDITION_PM_STATE_UNPREP;
+ bnx2_shmem_wr(bp, BNX2_BC_STATE_CONDITION, val);
+ }
+ pci_set_power_state(bp->pdev, PCI_D3hot);
/* No more memory access after this point until
* device is brought back to D0.
@@ -6206,7 +6238,7 @@ bnx2_free_irq(struct bnx2 *bp)
static void
bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
{
- int i, total_vecs, rc;
+ int i, total_vecs;
struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
struct net_device *dev = bp->dev;
const int len = sizeof(bp->irq_tbl[0].name);
@@ -6229,16 +6261,9 @@ bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
#ifdef BCM_CNIC
total_vecs++;
#endif
- rc = -ENOSPC;
- while (total_vecs >= BNX2_MIN_MSIX_VEC) {
- rc = pci_enable_msix(bp->pdev, msix_ent, total_vecs);
- if (rc <= 0)
- break;
- if (rc > 0)
- total_vecs = rc;
- }
-
- if (rc != 0)
+ total_vecs = pci_enable_msix_range(bp->pdev, msix_ent,
+ BNX2_MIN_MSIX_VEC, total_vecs);
+ if (total_vecs < 0)
return;
msix_vecs = total_vecs;
@@ -6611,7 +6636,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
mapping = dma_map_single(&bp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);
if (dma_mapping_error(&bp->pdev->dev, mapping)) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -6704,7 +6729,7 @@ dma_error:
PCI_DMA_TODEVICE);
}
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/broadcom/bnx2.h b/drivers/net/ethernet/broadcom/bnx2.h
index f1cf2c44e7ed..e341bc366fa5 100644
--- a/drivers/net/ethernet/broadcom/bnx2.h
+++ b/drivers/net/ethernet/broadcom/bnx2.h
@@ -6900,6 +6900,7 @@ struct bnx2 {
u16 fw_wr_seq;
u16 fw_drv_pulse_wr_seq;
+ u32 fw_last_msg;
int rx_max_ring;
int rx_ring_size;
@@ -7406,6 +7407,10 @@ struct bnx2_rv2p_fw_file {
#define BNX2_CONDITION_MFW_RUN_NCSI 0x00006000
#define BNX2_CONDITION_MFW_RUN_NONE 0x0000e000
#define BNX2_CONDITION_MFW_RUN_MASK 0x0000e000
+#define BNX2_CONDITION_PM_STATE_MASK 0x00030000
+#define BNX2_CONDITION_PM_STATE_FULL 0x00030000
+#define BNX2_CONDITION_PM_STATE_PREP 0x00020000
+#define BNX2_CONDITION_PM_STATE_UNPREP 0x00010000
#define BNX2_BC_STATE_DEBUG_CMD 0x1dc
#define BNX2_BC_STATE_BC_DBG_CMD_SIGNATURE 0x42440000
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index 391f29ef6d2e..4d8f8aba0ea5 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -26,8 +26,8 @@
* (you will need to reboot afterwards) */
/* #define BNX2X_STOP_ON_ERROR */
-#define DRV_MODULE_VERSION "1.78.17-0"
-#define DRV_MODULE_RELDATE "2013/04/11"
+#define DRV_MODULE_VERSION "1.78.19-0"
+#define DRV_MODULE_RELDATE "2014/02/10"
#define BNX2X_BC_VER 0x040200
#if defined(CONFIG_DCB)
@@ -75,13 +75,22 @@ enum bnx2x_int_mode {
#define BNX2X_MSG_DCB 0x8000000
/* regular debug print */
+#define DP_INNER(fmt, ...) \
+ pr_notice("[%s:%d(%s)]" fmt, \
+ __func__, __LINE__, \
+ bp->dev ? (bp->dev->name) : "?", \
+ ##__VA_ARGS__);
+
#define DP(__mask, fmt, ...) \
do { \
if (unlikely(bp->msg_enable & (__mask))) \
- pr_notice("[%s:%d(%s)]" fmt, \
- __func__, __LINE__, \
- bp->dev ? (bp->dev->name) : "?", \
- ##__VA_ARGS__); \
+ DP_INNER(fmt, ##__VA_ARGS__); \
+} while (0)
+
+#define DP_AND(__mask, fmt, ...) \
+do { \
+ if (unlikely((bp->msg_enable & (__mask)) == __mask)) \
+ DP_INNER(fmt, ##__VA_ARGS__); \
} while (0)
#define DP_CONT(__mask, fmt, ...) \
@@ -1146,10 +1155,6 @@ struct bnx2x_port {
(offsetof(struct bnx2x_eth_stats, stat_name) / 4)
/* slow path */
-
-/* slow path work-queue */
-extern struct workqueue_struct *bnx2x_wq;
-
#define BNX2X_MAX_NUM_OF_VFS 64
#define BNX2X_VF_CID_WND 4 /* log num of queues per VF. HW config. */
#define BNX2X_CIDS_PER_VF (1 << BNX2X_VF_CID_WND)
@@ -1261,6 +1266,7 @@ struct bnx2x_slowpath {
union {
struct client_init_ramrod_data init_data;
struct client_update_ramrod_data update_data;
+ struct tpa_update_ramrod_data tpa_data;
} q_rdata;
union {
@@ -1392,7 +1398,7 @@ struct bnx2x_fw_stats_data {
};
/* Public slow path states */
-enum {
+enum sp_rtnl_flag {
BNX2X_SP_RTNL_SETUP_TC,
BNX2X_SP_RTNL_TX_TIMEOUT,
BNX2X_SP_RTNL_FAN_FAILURE,
@@ -1403,6 +1409,12 @@ enum {
BNX2X_SP_RTNL_RX_MODE,
BNX2X_SP_RTNL_HYPERVISOR_VLAN,
BNX2X_SP_RTNL_TX_STOP,
+ BNX2X_SP_RTNL_GET_DRV_VERSION,
+};
+
+enum bnx2x_iov_flag {
+ BNX2X_IOV_HANDLE_VF_MSG,
+ BNX2X_IOV_HANDLE_FLR,
};
struct bnx2x_prev_path_list {
@@ -1603,6 +1615,8 @@ struct bnx2x {
int mrrs;
struct delayed_work sp_task;
+ struct delayed_work iov_task;
+
atomic_t interrupt_occurred;
struct delayed_work sp_rtnl_task;
@@ -1693,6 +1707,10 @@ struct bnx2x {
struct bnx2x_slowpath *slowpath;
dma_addr_t slowpath_mapping;
+ /* Mechanism protecting the drv_info_to_mcp */
+ struct mutex drv_info_mutex;
+ bool drv_info_mng_owner;
+
/* Total number of FW statistics requests */
u8 fw_stats_num;
@@ -1882,6 +1900,9 @@ struct bnx2x {
/* operation indication for the sp_rtnl task */
unsigned long sp_rtnl_state;
+ /* Indication of the IOV tasks */
+ unsigned long iov_task_state;
+
/* DCBX Negotiation results */
struct dcbx_features dcbx_local_feat;
u32 dcbx_error;
@@ -2525,6 +2546,8 @@ enum {
void bnx2x_set_local_cmng(struct bnx2x *bp);
+void bnx2x_update_mng_version(struct bnx2x *bp);
+
#define MCPR_SCRATCH_BASE(bp) \
(CHIP_IS_E1x(bp) ? MCP_REG_MCPR_SCRATCH : MCP_A_REG_MCPR_SCRATCH)
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index 9d7419e0390b..9261d5313b5b 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -61,10 +61,14 @@ static void bnx2x_add_all_napi(struct bnx2x *bp)
static int bnx2x_calc_num_queues(struct bnx2x *bp)
{
- return bnx2x_num_queues ?
- min_t(int, bnx2x_num_queues, BNX2X_MAX_QUEUES(bp)) :
- min_t(int, netif_get_num_default_rss_queues(),
- BNX2X_MAX_QUEUES(bp));
+ int nq = bnx2x_num_queues ? : netif_get_num_default_rss_queues();
+
+ /* Reduce memory usage in kdump environment by using only one queue */
+ if (reset_devices)
+ nq = 1;
+
+ nq = clamp(nq, 1, BNX2X_MAX_QUEUES(bp));
+ return nq;
}
/**
@@ -868,6 +872,8 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
if (unlikely(bp->panic))
return 0;
#endif
+ if (budget <= 0)
+ return rx_pkt;
bd_cons = fp->rx_bd_cons;
bd_prod = fp->rx_bd_prod;
@@ -1638,36 +1644,16 @@ int bnx2x_enable_msix(struct bnx2x *bp)
DP(BNX2X_MSG_SP, "about to request enable msix with %d vectors\n",
msix_vec);
- rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], msix_vec);
-
+ rc = pci_enable_msix_range(bp->pdev, &bp->msix_table[0],
+ BNX2X_MIN_MSIX_VEC_CNT(bp), msix_vec);
/*
* reconfigure number of tx/rx queues according to available
* MSI-X vectors
*/
- if (rc >= BNX2X_MIN_MSIX_VEC_CNT(bp)) {
- /* how less vectors we will have? */
- int diff = msix_vec - rc;
-
- BNX2X_DEV_INFO("Trying to use less MSI-X vectors: %d\n", rc);
-
- rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], rc);
-
- if (rc) {
- BNX2X_DEV_INFO("MSI-X is not attainable rc %d\n", rc);
- goto no_msix;
- }
- /*
- * decrease number of queues by number of unallocated entries
- */
- bp->num_ethernet_queues -= diff;
- bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues;
-
- BNX2X_DEV_INFO("New queue configuration set: %d\n",
- bp->num_queues);
- } else if (rc > 0) {
+ if (rc == -ENOSPC) {
/* Get by with single vector */
- rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], 1);
- if (rc) {
+ rc = pci_enable_msix_range(bp->pdev, &bp->msix_table[0], 1, 1);
+ if (rc < 0) {
BNX2X_DEV_INFO("Single MSI-X is not attainable rc %d\n",
rc);
goto no_msix;
@@ -1680,8 +1666,22 @@ int bnx2x_enable_msix(struct bnx2x *bp)
bp->num_ethernet_queues = 1;
bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues;
} else if (rc < 0) {
- BNX2X_DEV_INFO("MSI-X is not attainable rc %d\n", rc);
+ BNX2X_DEV_INFO("MSI-X is not attainable rc %d\n", rc);
goto no_msix;
+ } else if (rc < msix_vec) {
+ /* how less vectors we will have? */
+ int diff = msix_vec - rc;
+
+ BNX2X_DEV_INFO("Trying to use less MSI-X vectors: %d\n", rc);
+
+ /*
+ * decrease number of queues by number of unallocated entries
+ */
+ bp->num_ethernet_queues -= diff;
+ bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues;
+
+ BNX2X_DEV_INFO("New queue configuration set: %d\n",
+ bp->num_queues);
}
bp->flags |= USING_MSIX_FLAG;
@@ -1873,7 +1873,7 @@ void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
}
u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv, select_queue_fallback_t fallback)
{
struct bnx2x *bp = netdev_priv(dev);
@@ -1895,7 +1895,7 @@ u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb,
}
/* select a non-FCoE queue */
- return __netdev_pick_tx(dev, skb) % BNX2X_NUM_ETH_QUEUES(bp);
+ return fallback(dev, skb) % BNX2X_NUM_ETH_QUEUES(bp);
}
void bnx2x_set_num_queues(struct bnx2x *bp)
@@ -2234,8 +2234,10 @@ static int bnx2x_alloc_fw_stats_mem(struct bnx2x *bp)
sizeof(struct per_queue_stats) * num_queue_stats +
sizeof(struct stats_counter);
- BNX2X_PCI_ALLOC(bp->fw_stats, &bp->fw_stats_mapping,
- bp->fw_stats_data_sz + bp->fw_stats_req_sz);
+ bp->fw_stats = BNX2X_PCI_ALLOC(&bp->fw_stats_mapping,
+ bp->fw_stats_data_sz + bp->fw_stats_req_sz);
+ if (!bp->fw_stats)
+ goto alloc_mem_err;
/* Set shortcuts */
bp->fw_stats_req = (struct bnx2x_fw_stats_req *)bp->fw_stats;
@@ -2802,6 +2804,9 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
if (CNIC_ENABLED(bp))
bnx2x_load_cnic(bp);
+ if (IS_PF(bp))
+ bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_GET_DRV_VERSION, 0);
+
if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) {
/* mark driver is loaded in shmem2 */
u32 val;
@@ -3028,6 +3033,10 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
bp->state = BNX2X_STATE_CLOSED;
bp->cnic_loaded = false;
+ /* Clear driver version indication in shmem */
+ if (IS_PF(bp))
+ bnx2x_update_mng_version(bp);
+
/* Check if there are pending parity attentions. If there are - set
* RECOVERY_IN_PROGRESS.
*/
@@ -3875,7 +3884,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
xmit_type);
}
- /* Add the macs to the parsing BD this is a vf */
+ /* Add the macs to the parsing BD if this is a vf or if
+ * Tx Switching is enabled.
+ */
if (IS_VF(bp)) {
/* override GRE parameters in BD */
bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.src_hi,
@@ -3887,6 +3898,11 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
&pbd_e2->data.mac_addr.dst_mid,
&pbd_e2->data.mac_addr.dst_lo,
eth->h_dest);
+ } else if (bp->flags & TX_SWITCHING) {
+ bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.dst_hi,
+ &pbd_e2->data.mac_addr.dst_mid,
+ &pbd_e2->data.mac_addr.dst_lo,
+ eth->h_dest);
}
SET_FLAG(pbd_e2_parsing_data,
@@ -4363,14 +4379,17 @@ static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index)
if (!IS_FCOE_IDX(index)) {
/* status blocks */
- if (!CHIP_IS_E1x(bp))
- BNX2X_PCI_ALLOC(sb->e2_sb,
- &bnx2x_fp(bp, index, status_blk_mapping),
- sizeof(struct host_hc_status_block_e2));
- else
- BNX2X_PCI_ALLOC(sb->e1x_sb,
- &bnx2x_fp(bp, index, status_blk_mapping),
- sizeof(struct host_hc_status_block_e1x));
+ if (!CHIP_IS_E1x(bp)) {
+ sb->e2_sb = BNX2X_PCI_ALLOC(&bnx2x_fp(bp, index, status_blk_mapping),
+ sizeof(struct host_hc_status_block_e2));
+ if (!sb->e2_sb)
+ goto alloc_mem_err;
+ } else {
+ sb->e1x_sb = BNX2X_PCI_ALLOC(&bnx2x_fp(bp, index, status_blk_mapping),
+ sizeof(struct host_hc_status_block_e1x));
+ if (!sb->e1x_sb)
+ goto alloc_mem_err;
+ }
}
/* FCoE Queue uses Default SB and doesn't ACK the SB, thus no need to
@@ -4389,35 +4408,49 @@ static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index)
"allocating tx memory of fp %d cos %d\n",
index, cos);
- BNX2X_ALLOC(txdata->tx_buf_ring,
- sizeof(struct sw_tx_bd) * NUM_TX_BD);
- BNX2X_PCI_ALLOC(txdata->tx_desc_ring,
- &txdata->tx_desc_mapping,
- sizeof(union eth_tx_bd_types) * NUM_TX_BD);
+ txdata->tx_buf_ring = kcalloc(NUM_TX_BD,
+ sizeof(struct sw_tx_bd),
+ GFP_KERNEL);
+ if (!txdata->tx_buf_ring)
+ goto alloc_mem_err;
+ txdata->tx_desc_ring = BNX2X_PCI_ALLOC(&txdata->tx_desc_mapping,
+ sizeof(union eth_tx_bd_types) * NUM_TX_BD);
+ if (!txdata->tx_desc_ring)
+ goto alloc_mem_err;
}
}
/* Rx */
if (!skip_rx_queue(bp, index)) {
/* fastpath rx rings: rx_buf rx_desc rx_comp */
- BNX2X_ALLOC(bnx2x_fp(bp, index, rx_buf_ring),
- sizeof(struct sw_rx_bd) * NUM_RX_BD);
- BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, rx_desc_ring),
- &bnx2x_fp(bp, index, rx_desc_mapping),
- sizeof(struct eth_rx_bd) * NUM_RX_BD);
+ bnx2x_fp(bp, index, rx_buf_ring) =
+ kcalloc(NUM_RX_BD, sizeof(struct sw_rx_bd), GFP_KERNEL);
+ if (!bnx2x_fp(bp, index, rx_buf_ring))
+ goto alloc_mem_err;
+ bnx2x_fp(bp, index, rx_desc_ring) =
+ BNX2X_PCI_ALLOC(&bnx2x_fp(bp, index, rx_desc_mapping),
+ sizeof(struct eth_rx_bd) * NUM_RX_BD);
+ if (!bnx2x_fp(bp, index, rx_desc_ring))
+ goto alloc_mem_err;
/* Seed all CQEs by 1s */
- BNX2X_PCI_FALLOC(bnx2x_fp(bp, index, rx_comp_ring),
- &bnx2x_fp(bp, index, rx_comp_mapping),
- sizeof(struct eth_fast_path_rx_cqe) *
- NUM_RCQ_BD);
+ bnx2x_fp(bp, index, rx_comp_ring) =
+ BNX2X_PCI_FALLOC(&bnx2x_fp(bp, index, rx_comp_mapping),
+ sizeof(struct eth_fast_path_rx_cqe) * NUM_RCQ_BD);
+ if (!bnx2x_fp(bp, index, rx_comp_ring))
+ goto alloc_mem_err;
/* SGE ring */
- BNX2X_ALLOC(bnx2x_fp(bp, index, rx_page_ring),
- sizeof(struct sw_rx_page) * NUM_RX_SGE);
- BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, rx_sge_ring),
- &bnx2x_fp(bp, index, rx_sge_mapping),
- BCM_PAGE_SIZE * NUM_RX_SGE_PAGES);
+ bnx2x_fp(bp, index, rx_page_ring) =
+ kcalloc(NUM_RX_SGE, sizeof(struct sw_rx_page),
+ GFP_KERNEL);
+ if (!bnx2x_fp(bp, index, rx_page_ring))
+ goto alloc_mem_err;
+ bnx2x_fp(bp, index, rx_sge_ring) =
+ BNX2X_PCI_ALLOC(&bnx2x_fp(bp, index, rx_sge_mapping),
+ BCM_PAGE_SIZE * NUM_RX_SGE_PAGES);
+ if (!bnx2x_fp(bp, index, rx_sge_ring))
+ goto alloc_mem_err;
/* RX BD ring */
bnx2x_set_next_page_rx_bd(fp);
@@ -4773,12 +4806,8 @@ void bnx2x_tx_timeout(struct net_device *dev)
bnx2x_panic();
#endif
- smp_mb__before_clear_bit();
- set_bit(BNX2X_SP_RTNL_TX_TIMEOUT, &bp->sp_rtnl_state);
- smp_mb__after_clear_bit();
-
/* This allows the netif to be shutdown gracefully before resetting */
- schedule_delayed_work(&bp->sp_rtnl_task, 0);
+ bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_TX_TIMEOUT, 0);
}
int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state)
@@ -4906,3 +4935,15 @@ void bnx2x_update_coalesce_sb_index(struct bnx2x *bp, u8 fw_sb_id,
disable = disable ? 1 : (usec ? 0 : 1);
storm_memset_hc_disable(bp, port, fw_sb_id, sb_index, disable);
}
+
+void bnx2x_schedule_sp_rtnl(struct bnx2x *bp, enum sp_rtnl_flag flag,
+ u32 verbose)
+{
+ smp_mb__before_clear_bit();
+ set_bit(flag, &bp->sp_rtnl_state);
+ smp_mb__after_clear_bit();
+ DP((BNX2X_MSG_SP | verbose), "Scheduling sp_rtnl task [Flag: %d]\n",
+ flag);
+ schedule_delayed_work(&bp->sp_rtnl_task, 0);
+}
+EXPORT_SYMBOL(bnx2x_schedule_sp_rtnl);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index 17d1689aec6b..05f4f5f52635 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -47,31 +47,26 @@ extern int bnx2x_num_queues;
} \
} while (0)
-#define BNX2X_PCI_ALLOC(x, y, size) \
- do { \
- x = dma_zalloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
- if (x == NULL) \
- goto alloc_mem_err; \
- DP(NETIF_MSG_HW, "BNX2X_PCI_ALLOC: Physical %Lx Virtual %p\n", \
- (unsigned long long)(*y), x); \
- } while (0)
-
-#define BNX2X_PCI_FALLOC(x, y, size) \
- do { \
- x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
- if (x == NULL) \
- goto alloc_mem_err; \
- memset((void *)x, 0xFFFFFFFF, size); \
- DP(NETIF_MSG_HW, "BNX2X_PCI_FALLOC: Physical %Lx Virtual %p\n",\
- (unsigned long long)(*y), x); \
- } while (0)
-
-#define BNX2X_ALLOC(x, size) \
- do { \
- x = kzalloc(size, GFP_KERNEL); \
- if (x == NULL) \
- goto alloc_mem_err; \
- } while (0)
+#define BNX2X_PCI_ALLOC(y, size) \
+({ \
+ void *x = dma_zalloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
+ if (x) \
+ DP(NETIF_MSG_HW, \
+ "BNX2X_PCI_ALLOC: Physical %Lx Virtual %p\n", \
+ (unsigned long long)(*y), x); \
+ x; \
+})
+#define BNX2X_PCI_FALLOC(y, size) \
+({ \
+ void *x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
+ if (x) { \
+ memset(x, 0xff, size); \
+ DP(NETIF_MSG_HW, \
+ "BNX2X_PCI_FALLOC: Physical %Lx Virtual %p\n", \
+ (unsigned long long)(*y), x); \
+ } \
+ x; \
+})
/*********************** Interfaces ****************************
* Functions that need to be implemented by each driver version
@@ -496,7 +491,7 @@ int bnx2x_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos);
/* select_queue callback */
u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv);
+ void *accel_priv, select_queue_fallback_t fallback);
static inline void bnx2x_update_rx_prod(struct bnx2x *bp,
struct bnx2x_fastpath *fp,
@@ -936,7 +931,7 @@ static inline int bnx2x_func_start(struct bnx2x *bp)
else /* CHIP_IS_E1X */
start_params->network_cos_mode = FW_WRR;
- start_params->gre_tunnel_mode = IPGRE_TUNNEL;
+ start_params->gre_tunnel_mode = L2GRE_TUNNEL;
start_params->gre_tunnel_rss = GRE_INNER_HEADERS_RSS;
return bnx2x_func_state_change(bp, &func_params);
@@ -1324,4 +1319,7 @@ void bnx2x_fill_fw_str(struct bnx2x *bp, char *buf, size_t buf_len);
int bnx2x_drain_tx_queues(struct bnx2x *bp);
void bnx2x_squeeze_objects(struct bnx2x *bp);
+void bnx2x_schedule_sp_rtnl(struct bnx2x*, enum sp_rtnl_flag,
+ u32 verbose);
+
#endif /* BNX2X_CMN_H */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
index fdace204b054..97ea5421dd96 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
@@ -710,8 +710,7 @@ static inline void bnx2x_dcbx_update_tc_mapping(struct bnx2x *bp)
* as we are handling an attention on a work queue which must be
* flushed at some rtnl-locked contexts (e.g. if down)
*/
- if (!test_and_set_bit(BNX2X_SP_RTNL_SETUP_TC, &bp->sp_rtnl_state))
- schedule_delayed_work(&bp->sp_rtnl_task, 0);
+ bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_SETUP_TC, 0);
}
void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)
@@ -764,10 +763,7 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)
if (IS_MF(bp))
bnx2x_link_sync_notify(bp);
- set_bit(BNX2X_SP_RTNL_TX_STOP, &bp->sp_rtnl_state);
-
- schedule_delayed_work(&bp->sp_rtnl_task, 0);
-
+ bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_TX_STOP, 0);
return;
}
case BNX2X_DCBX_STATE_TX_PAUSED:
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
index 38fc794c1655..b6de05e3149b 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -2969,8 +2969,9 @@ static void bnx2x_self_test(struct net_device *dev,
#define IS_PORT_STAT(i) \
((bnx2x_stats_arr[i].flags & STATS_FLAGS_BOTH) == STATS_FLAGS_PORT)
#define IS_FUNC_STAT(i) (bnx2x_stats_arr[i].flags & STATS_FLAGS_FUNC)
-#define IS_MF_MODE_STAT(bp) \
- (IS_MF(bp) && !(bp->msg_enable & BNX2X_MSG_STATS))
+#define HIDE_PORT_STAT(bp) \
+ ((IS_MF(bp) && !(bp->msg_enable & BNX2X_MSG_STATS)) || \
+ IS_VF(bp))
/* ethtool statistics are displayed for all regular ethernet queues and the
* fcoe L2 queue if not disabled
@@ -2992,7 +2993,7 @@ static int bnx2x_get_sset_count(struct net_device *dev, int stringset)
BNX2X_NUM_Q_STATS;
} else
num_strings = 0;
- if (IS_MF_MODE_STAT(bp)) {
+ if (HIDE_PORT_STAT(bp)) {
for (i = 0; i < BNX2X_NUM_STATS; i++)
if (IS_FUNC_STAT(i))
num_strings++;
@@ -3047,7 +3048,7 @@ static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
}
for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) {
- if (IS_MF_MODE_STAT(bp) && IS_PORT_STAT(i))
+ if (HIDE_PORT_STAT(bp) && IS_PORT_STAT(i))
continue;
strcpy(buf + (k + j)*ETH_GSTRING_LEN,
bnx2x_stats_arr[i].string);
@@ -3105,7 +3106,7 @@ static void bnx2x_get_ethtool_stats(struct net_device *dev,
hw_stats = (u32 *)&bp->eth_stats;
for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) {
- if (IS_MF_MODE_STAT(bp) && IS_PORT_STAT(i))
+ if (HIDE_PORT_STAT(bp) && IS_PORT_STAT(i))
continue;
if (bnx2x_stats_arr[i].size == 0) {
/* skip this counter */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
index 84aecdf06f7a..95dc36543548 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
@@ -87,7 +87,6 @@
(IRO[156].base + ((vfId) * IRO[156].m1))
#define CSTORM_VF_TO_PF_OFFSET(funcId) \
(IRO[150].base + ((funcId) * IRO[150].m1))
-#define TSTORM_ACCEPT_CLASSIFY_FAILED_OFFSET (IRO[204].base)
#define TSTORM_APPROXIMATE_MATCH_MULTICAST_FILTERING_OFFSET(pfId) \
(IRO[203].base + ((pfId) * IRO[203].m1))
#define TSTORM_ASSERT_LIST_INDEX_OFFSET (IRO[102].base)
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
index cf1df8b62e2c..5ba8af50c84f 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
@@ -2003,6 +2003,23 @@ struct shmem_lfa {
#define SHMEM_LFA_DONT_CLEAR_STAT (1<<24)
};
+/* Used to support NSCI get OS driver version
+ * on driver load the version value will be set
+ * on driver unload driver value of 0x0 will be set.
+ */
+struct os_drv_ver {
+#define DRV_VER_NOT_LOADED 0
+
+ /* personalties order is important */
+#define DRV_PERS_ETHERNET 0
+#define DRV_PERS_ISCSI 1
+#define DRV_PERS_FCOE 2
+
+ /* shmem2 struct is constant can't add more personalties here */
+#define MAX_DRV_PERS 3
+ u32 versions[MAX_DRV_PERS];
+};
+
struct ncsi_oem_fcoe_features {
u32 fcoe_features1;
#define FCOE_FEATURES1_IOS_PER_CONNECTION_MASK 0x0000FFFF
@@ -2217,6 +2234,18 @@ struct shmem2_region {
u32 reserved4; /* Offset 0x150 */
u32 link_attr_sync[PORT_MAX]; /* Offset 0x154 */
#define LINK_ATTR_SYNC_KR2_ENABLE (1<<0)
+
+ u32 reserved5[2];
+ u32 reserved6[PORT_MAX];
+
+ /* driver version for each personality */
+ struct os_drv_ver func_os_drv_ver[E2_FUNC_MAX]; /* Offset 0x16c */
+
+ /* Flag to the driver that PF's drv_info_host_addr buffer was read */
+ u32 mfw_drv_indication;
+
+ /* We use indication for each PF (0..3) */
+#define MFW_DRV_IND_READ_DONE_OFFSET(_pf_) (1 << (_pf_))
};
@@ -2848,7 +2877,7 @@ struct afex_stats {
#define BCM_5710_FW_MAJOR_VERSION 7
#define BCM_5710_FW_MINOR_VERSION 8
-#define BCM_5710_FW_REVISION_VERSION 17
+#define BCM_5710_FW_REVISION_VERSION 19
#define BCM_5710_FW_ENGINEERING_VERSION 0
#define BCM_5710_FW_COMPILE_FLAGS 1
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index c9c445e7b4a5..a78edaccceee 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -95,32 +95,33 @@ MODULE_FIRMWARE(FW_FILE_NAME_E1H);
MODULE_FIRMWARE(FW_FILE_NAME_E2);
int bnx2x_num_queues;
-module_param_named(num_queues, bnx2x_num_queues, int, 0);
+module_param_named(num_queues, bnx2x_num_queues, int, S_IRUGO);
MODULE_PARM_DESC(num_queues,
" Set number of queues (default is as a number of CPUs)");
static int disable_tpa;
-module_param(disable_tpa, int, 0);
+module_param(disable_tpa, int, S_IRUGO);
MODULE_PARM_DESC(disable_tpa, " Disable the TPA (LRO) feature");
static int int_mode;
-module_param(int_mode, int, 0);
+module_param(int_mode, int, S_IRUGO);
MODULE_PARM_DESC(int_mode, " Force interrupt mode other than MSI-X "
"(1 INT#x; 2 MSI)");
static int dropless_fc;
-module_param(dropless_fc, int, 0);
+module_param(dropless_fc, int, S_IRUGO);
MODULE_PARM_DESC(dropless_fc, " Pause on exhausted host ring");
static int mrrs = -1;
-module_param(mrrs, int, 0);
+module_param(mrrs, int, S_IRUGO);
MODULE_PARM_DESC(mrrs, " Force Max Read Req Size (0..3) (for debug)");
static int debug;
-module_param(debug, int, 0);
+module_param(debug, int, S_IRUGO);
MODULE_PARM_DESC(debug, " Default debug msglevel");
-struct workqueue_struct *bnx2x_wq;
+static struct workqueue_struct *bnx2x_wq;
+struct workqueue_struct *bnx2x_iov_wq;
struct bnx2x_mac_vals {
u32 xmac_addr;
@@ -918,7 +919,7 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
u16 start = 0, end = 0;
u8 cos;
#endif
- if (disable_int)
+ if (IS_PF(bp) && disable_int)
bnx2x_int_disable(bp);
bp->stats_state = STATS_STATE_DISABLED;
@@ -929,33 +930,41 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
/* Indices */
/* Common */
- BNX2X_ERR("def_idx(0x%x) def_att_idx(0x%x) attn_state(0x%x) spq_prod_idx(0x%x) next_stats_cnt(0x%x)\n",
- bp->def_idx, bp->def_att_idx, bp->attn_state,
- bp->spq_prod_idx, bp->stats_counter);
- BNX2X_ERR("DSB: attn bits(0x%x) ack(0x%x) id(0x%x) idx(0x%x)\n",
- bp->def_status_blk->atten_status_block.attn_bits,
- bp->def_status_blk->atten_status_block.attn_bits_ack,
- bp->def_status_blk->atten_status_block.status_block_id,
- bp->def_status_blk->atten_status_block.attn_bits_index);
- BNX2X_ERR(" def (");
- for (i = 0; i < HC_SP_SB_MAX_INDICES; i++)
- pr_cont("0x%x%s",
- bp->def_status_blk->sp_sb.index_values[i],
- (i == HC_SP_SB_MAX_INDICES - 1) ? ") " : " ");
-
- for (i = 0; i < sizeof(struct hc_sp_status_block_data)/sizeof(u32); i++)
- *((u32 *)&sp_sb_data + i) = REG_RD(bp, BAR_CSTRORM_INTMEM +
- CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(func) +
- i*sizeof(u32));
-
- pr_cont("igu_sb_id(0x%x) igu_seg_id(0x%x) pf_id(0x%x) vnic_id(0x%x) vf_id(0x%x) vf_valid (0x%x) state(0x%x)\n",
- sp_sb_data.igu_sb_id,
- sp_sb_data.igu_seg_id,
- sp_sb_data.p_func.pf_id,
- sp_sb_data.p_func.vnic_id,
- sp_sb_data.p_func.vf_id,
- sp_sb_data.p_func.vf_valid,
- sp_sb_data.state);
+ if (IS_PF(bp)) {
+ struct host_sp_status_block *def_sb = bp->def_status_blk;
+ int data_size, cstorm_offset;
+
+ BNX2X_ERR("def_idx(0x%x) def_att_idx(0x%x) attn_state(0x%x) spq_prod_idx(0x%x) next_stats_cnt(0x%x)\n",
+ bp->def_idx, bp->def_att_idx, bp->attn_state,
+ bp->spq_prod_idx, bp->stats_counter);
+ BNX2X_ERR("DSB: attn bits(0x%x) ack(0x%x) id(0x%x) idx(0x%x)\n",
+ def_sb->atten_status_block.attn_bits,
+ def_sb->atten_status_block.attn_bits_ack,
+ def_sb->atten_status_block.status_block_id,
+ def_sb->atten_status_block.attn_bits_index);
+ BNX2X_ERR(" def (");
+ for (i = 0; i < HC_SP_SB_MAX_INDICES; i++)
+ pr_cont("0x%x%s",
+ def_sb->sp_sb.index_values[i],
+ (i == HC_SP_SB_MAX_INDICES - 1) ? ") " : " ");
+
+ data_size = sizeof(struct hc_sp_status_block_data) /
+ sizeof(u32);
+ cstorm_offset = CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(func);
+ for (i = 0; i < data_size; i++)
+ *((u32 *)&sp_sb_data + i) =
+ REG_RD(bp, BAR_CSTRORM_INTMEM + cstorm_offset +
+ i * sizeof(u32));
+
+ pr_cont("igu_sb_id(0x%x) igu_seg_id(0x%x) pf_id(0x%x) vnic_id(0x%x) vf_id(0x%x) vf_valid (0x%x) state(0x%x)\n",
+ sp_sb_data.igu_sb_id,
+ sp_sb_data.igu_seg_id,
+ sp_sb_data.p_func.pf_id,
+ sp_sb_data.p_func.vnic_id,
+ sp_sb_data.p_func.vf_id,
+ sp_sb_data.p_func.vf_valid,
+ sp_sb_data.state);
+ }
for_each_eth_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
@@ -1013,6 +1022,11 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
pr_cont("0x%x%s",
fp->sb_index_values[j],
(j == loop - 1) ? ")" : " ");
+
+ /* VF cannot access FW refelection for status block */
+ if (IS_VF(bp))
+ continue;
+
/* fw sb data */
data_size = CHIP_IS_E1x(bp) ?
sizeof(struct hc_status_block_data_e1x) :
@@ -1064,16 +1078,18 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
}
#ifdef BNX2X_STOP_ON_ERROR
-
- /* event queue */
- BNX2X_ERR("eq cons %x prod %x\n", bp->eq_cons, bp->eq_prod);
- for (i = 0; i < NUM_EQ_DESC; i++) {
- u32 *data = (u32 *)&bp->eq_ring[i].message.data;
-
- BNX2X_ERR("event queue [%d]: header: opcode %d, error %d\n",
- i, bp->eq_ring[i].message.opcode,
- bp->eq_ring[i].message.error);
- BNX2X_ERR("data: %x %x %x\n", data[0], data[1], data[2]);
+ if (IS_PF(bp)) {
+ /* event queue */
+ BNX2X_ERR("eq cons %x prod %x\n", bp->eq_cons, bp->eq_prod);
+ for (i = 0; i < NUM_EQ_DESC; i++) {
+ u32 *data = (u32 *)&bp->eq_ring[i].message.data;
+
+ BNX2X_ERR("event queue [%d]: header: opcode %d, error %d\n",
+ i, bp->eq_ring[i].message.opcode,
+ bp->eq_ring[i].message.error);
+ BNX2X_ERR("data: %x %x %x\n",
+ data[0], data[1], data[2]);
+ }
}
/* Rings */
@@ -1140,8 +1156,10 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
}
}
#endif
- bnx2x_fw_dump(bp);
- bnx2x_mc_assert(bp);
+ if (IS_PF(bp)) {
+ bnx2x_fw_dump(bp);
+ bnx2x_mc_assert(bp);
+ }
BNX2X_ERR("end crash dump -----------------\n");
}
@@ -1814,6 +1832,11 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
drv_cmd = BNX2X_Q_CMD_EMPTY;
break;
+ case (RAMROD_CMD_ID_ETH_TPA_UPDATE):
+ DP(BNX2X_MSG_SP, "got tpa update ramrod CID=%d\n", cid);
+ drv_cmd = BNX2X_Q_CMD_UPDATE_TPA;
+ break;
+
default:
BNX2X_ERR("unexpected MC reply (%d) on fp[%d]\n",
command, fp->index);
@@ -1834,8 +1857,6 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
#else
return;
#endif
- /* SRIOV: reschedule any 'in_progress' operations */
- bnx2x_iov_sp_event(bp, cid, true);
smp_mb__before_atomic_inc();
atomic_inc(&bp->cq_spq_left);
@@ -3460,10 +3481,15 @@ static void bnx2x_handle_eee_event(struct bnx2x *bp)
bnx2x_fw_command(bp, DRV_MSG_CODE_EEE_RESULTS_ACK, 0);
}
+#define BNX2X_UPDATE_DRV_INFO_IND_LENGTH (20)
+#define BNX2X_UPDATE_DRV_INFO_IND_COUNT (25)
+
static void bnx2x_handle_drv_info_req(struct bnx2x *bp)
{
enum drv_info_opcode op_code;
u32 drv_info_ctl = SHMEM2_RD(bp, drv_info_control);
+ bool release = false;
+ int wait;
/* if drv_info version supported by MFW doesn't match - send NACK */
if ((drv_info_ctl & DRV_INFO_CONTROL_VER_MASK) != DRV_INFO_CUR_VER) {
@@ -3474,6 +3500,9 @@ static void bnx2x_handle_drv_info_req(struct bnx2x *bp)
op_code = (drv_info_ctl & DRV_INFO_CONTROL_OP_CODE_MASK) >>
DRV_INFO_CONTROL_OP_CODE_SHIFT;
+ /* Must prevent other flows from accessing drv_info_to_mcp */
+ mutex_lock(&bp->drv_info_mutex);
+
memset(&bp->slowpath->drv_info_to_mcp, 0,
sizeof(union drv_info_to_mcp));
@@ -3490,7 +3519,7 @@ static void bnx2x_handle_drv_info_req(struct bnx2x *bp)
default:
/* if op code isn't supported - send NACK */
bnx2x_fw_command(bp, DRV_MSG_CODE_DRV_INFO_NACK, 0);
- return;
+ goto out;
}
/* if we got drv_info attn from MFW then these fields are defined in
@@ -3502,6 +3531,106 @@ static void bnx2x_handle_drv_info_req(struct bnx2x *bp)
U64_HI(bnx2x_sp_mapping(bp, drv_info_to_mcp)));
bnx2x_fw_command(bp, DRV_MSG_CODE_DRV_INFO_ACK, 0);
+
+ /* Since possible management wants both this and get_driver_version
+ * need to wait until management notifies us it finished utilizing
+ * the buffer.
+ */
+ if (!SHMEM2_HAS(bp, mfw_drv_indication)) {
+ DP(BNX2X_MSG_MCP, "Management does not support indication\n");
+ } else if (!bp->drv_info_mng_owner) {
+ u32 bit = MFW_DRV_IND_READ_DONE_OFFSET((BP_ABS_FUNC(bp) >> 1));
+
+ for (wait = 0; wait < BNX2X_UPDATE_DRV_INFO_IND_COUNT; wait++) {
+ u32 indication = SHMEM2_RD(bp, mfw_drv_indication);
+
+ /* Management is done; need to clear indication */
+ if (indication & bit) {
+ SHMEM2_WR(bp, mfw_drv_indication,
+ indication & ~bit);
+ release = true;
+ break;
+ }
+
+ msleep(BNX2X_UPDATE_DRV_INFO_IND_LENGTH);
+ }
+ }
+ if (!release) {
+ DP(BNX2X_MSG_MCP, "Management did not release indication\n");
+ bp->drv_info_mng_owner = true;
+ }
+
+out:
+ mutex_unlock(&bp->drv_info_mutex);
+}
+
+static u32 bnx2x_update_mng_version_utility(u8 *version, bool bnx2x_format)
+{
+ u8 vals[4];
+ int i = 0;
+
+ if (bnx2x_format) {
+ i = sscanf(version, "1.%c%hhd.%hhd.%hhd",
+ &vals[0], &vals[1], &vals[2], &vals[3]);
+ if (i > 0)
+ vals[0] -= '0';
+ } else {
+ i = sscanf(version, "%hhd.%hhd.%hhd.%hhd",
+ &vals[0], &vals[1], &vals[2], &vals[3]);
+ }
+
+ while (i < 4)
+ vals[i++] = 0;
+
+ return (vals[0] << 24) | (vals[1] << 16) | (vals[2] << 8) | vals[3];
+}
+
+void bnx2x_update_mng_version(struct bnx2x *bp)
+{
+ u32 iscsiver = DRV_VER_NOT_LOADED;
+ u32 fcoever = DRV_VER_NOT_LOADED;
+ u32 ethver = DRV_VER_NOT_LOADED;
+ int idx = BP_FW_MB_IDX(bp);
+ u8 *version;
+
+ if (!SHMEM2_HAS(bp, func_os_drv_ver))
+ return;
+
+ mutex_lock(&bp->drv_info_mutex);
+ /* Must not proceed when `bnx2x_handle_drv_info_req' is feasible */
+ if (bp->drv_info_mng_owner)
+ goto out;
+
+ if (bp->state != BNX2X_STATE_OPEN)
+ goto out;
+
+ /* Parse ethernet driver version */
+ ethver = bnx2x_update_mng_version_utility(DRV_MODULE_VERSION, true);
+ if (!CNIC_LOADED(bp))
+ goto out;
+
+ /* Try getting storage driver version via cnic */
+ memset(&bp->slowpath->drv_info_to_mcp, 0,
+ sizeof(union drv_info_to_mcp));
+ bnx2x_drv_info_iscsi_stat(bp);
+ version = bp->slowpath->drv_info_to_mcp.iscsi_stat.version;
+ iscsiver = bnx2x_update_mng_version_utility(version, false);
+
+ memset(&bp->slowpath->drv_info_to_mcp, 0,
+ sizeof(union drv_info_to_mcp));
+ bnx2x_drv_info_fcoe_stat(bp);
+ version = bp->slowpath->drv_info_to_mcp.fcoe_stat.version;
+ fcoever = bnx2x_update_mng_version_utility(version, false);
+
+out:
+ SHMEM2_WR(bp, func_os_drv_ver[idx].versions[DRV_PERS_ETHERNET], ethver);
+ SHMEM2_WR(bp, func_os_drv_ver[idx].versions[DRV_PERS_ISCSI], iscsiver);
+ SHMEM2_WR(bp, func_os_drv_ver[idx].versions[DRV_PERS_FCOE], fcoever);
+
+ mutex_unlock(&bp->drv_info_mutex);
+
+ DP(BNX2X_MSG_MCP, "Setting driver version: ETH [%08x] iSCSI [%08x] FCoE [%08x]\n",
+ ethver, iscsiver, fcoever);
}
static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event)
@@ -3644,10 +3773,18 @@ int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
cpu_to_le32((command << SPE_HDR_CMD_ID_SHIFT) |
HW_CID(bp, cid));
- type = (cmd_type << SPE_HDR_CONN_TYPE_SHIFT) & SPE_HDR_CONN_TYPE;
-
- type |= ((BP_FUNC(bp) << SPE_HDR_FUNCTION_ID_SHIFT) &
- SPE_HDR_FUNCTION_ID);
+ /* In some cases, type may already contain the func-id
+ * mainly in SRIOV related use cases, so we add it here only
+ * if it's not already set.
+ */
+ if (!(cmd_type & SPE_HDR_FUNCTION_ID)) {
+ type = (cmd_type << SPE_HDR_CONN_TYPE_SHIFT) &
+ SPE_HDR_CONN_TYPE;
+ type |= ((BP_FUNC(bp) << SPE_HDR_FUNCTION_ID_SHIFT) &
+ SPE_HDR_FUNCTION_ID);
+ } else {
+ type = cmd_type;
+ }
spe->hdr.type = cpu_to_le16(type);
@@ -3878,10 +4015,7 @@ static void bnx2x_fan_failure(struct bnx2x *bp)
* This is due to some boards consuming sufficient power when driver is
* up to overheat if fan fails.
*/
- smp_mb__before_clear_bit();
- set_bit(BNX2X_SP_RTNL_FAN_FAILURE, &bp->sp_rtnl_state);
- smp_mb__after_clear_bit();
- schedule_delayed_work(&bp->sp_rtnl_task, 0);
+ bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_FAN_FAILURE, 0);
}
static void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
@@ -4025,7 +4159,8 @@ static void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
bnx2x_handle_drv_info_req(bp);
if (val & DRV_STATUS_VF_DISABLED)
- bnx2x_vf_handle_flr_event(bp);
+ bnx2x_schedule_iov_task(bp,
+ BNX2X_IOV_HANDLE_FLR);
if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF))
bnx2x_pmf_update(bp);
@@ -5216,14 +5351,14 @@ static void bnx2x_eq_int(struct bnx2x *bp)
/* handle eq element */
switch (opcode) {
case EVENT_RING_OPCODE_VF_PF_CHANNEL:
- DP(BNX2X_MSG_IOV, "vf pf channel element on eq\n");
- bnx2x_vf_mbx(bp, &elem->message.data.vf_pf_event);
+ bnx2x_vf_mbx_schedule(bp,
+ &elem->message.data.vf_pf_event);
continue;
case EVENT_RING_OPCODE_STAT_QUERY:
- DP(BNX2X_MSG_SP | BNX2X_MSG_STATS,
- "got statistics comp event %d\n",
- bp->stats_comp++);
+ DP_AND((BNX2X_MSG_SP | BNX2X_MSG_STATS),
+ "got statistics comp event %d\n",
+ bp->stats_comp++);
/* nothing to do with stats comp */
goto next_spqe;
@@ -5273,6 +5408,8 @@ static void bnx2x_eq_int(struct bnx2x *bp)
break;
} else {
+ int cmd = BNX2X_SP_RTNL_AFEX_F_UPDATE;
+
DP(BNX2X_MSG_SP | BNX2X_MSG_MCP,
"AFEX: ramrod completed FUNCTION_UPDATE\n");
f_obj->complete_cmd(bp, f_obj,
@@ -5282,12 +5419,7 @@ static void bnx2x_eq_int(struct bnx2x *bp)
* sp_rtnl task as all Queue SP operations
* should run under rtnl_lock.
*/
- smp_mb__before_clear_bit();
- set_bit(BNX2X_SP_RTNL_AFEX_F_UPDATE,
- &bp->sp_rtnl_state);
- smp_mb__after_clear_bit();
-
- schedule_delayed_work(&bp->sp_rtnl_task, 0);
+ bnx2x_schedule_sp_rtnl(bp, cmd, 0);
}
goto next_spqe;
@@ -5435,13 +5567,6 @@ static void bnx2x_sp_task(struct work_struct *work)
le16_to_cpu(bp->def_att_idx), IGU_INT_ENABLE, 1);
}
- /* must be called after the EQ processing (since eq leads to sriov
- * ramrod completion flows).
- * This flow may have been scheduled by the arrival of a ramrod
- * completion, or by the sriov code rescheduling itself.
- */
- bnx2x_iov_sp_task(bp);
-
/* afex - poll to check if VIFSET_ACK should be sent to MFW */
if (test_and_clear_bit(BNX2X_AFEX_PENDING_VIFSET_MCP_ACK,
&bp->sp_state)) {
@@ -6005,18 +6130,6 @@ static void bnx2x_init_internal_common(struct bnx2x *bp)
{
int i;
- if (IS_MF_SI(bp))
- /*
- * In switch independent mode, the TSTORM needs to accept
- * packets that failed classification, since approximate match
- * mac addresses aren't written to NIG LLH
- */
- REG_WR8(bp, BAR_TSTRORM_INTMEM +
- TSTORM_ACCEPT_CLASSIFY_FAILED_OFFSET, 2);
- else if (!CHIP_IS_E1(bp)) /* 57710 doesn't support MF */
- REG_WR8(bp, BAR_TSTRORM_INTMEM +
- TSTORM_ACCEPT_CLASSIFY_FAILED_OFFSET, 0);
-
/* Zero this manually as its initialization is
currently missing in the initTool */
for (i = 0; i < (USTORM_AGG_DATA_SIZE >> 2); i++)
@@ -7989,19 +8102,25 @@ void bnx2x_free_mem(struct bnx2x *bp)
int bnx2x_alloc_mem_cnic(struct bnx2x *bp)
{
- if (!CHIP_IS_E1x(bp))
+ if (!CHIP_IS_E1x(bp)) {
/* size = the status block + ramrod buffers */
- BNX2X_PCI_ALLOC(bp->cnic_sb.e2_sb, &bp->cnic_sb_mapping,
- sizeof(struct host_hc_status_block_e2));
- else
- BNX2X_PCI_ALLOC(bp->cnic_sb.e1x_sb,
- &bp->cnic_sb_mapping,
- sizeof(struct
- host_hc_status_block_e1x));
+ bp->cnic_sb.e2_sb = BNX2X_PCI_ALLOC(&bp->cnic_sb_mapping,
+ sizeof(struct host_hc_status_block_e2));
+ if (!bp->cnic_sb.e2_sb)
+ goto alloc_mem_err;
+ } else {
+ bp->cnic_sb.e1x_sb = BNX2X_PCI_ALLOC(&bp->cnic_sb_mapping,
+ sizeof(struct host_hc_status_block_e1x));
+ if (!bp->cnic_sb.e1x_sb)
+ goto alloc_mem_err;
+ }
- if (CONFIGURE_NIC_MODE(bp) && !bp->t2)
+ if (CONFIGURE_NIC_MODE(bp) && !bp->t2) {
/* allocate searcher T2 table, as it wasn't allocated before */
- BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, SRC_T2_SZ);
+ bp->t2 = BNX2X_PCI_ALLOC(&bp->t2_mapping, SRC_T2_SZ);
+ if (!bp->t2)
+ goto alloc_mem_err;
+ }
/* write address to which L5 should insert its values */
bp->cnic_eth_dev.addr_drv_info_to_mcp =
@@ -8022,15 +8141,22 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
{
int i, allocated, context_size;
- if (!CONFIGURE_NIC_MODE(bp) && !bp->t2)
+ if (!CONFIGURE_NIC_MODE(bp) && !bp->t2) {
/* allocate searcher T2 table */
- BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, SRC_T2_SZ);
+ bp->t2 = BNX2X_PCI_ALLOC(&bp->t2_mapping, SRC_T2_SZ);
+ if (!bp->t2)
+ goto alloc_mem_err;
+ }
- BNX2X_PCI_ALLOC(bp->def_status_blk, &bp->def_status_blk_mapping,
- sizeof(struct host_sp_status_block));
+ bp->def_status_blk = BNX2X_PCI_ALLOC(&bp->def_status_blk_mapping,
+ sizeof(struct host_sp_status_block));
+ if (!bp->def_status_blk)
+ goto alloc_mem_err;
- BNX2X_PCI_ALLOC(bp->slowpath, &bp->slowpath_mapping,
- sizeof(struct bnx2x_slowpath));
+ bp->slowpath = BNX2X_PCI_ALLOC(&bp->slowpath_mapping,
+ sizeof(struct bnx2x_slowpath));
+ if (!bp->slowpath)
+ goto alloc_mem_err;
/* Allocate memory for CDU context:
* This memory is allocated separately and not in the generic ILT
@@ -8050,12 +8176,16 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
for (i = 0, allocated = 0; allocated < context_size; i++) {
bp->context[i].size = min(CDU_ILT_PAGE_SZ,
(context_size - allocated));
- BNX2X_PCI_ALLOC(bp->context[i].vcxt,
- &bp->context[i].cxt_mapping,
- bp->context[i].size);
+ bp->context[i].vcxt = BNX2X_PCI_ALLOC(&bp->context[i].cxt_mapping,
+ bp->context[i].size);
+ if (!bp->context[i].vcxt)
+ goto alloc_mem_err;
allocated += bp->context[i].size;
}
- BNX2X_ALLOC(bp->ilt->lines, sizeof(struct ilt_line) * ILT_MAX_LINES);
+ bp->ilt->lines = kcalloc(ILT_MAX_LINES, sizeof(struct ilt_line),
+ GFP_KERNEL);
+ if (!bp->ilt->lines)
+ goto alloc_mem_err;
if (bnx2x_ilt_mem_op(bp, ILT_MEMOP_ALLOC))
goto alloc_mem_err;
@@ -8064,11 +8194,15 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
goto alloc_mem_err;
/* Slow path ring */
- BNX2X_PCI_ALLOC(bp->spq, &bp->spq_mapping, BCM_PAGE_SIZE);
+ bp->spq = BNX2X_PCI_ALLOC(&bp->spq_mapping, BCM_PAGE_SIZE);
+ if (!bp->spq)
+ goto alloc_mem_err;
/* EQ */
- BNX2X_PCI_ALLOC(bp->eq_ring, &bp->eq_mapping,
- BCM_PAGE_SIZE * NUM_EQ_PAGES);
+ bp->eq_ring = BNX2X_PCI_ALLOC(&bp->eq_mapping,
+ BCM_PAGE_SIZE * NUM_EQ_PAGES);
+ if (!bp->eq_ring)
+ goto alloc_mem_err;
return 0;
@@ -8849,6 +8983,7 @@ static int bnx2x_func_wait_started(struct bnx2x *bp)
synchronize_irq(bp->pdev->irq);
flush_workqueue(bnx2x_wq);
+ flush_workqueue(bnx2x_iov_wq);
while (bnx2x_func_get_state(bp, &bp->func_obj) !=
BNX2X_F_STATE_STARTED && tout--)
@@ -9774,6 +9909,10 @@ sp_rtnl_not_reset:
bnx2x_dcbx_resume_hw_tx(bp);
}
+ if (test_and_clear_bit(BNX2X_SP_RTNL_GET_DRV_VERSION,
+ &bp->sp_rtnl_state))
+ bnx2x_update_mng_version(bp);
+
/* work which needs rtnl lock not-taken (as it takes the lock itself and
* can be called from other contexts as well)
*/
@@ -11724,12 +11863,15 @@ static int bnx2x_init_bp(struct bnx2x *bp)
mutex_init(&bp->port.phy_mutex);
mutex_init(&bp->fw_mb_mutex);
+ mutex_init(&bp->drv_info_mutex);
+ bp->drv_info_mng_owner = false;
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);
INIT_DELAYED_WORK(&bp->period_task, bnx2x_period_task);
+ INIT_DELAYED_WORK(&bp->iov_task, bnx2x_iov_task);
if (IS_PF(bp)) {
rc = bnx2x_get_hwinfo(bp);
if (rc)
@@ -11771,6 +11913,8 @@ static int bnx2x_init_bp(struct bnx2x *bp)
bp->disable_tpa = disable_tpa;
bp->disable_tpa |= IS_MF_STORAGE_SD(bp) || IS_MF_FCOE_AFEX(bp);
+ /* Reduce memory usage in kdump environment by disabling TPA */
+ bp->disable_tpa |= reset_devices;
/* Set TPA flags */
if (bp->disable_tpa) {
@@ -11942,7 +12086,7 @@ static int bnx2x_init_mcast_macs_list(struct bnx2x *bp,
{
int mc_count = netdev_mc_count(bp->dev);
struct bnx2x_mcast_list_elem *mc_mac =
- kzalloc(sizeof(*mc_mac) * mc_count, GFP_ATOMIC);
+ kcalloc(mc_count, sizeof(*mc_mac), GFP_ATOMIC);
struct netdev_hw_addr *ha;
if (!mc_mac)
@@ -12064,11 +12208,8 @@ static void bnx2x_set_rx_mode(struct net_device *dev)
return;
} else {
/* Schedule an SP task to handle rest of change */
- DP(NETIF_MSG_IFUP, "Scheduling an Rx mode change\n");
- smp_mb__before_clear_bit();
- set_bit(BNX2X_SP_RTNL_RX_MODE, &bp->sp_rtnl_state);
- smp_mb__after_clear_bit();
- schedule_delayed_work(&bp->sp_rtnl_task, 0);
+ bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_RX_MODE,
+ NETIF_MSG_IFUP);
}
}
@@ -12101,11 +12242,8 @@ void bnx2x_set_rx_mode_inner(struct bnx2x *bp)
/* configuring mcast to a vf involves sleeping (when we
* wait for the pf's response).
*/
- smp_mb__before_clear_bit();
- set_bit(BNX2X_SP_RTNL_VFPF_MCAST,
- &bp->sp_rtnl_state);
- smp_mb__after_clear_bit();
- schedule_delayed_work(&bp->sp_rtnl_task, 0);
+ bnx2x_schedule_sp_rtnl(bp,
+ BNX2X_SP_RTNL_VFPF_MCAST, 0);
}
}
@@ -13356,11 +13494,18 @@ static int __init bnx2x_init(void)
pr_err("Cannot create workqueue\n");
return -ENOMEM;
}
+ bnx2x_iov_wq = create_singlethread_workqueue("bnx2x_iov");
+ if (!bnx2x_iov_wq) {
+ pr_err("Cannot create iov workqueue\n");
+ destroy_workqueue(bnx2x_wq);
+ return -ENOMEM;
+ }
ret = pci_register_driver(&bnx2x_pci_driver);
if (ret) {
pr_err("Cannot register driver\n");
destroy_workqueue(bnx2x_wq);
+ destroy_workqueue(bnx2x_iov_wq);
}
return ret;
}
@@ -13372,6 +13517,7 @@ static void __exit bnx2x_cleanup(void)
pci_unregister_driver(&bnx2x_pci_driver);
destroy_workqueue(bnx2x_wq);
+ destroy_workqueue(bnx2x_iov_wq);
/* Free globally allocated resources */
list_for_each_safe(pos, q, &bnx2x_prev_list) {
@@ -13765,6 +13911,7 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
REG_WR(bp, scratch_offset + i,
*(host_addr + i/4));
}
+ bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_GET_DRV_VERSION, 0);
break;
}
@@ -13782,6 +13929,7 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
cap &= ~DRV_FLAGS_CAPABILITIES_LOADED_FCOE;
SHMEM2_WR(bp, drv_capabilities_flag[idx], cap);
}
+ bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_GET_DRV_VERSION, 0);
break;
}
@@ -13887,6 +14035,9 @@ static int bnx2x_register_cnic(struct net_device *dev, struct cnic_ops *ops,
rcu_assign_pointer(bp->cnic_ops, ops);
+ /* Schedule driver to read CNIC driver versions */
+ bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_GET_DRV_VERSION, 0);
+
return 0;
}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
index 0fb6ff2ac8e3..31297266b743 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
@@ -2277,11 +2277,11 @@ static int bnx2x_set_rx_mode_e2(struct bnx2x *bp,
data->header.rule_cnt, p->rx_accept_flags,
p->tx_accept_flags);
- /* No need for an explicit memory barrier here as long we would
- * need to ensure the ordering of writing to the SPQ element
+ /* No need for an explicit memory barrier here as long as we
+ * ensure the ordering of writing to the SPQ element
* and updating of the SPQ producer which involves a memory
- * read and we will have to put a full memory barrier there
- * (inside bnx2x_sp_post()).
+ * read. If the memory read is removed we will have to put a
+ * full memory barrier there (inside bnx2x_sp_post()).
*/
/* Send a ramrod */
@@ -2982,11 +2982,11 @@ static int bnx2x_mcast_setup_e2(struct bnx2x *bp,
raw->clear_pending(raw);
return 0;
} else {
- /* No need for an explicit memory barrier here as long we would
- * need to ensure the ordering of writing to the SPQ element
+ /* No need for an explicit memory barrier here as long as we
+ * ensure the ordering of writing to the SPQ element
* and updating of the SPQ producer which involves a memory
- * read and we will have to put a full memory barrier there
- * (inside bnx2x_sp_post()).
+ * read. If the memory read is removed we will have to put a
+ * full memory barrier there (inside bnx2x_sp_post()).
*/
/* Send a ramrod */
@@ -3466,11 +3466,11 @@ static int bnx2x_mcast_setup_e1(struct bnx2x *bp,
raw->clear_pending(raw);
return 0;
} else {
- /* No need for an explicit memory barrier here as long we would
- * need to ensure the ordering of writing to the SPQ element
+ /* No need for an explicit memory barrier here as long as we
+ * ensure the ordering of writing to the SPQ element
* and updating of the SPQ producer which involves a memory
- * read and we will have to put a full memory barrier there
- * (inside bnx2x_sp_post()).
+ * read. If the memory read is removed we will have to put a
+ * full memory barrier there (inside bnx2x_sp_post()).
*/
/* Send a ramrod */
@@ -4091,11 +4091,11 @@ static int bnx2x_setup_rss(struct bnx2x *bp,
data->capabilities |= ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY;
}
- /* No need for an explicit memory barrier here as long we would
- * need to ensure the ordering of writing to the SPQ element
+ /* No need for an explicit memory barrier here as long as we
+ * ensure the ordering of writing to the SPQ element
* and updating of the SPQ producer which involves a memory
- * read and we will have to put a full memory barrier there
- * (inside bnx2x_sp_post()).
+ * read. If the memory read is removed we will have to put a
+ * full memory barrier there (inside bnx2x_sp_post()).
*/
/* Send a ramrod */
@@ -4158,16 +4158,6 @@ void bnx2x_init_rss_config_obj(struct bnx2x *bp,
rss_obj->config_rss = bnx2x_setup_rss;
}
-int validate_vlan_mac(struct bnx2x *bp,
- struct bnx2x_vlan_mac_obj *vlan_mac)
-{
- if (!vlan_mac->get_n_elements) {
- BNX2X_ERR("vlan mac object was not intialized\n");
- return -EINVAL;
- }
- return 0;
-}
-
/********************** Queue state object ***********************************/
/**
@@ -4587,13 +4577,12 @@ static inline int bnx2x_q_send_setup_e1x(struct bnx2x *bp,
/* Fill the ramrod data */
bnx2x_q_fill_setup_data_cmn(bp, params, rdata);
- /* No need for an explicit memory barrier here as long we would
- * need to ensure the ordering of writing to the SPQ element
+ /* No need for an explicit memory barrier here as long as we
+ * ensure the ordering of writing to the SPQ element
* and updating of the SPQ producer which involves a memory
- * read and we will have to put a full memory barrier there
- * (inside bnx2x_sp_post()).
+ * read. If the memory read is removed we will have to put a
+ * full memory barrier there (inside bnx2x_sp_post()).
*/
-
return bnx2x_sp_post(bp, ramrod, o->cids[BNX2X_PRIMARY_CID_INDEX],
U64_HI(data_mapping),
U64_LO(data_mapping), ETH_CONNECTION_TYPE);
@@ -4615,13 +4604,12 @@ static inline int bnx2x_q_send_setup_e2(struct bnx2x *bp,
bnx2x_q_fill_setup_data_cmn(bp, params, rdata);
bnx2x_q_fill_setup_data_e2(bp, params, rdata);
- /* No need for an explicit memory barrier here as long we would
- * need to ensure the ordering of writing to the SPQ element
+ /* No need for an explicit memory barrier here as long as we
+ * ensure the ordering of writing to the SPQ element
* and updating of the SPQ producer which involves a memory
- * read and we will have to put a full memory barrier there
- * (inside bnx2x_sp_post()).
+ * read. If the memory read is removed we will have to put a
+ * full memory barrier there (inside bnx2x_sp_post()).
*/
-
return bnx2x_sp_post(bp, ramrod, o->cids[BNX2X_PRIMARY_CID_INDEX],
U64_HI(data_mapping),
U64_LO(data_mapping), ETH_CONNECTION_TYPE);
@@ -4659,13 +4647,12 @@ static inline int bnx2x_q_send_setup_tx_only(struct bnx2x *bp,
o->cids[cid_index], rdata->general.client_id,
rdata->general.sp_client_id, rdata->general.cos);
- /* No need for an explicit memory barrier here as long we would
- * need to ensure the ordering of writing to the SPQ element
+ /* No need for an explicit memory barrier here as long as we
+ * ensure the ordering of writing to the SPQ element
* and updating of the SPQ producer which involves a memory
- * read and we will have to put a full memory barrier there
- * (inside bnx2x_sp_post()).
+ * read. If the memory read is removed we will have to put a
+ * full memory barrier there (inside bnx2x_sp_post()).
*/
-
return bnx2x_sp_post(bp, ramrod, o->cids[cid_index],
U64_HI(data_mapping),
U64_LO(data_mapping), ETH_CONNECTION_TYPE);
@@ -4760,13 +4747,12 @@ static inline int bnx2x_q_send_update(struct bnx2x *bp,
/* Fill the ramrod data */
bnx2x_q_fill_update_data(bp, o, update_params, rdata);
- /* No need for an explicit memory barrier here as long we would
- * need to ensure the ordering of writing to the SPQ element
+ /* No need for an explicit memory barrier here as long as we
+ * ensure the ordering of writing to the SPQ element
* and updating of the SPQ producer which involves a memory
- * read and we will have to put a full memory barrier there
- * (inside bnx2x_sp_post()).
+ * read. If the memory read is removed we will have to put a
+ * full memory barrier there (inside bnx2x_sp_post()).
*/
-
return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CLIENT_UPDATE,
o->cids[cid_index], U64_HI(data_mapping),
U64_LO(data_mapping), ETH_CONNECTION_TYPE);
@@ -4813,11 +4799,62 @@ static inline int bnx2x_q_send_activate(struct bnx2x *bp,
return bnx2x_q_send_update(bp, params);
}
+static void bnx2x_q_fill_update_tpa_data(struct bnx2x *bp,
+ struct bnx2x_queue_sp_obj *obj,
+ struct bnx2x_queue_update_tpa_params *params,
+ struct tpa_update_ramrod_data *data)
+{
+ data->client_id = obj->cl_id;
+ data->complete_on_both_clients = params->complete_on_both_clients;
+ data->dont_verify_rings_pause_thr_flg =
+ params->dont_verify_thr;
+ data->max_agg_size = cpu_to_le16(params->max_agg_sz);
+ data->max_sges_for_packet = params->max_sges_pkt;
+ data->max_tpa_queues = params->max_tpa_queues;
+ data->sge_buff_size = cpu_to_le16(params->sge_buff_sz);
+ data->sge_page_base_hi = cpu_to_le32(U64_HI(params->sge_map));
+ data->sge_page_base_lo = cpu_to_le32(U64_LO(params->sge_map));
+ data->sge_pause_thr_high = cpu_to_le16(params->sge_pause_thr_high);
+ data->sge_pause_thr_low = cpu_to_le16(params->sge_pause_thr_low);
+ data->tpa_mode = params->tpa_mode;
+ data->update_ipv4 = params->update_ipv4;
+ data->update_ipv6 = params->update_ipv6;
+}
+
static inline int bnx2x_q_send_update_tpa(struct bnx2x *bp,
struct bnx2x_queue_state_params *params)
{
- /* TODO: Not implemented yet. */
- return -1;
+ struct bnx2x_queue_sp_obj *o = params->q_obj;
+ struct tpa_update_ramrod_data *rdata =
+ (struct tpa_update_ramrod_data *)o->rdata;
+ dma_addr_t data_mapping = o->rdata_mapping;
+ struct bnx2x_queue_update_tpa_params *update_tpa_params =
+ &params->params.update_tpa;
+ u16 type;
+
+ /* Clear the ramrod data */
+ memset(rdata, 0, sizeof(*rdata));
+
+ /* Fill the ramrod data */
+ bnx2x_q_fill_update_tpa_data(bp, o, update_tpa_params, rdata);
+
+ /* Add the function id inside the type, so that sp post function
+ * doesn't automatically add the PF func-id, this is required
+ * for operations done by PFs on behalf of their VFs
+ */
+ type = ETH_CONNECTION_TYPE |
+ ((o->func_id) << SPE_HDR_FUNCTION_ID_SHIFT);
+
+ /* No need for an explicit memory barrier here as long as we
+ * ensure the ordering of writing to the SPQ element
+ * and updating of the SPQ producer which involves a memory
+ * read. If the memory read is removed we will have to put a
+ * full memory barrier there (inside bnx2x_sp_post()).
+ */
+ return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_TPA_UPDATE,
+ o->cids[BNX2X_PRIMARY_CID_INDEX],
+ U64_HI(data_mapping),
+ U64_LO(data_mapping), type);
}
static inline int bnx2x_q_send_halt(struct bnx2x *bp,
@@ -5647,6 +5684,12 @@ static inline int bnx2x_func_send_switch_update(struct bnx2x *bp,
rdata->tx_switch_suspend = switch_update_params->suspend;
rdata->echo = SWITCH_UPDATE;
+ /* No need for an explicit memory barrier here as long as we
+ * ensure the ordering of writing to the SPQ element
+ * and updating of the SPQ producer which involves a memory
+ * read. If the memory read is removed we will have to put a
+ * full memory barrier there (inside bnx2x_sp_post()).
+ */
return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_FUNCTION_UPDATE, 0,
U64_HI(data_mapping),
U64_LO(data_mapping), NONE_CONNECTION_TYPE);
@@ -5674,11 +5717,11 @@ static inline int bnx2x_func_send_afex_update(struct bnx2x *bp,
rdata->allowed_priorities = afex_update_params->allowed_priorities;
rdata->echo = AFEX_UPDATE;
- /* No need for an explicit memory barrier here as long we would
- * need to ensure the ordering of writing to the SPQ element
- * and updating of the SPQ producer which involves a memory
- * read and we will have to put a full memory barrier there
- * (inside bnx2x_sp_post()).
+ /* No need for an explicit memory barrier here as long as we
+ * ensure the ordering of writing to the SPQ element
+ * and updating of the SPQ producer which involves a memory
+ * read. If the memory read is removed we will have to put a
+ * full memory barrier there (inside bnx2x_sp_post()).
*/
DP(BNX2X_MSG_SP,
"afex: sending func_update vif_id 0x%x dvlan 0x%x prio 0x%x\n",
@@ -5763,6 +5806,12 @@ static inline int bnx2x_func_send_tx_start(struct bnx2x *bp,
rdata->traffic_type_to_priority_cos[i] =
tx_start_params->traffic_type_to_priority_cos[i];
+ /* No need for an explicit memory barrier here as long as we
+ * ensure the ordering of writing to the SPQ element
+ * and updating of the SPQ producer which involves a memory
+ * read. If the memory read is removed we will have to put a
+ * full memory barrier there (inside bnx2x_sp_post()).
+ */
return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_START_TRAFFIC, 0,
U64_HI(data_mapping),
U64_LO(data_mapping), NONE_CONNECTION_TYPE);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
index 00d7f214a40a..80f6c790ed88 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
@@ -893,6 +893,24 @@ struct bnx2x_queue_update_params {
u8 cid_index;
};
+struct bnx2x_queue_update_tpa_params {
+ dma_addr_t sge_map;
+ u8 update_ipv4;
+ u8 update_ipv6;
+ u8 max_tpa_queues;
+ u8 max_sges_pkt;
+ u8 complete_on_both_clients;
+ u8 dont_verify_thr;
+ u8 tpa_mode;
+ u8 _pad;
+
+ u16 sge_buff_sz;
+ u16 max_agg_sz;
+
+ u16 sge_pause_thr_low;
+ u16 sge_pause_thr_high;
+};
+
struct rxq_pause_params {
u16 bd_th_lo;
u16 bd_th_hi;
@@ -987,6 +1005,7 @@ struct bnx2x_queue_state_params {
/* Params according to the current command */
union {
struct bnx2x_queue_update_params update;
+ struct bnx2x_queue_update_tpa_params update_tpa;
struct bnx2x_queue_setup_params setup;
struct bnx2x_queue_init_params init;
struct bnx2x_queue_setup_tx_only_params tx_only;
@@ -1403,6 +1422,4 @@ int bnx2x_config_rss(struct bnx2x *bp,
void bnx2x_get_rss_ind_table(struct bnx2x_rss_config_obj *rss_obj,
u8 *ind_table);
-int validate_vlan_mac(struct bnx2x *bp,
- struct bnx2x_vlan_mac_obj *vlan_mac);
#endif /* BNX2X_SP_VERBS */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
index aec5ef2ed7ce..5c523b32db70 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
@@ -102,82 +102,22 @@ static void bnx2x_vf_igu_ack_sb(struct bnx2x *bp, struct bnx2x_virtf *vf,
mmiowb();
barrier();
}
-/* VFOP - VF slow-path operation support */
-#define BNX2X_VFOP_FILTER_ADD_CNT_MAX 0x10000
+static bool bnx2x_validate_vf_sp_objs(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ bool print_err)
+{
+ if (!bnx2x_leading_vfq(vf, sp_initialized)) {
+ if (print_err)
+ BNX2X_ERR("Slowpath objects not yet initialized!\n");
+ else
+ DP(BNX2X_MSG_IOV, "Slowpath objects not yet initialized!\n");
+ return false;
+ }
+ return true;
+}
/* VFOP operations states */
-enum bnx2x_vfop_qctor_state {
- BNX2X_VFOP_QCTOR_INIT,
- BNX2X_VFOP_QCTOR_SETUP,
- BNX2X_VFOP_QCTOR_INT_EN
-};
-
-enum bnx2x_vfop_qdtor_state {
- BNX2X_VFOP_QDTOR_HALT,
- BNX2X_VFOP_QDTOR_TERMINATE,
- BNX2X_VFOP_QDTOR_CFCDEL,
- BNX2X_VFOP_QDTOR_DONE
-};
-
-enum bnx2x_vfop_vlan_mac_state {
- BNX2X_VFOP_VLAN_MAC_CONFIG_SINGLE,
- BNX2X_VFOP_VLAN_MAC_CLEAR,
- BNX2X_VFOP_VLAN_MAC_CHK_DONE,
- BNX2X_VFOP_MAC_CONFIG_LIST,
- BNX2X_VFOP_VLAN_CONFIG_LIST,
- BNX2X_VFOP_VLAN_CONFIG_LIST_0
-};
-
-enum bnx2x_vfop_qsetup_state {
- BNX2X_VFOP_QSETUP_CTOR,
- BNX2X_VFOP_QSETUP_VLAN0,
- BNX2X_VFOP_QSETUP_DONE
-};
-
-enum bnx2x_vfop_mcast_state {
- BNX2X_VFOP_MCAST_DEL,
- BNX2X_VFOP_MCAST_ADD,
- BNX2X_VFOP_MCAST_CHK_DONE
-};
-enum bnx2x_vfop_qflr_state {
- BNX2X_VFOP_QFLR_CLR_VLAN,
- BNX2X_VFOP_QFLR_CLR_MAC,
- BNX2X_VFOP_QFLR_TERMINATE,
- BNX2X_VFOP_QFLR_DONE
-};
-
-enum bnx2x_vfop_flr_state {
- BNX2X_VFOP_FLR_QUEUES,
- BNX2X_VFOP_FLR_HW
-};
-
-enum bnx2x_vfop_close_state {
- BNX2X_VFOP_CLOSE_QUEUES,
- BNX2X_VFOP_CLOSE_HW
-};
-
-enum bnx2x_vfop_rxmode_state {
- BNX2X_VFOP_RXMODE_CONFIG,
- BNX2X_VFOP_RXMODE_DONE
-};
-
-enum bnx2x_vfop_qteardown_state {
- BNX2X_VFOP_QTEARDOWN_RXMODE,
- BNX2X_VFOP_QTEARDOWN_CLR_VLAN,
- BNX2X_VFOP_QTEARDOWN_CLR_MAC,
- BNX2X_VFOP_QTEARDOWN_CLR_MCAST,
- BNX2X_VFOP_QTEARDOWN_QDTOR,
- BNX2X_VFOP_QTEARDOWN_DONE
-};
-
-enum bnx2x_vfop_rss_state {
- BNX2X_VFOP_RSS_CONFIG,
- BNX2X_VFOP_RSS_DONE
-};
-
-#define bnx2x_vfop_reset_wq(vf) atomic_set(&vf->op_in_progress, 0)
-
void bnx2x_vfop_qctor_dump_tx(struct bnx2x *bp, struct bnx2x_virtf *vf,
struct bnx2x_queue_init_params *init_params,
struct bnx2x_queue_setup_params *setup_params,
@@ -221,7 +161,7 @@ void bnx2x_vfop_qctor_dump_rx(struct bnx2x *bp, struct bnx2x_virtf *vf,
void bnx2x_vfop_qctor_prep(struct bnx2x *bp,
struct bnx2x_virtf *vf,
struct bnx2x_vf_queue *q,
- struct bnx2x_vfop_qctor_params *p,
+ struct bnx2x_vf_queue_construct_params *p,
unsigned long q_type)
{
struct bnx2x_queue_init_params *init_p = &p->qstate.params.init;
@@ -290,191 +230,85 @@ void bnx2x_vfop_qctor_prep(struct bnx2x *bp,
}
}
-/* VFOP queue construction */
-static void bnx2x_vfop_qctor(struct bnx2x *bp, struct bnx2x_virtf *vf)
+static int bnx2x_vf_queue_create(struct bnx2x *bp,
+ struct bnx2x_virtf *vf, int qid,
+ struct bnx2x_vf_queue_construct_params *qctor)
{
- struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
- struct bnx2x_vfop_args_qctor *args = &vfop->args.qctor;
- struct bnx2x_queue_state_params *q_params = &vfop->op_p->qctor.qstate;
- enum bnx2x_vfop_qctor_state state = vfop->state;
-
- bnx2x_vfop_reset_wq(vf);
-
- if (vfop->rc < 0)
- goto op_err;
-
- DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
-
- switch (state) {
- case BNX2X_VFOP_QCTOR_INIT:
-
- /* has this queue already been opened? */
- if (bnx2x_get_q_logical_state(bp, q_params->q_obj) ==
- BNX2X_Q_LOGICAL_STATE_ACTIVE) {
- DP(BNX2X_MSG_IOV,
- "Entered qctor but queue was already up. Aborting gracefully\n");
- goto op_done;
- }
-
- /* next state */
- vfop->state = BNX2X_VFOP_QCTOR_SETUP;
-
- q_params->cmd = BNX2X_Q_CMD_INIT;
- vfop->rc = bnx2x_queue_state_change(bp, q_params);
-
- bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
-
- case BNX2X_VFOP_QCTOR_SETUP:
- /* next state */
- vfop->state = BNX2X_VFOP_QCTOR_INT_EN;
-
- /* copy pre-prepared setup params to the queue-state params */
- vfop->op_p->qctor.qstate.params.setup =
- vfop->op_p->qctor.prep_qsetup;
-
- q_params->cmd = BNX2X_Q_CMD_SETUP;
- vfop->rc = bnx2x_queue_state_change(bp, q_params);
+ struct bnx2x_queue_state_params *q_params;
+ int rc = 0;
- bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+ DP(BNX2X_MSG_IOV, "vf[%d:%d]\n", vf->abs_vfid, qid);
- case BNX2X_VFOP_QCTOR_INT_EN:
+ /* Prepare ramrod information */
+ q_params = &qctor->qstate;
+ q_params->q_obj = &bnx2x_vfq(vf, qid, sp_obj);
+ set_bit(RAMROD_COMP_WAIT, &q_params->ramrod_flags);
- /* enable interrupts */
- bnx2x_vf_igu_ack_sb(bp, vf, vf_igu_sb(vf, args->sb_idx),
- USTORM_ID, 0, IGU_INT_ENABLE, 0);
- goto op_done;
- default:
- bnx2x_vfop_default(state);
+ if (bnx2x_get_q_logical_state(bp, q_params->q_obj) ==
+ BNX2X_Q_LOGICAL_STATE_ACTIVE) {
+ DP(BNX2X_MSG_IOV, "queue was already up. Aborting gracefully\n");
+ goto out;
}
-op_err:
- BNX2X_ERR("QCTOR[%d:%d] error: cmd %d, rc %d\n",
- vf->abs_vfid, args->qid, q_params->cmd, vfop->rc);
-op_done:
- bnx2x_vfop_end(bp, vf, vfop);
-op_pending:
- return;
-}
-static int bnx2x_vfop_qctor_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd,
- int qid)
-{
- struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
-
- if (vfop) {
- vf->op_params.qctor.qstate.q_obj = &bnx2x_vfq(vf, qid, sp_obj);
+ /* Run Queue 'construction' ramrods */
+ q_params->cmd = BNX2X_Q_CMD_INIT;
+ rc = bnx2x_queue_state_change(bp, q_params);
+ if (rc)
+ goto out;
- vfop->args.qctor.qid = qid;
- vfop->args.qctor.sb_idx = bnx2x_vfq(vf, qid, sb_idx);
+ memcpy(&q_params->params.setup, &qctor->prep_qsetup,
+ sizeof(struct bnx2x_queue_setup_params));
+ q_params->cmd = BNX2X_Q_CMD_SETUP;
+ rc = bnx2x_queue_state_change(bp, q_params);
+ if (rc)
+ goto out;
- bnx2x_vfop_opset(BNX2X_VFOP_QCTOR_INIT,
- bnx2x_vfop_qctor, cmd->done);
- return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qctor,
- cmd->block);
- }
- return -ENOMEM;
+ /* enable interrupts */
+ bnx2x_vf_igu_ack_sb(bp, vf, vf_igu_sb(vf, bnx2x_vfq(vf, qid, sb_idx)),
+ USTORM_ID, 0, IGU_INT_ENABLE, 0);
+out:
+ return rc;
}
-/* VFOP queue destruction */
-static void bnx2x_vfop_qdtor(struct bnx2x *bp, struct bnx2x_virtf *vf)
+static int bnx2x_vf_queue_destroy(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ int qid)
{
- struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
- struct bnx2x_vfop_args_qdtor *qdtor = &vfop->args.qdtor;
- struct bnx2x_queue_state_params *q_params = &vfop->op_p->qctor.qstate;
- enum bnx2x_vfop_qdtor_state state = vfop->state;
-
- bnx2x_vfop_reset_wq(vf);
-
- if (vfop->rc < 0)
- goto op_err;
-
- DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
-
- switch (state) {
- case BNX2X_VFOP_QDTOR_HALT:
-
- /* has this queue already been stopped? */
- if (bnx2x_get_q_logical_state(bp, q_params->q_obj) ==
- BNX2X_Q_LOGICAL_STATE_STOPPED) {
- DP(BNX2X_MSG_IOV,
- "Entered qdtor but queue was already stopped. Aborting gracefully\n");
-
- /* next state */
- vfop->state = BNX2X_VFOP_QDTOR_DONE;
-
- bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
- }
-
- /* next state */
- vfop->state = BNX2X_VFOP_QDTOR_TERMINATE;
-
- q_params->cmd = BNX2X_Q_CMD_HALT;
- vfop->rc = bnx2x_queue_state_change(bp, q_params);
-
- bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
-
- case BNX2X_VFOP_QDTOR_TERMINATE:
- /* next state */
- vfop->state = BNX2X_VFOP_QDTOR_CFCDEL;
-
- q_params->cmd = BNX2X_Q_CMD_TERMINATE;
- vfop->rc = bnx2x_queue_state_change(bp, q_params);
+ enum bnx2x_queue_cmd cmds[] = {BNX2X_Q_CMD_HALT,
+ BNX2X_Q_CMD_TERMINATE,
+ BNX2X_Q_CMD_CFC_DEL};
+ struct bnx2x_queue_state_params q_params;
+ int rc, i;
- bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+ DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
- case BNX2X_VFOP_QDTOR_CFCDEL:
- /* next state */
- vfop->state = BNX2X_VFOP_QDTOR_DONE;
+ /* Prepare ramrod information */
+ memset(&q_params, 0, sizeof(struct bnx2x_queue_state_params));
+ q_params.q_obj = &bnx2x_vfq(vf, qid, sp_obj);
+ set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags);
- q_params->cmd = BNX2X_Q_CMD_CFC_DEL;
- vfop->rc = bnx2x_queue_state_change(bp, q_params);
+ if (bnx2x_get_q_logical_state(bp, q_params.q_obj) ==
+ BNX2X_Q_LOGICAL_STATE_STOPPED) {
+ DP(BNX2X_MSG_IOV, "queue was already stopped. Aborting gracefully\n");
+ goto out;
+ }
- bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
-op_err:
- BNX2X_ERR("QDTOR[%d:%d] error: cmd %d, rc %d\n",
- vf->abs_vfid, qdtor->qid, q_params->cmd, vfop->rc);
-op_done:
- case BNX2X_VFOP_QDTOR_DONE:
- /* invalidate the context */
- if (qdtor->cxt) {
- qdtor->cxt->ustorm_ag_context.cdu_usage = 0;
- qdtor->cxt->xstorm_ag_context.cdu_reserved = 0;
+ /* Run Queue 'destruction' ramrods */
+ for (i = 0; i < ARRAY_SIZE(cmds); i++) {
+ q_params.cmd = cmds[i];
+ rc = bnx2x_queue_state_change(bp, &q_params);
+ if (rc) {
+ BNX2X_ERR("Failed to run Queue command %d\n", cmds[i]);
+ return rc;
}
- bnx2x_vfop_end(bp, vf, vfop);
- return;
- default:
- bnx2x_vfop_default(state);
}
-op_pending:
- return;
-}
-
-static int bnx2x_vfop_qdtor_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd,
- int qid)
-{
- struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
-
- if (vfop) {
- struct bnx2x_queue_state_params *qstate =
- &vf->op_params.qctor.qstate;
-
- memset(qstate, 0, sizeof(*qstate));
- qstate->q_obj = &bnx2x_vfq(vf, qid, sp_obj);
-
- vfop->args.qdtor.qid = qid;
- vfop->args.qdtor.cxt = bnx2x_vfq(vf, qid, cxt);
-
- bnx2x_vfop_opset(BNX2X_VFOP_QDTOR_HALT,
- bnx2x_vfop_qdtor, cmd->done);
- return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qdtor,
- cmd->block);
- } else {
- BNX2X_ERR("VF[%d] failed to add a vfop\n", vf->abs_vfid);
- return -ENOMEM;
+out:
+ /* Clean Context */
+ if (bnx2x_vfq(vf, qid, cxt)) {
+ bnx2x_vfq(vf, qid, cxt)->ustorm_ag_context.cdu_usage = 0;
+ bnx2x_vfq(vf, qid, cxt)->xstorm_ag_context.cdu_reserved = 0;
}
+
+ return 0;
}
static void
@@ -496,751 +330,293 @@ bnx2x_vf_set_igu_info(struct bnx2x *bp, u8 igu_sb_id, u8 abs_vfid)
BP_VFDB(bp)->vf_sbs_pool++;
}
-/* VFOP MAC/VLAN helpers */
-static inline void bnx2x_vfop_credit(struct bnx2x *bp,
- struct bnx2x_vfop *vfop,
- struct bnx2x_vlan_mac_obj *obj)
+static inline void bnx2x_vf_vlan_credit(struct bnx2x *bp,
+ struct bnx2x_vlan_mac_obj *obj,
+ atomic_t *counter)
{
- struct bnx2x_vfop_args_filters *args = &vfop->args.filters;
-
- /* update credit only if there is no error
- * and a valid credit counter
- */
- if (!vfop->rc && args->credit) {
- struct list_head *pos;
- int read_lock;
- int cnt = 0;
-
- read_lock = bnx2x_vlan_mac_h_read_lock(bp, obj);
- if (read_lock)
- DP(BNX2X_MSG_SP, "Failed to take vlan mac read head; continuing anyway\n");
+ struct list_head *pos;
+ int read_lock;
+ int cnt = 0;
- list_for_each(pos, &obj->head)
- cnt++;
+ read_lock = bnx2x_vlan_mac_h_read_lock(bp, obj);
+ if (read_lock)
+ DP(BNX2X_MSG_SP, "Failed to take vlan mac read head; continuing anyway\n");
- if (!read_lock)
- bnx2x_vlan_mac_h_read_unlock(bp, obj);
+ list_for_each(pos, &obj->head)
+ cnt++;
- atomic_set(args->credit, cnt);
- }
-}
-
-static int bnx2x_vfop_set_user_req(struct bnx2x *bp,
- struct bnx2x_vfop_filter *pos,
- struct bnx2x_vlan_mac_data *user_req)
-{
- user_req->cmd = pos->add ? BNX2X_VLAN_MAC_ADD :
- BNX2X_VLAN_MAC_DEL;
+ if (!read_lock)
+ bnx2x_vlan_mac_h_read_unlock(bp, obj);
- switch (pos->type) {
- case BNX2X_VFOP_FILTER_MAC:
- memcpy(user_req->u.mac.mac, pos->mac, ETH_ALEN);
- break;
- case BNX2X_VFOP_FILTER_VLAN:
- user_req->u.vlan.vlan = pos->vid;
- break;
- default:
- BNX2X_ERR("Invalid filter type, skipping\n");
- return 1;
- }
- return 0;
+ atomic_set(counter, cnt);
}
-static int bnx2x_vfop_config_list(struct bnx2x *bp,
- struct bnx2x_vfop_filters *filters,
- struct bnx2x_vlan_mac_ramrod_params *vlan_mac)
+static int bnx2x_vf_vlan_mac_clear(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ int qid, bool drv_only, bool mac)
{
- struct bnx2x_vfop_filter *pos, *tmp;
- struct list_head rollback_list, *filters_list = &filters->head;
- struct bnx2x_vlan_mac_data *user_req = &vlan_mac->user_req;
- int rc = 0, cnt = 0;
-
- INIT_LIST_HEAD(&rollback_list);
-
- list_for_each_entry_safe(pos, tmp, filters_list, link) {
- if (bnx2x_vfop_set_user_req(bp, pos, user_req))
- continue;
+ struct bnx2x_vlan_mac_ramrod_params ramrod;
+ int rc;
- rc = bnx2x_config_vlan_mac(bp, vlan_mac);
- if (rc >= 0) {
- cnt += pos->add ? 1 : -1;
- list_move(&pos->link, &rollback_list);
- rc = 0;
- } else if (rc == -EEXIST) {
- rc = 0;
- } else {
- BNX2X_ERR("Failed to add a new vlan_mac command\n");
- break;
- }
- }
+ DP(BNX2X_MSG_IOV, "vf[%d] - deleting all %s\n", vf->abs_vfid,
+ mac ? "MACs" : "VLANs");
- /* rollback if error or too many rules added */
- if (rc || cnt > filters->add_cnt) {
- BNX2X_ERR("error or too many rules added. Performing rollback\n");
- list_for_each_entry_safe(pos, tmp, &rollback_list, link) {
- pos->add = !pos->add; /* reverse op */
- bnx2x_vfop_set_user_req(bp, pos, user_req);
- bnx2x_config_vlan_mac(bp, vlan_mac);
- list_del(&pos->link);
- }
- cnt = 0;
- if (!rc)
- rc = -EINVAL;
+ /* Prepare ramrod params */
+ memset(&ramrod, 0, sizeof(struct bnx2x_vlan_mac_ramrod_params));
+ if (mac) {
+ set_bit(BNX2X_ETH_MAC, &ramrod.user_req.vlan_mac_flags);
+ ramrod.vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj);
+ } else {
+ set_bit(BNX2X_DONT_CONSUME_CAM_CREDIT,
+ &ramrod.user_req.vlan_mac_flags);
+ ramrod.vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
}
- filters->add_cnt = cnt;
- return rc;
-}
-
-/* VFOP set VLAN/MAC */
-static void bnx2x_vfop_vlan_mac(struct bnx2x *bp, struct bnx2x_virtf *vf)
-{
- struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
- struct bnx2x_vlan_mac_ramrod_params *vlan_mac = &vfop->op_p->vlan_mac;
- struct bnx2x_vlan_mac_obj *obj = vlan_mac->vlan_mac_obj;
- struct bnx2x_vfop_filters *filters = vfop->args.filters.multi_filter;
-
- enum bnx2x_vfop_vlan_mac_state state = vfop->state;
-
- if (vfop->rc < 0)
- goto op_err;
-
- DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
-
- bnx2x_vfop_reset_wq(vf);
-
- switch (state) {
- case BNX2X_VFOP_VLAN_MAC_CLEAR:
- /* next state */
- vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
-
- /* do delete */
- vfop->rc = obj->delete_all(bp, obj,
- &vlan_mac->user_req.vlan_mac_flags,
- &vlan_mac->ramrod_flags);
-
- bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
-
- case BNX2X_VFOP_VLAN_MAC_CONFIG_SINGLE:
- /* next state */
- vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
-
- /* do config */
- vfop->rc = bnx2x_config_vlan_mac(bp, vlan_mac);
- if (vfop->rc == -EEXIST)
- vfop->rc = 0;
+ ramrod.user_req.cmd = BNX2X_VLAN_MAC_DEL;
- bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
-
- case BNX2X_VFOP_VLAN_MAC_CHK_DONE:
- vfop->rc = !!obj->raw.check_pending(&obj->raw);
- bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
-
- case BNX2X_VFOP_MAC_CONFIG_LIST:
- /* next state */
- vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
-
- /* do list config */
- vfop->rc = bnx2x_vfop_config_list(bp, filters, vlan_mac);
- if (vfop->rc)
- goto op_err;
-
- 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);
-
- case BNX2X_VFOP_VLAN_CONFIG_LIST:
- /* next state */
- vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
-
- /* 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);
+ set_bit(RAMROD_EXEC, &ramrod.ramrod_flags);
+ if (drv_only)
+ set_bit(RAMROD_DRV_CLR_ONLY, &ramrod.ramrod_flags);
+ else
+ set_bit(RAMROD_COMP_WAIT, &ramrod.ramrod_flags);
- default:
- bnx2x_vfop_default(state);
+ /* Start deleting */
+ rc = ramrod.vlan_mac_obj->delete_all(bp,
+ ramrod.vlan_mac_obj,
+ &ramrod.user_req.vlan_mac_flags,
+ &ramrod.ramrod_flags);
+ if (rc) {
+ BNX2X_ERR("Failed to delete all %s\n",
+ mac ? "MACs" : "VLANs");
+ return rc;
}
-op_err:
- BNX2X_ERR("VLAN-MAC error: rc %d\n", vfop->rc);
-op_done:
- kfree(filters);
- bnx2x_vfop_credit(bp, vfop, obj);
- bnx2x_vfop_end(bp, vf, vfop);
-op_pending:
- return;
-}
-
-struct bnx2x_vfop_vlan_mac_flags {
- bool drv_only;
- bool dont_consume;
- bool single_cmd;
- bool add;
-};
-
-static void
-bnx2x_vfop_vlan_mac_prep_ramrod(struct bnx2x_vlan_mac_ramrod_params *ramrod,
- struct bnx2x_vfop_vlan_mac_flags *flags)
-{
- struct bnx2x_vlan_mac_data *ureq = &ramrod->user_req;
-
- memset(ramrod, 0, sizeof(*ramrod));
- /* ramrod flags */
- if (flags->drv_only)
- set_bit(RAMROD_DRV_CLR_ONLY, &ramrod->ramrod_flags);
- if (flags->single_cmd)
- set_bit(RAMROD_EXEC, &ramrod->ramrod_flags);
+ /* Clear the vlan counters */
+ if (!mac)
+ atomic_set(&bnx2x_vfq(vf, qid, vlan_count), 0);
- /* mac_vlan flags */
- if (flags->dont_consume)
- set_bit(BNX2X_DONT_CONSUME_CAM_CREDIT, &ureq->vlan_mac_flags);
-
- /* cmd */
- ureq->cmd = flags->add ? BNX2X_VLAN_MAC_ADD : BNX2X_VLAN_MAC_DEL;
-}
-
-static inline void
-bnx2x_vfop_mac_prep_ramrod(struct bnx2x_vlan_mac_ramrod_params *ramrod,
- struct bnx2x_vfop_vlan_mac_flags *flags)
-{
- bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, flags);
- set_bit(BNX2X_ETH_MAC, &ramrod->user_req.vlan_mac_flags);
+ return 0;
}
-static int bnx2x_vfop_mac_delall_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd,
- int qid, bool drv_only)
+static int bnx2x_vf_mac_vlan_config(struct bnx2x *bp,
+ struct bnx2x_virtf *vf, int qid,
+ struct bnx2x_vf_mac_vlan_filter *filter,
+ bool drv_only)
{
- struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+ struct bnx2x_vlan_mac_ramrod_params ramrod;
int rc;
- if (vfop) {
- struct bnx2x_vfop_args_filters filters = {
- .multi_filter = NULL, /* single */
- .credit = NULL, /* consume credit */
- };
- struct bnx2x_vfop_vlan_mac_flags flags = {
- .drv_only = drv_only,
- .dont_consume = (filters.credit != NULL),
- .single_cmd = true,
- .add = false /* don't care */,
- };
- struct bnx2x_vlan_mac_ramrod_params *ramrod =
- &vf->op_params.vlan_mac;
-
- /* set ramrod params */
- bnx2x_vfop_mac_prep_ramrod(ramrod, &flags);
-
- /* set object */
- rc = validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, mac_obj));
- if (rc)
- return rc;
- ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj);
-
- /* set extra args */
- vfop->args.filters = filters;
-
- bnx2x_vfop_opset(BNX2X_VFOP_VLAN_MAC_CLEAR,
- bnx2x_vfop_vlan_mac, cmd->done);
- return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
- cmd->block);
+ DP(BNX2X_MSG_IOV, "vf[%d] - %s a %s filter\n",
+ vf->abs_vfid, filter->add ? "Adding" : "Deleting",
+ filter->type == BNX2X_VF_FILTER_MAC ? "MAC" : "VLAN");
+
+ /* Prepare ramrod params */
+ memset(&ramrod, 0, sizeof(struct bnx2x_vlan_mac_ramrod_params));
+ if (filter->type == BNX2X_VF_FILTER_VLAN) {
+ set_bit(BNX2X_DONT_CONSUME_CAM_CREDIT,
+ &ramrod.user_req.vlan_mac_flags);
+ ramrod.vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
+ ramrod.user_req.u.vlan.vlan = filter->vid;
+ } else {
+ set_bit(BNX2X_ETH_MAC, &ramrod.user_req.vlan_mac_flags);
+ ramrod.vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj);
+ memcpy(&ramrod.user_req.u.mac.mac, filter->mac, ETH_ALEN);
+ }
+ ramrod.user_req.cmd = filter->add ? BNX2X_VLAN_MAC_ADD :
+ BNX2X_VLAN_MAC_DEL;
+
+ /* Verify there are available vlan credits */
+ if (filter->add && filter->type == BNX2X_VF_FILTER_VLAN &&
+ (atomic_read(&bnx2x_vfq(vf, qid, vlan_count)) >=
+ vf_vlan_rules_cnt(vf))) {
+ BNX2X_ERR("No credits for vlan\n");
+ return -ENOMEM;
}
- return -ENOMEM;
-}
-
-int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd,
- struct bnx2x_vfop_filters *macs,
- int qid, bool drv_only)
-{
- struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
- int rc;
- if (vfop) {
- struct bnx2x_vfop_args_filters filters = {
- .multi_filter = macs,
- .credit = NULL, /* consume credit */
- };
- struct bnx2x_vfop_vlan_mac_flags flags = {
- .drv_only = drv_only,
- .dont_consume = (filters.credit != NULL),
- .single_cmd = false,
- .add = false, /* don't care since only the items in the
- * filters list affect the sp operation,
- * not the list itself
- */
- };
- struct bnx2x_vlan_mac_ramrod_params *ramrod =
- &vf->op_params.vlan_mac;
-
- /* set ramrod params */
- bnx2x_vfop_mac_prep_ramrod(ramrod, &flags);
-
- /* set object */
- rc = validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, mac_obj));
- if (rc)
- return rc;
- ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj);
+ set_bit(RAMROD_EXEC, &ramrod.ramrod_flags);
+ if (drv_only)
+ set_bit(RAMROD_DRV_CLR_ONLY, &ramrod.ramrod_flags);
+ else
+ set_bit(RAMROD_COMP_WAIT, &ramrod.ramrod_flags);
+
+ /* Add/Remove the filter */
+ rc = bnx2x_config_vlan_mac(bp, &ramrod);
+ if (rc && rc != -EEXIST) {
+ BNX2X_ERR("Failed to %s %s\n",
+ filter->add ? "add" : "delete",
+ filter->type == BNX2X_VF_FILTER_MAC ? "MAC" :
+ "VLAN");
+ return rc;
+ }
- /* set extra args */
- filters.multi_filter->add_cnt = BNX2X_VFOP_FILTER_ADD_CNT_MAX;
- vfop->args.filters = filters;
+ /* Update the vlan counters */
+ if (filter->type == BNX2X_VF_FILTER_VLAN)
+ bnx2x_vf_vlan_credit(bp, ramrod.vlan_mac_obj,
+ &bnx2x_vfq(vf, qid, vlan_count));
- bnx2x_vfop_opset(BNX2X_VFOP_MAC_CONFIG_LIST,
- bnx2x_vfop_vlan_mac, cmd->done);
- return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
- cmd->block);
- }
- return -ENOMEM;
+ return 0;
}
-static int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd,
- int qid, u16 vid, bool add)
+int bnx2x_vf_mac_vlan_config_list(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct bnx2x_vf_mac_vlan_filters *filters,
+ int qid, bool drv_only)
{
- struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
- int rc;
+ int rc = 0, i;
- if (vfop) {
- struct bnx2x_vfop_args_filters filters = {
- .multi_filter = NULL, /* single command */
- .credit = &bnx2x_vfq(vf, qid, vlan_count),
- };
- struct bnx2x_vfop_vlan_mac_flags flags = {
- .drv_only = false,
- .dont_consume = (filters.credit != NULL),
- .single_cmd = true,
- .add = add,
- };
- struct bnx2x_vlan_mac_ramrod_params *ramrod =
- &vf->op_params.vlan_mac;
-
- /* set ramrod params */
- bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, &flags);
- ramrod->user_req.u.vlan.vlan = vid;
-
- /* set object */
- rc = validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, vlan_obj));
- if (rc)
- return rc;
- ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
+ DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
- /* set extra args */
- vfop->args.filters = filters;
+ if (!bnx2x_validate_vf_sp_objs(bp, vf, true))
+ return -EINVAL;
- bnx2x_vfop_opset(BNX2X_VFOP_VLAN_MAC_CONFIG_SINGLE,
- bnx2x_vfop_vlan_mac, cmd->done);
- return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
- cmd->block);
+ /* Prepare ramrod params */
+ for (i = 0; i < filters->count; i++) {
+ rc = bnx2x_vf_mac_vlan_config(bp, vf, qid,
+ &filters->filters[i], drv_only);
+ if (rc)
+ break;
}
- return -ENOMEM;
-}
-
-static int bnx2x_vfop_vlan_delall_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd,
- int qid, bool drv_only)
-{
- struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
- int rc;
- if (vfop) {
- struct bnx2x_vfop_args_filters filters = {
- .multi_filter = NULL, /* single command */
- .credit = &bnx2x_vfq(vf, qid, vlan_count),
- };
- struct bnx2x_vfop_vlan_mac_flags flags = {
- .drv_only = drv_only,
- .dont_consume = (filters.credit != NULL),
- .single_cmd = true,
- .add = false, /* don't care */
- };
- struct bnx2x_vlan_mac_ramrod_params *ramrod =
- &vf->op_params.vlan_mac;
-
- /* set ramrod params */
- bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, &flags);
-
- /* set object */
- rc = validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, vlan_obj));
- if (rc)
- return rc;
- ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
+ /* Rollback if needed */
+ if (i != filters->count) {
+ BNX2X_ERR("Managed only %d/%d filters - rolling back\n",
+ i, filters->count + 1);
+ while (--i >= 0) {
+ filters->filters[i].add = !filters->filters[i].add;
+ bnx2x_vf_mac_vlan_config(bp, vf, qid,
+ &filters->filters[i],
+ drv_only);
+ }
+ }
- /* set extra args */
- vfop->args.filters = filters;
+ /* It's our responsibility to free the filters */
+ kfree(filters);
- bnx2x_vfop_opset(BNX2X_VFOP_VLAN_MAC_CLEAR,
- bnx2x_vfop_vlan_mac, cmd->done);
- return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
- cmd->block);
- }
- return -ENOMEM;
+ return rc;
}
-int bnx2x_vfop_vlan_list_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd,
- struct bnx2x_vfop_filters *vlans,
- int qid, bool drv_only)
+int bnx2x_vf_queue_setup(struct bnx2x *bp, struct bnx2x_virtf *vf, int qid,
+ struct bnx2x_vf_queue_construct_params *qctor)
{
- struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
int rc;
- if (vfop) {
- struct bnx2x_vfop_args_filters filters = {
- .multi_filter = vlans,
- .credit = &bnx2x_vfq(vf, qid, vlan_count),
- };
- struct bnx2x_vfop_vlan_mac_flags flags = {
- .drv_only = drv_only,
- .dont_consume = (filters.credit != NULL),
- .single_cmd = false,
- .add = false, /* don't care */
- };
- struct bnx2x_vlan_mac_ramrod_params *ramrod =
- &vf->op_params.vlan_mac;
-
- /* set ramrod params */
- bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, &flags);
-
- /* set object */
- rc = validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, vlan_obj));
- if (rc)
- return rc;
- ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
-
- /* set extra args */
- filters.multi_filter->add_cnt = vf_vlan_rules_cnt(vf) -
- atomic_read(filters.credit);
-
- vfop->args.filters = filters;
+ DP(BNX2X_MSG_IOV, "vf[%d:%d]\n", vf->abs_vfid, qid);
- bnx2x_vfop_opset(BNX2X_VFOP_VLAN_CONFIG_LIST,
- bnx2x_vfop_vlan_mac, cmd->done);
- return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
- cmd->block);
- }
- return -ENOMEM;
-}
-
-/* VFOP queue setup (queue constructor + set vlan 0) */
-static void bnx2x_vfop_qsetup(struct bnx2x *bp, struct bnx2x_virtf *vf)
-{
- struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
- int qid = vfop->args.qctor.qid;
- enum bnx2x_vfop_qsetup_state state = vfop->state;
- struct bnx2x_vfop_cmd cmd = {
- .done = bnx2x_vfop_qsetup,
- .block = false,
- };
-
- if (vfop->rc < 0)
+ rc = bnx2x_vf_queue_create(bp, vf, qid, qctor);
+ if (rc)
goto op_err;
- DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+ /* Configure vlan0 for leading queue */
+ if (!qid) {
+ struct bnx2x_vf_mac_vlan_filter filter;
- switch (state) {
- case BNX2X_VFOP_QSETUP_CTOR:
- /* init the queue ctor command */
- vfop->state = BNX2X_VFOP_QSETUP_VLAN0;
- vfop->rc = bnx2x_vfop_qctor_cmd(bp, vf, &cmd, qid);
- if (vfop->rc)
+ memset(&filter, 0, sizeof(struct bnx2x_vf_mac_vlan_filter));
+ filter.type = BNX2X_VF_FILTER_VLAN;
+ filter.add = true;
+ filter.vid = 0;
+ rc = bnx2x_vf_mac_vlan_config(bp, vf, qid, &filter, false);
+ if (rc)
goto op_err;
- return;
-
- case BNX2X_VFOP_QSETUP_VLAN0:
- /* skip if non-leading or FPGA/EMU*/
- if (qid)
- goto op_done;
+ }
- /* init the queue set-vlan command (for vlan 0) */
- vfop->state = BNX2X_VFOP_QSETUP_DONE;
- vfop->rc = bnx2x_vfop_vlan_set_cmd(bp, vf, &cmd, qid, 0, true);
- if (vfop->rc)
- goto op_err;
- return;
+ /* Schedule the configuration of any pending vlan filters */
+ vf->cfg_flags |= VF_CFG_VLAN;
+ bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_HYPERVISOR_VLAN,
+ BNX2X_MSG_IOV);
+ return 0;
op_err:
- BNX2X_ERR("QSETUP[%d:%d] error: rc %d\n", vf->abs_vfid, qid, vfop->rc);
-op_done:
- case BNX2X_VFOP_QSETUP_DONE:
- vf->cfg_flags |= VF_CFG_VLAN;
- smp_mb__before_clear_bit();
- set_bit(BNX2X_SP_RTNL_HYPERVISOR_VLAN,
- &bp->sp_rtnl_state);
- smp_mb__after_clear_bit();
- schedule_delayed_work(&bp->sp_rtnl_task, 0);
- bnx2x_vfop_end(bp, vf, vfop);
- return;
- default:
- bnx2x_vfop_default(state);
- }
+ BNX2X_ERR("QSETUP[%d:%d] error: rc %d\n", vf->abs_vfid, qid, rc);
+ return rc;
}
-int bnx2x_vfop_qsetup_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd,
- int qid)
+static int bnx2x_vf_queue_flr(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ int qid)
{
- struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+ int rc;
- if (vfop) {
- vfop->args.qctor.qid = qid;
+ DP(BNX2X_MSG_IOV, "vf[%d:%d]\n", vf->abs_vfid, qid);
- bnx2x_vfop_opset(BNX2X_VFOP_QSETUP_CTOR,
- bnx2x_vfop_qsetup, cmd->done);
- return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qsetup,
- cmd->block);
+ /* If needed, clean the filtering data base */
+ if ((qid == LEADING_IDX) &&
+ bnx2x_validate_vf_sp_objs(bp, vf, false)) {
+ rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid, true, false);
+ if (rc)
+ goto op_err;
+ rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid, true, true);
+ if (rc)
+ goto op_err;
}
- return -ENOMEM;
-}
-
-/* VFOP queue FLR handling (clear vlans, clear macs, queue destructor) */
-static void bnx2x_vfop_qflr(struct bnx2x *bp, struct bnx2x_virtf *vf)
-{
- struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
- int qid = vfop->args.qx.qid;
- enum bnx2x_vfop_qflr_state state = vfop->state;
- struct bnx2x_queue_state_params *qstate;
- struct bnx2x_vfop_cmd cmd;
-
- bnx2x_vfop_reset_wq(vf);
-
- if (vfop->rc < 0)
- goto op_err;
- DP(BNX2X_MSG_IOV, "VF[%d] STATE: %d\n", vf->abs_vfid, state);
+ /* Terminate queue */
+ if (bnx2x_vfq(vf, qid, sp_obj).state != BNX2X_Q_STATE_RESET) {
+ struct bnx2x_queue_state_params qstate;
- cmd.done = bnx2x_vfop_qflr;
- cmd.block = false;
-
- switch (state) {
- case BNX2X_VFOP_QFLR_CLR_VLAN:
- /* vlan-clear-all: driver-only, don't consume credit */
- vfop->state = BNX2X_VFOP_QFLR_CLR_MAC;
-
- if (!validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, vlan_obj))) {
- /* the vlan_mac vfop will re-schedule us */
- vfop->rc = bnx2x_vfop_vlan_delall_cmd(bp, vf, &cmd,
- qid, true);
- if (vfop->rc)
- goto op_err;
- return;
-
- } else {
- /* need to reschedule ourselves */
- bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
- }
-
- case BNX2X_VFOP_QFLR_CLR_MAC:
- /* mac-clear-all: driver only consume credit */
- vfop->state = BNX2X_VFOP_QFLR_TERMINATE;
- if (!validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, mac_obj))) {
- /* the vlan_mac vfop will re-schedule us */
- vfop->rc = bnx2x_vfop_mac_delall_cmd(bp, vf, &cmd,
- qid, true);
- if (vfop->rc)
- goto op_err;
- return;
-
- } else {
- /* need to reschedule ourselves */
- bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
- }
-
- case BNX2X_VFOP_QFLR_TERMINATE:
- qstate = &vfop->op_p->qctor.qstate;
- memset(qstate , 0, sizeof(*qstate));
- qstate->q_obj = &bnx2x_vfq(vf, qid, sp_obj);
- vfop->state = BNX2X_VFOP_QFLR_DONE;
-
- DP(BNX2X_MSG_IOV, "VF[%d] qstate during flr was %d\n",
- vf->abs_vfid, qstate->q_obj->state);
-
- if (qstate->q_obj->state != BNX2X_Q_STATE_RESET) {
- qstate->q_obj->state = BNX2X_Q_STATE_STOPPED;
- qstate->cmd = BNX2X_Q_CMD_TERMINATE;
- vfop->rc = bnx2x_queue_state_change(bp, qstate);
- bnx2x_vfop_finalize(vf, vfop->rc, VFOP_VERIFY_PEND);
- } else {
- goto op_done;
- }
-
-op_err:
- BNX2X_ERR("QFLR[%d:%d] error: rc %d\n",
- vf->abs_vfid, qid, vfop->rc);
-op_done:
- case BNX2X_VFOP_QFLR_DONE:
- bnx2x_vfop_end(bp, vf, vfop);
- return;
- default:
- bnx2x_vfop_default(state);
+ memset(&qstate, 0, sizeof(struct bnx2x_queue_state_params));
+ qstate.q_obj = &bnx2x_vfq(vf, qid, sp_obj);
+ qstate.q_obj->state = BNX2X_Q_STATE_STOPPED;
+ qstate.cmd = BNX2X_Q_CMD_TERMINATE;
+ set_bit(RAMROD_COMP_WAIT, &qstate.ramrod_flags);
+ rc = bnx2x_queue_state_change(bp, &qstate);
+ if (rc)
+ goto op_err;
}
-op_pending:
- return;
-}
-
-static int bnx2x_vfop_qflr_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd,
- int qid)
-{
- struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
- if (vfop) {
- vfop->args.qx.qid = qid;
- bnx2x_vfop_opset(BNX2X_VFOP_QFLR_CLR_VLAN,
- bnx2x_vfop_qflr, cmd->done);
- return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qflr,
- cmd->block);
- }
- return -ENOMEM;
+ return 0;
+op_err:
+ BNX2X_ERR("vf[%d:%d] error: rc %d\n", vf->abs_vfid, qid, rc);
+ return rc;
}
-/* VFOP multi-casts */
-static void bnx2x_vfop_mcast(struct bnx2x *bp, struct bnx2x_virtf *vf)
+int bnx2x_vf_mcast(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ bnx2x_mac_addr_t *mcasts, int mc_num, bool drv_only)
{
- struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
- struct bnx2x_mcast_ramrod_params *mcast = &vfop->op_p->mcast;
- struct bnx2x_raw_obj *raw = &mcast->mcast_obj->raw;
- struct bnx2x_vfop_args_mcast *args = &vfop->args.mc_list;
- enum bnx2x_vfop_mcast_state state = vfop->state;
- int i;
-
- bnx2x_vfop_reset_wq(vf);
-
- if (vfop->rc < 0)
- goto op_err;
+ struct bnx2x_mcast_list_elem *mc = NULL;
+ struct bnx2x_mcast_ramrod_params mcast;
+ int rc, i;
- DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
-
- switch (state) {
- case BNX2X_VFOP_MCAST_DEL:
- /* clear existing mcasts */
- vfop->state = (args->mc_num) ? BNX2X_VFOP_MCAST_ADD
- : BNX2X_VFOP_MCAST_CHK_DONE;
- mcast->mcast_list_len = vf->mcast_list_len;
- vf->mcast_list_len = args->mc_num;
- vfop->rc = bnx2x_config_mcast(bp, mcast, BNX2X_MCAST_CMD_DEL);
- bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
-
- case BNX2X_VFOP_MCAST_ADD:
- if (raw->check_pending(raw))
- goto op_pending;
-
- /* update mcast list on the ramrod params */
- INIT_LIST_HEAD(&mcast->mcast_list);
- for (i = 0; i < args->mc_num; i++)
- list_add_tail(&(args->mc[i].link),
- &mcast->mcast_list);
- mcast->mcast_list_len = args->mc_num;
+ DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
- /* add new mcasts */
- vfop->state = BNX2X_VFOP_MCAST_CHK_DONE;
- vfop->rc = bnx2x_config_mcast(bp, mcast,
- BNX2X_MCAST_CMD_ADD);
- bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
-
- case BNX2X_VFOP_MCAST_CHK_DONE:
- vfop->rc = raw->check_pending(raw) ? 1 : 0;
- bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
- default:
- bnx2x_vfop_default(state);
+ /* Prepare Multicast command */
+ memset(&mcast, 0, sizeof(struct bnx2x_mcast_ramrod_params));
+ mcast.mcast_obj = &vf->mcast_obj;
+ if (drv_only)
+ set_bit(RAMROD_DRV_CLR_ONLY, &mcast.ramrod_flags);
+ else
+ set_bit(RAMROD_COMP_WAIT, &mcast.ramrod_flags);
+ if (mc_num) {
+ mc = kzalloc(mc_num * sizeof(struct bnx2x_mcast_list_elem),
+ GFP_KERNEL);
+ if (!mc) {
+ BNX2X_ERR("Cannot Configure mulicasts due to lack of memory\n");
+ return -ENOMEM;
+ }
}
-op_err:
- BNX2X_ERR("MCAST CONFIG error: rc %d\n", vfop->rc);
-op_done:
- kfree(args->mc);
- bnx2x_vfop_end(bp, vf, vfop);
-op_pending:
- return;
-}
-int bnx2x_vfop_mcast_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd,
- bnx2x_mac_addr_t *mcasts,
- int mcast_num, bool drv_only)
-{
- struct bnx2x_vfop *vfop = NULL;
- size_t mc_sz = mcast_num * sizeof(struct bnx2x_mcast_list_elem);
- struct bnx2x_mcast_list_elem *mc = mc_sz ? kzalloc(mc_sz, GFP_KERNEL) :
- NULL;
-
- if (!mc_sz || mc) {
- vfop = bnx2x_vfop_add(bp, vf);
- if (vfop) {
- int i;
- struct bnx2x_mcast_ramrod_params *ramrod =
- &vf->op_params.mcast;
-
- /* set ramrod params */
- memset(ramrod, 0, sizeof(*ramrod));
- ramrod->mcast_obj = &vf->mcast_obj;
- if (drv_only)
- set_bit(RAMROD_DRV_CLR_ONLY,
- &ramrod->ramrod_flags);
-
- /* copy mcasts pointers */
- vfop->args.mc_list.mc_num = mcast_num;
- vfop->args.mc_list.mc = mc;
- for (i = 0; i < mcast_num; i++)
- mc[i].mac = mcasts[i];
-
- bnx2x_vfop_opset(BNX2X_VFOP_MCAST_DEL,
- bnx2x_vfop_mcast, cmd->done);
- return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_mcast,
- cmd->block);
- } else {
+ /* clear existing mcasts */
+ mcast.mcast_list_len = vf->mcast_list_len;
+ vf->mcast_list_len = mc_num;
+ rc = bnx2x_config_mcast(bp, &mcast, BNX2X_MCAST_CMD_DEL);
+ if (rc) {
+ BNX2X_ERR("Failed to remove multicasts\n");
+ if (mc)
kfree(mc);
- }
+ return rc;
}
- return -ENOMEM;
-}
-
-/* VFOP rx-mode */
-static void bnx2x_vfop_rxmode(struct bnx2x *bp, struct bnx2x_virtf *vf)
-{
- struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
- struct bnx2x_rx_mode_ramrod_params *ramrod = &vfop->op_p->rx_mode;
- enum bnx2x_vfop_rxmode_state state = vfop->state;
-
- bnx2x_vfop_reset_wq(vf);
-
- if (vfop->rc < 0)
- goto op_err;
- DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
-
- switch (state) {
- case BNX2X_VFOP_RXMODE_CONFIG:
- /* next state */
- vfop->state = BNX2X_VFOP_RXMODE_DONE;
+ /* update mcast list on the ramrod params */
+ if (mc_num) {
+ INIT_LIST_HEAD(&mcast.mcast_list);
+ for (i = 0; i < mc_num; i++) {
+ mc[i].mac = mcasts[i];
+ list_add_tail(&mc[i].link,
+ &mcast.mcast_list);
+ }
- /* record the accept flags in vfdb so hypervisor can modify them
- * if necessary
- */
- bnx2x_vfq(vf, ramrod->cl_id - vf->igu_base_id, accept_flags) =
- ramrod->rx_accept_flags;
- vfop->rc = bnx2x_config_rx_mode(bp, ramrod);
- bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
-op_err:
- BNX2X_ERR("RXMODE error: rc %d\n", vfop->rc);
-op_done:
- case BNX2X_VFOP_RXMODE_DONE:
- bnx2x_vfop_end(bp, vf, vfop);
- return;
- default:
- bnx2x_vfop_default(state);
+ /* add new mcasts */
+ rc = bnx2x_config_mcast(bp, &mcast, BNX2X_MCAST_CMD_ADD);
+ if (rc)
+ BNX2X_ERR("Faled to add multicasts\n");
+ kfree(mc);
}
-op_pending:
- return;
+
+ return rc;
}
static void bnx2x_vf_prep_rx_mode(struct bnx2x *bp, u8 qid,
@@ -1268,118 +644,56 @@ static void bnx2x_vf_prep_rx_mode(struct bnx2x *bp, u8 qid,
ramrod->rdata_mapping = bnx2x_vf_sp_map(bp, vf, rx_mode_rdata.e2);
}
-int bnx2x_vfop_rxmode_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd,
- int qid, unsigned long accept_flags)
+int bnx2x_vf_rxmode(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ int qid, unsigned long accept_flags)
{
- struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
-
- if (vfop) {
- struct bnx2x_rx_mode_ramrod_params *ramrod =
- &vf->op_params.rx_mode;
+ struct bnx2x_rx_mode_ramrod_params ramrod;
- bnx2x_vf_prep_rx_mode(bp, qid, ramrod, vf, accept_flags);
+ DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
- bnx2x_vfop_opset(BNX2X_VFOP_RXMODE_CONFIG,
- bnx2x_vfop_rxmode, cmd->done);
- return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_rxmode,
- cmd->block);
- }
- return -ENOMEM;
+ bnx2x_vf_prep_rx_mode(bp, qid, &ramrod, vf, accept_flags);
+ set_bit(RAMROD_COMP_WAIT, &ramrod.ramrod_flags);
+ vfq_get(vf, qid)->accept_flags = ramrod.rx_accept_flags;
+ return bnx2x_config_rx_mode(bp, &ramrod);
}
-/* VFOP queue tear-down ('drop all' rx-mode, clear vlans, clear macs,
- * queue destructor)
- */
-static void bnx2x_vfop_qdown(struct bnx2x *bp, struct bnx2x_virtf *vf)
+int bnx2x_vf_queue_teardown(struct bnx2x *bp, struct bnx2x_virtf *vf, int qid)
{
- struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
- int qid = vfop->args.qx.qid;
- enum bnx2x_vfop_qteardown_state state = vfop->state;
- struct bnx2x_vfop_cmd cmd;
-
- if (vfop->rc < 0)
- goto op_err;
-
- DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
-
- cmd.done = bnx2x_vfop_qdown;
- cmd.block = false;
-
- switch (state) {
- case BNX2X_VFOP_QTEARDOWN_RXMODE:
- /* Drop all */
- vfop->state = BNX2X_VFOP_QTEARDOWN_CLR_VLAN;
- vfop->rc = bnx2x_vfop_rxmode_cmd(bp, vf, &cmd, qid, 0);
- if (vfop->rc)
- goto op_err;
- return;
-
- case BNX2X_VFOP_QTEARDOWN_CLR_VLAN:
- /* vlan-clear-all: don't consume credit */
- vfop->state = BNX2X_VFOP_QTEARDOWN_CLR_MAC;
- vfop->rc = bnx2x_vfop_vlan_delall_cmd(bp, vf, &cmd, qid, false);
- if (vfop->rc)
- goto op_err;
- return;
-
- case BNX2X_VFOP_QTEARDOWN_CLR_MAC:
- /* mac-clear-all: consume credit */
- vfop->state = BNX2X_VFOP_QTEARDOWN_CLR_MCAST;
- vfop->rc = bnx2x_vfop_mac_delall_cmd(bp, vf, &cmd, qid, false);
- if (vfop->rc)
- goto op_err;
- return;
+ int rc;
- case BNX2X_VFOP_QTEARDOWN_CLR_MCAST:
- vfop->state = BNX2X_VFOP_QTEARDOWN_QDTOR;
- vfop->rc = bnx2x_vfop_mcast_cmd(bp, vf, &cmd, NULL, 0, false);
- if (vfop->rc)
- goto op_err;
- return;
+ DP(BNX2X_MSG_IOV, "vf[%d:%d]\n", vf->abs_vfid, qid);
- case BNX2X_VFOP_QTEARDOWN_QDTOR:
- /* run the queue destruction flow */
- DP(BNX2X_MSG_IOV, "case: BNX2X_VFOP_QTEARDOWN_QDTOR\n");
- vfop->state = BNX2X_VFOP_QTEARDOWN_DONE;
- DP(BNX2X_MSG_IOV, "new state: BNX2X_VFOP_QTEARDOWN_DONE\n");
- vfop->rc = bnx2x_vfop_qdtor_cmd(bp, vf, &cmd, qid);
- DP(BNX2X_MSG_IOV, "returned from cmd\n");
- if (vfop->rc)
+ /* Remove all classification configuration for leading queue */
+ if (qid == LEADING_IDX) {
+ rc = bnx2x_vf_rxmode(bp, vf, qid, 0);
+ if (rc)
goto op_err;
- return;
-op_err:
- BNX2X_ERR("QTEARDOWN[%d:%d] error: rc %d\n",
- vf->abs_vfid, qid, vfop->rc);
-
- case BNX2X_VFOP_QTEARDOWN_DONE:
- bnx2x_vfop_end(bp, vf, vfop);
- return;
- default:
- bnx2x_vfop_default(state);
- }
-}
-int bnx2x_vfop_qdown_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd,
- int qid)
-{
- struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
-
- /* for non leading queues skip directly to qdown sate */
- if (vfop) {
- vfop->args.qx.qid = qid;
- bnx2x_vfop_opset(qid == LEADING_IDX ?
- BNX2X_VFOP_QTEARDOWN_RXMODE :
- BNX2X_VFOP_QTEARDOWN_QDTOR, bnx2x_vfop_qdown,
- cmd->done);
- return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qdown,
- cmd->block);
+ /* Remove filtering if feasible */
+ if (bnx2x_validate_vf_sp_objs(bp, vf, true)) {
+ rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid,
+ false, false);
+ if (rc)
+ goto op_err;
+ rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid,
+ false, true);
+ if (rc)
+ goto op_err;
+ rc = bnx2x_vf_mcast(bp, vf, NULL, 0, false);
+ if (rc)
+ goto op_err;
+ }
}
- return -ENOMEM;
+ /* Destroy queue */
+ rc = bnx2x_vf_queue_destroy(bp, vf, qid);
+ if (rc)
+ goto op_err;
+ return rc;
+op_err:
+ BNX2X_ERR("vf[%d:%d] error: rc %d\n",
+ vf->abs_vfid, qid, rc);
+ return rc;
}
/* VF enable primitives
@@ -1446,12 +760,12 @@ static void bnx2x_vf_igu_reset(struct bnx2x *bp, struct bnx2x_virtf *vf)
if (vf->cfg_flags & VF_CFG_INT_SIMD)
val |= IGU_VF_CONF_SINGLE_ISR_EN;
val &= ~IGU_VF_CONF_PARENT_MASK;
- val |= BP_FUNC(bp) << IGU_VF_CONF_PARENT_SHIFT; /* parent PF */
+ val |= (BP_ABS_FUNC(bp) >> 1) << IGU_VF_CONF_PARENT_SHIFT;
REG_WR(bp, IGU_REG_VF_CONFIGURATION, val);
DP(BNX2X_MSG_IOV,
- "value in IGU_REG_VF_CONFIGURATION of vf %d after write %x\n",
- vf->abs_vfid, REG_RD(bp, IGU_REG_VF_CONFIGURATION));
+ "value in IGU_REG_VF_CONFIGURATION of vf %d after write is 0x%08x\n",
+ vf->abs_vfid, val);
bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
@@ -1579,120 +893,63 @@ static void bnx2x_vf_flr_clnup_hw(struct bnx2x *bp, struct bnx2x_virtf *vf)
bnx2x_tx_hw_flushed(bp, poll_cnt);
}
-static void bnx2x_vfop_flr(struct bnx2x *bp, struct bnx2x_virtf *vf)
+static void bnx2x_vf_flr(struct bnx2x *bp, struct bnx2x_virtf *vf)
{
- struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
- struct bnx2x_vfop_args_qx *qx = &vfop->args.qx;
- enum bnx2x_vfop_flr_state state = vfop->state;
- struct bnx2x_vfop_cmd cmd = {
- .done = bnx2x_vfop_flr,
- .block = false,
- };
-
- if (vfop->rc < 0)
- goto op_err;
-
- DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+ int rc, i;
- switch (state) {
- case BNX2X_VFOP_FLR_QUEUES:
- /* the cleanup operations are valid if and only if the VF
- * was first acquired.
- */
- if (++(qx->qid) < vf_rxq_count(vf)) {
- vfop->rc = bnx2x_vfop_qflr_cmd(bp, vf, &cmd,
- qx->qid);
- if (vfop->rc)
- goto op_err;
- return;
- }
- /* remove multicasts */
- vfop->state = BNX2X_VFOP_FLR_HW;
- vfop->rc = bnx2x_vfop_mcast_cmd(bp, vf, &cmd, NULL,
- 0, true);
- if (vfop->rc)
- goto op_err;
- return;
- case BNX2X_VFOP_FLR_HW:
+ DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
- /* dispatch final cleanup and wait for HW queues to flush */
- bnx2x_vf_flr_clnup_hw(bp, vf);
+ /* the cleanup operations are valid if and only if the VF
+ * was first acquired.
+ */
+ for (i = 0; i < vf_rxq_count(vf); i++) {
+ rc = bnx2x_vf_queue_flr(bp, vf, i);
+ if (rc)
+ goto out;
+ }
- /* release VF resources */
- bnx2x_vf_free_resc(bp, vf);
+ /* remove multicasts */
+ bnx2x_vf_mcast(bp, vf, NULL, 0, true);
- /* re-open the mailbox */
- bnx2x_vf_enable_mbx(bp, vf->abs_vfid);
+ /* dispatch final cleanup and wait for HW queues to flush */
+ bnx2x_vf_flr_clnup_hw(bp, vf);
- goto op_done;
- default:
- bnx2x_vfop_default(state);
- }
-op_err:
- BNX2X_ERR("VF[%d] FLR error: rc %d\n", vf->abs_vfid, vfop->rc);
-op_done:
- vf->flr_clnup_stage = VF_FLR_ACK;
- bnx2x_vfop_end(bp, vf, vfop);
- bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_FLR);
-}
+ /* release VF resources */
+ bnx2x_vf_free_resc(bp, vf);
-static int bnx2x_vfop_flr_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- vfop_handler_t done)
-{
- struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
- if (vfop) {
- vfop->args.qx.qid = -1; /* loop */
- bnx2x_vfop_opset(BNX2X_VFOP_FLR_QUEUES,
- bnx2x_vfop_flr, done);
- return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_flr, false);
- }
- return -ENOMEM;
+ /* re-open the mailbox */
+ bnx2x_vf_enable_mbx(bp, vf->abs_vfid);
+ return;
+out:
+ BNX2X_ERR("vf[%d:%d] failed flr: rc %d\n",
+ vf->abs_vfid, i, rc);
}
-static void bnx2x_vf_flr_clnup(struct bnx2x *bp, struct bnx2x_virtf *prev_vf)
+static void bnx2x_vf_flr_clnup(struct bnx2x *bp)
{
- int i = prev_vf ? prev_vf->index + 1 : 0;
struct bnx2x_virtf *vf;
+ int i;
- /* find next VF to cleanup */
-next_vf_to_clean:
- for (;
- i < BNX2X_NR_VIRTFN(bp) &&
- (bnx2x_vf(bp, i, state) != VF_RESET ||
- bnx2x_vf(bp, i, flr_clnup_stage) != VF_FLR_CLN);
- i++)
- ;
+ for (i = 0; i < BNX2X_NR_VIRTFN(bp); i++) {
+ /* VF should be RESET & in FLR cleanup states */
+ if (bnx2x_vf(bp, i, state) != VF_RESET ||
+ !bnx2x_vf(bp, i, flr_clnup_stage))
+ continue;
- DP(BNX2X_MSG_IOV, "next vf to cleanup: %d. Num of vfs: %d\n", i,
- BNX2X_NR_VIRTFN(bp));
+ DP(BNX2X_MSG_IOV, "next vf to cleanup: %d. Num of vfs: %d\n",
+ i, BNX2X_NR_VIRTFN(bp));
- if (i < BNX2X_NR_VIRTFN(bp)) {
vf = BP_VF(bp, i);
/* lock the vf pf channel */
bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_FLR);
/* invoke the VF FLR SM */
- if (bnx2x_vfop_flr_cmd(bp, vf, bnx2x_vf_flr_clnup)) {
- BNX2X_ERR("VF[%d]: FLR cleanup failed -ENOMEM\n",
- vf->abs_vfid);
+ bnx2x_vf_flr(bp, vf);
- /* mark the VF to be ACKED and continue */
- vf->flr_clnup_stage = VF_FLR_ACK;
- goto next_vf_to_clean;
- }
- return;
- }
-
- /* we are done, update vf records */
- for_each_vf(bp, i) {
- vf = BP_VF(bp, i);
-
- if (vf->flr_clnup_stage != VF_FLR_ACK)
- continue;
-
- vf->flr_clnup_stage = VF_FLR_EPILOG;
+ /* mark the VF to be ACKED and continue */
+ vf->flr_clnup_stage = false;
+ bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_FLR);
}
/* Acknowledge the handled VFs.
@@ -1742,7 +999,7 @@ void bnx2x_vf_handle_flr_event(struct bnx2x *bp)
if (reset) {
/* set as reset and ready for cleanup */
vf->state = VF_RESET;
- vf->flr_clnup_stage = VF_FLR_CLN;
+ vf->flr_clnup_stage = true;
DP(BNX2X_MSG_IOV,
"Initiating Final cleanup for VF %d\n",
@@ -1751,7 +1008,7 @@ void bnx2x_vf_handle_flr_event(struct bnx2x *bp)
}
/* do the FLR cleanup for all marked VFs*/
- bnx2x_vf_flr_clnup(bp, NULL);
+ bnx2x_vf_flr_clnup(bp);
}
/* IOV global initialization routines */
@@ -2018,7 +1275,6 @@ int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
bnx2x_vf(bp, i, index) = i;
bnx2x_vf(bp, i, abs_vfid) = iov->first_vf_in_pf + i;
bnx2x_vf(bp, i, state) = VF_FREE;
- INIT_LIST_HEAD(&bnx2x_vf(bp, i, op_list_head));
mutex_init(&bnx2x_vf(bp, i, op_mutex));
bnx2x_vf(bp, i, op_current) = CHANNEL_TLV_NONE;
}
@@ -2039,6 +1295,9 @@ int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
goto failed;
}
+ /* Prepare the VFs event synchronization mechanism */
+ mutex_init(&bp->vfdb->event_mutex);
+
return 0;
failed:
DP(BNX2X_MSG_IOV, "Failed err=%d\n", err);
@@ -2117,7 +1376,9 @@ int bnx2x_iov_alloc_mem(struct bnx2x *bp)
cxt->size = min_t(size_t, tot_size, CDU_ILT_PAGE_SZ);
if (cxt->size) {
- BNX2X_PCI_ALLOC(cxt->addr, &cxt->mapping, cxt->size);
+ cxt->addr = BNX2X_PCI_ALLOC(&cxt->mapping, cxt->size);
+ if (!cxt->addr)
+ goto alloc_mem_err;
} else {
cxt->addr = NULL;
cxt->mapping = 0;
@@ -2127,20 +1388,28 @@ int bnx2x_iov_alloc_mem(struct bnx2x *bp)
/* allocate vfs ramrods dma memory - client_init and set_mac */
tot_size = BNX2X_NR_VIRTFN(bp) * sizeof(struct bnx2x_vf_sp);
- BNX2X_PCI_ALLOC(BP_VFDB(bp)->sp_dma.addr, &BP_VFDB(bp)->sp_dma.mapping,
- tot_size);
+ BP_VFDB(bp)->sp_dma.addr = BNX2X_PCI_ALLOC(&BP_VFDB(bp)->sp_dma.mapping,
+ tot_size);
+ if (!BP_VFDB(bp)->sp_dma.addr)
+ goto alloc_mem_err;
BP_VFDB(bp)->sp_dma.size = tot_size;
/* allocate mailboxes */
tot_size = BNX2X_NR_VIRTFN(bp) * MBX_MSG_ALIGNED_SIZE;
- BNX2X_PCI_ALLOC(BP_VF_MBX_DMA(bp)->addr, &BP_VF_MBX_DMA(bp)->mapping,
- tot_size);
+ BP_VF_MBX_DMA(bp)->addr = BNX2X_PCI_ALLOC(&BP_VF_MBX_DMA(bp)->mapping,
+ tot_size);
+ if (!BP_VF_MBX_DMA(bp)->addr)
+ goto alloc_mem_err;
+
BP_VF_MBX_DMA(bp)->size = tot_size;
/* allocate local bulletin boards */
tot_size = BNX2X_NR_VIRTFN(bp) * BULLETIN_CONTENT_SIZE;
- BNX2X_PCI_ALLOC(BP_VF_BULLETIN_DMA(bp)->addr,
- &BP_VF_BULLETIN_DMA(bp)->mapping, tot_size);
+ BP_VF_BULLETIN_DMA(bp)->addr = BNX2X_PCI_ALLOC(&BP_VF_BULLETIN_DMA(bp)->mapping,
+ tot_size);
+ if (!BP_VF_BULLETIN_DMA(bp)->addr)
+ goto alloc_mem_err;
+
BP_VF_BULLETIN_DMA(bp)->size = tot_size;
return 0;
@@ -2166,6 +1435,9 @@ static void bnx2x_vfq_init(struct bnx2x *bp, struct bnx2x_virtf *vf,
bnx2x_vf_sp_map(bp, vf, q_data),
q_type);
+ /* sp indication is set only when vlan/mac/etc. are initialized */
+ q->sp_initialized = false;
+
DP(BNX2X_MSG_IOV,
"initialized vf %d's queue object. func id set to %d. cid set to 0x%x\n",
vf->abs_vfid, q->sp_obj.func_id, q->cid);
@@ -2269,7 +1541,7 @@ int bnx2x_iov_chip_cleanup(struct bnx2x *bp)
/* release all the VFs */
for_each_vf(bp, i)
- bnx2x_vf_release(bp, BP_VF(bp, i), true); /* blocking */
+ bnx2x_vf_release(bp, BP_VF(bp, i));
return 0;
}
@@ -2359,6 +1631,12 @@ void bnx2x_vf_handle_filters_eqe(struct bnx2x *bp,
smp_mb__after_clear_bit();
}
+static void bnx2x_vf_handle_rss_update_eqe(struct bnx2x *bp,
+ struct bnx2x_virtf *vf)
+{
+ vf->rss_conf_obj.raw.clear_pending(&vf->rss_conf_obj.raw);
+}
+
int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem)
{
struct bnx2x_virtf *vf;
@@ -2383,6 +1661,7 @@ int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem)
case EVENT_RING_OPCODE_CLASSIFICATION_RULES:
case EVENT_RING_OPCODE_MULTICAST_RULES:
case EVENT_RING_OPCODE_FILTERS_RULES:
+ case EVENT_RING_OPCODE_RSS_UPDATE_RULES:
cid = (elem->message.data.eth_event.echo &
BNX2X_SWCID_MASK);
DP(BNX2X_MSG_IOV, "checking filtering comp cid=%d\n", cid);
@@ -2447,13 +1726,15 @@ get_vf:
vf->abs_vfid, qidx);
bnx2x_vf_handle_filters_eqe(bp, vf);
break;
+ case EVENT_RING_OPCODE_RSS_UPDATE_RULES:
+ DP(BNX2X_MSG_IOV, "got VF [%d:%d] RSS update ramrod\n",
+ vf->abs_vfid, qidx);
+ bnx2x_vf_handle_rss_update_eqe(bp, vf);
case EVENT_RING_OPCODE_VF_FLR:
case EVENT_RING_OPCODE_MALICIOUS_VF:
/* Do nothing for now */
return 0;
}
- /* SRIOV: reschedule any 'in_progress' operations */
- bnx2x_iov_sp_event(bp, cid, false);
return 0;
}
@@ -2490,23 +1771,6 @@ void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
}
}
-void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid, bool queue_work)
-{
- struct bnx2x_virtf *vf;
-
- /* check if the cid is the VF range */
- if (!IS_SRIOV(bp) || !bnx2x_iov_is_vf_cid(bp, vf_cid))
- return;
-
- vf = bnx2x_vf_by_cid(bp, vf_cid);
- if (vf) {
- /* set in_progress flag */
- atomic_set(&vf->op_in_progress, 1);
- if (queue_work)
- queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
- }
-}
-
void bnx2x_iov_adjust_stats_req(struct bnx2x *bp)
{
int i;
@@ -2527,10 +1791,10 @@ void bnx2x_iov_adjust_stats_req(struct bnx2x *bp)
first_queue_query_index = BNX2X_FIRST_QUEUE_QUERY_IDX -
(is_fcoe ? 0 : 1);
- DP(BNX2X_MSG_IOV,
- "BNX2X_NUM_ETH_QUEUES %d, is_fcoe %d, first_queue_query_index %d => determined the last non virtual statistics query index is %d. Will add queries on top of that\n",
- BNX2X_NUM_ETH_QUEUES(bp), is_fcoe, first_queue_query_index,
- first_queue_query_index + num_queues_req);
+ DP_AND((BNX2X_MSG_IOV | BNX2X_MSG_STATS),
+ "BNX2X_NUM_ETH_QUEUES %d, is_fcoe %d, first_queue_query_index %d => determined the last non virtual statistics query index is %d. Will add queries on top of that\n",
+ BNX2X_NUM_ETH_QUEUES(bp), is_fcoe, first_queue_query_index,
+ first_queue_query_index + num_queues_req);
cur_data_offset = bp->fw_stats_data_mapping +
offsetof(struct bnx2x_fw_stats_data, queue_stats) +
@@ -2544,9 +1808,9 @@ void bnx2x_iov_adjust_stats_req(struct bnx2x *bp)
struct bnx2x_virtf *vf = BP_VF(bp, i);
if (vf->state != VF_ENABLED) {
- DP(BNX2X_MSG_IOV,
- "vf %d not enabled so no stats for it\n",
- vf->abs_vfid);
+ DP_AND((BNX2X_MSG_IOV | BNX2X_MSG_STATS),
+ "vf %d not enabled so no stats for it\n",
+ vf->abs_vfid);
continue;
}
@@ -2588,32 +1852,6 @@ void bnx2x_iov_adjust_stats_req(struct bnx2x *bp)
bp->fw_stats_req->hdr.cmd_num = bp->fw_stats_num + stats_count;
}
-void bnx2x_iov_sp_task(struct bnx2x *bp)
-{
- int i;
-
- if (!IS_SRIOV(bp))
- return;
- /* Iterate over all VFs and invoke state transition for VFs with
- * 'in-progress' slow-path operations
- */
- DP(BNX2X_MSG_IOV, "searching for pending vf operations\n");
- for_each_vf(bp, i) {
- struct bnx2x_virtf *vf = BP_VF(bp, i);
-
- if (!vf) {
- BNX2X_ERR("VF was null! skipping...\n");
- continue;
- }
-
- if (!list_empty(&vf->op_list_head) &&
- atomic_read(&vf->op_in_progress)) {
- DP(BNX2X_MSG_IOV, "running pending op for vf %d\n", i);
- bnx2x_vfop_cur(bp, vf)->transition(bp, vf);
- }
- }
-}
-
static inline
struct bnx2x_virtf *__vf_from_stat_id(struct bnx2x *bp, u8 stat_id)
{
@@ -2849,52 +2087,26 @@ static void bnx2x_set_vf_state(void *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)
+int bnx2x_vf_close(struct bnx2x *bp, struct bnx2x_virtf *vf)
{
- struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
- struct bnx2x_vfop_args_qx *qx = &vfop->args.qx;
- enum bnx2x_vfop_close_state state = vfop->state;
- struct bnx2x_vfop_cmd cmd = {
- .done = bnx2x_vfop_close,
- .block = false,
- };
+ int rc = 0, i;
- if (vfop->rc < 0)
- goto op_err;
-
- DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
-
- switch (state) {
- case BNX2X_VFOP_CLOSE_QUEUES:
-
- if (++(qx->qid) < vf_rxq_count(vf)) {
- vfop->rc = bnx2x_vfop_qdown_cmd(bp, vf, &cmd, qx->qid);
- if (vfop->rc)
- goto op_err;
- return;
- }
- vfop->state = BNX2X_VFOP_CLOSE_HW;
- vfop->rc = 0;
- bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+ DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
- case BNX2X_VFOP_CLOSE_HW:
-
- /* disable the interrupts */
- DP(BNX2X_MSG_IOV, "disabling igu\n");
- bnx2x_vf_igu_disable(bp, vf);
+ /* Close all queues */
+ for (i = 0; i < vf_rxq_count(vf); i++) {
+ rc = bnx2x_vf_queue_teardown(bp, vf, i);
+ if (rc)
+ goto op_err;
+ }
- /* disable the VF */
- DP(BNX2X_MSG_IOV, "clearing qtbl\n");
- bnx2x_vf_clr_qtbl(bp, vf);
+ /* disable the interrupts */
+ DP(BNX2X_MSG_IOV, "disabling igu\n");
+ bnx2x_vf_igu_disable(bp, vf);
- goto op_done;
- default:
- bnx2x_vfop_default(state);
- }
-op_err:
- BNX2X_ERR("VF[%d] CLOSE error: rc %d\n", vf->abs_vfid, vfop->rc);
-op_done:
+ /* disable the VF */
+ DP(BNX2X_MSG_IOV, "clearing qtbl\n");
+ bnx2x_vf_clr_qtbl(bp, vf);
/* 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
@@ -2909,43 +2121,20 @@ op_done:
}
DP(BNX2X_MSG_IOV, "set state to acquired\n");
- bnx2x_vfop_end(bp, vf, vfop);
-op_pending:
- /* Not supported at the moment; Exists for macros only */
- return;
-}
-int bnx2x_vfop_close_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd)
-{
- struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
- if (vfop) {
- vfop->args.qx.qid = -1; /* loop */
- bnx2x_vfop_opset(BNX2X_VFOP_CLOSE_QUEUES,
- bnx2x_vfop_close, cmd->done);
- return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_close,
- cmd->block);
- }
- return -ENOMEM;
+ return 0;
+op_err:
+ BNX2X_ERR("vf[%d] CLOSE error: rc %d\n", vf->abs_vfid, rc);
+ return rc;
}
/* VF release can be called either: 1. The VF was acquired but
* not enabled 2. the vf was enabled or in the process of being
* enabled
*/
-static void bnx2x_vfop_release(struct bnx2x *bp, struct bnx2x_virtf *vf)
+int bnx2x_vf_free(struct bnx2x *bp, struct bnx2x_virtf *vf)
{
- struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
- struct bnx2x_vfop_cmd cmd = {
- .done = bnx2x_vfop_release,
- .block = false,
- };
-
- DP(BNX2X_MSG_IOV, "vfop->rc %d\n", vfop->rc);
-
- if (vfop->rc < 0)
- goto op_err;
+ int rc;
DP(BNX2X_MSG_IOV, "VF[%d] STATE: %s\n", vf->abs_vfid,
vf->state == VF_FREE ? "Free" :
@@ -2956,116 +2145,87 @@ static void bnx2x_vfop_release(struct bnx2x *bp, struct bnx2x_virtf *vf)
switch (vf->state) {
case VF_ENABLED:
- vfop->rc = bnx2x_vfop_close_cmd(bp, vf, &cmd);
- if (vfop->rc)
+ rc = bnx2x_vf_close(bp, vf);
+ if (rc)
goto op_err;
- return;
-
+ /* Fallthrough to release resources */
case VF_ACQUIRED:
DP(BNX2X_MSG_IOV, "about to free resources\n");
bnx2x_vf_free_resc(bp, vf);
- DP(BNX2X_MSG_IOV, "vfop->rc %d\n", vfop->rc);
- goto op_done;
+ break;
case VF_FREE:
case VF_RESET:
- /* do nothing */
- goto op_done;
default:
- bnx2x_vfop_default(vf->state);
+ break;
}
+ return 0;
op_err:
- BNX2X_ERR("VF[%d] RELEASE error: rc %d\n", vf->abs_vfid, vfop->rc);
-op_done:
- bnx2x_vfop_end(bp, vf, vfop);
+ BNX2X_ERR("VF[%d] RELEASE error: rc %d\n", vf->abs_vfid, rc);
+ return rc;
}
-static void bnx2x_vfop_rss(struct bnx2x *bp, struct bnx2x_virtf *vf)
+int bnx2x_vf_rss_update(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct bnx2x_config_rss_params *rss)
{
- struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
- enum bnx2x_vfop_rss_state state;
-
- if (!vfop) {
- BNX2X_ERR("vfop was null\n");
- return;
- }
-
- state = vfop->state;
- bnx2x_vfop_reset_wq(vf);
-
- if (vfop->rc < 0)
- goto op_err;
-
- DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
-
- switch (state) {
- case BNX2X_VFOP_RSS_CONFIG:
- /* next state */
- vfop->state = BNX2X_VFOP_RSS_DONE;
- bnx2x_config_rss(bp, &vfop->op_p->rss);
- bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
-op_err:
- BNX2X_ERR("RSS error: rc %d\n", vfop->rc);
-op_done:
- case BNX2X_VFOP_RSS_DONE:
- bnx2x_vfop_end(bp, vf, vfop);
- return;
- default:
- bnx2x_vfop_default(state);
- }
-op_pending:
- return;
+ DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
+ set_bit(RAMROD_COMP_WAIT, &rss->ramrod_flags);
+ return bnx2x_config_rss(bp, rss);
}
-int bnx2x_vfop_release_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd)
+int bnx2x_vf_tpa_update(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct vfpf_tpa_tlv *tlv,
+ struct bnx2x_queue_update_tpa_params *params)
{
- struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
- if (vfop) {
- bnx2x_vfop_opset(-1, /* use vf->state */
- bnx2x_vfop_release, cmd->done);
- return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_release,
- cmd->block);
- }
- return -ENOMEM;
-}
+ aligned_u64 *sge_addr = tlv->tpa_client_info.sge_addr;
+ struct bnx2x_queue_state_params qstate;
+ int qid, rc = 0;
-int bnx2x_vfop_rss_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd)
-{
- struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+ DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
+
+ /* Set ramrod params */
+ memset(&qstate, 0, sizeof(struct bnx2x_queue_state_params));
+ memcpy(&qstate.params.update_tpa, params,
+ sizeof(struct bnx2x_queue_update_tpa_params));
+ qstate.cmd = BNX2X_Q_CMD_UPDATE_TPA;
+ set_bit(RAMROD_COMP_WAIT, &qstate.ramrod_flags);
- if (vfop) {
- bnx2x_vfop_opset(BNX2X_VFOP_RSS_CONFIG, bnx2x_vfop_rss,
- cmd->done);
- return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_rss,
- cmd->block);
+ for (qid = 0; qid < vf_rxq_count(vf); qid++) {
+ qstate.q_obj = &bnx2x_vfq(vf, qid, sp_obj);
+ qstate.params.update_tpa.sge_map = sge_addr[qid];
+ DP(BNX2X_MSG_IOV, "sge_addr[%d:%d] %08x:%08x\n",
+ vf->abs_vfid, qid, U64_HI(sge_addr[qid]),
+ U64_LO(sge_addr[qid]));
+ rc = bnx2x_queue_state_change(bp, &qstate);
+ if (rc) {
+ BNX2X_ERR("Failed to configure sge_addr %08x:%08x for [%d:%d]\n",
+ U64_HI(sge_addr[qid]), U64_LO(sge_addr[qid]),
+ vf->abs_vfid, qid);
+ return rc;
+ }
}
- return -ENOMEM;
+
+ return rc;
}
/* VF release ~ VF close + VF release-resources
* Release is the ultimate SW shutdown and is called whenever an
* irrecoverable error is encountered.
*/
-void bnx2x_vf_release(struct bnx2x *bp, struct bnx2x_virtf *vf, bool block)
+int bnx2x_vf_release(struct bnx2x *bp, struct bnx2x_virtf *vf)
{
- struct bnx2x_vfop_cmd cmd = {
- .done = NULL,
- .block = block,
- };
int rc;
DP(BNX2X_MSG_IOV, "PF releasing vf %d\n", vf->abs_vfid);
bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_RELEASE_VF);
- rc = bnx2x_vfop_release_cmd(bp, vf, &cmd);
+ rc = bnx2x_vf_free(bp, vf);
if (rc)
WARN(rc,
"VF[%d] Failed to allocate resources for release op- rc=%d\n",
vf->abs_vfid, rc);
+ bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_RELEASE_VF);
+ return rc;
}
static inline void bnx2x_vf_get_sbdf(struct bnx2x *bp,
@@ -3074,16 +2234,6 @@ static inline void bnx2x_vf_get_sbdf(struct bnx2x *bp,
*sbdf = vf->devfn | (vf->bus << 8);
}
-static inline void bnx2x_vf_get_bars(struct bnx2x *bp, struct bnx2x_virtf *vf,
- struct bnx2x_vf_bar_info *bar_info)
-{
- int n;
-
- bar_info->nr_bars = bp->vfdb->sriov.nres;
- for (n = 0; n < bar_info->nr_bars; n++)
- bar_info->bars[n] = vf->bars[n];
-}
-
void bnx2x_lock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
enum channel_tlvs tlv)
{
@@ -3405,13 +2555,13 @@ int bnx2x_get_vf_config(struct net_device *dev, int vfidx,
ivi->spoofchk = 1; /*always enabled */
if (vf->state == VF_ENABLED) {
/* mac and vlan are in vlan_mac objects */
- if (validate_vlan_mac(bp, &bnx2x_leading_vfq(vf, mac_obj)))
+ if (bnx2x_validate_vf_sp_objs(bp, vf, false)) {
mac_obj->get_n_elements(bp, mac_obj, 1, (u8 *)&ivi->mac,
0, ETH_ALEN);
- if (validate_vlan_mac(bp, &bnx2x_leading_vfq(vf, vlan_obj)))
vlan_obj->get_n_elements(bp, vlan_obj, 1,
(u8 *)&ivi->vlan, 0,
VLAN_HLEN);
+ }
} else {
/* mac */
if (bulletin->valid_bitmap & (1 << MAC_ADDR_VALID))
@@ -3485,17 +2635,17 @@ int bnx2x_set_vf_mac(struct net_device *dev, int vfidx, u8 *mac)
q_logical_state == BNX2X_Q_LOGICAL_STATE_ACTIVE) {
/* configure the mac in device on this vf's queue */
unsigned long ramrod_flags = 0;
- struct bnx2x_vlan_mac_obj *mac_obj =
- &bnx2x_leading_vfq(vf, mac_obj);
+ struct bnx2x_vlan_mac_obj *mac_obj;
- rc = validate_vlan_mac(bp, &bnx2x_leading_vfq(vf, mac_obj));
- if (rc)
- return rc;
+ /* User should be able to see failure reason in system logs */
+ if (!bnx2x_validate_vf_sp_objs(bp, vf, true))
+ return -EINVAL;
/* must lock vfpf channel to protect against vf flows */
bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC);
/* remove existing eth macs */
+ mac_obj = &bnx2x_leading_vfq(vf, mac_obj);
rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_ETH_MAC, true);
if (rc) {
BNX2X_ERR("failed to delete eth macs\n");
@@ -3569,17 +2719,16 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos)
BNX2X_Q_LOGICAL_STATE_ACTIVE)
return rc;
- /* configure the vlan in device on this vf's queue */
- vlan_obj = &bnx2x_leading_vfq(vf, vlan_obj);
- rc = validate_vlan_mac(bp, &bnx2x_leading_vfq(vf, mac_obj));
- if (rc)
- return rc;
+ /* User should be able to see error in system logs */
+ if (!bnx2x_validate_vf_sp_objs(bp, vf, true))
+ return -EINVAL;
/* must lock vfpf channel to protect against vf flows */
bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_VLAN);
/* remove existing vlans */
__set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
+ vlan_obj = &bnx2x_leading_vfq(vf, vlan_obj);
rc = vlan_obj->delete_all(bp, vlan_obj, &vlan_mac_flags,
&ramrod_flags);
if (rc) {
@@ -3736,13 +2885,9 @@ void bnx2x_timer_sriov(struct bnx2x *bp)
bnx2x_sample_bulletin(bp);
/* if channel is down we need to self destruct */
- if (bp->old_bulletin.valid_bitmap & 1 << CHANNEL_DOWN) {
- smp_mb__before_clear_bit();
- set_bit(BNX2X_SP_RTNL_VFPF_CHANNEL_DOWN,
- &bp->sp_rtnl_state);
- smp_mb__after_clear_bit();
- schedule_delayed_work(&bp->sp_rtnl_task, 0);
- }
+ if (bp->old_bulletin.valid_bitmap & 1 << CHANNEL_DOWN)
+ bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_VFPF_CHANNEL_DOWN,
+ BNX2X_MSG_IOV);
}
void __iomem *bnx2x_vf_doorbells(struct bnx2x *bp)
@@ -3756,12 +2901,16 @@ int bnx2x_vf_pci_alloc(struct bnx2x *bp)
mutex_init(&bp->vf2pf_mutex);
/* allocate vf2pf mailbox for vf to pf channel */
- BNX2X_PCI_ALLOC(bp->vf2pf_mbox, &bp->vf2pf_mbox_mapping,
- sizeof(struct bnx2x_vf_mbx_msg));
+ bp->vf2pf_mbox = BNX2X_PCI_ALLOC(&bp->vf2pf_mbox_mapping,
+ sizeof(struct bnx2x_vf_mbx_msg));
+ if (!bp->vf2pf_mbox)
+ goto alloc_mem_err;
/* allocate pf 2 vf bulletin board */
- BNX2X_PCI_ALLOC(bp->pf2vf_bulletin, &bp->pf2vf_bulletin_mapping,
- sizeof(union pf_vf_bulletin));
+ bp->pf2vf_bulletin = BNX2X_PCI_ALLOC(&bp->pf2vf_bulletin_mapping,
+ sizeof(union pf_vf_bulletin));
+ if (!bp->pf2vf_bulletin)
+ goto alloc_mem_err;
return 0;
@@ -3792,3 +2941,28 @@ void bnx2x_iov_channel_down(struct bnx2x *bp)
bnx2x_post_vf_bulletin(bp, vf_idx);
}
}
+
+void bnx2x_iov_task(struct work_struct *work)
+{
+ struct bnx2x *bp = container_of(work, struct bnx2x, iov_task.work);
+
+ if (!netif_running(bp->dev))
+ return;
+
+ if (test_and_clear_bit(BNX2X_IOV_HANDLE_FLR,
+ &bp->iov_task_state))
+ bnx2x_vf_handle_flr_event(bp);
+
+ if (test_and_clear_bit(BNX2X_IOV_HANDLE_VF_MSG,
+ &bp->iov_task_state))
+ bnx2x_vf_mbx(bp);
+}
+
+void bnx2x_schedule_iov_task(struct bnx2x *bp, enum bnx2x_iov_flag flag)
+{
+ smp_mb__before_clear_bit();
+ set_bit(flag, &bp->iov_task_state);
+ smp_mb__after_clear_bit();
+ DP(BNX2X_MSG_IOV, "Scheduling iov task [Flag: %d]\n", flag);
+ queue_delayed_work(bnx2x_iov_wq, &bp->iov_task, 0);
+}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
index d9fcca1b5a9d..8bf764570eef 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
@@ -30,6 +30,8 @@ enum sample_bulletin_result {
#ifdef CONFIG_BNX2X_SRIOV
+extern struct workqueue_struct *bnx2x_iov_wq;
+
/* The bnx2x device structure holds vfdb structure described below.
* The VF array is indexed by the relative vfid.
*/
@@ -83,108 +85,35 @@ struct bnx2x_vf_queue {
u16 index;
u16 sb_idx;
bool is_leading;
+ bool sp_initialized;
};
-/* struct bnx2x_vfop_qctor_params - prepare queue construction parameters:
- * q-init, q-setup and SB index
+/* struct bnx2x_vf_queue_construct_params - prepare queue construction
+ * parameters: q-init, q-setup and SB index
*/
-struct bnx2x_vfop_qctor_params {
+struct bnx2x_vf_queue_construct_params {
struct bnx2x_queue_state_params qstate;
struct bnx2x_queue_setup_params prep_qsetup;
};
-/* VFOP parameters (one copy per VF) */
-union bnx2x_vfop_params {
- struct bnx2x_vlan_mac_ramrod_params vlan_mac;
- struct bnx2x_rx_mode_ramrod_params rx_mode;
- struct bnx2x_mcast_ramrod_params mcast;
- struct bnx2x_config_rss_params rss;
- struct bnx2x_vfop_qctor_params qctor;
-};
-
/* forward */
struct bnx2x_virtf;
/* VFOP definitions */
-typedef void (*vfop_handler_t)(struct bnx2x *bp, struct bnx2x_virtf *vf);
-
-struct bnx2x_vfop_cmd {
- vfop_handler_t done;
- bool block;
-};
-/* VFOP queue filters command additional arguments */
-struct bnx2x_vfop_filter {
- struct list_head link;
+struct bnx2x_vf_mac_vlan_filter {
int type;
-#define BNX2X_VFOP_FILTER_MAC 1
-#define BNX2X_VFOP_FILTER_VLAN 2
+#define BNX2X_VF_FILTER_MAC 1
+#define BNX2X_VF_FILTER_VLAN 2
bool add;
u8 *mac;
u16 vid;
};
-struct bnx2x_vfop_filters {
- int add_cnt;
- struct list_head head;
- struct bnx2x_vfop_filter filters[];
-};
-
-/* transient list allocated, built and saved until its
- * passed to the SP-VERBs layer.
- */
-struct bnx2x_vfop_args_mcast {
- int mc_num;
- struct bnx2x_mcast_list_elem *mc;
-};
-
-struct bnx2x_vfop_args_qctor {
- int qid;
- u16 sb_idx;
-};
-
-struct bnx2x_vfop_args_qdtor {
- int qid;
- struct eth_context *cxt;
-};
-
-struct bnx2x_vfop_args_defvlan {
- int qid;
- bool enable;
- u16 vid;
- u8 prio;
-};
-
-struct bnx2x_vfop_args_qx {
- int qid;
- bool en_add;
-};
-
-struct bnx2x_vfop_args_filters {
- struct bnx2x_vfop_filters *multi_filter;
- atomic_t *credit; /* non NULL means 'don't consume credit' */
-};
-
-union bnx2x_vfop_args {
- struct bnx2x_vfop_args_mcast mc_list;
- struct bnx2x_vfop_args_qctor qctor;
- struct bnx2x_vfop_args_qdtor qdtor;
- struct bnx2x_vfop_args_defvlan defvlan;
- struct bnx2x_vfop_args_qx qx;
- struct bnx2x_vfop_args_filters filters;
-};
-
-struct bnx2x_vfop {
- struct list_head link;
- int rc; /* return code */
- int state; /* next state */
- union bnx2x_vfop_args args; /* extra arguments */
- union bnx2x_vfop_params *op_p; /* ramrod params */
-
- /* state machine callbacks */
- vfop_handler_t transition;
- vfop_handler_t done;
+struct bnx2x_vf_mac_vlan_filters {
+ int count;
+ struct bnx2x_vf_mac_vlan_filter filters[];
};
/* vf context */
@@ -204,15 +133,7 @@ struct bnx2x_virtf {
#define VF_ENABLED 2 /* VF Enabled */
#define VF_RESET 3 /* VF FLR'd, pending cleanup */
- /* non 0 during flr cleanup */
- u8 flr_clnup_stage;
-#define VF_FLR_CLN 1 /* reclaim resources and do 'final cleanup'
- * sans the end-wait
- */
-#define VF_FLR_ACK 2 /* ACK flr notification */
-#define VF_FLR_EPILOG 3 /* wait for VF remnants to dissipate in the HW
- * ~ final cleanup' end wait
- */
+ bool flr_clnup_stage; /* true during flr cleanup */
/* dma */
dma_addr_t fw_stat_map; /* valid iff VF_CFG_STATS */
@@ -276,11 +197,6 @@ struct bnx2x_virtf {
struct bnx2x_rss_config_obj rss_conf_obj;
/* slow-path operations */
- atomic_t op_in_progress;
- int op_rc;
- bool op_wait_blocking;
- struct list_head op_list_head;
- union bnx2x_vfop_params op_params;
struct mutex op_mutex; /* one vfop at a time mutex */
enum channel_tlvs op_current;
};
@@ -338,11 +254,6 @@ struct bnx2x_vf_mbx {
u32 vf_addr_hi;
struct vfpf_first_tlv first_tlv; /* saved VF request header */
-
- u8 flags;
-#define VF_MSG_INPROCESS 0x1 /* failsafe - the FW should prevent
- * more then one pending msg
- */
};
struct bnx2x_vf_sp {
@@ -419,6 +330,10 @@ struct bnx2x_vfdb {
/* the number of msix vectors belonging to this PF designated for VFs */
u16 vf_sbs_pool;
u16 first_vf_igu_entry;
+
+ /* sp_rtnl synchronization */
+ struct mutex event_mutex;
+ u64 event_occur;
};
/* queue access */
@@ -468,13 +383,13 @@ void bnx2x_iov_init_dq(struct bnx2x *bp);
void bnx2x_iov_init_dmae(struct bnx2x *bp);
void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
struct bnx2x_queue_sp_obj **q_obj);
-void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid, bool queue_work);
int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem);
void bnx2x_iov_adjust_stats_req(struct bnx2x *bp);
void bnx2x_iov_storm_stats_update(struct bnx2x *bp);
-void bnx2x_iov_sp_task(struct bnx2x *bp);
/* global vf mailbox routines */
-void bnx2x_vf_mbx(struct bnx2x *bp, struct vf_pf_event_data *vfpf_event);
+void bnx2x_vf_mbx(struct bnx2x *bp);
+void bnx2x_vf_mbx_schedule(struct bnx2x *bp,
+ struct vf_pf_event_data *vfpf_event);
void bnx2x_vf_enable_mbx(struct bnx2x *bp, u8 abs_vfid);
/* CORE VF API */
@@ -487,162 +402,6 @@ int bnx2x_vf_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
int bnx2x_vf_init(struct bnx2x *bp, struct bnx2x_virtf *vf,
dma_addr_t *sb_map);
-/* VFOP generic helpers */
-#define bnx2x_vfop_default(state) do { \
- BNX2X_ERR("Bad state %d\n", (state)); \
- vfop->rc = -EINVAL; \
- goto op_err; \
- } while (0)
-
-enum {
- VFOP_DONE,
- VFOP_CONT,
- VFOP_VERIFY_PEND,
-};
-
-#define bnx2x_vfop_finalize(vf, rc, next) do { \
- if ((rc) < 0) \
- goto op_err; \
- else if ((rc) > 0) \
- goto op_pending; \
- else if ((next) == VFOP_DONE) \
- goto op_done; \
- else if ((next) == VFOP_VERIFY_PEND) \
- BNX2X_ERR("expected pending\n"); \
- else { \
- DP(BNX2X_MSG_IOV, "no ramrod. Scheduling\n"); \
- atomic_set(&vf->op_in_progress, 1); \
- queue_delayed_work(bnx2x_wq, &bp->sp_task, 0); \
- return; \
- } \
- } while (0)
-
-#define bnx2x_vfop_opset(first_state, trans_hndlr, done_hndlr) \
- do { \
- vfop->state = first_state; \
- vfop->op_p = &vf->op_params; \
- vfop->transition = trans_hndlr; \
- vfop->done = done_hndlr; \
- } while (0)
-
-static inline struct bnx2x_vfop *bnx2x_vfop_cur(struct bnx2x *bp,
- struct bnx2x_virtf *vf)
-{
- WARN(!mutex_is_locked(&vf->op_mutex), "about to access vf op linked list but mutex was not locked!");
- WARN_ON(list_empty(&vf->op_list_head));
- return list_first_entry(&vf->op_list_head, struct bnx2x_vfop, link);
-}
-
-static inline struct bnx2x_vfop *bnx2x_vfop_add(struct bnx2x *bp,
- struct bnx2x_virtf *vf)
-{
- struct bnx2x_vfop *vfop = kzalloc(sizeof(*vfop), GFP_KERNEL);
-
- WARN(!mutex_is_locked(&vf->op_mutex), "about to access vf op linked list but mutex was not locked!");
- if (vfop) {
- INIT_LIST_HEAD(&vfop->link);
- list_add(&vfop->link, &vf->op_list_head);
- }
- return vfop;
-}
-
-static inline void bnx2x_vfop_end(struct bnx2x *bp, struct bnx2x_virtf *vf,
- struct bnx2x_vfop *vfop)
-{
- /* rc < 0 - error, otherwise set to 0 */
- DP(BNX2X_MSG_IOV, "rc was %d\n", vfop->rc);
- if (vfop->rc >= 0)
- vfop->rc = 0;
- DP(BNX2X_MSG_IOV, "rc is now %d\n", vfop->rc);
-
- /* unlink the current op context and propagate error code
- * must be done before invoking the 'done()' handler
- */
- WARN(!mutex_is_locked(&vf->op_mutex),
- "about to access vf op linked list but mutex was not locked!");
- list_del(&vfop->link);
-
- if (list_empty(&vf->op_list_head)) {
- DP(BNX2X_MSG_IOV, "list was empty %d\n", vfop->rc);
- vf->op_rc = vfop->rc;
- DP(BNX2X_MSG_IOV, "copying rc vf->op_rc %d, vfop->rc %d\n",
- vf->op_rc, vfop->rc);
- } else {
- struct bnx2x_vfop *cur_vfop;
-
- DP(BNX2X_MSG_IOV, "list not empty %d\n", vfop->rc);
- cur_vfop = bnx2x_vfop_cur(bp, vf);
- cur_vfop->rc = vfop->rc;
- DP(BNX2X_MSG_IOV, "copying rc vf->op_rc %d, vfop->rc %d\n",
- vf->op_rc, vfop->rc);
- }
-
- /* invoke done handler */
- if (vfop->done) {
- DP(BNX2X_MSG_IOV, "calling done handler\n");
- vfop->done(bp, vf);
- } else {
- /* there is no done handler for the operation to unlock
- * the mutex. Must have gotten here from PF initiated VF RELEASE
- */
- bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_RELEASE_VF);
- }
-
- DP(BNX2X_MSG_IOV, "done handler complete. vf->op_rc %d, vfop->rc %d\n",
- vf->op_rc, vfop->rc);
-
- /* if this is the last nested op reset the wait_blocking flag
- * to release any blocking wrappers, only after 'done()' is invoked
- */
- if (list_empty(&vf->op_list_head)) {
- DP(BNX2X_MSG_IOV, "list was empty after done %d\n", vfop->rc);
- vf->op_wait_blocking = false;
- }
-
- kfree(vfop);
-}
-
-static inline int bnx2x_vfop_wait_blocking(struct bnx2x *bp,
- struct bnx2x_virtf *vf)
-{
- /* can take a while if any port is running */
- int cnt = 5000;
-
- might_sleep();
- while (cnt--) {
- if (vf->op_wait_blocking == false) {
-#ifdef BNX2X_STOP_ON_ERROR
- DP(BNX2X_MSG_IOV, "exit (cnt %d)\n", 5000 - cnt);
-#endif
- return 0;
- }
- usleep_range(1000, 2000);
-
- if (bp->panic)
- return -EIO;
- }
-
- /* timeout! */
-#ifdef BNX2X_STOP_ON_ERROR
- bnx2x_panic();
-#endif
-
- return -EBUSY;
-}
-
-static inline int bnx2x_vfop_transition(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- vfop_handler_t transition,
- bool block)
-{
- if (block)
- vf->op_wait_blocking = true;
- transition(bp, vf);
- if (block)
- return bnx2x_vfop_wait_blocking(bp, vf);
- return 0;
-}
-
/* VFOP queue construction helpers */
void bnx2x_vfop_qctor_dump_tx(struct bnx2x *bp, struct bnx2x_virtf *vf,
struct bnx2x_queue_init_params *init_params,
@@ -657,59 +416,41 @@ void bnx2x_vfop_qctor_dump_rx(struct bnx2x *bp, struct bnx2x_virtf *vf,
void bnx2x_vfop_qctor_prep(struct bnx2x *bp,
struct bnx2x_virtf *vf,
struct bnx2x_vf_queue *q,
- struct bnx2x_vfop_qctor_params *p,
+ struct bnx2x_vf_queue_construct_params *p,
unsigned long q_type);
-int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd,
- struct bnx2x_vfop_filters *macs,
- int qid, bool drv_only);
-
-int bnx2x_vfop_vlan_list_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd,
- struct bnx2x_vfop_filters *vlans,
- int qid, bool drv_only);
-
-int bnx2x_vfop_qsetup_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd,
- int qid);
-
-int bnx2x_vfop_qdown_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd,
- int qid);
-
-int bnx2x_vfop_mcast_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd,
- bnx2x_mac_addr_t *mcasts,
- int mcast_num, bool drv_only);
-
-int bnx2x_vfop_rxmode_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd,
- int qid, unsigned long accept_flags);
-
-int bnx2x_vfop_close_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd);
-
-int bnx2x_vfop_release_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd);
-int bnx2x_vfop_rss_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd);
+int bnx2x_vf_mac_vlan_config_list(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct bnx2x_vf_mac_vlan_filters *filters,
+ int qid, bool drv_only);
+
+int bnx2x_vf_queue_setup(struct bnx2x *bp, struct bnx2x_virtf *vf, int qid,
+ struct bnx2x_vf_queue_construct_params *qctor);
+
+int bnx2x_vf_queue_teardown(struct bnx2x *bp, struct bnx2x_virtf *vf, int qid);
+
+int bnx2x_vf_mcast(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ bnx2x_mac_addr_t *mcasts, int mc_num, bool drv_only);
+
+int bnx2x_vf_rxmode(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ int qid, unsigned long accept_flags);
+
+int bnx2x_vf_close(struct bnx2x *bp, struct bnx2x_virtf *vf);
+
+int bnx2x_vf_free(struct bnx2x *bp, struct bnx2x_virtf *vf);
+
+int bnx2x_vf_rss_update(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct bnx2x_config_rss_params *rss);
+
+int bnx2x_vf_tpa_update(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct vfpf_tpa_tlv *tlv,
+ struct bnx2x_queue_update_tpa_params *params);
/* VF release ~ VF close + VF release-resources
*
* Release is the ultimate SW shutdown and is called whenever an
* irrecoverable error is encountered.
*/
-void bnx2x_vf_release(struct bnx2x *bp, struct bnx2x_virtf *vf, bool block);
+int bnx2x_vf_release(struct bnx2x *bp, struct bnx2x_virtf *vf);
int bnx2x_vf_idx_by_abs_fid(struct bnx2x *bp, u16 abs_vfid);
u8 bnx2x_vf_max_queue_cnt(struct bnx2x *bp, struct bnx2x_virtf *vf);
@@ -772,18 +513,20 @@ void bnx2x_pf_set_vfs_vlan(struct bnx2x *bp);
int bnx2x_sriov_configure(struct pci_dev *dev, int num_vfs);
void bnx2x_iov_channel_down(struct bnx2x *bp);
+void bnx2x_iov_task(struct work_struct *work);
+
+void bnx2x_schedule_iov_task(struct bnx2x *bp, enum bnx2x_iov_flag flag);
+
#else /* CONFIG_BNX2X_SRIOV */
static inline void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
struct bnx2x_queue_sp_obj **q_obj) {}
-static inline void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid,
- bool queue_work) {}
static inline void bnx2x_vf_handle_flr_event(struct bnx2x *bp) {}
static inline int bnx2x_iov_eq_sp_event(struct bnx2x *bp,
union event_ring_elem *elem) {return 1; }
-static inline void bnx2x_iov_sp_task(struct bnx2x *bp) {}
-static inline void bnx2x_vf_mbx(struct bnx2x *bp,
- struct vf_pf_event_data *vfpf_event) {}
+static inline void bnx2x_vf_mbx(struct bnx2x *bp) {}
+static inline void bnx2x_vf_mbx_schedule(struct bnx2x *bp,
+ struct vf_pf_event_data *vfpf_event) {}
static inline int bnx2x_iov_init_ilt(struct bnx2x *bp, u16 line) {return line; }
static inline void bnx2x_iov_init_dq(struct bnx2x *bp) {}
static inline int bnx2x_iov_alloc_mem(struct bnx2x *bp) {return 0; }
@@ -830,5 +573,8 @@ static inline void bnx2x_pf_set_vfs_vlan(struct bnx2x *bp) {}
static inline int bnx2x_sriov_configure(struct pci_dev *dev, int num_vfs) {return 0; }
static inline void bnx2x_iov_channel_down(struct bnx2x *bp) {}
+static inline void bnx2x_iov_task(struct work_struct *work) {}
+static inline void bnx2x_schedule_iov_task(struct bnx2x *bp, enum bnx2x_iov_flag flag) {}
+
#endif /* CONFIG_BNX2X_SRIOV */
#endif /* bnx2x_sriov.h */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
index 3fa6c2a2a5a9..0622884596b2 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
@@ -548,6 +548,7 @@ static void bnx2x_leading_vfq_init(struct bnx2x *bp, struct bnx2x_virtf *vf,
vf->leading_rss = cl_id;
q->is_leading = true;
+ q->sp_initialized = true;
}
/* ask the pf to open a queue for the vf */
@@ -672,6 +673,7 @@ static int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx)
out:
bnx2x_vfpf_finalize(bp, &req->first_tlv);
+
return rc;
}
@@ -894,29 +896,16 @@ int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp)
DP(NETIF_MSG_IFUP, "Rx mode is %d\n", mode);
- switch (mode) {
- case BNX2X_RX_MODE_NONE: /* no Rx */
+ /* Ignore everything accept MODE_NONE */
+ if (mode == BNX2X_RX_MODE_NONE) {
req->rx_mask = VFPF_RX_MASK_ACCEPT_NONE;
- break;
- case BNX2X_RX_MODE_NORMAL:
+ } else {
+ /* Current PF driver will not look at the specific flags,
+ * but they are required when working with older drivers on hv.
+ */
req->rx_mask = VFPF_RX_MASK_ACCEPT_MATCHED_MULTICAST;
req->rx_mask |= VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST;
req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
- break;
- case BNX2X_RX_MODE_ALLMULTI:
- req->rx_mask = VFPF_RX_MASK_ACCEPT_ALL_MULTICAST;
- req->rx_mask |= VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST;
- req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
- break;
- case BNX2X_RX_MODE_PROMISC:
- req->rx_mask = VFPF_RX_MASK_ACCEPT_ALL_UNICAST;
- req->rx_mask |= VFPF_RX_MASK_ACCEPT_ALL_MULTICAST;
- req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
- break;
- default:
- BNX2X_ERR("BAD rx mode (%d)\n", mode);
- rc = -EINVAL;
- goto out;
}
req->flags |= VFPF_SET_Q_FILTERS_RX_MASK_CHANGED;
@@ -937,7 +926,7 @@ int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp)
BNX2X_ERR("Set Rx mode failed: %d\n", resp->hdr.status);
rc = -EINVAL;
}
-out:
+
bnx2x_vfpf_finalize(bp, &req->first_tlv);
return rc;
@@ -1047,7 +1036,8 @@ static void bnx2x_vf_mbx_resp_single_tlv(struct bnx2x *bp,
}
static void bnx2x_vf_mbx_resp_send_msg(struct bnx2x *bp,
- struct bnx2x_virtf *vf)
+ struct bnx2x_virtf *vf,
+ int vf_rc)
{
struct bnx2x_vf_mbx *mbx = BP_VF_MBX(bp, vf->index);
struct pfvf_general_resp_tlv *resp = &mbx->msg->resp.general_resp;
@@ -1059,7 +1049,7 @@ static void bnx2x_vf_mbx_resp_send_msg(struct bnx2x *bp,
DP(BNX2X_MSG_IOV, "mailbox vf address hi 0x%x, lo 0x%x, offset 0x%x\n",
mbx->vf_addr_hi, mbx->vf_addr_lo, mbx->first_tlv.resp_msg_offset);
- resp->hdr.status = bnx2x_pfvf_status_codes(vf->op_rc);
+ resp->hdr.status = bnx2x_pfvf_status_codes(vf_rc);
/* send response */
vf_addr = HILO_U64(mbx->vf_addr_hi, mbx->vf_addr_lo) +
@@ -1088,9 +1078,6 @@ static void bnx2x_vf_mbx_resp_send_msg(struct bnx2x *bp,
storm_memset_vf_mbx_ack(bp, vf->abs_vfid);
mmiowb();
- /* initiate dmae to send the response */
- mbx->flags &= ~VF_MSG_INPROCESS;
-
/* copy the response header including status-done field,
* must be last dmae, must be after FW is acked
*/
@@ -1110,14 +1097,15 @@ static void bnx2x_vf_mbx_resp_send_msg(struct bnx2x *bp,
return;
mbx_error:
- bnx2x_vf_release(bp, vf, false); /* non blocking */
+ bnx2x_vf_release(bp, vf);
}
static void bnx2x_vf_mbx_resp(struct bnx2x *bp,
- struct bnx2x_virtf *vf)
+ struct bnx2x_virtf *vf,
+ int rc)
{
bnx2x_vf_mbx_resp_single_tlv(bp, vf);
- bnx2x_vf_mbx_resp_send_msg(bp, vf);
+ bnx2x_vf_mbx_resp_send_msg(bp, vf, rc);
}
static void bnx2x_vf_mbx_resp_phys_port(struct bnx2x *bp,
@@ -1159,7 +1147,8 @@ static void bnx2x_vf_mbx_acquire_resp(struct bnx2x *bp, struct bnx2x_virtf *vf,
resp->pfdev_info.db_size = bp->db_size;
resp->pfdev_info.indices_per_sb = HC_SB_MAX_INDICES_E2;
resp->pfdev_info.pf_cap = (PFVF_CAP_RSS |
- /* PFVF_CAP_DHC |*/ PFVF_CAP_TPA);
+ PFVF_CAP_TPA |
+ PFVF_CAP_TPA_UPDATE);
bnx2x_fill_fw_str(bp, resp->pfdev_info.fw_ver,
sizeof(resp->pfdev_info.fw_ver));
@@ -1240,8 +1229,7 @@ static void bnx2x_vf_mbx_acquire_resp(struct bnx2x *bp, struct bnx2x_virtf *vf,
sizeof(struct channel_list_end_tlv));
/* send the response */
- vf->op_rc = vfop_status;
- bnx2x_vf_mbx_resp_send_msg(bp, vf);
+ bnx2x_vf_mbx_resp_send_msg(bp, vf, vfop_status);
}
static void bnx2x_vf_mbx_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
@@ -1273,19 +1261,20 @@ static void bnx2x_vf_mbx_init_vf(struct bnx2x *bp, struct bnx2x_virtf *vf,
struct bnx2x_vf_mbx *mbx)
{
struct vfpf_init_tlv *init = &mbx->msg->req.init;
+ int rc;
/* record ghost addresses from vf message */
vf->spq_map = init->spq_addr;
vf->fw_stat_map = init->stats_addr;
vf->stats_stride = init->stats_stride;
- vf->op_rc = bnx2x_vf_init(bp, vf, (dma_addr_t *)init->sb_addr);
+ rc = bnx2x_vf_init(bp, vf, (dma_addr_t *)init->sb_addr);
/* set VF multiqueue statistics collection mode */
if (init->flags & VFPF_INIT_FLG_STATS_COALESCE)
vf->cfg_flags |= VF_CFG_STATS_COALESCE;
/* response */
- bnx2x_vf_mbx_resp(bp, vf);
+ bnx2x_vf_mbx_resp(bp, vf, rc);
}
/* convert MBX queue-flags to standard SP queue-flags */
@@ -1320,16 +1309,14 @@ static void bnx2x_vf_mbx_setup_q(struct bnx2x *bp, struct bnx2x_virtf *vf,
struct bnx2x_vf_mbx *mbx)
{
struct vfpf_setup_q_tlv *setup_q = &mbx->msg->req.setup_q;
- struct bnx2x_vfop_cmd cmd = {
- .done = bnx2x_vf_mbx_resp,
- .block = false,
- };
+ struct bnx2x_vf_queue_construct_params qctor;
+ int rc = 0;
/* verify vf_qid */
if (setup_q->vf_qid >= vf_rxq_count(vf)) {
BNX2X_ERR("vf_qid %d invalid, max queue count is %d\n",
setup_q->vf_qid, vf_rxq_count(vf));
- vf->op_rc = -EINVAL;
+ rc = -EINVAL;
goto response;
}
@@ -1347,9 +1334,10 @@ static void bnx2x_vf_mbx_setup_q(struct bnx2x *bp, struct bnx2x_virtf *vf,
bnx2x_leading_vfq_init(bp, vf, q);
/* re-init the VF operation context */
- memset(&vf->op_params.qctor, 0 , sizeof(vf->op_params.qctor));
- setup_p = &vf->op_params.qctor.prep_qsetup;
- init_p = &vf->op_params.qctor.qstate.params.init;
+ memset(&qctor, 0 ,
+ sizeof(struct bnx2x_vf_queue_construct_params));
+ setup_p = &qctor.prep_qsetup;
+ init_p = &qctor.qstate.params.init;
/* activate immediately */
__set_bit(BNX2X_Q_FLG_ACTIVE, &setup_p->flags);
@@ -1435,44 +1423,34 @@ static void bnx2x_vf_mbx_setup_q(struct bnx2x *bp, struct bnx2x_virtf *vf,
q->index, q->sb_idx);
}
/* complete the preparations */
- bnx2x_vfop_qctor_prep(bp, vf, q, &vf->op_params.qctor, q_type);
+ bnx2x_vfop_qctor_prep(bp, vf, q, &qctor, q_type);
- vf->op_rc = bnx2x_vfop_qsetup_cmd(bp, vf, &cmd, q->index);
- if (vf->op_rc)
+ rc = bnx2x_vf_queue_setup(bp, vf, q->index, &qctor);
+ if (rc)
goto response;
- return;
}
response:
- bnx2x_vf_mbx_resp(bp, vf);
+ bnx2x_vf_mbx_resp(bp, vf, rc);
}
-enum bnx2x_vfop_filters_state {
- BNX2X_VFOP_MBX_Q_FILTERS_MACS,
- BNX2X_VFOP_MBX_Q_FILTERS_VLANS,
- BNX2X_VFOP_MBX_Q_FILTERS_RXMODE,
- BNX2X_VFOP_MBX_Q_FILTERS_MCAST,
- BNX2X_VFOP_MBX_Q_FILTERS_DONE
-};
-
static int bnx2x_vf_mbx_macvlan_list(struct bnx2x *bp,
struct bnx2x_virtf *vf,
struct vfpf_set_q_filters_tlv *tlv,
- struct bnx2x_vfop_filters **pfl,
+ struct bnx2x_vf_mac_vlan_filters **pfl,
u32 type_flag)
{
int i, j;
- struct bnx2x_vfop_filters *fl = NULL;
+ struct bnx2x_vf_mac_vlan_filters *fl = NULL;
size_t fsz;
- fsz = tlv->n_mac_vlan_filters * sizeof(struct bnx2x_vfop_filter) +
- sizeof(struct bnx2x_vfop_filters);
+ fsz = tlv->n_mac_vlan_filters *
+ sizeof(struct bnx2x_vf_mac_vlan_filter) +
+ sizeof(struct bnx2x_vf_mac_vlan_filters);
fl = kzalloc(fsz, GFP_KERNEL);
if (!fl)
return -ENOMEM;
- INIT_LIST_HEAD(&fl->head);
-
for (i = 0, j = 0; i < tlv->n_mac_vlan_filters; i++) {
struct vfpf_q_mac_vlan_filter *msg_filter = &tlv->filters[i];
@@ -1480,17 +1458,17 @@ static int bnx2x_vf_mbx_macvlan_list(struct bnx2x *bp,
continue;
if (type_flag == VFPF_Q_FILTER_DEST_MAC_VALID) {
fl->filters[j].mac = msg_filter->mac;
- fl->filters[j].type = BNX2X_VFOP_FILTER_MAC;
+ fl->filters[j].type = BNX2X_VF_FILTER_MAC;
} else {
fl->filters[j].vid = msg_filter->vlan_tag;
- fl->filters[j].type = BNX2X_VFOP_FILTER_VLAN;
+ fl->filters[j].type = BNX2X_VF_FILTER_VLAN;
}
fl->filters[j].add =
(msg_filter->flags & VFPF_Q_FILTER_SET_MAC) ?
true : false;
- list_add_tail(&fl->filters[j++].link, &fl->head);
+ fl->count++;
}
- if (list_empty(&fl->head))
+ if (!fl->count)
kfree(fl);
else
*pfl = fl;
@@ -1530,180 +1508,96 @@ static void bnx2x_vf_mbx_dp_q_filters(struct bnx2x *bp, int msglvl,
#define VFPF_MAC_FILTER VFPF_Q_FILTER_DEST_MAC_VALID
#define VFPF_VLAN_FILTER VFPF_Q_FILTER_VLAN_TAG_VALID
-static void bnx2x_vfop_mbx_qfilters(struct bnx2x *bp, struct bnx2x_virtf *vf)
+static int bnx2x_vf_mbx_qfilters(struct bnx2x *bp, struct bnx2x_virtf *vf)
{
- int rc;
+ int rc = 0;
struct vfpf_set_q_filters_tlv *msg =
&BP_VF_MBX(bp, vf->index)->msg->req.set_q_filters;
- struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
- enum bnx2x_vfop_filters_state state = vfop->state;
-
- struct bnx2x_vfop_cmd cmd = {
- .done = bnx2x_vfop_mbx_qfilters,
- .block = false,
- };
-
- DP(BNX2X_MSG_IOV, "STATE: %d\n", state);
-
- if (vfop->rc < 0)
- goto op_err;
+ /* check for any mac/vlan changes */
+ if (msg->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED) {
+ /* build mac list */
+ struct bnx2x_vf_mac_vlan_filters *fl = NULL;
- switch (state) {
- case BNX2X_VFOP_MBX_Q_FILTERS_MACS:
- /* next state */
- vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_VLANS;
+ rc = bnx2x_vf_mbx_macvlan_list(bp, vf, msg, &fl,
+ VFPF_MAC_FILTER);
+ if (rc)
+ goto op_err;
- /* check for any vlan/mac changes */
- if (msg->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED) {
- /* build mac list */
- struct bnx2x_vfop_filters *fl = NULL;
+ if (fl) {
- vfop->rc = bnx2x_vf_mbx_macvlan_list(bp, vf, msg, &fl,
- VFPF_MAC_FILTER);
- if (vfop->rc)
+ /* set mac list */
+ rc = bnx2x_vf_mac_vlan_config_list(bp, vf, fl,
+ msg->vf_qid,
+ false);
+ if (rc)
goto op_err;
-
- if (fl) {
- /* set mac list */
- rc = bnx2x_vfop_mac_list_cmd(bp, vf, &cmd, fl,
- msg->vf_qid,
- false);
- if (rc) {
- vfop->rc = rc;
- goto op_err;
- }
- return;
- }
}
- /* fall through */
- case BNX2X_VFOP_MBX_Q_FILTERS_VLANS:
- /* next state */
- vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_RXMODE;
+ /* build vlan list */
+ fl = NULL;
- /* check for any vlan/mac changes */
- if (msg->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED) {
- /* build vlan list */
- struct bnx2x_vfop_filters *fl = NULL;
-
- vfop->rc = bnx2x_vf_mbx_macvlan_list(bp, vf, msg, &fl,
- VFPF_VLAN_FILTER);
- if (vfop->rc)
+ rc = bnx2x_vf_mbx_macvlan_list(bp, vf, msg, &fl,
+ VFPF_VLAN_FILTER);
+ if (rc)
+ goto op_err;
+
+ if (fl) {
+ /* set vlan list */
+ rc = bnx2x_vf_mac_vlan_config_list(bp, vf, fl,
+ msg->vf_qid,
+ false);
+ if (rc)
goto op_err;
-
- if (fl) {
- /* set vlan list */
- rc = bnx2x_vfop_vlan_list_cmd(bp, vf, &cmd, fl,
- msg->vf_qid,
- false);
- if (rc) {
- vfop->rc = rc;
- goto op_err;
- }
- return;
- }
}
- /* fall through */
-
- case BNX2X_VFOP_MBX_Q_FILTERS_RXMODE:
- /* next state */
- vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_MCAST;
-
- if (msg->flags & VFPF_SET_Q_FILTERS_RX_MASK_CHANGED) {
- unsigned long accept = 0;
- struct pf_vf_bulletin_content *bulletin =
- BP_VF_BULLETIN(bp, vf->index);
-
- /* covert VF-PF if mask to bnx2x accept flags */
- if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST)
- __set_bit(BNX2X_ACCEPT_UNICAST, &accept);
-
- if (msg->rx_mask &
- VFPF_RX_MASK_ACCEPT_MATCHED_MULTICAST)
- __set_bit(BNX2X_ACCEPT_MULTICAST, &accept);
-
- if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_ALL_UNICAST)
- __set_bit(BNX2X_ACCEPT_ALL_UNICAST, &accept);
-
- if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_ALL_MULTICAST)
- __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &accept);
+ }
- if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_BROADCAST)
- __set_bit(BNX2X_ACCEPT_BROADCAST, &accept);
+ if (msg->flags & VFPF_SET_Q_FILTERS_RX_MASK_CHANGED) {
+ unsigned long accept = 0;
+ struct pf_vf_bulletin_content *bulletin =
+ BP_VF_BULLETIN(bp, vf->index);
- /* A packet arriving the vf's mac should be accepted
- * with any vlan, unless a vlan has already been
- * configured.
- */
- if (!(bulletin->valid_bitmap & (1 << VLAN_VALID)))
- __set_bit(BNX2X_ACCEPT_ANY_VLAN, &accept);
-
- /* set rx-mode */
- rc = bnx2x_vfop_rxmode_cmd(bp, vf, &cmd,
- msg->vf_qid, accept);
- if (rc) {
- vfop->rc = rc;
- goto op_err;
- }
- return;
+ /* Ignore VF requested mode; instead set a regular mode */
+ if (msg->rx_mask != VFPF_RX_MASK_ACCEPT_NONE) {
+ __set_bit(BNX2X_ACCEPT_UNICAST, &accept);
+ __set_bit(BNX2X_ACCEPT_MULTICAST, &accept);
+ __set_bit(BNX2X_ACCEPT_BROADCAST, &accept);
}
- /* fall through */
-
- case BNX2X_VFOP_MBX_Q_FILTERS_MCAST:
- /* next state */
- vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_DONE;
-
- if (msg->flags & VFPF_SET_Q_FILTERS_MULTICAST_CHANGED) {
- /* set mcasts */
- rc = bnx2x_vfop_mcast_cmd(bp, vf, &cmd, msg->multicast,
- msg->n_multicast, false);
- if (rc) {
- vfop->rc = rc;
- goto op_err;
- }
- return;
- }
- /* fall through */
-op_done:
- case BNX2X_VFOP_MBX_Q_FILTERS_DONE:
- bnx2x_vfop_end(bp, vf, vfop);
- return;
-op_err:
- BNX2X_ERR("QFILTERS[%d:%d] error: rc %d\n",
- vf->abs_vfid, msg->vf_qid, vfop->rc);
- goto op_done;
- default:
- bnx2x_vfop_default(state);
+ /* A packet arriving the vf's mac should be accepted
+ * with any vlan, unless a vlan has already been
+ * configured.
+ */
+ if (!(bulletin->valid_bitmap & (1 << VLAN_VALID)))
+ __set_bit(BNX2X_ACCEPT_ANY_VLAN, &accept);
+
+ /* set rx-mode */
+ rc = bnx2x_vf_rxmode(bp, vf, msg->vf_qid, accept);
+ if (rc)
+ goto op_err;
}
-}
-static int bnx2x_vfop_mbx_qfilters_cmd(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vfop_cmd *cmd)
-{
- struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
- if (vfop) {
- bnx2x_vfop_opset(BNX2X_VFOP_MBX_Q_FILTERS_MACS,
- bnx2x_vfop_mbx_qfilters, cmd->done);
- return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_mbx_qfilters,
- cmd->block);
+ if (msg->flags & VFPF_SET_Q_FILTERS_MULTICAST_CHANGED) {
+ /* set mcasts */
+ rc = bnx2x_vf_mcast(bp, vf, msg->multicast,
+ msg->n_multicast, false);
+ if (rc)
+ goto op_err;
}
- return -ENOMEM;
+op_err:
+ if (rc)
+ BNX2X_ERR("QFILTERS[%d:%d] error: rc %d\n",
+ vf->abs_vfid, msg->vf_qid, rc);
+ return rc;
}
-static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp,
- struct bnx2x_virtf *vf,
- struct bnx2x_vf_mbx *mbx)
+static int bnx2x_filters_validate_mac(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct vfpf_set_q_filters_tlv *filters)
{
- struct vfpf_set_q_filters_tlv *filters = &mbx->msg->req.set_q_filters;
struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vf->index);
- struct bnx2x_vfop_cmd cmd = {
- .done = bnx2x_vf_mbx_resp,
- .block = false,
- };
+ int rc = 0;
/* if a mac was already set for this VF via the set vf mac ndo, we only
* accept mac configurations of that mac. Why accept them at all?
@@ -1715,7 +1609,7 @@ static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp,
if (filters->n_mac_vlan_filters > 1) {
BNX2X_ERR("VF[%d] requested the addition of multiple macs after set_vf_mac ndo was called\n",
vf->abs_vfid);
- vf->op_rc = -EPERM;
+ rc = -EPERM;
goto response;
}
@@ -1725,10 +1619,22 @@ static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp,
BNX2X_ERR("VF[%d] requested the addition of a mac address not matching the one configured by set_vf_mac ndo\n",
vf->abs_vfid);
- vf->op_rc = -EPERM;
+ rc = -EPERM;
goto response;
}
}
+
+response:
+ return rc;
+}
+
+static int bnx2x_filters_validate_vlan(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct vfpf_set_q_filters_tlv *filters)
+{
+ struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vf->index);
+ int rc = 0;
+
/* if vlan was set by hypervisor we don't allow guest to config vlan */
if (bulletin->valid_bitmap & 1 << VLAN_VALID) {
int i;
@@ -1739,14 +1645,35 @@ static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp,
VFPF_Q_FILTER_VLAN_TAG_VALID) {
BNX2X_ERR("VF[%d] attempted to configure vlan but one was already set by Hypervisor. Aborting request\n",
vf->abs_vfid);
- vf->op_rc = -EPERM;
+ rc = -EPERM;
goto response;
}
}
}
/* verify vf_qid */
- if (filters->vf_qid > vf_rxq_count(vf))
+ if (filters->vf_qid > vf_rxq_count(vf)) {
+ rc = -EPERM;
+ goto response;
+ }
+
+response:
+ return rc;
+}
+
+static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vf_mbx *mbx)
+{
+ struct vfpf_set_q_filters_tlv *filters = &mbx->msg->req.set_q_filters;
+ int rc;
+
+ rc = bnx2x_filters_validate_mac(bp, vf, filters);
+ if (rc)
+ goto response;
+
+ rc = bnx2x_filters_validate_vlan(bp, vf, filters);
+ if (rc)
goto response;
DP(BNX2X_MSG_IOV, "VF[%d] Q_FILTERS: queue[%d]\n",
@@ -1756,125 +1683,169 @@ static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp,
/* print q_filter message */
bnx2x_vf_mbx_dp_q_filters(bp, BNX2X_MSG_IOV, filters);
- vf->op_rc = bnx2x_vfop_mbx_qfilters_cmd(bp, vf, &cmd);
- if (vf->op_rc)
- goto response;
- return;
-
+ rc = bnx2x_vf_mbx_qfilters(bp, vf);
response:
- bnx2x_vf_mbx_resp(bp, vf);
+ bnx2x_vf_mbx_resp(bp, vf, rc);
}
static void bnx2x_vf_mbx_teardown_q(struct bnx2x *bp, struct bnx2x_virtf *vf,
struct bnx2x_vf_mbx *mbx)
{
int qid = mbx->msg->req.q_op.vf_qid;
- struct bnx2x_vfop_cmd cmd = {
- .done = bnx2x_vf_mbx_resp,
- .block = false,
- };
+ int rc;
DP(BNX2X_MSG_IOV, "VF[%d] Q_TEARDOWN: vf_qid=%d\n",
vf->abs_vfid, qid);
- vf->op_rc = bnx2x_vfop_qdown_cmd(bp, vf, &cmd, qid);
- if (vf->op_rc)
- bnx2x_vf_mbx_resp(bp, vf);
+ rc = bnx2x_vf_queue_teardown(bp, vf, qid);
+ bnx2x_vf_mbx_resp(bp, vf, rc);
}
static void bnx2x_vf_mbx_close_vf(struct bnx2x *bp, struct bnx2x_virtf *vf,
struct bnx2x_vf_mbx *mbx)
{
- struct bnx2x_vfop_cmd cmd = {
- .done = bnx2x_vf_mbx_resp,
- .block = false,
- };
+ int rc;
DP(BNX2X_MSG_IOV, "VF[%d] VF_CLOSE\n", vf->abs_vfid);
- vf->op_rc = bnx2x_vfop_close_cmd(bp, vf, &cmd);
- if (vf->op_rc)
- bnx2x_vf_mbx_resp(bp, vf);
+ rc = bnx2x_vf_close(bp, vf);
+ bnx2x_vf_mbx_resp(bp, vf, rc);
}
static void bnx2x_vf_mbx_release_vf(struct bnx2x *bp, struct bnx2x_virtf *vf,
struct bnx2x_vf_mbx *mbx)
{
- struct bnx2x_vfop_cmd cmd = {
- .done = bnx2x_vf_mbx_resp,
- .block = false,
- };
+ int rc;
DP(BNX2X_MSG_IOV, "VF[%d] VF_RELEASE\n", vf->abs_vfid);
- vf->op_rc = bnx2x_vfop_release_cmd(bp, vf, &cmd);
- if (vf->op_rc)
- bnx2x_vf_mbx_resp(bp, vf);
+ rc = bnx2x_vf_free(bp, vf);
+ bnx2x_vf_mbx_resp(bp, vf, rc);
}
static void bnx2x_vf_mbx_update_rss(struct bnx2x *bp, struct bnx2x_virtf *vf,
struct bnx2x_vf_mbx *mbx)
{
- struct bnx2x_vfop_cmd cmd = {
- .done = bnx2x_vf_mbx_resp,
- .block = false,
- };
- struct bnx2x_config_rss_params *vf_op_params = &vf->op_params.rss;
+ struct bnx2x_config_rss_params rss;
struct vfpf_rss_tlv *rss_tlv = &mbx->msg->req.update_rss;
+ int rc = 0;
if (rss_tlv->ind_table_size != T_ETH_INDIRECTION_TABLE_SIZE ||
rss_tlv->rss_key_size != T_ETH_RSS_KEY) {
BNX2X_ERR("failing rss configuration of vf %d due to size mismatch\n",
vf->index);
- vf->op_rc = -EINVAL;
+ rc = -EINVAL;
goto mbx_resp;
}
+ memset(&rss, 0, sizeof(struct bnx2x_config_rss_params));
+
/* set vfop params according to rss tlv */
- memcpy(vf_op_params->ind_table, rss_tlv->ind_table,
+ memcpy(rss.ind_table, rss_tlv->ind_table,
T_ETH_INDIRECTION_TABLE_SIZE);
- memcpy(vf_op_params->rss_key, rss_tlv->rss_key,
- sizeof(rss_tlv->rss_key));
- vf_op_params->rss_obj = &vf->rss_conf_obj;
- vf_op_params->rss_result_mask = rss_tlv->rss_result_mask;
+ memcpy(rss.rss_key, rss_tlv->rss_key, sizeof(rss_tlv->rss_key));
+ rss.rss_obj = &vf->rss_conf_obj;
+ rss.rss_result_mask = rss_tlv->rss_result_mask;
/* flags handled individually for backward/forward compatability */
- vf_op_params->rss_flags = 0;
- vf_op_params->ramrod_flags = 0;
+ rss.rss_flags = 0;
+ rss.ramrod_flags = 0;
if (rss_tlv->rss_flags & VFPF_RSS_MODE_DISABLED)
- __set_bit(BNX2X_RSS_MODE_DISABLED, &vf_op_params->rss_flags);
+ __set_bit(BNX2X_RSS_MODE_DISABLED, &rss.rss_flags);
if (rss_tlv->rss_flags & VFPF_RSS_MODE_REGULAR)
- __set_bit(BNX2X_RSS_MODE_REGULAR, &vf_op_params->rss_flags);
+ __set_bit(BNX2X_RSS_MODE_REGULAR, &rss.rss_flags);
if (rss_tlv->rss_flags & VFPF_RSS_SET_SRCH)
- __set_bit(BNX2X_RSS_SET_SRCH, &vf_op_params->rss_flags);
+ __set_bit(BNX2X_RSS_SET_SRCH, &rss.rss_flags);
if (rss_tlv->rss_flags & VFPF_RSS_IPV4)
- __set_bit(BNX2X_RSS_IPV4, &vf_op_params->rss_flags);
+ __set_bit(BNX2X_RSS_IPV4, &rss.rss_flags);
if (rss_tlv->rss_flags & VFPF_RSS_IPV4_TCP)
- __set_bit(BNX2X_RSS_IPV4_TCP, &vf_op_params->rss_flags);
+ __set_bit(BNX2X_RSS_IPV4_TCP, &rss.rss_flags);
if (rss_tlv->rss_flags & VFPF_RSS_IPV4_UDP)
- __set_bit(BNX2X_RSS_IPV4_UDP, &vf_op_params->rss_flags);
+ __set_bit(BNX2X_RSS_IPV4_UDP, &rss.rss_flags);
if (rss_tlv->rss_flags & VFPF_RSS_IPV6)
- __set_bit(BNX2X_RSS_IPV6, &vf_op_params->rss_flags);
+ __set_bit(BNX2X_RSS_IPV6, &rss.rss_flags);
if (rss_tlv->rss_flags & VFPF_RSS_IPV6_TCP)
- __set_bit(BNX2X_RSS_IPV6_TCP, &vf_op_params->rss_flags);
+ __set_bit(BNX2X_RSS_IPV6_TCP, &rss.rss_flags);
if (rss_tlv->rss_flags & VFPF_RSS_IPV6_UDP)
- __set_bit(BNX2X_RSS_IPV6_UDP, &vf_op_params->rss_flags);
+ __set_bit(BNX2X_RSS_IPV6_UDP, &rss.rss_flags);
if ((!(rss_tlv->rss_flags & VFPF_RSS_IPV4_TCP) &&
rss_tlv->rss_flags & VFPF_RSS_IPV4_UDP) ||
(!(rss_tlv->rss_flags & VFPF_RSS_IPV6_TCP) &&
rss_tlv->rss_flags & VFPF_RSS_IPV6_UDP)) {
BNX2X_ERR("about to hit a FW assert. aborting...\n");
- vf->op_rc = -EINVAL;
+ rc = -EINVAL;
goto mbx_resp;
}
- vf->op_rc = bnx2x_vfop_rss_cmd(bp, vf, &cmd);
+ rc = bnx2x_vf_rss_update(bp, vf, &rss);
+mbx_resp:
+ bnx2x_vf_mbx_resp(bp, vf, rc);
+}
+
+static int bnx2x_validate_tpa_params(struct bnx2x *bp,
+ struct vfpf_tpa_tlv *tpa_tlv)
+{
+ int rc = 0;
+
+ if (tpa_tlv->tpa_client_info.max_sges_for_packet >
+ U_ETH_MAX_SGES_FOR_PACKET) {
+ rc = -EINVAL;
+ BNX2X_ERR("TPA update: max_sges received %d, max is %d\n",
+ tpa_tlv->tpa_client_info.max_sges_for_packet,
+ U_ETH_MAX_SGES_FOR_PACKET);
+ }
+
+ if (tpa_tlv->tpa_client_info.max_tpa_queues > MAX_AGG_QS(bp)) {
+ rc = -EINVAL;
+ BNX2X_ERR("TPA update: max_tpa_queues received %d, max is %d\n",
+ tpa_tlv->tpa_client_info.max_tpa_queues,
+ MAX_AGG_QS(bp));
+ }
+
+ return rc;
+}
+
+static void bnx2x_vf_mbx_update_tpa(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct bnx2x_vf_mbx *mbx)
+{
+ struct bnx2x_queue_update_tpa_params vf_op_params;
+ struct vfpf_tpa_tlv *tpa_tlv = &mbx->msg->req.update_tpa;
+ int rc = 0;
+
+ memset(&vf_op_params, 0, sizeof(vf_op_params));
+
+ if (bnx2x_validate_tpa_params(bp, tpa_tlv))
+ goto mbx_resp;
+
+ vf_op_params.complete_on_both_clients =
+ tpa_tlv->tpa_client_info.complete_on_both_clients;
+ vf_op_params.dont_verify_thr =
+ tpa_tlv->tpa_client_info.dont_verify_thr;
+ vf_op_params.max_agg_sz =
+ tpa_tlv->tpa_client_info.max_agg_size;
+ vf_op_params.max_sges_pkt =
+ tpa_tlv->tpa_client_info.max_sges_for_packet;
+ vf_op_params.max_tpa_queues =
+ tpa_tlv->tpa_client_info.max_tpa_queues;
+ vf_op_params.sge_buff_sz =
+ tpa_tlv->tpa_client_info.sge_buff_size;
+ vf_op_params.sge_pause_thr_high =
+ tpa_tlv->tpa_client_info.sge_pause_thr_high;
+ vf_op_params.sge_pause_thr_low =
+ tpa_tlv->tpa_client_info.sge_pause_thr_low;
+ vf_op_params.tpa_mode =
+ tpa_tlv->tpa_client_info.tpa_mode;
+ vf_op_params.update_ipv4 =
+ tpa_tlv->tpa_client_info.update_ipv4;
+ vf_op_params.update_ipv6 =
+ tpa_tlv->tpa_client_info.update_ipv6;
+
+ rc = bnx2x_vf_tpa_update(bp, vf, tpa_tlv, &vf_op_params);
mbx_resp:
- if (vf->op_rc)
- bnx2x_vf_mbx_resp(bp, vf);
+ bnx2x_vf_mbx_resp(bp, vf, rc);
}
/* dispatch request */
@@ -1916,6 +1887,9 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
case CHANNEL_TLV_UPDATE_RSS:
bnx2x_vf_mbx_update_rss(bp, vf, mbx);
return;
+ case CHANNEL_TLV_UPDATE_TPA:
+ bnx2x_vf_mbx_update_tpa(bp, vf, mbx);
+ return;
}
} else {
@@ -1935,11 +1909,8 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
/* can we respond to VF (do we have an address for it?) */
if (vf->state == VF_ACQUIRED || vf->state == VF_ENABLED) {
- /* mbx_resp uses the op_rc of the VF */
- vf->op_rc = PFVF_STATUS_NOT_SUPPORTED;
-
/* notify the VF that we do not support this request */
- bnx2x_vf_mbx_resp(bp, vf);
+ bnx2x_vf_mbx_resp(bp, vf, PFVF_STATUS_NOT_SUPPORTED);
} else {
/* can't send a response since this VF is unknown to us
* just ack the FW to release the mailbox and unlock
@@ -1952,13 +1923,10 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
}
}
-/* handle new vf-pf message */
-void bnx2x_vf_mbx(struct bnx2x *bp, struct vf_pf_event_data *vfpf_event)
+void bnx2x_vf_mbx_schedule(struct bnx2x *bp,
+ struct vf_pf_event_data *vfpf_event)
{
- struct bnx2x_virtf *vf;
- struct bnx2x_vf_mbx *mbx;
u8 vf_idx;
- int rc;
DP(BNX2X_MSG_IOV,
"vf pf event received: vfid %d, address_hi %x, address lo %x",
@@ -1970,50 +1938,73 @@ void bnx2x_vf_mbx(struct bnx2x *bp, struct vf_pf_event_data *vfpf_event)
BNX2X_NR_VIRTFN(bp)) {
BNX2X_ERR("Illegal vf_id %d max allowed: %d\n",
vfpf_event->vf_id, BNX2X_NR_VIRTFN(bp));
- goto mbx_done;
+ return;
}
+
vf_idx = bnx2x_vf_idx_by_abs_fid(bp, vfpf_event->vf_id);
- mbx = BP_VF_MBX(bp, vf_idx);
- /* verify an event is not currently being processed -
- * debug failsafe only
- */
- if (mbx->flags & VF_MSG_INPROCESS) {
- BNX2X_ERR("Previous message is still being processed, vf_id %d\n",
- vfpf_event->vf_id);
- goto mbx_done;
- }
- vf = BP_VF(bp, vf_idx);
+ /* Update VFDB with current message and schedule its handling */
+ mutex_lock(&BP_VFDB(bp)->event_mutex);
+ BP_VF_MBX(bp, vf_idx)->vf_addr_hi = vfpf_event->msg_addr_hi;
+ BP_VF_MBX(bp, vf_idx)->vf_addr_lo = vfpf_event->msg_addr_lo;
+ BP_VFDB(bp)->event_occur |= (1ULL << vf_idx);
+ mutex_unlock(&BP_VFDB(bp)->event_mutex);
- /* save the VF message address */
- mbx->vf_addr_hi = vfpf_event->msg_addr_hi;
- mbx->vf_addr_lo = vfpf_event->msg_addr_lo;
- DP(BNX2X_MSG_IOV, "mailbox vf address hi 0x%x, lo 0x%x, offset 0x%x\n",
- mbx->vf_addr_hi, mbx->vf_addr_lo, mbx->first_tlv.resp_msg_offset);
+ bnx2x_schedule_iov_task(bp, BNX2X_IOV_HANDLE_VF_MSG);
+}
- /* dmae to get the VF request */
- rc = bnx2x_copy32_vf_dmae(bp, true, mbx->msg_mapping, vf->abs_vfid,
- mbx->vf_addr_hi, mbx->vf_addr_lo,
- sizeof(union vfpf_tlvs)/4);
- if (rc) {
- BNX2X_ERR("Failed to copy request VF %d\n", vf->abs_vfid);
- goto mbx_error;
- }
+/* handle new vf-pf messages */
+void bnx2x_vf_mbx(struct bnx2x *bp)
+{
+ struct bnx2x_vfdb *vfdb = BP_VFDB(bp);
+ u64 events;
+ u8 vf_idx;
+ int rc;
- /* process the VF message header */
- mbx->first_tlv = mbx->msg->req.first_tlv;
+ if (!vfdb)
+ return;
- /* Clean response buffer to refrain from falsely seeing chains */
- memset(&mbx->msg->resp, 0, sizeof(union pfvf_tlvs));
+ mutex_lock(&vfdb->event_mutex);
+ events = vfdb->event_occur;
+ vfdb->event_occur = 0;
+ mutex_unlock(&vfdb->event_mutex);
- /* dispatch the request (will prepare the response) */
- bnx2x_vf_mbx_request(bp, vf, mbx);
- goto mbx_done;
+ for_each_vf(bp, vf_idx) {
+ struct bnx2x_vf_mbx *mbx = BP_VF_MBX(bp, vf_idx);
+ struct bnx2x_virtf *vf = BP_VF(bp, vf_idx);
-mbx_error:
- bnx2x_vf_release(bp, vf, false); /* non blocking */
-mbx_done:
- return;
+ /* Handle VFs which have pending events */
+ if (!(events & (1ULL << vf_idx)))
+ continue;
+
+ DP(BNX2X_MSG_IOV,
+ "Handling vf pf event vfid %d, address: [%x:%x], resp_offset 0x%x\n",
+ vf_idx, mbx->vf_addr_hi, mbx->vf_addr_lo,
+ mbx->first_tlv.resp_msg_offset);
+
+ /* dmae to get the VF request */
+ rc = bnx2x_copy32_vf_dmae(bp, true, mbx->msg_mapping,
+ vf->abs_vfid, mbx->vf_addr_hi,
+ mbx->vf_addr_lo,
+ sizeof(union vfpf_tlvs)/4);
+ if (rc) {
+ BNX2X_ERR("Failed to copy request VF %d\n",
+ vf->abs_vfid);
+ bnx2x_vf_release(bp, vf);
+ return;
+ }
+
+ /* process the VF message header */
+ mbx->first_tlv = mbx->msg->req.first_tlv;
+
+ /* Clean response buffer to refrain from falsely
+ * seeing chains.
+ */
+ memset(&mbx->msg->resp, 0, sizeof(union pfvf_tlvs));
+
+ /* dispatch the request (will prepare the response) */
+ bnx2x_vf_mbx_request(bp, vf, mbx);
+ }
}
/* propagate local bulletin board to vf */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h
index 208568bc7a71..c922b81170e5 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h
@@ -162,6 +162,7 @@ struct pfvf_acquire_resp_tlv {
#define PFVF_CAP_RSS 0x00000001
#define PFVF_CAP_DHC 0x00000002
#define PFVF_CAP_TPA 0x00000004
+#define PFVF_CAP_TPA_UPDATE 0x00000008
char fw_ver[32];
u16 db_size;
u8 indices_per_sb;
@@ -303,6 +304,25 @@ struct vfpf_set_q_filters_tlv {
u32 rx_mask; /* see mask constants at the top of the file */
};
+struct vfpf_tpa_tlv {
+ struct vfpf_first_tlv first_tlv;
+
+ struct vf_pf_tpa_client_info {
+ aligned_u64 sge_addr[PFVF_MAX_QUEUES_PER_VF];
+ u8 update_ipv4;
+ u8 update_ipv6;
+ u8 max_tpa_queues;
+ u8 max_sges_for_packet;
+ u8 complete_on_both_clients;
+ u8 dont_verify_thr;
+ u8 tpa_mode;
+ u16 sge_buff_size;
+ u16 max_agg_size;
+ u16 sge_pause_thr_low;
+ u16 sge_pause_thr_high;
+ } tpa_client_info;
+};
+
/* close VF (disable VF) */
struct vfpf_close_tlv {
struct vfpf_first_tlv first_tlv;
@@ -331,6 +351,7 @@ union vfpf_tlvs {
struct vfpf_set_q_filters_tlv set_q_filters;
struct vfpf_release_tlv release;
struct vfpf_rss_tlv update_rss;
+ struct vfpf_tpa_tlv update_tpa;
struct channel_list_end_tlv list_end;
struct tlv_buffer_size tlv_buf_size;
};
@@ -405,6 +426,7 @@ enum channel_tlvs {
CHANNEL_TLV_PF_SET_VLAN,
CHANNEL_TLV_UPDATE_RSS,
CHANNEL_TLV_PHYS_PORT_ID,
+ CHANNEL_TLV_UPDATE_TPA,
CHANNEL_TLV_MAX
};
diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c
index fcf9105a5476..09f3fefcbf9c 100644
--- a/drivers/net/ethernet/broadcom/cnic.c
+++ b/drivers/net/ethernet/broadcom/cnic.c
@@ -1,6 +1,6 @@
/* cnic.c: Broadcom CNIC core network driver.
*
- * Copyright (c) 2006-2013 Broadcom Corporation
+ * Copyright (c) 2006-2014 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
@@ -342,7 +342,7 @@ static int cnic_send_nlmsg(struct cnic_local *cp, u32 type,
while (retry < 3) {
rc = 0;
rcu_read_lock();
- ulp_ops = rcu_dereference(cnic_ulp_tbl[CNIC_ULP_ISCSI]);
+ ulp_ops = rcu_dereference(cp->ulp_ops[CNIC_ULP_ISCSI]);
if (ulp_ops)
rc = ulp_ops->iscsi_nl_send_msg(
cp->ulp_handle[CNIC_ULP_ISCSI],
@@ -726,7 +726,7 @@ static void cnic_free_dma(struct cnic_dev *dev, struct cnic_dma *dma)
for (i = 0; i < dma->num_pages; i++) {
if (dma->pg_arr[i]) {
- dma_free_coherent(&dev->pcidev->dev, BNX2_PAGE_SIZE,
+ dma_free_coherent(&dev->pcidev->dev, CNIC_PAGE_SIZE,
dma->pg_arr[i], dma->pg_map_arr[i]);
dma->pg_arr[i] = NULL;
}
@@ -785,7 +785,7 @@ static int cnic_alloc_dma(struct cnic_dev *dev, struct cnic_dma *dma,
for (i = 0; i < pages; i++) {
dma->pg_arr[i] = dma_alloc_coherent(&dev->pcidev->dev,
- BNX2_PAGE_SIZE,
+ CNIC_PAGE_SIZE,
&dma->pg_map_arr[i],
GFP_ATOMIC);
if (dma->pg_arr[i] == NULL)
@@ -794,8 +794,8 @@ static int cnic_alloc_dma(struct cnic_dev *dev, struct cnic_dma *dma,
if (!use_pg_tbl)
return 0;
- dma->pgtbl_size = ((pages * 8) + BNX2_PAGE_SIZE - 1) &
- ~(BNX2_PAGE_SIZE - 1);
+ dma->pgtbl_size = ((pages * 8) + CNIC_PAGE_SIZE - 1) &
+ ~(CNIC_PAGE_SIZE - 1);
dma->pgtbl = dma_alloc_coherent(&dev->pcidev->dev, dma->pgtbl_size,
&dma->pgtbl_map, GFP_ATOMIC);
if (dma->pgtbl == NULL)
@@ -900,8 +900,8 @@ static int cnic_alloc_context(struct cnic_dev *dev)
if (BNX2_CHIP(cp) == BNX2_CHIP_5709) {
int i, k, arr_size;
- cp->ctx_blk_size = BNX2_PAGE_SIZE;
- cp->cids_per_blk = BNX2_PAGE_SIZE / 128;
+ cp->ctx_blk_size = CNIC_PAGE_SIZE;
+ cp->cids_per_blk = CNIC_PAGE_SIZE / 128;
arr_size = BNX2_MAX_CID / cp->cids_per_blk *
sizeof(struct cnic_ctx);
cp->ctx_arr = kzalloc(arr_size, GFP_KERNEL);
@@ -933,7 +933,7 @@ static int cnic_alloc_context(struct cnic_dev *dev)
for (i = 0; i < cp->ctx_blks; i++) {
cp->ctx_arr[i].ctx =
dma_alloc_coherent(&dev->pcidev->dev,
- BNX2_PAGE_SIZE,
+ CNIC_PAGE_SIZE,
&cp->ctx_arr[i].mapping,
GFP_KERNEL);
if (cp->ctx_arr[i].ctx == NULL)
@@ -1013,7 +1013,7 @@ static int __cnic_alloc_uio_rings(struct cnic_uio_dev *udev, int pages)
if (udev->l2_ring)
return 0;
- udev->l2_ring_size = pages * BNX2_PAGE_SIZE;
+ udev->l2_ring_size = pages * CNIC_PAGE_SIZE;
udev->l2_ring = dma_alloc_coherent(&udev->pdev->dev, udev->l2_ring_size,
&udev->l2_ring_map,
GFP_KERNEL | __GFP_COMP);
@@ -1021,7 +1021,7 @@ static int __cnic_alloc_uio_rings(struct cnic_uio_dev *udev, int pages)
return -ENOMEM;
udev->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size;
- udev->l2_buf_size = PAGE_ALIGN(udev->l2_buf_size);
+ udev->l2_buf_size = CNIC_PAGE_ALIGN(udev->l2_buf_size);
udev->l2_buf = dma_alloc_coherent(&udev->pdev->dev, udev->l2_buf_size,
&udev->l2_buf_map,
GFP_KERNEL | __GFP_COMP);
@@ -1102,7 +1102,7 @@ static int cnic_init_uio(struct cnic_dev *dev)
uinfo->mem[0].size = MB_GET_CID_ADDR(TX_TSS_CID +
TX_MAX_TSS_RINGS + 1);
uinfo->mem[1].addr = (unsigned long) cp->status_blk.gen &
- PAGE_MASK;
+ CNIC_PAGE_MASK;
if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX)
uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE * 9;
else
@@ -1113,7 +1113,7 @@ static int cnic_init_uio(struct cnic_dev *dev)
uinfo->mem[0].size = pci_resource_len(dev->pcidev, 0);
uinfo->mem[1].addr = (unsigned long) cp->bnx2x_def_status_blk &
- PAGE_MASK;
+ CNIC_PAGE_MASK;
uinfo->mem[1].size = sizeof(*cp->bnx2x_def_status_blk);
uinfo->name = "bnx2x_cnic";
@@ -1267,14 +1267,14 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
for (i = MAX_ISCSI_TBL_SZ; i < cp->max_cid_space; i++)
cp->ctx_tbl[i].ulp_proto_id = CNIC_ULP_FCOE;
- pages = PAGE_ALIGN(cp->max_cid_space * CNIC_KWQ16_DATA_SIZE) /
- PAGE_SIZE;
+ pages = CNIC_PAGE_ALIGN(cp->max_cid_space * CNIC_KWQ16_DATA_SIZE) /
+ CNIC_PAGE_SIZE;
ret = cnic_alloc_dma(dev, kwq_16_dma, pages, 0);
if (ret)
return -ENOMEM;
- n = PAGE_SIZE / CNIC_KWQ16_DATA_SIZE;
+ n = CNIC_PAGE_SIZE / CNIC_KWQ16_DATA_SIZE;
for (i = 0, j = 0; i < cp->max_cid_space; i++) {
long off = CNIC_KWQ16_DATA_SIZE * (i % n);
@@ -1296,7 +1296,7 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
goto error;
}
- pages = PAGE_ALIGN(BNX2X_ISCSI_GLB_BUF_SIZE) / PAGE_SIZE;
+ pages = CNIC_PAGE_ALIGN(BNX2X_ISCSI_GLB_BUF_SIZE) / CNIC_PAGE_SIZE;
ret = cnic_alloc_dma(dev, &cp->gbl_buf_info, pages, 0);
if (ret)
goto error;
@@ -1466,8 +1466,8 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
cp->r2tq_size = cp->num_iscsi_tasks * BNX2X_ISCSI_MAX_PENDING_R2TS *
BNX2X_ISCSI_R2TQE_SIZE;
cp->hq_size = cp->num_ccells * BNX2X_ISCSI_HQ_BD_SIZE;
- pages = PAGE_ALIGN(cp->hq_size) / PAGE_SIZE;
- hq_bds = pages * (PAGE_SIZE / BNX2X_ISCSI_HQ_BD_SIZE);
+ pages = CNIC_PAGE_ALIGN(cp->hq_size) / CNIC_PAGE_SIZE;
+ hq_bds = pages * (CNIC_PAGE_SIZE / BNX2X_ISCSI_HQ_BD_SIZE);
cp->num_cqs = req1->num_cqs;
if (!dev->max_iscsi_conn)
@@ -1477,9 +1477,9 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
CNIC_WR16(dev, BAR_TSTRORM_INTMEM + TSTORM_ISCSI_RQ_SIZE_OFFSET(pfid),
req1->rq_num_wqes);
CNIC_WR16(dev, BAR_TSTRORM_INTMEM + TSTORM_ISCSI_PAGE_SIZE_OFFSET(pfid),
- PAGE_SIZE);
+ CNIC_PAGE_SIZE);
CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
- TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT);
+ TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), CNIC_PAGE_BITS);
CNIC_WR16(dev, BAR_TSTRORM_INTMEM +
TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid),
req1->num_tasks_per_conn);
@@ -1489,9 +1489,9 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(pfid),
req1->rq_buffer_size);
CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_PAGE_SIZE_OFFSET(pfid),
- PAGE_SIZE);
+ CNIC_PAGE_SIZE);
CNIC_WR8(dev, BAR_USTRORM_INTMEM +
- USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT);
+ USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), CNIC_PAGE_BITS);
CNIC_WR16(dev, BAR_USTRORM_INTMEM +
USTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid),
req1->num_tasks_per_conn);
@@ -1504,9 +1504,9 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
/* init Xstorm RAM */
CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_PAGE_SIZE_OFFSET(pfid),
- PAGE_SIZE);
+ CNIC_PAGE_SIZE);
CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
- XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT);
+ XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), CNIC_PAGE_BITS);
CNIC_WR16(dev, BAR_XSTRORM_INTMEM +
XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid),
req1->num_tasks_per_conn);
@@ -1519,9 +1519,9 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
/* init Cstorm RAM */
CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_PAGE_SIZE_OFFSET(pfid),
- PAGE_SIZE);
+ CNIC_PAGE_SIZE);
CNIC_WR8(dev, BAR_CSTRORM_INTMEM +
- CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT);
+ CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), CNIC_PAGE_BITS);
CNIC_WR16(dev, BAR_CSTRORM_INTMEM +
CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid),
req1->num_tasks_per_conn);
@@ -1623,18 +1623,18 @@ static int cnic_alloc_bnx2x_conn_resc(struct cnic_dev *dev, u32 l5_cid)
}
ctx->cid = cid;
- pages = PAGE_ALIGN(cp->task_array_size) / PAGE_SIZE;
+ pages = CNIC_PAGE_ALIGN(cp->task_array_size) / CNIC_PAGE_SIZE;
ret = cnic_alloc_dma(dev, &iscsi->task_array_info, pages, 1);
if (ret)
goto error;
- pages = PAGE_ALIGN(cp->r2tq_size) / PAGE_SIZE;
+ pages = CNIC_PAGE_ALIGN(cp->r2tq_size) / CNIC_PAGE_SIZE;
ret = cnic_alloc_dma(dev, &iscsi->r2tq_info, pages, 1);
if (ret)
goto error;
- pages = PAGE_ALIGN(cp->hq_size) / PAGE_SIZE;
+ pages = CNIC_PAGE_ALIGN(cp->hq_size) / CNIC_PAGE_SIZE;
ret = cnic_alloc_dma(dev, &iscsi->hq_info, pages, 1);
if (ret)
goto error;
@@ -1760,7 +1760,7 @@ static int cnic_setup_bnx2x_ctx(struct cnic_dev *dev, struct kwqe *wqes[],
ictx->tstorm_st_context.iscsi.hdr_bytes_2_fetch = ISCSI_HEADER_SIZE;
/* TSTORM requires the base address of RQ DB & not PTE */
ictx->tstorm_st_context.iscsi.rq_db_phy_addr.lo =
- req2->rq_page_table_addr_lo & PAGE_MASK;
+ req2->rq_page_table_addr_lo & CNIC_PAGE_MASK;
ictx->tstorm_st_context.iscsi.rq_db_phy_addr.hi =
req2->rq_page_table_addr_hi;
ictx->tstorm_st_context.iscsi.iscsi_conn_id = req1->iscsi_conn_id;
@@ -1842,7 +1842,7 @@ static int cnic_setup_bnx2x_ctx(struct cnic_dev *dev, struct kwqe *wqes[],
/* CSTORM and USTORM initialization is different, CSTORM requires
* CQ DB base & not PTE addr */
ictx->cstorm_st_context.cq_db_base.lo =
- req1->cq_page_table_addr_lo & PAGE_MASK;
+ req1->cq_page_table_addr_lo & CNIC_PAGE_MASK;
ictx->cstorm_st_context.cq_db_base.hi = req1->cq_page_table_addr_hi;
ictx->cstorm_st_context.iscsi_conn_id = req1->iscsi_conn_id;
ictx->cstorm_st_context.cq_proc_en_bit_map = (1 << cp->num_cqs) - 1;
@@ -2911,7 +2911,7 @@ static int cnic_l2_completion(struct cnic_local *cp)
u16 hw_cons, sw_cons;
struct cnic_uio_dev *udev = cp->udev;
union eth_rx_cqe *cqe, *cqe_ring = (union eth_rx_cqe *)
- (udev->l2_ring + (2 * BNX2_PAGE_SIZE));
+ (udev->l2_ring + (2 * CNIC_PAGE_SIZE));
u32 cmd;
int comp = 0;
@@ -3244,7 +3244,8 @@ static int cnic_copy_ulp_stats(struct cnic_dev *dev, int ulp_type)
int rc;
mutex_lock(&cnic_lock);
- ulp_ops = cnic_ulp_tbl_prot(ulp_type);
+ ulp_ops = rcu_dereference_protected(cp->ulp_ops[ulp_type],
+ lockdep_is_held(&cnic_lock));
if (ulp_ops && ulp_ops->cnic_get_stats)
rc = ulp_ops->cnic_get_stats(cp->ulp_handle[ulp_type]);
else
@@ -4384,7 +4385,7 @@ static int cnic_setup_5709_context(struct cnic_dev *dev, int valid)
u32 idx = cp->ctx_arr[i].cid / cp->cids_per_blk;
u32 val;
- memset(cp->ctx_arr[i].ctx, 0, BNX2_PAGE_SIZE);
+ memset(cp->ctx_arr[i].ctx, 0, CNIC_PAGE_SIZE);
CNIC_WR(dev, BNX2_CTX_HOST_PAGE_TBL_DATA0,
(cp->ctx_arr[i].mapping & 0xffffffff) | valid_bit);
@@ -4628,7 +4629,7 @@ static void cnic_init_bnx2_rx_ring(struct cnic_dev *dev)
val = BNX2_L2CTX_L2_STATUSB_NUM(sb_id);
cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_HOST_BDIDX, val);
- rxbd = udev->l2_ring + BNX2_PAGE_SIZE;
+ rxbd = udev->l2_ring + CNIC_PAGE_SIZE;
for (i = 0; i < BNX2_MAX_RX_DESC_CNT; i++, rxbd++) {
dma_addr_t buf_map;
int n = (i % cp->l2_rx_ring_size) + 1;
@@ -4639,11 +4640,11 @@ static void cnic_init_bnx2_rx_ring(struct cnic_dev *dev)
rxbd->rx_bd_haddr_hi = (u64) buf_map >> 32;
rxbd->rx_bd_haddr_lo = (u64) buf_map & 0xffffffff;
}
- val = (u64) (ring_map + BNX2_PAGE_SIZE) >> 32;
+ val = (u64) (ring_map + CNIC_PAGE_SIZE) >> 32;
cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
rxbd->rx_bd_haddr_hi = val;
- val = (u64) (ring_map + BNX2_PAGE_SIZE) & 0xffffffff;
+ val = (u64) (ring_map + CNIC_PAGE_SIZE) & 0xffffffff;
cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
rxbd->rx_bd_haddr_lo = val;
@@ -4709,10 +4710,10 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
val = CNIC_RD(dev, BNX2_MQ_CONFIG);
val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
- if (BNX2_PAGE_BITS > 12)
+ if (CNIC_PAGE_BITS > 12)
val |= (12 - 8) << 4;
else
- val |= (BNX2_PAGE_BITS - 8) << 4;
+ val |= (CNIC_PAGE_BITS - 8) << 4;
CNIC_WR(dev, BNX2_MQ_CONFIG, val);
@@ -4742,13 +4743,13 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
/* Initialize the kernel work queue context. */
val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE |
- (BNX2_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
+ (CNIC_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_TYPE, val);
- val = (BNX2_PAGE_SIZE / sizeof(struct kwqe) - 1) << 16;
+ val = (CNIC_PAGE_SIZE / sizeof(struct kwqe) - 1) << 16;
cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
- val = ((BNX2_PAGE_SIZE / sizeof(struct kwqe)) << 16) | KWQ_PAGE_CNT;
+ val = ((CNIC_PAGE_SIZE / sizeof(struct kwqe)) << 16) | KWQ_PAGE_CNT;
cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
val = (u32) ((u64) cp->kwq_info.pgtbl_map >> 32);
@@ -4768,13 +4769,13 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
/* Initialize the kernel complete queue context. */
val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE |
- (BNX2_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
+ (CNIC_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_TYPE, val);
- val = (BNX2_PAGE_SIZE / sizeof(struct kcqe) - 1) << 16;
+ val = (CNIC_PAGE_SIZE / sizeof(struct kcqe) - 1) << 16;
cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
- val = ((BNX2_PAGE_SIZE / sizeof(struct kcqe)) << 16) | KCQ_PAGE_CNT;
+ val = ((CNIC_PAGE_SIZE / sizeof(struct kcqe)) << 16) | KCQ_PAGE_CNT;
cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
val = (u32) ((u64) cp->kcq1.dma.pgtbl_map >> 32);
@@ -4918,7 +4919,7 @@ static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev,
u32 cli = cp->ethdev->iscsi_l2_client_id;
u32 val;
- memset(txbd, 0, BNX2_PAGE_SIZE);
+ memset(txbd, 0, CNIC_PAGE_SIZE);
buf_map = udev->l2_buf_map;
for (i = 0; i < BNX2_MAX_TX_DESC_CNT; i += 3, txbd += 3) {
@@ -4978,9 +4979,9 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev,
struct bnx2x *bp = netdev_priv(dev->netdev);
struct cnic_uio_dev *udev = cp->udev;
struct eth_rx_bd *rxbd = (struct eth_rx_bd *) (udev->l2_ring +
- BNX2_PAGE_SIZE);
+ CNIC_PAGE_SIZE);
struct eth_rx_cqe_next_page *rxcqe = (struct eth_rx_cqe_next_page *)
- (udev->l2_ring + (2 * BNX2_PAGE_SIZE));
+ (udev->l2_ring + (2 * CNIC_PAGE_SIZE));
struct host_sp_status_block *sb = cp->bnx2x_def_status_blk;
int i;
u32 cli = cp->ethdev->iscsi_l2_client_id;
@@ -5004,20 +5005,20 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev,
rxbd->addr_lo = cpu_to_le32(buf_map & 0xffffffff);
}
- val = (u64) (ring_map + BNX2_PAGE_SIZE) >> 32;
+ val = (u64) (ring_map + CNIC_PAGE_SIZE) >> 32;
rxbd->addr_hi = cpu_to_le32(val);
data->rx.bd_page_base.hi = cpu_to_le32(val);
- val = (u64) (ring_map + BNX2_PAGE_SIZE) & 0xffffffff;
+ val = (u64) (ring_map + CNIC_PAGE_SIZE) & 0xffffffff;
rxbd->addr_lo = cpu_to_le32(val);
data->rx.bd_page_base.lo = cpu_to_le32(val);
rxcqe += BNX2X_MAX_RCQ_DESC_CNT;
- val = (u64) (ring_map + (2 * BNX2_PAGE_SIZE)) >> 32;
+ val = (u64) (ring_map + (2 * CNIC_PAGE_SIZE)) >> 32;
rxcqe->addr_hi = cpu_to_le32(val);
data->rx.cqe_page_base.hi = cpu_to_le32(val);
- val = (u64) (ring_map + (2 * BNX2_PAGE_SIZE)) & 0xffffffff;
+ val = (u64) (ring_map + (2 * CNIC_PAGE_SIZE)) & 0xffffffff;
rxcqe->addr_lo = cpu_to_le32(val);
data->rx.cqe_page_base.lo = cpu_to_le32(val);
@@ -5265,8 +5266,8 @@ static void cnic_shutdown_rings(struct cnic_dev *dev)
msleep(10);
}
clear_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags);
- rx_ring = udev->l2_ring + BNX2_PAGE_SIZE;
- memset(rx_ring, 0, BNX2_PAGE_SIZE);
+ rx_ring = udev->l2_ring + CNIC_PAGE_SIZE;
+ memset(rx_ring, 0, CNIC_PAGE_SIZE);
}
static int cnic_register_netdev(struct cnic_dev *dev)
diff --git a/drivers/net/ethernet/broadcom/cnic.h b/drivers/net/ethernet/broadcom/cnic.h
index 0d6b13f854d9..d535ae4228b4 100644
--- a/drivers/net/ethernet/broadcom/cnic.h
+++ b/drivers/net/ethernet/broadcom/cnic.h
@@ -1,6 +1,6 @@
/* cnic.h: Broadcom CNIC core network driver.
*
- * Copyright (c) 2006-2013 Broadcom Corporation
+ * Copyright (c) 2006-2014 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/net/ethernet/broadcom/cnic_defs.h b/drivers/net/ethernet/broadcom/cnic_defs.h
index 95a8e4b11c9f..dcbca6997e8f 100644
--- a/drivers/net/ethernet/broadcom/cnic_defs.h
+++ b/drivers/net/ethernet/broadcom/cnic_defs.h
@@ -1,7 +1,7 @@
/* cnic.c: Broadcom CNIC core network driver.
*
- * Copyright (c) 2006-2013 Broadcom Corporation
+ * Copyright (c) 2006-2014 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/net/ethernet/broadcom/cnic_if.h b/drivers/net/ethernet/broadcom/cnic_if.h
index 8cf6b1926069..5f4d5573a73d 100644
--- a/drivers/net/ethernet/broadcom/cnic_if.h
+++ b/drivers/net/ethernet/broadcom/cnic_if.h
@@ -1,6 +1,6 @@
/* cnic_if.h: Broadcom CNIC core network driver.
*
- * Copyright (c) 2006-2013 Broadcom Corporation
+ * Copyright (c) 2006-2014 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
@@ -14,8 +14,8 @@
#include "bnx2x/bnx2x_mfw_req.h"
-#define CNIC_MODULE_VERSION "2.5.19"
-#define CNIC_MODULE_RELDATE "December 19, 2013"
+#define CNIC_MODULE_VERSION "2.5.20"
+#define CNIC_MODULE_RELDATE "March 14, 2014"
#define CNIC_ULP_RDMA 0
#define CNIC_ULP_ISCSI 1
@@ -24,6 +24,16 @@
#define MAX_CNIC_ULP_TYPE_EXT 3
#define MAX_CNIC_ULP_TYPE 4
+/* Use CPU native page size up to 16K for cnic ring sizes. */
+#if (PAGE_SHIFT > 14)
+#define CNIC_PAGE_BITS 14
+#else
+#define CNIC_PAGE_BITS PAGE_SHIFT
+#endif
+#define CNIC_PAGE_SIZE (1 << (CNIC_PAGE_BITS))
+#define CNIC_PAGE_ALIGN(addr) ALIGN(addr, CNIC_PAGE_SIZE)
+#define CNIC_PAGE_MASK (~((CNIC_PAGE_SIZE) - 1))
+
struct kwqe {
u32 kwqe_op_flag;
diff --git a/drivers/net/ethernet/broadcom/genet/Makefile b/drivers/net/ethernet/broadcom/genet/Makefile
new file mode 100644
index 000000000000..31f55a90a197
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/genet/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_BCMGENET) += genet.o
+genet-objs := bcmgenet.o bcmmii.o
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
new file mode 100644
index 000000000000..adf8acbddf56
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -0,0 +1,2584 @@
+/*
+ * Broadcom GENET (Gigabit Ethernet) controller driver
+ *
+ * Copyright (c) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define pr_fmt(fmt) "bcmgenet: " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/if_ether.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm.h>
+#include <linux/clk.h>
+#include <linux/version.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_net.h>
+#include <linux/of_platform.h>
+#include <net/arp.h>
+
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/phy.h>
+
+#include <asm/unaligned.h>
+
+#include "bcmgenet.h"
+
+/* Maximum number of hardware queues, downsized if needed */
+#define GENET_MAX_MQ_CNT 4
+
+/* Default highest priority queue for multi queue support */
+#define GENET_Q0_PRIORITY 0
+
+#define GENET_DEFAULT_BD_CNT \
+ (TOTAL_DESC - priv->hw_params->tx_queues * priv->hw_params->bds_cnt)
+
+#define RX_BUF_LENGTH 2048
+#define SKB_ALIGNMENT 32
+
+/* Tx/Rx DMA register offset, skip 256 descriptors */
+#define WORDS_PER_BD(p) (p->hw_params->words_per_bd)
+#define DMA_DESC_SIZE (WORDS_PER_BD(priv) * sizeof(u32))
+
+#define GENET_TDMA_REG_OFF (priv->hw_params->tdma_offset + \
+ TOTAL_DESC * DMA_DESC_SIZE)
+
+#define GENET_RDMA_REG_OFF (priv->hw_params->rdma_offset + \
+ TOTAL_DESC * DMA_DESC_SIZE)
+
+static inline void dmadesc_set_length_status(struct bcmgenet_priv *priv,
+ void __iomem *d, u32 value)
+{
+ __raw_writel(value, d + DMA_DESC_LENGTH_STATUS);
+}
+
+static inline u32 dmadesc_get_length_status(struct bcmgenet_priv *priv,
+ void __iomem *d)
+{
+ return __raw_readl(d + DMA_DESC_LENGTH_STATUS);
+}
+
+static inline void dmadesc_set_addr(struct bcmgenet_priv *priv,
+ void __iomem *d,
+ dma_addr_t addr)
+{
+ __raw_writel(lower_32_bits(addr), d + DMA_DESC_ADDRESS_LO);
+
+ /* Register writes to GISB bus can take couple hundred nanoseconds
+ * and are done for each packet, save these expensive writes unless
+ * the platform is explicitely configured for 64-bits/LPAE.
+ */
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+ if (priv->hw_params->flags & GENET_HAS_40BITS)
+ __raw_writel(upper_32_bits(addr), d + DMA_DESC_ADDRESS_HI);
+#endif
+}
+
+/* Combined address + length/status setter */
+static inline void dmadesc_set(struct bcmgenet_priv *priv,
+ void __iomem *d, dma_addr_t addr, u32 val)
+{
+ dmadesc_set_length_status(priv, d, val);
+ dmadesc_set_addr(priv, d, addr);
+}
+
+static inline dma_addr_t dmadesc_get_addr(struct bcmgenet_priv *priv,
+ void __iomem *d)
+{
+ dma_addr_t addr;
+
+ addr = __raw_readl(d + DMA_DESC_ADDRESS_LO);
+
+ /* Register writes to GISB bus can take couple hundred nanoseconds
+ * and are done for each packet, save these expensive writes unless
+ * the platform is explicitely configured for 64-bits/LPAE.
+ */
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+ if (priv->hw_params->flags & GENET_HAS_40BITS)
+ addr |= (u64)__raw_readl(d + DMA_DESC_ADDRESS_HI) << 32;
+#endif
+ return addr;
+}
+
+#define GENET_VER_FMT "%1d.%1d EPHY: 0x%04x"
+
+#define GENET_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | \
+ NETIF_MSG_LINK)
+
+static inline u32 bcmgenet_rbuf_ctrl_get(struct bcmgenet_priv *priv)
+{
+ if (GENET_IS_V1(priv))
+ return bcmgenet_rbuf_readl(priv, RBUF_FLUSH_CTRL_V1);
+ else
+ return bcmgenet_sys_readl(priv, SYS_RBUF_FLUSH_CTRL);
+}
+
+static inline void bcmgenet_rbuf_ctrl_set(struct bcmgenet_priv *priv, u32 val)
+{
+ if (GENET_IS_V1(priv))
+ bcmgenet_rbuf_writel(priv, val, RBUF_FLUSH_CTRL_V1);
+ else
+ bcmgenet_sys_writel(priv, val, SYS_RBUF_FLUSH_CTRL);
+}
+
+/* These macros are defined to deal with register map change
+ * between GENET1.1 and GENET2. Only those currently being used
+ * by driver are defined.
+ */
+static inline u32 bcmgenet_tbuf_ctrl_get(struct bcmgenet_priv *priv)
+{
+ if (GENET_IS_V1(priv))
+ return bcmgenet_rbuf_readl(priv, TBUF_CTRL_V1);
+ else
+ return __raw_readl(priv->base +
+ priv->hw_params->tbuf_offset + TBUF_CTRL);
+}
+
+static inline void bcmgenet_tbuf_ctrl_set(struct bcmgenet_priv *priv, u32 val)
+{
+ if (GENET_IS_V1(priv))
+ bcmgenet_rbuf_writel(priv, val, TBUF_CTRL_V1);
+ else
+ __raw_writel(val, priv->base +
+ priv->hw_params->tbuf_offset + TBUF_CTRL);
+}
+
+static inline u32 bcmgenet_bp_mc_get(struct bcmgenet_priv *priv)
+{
+ if (GENET_IS_V1(priv))
+ return bcmgenet_rbuf_readl(priv, TBUF_BP_MC_V1);
+ else
+ return __raw_readl(priv->base +
+ priv->hw_params->tbuf_offset + TBUF_BP_MC);
+}
+
+static inline void bcmgenet_bp_mc_set(struct bcmgenet_priv *priv, u32 val)
+{
+ if (GENET_IS_V1(priv))
+ bcmgenet_rbuf_writel(priv, val, TBUF_BP_MC_V1);
+ else
+ __raw_writel(val, priv->base +
+ priv->hw_params->tbuf_offset + TBUF_BP_MC);
+}
+
+/* RX/TX DMA register accessors */
+enum dma_reg {
+ DMA_RING_CFG = 0,
+ DMA_CTRL,
+ DMA_STATUS,
+ DMA_SCB_BURST_SIZE,
+ DMA_ARB_CTRL,
+ DMA_PRIORITY,
+ DMA_RING_PRIORITY,
+};
+
+static const u8 bcmgenet_dma_regs_v3plus[] = {
+ [DMA_RING_CFG] = 0x00,
+ [DMA_CTRL] = 0x04,
+ [DMA_STATUS] = 0x08,
+ [DMA_SCB_BURST_SIZE] = 0x0C,
+ [DMA_ARB_CTRL] = 0x2C,
+ [DMA_PRIORITY] = 0x30,
+ [DMA_RING_PRIORITY] = 0x38,
+};
+
+static const u8 bcmgenet_dma_regs_v2[] = {
+ [DMA_RING_CFG] = 0x00,
+ [DMA_CTRL] = 0x04,
+ [DMA_STATUS] = 0x08,
+ [DMA_SCB_BURST_SIZE] = 0x0C,
+ [DMA_ARB_CTRL] = 0x30,
+ [DMA_PRIORITY] = 0x34,
+ [DMA_RING_PRIORITY] = 0x3C,
+};
+
+static const u8 bcmgenet_dma_regs_v1[] = {
+ [DMA_CTRL] = 0x00,
+ [DMA_STATUS] = 0x04,
+ [DMA_SCB_BURST_SIZE] = 0x0C,
+ [DMA_ARB_CTRL] = 0x30,
+ [DMA_PRIORITY] = 0x34,
+ [DMA_RING_PRIORITY] = 0x3C,
+};
+
+/* Set at runtime once bcmgenet version is known */
+static const u8 *bcmgenet_dma_regs;
+
+static inline struct bcmgenet_priv *dev_to_priv(struct device *dev)
+{
+ return netdev_priv(dev_get_drvdata(dev));
+}
+
+static inline u32 bcmgenet_tdma_readl(struct bcmgenet_priv *priv,
+ enum dma_reg r)
+{
+ return __raw_readl(priv->base + GENET_TDMA_REG_OFF +
+ DMA_RINGS_SIZE + bcmgenet_dma_regs[r]);
+}
+
+static inline void bcmgenet_tdma_writel(struct bcmgenet_priv *priv,
+ u32 val, enum dma_reg r)
+{
+ __raw_writel(val, priv->base + GENET_TDMA_REG_OFF +
+ DMA_RINGS_SIZE + bcmgenet_dma_regs[r]);
+}
+
+static inline u32 bcmgenet_rdma_readl(struct bcmgenet_priv *priv,
+ enum dma_reg r)
+{
+ return __raw_readl(priv->base + GENET_RDMA_REG_OFF +
+ DMA_RINGS_SIZE + bcmgenet_dma_regs[r]);
+}
+
+static inline void bcmgenet_rdma_writel(struct bcmgenet_priv *priv,
+ u32 val, enum dma_reg r)
+{
+ __raw_writel(val, priv->base + GENET_RDMA_REG_OFF +
+ DMA_RINGS_SIZE + bcmgenet_dma_regs[r]);
+}
+
+/* RDMA/TDMA ring registers and accessors
+ * we merge the common fields and just prefix with T/D the registers
+ * having different meaning depending on the direction
+ */
+enum dma_ring_reg {
+ TDMA_READ_PTR = 0,
+ RDMA_WRITE_PTR = TDMA_READ_PTR,
+ TDMA_READ_PTR_HI,
+ RDMA_WRITE_PTR_HI = TDMA_READ_PTR_HI,
+ TDMA_CONS_INDEX,
+ RDMA_PROD_INDEX = TDMA_CONS_INDEX,
+ TDMA_PROD_INDEX,
+ RDMA_CONS_INDEX = TDMA_PROD_INDEX,
+ DMA_RING_BUF_SIZE,
+ DMA_START_ADDR,
+ DMA_START_ADDR_HI,
+ DMA_END_ADDR,
+ DMA_END_ADDR_HI,
+ DMA_MBUF_DONE_THRESH,
+ TDMA_FLOW_PERIOD,
+ RDMA_XON_XOFF_THRESH = TDMA_FLOW_PERIOD,
+ TDMA_WRITE_PTR,
+ RDMA_READ_PTR = TDMA_WRITE_PTR,
+ TDMA_WRITE_PTR_HI,
+ RDMA_READ_PTR_HI = TDMA_WRITE_PTR_HI
+};
+
+/* GENET v4 supports 40-bits pointer addressing
+ * for obvious reasons the LO and HI word parts
+ * are contiguous, but this offsets the other
+ * registers.
+ */
+static const u8 genet_dma_ring_regs_v4[] = {
+ [TDMA_READ_PTR] = 0x00,
+ [TDMA_READ_PTR_HI] = 0x04,
+ [TDMA_CONS_INDEX] = 0x08,
+ [TDMA_PROD_INDEX] = 0x0C,
+ [DMA_RING_BUF_SIZE] = 0x10,
+ [DMA_START_ADDR] = 0x14,
+ [DMA_START_ADDR_HI] = 0x18,
+ [DMA_END_ADDR] = 0x1C,
+ [DMA_END_ADDR_HI] = 0x20,
+ [DMA_MBUF_DONE_THRESH] = 0x24,
+ [TDMA_FLOW_PERIOD] = 0x28,
+ [TDMA_WRITE_PTR] = 0x2C,
+ [TDMA_WRITE_PTR_HI] = 0x30,
+};
+
+static const u8 genet_dma_ring_regs_v123[] = {
+ [TDMA_READ_PTR] = 0x00,
+ [TDMA_CONS_INDEX] = 0x04,
+ [TDMA_PROD_INDEX] = 0x08,
+ [DMA_RING_BUF_SIZE] = 0x0C,
+ [DMA_START_ADDR] = 0x10,
+ [DMA_END_ADDR] = 0x14,
+ [DMA_MBUF_DONE_THRESH] = 0x18,
+ [TDMA_FLOW_PERIOD] = 0x1C,
+ [TDMA_WRITE_PTR] = 0x20,
+};
+
+/* Set at runtime once GENET version is known */
+static const u8 *genet_dma_ring_regs;
+
+static inline u32 bcmgenet_tdma_ring_readl(struct bcmgenet_priv *priv,
+ unsigned int ring,
+ enum dma_ring_reg r)
+{
+ return __raw_readl(priv->base + GENET_TDMA_REG_OFF +
+ (DMA_RING_SIZE * ring) +
+ genet_dma_ring_regs[r]);
+}
+
+static inline void bcmgenet_tdma_ring_writel(struct bcmgenet_priv *priv,
+ unsigned int ring,
+ u32 val,
+ enum dma_ring_reg r)
+{
+ __raw_writel(val, priv->base + GENET_TDMA_REG_OFF +
+ (DMA_RING_SIZE * ring) +
+ genet_dma_ring_regs[r]);
+}
+
+static inline u32 bcmgenet_rdma_ring_readl(struct bcmgenet_priv *priv,
+ unsigned int ring,
+ enum dma_ring_reg r)
+{
+ return __raw_readl(priv->base + GENET_RDMA_REG_OFF +
+ (DMA_RING_SIZE * ring) +
+ genet_dma_ring_regs[r]);
+}
+
+static inline void bcmgenet_rdma_ring_writel(struct bcmgenet_priv *priv,
+ unsigned int ring,
+ u32 val,
+ enum dma_ring_reg r)
+{
+ __raw_writel(val, priv->base + GENET_RDMA_REG_OFF +
+ (DMA_RING_SIZE * ring) +
+ genet_dma_ring_regs[r]);
+}
+
+static int bcmgenet_get_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+
+ if (!netif_running(dev))
+ return -EINVAL;
+
+ if (!priv->phydev)
+ return -ENODEV;
+
+ return phy_ethtool_gset(priv->phydev, cmd);
+}
+
+static int bcmgenet_set_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+
+ if (!netif_running(dev))
+ return -EINVAL;
+
+ if (!priv->phydev)
+ return -ENODEV;
+
+ return phy_ethtool_sset(priv->phydev, cmd);
+}
+
+static int bcmgenet_set_rx_csum(struct net_device *dev,
+ netdev_features_t wanted)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ u32 rbuf_chk_ctrl;
+ bool rx_csum_en;
+
+ rx_csum_en = !!(wanted & NETIF_F_RXCSUM);
+
+ rbuf_chk_ctrl = bcmgenet_rbuf_readl(priv, RBUF_CHK_CTRL);
+
+ /* enable rx checksumming */
+ if (rx_csum_en)
+ rbuf_chk_ctrl |= RBUF_RXCHK_EN;
+ else
+ rbuf_chk_ctrl &= ~RBUF_RXCHK_EN;
+ priv->desc_rxchk_en = rx_csum_en;
+
+ /* If UniMAC forwards CRC, we need to skip over it to get
+ * a valid CHK bit to be set in the per-packet status word
+ */
+ if (rx_csum_en && priv->crc_fwd_en)
+ rbuf_chk_ctrl |= RBUF_SKIP_FCS;
+ else
+ rbuf_chk_ctrl &= ~RBUF_SKIP_FCS;
+
+ bcmgenet_rbuf_writel(priv, rbuf_chk_ctrl, RBUF_CHK_CTRL);
+
+ return 0;
+}
+
+static int bcmgenet_set_tx_csum(struct net_device *dev,
+ netdev_features_t wanted)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ bool desc_64b_en;
+ u32 tbuf_ctrl, rbuf_ctrl;
+
+ tbuf_ctrl = bcmgenet_tbuf_ctrl_get(priv);
+ rbuf_ctrl = bcmgenet_rbuf_readl(priv, RBUF_CTRL);
+
+ desc_64b_en = !!(wanted & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM));
+
+ /* enable 64 bytes descriptor in both directions (RBUF and TBUF) */
+ if (desc_64b_en) {
+ tbuf_ctrl |= RBUF_64B_EN;
+ rbuf_ctrl |= RBUF_64B_EN;
+ } else {
+ tbuf_ctrl &= ~RBUF_64B_EN;
+ rbuf_ctrl &= ~RBUF_64B_EN;
+ }
+ priv->desc_64b_en = desc_64b_en;
+
+ bcmgenet_tbuf_ctrl_set(priv, tbuf_ctrl);
+ bcmgenet_rbuf_writel(priv, rbuf_ctrl, RBUF_CTRL);
+
+ return 0;
+}
+
+static int bcmgenet_set_features(struct net_device *dev,
+ netdev_features_t features)
+{
+ netdev_features_t changed = features ^ dev->features;
+ netdev_features_t wanted = dev->wanted_features;
+ int ret = 0;
+
+ if (changed & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))
+ ret = bcmgenet_set_tx_csum(dev, wanted);
+ if (changed & (NETIF_F_RXCSUM))
+ ret = bcmgenet_set_rx_csum(dev, wanted);
+
+ return ret;
+}
+
+static u32 bcmgenet_get_msglevel(struct net_device *dev)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+
+ return priv->msg_enable;
+}
+
+static void bcmgenet_set_msglevel(struct net_device *dev, u32 level)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+
+ priv->msg_enable = level;
+}
+
+/* standard ethtool support functions. */
+enum bcmgenet_stat_type {
+ BCMGENET_STAT_NETDEV = -1,
+ BCMGENET_STAT_MIB_RX,
+ BCMGENET_STAT_MIB_TX,
+ BCMGENET_STAT_RUNT,
+ BCMGENET_STAT_MISC,
+};
+
+struct bcmgenet_stats {
+ char stat_string[ETH_GSTRING_LEN];
+ int stat_sizeof;
+ int stat_offset;
+ enum bcmgenet_stat_type type;
+ /* reg offset from UMAC base for misc counters */
+ u16 reg_offset;
+};
+
+#define STAT_NETDEV(m) { \
+ .stat_string = __stringify(m), \
+ .stat_sizeof = sizeof(((struct net_device_stats *)0)->m), \
+ .stat_offset = offsetof(struct net_device_stats, m), \
+ .type = BCMGENET_STAT_NETDEV, \
+}
+
+#define STAT_GENET_MIB(str, m, _type) { \
+ .stat_string = str, \
+ .stat_sizeof = sizeof(((struct bcmgenet_priv *)0)->m), \
+ .stat_offset = offsetof(struct bcmgenet_priv, m), \
+ .type = _type, \
+}
+
+#define STAT_GENET_MIB_RX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_RX)
+#define STAT_GENET_MIB_TX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_TX)
+#define STAT_GENET_RUNT(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_RUNT)
+
+#define STAT_GENET_MISC(str, m, offset) { \
+ .stat_string = str, \
+ .stat_sizeof = sizeof(((struct bcmgenet_priv *)0)->m), \
+ .stat_offset = offsetof(struct bcmgenet_priv, m), \
+ .type = BCMGENET_STAT_MISC, \
+ .reg_offset = offset, \
+}
+
+
+/* There is a 0xC gap between the end of RX and beginning of TX stats and then
+ * between the end of TX stats and the beginning of the RX RUNT
+ */
+#define BCMGENET_STAT_OFFSET 0xc
+
+/* Hardware counters must be kept in sync because the order/offset
+ * is important here (order in structure declaration = order in hardware)
+ */
+static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = {
+ /* general stats */
+ STAT_NETDEV(rx_packets),
+ STAT_NETDEV(tx_packets),
+ STAT_NETDEV(rx_bytes),
+ STAT_NETDEV(tx_bytes),
+ STAT_NETDEV(rx_errors),
+ STAT_NETDEV(tx_errors),
+ STAT_NETDEV(rx_dropped),
+ STAT_NETDEV(tx_dropped),
+ STAT_NETDEV(multicast),
+ /* UniMAC RSV counters */
+ STAT_GENET_MIB_RX("rx_64_octets", mib.rx.pkt_cnt.cnt_64),
+ STAT_GENET_MIB_RX("rx_65_127_oct", mib.rx.pkt_cnt.cnt_127),
+ STAT_GENET_MIB_RX("rx_128_255_oct", mib.rx.pkt_cnt.cnt_255),
+ STAT_GENET_MIB_RX("rx_256_511_oct", mib.rx.pkt_cnt.cnt_511),
+ STAT_GENET_MIB_RX("rx_512_1023_oct", mib.rx.pkt_cnt.cnt_1023),
+ STAT_GENET_MIB_RX("rx_1024_1518_oct", mib.rx.pkt_cnt.cnt_1518),
+ STAT_GENET_MIB_RX("rx_vlan_1519_1522_oct", mib.rx.pkt_cnt.cnt_mgv),
+ STAT_GENET_MIB_RX("rx_1522_2047_oct", mib.rx.pkt_cnt.cnt_2047),
+ STAT_GENET_MIB_RX("rx_2048_4095_oct", mib.rx.pkt_cnt.cnt_4095),
+ STAT_GENET_MIB_RX("rx_4096_9216_oct", mib.rx.pkt_cnt.cnt_9216),
+ STAT_GENET_MIB_RX("rx_pkts", mib.rx.pkt),
+ STAT_GENET_MIB_RX("rx_bytes", mib.rx.bytes),
+ STAT_GENET_MIB_RX("rx_multicast", mib.rx.mca),
+ STAT_GENET_MIB_RX("rx_broadcast", mib.rx.bca),
+ STAT_GENET_MIB_RX("rx_fcs", mib.rx.fcs),
+ STAT_GENET_MIB_RX("rx_control", mib.rx.cf),
+ STAT_GENET_MIB_RX("rx_pause", mib.rx.pf),
+ STAT_GENET_MIB_RX("rx_unknown", mib.rx.uo),
+ STAT_GENET_MIB_RX("rx_align", mib.rx.aln),
+ STAT_GENET_MIB_RX("rx_outrange", mib.rx.flr),
+ STAT_GENET_MIB_RX("rx_code", mib.rx.cde),
+ STAT_GENET_MIB_RX("rx_carrier", mib.rx.fcr),
+ STAT_GENET_MIB_RX("rx_oversize", mib.rx.ovr),
+ STAT_GENET_MIB_RX("rx_jabber", mib.rx.jbr),
+ STAT_GENET_MIB_RX("rx_mtu_err", mib.rx.mtue),
+ STAT_GENET_MIB_RX("rx_good_pkts", mib.rx.pok),
+ STAT_GENET_MIB_RX("rx_unicast", mib.rx.uc),
+ STAT_GENET_MIB_RX("rx_ppp", mib.rx.ppp),
+ STAT_GENET_MIB_RX("rx_crc", mib.rx.rcrc),
+ /* UniMAC TSV counters */
+ STAT_GENET_MIB_TX("tx_64_octets", mib.tx.pkt_cnt.cnt_64),
+ STAT_GENET_MIB_TX("tx_65_127_oct", mib.tx.pkt_cnt.cnt_127),
+ STAT_GENET_MIB_TX("tx_128_255_oct", mib.tx.pkt_cnt.cnt_255),
+ STAT_GENET_MIB_TX("tx_256_511_oct", mib.tx.pkt_cnt.cnt_511),
+ STAT_GENET_MIB_TX("tx_512_1023_oct", mib.tx.pkt_cnt.cnt_1023),
+ STAT_GENET_MIB_TX("tx_1024_1518_oct", mib.tx.pkt_cnt.cnt_1518),
+ STAT_GENET_MIB_TX("tx_vlan_1519_1522_oct", mib.tx.pkt_cnt.cnt_mgv),
+ STAT_GENET_MIB_TX("tx_1522_2047_oct", mib.tx.pkt_cnt.cnt_2047),
+ STAT_GENET_MIB_TX("tx_2048_4095_oct", mib.tx.pkt_cnt.cnt_4095),
+ STAT_GENET_MIB_TX("tx_4096_9216_oct", mib.tx.pkt_cnt.cnt_9216),
+ STAT_GENET_MIB_TX("tx_pkts", mib.tx.pkts),
+ STAT_GENET_MIB_TX("tx_multicast", mib.tx.mca),
+ STAT_GENET_MIB_TX("tx_broadcast", mib.tx.bca),
+ STAT_GENET_MIB_TX("tx_pause", mib.tx.pf),
+ STAT_GENET_MIB_TX("tx_control", mib.tx.cf),
+ STAT_GENET_MIB_TX("tx_fcs_err", mib.tx.fcs),
+ STAT_GENET_MIB_TX("tx_oversize", mib.tx.ovr),
+ STAT_GENET_MIB_TX("tx_defer", mib.tx.drf),
+ STAT_GENET_MIB_TX("tx_excess_defer", mib.tx.edf),
+ STAT_GENET_MIB_TX("tx_single_col", mib.tx.scl),
+ STAT_GENET_MIB_TX("tx_multi_col", mib.tx.mcl),
+ STAT_GENET_MIB_TX("tx_late_col", mib.tx.lcl),
+ STAT_GENET_MIB_TX("tx_excess_col", mib.tx.ecl),
+ STAT_GENET_MIB_TX("tx_frags", mib.tx.frg),
+ STAT_GENET_MIB_TX("tx_total_col", mib.tx.ncl),
+ STAT_GENET_MIB_TX("tx_jabber", mib.tx.jbr),
+ STAT_GENET_MIB_TX("tx_bytes", mib.tx.bytes),
+ STAT_GENET_MIB_TX("tx_good_pkts", mib.tx.pok),
+ STAT_GENET_MIB_TX("tx_unicast", mib.tx.uc),
+ /* UniMAC RUNT counters */
+ STAT_GENET_RUNT("rx_runt_pkts", mib.rx_runt_cnt),
+ STAT_GENET_RUNT("rx_runt_valid_fcs", mib.rx_runt_fcs),
+ STAT_GENET_RUNT("rx_runt_inval_fcs_align", mib.rx_runt_fcs_align),
+ STAT_GENET_RUNT("rx_runt_bytes", mib.rx_runt_bytes),
+ /* Misc UniMAC counters */
+ STAT_GENET_MISC("rbuf_ovflow_cnt", mib.rbuf_ovflow_cnt,
+ UMAC_RBUF_OVFL_CNT),
+ STAT_GENET_MISC("rbuf_err_cnt", mib.rbuf_err_cnt, UMAC_RBUF_ERR_CNT),
+ STAT_GENET_MISC("mdf_err_cnt", mib.mdf_err_cnt, UMAC_MDF_ERR_CNT),
+};
+
+#define BCMGENET_STATS_LEN ARRAY_SIZE(bcmgenet_gstrings_stats)
+
+static void bcmgenet_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strlcpy(info->driver, "bcmgenet", sizeof(info->driver));
+ strlcpy(info->version, "v2.0", sizeof(info->version));
+ info->n_stats = BCMGENET_STATS_LEN;
+
+}
+
+static int bcmgenet_get_sset_count(struct net_device *dev, int string_set)
+{
+ switch (string_set) {
+ case ETH_SS_STATS:
+ return BCMGENET_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void bcmgenet_get_strings(struct net_device *dev,
+ u32 stringset, u8 *data)
+{
+ int i;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < BCMGENET_STATS_LEN; i++) {
+ memcpy(data + i * ETH_GSTRING_LEN,
+ bcmgenet_gstrings_stats[i].stat_string,
+ ETH_GSTRING_LEN);
+ }
+ break;
+ }
+}
+
+static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv)
+{
+ int i, j = 0;
+
+ for (i = 0; i < BCMGENET_STATS_LEN; i++) {
+ const struct bcmgenet_stats *s;
+ u8 offset = 0;
+ u32 val = 0;
+ char *p;
+
+ s = &bcmgenet_gstrings_stats[i];
+ switch (s->type) {
+ case BCMGENET_STAT_NETDEV:
+ continue;
+ case BCMGENET_STAT_MIB_RX:
+ case BCMGENET_STAT_MIB_TX:
+ case BCMGENET_STAT_RUNT:
+ if (s->type != BCMGENET_STAT_MIB_RX)
+ offset = BCMGENET_STAT_OFFSET;
+ val = bcmgenet_umac_readl(priv, UMAC_MIB_START +
+ j + offset);
+ break;
+ case BCMGENET_STAT_MISC:
+ val = bcmgenet_umac_readl(priv, s->reg_offset);
+ /* clear if overflowed */
+ if (val == ~0)
+ bcmgenet_umac_writel(priv, 0, s->reg_offset);
+ break;
+ }
+
+ j += s->stat_sizeof;
+ p = (char *)priv + s->stat_offset;
+ *(u32 *)p = val;
+ }
+}
+
+static void bcmgenet_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats,
+ u64 *data)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ int i;
+
+ if (netif_running(dev))
+ bcmgenet_update_mib_counters(priv);
+
+ for (i = 0; i < BCMGENET_STATS_LEN; i++) {
+ const struct bcmgenet_stats *s;
+ char *p;
+
+ s = &bcmgenet_gstrings_stats[i];
+ if (s->type == BCMGENET_STAT_NETDEV)
+ p = (char *)&dev->stats;
+ else
+ p = (char *)priv;
+ p += s->stat_offset;
+ data[i] = *(u32 *)p;
+ }
+}
+
+/* standard ethtool support functions. */
+static struct ethtool_ops bcmgenet_ethtool_ops = {
+ .get_strings = bcmgenet_get_strings,
+ .get_sset_count = bcmgenet_get_sset_count,
+ .get_ethtool_stats = bcmgenet_get_ethtool_stats,
+ .get_settings = bcmgenet_get_settings,
+ .set_settings = bcmgenet_set_settings,
+ .get_drvinfo = bcmgenet_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_msglevel = bcmgenet_get_msglevel,
+ .set_msglevel = bcmgenet_set_msglevel,
+};
+
+/* Power down the unimac, based on mode. */
+static void bcmgenet_power_down(struct bcmgenet_priv *priv,
+ enum bcmgenet_power_mode mode)
+{
+ u32 reg;
+
+ switch (mode) {
+ case GENET_POWER_CABLE_SENSE:
+ phy_detach(priv->phydev);
+ break;
+
+ case GENET_POWER_PASSIVE:
+ /* Power down LED */
+ bcmgenet_mii_reset(priv->dev);
+ if (priv->hw_params->flags & GENET_HAS_EXT) {
+ reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
+ reg |= (EXT_PWR_DOWN_PHY |
+ EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS);
+ bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void bcmgenet_power_up(struct bcmgenet_priv *priv,
+ enum bcmgenet_power_mode mode)
+{
+ u32 reg;
+
+ if (!(priv->hw_params->flags & GENET_HAS_EXT))
+ return;
+
+ reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
+
+ switch (mode) {
+ case GENET_POWER_PASSIVE:
+ reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_PHY |
+ EXT_PWR_DOWN_BIAS);
+ /* fallthrough */
+ case GENET_POWER_CABLE_SENSE:
+ /* enable APD */
+ reg |= EXT_PWR_DN_EN_LD;
+ break;
+ default:
+ break;
+ }
+
+ bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
+ bcmgenet_mii_reset(priv->dev);
+}
+
+/* ioctl handle special commands that are not present in ethtool. */
+static int bcmgenet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ int val = 0;
+
+ if (!netif_running(dev))
+ return -EINVAL;
+
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ case SIOCGMIIREG:
+ case SIOCSMIIREG:
+ if (!priv->phydev)
+ val = -ENODEV;
+ else
+ val = phy_mii_ioctl(priv->phydev, rq, cmd);
+ break;
+
+ default:
+ val = -EINVAL;
+ break;
+ }
+
+ return val;
+}
+
+static struct enet_cb *bcmgenet_get_txcb(struct bcmgenet_priv *priv,
+ struct bcmgenet_tx_ring *ring)
+{
+ struct enet_cb *tx_cb_ptr;
+
+ tx_cb_ptr = ring->cbs;
+ tx_cb_ptr += ring->write_ptr - ring->cb_ptr;
+ tx_cb_ptr->bd_addr = priv->tx_bds + ring->write_ptr * DMA_DESC_SIZE;
+ /* Advancing local write pointer */
+ if (ring->write_ptr == ring->end_ptr)
+ ring->write_ptr = ring->cb_ptr;
+ else
+ ring->write_ptr++;
+
+ return tx_cb_ptr;
+}
+
+/* Simple helper to free a control block's resources */
+static void bcmgenet_free_cb(struct enet_cb *cb)
+{
+ dev_kfree_skb_any(cb->skb);
+ cb->skb = NULL;
+ dma_unmap_addr_set(cb, dma_addr, 0);
+}
+
+static inline void bcmgenet_tx_ring16_int_disable(struct bcmgenet_priv *priv,
+ struct bcmgenet_tx_ring *ring)
+{
+ bcmgenet_intrl2_0_writel(priv,
+ UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE,
+ INTRL2_CPU_MASK_SET);
+}
+
+static inline void bcmgenet_tx_ring16_int_enable(struct bcmgenet_priv *priv,
+ struct bcmgenet_tx_ring *ring)
+{
+ bcmgenet_intrl2_0_writel(priv,
+ UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE,
+ INTRL2_CPU_MASK_CLEAR);
+}
+
+static inline void bcmgenet_tx_ring_int_enable(struct bcmgenet_priv *priv,
+ struct bcmgenet_tx_ring *ring)
+{
+ bcmgenet_intrl2_1_writel(priv,
+ (1 << ring->index), INTRL2_CPU_MASK_CLEAR);
+ priv->int1_mask &= ~(1 << ring->index);
+}
+
+static inline void bcmgenet_tx_ring_int_disable(struct bcmgenet_priv *priv,
+ struct bcmgenet_tx_ring *ring)
+{
+ bcmgenet_intrl2_1_writel(priv,
+ (1 << ring->index), INTRL2_CPU_MASK_SET);
+ priv->int1_mask |= (1 << ring->index);
+}
+
+/* Unlocked version of the reclaim routine */
+static void __bcmgenet_tx_reclaim(struct net_device *dev,
+ struct bcmgenet_tx_ring *ring)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ int last_tx_cn, last_c_index, num_tx_bds;
+ struct enet_cb *tx_cb_ptr;
+ struct netdev_queue *txq;
+ unsigned int c_index;
+
+ /* Compute how many buffers are transmited since last xmit call */
+ c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX);
+ txq = netdev_get_tx_queue(dev, ring->queue);
+
+ last_c_index = ring->c_index;
+ num_tx_bds = ring->size;
+
+ c_index &= (num_tx_bds - 1);
+
+ if (c_index >= last_c_index)
+ last_tx_cn = c_index - last_c_index;
+ else
+ last_tx_cn = num_tx_bds - last_c_index + c_index;
+
+ netif_dbg(priv, tx_done, dev,
+ "%s ring=%d index=%d last_tx_cn=%d last_index=%d\n",
+ __func__, ring->index,
+ c_index, last_tx_cn, last_c_index);
+
+ /* Reclaim transmitted buffers */
+ while (last_tx_cn-- > 0) {
+ tx_cb_ptr = ring->cbs + last_c_index;
+ if (tx_cb_ptr->skb) {
+ dev->stats.tx_bytes += tx_cb_ptr->skb->len;
+ dma_unmap_single(&dev->dev,
+ dma_unmap_addr(tx_cb_ptr, dma_addr),
+ tx_cb_ptr->skb->len,
+ DMA_TO_DEVICE);
+ bcmgenet_free_cb(tx_cb_ptr);
+ } else if (dma_unmap_addr(tx_cb_ptr, dma_addr)) {
+ dev->stats.tx_bytes +=
+ dma_unmap_len(tx_cb_ptr, dma_len);
+ dma_unmap_page(&dev->dev,
+ dma_unmap_addr(tx_cb_ptr, dma_addr),
+ dma_unmap_len(tx_cb_ptr, dma_len),
+ DMA_TO_DEVICE);
+ dma_unmap_addr_set(tx_cb_ptr, dma_addr, 0);
+ }
+ dev->stats.tx_packets++;
+ ring->free_bds += 1;
+
+ last_c_index++;
+ last_c_index &= (num_tx_bds - 1);
+ }
+
+ if (ring->free_bds > (MAX_SKB_FRAGS + 1))
+ ring->int_disable(priv, ring);
+
+ if (netif_tx_queue_stopped(txq))
+ netif_tx_wake_queue(txq);
+
+ ring->c_index = c_index;
+}
+
+static void bcmgenet_tx_reclaim(struct net_device *dev,
+ struct bcmgenet_tx_ring *ring)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ring->lock, flags);
+ __bcmgenet_tx_reclaim(dev, ring);
+ spin_unlock_irqrestore(&ring->lock, flags);
+}
+
+static void bcmgenet_tx_reclaim_all(struct net_device *dev)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ int i;
+
+ if (netif_is_multiqueue(dev)) {
+ for (i = 0; i < priv->hw_params->tx_queues; i++)
+ bcmgenet_tx_reclaim(dev, &priv->tx_rings[i]);
+ }
+
+ bcmgenet_tx_reclaim(dev, &priv->tx_rings[DESC_INDEX]);
+}
+
+/* Transmits a single SKB (either head of a fragment or a single SKB)
+ * caller must hold priv->lock
+ */
+static int bcmgenet_xmit_single(struct net_device *dev,
+ struct sk_buff *skb,
+ u16 dma_desc_flags,
+ struct bcmgenet_tx_ring *ring)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ struct device *kdev = &priv->pdev->dev;
+ struct enet_cb *tx_cb_ptr;
+ unsigned int skb_len;
+ dma_addr_t mapping;
+ u32 length_status;
+ int ret;
+
+ tx_cb_ptr = bcmgenet_get_txcb(priv, ring);
+
+ if (unlikely(!tx_cb_ptr))
+ BUG();
+
+ tx_cb_ptr->skb = skb;
+
+ skb_len = skb_headlen(skb) < ETH_ZLEN ? ETH_ZLEN : skb_headlen(skb);
+
+ mapping = dma_map_single(kdev, skb->data, skb_len, DMA_TO_DEVICE);
+ ret = dma_mapping_error(kdev, mapping);
+ if (ret) {
+ netif_err(priv, tx_err, dev, "Tx DMA map failed\n");
+ dev_kfree_skb(skb);
+ return ret;
+ }
+
+ dma_unmap_addr_set(tx_cb_ptr, dma_addr, mapping);
+ dma_unmap_len_set(tx_cb_ptr, dma_len, skb->len);
+ length_status = (skb_len << DMA_BUFLENGTH_SHIFT) | dma_desc_flags |
+ (priv->hw_params->qtag_mask << DMA_TX_QTAG_SHIFT) |
+ DMA_TX_APPEND_CRC;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ length_status |= DMA_TX_DO_CSUM;
+
+ dmadesc_set(priv, tx_cb_ptr->bd_addr, mapping, length_status);
+
+ /* Decrement total BD count and advance our write pointer */
+ ring->free_bds -= 1;
+ ring->prod_index += 1;
+ ring->prod_index &= DMA_P_INDEX_MASK;
+
+ return 0;
+}
+
+/* Transmit a SKB fragement */
+static int bcmgenet_xmit_frag(struct net_device *dev,
+ skb_frag_t *frag,
+ u16 dma_desc_flags,
+ struct bcmgenet_tx_ring *ring)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ struct device *kdev = &priv->pdev->dev;
+ struct enet_cb *tx_cb_ptr;
+ dma_addr_t mapping;
+ int ret;
+
+ tx_cb_ptr = bcmgenet_get_txcb(priv, ring);
+
+ if (unlikely(!tx_cb_ptr))
+ BUG();
+ tx_cb_ptr->skb = NULL;
+
+ mapping = skb_frag_dma_map(kdev, frag, 0,
+ skb_frag_size(frag), DMA_TO_DEVICE);
+ ret = dma_mapping_error(kdev, mapping);
+ if (ret) {
+ netif_err(priv, tx_err, dev, "%s: Tx DMA map failed\n",
+ __func__);
+ return ret;
+ }
+
+ dma_unmap_addr_set(tx_cb_ptr, dma_addr, mapping);
+ dma_unmap_len_set(tx_cb_ptr, dma_len, frag->size);
+
+ dmadesc_set(priv, tx_cb_ptr->bd_addr, mapping,
+ (frag->size << DMA_BUFLENGTH_SHIFT) | dma_desc_flags |
+ (priv->hw_params->qtag_mask << DMA_TX_QTAG_SHIFT));
+
+
+ ring->free_bds -= 1;
+ ring->prod_index += 1;
+ ring->prod_index &= DMA_P_INDEX_MASK;
+
+ return 0;
+}
+
+/* Reallocate the SKB to put enough headroom in front of it and insert
+ * the transmit checksum offsets in the descriptors
+ */
+static int bcmgenet_put_tx_csum(struct net_device *dev, struct sk_buff *skb)
+{
+ struct status_64 *status = NULL;
+ struct sk_buff *new_skb;
+ u16 offset;
+ u8 ip_proto;
+ u16 ip_ver;
+ u32 tx_csum_info;
+
+ if (unlikely(skb_headroom(skb) < sizeof(*status))) {
+ /* If 64 byte status block enabled, must make sure skb has
+ * enough headroom for us to insert 64B status block.
+ */
+ new_skb = skb_realloc_headroom(skb, sizeof(*status));
+ dev_kfree_skb(skb);
+ if (!new_skb) {
+ dev->stats.tx_errors++;
+ dev->stats.tx_dropped++;
+ return -ENOMEM;
+ }
+ skb = new_skb;
+ }
+
+ skb_push(skb, sizeof(*status));
+ status = (struct status_64 *)skb->data;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ ip_ver = htons(skb->protocol);
+ switch (ip_ver) {
+ case ETH_P_IP:
+ ip_proto = ip_hdr(skb)->protocol;
+ break;
+ case ETH_P_IPV6:
+ ip_proto = ipv6_hdr(skb)->nexthdr;
+ break;
+ default:
+ return 0;
+ }
+
+ offset = skb_checksum_start_offset(skb) - sizeof(*status);
+ tx_csum_info = (offset << STATUS_TX_CSUM_START_SHIFT) |
+ (offset + skb->csum_offset);
+
+ /* Set the length valid bit for TCP and UDP and just set
+ * the special UDP flag for IPv4, else just set to 0.
+ */
+ if (ip_proto == IPPROTO_TCP || ip_proto == IPPROTO_UDP) {
+ tx_csum_info |= STATUS_TX_CSUM_LV;
+ if (ip_proto == IPPROTO_UDP && ip_ver == ETH_P_IP)
+ tx_csum_info |= STATUS_TX_CSUM_PROTO_UDP;
+ } else
+ tx_csum_info = 0;
+
+ status->tx_csum_info = tx_csum_info;
+ }
+
+ return 0;
+}
+
+static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ struct bcmgenet_tx_ring *ring = NULL;
+ struct netdev_queue *txq;
+ unsigned long flags = 0;
+ int nr_frags, index;
+ u16 dma_desc_flags;
+ int ret;
+ int i;
+
+ index = skb_get_queue_mapping(skb);
+ /* Mapping strategy:
+ * queue_mapping = 0, unclassified, packet xmited through ring16
+ * queue_mapping = 1, goes to ring 0. (highest priority queue
+ * queue_mapping = 2, goes to ring 1.
+ * queue_mapping = 3, goes to ring 2.
+ * queue_mapping = 4, goes to ring 3.
+ */
+ if (index == 0)
+ index = DESC_INDEX;
+ else
+ index -= 1;
+
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ ring = &priv->tx_rings[index];
+ txq = netdev_get_tx_queue(dev, ring->queue);
+
+ spin_lock_irqsave(&ring->lock, flags);
+ if (ring->free_bds <= nr_frags + 1) {
+ netif_tx_stop_queue(txq);
+ netdev_err(dev, "%s: tx ring %d full when queue %d awake\n",
+ __func__, index, ring->queue);
+ ret = NETDEV_TX_BUSY;
+ goto out;
+ }
+
+ /* set the SKB transmit checksum */
+ if (priv->desc_64b_en) {
+ ret = bcmgenet_put_tx_csum(dev, skb);
+ if (ret) {
+ ret = NETDEV_TX_OK;
+ goto out;
+ }
+ }
+
+ dma_desc_flags = DMA_SOP;
+ if (nr_frags == 0)
+ dma_desc_flags |= DMA_EOP;
+
+ /* Transmit single SKB or head of fragment list */
+ ret = bcmgenet_xmit_single(dev, skb, dma_desc_flags, ring);
+ if (ret) {
+ ret = NETDEV_TX_OK;
+ goto out;
+ }
+
+ /* xmit fragment */
+ for (i = 0; i < nr_frags; i++) {
+ ret = bcmgenet_xmit_frag(dev,
+ &skb_shinfo(skb)->frags[i],
+ (i == nr_frags - 1) ? DMA_EOP : 0, ring);
+ if (ret) {
+ ret = NETDEV_TX_OK;
+ goto out;
+ }
+ }
+
+ skb_tx_timestamp(skb);
+
+ /* we kept a software copy of how much we should advance the TDMA
+ * producer index, now write it down to the hardware
+ */
+ bcmgenet_tdma_ring_writel(priv, ring->index,
+ ring->prod_index, TDMA_PROD_INDEX);
+
+ if (ring->free_bds <= (MAX_SKB_FRAGS + 1)) {
+ netif_tx_stop_queue(txq);
+ ring->int_enable(priv, ring);
+ }
+
+out:
+ spin_unlock_irqrestore(&ring->lock, flags);
+
+ return ret;
+}
+
+
+static int bcmgenet_rx_refill(struct bcmgenet_priv *priv,
+ struct enet_cb *cb)
+{
+ struct device *kdev = &priv->pdev->dev;
+ struct sk_buff *skb;
+ dma_addr_t mapping;
+ int ret;
+
+ skb = netdev_alloc_skb(priv->dev,
+ priv->rx_buf_len + SKB_ALIGNMENT);
+ if (!skb)
+ return -ENOMEM;
+
+ /* a caller did not release this control block */
+ WARN_ON(cb->skb != NULL);
+ cb->skb = skb;
+ mapping = dma_map_single(kdev, skb->data,
+ priv->rx_buf_len, DMA_FROM_DEVICE);
+ ret = dma_mapping_error(kdev, mapping);
+ if (ret) {
+ bcmgenet_free_cb(cb);
+ netif_err(priv, rx_err, priv->dev,
+ "%s DMA map failed\n", __func__);
+ return ret;
+ }
+
+ dma_unmap_addr_set(cb, dma_addr, mapping);
+ /* assign packet, prepare descriptor, and advance pointer */
+
+ dmadesc_set_addr(priv, priv->rx_bd_assign_ptr, mapping);
+
+ /* turn on the newly assigned BD for DMA to use */
+ priv->rx_bd_assign_index++;
+ priv->rx_bd_assign_index &= (priv->num_rx_bds - 1);
+
+ priv->rx_bd_assign_ptr = priv->rx_bds +
+ (priv->rx_bd_assign_index * DMA_DESC_SIZE);
+
+ return 0;
+}
+
+/* bcmgenet_desc_rx - descriptor based rx process.
+ * this could be called from bottom half, or from NAPI polling method.
+ */
+static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
+ unsigned int budget)
+{
+ struct net_device *dev = priv->dev;
+ struct enet_cb *cb;
+ struct sk_buff *skb;
+ u32 dma_length_status;
+ unsigned long dma_flag;
+ int len, err;
+ unsigned int rxpktprocessed = 0, rxpkttoprocess;
+ unsigned int p_index;
+ unsigned int chksum_ok = 0;
+
+ p_index = bcmgenet_rdma_ring_readl(priv,
+ DESC_INDEX, RDMA_PROD_INDEX);
+ p_index &= DMA_P_INDEX_MASK;
+
+ if (p_index < priv->rx_c_index)
+ rxpkttoprocess = (DMA_C_INDEX_MASK + 1) -
+ priv->rx_c_index + p_index;
+ else
+ rxpkttoprocess = p_index - priv->rx_c_index;
+
+ netif_dbg(priv, rx_status, dev,
+ "RDMA: rxpkttoprocess=%d\n", rxpkttoprocess);
+
+ while ((rxpktprocessed < rxpkttoprocess) &&
+ (rxpktprocessed < budget)) {
+
+ /* Unmap the packet contents such that we can use the
+ * RSV from the 64 bytes descriptor when enabled and save
+ * a 32-bits register read
+ */
+ cb = &priv->rx_cbs[priv->rx_read_ptr];
+ skb = cb->skb;
+ dma_unmap_single(&dev->dev, dma_unmap_addr(cb, dma_addr),
+ priv->rx_buf_len, DMA_FROM_DEVICE);
+
+ if (!priv->desc_64b_en) {
+ dma_length_status = dmadesc_get_length_status(priv,
+ priv->rx_bds +
+ (priv->rx_read_ptr *
+ DMA_DESC_SIZE));
+ } else {
+ struct status_64 *status;
+ status = (struct status_64 *)skb->data;
+ dma_length_status = status->length_status;
+ }
+
+ /* DMA flags and length are still valid no matter how
+ * we got the Receive Status Vector (64B RSB or register)
+ */
+ dma_flag = dma_length_status & 0xffff;
+ len = dma_length_status >> DMA_BUFLENGTH_SHIFT;
+
+ netif_dbg(priv, rx_status, dev,
+ "%s: p_ind=%d c_ind=%d read_ptr=%d len_stat=0x%08x\n",
+ __func__, p_index, priv->rx_c_index, priv->rx_read_ptr,
+ dma_length_status);
+
+ rxpktprocessed++;
+
+ priv->rx_read_ptr++;
+ priv->rx_read_ptr &= (priv->num_rx_bds - 1);
+
+ /* out of memory, just drop packets at the hardware level */
+ if (unlikely(!skb)) {
+ dev->stats.rx_dropped++;
+ dev->stats.rx_errors++;
+ goto refill;
+ }
+
+ if (unlikely(!(dma_flag & DMA_EOP) || !(dma_flag & DMA_SOP))) {
+ netif_err(priv, rx_status, dev,
+ "Droping fragmented packet!\n");
+ dev->stats.rx_dropped++;
+ dev->stats.rx_errors++;
+ dev_kfree_skb_any(cb->skb);
+ cb->skb = NULL;
+ goto refill;
+ }
+ /* report errors */
+ if (unlikely(dma_flag & (DMA_RX_CRC_ERROR |
+ DMA_RX_OV |
+ DMA_RX_NO |
+ DMA_RX_LG |
+ DMA_RX_RXER))) {
+ netif_err(priv, rx_status, dev, "dma_flag=0x%x\n",
+ (unsigned int)dma_flag);
+ if (dma_flag & DMA_RX_CRC_ERROR)
+ dev->stats.rx_crc_errors++;
+ if (dma_flag & DMA_RX_OV)
+ dev->stats.rx_over_errors++;
+ if (dma_flag & DMA_RX_NO)
+ dev->stats.rx_frame_errors++;
+ if (dma_flag & DMA_RX_LG)
+ dev->stats.rx_length_errors++;
+ dev->stats.rx_dropped++;
+ dev->stats.rx_errors++;
+
+ /* discard the packet and advance consumer index.*/
+ dev_kfree_skb_any(cb->skb);
+ cb->skb = NULL;
+ goto refill;
+ } /* error packet */
+
+ chksum_ok = (dma_flag & priv->dma_rx_chk_bit) &&
+ priv->desc_rxchk_en;
+
+ skb_put(skb, len);
+ if (priv->desc_64b_en) {
+ skb_pull(skb, 64);
+ len -= 64;
+ }
+
+ if (likely(chksum_ok))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ /* remove hardware 2bytes added for IP alignment */
+ skb_pull(skb, 2);
+ len -= 2;
+
+ if (priv->crc_fwd_en) {
+ skb_trim(skb, len - ETH_FCS_LEN);
+ len -= ETH_FCS_LEN;
+ }
+
+ /*Finish setting up the received SKB and send it to the kernel*/
+ skb->protocol = eth_type_trans(skb, priv->dev);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
+ if (dma_flag & DMA_RX_MULT)
+ dev->stats.multicast++;
+
+ /* Notify kernel */
+ napi_gro_receive(&priv->napi, skb);
+ cb->skb = NULL;
+ netif_dbg(priv, rx_status, dev, "pushed up to kernel\n");
+
+ /* refill RX path on the current control block */
+refill:
+ err = bcmgenet_rx_refill(priv, cb);
+ if (err)
+ netif_err(priv, rx_err, dev, "Rx refill failed\n");
+ }
+
+ return rxpktprocessed;
+}
+
+/* Assign skb to RX DMA descriptor. */
+static int bcmgenet_alloc_rx_buffers(struct bcmgenet_priv *priv)
+{
+ struct enet_cb *cb;
+ int ret = 0;
+ int i;
+
+ netif_dbg(priv, hw, priv->dev, "%s:\n", __func__);
+
+ /* loop here for each buffer needing assign */
+ for (i = 0; i < priv->num_rx_bds; i++) {
+ cb = &priv->rx_cbs[priv->rx_bd_assign_index];
+ if (cb->skb)
+ continue;
+
+ /* set the DMA descriptor length once and for all
+ * it will only change if we support dynamically sizing
+ * priv->rx_buf_len, but we do not
+ */
+ dmadesc_set_length_status(priv, priv->rx_bd_assign_ptr,
+ priv->rx_buf_len << DMA_BUFLENGTH_SHIFT);
+
+ ret = bcmgenet_rx_refill(priv, cb);
+ if (ret)
+ break;
+
+ }
+
+ return ret;
+}
+
+static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv)
+{
+ struct enet_cb *cb;
+ int i;
+
+ for (i = 0; i < priv->num_rx_bds; i++) {
+ cb = &priv->rx_cbs[i];
+
+ if (dma_unmap_addr(cb, dma_addr)) {
+ dma_unmap_single(&priv->dev->dev,
+ dma_unmap_addr(cb, dma_addr),
+ priv->rx_buf_len, DMA_FROM_DEVICE);
+ dma_unmap_addr_set(cb, dma_addr, 0);
+ }
+
+ if (cb->skb)
+ bcmgenet_free_cb(cb);
+ }
+}
+
+static int reset_umac(struct bcmgenet_priv *priv)
+{
+ struct device *kdev = &priv->pdev->dev;
+ unsigned int timeout = 0;
+ u32 reg;
+
+ /* 7358a0/7552a0: bad default in RBUF_FLUSH_CTRL.umac_sw_rst */
+ bcmgenet_rbuf_ctrl_set(priv, 0);
+ udelay(10);
+
+ /* disable MAC while updating its registers */
+ bcmgenet_umac_writel(priv, 0, UMAC_CMD);
+
+ /* issue soft reset, wait for it to complete */
+ bcmgenet_umac_writel(priv, CMD_SW_RESET, UMAC_CMD);
+ while (timeout++ < 1000) {
+ reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+ if (!(reg & CMD_SW_RESET))
+ return 0;
+
+ udelay(1);
+ }
+
+ if (timeout == 1000) {
+ dev_err(kdev,
+ "timeout waiting for MAC to come out of resetn\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int init_umac(struct bcmgenet_priv *priv)
+{
+ struct device *kdev = &priv->pdev->dev;
+ int ret;
+ u32 reg, cpu_mask_clear;
+
+ dev_dbg(&priv->pdev->dev, "bcmgenet: init_umac\n");
+
+ ret = reset_umac(priv);
+ if (ret)
+ return ret;
+
+ bcmgenet_umac_writel(priv, 0, UMAC_CMD);
+ /* clear tx/rx counter */
+ bcmgenet_umac_writel(priv,
+ MIB_RESET_RX | MIB_RESET_TX | MIB_RESET_RUNT, UMAC_MIB_CTRL);
+ bcmgenet_umac_writel(priv, 0, UMAC_MIB_CTRL);
+
+ bcmgenet_umac_writel(priv, ENET_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN);
+
+ /* init rx registers, enable ip header optimization */
+ reg = bcmgenet_rbuf_readl(priv, RBUF_CTRL);
+ reg |= RBUF_ALIGN_2B;
+ bcmgenet_rbuf_writel(priv, reg, RBUF_CTRL);
+
+ if (!GENET_IS_V1(priv) && !GENET_IS_V2(priv))
+ bcmgenet_rbuf_writel(priv, 1, RBUF_TBUF_SIZE_CTRL);
+
+ /* Mask all interrupts.*/
+ bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET);
+ bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR);
+ bcmgenet_intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
+
+ cpu_mask_clear = UMAC_IRQ_RXDMA_BDONE;
+
+ dev_dbg(kdev, "%s:Enabling RXDMA_BDONE interrupt\n", __func__);
+
+ /* Monitor cable plug/unpluged event for internal PHY */
+ if (phy_is_internal(priv->phydev))
+ cpu_mask_clear |= (UMAC_IRQ_LINK_DOWN | UMAC_IRQ_LINK_UP);
+ else if (priv->ext_phy)
+ cpu_mask_clear |= (UMAC_IRQ_LINK_DOWN | UMAC_IRQ_LINK_UP);
+ else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
+ reg = bcmgenet_bp_mc_get(priv);
+ reg |= BIT(priv->hw_params->bp_in_en_shift);
+
+ /* bp_mask: back pressure mask */
+ if (netif_is_multiqueue(priv->dev))
+ reg |= priv->hw_params->bp_in_mask;
+ else
+ reg &= ~priv->hw_params->bp_in_mask;
+ bcmgenet_bp_mc_set(priv, reg);
+ }
+
+ /* Enable MDIO interrupts on GENET v3+ */
+ if (priv->hw_params->flags & GENET_HAS_MDIO_INTR)
+ cpu_mask_clear |= UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR;
+
+ bcmgenet_intrl2_0_writel(priv, cpu_mask_clear,
+ INTRL2_CPU_MASK_CLEAR);
+
+ /* Enable rx/tx engine.*/
+ dev_dbg(kdev, "done init umac\n");
+
+ return 0;
+}
+
+/* Initialize all house-keeping variables for a TX ring, along
+ * with corresponding hardware registers
+ */
+static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv,
+ unsigned int index, unsigned int size,
+ unsigned int write_ptr, unsigned int end_ptr)
+{
+ struct bcmgenet_tx_ring *ring = &priv->tx_rings[index];
+ u32 words_per_bd = WORDS_PER_BD(priv);
+ u32 flow_period_val = 0;
+ unsigned int first_bd;
+
+ spin_lock_init(&ring->lock);
+ ring->index = index;
+ if (index == DESC_INDEX) {
+ ring->queue = 0;
+ ring->int_enable = bcmgenet_tx_ring16_int_enable;
+ ring->int_disable = bcmgenet_tx_ring16_int_disable;
+ } else {
+ ring->queue = index + 1;
+ ring->int_enable = bcmgenet_tx_ring_int_enable;
+ ring->int_disable = bcmgenet_tx_ring_int_disable;
+ }
+ ring->cbs = priv->tx_cbs + write_ptr;
+ ring->size = size;
+ ring->c_index = 0;
+ ring->free_bds = size;
+ ring->write_ptr = write_ptr;
+ ring->cb_ptr = write_ptr;
+ ring->end_ptr = end_ptr - 1;
+ ring->prod_index = 0;
+
+ /* Set flow period for ring != 16 */
+ if (index != DESC_INDEX)
+ flow_period_val = ENET_MAX_MTU_SIZE << 16;
+
+ bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX);
+ bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_CONS_INDEX);
+ bcmgenet_tdma_ring_writel(priv, index, 1, DMA_MBUF_DONE_THRESH);
+ /* Disable rate control for now */
+ bcmgenet_tdma_ring_writel(priv, index, flow_period_val,
+ TDMA_FLOW_PERIOD);
+ /* Unclassified traffic goes to ring 16 */
+ bcmgenet_tdma_ring_writel(priv, index,
+ ((size << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH),
+ DMA_RING_BUF_SIZE);
+
+ first_bd = write_ptr;
+
+ /* Set start and end address, read and write pointers */
+ bcmgenet_tdma_ring_writel(priv, index, first_bd * words_per_bd,
+ DMA_START_ADDR);
+ bcmgenet_tdma_ring_writel(priv, index, first_bd * words_per_bd,
+ TDMA_READ_PTR);
+ bcmgenet_tdma_ring_writel(priv, index, first_bd,
+ TDMA_WRITE_PTR);
+ bcmgenet_tdma_ring_writel(priv, index, end_ptr * words_per_bd - 1,
+ DMA_END_ADDR);
+}
+
+/* Initialize a RDMA ring */
+static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv,
+ unsigned int index, unsigned int size)
+{
+ u32 words_per_bd = WORDS_PER_BD(priv);
+ int ret;
+
+ priv->num_rx_bds = TOTAL_DESC;
+ priv->rx_bds = priv->base + priv->hw_params->rdma_offset;
+ priv->rx_bd_assign_ptr = priv->rx_bds;
+ priv->rx_bd_assign_index = 0;
+ priv->rx_c_index = 0;
+ priv->rx_read_ptr = 0;
+ priv->rx_cbs = kzalloc(priv->num_rx_bds * sizeof(struct enet_cb),
+ GFP_KERNEL);
+ if (!priv->rx_cbs)
+ return -ENOMEM;
+
+ ret = bcmgenet_alloc_rx_buffers(priv);
+ if (ret) {
+ kfree(priv->rx_cbs);
+ return ret;
+ }
+
+ bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_WRITE_PTR);
+ bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_PROD_INDEX);
+ bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_CONS_INDEX);
+ bcmgenet_rdma_ring_writel(priv, index,
+ ((size << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH),
+ DMA_RING_BUF_SIZE);
+ bcmgenet_rdma_ring_writel(priv, index, 0, DMA_START_ADDR);
+ bcmgenet_rdma_ring_writel(priv, index,
+ words_per_bd * size - 1, DMA_END_ADDR);
+ bcmgenet_rdma_ring_writel(priv, index,
+ (DMA_FC_THRESH_LO << DMA_XOFF_THRESHOLD_SHIFT) |
+ DMA_FC_THRESH_HI, RDMA_XON_XOFF_THRESH);
+ bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_READ_PTR);
+
+ return ret;
+}
+
+/* init multi xmit queues, only available for GENET2+
+ * the queue is partitioned as follows:
+ *
+ * queue 0 - 3 is priority based, each one has 32 descriptors,
+ * with queue 0 being the highest priority queue.
+ *
+ * queue 16 is the default tx queue with GENET_DEFAULT_BD_CNT
+ * descriptors: 256 - (number of tx queues * bds per queues) = 128
+ * descriptors.
+ *
+ * The transmit control block pool is then partitioned as following:
+ * - tx_cbs[0...127] are for queue 16
+ * - tx_ring_cbs[0] points to tx_cbs[128..159]
+ * - tx_ring_cbs[1] points to tx_cbs[160..191]
+ * - tx_ring_cbs[2] points to tx_cbs[192..223]
+ * - tx_ring_cbs[3] points to tx_cbs[224..255]
+ */
+static void bcmgenet_init_multiq(struct net_device *dev)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ unsigned int i, dma_enable;
+ u32 reg, dma_ctrl, ring_cfg = 0, dma_priority = 0;
+
+ if (!netif_is_multiqueue(dev)) {
+ netdev_warn(dev, "called with non multi queue aware HW\n");
+ return;
+ }
+
+ dma_ctrl = bcmgenet_tdma_readl(priv, DMA_CTRL);
+ dma_enable = dma_ctrl & DMA_EN;
+ dma_ctrl &= ~DMA_EN;
+ bcmgenet_tdma_writel(priv, dma_ctrl, DMA_CTRL);
+
+ /* Enable strict priority arbiter mode */
+ bcmgenet_tdma_writel(priv, DMA_ARBITER_SP, DMA_ARB_CTRL);
+
+ for (i = 0; i < priv->hw_params->tx_queues; i++) {
+ /* first 64 tx_cbs are reserved for default tx queue
+ * (ring 16)
+ */
+ bcmgenet_init_tx_ring(priv, i, priv->hw_params->bds_cnt,
+ i * priv->hw_params->bds_cnt,
+ (i + 1) * priv->hw_params->bds_cnt);
+
+ /* Configure ring as decriptor ring and setup priority */
+ ring_cfg |= 1 << i;
+ dma_priority |= ((GENET_Q0_PRIORITY + i) <<
+ (GENET_MAX_MQ_CNT + 1) * i);
+ dma_ctrl |= 1 << (i + DMA_RING_BUF_EN_SHIFT);
+ }
+
+ /* Enable rings */
+ reg = bcmgenet_tdma_readl(priv, DMA_RING_CFG);
+ reg |= ring_cfg;
+ bcmgenet_tdma_writel(priv, reg, DMA_RING_CFG);
+
+ /* Use configured rings priority and set ring #16 priority */
+ reg = bcmgenet_tdma_readl(priv, DMA_RING_PRIORITY);
+ reg |= ((GENET_Q0_PRIORITY + priv->hw_params->tx_queues) << 20);
+ reg |= dma_priority;
+ bcmgenet_tdma_writel(priv, reg, DMA_PRIORITY);
+
+ /* Configure ring as descriptor ring and re-enable DMA if enabled */
+ reg = bcmgenet_tdma_readl(priv, DMA_CTRL);
+ reg |= dma_ctrl;
+ if (dma_enable)
+ reg |= DMA_EN;
+ bcmgenet_tdma_writel(priv, reg, DMA_CTRL);
+}
+
+static void bcmgenet_fini_dma(struct bcmgenet_priv *priv)
+{
+ int i;
+
+ /* disable DMA */
+ bcmgenet_rdma_writel(priv, 0, DMA_CTRL);
+ bcmgenet_tdma_writel(priv, 0, DMA_CTRL);
+
+ for (i = 0; i < priv->num_tx_bds; i++) {
+ if (priv->tx_cbs[i].skb != NULL) {
+ dev_kfree_skb(priv->tx_cbs[i].skb);
+ priv->tx_cbs[i].skb = NULL;
+ }
+ }
+
+ bcmgenet_free_rx_buffers(priv);
+ kfree(priv->rx_cbs);
+ kfree(priv->tx_cbs);
+}
+
+/* init_edma: Initialize DMA control register */
+static int bcmgenet_init_dma(struct bcmgenet_priv *priv)
+{
+ int ret;
+
+ netif_dbg(priv, hw, priv->dev, "bcmgenet: init_edma\n");
+
+ /* by default, enable ring 16 (descriptor based) */
+ ret = bcmgenet_init_rx_ring(priv, DESC_INDEX, TOTAL_DESC);
+ if (ret) {
+ netdev_err(priv->dev, "failed to initialize RX ring\n");
+ return ret;
+ }
+
+ /* init rDma */
+ bcmgenet_rdma_writel(priv, DMA_MAX_BURST_LENGTH, DMA_SCB_BURST_SIZE);
+
+ /* Init tDma */
+ bcmgenet_tdma_writel(priv, DMA_MAX_BURST_LENGTH, DMA_SCB_BURST_SIZE);
+
+ /* Initialize commont TX ring structures */
+ priv->tx_bds = priv->base + priv->hw_params->tdma_offset;
+ priv->num_tx_bds = TOTAL_DESC;
+ priv->tx_cbs = kzalloc(priv->num_tx_bds * sizeof(struct enet_cb),
+ GFP_KERNEL);
+ if (!priv->tx_cbs) {
+ bcmgenet_fini_dma(priv);
+ return -ENOMEM;
+ }
+
+ /* initialize multi xmit queue */
+ bcmgenet_init_multiq(priv->dev);
+
+ /* initialize special ring 16 */
+ bcmgenet_init_tx_ring(priv, DESC_INDEX, GENET_DEFAULT_BD_CNT,
+ priv->hw_params->tx_queues * priv->hw_params->bds_cnt,
+ TOTAL_DESC);
+
+ return 0;
+}
+
+/* NAPI polling method*/
+static int bcmgenet_poll(struct napi_struct *napi, int budget)
+{
+ struct bcmgenet_priv *priv = container_of(napi,
+ struct bcmgenet_priv, napi);
+ unsigned int work_done;
+
+ /* tx reclaim */
+ bcmgenet_tx_reclaim(priv->dev, &priv->tx_rings[DESC_INDEX]);
+
+ work_done = bcmgenet_desc_rx(priv, budget);
+
+ /* Advancing our consumer index*/
+ priv->rx_c_index += work_done;
+ priv->rx_c_index &= DMA_C_INDEX_MASK;
+ bcmgenet_rdma_ring_writel(priv, DESC_INDEX,
+ priv->rx_c_index, RDMA_CONS_INDEX);
+ if (work_done < budget) {
+ napi_complete(napi);
+ bcmgenet_intrl2_0_writel(priv,
+ UMAC_IRQ_RXDMA_BDONE, INTRL2_CPU_MASK_CLEAR);
+ }
+
+ return work_done;
+}
+
+/* Interrupt bottom half */
+static void bcmgenet_irq_task(struct work_struct *work)
+{
+ struct bcmgenet_priv *priv = container_of(
+ work, struct bcmgenet_priv, bcmgenet_irq_work);
+
+ netif_dbg(priv, intr, priv->dev, "%s\n", __func__);
+
+ /* Link UP/DOWN event */
+ if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) &&
+ (priv->irq0_stat & (UMAC_IRQ_LINK_UP|UMAC_IRQ_LINK_DOWN))) {
+ phy_mac_interrupt(priv->phydev,
+ priv->irq0_stat & UMAC_IRQ_LINK_UP);
+ priv->irq0_stat &= ~(UMAC_IRQ_LINK_UP|UMAC_IRQ_LINK_DOWN);
+ }
+}
+
+/* bcmgenet_isr1: interrupt handler for ring buffer. */
+static irqreturn_t bcmgenet_isr1(int irq, void *dev_id)
+{
+ struct bcmgenet_priv *priv = dev_id;
+ unsigned int index;
+
+ /* Save irq status for bottom-half processing. */
+ priv->irq1_stat =
+ bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_STAT) &
+ ~priv->int1_mask;
+ /* clear inerrupts*/
+ bcmgenet_intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR);
+
+ netif_dbg(priv, intr, priv->dev,
+ "%s: IRQ=0x%x\n", __func__, priv->irq1_stat);
+ /* Check the MBDONE interrupts.
+ * packet is done, reclaim descriptors
+ */
+ if (priv->irq1_stat & 0x0000ffff) {
+ index = 0;
+ for (index = 0; index < 16; index++) {
+ if (priv->irq1_stat & (1 << index))
+ bcmgenet_tx_reclaim(priv->dev,
+ &priv->tx_rings[index]);
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+/* bcmgenet_isr0: Handle various interrupts. */
+static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
+{
+ struct bcmgenet_priv *priv = dev_id;
+
+ /* Save irq status for bottom-half processing. */
+ priv->irq0_stat =
+ bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT) &
+ ~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS);
+ /* clear inerrupts*/
+ bcmgenet_intrl2_0_writel(priv, priv->irq0_stat, INTRL2_CPU_CLEAR);
+
+ netif_dbg(priv, intr, priv->dev,
+ "IRQ=0x%x\n", priv->irq0_stat);
+
+ if (priv->irq0_stat & (UMAC_IRQ_RXDMA_BDONE | UMAC_IRQ_RXDMA_PDONE)) {
+ /* We use NAPI(software interrupt throttling, if
+ * Rx Descriptor throttling is not used.
+ * Disable interrupt, will be enabled in the poll method.
+ */
+ if (likely(napi_schedule_prep(&priv->napi))) {
+ bcmgenet_intrl2_0_writel(priv,
+ UMAC_IRQ_RXDMA_BDONE, INTRL2_CPU_MASK_SET);
+ __napi_schedule(&priv->napi);
+ }
+ }
+ if (priv->irq0_stat &
+ (UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE)) {
+ /* Tx reclaim */
+ bcmgenet_tx_reclaim(priv->dev, &priv->tx_rings[DESC_INDEX]);
+ }
+ if (priv->irq0_stat & (UMAC_IRQ_PHY_DET_R |
+ UMAC_IRQ_PHY_DET_F |
+ UMAC_IRQ_LINK_UP |
+ UMAC_IRQ_LINK_DOWN |
+ UMAC_IRQ_HFB_SM |
+ UMAC_IRQ_HFB_MM |
+ UMAC_IRQ_MPD_R)) {
+ /* all other interested interrupts handled in bottom half */
+ schedule_work(&priv->bcmgenet_irq_work);
+ }
+
+ if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) &&
+ priv->irq0_stat & (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR)) {
+ priv->irq0_stat &= ~(UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR);
+ wake_up(&priv->wq);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void bcmgenet_umac_reset(struct bcmgenet_priv *priv)
+{
+ u32 reg;
+
+ reg = bcmgenet_rbuf_ctrl_get(priv);
+ reg |= BIT(1);
+ bcmgenet_rbuf_ctrl_set(priv, reg);
+ udelay(10);
+
+ reg &= ~BIT(1);
+ bcmgenet_rbuf_ctrl_set(priv, reg);
+ udelay(10);
+}
+
+static void bcmgenet_set_hw_addr(struct bcmgenet_priv *priv,
+ unsigned char *addr)
+{
+ bcmgenet_umac_writel(priv, (addr[0] << 24) | (addr[1] << 16) |
+ (addr[2] << 8) | addr[3], UMAC_MAC0);
+ bcmgenet_umac_writel(priv, (addr[4] << 8) | addr[5], UMAC_MAC1);
+}
+
+static int bcmgenet_wol_resume(struct bcmgenet_priv *priv)
+{
+ int ret;
+
+ /* From WOL-enabled suspend, switch to regular clock */
+ clk_disable(priv->clk_wol);
+ /* init umac registers to synchronize s/w with h/w */
+ ret = init_umac(priv);
+ if (ret)
+ return ret;
+
+ phy_init_hw(priv->phydev);
+ /* Speed settings must be restored */
+ bcmgenet_mii_config(priv->dev);
+
+ return 0;
+}
+
+/* Returns a reusable dma control register value */
+static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv)
+{
+ u32 reg;
+ u32 dma_ctrl;
+
+ /* disable DMA */
+ dma_ctrl = 1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT) | DMA_EN;
+ reg = bcmgenet_tdma_readl(priv, DMA_CTRL);
+ reg &= ~dma_ctrl;
+ bcmgenet_tdma_writel(priv, reg, DMA_CTRL);
+
+ reg = bcmgenet_rdma_readl(priv, DMA_CTRL);
+ reg &= ~dma_ctrl;
+ bcmgenet_rdma_writel(priv, reg, DMA_CTRL);
+
+ bcmgenet_umac_writel(priv, 1, UMAC_TX_FLUSH);
+ udelay(10);
+ bcmgenet_umac_writel(priv, 0, UMAC_TX_FLUSH);
+
+ return dma_ctrl;
+}
+
+static void bcmgenet_enable_dma(struct bcmgenet_priv *priv, u32 dma_ctrl)
+{
+ u32 reg;
+
+ reg = bcmgenet_rdma_readl(priv, DMA_CTRL);
+ reg |= dma_ctrl;
+ bcmgenet_rdma_writel(priv, reg, DMA_CTRL);
+
+ reg = bcmgenet_tdma_readl(priv, DMA_CTRL);
+ reg |= dma_ctrl;
+ bcmgenet_tdma_writel(priv, reg, DMA_CTRL);
+}
+
+static int bcmgenet_open(struct net_device *dev)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ unsigned long dma_ctrl;
+ u32 reg;
+ int ret;
+
+ netif_dbg(priv, ifup, dev, "bcmgenet_open\n");
+
+ /* Turn on the clock */
+ if (!IS_ERR(priv->clk))
+ clk_prepare_enable(priv->clk);
+
+ /* take MAC out of reset */
+ bcmgenet_umac_reset(priv);
+
+ ret = init_umac(priv);
+ if (ret)
+ goto err_clk_disable;
+
+ /* disable ethernet MAC while updating its registers */
+ reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+ reg &= ~(CMD_TX_EN | CMD_RX_EN);
+ bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+
+ bcmgenet_set_hw_addr(priv, dev->dev_addr);
+
+ if (priv->wol_enabled) {
+ ret = bcmgenet_wol_resume(priv);
+ if (ret)
+ return ret;
+ }
+
+ if (phy_is_internal(priv->phydev)) {
+ reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
+ reg |= EXT_ENERGY_DET_MASK;
+ bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
+ }
+
+ /* Disable RX/TX DMA and flush TX queues */
+ dma_ctrl = bcmgenet_dma_disable(priv);
+
+ /* Reinitialize TDMA and RDMA and SW housekeeping */
+ ret = bcmgenet_init_dma(priv);
+ if (ret) {
+ netdev_err(dev, "failed to initialize DMA\n");
+ goto err_fini_dma;
+ }
+
+ /* Always enable ring 16 - descriptor ring */
+ bcmgenet_enable_dma(priv, dma_ctrl);
+
+ ret = request_irq(priv->irq0, bcmgenet_isr0, IRQF_SHARED,
+ dev->name, priv);
+ if (ret < 0) {
+ netdev_err(dev, "can't request IRQ %d\n", priv->irq0);
+ goto err_fini_dma;
+ }
+
+ ret = request_irq(priv->irq1, bcmgenet_isr1, IRQF_SHARED,
+ dev->name, priv);
+ if (ret < 0) {
+ netdev_err(dev, "can't request IRQ %d\n", priv->irq1);
+ goto err_irq0;
+ }
+
+ /* Start the network engine */
+ napi_enable(&priv->napi);
+
+ reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+ reg |= (CMD_TX_EN | CMD_RX_EN);
+ bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+
+ /* Make sure we reflect the value of CRC_CMD_FWD */
+ priv->crc_fwd_en = !!(reg & CMD_CRC_FWD);
+
+ device_set_wakeup_capable(&dev->dev, 1);
+
+ if (phy_is_internal(priv->phydev))
+ bcmgenet_power_up(priv, GENET_POWER_PASSIVE);
+
+ netif_tx_start_all_queues(dev);
+
+ phy_start(priv->phydev);
+
+ return 0;
+
+err_irq0:
+ free_irq(priv->irq0, dev);
+err_fini_dma:
+ bcmgenet_fini_dma(priv);
+err_clk_disable:
+ if (!IS_ERR(priv->clk))
+ clk_disable_unprepare(priv->clk);
+ return ret;
+}
+
+static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv)
+{
+ int ret = 0;
+ int timeout = 0;
+ u32 reg;
+
+ /* Disable TDMA to stop add more frames in TX DMA */
+ reg = bcmgenet_tdma_readl(priv, DMA_CTRL);
+ reg &= ~DMA_EN;
+ bcmgenet_tdma_writel(priv, reg, DMA_CTRL);
+
+ /* Check TDMA status register to confirm TDMA is disabled */
+ while (timeout++ < DMA_TIMEOUT_VAL) {
+ reg = bcmgenet_tdma_readl(priv, DMA_STATUS);
+ if (reg & DMA_DISABLED)
+ break;
+
+ udelay(1);
+ }
+
+ if (timeout == DMA_TIMEOUT_VAL) {
+ netdev_warn(priv->dev,
+ "Timed out while disabling TX DMA\n");
+ ret = -ETIMEDOUT;
+ }
+
+ /* Wait 10ms for packet drain in both tx and rx dma */
+ usleep_range(10000, 20000);
+
+ /* Disable RDMA */
+ reg = bcmgenet_rdma_readl(priv, DMA_CTRL);
+ reg &= ~DMA_EN;
+ bcmgenet_rdma_writel(priv, reg, DMA_CTRL);
+
+ timeout = 0;
+ /* Check RDMA status register to confirm RDMA is disabled */
+ while (timeout++ < DMA_TIMEOUT_VAL) {
+ reg = bcmgenet_rdma_readl(priv, DMA_STATUS);
+ if (reg & DMA_DISABLED)
+ break;
+
+ udelay(1);
+ }
+
+ if (timeout == DMA_TIMEOUT_VAL) {
+ netdev_warn(priv->dev,
+ "Timed out while disabling RX DMA\n");
+ ret = -ETIMEDOUT;
+ }
+
+ return ret;
+}
+
+static int bcmgenet_close(struct net_device *dev)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ int ret;
+ u32 reg;
+
+ netif_dbg(priv, ifdown, dev, "bcmgenet_close\n");
+
+ phy_stop(priv->phydev);
+
+ /* Disable MAC receive */
+ reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+ reg &= ~CMD_RX_EN;
+ bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+
+ netif_tx_stop_all_queues(dev);
+
+ ret = bcmgenet_dma_teardown(priv);
+ if (ret)
+ return ret;
+
+ /* Disable MAC transmit. TX DMA disabled have to done before this */
+ reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+ reg &= ~CMD_TX_EN;
+ bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+
+ napi_disable(&priv->napi);
+
+ /* tx reclaim */
+ bcmgenet_tx_reclaim_all(dev);
+ bcmgenet_fini_dma(priv);
+
+ free_irq(priv->irq0, priv);
+ free_irq(priv->irq1, priv);
+
+ /* Wait for pending work items to complete - we are stopping
+ * the clock now. Since interrupts are disabled, no new work
+ * will be scheduled.
+ */
+ cancel_work_sync(&priv->bcmgenet_irq_work);
+
+ if (phy_is_internal(priv->phydev))
+ bcmgenet_power_down(priv, GENET_POWER_PASSIVE);
+
+ if (priv->wol_enabled)
+ clk_enable(priv->clk_wol);
+
+ if (!IS_ERR(priv->clk))
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+static void bcmgenet_timeout(struct net_device *dev)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+
+ netif_dbg(priv, tx_err, dev, "bcmgenet_timeout\n");
+
+ dev->trans_start = jiffies;
+
+ dev->stats.tx_errors++;
+
+ netif_tx_wake_all_queues(dev);
+}
+
+#define MAX_MC_COUNT 16
+
+static inline void bcmgenet_set_mdf_addr(struct bcmgenet_priv *priv,
+ unsigned char *addr,
+ int *i,
+ int *mc)
+{
+ u32 reg;
+
+ bcmgenet_umac_writel(priv,
+ addr[0] << 8 | addr[1], UMAC_MDF_ADDR + (*i * 4));
+ bcmgenet_umac_writel(priv,
+ addr[2] << 24 | addr[3] << 16 |
+ addr[4] << 8 | addr[5],
+ UMAC_MDF_ADDR + ((*i + 1) * 4));
+ reg = bcmgenet_umac_readl(priv, UMAC_MDF_CTRL);
+ reg |= (1 << (MAX_MC_COUNT - *mc));
+ bcmgenet_umac_writel(priv, reg, UMAC_MDF_CTRL);
+ *i += 2;
+ (*mc)++;
+}
+
+static void bcmgenet_set_rx_mode(struct net_device *dev)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ struct netdev_hw_addr *ha;
+ int i, mc;
+ u32 reg;
+
+ netif_dbg(priv, hw, dev, "%s: %08X\n", __func__, dev->flags);
+
+ /* Promiscous mode */
+ reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+ if (dev->flags & IFF_PROMISC) {
+ reg |= CMD_PROMISC;
+ bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+ bcmgenet_umac_writel(priv, 0, UMAC_MDF_CTRL);
+ return;
+ } else {
+ reg &= ~CMD_PROMISC;
+ bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+ }
+
+ /* UniMac doesn't support ALLMULTI */
+ if (dev->flags & IFF_ALLMULTI) {
+ netdev_warn(dev, "ALLMULTI is not supported\n");
+ return;
+ }
+
+ /* update MDF filter */
+ i = 0;
+ mc = 0;
+ /* Broadcast */
+ bcmgenet_set_mdf_addr(priv, dev->broadcast, &i, &mc);
+ /* my own address.*/
+ bcmgenet_set_mdf_addr(priv, dev->dev_addr, &i, &mc);
+ /* Unicast list*/
+ if (netdev_uc_count(dev) > (MAX_MC_COUNT - mc))
+ return;
+
+ if (!netdev_uc_empty(dev))
+ netdev_for_each_uc_addr(ha, dev)
+ bcmgenet_set_mdf_addr(priv, ha->addr, &i, &mc);
+ /* Multicast */
+ if (netdev_mc_empty(dev) || netdev_mc_count(dev) >= (MAX_MC_COUNT - mc))
+ return;
+
+ netdev_for_each_mc_addr(ha, dev)
+ bcmgenet_set_mdf_addr(priv, ha->addr, &i, &mc);
+}
+
+/* Set the hardware MAC address. */
+static int bcmgenet_set_mac_addr(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+
+ /* Setting the MAC address at the hardware level is not possible
+ * without disabling the UniMAC RX/TX enable bits.
+ */
+ if (netif_running(dev))
+ return -EBUSY;
+
+ ether_addr_copy(dev->dev_addr, addr->sa_data);
+
+ return 0;
+}
+
+static const struct net_device_ops bcmgenet_netdev_ops = {
+ .ndo_open = bcmgenet_open,
+ .ndo_stop = bcmgenet_close,
+ .ndo_start_xmit = bcmgenet_xmit,
+ .ndo_tx_timeout = bcmgenet_timeout,
+ .ndo_set_rx_mode = bcmgenet_set_rx_mode,
+ .ndo_set_mac_address = bcmgenet_set_mac_addr,
+ .ndo_do_ioctl = bcmgenet_ioctl,
+ .ndo_set_features = bcmgenet_set_features,
+};
+
+/* Array of GENET hardware parameters/characteristics */
+static struct bcmgenet_hw_params bcmgenet_hw_params[] = {
+ [GENET_V1] = {
+ .tx_queues = 0,
+ .rx_queues = 0,
+ .bds_cnt = 0,
+ .bp_in_en_shift = 16,
+ .bp_in_mask = 0xffff,
+ .hfb_filter_cnt = 16,
+ .qtag_mask = 0x1F,
+ .hfb_offset = 0x1000,
+ .rdma_offset = 0x2000,
+ .tdma_offset = 0x3000,
+ .words_per_bd = 2,
+ },
+ [GENET_V2] = {
+ .tx_queues = 4,
+ .rx_queues = 4,
+ .bds_cnt = 32,
+ .bp_in_en_shift = 16,
+ .bp_in_mask = 0xffff,
+ .hfb_filter_cnt = 16,
+ .qtag_mask = 0x1F,
+ .tbuf_offset = 0x0600,
+ .hfb_offset = 0x1000,
+ .hfb_reg_offset = 0x2000,
+ .rdma_offset = 0x3000,
+ .tdma_offset = 0x4000,
+ .words_per_bd = 2,
+ .flags = GENET_HAS_EXT,
+ },
+ [GENET_V3] = {
+ .tx_queues = 4,
+ .rx_queues = 4,
+ .bds_cnt = 32,
+ .bp_in_en_shift = 17,
+ .bp_in_mask = 0x1ffff,
+ .hfb_filter_cnt = 48,
+ .qtag_mask = 0x3F,
+ .tbuf_offset = 0x0600,
+ .hfb_offset = 0x8000,
+ .hfb_reg_offset = 0xfc00,
+ .rdma_offset = 0x10000,
+ .tdma_offset = 0x11000,
+ .words_per_bd = 2,
+ .flags = GENET_HAS_EXT | GENET_HAS_MDIO_INTR,
+ },
+ [GENET_V4] = {
+ .tx_queues = 4,
+ .rx_queues = 4,
+ .bds_cnt = 32,
+ .bp_in_en_shift = 17,
+ .bp_in_mask = 0x1ffff,
+ .hfb_filter_cnt = 48,
+ .qtag_mask = 0x3F,
+ .tbuf_offset = 0x0600,
+ .hfb_offset = 0x8000,
+ .hfb_reg_offset = 0xfc00,
+ .rdma_offset = 0x2000,
+ .tdma_offset = 0x4000,
+ .words_per_bd = 3,
+ .flags = GENET_HAS_40BITS | GENET_HAS_EXT | GENET_HAS_MDIO_INTR,
+ },
+};
+
+/* Infer hardware parameters from the detected GENET version */
+static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv)
+{
+ struct bcmgenet_hw_params *params;
+ u32 reg;
+ u8 major;
+
+ if (GENET_IS_V4(priv)) {
+ bcmgenet_dma_regs = bcmgenet_dma_regs_v3plus;
+ genet_dma_ring_regs = genet_dma_ring_regs_v4;
+ priv->dma_rx_chk_bit = DMA_RX_CHK_V3PLUS;
+ priv->version = GENET_V4;
+ } else if (GENET_IS_V3(priv)) {
+ bcmgenet_dma_regs = bcmgenet_dma_regs_v3plus;
+ genet_dma_ring_regs = genet_dma_ring_regs_v123;
+ priv->dma_rx_chk_bit = DMA_RX_CHK_V3PLUS;
+ priv->version = GENET_V3;
+ } else if (GENET_IS_V2(priv)) {
+ bcmgenet_dma_regs = bcmgenet_dma_regs_v2;
+ genet_dma_ring_regs = genet_dma_ring_regs_v123;
+ priv->dma_rx_chk_bit = DMA_RX_CHK_V12;
+ priv->version = GENET_V2;
+ } else if (GENET_IS_V1(priv)) {
+ bcmgenet_dma_regs = bcmgenet_dma_regs_v1;
+ genet_dma_ring_regs = genet_dma_ring_regs_v123;
+ priv->dma_rx_chk_bit = DMA_RX_CHK_V12;
+ priv->version = GENET_V1;
+ }
+
+ /* enum genet_version starts at 1 */
+ priv->hw_params = &bcmgenet_hw_params[priv->version];
+ params = priv->hw_params;
+
+ /* Read GENET HW version */
+ reg = bcmgenet_sys_readl(priv, SYS_REV_CTRL);
+ major = (reg >> 24 & 0x0f);
+ if (major == 5)
+ major = 4;
+ else if (major == 0)
+ major = 1;
+ if (major != priv->version) {
+ dev_err(&priv->pdev->dev,
+ "GENET version mismatch, got: %d, configured for: %d\n",
+ major, priv->version);
+ }
+
+ /* Print the GENET core version */
+ dev_info(&priv->pdev->dev, "GENET " GENET_VER_FMT,
+ major, (reg >> 16) & 0x0f, reg & 0xffff);
+
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+ if (!(params->flags & GENET_HAS_40BITS))
+ pr_warn("GENET does not support 40-bits PA\n");
+#endif
+
+ pr_debug("Configuration for version: %d\n"
+ "TXq: %1d, RXq: %1d, BDs: %1d\n"
+ "BP << en: %2d, BP msk: 0x%05x\n"
+ "HFB count: %2d, QTAQ msk: 0x%05x\n"
+ "TBUF: 0x%04x, HFB: 0x%04x, HFBreg: 0x%04x\n"
+ "RDMA: 0x%05x, TDMA: 0x%05x\n"
+ "Words/BD: %d\n",
+ priv->version,
+ params->tx_queues, params->rx_queues, params->bds_cnt,
+ params->bp_in_en_shift, params->bp_in_mask,
+ params->hfb_filter_cnt, params->qtag_mask,
+ params->tbuf_offset, params->hfb_offset,
+ params->hfb_reg_offset,
+ params->rdma_offset, params->tdma_offset,
+ params->words_per_bd);
+}
+
+static const struct of_device_id bcmgenet_match[] = {
+ { .compatible = "brcm,genet-v1", .data = (void *)GENET_V1 },
+ { .compatible = "brcm,genet-v2", .data = (void *)GENET_V2 },
+ { .compatible = "brcm,genet-v3", .data = (void *)GENET_V3 },
+ { .compatible = "brcm,genet-v4", .data = (void *)GENET_V4 },
+ { },
+};
+
+static int bcmgenet_probe(struct platform_device *pdev)
+{
+ struct device_node *dn = pdev->dev.of_node;
+ const struct of_device_id *of_id;
+ struct bcmgenet_priv *priv;
+ struct net_device *dev;
+ const void *macaddr;
+ struct resource *r;
+ int err = -EIO;
+
+ /* Up to GENET_MAX_MQ_CNT + 1 TX queues and a single RX queue */
+ dev = alloc_etherdev_mqs(sizeof(*priv), GENET_MAX_MQ_CNT + 1, 1);
+ if (!dev) {
+ dev_err(&pdev->dev, "can't allocate net device\n");
+ return -ENOMEM;
+ }
+
+ of_id = of_match_node(bcmgenet_match, dn);
+ if (!of_id)
+ return -EINVAL;
+
+ priv = netdev_priv(dev);
+ priv->irq0 = platform_get_irq(pdev, 0);
+ priv->irq1 = platform_get_irq(pdev, 1);
+ if (!priv->irq0 || !priv->irq1) {
+ dev_err(&pdev->dev, "can't find IRQs\n");
+ err = -EINVAL;
+ goto err;
+ }
+
+ macaddr = of_get_mac_address(dn);
+ if (!macaddr) {
+ dev_err(&pdev->dev, "can't find MAC address\n");
+ err = -EINVAL;
+ goto err;
+ }
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(priv->base)) {
+ err = PTR_ERR(priv->base);
+ goto err;
+ }
+
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ dev_set_drvdata(&pdev->dev, dev);
+ ether_addr_copy(dev->dev_addr, macaddr);
+ dev->watchdog_timeo = 2 * HZ;
+ SET_ETHTOOL_OPS(dev, &bcmgenet_ethtool_ops);
+ dev->netdev_ops = &bcmgenet_netdev_ops;
+ netif_napi_add(dev, &priv->napi, bcmgenet_poll, 64);
+
+ priv->msg_enable = netif_msg_init(-1, GENET_MSG_DEFAULT);
+
+ /* Set hardware features */
+ dev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM;
+
+ /* Set the needed headroom to account for any possible
+ * features enabling/disabling at runtime
+ */
+ dev->needed_headroom += 64;
+
+ netdev_boot_setup_check(dev);
+
+ priv->dev = dev;
+ priv->pdev = pdev;
+ priv->version = (enum bcmgenet_version)of_id->data;
+
+ bcmgenet_set_hw_params(priv);
+
+ /* Mii wait queue */
+ init_waitqueue_head(&priv->wq);
+ /* Always use RX_BUF_LENGTH (2KB) buffer for all chips */
+ priv->rx_buf_len = RX_BUF_LENGTH;
+ INIT_WORK(&priv->bcmgenet_irq_work, bcmgenet_irq_task);
+
+ priv->clk = devm_clk_get(&priv->pdev->dev, "enet");
+ if (IS_ERR(priv->clk))
+ dev_warn(&priv->pdev->dev, "failed to get enet clock\n");
+
+ priv->clk_wol = devm_clk_get(&priv->pdev->dev, "enet-wol");
+ if (IS_ERR(priv->clk_wol))
+ dev_warn(&priv->pdev->dev, "failed to get enet-wol clock\n");
+
+ if (!IS_ERR(priv->clk))
+ clk_prepare_enable(priv->clk);
+
+ err = reset_umac(priv);
+ if (err)
+ goto err_clk_disable;
+
+ err = bcmgenet_mii_init(dev);
+ if (err)
+ goto err_clk_disable;
+
+ /* setup number of real queues + 1 (GENET_V1 has 0 hardware queues
+ * just the ring 16 descriptor based TX
+ */
+ netif_set_real_num_tx_queues(priv->dev, priv->hw_params->tx_queues + 1);
+ netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1);
+
+ err = register_netdev(dev);
+ if (err)
+ goto err_clk_disable;
+
+ /* Turn off the main clock, WOL clock is handled separately */
+ if (!IS_ERR(priv->clk))
+ clk_disable_unprepare(priv->clk);
+
+ return err;
+
+err_clk_disable:
+ if (!IS_ERR(priv->clk))
+ clk_disable_unprepare(priv->clk);
+err:
+ free_netdev(dev);
+ return err;
+}
+
+static int bcmgenet_remove(struct platform_device *pdev)
+{
+ struct bcmgenet_priv *priv = dev_to_priv(&pdev->dev);
+
+ dev_set_drvdata(&pdev->dev, NULL);
+ unregister_netdev(priv->dev);
+ bcmgenet_mii_exit(priv->dev);
+ free_netdev(priv->dev);
+
+ return 0;
+}
+
+
+static struct platform_driver bcmgenet_driver = {
+ .probe = bcmgenet_probe,
+ .remove = bcmgenet_remove,
+ .driver = {
+ .name = "bcmgenet",
+ .owner = THIS_MODULE,
+ .of_match_table = bcmgenet_match,
+ },
+};
+module_platform_driver(bcmgenet_driver);
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Broadcom GENET Ethernet controller driver");
+MODULE_ALIAS("platform:bcmgenet");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
new file mode 100644
index 000000000000..0f117105fed1
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -0,0 +1,628 @@
+/*
+ * Copyright (c) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+*/
+#ifndef __BCMGENET_H__
+#define __BCMGENET_H__
+
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
+#include <linux/phy.h>
+
+/* total number of Buffer Descriptors, same for Rx/Tx */
+#define TOTAL_DESC 256
+
+/* which ring is descriptor based */
+#define DESC_INDEX 16
+
+/* Body(1500) + EH_SIZE(14) + VLANTAG(4) + BRCMTAG(6) + FCS(4) = 1528.
+ * 1536 is multiple of 256 bytes
+ */
+#define ENET_BRCM_TAG_LEN 6
+#define ENET_PAD 8
+#define ENET_MAX_MTU_SIZE (ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN + \
+ ENET_BRCM_TAG_LEN + ETH_FCS_LEN + ENET_PAD)
+#define DMA_MAX_BURST_LENGTH 0x10
+
+/* misc. configuration */
+#define CLEAR_ALL_HFB 0xFF
+#define DMA_FC_THRESH_HI (TOTAL_DESC >> 4)
+#define DMA_FC_THRESH_LO 5
+
+/* 64B receive/transmit status block */
+struct status_64 {
+ u32 length_status; /* length and peripheral status */
+ u32 ext_status; /* Extended status*/
+ u32 rx_csum; /* partial rx checksum */
+ u32 unused1[9]; /* unused */
+ u32 tx_csum_info; /* Tx checksum info. */
+ u32 unused2[3]; /* unused */
+};
+
+/* Rx status bits */
+#define STATUS_RX_EXT_MASK 0x1FFFFF
+#define STATUS_RX_CSUM_MASK 0xFFFF
+#define STATUS_RX_CSUM_OK 0x10000
+#define STATUS_RX_CSUM_FR 0x20000
+#define STATUS_RX_PROTO_TCP 0
+#define STATUS_RX_PROTO_UDP 1
+#define STATUS_RX_PROTO_ICMP 2
+#define STATUS_RX_PROTO_OTHER 3
+#define STATUS_RX_PROTO_MASK 3
+#define STATUS_RX_PROTO_SHIFT 18
+#define STATUS_FILTER_INDEX_MASK 0xFFFF
+/* Tx status bits */
+#define STATUS_TX_CSUM_START_MASK 0X7FFF
+#define STATUS_TX_CSUM_START_SHIFT 16
+#define STATUS_TX_CSUM_PROTO_UDP 0x8000
+#define STATUS_TX_CSUM_OFFSET_MASK 0x7FFF
+#define STATUS_TX_CSUM_LV 0x80000000
+
+/* DMA Descriptor */
+#define DMA_DESC_LENGTH_STATUS 0x00 /* in bytes of data in buffer */
+#define DMA_DESC_ADDRESS_LO 0x04 /* lower bits of PA */
+#define DMA_DESC_ADDRESS_HI 0x08 /* upper 32 bits of PA, GENETv4+ */
+
+/* Rx/Tx common counter group */
+struct bcmgenet_pkt_counters {
+ u32 cnt_64; /* RO Received/Transmited 64 bytes packet */
+ u32 cnt_127; /* RO Rx/Tx 127 bytes packet */
+ u32 cnt_255; /* RO Rx/Tx 65-255 bytes packet */
+ u32 cnt_511; /* RO Rx/Tx 256-511 bytes packet */
+ u32 cnt_1023; /* RO Rx/Tx 512-1023 bytes packet */
+ u32 cnt_1518; /* RO Rx/Tx 1024-1518 bytes packet */
+ u32 cnt_mgv; /* RO Rx/Tx 1519-1522 good VLAN packet */
+ u32 cnt_2047; /* RO Rx/Tx 1522-2047 bytes packet*/
+ u32 cnt_4095; /* RO Rx/Tx 2048-4095 bytes packet*/
+ u32 cnt_9216; /* RO Rx/Tx 4096-9216 bytes packet*/
+};
+
+/* RSV, Receive Status Vector */
+struct bcmgenet_rx_counters {
+ struct bcmgenet_pkt_counters pkt_cnt;
+ u32 pkt; /* RO (0x428) Received pkt count*/
+ u32 bytes; /* RO Received byte count */
+ u32 mca; /* RO # of Received multicast pkt */
+ u32 bca; /* RO # of Receive broadcast pkt */
+ u32 fcs; /* RO # of Received FCS error */
+ u32 cf; /* RO # of Received control frame pkt*/
+ u32 pf; /* RO # of Received pause frame pkt */
+ u32 uo; /* RO # of unknown op code pkt */
+ u32 aln; /* RO # of alignment error count */
+ u32 flr; /* RO # of frame length out of range count */
+ u32 cde; /* RO # of code error pkt */
+ u32 fcr; /* RO # of carrier sense error pkt */
+ u32 ovr; /* RO # of oversize pkt*/
+ u32 jbr; /* RO # of jabber count */
+ u32 mtue; /* RO # of MTU error pkt*/
+ u32 pok; /* RO # of Received good pkt */
+ u32 uc; /* RO # of unicast pkt */
+ u32 ppp; /* RO # of PPP pkt */
+ u32 rcrc; /* RO (0x470),# of CRC match pkt */
+};
+
+/* TSV, Transmit Status Vector */
+struct bcmgenet_tx_counters {
+ struct bcmgenet_pkt_counters pkt_cnt;
+ u32 pkts; /* RO (0x4a8) Transmited pkt */
+ u32 mca; /* RO # of xmited multicast pkt */
+ u32 bca; /* RO # of xmited broadcast pkt */
+ u32 pf; /* RO # of xmited pause frame count */
+ u32 cf; /* RO # of xmited control frame count */
+ u32 fcs; /* RO # of xmited FCS error count */
+ u32 ovr; /* RO # of xmited oversize pkt */
+ u32 drf; /* RO # of xmited deferral pkt */
+ u32 edf; /* RO # of xmited Excessive deferral pkt*/
+ u32 scl; /* RO # of xmited single collision pkt */
+ u32 mcl; /* RO # of xmited multiple collision pkt*/
+ u32 lcl; /* RO # of xmited late collision pkt */
+ u32 ecl; /* RO # of xmited excessive collision pkt*/
+ u32 frg; /* RO # of xmited fragments pkt*/
+ u32 ncl; /* RO # of xmited total collision count */
+ u32 jbr; /* RO # of xmited jabber count*/
+ u32 bytes; /* RO # of xmited byte count */
+ u32 pok; /* RO # of xmited good pkt */
+ u32 uc; /* RO (0x0x4f0)# of xmited unitcast pkt */
+};
+
+struct bcmgenet_mib_counters {
+ struct bcmgenet_rx_counters rx;
+ struct bcmgenet_tx_counters tx;
+ u32 rx_runt_cnt;
+ u32 rx_runt_fcs;
+ u32 rx_runt_fcs_align;
+ u32 rx_runt_bytes;
+ u32 rbuf_ovflow_cnt;
+ u32 rbuf_err_cnt;
+ u32 mdf_err_cnt;
+};
+
+#define UMAC_HD_BKP_CTRL 0x004
+#define HD_FC_EN (1 << 0)
+#define HD_FC_BKOFF_OK (1 << 1)
+#define IPG_CONFIG_RX_SHIFT 2
+#define IPG_CONFIG_RX_MASK 0x1F
+
+#define UMAC_CMD 0x008
+#define CMD_TX_EN (1 << 0)
+#define CMD_RX_EN (1 << 1)
+#define UMAC_SPEED_10 0
+#define UMAC_SPEED_100 1
+#define UMAC_SPEED_1000 2
+#define UMAC_SPEED_2500 3
+#define CMD_SPEED_SHIFT 2
+#define CMD_SPEED_MASK 3
+#define CMD_PROMISC (1 << 4)
+#define CMD_PAD_EN (1 << 5)
+#define CMD_CRC_FWD (1 << 6)
+#define CMD_PAUSE_FWD (1 << 7)
+#define CMD_RX_PAUSE_IGNORE (1 << 8)
+#define CMD_TX_ADDR_INS (1 << 9)
+#define CMD_HD_EN (1 << 10)
+#define CMD_SW_RESET (1 << 13)
+#define CMD_LCL_LOOP_EN (1 << 15)
+#define CMD_AUTO_CONFIG (1 << 22)
+#define CMD_CNTL_FRM_EN (1 << 23)
+#define CMD_NO_LEN_CHK (1 << 24)
+#define CMD_RMT_LOOP_EN (1 << 25)
+#define CMD_PRBL_EN (1 << 27)
+#define CMD_TX_PAUSE_IGNORE (1 << 28)
+#define CMD_TX_RX_EN (1 << 29)
+#define CMD_RUNT_FILTER_DIS (1 << 30)
+
+#define UMAC_MAC0 0x00C
+#define UMAC_MAC1 0x010
+#define UMAC_MAX_FRAME_LEN 0x014
+
+#define UMAC_TX_FLUSH 0x334
+
+#define UMAC_MIB_START 0x400
+
+#define UMAC_MDIO_CMD 0x614
+#define MDIO_START_BUSY (1 << 29)
+#define MDIO_READ_FAIL (1 << 28)
+#define MDIO_RD (2 << 26)
+#define MDIO_WR (1 << 26)
+#define MDIO_PMD_SHIFT 21
+#define MDIO_PMD_MASK 0x1F
+#define MDIO_REG_SHIFT 16
+#define MDIO_REG_MASK 0x1F
+
+#define UMAC_RBUF_OVFL_CNT 0x61C
+
+#define UMAC_MPD_CTRL 0x620
+#define MPD_EN (1 << 0)
+#define MPD_PW_EN (1 << 27)
+#define MPD_MSEQ_LEN_SHIFT 16
+#define MPD_MSEQ_LEN_MASK 0xFF
+
+#define UMAC_MPD_PW_MS 0x624
+#define UMAC_MPD_PW_LS 0x628
+#define UMAC_RBUF_ERR_CNT 0x634
+#define UMAC_MDF_ERR_CNT 0x638
+#define UMAC_MDF_CTRL 0x650
+#define UMAC_MDF_ADDR 0x654
+#define UMAC_MIB_CTRL 0x580
+#define MIB_RESET_RX (1 << 0)
+#define MIB_RESET_RUNT (1 << 1)
+#define MIB_RESET_TX (1 << 2)
+
+#define RBUF_CTRL 0x00
+#define RBUF_64B_EN (1 << 0)
+#define RBUF_ALIGN_2B (1 << 1)
+#define RBUF_BAD_DIS (1 << 2)
+
+#define RBUF_STATUS 0x0C
+#define RBUF_STATUS_WOL (1 << 0)
+#define RBUF_STATUS_MPD_INTR_ACTIVE (1 << 1)
+#define RBUF_STATUS_ACPI_INTR_ACTIVE (1 << 2)
+
+#define RBUF_CHK_CTRL 0x14
+#define RBUF_RXCHK_EN (1 << 0)
+#define RBUF_SKIP_FCS (1 << 4)
+
+#define RBUF_TBUF_SIZE_CTRL 0xb4
+
+#define RBUF_HFB_CTRL_V1 0x38
+#define RBUF_HFB_FILTER_EN_SHIFT 16
+#define RBUF_HFB_FILTER_EN_MASK 0xffff0000
+#define RBUF_HFB_EN (1 << 0)
+#define RBUF_HFB_256B (1 << 1)
+#define RBUF_ACPI_EN (1 << 2)
+
+#define RBUF_HFB_LEN_V1 0x3C
+#define RBUF_FLTR_LEN_MASK 0xFF
+#define RBUF_FLTR_LEN_SHIFT 8
+
+#define TBUF_CTRL 0x00
+#define TBUF_BP_MC 0x0C
+
+#define TBUF_CTRL_V1 0x80
+#define TBUF_BP_MC_V1 0xA0
+
+#define HFB_CTRL 0x00
+#define HFB_FLT_ENABLE_V3PLUS 0x04
+#define HFB_FLT_LEN_V2 0x04
+#define HFB_FLT_LEN_V3PLUS 0x1C
+
+/* uniMac intrl2 registers */
+#define INTRL2_CPU_STAT 0x00
+#define INTRL2_CPU_SET 0x04
+#define INTRL2_CPU_CLEAR 0x08
+#define INTRL2_CPU_MASK_STATUS 0x0C
+#define INTRL2_CPU_MASK_SET 0x10
+#define INTRL2_CPU_MASK_CLEAR 0x14
+
+/* INTRL2 instance 0 definitions */
+#define UMAC_IRQ_SCB (1 << 0)
+#define UMAC_IRQ_EPHY (1 << 1)
+#define UMAC_IRQ_PHY_DET_R (1 << 2)
+#define UMAC_IRQ_PHY_DET_F (1 << 3)
+#define UMAC_IRQ_LINK_UP (1 << 4)
+#define UMAC_IRQ_LINK_DOWN (1 << 5)
+#define UMAC_IRQ_UMAC (1 << 6)
+#define UMAC_IRQ_UMAC_TSV (1 << 7)
+#define UMAC_IRQ_TBUF_UNDERRUN (1 << 8)
+#define UMAC_IRQ_RBUF_OVERFLOW (1 << 9)
+#define UMAC_IRQ_HFB_SM (1 << 10)
+#define UMAC_IRQ_HFB_MM (1 << 11)
+#define UMAC_IRQ_MPD_R (1 << 12)
+#define UMAC_IRQ_RXDMA_MBDONE (1 << 13)
+#define UMAC_IRQ_RXDMA_PDONE (1 << 14)
+#define UMAC_IRQ_RXDMA_BDONE (1 << 15)
+#define UMAC_IRQ_TXDMA_MBDONE (1 << 16)
+#define UMAC_IRQ_TXDMA_PDONE (1 << 17)
+#define UMAC_IRQ_TXDMA_BDONE (1 << 18)
+/* Only valid for GENETv3+ */
+#define UMAC_IRQ_MDIO_DONE (1 << 23)
+#define UMAC_IRQ_MDIO_ERROR (1 << 24)
+
+/* Register block offsets */
+#define GENET_SYS_OFF 0x0000
+#define GENET_GR_BRIDGE_OFF 0x0040
+#define GENET_EXT_OFF 0x0080
+#define GENET_INTRL2_0_OFF 0x0200
+#define GENET_INTRL2_1_OFF 0x0240
+#define GENET_RBUF_OFF 0x0300
+#define GENET_UMAC_OFF 0x0800
+
+/* SYS block offsets and register definitions */
+#define SYS_REV_CTRL 0x00
+#define SYS_PORT_CTRL 0x04
+#define PORT_MODE_INT_EPHY 0
+#define PORT_MODE_INT_GPHY 1
+#define PORT_MODE_EXT_EPHY 2
+#define PORT_MODE_EXT_GPHY 3
+#define PORT_MODE_EXT_RVMII_25 (4 | BIT(4))
+#define PORT_MODE_EXT_RVMII_50 4
+#define LED_ACT_SOURCE_MAC (1 << 9)
+
+#define SYS_RBUF_FLUSH_CTRL 0x08
+#define SYS_TBUF_FLUSH_CTRL 0x0C
+#define RBUF_FLUSH_CTRL_V1 0x04
+
+/* Ext block register offsets and definitions */
+#define EXT_EXT_PWR_MGMT 0x00
+#define EXT_PWR_DOWN_BIAS (1 << 0)
+#define EXT_PWR_DOWN_DLL (1 << 1)
+#define EXT_PWR_DOWN_PHY (1 << 2)
+#define EXT_PWR_DN_EN_LD (1 << 3)
+#define EXT_ENERGY_DET (1 << 4)
+#define EXT_IDDQ_FROM_PHY (1 << 5)
+#define EXT_PHY_RESET (1 << 8)
+#define EXT_ENERGY_DET_MASK (1 << 12)
+
+#define EXT_RGMII_OOB_CTRL 0x0C
+#define RGMII_MODE_EN (1 << 0)
+#define RGMII_LINK (1 << 4)
+#define OOB_DISABLE (1 << 5)
+#define ID_MODE_DIS (1 << 16)
+
+#define EXT_GPHY_CTRL 0x1C
+#define EXT_CFG_IDDQ_BIAS (1 << 0)
+#define EXT_CFG_PWR_DOWN (1 << 1)
+#define EXT_GPHY_RESET (1 << 5)
+
+/* DMA rings size */
+#define DMA_RING_SIZE (0x40)
+#define DMA_RINGS_SIZE (DMA_RING_SIZE * (DESC_INDEX + 1))
+
+/* DMA registers common definitions */
+#define DMA_RW_POINTER_MASK 0x1FF
+#define DMA_P_INDEX_DISCARD_CNT_MASK 0xFFFF
+#define DMA_P_INDEX_DISCARD_CNT_SHIFT 16
+#define DMA_BUFFER_DONE_CNT_MASK 0xFFFF
+#define DMA_BUFFER_DONE_CNT_SHIFT 16
+#define DMA_P_INDEX_MASK 0xFFFF
+#define DMA_C_INDEX_MASK 0xFFFF
+
+/* DMA ring size register */
+#define DMA_RING_SIZE_MASK 0xFFFF
+#define DMA_RING_SIZE_SHIFT 16
+#define DMA_RING_BUFFER_SIZE_MASK 0xFFFF
+
+/* DMA interrupt threshold register */
+#define DMA_INTR_THRESHOLD_MASK 0x00FF
+
+/* DMA XON/XOFF register */
+#define DMA_XON_THREHOLD_MASK 0xFFFF
+#define DMA_XOFF_THRESHOLD_MASK 0xFFFF
+#define DMA_XOFF_THRESHOLD_SHIFT 16
+
+/* DMA flow period register */
+#define DMA_FLOW_PERIOD_MASK 0xFFFF
+#define DMA_MAX_PKT_SIZE_MASK 0xFFFF
+#define DMA_MAX_PKT_SIZE_SHIFT 16
+
+
+/* DMA control register */
+#define DMA_EN (1 << 0)
+#define DMA_RING_BUF_EN_SHIFT 0x01
+#define DMA_RING_BUF_EN_MASK 0xFFFF
+#define DMA_TSB_SWAP_EN (1 << 20)
+
+/* DMA status register */
+#define DMA_DISABLED (1 << 0)
+#define DMA_DESC_RAM_INIT_BUSY (1 << 1)
+
+/* DMA SCB burst size register */
+#define DMA_SCB_BURST_SIZE_MASK 0x1F
+
+/* DMA activity vector register */
+#define DMA_ACTIVITY_VECTOR_MASK 0x1FFFF
+
+/* DMA backpressure mask register */
+#define DMA_BACKPRESSURE_MASK 0x1FFFF
+#define DMA_PFC_ENABLE (1 << 31)
+
+/* DMA backpressure status register */
+#define DMA_BACKPRESSURE_STATUS_MASK 0x1FFFF
+
+/* DMA override register */
+#define DMA_LITTLE_ENDIAN_MODE (1 << 0)
+#define DMA_REGISTER_MODE (1 << 1)
+
+/* DMA timeout register */
+#define DMA_TIMEOUT_MASK 0xFFFF
+#define DMA_TIMEOUT_VAL 5000 /* micro seconds */
+
+/* TDMA rate limiting control register */
+#define DMA_RATE_LIMIT_EN_MASK 0xFFFF
+
+/* TDMA arbitration control register */
+#define DMA_ARBITER_MODE_MASK 0x03
+#define DMA_RING_BUF_PRIORITY_MASK 0x1F
+#define DMA_RING_BUF_PRIORITY_SHIFT 5
+#define DMA_RATE_ADJ_MASK 0xFF
+
+/* Tx/Rx Dma Descriptor common bits*/
+#define DMA_BUFLENGTH_MASK 0x0fff
+#define DMA_BUFLENGTH_SHIFT 16
+#define DMA_OWN 0x8000
+#define DMA_EOP 0x4000
+#define DMA_SOP 0x2000
+#define DMA_WRAP 0x1000
+/* Tx specific Dma descriptor bits */
+#define DMA_TX_UNDERRUN 0x0200
+#define DMA_TX_APPEND_CRC 0x0040
+#define DMA_TX_OW_CRC 0x0020
+#define DMA_TX_DO_CSUM 0x0010
+#define DMA_TX_QTAG_SHIFT 7
+
+/* Rx Specific Dma descriptor bits */
+#define DMA_RX_CHK_V3PLUS 0x8000
+#define DMA_RX_CHK_V12 0x1000
+#define DMA_RX_BRDCAST 0x0040
+#define DMA_RX_MULT 0x0020
+#define DMA_RX_LG 0x0010
+#define DMA_RX_NO 0x0008
+#define DMA_RX_RXER 0x0004
+#define DMA_RX_CRC_ERROR 0x0002
+#define DMA_RX_OV 0x0001
+#define DMA_RX_FI_MASK 0x001F
+#define DMA_RX_FI_SHIFT 0x0007
+#define DMA_DESC_ALLOC_MASK 0x00FF
+
+#define DMA_ARBITER_RR 0x00
+#define DMA_ARBITER_WRR 0x01
+#define DMA_ARBITER_SP 0x02
+
+struct enet_cb {
+ struct sk_buff *skb;
+ void __iomem *bd_addr;
+ DEFINE_DMA_UNMAP_ADDR(dma_addr);
+ DEFINE_DMA_UNMAP_LEN(dma_len);
+};
+
+/* power management mode */
+enum bcmgenet_power_mode {
+ GENET_POWER_CABLE_SENSE = 0,
+ GENET_POWER_PASSIVE,
+};
+
+struct bcmgenet_priv;
+
+/* We support both runtime GENET detection and compile-time
+ * to optimize code-paths for a given hardware
+ */
+enum bcmgenet_version {
+ GENET_V1 = 1,
+ GENET_V2,
+ GENET_V3,
+ GENET_V4
+};
+
+#define GENET_IS_V1(p) ((p)->version == GENET_V1)
+#define GENET_IS_V2(p) ((p)->version == GENET_V2)
+#define GENET_IS_V3(p) ((p)->version == GENET_V3)
+#define GENET_IS_V4(p) ((p)->version == GENET_V4)
+
+/* Hardware flags */
+#define GENET_HAS_40BITS (1 << 0)
+#define GENET_HAS_EXT (1 << 1)
+#define GENET_HAS_MDIO_INTR (1 << 2)
+
+/* BCMGENET hardware parameters, keep this structure nicely aligned
+ * since it is going to be used in hot paths
+ */
+struct bcmgenet_hw_params {
+ u8 tx_queues;
+ u8 rx_queues;
+ u8 bds_cnt;
+ u8 bp_in_en_shift;
+ u32 bp_in_mask;
+ u8 hfb_filter_cnt;
+ u8 qtag_mask;
+ u16 tbuf_offset;
+ u32 hfb_offset;
+ u32 hfb_reg_offset;
+ u32 rdma_offset;
+ u32 tdma_offset;
+ u32 words_per_bd;
+ u32 flags;
+};
+
+struct bcmgenet_tx_ring {
+ spinlock_t lock; /* ring lock */
+ unsigned int index; /* ring index */
+ unsigned int queue; /* queue index */
+ struct enet_cb *cbs; /* tx ring buffer control block*/
+ unsigned int size; /* size of each tx ring */
+ unsigned int c_index; /* last consumer index of each ring*/
+ unsigned int free_bds; /* # of free bds for each ring */
+ unsigned int write_ptr; /* Tx ring write pointer SW copy */
+ unsigned int prod_index; /* Tx ring producer index SW copy */
+ unsigned int cb_ptr; /* Tx ring initial CB ptr */
+ unsigned int end_ptr; /* Tx ring end CB ptr */
+ void (*int_enable)(struct bcmgenet_priv *priv,
+ struct bcmgenet_tx_ring *);
+ void (*int_disable)(struct bcmgenet_priv *priv,
+ struct bcmgenet_tx_ring *);
+};
+
+/* device context */
+struct bcmgenet_priv {
+ void __iomem *base;
+ enum bcmgenet_version version;
+ struct net_device *dev;
+ u32 int0_mask;
+ u32 int1_mask;
+
+ /* NAPI for descriptor based rx */
+ struct napi_struct napi ____cacheline_aligned;
+
+ /* transmit variables */
+ void __iomem *tx_bds;
+ struct enet_cb *tx_cbs;
+ unsigned int num_tx_bds;
+
+ struct bcmgenet_tx_ring tx_rings[DESC_INDEX + 1];
+
+ /* receive variables */
+ void __iomem *rx_bds;
+ void __iomem *rx_bd_assign_ptr;
+ int rx_bd_assign_index;
+ struct enet_cb *rx_cbs;
+ unsigned int num_rx_bds;
+ unsigned int rx_buf_len;
+ unsigned int rx_read_ptr;
+ unsigned int rx_c_index;
+
+ /* other misc variables */
+ struct bcmgenet_hw_params *hw_params;
+
+ /* MDIO bus variables */
+ wait_queue_head_t wq;
+ struct phy_device *phydev;
+ struct device_node *phy_dn;
+ struct mii_bus *mii_bus;
+
+ /* PHY device variables */
+ int old_duplex;
+ int old_link;
+ int old_pause;
+ phy_interface_t phy_interface;
+ int phy_addr;
+ int ext_phy;
+
+ /* Interrupt variables */
+ struct work_struct bcmgenet_irq_work;
+ int irq0;
+ int irq1;
+ unsigned int irq0_stat;
+ unsigned int irq1_stat;
+
+ /* HW descriptors/checksum variables */
+ bool desc_64b_en;
+ bool desc_rxchk_en;
+ bool crc_fwd_en;
+
+ unsigned int dma_rx_chk_bit;
+
+ u32 msg_enable;
+
+ struct clk *clk;
+ struct platform_device *pdev;
+
+ /* WOL */
+ unsigned long wol_enabled;
+ struct clk *clk_wol;
+ u32 wolopts;
+
+ struct bcmgenet_mib_counters mib;
+};
+
+#define GENET_IO_MACRO(name, offset) \
+static inline u32 bcmgenet_##name##_readl(struct bcmgenet_priv *priv, \
+ u32 off) \
+{ \
+ return __raw_readl(priv->base + offset + off); \
+} \
+static inline void bcmgenet_##name##_writel(struct bcmgenet_priv *priv, \
+ u32 val, u32 off) \
+{ \
+ __raw_writel(val, priv->base + offset + off); \
+}
+
+GENET_IO_MACRO(ext, GENET_EXT_OFF);
+GENET_IO_MACRO(umac, GENET_UMAC_OFF);
+GENET_IO_MACRO(sys, GENET_SYS_OFF);
+
+/* interrupt l2 registers accessors */
+GENET_IO_MACRO(intrl2_0, GENET_INTRL2_0_OFF);
+GENET_IO_MACRO(intrl2_1, GENET_INTRL2_1_OFF);
+
+/* HFB register accessors */
+GENET_IO_MACRO(hfb, priv->hw_params->hfb_offset);
+
+/* GENET v2+ HFB control and filter len helpers */
+GENET_IO_MACRO(hfb_reg, priv->hw_params->hfb_reg_offset);
+
+/* RBUF register accessors */
+GENET_IO_MACRO(rbuf, GENET_RBUF_OFF);
+
+/* MDIO routines */
+int bcmgenet_mii_init(struct net_device *dev);
+int bcmgenet_mii_config(struct net_device *dev);
+void bcmgenet_mii_exit(struct net_device *dev);
+void bcmgenet_mii_reset(struct net_device *dev);
+
+#endif /* __BCMGENET_H__ */
diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c
new file mode 100644
index 000000000000..4608673beaff
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -0,0 +1,464 @@
+/*
+ * Broadcom GENET MDIO routines
+ *
+ * Copyright (c) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/bitops.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
+#include <linux/brcmphy.h>
+#include <linux/of.h>
+#include <linux/of_net.h>
+#include <linux/of_mdio.h>
+
+#include "bcmgenet.h"
+
+/* read a value from the MII */
+static int bcmgenet_mii_read(struct mii_bus *bus, int phy_id, int location)
+{
+ int ret;
+ struct net_device *dev = bus->priv;
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ u32 reg;
+
+ bcmgenet_umac_writel(priv, (MDIO_RD | (phy_id << MDIO_PMD_SHIFT) |
+ (location << MDIO_REG_SHIFT)), UMAC_MDIO_CMD);
+ /* Start MDIO transaction*/
+ reg = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD);
+ reg |= MDIO_START_BUSY;
+ bcmgenet_umac_writel(priv, reg, UMAC_MDIO_CMD);
+ wait_event_timeout(priv->wq,
+ !(bcmgenet_umac_readl(priv, UMAC_MDIO_CMD)
+ & MDIO_START_BUSY),
+ HZ / 100);
+ ret = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD);
+
+ if (ret & MDIO_READ_FAIL)
+ return -EIO;
+
+ return ret & 0xffff;
+}
+
+/* write a value to the MII */
+static int bcmgenet_mii_write(struct mii_bus *bus, int phy_id,
+ int location, u16 val)
+{
+ struct net_device *dev = bus->priv;
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ u32 reg;
+
+ bcmgenet_umac_writel(priv, (MDIO_WR | (phy_id << MDIO_PMD_SHIFT) |
+ (location << MDIO_REG_SHIFT) | (0xffff & val)),
+ UMAC_MDIO_CMD);
+ reg = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD);
+ reg |= MDIO_START_BUSY;
+ bcmgenet_umac_writel(priv, reg, UMAC_MDIO_CMD);
+ wait_event_timeout(priv->wq,
+ !(bcmgenet_umac_readl(priv, UMAC_MDIO_CMD) &
+ MDIO_START_BUSY),
+ HZ / 100);
+
+ return 0;
+}
+
+/* setup netdev link state when PHY link status change and
+ * update UMAC and RGMII block when link up
+ */
+static void bcmgenet_mii_setup(struct net_device *dev)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev = priv->phydev;
+ u32 reg, cmd_bits = 0;
+ unsigned int status_changed = 0;
+
+ if (priv->old_link != phydev->link) {
+ status_changed = 1;
+ priv->old_link = phydev->link;
+ }
+
+ if (phydev->link) {
+ /* program UMAC and RGMII block based on established link
+ * speed, pause, and duplex.
+ * the speed set in umac->cmd tell RGMII block which clock
+ * 25MHz(100Mbps)/125MHz(1Gbps) to use for transmit.
+ * receive clock is provided by PHY.
+ */
+ reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL);
+ reg &= ~OOB_DISABLE;
+ reg |= RGMII_LINK;
+ bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
+
+ /* speed */
+ if (phydev->speed == SPEED_1000)
+ cmd_bits = UMAC_SPEED_1000;
+ else if (phydev->speed == SPEED_100)
+ cmd_bits = UMAC_SPEED_100;
+ else
+ cmd_bits = UMAC_SPEED_10;
+ cmd_bits <<= CMD_SPEED_SHIFT;
+
+ if (priv->old_duplex != phydev->duplex) {
+ status_changed = 1;
+ priv->old_duplex = phydev->duplex;
+ }
+
+ /* duplex */
+ if (phydev->duplex != DUPLEX_FULL)
+ cmd_bits |= CMD_HD_EN;
+
+ if (priv->old_pause != phydev->pause) {
+ status_changed = 1;
+ priv->old_pause = phydev->pause;
+ }
+
+ /* pause capability */
+ if (!phydev->pause)
+ cmd_bits |= CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE;
+
+ reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+ reg &= ~((CMD_SPEED_MASK << CMD_SPEED_SHIFT) |
+ CMD_HD_EN |
+ CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE);
+ reg |= cmd_bits;
+ bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+ }
+
+ if (status_changed)
+ phy_print_status(phydev);
+}
+
+void bcmgenet_mii_reset(struct net_device *dev)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+
+ if (priv->phydev) {
+ phy_init_hw(priv->phydev);
+ phy_start_aneg(priv->phydev);
+ }
+}
+
+static void bcmgenet_ephy_power_up(struct net_device *dev)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ u32 reg = 0;
+
+ /* EXT_GPHY_CTRL is only valid for GENETv4 and onward */
+ if (!GENET_IS_V4(priv))
+ return;
+
+ reg = bcmgenet_ext_readl(priv, EXT_GPHY_CTRL);
+ reg &= ~(EXT_CFG_IDDQ_BIAS | EXT_CFG_PWR_DOWN);
+ reg |= EXT_GPHY_RESET;
+ bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
+ mdelay(2);
+
+ reg &= ~EXT_GPHY_RESET;
+ bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
+ udelay(20);
+}
+
+static void bcmgenet_internal_phy_setup(struct net_device *dev)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ u32 reg;
+
+ /* Power up EPHY */
+ bcmgenet_ephy_power_up(dev);
+ /* enable APD */
+ reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
+ reg |= EXT_PWR_DN_EN_LD;
+ bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
+ bcmgenet_mii_reset(dev);
+}
+
+static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv)
+{
+ u32 reg;
+
+ /* Speed settings are set in bcmgenet_mii_setup() */
+ reg = bcmgenet_sys_readl(priv, SYS_PORT_CTRL);
+ reg |= LED_ACT_SOURCE_MAC;
+ bcmgenet_sys_writel(priv, reg, SYS_PORT_CTRL);
+}
+
+int bcmgenet_mii_config(struct net_device *dev)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev = priv->phydev;
+ struct device *kdev = &priv->pdev->dev;
+ const char *phy_name = NULL;
+ u32 id_mode_dis = 0;
+ u32 port_ctrl;
+ u32 reg;
+
+ priv->ext_phy = !phy_is_internal(priv->phydev) &&
+ (priv->phy_interface != PHY_INTERFACE_MODE_MOCA);
+
+ if (phy_is_internal(priv->phydev))
+ priv->phy_interface = PHY_INTERFACE_MODE_NA;
+
+ switch (priv->phy_interface) {
+ case PHY_INTERFACE_MODE_NA:
+ case PHY_INTERFACE_MODE_MOCA:
+ /* Irrespective of the actually configured PHY speed (100 or
+ * 1000) GENETv4 only has an internal GPHY so we will just end
+ * up masking the Gigabit features from what we support, not
+ * switching to the EPHY
+ */
+ if (GENET_IS_V4(priv))
+ port_ctrl = PORT_MODE_INT_GPHY;
+ else
+ port_ctrl = PORT_MODE_INT_EPHY;
+
+ bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL);
+
+ if (phy_is_internal(priv->phydev)) {
+ phy_name = "internal PHY";
+ bcmgenet_internal_phy_setup(dev);
+ } else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
+ phy_name = "MoCA";
+ bcmgenet_moca_phy_setup(priv);
+ }
+ break;
+
+ case PHY_INTERFACE_MODE_MII:
+ phy_name = "external MII";
+ phydev->supported &= PHY_BASIC_FEATURES;
+ bcmgenet_sys_writel(priv,
+ PORT_MODE_EXT_EPHY, SYS_PORT_CTRL);
+ break;
+
+ case PHY_INTERFACE_MODE_REVMII:
+ phy_name = "external RvMII";
+ /* of_mdiobus_register took care of reading the 'max-speed'
+ * PHY property for us, effectively limiting the PHY supported
+ * capabilities, use that knowledge to also configure the
+ * Reverse MII interface correctly.
+ */
+ if ((priv->phydev->supported & PHY_BASIC_FEATURES) ==
+ PHY_BASIC_FEATURES)
+ port_ctrl = PORT_MODE_EXT_RVMII_25;
+ else
+ port_ctrl = PORT_MODE_EXT_RVMII_50;
+ bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL);
+ break;
+
+ case PHY_INTERFACE_MODE_RGMII:
+ /* RGMII_NO_ID: TXC transitions at the same time as TXD
+ * (requires PCB or receiver-side delay)
+ * RGMII: Add 2ns delay on TXC (90 degree shift)
+ *
+ * ID is implicitly disabled for 100Mbps (RG)MII operation.
+ */
+ id_mode_dis = BIT(16);
+ /* fall through */
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ if (id_mode_dis)
+ phy_name = "external RGMII (no delay)";
+ else
+ phy_name = "external RGMII (TX delay)";
+ reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL);
+ reg |= RGMII_MODE_EN | id_mode_dis;
+ bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
+ bcmgenet_sys_writel(priv,
+ PORT_MODE_EXT_GPHY, SYS_PORT_CTRL);
+ break;
+ default:
+ dev_err(kdev, "unknown phy mode: %d\n", priv->phy_interface);
+ return -EINVAL;
+ }
+
+ dev_info(kdev, "configuring instance for %s\n", phy_name);
+
+ return 0;
+}
+
+static int bcmgenet_mii_probe(struct net_device *dev)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev;
+ unsigned int phy_flags;
+ int ret;
+
+ if (priv->phydev) {
+ pr_info("PHY already attached\n");
+ return 0;
+ }
+
+ if (priv->phy_dn)
+ phydev = of_phy_connect(dev, priv->phy_dn,
+ bcmgenet_mii_setup, 0,
+ priv->phy_interface);
+ else
+ phydev = of_phy_connect_fixed_link(dev,
+ bcmgenet_mii_setup,
+ priv->phy_interface);
+
+ if (!phydev) {
+ pr_err("could not attach to PHY\n");
+ return -ENODEV;
+ }
+
+ priv->old_link = -1;
+ priv->old_duplex = -1;
+ priv->old_pause = -1;
+ priv->phydev = phydev;
+
+ /* Configure port multiplexer based on what the probed PHY device since
+ * reading the 'max-speed' property determines the maximum supported
+ * PHY speed which is needed for bcmgenet_mii_config() to configure
+ * things appropriately.
+ */
+ ret = bcmgenet_mii_config(dev);
+ if (ret) {
+ phy_disconnect(priv->phydev);
+ return ret;
+ }
+
+ phy_flags = PHY_BRCM_100MBPS_WAR;
+
+ /* workarounds are only needed for 100Mpbs PHYs, and
+ * never on GENET V1 hardware
+ */
+ if ((phydev->supported & PHY_GBIT_FEATURES) || GENET_IS_V1(priv))
+ phy_flags = 0;
+
+ phydev->dev_flags |= phy_flags;
+ phydev->advertising = phydev->supported;
+
+ /* The internal PHY has its link interrupts routed to the
+ * Ethernet MAC ISRs
+ */
+ if (phy_is_internal(priv->phydev))
+ priv->mii_bus->irq[phydev->addr] = PHY_IGNORE_INTERRUPT;
+ else
+ priv->mii_bus->irq[phydev->addr] = PHY_POLL;
+
+ pr_info("attached PHY at address %d [%s]\n",
+ phydev->addr, phydev->drv->name);
+
+ return 0;
+}
+
+static int bcmgenet_mii_alloc(struct bcmgenet_priv *priv)
+{
+ struct mii_bus *bus;
+
+ if (priv->mii_bus)
+ return 0;
+
+ priv->mii_bus = mdiobus_alloc();
+ if (!priv->mii_bus) {
+ pr_err("failed to allocate\n");
+ return -ENOMEM;
+ }
+
+ bus = priv->mii_bus;
+ bus->priv = priv->dev;
+ bus->name = "bcmgenet MII bus";
+ bus->parent = &priv->pdev->dev;
+ bus->read = bcmgenet_mii_read;
+ bus->write = bcmgenet_mii_write;
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d",
+ priv->pdev->name, priv->pdev->id);
+
+ bus->irq = kzalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (!bus->irq) {
+ mdiobus_free(priv->mii_bus);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv)
+{
+ struct device_node *dn = priv->pdev->dev.of_node;
+ struct device *kdev = &priv->pdev->dev;
+ struct device_node *mdio_dn;
+ char *compat;
+ int ret;
+
+ compat = kasprintf(GFP_KERNEL, "brcm,genet-mdio-v%d", priv->version);
+ if (!compat)
+ return -ENOMEM;
+
+ mdio_dn = of_find_compatible_node(dn, NULL, compat);
+ kfree(compat);
+ if (!mdio_dn) {
+ dev_err(kdev, "unable to find MDIO bus node\n");
+ return -ENODEV;
+ }
+
+ ret = of_mdiobus_register(priv->mii_bus, mdio_dn);
+ if (ret) {
+ dev_err(kdev, "failed to register MDIO bus\n");
+ return ret;
+ }
+
+ /* Fetch the PHY phandle */
+ priv->phy_dn = of_parse_phandle(dn, "phy-handle", 0);
+
+ /* Get the link mode */
+ priv->phy_interface = of_get_phy_mode(dn);
+
+ return 0;
+}
+
+int bcmgenet_mii_init(struct net_device *dev)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+ int ret;
+
+ ret = bcmgenet_mii_alloc(priv);
+ if (ret)
+ return ret;
+
+ ret = bcmgenet_mii_of_init(priv);
+ if (ret)
+ goto out_free;
+
+ ret = bcmgenet_mii_probe(dev);
+ if (ret)
+ goto out;
+
+ return 0;
+
+out:
+ mdiobus_unregister(priv->mii_bus);
+out_free:
+ kfree(priv->mii_bus->irq);
+ mdiobus_free(priv->mii_bus);
+ return ret;
+}
+
+void bcmgenet_mii_exit(struct net_device *dev)
+{
+ struct bcmgenet_priv *priv = netdev_priv(dev);
+
+ mdiobus_unregister(priv->mii_bus);
+ kfree(priv->mii_bus->irq);
+ mdiobus_free(priv->mii_bus);
+}
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index e2ca03e23dc1..b9f7022f4e81 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -1401,11 +1401,6 @@ static int tg3_mdio_write(struct mii_bus *bp, int mii_id, int reg, u16 val)
return ret;
}
-static int tg3_mdio_reset(struct mii_bus *bp)
-{
- return 0;
-}
-
static void tg3_mdio_config_5785(struct tg3 *tp)
{
u32 val;
@@ -1542,7 +1537,6 @@ static int tg3_mdio_init(struct tg3 *tp)
tp->mdio_bus->parent = &tp->pdev->dev;
tp->mdio_bus->read = &tg3_mdio_read;
tp->mdio_bus->write = &tg3_mdio_write;
- tp->mdio_bus->reset = &tg3_mdio_reset;
tp->mdio_bus->phy_mask = ~(1 << tp->phy_addr);
tp->mdio_bus->irq = &tp->mdio_irq[0];
@@ -2609,13 +2603,14 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
tg3_writephy(tp, MII_CTRL1000, phy9_orig);
- if (!tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32)) {
- reg32 &= ~0x3000;
- tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
- } else if (!err)
- err = -EBUSY;
+ err = tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32);
+ if (err)
+ return err;
- return err;
+ reg32 &= ~0x3000;
+ tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
+
+ return 0;
}
static void tg3_carrier_off(struct tg3 *tp)
@@ -6321,6 +6316,7 @@ static const struct ptp_clock_info tg3_ptp_caps = {
.n_alarm = 0,
.n_ext_ts = 0,
.n_per_out = 1,
+ .n_pins = 0,
.pps = 0,
.adjfreq = tg3_ptp_adjfreq,
.adjtime = tg3_ptp_adjtime,
@@ -6592,7 +6588,7 @@ static void tg3_tx(struct tg3_napi *tnapi)
pkts_compl++;
bytes_compl += skb->len;
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
if (unlikely(tx_bug)) {
tg3_tx_recover(tp);
@@ -6842,8 +6838,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
work_mask |= opaque_key;
- if ((desc->err_vlan & RXD_ERR_MASK) != 0 &&
- (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) {
+ if (desc->err_vlan & RXD_ERR_MASK) {
drop_it:
tg3_recycle_rx(tnapi, tpr, opaque_key,
desc_idx, *post_ptr);
@@ -6924,7 +6919,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
if (len > (tp->dev->mtu + ETH_HLEN) &&
skb->protocol != htons(ETH_P_8021Q)) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
goto drop_it_no_recycle;
}
@@ -7807,7 +7802,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi,
PCI_DMA_TODEVICE);
/* Make sure the mapping succeeded */
if (pci_dma_mapping_error(tp->pdev, new_addr)) {
- dev_kfree_skb(new_skb);
+ dev_kfree_skb_any(new_skb);
ret = -1;
} else {
u32 save_entry = *entry;
@@ -7822,13 +7817,13 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi,
new_skb->len, base_flags,
mss, vlan)) {
tg3_tx_skb_unmap(tnapi, save_entry, -1);
- dev_kfree_skb(new_skb);
+ dev_kfree_skb_any(new_skb);
ret = -1;
}
}
}
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
*pskb = new_skb;
return ret;
}
@@ -7871,7 +7866,7 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb)
} while (segs);
tg3_tso_bug_end:
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -7923,8 +7918,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct iphdr *iph;
u32 tcp_opt_len, hdr_len;
- if (skb_header_cloned(skb) &&
- pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ if (skb_cow_head(skb, 0))
goto drop;
iph = ip_hdr(skb);
@@ -8093,7 +8087,7 @@ dma_error:
tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, --i);
tnapi->tx_buffers[tnapi->tx_prod].skb = NULL;
drop:
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
drop_nofree:
tp->tx_dropped++;
return NETDEV_TX_OK;
@@ -11361,12 +11355,10 @@ static bool tg3_enable_msix(struct tg3 *tp)
msix_ent[i].vector = 0;
}
- rc = pci_enable_msix(tp->pdev, msix_ent, tp->irq_cnt);
+ rc = pci_enable_msix_range(tp->pdev, msix_ent, 1, tp->irq_cnt);
if (rc < 0) {
return false;
- } else if (rc != 0) {
- if (pci_enable_msix(tp->pdev, msix_ent, rc))
- return false;
+ } else if (rc < tp->irq_cnt) {
netdev_notice(tp->dev, "Requested %d MSI-X vectors, received %d\n",
tp->irq_cnt, rc);
tp->irq_cnt = rc;
@@ -14113,12 +14105,12 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
tg3_netif_stop(tp);
+ tg3_set_mtu(dev, tp, new_mtu);
+
tg3_full_lock(tp, 1);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
- tg3_set_mtu(dev, tp, new_mtu);
-
/* Reset PHY, otherwise the read DMA engine will be in a mode that
* breaks all requests to 256 bytes.
*/
@@ -17649,8 +17641,6 @@ static int tg3_init_one(struct pci_dev *pdev,
tg3_init_bufmgr_config(tp);
- features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
-
/* 5700 B0 chips do not support checksumming correctly due
* to hardware bugs.
*/
@@ -17682,7 +17672,8 @@ static int tg3_init_one(struct pci_dev *pdev,
features |= NETIF_F_TSO_ECN;
}
- dev->features |= features;
+ dev->features |= features | NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX;
dev->vlan_features |= features;
/*
diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h
index ef472385bce4..04321e5a356e 100644
--- a/drivers/net/ethernet/broadcom/tg3.h
+++ b/drivers/net/ethernet/broadcom/tg3.h
@@ -2608,7 +2608,11 @@ struct tg3_rx_buffer_desc {
#define RXD_ERR_TOO_SMALL 0x00400000
#define RXD_ERR_NO_RESOURCES 0x00800000
#define RXD_ERR_HUGE_FRAME 0x01000000
-#define RXD_ERR_MASK 0xffff0000
+
+#define RXD_ERR_MASK (RXD_ERR_BAD_CRC | RXD_ERR_COLLISION | \
+ RXD_ERR_LINK_LOST | RXD_ERR_PHY_DECODE | \
+ RXD_ERR_MAC_ABRT | RXD_ERR_TOO_SMALL | \
+ RXD_ERR_NO_RESOURCES | RXD_ERR_HUGE_FRAME)
u32 reserved;
u32 opaque;
diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc.c b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
index 1803c3959044..354ae9792bad 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_ioc.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
@@ -1704,7 +1704,7 @@ bfa_flash_sem_get(void __iomem *bar)
while (!bfa_raw_sem_get(bar)) {
if (--n <= 0)
return BFA_STATUS_BADFLASH;
- udelay(10000);
+ mdelay(10);
}
return BFA_STATUS_OK;
}
diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c
index cf64f3d0b60d..675550fe8ee9 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.c
+++ b/drivers/net/ethernet/brocade/bna/bnad.c
@@ -707,7 +707,8 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget)
else
skb_checksum_none_assert(skb);
- if (flags & BNA_CQ_EF_VLAN)
+ if ((flags & BNA_CQ_EF_VLAN) &&
+ (bnad->netdev->features & NETIF_F_HW_VLAN_CTAG_RX))
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(cmpl->vlan_tag));
if (BNAD_RXBUF_IS_SK_BUFF(unmap_q->type))
@@ -2094,7 +2095,9 @@ bnad_init_rx_config(struct bnad *bnad, struct bna_rx_config *rx_config)
rx_config->q1_buf_size = BFI_SMALL_RXBUF_SIZE;
}
- rx_config->vlan_strip_status = BNA_STATUS_T_ENABLED;
+ rx_config->vlan_strip_status =
+ (bnad->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) ?
+ BNA_STATUS_T_ENABLED : BNA_STATUS_T_DISABLED;
}
static void
@@ -2493,12 +2496,10 @@ bnad_tso_prepare(struct bnad *bnad, struct sk_buff *skb)
{
int err;
- if (skb_header_cloned(skb)) {
- err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
- if (err) {
- BNAD_UPDATE_CTR(bnad, tso_err);
- return err;
- }
+ err = skb_cow_head(skb, 0);
+ if (err < 0) {
+ BNAD_UPDATE_CTR(bnad, tso_err);
+ return err;
}
/*
@@ -2666,9 +2667,11 @@ bnad_enable_msix(struct bnad *bnad)
for (i = 0; i < bnad->msix_num; i++)
bnad->msix_table[i].entry = i;
- ret = pci_enable_msix(bnad->pcidev, bnad->msix_table, bnad->msix_num);
- if (ret > 0) {
- /* Not enough MSI-X vectors. */
+ ret = pci_enable_msix_range(bnad->pcidev, bnad->msix_table,
+ 1, bnad->msix_num);
+ if (ret < 0) {
+ goto intx_mode;
+ } else if (ret < bnad->msix_num) {
pr_warn("BNA: %d MSI-X vectors allocated < %d requested\n",
ret, bnad->msix_num);
@@ -2681,18 +2684,11 @@ bnad_enable_msix(struct bnad *bnad)
bnad->msix_num = BNAD_NUM_TXQ + BNAD_NUM_RXP +
BNAD_MAILBOX_MSIX_VECTORS;
- if (bnad->msix_num > ret)
+ if (bnad->msix_num > ret) {
+ pci_disable_msix(bnad->pcidev);
goto intx_mode;
-
- /* Try once more with adjusted numbers */
- /* If this fails, fall back to INTx */
- ret = pci_enable_msix(bnad->pcidev, bnad->msix_table,
- bnad->msix_num);
- if (ret)
- goto intx_mode;
-
- } else if (ret < 0)
- goto intx_mode;
+ }
+ }
pci_intx(bnad->pcidev, 0);
@@ -2847,13 +2843,11 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb,
}
if (unlikely((gso_size + skb_transport_offset(skb) +
tcp_hdrlen(skb)) >= skb->len)) {
- txqent->hdr.wi.opcode =
- __constant_htons(BNA_TXQ_WI_SEND);
+ txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND);
txqent->hdr.wi.lso_mss = 0;
BNAD_UPDATE_CTR(bnad, tx_skb_tso_too_short);
} else {
- txqent->hdr.wi.opcode =
- __constant_htons(BNA_TXQ_WI_SEND_LSO);
+ txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND_LSO);
txqent->hdr.wi.lso_mss = htons(gso_size);
}
@@ -2867,7 +2861,7 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb,
htons(BNA_TXQ_WI_L4_HDR_N_OFFSET(
tcp_hdrlen(skb) >> 2, skb_transport_offset(skb)));
} else {
- txqent->hdr.wi.opcode = __constant_htons(BNA_TXQ_WI_SEND);
+ txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND);
txqent->hdr.wi.lso_mss = 0;
if (unlikely(skb->len > (bnad->netdev->mtu + ETH_HLEN))) {
@@ -2878,11 +2872,10 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb,
if (skb->ip_summed == CHECKSUM_PARTIAL) {
u8 proto = 0;
- if (skb->protocol == __constant_htons(ETH_P_IP))
+ if (skb->protocol == htons(ETH_P_IP))
proto = ip_hdr(skb)->protocol;
#ifdef NETIF_F_IPV6_CSUM
- else if (skb->protocol ==
- __constant_htons(ETH_P_IPV6)) {
+ else if (skb->protocol == htons(ETH_P_IPV6)) {
/* nexthdr may not be TCP immediately. */
proto = ipv6_hdr(skb)->nexthdr;
}
@@ -2951,17 +2944,17 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
/* Sanity checks for the skb */
if (unlikely(skb->len <= ETH_HLEN)) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_too_short);
return NETDEV_TX_OK;
}
if (unlikely(len > BFI_TX_MAX_DATA_PER_VECTOR)) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_headlen_zero);
return NETDEV_TX_OK;
}
if (unlikely(len == 0)) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_headlen_zero);
return NETDEV_TX_OK;
}
@@ -2973,7 +2966,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
* and the netif_tx_stop_all_queues() call.
*/
if (unlikely(!tcb || !test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_stopping);
return NETDEV_TX_OK;
}
@@ -2986,7 +2979,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
wis = BNA_TXQ_WI_NEEDED(vectors); /* 4 vectors per work item */
if (unlikely(vectors > BFI_TX_MAX_VECTORS_PER_PKT)) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_max_vectors);
return NETDEV_TX_OK;
}
@@ -3026,7 +3019,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
/* Program the opcode, flags, frame_len, num_vectors in WI */
if (bnad_txq_wi_prepare(bnad, tcb, skb, txqent)) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
txqent->hdr.wi.reserved = 0;
@@ -3052,7 +3045,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
/* Undo the changes starting at tcb->producer_index */
bnad_tx_buff_unmap(bnad, unmap_q, q_depth,
tcb->producer_index);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_frag_zero);
return NETDEV_TX_OK;
}
@@ -3064,8 +3057,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
vect_id = 0;
BNA_QE_INDX_INC(prod, q_depth);
txqent = &((struct bna_txq_entry *)tcb->sw_q)[prod];
- txqent->hdr.wi_ext.opcode =
- __constant_htons(BNA_TXQ_WI_EXTENSION);
+ txqent->hdr.wi_ext.opcode = htons(BNA_TXQ_WI_EXTENSION);
unmap = &unmap_q[prod];
}
@@ -3082,7 +3074,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
if (unlikely(len != skb->len)) {
/* Undo the changes starting at tcb->producer_index */
bnad_tx_buff_unmap(bnad, unmap_q, q_depth, tcb->producer_index);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
BNAD_UPDATE_CTR(bnad, tx_skb_len_mismatch);
return NETDEV_TX_OK;
}
@@ -3245,11 +3237,6 @@ bnad_set_rx_mode(struct net_device *netdev)
BNA_RXMODE_ALLMULTI;
bna_rx_mode_set(bnad->rx_info[0].rx, new_mode, mode_mask, NULL);
- if (bnad->cfg_flags & BNAD_CF_PROMISC)
- bna_rx_vlan_strip_disable(bnad->rx_info[0].rx);
- else
- bna_rx_vlan_strip_enable(bnad->rx_info[0].rx);
-
spin_unlock_irqrestore(&bnad->bna_lock, flags);
}
@@ -3374,6 +3361,27 @@ bnad_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
return 0;
}
+static int bnad_set_features(struct net_device *dev, netdev_features_t features)
+{
+ struct bnad *bnad = netdev_priv(dev);
+ netdev_features_t changed = features ^ dev->features;
+
+ if ((changed & NETIF_F_HW_VLAN_CTAG_RX) && netif_running(dev)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
+ bna_rx_vlan_strip_enable(bnad->rx_info[0].rx);
+ else
+ bna_rx_vlan_strip_disable(bnad->rx_info[0].rx);
+
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_NET_POLL_CONTROLLER
static void
bnad_netpoll(struct net_device *netdev)
@@ -3421,6 +3429,7 @@ static const struct net_device_ops bnad_netdev_ops = {
.ndo_change_mtu = bnad_change_mtu,
.ndo_vlan_rx_add_vid = bnad_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = bnad_vlan_rx_kill_vid,
+ .ndo_set_features = bnad_set_features,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = bnad_netpoll
#endif
@@ -3433,14 +3442,14 @@ bnad_netdev_init(struct bnad *bnad, bool using_dac)
netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
- NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_TX;
+ NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX;
netdev->vlan_features = NETIF_F_SG | NETIF_F_HIGHDMA |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_TSO | NETIF_F_TSO6;
- netdev->features |= netdev->hw_features |
- NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER;
+ netdev->features |= netdev->hw_features | NETIF_F_HW_VLAN_CTAG_FILTER;
if (using_dac)
netdev->features |= NETIF_F_HIGHDMA;
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index 3190d38e16fb..ca97005e24b4 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -199,11 +199,6 @@ static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
return 0;
}
-static int macb_mdio_reset(struct mii_bus *bus)
-{
- return 0;
-}
-
/**
* macb_set_tx_clk() - Set a clock to a new frequency
* @clk Pointer to the clock to change
@@ -375,7 +370,6 @@ int macb_mii_init(struct macb *bp)
bp->mii_bus->name = "MACB_mii_bus";
bp->mii_bus->read = &macb_mdio_read;
bp->mii_bus->write = &macb_mdio_write;
- bp->mii_bus->reset = &macb_mdio_reset;
snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
bp->pdev->name, bp->pdev->id);
bp->mii_bus->priv = bp;
@@ -632,11 +626,16 @@ static void gem_rx_refill(struct macb *bp)
"Unable to allocate sk_buff\n");
break;
}
- bp->rx_skbuff[entry] = skb;
/* now fill corresponding descriptor entry */
paddr = dma_map_single(&bp->pdev->dev, skb->data,
bp->rx_buffer_size, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&bp->pdev->dev, paddr)) {
+ dev_kfree_skb(skb);
+ break;
+ }
+
+ bp->rx_skbuff[entry] = skb;
if (entry == RX_RING_SIZE - 1)
paddr |= MACB_BIT(RX_WRAP);
@@ -725,7 +724,7 @@ static int gem_rx(struct macb *bp, int budget)
skb_put(skb, len);
addr = MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, addr));
dma_unmap_single(&bp->pdev->dev, addr,
- len, DMA_FROM_DEVICE);
+ bp->rx_buffer_size, DMA_FROM_DEVICE);
skb->protocol = eth_type_trans(skb, bp->dev);
skb_checksum_none_assert(skb);
@@ -1036,11 +1035,15 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
entry = macb_tx_ring_wrap(bp->tx_head);
- bp->tx_head++;
netdev_vdbg(bp->dev, "Allocated ring entry %u\n", entry);
mapping = dma_map_single(&bp->pdev->dev, skb->data,
len, DMA_TO_DEVICE);
+ if (dma_mapping_error(&bp->pdev->dev, mapping)) {
+ dev_kfree_skb_any(skb);
+ goto unlock;
+ }
+ bp->tx_head++;
tx_skb = &bp->tx_skb[entry];
tx_skb->skb = skb;
tx_skb->mapping = mapping;
@@ -1066,6 +1069,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (CIRC_SPACE(bp->tx_head, bp->tx_tail, TX_RING_SIZE) < 1)
netif_stop_queue(dev);
+unlock:
spin_unlock_irqrestore(&bp->lock, flags);
return NETDEV_TX_OK;
diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
index d2a183c3a6ce..521dfea44b83 100644
--- a/drivers/net/ethernet/calxeda/xgmac.c
+++ b/drivers/net/ethernet/calxeda/xgmac.c
@@ -897,7 +897,7 @@ static void xgmac_tx_complete(struct xgmac_priv *priv)
/* Check tx error on the last segment */
if (desc_get_tx_ls(p)) {
desc_get_tx_status(priv, p);
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
}
priv->tx_skbuff[entry] = NULL;
@@ -1105,7 +1105,7 @@ static netdev_tx_t xgmac_xmit(struct sk_buff *skb, struct net_device *dev)
len = skb_headlen(skb);
paddr = dma_map_single(priv->device, skb->data, len, DMA_TO_DEVICE);
if (dma_mapping_error(priv->device, paddr)) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
priv->tx_skbuff[entry] = skb;
@@ -1169,7 +1169,7 @@ dma_err:
desc = first;
dma_unmap_single(priv->device, desc_get_buf_addr(desc),
desc_get_buf_len(desc), DMA_TO_DEVICE);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
index 45d77334d7d9..07bbb711b7e5 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
@@ -3088,30 +3088,22 @@ static int cxgb_enable_msix(struct adapter *adap)
{
struct msix_entry entries[SGE_QSETS + 1];
int vectors;
- int i, err;
+ int i;
vectors = ARRAY_SIZE(entries);
for (i = 0; i < vectors; ++i)
entries[i].entry = i;
- while ((err = pci_enable_msix(adap->pdev, entries, vectors)) > 0)
- vectors = err;
-
- if (err < 0)
- pci_disable_msix(adap->pdev);
-
- if (!err && vectors < (adap->params.nports + 1)) {
- pci_disable_msix(adap->pdev);
- err = -1;
- }
+ vectors = pci_enable_msix_range(adap->pdev, entries,
+ adap->params.nports + 1, vectors);
+ if (vectors < 0)
+ return vectors;
- if (!err) {
- for (i = 0; i < vectors; ++i)
- adap->msix_info[i].vec = entries[i].vector;
- adap->msix_nvectors = vectors;
- }
+ for (i = 0; i < vectors; ++i)
+ adap->msix_info[i].vec = entries[i].vector;
+ adap->msix_nvectors = vectors;
- return err;
+ return 0;
}
static void print_port_info(struct adapter *adap, const struct adapter_info *ai)
diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c
index 632b318eb38a..8b069f96e920 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c
@@ -298,7 +298,7 @@ static void free_tx_desc(struct adapter *adapter, struct sge_txq *q,
if (need_unmap)
unmap_skb(d->skb, q, cidx, pdev);
if (d->eop) {
- kfree_skb(d->skb);
+ dev_consume_skb_any(d->skb);
d->skb = NULL;
}
}
@@ -1188,7 +1188,7 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb,
cpl->wr.wr_lo = htonl(V_WR_LEN(flits) | V_WR_GEN(gen) |
V_WR_TID(q->token));
wr_gen2(d, gen);
- kfree_skb(skb);
+ dev_consume_skb_any(skb);
return;
}
@@ -1233,7 +1233,7 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
* anything shorter than an Ethernet header.
*/
if (unlikely(skb->len < ETH_HLEN)) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index 1f4b9b30b9ed..32db37709263 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -66,6 +66,7 @@ enum {
SERNUM_LEN = 24, /* Serial # length */
EC_LEN = 16, /* E/C length */
ID_LEN = 16, /* ID length */
+ PN_LEN = 16, /* Part Number length */
};
enum {
@@ -254,6 +255,7 @@ struct vpd_params {
u8 ec[EC_LEN + 1];
u8 sn[SERNUM_LEN + 1];
u8 id[ID_LEN + 1];
+ u8 pn[PN_LEN + 1];
};
struct pci_params {
@@ -306,6 +308,7 @@ struct adapter_params {
unsigned char bypass;
unsigned int ofldq_wr_cred;
+ bool ulptx_memwrite_dsgl; /* use of T5 DSGL allowed */
};
#include "t4fw_api.h"
@@ -497,6 +500,7 @@ struct sge_txq {
spinlock_t db_lock;
int db_disabled;
unsigned short db_pidx;
+ unsigned short db_pidx_inc;
u64 udb;
};
@@ -553,8 +557,13 @@ struct sge {
u32 pktshift; /* padding between CPL & packet data */
u32 fl_align; /* response queue message alignment */
u32 fl_starve_thres; /* Free List starvation threshold */
- unsigned int starve_thres;
- u8 idma_state[2];
+
+ /* State variables for detecting an SGE Ingress DMA hang */
+ unsigned int idma_1s_thresh;/* SGE same State Counter 1s threshold */
+ unsigned int idma_stalled[2];/* SGE synthesized stalled timers in HZ */
+ unsigned int idma_state[2]; /* SGE IDMA Hang detect state */
+ unsigned int idma_qid[2]; /* SGE IDMA Hung Ingress Queue ID */
+
unsigned int egr_start;
unsigned int ingr_start;
void *egr_map[MAX_EGRQ]; /* qid->queue egress queue map */
@@ -957,7 +966,7 @@ int t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data,
u64 *parity);
int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data,
u64 *parity);
-
+const char *t4_get_port_type_description(enum fw_port_type port_type);
void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p);
void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log);
void t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr,
@@ -1029,4 +1038,5 @@ void t4_db_dropped(struct adapter *adapter);
int t4_mem_win_read_len(struct adapter *adap, u32 addr, __be32 *data, int len);
int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox,
u32 addr, u32 val);
+void t4_sge_decode_idma_state(struct adapter *adapter, int state);
#endif /* __CXGB4_H__ */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 43ab35fea48d..6fe58913403a 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -254,6 +254,14 @@ static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = {
CH_DEVICE(0x5011, 4),
CH_DEVICE(0x5012, 4),
CH_DEVICE(0x5013, 4),
+ CH_DEVICE(0x5014, 4),
+ CH_DEVICE(0x5015, 4),
+ CH_DEVICE(0x5080, 4),
+ CH_DEVICE(0x5081, 4),
+ CH_DEVICE(0x5082, 4),
+ CH_DEVICE(0x5083, 4),
+ CH_DEVICE(0x5084, 4),
+ CH_DEVICE(0x5085, 4),
CH_DEVICE(0x5401, 4),
CH_DEVICE(0x5402, 4),
CH_DEVICE(0x5403, 4),
@@ -273,6 +281,14 @@ static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = {
CH_DEVICE(0x5411, 4),
CH_DEVICE(0x5412, 4),
CH_DEVICE(0x5413, 4),
+ CH_DEVICE(0x5414, 4),
+ CH_DEVICE(0x5415, 4),
+ CH_DEVICE(0x5480, 4),
+ CH_DEVICE(0x5481, 4),
+ CH_DEVICE(0x5482, 4),
+ CH_DEVICE(0x5483, 4),
+ CH_DEVICE(0x5484, 4),
+ CH_DEVICE(0x5485, 4),
{ 0, }
};
@@ -423,15 +439,18 @@ static void link_report(struct net_device *dev)
const struct port_info *p = netdev_priv(dev);
switch (p->link_cfg.speed) {
- case SPEED_10000:
+ case 10000:
s = "10Gbps";
break;
- case SPEED_1000:
+ case 1000:
s = "1000Mbps";
break;
- case SPEED_100:
+ case 100:
s = "100Mbps";
break;
+ case 40000:
+ s = "40Gbps";
+ break;
}
netdev_info(dev, "link up, %s, full-duplex, %s PAUSE\n", s,
@@ -2061,7 +2080,7 @@ static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
0x40200, 0x40298,
0x402ac, 0x4033c,
0x403f8, 0x403fc,
- 0x41300, 0x413c4,
+ 0x41304, 0x413c4,
0x41400, 0x4141c,
0x41480, 0x414d0,
0x44000, 0x44078,
@@ -2089,7 +2108,7 @@ static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
0x48200, 0x48298,
0x482ac, 0x4833c,
0x483f8, 0x483fc,
- 0x49300, 0x493c4,
+ 0x49304, 0x493c4,
0x49400, 0x4941c,
0x49480, 0x494d0,
0x4c000, 0x4c078,
@@ -2199,6 +2218,8 @@ static unsigned int from_fw_linkcaps(unsigned int type, unsigned int caps)
else if (type == FW_PORT_TYPE_FIBER_XFI ||
type == FW_PORT_TYPE_FIBER_XAUI || type == FW_PORT_TYPE_SFP)
v |= SUPPORTED_FIBRE;
+ else if (type == FW_PORT_TYPE_BP40_BA)
+ v |= SUPPORTED_40000baseSR4_Full;
if (caps & FW_PORT_CAP_ANEG)
v |= SUPPORTED_Autoneg;
@@ -2215,6 +2236,8 @@ static unsigned int to_fw_linkcaps(unsigned int caps)
v |= FW_PORT_CAP_SPEED_1G;
if (caps & ADVERTISED_10000baseT_Full)
v |= FW_PORT_CAP_SPEED_10G;
+ if (caps & ADVERTISED_40000baseSR4_Full)
+ v |= FW_PORT_CAP_SPEED_40G;
return v;
}
@@ -2263,12 +2286,14 @@ static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
static unsigned int speed_to_caps(int speed)
{
- if (speed == SPEED_100)
+ if (speed == 100)
return FW_PORT_CAP_SPEED_100M;
- if (speed == SPEED_1000)
+ if (speed == 1000)
return FW_PORT_CAP_SPEED_1G;
- if (speed == SPEED_10000)
+ if (speed == 10000)
return FW_PORT_CAP_SPEED_10G;
+ if (speed == 40000)
+ return FW_PORT_CAP_SPEED_40G;
return 0;
}
@@ -2296,8 +2321,10 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
if (cmd->autoneg == AUTONEG_DISABLE) {
cap = speed_to_caps(speed);
- if (!(lc->supported & cap) || (speed == SPEED_1000) ||
- (speed == SPEED_10000))
+ if (!(lc->supported & cap) ||
+ (speed == 1000) ||
+ (speed == 10000) ||
+ (speed == 40000))
return -EINVAL;
lc->requested_speed = cap;
lc->advertising = 0;
@@ -3205,8 +3232,8 @@ static int cxgb4_clip_get(const struct net_device *dev,
c.op_to_write = htonl(FW_CMD_OP(FW_CLIP_CMD) |
FW_CMD_REQUEST | FW_CMD_WRITE);
c.alloc_to_len16 = htonl(F_FW_CLIP_CMD_ALLOC | FW_LEN16(c));
- *(__be64 *)&c.ip_hi = *(__be64 *)(lip->s6_addr);
- *(__be64 *)&c.ip_lo = *(__be64 *)(lip->s6_addr + 8);
+ c.ip_hi = *(__be64 *)(lip->s6_addr);
+ c.ip_lo = *(__be64 *)(lip->s6_addr + 8);
return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false);
}
@@ -3221,8 +3248,8 @@ static int cxgb4_clip_release(const struct net_device *dev,
c.op_to_write = htonl(FW_CMD_OP(FW_CLIP_CMD) |
FW_CMD_REQUEST | FW_CMD_READ);
c.alloc_to_len16 = htonl(F_FW_CLIP_CMD_FREE | FW_LEN16(c));
- *(__be64 *)&c.ip_hi = *(__be64 *)(lip->s6_addr);
- *(__be64 *)&c.ip_lo = *(__be64 *)(lip->s6_addr + 8);
+ c.ip_hi = *(__be64 *)(lip->s6_addr);
+ c.ip_lo = *(__be64 *)(lip->s6_addr + 8);
return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false);
}
@@ -3563,14 +3590,25 @@ static void drain_db_fifo(struct adapter *adap, int usecs)
static void disable_txq_db(struct sge_txq *q)
{
- spin_lock_irq(&q->db_lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->db_lock, flags);
q->db_disabled = 1;
- spin_unlock_irq(&q->db_lock);
+ spin_unlock_irqrestore(&q->db_lock, flags);
}
-static void enable_txq_db(struct sge_txq *q)
+static void enable_txq_db(struct adapter *adap, struct sge_txq *q)
{
spin_lock_irq(&q->db_lock);
+ if (q->db_pidx_inc) {
+ /* Make sure that all writes to the TX descriptors
+ * are committed before we tell HW about them.
+ */
+ wmb();
+ t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL),
+ QID(q->cntxt_id) | PIDX(q->db_pidx_inc));
+ q->db_pidx_inc = 0;
+ }
q->db_disabled = 0;
spin_unlock_irq(&q->db_lock);
}
@@ -3592,11 +3630,32 @@ static void enable_dbs(struct adapter *adap)
int i;
for_each_ethrxq(&adap->sge, i)
- enable_txq_db(&adap->sge.ethtxq[i].q);
+ enable_txq_db(adap, &adap->sge.ethtxq[i].q);
for_each_ofldrxq(&adap->sge, i)
- enable_txq_db(&adap->sge.ofldtxq[i].q);
+ enable_txq_db(adap, &adap->sge.ofldtxq[i].q);
for_each_port(adap, i)
- enable_txq_db(&adap->sge.ctrlq[i].q);
+ enable_txq_db(adap, &adap->sge.ctrlq[i].q);
+}
+
+static void notify_rdma_uld(struct adapter *adap, enum cxgb4_control cmd)
+{
+ if (adap->uld_handle[CXGB4_ULD_RDMA])
+ ulds[CXGB4_ULD_RDMA].control(adap->uld_handle[CXGB4_ULD_RDMA],
+ cmd);
+}
+
+static void process_db_full(struct work_struct *work)
+{
+ struct adapter *adap;
+
+ adap = container_of(work, struct adapter, db_full_task);
+
+ drain_db_fifo(adap, dbfifo_drain_delay);
+ enable_dbs(adap);
+ notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY);
+ t4_set_reg_field(adap, SGE_INT_ENABLE3,
+ DBFIFO_HP_INT | DBFIFO_LP_INT,
+ DBFIFO_HP_INT | DBFIFO_LP_INT);
}
static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q)
@@ -3604,7 +3663,7 @@ static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q)
u16 hw_pidx, hw_cidx;
int ret;
- spin_lock_bh(&q->db_lock);
+ spin_lock_irq(&q->db_lock);
ret = read_eq_indices(adap, (u16)q->cntxt_id, &hw_pidx, &hw_cidx);
if (ret)
goto out;
@@ -3621,7 +3680,8 @@ static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q)
}
out:
q->db_disabled = 0;
- spin_unlock_bh(&q->db_lock);
+ q->db_pidx_inc = 0;
+ spin_unlock_irq(&q->db_lock);
if (ret)
CH_WARN(adap, "DB drop recovery failed.\n");
}
@@ -3637,29 +3697,6 @@ static void recover_all_queues(struct adapter *adap)
sync_txq_pidx(adap, &adap->sge.ctrlq[i].q);
}
-static void notify_rdma_uld(struct adapter *adap, enum cxgb4_control cmd)
-{
- mutex_lock(&uld_mutex);
- if (adap->uld_handle[CXGB4_ULD_RDMA])
- ulds[CXGB4_ULD_RDMA].control(adap->uld_handle[CXGB4_ULD_RDMA],
- cmd);
- mutex_unlock(&uld_mutex);
-}
-
-static void process_db_full(struct work_struct *work)
-{
- struct adapter *adap;
-
- adap = container_of(work, struct adapter, db_full_task);
-
- notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL);
- drain_db_fifo(adap, dbfifo_drain_delay);
- t4_set_reg_field(adap, SGE_INT_ENABLE3,
- DBFIFO_HP_INT | DBFIFO_LP_INT,
- DBFIFO_HP_INT | DBFIFO_LP_INT);
- notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY);
-}
-
static void process_db_drop(struct work_struct *work)
{
struct adapter *adap;
@@ -3667,11 +3704,13 @@ static void process_db_drop(struct work_struct *work)
adap = container_of(work, struct adapter, db_drop_task);
if (is_t4(adap->params.chip)) {
- disable_dbs(adap);
+ drain_db_fifo(adap, dbfifo_drain_delay);
notify_rdma_uld(adap, CXGB4_CONTROL_DB_DROP);
- drain_db_fifo(adap, 1);
+ drain_db_fifo(adap, dbfifo_drain_delay);
recover_all_queues(adap);
+ drain_db_fifo(adap, dbfifo_drain_delay);
enable_dbs(adap);
+ notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY);
} else {
u32 dropped_db = t4_read_reg(adap, 0x010ac);
u16 qid = (dropped_db >> 15) & 0x1ffff;
@@ -3712,6 +3751,8 @@ static void process_db_drop(struct work_struct *work)
void t4_db_full(struct adapter *adap)
{
if (is_t4(adap->params.chip)) {
+ disable_dbs(adap);
+ notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL);
t4_set_reg_field(adap, SGE_INT_ENABLE3,
DBFIFO_HP_INT | DBFIFO_LP_INT, 0);
queue_work(workq, &adap->db_full_task);
@@ -3720,8 +3761,11 @@ void t4_db_full(struct adapter *adap)
void t4_db_dropped(struct adapter *adap)
{
- if (is_t4(adap->params.chip))
- queue_work(workq, &adap->db_drop_task);
+ if (is_t4(adap->params.chip)) {
+ disable_dbs(adap);
+ notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL);
+ }
+ queue_work(workq, &adap->db_drop_task);
}
static void uld_attach(struct adapter *adap, unsigned int uld)
@@ -3765,6 +3809,7 @@ static void uld_attach(struct adapter *adap, unsigned int uld)
lli.dbfifo_int_thresh = dbfifo_int_thresh;
lli.sge_pktshift = adap->sge.pktshift;
lli.enable_fw_ofld_conn = adap->flags & FW_OFLD_CONN;
+ lli.ulptx_memwrite_dsgl = adap->params.ulptx_memwrite_dsgl;
handle = ulds[uld].add(&lli);
if (IS_ERR(handle)) {
@@ -5370,6 +5415,21 @@ static int adap_init0(struct adapter *adap)
(void) t4_set_params(adap, adap->mbox, adap->fn, 0, 1, params, val);
/*
+ * Find out whether we're allowed to use the T5+ ULPTX MEMWRITE DSGL
+ * capability. Earlier versions of the firmware didn't have the
+ * ULPTX_MEMWRITE_DSGL so we'll interpret a query failure as no
+ * permission to use ULPTX MEMWRITE DSGL.
+ */
+ if (is_t4(adap->params.chip)) {
+ adap->params.ulptx_memwrite_dsgl = false;
+ } else {
+ params[0] = FW_PARAM_DEV(ULPTX_MEMWRITE_DSGL);
+ ret = t4_query_params(adap, adap->mbox, adap->fn, 0,
+ 1, params, val);
+ adap->params.ulptx_memwrite_dsgl = (ret == 0 && val[0] != 0);
+ }
+
+ /*
* Get device capabilities so we can determine what resources we need
* to manage.
*/
@@ -5603,9 +5663,10 @@ static const struct pci_error_handlers cxgb4_eeh = {
.resume = eeh_resume,
};
-static inline bool is_10g_port(const struct link_config *lc)
+static inline bool is_x_10g_port(const struct link_config *lc)
{
- return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0;
+ return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0 ||
+ (lc->supported & FW_PORT_CAP_SPEED_40G) != 0;
}
static inline void init_rspq(struct sge_rspq *q, u8 timer_idx, u8 pkt_cnt_idx,
@@ -5629,7 +5690,7 @@ static void cfg_queues(struct adapter *adap)
int i, q10g = 0, n10g = 0, qidx = 0;
for_each_port(adap, i)
- n10g += is_10g_port(&adap2pinfo(adap, i)->link_cfg);
+ n10g += is_x_10g_port(&adap2pinfo(adap, i)->link_cfg);
/*
* We default to 1 queue per non-10G port and up to # of cores queues
@@ -5644,7 +5705,7 @@ static void cfg_queues(struct adapter *adap)
struct port_info *pi = adap2pinfo(adap, i);
pi->first_qset = qidx;
- pi->nqsets = is_10g_port(&pi->link_cfg) ? q10g : 1;
+ pi->nqsets = is_x_10g_port(&pi->link_cfg) ? q10g : 1;
qidx += pi->nqsets;
}
@@ -5737,7 +5798,7 @@ static void reduce_ethqs(struct adapter *adap, int n)
static int enable_msix(struct adapter *adap)
{
int ofld_need = 0;
- int i, err, want, need;
+ int i, want, need;
struct sge *s = &adap->sge;
unsigned int nchan = adap->params.nports;
struct msix_entry entries[MAX_INGQ + 1];
@@ -5753,32 +5814,30 @@ static int enable_msix(struct adapter *adap)
}
need = adap->params.nports + EXTRA_VECS + ofld_need;
- while ((err = pci_enable_msix(adap->pdev, entries, want)) >= need)
- want = err;
+ want = pci_enable_msix_range(adap->pdev, entries, need, want);
+ if (want < 0)
+ return want;
- if (!err) {
- /*
- * Distribute available vectors to the various queue groups.
- * Every group gets its minimum requirement and NIC gets top
- * priority for leftovers.
- */
- i = want - EXTRA_VECS - ofld_need;
- if (i < s->max_ethqsets) {
- s->max_ethqsets = i;
- if (i < s->ethqsets)
- reduce_ethqs(adap, i);
- }
- if (is_offload(adap)) {
- i = want - EXTRA_VECS - s->max_ethqsets;
- i -= ofld_need - nchan;
- s->ofldqsets = (i / nchan) * nchan; /* round down */
- }
- for (i = 0; i < want; ++i)
- adap->msix_info[i].vec = entries[i].vector;
- } else if (err > 0)
- dev_info(adap->pdev_dev,
- "only %d MSI-X vectors left, not using MSI-X\n", err);
- return err;
+ /*
+ * Distribute available vectors to the various queue groups.
+ * Every group gets its minimum requirement and NIC gets top
+ * priority for leftovers.
+ */
+ i = want - EXTRA_VECS - ofld_need;
+ if (i < s->max_ethqsets) {
+ s->max_ethqsets = i;
+ if (i < s->ethqsets)
+ reduce_ethqs(adap, i);
+ }
+ if (is_offload(adap)) {
+ i = want - EXTRA_VECS - s->max_ethqsets;
+ i -= ofld_need - nchan;
+ s->ofldqsets = (i / nchan) * nchan; /* round down */
+ }
+ for (i = 0; i < want; ++i)
+ adap->msix_info[i].vec = entries[i].vector;
+
+ return 0;
}
#undef EXTRA_VECS
@@ -5801,11 +5860,6 @@ static int init_rss(struct adapter *adap)
static void print_port_info(const struct net_device *dev)
{
- static const char *base[] = {
- "R XFI", "R XAUI", "T SGMII", "T XFI", "T XAUI", "KX4", "CX4",
- "KX", "KR", "R SFP+", "KR/KX", "KR/KX/KX4"
- };
-
char buf[80];
char *bufp = buf;
const char *spd = "";
@@ -5823,9 +5877,11 @@ static void print_port_info(const struct net_device *dev)
bufp += sprintf(bufp, "1000/");
if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_10G)
bufp += sprintf(bufp, "10G/");
+ if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_40G)
+ bufp += sprintf(bufp, "40G/");
if (bufp != buf)
--bufp;
- sprintf(bufp, "BASE-%s", base[pi->port_type]);
+ sprintf(bufp, "BASE-%s", t4_get_port_type_description(pi->port_type));
netdev_info(dev, "Chelsio %s rev %d %s %sNIC PCIe x%d%s%s\n",
adap->params.vpd.id,
@@ -5833,8 +5889,8 @@ static void print_port_info(const struct net_device *dev)
is_offload(adap) ? "R" : "", adap->params.pci.width, spd,
(adap->flags & USING_MSIX) ? " MSI-X" :
(adap->flags & USING_MSI) ? " MSI" : "");
- netdev_info(dev, "S/N: %s, E/C: %s\n",
- adap->params.vpd.sn, adap->params.vpd.ec);
+ netdev_info(dev, "S/N: %s, P/N: %s\n",
+ adap->params.vpd.sn, adap->params.vpd.pn);
}
static void enable_pcie_relaxed_ordering(struct pci_dev *dev)
@@ -6179,6 +6235,7 @@ static struct pci_driver cxgb4_driver = {
.id_table = cxgb4_pci_tbl,
.probe = init_one,
.remove = remove_one,
+ .shutdown = remove_one,
.err_handler = &cxgb4_eeh,
};
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
index 4dd0a82533e4..e274a047528f 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
@@ -253,6 +253,7 @@ struct cxgb4_lld_info {
/* packet data */
bool enable_fw_ofld_conn; /* Enable connection through fw */
/* WR */
+ bool ulptx_memwrite_dsgl; /* use of T5 DSGL allowed */
};
struct cxgb4_uld_info {
diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c
index 47ffa64fcf19..ca95cf2954eb 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c
@@ -93,6 +93,16 @@
*/
#define TX_QCHECK_PERIOD (HZ / 2)
+/* SGE Hung Ingress DMA Threshold Warning time (in Hz) and Warning Repeat Rate
+ * (in RX_QCHECK_PERIOD multiples). If we find one of the SGE Ingress DMA
+ * State Machines in the same state for this amount of time (in HZ) then we'll
+ * issue a warning about a potential hang. We'll repeat the warning as the
+ * SGE Ingress DMA Channel appears to be hung every N RX_QCHECK_PERIODs till
+ * the situation clears. If the situation clears, we'll note that as well.
+ */
+#define SGE_IDMA_WARN_THRESH (1 * HZ)
+#define SGE_IDMA_WARN_REPEAT (20 * RX_QCHECK_PERIOD)
+
/*
* Max number of Tx descriptors to be reclaimed by the Tx timer.
*/
@@ -373,7 +383,7 @@ static void free_tx_desc(struct adapter *adap, struct sge_txq *q,
if (d->skb) { /* an SGL is present */
if (unmap)
unmap_sgl(dev, d->skb, d->sgl, q);
- kfree_skb(d->skb);
+ dev_consume_skb_any(d->skb);
d->skb = NULL;
}
++d;
@@ -706,11 +716,17 @@ static inline unsigned int flits_to_desc(unsigned int n)
* @skb: the packet
*
* Returns whether an Ethernet packet is small enough to fit as
- * immediate data.
+ * immediate data. Return value corresponds to headroom required.
*/
static inline int is_eth_imm(const struct sk_buff *skb)
{
- return skb->len <= MAX_IMM_TX_PKT_LEN - sizeof(struct cpl_tx_pkt);
+ int hdrlen = skb_shinfo(skb)->gso_size ?
+ sizeof(struct cpl_tx_pkt_lso_core) : 0;
+
+ hdrlen += sizeof(struct cpl_tx_pkt);
+ if (skb->len <= MAX_IMM_TX_PKT_LEN - hdrlen)
+ return hdrlen;
+ return 0;
}
/**
@@ -723,9 +739,10 @@ static inline int is_eth_imm(const struct sk_buff *skb)
static inline unsigned int calc_tx_flits(const struct sk_buff *skb)
{
unsigned int flits;
+ int hdrlen = is_eth_imm(skb);
- if (is_eth_imm(skb))
- return DIV_ROUND_UP(skb->len + sizeof(struct cpl_tx_pkt), 8);
+ if (hdrlen)
+ return DIV_ROUND_UP(skb->len + hdrlen, sizeof(__be64));
flits = sgl_len(skb_shinfo(skb)->nr_frags + 1) + 4;
if (skb_shinfo(skb)->gso_size)
@@ -843,9 +860,10 @@ static void cxgb_pio_copy(u64 __iomem *dst, u64 *src)
static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n)
{
unsigned int *wr, index;
+ unsigned long flags;
wmb(); /* write descriptors before telling HW */
- spin_lock(&q->db_lock);
+ spin_lock_irqsave(&q->db_lock, flags);
if (!q->db_disabled) {
if (is_t4(adap->params.chip)) {
t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL),
@@ -861,9 +879,10 @@ static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n)
writel(n, adap->bar2 + q->udb + 8);
wmb();
}
- }
+ } else
+ q->db_pidx_inc += n;
q->db_pidx = q->pidx;
- spin_unlock(&q->db_lock);
+ spin_unlock_irqrestore(&q->db_lock, flags);
}
/**
@@ -971,6 +990,7 @@ static inline void txq_advance(struct sge_txq *q, unsigned int n)
*/
netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev)
{
+ int len;
u32 wr_mid;
u64 cntrl, *end;
int qidx, credits;
@@ -982,13 +1002,14 @@ netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev)
struct cpl_tx_pkt_core *cpl;
const struct skb_shared_info *ssi;
dma_addr_t addr[MAX_SKB_FRAGS + 1];
+ bool immediate = false;
/*
* The chip min packet length is 10 octets but play safe and reject
* anything shorter than an Ethernet header.
*/
if (unlikely(skb->len < ETH_HLEN)) {
-out_free: dev_kfree_skb(skb);
+out_free: dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -1011,7 +1032,10 @@ out_free: dev_kfree_skb(skb);
return NETDEV_TX_BUSY;
}
- if (!is_eth_imm(skb) &&
+ if (is_eth_imm(skb))
+ immediate = true;
+
+ if (!immediate &&
unlikely(map_skb(adap->pdev_dev, skb, addr) < 0)) {
q->mapping_err++;
goto out_free;
@@ -1028,6 +1052,7 @@ out_free: dev_kfree_skb(skb);
wr->r3 = cpu_to_be64(0);
end = (u64 *)wr + flits;
+ len = immediate ? skb->len : 0;
ssi = skb_shinfo(skb);
if (ssi->gso_size) {
struct cpl_tx_pkt_lso *lso = (void *)wr;
@@ -1035,8 +1060,9 @@ out_free: dev_kfree_skb(skb);
int l3hdr_len = skb_network_header_len(skb);
int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN;
+ len += sizeof(*lso);
wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) |
- FW_WR_IMMDLEN(sizeof(*lso)));
+ FW_WR_IMMDLEN(len));
lso->c.lso_ctrl = htonl(LSO_OPCODE(CPL_TX_PKT_LSO) |
LSO_FIRST_SLICE | LSO_LAST_SLICE |
LSO_IPV6(v6) |
@@ -1054,9 +1080,7 @@ out_free: dev_kfree_skb(skb);
q->tso++;
q->tx_cso += ssi->gso_segs;
} else {
- int len;
-
- len = is_eth_imm(skb) ? skb->len + sizeof(*cpl) : sizeof(*cpl);
+ len += sizeof(*cpl);
wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) |
FW_WR_IMMDLEN(len));
cpl = (void *)(wr + 1);
@@ -1078,9 +1102,9 @@ out_free: dev_kfree_skb(skb);
cpl->len = htons(skb->len);
cpl->ctrl1 = cpu_to_be64(cntrl);
- if (is_eth_imm(skb)) {
+ if (immediate) {
inline_tx_skb(skb, &q->q, cpl + 1);
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
} else {
int last_desc;
@@ -1467,8 +1491,12 @@ static inline int ofld_send(struct adapter *adap, struct sk_buff *skb)
{
unsigned int idx = skb_txq(skb);
- if (unlikely(is_ctrl_pkt(skb)))
+ if (unlikely(is_ctrl_pkt(skb))) {
+ /* Single ctrl queue is a requirement for LE workaround path */
+ if (adap->tids.nsftids)
+ idx = 0;
return ctrl_xmit(&adap->sge.ctrlq[idx], skb);
+ }
return ofld_xmit(&adap->sge.ofldtxq[idx], skb);
}
@@ -1992,7 +2020,7 @@ irq_handler_t t4_intr_handler(struct adapter *adap)
static void sge_rx_timer_cb(unsigned long data)
{
unsigned long m;
- unsigned int i, cnt[2];
+ unsigned int i, idma_same_state_cnt[2];
struct adapter *adap = (struct adapter *)data;
struct sge *s = &adap->sge;
@@ -2015,21 +2043,64 @@ static void sge_rx_timer_cb(unsigned long data)
}
t4_write_reg(adap, SGE_DEBUG_INDEX, 13);
- cnt[0] = t4_read_reg(adap, SGE_DEBUG_DATA_HIGH);
- cnt[1] = t4_read_reg(adap, SGE_DEBUG_DATA_LOW);
-
- for (i = 0; i < 2; i++)
- if (cnt[i] >= s->starve_thres) {
- if (s->idma_state[i] || cnt[i] == 0xffffffff)
- continue;
- s->idma_state[i] = 1;
- t4_write_reg(adap, SGE_DEBUG_INDEX, 11);
- m = t4_read_reg(adap, SGE_DEBUG_DATA_LOW) >> (i * 16);
- dev_warn(adap->pdev_dev,
- "SGE idma%u starvation detected for "
- "queue %lu\n", i, m & 0xffff);
- } else if (s->idma_state[i])
- s->idma_state[i] = 0;
+ idma_same_state_cnt[0] = t4_read_reg(adap, SGE_DEBUG_DATA_HIGH);
+ idma_same_state_cnt[1] = t4_read_reg(adap, SGE_DEBUG_DATA_LOW);
+
+ for (i = 0; i < 2; i++) {
+ u32 debug0, debug11;
+
+ /* If the Ingress DMA Same State Counter ("timer") is less
+ * than 1s, then we can reset our synthesized Stall Timer and
+ * continue. If we have previously emitted warnings about a
+ * potential stalled Ingress Queue, issue a note indicating
+ * that the Ingress Queue has resumed forward progress.
+ */
+ if (idma_same_state_cnt[i] < s->idma_1s_thresh) {
+ if (s->idma_stalled[i] >= SGE_IDMA_WARN_THRESH)
+ CH_WARN(adap, "SGE idma%d, queue%u,resumed after %d sec\n",
+ i, s->idma_qid[i],
+ s->idma_stalled[i]/HZ);
+ s->idma_stalled[i] = 0;
+ continue;
+ }
+
+ /* Synthesize an SGE Ingress DMA Same State Timer in the Hz
+ * domain. The first time we get here it'll be because we
+ * passed the 1s Threshold; each additional time it'll be
+ * because the RX Timer Callback is being fired on its regular
+ * schedule.
+ *
+ * If the stall is below our Potential Hung Ingress Queue
+ * Warning Threshold, continue.
+ */
+ if (s->idma_stalled[i] == 0)
+ s->idma_stalled[i] = HZ;
+ else
+ s->idma_stalled[i] += RX_QCHECK_PERIOD;
+
+ if (s->idma_stalled[i] < SGE_IDMA_WARN_THRESH)
+ continue;
+
+ /* We'll issue a warning every SGE_IDMA_WARN_REPEAT Hz */
+ if (((s->idma_stalled[i] - HZ) % SGE_IDMA_WARN_REPEAT) != 0)
+ continue;
+
+ /* Read and save the SGE IDMA State and Queue ID information.
+ * We do this every time in case it changes across time ...
+ */
+ t4_write_reg(adap, SGE_DEBUG_INDEX, 0);
+ debug0 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW);
+ s->idma_state[i] = (debug0 >> (i * 9)) & 0x3f;
+
+ t4_write_reg(adap, SGE_DEBUG_INDEX, 11);
+ debug11 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW);
+ s->idma_qid[i] = (debug11 >> (i * 16)) & 0xffff;
+
+ CH_WARN(adap, "SGE idma%u, queue%u, maybe stuck state%u %dsecs (debug0=%#x, debug11=%#x)\n",
+ i, s->idma_qid[i], s->idma_state[i],
+ s->idma_stalled[i]/HZ, debug0, debug11);
+ t4_sge_decode_idma_state(adap, s->idma_state[i]);
+ }
mod_timer(&s->rx_timer, jiffies + RX_QCHECK_PERIOD);
}
@@ -2580,11 +2651,19 @@ static int t4_sge_init_soft(struct adapter *adap)
fl_small_mtu = READ_FL_BUF(RX_SMALL_MTU_BUF);
fl_large_mtu = READ_FL_BUF(RX_LARGE_MTU_BUF);
+ /* We only bother using the Large Page logic if the Large Page Buffer
+ * is larger than our Page Size Buffer.
+ */
+ if (fl_large_pg <= fl_small_pg)
+ fl_large_pg = 0;
+
#undef READ_FL_BUF
+ /* The Page Size Buffer must be exactly equal to our Page Size and the
+ * Large Page Size Buffer should be 0 (per above) or a power of 2.
+ */
if (fl_small_pg != PAGE_SIZE ||
- (fl_large_pg != 0 && (fl_large_pg < fl_small_pg ||
- (fl_large_pg & (fl_large_pg-1)) != 0))) {
+ (fl_large_pg & (fl_large_pg-1)) != 0) {
dev_err(adap->pdev_dev, "bad SGE FL page buffer sizes [%d, %d]\n",
fl_small_pg, fl_large_pg);
return -EINVAL;
@@ -2699,8 +2778,8 @@ static int t4_sge_init_hard(struct adapter *adap)
int t4_sge_init(struct adapter *adap)
{
struct sge *s = &adap->sge;
- u32 sge_control;
- int ret;
+ u32 sge_control, sge_conm_ctrl;
+ int ret, egress_threshold;
/*
* Ingress Padding Boundary and Egress Status Page Size are set up by
@@ -2725,15 +2804,24 @@ int t4_sge_init(struct adapter *adap)
* SGE's Egress Congestion Threshold. If it isn't, then we can get
* stuck waiting for new packets while the SGE is waiting for us to
* give it more Free List entries. (Note that the SGE's Egress
- * Congestion Threshold is in units of 2 Free List pointers.)
+ * Congestion Threshold is in units of 2 Free List pointers.) For T4,
+ * there was only a single field to control this. For T5 there's the
+ * original field which now only applies to Unpacked Mode Free List
+ * buffers and a new field which only applies to Packed Mode Free List
+ * buffers.
*/
- s->fl_starve_thres
- = EGRTHRESHOLD_GET(t4_read_reg(adap, SGE_CONM_CTRL))*2 + 1;
+ sge_conm_ctrl = t4_read_reg(adap, SGE_CONM_CTRL);
+ if (is_t4(adap->params.chip))
+ egress_threshold = EGRTHRESHOLD_GET(sge_conm_ctrl);
+ else
+ egress_threshold = EGRTHRESHOLDPACKING_GET(sge_conm_ctrl);
+ s->fl_starve_thres = 2*egress_threshold + 1;
setup_timer(&s->rx_timer, sge_rx_timer_cb, (unsigned long)adap);
setup_timer(&s->tx_timer, sge_tx_timer_cb, (unsigned long)adap);
- s->starve_thres = core_ticks_per_usec(adap) * 1000000; /* 1 s */
- s->idma_state[0] = s->idma_state[1] = 0;
+ s->idma_1s_thresh = core_ticks_per_usec(adap) * 1000000; /* 1 s */
+ s->idma_stalled[0] = 0;
+ s->idma_stalled[1] = 0;
spin_lock_init(&s->intrq_lock);
return 0;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index 2c109343d570..fb2fe65903c2 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -573,7 +573,7 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
{
u32 cclk_param, cclk_val;
int i, ret, addr;
- int ec, sn;
+ int ec, sn, pn;
u8 *vpd, csum;
unsigned int vpdr_len, kw_offset, id_len;
@@ -638,6 +638,7 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
FIND_VPD_KW(ec, "EC");
FIND_VPD_KW(sn, "SN");
+ FIND_VPD_KW(pn, "PN");
#undef FIND_VPD_KW
memcpy(p->id, vpd + PCI_VPD_LRDT_TAG_SIZE, id_len);
@@ -647,6 +648,8 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
i = pci_vpd_info_field_size(vpd + sn - PCI_VPD_INFO_FLD_HDR_SIZE);
memcpy(p->sn, vpd + sn, min(i, SERNUM_LEN));
strim(p->sn);
+ memcpy(p->pn, vpd + pn, min(i, PN_LEN));
+ strim(p->pn);
/*
* Ask firmware for the Core Clock since it knows how to translate the
@@ -1155,7 +1158,8 @@ out:
}
#define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\
- FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_ANEG)
+ FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G | \
+ FW_PORT_CAP_ANEG)
/**
* t4_link_start - apply link configuration to MAC/PHY
@@ -2247,6 +2251,36 @@ static unsigned int get_mps_bg_map(struct adapter *adap, int idx)
}
/**
+ * t4_get_port_type_description - return Port Type string description
+ * @port_type: firmware Port Type enumeration
+ */
+const char *t4_get_port_type_description(enum fw_port_type port_type)
+{
+ static const char *const port_type_description[] = {
+ "R XFI",
+ "R XAUI",
+ "T SGMII",
+ "T XFI",
+ "T XAUI",
+ "KX4",
+ "CX4",
+ "KX",
+ "KR",
+ "R SFP+",
+ "KR/KX",
+ "KR/KX/KX4",
+ "R QSFP_10G",
+ "",
+ "R QSFP",
+ "R BP40_BA",
+ };
+
+ if (port_type < ARRAY_SIZE(port_type_description))
+ return port_type_description[port_type];
+ return "UNKNOWN";
+}
+
+/**
* t4_get_port_stats - collect port statistics
* @adap: the adapter
* @idx: the port index
@@ -2563,6 +2597,112 @@ int t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
}
/**
+ * t4_sge_decode_idma_state - decode the idma state
+ * @adap: the adapter
+ * @state: the state idma is stuck in
+ */
+void t4_sge_decode_idma_state(struct adapter *adapter, int state)
+{
+ static const char * const t4_decode[] = {
+ "IDMA_IDLE",
+ "IDMA_PUSH_MORE_CPL_FIFO",
+ "IDMA_PUSH_CPL_MSG_HEADER_TO_FIFO",
+ "Not used",
+ "IDMA_PHYSADDR_SEND_PCIEHDR",
+ "IDMA_PHYSADDR_SEND_PAYLOAD_FIRST",
+ "IDMA_PHYSADDR_SEND_PAYLOAD",
+ "IDMA_SEND_FIFO_TO_IMSG",
+ "IDMA_FL_REQ_DATA_FL_PREP",
+ "IDMA_FL_REQ_DATA_FL",
+ "IDMA_FL_DROP",
+ "IDMA_FL_H_REQ_HEADER_FL",
+ "IDMA_FL_H_SEND_PCIEHDR",
+ "IDMA_FL_H_PUSH_CPL_FIFO",
+ "IDMA_FL_H_SEND_CPL",
+ "IDMA_FL_H_SEND_IP_HDR_FIRST",
+ "IDMA_FL_H_SEND_IP_HDR",
+ "IDMA_FL_H_REQ_NEXT_HEADER_FL",
+ "IDMA_FL_H_SEND_NEXT_PCIEHDR",
+ "IDMA_FL_H_SEND_IP_HDR_PADDING",
+ "IDMA_FL_D_SEND_PCIEHDR",
+ "IDMA_FL_D_SEND_CPL_AND_IP_HDR",
+ "IDMA_FL_D_REQ_NEXT_DATA_FL",
+ "IDMA_FL_SEND_PCIEHDR",
+ "IDMA_FL_PUSH_CPL_FIFO",
+ "IDMA_FL_SEND_CPL",
+ "IDMA_FL_SEND_PAYLOAD_FIRST",
+ "IDMA_FL_SEND_PAYLOAD",
+ "IDMA_FL_REQ_NEXT_DATA_FL",
+ "IDMA_FL_SEND_NEXT_PCIEHDR",
+ "IDMA_FL_SEND_PADDING",
+ "IDMA_FL_SEND_COMPLETION_TO_IMSG",
+ "IDMA_FL_SEND_FIFO_TO_IMSG",
+ "IDMA_FL_REQ_DATAFL_DONE",
+ "IDMA_FL_REQ_HEADERFL_DONE",
+ };
+ static const char * const t5_decode[] = {
+ "IDMA_IDLE",
+ "IDMA_ALMOST_IDLE",
+ "IDMA_PUSH_MORE_CPL_FIFO",
+ "IDMA_PUSH_CPL_MSG_HEADER_TO_FIFO",
+ "IDMA_SGEFLRFLUSH_SEND_PCIEHDR",
+ "IDMA_PHYSADDR_SEND_PCIEHDR",
+ "IDMA_PHYSADDR_SEND_PAYLOAD_FIRST",
+ "IDMA_PHYSADDR_SEND_PAYLOAD",
+ "IDMA_SEND_FIFO_TO_IMSG",
+ "IDMA_FL_REQ_DATA_FL",
+ "IDMA_FL_DROP",
+ "IDMA_FL_DROP_SEND_INC",
+ "IDMA_FL_H_REQ_HEADER_FL",
+ "IDMA_FL_H_SEND_PCIEHDR",
+ "IDMA_FL_H_PUSH_CPL_FIFO",
+ "IDMA_FL_H_SEND_CPL",
+ "IDMA_FL_H_SEND_IP_HDR_FIRST",
+ "IDMA_FL_H_SEND_IP_HDR",
+ "IDMA_FL_H_REQ_NEXT_HEADER_FL",
+ "IDMA_FL_H_SEND_NEXT_PCIEHDR",
+ "IDMA_FL_H_SEND_IP_HDR_PADDING",
+ "IDMA_FL_D_SEND_PCIEHDR",
+ "IDMA_FL_D_SEND_CPL_AND_IP_HDR",
+ "IDMA_FL_D_REQ_NEXT_DATA_FL",
+ "IDMA_FL_SEND_PCIEHDR",
+ "IDMA_FL_PUSH_CPL_FIFO",
+ "IDMA_FL_SEND_CPL",
+ "IDMA_FL_SEND_PAYLOAD_FIRST",
+ "IDMA_FL_SEND_PAYLOAD",
+ "IDMA_FL_REQ_NEXT_DATA_FL",
+ "IDMA_FL_SEND_NEXT_PCIEHDR",
+ "IDMA_FL_SEND_PADDING",
+ "IDMA_FL_SEND_COMPLETION_TO_IMSG",
+ };
+ static const u32 sge_regs[] = {
+ SGE_DEBUG_DATA_LOW_INDEX_2,
+ SGE_DEBUG_DATA_LOW_INDEX_3,
+ SGE_DEBUG_DATA_HIGH_INDEX_10,
+ };
+ const char **sge_idma_decode;
+ int sge_idma_decode_nstates;
+ int i;
+
+ if (is_t4(adapter->params.chip)) {
+ sge_idma_decode = (const char **)t4_decode;
+ sge_idma_decode_nstates = ARRAY_SIZE(t4_decode);
+ } else {
+ sge_idma_decode = (const char **)t5_decode;
+ sge_idma_decode_nstates = ARRAY_SIZE(t5_decode);
+ }
+
+ if (state < sge_idma_decode_nstates)
+ CH_WARN(adapter, "idma state %s\n", sge_idma_decode[state]);
+ else
+ CH_WARN(adapter, "idma state %d unknown\n", state);
+
+ for (i = 0; i < ARRAY_SIZE(sge_regs); i++)
+ CH_WARN(adapter, "SGE register %#x value %#x\n",
+ sge_regs[i], t4_read_reg(adapter, sge_regs[i]));
+}
+
+/**
* t4_fw_hello - establish communication with FW
* @adap: the adapter
* @mbox: mailbox to use for the FW command
@@ -3533,11 +3673,13 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl)
if (stat & FW_PORT_CMD_TXPAUSE)
fc |= PAUSE_TX;
if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M))
- speed = SPEED_100;
+ speed = 100;
else if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G))
- speed = SPEED_1000;
+ speed = 1000;
else if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G))
- speed = SPEED_10000;
+ speed = 10000;
+ else if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_40G))
+ speed = 40000;
if (link_ok != lc->link_ok || speed != lc->speed ||
fc != lc->fc) { /* something changed */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
index cd6874b571ee..f2738c710789 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
@@ -116,6 +116,7 @@ enum CPL_error {
CPL_ERR_KEEPALIVE_TIMEDOUT = 34,
CPL_ERR_RTX_NEG_ADVICE = 35,
CPL_ERR_PERSIST_NEG_ADVICE = 36,
+ CPL_ERR_KEEPALV_NEG_ADVICE = 37,
CPL_ERR_ABORT_FAILED = 42,
CPL_ERR_IWARP_FLM = 50,
};
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
index 4082522d8140..225ad8a5722d 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
@@ -230,6 +230,12 @@
#define EGRTHRESHOLD(x) ((x) << EGRTHRESHOLDshift)
#define EGRTHRESHOLD_GET(x) (((x) & EGRTHRESHOLD_MASK) >> EGRTHRESHOLDshift)
+#define EGRTHRESHOLDPACKING_MASK 0x3fU
+#define EGRTHRESHOLDPACKING_SHIFT 14
+#define EGRTHRESHOLDPACKING(x) ((x) << EGRTHRESHOLDPACKING_SHIFT)
+#define EGRTHRESHOLDPACKING_GET(x) (((x) >> EGRTHRESHOLDPACKING_SHIFT) & \
+ EGRTHRESHOLDPACKING_MASK)
+
#define SGE_DBFIFO_STATUS 0x10a4
#define HP_INT_THRESH_SHIFT 28
#define HP_INT_THRESH_MASK 0xfU
@@ -278,6 +284,9 @@
#define SGE_DEBUG_INDEX 0x10cc
#define SGE_DEBUG_DATA_HIGH 0x10d0
#define SGE_DEBUG_DATA_LOW 0x10d4
+#define SGE_DEBUG_DATA_LOW_INDEX_2 0x12c8
+#define SGE_DEBUG_DATA_LOW_INDEX_3 0x12cc
+#define SGE_DEBUG_DATA_HIGH_INDEX_10 0x12a8
#define SGE_INGRESS_QUEUES_PER_PAGE_PF 0x10f4
#define S_HP_INT_THRESH 28
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
index 74fea74ce0aa..9cc973fbcf26 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
@@ -932,6 +932,7 @@ enum fw_params_param_dev {
FW_PARAMS_PARAM_DEV_FWREV = 0x0B,
FW_PARAMS_PARAM_DEV_TPREV = 0x0C,
FW_PARAMS_PARAM_DEV_CF = 0x0D,
+ FW_PARAMS_PARAM_DEV_ULPTX_MEMWRITE_DSGL = 0x17,
};
/*
@@ -1742,6 +1743,9 @@ enum fw_port_type {
FW_PORT_TYPE_SFP,
FW_PORT_TYPE_BP_AP,
FW_PORT_TYPE_BP4_AP,
+ FW_PORT_TYPE_QSFP_10G,
+ FW_PORT_TYPE_QSFP,
+ FW_PORT_TYPE_BP40_BA,
FW_PORT_TYPE_NONE = FW_PORT_CMD_PTYPE_MASK
};
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
index 0899c0983594..52859288de7b 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
@@ -2444,7 +2444,7 @@ static void reduce_ethqs(struct adapter *adapter, int n)
*/
static int enable_msix(struct adapter *adapter)
{
- int i, err, want, need;
+ int i, want, need, nqsets;
struct msix_entry entries[MSIX_ENTRIES];
struct sge *s = &adapter->sge;
@@ -2460,26 +2460,23 @@ static int enable_msix(struct adapter *adapter)
*/
want = s->max_ethqsets + MSIX_EXTRAS;
need = adapter->params.nports + MSIX_EXTRAS;
- while ((err = pci_enable_msix(adapter->pdev, entries, want)) >= need)
- want = err;
- if (err == 0) {
- int nqsets = want - MSIX_EXTRAS;
- if (nqsets < s->max_ethqsets) {
- dev_warn(adapter->pdev_dev, "only enough MSI-X vectors"
- " for %d Queue Sets\n", nqsets);
- s->max_ethqsets = nqsets;
- if (nqsets < s->ethqsets)
- reduce_ethqs(adapter, nqsets);
- }
- for (i = 0; i < want; ++i)
- adapter->msix_info[i].vec = entries[i].vector;
- } else if (err > 0) {
- pci_disable_msix(adapter->pdev);
- dev_info(adapter->pdev_dev, "only %d MSI-X vectors left,"
- " not using MSI-X\n", err);
+ want = pci_enable_msix_range(adapter->pdev, entries, need, want);
+ if (want < 0)
+ return want;
+
+ nqsets = want - MSIX_EXTRAS;
+ if (nqsets < s->max_ethqsets) {
+ dev_warn(adapter->pdev_dev, "only enough MSI-X vectors"
+ " for %d Queue Sets\n", nqsets);
+ s->max_ethqsets = nqsets;
+ if (nqsets < s->ethqsets)
+ reduce_ethqs(adapter, nqsets);
}
- return err;
+ for (i = 0; i < want; ++i)
+ adapter->msix_info[i].vec = entries[i].vector;
+
+ return 0;
}
static const struct net_device_ops cxgb4vf_netdev_ops = {
@@ -2947,6 +2944,14 @@ static DEFINE_PCI_DEVICE_TABLE(cxgb4vf_pci_tbl) = {
CH_DEVICE(0x5811, 0), /* T520-lp-cr */
CH_DEVICE(0x5812, 0), /* T560-cr */
CH_DEVICE(0x5813, 0), /* T580-cr */
+ CH_DEVICE(0x5814, 0), /* T580-so-cr */
+ CH_DEVICE(0x5815, 0), /* T502-bt */
+ CH_DEVICE(0x5880, 0),
+ CH_DEVICE(0x5881, 0),
+ CH_DEVICE(0x5882, 0),
+ CH_DEVICE(0x5883, 0),
+ CH_DEVICE(0x5884, 0),
+ CH_DEVICE(0x5885, 0),
{ 0, }
};
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
index 0a89963c48ce..9cfa4b4bb089 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
@@ -401,7 +401,7 @@ static void free_tx_desc(struct adapter *adapter, struct sge_txq *tq,
if (sdesc->skb) {
if (need_unmap)
unmap_sgl(dev, sdesc->skb, sdesc->sgl, tq);
- kfree_skb(sdesc->skb);
+ dev_consume_skb_any(sdesc->skb);
sdesc->skb = NULL;
}
@@ -1275,7 +1275,7 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
* need it any longer.
*/
inline_tx_skb(skb, &txq->q, cpl + 1);
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
} else {
/*
* Write the skb's Scatter/Gather list into the TX Packet CPL
@@ -1354,7 +1354,7 @@ out_free:
* An error of some sort happened. Free the TX skb and tell the
* OS that we've "dealt" with the packet ...
*/
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c
index 19f642a45f40..fe84fbabc0d4 100644
--- a/drivers/net/ethernet/cirrus/cs89x0.c
+++ b/drivers/net/ethernet/cirrus/cs89x0.c
@@ -1174,7 +1174,7 @@ static netdev_tx_t net_send_packet(struct sk_buff *skb, struct net_device *dev)
writewords(lp, TX_FRAME_PORT, skb->data, (skb->len + 1) >> 1);
spin_unlock_irqrestore(&lp->lock, flags);
dev->stats.tx_bytes += skb->len;
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
/* We DO NOT call netif_wake_queue() here.
* We also DO NOT call netif_start_queue().
diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c
index b740bfce72ef..2945718ce806 100644
--- a/drivers/net/ethernet/cisco/enic/enic_main.c
+++ b/drivers/net/ethernet/cisco/enic/enic_main.c
@@ -521,7 +521,7 @@ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb,
unsigned int txq_map;
if (skb->len <= 0) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -536,7 +536,7 @@ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb,
if (skb_shinfo(skb)->gso_size == 0 &&
skb_shinfo(skb)->nr_frags + 1 > ENIC_NON_TSO_MAX_DESC &&
skb_linearize(skb)) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -1086,14 +1086,15 @@ static int enic_poll(struct napi_struct *napi, int budget)
unsigned int intr = enic_legacy_io_intr();
unsigned int rq_work_to_do = budget;
unsigned int wq_work_to_do = -1; /* no limit */
- unsigned int work_done, rq_work_done, wq_work_done;
+ unsigned int work_done, rq_work_done = 0, wq_work_done;
int err;
/* Service RQ (first) and WQ
*/
- rq_work_done = vnic_cq_service(&enic->cq[cq_rq],
- rq_work_to_do, enic_rq_service, NULL);
+ if (budget > 0)
+ rq_work_done = vnic_cq_service(&enic->cq[cq_rq],
+ rq_work_to_do, enic_rq_service, NULL);
wq_work_done = vnic_cq_service(&enic->cq[cq_wq],
wq_work_to_do, enic_wq_service, NULL);
@@ -1141,14 +1142,15 @@ static int enic_poll_msix(struct napi_struct *napi, int budget)
unsigned int cq = enic_cq_rq(enic, rq);
unsigned int intr = enic_msix_rq_intr(enic, rq);
unsigned int work_to_do = budget;
- unsigned int work_done;
+ unsigned int work_done = 0;
int err;
/* Service RQ
*/
- work_done = vnic_cq_service(&enic->cq[cq],
- work_to_do, enic_rq_service, NULL);
+ if (budget > 0)
+ work_done = vnic_cq_service(&enic->cq[cq],
+ work_to_do, enic_rq_service, NULL);
/* Return intr event credits for this polling
* cycle. An intr event is the completion of a
@@ -1796,7 +1798,8 @@ static int enic_set_intr_mode(struct enic *enic)
enic->cq_count >= n + m &&
enic->intr_count >= n + m + 2) {
- if (!pci_enable_msix(enic->pdev, enic->msix_entry, n + m + 2)) {
+ if (pci_enable_msix_range(enic->pdev, enic->msix_entry,
+ n + m + 2, n + m + 2) > 0) {
enic->rq_count = n;
enic->wq_count = m;
@@ -1815,7 +1818,8 @@ static int enic_set_intr_mode(struct enic *enic)
enic->wq_count >= m &&
enic->cq_count >= 1 + m &&
enic->intr_count >= 1 + m + 2) {
- if (!pci_enable_msix(enic->pdev, enic->msix_entry, 1 + m + 2)) {
+ if (pci_enable_msix_range(enic->pdev, enic->msix_entry,
+ 1 + m + 2, 1 + m + 2) > 0) {
enic->rq_count = 1;
enic->wq_count = m;
diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c
index a1a2b4028a5c..8c4b93be333b 100644
--- a/drivers/net/ethernet/davicom/dm9000.c
+++ b/drivers/net/ethernet/davicom/dm9000.c
@@ -1033,7 +1033,7 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&db->lock, flags);
/* free this SKB */
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/dec/tulip/dmfe.c b/drivers/net/ethernet/dec/tulip/dmfe.c
index 5ad9e3e3c0b8..53f0c618045c 100644
--- a/drivers/net/ethernet/dec/tulip/dmfe.c
+++ b/drivers/net/ethernet/dec/tulip/dmfe.c
@@ -696,7 +696,7 @@ static netdev_tx_t dmfe_start_xmit(struct sk_buff *skb,
/* Too large packet check */
if (skb->len > MAX_PACKET_SIZE) {
pr_err("big packet = %d\n", (u16)skb->len);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -743,7 +743,7 @@ static netdev_tx_t dmfe_start_xmit(struct sk_buff *skb,
dw32(DCR7, db->cr7_data);
/* free this SKB */
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/dec/tulip/tulip_core.c b/drivers/net/ethernet/dec/tulip/tulip_core.c
index add05f14b38b..1642de78aac8 100644
--- a/drivers/net/ethernet/dec/tulip/tulip_core.c
+++ b/drivers/net/ethernet/dec/tulip/tulip_core.c
@@ -1939,6 +1939,7 @@ static void tulip_remove_one(struct pci_dev *pdev)
pci_iounmap(pdev, tp->base_addr);
free_netdev (dev);
pci_release_regions (pdev);
+ pci_disable_device(pdev);
/* pci_power_off (pdev, -1); */
}
diff --git a/drivers/net/ethernet/dec/tulip/uli526x.c b/drivers/net/ethernet/dec/tulip/uli526x.c
index aa4ee385091f..aa801a6af7b9 100644
--- a/drivers/net/ethernet/dec/tulip/uli526x.c
+++ b/drivers/net/ethernet/dec/tulip/uli526x.c
@@ -607,7 +607,7 @@ static netdev_tx_t uli526x_start_xmit(struct sk_buff *skb,
/* Too large packet check */
if (skb->len > MAX_PACKET_SIZE) {
netdev_err(dev, "big packet = %d\n", (u16)skb->len);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -648,7 +648,7 @@ static netdev_tx_t uli526x_start_xmit(struct sk_buff *skb,
uw32(DCR7, db->cr7_data);
/* free this SKB */
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/dlink/sundance.c b/drivers/net/ethernet/dlink/sundance.c
index 113cd799a131..d9e5ca0d48c1 100644
--- a/drivers/net/ethernet/dlink/sundance.c
+++ b/drivers/net/ethernet/dlink/sundance.c
@@ -1137,7 +1137,7 @@ start_tx (struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
drop_frame:
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
np->tx_skbuff[entry] = NULL;
dev->stats.tx_dropped++;
return NETDEV_TX_OK;
diff --git a/drivers/net/ethernet/dnet.c b/drivers/net/ethernet/dnet.c
index 8a79a32a5674..e9b0faba3078 100644
--- a/drivers/net/ethernet/dnet.c
+++ b/drivers/net/ethernet/dnet.c
@@ -170,11 +170,6 @@ static int dnet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
return 0;
}
-static int dnet_mdio_reset(struct mii_bus *bus)
-{
- return 0;
-}
-
static void dnet_handle_link_change(struct net_device *dev)
{
struct dnet *bp = netdev_priv(dev);
@@ -322,7 +317,6 @@ static int dnet_mii_init(struct dnet *bp)
bp->mii_bus->name = "dnet_mii_bus";
bp->mii_bus->read = &dnet_mdio_read;
bp->mii_bus->write = &dnet_mdio_write;
- bp->mii_bus->reset = &dnet_mdio_reset;
snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
bp->pdev->name, bp->pdev->id);
diff --git a/drivers/net/ethernet/emulex/benet/Kconfig b/drivers/net/ethernet/emulex/benet/Kconfig
index 231129dd1764..ea94a8eb6b35 100644
--- a/drivers/net/ethernet/emulex/benet/Kconfig
+++ b/drivers/net/ethernet/emulex/benet/Kconfig
@@ -4,3 +4,11 @@ config BE2NET
---help---
This driver implements the NIC functionality for ServerEngines'
10Gbps network adapter - BladeEngine.
+
+config BE2NET_VXLAN
+ bool "VXLAN offload support on be2net driver"
+ default y
+ depends on BE2NET && VXLAN && !(BE2NET=y && VXLAN=m)
+ ---help---
+ Say Y here if you want to enable VXLAN offload support on
+ be2net driver.
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index 8d09615da585..8ccaa2520dc3 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2013 Emulex
+ * Copyright (C) 2005 - 2014 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -34,7 +34,7 @@
#include "be_hw.h"
#include "be_roce.h"
-#define DRV_VER "10.0.600.0u"
+#define DRV_VER "10.2u"
#define DRV_NAME "be2net"
#define BE_NAME "Emulex BladeEngine2"
#define BE3_NAME "Emulex BladeEngine3"
@@ -88,7 +88,6 @@ static inline char *nic_name(struct pci_dev *pdev)
#define BE_MIN_MTU 256
#define BE_NUM_VLANS_SUPPORTED 64
-#define BE_UMC_NUM_VLANS_SUPPORTED 15
#define BE_MAX_EQD 128u
#define BE_MAX_TX_FRAG_COUNT 30
@@ -262,9 +261,10 @@ struct be_tx_obj {
/* Struct to remember the pages posted for rx frags */
struct be_rx_page_info {
struct page *page;
+ /* set to page-addr for last frag of the page & frag-addr otherwise */
DEFINE_DMA_UNMAP_ADDR(bus);
u16 page_offset;
- bool last_page_user;
+ bool last_frag; /* last frag of the page */
};
struct be_rx_stats {
@@ -293,9 +293,10 @@ struct be_rx_compl_info {
u8 ip_csum;
u8 l4_csum;
u8 ipv6;
- u8 vtm;
+ u8 qnq;
u8 pkt_type;
u8 ip_frag;
+ u8 tunneled;
};
struct be_rx_obj {
@@ -350,13 +351,16 @@ struct be_drv_stats {
u32 roce_drops_crc;
};
+/* A vlan-id of 0xFFFF must be used to clear transparent vlan-tagging */
+#define BE_RESET_VLAN_TAG_ID 0xFFFF
+
struct be_vf_cfg {
unsigned char mac_addr[ETH_ALEN];
int if_handle;
int pmac_id;
- u16 def_vid;
u16 vlan_tag;
u32 tx_rate;
+ u32 plink_tracking;
};
enum vf_state {
@@ -368,10 +372,11 @@ enum vf_state {
#define BE_FLAGS_WORKER_SCHEDULED (1 << 3)
#define BE_FLAGS_VLAN_PROMISC (1 << 4)
#define BE_FLAGS_NAPI_ENABLED (1 << 9)
-#define BE_UC_PMAC_COUNT 30
-#define BE_VF_UC_PMAC_COUNT 2
#define BE_FLAGS_QNQ_ASYNC_EVT_RCVD (1 << 11)
+#define BE_FLAGS_VXLAN_OFFLOADS (1 << 12)
+#define BE_UC_PMAC_COUNT 30
+#define BE_VF_UC_PMAC_COUNT 2
/* Ethtool set_dump flags */
#define LANCER_INITIATE_FW_DUMP 0x1
@@ -465,6 +470,7 @@ struct be_adapter {
u32 port_num;
bool promiscuous;
+ u8 mc_type;
u32 function_mode;
u32 function_caps;
u32 rx_fc; /* Rx flow control */
@@ -490,6 +496,7 @@ struct be_adapter {
u32 sli_family;
u8 hba_port_num;
u16 pvid;
+ __be16 vxlan_port;
struct phy_info phy;
u8 wol_cap;
bool wol_en;
@@ -534,6 +541,14 @@ static inline u16 be_max_qs(struct be_adapter *adapter)
return min_t(u16, num, num_online_cpus());
}
+/* Is BE in pvid_tagging mode */
+#define be_pvid_tagging_enabled(adapter) (adapter->pvid)
+
+/* Is BE in QNQ multi-channel mode */
+#define be_is_qnq_mode(adapter) (adapter->mc_type == FLEX10 || \
+ adapter->mc_type == vNIC1 || \
+ adapter->mc_type == UFP)
+
#define lancer_chip(adapter) (adapter->pdev->device == OC_DEVICE_ID3 || \
adapter->pdev->device == OC_DEVICE_ID4)
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index 48076a6370c3..d1ec15af0d24 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2013 Emulex
+ * Copyright (C) 2005 - 2014 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -202,8 +202,12 @@ static void be_async_link_state_process(struct be_adapter *adapter,
/* When link status changes, link speed must be re-queried from FW */
adapter->phy.link_speed = -1;
- /* Ignore physical link event */
- if (lancer_chip(adapter) &&
+ /* On BEx the FW does not send a separate link status
+ * notification for physical and logical link.
+ * On other chips just process the logical link
+ * status notification
+ */
+ if (!BEx_chip(adapter) &&
!(evt->port_link_status & LOGICAL_LINK_STATUS_MASK))
return;
@@ -211,7 +215,8 @@ static void be_async_link_state_process(struct be_adapter *adapter,
* it may not be received in some cases.
*/
if (adapter->flags & BE_FLAGS_LINK_STATUS_INIT)
- be_link_status_update(adapter, evt->port_link_status);
+ be_link_status_update(adapter,
+ evt->port_link_status & LINK_STATUS_MASK);
}
/* Grp5 CoS Priority evt */
@@ -239,10 +244,12 @@ static void be_async_grp5_qos_speed_process(struct be_adapter *adapter,
static void be_async_grp5_pvid_state_process(struct be_adapter *adapter,
struct be_async_event_grp5_pvid_state *evt)
{
- if (evt->enabled)
+ if (evt->enabled) {
adapter->pvid = le16_to_cpu(evt->tag) & VLAN_VID_MASK;
- else
+ dev_info(&adapter->pdev->dev, "LPVID: %d\n", adapter->pvid);
+ } else {
adapter->pvid = 0;
+ }
}
static void be_async_grp5_evt_process(struct be_adapter *adapter,
@@ -3296,6 +3303,21 @@ static struct be_pcie_res_desc *be_get_pcie_desc(u8 devfn, u8 *buf,
return NULL;
}
+static struct be_port_res_desc *be_get_port_desc(u8 *buf, u32 desc_count)
+{
+ struct be_res_desc_hdr *hdr = (struct be_res_desc_hdr *)buf;
+ int i;
+
+ for (i = 0; i < desc_count; i++) {
+ if (hdr->desc_type == PORT_RESOURCE_DESC_TYPE_V1)
+ return (struct be_port_res_desc *)hdr;
+
+ hdr->desc_len = hdr->desc_len ? : RESOURCE_DESC_SIZE_V0;
+ hdr = (void *)hdr + hdr->desc_len;
+ }
+ return NULL;
+}
+
static void be_copy_nic_desc(struct be_resources *res,
struct be_nic_res_desc *desc)
{
@@ -3439,6 +3461,7 @@ int be_cmd_get_profile_config(struct be_adapter *adapter,
{
struct be_cmd_resp_get_profile_config *resp;
struct be_pcie_res_desc *pcie;
+ struct be_port_res_desc *port;
struct be_nic_res_desc *nic;
struct be_queue_info *mccq = &adapter->mcc_obj.q;
struct be_dma_mem cmd;
@@ -3466,6 +3489,10 @@ int be_cmd_get_profile_config(struct be_adapter *adapter,
if (pcie)
res->max_vfs = le16_to_cpu(pcie->num_vfs);
+ port = be_get_port_desc(resp->func_param, desc_count);
+ if (port)
+ adapter->mc_type = port->mc_type;
+
nic = be_get_nic_desc(resp->func_param, desc_count);
if (nic)
be_copy_nic_desc(res, nic);
@@ -3476,14 +3503,11 @@ err:
return status;
}
-/* Currently only Lancer uses this command and it supports version 0 only
- * Uses sync mcc
- */
-int be_cmd_set_profile_config(struct be_adapter *adapter, u32 bps,
- u8 domain)
+int be_cmd_set_profile_config(struct be_adapter *adapter, void *desc,
+ int size, u8 version, u8 domain)
{
- struct be_mcc_wrb *wrb;
struct be_cmd_req_set_profile_config *req;
+ struct be_mcc_wrb *wrb;
int status;
spin_lock_bh(&adapter->mcc_lock);
@@ -3495,44 +3519,116 @@ int be_cmd_set_profile_config(struct be_adapter *adapter, u32 bps,
}
req = embedded_payload(wrb);
-
be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_SET_PROFILE_CONFIG, sizeof(*req),
wrb, NULL);
+ req->hdr.version = version;
req->hdr.domain = domain;
req->desc_count = cpu_to_le32(1);
- req->nic_desc.hdr.desc_type = NIC_RESOURCE_DESC_TYPE_V0;
- req->nic_desc.hdr.desc_len = RESOURCE_DESC_SIZE_V0;
- req->nic_desc.flags = (1 << QUN) | (1 << IMM) | (1 << NOSV);
- req->nic_desc.pf_num = adapter->pf_number;
- req->nic_desc.vf_num = domain;
-
- /* Mark fields invalid */
- req->nic_desc.unicast_mac_count = 0xFFFF;
- req->nic_desc.mcc_count = 0xFFFF;
- req->nic_desc.vlan_count = 0xFFFF;
- req->nic_desc.mcast_mac_count = 0xFFFF;
- req->nic_desc.txq_count = 0xFFFF;
- req->nic_desc.rq_count = 0xFFFF;
- req->nic_desc.rssq_count = 0xFFFF;
- req->nic_desc.lro_count = 0xFFFF;
- req->nic_desc.cq_count = 0xFFFF;
- req->nic_desc.toe_conn_count = 0xFFFF;
- req->nic_desc.eq_count = 0xFFFF;
- req->nic_desc.link_param = 0xFF;
- req->nic_desc.bw_min = 0xFFFFFFFF;
- req->nic_desc.acpi_params = 0xFF;
- req->nic_desc.wol_param = 0x0F;
-
- /* Change BW */
- req->nic_desc.bw_min = cpu_to_le32(bps);
- req->nic_desc.bw_max = cpu_to_le32(bps);
+ memcpy(req->desc, desc, size);
+
status = be_mcc_notify_wait(adapter);
err:
spin_unlock_bh(&adapter->mcc_lock);
return status;
}
+/* Mark all fields invalid */
+void be_reset_nic_desc(struct be_nic_res_desc *nic)
+{
+ memset(nic, 0, sizeof(*nic));
+ nic->unicast_mac_count = 0xFFFF;
+ nic->mcc_count = 0xFFFF;
+ nic->vlan_count = 0xFFFF;
+ nic->mcast_mac_count = 0xFFFF;
+ nic->txq_count = 0xFFFF;
+ nic->rq_count = 0xFFFF;
+ nic->rssq_count = 0xFFFF;
+ nic->lro_count = 0xFFFF;
+ nic->cq_count = 0xFFFF;
+ nic->toe_conn_count = 0xFFFF;
+ nic->eq_count = 0xFFFF;
+ nic->link_param = 0xFF;
+ nic->acpi_params = 0xFF;
+ nic->wol_param = 0x0F;
+ nic->bw_min = 0xFFFFFFFF;
+ nic->bw_max = 0xFFFFFFFF;
+}
+
+int be_cmd_config_qos(struct be_adapter *adapter, u32 bps, u8 domain)
+{
+ if (lancer_chip(adapter)) {
+ struct be_nic_res_desc nic_desc;
+
+ be_reset_nic_desc(&nic_desc);
+ nic_desc.hdr.desc_type = NIC_RESOURCE_DESC_TYPE_V0;
+ nic_desc.hdr.desc_len = RESOURCE_DESC_SIZE_V0;
+ nic_desc.flags = (1 << QUN_SHIFT) | (1 << IMM_SHIFT) |
+ (1 << NOSV_SHIFT);
+ nic_desc.pf_num = adapter->pf_number;
+ nic_desc.vf_num = domain;
+ nic_desc.bw_max = cpu_to_le32(bps);
+
+ return be_cmd_set_profile_config(adapter, &nic_desc,
+ RESOURCE_DESC_SIZE_V0,
+ 0, domain);
+ } else {
+ return be_cmd_set_qos(adapter, bps, domain);
+ }
+}
+
+int be_cmd_manage_iface(struct be_adapter *adapter, u32 iface, u8 op)
+{
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_manage_iface_filters *req;
+ int status;
+
+ if (iface == 0xFFFFFFFF)
+ return -1;
+
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
+ if (!wrb) {
+ status = -EBUSY;
+ goto err;
+ }
+ req = embedded_payload(wrb);
+
+ be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_MANAGE_IFACE_FILTERS, sizeof(*req),
+ wrb, NULL);
+ req->op = op;
+ req->target_iface_id = cpu_to_le32(iface);
+
+ status = be_mcc_notify_wait(adapter);
+err:
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+}
+
+int be_cmd_set_vxlan_port(struct be_adapter *adapter, __be16 port)
+{
+ struct be_port_res_desc port_desc;
+
+ memset(&port_desc, 0, sizeof(port_desc));
+ port_desc.hdr.desc_type = PORT_RESOURCE_DESC_TYPE_V1;
+ port_desc.hdr.desc_len = RESOURCE_DESC_SIZE_V1;
+ port_desc.flags = (1 << IMM_SHIFT) | (1 << NOSV_SHIFT);
+ port_desc.link_num = adapter->hba_port_num;
+ if (port) {
+ port_desc.nv_flags = NV_TYPE_VXLAN | (1 << SOCVID_SHIFT) |
+ (1 << RCVID_SHIFT);
+ port_desc.nv_port = swab16(port);
+ } else {
+ port_desc.nv_flags = NV_TYPE_DISABLED;
+ port_desc.nv_port = 0;
+ }
+
+ return be_cmd_set_profile_config(adapter, &port_desc,
+ RESOURCE_DESC_SIZE_V1, 1, 0);
+}
+
int be_cmd_get_if_id(struct be_adapter *adapter, struct be_vf_cfg *vf_cfg,
int vf_num)
{
@@ -3723,6 +3819,45 @@ err:
return status;
}
+int be_cmd_set_logical_link_config(struct be_adapter *adapter,
+ int link_state, u8 domain)
+{
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_set_ll_link *req;
+ int status;
+
+ if (BEx_chip(adapter) || lancer_chip(adapter))
+ return 0;
+
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
+ if (!wrb) {
+ status = -EBUSY;
+ goto err;
+ }
+
+ req = embedded_payload(wrb);
+
+ be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_SET_LOGICAL_LINK_CONFIG,
+ sizeof(*req), wrb, NULL);
+
+ req->hdr.version = 1;
+ req->hdr.domain = domain;
+
+ if (link_state == IFLA_VF_LINK_STATE_ENABLE)
+ req->link_config |= 1;
+
+ if (link_state == IFLA_VF_LINK_STATE_AUTO)
+ req->link_config |= 1 << PLINK_TRACK_SHIFT;
+
+ status = be_mcc_notify_wait(adapter);
+err:
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+}
+
int be_roce_mcc_cmd(void *netdev_handle, void *wrb_payload,
int wrb_payload_size, u16 *cmd_status, u16 *ext_status)
{
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index fc4e076dc202..b60e4d53c1c9 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2013 Emulex
+ * Copyright (C) 2005 - 2014 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -203,6 +203,7 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_GET_BEACON_STATE 70
#define OPCODE_COMMON_READ_TRANSRECV_DATA 73
#define OPCODE_COMMON_GET_PORT_NAME 77
+#define OPCODE_COMMON_SET_LOGICAL_LINK_CONFIG 80
#define OPCODE_COMMON_SET_INTERRUPT_ENABLE 89
#define OPCODE_COMMON_SET_FN_PRIVILEGES 100
#define OPCODE_COMMON_GET_PHY_DETAILS 102
@@ -221,6 +222,7 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_GET_FN_PRIVILEGES 170
#define OPCODE_COMMON_READ_OBJECT 171
#define OPCODE_COMMON_WRITE_OBJECT 172
+#define OPCODE_COMMON_MANAGE_IFACE_FILTERS 193
#define OPCODE_COMMON_GET_IFACE_LIST 194
#define OPCODE_COMMON_ENABLE_DISABLE_VF 196
@@ -1098,14 +1100,6 @@ struct be_cmd_resp_query_fw_cfg {
u32 function_caps;
};
-/* Is BE in a multi-channel mode */
-static inline bool be_is_mc(struct be_adapter *adapter)
-{
- return adapter->function_mode & FLEX10_MODE ||
- adapter->function_mode & VNIC_MODE ||
- adapter->function_mode & UMC_ENABLED;
-}
-
/******************** RSS Config ****************************************/
/* RSS type Input parameters used to compute RX hash
* RSS_ENABLE_IPV4 SRC IPv4, DST IPv4
@@ -1828,20 +1822,36 @@ struct be_cmd_req_set_ext_fat_caps {
#define NIC_RESOURCE_DESC_TYPE_V0 0x41
#define PCIE_RESOURCE_DESC_TYPE_V1 0x50
#define NIC_RESOURCE_DESC_TYPE_V1 0x51
+#define PORT_RESOURCE_DESC_TYPE_V1 0x55
#define MAX_RESOURCE_DESC 264
-/* QOS unit number */
-#define QUN 4
-/* Immediate */
-#define IMM 6
-/* No save */
-#define NOSV 7
+#define IMM_SHIFT 6 /* Immediate */
+#define NOSV_SHIFT 7 /* No save */
struct be_res_desc_hdr {
u8 desc_type;
u8 desc_len;
} __packed;
+struct be_port_res_desc {
+ struct be_res_desc_hdr hdr;
+ u8 rsvd0;
+ u8 flags;
+ u8 link_num;
+ u8 mc_type;
+ u16 rsvd1;
+
+#define NV_TYPE_MASK 0x3 /* bits 0-1 */
+#define NV_TYPE_DISABLED 1
+#define NV_TYPE_VXLAN 3
+#define SOCVID_SHIFT 2 /* Strip outer vlan */
+#define RCVID_SHIFT 4 /* Report vlan */
+ u8 nv_flags;
+ u8 rsvd2;
+ __le16 nv_port; /* vxlan/gre port */
+ u32 rsvd3[19];
+} __packed;
+
struct be_pcie_res_desc {
struct be_res_desc_hdr hdr;
u8 rsvd0;
@@ -1862,6 +1872,8 @@ struct be_pcie_res_desc {
struct be_nic_res_desc {
struct be_res_desc_hdr hdr;
u8 rsvd1;
+
+#define QUN_SHIFT 4 /* QoS is in absolute units */
u8 flags;
u8 vf_num;
u8 rsvd2;
@@ -1891,6 +1903,23 @@ struct be_nic_res_desc {
u32 rsvd8[7];
} __packed;
+/************ Multi-Channel type ***********/
+enum mc_type {
+ MC_NONE = 0x01,
+ UMC = 0x02,
+ FLEX10 = 0x03,
+ vNIC1 = 0x04,
+ nPAR = 0x05,
+ UFP = 0x06,
+ vNIC2 = 0x07
+};
+
+/* Is BE in a multi-channel mode */
+static inline bool be_is_mc(struct be_adapter *adapter)
+{
+ return adapter->mc_type > MC_NONE;
+}
+
struct be_cmd_req_get_func_config {
struct be_cmd_req_hdr hdr;
};
@@ -1919,7 +1948,7 @@ struct be_cmd_req_set_profile_config {
struct be_cmd_req_hdr hdr;
u32 rsvd;
u32 desc_count;
- struct be_nic_res_desc nic_desc;
+ u8 desc[RESOURCE_DESC_SIZE_V1];
};
struct be_cmd_resp_set_profile_config {
@@ -1971,6 +2000,33 @@ struct be_cmd_resp_get_iface_list {
struct be_if_desc if_desc;
};
+/*************** Set logical link ********************/
+#define PLINK_TRACK_SHIFT 8
+struct be_cmd_req_set_ll_link {
+ struct be_cmd_req_hdr hdr;
+ u32 link_config; /* Bit 0: UP_DOWN, Bit 9: PLINK */
+};
+
+/************** Manage IFACE Filters *******************/
+#define OP_CONVERT_NORMAL_TO_TUNNEL 0
+#define OP_CONVERT_TUNNEL_TO_NORMAL 1
+
+struct be_cmd_req_manage_iface_filters {
+ struct be_cmd_req_hdr hdr;
+ u8 op;
+ u8 rsvd0;
+ u8 flags;
+ u8 rsvd1;
+ u32 tunnel_iface_id;
+ u32 target_iface_id;
+ u8 mac[6];
+ u16 vlan_tag;
+ u32 tenant_id;
+ u32 filter_id;
+ u32 cap_flags;
+ u32 cap_control_flags;
+} __packed;
+
int be_pci_fnum_get(struct be_adapter *adapter);
int be_fw_wait_ready(struct be_adapter *adapter);
int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
@@ -2045,7 +2101,7 @@ int be_cmd_get_seeprom_data(struct be_adapter *adapter,
int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num,
u8 loopback_type, u8 enable);
int be_cmd_get_phy_info(struct be_adapter *adapter);
-int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain);
+int be_cmd_config_qos(struct be_adapter *adapter, u32 bps, u8 domain);
void be_detect_error(struct be_adapter *adapter);
int be_cmd_get_die_temperature(struct be_adapter *adapter);
int be_cmd_get_cntl_attributes(struct be_adapter *adapter);
@@ -2086,9 +2142,14 @@ int be_cmd_get_func_config(struct be_adapter *adapter,
struct be_resources *res);
int be_cmd_get_profile_config(struct be_adapter *adapter,
struct be_resources *res, u8 domain);
-int be_cmd_set_profile_config(struct be_adapter *adapter, u32 bps, u8 domain);
+int be_cmd_set_profile_config(struct be_adapter *adapter, void *desc,
+ int size, u8 version, u8 domain);
int be_cmd_get_active_profile(struct be_adapter *adapter, u16 *profile);
int be_cmd_get_if_id(struct be_adapter *adapter, struct be_vf_cfg *vf_cfg,
int vf_num);
int be_cmd_enable_vf(struct be_adapter *adapter, u8 domain);
int be_cmd_intr_set(struct be_adapter *adapter, bool intr_enable);
+int be_cmd_set_logical_link_config(struct be_adapter *adapter,
+ int link_state, u8 domain);
+int be_cmd_set_vxlan_port(struct be_adapter *adapter, __be16 port);
+int be_cmd_manage_iface(struct be_adapter *adapter, u32 iface, u8 op);
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c
index 05be0070f55f..15ba96cba65d 100644
--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2013 Emulex
+ * Copyright (C) 2005 - 2014 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -357,10 +357,10 @@ be_get_ethtool_stats(struct net_device *netdev,
struct be_rx_stats *stats = rx_stats(rxo);
do {
- start = u64_stats_fetch_begin_bh(&stats->sync);
+ start = u64_stats_fetch_begin_irq(&stats->sync);
data[base] = stats->rx_bytes;
data[base + 1] = stats->rx_pkts;
- } while (u64_stats_fetch_retry_bh(&stats->sync, start));
+ } while (u64_stats_fetch_retry_irq(&stats->sync, start));
for (i = 2; i < ETHTOOL_RXSTATS_NUM; i++) {
p = (u8 *)stats + et_rx_stats[i].offset;
@@ -373,19 +373,19 @@ be_get_ethtool_stats(struct net_device *netdev,
struct be_tx_stats *stats = tx_stats(txo);
do {
- start = u64_stats_fetch_begin_bh(&stats->sync_compl);
+ start = u64_stats_fetch_begin_irq(&stats->sync_compl);
data[base] = stats->tx_compl;
- } while (u64_stats_fetch_retry_bh(&stats->sync_compl, start));
+ } while (u64_stats_fetch_retry_irq(&stats->sync_compl, start));
do {
- start = u64_stats_fetch_begin_bh(&stats->sync);
+ start = u64_stats_fetch_begin_irq(&stats->sync);
for (i = 1; i < ETHTOOL_TXSTATS_NUM; i++) {
p = (u8 *)stats + et_tx_stats[i].offset;
data[base + i] =
(et_tx_stats[i].size == sizeof(u64)) ?
*(u64 *)p : *(u32 *)p;
}
- } while (u64_stats_fetch_retry_bh(&stats->sync, start));
+ } while (u64_stats_fetch_retry_irq(&stats->sync, start));
base += ETHTOOL_TXSTATS_NUM;
}
}
@@ -802,16 +802,18 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)
if (test->flags & ETH_TEST_FL_OFFLINE) {
if (be_loopback_test(adapter, BE_MAC_LOOPBACK,
- &data[0]) != 0) {
+ &data[0]) != 0)
test->flags |= ETH_TEST_FL_FAILED;
- }
+
if (be_loopback_test(adapter, BE_PHY_LOOPBACK,
- &data[1]) != 0) {
- test->flags |= ETH_TEST_FL_FAILED;
- }
- if (be_loopback_test(adapter, BE_ONE_PORT_EXT_LOOPBACK,
- &data[2]) != 0) {
+ &data[1]) != 0)
test->flags |= ETH_TEST_FL_FAILED;
+
+ if (test->flags & ETH_TEST_FL_EXTERNAL_LB) {
+ if (be_loopback_test(adapter, BE_ONE_PORT_EXT_LOOPBACK,
+ &data[2]) != 0)
+ test->flags |= ETH_TEST_FL_FAILED;
+ test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
}
}
diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h
index dc88782185f2..3bd198550edb 100644
--- a/drivers/net/ethernet/emulex/benet/be_hw.h
+++ b/drivers/net/ethernet/emulex/benet/be_hw.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2013 Emulex
+ * Copyright (C) 2005 - 2014 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -368,7 +368,7 @@ struct amap_eth_rx_compl_v0 {
u8 numfrags[3]; /* dword 1 */
u8 rss_flush; /* dword 2 */
u8 cast_enc[2]; /* dword 2 */
- u8 vtm; /* dword 2 */
+ u8 qnq; /* dword 2 */
u8 rss_bank; /* dword 2 */
u8 rsvd1[23]; /* dword 2 */
u8 lro_pkt; /* dword 2 */
@@ -401,13 +401,14 @@ struct amap_eth_rx_compl_v1 {
u8 numfrags[3]; /* dword 1 */
u8 rss_flush; /* dword 2 */
u8 cast_enc[2]; /* dword 2 */
- u8 vtm; /* dword 2 */
+ u8 qnq; /* dword 2 */
u8 rss_bank; /* dword 2 */
u8 port[2]; /* dword 2 */
u8 vntagp; /* dword 2 */
u8 header_len[8]; /* dword 2 */
u8 header_split[2]; /* dword 2 */
- u8 rsvd1[13]; /* dword 2 */
+ u8 rsvd1[12]; /* dword 2 */
+ u8 tunneled;
u8 valid; /* dword 2 */
u8 rsshash[32]; /* dword 3 */
} __packed;
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 04ac9c6a0d39..3e6df47b6973 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2013 Emulex
+ * Copyright (C) 2005 - 2014 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -23,6 +23,7 @@
#include <linux/aer.h>
#include <linux/if_bridge.h>
#include <net/busy_poll.h>
+#include <net/vxlan.h>
MODULE_VERSION(DRV_VER);
MODULE_DEVICE_TABLE(pci, be_dev_ids);
@@ -591,10 +592,10 @@ static struct rtnl_link_stats64 *be_get_stats64(struct net_device *netdev,
for_all_rx_queues(adapter, rxo, i) {
const struct be_rx_stats *rx_stats = rx_stats(rxo);
do {
- start = u64_stats_fetch_begin_bh(&rx_stats->sync);
+ start = u64_stats_fetch_begin_irq(&rx_stats->sync);
pkts = rx_stats(rxo)->rx_pkts;
bytes = rx_stats(rxo)->rx_bytes;
- } while (u64_stats_fetch_retry_bh(&rx_stats->sync, start));
+ } while (u64_stats_fetch_retry_irq(&rx_stats->sync, start));
stats->rx_packets += pkts;
stats->rx_bytes += bytes;
stats->multicast += rx_stats(rxo)->rx_mcast_pkts;
@@ -605,10 +606,10 @@ static struct rtnl_link_stats64 *be_get_stats64(struct net_device *netdev,
for_all_tx_queues(adapter, txo, i) {
const struct be_tx_stats *tx_stats = tx_stats(txo);
do {
- start = u64_stats_fetch_begin_bh(&tx_stats->sync);
+ start = u64_stats_fetch_begin_irq(&tx_stats->sync);
pkts = tx_stats(txo)->tx_pkts;
bytes = tx_stats(txo)->tx_bytes;
- } while (u64_stats_fetch_retry_bh(&tx_stats->sync, start));
+ } while (u64_stats_fetch_retry_irq(&tx_stats->sync, start));
stats->tx_packets += pkts;
stats->tx_bytes += bytes;
}
@@ -652,7 +653,7 @@ void be_link_status_update(struct be_adapter *adapter, u8 link_status)
adapter->flags |= BE_FLAGS_LINK_STATUS_INIT;
}
- if ((link_status & LINK_STATUS_MASK) == LINK_UP)
+ if (link_status)
netif_carrier_on(netdev);
else
netif_carrier_off(netdev);
@@ -718,10 +719,23 @@ static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter,
return vlan_tag;
}
+/* Used only for IP tunnel packets */
+static u16 skb_inner_ip_proto(struct sk_buff *skb)
+{
+ return (inner_ip_hdr(skb)->version == 4) ?
+ inner_ip_hdr(skb)->protocol : inner_ipv6_hdr(skb)->nexthdr;
+}
+
+static u16 skb_ip_proto(struct sk_buff *skb)
+{
+ return (ip_hdr(skb)->version == 4) ?
+ ip_hdr(skb)->protocol : ipv6_hdr(skb)->nexthdr;
+}
+
static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
struct sk_buff *skb, u32 wrb_cnt, u32 len, bool skip_hw_vlan)
{
- u16 vlan_tag;
+ u16 vlan_tag, proto;
memset(hdr, 0, sizeof(*hdr));
@@ -734,9 +748,15 @@ static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
if (skb_is_gso_v6(skb) && !lancer_chip(adapter))
AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso6, hdr, 1);
} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
- if (is_tcp_pkt(skb))
+ if (skb->encapsulation) {
+ AMAP_SET_BITS(struct amap_eth_hdr_wrb, ipcs, hdr, 1);
+ proto = skb_inner_ip_proto(skb);
+ } else {
+ proto = skb_ip_proto(skb);
+ }
+ if (proto == IPPROTO_TCP)
AMAP_SET_BITS(struct amap_eth_hdr_wrb, tcpcs, hdr, 1);
- else if (is_udp_pkt(skb))
+ else if (proto == IPPROTO_UDP)
AMAP_SET_BITS(struct amap_eth_hdr_wrb, udpcs, hdr, 1);
}
@@ -913,24 +933,14 @@ static int be_ipv6_tx_stall_chk(struct be_adapter *adapter,
return BE3_chip(adapter) && be_ipv6_exthdr_check(skb);
}
-static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
- struct sk_buff *skb,
- bool *skip_hw_vlan)
+static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
+ struct sk_buff *skb,
+ bool *skip_hw_vlan)
{
struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
unsigned int eth_hdr_len;
struct iphdr *ip;
- /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or less
- * may cause a transmit stall on that port. So the work-around is to
- * pad short packets (<= 32 bytes) to a 36-byte length.
- */
- if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) {
- if (skb_padto(skb, 36))
- goto tx_drop;
- skb->len = 36;
- }
-
/* For padded packets, BE HW modifies tot_len field in IP header
* incorrecly when VLAN tag is inserted by HW.
* For padded packets, Lancer computes incorrect checksum.
@@ -945,9 +955,9 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
}
/* If vlan tag is already inlined in the packet, skip HW VLAN
- * tagging in UMC mode
+ * tagging in pvid-tagging mode
*/
- if ((adapter->function_mode & UMC_ENABLED) &&
+ if (be_pvid_tagging_enabled(adapter) &&
veh->h_vlan_proto == htons(ETH_P_8021Q))
*skip_hw_vlan = true;
@@ -959,7 +969,7 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
vlan_tx_tag_present(skb)) {
skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan);
if (unlikely(!skb))
- goto tx_drop;
+ goto err;
}
/* HW may lockup when VLAN HW tagging is requested on
@@ -981,15 +991,39 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
be_vlan_tag_tx_chk(adapter, skb)) {
skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan);
if (unlikely(!skb))
- goto tx_drop;
+ goto err;
}
return skb;
tx_drop:
dev_kfree_skb_any(skb);
+err:
return NULL;
}
+static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
+ struct sk_buff *skb,
+ bool *skip_hw_vlan)
+{
+ /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or
+ * less may cause a transmit stall on that port. So the work-around is
+ * to pad short packets (<= 32 bytes) to a 36-byte length.
+ */
+ if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) {
+ if (skb_padto(skb, 36))
+ return NULL;
+ skb->len = 36;
+ }
+
+ if (BEx_chip(adapter) || lancer_chip(adapter)) {
+ skb = be_lancer_xmit_workarounds(adapter, skb, skip_hw_vlan);
+ if (!skb)
+ return NULL;
+ }
+
+ return skb;
+}
+
static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
@@ -1124,7 +1158,10 @@ static int be_vlan_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
/* Packets with VID 0 are always received by Lancer by default */
if (lancer_chip(adapter) && vid == 0)
- goto ret;
+ return status;
+
+ if (adapter->vlan_tag[vid])
+ return status;
adapter->vlan_tag[vid] = 1;
adapter->vlans_added++;
@@ -1134,7 +1171,7 @@ static int be_vlan_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
adapter->vlans_added--;
adapter->vlan_tag[vid] = 0;
}
-ret:
+
return status;
}
@@ -1157,6 +1194,14 @@ ret:
return status;
}
+static void be_clear_promisc(struct be_adapter *adapter)
+{
+ adapter->promiscuous = false;
+ adapter->flags &= ~BE_FLAGS_VLAN_PROMISC;
+
+ be_cmd_rx_filter(adapter, IFF_PROMISC, OFF);
+}
+
static void be_set_rx_mode(struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
@@ -1170,9 +1215,7 @@ static void be_set_rx_mode(struct net_device *netdev)
/* BE was previously in promiscuous mode; disable it */
if (adapter->promiscuous) {
- adapter->promiscuous = false;
- be_cmd_rx_filter(adapter, IFF_PROMISC, OFF);
-
+ be_clear_promisc(adapter);
if (adapter->vlans_added)
be_vid_config(adapter);
}
@@ -1268,6 +1311,7 @@ static int be_get_vf_config(struct net_device *netdev, int vf,
vi->vlan = vf_cfg->vlan_tag & VLAN_VID_MASK;
vi->qos = vf_cfg->vlan_tag >> VLAN_PRIO_SHIFT;
memcpy(&vi->mac, vf_cfg->mac_addr, ETH_ALEN);
+ vi->linkstate = adapter->vf_cfg[vf].plink_tracking;
return 0;
}
@@ -1287,24 +1331,20 @@ static int be_set_vf_vlan(struct net_device *netdev,
if (vlan || qos) {
vlan |= qos << VLAN_PRIO_SHIFT;
- if (vf_cfg->vlan_tag != vlan) {
- /* If this is new value, program it. Else skip. */
- vf_cfg->vlan_tag = vlan;
+ if (vf_cfg->vlan_tag != vlan)
status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
vf_cfg->if_handle, 0);
- }
} else {
/* Reset Transparent Vlan Tagging. */
- vf_cfg->vlan_tag = 0;
- vlan = vf_cfg->def_vid;
- status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
- vf_cfg->if_handle, 0);
+ status = be_cmd_set_hsw_config(adapter, BE_RESET_VLAN_TAG_ID,
+ vf + 1, vf_cfg->if_handle, 0);
}
-
- if (status)
+ if (!status)
+ vf_cfg->vlan_tag = vlan;
+ else
dev_info(&adapter->pdev->dev,
- "VLAN %d config on VF %d failed\n", vlan, vf);
+ "VLAN %d config on VF %d failed\n", vlan, vf);
return status;
}
@@ -1326,11 +1366,7 @@ static int be_set_vf_tx_rate(struct net_device *netdev,
return -EINVAL;
}
- if (lancer_chip(adapter))
- status = be_cmd_set_profile_config(adapter, rate / 10, vf + 1);
- else
- status = be_cmd_set_qos(adapter, rate / 10, vf + 1);
-
+ status = be_cmd_config_qos(adapter, rate / 10, vf + 1);
if (status)
dev_err(&adapter->pdev->dev,
"tx rate %d on VF %d failed\n", rate, vf);
@@ -1338,6 +1374,24 @@ static int be_set_vf_tx_rate(struct net_device *netdev,
adapter->vf_cfg[vf].tx_rate = rate;
return status;
}
+static int be_set_vf_link_state(struct net_device *netdev, int vf,
+ int link_state)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+ int status;
+
+ if (!sriov_enabled(adapter))
+ return -EPERM;
+
+ if (vf >= adapter->num_vfs)
+ return -EINVAL;
+
+ status = be_cmd_set_logical_link_config(adapter, link_state, vf+1);
+ if (!status)
+ adapter->vf_cfg[vf].plink_tracking = link_state;
+
+ return status;
+}
static void be_aic_update(struct be_aic_obj *aic, u64 rx_pkts, u64 tx_pkts,
ulong now)
@@ -1370,15 +1424,15 @@ static void be_eqd_update(struct be_adapter *adapter)
rxo = &adapter->rx_obj[eqo->idx];
do {
- start = u64_stats_fetch_begin_bh(&rxo->stats.sync);
+ start = u64_stats_fetch_begin_irq(&rxo->stats.sync);
rx_pkts = rxo->stats.rx_pkts;
- } while (u64_stats_fetch_retry_bh(&rxo->stats.sync, start));
+ } while (u64_stats_fetch_retry_irq(&rxo->stats.sync, start));
txo = &adapter->tx_obj[eqo->idx];
do {
- start = u64_stats_fetch_begin_bh(&txo->stats.sync);
+ start = u64_stats_fetch_begin_irq(&txo->stats.sync);
tx_pkts = txo->stats.tx_reqs;
- } while (u64_stats_fetch_retry_bh(&txo->stats.sync, start));
+ } while (u64_stats_fetch_retry_irq(&txo->stats.sync, start));
/* Skip, if wrapped around or first calculation */
@@ -1433,9 +1487,10 @@ static void be_rx_stats_update(struct be_rx_obj *rxo,
static inline bool csum_passed(struct be_rx_compl_info *rxcp)
{
/* L4 checksum is not reliable for non TCP/UDP packets.
- * Also ignore ipcksm for ipv6 pkts */
+ * Also ignore ipcksm for ipv6 pkts
+ */
return (rxcp->tcpf || rxcp->udpf) && rxcp->l4_csum &&
- (rxcp->ip_csum || rxcp->ipv6);
+ (rxcp->ip_csum || rxcp->ipv6) && !rxcp->err;
}
static struct be_rx_page_info *get_rx_page_info(struct be_rx_obj *rxo)
@@ -1448,11 +1503,15 @@ static struct be_rx_page_info *get_rx_page_info(struct be_rx_obj *rxo)
rx_page_info = &rxo->page_info_tbl[frag_idx];
BUG_ON(!rx_page_info->page);
- if (rx_page_info->last_page_user) {
+ if (rx_page_info->last_frag) {
dma_unmap_page(&adapter->pdev->dev,
dma_unmap_addr(rx_page_info, bus),
adapter->big_page_size, DMA_FROM_DEVICE);
- rx_page_info->last_page_user = false;
+ rx_page_info->last_frag = false;
+ } else {
+ dma_sync_single_for_cpu(&adapter->pdev->dev,
+ dma_unmap_addr(rx_page_info, bus),
+ rx_frag_size, DMA_FROM_DEVICE);
}
queue_tail_inc(rxq);
@@ -1574,6 +1633,8 @@ static void be_rx_compl_process(struct be_rx_obj *rxo, struct napi_struct *napi,
skb_record_rx_queue(skb, rxo - &adapter->rx_obj[0]);
if (netdev->features & NETIF_F_RXHASH)
skb_set_hash(skb, rxcp->rss_hash, PKT_HASH_TYPE_L3);
+
+ skb->encapsulation = rxcp->tunneled;
skb_mark_napi_id(skb, napi);
if (rxcp->vlanf)
@@ -1630,6 +1691,8 @@ static void be_rx_compl_process_gro(struct be_rx_obj *rxo,
skb_record_rx_queue(skb, rxo - &adapter->rx_obj[0]);
if (adapter->netdev->features & NETIF_F_RXHASH)
skb_set_hash(skb, rxcp->rss_hash, PKT_HASH_TYPE_L3);
+
+ skb->encapsulation = rxcp->tunneled;
skb_mark_napi_id(skb, napi);
if (rxcp->vlanf)
@@ -1660,12 +1723,14 @@ static void be_parse_rx_compl_v1(struct be_eth_rx_compl *compl,
rxcp->rss_hash =
AMAP_GET_BITS(struct amap_eth_rx_compl_v1, rsshash, compl);
if (rxcp->vlanf) {
- rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm,
+ rxcp->qnq = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, qnq,
compl);
rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag,
compl);
}
rxcp->port = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, port, compl);
+ rxcp->tunneled =
+ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, tunneled, compl);
}
static void be_parse_rx_compl_v0(struct be_eth_rx_compl *compl,
@@ -1690,7 +1755,7 @@ static void be_parse_rx_compl_v0(struct be_eth_rx_compl *compl,
rxcp->rss_hash =
AMAP_GET_BITS(struct amap_eth_rx_compl_v0, rsshash, compl);
if (rxcp->vlanf) {
- rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm,
+ rxcp->qnq = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, qnq,
compl);
rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag,
compl);
@@ -1723,9 +1788,11 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
rxcp->l4_csum = 0;
if (rxcp->vlanf) {
- /* vlanf could be wrongly set in some cards.
- * ignore if vtm is not set */
- if ((adapter->function_mode & FLEX10_MODE) && !rxcp->vtm)
+ /* In QNQ modes, if qnq bit is not set, then the packet was
+ * tagged only with the transparent outer vlan-tag and must
+ * not be treated as a vlan packet by host
+ */
+ if (be_is_qnq_mode(adapter) && !rxcp->qnq)
rxcp->vlanf = 0;
if (!lancer_chip(adapter))
@@ -1784,17 +1851,16 @@ static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp)
rx_stats(rxo)->rx_post_fail++;
break;
}
- page_info->page_offset = 0;
+ page_offset = 0;
} else {
get_page(pagep);
- page_info->page_offset = page_offset + rx_frag_size;
+ page_offset += rx_frag_size;
}
- page_offset = page_info->page_offset;
+ page_info->page_offset = page_offset;
page_info->page = pagep;
- dma_unmap_addr_set(page_info, bus, page_dmaaddr);
- frag_dmaaddr = page_dmaaddr + page_info->page_offset;
rxd = queue_head_node(rxq);
+ frag_dmaaddr = page_dmaaddr + page_info->page_offset;
rxd->fragpa_lo = cpu_to_le32(frag_dmaaddr & 0xFFFFFFFF);
rxd->fragpa_hi = cpu_to_le32(upper_32_bits(frag_dmaaddr));
@@ -1802,15 +1868,24 @@ static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp)
if ((page_offset + rx_frag_size + rx_frag_size) >
adapter->big_page_size) {
pagep = NULL;
- page_info->last_page_user = true;
+ page_info->last_frag = true;
+ dma_unmap_addr_set(page_info, bus, page_dmaaddr);
+ } else {
+ dma_unmap_addr_set(page_info, bus, frag_dmaaddr);
}
prev_page_info = page_info;
queue_head_inc(rxq);
page_info = &rxo->page_info_tbl[rxq->head];
}
- if (pagep)
- prev_page_info->last_page_user = true;
+
+ /* Mark the last frag of a page when we break out of the above loop
+ * with no more slots available in the RXQ
+ */
+ if (pagep) {
+ prev_page_info->last_frag = true;
+ dma_unmap_addr_set(prev_page_info, bus, page_dmaaddr);
+ }
if (posted) {
atomic_add(posted, &rxq->used);
@@ -1867,7 +1942,7 @@ static u16 be_tx_compl_process(struct be_adapter *adapter,
queue_tail_inc(txq);
} while (cur_index != last_index);
- kfree_skb(sent_skb);
+ dev_kfree_skb_any(sent_skb);
return num_wrbs;
}
@@ -2423,6 +2498,9 @@ void be_detect_error(struct be_adapter *adapter)
u32 ue_lo = 0, ue_hi = 0, ue_lo_mask = 0, ue_hi_mask = 0;
u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0;
u32 i;
+ bool error_detected = false;
+ struct device *dev = &adapter->pdev->dev;
+ struct net_device *netdev = adapter->netdev;
if (be_hw_error(adapter))
return;
@@ -2434,6 +2512,21 @@ void be_detect_error(struct be_adapter *adapter)
SLIPORT_ERROR1_OFFSET);
sliport_err2 = ioread32(adapter->db +
SLIPORT_ERROR2_OFFSET);
+ adapter->hw_error = true;
+ /* Do not log error messages if its a FW reset */
+ if (sliport_err1 == SLIPORT_ERROR_FW_RESET1 &&
+ sliport_err2 == SLIPORT_ERROR_FW_RESET2) {
+ dev_info(dev, "Firmware update in progress\n");
+ } else {
+ error_detected = true;
+ dev_err(dev, "Error detected in the card\n");
+ dev_err(dev, "ERR: sliport status 0x%x\n",
+ sliport_status);
+ dev_err(dev, "ERR: sliport error1 0x%x\n",
+ sliport_err1);
+ dev_err(dev, "ERR: sliport error2 0x%x\n",
+ sliport_err2);
+ }
}
} else {
pci_read_config_dword(adapter->pdev,
@@ -2447,51 +2540,33 @@ void be_detect_error(struct be_adapter *adapter)
ue_lo = (ue_lo & ~ue_lo_mask);
ue_hi = (ue_hi & ~ue_hi_mask);
- }
-
- /* On certain platforms BE hardware can indicate spurious UEs.
- * Allow the h/w to stop working completely in case of a real UE.
- * Hence not setting the hw_error for UE detection.
- */
- if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
- adapter->hw_error = true;
- /* Do not log error messages if its a FW reset */
- if (sliport_err1 == SLIPORT_ERROR_FW_RESET1 &&
- sliport_err2 == SLIPORT_ERROR_FW_RESET2) {
- dev_info(&adapter->pdev->dev,
- "Firmware update in progress\n");
- return;
- } else {
- dev_err(&adapter->pdev->dev,
- "Error detected in the card\n");
- }
- }
-
- if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
- dev_err(&adapter->pdev->dev,
- "ERR: sliport status 0x%x\n", sliport_status);
- dev_err(&adapter->pdev->dev,
- "ERR: sliport error1 0x%x\n", sliport_err1);
- dev_err(&adapter->pdev->dev,
- "ERR: sliport error2 0x%x\n", sliport_err2);
- }
- if (ue_lo) {
- for (i = 0; ue_lo; ue_lo >>= 1, i++) {
- if (ue_lo & 1)
- dev_err(&adapter->pdev->dev,
- "UE: %s bit set\n", ue_status_low_desc[i]);
- }
- }
+ /* On certain platforms BE hardware can indicate spurious UEs.
+ * Allow HW to stop working completely in case of a real UE.
+ * Hence not setting the hw_error for UE detection.
+ */
- if (ue_hi) {
- for (i = 0; ue_hi; ue_hi >>= 1, i++) {
- if (ue_hi & 1)
- dev_err(&adapter->pdev->dev,
- "UE: %s bit set\n", ue_status_hi_desc[i]);
+ if (ue_lo || ue_hi) {
+ error_detected = true;
+ dev_err(dev,
+ "Unrecoverable Error detected in the adapter");
+ dev_err(dev, "Please reboot server to recover");
+ if (skyhawk_chip(adapter))
+ adapter->hw_error = true;
+ for (i = 0; ue_lo; ue_lo >>= 1, i++) {
+ if (ue_lo & 1)
+ dev_err(dev, "UE: %s bit set\n",
+ ue_status_low_desc[i]);
+ }
+ for (i = 0; ue_hi; ue_hi >>= 1, i++) {
+ if (ue_hi & 1)
+ dev_err(dev, "UE: %s bit set\n",
+ ue_status_hi_desc[i]);
+ }
}
}
-
+ if (error_detected)
+ netif_carrier_off(netdev);
}
static void be_msix_disable(struct be_adapter *adapter)
@@ -2505,7 +2580,7 @@ static void be_msix_disable(struct be_adapter *adapter)
static int be_msix_enable(struct be_adapter *adapter)
{
- int i, status, num_vec;
+ int i, num_vec;
struct device *dev = &adapter->pdev->dev;
/* If RoCE is supported, program the max number of NIC vectors that
@@ -2521,24 +2596,11 @@ static int be_msix_enable(struct be_adapter *adapter)
for (i = 0; i < num_vec; i++)
adapter->msix_entries[i].entry = i;
- status = pci_enable_msix(adapter->pdev, adapter->msix_entries, num_vec);
- if (status == 0) {
- goto done;
- } else if (status >= MIN_MSIX_VECTORS) {
- num_vec = status;
- status = pci_enable_msix(adapter->pdev, adapter->msix_entries,
- num_vec);
- if (!status)
- goto done;
- }
-
- dev_warn(dev, "MSIx enable failed\n");
+ num_vec = pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+ MIN_MSIX_VECTORS, num_vec);
+ if (num_vec < 0)
+ goto fail;
- /* INTx is not supported in VFs, so fail probe if enable_msix fails */
- if (!be_physfn(adapter))
- return status;
- return 0;
-done:
if (be_roce_supported(adapter) && num_vec > MIN_MSIX_VECTORS) {
adapter->num_msix_roce_vec = num_vec / 2;
dev_info(dev, "enabled %d MSI-x vector(s) for RoCE\n",
@@ -2550,6 +2612,14 @@ done:
dev_info(dev, "enabled %d MSI-x vector(s) for NIC\n",
adapter->num_msix_vec);
return 0;
+
+fail:
+ dev_warn(dev, "MSIx enable failed\n");
+
+ /* INTx is not supported in VFs, so fail probe if enable_msix fails */
+ if (!be_physfn(adapter))
+ return num_vec;
+ return 0;
}
static inline int be_msix_vec_get(struct be_adapter *adapter,
@@ -2791,6 +2861,12 @@ static int be_open(struct net_device *netdev)
netif_tx_start_all_queues(netdev);
be_roce_dev_open(adapter);
+
+#ifdef CONFIG_BE2NET_VXLAN
+ if (skyhawk_chip(adapter))
+ vxlan_get_rx_port(netdev);
+#endif
+
return 0;
err:
be_close(adapter->netdev);
@@ -2946,6 +3022,21 @@ static void be_mac_clear(struct be_adapter *adapter)
}
}
+#ifdef CONFIG_BE2NET_VXLAN
+static void be_disable_vxlan_offloads(struct be_adapter *adapter)
+{
+ if (adapter->flags & BE_FLAGS_VXLAN_OFFLOADS)
+ be_cmd_manage_iface(adapter, adapter->if_handle,
+ OP_CONVERT_TUNNEL_TO_NORMAL);
+
+ if (adapter->vxlan_port)
+ be_cmd_set_vxlan_port(adapter, 0);
+
+ adapter->flags &= ~BE_FLAGS_VXLAN_OFFLOADS;
+ adapter->vxlan_port = 0;
+}
+#endif
+
static int be_clear(struct be_adapter *adapter)
{
be_cancel_worker(adapter);
@@ -2953,6 +3044,9 @@ static int be_clear(struct be_adapter *adapter)
if (sriov_enabled(adapter))
be_vf_clear(adapter);
+#ifdef CONFIG_BE2NET_VXLAN
+ be_disable_vxlan_offloads(adapter);
+#endif
/* delete the primary mac along with the uc-mac list */
be_mac_clear(adapter);
@@ -3013,11 +3107,11 @@ static int be_vf_setup_init(struct be_adapter *adapter)
static int be_vf_setup(struct be_adapter *adapter)
{
+ struct device *dev = &adapter->pdev->dev;
struct be_vf_cfg *vf_cfg;
- u16 def_vlan, lnk_speed;
int status, old_vfs, vf;
- struct device *dev = &adapter->pdev->dev;
u32 privileges;
+ u16 lnk_speed;
old_vfs = pci_num_vf(adapter->pdev);
if (old_vfs) {
@@ -3077,21 +3171,19 @@ static int be_vf_setup(struct be_adapter *adapter)
* Allow full available bandwidth
*/
if (BE3_chip(adapter) && !old_vfs)
- be_cmd_set_qos(adapter, 1000, vf+1);
+ be_cmd_config_qos(adapter, 1000, vf + 1);
status = be_cmd_link_status_query(adapter, &lnk_speed,
NULL, vf + 1);
if (!status)
vf_cfg->tx_rate = lnk_speed;
- status = be_cmd_get_hsw_config(adapter, &def_vlan,
- vf + 1, vf_cfg->if_handle, NULL);
- if (status)
- goto err;
- vf_cfg->def_vid = def_vlan;
-
- if (!old_vfs)
+ if (!old_vfs) {
be_cmd_enable_vf(adapter, vf + 1);
+ be_cmd_set_logical_link_config(adapter,
+ IFLA_VF_LINK_STATE_AUTO,
+ vf+1);
+ }
}
if (!old_vfs) {
@@ -3109,19 +3201,38 @@ err:
return status;
}
+/* Converting function_mode bits on BE3 to SH mc_type enums */
+
+static u8 be_convert_mc_type(u32 function_mode)
+{
+ if (function_mode & VNIC_MODE && function_mode & FLEX10_MODE)
+ return vNIC1;
+ else if (function_mode & FLEX10_MODE)
+ return FLEX10;
+ else if (function_mode & VNIC_MODE)
+ return vNIC2;
+ else if (function_mode & UMC_ENABLED)
+ return UMC;
+ else
+ return MC_NONE;
+}
+
/* On BE2/BE3 FW does not suggest the supported limits */
static void BEx_get_resources(struct be_adapter *adapter,
struct be_resources *res)
{
struct pci_dev *pdev = adapter->pdev;
bool use_sriov = false;
- int max_vfs;
-
- max_vfs = pci_sriov_get_totalvfs(pdev);
-
- if (BE3_chip(adapter) && sriov_want(adapter)) {
- res->max_vfs = max_vfs > 0 ? min(MAX_VFS, max_vfs) : 0;
- use_sriov = res->max_vfs;
+ int max_vfs = 0;
+
+ if (be_physfn(adapter) && BE3_chip(adapter)) {
+ be_cmd_get_profile_config(adapter, res, 0);
+ /* Some old versions of BE3 FW don't report max_vfs value */
+ if (res->max_vfs == 0) {
+ max_vfs = pci_sriov_get_totalvfs(pdev);
+ res->max_vfs = max_vfs > 0 ? min(MAX_VFS, max_vfs) : 0;
+ }
+ use_sriov = res->max_vfs && sriov_want(adapter);
}
if (be_physfn(adapter))
@@ -3129,17 +3240,32 @@ static void BEx_get_resources(struct be_adapter *adapter,
else
res->max_uc_mac = BE_VF_UC_PMAC_COUNT;
- if (adapter->function_mode & FLEX10_MODE)
- res->max_vlans = BE_NUM_VLANS_SUPPORTED/8;
- else if (adapter->function_mode & UMC_ENABLED)
- res->max_vlans = BE_UMC_NUM_VLANS_SUPPORTED;
- else
+ adapter->mc_type = be_convert_mc_type(adapter->function_mode);
+
+ if (be_is_mc(adapter)) {
+ /* Assuming that there are 4 channels per port,
+ * when multi-channel is enabled
+ */
+ if (be_is_qnq_mode(adapter))
+ res->max_vlans = BE_NUM_VLANS_SUPPORTED/8;
+ else
+ /* In a non-qnq multichannel mode, the pvid
+ * takes up one vlan entry
+ */
+ res->max_vlans = (BE_NUM_VLANS_SUPPORTED / 4) - 1;
+ } else {
res->max_vlans = BE_NUM_VLANS_SUPPORTED;
+ }
+
res->max_mcast_mac = BE_MAX_MC;
- /* For BE3 1Gb ports, F/W does not properly support multiple TXQs */
- if (BE2_chip(adapter) || use_sriov || be_is_mc(adapter) ||
- !be_physfn(adapter) || (adapter->port_num > 1))
+ /* 1) For BE3 1Gb ports, FW does not support multiple TXQs
+ * 2) Create multiple TX rings on a BE3-R multi-channel interface
+ * *only* if it is RSS-capable.
+ */
+ if (BE2_chip(adapter) || use_sriov || (adapter->port_num > 1) ||
+ !be_physfn(adapter) || (be_is_mc(adapter) &&
+ !(adapter->function_caps & BE_FUNCTION_CAPS_RSS)))
res->max_tx_qs = 1;
else
res->max_tx_qs = BE3_MAX_TX_QS;
@@ -3151,7 +3277,7 @@ static void BEx_get_resources(struct be_adapter *adapter,
res->max_rx_qs = res->max_rss_qs + 1;
if (be_physfn(adapter))
- res->max_evt_qs = (max_vfs > 0) ?
+ res->max_evt_qs = (res->max_vfs > 0) ?
BE3_SRIOV_MAX_EVT_QS : BE3_MAX_EVT_QS;
else
res->max_evt_qs = 1;
@@ -3242,9 +3368,8 @@ static int be_get_config(struct be_adapter *adapter)
if (status)
return status;
- /* primary mac needs 1 pmac entry */
- adapter->pmac_id = kcalloc(be_max_uc(adapter) + 1, sizeof(u32),
- GFP_KERNEL);
+ adapter->pmac_id = kcalloc(be_max_uc(adapter),
+ sizeof(*adapter->pmac_id), GFP_KERNEL);
if (!adapter->pmac_id)
return -ENOMEM;
@@ -3418,6 +3543,10 @@ static int be_setup(struct be_adapter *adapter)
be_cmd_set_flow_control(adapter, adapter->tx_fc,
adapter->rx_fc);
+ if (be_physfn(adapter))
+ be_cmd_set_logical_link_config(adapter,
+ IFLA_VF_LINK_STATE_AUTO, 0);
+
if (sriov_want(adapter)) {
if (be_max_vfs(adapter))
be_vf_setup(adapter);
@@ -4042,6 +4171,67 @@ static int be_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
BRIDGE_MODE_VEPA : BRIDGE_MODE_VEB);
}
+#ifdef CONFIG_BE2NET_VXLAN
+static void be_add_vxlan_port(struct net_device *netdev, sa_family_t sa_family,
+ __be16 port)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+ struct device *dev = &adapter->pdev->dev;
+ int status;
+
+ if (lancer_chip(adapter) || BEx_chip(adapter))
+ return;
+
+ if (adapter->flags & BE_FLAGS_VXLAN_OFFLOADS) {
+ dev_warn(dev, "Cannot add UDP port %d for VxLAN offloads\n",
+ be16_to_cpu(port));
+ dev_info(dev,
+ "Only one UDP port supported for VxLAN offloads\n");
+ return;
+ }
+
+ status = be_cmd_manage_iface(adapter, adapter->if_handle,
+ OP_CONVERT_NORMAL_TO_TUNNEL);
+ if (status) {
+ dev_warn(dev, "Failed to convert normal interface to tunnel\n");
+ goto err;
+ }
+
+ status = be_cmd_set_vxlan_port(adapter, port);
+ if (status) {
+ dev_warn(dev, "Failed to add VxLAN port\n");
+ goto err;
+ }
+ adapter->flags |= BE_FLAGS_VXLAN_OFFLOADS;
+ adapter->vxlan_port = port;
+
+ dev_info(dev, "Enabled VxLAN offloads for UDP port %d\n",
+ be16_to_cpu(port));
+ return;
+err:
+ be_disable_vxlan_offloads(adapter);
+ return;
+}
+
+static void be_del_vxlan_port(struct net_device *netdev, sa_family_t sa_family,
+ __be16 port)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+
+ if (lancer_chip(adapter) || BEx_chip(adapter))
+ return;
+
+ if (adapter->vxlan_port != port)
+ return;
+
+ be_disable_vxlan_offloads(adapter);
+
+ dev_info(&adapter->pdev->dev,
+ "Disabled VxLAN offloads for UDP port %d\n",
+ be16_to_cpu(port));
+}
+#endif
+
static const struct net_device_ops be_netdev_ops = {
.ndo_open = be_open,
.ndo_stop = be_close,
@@ -4057,13 +4247,18 @@ static const struct net_device_ops be_netdev_ops = {
.ndo_set_vf_vlan = be_set_vf_vlan,
.ndo_set_vf_tx_rate = be_set_vf_tx_rate,
.ndo_get_vf_config = be_get_vf_config,
+ .ndo_set_vf_link_state = be_set_vf_link_state,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = be_netpoll,
#endif
.ndo_bridge_setlink = be_ndo_bridge_setlink,
.ndo_bridge_getlink = be_ndo_bridge_getlink,
#ifdef CONFIG_NET_RX_BUSY_POLL
- .ndo_busy_poll = be_busy_poll
+ .ndo_busy_poll = be_busy_poll,
+#endif
+#ifdef CONFIG_BE2NET_VXLAN
+ .ndo_add_vxlan_port = be_add_vxlan_port,
+ .ndo_del_vxlan_port = be_del_vxlan_port,
#endif
};
@@ -4071,6 +4266,12 @@ static void be_netdev_init(struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
+ if (skyhawk_chip(adapter)) {
+ netdev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_TSO | NETIF_F_TSO6 |
+ NETIF_F_GSO_UDP_TUNNEL;
+ netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL;
+ }
netdev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |
NETIF_F_HW_VLAN_CTAG_TX;
@@ -4417,14 +4618,32 @@ static bool be_reset_required(struct be_adapter *adapter)
static char *mc_name(struct be_adapter *adapter)
{
- if (adapter->function_mode & FLEX10_MODE)
- return "FLEX10";
- else if (adapter->function_mode & VNIC_MODE)
- return "vNIC";
- else if (adapter->function_mode & UMC_ENABLED)
- return "UMC";
- else
- return "";
+ char *str = ""; /* default */
+
+ switch (adapter->mc_type) {
+ case UMC:
+ str = "UMC";
+ break;
+ case FLEX10:
+ str = "FLEX10";
+ break;
+ case vNIC1:
+ str = "vNIC-1";
+ break;
+ case nPAR:
+ str = "nPAR";
+ break;
+ case UFP:
+ str = "UFP";
+ break;
+ case vNIC2:
+ str = "vNIC-2";
+ break;
+ default:
+ str = "";
+ }
+
+ return str;
}
static inline char *func_name(struct be_adapter *adapter)
diff --git a/drivers/net/ethernet/emulex/benet/be_roce.c b/drivers/net/ethernet/emulex/benet/be_roce.c
index 9cd5415fe017..5bf16603a3e9 100644
--- a/drivers/net/ethernet/emulex/benet/be_roce.c
+++ b/drivers/net/ethernet/emulex/benet/be_roce.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2013 Emulex
+ * Copyright (C) 2005 - 2014 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -35,6 +35,12 @@ static void _be_roce_dev_add(struct be_adapter *adapter)
if (!ocrdma_drv)
return;
+
+ if (ocrdma_drv->be_abi_version != BE_ROCE_ABI_VERSION) {
+ dev_warn(&pdev->dev, "Cannot initialize RoCE due to ocrdma ABI mismatch\n");
+ return;
+ }
+
if (pdev->device == OC_DEVICE_ID5) {
/* only msix is supported on these devices */
if (!msix_enabled(adapter))
diff --git a/drivers/net/ethernet/emulex/benet/be_roce.h b/drivers/net/ethernet/emulex/benet/be_roce.h
index 2cd1129e19af..a3d9e96c18eb 100644
--- a/drivers/net/ethernet/emulex/benet/be_roce.h
+++ b/drivers/net/ethernet/emulex/benet/be_roce.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2013 Emulex
+ * Copyright (C) 2005 - 2014 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -21,6 +21,8 @@
#include <linux/pci.h>
#include <linux/netdevice.h>
+#define BE_ROCE_ABI_VERSION 1
+
struct ocrdma_dev;
enum be_interrupt_mode {
@@ -52,6 +54,7 @@ struct be_dev_info {
/* ocrdma driver register's the callback functions with nic driver. */
struct ocrdma_driver {
unsigned char name[32];
+ u32 be_abi_version;
struct ocrdma_dev *(*add) (struct be_dev_info *dev_info);
void (*remove) (struct ocrdma_dev *);
void (*state_change_handler) (struct ocrdma_dev *, u32 new_state);
diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c
index 4de8cfd149cf..8b70ca7e342b 100644
--- a/drivers/net/ethernet/ethoc.c
+++ b/drivers/net/ethernet/ethoc.c
@@ -13,6 +13,7 @@
#include <linux/dma-mapping.h>
#include <linux/etherdevice.h>
+#include <linux/clk.h>
#include <linux/crc32.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -51,6 +52,7 @@ MODULE_PARM_DESC(buffer_size, "DMA buffer allocation size");
#define ETH_HASH0 0x48
#define ETH_HASH1 0x4c
#define ETH_TXCTRL 0x50
+#define ETH_END 0x54
/* mode register */
#define MODER_RXEN (1 << 0) /* receive enable */
@@ -179,6 +181,7 @@ MODULE_PARM_DESC(buffer_size, "DMA buffer allocation size");
* @membase: pointer to buffer memory region
* @dma_alloc: dma allocated buffer size
* @io_region_size: I/O memory region size
+ * @num_bd: number of buffer descriptors
* @num_tx: number of send buffers
* @cur_tx: last send buffer written
* @dty_tx: last buffer actually sent
@@ -199,6 +202,7 @@ struct ethoc {
int dma_alloc;
resource_size_t io_region_size;
+ unsigned int num_bd;
unsigned int num_tx;
unsigned int cur_tx;
unsigned int dty_tx;
@@ -216,6 +220,7 @@ struct ethoc {
struct phy_device *phy;
struct mii_bus *mdio;
+ struct clk *clk;
s8 phy_id;
};
@@ -655,11 +660,6 @@ static int ethoc_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
return -EBUSY;
}
-static int ethoc_mdio_reset(struct mii_bus *bus)
-{
- return 0;
-}
-
static void ethoc_mdio_poll(struct net_device *dev)
{
}
@@ -688,6 +688,11 @@ static int ethoc_mdio_probe(struct net_device *dev)
}
priv->phy = phy;
+ phy->advertising &= ~(ADVERTISED_1000baseT_Full |
+ ADVERTISED_1000baseT_Half);
+ phy->supported &= ~(SUPPORTED_1000baseT_Full |
+ SUPPORTED_1000baseT_Half);
+
return 0;
}
@@ -890,6 +895,102 @@ out:
return NETDEV_TX_OK;
}
+static int ethoc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct ethoc *priv = netdev_priv(dev);
+ struct phy_device *phydev = priv->phy;
+
+ if (!phydev)
+ return -EOPNOTSUPP;
+
+ return phy_ethtool_gset(phydev, cmd);
+}
+
+static int ethoc_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct ethoc *priv = netdev_priv(dev);
+ struct phy_device *phydev = priv->phy;
+
+ if (!phydev)
+ return -EOPNOTSUPP;
+
+ return phy_ethtool_sset(phydev, cmd);
+}
+
+static int ethoc_get_regs_len(struct net_device *netdev)
+{
+ return ETH_END;
+}
+
+static void ethoc_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+ void *p)
+{
+ struct ethoc *priv = netdev_priv(dev);
+ u32 *regs_buff = p;
+ unsigned i;
+
+ regs->version = 0;
+ for (i = 0; i < ETH_END / sizeof(u32); ++i)
+ regs_buff[i] = ethoc_read(priv, i * sizeof(u32));
+}
+
+static void ethoc_get_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ring)
+{
+ struct ethoc *priv = netdev_priv(dev);
+
+ ring->rx_max_pending = priv->num_bd - 1;
+ ring->rx_mini_max_pending = 0;
+ ring->rx_jumbo_max_pending = 0;
+ ring->tx_max_pending = priv->num_bd - 1;
+
+ ring->rx_pending = priv->num_rx;
+ ring->rx_mini_pending = 0;
+ ring->rx_jumbo_pending = 0;
+ ring->tx_pending = priv->num_tx;
+}
+
+static int ethoc_set_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ring)
+{
+ struct ethoc *priv = netdev_priv(dev);
+
+ if (ring->tx_pending < 1 || ring->rx_pending < 1 ||
+ ring->tx_pending + ring->rx_pending > priv->num_bd)
+ return -EINVAL;
+ if (ring->rx_mini_pending || ring->rx_jumbo_pending)
+ return -EINVAL;
+
+ if (netif_running(dev)) {
+ netif_tx_disable(dev);
+ ethoc_disable_rx_and_tx(priv);
+ ethoc_disable_irq(priv, INT_MASK_TX | INT_MASK_RX);
+ synchronize_irq(dev->irq);
+ }
+
+ priv->num_tx = rounddown_pow_of_two(ring->tx_pending);
+ priv->num_rx = ring->rx_pending;
+ ethoc_init_ring(priv, dev->mem_start);
+
+ if (netif_running(dev)) {
+ ethoc_enable_irq(priv, INT_MASK_TX | INT_MASK_RX);
+ ethoc_enable_rx_and_tx(priv);
+ netif_wake_queue(dev);
+ }
+ return 0;
+}
+
+const struct ethtool_ops ethoc_ethtool_ops = {
+ .get_settings = ethoc_get_settings,
+ .set_settings = ethoc_set_settings,
+ .get_regs_len = ethoc_get_regs_len,
+ .get_regs = ethoc_get_regs,
+ .get_link = ethtool_op_get_link,
+ .get_ringparam = ethoc_get_ringparam,
+ .set_ringparam = ethoc_set_ringparam,
+ .get_ts_info = ethtool_op_get_ts_info,
+};
+
static const struct net_device_ops ethoc_netdev_ops = {
.ndo_open = ethoc_open,
.ndo_stop = ethoc_stop,
@@ -917,6 +1018,8 @@ static int ethoc_probe(struct platform_device *pdev)
int num_bd;
int ret = 0;
bool random_mac = false;
+ struct ethoc_platform_data *pdata = dev_get_platdata(&pdev->dev);
+ u32 eth_clkfreq = pdata ? pdata->eth_clkfreq : 0;
/* allocate networking device */
netdev = alloc_etherdev(sizeof(struct ethoc));
@@ -1016,6 +1119,7 @@ static int ethoc_probe(struct platform_device *pdev)
ret = -ENODEV;
goto error;
}
+ priv->num_bd = num_bd;
/* num_tx must be a power of two */
priv->num_tx = rounddown_pow_of_two(num_bd >> 1);
priv->num_rx = num_bd - priv->num_tx;
@@ -1030,8 +1134,7 @@ static int ethoc_probe(struct platform_device *pdev)
}
/* Allow the platform setup code to pass in a MAC address. */
- if (dev_get_platdata(&pdev->dev)) {
- struct ethoc_platform_data *pdata = dev_get_platdata(&pdev->dev);
+ if (pdata) {
memcpy(netdev->dev_addr, pdata->hwaddr, IFHWADDRLEN);
priv->phy_id = pdata->phy_id;
} else {
@@ -1069,6 +1172,27 @@ static int ethoc_probe(struct platform_device *pdev)
if (random_mac)
netdev->addr_assign_type = NET_ADDR_RANDOM;
+ /* Allow the platform setup code to adjust MII management bus clock. */
+ if (!eth_clkfreq) {
+ struct clk *clk = devm_clk_get(&pdev->dev, NULL);
+
+ if (!IS_ERR(clk)) {
+ priv->clk = clk;
+ clk_prepare_enable(clk);
+ eth_clkfreq = clk_get_rate(clk);
+ }
+ }
+ if (eth_clkfreq) {
+ u32 clkdiv = MIIMODER_CLKDIV(eth_clkfreq / 2500000 + 1);
+
+ if (!clkdiv)
+ clkdiv = 2;
+ dev_dbg(&pdev->dev, "setting MII clkdiv to %u\n", clkdiv);
+ ethoc_write(priv, MIIMODER,
+ (ethoc_read(priv, MIIMODER) & MIIMODER_NOPRE) |
+ clkdiv);
+ }
+
/* register MII bus */
priv->mdio = mdiobus_alloc();
if (!priv->mdio) {
@@ -1081,7 +1205,6 @@ static int ethoc_probe(struct platform_device *pdev)
priv->mdio->name, pdev->id);
priv->mdio->read = ethoc_mdio_read;
priv->mdio->write = ethoc_mdio_write;
- priv->mdio->reset = ethoc_mdio_reset;
priv->mdio->priv = priv;
priv->mdio->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
@@ -1111,6 +1234,7 @@ static int ethoc_probe(struct platform_device *pdev)
netdev->netdev_ops = &ethoc_netdev_ops;
netdev->watchdog_timeo = ETHOC_TIMEOUT;
netdev->features |= 0;
+ netdev->ethtool_ops = &ethoc_ethtool_ops;
/* setup NAPI */
netif_napi_add(netdev, &priv->napi, ethoc_poll, 64);
@@ -1133,6 +1257,8 @@ free_mdio:
kfree(priv->mdio->irq);
mdiobus_free(priv->mdio);
free:
+ if (priv->clk)
+ clk_disable_unprepare(priv->clk);
free_netdev(netdev);
out:
return ret;
@@ -1157,6 +1283,8 @@ static int ethoc_remove(struct platform_device *pdev)
kfree(priv->mdio->irq);
mdiobus_free(priv->mdio);
}
+ if (priv->clk)
+ clk_disable_unprepare(priv->clk);
unregister_netdev(netdev);
free_netdev(netdev);
}
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
index c11ecbc98149..68069eabc4f8 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.c
+++ b/drivers/net/ethernet/faraday/ftgmac100.c
@@ -940,11 +940,6 @@ static int ftgmac100_mdiobus_write(struct mii_bus *bus, int phy_addr,
return -EIO;
}
-static int ftgmac100_mdiobus_reset(struct mii_bus *bus)
-{
- return 0;
-}
-
/******************************************************************************
* struct ethtool_ops functions
*****************************************************************************/
@@ -1262,7 +1257,6 @@ static int ftgmac100_probe(struct platform_device *pdev)
priv->mii_bus->priv = netdev;
priv->mii_bus->read = ftgmac100_mdiobus_read;
priv->mii_bus->write = ftgmac100_mdiobus_write;
- priv->mii_bus->reset = ftgmac100_mdiobus_reset;
priv->mii_bus->irq = priv->phy_irq;
for (i = 0; i < PHY_MAX_ADDR; i++)
diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile
index 549ce13b92ac..71debd1c18c9 100644
--- a/drivers/net/ethernet/freescale/Makefile
+++ b/drivers/net/ethernet/freescale/Makefile
@@ -14,7 +14,6 @@ obj-$(CONFIG_FSL_XGMAC_MDIO) += xgmac_mdio.o
obj-$(CONFIG_GIANFAR) += gianfar_driver.o
obj-$(CONFIG_PTP_1588_CLOCK_GIANFAR) += gianfar_ptp.o
gianfar_driver-objs := gianfar.o \
- gianfar_ethtool.o \
- gianfar_sysfs.o
+ gianfar_ethtool.o
obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o
ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index d4782b42401b..8d69e439f0c5 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -338,7 +338,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
/* Protocol checksum off-load for TCP and UDP. */
if (fec_enet_clear_csum(skb, ndev)) {
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -389,12 +389,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
netdev_err(ndev, "Tx DMA memory map failed\n");
return NETDEV_TX_OK;
}
- /* Send it on its way. Tell FEC it's ready, interrupt when done,
- * it's the last BD of the frame, and to put the CRC on the end.
- */
- status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
- | BD_ENET_TX_LAST | BD_ENET_TX_TC);
- bdp->cbd_sc = status;
if (fep->bufdesc_ex) {
@@ -416,6 +410,13 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
}
}
+ /* Send it on its way. Tell FEC it's ready, interrupt when done,
+ * it's the last BD of the frame, and to put the CRC on the end.
+ */
+ status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
+ | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+ bdp->cbd_sc = status;
+
bdp_pre = fec_enet_get_prevdesc(bdp, fep);
if ((id_entry->driver_data & FEC_QUIRK_ERR006358) &&
!(bdp_pre->cbd_sc & BD_ENET_TX_READY)) {
@@ -527,13 +528,6 @@ fec_restart(struct net_device *ndev, int duplex)
/* Clear any outstanding interrupt. */
writel(0xffc00000, fep->hwp + FEC_IEVENT);
- /* Setup multicast filter. */
- set_multicast_list(ndev);
-#ifndef CONFIG_M5272
- writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
- writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
-#endif
-
/* Set maximum receive buffer size. */
writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE);
@@ -654,6 +648,13 @@ fec_restart(struct net_device *ndev, int duplex)
writel(rcntl, fep->hwp + FEC_R_CNTRL);
+ /* Setup multicast filter. */
+ set_multicast_list(ndev);
+#ifndef CONFIG_M5272
+ writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
+ writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
+#endif
+
if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
/* enable ENET endian swap */
ecntl |= (1 << 8);
@@ -1254,11 +1255,6 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
return 0;
}
-static int fec_enet_mdio_reset(struct mii_bus *bus)
-{
- return 0;
-}
-
static int fec_enet_mii_probe(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
@@ -1383,7 +1379,6 @@ static int fec_enet_mii_init(struct platform_device *pdev)
fep->mii_bus->name = "fec_enet_mii_bus";
fep->mii_bus->read = fec_enet_mdio_read;
fep->mii_bus->write = fec_enet_mdio_write;
- fep->mii_bus->reset = fec_enet_mdio_reset;
snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
pdev->name, fep->dev_id + 1);
fep->mii_bus->priv = fep;
@@ -1778,8 +1773,6 @@ fec_enet_open(struct net_device *ndev)
struct fec_enet_private *fep = netdev_priv(ndev);
int ret;
- napi_enable(&fep->napi);
-
/* I should reset the ring buffers here, but I don't yet know
* a simple way to do that.
*/
@@ -1794,6 +1787,8 @@ fec_enet_open(struct net_device *ndev)
fec_enet_free_buffers(ndev);
return ret;
}
+
+ napi_enable(&fep->napi);
phy_start(fep->phy_dev);
netif_start_queue(ndev);
fep->opened = 1;
@@ -1903,10 +1898,11 @@ fec_set_mac_address(struct net_device *ndev, void *p)
struct fec_enet_private *fep = netdev_priv(ndev);
struct sockaddr *addr = p;
- if (!is_valid_ether_addr(addr->sa_data))
- return -EADDRNOTAVAIL;
-
- memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);
+ if (addr) {
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+ memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);
+ }
writel(ndev->dev_addr[3] | (ndev->dev_addr[2] << 8) |
(ndev->dev_addr[1] << 16) | (ndev->dev_addr[0] << 24),
@@ -2005,6 +2001,8 @@ static int fec_enet_init(struct net_device *ndev)
/* Get the Ethernet address */
fec_get_mac(ndev);
+ /* make sure MAC we just acquired is programmed into the hw */
+ fec_set_mac_address(ndev, NULL);
/* init the tx & rx ring size */
fep->tx_ring_size = TX_RING_SIZE;
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index 89ccb5b08708..82386b29914a 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -372,6 +372,7 @@ void fec_ptp_init(struct platform_device *pdev)
fep->ptp_caps.n_alarm = 0;
fep->ptp_caps.n_ext_ts = 0;
fep->ptp_caps.n_per_out = 0;
+ fep->ptp_caps.n_pins = 0;
fep->ptp_caps.pps = 0;
fep->ptp_caps.adjfreq = fec_ptp_adjfreq;
fep->ptp_caps.adjtime = fec_ptp_adjtime;
diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
index 62f042d4aaa9..dc80db41d6b3 100644
--- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
+++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
@@ -91,6 +91,9 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget)
u16 pkt_len, sc;
int curidx;
+ if (budget <= 0)
+ return received;
+
/*
* First, grab all of the stats for the incoming packet.
* These get messed up if we get called due to a busy condition.
diff --git a/drivers/net/ethernet/freescale/fs_enet/mii-fec.c b/drivers/net/ethernet/freescale/fs_enet/mii-fec.c
index 7e69c983d12a..ebf5d6429a8d 100644
--- a/drivers/net/ethernet/freescale/fs_enet/mii-fec.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mii-fec.c
@@ -95,12 +95,6 @@ static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location,
}
-static int fs_enet_fec_mii_reset(struct mii_bus *bus)
-{
- /* nothing here - for now */
- return 0;
-}
-
static struct of_device_id fs_enet_mdio_fec_match[];
static int fs_enet_mdio_probe(struct platform_device *ofdev)
{
@@ -128,7 +122,6 @@ static int fs_enet_mdio_probe(struct platform_device *ofdev)
new_bus->name = "FEC MII Bus";
new_bus->read = &fs_enet_fec_mii_read;
new_bus->write = &fs_enet_fec_mii_write;
- new_bus->reset = &fs_enet_fec_mii_reset;
ret = of_address_to_resource(ofdev->dev.of_node, 0, &res);
if (ret)
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index ad5a5aadc7e1..9125d9abf099 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -9,7 +9,7 @@
* Maintainer: Kumar Gala
* Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com>
*
- * Copyright 2002-2009, 2011 Freescale Semiconductor, Inc.
+ * Copyright 2002-2009, 2011-2013 Freescale Semiconductor, Inc.
* Copyright 2007 MontaVista Software, Inc.
*
* This program is free software; you can redistribute it and/or modify it
@@ -121,7 +121,6 @@ static irqreturn_t gfar_error(int irq, void *dev_id);
static irqreturn_t gfar_transmit(int irq, void *dev_id);
static irqreturn_t gfar_interrupt(int irq, void *dev_id);
static void adjust_link(struct net_device *dev);
-static void init_registers(struct net_device *dev);
static int init_phy(struct net_device *dev);
static int gfar_probe(struct platform_device *ofdev);
static int gfar_remove(struct platform_device *ofdev);
@@ -129,8 +128,10 @@ static void free_skb_resources(struct gfar_private *priv);
static void gfar_set_multi(struct net_device *dev);
static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
static void gfar_configure_serdes(struct net_device *dev);
-static int gfar_poll(struct napi_struct *napi, int budget);
-static int gfar_poll_sq(struct napi_struct *napi, int budget);
+static int gfar_poll_rx(struct napi_struct *napi, int budget);
+static int gfar_poll_tx(struct napi_struct *napi, int budget);
+static int gfar_poll_rx_sq(struct napi_struct *napi, int budget);
+static int gfar_poll_tx_sq(struct napi_struct *napi, int budget);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void gfar_netpoll(struct net_device *dev);
#endif
@@ -138,9 +139,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit);
static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue);
static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
int amount_pull, struct napi_struct *napi);
-void gfar_halt(struct net_device *dev);
-static void gfar_halt_nodisable(struct net_device *dev);
-void gfar_start(struct net_device *dev);
+static void gfar_halt_nodisable(struct gfar_private *priv);
static void gfar_clear_exact_match(struct net_device *dev);
static void gfar_set_mac_for_addr(struct net_device *dev, int num,
const u8 *addr);
@@ -332,72 +331,76 @@ static void gfar_init_tx_rx_base(struct gfar_private *priv)
}
}
-static void gfar_init_mac(struct net_device *ndev)
+static void gfar_rx_buff_size_config(struct gfar_private *priv)
{
- struct gfar_private *priv = netdev_priv(ndev);
- struct gfar __iomem *regs = priv->gfargrp[0].regs;
- u32 rctrl = 0;
- u32 tctrl = 0;
- u32 attrs = 0;
-
- /* write the tx/rx base registers */
- gfar_init_tx_rx_base(priv);
-
- /* Configure the coalescing support */
- gfar_configure_coalescing_all(priv);
+ int frame_size = priv->ndev->mtu + ETH_HLEN;
/* set this when rx hw offload (TOE) functions are being used */
priv->uses_rxfcb = 0;
+ if (priv->ndev->features & (NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_RX))
+ priv->uses_rxfcb = 1;
+
+ if (priv->hwts_rx_en)
+ priv->uses_rxfcb = 1;
+
+ if (priv->uses_rxfcb)
+ frame_size += GMAC_FCB_LEN;
+
+ frame_size += priv->padding;
+
+ frame_size = (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) +
+ INCREMENTAL_BUFFER_SIZE;
+
+ priv->rx_buffer_size = frame_size;
+}
+
+static void gfar_mac_rx_config(struct gfar_private *priv)
+{
+ struct gfar __iomem *regs = priv->gfargrp[0].regs;
+ u32 rctrl = 0;
+
if (priv->rx_filer_enable) {
rctrl |= RCTRL_FILREN;
/* Program the RIR0 reg with the required distribution */
- gfar_write(&regs->rir0, DEFAULT_RIR0);
+ if (priv->poll_mode == GFAR_SQ_POLLING)
+ gfar_write(&regs->rir0, DEFAULT_2RXQ_RIR0);
+ else /* GFAR_MQ_POLLING */
+ gfar_write(&regs->rir0, DEFAULT_8RXQ_RIR0);
}
/* Restore PROMISC mode */
- if (ndev->flags & IFF_PROMISC)
+ if (priv->ndev->flags & IFF_PROMISC)
rctrl |= RCTRL_PROM;
- if (ndev->features & NETIF_F_RXCSUM) {
+ if (priv->ndev->features & NETIF_F_RXCSUM)
rctrl |= RCTRL_CHECKSUMMING;
- priv->uses_rxfcb = 1;
- }
- if (priv->extended_hash) {
- rctrl |= RCTRL_EXTHASH;
-
- gfar_clear_exact_match(ndev);
- rctrl |= RCTRL_EMEN;
- }
+ if (priv->extended_hash)
+ rctrl |= RCTRL_EXTHASH | RCTRL_EMEN;
if (priv->padding) {
rctrl &= ~RCTRL_PAL_MASK;
rctrl |= RCTRL_PADDING(priv->padding);
}
- /* Insert receive time stamps into padding alignment bytes */
- if (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER) {
- rctrl &= ~RCTRL_PAL_MASK;
- rctrl |= RCTRL_PADDING(8);
- priv->padding = 8;
- }
-
/* Enable HW time stamping if requested from user space */
- if (priv->hwts_rx_en) {
+ if (priv->hwts_rx_en)
rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE;
- priv->uses_rxfcb = 1;
- }
- if (ndev->features & NETIF_F_HW_VLAN_CTAG_RX) {
+ if (priv->ndev->features & NETIF_F_HW_VLAN_CTAG_RX)
rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;
- priv->uses_rxfcb = 1;
- }
/* Init rctrl based on our settings */
gfar_write(&regs->rctrl, rctrl);
+}
+
+static void gfar_mac_tx_config(struct gfar_private *priv)
+{
+ struct gfar __iomem *regs = priv->gfargrp[0].regs;
+ u32 tctrl = 0;
- if (ndev->features & NETIF_F_IP_CSUM)
+ if (priv->ndev->features & NETIF_F_IP_CSUM)
tctrl |= TCTRL_INIT_CSUM;
if (priv->prio_sched_en)
@@ -408,30 +411,51 @@ static void gfar_init_mac(struct net_device *ndev)
gfar_write(&regs->tr47wt, DEFAULT_WRRS_WEIGHT);
}
- gfar_write(&regs->tctrl, tctrl);
+ if (priv->ndev->features & NETIF_F_HW_VLAN_CTAG_TX)
+ tctrl |= TCTRL_VLINS;
- /* Set the extraction length and index */
- attrs = ATTRELI_EL(priv->rx_stash_size) |
- ATTRELI_EI(priv->rx_stash_index);
+ gfar_write(&regs->tctrl, tctrl);
+}
- gfar_write(&regs->attreli, attrs);
+static void gfar_configure_coalescing(struct gfar_private *priv,
+ unsigned long tx_mask, unsigned long rx_mask)
+{
+ struct gfar __iomem *regs = priv->gfargrp[0].regs;
+ u32 __iomem *baddr;
- /* Start with defaults, and add stashing or locking
- * depending on the approprate variables
- */
- attrs = ATTR_INIT_SETTINGS;
+ if (priv->mode == MQ_MG_MODE) {
+ int i = 0;
- if (priv->bd_stash_en)
- attrs |= ATTR_BDSTASH;
+ baddr = &regs->txic0;
+ for_each_set_bit(i, &tx_mask, priv->num_tx_queues) {
+ gfar_write(baddr + i, 0);
+ if (likely(priv->tx_queue[i]->txcoalescing))
+ gfar_write(baddr + i, priv->tx_queue[i]->txic);
+ }
- if (priv->rx_stash_size != 0)
- attrs |= ATTR_BUFSTASH;
+ baddr = &regs->rxic0;
+ for_each_set_bit(i, &rx_mask, priv->num_rx_queues) {
+ gfar_write(baddr + i, 0);
+ if (likely(priv->rx_queue[i]->rxcoalescing))
+ gfar_write(baddr + i, priv->rx_queue[i]->rxic);
+ }
+ } else {
+ /* Backward compatible case -- even if we enable
+ * multiple queues, there's only single reg to program
+ */
+ gfar_write(&regs->txic, 0);
+ if (likely(priv->tx_queue[0]->txcoalescing))
+ gfar_write(&regs->txic, priv->tx_queue[0]->txic);
- gfar_write(&regs->attr, attrs);
+ gfar_write(&regs->rxic, 0);
+ if (unlikely(priv->rx_queue[0]->rxcoalescing))
+ gfar_write(&regs->rxic, priv->rx_queue[0]->rxic);
+ }
+}
- gfar_write(&regs->fifo_tx_thr, priv->fifo_threshold);
- gfar_write(&regs->fifo_tx_starve, priv->fifo_starve);
- gfar_write(&regs->fifo_tx_starve_shutoff, priv->fifo_starve_off);
+void gfar_configure_coalescing_all(struct gfar_private *priv)
+{
+ gfar_configure_coalescing(priv, 0xFF, 0xFF);
}
static struct net_device_stats *gfar_get_stats(struct net_device *dev)
@@ -479,12 +503,27 @@ static const struct net_device_ops gfar_netdev_ops = {
#endif
};
-void lock_rx_qs(struct gfar_private *priv)
+static void gfar_ints_disable(struct gfar_private *priv)
{
int i;
+ for (i = 0; i < priv->num_grps; i++) {
+ struct gfar __iomem *regs = priv->gfargrp[i].regs;
+ /* Clear IEVENT */
+ gfar_write(&regs->ievent, IEVENT_INIT_CLEAR);
- for (i = 0; i < priv->num_rx_queues; i++)
- spin_lock(&priv->rx_queue[i]->rxlock);
+ /* Initialize IMASK */
+ gfar_write(&regs->imask, IMASK_INIT_CLEAR);
+ }
+}
+
+static void gfar_ints_enable(struct gfar_private *priv)
+{
+ int i;
+ for (i = 0; i < priv->num_grps; i++) {
+ struct gfar __iomem *regs = priv->gfargrp[i].regs;
+ /* Unmask the interrupts we look for */
+ gfar_write(&regs->imask, IMASK_DEFAULT);
+ }
}
void lock_tx_qs(struct gfar_private *priv)
@@ -495,23 +534,50 @@ void lock_tx_qs(struct gfar_private *priv)
spin_lock(&priv->tx_queue[i]->txlock);
}
-void unlock_rx_qs(struct gfar_private *priv)
+void unlock_tx_qs(struct gfar_private *priv)
{
int i;
- for (i = 0; i < priv->num_rx_queues; i++)
- spin_unlock(&priv->rx_queue[i]->rxlock);
+ for (i = 0; i < priv->num_tx_queues; i++)
+ spin_unlock(&priv->tx_queue[i]->txlock);
}
-void unlock_tx_qs(struct gfar_private *priv)
+static int gfar_alloc_tx_queues(struct gfar_private *priv)
{
int i;
- for (i = 0; i < priv->num_tx_queues; i++)
- spin_unlock(&priv->tx_queue[i]->txlock);
+ for (i = 0; i < priv->num_tx_queues; i++) {
+ priv->tx_queue[i] = kzalloc(sizeof(struct gfar_priv_tx_q),
+ GFP_KERNEL);
+ if (!priv->tx_queue[i])
+ return -ENOMEM;
+
+ priv->tx_queue[i]->tx_skbuff = NULL;
+ priv->tx_queue[i]->qindex = i;
+ priv->tx_queue[i]->dev = priv->ndev;
+ spin_lock_init(&(priv->tx_queue[i]->txlock));
+ }
+ return 0;
}
-static void free_tx_pointers(struct gfar_private *priv)
+static int gfar_alloc_rx_queues(struct gfar_private *priv)
+{
+ int i;
+
+ for (i = 0; i < priv->num_rx_queues; i++) {
+ priv->rx_queue[i] = kzalloc(sizeof(struct gfar_priv_rx_q),
+ GFP_KERNEL);
+ if (!priv->rx_queue[i])
+ return -ENOMEM;
+
+ priv->rx_queue[i]->rx_skbuff = NULL;
+ priv->rx_queue[i]->qindex = i;
+ priv->rx_queue[i]->dev = priv->ndev;
+ }
+ return 0;
+}
+
+static void gfar_free_tx_queues(struct gfar_private *priv)
{
int i;
@@ -519,7 +585,7 @@ static void free_tx_pointers(struct gfar_private *priv)
kfree(priv->tx_queue[i]);
}
-static void free_rx_pointers(struct gfar_private *priv)
+static void gfar_free_rx_queues(struct gfar_private *priv)
{
int i;
@@ -553,23 +619,26 @@ static void disable_napi(struct gfar_private *priv)
{
int i;
- for (i = 0; i < priv->num_grps; i++)
- napi_disable(&priv->gfargrp[i].napi);
+ for (i = 0; i < priv->num_grps; i++) {
+ napi_disable(&priv->gfargrp[i].napi_rx);
+ napi_disable(&priv->gfargrp[i].napi_tx);
+ }
}
static void enable_napi(struct gfar_private *priv)
{
int i;
- for (i = 0; i < priv->num_grps; i++)
- napi_enable(&priv->gfargrp[i].napi);
+ for (i = 0; i < priv->num_grps; i++) {
+ napi_enable(&priv->gfargrp[i].napi_rx);
+ napi_enable(&priv->gfargrp[i].napi_tx);
+ }
}
static int gfar_parse_group(struct device_node *np,
struct gfar_private *priv, const char *model)
{
struct gfar_priv_grp *grp = &priv->gfargrp[priv->num_grps];
- u32 *queue_mask;
int i;
for (i = 0; i < GFAR_NUM_IRQS; i++) {
@@ -598,16 +667,52 @@ static int gfar_parse_group(struct device_node *np,
grp->priv = priv;
spin_lock_init(&grp->grplock);
if (priv->mode == MQ_MG_MODE) {
- queue_mask = (u32 *)of_get_property(np, "fsl,rx-bit-map", NULL);
- grp->rx_bit_map = queue_mask ?
- *queue_mask : (DEFAULT_MAPPING >> priv->num_grps);
- queue_mask = (u32 *)of_get_property(np, "fsl,tx-bit-map", NULL);
- grp->tx_bit_map = queue_mask ?
- *queue_mask : (DEFAULT_MAPPING >> priv->num_grps);
+ u32 *rxq_mask, *txq_mask;
+ rxq_mask = (u32 *)of_get_property(np, "fsl,rx-bit-map", NULL);
+ txq_mask = (u32 *)of_get_property(np, "fsl,tx-bit-map", NULL);
+
+ if (priv->poll_mode == GFAR_SQ_POLLING) {
+ /* One Q per interrupt group: Q0 to G0, Q1 to G1 */
+ grp->rx_bit_map = (DEFAULT_MAPPING >> priv->num_grps);
+ grp->tx_bit_map = (DEFAULT_MAPPING >> priv->num_grps);
+ } else { /* GFAR_MQ_POLLING */
+ grp->rx_bit_map = rxq_mask ?
+ *rxq_mask : (DEFAULT_MAPPING >> priv->num_grps);
+ grp->tx_bit_map = txq_mask ?
+ *txq_mask : (DEFAULT_MAPPING >> priv->num_grps);
+ }
} else {
grp->rx_bit_map = 0xFF;
grp->tx_bit_map = 0xFF;
}
+
+ /* bit_map's MSB is q0 (from q0 to q7) but, for_each_set_bit parses
+ * right to left, so we need to revert the 8 bits to get the q index
+ */
+ grp->rx_bit_map = bitrev8(grp->rx_bit_map);
+ grp->tx_bit_map = bitrev8(grp->tx_bit_map);
+
+ /* Calculate RSTAT, TSTAT, RQUEUE and TQUEUE values,
+ * also assign queues to groups
+ */
+ for_each_set_bit(i, &grp->rx_bit_map, priv->num_rx_queues) {
+ if (!grp->rx_queue)
+ grp->rx_queue = priv->rx_queue[i];
+ grp->num_rx_queues++;
+ grp->rstat |= (RSTAT_CLEAR_RHALT >> i);
+ priv->rqueue |= ((RQUEUE_EN0 | RQUEUE_EX0) >> i);
+ priv->rx_queue[i]->grp = grp;
+ }
+
+ for_each_set_bit(i, &grp->tx_bit_map, priv->num_tx_queues) {
+ if (!grp->tx_queue)
+ grp->tx_queue = priv->tx_queue[i];
+ grp->num_tx_queues++;
+ grp->tstat |= (TSTAT_CLEAR_THALT >> i);
+ priv->tqueue |= (TQUEUE_EN0 >> i);
+ priv->tx_queue[i]->grp = grp;
+ }
+
priv->num_grps++;
return 0;
@@ -628,13 +733,45 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
const u32 *stash_idx;
unsigned int num_tx_qs, num_rx_qs;
u32 *tx_queues, *rx_queues;
+ unsigned short mode, poll_mode;
if (!np || !of_device_is_available(np))
return -ENODEV;
- /* parse the num of tx and rx queues */
+ if (of_device_is_compatible(np, "fsl,etsec2")) {
+ mode = MQ_MG_MODE;
+ poll_mode = GFAR_SQ_POLLING;
+ } else {
+ mode = SQ_SG_MODE;
+ poll_mode = GFAR_SQ_POLLING;
+ }
+
+ /* parse the num of HW tx and rx queues */
tx_queues = (u32 *)of_get_property(np, "fsl,num_tx_queues", NULL);
- num_tx_qs = tx_queues ? *tx_queues : 1;
+ rx_queues = (u32 *)of_get_property(np, "fsl,num_rx_queues", NULL);
+
+ if (mode == SQ_SG_MODE) {
+ num_tx_qs = 1;
+ num_rx_qs = 1;
+ } else { /* MQ_MG_MODE */
+ /* get the actual number of supported groups */
+ unsigned int num_grps = of_get_available_child_count(np);
+
+ if (num_grps == 0 || num_grps > MAXGROUPS) {
+ dev_err(&ofdev->dev, "Invalid # of int groups(%d)\n",
+ num_grps);
+ pr_err("Cannot do alloc_etherdev, aborting\n");
+ return -EINVAL;
+ }
+
+ if (poll_mode == GFAR_SQ_POLLING) {
+ num_tx_qs = num_grps; /* one txq per int group */
+ num_rx_qs = num_grps; /* one rxq per int group */
+ } else { /* GFAR_MQ_POLLING */
+ num_tx_qs = tx_queues ? *tx_queues : 1;
+ num_rx_qs = rx_queues ? *rx_queues : 1;
+ }
+ }
if (num_tx_qs > MAX_TX_QS) {
pr_err("num_tx_qs(=%d) greater than MAX_TX_QS(=%d)\n",
@@ -643,9 +780,6 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
return -EINVAL;
}
- rx_queues = (u32 *)of_get_property(np, "fsl,num_rx_queues", NULL);
- num_rx_qs = rx_queues ? *rx_queues : 1;
-
if (num_rx_qs > MAX_RX_QS) {
pr_err("num_rx_qs(=%d) greater than MAX_RX_QS(=%d)\n",
num_rx_qs, MAX_RX_QS);
@@ -661,10 +795,20 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
priv = netdev_priv(dev);
priv->ndev = dev;
+ priv->mode = mode;
+ priv->poll_mode = poll_mode;
+
priv->num_tx_queues = num_tx_qs;
netif_set_real_num_rx_queues(dev, num_rx_qs);
priv->num_rx_queues = num_rx_qs;
- priv->num_grps = 0x0;
+
+ err = gfar_alloc_tx_queues(priv);
+ if (err)
+ goto tx_alloc_failed;
+
+ err = gfar_alloc_rx_queues(priv);
+ if (err)
+ goto rx_alloc_failed;
/* Init Rx queue filer rule set linked list */
INIT_LIST_HEAD(&priv->rx_list.list);
@@ -677,52 +821,18 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
priv->gfargrp[i].regs = NULL;
/* Parse and initialize group specific information */
- if (of_device_is_compatible(np, "fsl,etsec2")) {
- priv->mode = MQ_MG_MODE;
+ if (priv->mode == MQ_MG_MODE) {
for_each_child_of_node(np, child) {
err = gfar_parse_group(child, priv, model);
if (err)
goto err_grp_init;
}
- } else {
- priv->mode = SQ_SG_MODE;
+ } else { /* SQ_SG_MODE */
err = gfar_parse_group(np, priv, model);
if (err)
goto err_grp_init;
}
- for (i = 0; i < priv->num_tx_queues; i++)
- priv->tx_queue[i] = NULL;
- for (i = 0; i < priv->num_rx_queues; i++)
- priv->rx_queue[i] = NULL;
-
- for (i = 0; i < priv->num_tx_queues; i++) {
- priv->tx_queue[i] = kzalloc(sizeof(struct gfar_priv_tx_q),
- GFP_KERNEL);
- if (!priv->tx_queue[i]) {
- err = -ENOMEM;
- goto tx_alloc_failed;
- }
- priv->tx_queue[i]->tx_skbuff = NULL;
- priv->tx_queue[i]->qindex = i;
- priv->tx_queue[i]->dev = dev;
- spin_lock_init(&(priv->tx_queue[i]->txlock));
- }
-
- for (i = 0; i < priv->num_rx_queues; i++) {
- priv->rx_queue[i] = kzalloc(sizeof(struct gfar_priv_rx_q),
- GFP_KERNEL);
- if (!priv->rx_queue[i]) {
- err = -ENOMEM;
- goto rx_alloc_failed;
- }
- priv->rx_queue[i]->rx_skbuff = NULL;
- priv->rx_queue[i]->qindex = i;
- priv->rx_queue[i]->dev = dev;
- spin_lock_init(&(priv->rx_queue[i]->rxlock));
- }
-
-
stash = of_get_property(np, "bd-stash", NULL);
if (stash) {
@@ -749,17 +859,16 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
memcpy(dev->dev_addr, mac_addr, ETH_ALEN);
if (model && !strcasecmp(model, "TSEC"))
- priv->device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
+ priv->device_flags |= FSL_GIANFAR_DEV_HAS_GIGABIT |
FSL_GIANFAR_DEV_HAS_COALESCE |
FSL_GIANFAR_DEV_HAS_RMON |
FSL_GIANFAR_DEV_HAS_MULTI_INTR;
if (model && !strcasecmp(model, "eTSEC"))
- priv->device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
+ priv->device_flags |= FSL_GIANFAR_DEV_HAS_GIGABIT |
FSL_GIANFAR_DEV_HAS_COALESCE |
FSL_GIANFAR_DEV_HAS_RMON |
FSL_GIANFAR_DEV_HAS_MULTI_INTR |
- FSL_GIANFAR_DEV_HAS_PADDING |
FSL_GIANFAR_DEV_HAS_CSUM |
FSL_GIANFAR_DEV_HAS_VLAN |
FSL_GIANFAR_DEV_HAS_MAGIC_PACKET |
@@ -784,12 +893,12 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
return 0;
-rx_alloc_failed:
- free_rx_pointers(priv);
-tx_alloc_failed:
- free_tx_pointers(priv);
err_grp_init:
unmap_group_regs(priv);
+rx_alloc_failed:
+ gfar_free_rx_queues(priv);
+tx_alloc_failed:
+ gfar_free_tx_queues(priv);
free_gfar_dev(priv);
return err;
}
@@ -822,18 +931,16 @@ static int gfar_hwtstamp_set(struct net_device *netdev, struct ifreq *ifr)
switch (config.rx_filter) {
case HWTSTAMP_FILTER_NONE:
if (priv->hwts_rx_en) {
- stop_gfar(netdev);
priv->hwts_rx_en = 0;
- startup_gfar(netdev);
+ reset_gfar(netdev);
}
break;
default:
if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER))
return -ERANGE;
if (!priv->hwts_rx_en) {
- stop_gfar(netdev);
priv->hwts_rx_en = 1;
- startup_gfar(netdev);
+ reset_gfar(netdev);
}
config.rx_filter = HWTSTAMP_FILTER_ALL;
break;
@@ -875,19 +982,6 @@ static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return phy_mii_ioctl(priv->phydev, rq, cmd);
}
-static unsigned int reverse_bitmap(unsigned int bit_map, unsigned int max_qs)
-{
- unsigned int new_bit_map = 0x0;
- int mask = 0x1 << (max_qs - 1), i;
-
- for (i = 0; i < max_qs; i++) {
- if (bit_map & mask)
- new_bit_map = new_bit_map + (1 << i);
- mask = mask >> 0x1;
- }
- return new_bit_map;
-}
-
static u32 cluster_entry_per_class(struct gfar_private *priv, u32 rqfar,
u32 class)
{
@@ -1005,99 +1099,140 @@ static void gfar_detect_errata(struct gfar_private *priv)
priv->errata);
}
-/* Set up the ethernet device structure, private data,
- * and anything else we need before we start
- */
-static int gfar_probe(struct platform_device *ofdev)
+void gfar_mac_reset(struct gfar_private *priv)
{
+ struct gfar __iomem *regs = priv->gfargrp[0].regs;
u32 tempval;
- struct net_device *dev = NULL;
- struct gfar_private *priv = NULL;
- struct gfar __iomem *regs = NULL;
- int err = 0, i, grp_idx = 0;
- u32 rstat = 0, tstat = 0, rqueue = 0, tqueue = 0;
- u32 isrg = 0;
- u32 __iomem *baddr;
-
- err = gfar_of_init(ofdev, &dev);
-
- if (err)
- return err;
-
- priv = netdev_priv(dev);
- priv->ndev = dev;
- priv->ofdev = ofdev;
- priv->dev = &ofdev->dev;
- SET_NETDEV_DEV(dev, &ofdev->dev);
-
- spin_lock_init(&priv->bflock);
- INIT_WORK(&priv->reset_task, gfar_reset_task);
-
- platform_set_drvdata(ofdev, priv);
- regs = priv->gfargrp[0].regs;
-
- gfar_detect_errata(priv);
-
- /* Stop the DMA engine now, in case it was running before
- * (The firmware could have used it, and left it running).
- */
- gfar_halt(dev);
/* Reset MAC layer */
gfar_write(&regs->maccfg1, MACCFG1_SOFT_RESET);
/* We need to delay at least 3 TX clocks */
- udelay(2);
+ udelay(3);
- tempval = 0;
- if (!priv->pause_aneg_en && priv->tx_pause_en)
- tempval |= MACCFG1_TX_FLOW;
- if (!priv->pause_aneg_en && priv->rx_pause_en)
- tempval |= MACCFG1_RX_FLOW;
/* the soft reset bit is not self-resetting, so we need to
* clear it before resuming normal operation
*/
- gfar_write(&regs->maccfg1, tempval);
+ gfar_write(&regs->maccfg1, 0);
+
+ udelay(3);
+
+ /* Compute rx_buff_size based on config flags */
+ gfar_rx_buff_size_config(priv);
+
+ /* Initialize the max receive frame/buffer lengths */
+ gfar_write(&regs->maxfrm, priv->rx_buffer_size);
+ gfar_write(&regs->mrblr, priv->rx_buffer_size);
+
+ /* Initialize the Minimum Frame Length Register */
+ gfar_write(&regs->minflr, MINFLR_INIT_SETTINGS);
/* Initialize MACCFG2. */
tempval = MACCFG2_INIT_SETTINGS;
- if (gfar_has_errata(priv, GFAR_ERRATA_74))
+
+ /* If the mtu is larger than the max size for standard
+ * ethernet frames (ie, a jumbo frame), then set maccfg2
+ * to allow huge frames, and to check the length
+ */
+ if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE ||
+ gfar_has_errata(priv, GFAR_ERRATA_74))
tempval |= MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK;
+
gfar_write(&regs->maccfg2, tempval);
+ /* Clear mac addr hash registers */
+ gfar_write(&regs->igaddr0, 0);
+ gfar_write(&regs->igaddr1, 0);
+ gfar_write(&regs->igaddr2, 0);
+ gfar_write(&regs->igaddr3, 0);
+ gfar_write(&regs->igaddr4, 0);
+ gfar_write(&regs->igaddr5, 0);
+ gfar_write(&regs->igaddr6, 0);
+ gfar_write(&regs->igaddr7, 0);
+
+ gfar_write(&regs->gaddr0, 0);
+ gfar_write(&regs->gaddr1, 0);
+ gfar_write(&regs->gaddr2, 0);
+ gfar_write(&regs->gaddr3, 0);
+ gfar_write(&regs->gaddr4, 0);
+ gfar_write(&regs->gaddr5, 0);
+ gfar_write(&regs->gaddr6, 0);
+ gfar_write(&regs->gaddr7, 0);
+
+ if (priv->extended_hash)
+ gfar_clear_exact_match(priv->ndev);
+
+ gfar_mac_rx_config(priv);
+
+ gfar_mac_tx_config(priv);
+
+ gfar_set_mac_address(priv->ndev);
+
+ gfar_set_multi(priv->ndev);
+
+ /* clear ievent and imask before configuring coalescing */
+ gfar_ints_disable(priv);
+
+ /* Configure the coalescing support */
+ gfar_configure_coalescing_all(priv);
+}
+
+static void gfar_hw_init(struct gfar_private *priv)
+{
+ struct gfar __iomem *regs = priv->gfargrp[0].regs;
+ u32 attrs;
+
+ /* Stop the DMA engine now, in case it was running before
+ * (The firmware could have used it, and left it running).
+ */
+ gfar_halt(priv);
+
+ gfar_mac_reset(priv);
+
+ /* Zero out the rmon mib registers if it has them */
+ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
+ memset_io(&(regs->rmon), 0, sizeof(struct rmon_mib));
+
+ /* Mask off the CAM interrupts */
+ gfar_write(&regs->rmon.cam1, 0xffffffff);
+ gfar_write(&regs->rmon.cam2, 0xffffffff);
+ }
+
/* Initialize ECNTRL */
gfar_write(&regs->ecntrl, ECNTRL_INIT_SETTINGS);
- /* Set the dev->base_addr to the gfar reg region */
- dev->base_addr = (unsigned long) regs;
+ /* Set the extraction length and index */
+ attrs = ATTRELI_EL(priv->rx_stash_size) |
+ ATTRELI_EI(priv->rx_stash_index);
- /* Fill in the dev structure */
- dev->watchdog_timeo = TX_TIMEOUT;
- dev->mtu = 1500;
- dev->netdev_ops = &gfar_netdev_ops;
- dev->ethtool_ops = &gfar_ethtool_ops;
+ gfar_write(&regs->attreli, attrs);
- /* Register for napi ...We are registering NAPI for each grp */
- if (priv->mode == SQ_SG_MODE)
- netif_napi_add(dev, &priv->gfargrp[0].napi, gfar_poll_sq,
- GFAR_DEV_WEIGHT);
- else
- for (i = 0; i < priv->num_grps; i++)
- netif_napi_add(dev, &priv->gfargrp[i].napi, gfar_poll,
- GFAR_DEV_WEIGHT);
+ /* Start with defaults, and add stashing
+ * depending on driver parameters
+ */
+ attrs = ATTR_INIT_SETTINGS;
- if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
- dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
- NETIF_F_RXCSUM;
- dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG |
- NETIF_F_RXCSUM | NETIF_F_HIGHDMA;
- }
+ if (priv->bd_stash_en)
+ attrs |= ATTR_BDSTASH;
- if (priv->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {
- dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX |
- NETIF_F_HW_VLAN_CTAG_RX;
- dev->features |= NETIF_F_HW_VLAN_CTAG_RX;
- }
+ if (priv->rx_stash_size != 0)
+ attrs |= ATTR_BUFSTASH;
+
+ gfar_write(&regs->attr, attrs);
+
+ /* FIFO configs */
+ gfar_write(&regs->fifo_tx_thr, DEFAULT_FIFO_TX_THR);
+ gfar_write(&regs->fifo_tx_starve, DEFAULT_FIFO_TX_STARVE);
+ gfar_write(&regs->fifo_tx_starve_shutoff, DEFAULT_FIFO_TX_STARVE_OFF);
+
+ /* Program the interrupt steering regs, only for MG devices */
+ if (priv->num_grps > 1)
+ gfar_write_isrg(priv);
+}
+
+static void __init gfar_init_addr_hash_table(struct gfar_private *priv)
+{
+ struct gfar __iomem *regs = priv->gfargrp[0].regs;
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) {
priv->extended_hash = 1;
@@ -1133,68 +1268,81 @@ static int gfar_probe(struct platform_device *ofdev)
priv->hash_regs[6] = &regs->gaddr6;
priv->hash_regs[7] = &regs->gaddr7;
}
+}
- if (priv->device_flags & FSL_GIANFAR_DEV_HAS_PADDING)
- priv->padding = DEFAULT_PADDING;
- else
- priv->padding = 0;
+/* Set up the ethernet device structure, private data,
+ * and anything else we need before we start
+ */
+static int gfar_probe(struct platform_device *ofdev)
+{
+ struct net_device *dev = NULL;
+ struct gfar_private *priv = NULL;
+ int err = 0, i;
- if (dev->features & NETIF_F_IP_CSUM ||
- priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)
- dev->needed_headroom = GMAC_FCB_LEN;
+ err = gfar_of_init(ofdev, &dev);
- /* Program the isrg regs only if number of grps > 1 */
- if (priv->num_grps > 1) {
- baddr = &regs->isrg0;
- for (i = 0; i < priv->num_grps; i++) {
- isrg |= (priv->gfargrp[i].rx_bit_map << ISRG_SHIFT_RX);
- isrg |= (priv->gfargrp[i].tx_bit_map << ISRG_SHIFT_TX);
- gfar_write(baddr, isrg);
- baddr++;
- isrg = 0x0;
+ if (err)
+ return err;
+
+ priv = netdev_priv(dev);
+ priv->ndev = dev;
+ priv->ofdev = ofdev;
+ priv->dev = &ofdev->dev;
+ SET_NETDEV_DEV(dev, &ofdev->dev);
+
+ spin_lock_init(&priv->bflock);
+ INIT_WORK(&priv->reset_task, gfar_reset_task);
+
+ platform_set_drvdata(ofdev, priv);
+
+ gfar_detect_errata(priv);
+
+ /* Set the dev->base_addr to the gfar reg region */
+ dev->base_addr = (unsigned long) priv->gfargrp[0].regs;
+
+ /* Fill in the dev structure */
+ dev->watchdog_timeo = TX_TIMEOUT;
+ dev->mtu = 1500;
+ dev->netdev_ops = &gfar_netdev_ops;
+ dev->ethtool_ops = &gfar_ethtool_ops;
+
+ /* Register for napi ...We are registering NAPI for each grp */
+ for (i = 0; i < priv->num_grps; i++) {
+ if (priv->poll_mode == GFAR_SQ_POLLING) {
+ netif_napi_add(dev, &priv->gfargrp[i].napi_rx,
+ gfar_poll_rx_sq, GFAR_DEV_WEIGHT);
+ netif_napi_add(dev, &priv->gfargrp[i].napi_tx,
+ gfar_poll_tx_sq, 2);
+ } else {
+ netif_napi_add(dev, &priv->gfargrp[i].napi_rx,
+ gfar_poll_rx, GFAR_DEV_WEIGHT);
+ netif_napi_add(dev, &priv->gfargrp[i].napi_tx,
+ gfar_poll_tx, 2);
}
}
- /* Need to reverse the bit maps as bit_map's MSB is q0
- * but, for_each_set_bit parses from right to left, which
- * basically reverses the queue numbers
- */
- for (i = 0; i< priv->num_grps; i++) {
- priv->gfargrp[i].tx_bit_map =
- reverse_bitmap(priv->gfargrp[i].tx_bit_map, MAX_TX_QS);
- priv->gfargrp[i].rx_bit_map =
- reverse_bitmap(priv->gfargrp[i].rx_bit_map, MAX_RX_QS);
+ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
+ dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
+ NETIF_F_RXCSUM;
+ dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG |
+ NETIF_F_RXCSUM | NETIF_F_HIGHDMA;
}
- /* Calculate RSTAT, TSTAT, RQUEUE and TQUEUE values,
- * also assign queues to groups
- */
- for (grp_idx = 0; grp_idx < priv->num_grps; grp_idx++) {
- priv->gfargrp[grp_idx].num_rx_queues = 0x0;
-
- for_each_set_bit(i, &priv->gfargrp[grp_idx].rx_bit_map,
- priv->num_rx_queues) {
- priv->gfargrp[grp_idx].num_rx_queues++;
- priv->rx_queue[i]->grp = &priv->gfargrp[grp_idx];
- rstat = rstat | (RSTAT_CLEAR_RHALT >> i);
- rqueue = rqueue | ((RQUEUE_EN0 | RQUEUE_EX0) >> i);
- }
- priv->gfargrp[grp_idx].num_tx_queues = 0x0;
-
- for_each_set_bit(i, &priv->gfargrp[grp_idx].tx_bit_map,
- priv->num_tx_queues) {
- priv->gfargrp[grp_idx].num_tx_queues++;
- priv->tx_queue[i]->grp = &priv->gfargrp[grp_idx];
- tstat = tstat | (TSTAT_CLEAR_THALT >> i);
- tqueue = tqueue | (TQUEUE_EN0 >> i);
- }
- priv->gfargrp[grp_idx].rstat = rstat;
- priv->gfargrp[grp_idx].tstat = tstat;
- rstat = tstat =0;
+ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {
+ dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX;
+ dev->features |= NETIF_F_HW_VLAN_CTAG_RX;
}
- gfar_write(&regs->rqueue, rqueue);
- gfar_write(&regs->tqueue, tqueue);
+ gfar_init_addr_hash_table(priv);
+
+ /* Insert receive time stamps into padding alignment bytes */
+ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)
+ priv->padding = 8;
+
+ if (dev->features & NETIF_F_IP_CSUM ||
+ priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)
+ dev->needed_headroom = GMAC_FCB_LEN;
priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE;
@@ -1220,8 +1368,9 @@ static int gfar_probe(struct platform_device *ofdev)
if (priv->num_tx_queues == 1)
priv->prio_sched_en = 1;
- /* Carrier starts down, phylib will bring it up */
- netif_carrier_off(dev);
+ set_bit(GFAR_DOWN, &priv->state);
+
+ gfar_hw_init(priv);
err = register_netdev(dev);
@@ -1230,6 +1379,9 @@ static int gfar_probe(struct platform_device *ofdev)
goto register_fail;
}
+ /* Carrier starts down, phylib will bring it up */
+ netif_carrier_off(dev);
+
device_init_wakeup(&dev->dev,
priv->device_flags &
FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
@@ -1251,9 +1403,6 @@ static int gfar_probe(struct platform_device *ofdev)
/* Initialize the filer table */
gfar_init_filer_table(priv);
- /* Create all the sysfs files */
- gfar_init_sysfs(dev);
-
/* Print out the device info */
netdev_info(dev, "mac: %pM\n", dev->dev_addr);
@@ -1272,8 +1421,8 @@ static int gfar_probe(struct platform_device *ofdev)
register_fail:
unmap_group_regs(priv);
- free_tx_pointers(priv);
- free_rx_pointers(priv);
+ gfar_free_rx_queues(priv);
+ gfar_free_tx_queues(priv);
if (priv->phy_node)
of_node_put(priv->phy_node);
if (priv->tbi_node)
@@ -1293,6 +1442,8 @@ static int gfar_remove(struct platform_device *ofdev)
unregister_netdev(priv->ndev);
unmap_group_regs(priv);
+ gfar_free_rx_queues(priv);
+ gfar_free_tx_queues(priv);
free_gfar_dev(priv);
return 0;
@@ -1318,9 +1469,8 @@ static int gfar_suspend(struct device *dev)
local_irq_save(flags);
lock_tx_qs(priv);
- lock_rx_qs(priv);
- gfar_halt_nodisable(ndev);
+ gfar_halt_nodisable(priv);
/* Disable Tx, and Rx if wake-on-LAN is disabled. */
tempval = gfar_read(&regs->maccfg1);
@@ -1332,7 +1482,6 @@ static int gfar_suspend(struct device *dev)
gfar_write(&regs->maccfg1, tempval);
- unlock_rx_qs(priv);
unlock_tx_qs(priv);
local_irq_restore(flags);
@@ -1378,15 +1527,13 @@ static int gfar_resume(struct device *dev)
*/
local_irq_save(flags);
lock_tx_qs(priv);
- lock_rx_qs(priv);
tempval = gfar_read(&regs->maccfg2);
tempval &= ~MACCFG2_MPEN;
gfar_write(&regs->maccfg2, tempval);
- gfar_start(ndev);
+ gfar_start(priv);
- unlock_rx_qs(priv);
unlock_tx_qs(priv);
local_irq_restore(flags);
@@ -1413,10 +1560,11 @@ static int gfar_restore(struct device *dev)
return -ENOMEM;
}
- init_registers(ndev);
- gfar_set_mac_address(ndev);
- gfar_init_mac(ndev);
- gfar_start(ndev);
+ gfar_mac_reset(priv);
+
+ gfar_init_tx_rx_base(priv);
+
+ gfar_start(priv);
priv->oldlink = 0;
priv->oldspeed = 0;
@@ -1574,57 +1722,6 @@ static void gfar_configure_serdes(struct net_device *dev)
BMCR_SPEED1000);
}
-static void init_registers(struct net_device *dev)
-{
- struct gfar_private *priv = netdev_priv(dev);
- struct gfar __iomem *regs = NULL;
- int i;
-
- for (i = 0; i < priv->num_grps; i++) {
- regs = priv->gfargrp[i].regs;
- /* Clear IEVENT */
- gfar_write(&regs->ievent, IEVENT_INIT_CLEAR);
-
- /* Initialize IMASK */
- gfar_write(&regs->imask, IMASK_INIT_CLEAR);
- }
-
- regs = priv->gfargrp[0].regs;
- /* Init hash registers to zero */
- gfar_write(&regs->igaddr0, 0);
- gfar_write(&regs->igaddr1, 0);
- gfar_write(&regs->igaddr2, 0);
- gfar_write(&regs->igaddr3, 0);
- gfar_write(&regs->igaddr4, 0);
- gfar_write(&regs->igaddr5, 0);
- gfar_write(&regs->igaddr6, 0);
- gfar_write(&regs->igaddr7, 0);
-
- gfar_write(&regs->gaddr0, 0);
- gfar_write(&regs->gaddr1, 0);
- gfar_write(&regs->gaddr2, 0);
- gfar_write(&regs->gaddr3, 0);
- gfar_write(&regs->gaddr4, 0);
- gfar_write(&regs->gaddr5, 0);
- gfar_write(&regs->gaddr6, 0);
- gfar_write(&regs->gaddr7, 0);
-
- /* Zero out the rmon mib registers if it has them */
- if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
- memset_io(&(regs->rmon), 0, sizeof (struct rmon_mib));
-
- /* Mask off the CAM interrupts */
- gfar_write(&regs->rmon.cam1, 0xffffffff);
- gfar_write(&regs->rmon.cam2, 0xffffffff);
- }
-
- /* Initialize the max receive buffer length */
- gfar_write(&regs->mrblr, priv->rx_buffer_size);
-
- /* Initialize the Minimum Frame Length Register */
- gfar_write(&regs->minflr, MINFLR_INIT_SETTINGS);
-}
-
static int __gfar_is_rx_idle(struct gfar_private *priv)
{
u32 res;
@@ -1648,23 +1745,13 @@ static int __gfar_is_rx_idle(struct gfar_private *priv)
}
/* Halt the receive and transmit queues */
-static void gfar_halt_nodisable(struct net_device *dev)
+static void gfar_halt_nodisable(struct gfar_private *priv)
{
- struct gfar_private *priv = netdev_priv(dev);
- struct gfar __iomem *regs = NULL;
+ struct gfar __iomem *regs = priv->gfargrp[0].regs;
u32 tempval;
- int i;
-
- for (i = 0; i < priv->num_grps; i++) {
- regs = priv->gfargrp[i].regs;
- /* Mask all interrupts */
- gfar_write(&regs->imask, IMASK_INIT_CLEAR);
- /* Clear all interrupts */
- gfar_write(&regs->ievent, IEVENT_INIT_CLEAR);
- }
+ gfar_ints_disable(priv);
- regs = priv->gfargrp[0].regs;
/* Stop the DMA, and wait for it to stop */
tempval = gfar_read(&regs->dmactrl);
if ((tempval & (DMACTRL_GRS | DMACTRL_GTS)) !=
@@ -1685,56 +1772,41 @@ static void gfar_halt_nodisable(struct net_device *dev)
}
/* Halt the receive and transmit queues */
-void gfar_halt(struct net_device *dev)
+void gfar_halt(struct gfar_private *priv)
{
- struct gfar_private *priv = netdev_priv(dev);
struct gfar __iomem *regs = priv->gfargrp[0].regs;
u32 tempval;
- gfar_halt_nodisable(dev);
+ /* Dissable the Rx/Tx hw queues */
+ gfar_write(&regs->rqueue, 0);
+ gfar_write(&regs->tqueue, 0);
- /* Disable Rx and Tx */
+ mdelay(10);
+
+ gfar_halt_nodisable(priv);
+
+ /* Disable Rx/Tx DMA */
tempval = gfar_read(&regs->maccfg1);
tempval &= ~(MACCFG1_RX_EN | MACCFG1_TX_EN);
gfar_write(&regs->maccfg1, tempval);
}
-static void free_grp_irqs(struct gfar_priv_grp *grp)
-{
- free_irq(gfar_irq(grp, TX)->irq, grp);
- free_irq(gfar_irq(grp, RX)->irq, grp);
- free_irq(gfar_irq(grp, ER)->irq, grp);
-}
-
void stop_gfar(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
- unsigned long flags;
- int i;
-
- phy_stop(priv->phydev);
+ netif_tx_stop_all_queues(dev);
- /* Lock it down */
- local_irq_save(flags);
- lock_tx_qs(priv);
- lock_rx_qs(priv);
+ smp_mb__before_clear_bit();
+ set_bit(GFAR_DOWN, &priv->state);
+ smp_mb__after_clear_bit();
- gfar_halt(dev);
+ disable_napi(priv);
- unlock_rx_qs(priv);
- unlock_tx_qs(priv);
- local_irq_restore(flags);
+ /* disable ints and gracefully shut down Rx/Tx DMA */
+ gfar_halt(priv);
- /* Free the IRQs */
- if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
- for (i = 0; i < priv->num_grps; i++)
- free_grp_irqs(&priv->gfargrp[i]);
- } else {
- for (i = 0; i < priv->num_grps; i++)
- free_irq(gfar_irq(&priv->gfargrp[i], TX)->irq,
- &priv->gfargrp[i]);
- }
+ phy_stop(priv->phydev);
free_skb_resources(priv);
}
@@ -1825,17 +1897,15 @@ static void free_skb_resources(struct gfar_private *priv)
priv->tx_queue[0]->tx_bd_dma_base);
}
-void gfar_start(struct net_device *dev)
+void gfar_start(struct gfar_private *priv)
{
- struct gfar_private *priv = netdev_priv(dev);
struct gfar __iomem *regs = priv->gfargrp[0].regs;
u32 tempval;
int i = 0;
- /* Enable Rx and Tx in MACCFG1 */
- tempval = gfar_read(&regs->maccfg1);
- tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
- gfar_write(&regs->maccfg1, tempval);
+ /* Enable Rx/Tx hw queues */
+ gfar_write(&regs->rqueue, priv->rqueue);
+ gfar_write(&regs->tqueue, priv->tqueue);
/* Initialize DMACTRL to have WWR and WOP */
tempval = gfar_read(&regs->dmactrl);
@@ -1852,52 +1922,23 @@ void gfar_start(struct net_device *dev)
/* Clear THLT/RHLT, so that the DMA starts polling now */
gfar_write(&regs->tstat, priv->gfargrp[i].tstat);
gfar_write(&regs->rstat, priv->gfargrp[i].rstat);
- /* Unmask the interrupts we look for */
- gfar_write(&regs->imask, IMASK_DEFAULT);
}
- dev->trans_start = jiffies; /* prevent tx timeout */
-}
-
-static void gfar_configure_coalescing(struct gfar_private *priv,
- unsigned long tx_mask, unsigned long rx_mask)
-{
- struct gfar __iomem *regs = priv->gfargrp[0].regs;
- u32 __iomem *baddr;
-
- if (priv->mode == MQ_MG_MODE) {
- int i = 0;
-
- baddr = &regs->txic0;
- for_each_set_bit(i, &tx_mask, priv->num_tx_queues) {
- gfar_write(baddr + i, 0);
- if (likely(priv->tx_queue[i]->txcoalescing))
- gfar_write(baddr + i, priv->tx_queue[i]->txic);
- }
+ /* Enable Rx/Tx DMA */
+ tempval = gfar_read(&regs->maccfg1);
+ tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
+ gfar_write(&regs->maccfg1, tempval);
- baddr = &regs->rxic0;
- for_each_set_bit(i, &rx_mask, priv->num_rx_queues) {
- gfar_write(baddr + i, 0);
- if (likely(priv->rx_queue[i]->rxcoalescing))
- gfar_write(baddr + i, priv->rx_queue[i]->rxic);
- }
- } else {
- /* Backward compatible case -- even if we enable
- * multiple queues, there's only single reg to program
- */
- gfar_write(&regs->txic, 0);
- if (likely(priv->tx_queue[0]->txcoalescing))
- gfar_write(&regs->txic, priv->tx_queue[0]->txic);
+ gfar_ints_enable(priv);
- gfar_write(&regs->rxic, 0);
- if (unlikely(priv->rx_queue[0]->rxcoalescing))
- gfar_write(&regs->rxic, priv->rx_queue[0]->rxic);
- }
+ priv->ndev->trans_start = jiffies; /* prevent tx timeout */
}
-void gfar_configure_coalescing_all(struct gfar_private *priv)
+static void free_grp_irqs(struct gfar_priv_grp *grp)
{
- gfar_configure_coalescing(priv, 0xFF, 0xFF);
+ free_irq(gfar_irq(grp, TX)->irq, grp);
+ free_irq(gfar_irq(grp, RX)->irq, grp);
+ free_irq(gfar_irq(grp, ER)->irq, grp);
}
static int register_grp_irqs(struct gfar_priv_grp *grp)
@@ -1956,46 +1997,65 @@ err_irq_fail:
}
-/* Bring the controller up and running */
-int startup_gfar(struct net_device *ndev)
+static void gfar_free_irq(struct gfar_private *priv)
{
- struct gfar_private *priv = netdev_priv(ndev);
- struct gfar __iomem *regs = NULL;
- int err, i, j;
+ int i;
- for (i = 0; i < priv->num_grps; i++) {
- regs= priv->gfargrp[i].regs;
- gfar_write(&regs->imask, IMASK_INIT_CLEAR);
+ /* Free the IRQs */
+ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
+ for (i = 0; i < priv->num_grps; i++)
+ free_grp_irqs(&priv->gfargrp[i]);
+ } else {
+ for (i = 0; i < priv->num_grps; i++)
+ free_irq(gfar_irq(&priv->gfargrp[i], TX)->irq,
+ &priv->gfargrp[i]);
}
+}
- regs= priv->gfargrp[0].regs;
- err = gfar_alloc_skb_resources(ndev);
- if (err)
- return err;
-
- gfar_init_mac(ndev);
+static int gfar_request_irq(struct gfar_private *priv)
+{
+ int err, i, j;
for (i = 0; i < priv->num_grps; i++) {
err = register_grp_irqs(&priv->gfargrp[i]);
if (err) {
for (j = 0; j < i; j++)
free_grp_irqs(&priv->gfargrp[j]);
- goto irq_fail;
+ return err;
}
}
- /* Start the controller */
- gfar_start(ndev);
+ return 0;
+}
+
+/* Bring the controller up and running */
+int startup_gfar(struct net_device *ndev)
+{
+ struct gfar_private *priv = netdev_priv(ndev);
+ int err;
+
+ gfar_mac_reset(priv);
+
+ err = gfar_alloc_skb_resources(ndev);
+ if (err)
+ return err;
+
+ gfar_init_tx_rx_base(priv);
+
+ smp_mb__before_clear_bit();
+ clear_bit(GFAR_DOWN, &priv->state);
+ smp_mb__after_clear_bit();
+
+ /* Start Rx/Tx DMA and enable the interrupts */
+ gfar_start(priv);
phy_start(priv->phydev);
- gfar_configure_coalescing_all(priv);
+ enable_napi(priv);
- return 0;
+ netif_tx_wake_all_queues(ndev);
-irq_fail:
- free_skb_resources(priv);
- return err;
+ return 0;
}
/* Called when something needs to use the ethernet device
@@ -2006,27 +2066,17 @@ static int gfar_enet_open(struct net_device *dev)
struct gfar_private *priv = netdev_priv(dev);
int err;
- enable_napi(priv);
-
- /* Initialize a bunch of registers */
- init_registers(dev);
-
- gfar_set_mac_address(dev);
-
err = init_phy(dev);
+ if (err)
+ return err;
- if (err) {
- disable_napi(priv);
+ err = gfar_request_irq(priv);
+ if (err)
return err;
- }
err = startup_gfar(dev);
- if (err) {
- disable_napi(priv);
+ if (err)
return err;
- }
-
- netif_tx_start_all_queues(dev);
device_set_wakeup_enable(&dev->dev, priv->wol_en);
@@ -2152,13 +2202,13 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb_new = skb_realloc_headroom(skb, fcb_len);
if (!skb_new) {
dev->stats.tx_errors++;
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
if (skb->sk)
skb_set_owner_w(skb_new, skb->sk);
- consume_skb(skb);
+ dev_consume_skb_any(skb);
skb = skb_new;
}
@@ -2351,8 +2401,6 @@ static int gfar_close(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
- disable_napi(priv);
-
cancel_work_sync(&priv->reset_task);
stop_gfar(dev);
@@ -2360,7 +2408,7 @@ static int gfar_close(struct net_device *dev)
phy_disconnect(priv->phydev);
priv->phydev = NULL;
- netif_tx_stop_all_queues(dev);
+ gfar_free_irq(priv);
return 0;
}
@@ -2373,77 +2421,9 @@ static int gfar_set_mac_address(struct net_device *dev)
return 0;
}
-/* Check if rx parser should be activated */
-void gfar_check_rx_parser_mode(struct gfar_private *priv)
-{
- struct gfar __iomem *regs;
- u32 tempval;
-
- regs = priv->gfargrp[0].regs;
-
- tempval = gfar_read(&regs->rctrl);
- /* If parse is no longer required, then disable parser */
- if (tempval & RCTRL_REQ_PARSER) {
- tempval |= RCTRL_PRSDEP_INIT;
- priv->uses_rxfcb = 1;
- } else {
- tempval &= ~RCTRL_PRSDEP_INIT;
- priv->uses_rxfcb = 0;
- }
- gfar_write(&regs->rctrl, tempval);
-}
-
-/* Enables and disables VLAN insertion/extraction */
-void gfar_vlan_mode(struct net_device *dev, netdev_features_t features)
-{
- struct gfar_private *priv = netdev_priv(dev);
- struct gfar __iomem *regs = NULL;
- unsigned long flags;
- u32 tempval;
-
- regs = priv->gfargrp[0].regs;
- local_irq_save(flags);
- lock_rx_qs(priv);
-
- if (features & NETIF_F_HW_VLAN_CTAG_TX) {
- /* Enable VLAN tag insertion */
- tempval = gfar_read(&regs->tctrl);
- tempval |= TCTRL_VLINS;
- gfar_write(&regs->tctrl, tempval);
- } else {
- /* Disable VLAN tag insertion */
- tempval = gfar_read(&regs->tctrl);
- tempval &= ~TCTRL_VLINS;
- gfar_write(&regs->tctrl, tempval);
- }
-
- if (features & NETIF_F_HW_VLAN_CTAG_RX) {
- /* Enable VLAN tag extraction */
- tempval = gfar_read(&regs->rctrl);
- tempval |= (RCTRL_VLEX | RCTRL_PRSDEP_INIT);
- gfar_write(&regs->rctrl, tempval);
- priv->uses_rxfcb = 1;
- } else {
- /* Disable VLAN tag extraction */
- tempval = gfar_read(&regs->rctrl);
- tempval &= ~RCTRL_VLEX;
- gfar_write(&regs->rctrl, tempval);
-
- gfar_check_rx_parser_mode(priv);
- }
-
- gfar_change_mtu(dev, dev->mtu);
-
- unlock_rx_qs(priv);
- local_irq_restore(flags);
-}
-
static int gfar_change_mtu(struct net_device *dev, int new_mtu)
{
- int tempsize, tempval;
struct gfar_private *priv = netdev_priv(dev);
- struct gfar __iomem *regs = priv->gfargrp[0].regs;
- int oldsize = priv->rx_buffer_size;
int frame_size = new_mtu + ETH_HLEN;
if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) {
@@ -2451,45 +2431,33 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu)
return -EINVAL;
}
- if (priv->uses_rxfcb)
- frame_size += GMAC_FCB_LEN;
+ while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state))
+ cpu_relax();
- frame_size += priv->padding;
-
- tempsize = (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) +
- INCREMENTAL_BUFFER_SIZE;
-
- /* Only stop and start the controller if it isn't already
- * stopped, and we changed something
- */
- if ((oldsize != tempsize) && (dev->flags & IFF_UP))
+ if (dev->flags & IFF_UP)
stop_gfar(dev);
- priv->rx_buffer_size = tempsize;
-
dev->mtu = new_mtu;
- gfar_write(&regs->mrblr, priv->rx_buffer_size);
- gfar_write(&regs->maxfrm, priv->rx_buffer_size);
+ if (dev->flags & IFF_UP)
+ startup_gfar(dev);
- /* If the mtu is larger than the max size for standard
- * ethernet frames (ie, a jumbo frame), then set maccfg2
- * to allow huge frames, and to check the length
- */
- tempval = gfar_read(&regs->maccfg2);
+ clear_bit_unlock(GFAR_RESETTING, &priv->state);
- if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE ||
- gfar_has_errata(priv, GFAR_ERRATA_74))
- tempval |= (MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK);
- else
- tempval &= ~(MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK);
+ return 0;
+}
- gfar_write(&regs->maccfg2, tempval);
+void reset_gfar(struct net_device *ndev)
+{
+ struct gfar_private *priv = netdev_priv(ndev);
- if ((oldsize != tempsize) && (dev->flags & IFF_UP))
- startup_gfar(dev);
+ while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state))
+ cpu_relax();
- return 0;
+ stop_gfar(ndev);
+ startup_gfar(ndev);
+
+ clear_bit_unlock(GFAR_RESETTING, &priv->state);
}
/* gfar_reset_task gets scheduled when a packet has not been
@@ -2501,16 +2469,7 @@ static void gfar_reset_task(struct work_struct *work)
{
struct gfar_private *priv = container_of(work, struct gfar_private,
reset_task);
- struct net_device *dev = priv->ndev;
-
- if (dev->flags & IFF_UP) {
- netif_tx_stop_all_queues(dev);
- stop_gfar(dev);
- startup_gfar(dev);
- netif_tx_start_all_queues(dev);
- }
-
- netif_tx_schedule_all(dev);
+ reset_gfar(priv->ndev);
}
static void gfar_timeout(struct net_device *dev)
@@ -2623,8 +2582,10 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
}
/* If we freed a buffer, we can restart transmission, if necessary */
- if (netif_tx_queue_stopped(txq) && tx_queue->num_txbdfree)
- netif_wake_subqueue(dev, tqi);
+ if (tx_queue->num_txbdfree &&
+ netif_tx_queue_stopped(txq) &&
+ !(test_bit(GFAR_DOWN, &priv->state)))
+ netif_wake_subqueue(priv->ndev, tqi);
/* Update dirty indicators */
tx_queue->skb_dirtytx = skb_dirtytx;
@@ -2633,31 +2594,6 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
netdev_tx_completed_queue(txq, howmany, bytes_sent);
}
-static void gfar_schedule_cleanup(struct gfar_priv_grp *gfargrp)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&gfargrp->grplock, flags);
- if (napi_schedule_prep(&gfargrp->napi)) {
- gfar_write(&gfargrp->regs->imask, IMASK_RTX_DISABLED);
- __napi_schedule(&gfargrp->napi);
- } else {
- /* Clear IEVENT, so interrupts aren't called again
- * because of the packets that have already arrived.
- */
- gfar_write(&gfargrp->regs->ievent, IEVENT_RTX_MASK);
- }
- spin_unlock_irqrestore(&gfargrp->grplock, flags);
-
-}
-
-/* Interrupt Handler for Transmit complete */
-static irqreturn_t gfar_transmit(int irq, void *grp_id)
-{
- gfar_schedule_cleanup((struct gfar_priv_grp *)grp_id);
- return IRQ_HANDLED;
-}
-
static void gfar_new_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp,
struct sk_buff *skb)
{
@@ -2728,7 +2664,48 @@ static inline void count_errors(unsigned short status, struct net_device *dev)
irqreturn_t gfar_receive(int irq, void *grp_id)
{
- gfar_schedule_cleanup((struct gfar_priv_grp *)grp_id);
+ struct gfar_priv_grp *grp = (struct gfar_priv_grp *)grp_id;
+ unsigned long flags;
+ u32 imask;
+
+ if (likely(napi_schedule_prep(&grp->napi_rx))) {
+ spin_lock_irqsave(&grp->grplock, flags);
+ imask = gfar_read(&grp->regs->imask);
+ imask &= IMASK_RX_DISABLED;
+ gfar_write(&grp->regs->imask, imask);
+ spin_unlock_irqrestore(&grp->grplock, flags);
+ __napi_schedule(&grp->napi_rx);
+ } else {
+ /* Clear IEVENT, so interrupts aren't called again
+ * because of the packets that have already arrived.
+ */
+ gfar_write(&grp->regs->ievent, IEVENT_RX_MASK);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/* Interrupt Handler for Transmit complete */
+static irqreturn_t gfar_transmit(int irq, void *grp_id)
+{
+ struct gfar_priv_grp *grp = (struct gfar_priv_grp *)grp_id;
+ unsigned long flags;
+ u32 imask;
+
+ if (likely(napi_schedule_prep(&grp->napi_tx))) {
+ spin_lock_irqsave(&grp->grplock, flags);
+ imask = gfar_read(&grp->regs->imask);
+ imask &= IMASK_TX_DISABLED;
+ gfar_write(&grp->regs->imask, imask);
+ spin_unlock_irqrestore(&grp->grplock, flags);
+ __napi_schedule(&grp->napi_tx);
+ } else {
+ /* Clear IEVENT, so interrupts aren't called again
+ * because of the packets that have already arrived.
+ */
+ gfar_write(&grp->regs->ievent, IEVENT_TX_MASK);
+ }
+
return IRQ_HANDLED;
}
@@ -2852,7 +2829,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
rx_queue->stats.rx_bytes += pkt_len;
skb_record_rx_queue(skb, rx_queue->qindex);
gfar_process_frame(dev, skb, amount_pull,
- &rx_queue->grp->napi);
+ &rx_queue->grp->napi_rx);
} else {
netif_warn(priv, rx_err, dev, "Missing skb!\n");
@@ -2881,66 +2858,81 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
return howmany;
}
-static int gfar_poll_sq(struct napi_struct *napi, int budget)
+static int gfar_poll_rx_sq(struct napi_struct *napi, int budget)
{
struct gfar_priv_grp *gfargrp =
- container_of(napi, struct gfar_priv_grp, napi);
+ container_of(napi, struct gfar_priv_grp, napi_rx);
struct gfar __iomem *regs = gfargrp->regs;
- struct gfar_priv_tx_q *tx_queue = gfargrp->priv->tx_queue[0];
- struct gfar_priv_rx_q *rx_queue = gfargrp->priv->rx_queue[0];
+ struct gfar_priv_rx_q *rx_queue = gfargrp->rx_queue;
int work_done = 0;
/* Clear IEVENT, so interrupts aren't called again
* because of the packets that have already arrived
*/
- gfar_write(&regs->ievent, IEVENT_RTX_MASK);
-
- /* run Tx cleanup to completion */
- if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx])
- gfar_clean_tx_ring(tx_queue);
+ gfar_write(&regs->ievent, IEVENT_RX_MASK);
work_done = gfar_clean_rx_ring(rx_queue, budget);
if (work_done < budget) {
+ u32 imask;
napi_complete(napi);
/* Clear the halt bit in RSTAT */
gfar_write(&regs->rstat, gfargrp->rstat);
- gfar_write(&regs->imask, IMASK_DEFAULT);
-
- /* If we are coalescing interrupts, update the timer
- * Otherwise, clear it
- */
- gfar_write(&regs->txic, 0);
- if (likely(tx_queue->txcoalescing))
- gfar_write(&regs->txic, tx_queue->txic);
-
- gfar_write(&regs->rxic, 0);
- if (unlikely(rx_queue->rxcoalescing))
- gfar_write(&regs->rxic, rx_queue->rxic);
+ spin_lock_irq(&gfargrp->grplock);
+ imask = gfar_read(&regs->imask);
+ imask |= IMASK_RX_DEFAULT;
+ gfar_write(&regs->imask, imask);
+ spin_unlock_irq(&gfargrp->grplock);
}
return work_done;
}
-static int gfar_poll(struct napi_struct *napi, int budget)
+static int gfar_poll_tx_sq(struct napi_struct *napi, int budget)
+{
+ struct gfar_priv_grp *gfargrp =
+ container_of(napi, struct gfar_priv_grp, napi_tx);
+ struct gfar __iomem *regs = gfargrp->regs;
+ struct gfar_priv_tx_q *tx_queue = gfargrp->tx_queue;
+ u32 imask;
+
+ /* Clear IEVENT, so interrupts aren't called again
+ * because of the packets that have already arrived
+ */
+ gfar_write(&regs->ievent, IEVENT_TX_MASK);
+
+ /* run Tx cleanup to completion */
+ if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx])
+ gfar_clean_tx_ring(tx_queue);
+
+ napi_complete(napi);
+
+ spin_lock_irq(&gfargrp->grplock);
+ imask = gfar_read(&regs->imask);
+ imask |= IMASK_TX_DEFAULT;
+ gfar_write(&regs->imask, imask);
+ spin_unlock_irq(&gfargrp->grplock);
+
+ return 0;
+}
+
+static int gfar_poll_rx(struct napi_struct *napi, int budget)
{
struct gfar_priv_grp *gfargrp =
- container_of(napi, struct gfar_priv_grp, napi);
+ container_of(napi, struct gfar_priv_grp, napi_rx);
struct gfar_private *priv = gfargrp->priv;
struct gfar __iomem *regs = gfargrp->regs;
- struct gfar_priv_tx_q *tx_queue = NULL;
struct gfar_priv_rx_q *rx_queue = NULL;
int work_done = 0, work_done_per_q = 0;
int i, budget_per_q = 0;
- int has_tx_work = 0;
unsigned long rstat_rxf;
int num_act_queues;
/* Clear IEVENT, so interrupts aren't called again
* because of the packets that have already arrived
*/
- gfar_write(&regs->ievent, IEVENT_RTX_MASK);
+ gfar_write(&regs->ievent, IEVENT_RX_MASK);
rstat_rxf = gfar_read(&regs->rstat) & RSTAT_RXF_MASK;
@@ -2948,15 +2940,6 @@ static int gfar_poll(struct napi_struct *napi, int budget)
if (num_act_queues)
budget_per_q = budget/num_act_queues;
- for_each_set_bit(i, &gfargrp->tx_bit_map, priv->num_tx_queues) {
- tx_queue = priv->tx_queue[i];
- /* run Tx cleanup to completion */
- if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) {
- gfar_clean_tx_ring(tx_queue);
- has_tx_work = 1;
- }
- }
-
for_each_set_bit(i, &gfargrp->rx_bit_map, priv->num_rx_queues) {
/* skip queue if not active */
if (!(rstat_rxf & (RSTAT_CLEAR_RXF0 >> i)))
@@ -2979,25 +2962,62 @@ static int gfar_poll(struct napi_struct *napi, int budget)
}
}
- if (!num_act_queues && !has_tx_work) {
-
+ if (!num_act_queues) {
+ u32 imask;
napi_complete(napi);
/* Clear the halt bit in RSTAT */
gfar_write(&regs->rstat, gfargrp->rstat);
- gfar_write(&regs->imask, IMASK_DEFAULT);
-
- /* If we are coalescing interrupts, update the timer
- * Otherwise, clear it
- */
- gfar_configure_coalescing(priv, gfargrp->rx_bit_map,
- gfargrp->tx_bit_map);
+ spin_lock_irq(&gfargrp->grplock);
+ imask = gfar_read(&regs->imask);
+ imask |= IMASK_RX_DEFAULT;
+ gfar_write(&regs->imask, imask);
+ spin_unlock_irq(&gfargrp->grplock);
}
return work_done;
}
+static int gfar_poll_tx(struct napi_struct *napi, int budget)
+{
+ struct gfar_priv_grp *gfargrp =
+ container_of(napi, struct gfar_priv_grp, napi_tx);
+ struct gfar_private *priv = gfargrp->priv;
+ struct gfar __iomem *regs = gfargrp->regs;
+ struct gfar_priv_tx_q *tx_queue = NULL;
+ int has_tx_work = 0;
+ int i;
+
+ /* Clear IEVENT, so interrupts aren't called again
+ * because of the packets that have already arrived
+ */
+ gfar_write(&regs->ievent, IEVENT_TX_MASK);
+
+ for_each_set_bit(i, &gfargrp->tx_bit_map, priv->num_tx_queues) {
+ tx_queue = priv->tx_queue[i];
+ /* run Tx cleanup to completion */
+ if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) {
+ gfar_clean_tx_ring(tx_queue);
+ has_tx_work = 1;
+ }
+ }
+
+ if (!has_tx_work) {
+ u32 imask;
+ napi_complete(napi);
+
+ spin_lock_irq(&gfargrp->grplock);
+ imask = gfar_read(&regs->imask);
+ imask |= IMASK_TX_DEFAULT;
+ gfar_write(&regs->imask, imask);
+ spin_unlock_irq(&gfargrp->grplock);
+ }
+
+ return 0;
+}
+
+
#ifdef CONFIG_NET_POLL_CONTROLLER
/* Polling 'interrupt' - used by things like netconsole to send skbs
* without having to re-enable interrupts. It's not called while
@@ -3101,12 +3121,11 @@ static void adjust_link(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
struct gfar __iomem *regs = priv->gfargrp[0].regs;
- unsigned long flags;
struct phy_device *phydev = priv->phydev;
int new_state = 0;
- local_irq_save(flags);
- lock_tx_qs(priv);
+ if (test_bit(GFAR_RESETTING, &priv->state))
+ return;
if (phydev->link) {
u32 tempval1 = gfar_read(&regs->maccfg1);
@@ -3178,8 +3197,6 @@ static void adjust_link(struct net_device *dev)
if (new_state && netif_msg_link(priv))
phy_print_status(phydev);
- unlock_tx_qs(priv);
- local_irq_restore(flags);
}
/* Update the hash table based on the current list of multicast
diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h
index 52bb2b0195cc..84632c569f2c 100644
--- a/drivers/net/ethernet/freescale/gianfar.h
+++ b/drivers/net/ethernet/freescale/gianfar.h
@@ -9,7 +9,7 @@
* Maintainer: Kumar Gala
* Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com>
*
- * Copyright 2002-2009, 2011 Freescale Semiconductor, Inc.
+ * Copyright 2002-2009, 2011-2013 Freescale Semiconductor, Inc.
*
* 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
@@ -377,8 +377,11 @@ extern const char gfar_driver_version[];
IMASK_RXFEN0 | IMASK_BSY | IMASK_EBERR | IMASK_BABR | \
IMASK_XFUN | IMASK_RXC | IMASK_BABT | IMASK_DPE \
| IMASK_PERR)
-#define IMASK_RTX_DISABLED ((~(IMASK_RXFEN0 | IMASK_TXFEN | IMASK_BSY)) \
- & IMASK_DEFAULT)
+#define IMASK_RX_DEFAULT (IMASK_RXFEN0 | IMASK_BSY)
+#define IMASK_TX_DEFAULT (IMASK_TXFEN | IMASK_TXBEN)
+
+#define IMASK_RX_DISABLED ((~(IMASK_RX_DEFAULT)) & IMASK_DEFAULT)
+#define IMASK_TX_DISABLED ((~(IMASK_TX_DEFAULT)) & IMASK_DEFAULT)
/* Fifo management */
#define FIFO_TX_THR_MASK 0x01ff
@@ -409,7 +412,9 @@ extern const char gfar_driver_version[];
/* This default RIR value directly corresponds
* to the 3-bit hash value generated */
-#define DEFAULT_RIR0 0x05397700
+#define DEFAULT_8RXQ_RIR0 0x05397700
+/* Map even hash values to Q0, and odd ones to Q1 */
+#define DEFAULT_2RXQ_RIR0 0x04104100
/* RQFCR register bits */
#define RQFCR_GPI 0x80000000
@@ -880,7 +885,6 @@ struct gfar {
#define FSL_GIANFAR_DEV_HAS_CSUM 0x00000010
#define FSL_GIANFAR_DEV_HAS_VLAN 0x00000020
#define FSL_GIANFAR_DEV_HAS_EXTENDED_HASH 0x00000040
-#define FSL_GIANFAR_DEV_HAS_PADDING 0x00000080
#define FSL_GIANFAR_DEV_HAS_MAGIC_PACKET 0x00000100
#define FSL_GIANFAR_DEV_HAS_BD_STASHING 0x00000200
#define FSL_GIANFAR_DEV_HAS_BUF_STASHING 0x00000400
@@ -892,8 +896,8 @@ struct gfar {
#define DEFAULT_MAPPING 0xFF
#endif
-#define ISRG_SHIFT_TX 0x10
-#define ISRG_SHIFT_RX 0x18
+#define ISRG_RR0 0x80000000
+#define ISRG_TR0 0x00800000
/* The same driver can operate in two modes */
/* SQ_SG_MODE: Single Queue Single Group Mode
@@ -905,6 +909,22 @@ enum {
MQ_MG_MODE
};
+/* GFAR_SQ_POLLING: Single Queue NAPI polling mode
+ * The driver supports a single pair of RX/Tx queues
+ * per interrupt group (Rx/Tx int line). MQ_MG mode
+ * devices have 2 interrupt groups, so the device will
+ * have a total of 2 Tx and 2 Rx queues in this case.
+ * GFAR_MQ_POLLING: Multi Queue NAPI polling mode
+ * The driver supports all the 8 Rx and Tx HW queues
+ * each queue mapped by the Device Tree to one of
+ * the 2 interrupt groups. This mode implies significant
+ * processing overhead (CPU and controller level).
+ */
+enum gfar_poll_mode {
+ GFAR_SQ_POLLING = 0,
+ GFAR_MQ_POLLING
+};
+
/*
* Per TX queue stats
*/
@@ -966,7 +986,6 @@ struct rx_q_stats {
/**
* struct gfar_priv_rx_q - per rx queue structure
- * @rxlock: per queue rx spin lock
* @rx_skbuff: skb pointers
* @skb_currx: currently use skb pointer
* @rx_bd_base: First rx buffer descriptor
@@ -979,8 +998,7 @@ struct rx_q_stats {
*/
struct gfar_priv_rx_q {
- spinlock_t rxlock __attribute__ ((aligned (SMP_CACHE_BYTES)));
- struct sk_buff ** rx_skbuff;
+ struct sk_buff **rx_skbuff __aligned(SMP_CACHE_BYTES);
dma_addr_t rx_bd_dma_base;
struct rxbd8 *rx_bd_base;
struct rxbd8 *cur_rx;
@@ -1016,17 +1034,20 @@ struct gfar_irqinfo {
*/
struct gfar_priv_grp {
- spinlock_t grplock __attribute__ ((aligned (SMP_CACHE_BYTES)));
- struct napi_struct napi;
- struct gfar_private *priv;
+ spinlock_t grplock __aligned(SMP_CACHE_BYTES);
+ struct napi_struct napi_rx;
+ struct napi_struct napi_tx;
struct gfar __iomem *regs;
- unsigned int rstat;
- unsigned long num_rx_queues;
- unsigned long rx_bit_map;
- /* cacheline 3 */
+ struct gfar_priv_tx_q *tx_queue;
+ struct gfar_priv_rx_q *rx_queue;
unsigned int tstat;
+ unsigned int rstat;
+
+ struct gfar_private *priv;
unsigned long num_tx_queues;
unsigned long tx_bit_map;
+ unsigned long num_rx_queues;
+ unsigned long rx_bit_map;
struct gfar_irqinfo *irqinfo[GFAR_NUM_IRQS];
};
@@ -1041,6 +1062,11 @@ enum gfar_errata {
GFAR_ERRATA_12 = 0x08, /* a.k.a errata eTSEC49 */
};
+enum gfar_dev_state {
+ GFAR_DOWN = 1,
+ GFAR_RESETTING
+};
+
/* Struct stolen almost completely (and shamelessly) from the FCC enet source
* (Ok, that's not so true anymore, but there is a family resemblance)
* The GFAR buffer descriptors track the ring buffers. The rx_bd_base
@@ -1051,8 +1077,6 @@ enum gfar_errata {
* the buffer descriptor determines the actual condition.
*/
struct gfar_private {
- unsigned int num_rx_queues;
-
struct device *dev;
struct net_device *ndev;
enum gfar_errata errata;
@@ -1060,6 +1084,7 @@ struct gfar_private {
u16 uses_rxfcb;
u16 padding;
+ u32 device_flags;
/* HW time stamping enabled flag */
int hwts_rx_en;
@@ -1069,10 +1094,12 @@ struct gfar_private {
struct gfar_priv_rx_q *rx_queue[MAX_RX_QS];
struct gfar_priv_grp gfargrp[MAXGROUPS];
- u32 device_flags;
+ unsigned long state;
- unsigned int mode;
+ unsigned short mode;
+ unsigned short poll_mode;
unsigned int num_tx_queues;
+ unsigned int num_rx_queues;
unsigned int num_grps;
/* Network Statistics */
@@ -1113,6 +1140,9 @@ struct gfar_private {
unsigned int total_tx_ring_size;
unsigned int total_rx_ring_size;
+ u32 rqueue;
+ u32 tqueue;
+
/* RX per device parameters */
unsigned int rx_stash_size;
unsigned int rx_stash_index;
@@ -1127,11 +1157,6 @@ struct gfar_private {
u32 __iomem *hash_regs[16];
int hash_width;
- /* global parameters */
- unsigned int fifo_threshold;
- unsigned int fifo_starve;
- unsigned int fifo_starve_off;
-
/*Filer table*/
unsigned int ftp_rqfpr[MAX_FILER_IDX + 1];
unsigned int ftp_rqfcr[MAX_FILER_IDX + 1];
@@ -1176,21 +1201,42 @@ static inline void gfar_read_filer(struct gfar_private *priv,
*fpr = gfar_read(&regs->rqfpr);
}
-void lock_rx_qs(struct gfar_private *priv);
-void lock_tx_qs(struct gfar_private *priv);
-void unlock_rx_qs(struct gfar_private *priv);
-void unlock_tx_qs(struct gfar_private *priv);
+static inline void gfar_write_isrg(struct gfar_private *priv)
+{
+ struct gfar __iomem *regs = priv->gfargrp[0].regs;
+ u32 __iomem *baddr = &regs->isrg0;
+ u32 isrg = 0;
+ int grp_idx, i;
+
+ for (grp_idx = 0; grp_idx < priv->num_grps; grp_idx++) {
+ struct gfar_priv_grp *grp = &priv->gfargrp[grp_idx];
+
+ for_each_set_bit(i, &grp->rx_bit_map, priv->num_rx_queues) {
+ isrg |= (ISRG_RR0 >> i);
+ }
+
+ for_each_set_bit(i, &grp->tx_bit_map, priv->num_tx_queues) {
+ isrg |= (ISRG_TR0 >> i);
+ }
+
+ gfar_write(baddr, isrg);
+
+ baddr++;
+ isrg = 0;
+ }
+}
+
irqreturn_t gfar_receive(int irq, void *dev_id);
int startup_gfar(struct net_device *dev);
void stop_gfar(struct net_device *dev);
-void gfar_halt(struct net_device *dev);
+void reset_gfar(struct net_device *dev);
+void gfar_mac_reset(struct gfar_private *priv);
+void gfar_halt(struct gfar_private *priv);
+void gfar_start(struct gfar_private *priv);
void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev, int enable,
u32 regnum, u32 read);
void gfar_configure_coalescing_all(struct gfar_private *priv);
-void gfar_init_sysfs(struct net_device *dev);
int gfar_set_features(struct net_device *dev, netdev_features_t features);
-void gfar_check_rx_parser_mode(struct gfar_private *priv);
-void gfar_vlan_mode(struct net_device *dev, netdev_features_t features);
extern const struct ethtool_ops gfar_ethtool_ops;
diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c
index 63d234419cc1..891dbee6e6c1 100644
--- a/drivers/net/ethernet/freescale/gianfar_ethtool.c
+++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c
@@ -44,10 +44,6 @@
#include "gianfar.h"
-extern void gfar_start(struct net_device *dev);
-extern int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue,
- int rx_work_limit);
-
#define GFAR_MAX_COAL_USECS 0xffff
#define GFAR_MAX_COAL_FRAMES 0xff
static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
@@ -364,25 +360,11 @@ static int gfar_scoalesce(struct net_device *dev,
struct ethtool_coalesce *cvals)
{
struct gfar_private *priv = netdev_priv(dev);
- int i = 0;
+ int i, err = 0;
if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
return -EOPNOTSUPP;
- /* Set up rx coalescing */
- /* As of now, we will enable/disable coalescing for all
- * queues together in case of eTSEC2, this will be modified
- * along with the ethtool interface
- */
- if ((cvals->rx_coalesce_usecs == 0) ||
- (cvals->rx_max_coalesced_frames == 0)) {
- for (i = 0; i < priv->num_rx_queues; i++)
- priv->rx_queue[i]->rxcoalescing = 0;
- } else {
- for (i = 0; i < priv->num_rx_queues; i++)
- priv->rx_queue[i]->rxcoalescing = 1;
- }
-
if (NULL == priv->phydev)
return -ENODEV;
@@ -399,6 +381,32 @@ static int gfar_scoalesce(struct net_device *dev,
return -EINVAL;
}
+ /* Check the bounds of the values */
+ if (cvals->tx_coalesce_usecs > GFAR_MAX_COAL_USECS) {
+ netdev_info(dev, "Coalescing is limited to %d microseconds\n",
+ GFAR_MAX_COAL_USECS);
+ return -EINVAL;
+ }
+
+ if (cvals->tx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) {
+ netdev_info(dev, "Coalescing is limited to %d frames\n",
+ GFAR_MAX_COAL_FRAMES);
+ return -EINVAL;
+ }
+
+ while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state))
+ cpu_relax();
+
+ /* Set up rx coalescing */
+ if ((cvals->rx_coalesce_usecs == 0) ||
+ (cvals->rx_max_coalesced_frames == 0)) {
+ for (i = 0; i < priv->num_rx_queues; i++)
+ priv->rx_queue[i]->rxcoalescing = 0;
+ } else {
+ for (i = 0; i < priv->num_rx_queues; i++)
+ priv->rx_queue[i]->rxcoalescing = 1;
+ }
+
for (i = 0; i < priv->num_rx_queues; i++) {
priv->rx_queue[i]->rxic = mk_ic_value(
cvals->rx_max_coalesced_frames,
@@ -415,28 +423,22 @@ static int gfar_scoalesce(struct net_device *dev,
priv->tx_queue[i]->txcoalescing = 1;
}
- /* Check the bounds of the values */
- if (cvals->tx_coalesce_usecs > GFAR_MAX_COAL_USECS) {
- netdev_info(dev, "Coalescing is limited to %d microseconds\n",
- GFAR_MAX_COAL_USECS);
- return -EINVAL;
- }
-
- if (cvals->tx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) {
- netdev_info(dev, "Coalescing is limited to %d frames\n",
- GFAR_MAX_COAL_FRAMES);
- return -EINVAL;
- }
-
for (i = 0; i < priv->num_tx_queues; i++) {
priv->tx_queue[i]->txic = mk_ic_value(
cvals->tx_max_coalesced_frames,
gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs));
}
- gfar_configure_coalescing_all(priv);
+ if (dev->flags & IFF_UP) {
+ stop_gfar(dev);
+ err = startup_gfar(dev);
+ } else {
+ gfar_mac_reset(priv);
+ }
+
+ clear_bit_unlock(GFAR_RESETTING, &priv->state);
- return 0;
+ return err;
}
/* Fills in rvals with the current ring parameters. Currently,
@@ -467,15 +469,13 @@ static void gfar_gringparam(struct net_device *dev,
}
/* Change the current ring parameters, stopping the controller if
- * necessary so that we don't mess things up while we're in
- * motion. We wait for the ring to be clean before reallocating
- * the rings.
+ * necessary so that we don't mess things up while we're in motion.
*/
static int gfar_sringparam(struct net_device *dev,
struct ethtool_ringparam *rvals)
{
struct gfar_private *priv = netdev_priv(dev);
- int err = 0, i = 0;
+ int err = 0, i;
if (rvals->rx_pending > GFAR_RX_MAX_RING_SIZE)
return -EINVAL;
@@ -493,44 +493,25 @@ static int gfar_sringparam(struct net_device *dev,
return -EINVAL;
}
+ while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state))
+ cpu_relax();
- if (dev->flags & IFF_UP) {
- unsigned long flags;
-
- /* Halt TX and RX, and process the frames which
- * have already been received
- */
- local_irq_save(flags);
- lock_tx_qs(priv);
- lock_rx_qs(priv);
-
- gfar_halt(dev);
-
- unlock_rx_qs(priv);
- unlock_tx_qs(priv);
- local_irq_restore(flags);
-
- for (i = 0; i < priv->num_rx_queues; i++)
- gfar_clean_rx_ring(priv->rx_queue[i],
- priv->rx_queue[i]->rx_ring_size);
-
- /* Now we take down the rings to rebuild them */
+ if (dev->flags & IFF_UP)
stop_gfar(dev);
- }
- /* Change the size */
- for (i = 0; i < priv->num_rx_queues; i++) {
+ /* Change the sizes */
+ for (i = 0; i < priv->num_rx_queues; i++)
priv->rx_queue[i]->rx_ring_size = rvals->rx_pending;
+
+ for (i = 0; i < priv->num_tx_queues; i++)
priv->tx_queue[i]->tx_ring_size = rvals->tx_pending;
- priv->tx_queue[i]->num_txbdfree =
- priv->tx_queue[i]->tx_ring_size;
- }
/* Rebuild the rings with the new size */
- if (dev->flags & IFF_UP) {
+ if (dev->flags & IFF_UP)
err = startup_gfar(dev);
- netif_tx_wake_all_queues(dev);
- }
+
+ clear_bit_unlock(GFAR_RESETTING, &priv->state);
+
return err;
}
@@ -608,43 +589,29 @@ static int gfar_spauseparam(struct net_device *dev,
int gfar_set_features(struct net_device *dev, netdev_features_t features)
{
- struct gfar_private *priv = netdev_priv(dev);
- unsigned long flags;
- int err = 0, i = 0;
netdev_features_t changed = dev->features ^ features;
+ struct gfar_private *priv = netdev_priv(dev);
+ int err = 0;
- if (changed & (NETIF_F_HW_VLAN_CTAG_TX|NETIF_F_HW_VLAN_CTAG_RX))
- gfar_vlan_mode(dev, features);
-
- if (!(changed & NETIF_F_RXCSUM))
+ if (!(changed & (NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_RXCSUM)))
return 0;
- if (dev->flags & IFF_UP) {
- /* Halt TX and RX, and process the frames which
- * have already been received
- */
- local_irq_save(flags);
- lock_tx_qs(priv);
- lock_rx_qs(priv);
-
- gfar_halt(dev);
+ while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state))
+ cpu_relax();
- unlock_tx_qs(priv);
- unlock_rx_qs(priv);
- local_irq_restore(flags);
-
- for (i = 0; i < priv->num_rx_queues; i++)
- gfar_clean_rx_ring(priv->rx_queue[i],
- priv->rx_queue[i]->rx_ring_size);
+ dev->features = features;
+ if (dev->flags & IFF_UP) {
/* Now we take down the rings to rebuild them */
stop_gfar(dev);
-
- dev->features = features;
-
err = startup_gfar(dev);
- netif_tx_wake_all_queues(dev);
+ } else {
+ gfar_mac_reset(priv);
}
+
+ clear_bit_unlock(GFAR_RESETTING, &priv->state);
+
return err;
}
@@ -1610,9 +1577,6 @@ static int gfar_write_filer_table(struct gfar_private *priv,
if (tab->index > MAX_FILER_IDX - 1)
return -EBUSY;
- /* Avoid inconsistent filer table to be processed */
- lock_rx_qs(priv);
-
/* Fill regular entries */
for (; i < MAX_FILER_IDX - 1 && (tab->fe[i].ctrl | tab->fe[i].ctrl);
i++)
@@ -1625,8 +1589,6 @@ static int gfar_write_filer_table(struct gfar_private *priv,
*/
gfar_write_filer(priv, i, 0x20, 0x0);
- unlock_rx_qs(priv);
-
return 0;
}
@@ -1831,6 +1793,9 @@ static int gfar_set_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
struct gfar_private *priv = netdev_priv(dev);
int ret = 0;
+ if (test_bit(GFAR_RESETTING, &priv->state))
+ return -EBUSY;
+
mutex_lock(&priv->rx_queue_access);
switch (cmd->cmd) {
diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c
index abc28da27042..bb568006f37d 100644
--- a/drivers/net/ethernet/freescale/gianfar_ptp.c
+++ b/drivers/net/ethernet/freescale/gianfar_ptp.c
@@ -414,6 +414,7 @@ static struct ptp_clock_info ptp_gianfar_caps = {
.n_alarm = 0,
.n_ext_ts = N_EXT_TS,
.n_per_out = 0,
+ .n_pins = 0,
.pps = 1,
.adjfreq = ptp_gianfar_adjfreq,
.adjtime = ptp_gianfar_adjtime,
diff --git a/drivers/net/ethernet/freescale/gianfar_sysfs.c b/drivers/net/ethernet/freescale/gianfar_sysfs.c
deleted file mode 100644
index e02dd1378751..000000000000
--- a/drivers/net/ethernet/freescale/gianfar_sysfs.c
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * drivers/net/ethernet/freescale/gianfar_sysfs.c
- *
- * Gianfar Ethernet Driver
- * This driver is designed for the non-CPM ethernet controllers
- * on the 85xx and 83xx family of integrated processors
- * Based on 8260_io/fcc_enet.c
- *
- * Author: Andy Fleming
- * Maintainer: Kumar Gala (galak@kernel.crashing.org)
- * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com>
- *
- * Copyright 2002-2009 Freescale Semiconductor, Inc.
- *
- * 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.
- *
- * Sysfs file creation and management
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/unistd.h>
-#include <linux/delay.h>
-#include <linux/etherdevice.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-#include <linux/device.h>
-
-#include <asm/uaccess.h>
-#include <linux/module.h>
-
-#include "gianfar.h"
-
-static ssize_t gfar_show_bd_stash(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-
- return sprintf(buf, "%s\n", priv->bd_stash_en ? "on" : "off");
-}
-
-static ssize_t gfar_set_bd_stash(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct gfar_private *priv = netdev_priv(to_net_dev(dev));
- struct gfar __iomem *regs = priv->gfargrp[0].regs;
- int new_setting = 0;
- u32 temp;
- unsigned long flags;
-
- if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BD_STASHING))
- return count;
-
-
- /* Find out the new setting */
- if (!strncmp("on", buf, count - 1) || !strncmp("1", buf, count - 1))
- new_setting = 1;
- else if (!strncmp("off", buf, count - 1) ||
- !strncmp("0", buf, count - 1))
- new_setting = 0;
- else
- return count;
-
-
- local_irq_save(flags);
- lock_rx_qs(priv);
-
- /* Set the new stashing value */
- priv->bd_stash_en = new_setting;
-
- temp = gfar_read(&regs->attr);
-
- if (new_setting)
- temp |= ATTR_BDSTASH;
- else
- temp &= ~(ATTR_BDSTASH);
-
- gfar_write(&regs->attr, temp);
-
- unlock_rx_qs(priv);
- local_irq_restore(flags);
-
- return count;
-}
-
-static DEVICE_ATTR(bd_stash, 0644, gfar_show_bd_stash, gfar_set_bd_stash);
-
-static ssize_t gfar_show_rx_stash_size(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-
- return sprintf(buf, "%d\n", priv->rx_stash_size);
-}
-
-static ssize_t gfar_set_rx_stash_size(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct gfar_private *priv = netdev_priv(to_net_dev(dev));
- struct gfar __iomem *regs = priv->gfargrp[0].regs;
- unsigned int length = simple_strtoul(buf, NULL, 0);
- u32 temp;
- unsigned long flags;
-
- if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BUF_STASHING))
- return count;
-
- local_irq_save(flags);
- lock_rx_qs(priv);
-
- if (length > priv->rx_buffer_size)
- goto out;
-
- if (length == priv->rx_stash_size)
- goto out;
-
- priv->rx_stash_size = length;
-
- temp = gfar_read(&regs->attreli);
- temp &= ~ATTRELI_EL_MASK;
- temp |= ATTRELI_EL(length);
- gfar_write(&regs->attreli, temp);
-
- /* Turn stashing on/off as appropriate */
- temp = gfar_read(&regs->attr);
-
- if (length)
- temp |= ATTR_BUFSTASH;
- else
- temp &= ~(ATTR_BUFSTASH);
-
- gfar_write(&regs->attr, temp);
-
-out:
- unlock_rx_qs(priv);
- local_irq_restore(flags);
-
- return count;
-}
-
-static DEVICE_ATTR(rx_stash_size, 0644, gfar_show_rx_stash_size,
- gfar_set_rx_stash_size);
-
-/* Stashing will only be enabled when rx_stash_size != 0 */
-static ssize_t gfar_show_rx_stash_index(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-
- return sprintf(buf, "%d\n", priv->rx_stash_index);
-}
-
-static ssize_t gfar_set_rx_stash_index(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct gfar_private *priv = netdev_priv(to_net_dev(dev));
- struct gfar __iomem *regs = priv->gfargrp[0].regs;
- unsigned short index = simple_strtoul(buf, NULL, 0);
- u32 temp;
- unsigned long flags;
-
- if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BUF_STASHING))
- return count;
-
- local_irq_save(flags);
- lock_rx_qs(priv);
-
- if (index > priv->rx_stash_size)
- goto out;
-
- if (index == priv->rx_stash_index)
- goto out;
-
- priv->rx_stash_index = index;
-
- temp = gfar_read(&regs->attreli);
- temp &= ~ATTRELI_EI_MASK;
- temp |= ATTRELI_EI(index);
- gfar_write(&regs->attreli, temp);
-
-out:
- unlock_rx_qs(priv);
- local_irq_restore(flags);
-
- return count;
-}
-
-static DEVICE_ATTR(rx_stash_index, 0644, gfar_show_rx_stash_index,
- gfar_set_rx_stash_index);
-
-static ssize_t gfar_show_fifo_threshold(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-
- return sprintf(buf, "%d\n", priv->fifo_threshold);
-}
-
-static ssize_t gfar_set_fifo_threshold(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct gfar_private *priv = netdev_priv(to_net_dev(dev));
- struct gfar __iomem *regs = priv->gfargrp[0].regs;
- unsigned int length = simple_strtoul(buf, NULL, 0);
- u32 temp;
- unsigned long flags;
-
- if (length > GFAR_MAX_FIFO_THRESHOLD)
- return count;
-
- local_irq_save(flags);
- lock_tx_qs(priv);
-
- priv->fifo_threshold = length;
-
- temp = gfar_read(&regs->fifo_tx_thr);
- temp &= ~FIFO_TX_THR_MASK;
- temp |= length;
- gfar_write(&regs->fifo_tx_thr, temp);
-
- unlock_tx_qs(priv);
- local_irq_restore(flags);
-
- return count;
-}
-
-static DEVICE_ATTR(fifo_threshold, 0644, gfar_show_fifo_threshold,
- gfar_set_fifo_threshold);
-
-static ssize_t gfar_show_fifo_starve(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-
- return sprintf(buf, "%d\n", priv->fifo_starve);
-}
-
-static ssize_t gfar_set_fifo_starve(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct gfar_private *priv = netdev_priv(to_net_dev(dev));
- struct gfar __iomem *regs = priv->gfargrp[0].regs;
- unsigned int num = simple_strtoul(buf, NULL, 0);
- u32 temp;
- unsigned long flags;
-
- if (num > GFAR_MAX_FIFO_STARVE)
- return count;
-
- local_irq_save(flags);
- lock_tx_qs(priv);
-
- priv->fifo_starve = num;
-
- temp = gfar_read(&regs->fifo_tx_starve);
- temp &= ~FIFO_TX_STARVE_MASK;
- temp |= num;
- gfar_write(&regs->fifo_tx_starve, temp);
-
- unlock_tx_qs(priv);
- local_irq_restore(flags);
-
- return count;
-}
-
-static DEVICE_ATTR(fifo_starve, 0644, gfar_show_fifo_starve,
- gfar_set_fifo_starve);
-
-static ssize_t gfar_show_fifo_starve_off(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-
- return sprintf(buf, "%d\n", priv->fifo_starve_off);
-}
-
-static ssize_t gfar_set_fifo_starve_off(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct gfar_private *priv = netdev_priv(to_net_dev(dev));
- struct gfar __iomem *regs = priv->gfargrp[0].regs;
- unsigned int num = simple_strtoul(buf, NULL, 0);
- u32 temp;
- unsigned long flags;
-
- if (num > GFAR_MAX_FIFO_STARVE_OFF)
- return count;
-
- local_irq_save(flags);
- lock_tx_qs(priv);
-
- priv->fifo_starve_off = num;
-
- temp = gfar_read(&regs->fifo_tx_starve_shutoff);
- temp &= ~FIFO_TX_STARVE_OFF_MASK;
- temp |= num;
- gfar_write(&regs->fifo_tx_starve_shutoff, temp);
-
- unlock_tx_qs(priv);
- local_irq_restore(flags);
-
- return count;
-}
-
-static DEVICE_ATTR(fifo_starve_off, 0644, gfar_show_fifo_starve_off,
- gfar_set_fifo_starve_off);
-
-void gfar_init_sysfs(struct net_device *dev)
-{
- struct gfar_private *priv = netdev_priv(dev);
- int rc;
-
- /* Initialize the default values */
- priv->fifo_threshold = DEFAULT_FIFO_TX_THR;
- priv->fifo_starve = DEFAULT_FIFO_TX_STARVE;
- priv->fifo_starve_off = DEFAULT_FIFO_TX_STARVE_OFF;
-
- /* Create our sysfs files */
- rc = device_create_file(&dev->dev, &dev_attr_bd_stash);
- rc |= device_create_file(&dev->dev, &dev_attr_rx_stash_size);
- rc |= device_create_file(&dev->dev, &dev_attr_rx_stash_index);
- rc |= device_create_file(&dev->dev, &dev_attr_fifo_threshold);
- rc |= device_create_file(&dev->dev, &dev_attr_fifo_starve);
- rc |= device_create_file(&dev->dev, &dev_attr_fifo_starve_off);
- if (rc)
- dev_err(&dev->dev, "Error creating gianfar sysfs files\n");
-}
diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c
index 72291a8904a9..c8299c31b21f 100644
--- a/drivers/net/ethernet/freescale/ucc_geth.c
+++ b/drivers/net/ethernet/freescale/ucc_geth.c
@@ -3261,7 +3261,7 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
dev->stats.tx_packets++;
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL;
ugeth->skb_dirtytx[txQ] =
diff --git a/drivers/net/ethernet/i825xx/lib82596.c b/drivers/net/ethernet/i825xx/lib82596.c
index 17fca323c143..c984998b34a0 100644
--- a/drivers/net/ethernet/i825xx/lib82596.c
+++ b/drivers/net/ethernet/i825xx/lib82596.c
@@ -993,7 +993,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->name));
dev->stats.tx_dropped++;
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
} else {
if (++lp->next_tx_cmd == TX_RING_SIZE)
lp->next_tx_cmd = 0;
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c
index 7628e0fd8455..538903bf13bc 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_main.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c
@@ -490,7 +490,7 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr,
skb_arr[index] = skb;
tmp_addr = ehea_map_vaddr(skb->data);
if (tmp_addr == -1) {
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
q_skba->os_skbs = fill_wqes - i;
ret = 0;
break;
@@ -856,7 +856,7 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id);
skb = pr->sq_skba.arr[index];
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
pr->sq_skba.arr[index] = NULL;
}
@@ -2044,7 +2044,7 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev,
skb_copy_bits(skb, 0, imm_data, skb->len);
swqe->immediate_data_length = skb->len;
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
}
static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 4be971590461..c9127562bd22 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -522,10 +522,21 @@ retry:
return rc;
}
+static u64 ibmveth_encode_mac_addr(u8 *mac)
+{
+ int i;
+ u64 encoded = 0;
+
+ for (i = 0; i < ETH_ALEN; i++)
+ encoded = (encoded << 8) | mac[i];
+
+ return encoded;
+}
+
static int ibmveth_open(struct net_device *netdev)
{
struct ibmveth_adapter *adapter = netdev_priv(netdev);
- u64 mac_address = 0;
+ u64 mac_address;
int rxq_entries = 1;
unsigned long lpar_rc;
int rc;
@@ -579,8 +590,7 @@ static int ibmveth_open(struct net_device *netdev)
adapter->rx_queue.num_slots = rxq_entries;
adapter->rx_queue.toggle = 1;
- memcpy(&mac_address, netdev->dev_addr, netdev->addr_len);
- mac_address = mac_address >> 16;
+ mac_address = ibmveth_encode_mac_addr(netdev->dev_addr);
rxq_desc.fields.flags_len = IBMVETH_BUF_VALID |
adapter->rx_queue.queue_len;
@@ -1034,7 +1044,7 @@ retry_bounce:
DMA_TO_DEVICE);
out:
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
return NETDEV_TX_OK;
map_failed_frags:
@@ -1062,7 +1072,7 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
unsigned long lpar_rc;
restart_poll:
- do {
+ while (frames_processed < budget) {
if (!ibmveth_rxq_pending_buffer(adapter))
break;
@@ -1111,7 +1121,7 @@ restart_poll:
netdev->stats.rx_bytes += length;
frames_processed++;
}
- } while (frames_processed < budget);
+ }
ibmveth_replenish_task(adapter);
@@ -1183,8 +1193,8 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
/* add the addresses to the filter table */
netdev_for_each_mc_addr(ha, netdev) {
/* add the multicast address to the filter table */
- unsigned long mcast_addr = 0;
- memcpy(((char *)&mcast_addr)+2, ha->addr, ETH_ALEN);
+ u64 mcast_addr;
+ mcast_addr = ibmveth_encode_mac_addr(ha->addr);
lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address,
IbmVethMcastAddFilter,
mcast_addr);
@@ -1372,9 +1382,6 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
netif_napi_add(netdev, &adapter->napi, ibmveth_poll, 16);
- adapter->mac_addr = 0;
- memcpy(&adapter->mac_addr, mac_addr_p, ETH_ALEN);
-
netdev->irq = dev->irq;
netdev->netdev_ops = &ibmveth_netdev_ops;
netdev->ethtool_ops = &netdev_ethtool_ops;
@@ -1383,7 +1390,7 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
netdev->features |= netdev->hw_features;
- memcpy(netdev->dev_addr, &adapter->mac_addr, netdev->addr_len);
+ memcpy(netdev->dev_addr, mac_addr_p, ETH_ALEN);
for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
struct kobject *kobj = &adapter->rx_buff_pool[i].kobj;
diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h
index 451ba7949e15..1f37499d4398 100644
--- a/drivers/net/ethernet/ibm/ibmveth.h
+++ b/drivers/net/ethernet/ibm/ibmveth.h
@@ -138,7 +138,6 @@ struct ibmveth_adapter {
struct napi_struct napi;
struct net_device_stats stats;
unsigned int mcastFilterSize;
- unsigned long mac_addr;
void * buffer_list_addr;
void * filter_list_addr;
dma_addr_t buffer_list_dma;
diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c
index cbaba4442d4b..b56461ce674c 100644
--- a/drivers/net/ethernet/intel/e100.c
+++ b/drivers/net/ethernet/intel/e100.c
@@ -1778,9 +1778,9 @@ static int e100_xmit_prepare(struct nic *nic, struct cb *cb,
* testing, ie sending frames with bad CRC.
*/
if (unlikely(skb->no_fcs))
- cb->command |= __constant_cpu_to_le16(cb_tx_nc);
+ cb->command |= cpu_to_le16(cb_tx_nc);
else
- cb->command &= ~__constant_cpu_to_le16(cb_tx_nc);
+ cb->command &= ~cpu_to_le16(cb_tx_nc);
/* interrupt every 16 packets regardless of delay */
if ((nic->cbs_avail & ~15) == nic->cbs_avail)
@@ -3034,7 +3034,7 @@ static void __e100_shutdown(struct pci_dev *pdev, bool *enable_wake)
*enable_wake = false;
}
- pci_disable_device(pdev);
+ pci_clear_master(pdev);
}
static int __e100_power_off(struct pci_dev *pdev, bool wake)
diff --git a/drivers/net/ethernet/intel/e1000e/80003es2lan.c b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
index ff2d806eaef7..a5f6b11d6992 100644
--- a/drivers/net/ethernet/intel/e1000e/80003es2lan.c
+++ b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
/* 80003ES2LAN Gigabit Ethernet Controller (Copper)
* 80003ES2LAN Gigabit Ethernet Controller (Serdes)
diff --git a/drivers/net/ethernet/intel/e1000e/80003es2lan.h b/drivers/net/ethernet/intel/e1000e/80003es2lan.h
index 90d363b2d280..535a9430976d 100644
--- a/drivers/net/ethernet/intel/e1000e/80003es2lan.h
+++ b/drivers/net/ethernet/intel/e1000e/80003es2lan.h
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
#ifndef _E1000E_80003ES2LAN_H_
#define _E1000E_80003ES2LAN_H_
diff --git a/drivers/net/ethernet/intel/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c
index 8fed74e3fa53..e0aa7f1efb08 100644
--- a/drivers/net/ethernet/intel/e1000e/82571.c
+++ b/drivers/net/ethernet/intel/e1000e/82571.c
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
/* 82571EB Gigabit Ethernet Controller
* 82571EB Gigabit Ethernet Controller (Copper)
diff --git a/drivers/net/ethernet/intel/e1000e/82571.h b/drivers/net/ethernet/intel/e1000e/82571.h
index 08e24dc3dc0e..2e758f796d60 100644
--- a/drivers/net/ethernet/intel/e1000e/82571.h
+++ b/drivers/net/ethernet/intel/e1000e/82571.h
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
#ifndef _E1000E_82571_H_
#define _E1000E_82571_H_
diff --git a/drivers/net/ethernet/intel/e1000e/Makefile b/drivers/net/ethernet/intel/e1000e/Makefile
index c2dcfcc10857..106de493373c 100644
--- a/drivers/net/ethernet/intel/e1000e/Makefile
+++ b/drivers/net/ethernet/intel/e1000e/Makefile
@@ -1,7 +1,7 @@
################################################################################
#
# Intel PRO/1000 Linux driver
-# Copyright(c) 1999 - 2013 Intel Corporation.
+# Copyright(c) 1999 - 2014 Intel Corporation.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms and conditions of the GNU General Public License,
@@ -12,9 +12,8 @@
# 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.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# The full GNU General Public License is included in this distribution in
# the file called "COPYING".
diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h
index 351c94a0cf74..d18e89212575 100644
--- a/drivers/net/ethernet/intel/e1000e/defines.h
+++ b/drivers/net/ethernet/intel/e1000e/defines.h
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
#ifndef _E1000_DEFINES_H_
#define _E1000_DEFINES_H_
@@ -35,9 +28,11 @@
/* Definitions for power management and wakeup registers */
/* Wake Up Control */
-#define E1000_WUC_APME 0x00000001 /* APM Enable */
-#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */
-#define E1000_WUC_PHY_WAKE 0x00000100 /* if PHY supports wakeup */
+#define E1000_WUC_APME 0x00000001 /* APM Enable */
+#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */
+#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
+#define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */
+#define E1000_WUC_PHY_WAKE 0x00000100 /* if PHY supports wakeup */
/* Wake Up Filter Control */
#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h
index 0150f7fc893d..1471c5464a89 100644
--- a/drivers/net/ethernet/intel/e1000e/e1000.h
+++ b/drivers/net/ethernet/intel/e1000e/e1000.h
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
/* Linux PRO/1000 Ethernet Driver main header file */
@@ -269,6 +262,7 @@ struct e1000_adapter {
u32 tx_head_addr;
u32 tx_fifo_size;
u32 tx_dma_failed;
+ u32 tx_hwtstamp_timeouts;
/* Rx */
bool (*clean_rx) (struct e1000_ring *ring, int *work_done,
@@ -333,7 +327,6 @@ struct e1000_adapter {
struct work_struct update_phy_task;
struct work_struct print_hang_task;
- bool idle_check;
int phy_hang_count;
u16 tx_ring_count;
@@ -342,6 +335,7 @@ struct e1000_adapter {
struct hwtstamp_config hwtstamp_config;
struct delayed_work systim_overflow_work;
struct sk_buff *tx_hwtstamp_skb;
+ unsigned long tx_hwtstamp_start;
struct work_struct tx_hwtstamp_work;
spinlock_t systim_lock; /* protects SYSTIML/H regsters */
struct cyclecounter cc;
@@ -476,7 +470,7 @@ void e1000e_check_options(struct e1000_adapter *adapter);
void e1000e_set_ethtool_ops(struct net_device *netdev);
int e1000e_up(struct e1000_adapter *adapter);
-void e1000e_down(struct e1000_adapter *adapter);
+void e1000e_down(struct e1000_adapter *adapter, bool reset);
void e1000e_reinit_locked(struct e1000_adapter *adapter);
void e1000e_reset(struct e1000_adapter *adapter);
void e1000e_power_up_phy(struct e1000_adapter *adapter);
diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c
index d14c8f53384c..cad250bc1b99 100644
--- a/drivers/net/ethernet/intel/e1000e/ethtool.c
+++ b/drivers/net/ethernet/intel/e1000e/ethtool.c
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
/* ethtool support for e1000 */
@@ -111,6 +104,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
E1000_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
E1000_STAT("uncorr_ecc_errors", uncorr_errors),
E1000_STAT("corr_ecc_errors", corr_errors),
+ E1000_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
};
#define E1000_GLOBAL_STATS_LEN ARRAY_SIZE(e1000_gstrings_stats)
@@ -332,7 +326,7 @@ static int e1000_set_settings(struct net_device *netdev,
/* reset the link */
if (netif_running(adapter->netdev)) {
- e1000e_down(adapter);
+ e1000e_down(adapter, true);
e1000e_up(adapter);
} else {
e1000e_reset(adapter);
@@ -380,7 +374,7 @@ static int e1000_set_pauseparam(struct net_device *netdev,
if (adapter->fc_autoneg == AUTONEG_ENABLE) {
hw->fc.requested_mode = e1000_fc_default;
if (netif_running(adapter->netdev)) {
- e1000e_down(adapter);
+ e1000e_down(adapter, true);
e1000e_up(adapter);
} else {
e1000e_reset(adapter);
@@ -726,7 +720,7 @@ static int e1000_set_ringparam(struct net_device *netdev,
pm_runtime_get_sync(netdev->dev.parent);
- e1000e_down(adapter);
+ e1000e_down(adapter, true);
/* We can't just free everything and then setup again, because the
* ISRs in MSI-X mode get passed pointers to the Tx and Rx ring
@@ -924,15 +918,21 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
}
if (mac->type == e1000_pch2lan) {
/* SHRAH[0,1,2] different than previous */
- if (i == 7)
+ if (i == 1)
mask &= 0xFFF4FFFF;
/* SHRAH[3] different than SHRAH[0,1,2] */
- if (i == 10)
+ if (i == 4)
mask |= (1 << 30);
+ /* RAR[1-6] owned by management engine - skipping */
+ if (i > 0)
+ i += 6;
}
REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1), mask,
0xFFFFFFFF);
+ /* reset index to actual value */
+ if ((mac->type == e1000_pch2lan) && (i > 6))
+ i -= 6;
}
for (i = 0; i < mac->mta_reg_count; i++)
diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h
index b7f38435d1fd..6b3de5f39a97 100644
--- a/drivers/net/ethernet/intel/e1000e/hw.h
+++ b/drivers/net/ethernet/intel/e1000e/hw.h
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
#ifndef _E1000_HW_H_
#define _E1000_HW_H_
@@ -655,12 +648,20 @@ struct e1000_shadow_ram {
#define E1000_ICH8_SHADOW_RAM_WORDS 2048
+/* I218 PHY Ultra Low Power (ULP) states */
+enum e1000_ulp_state {
+ e1000_ulp_state_unknown,
+ e1000_ulp_state_off,
+ e1000_ulp_state_on,
+};
+
struct e1000_dev_spec_ich8lan {
bool kmrn_lock_loss_workaround_enabled;
struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS];
bool nvm_k1_enabled;
bool eee_disable;
u16 eee_lp_ability;
+ enum e1000_ulp_state ulp_state;
};
struct e1000_hw {
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
index 42f0f6717511..9866f264f55e 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
/* 82562G 10/100 Network Connection
* 82562G-2 10/100 Network Connection
@@ -53,6 +46,14 @@
* 82578DC Gigabit Network Connection
* 82579LM Gigabit Network Connection
* 82579V Gigabit Network Connection
+ * Ethernet Connection I217-LM
+ * Ethernet Connection I217-V
+ * Ethernet Connection I218-V
+ * Ethernet Connection I218-LM
+ * Ethernet Connection (2) I218-LM
+ * Ethernet Connection (2) I218-V
+ * Ethernet Connection (3) I218-LM
+ * Ethernet Connection (3) I218-V
*/
#include "e1000.h"
@@ -142,7 +143,9 @@ static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index);
static void e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index);
static s32 e1000_k1_workaround_lv(struct e1000_hw *hw);
static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate);
+static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force);
static s32 e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw);
+static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state);
static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg)
{
@@ -239,6 +242,47 @@ out:
}
/**
+ * e1000_toggle_lanphypc_pch_lpt - toggle the LANPHYPC pin value
+ * @hw: pointer to the HW structure
+ *
+ * Toggling the LANPHYPC pin value fully power-cycles the PHY and is
+ * used to reset the PHY to a quiescent state when necessary.
+ **/
+static void e1000_toggle_lanphypc_pch_lpt(struct e1000_hw *hw)
+{
+ u32 mac_reg;
+
+ /* Set Phy Config Counter to 50msec */
+ mac_reg = er32(FEXTNVM3);
+ mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK;
+ mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
+ ew32(FEXTNVM3, mac_reg);
+
+ /* Toggle LANPHYPC Value bit */
+ mac_reg = er32(CTRL);
+ mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE;
+ mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE;
+ ew32(CTRL, mac_reg);
+ e1e_flush();
+ usleep_range(10, 20);
+ mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
+ ew32(CTRL, mac_reg);
+ e1e_flush();
+
+ if (hw->mac.type < e1000_pch_lpt) {
+ msleep(50);
+ } else {
+ u16 count = 20;
+
+ do {
+ usleep_range(5000, 10000);
+ } while (!(er32(CTRL_EXT) & E1000_CTRL_EXT_LPCD) && count--);
+
+ msleep(30);
+ }
+}
+
+/**
* e1000_init_phy_workarounds_pchlan - PHY initialization workarounds
* @hw: pointer to the HW structure
*
@@ -247,6 +291,7 @@ out:
**/
static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
{
+ struct e1000_adapter *adapter = hw->adapter;
u32 mac_reg, fwsm = er32(FWSM);
s32 ret_val;
@@ -255,6 +300,12 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
*/
e1000_gate_hw_phy_config_ich8lan(hw, true);
+ /* It is not possible to be certain of the current state of ULP
+ * so forcibly disable it.
+ */
+ hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_unknown;
+ e1000_disable_ulp_lpt_lp(hw, true);
+
ret_val = hw->phy.ops.acquire(hw);
if (ret_val) {
e_dbg("Failed to initialize PHY flow\n");
@@ -300,33 +351,9 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
break;
}
- e_dbg("Toggling LANPHYPC\n");
-
- /* Set Phy Config Counter to 50msec */
- mac_reg = er32(FEXTNVM3);
- mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK;
- mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
- ew32(FEXTNVM3, mac_reg);
-
/* Toggle LANPHYPC Value bit */
- mac_reg = er32(CTRL);
- mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE;
- mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE;
- ew32(CTRL, mac_reg);
- e1e_flush();
- usleep_range(10, 20);
- mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
- ew32(CTRL, mac_reg);
- e1e_flush();
- if (hw->mac.type < e1000_pch_lpt) {
- msleep(50);
- } else {
- u16 count = 20;
- do {
- usleep_range(5000, 10000);
- } while (!(er32(CTRL_EXT) &
- E1000_CTRL_EXT_LPCD) && count--);
- usleep_range(30000, 60000);
+ e1000_toggle_lanphypc_pch_lpt(hw);
+ if (hw->mac.type >= e1000_pch_lpt) {
if (e1000_phy_is_accessible_pchlan(hw))
break;
@@ -349,12 +376,31 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
hw->phy.ops.release(hw);
if (!ret_val) {
+
+ /* Check to see if able to reset PHY. Print error if not */
+ if (hw->phy.ops.check_reset_block(hw)) {
+ e_err("Reset blocked by ME\n");
+ goto out;
+ }
+
/* Reset the PHY before any access to it. Doing so, ensures
* that the PHY is in a known good state before we read/write
* PHY registers. The generic reset is sufficient here,
* because we haven't determined the PHY type yet.
*/
ret_val = e1000e_phy_hw_reset_generic(hw);
+ if (ret_val)
+ goto out;
+
+ /* On a successful reset, possibly need to wait for the PHY
+ * to quiesce to an accessible state before returning control
+ * to the calling function. If the PHY does not quiesce, then
+ * return E1000E_BLK_PHY_RESET, as this is the condition that
+ * the PHY is in.
+ */
+ ret_val = hw->phy.ops.check_reset_block(hw);
+ if (ret_val)
+ e_err("ME blocked access to PHY after reset\n");
}
out:
@@ -724,8 +770,14 @@ s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data)
* Enable/disable EEE based on setting in dev_spec structure, the duplex of
* the link and the EEE capabilities of the link partner. The LPI Control
* register bits will remain set only if/when link is up.
+ *
+ * EEE LPI must not be asserted earlier than one second after link is up.
+ * On 82579, EEE LPI should not be enabled until such time otherwise there
+ * can be link issues with some switches. Other devices can have EEE LPI
+ * enabled immediately upon link up since they have a timer in hardware which
+ * prevents LPI from being asserted too early.
**/
-static s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
+s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
{
struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
s32 ret_val;
@@ -979,6 +1031,253 @@ static s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link)
}
/**
+ * e1000_enable_ulp_lpt_lp - configure Ultra Low Power mode for LynxPoint-LP
+ * @hw: pointer to the HW structure
+ * @to_sx: boolean indicating a system power state transition to Sx
+ *
+ * When link is down, configure ULP mode to significantly reduce the power
+ * to the PHY. If on a Manageability Engine (ME) enabled system, tell the
+ * ME firmware to start the ULP configuration. If not on an ME enabled
+ * system, configure the ULP mode by software.
+ */
+s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx)
+{
+ u32 mac_reg;
+ s32 ret_val = 0;
+ u16 phy_reg;
+
+ if ((hw->mac.type < e1000_pch_lpt) ||
+ (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_LM) ||
+ (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_V) ||
+ (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_LM2) ||
+ (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_V2) ||
+ (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_on))
+ return 0;
+
+ if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) {
+ /* Request ME configure ULP mode in the PHY */
+ mac_reg = er32(H2ME);
+ mac_reg |= E1000_H2ME_ULP | E1000_H2ME_ENFORCE_SETTINGS;
+ ew32(H2ME, mac_reg);
+
+ goto out;
+ }
+
+ if (!to_sx) {
+ int i = 0;
+
+ /* Poll up to 5 seconds for Cable Disconnected indication */
+ while (!(er32(FEXT) & E1000_FEXT_PHY_CABLE_DISCONNECTED)) {
+ /* Bail if link is re-acquired */
+ if (er32(STATUS) & E1000_STATUS_LU)
+ return -E1000_ERR_PHY;
+
+ if (i++ == 100)
+ break;
+
+ msleep(50);
+ }
+ e_dbg("CABLE_DISCONNECTED %s set after %dmsec\n",
+ (er32(FEXT) &
+ E1000_FEXT_PHY_CABLE_DISCONNECTED) ? "" : "not", i * 50);
+ }
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ /* Force SMBus mode in PHY */
+ ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
+ if (ret_val)
+ goto release;
+ phy_reg |= CV_SMB_CTRL_FORCE_SMBUS;
+ e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg);
+
+ /* Force SMBus mode in MAC */
+ mac_reg = er32(CTRL_EXT);
+ mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
+ ew32(CTRL_EXT, mac_reg);
+
+ /* Set Inband ULP Exit, Reset to SMBus mode and
+ * Disable SMBus Release on PERST# in PHY
+ */
+ ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg);
+ if (ret_val)
+ goto release;
+ phy_reg |= (I218_ULP_CONFIG1_RESET_TO_SMBUS |
+ I218_ULP_CONFIG1_DISABLE_SMB_PERST);
+ if (to_sx) {
+ if (er32(WUFC) & E1000_WUFC_LNKC)
+ phy_reg |= I218_ULP_CONFIG1_WOL_HOST;
+
+ phy_reg |= I218_ULP_CONFIG1_STICKY_ULP;
+ } else {
+ phy_reg |= I218_ULP_CONFIG1_INBAND_EXIT;
+ }
+ e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
+
+ /* Set Disable SMBus Release on PERST# in MAC */
+ mac_reg = er32(FEXTNVM7);
+ mac_reg |= E1000_FEXTNVM7_DISABLE_SMB_PERST;
+ ew32(FEXTNVM7, mac_reg);
+
+ /* Commit ULP changes in PHY by starting auto ULP configuration */
+ phy_reg |= I218_ULP_CONFIG1_START;
+ e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
+release:
+ hw->phy.ops.release(hw);
+out:
+ if (ret_val)
+ e_dbg("Error in ULP enable flow: %d\n", ret_val);
+ else
+ hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_on;
+
+ return ret_val;
+}
+
+/**
+ * e1000_disable_ulp_lpt_lp - unconfigure Ultra Low Power mode for LynxPoint-LP
+ * @hw: pointer to the HW structure
+ * @force: boolean indicating whether or not to force disabling ULP
+ *
+ * Un-configure ULP mode when link is up, the system is transitioned from
+ * Sx or the driver is unloaded. If on a Manageability Engine (ME) enabled
+ * system, poll for an indication from ME that ULP has been un-configured.
+ * If not on an ME enabled system, un-configure the ULP mode by software.
+ *
+ * During nominal operation, this function is called when link is acquired
+ * to disable ULP mode (force=false); otherwise, for example when unloading
+ * the driver or during Sx->S0 transitions, this is called with force=true
+ * to forcibly disable ULP.
+ */
+static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force)
+{
+ s32 ret_val = 0;
+ u32 mac_reg;
+ u16 phy_reg;
+ int i = 0;
+
+ if ((hw->mac.type < e1000_pch_lpt) ||
+ (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_LM) ||
+ (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_V) ||
+ (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_LM2) ||
+ (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_V2) ||
+ (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_off))
+ return 0;
+
+ if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) {
+ if (force) {
+ /* Request ME un-configure ULP mode in the PHY */
+ mac_reg = er32(H2ME);
+ mac_reg &= ~E1000_H2ME_ULP;
+ mac_reg |= E1000_H2ME_ENFORCE_SETTINGS;
+ ew32(H2ME, mac_reg);
+ }
+
+ /* Poll up to 100msec for ME to clear ULP_CFG_DONE */
+ while (er32(FWSM) & E1000_FWSM_ULP_CFG_DONE) {
+ if (i++ == 10) {
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+ usleep_range(10000, 20000);
+ }
+ e_dbg("ULP_CONFIG_DONE cleared after %dmsec\n", i * 10);
+
+ if (force) {
+ mac_reg = er32(H2ME);
+ mac_reg &= ~E1000_H2ME_ENFORCE_SETTINGS;
+ ew32(H2ME, mac_reg);
+ } else {
+ /* Clear H2ME.ULP after ME ULP configuration */
+ mac_reg = er32(H2ME);
+ mac_reg &= ~E1000_H2ME_ULP;
+ ew32(H2ME, mac_reg);
+ }
+
+ goto out;
+ }
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ if (force)
+ /* Toggle LANPHYPC Value bit */
+ e1000_toggle_lanphypc_pch_lpt(hw);
+
+ /* Unforce SMBus mode in PHY */
+ ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
+ if (ret_val) {
+ /* The MAC might be in PCIe mode, so temporarily force to
+ * SMBus mode in order to access the PHY.
+ */
+ mac_reg = er32(CTRL_EXT);
+ mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
+ ew32(CTRL_EXT, mac_reg);
+
+ msleep(50);
+
+ ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL,
+ &phy_reg);
+ if (ret_val)
+ goto release;
+ }
+ phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
+ e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg);
+
+ /* Unforce SMBus mode in MAC */
+ mac_reg = er32(CTRL_EXT);
+ mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
+ ew32(CTRL_EXT, mac_reg);
+
+ /* When ULP mode was previously entered, K1 was disabled by the
+ * hardware. Re-Enable K1 in the PHY when exiting ULP.
+ */
+ ret_val = e1000_read_phy_reg_hv_locked(hw, HV_PM_CTRL, &phy_reg);
+ if (ret_val)
+ goto release;
+ phy_reg |= HV_PM_CTRL_K1_ENABLE;
+ e1000_write_phy_reg_hv_locked(hw, HV_PM_CTRL, phy_reg);
+
+ /* Clear ULP enabled configuration */
+ ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg);
+ if (ret_val)
+ goto release;
+ phy_reg &= ~(I218_ULP_CONFIG1_IND |
+ I218_ULP_CONFIG1_STICKY_ULP |
+ I218_ULP_CONFIG1_RESET_TO_SMBUS |
+ I218_ULP_CONFIG1_WOL_HOST |
+ I218_ULP_CONFIG1_INBAND_EXIT |
+ I218_ULP_CONFIG1_DISABLE_SMB_PERST);
+ e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
+
+ /* Commit ULP changes by starting auto ULP configuration */
+ phy_reg |= I218_ULP_CONFIG1_START;
+ e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
+
+ /* Clear Disable SMBus Release on PERST# in MAC */
+ mac_reg = er32(FEXTNVM7);
+ mac_reg &= ~E1000_FEXTNVM7_DISABLE_SMB_PERST;
+ ew32(FEXTNVM7, mac_reg);
+
+release:
+ hw->phy.ops.release(hw);
+ if (force) {
+ e1000_phy_hw_reset(hw);
+ msleep(50);
+ }
+out:
+ if (ret_val)
+ e_dbg("Error in ULP disable flow: %d\n", ret_val);
+ else
+ hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_off;
+
+ return ret_val;
+}
+
+/**
* e1000_check_for_copper_link_ich8lan - Check for link (Copper)
* @hw: pointer to the HW structure
*
@@ -1106,9 +1405,11 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
e1000e_check_downshift(hw);
/* Enable/Disable EEE after link up */
- ret_val = e1000_set_eee_pchlan(hw);
- if (ret_val)
- return ret_val;
+ if (hw->phy.type > e1000_phy_82579) {
+ ret_val = e1000_set_eee_pchlan(hw);
+ if (ret_val)
+ return ret_val;
+ }
/* If we are forcing speed/duplex, then we simply return since
* we have already determined whether we have link or not.
@@ -1374,7 +1675,7 @@ static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index)
/* RAR[1-6] are owned by manageability. Skip those and program the
* next address into the SHRA register array.
*/
- if (index < (u32)(hw->mac.rar_entry_count - 6)) {
+ if (index < (u32)(hw->mac.rar_entry_count)) {
s32 ret_val;
ret_val = e1000_acquire_swflag_ich8lan(hw);
@@ -1484,11 +1785,13 @@ out:
**/
static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
{
- u32 fwsm;
+ bool blocked = false;
+ int i = 0;
- fwsm = er32(FWSM);
-
- return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? 0 : E1000_BLK_PHY_RESET;
+ while ((blocked = !(er32(FWSM) & E1000_ICH_FWSM_RSPCIPHY)) &&
+ (i++ < 10))
+ usleep_range(10000, 20000);
+ return blocked ? E1000_BLK_PHY_RESET : 0;
}
/**
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.h b/drivers/net/ethernet/intel/e1000e/ich8lan.h
index 217090df33e7..bead50f9187b 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.h
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.h
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
#ifndef _E1000E_ICH8LAN_H_
#define _E1000E_ICH8LAN_H_
@@ -65,11 +58,16 @@
#define E1000_FWSM_WLOCK_MAC_MASK 0x0380
#define E1000_FWSM_WLOCK_MAC_SHIFT 7
+#define E1000_FWSM_ULP_CFG_DONE 0x00000400 /* Low power cfg done */
/* Shared Receive Address Registers */
#define E1000_SHRAL_PCH_LPT(_i) (0x05408 + ((_i) * 8))
#define E1000_SHRAH_PCH_LPT(_i) (0x0540C + ((_i) * 8))
+#define E1000_H2ME 0x05B50 /* Host to ME */
+#define E1000_H2ME_ULP 0x00000800 /* ULP Indication Bit */
+#define E1000_H2ME_ENFORCE_SETTINGS 0x00001000 /* Enforce Settings */
+
#define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \
(ID_LED_OFF1_OFF2 << 8) | \
(ID_LED_OFF1_ON2 << 4) | \
@@ -82,6 +80,9 @@
#define E1000_ICH8_LAN_INIT_TIMEOUT 1500
+/* FEXT register bit definition */
+#define E1000_FEXT_PHY_CABLE_DISCONNECTED 0x00000004
+
#define E1000_FEXTNVM_SW_CONFIG 1
#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* different on ICH8M */
@@ -95,10 +96,12 @@
#define E1000_FEXTNVM6_REQ_PLL_CLK 0x00000100
#define E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION 0x00000200
+#define E1000_FEXTNVM7_DISABLE_SMB_PERST 0x00000020
+
#define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL
#define E1000_ICH_RAR_ENTRIES 7
-#define E1000_PCH2_RAR_ENTRIES 11 /* RAR[0-6], SHRA[0-3] */
+#define E1000_PCH2_RAR_ENTRIES 5 /* RAR[0], SHRA[0-3] */
#define E1000_PCH_LPT_RAR_ENTRIES 12 /* RAR[0], SHRA[0-10] */
#define PHY_PAGE_SHIFT 5
@@ -161,6 +164,16 @@
#define CV_SMB_CTRL PHY_REG(769, 23)
#define CV_SMB_CTRL_FORCE_SMBUS 0x0001
+/* I218 Ultra Low Power Configuration 1 Register */
+#define I218_ULP_CONFIG1 PHY_REG(779, 16)
+#define I218_ULP_CONFIG1_START 0x0001 /* Start auto ULP config */
+#define I218_ULP_CONFIG1_IND 0x0004 /* Pwr up from ULP indication */
+#define I218_ULP_CONFIG1_STICKY_ULP 0x0010 /* Set sticky ULP mode */
+#define I218_ULP_CONFIG1_INBAND_EXIT 0x0020 /* Inband on ULP exit */
+#define I218_ULP_CONFIG1_WOL_HOST 0x0040 /* WoL Host on ULP exit */
+#define I218_ULP_CONFIG1_RESET_TO_SMBUS 0x0100 /* Reset to SMBus mode */
+#define I218_ULP_CONFIG1_DISABLE_SMB_PERST 0x1000 /* Disable on PERST# */
+
/* SMBus Address Phy Register */
#define HV_SMB_ADDR PHY_REG(768, 26)
#define HV_SMB_ADDR_MASK 0x007F
@@ -195,6 +208,7 @@
/* PHY Power Management Control */
#define HV_PM_CTRL PHY_REG(770, 17)
#define HV_PM_CTRL_PLL_STOP_IN_K1_GIGA 0x100
+#define HV_PM_CTRL_K1_ENABLE 0x4000
#define SW_FLAG_TIMEOUT 1000 /* SW Semaphore flag timeout in ms */
@@ -268,4 +282,6 @@ void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw);
s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable);
s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data);
s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data);
+s32 e1000_set_eee_pchlan(struct e1000_hw *hw);
+s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx);
#endif /* _E1000E_ICH8LAN_H_ */
diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c
index 2480c1091873..baa0a466d1d0 100644
--- a/drivers/net/ethernet/intel/e1000e/mac.c
+++ b/drivers/net/ethernet/intel/e1000e/mac.c
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
#include "e1000.h"
diff --git a/drivers/net/ethernet/intel/e1000e/mac.h b/drivers/net/ethernet/intel/e1000e/mac.h
index a61fee404ebe..4e81c2825b7a 100644
--- a/drivers/net/ethernet/intel/e1000e/mac.h
+++ b/drivers/net/ethernet/intel/e1000e/mac.h
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
#ifndef _E1000E_MAC_H_
#define _E1000E_MAC_H_
diff --git a/drivers/net/ethernet/intel/e1000e/manage.c b/drivers/net/ethernet/intel/e1000e/manage.c
index e4b0f1ef92f6..cb37ff1f1321 100644
--- a/drivers/net/ethernet/intel/e1000e/manage.c
+++ b/drivers/net/ethernet/intel/e1000e/manage.c
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
#include "e1000.h"
diff --git a/drivers/net/ethernet/intel/e1000e/manage.h b/drivers/net/ethernet/intel/e1000e/manage.h
index 326897c29ea8..a8c27f98f7b0 100644
--- a/drivers/net/ethernet/intel/e1000e/manage.h
+++ b/drivers/net/ethernet/intel/e1000e/manage.h
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
#ifndef _E1000E_MANAGE_H_
#define _E1000E_MANAGE_H_
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 6d91933c4cdd..dce377b59b2c 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -885,7 +878,7 @@ static inline void e1000_rx_hash(struct net_device *netdev, __le32 rss,
struct sk_buff *skb)
{
if (netdev->features & NETIF_F_RXHASH)
- skb->rxhash = le32_to_cpu(rss);
+ skb_set_hash(skb, le32_to_cpu(rss), PKT_HASH_TYPE_L3);
}
/**
@@ -1097,8 +1090,14 @@ static void e1000_print_hw_hang(struct work_struct *work)
adapter->tx_hang_recheck = true;
return;
}
- /* Real hang detected */
adapter->tx_hang_recheck = false;
+
+ if (er32(TDH(0)) == er32(TDT(0))) {
+ e_dbg("false hang detected, ignoring\n");
+ return;
+ }
+
+ /* Real hang detected */
netif_stop_queue(netdev);
e1e_rphy(hw, MII_BMSR, &phy_status);
@@ -1128,6 +1127,8 @@ static void e1000_print_hw_hang(struct work_struct *work)
eop, jiffies, eop_desc->upper.fields.status, er32(STATUS),
phy_status, phy_1000t_status, phy_ext_status, pci_status);
+ e1000e_dump(adapter);
+
/* Suggest workaround for known h/w issue */
if ((hw->mac.type == e1000_pchlan) && (er32(CTRL) & E1000_CTRL_TFCE))
e_err("Try turning off Tx pause (flow control) via ethtool\n");
@@ -1147,9 +1148,6 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work)
tx_hwtstamp_work);
struct e1000_hw *hw = &adapter->hw;
- if (!adapter->tx_hwtstamp_skb)
- return;
-
if (er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID) {
struct skb_shared_hwtstamps shhwtstamps;
u64 txstmp;
@@ -1162,6 +1160,12 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work)
skb_tstamp_tx(adapter->tx_hwtstamp_skb, &shhwtstamps);
dev_kfree_skb_any(adapter->tx_hwtstamp_skb);
adapter->tx_hwtstamp_skb = NULL;
+ } else if (time_after(jiffies, adapter->tx_hwtstamp_start
+ + adapter->tx_timeout_factor * HZ)) {
+ dev_kfree_skb_any(adapter->tx_hwtstamp_skb);
+ adapter->tx_hwtstamp_skb = NULL;
+ adapter->tx_hwtstamp_timeouts++;
+ e_warn("clearing Tx timestamp hang");
} else {
/* reschedule to check later */
schedule_work(&adapter->tx_hwtstamp_work);
@@ -1701,7 +1705,7 @@ static void e1000_clean_rx_ring(struct e1000_ring *rx_ring)
adapter->flags2 &= ~FLAG2_IS_DISCARDING;
writel(0, rx_ring->head);
- if (rx_ring->adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+ if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
e1000e_update_rdt_wa(rx_ring, 0);
else
writel(0, rx_ring->tail);
@@ -2038,13 +2042,16 @@ void e1000e_set_interrupt_capability(struct e1000_adapter *adapter)
msix_entry),
GFP_KERNEL);
if (adapter->msix_entries) {
+ struct e1000_adapter *a = adapter;
+
for (i = 0; i < adapter->num_vectors; i++)
adapter->msix_entries[i].entry = i;
- err = pci_enable_msix(adapter->pdev,
- adapter->msix_entries,
- adapter->num_vectors);
- if (err == 0)
+ err = pci_enable_msix_range(a->pdev,
+ a->msix_entries,
+ a->num_vectors,
+ a->num_vectors);
+ if (err > 0)
return;
}
/* MSI-X failed, so fall through and try MSI */
@@ -2402,7 +2409,7 @@ static void e1000_clean_tx_ring(struct e1000_ring *tx_ring)
tx_ring->next_to_clean = 0;
writel(0, tx_ring->head);
- if (tx_ring->adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+ if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
e1000e_update_tdt_wa(tx_ring, 0);
else
writel(0, tx_ring->tail);
@@ -2894,7 +2901,7 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
struct e1000_ring *tx_ring = adapter->tx_ring;
u64 tdba;
- u32 tdlen, tarc;
+ u32 tdlen, tctl, tarc;
/* Setup the HW Tx Head and Tail descriptor pointers */
tdba = tx_ring->dma;
@@ -2931,6 +2938,12 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)
/* erratum work around: set txdctl the same for both queues */
ew32(TXDCTL(1), er32(TXDCTL(0)));
+ /* Program the Transmit Control Register */
+ tctl = er32(TCTL);
+ tctl &= ~E1000_TCTL_CT;
+ tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
+ (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+
if (adapter->flags & FLAG_TARC_SPEED_MODE_BIT) {
tarc = er32(TARC(0));
/* set the speed mode bit, we'll clear it if we're not at
@@ -2961,6 +2974,8 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)
/* enable Report Status bit */
adapter->txd_cmd |= E1000_TXD_CMD_RS;
+ ew32(TCTL, tctl);
+
hw->mac.ops.config_collision_dist(hw);
}
@@ -2976,11 +2991,21 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
u32 rctl, rfctl;
u32 pages = 0;
- /* Workaround Si errata on PCHx - configure jumbo frame flow */
- if ((hw->mac.type >= e1000_pch2lan) &&
- (adapter->netdev->mtu > ETH_DATA_LEN) &&
- e1000_lv_jumbo_workaround_ich8lan(hw, true))
- e_dbg("failed to enable jumbo frame workaround mode\n");
+ /* Workaround Si errata on PCHx - configure jumbo frame flow.
+ * If jumbo frames not set, program related MAC/PHY registers
+ * to h/w defaults
+ */
+ if (hw->mac.type >= e1000_pch2lan) {
+ s32 ret_val;
+
+ if (adapter->netdev->mtu > ETH_DATA_LEN)
+ ret_val = e1000_lv_jumbo_workaround_ich8lan(hw, true);
+ else
+ ret_val = e1000_lv_jumbo_workaround_ich8lan(hw, false);
+
+ if (ret_val)
+ e_dbg("failed to enable|disable jumbo frame workaround mode\n");
+ }
/* Program MC offset vector base */
rctl = er32(RCTL);
@@ -3331,6 +3356,9 @@ static void e1000e_set_rx_mode(struct net_device *netdev)
struct e1000_hw *hw = &adapter->hw;
u32 rctl;
+ if (pm_runtime_suspended(netdev->dev.parent))
+ return;
+
/* Check for Promiscuous and All Multicast modes */
rctl = er32(RCTL);
@@ -3691,10 +3719,6 @@ void e1000e_power_up_phy(struct e1000_adapter *adapter)
*/
static void e1000_power_down_phy(struct e1000_adapter *adapter)
{
- /* WoL is enabled */
- if (adapter->wol)
- return;
-
if (adapter->hw.phy.ops.power_down)
adapter->hw.phy.ops.power_down(&adapter->hw);
}
@@ -3911,10 +3935,8 @@ void e1000e_reset(struct e1000_adapter *adapter)
}
if (!netif_running(adapter->netdev) &&
- !test_bit(__E1000_TESTING, &adapter->state)) {
+ !test_bit(__E1000_TESTING, &adapter->state))
e1000_power_down_phy(adapter);
- return;
- }
e1000_get_phy_info(hw);
@@ -3981,7 +4003,12 @@ static void e1000e_flush_descriptors(struct e1000_adapter *adapter)
static void e1000e_update_stats(struct e1000_adapter *adapter);
-void e1000e_down(struct e1000_adapter *adapter)
+/**
+ * e1000e_down - quiesce the device and optionally reset the hardware
+ * @adapter: board private structure
+ * @reset: boolean flag to reset the hardware or not
+ */
+void e1000e_down(struct e1000_adapter *adapter, bool reset)
{
struct net_device *netdev = adapter->netdev;
struct e1000_hw *hw = &adapter->hw;
@@ -4035,12 +4062,8 @@ void e1000e_down(struct e1000_adapter *adapter)
e1000_lv_jumbo_workaround_ich8lan(hw, false))
e_dbg("failed to disable jumbo frame workaround mode\n");
- if (!pci_channel_offline(adapter->pdev))
+ if (reset && !pci_channel_offline(adapter->pdev))
e1000e_reset(adapter);
-
- /* TODO: for power management, we could drop the link and
- * pci_disable_device here.
- */
}
void e1000e_reinit_locked(struct e1000_adapter *adapter)
@@ -4048,7 +4071,7 @@ void e1000e_reinit_locked(struct e1000_adapter *adapter)
might_sleep();
while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
usleep_range(1000, 2000);
- e1000e_down(adapter);
+ e1000e_down(adapter, true);
e1000e_up(adapter);
clear_bit(__E1000_RESETTING, &adapter->state);
}
@@ -4326,7 +4349,6 @@ static int e1000_open(struct net_device *netdev)
adapter->tx_hang_recheck = false;
netif_start_queue(netdev);
- adapter->idle_check = true;
hw->mac.get_link_status = true;
pm_runtime_put(&pdev->dev);
@@ -4376,14 +4398,15 @@ static int e1000_close(struct net_device *netdev)
pm_runtime_get_sync(&pdev->dev);
if (!test_bit(__E1000_DOWN, &adapter->state)) {
- e1000e_down(adapter);
+ e1000e_down(adapter, true);
e1000_free_irq(adapter);
+
+ /* Link status message must follow this format */
+ pr_info("%s NIC Link is Down\n", adapter->netdev->name);
}
napi_disable(&adapter->napi);
- e1000_power_down_phy(adapter);
-
e1000e_free_tx_resources(adapter->tx_ring);
e1000e_free_rx_resources(adapter->rx_ring);
@@ -4460,11 +4483,16 @@ static void e1000e_update_phy_task(struct work_struct *work)
struct e1000_adapter *adapter = container_of(work,
struct e1000_adapter,
update_phy_task);
+ struct e1000_hw *hw = &adapter->hw;
if (test_bit(__E1000_DOWN, &adapter->state))
return;
- e1000_get_phy_info(&adapter->hw);
+ e1000_get_phy_info(hw);
+
+ /* Enable EEE on 82579 after link up */
+ if (hw->phy.type == e1000_phy_82579)
+ e1000_set_eee_pchlan(hw);
}
/**
@@ -4799,6 +4827,7 @@ static void e1000e_check_82574_phy_workaround(struct e1000_adapter *adapter)
if (adapter->phy_hang_count > 1) {
adapter->phy_hang_count = 0;
+ e_dbg("PHY appears hung - resetting\n");
schedule_work(&adapter->reset_task);
}
}
@@ -4957,15 +4986,11 @@ static void e1000_watchdog_task(struct work_struct *work)
mod_timer(&adapter->phy_info_timer,
round_jiffies(jiffies + 2 * HZ));
- /* The link is lost so the controller stops DMA.
- * If there is queued Tx work that cannot be done
- * or if on an 8000ES2LAN which requires a Rx packet
- * buffer work-around on link down event, reset the
- * controller to flush the Tx/Rx packet buffers.
- * (Do the reset outside of interrupt context).
+ /* 8000ES2LAN requires a Rx packet buffer work-around
+ * on link down event; reset the controller to flush
+ * the Rx packet buffer.
*/
- if ((adapter->flags & FLAG_RX_NEEDS_RESTART) ||
- (e1000_desc_unused(tx_ring) + 1 < tx_ring->count))
+ if (adapter->flags & FLAG_RX_NEEDS_RESTART)
adapter->flags |= FLAG_RESTART_NOW;
else
pm_schedule_suspend(netdev->dev.parent,
@@ -4988,6 +5013,15 @@ link_up:
adapter->gotc_old = adapter->stats.gotc;
spin_unlock(&adapter->stats64_lock);
+ /* If the link is lost the controller stops DMA, but
+ * if there is queued Tx work it cannot be done. So
+ * reset the controller to flush the Tx packet buffers.
+ */
+ if (!netif_carrier_ok(netdev) &&
+ (e1000_desc_unused(tx_ring) + 1 < tx_ring->count))
+ adapter->flags |= FLAG_RESTART_NOW;
+
+ /* If reset is necessary, do it outside of interrupt context. */
if (adapter->flags & FLAG_RESTART_NOW) {
schedule_work(&adapter->reset_task);
/* return immediately since reset is imminent */
@@ -5546,6 +5580,7 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_flags |= E1000_TX_FLAGS_HWTSTAMP;
adapter->tx_hwtstamp_skb = skb_get(skb);
+ adapter->tx_hwtstamp_start = jiffies;
schedule_work(&adapter->tx_hwtstamp_work);
} else {
skb_tx_timestamp(skb);
@@ -5684,8 +5719,11 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
adapter->max_frame_size = max_frame;
e_info("changing MTU from %d to %d\n", netdev->mtu, new_mtu);
netdev->mtu = new_mtu;
+
+ pm_runtime_get_sync(netdev->dev.parent);
+
if (netif_running(netdev))
- e1000e_down(adapter);
+ e1000e_down(adapter, true);
/* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
* means we reserve 2 more, this pushes us to allocate from the next
@@ -5711,6 +5749,8 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
else
e1000e_reset(adapter);
+ pm_runtime_put_sync(netdev->dev.parent);
+
clear_bit(__E1000_RESETTING, &adapter->state);
return 0;
@@ -5852,7 +5892,7 @@ static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc)
{
struct e1000_hw *hw = &adapter->hw;
- u32 i, mac_reg;
+ u32 i, mac_reg, wuc;
u16 phy_reg, wuc_enable;
int retval;
@@ -5899,13 +5939,18 @@ static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc)
phy_reg |= BM_RCTL_RFCE;
hw->phy.ops.write_reg_page(&adapter->hw, BM_RCTL, phy_reg);
+ wuc = E1000_WUC_PME_EN;
+ if (wufc & (E1000_WUFC_MAG | E1000_WUFC_LNKC))
+ wuc |= E1000_WUC_APME;
+
/* enable PHY wakeup in MAC register */
ew32(WUFC, wufc);
- ew32(WUC, E1000_WUC_PHY_WAKE | E1000_WUC_PME_EN);
+ ew32(WUC, (E1000_WUC_PHY_WAKE | E1000_WUC_APMPME |
+ E1000_WUC_PME_STATUS | wuc));
/* configure and enable PHY wakeup in PHY registers */
hw->phy.ops.write_reg_page(&adapter->hw, BM_WUFC, wufc);
- hw->phy.ops.write_reg_page(&adapter->hw, BM_WUC, E1000_WUC_PME_EN);
+ hw->phy.ops.write_reg_page(&adapter->hw, BM_WUC, wuc);
/* activate PHY wakeup */
wuc_enable |= BM_WUC_ENABLE_BIT | BM_WUC_HOST_WU_BIT;
@@ -5918,15 +5963,10 @@ release:
return retval;
}
-static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
+static int e1000e_pm_freeze(struct device *dev)
{
- struct net_device *netdev = pci_get_drvdata(pdev);
+ struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
struct e1000_adapter *adapter = netdev_priv(netdev);
- struct e1000_hw *hw = &adapter->hw;
- u32 ctrl, ctrl_ext, rctl, status;
- /* Runtime suspend should only enable wakeup for link changes */
- u32 wufc = runtime ? E1000_WUFC_LNKC : adapter->wol;
- int retval = 0;
netif_device_detach(netdev);
@@ -5937,11 +5977,29 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
usleep_range(10000, 20000);
WARN_ON(test_bit(__E1000_RESETTING, &adapter->state));
- e1000e_down(adapter);
+
+ /* Quiesce the device without resetting the hardware */
+ e1000e_down(adapter, false);
e1000_free_irq(adapter);
}
e1000e_reset_interrupt_capability(adapter);
+ /* Allow time for pending master requests to run */
+ e1000e_disable_pcie_master(&adapter->hw);
+
+ return 0;
+}
+
+static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 ctrl, ctrl_ext, rctl, status;
+ /* Runtime suspend should only enable wakeup for link changes */
+ u32 wufc = runtime ? E1000_WUFC_LNKC : adapter->wol;
+ int retval = 0;
+
status = er32(STATUS);
if (status & E1000_STATUS_LU)
wufc &= ~E1000_WUFC_LNKC;
@@ -5972,12 +6030,12 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
ew32(CTRL_EXT, ctrl_ext);
}
+ if (!runtime)
+ e1000e_power_up_phy(adapter);
+
if (adapter->flags & FLAG_IS_ICH)
e1000_suspend_workarounds_ich8lan(&adapter->hw);
- /* Allow time for pending master requests to run */
- e1000e_disable_pcie_master(&adapter->hw);
-
if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) {
/* enable wakeup by the PHY */
retval = e1000_init_phy_wakeup(adapter, wufc);
@@ -5991,10 +6049,23 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
} else {
ew32(WUC, 0);
ew32(WUFC, 0);
+
+ e1000_power_down_phy(adapter);
}
- if (adapter->hw.phy.type == e1000_phy_igp_3)
+ if (adapter->hw.phy.type == e1000_phy_igp_3) {
e1000e_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw);
+ } else if (hw->mac.type == e1000_pch_lpt) {
+ if (!(wufc & (E1000_WUFC_EX | E1000_WUFC_MC | E1000_WUFC_BC)))
+ /* ULP does not support wake from unicast, multicast
+ * or broadcast.
+ */
+ retval = e1000_enable_ulp_lpt_lp(hw, !runtime);
+
+ if (retval)
+ return retval;
+ }
+
/* Release control of h/w to f/w. If f/w is AMT enabled, this
* would have already happened in close and is redundant.
@@ -6102,18 +6173,12 @@ static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
}
#ifdef CONFIG_PM
-static bool e1000e_pm_ready(struct e1000_adapter *adapter)
-{
- return !!adapter->tx_ring->buffer_info;
-}
-
static int __e1000_resume(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
u16 aspm_disable_flag = 0;
- u32 err;
if (adapter->flags2 & FLAG2_DISABLE_ASPM_L0S)
aspm_disable_flag = PCIE_LINK_STATE_L0S;
@@ -6124,13 +6189,6 @@ static int __e1000_resume(struct pci_dev *pdev)
pci_set_master(pdev);
- e1000e_set_interrupt_capability(adapter);
- if (netif_running(netdev)) {
- err = e1000_request_irq(adapter);
- if (err)
- return err;
- }
-
if (hw->mac.type >= e1000_pch2lan)
e1000_resume_workarounds_pchlan(&adapter->hw);
@@ -6169,11 +6227,6 @@ static int __e1000_resume(struct pci_dev *pdev)
e1000_init_manageability_pt(adapter);
- if (netif_running(netdev))
- e1000e_up(adapter);
-
- netif_device_attach(netdev);
-
/* If the controller has AMT, do not set DRV_LOAD until the interface
* is up. For all other cases, let the f/w know that the h/w is now
* under the control of the driver.
@@ -6184,75 +6237,111 @@ static int __e1000_resume(struct pci_dev *pdev)
return 0;
}
+static int e1000e_pm_thaw(struct device *dev)
+{
+ struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ e1000e_set_interrupt_capability(adapter);
+ if (netif_running(netdev)) {
+ u32 err = e1000_request_irq(adapter);
+
+ if (err)
+ return err;
+
+ e1000e_up(adapter);
+ }
+
+ netif_device_attach(netdev);
+
+ return 0;
+}
+
#ifdef CONFIG_PM_SLEEP
-static int e1000_suspend(struct device *dev)
+static int e1000e_pm_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
+ e1000e_pm_freeze(dev);
+
return __e1000_shutdown(pdev, false);
}
-static int e1000_resume(struct device *dev)
+static int e1000e_pm_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
- struct net_device *netdev = pci_get_drvdata(pdev);
- struct e1000_adapter *adapter = netdev_priv(netdev);
+ int rc;
- if (e1000e_pm_ready(adapter))
- adapter->idle_check = true;
+ rc = __e1000_resume(pdev);
+ if (rc)
+ return rc;
- return __e1000_resume(pdev);
+ return e1000e_pm_thaw(dev);
}
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM_RUNTIME
-static int e1000_runtime_suspend(struct device *dev)
+static int e1000e_pm_runtime_idle(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev_priv(netdev);
- if (!e1000e_pm_ready(adapter))
- return 0;
+ if (!e1000e_has_link(adapter))
+ pm_schedule_suspend(dev, 5 * MSEC_PER_SEC);
- return __e1000_shutdown(pdev, true);
+ return -EBUSY;
}
-static int e1000_idle(struct device *dev)
+static int e1000e_pm_runtime_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev_priv(netdev);
+ int rc;
- if (!e1000e_pm_ready(adapter))
- return 0;
+ rc = __e1000_resume(pdev);
+ if (rc)
+ return rc;
- if (adapter->idle_check) {
- adapter->idle_check = false;
- if (!e1000e_has_link(adapter))
- pm_schedule_suspend(dev, MSEC_PER_SEC);
- }
+ if (netdev->flags & IFF_UP)
+ rc = e1000e_up(adapter);
- return -EBUSY;
+ return rc;
}
-static int e1000_runtime_resume(struct device *dev)
+static int e1000e_pm_runtime_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev_priv(netdev);
- if (!e1000e_pm_ready(adapter))
- return 0;
+ if (netdev->flags & IFF_UP) {
+ int count = E1000_CHECK_RESET_COUNT;
+
+ while (test_bit(__E1000_RESETTING, &adapter->state) && count--)
+ usleep_range(10000, 20000);
+
+ WARN_ON(test_bit(__E1000_RESETTING, &adapter->state));
+
+ /* Down the device without resetting the hardware */
+ e1000e_down(adapter, false);
+ }
- adapter->idle_check = !dev->power.runtime_auto;
- return __e1000_resume(pdev);
+ if (__e1000_shutdown(pdev, true)) {
+ e1000e_pm_runtime_resume(dev);
+ return -EBUSY;
+ }
+
+ return 0;
}
#endif /* CONFIG_PM_RUNTIME */
#endif /* CONFIG_PM */
static void e1000_shutdown(struct pci_dev *pdev)
{
+ e1000e_pm_freeze(&pdev->dev);
+
__e1000_shutdown(pdev, false);
}
@@ -6338,7 +6427,7 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
return PCI_ERS_RESULT_DISCONNECT;
if (netif_running(netdev))
- e1000e_down(adapter);
+ e1000e_down(adapter, true);
pci_disable_device(pdev);
/* Request a slot slot reset. */
@@ -6350,7 +6439,7 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
* @pdev: Pointer to PCI device
*
* Restart the card from scratch, as if from a cold-boot. Implementation
- * resembles the first-half of the e1000_resume routine.
+ * resembles the first-half of the e1000e_pm_resume routine.
*/
static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
{
@@ -6397,7 +6486,7 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
*
* This callback is called when the error recovery driver tells us that
* its OK to resume normal operation. Implementation resembles the
- * second-half of the e1000_resume routine.
+ * second-half of the e1000e_pm_resume routine.
*/
static void e1000_io_resume(struct pci_dev *pdev)
{
@@ -6902,9 +6991,6 @@ static void e1000_remove(struct pci_dev *pdev)
}
}
- if (!(netdev->flags & IFF_UP))
- e1000_power_down_phy(adapter);
-
/* Don't lie to e1000_close() down the road. */
if (!down)
clear_bit(__E1000_DOWN, &adapter->state);
@@ -7026,9 +7112,16 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = {
MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
static const struct dev_pm_ops e1000_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(e1000_suspend, e1000_resume)
- SET_RUNTIME_PM_OPS(e1000_runtime_suspend, e1000_runtime_resume,
- e1000_idle)
+#ifdef CONFIG_PM_SLEEP
+ .suspend = e1000e_pm_suspend,
+ .resume = e1000e_pm_resume,
+ .freeze = e1000e_pm_freeze,
+ .thaw = e1000e_pm_thaw,
+ .poweroff = e1000e_pm_suspend,
+ .restore = e1000e_pm_resume,
+#endif
+ SET_RUNTIME_PM_OPS(e1000e_pm_runtime_suspend, e1000e_pm_runtime_resume,
+ e1000e_pm_runtime_idle)
};
/* PCI Device API Driver */
@@ -7055,7 +7148,7 @@ static int __init e1000_init_module(void)
int ret;
pr_info("Intel(R) PRO/1000 Network Driver - %s\n",
e1000e_driver_version);
- pr_info("Copyright(c) 1999 - 2013 Intel Corporation.\n");
+ pr_info("Copyright(c) 1999 - 2014 Intel Corporation.\n");
ret = pci_register_driver(&e1000_driver);
return ret;
diff --git a/drivers/net/ethernet/intel/e1000e/nvm.c b/drivers/net/ethernet/intel/e1000e/nvm.c
index d70a03906ac0..a9a976f04bff 100644
--- a/drivers/net/ethernet/intel/e1000e/nvm.c
+++ b/drivers/net/ethernet/intel/e1000e/nvm.c
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
#include "e1000.h"
diff --git a/drivers/net/ethernet/intel/e1000e/nvm.h b/drivers/net/ethernet/intel/e1000e/nvm.h
index 45fc69561627..342bf69efab5 100644
--- a/drivers/net/ethernet/intel/e1000e/nvm.h
+++ b/drivers/net/ethernet/intel/e1000e/nvm.h
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
#ifndef _E1000E_NVM_H_
#define _E1000E_NVM_H_
diff --git a/drivers/net/ethernet/intel/e1000e/param.c b/drivers/net/ethernet/intel/e1000e/param.c
index c16bd75b6caa..d0ac0f3249c8 100644
--- a/drivers/net/ethernet/intel/e1000e/param.c
+++ b/drivers/net/ethernet/intel/e1000e/param.c
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
#include <linux/netdevice.h>
#include <linux/module.h>
@@ -381,6 +374,12 @@ void e1000e_check_options(struct e1000_adapter *adapter)
"%s set to dynamic mode\n", opt.name);
adapter->itr = 20000;
break;
+ case 2:
+ dev_info(&adapter->pdev->dev,
+ "%s Invalid mode - setting default\n",
+ opt.name);
+ adapter->itr_setting = opt.def;
+ /* fall-through */
case 3:
dev_info(&adapter->pdev->dev,
"%s set to dynamic conservative mode\n",
diff --git a/drivers/net/ethernet/intel/e1000e/phy.c b/drivers/net/ethernet/intel/e1000e/phy.c
index 20e71f4ca426..00b3fc98bf30 100644
--- a/drivers/net/ethernet/intel/e1000e/phy.c
+++ b/drivers/net/ethernet/intel/e1000e/phy.c
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
#include "e1000.h"
diff --git a/drivers/net/ethernet/intel/e1000e/phy.h b/drivers/net/ethernet/intel/e1000e/phy.h
index f4f71b9991e3..3841bccf058c 100644
--- a/drivers/net/ethernet/intel/e1000e/phy.h
+++ b/drivers/net/ethernet/intel/e1000e/phy.h
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
#ifndef _E1000E_PHY_H_
#define _E1000E_PHY_H_
diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c
index 065f8c80d4f2..fb1a914a3ad4 100644
--- a/drivers/net/ethernet/intel/e1000e/ptp.c
+++ b/drivers/net/ethernet/intel/e1000e/ptp.c
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
/* PTP 1588 Hardware Clock (PHC)
* Derived from PTP Hardware Clock driver for Intel 82576 and 82580 (igb)
@@ -47,6 +40,7 @@ static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
ptp_clock_info);
struct e1000_hw *hw = &adapter->hw;
bool neg_adj = false;
+ unsigned long flags;
u64 adjustment;
u32 timinca, incvalue;
s32 ret_val;
@@ -64,6 +58,8 @@ static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
if (ret_val)
return ret_val;
+ spin_lock_irqsave(&adapter->systim_lock, flags);
+
incvalue = timinca & E1000_TIMINCA_INCVALUE_MASK;
adjustment = incvalue;
@@ -77,6 +73,8 @@ static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
ew32(TIMINCA, timinca);
+ spin_unlock_irqrestore(&adapter->systim_lock, flags);
+
return 0;
}
@@ -191,6 +189,7 @@ static const struct ptp_clock_info e1000e_ptp_clock_info = {
.n_alarm = 0,
.n_ext_ts = 0,
.n_per_out = 0,
+ .n_pins = 0,
.pps = 0,
.adjfreq = e1000e_phc_adjfreq,
.adjtime = e1000e_phc_adjtime,
diff --git a/drivers/net/ethernet/intel/e1000e/regs.h b/drivers/net/ethernet/intel/e1000e/regs.h
index a7e6a3e37257..ea235bbe50d3 100644
--- a/drivers/net/ethernet/intel/e1000e/regs.h
+++ b/drivers/net/ethernet/intel/e1000e/regs.h
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
- Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
-
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
-
- Contact Information:
- Linux NICS <linux.nics@intel.com>
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
#ifndef _E1000E_REGS_H_
#define _E1000E_REGS_H_
@@ -39,6 +32,7 @@
#define E1000_SCTL 0x00024 /* SerDes Control - RW */
#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */
+#define E1000_FEXT 0x0002C /* Future Extended - RW */
#define E1000_FEXTNVM 0x00028 /* Future Extended NVM - RW */
#define E1000_FEXTNVM3 0x0003C /* Future Extended NVM 3 - RW */
#define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index 72dae4d97b43..beb7b4393a6c 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -86,12 +86,12 @@
#define I40E_NVM_VERSION_LO_SHIFT 0
#define I40E_NVM_VERSION_LO_MASK (0xff << I40E_NVM_VERSION_LO_SHIFT)
-#define I40E_NVM_VERSION_HI_SHIFT 8
-#define I40E_NVM_VERSION_HI_MASK (0xff << I40E_NVM_VERSION_HI_SHIFT)
+#define I40E_NVM_VERSION_HI_SHIFT 12
+#define I40E_NVM_VERSION_HI_MASK (0xf << I40E_NVM_VERSION_HI_SHIFT)
/* The values in here are decimal coded as hex as is the case in the NVM map*/
#define I40E_CURRENT_NVM_VERSION_HI 0x2
-#define I40E_CURRENT_NVM_VERSION_LO 0x30
+#define I40E_CURRENT_NVM_VERSION_LO 0x40
/* magic for getting defines into strings */
#define STRINGIFY(foo) #foo
@@ -136,6 +136,7 @@ enum i40e_state_t {
__I40E_EMP_RESET_REQUESTED,
__I40E_FILTER_OVERFLOW_PROMISC,
__I40E_SUSPENDED,
+ __I40E_BAD_EEPROM,
};
enum i40e_interrupt_policy {
@@ -152,8 +153,21 @@ struct i40e_lump_tracking {
};
#define I40E_DEFAULT_ATR_SAMPLE_RATE 20
-#define I40E_FDIR_MAX_RAW_PACKET_LOOKUP 512
-struct i40e_fdir_data {
+#define I40E_FDIR_MAX_RAW_PACKET_SIZE 512
+#define I40E_FDIR_BUFFER_FULL_MARGIN 10
+#define I40E_FDIR_BUFFER_HEAD_ROOM 200
+
+struct i40e_fdir_filter {
+ struct hlist_node fdir_node;
+ /* filter ipnut set */
+ u8 flow_type;
+ u8 ip4_proto;
+ __be32 dst_ip[4];
+ __be32 src_ip[4];
+ __be16 src_port;
+ __be16 dst_port;
+ __be32 sctp_v_tag;
+ /* filter control */
u16 q_index;
u8 flex_off;
u8 pctype;
@@ -162,7 +176,6 @@ struct i40e_fdir_data {
u8 fd_status;
u16 cnt_index;
u32 fd_id;
- u8 *raw_packet;
};
#define I40E_ETH_P_LLDP 0x88cc
@@ -196,7 +209,7 @@ struct i40e_pf {
bool fc_autoneg_status;
u16 eeprom_version;
- u16 num_vmdq_vsis; /* num vmdq pools this pf has set up */
+ u16 num_vmdq_vsis; /* num vmdq vsis this pf has set up */
u16 num_vmdq_qps; /* num queue pairs per vmdq pool */
u16 num_vmdq_msix; /* num queue vectors per vmdq pool */
u16 num_req_vfs; /* num vfs requested for this vf */
@@ -210,6 +223,9 @@ struct i40e_pf {
u8 atr_sample_rate;
bool wol_en;
+ struct hlist_head fdir_filter_list;
+ u16 fdir_pf_active_filters;
+
#ifdef CONFIG_I40E_VXLAN
__be16 vxlan_ports[I40E_MAX_PF_UDP_OFFLOAD_PORTS];
u16 pending_vxlan_bitmap;
@@ -251,6 +267,9 @@ struct i40e_pf {
#define I40E_FLAG_VXLAN_FILTER_SYNC (u64)(1 << 27)
#endif
+ /* tracks features that get auto disabled by errors */
+ u64 auto_disable_flags;
+
bool stat_offsets_loaded;
struct i40e_hw_port_stats stats;
struct i40e_hw_port_stats stats_offsets;
@@ -477,10 +496,10 @@ static inline char *i40e_fw_version_str(struct i40e_hw *hw)
"f%d.%d a%d.%d n%02x.%02x e%08x",
hw->aq.fw_maj_ver, hw->aq.fw_min_ver,
hw->aq.api_maj_ver, hw->aq.api_min_ver,
- (hw->nvm.version & I40E_NVM_VERSION_HI_MASK)
- >> I40E_NVM_VERSION_HI_SHIFT,
- (hw->nvm.version & I40E_NVM_VERSION_LO_MASK)
- >> I40E_NVM_VERSION_LO_SHIFT,
+ (hw->nvm.version & I40E_NVM_VERSION_HI_MASK) >>
+ I40E_NVM_VERSION_HI_SHIFT,
+ (hw->nvm.version & I40E_NVM_VERSION_LO_MASK) >>
+ I40E_NVM_VERSION_LO_SHIFT,
hw->nvm.eetrack);
return buf;
@@ -534,9 +553,13 @@ struct rtnl_link_stats64 *i40e_get_vsi_stats_struct(struct i40e_vsi *vsi);
int i40e_fetch_switch_configuration(struct i40e_pf *pf,
bool printconfig);
-int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data,
+int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet,
struct i40e_pf *pf, bool add);
-
+int i40e_add_del_fdir(struct i40e_vsi *vsi,
+ struct i40e_fdir_filter *input, bool add);
+void i40e_fdir_check_and_reenable(struct i40e_pf *pf);
+int i40e_get_current_fd_count(struct i40e_pf *pf);
+bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features);
void i40e_set_ethtool_ops(struct net_device *netdev);
struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
u8 *macaddr, s16 vlan,
@@ -575,6 +598,7 @@ void i40e_irq_dynamic_enable(struct i40e_vsi *vsi, int vector);
void i40e_irq_dynamic_disable_icr0(struct i40e_pf *pf);
void i40e_irq_dynamic_enable_icr0(struct i40e_pf *pf);
int i40e_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
+int i40e_vsi_open(struct i40e_vsi *vsi);
void i40e_vlan_stripping_disable(struct i40e_vsi *vsi);
int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid);
int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c
index a50e6b3479ae..ed3902bf249b 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c
@@ -647,9 +647,8 @@ static u16 i40e_clean_asq(struct i40e_hw *hw)
desc_cb = *desc;
cb_func(hw, &desc_cb);
}
- memset((void *)desc, 0, sizeof(struct i40e_aq_desc));
- memset((void *)details, 0,
- sizeof(struct i40e_asq_cmd_details));
+ memset(desc, 0, sizeof(*desc));
+ memset(details, 0, sizeof(*details));
ntc++;
if (ntc == asq->count)
ntc = 0;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
index e7f38b57834d..922cdcc45c54 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_common.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
@@ -162,6 +162,372 @@ i40e_status i40e_aq_queue_shutdown(struct i40e_hw *hw,
return status;
}
+/* The i40e_ptype_lookup table is used to convert from the 8-bit ptype in the
+ * hardware to a bit-field that can be used by SW to more easily determine the
+ * packet type.
+ *
+ * Macros are used to shorten the table lines and make this table human
+ * readable.
+ *
+ * We store the PTYPE in the top byte of the bit field - this is just so that
+ * we can check that the table doesn't have a row missing, as the index into
+ * the table should be the PTYPE.
+ *
+ * Typical work flow:
+ *
+ * IF NOT i40e_ptype_lookup[ptype].known
+ * THEN
+ * Packet is unknown
+ * ELSE IF i40e_ptype_lookup[ptype].outer_ip == I40E_RX_PTYPE_OUTER_IP
+ * Use the rest of the fields to look at the tunnels, inner protocols, etc
+ * ELSE
+ * Use the enum i40e_rx_l2_ptype to decode the packet type
+ * ENDIF
+ */
+
+/* macro to make the table lines short */
+#define I40E_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\
+ { PTYPE, \
+ 1, \
+ I40E_RX_PTYPE_OUTER_##OUTER_IP, \
+ I40E_RX_PTYPE_OUTER_##OUTER_IP_VER, \
+ I40E_RX_PTYPE_##OUTER_FRAG, \
+ I40E_RX_PTYPE_TUNNEL_##T, \
+ I40E_RX_PTYPE_TUNNEL_END_##TE, \
+ I40E_RX_PTYPE_##TEF, \
+ I40E_RX_PTYPE_INNER_PROT_##I, \
+ I40E_RX_PTYPE_PAYLOAD_LAYER_##PL }
+
+#define I40E_PTT_UNUSED_ENTRY(PTYPE) \
+ { PTYPE, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+
+/* shorter macros makes the table fit but are terse */
+#define I40E_RX_PTYPE_NOF I40E_RX_PTYPE_NOT_FRAG
+#define I40E_RX_PTYPE_FRG I40E_RX_PTYPE_FRAG
+#define I40E_RX_PTYPE_INNER_PROT_TS I40E_RX_PTYPE_INNER_PROT_TIMESYNC
+
+/* Lookup table mapping the HW PTYPE to the bit field for decoding */
+struct i40e_rx_ptype_decoded i40e_ptype_lookup[] = {
+ /* L2 Packet types */
+ I40E_PTT_UNUSED_ENTRY(0),
+ I40E_PTT(1, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+ I40E_PTT(2, L2, NONE, NOF, NONE, NONE, NOF, TS, PAY2),
+ I40E_PTT(3, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+ I40E_PTT_UNUSED_ENTRY(4),
+ I40E_PTT_UNUSED_ENTRY(5),
+ I40E_PTT(6, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+ I40E_PTT(7, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+ I40E_PTT_UNUSED_ENTRY(8),
+ I40E_PTT_UNUSED_ENTRY(9),
+ I40E_PTT(10, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+ I40E_PTT(11, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE),
+ I40E_PTT(12, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(13, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(14, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(15, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(16, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(17, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(18, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(19, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(20, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(21, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+
+ /* Non Tunneled IPv4 */
+ I40E_PTT(22, IP, IPV4, FRG, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(23, IP, IPV4, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(24, IP, IPV4, NOF, NONE, NONE, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(25),
+ I40E_PTT(26, IP, IPV4, NOF, NONE, NONE, NOF, TCP, PAY4),
+ I40E_PTT(27, IP, IPV4, NOF, NONE, NONE, NOF, SCTP, PAY4),
+ I40E_PTT(28, IP, IPV4, NOF, NONE, NONE, NOF, ICMP, PAY4),
+
+ /* IPv4 --> IPv4 */
+ I40E_PTT(29, IP, IPV4, NOF, IP_IP, IPV4, FRG, NONE, PAY3),
+ I40E_PTT(30, IP, IPV4, NOF, IP_IP, IPV4, NOF, NONE, PAY3),
+ I40E_PTT(31, IP, IPV4, NOF, IP_IP, IPV4, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(32),
+ I40E_PTT(33, IP, IPV4, NOF, IP_IP, IPV4, NOF, TCP, PAY4),
+ I40E_PTT(34, IP, IPV4, NOF, IP_IP, IPV4, NOF, SCTP, PAY4),
+ I40E_PTT(35, IP, IPV4, NOF, IP_IP, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv4 --> IPv6 */
+ I40E_PTT(36, IP, IPV4, NOF, IP_IP, IPV6, FRG, NONE, PAY3),
+ I40E_PTT(37, IP, IPV4, NOF, IP_IP, IPV6, NOF, NONE, PAY3),
+ I40E_PTT(38, IP, IPV4, NOF, IP_IP, IPV6, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(39),
+ I40E_PTT(40, IP, IPV4, NOF, IP_IP, IPV6, NOF, TCP, PAY4),
+ I40E_PTT(41, IP, IPV4, NOF, IP_IP, IPV6, NOF, SCTP, PAY4),
+ I40E_PTT(42, IP, IPV4, NOF, IP_IP, IPV6, NOF, ICMP, PAY4),
+
+ /* IPv4 --> GRE/NAT */
+ I40E_PTT(43, IP, IPV4, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3),
+
+ /* IPv4 --> GRE/NAT --> IPv4 */
+ I40E_PTT(44, IP, IPV4, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3),
+ I40E_PTT(45, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3),
+ I40E_PTT(46, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(47),
+ I40E_PTT(48, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4),
+ I40E_PTT(49, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4),
+ I40E_PTT(50, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv4 --> GRE/NAT --> IPv6 */
+ I40E_PTT(51, IP, IPV4, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3),
+ I40E_PTT(52, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3),
+ I40E_PTT(53, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(54),
+ I40E_PTT(55, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4),
+ I40E_PTT(56, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4),
+ I40E_PTT(57, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4),
+
+ /* IPv4 --> GRE/NAT --> MAC */
+ I40E_PTT(58, IP, IPV4, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3),
+
+ /* IPv4 --> GRE/NAT --> MAC --> IPv4 */
+ I40E_PTT(59, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3),
+ I40E_PTT(60, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3),
+ I40E_PTT(61, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(62),
+ I40E_PTT(63, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4),
+ I40E_PTT(64, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4),
+ I40E_PTT(65, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv4 --> GRE/NAT -> MAC --> IPv6 */
+ I40E_PTT(66, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3),
+ I40E_PTT(67, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3),
+ I40E_PTT(68, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(69),
+ I40E_PTT(70, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4),
+ I40E_PTT(71, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4),
+ I40E_PTT(72, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4),
+
+ /* IPv4 --> GRE/NAT --> MAC/VLAN */
+ I40E_PTT(73, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3),
+
+ /* IPv4 ---> GRE/NAT -> MAC/VLAN --> IPv4 */
+ I40E_PTT(74, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3),
+ I40E_PTT(75, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3),
+ I40E_PTT(76, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(77),
+ I40E_PTT(78, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4),
+ I40E_PTT(79, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4),
+ I40E_PTT(80, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv4 -> GRE/NAT -> MAC/VLAN --> IPv6 */
+ I40E_PTT(81, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3),
+ I40E_PTT(82, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3),
+ I40E_PTT(83, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(84),
+ I40E_PTT(85, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4),
+ I40E_PTT(86, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4),
+ I40E_PTT(87, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4),
+
+ /* Non Tunneled IPv6 */
+ I40E_PTT(88, IP, IPV6, FRG, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(89, IP, IPV6, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP, PAY3),
+ I40E_PTT_UNUSED_ENTRY(91),
+ I40E_PTT(92, IP, IPV6, NOF, NONE, NONE, NOF, TCP, PAY4),
+ I40E_PTT(93, IP, IPV6, NOF, NONE, NONE, NOF, SCTP, PAY4),
+ I40E_PTT(94, IP, IPV6, NOF, NONE, NONE, NOF, ICMP, PAY4),
+
+ /* IPv6 --> IPv4 */
+ I40E_PTT(95, IP, IPV6, NOF, IP_IP, IPV4, FRG, NONE, PAY3),
+ I40E_PTT(96, IP, IPV6, NOF, IP_IP, IPV4, NOF, NONE, PAY3),
+ I40E_PTT(97, IP, IPV6, NOF, IP_IP, IPV4, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(98),
+ I40E_PTT(99, IP, IPV6, NOF, IP_IP, IPV4, NOF, TCP, PAY4),
+ I40E_PTT(100, IP, IPV6, NOF, IP_IP, IPV4, NOF, SCTP, PAY4),
+ I40E_PTT(101, IP, IPV6, NOF, IP_IP, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv6 --> IPv6 */
+ I40E_PTT(102, IP, IPV6, NOF, IP_IP, IPV6, FRG, NONE, PAY3),
+ I40E_PTT(103, IP, IPV6, NOF, IP_IP, IPV6, NOF, NONE, PAY3),
+ I40E_PTT(104, IP, IPV6, NOF, IP_IP, IPV6, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(105),
+ I40E_PTT(106, IP, IPV6, NOF, IP_IP, IPV6, NOF, TCP, PAY4),
+ I40E_PTT(107, IP, IPV6, NOF, IP_IP, IPV6, NOF, SCTP, PAY4),
+ I40E_PTT(108, IP, IPV6, NOF, IP_IP, IPV6, NOF, ICMP, PAY4),
+
+ /* IPv6 --> GRE/NAT */
+ I40E_PTT(109, IP, IPV6, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3),
+
+ /* IPv6 --> GRE/NAT -> IPv4 */
+ I40E_PTT(110, IP, IPV6, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3),
+ I40E_PTT(111, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3),
+ I40E_PTT(112, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(113),
+ I40E_PTT(114, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4),
+ I40E_PTT(115, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4),
+ I40E_PTT(116, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv6 --> GRE/NAT -> IPv6 */
+ I40E_PTT(117, IP, IPV6, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3),
+ I40E_PTT(118, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3),
+ I40E_PTT(119, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(120),
+ I40E_PTT(121, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4),
+ I40E_PTT(122, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4),
+ I40E_PTT(123, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4),
+
+ /* IPv6 --> GRE/NAT -> MAC */
+ I40E_PTT(124, IP, IPV6, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3),
+
+ /* IPv6 --> GRE/NAT -> MAC -> IPv4 */
+ I40E_PTT(125, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3),
+ I40E_PTT(126, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3),
+ I40E_PTT(127, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(128),
+ I40E_PTT(129, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4),
+ I40E_PTT(130, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4),
+ I40E_PTT(131, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv6 --> GRE/NAT -> MAC -> IPv6 */
+ I40E_PTT(132, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3),
+ I40E_PTT(133, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3),
+ I40E_PTT(134, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(135),
+ I40E_PTT(136, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4),
+ I40E_PTT(137, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4),
+ I40E_PTT(138, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4),
+
+ /* IPv6 --> GRE/NAT -> MAC/VLAN */
+ I40E_PTT(139, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3),
+
+ /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv4 */
+ I40E_PTT(140, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3),
+ I40E_PTT(141, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3),
+ I40E_PTT(142, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(143),
+ I40E_PTT(144, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4),
+ I40E_PTT(145, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4),
+ I40E_PTT(146, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv6 */
+ I40E_PTT(147, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3),
+ I40E_PTT(148, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3),
+ I40E_PTT(149, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(150),
+ I40E_PTT(151, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4),
+ I40E_PTT(152, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4),
+ I40E_PTT(153, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4),
+
+ /* unused entries */
+ I40E_PTT_UNUSED_ENTRY(154),
+ I40E_PTT_UNUSED_ENTRY(155),
+ I40E_PTT_UNUSED_ENTRY(156),
+ I40E_PTT_UNUSED_ENTRY(157),
+ I40E_PTT_UNUSED_ENTRY(158),
+ I40E_PTT_UNUSED_ENTRY(159),
+
+ I40E_PTT_UNUSED_ENTRY(160),
+ I40E_PTT_UNUSED_ENTRY(161),
+ I40E_PTT_UNUSED_ENTRY(162),
+ I40E_PTT_UNUSED_ENTRY(163),
+ I40E_PTT_UNUSED_ENTRY(164),
+ I40E_PTT_UNUSED_ENTRY(165),
+ I40E_PTT_UNUSED_ENTRY(166),
+ I40E_PTT_UNUSED_ENTRY(167),
+ I40E_PTT_UNUSED_ENTRY(168),
+ I40E_PTT_UNUSED_ENTRY(169),
+
+ I40E_PTT_UNUSED_ENTRY(170),
+ I40E_PTT_UNUSED_ENTRY(171),
+ I40E_PTT_UNUSED_ENTRY(172),
+ I40E_PTT_UNUSED_ENTRY(173),
+ I40E_PTT_UNUSED_ENTRY(174),
+ I40E_PTT_UNUSED_ENTRY(175),
+ I40E_PTT_UNUSED_ENTRY(176),
+ I40E_PTT_UNUSED_ENTRY(177),
+ I40E_PTT_UNUSED_ENTRY(178),
+ I40E_PTT_UNUSED_ENTRY(179),
+
+ I40E_PTT_UNUSED_ENTRY(180),
+ I40E_PTT_UNUSED_ENTRY(181),
+ I40E_PTT_UNUSED_ENTRY(182),
+ I40E_PTT_UNUSED_ENTRY(183),
+ I40E_PTT_UNUSED_ENTRY(184),
+ I40E_PTT_UNUSED_ENTRY(185),
+ I40E_PTT_UNUSED_ENTRY(186),
+ I40E_PTT_UNUSED_ENTRY(187),
+ I40E_PTT_UNUSED_ENTRY(188),
+ I40E_PTT_UNUSED_ENTRY(189),
+
+ I40E_PTT_UNUSED_ENTRY(190),
+ I40E_PTT_UNUSED_ENTRY(191),
+ I40E_PTT_UNUSED_ENTRY(192),
+ I40E_PTT_UNUSED_ENTRY(193),
+ I40E_PTT_UNUSED_ENTRY(194),
+ I40E_PTT_UNUSED_ENTRY(195),
+ I40E_PTT_UNUSED_ENTRY(196),
+ I40E_PTT_UNUSED_ENTRY(197),
+ I40E_PTT_UNUSED_ENTRY(198),
+ I40E_PTT_UNUSED_ENTRY(199),
+
+ I40E_PTT_UNUSED_ENTRY(200),
+ I40E_PTT_UNUSED_ENTRY(201),
+ I40E_PTT_UNUSED_ENTRY(202),
+ I40E_PTT_UNUSED_ENTRY(203),
+ I40E_PTT_UNUSED_ENTRY(204),
+ I40E_PTT_UNUSED_ENTRY(205),
+ I40E_PTT_UNUSED_ENTRY(206),
+ I40E_PTT_UNUSED_ENTRY(207),
+ I40E_PTT_UNUSED_ENTRY(208),
+ I40E_PTT_UNUSED_ENTRY(209),
+
+ I40E_PTT_UNUSED_ENTRY(210),
+ I40E_PTT_UNUSED_ENTRY(211),
+ I40E_PTT_UNUSED_ENTRY(212),
+ I40E_PTT_UNUSED_ENTRY(213),
+ I40E_PTT_UNUSED_ENTRY(214),
+ I40E_PTT_UNUSED_ENTRY(215),
+ I40E_PTT_UNUSED_ENTRY(216),
+ I40E_PTT_UNUSED_ENTRY(217),
+ I40E_PTT_UNUSED_ENTRY(218),
+ I40E_PTT_UNUSED_ENTRY(219),
+
+ I40E_PTT_UNUSED_ENTRY(220),
+ I40E_PTT_UNUSED_ENTRY(221),
+ I40E_PTT_UNUSED_ENTRY(222),
+ I40E_PTT_UNUSED_ENTRY(223),
+ I40E_PTT_UNUSED_ENTRY(224),
+ I40E_PTT_UNUSED_ENTRY(225),
+ I40E_PTT_UNUSED_ENTRY(226),
+ I40E_PTT_UNUSED_ENTRY(227),
+ I40E_PTT_UNUSED_ENTRY(228),
+ I40E_PTT_UNUSED_ENTRY(229),
+
+ I40E_PTT_UNUSED_ENTRY(230),
+ I40E_PTT_UNUSED_ENTRY(231),
+ I40E_PTT_UNUSED_ENTRY(232),
+ I40E_PTT_UNUSED_ENTRY(233),
+ I40E_PTT_UNUSED_ENTRY(234),
+ I40E_PTT_UNUSED_ENTRY(235),
+ I40E_PTT_UNUSED_ENTRY(236),
+ I40E_PTT_UNUSED_ENTRY(237),
+ I40E_PTT_UNUSED_ENTRY(238),
+ I40E_PTT_UNUSED_ENTRY(239),
+
+ I40E_PTT_UNUSED_ENTRY(240),
+ I40E_PTT_UNUSED_ENTRY(241),
+ I40E_PTT_UNUSED_ENTRY(242),
+ I40E_PTT_UNUSED_ENTRY(243),
+ I40E_PTT_UNUSED_ENTRY(244),
+ I40E_PTT_UNUSED_ENTRY(245),
+ I40E_PTT_UNUSED_ENTRY(246),
+ I40E_PTT_UNUSED_ENTRY(247),
+ I40E_PTT_UNUSED_ENTRY(248),
+ I40E_PTT_UNUSED_ENTRY(249),
+
+ I40E_PTT_UNUSED_ENTRY(250),
+ I40E_PTT_UNUSED_ENTRY(251),
+ I40E_PTT_UNUSED_ENTRY(252),
+ I40E_PTT_UNUSED_ENTRY(253),
+ I40E_PTT_UNUSED_ENTRY(254),
+ I40E_PTT_UNUSED_ENTRY(255)
+};
+
+
/**
* i40e_init_shared_code - Initialize the shared code
* @hw: pointer to hardware structure
@@ -1409,9 +1775,9 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff,
cap = (struct i40e_aqc_list_capabilities_element_resp *) buff;
if (list_type_opc == i40e_aqc_opc_list_dev_capabilities)
- p = (struct i40e_hw_capabilities *)&hw->dev_caps;
+ p = &hw->dev_caps;
else if (list_type_opc == i40e_aqc_opc_list_func_capabilities)
- p = (struct i40e_hw_capabilities *)&hw->func_caps;
+ p = &hw->func_caps;
else
return;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb.c b/drivers/net/ethernet/intel/i40e/i40e_dcb.c
index 50730141bb7b..036570d76176 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_dcb.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_dcb.c
@@ -332,6 +332,7 @@ i40e_status i40e_lldp_to_dcb_config(u8 *lldpmib,
u16 type;
u16 length;
u16 typelength;
+ u16 offset = 0;
if (!lldpmib || !dcbcfg)
return I40E_ERR_PARAM;
@@ -339,15 +340,17 @@ i40e_status i40e_lldp_to_dcb_config(u8 *lldpmib,
/* set to the start of LLDPDU */
lldpmib += ETH_HLEN;
tlv = (struct i40e_lldp_org_tlv *)lldpmib;
- while (tlv) {
+ while (1) {
typelength = ntohs(tlv->typelength);
type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
I40E_LLDP_TLV_TYPE_SHIFT);
length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
I40E_LLDP_TLV_LEN_SHIFT);
+ offset += sizeof(typelength) + length;
- if (type == I40E_TLV_TYPE_END)
- break;/* END TLV break out */
+ /* END TLV or beyond LLDPDU size */
+ if ((type == I40E_TLV_TYPE_END) || (offset > I40E_LLDPDU_SIZE))
+ break;
switch (type) {
case I40E_TLV_TYPE_ORG:
diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
index da22c3fa2c00..3c37386fd138 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
@@ -1011,10 +1011,12 @@ static void i40e_dbg_dump_veb_all(struct i40e_pf *pf)
**/
static void i40e_dbg_cmd_fd_ctrl(struct i40e_pf *pf, u64 flag, bool enable)
{
- if (enable)
+ if (enable) {
pf->flags |= flag;
- else
+ } else {
pf->flags &= ~flag;
+ pf->auto_disable_flags |= flag;
+ }
dev_info(&pf->pdev->dev, "requesting a pf reset\n");
i40e_do_reset_safe(pf, (1 << __I40E_PF_RESET_REQUESTED));
}
@@ -1467,19 +1469,19 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
pf->msg_enable);
}
} else if (strncmp(cmd_buf, "pfr", 3) == 0) {
- dev_info(&pf->pdev->dev, "forcing PFR\n");
+ dev_info(&pf->pdev->dev, "debugfs: forcing PFR\n");
i40e_do_reset_safe(pf, (1 << __I40E_PF_RESET_REQUESTED));
} else if (strncmp(cmd_buf, "corer", 5) == 0) {
- dev_info(&pf->pdev->dev, "forcing CoreR\n");
+ dev_info(&pf->pdev->dev, "debugfs: forcing CoreR\n");
i40e_do_reset_safe(pf, (1 << __I40E_CORE_RESET_REQUESTED));
} else if (strncmp(cmd_buf, "globr", 5) == 0) {
- dev_info(&pf->pdev->dev, "forcing GlobR\n");
+ dev_info(&pf->pdev->dev, "debugfs: forcing GlobR\n");
i40e_do_reset_safe(pf, (1 << __I40E_GLOBAL_RESET_REQUESTED));
} else if (strncmp(cmd_buf, "empr", 4) == 0) {
- dev_info(&pf->pdev->dev, "forcing EMPR\n");
+ dev_info(&pf->pdev->dev, "debugfs: forcing EMPR\n");
i40e_do_reset_safe(pf, (1 << __I40E_EMP_RESET_REQUESTED));
} else if (strncmp(cmd_buf, "read", 4) == 0) {
@@ -1663,28 +1665,36 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
desc = NULL;
} else if ((strncmp(cmd_buf, "add fd_filter", 13) == 0) ||
(strncmp(cmd_buf, "rem fd_filter", 13) == 0)) {
- struct i40e_fdir_data fd_data;
+ struct i40e_fdir_filter fd_data;
u16 packet_len, i, j = 0;
char *asc_packet;
+ u8 *raw_packet;
bool add = false;
int ret;
- asc_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP,
+ if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
+ goto command_write_done;
+
+ if (strncmp(cmd_buf, "add", 3) == 0)
+ add = true;
+
+ if (add && (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED))
+ goto command_write_done;
+
+ asc_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE,
GFP_KERNEL);
if (!asc_packet)
goto command_write_done;
- fd_data.raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP,
- GFP_KERNEL);
+ raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE,
+ GFP_KERNEL);
- if (!fd_data.raw_packet) {
+ if (!raw_packet) {
kfree(asc_packet);
asc_packet = NULL;
goto command_write_done;
}
- if (strncmp(cmd_buf, "add", 3) == 0)
- add = true;
cnt = sscanf(&cmd_buf[13],
"%hx %2hhx %2hhx %hx %2hhx %2hhx %hx %x %hd %511s",
&fd_data.q_index,
@@ -1698,36 +1708,36 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
cnt);
kfree(asc_packet);
asc_packet = NULL;
- kfree(fd_data.raw_packet);
+ kfree(raw_packet);
goto command_write_done;
}
/* fix packet length if user entered 0 */
if (packet_len == 0)
- packet_len = I40E_FDIR_MAX_RAW_PACKET_LOOKUP;
+ packet_len = I40E_FDIR_MAX_RAW_PACKET_SIZE;
/* make sure to check the max as well */
packet_len = min_t(u16,
- packet_len, I40E_FDIR_MAX_RAW_PACKET_LOOKUP);
+ packet_len, I40E_FDIR_MAX_RAW_PACKET_SIZE);
for (i = 0; i < packet_len; i++) {
sscanf(&asc_packet[j], "%2hhx ",
- &fd_data.raw_packet[i]);
+ &raw_packet[i]);
j += 3;
}
dev_info(&pf->pdev->dev, "FD raw packet dump\n");
print_hex_dump(KERN_INFO, "FD raw packet: ",
DUMP_PREFIX_OFFSET, 16, 1,
- fd_data.raw_packet, packet_len, true);
- ret = i40e_program_fdir_filter(&fd_data, pf, add);
+ raw_packet, packet_len, true);
+ ret = i40e_program_fdir_filter(&fd_data, raw_packet, pf, add);
if (!ret) {
dev_info(&pf->pdev->dev, "Filter command send Status : Success\n");
} else {
dev_info(&pf->pdev->dev,
"Filter command send failed %d\n", ret);
}
- kfree(fd_data.raw_packet);
- fd_data.raw_packet = NULL;
+ kfree(raw_packet);
+ raw_packet = NULL;
kfree(asc_packet);
asc_packet = NULL;
} else if (strncmp(cmd_buf, "fd-atr off", 10) == 0) {
@@ -2077,9 +2087,13 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
if (!vsi) {
dev_info(&pf->pdev->dev,
"tx_timeout: VSI %d not found\n", vsi_seid);
- goto netdev_ops_write_done;
- }
- if (rtnl_trylock()) {
+ } else if (!vsi->netdev) {
+ dev_info(&pf->pdev->dev, "tx_timeout: no netdev for VSI %d\n",
+ vsi_seid);
+ } else if (test_bit(__I40E_DOWN, &vsi->state)) {
+ dev_info(&pf->pdev->dev, "tx_timeout: VSI %d not UP\n",
+ vsi_seid);
+ } else if (rtnl_trylock()) {
vsi->netdev->netdev_ops->ndo_tx_timeout(vsi->netdev);
rtnl_unlock();
dev_info(&pf->pdev->dev, "tx_timeout called\n");
@@ -2098,9 +2112,10 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
if (!vsi) {
dev_info(&pf->pdev->dev,
"change_mtu: VSI %d not found\n", vsi_seid);
- goto netdev_ops_write_done;
- }
- if (rtnl_trylock()) {
+ } else if (!vsi->netdev) {
+ dev_info(&pf->pdev->dev, "change_mtu: no netdev for VSI %d\n",
+ vsi_seid);
+ } else if (rtnl_trylock()) {
vsi->netdev->netdev_ops->ndo_change_mtu(vsi->netdev,
mtu);
rtnl_unlock();
@@ -2119,9 +2134,10 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
if (!vsi) {
dev_info(&pf->pdev->dev,
"set_rx_mode: VSI %d not found\n", vsi_seid);
- goto netdev_ops_write_done;
- }
- if (rtnl_trylock()) {
+ } else if (!vsi->netdev) {
+ dev_info(&pf->pdev->dev, "set_rx_mode: no netdev for VSI %d\n",
+ vsi_seid);
+ } else if (rtnl_trylock()) {
vsi->netdev->netdev_ops->ndo_set_rx_mode(vsi->netdev);
rtnl_unlock();
dev_info(&pf->pdev->dev, "set_rx_mode called\n");
@@ -2139,11 +2155,14 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
if (!vsi) {
dev_info(&pf->pdev->dev, "napi: VSI %d not found\n",
vsi_seid);
- goto netdev_ops_write_done;
+ } else if (!vsi->netdev) {
+ dev_info(&pf->pdev->dev, "napi: no netdev for VSI %d\n",
+ vsi_seid);
+ } else {
+ for (i = 0; i < vsi->num_q_vectors; i++)
+ napi_schedule(&vsi->q_vectors[i]->napi);
+ dev_info(&pf->pdev->dev, "napi called\n");
}
- for (i = 0; i < vsi->num_q_vectors; i++)
- napi_schedule(&vsi->q_vectors[i]->napi);
- dev_info(&pf->pdev->dev, "napi called\n");
} else {
dev_info(&pf->pdev->dev, "unknown command '%s'\n",
i40e_dbg_netdev_ops_buf);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
index b1d7d8c5cb9b..03d99cbc5c25 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -62,6 +62,9 @@ static const struct i40e_stats i40e_gstrings_net_stats[] = {
I40E_NETDEV_STAT(rx_crc_errors),
};
+static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
+ struct ethtool_rxnfc *cmd);
+
/* These PF_STATs might look like duplicates of some NETDEV_STATs,
* but they are separate. This device supports Virtualization, and
* as such might have several netdevs supporting VMDq and FCoE going
@@ -84,6 +87,7 @@ static struct i40e_stats i40e_gstrings_stats[] = {
I40E_PF_STAT("illegal_bytes", stats.illegal_bytes),
I40E_PF_STAT("mac_local_faults", stats.mac_local_faults),
I40E_PF_STAT("mac_remote_faults", stats.mac_remote_faults),
+ I40E_PF_STAT("tx_timeout", tx_timeout_count),
I40E_PF_STAT("rx_length_errors", stats.rx_length_errors),
I40E_PF_STAT("link_xon_rx", stats.link_xon_rx),
I40E_PF_STAT("link_xoff_rx", stats.link_xoff_rx),
@@ -110,6 +114,11 @@ static struct i40e_stats i40e_gstrings_stats[] = {
I40E_PF_STAT("VF_admin_queue_requests", vf_aq_requests),
I40E_PF_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
I40E_PF_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
+ /* LPI stats */
+ I40E_PF_STAT("tx_lpi_status", stats.tx_lpi_status),
+ I40E_PF_STAT("rx_lpi_status", stats.rx_lpi_status),
+ I40E_PF_STAT("tx_lpi_count", stats.tx_lpi_count),
+ I40E_PF_STAT("rx_lpi_count", stats.rx_lpi_count),
};
#define I40E_QUEUE_STATS_LEN(n) \
@@ -387,7 +396,7 @@ static int i40e_get_eeprom(struct net_device *netdev,
ret_val = i40e_aq_read_nvm(hw, 0x0,
eeprom->offset + (I40E_NVM_SECTOR_SIZE * i),
len,
- (u8 *)eeprom_buff + (I40E_NVM_SECTOR_SIZE * i),
+ eeprom_buff + (I40E_NVM_SECTOR_SIZE * i),
last, NULL);
if (ret_val) {
dev_info(&pf->pdev->dev,
@@ -399,7 +408,7 @@ static int i40e_get_eeprom(struct net_device *netdev,
release_nvm:
i40e_release_nvm(hw);
- memcpy(bytes, (u8 *)eeprom_buff, eeprom->len);
+ memcpy(bytes, eeprom_buff, eeprom->len);
free_buff:
kfree(eeprom_buff);
return ret_val;
@@ -649,18 +658,18 @@ static void i40e_get_ethtool_stats(struct net_device *netdev,
/* process Tx ring statistics */
do {
- start = u64_stats_fetch_begin_bh(&tx_ring->syncp);
+ start = u64_stats_fetch_begin_irq(&tx_ring->syncp);
data[i] = tx_ring->stats.packets;
data[i + 1] = tx_ring->stats.bytes;
- } while (u64_stats_fetch_retry_bh(&tx_ring->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&tx_ring->syncp, start));
/* Rx ring is the 2nd half of the queue pair */
rx_ring = &tx_ring[1];
do {
- start = u64_stats_fetch_begin_bh(&rx_ring->syncp);
+ start = u64_stats_fetch_begin_irq(&rx_ring->syncp);
data[i + 2] = rx_ring->stats.packets;
data[i + 3] = rx_ring->stats.bytes;
- } while (u64_stats_fetch_retry_bh(&rx_ring->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&rx_ring->syncp, start));
}
rcu_read_unlock();
if (vsi == pf->vsi[pf->lan_vsi]) {
@@ -1112,6 +1121,84 @@ static int i40e_get_rss_hash_opts(struct i40e_pf *pf, struct ethtool_rxnfc *cmd)
}
/**
+ * i40e_get_ethtool_fdir_all - Populates the rule count of a command
+ * @pf: Pointer to the physical function struct
+ * @cmd: The command to get or set Rx flow classification rules
+ * @rule_locs: Array of used rule locations
+ *
+ * This function populates both the total and actual rule count of
+ * the ethtool flow classification command
+ *
+ * Returns 0 on success or -EMSGSIZE if entry not found
+ **/
+static int i40e_get_ethtool_fdir_all(struct i40e_pf *pf,
+ struct ethtool_rxnfc *cmd,
+ u32 *rule_locs)
+{
+ struct i40e_fdir_filter *rule;
+ struct hlist_node *node2;
+ int cnt = 0;
+
+ /* report total rule count */
+ cmd->data = pf->hw.fdir_shared_filter_count +
+ pf->fdir_pf_filter_count;
+
+ hlist_for_each_entry_safe(rule, node2,
+ &pf->fdir_filter_list, fdir_node) {
+ if (cnt == cmd->rule_cnt)
+ return -EMSGSIZE;
+
+ rule_locs[cnt] = rule->fd_id;
+ cnt++;
+ }
+
+ cmd->rule_cnt = cnt;
+
+ return 0;
+}
+
+/**
+ * i40e_get_ethtool_fdir_entry - Look up a filter based on Rx flow
+ * @pf: Pointer to the physical function struct
+ * @cmd: The command to get or set Rx flow classification rules
+ *
+ * This function looks up a filter based on the Rx flow classification
+ * command and fills the flow spec info for it if found
+ *
+ * Returns 0 on success or -EINVAL if filter not found
+ **/
+static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf,
+ struct ethtool_rxnfc *cmd)
+{
+ struct ethtool_rx_flow_spec *fsp =
+ (struct ethtool_rx_flow_spec *)&cmd->fs;
+ struct i40e_fdir_filter *rule = NULL;
+ struct hlist_node *node2;
+
+ /* report total rule count */
+ cmd->data = pf->hw.fdir_shared_filter_count +
+ pf->fdir_pf_filter_count;
+
+ hlist_for_each_entry_safe(rule, node2,
+ &pf->fdir_filter_list, fdir_node) {
+ if (fsp->location <= rule->fd_id)
+ break;
+ }
+
+ if (!rule || fsp->location != rule->fd_id)
+ return -EINVAL;
+
+ fsp->flow_type = rule->flow_type;
+ fsp->h_u.tcp_ip4_spec.psrc = rule->src_port;
+ fsp->h_u.tcp_ip4_spec.pdst = rule->dst_port;
+ fsp->h_u.tcp_ip4_spec.ip4src = rule->src_ip[0];
+ fsp->h_u.tcp_ip4_spec.ip4dst = rule->dst_ip[0];
+ fsp->ring_cookie = rule->q_index;
+
+ return 0;
+}
+
+/**
* i40e_get_rxnfc - command to get RX flow classification rules
* @netdev: network interface device structure
* @cmd: ethtool rxnfc command
@@ -1135,15 +1222,15 @@ static int i40e_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
ret = i40e_get_rss_hash_opts(pf, cmd);
break;
case ETHTOOL_GRXCLSRLCNT:
- cmd->rule_cnt = 10;
+ cmd->rule_cnt = pf->fdir_pf_active_filters;
ret = 0;
break;
case ETHTOOL_GRXCLSRULE:
- ret = 0;
+ ret = i40e_get_ethtool_fdir_entry(pf, cmd);
break;
case ETHTOOL_GRXCLSRLALL:
- cmd->data = 500;
- ret = 0;
+ ret = i40e_get_ethtool_fdir_all(pf, cmd, rule_locs);
+ break;
default:
break;
}
@@ -1274,289 +1361,182 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
return 0;
}
-#define IP_HEADER_OFFSET 14
-#define I40E_UDPIP_DUMMY_PACKET_LEN 42
/**
- * i40e_add_del_fdir_udpv4 - Add/Remove UDPv4 Flow Director filters for
- * a specific flow spec
- * @vsi: pointer to the targeted VSI
- * @fd_data: the flow director data required from the FDir descriptor
- * @ethtool_rx_flow_spec: the flow spec
- * @add: true adds a filter, false removes it
+ * i40e_match_fdir_input_set - Match a new filter against an existing one
+ * @rule: The filter already added
+ * @input: The new filter to comapre against
*
- * Returns 0 if the filters were successfully added or removed
+ * Returns true if the two input set match
**/
-static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,
- struct i40e_fdir_data *fd_data,
- struct ethtool_rx_flow_spec *fsp, bool add)
+static bool i40e_match_fdir_input_set(struct i40e_fdir_filter *rule,
+ struct i40e_fdir_filter *input)
{
- struct i40e_pf *pf = vsi->back;
- struct udphdr *udp;
- struct iphdr *ip;
- bool err = false;
- int ret;
- int i;
- char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
- 0x45, 0, 0, 0x1c, 0, 0, 0x40, 0, 0x40, 0x11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0};
-
- memcpy(fd_data->raw_packet, packet, I40E_UDPIP_DUMMY_PACKET_LEN);
-
- ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET);
- udp = (struct udphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET
- + sizeof(struct iphdr));
-
- ip->saddr = fsp->h_u.tcp_ip4_spec.ip4src;
- ip->daddr = fsp->h_u.tcp_ip4_spec.ip4dst;
- udp->source = fsp->h_u.tcp_ip4_spec.psrc;
- udp->dest = fsp->h_u.tcp_ip4_spec.pdst;
-
- for (i = I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP;
- i <= I40E_FILTER_PCTYPE_NONF_IPV4_UDP; i++) {
- fd_data->pctype = i;
- ret = i40e_program_fdir_filter(fd_data, pf, add);
-
- if (ret) {
- dev_info(&pf->pdev->dev,
- "Filter command send failed for PCTYPE %d (ret = %d)\n",
- fd_data->pctype, ret);
- err = true;
- } else {
- dev_info(&pf->pdev->dev,
- "Filter OK for PCTYPE %d (ret = %d)\n",
- fd_data->pctype, ret);
- }
- }
-
- return err ? -EOPNOTSUPP : 0;
+ if ((rule->dst_ip[0] != input->dst_ip[0]) ||
+ (rule->src_ip[0] != input->src_ip[0]) ||
+ (rule->dst_port != input->dst_port) ||
+ (rule->src_port != input->src_port))
+ return false;
+ return true;
}
-#define I40E_TCPIP_DUMMY_PACKET_LEN 54
/**
- * i40e_add_del_fdir_tcpv4 - Add/Remove TCPv4 Flow Director filters for
- * a specific flow spec
- * @vsi: pointer to the targeted VSI
- * @fd_data: the flow director data required from the FDir descriptor
- * @ethtool_rx_flow_spec: the flow spec
- * @add: true adds a filter, false removes it
+ * i40e_update_ethtool_fdir_entry - Updates the fdir filter entry
+ * @vsi: Pointer to the targeted VSI
+ * @input: The filter to update or NULL to indicate deletion
+ * @sw_idx: Software index to the filter
+ * @cmd: The command to get or set Rx flow classification rules
*
- * Returns 0 if the filters were successfully added or removed
+ * This function updates (or deletes) a Flow Director entry from
+ * the hlist of the corresponding PF
+ *
+ * Returns 0 on success
**/
-static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
- struct i40e_fdir_data *fd_data,
- struct ethtool_rx_flow_spec *fsp, bool add)
+static int i40e_update_ethtool_fdir_entry(struct i40e_vsi *vsi,
+ struct i40e_fdir_filter *input,
+ u16 sw_idx,
+ struct ethtool_rxnfc *cmd)
{
+ struct i40e_fdir_filter *rule, *parent;
struct i40e_pf *pf = vsi->back;
- struct tcphdr *tcp;
- struct iphdr *ip;
- bool err = false;
- int ret;
- /* Dummy packet */
- char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
- 0x45, 0, 0, 0x28, 0, 0, 0x40, 0, 0x40, 0x6,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0x80, 0x11, 0x0, 0x72, 0, 0, 0, 0};
-
- memcpy(fd_data->raw_packet, packet, I40E_TCPIP_DUMMY_PACKET_LEN);
-
- ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET);
- tcp = (struct tcphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET
- + sizeof(struct iphdr));
-
- ip->daddr = fsp->h_u.tcp_ip4_spec.ip4dst;
- tcp->dest = fsp->h_u.tcp_ip4_spec.pdst;
- ip->saddr = fsp->h_u.tcp_ip4_spec.ip4src;
- tcp->source = fsp->h_u.tcp_ip4_spec.psrc;
-
- if (add) {
- if (pf->flags & I40E_FLAG_FD_ATR_ENABLED) {
- dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n");
- pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
- }
- }
+ struct hlist_node *node2;
+ int err = -EINVAL;
- fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN;
- ret = i40e_program_fdir_filter(fd_data, pf, add);
+ parent = NULL;
+ rule = NULL;
- if (ret) {
- dev_info(&pf->pdev->dev,
- "Filter command send failed for PCTYPE %d (ret = %d)\n",
- fd_data->pctype, ret);
- err = true;
- } else {
- dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n",
- fd_data->pctype, ret);
+ hlist_for_each_entry_safe(rule, node2,
+ &pf->fdir_filter_list, fdir_node) {
+ /* hash found, or no matching entry */
+ if (rule->fd_id >= sw_idx)
+ break;
+ parent = rule;
}
- fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
-
- ret = i40e_program_fdir_filter(fd_data, pf, add);
- if (ret) {
- dev_info(&pf->pdev->dev,
- "Filter command send failed for PCTYPE %d (ret = %d)\n",
- fd_data->pctype, ret);
- err = true;
- } else {
- dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n",
- fd_data->pctype, ret);
+ /* if there is an old rule occupying our place remove it */
+ if (rule && (rule->fd_id == sw_idx)) {
+ if (input && !i40e_match_fdir_input_set(rule, input))
+ err = i40e_add_del_fdir(vsi, rule, false);
+ else if (!input)
+ err = i40e_add_del_fdir(vsi, rule, false);
+ hlist_del(&rule->fdir_node);
+ kfree(rule);
+ pf->fdir_pf_active_filters--;
}
- return err ? -EOPNOTSUPP : 0;
-}
+ /* If no input this was a delete, err should be 0 if a rule was
+ * successfully found and removed from the list else -EINVAL
+ */
+ if (!input)
+ return err;
-/**
- * i40e_add_del_fdir_sctpv4 - Add/Remove SCTPv4 Flow Director filters for
- * a specific flow spec
- * @vsi: pointer to the targeted VSI
- * @fd_data: the flow director data required from the FDir descriptor
- * @ethtool_rx_flow_spec: the flow spec
- * @add: true adds a filter, false removes it
- *
- * Returns 0 if the filters were successfully added or removed
- **/
-static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi,
- struct i40e_fdir_data *fd_data,
- struct ethtool_rx_flow_spec *fsp, bool add)
-{
- return -EOPNOTSUPP;
+ /* initialize node and set software index */
+ INIT_HLIST_NODE(&input->fdir_node);
+
+ /* add filter to the list */
+ if (parent)
+ hlist_add_after(&parent->fdir_node, &input->fdir_node);
+ else
+ hlist_add_head(&input->fdir_node,
+ &pf->fdir_filter_list);
+
+ /* update counts */
+ pf->fdir_pf_active_filters++;
+
+ return 0;
}
-#define I40E_IP_DUMMY_PACKET_LEN 34
/**
- * i40e_add_del_fdir_ipv4 - Add/Remove IPv4 Flow Director filters for
- * a specific flow spec
- * @vsi: pointer to the targeted VSI
- * @fd_data: the flow director data required for the FDir descriptor
- * @fsp: the ethtool flow spec
- * @add: true adds a filter, false removes it
+ * i40e_del_fdir_entry - Deletes a Flow Director filter entry
+ * @vsi: Pointer to the targeted VSI
+ * @cmd: The command to get or set Rx flow classification rules
*
- * Returns 0 if the filters were successfully added or removed
- **/
-static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,
- struct i40e_fdir_data *fd_data,
- struct ethtool_rx_flow_spec *fsp, bool add)
+ * The function removes a Flow Director filter entry from the
+ * hlist of the corresponding PF
+ *
+ * Returns 0 on success
+ */
+static int i40e_del_fdir_entry(struct i40e_vsi *vsi,
+ struct ethtool_rxnfc *cmd)
{
+ struct ethtool_rx_flow_spec *fsp =
+ (struct ethtool_rx_flow_spec *)&cmd->fs;
struct i40e_pf *pf = vsi->back;
- struct iphdr *ip;
- bool err = false;
- int ret;
- int i;
- char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
- 0x45, 0, 0, 0x14, 0, 0, 0x40, 0, 0x40, 0x10,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
- memcpy(fd_data->raw_packet, packet, I40E_IP_DUMMY_PACKET_LEN);
- ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET);
+ int ret = 0;
- ip->saddr = fsp->h_u.usr_ip4_spec.ip4src;
- ip->daddr = fsp->h_u.usr_ip4_spec.ip4dst;
- ip->protocol = fsp->h_u.usr_ip4_spec.proto;
+ ret = i40e_update_ethtool_fdir_entry(vsi, NULL, fsp->location, cmd);
- for (i = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
- i <= I40E_FILTER_PCTYPE_FRAG_IPV4; i++) {
- fd_data->pctype = i;
- ret = i40e_program_fdir_filter(fd_data, pf, add);
-
- if (ret) {
- dev_info(&pf->pdev->dev,
- "Filter command send failed for PCTYPE %d (ret = %d)\n",
- fd_data->pctype, ret);
- err = true;
- } else {
- dev_info(&pf->pdev->dev,
- "Filter OK for PCTYPE %d (ret = %d)\n",
- fd_data->pctype, ret);
- }
- }
-
- return err ? -EOPNOTSUPP : 0;
+ i40e_fdir_check_and_reenable(pf);
+ return ret;
}
/**
- * i40e_add_del_fdir_ethtool - Add/Remove Flow Director filters for
- * a specific flow spec based on their protocol
+ * i40e_add_fdir_ethtool - Add/Remove Flow Director filters
* @vsi: pointer to the targeted VSI
* @cmd: command to get or set RX flow classification rules
- * @add: true adds a filter, false removes it
*
- * Returns 0 if the filters were successfully added or removed
+ * Add Flow Director filters for a specific flow spec based on their
+ * protocol. Returns 0 if the filters were successfully added.
**/
-static int i40e_add_del_fdir_ethtool(struct i40e_vsi *vsi,
- struct ethtool_rxnfc *cmd, bool add)
+static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
+ struct ethtool_rxnfc *cmd)
{
- struct i40e_fdir_data fd_data;
- int ret = -EINVAL;
+ struct ethtool_rx_flow_spec *fsp;
+ struct i40e_fdir_filter *input;
struct i40e_pf *pf;
- struct ethtool_rx_flow_spec *fsp =
- (struct ethtool_rx_flow_spec *)&cmd->fs;
+ int ret = -EINVAL;
if (!vsi)
return -EINVAL;
pf = vsi->back;
- if ((fsp->ring_cookie != RX_CLS_FLOW_DISC) &&
- (fsp->ring_cookie >= vsi->num_queue_pairs))
- return -EINVAL;
+ if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
+ return -EOPNOTSUPP;
- /* Populate the Flow Director that we have at the moment
- * and allocate the raw packet buffer for the calling functions
- */
- fd_data.raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP,
- GFP_KERNEL);
+ if (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)
+ return -ENOSPC;
- if (!fd_data.raw_packet) {
- dev_info(&pf->pdev->dev, "Could not allocate memory\n");
- return -ENOMEM;
+ fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
+
+ if (fsp->location >= (pf->hw.func_caps.fd_filters_best_effort +
+ pf->hw.func_caps.fd_filters_guaranteed)) {
+ return -EINVAL;
}
- fd_data.q_index = fsp->ring_cookie;
- fd_data.flex_off = 0;
- fd_data.pctype = 0;
- fd_data.dest_vsi = vsi->id;
- fd_data.dest_ctl = I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX;
- fd_data.fd_status = I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID;
- fd_data.cnt_index = 0;
- fd_data.fd_id = 0;
+ if (fsp->ring_cookie >= vsi->num_queue_pairs)
+ return -EINVAL;
- switch (fsp->flow_type & ~FLOW_EXT) {
- case TCP_V4_FLOW:
- ret = i40e_add_del_fdir_tcpv4(vsi, &fd_data, fsp, add);
- break;
- case UDP_V4_FLOW:
- ret = i40e_add_del_fdir_udpv4(vsi, &fd_data, fsp, add);
- break;
- case SCTP_V4_FLOW:
- ret = i40e_add_del_fdir_sctpv4(vsi, &fd_data, fsp, add);
- break;
- case IPV4_FLOW:
- ret = i40e_add_del_fdir_ipv4(vsi, &fd_data, fsp, add);
- break;
- case IP_USER_FLOW:
- switch (fsp->h_u.usr_ip4_spec.proto) {
- case IPPROTO_TCP:
- ret = i40e_add_del_fdir_tcpv4(vsi, &fd_data, fsp, add);
- break;
- case IPPROTO_UDP:
- ret = i40e_add_del_fdir_udpv4(vsi, &fd_data, fsp, add);
- break;
- case IPPROTO_SCTP:
- ret = i40e_add_del_fdir_sctpv4(vsi, &fd_data, fsp, add);
- break;
- default:
- ret = i40e_add_del_fdir_ipv4(vsi, &fd_data, fsp, add);
- break;
- }
- break;
- default:
- dev_info(&pf->pdev->dev, "Could not specify spec type\n");
- ret = -EINVAL;
- }
+ input = kzalloc(sizeof(*input), GFP_KERNEL);
+
+ if (!input)
+ return -ENOMEM;
- kfree(fd_data.raw_packet);
- fd_data.raw_packet = NULL;
+ input->fd_id = fsp->location;
+
+ if (fsp->ring_cookie == RX_CLS_FLOW_DISC)
+ input->dest_ctl = I40E_FILTER_PROGRAM_DESC_DEST_DROP_PACKET;
+ else
+ input->dest_ctl =
+ I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX;
+
+ input->q_index = fsp->ring_cookie;
+ input->flex_off = 0;
+ input->pctype = 0;
+ input->dest_vsi = vsi->id;
+ input->fd_status = I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID;
+ input->cnt_index = 0;
+ input->flow_type = fsp->flow_type;
+ input->ip4_proto = fsp->h_u.usr_ip4_spec.proto;
+ input->src_port = fsp->h_u.tcp_ip4_spec.psrc;
+ input->dst_port = fsp->h_u.tcp_ip4_spec.pdst;
+ input->src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src;
+ input->dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst;
+
+ ret = i40e_add_del_fdir(vsi, input, true);
+ if (ret)
+ kfree(input);
+ else
+ i40e_update_ethtool_fdir_entry(vsi, input, fsp->location, NULL);
return ret;
}
@@ -1580,10 +1560,10 @@ static int i40e_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
ret = i40e_set_rss_hash_opt(pf, cmd);
break;
case ETHTOOL_SRXCLSRLINS:
- ret = i40e_add_del_fdir_ethtool(vsi, cmd, true);
+ ret = i40e_add_fdir_ethtool(vsi, cmd);
break;
case ETHTOOL_SRXCLSRLDEL:
- ret = i40e_add_del_fdir_ethtool(vsi, cmd, false);
+ ret = i40e_del_fdir_entry(vsi, cmd);
break;
default:
break;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index b901371ca361..861b722c2672 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -26,6 +26,7 @@
/* Local includes */
#include "i40e.h"
+#include "i40e_diag.h"
#ifdef CONFIG_I40E_VXLAN
#include <net/vxlan.h>
#endif
@@ -38,7 +39,7 @@ static const char i40e_driver_string[] =
#define DRV_VERSION_MAJOR 0
#define DRV_VERSION_MINOR 3
-#define DRV_VERSION_BUILD 30
+#define DRV_VERSION_BUILD 36
#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
__stringify(DRV_VERSION_MINOR) "." \
__stringify(DRV_VERSION_BUILD) DRV_KERN
@@ -305,6 +306,7 @@ static void i40e_tx_timeout(struct net_device *netdev)
break;
default:
netdev_err(netdev, "tx_timeout recovery unsuccessful\n");
+ set_bit(__I40E_DOWN, &vsi->state);
i40e_down(vsi);
break;
}
@@ -375,20 +377,20 @@ static struct rtnl_link_stats64 *i40e_get_netdev_stats_struct(
continue;
do {
- start = u64_stats_fetch_begin_bh(&tx_ring->syncp);
+ start = u64_stats_fetch_begin_irq(&tx_ring->syncp);
packets = tx_ring->stats.packets;
bytes = tx_ring->stats.bytes;
- } while (u64_stats_fetch_retry_bh(&tx_ring->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&tx_ring->syncp, start));
stats->tx_packets += packets;
stats->tx_bytes += bytes;
rx_ring = &tx_ring[1];
do {
- start = u64_stats_fetch_begin_bh(&rx_ring->syncp);
+ start = u64_stats_fetch_begin_irq(&rx_ring->syncp);
packets = rx_ring->stats.packets;
bytes = rx_ring->stats.bytes;
- } while (u64_stats_fetch_retry_bh(&rx_ring->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&rx_ring->syncp, start));
stats->rx_packets += packets;
stats->rx_bytes += bytes;
@@ -739,6 +741,7 @@ void i40e_update_stats(struct i40e_vsi *vsi)
u32 rx_page, rx_buf;
u64 rx_p, rx_b;
u64 tx_p, tx_b;
+ u32 val;
int i;
u16 q;
@@ -769,10 +772,10 @@ void i40e_update_stats(struct i40e_vsi *vsi)
p = ACCESS_ONCE(vsi->tx_rings[q]);
do {
- start = u64_stats_fetch_begin_bh(&p->syncp);
+ start = u64_stats_fetch_begin_irq(&p->syncp);
packets = p->stats.packets;
bytes = p->stats.bytes;
- } while (u64_stats_fetch_retry_bh(&p->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&p->syncp, start));
tx_b += bytes;
tx_p += packets;
tx_restart += p->tx_stats.restart_queue;
@@ -781,10 +784,10 @@ void i40e_update_stats(struct i40e_vsi *vsi)
/* Rx queue is part of the same block as Tx queue */
p = &p[1];
do {
- start = u64_stats_fetch_begin_bh(&p->syncp);
+ start = u64_stats_fetch_begin_irq(&p->syncp);
packets = p->stats.packets;
bytes = p->stats.bytes;
- } while (u64_stats_fetch_retry_bh(&p->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&p->syncp, start));
rx_b += bytes;
rx_p += packets;
rx_buf += p->rx_stats.alloc_buff_failed;
@@ -971,6 +974,20 @@ void i40e_update_stats(struct i40e_vsi *vsi)
i40e_stat_update32(hw, I40E_GLPRT_RJC(hw->port),
pf->stat_offsets_loaded,
&osd->rx_jabber, &nsd->rx_jabber);
+
+ val = rd32(hw, I40E_PRTPM_EEE_STAT);
+ nsd->tx_lpi_status =
+ (val & I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_MASK) >>
+ I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_SHIFT;
+ nsd->rx_lpi_status =
+ (val & I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_MASK) >>
+ I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_SHIFT;
+ i40e_stat_update32(hw, I40E_PRTPM_TLPIC,
+ pf->stat_offsets_loaded,
+ &osd->tx_lpi_count, &nsd->tx_lpi_count);
+ i40e_stat_update32(hw, I40E_PRTPM_RLPIC,
+ pf->stat_offsets_loaded,
+ &osd->rx_lpi_count, &nsd->rx_lpi_count);
}
pf->stat_offsets_loaded = true;
@@ -1964,11 +1981,14 @@ static int i40e_vlan_rx_add_vid(struct net_device *netdev,
netdev_info(netdev, "adding %pM vid=%d\n", netdev->dev_addr, vid);
- /* If the network stack called us with vid = 0, we should
- * indicate to i40e_vsi_add_vlan() that we want to receive
- * any traffic (i.e. with any vlan tag, or untagged)
+ /* If the network stack called us with vid = 0 then
+ * it is asking to receive priority tagged packets with
+ * vlan id 0. Our HW receives them by default when configured
+ * to receive untagged packets so there is no need to add an
+ * extra filter for vlan 0 tagged packets.
*/
- ret = i40e_vsi_add_vlan(vsi, vid ? vid : I40E_VLAN_ANY);
+ if (vid)
+ ret = i40e_vsi_add_vlan(vsi, vid);
if (!ret && (vid < VLAN_N_VID))
set_bit(vid, vsi->active_vlans);
@@ -1981,7 +2001,7 @@ static int i40e_vlan_rx_add_vid(struct net_device *netdev,
* @netdev: network interface to be adjusted
* @vid: vlan id to be removed
*
- * net_device_ops implementation for adding vlan ids
+ * net_device_ops implementation for removing vlan ids
**/
static int i40e_vlan_rx_kill_vid(struct net_device *netdev,
__always_unused __be16 proto, u16 vid)
@@ -2177,6 +2197,11 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
tx_ctx.fd_ena = !!(vsi->back->flags & (I40E_FLAG_FD_SB_ENABLED |
I40E_FLAG_FD_ATR_ENABLED));
tx_ctx.timesync_ena = !!(vsi->back->flags & I40E_FLAG_PTP);
+ /* FDIR VSI tx ring can still use RS bit and writebacks */
+ if (vsi->type != I40E_VSI_FDIR)
+ tx_ctx.head_wb_ena = 1;
+ tx_ctx.head_wb_addr = ring->dma +
+ (ring->count * sizeof(struct i40e_tx_desc));
/* As part of VSI creation/update, FW allocates certain
* Tx arbitration queue sets for each TC enabled for
@@ -2420,6 +2445,28 @@ static void i40e_set_vsi_rx_mode(struct i40e_vsi *vsi)
}
/**
+ * i40e_fdir_filter_restore - Restore the Sideband Flow Director filters
+ * @vsi: Pointer to the targeted VSI
+ *
+ * This function replays the hlist on the hw where all the SB Flow Director
+ * filters were saved.
+ **/
+static void i40e_fdir_filter_restore(struct i40e_vsi *vsi)
+{
+ struct i40e_fdir_filter *filter;
+ struct i40e_pf *pf = vsi->back;
+ struct hlist_node *node;
+
+ if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
+ return;
+
+ hlist_for_each_entry_safe(filter, node,
+ &pf->fdir_filter_list, fdir_node) {
+ i40e_add_del_fdir(vsi, filter, true);
+ }
+}
+
+/**
* i40e_vsi_configure - Set up the VSI for action
* @vsi: the VSI being configured
**/
@@ -2557,7 +2604,7 @@ static void i40e_configure_msi_and_legacy(struct i40e_vsi *vsi)
/* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */
wr32(hw, I40E_PFINT_LNKLST0, 0);
- /* Associate the queue pair to the vector and enable the q int */
+ /* Associate the queue pair to the vector and enable the queue int */
val = I40E_QINT_RQCTL_CAUSE_ENA_MASK |
(I40E_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
(I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
@@ -2831,12 +2878,14 @@ static irqreturn_t i40e_intr(int irq, void *data)
val = rd32(hw, I40E_GLGEN_RSTAT);
val = (val & I40E_GLGEN_RSTAT_RESET_TYPE_MASK)
>> I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT;
- if (val == I40E_RESET_CORER)
+ if (val == I40E_RESET_CORER) {
pf->corer_count++;
- else if (val == I40E_RESET_GLOBR)
+ } else if (val == I40E_RESET_GLOBR) {
pf->globr_count++;
- else if (val == I40E_RESET_EMPR)
+ } else if (val == I40E_RESET_EMPR) {
pf->empr_count++;
+ set_bit(__I40E_EMP_RESET_REQUESTED, &pf->state);
+ }
}
if (icr0 & I40E_PFINT_ICR0_HMC_ERR_MASK) {
@@ -2866,8 +2915,7 @@ static irqreturn_t i40e_intr(int irq, void *data)
icr0_remaining);
if ((icr0_remaining & I40E_PFINT_ICR0_PE_CRITERR_MASK) ||
(icr0_remaining & I40E_PFINT_ICR0_PCI_EXCEPTION_MASK) ||
- (icr0_remaining & I40E_PFINT_ICR0_ECC_ERR_MASK) ||
- (icr0_remaining & I40E_PFINT_ICR0_MAL_DETECT_MASK)) {
+ (icr0_remaining & I40E_PFINT_ICR0_ECC_ERR_MASK)) {
dev_info(&pf->pdev->dev, "device will be reset\n");
set_bit(__I40E_PF_RESET_REQUESTED, &pf->state);
i40e_service_event_schedule(pf);
@@ -3107,13 +3155,13 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)
pf_q = vsi->base_queue;
for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
- j = 1000;
- do {
- usleep_range(1000, 2000);
+ for (j = 0; j < 50; j++) {
tx_reg = rd32(hw, I40E_QTX_ENA(pf_q));
- } while (j-- && ((tx_reg >> I40E_QTX_ENA_QENA_REQ_SHIFT)
- ^ (tx_reg >> I40E_QTX_ENA_QENA_STAT_SHIFT)) & 1);
-
+ if (((tx_reg >> I40E_QTX_ENA_QENA_REQ_SHIFT) & 1) ==
+ ((tx_reg >> I40E_QTX_ENA_QENA_STAT_SHIFT) & 1))
+ break;
+ usleep_range(1000, 2000);
+ }
/* Skip if the queue is already in the requested state */
if (enable && (tx_reg & I40E_QTX_ENA_QENA_STAT_MASK))
continue;
@@ -3123,8 +3171,7 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)
/* turn on/off the queue */
if (enable) {
wr32(hw, I40E_QTX_HEAD(pf_q), 0);
- tx_reg |= I40E_QTX_ENA_QENA_REQ_MASK |
- I40E_QTX_ENA_QENA_STAT_MASK;
+ tx_reg |= I40E_QTX_ENA_QENA_REQ_MASK;
} else {
tx_reg &= ~I40E_QTX_ENA_QENA_REQ_MASK;
}
@@ -3171,12 +3218,13 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable)
pf_q = vsi->base_queue;
for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
- j = 1000;
- do {
- usleep_range(1000, 2000);
+ for (j = 0; j < 50; j++) {
rx_reg = rd32(hw, I40E_QRX_ENA(pf_q));
- } while (j-- && ((rx_reg >> I40E_QRX_ENA_QENA_REQ_SHIFT)
- ^ (rx_reg >> I40E_QRX_ENA_QENA_STAT_SHIFT)) & 1);
+ if (((rx_reg >> I40E_QRX_ENA_QENA_REQ_SHIFT) & 1) ==
+ ((rx_reg >> I40E_QRX_ENA_QENA_STAT_SHIFT) & 1))
+ break;
+ usleep_range(1000, 2000);
+ }
if (enable) {
/* is STAT set ? */
@@ -3190,11 +3238,9 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable)
/* turn on/off the queue */
if (enable)
- rx_reg |= I40E_QRX_ENA_QENA_REQ_MASK |
- I40E_QRX_ENA_QENA_STAT_MASK;
+ rx_reg |= I40E_QRX_ENA_QENA_REQ_MASK;
else
- rx_reg &= ~(I40E_QRX_ENA_QENA_REQ_MASK |
- I40E_QRX_ENA_QENA_STAT_MASK);
+ rx_reg &= ~I40E_QRX_ENA_QENA_REQ_MASK;
wr32(hw, I40E_QRX_ENA(pf_q), rx_reg);
/* wait for the change to finish */
@@ -3732,8 +3778,8 @@ static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, u8 enabled_tc,
NULL);
if (aq_ret) {
dev_info(&vsi->back->pdev->dev,
- "%s: AQ command Config VSI BW allocation per TC failed = %d\n",
- __func__, vsi->back->hw.aq.asq_last_status);
+ "AQ command Config VSI BW allocation per TC failed = %d\n",
+ vsi->back->hw.aq.asq_last_status);
return -EINVAL;
}
@@ -4062,6 +4108,10 @@ static int i40e_up_complete(struct i40e_vsi *vsi)
} else if (vsi->netdev) {
netdev_info(vsi->netdev, "NIC Link is Down\n");
}
+
+ /* replay FDIR SB filters */
+ if (vsi->type == I40E_VSI_FDIR)
+ i40e_fdir_filter_restore(vsi);
i40e_service_event_schedule(pf);
return 0;
@@ -4208,15 +4258,40 @@ static int i40e_open(struct net_device *netdev)
struct i40e_netdev_priv *np = netdev_priv(netdev);
struct i40e_vsi *vsi = np->vsi;
struct i40e_pf *pf = vsi->back;
- char int_name[IFNAMSIZ];
int err;
- /* disallow open during test */
- if (test_bit(__I40E_TESTING, &pf->state))
+ /* disallow open during test or if eeprom is broken */
+ if (test_bit(__I40E_TESTING, &pf->state) ||
+ test_bit(__I40E_BAD_EEPROM, &pf->state))
return -EBUSY;
netif_carrier_off(netdev);
+ err = i40e_vsi_open(vsi);
+ if (err)
+ return err;
+
+#ifdef CONFIG_I40E_VXLAN
+ vxlan_get_rx_port(netdev);
+#endif
+
+ return 0;
+}
+
+/**
+ * i40e_vsi_open -
+ * @vsi: the VSI to open
+ *
+ * Finish initialization of the VSI.
+ *
+ * Returns 0 on success, negative value on failure
+ **/
+int i40e_vsi_open(struct i40e_vsi *vsi)
+{
+ struct i40e_pf *pf = vsi->back;
+ char int_name[IFNAMSIZ];
+ int err;
+
/* allocate descriptors */
err = i40e_vsi_setup_tx_resources(vsi);
if (err)
@@ -4229,18 +4304,22 @@ static int i40e_open(struct net_device *netdev)
if (err)
goto err_setup_rx;
+ if (!vsi->netdev) {
+ err = EINVAL;
+ goto err_setup_rx;
+ }
snprintf(int_name, sizeof(int_name) - 1, "%s-%s",
- dev_driver_string(&pf->pdev->dev), netdev->name);
+ dev_driver_string(&pf->pdev->dev), vsi->netdev->name);
err = i40e_vsi_request_irq(vsi, int_name);
if (err)
goto err_setup_rx;
/* Notify the stack of the actual queue counts. */
- err = netif_set_real_num_tx_queues(netdev, vsi->num_queue_pairs);
+ err = netif_set_real_num_tx_queues(vsi->netdev, vsi->num_queue_pairs);
if (err)
goto err_set_queues;
- err = netif_set_real_num_rx_queues(netdev, vsi->num_queue_pairs);
+ err = netif_set_real_num_rx_queues(vsi->netdev, vsi->num_queue_pairs);
if (err)
goto err_set_queues;
@@ -4248,10 +4327,6 @@ static int i40e_open(struct net_device *netdev)
if (err)
goto err_up_complete;
-#ifdef CONFIG_I40E_VXLAN
- vxlan_get_rx_port(netdev);
-#endif
-
return 0;
err_up_complete:
@@ -4269,6 +4344,26 @@ err_setup_tx:
}
/**
+ * i40e_fdir_filter_exit - Cleans up the Flow Director accounting
+ * @pf: Pointer to pf
+ *
+ * This function destroys the hlist where all the Flow Director
+ * filters were saved.
+ **/
+static void i40e_fdir_filter_exit(struct i40e_pf *pf)
+{
+ struct i40e_fdir_filter *filter;
+ struct hlist_node *node2;
+
+ hlist_for_each_entry_safe(filter, node2,
+ &pf->fdir_filter_list, fdir_node) {
+ hlist_del(&filter->fdir_node);
+ kfree(filter);
+ }
+ pf->fdir_pf_active_filters = 0;
+}
+
+/**
* i40e_close - Disables a network interface
* @netdev: network interface device structure
*
@@ -4321,7 +4416,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags)
* for the warning interrupt will deal with the shutdown
* and recovery of the switch setup.
*/
- dev_info(&pf->pdev->dev, "GlobalR requested\n");
+ dev_dbg(&pf->pdev->dev, "GlobalR requested\n");
val = rd32(&pf->hw, I40E_GLGEN_RTRIG);
val |= I40E_GLGEN_RTRIG_GLOBR_MASK;
wr32(&pf->hw, I40E_GLGEN_RTRIG, val);
@@ -4332,7 +4427,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags)
*
* Same as Global Reset, except does *not* include the MAC/PHY
*/
- dev_info(&pf->pdev->dev, "CoreR requested\n");
+ dev_dbg(&pf->pdev->dev, "CoreR requested\n");
val = rd32(&pf->hw, I40E_GLGEN_RTRIG);
val |= I40E_GLGEN_RTRIG_CORER_MASK;
wr32(&pf->hw, I40E_GLGEN_RTRIG, val);
@@ -4366,7 +4461,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags)
* the switch, since we need to do all the recovery as
* for the Core Reset.
*/
- dev_info(&pf->pdev->dev, "PFR requested\n");
+ dev_dbg(&pf->pdev->dev, "PFR requested\n");
i40e_handle_reset_warning(pf);
} else if (reset_flags & (1 << __I40E_REINIT_REQUESTED)) {
@@ -4415,18 +4510,18 @@ bool i40e_dcb_need_reconfig(struct i40e_pf *pf,
&old_cfg->etscfg.prioritytable,
sizeof(new_cfg->etscfg.prioritytable))) {
need_reconfig = true;
- dev_info(&pf->pdev->dev, "ETS UP2TC changed.\n");
+ dev_dbg(&pf->pdev->dev, "ETS UP2TC changed.\n");
}
if (memcmp(&new_cfg->etscfg.tcbwtable,
&old_cfg->etscfg.tcbwtable,
sizeof(new_cfg->etscfg.tcbwtable)))
- dev_info(&pf->pdev->dev, "ETS TC BW Table changed.\n");
+ dev_dbg(&pf->pdev->dev, "ETS TC BW Table changed.\n");
if (memcmp(&new_cfg->etscfg.tsatable,
&old_cfg->etscfg.tsatable,
sizeof(new_cfg->etscfg.tsatable)))
- dev_info(&pf->pdev->dev, "ETS TSA Table changed.\n");
+ dev_dbg(&pf->pdev->dev, "ETS TSA Table changed.\n");
}
/* Check if PFC configuration has changed */
@@ -4434,7 +4529,7 @@ bool i40e_dcb_need_reconfig(struct i40e_pf *pf,
&old_cfg->pfc,
sizeof(new_cfg->pfc))) {
need_reconfig = true;
- dev_info(&pf->pdev->dev, "PFC config change detected.\n");
+ dev_dbg(&pf->pdev->dev, "PFC config change detected.\n");
}
/* Check if APP Table has changed */
@@ -4442,7 +4537,7 @@ bool i40e_dcb_need_reconfig(struct i40e_pf *pf,
&old_cfg->app,
sizeof(new_cfg->app))) {
need_reconfig = true;
- dev_info(&pf->pdev->dev, "APP Table change detected.\n");
+ dev_dbg(&pf->pdev->dev, "APP Table change detected.\n");
}
return need_reconfig;
@@ -4492,7 +4587,7 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf,
/* No change detected in DCBX configs */
if (!memcmp(&tmp_dcbx_cfg, dcbx_cfg, sizeof(tmp_dcbx_cfg))) {
- dev_info(&pf->pdev->dev, "No change detected in DCBX configuration.\n");
+ dev_dbg(&pf->pdev->dev, "No change detected in DCBX configuration.\n");
goto exit;
}
@@ -4550,8 +4645,8 @@ static void i40e_handle_lan_overflow_event(struct i40e_pf *pf,
struct i40e_vf *vf;
u16 vf_id;
- dev_info(&pf->pdev->dev, "%s: Rx Queue Number = %d QTX_CTL=0x%08x\n",
- __func__, queue, qtx_ctl);
+ dev_dbg(&pf->pdev->dev, "overflow Rx Queue Number = %d QTX_CTL=0x%08x\n",
+ queue, qtx_ctl);
/* Queue belongs to VF, find the VF and issue VF reset */
if (((qtx_ctl & I40E_QTX_CTL_PFVF_Q_MASK)
@@ -4581,6 +4676,54 @@ static void i40e_service_event_complete(struct i40e_pf *pf)
}
/**
+ * i40e_get_current_fd_count - Get the count of FD filters programmed in the HW
+ * @pf: board private structure
+ **/
+int i40e_get_current_fd_count(struct i40e_pf *pf)
+{
+ int val, fcnt_prog;
+ val = rd32(&pf->hw, I40E_PFQF_FDSTAT);
+ fcnt_prog = (val & I40E_PFQF_FDSTAT_GUARANT_CNT_MASK) +
+ ((val & I40E_PFQF_FDSTAT_BEST_CNT_MASK) >>
+ I40E_PFQF_FDSTAT_BEST_CNT_SHIFT);
+ return fcnt_prog;
+}
+
+/**
+ * i40e_fdir_check_and_reenable - Function to reenabe FD ATR or SB if disabled
+ * @pf: board private structure
+ **/
+void i40e_fdir_check_and_reenable(struct i40e_pf *pf)
+{
+ u32 fcnt_prog, fcnt_avail;
+
+ /* Check if, FD SB or ATR was auto disabled and if there is enough room
+ * to re-enable
+ */
+ if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
+ (pf->flags & I40E_FLAG_FD_SB_ENABLED))
+ return;
+ fcnt_prog = i40e_get_current_fd_count(pf);
+ fcnt_avail = pf->hw.fdir_shared_filter_count +
+ pf->fdir_pf_filter_count;
+ if (fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM)) {
+ if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
+ (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)) {
+ pf->auto_disable_flags &= ~I40E_FLAG_FD_SB_ENABLED;
+ dev_info(&pf->pdev->dev, "FD Sideband/ntuple is being enabled since we have space in the table now\n");
+ }
+ }
+ /* Wait for some more space to be available to turn on ATR */
+ if (fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM * 2)) {
+ if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
+ (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED)) {
+ pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
+ dev_info(&pf->pdev->dev, "ATR is being enabled since we have space in the table now\n");
+ }
+ }
+}
+
+/**
* i40e_fdir_reinit_subtask - Worker thread to reinit FDIR filter table
* @pf: board private structure
**/
@@ -4589,11 +4732,14 @@ static void i40e_fdir_reinit_subtask(struct i40e_pf *pf)
if (!(pf->flags & I40E_FLAG_FDIR_REQUIRES_REINIT))
return;
- pf->flags &= ~I40E_FLAG_FDIR_REQUIRES_REINIT;
-
/* if interface is down do nothing */
if (test_bit(__I40E_DOWN, &pf->state))
return;
+ i40e_fdir_check_and_reenable(pf);
+
+ if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
+ (pf->flags & I40E_FLAG_FD_SB_ENABLED))
+ pf->flags &= ~I40E_FLAG_FDIR_REQUIRES_REINIT;
}
/**
@@ -4903,7 +5049,7 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf)
event.msg_size);
break;
case i40e_aqc_opc_lldp_update_mib:
- dev_info(&pf->pdev->dev, "ARQ: Update LLDP MIB event received\n");
+ dev_dbg(&pf->pdev->dev, "ARQ: Update LLDP MIB event received\n");
#ifdef CONFIG_I40E_DCB
rtnl_lock();
ret = i40e_handle_lldp_event(pf, &event);
@@ -4911,7 +5057,7 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf)
#endif /* CONFIG_I40E_DCB */
break;
case i40e_aqc_opc_event_lan_overflow:
- dev_info(&pf->pdev->dev, "ARQ LAN queue overflow event received\n");
+ dev_dbg(&pf->pdev->dev, "ARQ LAN queue overflow event received\n");
i40e_handle_lan_overflow_event(pf, &event);
break;
case i40e_aqc_opc_send_msg_to_peer:
@@ -4936,6 +5082,31 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf)
}
/**
+ * i40e_verify_eeprom - make sure eeprom is good to use
+ * @pf: board private structure
+ **/
+static void i40e_verify_eeprom(struct i40e_pf *pf)
+{
+ int err;
+
+ err = i40e_diag_eeprom_test(&pf->hw);
+ if (err) {
+ /* retry in case of garbage read */
+ err = i40e_diag_eeprom_test(&pf->hw);
+ if (err) {
+ dev_info(&pf->pdev->dev, "eeprom check failed (%d), Tx/Rx traffic disabled\n",
+ err);
+ set_bit(__I40E_BAD_EEPROM, &pf->state);
+ }
+ }
+
+ if (!err && test_bit(__I40E_BAD_EEPROM, &pf->state)) {
+ dev_info(&pf->pdev->dev, "eeprom check passed, Tx/Rx traffic enabled\n");
+ clear_bit(__I40E_BAD_EEPROM, &pf->state);
+ }
+}
+
+/**
* i40e_reconstitute_veb - rebuild the VEB and anything connected to it
* @veb: pointer to the VEB instance
*
@@ -5053,6 +5224,12 @@ static int i40e_get_capabilities(struct i40e_pf *pf)
/* increment MSI-X count because current FW skips one */
pf->hw.func_caps.num_msix_vectors++;
+ if (((pf->hw.aq.fw_maj_ver == 2) && (pf->hw.aq.fw_min_ver < 22)) ||
+ (pf->hw.aq.fw_maj_ver < 2)) {
+ pf->hw.func_caps.num_msix_vectors++;
+ pf->hw.func_caps.num_msix_vectors_vf++;
+ }
+
if (pf->hw.debug_mask & I40E_DEBUG_USER)
dev_info(&pf->pdev->dev,
"pf=%d, num_vfs=%d, msix_pf=%d, msix_vf=%d, fd_g=%d, fd_b=%d, pf_max_q=%d num_vsi=%d\n",
@@ -5132,9 +5309,9 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)
err = i40e_up_complete(vsi);
if (err)
goto err_up_complete;
+ clear_bit(__I40E_NEEDS_RESTART, &vsi->state);
}
- clear_bit(__I40E_NEEDS_RESTART, &vsi->state);
return;
err_up_complete:
@@ -5157,6 +5334,7 @@ static void i40e_fdir_teardown(struct i40e_pf *pf)
{
int i;
+ i40e_fdir_filter_exit(pf);
for (i = 0; i < pf->hw.func_caps.num_vsis; i++) {
if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR) {
i40e_vsi_release(pf->vsi[i]);
@@ -5181,7 +5359,7 @@ static int i40e_prep_for_reset(struct i40e_pf *pf)
if (test_and_set_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state))
return 0;
- dev_info(&pf->pdev->dev, "Tearing down internal switch for reset\n");
+ dev_dbg(&pf->pdev->dev, "Tearing down internal switch for reset\n");
if (i40e_check_asq_alive(hw))
i40e_vc_notify_reset(pf);
@@ -5228,7 +5406,7 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
if (test_bit(__I40E_DOWN, &pf->state))
goto end_core_reset;
- dev_info(&pf->pdev->dev, "Rebuilding internal switch\n");
+ dev_dbg(&pf->pdev->dev, "Rebuilding internal switch\n");
/* rebuild the basics for the AdminQ, HMC, and initial HW switch */
ret = i40e_init_adminq(&pf->hw);
@@ -5237,6 +5415,12 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
goto end_core_reset;
}
+ /* re-verify the eeprom if we just had an EMP reset */
+ if (test_bit(__I40E_EMP_RESET_REQUESTED, &pf->state)) {
+ clear_bit(__I40E_EMP_RESET_REQUESTED, &pf->state);
+ i40e_verify_eeprom(pf);
+ }
+
ret = i40e_get_capabilities(pf);
if (ret) {
dev_info(&pf->pdev->dev, "i40e_get_capabilities failed, %d\n",
@@ -5278,7 +5462,7 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
* try to recover minimal use by getting the basic PF VSI working.
*/
if (pf->vsi[pf->lan_vsi]->uplink_seid != pf->mac_seid) {
- dev_info(&pf->pdev->dev, "attempting to rebuild switch\n");
+ dev_dbg(&pf->pdev->dev, "attempting to rebuild switch\n");
/* find the one VEB connected to the MAC, and find orphans */
for (v = 0; v < I40E_MAX_VEB; v++) {
if (!pf->veb[v])
@@ -5331,6 +5515,11 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
/* restart the VSIs that were rebuilt and running before the reset */
i40e_pf_unquiesce_all_vsi(pf);
+ if (pf->num_alloc_vfs) {
+ for (v = 0; v < pf->num_alloc_vfs; v++)
+ i40e_reset_vf(&pf->vf[v], true);
+ }
+
/* tell the firmware that we're starting */
dv.major_version = DRV_VERSION_MAJOR;
dv.minor_version = DRV_VERSION_MINOR;
@@ -5338,7 +5527,7 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
dv.subbuild_version = 0;
i40e_aq_send_driver_version(&pf->hw, &dv, NULL);
- dev_info(&pf->pdev->dev, "PF reset done\n");
+ dev_info(&pf->pdev->dev, "reset complete\n");
end_core_reset:
clear_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state);
@@ -5387,7 +5576,7 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK)
>> I40E_GL_MDET_TX_QUEUE_SHIFT;
dev_info(&pf->pdev->dev,
- "Malicious Driver Detection TX event 0x%02x on q %d of function 0x%02x\n",
+ "Malicious Driver Detection event 0x%02x on TX queue %d of function 0x%02x\n",
event, queue, func);
wr32(hw, I40E_GL_MDET_TX, 0xffffffff);
mdd_detected = true;
@@ -5401,7 +5590,7 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK)
>> I40E_GL_MDET_RX_QUEUE_SHIFT;
dev_info(&pf->pdev->dev,
- "Malicious Driver Detection RX event 0x%02x on q %d of function 0x%02x\n",
+ "Malicious Driver Detection event 0x%02x on RX queue %d of function 0x%02x\n",
event, queue, func);
wr32(hw, I40E_GL_MDET_RX, 0xffffffff);
mdd_detected = true;
@@ -5850,37 +6039,16 @@ err_out:
**/
static int i40e_reserve_msix_vectors(struct i40e_pf *pf, int vectors)
{
- int err = 0;
-
- pf->num_msix_entries = 0;
- while (vectors >= I40E_MIN_MSIX) {
- err = pci_enable_msix(pf->pdev, pf->msix_entries, vectors);
- if (err == 0) {
- /* good to go */
- pf->num_msix_entries = vectors;
- break;
- } else if (err < 0) {
- /* total failure */
- dev_info(&pf->pdev->dev,
- "MSI-X vector reservation failed: %d\n", err);
- vectors = 0;
- break;
- } else {
- /* err > 0 is the hint for retry */
- dev_info(&pf->pdev->dev,
- "MSI-X vectors wanted %d, retrying with %d\n",
- vectors, err);
- vectors = err;
- }
- }
-
- if (vectors > 0 && vectors < I40E_MIN_MSIX) {
+ vectors = pci_enable_msix_range(pf->pdev, pf->msix_entries,
+ I40E_MIN_MSIX, vectors);
+ if (vectors < 0) {
dev_info(&pf->pdev->dev,
- "Couldn't get enough vectors, only %d available\n",
- vectors);
+ "MSI-X vector reservation failed: %d\n", vectors);
vectors = 0;
}
+ pf->num_msix_entries = vectors;
+
return vectors;
}
@@ -5942,7 +6110,7 @@ static int i40e_init_msix(struct i40e_pf *pf)
} else if (vec == I40E_MIN_MSIX) {
/* Adjust for minimal MSIX use */
- dev_info(&pf->pdev->dev, "Features disabled, not enough MSIX vectors\n");
+ dev_info(&pf->pdev->dev, "Features disabled, not enough MSI-X vectors\n");
pf->flags &= ~I40E_FLAG_VMDQ_ENABLED;
pf->num_vmdq_vsis = 0;
pf->num_vmdq_qps = 0;
@@ -5978,13 +6146,13 @@ static int i40e_init_msix(struct i40e_pf *pf)
}
/**
- * i40e_alloc_q_vector - Allocate memory for a single interrupt vector
+ * i40e_vsi_alloc_q_vector - Allocate memory for a single interrupt vector
* @vsi: the VSI being configured
* @v_idx: index of the vector in the vsi struct
*
* We allocate one q_vector. If allocation fails we return -ENOMEM.
**/
-static int i40e_alloc_q_vector(struct i40e_vsi *vsi, int v_idx)
+static int i40e_vsi_alloc_q_vector(struct i40e_vsi *vsi, int v_idx)
{
struct i40e_q_vector *q_vector;
@@ -6010,13 +6178,13 @@ static int i40e_alloc_q_vector(struct i40e_vsi *vsi, int v_idx)
}
/**
- * i40e_alloc_q_vectors - Allocate memory for interrupt vectors
+ * i40e_vsi_alloc_q_vectors - Allocate memory for interrupt vectors
* @vsi: the VSI being configured
*
* We allocate one q_vector per queue interrupt. If allocation fails we
* return -ENOMEM.
**/
-static int i40e_alloc_q_vectors(struct i40e_vsi *vsi)
+static int i40e_vsi_alloc_q_vectors(struct i40e_vsi *vsi)
{
struct i40e_pf *pf = vsi->back;
int v_idx, num_q_vectors;
@@ -6031,7 +6199,7 @@ static int i40e_alloc_q_vectors(struct i40e_vsi *vsi)
return -EINVAL;
for (v_idx = 0; v_idx < num_q_vectors; v_idx++) {
- err = i40e_alloc_q_vector(vsi, v_idx);
+ err = i40e_vsi_alloc_q_vector(vsi, v_idx);
if (err)
goto err_out;
}
@@ -6071,7 +6239,7 @@ static void i40e_init_interrupt_scheme(struct i40e_pf *pf)
if (!(pf->flags & I40E_FLAG_MSIX_ENABLED) &&
(pf->flags & I40E_FLAG_MSI_ENABLED)) {
- dev_info(&pf->pdev->dev, "MSIX not available, trying MSI\n");
+ dev_info(&pf->pdev->dev, "MSI-X not available, trying MSI\n");
err = pci_enable_msi(pf->pdev);
if (err) {
dev_info(&pf->pdev->dev, "MSI init failed - %d\n", err);
@@ -6080,7 +6248,7 @@ static void i40e_init_interrupt_scheme(struct i40e_pf *pf)
}
if (!(pf->flags & (I40E_FLAG_MSIX_ENABLED | I40E_FLAG_MSI_ENABLED)))
- dev_info(&pf->pdev->dev, "MSIX and MSI not available, falling back to Legacy IRQ\n");
+ dev_info(&pf->pdev->dev, "MSI-X and MSI not available, falling back to Legacy IRQ\n");
/* track first vector for misc interrupts */
err = i40e_get_lump(pf, pf->irq_pile, 1, I40E_PILE_VALID_BIT-1);
@@ -6107,7 +6275,8 @@ static int i40e_setup_misc_vector(struct i40e_pf *pf)
i40e_intr, 0, pf->misc_int_name, pf);
if (err) {
dev_info(&pf->pdev->dev,
- "request_irq for msix_misc failed: %d\n", err);
+ "request_irq for %s failed: %d\n",
+ pf->misc_int_name, err);
return -EFAULT;
}
}
@@ -6258,15 +6427,11 @@ static int i40e_sw_init(struct i40e_pf *pf)
(pf->hw.func_caps.fd_filters_best_effort > 0)) {
pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
pf->atr_sample_rate = I40E_DEFAULT_ATR_SAMPLE_RATE;
- dev_info(&pf->pdev->dev,
- "Flow Director ATR mode Enabled\n");
if (!(pf->flags & I40E_FLAG_MFP_ENABLED)) {
pf->flags |= I40E_FLAG_FD_SB_ENABLED;
- dev_info(&pf->pdev->dev,
- "Flow Director Side Band mode Enabled\n");
} else {
dev_info(&pf->pdev->dev,
- "Flow Director Side Band mode Disabled in MFP mode\n");
+ "Flow Director Sideband mode Disabled in MFP mode\n");
}
pf->fdir_pf_filter_count =
pf->hw.func_caps.fd_filters_guaranteed;
@@ -6287,9 +6452,6 @@ static int i40e_sw_init(struct i40e_pf *pf)
pf->num_req_vfs = min_t(int,
pf->hw.func_caps.num_vfs,
I40E_MAX_VF_COUNT);
- dev_info(&pf->pdev->dev,
- "Number of VFs being requested for PF[%d] = %d\n",
- pf->hw.pf_id, pf->num_req_vfs);
}
#endif /* CONFIG_PCI_IOV */
pf->eeprom_version = 0xDEAD;
@@ -6326,6 +6488,39 @@ sw_init_done:
}
/**
+ * i40e_set_ntuple - set the ntuple feature flag and take action
+ * @pf: board private structure to initialize
+ * @features: the feature set that the stack is suggesting
+ *
+ * returns a bool to indicate if reset needs to happen
+ **/
+bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)
+{
+ bool need_reset = false;
+
+ /* Check if Flow Director n-tuple support was enabled or disabled. If
+ * the state changed, we need to reset.
+ */
+ if (features & NETIF_F_NTUPLE) {
+ /* Enable filters and mark for reset */
+ if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
+ need_reset = true;
+ pf->flags |= I40E_FLAG_FD_SB_ENABLED;
+ } else {
+ /* turn off filters, mark for reset and clear SW filter list */
+ if (pf->flags & I40E_FLAG_FD_SB_ENABLED) {
+ need_reset = true;
+ i40e_fdir_filter_exit(pf);
+ }
+ pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
+ /* if ATR was disabled it can be re-enabled. */
+ if (!(pf->flags & I40E_FLAG_FD_ATR_ENABLED))
+ pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
+ }
+ return need_reset;
+}
+
+/**
* i40e_set_features - set the netdev feature flags
* @netdev: ptr to the netdev being adjusted
* @features: the feature set that the stack is suggesting
@@ -6335,12 +6530,19 @@ static int i40e_set_features(struct net_device *netdev,
{
struct i40e_netdev_priv *np = netdev_priv(netdev);
struct i40e_vsi *vsi = np->vsi;
+ struct i40e_pf *pf = vsi->back;
+ bool need_reset;
if (features & NETIF_F_HW_VLAN_CTAG_RX)
i40e_vlan_stripping_enable(vsi);
else
i40e_vlan_stripping_disable(vsi);
+ need_reset = i40e_set_ntuple(pf, features);
+
+ if (need_reset)
+ i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED));
+
return 0;
}
@@ -6464,6 +6666,7 @@ static const struct net_device_ops i40e_netdev_ops = {
.ndo_set_vf_vlan = i40e_ndo_set_vf_port_vlan,
.ndo_set_vf_tx_rate = i40e_ndo_set_vf_bw,
.ndo_get_vf_config = i40e_ndo_get_vf_config,
+ .ndo_set_vf_link_state = i40e_ndo_set_vf_link_state,
#ifdef CONFIG_I40E_VXLAN
.ndo_add_vxlan_port = i40e_add_vxlan_port,
.ndo_del_vxlan_port = i40e_del_vxlan_port,
@@ -6495,10 +6698,9 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
np = netdev_priv(netdev);
np->vsi = vsi;
- netdev->hw_enc_features = NETIF_F_IP_CSUM |
+ netdev->hw_enc_features |= NETIF_F_IP_CSUM |
NETIF_F_GSO_UDP_TUNNEL |
- NETIF_F_TSO |
- NETIF_F_SG;
+ NETIF_F_TSO;
netdev->features = NETIF_F_SG |
NETIF_F_IP_CSUM |
@@ -6512,6 +6714,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
NETIF_F_TSO |
NETIF_F_TSO6 |
NETIF_F_RXCSUM |
+ NETIF_F_NTUPLE |
NETIF_F_RXHASH |
0;
@@ -6771,8 +6974,6 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
if (vsi->netdev) {
/* results in a call to i40e_close() */
unregister_netdev(vsi->netdev);
- free_netdev(vsi->netdev);
- vsi->netdev = NULL;
}
} else {
if (!test_and_set_bit(__I40E_DOWN, &vsi->state))
@@ -6791,6 +6992,10 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
i40e_vsi_delete(vsi);
i40e_vsi_free_q_vectors(vsi);
+ if (vsi->netdev) {
+ free_netdev(vsi->netdev);
+ vsi->netdev = NULL;
+ }
i40e_vsi_clear_rings(vsi);
i40e_vsi_clear(vsi);
@@ -6845,13 +7050,12 @@ static int i40e_vsi_setup_vectors(struct i40e_vsi *vsi)
}
if (vsi->base_vector) {
- dev_info(&pf->pdev->dev,
- "VSI %d has non-zero base vector %d\n",
+ dev_info(&pf->pdev->dev, "VSI %d has non-zero base vector %d\n",
vsi->seid, vsi->base_vector);
return -EEXIST;
}
- ret = i40e_alloc_q_vectors(vsi);
+ ret = i40e_vsi_alloc_q_vectors(vsi);
if (ret) {
dev_info(&pf->pdev->dev,
"failed to allocate %d q_vector for VSI %d, ret=%d\n",
@@ -6865,7 +7069,7 @@ static int i40e_vsi_setup_vectors(struct i40e_vsi *vsi)
vsi->num_q_vectors, vsi->idx);
if (vsi->base_vector < 0) {
dev_info(&pf->pdev->dev,
- "failed to get q tracking for VSI %d, err=%d\n",
+ "failed to get queue tracking for VSI %d, err=%d\n",
vsi->seid, vsi->base_vector);
i40e_vsi_free_q_vectors(vsi);
ret = -ENOENT;
@@ -7822,6 +8026,44 @@ static int i40e_setup_pf_filter_control(struct i40e_pf *pf)
return 0;
}
+#define INFO_STRING_LEN 255
+static void i40e_print_features(struct i40e_pf *pf)
+{
+ struct i40e_hw *hw = &pf->hw;
+ char *buf, *string;
+
+ string = kzalloc(INFO_STRING_LEN, GFP_KERNEL);
+ if (!string) {
+ dev_err(&pf->pdev->dev, "Features string allocation failed\n");
+ return;
+ }
+
+ buf = string;
+
+ buf += sprintf(string, "Features: PF-id[%d] ", hw->pf_id);
+#ifdef CONFIG_PCI_IOV
+ buf += sprintf(buf, "VFs: %d ", pf->num_req_vfs);
+#endif
+ buf += sprintf(buf, "VSIs: %d QP: %d ", pf->hw.func_caps.num_vsis,
+ pf->vsi[pf->lan_vsi]->num_queue_pairs);
+
+ if (pf->flags & I40E_FLAG_RSS_ENABLED)
+ buf += sprintf(buf, "RSS ");
+ buf += sprintf(buf, "FDir ");
+ if (pf->flags & I40E_FLAG_FD_ATR_ENABLED)
+ buf += sprintf(buf, "ATR ");
+ if (pf->flags & I40E_FLAG_FD_SB_ENABLED)
+ buf += sprintf(buf, "NTUPLE ");
+ if (pf->flags & I40E_FLAG_DCB_ENABLED)
+ buf += sprintf(buf, "DCB ");
+ if (pf->flags & I40E_FLAG_PTP)
+ buf += sprintf(buf, "PTP ");
+
+ BUG_ON(buf > (string + INFO_STRING_LEN));
+ dev_info(&pf->pdev->dev, "%s\n", string);
+ kfree(string);
+}
+
/**
* i40e_probe - Device initialization routine
* @pdev: PCI device information struct
@@ -7848,17 +8090,14 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return err;
/* set up for high or low dma */
- if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) {
- /* coherent mask for the same size will always succeed if
- * dma_set_mask does
- */
- dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
- } else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
- dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
- } else {
- dev_err(&pdev->dev, "DMA configuration failed: %d\n", err);
- err = -EIO;
- goto err_dma;
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (err) {
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (err) {
+ dev_err(&pdev->dev,
+ "DMA configuration failed: 0x%x\n", err);
+ goto err_dma;
+ }
}
/* set up pci connections */
@@ -7946,13 +8185,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = i40e_init_adminq(hw);
dev_info(&pdev->dev, "%s\n", i40e_fw_version_str(hw));
- if (((hw->nvm.version & I40E_NVM_VERSION_HI_MASK)
- >> I40E_NVM_VERSION_HI_SHIFT) != I40E_CURRENT_NVM_VERSION_HI) {
- dev_info(&pdev->dev,
- "warning: NVM version not supported, supported version: %02x.%02x\n",
- I40E_CURRENT_NVM_VERSION_HI,
- I40E_CURRENT_NVM_VERSION_LO);
- }
if (err) {
dev_info(&pdev->dev,
"init_adminq failed: %d expecting API %02x.%02x\n",
@@ -7961,6 +8193,8 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_pf_reset;
}
+ i40e_verify_eeprom(pf);
+
i40e_clear_pxe_mode(hw);
err = i40e_get_capabilities(pf);
if (err)
@@ -8062,7 +8296,8 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* prep for VF support */
if ((pf->flags & I40E_FLAG_SRIOV_ENABLED) &&
- (pf->flags & I40E_FLAG_MSIX_ENABLED)) {
+ (pf->flags & I40E_FLAG_MSIX_ENABLED) &&
+ !test_bit(__I40E_BAD_EEPROM, &pf->state)) {
u32 val;
/* disable link interrupts for VFs */
@@ -8070,6 +8305,16 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
val &= ~I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_MASK;
wr32(hw, I40E_PFGEN_PORTMDIO_NUM, val);
i40e_flush(hw);
+
+ if (pci_num_vf(pdev)) {
+ dev_info(&pdev->dev,
+ "Active VFs found, allocating resources.\n");
+ err = i40e_alloc_vfs(pf, pci_num_vf(pdev));
+ if (err)
+ dev_info(&pdev->dev,
+ "Error %d allocating resources for existing VFs\n",
+ err);
+ }
}
pfs_found++;
@@ -8092,7 +8337,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
i40e_set_pci_config_data(hw, link_status);
- dev_info(&pdev->dev, "PCI Express: %s %s\n",
+ dev_info(&pdev->dev, "PCI-Express: %s %s\n",
(hw->bus.speed == i40e_bus_speed_8000 ? "Speed 8.0GT/s" :
hw->bus.speed == i40e_bus_speed_5000 ? "Speed 5.0GT/s" :
hw->bus.speed == i40e_bus_speed_2500 ? "Speed 2.5GT/s" :
@@ -8109,6 +8354,9 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_warn(&pdev->dev, "Please move the device to a different PCI-e link with more lanes and/or higher transfer rate.\n");
}
+ /* print a string summarizing features */
+ i40e_print_features(pf);
+
return 0;
/* Unwind what we've done if something failed in the setup */
@@ -8165,16 +8413,16 @@ static void i40e_remove(struct pci_dev *pdev)
i40e_ptp_stop(pf);
- if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
- i40e_free_vfs(pf);
- pf->flags &= ~I40E_FLAG_SRIOV_ENABLED;
- }
-
/* no more scheduling of any task */
set_bit(__I40E_DOWN, &pf->state);
del_timer_sync(&pf->service_timer);
cancel_work_sync(&pf->service_task);
+ if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
+ i40e_free_vfs(pf);
+ pf->flags &= ~I40E_FLAG_SRIOV_ENABLED;
+ }
+
i40e_fdir_teardown(pf);
/* If there is a switch structure or any orphans, remove them.
diff --git a/drivers/net/ethernet/intel/i40e/i40e_nvm.c b/drivers/net/ethernet/intel/i40e/i40e_nvm.c
index 73f95b081927..262bdf11d221 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_nvm.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_nvm.c
@@ -27,14 +27,14 @@
#include "i40e_prototype.h"
/**
- * i40e_init_nvm_ops - Initialize NVM function pointers.
- * @hw: pointer to the HW structure.
+ * i40e_init_nvm_ops - Initialize NVM function pointers
+ * @hw: pointer to the HW structure
*
- * Setups the function pointers and the NVM info structure. Should be called
- * once per NVM initialization, e.g. inside the i40e_init_shared_code().
- * Please notice that the NVM term is used here (& in all methods covered
- * in this file) as an equivalent of the FLASH part mapped into the SR.
- * We are accessing FLASH always thru the Shadow RAM.
+ * Setup the function pointers and the NVM info structure. Should be called
+ * once per NVM initialization, e.g. inside the i40e_init_shared_code().
+ * Please notice that the NVM term is used here (& in all methods covered
+ * in this file) as an equivalent of the FLASH part mapped into the SR.
+ * We are accessing FLASH always thru the Shadow RAM.
**/
i40e_status i40e_init_nvm(struct i40e_hw *hw)
{
@@ -49,16 +49,16 @@ i40e_status i40e_init_nvm(struct i40e_hw *hw)
gens = rd32(hw, I40E_GLNVM_GENS);
sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >>
I40E_GLNVM_GENS_SR_SIZE_SHIFT);
- /* Switching to words (sr_size contains power of 2KB). */
+ /* Switching to words (sr_size contains power of 2KB) */
nvm->sr_size = (1 << sr_size) * I40E_SR_WORDS_IN_1KB;
- /* Check if we are in the normal or blank NVM programming mode. */
+ /* Check if we are in the normal or blank NVM programming mode */
fla = rd32(hw, I40E_GLNVM_FLA);
- if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode. */
- /* Max NVM timeout. */
+ if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode */
+ /* Max NVM timeout */
nvm->timeout = I40E_MAX_NVM_TIMEOUT;
nvm->blank_nvm_mode = false;
- } else { /* Blank programming mode. */
+ } else { /* Blank programming mode */
nvm->blank_nvm_mode = true;
ret_code = I40E_ERR_NVM_BLANK_MODE;
hw_dbg(hw, "NVM init error: unsupported blank mode.\n");
@@ -68,12 +68,12 @@ i40e_status i40e_init_nvm(struct i40e_hw *hw)
}
/**
- * i40e_acquire_nvm - Generic request for acquiring the NVM ownership.
- * @hw: pointer to the HW structure.
- * @access: NVM access type (read or write).
+ * i40e_acquire_nvm - Generic request for acquiring the NVM ownership
+ * @hw: pointer to the HW structure
+ * @access: NVM access type (read or write)
*
- * This function will request NVM ownership for reading
- * via the proper Admin Command.
+ * This function will request NVM ownership for reading
+ * via the proper Admin Command.
**/
i40e_status i40e_acquire_nvm(struct i40e_hw *hw,
enum i40e_aq_resource_access_type access)
@@ -87,20 +87,20 @@ i40e_status i40e_acquire_nvm(struct i40e_hw *hw,
ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access,
0, &time, NULL);
- /* Reading the Global Device Timer. */
+ /* Reading the Global Device Timer */
gtime = rd32(hw, I40E_GLVFGEN_TIMER);
- /* Store the timeout. */
+ /* Store the timeout */
hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time) + gtime;
if (ret_code) {
- /* Set the polling timeout. */
+ /* Set the polling timeout */
if (time > I40E_MAX_NVM_TIMEOUT)
timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT)
+ gtime;
else
timeout = hw->nvm.hw_semaphore_timeout;
- /* Poll until the current NVM owner timeouts. */
+ /* Poll until the current NVM owner timeouts */
while (gtime < timeout) {
usleep_range(10000, 20000);
ret_code = i40e_aq_request_resource(hw,
@@ -128,10 +128,10 @@ i40e_i40e_acquire_nvm_exit:
}
/**
- * i40e_release_nvm - Generic request for releasing the NVM ownership.
- * @hw: pointer to the HW structure.
+ * i40e_release_nvm - Generic request for releasing the NVM ownership
+ * @hw: pointer to the HW structure
*
- * This function will release NVM resource via the proper Admin Command.
+ * This function will release NVM resource via the proper Admin Command.
**/
void i40e_release_nvm(struct i40e_hw *hw)
{
@@ -140,17 +140,17 @@ void i40e_release_nvm(struct i40e_hw *hw)
}
/**
- * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit.
- * @hw: pointer to the HW structure.
+ * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit
+ * @hw: pointer to the HW structure
*
- * Polls the SRCTL Shadow RAM register done bit.
+ * Polls the SRCTL Shadow RAM register done bit.
**/
static i40e_status i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw)
{
i40e_status ret_code = I40E_ERR_TIMEOUT;
u32 srctl, wait_cnt;
- /* Poll the I40E_GLNVM_SRCTL until the done bit is set. */
+ /* Poll the I40E_GLNVM_SRCTL until the done bit is set */
for (wait_cnt = 0; wait_cnt < I40E_SRRD_SRCTL_ATTEMPTS; wait_cnt++) {
srctl = rd32(hw, I40E_GLNVM_SRCTL);
if (srctl & I40E_GLNVM_SRCTL_DONE_MASK) {
@@ -165,12 +165,12 @@ static i40e_status i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw)
}
/**
- * i40e_read_nvm_word - Reads Shadow RAM
- * @hw: pointer to the HW structure.
- * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
- * @data: word read from the Shadow RAM.
+ * i40e_read_nvm_word - Reads Shadow RAM
+ * @hw: pointer to the HW structure
+ * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
+ * @data: word read from the Shadow RAM
*
- * Reads 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
+ * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
**/
i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
u16 *data)
@@ -184,15 +184,15 @@ i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
goto read_nvm_exit;
}
- /* Poll the done bit first. */
+ /* Poll the done bit first */
ret_code = i40e_poll_sr_srctl_done_bit(hw);
if (!ret_code) {
- /* Write the address and start reading. */
+ /* Write the address and start reading */
sr_reg = (u32)(offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) |
(1 << I40E_GLNVM_SRCTL_START_SHIFT);
wr32(hw, I40E_GLNVM_SRCTL, sr_reg);
- /* Poll I40E_GLNVM_SRCTL until the done bit is set. */
+ /* Poll I40E_GLNVM_SRCTL until the done bit is set */
ret_code = i40e_poll_sr_srctl_done_bit(hw);
if (!ret_code) {
sr_reg = rd32(hw, I40E_GLNVM_SRDATA);
@@ -210,16 +210,15 @@ read_nvm_exit:
}
/**
- * i40e_read_nvm_buffer - Reads Shadow RAM buffer.
- * @hw: pointer to the HW structure.
- * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
- * @words: number of words to read (in) &
- * number of words read before the NVM ownership timeout (out).
- * @data: words read from the Shadow RAM.
+ * i40e_read_nvm_buffer - Reads Shadow RAM buffer
+ * @hw: pointer to the HW structure
+ * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
+ * @words: (in) number of words to read; (out) number of words actually read
+ * @data: words read from the Shadow RAM
*
- * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
- * method. The buffer read is preceded by the NVM ownership take
- * and followed by the release.
+ * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
+ * method. The buffer read is preceded by the NVM ownership take
+ * and followed by the release.
**/
i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
u16 *words, u16 *data)
@@ -227,7 +226,7 @@ i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
i40e_status ret_code = 0;
u16 index, word;
- /* Loop thru the selected region. */
+ /* Loop thru the selected region */
for (word = 0; word < *words; word++) {
index = offset + word;
ret_code = i40e_read_nvm_word(hw, index, &data[word]);
@@ -235,21 +234,21 @@ i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
break;
}
- /* Update the number of words read from the Shadow RAM. */
+ /* Update the number of words read from the Shadow RAM */
*words = word;
return ret_code;
}
/**
- * i40e_calc_nvm_checksum - Calculates and returns the checksum
- * @hw: pointer to hardware structure
- * @checksum: pointer to the checksum
+ * i40e_calc_nvm_checksum - Calculates and returns the checksum
+ * @hw: pointer to hardware structure
+ * @checksum: pointer to the checksum
*
- * This function calculate SW Checksum that covers the whole 64kB shadow RAM
- * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD
- * is customer specific and unknown. Therefore, this function skips all maximum
- * possible size of VPD (1kB).
+ * This function calculates SW Checksum that covers the whole 64kB shadow RAM
+ * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD
+ * is customer specific and unknown. Therefore, this function skips all maximum
+ * possible size of VPD (1kB).
**/
static i40e_status i40e_calc_nvm_checksum(struct i40e_hw *hw,
u16 *checksum)
@@ -311,12 +310,12 @@ i40e_calc_nvm_checksum_exit:
}
/**
- * i40e_validate_nvm_checksum - Validate EEPROM checksum
- * @hw: pointer to hardware structure
- * @checksum: calculated checksum
+ * i40e_validate_nvm_checksum - Validate EEPROM checksum
+ * @hw: pointer to hardware structure
+ * @checksum: calculated checksum
*
- * Performs checksum calculation and validates the NVM SW checksum. If the
- * caller does not need checksum, the value can be NULL.
+ * Performs checksum calculation and validates the NVM SW checksum. If the
+ * caller does not need checksum, the value can be NULL.
**/
i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw,
u16 *checksum)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
index ed91f93ede2b..9cd57e617959 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
@@ -231,6 +231,13 @@ i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw,
u16 *checksum);
void i40e_set_pci_config_data(struct i40e_hw *hw, u16 link_status);
+extern struct i40e_rx_ptype_decoded i40e_ptype_lookup[];
+
+static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype)
+{
+ return i40e_ptype_lookup[ptype];
+}
+
/* prototype for functions used for SW locks */
/* i40e_common for VF drivers*/
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index d4bb482b1a7f..0f5d96ad281d 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -25,6 +25,7 @@
******************************************************************************/
#include "i40e.h"
+#include "i40e_prototype.h"
static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
u32 td_tag)
@@ -39,11 +40,12 @@ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
#define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
/**
* i40e_program_fdir_filter - Program a Flow Director filter
- * @fdir_input: Packet data that will be filter parameters
+ * @fdir_data: Packet data that will be filter parameters
+ * @raw_packet: the pre-allocated packet buffer for FDir
* @pf: The pf pointer
* @add: True for add/update, False for remove
**/
-int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data,
+int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet,
struct i40e_pf *pf, bool add)
{
struct i40e_filter_program_desc *fdir_desc;
@@ -68,8 +70,8 @@ int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data,
tx_ring = vsi->tx_rings[0];
dev = tx_ring->dev;
- dma = dma_map_single(dev, fdir_data->raw_packet,
- I40E_FDIR_MAX_RAW_PACKET_LOOKUP, DMA_TO_DEVICE);
+ dma = dma_map_single(dev, raw_packet,
+ I40E_FDIR_MAX_RAW_PACKET_SIZE, DMA_TO_DEVICE);
if (dma_mapping_error(dev, dma))
goto dma_fail;
@@ -132,14 +134,14 @@ int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data,
tx_ring->next_to_use = (i + 1 < tx_ring->count) ? i + 1 : 0;
/* record length, and DMA address */
- dma_unmap_len_set(tx_buf, len, I40E_FDIR_MAX_RAW_PACKET_LOOKUP);
+ dma_unmap_len_set(tx_buf, len, I40E_FDIR_MAX_RAW_PACKET_SIZE);
dma_unmap_addr_set(tx_buf, dma, dma);
tx_desc->buffer_addr = cpu_to_le64(dma);
td_cmd = I40E_TXD_CMD | I40E_TX_DESC_CMD_DUMMY;
tx_desc->cmd_type_offset_bsz =
- build_ctob(td_cmd, 0, I40E_FDIR_MAX_RAW_PACKET_LOOKUP, 0);
+ build_ctob(td_cmd, 0, I40E_FDIR_MAX_RAW_PACKET_SIZE, 0);
/* set the timestamp */
tx_buf->time_stamp = jiffies;
@@ -161,26 +163,329 @@ dma_fail:
return -1;
}
+#define IP_HEADER_OFFSET 14
+#define I40E_UDPIP_DUMMY_PACKET_LEN 42
+/**
+ * i40e_add_del_fdir_udpv4 - Add/Remove UDPv4 filters
+ * @vsi: pointer to the targeted VSI
+ * @fd_data: the flow director data required for the FDir descriptor
+ * @raw_packet: the pre-allocated packet buffer for FDir
+ * @add: true adds a filter, false removes it
+ *
+ * Returns 0 if the filters were successfully added or removed
+ **/
+static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,
+ struct i40e_fdir_filter *fd_data,
+ u8 *raw_packet, bool add)
+{
+ struct i40e_pf *pf = vsi->back;
+ struct udphdr *udp;
+ struct iphdr *ip;
+ bool err = false;
+ int ret;
+ int i;
+ static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
+ 0x45, 0, 0, 0x1c, 0, 0, 0x40, 0, 0x40, 0x11, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ memcpy(raw_packet, packet, I40E_UDPIP_DUMMY_PACKET_LEN);
+
+ ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
+ udp = (struct udphdr *)(raw_packet + IP_HEADER_OFFSET
+ + sizeof(struct iphdr));
+
+ ip->daddr = fd_data->dst_ip[0];
+ udp->dest = fd_data->dst_port;
+ ip->saddr = fd_data->src_ip[0];
+ udp->source = fd_data->src_port;
+
+ for (i = I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP;
+ i <= I40E_FILTER_PCTYPE_NONF_IPV4_UDP; i++) {
+ fd_data->pctype = i;
+ ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
+
+ if (ret) {
+ dev_info(&pf->pdev->dev,
+ "Filter command send failed for PCTYPE %d (ret = %d)\n",
+ fd_data->pctype, ret);
+ err = true;
+ } else {
+ dev_info(&pf->pdev->dev,
+ "Filter OK for PCTYPE %d (ret = %d)\n",
+ fd_data->pctype, ret);
+ }
+ }
+
+ return err ? -EOPNOTSUPP : 0;
+}
+
+#define I40E_TCPIP_DUMMY_PACKET_LEN 54
+/**
+ * i40e_add_del_fdir_tcpv4 - Add/Remove TCPv4 filters
+ * @vsi: pointer to the targeted VSI
+ * @fd_data: the flow director data required for the FDir descriptor
+ * @raw_packet: the pre-allocated packet buffer for FDir
+ * @add: true adds a filter, false removes it
+ *
+ * Returns 0 if the filters were successfully added or removed
+ **/
+static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
+ struct i40e_fdir_filter *fd_data,
+ u8 *raw_packet, bool add)
+{
+ struct i40e_pf *pf = vsi->back;
+ struct tcphdr *tcp;
+ struct iphdr *ip;
+ bool err = false;
+ int ret;
+ /* Dummy packet */
+ static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
+ 0x45, 0, 0, 0x28, 0, 0, 0x40, 0, 0x40, 0x6, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0x11,
+ 0x0, 0x72, 0, 0, 0, 0};
+
+ memcpy(raw_packet, packet, I40E_TCPIP_DUMMY_PACKET_LEN);
+
+ ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
+ tcp = (struct tcphdr *)(raw_packet + IP_HEADER_OFFSET
+ + sizeof(struct iphdr));
+
+ ip->daddr = fd_data->dst_ip[0];
+ tcp->dest = fd_data->dst_port;
+ ip->saddr = fd_data->src_ip[0];
+ tcp->source = fd_data->src_port;
+
+ if (add) {
+ if (pf->flags & I40E_FLAG_FD_ATR_ENABLED) {
+ dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n");
+ pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
+ }
+ }
+
+ fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN;
+ ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
+
+ if (ret) {
+ dev_info(&pf->pdev->dev,
+ "Filter command send failed for PCTYPE %d (ret = %d)\n",
+ fd_data->pctype, ret);
+ err = true;
+ } else {
+ dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n",
+ fd_data->pctype, ret);
+ }
+
+ fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
+
+ ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
+ if (ret) {
+ dev_info(&pf->pdev->dev,
+ "Filter command send failed for PCTYPE %d (ret = %d)\n",
+ fd_data->pctype, ret);
+ err = true;
+ } else {
+ dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n",
+ fd_data->pctype, ret);
+ }
+
+ return err ? -EOPNOTSUPP : 0;
+}
+
+/**
+ * i40e_add_del_fdir_sctpv4 - Add/Remove SCTPv4 Flow Director filters for
+ * a specific flow spec
+ * @vsi: pointer to the targeted VSI
+ * @fd_data: the flow director data required for the FDir descriptor
+ * @raw_packet: the pre-allocated packet buffer for FDir
+ * @add: true adds a filter, false removes it
+ *
+ * Always returns -EOPNOTSUPP
+ **/
+static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi,
+ struct i40e_fdir_filter *fd_data,
+ u8 *raw_packet, bool add)
+{
+ return -EOPNOTSUPP;
+}
+
+#define I40E_IP_DUMMY_PACKET_LEN 34
+/**
+ * i40e_add_del_fdir_ipv4 - Add/Remove IPv4 Flow Director filters for
+ * a specific flow spec
+ * @vsi: pointer to the targeted VSI
+ * @fd_data: the flow director data required for the FDir descriptor
+ * @raw_packet: the pre-allocated packet buffer for FDir
+ * @add: true adds a filter, false removes it
+ *
+ * Returns 0 if the filters were successfully added or removed
+ **/
+static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,
+ struct i40e_fdir_filter *fd_data,
+ u8 *raw_packet, bool add)
+{
+ struct i40e_pf *pf = vsi->back;
+ struct iphdr *ip;
+ bool err = false;
+ int ret;
+ int i;
+ static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
+ 0x45, 0, 0, 0x14, 0, 0, 0x40, 0, 0x40, 0x10, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0};
+
+ memcpy(raw_packet, packet, I40E_IP_DUMMY_PACKET_LEN);
+ ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
+
+ ip->saddr = fd_data->src_ip[0];
+ ip->daddr = fd_data->dst_ip[0];
+ ip->protocol = 0;
+
+ for (i = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
+ i <= I40E_FILTER_PCTYPE_FRAG_IPV4; i++) {
+ fd_data->pctype = i;
+ ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
+
+ if (ret) {
+ dev_info(&pf->pdev->dev,
+ "Filter command send failed for PCTYPE %d (ret = %d)\n",
+ fd_data->pctype, ret);
+ err = true;
+ } else {
+ dev_info(&pf->pdev->dev,
+ "Filter OK for PCTYPE %d (ret = %d)\n",
+ fd_data->pctype, ret);
+ }
+ }
+
+ return err ? -EOPNOTSUPP : 0;
+}
+
+/**
+ * i40e_add_del_fdir - Build raw packets to add/del fdir filter
+ * @vsi: pointer to the targeted VSI
+ * @cmd: command to get or set RX flow classification rules
+ * @add: true adds a filter, false removes it
+ *
+ **/
+int i40e_add_del_fdir(struct i40e_vsi *vsi,
+ struct i40e_fdir_filter *input, bool add)
+{
+ struct i40e_pf *pf = vsi->back;
+ u8 *raw_packet;
+ int ret;
+
+ /* Populate the Flow Director that we have at the moment
+ * and allocate the raw packet buffer for the calling functions
+ */
+ raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL);
+ if (!raw_packet)
+ return -ENOMEM;
+
+ switch (input->flow_type & ~FLOW_EXT) {
+ case TCP_V4_FLOW:
+ ret = i40e_add_del_fdir_tcpv4(vsi, input, raw_packet,
+ add);
+ break;
+ case UDP_V4_FLOW:
+ ret = i40e_add_del_fdir_udpv4(vsi, input, raw_packet,
+ add);
+ break;
+ case SCTP_V4_FLOW:
+ ret = i40e_add_del_fdir_sctpv4(vsi, input, raw_packet,
+ add);
+ break;
+ case IPV4_FLOW:
+ ret = i40e_add_del_fdir_ipv4(vsi, input, raw_packet,
+ add);
+ break;
+ case IP_USER_FLOW:
+ switch (input->ip4_proto) {
+ case IPPROTO_TCP:
+ ret = i40e_add_del_fdir_tcpv4(vsi, input,
+ raw_packet, add);
+ break;
+ case IPPROTO_UDP:
+ ret = i40e_add_del_fdir_udpv4(vsi, input,
+ raw_packet, add);
+ break;
+ case IPPROTO_SCTP:
+ ret = i40e_add_del_fdir_sctpv4(vsi, input,
+ raw_packet, add);
+ break;
+ default:
+ ret = i40e_add_del_fdir_ipv4(vsi, input,
+ raw_packet, add);
+ break;
+ }
+ break;
+ default:
+ dev_info(&pf->pdev->dev, "Could not specify spec type %d",
+ input->flow_type);
+ ret = -EINVAL;
+ }
+
+ kfree(raw_packet);
+ return ret;
+}
+
/**
* i40e_fd_handle_status - check the Programming Status for FD
* @rx_ring: the Rx ring for this descriptor
- * @qw: the descriptor data
+ * @rx_desc: the Rx descriptor for programming Status, not a packet descriptor.
* @prog_id: the id originally used for programming
*
* This is used to verify if the FD programming or invalidation
* requested by SW to the HW is successful or not and take actions accordingly.
**/
-static void i40e_fd_handle_status(struct i40e_ring *rx_ring, u32 qw, u8 prog_id)
+static void i40e_fd_handle_status(struct i40e_ring *rx_ring,
+ union i40e_rx_desc *rx_desc, u8 prog_id)
{
- struct pci_dev *pdev = rx_ring->vsi->back->pdev;
+ struct i40e_pf *pf = rx_ring->vsi->back;
+ struct pci_dev *pdev = pf->pdev;
+ u32 fcnt_prog, fcnt_avail;
u32 error;
+ u64 qw;
+ qw = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
error = (qw & I40E_RX_PROG_STATUS_DESC_QW1_ERROR_MASK) >>
I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT;
- /* for now just print the Status */
- dev_info(&pdev->dev, "FD programming id %02x, Status %08x\n",
- prog_id, error);
+ if (error == (0x1 << I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT)) {
+ dev_warn(&pdev->dev, "ntuple filter loc = %d, could not be added\n",
+ rx_desc->wb.qword0.hi_dword.fd_id);
+
+ /* filter programming failed most likely due to table full */
+ fcnt_prog = i40e_get_current_fd_count(pf);
+ fcnt_avail = pf->hw.fdir_shared_filter_count +
+ pf->fdir_pf_filter_count;
+
+ /* If ATR is running fcnt_prog can quickly change,
+ * if we are very close to full, it makes sense to disable
+ * FD ATR/SB and then re-enable it when there is room.
+ */
+ if (fcnt_prog >= (fcnt_avail - I40E_FDIR_BUFFER_FULL_MARGIN)) {
+ /* Turn off ATR first */
+ if (pf->flags | I40E_FLAG_FD_ATR_ENABLED) {
+ pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
+ dev_warn(&pdev->dev, "FD filter space full, ATR for further flows will be turned off\n");
+ pf->auto_disable_flags |=
+ I40E_FLAG_FD_ATR_ENABLED;
+ pf->flags |= I40E_FLAG_FDIR_REQUIRES_REINIT;
+ } else if (pf->flags | I40E_FLAG_FD_SB_ENABLED) {
+ pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
+ dev_warn(&pdev->dev, "FD filter space full, new ntuple rules will not be added\n");
+ pf->auto_disable_flags |=
+ I40E_FLAG_FD_SB_ENABLED;
+ pf->flags |= I40E_FLAG_FDIR_REQUIRES_REINIT;
+ }
+ } else {
+ dev_info(&pdev->dev, "FD filter programming error");
+ }
+ } else if (error ==
+ (0x1 << I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT)) {
+ if (I40E_DEBUG_FD & pf->hw.debug_mask)
+ dev_info(&pdev->dev, "ntuple filter loc = %d, could not be removed\n",
+ rx_desc->wb.qword0.hi_dword.fd_id);
+ }
}
/**
@@ -315,6 +620,20 @@ static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
}
/**
+ * i40e_get_head - Retrieve head from head writeback
+ * @tx_ring: tx ring to fetch head of
+ *
+ * Returns value of Tx ring head based on value stored
+ * in head write-back location
+ **/
+static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
+{
+ void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
+
+ return le32_to_cpu(*(volatile __le32 *)head);
+}
+
+/**
* i40e_clean_tx_irq - Reclaim resources after transmit completes
* @tx_ring: tx ring to clean
* @budget: how many cleans we're allowed
@@ -325,6 +644,7 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
{
u16 i = tx_ring->next_to_clean;
struct i40e_tx_buffer *tx_buf;
+ struct i40e_tx_desc *tx_head;
struct i40e_tx_desc *tx_desc;
unsigned int total_packets = 0;
unsigned int total_bytes = 0;
@@ -333,6 +653,8 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
tx_desc = I40E_TX_DESC(tx_ring, i);
i -= tx_ring->count;
+ tx_head = I40E_TX_DESC(tx_ring, i40e_get_head(tx_ring));
+
do {
struct i40e_tx_desc *eop_desc = tx_buf->next_to_watch;
@@ -343,9 +665,8 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
/* prevent any other reads prior to eop_desc */
read_barrier_depends();
- /* if the descriptor isn't done, no work yet to do */
- if (!(eop_desc->cmd_type_offset_bsz &
- cpu_to_le64(I40E_TX_DESC_DTYPE_DESC_DONE)))
+ /* we have caught up to head, no work left to do */
+ if (tx_head == tx_desc)
break;
/* clear next_to_watch to prevent false hangs */
@@ -577,7 +898,7 @@ static void i40e_clean_programming_status(struct i40e_ring *rx_ring,
I40E_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT;
if (id == I40E_RX_PROG_STATUS_DESC_FD_FILTER_STATUS)
- i40e_fd_handle_status(rx_ring, qw, id);
+ i40e_fd_handle_status(rx_ring, rx_desc, id);
}
/**
@@ -601,6 +922,10 @@ int i40e_setup_tx_descriptors(struct i40e_ring *tx_ring)
/* round up to nearest 4K */
tx_ring->size = tx_ring->count * sizeof(struct i40e_tx_desc);
+ /* add u32 for head writeback, align after this takes care of
+ * guaranteeing this is at least one cache line in size
+ */
+ tx_ring->size += sizeof(u32);
tx_ring->size = ALIGN(tx_ring->size, 4096);
tx_ring->desc = dma_alloc_coherent(dev, tx_ring->size,
&tx_ring->dma, GFP_KERNEL);
@@ -892,7 +1217,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT)))
return;
- /* likely incorrect csum if alternate IP extention headers found */
+ /* likely incorrect csum if alternate IP extension headers found */
if (rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT))
return;
@@ -956,6 +1281,29 @@ static inline u32 i40e_rx_hash(struct i40e_ring *ring,
}
/**
+ * i40e_ptype_to_hash - get a hash type
+ * @ptype: the ptype value from the descriptor
+ *
+ * Returns a hash type to be used by skb_set_hash
+ **/
+static inline enum pkt_hash_types i40e_ptype_to_hash(u8 ptype)
+{
+ struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(ptype);
+
+ if (!decoded.known)
+ return PKT_HASH_TYPE_NONE;
+
+ if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
+ decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY4)
+ return PKT_HASH_TYPE_L4;
+ else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
+ decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY3)
+ return PKT_HASH_TYPE_L3;
+ else
+ return PKT_HASH_TYPE_L2;
+}
+
+/**
* i40e_clean_rx_irq - Reclaim resources after receive completes
* @rx_ring: rx ring to clean
* @budget: how many cleans we're allowed
@@ -972,8 +1320,11 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
u16 i = rx_ring->next_to_clean;
union i40e_rx_desc *rx_desc;
u32 rx_error, rx_status;
+ u8 rx_ptype;
u64 qword;
- u16 rx_ptype;
+
+ if (budget <= 0)
+ return 0;
rx_desc = I40E_RX_DESC(rx_ring, i);
qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
@@ -1087,7 +1438,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
goto next_desc;
}
- skb->rxhash = i40e_rx_hash(rx_ring, rx_desc);
+ skb_set_hash(skb, i40e_rx_hash(rx_ring, rx_desc),
+ i40e_ptype_to_hash(rx_ptype));
if (unlikely(rx_status & I40E_RXD_QW1_STATUS_TSYNVALID_MASK)) {
i40e_ptp_rx_hwtstamp(vsi->back, skb, (rx_status &
I40E_RXD_QW1_STATUS_TSYNINDX_MASK) >>
@@ -1246,8 +1598,6 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
if (!tx_ring->atr_sample_rate)
return;
- tx_ring->atr_count++;
-
/* snag network header to get L4 type and address */
hdr.network = skb_network_header(skb);
@@ -1269,8 +1619,17 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
th = (struct tcphdr *)(hdr.network + hlen);
- /* sample on all syn/fin packets or once every atr sample rate */
- if (!th->fin && !th->syn && (tx_ring->atr_count < tx_ring->atr_sample_rate))
+ /* Due to lack of space, no more new filters can be programmed */
+ if (th->syn && (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED))
+ return;
+
+ tx_ring->atr_count++;
+
+ /* sample on all syn/fin/rst packets or once every atr sample rate */
+ if (!th->fin &&
+ !th->syn &&
+ !th->rst &&
+ (tx_ring->atr_count < tx_ring->atr_sample_rate))
return;
tx_ring->atr_count = 0;
@@ -1294,7 +1653,7 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
dtype_cmd = I40E_TX_DESC_DTYPE_FILTER_PROG;
- dtype_cmd |= th->fin ?
+ dtype_cmd |= (th->fin || th->rst) ?
(I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE <<
I40E_TXD_FLTR_QW1_PCMD_SHIFT) :
(I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE <<
@@ -1596,7 +1955,8 @@ static void i40e_create_tx_ctx(struct i40e_ring *tx_ring,
struct i40e_tx_context_desc *context_desc;
int i = tx_ring->next_to_use;
- if (!cd_type_cmd_tso_mss && !cd_tunneling && !cd_l2tag2)
+ if ((cd_type_cmd_tso_mss == I40E_TX_DESC_DTYPE_CONTEXT) &&
+ !cd_tunneling && !cd_l2tag2)
return;
/* grab the next descriptor */
@@ -1707,9 +2067,23 @@ static void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
tx_bi = &tx_ring->tx_bi[i];
}
- tx_desc->cmd_type_offset_bsz =
- build_ctob(td_cmd, td_offset, size, td_tag) |
- cpu_to_le64((u64)I40E_TXD_CMD << I40E_TXD_QW1_CMD_SHIFT);
+ /* Place RS bit on last descriptor of any packet that spans across the
+ * 4th descriptor (WB_STRIDE aka 0x3) in a 64B cacheline.
+ */
+#define WB_STRIDE 0x3
+ if (((i & WB_STRIDE) != WB_STRIDE) &&
+ (first <= &tx_ring->tx_bi[i]) &&
+ (first >= &tx_ring->tx_bi[i & ~WB_STRIDE])) {
+ tx_desc->cmd_type_offset_bsz =
+ build_ctob(td_cmd, td_offset, size, td_tag) |
+ cpu_to_le64((u64)I40E_TX_DESC_CMD_EOP <<
+ I40E_TXD_QW1_CMD_SHIFT);
+ } else {
+ tx_desc->cmd_type_offset_bsz =
+ build_ctob(td_cmd, td_offset, size, td_tag) |
+ cpu_to_le64((u64)I40E_TXD_CMD <<
+ I40E_TXD_QW1_CMD_SHIFT);
+ }
netdev_tx_sent_queue(netdev_get_tx_queue(tx_ring->netdev,
tx_ring->queue_index),
@@ -1812,7 +2186,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb,
/* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,
* + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,
- * + 2 desc gap to keep tail from touching head,
+ * + 4 desc gap to avoid the cache line where head is,
* + 1 desc for context descriptor,
* otherwise try next time
*/
@@ -1823,7 +2197,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb,
count += skb_shinfo(skb)->nr_frags;
#endif
count += TXD_USE_COUNT(skb_headlen(skb));
- if (i40e_maybe_stop_tx(tx_ring, count + 3)) {
+ if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) {
tx_ring->tx_stats.tx_busy++;
return 0;
}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
index 181a825d3160..71a968fe557f 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_type.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
@@ -91,6 +91,7 @@ enum i40e_debug_mask {
I40E_DEBUG_FLOW = 0x00000200,
I40E_DEBUG_DCB = 0x00000400,
I40E_DEBUG_DIAG = 0x00000800,
+ I40E_DEBUG_FD = 0x00001000,
I40E_DEBUG_AQ_MESSAGE = 0x01000000,
I40E_DEBUG_AQ_DESCRIPTOR = 0x02000000,
@@ -458,6 +459,10 @@ union i40e_32byte_rx_desc {
union {
__le32 rss; /* RSS Hash */
__le32 fcoe_param; /* FCoE DDP Context id */
+ /* Flow director filter id in case of
+ * Programming status desc WB
+ */
+ __le32 fd_id;
} hi_dword;
} qword0;
struct {
@@ -698,7 +703,7 @@ enum i40e_rx_prog_status_desc_prog_id_masks {
enum i40e_rx_prog_status_desc_error_bits {
/* Note: These are predefined bit offsets */
I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT = 0,
- I40E_RX_PROG_STATUS_DESC_NO_FD_QUOTA_SHIFT = 1,
+ I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT = 1,
I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT = 2,
I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT = 3
};
@@ -1010,6 +1015,11 @@ struct i40e_hw_port_stats {
u64 tx_size_big; /* ptc9522 */
u64 mac_short_packet_dropped; /* mspdc */
u64 checksum_error; /* xec */
+ /* EEE LPI */
+ bool tx_lpi_status;
+ bool rx_lpi_status;
+ u64 tx_lpi_count; /* etlpic */
+ u64 rx_lpi_count; /* erlpic */
};
/* Checksum and Shadow RAM pointers */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index b9d1c1c8ca5a..02c11a7f7d29 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -69,7 +69,7 @@ static inline bool i40e_vc_isvalid_vector_id(struct i40e_vf *vf, u8 vector_id)
{
struct i40e_pf *pf = vf->pf;
- return vector_id <= pf->hw.func_caps.num_msix_vectors_vf;
+ return vector_id < pf->hw.func_caps.num_msix_vectors_vf;
}
/***********************vf resource mgmt routines*****************/
@@ -126,8 +126,8 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_idx,
reg_idx = I40E_VPINT_LNKLST0(vf->vf_id);
else
reg_idx = I40E_VPINT_LNKLSTN(
- (pf->hw.func_caps.num_msix_vectors_vf
- * vf->vf_id) + (vector_id - 1));
+ ((pf->hw.func_caps.num_msix_vectors_vf - 1) * vf->vf_id) +
+ (vector_id - 1));
if (vecmap->rxq_map == 0 && vecmap->txq_map == 0) {
/* Special case - No queues mapped on this vector */
@@ -230,6 +230,9 @@ static int i40e_config_vsi_tx_queue(struct i40e_vf *vf, u16 vsi_idx,
tx_ctx.qlen = info->ring_len;
tx_ctx.rdylist = le16_to_cpu(pf->vsi[vsi_idx]->info.qs_handle[0]);
tx_ctx.rdylist_act = 0;
+ tx_ctx.head_wb_ena = 1;
+ tx_ctx.head_wb_addr = info->dma_ring_addr +
+ (info->ring_len * sizeof(struct i40e_tx_desc));
/* clear the context in the HMC */
ret = i40e_clear_lan_tx_queue_context(hw, pf_queue_id);
@@ -408,18 +411,10 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)
"Could not allocate VF broadcast filter\n");
}
- if (!f) {
- dev_err(&pf->pdev->dev, "Unable to add ucast filter\n");
- ret = -ENOMEM;
- goto error_alloc_vsi_res;
- }
-
/* program mac filter */
ret = i40e_sync_vsi_filters(vsi);
- if (ret) {
+ if (ret)
dev_err(&pf->pdev->dev, "Unable to program ucast filters\n");
- goto error_alloc_vsi_res;
- }
error_alloc_vsi_res:
return ret;
@@ -514,7 +509,8 @@ static void i40e_free_vf_res(struct i40e_vf *vf)
vf->lan_vsi_index = 0;
vf->lan_vsi_id = 0;
}
- msix_vf = pf->hw.func_caps.num_msix_vectors_vf + 1;
+ msix_vf = pf->hw.func_caps.num_msix_vectors_vf;
+
/* disable interrupts so the VF starts in a known state */
for (i = 0; i < msix_vf; i++) {
/* format is same for both registers */
@@ -679,9 +675,9 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr)
complete_reset:
/* reallocate vf resources to reset the VSI state */
i40e_free_vf_res(vf);
- mdelay(10);
i40e_alloc_vf_res(vf);
i40e_enable_vf_mappings(vf);
+ set_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states);
/* tell the VF the reset is done */
wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_VFACTIVE);
@@ -847,7 +843,7 @@ void i40e_free_vfs(struct i40e_pf *pf)
*
* allocate vf resources
**/
-static int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs)
+int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs)
{
struct i40e_vf *vfs;
int i, ret = 0;
@@ -855,16 +851,18 @@ static int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs)
/* Disable interrupt 0 so we don't try to handle the VFLR. */
i40e_irq_dynamic_disable_icr0(pf);
- ret = pci_enable_sriov(pf->pdev, num_alloc_vfs);
- if (ret) {
- dev_err(&pf->pdev->dev,
- "pci_enable_sriov failed with error %d!\n", ret);
- pf->num_alloc_vfs = 0;
- goto err_iov;
+ /* Check to see if we're just allocating resources for extant VFs */
+ if (pci_num_vf(pf->pdev) != num_alloc_vfs) {
+ ret = pci_enable_sriov(pf->pdev, num_alloc_vfs);
+ if (ret) {
+ dev_err(&pf->pdev->dev,
+ "Failed to enable SR-IOV, error %d.\n", ret);
+ pf->num_alloc_vfs = 0;
+ goto err_iov;
+ }
}
-
/* allocate memory */
- vfs = kzalloc(num_alloc_vfs * sizeof(struct i40e_vf), GFP_KERNEL);
+ vfs = kcalloc(num_alloc_vfs, sizeof(struct i40e_vf), GFP_KERNEL);
if (!vfs) {
ret = -ENOMEM;
goto err_alloc;
@@ -1776,7 +1774,7 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, u16 vf_id, u32 v_opcode,
u32 v_retval, u8 *msg, u16 msglen)
{
struct i40e_hw *hw = &pf->hw;
- int local_vf_id = vf_id - hw->func_caps.vf_base_id;
+ unsigned int local_vf_id = vf_id - hw->func_caps.vf_base_id;
struct i40e_vf *vf;
int ret;
@@ -1873,7 +1871,8 @@ int i40e_vc_process_vflr_event(struct i40e_pf *pf)
/* clear the bit in GLGEN_VFLRSTAT */
wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), (1 << bit_idx));
- i40e_reset_vf(vf, true);
+ if (!test_bit(__I40E_DOWN, &pf->state))
+ i40e_reset_vf(vf, true);
}
}
@@ -1924,15 +1923,28 @@ static void i40e_vc_vf_broadcast(struct i40e_pf *pf,
void i40e_vc_notify_link_state(struct i40e_pf *pf)
{
struct i40e_virtchnl_pf_event pfe;
+ struct i40e_hw *hw = &pf->hw;
+ struct i40e_vf *vf = pf->vf;
+ struct i40e_link_status *ls = &pf->hw.phy.link_info;
+ int i;
pfe.event = I40E_VIRTCHNL_EVENT_LINK_CHANGE;
pfe.severity = I40E_PF_EVENT_SEVERITY_INFO;
- pfe.event_data.link_event.link_status =
- pf->hw.phy.link_info.link_info & I40E_AQ_LINK_UP;
- pfe.event_data.link_event.link_speed = pf->hw.phy.link_info.link_speed;
-
- i40e_vc_vf_broadcast(pf, I40E_VIRTCHNL_OP_EVENT, I40E_SUCCESS,
- (u8 *)&pfe, sizeof(struct i40e_virtchnl_pf_event));
+ for (i = 0; i < pf->num_alloc_vfs; i++) {
+ if (vf->link_forced) {
+ pfe.event_data.link_event.link_status = vf->link_up;
+ pfe.event_data.link_event.link_speed =
+ (vf->link_up ? I40E_LINK_SPEED_40GB : 0);
+ } else {
+ pfe.event_data.link_event.link_status =
+ ls->link_info & I40E_AQ_LINK_UP;
+ pfe.event_data.link_event.link_speed = ls->link_speed;
+ }
+ i40e_aq_send_msg_to_vf(hw, vf->vf_id, I40E_VIRTCHNL_OP_EVENT,
+ 0, (u8 *)&pfe, sizeof(pfe),
+ NULL);
+ vf++;
+ }
}
/**
@@ -2197,3 +2209,64 @@ int i40e_ndo_get_vf_config(struct net_device *netdev,
error_param:
return ret;
}
+
+/**
+ * i40e_ndo_set_vf_link_state
+ * @netdev: network interface device structure
+ * @vf_id: vf identifier
+ * @link: required link state
+ *
+ * Set the link state of a specified VF, regardless of physical link state
+ **/
+int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link)
+{
+ struct i40e_netdev_priv *np = netdev_priv(netdev);
+ struct i40e_pf *pf = np->vsi->back;
+ struct i40e_virtchnl_pf_event pfe;
+ struct i40e_hw *hw = &pf->hw;
+ struct i40e_vf *vf;
+ int ret = 0;
+
+ /* validate the request */
+ if (vf_id >= pf->num_alloc_vfs) {
+ dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id);
+ ret = -EINVAL;
+ goto error_out;
+ }
+
+ vf = &pf->vf[vf_id];
+
+ pfe.event = I40E_VIRTCHNL_EVENT_LINK_CHANGE;
+ pfe.severity = I40E_PF_EVENT_SEVERITY_INFO;
+
+ switch (link) {
+ case IFLA_VF_LINK_STATE_AUTO:
+ vf->link_forced = false;
+ pfe.event_data.link_event.link_status =
+ pf->hw.phy.link_info.link_info & I40E_AQ_LINK_UP;
+ pfe.event_data.link_event.link_speed =
+ pf->hw.phy.link_info.link_speed;
+ break;
+ case IFLA_VF_LINK_STATE_ENABLE:
+ vf->link_forced = true;
+ vf->link_up = true;
+ pfe.event_data.link_event.link_status = true;
+ pfe.event_data.link_event.link_speed = I40E_LINK_SPEED_40GB;
+ break;
+ case IFLA_VF_LINK_STATE_DISABLE:
+ vf->link_forced = true;
+ vf->link_up = false;
+ pfe.event_data.link_event.link_status = false;
+ pfe.event_data.link_event.link_speed = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ goto error_out;
+ }
+ /* Notify the VF of its new link state */
+ i40e_aq_send_msg_to_vf(hw, vf->vf_id, I40E_VIRTCHNL_OP_EVENT,
+ 0, (u8 *)&pfe, sizeof(pfe), NULL);
+
+error_out:
+ return ret;
+}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
index cc1feee36e12..389c47f396d5 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
@@ -98,10 +98,13 @@ struct i40e_vf {
unsigned long vf_caps; /* vf's adv. capabilities */
unsigned long vf_states; /* vf's runtime states */
+ bool link_forced;
+ bool link_up; /* only valid if vf link is forced */
};
void i40e_free_vfs(struct i40e_pf *pf);
int i40e_pci_sriov_configure(struct pci_dev *dev, int num_vfs);
+int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs);
int i40e_vc_process_vf_msg(struct i40e_pf *pf, u16 vf_id, u32 v_opcode,
u32 v_retval, u8 *msg, u16 msglen);
int i40e_vc_process_vflr_event(struct i40e_pf *pf);
@@ -115,6 +118,8 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev,
int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int tx_rate);
int i40e_ndo_get_vf_config(struct net_device *netdev,
int vf_id, struct ifla_vf_info *ivi);
+int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link);
+
void i40e_vc_notify_link_state(struct i40e_pf *pf);
void i40e_vc_notify_reset(struct i40e_pf *pf);
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
index f7cea1bca38d..97662b6bd98a 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
@@ -1229,7 +1229,7 @@ struct i40e_aqc_add_remove_cloud_filters_element_data {
#define I40E_AQC_ADD_CLOUD_TNL_TYPE_NGE 2
#define I40E_AQC_ADD_CLOUD_TNL_TYPE_IP 3
- __le32 tenant_id ;
+ __le32 tenant_id;
u8 reserved[4];
__le16 queue_number;
#define I40E_AQC_ADD_CLOUD_QUEUE_SHIFT 0
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c
index 7b13953b28c4..ae084378faab 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_common.c
+++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c
@@ -160,6 +160,372 @@ i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw,
}
+/* The i40evf_ptype_lookup table is used to convert from the 8-bit ptype in the
+ * hardware to a bit-field that can be used by SW to more easily determine the
+ * packet type.
+ *
+ * Macros are used to shorten the table lines and make this table human
+ * readable.
+ *
+ * We store the PTYPE in the top byte of the bit field - this is just so that
+ * we can check that the table doesn't have a row missing, as the index into
+ * the table should be the PTYPE.
+ *
+ * Typical work flow:
+ *
+ * IF NOT i40evf_ptype_lookup[ptype].known
+ * THEN
+ * Packet is unknown
+ * ELSE IF i40evf_ptype_lookup[ptype].outer_ip == I40E_RX_PTYPE_OUTER_IP
+ * Use the rest of the fields to look at the tunnels, inner protocols, etc
+ * ELSE
+ * Use the enum i40e_rx_l2_ptype to decode the packet type
+ * ENDIF
+ */
+
+/* macro to make the table lines short */
+#define I40E_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\
+ { PTYPE, \
+ 1, \
+ I40E_RX_PTYPE_OUTER_##OUTER_IP, \
+ I40E_RX_PTYPE_OUTER_##OUTER_IP_VER, \
+ I40E_RX_PTYPE_##OUTER_FRAG, \
+ I40E_RX_PTYPE_TUNNEL_##T, \
+ I40E_RX_PTYPE_TUNNEL_END_##TE, \
+ I40E_RX_PTYPE_##TEF, \
+ I40E_RX_PTYPE_INNER_PROT_##I, \
+ I40E_RX_PTYPE_PAYLOAD_LAYER_##PL }
+
+#define I40E_PTT_UNUSED_ENTRY(PTYPE) \
+ { PTYPE, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+
+/* shorter macros makes the table fit but are terse */
+#define I40E_RX_PTYPE_NOF I40E_RX_PTYPE_NOT_FRAG
+#define I40E_RX_PTYPE_FRG I40E_RX_PTYPE_FRAG
+#define I40E_RX_PTYPE_INNER_PROT_TS I40E_RX_PTYPE_INNER_PROT_TIMESYNC
+
+/* Lookup table mapping the HW PTYPE to the bit field for decoding */
+struct i40e_rx_ptype_decoded i40evf_ptype_lookup[] = {
+ /* L2 Packet types */
+ I40E_PTT_UNUSED_ENTRY(0),
+ I40E_PTT(1, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+ I40E_PTT(2, L2, NONE, NOF, NONE, NONE, NOF, TS, PAY2),
+ I40E_PTT(3, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+ I40E_PTT_UNUSED_ENTRY(4),
+ I40E_PTT_UNUSED_ENTRY(5),
+ I40E_PTT(6, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+ I40E_PTT(7, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+ I40E_PTT_UNUSED_ENTRY(8),
+ I40E_PTT_UNUSED_ENTRY(9),
+ I40E_PTT(10, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+ I40E_PTT(11, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE),
+ I40E_PTT(12, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(13, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(14, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(15, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(16, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(17, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(18, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(19, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(20, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(21, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+
+ /* Non Tunneled IPv4 */
+ I40E_PTT(22, IP, IPV4, FRG, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(23, IP, IPV4, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(24, IP, IPV4, NOF, NONE, NONE, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(25),
+ I40E_PTT(26, IP, IPV4, NOF, NONE, NONE, NOF, TCP, PAY4),
+ I40E_PTT(27, IP, IPV4, NOF, NONE, NONE, NOF, SCTP, PAY4),
+ I40E_PTT(28, IP, IPV4, NOF, NONE, NONE, NOF, ICMP, PAY4),
+
+ /* IPv4 --> IPv4 */
+ I40E_PTT(29, IP, IPV4, NOF, IP_IP, IPV4, FRG, NONE, PAY3),
+ I40E_PTT(30, IP, IPV4, NOF, IP_IP, IPV4, NOF, NONE, PAY3),
+ I40E_PTT(31, IP, IPV4, NOF, IP_IP, IPV4, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(32),
+ I40E_PTT(33, IP, IPV4, NOF, IP_IP, IPV4, NOF, TCP, PAY4),
+ I40E_PTT(34, IP, IPV4, NOF, IP_IP, IPV4, NOF, SCTP, PAY4),
+ I40E_PTT(35, IP, IPV4, NOF, IP_IP, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv4 --> IPv6 */
+ I40E_PTT(36, IP, IPV4, NOF, IP_IP, IPV6, FRG, NONE, PAY3),
+ I40E_PTT(37, IP, IPV4, NOF, IP_IP, IPV6, NOF, NONE, PAY3),
+ I40E_PTT(38, IP, IPV4, NOF, IP_IP, IPV6, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(39),
+ I40E_PTT(40, IP, IPV4, NOF, IP_IP, IPV6, NOF, TCP, PAY4),
+ I40E_PTT(41, IP, IPV4, NOF, IP_IP, IPV6, NOF, SCTP, PAY4),
+ I40E_PTT(42, IP, IPV4, NOF, IP_IP, IPV6, NOF, ICMP, PAY4),
+
+ /* IPv4 --> GRE/NAT */
+ I40E_PTT(43, IP, IPV4, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3),
+
+ /* IPv4 --> GRE/NAT --> IPv4 */
+ I40E_PTT(44, IP, IPV4, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3),
+ I40E_PTT(45, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3),
+ I40E_PTT(46, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(47),
+ I40E_PTT(48, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4),
+ I40E_PTT(49, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4),
+ I40E_PTT(50, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv4 --> GRE/NAT --> IPv6 */
+ I40E_PTT(51, IP, IPV4, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3),
+ I40E_PTT(52, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3),
+ I40E_PTT(53, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(54),
+ I40E_PTT(55, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4),
+ I40E_PTT(56, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4),
+ I40E_PTT(57, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4),
+
+ /* IPv4 --> GRE/NAT --> MAC */
+ I40E_PTT(58, IP, IPV4, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3),
+
+ /* IPv4 --> GRE/NAT --> MAC --> IPv4 */
+ I40E_PTT(59, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3),
+ I40E_PTT(60, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3),
+ I40E_PTT(61, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(62),
+ I40E_PTT(63, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4),
+ I40E_PTT(64, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4),
+ I40E_PTT(65, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv4 --> GRE/NAT -> MAC --> IPv6 */
+ I40E_PTT(66, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3),
+ I40E_PTT(67, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3),
+ I40E_PTT(68, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(69),
+ I40E_PTT(70, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4),
+ I40E_PTT(71, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4),
+ I40E_PTT(72, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4),
+
+ /* IPv4 --> GRE/NAT --> MAC/VLAN */
+ I40E_PTT(73, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3),
+
+ /* IPv4 ---> GRE/NAT -> MAC/VLAN --> IPv4 */
+ I40E_PTT(74, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3),
+ I40E_PTT(75, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3),
+ I40E_PTT(76, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(77),
+ I40E_PTT(78, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4),
+ I40E_PTT(79, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4),
+ I40E_PTT(80, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv4 -> GRE/NAT -> MAC/VLAN --> IPv6 */
+ I40E_PTT(81, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3),
+ I40E_PTT(82, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3),
+ I40E_PTT(83, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(84),
+ I40E_PTT(85, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4),
+ I40E_PTT(86, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4),
+ I40E_PTT(87, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4),
+
+ /* Non Tunneled IPv6 */
+ I40E_PTT(88, IP, IPV6, FRG, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(89, IP, IPV6, NOF, NONE, NONE, NOF, NONE, PAY3),
+ I40E_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP, PAY3),
+ I40E_PTT_UNUSED_ENTRY(91),
+ I40E_PTT(92, IP, IPV6, NOF, NONE, NONE, NOF, TCP, PAY4),
+ I40E_PTT(93, IP, IPV6, NOF, NONE, NONE, NOF, SCTP, PAY4),
+ I40E_PTT(94, IP, IPV6, NOF, NONE, NONE, NOF, ICMP, PAY4),
+
+ /* IPv6 --> IPv4 */
+ I40E_PTT(95, IP, IPV6, NOF, IP_IP, IPV4, FRG, NONE, PAY3),
+ I40E_PTT(96, IP, IPV6, NOF, IP_IP, IPV4, NOF, NONE, PAY3),
+ I40E_PTT(97, IP, IPV6, NOF, IP_IP, IPV4, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(98),
+ I40E_PTT(99, IP, IPV6, NOF, IP_IP, IPV4, NOF, TCP, PAY4),
+ I40E_PTT(100, IP, IPV6, NOF, IP_IP, IPV4, NOF, SCTP, PAY4),
+ I40E_PTT(101, IP, IPV6, NOF, IP_IP, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv6 --> IPv6 */
+ I40E_PTT(102, IP, IPV6, NOF, IP_IP, IPV6, FRG, NONE, PAY3),
+ I40E_PTT(103, IP, IPV6, NOF, IP_IP, IPV6, NOF, NONE, PAY3),
+ I40E_PTT(104, IP, IPV6, NOF, IP_IP, IPV6, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(105),
+ I40E_PTT(106, IP, IPV6, NOF, IP_IP, IPV6, NOF, TCP, PAY4),
+ I40E_PTT(107, IP, IPV6, NOF, IP_IP, IPV6, NOF, SCTP, PAY4),
+ I40E_PTT(108, IP, IPV6, NOF, IP_IP, IPV6, NOF, ICMP, PAY4),
+
+ /* IPv6 --> GRE/NAT */
+ I40E_PTT(109, IP, IPV6, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3),
+
+ /* IPv6 --> GRE/NAT -> IPv4 */
+ I40E_PTT(110, IP, IPV6, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3),
+ I40E_PTT(111, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3),
+ I40E_PTT(112, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(113),
+ I40E_PTT(114, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4),
+ I40E_PTT(115, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4),
+ I40E_PTT(116, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv6 --> GRE/NAT -> IPv6 */
+ I40E_PTT(117, IP, IPV6, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3),
+ I40E_PTT(118, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3),
+ I40E_PTT(119, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(120),
+ I40E_PTT(121, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4),
+ I40E_PTT(122, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4),
+ I40E_PTT(123, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4),
+
+ /* IPv6 --> GRE/NAT -> MAC */
+ I40E_PTT(124, IP, IPV6, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3),
+
+ /* IPv6 --> GRE/NAT -> MAC -> IPv4 */
+ I40E_PTT(125, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3),
+ I40E_PTT(126, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3),
+ I40E_PTT(127, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(128),
+ I40E_PTT(129, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4),
+ I40E_PTT(130, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4),
+ I40E_PTT(131, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv6 --> GRE/NAT -> MAC -> IPv6 */
+ I40E_PTT(132, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3),
+ I40E_PTT(133, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3),
+ I40E_PTT(134, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(135),
+ I40E_PTT(136, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4),
+ I40E_PTT(137, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4),
+ I40E_PTT(138, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4),
+
+ /* IPv6 --> GRE/NAT -> MAC/VLAN */
+ I40E_PTT(139, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3),
+
+ /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv4 */
+ I40E_PTT(140, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3),
+ I40E_PTT(141, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3),
+ I40E_PTT(142, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(143),
+ I40E_PTT(144, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4),
+ I40E_PTT(145, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4),
+ I40E_PTT(146, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv6 */
+ I40E_PTT(147, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3),
+ I40E_PTT(148, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3),
+ I40E_PTT(149, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4),
+ I40E_PTT_UNUSED_ENTRY(150),
+ I40E_PTT(151, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4),
+ I40E_PTT(152, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4),
+ I40E_PTT(153, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4),
+
+ /* unused entries */
+ I40E_PTT_UNUSED_ENTRY(154),
+ I40E_PTT_UNUSED_ENTRY(155),
+ I40E_PTT_UNUSED_ENTRY(156),
+ I40E_PTT_UNUSED_ENTRY(157),
+ I40E_PTT_UNUSED_ENTRY(158),
+ I40E_PTT_UNUSED_ENTRY(159),
+
+ I40E_PTT_UNUSED_ENTRY(160),
+ I40E_PTT_UNUSED_ENTRY(161),
+ I40E_PTT_UNUSED_ENTRY(162),
+ I40E_PTT_UNUSED_ENTRY(163),
+ I40E_PTT_UNUSED_ENTRY(164),
+ I40E_PTT_UNUSED_ENTRY(165),
+ I40E_PTT_UNUSED_ENTRY(166),
+ I40E_PTT_UNUSED_ENTRY(167),
+ I40E_PTT_UNUSED_ENTRY(168),
+ I40E_PTT_UNUSED_ENTRY(169),
+
+ I40E_PTT_UNUSED_ENTRY(170),
+ I40E_PTT_UNUSED_ENTRY(171),
+ I40E_PTT_UNUSED_ENTRY(172),
+ I40E_PTT_UNUSED_ENTRY(173),
+ I40E_PTT_UNUSED_ENTRY(174),
+ I40E_PTT_UNUSED_ENTRY(175),
+ I40E_PTT_UNUSED_ENTRY(176),
+ I40E_PTT_UNUSED_ENTRY(177),
+ I40E_PTT_UNUSED_ENTRY(178),
+ I40E_PTT_UNUSED_ENTRY(179),
+
+ I40E_PTT_UNUSED_ENTRY(180),
+ I40E_PTT_UNUSED_ENTRY(181),
+ I40E_PTT_UNUSED_ENTRY(182),
+ I40E_PTT_UNUSED_ENTRY(183),
+ I40E_PTT_UNUSED_ENTRY(184),
+ I40E_PTT_UNUSED_ENTRY(185),
+ I40E_PTT_UNUSED_ENTRY(186),
+ I40E_PTT_UNUSED_ENTRY(187),
+ I40E_PTT_UNUSED_ENTRY(188),
+ I40E_PTT_UNUSED_ENTRY(189),
+
+ I40E_PTT_UNUSED_ENTRY(190),
+ I40E_PTT_UNUSED_ENTRY(191),
+ I40E_PTT_UNUSED_ENTRY(192),
+ I40E_PTT_UNUSED_ENTRY(193),
+ I40E_PTT_UNUSED_ENTRY(194),
+ I40E_PTT_UNUSED_ENTRY(195),
+ I40E_PTT_UNUSED_ENTRY(196),
+ I40E_PTT_UNUSED_ENTRY(197),
+ I40E_PTT_UNUSED_ENTRY(198),
+ I40E_PTT_UNUSED_ENTRY(199),
+
+ I40E_PTT_UNUSED_ENTRY(200),
+ I40E_PTT_UNUSED_ENTRY(201),
+ I40E_PTT_UNUSED_ENTRY(202),
+ I40E_PTT_UNUSED_ENTRY(203),
+ I40E_PTT_UNUSED_ENTRY(204),
+ I40E_PTT_UNUSED_ENTRY(205),
+ I40E_PTT_UNUSED_ENTRY(206),
+ I40E_PTT_UNUSED_ENTRY(207),
+ I40E_PTT_UNUSED_ENTRY(208),
+ I40E_PTT_UNUSED_ENTRY(209),
+
+ I40E_PTT_UNUSED_ENTRY(210),
+ I40E_PTT_UNUSED_ENTRY(211),
+ I40E_PTT_UNUSED_ENTRY(212),
+ I40E_PTT_UNUSED_ENTRY(213),
+ I40E_PTT_UNUSED_ENTRY(214),
+ I40E_PTT_UNUSED_ENTRY(215),
+ I40E_PTT_UNUSED_ENTRY(216),
+ I40E_PTT_UNUSED_ENTRY(217),
+ I40E_PTT_UNUSED_ENTRY(218),
+ I40E_PTT_UNUSED_ENTRY(219),
+
+ I40E_PTT_UNUSED_ENTRY(220),
+ I40E_PTT_UNUSED_ENTRY(221),
+ I40E_PTT_UNUSED_ENTRY(222),
+ I40E_PTT_UNUSED_ENTRY(223),
+ I40E_PTT_UNUSED_ENTRY(224),
+ I40E_PTT_UNUSED_ENTRY(225),
+ I40E_PTT_UNUSED_ENTRY(226),
+ I40E_PTT_UNUSED_ENTRY(227),
+ I40E_PTT_UNUSED_ENTRY(228),
+ I40E_PTT_UNUSED_ENTRY(229),
+
+ I40E_PTT_UNUSED_ENTRY(230),
+ I40E_PTT_UNUSED_ENTRY(231),
+ I40E_PTT_UNUSED_ENTRY(232),
+ I40E_PTT_UNUSED_ENTRY(233),
+ I40E_PTT_UNUSED_ENTRY(234),
+ I40E_PTT_UNUSED_ENTRY(235),
+ I40E_PTT_UNUSED_ENTRY(236),
+ I40E_PTT_UNUSED_ENTRY(237),
+ I40E_PTT_UNUSED_ENTRY(238),
+ I40E_PTT_UNUSED_ENTRY(239),
+
+ I40E_PTT_UNUSED_ENTRY(240),
+ I40E_PTT_UNUSED_ENTRY(241),
+ I40E_PTT_UNUSED_ENTRY(242),
+ I40E_PTT_UNUSED_ENTRY(243),
+ I40E_PTT_UNUSED_ENTRY(244),
+ I40E_PTT_UNUSED_ENTRY(245),
+ I40E_PTT_UNUSED_ENTRY(246),
+ I40E_PTT_UNUSED_ENTRY(247),
+ I40E_PTT_UNUSED_ENTRY(248),
+ I40E_PTT_UNUSED_ENTRY(249),
+
+ I40E_PTT_UNUSED_ENTRY(250),
+ I40E_PTT_UNUSED_ENTRY(251),
+ I40E_PTT_UNUSED_ENTRY(252),
+ I40E_PTT_UNUSED_ENTRY(253),
+ I40E_PTT_UNUSED_ENTRY(254),
+ I40E_PTT_UNUSED_ENTRY(255)
+};
+
+
/**
* i40e_aq_send_msg_to_pf
* @hw: pointer to the hardware structure
@@ -199,8 +565,7 @@ i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw,
details.async = true;
cmd_details = &details;
}
- status = i40evf_asq_send_command(hw, (struct i40e_aq_desc *)&desc, msg,
- msglen, cmd_details);
+ status = i40evf_asq_send_command(hw, &desc, msg, msglen, cmd_details);
return status;
}
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
index 7841573a58c9..97ab8c2b76f8 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
@@ -63,6 +63,13 @@ i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw,
i40e_status i40e_set_mac_type(struct i40e_hw *hw);
+extern struct i40e_rx_ptype_decoded i40evf_ptype_lookup[];
+
+static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype)
+{
+ return i40evf_ptype_lookup[ptype];
+}
+
/* prototype for functions used for SW locks */
/* i40e_common for VF drivers*/
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
index ffdb01d853db..53be5f44d015 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
@@ -1,7 +1,7 @@
/*******************************************************************************
*
* Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 Intel Corporation.
+ * Copyright(c) 2013 - 2014 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -24,6 +24,7 @@
#include <linux/prefetch.h>
#include "i40evf.h"
+#include "i40e_prototype.h"
static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
u32 td_tag)
@@ -169,6 +170,20 @@ static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
}
/**
+ * i40e_get_head - Retrieve head from head writeback
+ * @tx_ring: tx ring to fetch head of
+ *
+ * Returns value of Tx ring head based on value stored
+ * in head write-back location
+ **/
+static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
+{
+ void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
+
+ return le32_to_cpu(*(volatile __le32 *)head);
+}
+
+/**
* i40e_clean_tx_irq - Reclaim resources after transmit completes
* @tx_ring: tx ring to clean
* @budget: how many cleans we're allowed
@@ -179,6 +194,7 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
{
u16 i = tx_ring->next_to_clean;
struct i40e_tx_buffer *tx_buf;
+ struct i40e_tx_desc *tx_head;
struct i40e_tx_desc *tx_desc;
unsigned int total_packets = 0;
unsigned int total_bytes = 0;
@@ -187,6 +203,8 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
tx_desc = I40E_TX_DESC(tx_ring, i);
i -= tx_ring->count;
+ tx_head = I40E_TX_DESC(tx_ring, i40e_get_head(tx_ring));
+
do {
struct i40e_tx_desc *eop_desc = tx_buf->next_to_watch;
@@ -197,9 +215,8 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
/* prevent any other reads prior to eop_desc */
read_barrier_depends();
- /* if the descriptor isn't done, no work yet to do */
- if (!(eop_desc->cmd_type_offset_bsz &
- cpu_to_le64(I40E_TX_DESC_DTYPE_DESC_DONE)))
+ /* we have caught up to head, no work left to do */
+ if (tx_head == tx_desc)
break;
/* clear next_to_watch to prevent false hangs */
@@ -431,6 +448,10 @@ int i40evf_setup_tx_descriptors(struct i40e_ring *tx_ring)
/* round up to nearest 4K */
tx_ring->size = tx_ring->count * sizeof(struct i40e_tx_desc);
+ /* add u32 for head writeback, align after this takes care of
+ * guaranteeing this is at least one cache line in size
+ */
+ tx_ring->size += sizeof(u32);
tx_ring->size = ALIGN(tx_ring->size, 4096);
tx_ring->desc = dma_alloc_coherent(dev, tx_ring->size,
&tx_ring->dma, GFP_KERNEL);
@@ -722,7 +743,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT)))
return;
- /* likely incorrect csum if alternate IP extention headers found */
+ /* likely incorrect csum if alternate IP extension headers found */
if (rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT))
return;
@@ -786,6 +807,29 @@ static inline u32 i40e_rx_hash(struct i40e_ring *ring,
}
/**
+ * i40e_ptype_to_hash - get a hash type
+ * @ptype: the ptype value from the descriptor
+ *
+ * Returns a hash type to be used by skb_set_hash
+ **/
+static inline enum pkt_hash_types i40e_ptype_to_hash(u8 ptype)
+{
+ struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(ptype);
+
+ if (!decoded.known)
+ return PKT_HASH_TYPE_NONE;
+
+ if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
+ decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY4)
+ return PKT_HASH_TYPE_L4;
+ else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
+ decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY3)
+ return PKT_HASH_TYPE_L3;
+ else
+ return PKT_HASH_TYPE_L2;
+}
+
+/**
* i40e_clean_rx_irq - Reclaim resources after receive completes
* @rx_ring: rx ring to clean
* @budget: how many cleans we're allowed
@@ -802,13 +846,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
u16 i = rx_ring->next_to_clean;
union i40e_rx_desc *rx_desc;
u32 rx_error, rx_status;
+ u8 rx_ptype;
u64 qword;
- u16 rx_ptype;
rx_desc = I40E_RX_DESC(rx_ring, i);
qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
- rx_status = (qword & I40E_RXD_QW1_STATUS_MASK)
- >> I40E_RXD_QW1_STATUS_SHIFT;
+ rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >>
+ I40E_RXD_QW1_STATUS_SHIFT;
while (rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)) {
union i40e_rx_desc *next_rxd;
@@ -912,7 +956,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
goto next_desc;
}
- skb->rxhash = i40e_rx_hash(rx_ring, rx_desc);
+ skb_set_hash(skb, i40e_rx_hash(rx_ring, rx_desc),
+ i40e_ptype_to_hash(rx_ptype));
/* probably a little skewed due to removing CRC */
total_rx_bytes += skb->len;
total_rx_packets++;
@@ -1241,7 +1286,8 @@ static void i40e_create_tx_ctx(struct i40e_ring *tx_ring,
struct i40e_tx_context_desc *context_desc;
int i = tx_ring->next_to_use;
- if (!cd_type_cmd_tso_mss && !cd_tunneling && !cd_l2tag2)
+ if ((cd_type_cmd_tso_mss == I40E_TX_DESC_DTYPE_CONTEXT) &&
+ !cd_tunneling && !cd_l2tag2)
return;
/* grab the next descriptor */
@@ -1352,9 +1398,23 @@ static void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
tx_bi = &tx_ring->tx_bi[i];
}
- tx_desc->cmd_type_offset_bsz =
- build_ctob(td_cmd, td_offset, size, td_tag) |
- cpu_to_le64((u64)I40E_TXD_CMD << I40E_TXD_QW1_CMD_SHIFT);
+ /* Place RS bit on last descriptor of any packet that spans across the
+ * 4th descriptor (WB_STRIDE aka 0x3) in a 64B cacheline.
+ */
+#define WB_STRIDE 0x3
+ if (((i & WB_STRIDE) != WB_STRIDE) &&
+ (first <= &tx_ring->tx_bi[i]) &&
+ (first >= &tx_ring->tx_bi[i & ~WB_STRIDE])) {
+ tx_desc->cmd_type_offset_bsz =
+ build_ctob(td_cmd, td_offset, size, td_tag) |
+ cpu_to_le64((u64)I40E_TX_DESC_CMD_EOP <<
+ I40E_TXD_QW1_CMD_SHIFT);
+ } else {
+ tx_desc->cmd_type_offset_bsz =
+ build_ctob(td_cmd, td_offset, size, td_tag) |
+ cpu_to_le64((u64)I40E_TXD_CMD <<
+ I40E_TXD_QW1_CMD_SHIFT);
+ }
netdev_tx_sent_queue(netdev_get_tx_queue(tx_ring->netdev,
tx_ring->queue_index),
@@ -1457,7 +1517,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb,
/* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,
* + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,
- * + 2 desc gap to keep tail from touching head,
+ * + 4 desc gap to avoid the cache line where head is,
* + 1 desc for context descriptor,
* otherwise try next time
*/
@@ -1468,7 +1528,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb,
count += skb_shinfo(skb)->nr_frags;
#endif
count += TXD_USE_COUNT(skb_headlen(skb));
- if (i40e_maybe_stop_tx(tx_ring, count + 3)) {
+ if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) {
tx_ring->tx_stats.tx_busy++;
return 0;
}
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h
index 3bffac06592f..4673b3381edd 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_type.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h
@@ -1,7 +1,7 @@
/*******************************************************************************
*
* Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 Intel Corporation.
+ * Copyright(c) 2013 - 2014 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -64,8 +64,6 @@
struct i40e_hw;
typedef void (*I40E_ADMINQ_CALLBACK)(struct i40e_hw *, struct i40e_aq_desc *);
-#define ETH_ALEN 6
-
/* Data type manipulation macros. */
#define I40E_DESC_UNUSED(R) \
@@ -90,6 +88,7 @@ enum i40e_debug_mask {
I40E_DEBUG_FLOW = 0x00000200,
I40E_DEBUG_DCB = 0x00000400,
I40E_DEBUG_DIAG = 0x00000800,
+ I40E_DEBUG_FD = 0x00001000,
I40E_DEBUG_AQ_MESSAGE = 0x01000000,
I40E_DEBUG_AQ_DESCRIPTOR = 0x02000000,
@@ -466,6 +465,10 @@ union i40e_32byte_rx_desc {
union {
__le32 rss; /* RSS Hash */
__le32 fcoe_param; /* FCoE DDP Context id */
+ /* Flow director filter id in case of
+ * Programming status desc WB
+ */
+ __le32 fd_id;
} hi_dword;
} qword0;
struct {
@@ -706,7 +709,7 @@ enum i40e_rx_prog_status_desc_prog_id_masks {
enum i40e_rx_prog_status_desc_error_bits {
/* Note: These are predefined bit offsets */
I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT = 0,
- I40E_RX_PROG_STATUS_DESC_NO_FD_QUOTA_SHIFT = 1,
+ I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT = 1,
I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT = 2,
I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT = 3
};
@@ -1018,6 +1021,11 @@ struct i40e_hw_port_stats {
u64 tx_size_big; /* ptc9522 */
u64 mac_short_packet_dropped; /* mspdc */
u64 checksum_error; /* xec */
+ /* EEE LPI */
+ bool tx_lpi_status;
+ bool rx_lpi_status;
+ u64 tx_lpi_count; /* etlpic */
+ u64 rx_lpi_count; /* erlpic */
};
/* Checksum and Shadow RAM pointers */
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h
index ff6529b288a1..807807d62387 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf.h
+++ b/drivers/net/ethernet/intel/i40evf/i40evf.h
@@ -1,7 +1,7 @@
/*******************************************************************************
*
* Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 Intel Corporation.
+ * Copyright(c) 2013 - 2014 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -38,8 +38,6 @@
#include <linux/ipv6.h>
#include <net/ip6_checksum.h>
#include <net/udp.h>
-#include <linux/sctp.h>
-
#include "i40e_type.h"
#include "i40e_virtchnl.h"
@@ -164,15 +162,14 @@ struct i40evf_vlan_filter {
/* Driver state. The order of these is important! */
enum i40evf_state_t {
__I40EVF_STARTUP, /* driver loaded, probe complete */
- __I40EVF_FAILED, /* PF communication failed. Fatal. */
__I40EVF_REMOVE, /* driver is being unloaded */
__I40EVF_INIT_VERSION_CHECK, /* aq msg sent, awaiting reply */
__I40EVF_INIT_GET_RESOURCES, /* aq msg sent, awaiting reply */
__I40EVF_INIT_SW, /* got resources, setting up structs */
+ __I40EVF_RESETTING, /* in reset */
/* Below here, watchdog is running */
__I40EVF_DOWN, /* ready, can be opened */
__I40EVF_TESTING, /* in ethtool self-test */
- __I40EVF_RESETTING, /* in reset */
__I40EVF_RUNNING, /* opened, working */
};
@@ -185,47 +182,25 @@ enum i40evf_critical_section_t {
/* board specific private data structure */
struct i40evf_adapter {
struct timer_list watchdog_timer;
- struct vlan_group *vlgrp;
struct work_struct reset_task;
struct work_struct adminq_task;
struct delayed_work init_task;
struct i40e_q_vector *q_vector[MAX_MSIX_Q_VECTORS];
struct list_head vlan_filter_list;
- char name[MAX_MSIX_COUNT][IFNAMSIZ + 9];
-
- /* Interrupt Throttle Rate */
- u32 itr_setting;
- u16 eitr_low;
- u16 eitr_high;
+ char misc_vector_name[IFNAMSIZ + 9];
/* TX */
struct i40e_ring *tx_rings[I40E_MAX_VSI_QP];
- u64 restart_queue;
- u64 hw_csum_tx_good;
- u64 lsc_int;
- u64 hw_tso_ctxt;
- u64 hw_tso6_ctxt;
u32 tx_timeout_count;
struct list_head mac_filter_list;
-#ifdef DEBUG
- bool detect_tx_hung;
-#endif /* DEBUG */
/* RX */
struct i40e_ring *rx_rings[I40E_MAX_VSI_QP];
- int txd_count;
- int rxd_count;
u64 hw_csum_rx_error;
- u64 hw_rx_no_dma_resources;
- u64 hw_csum_rx_good;
- u64 non_eop_descs;
int num_msix_vectors;
struct msix_entry *msix_entries;
- u64 rx_hdr_split;
-
- u32 init_state;
- volatile unsigned long flags;
+ u32 flags;
#define I40EVF_FLAG_RX_CSUM_ENABLED (u32)(1)
#define I40EVF_FLAG_RX_1BUF_CAPABLE (u32)(1 << 1)
#define I40EVF_FLAG_RX_PS_CAPABLE (u32)(1 << 2)
@@ -234,6 +209,9 @@ struct i40evf_adapter {
#define I40EVF_FLAG_IMIR_ENABLED (u32)(1 << 5)
#define I40EVF_FLAG_MQ_CAPABLE (u32)(1 << 6)
#define I40EVF_FLAG_NEED_LINK_UPDATE (u32)(1 << 7)
+#define I40EVF_FLAG_PF_COMMS_FAILED (u32)(1 << 8)
+#define I40EVF_FLAG_RESET_PENDING (u32)(1 << 9)
+#define I40EVF_FLAG_RESET_NEEDED (u32)(1 << 10)
/* duplcates for common code */
#define I40E_FLAG_FDIR_ATR_ENABLED 0
#define I40E_FLAG_DCB_ENABLED 0
@@ -251,21 +229,19 @@ struct i40evf_adapter {
#define I40EVF_FLAG_AQ_CONFIGURE_QUEUES (u32)(1 << 6)
#define I40EVF_FLAG_AQ_MAP_VECTORS (u32)(1 << 7)
#define I40EVF_FLAG_AQ_HANDLE_RESET (u32)(1 << 8)
+
/* OS defined structs */
struct net_device *netdev;
struct pci_dev *pdev;
struct net_device_stats net_stats;
- /* structs defined in i40e_vf.h */
- struct i40e_hw hw;
+ struct i40e_hw hw; /* defined in i40e_type.h */
enum i40evf_state_t state;
volatile unsigned long crit_section;
- u64 tx_busy;
struct work_struct watchdog_task;
bool netdev_registered;
- bool dev_closed;
bool link_up;
enum i40e_virtchnl_ops current_op;
struct i40e_virtchnl_vf_resource *vf_res; /* incl. all VSIs */
@@ -276,11 +252,6 @@ struct i40evf_adapter {
u32 aq_wait_count;
};
-struct i40evf_info {
- enum i40e_mac_type mac;
- unsigned int flags;
-};
-
/* needed by i40evf_ethtool.c */
extern char i40evf_driver_name[];
@@ -315,6 +286,7 @@ void i40evf_add_vlans(struct i40evf_adapter *adapter);
void i40evf_del_vlans(struct i40evf_adapter *adapter);
void i40evf_set_promiscuous(struct i40evf_adapter *adapter, int flags);
void i40evf_request_stats(struct i40evf_adapter *adapter);
+void i40evf_request_reset(struct i40evf_adapter *adapter);
void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
enum i40e_virtchnl_ops v_opcode,
i40e_status v_retval, u8 *msg, u16 msglen);
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
index b0b1f4bf5ac0..8b0db1ce179c 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
@@ -1,7 +1,7 @@
/*******************************************************************************
*
* Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 Intel Corporation.
+ * Copyright(c) 2013 - 2014 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -241,6 +241,7 @@ static int i40evf_set_ringparam(struct net_device *netdev,
{
struct i40evf_adapter *adapter = netdev_priv(netdev);
u32 new_rx_count, new_tx_count;
+ int i;
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
return -EINVAL;
@@ -256,12 +257,14 @@ static int i40evf_set_ringparam(struct net_device *netdev,
new_rx_count = ALIGN(new_rx_count, I40EVF_REQ_DESCRIPTOR_MULTIPLE);
/* if nothing to do return success */
- if ((new_tx_count == adapter->txd_count) &&
- (new_rx_count == adapter->rxd_count))
+ if ((new_tx_count == adapter->tx_rings[0]->count) &&
+ (new_rx_count == adapter->rx_rings[0]->count))
return 0;
- adapter->txd_count = new_tx_count;
- adapter->rxd_count = new_rx_count;
+ for (i = 0; i < adapter->vsi_res->num_queue_pairs; i++) {
+ adapter->tx_rings[0]->count = new_tx_count;
+ adapter->rx_rings[0]->count = new_rx_count;
+ }
if (netif_running(netdev))
i40evf_reinit_locked(adapter);
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
index f5caf4419243..e35e66ffa782 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
@@ -1,7 +1,7 @@
/*******************************************************************************
*
* Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 Intel Corporation.
+ * Copyright(c) 2013 - 2014 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -31,10 +31,10 @@ char i40evf_driver_name[] = "i40evf";
static const char i40evf_driver_string[] =
"Intel(R) XL710 X710 Virtual Function Network Driver";
-#define DRV_VERSION "0.9.11"
+#define DRV_VERSION "0.9.16"
const char i40evf_driver_version[] = DRV_VERSION;
static const char i40evf_copyright[] =
- "Copyright (c) 2013 Intel Corporation.";
+ "Copyright (c) 2013 - 2014 Intel Corporation.";
/* i40evf_pci_tbl - PCI Device ID Table
*
@@ -167,9 +167,11 @@ static void i40evf_tx_timeout(struct net_device *netdev)
struct i40evf_adapter *adapter = netdev_priv(netdev);
adapter->tx_timeout_count++;
-
- /* Do the reset outside of interrupt context */
- schedule_work(&adapter->reset_task);
+ dev_info(&adapter->pdev->dev, "TX timeout detected.\n");
+ if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING)) {
+ adapter->flags |= I40EVF_FLAG_RESET_NEEDED;
+ schedule_work(&adapter->reset_task);
+ }
}
/**
@@ -211,6 +213,9 @@ static void i40evf_irq_disable(struct i40evf_adapter *adapter)
int i;
struct i40e_hw *hw = &adapter->hw;
+ if (!adapter->msix_entries)
+ return;
+
for (i = 1; i < adapter->num_msix_vectors; i++) {
wr32(hw, I40E_VFINT_DYN_CTLN1(i - 1), 0);
synchronize_irq(adapter->msix_entries[i].vector);
@@ -511,12 +516,14 @@ static int i40evf_request_misc_irq(struct i40evf_adapter *adapter)
struct net_device *netdev = adapter->netdev;
int err;
- sprintf(adapter->name[0], "i40evf:mbx");
+ sprintf(adapter->misc_vector_name, "i40evf:mbx");
err = request_irq(adapter->msix_entries[0].vector,
- &i40evf_msix_aq, 0, adapter->name[0], netdev);
+ &i40evf_msix_aq, 0,
+ adapter->misc_vector_name, netdev);
if (err) {
dev_err(&adapter->pdev->dev,
- "request_irq for msix_aq failed: %d\n", err);
+ "request_irq for %s failed: %d\n",
+ adapter->misc_vector_name, err);
free_irq(adapter->msix_entries[0].vector, netdev);
}
return err;
@@ -963,16 +970,23 @@ void i40evf_down(struct i40evf_adapter *adapter)
struct net_device *netdev = adapter->netdev;
struct i40evf_mac_filter *f;
- /* remove all MAC filters from the VSI */
+ /* remove all MAC filters */
list_for_each_entry(f, &adapter->mac_filter_list, list) {
f->remove = true;
}
- adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER;
- /* disable receives */
- adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_QUEUES;
- mod_timer_pending(&adapter->watchdog_timer, jiffies + 1);
- msleep(20);
-
+ /* remove all VLAN filters */
+ list_for_each_entry(f, &adapter->vlan_filter_list, list) {
+ f->remove = true;
+ }
+ if (!(adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) &&
+ adapter->state != __I40EVF_RESETTING) {
+ adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER;
+ adapter->aq_required |= I40EVF_FLAG_AQ_DEL_VLAN_FILTER;
+ /* disable receives */
+ adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_QUEUES;
+ mod_timer_pending(&adapter->watchdog_timer, jiffies + 1);
+ msleep(20);
+ }
netif_tx_disable(netdev);
netif_tx_stop_all_queues(netdev);
@@ -1124,8 +1138,8 @@ static int i40evf_set_interrupt_capability(struct i40evf_adapter *adapter)
* than CPU's. So let's be conservative and only ask for
* (roughly) twice the number of vectors as there are CPU's.
*/
- v_budget = min(pairs, (int)(num_online_cpus() * 2)) + NONQ_VECS;
- v_budget = min(v_budget, (int)adapter->vf_res->max_vectors + 1);
+ v_budget = min_t(int, pairs, (int)(num_online_cpus() * 2)) + NONQ_VECS;
+ v_budget = min_t(int, v_budget, (int)adapter->vf_res->max_vectors);
/* A failure in MSI-X entry allocation isn't fatal, but it does
* mean we disable MSI-X capabilities of the adapter.
@@ -1291,19 +1305,47 @@ static void i40evf_watchdog_task(struct work_struct *work)
watchdog_task);
struct i40e_hw *hw = &adapter->hw;
- if (adapter->state < __I40EVF_DOWN)
+ if (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section))
+ goto restart_watchdog;
+
+ if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) {
+ dev_info(&adapter->pdev->dev, "Checking for redemption\n");
+ if ((rd32(hw, I40E_VFGEN_RSTAT) & 0x3) == I40E_VFR_VFACTIVE) {
+ /* A chance for redemption! */
+ dev_err(&adapter->pdev->dev, "Hardware came out of reset. Attempting reinit.\n");
+ adapter->state = __I40EVF_STARTUP;
+ adapter->flags &= ~I40EVF_FLAG_PF_COMMS_FAILED;
+ schedule_delayed_work(&adapter->init_task, 10);
+ clear_bit(__I40EVF_IN_CRITICAL_TASK,
+ &adapter->crit_section);
+ /* Don't reschedule the watchdog, since we've restarted
+ * the init task. When init_task contacts the PF and
+ * gets everything set up again, it'll restart the
+ * watchdog for us. Down, boy. Sit. Stay. Woof.
+ */
+ return;
+ }
+ adapter->aq_pending = 0;
+ adapter->aq_required = 0;
+ adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN;
goto watchdog_done;
+ }
- if (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section))
+ if ((adapter->state < __I40EVF_DOWN) ||
+ (adapter->flags & I40EVF_FLAG_RESET_PENDING))
goto watchdog_done;
- /* check for unannounced reset */
- if ((adapter->state != __I40EVF_RESETTING) &&
+ /* check for reset */
+ if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING) &&
(rd32(hw, I40E_VFGEN_RSTAT) & 0x3) != I40E_VFR_VFACTIVE) {
adapter->state = __I40EVF_RESETTING;
+ adapter->flags |= I40EVF_FLAG_RESET_PENDING;
+ dev_err(&adapter->pdev->dev, "Hardware reset detected.\n");
+ dev_info(&adapter->pdev->dev, "Scheduling reset task\n");
schedule_work(&adapter->reset_task);
- dev_info(&adapter->pdev->dev, "%s: hardware reset detected\n",
- __func__);
+ adapter->aq_pending = 0;
+ adapter->aq_required = 0;
+ adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN;
goto watchdog_done;
}
@@ -1358,16 +1400,25 @@ static void i40evf_watchdog_task(struct work_struct *work)
i40evf_irq_enable(adapter, true);
i40evf_fire_sw_int(adapter, 0xFF);
+
watchdog_done:
+ clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
+restart_watchdog:
if (adapter->aq_required)
mod_timer(&adapter->watchdog_timer,
jiffies + msecs_to_jiffies(20));
else
mod_timer(&adapter->watchdog_timer, jiffies + (HZ * 2));
- clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
schedule_work(&adapter->adminq_task);
}
+static int next_queue(struct i40evf_adapter *adapter, int j)
+{
+ j += 1;
+
+ return j >= adapter->vsi_res->num_queue_pairs ? 0 : j;
+}
+
/**
* i40evf_configure_rss - Prepare for RSS if used
* @adapter: board private structure
@@ -1398,19 +1449,19 @@ static void i40evf_configure_rss(struct i40evf_adapter *adapter)
wr32(hw, I40E_VFQF_HENA(1), (u32)(hena >> 32));
/* Populate the LUT with max no. of queues in round robin fashion */
- for (i = 0, j = 0; i < I40E_VFQF_HLUT_MAX_INDEX; i++, j++) {
- if (j == adapter->vsi_res->num_queue_pairs)
- j = 0;
- /* lut = 4-byte sliding window of 4 lut entries */
- lut = (lut << 8) | (j &
- ((0x1 << 8) - 1));
- /* On i = 3, we have 4 entries in lut; write to the register */
- if ((i & 3) == 3)
- wr32(hw, I40E_VFQF_HLUT(i >> 2), lut);
+ j = adapter->vsi_res->num_queue_pairs;
+ for (i = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) {
+ lut = next_queue(adapter, j);
+ lut |= next_queue(adapter, j) << 8;
+ lut |= next_queue(adapter, j) << 16;
+ lut |= next_queue(adapter, j) << 24;
+ wr32(hw, I40E_VFQF_HLUT(i), lut);
}
i40e_flush(hw);
}
+#define I40EVF_RESET_WAIT_MS 100
+#define I40EVF_RESET_WAIT_COUNT 200
/**
* i40evf_reset_task - Call-back task to handle hardware reset
* @work: pointer to work_struct
@@ -1421,8 +1472,9 @@ static void i40evf_configure_rss(struct i40evf_adapter *adapter)
**/
static void i40evf_reset_task(struct work_struct *work)
{
- struct i40evf_adapter *adapter =
- container_of(work, struct i40evf_adapter, reset_task);
+ struct i40evf_adapter *adapter = container_of(work,
+ struct i40evf_adapter,
+ reset_task);
struct i40e_hw *hw = &adapter->hw;
int i = 0, err;
uint32_t rstat_val;
@@ -1431,21 +1483,61 @@ static void i40evf_reset_task(struct work_struct *work)
&adapter->crit_section))
udelay(500);
- /* wait until the reset is complete */
- for (i = 0; i < 20; i++) {
+ if (adapter->flags & I40EVF_FLAG_RESET_NEEDED) {
+ dev_info(&adapter->pdev->dev, "Requesting reset from PF\n");
+ i40evf_request_reset(adapter);
+ }
+
+ /* poll until we see the reset actually happen */
+ for (i = 0; i < I40EVF_RESET_WAIT_COUNT; i++) {
rstat_val = rd32(hw, I40E_VFGEN_RSTAT) &
I40E_VFGEN_RSTAT_VFR_STATE_MASK;
- if (rstat_val == I40E_VFR_COMPLETED)
+ if (rstat_val != I40E_VFR_VFACTIVE) {
+ dev_info(&adapter->pdev->dev, "Reset now occurring\n");
break;
- else
- mdelay(100);
+ } else {
+ msleep(I40EVF_RESET_WAIT_MS);
+ }
+ }
+ if (i == I40EVF_RESET_WAIT_COUNT) {
+ dev_err(&adapter->pdev->dev, "Reset was not detected\n");
+ adapter->flags &= ~I40EVF_FLAG_RESET_PENDING;
+ goto continue_reset; /* act like the reset happened */
+ }
+
+ /* wait until the reset is complete and the PF is responding to us */
+ for (i = 0; i < I40EVF_RESET_WAIT_COUNT; i++) {
+ rstat_val = rd32(hw, I40E_VFGEN_RSTAT) &
+ I40E_VFGEN_RSTAT_VFR_STATE_MASK;
+ if (rstat_val == I40E_VFR_VFACTIVE) {
+ dev_info(&adapter->pdev->dev, "Reset is complete. Reinitializing.\n");
+ break;
+ } else {
+ msleep(I40EVF_RESET_WAIT_MS);
+ }
}
- if (i == 20) {
+ if (i == I40EVF_RESET_WAIT_COUNT) {
/* reset never finished */
- dev_info(&adapter->pdev->dev, "%s: reset never finished: %x\n",
- __func__, rstat_val);
- /* carry on anyway */
+ dev_err(&adapter->pdev->dev, "Reset never finished (%x). PF driver is dead, and so am I.\n",
+ rstat_val);
+ adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED;
+
+ if (netif_running(adapter->netdev))
+ i40evf_close(adapter->netdev);
+
+ i40evf_free_misc_irq(adapter);
+ i40evf_reset_interrupt_capability(adapter);
+ i40evf_free_queues(adapter);
+ kfree(adapter->vf_res);
+ i40evf_shutdown_adminq(hw);
+ adapter->netdev->flags &= ~IFF_UP;
+ clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
+ return; /* Do not attempt to reinit. It's dead, Jim. */
}
+
+continue_reset:
+ adapter->flags &= ~I40EVF_FLAG_RESET_PENDING;
+
i40evf_down(adapter);
adapter->state = __I40EVF_RESETTING;
@@ -1505,6 +1597,9 @@ static void i40evf_adminq_task(struct work_struct *work)
i40e_status ret;
u16 pending;
+ if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED)
+ return;
+
event.msg_size = I40EVF_MAX_AQ_BUF_SIZE;
event.msg_buf = kzalloc(event.msg_size, GFP_KERNEL);
if (!event.msg_buf) {
@@ -1636,6 +1731,10 @@ static int i40evf_open(struct net_device *netdev)
struct i40evf_adapter *adapter = netdev_priv(netdev);
int err;
+ if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) {
+ dev_err(&adapter->pdev->dev, "Unable to open device due to PF driver failure.\n");
+ return -EIO;
+ }
if (adapter->state != __I40EVF_DOWN)
return -EBUSY;
@@ -1690,8 +1789,12 @@ static int i40evf_close(struct net_device *netdev)
{
struct i40evf_adapter *adapter = netdev_priv(netdev);
+ if (adapter->state <= __I40EVF_DOWN)
+ return 0;
+
/* signal that we are down to the interrupt handler */
adapter->state = __I40EVF_DOWN;
+
set_bit(__I40E_DOWN, &adapter->vsi.state);
i40evf_down(adapter);
@@ -1842,16 +1945,18 @@ static void i40evf_init_task(struct work_struct *work)
switch (adapter->state) {
case __I40EVF_STARTUP:
/* driver loaded, probe complete */
+ adapter->flags &= ~I40EVF_FLAG_PF_COMMS_FAILED;
+ adapter->flags &= ~I40EVF_FLAG_RESET_PENDING;
err = i40e_set_mac_type(hw);
if (err) {
- dev_info(&pdev->dev, "%s: set_mac_type failed: %d\n",
- __func__, err);
+ dev_err(&pdev->dev, "Failed to set MAC type (%d)\n",
+ err);
goto err;
}
err = i40evf_check_reset_complete(hw);
if (err) {
- dev_info(&pdev->dev, "%s: device is still in reset (%d).\n",
- __func__, err);
+ dev_err(&pdev->dev, "Device is still in reset (%d)\n",
+ err);
goto err;
}
hw->aq.num_arq_entries = I40EVF_AQ_LEN;
@@ -1861,14 +1966,13 @@ static void i40evf_init_task(struct work_struct *work)
err = i40evf_init_adminq(hw);
if (err) {
- dev_info(&pdev->dev, "%s: init_adminq failed: %d\n",
- __func__, err);
+ dev_err(&pdev->dev, "Failed to init Admin Queue (%d)\n",
+ err);
goto err;
}
err = i40evf_send_api_ver(adapter);
if (err) {
- dev_info(&pdev->dev, "%s: unable to send to PF (%d)\n",
- __func__, err);
+ dev_err(&pdev->dev, "Unable to send to PF (%d)\n", err);
i40evf_shutdown_adminq(hw);
goto err;
}
@@ -1876,19 +1980,21 @@ static void i40evf_init_task(struct work_struct *work)
goto restart;
break;
case __I40EVF_INIT_VERSION_CHECK:
- if (!i40evf_asq_done(hw))
+ if (!i40evf_asq_done(hw)) {
+ dev_err(&pdev->dev, "Admin queue command never completed.\n");
goto err;
+ }
/* aq msg sent, awaiting reply */
err = i40evf_verify_api_ver(adapter);
if (err) {
- dev_err(&pdev->dev, "Unable to verify API version, error %d\n",
+ dev_err(&pdev->dev, "Unable to verify API version (%d)\n",
err);
goto err;
}
err = i40evf_send_vf_config_msg(adapter);
if (err) {
- dev_err(&pdev->dev, "Unable send config request, error %d\n",
+ dev_err(&pdev->dev, "Unable send config request (%d)\n",
err);
goto err;
}
@@ -1902,18 +2008,15 @@ static void i40evf_init_task(struct work_struct *work)
(I40E_MAX_VF_VSI *
sizeof(struct i40e_virtchnl_vsi_resource));
adapter->vf_res = kzalloc(bufsz, GFP_KERNEL);
- if (!adapter->vf_res) {
- dev_err(&pdev->dev, "%s: unable to allocate memory\n",
- __func__);
+ if (!adapter->vf_res)
goto err;
- }
}
err = i40evf_get_vf_config(adapter);
if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK)
goto restart;
if (err) {
- dev_info(&pdev->dev, "%s: unable to get VF config (%d)\n",
- __func__, err);
+ dev_err(&pdev->dev, "Unable to get VF config (%d)\n",
+ err);
goto err_alloc;
}
adapter->state = __I40EVF_INIT_SW;
@@ -1927,25 +2030,23 @@ static void i40evf_init_task(struct work_struct *work)
adapter->vsi_res = &adapter->vf_res->vsi_res[i];
}
if (!adapter->vsi_res) {
- dev_info(&pdev->dev, "%s: no LAN VSI found\n", __func__);
+ dev_err(&pdev->dev, "No LAN VSI found\n");
goto err_alloc;
}
adapter->flags |= I40EVF_FLAG_RX_CSUM_ENABLED;
- adapter->txd_count = I40EVF_DEFAULT_TXD;
- adapter->rxd_count = I40EVF_DEFAULT_RXD;
-
netdev->netdev_ops = &i40evf_netdev_ops;
i40evf_set_ethtool_ops(netdev);
netdev->watchdog_timeo = 5 * HZ;
-
- netdev->features |= NETIF_F_SG |
+ netdev->features |= NETIF_F_HIGHDMA |
+ NETIF_F_SG |
NETIF_F_IP_CSUM |
NETIF_F_SCTP_CSUM |
NETIF_F_IPV6_CSUM |
NETIF_F_TSO |
NETIF_F_TSO6 |
+ NETIF_F_RXCSUM |
NETIF_F_GRO;
if (adapter->vf_res->vf_offload_flags
@@ -1956,11 +2057,13 @@ static void i40evf_init_task(struct work_struct *work)
NETIF_F_HW_VLAN_CTAG_FILTER;
}
- /* The HW MAC address was set and/or determined in sw_init */
+ /* copy netdev features into list of user selectable features */
+ netdev->hw_features |= netdev->features;
+ netdev->hw_features &= ~NETIF_F_RXCSUM;
+
if (!is_valid_ether_addr(adapter->hw.mac.addr)) {
- dev_info(&pdev->dev,
- "Invalid MAC address %pMAC, using random\n",
- adapter->hw.mac.addr);
+ dev_info(&pdev->dev, "Invalid MAC address %pMAC, using random\n",
+ adapter->hw.mac.addr);
random_ether_addr(adapter->hw.mac.addr);
}
memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len);
@@ -1994,8 +2097,6 @@ static void i40evf_init_task(struct work_struct *work)
netif_carrier_off(netdev);
- strcpy(netdev->name, "eth%d");
-
adapter->vsi.id = adapter->vsi_res->vsi_id;
adapter->vsi.seid = adapter->vsi_res->vsi_id; /* dummy */
adapter->vsi.back = adapter;
@@ -2005,9 +2106,11 @@ static void i40evf_init_task(struct work_struct *work)
adapter->vsi.tx_itr_setting = I40E_ITR_DYNAMIC;
adapter->vsi.netdev = adapter->netdev;
- err = register_netdev(netdev);
- if (err)
- goto err_register;
+ if (!adapter->netdev_registered) {
+ err = register_netdev(netdev);
+ if (err)
+ goto err_register;
+ }
adapter->netdev_registered = true;
@@ -2031,7 +2134,6 @@ err_register:
i40evf_free_misc_irq(adapter);
err_sw_init:
i40evf_reset_interrupt_capability(adapter);
- adapter->state = __I40EVF_FAILED;
err_alloc:
kfree(adapter->vf_res);
adapter->vf_res = NULL;
@@ -2039,9 +2141,7 @@ err:
/* Things went into the weeds, so try again later */
if (++adapter->aq_wait_count > I40EVF_AQ_MAX_ERR) {
dev_err(&pdev->dev, "Failed to communicate with PF; giving up.\n");
- if (hw->aq.asq.count)
- i40evf_shutdown_adminq(hw); /* ignore error */
- adapter->state = __I40EVF_FAILED;
+ adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED;
return; /* do not reschedule */
}
schedule_delayed_work(&adapter->init_task, HZ * 3);
@@ -2084,26 +2184,20 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct net_device *netdev;
struct i40evf_adapter *adapter = NULL;
struct i40e_hw *hw = NULL;
- int err, pci_using_dac;
+ int err;
err = pci_enable_device(pdev);
if (err)
return err;
- if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) {
- pci_using_dac = true;
- /* coherent mask for the same size will always succeed if
- * dma_set_mask does
- */
- dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
- } else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
- pci_using_dac = false;
- dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
- } else {
- dev_err(&pdev->dev, "%s: DMA configuration failed: %d\n",
- __func__, err);
- err = -EIO;
- goto err_dma;
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (err) {
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (err) {
+ dev_err(&pdev->dev,
+ "DMA configuration failed: 0x%x\n", err);
+ goto err_dma;
+ }
}
err = pci_request_regions(pdev, i40evf_driver_name);
@@ -2128,8 +2222,6 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_drvdata(pdev, netdev);
adapter = netdev_priv(netdev);
- if (pci_using_dac)
- netdev->features |= NETIF_F_HIGHDMA;
adapter->netdev = netdev;
adapter->pdev = pdev;
@@ -2271,6 +2363,7 @@ static void i40evf_remove(struct pci_dev *pdev)
struct i40e_hw *hw = &adapter->hw;
cancel_delayed_work_sync(&adapter->init_task);
+ cancel_work_sync(&adapter->reset_task);
if (adapter->netdev_registered) {
unregister_netdev(netdev);
@@ -2278,17 +2371,15 @@ static void i40evf_remove(struct pci_dev *pdev)
}
adapter->state = __I40EVF_REMOVE;
- if (adapter->num_msix_vectors) {
+ if (adapter->msix_entries) {
i40evf_misc_irq_disable(adapter);
- del_timer_sync(&adapter->watchdog_timer);
-
- flush_scheduled_work();
-
i40evf_free_misc_irq(adapter);
-
i40evf_reset_interrupt_capability(adapter);
}
+ del_timer_sync(&adapter->watchdog_timer);
+ flush_scheduled_work();
+
if (hw->aq.asq.count)
i40evf_shutdown_adminq(hw);
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
index e6978d79e62b..e294f012647d 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
@@ -1,7 +1,7 @@
/*******************************************************************************
*
* Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 Intel Corporation.
+ * Copyright(c) 2013 - 2014 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -43,6 +43,9 @@ static int i40evf_send_pf_msg(struct i40evf_adapter *adapter,
struct i40e_hw *hw = &adapter->hw;
i40e_status err;
+ if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED)
+ return 0; /* nothing to see here, move along */
+
err = i40e_aq_send_msg_to_pf(hw, op, 0, msg, len, NULL);
if (err)
dev_err(&adapter->pdev->dev, "Unable to send opcode %d to PF, error %d, aq status %d\n",
@@ -651,6 +654,18 @@ void i40evf_request_stats(struct i40evf_adapter *adapter)
/* if the request failed, don't lock out others */
adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN;
}
+/**
+ * i40evf_request_reset
+ * @adapter: adapter structure
+ *
+ * Request that the PF reset this VF. No response is expected.
+ **/
+void i40evf_request_reset(struct i40evf_adapter *adapter)
+{
+ /* Don't check CURRENT_OP - this is always higher priority */
+ i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_RESET_VF, NULL, 0);
+ adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN;
+}
/**
* i40evf_virtchnl_completion
@@ -689,10 +704,12 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
}
break;
case I40E_VIRTCHNL_EVENT_RESET_IMPENDING:
- adapter->state = __I40EVF_RESETTING;
- schedule_work(&adapter->reset_task);
- dev_info(&adapter->pdev->dev,
- "%s: hardware reset pending\n", __func__);
+ dev_info(&adapter->pdev->dev, "PF reset warning received\n");
+ if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING)) {
+ adapter->flags |= I40EVF_FLAG_RESET_PENDING;
+ dev_info(&adapter->pdev->dev, "Scheduling reset task\n");
+ schedule_work(&adapter->reset_task);
+ }
break;
default:
dev_err(&adapter->pdev->dev,
diff --git a/drivers/net/ethernet/intel/igb/Makefile b/drivers/net/ethernet/intel/igb/Makefile
index f19700e285bb..5bcb2de75933 100644
--- a/drivers/net/ethernet/intel/igb/Makefile
+++ b/drivers/net/ethernet/intel/igb/Makefile
@@ -1,7 +1,7 @@
################################################################################
#
# Intel 82575 PCI-Express Ethernet Linux driver
-# Copyright(c) 1999 - 2013 Intel Corporation.
+# Copyright(c) 1999 - 2014 Intel Corporation.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
# 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.
+# this program; if not, see <http://www.gnu.org/licenses/>.
#
# The full GNU General Public License is included in this distribution in
# the file called "COPYING".
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c
index 06df6928f44c..fa36fe12e775 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2013 Intel Corporation.
+ Copyright(c) 2007-2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
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.
+ this program; if not, see <http://www.gnu.org/licenses/>.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
@@ -77,8 +76,6 @@ static s32 igb_update_nvm_checksum_i350(struct e1000_hw *hw);
static const u16 e1000_82580_rxpbs_table[] =
{ 36, 72, 144, 1, 2, 4, 8, 16,
35, 70, 140 };
-#define E1000_82580_RXPBS_TABLE_SIZE \
- (sizeof(e1000_82580_rxpbs_table)/sizeof(u16))
/**
* igb_sgmii_uses_mdio_82575 - Determine if I2C pins are for external MDIO
@@ -2308,7 +2305,7 @@ u16 igb_rxpbs_adjust_82580(u32 data)
{
u16 ret_val = 0;
- if (data < E1000_82580_RXPBS_TABLE_SIZE)
+ if (data < ARRAY_SIZE(e1000_82580_rxpbs_table))
ret_val = e1000_82580_rxpbs_table[data];
return ret_val;
@@ -2714,13 +2711,14 @@ static const u8 e1000_emc_therm_limit[4] = {
E1000_EMC_DIODE3_THERM_LIMIT
};
+#ifdef CONFIG_IGB_HWMON
/**
* igb_get_thermal_sensor_data_generic - Gathers thermal sensor data
* @hw: pointer to hardware structure
*
* Updates the temperatures in mac.thermal_sensor_data
**/
-s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw)
+static s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw)
{
s32 status = E1000_SUCCESS;
u16 ets_offset;
@@ -2774,7 +2772,7 @@ s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw)
* Sets the thermal sensor thresholds according to the NVM map
* and save off the threshold and location values into mac.thermal_sensor_data
**/
-s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *hw)
+static s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *hw)
{
s32 status = E1000_SUCCESS;
u16 ets_offset;
@@ -2836,6 +2834,7 @@ s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *hw)
return status;
}
+#endif
static struct e1000_mac_operations e1000_mac_ops_82575 = {
.init_hw = igb_init_hw_82575,
.check_for_link = igb_check_for_link_82575,
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.h b/drivers/net/ethernet/intel/igb/e1000_82575.h
index 8c2437722aad..09d78be72416 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.h
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2013 Intel Corporation.
+ Copyright(c) 2007-2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
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.
+ this program; if not, see <http://www.gnu.org/licenses/>.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
@@ -231,6 +230,10 @@ struct e1000_adv_tx_context_desc {
#define E1000_VMOLR_STRVLAN 0x40000000 /* Vlan stripping enable */
#define E1000_VMOLR_STRCRC 0x80000000 /* CRC stripping enable */
+#define E1000_DVMOLR_HIDEVLAN 0x20000000 /* Hide vlan enable */
+#define E1000_DVMOLR_STRVLAN 0x40000000 /* Vlan stripping enable */
+#define E1000_DVMOLR_STRCRC 0x80000000 /* CRC stripping enable */
+
#define E1000_VLVF_ARRAY_SIZE 32
#define E1000_VLVF_VLANID_MASK 0x00000FFF
#define E1000_VLVF_POOLSEL_SHIFT 12
@@ -266,8 +269,7 @@ u16 igb_rxpbs_adjust_82580(u32 data);
s32 igb_read_emi_reg(struct e1000_hw *, u16 addr, u16 *data);
s32 igb_set_eee_i350(struct e1000_hw *);
s32 igb_set_eee_i354(struct e1000_hw *);
-s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *);
-s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw);
+s32 igb_get_eee_status_i354(struct e1000_hw *hw, bool *status);
#define E1000_I2C_THERMAL_SENSOR_ADDR 0xF8
#define E1000_EMC_INTERNAL_DATA 0x00
diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h
index 0571b973be80..b05bf925ac72 100644
--- a/drivers/net/ethernet/intel/igb/e1000_defines.h
+++ b/drivers/net/ethernet/intel/igb/e1000_defines.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2013 Intel Corporation.
+ Copyright(c) 2007-2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
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.
+ this program; if not, see <http://www.gnu.org/licenses/>.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
@@ -44,7 +43,11 @@
#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */
/* Extended Device Control */
+#define E1000_CTRL_EXT_SDP2_DATA 0x00000040 /* Value of SW Defineable Pin 2 */
#define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Defineable Pin 3 */
+#define E1000_CTRL_EXT_SDP2_DIR 0x00000400 /* SDP2 Data direction */
+#define E1000_CTRL_EXT_SDP3_DIR 0x00000800 /* SDP3 Data direction */
+
/* Physical Func Reset Done Indication */
#define E1000_CTRL_EXT_PFRSTD 0x00004000
#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
@@ -191,7 +194,8 @@
/* enable link status from external LINK_0 and LINK_1 pins */
#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */
#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */
-#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SDP0_DIR 0x00400000 /* SDP0 Data direction */
+#define E1000_CTRL_SDP1_DIR 0x00800000 /* SDP1 Data direction */
#define E1000_CTRL_RST 0x04000000 /* Global reset */
#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */
#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */
@@ -529,8 +533,67 @@
#define E1000_TIMINCA_16NS_SHIFT 24
-#define E1000_TSICR_TXTS 0x00000002
-#define E1000_TSIM_TXTS 0x00000002
+/* Time Sync Interrupt Cause/Mask Register Bits */
+
+#define TSINTR_SYS_WRAP (1 << 0) /* SYSTIM Wrap around. */
+#define TSINTR_TXTS (1 << 1) /* Transmit Timestamp. */
+#define TSINTR_RXTS (1 << 2) /* Receive Timestamp. */
+#define TSINTR_TT0 (1 << 3) /* Target Time 0 Trigger. */
+#define TSINTR_TT1 (1 << 4) /* Target Time 1 Trigger. */
+#define TSINTR_AUTT0 (1 << 5) /* Auxiliary Timestamp 0 Taken. */
+#define TSINTR_AUTT1 (1 << 6) /* Auxiliary Timestamp 1 Taken. */
+#define TSINTR_TADJ (1 << 7) /* Time Adjust Done. */
+
+#define TSYNC_INTERRUPTS TSINTR_TXTS
+#define E1000_TSICR_TXTS TSINTR_TXTS
+
+/* TSAUXC Configuration Bits */
+#define TSAUXC_EN_TT0 (1 << 0) /* Enable target time 0. */
+#define TSAUXC_EN_TT1 (1 << 1) /* Enable target time 1. */
+#define TSAUXC_EN_CLK0 (1 << 2) /* Enable Configurable Frequency Clock 0. */
+#define TSAUXC_SAMP_AUT0 (1 << 3) /* Latch SYSTIML/H into AUXSTMPL/0. */
+#define TSAUXC_ST0 (1 << 4) /* Start Clock 0 Toggle on Target Time 0. */
+#define TSAUXC_EN_CLK1 (1 << 5) /* Enable Configurable Frequency Clock 1. */
+#define TSAUXC_SAMP_AUT1 (1 << 6) /* Latch SYSTIML/H into AUXSTMPL/1. */
+#define TSAUXC_ST1 (1 << 7) /* Start Clock 1 Toggle on Target Time 1. */
+#define TSAUXC_EN_TS0 (1 << 8) /* Enable hardware timestamp 0. */
+#define TSAUXC_AUTT0 (1 << 9) /* Auxiliary Timestamp Taken. */
+#define TSAUXC_EN_TS1 (1 << 10) /* Enable hardware timestamp 0. */
+#define TSAUXC_AUTT1 (1 << 11) /* Auxiliary Timestamp Taken. */
+#define TSAUXC_PLSG (1 << 17) /* Generate a pulse. */
+#define TSAUXC_DISABLE (1 << 31) /* Disable SYSTIM Count Operation. */
+
+/* SDP Configuration Bits */
+#define AUX0_SEL_SDP0 (0 << 0) /* Assign SDP0 to auxiliary time stamp 0. */
+#define AUX0_SEL_SDP1 (1 << 0) /* Assign SDP1 to auxiliary time stamp 0. */
+#define AUX0_SEL_SDP2 (2 << 0) /* Assign SDP2 to auxiliary time stamp 0. */
+#define AUX0_SEL_SDP3 (3 << 0) /* Assign SDP3 to auxiliary time stamp 0. */
+#define AUX0_TS_SDP_EN (1 << 2) /* Enable auxiliary time stamp trigger 0. */
+#define AUX1_SEL_SDP0 (0 << 3) /* Assign SDP0 to auxiliary time stamp 1. */
+#define AUX1_SEL_SDP1 (1 << 3) /* Assign SDP1 to auxiliary time stamp 1. */
+#define AUX1_SEL_SDP2 (2 << 3) /* Assign SDP2 to auxiliary time stamp 1. */
+#define AUX1_SEL_SDP3 (3 << 3) /* Assign SDP3 to auxiliary time stamp 1. */
+#define AUX1_TS_SDP_EN (1 << 5) /* Enable auxiliary time stamp trigger 1. */
+#define TS_SDP0_SEL_TT0 (0 << 6) /* Target time 0 is output on SDP0. */
+#define TS_SDP0_SEL_TT1 (1 << 6) /* Target time 1 is output on SDP0. */
+#define TS_SDP0_SEL_FC0 (2 << 6) /* Freq clock 0 is output on SDP0. */
+#define TS_SDP0_SEL_FC1 (3 << 6) /* Freq clock 1 is output on SDP0. */
+#define TS_SDP0_EN (1 << 8) /* SDP0 is assigned to Tsync. */
+#define TS_SDP1_SEL_TT0 (0 << 9) /* Target time 0 is output on SDP1. */
+#define TS_SDP1_SEL_TT1 (1 << 9) /* Target time 1 is output on SDP1. */
+#define TS_SDP1_SEL_FC0 (2 << 9) /* Freq clock 0 is output on SDP1. */
+#define TS_SDP1_SEL_FC1 (3 << 9) /* Freq clock 1 is output on SDP1. */
+#define TS_SDP1_EN (1 << 11) /* SDP1 is assigned to Tsync. */
+#define TS_SDP2_SEL_TT0 (0 << 12) /* Target time 0 is output on SDP2. */
+#define TS_SDP2_SEL_TT1 (1 << 12) /* Target time 1 is output on SDP2. */
+#define TS_SDP2_SEL_FC0 (2 << 12) /* Freq clock 0 is output on SDP2. */
+#define TS_SDP2_SEL_FC1 (3 << 12) /* Freq clock 1 is output on SDP2. */
+#define TS_SDP2_EN (1 << 14) /* SDP2 is assigned to Tsync. */
+#define TS_SDP3_SEL_TT0 (0 << 15) /* Target time 0 is output on SDP3. */
+#define TS_SDP3_SEL_TT1 (1 << 15) /* Target time 1 is output on SDP3. */
+#define TS_SDP3_SEL_FC0 (2 << 15) /* Freq clock 0 is output on SDP3. */
+#define TS_SDP3_SEL_FC1 (3 << 15) /* Freq clock 1 is output on SDP3. */
+#define TS_SDP3_EN (1 << 17) /* SDP3 is assigned to Tsync. */
#define E1000_MDICNFG_EXT_MDIO 0x80000000 /* MDI ext/int destination */
#define E1000_MDICNFG_COM_MDIO 0x40000000 /* MDI shared w/ lan 0 */
diff --git a/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h
index ab99e2b582a8..10741d170f2d 100644
--- a/drivers/net/ethernet/intel/igb/e1000_hw.h
+++ b/drivers/net/ethernet/intel/igb/e1000_hw.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2013 Intel Corporation.
+ Copyright(c) 2007-2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
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.
+ this program; if not, see <http://www.gnu.org/licenses/>.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.c b/drivers/net/ethernet/intel/igb/e1000_i210.c
index 0c0393316a3a..db963397cc27 100644
--- a/drivers/net/ethernet/intel/igb/e1000_i210.c
+++ b/drivers/net/ethernet/intel/igb/e1000_i210.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2013 Intel Corporation.
+ Copyright(c) 2007-2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
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.
+ this program; if not, see <http://www.gnu.org/licenses/>.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
@@ -35,6 +34,8 @@
#include "e1000_hw.h"
#include "e1000_i210.h"
+static s32 igb_update_flash_i210(struct e1000_hw *hw);
+
/**
* igb_get_hw_semaphore_i210 - Acquire hardware semaphore
* @hw: pointer to the HW structure
@@ -111,7 +112,7 @@ static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw)
* Return successful if access grant bit set, else clear the request for
* EEPROM access and return -E1000_ERR_NVM (-1).
**/
-s32 igb_acquire_nvm_i210(struct e1000_hw *hw)
+static s32 igb_acquire_nvm_i210(struct e1000_hw *hw)
{
return igb_acquire_swfw_sync_i210(hw, E1000_SWFW_EEP_SM);
}
@@ -123,7 +124,7 @@ s32 igb_acquire_nvm_i210(struct e1000_hw *hw)
* Stop any current commands to the EEPROM and clear the EEPROM request bit,
* then release the semaphores acquired.
**/
-void igb_release_nvm_i210(struct e1000_hw *hw)
+static void igb_release_nvm_i210(struct e1000_hw *hw)
{
igb_release_swfw_sync_i210(hw, E1000_SWFW_EEP_SM);
}
@@ -206,8 +207,8 @@ void igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask)
* Reads a 16 bit word from the Shadow Ram using the EERD register.
* Uses necessary synchronization semaphores.
**/
-s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words,
- u16 *data)
+static s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data)
{
s32 status = E1000_SUCCESS;
u16 i, count;
@@ -306,8 +307,8 @@ out:
* If error code is returned, data and Shadow RAM may be inconsistent - buffer
* partially written.
**/
-s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words,
- u16 *data)
+static s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data)
{
s32 status = E1000_SUCCESS;
u16 i, count;
@@ -555,7 +556,7 @@ s32 igb_read_invm_version(struct e1000_hw *hw,
* Calculates the EEPROM checksum by reading/adding each word of the EEPROM
* and then verifies that the sum of the EEPROM is equal to 0xBABA.
**/
-s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw)
+static s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw)
{
s32 status = E1000_SUCCESS;
s32 (*read_op_ptr)(struct e1000_hw *, u16, u16, u16 *);
@@ -590,7 +591,7 @@ s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw)
* up to the checksum. Then calculates the EEPROM checksum and writes the
* value to the EEPROM. Next commit EEPROM data onto the Flash.
**/
-s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw)
+static s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw)
{
s32 ret_val = E1000_SUCCESS;
u16 checksum = 0;
@@ -684,7 +685,7 @@ bool igb_get_flash_presence_i210(struct e1000_hw *hw)
* @hw: pointer to the HW structure
*
**/
-s32 igb_update_flash_i210(struct e1000_hw *hw)
+static s32 igb_update_flash_i210(struct e1000_hw *hw)
{
s32 ret_val = E1000_SUCCESS;
u32 flup;
diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.h b/drivers/net/ethernet/intel/igb/e1000_i210.h
index 2d913716573a..907fe99a9813 100644
--- a/drivers/net/ethernet/intel/igb/e1000_i210.h
+++ b/drivers/net/ethernet/intel/igb/e1000_i210.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2013 Intel Corporation.
+ Copyright(c) 2007-2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
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.
+ this program; if not, see <http://www.gnu.org/licenses/>.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
@@ -28,17 +27,8 @@
#ifndef _E1000_I210_H_
#define _E1000_I210_H_
-s32 igb_update_flash_i210(struct e1000_hw *hw);
-s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw);
-s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw);
-s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words,
- u16 *data);
-s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words,
- u16 *data);
s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask);
void igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask);
-s32 igb_acquire_nvm_i210(struct e1000_hw *hw);
-void igb_release_nvm_i210(struct e1000_hw *hw);
s32 igb_valid_led_default_i210(struct e1000_hw *hw, u16 *data);
s32 igb_read_invm_version(struct e1000_hw *hw,
struct e1000_fw_version *invm_ver);
diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.c b/drivers/net/ethernet/intel/igb/e1000_mac.c
index 298f0ed50670..5910a932ea7c 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mac.c
+++ b/drivers/net/ethernet/intel/igb/e1000_mac.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2013 Intel Corporation.
+ Copyright(c) 2007-2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
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.
+ this program; if not, see <http://www.gnu.org/licenses/>.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.h b/drivers/net/ethernet/intel/igb/e1000_mac.h
index e4cbe8ef67b3..99299ba8ee3a 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mac.h
+++ b/drivers/net/ethernet/intel/igb/e1000_mac.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2013 Intel Corporation.
+ Copyright(c) 2007-2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
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.
+ this program; if not, see <http://www.gnu.org/licenses/>.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
diff --git a/drivers/net/ethernet/intel/igb/e1000_mbx.c b/drivers/net/ethernet/intel/igb/e1000_mbx.c
index dac1447fabf7..d5b121771c31 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mbx.c
+++ b/drivers/net/ethernet/intel/igb/e1000_mbx.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2013 Intel Corporation.
+ Copyright(c) 2007-2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
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.
+ this program; if not, see <http://www.gnu.org/licenses/>.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
diff --git a/drivers/net/ethernet/intel/igb/e1000_mbx.h b/drivers/net/ethernet/intel/igb/e1000_mbx.h
index de9bba41acf3..f52f5515e5a8 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mbx.h
+++ b/drivers/net/ethernet/intel/igb/e1000_mbx.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2013 Intel Corporation.
+ Copyright(c) 2007-2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
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.
+ this program; if not, see <http://www.gnu.org/licenses/>.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.c b/drivers/net/ethernet/intel/igb/e1000_nvm.c
index a7db7f3db914..9abf82919c65 100644
--- a/drivers/net/ethernet/intel/igb/e1000_nvm.c
+++ b/drivers/net/ethernet/intel/igb/e1000_nvm.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2013 Intel Corporation.
+ Copyright(c) 2007-2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
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.
+ this program; if not, see <http://www.gnu.org/licenses/>.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.h b/drivers/net/ethernet/intel/igb/e1000_nvm.h
index 433b7419cb98..5b101170b17e 100644
--- a/drivers/net/ethernet/intel/igb/e1000_nvm.h
+++ b/drivers/net/ethernet/intel/igb/e1000_nvm.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2013 Intel Corporation.
+ Copyright(c) 2007-2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
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.
+ this program; if not, see <http://www.gnu.org/licenses/>.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.c b/drivers/net/ethernet/intel/igb/e1000_phy.c
index ad2b74d95138..4009bbab7407 100644
--- a/drivers/net/ethernet/intel/igb/e1000_phy.c
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2013 Intel Corporation.
+ Copyright(c) 2007-2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
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.
+ this program; if not, see <http://www.gnu.org/licenses/>.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
@@ -394,77 +393,6 @@ s32 igb_read_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 *data)
}
/**
- * e1000_write_sfp_data_byte - Writes SFP module data.
- * @hw: pointer to the HW structure
- * @offset: byte location offset to write to
- * @data: data to write
- *
- * Writes one byte to SFP module data stored
- * in SFP resided EEPROM memory or SFP diagnostic area.
- * Function should be called with
- * E1000_I2CCMD_SFP_DATA_ADDR(<byte offset>) for SFP module database access
- * E1000_I2CCMD_SFP_DIAG_ADDR(<byte offset>) for SFP diagnostics parameters
- * access
- **/
-s32 e1000_write_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 data)
-{
- u32 i = 0;
- u32 i2ccmd = 0;
- u32 data_local = 0;
-
- if (offset > E1000_I2CCMD_SFP_DIAG_ADDR(255)) {
- hw_dbg("I2CCMD command address exceeds upper limit\n");
- return -E1000_ERR_PHY;
- }
- /* The programming interface is 16 bits wide
- * so we need to read the whole word first
- * then update appropriate byte lane and write
- * the updated word back.
- */
- /* Set up Op-code, EEPROM Address,in the I2CCMD
- * register. The MAC will take care of interfacing
- * with an EEPROM to write the data given.
- */
- i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
- E1000_I2CCMD_OPCODE_READ);
- /* Set a command to read single word */
- wr32(E1000_I2CCMD, i2ccmd);
- for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
- udelay(50);
- /* Poll the ready bit to see if lastly
- * launched I2C operation completed
- */
- i2ccmd = rd32(E1000_I2CCMD);
- if (i2ccmd & E1000_I2CCMD_READY) {
- /* Check if this is READ or WRITE phase */
- if ((i2ccmd & E1000_I2CCMD_OPCODE_READ) ==
- E1000_I2CCMD_OPCODE_READ) {
- /* Write the selected byte
- * lane and update whole word
- */
- data_local = i2ccmd & 0xFF00;
- data_local |= data;
- i2ccmd = ((offset <<
- E1000_I2CCMD_REG_ADDR_SHIFT) |
- E1000_I2CCMD_OPCODE_WRITE | data_local);
- wr32(E1000_I2CCMD, i2ccmd);
- } else {
- break;
- }
- }
- }
- if (!(i2ccmd & E1000_I2CCMD_READY)) {
- hw_dbg("I2CCMD Write did not complete\n");
- return -E1000_ERR_PHY;
- }
- if (i2ccmd & E1000_I2CCMD_ERROR) {
- hw_dbg("I2CCMD Error bit set\n");
- return -E1000_ERR_PHY;
- }
- return 0;
-}
-
-/**
* igb_read_phy_reg_igp - Read igp PHY register
* @hw: pointer to the HW structure
* @offset: register offset to be read
diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.h b/drivers/net/ethernet/intel/igb/e1000_phy.h
index 6a0873f2095a..4c2c36c46a73 100644
--- a/drivers/net/ethernet/intel/igb/e1000_phy.h
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2013 Intel Corporation.
+ Copyright(c) 2007-2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
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.
+ this program; if not, see <http://www.gnu.org/licenses/>.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
@@ -70,7 +69,6 @@ s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
s32 igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data);
s32 igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data);
s32 igb_read_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 *data);
-s32 e1000_write_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 data);
s32 igb_copper_link_setup_82580(struct e1000_hw *hw);
s32 igb_get_phy_info_82580(struct e1000_hw *hw);
s32 igb_phy_force_speed_duplex_82580(struct e1000_hw *hw);
diff --git a/drivers/net/ethernet/intel/igb/e1000_regs.h b/drivers/net/ethernet/intel/igb/e1000_regs.h
index 82632c6c53af..bdb246e848e1 100644
--- a/drivers/net/ethernet/intel/igb/e1000_regs.h
+++ b/drivers/net/ethernet/intel/igb/e1000_regs.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2013 Intel Corporation.
+ Copyright(c) 2007-2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
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.
+ this program; if not, see <http://www.gnu.org/licenses/>.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
@@ -41,6 +40,7 @@
#define E1000_FCT 0x00030 /* Flow Control Type - RW */
#define E1000_CONNSW 0x00034 /* Copper/Fiber switch control - RW */
#define E1000_VET 0x00038 /* VLAN Ether Type - RW */
+#define E1000_TSSDP 0x0003C /* Time Sync SDP Configuration Register - RW */
#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */
#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */
#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */
@@ -102,6 +102,14 @@
#define E1000_SYSTIMH 0x0B604 /* System time register High - RO */
#define E1000_TIMINCA 0x0B608 /* Increment attributes register - RW */
#define E1000_TSAUXC 0x0B640 /* Timesync Auxiliary Control register */
+#define E1000_TRGTTIML0 0x0B644 /* Target Time Register 0 Low - RW */
+#define E1000_TRGTTIMH0 0x0B648 /* Target Time Register 0 High - RW */
+#define E1000_TRGTTIML1 0x0B64C /* Target Time Register 1 Low - RW */
+#define E1000_TRGTTIMH1 0x0B650 /* Target Time Register 1 High - RW */
+#define E1000_AUXSTMPL0 0x0B65C /* Auxiliary Time Stamp 0 Register Low - RO */
+#define E1000_AUXSTMPH0 0x0B660 /* Auxiliary Time Stamp 0 Register High - RO */
+#define E1000_AUXSTMPL1 0x0B664 /* Auxiliary Time Stamp 1 Register Low - RO */
+#define E1000_AUXSTMPH1 0x0B668 /* Auxiliary Time Stamp 1 Register High - RO */
#define E1000_SYSTIMR 0x0B6F8 /* System time register Residue */
#define E1000_TSICR 0x0B66C /* Interrupt Cause Register */
#define E1000_TSIM 0x0B674 /* Interrupt Mask Register */
@@ -349,16 +357,30 @@
#define E1000_P2VMAILBOX(_n) (0x00C00 + (4 * (_n)))
#define E1000_VMBMEM(_n) (0x00800 + (64 * (_n)))
#define E1000_VMOLR(_n) (0x05AD0 + (4 * (_n)))
+#define E1000_DVMOLR(_n) (0x0C038 + (64 * (_n)))
#define E1000_VLVF(_n) (0x05D00 + (4 * (_n))) /* VLAN Virtual Machine
* Filter - RW */
#define E1000_VMVIR(_n) (0x03700 + (4 * (_n)))
-#define wr32(reg, value) (writel(value, hw->hw_addr + reg))
-#define rd32(reg) (readl(hw->hw_addr + reg))
+struct e1000_hw;
+
+u32 igb_rd32(struct e1000_hw *hw, u32 reg);
+
+/* write operations, indexed using DWORDS */
+#define wr32(reg, val) \
+do { \
+ u8 __iomem *hw_addr = ACCESS_ONCE((hw)->hw_addr); \
+ if (!E1000_REMOVED(hw_addr)) \
+ writel((val), &hw_addr[(reg)]); \
+} while (0)
+
+#define rd32(reg) (igb_rd32(hw, reg))
+
#define wrfl() ((void)rd32(E1000_STATUS))
#define array_wr32(reg, offset, value) \
- (writel(value, hw->hw_addr + reg + ((offset) << 2)))
+ wr32((reg) + ((offset) << 2), (value))
+
#define array_rd32(reg, offset) \
(readl(hw->hw_addr + reg + ((offset) << 2)))
@@ -397,4 +419,6 @@
#define E1000_INVM_DATA_REG(_n) (0x12120 + 4*(_n))
#define E1000_INVM_SIZE 64 /* Number of INVM Data Registers */
+#define E1000_REMOVED(h) unlikely(!(h))
+
#endif
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index ccf472f073dd..7fbe1e925143 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2013 Intel Corporation.
+ Copyright(c) 2007-2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
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.
+ this program; if not, see <http://www.gnu.org/licenses/>.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
@@ -42,6 +41,7 @@
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/pci.h>
+#include <linux/mdio.h>
struct igb_adapter;
@@ -434,6 +434,7 @@ struct igb_adapter {
struct delayed_work ptp_overflow_work;
struct work_struct ptp_tx_work;
struct sk_buff *ptp_tx_skb;
+ struct hwtstamp_config tstamp_config;
unsigned long ptp_tx_start;
unsigned long last_rx_ptp_check;
spinlock_t tmreg_lock;
@@ -456,6 +457,7 @@ struct igb_adapter {
unsigned long link_check_timeout;
int copper_tries;
struct e1000_info ei;
+ u16 eee_advert;
};
#define IGB_FLAG_HAS_MSI (1 << 0)
@@ -472,6 +474,7 @@ struct igb_adapter {
#define IGB_FLAG_MAS_CAPABLE (1 << 11)
#define IGB_FLAG_MAS_ENABLE (1 << 12)
#define IGB_FLAG_HAS_MSIX (1 << 13)
+#define IGB_FLAG_EEE (1 << 14)
/* Media Auto Sense */
#define IGB_MAS_ENABLE_0 0X0001
@@ -489,7 +492,8 @@ struct igb_adapter {
enum e1000_state_t {
__IGB_TESTING,
__IGB_RESETTING,
- __IGB_DOWN
+ __IGB_DOWN,
+ __IGB_PTP_TX_IN_PROGRESS,
};
enum igb_boards {
@@ -525,9 +529,7 @@ void igb_set_fw_version(struct igb_adapter *);
void igb_ptp_init(struct igb_adapter *adapter);
void igb_ptp_stop(struct igb_adapter *adapter);
void igb_ptp_reset(struct igb_adapter *adapter);
-void igb_ptp_tx_work(struct work_struct *work);
void igb_ptp_rx_hang(struct igb_adapter *adapter);
-void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter);
void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector, struct sk_buff *skb);
void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, unsigned char *va,
struct sk_buff *skb);
@@ -545,8 +547,8 @@ static inline void igb_ptp_rx_hwtstamp(struct igb_ring *rx_ring,
rx_ring->last_rx_timestamp = jiffies;
}
-int igb_ptp_hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr,
- int cmd);
+int igb_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr);
+int igb_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr);
#ifdef CONFIG_IGB_HWMON
void igb_sysfs_exit(struct igb_adapter *adapter);
int igb_sysfs_init(struct igb_adapter *adapter);
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index 1df02378de69..e5570acbeea8 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2013 Intel Corporation.
+ Copyright(c) 2007-2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
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.
+ this program; if not, see <http://www.gnu.org/licenses/>.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
@@ -2274,15 +2273,15 @@ static void igb_get_ethtool_stats(struct net_device *netdev,
ring = adapter->tx_ring[j];
do {
- start = u64_stats_fetch_begin_bh(&ring->tx_syncp);
+ start = u64_stats_fetch_begin_irq(&ring->tx_syncp);
data[i] = ring->tx_stats.packets;
data[i+1] = ring->tx_stats.bytes;
data[i+2] = ring->tx_stats.restart_queue;
- } while (u64_stats_fetch_retry_bh(&ring->tx_syncp, start));
+ } while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start));
do {
- start = u64_stats_fetch_begin_bh(&ring->tx_syncp2);
+ start = u64_stats_fetch_begin_irq(&ring->tx_syncp2);
restart2 = ring->tx_stats.restart_queue2;
- } while (u64_stats_fetch_retry_bh(&ring->tx_syncp2, start));
+ } while (u64_stats_fetch_retry_irq(&ring->tx_syncp2, start));
data[i+2] += restart2;
i += IGB_TX_QUEUE_STATS_LEN;
@@ -2290,13 +2289,13 @@ static void igb_get_ethtool_stats(struct net_device *netdev,
for (j = 0; j < adapter->num_rx_queues; j++) {
ring = adapter->rx_ring[j];
do {
- start = u64_stats_fetch_begin_bh(&ring->rx_syncp);
+ start = u64_stats_fetch_begin_irq(&ring->rx_syncp);
data[i] = ring->rx_stats.packets;
data[i+1] = ring->rx_stats.bytes;
data[i+2] = ring->rx_stats.drops;
data[i+3] = ring->rx_stats.csum_err;
data[i+4] = ring->rx_stats.alloc_failed;
- } while (u64_stats_fetch_retry_bh(&ring->rx_syncp, start));
+ } while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start));
i += IGB_RX_QUEUE_STATS_LEN;
}
spin_unlock(&adapter->stats64_lock);
@@ -2354,6 +2353,11 @@ static int igb_get_ts_info(struct net_device *dev,
{
struct igb_adapter *adapter = netdev_priv(dev);
+ if (adapter->ptp_clock)
+ info->phc_index = ptp_clock_index(adapter->ptp_clock);
+ else
+ info->phc_index = -1;
+
switch (adapter->hw.mac.type) {
case e1000_82575:
info->so_timestamping =
@@ -2375,11 +2379,6 @@ static int igb_get_ts_info(struct net_device *dev,
SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;
- if (adapter->ptp_clock)
- info->phc_index = ptp_clock_index(adapter->ptp_clock);
- else
- info->phc_index = -1;
-
info->tx_types =
(1 << HWTSTAMP_TX_OFF) |
(1 << HWTSTAMP_TX_ON);
@@ -2588,7 +2587,7 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- u32 ipcnfg, eeer, ret_val;
+ u32 ret_val;
u16 phy_data;
if ((hw->mac.type < e1000_i350) ||
@@ -2597,16 +2596,25 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
edata->supported = (SUPPORTED_1000baseT_Full |
SUPPORTED_100baseT_Full);
+ if (!hw->dev_spec._82575.eee_disable)
+ edata->advertised =
+ mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert);
+
+ /* The IPCNFG and EEER registers are not supported on I354. */
+ if (hw->mac.type == e1000_i354) {
+ igb_get_eee_status_i354(hw, (bool *)&edata->eee_active);
+ } else {
+ u32 eeer;
- ipcnfg = rd32(E1000_IPCNFG);
- eeer = rd32(E1000_EEER);
+ eeer = rd32(E1000_EEER);
- /* EEE status on negotiated link */
- if (ipcnfg & E1000_IPCNFG_EEE_1G_AN)
- edata->advertised = ADVERTISED_1000baseT_Full;
+ /* EEE status on negotiated link */
+ if (eeer & E1000_EEER_EEE_NEG)
+ edata->eee_active = true;
- if (ipcnfg & E1000_IPCNFG_EEE_100M_AN)
- edata->advertised |= ADVERTISED_100baseT_Full;
+ if (eeer & E1000_EEER_TX_LPI_EN)
+ edata->tx_lpi_enabled = true;
+ }
/* EEE Link Partner Advertised */
switch (hw->mac.type) {
@@ -2617,8 +2625,8 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
return -ENODATA;
edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data);
-
break;
+ case e1000_i354:
case e1000_i210:
case e1000_i211:
ret_val = igb_read_xmdio_reg(hw, E1000_EEE_LP_ADV_ADDR_I210,
@@ -2634,12 +2642,10 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
break;
}
- if (eeer & E1000_EEER_EEE_NEG)
- edata->eee_active = true;
-
edata->eee_enabled = !hw->dev_spec._82575.eee_disable;
- if (eeer & E1000_EEER_TX_LPI_EN)
+ if ((hw->mac.type == e1000_i354) &&
+ (edata->eee_enabled))
edata->tx_lpi_enabled = true;
/* Report correct negotiated EEE status for devices that
@@ -2687,9 +2693,10 @@ static int igb_set_eee(struct net_device *netdev,
return -EINVAL;
}
- if (eee_curr.advertised != edata->advertised) {
+ if (edata->advertised &
+ ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL)) {
dev_err(&adapter->pdev->dev,
- "Setting EEE Advertisement is not supported\n");
+ "EEE Advertisement supports only 100Tx and or 100T full duplex\n");
return -EINVAL;
}
@@ -2699,9 +2706,14 @@ static int igb_set_eee(struct net_device *netdev,
return -EINVAL;
}
+ adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised);
if (hw->dev_spec._82575.eee_disable != !edata->eee_enabled) {
hw->dev_spec._82575.eee_disable = !edata->eee_enabled;
- igb_set_eee_i350(hw);
+ adapter->flags |= IGB_FLAG_EEE;
+ if (hw->mac.type == e1000_i350)
+ igb_set_eee_i350(hw);
+ else
+ igb_set_eee_i354(hw);
/* reset link */
if (netif_running(netdev))
@@ -2779,9 +2791,11 @@ static int igb_get_module_eeprom(struct net_device *netdev,
/* Read EEPROM block, SFF-8079/SFF-8472, word at a time */
for (i = 0; i < last_word - first_word + 1; i++) {
status = igb_read_phy_reg_i2c(hw, first_word + i, &dataword[i]);
- if (status != E1000_SUCCESS)
+ if (status != E1000_SUCCESS) {
/* Error occurred while reading module */
+ kfree(dataword);
return -EIO;
+ }
be16_to_cpus(&dataword[i]);
}
diff --git a/drivers/net/ethernet/intel/igb/igb_hwmon.c b/drivers/net/ethernet/intel/igb/igb_hwmon.c
index e0af5bc61613..8333f67acf96 100644
--- a/drivers/net/ethernet/intel/igb/igb_hwmon.c
+++ b/drivers/net/ethernet/intel/igb/igb_hwmon.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2013 Intel Corporation.
+ Copyright(c) 2007-2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
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.
+ this program; if not, see <http://www.gnu.org/licenses/>.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 46d31a49f5ea..30198185d19a 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2013 Intel Corporation.
+ Copyright(c) 2007-2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
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.
+ this program; if not, see <http://www.gnu.org/licenses/>.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
@@ -70,7 +69,7 @@ char igb_driver_version[] = DRV_VERSION;
static const char igb_driver_string[] =
"Intel(R) Gigabit Ethernet Network Driver";
static const char igb_copyright[] =
- "Copyright (c) 2007-2013 Intel Corporation.";
+ "Copyright (c) 2007-2014 Intel Corporation.";
static const struct e1000_info *igb_info_tbl[] = {
[board_82575] = &e1000_82575_info,
@@ -752,6 +751,28 @@ static void igb_cache_ring_register(struct igb_adapter *adapter)
}
}
+u32 igb_rd32(struct e1000_hw *hw, u32 reg)
+{
+ struct igb_adapter *igb = container_of(hw, struct igb_adapter, hw);
+ u8 __iomem *hw_addr = ACCESS_ONCE(hw->hw_addr);
+ u32 value = 0;
+
+ if (E1000_REMOVED(hw_addr))
+ return ~value;
+
+ value = readl(&hw_addr[reg]);
+
+ /* reads should not return all F's */
+ if (!(~value) && (!reg || !(~readl(hw_addr)))) {
+ struct net_device *netdev = igb->netdev;
+ hw->hw_addr = NULL;
+ netif_device_detach(netdev);
+ netdev_err(netdev, "PCIe link lost, device now detached\n");
+ }
+
+ return value;
+}
+
/**
* igb_write_ivar - configure ivar for given MSI-X vector
* @hw: pointer to the HW structure
@@ -1014,6 +1035,12 @@ static void igb_reset_q_vector(struct igb_adapter *adapter, int v_idx)
{
struct igb_q_vector *q_vector = adapter->q_vector[v_idx];
+ /* Coming from igb_set_interrupt_capability, the vectors are not yet
+ * allocated. So, q_vector is NULL so we should stop here.
+ */
+ if (!q_vector)
+ return;
+
if (q_vector->tx.ring)
adapter->tx_ring[q_vector->tx.ring->queue_index] = NULL;
@@ -1111,16 +1138,18 @@ static void igb_set_interrupt_capability(struct igb_adapter *adapter, bool msix)
for (i = 0; i < numvecs; i++)
adapter->msix_entries[i].entry = i;
- err = pci_enable_msix(adapter->pdev,
- adapter->msix_entries,
- numvecs);
- if (err == 0)
+ err = pci_enable_msix_range(adapter->pdev,
+ adapter->msix_entries,
+ numvecs,
+ numvecs);
+ if (err > 0)
return;
igb_reset_interrupt_capability(adapter);
/* If we can't do MSI-X, try MSI */
msi_only:
+ adapter->flags &= ~IGB_FLAG_HAS_MSIX;
#ifdef CONFIG_PCI_IOV
/* disable SR-IOV for non MSI-X configurations */
if (adapter->vf_data) {
@@ -1726,6 +1755,10 @@ int igb_up(struct igb_adapter *adapter)
hw->mac.get_link_status = 1;
schedule_work(&adapter->watchdog_task);
+ if ((adapter->flags & IGB_FLAG_EEE) &&
+ (!hw->dev_spec._82575.eee_disable))
+ adapter->eee_advert = MDIO_EEE_100TX | MDIO_EEE_1000T;
+
return 0;
}
@@ -1974,6 +2007,21 @@ void igb_reset(struct igb_adapter *adapter)
}
}
#endif
+ /* Re-establish EEE setting */
+ if (hw->phy.media_type == e1000_media_type_copper) {
+ switch (mac->type) {
+ case e1000_i350:
+ case e1000_i210:
+ case e1000_i211:
+ igb_set_eee_i350(hw);
+ break;
+ case e1000_i354:
+ igb_set_eee_i354(hw);
+ break;
+ default:
+ break;
+ }
+ }
if (!netif_running(adapter->netdev))
igb_power_down_link(adapter);
@@ -2560,23 +2608,36 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
(adapter->flags & IGB_FLAG_HAS_MSIX) ? "MSI-X" :
(adapter->flags & IGB_FLAG_HAS_MSI) ? "MSI" : "legacy",
adapter->num_rx_queues, adapter->num_tx_queues);
- switch (hw->mac.type) {
- case e1000_i350:
- case e1000_i210:
- case e1000_i211:
- igb_set_eee_i350(hw);
- break;
- case e1000_i354:
- if (hw->phy.media_type == e1000_media_type_copper) {
+ if (hw->phy.media_type == e1000_media_type_copper) {
+ switch (hw->mac.type) {
+ case e1000_i350:
+ case e1000_i210:
+ case e1000_i211:
+ /* Enable EEE for internal copper PHY devices */
+ err = igb_set_eee_i350(hw);
+ if ((!err) &&
+ (!hw->dev_spec._82575.eee_disable)) {
+ adapter->eee_advert =
+ MDIO_EEE_100TX | MDIO_EEE_1000T;
+ adapter->flags |= IGB_FLAG_EEE;
+ }
+ break;
+ case e1000_i354:
if ((rd32(E1000_CTRL_EXT) &
- E1000_CTRL_EXT_LINK_MODE_SGMII))
- igb_set_eee_i354(hw);
+ E1000_CTRL_EXT_LINK_MODE_SGMII)) {
+ err = igb_set_eee_i354(hw);
+ if ((!err) &&
+ (!hw->dev_spec._82575.eee_disable)) {
+ adapter->eee_advert =
+ MDIO_EEE_100TX | MDIO_EEE_1000T;
+ adapter->flags |= IGB_FLAG_EEE;
+ }
+ }
+ break;
+ default:
+ break;
}
- break;
- default:
- break;
}
-
pm_runtime_put_noidle(&pdev->dev);
return 0;
@@ -2591,7 +2652,7 @@ err_eeprom:
iounmap(hw->flash_address);
err_sw_init:
igb_clear_interrupt_scheme(adapter);
- iounmap(hw->hw_addr);
+ pci_iounmap(pdev, hw->hw_addr);
err_ioremap:
free_netdev(netdev);
err_alloc_etherdev:
@@ -2758,7 +2819,7 @@ static void igb_remove(struct pci_dev *pdev)
igb_disable_sriov(pdev);
#endif
- iounmap(hw->hw_addr);
+ pci_iounmap(pdev, hw->hw_addr);
if (hw->flash_address)
iounmap(hw->flash_address);
pci_release_selected_regions(pdev,
@@ -3510,6 +3571,13 @@ static inline void igb_set_vmolr(struct igb_adapter *adapter,
vmolr = rd32(E1000_VMOLR(vfn));
vmolr |= E1000_VMOLR_STRVLAN; /* Strip vlan tags */
+ if (hw->mac.type == e1000_i350) {
+ u32 dvmolr;
+
+ dvmolr = rd32(E1000_DVMOLR(vfn));
+ dvmolr |= E1000_DVMOLR_STRVLAN;
+ wr32(E1000_DVMOLR(vfn), dvmolr);
+ }
if (aupe)
vmolr |= E1000_VMOLR_AUPE; /* Accept untagged packets */
else
@@ -4158,6 +4226,15 @@ static void igb_watchdog_task(struct work_struct *work)
(ctrl & E1000_CTRL_RFCE) ? "RX" :
(ctrl & E1000_CTRL_TFCE) ? "TX" : "None");
+ /* disable EEE if enabled */
+ if ((adapter->flags & IGB_FLAG_EEE) &&
+ (adapter->link_duplex == HALF_DUPLEX)) {
+ dev_info(&adapter->pdev->dev,
+ "EEE Disabled: unsupported at half duplex. Re-enable using ethtool when at full duplex.\n");
+ adapter->hw.dev_spec._82575.eee_disable = true;
+ adapter->flags &= ~IGB_FLAG_EEE;
+ }
+
/* check if SmartSpeed worked */
igb_check_downshift(hw);
if (phy->speed_downgraded)
@@ -4306,8 +4383,7 @@ enum latency_range {
* were determined based on theoretical maximum wire speed and testing
* data, in order to minimize response time while increasing bulk
* throughput.
- * This functionality is controlled by the InterruptThrottleRate module
- * parameter (see igb_param.c)
+ * This functionality is controlled by ethtool's coalescing settings.
* NOTE: This function is called only when operating in a multiqueue
* receive environment.
**/
@@ -4381,8 +4457,7 @@ clear_counts:
* based on theoretical maximum wire speed and thresholds were set based
* on testing data as well as attempting to minimize response time
* while increasing bulk throughput.
- * this functionality is controlled by the InterruptThrottleRate module
- * parameter (see igb_param.c)
+ * This functionality is controlled by ethtool's coalescing settings.
* NOTE: These calculations are only valid when operating in a single-
* queue environment.
**/
@@ -4546,7 +4621,7 @@ static int igb_tso(struct igb_ring *tx_ring,
/* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
type_tucmd = E1000_ADVTXD_TUCMD_L4T_TCP;
- if (first->protocol == __constant_htons(ETH_P_IP)) {
+ if (first->protocol == htons(ETH_P_IP)) {
struct iphdr *iph = ip_hdr(skb);
iph->tot_len = 0;
iph->check = 0;
@@ -4602,12 +4677,12 @@ static void igb_tx_csum(struct igb_ring *tx_ring, struct igb_tx_buffer *first)
} else {
u8 l4_hdr = 0;
switch (first->protocol) {
- case __constant_htons(ETH_P_IP):
+ case htons(ETH_P_IP):
vlan_macip_lens |= skb_network_header_len(skb);
type_tucmd |= E1000_ADVTXD_TUCMD_IPV4;
l4_hdr = ip_hdr(skb)->protocol;
break;
- case __constant_htons(ETH_P_IPV6):
+ case htons(ETH_P_IPV6):
vlan_macip_lens |= skb_network_header_len(skb);
l4_hdr = ipv6_hdr(skb)->nexthdr;
break;
@@ -4905,12 +4980,11 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
first->bytecount = skb->len;
first->gso_segs = 1;
- skb_tx_timestamp(skb);
-
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
struct igb_adapter *adapter = netdev_priv(tx_ring->netdev);
- if (!(adapter->ptp_tx_skb)) {
+ if (!test_and_set_bit_lock(__IGB_PTP_TX_IN_PROGRESS,
+ &adapter->state)) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_flags |= IGB_TX_FLAGS_TSTAMP;
@@ -4921,6 +4995,8 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
}
}
+ skb_tx_timestamp(skb);
+
if (vlan_tx_tag_present(skb)) {
tx_flags |= IGB_TX_FLAGS_VLAN;
tx_flags |= (vlan_tx_tag_get(skb) << IGB_TX_FLAGS_VLAN_SHIFT);
@@ -5127,10 +5203,10 @@ void igb_update_stats(struct igb_adapter *adapter,
}
do {
- start = u64_stats_fetch_begin_bh(&ring->rx_syncp);
+ start = u64_stats_fetch_begin_irq(&ring->rx_syncp);
_bytes = ring->rx_stats.bytes;
_packets = ring->rx_stats.packets;
- } while (u64_stats_fetch_retry_bh(&ring->rx_syncp, start));
+ } while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start));
bytes += _bytes;
packets += _packets;
}
@@ -5143,10 +5219,10 @@ void igb_update_stats(struct igb_adapter *adapter,
for (i = 0; i < adapter->num_tx_queues; i++) {
struct igb_ring *ring = adapter->tx_ring[i];
do {
- start = u64_stats_fetch_begin_bh(&ring->tx_syncp);
+ start = u64_stats_fetch_begin_irq(&ring->tx_syncp);
_bytes = ring->tx_stats.bytes;
_packets = ring->tx_stats.packets;
- } while (u64_stats_fetch_retry_bh(&ring->tx_syncp, start));
+ } while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start));
bytes += _bytes;
packets += _packets;
}
@@ -6620,7 +6696,9 @@ static inline void igb_rx_hash(struct igb_ring *ring,
struct sk_buff *skb)
{
if (ring->netdev->features & NETIF_F_RXHASH)
- skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
+ skb_set_hash(skb,
+ le32_to_cpu(rx_desc->wb.lower.hi_dword.rss),
+ PKT_HASH_TYPE_L3);
}
/**
@@ -6690,7 +6768,7 @@ static unsigned int igb_get_headlen(unsigned char *data,
hdr.network += ETH_HLEN;
/* handle any vlan tag if present */
- if (protocol == __constant_htons(ETH_P_8021Q)) {
+ if (protocol == htons(ETH_P_8021Q)) {
if ((hdr.network - data) > (max_len - VLAN_HLEN))
return max_len;
@@ -6699,7 +6777,7 @@ static unsigned int igb_get_headlen(unsigned char *data,
}
/* handle L3 protocols */
- if (protocol == __constant_htons(ETH_P_IP)) {
+ if (protocol == htons(ETH_P_IP)) {
if ((hdr.network - data) > (max_len - sizeof(struct iphdr)))
return max_len;
@@ -6713,7 +6791,7 @@ static unsigned int igb_get_headlen(unsigned char *data,
/* record next protocol if header is present */
if (!(hdr.ipv4->frag_off & htons(IP_OFFSET)))
nexthdr = hdr.ipv4->protocol;
- } else if (protocol == __constant_htons(ETH_P_IPV6)) {
+ } else if (protocol == htons(ETH_P_IPV6)) {
if ((hdr.network - data) > (max_len - sizeof(struct ipv6hdr)))
return max_len;
@@ -6903,7 +6981,7 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
unsigned int total_bytes = 0, total_packets = 0;
u16 cleaned_count = igb_desc_unused(rx_ring);
- do {
+ while (likely(total_packets < budget)) {
union e1000_adv_rx_desc *rx_desc;
/* return some buffers to hardware, one at a time is too slow */
@@ -6955,7 +7033,7 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
/* update budget accounting */
total_packets++;
- } while (likely(total_packets < budget));
+ }
/* place incomplete frames back on ring for completion */
rx_ring->skb = skb;
@@ -7114,8 +7192,10 @@ static int igb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
case SIOCGMIIREG:
case SIOCSMIIREG:
return igb_mii_ioctl(netdev, ifr, cmd);
+ case SIOCGHWTSTAMP:
+ return igb_ptp_get_ts_config(netdev, ifr);
case SIOCSHWTSTAMP:
- return igb_ptp_hwtstamp_ioctl(netdev, ifr, cmd);
+ return igb_ptp_set_ts_config(netdev, ifr);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index 5a54e3dc535d..2cca8fd5e574 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -12,9 +12,8 @@
* 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.
+ * 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>
#include <linux/device.h>
@@ -75,6 +74,8 @@
#define INCVALUE_82576 (16 << IGB_82576_TSYNC_SHIFT)
#define IGB_NBITS_82580 40
+static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter);
+
/* SYSTIM read access for the 82576 */
static cycle_t igb_ptp_read_82576(const struct cyclecounter *cc)
{
@@ -372,7 +373,7 @@ static int igb_ptp_enable(struct ptp_clock_info *ptp,
* This work function polls the TSYNCTXCTL valid bit to determine when a
* timestamp has been taken for the current stored skb.
**/
-void igb_ptp_tx_work(struct work_struct *work)
+static void igb_ptp_tx_work(struct work_struct *work)
{
struct igb_adapter *adapter = container_of(work, struct igb_adapter,
ptp_tx_work);
@@ -386,6 +387,7 @@ void igb_ptp_tx_work(struct work_struct *work)
IGB_PTP_TX_TIMEOUT)) {
dev_kfree_skb_any(adapter->ptp_tx_skb);
adapter->ptp_tx_skb = NULL;
+ clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
adapter->tx_hwtstamp_timeouts++;
dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang");
return;
@@ -466,7 +468,7 @@ void igb_ptp_rx_hang(struct igb_adapter *adapter)
* available, then it must have been for this skb here because we only
* allow only one such packet into the queue.
**/
-void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)
+static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
struct skb_shared_hwtstamps shhwtstamps;
@@ -479,6 +481,7 @@ void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)
skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps);
dev_kfree_skb_any(adapter->ptp_tx_skb);
adapter->ptp_tx_skb = NULL;
+ clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
}
/**
@@ -540,10 +543,26 @@ void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector,
}
/**
- * igb_ptp_hwtstamp_ioctl - control hardware time stamping
+ * igb_ptp_get_ts_config - get hardware time stamping config
+ * @netdev:
+ * @ifreq:
+ *
+ * Get the hwtstamp_config settings to return to the user. Rather than attempt
+ * to deconstruct the settings from the registers, just return a shadow copy
+ * of the last known settings.
+ **/
+int igb_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr)
+{
+ struct igb_adapter *adapter = netdev_priv(netdev);
+ struct hwtstamp_config *config = &adapter->tstamp_config;
+
+ return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ?
+ -EFAULT : 0;
+}
+/**
+ * igb_ptp_set_ts_config - control hardware time stamping
* @netdev:
* @ifreq:
- * @cmd:
*
* Outgoing time stamping can be enabled and disabled. Play nice and
* disable it when requested, although it shouldn't case any overhead
@@ -557,12 +576,11 @@ void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector,
* not supported, with the exception of "all V2 events regardless of
* level 2 or 4".
**/
-int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
- struct ifreq *ifr, int cmd)
+int igb_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- struct hwtstamp_config config;
+ struct hwtstamp_config *config = &adapter->tstamp_config;
u32 tsync_tx_ctl = E1000_TSYNCTXCTL_ENABLED;
u32 tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
u32 tsync_rx_cfg = 0;
@@ -570,14 +588,14 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
bool is_l2 = false;
u32 regval;
- if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+ if (copy_from_user(config, ifr->ifr_data, sizeof(*config)))
return -EFAULT;
/* reserved for future extensions */
- if (config.flags)
+ if (config->flags)
return -EINVAL;
- switch (config.tx_type) {
+ switch (config->tx_type) {
case HWTSTAMP_TX_OFF:
tsync_tx_ctl = 0;
case HWTSTAMP_TX_ON:
@@ -586,7 +604,7 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
return -ERANGE;
}
- switch (config.rx_filter) {
+ switch (config->rx_filter) {
case HWTSTAMP_FILTER_NONE:
tsync_rx_ctl = 0;
break;
@@ -610,7 +628,7 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_EVENT_V2;
- config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+ config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
is_l2 = true;
is_l4 = true;
break;
@@ -621,12 +639,12 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
*/
if (hw->mac.type != e1000_82576) {
tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL;
- config.rx_filter = HWTSTAMP_FILTER_ALL;
+ config->rx_filter = HWTSTAMP_FILTER_ALL;
break;
}
/* fall through */
default:
- config.rx_filter = HWTSTAMP_FILTER_NONE;
+ config->rx_filter = HWTSTAMP_FILTER_NONE;
return -ERANGE;
}
@@ -643,7 +661,7 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
if ((hw->mac.type >= e1000_82580) && tsync_rx_ctl) {
tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL;
- config.rx_filter = HWTSTAMP_FILTER_ALL;
+ config->rx_filter = HWTSTAMP_FILTER_ALL;
is_l2 = true;
is_l4 = true;
@@ -707,7 +725,7 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
regval = rd32(E1000_RXSTMPL);
regval = rd32(E1000_RXSTMPH);
- return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
+ return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ?
-EFAULT : 0;
}
@@ -798,7 +816,7 @@ void igb_ptp_init(struct igb_adapter *adapter)
/* Initialize the time sync interrupts for devices that support it. */
if (hw->mac.type >= e1000_82580) {
- wr32(E1000_TSIM, E1000_TSIM_TXTS);
+ wr32(E1000_TSIM, TSYNC_INTERRUPTS);
wr32(E1000_IMS, E1000_IMS_TS);
}
@@ -841,6 +859,7 @@ void igb_ptp_stop(struct igb_adapter *adapter)
if (adapter->ptp_tx_skb) {
dev_kfree_skb_any(adapter->ptp_tx_skb);
adapter->ptp_tx_skb = NULL;
+ clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
}
if (adapter->ptp_clock) {
@@ -864,6 +883,9 @@ void igb_ptp_reset(struct igb_adapter *adapter)
if (!(adapter->flags & IGB_FLAG_PTP))
return;
+ /* reset the tstamp_config */
+ memset(&adapter->tstamp_config, 0, sizeof(adapter->tstamp_config));
+
switch (adapter->hw.mac.type) {
case e1000_82576:
/* Dial the nominal frequency. */
@@ -876,7 +898,7 @@ void igb_ptp_reset(struct igb_adapter *adapter)
case e1000_i211:
/* Enable the timer functions and interrupts. */
wr32(E1000_TSAUXC, 0x0);
- wr32(E1000_TSIM, E1000_TSIM_TXTS);
+ wr32(E1000_TSIM, TSYNC_INTERRUPTS);
wr32(E1000_IMS, E1000_IMS_TS);
break;
default:
diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c
index 675435fc2e53..b7ab03a2f28f 100644
--- a/drivers/net/ethernet/intel/igbvf/netdev.c
+++ b/drivers/net/ethernet/intel/igbvf/netdev.c
@@ -1043,11 +1043,11 @@ static void igbvf_set_interrupt_capability(struct igbvf_adapter *adapter)
for (i = 0; i < 3; i++)
adapter->msix_entries[i].entry = i;
- err = pci_enable_msix(adapter->pdev,
- adapter->msix_entries, 3);
+ err = pci_enable_msix_range(adapter->pdev,
+ adapter->msix_entries, 3, 3);
}
- if (err) {
+ if (err < 0) {
/* MSI-X failed */
dev_err(&adapter->pdev->dev,
"Failed to initialize MSI-X interrupts.\n");
@@ -2014,12 +2014,12 @@ static inline bool igbvf_tx_csum(struct igbvf_adapter *adapter,
if (skb->ip_summed == CHECKSUM_PARTIAL) {
switch (skb->protocol) {
- case __constant_htons(ETH_P_IP):
+ case htons(ETH_P_IP):
tu_cmd |= E1000_ADVTXD_TUCMD_IPV4;
if (ip_hdr(skb)->protocol == IPPROTO_TCP)
tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
break;
- case __constant_htons(ETH_P_IPV6):
+ case htons(ETH_P_IPV6):
if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
break;
diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c
index 57e390cbe6d0..f42c201f727f 100644
--- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c
+++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c
@@ -1521,12 +1521,12 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
int tso;
if (test_bit(__IXGB_DOWN, &adapter->flags)) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
if (skb->len <= 0) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -1543,7 +1543,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
tso = ixgb_tso(adapter, skb);
if (tso < 0) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 0186ea2969fe..55c53a1cbb62 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
@@ -765,6 +766,7 @@ struct ixgbe_adapter {
struct ptp_clock_info ptp_caps;
struct work_struct ptp_tx_work;
struct sk_buff *ptp_tx_skb;
+ struct hwtstamp_config tstamp_config;
unsigned long ptp_tx_start;
unsigned long last_overflow_check;
unsigned long last_rx_ptp_check;
@@ -806,10 +808,12 @@ enum ixgbe_state_t {
__IXGBE_TESTING,
__IXGBE_RESETTING,
__IXGBE_DOWN,
+ __IXGBE_DISABLED,
__IXGBE_REMOVING,
__IXGBE_SERVICE_SCHED,
__IXGBE_IN_SFP_INIT,
__IXGBE_PTP_RUNNING,
+ __IXGBE_PTP_TX_IN_PROGRESS,
};
struct ixgbe_cb {
@@ -884,7 +888,6 @@ s32 ixgbe_fdir_erase_perfect_filter_82599(struct ixgbe_hw *hw,
u16 soft_id);
void ixgbe_atr_compute_perfect_hash_82599(union ixgbe_atr_input *input,
union ixgbe_atr_input *mask);
-bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw);
void ixgbe_set_rx_mode(struct net_device *netdev);
#ifdef CONFIG_IXGBE_DCB
void ixgbe_set_rx_drop_en(struct ixgbe_adapter *adapter);
@@ -958,8 +961,8 @@ static inline void ixgbe_ptp_rx_hwtstamp(struct ixgbe_ring *rx_ring,
rx_ring->last_rx_timestamp = jiffies;
}
-int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter, struct ifreq *ifr,
- int cmd);
+int ixgbe_ptp_set_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr);
+int ixgbe_ptp_get_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr);
void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter);
void ixgbe_ptp_reset(struct ixgbe_adapter *adapter);
void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter, u32 eicr);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
index a26f3fee4f35..4c78ea8946c1 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
+ Copyright(c) 1999 - 2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
@@ -57,10 +58,12 @@ static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset,
**/
static void ixgbe_set_pcie_completion_timeout(struct ixgbe_hw *hw)
{
- struct ixgbe_adapter *adapter = hw->back;
u32 gcr = IXGBE_READ_REG(hw, IXGBE_GCR);
u16 pcie_devctl2;
+ if (ixgbe_removed(hw->hw_addr))
+ return;
+
/* only take action if timeout value is defaulted to 0 */
if (gcr & IXGBE_GCR_CMPL_TMOUT_MASK)
goto out;
@@ -79,11 +82,9 @@ static void ixgbe_set_pcie_completion_timeout(struct ixgbe_hw *hw)
* directly in order to set the completion timeout value for
* 16ms to 55ms
*/
- pci_read_config_word(adapter->pdev,
- IXGBE_PCI_DEVICE_CONTROL2, &pcie_devctl2);
+ pcie_devctl2 = ixgbe_read_pci_cfg_word(hw, IXGBE_PCI_DEVICE_CONTROL2);
pcie_devctl2 |= IXGBE_PCI_DEVICE_CONTROL2_16ms;
- pci_write_config_word(adapter->pdev,
- IXGBE_PCI_DEVICE_CONTROL2, pcie_devctl2);
+ ixgbe_write_pci_cfg_word(hw, IXGBE_PCI_DEVICE_CONTROL2, pcie_devctl2);
out:
/* disable completion timeout resend */
gcr &= ~IXGBE_GCR_CMPL_TMOUT_RESEND;
@@ -100,6 +101,7 @@ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw)
mac->mcft_size = IXGBE_82598_MC_TBL_SIZE;
mac->vft_size = IXGBE_82598_VFT_TBL_SIZE;
mac->num_rar_entries = IXGBE_82598_RAR_ENTRIES;
+ mac->rx_pb_size = IXGBE_82598_RX_PB_SIZE;
mac->max_rx_queues = IXGBE_82598_MAX_RX_QUEUES;
mac->max_tx_queues = IXGBE_82598_MAX_TX_QUEUES;
mac->max_msix_vectors = ixgbe_get_pcie_msix_count_generic(hw);
@@ -201,8 +203,6 @@ static s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw)
IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(i), regval);
}
- hw->mac.rx_pb_size = IXGBE_82598_RX_PB_SIZE;
-
/* set the completion timeout for interface */
if (ret_val == 0)
ixgbe_set_pcie_completion_timeout(hw);
@@ -1237,14 +1237,14 @@ static void ixgbe_set_lan_id_multi_port_pcie_82598(struct ixgbe_hw *hw)
}
/**
- * ixgbe_set_rxpba_82598 - Configure packet buffers
+ * ixgbe_set_rxpba_82598 - Initialize RX packet buffer
* @hw: pointer to hardware structure
- * @dcb_config: pointer to ixgbe_dcb_config structure
- *
- * Configure packet buffers.
- */
-static void ixgbe_set_rxpba_82598(struct ixgbe_hw *hw, int num_pb, u32 headroom,
- int strategy)
+ * @num_pb: number of packet buffers to allocate
+ * @headroom: reserve n KB of headroom
+ * @strategy: packet buffer allocation strategy
+ **/
+static void ixgbe_set_rxpba_82598(struct ixgbe_hw *hw, int num_pb,
+ u32 headroom, int strategy)
{
u32 rxpktsize = IXGBE_RXPBSIZE_64KB;
u8 i = 0;
@@ -1315,7 +1315,8 @@ static struct ixgbe_mac_operations mac_ops_82598 = {
.release_swfw_sync = &ixgbe_release_swfw_sync,
.get_thermal_sensor_data = NULL,
.init_thermal_sensor_thresh = NULL,
- .mng_fw_enabled = NULL,
+ .prot_autoc_read = &prot_autoc_read_generic,
+ .prot_autoc_write = &prot_autoc_write_generic,
};
static struct ixgbe_eeprom_operations eeprom_ops_82598 = {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
index edda6814108c..f32b3dd1ba8e 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
+ Copyright(c) 1999 - 2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
@@ -63,8 +64,10 @@ static s32 ixgbe_read_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset,
u8 dev_addr, u8 *data);
static s32 ixgbe_write_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset,
u8 dev_addr, u8 data);
+static s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw);
+static bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw);
-static bool ixgbe_mng_enabled(struct ixgbe_hw *hw)
+bool ixgbe_mng_enabled(struct ixgbe_hw *hw)
{
u32 fwsm, manc, factps;
@@ -91,7 +94,7 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw)
* and MNG not enabled
*/
if ((mac->ops.get_media_type(hw) == ixgbe_media_type_fiber) &&
- !hw->mng_fw_enabled) {
+ !ixgbe_mng_enabled(hw)) {
mac->ops.disable_tx_laser =
&ixgbe_disable_tx_laser_multispeed_fiber;
mac->ops.enable_tx_laser =
@@ -122,7 +125,6 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw)
{
s32 ret_val = 0;
u16 list_offset, data_offset, data_value;
- bool got_lock = false;
if (hw->phy.sfp_type != ixgbe_sfp_type_unknown) {
ixgbe_init_mac_link_ops_82599(hw);
@@ -160,30 +162,10 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw)
usleep_range(hw->eeprom.semaphore_delay * 1000,
hw->eeprom.semaphore_delay * 2000);
- /* Need SW/FW semaphore around AUTOC writes if LESM on,
- * likewise reset_pipeline requires lock as it also writes
- * AUTOC.
- */
- if (ixgbe_verify_lesm_fw_enabled_82599(hw)) {
- ret_val = hw->mac.ops.acquire_swfw_sync(hw,
- IXGBE_GSSR_MAC_CSR_SM);
- if (ret_val)
- goto setup_sfp_out;
-
- got_lock = true;
- }
-
/* Restart DSP and set SFI mode */
- IXGBE_WRITE_REG(hw, IXGBE_AUTOC, ((hw->mac.orig_autoc) |
- IXGBE_AUTOC_LMS_10G_SERIAL));
- hw->mac.cached_autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
- ret_val = ixgbe_reset_pipeline_82599(hw);
-
- if (got_lock) {
- hw->mac.ops.release_swfw_sync(hw,
- IXGBE_GSSR_MAC_CSR_SM);
- got_lock = false;
- }
+ ret_val = hw->mac.ops.prot_autoc_write(hw,
+ hw->mac.orig_autoc | IXGBE_AUTOC_LMS_10G_SERIAL,
+ false);
if (ret_val) {
hw_dbg(hw, " sfp module setup not complete\n");
@@ -207,6 +189,81 @@ setup_sfp_err:
return IXGBE_ERR_SFP_SETUP_NOT_COMPLETE;
}
+/**
+ * prot_autoc_read_82599 - Hides MAC differences needed for AUTOC read
+ * @hw: pointer to hardware structure
+ * @locked: Return the if we locked for this read.
+ * @reg_val: Value we read from AUTOC
+ *
+ * For this part (82599) we need to wrap read-modify-writes with a possible
+ * FW/SW lock. It is assumed this lock will be freed with the next
+ * prot_autoc_write_82599(). Note, that locked can only be true in cases
+ * where this function doesn't return an error.
+ **/
+static s32 prot_autoc_read_82599(struct ixgbe_hw *hw, bool *locked,
+ u32 *reg_val)
+{
+ s32 ret_val;
+
+ *locked = false;
+ /* If LESM is on then we need to hold the SW/FW semaphore. */
+ if (ixgbe_verify_lesm_fw_enabled_82599(hw)) {
+ ret_val = hw->mac.ops.acquire_swfw_sync(hw,
+ IXGBE_GSSR_MAC_CSR_SM);
+ if (ret_val)
+ return IXGBE_ERR_SWFW_SYNC;
+
+ *locked = true;
+ }
+
+ *reg_val = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+ return 0;
+}
+
+/**
+ * prot_autoc_write_82599 - Hides MAC differences needed for AUTOC write
+ * @hw: pointer to hardware structure
+ * @reg_val: value to write to AUTOC
+ * @locked: bool to indicate whether the SW/FW lock was already taken by
+ * previous proc_autoc_read_82599.
+ *
+ * This part (82599) may need to hold a the SW/FW lock around all writes to
+ * AUTOC. Likewise after a write we need to do a pipeline reset.
+ **/
+static s32 prot_autoc_write_82599(struct ixgbe_hw *hw, u32 autoc, bool locked)
+{
+ s32 ret_val = 0;
+
+ /* Blocked by MNG FW so bail */
+ if (ixgbe_check_reset_blocked(hw))
+ goto out;
+
+ /* We only need to get the lock if:
+ * - We didn't do it already (in the read part of a read-modify-write)
+ * - LESM is enabled.
+ */
+ if (!locked && ixgbe_verify_lesm_fw_enabled_82599(hw)) {
+ ret_val = hw->mac.ops.acquire_swfw_sync(hw,
+ IXGBE_GSSR_MAC_CSR_SM);
+ if (ret_val)
+ return IXGBE_ERR_SWFW_SYNC;
+
+ locked = true;
+ }
+
+ IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc);
+ ret_val = ixgbe_reset_pipeline_82599(hw);
+
+out:
+ /* Free the SW/FW semaphore as we either grabbed it here or
+ * already had it when this function was called.
+ */
+ if (locked)
+ hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM);
+
+ return ret_val;
+}
+
static s32 ixgbe_get_invariants_82599(struct ixgbe_hw *hw)
{
struct ixgbe_mac_info *mac = &hw->mac;
@@ -216,6 +273,7 @@ static s32 ixgbe_get_invariants_82599(struct ixgbe_hw *hw)
mac->mcft_size = IXGBE_82599_MC_TBL_SIZE;
mac->vft_size = IXGBE_82599_VFT_TBL_SIZE;
mac->num_rar_entries = IXGBE_82599_RAR_ENTRIES;
+ mac->rx_pb_size = IXGBE_82599_RX_PB_SIZE;
mac->max_rx_queues = IXGBE_82599_MAX_RX_QUEUES;
mac->max_tx_queues = IXGBE_82599_MAX_TX_QUEUES;
mac->max_msix_vectors = ixgbe_get_pcie_msix_count_generic(hw);
@@ -456,12 +514,20 @@ out:
*
* Disables link, should be called during D3 power down sequence.
*
- */
+ **/
static void ixgbe_stop_mac_link_on_d3_82599(struct ixgbe_hw *hw)
{
- u32 autoc2_reg;
+ u32 autoc2_reg, fwsm;
+ u16 ee_ctrl_2 = 0;
+
+ hw->eeprom.ops.read(hw, IXGBE_EEPROM_CTRL_2, &ee_ctrl_2);
- if (!hw->mng_fw_enabled && !hw->wol_enabled) {
+ /* Check to see if MNG FW could be enabled */
+ fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM);
+
+ if (((fwsm & IXGBE_FWSM_MODE_MASK) != IXGBE_FWSM_FW_MODE_PT) &&
+ !hw->wol_enabled &&
+ ee_ctrl_2 & IXGBE_EEPROM_CCD_BIT) {
autoc2_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
autoc2_reg |= IXGBE_AUTOC2_LINK_DISABLE_ON_D3_MASK;
IXGBE_WRITE_REG(hw, IXGBE_AUTOC2, autoc2_reg);
@@ -542,6 +608,10 @@ static void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
{
u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP);
+ /* Blocked by MNG FW so bail */
+ if (ixgbe_check_reset_blocked(hw))
+ return;
+
/* Disable tx laser; allow 100us to go dark per spec */
esdp_reg |= IXGBE_ESDP_SDP3;
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
@@ -582,6 +652,10 @@ static void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
**/
static void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
{
+ /* Blocked by MNG FW so bail */
+ if (ixgbe_check_reset_blocked(hw))
+ return;
+
if (hw->mac.autotry_restart) {
ixgbe_disable_tx_laser_multispeed_fiber(hw);
ixgbe_enable_tx_laser_multispeed_fiber(hw);
@@ -590,75 +664,6 @@ static void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
}
/**
- * ixgbe_set_fiber_fixed_speed - Set module link speed for fixed fiber
- * @hw: pointer to hardware structure
- * @speed: link speed to set
- *
- * We set the module speed differently for fixed fiber. For other
- * multi-speed devices we don't have an error value so here if we
- * detect an error we just log it and exit.
- */
-static void ixgbe_set_fiber_fixed_speed(struct ixgbe_hw *hw,
- ixgbe_link_speed speed)
-{
- s32 status;
- u8 rs, eeprom_data;
-
- switch (speed) {
- case IXGBE_LINK_SPEED_10GB_FULL:
- /* one bit mask same as setting on */
- rs = IXGBE_SFF_SOFT_RS_SELECT_10G;
- break;
- case IXGBE_LINK_SPEED_1GB_FULL:
- rs = IXGBE_SFF_SOFT_RS_SELECT_1G;
- break;
- default:
- hw_dbg(hw, "Invalid fixed module speed\n");
- return;
- }
-
- /* Set RS0 */
- status = hw->phy.ops.read_i2c_byte(hw, IXGBE_SFF_SFF_8472_OSCB,
- IXGBE_I2C_EEPROM_DEV_ADDR2,
- &eeprom_data);
- if (status) {
- hw_dbg(hw, "Failed to read Rx Rate Select RS0\n");
- goto out;
- }
-
- eeprom_data = (eeprom_data & ~IXGBE_SFF_SOFT_RS_SELECT_MASK) | rs;
-
- status = hw->phy.ops.write_i2c_byte(hw, IXGBE_SFF_SFF_8472_OSCB,
- IXGBE_I2C_EEPROM_DEV_ADDR2,
- eeprom_data);
- if (status) {
- hw_dbg(hw, "Failed to write Rx Rate Select RS0\n");
- goto out;
- }
-
- /* Set RS1 */
- status = hw->phy.ops.read_i2c_byte(hw, IXGBE_SFF_SFF_8472_ESCB,
- IXGBE_I2C_EEPROM_DEV_ADDR2,
- &eeprom_data);
- if (status) {
- hw_dbg(hw, "Failed to read Rx Rate Select RS1\n");
- goto out;
- }
-
- eeprom_data = (eeprom_data & ~IXGBE_SFF_SOFT_RS_SELECT_MASK) & rs;
-
- status = hw->phy.ops.write_i2c_byte(hw, IXGBE_SFF_SFF_8472_ESCB,
- IXGBE_I2C_EEPROM_DEV_ADDR2,
- eeprom_data);
- if (status) {
- hw_dbg(hw, "Failed to write Rx Rate Select RS1\n");
- goto out;
- }
-out:
- return;
-}
-
-/**
* ixgbe_setup_mac_link_multispeed_fiber - Set MAC link speed
* @hw: pointer to hardware structure
* @speed: new link speed
@@ -768,10 +773,6 @@ static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
/* Set the module link speed */
switch (hw->phy.media_type) {
- case ixgbe_media_type_fiber_fixed:
- ixgbe_set_fiber_fixed_speed(hw,
- IXGBE_LINK_SPEED_1GB_FULL);
- break;
case ixgbe_media_type_fiber:
esdp_reg &= ~IXGBE_ESDP_SDP5;
esdp_reg |= IXGBE_ESDP_SDP5_DIR;
@@ -941,8 +942,7 @@ static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw,
out:
if (link_up && (link_speed == IXGBE_LINK_SPEED_1GB_FULL))
- hw_dbg(hw, "Smartspeed has downgraded the link speed from "
- "the maximum advertised\n");
+ hw_dbg(hw, "Smartspeed has downgraded the link speed from the maximum advertised\n");
return status;
}
@@ -958,16 +958,19 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
bool autoneg_wait_to_complete)
{
+ bool autoneg = false;
s32 status = 0;
- u32 autoc, pma_pmd_1g, link_mode, start_autoc;
+ u32 pma_pmd_1g, link_mode, links_reg, i;
u32 autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
- u32 orig_autoc = 0;
u32 pma_pmd_10g_serial = autoc2 & IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_MASK;
- u32 links_reg;
- u32 i;
ixgbe_link_speed link_capabilities = IXGBE_LINK_SPEED_UNKNOWN;
- bool got_lock = false;
- bool autoneg = false;
+
+ /* holds the value of AUTOC register at this current point in time */
+ u32 current_autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+ /* holds the cached value of AUTOC register */
+ u32 orig_autoc = 0;
+ /* temporary variable used for comparison purposes */
+ u32 autoc = current_autoc;
/* Check to see if speed passed in is supported. */
status = hw->mac.ops.get_link_capabilities(hw, &link_capabilities,
@@ -984,12 +987,10 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
/* Use stored value (EEPROM defaults) of AUTOC to find KR/KX4 support*/
if (hw->mac.orig_link_settings_stored)
- autoc = hw->mac.orig_autoc;
+ orig_autoc = hw->mac.orig_autoc;
else
- autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+ orig_autoc = autoc;
- orig_autoc = autoc;
- start_autoc = hw->mac.cached_autoc;
link_mode = autoc & IXGBE_AUTOC_LMS_MASK;
pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK;
@@ -1029,28 +1030,11 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
}
}
- if (autoc != start_autoc) {
- /* Need SW/FW semaphore around AUTOC writes if LESM is on,
- * likewise reset_pipeline requires us to hold this lock as
- * it also writes to AUTOC.
- */
- if (ixgbe_verify_lesm_fw_enabled_82599(hw)) {
- status = hw->mac.ops.acquire_swfw_sync(hw,
- IXGBE_GSSR_MAC_CSR_SM);
- if (status != 0)
- goto out;
-
- got_lock = true;
- }
-
+ if (autoc != current_autoc) {
/* Restart link */
- IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc);
- hw->mac.cached_autoc = autoc;
- ixgbe_reset_pipeline_82599(hw);
-
- if (got_lock)
- hw->mac.ops.release_swfw_sync(hw,
- IXGBE_GSSR_MAC_CSR_SM);
+ status = hw->mac.ops.prot_autoc_write(hw, autoc, false);
+ if (status)
+ goto out;
/* Only poll for autoneg to complete if specified to do so */
if (autoneg_wait_to_complete) {
@@ -1068,8 +1052,7 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) {
status =
IXGBE_ERR_AUTONEG_NOT_COMPLETE;
- hw_dbg(hw, "Autoneg did not "
- "complete.\n");
+ hw_dbg(hw, "Autoneg did not complete.\n");
}
}
}
@@ -1117,7 +1100,7 @@ static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw)
{
ixgbe_link_speed link_speed;
s32 status;
- u32 ctrl, i, autoc2;
+ u32 ctrl, i, autoc, autoc2;
u32 curr_lms;
bool link_up = false;
@@ -1151,11 +1134,7 @@ static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw)
hw->phy.ops.reset(hw);
/* remember AUTOC from before we reset */
- if (hw->mac.cached_autoc)
- curr_lms = hw->mac.cached_autoc & IXGBE_AUTOC_LMS_MASK;
- else
- curr_lms = IXGBE_READ_REG(hw, IXGBE_AUTOC) &
- IXGBE_AUTOC_LMS_MASK;
+ curr_lms = IXGBE_READ_REG(hw, IXGBE_AUTOC) & IXGBE_AUTOC_LMS_MASK;
mac_reset_top:
/*
@@ -1205,7 +1184,7 @@ mac_reset_top:
* stored off yet. Otherwise restore the stored original
* values since the reset operation sets back to defaults.
*/
- hw->mac.cached_autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+ autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
/* Enable link if disabled in NVM */
@@ -1216,7 +1195,7 @@ mac_reset_top:
}
if (hw->mac.orig_link_settings_stored == false) {
- hw->mac.orig_autoc = hw->mac.cached_autoc;
+ hw->mac.orig_autoc = autoc;
hw->mac.orig_autoc2 = autoc2;
hw->mac.orig_link_settings_stored = true;
} else {
@@ -1227,34 +1206,18 @@ mac_reset_top:
* Likewise if we support WoL we don't want change the
* LMS state either.
*/
- if ((hw->phy.multispeed_fiber && hw->mng_fw_enabled) ||
+ if ((hw->phy.multispeed_fiber && ixgbe_mng_enabled(hw)) ||
hw->wol_enabled)
hw->mac.orig_autoc =
(hw->mac.orig_autoc & ~IXGBE_AUTOC_LMS_MASK) |
curr_lms;
- if (hw->mac.cached_autoc != hw->mac.orig_autoc) {
- /* Need SW/FW semaphore around AUTOC writes if LESM is
- * on, likewise reset_pipeline requires us to hold
- * this lock as it also writes to AUTOC.
- */
- bool got_lock = false;
- if (ixgbe_verify_lesm_fw_enabled_82599(hw)) {
- status = hw->mac.ops.acquire_swfw_sync(hw,
- IXGBE_GSSR_MAC_CSR_SM);
- if (status)
- goto reset_hw_out;
-
- got_lock = true;
- }
-
- IXGBE_WRITE_REG(hw, IXGBE_AUTOC, hw->mac.orig_autoc);
- hw->mac.cached_autoc = hw->mac.orig_autoc;
- ixgbe_reset_pipeline_82599(hw);
-
- if (got_lock)
- hw->mac.ops.release_swfw_sync(hw,
- IXGBE_GSSR_MAC_CSR_SM);
+ if (autoc != hw->mac.orig_autoc) {
+ status = hw->mac.ops.prot_autoc_write(hw,
+ hw->mac.orig_autoc,
+ false);
+ if (status)
+ goto reset_hw_out;
}
if ((autoc2 & IXGBE_AUTOC2_UPPER_MASK) !=
@@ -1634,35 +1597,20 @@ void ixgbe_atr_compute_perfect_hash_82599(union ixgbe_atr_input *input,
{
u32 hi_hash_dword, lo_hash_dword, flow_vm_vlan;
- u32 bucket_hash = 0;
+ u32 bucket_hash = 0, hi_dword = 0;
+ int i;
/* Apply masks to input data */
- input->dword_stream[0] &= input_mask->dword_stream[0];
- input->dword_stream[1] &= input_mask->dword_stream[1];
- input->dword_stream[2] &= input_mask->dword_stream[2];
- input->dword_stream[3] &= input_mask->dword_stream[3];
- input->dword_stream[4] &= input_mask->dword_stream[4];
- input->dword_stream[5] &= input_mask->dword_stream[5];
- input->dword_stream[6] &= input_mask->dword_stream[6];
- input->dword_stream[7] &= input_mask->dword_stream[7];
- input->dword_stream[8] &= input_mask->dword_stream[8];
- input->dword_stream[9] &= input_mask->dword_stream[9];
- input->dword_stream[10] &= input_mask->dword_stream[10];
+ for (i = 0; i <= 10; i++)
+ input->dword_stream[i] &= input_mask->dword_stream[i];
/* record the flow_vm_vlan bits as they are a key part to the hash */
flow_vm_vlan = ntohl(input->dword_stream[0]);
/* generate common hash dword */
- hi_hash_dword = ntohl(input->dword_stream[1] ^
- input->dword_stream[2] ^
- input->dword_stream[3] ^
- input->dword_stream[4] ^
- input->dword_stream[5] ^
- input->dword_stream[6] ^
- input->dword_stream[7] ^
- input->dword_stream[8] ^
- input->dword_stream[9] ^
- input->dword_stream[10]);
+ for (i = 1; i <= 10; i++)
+ hi_dword ^= input->dword_stream[i];
+ hi_hash_dword = ntohl(hi_dword);
/* low dword is word swapped version of common */
lo_hash_dword = (hi_hash_dword >> 16) | (hi_hash_dword << 16);
@@ -1681,21 +1629,8 @@ void ixgbe_atr_compute_perfect_hash_82599(union ixgbe_atr_input *input,
lo_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan << 16);
/* Process remaining 30 bit of the key */
- IXGBE_COMPUTE_BKT_HASH_ITERATION(1);
- IXGBE_COMPUTE_BKT_HASH_ITERATION(2);
- IXGBE_COMPUTE_BKT_HASH_ITERATION(3);
- IXGBE_COMPUTE_BKT_HASH_ITERATION(4);
- IXGBE_COMPUTE_BKT_HASH_ITERATION(5);
- IXGBE_COMPUTE_BKT_HASH_ITERATION(6);
- IXGBE_COMPUTE_BKT_HASH_ITERATION(7);
- IXGBE_COMPUTE_BKT_HASH_ITERATION(8);
- IXGBE_COMPUTE_BKT_HASH_ITERATION(9);
- IXGBE_COMPUTE_BKT_HASH_ITERATION(10);
- IXGBE_COMPUTE_BKT_HASH_ITERATION(11);
- IXGBE_COMPUTE_BKT_HASH_ITERATION(12);
- IXGBE_COMPUTE_BKT_HASH_ITERATION(13);
- IXGBE_COMPUTE_BKT_HASH_ITERATION(14);
- IXGBE_COMPUTE_BKT_HASH_ITERATION(15);
+ for (i = 1; i <= 15; i++)
+ IXGBE_COMPUTE_BKT_HASH_ITERATION(i);
/*
* Limit hash to 13 bits since max bucket count is 8K.
@@ -2001,7 +1936,6 @@ static s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw)
/* We need to run link autotry after the driver loads */
hw->mac.autotry_restart = true;
- hw->mac.rx_pb_size = IXGBE_82599_RX_PB_SIZE;
if (ret_val == 0)
ret_val = ixgbe_verify_fw_version_82599(hw);
@@ -2260,7 +2194,7 @@ fw_version_err:
* Returns true if the LESM FW module is present and enabled. Otherwise
* returns false. Smart Speed must be disabled if LESM FW module is enabled.
**/
-bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw)
+static bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw)
{
bool lesm_enabled = false;
u16 fw_offset, fw_lesm_param_offset, fw_lesm_state;
@@ -2366,7 +2300,7 @@ static s32 ixgbe_read_eeprom_82599(struct ixgbe_hw *hw,
* full pipeline reset. Note - We must hold the SW/FW semaphore before writing
* to AUTOC, so this function assumes the semaphore is held.
**/
-s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw)
+static s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw)
{
s32 ret_val;
u32 anlp1_reg = 0;
@@ -2380,11 +2314,12 @@ s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw)
IXGBE_WRITE_FLUSH(hw);
}
- autoc_reg = hw->mac.cached_autoc;
+ autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
autoc_reg |= IXGBE_AUTOC_AN_RESTART;
/* Write AUTOC register with toggled LMS[2] bit and Restart_AN */
- IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg ^ IXGBE_AUTOC_LMS_1G_AN);
+ IXGBE_WRITE_REG(hw, IXGBE_AUTOC,
+ autoc_reg ^ (0x4 << IXGBE_AUTOC_LMS_SHIFT));
/* Wait for AN to leave state 0 */
for (i = 0; i < 10; i++) {
@@ -2565,7 +2500,8 @@ static struct ixgbe_mac_operations mac_ops_82599 = {
.release_swfw_sync = &ixgbe_release_swfw_sync,
.get_thermal_sensor_data = &ixgbe_get_thermal_sensor_data_generic,
.init_thermal_sensor_thresh = &ixgbe_init_thermal_sensor_thresh_generic,
- .mng_fw_enabled = &ixgbe_mng_enabled,
+ .prot_autoc_read = &prot_autoc_read_82599,
+ .prot_autoc_write = &prot_autoc_write_82599,
};
static struct ixgbe_eeprom_operations eeprom_ops_82599 = {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
index b5c434b617b1..24fba39e194e 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
+ Copyright(c) 1999 - 2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
@@ -72,7 +73,6 @@ bool ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw)
bool link_up;
switch (hw->phy.media_type) {
- case ixgbe_media_type_fiber_fixed:
case ixgbe_media_type_fiber:
hw->mac.ops.check_link(hw, &speed, &link_up, false);
/* if link is down, assume supported */
@@ -114,7 +114,7 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw)
s32 ret_val = 0;
u32 reg = 0, reg_bp = 0;
u16 reg_cu = 0;
- bool got_lock = false;
+ bool locked = false;
/*
* Validate the requested mode. Strict IEEE mode does not allow
@@ -139,11 +139,16 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw)
* we link at 10G, the 1G advertisement is harmless and vice versa.
*/
switch (hw->phy.media_type) {
- case ixgbe_media_type_fiber_fixed:
- case ixgbe_media_type_fiber:
case ixgbe_media_type_backplane:
+ /* some MAC's need RMW protection on AUTOC */
+ ret_val = hw->mac.ops.prot_autoc_read(hw, &locked, &reg_bp);
+ if (ret_val)
+ goto out;
+
+ /* only backplane uses autoc so fall though */
+ case ixgbe_media_type_fiber:
reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA);
- reg_bp = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+
break;
case ixgbe_media_type_copper:
hw->phy.ops.read_reg(hw, MDIO_AN_ADVERTISE,
@@ -240,27 +245,12 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw)
* LESM is on, likewise reset_pipeline requries the lock as
* it also writes AUTOC.
*/
- if ((hw->mac.type == ixgbe_mac_82599EB) &&
- ixgbe_verify_lesm_fw_enabled_82599(hw)) {
- ret_val = hw->mac.ops.acquire_swfw_sync(hw,
- IXGBE_GSSR_MAC_CSR_SM);
- if (ret_val)
- goto out;
-
- got_lock = true;
- }
-
- IXGBE_WRITE_REG(hw, IXGBE_AUTOC, reg_bp);
-
- if (hw->mac.type == ixgbe_mac_82599EB)
- ixgbe_reset_pipeline_82599(hw);
-
- if (got_lock)
- hw->mac.ops.release_swfw_sync(hw,
- IXGBE_GSSR_MAC_CSR_SM);
+ ret_val = hw->mac.ops.prot_autoc_write(hw, reg_bp, locked);
+ if (ret_val)
+ goto out;
} else if ((hw->phy.media_type == ixgbe_media_type_copper) &&
- ixgbe_device_supports_autoneg_fc(hw)) {
+ ixgbe_device_supports_autoneg_fc(hw)) {
hw->phy.ops.write_reg(hw, MDIO_AN_ADVERTISE,
MDIO_MMD_AN, reg_cu);
}
@@ -656,20 +646,17 @@ enum ixgbe_bus_speed ixgbe_convert_bus_speed(u16 link_status)
**/
s32 ixgbe_get_bus_info_generic(struct ixgbe_hw *hw)
{
- struct ixgbe_adapter *adapter = hw->back;
- struct ixgbe_mac_info *mac = &hw->mac;
u16 link_status;
hw->bus.type = ixgbe_bus_type_pci_express;
/* Get the negotiated link width and speed from PCI config space */
- pci_read_config_word(adapter->pdev, IXGBE_PCI_LINK_STATUS,
- &link_status);
+ link_status = ixgbe_read_pci_cfg_word(hw, IXGBE_PCI_LINK_STATUS);
hw->bus.width = ixgbe_convert_bus_width(link_status);
hw->bus.speed = ixgbe_convert_bus_speed(link_status);
- mac->ops.set_lan_id(hw);
+ hw->mac.ops.set_lan_id(hw);
return 0;
}
@@ -2406,7 +2393,6 @@ void ixgbe_fc_autoneg(struct ixgbe_hw *hw)
switch (hw->phy.media_type) {
/* Autoneg flow control on fiber adapters */
- case ixgbe_media_type_fiber_fixed:
case ixgbe_media_type_fiber:
if (speed == IXGBE_LINK_SPEED_1GB_FULL)
ret_val = ixgbe_fc_autoneg_fiber(hw);
@@ -2437,6 +2423,53 @@ out:
}
/**
+ * ixgbe_pcie_timeout_poll - Return number of times to poll for completion
+ * @hw: pointer to hardware structure
+ *
+ * System-wide timeout range is encoded in PCIe Device Control2 register.
+ *
+ * Add 10% to specified maximum and return the number of times to poll for
+ * completion timeout, in units of 100 microsec. Never return less than
+ * 800 = 80 millisec.
+ **/
+static u32 ixgbe_pcie_timeout_poll(struct ixgbe_hw *hw)
+{
+ s16 devctl2;
+ u32 pollcnt;
+
+ devctl2 = ixgbe_read_pci_cfg_word(hw, IXGBE_PCI_DEVICE_CONTROL2);
+ devctl2 &= IXGBE_PCIDEVCTRL2_TIMEO_MASK;
+
+ switch (devctl2) {
+ case IXGBE_PCIDEVCTRL2_65_130ms:
+ pollcnt = 1300; /* 130 millisec */
+ break;
+ case IXGBE_PCIDEVCTRL2_260_520ms:
+ pollcnt = 5200; /* 520 millisec */
+ break;
+ case IXGBE_PCIDEVCTRL2_1_2s:
+ pollcnt = 20000; /* 2 sec */
+ break;
+ case IXGBE_PCIDEVCTRL2_4_8s:
+ pollcnt = 80000; /* 8 sec */
+ break;
+ case IXGBE_PCIDEVCTRL2_17_34s:
+ pollcnt = 34000; /* 34 sec */
+ break;
+ case IXGBE_PCIDEVCTRL2_50_100us: /* 100 microsecs */
+ case IXGBE_PCIDEVCTRL2_1_2ms: /* 2 millisecs */
+ case IXGBE_PCIDEVCTRL2_16_32ms: /* 32 millisec */
+ case IXGBE_PCIDEVCTRL2_16_32ms_def: /* 32 millisec default */
+ default:
+ pollcnt = 800; /* 80 millisec minimum */
+ break;
+ }
+
+ /* add 10% to spec maximum */
+ return (pollcnt * 11) / 10;
+}
+
+/**
* ixgbe_disable_pcie_master - Disable PCI-express master access
* @hw: pointer to hardware structure
*
@@ -2447,16 +2480,16 @@ out:
**/
static s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw)
{
- struct ixgbe_adapter *adapter = hw->back;
s32 status = 0;
- u32 i;
+ u32 i, poll;
u16 value;
/* Always set this bit to ensure any future transactions are blocked */
IXGBE_WRITE_REG(hw, IXGBE_CTRL, IXGBE_CTRL_GIO_DIS);
/* Exit if master requests are blocked */
- if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO))
+ if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO) ||
+ ixgbe_removed(hw->hw_addr))
goto out;
/* Poll for master request bit to clear */
@@ -2481,10 +2514,12 @@ static s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw)
* Before proceeding, make sure that the PCIe block does not have
* transactions pending.
*/
- for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) {
+ poll = ixgbe_pcie_timeout_poll(hw);
+ for (i = 0; i < poll; i++) {
udelay(100);
- pci_read_config_word(adapter->pdev, IXGBE_PCI_DEVICE_STATUS,
- &value);
+ value = ixgbe_read_pci_cfg_word(hw, IXGBE_PCI_DEVICE_STATUS);
+ if (ixgbe_removed(hw->hw_addr))
+ goto out;
if (!(value & IXGBE_PCI_DEVICE_STATUS_TRANSACTION_PENDING))
goto out;
}
@@ -2564,6 +2599,35 @@ void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask)
}
/**
+ * prot_autoc_read_generic - Hides MAC differences needed for AUTOC read
+ * @hw: pointer to hardware structure
+ * @reg_val: Value we read from AUTOC
+ * @locked: bool to indicate whether the SW/FW lock should be taken. Never
+ * true in this the generic case.
+ *
+ * The default case requires no protection so just to the register read.
+ **/
+s32 prot_autoc_read_generic(struct ixgbe_hw *hw, bool *locked, u32 *reg_val)
+{
+ *locked = false;
+ *reg_val = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+ return 0;
+}
+
+/**
+ * prot_autoc_write_generic - Hides MAC differences needed for AUTOC write
+ * @hw: pointer to hardware structure
+ * @reg_val: value to write to AUTOC
+ * @locked: bool to indicate whether the SW/FW lock was already taken by
+ * previous read.
+ **/
+s32 prot_autoc_write_generic(struct ixgbe_hw *hw, u32 reg_val, bool locked)
+{
+ IXGBE_WRITE_REG(hw, IXGBE_AUTOC, reg_val);
+ return 0;
+}
+
+/**
* ixgbe_disable_rx_buff_generic - Stops the receive data path
* @hw: pointer to hardware structure
*
@@ -2641,6 +2705,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index)
u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
s32 ret_val = 0;
+ bool locked = false;
/*
* Link must be up to auto-blink the LEDs;
@@ -2649,28 +2714,19 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index)
hw->mac.ops.check_link(hw, &speed, &link_up, false);
if (!link_up) {
- /* Need the SW/FW semaphore around AUTOC writes if 82599 and
- * LESM is on.
- */
- bool got_lock = false;
-
- if ((hw->mac.type == ixgbe_mac_82599EB) &&
- ixgbe_verify_lesm_fw_enabled_82599(hw)) {
- ret_val = hw->mac.ops.acquire_swfw_sync(hw,
- IXGBE_GSSR_MAC_CSR_SM);
- if (ret_val)
- goto out;
+ ret_val = hw->mac.ops.prot_autoc_read(hw, &locked, &autoc_reg);
+ if (ret_val)
+ goto out;
- got_lock = true;
- }
autoc_reg |= IXGBE_AUTOC_AN_RESTART;
autoc_reg |= IXGBE_AUTOC_FLU;
- IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
+
+ ret_val = hw->mac.ops.prot_autoc_write(hw, autoc_reg, locked);
+ if (ret_val)
+ goto out;
+
IXGBE_WRITE_FLUSH(hw);
- if (got_lock)
- hw->mac.ops.release_swfw_sync(hw,
- IXGBE_GSSR_MAC_CSR_SM);
usleep_range(10000, 20000);
}
@@ -2690,33 +2746,21 @@ out:
**/
s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index)
{
- u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+ u32 autoc_reg = 0;
u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
s32 ret_val = 0;
- bool got_lock = false;
+ bool locked = false;
- /* Need the SW/FW semaphore around AUTOC writes if 82599 and
- * LESM is on.
- */
- if ((hw->mac.type == ixgbe_mac_82599EB) &&
- ixgbe_verify_lesm_fw_enabled_82599(hw)) {
- ret_val = hw->mac.ops.acquire_swfw_sync(hw,
- IXGBE_GSSR_MAC_CSR_SM);
- if (ret_val)
- goto out;
-
- got_lock = true;
- }
+ ret_val = hw->mac.ops.prot_autoc_read(hw, &locked, &autoc_reg);
+ if (ret_val)
+ goto out;
autoc_reg &= ~IXGBE_AUTOC_FLU;
autoc_reg |= IXGBE_AUTOC_AN_RESTART;
- IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
-
- if (hw->mac.type == ixgbe_mac_82599EB)
- ixgbe_reset_pipeline_82599(hw);
- if (got_lock)
- hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM);
+ ret_val = hw->mac.ops.prot_autoc_write(hw, autoc_reg, locked);
+ if (ret_val)
+ goto out;
led_reg &= ~IXGBE_LED_MODE_MASK(index);
led_reg &= ~IXGBE_LED_BLINK(index);
@@ -2817,7 +2861,6 @@ san_mac_addr_clr:
**/
u16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw)
{
- struct ixgbe_adapter *adapter = hw->back;
u16 msix_count = 1;
u16 max_msix_count;
u16 pcie_offset;
@@ -2836,7 +2879,9 @@ u16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw)
return msix_count;
}
- pci_read_config_word(adapter->pdev, pcie_offset, &msix_count);
+ msix_count = ixgbe_read_pci_cfg_word(hw, pcie_offset);
+ if (ixgbe_removed(hw->hw_addr))
+ msix_count = 0;
msix_count &= IXGBE_PCIE_MSIX_TBL_SZ_MASK;
/* MSI-X count is zero-based in HW */
@@ -2868,6 +2913,9 @@ s32 ixgbe_clear_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq)
mpsar_lo = IXGBE_READ_REG(hw, IXGBE_MPSAR_LO(rar));
mpsar_hi = IXGBE_READ_REG(hw, IXGBE_MPSAR_HI(rar));
+ if (ixgbe_removed(hw->hw_addr))
+ goto done;
+
if (!mpsar_lo && !mpsar_hi)
goto done;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
index f2e3919750ec..f12c40fb5537 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
+ Copyright(c) 1999 - 2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
@@ -98,6 +99,10 @@ s32 ixgbe_check_mac_link_generic(struct ixgbe_hw *hw,
bool *link_up, bool link_up_wait_to_complete);
s32 ixgbe_get_wwn_prefix_generic(struct ixgbe_hw *hw, u16 *wwnn_prefix,
u16 *wwpn_prefix);
+
+s32 prot_autoc_read_generic(struct ixgbe_hw *hw, bool *, u32 *reg_val);
+s32 prot_autoc_write_generic(struct ixgbe_hw *hw, u32 reg_val, bool locked);
+
s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index);
s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index);
void ixgbe_set_mac_anti_spoofing(struct ixgbe_hw *hw, bool enable, int pf);
@@ -106,10 +111,10 @@ s32 ixgbe_get_device_caps_generic(struct ixgbe_hw *hw, u16 *device_caps);
s32 ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min,
u8 build, u8 ver);
void ixgbe_clear_tx_pending(struct ixgbe_hw *hw);
+bool ixgbe_mng_enabled(struct ixgbe_hw *hw);
void ixgbe_set_rxpba_generic(struct ixgbe_hw *hw, int num_pb,
u32 headroom, int strategy);
-s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw);
#define IXGBE_I2C_THERMAL_SENSOR_ADDR 0xF8
#define IXGBE_EMC_INTERNAL_DATA 0x00
@@ -125,6 +130,11 @@ s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw);
s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw);
#define IXGBE_FAILED_READ_REG 0xffffffffU
+#define IXGBE_FAILED_READ_CFG_DWORD 0xffffffffU
+#define IXGBE_FAILED_READ_CFG_WORD 0xffffU
+
+u16 ixgbe_read_pci_cfg_word(struct ixgbe_hw *hw, u32 reg);
+void ixgbe_write_pci_cfg_word(struct ixgbe_hw *hw, u32 reg, u16 value);
static inline bool ixgbe_removed(void __iomem *addr)
{
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c
index 05e23b80b5e3..bdb99b3b0f30 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h
index d71d9ce3e394..d5a1e3db0774 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
index c5933f6dceee..472b0f450bf9 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
index 043307024c4a..6c55c14d082a 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
+ Copyright(c) 1999 - 2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
@@ -1127,10 +1128,10 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
}
do {
- start = u64_stats_fetch_begin_bh(&ring->syncp);
+ start = u64_stats_fetch_begin_irq(&ring->syncp);
data[i] = ring->stats.packets;
data[i+1] = ring->stats.bytes;
- } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
i += 2;
#ifdef BP_EXTENDED_STATS
data[i] = ring->stats.yields;
@@ -1155,10 +1156,10 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
}
do {
- start = u64_stats_fetch_begin_bh(&ring->syncp);
+ start = u64_stats_fetch_begin_irq(&ring->syncp);
data[i] = ring->stats.packets;
data[i+1] = ring->stats.bytes;
- } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
i += 2;
#ifdef BP_EXTENDED_STATS
data[i] = ring->stats.yields;
@@ -1247,6 +1248,11 @@ static int ixgbe_link_test(struct ixgbe_adapter *adapter, u64 *data)
struct ixgbe_hw *hw = &adapter->hw;
bool link_up;
u32 link_speed = 0;
+
+ if (ixgbe_removed(hw->hw_addr)) {
+ *data = 1;
+ return 1;
+ }
*data = 0;
hw->mac.ops.check_link(hw, &link_speed, &link_up, true);
@@ -1969,6 +1975,7 @@ static void ixgbe_diag_test(struct net_device *netdev,
data[1] = 1;
data[2] = 1;
data[3] = 1;
+ data[4] = 1;
eth_test->flags |= ETH_TEST_FL_FAILED;
return;
}
@@ -1988,6 +1995,7 @@ static void ixgbe_diag_test(struct net_device *netdev,
data[1] = 1;
data[2] = 1;
data[3] = 1;
+ data[4] = 1;
eth_test->flags |= ETH_TEST_FL_FAILED;
clear_bit(__IXGBE_TESTING,
&adapter->state);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
index f58db453a97e..25a3dfef33e8 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
@@ -407,13 +408,13 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter,
switch (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_FCSTAT)) {
/* return 0 to bypass going to ULD for DDPed data */
- case __constant_cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_DDP):
+ case cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_DDP):
/* update length of DDPed data */
ddp->len = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
rc = 0;
break;
/* unmap the sg list when FCPRSP is received */
- case __constant_cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_FCPRSP):
+ case cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_FCPRSP):
dma_unmap_sg(&adapter->pdev->dev, ddp->sgl,
ddp->sgc, DMA_FROM_DEVICE);
ddp->err = ddp_err;
@@ -421,14 +422,14 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter,
ddp->sgc = 0;
/* fall through */
/* if DDP length is present pass it through to ULD */
- case __constant_cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_NODDP):
+ case cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_NODDP):
/* update length of DDPed data */
ddp->len = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
if (ddp->len)
rc = ddp->len;
break;
/* no match will return as an error */
- case __constant_cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_NOMTCH):
+ case cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_NOMTCH):
default:
break;
}
@@ -585,7 +586,7 @@ static int ixgbe_fcoe_dma_pool_alloc(struct ixgbe_fcoe *fcoe,
struct dma_pool *pool;
char pool_name[32];
- snprintf(pool_name, 32, "ixgbe_fcoe_ddp_%d", cpu);
+ snprintf(pool_name, 32, "ixgbe_fcoe_ddp_%u", cpu);
pool = dma_pool_create(pool_name, dev, IXGBE_FCPTR_MAX,
IXGBE_FCPTR_ALIGN, PAGE_SIZE);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h
index 3a02759b5e95..b16cc786750d 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
index 32e3eaaa160a..2067d392cc3d 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
@@ -698,7 +699,7 @@ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter)
static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter,
int vectors)
{
- int err, vector_threshold;
+ int vector_threshold;
/* We'll want at least 2 (vector_threshold):
* 1) TxQ[0] + RxQ[0] handler
@@ -712,18 +713,10 @@ static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter,
* Right now, we simply care about how many we'll get; we'll
* set them up later while requesting irq's.
*/
- while (vectors >= vector_threshold) {
- err = pci_enable_msix(adapter->pdev, adapter->msix_entries,
- vectors);
- if (!err) /* Success in acquiring all requested vectors. */
- break;
- else if (err < 0)
- vectors = 0; /* Nasty failure, quit now */
- else /* err == number of vectors we should try again with */
- vectors = err;
- }
+ vectors = pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+ vector_threshold, vectors);
- if (vectors < vector_threshold) {
+ if (vectors < 0) {
/* Can't allocate enough MSI-X interrupts? Oh well.
* This just means we'll go with either a single MSI
* vector or fall back to legacy interrupts.
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 6d4ada72dfd0..8436c651b735 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
+ Copyright(c) 1999 - 2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
@@ -67,7 +68,7 @@ static char ixgbe_default_device_descr[] =
#define DRV_VERSION "3.19.1-k"
const char ixgbe_driver_version[] = DRV_VERSION;
static const char ixgbe_copyright[] =
- "Copyright (c) 1999-2013 Intel Corporation.";
+ "Copyright (c) 1999-2014 Intel Corporation.";
static const struct ixgbe_info *ixgbe_info_tbl[] = {
[board_82598] = &ixgbe_82598_info,
@@ -151,6 +152,8 @@ MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
+static bool ixgbe_check_cfg_remove(struct ixgbe_hw *hw, struct pci_dev *pdev);
+
static int ixgbe_read_pci_cfg_word_parent(struct ixgbe_adapter *adapter,
u32 reg, u16 *value)
{
@@ -169,6 +172,9 @@ static int ixgbe_read_pci_cfg_word_parent(struct ixgbe_adapter *adapter,
return -1;
pcie_capability_read_word(parent_dev, reg, value);
+ if (*value == IXGBE_FAILED_READ_CFG_WORD &&
+ ixgbe_check_cfg_remove(&adapter->hw, parent_dev))
+ return -1;
return 0;
}
@@ -313,6 +319,57 @@ void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg)
ixgbe_remove_adapter(hw);
}
+static bool ixgbe_check_cfg_remove(struct ixgbe_hw *hw, struct pci_dev *pdev)
+{
+ u16 value;
+
+ pci_read_config_word(pdev, PCI_VENDOR_ID, &value);
+ if (value == IXGBE_FAILED_READ_CFG_WORD) {
+ ixgbe_remove_adapter(hw);
+ return true;
+ }
+ return false;
+}
+
+u16 ixgbe_read_pci_cfg_word(struct ixgbe_hw *hw, u32 reg)
+{
+ struct ixgbe_adapter *adapter = hw->back;
+ u16 value;
+
+ if (ixgbe_removed(hw->hw_addr))
+ return IXGBE_FAILED_READ_CFG_WORD;
+ pci_read_config_word(adapter->pdev, reg, &value);
+ if (value == IXGBE_FAILED_READ_CFG_WORD &&
+ ixgbe_check_cfg_remove(hw, adapter->pdev))
+ return IXGBE_FAILED_READ_CFG_WORD;
+ return value;
+}
+
+#ifdef CONFIG_PCI_IOV
+static u32 ixgbe_read_pci_cfg_dword(struct ixgbe_hw *hw, u32 reg)
+{
+ struct ixgbe_adapter *adapter = hw->back;
+ u32 value;
+
+ if (ixgbe_removed(hw->hw_addr))
+ return IXGBE_FAILED_READ_CFG_DWORD;
+ pci_read_config_dword(adapter->pdev, reg, &value);
+ if (value == IXGBE_FAILED_READ_CFG_DWORD &&
+ ixgbe_check_cfg_remove(hw, adapter->pdev))
+ return IXGBE_FAILED_READ_CFG_DWORD;
+ return value;
+}
+#endif /* CONFIG_PCI_IOV */
+
+void ixgbe_write_pci_cfg_word(struct ixgbe_hw *hw, u32 reg, u16 value)
+{
+ struct ixgbe_adapter *adapter = hw->back;
+
+ if (ixgbe_removed(hw->hw_addr))
+ return;
+ pci_write_config_word(adapter->pdev, reg, value);
+}
+
static void ixgbe_service_event_complete(struct ixgbe_adapter *adapter)
{
BUG_ON(!test_bit(__IXGBE_SERVICE_SCHED, &adapter->state));
@@ -1264,7 +1321,9 @@ static inline void ixgbe_rx_hash(struct ixgbe_ring *ring,
struct sk_buff *skb)
{
if (ring->netdev->features & NETIF_F_RXHASH)
- skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
+ skb_set_hash(skb,
+ le32_to_cpu(rx_desc->wb.lower.hi_dword.rss),
+ PKT_HASH_TYPE_L3);
}
#ifdef IXGBE_FCOE
@@ -1480,7 +1539,7 @@ static unsigned int ixgbe_get_headlen(unsigned char *data,
hdr.network += ETH_HLEN;
/* handle any vlan tag if present */
- if (protocol == __constant_htons(ETH_P_8021Q)) {
+ if (protocol == htons(ETH_P_8021Q)) {
if ((hdr.network - data) > (max_len - VLAN_HLEN))
return max_len;
@@ -1489,7 +1548,7 @@ static unsigned int ixgbe_get_headlen(unsigned char *data,
}
/* handle L3 protocols */
- if (protocol == __constant_htons(ETH_P_IP)) {
+ if (protocol == htons(ETH_P_IP)) {
if ((hdr.network - data) > (max_len - sizeof(struct iphdr)))
return max_len;
@@ -1503,7 +1562,7 @@ static unsigned int ixgbe_get_headlen(unsigned char *data,
/* record next protocol if header is present */
if (!(hdr.ipv4->frag_off & htons(IP_OFFSET)))
nexthdr = hdr.ipv4->protocol;
- } else if (protocol == __constant_htons(ETH_P_IPV6)) {
+ } else if (protocol == htons(ETH_P_IPV6)) {
if ((hdr.network - data) > (max_len - sizeof(struct ipv6hdr)))
return max_len;
@@ -1511,7 +1570,7 @@ static unsigned int ixgbe_get_headlen(unsigned char *data,
nexthdr = hdr.ipv6->nexthdr;
hlen = sizeof(struct ipv6hdr);
#ifdef IXGBE_FCOE
- } else if (protocol == __constant_htons(ETH_P_FCOE)) {
+ } else if (protocol == htons(ETH_P_FCOE)) {
if ((hdr.network - data) > (max_len - FCOE_HEADER_LEN))
return max_len;
hlen = FCOE_HEADER_LEN;
@@ -2026,7 +2085,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
#endif /* IXGBE_FCOE */
u16 cleaned_count = ixgbe_desc_unused(rx_ring);
- do {
+ while (likely(total_rx_packets < budget)) {
union ixgbe_adv_rx_desc *rx_desc;
struct sk_buff *skb;
@@ -2101,7 +2160,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
/* update budget accounting */
total_rx_packets++;
- } while (likely(total_rx_packets < budget));
+ }
u64_stats_update_begin(&rx_ring->syncp);
rx_ring->stats.packets += total_rx_packets;
@@ -2630,9 +2689,12 @@ static irqreturn_t ixgbe_msix_other(int irq, void *data)
switch (hw->mac.type) {
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
- if (eicr & IXGBE_EICR_ECC)
- e_info(link, "Received unrecoverable ECC Err, please "
- "reboot\n");
+ if (eicr & IXGBE_EICR_ECC) {
+ e_info(link, "Received ECC Err, initiating reset\n");
+ adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
+ ixgbe_service_event_schedule(adapter);
+ IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC);
+ }
/* Handle Flow Director Full threshold interrupt */
if (eicr & IXGBE_EICR_FLOW_DIR) {
int reinit_count = 0;
@@ -2846,9 +2908,12 @@ static irqreturn_t ixgbe_intr(int irq, void *data)
ixgbe_check_sfp_event(adapter, eicr);
/* Fall through */
case ixgbe_mac_X540:
- if (eicr & IXGBE_EICR_ECC)
- e_info(link, "Received unrecoverable ECC err, please "
- "reboot\n");
+ if (eicr & IXGBE_EICR_ECC) {
+ e_info(link, "Received ECC Err, initiating reset\n");
+ adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
+ ixgbe_service_event_schedule(adapter);
+ IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC);
+ }
ixgbe_check_overtemp_event(adapter, eicr);
break;
default:
@@ -4590,8 +4655,6 @@ static void ixgbe_setup_gpie(struct ixgbe_adapter *adapter)
static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
- struct net_device *upper;
- struct list_head *iter;
int err;
u32 ctrl_ext;
@@ -4633,19 +4696,6 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
e_crit(drv, "Fan has stopped, replace the adapter\n");
}
- /* enable transmits */
- netif_tx_start_all_queues(adapter->netdev);
-
- /* enable any upper devices */
- netdev_for_each_all_upper_dev_rcu(adapter->netdev, upper, iter) {
- if (netif_is_macvlan(upper)) {
- struct macvlan_dev *vlan = netdev_priv(upper);
-
- if (vlan->fwd_priv)
- netif_tx_start_all_queues(upper);
- }
- }
-
/* bring the link up in the watchdog, this could race with our first
* link up interrupt but shouldn't be a problem */
adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -5502,6 +5552,7 @@ static int ixgbe_resume(struct pci_dev *pdev)
struct net_device *netdev = adapter->netdev;
u32 err;
+ adapter->hw.hw_addr = adapter->io_addr;
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
/*
@@ -5515,6 +5566,8 @@ static int ixgbe_resume(struct pci_dev *pdev)
e_dev_err("Cannot enable PCI device from suspend\n");
return err;
}
+ smp_mb__before_clear_bit();
+ clear_bit(__IXGBE_DISABLED, &adapter->state);
pci_set_master(pdev);
pci_wake_from_d3(pdev, false);
@@ -5612,7 +5665,8 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake)
ixgbe_release_hw_control(adapter);
- pci_disable_device(pdev);
+ if (!test_and_set_bit(__IXGBE_DISABLED, &adapter->state))
+ pci_disable_device(pdev);
return 0;
}
@@ -6016,6 +6070,8 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
struct ixgbe_hw *hw = &adapter->hw;
+ struct net_device *upper;
+ struct list_head *iter;
u32 link_speed = adapter->link_speed;
bool flow_rx, flow_tx;
@@ -6067,6 +6123,21 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
netif_carrier_on(netdev);
ixgbe_check_vf_rate_limit(adapter);
+ /* enable transmits */
+ netif_tx_wake_all_queues(adapter->netdev);
+
+ /* enable any upper devices */
+ rtnl_lock();
+ netdev_for_each_all_upper_dev_rcu(adapter->netdev, upper, iter) {
+ if (netif_is_macvlan(upper)) {
+ struct macvlan_dev *vlan = netdev_priv(upper);
+
+ if (vlan->fwd_priv)
+ netif_tx_wake_all_queues(upper);
+ }
+ }
+ rtnl_unlock();
+
/* update the default user priority for VFs */
ixgbe_update_default_up(adapter);
@@ -6454,7 +6525,7 @@ static int ixgbe_tso(struct ixgbe_ring *tx_ring,
/* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
type_tucmd = IXGBE_ADVTXD_TUCMD_L4T_TCP;
- if (first->protocol == __constant_htons(ETH_P_IP)) {
+ if (first->protocol == htons(ETH_P_IP)) {
struct iphdr *iph = ip_hdr(skb);
iph->tot_len = 0;
iph->check = 0;
@@ -6514,12 +6585,12 @@ static void ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
} else {
u8 l4_hdr = 0;
switch (first->protocol) {
- case __constant_htons(ETH_P_IP):
+ case htons(ETH_P_IP):
vlan_macip_lens |= skb_network_header_len(skb);
type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4;
l4_hdr = ip_hdr(skb)->protocol;
break;
- case __constant_htons(ETH_P_IPV6):
+ case htons(ETH_P_IPV6):
vlan_macip_lens |= skb_network_header_len(skb);
l4_hdr = ipv6_hdr(skb)->nexthdr;
break;
@@ -6794,9 +6865,9 @@ static void ixgbe_atr(struct ixgbe_ring *ring,
hdr.network = skb_network_header(first->skb);
/* Currently only IPv4/IPv6 with TCP is supported */
- if ((first->protocol != __constant_htons(ETH_P_IPV6) ||
+ if ((first->protocol != htons(ETH_P_IPV6) ||
hdr.ipv6->nexthdr != IPPROTO_TCP) &&
- (first->protocol != __constant_htons(ETH_P_IP) ||
+ (first->protocol != htons(ETH_P_IP) ||
hdr.ipv4->protocol != IPPROTO_TCP))
return;
@@ -6829,12 +6900,12 @@ static void ixgbe_atr(struct ixgbe_ring *ring,
* and write the value to source port portion of compressed dword
*/
if (first->tx_flags & (IXGBE_TX_FLAGS_SW_VLAN | IXGBE_TX_FLAGS_HW_VLAN))
- common.port.src ^= th->dest ^ __constant_htons(ETH_P_8021Q);
+ common.port.src ^= th->dest ^ htons(ETH_P_8021Q);
else
common.port.src ^= th->dest ^ first->protocol;
common.port.dst ^= th->source;
- if (first->protocol == __constant_htons(ETH_P_IP)) {
+ if (first->protocol == htons(ETH_P_IP)) {
input.formatted.flow_type = IXGBE_ATR_FLOW_TYPE_TCPV4;
common.ip ^= hdr.ipv4->saddr ^ hdr.ipv4->daddr;
} else {
@@ -6881,7 +6952,7 @@ static inline int ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size)
}
static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv, select_queue_fallback_t fallback)
{
struct ixgbe_fwd_adapter *fwd_adapter = accel_priv;
#ifdef IXGBE_FCOE
@@ -6900,14 +6971,14 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
* or FIP and we have FCoE enabled on the adapter
*/
switch (vlan_get_protocol(skb)) {
- case __constant_htons(ETH_P_FCOE):
- case __constant_htons(ETH_P_FIP):
+ case htons(ETH_P_FCOE):
+ case htons(ETH_P_FIP):
adapter = netdev_priv(dev);
if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)
break;
default:
- return __netdev_pick_tx(dev, skb);
+ return fallback(dev, skb);
}
f = &adapter->ring_feature[RING_F_FCOE];
@@ -6920,7 +6991,7 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
return txq + f->offset;
#else
- return __netdev_pick_tx(dev, skb);
+ return fallback(dev, skb);
#endif
}
@@ -6962,7 +7033,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
tx_flags |= vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT;
tx_flags |= IXGBE_TX_FLAGS_HW_VLAN;
/* else if it is a SW VLAN check the next protocol and store the tag */
- } else if (protocol == __constant_htons(ETH_P_8021Q)) {
+ } else if (protocol == htons(ETH_P_8021Q)) {
struct vlan_hdr *vhdr, _vhdr;
vhdr = skb_header_pointer(skb, ETH_HLEN, sizeof(_vhdr), &_vhdr);
if (!vhdr)
@@ -6974,9 +7045,9 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
tx_flags |= IXGBE_TX_FLAGS_SW_VLAN;
}
- skb_tx_timestamp(skb);
-
- if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
+ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
+ !test_and_set_bit_lock(__IXGBE_PTP_TX_IN_PROGRESS,
+ &adapter->state))) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_flags |= IXGBE_TX_FLAGS_TSTAMP;
@@ -6986,6 +7057,8 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
schedule_work(&adapter->ptp_tx_work);
}
+ skb_tx_timestamp(skb);
+
#ifdef CONFIG_PCI_IOV
/*
* Use the l2switch_enable flag - would be false if the DMA
@@ -7021,7 +7094,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
#ifdef IXGBE_FCOE
/* setup tx offload for FCoE */
- if ((protocol == __constant_htons(ETH_P_FCOE)) &&
+ if ((protocol == htons(ETH_P_FCOE)) &&
(tx_ring->netdev->features & (NETIF_F_FSO | NETIF_F_FCOE_CRC))) {
tso = ixgbe_fso(tx_ring, first, &hdr_len);
if (tso < 0)
@@ -7143,7 +7216,9 @@ static int ixgbe_ioctl(struct net_device *netdev, struct ifreq *req, int cmd)
switch (cmd) {
case SIOCSHWTSTAMP:
- return ixgbe_ptp_hwtstamp_ioctl(adapter, req, cmd);
+ return ixgbe_ptp_set_ts_config(adapter, req);
+ case SIOCGHWTSTAMP:
+ return ixgbe_ptp_get_ts_config(adapter, req);
default:
return mdio_mii_ioctl(&adapter->hw.phy.mdio, if_mii(req), cmd);
}
@@ -7234,10 +7309,10 @@ static struct rtnl_link_stats64 *ixgbe_get_stats64(struct net_device *netdev,
if (ring) {
do {
- start = u64_stats_fetch_begin_bh(&ring->syncp);
+ start = u64_stats_fetch_begin_irq(&ring->syncp);
packets = ring->stats.packets;
bytes = ring->stats.bytes;
- } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
stats->rx_packets += packets;
stats->rx_bytes += bytes;
}
@@ -7250,10 +7325,10 @@ static struct rtnl_link_stats64 *ixgbe_get_stats64(struct net_device *netdev,
if (ring) {
do {
- start = u64_stats_fetch_begin_bh(&ring->syncp);
+ start = u64_stats_fetch_begin_irq(&ring->syncp);
packets = ring->stats.packets;
bytes = ring->stats.bytes;
- } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
stats->tx_packets += packets;
stats->tx_bytes += bytes;
}
@@ -7792,6 +7867,7 @@ int ixgbe_wol_supported(struct ixgbe_adapter *adapter, u16 device_id,
case IXGBE_DEV_ID_82599_SFP:
/* Only these subdevices could supports WOL */
switch (subdevice_id) {
+ case IXGBE_SUBDEV_ID_82599_SFP_WOL0:
case IXGBE_SUBDEV_ID_82599_560FLR:
/* only support first port */
if (hw->bus.func != 0)
@@ -7969,10 +8045,6 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto err_sw_init;
- /* Cache if MNG FW is up so we don't have to read the REG later */
- if (hw->mac.ops.mng_fw_enabled)
- hw->mng_fw_enabled = hw->mac.ops.mng_fw_enabled(hw);
-
/* Make it possible the adapter to be woken up via WOL */
switch (adapter->hw.mac.type) {
case ixgbe_mac_82599EB:
@@ -8223,7 +8295,7 @@ skip_sriov:
ixgbe_dbg_adapter_init(adapter);
/* Need link setup for MNG FW, else wait for IXGBE_UP */
- if (hw->mng_fw_enabled && hw->mac.ops.setup_link)
+ if (ixgbe_mng_enabled(hw) && hw->mac.ops.setup_link)
hw->mac.ops.setup_link(hw,
IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
true);
@@ -8244,7 +8316,8 @@ err_alloc_etherdev:
pci_select_bars(pdev, IORESOURCE_MEM));
err_pci_reg:
err_dma:
- pci_disable_device(pdev);
+ if (!test_and_set_bit(__IXGBE_DISABLED, &adapter->state))
+ pci_disable_device(pdev);
return err;
}
@@ -8313,7 +8386,8 @@ static void ixgbe_remove(struct pci_dev *pdev)
pci_disable_pcie_error_reporting(pdev);
- pci_disable_device(pdev);
+ if (!test_and_set_bit(__IXGBE_DISABLED, &adapter->state))
+ pci_disable_device(pdev);
}
/**
@@ -8331,6 +8405,7 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
struct net_device *netdev = adapter->netdev;
#ifdef CONFIG_PCI_IOV
+ struct ixgbe_hw *hw = &adapter->hw;
struct pci_dev *bdev, *vfdev;
u32 dw0, dw1, dw2, dw3;
int vf, pos;
@@ -8351,10 +8426,12 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
if (!pos)
goto skip_bad_vf_detection;
- pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG, &dw0);
- pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG + 4, &dw1);
- pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG + 8, &dw2);
- pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG + 12, &dw3);
+ dw0 = ixgbe_read_pci_cfg_dword(hw, pos + PCI_ERR_HEADER_LOG);
+ dw1 = ixgbe_read_pci_cfg_dword(hw, pos + PCI_ERR_HEADER_LOG + 4);
+ dw2 = ixgbe_read_pci_cfg_dword(hw, pos + PCI_ERR_HEADER_LOG + 8);
+ dw3 = ixgbe_read_pci_cfg_dword(hw, pos + PCI_ERR_HEADER_LOG + 12);
+ if (ixgbe_removed(hw->hw_addr))
+ goto skip_bad_vf_detection;
req_id = dw1 >> 16;
/* On the 82599 if bit 7 of the requestor ID is set then it's a VF */
@@ -8417,14 +8494,20 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
skip_bad_vf_detection:
#endif /* CONFIG_PCI_IOV */
+ rtnl_lock();
netif_device_detach(netdev);
- if (state == pci_channel_io_perm_failure)
+ if (state == pci_channel_io_perm_failure) {
+ rtnl_unlock();
return PCI_ERS_RESULT_DISCONNECT;
+ }
if (netif_running(netdev))
ixgbe_down(adapter);
- pci_disable_device(pdev);
+
+ if (!test_and_set_bit(__IXGBE_DISABLED, &adapter->state))
+ pci_disable_device(pdev);
+ rtnl_unlock();
/* Request a slot reset. */
return PCI_ERS_RESULT_NEED_RESET;
@@ -8446,6 +8529,9 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
e_err(probe, "Cannot re-enable PCI device after reset.\n");
result = PCI_ERS_RESULT_DISCONNECT;
} else {
+ smp_mb__before_clear_bit();
+ clear_bit(__IXGBE_DISABLED, &adapter->state);
+ adapter->hw.hw_addr = adapter->io_addr;
pci_set_master(pdev);
pci_restore_state(pdev);
pci_save_state(pdev);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
index cc3101afd29f..f5c6af2b891b 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
index e44ff47659b5..a9b9ad69ed0e 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
index 132557c318f8..23f765263f12 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
+ Copyright(c) 1999 - 2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
@@ -98,6 +99,32 @@ s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw)
}
/**
+ * ixgbe_check_reset_blocked - check status of MNG FW veto bit
+ * @hw: pointer to the hardware structure
+ *
+ * This function checks the MMNGC.MNG_VETO bit to see if there are
+ * any constraints on link from manageability. For MAC's that don't
+ * have this bit just return false since the link can not be blocked
+ * via this method.
+ **/
+bool ixgbe_check_reset_blocked(struct ixgbe_hw *hw)
+{
+ u32 mmngc;
+
+ /* If we don't have this bit, it can't be blocking */
+ if (hw->mac.type == ixgbe_mac_82598EB)
+ return false;
+
+ mmngc = IXGBE_READ_REG(hw, IXGBE_MMNGC);
+ if (mmngc & IXGBE_MMNGC_MNG_VETO) {
+ hw_dbg(hw, "MNG_VETO bit detected.\n");
+ return true;
+ }
+
+ return false;
+}
+
+/**
* ixgbe_get_phy_id - Get the phy type
* @hw: pointer to hardware structure
*
@@ -172,6 +199,10 @@ s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw)
(IXGBE_ERR_OVERTEMP == hw->phy.ops.check_overtemp(hw)))
goto out;
+ /* Blocked by MNG FW so bail */
+ if (ixgbe_check_reset_blocked(hw))
+ goto out;
+
/*
* Perform soft PHY reset to the PHY_XS.
* This will cause a soft reset to the PHY
@@ -476,6 +507,10 @@ s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw)
autoneg_reg);
}
+ /* Blocked by MNG FW so don't reset PHY */
+ if (ixgbe_check_reset_blocked(hw))
+ return status;
+
/* Restart PHY autonegotiation and wait for completion */
hw->phy.ops.read_reg(hw, MDIO_CTRL1,
MDIO_MMD_AN, &autoneg_reg);
@@ -682,6 +717,10 @@ s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw)
autoneg_reg);
}
+ /* Blocked by MNG FW so don't reset PHY */
+ if (ixgbe_check_reset_blocked(hw))
+ return status;
+
/* Restart PHY autonegotiation and wait for completion */
hw->phy.ops.read_reg(hw, MDIO_CTRL1,
MDIO_MMD_AN, &autoneg_reg);
@@ -759,6 +798,10 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw)
s32 ret_val = 0;
u32 i;
+ /* Blocked by MNG FW so bail */
+ if (ixgbe_check_reset_blocked(hw))
+ goto out;
+
hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS, &phy_data);
/* reset the PHY and poll for completion */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
index fffcbdd2bf0e..0bb047f751c2 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
+ Copyright(c) 1999 - 2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
@@ -65,9 +66,6 @@
#define IXGBE_SFF_1GBASET_CAPABLE 0x8
#define IXGBE_SFF_10GBASESR_CAPABLE 0x10
#define IXGBE_SFF_10GBASELR_CAPABLE 0x20
-#define IXGBE_SFF_SOFT_RS_SELECT_MASK 0x8
-#define IXGBE_SFF_SOFT_RS_SELECT_10G 0x8
-#define IXGBE_SFF_SOFT_RS_SELECT_1G 0x0
#define IXGBE_SFF_ADDRESSING_MODE 0x4
#define IXGBE_SFF_QSFP_DA_ACTIVE_CABLE 0x1
#define IXGBE_SFF_QSFP_DA_PASSIVE_CABLE 0x8
@@ -79,7 +77,6 @@
#define IXGBE_I2C_EEPROM_STATUS_PASS 0x1
#define IXGBE_I2C_EEPROM_STATUS_FAIL 0x2
#define IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS 0x3
-
/* Flow control defines */
#define IXGBE_TAF_SYM_PAUSE 0x400
#define IXGBE_TAF_ASM_PAUSE 0x800
@@ -131,6 +128,7 @@ s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw,
ixgbe_link_speed *speed,
bool *autoneg);
+bool ixgbe_check_reset_blocked(struct ixgbe_hw *hw);
/* PHY specific */
s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
index 5184e2a1a7d8..63515a6f67fa 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
@@ -492,6 +493,7 @@ static void ixgbe_ptp_tx_hwtstamp(struct ixgbe_adapter *adapter)
dev_kfree_skb_any(adapter->ptp_tx_skb);
adapter->ptp_tx_skb = NULL;
+ clear_bit_unlock(__IXGBE_PTP_TX_IN_PROGRESS, &adapter->state);
}
/**
@@ -511,13 +513,10 @@ static void ixgbe_ptp_tx_hwtstamp_work(struct work_struct *work)
IXGBE_PTP_TX_TIMEOUT);
u32 tsynctxctl;
- /* we have to have a valid skb */
- if (!adapter->ptp_tx_skb)
- return;
-
if (timeout) {
dev_kfree_skb_any(adapter->ptp_tx_skb);
adapter->ptp_tx_skb = NULL;
+ clear_bit_unlock(__IXGBE_PTP_TX_IN_PROGRESS, &adapter->state);
e_warn(drv, "clearing Tx Timestamp hang");
return;
}
@@ -576,14 +575,21 @@ void __ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
shhwtstamps->hwtstamp = ns_to_ktime(ns);
}
+int ixgbe_ptp_get_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr)
+{
+ struct hwtstamp_config *config = &adapter->tstamp_config;
+
+ return copy_to_user(ifr->ifr_data, config,
+ sizeof(*config)) ? -EFAULT : 0;
+}
+
/**
- * ixgbe_ptp_hwtstamp_ioctl - control hardware time stamping
+ * ixgbe_ptp_set_ts_config - control hardware time stamping
* @adapter: pointer to adapter struct
* @ifreq: ioctl data
- * @cmd: particular ioctl requested
*
* Outgoing time stamping can be enabled and disabled. Play nice and
- * disable it when requested, although it shouldn't case any overhead
+ * disable it when requested, although it shouldn't cause any overhead
* when no packet needs it. At most one packet in the queue may be
* marked for time stamping, otherwise it would be impossible to tell
* for sure to which packet the hardware time stamp belongs.
@@ -599,8 +605,7 @@ void __ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
* Event mode. This more accurately tells the user what the hardware is going
* to do anyways.
*/
-int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter,
- struct ifreq *ifr, int cmd)
+int ixgbe_ptp_set_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr)
{
struct ixgbe_hw *hw = &adapter->hw;
struct hwtstamp_config config;
@@ -702,6 +707,10 @@ int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter,
regval = IXGBE_READ_REG(hw, IXGBE_TXSTMPH);
regval = IXGBE_READ_REG(hw, IXGBE_RXSTMPH);
+ /* save these settings for future reference */
+ memcpy(&adapter->tstamp_config, &config,
+ sizeof(adapter->tstamp_config));
+
return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
-EFAULT : 0;
}
@@ -809,6 +818,9 @@ void ixgbe_ptp_reset(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(hw, IXGBE_SYSTIMH, 0x00000000);
IXGBE_WRITE_FLUSH(hw);
+ /* Reset the saved tstamp_config */
+ memset(&adapter->tstamp_config, 0, sizeof(adapter->tstamp_config));
+
ixgbe_ptp_start_cyclecounter(adapter);
spin_lock_irqsave(&adapter->tmreg_lock, flags);
@@ -840,7 +852,9 @@ void ixgbe_ptp_init(struct ixgbe_adapter *adapter)
switch (adapter->hw.mac.type) {
case ixgbe_mac_X540:
- snprintf(adapter->ptp_caps.name, 16, "%s", netdev->name);
+ snprintf(adapter->ptp_caps.name,
+ sizeof(adapter->ptp_caps.name),
+ "%s", netdev->name);
adapter->ptp_caps.owner = THIS_MODULE;
adapter->ptp_caps.max_adj = 250000000;
adapter->ptp_caps.n_alarm = 0;
@@ -854,7 +868,9 @@ void ixgbe_ptp_init(struct ixgbe_adapter *adapter)
adapter->ptp_caps.enable = ixgbe_ptp_enable;
break;
case ixgbe_mac_82599EB:
- snprintf(adapter->ptp_caps.name, 16, "%s", netdev->name);
+ snprintf(adapter->ptp_caps.name,
+ sizeof(adapter->ptp_caps.name),
+ "%s", netdev->name);
adapter->ptp_caps.owner = THIS_MODULE;
adapter->ptp_caps.max_adj = 250000000;
adapter->ptp_caps.n_alarm = 0;
@@ -911,6 +927,7 @@ void ixgbe_ptp_stop(struct ixgbe_adapter *adapter)
if (adapter->ptp_tx_skb) {
dev_kfree_skb_any(adapter->ptp_tx_skb);
adapter->ptp_tx_skb = NULL;
+ clear_bit_unlock(__IXGBE_PTP_TX_IN_PROGRESS, &adapter->state);
}
if (adapter->ptp_clock) {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
index dff0977876f7..e6c68d396c99 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h
index 8bd29190514e..139eaddfb2ed 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
index e74ae3682733..ef6df3d6437e 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
index 0d39cfc4a3bf..8a6ff2423f07 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2013 Intel Corporation.
+ Copyright(c) 1999 - 2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
@@ -54,6 +55,7 @@
#define IXGBE_DEV_ID_82599_BACKPLANE_FCOE 0x152a
#define IXGBE_DEV_ID_82599_SFP_FCOE 0x1529
#define IXGBE_SUBDEV_ID_82599_SFP 0x11A9
+#define IXGBE_SUBDEV_ID_82599_SFP_WOL0 0x1071
#define IXGBE_SUBDEV_ID_82599_RNDC 0x1F72
#define IXGBE_SUBDEV_ID_82599_560FLR 0x17D0
#define IXGBE_SUBDEV_ID_82599_SP_560FLR 0x211B
@@ -1609,6 +1611,9 @@ enum {
#define IXGBE_MACC_FS 0x00040000
#define IXGBE_MAC_RX2TX_LPBK 0x00000002
+/* Veto Bit definiton */
+#define IXGBE_MMNGC_MNG_VETO 0x00000001
+
/* LINKS Bit Masks */
#define IXGBE_LINKS_KX_AN_COMP 0x80000000
#define IXGBE_LINKS_UP 0x40000000
@@ -1788,6 +1793,9 @@ enum {
#define IXGBE_EEPROM_RD_BUFFER_MAX_COUNT 512 /* EEPROM words # read in burst */
#define IXGBE_EEPROM_WR_BUFFER_MAX_COUNT 256 /* EEPROM words # wr in burst */
+#define IXGBE_EEPROM_CTRL_2 1 /* EEPROM CTRL word 2 */
+#define IXGBE_EEPROM_CCD_BIT 2 /* EEPROM Core Clock Disable bit */
+
#ifndef IXGBE_EEPROM_GRANT_ATTEMPTS
#define IXGBE_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
#endif
@@ -1853,8 +1861,19 @@ enum {
#define IXGBE_PCI_HEADER_TYPE_MULTIFUNC 0x80
#define IXGBE_PCI_DEVICE_CONTROL2_16ms 0x0005
+#define IXGBE_PCIDEVCTRL2_TIMEO_MASK 0xf
+#define IXGBE_PCIDEVCTRL2_16_32ms_def 0x0
+#define IXGBE_PCIDEVCTRL2_50_100us 0x1
+#define IXGBE_PCIDEVCTRL2_1_2ms 0x2
+#define IXGBE_PCIDEVCTRL2_16_32ms 0x5
+#define IXGBE_PCIDEVCTRL2_65_130ms 0x6
+#define IXGBE_PCIDEVCTRL2_260_520ms 0x9
+#define IXGBE_PCIDEVCTRL2_1_2s 0xa
+#define IXGBE_PCIDEVCTRL2_4_8s 0xd
+#define IXGBE_PCIDEVCTRL2_17_34s 0xe
+
/* Number of 100 microseconds we wait for PCI Express master disable */
-#define IXGBE_PCI_MASTER_DISABLE_TIMEOUT 800
+#define IXGBE_PCI_MASTER_DISABLE_TIMEOUT 800
/* RAH */
#define IXGBE_RAH_VIND_MASK 0x003C0000
@@ -2645,7 +2664,6 @@ enum ixgbe_sfp_type {
enum ixgbe_media_type {
ixgbe_media_type_unknown = 0,
ixgbe_media_type_fiber,
- ixgbe_media_type_fiber_fixed,
ixgbe_media_type_fiber_qsfp,
ixgbe_media_type_fiber_lco,
ixgbe_media_type_copper,
@@ -2858,6 +2876,8 @@ struct ixgbe_mac_operations {
s32 (*enable_rx_dma)(struct ixgbe_hw *, u32);
s32 (*acquire_swfw_sync)(struct ixgbe_hw *, u16);
void (*release_swfw_sync)(struct ixgbe_hw *, u16);
+ s32 (*prot_autoc_read)(struct ixgbe_hw *, bool *, u32 *);
+ s32 (*prot_autoc_write)(struct ixgbe_hw *, u32, bool);
/* Link */
void (*disable_tx_laser)(struct ixgbe_hw *);
@@ -2901,7 +2921,6 @@ struct ixgbe_mac_operations {
s32 (*set_fw_drv_ver)(struct ixgbe_hw *, u8, u8, u8, u8);
s32 (*get_thermal_sensor_data)(struct ixgbe_hw *);
s32 (*init_thermal_sensor_thresh)(struct ixgbe_hw *hw);
- bool (*mng_fw_enabled)(struct ixgbe_hw *hw);
};
struct ixgbe_phy_operations {
@@ -2957,7 +2976,6 @@ struct ixgbe_mac_info {
u32 max_tx_queues;
u32 max_rx_queues;
u32 orig_autoc;
- u32 cached_autoc;
u32 orig_autoc2;
bool orig_link_settings_stored;
bool autotry_restart;
@@ -3033,7 +3051,6 @@ struct ixgbe_hw {
bool adapter_stopped;
bool force_full_reset;
bool allow_unsupported_sfp;
- bool mng_fw_enabled;
bool wol_enabled;
};
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
index 24b80a6cfca4..188a5974b85c 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
@@ -20,6 +20,7 @@
the file called "COPYING".
Contact Information:
+ Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
@@ -61,6 +62,7 @@ static s32 ixgbe_get_invariants_X540(struct ixgbe_hw *hw)
mac->mcft_size = IXGBE_X540_MC_TBL_SIZE;
mac->vft_size = IXGBE_X540_VFT_TBL_SIZE;
mac->num_rar_entries = IXGBE_X540_RAR_ENTRIES;
+ mac->rx_pb_size = IXGBE_X540_RX_PB_SIZE;
mac->max_rx_queues = IXGBE_X540_MAX_RX_QUEUES;
mac->max_tx_queues = IXGBE_X540_MAX_TX_QUEUES;
mac->max_msix_vectors = ixgbe_get_pcie_msix_count_generic(hw);
@@ -187,7 +189,6 @@ static s32 ixgbe_start_hw_X540(struct ixgbe_hw *hw)
goto out;
ret_val = ixgbe_start_hw_gen2(hw);
- hw->mac.rx_pb_size = IXGBE_X540_RX_PB_SIZE;
out:
return ret_val;
}
@@ -854,7 +855,8 @@ static struct ixgbe_mac_operations mac_ops_X540 = {
.enable_rx_buff = &ixgbe_enable_rx_buff_generic,
.get_thermal_sensor_data = NULL,
.init_thermal_sensor_thresh = NULL,
- .mng_fw_enabled = NULL,
+ .prot_autoc_read = &prot_autoc_read_generic,
+ .prot_autoc_write = &prot_autoc_write_generic,
};
static struct ixgbe_eeprom_operations eeprom_ops_X540 = {
diff --git a/drivers/net/ethernet/intel/ixgbevf/ethtool.c b/drivers/net/ethernet/intel/ixgbevf/ethtool.c
index f68b78c732a8..1baecb60f065 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ethtool.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 82599 Virtual Function driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -530,41 +530,55 @@ static const u32 register_test_patterns[] = {
0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF
};
-#define REG_PATTERN_TEST(R, M, W) \
-{ \
- u32 pat, val, before; \
- for (pat = 0; pat < ARRAY_SIZE(register_test_patterns); pat++) { \
- before = readl(adapter->hw.hw_addr + R); \
- writel((register_test_patterns[pat] & W), \
- (adapter->hw.hw_addr + R)); \
- val = readl(adapter->hw.hw_addr + R); \
- if (val != (register_test_patterns[pat] & W & M)) { \
- hw_dbg(&adapter->hw, \
- "pattern test reg %04X failed: got " \
- "0x%08X expected 0x%08X\n", \
- R, val, (register_test_patterns[pat] & W & M)); \
- *data = R; \
- writel(before, adapter->hw.hw_addr + R); \
- return 1; \
- } \
- writel(before, adapter->hw.hw_addr + R); \
- } \
+static bool reg_pattern_test(struct ixgbevf_adapter *adapter, u64 *data,
+ int reg, u32 mask, u32 write)
+{
+ u32 pat, val, before;
+
+ if (IXGBE_REMOVED(adapter->hw.hw_addr)) {
+ *data = 1;
+ return true;
+ }
+ for (pat = 0; pat < ARRAY_SIZE(register_test_patterns); pat++) {
+ before = ixgbevf_read_reg(&adapter->hw, reg);
+ ixgbe_write_reg(&adapter->hw, reg,
+ register_test_patterns[pat] & write);
+ val = ixgbevf_read_reg(&adapter->hw, reg);
+ if (val != (register_test_patterns[pat] & write & mask)) {
+ hw_dbg(&adapter->hw,
+ "pattern test reg %04X failed: got 0x%08X expected 0x%08X\n",
+ reg, val,
+ register_test_patterns[pat] & write & mask);
+ *data = reg;
+ ixgbe_write_reg(&adapter->hw, reg, before);
+ return true;
+ }
+ ixgbe_write_reg(&adapter->hw, reg, before);
+ }
+ return false;
}
-#define REG_SET_AND_CHECK(R, M, W) \
-{ \
- u32 val, before; \
- before = readl(adapter->hw.hw_addr + R); \
- writel((W & M), (adapter->hw.hw_addr + R)); \
- val = readl(adapter->hw.hw_addr + R); \
- if ((W & M) != (val & M)) { \
- pr_err("set/check reg %04X test failed: got 0x%08X expected " \
- "0x%08X\n", R, (val & M), (W & M)); \
- *data = R; \
- writel(before, (adapter->hw.hw_addr + R)); \
- return 1; \
- } \
- writel(before, (adapter->hw.hw_addr + R)); \
+static bool reg_set_and_check(struct ixgbevf_adapter *adapter, u64 *data,
+ int reg, u32 mask, u32 write)
+{
+ u32 val, before;
+
+ if (IXGBE_REMOVED(adapter->hw.hw_addr)) {
+ *data = 1;
+ return true;
+ }
+ before = ixgbevf_read_reg(&adapter->hw, reg);
+ ixgbe_write_reg(&adapter->hw, reg, write & mask);
+ val = ixgbevf_read_reg(&adapter->hw, reg);
+ if ((write & mask) != (val & mask)) {
+ pr_err("set/check reg %04X test failed: got 0x%08X expected 0x%08X\n",
+ reg, (val & mask), write & mask);
+ *data = reg;
+ ixgbe_write_reg(&adapter->hw, reg, before);
+ return true;
+ }
+ ixgbe_write_reg(&adapter->hw, reg, before);
+ return false;
}
static int ixgbevf_reg_test(struct ixgbevf_adapter *adapter, u64 *data)
@@ -572,6 +586,12 @@ static int ixgbevf_reg_test(struct ixgbevf_adapter *adapter, u64 *data)
const struct ixgbevf_reg_test *test;
u32 i;
+ if (IXGBE_REMOVED(adapter->hw.hw_addr)) {
+ dev_err(&adapter->pdev->dev,
+ "Adapter removed - register test blocked\n");
+ *data = 1;
+ return 1;
+ }
test = reg_test_vf;
/*
@@ -580,38 +600,47 @@ static int ixgbevf_reg_test(struct ixgbevf_adapter *adapter, u64 *data)
*/
while (test->reg) {
for (i = 0; i < test->array_len; i++) {
+ bool b = false;
+
switch (test->test_type) {
case PATTERN_TEST:
- REG_PATTERN_TEST(test->reg + (i * 0x40),
- test->mask,
- test->write);
+ b = reg_pattern_test(adapter, data,
+ test->reg + (i * 0x40),
+ test->mask,
+ test->write);
break;
case SET_READ_TEST:
- REG_SET_AND_CHECK(test->reg + (i * 0x40),
- test->mask,
- test->write);
+ b = reg_set_and_check(adapter, data,
+ test->reg + (i * 0x40),
+ test->mask,
+ test->write);
break;
case WRITE_NO_TEST:
- writel(test->write,
- (adapter->hw.hw_addr + test->reg)
- + (i * 0x40));
+ ixgbe_write_reg(&adapter->hw,
+ test->reg + (i * 0x40),
+ test->write);
break;
case TABLE32_TEST:
- REG_PATTERN_TEST(test->reg + (i * 4),
- test->mask,
- test->write);
+ b = reg_pattern_test(adapter, data,
+ test->reg + (i * 4),
+ test->mask,
+ test->write);
break;
case TABLE64_TEST_LO:
- REG_PATTERN_TEST(test->reg + (i * 8),
- test->mask,
- test->write);
+ b = reg_pattern_test(adapter, data,
+ test->reg + (i * 8),
+ test->mask,
+ test->write);
break;
case TABLE64_TEST_HI:
- REG_PATTERN_TEST((test->reg + 4) + (i * 8),
- test->mask,
- test->write);
+ b = reg_pattern_test(adapter, data,
+ test->reg + 4 + (i * 8),
+ test->mask,
+ test->write);
break;
}
+ if (b)
+ return 1;
}
test++;
}
@@ -626,6 +655,14 @@ static void ixgbevf_diag_test(struct net_device *netdev,
struct ixgbevf_adapter *adapter = netdev_priv(netdev);
bool if_running = netif_running(netdev);
+ if (IXGBE_REMOVED(adapter->hw.hw_addr)) {
+ dev_err(&adapter->pdev->dev,
+ "Adapter removed - test blocked\n");
+ data[0] = 1;
+ data[1] = 1;
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+ return;
+ }
set_bit(__IXGBEVF_TESTING, &adapter->state);
if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
/* Offline tests */
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
index 54829326bb09..e7e7d695816b 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 82599 Virtual Function driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -315,6 +315,11 @@ static inline u16 ixgbevf_desc_unused(struct ixgbevf_ring *ring)
return ((ntc > ntu) ? 0 : ring->count) + ntc - ntu - 1;
}
+static inline void ixgbevf_write_tail(struct ixgbevf_ring *ring, u32 value)
+{
+ writel(value, ring->tail);
+}
+
#define IXGBEVF_RX_DESC(R, i) \
(&(((union ixgbe_adv_rx_desc *)((R)->desc))[i]))
#define IXGBEVF_TX_DESC(R, i) \
@@ -401,6 +406,7 @@ struct ixgbevf_adapter {
u64 bp_tx_missed;
#endif
+ u8 __iomem *io_addr; /* Mainly for iounmap use */
u32 link_speed;
bool link_up;
@@ -412,7 +418,9 @@ struct ixgbevf_adapter {
enum ixbgevf_state_t {
__IXGBEVF_TESTING,
__IXGBEVF_RESETTING,
- __IXGBEVF_DOWN
+ __IXGBEVF_DOWN,
+ __IXGBEVF_DISABLED,
+ __IXGBEVF_REMOVING,
};
struct ixgbevf_cb {
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
index 9df28985eba7..4ba139b2d25a 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 82599 Virtual Function driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -99,6 +99,49 @@ static void ixgbevf_queue_reset_subtask(struct ixgbevf_adapter *adapter);
static void ixgbevf_set_itr(struct ixgbevf_q_vector *q_vector);
static void ixgbevf_free_all_rx_resources(struct ixgbevf_adapter *adapter);
+static void ixgbevf_remove_adapter(struct ixgbe_hw *hw)
+{
+ struct ixgbevf_adapter *adapter = hw->back;
+
+ if (!hw->hw_addr)
+ return;
+ hw->hw_addr = NULL;
+ dev_err(&adapter->pdev->dev, "Adapter removed\n");
+ schedule_work(&adapter->watchdog_task);
+}
+
+static void ixgbevf_check_remove(struct ixgbe_hw *hw, u32 reg)
+{
+ u32 value;
+
+ /* The following check not only optimizes a bit by not
+ * performing a read on the status register when the
+ * register just read was a status register read that
+ * returned IXGBE_FAILED_READ_REG. It also blocks any
+ * potential recursion.
+ */
+ if (reg == IXGBE_VFSTATUS) {
+ ixgbevf_remove_adapter(hw);
+ return;
+ }
+ value = ixgbevf_read_reg(hw, IXGBE_VFSTATUS);
+ if (value == IXGBE_FAILED_READ_REG)
+ ixgbevf_remove_adapter(hw);
+}
+
+u32 ixgbevf_read_reg(struct ixgbe_hw *hw, u32 reg)
+{
+ u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
+ u32 value;
+
+ if (IXGBE_REMOVED(reg_addr))
+ return IXGBE_FAILED_READ_REG;
+ value = readl(reg_addr + reg);
+ if (unlikely(value == IXGBE_FAILED_READ_REG))
+ ixgbevf_check_remove(hw, reg);
+ return value;
+}
+
static inline void ixgbevf_release_rx_desc(struct ixgbevf_ring *rx_ring,
u32 val)
{
@@ -111,7 +154,7 @@ static inline void ixgbevf_release_rx_desc(struct ixgbevf_ring *rx_ring,
* such as IA-64).
*/
wmb();
- writel(val, rx_ring->tail);
+ ixgbevf_write_tail(rx_ring, val);
}
/**
@@ -516,7 +559,8 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
/* Workaround hardware that can't do proper VEPA multicast
* source pruning.
*/
- if ((skb->pkt_type & (PACKET_BROADCAST | PACKET_MULTICAST)) &&
+ if ((skb->pkt_type == PACKET_BROADCAST ||
+ skb->pkt_type == PACKET_MULTICAST) &&
ether_addr_equal(rx_ring->netdev->dev_addr,
eth_hdr(skb)->h_source)) {
dev_kfree_skb_irq(skb);
@@ -607,7 +651,8 @@ static int ixgbevf_poll(struct napi_struct *napi, int budget)
napi_complete(napi);
if (adapter->rx_itr_setting & 1)
ixgbevf_set_itr(q_vector);
- if (!test_bit(__IXGBEVF_DOWN, &adapter->state))
+ if (!test_bit(__IXGBEVF_DOWN, &adapter->state) &&
+ !test_bit(__IXGBEVF_REMOVING, &adapter->state))
ixgbevf_irq_enable_queues(adapter,
1 << q_vector->v_idx);
@@ -832,7 +877,8 @@ static irqreturn_t ixgbevf_msix_other(int irq, void *data)
hw->mac.get_link_status = 1;
- if (!test_bit(__IXGBEVF_DOWN, &adapter->state))
+ if (!test_bit(__IXGBEVF_DOWN, &adapter->state) &&
+ !test_bit(__IXGBEVF_REMOVING, &adapter->state))
mod_timer(&adapter->watchdog_timer, jiffies);
IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, adapter->eims_other);
@@ -1136,7 +1182,7 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
/* reset head and tail pointers */
IXGBE_WRITE_REG(hw, IXGBE_VFTDH(reg_idx), 0);
IXGBE_WRITE_REG(hw, IXGBE_VFTDT(reg_idx), 0);
- ring->tail = hw->hw_addr + IXGBE_VFTDT(reg_idx);
+ ring->tail = adapter->io_addr + IXGBE_VFTDT(reg_idx);
/* reset ntu and ntc to place SW in sync with hardwdare */
ring->next_to_clean = 0;
@@ -1256,6 +1302,8 @@ static void ixgbevf_disable_rx_queue(struct ixgbevf_adapter *adapter,
u32 rxdctl;
u8 reg_idx = ring->reg_idx;
+ if (IXGBE_REMOVED(hw->hw_addr))
+ return;
rxdctl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(reg_idx));
rxdctl &= ~IXGBE_RXDCTL_ENABLE;
@@ -1281,6 +1329,8 @@ static void ixgbevf_rx_desc_queue_enable(struct ixgbevf_adapter *adapter,
u32 rxdctl;
u8 reg_idx = ring->reg_idx;
+ if (IXGBE_REMOVED(hw->hw_addr))
+ return;
do {
usleep_range(1000, 2000);
rxdctl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(reg_idx));
@@ -1315,7 +1365,7 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
/* reset head and tail pointers */
IXGBE_WRITE_REG(hw, IXGBE_VFRDH(reg_idx), 0);
IXGBE_WRITE_REG(hw, IXGBE_VFRDT(reg_idx), 0);
- ring->tail = hw->hw_addr + IXGBE_VFRDT(reg_idx);
+ ring->tail = adapter->io_addr + IXGBE_VFRDT(reg_idx);
/* reset ntu and ntc to place SW in sync with hardwdare */
ring->next_to_clean = 0;
@@ -1617,6 +1667,7 @@ static void ixgbevf_up_complete(struct ixgbevf_adapter *adapter)
spin_unlock_bh(&adapter->mbx_lock);
+ smp_mb__before_clear_bit();
clear_bit(__IXGBEVF_DOWN, &adapter->state);
ixgbevf_napi_enable_all(adapter);
@@ -1741,7 +1792,8 @@ void ixgbevf_down(struct ixgbevf_adapter *adapter)
int i;
/* signal that we are down to the interrupt handler */
- set_bit(__IXGBEVF_DOWN, &adapter->state);
+ if (test_and_set_bit(__IXGBEVF_DOWN, &adapter->state))
+ return; /* do nothing if already down */
/* disable all enabled rx queues */
for (i = 0; i < adapter->num_rx_queues; i++)
@@ -1817,7 +1869,6 @@ void ixgbevf_reset(struct ixgbevf_adapter *adapter)
static int ixgbevf_acquire_msix_vectors(struct ixgbevf_adapter *adapter,
int vectors)
{
- int err = 0;
int vector_threshold;
/* We'll want at least 2 (vector_threshold):
@@ -1831,33 +1882,24 @@ static int ixgbevf_acquire_msix_vectors(struct ixgbevf_adapter *adapter,
* Right now, we simply care about how many we'll get; we'll
* set them up later while requesting irq's.
*/
- while (vectors >= vector_threshold) {
- err = pci_enable_msix(adapter->pdev, adapter->msix_entries,
- vectors);
- if (!err || err < 0) /* Success or a nasty failure. */
- break;
- else /* err == number of vectors we should try again with */
- vectors = err;
- }
-
- if (vectors < vector_threshold)
- err = -ENOMEM;
+ vectors = pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+ vector_threshold, vectors);
- if (err) {
+ if (vectors < 0) {
dev_err(&adapter->pdev->dev,
"Unable to allocate MSI-X interrupts\n");
kfree(adapter->msix_entries);
adapter->msix_entries = NULL;
- } else {
- /*
- * Adjust for only the vectors we'll use, which is minimum
- * of max_msix_q_vectors + NON_Q_VECTORS, or the number of
- * vectors we were allocated.
- */
- adapter->num_msix_vectors = vectors;
+ return vectors;
}
- return err;
+ /* Adjust for only the vectors we'll use, which is minimum
+ * of max_msix_q_vectors + NON_Q_VECTORS, or the number of
+ * vectors we were allocated.
+ */
+ adapter->num_msix_vectors = vectors;
+
+ return 0;
}
/**
@@ -2338,6 +2380,7 @@ static void ixgbevf_reset_task(struct work_struct *work)
/* If we're already down or resetting, just bail */
if (test_bit(__IXGBEVF_DOWN, &adapter->state) ||
+ test_bit(__IXGBEVF_REMOVING, &adapter->state) ||
test_bit(__IXGBEVF_RESETTING, &adapter->state))
return;
@@ -2361,6 +2404,14 @@ static void ixgbevf_watchdog_task(struct work_struct *work)
bool link_up = adapter->link_up;
s32 need_reset;
+ if (IXGBE_REMOVED(hw->hw_addr)) {
+ if (!test_bit(__IXGBEVF_DOWN, &adapter->state)) {
+ rtnl_lock();
+ ixgbevf_down(adapter);
+ rtnl_unlock();
+ }
+ return;
+ }
ixgbevf_queue_reset_subtask(adapter);
adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK;
@@ -2422,7 +2473,8 @@ static void ixgbevf_watchdog_task(struct work_struct *work)
pf_has_reset:
/* Reset the timer */
- if (!test_bit(__IXGBEVF_DOWN, &adapter->state))
+ if (!test_bit(__IXGBEVF_DOWN, &adapter->state) &&
+ !test_bit(__IXGBEVF_REMOVING, &adapter->state))
mod_timer(&adapter->watchdog_timer,
round_jiffies(jiffies + (2 * HZ)));
@@ -2787,6 +2839,9 @@ static int ixgbevf_tso(struct ixgbevf_ring *tx_ring,
u32 vlan_macip_lens, type_tucmd;
u32 mss_l4len_idx, l4len;
+ if (skb->ip_summed != CHECKSUM_PARTIAL)
+ return 0;
+
if (!skb_is_gso(skb))
return 0;
@@ -2857,12 +2912,12 @@ static void ixgbevf_tx_csum(struct ixgbevf_ring *tx_ring,
if (skb->ip_summed == CHECKSUM_PARTIAL) {
u8 l4_hdr = 0;
switch (skb->protocol) {
- case __constant_htons(ETH_P_IP):
+ case htons(ETH_P_IP):
vlan_macip_lens |= skb_network_header_len(skb);
type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4;
l4_hdr = ip_hdr(skb)->protocol;
break;
- case __constant_htons(ETH_P_IPV6):
+ case htons(ETH_P_IPV6):
vlan_macip_lens |= skb_network_header_len(skb);
l4_hdr = ipv6_hdr(skb)->nexthdr;
break;
@@ -3060,7 +3115,7 @@ static void ixgbevf_tx_map(struct ixgbevf_ring *tx_ring,
tx_ring->next_to_use = i;
/* notify HW of packet */
- writel(i, tx_ring->tail);
+ ixgbevf_write_tail(tx_ring, i);
return;
dma_error:
@@ -3165,7 +3220,7 @@ static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
tso = ixgbevf_tso(tx_ring, first, &hdr_len);
if (tso < 0)
goto out_drop;
- else
+ else if (!tso)
ixgbevf_tx_csum(tx_ring, first);
ixgbevf_tx_map(tx_ring, first, hdr_len);
@@ -3274,7 +3329,8 @@ static int ixgbevf_suspend(struct pci_dev *pdev, pm_message_t state)
return retval;
#endif
- pci_disable_device(pdev);
+ if (!test_and_set_bit(__IXGBEVF_DISABLED, &adapter->state))
+ pci_disable_device(pdev);
return 0;
}
@@ -3286,7 +3342,6 @@ static int ixgbevf_resume(struct pci_dev *pdev)
struct ixgbevf_adapter *adapter = netdev_priv(netdev);
u32 err;
- pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
/*
* pci_restore_state clears dev->state_saved so call
@@ -3299,6 +3354,8 @@ static int ixgbevf_resume(struct pci_dev *pdev)
dev_err(&pdev->dev, "Cannot enable PCI device from suspend\n");
return err;
}
+ smp_mb__before_clear_bit();
+ clear_bit(__IXGBEVF_DISABLED, &adapter->state);
pci_set_master(pdev);
ixgbevf_reset(adapter);
@@ -3344,10 +3401,10 @@ static struct rtnl_link_stats64 *ixgbevf_get_stats(struct net_device *netdev,
for (i = 0; i < adapter->num_rx_queues; i++) {
ring = adapter->rx_ring[i];
do {
- start = u64_stats_fetch_begin_bh(&ring->syncp);
+ start = u64_stats_fetch_begin_irq(&ring->syncp);
bytes = ring->stats.bytes;
packets = ring->stats.packets;
- } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
stats->rx_bytes += bytes;
stats->rx_packets += packets;
}
@@ -3355,10 +3412,10 @@ static struct rtnl_link_stats64 *ixgbevf_get_stats(struct net_device *netdev,
for (i = 0; i < adapter->num_tx_queues; i++) {
ring = adapter->tx_ring[i];
do {
- start = u64_stats_fetch_begin_bh(&ring->syncp);
+ start = u64_stats_fetch_begin_irq(&ring->syncp);
bytes = ring->stats.bytes;
packets = ring->stats.packets;
- } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
stats->tx_bytes += bytes;
stats->tx_packets += packets;
}
@@ -3460,6 +3517,7 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
hw->hw_addr = ioremap(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
+ adapter->io_addr = hw->hw_addr;
if (!hw->hw_addr) {
err = -EIO;
goto err_ioremap;
@@ -3545,14 +3603,15 @@ err_register:
ixgbevf_clear_interrupt_scheme(adapter);
err_sw_init:
ixgbevf_reset_interrupt_capability(adapter);
- iounmap(hw->hw_addr);
+ iounmap(adapter->io_addr);
err_ioremap:
free_netdev(netdev);
err_alloc_etherdev:
pci_release_regions(pdev);
err_pci_reg:
err_dma:
- pci_disable_device(pdev);
+ if (!test_and_set_bit(__IXGBEVF_DISABLED, &adapter->state))
+ pci_disable_device(pdev);
return err;
}
@@ -3570,7 +3629,7 @@ static void ixgbevf_remove(struct pci_dev *pdev)
struct net_device *netdev = pci_get_drvdata(pdev);
struct ixgbevf_adapter *adapter = netdev_priv(netdev);
- set_bit(__IXGBEVF_DOWN, &adapter->state);
+ set_bit(__IXGBEVF_REMOVING, &adapter->state);
del_timer_sync(&adapter->watchdog_timer);
@@ -3583,14 +3642,15 @@ static void ixgbevf_remove(struct pci_dev *pdev)
ixgbevf_clear_interrupt_scheme(adapter);
ixgbevf_reset_interrupt_capability(adapter);
- iounmap(adapter->hw.hw_addr);
+ iounmap(adapter->io_addr);
pci_release_regions(pdev);
hw_dbg(&adapter->hw, "Remove complete\n");
free_netdev(netdev);
- pci_disable_device(pdev);
+ if (!test_and_set_bit(__IXGBEVF_DISABLED, &adapter->state))
+ pci_disable_device(pdev);
}
/**
@@ -3607,15 +3667,20 @@ static pci_ers_result_t ixgbevf_io_error_detected(struct pci_dev *pdev,
struct net_device *netdev = pci_get_drvdata(pdev);
struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ rtnl_lock();
netif_device_detach(netdev);
- if (state == pci_channel_io_perm_failure)
+ if (state == pci_channel_io_perm_failure) {
+ rtnl_unlock();
return PCI_ERS_RESULT_DISCONNECT;
+ }
if (netif_running(netdev))
ixgbevf_down(adapter);
- pci_disable_device(pdev);
+ if (!test_and_set_bit(__IXGBEVF_DISABLED, &adapter->state))
+ pci_disable_device(pdev);
+ rtnl_unlock();
/* Request a slot slot reset. */
return PCI_ERS_RESULT_NEED_RESET;
@@ -3639,6 +3704,8 @@ static pci_ers_result_t ixgbevf_io_slot_reset(struct pci_dev *pdev)
return PCI_ERS_RESULT_DISCONNECT;
}
+ smp_mb__before_clear_bit();
+ clear_bit(__IXGBEVF_DISABLED, &adapter->state);
pci_set_master(pdev);
ixgbevf_reset(adapter);
diff --git a/drivers/net/ethernet/intel/ixgbevf/regs.h b/drivers/net/ethernet/intel/ixgbevf/regs.h
index debd8c0e1f28..09dd8f698bea 100644
--- a/drivers/net/ethernet/intel/ixgbevf/regs.h
+++ b/drivers/net/ethernet/intel/ixgbevf/regs.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 82599 Virtual Function driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -70,16 +70,6 @@
#define IXGBE_VFGOTC_MSB 0x02024
#define IXGBE_VFMPRC 0x01034
-#define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
-
-#define IXGBE_READ_REG(a, reg) readl((a)->hw_addr + (reg))
-
-#define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) ( \
- writel((value), ((a)->hw_addr + (reg) + ((offset) << 2))))
-
-#define IXGBE_READ_REG_ARRAY(a, reg, offset) ( \
- readl((a)->hw_addr + (reg) + ((offset) << 2)))
-
#define IXGBE_WRITE_FLUSH(a) (IXGBE_READ_REG(a, IXGBE_VFSTATUS))
#endif /* _IXGBEVF_REGS_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbevf/vf.h b/drivers/net/ethernet/intel/ixgbevf/vf.h
index 7b1f502d1716..3061d1890471 100644
--- a/drivers/net/ethernet/intel/ixgbevf/vf.h
+++ b/drivers/net/ethernet/intel/ixgbevf/vf.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 82599 Virtual Function driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2014 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -172,6 +172,37 @@ struct ixgbevf_info {
const struct ixgbe_mac_operations *mac_ops;
};
+#define IXGBE_FAILED_READ_REG 0xffffffffU
+
+#define IXGBE_REMOVED(a) unlikely(!(a))
+
+static inline void ixgbe_write_reg(struct ixgbe_hw *hw, u32 reg, u32 value)
+{
+ u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
+
+ if (IXGBE_REMOVED(reg_addr))
+ return;
+ writel(value, reg_addr + reg);
+}
+#define IXGBE_WRITE_REG(h, r, v) ixgbe_write_reg(h, r, v)
+
+u32 ixgbevf_read_reg(struct ixgbe_hw *hw, u32 reg);
+#define IXGBE_READ_REG(h, r) ixgbevf_read_reg(h, r)
+
+static inline void ixgbe_write_reg_array(struct ixgbe_hw *hw, u32 reg,
+ u32 offset, u32 value)
+{
+ ixgbe_write_reg(hw, reg + (offset << 2), value);
+}
+#define IXGBE_WRITE_REG_ARRAY(h, r, o, v) ixgbe_write_reg_array(h, r, o, v)
+
+static inline u32 ixgbe_read_reg_array(struct ixgbe_hw *hw, u32 reg,
+ u32 offset)
+{
+ return ixgbevf_read_reg(hw, reg + (offset << 2));
+}
+#define IXGBE_READ_REG_ARRAY(h, r, o) ixgbe_read_reg_array(h, r, o)
+
void ixgbevf_rlpml_set_vf(struct ixgbe_hw *hw, u16 max_size);
int ixgbevf_negotiate_api_version(struct ixgbe_hw *hw, int api);
int ixgbevf_get_queues(struct ixgbe_hw *hw, unsigned int *num_tcs,
diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c
index f5685c0d0579..b0c6050479eb 100644
--- a/drivers/net/ethernet/jme.c
+++ b/drivers/net/ethernet/jme.c
@@ -2054,19 +2054,6 @@ jme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx)
}
static int
-jme_expand_header(struct jme_adapter *jme, struct sk_buff *skb)
-{
- if (unlikely(skb_shinfo(skb)->gso_size &&
- skb_header_cloned(skb) &&
- pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) {
- dev_kfree_skb(skb);
- return -1;
- }
-
- return 0;
-}
-
-static int
jme_tx_tso(struct sk_buff *skb, __le16 *mss, u8 *flags)
{
*mss = cpu_to_le16(skb_shinfo(skb)->gso_size << TXDESC_MSS_SHIFT);
@@ -2225,7 +2212,8 @@ jme_start_xmit(struct sk_buff *skb, struct net_device *netdev)
struct jme_adapter *jme = netdev_priv(netdev);
int idx;
- if (unlikely(jme_expand_header(jme, skb))) {
+ if (unlikely(skb_is_gso(skb) && skb_cow_head(skb, 0))) {
+ dev_kfree_skb_any(skb);
++(NET_STAT(jme).tx_dropped);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c
index 8f9266c64c75..fd4b6aecf6ee 100644
--- a/drivers/net/ethernet/lantiq_etop.c
+++ b/drivers/net/ethernet/lantiq_etop.c
@@ -619,7 +619,7 @@ ltq_etop_set_multicast_list(struct net_device *dev)
static u16
ltq_etop_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv, select_queue_fallback_t fallback)
{
/* we are currently only using the first queue */
return 0;
diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig
index 6300fd27f2db..68e6a6613e9a 100644
--- a/drivers/net/ethernet/marvell/Kconfig
+++ b/drivers/net/ethernet/marvell/Kconfig
@@ -43,12 +43,12 @@ config MVMDIO
This driver is used by the MV643XX_ETH and MVNETA drivers.
config MVNETA
- tristate "Marvell Armada 370/XP network interface support"
- depends on MACH_ARMADA_370_XP
+ tristate "Marvell Armada 370/38x/XP network interface support"
+ depends on PLAT_ORION
select MVMDIO
---help---
This driver supports the network interface units in the
- Marvell ARMADA XP and ARMADA 370 SoC family.
+ Marvell ARMADA XP, ARMADA 370 and ARMADA 38x SoC family.
Note that this driver is distinct from the mv643xx_eth
driver, which should be used for the older Marvell SoCs
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index a2565ce22b7c..b7b8d74c22d9 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -730,7 +730,7 @@ static int txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb)
unlikely(tag_bytes & ~12)) {
if (skb_checksum_help(skb) == 0)
goto no_csum;
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return 1;
}
@@ -819,7 +819,7 @@ static netdev_tx_t mv643xx_eth_xmit(struct sk_buff *skb, struct net_device *dev)
if (txq->tx_ring_size - txq->tx_desc_count < MAX_SKB_FRAGS + 1) {
if (net_ratelimit())
netdev_err(dev, "tx queue full?!\n");
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c
index fd409d76b811..b161a525fc5b 100644
--- a/drivers/net/ethernet/marvell/mvmdio.c
+++ b/drivers/net/ethernet/marvell/mvmdio.c
@@ -167,11 +167,6 @@ out:
return ret;
}
-static int orion_mdio_reset(struct mii_bus *bus)
-{
- return 0;
-}
-
static irqreturn_t orion_mdio_err_irq(int irq, void *dev_id)
{
struct orion_mdio_dev *dev = dev_id;
@@ -209,7 +204,6 @@ static int orion_mdio_probe(struct platform_device *pdev)
bus->name = "orion_mdio_bus";
bus->read = orion_mdio_read;
bus->write = orion_mdio_write;
- bus->reset = orion_mdio_reset;
snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii",
dev_name(&pdev->dev));
bus->parent = &pdev->dev;
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index f418f4f20f94..d04b1c3c9b85 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -22,6 +22,7 @@
#include <linux/interrupt.h>
#include <net/ip.h>
#include <net/ipv6.h>
+#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_mdio.h>
@@ -88,8 +89,9 @@
#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_SERDES_CFG 0x24A0
#define MVNETA_SGMII_SERDES_PROTO 0x0cc7
+#define MVNETA_RGMII_SERDES_PROTO 0x0667
#define MVNETA_TYPE_PRIO 0x24bc
#define MVNETA_FORCE_UNI BIT(21)
#define MVNETA_TXQ_CMD_1 0x24e4
@@ -161,7 +163,7 @@
#define MVNETA_GMAC_MAX_RX_SIZE_MASK 0x7ffc
#define MVNETA_GMAC0_PORT_ENABLE BIT(0)
#define MVNETA_GMAC_CTRL_2 0x2c08
-#define MVNETA_GMAC2_PSC_ENABLE BIT(3)
+#define MVNETA_GMAC2_PCS_ENABLE BIT(3)
#define MVNETA_GMAC2_PORT_RGMII BIT(4)
#define MVNETA_GMAC2_PORT_RESET BIT(6)
#define MVNETA_GMAC_STATUS 0x2c10
@@ -508,12 +510,12 @@ struct rtnl_link_stats64 *mvneta_get_stats64(struct net_device *dev,
cpu_stats = per_cpu_ptr(pp->stats, cpu);
do {
- start = u64_stats_fetch_begin_bh(&cpu_stats->syncp);
+ start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
rx_packets = cpu_stats->rx_packets;
rx_bytes = cpu_stats->rx_bytes;
tx_packets = cpu_stats->tx_packets;
tx_bytes = cpu_stats->tx_bytes;
- } while (u64_stats_fetch_retry_bh(&cpu_stats->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
stats->rx_packets += rx_packets;
stats->rx_bytes += rx_bytes;
@@ -710,35 +712,6 @@ static void mvneta_rxq_bm_disable(struct mvneta_port *pp,
mvreg_write(pp, MVNETA_RXQ_CONFIG_REG(rxq->id), val);
}
-
-
-/* Sets the RGMII Enable bit (RGMIIEn) in port MAC control register */
-static void mvneta_gmac_rgmii_set(struct mvneta_port *pp, int enable)
-{
- u32 val;
-
- val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
-
- if (enable)
- val |= MVNETA_GMAC2_PORT_RGMII;
- else
- val &= ~MVNETA_GMAC2_PORT_RGMII;
-
- mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
-}
-
-/* Config SGMII port */
-static void mvneta_port_sgmii_config(struct mvneta_port *pp)
-{
- u32 val;
-
- 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 */
static void mvneta_port_up(struct mvneta_port *pp)
{
@@ -2756,12 +2729,15 @@ static void mvneta_port_power_up(struct mvneta_port *pp, int phy_mode)
mvreg_write(pp, MVNETA_UNIT_INTR_CAUSE, 0);
if (phy_mode == PHY_INTERFACE_MODE_SGMII)
- mvneta_port_sgmii_config(pp);
+ mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO);
+ else
+ mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_RGMII_SERDES_PROTO);
+
+ val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
- mvneta_gmac_rgmii_set(pp, 1);
+ val |= MVNETA_GMAC2_PCS_ENABLE | MVNETA_GMAC2_PORT_RGMII;
/* Cancel Port Reset */
- val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
val &= ~MVNETA_GMAC2_PORT_RESET;
mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
@@ -2774,6 +2750,7 @@ static void mvneta_port_power_up(struct mvneta_port *pp, int phy_mode)
static int mvneta_probe(struct platform_device *pdev)
{
const struct mbus_dram_target_info *dram_target_info;
+ struct resource *res;
struct device_node *dn = pdev->dev.of_node;
struct device_node *phy_node;
u32 phy_addr;
@@ -2784,7 +2761,6 @@ static int mvneta_probe(struct platform_device *pdev)
const char *mac_from;
int phy_mode;
int err;
- int cpu;
/* Our multiqueue support is not complete, so for now, only
* allow the usage of the first RX queue
@@ -2838,23 +2814,18 @@ static int mvneta_probe(struct platform_device *pdev)
clk_prepare_enable(pp->clk);
- pp->base = of_iomap(dn, 0);
- if (pp->base == NULL) {
- err = -ENOMEM;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pp->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pp->base)) {
+ err = PTR_ERR(pp->base);
goto err_clk;
}
/* Alloc per-cpu stats */
- pp->stats = alloc_percpu(struct mvneta_pcpu_stats);
+ pp->stats = netdev_alloc_pcpu_stats(struct mvneta_pcpu_stats);
if (!pp->stats) {
err = -ENOMEM;
- goto err_unmap;
- }
-
- for_each_possible_cpu(cpu) {
- struct mvneta_pcpu_stats *stats;
- stats = per_cpu_ptr(pp->stats, cpu);
- u64_stats_init(&stats->syncp);
+ goto err_clk;
}
dt_mac_addr = of_get_mac_address(dn);
@@ -2913,8 +2884,6 @@ err_deinit:
mvneta_deinit(pp);
err_free_stats:
free_percpu(pp->stats);
-err_unmap:
- iounmap(pp->base);
err_clk:
clk_disable_unprepare(pp->clk);
err_free_irq:
@@ -2934,7 +2903,6 @@ static int mvneta_remove(struct platform_device *pdev)
mvneta_deinit(pp);
clk_disable_unprepare(pp->clk);
free_percpu(pp->stats);
- iounmap(pp->base);
irq_dispose_mapping(dev->irq);
free_netdev(dev);
diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c
index 597846193869..7f81ae66cc89 100644
--- a/drivers/net/ethernet/marvell/skge.c
+++ b/drivers/net/ethernet/marvell/skge.c
@@ -2845,7 +2845,7 @@ mapping_unwind:
mapping_error:
if (net_ratelimit())
dev_warn(&hw->pdev->dev, "%s: tx mapping error\n", dev->name);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -3172,7 +3172,7 @@ static void skge_tx_done(struct net_device *dev)
pkts_compl++;
bytes_compl += e->skb->len;
- dev_kfree_skb(e->skb);
+ dev_consume_skb_any(e->skb);
}
}
netdev_completed_queue(dev, pkts_compl, bytes_compl);
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index 55a37ae11440..b81106451a0a 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -44,6 +44,8 @@
#include <linux/prefetch.h>
#include <linux/debugfs.h>
#include <linux/mii.h>
+#include <linux/of_device.h>
+#include <linux/of_net.h>
#include <asm/irq.h>
@@ -2000,7 +2002,7 @@ mapping_unwind:
mapping_error:
if (net_ratelimit())
dev_warn(&hw->pdev->dev, "%s: tx mapping error\n", dev->name);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -2733,6 +2735,9 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
unsigned int total_bytes[2] = { 0 };
unsigned int total_packets[2] = { 0 };
+ if (to_do <= 0)
+ return work_done;
+
rmb();
do {
struct sky2_port *sky2;
@@ -3906,19 +3911,19 @@ static struct rtnl_link_stats64 *sky2_get_stats(struct net_device *dev,
u64 _bytes, _packets;
do {
- start = u64_stats_fetch_begin_bh(&sky2->rx_stats.syncp);
+ start = u64_stats_fetch_begin_irq(&sky2->rx_stats.syncp);
_bytes = sky2->rx_stats.bytes;
_packets = sky2->rx_stats.packets;
- } while (u64_stats_fetch_retry_bh(&sky2->rx_stats.syncp, start));
+ } while (u64_stats_fetch_retry_irq(&sky2->rx_stats.syncp, start));
stats->rx_packets = _packets;
stats->rx_bytes = _bytes;
do {
- start = u64_stats_fetch_begin_bh(&sky2->tx_stats.syncp);
+ start = u64_stats_fetch_begin_irq(&sky2->tx_stats.syncp);
_bytes = sky2->tx_stats.bytes;
_packets = sky2->tx_stats.packets;
- } while (u64_stats_fetch_retry_bh(&sky2->tx_stats.syncp, start));
+ } while (u64_stats_fetch_retry_irq(&sky2->tx_stats.syncp, start));
stats->tx_packets = _packets;
stats->tx_bytes = _bytes;
@@ -4748,6 +4753,7 @@ static struct net_device *sky2_init_netdev(struct sky2_hw *hw, unsigned port,
{
struct sky2_port *sky2;
struct net_device *dev = alloc_etherdev(sizeof(*sky2));
+ const void *iap;
if (!dev)
return NULL;
@@ -4805,8 +4811,16 @@ static struct net_device *sky2_init_netdev(struct sky2_hw *hw, unsigned port,
dev->features |= dev->hw_features;
- /* read the mac address */
- memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN);
+ /* try to get mac address in the following order:
+ * 1) from device tree data
+ * 2) from internal registers set by bootloader
+ */
+ iap = of_get_mac_address(hw->pdev->dev.of_node);
+ if (iap)
+ memcpy(dev->dev_addr, iap, ETH_ALEN);
+ else
+ memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8,
+ ETH_ALEN);
return dev;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/Kconfig b/drivers/net/ethernet/mellanox/mlx4/Kconfig
index 563495d8975a..1486ce902a56 100644
--- a/drivers/net/ethernet/mellanox/mlx4/Kconfig
+++ b/drivers/net/ethernet/mellanox/mlx4/Kconfig
@@ -3,7 +3,7 @@
#
config MLX4_EN
- tristate "Mellanox Technologies 10Gbit Ethernet support"
+ tristate "Mellanox Technologies 1/10/40Gbit Ethernet support"
depends on PCI
select MLX4_CORE
select PTP_1588_CLOCK
@@ -23,6 +23,13 @@ config MLX4_EN_DCB
If unsure, set to Y
+config MLX4_EN_VXLAN
+ bool "VXLAN offloads Support"
+ default y
+ depends on MLX4_EN && VXLAN && !(MLX4_EN=y && VXLAN=m)
+ ---help---
+ Say Y here if you want to use VXLAN offloads in the driver.
+
config MLX4_CORE
tristate
depends on PCI
diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c
index 0d02fba94536..78099eab7673 100644
--- a/drivers/net/ethernet/mellanox/mlx4/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c
@@ -800,16 +800,7 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave,
vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
}
-static int MLX4_CMD_UPDATE_QP_wrapper(struct mlx4_dev *dev, int slave,
- struct mlx4_vhcr *vhcr,
- struct mlx4_cmd_mailbox *inbox,
- struct mlx4_cmd_mailbox *outbox,
- struct mlx4_cmd_info *cmd)
-{
- return -EPERM;
-}
-
-static int MLX4_CMD_GET_OP_REQ_wrapper(struct mlx4_dev *dev, int slave,
+static int mlx4_CMD_EPERM_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_vhcr *vhcr,
struct mlx4_cmd_mailbox *inbox,
struct mlx4_cmd_mailbox *outbox,
@@ -964,6 +955,15 @@ static struct mlx4_cmd_info cmd_info[] = {
.wrapper = NULL
},
{
+ .opcode = MLX4_CMD_CONFIG_DEV,
+ .has_inbox = false,
+ .has_outbox = false,
+ .out_is_imm = false,
+ .encode_slave_id = false,
+ .verify = NULL,
+ .wrapper = mlx4_CMD_EPERM_wrapper
+ },
+ {
.opcode = MLX4_CMD_ALLOC_RES,
.has_inbox = false,
.has_outbox = false,
@@ -1258,7 +1258,7 @@ static struct mlx4_cmd_info cmd_info[] = {
.out_is_imm = false,
.encode_slave_id = false,
.verify = NULL,
- .wrapper = MLX4_CMD_UPDATE_QP_wrapper
+ .wrapper = mlx4_CMD_EPERM_wrapper
},
{
.opcode = MLX4_CMD_GET_OP_REQ,
@@ -1267,7 +1267,7 @@ static struct mlx4_cmd_info cmd_info[] = {
.out_is_imm = false,
.encode_slave_id = false,
.verify = NULL,
- .wrapper = MLX4_CMD_GET_OP_REQ_wrapper,
+ .wrapper = mlx4_CMD_EPERM_wrapper,
},
{
.opcode = MLX4_CMD_CONF_SPECIAL_QP,
@@ -1378,7 +1378,7 @@ static struct mlx4_cmd_info cmd_info[] = {
.out_is_imm = false,
.encode_slave_id = false,
.verify = NULL,
- .wrapper = mlx4_FLOW_STEERING_IB_UC_QP_RANGE_wrapper
+ .wrapper = mlx4_CMD_EPERM_wrapper
},
};
@@ -1643,8 +1643,16 @@ static int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave)
int port, err;
struct mlx4_vport_state *vp_admin;
struct mlx4_vport_oper_state *vp_oper;
-
- for (port = 1; port <= MLX4_MAX_PORTS; port++) {
+ struct mlx4_active_ports actv_ports = mlx4_get_active_ports(
+ &priv->dev, slave);
+ int min_port = find_first_bit(actv_ports.ports,
+ priv->dev.caps.num_ports) + 1;
+ int max_port = min_port - 1 +
+ bitmap_weight(actv_ports.ports, priv->dev.caps.num_ports);
+
+ for (port = min_port; port <= max_port; port++) {
+ if (!test_bit(port - 1, actv_ports.ports))
+ continue;
vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
vp_oper->state = *vp_admin;
@@ -1685,8 +1693,17 @@ static void mlx4_master_deactivate_admin_state(struct mlx4_priv *priv, int slave
{
int port;
struct mlx4_vport_oper_state *vp_oper;
+ struct mlx4_active_ports actv_ports = mlx4_get_active_ports(
+ &priv->dev, slave);
+ int min_port = find_first_bit(actv_ports.ports,
+ priv->dev.caps.num_ports) + 1;
+ int max_port = min_port - 1 +
+ bitmap_weight(actv_ports.ports, priv->dev.caps.num_ports);
+
- for (port = 1; port <= MLX4_MAX_PORTS; port++) {
+ for (port = min_port; port <= max_port; port++) {
+ if (!test_bit(port - 1, actv_ports.ports))
+ continue;
vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
if (NO_INDX != vp_oper->vlan_idx) {
__mlx4_unregister_vlan(&priv->dev,
@@ -2234,6 +2251,112 @@ static int mlx4_get_slave_indx(struct mlx4_dev *dev, int vf)
return vf+1;
}
+int mlx4_get_vf_indx(struct mlx4_dev *dev, int slave)
+{
+ if (slave < 1 || slave > dev->num_vfs) {
+ mlx4_err(dev,
+ "Bad slave number:%d (number of activated slaves: %lu)\n",
+ slave, dev->num_slaves);
+ return -EINVAL;
+ }
+ return slave - 1;
+}
+
+struct mlx4_active_ports mlx4_get_active_ports(struct mlx4_dev *dev, int slave)
+{
+ struct mlx4_active_ports actv_ports;
+ int vf;
+
+ bitmap_zero(actv_ports.ports, MLX4_MAX_PORTS);
+
+ if (slave == 0) {
+ bitmap_fill(actv_ports.ports, dev->caps.num_ports);
+ return actv_ports;
+ }
+
+ vf = mlx4_get_vf_indx(dev, slave);
+ if (vf < 0)
+ return actv_ports;
+
+ bitmap_set(actv_ports.ports, dev->dev_vfs[vf].min_port - 1,
+ min((int)dev->dev_vfs[mlx4_get_vf_indx(dev, slave)].n_ports,
+ dev->caps.num_ports));
+
+ return actv_ports;
+}
+EXPORT_SYMBOL_GPL(mlx4_get_active_ports);
+
+int mlx4_slave_convert_port(struct mlx4_dev *dev, int slave, int port)
+{
+ unsigned n;
+ struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave);
+ unsigned m = bitmap_weight(actv_ports.ports, dev->caps.num_ports);
+
+ if (port <= 0 || port > m)
+ return -EINVAL;
+
+ n = find_first_bit(actv_ports.ports, dev->caps.num_ports);
+ if (port <= n)
+ port = n + 1;
+
+ return port;
+}
+EXPORT_SYMBOL_GPL(mlx4_slave_convert_port);
+
+int mlx4_phys_to_slave_port(struct mlx4_dev *dev, int slave, int port)
+{
+ struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave);
+ if (test_bit(port - 1, actv_ports.ports))
+ return port -
+ find_first_bit(actv_ports.ports, dev->caps.num_ports);
+
+ return -1;
+}
+EXPORT_SYMBOL_GPL(mlx4_phys_to_slave_port);
+
+struct mlx4_slaves_pport mlx4_phys_to_slaves_pport(struct mlx4_dev *dev,
+ int port)
+{
+ unsigned i;
+ struct mlx4_slaves_pport slaves_pport;
+
+ bitmap_zero(slaves_pport.slaves, MLX4_MFUNC_MAX);
+
+ if (port <= 0 || port > dev->caps.num_ports)
+ return slaves_pport;
+
+ for (i = 0; i < dev->num_vfs + 1; i++) {
+ struct mlx4_active_ports actv_ports =
+ mlx4_get_active_ports(dev, i);
+ if (test_bit(port - 1, actv_ports.ports))
+ set_bit(i, slaves_pport.slaves);
+ }
+
+ return slaves_pport;
+}
+EXPORT_SYMBOL_GPL(mlx4_phys_to_slaves_pport);
+
+struct mlx4_slaves_pport mlx4_phys_to_slaves_pport_actv(
+ struct mlx4_dev *dev,
+ const struct mlx4_active_ports *crit_ports)
+{
+ unsigned i;
+ struct mlx4_slaves_pport slaves_pport;
+
+ bitmap_zero(slaves_pport.slaves, MLX4_MFUNC_MAX);
+
+ for (i = 0; i < dev->num_vfs + 1; i++) {
+ struct mlx4_active_ports actv_ports =
+ mlx4_get_active_ports(dev, i);
+ if (bitmap_equal(crit_ports->ports, actv_ports.ports,
+ dev->caps.num_ports))
+ set_bit(i, slaves_pport.slaves);
+ }
+
+ return slaves_pport;
+}
+EXPORT_SYMBOL_GPL(mlx4_phys_to_slaves_pport_actv);
+
int mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u64 mac)
{
struct mlx4_priv *priv = mlx4_priv(dev);
@@ -2289,6 +2412,30 @@ int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos)
}
EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan);
+ /* mlx4_get_slave_default_vlan -
+ * return true if VST ( default vlan)
+ * if VST, will return vlan & qos (if not NULL)
+ */
+bool mlx4_get_slave_default_vlan(struct mlx4_dev *dev, int port, int slave,
+ u16 *vlan, u8 *qos)
+{
+ struct mlx4_vport_oper_state *vp_oper;
+ struct mlx4_priv *priv;
+
+ priv = mlx4_priv(dev);
+ vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
+
+ if (MLX4_VGT != vp_oper->state.default_vlan) {
+ if (vlan)
+ *vlan = vp_oper->state.default_vlan;
+ if (qos)
+ *qos = vp_oper->state.default_qos;
+ return true;
+ }
+ return false;
+}
+EXPORT_SYMBOL_GPL(mlx4_get_slave_default_vlan);
+
int mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting)
{
struct mlx4_priv *priv = mlx4_priv(dev);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_clock.c b/drivers/net/ethernet/mellanox/mlx4/en_clock.c
index abaf6bb22416..57dda95b67d8 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_clock.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_clock.c
@@ -276,6 +276,7 @@ static const struct ptp_clock_info mlx4_en_ptp_clock_info = {
.n_alarm = 0,
.n_ext_ts = 0,
.n_per_out = 0,
+ .n_pins = 0,
.pps = 0,
.adjfreq = mlx4_en_phc_adjfreq,
.adjtime = mlx4_en_phc_adjtime,
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
index b4881b686159..c95ca252187c 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
@@ -62,7 +62,7 @@ static int mlx4_en_ets_validate(struct mlx4_en_priv *priv, struct ieee_ets *ets)
int has_ets_tc = 0;
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
- if (ets->prio_tc[i] > MLX4_EN_NUM_UP) {
+ if (ets->prio_tc[i] >= MLX4_EN_NUM_UP) {
en_err(priv, "Bad priority in UP <=> TC mapping. TC: %d, UP: %d\n",
i, ets->prio_tc[i]);
return -EINVAL;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c
index d357bf5a4686..0c59d4fe7e3a 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c
@@ -72,6 +72,12 @@ MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]."
MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]."
" Per priority bit mask");
+MLX4_EN_PARM_INT(inline_thold, MAX_INLINE,
+ "Threshold for using inline data (range: 17-104, default: 104)");
+
+#define MAX_PFC_TX 0xff
+#define MAX_PFC_RX 0xff
+
int en_print(const char *level, const struct mlx4_en_priv *priv,
const char *format, ...)
{
@@ -140,6 +146,7 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
params->prof[i].tx_ring_num = params->num_tx_rings_p_up *
MLX4_EN_NUM_UP;
params->prof[i].rss_rings = 0;
+ params->prof[i].inline_thold = inline_thold;
}
return 0;
@@ -274,19 +281,8 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
mlx4_en_init_timestamp(mdev);
- mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
- if (!dev->caps.comp_pool) {
- mdev->profile.prof[i].rx_ring_num =
- rounddown_pow_of_two(max_t(int, MIN_RX_RINGS,
- min_t(int,
- dev->caps.num_comp_vectors,
- DEF_RX_RINGS)));
- } else {
- mdev->profile.prof[i].rx_ring_num = rounddown_pow_of_two(
- min_t(int, dev->caps.comp_pool/
- dev->caps.num_ports - 1 , MAX_MSIX_P_PORT - 1));
- }
- }
+ /* Set default number of RX rings*/
+ mlx4_en_set_num_rx_rings(mdev);
/* Create our own workqueue for reset/multicast tasks
* Note: we cannot use the shared workqueue because of deadlocks caused
@@ -336,8 +332,31 @@ static struct mlx4_interface mlx4_en_interface = {
.protocol = MLX4_PROT_ETH,
};
+static void mlx4_en_verify_params(void)
+{
+ if (pfctx > MAX_PFC_TX) {
+ pr_warn("mlx4_en: WARNING: illegal module parameter pfctx 0x%x - should be in range 0-0x%x, will be changed to default (0)\n",
+ pfctx, MAX_PFC_TX);
+ pfctx = 0;
+ }
+
+ if (pfcrx > MAX_PFC_RX) {
+ pr_warn("mlx4_en: WARNING: illegal module parameter pfcrx 0x%x - should be in range 0-0x%x, will be changed to default (0)\n",
+ pfcrx, MAX_PFC_RX);
+ pfcrx = 0;
+ }
+
+ if (inline_thold < MIN_PKT_LEN || inline_thold > MAX_INLINE) {
+ pr_warn("mlx4_en: WARNING: illegal module parameter inline_thold %d - should be in range %d-%d, will be changed to default (%d)\n",
+ inline_thold, MIN_PKT_LEN, MAX_INLINE, MAX_INLINE);
+ inline_thold = MAX_INLINE;
+ }
+}
+
static int __init mlx4_en_init(void)
{
+ mlx4_en_verify_params();
+
return mlx4_register_interface(&mlx4_en_interface);
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index fad45316200a..f085c2df5e69 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -39,6 +39,7 @@
#include <linux/hash.h>
#include <net/ip.h>
#include <net/busy_poll.h>
+#include <net/vxlan.h>
#include <linux/mlx4/driver.h>
#include <linux/mlx4/device.h>
@@ -603,7 +604,7 @@ static int mlx4_en_get_qp(struct mlx4_en_priv *priv)
int err = 0;
u64 reg_id;
int *qpn = &priv->base_qpn;
- u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr);
+ u64 mac = mlx4_mac_to_u64(priv->dev->dev_addr);
en_dbg(DRV, priv, "Registering MAC: %pM for adding\n",
priv->dev->dev_addr);
@@ -672,7 +673,7 @@ static void mlx4_en_put_qp(struct mlx4_en_priv *priv)
u64 mac;
if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) {
- mac = mlx4_en_mac_to_u64(priv->dev->dev_addr);
+ mac = mlx4_mac_to_u64(priv->dev->dev_addr);
en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n",
priv->dev->dev_addr);
mlx4_unregister_mac(dev, priv->port, mac);
@@ -685,7 +686,7 @@ static void mlx4_en_put_qp(struct mlx4_en_priv *priv)
for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) {
bucket = &priv->mac_hash[i];
hlist_for_each_entry_safe(entry, tmp, bucket, hlist) {
- mac = mlx4_en_mac_to_u64(entry->mac);
+ mac = mlx4_mac_to_u64(entry->mac);
en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n",
entry->mac);
mlx4_en_uc_steer_release(priv, entry->mac,
@@ -715,14 +716,14 @@ static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn,
struct mlx4_en_dev *mdev = priv->mdev;
struct mlx4_dev *dev = mdev->dev;
int err = 0;
- u64 new_mac_u64 = mlx4_en_mac_to_u64(new_mac);
+ u64 new_mac_u64 = mlx4_mac_to_u64(new_mac);
if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
struct hlist_head *bucket;
unsigned int mac_hash;
struct mlx4_mac_entry *entry;
struct hlist_node *tmp;
- u64 prev_mac_u64 = mlx4_en_mac_to_u64(prev_mac);
+ u64 prev_mac_u64 = mlx4_mac_to_u64(prev_mac);
bucket = &priv->mac_hash[prev_mac[MLX4_EN_MAC_HASH_IDX]];
hlist_for_each_entry_safe(entry, tmp, bucket, hlist) {
@@ -742,6 +743,14 @@ static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn,
err = mlx4_en_uc_steer_add(priv, new_mac,
&qpn,
&entry->reg_id);
+ if (err)
+ return err;
+ if (priv->tunnel_reg_id) {
+ mlx4_flow_detach(priv->mdev->dev, priv->tunnel_reg_id);
+ priv->tunnel_reg_id = 0;
+ }
+ err = mlx4_en_tunnel_steer_add(priv, new_mac, qpn,
+ &priv->tunnel_reg_id);
return err;
}
}
@@ -751,18 +760,6 @@ static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn,
return __mlx4_replace_mac(dev, priv->port, qpn, new_mac_u64);
}
-u64 mlx4_en_mac_to_u64(u8 *addr)
-{
- u64 mac = 0;
- int i;
-
- for (i = 0; i < ETH_ALEN; i++) {
- mac <<= 8;
- mac |= addr[i];
- }
- return mac;
-}
-
static int mlx4_en_do_set_mac(struct mlx4_en_priv *priv)
{
int err = 0;
@@ -1081,7 +1078,7 @@ static void mlx4_en_do_multicast(struct mlx4_en_priv *priv,
mlx4_en_cache_mclist(dev);
netif_addr_unlock_bh(dev);
list_for_each_entry(mclist, &priv->mc_list, list) {
- mcast_addr = mlx4_en_mac_to_u64(mclist->addr);
+ mcast_addr = mlx4_mac_to_u64(mclist->addr);
mlx4_SET_MCAST_FLTR(mdev->dev, priv->port,
mcast_addr, 0, MLX4_MCAST_CONFIG);
}
@@ -1173,7 +1170,7 @@ static void mlx4_en_do_uc_filter(struct mlx4_en_priv *priv,
found = true;
if (!found) {
- mac = mlx4_en_mac_to_u64(entry->mac);
+ mac = mlx4_mac_to_u64(entry->mac);
mlx4_en_uc_steer_release(priv, entry->mac,
priv->base_qpn,
entry->reg_id);
@@ -1216,7 +1213,7 @@ static void mlx4_en_do_uc_filter(struct mlx4_en_priv *priv,
priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC;
break;
}
- mac = mlx4_en_mac_to_u64(ha->addr);
+ mac = mlx4_mac_to_u64(ha->addr);
memcpy(entry->mac, ha->addr, ETH_ALEN);
err = mlx4_register_mac(mdev->dev, priv->port, mac);
if (err < 0) {
@@ -1669,7 +1666,7 @@ int mlx4_en_start_port(struct net_device *dev)
}
if (mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) {
- err = mlx4_SET_PORT_VXLAN(mdev->dev, priv->port, VXLAN_STEER_BY_OUTER_MAC);
+ err = mlx4_SET_PORT_VXLAN(mdev->dev, priv->port, VXLAN_STEER_BY_OUTER_MAC, 1);
if (err) {
en_err(priv, "Failed setting port L2 tunnel configuration, err %d\n",
err);
@@ -1701,6 +1698,10 @@ int mlx4_en_start_port(struct net_device *dev)
mlx4_set_stats_bitmap(mdev->dev, &priv->stats_bitmap);
+#ifdef CONFIG_MLX4_EN_VXLAN
+ if (priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS)
+ vxlan_get_rx_port(dev);
+#endif
priv->port_up = true;
netif_tx_start_all_queues(dev);
netif_device_attach(dev);
@@ -1792,6 +1793,8 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)
mc_list[5] = priv->port;
mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp,
mc_list, MLX4_PROT_ETH, mclist->reg_id);
+ if (mclist->tunnel_reg_id)
+ mlx4_flow_detach(mdev->dev, mclist->tunnel_reg_id);
}
mlx4_en_clear_list(dev);
list_for_each_entry_safe(mclist, tmp, &priv->curr_list, list) {
@@ -2206,7 +2209,7 @@ static int mlx4_en_set_vf_mac(struct net_device *dev, int queue, u8 *mac)
{
struct mlx4_en_priv *en_priv = netdev_priv(dev);
struct mlx4_en_dev *mdev = en_priv->mdev;
- u64 mac_u64 = mlx4_en_mac_to_u64(mac);
+ u64 mac_u64 = mlx4_mac_to_u64(mac);
if (!is_valid_ether_addr(mac))
return -EINVAL;
@@ -2266,6 +2269,83 @@ static int mlx4_en_get_phys_port_id(struct net_device *dev,
return 0;
}
+#ifdef CONFIG_MLX4_EN_VXLAN
+static void mlx4_en_add_vxlan_offloads(struct work_struct *work)
+{
+ int ret;
+ struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
+ vxlan_add_task);
+
+ ret = mlx4_config_vxlan_port(priv->mdev->dev, priv->vxlan_port);
+ if (ret)
+ goto out;
+
+ ret = mlx4_SET_PORT_VXLAN(priv->mdev->dev, priv->port,
+ VXLAN_STEER_BY_OUTER_MAC, 1);
+out:
+ if (ret)
+ en_err(priv, "failed setting L2 tunnel configuration ret %d\n", ret);
+}
+
+static void mlx4_en_del_vxlan_offloads(struct work_struct *work)
+{
+ int ret;
+ struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
+ vxlan_del_task);
+
+ ret = mlx4_SET_PORT_VXLAN(priv->mdev->dev, priv->port,
+ VXLAN_STEER_BY_OUTER_MAC, 0);
+ if (ret)
+ en_err(priv, "failed setting L2 tunnel configuration ret %d\n", ret);
+
+ priv->vxlan_port = 0;
+}
+
+static void mlx4_en_add_vxlan_port(struct net_device *dev,
+ sa_family_t sa_family, __be16 port)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ __be16 current_port;
+
+ if (!(priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS))
+ return;
+
+ if (sa_family == AF_INET6)
+ return;
+
+ current_port = priv->vxlan_port;
+ if (current_port && current_port != port) {
+ en_warn(priv, "vxlan port %d configured, can't add port %d\n",
+ ntohs(current_port), ntohs(port));
+ return;
+ }
+
+ priv->vxlan_port = port;
+ queue_work(priv->mdev->workqueue, &priv->vxlan_add_task);
+}
+
+static void mlx4_en_del_vxlan_port(struct net_device *dev,
+ sa_family_t sa_family, __be16 port)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ __be16 current_port;
+
+ if (priv->mdev->dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN)
+ return;
+
+ if (sa_family == AF_INET6)
+ return;
+
+ current_port = priv->vxlan_port;
+ if (current_port != port) {
+ en_dbg(DRV, priv, "vxlan port %d isn't configured, ignoring\n", ntohs(port));
+ return;
+ }
+
+ queue_work(priv->mdev->workqueue, &priv->vxlan_del_task);
+}
+#endif
+
static const struct net_device_ops mlx4_netdev_ops = {
.ndo_open = mlx4_en_open,
.ndo_stop = mlx4_en_close,
@@ -2292,6 +2372,10 @@ static const struct net_device_ops mlx4_netdev_ops = {
.ndo_busy_poll = mlx4_en_low_latency_recv,
#endif
.ndo_get_phys_port_id = mlx4_en_get_phys_port_id,
+#ifdef CONFIG_MLX4_EN_VXLAN
+ .ndo_add_vxlan_port = mlx4_en_add_vxlan_port,
+ .ndo_del_vxlan_port = mlx4_en_del_vxlan_port,
+#endif
};
static const struct net_device_ops mlx4_netdev_ops_master = {
@@ -2341,7 +2425,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
netif_set_real_num_rx_queues(dev, prof->rx_ring_num);
SET_NETDEV_DEV(dev, &mdev->dev->pdev->dev);
- dev->dev_id = port - 1;
+ dev->dev_port = port - 1;
/*
* Initialize driver private data
@@ -2383,6 +2467,10 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate);
INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats);
INIT_DELAYED_WORK(&priv->service_task, mlx4_en_service_task);
+#ifdef CONFIG_MLX4_EN_VXLAN
+ INIT_WORK(&priv->vxlan_add_task, mlx4_en_add_vxlan_offloads);
+ INIT_WORK(&priv->vxlan_del_task, mlx4_en_del_vxlan_offloads);
+#endif
#ifdef CONFIG_MLX4_EN_DCB
if (!mlx4_is_slave(priv->mdev->dev)) {
if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_SET_ETH_SCHED) {
@@ -2407,7 +2495,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
if (mlx4_is_slave(priv->mdev->dev)) {
eth_hw_addr_random(dev);
en_warn(priv, "Assigned random MAC address %pM\n", dev->dev_addr);
- mac_u64 = mlx4_en_mac_to_u64(dev->dev_addr);
+ mac_u64 = mlx4_mac_to_u64(dev->dev_addr);
mdev->dev->caps.def_mac[priv->port] = mac_u64;
} else {
en_err(priv, "Port: %d, invalid mac burned: %pM, quiting\n",
@@ -2516,7 +2604,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
}
if (mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) {
- err = mlx4_SET_PORT_VXLAN(mdev->dev, priv->port, VXLAN_STEER_BY_OUTER_MAC);
+ err = mlx4_SET_PORT_VXLAN(mdev->dev, priv->port, VXLAN_STEER_BY_OUTER_MAC, 1);
if (err) {
en_err(priv, "Failed setting port L2 tunnel configuration, err %d\n",
err);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_port.c b/drivers/net/ethernet/mellanox/mlx4/en_port.c
index dae1a1f4ae55..c2cfb05e7290 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_port.c
@@ -148,10 +148,16 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
stats->tx_packets = 0;
stats->tx_bytes = 0;
priv->port_stats.tx_chksum_offload = 0;
+ priv->port_stats.queue_stopped = 0;
+ priv->port_stats.wake_queue = 0;
+
for (i = 0; i < priv->tx_ring_num; i++) {
stats->tx_packets += priv->tx_ring[i]->packets;
stats->tx_bytes += priv->tx_ring[i]->bytes;
priv->port_stats.tx_chksum_offload += priv->tx_ring[i]->tx_csum;
+ priv->port_stats.queue_stopped +=
+ priv->tx_ring[i]->queue_stopped;
+ priv->port_stats.wake_queue += priv->tx_ring[i]->wake_queue;
}
stats->rx_errors = be64_to_cpu(mlx4_en_stats->PCS) +
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index 890922c1c8ee..ba049ae88749 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -318,6 +318,31 @@ static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv,
}
}
+void mlx4_en_set_num_rx_rings(struct mlx4_en_dev *mdev)
+{
+ int i;
+ int num_of_eqs;
+ int num_rx_rings;
+ struct mlx4_dev *dev = mdev->dev;
+
+ mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
+ if (!dev->caps.comp_pool)
+ num_of_eqs = max_t(int, MIN_RX_RINGS,
+ min_t(int,
+ dev->caps.num_comp_vectors,
+ DEF_RX_RINGS));
+ else
+ num_of_eqs = min_t(int, MAX_MSIX_P_PORT,
+ dev->caps.comp_pool/
+ dev->caps.num_ports) - 1;
+
+ num_rx_rings = min_t(int, num_of_eqs,
+ netif_get_num_default_rss_queues());
+ mdev->profile.prof[i].rx_ring_num =
+ rounddown_pow_of_two(num_rx_rings);
+ }
+}
+
int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
struct mlx4_en_rx_ring **pring,
u32 size, u16 stride, int node)
@@ -636,6 +661,9 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
if (!priv->port_up)
return 0;
+ if (budget <= 0)
+ return polled;
+
/* We assume a 1:1 mapping between CQEs and Rx descriptors, so Rx
* descriptor offset can be deduced from the CQE index instead of
* reading 'cqe->index' */
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
index c11d063473e5..03e5f6ac67e7 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
@@ -129,8 +129,10 @@ static int mlx4_en_test_speed(struct mlx4_en_priv *priv)
if (mlx4_en_QUERY_PORT(priv->mdev, priv->port))
return -ENOMEM;
- /* The device currently only supports 10G speed */
- if (priv->port_state.link_speed != SPEED_10000)
+ /* The device supports 1G, 10G and 40G speeds */
+ if (priv->port_state.link_speed != 1000 &&
+ priv->port_state.link_speed != 10000 &&
+ priv->port_state.link_speed != 40000)
return priv->port_state.link_speed;
return 0;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index 8e8a7eb43a2c..dd1f6d346459 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -44,16 +44,6 @@
#include "mlx4_en.h"
-enum {
- MAX_INLINE = 104, /* 128 - 16 - 4 - 4 */
- MAX_BF = 256,
-};
-
-static int inline_thold __read_mostly = MAX_INLINE;
-
-module_param_named(inline_thold, inline_thold, int, 0444);
-MODULE_PARM_DESC(inline_thold, "threshold for using inline data");
-
int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
struct mlx4_en_tx_ring **pring, int qpn, u32 size,
u16 stride, int node, int queue_index)
@@ -75,8 +65,7 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
ring->size = size;
ring->size_mask = size - 1;
ring->stride = stride;
-
- inline_thold = min(inline_thold, MAX_INLINE);
+ ring->inline_thold = priv->prof->inline_thold;
tmp = size * sizeof(struct mlx4_en_tx_info);
ring->tx_info = vmalloc_node(tmp, node);
@@ -325,7 +314,7 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
}
}
}
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return tx_info->nr_txbb;
}
@@ -456,7 +445,7 @@ static int mlx4_en_process_tx_cq(struct net_device *dev,
*/
if (netif_tx_queue_stopped(ring->tx_queue) && txbbs_skipped > 0) {
netif_tx_wake_queue(ring->tx_queue);
- priv->port_stats.wake_queue++;
+ ring->wake_queue++;
}
return done;
}
@@ -520,7 +509,7 @@ static struct mlx4_en_tx_desc *mlx4_en_bounce_to_desc(struct mlx4_en_priv *priv,
return ring->buf + index * TXBB_SIZE;
}
-static int is_inline(struct sk_buff *skb, void **pfrag)
+static int is_inline(int inline_thold, struct sk_buff *skb, void **pfrag)
{
void *ptr;
@@ -580,7 +569,7 @@ static int get_real_size(struct sk_buff *skb, struct net_device *dev,
}
} else {
*lso_header_size = 0;
- if (!is_inline(skb, NULL))
+ if (!is_inline(priv->prof->inline_thold, skb, NULL))
real_size = CTRL_SIZE + (skb_shinfo(skb)->nr_frags + 1) * DS_SIZE;
else
real_size = inline_size(skb);
@@ -596,7 +585,13 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk
int spc = MLX4_INLINE_ALIGN - CTRL_SIZE - sizeof *inl;
if (skb->len <= spc) {
- inl->byte_count = cpu_to_be32(1 << 31 | skb->len);
+ if (likely(skb->len >= MIN_PKT_LEN)) {
+ inl->byte_count = cpu_to_be32(1 << 31 | skb->len);
+ } else {
+ inl->byte_count = cpu_to_be32(1 << 31 | MIN_PKT_LEN);
+ memset(((void *)(inl + 1)) + skb->len, 0,
+ MIN_PKT_LEN - skb->len);
+ }
skb_copy_from_linear_data(skb, inl + 1, skb_headlen(skb));
if (skb_shinfo(skb)->nr_frags)
memcpy(((void *)(inl + 1)) + skb_headlen(skb), fragptr,
@@ -629,7 +624,7 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk
}
u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv, select_queue_fallback_t fallback)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
u16 rings_p_up = priv->num_tx_rings_p_up;
@@ -641,7 +636,7 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb,
if (vlan_tx_tag_present(skb))
up = vlan_tx_tag_get(skb) >> VLAN_PRIO_SHIFT;
- return __netdev_pick_tx(dev, skb) % rings_p_up + up * rings_p_up;
+ return fallback(dev, skb) % rings_p_up + up * rings_p_up;
}
static void mlx4_bf_copy(void __iomem *dst, unsigned long *src, unsigned bytecnt)
@@ -696,7 +691,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
ring->size - HEADROOM - MAX_DESC_TXBBS)) {
/* every full Tx ring stops queue */
netif_tx_stop_queue(ring->tx_queue);
- priv->port_stats.queue_stopped++;
+ ring->queue_stopped++;
/* If queue was emptied after the if, and before the
* stop_queue - need to wake the queue, or else it will remain
@@ -709,7 +704,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(((int)(ring->prod - ring->cons)) <=
ring->size - HEADROOM - MAX_DESC_TXBBS)) {
netif_tx_wake_queue(ring->tx_queue);
- priv->port_stats.wake_queue++;
+ ring->wake_queue++;
} else {
return NETDEV_TX_BUSY;
}
@@ -747,11 +742,11 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
tx_info->data_offset = (void *)data - (void *)tx_desc;
tx_info->linear = (lso_header_size < skb_headlen(skb) &&
- !is_inline(skb, NULL)) ? 1 : 0;
+ !is_inline(ring->inline_thold, skb, NULL)) ? 1 : 0;
data += skb_shinfo(skb)->nr_frags + tx_info->linear - 1;
- if (is_inline(skb, &fragptr)) {
+ if (is_inline(ring->inline_thold, skb, &fragptr)) {
tx_info->inl = 1;
} else {
/* Map fragments */
@@ -881,7 +876,8 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
skb_tx_timestamp(skb);
if (ring->bf_enabled && desc_size <= MAX_BF && !bounce && !vlan_tx_tag_present(skb)) {
- *(__be32 *) (&tx_desc->ctrl.vlan_tag) |= cpu_to_be32(ring->doorbell_qpn);
+ tx_desc->ctrl.bf_qpn |= cpu_to_be32(ring->doorbell_qpn);
+
op_own |= htonl((bf_index & 0xffff) << 8);
/* Ensure new descirptor hits memory
* before setting ownership of this descriptor to HW */
diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c
index 8992b38578d5..d501a2b0fb79 100644
--- a/drivers/net/ethernet/mellanox/mlx4/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/eq.c
@@ -271,7 +271,10 @@ enum slave_port_state mlx4_get_slave_port_state(struct mlx4_dev *dev, int slave,
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_slave_state *s_state = priv->mfunc.master.slave_state;
- if (slave >= dev->num_slaves || port > MLX4_MAX_PORTS) {
+ struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave);
+
+ if (slave >= dev->num_slaves || port > dev->caps.num_ports ||
+ port <= 0 || !test_bit(port - 1, actv_ports.ports)) {
pr_err("%s: Error: asking for slave:%d, port:%d\n",
__func__, slave, port);
return SLAVE_PORT_DOWN;
@@ -285,8 +288,10 @@ static int mlx4_set_slave_port_state(struct mlx4_dev *dev, int slave, u8 port,
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_slave_state *s_state = priv->mfunc.master.slave_state;
+ struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave);
- if (slave >= dev->num_slaves || port > MLX4_MAX_PORTS || port == 0) {
+ if (slave >= dev->num_slaves || port > dev->caps.num_ports ||
+ port <= 0 || !test_bit(port - 1, actv_ports.ports)) {
pr_err("%s: Error: asking for slave:%d, port:%d\n",
__func__, slave, port);
return -1;
@@ -300,9 +305,13 @@ static void set_all_slave_state(struct mlx4_dev *dev, u8 port, int event)
{
int i;
enum slave_port_gen_event gen_event;
+ struct mlx4_slaves_pport slaves_pport = mlx4_phys_to_slaves_pport(dev,
+ port);
- for (i = 0; i < dev->num_slaves; i++)
- set_and_calc_slave_port_state(dev, i, port, event, &gen_event);
+ for (i = 0; i < dev->num_vfs + 1; i++)
+ if (test_bit(i, slaves_pport.slaves))
+ set_and_calc_slave_port_state(dev, i, port,
+ event, &gen_event);
}
/**************************************************************************
The function get as input the new event to that port,
@@ -321,12 +330,14 @@ int set_and_calc_slave_port_state(struct mlx4_dev *dev, int slave,
struct mlx4_slave_state *ctx = NULL;
unsigned long flags;
int ret = -1;
+ struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave);
enum slave_port_state cur_state =
mlx4_get_slave_port_state(dev, slave, port);
*gen_event = SLAVE_PORT_GEN_EVENT_NONE;
- if (slave >= dev->num_slaves || port > MLX4_MAX_PORTS || port == 0) {
+ if (slave >= dev->num_slaves || port > dev->caps.num_ports ||
+ port <= 0 || !test_bit(port - 1, actv_ports.ports)) {
pr_err("%s: Error: asking for slave:%d, port:%d\n",
__func__, slave, port);
return ret;
@@ -542,15 +553,19 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
be64_to_cpu(eqe->event.cmd.out_param));
break;
- case MLX4_EVENT_TYPE_PORT_CHANGE:
+ case MLX4_EVENT_TYPE_PORT_CHANGE: {
+ struct mlx4_slaves_pport slaves_port;
port = be32_to_cpu(eqe->event.port_change.port) >> 28;
+ slaves_port = mlx4_phys_to_slaves_pport(dev, port);
if (eqe->subtype == MLX4_PORT_CHANGE_SUBTYPE_DOWN) {
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_DOWN,
port);
mlx4_priv(dev)->sense.do_sense_port[port] = 1;
if (!mlx4_is_master(dev))
break;
- for (i = 0; i < dev->num_slaves; i++) {
+ for (i = 0; i < dev->num_vfs + 1; i++) {
+ if (!test_bit(i, slaves_port.slaves))
+ continue;
if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) {
if (i == mlx4_master_func_num(dev))
continue;
@@ -558,8 +573,13 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
" to slave: %d, port:%d\n",
__func__, i, port);
s_info = &priv->mfunc.master.vf_oper[slave].vport[port].state;
- if (IFLA_VF_LINK_STATE_AUTO == s_info->link_state)
+ if (IFLA_VF_LINK_STATE_AUTO == s_info->link_state) {
+ eqe->event.port_change.port =
+ cpu_to_be32(
+ (be32_to_cpu(eqe->event.port_change.port) & 0xFFFFFFF)
+ | (mlx4_phys_to_slave_port(dev, i, port) << 28));
mlx4_slave_event(dev, i, eqe);
+ }
} else { /* IB port */
set_and_calc_slave_port_state(dev, i, port,
MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN,
@@ -580,12 +600,19 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
if (!mlx4_is_master(dev))
break;
if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
- for (i = 0; i < dev->num_slaves; i++) {
+ for (i = 0; i < dev->num_vfs + 1; i++) {
+ if (!test_bit(i, slaves_port.slaves))
+ continue;
if (i == mlx4_master_func_num(dev))
continue;
s_info = &priv->mfunc.master.vf_oper[slave].vport[port].state;
- if (IFLA_VF_LINK_STATE_AUTO == s_info->link_state)
+ if (IFLA_VF_LINK_STATE_AUTO == s_info->link_state) {
+ eqe->event.port_change.port =
+ cpu_to_be32(
+ (be32_to_cpu(eqe->event.port_change.port) & 0xFFFFFFF)
+ | (mlx4_phys_to_slave_port(dev, i, port) << 28));
mlx4_slave_event(dev, i, eqe);
+ }
}
else /* IB port */
/* port-up event will be sent to a slave when the
@@ -594,6 +621,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
set_all_slave_state(dev, port, MLX4_DEV_EVENT_PORT_UP);
}
break;
+ }
case MLX4_EVENT_TYPE_CQ_ERROR:
mlx4_warn(dev, "CQ %s on CQN %06x\n",
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c
index 91b69ff4b4a2..d16a4d118903 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.c
@@ -129,13 +129,14 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
[0] = "RSS support",
[1] = "RSS Toeplitz Hash Function support",
[2] = "RSS XOR Hash Function support",
- [3] = "Device manage flow steering support",
+ [3] = "Device managed flow steering support",
[4] = "Automatic MAC reassignment support",
[5] = "Time stamping support",
[6] = "VST (control vlan insertion/stripping) support",
[7] = "FSM (MAC anti-spoofing) support",
[8] = "Dynamic QP updates support",
- [9] = "TCP/IP offloads/flow-steering for VXLAN support"
+ [9] = "Device managed flow steering IPoIB support",
+ [10] = "TCP/IP offloads/flow-steering for VXLAN support"
};
int i;
@@ -224,13 +225,25 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
#define QUERY_FUNC_CAP_FLAGS0_FORCE_PHY_WQE_GID 0x80
if (vhcr->op_modifier == 1) {
+ struct mlx4_active_ports actv_ports =
+ mlx4_get_active_ports(dev, slave);
+ int converted_port = mlx4_slave_convert_port(
+ dev, slave, vhcr->in_modifier);
+
+ if (converted_port < 0)
+ return -EINVAL;
+
+ vhcr->in_modifier = converted_port;
/* Set nic_info bit to mark new fields support */
field = QUERY_FUNC_CAP_FLAGS1_NIC_INFO;
MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS1_OFFSET);
- field = vhcr->in_modifier; /* phys-port = logical-port */
+ /* phys-port = logical-port */
+ field = vhcr->in_modifier -
+ find_first_bit(actv_ports.ports, dev->caps.num_ports);
MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_PHYS_PORT_OFFSET);
+ field = vhcr->in_modifier;
/* size is now the QP number */
size = dev->phys_caps.base_tunnel_sqpn + 8 * slave + field - 1;
MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP0_TUNNEL);
@@ -248,12 +261,16 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
QUERY_FUNC_CAP_PHYS_PORT_ID);
} else if (vhcr->op_modifier == 0) {
+ struct mlx4_active_ports actv_ports =
+ mlx4_get_active_ports(dev, slave);
/* enable rdma and ethernet interfaces, and new quota locations */
field = (QUERY_FUNC_CAP_FLAG_ETH | QUERY_FUNC_CAP_FLAG_RDMA |
QUERY_FUNC_CAP_FLAG_QUOTAS);
MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS_OFFSET);
- field = dev->caps.num_ports;
+ field = min(
+ bitmap_weight(actv_ports.ports, dev->caps.num_ports),
+ dev->caps.num_ports);
MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_NUM_PORTS_OFFSET);
size = dev->caps.function_caps; /* set PF behaviours */
@@ -839,6 +856,10 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
int err = 0;
u8 field;
u32 bmme_flags;
+ int real_port;
+ int slave_port;
+ int first_port;
+ struct mlx4_active_ports actv_ports;
err = mlx4_cmd_box(dev, 0, outbox->dma, 0, 0, MLX4_CMD_QUERY_DEV_CAP,
MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
@@ -851,15 +872,33 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
MLX4_GET(flags, outbox->buf, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
flags |= MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV;
flags &= ~MLX4_DEV_CAP_FLAG_MEM_WINDOW;
+ actv_ports = mlx4_get_active_ports(dev, slave);
+ first_port = find_first_bit(actv_ports.ports, dev->caps.num_ports);
+ for (slave_port = 0, real_port = first_port;
+ real_port < first_port +
+ bitmap_weight(actv_ports.ports, dev->caps.num_ports);
+ ++real_port, ++slave_port) {
+ if (flags & (MLX4_DEV_CAP_FLAG_WOL_PORT1 << real_port))
+ flags |= MLX4_DEV_CAP_FLAG_WOL_PORT1 << slave_port;
+ else
+ flags &= ~(MLX4_DEV_CAP_FLAG_WOL_PORT1 << slave_port);
+ }
+ for (; slave_port < dev->caps.num_ports; ++slave_port)
+ flags &= ~(MLX4_DEV_CAP_FLAG_WOL_PORT1 << slave_port);
MLX4_PUT(outbox->buf, flags, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
+ MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_VL_PORT_OFFSET);
+ field &= ~0x0F;
+ field |= bitmap_weight(actv_ports.ports, dev->caps.num_ports) & 0x0F;
+ MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_VL_PORT_OFFSET);
+
/* For guests, disable timestamp */
MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET);
field &= 0x7f;
MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET);
/* For guests, disable vxlan tunneling */
- MLX4_GET(field, outbox, QUERY_DEV_CAP_VXLAN);
+ MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_VXLAN);
field &= 0xf7;
MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_VXLAN);
@@ -869,7 +908,7 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_BF_OFFSET);
/* For guests, disable mw type 2 */
- MLX4_GET(bmme_flags, outbox, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
+ MLX4_GET(bmme_flags, outbox->buf, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
bmme_flags &= ~MLX4_BMME_FLAG_TYPE_2_WIN;
MLX4_PUT(outbox->buf, bmme_flags, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
@@ -883,7 +922,7 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
}
/* turn off ipoib managed steering for guests */
- MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
+ MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
field &= ~0x80;
MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
@@ -902,12 +941,20 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
u16 short_field;
int err;
int admin_link_state;
+ int port = mlx4_slave_convert_port(dev, slave,
+ vhcr->in_modifier & 0xFF);
#define MLX4_VF_PORT_NO_LINK_SENSE_MASK 0xE0
#define MLX4_PORT_LINK_UP_MASK 0x80
#define QUERY_PORT_CUR_MAX_PKEY_OFFSET 0x0c
#define QUERY_PORT_CUR_MAX_GID_OFFSET 0x0e
+ if (port < 0)
+ return -EINVAL;
+
+ vhcr->in_modifier = (vhcr->in_modifier & ~0xFF) |
+ (port & 0xFF);
+
err = mlx4_cmd_box(dev, 0, outbox->dma, vhcr->in_modifier, 0,
MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B,
MLX4_CMD_NATIVE);
@@ -934,7 +981,10 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
MLX4_PUT(outbox->buf, port_type,
QUERY_PORT_SUPPORTED_TYPE_OFFSET);
- short_field = 1; /* slave max gids */
+ if (dev->caps.port_type[vhcr->in_modifier] == MLX4_PORT_TYPE_ETH)
+ short_field = mlx4_get_slave_num_gids(dev, slave, port);
+ else
+ short_field = 1; /* slave max gids */
MLX4_PUT(outbox->buf, short_field,
QUERY_PORT_CUR_MAX_GID_OFFSET);
@@ -1584,9 +1634,12 @@ int mlx4_INIT_PORT_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_cmd_info *cmd)
{
struct mlx4_priv *priv = mlx4_priv(dev);
- int port = vhcr->in_modifier;
+ int port = mlx4_slave_convert_port(dev, slave, vhcr->in_modifier);
int err;
+ if (port < 0)
+ return -EINVAL;
+
if (priv->mfunc.master.slave_state[slave].init_port_mask & (1 << port))
return 0;
@@ -1676,9 +1729,12 @@ int mlx4_CLOSE_PORT_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_cmd_info *cmd)
{
struct mlx4_priv *priv = mlx4_priv(dev);
- int port = vhcr->in_modifier;
+ int port = mlx4_slave_convert_port(dev, slave, vhcr->in_modifier);
int err;
+ if (port < 0)
+ return -EINVAL;
+
if (!(priv->mfunc.master.slave_state[slave].init_port_mask &
(1 << port)))
return 0;
@@ -1723,6 +1779,46 @@ int mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic)
MLX4_CMD_NATIVE);
}
+struct mlx4_config_dev {
+ __be32 update_flags;
+ __be32 rsdv1[3];
+ __be16 vxlan_udp_dport;
+ __be16 rsvd2;
+};
+
+#define MLX4_VXLAN_UDP_DPORT (1 << 0)
+
+static int mlx4_CONFIG_DEV(struct mlx4_dev *dev, struct mlx4_config_dev *config_dev)
+{
+ int err;
+ struct mlx4_cmd_mailbox *mailbox;
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+
+ memcpy(mailbox->buf, config_dev, sizeof(*config_dev));
+
+ err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_CONFIG_DEV,
+ MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
+
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ return err;
+}
+
+int mlx4_config_vxlan_port(struct mlx4_dev *dev, __be16 udp_port)
+{
+ struct mlx4_config_dev config_dev;
+
+ memset(&config_dev, 0, sizeof(config_dev));
+ config_dev.update_flags = cpu_to_be32(MLX4_VXLAN_UDP_DPORT);
+ config_dev.vxlan_udp_dport = udp_port;
+
+ return mlx4_CONFIG_DEV(dev, &config_dev);
+}
+EXPORT_SYMBOL_GPL(mlx4_config_vxlan_port);
+
+
int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages)
{
int ret = mlx4_cmd_imm(dev, icm_size, aux_pages, 0, 0,
@@ -1890,7 +1986,8 @@ void mlx4_opreq_action(struct work_struct *work)
err = EINVAL;
break;
}
- err = mlx4_cmd(dev, 0, ((u32) err | cpu_to_be32(token) << 16),
+ err = mlx4_cmd(dev, 0, ((u32) err |
+ (__force u32)cpu_to_be32(token) << 16),
1, MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A,
MLX4_CMD_NATIVE);
if (err) {
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index d711158b0d4b..f0ae95f66ceb 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -41,7 +41,6 @@
#include <linux/slab.h>
#include <linux/io-mapping.h>
#include <linux/delay.h>
-#include <linux/netdevice.h>
#include <linux/kmod.h>
#include <linux/mlx4/device.h>
@@ -78,13 +77,17 @@ MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero");
#endif /* CONFIG_PCI_MSI */
-static int num_vfs;
-module_param(num_vfs, int, 0444);
-MODULE_PARM_DESC(num_vfs, "enable #num_vfs functions if num_vfs > 0");
+static uint8_t num_vfs[3] = {0, 0, 0};
+static int num_vfs_argc = 3;
+module_param_array(num_vfs, byte , &num_vfs_argc, 0444);
+MODULE_PARM_DESC(num_vfs, "enable #num_vfs functions if num_vfs > 0\n"
+ "num_vfs=port1,port2,port1+2");
-static int probe_vf;
-module_param(probe_vf, int, 0644);
-MODULE_PARM_DESC(probe_vf, "number of vfs to probe by pf driver (num_vfs > 0)");
+static uint8_t probe_vf[3] = {0, 0, 0};
+static int probe_vfs_argc = 3;
+module_param_array(probe_vf, byte, &probe_vfs_argc, 0444);
+MODULE_PARM_DESC(probe_vf, "number of vfs to probe by pf driver (num_vfs > 0)\n"
+ "probe_vf=port1,port2,port1+2");
int mlx4_log_num_mgm_entry_size = MLX4_DEFAULT_MGM_LOG_ENTRY_SIZE;
module_param_named(log_num_mgm_entry_size,
@@ -150,6 +153,8 @@ struct mlx4_port_config {
struct pci_dev *pdev;
};
+static atomic_t pf_loading = ATOMIC_INIT(0);
+
int mlx4_check_port_params(struct mlx4_dev *dev,
enum mlx4_port_type *port_type)
{
@@ -749,7 +754,7 @@ static void mlx4_request_modules(struct mlx4_dev *dev)
has_eth_port = true;
}
- if (has_ib_port)
+ if (has_ib_port || (dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE))
request_module_nowait(IB_DRV_NAME);
if (has_eth_port)
request_module_nowait(EN_DRV_NAME);
@@ -1407,6 +1412,11 @@ static int mlx4_init_slave(struct mlx4_dev *dev)
u32 slave_read;
u32 cmd_channel_ver;
+ if (atomic_read(&pf_loading)) {
+ mlx4_warn(dev, "PF is not ready. Deferring probe\n");
+ return -EPROBE_DEFER;
+ }
+
mutex_lock(&priv->cmd.slave_cmd_mutex);
priv->cmd.max_cmds = 1;
mlx4_warn(dev, "Sending reset\n");
@@ -1463,7 +1473,11 @@ static void mlx4_parav_master_pf_caps(struct mlx4_dev *dev)
int i;
for (i = 1; i <= dev->caps.num_ports; i++) {
- dev->caps.gid_table_len[i] = 1;
+ if (dev->caps.port_type[i] == MLX4_PORT_TYPE_ETH)
+ dev->caps.gid_table_len[i] =
+ mlx4_get_slave_num_gids(dev, 0, i);
+ else
+ dev->caps.gid_table_len[i] = 1;
dev->caps.pkey_table_len[i] =
dev->phys_caps.pkey_phys_table_len[i] - 1;
}
@@ -1488,7 +1502,7 @@ static void choose_steering_mode(struct mlx4_dev *dev,
if (mlx4_log_num_mgm_entry_size == -1 &&
dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_FS_EN &&
(!mlx4_is_mfunc(dev) ||
- (dev_cap->fs_max_num_qp_per_entry >= (num_vfs + 1))) &&
+ (dev_cap->fs_max_num_qp_per_entry >= (dev->num_vfs + 1))) &&
choose_log_fs_mgm_entry_size(dev_cap->fs_max_num_qp_per_entry) >=
MLX4_MIN_MGM_LOG_ENTRY_SIZE) {
dev->oper_log_mgm_entry_size =
@@ -1974,9 +1988,8 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev)
struct mlx4_priv *priv = mlx4_priv(dev);
struct msix_entry *entries;
int nreq = min_t(int, dev->caps.num_ports *
- min_t(int, netif_get_num_default_rss_queues() + 1,
+ min_t(int, num_online_cpus() + 1,
MAX_MSIX_P_PORT) + MSIX_LEGACY_SZ, MAX_MSIX);
- int err;
int i;
if (msi_x) {
@@ -1990,23 +2003,13 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev)
for (i = 0; i < nreq; ++i)
entries[i].entry = i;
- retry:
- err = pci_enable_msix(dev->pdev, entries, nreq);
- if (err) {
- /* Try again if at least 2 vectors are available */
- if (err > 1) {
- mlx4_info(dev, "Requested %d vectors, "
- "but only %d MSI-X vectors available, "
- "trying again\n", nreq, err);
- nreq = err;
- goto retry;
- }
+ nreq = pci_enable_msix_range(dev->pdev, entries, 2, nreq);
+
+ if (nreq < 0) {
kfree(entries);
goto no_msi;
- }
-
- if (nreq <
- MSIX_LEGACY_SZ + dev->caps.num_ports * MIN_MSIX_P_PORT) {
+ } else if (nreq < MSIX_LEGACY_SZ +
+ dev->caps.num_ports * MIN_MSIX_P_PORT) {
/*Working in legacy mode , all EQ's shared*/
dev->caps.comp_pool = 0;
dev->caps.num_comp_vectors = nreq - 1;
@@ -2194,6 +2197,13 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
struct mlx4_dev *dev;
int err;
int port;
+ int nvfs[MLX4_MAX_PORTS + 1] = {0, 0, 0};
+ int prb_vf[MLX4_MAX_PORTS + 1] = {0, 0, 0};
+ const int param_map[MLX4_MAX_PORTS + 1][MLX4_MAX_PORTS + 1] = {
+ {2, 0, 0}, {0, 1, 2}, {0, 1, 2} };
+ unsigned total_vfs = 0;
+ int sriov_initialized = 0;
+ unsigned int i;
pr_info(DRV_NAME ": Initializing %s\n", pci_name(pdev));
@@ -2208,17 +2218,40 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
* per port, we must limit the number of VFs to 63 (since their are
* 128 MACs)
*/
- if (num_vfs >= MLX4_MAX_NUM_VF) {
+ for (i = 0; i < sizeof(nvfs)/sizeof(nvfs[0]) && i < num_vfs_argc;
+ total_vfs += nvfs[param_map[num_vfs_argc - 1][i]], i++) {
+ nvfs[param_map[num_vfs_argc - 1][i]] = num_vfs[i];
+ if (nvfs[i] < 0) {
+ dev_err(&pdev->dev, "num_vfs module parameter cannot be negative\n");
+ return -EINVAL;
+ }
+ }
+ for (i = 0; i < sizeof(prb_vf)/sizeof(prb_vf[0]) && i < probe_vfs_argc;
+ i++) {
+ prb_vf[param_map[probe_vfs_argc - 1][i]] = probe_vf[i];
+ if (prb_vf[i] < 0 || prb_vf[i] > nvfs[i]) {
+ dev_err(&pdev->dev, "probe_vf module parameter cannot be negative or greater than num_vfs\n");
+ return -EINVAL;
+ }
+ }
+ if (total_vfs >= MLX4_MAX_NUM_VF) {
dev_err(&pdev->dev,
"Requested more VF's (%d) than allowed (%d)\n",
- num_vfs, MLX4_MAX_NUM_VF - 1);
+ total_vfs, MLX4_MAX_NUM_VF - 1);
return -EINVAL;
}
- if (num_vfs < 0) {
- pr_err("num_vfs module parameter cannot be negative\n");
- return -EINVAL;
+ for (i = 0; i < MLX4_MAX_PORTS; i++) {
+ if (nvfs[i] + nvfs[2] >= MLX4_MAX_NUM_VF_P_PORT) {
+ dev_err(&pdev->dev,
+ "Requested more VF's (%d) for port (%d) than allowed (%d)\n",
+ nvfs[i] + nvfs[2], i + 1,
+ MLX4_MAX_NUM_VF_P_PORT - 1);
+ return -EINVAL;
+ }
}
+
+
/*
* Check for BARs.
*/
@@ -2293,11 +2326,23 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
if (pci_dev_data & MLX4_PCI_DEV_IS_VF) {
/* When acting as pf, we normally skip vfs unless explicitly
* requested to probe them. */
- if (num_vfs && extended_func_num(pdev) > probe_vf) {
- mlx4_warn(dev, "Skipping virtual function:%d\n",
- extended_func_num(pdev));
- err = -ENODEV;
- goto err_free_dev;
+ if (total_vfs) {
+ unsigned vfs_offset = 0;
+ for (i = 0; i < sizeof(nvfs)/sizeof(nvfs[0]) &&
+ vfs_offset + nvfs[i] < extended_func_num(pdev);
+ vfs_offset += nvfs[i], i++)
+ ;
+ if (i == sizeof(nvfs)/sizeof(nvfs[0])) {
+ err = -ENODEV;
+ goto err_free_dev;
+ }
+ if ((extended_func_num(pdev) - vfs_offset)
+ > prb_vf[i]) {
+ mlx4_warn(dev, "Skipping virtual function:%d\n",
+ extended_func_num(pdev));
+ err = -ENODEV;
+ goto err_free_dev;
+ }
}
mlx4_warn(dev, "Detected virtual function - running in slave mode\n");
dev->flags |= MLX4_FLAG_SLAVE;
@@ -2317,18 +2362,30 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
}
}
- if (num_vfs) {
- mlx4_warn(dev, "Enabling SR-IOV with %d VFs\n", num_vfs);
- err = pci_enable_sriov(pdev, num_vfs);
- if (err) {
- mlx4_err(dev, "Failed to enable SR-IOV, continuing without SR-IOV (err = %d).\n",
- err);
+ if (total_vfs) {
+ mlx4_warn(dev, "Enabling SR-IOV with %d VFs\n",
+ total_vfs);
+ dev->dev_vfs = kzalloc(
+ total_vfs * sizeof(*dev->dev_vfs),
+ GFP_KERNEL);
+ if (NULL == dev->dev_vfs) {
+ mlx4_err(dev, "Failed to allocate memory for VFs\n");
err = 0;
} else {
- mlx4_warn(dev, "Running in master mode\n");
- dev->flags |= MLX4_FLAG_SRIOV |
- MLX4_FLAG_MASTER;
- dev->num_vfs = num_vfs;
+ atomic_inc(&pf_loading);
+ err = pci_enable_sriov(pdev, total_vfs);
+ atomic_dec(&pf_loading);
+ if (err) {
+ mlx4_err(dev, "Failed to enable SR-IOV, continuing without SR-IOV (err = %d).\n",
+ err);
+ err = 0;
+ } else {
+ mlx4_warn(dev, "Running in master mode\n");
+ dev->flags |= MLX4_FLAG_SRIOV |
+ MLX4_FLAG_MASTER;
+ dev->num_vfs = total_vfs;
+ sriov_initialized = 1;
+ }
}
}
@@ -2393,12 +2450,37 @@ slave_start:
/* In master functions, the communication channel must be initialized
* after obtaining its address from fw */
if (mlx4_is_master(dev)) {
+ unsigned sum = 0;
err = mlx4_multi_func_init(dev);
if (err) {
mlx4_err(dev, "Failed to init master mfunc"
"interface, aborting.\n");
goto err_close;
}
+ if (sriov_initialized) {
+ int ib_ports = 0;
+ mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
+ ib_ports++;
+
+ if (ib_ports &&
+ (num_vfs_argc > 1 || probe_vfs_argc > 1)) {
+ mlx4_err(dev,
+ "Invalid syntax of num_vfs/probe_vfs "
+ "with IB port. Single port VFs syntax"
+ " is only supported when all ports "
+ "are configured as ethernet\n");
+ goto err_close;
+ }
+ for (i = 0; i < sizeof(nvfs)/sizeof(nvfs[0]); i++) {
+ unsigned j;
+ for (j = 0; j < nvfs[i]; ++sum, ++j) {
+ dev->dev_vfs[sum].min_port =
+ i < 2 ? i + 1 : 1;
+ dev->dev_vfs[sum].n_ports = i < 2 ? 1 :
+ dev->caps.num_ports;
+ }
+ }
+ }
}
err = mlx4_alloc_eq_table(dev);
@@ -2506,6 +2588,8 @@ err_rel_own:
if (!mlx4_is_slave(dev))
mlx4_free_ownership(dev);
+ kfree(priv->dev.dev_vfs);
+
err_free_dev:
kfree(priv);
@@ -2592,6 +2676,7 @@ static void mlx4_remove_one(struct pci_dev *pdev)
kfree(dev->caps.qp0_proxy);
kfree(dev->caps.qp1_tunnel);
kfree(dev->caps.qp1_proxy);
+ kfree(dev->dev_vfs);
kfree(priv);
pci_release_regions(pdev);
@@ -2670,7 +2755,11 @@ static pci_ers_result_t mlx4_pci_err_detected(struct pci_dev *pdev,
static pci_ers_result_t mlx4_pci_slot_reset(struct pci_dev *pdev)
{
- int ret = __mlx4_init_one(pdev, 0);
+ const struct pci_device_id *id;
+ int ret;
+
+ id = pci_match_id(mlx4_pci_table, pdev);
+ ret = __mlx4_init_one(pdev, id->driver_data);
return ret ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
}
@@ -2684,6 +2773,7 @@ static struct pci_driver mlx4_driver = {
.name = DRV_NAME,
.id_table = mlx4_pci_table,
.probe = mlx4_init_one,
+ .shutdown = mlx4_remove_one,
.remove = mlx4_remove_one,
.err_handler = &mlx4_err_handler,
};
diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c
index db7dc0b6667d..80ccb4edf825 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mcg.c
+++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c
@@ -1387,9 +1387,12 @@ int mlx4_PROMISC_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_cmd_info *cmd)
{
u32 qpn = (u32) vhcr->in_param & 0xffffffff;
- u8 port = vhcr->in_param >> 62;
+ int port = mlx4_slave_convert_port(dev, slave, vhcr->in_param >> 62);
enum mlx4_steer_type steer = vhcr->in_modifier;
+ if (port < 0)
+ return -EINVAL;
+
/* Promiscuous unicast is not allowed in mfunc */
if (mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index 6b65f7795215..cf8be41abb36 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -51,8 +51,8 @@
#define DRV_NAME "mlx4_core"
#define PFX DRV_NAME ": "
-#define DRV_VERSION "1.1"
-#define DRV_RELDATE "Dec, 2011"
+#define DRV_VERSION "2.2-1"
+#define DRV_RELDATE "Feb, 2014"
#define MLX4_FS_UDP_UC_EN (1 << 1)
#define MLX4_FS_TCP_UC_EN (1 << 2)
@@ -788,6 +788,10 @@ enum {
MLX4_USE_RR = 1,
};
+struct mlx4_roce_gid_entry {
+ u8 raw[16];
+};
+
struct mlx4_priv {
struct mlx4_dev dev;
@@ -834,6 +838,7 @@ struct mlx4_priv {
int fs_hash_mode;
u8 virt2phys_pkey[MLX4_MFUNC_MAX][MLX4_MAX_PORTS][MLX4_MAX_PORT_PKEYS];
__be64 slave_node_guids[MLX4_MFUNC_MAX];
+ struct mlx4_roce_gid_entry roce_gids[MLX4_MAX_PORTS][MLX4_ROCE_MAX_GIDS];
atomic_t opreq_count;
struct work_struct opreq_task;
@@ -1242,11 +1247,6 @@ int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_cmd_mailbox *inbox,
struct mlx4_cmd_mailbox *outbox,
struct mlx4_cmd_info *cmd);
-int mlx4_FLOW_STEERING_IB_UC_QP_RANGE_wrapper(struct mlx4_dev *dev, int slave,
- struct mlx4_vhcr *vhcr,
- struct mlx4_cmd_mailbox *inbox,
- struct mlx4_cmd_mailbox *outbox,
- struct mlx4_cmd_info *cmd);
int mlx4_get_mgm_entry_size(struct mlx4_dev *dev);
int mlx4_get_qp_per_mgm(struct mlx4_dev *dev);
@@ -1282,4 +1282,8 @@ void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work);
void mlx4_init_quotas(struct mlx4_dev *dev);
+int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port);
+/* Returns the VF index of slave */
+int mlx4_get_vf_indx(struct mlx4_dev *dev, int slave);
+
#endif /* MLX4_H */
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 3af04c3f42ea..7a733c287744 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -57,8 +57,8 @@
#include "en_port.h"
#define DRV_NAME "mlx4_en"
-#define DRV_VERSION "2.0"
-#define DRV_RELDATE "Dec 2011"
+#define DRV_VERSION "2.2-1"
+#define DRV_RELDATE "Feb 2014"
#define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN)
@@ -187,6 +187,13 @@ enum {
#define GET_AVG_PERF_COUNTER(cnt) (0)
#endif /* MLX4_EN_PERF_STAT */
+/* Constants for TX flow */
+enum {
+ MAX_INLINE = 104, /* 128 - 16 - 4 - 4 */
+ MAX_BF = 256,
+ MIN_PKT_LEN = 17,
+};
+
/*
* Configurables
*/
@@ -267,10 +274,13 @@ struct mlx4_en_tx_ring {
unsigned long bytes;
unsigned long packets;
unsigned long tx_csum;
+ unsigned long queue_stopped;
+ unsigned long wake_queue;
struct mlx4_bf bf;
bool bf_enabled;
struct netdev_queue *tx_queue;
int hwtstamp_tx_type;
+ int inline_thold;
};
struct mlx4_en_rx_desc {
@@ -346,6 +356,7 @@ struct mlx4_en_port_profile {
u8 tx_pause;
u8 tx_ppp;
int rss_rings;
+ int inline_thold;
};
struct mlx4_en_profile {
@@ -548,6 +559,10 @@ struct mlx4_en_priv {
struct work_struct linkstate_task;
struct delayed_work stats_task;
struct delayed_work service_task;
+#ifdef CONFIG_MLX4_EN_VXLAN
+ struct work_struct vxlan_add_task;
+ struct work_struct vxlan_del_task;
+#endif
struct mlx4_en_perf_stats pstats;
struct mlx4_en_pkt_stats pkstats;
struct mlx4_en_port_stats port_stats;
@@ -574,6 +589,7 @@ struct mlx4_en_priv {
struct hlist_head filter_hash[1 << MLX4_EN_FILTER_HASH_SHIFT];
#endif
u64 tunnel_reg_id;
+ __be16 vxlan_port;
};
enum mlx4_en_wol {
@@ -723,7 +739,7 @@ int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
void mlx4_en_tx_irq(struct mlx4_cq *mcq);
u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv);
+ void *accel_priv, select_queue_fallback_t fallback);
netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev);
int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
@@ -737,7 +753,7 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
int cq, int user_prio);
void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv,
struct mlx4_en_tx_ring *ring);
-
+void mlx4_en_set_num_rx_rings(struct mlx4_en_dev *mdev);
int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
struct mlx4_en_rx_ring **pring,
u32 size, u16 stride, int node);
@@ -786,7 +802,6 @@ void mlx4_en_cleanup_filters(struct mlx4_en_priv *priv);
#define MLX4_EN_NUM_SELF_TEST 5
void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf);
-u64 mlx4_en_mac_to_u64(u8 *addr);
void mlx4_en_ptp_overflow_check(struct mlx4_en_dev *mdev);
/*
diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c
index a58bcbf1b806..cfcad26ed40f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/port.c
@@ -505,6 +505,84 @@ int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps)
mlx4_free_cmd_mailbox(dev, outmailbox);
return err;
}
+static struct mlx4_roce_gid_entry zgid_entry;
+
+int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port)
+{
+ int vfs;
+ int slave_gid = slave;
+ unsigned i;
+ struct mlx4_slaves_pport slaves_pport;
+ struct mlx4_active_ports actv_ports;
+ unsigned max_port_p_one;
+
+ if (slave == 0)
+ return MLX4_ROCE_PF_GIDS;
+
+ /* Slave is a VF */
+ slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
+ actv_ports = mlx4_get_active_ports(dev, slave);
+ max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) +
+ bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1;
+
+ for (i = 1; i < max_port_p_one; i++) {
+ struct mlx4_active_ports exclusive_ports;
+ struct mlx4_slaves_pport slaves_pport_actv;
+ bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
+ set_bit(i - 1, exclusive_ports.ports);
+ if (i == port)
+ continue;
+ slaves_pport_actv = mlx4_phys_to_slaves_pport_actv(
+ dev, &exclusive_ports);
+ slave_gid -= bitmap_weight(slaves_pport_actv.slaves,
+ dev->num_vfs + 1);
+ }
+ vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1;
+ if (slave_gid <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % vfs))
+ return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs) + 1;
+ return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs;
+}
+
+int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port)
+{
+ int gids;
+ unsigned i;
+ int slave_gid = slave;
+ int vfs;
+
+ struct mlx4_slaves_pport slaves_pport;
+ struct mlx4_active_ports actv_ports;
+ unsigned max_port_p_one;
+
+ if (slave == 0)
+ return 0;
+
+ slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
+ actv_ports = mlx4_get_active_ports(dev, slave);
+ max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) +
+ bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1;
+
+ for (i = 1; i < max_port_p_one; i++) {
+ struct mlx4_active_ports exclusive_ports;
+ struct mlx4_slaves_pport slaves_pport_actv;
+ bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
+ set_bit(i - 1, exclusive_ports.ports);
+ if (i == port)
+ continue;
+ slaves_pport_actv = mlx4_phys_to_slaves_pport_actv(
+ dev, &exclusive_ports);
+ slave_gid -= bitmap_weight(slaves_pport_actv.slaves,
+ dev->num_vfs + 1);
+ }
+ gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
+ vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1;
+ if (slave_gid <= gids % vfs)
+ return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave_gid - 1);
+
+ return MLX4_ROCE_PF_GIDS + (gids % vfs) +
+ ((gids / vfs) * (slave_gid - 1));
+}
+EXPORT_SYMBOL_GPL(mlx4_get_base_gid_ix);
static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
u8 op_mod, struct mlx4_cmd_mailbox *inbox)
@@ -515,14 +593,18 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
struct mlx4_slave_state *slave_st = &master->slave_state[slave];
struct mlx4_set_port_rqp_calc_context *qpn_context;
struct mlx4_set_port_general_context *gen_context;
+ struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1;
int reset_qkey_viols;
int port;
int is_eth;
+ int num_gids;
+ int base;
u32 in_modifier;
u32 promisc;
u16 mtu, prev_mtu;
int err;
- int i;
+ int i, j;
+ int offset;
__be32 agg_cap_mask;
__be32 slave_cap_mask;
__be32 new_cap_mask;
@@ -535,7 +617,8 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
/* Slaves cannot perform SET_PORT operations except changing MTU */
if (is_eth) {
if (slave != dev->caps.function &&
- in_modifier != MLX4_SET_PORT_GENERAL) {
+ in_modifier != MLX4_SET_PORT_GENERAL &&
+ in_modifier != MLX4_SET_PORT_GID_TABLE) {
mlx4_warn(dev, "denying SET_PORT for slave:%d\n",
slave);
return -EINVAL;
@@ -581,6 +664,67 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
gen_context->mtu = cpu_to_be16(master->max_mtu[port]);
break;
+ case MLX4_SET_PORT_GID_TABLE:
+ /* change to MULTIPLE entries: number of guest's gids
+ * need a FOR-loop here over number of gids the guest has.
+ * 1. Check no duplicates in gids passed by slave
+ */
+ num_gids = mlx4_get_slave_num_gids(dev, slave, port);
+ base = mlx4_get_base_gid_ix(dev, slave, port);
+ gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
+ for (i = 0; i < num_gids; gid_entry_mbox++, i++) {
+ if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw,
+ sizeof(zgid_entry)))
+ continue;
+ gid_entry_mb1 = gid_entry_mbox + 1;
+ for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) {
+ if (!memcmp(gid_entry_mb1->raw,
+ zgid_entry.raw, sizeof(zgid_entry)))
+ continue;
+ if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw,
+ sizeof(gid_entry_mbox->raw))) {
+ /* found duplicate */
+ return -EINVAL;
+ }
+ }
+ }
+
+ /* 2. Check that do not have duplicates in OTHER
+ * entries in the port GID table
+ */
+ for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
+ if (i >= base && i < base + num_gids)
+ continue; /* don't compare to slave's current gids */
+ gid_entry_tbl = &priv->roce_gids[port - 1][i];
+ if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry)))
+ continue;
+ gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
+ for (j = 0; j < num_gids; gid_entry_mbox++, j++) {
+ if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw,
+ sizeof(zgid_entry)))
+ continue;
+ if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw,
+ sizeof(gid_entry_tbl->raw))) {
+ /* found duplicate */
+ mlx4_warn(dev, "requested gid entry for slave:%d "
+ "is a duplicate of gid at index %d\n",
+ slave, i);
+ return -EINVAL;
+ }
+ }
+ }
+
+ /* insert slave GIDs with memcpy, starting at slave's base index */
+ gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
+ for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++)
+ memcpy(priv->roce_gids[port - 1][offset].raw, gid_entry_mbox->raw, 16);
+
+ /* Now, copy roce port gids table to current mailbox for passing to FW */
+ gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
+ for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++)
+ memcpy(gid_entry_mbox->raw, priv->roce_gids[port - 1][i].raw, 16);
+
+ break;
}
return mlx4_cmd(dev, inbox->dma, in_mod, op_mod,
MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
@@ -646,6 +790,15 @@ int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_cmd_mailbox *outbox,
struct mlx4_cmd_info *cmd)
{
+ int port = mlx4_slave_convert_port(
+ dev, slave, vhcr->in_modifier & 0xFF);
+
+ if (port < 0)
+ return -EINVAL;
+
+ vhcr->in_modifier = (vhcr->in_modifier & ~0xFF) |
+ (port & 0xFF);
+
return mlx4_common_set_port(dev, slave, vhcr->in_modifier,
vhcr->op_modifier, inbox);
}
@@ -835,7 +988,7 @@ struct mlx4_set_port_vxlan_context {
u8 steering;
};
-int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering)
+int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable)
{
int err;
u32 in_mod;
@@ -849,7 +1002,8 @@ int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering)
memset(context, 0, sizeof(*context));
context->modify_flags = VXLAN_ENABLE_MODIFY | VXLAN_STEERING_MODIFY;
- context->enable_flags = VXLAN_ENABLE;
+ if (enable)
+ context->enable_flags = VXLAN_ENABLE;
context->steering = steering;
in_mod = MLX4_SET_PORT_VXLAN << 8 | port;
@@ -927,3 +1081,108 @@ void mlx4_set_stats_bitmap(struct mlx4_dev *dev, u64 *stats_bitmap)
*stats_bitmap |= MLX4_STATS_ERROR_COUNTERS_MASK;
}
EXPORT_SYMBOL(mlx4_set_stats_bitmap);
+
+int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid,
+ int *slave_id)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ int i, found_ix = -1;
+ int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
+ struct mlx4_slaves_pport slaves_pport;
+ unsigned num_vfs;
+ int slave_gid;
+
+ if (!mlx4_is_mfunc(dev))
+ return -EINVAL;
+
+ slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
+ num_vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1;
+
+ for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
+ if (!memcmp(priv->roce_gids[port - 1][i].raw, gid, 16)) {
+ found_ix = i;
+ break;
+ }
+ }
+
+ if (found_ix >= 0) {
+ if (found_ix < MLX4_ROCE_PF_GIDS)
+ slave_gid = 0;
+ else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % num_vfs) *
+ (vf_gids / num_vfs + 1))
+ slave_gid = ((found_ix - MLX4_ROCE_PF_GIDS) /
+ (vf_gids / num_vfs + 1)) + 1;
+ else
+ slave_gid =
+ ((found_ix - MLX4_ROCE_PF_GIDS -
+ ((vf_gids % num_vfs) * ((vf_gids / num_vfs + 1)))) /
+ (vf_gids / num_vfs)) + vf_gids % num_vfs + 1;
+
+ if (slave_gid) {
+ struct mlx4_active_ports exclusive_ports;
+ struct mlx4_active_ports actv_ports;
+ struct mlx4_slaves_pport slaves_pport_actv;
+ unsigned max_port_p_one;
+ int num_slaves_before = 1;
+
+ for (i = 1; i < port; i++) {
+ bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
+ set_bit(i, exclusive_ports.ports);
+ slaves_pport_actv =
+ mlx4_phys_to_slaves_pport_actv(
+ dev, &exclusive_ports);
+ num_slaves_before += bitmap_weight(
+ slaves_pport_actv.slaves,
+ dev->num_vfs + 1);
+ }
+
+ if (slave_gid < num_slaves_before) {
+ bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
+ set_bit(port - 1, exclusive_ports.ports);
+ slaves_pport_actv =
+ mlx4_phys_to_slaves_pport_actv(
+ dev, &exclusive_ports);
+ slave_gid += bitmap_weight(
+ slaves_pport_actv.slaves,
+ dev->num_vfs + 1) -
+ num_slaves_before;
+ }
+ actv_ports = mlx4_get_active_ports(dev, slave_gid);
+ max_port_p_one = find_first_bit(
+ actv_ports.ports, dev->caps.num_ports) +
+ bitmap_weight(actv_ports.ports,
+ dev->caps.num_ports) + 1;
+
+ for (i = 1; i < max_port_p_one; i++) {
+ if (i == port)
+ continue;
+ bitmap_zero(exclusive_ports.ports,
+ dev->caps.num_ports);
+ set_bit(i - 1, exclusive_ports.ports);
+ slaves_pport_actv =
+ mlx4_phys_to_slaves_pport_actv(
+ dev, &exclusive_ports);
+ slave_gid += bitmap_weight(
+ slaves_pport_actv.slaves,
+ dev->num_vfs + 1);
+ }
+ }
+ *slave_id = slave_gid;
+ }
+
+ return (found_ix >= 0) ? 0 : -EINVAL;
+}
+EXPORT_SYMBOL(mlx4_get_slave_from_roce_gid);
+
+int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id,
+ u8 *gid)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+
+ if (!mlx4_is_master(dev))
+ return -EINVAL;
+
+ memcpy(gid, priv->roce_gids[port - 1][slave_id].raw, 16);
+ return 0;
+}
+EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave);
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index 57428a0cb9dd..3b5f53ef29b2 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -52,6 +52,8 @@
struct mac_res {
struct list_head list;
u64 mac;
+ int ref_count;
+ u8 smac_index;
u8 port;
};
@@ -219,6 +221,11 @@ struct res_fs_rule {
int qpn;
};
+static int mlx4_is_eth(struct mlx4_dev *dev, int port)
+{
+ return dev->caps.port_mask[port] == MLX4_PORT_TYPE_IB ? 0 : 1;
+}
+
static void *res_tracker_lookup(struct rb_root *root, u64 res_id)
{
struct rb_node *node = root->rb_node;
@@ -461,6 +468,8 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev)
spin_lock_init(&res_alloc->alloc_lock);
for (t = 0; t < dev->num_vfs + 1; t++) {
+ struct mlx4_active_ports actv_ports =
+ mlx4_get_active_ports(dev, t);
switch (i) {
case RES_QP:
initialize_res_quotas(dev, res_alloc, RES_QP,
@@ -490,10 +499,27 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev)
break;
case RES_MAC:
if (t == mlx4_master_func_num(dev)) {
- res_alloc->quota[t] = MLX4_MAX_MAC_NUM;
+ int max_vfs_pport = 0;
+ /* Calculate the max vfs per port for */
+ /* both ports. */
+ for (j = 0; j < dev->caps.num_ports;
+ j++) {
+ struct mlx4_slaves_pport slaves_pport =
+ mlx4_phys_to_slaves_pport(dev, j + 1);
+ unsigned current_slaves =
+ bitmap_weight(slaves_pport.slaves,
+ dev->caps.num_ports) - 1;
+ if (max_vfs_pport < current_slaves)
+ max_vfs_pport =
+ current_slaves;
+ }
+ res_alloc->quota[t] =
+ MLX4_MAX_MAC_NUM -
+ 2 * max_vfs_pport;
res_alloc->guaranteed[t] = 2;
for (j = 0; j < MLX4_MAX_PORTS; j++)
- res_alloc->res_port_free[j] = MLX4_MAX_MAC_NUM;
+ res_alloc->res_port_free[j] =
+ MLX4_MAX_MAC_NUM;
} else {
res_alloc->quota[t] = MLX4_MAX_MAC_NUM;
res_alloc->guaranteed[t] = 2;
@@ -521,9 +547,10 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev)
break;
}
if (i == RES_MAC || i == RES_VLAN) {
- for (j = 0; j < MLX4_MAX_PORTS; j++)
- res_alloc->res_port_rsvd[j] +=
- res_alloc->guaranteed[t];
+ for (j = 0; j < dev->caps.num_ports; j++)
+ if (test_bit(j, actv_ports.ports))
+ res_alloc->res_port_rsvd[j] +=
+ res_alloc->guaranteed[t];
} else {
res_alloc->res_reserved += res_alloc->guaranteed[t];
}
@@ -600,15 +627,37 @@ static void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox,
struct mlx4_qp_context *qp_ctx = inbox->buf + 8;
enum mlx4_qp_optpar optpar = be32_to_cpu(*(__be32 *) inbox->buf);
u32 ts = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff;
+ int port;
- if (MLX4_QP_ST_UD == ts)
- qp_ctx->pri_path.mgid_index = 0x80 | slave;
-
- if (MLX4_QP_ST_RC == ts || MLX4_QP_ST_UC == ts) {
- if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH)
- qp_ctx->pri_path.mgid_index = slave & 0x7F;
- if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH)
- qp_ctx->alt_path.mgid_index = slave & 0x7F;
+ if (MLX4_QP_ST_UD == ts) {
+ port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
+ if (mlx4_is_eth(dev, port))
+ qp_ctx->pri_path.mgid_index =
+ mlx4_get_base_gid_ix(dev, slave, port) | 0x80;
+ else
+ qp_ctx->pri_path.mgid_index = slave | 0x80;
+
+ } else if (MLX4_QP_ST_RC == ts || MLX4_QP_ST_XRC == ts || MLX4_QP_ST_UC == ts) {
+ if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) {
+ port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
+ if (mlx4_is_eth(dev, port)) {
+ qp_ctx->pri_path.mgid_index +=
+ mlx4_get_base_gid_ix(dev, slave, port);
+ qp_ctx->pri_path.mgid_index &= 0x7f;
+ } else {
+ qp_ctx->pri_path.mgid_index = slave & 0x7F;
+ }
+ }
+ if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) {
+ port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1;
+ if (mlx4_is_eth(dev, port)) {
+ qp_ctx->alt_path.mgid_index +=
+ mlx4_get_base_gid_ix(dev, slave, port);
+ qp_ctx->alt_path.mgid_index &= 0x7f;
+ } else {
+ qp_ctx->alt_path.mgid_index = slave & 0x7F;
+ }
+ }
}
}
@@ -619,7 +668,6 @@ static int update_vport_qp_param(struct mlx4_dev *dev,
struct mlx4_qp_context *qpc = inbox->buf + 8;
struct mlx4_vport_oper_state *vp_oper;
struct mlx4_priv *priv;
- u32 qp_type;
int port;
port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1;
@@ -627,12 +675,6 @@ static int update_vport_qp_param(struct mlx4_dev *dev,
vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
if (MLX4_VGT != vp_oper->state.default_vlan) {
- qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff;
- if (MLX4_QP_ST_RC == qp_type ||
- (MLX4_QP_ST_UD == qp_type &&
- !mlx4_is_qp_reserved(dev, qpn)))
- return -EINVAL;
-
/* the reserved QPs (special, proxy, tunnel)
* do not operate over vlans
*/
@@ -1659,11 +1701,39 @@ static int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
return err;
}
-static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port)
+static int mac_find_smac_ix_in_slave(struct mlx4_dev *dev, int slave, int port,
+ u8 smac_index, u64 *mac)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
+ struct list_head *mac_list =
+ &tracker->slave_list[slave].res_list[RES_MAC];
+ struct mac_res *res, *tmp;
+
+ list_for_each_entry_safe(res, tmp, mac_list, list) {
+ if (res->smac_index == smac_index && res->port == (u8) port) {
+ *mac = res->mac;
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port, u8 smac_index)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
- struct mac_res *res;
+ struct list_head *mac_list =
+ &tracker->slave_list[slave].res_list[RES_MAC];
+ struct mac_res *res, *tmp;
+
+ list_for_each_entry_safe(res, tmp, mac_list, list) {
+ if (res->mac == mac && res->port == (u8) port) {
+ /* mac found. update ref count */
+ ++res->ref_count;
+ return 0;
+ }
+ }
if (mlx4_grant_resource(dev, slave, RES_MAC, 1, port))
return -EINVAL;
@@ -1674,6 +1744,8 @@ static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port)
}
res->mac = mac;
res->port = (u8) port;
+ res->smac_index = smac_index;
+ res->ref_count = 1;
list_add_tail(&res->list,
&tracker->slave_list[slave].res_list[RES_MAC]);
return 0;
@@ -1690,9 +1762,11 @@ static void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac,
list_for_each_entry_safe(res, tmp, mac_list, list) {
if (res->mac == mac && res->port == (u8) port) {
- list_del(&res->list);
- mlx4_release_resource(dev, slave, RES_MAC, 1, port);
- kfree(res);
+ if (!--res->ref_count) {
+ list_del(&res->list);
+ mlx4_release_resource(dev, slave, RES_MAC, 1, port);
+ kfree(res);
+ }
break;
}
}
@@ -1705,10 +1779,13 @@ static void rem_slave_macs(struct mlx4_dev *dev, int slave)
struct list_head *mac_list =
&tracker->slave_list[slave].res_list[RES_MAC];
struct mac_res *res, *tmp;
+ int i;
list_for_each_entry_safe(res, tmp, mac_list, list) {
list_del(&res->list);
- __mlx4_unregister_mac(dev, res->port, res->mac);
+ /* dereference the mac the num times the slave referenced it */
+ for (i = 0; i < res->ref_count; i++)
+ __mlx4_unregister_mac(dev, res->port, res->mac);
mlx4_release_resource(dev, slave, RES_MAC, 1, res->port);
kfree(res);
}
@@ -1720,21 +1797,28 @@ static int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
int err = -EINVAL;
int port;
u64 mac;
+ u8 smac_index;
if (op != RES_OP_RESERVE_AND_MAP)
return err;
port = !in_port ? get_param_l(out_param) : in_port;
+ port = mlx4_slave_convert_port(
+ dev, slave, port);
+
+ if (port < 0)
+ return -EINVAL;
mac = in_param;
err = __mlx4_register_mac(dev, port, mac);
if (err >= 0) {
+ smac_index = err;
set_param_l(out_param, err);
err = 0;
}
if (!err) {
- err = mac_add_to_slave(dev, slave, mac, port);
+ err = mac_add_to_slave(dev, slave, mac, port, smac_index);
if (err)
__mlx4_unregister_mac(dev, port, mac);
}
@@ -1831,6 +1915,11 @@ static int vlan_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
if (!port || op != RES_OP_RESERVE_AND_MAP)
return -EINVAL;
+ port = mlx4_slave_convert_port(
+ dev, slave, port);
+
+ if (port < 0)
+ return -EINVAL;
/* upstream kernels had NOP for reg/unreg vlan. Continue this. */
if (!in_port && port > 0 && port <= dev->caps.num_ports) {
slave_state[slave].old_vlan_api = true;
@@ -2128,6 +2217,11 @@ static int mac_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
switch (op) {
case RES_OP_RESERVE_AND_MAP:
port = !in_port ? get_param_l(out_param) : in_port;
+ port = mlx4_slave_convert_port(
+ dev, slave, port);
+
+ if (port < 0)
+ return -EINVAL;
mac_del_from_slave(dev, slave, in_param, port);
__mlx4_unregister_mac(dev, port, in_param);
break;
@@ -2147,6 +2241,11 @@ static int vlan_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state;
int err = 0;
+ port = mlx4_slave_convert_port(
+ dev, slave, port);
+
+ if (port < 0)
+ return -EINVAL;
switch (op) {
case RES_OP_RESERVE_AND_MAP:
if (slave_state[slave].old_vlan_api)
@@ -2734,6 +2833,8 @@ static int verify_qp_parameters(struct mlx4_dev *dev,
u32 qp_type;
struct mlx4_qp_context *qp_ctx;
enum mlx4_qp_optpar optpar;
+ int port;
+ int num_gids;
qp_ctx = inbox->buf + 8;
qp_type = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff;
@@ -2741,6 +2842,7 @@ static int verify_qp_parameters(struct mlx4_dev *dev,
switch (qp_type) {
case MLX4_QP_ST_RC:
+ case MLX4_QP_ST_XRC:
case MLX4_QP_ST_UC:
switch (transition) {
case QP_TRANS_INIT2RTR:
@@ -2749,13 +2851,24 @@ static int verify_qp_parameters(struct mlx4_dev *dev,
case QP_TRANS_SQD2SQD:
case QP_TRANS_SQD2RTS:
if (slave != mlx4_master_func_num(dev))
- /* slaves have only gid index 0 */
- if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH)
- if (qp_ctx->pri_path.mgid_index)
+ if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) {
+ port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
+ if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB)
+ num_gids = mlx4_get_slave_num_gids(dev, slave, port);
+ else
+ num_gids = 1;
+ if (qp_ctx->pri_path.mgid_index >= num_gids)
return -EINVAL;
- if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH)
- if (qp_ctx->alt_path.mgid_index)
+ }
+ if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) {
+ port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1;
+ if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB)
+ num_gids = mlx4_get_slave_num_gids(dev, slave, port);
+ else
+ num_gids = 1;
+ if (qp_ctx->alt_path.mgid_index >= num_gids)
return -EINVAL;
+ }
break;
default:
break;
@@ -3268,6 +3381,58 @@ int mlx4_INIT2INIT_QP_wrapper(struct mlx4_dev *dev, int slave,
return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
}
+static int adjust_qp_sched_queue(struct mlx4_dev *dev, int slave,
+ struct mlx4_qp_context *qpc,
+ struct mlx4_cmd_mailbox *inbox)
+{
+ enum mlx4_qp_optpar optpar = be32_to_cpu(*(__be32 *)inbox->buf);
+ u8 pri_sched_queue;
+ int port = mlx4_slave_convert_port(
+ dev, slave, (qpc->pri_path.sched_queue >> 6 & 1) + 1) - 1;
+
+ if (port < 0)
+ return -EINVAL;
+
+ pri_sched_queue = (qpc->pri_path.sched_queue & ~(1 << 6)) |
+ ((port & 1) << 6);
+
+ if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH ||
+ mlx4_is_eth(dev, port + 1)) {
+ qpc->pri_path.sched_queue = pri_sched_queue;
+ }
+
+ if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) {
+ port = mlx4_slave_convert_port(
+ dev, slave, (qpc->alt_path.sched_queue >> 6 & 1)
+ + 1) - 1;
+ if (port < 0)
+ return -EINVAL;
+ qpc->alt_path.sched_queue =
+ (qpc->alt_path.sched_queue & ~(1 << 6)) |
+ (port & 1) << 6;
+ }
+ return 0;
+}
+
+static int roce_verify_mac(struct mlx4_dev *dev, int slave,
+ struct mlx4_qp_context *qpc,
+ struct mlx4_cmd_mailbox *inbox)
+{
+ u64 mac;
+ int port;
+ u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff;
+ u8 sched = *(u8 *)(inbox->buf + 64);
+ u8 smac_ix;
+
+ port = (sched >> 6 & 1) + 1;
+ if (mlx4_is_eth(dev, port) && (ts != MLX4_QP_ST_MLX)) {
+ smac_ix = qpc->pri_path.grh_mylmc & 0x7f;
+ if (mac_find_smac_ix_in_slave(dev, slave, port, smac_ix, &mac))
+ return -ENOENT;
+ }
+ return 0;
+}
+
int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_vhcr *vhcr,
struct mlx4_cmd_mailbox *inbox,
@@ -3286,10 +3451,16 @@ int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,
u8 orig_vlan_index = qpc->pri_path.vlan_index;
u8 orig_feup = qpc->pri_path.feup;
+ err = adjust_qp_sched_queue(dev, slave, qpc, inbox);
+ if (err)
+ return err;
err = verify_qp_parameters(dev, inbox, QP_TRANS_INIT2RTR, slave);
if (err)
return err;
+ if (roce_verify_mac(dev, slave, qpc, inbox))
+ return -EINVAL;
+
update_pkey_index(dev, slave, inbox);
update_gid(dev, inbox, (u8)slave);
adjust_proxy_tun_qkey(dev, vhcr, qpc);
@@ -3334,6 +3505,9 @@ int mlx4_RTR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
int err;
struct mlx4_qp_context *context = inbox->buf + 8;
+ err = adjust_qp_sched_queue(dev, slave, context, inbox);
+ if (err)
+ return err;
err = verify_qp_parameters(dev, inbox, QP_TRANS_RTR2RTS, slave);
if (err)
return err;
@@ -3353,6 +3527,9 @@ int mlx4_RTS2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
int err;
struct mlx4_qp_context *context = inbox->buf + 8;
+ err = adjust_qp_sched_queue(dev, slave, context, inbox);
+ if (err)
+ return err;
err = verify_qp_parameters(dev, inbox, QP_TRANS_RTS2RTS, slave);
if (err)
return err;
@@ -3371,6 +3548,9 @@ int mlx4_SQERR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_cmd_info *cmd)
{
struct mlx4_qp_context *context = inbox->buf + 8;
+ int err = adjust_qp_sched_queue(dev, slave, context, inbox);
+ if (err)
+ return err;
adjust_proxy_tun_qkey(dev, vhcr, context);
return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
}
@@ -3384,6 +3564,9 @@ int mlx4_SQD2SQD_QP_wrapper(struct mlx4_dev *dev, int slave,
int err;
struct mlx4_qp_context *context = inbox->buf + 8;
+ err = adjust_qp_sched_queue(dev, slave, context, inbox);
+ if (err)
+ return err;
err = verify_qp_parameters(dev, inbox, QP_TRANS_SQD2SQD, slave);
if (err)
return err;
@@ -3403,6 +3586,9 @@ int mlx4_SQD2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
int err;
struct mlx4_qp_context *context = inbox->buf + 8;
+ err = adjust_qp_sched_queue(dev, slave, context, inbox);
+ if (err)
+ return err;
err = verify_qp_parameters(dev, inbox, QP_TRANS_SQD2RTS, slave);
if (err)
return err;
@@ -3506,16 +3692,26 @@ static int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
return err;
}
-static int qp_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
- int block_loopback, enum mlx4_protocol prot,
+static int qp_attach(struct mlx4_dev *dev, int slave, struct mlx4_qp *qp,
+ u8 gid[16], int block_loopback, enum mlx4_protocol prot,
enum mlx4_steer_type type, u64 *reg_id)
{
switch (dev->caps.steering_mode) {
- case MLX4_STEERING_MODE_DEVICE_MANAGED:
- return mlx4_trans_to_dmfs_attach(dev, qp, gid, gid[5],
+ case MLX4_STEERING_MODE_DEVICE_MANAGED: {
+ int port = mlx4_slave_convert_port(dev, slave, gid[5]);
+ if (port < 0)
+ return port;
+ return mlx4_trans_to_dmfs_attach(dev, qp, gid, port,
block_loopback, prot,
reg_id);
+ }
case MLX4_STEERING_MODE_B0:
+ if (prot == MLX4_PROT_ETH) {
+ int port = mlx4_slave_convert_port(dev, slave, gid[5]);
+ if (port < 0)
+ return port;
+ gid[5] = port;
+ }
return mlx4_qp_attach_common(dev, qp, gid,
block_loopback, prot, type);
default:
@@ -3523,9 +3719,9 @@ static int qp_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
}
}
-static int qp_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
- enum mlx4_protocol prot, enum mlx4_steer_type type,
- u64 reg_id)
+static int qp_detach(struct mlx4_dev *dev, struct mlx4_qp *qp,
+ u8 gid[16], enum mlx4_protocol prot,
+ enum mlx4_steer_type type, u64 reg_id)
{
switch (dev->caps.steering_mode) {
case MLX4_STEERING_MODE_DEVICE_MANAGED:
@@ -3562,7 +3758,7 @@ int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
qp.qpn = qpn;
if (attach) {
- err = qp_attach(dev, &qp, gid, block_loopback, prot,
+ err = qp_attach(dev, slave, &qp, gid, block_loopback, prot,
type, &reg_id);
if (err) {
pr_err("Fail to attach rule to qp 0x%x\n", qpn);
@@ -3698,6 +3894,9 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
return -EOPNOTSUPP;
ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf;
+ ctrl->port = mlx4_slave_convert_port(dev, slave, ctrl->port);
+ if (ctrl->port <= 0)
+ return -EINVAL;
qpn = be32_to_cpu(ctrl->qpn) & 0xffffff;
err = get_res(dev, slave, qpn, RES_QP, &rqp);
if (err) {
@@ -3816,16 +4015,6 @@ int mlx4_QUERY_IF_STAT_wrapper(struct mlx4_dev *dev, int slave,
return err;
}
-int mlx4_FLOW_STEERING_IB_UC_QP_RANGE_wrapper(struct mlx4_dev *dev, int slave,
- struct mlx4_vhcr *vhcr,
- struct mlx4_cmd_mailbox *inbox,
- struct mlx4_cmd_mailbox *outbox,
- struct mlx4_cmd_info *cmd)
-{
- return -EPERM;
-}
-
-
static void detach_qp(struct mlx4_dev *dev, int slave, struct res_qp *rqp)
{
struct res_gid *rgid;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
index 157fe8df2c3e..8ff57e8e3e91 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
@@ -4,5 +4,5 @@
config MLX5_CORE
tristate
- depends on PCI && X86
+ depends on PCI
default n
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index a064f06e0cb8..c3eee5f70051 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -46,8 +46,8 @@
#include "mlx5_core.h"
#define DRIVER_NAME "mlx5_core"
-#define DRIVER_VERSION "1.0"
-#define DRIVER_RELDATE "June 2013"
+#define DRIVER_VERSION "2.2-1"
+#define DRIVER_RELDATE "Feb 2014"
MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
MODULE_DESCRIPTION("Mellanox ConnectX-IB HCA core library");
@@ -116,7 +116,6 @@ static int mlx5_enable_msix(struct mlx5_core_dev *dev)
struct mlx5_eq_table *table = &dev->priv.eq_table;
int num_eqs = 1 << dev->caps.log_max_eq;
int nvec;
- int err;
int i;
nvec = dev->caps.num_ports * num_online_cpus() + MLX5_EQ_VEC_COMP_BASE;
@@ -131,17 +130,12 @@ static int mlx5_enable_msix(struct mlx5_core_dev *dev)
for (i = 0; i < nvec; i++)
table->msix_arr[i].entry = i;
-retry:
- table->num_comp_vectors = nvec - MLX5_EQ_VEC_COMP_BASE;
- err = pci_enable_msix(dev->pdev, table->msix_arr, nvec);
- if (err <= 0) {
- return err;
- } else if (err > 2) {
- nvec = err;
- goto retry;
- }
+ nvec = pci_enable_msix_range(dev->pdev, table->msix_arr,
+ MLX5_EQ_VEC_COMP_BASE, nvec);
+ if (nvec < 0)
+ return nvec;
- mlx5_core_dbg(dev, "received %d MSI vectors out of %d requested\n", err, nvec);
+ table->num_comp_vectors = nvec - MLX5_EQ_VEC_COMP_BASE;
return 0;
}
@@ -446,6 +440,7 @@ int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev)
mlx5_init_cq_table(dev);
mlx5_init_qp_table(dev);
mlx5_init_srq_table(dev);
+ mlx5_init_mr_table(dev);
return 0;
@@ -537,7 +532,6 @@ static int __init init(void)
return 0;
- mlx5_health_cleanup();
err_debug:
mlx5_unregister_debugfs();
return err;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mr.c b/drivers/net/ethernet/mellanox/mlx5/core/mr.c
index 35e514dc7b7d..4cc927649404 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mr.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mr.c
@@ -36,11 +36,24 @@
#include <linux/mlx5/cmd.h>
#include "mlx5_core.h"
+void mlx5_init_mr_table(struct mlx5_core_dev *dev)
+{
+ struct mlx5_mr_table *table = &dev->priv.mr_table;
+
+ rwlock_init(&table->lock);
+ INIT_RADIX_TREE(&table->tree, GFP_ATOMIC);
+}
+
+void mlx5_cleanup_mr_table(struct mlx5_core_dev *dev)
+{
+}
+
int mlx5_core_create_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,
struct mlx5_create_mkey_mbox_in *in, int inlen,
mlx5_cmd_cbk_t callback, void *context,
struct mlx5_create_mkey_mbox_out *out)
{
+ struct mlx5_mr_table *table = &dev->priv.mr_table;
struct mlx5_create_mkey_mbox_out lout;
int err;
u8 key;
@@ -73,14 +86,21 @@ int mlx5_core_create_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,
mlx5_core_dbg(dev, "out 0x%x, key 0x%x, mkey 0x%x\n",
be32_to_cpu(lout.mkey), key, mr->key);
+ /* connect to MR tree */
+ write_lock_irq(&table->lock);
+ err = radix_tree_insert(&table->tree, mlx5_base_mkey(mr->key), mr);
+ write_unlock_irq(&table->lock);
+
return err;
}
EXPORT_SYMBOL(mlx5_core_create_mkey);
int mlx5_core_destroy_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr)
{
+ struct mlx5_mr_table *table = &dev->priv.mr_table;
struct mlx5_destroy_mkey_mbox_in in;
struct mlx5_destroy_mkey_mbox_out out;
+ unsigned long flags;
int err;
memset(&in, 0, sizeof(in));
@@ -95,6 +115,10 @@ int mlx5_core_destroy_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr)
if (out.hdr.status)
return mlx5_cmd_status_to_err(&out.hdr);
+ write_lock_irqsave(&table->lock, flags);
+ radix_tree_delete(&table->tree, mlx5_base_mkey(mr->key));
+ write_unlock_irqrestore(&table->lock, flags);
+
return err;
}
EXPORT_SYMBOL(mlx5_core_destroy_mkey);
@@ -144,3 +168,64 @@ int mlx5_core_dump_fill_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,
return err;
}
EXPORT_SYMBOL(mlx5_core_dump_fill_mkey);
+
+int mlx5_core_create_psv(struct mlx5_core_dev *dev, u32 pdn,
+ int npsvs, u32 *sig_index)
+{
+ struct mlx5_allocate_psv_in in;
+ struct mlx5_allocate_psv_out out;
+ int i, err;
+
+ if (npsvs > MLX5_MAX_PSVS)
+ return -EINVAL;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_PSV);
+ in.npsv_pd = cpu_to_be32((npsvs << 28) | pdn);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ if (err) {
+ mlx5_core_err(dev, "cmd exec failed %d\n", err);
+ return err;
+ }
+
+ if (out.hdr.status) {
+ mlx5_core_err(dev, "create_psv bad status %d\n", out.hdr.status);
+ return mlx5_cmd_status_to_err(&out.hdr);
+ }
+
+ for (i = 0; i < npsvs; i++)
+ sig_index[i] = be32_to_cpu(out.psv_idx[i]) & 0xffffff;
+
+ return err;
+}
+EXPORT_SYMBOL(mlx5_core_create_psv);
+
+int mlx5_core_destroy_psv(struct mlx5_core_dev *dev, int psv_num)
+{
+ struct mlx5_destroy_psv_in in;
+ struct mlx5_destroy_psv_out out;
+ int err;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+
+ in.psv_number = cpu_to_be32(psv_num);
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_PSV);
+ err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ if (err) {
+ mlx5_core_err(dev, "destroy_psv cmd exec failed %d\n", err);
+ goto out;
+ }
+
+ if (out.hdr.status) {
+ mlx5_core_err(dev, "destroy_psv bad status %d\n", out.hdr.status);
+ err = mlx5_cmd_status_to_err(&out.hdr);
+ goto out;
+ }
+
+out:
+ return err;
+}
+EXPORT_SYMBOL(mlx5_core_destroy_psv);
diff --git a/drivers/net/ethernet/micrel/ks8851.c b/drivers/net/ethernet/micrel/ks8851.c
index 727b546a9eb8..e0c92e0e5e1d 100644
--- a/drivers/net/ethernet/micrel/ks8851.c
+++ b/drivers/net/ethernet/micrel/ks8851.c
@@ -23,6 +23,7 @@
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/eeprom_93cx6.h>
+#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
@@ -83,6 +84,7 @@ union ks8851_tx_hdr {
* @rc_rxqcr: Cached copy of KS_RXQCR.
* @eeprom_size: Companion eeprom size in Bytes, 0 if no eeprom
* @eeprom: 93CX6 EEPROM state for accessing on-board EEPROM.
+ * @vdd_reg: Optional regulator supplying the chip
*
* The @lock ensures that the chip is protected when certain operations are
* in progress. When the read or write packet transfer is in progress, most
@@ -130,6 +132,7 @@ struct ks8851_net {
struct spi_transfer spi_xfer2[2];
struct eeprom_93cx6 eeprom;
+ struct regulator *vdd_reg;
};
static int msg_enable;
@@ -1414,6 +1417,21 @@ static int ks8851_probe(struct spi_device *spi)
ks->spidev = spi;
ks->tx_space = 6144;
+ ks->vdd_reg = regulator_get_optional(&spi->dev, "vdd");
+ if (IS_ERR(ks->vdd_reg)) {
+ ret = PTR_ERR(ks->vdd_reg);
+ if (ret == -EPROBE_DEFER)
+ goto err_reg;
+ } else {
+ ret = regulator_enable(ks->vdd_reg);
+ if (ret) {
+ dev_err(&spi->dev, "regulator enable fail: %d\n",
+ ret);
+ goto err_reg_en;
+ }
+ }
+
+
mutex_init(&ks->lock);
spin_lock_init(&ks->statelock);
@@ -1508,8 +1526,14 @@ static int ks8851_probe(struct spi_device *spi)
err_netdev:
free_irq(ndev->irq, ks);
-err_id:
err_irq:
+err_id:
+ if (!IS_ERR(ks->vdd_reg))
+ regulator_disable(ks->vdd_reg);
+err_reg_en:
+ if (!IS_ERR(ks->vdd_reg))
+ regulator_put(ks->vdd_reg);
+err_reg:
free_netdev(ndev);
return ret;
}
@@ -1523,6 +1547,10 @@ static int ks8851_remove(struct spi_device *spi)
unregister_netdev(priv->netdev);
free_irq(spi->irq, priv);
+ if (!IS_ERR(priv->vdd_reg)) {
+ regulator_disable(priv->vdd_reg);
+ regulator_put(priv->vdd_reg);
+ }
free_netdev(priv->netdev);
return 0;
diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c
index ce84dc289c8f..14ac0e2bc09f 100644
--- a/drivers/net/ethernet/micrel/ksz884x.c
+++ b/drivers/net/ethernet/micrel/ksz884x.c
@@ -4832,7 +4832,7 @@ static inline void copy_old_skb(struct sk_buff *old, struct sk_buff *skb)
skb->csum = old->csum;
skb_set_network_header(skb, ETH_HLEN);
- dev_kfree_skb(old);
+ dev_consume_skb_any(old);
}
/**
diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
index 68026f7e8ba3..130f6b204efa 100644
--- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
+++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
@@ -2329,16 +2329,14 @@ static int myri10ge_request_irq(struct myri10ge_priv *mgp)
status = 0;
if (myri10ge_msi) {
if (mgp->num_slices > 1) {
- status =
- pci_enable_msix(pdev, mgp->msix_vectors,
- mgp->num_slices);
- if (status == 0) {
- mgp->msix_enabled = 1;
- } else {
+ status = pci_enable_msix_range(pdev, mgp->msix_vectors,
+ mgp->num_slices, mgp->num_slices);
+ if (status < 0) {
dev_err(&pdev->dev,
"Error %d setting up MSI-X\n", status);
return status;
}
+ mgp->msix_enabled = 1;
}
if (mgp->msix_enabled == 0) {
status = pci_enable_msi(pdev);
@@ -3895,32 +3893,34 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp)
mgp->msix_vectors = kcalloc(mgp->num_slices, sizeof(*mgp->msix_vectors),
GFP_KERNEL);
if (mgp->msix_vectors == NULL)
- goto disable_msix;
+ goto no_msix;
for (i = 0; i < mgp->num_slices; i++) {
mgp->msix_vectors[i].entry = i;
}
while (mgp->num_slices > 1) {
- /* make sure it is a power of two */
- while (!is_power_of_2(mgp->num_slices))
- mgp->num_slices--;
+ mgp->num_slices = rounddown_pow_of_two(mgp->num_slices);
if (mgp->num_slices == 1)
- goto disable_msix;
- status = pci_enable_msix(pdev, mgp->msix_vectors,
- mgp->num_slices);
- if (status == 0) {
- pci_disable_msix(pdev);
+ goto no_msix;
+ status = pci_enable_msix_range(pdev,
+ mgp->msix_vectors,
+ mgp->num_slices,
+ mgp->num_slices);
+ if (status < 0)
+ goto no_msix;
+
+ pci_disable_msix(pdev);
+
+ if (status == mgp->num_slices) {
if (old_allocated)
kfree(old_fw);
return;
- }
- if (status > 0)
+ } else {
mgp->num_slices = status;
- else
- goto disable_msix;
+ }
}
-disable_msix:
+no_msix:
if (mgp->msix_vectors != NULL) {
kfree(mgp->msix_vectors);
mgp->msix_vectors = NULL;
diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c
index 9eeddbd0b2c7..a2844ff322c4 100644
--- a/drivers/net/ethernet/neterion/s2io.c
+++ b/drivers/net/ethernet/neterion/s2io.c
@@ -2914,6 +2914,9 @@ static int rx_intr_handler(struct ring_info *ring_data, int budget)
struct RxD1 *rxdp1;
struct RxD3 *rxdp3;
+ if (budget <= 0)
+ return napi_pkts;
+
get_info = ring_data->rx_curr_get_info;
get_block = get_info.block_index;
memcpy(&put_info, &ring_data->rx_curr_put_info, sizeof(put_info));
@@ -3792,9 +3795,10 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
writeq(rx_mat, &bar0->rx_mat);
readq(&bar0->rx_mat);
- ret = pci_enable_msix(nic->pdev, nic->entries, nic->num_entries);
+ ret = pci_enable_msix_range(nic->pdev, nic->entries,
+ nic->num_entries, nic->num_entries);
/* We fail init if error or we get less vectors than min required */
- if (ret) {
+ if (ret < 0) {
DBG_PRINT(ERR_DBG, "Enabling MSI-X failed\n");
kfree(nic->entries);
swstats->mem_freed += nic->num_entries *
@@ -4045,7 +4049,7 @@ static netdev_tx_t s2io_xmit(struct sk_buff *skb, struct net_device *dev)
if (!is_s2io_card_up(sp)) {
DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
dev->name);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -4118,7 +4122,7 @@ static netdev_tx_t s2io_xmit(struct sk_buff *skb, struct net_device *dev)
((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n");
s2io_stop_tx_queue(sp, fifo->fifo_no);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
spin_unlock_irqrestore(&fifo->tx_lock, flags);
return NETDEV_TX_OK;
}
@@ -4240,7 +4244,7 @@ pci_map_failed:
swstats->pci_map_fail_cnt++;
s2io_stop_tx_queue(sp, fifo->fifo_no);
swstats->mem_freed += skb->truesize;
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
spin_unlock_irqrestore(&fifo->tx_lock, flags);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c
index 1ded50ca1600..d107bcbb8543 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-main.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c
@@ -368,6 +368,9 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
ring->ndev->name, __func__, __LINE__);
+ if (ring->budget <= 0)
+ goto out;
+
do {
prefetch((char *)dtr + L1_CACHE_BYTES);
rx_priv = vxge_hw_ring_rxd_private_get(dtr);
@@ -525,6 +528,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
if (first_dtr)
vxge_hw_ring_rxd_post_post_wmb(ringh, first_dtr);
+out:
vxge_debug_entryexit(VXGE_TRACE,
"%s:%d Exiting...",
__func__, __LINE__);
@@ -726,9 +730,6 @@ static int vxge_learn_mac(struct vxgedev *vdev, u8 *mac_header)
int vpath_idx = 0;
enum vxge_hw_status status = VXGE_HW_OK;
struct vxge_vpath *vpath = NULL;
- struct __vxge_hw_device *hldev;
-
- hldev = pci_get_drvdata(vdev->pdev);
mac_address = (u8 *)&mac_addr;
memcpy(mac_address, mac_header, ETH_ALEN);
@@ -823,7 +824,7 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(skb->len <= 0)) {
vxge_debug_tx(VXGE_ERR,
"%s: Buffer has no data..", dev->name);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -832,7 +833,7 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(!is_vxge_card_up(vdev))) {
vxge_debug_tx(VXGE_ERR,
"%s: vdev not initialized", dev->name);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -842,7 +843,7 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
vxge_debug_tx(VXGE_ERR,
"%s: Failed to store the mac address",
dev->name);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
}
@@ -989,7 +990,7 @@ _exit1:
vxge_hw_fifo_txdl_free(fifo_hw, dtr);
_exit0:
netif_tx_stop_queue(fifo->txq);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -2352,12 +2353,18 @@ start:
vdev->vxge_entries[j].entry = VXGE_ALARM_MSIX_ID;
vdev->vxge_entries[j].in_use = 0;
- ret = pci_enable_msix(vdev->pdev, vdev->entries, vdev->intr_cnt);
- if (ret > 0) {
+ ret = pci_enable_msix_range(vdev->pdev,
+ vdev->entries, 3, vdev->intr_cnt);
+ if (ret < 0) {
+ ret = -ENODEV;
+ goto enable_msix_failed;
+ } else if (ret < vdev->intr_cnt) {
+ pci_disable_msix(vdev->pdev);
+
vxge_debug_init(VXGE_ERR,
"%s: MSI-X enable failed for %d vectors, ret: %d",
VXGE_DRIVER_NAME, vdev->intr_cnt, ret);
- if ((max_config_vpath != VXGE_USE_DEFAULT) || (ret < 3)) {
+ if (max_config_vpath != VXGE_USE_DEFAULT) {
ret = -ENODEV;
goto enable_msix_failed;
}
@@ -2371,9 +2378,6 @@ start:
vxge_close_vpaths(vdev, temp);
vdev->no_of_vpath = temp;
goto start;
- } else if (ret < 0) {
- ret = -ENODEV;
- goto enable_msix_failed;
}
return 0;
@@ -2443,9 +2447,6 @@ static void vxge_rem_msix_isr(struct vxgedev *vdev)
static void vxge_rem_isr(struct vxgedev *vdev)
{
- struct __vxge_hw_device *hldev;
- hldev = pci_get_drvdata(vdev->pdev);
-
#ifdef CONFIG_PCI_MSI
if (vdev->config.intr_type == MSI_X) {
vxge_rem_msix_isr(vdev);
@@ -3137,12 +3138,12 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
u64 packets, bytes, multicast;
do {
- start = u64_stats_fetch_begin_bh(&rxstats->syncp);
+ start = u64_stats_fetch_begin_irq(&rxstats->syncp);
packets = rxstats->rx_frms;
multicast = rxstats->rx_mcast;
bytes = rxstats->rx_bytes;
- } while (u64_stats_fetch_retry_bh(&rxstats->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&rxstats->syncp, start));
net_stats->rx_packets += packets;
net_stats->rx_bytes += bytes;
@@ -3152,11 +3153,11 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
net_stats->rx_dropped += rxstats->rx_dropped;
do {
- start = u64_stats_fetch_begin_bh(&txstats->syncp);
+ start = u64_stats_fetch_begin_irq(&txstats->syncp);
packets = txstats->tx_frms;
bytes = txstats->tx_bytes;
- } while (u64_stats_fetch_retry_bh(&txstats->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&txstats->syncp, start));
net_stats->tx_packets += packets;
net_stats->tx_bytes += bytes;
diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c
index 70cf97fe67f2..fddb464aeab3 100644
--- a/drivers/net/ethernet/nvidia/forcedeth.c
+++ b/drivers/net/ethernet/nvidia/forcedeth.c
@@ -1753,19 +1753,19 @@ nv_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *storage)
/* software stats */
do {
- syncp_start = u64_stats_fetch_begin_bh(&np->swstats_rx_syncp);
+ syncp_start = u64_stats_fetch_begin_irq(&np->swstats_rx_syncp);
storage->rx_packets = np->stat_rx_packets;
storage->rx_bytes = np->stat_rx_bytes;
storage->rx_dropped = np->stat_rx_dropped;
storage->rx_missed_errors = np->stat_rx_missed_errors;
- } while (u64_stats_fetch_retry_bh(&np->swstats_rx_syncp, syncp_start));
+ } while (u64_stats_fetch_retry_irq(&np->swstats_rx_syncp, syncp_start));
do {
- syncp_start = u64_stats_fetch_begin_bh(&np->swstats_tx_syncp);
+ syncp_start = u64_stats_fetch_begin_irq(&np->swstats_tx_syncp);
storage->tx_packets = np->stat_tx_packets;
storage->tx_bytes = np->stat_tx_bytes;
storage->tx_dropped = np->stat_tx_dropped;
- } while (u64_stats_fetch_retry_bh(&np->swstats_tx_syncp, syncp_start));
+ } while (u64_stats_fetch_retry_irq(&np->swstats_tx_syncp, syncp_start));
/* If the nic supports hw counters then retrieve latest values */
if (np->driver_data & DEV_HAS_STATISTICS_V123) {
@@ -2231,7 +2231,7 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (pci_dma_mapping_error(np->pci_dev,
np->put_tx_ctx->dma)) {
/* on DMA mapping error - drop the packet */
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
u64_stats_update_begin(&np->swstats_tx_syncp);
np->stat_tx_dropped++;
u64_stats_update_end(&np->swstats_tx_syncp);
@@ -2277,7 +2277,7 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(tmp_tx_ctx++ == np->last_tx_ctx))
tmp_tx_ctx = np->first_tx_ctx;
} while (tmp_tx_ctx != np->put_tx_ctx);
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
np->put_tx_ctx = start_tx_ctx;
u64_stats_update_begin(&np->swstats_tx_syncp);
np->stat_tx_dropped++;
@@ -2380,7 +2380,7 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
if (pci_dma_mapping_error(np->pci_dev,
np->put_tx_ctx->dma)) {
/* on DMA mapping error - drop the packet */
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
u64_stats_update_begin(&np->swstats_tx_syncp);
np->stat_tx_dropped++;
u64_stats_update_end(&np->swstats_tx_syncp);
@@ -2427,7 +2427,7 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
if (unlikely(tmp_tx_ctx++ == np->last_tx_ctx))
tmp_tx_ctx = np->first_tx_ctx;
} while (tmp_tx_ctx != np->put_tx_ctx);
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
np->put_tx_ctx = start_tx_ctx;
u64_stats_update_begin(&np->swstats_tx_syncp);
np->stat_tx_dropped++;
@@ -3930,7 +3930,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
{
struct fe_priv *np = get_nvpriv(dev);
u8 __iomem *base = get_hwbase(dev);
- int ret = 1;
+ int ret;
int i;
irqreturn_t (*handler)(int foo, void *data);
@@ -3946,14 +3946,18 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
if (np->msi_flags & NV_MSI_X_CAPABLE) {
for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++)
np->msi_x_entry[i].entry = i;
- ret = pci_enable_msix(np->pci_dev, np->msi_x_entry, (np->msi_flags & NV_MSI_X_VECTORS_MASK));
- if (ret == 0) {
+ ret = pci_enable_msix_range(np->pci_dev,
+ np->msi_x_entry,
+ np->msi_flags & NV_MSI_X_VECTORS_MASK,
+ np->msi_flags & NV_MSI_X_VECTORS_MASK);
+ if (ret > 0) {
np->msi_flags |= NV_MSI_X_ENABLED;
if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT && !intr_test) {
/* Request irq for rx handling */
sprintf(np->name_rx, "%s-rx", dev->name);
- if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector,
- nv_nic_irq_rx, IRQF_SHARED, np->name_rx, dev) != 0) {
+ ret = request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector,
+ nv_nic_irq_rx, IRQF_SHARED, np->name_rx, dev);
+ if (ret) {
netdev_info(dev,
"request_irq failed for rx %d\n",
ret);
@@ -3963,8 +3967,9 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
}
/* Request irq for tx handling */
sprintf(np->name_tx, "%s-tx", dev->name);
- if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector,
- nv_nic_irq_tx, IRQF_SHARED, np->name_tx, dev) != 0) {
+ ret = request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector,
+ nv_nic_irq_tx, IRQF_SHARED, np->name_tx, dev);
+ if (ret) {
netdev_info(dev,
"request_irq failed for tx %d\n",
ret);
@@ -3974,8 +3979,9 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
}
/* Request irq for link and timer handling */
sprintf(np->name_other, "%s-other", dev->name);
- if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector,
- nv_nic_irq_other, IRQF_SHARED, np->name_other, dev) != 0) {
+ ret = request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector,
+ nv_nic_irq_other, IRQF_SHARED, np->name_other, dev);
+ if (ret) {
netdev_info(dev,
"request_irq failed for link %d\n",
ret);
@@ -3991,7 +3997,9 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
set_msix_vector_map(dev, NV_MSI_X_VECTOR_OTHER, NVREG_IRQ_OTHER);
} else {
/* Request irq for all interrupts */
- if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, handler, IRQF_SHARED, dev->name, dev) != 0) {
+ ret = request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector,
+ handler, IRQF_SHARED, dev->name, dev);
+ if (ret) {
netdev_info(dev,
"request_irq failed %d\n",
ret);
@@ -4005,13 +4013,15 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
writel(0, base + NvRegMSIXMap1);
}
netdev_info(dev, "MSI-X enabled\n");
+ return 0;
}
}
- if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) {
+ if (np->msi_flags & NV_MSI_CAPABLE) {
ret = pci_enable_msi(np->pci_dev);
if (ret == 0) {
np->msi_flags |= NV_MSI_ENABLED;
- if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0) {
+ ret = request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev);
+ if (ret) {
netdev_info(dev, "request_irq failed %d\n",
ret);
pci_disable_msi(np->pci_dev);
@@ -4025,13 +4035,12 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
/* enable msi vector 0 */
writel(NVREG_MSI_VECTOR_0_ENABLED, base + NvRegMSIIrqMask);
netdev_info(dev, "MSI enabled\n");
+ return 0;
}
}
- if (ret != 0) {
- if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0)
- goto out_err;
- }
+ if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0)
+ goto out_err;
return 0;
out_free_tx:
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
index 464e91058c81..73e66838cfef 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
@@ -120,10 +120,6 @@ static void pch_gbe_mdio_write(struct net_device *netdev, int addr, int reg,
int data);
static void pch_gbe_set_multi(struct net_device *netdev);
-static struct sock_filter ptp_filter[] = {
- PTP_FILTER
-};
-
static int pch_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid)
{
u8 *data = skb->data;
@@ -131,7 +127,7 @@ static int pch_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid)
u16 *hi, *id;
u32 lo;
- if (sk_run_filter(skb, ptp_filter) == PTP_CLASS_NONE)
+ if (ptp_classify_raw(skb) == PTP_CLASS_NONE)
return 0;
offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN;
@@ -2635,11 +2631,6 @@ static int pch_gbe_probe(struct pci_dev *pdev,
adapter->ptp_pdev = pci_get_bus_and_slot(adapter->pdev->bus->number,
PCI_DEVFN(12, 4));
- if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter))) {
- dev_err(&pdev->dev, "Bad ptp filter\n");
- ret = -EINVAL;
- goto err_free_netdev;
- }
netdev->netdev_ops = &pch_gbe_netdev_ops;
netdev->watchdog_timeo = PCH_GBE_WATCHDOG_PERIOD;
diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig
index f59e6be4a66e..c14bd3116e45 100644
--- a/drivers/net/ethernet/qlogic/Kconfig
+++ b/drivers/net/ethernet/qlogic/Kconfig
@@ -56,6 +56,16 @@ config QLCNIC_DCB
mode of DCB is supported. PG and PFC values are related only
to Tx.
+config QLCNIC_VXLAN
+ bool "Virtual eXtensible Local Area Network (VXLAN) offload support"
+ default n
+ depends on QLCNIC && VXLAN && !(QLCNIC=y && VXLAN=m)
+ ---help---
+ This enables hardware offload support for VXLAN protocol over QLogic's
+ 84XX series adapters.
+ Say Y here if you want to enable hardware offload support for
+ Virtual eXtensible Local Area Network (VXLAN) in the driver.
+
config QLGE
tristate "QLogic QLGE 10Gb Ethernet Driver Support"
depends on PCI
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
index 70849dea32b1..f09c35d669b3 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
@@ -643,8 +643,9 @@ static int netxen_setup_msi_interrupts(struct netxen_adapter *adapter,
if (adapter->msix_supported) {
netxen_init_msix_entries(adapter, num_msix);
- err = pci_enable_msix(pdev, adapter->msix_entries, num_msix);
- if (err == 0) {
+ err = pci_enable_msix_range(pdev, adapter->msix_entries,
+ num_msix, num_msix);
+ if (err > 0) {
adapter->flags |= NETXEN_NIC_MSIX_ENABLED;
netxen_set_msix_bit(pdev, 1);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index f19f81cde134..f31bb5e9d8a9 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -38,8 +38,8 @@
#define _QLCNIC_LINUX_MAJOR 5
#define _QLCNIC_LINUX_MINOR 3
-#define _QLCNIC_LINUX_SUBVERSION 55
-#define QLCNIC_LINUX_VERSIONID "5.3.55"
+#define _QLCNIC_LINUX_SUBVERSION 57
+#define QLCNIC_LINUX_VERSIONID "5.3.57"
#define QLCNIC_DRV_IDC_VER 0x01
#define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\
(_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
@@ -169,11 +169,20 @@ struct cmd_desc_type0 {
__le64 addr_buffer2;
- __le16 reference_handle;
+ __le16 encap_descr; /* 15:10 offset of outer L3 header,
+ * 9:6 number of 32bit words in outer L3 header,
+ * 5 offload outer L4 checksum,
+ * 4 offload outer L3 checksum,
+ * 3 Inner L4 type, TCP=0, UDP=1,
+ * 2 Inner L3 type, IPv4=0, IPv6=1,
+ * 1 Outer L3 type,IPv4=0, IPv6=1,
+ * 0 type of encapsulation, GRE=0, VXLAN=1
+ */
__le16 mss;
u8 port_ctxid; /* 7:4 ctxid 3:0 port */
- u8 total_hdr_length; /* LSO only : MAC+IP+TCP Hdr size */
- __le16 conn_id; /* IPSec offoad only */
+ u8 hdr_length; /* LSO only : MAC+IP+TCP Hdr size */
+ u8 outer_hdr_length; /* Encapsulation only */
+ u8 rsvd1;
__le64 addr_buffer3;
__le64 addr_buffer1;
@@ -183,7 +192,9 @@ struct cmd_desc_type0 {
__le64 addr_buffer4;
u8 eth_addr[ETH_ALEN];
- __le16 vlan_TCI;
+ __le16 vlan_TCI; /* In case of encapsulation,
+ * this is for outer VLAN
+ */
} __attribute__ ((aligned(64)));
@@ -394,7 +405,7 @@ struct qlcnic_nic_intr_coalesce {
u32 timer_out;
};
-struct qlcnic_dump_template_hdr {
+struct qlcnic_83xx_dump_template_hdr {
u32 type;
u32 offset;
u32 size;
@@ -411,15 +422,42 @@ struct qlcnic_dump_template_hdr {
u32 rsvd[0];
};
+struct qlcnic_82xx_dump_template_hdr {
+ u32 type;
+ u32 offset;
+ u32 size;
+ u32 cap_mask;
+ u32 num_entries;
+ u32 version;
+ u32 timestamp;
+ u32 checksum;
+ u32 drv_cap_mask;
+ u32 sys_info[3];
+ u32 saved_state[16];
+ u32 cap_sizes[8];
+ u32 rsvd[7];
+ u32 capabilities;
+ u32 rsvd1[0];
+};
+
struct qlcnic_fw_dump {
u8 clr; /* flag to indicate if dump is cleared */
bool enable; /* enable/disable dump */
u32 size; /* total size of the dump */
+ u32 cap_mask; /* Current capture mask */
void *data; /* dump data area */
- struct qlcnic_dump_template_hdr *tmpl_hdr;
+ void *tmpl_hdr;
dma_addr_t phys_addr;
void *dma_buffer;
bool use_pex_dma;
+ /* Read only elements which are common between 82xx and 83xx
+ * template header. Update these values immediately after we read
+ * template header from Firmware
+ */
+ u32 tmpl_hdr_size;
+ u32 version;
+ u32 num_entries;
+ u32 offset;
};
/*
@@ -497,6 +535,7 @@ struct qlcnic_hardware_context {
u8 extend_lb_time;
u8 phys_port_id[ETH_ALEN];
u8 lb_mode;
+ u16 vxlan_port;
};
struct qlcnic_adapter_stats {
@@ -511,6 +550,9 @@ struct qlcnic_adapter_stats {
u64 txbytes;
u64 lrobytes;
u64 lso_frames;
+ u64 encap_lso_frames;
+ u64 encap_tx_csummed;
+ u64 encap_rx_csummed;
u64 xmit_on;
u64 xmit_off;
u64 skb_alloc_failure;
@@ -872,6 +914,10 @@ struct qlcnic_mac_vlan_list {
#define QLCNIC_FW_CAPABILITY_2_BEACON BIT_7
#define QLCNIC_FW_CAPABILITY_2_PER_PORT_ESWITCH_CFG BIT_9
+#define QLCNIC_83XX_FW_CAPAB_ENCAP_RX_OFFLOAD BIT_0
+#define QLCNIC_83XX_FW_CAPAB_ENCAP_TX_OFFLOAD BIT_1
+#define QLCNIC_83XX_FW_CAPAB_ENCAP_CKO_OFFLOAD BIT_4
+
/* module types */
#define LINKEVENT_MODULE_NOT_PRESENT 1
#define LINKEVENT_MODULE_OPTICAL_UNKNOWN 2
@@ -966,6 +1012,11 @@ struct qlcnic_ipaddr {
#define QLCNIC_HAS_PHYS_PORT_ID 0x40000
#define QLCNIC_TSS_RSS 0x80000
+#ifdef CONFIG_QLCNIC_VXLAN
+#define QLCNIC_ADD_VXLAN_PORT 0x100000
+#define QLCNIC_DEL_VXLAN_PORT 0x200000
+#endif
+
#define QLCNIC_IS_MSI_FAMILY(adapter) \
((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
#define QLCNIC_IS_TSO_CAPABLE(adapter) \
@@ -1769,10 +1820,28 @@ struct qlcnic_hardware_ops {
struct qlcnic_host_tx_ring *);
void (*disable_tx_intr) (struct qlcnic_adapter *,
struct qlcnic_host_tx_ring *);
+ u32 (*get_saved_state)(void *, u32);
+ void (*set_saved_state)(void *, u32, u32);
+ void (*cache_tmpl_hdr_values)(struct qlcnic_fw_dump *);
+ u32 (*get_cap_size)(void *, int);
+ void (*set_sys_info)(void *, int, u32);
+ void (*store_cap_mask)(void *, u32);
};
extern struct qlcnic_nic_template qlcnic_vf_ops;
+static inline bool qlcnic_encap_tx_offload(struct qlcnic_adapter *adapter)
+{
+ return adapter->ahw->extra_capability[0] &
+ QLCNIC_83XX_FW_CAPAB_ENCAP_TX_OFFLOAD;
+}
+
+static inline bool qlcnic_encap_rx_offload(struct qlcnic_adapter *adapter)
+{
+ return adapter->ahw->extra_capability[0] &
+ QLCNIC_83XX_FW_CAPAB_ENCAP_RX_OFFLOAD;
+}
+
static inline int qlcnic_start_firmware(struct qlcnic_adapter *adapter)
{
return adapter->nic_ops->start_firmware(adapter);
@@ -2007,6 +2076,42 @@ static inline void qlcnic_read_phys_port_id(struct qlcnic_adapter *adapter)
adapter->ahw->hw_ops->read_phys_port_id(adapter);
}
+static inline u32 qlcnic_get_saved_state(struct qlcnic_adapter *adapter,
+ void *t_hdr, u32 index)
+{
+ return adapter->ahw->hw_ops->get_saved_state(t_hdr, index);
+}
+
+static inline void qlcnic_set_saved_state(struct qlcnic_adapter *adapter,
+ void *t_hdr, u32 index, u32 value)
+{
+ adapter->ahw->hw_ops->set_saved_state(t_hdr, index, value);
+}
+
+static inline void qlcnic_cache_tmpl_hdr_values(struct qlcnic_adapter *adapter,
+ struct qlcnic_fw_dump *fw_dump)
+{
+ adapter->ahw->hw_ops->cache_tmpl_hdr_values(fw_dump);
+}
+
+static inline u32 qlcnic_get_cap_size(struct qlcnic_adapter *adapter,
+ void *tmpl_hdr, int index)
+{
+ return adapter->ahw->hw_ops->get_cap_size(tmpl_hdr, index);
+}
+
+static inline void qlcnic_set_sys_info(struct qlcnic_adapter *adapter,
+ void *tmpl_hdr, int idx, u32 value)
+{
+ adapter->ahw->hw_ops->set_sys_info(tmpl_hdr, idx, value);
+}
+
+static inline void qlcnic_store_cap_mask(struct qlcnic_adapter *adapter,
+ void *tmpl_hdr, u32 mask)
+{
+ adapter->ahw->hw_ops->store_cap_mask(tmpl_hdr, mask);
+}
+
static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter,
u32 key)
{
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index 4146664d4d6a..b7cffb46a75d 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -77,7 +77,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
{QLCNIC_CMD_GET_PORT_CONFIG, 2, 2},
{QLCNIC_CMD_GET_LINK_STATUS, 2, 4},
{QLCNIC_CMD_IDC_ACK, 5, 1},
- {QLCNIC_CMD_INIT_NIC_FUNC, 2, 1},
+ {QLCNIC_CMD_INIT_NIC_FUNC, 3, 1},
{QLCNIC_CMD_STOP_NIC_FUNC, 2, 1},
{QLCNIC_CMD_SET_LED_CONFIG, 5, 1},
{QLCNIC_CMD_GET_LED_CONFIG, 1, 5},
@@ -87,6 +87,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
{QLCNIC_CMD_BC_EVENT_SETUP, 2, 1},
{QLCNIC_CMD_DCB_QUERY_CAP, 1, 2},
{QLCNIC_CMD_DCB_QUERY_PARAM, 1, 50},
+ {QLCNIC_CMD_SET_INGRESS_ENCAP, 2, 1},
};
const u32 qlcnic_83xx_ext_reg_tbl[] = {
@@ -203,7 +204,12 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = {
.disable_sds_intr = qlcnic_83xx_disable_sds_intr,
.enable_tx_intr = qlcnic_83xx_enable_tx_intr,
.disable_tx_intr = qlcnic_83xx_disable_tx_intr,
-
+ .get_saved_state = qlcnic_83xx_get_saved_state,
+ .set_saved_state = qlcnic_83xx_set_saved_state,
+ .cache_tmpl_hdr_values = qlcnic_83xx_cache_tmpl_hdr_values,
+ .get_cap_size = qlcnic_83xx_get_cap_size,
+ .set_sys_info = qlcnic_83xx_set_sys_info,
+ .store_cap_mask = qlcnic_83xx_store_cap_mask,
};
static struct qlcnic_nic_template qlcnic_83xx_ops = {
@@ -340,6 +346,7 @@ int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter)
if (qlcnic_sriov_vf_check(adapter))
return -EINVAL;
num_msix = 1;
+ adapter->drv_sds_rings = QLCNIC_SINGLE_RING;
adapter->drv_tx_rings = QLCNIC_SINGLE_RING;
}
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
index f92485ca21d1..88d809c35633 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
@@ -308,6 +308,8 @@ struct qlc_83xx_reset {
#define QLC_83XX_IDC_FLASH_PARAM_ADDR 0x3e8020
struct qlcnic_adapter;
+struct qlcnic_fw_dump;
+
struct qlc_83xx_idc {
int (*state_entry) (struct qlcnic_adapter *);
u64 sec_counter;
@@ -526,8 +528,9 @@ enum qlc_83xx_ext_regs {
};
/* Initialize/Stop NIC command bit definitions */
-#define QLC_REGISTER_DCB_AEN BIT_1
#define QLC_REGISTER_LB_IDC BIT_0
+#define QLC_REGISTER_DCB_AEN BIT_1
+#define QLC_83XX_MULTI_TENANCY_INFO BIT_29
#define QLC_INIT_FW_RESOURCES BIT_31
/* 83xx funcitons */
@@ -650,4 +653,10 @@ int qlcnic_83xx_check_vnic_state(struct qlcnic_adapter *);
void qlcnic_83xx_aer_stop_poll_work(struct qlcnic_adapter *);
int qlcnic_83xx_aer_reset(struct qlcnic_adapter *);
void qlcnic_83xx_aer_start_poll_work(struct qlcnic_adapter *);
+u32 qlcnic_83xx_get_saved_state(void *, u32);
+void qlcnic_83xx_set_saved_state(void *, u32, u32);
+void qlcnic_83xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *);
+u32 qlcnic_83xx_get_cap_size(void *, int);
+void qlcnic_83xx_set_sys_info(void *, int, u32);
+void qlcnic_83xx_store_cap_mask(void *, u32);
#endif
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
index 90a2dda351ec..b48737dcd3c5 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -1020,10 +1020,99 @@ static int qlcnic_83xx_idc_check_state_validity(struct qlcnic_adapter *adapter,
return 0;
}
+#ifdef CONFIG_QLCNIC_VXLAN
+#define QLC_83XX_ENCAP_TYPE_VXLAN BIT_1
+#define QLC_83XX_MATCH_ENCAP_ID BIT_2
+#define QLC_83XX_SET_VXLAN_UDP_DPORT BIT_3
+#define QLC_83XX_VXLAN_UDP_DPORT(PORT) ((PORT & 0xffff) << 16)
+
+#define QLCNIC_ENABLE_INGRESS_ENCAP_PARSING 1
+#define QLCNIC_DISABLE_INGRESS_ENCAP_PARSING 0
+
+static int qlcnic_set_vxlan_port(struct qlcnic_adapter *adapter)
+{
+ u16 port = adapter->ahw->vxlan_port;
+ struct qlcnic_cmd_args cmd;
+ int ret = 0;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ ret = qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_INIT_NIC_FUNC);
+ if (ret)
+ return ret;
+
+ cmd.req.arg[1] = QLC_83XX_MULTI_TENANCY_INFO;
+ cmd.req.arg[2] = QLC_83XX_ENCAP_TYPE_VXLAN |
+ QLC_83XX_SET_VXLAN_UDP_DPORT |
+ QLC_83XX_VXLAN_UDP_DPORT(port);
+
+ ret = qlcnic_issue_cmd(adapter, &cmd);
+ if (ret)
+ netdev_err(adapter->netdev,
+ "Failed to set VXLAN port %d in adapter\n",
+ port);
+
+ qlcnic_free_mbx_args(&cmd);
+
+ return ret;
+}
+
+static int qlcnic_set_vxlan_parsing(struct qlcnic_adapter *adapter,
+ bool state)
+{
+ u16 vxlan_port = adapter->ahw->vxlan_port;
+ struct qlcnic_cmd_args cmd;
+ int ret = 0;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ ret = qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_SET_INGRESS_ENCAP);
+ if (ret)
+ return ret;
+
+ cmd.req.arg[1] = state ? QLCNIC_ENABLE_INGRESS_ENCAP_PARSING :
+ QLCNIC_DISABLE_INGRESS_ENCAP_PARSING;
+
+ ret = qlcnic_issue_cmd(adapter, &cmd);
+ if (ret)
+ netdev_err(adapter->netdev,
+ "Failed to %s VXLAN parsing for port %d\n",
+ state ? "enable" : "disable", vxlan_port);
+ else
+ netdev_info(adapter->netdev,
+ "%s VXLAN parsing for port %d\n",
+ state ? "Enabled" : "Disabled", vxlan_port);
+
+ qlcnic_free_mbx_args(&cmd);
+
+ return ret;
+}
+#endif
+
static void qlcnic_83xx_periodic_tasks(struct qlcnic_adapter *adapter)
{
if (adapter->fhash.fnum)
qlcnic_prune_lb_filters(adapter);
+
+#ifdef CONFIG_QLCNIC_VXLAN
+ if (adapter->flags & QLCNIC_ADD_VXLAN_PORT) {
+ if (qlcnic_set_vxlan_port(adapter))
+ return;
+
+ if (qlcnic_set_vxlan_parsing(adapter, true))
+ return;
+
+ adapter->flags &= ~QLCNIC_ADD_VXLAN_PORT;
+ } else if (adapter->flags & QLCNIC_DEL_VXLAN_PORT) {
+ if (qlcnic_set_vxlan_parsing(adapter, false))
+ return;
+
+ adapter->ahw->vxlan_port = 0;
+ adapter->flags &= ~QLCNIC_DEL_VXLAN_PORT;
+ }
+#endif
}
/**
@@ -1301,7 +1390,7 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter)
addr = (u64)dest;
ret = qlcnic_83xx_ms_mem_write128(adapter, addr,
- (u32 *)p_cache, size / 16);
+ p_cache, size / 16);
if (ret) {
dev_err(&adapter->pdev->dev, "MS memory write failed\n");
release_firmware(fw);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c
index 77f1bce432d2..7d4f54912bad 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c
@@ -807,7 +807,7 @@ qlcnic_dcb_get_pg_tc_cfg_tx(struct net_device *netdev, int tc, u8 *prio,
!type->tc_param_valid)
return;
- if (tc < 0 || (tc > QLC_DCB_MAX_TC))
+ if (tc < 0 || (tc >= QLC_DCB_MAX_TC))
return;
tc_cfg = &type->tc_cfg[tc];
@@ -843,7 +843,7 @@ static void qlcnic_dcb_get_pg_bwg_cfg_tx(struct net_device *netdev, int pgid,
!type->tc_param_valid)
return;
- if (pgid < 0 || pgid > QLC_DCB_MAX_PG)
+ if (pgid < 0 || pgid >= QLC_DCB_MAX_PG)
return;
pgcfg = &type->pg_cfg[pgid];
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
index acee1a5d80c6..5bacf5210aed 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
@@ -47,6 +47,12 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
{"lro_pkts", QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},
{"lrobytes", QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)},
{"lso_frames", QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)},
+ {"encap_lso_frames", QLC_SIZEOF(stats.encap_lso_frames),
+ QLC_OFF(stats.encap_lso_frames)},
+ {"encap_tx_csummed", QLC_SIZEOF(stats.encap_tx_csummed),
+ QLC_OFF(stats.encap_tx_csummed)},
+ {"encap_rx_csummed", QLC_SIZEOF(stats.encap_rx_csummed),
+ QLC_OFF(stats.encap_rx_csummed)},
{"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure),
QLC_OFF(stats.skb_alloc_failure)},
{"mac_filter_limit_overrun", QLC_SIZEOF(stats.mac_filter_limit_overrun),
@@ -1639,14 +1645,14 @@ qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
}
if (fw_dump->clr)
- dump->len = fw_dump->tmpl_hdr->size + fw_dump->size;
+ dump->len = fw_dump->tmpl_hdr_size + fw_dump->size;
else
dump->len = 0;
if (!qlcnic_check_fw_dump_state(adapter))
dump->flag = ETH_FW_DUMP_DISABLE;
else
- dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
+ dump->flag = fw_dump->cap_mask;
dump->version = adapter->fw_version;
return 0;
@@ -1671,9 +1677,10 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
netdev_info(netdev, "Dump not available\n");
return -EINVAL;
}
+
/* Copy template header first */
- copy_sz = fw_dump->tmpl_hdr->size;
- hdr_ptr = (u32 *) fw_dump->tmpl_hdr;
+ copy_sz = fw_dump->tmpl_hdr_size;
+ hdr_ptr = (u32 *)fw_dump->tmpl_hdr;
data = buffer;
for (i = 0; i < copy_sz/sizeof(u32); i++)
*data++ = cpu_to_le32(*hdr_ptr++);
@@ -1681,7 +1688,7 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
/* Copy captured dump data */
memcpy(buffer + copy_sz, fw_dump->data, fw_dump->size);
dump->len = copy_sz + fw_dump->size;
- dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
+ dump->flag = fw_dump->cap_mask;
/* Free dump area once data has been captured */
vfree(fw_dump->data);
@@ -1703,7 +1710,11 @@ static int qlcnic_set_dump_mask(struct qlcnic_adapter *adapter, u32 mask)
return -EOPNOTSUPP;
}
- fw_dump->tmpl_hdr->drv_cap_mask = mask;
+ fw_dump->cap_mask = mask;
+
+ /* Store new capture mask in template header as well*/
+ qlcnic_store_cap_mask(adapter, fw_dump->tmpl_hdr, mask);
+
netdev_info(netdev, "Driver mask changed to: 0x%x\n", mask);
return 0;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
index 03d18a0be6ce..9f3adf4e70b5 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -317,9 +317,7 @@ 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 timeout = 0;
- int err = 0;
- u32 done = 0;
+ int timeout = 0, err = 0, done = 0;
while (!done) {
done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)),
@@ -327,10 +325,20 @@ qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
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, &err) : -1);
+ if (id_reg) {
+ done = QLCRD32(adapter, id_reg, &err);
+ if (done != -1)
+ dev_err(&adapter->pdev->dev,
+ "Failed to acquire sem=%d lock held by=%d\n",
+ sem, done);
+ else
+ dev_err(&adapter->pdev->dev,
+ "Failed to acquire sem=%d lock",
+ sem);
+ } else {
+ dev_err(&adapter->pdev->dev,
+ "Failed to acquire sem=%d lock", sem);
+ }
return -EIO;
}
msleep(1);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
index 63d75617d445..cbe2399c30a0 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
@@ -98,6 +98,7 @@ enum qlcnic_regs {
#define QLCNIC_CMD_GET_LINK_EVENT 0x48
#define QLCNIC_CMD_CONFIGURE_MAC_RX_MODE 0x49
#define QLCNIC_CMD_CONFIGURE_HW_LRO 0x4A
+#define QLCNIC_CMD_SET_INGRESS_ENCAP 0x4E
#define QLCNIC_CMD_INIT_NIC_FUNC 0x60
#define QLCNIC_CMD_STOP_NIC_FUNC 0x61
#define QLCNIC_CMD_IDC_ACK 0x63
@@ -161,6 +162,7 @@ struct qlcnic_host_sds_ring;
struct qlcnic_host_tx_ring;
struct qlcnic_hardware_context;
struct qlcnic_adapter;
+struct qlcnic_fw_dump;
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);
@@ -213,4 +215,11 @@ int qlcnic_82xx_shutdown(struct pci_dev *);
int qlcnic_82xx_resume(struct qlcnic_adapter *);
void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed);
void qlcnic_fw_poll_work(struct work_struct *work);
+
+u32 qlcnic_82xx_get_saved_state(void *, u32);
+void qlcnic_82xx_set_saved_state(void *, u32, u32);
+void qlcnic_82xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *);
+u32 qlcnic_82xx_get_cap_size(void *, int);
+void qlcnic_82xx_set_sys_info(void *, int, u32);
+void qlcnic_82xx_store_cap_mask(void *, u32);
#endif /* __QLCNIC_HW_H_ */
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
index 54ebf300332a..173b3d12991f 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -13,16 +13,19 @@
#include "qlcnic.h"
-#define TX_ETHER_PKT 0x01
-#define TX_TCP_PKT 0x02
-#define TX_UDP_PKT 0x03
-#define TX_IP_PKT 0x04
-#define TX_TCP_LSO 0x05
-#define TX_TCP_LSO6 0x06
-#define TX_TCPV6_PKT 0x0b
-#define TX_UDPV6_PKT 0x0c
-#define FLAGS_VLAN_TAGGED 0x10
-#define FLAGS_VLAN_OOB 0x40
+#define QLCNIC_TX_ETHER_PKT 0x01
+#define QLCNIC_TX_TCP_PKT 0x02
+#define QLCNIC_TX_UDP_PKT 0x03
+#define QLCNIC_TX_IP_PKT 0x04
+#define QLCNIC_TX_TCP_LSO 0x05
+#define QLCNIC_TX_TCP_LSO6 0x06
+#define QLCNIC_TX_ENCAP_PKT 0x07
+#define QLCNIC_TX_ENCAP_LSO 0x08
+#define QLCNIC_TX_TCPV6_PKT 0x0b
+#define QLCNIC_TX_UDPV6_PKT 0x0c
+
+#define QLCNIC_FLAGS_VLAN_TAGGED 0x10
+#define QLCNIC_FLAGS_VLAN_OOB 0x40
#define qlcnic_set_tx_vlan_tci(cmd_desc, v) \
(cmd_desc)->vlan_TCI = cpu_to_le16(v);
@@ -364,6 +367,101 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
spin_unlock(&adapter->mac_learn_lock);
}
+#define QLCNIC_ENCAP_VXLAN_PKT BIT_0
+#define QLCNIC_ENCAP_OUTER_L3_IP6 BIT_1
+#define QLCNIC_ENCAP_INNER_L3_IP6 BIT_2
+#define QLCNIC_ENCAP_INNER_L4_UDP BIT_3
+#define QLCNIC_ENCAP_DO_L3_CSUM BIT_4
+#define QLCNIC_ENCAP_DO_L4_CSUM BIT_5
+
+static int qlcnic_tx_encap_pkt(struct qlcnic_adapter *adapter,
+ struct cmd_desc_type0 *first_desc,
+ struct sk_buff *skb,
+ struct qlcnic_host_tx_ring *tx_ring)
+{
+ u8 opcode = 0, inner_hdr_len = 0, outer_hdr_len = 0, total_hdr_len = 0;
+ int copied, copy_len, descr_size;
+ u32 producer = tx_ring->producer;
+ struct cmd_desc_type0 *hwdesc;
+ u16 flags = 0, encap_descr = 0;
+
+ opcode = QLCNIC_TX_ETHER_PKT;
+ encap_descr = QLCNIC_ENCAP_VXLAN_PKT;
+
+ if (skb_is_gso(skb)) {
+ inner_hdr_len = skb_inner_transport_header(skb) +
+ inner_tcp_hdrlen(skb) -
+ skb_inner_mac_header(skb);
+
+ /* VXLAN header size = 8 */
+ outer_hdr_len = skb_transport_offset(skb) + 8 +
+ sizeof(struct udphdr);
+ first_desc->outer_hdr_length = outer_hdr_len;
+ total_hdr_len = inner_hdr_len + outer_hdr_len;
+ encap_descr |= QLCNIC_ENCAP_DO_L3_CSUM |
+ QLCNIC_ENCAP_DO_L4_CSUM;
+ first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
+ first_desc->hdr_length = inner_hdr_len;
+
+ /* Copy inner and outer headers in Tx descriptor(s)
+ * If total_hdr_len > cmd_desc_type0, use multiple
+ * descriptors
+ */
+ copied = 0;
+ descr_size = (int)sizeof(struct cmd_desc_type0);
+ while (copied < total_hdr_len) {
+ copy_len = min(descr_size, (total_hdr_len - copied));
+ hwdesc = &tx_ring->desc_head[producer];
+ tx_ring->cmd_buf_arr[producer].skb = NULL;
+ skb_copy_from_linear_data_offset(skb, copied,
+ (char *)hwdesc,
+ copy_len);
+ copied += copy_len;
+ producer = get_next_index(producer, tx_ring->num_desc);
+ }
+
+ tx_ring->producer = producer;
+
+ /* Make sure updated tx_ring->producer is visible
+ * for qlcnic_tx_avail()
+ */
+ smp_mb();
+ adapter->stats.encap_lso_frames++;
+
+ opcode = QLCNIC_TX_ENCAP_LSO;
+ } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (inner_ip_hdr(skb)->version == 6) {
+ if (inner_ipv6_hdr(skb)->nexthdr == IPPROTO_UDP)
+ encap_descr |= QLCNIC_ENCAP_INNER_L4_UDP;
+ } else {
+ if (inner_ip_hdr(skb)->protocol == IPPROTO_UDP)
+ encap_descr |= QLCNIC_ENCAP_INNER_L4_UDP;
+ }
+
+ adapter->stats.encap_tx_csummed++;
+ opcode = QLCNIC_TX_ENCAP_PKT;
+ }
+
+ /* Prepare first 16 bits of byte offset 16 of Tx descriptor */
+ if (ip_hdr(skb)->version == 6)
+ encap_descr |= QLCNIC_ENCAP_OUTER_L3_IP6;
+
+ /* outer IP header's size in 32bit words size*/
+ encap_descr |= (skb_network_header_len(skb) >> 2) << 6;
+
+ /* outer IP header offset */
+ encap_descr |= skb_network_offset(skb) << 10;
+ first_desc->encap_descr = cpu_to_le16(encap_descr);
+
+ first_desc->tcp_hdr_offset = skb_inner_transport_header(skb) -
+ skb->data;
+ first_desc->ip_hdr_offset = skb_inner_network_offset(skb);
+
+ qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
+
+ return 0;
+}
+
static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter,
struct cmd_desc_type0 *first_desc, struct sk_buff *skb,
struct qlcnic_host_tx_ring *tx_ring)
@@ -378,11 +476,11 @@ static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter,
if (protocol == ETH_P_8021Q) {
vh = (struct vlan_ethhdr *)skb->data;
- flags = FLAGS_VLAN_TAGGED;
+ flags = QLCNIC_FLAGS_VLAN_TAGGED;
vlan_tci = ntohs(vh->h_vlan_TCI);
protocol = ntohs(vh->h_vlan_encapsulated_proto);
} else if (vlan_tx_tag_present(skb)) {
- flags = FLAGS_VLAN_OOB;
+ flags = QLCNIC_FLAGS_VLAN_OOB;
vlan_tci = vlan_tx_tag_get(skb);
}
if (unlikely(adapter->tx_pvid)) {
@@ -391,7 +489,7 @@ static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter,
if (vlan_tci && (adapter->flags & QLCNIC_TAGGING_ENABLED))
goto set_flags;
- flags = FLAGS_VLAN_OOB;
+ flags = QLCNIC_FLAGS_VLAN_OOB;
vlan_tci = adapter->tx_pvid;
}
set_flags:
@@ -402,25 +500,26 @@ set_flags:
flags |= BIT_0;
memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN);
}
- opcode = TX_ETHER_PKT;
+ opcode = QLCNIC_TX_ETHER_PKT;
if (skb_is_gso(skb)) {
hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
- first_desc->total_hdr_length = hdr_len;
- opcode = (protocol == ETH_P_IPV6) ? TX_TCP_LSO6 : TX_TCP_LSO;
+ first_desc->hdr_length = hdr_len;
+ opcode = (protocol == ETH_P_IPV6) ? QLCNIC_TX_TCP_LSO6 :
+ QLCNIC_TX_TCP_LSO;
/* For LSO, we need to copy the MAC/IP/TCP headers into
* the descriptor ring */
copied = 0;
offset = 2;
- if (flags & FLAGS_VLAN_OOB) {
- first_desc->total_hdr_length += VLAN_HLEN;
+ if (flags & QLCNIC_FLAGS_VLAN_OOB) {
+ first_desc->hdr_length += VLAN_HLEN;
first_desc->tcp_hdr_offset = VLAN_HLEN;
first_desc->ip_hdr_offset = VLAN_HLEN;
/* Only in case of TSO on vlan device */
- flags |= FLAGS_VLAN_TAGGED;
+ flags |= QLCNIC_FLAGS_VLAN_TAGGED;
/* Create a TSO vlan header template for firmware */
hwdesc = &tx_ring->desc_head[producer];
@@ -464,16 +563,16 @@ set_flags:
l4proto = ip_hdr(skb)->protocol;
if (l4proto == IPPROTO_TCP)
- opcode = TX_TCP_PKT;
+ opcode = QLCNIC_TX_TCP_PKT;
else if (l4proto == IPPROTO_UDP)
- opcode = TX_UDP_PKT;
+ opcode = QLCNIC_TX_UDP_PKT;
} else if (protocol == ETH_P_IPV6) {
l4proto = ipv6_hdr(skb)->nexthdr;
if (l4proto == IPPROTO_TCP)
- opcode = TX_TCPV6_PKT;
+ opcode = QLCNIC_TX_TCPV6_PKT;
else if (l4proto == IPPROTO_UDP)
- opcode = TX_UDPV6_PKT;
+ opcode = QLCNIC_TX_UDPV6_PKT;
}
}
first_desc->tcp_hdr_offset += skb_transport_offset(skb);
@@ -563,6 +662,8 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
struct ethhdr *phdr;
int i, k, frag_count, delta = 0;
u32 producer, num_txd;
+ u16 protocol;
+ bool l4_is_udp = false;
if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
netif_tx_stop_all_queues(netdev);
@@ -653,8 +754,23 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
tx_ring->producer = get_next_index(producer, num_txd);
smp_mb();
- if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb, tx_ring)))
- goto unwind_buff;
+ protocol = ntohs(skb->protocol);
+ if (protocol == ETH_P_IP)
+ l4_is_udp = ip_hdr(skb)->protocol == IPPROTO_UDP;
+ else if (protocol == ETH_P_IPV6)
+ l4_is_udp = ipv6_hdr(skb)->nexthdr == IPPROTO_UDP;
+
+ /* Check if it is a VXLAN packet */
+ if (!skb->encapsulation || !l4_is_udp ||
+ !qlcnic_encap_tx_offload(adapter)) {
+ if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb,
+ tx_ring)))
+ goto unwind_buff;
+ } else {
+ if (unlikely(qlcnic_tx_encap_pkt(adapter, first_desc,
+ skb, tx_ring)))
+ goto unwind_buff;
+ }
if (adapter->drv_mac_learn)
qlcnic_send_filter(adapter, first_desc, skb);
@@ -1587,6 +1703,13 @@ static inline int qlcnic_83xx_is_lb_pkt(u64 sts_data, int lro_pkt)
return (sts_data & QLC_83XX_NORMAL_LB_PKT) ? 1 : 0;
}
+#define QLCNIC_ENCAP_LENGTH_MASK 0x7f
+
+static inline u8 qlcnic_encap_length(u64 sts_data)
+{
+ return sts_data & QLCNIC_ENCAP_LENGTH_MASK;
+}
+
static struct qlcnic_rx_buffer *
qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
struct qlcnic_host_sds_ring *sds_ring,
@@ -1637,6 +1760,12 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
skb->protocol = eth_type_trans(skb, netdev);
+ if (qlcnic_encap_length(sts_data[1]) &&
+ skb->ip_summed == CHECKSUM_UNNECESSARY) {
+ skb->encapsulation = 1;
+ adapter->stats.encap_rx_csummed++;
+ }
+
if (vid != 0xffff)
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index ba78c7481fa3..309d05640883 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -21,6 +21,9 @@
#include <linux/aer.h>
#include <linux/log2.h>
#include <linux/pci.h>
+#ifdef CONFIG_QLCNIC_VXLAN
+#include <net/vxlan.h>
+#endif
MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver");
MODULE_LICENSE("GPL");
@@ -90,7 +93,6 @@ static void qlcnic_82xx_io_resume(struct pci_dev *);
static void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *);
static pci_ers_result_t qlcnic_82xx_io_error_detected(struct pci_dev *,
pci_channel_state_t);
-
static u32 qlcnic_vlan_tx_check(struct qlcnic_adapter *adapter)
{
struct qlcnic_hardware_context *ahw = adapter->ahw;
@@ -462,6 +464,37 @@ static int qlcnic_get_phys_port_id(struct net_device *netdev,
return 0;
}
+#ifdef CONFIG_QLCNIC_VXLAN
+static void qlcnic_add_vxlan_port(struct net_device *netdev,
+ sa_family_t sa_family, __be16 port)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ /* Adapter supports only one VXLAN port. Use very first port
+ * for enabling offload
+ */
+ if (!qlcnic_encap_rx_offload(adapter) || ahw->vxlan_port)
+ return;
+
+ ahw->vxlan_port = ntohs(port);
+ adapter->flags |= QLCNIC_ADD_VXLAN_PORT;
+}
+
+static void qlcnic_del_vxlan_port(struct net_device *netdev,
+ sa_family_t sa_family, __be16 port)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ if (!qlcnic_encap_rx_offload(adapter) || !ahw->vxlan_port ||
+ (ahw->vxlan_port != ntohs(port)))
+ return;
+
+ adapter->flags |= QLCNIC_DEL_VXLAN_PORT;
+}
+#endif
+
static const struct net_device_ops qlcnic_netdev_ops = {
.ndo_open = qlcnic_open,
.ndo_stop = qlcnic_close,
@@ -480,6 +513,10 @@ static const struct net_device_ops qlcnic_netdev_ops = {
.ndo_fdb_del = qlcnic_fdb_del,
.ndo_fdb_dump = qlcnic_fdb_dump,
.ndo_get_phys_port_id = qlcnic_get_phys_port_id,
+#ifdef CONFIG_QLCNIC_VXLAN
+ .ndo_add_vxlan_port = qlcnic_add_vxlan_port,
+ .ndo_del_vxlan_port = qlcnic_del_vxlan_port,
+#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = qlcnic_poll_controller,
#endif
@@ -561,6 +598,12 @@ static struct qlcnic_hardware_ops qlcnic_hw_ops = {
.disable_sds_intr = qlcnic_82xx_disable_sds_intr,
.enable_tx_intr = qlcnic_82xx_enable_tx_intr,
.disable_tx_intr = qlcnic_82xx_disable_tx_intr,
+ .get_saved_state = qlcnic_82xx_get_saved_state,
+ .set_saved_state = qlcnic_82xx_set_saved_state,
+ .cache_tmpl_hdr_values = qlcnic_82xx_cache_tmpl_hdr_values,
+ .get_cap_size = qlcnic_82xx_get_cap_size,
+ .set_sys_info = qlcnic_82xx_set_sys_info,
+ .store_cap_mask = qlcnic_82xx_store_cap_mask,
};
static int qlcnic_check_multi_tx_capability(struct qlcnic_adapter *adapter)
@@ -684,7 +727,7 @@ restore:
int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
{
struct pci_dev *pdev = adapter->pdev;
- int err = -1, vector;
+ int err, vector;
if (!adapter->msix_entries) {
adapter->msix_entries = kcalloc(num_msix,
@@ -701,13 +744,17 @@ enable_msix:
for (vector = 0; vector < num_msix; vector++)
adapter->msix_entries[vector].entry = vector;
- err = pci_enable_msix(pdev, adapter->msix_entries, num_msix);
- if (err == 0) {
+ err = pci_enable_msix_range(pdev,
+ adapter->msix_entries, 1, num_msix);
+
+ if (err == num_msix) {
adapter->flags |= QLCNIC_MSIX_ENABLED;
adapter->ahw->num_msix = num_msix;
dev_info(&pdev->dev, "using msi-x interrupts\n");
- return err;
+ return 0;
} else if (err > 0) {
+ pci_disable_msix(pdev);
+
dev_info(&pdev->dev,
"Unable to allocate %d MSI-X vectors, Available vectors %d\n",
num_msix, err);
@@ -715,12 +762,12 @@ enable_msix:
if (qlcnic_82xx_check(adapter)) {
num_msix = rounddown_pow_of_two(err);
if (err < QLCNIC_82XX_MINIMUM_VECTOR)
- return -EIO;
+ return -ENOSPC;
} else {
num_msix = rounddown_pow_of_two(err - 1);
num_msix += 1;
if (err < QLCNIC_83XX_MINIMUM_VECTOR)
- return -EIO;
+ return -ENOSPC;
}
if (qlcnic_82xx_check(adapter) &&
@@ -747,7 +794,7 @@ enable_msix:
}
}
- return err;
+ return -EIO;
}
static int qlcnic_82xx_calculate_msix_vector(struct qlcnic_adapter *adapter)
@@ -816,9 +863,10 @@ static int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter)
if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) {
qlcnic_disable_multi_tx(adapter);
+ adapter->drv_sds_rings = QLCNIC_SINGLE_RING;
err = qlcnic_enable_msi_legacy(adapter);
- if (!err)
+ if (err)
return err;
}
}
@@ -1933,6 +1981,11 @@ qlcnic_attach(struct qlcnic_adapter *adapter)
qlcnic_create_sysfs_entries(adapter);
+#ifdef CONFIG_QLCNIC_VXLAN
+ if (qlcnic_encap_rx_offload(adapter))
+ vxlan_get_rx_port(netdev);
+#endif
+
adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC;
return 0;
@@ -2195,6 +2248,19 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,
if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
netdev->features |= NETIF_F_LRO;
+ if (qlcnic_encap_tx_offload(adapter)) {
+ netdev->features |= NETIF_F_GSO_UDP_TUNNEL;
+
+ /* encapsulation Tx offload supported by Adapter */
+ netdev->hw_enc_features = NETIF_F_IP_CSUM |
+ NETIF_F_GSO_UDP_TUNNEL |
+ NETIF_F_TSO |
+ NETIF_F_TSO6;
+ }
+
+ if (qlcnic_encap_rx_offload(adapter))
+ netdev->hw_enc_features |= NETIF_F_RXCSUM;
+
netdev->hw_features = netdev->features;
netdev->priv_flags |= IFF_UNICAST_FLT;
netdev->irq = adapter->msix_entries[0].vector;
@@ -2441,8 +2507,8 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err) {
switch (err) {
case -ENOTRECOVERABLE:
- dev_err(&pdev->dev, "Adapter initialization failed due to a faulty hardware. Please reboot\n");
- dev_err(&pdev->dev, "If reboot doesn't help, please replace the adapter with new one and return the faulty adapter for repair\n");
+ dev_err(&pdev->dev, "Adapter initialization failed due to a faulty hardware\n");
+ dev_err(&pdev->dev, "Please replace the adapter with new one and return the faulty adapter for repair\n");
goto err_out_free_hw;
case -ENOMEM:
dev_err(&pdev->dev, "Adapter initialization failed. Please reboot\n");
@@ -3863,7 +3929,7 @@ int qlcnic_validate_rings(struct qlcnic_adapter *adapter, __u32 ring_cnt,
strcpy(buf, "Tx");
}
- if (!qlcnic_use_msi_x && !qlcnic_use_msi) {
+ if (!QLCNIC_IS_MSI_FAMILY(adapter)) {
netdev_err(netdev, "No RSS/TSS support in INT-x mode\n");
return -EINVAL;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
index 7763962e2ec4..37b979b1266b 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
@@ -211,6 +211,107 @@ enum qlcnic_minidump_opcode {
QLCNIC_DUMP_RDEND = 255
};
+inline u32 qlcnic_82xx_get_saved_state(void *t_hdr, u32 index)
+{
+ struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
+
+ return hdr->saved_state[index];
+}
+
+inline void qlcnic_82xx_set_saved_state(void *t_hdr, u32 index,
+ u32 value)
+{
+ struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
+
+ hdr->saved_state[index] = value;
+}
+
+void qlcnic_82xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *fw_dump)
+{
+ struct qlcnic_82xx_dump_template_hdr *hdr;
+
+ hdr = fw_dump->tmpl_hdr;
+ fw_dump->tmpl_hdr_size = hdr->size;
+ fw_dump->version = hdr->version;
+ fw_dump->num_entries = hdr->num_entries;
+ fw_dump->offset = hdr->offset;
+
+ hdr->drv_cap_mask = hdr->cap_mask;
+ fw_dump->cap_mask = hdr->cap_mask;
+}
+
+inline u32 qlcnic_82xx_get_cap_size(void *t_hdr, int index)
+{
+ struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
+
+ return hdr->cap_sizes[index];
+}
+
+void qlcnic_82xx_set_sys_info(void *t_hdr, int idx, u32 value)
+{
+ struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
+
+ hdr->sys_info[idx] = value;
+}
+
+void qlcnic_82xx_store_cap_mask(void *tmpl_hdr, u32 mask)
+{
+ struct qlcnic_82xx_dump_template_hdr *hdr = tmpl_hdr;
+
+ hdr->drv_cap_mask = mask;
+}
+
+inline u32 qlcnic_83xx_get_saved_state(void *t_hdr, u32 index)
+{
+ struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
+
+ return hdr->saved_state[index];
+}
+
+inline void qlcnic_83xx_set_saved_state(void *t_hdr, u32 index,
+ u32 value)
+{
+ struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
+
+ hdr->saved_state[index] = value;
+}
+
+void qlcnic_83xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *fw_dump)
+{
+ struct qlcnic_83xx_dump_template_hdr *hdr;
+
+ hdr = fw_dump->tmpl_hdr;
+ fw_dump->tmpl_hdr_size = hdr->size;
+ fw_dump->version = hdr->version;
+ fw_dump->num_entries = hdr->num_entries;
+ fw_dump->offset = hdr->offset;
+
+ hdr->drv_cap_mask = hdr->cap_mask;
+ fw_dump->cap_mask = hdr->cap_mask;
+}
+
+inline u32 qlcnic_83xx_get_cap_size(void *t_hdr, int index)
+{
+ struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
+
+ return hdr->cap_sizes[index];
+}
+
+void qlcnic_83xx_set_sys_info(void *t_hdr, int idx, u32 value)
+{
+ struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
+
+ hdr->sys_info[idx] = value;
+}
+
+void qlcnic_83xx_store_cap_mask(void *tmpl_hdr, u32 mask)
+{
+ struct qlcnic_83xx_dump_template_hdr *hdr;
+
+ hdr = tmpl_hdr;
+ hdr->drv_cap_mask = mask;
+}
+
struct qlcnic_dump_operations {
enum qlcnic_minidump_opcode opcode;
u32 (*handler)(struct qlcnic_adapter *, struct qlcnic_dump_entry *,
@@ -238,11 +339,11 @@ static u32 qlcnic_dump_crb(struct qlcnic_adapter *adapter,
static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
struct qlcnic_dump_entry *entry, __le32 *buffer)
{
+ void *hdr = adapter->ahw->fw_dump.tmpl_hdr;
+ struct __ctrl *ctr = &entry->region.ctrl;
int i, k, timeout = 0;
- u32 addr, data;
+ u32 addr, data, temp;
u8 no_ops;
- struct __ctrl *ctr = &entry->region.ctrl;
- struct qlcnic_dump_template_hdr *t_hdr = adapter->ahw->fw_dump.tmpl_hdr;
addr = ctr->addr;
no_ops = ctr->no_ops;
@@ -285,29 +386,42 @@ static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
}
break;
case QLCNIC_DUMP_RD_SAVE:
- if (ctr->index_a)
- addr = t_hdr->saved_state[ctr->index_a];
+ temp = ctr->index_a;
+ if (temp)
+ addr = qlcnic_get_saved_state(adapter,
+ hdr,
+ temp);
data = qlcnic_ind_rd(adapter, addr);
- t_hdr->saved_state[ctr->index_v] = data;
+ qlcnic_set_saved_state(adapter, hdr,
+ ctr->index_v, data);
break;
case QLCNIC_DUMP_WRT_SAVED:
- if (ctr->index_v)
- data = t_hdr->saved_state[ctr->index_v];
+ temp = ctr->index_v;
+ if (temp)
+ data = qlcnic_get_saved_state(adapter,
+ hdr,
+ temp);
else
data = ctr->val1;
- if (ctr->index_a)
- addr = t_hdr->saved_state[ctr->index_a];
+
+ temp = ctr->index_a;
+ if (temp)
+ addr = qlcnic_get_saved_state(adapter,
+ hdr,
+ temp);
qlcnic_ind_wr(adapter, addr, data);
break;
case QLCNIC_DUMP_MOD_SAVE_ST:
- data = t_hdr->saved_state[ctr->index_v];
+ data = qlcnic_get_saved_state(adapter, hdr,
+ ctr->index_v);
data <<= ctr->shl_val;
data >>= ctr->shr_val;
if (ctr->val2)
data &= ctr->val2;
data |= ctr->val3;
data += ctr->val1;
- t_hdr->saved_state[ctr->index_v] = data;
+ qlcnic_set_saved_state(adapter, hdr,
+ ctr->index_v, data);
break;
default:
dev_info(&adapter->pdev->dev,
@@ -544,7 +658,7 @@ out:
static int qlcnic_start_pex_dma(struct qlcnic_adapter *adapter,
struct __mem *mem)
{
- struct qlcnic_dump_template_hdr *tmpl_hdr;
+ struct qlcnic_83xx_dump_template_hdr *tmpl_hdr;
struct device *dev = &adapter->pdev->dev;
u32 dma_no, dma_base_addr, temp_addr;
int i, ret, dma_sts;
@@ -596,7 +710,7 @@ static u32 qlcnic_read_memory_pexdma(struct qlcnic_adapter *adapter,
struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
u32 temp, dma_base_addr, size = 0, read_size = 0;
struct qlcnic_pex_dma_descriptor *dma_descr;
- struct qlcnic_dump_template_hdr *tmpl_hdr;
+ struct qlcnic_83xx_dump_template_hdr *tmpl_hdr;
struct device *dev = &adapter->pdev->dev;
dma_addr_t dma_phys_addr;
void *dma_buffer;
@@ -938,8 +1052,8 @@ static int
qlcnic_fw_flash_get_minidump_temp_size(struct qlcnic_adapter *adapter,
struct qlcnic_cmd_args *cmd)
{
- struct qlcnic_dump_template_hdr tmp_hdr;
- u32 size = sizeof(struct qlcnic_dump_template_hdr) / sizeof(u32);
+ struct qlcnic_83xx_dump_template_hdr tmp_hdr;
+ u32 size = sizeof(tmp_hdr) / sizeof(u32);
int ret = 0;
if (qlcnic_82xx_check(adapter))
@@ -1027,17 +1141,19 @@ free_mem:
return err;
}
+#define QLCNIC_TEMPLATE_VERSION (0x20001)
+
int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
{
- int err;
- u32 temp_size = 0;
- u32 version, csum, *tmp_buf;
struct qlcnic_hardware_context *ahw;
- struct qlcnic_dump_template_hdr *tmpl_hdr;
+ struct qlcnic_fw_dump *fw_dump;
+ u32 version, csum, *tmp_buf;
u8 use_flash_temp = 0;
+ u32 temp_size = 0;
+ int err;
ahw = adapter->ahw;
-
+ fw_dump = &ahw->fw_dump;
err = qlcnic_fw_get_minidump_temp_size(adapter, &version, &temp_size,
&use_flash_temp);
if (err) {
@@ -1046,11 +1162,11 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
return -EIO;
}
- ahw->fw_dump.tmpl_hdr = vzalloc(temp_size);
- if (!ahw->fw_dump.tmpl_hdr)
+ fw_dump->tmpl_hdr = vzalloc(temp_size);
+ if (!fw_dump->tmpl_hdr)
return -ENOMEM;
- tmp_buf = (u32 *)ahw->fw_dump.tmpl_hdr;
+ tmp_buf = (u32 *)fw_dump->tmpl_hdr;
if (use_flash_temp)
goto flash_temp;
@@ -1065,8 +1181,8 @@ flash_temp:
dev_err(&adapter->pdev->dev,
"Failed to get minidump template header %d\n",
err);
- vfree(ahw->fw_dump.tmpl_hdr);
- ahw->fw_dump.tmpl_hdr = NULL;
+ vfree(fw_dump->tmpl_hdr);
+ fw_dump->tmpl_hdr = NULL;
return -EIO;
}
}
@@ -1076,21 +1192,22 @@ flash_temp:
if (csum) {
dev_err(&adapter->pdev->dev,
"Template header checksum validation failed\n");
- vfree(ahw->fw_dump.tmpl_hdr);
- ahw->fw_dump.tmpl_hdr = NULL;
+ vfree(fw_dump->tmpl_hdr);
+ fw_dump->tmpl_hdr = NULL;
return -EIO;
}
- tmpl_hdr = ahw->fw_dump.tmpl_hdr;
- tmpl_hdr->drv_cap_mask = tmpl_hdr->cap_mask;
+ qlcnic_cache_tmpl_hdr_values(adapter, fw_dump);
+
dev_info(&adapter->pdev->dev,
"Default minidump capture mask 0x%x\n",
- tmpl_hdr->cap_mask);
+ fw_dump->cap_mask);
- if ((tmpl_hdr->version & 0xfffff) >= 0x20001)
- ahw->fw_dump.use_pex_dma = true;
+ if (qlcnic_83xx_check(adapter) &&
+ (fw_dump->version & 0xfffff) >= QLCNIC_TEMPLATE_VERSION)
+ fw_dump->use_pex_dma = true;
else
- ahw->fw_dump.use_pex_dma = false;
+ fw_dump->use_pex_dma = false;
qlcnic_enable_fw_dump_state(adapter);
@@ -1099,21 +1216,22 @@ flash_temp:
int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
{
- __le32 *buffer;
- u32 ocm_window;
- char mesg[64];
- char *msg[] = {mesg, NULL};
- int i, k, ops_cnt, ops_index, dump_size = 0;
- u32 entry_offset, dump, no_entries, buf_offset = 0;
- struct qlcnic_dump_entry *entry;
struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
- struct qlcnic_dump_template_hdr *tmpl_hdr = fw_dump->tmpl_hdr;
static const struct qlcnic_dump_operations *fw_dump_ops;
+ struct qlcnic_83xx_dump_template_hdr *hdr_83xx;
+ u32 entry_offset, dump, no_entries, buf_offset = 0;
+ int i, k, ops_cnt, ops_index, dump_size = 0;
struct device *dev = &adapter->pdev->dev;
struct qlcnic_hardware_context *ahw;
- void *temp_buffer;
+ struct qlcnic_dump_entry *entry;
+ void *temp_buffer, *tmpl_hdr;
+ u32 ocm_window;
+ __le32 *buffer;
+ char mesg[64];
+ char *msg[] = {mesg, NULL};
ahw = adapter->ahw;
+ tmpl_hdr = fw_dump->tmpl_hdr;
/* Return if we don't have firmware dump template header */
if (!tmpl_hdr)
@@ -1133,8 +1251,9 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
netif_info(adapter->ahw, drv, adapter->netdev, "Take FW dump\n");
/* Calculate the size for dump data area only */
for (i = 2, k = 1; (i & QLCNIC_DUMP_MASK_MAX); i <<= 1, k++)
- if (i & tmpl_hdr->drv_cap_mask)
- dump_size += tmpl_hdr->cap_sizes[k];
+ if (i & fw_dump->cap_mask)
+ dump_size += qlcnic_get_cap_size(adapter, tmpl_hdr, k);
+
if (!dump_size)
return -EIO;
@@ -1144,10 +1263,10 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
buffer = fw_dump->data;
fw_dump->size = dump_size;
- no_entries = tmpl_hdr->num_entries;
- entry_offset = tmpl_hdr->offset;
- tmpl_hdr->sys_info[0] = QLCNIC_DRIVER_VERSION;
- tmpl_hdr->sys_info[1] = adapter->fw_version;
+ no_entries = fw_dump->num_entries;
+ entry_offset = fw_dump->offset;
+ qlcnic_set_sys_info(adapter, tmpl_hdr, 0, QLCNIC_DRIVER_VERSION);
+ qlcnic_set_sys_info(adapter, tmpl_hdr, 1, adapter->fw_version);
if (fw_dump->use_pex_dma) {
temp_buffer = dma_alloc_coherent(dev, QLC_PEX_DMA_READ_SIZE,
@@ -1163,16 +1282,17 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
ops_cnt = ARRAY_SIZE(qlcnic_fw_dump_ops);
fw_dump_ops = qlcnic_fw_dump_ops;
} else {
+ hdr_83xx = tmpl_hdr;
ops_cnt = ARRAY_SIZE(qlcnic_83xx_fw_dump_ops);
fw_dump_ops = qlcnic_83xx_fw_dump_ops;
- ocm_window = tmpl_hdr->ocm_wnd_reg[adapter->ahw->pci_func];
- tmpl_hdr->saved_state[QLC_83XX_OCM_INDEX] = ocm_window;
- tmpl_hdr->saved_state[QLC_83XX_PCI_INDEX] = ahw->pci_func;
+ ocm_window = hdr_83xx->ocm_wnd_reg[ahw->pci_func];
+ hdr_83xx->saved_state[QLC_83XX_OCM_INDEX] = ocm_window;
+ hdr_83xx->saved_state[QLC_83XX_PCI_INDEX] = ahw->pci_func;
}
for (i = 0; i < no_entries; i++) {
- entry = (void *)tmpl_hdr + entry_offset;
- if (!(entry->hdr.mask & tmpl_hdr->drv_cap_mask)) {
+ entry = tmpl_hdr + entry_offset;
+ if (!(entry->hdr.mask & fw_dump->cap_mask)) {
entry->hdr.flags |= QLCNIC_DUMP_SKIP;
entry_offset += entry->hdr.offset;
continue;
@@ -1209,8 +1329,9 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
fw_dump->clr = 1;
snprintf(mesg, sizeof(mesg), "FW_DUMP=%s", adapter->netdev->name);
- dev_info(dev, "%s: Dump data %d bytes captured, template header size %d bytes\n",
- adapter->netdev->name, fw_dump->size, tmpl_hdr->size);
+ netdev_info(adapter->netdev,
+ "Dump data %d bytes captured, template header size %d bytes\n",
+ fw_dump->size, fw_dump->tmpl_hdr_size);
/* Send a udev event to notify availability of FW dump */
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, msg);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
index 09acf15c3a56..14f748cbf0de 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
@@ -13,10 +13,9 @@
#define QLC_VF_MIN_TX_RATE 100
#define QLC_VF_MAX_TX_RATE 9999
#define QLC_MAC_OPCODE_MASK 0x7
-#define QLC_MAC_STAR_ADD 6
-#define QLC_MAC_STAR_DEL 7
#define QLC_VF_FLOOD_BIT BIT_16
#define QLC_FLOOD_MODE 0x5
+#define QLC_SRIOV_ALLOW_VLAN0 BIT_19
static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8);
@@ -337,8 +336,11 @@ static int qlcnic_sriov_pf_cfg_vlan_filtering(struct qlcnic_adapter *adapter,
return err;
cmd.req.arg[1] = 0x4;
- if (enable)
+ if (enable) {
cmd.req.arg[1] |= BIT_16;
+ if (qlcnic_84xx_check(adapter))
+ cmd.req.arg[1] |= QLC_SRIOV_ALLOW_VLAN0;
+ }
err = qlcnic_issue_cmd(adapter, &cmd);
if (err)
@@ -1206,13 +1208,6 @@ static int qlcnic_sriov_validate_cfg_macvlan(struct qlcnic_adapter *adapter,
struct qlcnic_vport *vp = vf->vp;
u8 op, new_op;
- if (((cmd->req.arg[1] & QLC_MAC_OPCODE_MASK) == QLC_MAC_STAR_ADD) ||
- ((cmd->req.arg[1] & QLC_MAC_OPCODE_MASK) == QLC_MAC_STAR_DEL)) {
- netdev_err(adapter->netdev, "MAC + any VLAN filter not allowed from VF %d\n",
- vf->pci_func);
- return -EINVAL;
- }
-
if (!(cmd->req.arg[1] & BIT_8))
return -EINVAL;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
index 3d64113a35af..448d156c3d08 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
@@ -350,33 +350,15 @@ static ssize_t qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
return size;
}
-static u32 qlcnic_get_pci_func_count(struct qlcnic_adapter *adapter)
-{
- struct qlcnic_hardware_context *ahw = adapter->ahw;
- u32 count = 0;
-
- if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
- return ahw->total_nic_func;
-
- if (ahw->total_pci_func <= QLC_DEFAULT_VNIC_COUNT)
- count = QLC_DEFAULT_VNIC_COUNT;
- else
- count = ahw->max_vnic_func;
-
- return count;
-}
-
int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func)
{
- u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
int i;
- for (i = 0; i < pci_func_count; i++) {
+ for (i = 0; i < adapter->ahw->max_vnic_func; i++) {
if (adapter->npars[i].pci_func == pci_func)
return i;
}
-
- return -1;
+ return -EINVAL;
}
static int validate_pm_config(struct qlcnic_adapter *adapter,
@@ -464,23 +446,21 @@ static ssize_t qlcnic_sysfs_read_pm_config(struct file *filp,
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
struct qlcnic_pm_func_cfg *pm_cfg;
- int i, pm_cfg_size;
u8 pci_func;
+ u32 count;
+ int i;
- pm_cfg_size = pci_func_count * sizeof(*pm_cfg);
- if (size != pm_cfg_size)
- return QL_STATUS_INVALID_PARAM;
-
- memset(buf, 0, pm_cfg_size);
+ memset(buf, 0, size);
pm_cfg = (struct qlcnic_pm_func_cfg *)buf;
-
- for (i = 0; i < pci_func_count; i++) {
+ count = size / sizeof(struct qlcnic_pm_func_cfg);
+ for (i = 0; i < adapter->ahw->total_nic_func; i++) {
pci_func = adapter->npars[i].pci_func;
- if (!adapter->npars[i].active)
+ if (pci_func >= count) {
+ dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n",
+ __func__, adapter->ahw->total_nic_func, count);
continue;
-
+ }
if (!adapter->npars[i].eswitch_status)
continue;
@@ -494,7 +474,6 @@ static ssize_t qlcnic_sysfs_read_pm_config(struct file *filp,
static int validate_esw_config(struct qlcnic_adapter *adapter,
struct qlcnic_esw_func_cfg *esw_cfg, int count)
{
- u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
struct qlcnic_hardware_context *ahw = adapter->ahw;
int i, ret;
u32 op_mode;
@@ -507,7 +486,7 @@ static int validate_esw_config(struct qlcnic_adapter *adapter,
for (i = 0; i < count; i++) {
pci_func = esw_cfg[i].pci_func;
- if (pci_func >= pci_func_count)
+ if (pci_func >= ahw->max_vnic_func)
return QL_STATUS_INVALID_PARAM;
if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
@@ -642,23 +621,21 @@ static ssize_t qlcnic_sysfs_read_esw_config(struct file *file,
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
struct qlcnic_esw_func_cfg *esw_cfg;
- size_t esw_cfg_size;
- u8 i, pci_func;
-
- esw_cfg_size = pci_func_count * sizeof(*esw_cfg);
- if (size != esw_cfg_size)
- return QL_STATUS_INVALID_PARAM;
+ u8 pci_func;
+ u32 count;
+ int i;
- memset(buf, 0, esw_cfg_size);
+ memset(buf, 0, size);
esw_cfg = (struct qlcnic_esw_func_cfg *)buf;
-
- for (i = 0; i < pci_func_count; i++) {
+ count = size / sizeof(struct qlcnic_esw_func_cfg);
+ for (i = 0; i < adapter->ahw->total_nic_func; i++) {
pci_func = adapter->npars[i].pci_func;
- if (!adapter->npars[i].active)
+ if (pci_func >= count) {
+ dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n",
+ __func__, adapter->ahw->total_nic_func, count);
continue;
-
+ }
if (!adapter->npars[i].eswitch_status)
continue;
@@ -741,23 +718,24 @@ static ssize_t qlcnic_sysfs_read_npar_config(struct file *file,
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
struct qlcnic_npar_func_cfg *np_cfg;
struct qlcnic_info nic_info;
- size_t np_cfg_size;
int i, ret;
-
- np_cfg_size = pci_func_count * sizeof(*np_cfg);
- if (size != np_cfg_size)
- return QL_STATUS_INVALID_PARAM;
+ u32 count;
memset(&nic_info, 0, sizeof(struct qlcnic_info));
- memset(buf, 0, np_cfg_size);
+ memset(buf, 0, size);
np_cfg = (struct qlcnic_npar_func_cfg *)buf;
- for (i = 0; i < pci_func_count; i++) {
+ count = size / sizeof(struct qlcnic_npar_func_cfg);
+ for (i = 0; i < adapter->ahw->total_nic_func; i++) {
if (qlcnic_is_valid_nic_func(adapter, i) < 0)
continue;
+ if (adapter->npars[i].pci_func >= count) {
+ dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n",
+ __func__, adapter->ahw->total_nic_func, count);
+ continue;
+ }
ret = qlcnic_get_nic_info(adapter, &nic_info, i);
if (ret)
return ret;
@@ -783,7 +761,6 @@ static ssize_t qlcnic_sysfs_get_port_stats(struct file *file,
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
struct qlcnic_esw_statistics port_stats;
int ret;
@@ -793,7 +770,7 @@ static ssize_t qlcnic_sysfs_get_port_stats(struct file *file,
if (size != sizeof(struct qlcnic_esw_statistics))
return QL_STATUS_INVALID_PARAM;
- if (offset >= pci_func_count)
+ if (offset >= adapter->ahw->max_vnic_func)
return QL_STATUS_INVALID_PARAM;
memset(&port_stats, 0, size);
@@ -884,13 +861,12 @@ static ssize_t qlcnic_sysfs_clear_port_stats(struct file *file,
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
int ret;
if (qlcnic_83xx_check(adapter))
return QLC_STATUS_UNSUPPORTED_CMD;
- if (offset >= pci_func_count)
+ if (offset >= adapter->ahw->max_vnic_func)
return QL_STATUS_INVALID_PARAM;
ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
@@ -914,17 +890,12 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file,
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
struct qlcnic_pci_func_cfg *pci_cfg;
struct qlcnic_pci_info *pci_info;
- size_t pci_cfg_sz;
int i, ret;
+ u32 count;
- pci_cfg_sz = pci_func_count * sizeof(*pci_cfg);
- if (size != pci_cfg_sz)
- return QL_STATUS_INVALID_PARAM;
-
- pci_info = kcalloc(pci_func_count, sizeof(*pci_info), GFP_KERNEL);
+ pci_info = kcalloc(size, sizeof(*pci_info), GFP_KERNEL);
if (!pci_info)
return -ENOMEM;
@@ -935,7 +906,8 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file,
}
pci_cfg = (struct qlcnic_pci_func_cfg *)buf;
- for (i = 0; i < pci_func_count; i++) {
+ count = size / sizeof(struct qlcnic_pci_func_cfg);
+ for (i = 0; i < count; i++) {
pci_cfg[i].pci_func = pci_info[i].id;
pci_cfg[i].func_type = pci_info[i].type;
pci_cfg[i].func_state = 0;
diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
index ce2cfddbed50..0a1d76acab81 100644
--- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
@@ -2556,11 +2556,10 @@ static int ql_tso(struct sk_buff *skb, struct ob_mac_tso_iocb_req *mac_iocb_ptr)
if (skb_is_gso(skb)) {
int err;
- if (skb_header_cloned(skb)) {
- err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
- if (err)
- return err;
- }
+
+ err = skb_cow_head(skb, 0);
+ if (err < 0)
+ return err;
mac_iocb_ptr->opcode = OPCODE_OB_MAC_TSO_IOCB;
mac_iocb_ptr->flags3 |= OB_MAC_TSO_IOCB_IC;
@@ -3331,24 +3330,16 @@ static void ql_enable_msix(struct ql_adapter *qdev)
for (i = 0; i < qdev->intr_count; i++)
qdev->msi_x_entry[i].entry = i;
- /* Loop to get our vectors. We start with
- * what we want and settle for what we get.
- */
- do {
- err = pci_enable_msix(qdev->pdev,
- qdev->msi_x_entry, qdev->intr_count);
- if (err > 0)
- qdev->intr_count = err;
- } while (err > 0);
-
+ err = pci_enable_msix_range(qdev->pdev, qdev->msi_x_entry,
+ 1, qdev->intr_count);
if (err < 0) {
kfree(qdev->msi_x_entry);
qdev->msi_x_entry = NULL;
netif_warn(qdev, ifup, qdev->ndev,
"MSI-X Enable failed, trying MSI.\n");
- qdev->intr_count = 1;
qlge_irq_type = MSI_IRQ;
- } else if (err == 0) {
+ } else {
+ qdev->intr_count = err;
set_bit(QL_MSIX_ENABLED, &qdev->flags);
netif_info(qdev, ifup, qdev->ndev,
"MSI-X Enabled, got %d vectors.\n",
@@ -4765,7 +4756,9 @@ static int qlge_probe(struct pci_dev *pdev,
ndev->features = ndev->hw_features;
ndev->vlan_features = ndev->hw_features;
/* vlan gets same features (except vlan filter) */
- ndev->vlan_features &= ~NETIF_F_HW_VLAN_CTAG_FILTER;
+ ndev->vlan_features &= ~(NETIF_F_HW_VLAN_CTAG_FILTER |
+ NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX);
if (test_bit(QL_DMA64, &qdev->flags))
ndev->features |= NETIF_F_HIGHDMA;
diff --git a/drivers/net/ethernet/rdc/r6040.c b/drivers/net/ethernet/rdc/r6040.c
index 819b74cefd64..cd045ecb9816 100644
--- a/drivers/net/ethernet/rdc/r6040.c
+++ b/drivers/net/ethernet/rdc/r6040.c
@@ -270,11 +270,6 @@ static int r6040_mdiobus_write(struct mii_bus *bus, int phy_addr,
return r6040_phy_write(ioaddr, phy_addr, reg, value);
}
-static int r6040_mdiobus_reset(struct mii_bus *bus)
-{
- return 0;
-}
-
static void r6040_free_txbufs(struct net_device *dev)
{
struct r6040_private *lp = netdev_priv(dev);
@@ -1191,7 +1186,6 @@ static int r6040_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
lp->mii_bus->priv = dev;
lp->mii_bus->read = r6040_mdiobus_read;
lp->mii_bus->write = r6040_mdiobus_write;
- lp->mii_bus->reset = r6040_mdiobus_reset;
lp->mii_bus->name = "r6040_eth_mii";
snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
dev_name(&pdev->dev), card_idx);
diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c
index 737c1a881f78..2bc728e65e24 100644
--- a/drivers/net/ethernet/realtek/8139cp.c
+++ b/drivers/net/ethernet/realtek/8139cp.c
@@ -476,7 +476,7 @@ rx_status_loop:
rx = 0;
cpw16(IntrStatus, cp_rx_intr_mask);
- while (1) {
+ while (rx < budget) {
u32 status, len;
dma_addr_t mapping, new_mapping;
struct sk_buff *skb, *new_skb;
@@ -554,9 +554,6 @@ rx_next:
else
desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz);
rx_tail = NEXT_RX(rx_tail);
-
- if (rx >= budget)
- break;
}
cp->rx_tail = rx_tail;
@@ -899,7 +896,7 @@ out_unlock:
return NETDEV_TX_OK;
out_dma_error:
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
cp->dev->stats.tx_dropped++;
goto out_unlock;
}
diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c
index da5972eefdd2..2e5df148af4c 100644
--- a/drivers/net/ethernet/realtek/8139too.c
+++ b/drivers/net/ethernet/realtek/8139too.c
@@ -1717,9 +1717,9 @@ static netdev_tx_t rtl8139_start_xmit (struct sk_buff *skb,
if (len < ETH_ZLEN)
memset(tp->tx_buf[entry], 0, ETH_ZLEN);
skb_copy_and_csum_dev(skb, tp->tx_buf[entry]);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
} else {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
dev->stats.tx_dropped++;
return NETDEV_TX_OK;
}
@@ -2522,16 +2522,16 @@ rtl8139_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
netdev_stats_to_stats64(stats, &dev->stats);
do {
- start = u64_stats_fetch_begin_bh(&tp->rx_stats.syncp);
+ start = u64_stats_fetch_begin_irq(&tp->rx_stats.syncp);
stats->rx_packets = tp->rx_stats.packets;
stats->rx_bytes = tp->rx_stats.bytes;
- } while (u64_stats_fetch_retry_bh(&tp->rx_stats.syncp, start));
+ } while (u64_stats_fetch_retry_irq(&tp->rx_stats.syncp, start));
do {
- start = u64_stats_fetch_begin_bh(&tp->tx_stats.syncp);
+ start = u64_stats_fetch_begin_irq(&tp->tx_stats.syncp);
stats->tx_packets = tp->tx_stats.packets;
stats->tx_bytes = tp->tx_stats.bytes;
- } while (u64_stats_fetch_retry_bh(&tp->tx_stats.syncp, start));
+ } while (u64_stats_fetch_retry_irq(&tp->tx_stats.syncp, start));
return stats;
}
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 91a67ae8f17b..aa1c079f231d 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -209,7 +209,7 @@ static const struct {
[RTL_GIGA_MAC_VER_16] =
_R("RTL8101e", RTL_TD_0, NULL, JUMBO_1K, true),
[RTL_GIGA_MAC_VER_17] =
- _R("RTL8168b/8111b", RTL_TD_1, NULL, JUMBO_4K, false),
+ _R("RTL8168b/8111b", RTL_TD_0, NULL, JUMBO_4K, false),
[RTL_GIGA_MAC_VER_18] =
_R("RTL8168cp/8111cp", RTL_TD_1, NULL, JUMBO_6K, false),
[RTL_GIGA_MAC_VER_19] =
@@ -5834,7 +5834,7 @@ static void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start,
tp->TxDescArray + entry);
if (skb) {
tp->dev->stats.tx_dropped++;
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
tx_skb->skb = NULL;
}
}
@@ -6059,7 +6059,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
err_dma_1:
rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd);
err_dma_0:
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
err_update_stats:
dev->stats.tx_dropped++;
return NETDEV_TX_OK;
@@ -6142,7 +6142,7 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
tp->tx_stats.packets++;
tp->tx_stats.bytes += tx_skb->skb->len;
u64_stats_update_end(&tp->tx_stats.syncp);
- dev_kfree_skb(tx_skb->skb);
+ dev_kfree_skb_any(tx_skb->skb);
tx_skb->skb = NULL;
}
dirty_tx++;
@@ -6590,17 +6590,17 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
rtl8169_rx_missed(dev, ioaddr);
do {
- start = u64_stats_fetch_begin_bh(&tp->rx_stats.syncp);
+ start = u64_stats_fetch_begin_irq(&tp->rx_stats.syncp);
stats->rx_packets = tp->rx_stats.packets;
stats->rx_bytes = tp->rx_stats.bytes;
- } while (u64_stats_fetch_retry_bh(&tp->rx_stats.syncp, start));
+ } while (u64_stats_fetch_retry_irq(&tp->rx_stats.syncp, start));
do {
- start = u64_stats_fetch_begin_bh(&tp->tx_stats.syncp);
+ start = u64_stats_fetch_begin_irq(&tp->tx_stats.syncp);
stats->tx_packets = tp->tx_stats.packets;
stats->tx_bytes = tp->tx_stats.bytes;
- } while (u64_stats_fetch_retry_bh(&tp->tx_stats.syncp, start));
+ } while (u64_stats_fetch_retry_irq(&tp->tx_stats.syncp, start));
stats->rx_dropped = dev->stats.rx_dropped;
stats->tx_dropped = dev->stats.tx_dropped;
@@ -7118,6 +7118,8 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
mutex_init(&tp->wk.mutex);
+ u64_stats_init(&tp->rx_stats.syncp);
+ u64_stats_init(&tp->tx_stats.syncp);
/* Get MAC address */
for (i = 0; i < ETH_ALEN; i++)
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index 040cb94e8219..6a9509ccd33b 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -1,8 +1,9 @@
/* SuperH Ethernet device driver
*
* Copyright (C) 2006-2012 Nobuhiro Iwamatsu
- * Copyright (C) 2008-2013 Renesas Solutions Corp.
- * Copyright (C) 2013 Cogent Embedded, Inc.
+ * Copyright (C) 2008-2014 Renesas Solutions Corp.
+ * Copyright (C) 2013-2014 Cogent Embedded, Inc.
+ * Copyright (C) 2014 Codethink Limited
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -27,6 +28,10 @@
#include <linux/platform_device.h>
#include <linux/mdio-bitbang.h>
#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_net.h>
#include <linux/phy.h>
#include <linux/cache.h>
#include <linux/io.h>
@@ -36,6 +41,7 @@
#include <linux/if_vlan.h>
#include <linux/clk.h>
#include <linux/sh_eth.h>
+#include <linux/of_mdio.h>
#include "sh_eth.h"
@@ -394,7 +400,8 @@ static void sh_eth_select_mii(struct net_device *ndev)
value = 0x0;
break;
default:
- pr_warn("PHY interface mode was not setup. Set to MII.\n");
+ netdev_warn(ndev,
+ "PHY interface mode was not setup. Set to MII.\n");
value = 0x1;
break;
}
@@ -848,7 +855,7 @@ static int sh_eth_check_reset(struct net_device *ndev)
cnt--;
}
if (cnt <= 0) {
- pr_err("Device reset failed\n");
+ netdev_err(ndev, "Device reset failed\n");
ret = -ETIMEDOUT;
}
return ret;
@@ -866,7 +873,7 @@ static int sh_eth_reset(struct net_device *ndev)
ret = sh_eth_check_reset(ndev);
if (ret)
- goto out;
+ return ret;
/* Table Init */
sh_eth_write(ndev, 0x0, TDLAR);
@@ -893,7 +900,6 @@ static int sh_eth_reset(struct net_device *ndev)
EDMR);
}
-out:
return ret;
}
@@ -1257,7 +1263,7 @@ static int sh_eth_dev_init(struct net_device *ndev, bool start)
/* Soft Reset */
ret = sh_eth_reset(ndev);
if (ret)
- goto out;
+ return ret;
if (mdp->cd->rmiimode)
sh_eth_write(ndev, 0x1, RMIIMODE);
@@ -1336,7 +1342,6 @@ static int sh_eth_dev_init(struct net_device *ndev, bool start)
netif_start_queue(ndev);
}
-out:
return ret;
}
@@ -1550,8 +1555,7 @@ ignore_link:
/* Unused write back interrupt */
if (intr_status & EESR_TABT) { /* Transmit Abort int */
ndev->stats.tx_aborted_errors++;
- if (netif_msg_tx_err(mdp))
- dev_err(&ndev->dev, "Transmit Abort\n");
+ netif_err(mdp, tx_err, ndev, "Transmit Abort\n");
}
}
@@ -1560,45 +1564,38 @@ ignore_link:
if (intr_status & EESR_RFRMER) {
/* Receive Frame Overflow int */
ndev->stats.rx_frame_errors++;
- if (netif_msg_rx_err(mdp))
- dev_err(&ndev->dev, "Receive Abort\n");
+ netif_err(mdp, rx_err, ndev, "Receive Abort\n");
}
}
if (intr_status & EESR_TDE) {
/* Transmit Descriptor Empty int */
ndev->stats.tx_fifo_errors++;
- if (netif_msg_tx_err(mdp))
- dev_err(&ndev->dev, "Transmit Descriptor Empty\n");
+ netif_err(mdp, tx_err, ndev, "Transmit Descriptor Empty\n");
}
if (intr_status & EESR_TFE) {
/* FIFO under flow */
ndev->stats.tx_fifo_errors++;
- if (netif_msg_tx_err(mdp))
- dev_err(&ndev->dev, "Transmit FIFO Under flow\n");
+ netif_err(mdp, tx_err, ndev, "Transmit FIFO Under flow\n");
}
if (intr_status & EESR_RDE) {
/* Receive Descriptor Empty int */
ndev->stats.rx_over_errors++;
-
- if (netif_msg_rx_err(mdp))
- dev_err(&ndev->dev, "Receive Descriptor Empty\n");
+ netif_err(mdp, rx_err, ndev, "Receive Descriptor Empty\n");
}
if (intr_status & EESR_RFE) {
/* Receive FIFO Overflow int */
ndev->stats.rx_fifo_errors++;
- if (netif_msg_rx_err(mdp))
- dev_err(&ndev->dev, "Receive FIFO Overflow\n");
+ netif_err(mdp, rx_err, ndev, "Receive FIFO Overflow\n");
}
if (!mdp->cd->no_ade && (intr_status & EESR_ADE)) {
/* Address Error */
ndev->stats.tx_fifo_errors++;
- if (netif_msg_tx_err(mdp))
- dev_err(&ndev->dev, "Address Error\n");
+ netif_err(mdp, tx_err, ndev, "Address Error\n");
}
mask = EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE;
@@ -1609,9 +1606,9 @@ ignore_link:
u32 edtrr = sh_eth_read(ndev, EDTRR);
/* dmesg */
- dev_err(&ndev->dev, "TX error. status=%8.8x cur_tx=%8.8x dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n",
- intr_status, mdp->cur_tx, mdp->dirty_tx,
- (u32)ndev->state, edtrr);
+ netdev_err(ndev, "TX error. status=%8.8x cur_tx=%8.8x dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n",
+ intr_status, mdp->cur_tx, mdp->dirty_tx,
+ (u32)ndev->state, edtrr);
/* dirty buffer free */
sh_eth_txfree(ndev);
@@ -1656,9 +1653,9 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
EESIPR);
__napi_schedule(&mdp->napi);
} else {
- dev_warn(&ndev->dev,
- "ignoring interrupt, status 0x%08lx, mask 0x%08lx.\n",
- intr_status, intr_enable);
+ netdev_warn(ndev,
+ "ignoring interrupt, status 0x%08lx, mask 0x%08lx.\n",
+ intr_status, intr_enable);
}
}
@@ -1757,27 +1754,42 @@ static void sh_eth_adjust_link(struct net_device *ndev)
/* PHY init function */
static int sh_eth_phy_init(struct net_device *ndev)
{
+ struct device_node *np = ndev->dev.parent->of_node;
struct sh_eth_private *mdp = netdev_priv(ndev);
- char phy_id[MII_BUS_ID_SIZE + 3];
struct phy_device *phydev = NULL;
- snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
- mdp->mii_bus->id, mdp->phy_id);
-
mdp->link = 0;
mdp->speed = 0;
mdp->duplex = -1;
/* Try connect to PHY */
- phydev = phy_connect(ndev, phy_id, sh_eth_adjust_link,
- mdp->phy_interface);
+ if (np) {
+ struct device_node *pn;
+
+ pn = of_parse_phandle(np, "phy-handle", 0);
+ phydev = of_phy_connect(ndev, pn,
+ sh_eth_adjust_link, 0,
+ mdp->phy_interface);
+
+ if (!phydev)
+ phydev = ERR_PTR(-ENOENT);
+ } else {
+ char phy_id[MII_BUS_ID_SIZE + 3];
+
+ snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
+ mdp->mii_bus->id, mdp->phy_id);
+
+ phydev = phy_connect(ndev, phy_id, sh_eth_adjust_link,
+ mdp->phy_interface);
+ }
+
if (IS_ERR(phydev)) {
- dev_err(&ndev->dev, "phy_connect failed\n");
+ netdev_err(ndev, "failed to connect PHY\n");
return PTR_ERR(phydev);
}
- dev_info(&ndev->dev, "attached PHY %d (IRQ %d) to driver %s\n",
- phydev->addr, phydev->irq, phydev->drv->name);
+ netdev_info(ndev, "attached PHY %d (IRQ %d) to driver %s\n",
+ phydev->addr, phydev->irq, phydev->drv->name);
mdp->phydev = phydev;
@@ -1958,12 +1970,12 @@ static int sh_eth_set_ringparam(struct net_device *ndev,
ret = sh_eth_ring_init(ndev);
if (ret < 0) {
- dev_err(&ndev->dev, "%s: sh_eth_ring_init failed.\n", __func__);
+ netdev_err(ndev, "%s: sh_eth_ring_init failed.\n", __func__);
return ret;
}
ret = sh_eth_dev_init(ndev, false);
if (ret < 0) {
- dev_err(&ndev->dev, "%s: sh_eth_dev_init failed.\n", __func__);
+ netdev_err(ndev, "%s: sh_eth_dev_init failed.\n", __func__);
return ret;
}
@@ -2004,7 +2016,7 @@ static int sh_eth_open(struct net_device *ndev)
ret = request_irq(ndev->irq, sh_eth_interrupt,
mdp->cd->irq_flags, ndev->name, ndev);
if (ret) {
- dev_err(&ndev->dev, "Can not assign IRQ number\n");
+ netdev_err(ndev, "Can not assign IRQ number\n");
goto out_napi_off;
}
@@ -2042,10 +2054,9 @@ static void sh_eth_tx_timeout(struct net_device *ndev)
netif_stop_queue(ndev);
- if (netif_msg_timer(mdp)) {
- dev_err(&ndev->dev, "%s: transmit timed out, status %8.8x, resetting...\n",
- ndev->name, (int)sh_eth_read(ndev, EESR));
- }
+ netif_err(mdp, timer, ndev,
+ "transmit timed out, status %8.8x, resetting...\n",
+ (int)sh_eth_read(ndev, EESR));
/* tx_errors count up */
ndev->stats.tx_errors++;
@@ -2080,8 +2091,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
spin_lock_irqsave(&mdp->lock, flags);
if ((mdp->cur_tx - mdp->dirty_tx) >= (mdp->num_tx_ring - 4)) {
if (!sh_eth_txfree(ndev)) {
- if (netif_msg_tx_queued(mdp))
- dev_warn(&ndev->dev, "TxFD exhausted.\n");
+ netif_warn(mdp, tx_queued, ndev, "TxFD exhausted.\n");
netif_stop_queue(ndev);
spin_unlock_irqrestore(&mdp->lock, flags);
return NETDEV_TX_BUSY;
@@ -2098,8 +2108,8 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
skb->len + 2);
txdesc->addr = dma_map_single(&ndev->dev, skb->data, skb->len,
DMA_TO_DEVICE);
- if (skb->len < ETHERSMALL)
- txdesc->buffer_length = ETHERSMALL;
+ if (skb->len < ETH_ZLEN)
+ txdesc->buffer_length = ETH_ZLEN;
else
txdesc->buffer_length = skb->len;
@@ -2251,7 +2261,7 @@ static int sh_eth_tsu_busy(struct net_device *ndev)
udelay(10);
timeout--;
if (timeout <= 0) {
- dev_err(&ndev->dev, "%s: timeout\n", __func__);
+ netdev_err(ndev, "%s: timeout\n", __func__);
return -ETIMEDOUT;
}
}
@@ -2571,37 +2581,30 @@ static void sh_eth_tsu_init(struct sh_eth_private *mdp)
}
/* MDIO bus release function */
-static int sh_mdio_release(struct net_device *ndev)
+static int sh_mdio_release(struct sh_eth_private *mdp)
{
- struct mii_bus *bus = dev_get_drvdata(&ndev->dev);
-
/* unregister mdio bus */
- mdiobus_unregister(bus);
-
- /* remove mdio bus info from net_device */
- dev_set_drvdata(&ndev->dev, NULL);
+ mdiobus_unregister(mdp->mii_bus);
/* free bitbang info */
- free_mdio_bitbang(bus);
+ free_mdio_bitbang(mdp->mii_bus);
return 0;
}
/* MDIO bus init function */
-static int sh_mdio_init(struct net_device *ndev, int id,
+static int sh_mdio_init(struct sh_eth_private *mdp,
struct sh_eth_plat_data *pd)
{
int ret, i;
struct bb_info *bitbang;
- struct sh_eth_private *mdp = netdev_priv(ndev);
+ struct platform_device *pdev = mdp->pdev;
+ struct device *dev = &mdp->pdev->dev;
/* create bit control struct for PHY */
- bitbang = devm_kzalloc(&ndev->dev, sizeof(struct bb_info),
- GFP_KERNEL);
- if (!bitbang) {
- ret = -ENOMEM;
- goto out;
- }
+ bitbang = devm_kzalloc(dev, sizeof(struct bb_info), GFP_KERNEL);
+ if (!bitbang)
+ return -ENOMEM;
/* bitbang init */
bitbang->addr = mdp->addr + mdp->reg_offset[PIR];
@@ -2614,44 +2617,42 @@ static int sh_mdio_init(struct net_device *ndev, int id,
/* MII controller setting */
mdp->mii_bus = alloc_mdio_bitbang(&bitbang->ctrl);
- if (!mdp->mii_bus) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!mdp->mii_bus)
+ return -ENOMEM;
/* Hook up MII support for ethtool */
mdp->mii_bus->name = "sh_mii";
- mdp->mii_bus->parent = &ndev->dev;
+ mdp->mii_bus->parent = dev;
snprintf(mdp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
- mdp->pdev->name, id);
+ pdev->name, pdev->id);
/* PHY IRQ */
- mdp->mii_bus->irq = devm_kzalloc(&ndev->dev,
- sizeof(int) * PHY_MAX_ADDR,
+ mdp->mii_bus->irq = devm_kzalloc(dev, sizeof(int) * PHY_MAX_ADDR,
GFP_KERNEL);
if (!mdp->mii_bus->irq) {
ret = -ENOMEM;
goto out_free_bus;
}
- for (i = 0; i < PHY_MAX_ADDR; i++)
- mdp->mii_bus->irq[i] = PHY_POLL;
- if (pd->phy_irq > 0)
- mdp->mii_bus->irq[pd->phy] = pd->phy_irq;
+ /* register MDIO bus */
+ if (dev->of_node) {
+ ret = of_mdiobus_register(mdp->mii_bus, dev->of_node);
+ } else {
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ mdp->mii_bus->irq[i] = PHY_POLL;
+ if (pd->phy_irq > 0)
+ mdp->mii_bus->irq[pd->phy] = pd->phy_irq;
+
+ ret = mdiobus_register(mdp->mii_bus);
+ }
- /* register mdio bus */
- ret = mdiobus_register(mdp->mii_bus);
if (ret)
goto out_free_bus;
- dev_set_drvdata(&ndev->dev, mdp->mii_bus);
-
return 0;
out_free_bus:
free_mdio_bitbang(mdp->mii_bus);
-
-out:
return ret;
}
@@ -2676,7 +2677,6 @@ static const u16 *sh_eth_get_register_offset(int register_type)
reg_offset = sh_eth_offset_fast_sh3_sh2;
break;
default:
- pr_err("Unknown register type (%d)\n", register_type);
break;
}
@@ -2710,6 +2710,48 @@ static const struct net_device_ops sh_eth_netdev_ops_tsu = {
.ndo_change_mtu = eth_change_mtu,
};
+#ifdef CONFIG_OF
+static struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ struct sh_eth_plat_data *pdata;
+ const char *mac_addr;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return NULL;
+
+ pdata->phy_interface = of_get_phy_mode(np);
+
+ mac_addr = of_get_mac_address(np);
+ if (mac_addr)
+ memcpy(pdata->mac_addr, mac_addr, ETH_ALEN);
+
+ pdata->no_ether_link =
+ of_property_read_bool(np, "renesas,no-ether-link");
+ pdata->ether_link_active_low =
+ of_property_read_bool(np, "renesas,ether-link-active-low");
+
+ return pdata;
+}
+
+static const struct of_device_id sh_eth_match_table[] = {
+ { .compatible = "renesas,gether-r8a7740", .data = &r8a7740_data },
+ { .compatible = "renesas,ether-r8a7778", .data = &r8a777x_data },
+ { .compatible = "renesas,ether-r8a7779", .data = &r8a777x_data },
+ { .compatible = "renesas,ether-r8a7790", .data = &r8a779x_data },
+ { .compatible = "renesas,ether-r8a7791", .data = &r8a779x_data },
+ { .compatible = "renesas,ether-r7s72100", .data = &r7s72100_data },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sh_eth_match_table);
+#else
+static inline struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev)
+{
+ return NULL;
+}
+#endif
+
static int sh_eth_drv_probe(struct platform_device *pdev)
{
int ret, devno = 0;
@@ -2723,15 +2765,15 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (unlikely(res == NULL)) {
dev_err(&pdev->dev, "invalid resource\n");
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
ndev = alloc_etherdev(sizeof(struct sh_eth_private));
- if (!ndev) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!ndev)
+ return -ENOMEM;
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
/* The sh Ether-specific entries in the device structure. */
ndev->base_addr = res->start;
@@ -2760,9 +2802,9 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
spin_lock_init(&mdp->lock);
mdp->pdev = pdev;
- pm_runtime_enable(&pdev->dev);
- pm_runtime_resume(&pdev->dev);
+ if (pdev->dev.of_node)
+ pd = sh_eth_parse_dt(&pdev->dev);
if (!pd) {
dev_err(&pdev->dev, "no platform data\n");
ret = -EINVAL;
@@ -2778,8 +2820,22 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
mdp->ether_link_active_low = pd->ether_link_active_low;
/* set cpu data */
- mdp->cd = (struct sh_eth_cpu_data *)id->driver_data;
+ if (id) {
+ mdp->cd = (struct sh_eth_cpu_data *)id->driver_data;
+ } else {
+ const struct of_device_id *match;
+
+ match = of_match_device(of_match_ptr(sh_eth_match_table),
+ &pdev->dev);
+ mdp->cd = (struct sh_eth_cpu_data *)match->data;
+ }
mdp->reg_offset = sh_eth_get_register_offset(mdp->cd->register_type);
+ if (!mdp->reg_offset) {
+ dev_err(&pdev->dev, "Unknown register type (%d)\n",
+ mdp->cd->register_type);
+ ret = -EINVAL;
+ goto out_release;
+ }
sh_eth_set_default_cpu_data(mdp->cd);
/* set function */
@@ -2825,6 +2881,13 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
}
}
+ /* MDIO bus init */
+ ret = sh_mdio_init(mdp, pd);
+ if (ret) {
+ dev_err(&ndev->dev, "failed to initialise MDIO\n");
+ goto out_release;
+ }
+
netif_napi_add(ndev, &mdp->napi, sh_eth_poll, 64);
/* network device register */
@@ -2832,31 +2895,26 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
if (ret)
goto out_napi_del;
- /* mdio bus init */
- ret = sh_mdio_init(ndev, pdev->id, pd);
- if (ret)
- goto out_unregister;
-
/* print device information */
- pr_info("Base address at 0x%x, %pM, IRQ %d.\n",
- (u32)ndev->base_addr, ndev->dev_addr, ndev->irq);
+ netdev_info(ndev, "Base address at 0x%x, %pM, IRQ %d.\n",
+ (u32)ndev->base_addr, ndev->dev_addr, ndev->irq);
+ pm_runtime_put(&pdev->dev);
platform_set_drvdata(pdev, ndev);
return ret;
-out_unregister:
- unregister_netdev(ndev);
-
out_napi_del:
netif_napi_del(&mdp->napi);
+ sh_mdio_release(mdp);
out_release:
/* net_dev free */
if (ndev)
free_netdev(ndev);
-out:
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
return ret;
}
@@ -2865,9 +2923,9 @@ static int sh_eth_drv_remove(struct platform_device *pdev)
struct net_device *ndev = platform_get_drvdata(pdev);
struct sh_eth_private *mdp = netdev_priv(ndev);
- sh_mdio_release(ndev);
unregister_netdev(ndev);
netif_napi_del(&mdp->napi);
+ sh_mdio_release(mdp);
pm_runtime_disable(&pdev->dev);
free_netdev(ndev);
@@ -2920,6 +2978,7 @@ static struct platform_driver sh_eth_driver = {
.driver = {
.name = CARDNAME,
.pm = SH_ETH_PM_OPS,
+ .of_match_table = of_match_ptr(sh_eth_match_table),
},
};
diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h
index 6075915b88ec..d55e37cd5fec 100644
--- a/drivers/net/ethernet/renesas/sh_eth.h
+++ b/drivers/net/ethernet/renesas/sh_eth.h
@@ -27,8 +27,7 @@
#define RX_RING_MIN 64
#define TX_RING_MAX 1024
#define RX_RING_MAX 1024
-#define ETHERSMALL 60
-#define PKT_BUF_SZ 1538
+#define PKT_BUF_SZ 1538
#define SH_ETH_TSU_TIMEOUT_MS 500
#define SH_ETH_TSU_CAM_ENTRIES 32
diff --git a/drivers/net/ethernet/samsung/Kconfig b/drivers/net/ethernet/samsung/Kconfig
new file mode 100644
index 000000000000..7902341f2623
--- /dev/null
+++ b/drivers/net/ethernet/samsung/Kconfig
@@ -0,0 +1,16 @@
+#
+# Samsung Ethernet device configuration
+#
+
+config NET_VENDOR_SAMSUNG
+ bool "Samsung Ethernet device"
+ default y
+ ---help---
+ This is the driver for the SXGBE 10G Ethernet IP block found on Samsung
+ platforms.
+
+if NET_VENDOR_SAMSUNG
+
+source "drivers/net/ethernet/samsung/sxgbe/Kconfig"
+
+endif # NET_VENDOR_SAMSUNG
diff --git a/drivers/net/ethernet/samsung/Makefile b/drivers/net/ethernet/samsung/Makefile
new file mode 100644
index 000000000000..1773c29b8d76
--- /dev/null
+++ b/drivers/net/ethernet/samsung/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Samsung Ethernet device drivers.
+#
+
+obj-$(CONFIG_SXGBE_ETH) += sxgbe/
diff --git a/drivers/net/ethernet/samsung/sxgbe/Kconfig b/drivers/net/ethernet/samsung/sxgbe/Kconfig
new file mode 100644
index 000000000000..d79288c51d0a
--- /dev/null
+++ b/drivers/net/ethernet/samsung/sxgbe/Kconfig
@@ -0,0 +1,9 @@
+config SXGBE_ETH
+ tristate "Samsung 10G/2.5G/1G SXGBE Ethernet driver"
+ depends on HAS_IOMEM && HAS_DMA
+ select PHYLIB
+ select CRC32
+ select PTP_1588_CLOCK
+ ---help---
+ This is the driver for the SXGBE 10G Ethernet IP block found on Samsung
+ platforms.
diff --git a/drivers/net/ethernet/samsung/sxgbe/Makefile b/drivers/net/ethernet/samsung/sxgbe/Makefile
new file mode 100644
index 000000000000..dcc80b9d4370
--- /dev/null
+++ b/drivers/net/ethernet/samsung/sxgbe/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_SXGBE_ETH) += samsung-sxgbe.o
+samsung-sxgbe-objs:= sxgbe_platform.o sxgbe_main.o sxgbe_desc.o \
+ sxgbe_dma.o sxgbe_core.o sxgbe_mtl.o sxgbe_mdio.o \
+ sxgbe_ethtool.o sxgbe_xpcs.o $(samsung-sxgbe-y)
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h
new file mode 100644
index 000000000000..6203c7d8550f
--- /dev/null
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h
@@ -0,0 +1,535 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __SXGBE_COMMON_H__
+#define __SXGBE_COMMON_H__
+
+/* forward references */
+struct sxgbe_desc_ops;
+struct sxgbe_dma_ops;
+struct sxgbe_mtl_ops;
+
+#define SXGBE_RESOURCE_NAME "sam_sxgbeeth"
+#define DRV_MODULE_VERSION "November_2013"
+
+/* MAX HW feature words */
+#define SXGBE_HW_WORDS 3
+
+#define SXGBE_RX_COE_NONE 0
+
+/* CSR Frequency Access Defines*/
+#define SXGBE_CSR_F_150M 150000000
+#define SXGBE_CSR_F_250M 250000000
+#define SXGBE_CSR_F_300M 300000000
+#define SXGBE_CSR_F_350M 350000000
+#define SXGBE_CSR_F_400M 400000000
+#define SXGBE_CSR_F_500M 500000000
+
+/* pause time */
+#define SXGBE_PAUSE_TIME 0x200
+
+/* tx queues */
+#define SXGBE_TX_QUEUES 8
+#define SXGBE_RX_QUEUES 16
+
+/* Calculated based how much time does it take to fill 256KB Rx memory
+ * at 10Gb speed at 156MHz clock rate and considered little less then
+ * the actual value.
+ */
+#define SXGBE_MAX_DMA_RIWT 0x70
+#define SXGBE_MIN_DMA_RIWT 0x01
+
+/* Tx coalesce parameters */
+#define SXGBE_COAL_TX_TIMER 40000
+#define SXGBE_MAX_COAL_TX_TICK 100000
+#define SXGBE_TX_MAX_FRAMES 512
+#define SXGBE_TX_FRAMES 128
+
+/* SXGBE TX FIFO is 8K, Rx FIFO is 16K */
+#define BUF_SIZE_16KiB 16384
+#define BUF_SIZE_8KiB 8192
+#define BUF_SIZE_4KiB 4096
+#define BUF_SIZE_2KiB 2048
+
+#define SXGBE_DEFAULT_LIT_LS 0x3E8
+#define SXGBE_DEFAULT_TWT_LS 0x0
+
+/* Flow Control defines */
+#define SXGBE_FLOW_OFF 0
+#define SXGBE_FLOW_RX 1
+#define SXGBE_FLOW_TX 2
+#define SXGBE_FLOW_AUTO (SXGBE_FLOW_TX | SXGBE_FLOW_RX)
+
+#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */
+
+/* errors */
+#define RX_GMII_ERR 0x01
+#define RX_WATCHDOG_ERR 0x02
+#define RX_CRC_ERR 0x03
+#define RX_GAINT_ERR 0x04
+#define RX_IP_HDR_ERR 0x05
+#define RX_PAYLOAD_ERR 0x06
+#define RX_OVERFLOW_ERR 0x07
+
+/* pkt type */
+#define RX_LEN_PKT 0x00
+#define RX_MACCTL_PKT 0x01
+#define RX_DCBCTL_PKT 0x02
+#define RX_ARP_PKT 0x03
+#define RX_OAM_PKT 0x04
+#define RX_UNTAG_PKT 0x05
+#define RX_OTHER_PKT 0x07
+#define RX_SVLAN_PKT 0x08
+#define RX_CVLAN_PKT 0x09
+#define RX_DVLAN_OCVLAN_ICVLAN_PKT 0x0A
+#define RX_DVLAN_OSVLAN_ISVLAN_PKT 0x0B
+#define RX_DVLAN_OSVLAN_ICVLAN_PKT 0x0C
+#define RX_DVLAN_OCVLAN_ISVLAN_PKT 0x0D
+
+#define RX_NOT_IP_PKT 0x00
+#define RX_IPV4_TCP_PKT 0x01
+#define RX_IPV4_UDP_PKT 0x02
+#define RX_IPV4_ICMP_PKT 0x03
+#define RX_IPV4_UNKNOWN_PKT 0x07
+#define RX_IPV6_TCP_PKT 0x09
+#define RX_IPV6_UDP_PKT 0x0A
+#define RX_IPV6_ICMP_PKT 0x0B
+#define RX_IPV6_UNKNOWN_PKT 0x0F
+
+#define RX_NO_PTP 0x00
+#define RX_PTP_SYNC 0x01
+#define RX_PTP_FOLLOW_UP 0x02
+#define RX_PTP_DELAY_REQ 0x03
+#define RX_PTP_DELAY_RESP 0x04
+#define RX_PTP_PDELAY_REQ 0x05
+#define RX_PTP_PDELAY_RESP 0x06
+#define RX_PTP_PDELAY_FOLLOW_UP 0x07
+#define RX_PTP_ANNOUNCE 0x08
+#define RX_PTP_MGMT 0x09
+#define RX_PTP_SIGNAL 0x0A
+#define RX_PTP_RESV_MSG 0x0F
+
+/* EEE-LPI mode flags*/
+#define TX_ENTRY_LPI_MODE 0x10
+#define TX_EXIT_LPI_MODE 0x20
+#define RX_ENTRY_LPI_MODE 0x40
+#define RX_EXIT_LPI_MODE 0x80
+
+/* EEE-LPI Interrupt status flag */
+#define LPI_INT_STATUS BIT(5)
+
+/* EEE-LPI Default timer values */
+#define LPI_LINK_STATUS_TIMER 0x3E8
+#define LPI_MAC_WAIT_TIMER 0x00
+
+/* EEE-LPI Control and status definitions */
+#define LPI_CTRL_STATUS_TXA BIT(19)
+#define LPI_CTRL_STATUS_PLSDIS BIT(18)
+#define LPI_CTRL_STATUS_PLS BIT(17)
+#define LPI_CTRL_STATUS_LPIEN BIT(16)
+#define LPI_CTRL_STATUS_TXRSTP BIT(11)
+#define LPI_CTRL_STATUS_RXRSTP BIT(10)
+#define LPI_CTRL_STATUS_RLPIST BIT(9)
+#define LPI_CTRL_STATUS_TLPIST BIT(8)
+#define LPI_CTRL_STATUS_RLPIEX BIT(3)
+#define LPI_CTRL_STATUS_RLPIEN BIT(2)
+#define LPI_CTRL_STATUS_TLPIEX BIT(1)
+#define LPI_CTRL_STATUS_TLPIEN BIT(0)
+
+enum dma_irq_status {
+ tx_hard_error = BIT(0),
+ tx_bump_tc = BIT(1),
+ handle_tx = BIT(2),
+ rx_hard_error = BIT(3),
+ rx_bump_tc = BIT(4),
+ handle_rx = BIT(5),
+};
+
+#define NETIF_F_HW_VLAN_ALL (NETIF_F_HW_VLAN_CTAG_RX | \
+ NETIF_F_HW_VLAN_STAG_RX | \
+ NETIF_F_HW_VLAN_CTAG_TX | \
+ NETIF_F_HW_VLAN_STAG_TX | \
+ NETIF_F_HW_VLAN_CTAG_FILTER | \
+ NETIF_F_HW_VLAN_STAG_FILTER)
+
+/* MMC control defines */
+#define SXGBE_MMC_CTRL_CNT_FRZ 0x00000008
+
+/* SXGBE HW ADDR regs */
+#define SXGBE_ADDR_HIGH(reg) (((reg > 15) ? 0x00000800 : 0x00000040) + \
+ (reg * 8))
+#define SXGBE_ADDR_LOW(reg) (((reg > 15) ? 0x00000804 : 0x00000044) + \
+ (reg * 8))
+#define SXGBE_MAX_PERFECT_ADDRESSES 32 /* Maximum unicast perfect filtering */
+#define SXGBE_FRAME_FILTER 0x00000004 /* Frame Filter */
+
+/* SXGBE Frame Filter defines */
+#define SXGBE_FRAME_FILTER_PR 0x00000001 /* Promiscuous Mode */
+#define SXGBE_FRAME_FILTER_HUC 0x00000002 /* Hash Unicast */
+#define SXGBE_FRAME_FILTER_HMC 0x00000004 /* Hash Multicast */
+#define SXGBE_FRAME_FILTER_DAIF 0x00000008 /* DA Inverse Filtering */
+#define SXGBE_FRAME_FILTER_PM 0x00000010 /* Pass all multicast */
+#define SXGBE_FRAME_FILTER_DBF 0x00000020 /* Disable Broadcast frames */
+#define SXGBE_FRAME_FILTER_SAIF 0x00000100 /* Inverse Filtering */
+#define SXGBE_FRAME_FILTER_SAF 0x00000200 /* Source Address Filter */
+#define SXGBE_FRAME_FILTER_HPF 0x00000400 /* Hash or perfect Filter */
+#define SXGBE_FRAME_FILTER_RA 0x80000000 /* Receive all mode */
+
+#define SXGBE_HASH_TABLE_SIZE 64
+#define SXGBE_HASH_HIGH 0x00000008 /* Multicast Hash Table High */
+#define SXGBE_HASH_LOW 0x0000000c /* Multicast Hash Table Low */
+
+#define SXGBE_HI_REG_AE 0x80000000
+
+/* Minimum and maximum MTU */
+#define MIN_MTU 68
+#define MAX_MTU 9000
+
+#define SXGBE_FOR_EACH_QUEUE(max_queues, queue_num) \
+ for (queue_num = 0; queue_num < max_queues; queue_num++)
+
+#define DRV_VERSION "1.0.0"
+
+#define SXGBE_MAX_RX_CHANNELS 16
+#define SXGBE_MAX_TX_CHANNELS 16
+
+#define START_MAC_REG_OFFSET 0x0000
+#define MAX_MAC_REG_OFFSET 0x0DFC
+#define START_MTL_REG_OFFSET 0x1000
+#define MAX_MTL_REG_OFFSET 0x18FC
+#define START_DMA_REG_OFFSET 0x3000
+#define MAX_DMA_REG_OFFSET 0x38FC
+
+#define REG_SPACE_SIZE 0x2000
+
+/* sxgbe statistics counters */
+struct sxgbe_extra_stats {
+ /* TX/RX IRQ events */
+ unsigned long tx_underflow_irq;
+ unsigned long tx_process_stopped_irq;
+ unsigned long tx_ctxt_desc_err;
+ unsigned long tx_threshold;
+ unsigned long rx_threshold;
+ unsigned long tx_pkt_n;
+ unsigned long rx_pkt_n;
+ unsigned long normal_irq_n;
+ unsigned long tx_normal_irq_n;
+ unsigned long rx_normal_irq_n;
+ unsigned long napi_poll;
+ unsigned long tx_clean;
+ unsigned long tx_reset_ic_bit;
+ unsigned long rx_process_stopped_irq;
+ unsigned long rx_underflow_irq;
+
+ /* Bus access errors */
+ unsigned long fatal_bus_error_irq;
+ unsigned long tx_read_transfer_err;
+ unsigned long tx_write_transfer_err;
+ unsigned long tx_desc_access_err;
+ unsigned long tx_buffer_access_err;
+ unsigned long tx_data_transfer_err;
+ unsigned long rx_read_transfer_err;
+ unsigned long rx_write_transfer_err;
+ unsigned long rx_desc_access_err;
+ unsigned long rx_buffer_access_err;
+ unsigned long rx_data_transfer_err;
+
+ /* EEE-LPI stats */
+ unsigned long tx_lpi_entry_n;
+ unsigned long tx_lpi_exit_n;
+ unsigned long rx_lpi_entry_n;
+ unsigned long rx_lpi_exit_n;
+ unsigned long eee_wakeup_error_n;
+
+ /* RX specific */
+ /* L2 error */
+ unsigned long rx_code_gmii_err;
+ unsigned long rx_watchdog_err;
+ unsigned long rx_crc_err;
+ unsigned long rx_gaint_pkt_err;
+ unsigned long ip_hdr_err;
+ unsigned long ip_payload_err;
+ unsigned long overflow_error;
+
+ /* L2 Pkt type */
+ unsigned long len_pkt;
+ unsigned long mac_ctl_pkt;
+ unsigned long dcb_ctl_pkt;
+ unsigned long arp_pkt;
+ unsigned long oam_pkt;
+ unsigned long untag_okt;
+ unsigned long other_pkt;
+ unsigned long svlan_tag_pkt;
+ unsigned long cvlan_tag_pkt;
+ unsigned long dvlan_ocvlan_icvlan_pkt;
+ unsigned long dvlan_osvlan_isvlan_pkt;
+ unsigned long dvlan_osvlan_icvlan_pkt;
+ unsigned long dvan_ocvlan_icvlan_pkt;
+
+ /* L3/L4 Pkt type */
+ unsigned long not_ip_pkt;
+ unsigned long ip4_tcp_pkt;
+ unsigned long ip4_udp_pkt;
+ unsigned long ip4_icmp_pkt;
+ unsigned long ip4_unknown_pkt;
+ unsigned long ip6_tcp_pkt;
+ unsigned long ip6_udp_pkt;
+ unsigned long ip6_icmp_pkt;
+ unsigned long ip6_unknown_pkt;
+
+ /* Filter specific */
+ unsigned long vlan_filter_match;
+ unsigned long sa_filter_fail;
+ unsigned long da_filter_fail;
+ unsigned long hash_filter_pass;
+ unsigned long l3_filter_match;
+ unsigned long l4_filter_match;
+
+ /* RX context specific */
+ unsigned long timestamp_dropped;
+ unsigned long rx_msg_type_no_ptp;
+ unsigned long rx_ptp_type_sync;
+ unsigned long rx_ptp_type_follow_up;
+ unsigned long rx_ptp_type_delay_req;
+ unsigned long rx_ptp_type_delay_resp;
+ unsigned long rx_ptp_type_pdelay_req;
+ unsigned long rx_ptp_type_pdelay_resp;
+ unsigned long rx_ptp_type_pdelay_follow_up;
+ unsigned long rx_ptp_announce;
+ unsigned long rx_ptp_mgmt;
+ unsigned long rx_ptp_signal;
+ unsigned long rx_ptp_resv_msg_type;
+};
+
+struct mac_link {
+ int port;
+ int duplex;
+ int speed;
+};
+
+struct mii_regs {
+ unsigned int addr; /* MII Address */
+ unsigned int data; /* MII Data */
+};
+
+struct sxgbe_core_ops {
+ /* MAC core initialization */
+ void (*core_init)(void __iomem *ioaddr);
+ /* Dump MAC registers */
+ void (*dump_regs)(void __iomem *ioaddr);
+ /* Handle extra events on specific interrupts hw dependent */
+ int (*host_irq_status)(void __iomem *ioaddr,
+ struct sxgbe_extra_stats *x);
+ /* Set power management mode (e.g. magic frame) */
+ void (*pmt)(void __iomem *ioaddr, unsigned long mode);
+ /* Set/Get Unicast MAC addresses */
+ void (*set_umac_addr)(void __iomem *ioaddr, unsigned char *addr,
+ unsigned int reg_n);
+ void (*get_umac_addr)(void __iomem *ioaddr, unsigned char *addr,
+ unsigned int reg_n);
+ void (*enable_rx)(void __iomem *ioaddr, bool enable);
+ void (*enable_tx)(void __iomem *ioaddr, bool enable);
+
+ /* controller version specific operations */
+ int (*get_controller_version)(void __iomem *ioaddr);
+
+ /* If supported then get the optional core features */
+ unsigned int (*get_hw_feature)(void __iomem *ioaddr,
+ unsigned char feature_index);
+ /* adjust SXGBE speed */
+ void (*set_speed)(void __iomem *ioaddr, unsigned char speed);
+
+ /* EEE-LPI specific operations */
+ void (*set_eee_mode)(void __iomem *ioaddr);
+ void (*reset_eee_mode)(void __iomem *ioaddr);
+ void (*set_eee_timer)(void __iomem *ioaddr, const int ls,
+ const int tw);
+ void (*set_eee_pls)(void __iomem *ioaddr, const int link);
+
+ /* Enable disable checksum offload operations */
+ void (*enable_rx_csum)(void __iomem *ioaddr);
+ void (*disable_rx_csum)(void __iomem *ioaddr);
+};
+
+const struct sxgbe_core_ops *sxgbe_get_core_ops(void);
+
+struct sxgbe_ops {
+ const struct sxgbe_core_ops *mac;
+ const struct sxgbe_desc_ops *desc;
+ const struct sxgbe_dma_ops *dma;
+ const struct sxgbe_mtl_ops *mtl;
+ struct mii_regs mii; /* MII register Addresses */
+ struct mac_link link;
+ unsigned int ctrl_uid;
+ unsigned int ctrl_id;
+};
+
+/* SXGBE private data structures */
+struct sxgbe_tx_queue {
+ unsigned int irq_no;
+ struct sxgbe_priv_data *priv_ptr;
+ struct sxgbe_tx_norm_desc *dma_tx;
+ dma_addr_t dma_tx_phy;
+ dma_addr_t *tx_skbuff_dma;
+ struct sk_buff **tx_skbuff;
+ struct timer_list txtimer;
+ spinlock_t tx_lock; /* lock for tx queues */
+ unsigned int cur_tx;
+ unsigned int dirty_tx;
+ u32 tx_count_frames;
+ u32 tx_coal_frames;
+ u32 tx_coal_timer;
+ int hwts_tx_en;
+ u16 prev_mss;
+ u8 queue_no;
+};
+
+struct sxgbe_rx_queue {
+ struct sxgbe_priv_data *priv_ptr;
+ struct sxgbe_rx_norm_desc *dma_rx;
+ struct sk_buff **rx_skbuff;
+ unsigned int cur_rx;
+ unsigned int dirty_rx;
+ unsigned int irq_no;
+ u32 rx_riwt;
+ dma_addr_t *rx_skbuff_dma;
+ dma_addr_t dma_rx_phy;
+ u8 queue_no;
+};
+
+/* SXGBE HW capabilities */
+struct sxgbe_hw_features {
+ /****** CAP [0] *******/
+ unsigned int pmt_remote_wake_up;
+ unsigned int pmt_magic_frame;
+ /* IEEE 1588-2008 */
+ unsigned int atime_stamp;
+
+ unsigned int eee;
+
+ unsigned int tx_csum_offload;
+ unsigned int rx_csum_offload;
+ unsigned int multi_macaddr;
+ unsigned int tstamp_srcselect;
+ unsigned int sa_vlan_insert;
+
+ /****** CAP [1] *******/
+ unsigned int rxfifo_size;
+ unsigned int txfifo_size;
+ unsigned int atstmap_hword;
+ unsigned int dcb_enable;
+ unsigned int splithead_enable;
+ unsigned int tcpseg_offload;
+ unsigned int debug_mem;
+ unsigned int rss_enable;
+ unsigned int hash_tsize;
+ unsigned int l3l4_filer_size;
+
+ /* This value is in bytes and
+ * as mentioned in HW features
+ * of SXGBE data book
+ */
+ unsigned int rx_mtl_qsize;
+ unsigned int tx_mtl_qsize;
+
+ /****** CAP [2] *******/
+ /* TX and RX number of channels */
+ unsigned int rx_mtl_queues;
+ unsigned int tx_mtl_queues;
+ unsigned int rx_dma_channels;
+ unsigned int tx_dma_channels;
+ unsigned int pps_output_count;
+ unsigned int aux_input_count;
+};
+
+struct sxgbe_priv_data {
+ /* DMA descriptos */
+ struct sxgbe_tx_queue *txq[SXGBE_TX_QUEUES];
+ struct sxgbe_rx_queue *rxq[SXGBE_RX_QUEUES];
+ u8 cur_rx_qnum;
+
+ unsigned int dma_tx_size;
+ unsigned int dma_rx_size;
+ unsigned int dma_buf_sz;
+ u32 rx_riwt;
+
+ struct napi_struct napi;
+
+ void __iomem *ioaddr;
+ struct net_device *dev;
+ struct device *device;
+ struct sxgbe_ops *hw; /* sxgbe specific ops */
+ int no_csum_insertion;
+ int irq;
+ int rxcsum_insertion;
+ spinlock_t stats_lock; /* lock for tx/rx statatics */
+
+ struct phy_device *phydev;
+ int oldlink;
+ int speed;
+ int oldduplex;
+ struct mii_bus *mii;
+ int mii_irq[PHY_MAX_ADDR];
+ u8 rx_pause;
+ u8 tx_pause;
+
+ struct sxgbe_extra_stats xstats;
+ struct sxgbe_plat_data *plat;
+ struct sxgbe_hw_features hw_cap;
+
+ u32 msg_enable;
+
+ struct clk *sxgbe_clk;
+ int clk_csr;
+ unsigned int mode;
+ unsigned int default_addend;
+
+ /* advanced time stamp support */
+ u32 adv_ts;
+ int use_riwt;
+ struct ptp_clock *ptp_clock;
+
+ /* tc control */
+ int tx_tc;
+ int rx_tc;
+ /* EEE-LPI specific members */
+ struct timer_list eee_ctrl_timer;
+ bool tx_path_in_lpi_mode;
+ int lpi_irq;
+ int eee_enabled;
+ int eee_active;
+ int tx_lpi_timer;
+};
+
+/* Function prototypes */
+struct sxgbe_priv_data *sxgbe_drv_probe(struct device *device,
+ struct sxgbe_plat_data *plat_dat,
+ void __iomem *addr);
+int sxgbe_drv_remove(struct net_device *ndev);
+void sxgbe_set_ethtool_ops(struct net_device *netdev);
+int sxgbe_mdio_unregister(struct net_device *ndev);
+int sxgbe_mdio_register(struct net_device *ndev);
+int sxgbe_register_platform(void);
+void sxgbe_unregister_platform(void);
+
+#ifdef CONFIG_PM
+int sxgbe_suspend(struct net_device *ndev);
+int sxgbe_resume(struct net_device *ndev);
+int sxgbe_freeze(struct net_device *ndev);
+int sxgbe_restore(struct net_device *ndev);
+#endif /* CONFIG_PM */
+
+const struct sxgbe_mtl_ops *sxgbe_get_mtl_ops(void);
+
+void sxgbe_disable_eee_mode(struct sxgbe_priv_data * const priv);
+bool sxgbe_eee_init(struct sxgbe_priv_data * const priv);
+#endif /* __SXGBE_COMMON_H__ */
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c
new file mode 100644
index 000000000000..c4da7a2b002a
--- /dev/null
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c
@@ -0,0 +1,262 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+
+#include "sxgbe_common.h"
+#include "sxgbe_reg.h"
+
+/* MAC core initialization */
+static void sxgbe_core_init(void __iomem *ioaddr)
+{
+ u32 regval;
+
+ /* TX configuration */
+ regval = readl(ioaddr + SXGBE_CORE_TX_CONFIG_REG);
+ /* Other configurable parameters IFP, IPG, ISR, ISM
+ * needs to be set if needed
+ */
+ regval |= SXGBE_TX_JABBER_DISABLE;
+ writel(regval, ioaddr + SXGBE_CORE_TX_CONFIG_REG);
+
+ /* RX configuration */
+ regval = readl(ioaddr + SXGBE_CORE_RX_CONFIG_REG);
+ /* Other configurable parameters CST, SPEN, USP, GPSLCE
+ * WD, LM, S2KP, HDSMS, GPSL, ELEN, ARPEN needs to be
+ * set if needed
+ */
+ regval |= SXGBE_RX_JUMBPKT_ENABLE | SXGBE_RX_ACS_ENABLE;
+ writel(regval, ioaddr + SXGBE_CORE_RX_CONFIG_REG);
+}
+
+/* Dump MAC registers */
+static void sxgbe_core_dump_regs(void __iomem *ioaddr)
+{
+}
+
+static int sxgbe_get_lpi_status(void __iomem *ioaddr, const u32 irq_status)
+{
+ int status = 0;
+ int lpi_status;
+
+ /* Reading this register shall clear all the LPI status bits */
+ lpi_status = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
+
+ if (lpi_status & LPI_CTRL_STATUS_TLPIEN)
+ status |= TX_ENTRY_LPI_MODE;
+ if (lpi_status & LPI_CTRL_STATUS_TLPIEX)
+ status |= TX_EXIT_LPI_MODE;
+ if (lpi_status & LPI_CTRL_STATUS_RLPIEN)
+ status |= RX_ENTRY_LPI_MODE;
+ if (lpi_status & LPI_CTRL_STATUS_RLPIEX)
+ status |= RX_EXIT_LPI_MODE;
+
+ return status;
+}
+
+/* Handle extra events on specific interrupts hw dependent */
+static int sxgbe_core_host_irq_status(void __iomem *ioaddr,
+ struct sxgbe_extra_stats *x)
+{
+ int irq_status, status = 0;
+
+ irq_status = readl(ioaddr + SXGBE_CORE_INT_STATUS_REG);
+
+ if (unlikely(irq_status & LPI_INT_STATUS))
+ status |= sxgbe_get_lpi_status(ioaddr, irq_status);
+
+ return status;
+}
+
+/* Set power management mode (e.g. magic frame) */
+static void sxgbe_core_pmt(void __iomem *ioaddr, unsigned long mode)
+{
+}
+
+/* Set/Get Unicast MAC addresses */
+static void sxgbe_core_set_umac_addr(void __iomem *ioaddr, unsigned char *addr,
+ unsigned int reg_n)
+{
+ u32 high_word, low_word;
+
+ high_word = (addr[5] << 8) | (addr[4]);
+ low_word = (addr[3] << 24) | (addr[2] << 16) |
+ (addr[1] << 8) | (addr[0]);
+ writel(high_word, ioaddr + SXGBE_CORE_ADD_HIGHOFFSET(reg_n));
+ writel(low_word, ioaddr + SXGBE_CORE_ADD_LOWOFFSET(reg_n));
+}
+
+static void sxgbe_core_get_umac_addr(void __iomem *ioaddr, unsigned char *addr,
+ unsigned int reg_n)
+{
+ u32 high_word, low_word;
+
+ high_word = readl(ioaddr + SXGBE_CORE_ADD_HIGHOFFSET(reg_n));
+ low_word = readl(ioaddr + SXGBE_CORE_ADD_LOWOFFSET(reg_n));
+
+ /* extract and assign address */
+ addr[5] = (high_word & 0x0000FF00) >> 8;
+ addr[4] = (high_word & 0x000000FF);
+ addr[3] = (low_word & 0xFF000000) >> 24;
+ addr[2] = (low_word & 0x00FF0000) >> 16;
+ addr[1] = (low_word & 0x0000FF00) >> 8;
+ addr[0] = (low_word & 0x000000FF);
+}
+
+static void sxgbe_enable_tx(void __iomem *ioaddr, bool enable)
+{
+ u32 tx_config;
+
+ tx_config = readl(ioaddr + SXGBE_CORE_TX_CONFIG_REG);
+ tx_config &= ~SXGBE_TX_ENABLE;
+
+ if (enable)
+ tx_config |= SXGBE_TX_ENABLE;
+ writel(tx_config, ioaddr + SXGBE_CORE_TX_CONFIG_REG);
+}
+
+static void sxgbe_enable_rx(void __iomem *ioaddr, bool enable)
+{
+ u32 rx_config;
+
+ rx_config = readl(ioaddr + SXGBE_CORE_RX_CONFIG_REG);
+ rx_config &= ~SXGBE_RX_ENABLE;
+
+ if (enable)
+ rx_config |= SXGBE_RX_ENABLE;
+ writel(rx_config, ioaddr + SXGBE_CORE_RX_CONFIG_REG);
+}
+
+static int sxgbe_get_controller_version(void __iomem *ioaddr)
+{
+ return readl(ioaddr + SXGBE_CORE_VERSION_REG);
+}
+
+/* If supported then get the optional core features */
+static unsigned int sxgbe_get_hw_feature(void __iomem *ioaddr,
+ unsigned char feature_index)
+{
+ return readl(ioaddr + (SXGBE_CORE_HW_FEA_REG(feature_index)));
+}
+
+static void sxgbe_core_set_speed(void __iomem *ioaddr, unsigned char speed)
+{
+ u32 tx_cfg = readl(ioaddr + SXGBE_CORE_TX_CONFIG_REG);
+
+ /* clear the speed bits */
+ tx_cfg &= ~0x60000000;
+ tx_cfg |= (speed << SXGBE_SPEED_LSHIFT);
+
+ /* set the speed */
+ writel(tx_cfg, ioaddr + SXGBE_CORE_TX_CONFIG_REG);
+}
+
+static void sxgbe_set_eee_mode(void __iomem *ioaddr)
+{
+ u32 ctrl;
+
+ /* Enable the LPI mode for transmit path with Tx automate bit set.
+ * When Tx Automate bit is set, MAC internally handles the entry
+ * to LPI mode after all outstanding and pending packets are
+ * transmitted.
+ */
+ ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
+ ctrl |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_TXA;
+ writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
+}
+
+static void sxgbe_reset_eee_mode(void __iomem *ioaddr)
+{
+ u32 ctrl;
+
+ ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
+ ctrl &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_TXA);
+ writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
+}
+
+static void sxgbe_set_eee_pls(void __iomem *ioaddr, const int link)
+{
+ u32 ctrl;
+
+ ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
+
+ /* If the PHY link status is UP then set PLS */
+ if (link)
+ ctrl |= LPI_CTRL_STATUS_PLS;
+ else
+ ctrl &= ~LPI_CTRL_STATUS_PLS;
+
+ writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
+}
+
+static void sxgbe_set_eee_timer(void __iomem *ioaddr,
+ const int ls, const int tw)
+{
+ int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16);
+
+ /* Program the timers in the LPI timer control register:
+ * LS: minimum time (ms) for which the link
+ * status from PHY should be ok before transmitting
+ * the LPI pattern.
+ * TW: minimum time (us) for which the core waits
+ * after it has stopped transmitting the LPI pattern.
+ */
+ writel(value, ioaddr + SXGBE_CORE_LPI_TIMER_CTRL);
+}
+
+static void sxgbe_enable_rx_csum(void __iomem *ioaddr)
+{
+ u32 ctrl;
+
+ ctrl = readl(ioaddr + SXGBE_CORE_RX_CONFIG_REG);
+ ctrl |= SXGBE_RX_CSUMOFFLOAD_ENABLE;
+ writel(ctrl, ioaddr + SXGBE_CORE_RX_CONFIG_REG);
+}
+
+static void sxgbe_disable_rx_csum(void __iomem *ioaddr)
+{
+ u32 ctrl;
+
+ ctrl = readl(ioaddr + SXGBE_CORE_RX_CONFIG_REG);
+ ctrl &= ~SXGBE_RX_CSUMOFFLOAD_ENABLE;
+ writel(ctrl, ioaddr + SXGBE_CORE_RX_CONFIG_REG);
+}
+
+static const struct sxgbe_core_ops core_ops = {
+ .core_init = sxgbe_core_init,
+ .dump_regs = sxgbe_core_dump_regs,
+ .host_irq_status = sxgbe_core_host_irq_status,
+ .pmt = sxgbe_core_pmt,
+ .set_umac_addr = sxgbe_core_set_umac_addr,
+ .get_umac_addr = sxgbe_core_get_umac_addr,
+ .enable_rx = sxgbe_enable_rx,
+ .enable_tx = sxgbe_enable_tx,
+ .get_controller_version = sxgbe_get_controller_version,
+ .get_hw_feature = sxgbe_get_hw_feature,
+ .set_speed = sxgbe_core_set_speed,
+ .set_eee_mode = sxgbe_set_eee_mode,
+ .reset_eee_mode = sxgbe_reset_eee_mode,
+ .set_eee_timer = sxgbe_set_eee_timer,
+ .set_eee_pls = sxgbe_set_eee_pls,
+ .enable_rx_csum = sxgbe_enable_rx_csum,
+ .disable_rx_csum = sxgbe_disable_rx_csum,
+};
+
+const struct sxgbe_core_ops *sxgbe_get_core_ops(void)
+{
+ return &core_ops;
+}
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.c
new file mode 100644
index 000000000000..e896dbbd2e15
--- /dev/null
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.c
@@ -0,0 +1,515 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/bitops.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+
+#include "sxgbe_common.h"
+#include "sxgbe_dma.h"
+#include "sxgbe_desc.h"
+
+/* DMA TX descriptor ring initialization */
+static void sxgbe_init_tx_desc(struct sxgbe_tx_norm_desc *p)
+{
+ p->tdes23.tx_rd_des23.own_bit = 0;
+}
+
+static void sxgbe_tx_desc_enable_tse(struct sxgbe_tx_norm_desc *p, u8 is_tse,
+ u32 total_hdr_len, u32 tcp_hdr_len,
+ u32 tcp_payload_len)
+{
+ p->tdes23.tx_rd_des23.tse_bit = is_tse;
+ p->tdes23.tx_rd_des23.buf1_size = total_hdr_len;
+ p->tdes23.tx_rd_des23.tcp_hdr_len = tcp_hdr_len / 4;
+ p->tdes23.tx_rd_des23.tx_pkt_len.tcp_payload_len = tcp_payload_len;
+}
+
+/* Assign buffer lengths for descriptor */
+static void sxgbe_prepare_tx_desc(struct sxgbe_tx_norm_desc *p, u8 is_fd,
+ int buf1_len, int pkt_len, int cksum)
+{
+ p->tdes23.tx_rd_des23.first_desc = is_fd;
+ p->tdes23.tx_rd_des23.buf1_size = buf1_len;
+
+ p->tdes23.tx_rd_des23.tx_pkt_len.cksum_pktlen.total_pkt_len = pkt_len;
+
+ if (cksum)
+ p->tdes23.tx_rd_des23.tx_pkt_len.cksum_pktlen.cksum_ctl = cic_full;
+}
+
+/* Set VLAN control information */
+static void sxgbe_tx_vlanctl_desc(struct sxgbe_tx_norm_desc *p, int vlan_ctl)
+{
+ p->tdes23.tx_rd_des23.vlan_tag_ctl = vlan_ctl;
+}
+
+/* Set the owner of Normal descriptor */
+static void sxgbe_set_tx_owner(struct sxgbe_tx_norm_desc *p)
+{
+ p->tdes23.tx_rd_des23.own_bit = 1;
+}
+
+/* Get the owner of Normal descriptor */
+static int sxgbe_get_tx_owner(struct sxgbe_tx_norm_desc *p)
+{
+ return p->tdes23.tx_rd_des23.own_bit;
+}
+
+/* Invoked by the xmit function to close the tx descriptor */
+static void sxgbe_close_tx_desc(struct sxgbe_tx_norm_desc *p)
+{
+ p->tdes23.tx_rd_des23.last_desc = 1;
+ p->tdes23.tx_rd_des23.int_on_com = 1;
+}
+
+/* Clean the tx descriptor as soon as the tx irq is received */
+static void sxgbe_release_tx_desc(struct sxgbe_tx_norm_desc *p)
+{
+ memset(p, 0, sizeof(*p));
+}
+
+/* Clear interrupt on tx frame completion. When this bit is
+ * set an interrupt happens as soon as the frame is transmitted
+ */
+static void sxgbe_clear_tx_ic(struct sxgbe_tx_norm_desc *p)
+{
+ p->tdes23.tx_rd_des23.int_on_com = 0;
+}
+
+/* Last tx segment reports the transmit status */
+static int sxgbe_get_tx_ls(struct sxgbe_tx_norm_desc *p)
+{
+ return p->tdes23.tx_rd_des23.last_desc;
+}
+
+/* Get the buffer size from the descriptor */
+static int sxgbe_get_tx_len(struct sxgbe_tx_norm_desc *p)
+{
+ return p->tdes23.tx_rd_des23.buf1_size;
+}
+
+/* Set tx timestamp enable bit */
+static void sxgbe_tx_enable_tstamp(struct sxgbe_tx_norm_desc *p)
+{
+ p->tdes23.tx_rd_des23.timestmp_enable = 1;
+}
+
+/* get tx timestamp status */
+static int sxgbe_get_tx_timestamp_status(struct sxgbe_tx_norm_desc *p)
+{
+ return p->tdes23.tx_rd_des23.timestmp_enable;
+}
+
+/* TX Context Descripto Specific */
+static void sxgbe_tx_ctxt_desc_set_ctxt(struct sxgbe_tx_ctxt_desc *p)
+{
+ p->ctxt_bit = 1;
+}
+
+/* Set the owner of TX context descriptor */
+static void sxgbe_tx_ctxt_desc_set_owner(struct sxgbe_tx_ctxt_desc *p)
+{
+ p->own_bit = 1;
+}
+
+/* Get the owner of TX context descriptor */
+static int sxgbe_tx_ctxt_desc_get_owner(struct sxgbe_tx_ctxt_desc *p)
+{
+ return p->own_bit;
+}
+
+/* Set TX mss in TX context Descriptor */
+static void sxgbe_tx_ctxt_desc_set_mss(struct sxgbe_tx_ctxt_desc *p, u16 mss)
+{
+ p->maxseg_size = mss;
+}
+
+/* Get TX mss from TX context Descriptor */
+static int sxgbe_tx_ctxt_desc_get_mss(struct sxgbe_tx_ctxt_desc *p)
+{
+ return p->maxseg_size;
+}
+
+/* Set TX tcmssv in TX context Descriptor */
+static void sxgbe_tx_ctxt_desc_set_tcmssv(struct sxgbe_tx_ctxt_desc *p)
+{
+ p->tcmssv = 1;
+}
+
+/* Reset TX ostc in TX context Descriptor */
+static void sxgbe_tx_ctxt_desc_reset_ostc(struct sxgbe_tx_ctxt_desc *p)
+{
+ p->ostc = 0;
+}
+
+/* Set IVLAN information */
+static void sxgbe_tx_ctxt_desc_set_ivlantag(struct sxgbe_tx_ctxt_desc *p,
+ int is_ivlanvalid, int ivlan_tag,
+ int ivlan_ctl)
+{
+ if (is_ivlanvalid) {
+ p->ivlan_tag_valid = is_ivlanvalid;
+ p->ivlan_tag = ivlan_tag;
+ p->ivlan_tag_ctl = ivlan_ctl;
+ }
+}
+
+/* Return IVLAN Tag */
+static int sxgbe_tx_ctxt_desc_get_ivlantag(struct sxgbe_tx_ctxt_desc *p)
+{
+ return p->ivlan_tag;
+}
+
+/* Set VLAN Tag */
+static void sxgbe_tx_ctxt_desc_set_vlantag(struct sxgbe_tx_ctxt_desc *p,
+ int is_vlanvalid, int vlan_tag)
+{
+ if (is_vlanvalid) {
+ p->vltag_valid = is_vlanvalid;
+ p->vlan_tag = vlan_tag;
+ }
+}
+
+/* Return VLAN Tag */
+static int sxgbe_tx_ctxt_desc_get_vlantag(struct sxgbe_tx_ctxt_desc *p)
+{
+ return p->vlan_tag;
+}
+
+/* Set Time stamp */
+static void sxgbe_tx_ctxt_desc_set_tstamp(struct sxgbe_tx_ctxt_desc *p,
+ u8 ostc_enable, u64 tstamp)
+{
+ if (ostc_enable) {
+ p->ostc = ostc_enable;
+ p->tstamp_lo = (u32) tstamp;
+ p->tstamp_hi = (u32) (tstamp>>32);
+ }
+}
+/* Close TX context descriptor */
+static void sxgbe_tx_ctxt_desc_close(struct sxgbe_tx_ctxt_desc *p)
+{
+ p->own_bit = 1;
+}
+
+/* WB status of context descriptor */
+static int sxgbe_tx_ctxt_desc_get_cde(struct sxgbe_tx_ctxt_desc *p)
+{
+ return p->ctxt_desc_err;
+}
+
+/* DMA RX descriptor ring initialization */
+static void sxgbe_init_rx_desc(struct sxgbe_rx_norm_desc *p, int disable_rx_ic,
+ int mode, int end)
+{
+ p->rdes23.rx_rd_des23.own_bit = 1;
+ if (disable_rx_ic)
+ p->rdes23.rx_rd_des23.int_on_com = disable_rx_ic;
+}
+
+/* Get RX own bit */
+static int sxgbe_get_rx_owner(struct sxgbe_rx_norm_desc *p)
+{
+ return p->rdes23.rx_rd_des23.own_bit;
+}
+
+/* Set RX own bit */
+static void sxgbe_set_rx_owner(struct sxgbe_rx_norm_desc *p)
+{
+ p->rdes23.rx_rd_des23.own_bit = 1;
+}
+
+/* Get the receive frame size */
+static int sxgbe_get_rx_frame_len(struct sxgbe_rx_norm_desc *p)
+{
+ return p->rdes23.rx_wb_des23.pkt_len;
+}
+
+/* Return first Descriptor status */
+static int sxgbe_get_rx_fd_status(struct sxgbe_rx_norm_desc *p)
+{
+ return p->rdes23.rx_wb_des23.first_desc;
+}
+
+/* Return Last Descriptor status */
+static int sxgbe_get_rx_ld_status(struct sxgbe_rx_norm_desc *p)
+{
+ return p->rdes23.rx_wb_des23.last_desc;
+}
+
+
+/* Return the RX status looking at the WB fields */
+static int sxgbe_rx_wbstatus(struct sxgbe_rx_norm_desc *p,
+ struct sxgbe_extra_stats *x, int *checksum)
+{
+ int status = 0;
+
+ *checksum = CHECKSUM_UNNECESSARY;
+ if (p->rdes23.rx_wb_des23.err_summary) {
+ switch (p->rdes23.rx_wb_des23.err_l2_type) {
+ case RX_GMII_ERR:
+ status = -EINVAL;
+ x->rx_code_gmii_err++;
+ break;
+ case RX_WATCHDOG_ERR:
+ status = -EINVAL;
+ x->rx_watchdog_err++;
+ break;
+ case RX_CRC_ERR:
+ status = -EINVAL;
+ x->rx_crc_err++;
+ break;
+ case RX_GAINT_ERR:
+ status = -EINVAL;
+ x->rx_gaint_pkt_err++;
+ break;
+ case RX_IP_HDR_ERR:
+ *checksum = CHECKSUM_NONE;
+ x->ip_hdr_err++;
+ break;
+ case RX_PAYLOAD_ERR:
+ *checksum = CHECKSUM_NONE;
+ x->ip_payload_err++;
+ break;
+ case RX_OVERFLOW_ERR:
+ status = -EINVAL;
+ x->overflow_error++;
+ break;
+ default:
+ pr_err("Invalid Error type\n");
+ break;
+ }
+ } else {
+ switch (p->rdes23.rx_wb_des23.err_l2_type) {
+ case RX_LEN_PKT:
+ x->len_pkt++;
+ break;
+ case RX_MACCTL_PKT:
+ x->mac_ctl_pkt++;
+ break;
+ case RX_DCBCTL_PKT:
+ x->dcb_ctl_pkt++;
+ break;
+ case RX_ARP_PKT:
+ x->arp_pkt++;
+ break;
+ case RX_OAM_PKT:
+ x->oam_pkt++;
+ break;
+ case RX_UNTAG_PKT:
+ x->untag_okt++;
+ break;
+ case RX_OTHER_PKT:
+ x->other_pkt++;
+ break;
+ case RX_SVLAN_PKT:
+ x->svlan_tag_pkt++;
+ break;
+ case RX_CVLAN_PKT:
+ x->cvlan_tag_pkt++;
+ break;
+ case RX_DVLAN_OCVLAN_ICVLAN_PKT:
+ x->dvlan_ocvlan_icvlan_pkt++;
+ break;
+ case RX_DVLAN_OSVLAN_ISVLAN_PKT:
+ x->dvlan_osvlan_isvlan_pkt++;
+ break;
+ case RX_DVLAN_OSVLAN_ICVLAN_PKT:
+ x->dvlan_osvlan_icvlan_pkt++;
+ break;
+ case RX_DVLAN_OCVLAN_ISVLAN_PKT:
+ x->dvlan_ocvlan_icvlan_pkt++;
+ break;
+ default:
+ pr_err("Invalid L2 Packet type\n");
+ break;
+ }
+ }
+
+ /* L3/L4 Pkt type */
+ switch (p->rdes23.rx_wb_des23.layer34_pkt_type) {
+ case RX_NOT_IP_PKT:
+ x->not_ip_pkt++;
+ break;
+ case RX_IPV4_TCP_PKT:
+ x->ip4_tcp_pkt++;
+ break;
+ case RX_IPV4_UDP_PKT:
+ x->ip4_udp_pkt++;
+ break;
+ case RX_IPV4_ICMP_PKT:
+ x->ip4_icmp_pkt++;
+ break;
+ case RX_IPV4_UNKNOWN_PKT:
+ x->ip4_unknown_pkt++;
+ break;
+ case RX_IPV6_TCP_PKT:
+ x->ip6_tcp_pkt++;
+ break;
+ case RX_IPV6_UDP_PKT:
+ x->ip6_udp_pkt++;
+ break;
+ case RX_IPV6_ICMP_PKT:
+ x->ip6_icmp_pkt++;
+ break;
+ case RX_IPV6_UNKNOWN_PKT:
+ x->ip6_unknown_pkt++;
+ break;
+ default:
+ pr_err("Invalid L3/L4 Packet type\n");
+ break;
+ }
+
+ /* Filter */
+ if (p->rdes23.rx_wb_des23.vlan_filter_match)
+ x->vlan_filter_match++;
+
+ if (p->rdes23.rx_wb_des23.sa_filter_fail) {
+ status = -EINVAL;
+ x->sa_filter_fail++;
+ }
+ if (p->rdes23.rx_wb_des23.da_filter_fail) {
+ status = -EINVAL;
+ x->da_filter_fail++;
+ }
+ if (p->rdes23.rx_wb_des23.hash_filter_pass)
+ x->hash_filter_pass++;
+
+ if (p->rdes23.rx_wb_des23.l3_filter_match)
+ x->l3_filter_match++;
+
+ if (p->rdes23.rx_wb_des23.l4_filter_match)
+ x->l4_filter_match++;
+
+ return status;
+}
+
+/* Get own bit of context descriptor */
+static int sxgbe_get_rx_ctxt_owner(struct sxgbe_rx_ctxt_desc *p)
+{
+ return p->own_bit;
+}
+
+/* Set own bit for context descriptor */
+static void sxgbe_set_ctxt_rx_owner(struct sxgbe_rx_ctxt_desc *p)
+{
+ p->own_bit = 1;
+}
+
+
+/* Return the reception status looking at Context control information */
+static void sxgbe_rx_ctxt_wbstatus(struct sxgbe_rx_ctxt_desc *p,
+ struct sxgbe_extra_stats *x)
+{
+ if (p->tstamp_dropped)
+ x->timestamp_dropped++;
+
+ /* ptp */
+ if (p->ptp_msgtype == RX_NO_PTP)
+ x->rx_msg_type_no_ptp++;
+ else if (p->ptp_msgtype == RX_PTP_SYNC)
+ x->rx_ptp_type_sync++;
+ else if (p->ptp_msgtype == RX_PTP_FOLLOW_UP)
+ x->rx_ptp_type_follow_up++;
+ else if (p->ptp_msgtype == RX_PTP_DELAY_REQ)
+ x->rx_ptp_type_delay_req++;
+ else if (p->ptp_msgtype == RX_PTP_DELAY_RESP)
+ x->rx_ptp_type_delay_resp++;
+ else if (p->ptp_msgtype == RX_PTP_PDELAY_REQ)
+ x->rx_ptp_type_pdelay_req++;
+ else if (p->ptp_msgtype == RX_PTP_PDELAY_RESP)
+ x->rx_ptp_type_pdelay_resp++;
+ else if (p->ptp_msgtype == RX_PTP_PDELAY_FOLLOW_UP)
+ x->rx_ptp_type_pdelay_follow_up++;
+ else if (p->ptp_msgtype == RX_PTP_ANNOUNCE)
+ x->rx_ptp_announce++;
+ else if (p->ptp_msgtype == RX_PTP_MGMT)
+ x->rx_ptp_mgmt++;
+ else if (p->ptp_msgtype == RX_PTP_SIGNAL)
+ x->rx_ptp_signal++;
+ else if (p->ptp_msgtype == RX_PTP_RESV_MSG)
+ x->rx_ptp_resv_msg_type++;
+}
+
+/* Get rx timestamp status */
+static int sxgbe_get_rx_ctxt_tstamp_status(struct sxgbe_rx_ctxt_desc *p)
+{
+ if ((p->tstamp_hi == 0xffffffff) && (p->tstamp_lo == 0xffffffff)) {
+ pr_err("Time stamp corrupted\n");
+ return 0;
+ }
+
+ return p->tstamp_available;
+}
+
+
+static u64 sxgbe_get_rx_timestamp(struct sxgbe_rx_ctxt_desc *p)
+{
+ u64 ns;
+
+ ns = p->tstamp_lo;
+ ns |= ((u64)p->tstamp_hi) << 32;
+
+ return ns;
+}
+
+static const struct sxgbe_desc_ops desc_ops = {
+ .init_tx_desc = sxgbe_init_tx_desc,
+ .tx_desc_enable_tse = sxgbe_tx_desc_enable_tse,
+ .prepare_tx_desc = sxgbe_prepare_tx_desc,
+ .tx_vlanctl_desc = sxgbe_tx_vlanctl_desc,
+ .set_tx_owner = sxgbe_set_tx_owner,
+ .get_tx_owner = sxgbe_get_tx_owner,
+ .close_tx_desc = sxgbe_close_tx_desc,
+ .release_tx_desc = sxgbe_release_tx_desc,
+ .clear_tx_ic = sxgbe_clear_tx_ic,
+ .get_tx_ls = sxgbe_get_tx_ls,
+ .get_tx_len = sxgbe_get_tx_len,
+ .tx_enable_tstamp = sxgbe_tx_enable_tstamp,
+ .get_tx_timestamp_status = sxgbe_get_tx_timestamp_status,
+ .tx_ctxt_desc_set_ctxt = sxgbe_tx_ctxt_desc_set_ctxt,
+ .tx_ctxt_desc_set_owner = sxgbe_tx_ctxt_desc_set_owner,
+ .get_tx_ctxt_owner = sxgbe_tx_ctxt_desc_get_owner,
+ .tx_ctxt_desc_set_mss = sxgbe_tx_ctxt_desc_set_mss,
+ .tx_ctxt_desc_get_mss = sxgbe_tx_ctxt_desc_get_mss,
+ .tx_ctxt_desc_set_tcmssv = sxgbe_tx_ctxt_desc_set_tcmssv,
+ .tx_ctxt_desc_reset_ostc = sxgbe_tx_ctxt_desc_reset_ostc,
+ .tx_ctxt_desc_set_ivlantag = sxgbe_tx_ctxt_desc_set_ivlantag,
+ .tx_ctxt_desc_get_ivlantag = sxgbe_tx_ctxt_desc_get_ivlantag,
+ .tx_ctxt_desc_set_vlantag = sxgbe_tx_ctxt_desc_set_vlantag,
+ .tx_ctxt_desc_get_vlantag = sxgbe_tx_ctxt_desc_get_vlantag,
+ .tx_ctxt_set_tstamp = sxgbe_tx_ctxt_desc_set_tstamp,
+ .close_tx_ctxt_desc = sxgbe_tx_ctxt_desc_close,
+ .get_tx_ctxt_cde = sxgbe_tx_ctxt_desc_get_cde,
+ .init_rx_desc = sxgbe_init_rx_desc,
+ .get_rx_owner = sxgbe_get_rx_owner,
+ .set_rx_owner = sxgbe_set_rx_owner,
+ .get_rx_frame_len = sxgbe_get_rx_frame_len,
+ .get_rx_fd_status = sxgbe_get_rx_fd_status,
+ .get_rx_ld_status = sxgbe_get_rx_ld_status,
+ .rx_wbstatus = sxgbe_rx_wbstatus,
+ .get_rx_ctxt_owner = sxgbe_get_rx_ctxt_owner,
+ .set_rx_ctxt_owner = sxgbe_set_ctxt_rx_owner,
+ .rx_ctxt_wbstatus = sxgbe_rx_ctxt_wbstatus,
+ .get_rx_ctxt_tstamp_status = sxgbe_get_rx_ctxt_tstamp_status,
+ .get_timestamp = sxgbe_get_rx_timestamp,
+};
+
+const struct sxgbe_desc_ops *sxgbe_get_desc_ops(void)
+{
+ return &desc_ops;
+}
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.h
new file mode 100644
index 000000000000..838cb9fb0ea9
--- /dev/null
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.h
@@ -0,0 +1,298 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __SXGBE_DESC_H__
+#define __SXGBE_DESC_H__
+
+#define SXGBE_DESC_SIZE_BYTES 16
+
+/* forward declaration */
+struct sxgbe_extra_stats;
+
+/* Transmit checksum insertion control */
+enum tdes_csum_insertion {
+ cic_disabled = 0, /* Checksum Insertion Control */
+ cic_only_ip = 1, /* Only IP header */
+ /* IP header but pseudoheader is not calculated */
+ cic_no_pseudoheader = 2,
+ cic_full = 3, /* IP header and pseudoheader */
+};
+
+struct sxgbe_tx_norm_desc {
+ u64 tdes01; /* buf1 address */
+ union {
+ /* TX Read-Format Desc 2,3 */
+ struct {
+ /* TDES2 */
+ u32 buf1_size:14;
+ u32 vlan_tag_ctl:2;
+ u32 buf2_size:14;
+ u32 timestmp_enable:1;
+ u32 int_on_com:1;
+ /* TDES3 */
+ union {
+ u32 tcp_payload_len:18;
+ struct {
+ u32 total_pkt_len:15;
+ u32 reserved1:1;
+ u32 cksum_ctl:2;
+ } cksum_pktlen;
+ } tx_pkt_len;
+
+ u32 tse_bit:1;
+ u32 tcp_hdr_len:4;
+ u32 sa_insert_ctl:3;
+ u32 crc_pad_ctl:2;
+ u32 last_desc:1;
+ u32 first_desc:1;
+ u32 ctxt_bit:1;
+ u32 own_bit:1;
+ } tx_rd_des23;
+
+ /* tx write back Desc 2,3 */
+ struct {
+ /* WB TES2 */
+ u32 reserved1;
+ /* WB TES3 */
+ u32 reserved2:31;
+ u32 own_bit:1;
+ } tx_wb_des23;
+ } tdes23;
+};
+
+struct sxgbe_rx_norm_desc {
+ union {
+ u32 rdes0; /* buf1 address */
+ struct {
+ u32 out_vlan_tag:16;
+ u32 in_vlan_tag:16;
+ } wb_rx_des0;
+ } rd_wb_des0;
+
+ union {
+ u32 rdes1; /* buf2 address or buf1[63:32] */
+ u32 rss_hash; /* Write-back RX */
+ } rd_wb_des1;
+
+ union {
+ /* RX Read format Desc 2,3 */
+ struct{
+ /* RDES2 */
+ u32 buf2_addr;
+ /* RDES3 */
+ u32 buf2_hi_addr:30;
+ u32 int_on_com:1;
+ u32 own_bit:1;
+ } rx_rd_des23;
+
+ /* RX write back */
+ struct{
+ /* WB RDES2 */
+ u32 hdr_len:10;
+ u32 rdes2_reserved:2;
+ u32 elrd_val:1;
+ u32 iovt_sel:1;
+ u32 res_pkt:1;
+ u32 vlan_filter_match:1;
+ u32 sa_filter_fail:1;
+ u32 da_filter_fail:1;
+ u32 hash_filter_pass:1;
+ u32 macaddr_filter_match:8;
+ u32 l3_filter_match:1;
+ u32 l4_filter_match:1;
+ u32 l34_filter_num:3;
+
+ /* WB RDES3 */
+ u32 pkt_len:14;
+ u32 rdes3_reserved:1;
+ u32 err_summary:1;
+ u32 err_l2_type:4;
+ u32 layer34_pkt_type:4;
+ u32 no_coagulation_pkt:1;
+ u32 in_seq_pkt:1;
+ u32 rss_valid:1;
+ u32 context_des_avail:1;
+ u32 last_desc:1;
+ u32 first_desc:1;
+ u32 recv_context_desc:1;
+ u32 own_bit:1;
+ } rx_wb_des23;
+ } rdes23;
+};
+
+/* Context descriptor structure */
+struct sxgbe_tx_ctxt_desc {
+ u32 tstamp_lo;
+ u32 tstamp_hi;
+ u32 maxseg_size:15;
+ u32 reserved1:1;
+ u32 ivlan_tag:16;
+ u32 vlan_tag:16;
+ u32 vltag_valid:1;
+ u32 ivlan_tag_valid:1;
+ u32 ivlan_tag_ctl:2;
+ u32 reserved2:3;
+ u32 ctxt_desc_err:1;
+ u32 reserved3:2;
+ u32 ostc:1;
+ u32 tcmssv:1;
+ u32 reserved4:2;
+ u32 ctxt_bit:1;
+ u32 own_bit:1;
+};
+
+struct sxgbe_rx_ctxt_desc {
+ u32 tstamp_lo;
+ u32 tstamp_hi;
+ u32 reserved1;
+ u32 ptp_msgtype:4;
+ u32 tstamp_available:1;
+ u32 ptp_rsp_err:1;
+ u32 tstamp_dropped:1;
+ u32 reserved2:23;
+ u32 rx_ctxt_desc:1;
+ u32 own_bit:1;
+};
+
+struct sxgbe_desc_ops {
+ /* DMA TX descriptor ring initialization */
+ void (*init_tx_desc)(struct sxgbe_tx_norm_desc *p);
+
+ /* Invoked by the xmit function to prepare the tx descriptor */
+ void (*tx_desc_enable_tse)(struct sxgbe_tx_norm_desc *p, u8 is_tse,
+ u32 total_hdr_len, u32 tcp_hdr_len,
+ u32 tcp_payload_len);
+
+ /* Assign buffer lengths for descriptor */
+ void (*prepare_tx_desc)(struct sxgbe_tx_norm_desc *p, u8 is_fd,
+ int buf1_len, int pkt_len, int cksum);
+
+ /* Set VLAN control information */
+ void (*tx_vlanctl_desc)(struct sxgbe_tx_norm_desc *p, int vlan_ctl);
+
+ /* Set the owner of the descriptor */
+ void (*set_tx_owner)(struct sxgbe_tx_norm_desc *p);
+
+ /* Get the owner of the descriptor */
+ int (*get_tx_owner)(struct sxgbe_tx_norm_desc *p);
+
+ /* Invoked by the xmit function to close the tx descriptor */
+ void (*close_tx_desc)(struct sxgbe_tx_norm_desc *p);
+
+ /* Clean the tx descriptor as soon as the tx irq is received */
+ void (*release_tx_desc)(struct sxgbe_tx_norm_desc *p);
+
+ /* Clear interrupt on tx frame completion. When this bit is
+ * set an interrupt happens as soon as the frame is transmitted
+ */
+ void (*clear_tx_ic)(struct sxgbe_tx_norm_desc *p);
+
+ /* Last tx segment reports the transmit status */
+ int (*get_tx_ls)(struct sxgbe_tx_norm_desc *p);
+
+ /* Get the buffer size from the descriptor */
+ int (*get_tx_len)(struct sxgbe_tx_norm_desc *p);
+
+ /* Set tx timestamp enable bit */
+ void (*tx_enable_tstamp)(struct sxgbe_tx_norm_desc *p);
+
+ /* get tx timestamp status */
+ int (*get_tx_timestamp_status)(struct sxgbe_tx_norm_desc *p);
+
+ /* TX Context Descripto Specific */
+ void (*tx_ctxt_desc_set_ctxt)(struct sxgbe_tx_ctxt_desc *p);
+
+ /* Set the owner of the TX context descriptor */
+ void (*tx_ctxt_desc_set_owner)(struct sxgbe_tx_ctxt_desc *p);
+
+ /* Get the owner of the TX context descriptor */
+ int (*get_tx_ctxt_owner)(struct sxgbe_tx_ctxt_desc *p);
+
+ /* Set TX mss */
+ void (*tx_ctxt_desc_set_mss)(struct sxgbe_tx_ctxt_desc *p, u16 mss);
+
+ /* Set TX mss */
+ int (*tx_ctxt_desc_get_mss)(struct sxgbe_tx_ctxt_desc *p);
+
+ /* Set TX tcmssv */
+ void (*tx_ctxt_desc_set_tcmssv)(struct sxgbe_tx_ctxt_desc *p);
+
+ /* Reset TX ostc */
+ void (*tx_ctxt_desc_reset_ostc)(struct sxgbe_tx_ctxt_desc *p);
+
+ /* Set IVLAN information */
+ void (*tx_ctxt_desc_set_ivlantag)(struct sxgbe_tx_ctxt_desc *p,
+ int is_ivlanvalid, int ivlan_tag,
+ int ivlan_ctl);
+
+ /* Return IVLAN Tag */
+ int (*tx_ctxt_desc_get_ivlantag)(struct sxgbe_tx_ctxt_desc *p);
+
+ /* Set VLAN Tag */
+ void (*tx_ctxt_desc_set_vlantag)(struct sxgbe_tx_ctxt_desc *p,
+ int is_vlanvalid, int vlan_tag);
+
+ /* Return VLAN Tag */
+ int (*tx_ctxt_desc_get_vlantag)(struct sxgbe_tx_ctxt_desc *p);
+
+ /* Set Time stamp */
+ void (*tx_ctxt_set_tstamp)(struct sxgbe_tx_ctxt_desc *p,
+ u8 ostc_enable, u64 tstamp);
+
+ /* Close TX context descriptor */
+ void (*close_tx_ctxt_desc)(struct sxgbe_tx_ctxt_desc *p);
+
+ /* WB status of context descriptor */
+ int (*get_tx_ctxt_cde)(struct sxgbe_tx_ctxt_desc *p);
+
+ /* DMA RX descriptor ring initialization */
+ void (*init_rx_desc)(struct sxgbe_rx_norm_desc *p, int disable_rx_ic,
+ int mode, int end);
+
+ /* Get own bit */
+ int (*get_rx_owner)(struct sxgbe_rx_norm_desc *p);
+
+ /* Set own bit */
+ void (*set_rx_owner)(struct sxgbe_rx_norm_desc *p);
+
+ /* Get the receive frame size */
+ int (*get_rx_frame_len)(struct sxgbe_rx_norm_desc *p);
+
+ /* Return first Descriptor status */
+ int (*get_rx_fd_status)(struct sxgbe_rx_norm_desc *p);
+
+ /* Return first Descriptor status */
+ int (*get_rx_ld_status)(struct sxgbe_rx_norm_desc *p);
+
+ /* Return the reception status looking at the RDES1 */
+ int (*rx_wbstatus)(struct sxgbe_rx_norm_desc *p,
+ struct sxgbe_extra_stats *x, int *checksum);
+
+ /* Get own bit */
+ int (*get_rx_ctxt_owner)(struct sxgbe_rx_ctxt_desc *p);
+
+ /* Set own bit */
+ void (*set_rx_ctxt_owner)(struct sxgbe_rx_ctxt_desc *p);
+
+ /* Return the reception status looking at Context control information */
+ void (*rx_ctxt_wbstatus)(struct sxgbe_rx_ctxt_desc *p,
+ struct sxgbe_extra_stats *x);
+
+ /* Get rx timestamp status */
+ int (*get_rx_ctxt_tstamp_status)(struct sxgbe_rx_ctxt_desc *p);
+
+ /* Get timestamp value for rx, need to check this */
+ u64 (*get_timestamp)(struct sxgbe_rx_ctxt_desc *p);
+};
+
+const struct sxgbe_desc_ops *sxgbe_get_desc_ops(void);
+
+#endif /* __SXGBE_DESC_H__ */
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.c
new file mode 100644
index 000000000000..28f89c41d0cd
--- /dev/null
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.c
@@ -0,0 +1,382 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+
+#include "sxgbe_common.h"
+#include "sxgbe_dma.h"
+#include "sxgbe_reg.h"
+#include "sxgbe_desc.h"
+
+/* DMA core initialization */
+static int sxgbe_dma_init(void __iomem *ioaddr, int fix_burst, int burst_map)
+{
+ int retry_count = 10;
+ u32 reg_val;
+
+ /* reset the DMA */
+ writel(SXGBE_DMA_SOFT_RESET, ioaddr + SXGBE_DMA_MODE_REG);
+ while (retry_count--) {
+ if (!(readl(ioaddr + SXGBE_DMA_MODE_REG) &
+ SXGBE_DMA_SOFT_RESET))
+ break;
+ mdelay(10);
+ }
+
+ if (retry_count < 0)
+ return -EBUSY;
+
+ reg_val = readl(ioaddr + SXGBE_DMA_SYSBUS_MODE_REG);
+
+ /* if fix_burst = 0, Set UNDEF = 1 of DMA_Sys_Mode Register.
+ * if fix_burst = 1, Set UNDEF = 0 of DMA_Sys_Mode Register.
+ * burst_map is bitmap for BLEN[4, 8, 16, 32, 64, 128 and 256].
+ * Set burst_map irrespective of fix_burst value.
+ */
+ if (!fix_burst)
+ reg_val |= SXGBE_DMA_AXI_UNDEF_BURST;
+
+ /* write burst len map */
+ reg_val |= (burst_map << SXGBE_DMA_BLENMAP_LSHIFT);
+
+ writel(reg_val, ioaddr + SXGBE_DMA_SYSBUS_MODE_REG);
+
+ return 0;
+}
+
+static void sxgbe_dma_channel_init(void __iomem *ioaddr, int cha_num,
+ int fix_burst, int pbl, dma_addr_t dma_tx,
+ dma_addr_t dma_rx, int t_rsize, int r_rsize)
+{
+ u32 reg_val;
+ dma_addr_t dma_addr;
+
+ reg_val = readl(ioaddr + SXGBE_DMA_CHA_CTL_REG(cha_num));
+ /* set the pbl */
+ if (fix_burst) {
+ reg_val |= SXGBE_DMA_PBL_X8MODE;
+ writel(reg_val, ioaddr + SXGBE_DMA_CHA_CTL_REG(cha_num));
+ /* program the TX pbl */
+ reg_val = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cha_num));
+ reg_val |= (pbl << SXGBE_DMA_TXPBL_LSHIFT);
+ writel(reg_val, ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cha_num));
+ /* program the RX pbl */
+ reg_val = readl(ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cha_num));
+ reg_val |= (pbl << SXGBE_DMA_RXPBL_LSHIFT);
+ writel(reg_val, ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cha_num));
+ }
+
+ /* program desc registers */
+ writel(upper_32_bits(dma_tx),
+ ioaddr + SXGBE_DMA_CHA_TXDESC_HADD_REG(cha_num));
+ writel(lower_32_bits(dma_tx),
+ ioaddr + SXGBE_DMA_CHA_TXDESC_LADD_REG(cha_num));
+
+ writel(upper_32_bits(dma_rx),
+ ioaddr + SXGBE_DMA_CHA_RXDESC_HADD_REG(cha_num));
+ writel(lower_32_bits(dma_rx),
+ ioaddr + SXGBE_DMA_CHA_RXDESC_LADD_REG(cha_num));
+
+ /* program tail pointers */
+ /* assumption: upper 32 bits are constant and
+ * same as TX/RX desc list
+ */
+ dma_addr = dma_tx + ((t_rsize - 1) * SXGBE_DESC_SIZE_BYTES);
+ writel(lower_32_bits(dma_addr),
+ ioaddr + SXGBE_DMA_CHA_TXDESC_TAILPTR_REG(cha_num));
+
+ dma_addr = dma_rx + ((r_rsize - 1) * SXGBE_DESC_SIZE_BYTES);
+ writel(lower_32_bits(dma_addr),
+ ioaddr + SXGBE_DMA_CHA_RXDESC_LADD_REG(cha_num));
+ /* program the ring sizes */
+ writel(t_rsize - 1, ioaddr + SXGBE_DMA_CHA_TXDESC_RINGLEN_REG(cha_num));
+ writel(r_rsize - 1, ioaddr + SXGBE_DMA_CHA_RXDESC_RINGLEN_REG(cha_num));
+
+ /* Enable TX/RX interrupts */
+ writel(SXGBE_DMA_ENA_INT,
+ ioaddr + SXGBE_DMA_CHA_INT_ENABLE_REG(cha_num));
+}
+
+static void sxgbe_enable_dma_transmission(void __iomem *ioaddr, int cha_num)
+{
+ u32 tx_config;
+
+ tx_config = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cha_num));
+ tx_config |= SXGBE_TX_START_DMA;
+ writel(tx_config, ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cha_num));
+}
+
+static void sxgbe_enable_dma_irq(void __iomem *ioaddr, int dma_cnum)
+{
+ /* Enable TX/RX interrupts */
+ writel(SXGBE_DMA_ENA_INT,
+ ioaddr + SXGBE_DMA_CHA_INT_ENABLE_REG(dma_cnum));
+}
+
+static void sxgbe_disable_dma_irq(void __iomem *ioaddr, int dma_cnum)
+{
+ /* Disable TX/RX interrupts */
+ writel(0, ioaddr + SXGBE_DMA_CHA_INT_ENABLE_REG(dma_cnum));
+}
+
+static void sxgbe_dma_start_tx(void __iomem *ioaddr, int tchannels)
+{
+ int cnum;
+ u32 tx_ctl_reg;
+
+ for (cnum = 0; cnum < tchannels; cnum++) {
+ tx_ctl_reg = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cnum));
+ tx_ctl_reg |= SXGBE_TX_ENABLE;
+ writel(tx_ctl_reg,
+ ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cnum));
+ }
+}
+
+static void sxgbe_dma_start_tx_queue(void __iomem *ioaddr, int dma_cnum)
+{
+ u32 tx_ctl_reg;
+
+ tx_ctl_reg = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(dma_cnum));
+ tx_ctl_reg |= SXGBE_TX_ENABLE;
+ writel(tx_ctl_reg, ioaddr + SXGBE_DMA_CHA_TXCTL_REG(dma_cnum));
+}
+
+static void sxgbe_dma_stop_tx_queue(void __iomem *ioaddr, int dma_cnum)
+{
+ u32 tx_ctl_reg;
+
+ tx_ctl_reg = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(dma_cnum));
+ tx_ctl_reg &= ~(SXGBE_TX_ENABLE);
+ writel(tx_ctl_reg, ioaddr + SXGBE_DMA_CHA_TXCTL_REG(dma_cnum));
+}
+
+static void sxgbe_dma_stop_tx(void __iomem *ioaddr, int tchannels)
+{
+ int cnum;
+ u32 tx_ctl_reg;
+
+ for (cnum = 0; cnum < tchannels; cnum++) {
+ tx_ctl_reg = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cnum));
+ tx_ctl_reg &= ~(SXGBE_TX_ENABLE);
+ writel(tx_ctl_reg, ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cnum));
+ }
+}
+
+static void sxgbe_dma_start_rx(void __iomem *ioaddr, int rchannels)
+{
+ int cnum;
+ u32 rx_ctl_reg;
+
+ for (cnum = 0; cnum < rchannels; cnum++) {
+ rx_ctl_reg = readl(ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cnum));
+ rx_ctl_reg |= SXGBE_RX_ENABLE;
+ writel(rx_ctl_reg,
+ ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cnum));
+ }
+}
+
+static void sxgbe_dma_stop_rx(void __iomem *ioaddr, int rchannels)
+{
+ int cnum;
+ u32 rx_ctl_reg;
+
+ for (cnum = 0; cnum < rchannels; cnum++) {
+ rx_ctl_reg = readl(ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cnum));
+ rx_ctl_reg &= ~(SXGBE_RX_ENABLE);
+ writel(rx_ctl_reg, ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cnum));
+ }
+}
+
+static int sxgbe_tx_dma_int_status(void __iomem *ioaddr, int channel_no,
+ struct sxgbe_extra_stats *x)
+{
+ u32 int_status = readl(ioaddr + SXGBE_DMA_CHA_STATUS_REG(channel_no));
+ u32 clear_val = 0;
+ u32 ret_val = 0;
+
+ /* TX Normal Interrupt Summary */
+ if (likely(int_status & SXGBE_DMA_INT_STATUS_NIS)) {
+ x->normal_irq_n++;
+ if (int_status & SXGBE_DMA_INT_STATUS_TI) {
+ ret_val |= handle_tx;
+ x->tx_normal_irq_n++;
+ clear_val |= SXGBE_DMA_INT_STATUS_TI;
+ }
+
+ if (int_status & SXGBE_DMA_INT_STATUS_TBU) {
+ x->tx_underflow_irq++;
+ ret_val |= tx_bump_tc;
+ clear_val |= SXGBE_DMA_INT_STATUS_TBU;
+ }
+ } else if (unlikely(int_status & SXGBE_DMA_INT_STATUS_AIS)) {
+ /* TX Abnormal Interrupt Summary */
+ if (int_status & SXGBE_DMA_INT_STATUS_TPS) {
+ ret_val |= tx_hard_error;
+ clear_val |= SXGBE_DMA_INT_STATUS_TPS;
+ x->tx_process_stopped_irq++;
+ }
+
+ if (int_status & SXGBE_DMA_INT_STATUS_FBE) {
+ ret_val |= tx_hard_error;
+ x->fatal_bus_error_irq++;
+
+ /* Assumption: FBE bit is the combination of
+ * all the bus access erros and cleared when
+ * the respective error bits cleared
+ */
+
+ /* check for actual cause */
+ if (int_status & SXGBE_DMA_INT_STATUS_TEB0) {
+ x->tx_read_transfer_err++;
+ clear_val |= SXGBE_DMA_INT_STATUS_TEB0;
+ } else {
+ x->tx_write_transfer_err++;
+ }
+
+ if (int_status & SXGBE_DMA_INT_STATUS_TEB1) {
+ x->tx_desc_access_err++;
+ clear_val |= SXGBE_DMA_INT_STATUS_TEB1;
+ } else {
+ x->tx_buffer_access_err++;
+ }
+
+ if (int_status & SXGBE_DMA_INT_STATUS_TEB2) {
+ x->tx_data_transfer_err++;
+ clear_val |= SXGBE_DMA_INT_STATUS_TEB2;
+ }
+ }
+
+ /* context descriptor error */
+ if (int_status & SXGBE_DMA_INT_STATUS_CTXTERR) {
+ x->tx_ctxt_desc_err++;
+ clear_val |= SXGBE_DMA_INT_STATUS_CTXTERR;
+ }
+ }
+
+ /* clear the served bits */
+ writel(clear_val, ioaddr + SXGBE_DMA_CHA_STATUS_REG(channel_no));
+
+ return ret_val;
+}
+
+static int sxgbe_rx_dma_int_status(void __iomem *ioaddr, int channel_no,
+ struct sxgbe_extra_stats *x)
+{
+ u32 int_status = readl(ioaddr + SXGBE_DMA_CHA_STATUS_REG(channel_no));
+ u32 clear_val = 0;
+ u32 ret_val = 0;
+
+ /* RX Normal Interrupt Summary */
+ if (likely(int_status & SXGBE_DMA_INT_STATUS_NIS)) {
+ x->normal_irq_n++;
+ if (int_status & SXGBE_DMA_INT_STATUS_RI) {
+ ret_val |= handle_rx;
+ x->rx_normal_irq_n++;
+ clear_val |= SXGBE_DMA_INT_STATUS_RI;
+ }
+ } else if (unlikely(int_status & SXGBE_DMA_INT_STATUS_AIS)) {
+ /* RX Abnormal Interrupt Summary */
+ if (int_status & SXGBE_DMA_INT_STATUS_RBU) {
+ ret_val |= rx_bump_tc;
+ clear_val |= SXGBE_DMA_INT_STATUS_RBU;
+ x->rx_underflow_irq++;
+ }
+
+ if (int_status & SXGBE_DMA_INT_STATUS_RPS) {
+ ret_val |= rx_hard_error;
+ clear_val |= SXGBE_DMA_INT_STATUS_RPS;
+ x->rx_process_stopped_irq++;
+ }
+
+ if (int_status & SXGBE_DMA_INT_STATUS_FBE) {
+ ret_val |= rx_hard_error;
+ x->fatal_bus_error_irq++;
+
+ /* Assumption: FBE bit is the combination of
+ * all the bus access erros and cleared when
+ * the respective error bits cleared
+ */
+
+ /* check for actual cause */
+ if (int_status & SXGBE_DMA_INT_STATUS_REB0) {
+ x->rx_read_transfer_err++;
+ clear_val |= SXGBE_DMA_INT_STATUS_REB0;
+ } else {
+ x->rx_write_transfer_err++;
+ }
+
+ if (int_status & SXGBE_DMA_INT_STATUS_REB1) {
+ x->rx_desc_access_err++;
+ clear_val |= SXGBE_DMA_INT_STATUS_REB1;
+ } else {
+ x->rx_buffer_access_err++;
+ }
+
+ if (int_status & SXGBE_DMA_INT_STATUS_REB2) {
+ x->rx_data_transfer_err++;
+ clear_val |= SXGBE_DMA_INT_STATUS_REB2;
+ }
+ }
+ }
+
+ /* clear the served bits */
+ writel(clear_val, ioaddr + SXGBE_DMA_CHA_STATUS_REG(channel_no));
+
+ return ret_val;
+}
+
+/* Program the HW RX Watchdog */
+static void sxgbe_dma_rx_watchdog(void __iomem *ioaddr, u32 riwt)
+{
+ u32 que_num;
+
+ SXGBE_FOR_EACH_QUEUE(SXGBE_RX_QUEUES, que_num) {
+ writel(riwt,
+ ioaddr + SXGBE_DMA_CHA_INT_RXWATCHTMR_REG(que_num));
+ }
+}
+
+static void sxgbe_enable_tso(void __iomem *ioaddr, u8 chan_num)
+{
+ u32 ctrl;
+
+ ctrl = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(chan_num));
+ ctrl |= SXGBE_DMA_CHA_TXCTL_TSE_ENABLE;
+ writel(ctrl, ioaddr + SXGBE_DMA_CHA_TXCTL_REG(chan_num));
+}
+
+static const struct sxgbe_dma_ops sxgbe_dma_ops = {
+ .init = sxgbe_dma_init,
+ .cha_init = sxgbe_dma_channel_init,
+ .enable_dma_transmission = sxgbe_enable_dma_transmission,
+ .enable_dma_irq = sxgbe_enable_dma_irq,
+ .disable_dma_irq = sxgbe_disable_dma_irq,
+ .start_tx = sxgbe_dma_start_tx,
+ .start_tx_queue = sxgbe_dma_start_tx_queue,
+ .stop_tx = sxgbe_dma_stop_tx,
+ .stop_tx_queue = sxgbe_dma_stop_tx_queue,
+ .start_rx = sxgbe_dma_start_rx,
+ .stop_rx = sxgbe_dma_stop_rx,
+ .tx_dma_int_status = sxgbe_tx_dma_int_status,
+ .rx_dma_int_status = sxgbe_rx_dma_int_status,
+ .rx_watchdog = sxgbe_dma_rx_watchdog,
+ .enable_tso = sxgbe_enable_tso,
+};
+
+const struct sxgbe_dma_ops *sxgbe_get_dma_ops(void)
+{
+ return &sxgbe_dma_ops;
+}
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.h
new file mode 100644
index 000000000000..1607b54c9bb0
--- /dev/null
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.h
@@ -0,0 +1,50 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __SXGBE_DMA_H__
+#define __SXGBE_DMA_H__
+
+/* forward declaration */
+struct sxgbe_extra_stats;
+
+#define SXGBE_DMA_BLENMAP_LSHIFT 1
+#define SXGBE_DMA_TXPBL_LSHIFT 16
+#define SXGBE_DMA_RXPBL_LSHIFT 16
+#define DEFAULT_DMA_PBL 8
+
+struct sxgbe_dma_ops {
+ /* DMA core initialization */
+ int (*init)(void __iomem *ioaddr, int fix_burst, int burst_map);
+ void (*cha_init)(void __iomem *ioaddr, int cha_num, int fix_burst,
+ int pbl, dma_addr_t dma_tx, dma_addr_t dma_rx,
+ int t_rzie, int r_rsize);
+ void (*enable_dma_transmission)(void __iomem *ioaddr, int dma_cnum);
+ void (*enable_dma_irq)(void __iomem *ioaddr, int dma_cnum);
+ void (*disable_dma_irq)(void __iomem *ioaddr, int dma_cnum);
+ void (*start_tx)(void __iomem *ioaddr, int tchannels);
+ void (*start_tx_queue)(void __iomem *ioaddr, int dma_cnum);
+ void (*stop_tx)(void __iomem *ioaddr, int tchannels);
+ void (*stop_tx_queue)(void __iomem *ioaddr, int dma_cnum);
+ void (*start_rx)(void __iomem *ioaddr, int rchannels);
+ void (*stop_rx)(void __iomem *ioaddr, int rchannels);
+ int (*tx_dma_int_status)(void __iomem *ioaddr, int channel_no,
+ struct sxgbe_extra_stats *x);
+ int (*rx_dma_int_status)(void __iomem *ioaddr, int channel_no,
+ struct sxgbe_extra_stats *x);
+ /* Program the HW RX Watchdog */
+ void (*rx_watchdog)(void __iomem *ioaddr, u32 riwt);
+ /* Enable TSO for each DMA channel */
+ void (*enable_tso)(void __iomem *ioaddr, u8 chan_num);
+};
+
+const struct sxgbe_dma_ops *sxgbe_get_dma_ops(void);
+
+#endif /* __SXGBE_CORE_H__ */
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c
new file mode 100644
index 000000000000..0415fa50eeb7
--- /dev/null
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c
@@ -0,0 +1,524 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/net_tstamp.h>
+#include <linux/phy.h>
+#include <linux/ptp_clock_kernel.h>
+
+#include "sxgbe_common.h"
+#include "sxgbe_reg.h"
+#include "sxgbe_dma.h"
+
+struct sxgbe_stats {
+ char stat_string[ETH_GSTRING_LEN];
+ int sizeof_stat;
+ int stat_offset;
+};
+
+#define SXGBE_STAT(m) \
+{ \
+ #m, \
+ FIELD_SIZEOF(struct sxgbe_extra_stats, m), \
+ offsetof(struct sxgbe_priv_data, xstats.m) \
+}
+
+static const struct sxgbe_stats sxgbe_gstrings_stats[] = {
+ /* TX/RX IRQ events */
+ SXGBE_STAT(tx_process_stopped_irq),
+ SXGBE_STAT(tx_ctxt_desc_err),
+ SXGBE_STAT(tx_threshold),
+ SXGBE_STAT(rx_threshold),
+ SXGBE_STAT(tx_pkt_n),
+ SXGBE_STAT(rx_pkt_n),
+ SXGBE_STAT(normal_irq_n),
+ SXGBE_STAT(tx_normal_irq_n),
+ SXGBE_STAT(rx_normal_irq_n),
+ SXGBE_STAT(napi_poll),
+ SXGBE_STAT(tx_clean),
+ SXGBE_STAT(tx_reset_ic_bit),
+ SXGBE_STAT(rx_process_stopped_irq),
+ SXGBE_STAT(rx_underflow_irq),
+
+ /* Bus access errors */
+ SXGBE_STAT(fatal_bus_error_irq),
+ SXGBE_STAT(tx_read_transfer_err),
+ SXGBE_STAT(tx_write_transfer_err),
+ SXGBE_STAT(tx_desc_access_err),
+ SXGBE_STAT(tx_buffer_access_err),
+ SXGBE_STAT(tx_data_transfer_err),
+ SXGBE_STAT(rx_read_transfer_err),
+ SXGBE_STAT(rx_write_transfer_err),
+ SXGBE_STAT(rx_desc_access_err),
+ SXGBE_STAT(rx_buffer_access_err),
+ SXGBE_STAT(rx_data_transfer_err),
+
+ /* EEE-LPI stats */
+ SXGBE_STAT(tx_lpi_entry_n),
+ SXGBE_STAT(tx_lpi_exit_n),
+ SXGBE_STAT(rx_lpi_entry_n),
+ SXGBE_STAT(rx_lpi_exit_n),
+ SXGBE_STAT(eee_wakeup_error_n),
+
+ /* RX specific */
+ /* L2 error */
+ SXGBE_STAT(rx_code_gmii_err),
+ SXGBE_STAT(rx_watchdog_err),
+ SXGBE_STAT(rx_crc_err),
+ SXGBE_STAT(rx_gaint_pkt_err),
+ SXGBE_STAT(ip_hdr_err),
+ SXGBE_STAT(ip_payload_err),
+ SXGBE_STAT(overflow_error),
+
+ /* L2 Pkt type */
+ SXGBE_STAT(len_pkt),
+ SXGBE_STAT(mac_ctl_pkt),
+ SXGBE_STAT(dcb_ctl_pkt),
+ SXGBE_STAT(arp_pkt),
+ SXGBE_STAT(oam_pkt),
+ SXGBE_STAT(untag_okt),
+ SXGBE_STAT(other_pkt),
+ SXGBE_STAT(svlan_tag_pkt),
+ SXGBE_STAT(cvlan_tag_pkt),
+ SXGBE_STAT(dvlan_ocvlan_icvlan_pkt),
+ SXGBE_STAT(dvlan_osvlan_isvlan_pkt),
+ SXGBE_STAT(dvlan_osvlan_icvlan_pkt),
+ SXGBE_STAT(dvan_ocvlan_icvlan_pkt),
+
+ /* L3/L4 Pkt type */
+ SXGBE_STAT(not_ip_pkt),
+ SXGBE_STAT(ip4_tcp_pkt),
+ SXGBE_STAT(ip4_udp_pkt),
+ SXGBE_STAT(ip4_icmp_pkt),
+ SXGBE_STAT(ip4_unknown_pkt),
+ SXGBE_STAT(ip6_tcp_pkt),
+ SXGBE_STAT(ip6_udp_pkt),
+ SXGBE_STAT(ip6_icmp_pkt),
+ SXGBE_STAT(ip6_unknown_pkt),
+
+ /* Filter specific */
+ SXGBE_STAT(vlan_filter_match),
+ SXGBE_STAT(sa_filter_fail),
+ SXGBE_STAT(da_filter_fail),
+ SXGBE_STAT(hash_filter_pass),
+ SXGBE_STAT(l3_filter_match),
+ SXGBE_STAT(l4_filter_match),
+
+ /* RX context specific */
+ SXGBE_STAT(timestamp_dropped),
+ SXGBE_STAT(rx_msg_type_no_ptp),
+ SXGBE_STAT(rx_ptp_type_sync),
+ SXGBE_STAT(rx_ptp_type_follow_up),
+ SXGBE_STAT(rx_ptp_type_delay_req),
+ SXGBE_STAT(rx_ptp_type_delay_resp),
+ SXGBE_STAT(rx_ptp_type_pdelay_req),
+ SXGBE_STAT(rx_ptp_type_pdelay_resp),
+ SXGBE_STAT(rx_ptp_type_pdelay_follow_up),
+ SXGBE_STAT(rx_ptp_announce),
+ SXGBE_STAT(rx_ptp_mgmt),
+ SXGBE_STAT(rx_ptp_signal),
+ SXGBE_STAT(rx_ptp_resv_msg_type),
+};
+#define SXGBE_STATS_LEN ARRAY_SIZE(sxgbe_gstrings_stats)
+
+static int sxgbe_get_eee(struct net_device *dev,
+ struct ethtool_eee *edata)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+
+ if (!priv->hw_cap.eee)
+ return -EOPNOTSUPP;
+
+ edata->eee_enabled = priv->eee_enabled;
+ edata->eee_active = priv->eee_active;
+ edata->tx_lpi_timer = priv->tx_lpi_timer;
+
+ return phy_ethtool_get_eee(priv->phydev, edata);
+}
+
+static int sxgbe_set_eee(struct net_device *dev,
+ struct ethtool_eee *edata)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+
+ priv->eee_enabled = edata->eee_enabled;
+
+ if (!priv->eee_enabled) {
+ sxgbe_disable_eee_mode(priv);
+ } else {
+ /* We are asking for enabling the EEE but it is safe
+ * to verify all by invoking the eee_init function.
+ * In case of failure it will return an error.
+ */
+ priv->eee_enabled = sxgbe_eee_init(priv);
+ if (!priv->eee_enabled)
+ return -EOPNOTSUPP;
+
+ /* Do not change tx_lpi_timer in case of failure */
+ priv->tx_lpi_timer = edata->tx_lpi_timer;
+ }
+
+ return phy_ethtool_set_eee(priv->phydev, edata);
+}
+
+static void sxgbe_getdrvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+}
+
+static int sxgbe_getsettings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+
+ if (priv->phydev)
+ return phy_ethtool_gset(priv->phydev, cmd);
+
+ return -EOPNOTSUPP;
+}
+
+static int sxgbe_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+
+ if (priv->phydev)
+ return phy_ethtool_sset(priv->phydev, cmd);
+
+ return -EOPNOTSUPP;
+}
+
+static u32 sxgbe_getmsglevel(struct net_device *dev)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+ return priv->msg_enable;
+}
+
+static void sxgbe_setmsglevel(struct net_device *dev, u32 level)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+ priv->msg_enable = level;
+}
+
+static void sxgbe_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+ int i;
+ u8 *p = data;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < SXGBE_STATS_LEN; i++) {
+ memcpy(p, sxgbe_gstrings_stats[i].stat_string,
+ ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+}
+
+static int sxgbe_get_sset_count(struct net_device *netdev, int sset)
+{
+ int len;
+
+ switch (sset) {
+ case ETH_SS_STATS:
+ len = SXGBE_STATS_LEN;
+ return len;
+ default:
+ return -EINVAL;
+ }
+}
+
+static void sxgbe_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *dummy, u64 *data)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+ int i;
+ char *p;
+
+ if (priv->eee_enabled) {
+ int val = phy_get_eee_err(priv->phydev);
+
+ if (val)
+ priv->xstats.eee_wakeup_error_n = val;
+ }
+
+ for (i = 0; i < SXGBE_STATS_LEN; i++) {
+ p = (char *)priv + sxgbe_gstrings_stats[i].stat_offset;
+ data[i] = (sxgbe_gstrings_stats[i].sizeof_stat == sizeof(u64))
+ ? (*(u64 *)p) : (*(u32 *)p);
+ }
+}
+
+static void sxgbe_get_channels(struct net_device *dev,
+ struct ethtool_channels *channel)
+{
+ channel->max_rx = SXGBE_MAX_RX_CHANNELS;
+ channel->max_tx = SXGBE_MAX_TX_CHANNELS;
+ channel->rx_count = SXGBE_RX_QUEUES;
+ channel->tx_count = SXGBE_TX_QUEUES;
+}
+
+static u32 sxgbe_riwt2usec(u32 riwt, struct sxgbe_priv_data *priv)
+{
+ unsigned long clk = clk_get_rate(priv->sxgbe_clk);
+
+ if (!clk)
+ return 0;
+
+ return (riwt * 256) / (clk / 1000000);
+}
+
+static u32 sxgbe_usec2riwt(u32 usec, struct sxgbe_priv_data *priv)
+{
+ unsigned long clk = clk_get_rate(priv->sxgbe_clk);
+
+ if (!clk)
+ return 0;
+
+ return (usec * (clk / 1000000)) / 256;
+}
+
+static int sxgbe_get_coalesce(struct net_device *dev,
+ struct ethtool_coalesce *ec)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+
+ if (priv->use_riwt)
+ ec->rx_coalesce_usecs = sxgbe_riwt2usec(priv->rx_riwt, priv);
+
+ return 0;
+}
+
+static int sxgbe_set_coalesce(struct net_device *dev,
+ struct ethtool_coalesce *ec)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+ unsigned int rx_riwt;
+
+ if (!ec->rx_coalesce_usecs)
+ return -EINVAL;
+
+ rx_riwt = sxgbe_usec2riwt(ec->rx_coalesce_usecs, priv);
+
+ if ((rx_riwt > SXGBE_MAX_DMA_RIWT) || (rx_riwt < SXGBE_MIN_DMA_RIWT))
+ return -EINVAL;
+ else if (!priv->use_riwt)
+ return -EOPNOTSUPP;
+
+ priv->rx_riwt = rx_riwt;
+ priv->hw->dma->rx_watchdog(priv->ioaddr, priv->rx_riwt);
+
+ return 0;
+}
+
+static int sxgbe_get_rss_hash_opts(struct sxgbe_priv_data *priv,
+ struct ethtool_rxnfc *cmd)
+{
+ cmd->data = 0;
+
+ /* Report default options for RSS on sxgbe */
+ switch (cmd->flow_type) {
+ case TCP_V4_FLOW:
+ case UDP_V4_FLOW:
+ cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ case SCTP_V4_FLOW:
+ case AH_ESP_V4_FLOW:
+ case AH_V4_FLOW:
+ case ESP_V4_FLOW:
+ case IPV4_FLOW:
+ cmd->data |= RXH_IP_SRC | RXH_IP_DST;
+ break;
+ case TCP_V6_FLOW:
+ case UDP_V6_FLOW:
+ cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ case SCTP_V6_FLOW:
+ case AH_ESP_V6_FLOW:
+ case AH_V6_FLOW:
+ case ESP_V6_FLOW:
+ case IPV6_FLOW:
+ cmd->data |= RXH_IP_SRC | RXH_IP_DST;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int sxgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
+ u32 *rule_locs)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+ int ret = -EOPNOTSUPP;
+
+ switch (cmd->cmd) {
+ case ETHTOOL_GRXFH:
+ ret = sxgbe_get_rss_hash_opts(priv, cmd);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static int sxgbe_set_rss_hash_opt(struct sxgbe_priv_data *priv,
+ struct ethtool_rxnfc *cmd)
+{
+ u32 reg_val = 0;
+
+ /* RSS does not support anything other than hashing
+ * to queues on src and dst IPs and ports
+ */
+ if (cmd->data & ~(RXH_IP_SRC | RXH_IP_DST |
+ RXH_L4_B_0_1 | RXH_L4_B_2_3))
+ return -EINVAL;
+
+ switch (cmd->flow_type) {
+ case TCP_V4_FLOW:
+ case TCP_V6_FLOW:
+ if (!(cmd->data & RXH_IP_SRC) ||
+ !(cmd->data & RXH_IP_DST) ||
+ !(cmd->data & RXH_L4_B_0_1) ||
+ !(cmd->data & RXH_L4_B_2_3))
+ return -EINVAL;
+ reg_val = SXGBE_CORE_RSS_CTL_TCP4TE;
+ break;
+ case UDP_V4_FLOW:
+ case UDP_V6_FLOW:
+ if (!(cmd->data & RXH_IP_SRC) ||
+ !(cmd->data & RXH_IP_DST) ||
+ !(cmd->data & RXH_L4_B_0_1) ||
+ !(cmd->data & RXH_L4_B_2_3))
+ return -EINVAL;
+ reg_val = SXGBE_CORE_RSS_CTL_UDP4TE;
+ break;
+ case SCTP_V4_FLOW:
+ case AH_ESP_V4_FLOW:
+ case AH_V4_FLOW:
+ case ESP_V4_FLOW:
+ case AH_ESP_V6_FLOW:
+ case AH_V6_FLOW:
+ case ESP_V6_FLOW:
+ case SCTP_V6_FLOW:
+ case IPV4_FLOW:
+ case IPV6_FLOW:
+ if (!(cmd->data & RXH_IP_SRC) ||
+ !(cmd->data & RXH_IP_DST) ||
+ (cmd->data & RXH_L4_B_0_1) ||
+ (cmd->data & RXH_L4_B_2_3))
+ return -EINVAL;
+ reg_val = SXGBE_CORE_RSS_CTL_IP2TE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Read SXGBE RSS control register and update */
+ reg_val |= readl(priv->ioaddr + SXGBE_CORE_RSS_CTL_REG);
+ writel(reg_val, priv->ioaddr + SXGBE_CORE_RSS_CTL_REG);
+ readl(priv->ioaddr + SXGBE_CORE_RSS_CTL_REG);
+
+ return 0;
+}
+
+static int sxgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+ int ret = -EOPNOTSUPP;
+
+ switch (cmd->cmd) {
+ case ETHTOOL_SRXFH:
+ ret = sxgbe_set_rss_hash_opt(priv, cmd);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static void sxgbe_get_regs(struct net_device *dev,
+ struct ethtool_regs *regs, void *space)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+ u32 *reg_space = (u32 *)space;
+ int reg_offset;
+ int reg_ix = 0;
+ void __iomem *ioaddr = priv->ioaddr;
+
+ memset(reg_space, 0x0, REG_SPACE_SIZE);
+
+ /* MAC registers */
+ for (reg_offset = START_MAC_REG_OFFSET;
+ reg_offset <= MAX_MAC_REG_OFFSET; reg_offset += 4) {
+ reg_space[reg_ix] = readl(ioaddr + reg_offset);
+ reg_ix++;
+ }
+
+ /* MTL registers */
+ for (reg_offset = START_MTL_REG_OFFSET;
+ reg_offset <= MAX_MTL_REG_OFFSET; reg_offset += 4) {
+ reg_space[reg_ix] = readl(ioaddr + reg_offset);
+ reg_ix++;
+ }
+
+ /* DMA registers */
+ for (reg_offset = START_DMA_REG_OFFSET;
+ reg_offset <= MAX_DMA_REG_OFFSET; reg_offset += 4) {
+ reg_space[reg_ix] = readl(ioaddr + reg_offset);
+ reg_ix++;
+ }
+
+ BUG_ON(reg_ix * 4 > REG_SPACE_SIZE);
+}
+
+static int sxgbe_get_regs_len(struct net_device *dev)
+{
+ return REG_SPACE_SIZE;
+}
+
+static const struct ethtool_ops sxgbe_ethtool_ops = {
+ .get_drvinfo = sxgbe_getdrvinfo,
+ .get_settings = sxgbe_getsettings,
+ .set_settings = sxgbe_setsettings,
+ .get_msglevel = sxgbe_getmsglevel,
+ .set_msglevel = sxgbe_setmsglevel,
+ .get_link = ethtool_op_get_link,
+ .get_strings = sxgbe_get_strings,
+ .get_ethtool_stats = sxgbe_get_ethtool_stats,
+ .get_sset_count = sxgbe_get_sset_count,
+ .get_channels = sxgbe_get_channels,
+ .get_coalesce = sxgbe_get_coalesce,
+ .set_coalesce = sxgbe_set_coalesce,
+ .get_rxnfc = sxgbe_get_rxnfc,
+ .set_rxnfc = sxgbe_set_rxnfc,
+ .get_regs = sxgbe_get_regs,
+ .get_regs_len = sxgbe_get_regs_len,
+ .get_eee = sxgbe_get_eee,
+ .set_eee = sxgbe_set_eee,
+};
+
+void sxgbe_set_ethtool_ops(struct net_device *netdev)
+{
+ SET_ETHTOOL_OPS(netdev, &sxgbe_ethtool_ops);
+}
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
new file mode 100644
index 000000000000..a72688e8dc6c
--- /dev/null
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
@@ -0,0 +1,2317 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/crc32.h>
+#include <linux/dma-mapping.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/if.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/net_tstamp.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/prefetch.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/tcp.h>
+#include <linux/sxgbe_platform.h>
+
+#include "sxgbe_common.h"
+#include "sxgbe_desc.h"
+#include "sxgbe_dma.h"
+#include "sxgbe_mtl.h"
+#include "sxgbe_reg.h"
+
+#define SXGBE_ALIGN(x) L1_CACHE_ALIGN(x)
+#define JUMBO_LEN 9000
+
+/* Module parameters */
+#define TX_TIMEO 5000
+#define DMA_TX_SIZE 512
+#define DMA_RX_SIZE 1024
+#define TC_DEFAULT 64
+#define DMA_BUFFER_SIZE BUF_SIZE_2KiB
+/* The default timer value as per the sxgbe specification 1 sec(1000 ms) */
+#define SXGBE_DEFAULT_LPI_TIMER 1000
+
+static int debug = -1;
+static int eee_timer = SXGBE_DEFAULT_LPI_TIMER;
+
+module_param(eee_timer, int, S_IRUGO | S_IWUSR);
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
+ NETIF_MSG_LINK | NETIF_MSG_IFUP |
+ NETIF_MSG_IFDOWN | NETIF_MSG_TIMER);
+
+static irqreturn_t sxgbe_common_interrupt(int irq, void *dev_id);
+static irqreturn_t sxgbe_tx_interrupt(int irq, void *dev_id);
+static irqreturn_t sxgbe_rx_interrupt(int irq, void *dev_id);
+
+#define SXGBE_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x))
+
+#define SXGBE_LPI_TIMER(x) (jiffies + msecs_to_jiffies(x))
+
+/**
+ * sxgbe_verify_args - verify the driver parameters.
+ * Description: it verifies if some wrong parameter is passed to the driver.
+ * Note that wrong parameters are replaced with the default values.
+ */
+static void sxgbe_verify_args(void)
+{
+ if (unlikely(eee_timer < 0))
+ eee_timer = SXGBE_DEFAULT_LPI_TIMER;
+}
+
+static void sxgbe_enable_eee_mode(const struct sxgbe_priv_data *priv)
+{
+ /* Check and enter in LPI mode */
+ if (!priv->tx_path_in_lpi_mode)
+ priv->hw->mac->set_eee_mode(priv->ioaddr);
+}
+
+void sxgbe_disable_eee_mode(struct sxgbe_priv_data * const priv)
+{
+ /* Exit and disable EEE in case of we are are in LPI state. */
+ priv->hw->mac->reset_eee_mode(priv->ioaddr);
+ del_timer_sync(&priv->eee_ctrl_timer);
+ priv->tx_path_in_lpi_mode = false;
+}
+
+/**
+ * sxgbe_eee_ctrl_timer
+ * @arg : data hook
+ * Description:
+ * If there is no data transfer and if we are not in LPI state,
+ * then MAC Transmitter can be moved to LPI state.
+ */
+static void sxgbe_eee_ctrl_timer(unsigned long arg)
+{
+ struct sxgbe_priv_data *priv = (struct sxgbe_priv_data *)arg;
+
+ sxgbe_enable_eee_mode(priv);
+ mod_timer(&priv->eee_ctrl_timer, SXGBE_LPI_TIMER(eee_timer));
+}
+
+/**
+ * sxgbe_eee_init
+ * @priv: private device pointer
+ * Description:
+ * If the EEE support has been enabled while configuring the driver,
+ * if the GMAC actually supports the EEE (from the HW cap reg) and the
+ * phy can also manage EEE, so enable the LPI state and start the timer
+ * to verify if the tx path can enter in LPI state.
+ */
+bool sxgbe_eee_init(struct sxgbe_priv_data * const priv)
+{
+ bool ret = false;
+
+ /* MAC core supports the EEE feature. */
+ if (priv->hw_cap.eee) {
+ /* Check if the PHY supports EEE */
+ if (phy_init_eee(priv->phydev, 1))
+ return false;
+
+ priv->eee_active = 1;
+ init_timer(&priv->eee_ctrl_timer);
+ priv->eee_ctrl_timer.function = sxgbe_eee_ctrl_timer;
+ priv->eee_ctrl_timer.data = (unsigned long)priv;
+ priv->eee_ctrl_timer.expires = SXGBE_LPI_TIMER(eee_timer);
+ add_timer(&priv->eee_ctrl_timer);
+
+ priv->hw->mac->set_eee_timer(priv->ioaddr,
+ SXGBE_DEFAULT_LPI_TIMER,
+ priv->tx_lpi_timer);
+
+ pr_info("Energy-Efficient Ethernet initialized\n");
+
+ ret = true;
+ }
+
+ return ret;
+}
+
+static void sxgbe_eee_adjust(const struct sxgbe_priv_data *priv)
+{
+ /* When the EEE has been already initialised we have to
+ * modify the PLS bit in the LPI ctrl & status reg according
+ * to the PHY link status. For this reason.
+ */
+ if (priv->eee_enabled)
+ priv->hw->mac->set_eee_pls(priv->ioaddr, priv->phydev->link);
+}
+
+/**
+ * sxgbe_clk_csr_set - dynamically set the MDC clock
+ * @priv: driver private structure
+ * Description: this is to dynamically set the MDC clock according to the csr
+ * clock input.
+ */
+static void sxgbe_clk_csr_set(struct sxgbe_priv_data *priv)
+{
+ u32 clk_rate = clk_get_rate(priv->sxgbe_clk);
+
+ /* assign the proper divider, this will be used during
+ * mdio communication
+ */
+ if (clk_rate < SXGBE_CSR_F_150M)
+ priv->clk_csr = SXGBE_CSR_100_150M;
+ else if (clk_rate <= SXGBE_CSR_F_250M)
+ priv->clk_csr = SXGBE_CSR_150_250M;
+ else if (clk_rate <= SXGBE_CSR_F_300M)
+ priv->clk_csr = SXGBE_CSR_250_300M;
+ else if (clk_rate <= SXGBE_CSR_F_350M)
+ priv->clk_csr = SXGBE_CSR_300_350M;
+ else if (clk_rate <= SXGBE_CSR_F_400M)
+ priv->clk_csr = SXGBE_CSR_350_400M;
+ else if (clk_rate <= SXGBE_CSR_F_500M)
+ priv->clk_csr = SXGBE_CSR_400_500M;
+}
+
+/* minimum number of free TX descriptors required to wake up TX process */
+#define SXGBE_TX_THRESH(x) (x->dma_tx_size/4)
+
+static inline u32 sxgbe_tx_avail(struct sxgbe_tx_queue *queue, int tx_qsize)
+{
+ return queue->dirty_tx + tx_qsize - queue->cur_tx - 1;
+}
+
+/**
+ * sxgbe_adjust_link
+ * @dev: net device structure
+ * Description: it adjusts the link parameters.
+ */
+static void sxgbe_adjust_link(struct net_device *dev)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+ struct phy_device *phydev = priv->phydev;
+ u8 new_state = 0;
+ u8 speed = 0xff;
+
+ if (!phydev)
+ return;
+
+ /* SXGBE is not supporting auto-negotiation and
+ * half duplex mode. so, not handling duplex change
+ * in this function. only handling speed and link status
+ */
+ if (phydev->link) {
+ if (phydev->speed != priv->speed) {
+ new_state = 1;
+ switch (phydev->speed) {
+ case SPEED_10000:
+ speed = SXGBE_SPEED_10G;
+ break;
+ case SPEED_2500:
+ speed = SXGBE_SPEED_2_5G;
+ break;
+ case SPEED_1000:
+ speed = SXGBE_SPEED_1G;
+ break;
+ default:
+ netif_err(priv, link, dev,
+ "Speed (%d) not supported\n",
+ phydev->speed);
+ }
+
+ priv->speed = phydev->speed;
+ priv->hw->mac->set_speed(priv->ioaddr, speed);
+ }
+
+ if (!priv->oldlink) {
+ new_state = 1;
+ priv->oldlink = 1;
+ }
+ } else if (priv->oldlink) {
+ new_state = 1;
+ priv->oldlink = 0;
+ priv->speed = SPEED_UNKNOWN;
+ }
+
+ if (new_state & netif_msg_link(priv))
+ phy_print_status(phydev);
+
+ /* Alter the MAC settings for EEE */
+ sxgbe_eee_adjust(priv);
+}
+
+/**
+ * sxgbe_init_phy - PHY initialization
+ * @dev: net device structure
+ * Description: it initializes the driver's PHY state, and attaches the PHY
+ * to the mac driver.
+ * Return value:
+ * 0 on success
+ */
+static int sxgbe_init_phy(struct net_device *ndev)
+{
+ char phy_id_fmt[MII_BUS_ID_SIZE + 3];
+ char bus_id[MII_BUS_ID_SIZE];
+ struct phy_device *phydev;
+ struct sxgbe_priv_data *priv = netdev_priv(ndev);
+ int phy_iface = priv->plat->interface;
+
+ /* assign default link status */
+ priv->oldlink = 0;
+ priv->speed = SPEED_UNKNOWN;
+ priv->oldduplex = DUPLEX_UNKNOWN;
+
+ if (priv->plat->phy_bus_name)
+ snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x",
+ priv->plat->phy_bus_name, priv->plat->bus_id);
+ else
+ snprintf(bus_id, MII_BUS_ID_SIZE, "sxgbe-%x",
+ priv->plat->bus_id);
+
+ snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
+ priv->plat->phy_addr);
+ netdev_dbg(ndev, "%s: trying to attach to %s\n", __func__, phy_id_fmt);
+
+ phydev = phy_connect(ndev, phy_id_fmt, &sxgbe_adjust_link, phy_iface);
+
+ if (IS_ERR(phydev)) {
+ netdev_err(ndev, "Could not attach to PHY\n");
+ return PTR_ERR(phydev);
+ }
+
+ /* Stop Advertising 1000BASE Capability if interface is not GMII */
+ if ((phy_iface == PHY_INTERFACE_MODE_MII) ||
+ (phy_iface == PHY_INTERFACE_MODE_RMII))
+ phydev->advertising &= ~(SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full);
+ if (phydev->phy_id == 0) {
+ phy_disconnect(phydev);
+ return -ENODEV;
+ }
+
+ netdev_dbg(ndev, "%s: attached to PHY (UID 0x%x) Link = %d\n",
+ __func__, phydev->phy_id, phydev->link);
+
+ /* save phy device in private structure */
+ priv->phydev = phydev;
+
+ return 0;
+}
+
+/**
+ * sxgbe_clear_descriptors: clear descriptors
+ * @priv: driver private structure
+ * Description: this function is called to clear the tx and rx descriptors
+ * in case of both basic and extended descriptors are used.
+ */
+static void sxgbe_clear_descriptors(struct sxgbe_priv_data *priv)
+{
+ int i, j;
+ unsigned int txsize = priv->dma_tx_size;
+ unsigned int rxsize = priv->dma_rx_size;
+
+ /* Clear the Rx/Tx descriptors */
+ for (j = 0; j < SXGBE_RX_QUEUES; j++) {
+ for (i = 0; i < rxsize; i++)
+ priv->hw->desc->init_rx_desc(&priv->rxq[j]->dma_rx[i],
+ priv->use_riwt, priv->mode,
+ (i == rxsize - 1));
+ }
+
+ for (j = 0; j < SXGBE_TX_QUEUES; j++) {
+ for (i = 0; i < txsize; i++)
+ priv->hw->desc->init_tx_desc(&priv->txq[j]->dma_tx[i]);
+ }
+}
+
+static int sxgbe_init_rx_buffers(struct net_device *dev,
+ struct sxgbe_rx_norm_desc *p, int i,
+ unsigned int dma_buf_sz,
+ struct sxgbe_rx_queue *rx_ring)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+ struct sk_buff *skb;
+
+ skb = __netdev_alloc_skb_ip_align(dev, dma_buf_sz, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ rx_ring->rx_skbuff[i] = skb;
+ rx_ring->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,
+ dma_buf_sz, DMA_FROM_DEVICE);
+
+ if (dma_mapping_error(priv->device, rx_ring->rx_skbuff_dma[i])) {
+ netdev_err(dev, "%s: DMA mapping error\n", __func__);
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+ }
+
+ p->rdes23.rx_rd_des23.buf2_addr = rx_ring->rx_skbuff_dma[i];
+
+ return 0;
+}
+/**
+ * init_tx_ring - init the TX descriptor ring
+ * @dev: net device structure
+ * @tx_ring: ring to be intialised
+ * @tx_rsize: ring size
+ * Description: this function initializes the DMA TX descriptor
+ */
+static int init_tx_ring(struct device *dev, u8 queue_no,
+ struct sxgbe_tx_queue *tx_ring, int tx_rsize)
+{
+ /* TX ring is not allcoated */
+ if (!tx_ring) {
+ dev_err(dev, "No memory for TX queue of SXGBE\n");
+ return -ENOMEM;
+ }
+
+ /* allocate memory for TX descriptors */
+ tx_ring->dma_tx = dma_zalloc_coherent(dev,
+ tx_rsize * sizeof(struct sxgbe_tx_norm_desc),
+ &tx_ring->dma_tx_phy, GFP_KERNEL);
+ if (!tx_ring->dma_tx)
+ return -ENOMEM;
+
+ /* allocate memory for TX skbuff array */
+ tx_ring->tx_skbuff_dma = devm_kcalloc(dev, tx_rsize,
+ sizeof(dma_addr_t), GFP_KERNEL);
+ if (!tx_ring->tx_skbuff_dma)
+ goto dmamem_err;
+
+ tx_ring->tx_skbuff = devm_kcalloc(dev, tx_rsize,
+ sizeof(struct sk_buff *), GFP_KERNEL);
+
+ if (!tx_ring->tx_skbuff)
+ goto dmamem_err;
+
+ /* assign queue number */
+ tx_ring->queue_no = queue_no;
+
+ /* initalise counters */
+ tx_ring->dirty_tx = 0;
+ tx_ring->cur_tx = 0;
+
+ /* initalise TX queue lock */
+ spin_lock_init(&tx_ring->tx_lock);
+
+ return 0;
+
+dmamem_err:
+ dma_free_coherent(dev, tx_rsize * sizeof(struct sxgbe_tx_norm_desc),
+ tx_ring->dma_tx, tx_ring->dma_tx_phy);
+ return -ENOMEM;
+}
+
+/**
+ * free_rx_ring - free the RX descriptor ring
+ * @dev: net device structure
+ * @rx_ring: ring to be intialised
+ * @rx_rsize: ring size
+ * Description: this function initializes the DMA RX descriptor
+ */
+void free_rx_ring(struct device *dev, struct sxgbe_rx_queue *rx_ring,
+ int rx_rsize)
+{
+ dma_free_coherent(dev, rx_rsize * sizeof(struct sxgbe_rx_norm_desc),
+ rx_ring->dma_rx, rx_ring->dma_rx_phy);
+ kfree(rx_ring->rx_skbuff_dma);
+ kfree(rx_ring->rx_skbuff);
+}
+
+/**
+ * init_rx_ring - init the RX descriptor ring
+ * @dev: net device structure
+ * @rx_ring: ring to be intialised
+ * @rx_rsize: ring size
+ * Description: this function initializes the DMA RX descriptor
+ */
+static int init_rx_ring(struct net_device *dev, u8 queue_no,
+ struct sxgbe_rx_queue *rx_ring, int rx_rsize)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+ int desc_index;
+ unsigned int bfsize = 0;
+ unsigned int ret = 0;
+
+ /* Set the max buffer size according to the MTU. */
+ bfsize = ALIGN(dev->mtu + ETH_HLEN + ETH_FCS_LEN + NET_IP_ALIGN, 8);
+
+ netif_dbg(priv, probe, dev, "%s: bfsize %d\n", __func__, bfsize);
+
+ /* RX ring is not allcoated */
+ if (rx_ring == NULL) {
+ netdev_err(dev, "No memory for RX queue\n");
+ goto error;
+ }
+
+ /* assign queue number */
+ rx_ring->queue_no = queue_no;
+
+ /* allocate memory for RX descriptors */
+ rx_ring->dma_rx = dma_zalloc_coherent(priv->device,
+ rx_rsize * sizeof(struct sxgbe_rx_norm_desc),
+ &rx_ring->dma_rx_phy, GFP_KERNEL);
+
+ if (rx_ring->dma_rx == NULL)
+ goto error;
+
+ /* allocate memory for RX skbuff array */
+ rx_ring->rx_skbuff_dma = kmalloc_array(rx_rsize,
+ sizeof(dma_addr_t), GFP_KERNEL);
+ if (rx_ring->rx_skbuff_dma == NULL)
+ goto dmamem_err;
+
+ rx_ring->rx_skbuff = kmalloc_array(rx_rsize,
+ sizeof(struct sk_buff *), GFP_KERNEL);
+ if (rx_ring->rx_skbuff == NULL)
+ goto rxbuff_err;
+
+ /* initialise the buffers */
+ for (desc_index = 0; desc_index < rx_rsize; desc_index++) {
+ struct sxgbe_rx_norm_desc *p;
+ p = rx_ring->dma_rx + desc_index;
+ ret = sxgbe_init_rx_buffers(dev, p, desc_index,
+ bfsize, rx_ring);
+ if (ret)
+ goto err_init_rx_buffers;
+ }
+
+ /* initalise counters */
+ rx_ring->cur_rx = 0;
+ rx_ring->dirty_rx = (unsigned int)(desc_index - rx_rsize);
+ priv->dma_buf_sz = bfsize;
+
+ return 0;
+
+err_init_rx_buffers:
+ while (--desc_index >= 0)
+ free_rx_ring(priv->device, rx_ring, desc_index);
+ kfree(rx_ring->rx_skbuff);
+rxbuff_err:
+ kfree(rx_ring->rx_skbuff_dma);
+dmamem_err:
+ dma_free_coherent(priv->device,
+ rx_rsize * sizeof(struct sxgbe_rx_norm_desc),
+ rx_ring->dma_rx, rx_ring->dma_rx_phy);
+error:
+ return -ENOMEM;
+}
+/**
+ * free_tx_ring - free the TX descriptor ring
+ * @dev: net device structure
+ * @tx_ring: ring to be intialised
+ * @tx_rsize: ring size
+ * Description: this function initializes the DMA TX descriptor
+ */
+void free_tx_ring(struct device *dev, struct sxgbe_tx_queue *tx_ring,
+ int tx_rsize)
+{
+ dma_free_coherent(dev, tx_rsize * sizeof(struct sxgbe_tx_norm_desc),
+ tx_ring->dma_tx, tx_ring->dma_tx_phy);
+}
+
+/**
+ * init_dma_desc_rings - init the RX/TX descriptor rings
+ * @dev: net device structure
+ * Description: this function initializes the DMA RX/TX descriptors
+ * and allocates the socket buffers. It suppors the chained and ring
+ * modes.
+ */
+static int init_dma_desc_rings(struct net_device *netd)
+{
+ int queue_num, ret;
+ struct sxgbe_priv_data *priv = netdev_priv(netd);
+ int tx_rsize = priv->dma_tx_size;
+ int rx_rsize = priv->dma_rx_size;
+
+ /* Allocate memory for queue structures and TX descs */
+ SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
+ ret = init_tx_ring(priv->device, queue_num,
+ priv->txq[queue_num], tx_rsize);
+ if (ret) {
+ dev_err(&netd->dev, "TX DMA ring allocation failed!\n");
+ goto txalloc_err;
+ }
+
+ /* save private pointer in each ring this
+ * pointer is needed during cleaing TX queue
+ */
+ priv->txq[queue_num]->priv_ptr = priv;
+ }
+
+ /* Allocate memory for queue structures and RX descs */
+ SXGBE_FOR_EACH_QUEUE(SXGBE_RX_QUEUES, queue_num) {
+ ret = init_rx_ring(netd, queue_num,
+ priv->rxq[queue_num], rx_rsize);
+ if (ret) {
+ netdev_err(netd, "RX DMA ring allocation failed!!\n");
+ goto rxalloc_err;
+ }
+
+ /* save private pointer in each ring this
+ * pointer is needed during cleaing TX queue
+ */
+ priv->rxq[queue_num]->priv_ptr = priv;
+ }
+
+ sxgbe_clear_descriptors(priv);
+
+ return 0;
+
+txalloc_err:
+ while (queue_num--)
+ free_tx_ring(priv->device, priv->txq[queue_num], tx_rsize);
+ return ret;
+
+rxalloc_err:
+ while (queue_num--)
+ free_rx_ring(priv->device, priv->rxq[queue_num], rx_rsize);
+ return ret;
+}
+
+static void tx_free_ring_skbufs(struct sxgbe_tx_queue *txqueue)
+{
+ int dma_desc;
+ struct sxgbe_priv_data *priv = txqueue->priv_ptr;
+ int tx_rsize = priv->dma_tx_size;
+
+ for (dma_desc = 0; dma_desc < tx_rsize; dma_desc++) {
+ struct sxgbe_tx_norm_desc *tdesc = txqueue->dma_tx + dma_desc;
+
+ if (txqueue->tx_skbuff_dma[dma_desc])
+ dma_unmap_single(priv->device,
+ txqueue->tx_skbuff_dma[dma_desc],
+ priv->hw->desc->get_tx_len(tdesc),
+ DMA_TO_DEVICE);
+
+ dev_kfree_skb_any(txqueue->tx_skbuff[dma_desc]);
+ txqueue->tx_skbuff[dma_desc] = NULL;
+ txqueue->tx_skbuff_dma[dma_desc] = 0;
+ }
+}
+
+
+static void dma_free_tx_skbufs(struct sxgbe_priv_data *priv)
+{
+ int queue_num;
+
+ SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
+ struct sxgbe_tx_queue *tqueue = priv->txq[queue_num];
+ tx_free_ring_skbufs(tqueue);
+ }
+}
+
+static void free_dma_desc_resources(struct sxgbe_priv_data *priv)
+{
+ int queue_num;
+ int tx_rsize = priv->dma_tx_size;
+ int rx_rsize = priv->dma_rx_size;
+
+ /* Release the DMA TX buffers */
+ dma_free_tx_skbufs(priv);
+
+ /* Release the TX ring memory also */
+ SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
+ free_tx_ring(priv->device, priv->txq[queue_num], tx_rsize);
+ }
+
+ /* Release the RX ring memory also */
+ SXGBE_FOR_EACH_QUEUE(SXGBE_RX_QUEUES, queue_num) {
+ free_rx_ring(priv->device, priv->rxq[queue_num], rx_rsize);
+ }
+}
+
+static int txring_mem_alloc(struct sxgbe_priv_data *priv)
+{
+ int queue_num;
+
+ SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
+ priv->txq[queue_num] = devm_kmalloc(priv->device,
+ sizeof(struct sxgbe_tx_queue), GFP_KERNEL);
+ if (!priv->txq[queue_num])
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int rxring_mem_alloc(struct sxgbe_priv_data *priv)
+{
+ int queue_num;
+
+ SXGBE_FOR_EACH_QUEUE(SXGBE_RX_QUEUES, queue_num) {
+ priv->rxq[queue_num] = devm_kmalloc(priv->device,
+ sizeof(struct sxgbe_rx_queue), GFP_KERNEL);
+ if (!priv->rxq[queue_num])
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/**
+ * sxgbe_mtl_operation_mode - HW MTL operation mode
+ * @priv: driver private structure
+ * Description: it sets the MTL operation mode: tx/rx MTL thresholds
+ * or Store-And-Forward capability.
+ */
+static void sxgbe_mtl_operation_mode(struct sxgbe_priv_data *priv)
+{
+ int queue_num;
+
+ /* TX/RX threshold control */
+ if (likely(priv->plat->force_sf_dma_mode)) {
+ /* set TC mode for TX QUEUES */
+ SXGBE_FOR_EACH_QUEUE(priv->hw_cap.tx_mtl_queues, queue_num)
+ priv->hw->mtl->set_tx_mtl_mode(priv->ioaddr, queue_num,
+ SXGBE_MTL_SFMODE);
+ priv->tx_tc = SXGBE_MTL_SFMODE;
+
+ /* set TC mode for RX QUEUES */
+ SXGBE_FOR_EACH_QUEUE(priv->hw_cap.rx_mtl_queues, queue_num)
+ priv->hw->mtl->set_rx_mtl_mode(priv->ioaddr, queue_num,
+ SXGBE_MTL_SFMODE);
+ priv->rx_tc = SXGBE_MTL_SFMODE;
+ } else if (unlikely(priv->plat->force_thresh_dma_mode)) {
+ /* set TC mode for TX QUEUES */
+ SXGBE_FOR_EACH_QUEUE(priv->hw_cap.tx_mtl_queues, queue_num)
+ priv->hw->mtl->set_tx_mtl_mode(priv->ioaddr, queue_num,
+ priv->tx_tc);
+ /* set TC mode for RX QUEUES */
+ SXGBE_FOR_EACH_QUEUE(priv->hw_cap.rx_mtl_queues, queue_num)
+ priv->hw->mtl->set_rx_mtl_mode(priv->ioaddr, queue_num,
+ priv->rx_tc);
+ } else {
+ pr_err("ERROR: %s: Invalid TX threshold mode\n", __func__);
+ }
+}
+
+/**
+ * sxgbe_tx_queue_clean:
+ * @priv: driver private structure
+ * Description: it reclaims resources after transmission completes.
+ */
+static void sxgbe_tx_queue_clean(struct sxgbe_tx_queue *tqueue)
+{
+ struct sxgbe_priv_data *priv = tqueue->priv_ptr;
+ unsigned int tx_rsize = priv->dma_tx_size;
+ struct netdev_queue *dev_txq;
+ u8 queue_no = tqueue->queue_no;
+
+ dev_txq = netdev_get_tx_queue(priv->dev, queue_no);
+
+ spin_lock(&tqueue->tx_lock);
+
+ priv->xstats.tx_clean++;
+ while (tqueue->dirty_tx != tqueue->cur_tx) {
+ unsigned int entry = tqueue->dirty_tx % tx_rsize;
+ struct sk_buff *skb = tqueue->tx_skbuff[entry];
+ struct sxgbe_tx_norm_desc *p;
+
+ p = tqueue->dma_tx + entry;
+
+ /* Check if the descriptor is owned by the DMA. */
+ if (priv->hw->desc->get_tx_owner(p))
+ break;
+
+ if (netif_msg_tx_done(priv))
+ pr_debug("%s: curr %d, dirty %d\n",
+ __func__, tqueue->cur_tx, tqueue->dirty_tx);
+
+ if (likely(tqueue->tx_skbuff_dma[entry])) {
+ dma_unmap_single(priv->device,
+ tqueue->tx_skbuff_dma[entry],
+ priv->hw->desc->get_tx_len(p),
+ DMA_TO_DEVICE);
+ tqueue->tx_skbuff_dma[entry] = 0;
+ }
+
+ if (likely(skb)) {
+ dev_kfree_skb(skb);
+ tqueue->tx_skbuff[entry] = NULL;
+ }
+
+ priv->hw->desc->release_tx_desc(p);
+
+ tqueue->dirty_tx++;
+ }
+
+ /* wake up queue */
+ if (unlikely(netif_tx_queue_stopped(dev_txq) &&
+ sxgbe_tx_avail(tqueue, tx_rsize) > SXGBE_TX_THRESH(priv))) {
+ netif_tx_lock(priv->dev);
+ if (netif_tx_queue_stopped(dev_txq) &&
+ sxgbe_tx_avail(tqueue, tx_rsize) > SXGBE_TX_THRESH(priv)) {
+ if (netif_msg_tx_done(priv))
+ pr_debug("%s: restart transmit\n", __func__);
+ netif_tx_wake_queue(dev_txq);
+ }
+ netif_tx_unlock(priv->dev);
+ }
+
+ spin_unlock(&tqueue->tx_lock);
+}
+
+/**
+ * sxgbe_tx_clean:
+ * @priv: driver private structure
+ * Description: it reclaims resources after transmission completes.
+ */
+static void sxgbe_tx_all_clean(struct sxgbe_priv_data * const priv)
+{
+ u8 queue_num;
+
+ SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
+ struct sxgbe_tx_queue *tqueue = priv->txq[queue_num];
+
+ sxgbe_tx_queue_clean(tqueue);
+ }
+
+ if ((priv->eee_enabled) && (!priv->tx_path_in_lpi_mode)) {
+ sxgbe_enable_eee_mode(priv);
+ mod_timer(&priv->eee_ctrl_timer, SXGBE_LPI_TIMER(eee_timer));
+ }
+}
+
+/**
+ * sxgbe_restart_tx_queue: irq tx error mng function
+ * @priv: driver private structure
+ * Description: it cleans the descriptors and restarts the transmission
+ * in case of errors.
+ */
+static void sxgbe_restart_tx_queue(struct sxgbe_priv_data *priv, int queue_num)
+{
+ struct sxgbe_tx_queue *tx_ring = priv->txq[queue_num];
+ struct netdev_queue *dev_txq = netdev_get_tx_queue(priv->dev,
+ queue_num);
+
+ /* stop the queue */
+ netif_tx_stop_queue(dev_txq);
+
+ /* stop the tx dma */
+ priv->hw->dma->stop_tx_queue(priv->ioaddr, queue_num);
+
+ /* free the skbuffs of the ring */
+ tx_free_ring_skbufs(tx_ring);
+
+ /* initalise counters */
+ tx_ring->cur_tx = 0;
+ tx_ring->dirty_tx = 0;
+
+ /* start the tx dma */
+ priv->hw->dma->start_tx_queue(priv->ioaddr, queue_num);
+
+ priv->dev->stats.tx_errors++;
+
+ /* wakeup the queue */
+ netif_tx_wake_queue(dev_txq);
+}
+
+/**
+ * sxgbe_reset_all_tx_queues: irq tx error mng function
+ * @priv: driver private structure
+ * Description: it cleans all the descriptors and
+ * restarts the transmission on all queues in case of errors.
+ */
+static void sxgbe_reset_all_tx_queues(struct sxgbe_priv_data *priv)
+{
+ int queue_num;
+
+ /* On TX timeout of net device, resetting of all queues
+ * may not be proper way, revisit this later if needed
+ */
+ SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num)
+ sxgbe_restart_tx_queue(priv, queue_num);
+}
+
+/**
+ * sxgbe_get_hw_features: get XMAC capabilities from the HW cap. register.
+ * @priv: driver private structure
+ * Description:
+ * new GMAC chip generations have a new register to indicate the
+ * presence of the optional feature/functions.
+ * This can be also used to override the value passed through the
+ * platform and necessary for old MAC10/100 and GMAC chips.
+ */
+static int sxgbe_get_hw_features(struct sxgbe_priv_data * const priv)
+{
+ int rval = 0;
+ struct sxgbe_hw_features *features = &priv->hw_cap;
+
+ /* Read First Capability Register CAP[0] */
+ rval = priv->hw->mac->get_hw_feature(priv->ioaddr, 0);
+ if (rval) {
+ features->pmt_remote_wake_up =
+ SXGBE_HW_FEAT_PMT_TEMOTE_WOP(rval);
+ features->pmt_magic_frame = SXGBE_HW_FEAT_PMT_MAGIC_PKT(rval);
+ features->atime_stamp = SXGBE_HW_FEAT_IEEE1500_2008(rval);
+ features->tx_csum_offload =
+ SXGBE_HW_FEAT_TX_CSUM_OFFLOAD(rval);
+ features->rx_csum_offload =
+ SXGBE_HW_FEAT_RX_CSUM_OFFLOAD(rval);
+ features->multi_macaddr = SXGBE_HW_FEAT_MACADDR_COUNT(rval);
+ features->tstamp_srcselect = SXGBE_HW_FEAT_TSTMAP_SRC(rval);
+ features->sa_vlan_insert = SXGBE_HW_FEAT_SRCADDR_VLAN(rval);
+ features->eee = SXGBE_HW_FEAT_EEE(rval);
+ }
+
+ /* Read First Capability Register CAP[1] */
+ rval = priv->hw->mac->get_hw_feature(priv->ioaddr, 1);
+ if (rval) {
+ features->rxfifo_size = SXGBE_HW_FEAT_RX_FIFO_SIZE(rval);
+ features->txfifo_size = SXGBE_HW_FEAT_TX_FIFO_SIZE(rval);
+ features->atstmap_hword = SXGBE_HW_FEAT_TX_FIFO_SIZE(rval);
+ features->dcb_enable = SXGBE_HW_FEAT_DCB(rval);
+ features->splithead_enable = SXGBE_HW_FEAT_SPLIT_HDR(rval);
+ features->tcpseg_offload = SXGBE_HW_FEAT_TSO(rval);
+ features->debug_mem = SXGBE_HW_FEAT_DEBUG_MEM_IFACE(rval);
+ features->rss_enable = SXGBE_HW_FEAT_RSS(rval);
+ features->hash_tsize = SXGBE_HW_FEAT_HASH_TABLE_SIZE(rval);
+ features->l3l4_filer_size = SXGBE_HW_FEAT_L3L4_FILTER_NUM(rval);
+ }
+
+ /* Read First Capability Register CAP[2] */
+ rval = priv->hw->mac->get_hw_feature(priv->ioaddr, 2);
+ if (rval) {
+ features->rx_mtl_queues = SXGBE_HW_FEAT_RX_MTL_QUEUES(rval);
+ features->tx_mtl_queues = SXGBE_HW_FEAT_TX_MTL_QUEUES(rval);
+ features->rx_dma_channels = SXGBE_HW_FEAT_RX_DMA_CHANNELS(rval);
+ features->tx_dma_channels = SXGBE_HW_FEAT_TX_DMA_CHANNELS(rval);
+ features->pps_output_count = SXGBE_HW_FEAT_PPS_OUTPUTS(rval);
+ features->aux_input_count = SXGBE_HW_FEAT_AUX_SNAPSHOTS(rval);
+ }
+
+ return rval;
+}
+
+/**
+ * sxgbe_check_ether_addr: check if the MAC addr is valid
+ * @priv: driver private structure
+ * Description:
+ * it is to verify if the MAC address is valid, in case of failures it
+ * generates a random MAC address
+ */
+static void sxgbe_check_ether_addr(struct sxgbe_priv_data *priv)
+{
+ if (!is_valid_ether_addr(priv->dev->dev_addr)) {
+ priv->hw->mac->get_umac_addr((void __iomem *)
+ priv->ioaddr,
+ priv->dev->dev_addr, 0);
+ if (!is_valid_ether_addr(priv->dev->dev_addr))
+ eth_hw_addr_random(priv->dev);
+ }
+ dev_info(priv->device, "device MAC address %pM\n",
+ priv->dev->dev_addr);
+}
+
+/**
+ * sxgbe_init_dma_engine: DMA init.
+ * @priv: driver private structure
+ * Description:
+ * It inits the DMA invoking the specific SXGBE callback.
+ * Some DMA parameters can be passed from the platform;
+ * in case of these are not passed a default is kept for the MAC or GMAC.
+ */
+static int sxgbe_init_dma_engine(struct sxgbe_priv_data *priv)
+{
+ int pbl = DEFAULT_DMA_PBL, fixed_burst = 0, burst_map = 0;
+ int queue_num;
+
+ if (priv->plat->dma_cfg) {
+ pbl = priv->plat->dma_cfg->pbl;
+ fixed_burst = priv->plat->dma_cfg->fixed_burst;
+ burst_map = priv->plat->dma_cfg->burst_map;
+ }
+
+ SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num)
+ priv->hw->dma->cha_init(priv->ioaddr, queue_num,
+ fixed_burst, pbl,
+ (priv->txq[queue_num])->dma_tx_phy,
+ (priv->rxq[queue_num])->dma_rx_phy,
+ priv->dma_tx_size, priv->dma_rx_size);
+
+ return priv->hw->dma->init(priv->ioaddr, fixed_burst, burst_map);
+}
+
+/**
+ * sxgbe_init_mtl_engine: MTL init.
+ * @priv: driver private structure
+ * Description:
+ * It inits the MTL invoking the specific SXGBE callback.
+ */
+static void sxgbe_init_mtl_engine(struct sxgbe_priv_data *priv)
+{
+ int queue_num;
+
+ SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
+ priv->hw->mtl->mtl_set_txfifosize(priv->ioaddr, queue_num,
+ priv->hw_cap.tx_mtl_qsize);
+ priv->hw->mtl->mtl_enable_txqueue(priv->ioaddr, queue_num);
+ }
+}
+
+/**
+ * sxgbe_disable_mtl_engine: MTL disable.
+ * @priv: driver private structure
+ * Description:
+ * It disables the MTL queues by invoking the specific SXGBE callback.
+ */
+static void sxgbe_disable_mtl_engine(struct sxgbe_priv_data *priv)
+{
+ int queue_num;
+
+ SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num)
+ priv->hw->mtl->mtl_disable_txqueue(priv->ioaddr, queue_num);
+}
+
+
+/**
+ * sxgbe_tx_timer: mitigation sw timer for tx.
+ * @data: data pointer
+ * Description:
+ * This is the timer handler to directly invoke the sxgbe_tx_clean.
+ */
+static void sxgbe_tx_timer(unsigned long data)
+{
+ struct sxgbe_tx_queue *p = (struct sxgbe_tx_queue *)data;
+ sxgbe_tx_queue_clean(p);
+}
+
+/**
+ * sxgbe_init_tx_coalesce: init tx mitigation options.
+ * @priv: driver private structure
+ * Description:
+ * This inits the transmit coalesce parameters: i.e. timer rate,
+ * timer handler and default threshold used for enabling the
+ * interrupt on completion bit.
+ */
+static void sxgbe_tx_init_coalesce(struct sxgbe_priv_data *priv)
+{
+ u8 queue_num;
+
+ SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
+ struct sxgbe_tx_queue *p = priv->txq[queue_num];
+ p->tx_coal_frames = SXGBE_TX_FRAMES;
+ p->tx_coal_timer = SXGBE_COAL_TX_TIMER;
+ init_timer(&p->txtimer);
+ p->txtimer.expires = SXGBE_COAL_TIMER(p->tx_coal_timer);
+ p->txtimer.data = (unsigned long)&priv->txq[queue_num];
+ p->txtimer.function = sxgbe_tx_timer;
+ add_timer(&p->txtimer);
+ }
+}
+
+static void sxgbe_tx_del_timer(struct sxgbe_priv_data *priv)
+{
+ u8 queue_num;
+
+ SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
+ struct sxgbe_tx_queue *p = priv->txq[queue_num];
+ del_timer_sync(&p->txtimer);
+ }
+}
+
+/**
+ * sxgbe_open - open entry point of the driver
+ * @dev : pointer to the device structure.
+ * Description:
+ * This function is the open entry point of the driver.
+ * Return value:
+ * 0 on success and an appropriate (-)ve integer as defined in errno.h
+ * file on failure.
+ */
+static int sxgbe_open(struct net_device *dev)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+ int ret, queue_num;
+
+ clk_prepare_enable(priv->sxgbe_clk);
+
+ sxgbe_check_ether_addr(priv);
+
+ /* Init the phy */
+ ret = sxgbe_init_phy(dev);
+ if (ret) {
+ netdev_err(dev, "%s: Cannot attach to PHY (error: %d)\n",
+ __func__, ret);
+ goto phy_error;
+ }
+
+ /* Create and initialize the TX/RX descriptors chains. */
+ priv->dma_tx_size = SXGBE_ALIGN(DMA_TX_SIZE);
+ priv->dma_rx_size = SXGBE_ALIGN(DMA_RX_SIZE);
+ priv->dma_buf_sz = SXGBE_ALIGN(DMA_BUFFER_SIZE);
+ priv->tx_tc = TC_DEFAULT;
+ priv->rx_tc = TC_DEFAULT;
+ init_dma_desc_rings(dev);
+
+ /* DMA initialization and SW reset */
+ ret = sxgbe_init_dma_engine(priv);
+ if (ret < 0) {
+ netdev_err(dev, "%s: DMA initialization failed\n", __func__);
+ goto init_error;
+ }
+
+ /* MTL initialization */
+ sxgbe_init_mtl_engine(priv);
+
+ /* Copy the MAC addr into the HW */
+ priv->hw->mac->set_umac_addr(priv->ioaddr, dev->dev_addr, 0);
+
+ /* Initialize the MAC Core */
+ priv->hw->mac->core_init(priv->ioaddr);
+
+ /* Request the IRQ lines */
+ ret = devm_request_irq(priv->device, priv->irq, sxgbe_common_interrupt,
+ IRQF_SHARED, dev->name, dev);
+ if (unlikely(ret < 0)) {
+ netdev_err(dev, "%s: ERROR: allocating the IRQ %d (error: %d)\n",
+ __func__, priv->irq, ret);
+ goto init_error;
+ }
+
+ /* If the LPI irq is different from the mac irq
+ * register a dedicated handler
+ */
+ if (priv->lpi_irq != dev->irq) {
+ ret = devm_request_irq(priv->device, priv->lpi_irq,
+ sxgbe_common_interrupt,
+ IRQF_SHARED, dev->name, dev);
+ if (unlikely(ret < 0)) {
+ netdev_err(dev, "%s: ERROR: allocating the LPI IRQ %d (%d)\n",
+ __func__, priv->lpi_irq, ret);
+ goto init_error;
+ }
+ }
+
+ /* Request TX DMA irq lines */
+ SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
+ ret = devm_request_irq(priv->device,
+ (priv->txq[queue_num])->irq_no,
+ sxgbe_tx_interrupt, 0,
+ dev->name, priv->txq[queue_num]);
+ if (unlikely(ret < 0)) {
+ netdev_err(dev, "%s: ERROR: allocating TX IRQ %d (error: %d)\n",
+ __func__, priv->irq, ret);
+ goto init_error;
+ }
+ }
+
+ /* Request RX DMA irq lines */
+ SXGBE_FOR_EACH_QUEUE(SXGBE_RX_QUEUES, queue_num) {
+ ret = devm_request_irq(priv->device,
+ (priv->rxq[queue_num])->irq_no,
+ sxgbe_rx_interrupt, 0,
+ dev->name, priv->rxq[queue_num]);
+ if (unlikely(ret < 0)) {
+ netdev_err(dev, "%s: ERROR: allocating TX IRQ %d (error: %d)\n",
+ __func__, priv->irq, ret);
+ goto init_error;
+ }
+ }
+
+ /* Enable the MAC Rx/Tx */
+ priv->hw->mac->enable_tx(priv->ioaddr, true);
+ priv->hw->mac->enable_rx(priv->ioaddr, true);
+
+ /* Set the HW DMA mode and the COE */
+ sxgbe_mtl_operation_mode(priv);
+
+ /* Extra statistics */
+ memset(&priv->xstats, 0, sizeof(struct sxgbe_extra_stats));
+
+ priv->xstats.tx_threshold = priv->tx_tc;
+ priv->xstats.rx_threshold = priv->rx_tc;
+
+ /* Start the ball rolling... */
+ netdev_dbg(dev, "DMA RX/TX processes started...\n");
+ priv->hw->dma->start_tx(priv->ioaddr, SXGBE_TX_QUEUES);
+ priv->hw->dma->start_rx(priv->ioaddr, SXGBE_RX_QUEUES);
+
+ if (priv->phydev)
+ phy_start(priv->phydev);
+
+ /* initalise TX coalesce parameters */
+ sxgbe_tx_init_coalesce(priv);
+
+ if ((priv->use_riwt) && (priv->hw->dma->rx_watchdog)) {
+ priv->rx_riwt = SXGBE_MAX_DMA_RIWT;
+ priv->hw->dma->rx_watchdog(priv->ioaddr, SXGBE_MAX_DMA_RIWT);
+ }
+
+ priv->tx_lpi_timer = SXGBE_DEFAULT_LPI_TIMER;
+ priv->eee_enabled = sxgbe_eee_init(priv);
+
+ napi_enable(&priv->napi);
+ netif_start_queue(dev);
+
+ return 0;
+
+init_error:
+ free_dma_desc_resources(priv);
+ if (priv->phydev)
+ phy_disconnect(priv->phydev);
+phy_error:
+ clk_disable_unprepare(priv->sxgbe_clk);
+
+ return ret;
+}
+
+/**
+ * sxgbe_release - close entry point of the driver
+ * @dev : device pointer.
+ * Description:
+ * This is the stop entry point of the driver.
+ */
+static int sxgbe_release(struct net_device *dev)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+
+ if (priv->eee_enabled)
+ del_timer_sync(&priv->eee_ctrl_timer);
+
+ /* Stop and disconnect the PHY */
+ if (priv->phydev) {
+ phy_stop(priv->phydev);
+ phy_disconnect(priv->phydev);
+ priv->phydev = NULL;
+ }
+
+ netif_tx_stop_all_queues(dev);
+
+ napi_disable(&priv->napi);
+
+ /* delete TX timers */
+ sxgbe_tx_del_timer(priv);
+
+ /* Stop TX/RX DMA and clear the descriptors */
+ priv->hw->dma->stop_tx(priv->ioaddr, SXGBE_TX_QUEUES);
+ priv->hw->dma->stop_rx(priv->ioaddr, SXGBE_RX_QUEUES);
+
+ /* disable MTL queue */
+ sxgbe_disable_mtl_engine(priv);
+
+ /* Release and free the Rx/Tx resources */
+ free_dma_desc_resources(priv);
+
+ /* Disable the MAC Rx/Tx */
+ priv->hw->mac->enable_tx(priv->ioaddr, false);
+ priv->hw->mac->enable_rx(priv->ioaddr, false);
+
+ clk_disable_unprepare(priv->sxgbe_clk);
+
+ return 0;
+}
+
+/* Prepare first Tx descriptor for doing TSO operation */
+void sxgbe_tso_prepare(struct sxgbe_priv_data *priv,
+ struct sxgbe_tx_norm_desc *first_desc,
+ struct sk_buff *skb)
+{
+ unsigned int total_hdr_len, tcp_hdr_len;
+
+ /* Write first Tx descriptor with appropriate value */
+ tcp_hdr_len = tcp_hdrlen(skb);
+ total_hdr_len = skb_transport_offset(skb) + tcp_hdr_len;
+
+ first_desc->tdes01 = dma_map_single(priv->device, skb->data,
+ total_hdr_len, DMA_TO_DEVICE);
+ if (dma_mapping_error(priv->device, first_desc->tdes01))
+ pr_err("%s: TX dma mapping failed!!\n", __func__);
+
+ first_desc->tdes23.tx_rd_des23.first_desc = 1;
+ priv->hw->desc->tx_desc_enable_tse(first_desc, 1, total_hdr_len,
+ tcp_hdr_len,
+ skb->len - total_hdr_len);
+}
+
+/**
+ * sxgbe_xmit: Tx entry point of the driver
+ * @skb : the socket buffer
+ * @dev : device pointer
+ * Description : this is the tx entry point of the driver.
+ * It programs the chain or the ring and supports oversized frames
+ * and SG feature.
+ */
+static netdev_tx_t sxgbe_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ unsigned int entry, frag_num;
+ int cksum_flag = 0;
+ struct netdev_queue *dev_txq;
+ unsigned txq_index = skb_get_queue_mapping(skb);
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+ unsigned int tx_rsize = priv->dma_tx_size;
+ struct sxgbe_tx_queue *tqueue = priv->txq[txq_index];
+ struct sxgbe_tx_norm_desc *tx_desc, *first_desc;
+ struct sxgbe_tx_ctxt_desc *ctxt_desc = NULL;
+ int nr_frags = skb_shinfo(skb)->nr_frags;
+ int no_pagedlen = skb_headlen(skb);
+ int is_jumbo = 0;
+ u16 cur_mss = skb_shinfo(skb)->gso_size;
+ u32 ctxt_desc_req = 0;
+
+ /* get the TX queue handle */
+ dev_txq = netdev_get_tx_queue(dev, txq_index);
+
+ if (unlikely(skb_is_gso(skb) && tqueue->prev_mss != cur_mss))
+ ctxt_desc_req = 1;
+
+ if (unlikely(vlan_tx_tag_present(skb) ||
+ ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+ tqueue->hwts_tx_en)))
+ ctxt_desc_req = 1;
+
+ /* get the spinlock */
+ spin_lock(&tqueue->tx_lock);
+
+ if (priv->tx_path_in_lpi_mode)
+ sxgbe_disable_eee_mode(priv);
+
+ if (unlikely(sxgbe_tx_avail(tqueue, tx_rsize) < nr_frags + 1)) {
+ if (!netif_tx_queue_stopped(dev_txq)) {
+ netif_tx_stop_queue(dev_txq);
+ netdev_err(dev, "%s: Tx Ring is full when %d queue is awake\n",
+ __func__, txq_index);
+ }
+ /* release the spin lock in case of BUSY */
+ spin_unlock(&tqueue->tx_lock);
+ return NETDEV_TX_BUSY;
+ }
+
+ entry = tqueue->cur_tx % tx_rsize;
+ tx_desc = tqueue->dma_tx + entry;
+
+ first_desc = tx_desc;
+ if (ctxt_desc_req)
+ ctxt_desc = (struct sxgbe_tx_ctxt_desc *)first_desc;
+
+ /* save the skb address */
+ tqueue->tx_skbuff[entry] = skb;
+
+ if (!is_jumbo) {
+ if (likely(skb_is_gso(skb))) {
+ /* TSO support */
+ if (unlikely(tqueue->prev_mss != cur_mss)) {
+ priv->hw->desc->tx_ctxt_desc_set_mss(
+ ctxt_desc, cur_mss);
+ priv->hw->desc->tx_ctxt_desc_set_tcmssv(
+ ctxt_desc);
+ priv->hw->desc->tx_ctxt_desc_reset_ostc(
+ ctxt_desc);
+ priv->hw->desc->tx_ctxt_desc_set_ctxt(
+ ctxt_desc);
+ priv->hw->desc->tx_ctxt_desc_set_owner(
+ ctxt_desc);
+
+ entry = (++tqueue->cur_tx) % tx_rsize;
+ first_desc = tqueue->dma_tx + entry;
+
+ tqueue->prev_mss = cur_mss;
+ }
+ sxgbe_tso_prepare(priv, first_desc, skb);
+ } else {
+ tx_desc->tdes01 = dma_map_single(priv->device,
+ skb->data, no_pagedlen, DMA_TO_DEVICE);
+ if (dma_mapping_error(priv->device, tx_desc->tdes01))
+ netdev_err(dev, "%s: TX dma mapping failed!!\n",
+ __func__);
+
+ priv->hw->desc->prepare_tx_desc(tx_desc, 1, no_pagedlen,
+ no_pagedlen, cksum_flag);
+ }
+ }
+
+ for (frag_num = 0; frag_num < nr_frags; frag_num++) {
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[frag_num];
+ int len = skb_frag_size(frag);
+
+ entry = (++tqueue->cur_tx) % tx_rsize;
+ tx_desc = tqueue->dma_tx + entry;
+ tx_desc->tdes01 = skb_frag_dma_map(priv->device, frag, 0, len,
+ DMA_TO_DEVICE);
+
+ tqueue->tx_skbuff_dma[entry] = tx_desc->tdes01;
+ tqueue->tx_skbuff[entry] = NULL;
+
+ /* prepare the descriptor */
+ priv->hw->desc->prepare_tx_desc(tx_desc, 0, len,
+ len, cksum_flag);
+ /* memory barrier to flush descriptor */
+ wmb();
+
+ /* set the owner */
+ priv->hw->desc->set_tx_owner(tx_desc);
+ }
+
+ /* close the descriptors */
+ priv->hw->desc->close_tx_desc(tx_desc);
+
+ /* memory barrier to flush descriptor */
+ wmb();
+
+ tqueue->tx_count_frames += nr_frags + 1;
+ if (tqueue->tx_count_frames > tqueue->tx_coal_frames) {
+ priv->hw->desc->clear_tx_ic(tx_desc);
+ priv->xstats.tx_reset_ic_bit++;
+ mod_timer(&tqueue->txtimer,
+ SXGBE_COAL_TIMER(tqueue->tx_coal_timer));
+ } else {
+ tqueue->tx_count_frames = 0;
+ }
+
+ /* set owner for first desc */
+ priv->hw->desc->set_tx_owner(first_desc);
+
+ /* memory barrier to flush descriptor */
+ wmb();
+
+ tqueue->cur_tx++;
+
+ /* display current ring */
+ netif_dbg(priv, pktdata, dev, "%s: curr %d dirty=%d entry=%d, first=%p, nfrags=%d\n",
+ __func__, tqueue->cur_tx % tx_rsize,
+ tqueue->dirty_tx % tx_rsize, entry,
+ first_desc, nr_frags);
+
+ if (unlikely(sxgbe_tx_avail(tqueue, tx_rsize) <= (MAX_SKB_FRAGS + 1))) {
+ netif_dbg(priv, hw, dev, "%s: stop transmitted packets\n",
+ __func__);
+ netif_tx_stop_queue(dev_txq);
+ }
+
+ dev->stats.tx_bytes += skb->len;
+
+ if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+ tqueue->hwts_tx_en)) {
+ /* declare that device is doing timestamping */
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ priv->hw->desc->tx_enable_tstamp(first_desc);
+ }
+
+ if (!tqueue->hwts_tx_en)
+ skb_tx_timestamp(skb);
+
+ priv->hw->dma->enable_dma_transmission(priv->ioaddr, txq_index);
+
+ spin_unlock(&tqueue->tx_lock);
+
+ return NETDEV_TX_OK;
+}
+
+/**
+ * sxgbe_rx_refill: refill used skb preallocated buffers
+ * @priv: driver private structure
+ * Description : this is to reallocate the skb for the reception process
+ * that is based on zero-copy.
+ */
+static void sxgbe_rx_refill(struct sxgbe_priv_data *priv)
+{
+ unsigned int rxsize = priv->dma_rx_size;
+ int bfsize = priv->dma_buf_sz;
+ u8 qnum = priv->cur_rx_qnum;
+
+ for (; priv->rxq[qnum]->cur_rx - priv->rxq[qnum]->dirty_rx > 0;
+ priv->rxq[qnum]->dirty_rx++) {
+ unsigned int entry = priv->rxq[qnum]->dirty_rx % rxsize;
+ struct sxgbe_rx_norm_desc *p;
+
+ p = priv->rxq[qnum]->dma_rx + entry;
+
+ if (likely(priv->rxq[qnum]->rx_skbuff[entry] == NULL)) {
+ struct sk_buff *skb;
+
+ skb = netdev_alloc_skb_ip_align(priv->dev, bfsize);
+
+ if (unlikely(skb == NULL))
+ break;
+
+ priv->rxq[qnum]->rx_skbuff[entry] = skb;
+ priv->rxq[qnum]->rx_skbuff_dma[entry] =
+ dma_map_single(priv->device, skb->data, bfsize,
+ DMA_FROM_DEVICE);
+
+ p->rdes23.rx_rd_des23.buf2_addr =
+ priv->rxq[qnum]->rx_skbuff_dma[entry];
+ }
+
+ /* Added memory barrier for RX descriptor modification */
+ wmb();
+ priv->hw->desc->set_rx_owner(p);
+ /* Added memory barrier for RX descriptor modification */
+ wmb();
+ }
+}
+
+/**
+ * sxgbe_rx: receive the frames from the remote host
+ * @priv: driver private structure
+ * @limit: napi bugget.
+ * Description : this the function called by the napi poll method.
+ * It gets all the frames inside the ring.
+ */
+static int sxgbe_rx(struct sxgbe_priv_data *priv, int limit)
+{
+ u8 qnum = priv->cur_rx_qnum;
+ unsigned int rxsize = priv->dma_rx_size;
+ unsigned int entry = priv->rxq[qnum]->cur_rx;
+ unsigned int next_entry = 0;
+ unsigned int count = 0;
+ int checksum;
+ int status;
+
+ while (count < limit) {
+ struct sxgbe_rx_norm_desc *p;
+ struct sk_buff *skb;
+ int frame_len;
+
+ p = priv->rxq[qnum]->dma_rx + entry;
+
+ if (priv->hw->desc->get_rx_owner(p))
+ break;
+
+ count++;
+
+ next_entry = (++priv->rxq[qnum]->cur_rx) % rxsize;
+ prefetch(priv->rxq[qnum]->dma_rx + next_entry);
+
+ /* Read the status of the incoming frame and also get checksum
+ * value based on whether it is enabled in SXGBE hardware or
+ * not.
+ */
+ status = priv->hw->desc->rx_wbstatus(p, &priv->xstats,
+ &checksum);
+ if (unlikely(status < 0)) {
+ entry = next_entry;
+ continue;
+ }
+ if (unlikely(!priv->rxcsum_insertion))
+ checksum = CHECKSUM_NONE;
+
+ skb = priv->rxq[qnum]->rx_skbuff[entry];
+
+ if (unlikely(!skb))
+ netdev_err(priv->dev, "rx descriptor is not consistent\n");
+
+ prefetch(skb->data - NET_IP_ALIGN);
+ priv->rxq[qnum]->rx_skbuff[entry] = NULL;
+
+ frame_len = priv->hw->desc->get_rx_frame_len(p);
+
+ skb_put(skb, frame_len);
+
+ skb->ip_summed = checksum;
+ if (checksum == CHECKSUM_NONE)
+ netif_receive_skb(skb);
+ else
+ napi_gro_receive(&priv->napi, skb);
+
+ entry = next_entry;
+ }
+
+ sxgbe_rx_refill(priv);
+
+ return count;
+}
+
+/**
+ * sxgbe_poll - sxgbe poll method (NAPI)
+ * @napi : pointer to the napi structure.
+ * @budget : maximum number of packets that the current CPU can receive from
+ * all interfaces.
+ * Description :
+ * To look at the incoming frames and clear the tx resources.
+ */
+static int sxgbe_poll(struct napi_struct *napi, int budget)
+{
+ struct sxgbe_priv_data *priv = container_of(napi,
+ struct sxgbe_priv_data, napi);
+ int work_done = 0;
+ u8 qnum = priv->cur_rx_qnum;
+
+ priv->xstats.napi_poll++;
+ /* first, clean the tx queues */
+ sxgbe_tx_all_clean(priv);
+
+ work_done = sxgbe_rx(priv, budget);
+ if (work_done < budget) {
+ napi_complete(napi);
+ priv->hw->dma->enable_dma_irq(priv->ioaddr, qnum);
+ }
+
+ return work_done;
+}
+
+/**
+ * sxgbe_tx_timeout
+ * @dev : Pointer to net device structure
+ * Description: this function is called when a packet transmission fails to
+ * complete within a reasonable time. The driver will mark the error in the
+ * netdev structure and arrange for the device to be reset to a sane state
+ * in order to transmit a new packet.
+ */
+static void sxgbe_tx_timeout(struct net_device *dev)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+
+ sxgbe_reset_all_tx_queues(priv);
+}
+
+/**
+ * sxgbe_common_interrupt - main ISR
+ * @irq: interrupt number.
+ * @dev_id: to pass the net device pointer.
+ * Description: this is the main driver interrupt service routine.
+ * It calls the DMA ISR and also the core ISR to manage PMT, MMC, LPI
+ * interrupts.
+ */
+static irqreturn_t sxgbe_common_interrupt(int irq, void *dev_id)
+{
+ struct net_device *netdev = (struct net_device *)dev_id;
+ struct sxgbe_priv_data *priv = netdev_priv(netdev);
+ int status;
+
+ status = priv->hw->mac->host_irq_status(priv->ioaddr, &priv->xstats);
+ /* For LPI we need to save the tx status */
+ if (status & TX_ENTRY_LPI_MODE) {
+ priv->xstats.tx_lpi_entry_n++;
+ priv->tx_path_in_lpi_mode = true;
+ }
+ if (status & TX_EXIT_LPI_MODE) {
+ priv->xstats.tx_lpi_exit_n++;
+ priv->tx_path_in_lpi_mode = false;
+ }
+ if (status & RX_ENTRY_LPI_MODE)
+ priv->xstats.rx_lpi_entry_n++;
+ if (status & RX_EXIT_LPI_MODE)
+ priv->xstats.rx_lpi_exit_n++;
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * sxgbe_tx_interrupt - TX DMA ISR
+ * @irq: interrupt number.
+ * @dev_id: to pass the net device pointer.
+ * Description: this is the tx dma interrupt service routine.
+ */
+static irqreturn_t sxgbe_tx_interrupt(int irq, void *dev_id)
+{
+ int status;
+ struct sxgbe_tx_queue *txq = (struct sxgbe_tx_queue *)dev_id;
+ struct sxgbe_priv_data *priv = txq->priv_ptr;
+
+ /* get the channel status */
+ status = priv->hw->dma->tx_dma_int_status(priv->ioaddr, txq->queue_no,
+ &priv->xstats);
+ /* check for normal path */
+ if (likely((status & handle_tx)))
+ napi_schedule(&priv->napi);
+
+ /* check for unrecoverable error */
+ if (unlikely((status & tx_hard_error)))
+ sxgbe_restart_tx_queue(priv, txq->queue_no);
+
+ /* check for TC configuration change */
+ if (unlikely((status & tx_bump_tc) &&
+ (priv->tx_tc != SXGBE_MTL_SFMODE) &&
+ (priv->tx_tc < 512))) {
+ /* step of TX TC is 32 till 128, otherwise 64 */
+ priv->tx_tc += (priv->tx_tc < 128) ? 32 : 64;
+ priv->hw->mtl->set_tx_mtl_mode(priv->ioaddr,
+ txq->queue_no, priv->tx_tc);
+ priv->xstats.tx_threshold = priv->tx_tc;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * sxgbe_rx_interrupt - RX DMA ISR
+ * @irq: interrupt number.
+ * @dev_id: to pass the net device pointer.
+ * Description: this is the rx dma interrupt service routine.
+ */
+static irqreturn_t sxgbe_rx_interrupt(int irq, void *dev_id)
+{
+ int status;
+ struct sxgbe_rx_queue *rxq = (struct sxgbe_rx_queue *)dev_id;
+ struct sxgbe_priv_data *priv = rxq->priv_ptr;
+
+ /* get the channel status */
+ status = priv->hw->dma->rx_dma_int_status(priv->ioaddr, rxq->queue_no,
+ &priv->xstats);
+
+ if (likely((status & handle_rx) && (napi_schedule_prep(&priv->napi)))) {
+ priv->hw->dma->disable_dma_irq(priv->ioaddr, rxq->queue_no);
+ __napi_schedule(&priv->napi);
+ }
+
+ /* check for TC configuration change */
+ if (unlikely((status & rx_bump_tc) &&
+ (priv->rx_tc != SXGBE_MTL_SFMODE) &&
+ (priv->rx_tc < 128))) {
+ /* step of TC is 32 */
+ priv->rx_tc += 32;
+ priv->hw->mtl->set_rx_mtl_mode(priv->ioaddr,
+ rxq->queue_no, priv->rx_tc);
+ priv->xstats.rx_threshold = priv->rx_tc;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static inline u64 sxgbe_get_stat64(void __iomem *ioaddr, int reg_lo, int reg_hi)
+{
+ u64 val = readl(ioaddr + reg_lo);
+
+ val |= ((u64)readl(ioaddr + reg_hi)) << 32;
+
+ return val;
+}
+
+
+/* sxgbe_get_stats64 - entry point to see statistical information of device
+ * @dev : device pointer.
+ * @stats : pointer to hold all the statistical information of device.
+ * Description:
+ * This function is a driver entry point whenever ifconfig command gets
+ * executed to see device statistics. Statistics are number of
+ * bytes sent or received, errors occured etc.
+ * Return value:
+ * This function returns various statistical information of device.
+ */
+static struct rtnl_link_stats64 *sxgbe_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+ void __iomem *ioaddr = priv->ioaddr;
+ u64 count;
+
+ spin_lock(&priv->stats_lock);
+ /* Freeze the counter registers before reading value otherwise it may
+ * get updated by hardware while we are reading them
+ */
+ writel(SXGBE_MMC_CTRL_CNT_FRZ, ioaddr + SXGBE_MMC_CTL_REG);
+
+ stats->rx_bytes = sxgbe_get_stat64(ioaddr,
+ SXGBE_MMC_RXOCTETLO_GCNT_REG,
+ SXGBE_MMC_RXOCTETHI_GCNT_REG);
+
+ stats->rx_packets = sxgbe_get_stat64(ioaddr,
+ SXGBE_MMC_RXFRAMELO_GBCNT_REG,
+ SXGBE_MMC_RXFRAMEHI_GBCNT_REG);
+
+ stats->multicast = sxgbe_get_stat64(ioaddr,
+ SXGBE_MMC_RXMULTILO_GCNT_REG,
+ SXGBE_MMC_RXMULTIHI_GCNT_REG);
+
+ stats->rx_crc_errors = sxgbe_get_stat64(ioaddr,
+ SXGBE_MMC_RXCRCERRLO_REG,
+ SXGBE_MMC_RXCRCERRHI_REG);
+
+ stats->rx_length_errors = sxgbe_get_stat64(ioaddr,
+ SXGBE_MMC_RXLENERRLO_REG,
+ SXGBE_MMC_RXLENERRHI_REG);
+
+ stats->rx_missed_errors = sxgbe_get_stat64(ioaddr,
+ SXGBE_MMC_RXFIFOOVERFLOWLO_GBCNT_REG,
+ SXGBE_MMC_RXFIFOOVERFLOWHI_GBCNT_REG);
+
+ stats->tx_bytes = sxgbe_get_stat64(ioaddr,
+ SXGBE_MMC_TXOCTETLO_GCNT_REG,
+ SXGBE_MMC_TXOCTETHI_GCNT_REG);
+
+ count = sxgbe_get_stat64(ioaddr, SXGBE_MMC_TXFRAMELO_GBCNT_REG,
+ SXGBE_MMC_TXFRAMEHI_GBCNT_REG);
+
+ stats->tx_errors = sxgbe_get_stat64(ioaddr, SXGBE_MMC_TXFRAMELO_GCNT_REG,
+ SXGBE_MMC_TXFRAMEHI_GCNT_REG);
+ stats->tx_errors = count - stats->tx_errors;
+ stats->tx_packets = count;
+ stats->tx_fifo_errors = sxgbe_get_stat64(ioaddr, SXGBE_MMC_TXUFLWLO_GBCNT_REG,
+ SXGBE_MMC_TXUFLWHI_GBCNT_REG);
+ writel(0, ioaddr + SXGBE_MMC_CTL_REG);
+ spin_unlock(&priv->stats_lock);
+
+ return stats;
+}
+
+/* sxgbe_set_features - entry point to set offload features of the device.
+ * @dev : device pointer.
+ * @features : features which are required to be set.
+ * Description:
+ * This function is a driver entry point and called by Linux kernel whenever
+ * any device features are set or reset by user.
+ * Return value:
+ * This function returns 0 after setting or resetting device features.
+ */
+static int sxgbe_set_features(struct net_device *dev,
+ netdev_features_t features)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+ netdev_features_t changed = dev->features ^ features;
+
+ if (changed & NETIF_F_RXCSUM) {
+ if (features & NETIF_F_RXCSUM) {
+ priv->hw->mac->enable_rx_csum(priv->ioaddr);
+ priv->rxcsum_insertion = true;
+ } else {
+ priv->hw->mac->disable_rx_csum(priv->ioaddr);
+ priv->rxcsum_insertion = false;
+ }
+ }
+
+ return 0;
+}
+
+/* sxgbe_change_mtu - entry point to change MTU size for the device.
+ * @dev : device pointer.
+ * @new_mtu : the new MTU size for the device.
+ * Description: the Maximum Transfer Unit (MTU) is used by the network layer
+ * to drive packet transmission. Ethernet has an MTU of 1500 octets
+ * (ETH_DATA_LEN). This value can be changed with ifconfig.
+ * Return value:
+ * 0 on success and an appropriate (-)ve integer as defined in errno.h
+ * file on failure.
+ */
+static int sxgbe_change_mtu(struct net_device *dev, int new_mtu)
+{
+ /* RFC 791, page 25, "Every internet module must be able to forward
+ * a datagram of 68 octets without further fragmentation."
+ */
+ if (new_mtu < MIN_MTU || (new_mtu > MAX_MTU)) {
+ netdev_err(dev, "invalid MTU, MTU should be in between %d and %d\n",
+ MIN_MTU, MAX_MTU);
+ return -EINVAL;
+ }
+
+ /* Return if the buffer sizes will not change */
+ if (dev->mtu == new_mtu)
+ return 0;
+
+ dev->mtu = new_mtu;
+
+ if (!netif_running(dev))
+ return 0;
+
+ /* Recevice ring buffer size is needed to be set based on MTU. If MTU is
+ * changed then reinitilisation of the receive ring buffers need to be
+ * done. Hence bring interface down and bring interface back up
+ */
+ sxgbe_release(dev);
+ return sxgbe_open(dev);
+}
+
+static void sxgbe_set_umac_addr(void __iomem *ioaddr, unsigned char *addr,
+ unsigned int reg_n)
+{
+ unsigned long data;
+
+ data = (addr[5] << 8) | addr[4];
+ /* For MAC Addr registers se have to set the Address Enable (AE)
+ * bit that has no effect on the High Reg 0 where the bit 31 (MO)
+ * is RO.
+ */
+ writel(data | SXGBE_HI_REG_AE, ioaddr + SXGBE_ADDR_HIGH(reg_n));
+ data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
+ writel(data, ioaddr + SXGBE_ADDR_LOW(reg_n));
+}
+
+/**
+ * sxgbe_set_rx_mode - entry point for setting different receive mode of
+ * a device. unicast, multicast addressing
+ * @dev : pointer to the device structure
+ * Description:
+ * This function is a driver entry point which gets called by the kernel
+ * whenever different receive mode like unicast, multicast and promiscuous
+ * must be enabled/disabled.
+ * Return value:
+ * void.
+ */
+static void sxgbe_set_rx_mode(struct net_device *dev)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+ void __iomem *ioaddr = (void __iomem *)priv->ioaddr;
+ unsigned int value = 0;
+ u32 mc_filter[2];
+ struct netdev_hw_addr *ha;
+ int reg = 1;
+
+ netdev_dbg(dev, "%s: # mcasts %d, # unicast %d\n",
+ __func__, netdev_mc_count(dev), netdev_uc_count(dev));
+
+ if (dev->flags & IFF_PROMISC) {
+ value = SXGBE_FRAME_FILTER_PR;
+
+ } else if ((netdev_mc_count(dev) > SXGBE_HASH_TABLE_SIZE) ||
+ (dev->flags & IFF_ALLMULTI)) {
+ value = SXGBE_FRAME_FILTER_PM; /* pass all multi */
+ writel(0xffffffff, ioaddr + SXGBE_HASH_HIGH);
+ writel(0xffffffff, ioaddr + SXGBE_HASH_LOW);
+
+ } else if (!netdev_mc_empty(dev)) {
+ /* Hash filter for multicast */
+ value = SXGBE_FRAME_FILTER_HMC;
+
+ memset(mc_filter, 0, sizeof(mc_filter));
+ netdev_for_each_mc_addr(ha, dev) {
+ /* The upper 6 bits of the calculated CRC are used to
+ * index the contens of the hash table
+ */
+ int bit_nr = bitrev32(~crc32_le(~0, ha->addr, 6)) >> 26;
+
+ /* The most significant bit determines the register to
+ * use (H/L) while the other 5 bits determine the bit
+ * within the register.
+ */
+ mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+ }
+ writel(mc_filter[0], ioaddr + SXGBE_HASH_LOW);
+ writel(mc_filter[1], ioaddr + SXGBE_HASH_HIGH);
+ }
+
+ /* Handle multiple unicast addresses (perfect filtering) */
+ if (netdev_uc_count(dev) > SXGBE_MAX_PERFECT_ADDRESSES)
+ /* Switch to promiscuous mode if more than 16 addrs
+ * are required
+ */
+ value |= SXGBE_FRAME_FILTER_PR;
+ else {
+ netdev_for_each_uc_addr(ha, dev) {
+ sxgbe_set_umac_addr(ioaddr, ha->addr, reg);
+ reg++;
+ }
+ }
+#ifdef FRAME_FILTER_DEBUG
+ /* Enable Receive all mode (to debug filtering_fail errors) */
+ value |= SXGBE_FRAME_FILTER_RA;
+#endif
+ writel(value, ioaddr + SXGBE_FRAME_FILTER);
+
+ netdev_dbg(dev, "Filter: 0x%08x\n\tHash: HI 0x%08x, LO 0x%08x\n",
+ readl(ioaddr + SXGBE_FRAME_FILTER),
+ readl(ioaddr + SXGBE_HASH_HIGH),
+ readl(ioaddr + SXGBE_HASH_LOW));
+}
+
+/**
+ * sxgbe_config - entry point for changing configuration mode passed on by
+ * ifconfig
+ * @dev : pointer to the device structure
+ * @map : pointer to the device mapping structure
+ * Description:
+ * This function is a driver entry point which gets called by the kernel
+ * whenever some device configuration is changed.
+ * Return value:
+ * This function returns 0 if success and appropriate error otherwise.
+ */
+static int sxgbe_config(struct net_device *dev, struct ifmap *map)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+
+ /* Can't act on a running interface */
+ if (dev->flags & IFF_UP)
+ return -EBUSY;
+
+ /* Don't allow changing the I/O address */
+ if (map->base_addr != (unsigned long)priv->ioaddr) {
+ netdev_warn(dev, "can't change I/O address\n");
+ return -EOPNOTSUPP;
+ }
+
+ /* Don't allow changing the IRQ */
+ if (map->irq != priv->irq) {
+ netdev_warn(dev, "not change IRQ number %d\n", priv->irq);
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/**
+ * sxgbe_poll_controller - entry point for polling receive by device
+ * @dev : pointer to the device structure
+ * Description:
+ * This function is used by NETCONSOLE and other diagnostic tools
+ * to allow network I/O with interrupts disabled.
+ * Return value:
+ * Void.
+ */
+static void sxgbe_poll_controller(struct net_device *dev)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+
+ disable_irq(priv->irq);
+ sxgbe_rx_interrupt(priv->irq, dev);
+ enable_irq(priv->irq);
+}
+#endif
+
+/* sxgbe_ioctl - Entry point for the Ioctl
+ * @dev: Device pointer.
+ * @rq: An IOCTL specefic structure, that can contain a pointer to
+ * a proprietary structure used to pass information to the driver.
+ * @cmd: IOCTL command
+ * Description:
+ * Currently it supports the phy_mii_ioctl(...) and HW time stamping.
+ */
+static int sxgbe_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+ int ret = -EOPNOTSUPP;
+
+ if (!netif_running(dev))
+ return -EINVAL;
+
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ case SIOCGMIIREG:
+ case SIOCSMIIREG:
+ if (!priv->phydev)
+ return -EINVAL;
+ ret = phy_mii_ioctl(priv->phydev, rq, cmd);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static const struct net_device_ops sxgbe_netdev_ops = {
+ .ndo_open = sxgbe_open,
+ .ndo_start_xmit = sxgbe_xmit,
+ .ndo_stop = sxgbe_release,
+ .ndo_get_stats64 = sxgbe_get_stats64,
+ .ndo_change_mtu = sxgbe_change_mtu,
+ .ndo_set_features = sxgbe_set_features,
+ .ndo_set_rx_mode = sxgbe_set_rx_mode,
+ .ndo_tx_timeout = sxgbe_tx_timeout,
+ .ndo_do_ioctl = sxgbe_ioctl,
+ .ndo_set_config = sxgbe_config,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = sxgbe_poll_controller,
+#endif
+ .ndo_set_mac_address = eth_mac_addr,
+};
+
+/* Get the hardware ops */
+static void sxgbe_get_ops(struct sxgbe_ops * const ops_ptr)
+{
+ ops_ptr->mac = sxgbe_get_core_ops();
+ ops_ptr->desc = sxgbe_get_desc_ops();
+ ops_ptr->dma = sxgbe_get_dma_ops();
+ ops_ptr->mtl = sxgbe_get_mtl_ops();
+
+ /* set the MDIO communication Address/Data regisers */
+ ops_ptr->mii.addr = SXGBE_MDIO_SCMD_ADD_REG;
+ ops_ptr->mii.data = SXGBE_MDIO_SCMD_DATA_REG;
+
+ /* Assigning the default link settings
+ * no SXGBE defined default values to be set in registers,
+ * so assigning as 0 for port and duplex
+ */
+ ops_ptr->link.port = 0;
+ ops_ptr->link.duplex = 0;
+ ops_ptr->link.speed = SXGBE_SPEED_10G;
+}
+
+/**
+ * sxgbe_hw_init - Init the GMAC device
+ * @priv: driver private structure
+ * Description: this function checks the HW capability
+ * (if supported) and sets the driver's features.
+ */
+static int sxgbe_hw_init(struct sxgbe_priv_data * const priv)
+{
+ u32 ctrl_ids;
+
+ priv->hw = kmalloc(sizeof(*priv->hw), GFP_KERNEL);
+ if(!priv->hw)
+ return -ENOMEM;
+
+ /* get the hardware ops */
+ sxgbe_get_ops(priv->hw);
+
+ /* get the controller id */
+ ctrl_ids = priv->hw->mac->get_controller_version(priv->ioaddr);
+ priv->hw->ctrl_uid = (ctrl_ids & 0x00ff0000) >> 16;
+ priv->hw->ctrl_id = (ctrl_ids & 0x000000ff);
+ pr_info("user ID: 0x%x, Controller ID: 0x%x\n",
+ priv->hw->ctrl_uid, priv->hw->ctrl_id);
+
+ /* get the H/W features */
+ if (!sxgbe_get_hw_features(priv))
+ pr_info("Hardware features not found\n");
+
+ if (priv->hw_cap.tx_csum_offload)
+ pr_info("TX Checksum offload supported\n");
+
+ if (priv->hw_cap.rx_csum_offload)
+ pr_info("RX Checksum offload supported\n");
+
+ return 0;
+}
+
+/**
+ * sxgbe_drv_probe
+ * @device: device pointer
+ * @plat_dat: platform data pointer
+ * @addr: iobase memory address
+ * Description: this is the main probe function used to
+ * call the alloc_etherdev, allocate the priv structure.
+ */
+struct sxgbe_priv_data *sxgbe_drv_probe(struct device *device,
+ struct sxgbe_plat_data *plat_dat,
+ void __iomem *addr)
+{
+ struct sxgbe_priv_data *priv;
+ struct net_device *ndev;
+ int ret;
+ u8 queue_num;
+
+ ndev = alloc_etherdev_mqs(sizeof(struct sxgbe_priv_data),
+ SXGBE_TX_QUEUES, SXGBE_RX_QUEUES);
+ if (!ndev)
+ return NULL;
+
+ SET_NETDEV_DEV(ndev, device);
+
+ priv = netdev_priv(ndev);
+ priv->device = device;
+ priv->dev = ndev;
+
+ sxgbe_set_ethtool_ops(ndev);
+ priv->plat = plat_dat;
+ priv->ioaddr = addr;
+
+ /* Verify driver arguments */
+ sxgbe_verify_args();
+
+ /* Init MAC and get the capabilities */
+ ret = sxgbe_hw_init(priv);
+ if (ret)
+ goto error_free_netdev;
+
+ /* allocate memory resources for Descriptor rings */
+ ret = txring_mem_alloc(priv);
+ if (ret)
+ goto error_free_netdev;
+
+ ret = rxring_mem_alloc(priv);
+ if (ret)
+ goto error_free_netdev;
+
+ ndev->netdev_ops = &sxgbe_netdev_ops;
+
+ ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_RXCSUM | NETIF_F_TSO | NETIF_F_TSO6 |
+ NETIF_F_GRO;
+ ndev->features |= ndev->hw_features | NETIF_F_HIGHDMA;
+ ndev->watchdog_timeo = msecs_to_jiffies(TX_TIMEO);
+
+ /* assign filtering support */
+ ndev->priv_flags |= IFF_UNICAST_FLT;
+
+ priv->msg_enable = netif_msg_init(debug, default_msg_level);
+
+ /* Enable TCP segmentation offload for all DMA channels */
+ if (priv->hw_cap.tcpseg_offload) {
+ SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
+ priv->hw->dma->enable_tso(priv->ioaddr, queue_num);
+ }
+ }
+
+ /* Enable Rx checksum offload */
+ if (priv->hw_cap.rx_csum_offload) {
+ priv->hw->mac->enable_rx_csum(priv->ioaddr);
+ priv->rxcsum_insertion = true;
+ }
+
+ /* Initialise pause frame settings */
+ priv->rx_pause = 1;
+ priv->tx_pause = 1;
+
+ /* Rx Watchdog is available, enable depend on platform data */
+ if (!priv->plat->riwt_off) {
+ priv->use_riwt = 1;
+ pr_info("Enable RX Mitigation via HW Watchdog Timer\n");
+ }
+
+ netif_napi_add(ndev, &priv->napi, sxgbe_poll, 64);
+
+ spin_lock_init(&priv->stats_lock);
+
+ priv->sxgbe_clk = clk_get(priv->device, SXGBE_RESOURCE_NAME);
+ if (IS_ERR(priv->sxgbe_clk)) {
+ netdev_warn(ndev, "%s: warning: cannot get CSR clock\n",
+ __func__);
+ goto error_clk_get;
+ }
+
+ /* If a specific clk_csr value is passed from the platform
+ * this means that the CSR Clock Range selection cannot be
+ * changed at run-time and it is fixed. Viceversa the driver'll try to
+ * set the MDC clock dynamically according to the csr actual
+ * clock input.
+ */
+ if (!priv->plat->clk_csr)
+ sxgbe_clk_csr_set(priv);
+ else
+ priv->clk_csr = priv->plat->clk_csr;
+
+ /* MDIO bus Registration */
+ ret = sxgbe_mdio_register(ndev);
+ if (ret < 0) {
+ netdev_dbg(ndev, "%s: MDIO bus (id: %d) registration failed\n",
+ __func__, priv->plat->bus_id);
+ goto error_mdio_register;
+ }
+
+ ret = register_netdev(ndev);
+ if (ret) {
+ pr_err("%s: ERROR %i registering the device\n", __func__, ret);
+ goto error_netdev_register;
+ }
+
+ sxgbe_check_ether_addr(priv);
+
+ return priv;
+
+error_mdio_register:
+ clk_put(priv->sxgbe_clk);
+error_clk_get:
+error_netdev_register:
+ netif_napi_del(&priv->napi);
+error_free_netdev:
+ free_netdev(ndev);
+
+ return NULL;
+}
+
+/**
+ * sxgbe_drv_remove
+ * @ndev: net device pointer
+ * Description: this function resets the TX/RX processes, disables the MAC RX/TX
+ * changes the link status, releases the DMA descriptor rings.
+ */
+int sxgbe_drv_remove(struct net_device *ndev)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(ndev);
+
+ netdev_info(ndev, "%s: removing driver\n", __func__);
+
+ priv->hw->dma->stop_rx(priv->ioaddr, SXGBE_RX_QUEUES);
+ priv->hw->dma->stop_tx(priv->ioaddr, SXGBE_TX_QUEUES);
+
+ priv->hw->mac->enable_tx(priv->ioaddr, false);
+ priv->hw->mac->enable_rx(priv->ioaddr, false);
+
+ netif_napi_del(&priv->napi);
+
+ sxgbe_mdio_unregister(ndev);
+
+ unregister_netdev(ndev);
+
+ free_netdev(ndev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+int sxgbe_suspend(struct net_device *ndev)
+{
+ return 0;
+}
+
+int sxgbe_resume(struct net_device *ndev)
+{
+ return 0;
+}
+
+int sxgbe_freeze(struct net_device *ndev)
+{
+ return -ENOSYS;
+}
+
+int sxgbe_restore(struct net_device *ndev)
+{
+ return -ENOSYS;
+}
+#endif /* CONFIG_PM */
+
+/* Driver is configured as Platform driver */
+static int __init sxgbe_init(void)
+{
+ int ret;
+
+ ret = sxgbe_register_platform();
+ if (ret)
+ goto err;
+ return 0;
+err:
+ pr_err("driver registration failed\n");
+ return ret;
+}
+
+static void __exit sxgbe_exit(void)
+{
+ sxgbe_unregister_platform();
+}
+
+module_init(sxgbe_init);
+module_exit(sxgbe_exit);
+
+#ifndef MODULE
+static int __init sxgbe_cmdline_opt(char *str)
+{
+ char *opt;
+
+ if (!str || !*str)
+ return -EINVAL;
+ while ((opt = strsep(&str, ",")) != NULL) {
+ if (!strncmp(opt, "eee_timer:", 6)) {
+ if (kstrtoint(opt + 10, 0, &eee_timer))
+ goto err;
+ }
+ }
+ return 0;
+
+err:
+ pr_err("%s: ERROR broken module parameter conversion\n", __func__);
+ return -EINVAL;
+}
+
+__setup("sxgbeeth=", sxgbe_cmdline_opt);
+#endif /* MODULE */
+
+
+
+MODULE_DESCRIPTION("SAMSUNG 10G/2.5G/1G Ethernet PLATFORM driver");
+
+MODULE_PARM_DESC(debug, "Message Level (-1: default, 0: no output, 16: all)");
+MODULE_PARM_DESC(eee_timer, "EEE-LPI Default LS timer value");
+
+MODULE_AUTHOR("Siva Reddy Kallam <siva.kallam@samsung.com>");
+MODULE_AUTHOR("ByungHo An <bh74.an@samsung.com>");
+MODULE_AUTHOR("Girish K S <ks.giri@samsung.com>");
+MODULE_AUTHOR("Vipul Pandya <vipul.pandya@samsung.com>");
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_mdio.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mdio.c
new file mode 100644
index 000000000000..01af2cbb479d
--- /dev/null
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mdio.c
@@ -0,0 +1,244 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/io.h>
+#include <linux/mii.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+#include <linux/phy.h>
+#include <linux/slab.h>
+#include <linux/sxgbe_platform.h>
+
+#include "sxgbe_common.h"
+#include "sxgbe_reg.h"
+
+#define SXGBE_SMA_WRITE_CMD 0x01 /* write command */
+#define SXGBE_SMA_PREAD_CMD 0x02 /* post read increament address */
+#define SXGBE_SMA_READ_CMD 0x03 /* read command */
+#define SXGBE_SMA_SKIP_ADDRFRM 0x00040000 /* skip the address frame */
+#define SXGBE_MII_BUSY 0x00800000 /* mii busy */
+
+static int sxgbe_mdio_busy_wait(void __iomem *ioaddr, unsigned int mii_data)
+{
+ unsigned long fin_time = jiffies + 3 * HZ; /* 3 seconds */
+
+ while (!time_after(jiffies, fin_time)) {
+ if (!(readl(ioaddr + mii_data) & SXGBE_MII_BUSY))
+ return 0;
+ cpu_relax();
+ }
+
+ return -EBUSY;
+}
+
+static void sxgbe_mdio_ctrl_data(struct sxgbe_priv_data *sp, u32 cmd,
+ u16 phydata)
+{
+ u32 reg = phydata;
+
+ reg |= (cmd << 16) | SXGBE_SMA_SKIP_ADDRFRM |
+ ((sp->clk_csr & 0x7) << 19) | SXGBE_MII_BUSY;
+ writel(reg, sp->ioaddr + sp->hw->mii.data);
+}
+
+static void sxgbe_mdio_c45(struct sxgbe_priv_data *sp, u32 cmd, int phyaddr,
+ int phyreg, u16 phydata)
+{
+ u32 reg;
+
+ /* set mdio address register */
+ reg = ((phyreg >> 16) & 0x1f) << 21;
+ reg |= (phyaddr << 16) | (phyreg & 0xffff);
+ writel(reg, sp->ioaddr + sp->hw->mii.addr);
+
+ sxgbe_mdio_ctrl_data(sp, cmd, phydata);
+}
+
+static void sxgbe_mdio_c22(struct sxgbe_priv_data *sp, u32 cmd, int phyaddr,
+ int phyreg, u16 phydata)
+{
+ u32 reg;
+
+ writel(1 << phyaddr, sp->ioaddr + SXGBE_MDIO_CLAUSE22_PORT_REG);
+
+ /* set mdio address register */
+ reg = (phyaddr << 16) | (phyreg & 0x1f);
+ writel(reg, sp->ioaddr + sp->hw->mii.addr);
+
+ sxgbe_mdio_ctrl_data(sp, cmd, phydata);
+}
+
+static int sxgbe_mdio_access(struct sxgbe_priv_data *sp, u32 cmd, int phyaddr,
+ int phyreg, u16 phydata)
+{
+ const struct mii_regs *mii = &sp->hw->mii;
+ int rc;
+
+ rc = sxgbe_mdio_busy_wait(sp->ioaddr, mii->data);
+ if (rc < 0)
+ return rc;
+
+ if (phyreg & MII_ADDR_C45) {
+ sxgbe_mdio_c45(sp, cmd, phyaddr, phyreg, phydata);
+ } else {
+ /* Ports 0-3 only support C22. */
+ if (phyaddr >= 4)
+ return -ENODEV;
+
+ sxgbe_mdio_c22(sp, cmd, phyaddr, phyreg, phydata);
+ }
+
+ return sxgbe_mdio_busy_wait(sp->ioaddr, mii->data);
+}
+
+/**
+ * sxgbe_mdio_read
+ * @bus: points to the mii_bus structure
+ * @phyaddr: address of phy port
+ * @phyreg: address of register with in phy register
+ * Description: this function used for C45 and C22 MDIO Read
+ */
+static int sxgbe_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
+{
+ struct net_device *ndev = bus->priv;
+ struct sxgbe_priv_data *priv = netdev_priv(ndev);
+ int rc;
+
+ rc = sxgbe_mdio_access(priv, SXGBE_SMA_READ_CMD, phyaddr, phyreg, 0);
+ if (rc < 0)
+ return rc;
+
+ return readl(priv->ioaddr + priv->hw->mii.data) & 0xffff;
+}
+
+/**
+ * sxgbe_mdio_write
+ * @bus: points to the mii_bus structure
+ * @phyaddr: address of phy port
+ * @phyreg: address of phy registers
+ * @phydata: data to be written into phy register
+ * Description: this function is used for C45 and C22 MDIO write
+ */
+static int sxgbe_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
+ u16 phydata)
+{
+ struct net_device *ndev = bus->priv;
+ struct sxgbe_priv_data *priv = netdev_priv(ndev);
+
+ return sxgbe_mdio_access(priv, SXGBE_SMA_WRITE_CMD, phyaddr, phyreg,
+ phydata);
+}
+
+int sxgbe_mdio_register(struct net_device *ndev)
+{
+ struct mii_bus *mdio_bus;
+ struct sxgbe_priv_data *priv = netdev_priv(ndev);
+ struct sxgbe_mdio_bus_data *mdio_data = priv->plat->mdio_bus_data;
+ int err, phy_addr;
+ int *irqlist;
+ bool act;
+
+ /* allocate the new mdio bus */
+ mdio_bus = mdiobus_alloc();
+ if (!mdio_bus) {
+ netdev_err(ndev, "%s: mii bus allocation failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ if (mdio_data->irqs)
+ irqlist = mdio_data->irqs;
+ else
+ irqlist = priv->mii_irq;
+
+ /* assign mii bus fields */
+ mdio_bus->name = "samsxgbe";
+ mdio_bus->read = &sxgbe_mdio_read;
+ mdio_bus->write = &sxgbe_mdio_write;
+ snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+ mdio_bus->name, priv->plat->bus_id);
+ mdio_bus->priv = ndev;
+ mdio_bus->phy_mask = mdio_data->phy_mask;
+ mdio_bus->parent = priv->device;
+
+ /* register with kernel subsystem */
+ err = mdiobus_register(mdio_bus);
+ if (err != 0) {
+ netdev_err(ndev, "mdiobus register failed\n");
+ goto mdiobus_err;
+ }
+
+ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+ struct phy_device *phy = mdio_bus->phy_map[phy_addr];
+
+ if (phy) {
+ char irq_num[4];
+ char *irq_str;
+ /* If an IRQ was provided to be assigned after
+ * the bus probe, do it here.
+ */
+ if ((mdio_data->irqs == NULL) &&
+ (mdio_data->probed_phy_irq > 0)) {
+ irqlist[phy_addr] = mdio_data->probed_phy_irq;
+ phy->irq = mdio_data->probed_phy_irq;
+ }
+
+ /* If we're going to bind the MAC to this PHY bus,
+ * and no PHY number was provided to the MAC,
+ * use the one probed here.
+ */
+ if (priv->plat->phy_addr == -1)
+ priv->plat->phy_addr = phy_addr;
+
+ act = (priv->plat->phy_addr == phy_addr);
+ switch (phy->irq) {
+ case PHY_POLL:
+ irq_str = "POLL";
+ break;
+ case PHY_IGNORE_INTERRUPT:
+ irq_str = "IGNORE";
+ break;
+ default:
+ sprintf(irq_num, "%d", phy->irq);
+ irq_str = irq_num;
+ break;
+ }
+ netdev_info(ndev, "PHY ID %08x at %d IRQ %s (%s)%s\n",
+ phy->phy_id, phy_addr, irq_str,
+ dev_name(&phy->dev), act ? " active" : "");
+ }
+ }
+
+ priv->mii = mdio_bus;
+
+ return 0;
+
+mdiobus_err:
+ mdiobus_free(mdio_bus);
+ return err;
+}
+
+int sxgbe_mdio_unregister(struct net_device *ndev)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(ndev);
+
+ if (!priv->mii)
+ return 0;
+
+ mdiobus_unregister(priv->mii);
+ priv->mii->priv = NULL;
+ mdiobus_free(priv->mii);
+ priv->mii = NULL;
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.c
new file mode 100644
index 000000000000..324681c2bb74
--- /dev/null
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.c
@@ -0,0 +1,254 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/jiffies.h>
+
+#include "sxgbe_mtl.h"
+#include "sxgbe_reg.h"
+
+static void sxgbe_mtl_init(void __iomem *ioaddr, unsigned int etsalg,
+ unsigned int raa)
+{
+ u32 reg_val;
+
+ reg_val = readl(ioaddr + SXGBE_MTL_OP_MODE_REG);
+ reg_val &= ETS_RST;
+
+ /* ETS Algorith */
+ switch (etsalg & SXGBE_MTL_OPMODE_ESTMASK) {
+ case ETS_WRR:
+ reg_val &= ETS_WRR;
+ break;
+ case ETS_WFQ:
+ reg_val |= ETS_WFQ;
+ break;
+ case ETS_DWRR:
+ reg_val |= ETS_DWRR;
+ break;
+ }
+ writel(reg_val, ioaddr + SXGBE_MTL_OP_MODE_REG);
+
+ switch (raa & SXGBE_MTL_OPMODE_RAAMASK) {
+ case RAA_SP:
+ reg_val &= RAA_SP;
+ break;
+ case RAA_WSP:
+ reg_val |= RAA_WSP;
+ break;
+ }
+ writel(reg_val, ioaddr + SXGBE_MTL_OP_MODE_REG);
+}
+
+/* For Dynamic DMA channel mapping for Rx queue */
+static void sxgbe_mtl_dma_dm_rxqueue(void __iomem *ioaddr)
+{
+ writel(RX_QUEUE_DYNAMIC, ioaddr + SXGBE_MTL_RXQ_DMAMAP0_REG);
+ writel(RX_QUEUE_DYNAMIC, ioaddr + SXGBE_MTL_RXQ_DMAMAP1_REG);
+ writel(RX_QUEUE_DYNAMIC, ioaddr + SXGBE_MTL_RXQ_DMAMAP2_REG);
+}
+
+static void sxgbe_mtl_set_txfifosize(void __iomem *ioaddr, int queue_num,
+ int queue_fifo)
+{
+ u32 fifo_bits, reg_val;
+
+ /* 0 means 256 bytes */
+ fifo_bits = (queue_fifo / SXGBE_MTL_TX_FIFO_DIV) - 1;
+ reg_val = readl(ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
+ reg_val |= (fifo_bits << SXGBE_MTL_FIFO_LSHIFT);
+ writel(reg_val, ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_mtl_set_rxfifosize(void __iomem *ioaddr, int queue_num,
+ int queue_fifo)
+{
+ u32 fifo_bits, reg_val;
+
+ /* 0 means 256 bytes */
+ fifo_bits = (queue_fifo / SXGBE_MTL_RX_FIFO_DIV)-1;
+ reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+ reg_val |= (fifo_bits << SXGBE_MTL_FIFO_LSHIFT);
+ writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_mtl_enable_txqueue(void __iomem *ioaddr, int queue_num)
+{
+ u32 reg_val;
+
+ reg_val = readl(ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
+ reg_val |= SXGBE_MTL_ENABLE_QUEUE;
+ writel(reg_val, ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_mtl_disable_txqueue(void __iomem *ioaddr, int queue_num)
+{
+ u32 reg_val;
+
+ reg_val = readl(ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
+ reg_val &= ~SXGBE_MTL_ENABLE_QUEUE;
+ writel(reg_val, ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_mtl_fc_active(void __iomem *ioaddr, int queue_num,
+ int threshold)
+{
+ u32 reg_val;
+
+ reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+ reg_val &= ~(SXGBE_MTL_FCMASK << RX_FC_ACTIVE);
+ reg_val |= (threshold << RX_FC_ACTIVE);
+
+ writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_mtl_fc_enable(void __iomem *ioaddr, int queue_num)
+{
+ u32 reg_val;
+
+ reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+ reg_val |= SXGBE_MTL_ENABLE_FC;
+ writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_mtl_fc_deactive(void __iomem *ioaddr, int queue_num,
+ int threshold)
+{
+ u32 reg_val;
+
+ reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+ reg_val &= ~(SXGBE_MTL_FCMASK << RX_FC_DEACTIVE);
+ reg_val |= (threshold << RX_FC_DEACTIVE);
+
+ writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_mtl_fep_enable(void __iomem *ioaddr, int queue_num)
+{
+ u32 reg_val;
+
+ reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+ reg_val |= SXGBE_MTL_RXQ_OP_FEP;
+
+ writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_mtl_fep_disable(void __iomem *ioaddr, int queue_num)
+{
+ u32 reg_val;
+
+ reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+ reg_val &= ~(SXGBE_MTL_RXQ_OP_FEP);
+
+ writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_mtl_fup_enable(void __iomem *ioaddr, int queue_num)
+{
+ u32 reg_val;
+
+ reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+ reg_val |= SXGBE_MTL_RXQ_OP_FUP;
+
+ writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_mtl_fup_disable(void __iomem *ioaddr, int queue_num)
+{
+ u32 reg_val;
+
+ reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+ reg_val &= ~(SXGBE_MTL_RXQ_OP_FUP);
+
+ writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+}
+
+
+static void sxgbe_set_tx_mtl_mode(void __iomem *ioaddr, int queue_num,
+ int tx_mode)
+{
+ u32 reg_val;
+
+ reg_val = readl(ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
+ /* TX specific MTL mode settings */
+ if (tx_mode == SXGBE_MTL_SFMODE) {
+ reg_val |= SXGBE_MTL_SFMODE;
+ } else {
+ /* set the TTC values */
+ if (tx_mode <= 64)
+ reg_val |= MTL_CONTROL_TTC_64;
+ else if (tx_mode <= 96)
+ reg_val |= MTL_CONTROL_TTC_96;
+ else if (tx_mode <= 128)
+ reg_val |= MTL_CONTROL_TTC_128;
+ else if (tx_mode <= 192)
+ reg_val |= MTL_CONTROL_TTC_192;
+ else if (tx_mode <= 256)
+ reg_val |= MTL_CONTROL_TTC_256;
+ else if (tx_mode <= 384)
+ reg_val |= MTL_CONTROL_TTC_384;
+ else
+ reg_val |= MTL_CONTROL_TTC_512;
+ }
+
+ /* write into TXQ operation register */
+ writel(reg_val, ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_set_rx_mtl_mode(void __iomem *ioaddr, int queue_num,
+ int rx_mode)
+{
+ u32 reg_val;
+
+ reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+ /* RX specific MTL mode settings */
+ if (rx_mode == SXGBE_RX_MTL_SFMODE) {
+ reg_val |= SXGBE_RX_MTL_SFMODE;
+ } else {
+ if (rx_mode <= 64)
+ reg_val |= MTL_CONTROL_RTC_64;
+ else if (rx_mode <= 96)
+ reg_val |= MTL_CONTROL_RTC_96;
+ else if (rx_mode <= 128)
+ reg_val |= MTL_CONTROL_RTC_128;
+ }
+
+ /* write into RXQ operation register */
+ writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+}
+
+static const struct sxgbe_mtl_ops mtl_ops = {
+ .mtl_set_txfifosize = sxgbe_mtl_set_txfifosize,
+ .mtl_set_rxfifosize = sxgbe_mtl_set_rxfifosize,
+ .mtl_enable_txqueue = sxgbe_mtl_enable_txqueue,
+ .mtl_disable_txqueue = sxgbe_mtl_disable_txqueue,
+ .mtl_dynamic_dma_rxqueue = sxgbe_mtl_dma_dm_rxqueue,
+ .set_tx_mtl_mode = sxgbe_set_tx_mtl_mode,
+ .set_rx_mtl_mode = sxgbe_set_rx_mtl_mode,
+ .mtl_init = sxgbe_mtl_init,
+ .mtl_fc_active = sxgbe_mtl_fc_active,
+ .mtl_fc_deactive = sxgbe_mtl_fc_deactive,
+ .mtl_fc_enable = sxgbe_mtl_fc_enable,
+ .mtl_fep_enable = sxgbe_mtl_fep_enable,
+ .mtl_fep_disable = sxgbe_mtl_fep_disable,
+ .mtl_fup_enable = sxgbe_mtl_fup_enable,
+ .mtl_fup_disable = sxgbe_mtl_fup_disable
+};
+
+const struct sxgbe_mtl_ops *sxgbe_get_mtl_ops(void)
+{
+ return &mtl_ops;
+}
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.h
new file mode 100644
index 000000000000..7e4810c4137e
--- /dev/null
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.h
@@ -0,0 +1,104 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __SXGBE_MTL_H__
+#define __SXGBE_MTL_H__
+
+#define SXGBE_MTL_OPMODE_ESTMASK 0x3
+#define SXGBE_MTL_OPMODE_RAAMASK 0x1
+#define SXGBE_MTL_FCMASK 0x7
+#define SXGBE_MTL_TX_FIFO_DIV 256
+#define SXGBE_MTL_RX_FIFO_DIV 256
+
+#define SXGBE_MTL_RXQ_OP_FEP BIT(4)
+#define SXGBE_MTL_RXQ_OP_FUP BIT(3)
+#define SXGBE_MTL_ENABLE_FC 0x80
+
+#define ETS_WRR 0xFFFFFF9F
+#define ETS_RST 0xFFFFFF9F
+#define ETS_WFQ 0x00000020
+#define ETS_DWRR 0x00000040
+#define RAA_SP 0xFFFFFFFB
+#define RAA_WSP 0x00000004
+
+#define RX_QUEUE_DYNAMIC 0x80808080
+#define RX_FC_ACTIVE 8
+#define RX_FC_DEACTIVE 13
+
+enum ttc_control {
+ MTL_CONTROL_TTC_64 = 0x00000000,
+ MTL_CONTROL_TTC_96 = 0x00000020,
+ MTL_CONTROL_TTC_128 = 0x00000030,
+ MTL_CONTROL_TTC_192 = 0x00000040,
+ MTL_CONTROL_TTC_256 = 0x00000050,
+ MTL_CONTROL_TTC_384 = 0x00000060,
+ MTL_CONTROL_TTC_512 = 0x00000070,
+};
+
+enum rtc_control {
+ MTL_CONTROL_RTC_64 = 0x00000000,
+ MTL_CONTROL_RTC_96 = 0x00000002,
+ MTL_CONTROL_RTC_128 = 0x00000003,
+};
+
+enum flow_control_th {
+ MTL_FC_FULL_1K = 0x00000000,
+ MTL_FC_FULL_2K = 0x00000001,
+ MTL_FC_FULL_4K = 0x00000002,
+ MTL_FC_FULL_5K = 0x00000003,
+ MTL_FC_FULL_6K = 0x00000004,
+ MTL_FC_FULL_8K = 0x00000005,
+ MTL_FC_FULL_16K = 0x00000006,
+ MTL_FC_FULL_24K = 0x00000007,
+};
+
+struct sxgbe_mtl_ops {
+ void (*mtl_init)(void __iomem *ioaddr, unsigned int etsalg,
+ unsigned int raa);
+
+ void (*mtl_set_txfifosize)(void __iomem *ioaddr, int queue_num,
+ int mtl_fifo);
+
+ void (*mtl_set_rxfifosize)(void __iomem *ioaddr, int queue_num,
+ int queue_fifo);
+
+ void (*mtl_enable_txqueue)(void __iomem *ioaddr, int queue_num);
+
+ void (*mtl_disable_txqueue)(void __iomem *ioaddr, int queue_num);
+
+ void (*set_tx_mtl_mode)(void __iomem *ioaddr, int queue_num,
+ int tx_mode);
+
+ void (*set_rx_mtl_mode)(void __iomem *ioaddr, int queue_num,
+ int rx_mode);
+
+ void (*mtl_dynamic_dma_rxqueue)(void __iomem *ioaddr);
+
+ void (*mtl_fc_active)(void __iomem *ioaddr, int queue_num,
+ int threshold);
+
+ void (*mtl_fc_deactive)(void __iomem *ioaddr, int queue_num,
+ int threshold);
+
+ void (*mtl_fc_enable)(void __iomem *ioaddr, int queue_num);
+
+ void (*mtl_fep_enable)(void __iomem *ioaddr, int queue_num);
+
+ void (*mtl_fep_disable)(void __iomem *ioaddr, int queue_num);
+
+ void (*mtl_fup_enable)(void __iomem *ioaddr, int queue_num);
+
+ void (*mtl_fup_disable)(void __iomem *ioaddr, int queue_num);
+};
+
+const struct sxgbe_mtl_ops *sxgbe_get_mtl_ops(void);
+
+#endif /* __SXGBE_MTL_H__ */
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c
new file mode 100644
index 000000000000..b147d469a799
--- /dev/null
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c
@@ -0,0 +1,259 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/etherdevice.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_net.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/sxgbe_platform.h>
+
+#include "sxgbe_common.h"
+#include "sxgbe_reg.h"
+
+#ifdef CONFIG_OF
+static int sxgbe_probe_config_dt(struct platform_device *pdev,
+ struct sxgbe_plat_data *plat,
+ const char **mac)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct sxgbe_dma_cfg *dma_cfg;
+
+ if (!np)
+ return -ENODEV;
+
+ *mac = of_get_mac_address(np);
+ plat->interface = of_get_phy_mode(np);
+
+ plat->bus_id = of_alias_get_id(np, "ethernet");
+ if (plat->bus_id < 0)
+ plat->bus_id = 0;
+
+ plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
+ sizeof(*plat->mdio_bus_data),
+ GFP_KERNEL);
+
+ 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, "samsung,pbl", &dma_cfg->pbl);
+ if (of_property_read_u32(np, "samsung,burst-map", &dma_cfg->burst_map) == 0)
+ dma_cfg->fixed_burst = true;
+
+ return 0;
+}
+#else
+static int sxgbe_probe_config_dt(struct platform_device *pdev,
+ struct sxgbe_plat_data *plat,
+ const char **mac)
+{
+ return -ENOSYS;
+}
+#endif /* CONFIG_OF */
+
+/**
+ * sxgbe_platform_probe
+ * @pdev: platform device pointer
+ * Description: platform_device probe function. It allocates
+ * the necessary resources and invokes the main to init
+ * the net device, register the mdio bus etc.
+ */
+static int sxgbe_platform_probe(struct platform_device *pdev)
+{
+ int ret;
+ int i, chan;
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ void __iomem *addr;
+ struct sxgbe_priv_data *priv = NULL;
+ struct sxgbe_plat_data *plat_dat = NULL;
+ const char *mac = NULL;
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct device_node *node = dev->of_node;
+
+ /* Get memory resource */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ goto err_out;
+
+ addr = devm_ioremap_resource(dev, res);
+ if (IS_ERR(addr))
+ return PTR_ERR(addr);
+
+ if (pdev->dev.of_node) {
+ plat_dat = devm_kzalloc(&pdev->dev,
+ sizeof(struct sxgbe_plat_data),
+ GFP_KERNEL);
+ if (!plat_dat)
+ return -ENOMEM;
+
+ ret = sxgbe_probe_config_dt(pdev, plat_dat, &mac);
+ if (ret) {
+ pr_err("%s: main dt probe failed\n", __func__);
+ return ret;
+ }
+ }
+
+ /* Get MAC address if available (DT) */
+ if (mac)
+ ether_addr_copy(priv->dev->dev_addr, mac);
+
+ priv = sxgbe_drv_probe(&(pdev->dev), plat_dat, addr);
+ if (!priv) {
+ pr_err("%s: main driver probe failed\n", __func__);
+ goto err_out;
+ }
+
+ /* Get the SXGBE common INT information */
+ priv->irq = irq_of_parse_and_map(node, 0);
+ if (priv->irq <= 0) {
+ dev_err(dev, "sxgbe common irq parsing failed\n");
+ goto err_drv_remove;
+ }
+
+ /* Get the TX/RX IRQ numbers */
+ for (i = 0, chan = 1; i < SXGBE_TX_QUEUES; i++) {
+ priv->txq[i]->irq_no = irq_of_parse_and_map(node, chan++);
+ if (priv->txq[i]->irq_no <= 0) {
+ dev_err(dev, "sxgbe tx irq parsing failed\n");
+ goto err_tx_irq_unmap;
+ }
+ }
+
+ for (i = 0; i < SXGBE_RX_QUEUES; i++) {
+ priv->rxq[i]->irq_no = irq_of_parse_and_map(node, chan++);
+ if (priv->rxq[i]->irq_no <= 0) {
+ dev_err(dev, "sxgbe rx irq parsing failed\n");
+ goto err_rx_irq_unmap;
+ }
+ }
+
+ priv->lpi_irq = irq_of_parse_and_map(node, chan);
+ if (priv->lpi_irq <= 0) {
+ dev_err(dev, "sxgbe lpi irq parsing failed\n");
+ goto err_rx_irq_unmap;
+ }
+
+ platform_set_drvdata(pdev, priv->dev);
+
+ pr_debug("platform driver registration completed\n");
+
+ return 0;
+
+err_rx_irq_unmap:
+ while (--i)
+ irq_dispose_mapping(priv->rxq[i]->irq_no);
+ i = SXGBE_TX_QUEUES;
+err_tx_irq_unmap:
+ while (--i)
+ irq_dispose_mapping(priv->txq[i]->irq_no);
+ irq_dispose_mapping(priv->irq);
+err_drv_remove:
+ sxgbe_drv_remove(ndev);
+err_out:
+ return -ENODEV;
+}
+
+/**
+ * sxgbe_platform_remove
+ * @pdev: platform device pointer
+ * Description: this function calls the main to free the net resources
+ * and calls the platforms hook and release the resources (e.g. mem).
+ */
+static int sxgbe_platform_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ int ret = sxgbe_drv_remove(ndev);
+
+ return ret;
+}
+
+#ifdef CONFIG_PM
+static int sxgbe_platform_suspend(struct device *dev)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+
+ return sxgbe_suspend(ndev);
+}
+
+static int sxgbe_platform_resume(struct device *dev)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+
+ return sxgbe_resume(ndev);
+}
+
+static int sxgbe_platform_freeze(struct device *dev)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+
+ return sxgbe_freeze(ndev);
+}
+
+static int sxgbe_platform_restore(struct device *dev)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+
+ return sxgbe_restore(ndev);
+}
+
+static const struct dev_pm_ops sxgbe_platform_pm_ops = {
+ .suspend = sxgbe_platform_suspend,
+ .resume = sxgbe_platform_resume,
+ .freeze = sxgbe_platform_freeze,
+ .thaw = sxgbe_platform_restore,
+ .restore = sxgbe_platform_restore,
+};
+#else
+static const struct dev_pm_ops sxgbe_platform_pm_ops;
+#endif /* CONFIG_PM */
+
+static const struct of_device_id sxgbe_dt_ids[] = {
+ { .compatible = "samsung,sxgbe-v2.0a"},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sxgbe_dt_ids);
+
+static struct platform_driver sxgbe_platform_driver = {
+ .probe = sxgbe_platform_probe,
+ .remove = sxgbe_platform_remove,
+ .driver = {
+ .name = SXGBE_RESOURCE_NAME,
+ .owner = THIS_MODULE,
+ .pm = &sxgbe_platform_pm_ops,
+ .of_match_table = of_match_ptr(sxgbe_dt_ids),
+ },
+};
+
+int sxgbe_register_platform(void)
+{
+ int err;
+
+ err = platform_driver_register(&sxgbe_platform_driver);
+ if (err)
+ pr_err("failed to register the platform driver\n");
+
+ return err;
+}
+
+void sxgbe_unregister_platform(void)
+{
+ platform_driver_unregister(&sxgbe_platform_driver);
+}
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h
new file mode 100644
index 000000000000..5a89acb4c505
--- /dev/null
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h
@@ -0,0 +1,488 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __SXGBE_REGMAP_H__
+#define __SXGBE_REGMAP_H__
+
+/* SXGBE MAC Registers */
+#define SXGBE_CORE_TX_CONFIG_REG 0x0000
+#define SXGBE_CORE_RX_CONFIG_REG 0x0004
+#define SXGBE_CORE_PKT_FILTER_REG 0x0008
+#define SXGBE_CORE_WATCHDOG_TIMEOUT_REG 0x000C
+#define SXGBE_CORE_HASH_TABLE_REG0 0x0010
+#define SXGBE_CORE_HASH_TABLE_REG1 0x0014
+#define SXGBE_CORE_HASH_TABLE_REG2 0x0018
+#define SXGBE_CORE_HASH_TABLE_REG3 0x001C
+#define SXGBE_CORE_HASH_TABLE_REG4 0x0020
+#define SXGBE_CORE_HASH_TABLE_REG5 0x0024
+#define SXGBE_CORE_HASH_TABLE_REG6 0x0028
+#define SXGBE_CORE_HASH_TABLE_REG7 0x002C
+
+/* EEE-LPI Registers */
+#define SXGBE_CORE_LPI_CTRL_STATUS 0x00D0
+#define SXGBE_CORE_LPI_TIMER_CTRL 0x00D4
+
+/* VLAN Specific Registers */
+#define SXGBE_CORE_VLAN_TAG_REG 0x0050
+#define SXGBE_CORE_VLAN_HASHTAB_REG 0x0058
+#define SXGBE_CORE_VLAN_INSCTL_REG 0x0060
+#define SXGBE_CORE_VLAN_INNERCTL_REG 0x0064
+#define SXGBE_CORE_RX_ETHTYPE_MATCH_REG 0x006C
+
+/* Flow Contol Registers */
+#define SXGBE_CORE_TX_Q0_FLOWCTL_REG 0x0070
+#define SXGBE_CORE_TX_Q1_FLOWCTL_REG 0x0074
+#define SXGBE_CORE_TX_Q2_FLOWCTL_REG 0x0078
+#define SXGBE_CORE_TX_Q3_FLOWCTL_REG 0x007C
+#define SXGBE_CORE_TX_Q4_FLOWCTL_REG 0x0080
+#define SXGBE_CORE_TX_Q5_FLOWCTL_REG 0x0084
+#define SXGBE_CORE_TX_Q6_FLOWCTL_REG 0x0088
+#define SXGBE_CORE_TX_Q7_FLOWCTL_REG 0x008C
+#define SXGBE_CORE_RX_FLOWCTL_REG 0x0090
+#define SXGBE_CORE_RX_CTL0_REG 0x00A0
+#define SXGBE_CORE_RX_CTL1_REG 0x00A4
+#define SXGBE_CORE_RX_CTL2_REG 0x00A8
+#define SXGBE_CORE_RX_CTL3_REG 0x00AC
+
+/* Interrupt Registers */
+#define SXGBE_CORE_INT_STATUS_REG 0x00B0
+#define SXGBE_CORE_INT_ENABLE_REG 0x00B4
+#define SXGBE_CORE_RXTX_ERR_STATUS_REG 0x00B8
+#define SXGBE_CORE_PMT_CTL_STATUS_REG 0x00C0
+#define SXGBE_CORE_RWK_PKT_FILTER_REG 0x00C4
+#define SXGBE_CORE_VERSION_REG 0x0110
+#define SXGBE_CORE_DEBUG_REG 0x0114
+#define SXGBE_CORE_HW_FEA_REG(index) (0x011C + index * 4)
+
+/* SMA(MDIO) module registers */
+#define SXGBE_MDIO_SCMD_ADD_REG 0x0200
+#define SXGBE_MDIO_SCMD_DATA_REG 0x0204
+#define SXGBE_MDIO_CCMD_WADD_REG 0x0208
+#define SXGBE_MDIO_CCMD_WDATA_REG 0x020C
+#define SXGBE_MDIO_CSCAN_PORT_REG 0x0210
+#define SXGBE_MDIO_INT_STATUS_REG 0x0214
+#define SXGBE_MDIO_INT_ENABLE_REG 0x0218
+#define SXGBE_MDIO_PORT_CONDCON_REG 0x021C
+#define SXGBE_MDIO_CLAUSE22_PORT_REG 0x0220
+
+/* port specific, addr = 0-3 */
+#define SXGBE_MDIO_DEV_BASE_REG 0x0230
+#define SXGBE_MDIO_PORT_DEV_REG(addr) \
+ (SXGBE_MDIO_DEV_BASE_REG + (0x10 * addr) + 0x0)
+#define SXGBE_MDIO_PORT_LSTATUS_REG(addr) \
+ (SXGBE_MDIO_DEV_BASE_REG + (0x10 * addr) + 0x4)
+#define SXGBE_MDIO_PORT_ALIVE_REG(addr) \
+ (SXGBE_MDIO_DEV_BASE_REG + (0x10 * addr) + 0x8)
+
+#define SXGBE_CORE_GPIO_CTL_REG 0x0278
+#define SXGBE_CORE_GPIO_STATUS_REG 0x027C
+
+/* Address registers for filtering */
+#define SXGBE_CORE_ADD_BASE_REG 0x0300
+
+/* addr = 0-31 */
+#define SXGBE_CORE_ADD_HIGHOFFSET(addr) \
+ (SXGBE_CORE_ADD_BASE_REG + (0x8 * addr) + 0x0)
+#define SXGBE_CORE_ADD_LOWOFFSET(addr) \
+ (SXGBE_CORE_ADD_BASE_REG + (0x8 * addr) + 0x4)
+
+/* SXGBE MMC registers */
+#define SXGBE_MMC_CTL_REG 0x0800
+#define SXGBE_MMC_RXINT_STATUS_REG 0x0804
+#define SXGBE_MMC_TXINT_STATUS_REG 0x0808
+#define SXGBE_MMC_RXINT_ENABLE_REG 0x080C
+#define SXGBE_MMC_TXINT_ENABLE_REG 0x0810
+
+/* TX specific counters */
+#define SXGBE_MMC_TXOCTETHI_GBCNT_REG 0x0814
+#define SXGBE_MMC_TXOCTETLO_GBCNT_REG 0x0818
+#define SXGBE_MMC_TXFRAMELO_GBCNT_REG 0x081C
+#define SXGBE_MMC_TXFRAMEHI_GBCNT_REG 0x0820
+#define SXGBE_MMC_TXBROADLO_GCNT_REG 0x0824
+#define SXGBE_MMC_TXBROADHI_GCNT_REG 0x0828
+#define SXGBE_MMC_TXMULTILO_GCNT_REG 0x082C
+#define SXGBE_MMC_TXMULTIHI_GCNT_REG 0x0830
+#define SXGBE_MMC_TX64LO_GBCNT_REG 0x0834
+#define SXGBE_MMC_TX64HI_GBCNT_REG 0x0838
+#define SXGBE_MMC_TX65TO127LO_GBCNT_REG 0x083C
+#define SXGBE_MMC_TX65TO127HI_GBCNT_REG 0x0840
+#define SXGBE_MMC_TX128TO255LO_GBCNT_REG 0x0844
+#define SXGBE_MMC_TX128TO255HI_GBCNT_REG 0x0848
+#define SXGBE_MMC_TX256TO511LO_GBCNT_REG 0x084C
+#define SXGBE_MMC_TX256TO511HI_GBCNT_REG 0x0850
+#define SXGBE_MMC_TX512TO1023LO_GBCNT_REG 0x0854
+#define SXGBE_MMC_TX512TO1023HI_GBCNT_REG 0x0858
+#define SXGBE_MMC_TX1023TOMAXLO_GBCNT_REG 0x085C
+#define SXGBE_MMC_TX1023TOMAXHI_GBCNT_REG 0x0860
+#define SXGBE_MMC_TXUNICASTLO_GBCNT_REG 0x0864
+#define SXGBE_MMC_TXUNICASTHI_GBCNT_REG 0x0868
+#define SXGBE_MMC_TXMULTILO_GBCNT_REG 0x086C
+#define SXGBE_MMC_TXMULTIHI_GBCNT_REG 0x0870
+#define SXGBE_MMC_TXBROADLO_GBCNT_REG 0x0874
+#define SXGBE_MMC_TXBROADHI_GBCNT_REG 0x0878
+#define SXGBE_MMC_TXUFLWLO_GBCNT_REG 0x087C
+#define SXGBE_MMC_TXUFLWHI_GBCNT_REG 0x0880
+#define SXGBE_MMC_TXOCTETLO_GCNT_REG 0x0884
+#define SXGBE_MMC_TXOCTETHI_GCNT_REG 0x0888
+#define SXGBE_MMC_TXFRAMELO_GCNT_REG 0x088C
+#define SXGBE_MMC_TXFRAMEHI_GCNT_REG 0x0890
+#define SXGBE_MMC_TXPAUSELO_CNT_REG 0x0894
+#define SXGBE_MMC_TXPAUSEHI_CNT_REG 0x0898
+#define SXGBE_MMC_TXVLANLO_GCNT_REG 0x089C
+#define SXGBE_MMC_TXVLANHI_GCNT_REG 0x08A0
+
+/* RX specific counters */
+#define SXGBE_MMC_RXFRAMELO_GBCNT_REG 0x0900
+#define SXGBE_MMC_RXFRAMEHI_GBCNT_REG 0x0904
+#define SXGBE_MMC_RXOCTETLO_GBCNT_REG 0x0908
+#define SXGBE_MMC_RXOCTETHI_GBCNT_REG 0x090C
+#define SXGBE_MMC_RXOCTETLO_GCNT_REG 0x0910
+#define SXGBE_MMC_RXOCTETHI_GCNT_REG 0x0914
+#define SXGBE_MMC_RXBROADLO_GCNT_REG 0x0918
+#define SXGBE_MMC_RXBROADHI_GCNT_REG 0x091C
+#define SXGBE_MMC_RXMULTILO_GCNT_REG 0x0920
+#define SXGBE_MMC_RXMULTIHI_GCNT_REG 0x0924
+#define SXGBE_MMC_RXCRCERRLO_REG 0x0928
+#define SXGBE_MMC_RXCRCERRHI_REG 0x092C
+#define SXGBE_MMC_RXSHORT64BFRAME_ERR_REG 0x0930
+#define SXGBE_MMC_RXJABBERERR_REG 0x0934
+#define SXGBE_MMC_RXSHORT64BFRAME_COR_REG 0x0938
+#define SXGBE_MMC_RXOVERMAXFRAME_COR_REG 0x093C
+#define SXGBE_MMC_RX64LO_GBCNT_REG 0x0940
+#define SXGBE_MMC_RX64HI_GBCNT_REG 0x0944
+#define SXGBE_MMC_RX65TO127LO_GBCNT_REG 0x0948
+#define SXGBE_MMC_RX65TO127HI_GBCNT_REG 0x094C
+#define SXGBE_MMC_RX128TO255LO_GBCNT_REG 0x0950
+#define SXGBE_MMC_RX128TO255HI_GBCNT_REG 0x0954
+#define SXGBE_MMC_RX256TO511LO_GBCNT_REG 0x0958
+#define SXGBE_MMC_RX256TO511HI_GBCNT_REG 0x095C
+#define SXGBE_MMC_RX512TO1023LO_GBCNT_REG 0x0960
+#define SXGBE_MMC_RX512TO1023HI_GBCNT_REG 0x0964
+#define SXGBE_MMC_RX1023TOMAXLO_GBCNT_REG 0x0968
+#define SXGBE_MMC_RX1023TOMAXHI_GBCNT_REG 0x096C
+#define SXGBE_MMC_RXUNICASTLO_GCNT_REG 0x0970
+#define SXGBE_MMC_RXUNICASTHI_GCNT_REG 0x0974
+#define SXGBE_MMC_RXLENERRLO_REG 0x0978
+#define SXGBE_MMC_RXLENERRHI_REG 0x097C
+#define SXGBE_MMC_RXOUTOFRANGETYPELO_REG 0x0980
+#define SXGBE_MMC_RXOUTOFRANGETYPEHI_REG 0x0984
+#define SXGBE_MMC_RXPAUSELO_CNT_REG 0x0988
+#define SXGBE_MMC_RXPAUSEHI_CNT_REG 0x098C
+#define SXGBE_MMC_RXFIFOOVERFLOWLO_GBCNT_REG 0x0990
+#define SXGBE_MMC_RXFIFOOVERFLOWHI_GBCNT_REG 0x0994
+#define SXGBE_MMC_RXVLANLO_GBCNT_REG 0x0998
+#define SXGBE_MMC_RXVLANHI_GBCNT_REG 0x099C
+#define SXGBE_MMC_RXWATCHDOG_ERR_REG 0x09A0
+
+/* L3/L4 function registers */
+#define SXGBE_CORE_L34_ADDCTL_REG 0x0C00
+#define SXGBE_CORE_L34_ADDCTL_REG 0x0C00
+#define SXGBE_CORE_L34_DATA_REG 0x0C04
+
+/* ARP registers */
+#define SXGBE_CORE_ARP_ADD_REG 0x0C10
+
+/* RSS registers */
+#define SXGBE_CORE_RSS_CTL_REG 0x0C80
+#define SXGBE_CORE_RSS_ADD_REG 0x0C88
+#define SXGBE_CORE_RSS_DATA_REG 0x0C8C
+
+/* RSS control register bits */
+#define SXGBE_CORE_RSS_CTL_UDP4TE BIT(3)
+#define SXGBE_CORE_RSS_CTL_TCP4TE BIT(2)
+#define SXGBE_CORE_RSS_CTL_IP2TE BIT(1)
+#define SXGBE_CORE_RSS_CTL_RSSE BIT(0)
+
+/* IEEE 1588 registers */
+#define SXGBE_CORE_TSTAMP_CTL_REG 0x0D00
+#define SXGBE_CORE_SUBSEC_INC_REG 0x0D04
+#define SXGBE_CORE_SYSTIME_SEC_REG 0x0D0C
+#define SXGBE_CORE_SYSTIME_NSEC_REG 0x0D10
+#define SXGBE_CORE_SYSTIME_SECUP_REG 0x0D14
+#define SXGBE_CORE_TSTAMP_ADD_REG 0x0D18
+#define SXGBE_CORE_SYSTIME_HWORD_REG 0x0D1C
+#define SXGBE_CORE_TSTAMP_STATUS_REG 0x0D20
+#define SXGBE_CORE_TXTIME_STATUSNSEC_REG 0x0D30
+#define SXGBE_CORE_TXTIME_STATUSSEC_REG 0x0D34
+
+/* Auxiliary registers */
+#define SXGBE_CORE_AUX_CTL_REG 0x0D40
+#define SXGBE_CORE_AUX_TSTAMP_NSEC_REG 0x0D48
+#define SXGBE_CORE_AUX_TSTAMP_SEC_REG 0x0D4C
+#define SXGBE_CORE_AUX_TSTAMP_INGCOR_REG 0x0D50
+#define SXGBE_CORE_AUX_TSTAMP_ENGCOR_REG 0x0D54
+#define SXGBE_CORE_AUX_TSTAMP_INGCOR_NSEC_REG 0x0D58
+#define SXGBE_CORE_AUX_TSTAMP_INGCOR_SUBNSEC_REG 0x0D5C
+#define SXGBE_CORE_AUX_TSTAMP_ENGCOR_NSEC_REG 0x0D60
+#define SXGBE_CORE_AUX_TSTAMP_ENGCOR_SUBNSEC_REG 0x0D64
+
+/* PPS registers */
+#define SXGBE_CORE_PPS_CTL_REG 0x0D70
+#define SXGBE_CORE_PPS_BASE 0x0D80
+
+/* addr = 0 - 3 */
+#define SXGBE_CORE_PPS_TTIME_SEC_REG(addr) \
+ (SXGBE_CORE_PPS_BASE + (0x10 * addr) + 0x0)
+#define SXGBE_CORE_PPS_TTIME_NSEC_REG(addr) \
+ (SXGBE_CORE_PPS_BASE + (0x10 * addr) + 0x4)
+#define SXGBE_CORE_PPS_INTERVAL_REG(addr) \
+ (SXGBE_CORE_PPS_BASE + (0x10 * addr) + 0x8)
+#define SXGBE_CORE_PPS_WIDTH_REG(addr) \
+ (SXGBE_CORE_PPS_BASE + (0x10 * addr) + 0xC)
+#define SXGBE_CORE_PTO_CTL_REG 0x0DC0
+#define SXGBE_CORE_SRCPORT_ITY0_REG 0x0DC4
+#define SXGBE_CORE_SRCPORT_ITY1_REG 0x0DC8
+#define SXGBE_CORE_SRCPORT_ITY2_REG 0x0DCC
+#define SXGBE_CORE_LOGMSG_LEVEL_REG 0x0DD0
+
+/* SXGBE MTL Registers */
+#define SXGBE_MTL_BASE_REG 0x1000
+#define SXGBE_MTL_OP_MODE_REG (SXGBE_MTL_BASE_REG + 0x0000)
+#define SXGBE_MTL_DEBUG_CTL_REG (SXGBE_MTL_BASE_REG + 0x0008)
+#define SXGBE_MTL_DEBUG_STATUS_REG (SXGBE_MTL_BASE_REG + 0x000C)
+#define SXGBE_MTL_FIFO_DEBUGDATA_REG (SXGBE_MTL_BASE_REG + 0x0010)
+#define SXGBE_MTL_INT_STATUS_REG (SXGBE_MTL_BASE_REG + 0x0020)
+#define SXGBE_MTL_RXQ_DMAMAP0_REG (SXGBE_MTL_BASE_REG + 0x0030)
+#define SXGBE_MTL_RXQ_DMAMAP1_REG (SXGBE_MTL_BASE_REG + 0x0034)
+#define SXGBE_MTL_RXQ_DMAMAP2_REG (SXGBE_MTL_BASE_REG + 0x0038)
+#define SXGBE_MTL_TX_PRTYMAP0_REG (SXGBE_MTL_BASE_REG + 0x0040)
+#define SXGBE_MTL_TX_PRTYMAP1_REG (SXGBE_MTL_BASE_REG + 0x0044)
+
+/* TC/Queue registers, qnum=0-15 */
+#define SXGBE_MTL_TC_TXBASE_REG (SXGBE_MTL_BASE_REG + 0x0100)
+#define SXGBE_MTL_TXQ_OPMODE_REG(qnum) \
+ (SXGBE_MTL_TC_TXBASE_REG + (qnum * 0x80) + 0x00)
+#define SXGBE_MTL_SFMODE BIT(1)
+#define SXGBE_MTL_FIFO_LSHIFT 16
+#define SXGBE_MTL_ENABLE_QUEUE 0x00000008
+#define SXGBE_MTL_TXQ_UNDERFLOW_REG(qnum) \
+ (SXGBE_MTL_TC_TXBASE_REG + (qnum * 0x80) + 0x04)
+#define SXGBE_MTL_TXQ_DEBUG_REG(qnum) \
+ (SXGBE_MTL_TC_TXBASE_REG + (qnum * 0x80) + 0x08)
+#define SXGBE_MTL_TXQ_ETSCTL_REG(qnum) \
+ (SXGBE_MTL_TC_TXBASE_REG + (qnum * 0x80) + 0x10)
+#define SXGBE_MTL_TXQ_ETSSTATUS_REG(qnum) \
+ (SXGBE_MTL_TC_TXBASE_REG + (qnum * 0x80) + 0x14)
+#define SXGBE_MTL_TXQ_QUANTWEIGHT_REG(qnum) \
+ (SXGBE_MTL_TC_TXBASE_REG + (qnum * 0x80) + 0x18)
+
+#define SXGBE_MTL_TC_RXBASE_REG 0x1140
+#define SXGBE_RX_MTL_SFMODE BIT(5)
+#define SXGBE_MTL_RXQ_OPMODE_REG(qnum) \
+ (SXGBE_MTL_TC_RXBASE_REG + (qnum * 0x80) + 0x00)
+#define SXGBE_MTL_RXQ_MISPKTOVERFLOW_REG(qnum) \
+ (SXGBE_MTL_TC_RXBASE_REG + (qnum * 0x80) + 0x04)
+#define SXGBE_MTL_RXQ_DEBUG_REG(qnum) \
+ (SXGBE_MTL_TC_RXBASE_REG + (qnum * 0x80) + 0x08)
+#define SXGBE_MTL_RXQ_CTL_REG(qnum) \
+ (SXGBE_MTL_TC_RXBASE_REG + (qnum * 0x80) + 0x0C)
+#define SXGBE_MTL_RXQ_INTENABLE_REG(qnum) \
+ (SXGBE_MTL_TC_RXBASE_REG + (qnum * 0x80) + 0x30)
+#define SXGBE_MTL_RXQ_INTSTATUS_REG(qnum) \
+ (SXGBE_MTL_TC_RXBASE_REG + (qnum * 0x80) + 0x34)
+
+/* SXGBE DMA Registers */
+#define SXGBE_DMA_BASE_REG 0x3000
+#define SXGBE_DMA_MODE_REG (SXGBE_DMA_BASE_REG + 0x0000)
+#define SXGBE_DMA_SOFT_RESET BIT(0)
+#define SXGBE_DMA_SYSBUS_MODE_REG (SXGBE_DMA_BASE_REG + 0x0004)
+#define SXGBE_DMA_AXI_UNDEF_BURST BIT(0)
+#define SXGBE_DMA_ENHACE_ADDR_MODE BIT(11)
+#define SXGBE_DMA_INT_STATUS_REG (SXGBE_DMA_BASE_REG + 0x0008)
+#define SXGBE_DMA_AXI_ARCACHECTL_REG (SXGBE_DMA_BASE_REG + 0x0010)
+#define SXGBE_DMA_AXI_AWCACHECTL_REG (SXGBE_DMA_BASE_REG + 0x0018)
+#define SXGBE_DMA_DEBUG_STATUS0_REG (SXGBE_DMA_BASE_REG + 0x0020)
+#define SXGBE_DMA_DEBUG_STATUS1_REG (SXGBE_DMA_BASE_REG + 0x0024)
+#define SXGBE_DMA_DEBUG_STATUS2_REG (SXGBE_DMA_BASE_REG + 0x0028)
+#define SXGBE_DMA_DEBUG_STATUS3_REG (SXGBE_DMA_BASE_REG + 0x002C)
+#define SXGBE_DMA_DEBUG_STATUS4_REG (SXGBE_DMA_BASE_REG + 0x0030)
+#define SXGBE_DMA_DEBUG_STATUS5_REG (SXGBE_DMA_BASE_REG + 0x0034)
+
+/* Channel Registers, cha_num = 0-15 */
+#define SXGBE_DMA_CHA_BASE_REG \
+ (SXGBE_DMA_BASE_REG + 0x0100)
+#define SXGBE_DMA_CHA_CTL_REG(cha_num) \
+ (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x00)
+#define SXGBE_DMA_PBL_X8MODE BIT(16)
+#define SXGBE_DMA_CHA_TXCTL_TSE_ENABLE BIT(12)
+#define SXGBE_DMA_CHA_TXCTL_REG(cha_num) \
+ (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x04)
+#define SXGBE_DMA_CHA_RXCTL_REG(cha_num) \
+ (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x08)
+#define SXGBE_DMA_CHA_TXDESC_HADD_REG(cha_num) \
+ (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x10)
+#define SXGBE_DMA_CHA_TXDESC_LADD_REG(cha_num) \
+ (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x14)
+#define SXGBE_DMA_CHA_RXDESC_HADD_REG(cha_num) \
+ (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x18)
+#define SXGBE_DMA_CHA_RXDESC_LADD_REG(cha_num) \
+ (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x1C)
+#define SXGBE_DMA_CHA_TXDESC_TAILPTR_REG(cha_num) \
+ (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x24)
+#define SXGBE_DMA_CHA_RXDESC_TAILPTR_REG(cha_num) \
+ (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x2C)
+#define SXGBE_DMA_CHA_TXDESC_RINGLEN_REG(cha_num) \
+ (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x30)
+#define SXGBE_DMA_CHA_RXDESC_RINGLEN_REG(cha_num) \
+ (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x34)
+#define SXGBE_DMA_CHA_INT_ENABLE_REG(cha_num) \
+ (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x38)
+#define SXGBE_DMA_CHA_INT_RXWATCHTMR_REG(cha_num) \
+ (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x3C)
+#define SXGBE_DMA_CHA_TXDESC_CURADDLO_REG(cha_num) \
+ (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x44)
+#define SXGBE_DMA_CHA_RXDESC_CURADDLO_REG(cha_num) \
+ (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x4C)
+#define SXGBE_DMA_CHA_CURTXBUF_ADDHI_REG(cha_num) \
+ (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x50)
+#define SXGBE_DMA_CHA_CURTXBUF_ADDLO_REG(cha_num) \
+ (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x54)
+#define SXGBE_DMA_CHA_CURRXBUF_ADDHI_REG(cha_num) \
+ (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x58)
+#define SXGBE_DMA_CHA_CURRXBUF_ADDLO_REG(cha_num) \
+ (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x5C)
+#define SXGBE_DMA_CHA_STATUS_REG(cha_num) \
+ (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x60)
+
+/* TX DMA control register specific */
+#define SXGBE_TX_START_DMA BIT(0)
+
+/* sxgbe tx configuration register bitfields */
+#define SXGBE_SPEED_10G 0x0
+#define SXGBE_SPEED_2_5G 0x1
+#define SXGBE_SPEED_1G 0x2
+#define SXGBE_SPEED_LSHIFT 29
+
+#define SXGBE_TX_ENABLE BIT(0)
+#define SXGBE_TX_DISDIC_ALGO BIT(1)
+#define SXGBE_TX_JABBER_DISABLE BIT(16)
+
+/* sxgbe rx configuration register bitfields */
+#define SXGBE_RX_ENABLE BIT(0)
+#define SXGBE_RX_ACS_ENABLE BIT(1)
+#define SXGBE_RX_WATCHDOG_DISABLE BIT(7)
+#define SXGBE_RX_JUMBPKT_ENABLE BIT(8)
+#define SXGBE_RX_CSUMOFFLOAD_ENABLE BIT(9)
+#define SXGBE_RX_LOOPBACK_ENABLE BIT(10)
+#define SXGBE_RX_ARPOFFLOAD_ENABLE BIT(31)
+
+/* sxgbe vlan Tag Register bitfields */
+#define SXGBE_VLAN_SVLAN_ENABLE BIT(18)
+#define SXGBE_VLAN_DOUBLEVLAN_ENABLE BIT(26)
+#define SXGBE_VLAN_INNERVLAN_ENABLE BIT(27)
+
+/* XMAC VLAN Tag Inclusion Register(0x0060) bitfields
+ * Below fields same for Inner VLAN Tag Inclusion
+ * Register(0x0064) register
+ */
+enum vlan_tag_ctl_tx {
+ VLAN_TAG_TX_NOP,
+ VLAN_TAG_TX_DEL,
+ VLAN_TAG_TX_INSERT,
+ VLAN_TAG_TX_REPLACE
+};
+#define SXGBE_VLAN_PRTY_CTL BIT(18)
+#define SXGBE_VLAN_CSVL_CTL BIT(19)
+
+/* SXGBE TX Q Flow Control Register bitfields */
+#define SXGBE_TX_FLOW_CTL_FCB BIT(0)
+#define SXGBE_TX_FLOW_CTL_TFB BIT(1)
+
+/* SXGBE RX Q Flow Control Register bitfields */
+#define SXGBE_RX_FLOW_CTL_ENABLE BIT(0)
+#define SXGBE_RX_UNICAST_DETECT BIT(1)
+#define SXGBE_RX_PRTYFLOW_CTL_ENABLE BIT(8)
+
+/* sxgbe rx Q control0 register bitfields */
+#define SXGBE_RX_Q_ENABLE 0x2
+
+/* SXGBE hardware features bitfield specific */
+/* Capability Register 0 */
+#define SXGBE_HW_FEAT_GMII(cap) ((cap & 0x00000002) >> 1)
+#define SXGBE_HW_FEAT_VLAN_HASH_FILTER(cap) ((cap & 0x00000010) >> 4)
+#define SXGBE_HW_FEAT_SMA(cap) ((cap & 0x00000020) >> 5)
+#define SXGBE_HW_FEAT_PMT_TEMOTE_WOP(cap) ((cap & 0x00000040) >> 6)
+#define SXGBE_HW_FEAT_PMT_MAGIC_PKT(cap) ((cap & 0x00000080) >> 7)
+#define SXGBE_HW_FEAT_RMON(cap) ((cap & 0x00000100) >> 8)
+#define SXGBE_HW_FEAT_ARP_OFFLOAD(cap) ((cap & 0x00000200) >> 9)
+#define SXGBE_HW_FEAT_IEEE1500_2008(cap) ((cap & 0x00001000) >> 12)
+#define SXGBE_HW_FEAT_EEE(cap) ((cap & 0x00002000) >> 13)
+#define SXGBE_HW_FEAT_TX_CSUM_OFFLOAD(cap) ((cap & 0x00004000) >> 14)
+#define SXGBE_HW_FEAT_RX_CSUM_OFFLOAD(cap) ((cap & 0x00010000) >> 16)
+#define SXGBE_HW_FEAT_MACADDR_COUNT(cap) ((cap & 0x007C0000) >> 18)
+#define SXGBE_HW_FEAT_TSTMAP_SRC(cap) ((cap & 0x06000000) >> 25)
+#define SXGBE_HW_FEAT_SRCADDR_VLAN(cap) ((cap & 0x08000000) >> 27)
+
+/* Capability Register 1 */
+#define SXGBE_HW_FEAT_RX_FIFO_SIZE(cap) ((cap & 0x0000001F))
+#define SXGBE_HW_FEAT_TX_FIFO_SIZE(cap) ((cap & 0x000007C0) >> 6)
+#define SXGBE_HW_FEAT_IEEE1588_HWORD(cap) ((cap & 0x00002000) >> 13)
+#define SXGBE_HW_FEAT_DCB(cap) ((cap & 0x00010000) >> 16)
+#define SXGBE_HW_FEAT_SPLIT_HDR(cap) ((cap & 0x00020000) >> 17)
+#define SXGBE_HW_FEAT_TSO(cap) ((cap & 0x00040000) >> 18)
+#define SXGBE_HW_FEAT_DEBUG_MEM_IFACE(cap) ((cap & 0x00080000) >> 19)
+#define SXGBE_HW_FEAT_RSS(cap) ((cap & 0x00100000) >> 20)
+#define SXGBE_HW_FEAT_HASH_TABLE_SIZE(cap) ((cap & 0x03000000) >> 24)
+#define SXGBE_HW_FEAT_L3L4_FILTER_NUM(cap) ((cap & 0x78000000) >> 27)
+
+/* Capability Register 2 */
+#define SXGBE_HW_FEAT_RX_MTL_QUEUES(cap) ((cap & 0x0000000F))
+#define SXGBE_HW_FEAT_TX_MTL_QUEUES(cap) ((cap & 0x000003C0) >> 6)
+#define SXGBE_HW_FEAT_RX_DMA_CHANNELS(cap) ((cap & 0x0000F000) >> 12)
+#define SXGBE_HW_FEAT_TX_DMA_CHANNELS(cap) ((cap & 0x003C0000) >> 18)
+#define SXGBE_HW_FEAT_PPS_OUTPUTS(cap) ((cap & 0x07000000) >> 24)
+#define SXGBE_HW_FEAT_AUX_SNAPSHOTS(cap) ((cap & 0x70000000) >> 28)
+
+/* DMAchannel interrupt enable specific */
+/* DMA Normal interrupt */
+#define SXGBE_DMA_INT_ENA_NIE BIT(16) /* Normal Summary */
+#define SXGBE_DMA_INT_ENA_TIE BIT(0) /* Transmit Interrupt */
+#define SXGBE_DMA_INT_ENA_TUE BIT(2) /* Transmit Buffer Unavailable */
+#define SXGBE_DMA_INT_ENA_RIE BIT(6) /* Receive Interrupt */
+
+#define SXGBE_DMA_INT_NORMAL \
+ (SXGBE_DMA_INT_ENA_NIE | SXGBE_DMA_INT_ENA_RIE | \
+ SXGBE_DMA_INT_ENA_TIE | SXGBE_DMA_INT_ENA_TUE)
+
+/* DMA Abnormal interrupt */
+#define SXGBE_DMA_INT_ENA_AIE BIT(15) /* Abnormal Summary */
+#define SXGBE_DMA_INT_ENA_TSE BIT(1) /* Transmit Stopped */
+#define SXGBE_DMA_INT_ENA_RUE BIT(7) /* Receive Buffer Unavailable */
+#define SXGBE_DMA_INT_ENA_RSE BIT(8) /* Receive Stopped */
+#define SXGBE_DMA_INT_ENA_FBE BIT(12) /* Fatal Bus Error */
+#define SXGBE_DMA_INT_ENA_CDEE BIT(13) /* Context Descriptor Error */
+
+#define SXGBE_DMA_INT_ABNORMAL \
+ (SXGBE_DMA_INT_ENA_AIE | SXGBE_DMA_INT_ENA_TSE | \
+ SXGBE_DMA_INT_ENA_RUE | SXGBE_DMA_INT_ENA_RSE | \
+ SXGBE_DMA_INT_ENA_FBE | SXGBE_DMA_INT_ENA_CDEE)
+
+#define SXGBE_DMA_ENA_INT (SXGBE_DMA_INT_NORMAL | SXGBE_DMA_INT_ABNORMAL)
+
+/* DMA channel interrupt status specific */
+#define SXGBE_DMA_INT_STATUS_REB2 BIT(21)
+#define SXGBE_DMA_INT_STATUS_REB1 BIT(20)
+#define SXGBE_DMA_INT_STATUS_REB0 BIT(19)
+#define SXGBE_DMA_INT_STATUS_TEB2 BIT(18)
+#define SXGBE_DMA_INT_STATUS_TEB1 BIT(17)
+#define SXGBE_DMA_INT_STATUS_TEB0 BIT(16)
+#define SXGBE_DMA_INT_STATUS_NIS BIT(15)
+#define SXGBE_DMA_INT_STATUS_AIS BIT(14)
+#define SXGBE_DMA_INT_STATUS_CTXTERR BIT(13)
+#define SXGBE_DMA_INT_STATUS_FBE BIT(12)
+#define SXGBE_DMA_INT_STATUS_RPS BIT(8)
+#define SXGBE_DMA_INT_STATUS_RBU BIT(7)
+#define SXGBE_DMA_INT_STATUS_RI BIT(6)
+#define SXGBE_DMA_INT_STATUS_TBU BIT(2)
+#define SXGBE_DMA_INT_STATUS_TPS BIT(1)
+#define SXGBE_DMA_INT_STATUS_TI BIT(0)
+
+#endif /* __SXGBE_REGMAP_H__ */
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_xpcs.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_xpcs.c
new file mode 100644
index 000000000000..51c32194ba88
--- /dev/null
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_xpcs.c
@@ -0,0 +1,91 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include "sxgbe_common.h"
+#include "sxgbe_xpcs.h"
+
+static int sxgbe_xpcs_read(struct net_device *ndev, unsigned int reg)
+{
+ u32 value;
+ struct sxgbe_priv_data *priv = netdev_priv(ndev);
+
+ value = readl(priv->ioaddr + XPCS_OFFSET + reg);
+
+ return value;
+}
+
+static int sxgbe_xpcs_write(struct net_device *ndev, int reg, int data)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(ndev);
+
+ writel(data, priv->ioaddr + XPCS_OFFSET + reg);
+
+ return 0;
+}
+
+int sxgbe_xpcs_init(struct net_device *ndev)
+{
+ u32 value;
+
+ value = sxgbe_xpcs_read(ndev, SR_PCS_MMD_CONTROL1);
+ /* 10G XAUI mode */
+ sxgbe_xpcs_write(ndev, SR_PCS_CONTROL2, XPCS_TYPE_SEL_X);
+ sxgbe_xpcs_write(ndev, VR_PCS_MMD_XAUI_MODE_CONTROL, XPCS_XAUI_MODE);
+ sxgbe_xpcs_write(ndev, VR_PCS_MMD_XAUI_MODE_CONTROL, value | BIT(13));
+ sxgbe_xpcs_write(ndev, SR_PCS_MMD_CONTROL1, value | BIT(11));
+
+ do {
+ value = sxgbe_xpcs_read(ndev, VR_PCS_MMD_DIGITAL_STATUS);
+ } while ((value & XPCS_QSEQ_STATE_MPLLOFF) == XPCS_QSEQ_STATE_STABLE);
+
+ value = sxgbe_xpcs_read(ndev, SR_PCS_MMD_CONTROL1);
+ sxgbe_xpcs_write(ndev, SR_PCS_MMD_CONTROL1, value & ~BIT(11));
+
+ do {
+ value = sxgbe_xpcs_read(ndev, VR_PCS_MMD_DIGITAL_STATUS);
+ } while ((value & XPCS_QSEQ_STATE_MPLLOFF) != XPCS_QSEQ_STATE_STABLE);
+
+ return 0;
+}
+
+int sxgbe_xpcs_init_1G(struct net_device *ndev)
+{
+ int value;
+
+ /* 10GBASE-X PCS (1G) mode */
+ sxgbe_xpcs_write(ndev, SR_PCS_CONTROL2, XPCS_TYPE_SEL_X);
+ sxgbe_xpcs_write(ndev, VR_PCS_MMD_XAUI_MODE_CONTROL, XPCS_XAUI_MODE);
+ value = sxgbe_xpcs_read(ndev, SR_PCS_MMD_CONTROL1);
+ sxgbe_xpcs_write(ndev, SR_PCS_MMD_CONTROL1, value & ~BIT(13));
+
+ value = sxgbe_xpcs_read(ndev, SR_MII_MMD_CONTROL);
+ sxgbe_xpcs_write(ndev, SR_MII_MMD_CONTROL, value | BIT(6));
+ sxgbe_xpcs_write(ndev, SR_MII_MMD_CONTROL, value & ~BIT(13));
+ value = sxgbe_xpcs_read(ndev, SR_PCS_MMD_CONTROL1);
+ sxgbe_xpcs_write(ndev, SR_PCS_MMD_CONTROL1, value | BIT(11));
+
+ do {
+ value = sxgbe_xpcs_read(ndev, VR_PCS_MMD_DIGITAL_STATUS);
+ } while ((value & XPCS_QSEQ_STATE_MPLLOFF) != XPCS_QSEQ_STATE_STABLE);
+
+ value = sxgbe_xpcs_read(ndev, SR_PCS_MMD_CONTROL1);
+ sxgbe_xpcs_write(ndev, SR_PCS_MMD_CONTROL1, value & ~BIT(11));
+
+ /* Auto Negotiation cluase 37 enable */
+ value = sxgbe_xpcs_read(ndev, SR_MII_MMD_CONTROL);
+ sxgbe_xpcs_write(ndev, SR_MII_MMD_CONTROL, value | BIT(12));
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_xpcs.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_xpcs.h
new file mode 100644
index 000000000000..6b26a50724d3
--- /dev/null
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_xpcs.h
@@ -0,0 +1,38 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Byungho An <bh74.an@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __SXGBE_XPCS_H__
+#define __SXGBE_XPCS_H__
+
+/* XPCS Registers */
+#define XPCS_OFFSET 0x1A060000
+#define SR_PCS_MMD_CONTROL1 0x030000
+#define SR_PCS_CONTROL2 0x030007
+#define VR_PCS_MMD_XAUI_MODE_CONTROL 0x038004
+#define VR_PCS_MMD_DIGITAL_STATUS 0x038010
+#define SR_MII_MMD_CONTROL 0x1F0000
+#define SR_MII_MMD_AN_ADV 0x1F0004
+#define SR_MII_MMD_AN_LINK_PARTNER_BA 0x1F0005
+#define VR_MII_MMD_AN_CONTROL 0x1F8001
+#define VR_MII_MMD_AN_INT_STATUS 0x1F8002
+
+#define XPCS_QSEQ_STATE_STABLE 0x10
+#define XPCS_QSEQ_STATE_MPLLOFF 0x1c
+#define XPCS_TYPE_SEL_R 0x00
+#define XPCS_TYPE_SEL_X 0x01
+#define XPCS_TYPE_SEL_W 0x02
+#define XPCS_XAUI_MODE 0x00
+#define XPCS_RXAUI_MODE 0x01
+
+int sxgbe_xpcs_init(struct net_device *ndev);
+int sxgbe_xpcs_init_1G(struct net_device *ndev);
+
+#endif /* __SXGBE_XPCS_H__ */
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index 174a92f5fe51..21c20ea0dad0 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -162,8 +162,8 @@ static int efx_ef10_get_mac_address(struct efx_nic *efx, u8 *mac_address)
if (outlen < MC_CMD_GET_MAC_ADDRESSES_OUT_LEN)
return -EIO;
- memcpy(mac_address,
- MCDI_PTR(outbuf, GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE), ETH_ALEN);
+ ether_addr_copy(mac_address,
+ MCDI_PTR(outbuf, GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE));
return 0;
}
@@ -172,8 +172,8 @@ static int efx_ef10_probe(struct efx_nic *efx)
struct efx_ef10_nic_data *nic_data;
int i, rc;
- /* We can have one VI for each 8K region. However we need
- * multiple TX queues per channel.
+ /* We can have one VI for each 8K region. However, until we
+ * use TX option descriptors we need two TX queues per channel.
*/
efx->max_channels =
min_t(unsigned int,
@@ -565,10 +565,17 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx)
* several of each (in fact that's the only option if host
* page size is >4K). So we may allocate some extra VIs just
* for writing PIO buffers through.
+ *
+ * The UC mapping contains (min_vis - 1) complete VIs and the
+ * first half of the next VI. Then the WC mapping begins with
+ * the second half of this last VI.
*/
uc_mem_map_size = PAGE_ALIGN((min_vis - 1) * EFX_VI_PAGE_SIZE +
ER_DZ_TX_PIOBUF);
if (nic_data->n_piobufs) {
+ /* pio_write_vi_base rounds down to give the number of complete
+ * VIs inside the UC mapping.
+ */
pio_write_vi_base = uc_mem_map_size / EFX_VI_PAGE_SIZE;
wc_mem_map_size = (PAGE_ALIGN((pio_write_vi_base +
nic_data->n_piobufs) *
@@ -1955,6 +1962,9 @@ static int efx_ef10_ev_process(struct efx_channel *channel, int quota)
int tx_descs = 0;
int spent = 0;
+ if (quota <= 0)
+ return spent;
+
read_ptr = channel->eventq_read_ptr;
for (;;) {
@@ -3145,12 +3155,10 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
table->dev_uc_count = -1;
} else {
table->dev_uc_count = 1 + netdev_uc_count(net_dev);
- memcpy(table->dev_uc_list[0].addr, net_dev->dev_addr,
- ETH_ALEN);
+ ether_addr_copy(table->dev_uc_list[0].addr, net_dev->dev_addr);
i = 1;
netdev_for_each_uc_addr(uc, net_dev) {
- memcpy(table->dev_uc_list[i].addr,
- uc->addr, ETH_ALEN);
+ ether_addr_copy(table->dev_uc_list[i].addr, uc->addr);
i++;
}
}
@@ -3162,8 +3170,7 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
eth_broadcast_addr(table->dev_mc_list[0].addr);
i = 1;
netdev_for_each_mc_addr(mc, net_dev) {
- memcpy(table->dev_mc_list[i].addr,
- mc->addr, ETH_ALEN);
+ ether_addr_copy(table->dev_mc_list[i].addr, mc->addr);
i++;
}
}
diff --git a/drivers/net/ethernet/sfc/ef10_regs.h b/drivers/net/ethernet/sfc/ef10_regs.h
index 207ac9a1e3de..62a55dde61d5 100644
--- a/drivers/net/ethernet/sfc/ef10_regs.h
+++ b/drivers/net/ethernet/sfc/ef10_regs.h
@@ -227,36 +227,6 @@
#define ESF_DZ_RX_KER_BUF_ADDR_LBN 0
#define ESF_DZ_RX_KER_BUF_ADDR_WIDTH 48
-/* RX_USER_DESC */
-#define ESF_DZ_RX_USR_RESERVED_LBN 62
-#define ESF_DZ_RX_USR_RESERVED_WIDTH 2
-#define ESF_DZ_RX_USR_BYTE_CNT_LBN 48
-#define ESF_DZ_RX_USR_BYTE_CNT_WIDTH 14
-#define ESF_DZ_RX_USR_BUF_PAGE_SIZE_LBN 44
-#define ESF_DZ_RX_USR_BUF_PAGE_SIZE_WIDTH 4
-#define ESE_DZ_USR_BUF_PAGE_SZ_4MB 10
-#define ESE_DZ_USR_BUF_PAGE_SZ_1MB 8
-#define ESE_DZ_USR_BUF_PAGE_SZ_64KB 4
-#define ESE_DZ_USR_BUF_PAGE_SZ_4KB 0
-#define ESF_DZ_RX_USR_BUF_ID_OFFSET_LBN 0
-#define ESF_DZ_RX_USR_BUF_ID_OFFSET_WIDTH 44
-#define ESF_DZ_RX_USR_4KBPS_BUF_ID_LBN 12
-#define ESF_DZ_RX_USR_4KBPS_BUF_ID_WIDTH 32
-#define ESF_DZ_RX_USR_64KBPS_BUF_ID_LBN 16
-#define ESF_DZ_RX_USR_64KBPS_BUF_ID_WIDTH 28
-#define ESF_DZ_RX_USR_1MBPS_BUF_ID_LBN 20
-#define ESF_DZ_RX_USR_1MBPS_BUF_ID_WIDTH 24
-#define ESF_DZ_RX_USR_4MBPS_BUF_ID_LBN 22
-#define ESF_DZ_RX_USR_4MBPS_BUF_ID_WIDTH 22
-#define ESF_DZ_RX_USR_4MBPS_BYTE_OFFSET_LBN 0
-#define ESF_DZ_RX_USR_4MBPS_BYTE_OFFSET_WIDTH 22
-#define ESF_DZ_RX_USR_1MBPS_BYTE_OFFSET_LBN 0
-#define ESF_DZ_RX_USR_1MBPS_BYTE_OFFSET_WIDTH 20
-#define ESF_DZ_RX_USR_64KBPS_BYTE_OFFSET_LBN 0
-#define ESF_DZ_RX_USR_64KBPS_BYTE_OFFSET_WIDTH 16
-#define ESF_DZ_RX_USR_4KBPS_BYTE_OFFSET_LBN 0
-#define ESF_DZ_RX_USR_4KBPS_BYTE_OFFSET_WIDTH 12
-
/* TX_CSUM_TSTAMP_DESC */
#define ESF_DZ_TX_DESC_IS_OPT_LBN 63
#define ESF_DZ_TX_DESC_IS_OPT_WIDTH 1
@@ -338,37 +308,6 @@
#define ESF_DZ_TX_TSO_TCP_SEQNO_LBN 0
#define ESF_DZ_TX_TSO_TCP_SEQNO_WIDTH 32
-/* TX_USER_DESC */
-#define ESF_DZ_TX_USR_TYPE_LBN 63
-#define ESF_DZ_TX_USR_TYPE_WIDTH 1
-#define ESF_DZ_TX_USR_CONT_LBN 62
-#define ESF_DZ_TX_USR_CONT_WIDTH 1
-#define ESF_DZ_TX_USR_BYTE_CNT_LBN 48
-#define ESF_DZ_TX_USR_BYTE_CNT_WIDTH 14
-#define ESF_DZ_TX_USR_BUF_PAGE_SIZE_LBN 44
-#define ESF_DZ_TX_USR_BUF_PAGE_SIZE_WIDTH 4
-#define ESE_DZ_USR_BUF_PAGE_SZ_4MB 10
-#define ESE_DZ_USR_BUF_PAGE_SZ_1MB 8
-#define ESE_DZ_USR_BUF_PAGE_SZ_64KB 4
-#define ESE_DZ_USR_BUF_PAGE_SZ_4KB 0
-#define ESF_DZ_TX_USR_BUF_ID_OFFSET_LBN 0
-#define ESF_DZ_TX_USR_BUF_ID_OFFSET_WIDTH 44
-#define ESF_DZ_TX_USR_4KBPS_BUF_ID_LBN 12
-#define ESF_DZ_TX_USR_4KBPS_BUF_ID_WIDTH 32
-#define ESF_DZ_TX_USR_64KBPS_BUF_ID_LBN 16
-#define ESF_DZ_TX_USR_64KBPS_BUF_ID_WIDTH 28
-#define ESF_DZ_TX_USR_1MBPS_BUF_ID_LBN 20
-#define ESF_DZ_TX_USR_1MBPS_BUF_ID_WIDTH 24
-#define ESF_DZ_TX_USR_4MBPS_BUF_ID_LBN 22
-#define ESF_DZ_TX_USR_4MBPS_BUF_ID_WIDTH 22
-#define ESF_DZ_TX_USR_4MBPS_BYTE_OFFSET_LBN 0
-#define ESF_DZ_TX_USR_4MBPS_BYTE_OFFSET_WIDTH 22
-#define ESF_DZ_TX_USR_1MBPS_BYTE_OFFSET_LBN 0
-#define ESF_DZ_TX_USR_1MBPS_BYTE_OFFSET_WIDTH 20
-#define ESF_DZ_TX_USR_64KBPS_BYTE_OFFSET_LBN 0
-#define ESF_DZ_TX_USR_64KBPS_BYTE_OFFSET_WIDTH 16
-#define ESF_DZ_TX_USR_4KBPS_BYTE_OFFSET_LBN 0
-#define ESF_DZ_TX_USR_4KBPS_BYTE_OFFSET_WIDTH 12
/*************************************************************************/
/* TX_DESC_UPD_REG: Transmit descriptor update register.
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 83d464347021..57b971e5e6b2 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -503,8 +503,6 @@ static int efx_probe_channel(struct efx_channel *channel)
goto fail;
}
- channel->n_rx_frm_trunc = 0;
-
return 0;
fail:
@@ -1014,7 +1012,7 @@ static int efx_probe_port(struct efx_nic *efx)
return rc;
/* Initialise MAC address to permanent address */
- memcpy(efx->net_dev->dev_addr, efx->net_dev->perm_addr, ETH_ALEN);
+ ether_addr_copy(efx->net_dev->dev_addr, efx->net_dev->perm_addr);
return 0;
}
@@ -1346,20 +1344,23 @@ static int efx_probe_interrupts(struct efx_nic *efx)
for (i = 0; i < n_channels; i++)
xentries[i].entry = i;
- rc = pci_enable_msix(efx->pci_dev, xentries, n_channels);
- if (rc > 0) {
+ rc = pci_enable_msix_range(efx->pci_dev,
+ xentries, 1, n_channels);
+ if (rc < 0) {
+ /* Fall back to single channel MSI */
+ efx->interrupt_mode = EFX_INT_MODE_MSI;
+ netif_err(efx, drv, efx->net_dev,
+ "could not enable MSI-X\n");
+ } else if (rc < n_channels) {
netif_err(efx, drv, efx->net_dev,
"WARNING: Insufficient MSI-X vectors"
" available (%d < %u).\n", rc, n_channels);
netif_err(efx, drv, efx->net_dev,
"WARNING: Performance may be reduced.\n");
- EFX_BUG_ON_PARANOID(rc >= n_channels);
n_channels = rc;
- rc = pci_enable_msix(efx->pci_dev, xentries,
- n_channels);
}
- if (rc == 0) {
+ if (rc > 0) {
efx->n_channels = n_channels;
if (n_channels > extra_channels)
n_channels -= extra_channels;
@@ -1375,11 +1376,6 @@ static int efx_probe_interrupts(struct efx_nic *efx)
for (i = 0; i < efx->n_channels; i++)
efx_get_channel(efx, i)->irq =
xentries[i].vector;
- } else {
- /* Fall back to single channel MSI */
- efx->interrupt_mode = EFX_INT_MODE_MSI;
- netif_err(efx, drv, efx->net_dev,
- "could not enable MSI-X\n");
}
}
@@ -1603,6 +1599,8 @@ static int efx_probe_nic(struct efx_nic *efx)
if (rc)
goto fail1;
+ efx_set_channels(efx);
+
rc = efx->type->dimension_resources(efx);
if (rc)
goto fail2;
@@ -1613,7 +1611,6 @@ static int efx_probe_nic(struct efx_nic *efx)
efx->rx_indir_table[i] =
ethtool_rxfh_indir_default(i, efx->rss_spread);
- efx_set_channels(efx);
netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels);
netif_set_real_num_rx_queues(efx->net_dev, efx->n_rx_channels);
@@ -2115,7 +2112,7 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct sockaddr *addr = data;
- char *new_addr = addr->sa_data;
+ u8 *new_addr = addr->sa_data;
if (!is_valid_ether_addr(new_addr)) {
netif_err(efx, drv, efx->net_dev,
@@ -2124,7 +2121,7 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data)
return -EADDRNOTAVAIL;
}
- memcpy(net_dev->dev_addr, new_addr, net_dev->addr_len);
+ ether_addr_copy(net_dev->dev_addr, new_addr);
efx_sriov_mac_address_changed(efx);
/* Reconfigure the MAC */
@@ -3273,6 +3270,6 @@ module_exit(efx_exit_module);
MODULE_AUTHOR("Solarflare Communications and "
"Michael Brown <mbrown@fensystems.co.uk>");
-MODULE_DESCRIPTION("Solarflare Communications network driver");
+MODULE_DESCRIPTION("Solarflare network driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, efx_pci_table);
diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h
index dbd7b78fe01c..99032581336f 100644
--- a/drivers/net/ethernet/sfc/efx.h
+++ b/drivers/net/ethernet/sfc/efx.h
@@ -14,7 +14,7 @@
#include "net_driver.h"
#include "filter.h"
-/* Solarstorm controllers use BAR 0 for I/O space and BAR 2(&3) for memory */
+/* All controllers use BAR 0 for I/O space and BAR 2(&3) for memory */
#define EFX_MEM_BAR 2
/* TX */
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index 229428915aa8..0de8b07c24c2 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -251,6 +251,9 @@ static void efx_fill_test(unsigned int test_index, u8 *strings, u64 *data,
* @test_index: Starting index of the test
* @strings: Ethtool strings, or %NULL
* @data: Ethtool test results, or %NULL
+ *
+ * Fill in a block of loopback self-test entries. Return new test
+ * index.
*/
static int efx_fill_loopback_test(struct efx_nic *efx,
struct efx_loopback_self_tests *lb_tests,
@@ -290,6 +293,12 @@ static int efx_fill_loopback_test(struct efx_nic *efx,
* @tests: Efx self-test results structure, or %NULL
* @strings: Ethtool strings, or %NULL
* @data: Ethtool test results, or %NULL
+ *
+ * Get self-test number of strings, strings, and/or test results.
+ * Return number of strings (== number of test results).
+ *
+ * The reason for merging these three functions is to make sure that
+ * they can never be inconsistent.
*/
static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
struct efx_self_tests *tests,
@@ -444,7 +453,7 @@ static void efx_ethtool_self_test(struct net_device *net_dev,
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_self_tests *efx_tests;
- int already_up;
+ bool already_up;
int rc = -ENOMEM;
efx_tests = kzalloc(sizeof(*efx_tests), GFP_KERNEL);
@@ -452,8 +461,8 @@ static void efx_ethtool_self_test(struct net_device *net_dev,
goto fail;
if (efx->state != STATE_READY) {
- rc = -EIO;
- goto fail1;
+ rc = -EBUSY;
+ goto out;
}
netif_info(efx, drv, efx->net_dev, "starting %sline testing\n",
@@ -466,7 +475,7 @@ static void efx_ethtool_self_test(struct net_device *net_dev,
if (rc) {
netif_err(efx, drv, efx->net_dev,
"failed opening device.\n");
- goto fail1;
+ goto out;
}
}
@@ -479,8 +488,7 @@ static void efx_ethtool_self_test(struct net_device *net_dev,
rc == 0 ? "passed" : "failed",
(test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on");
-fail1:
- /* Fill ethtool results structures */
+out:
efx_ethtool_fill_self_tests(efx, efx_tests, NULL, data);
kfree(efx_tests);
fail:
@@ -691,7 +699,6 @@ static void efx_ethtool_get_pauseparam(struct net_device *net_dev,
pause->autoneg = !!(efx->wanted_fc & EFX_FC_AUTO);
}
-
static void efx_ethtool_get_wol(struct net_device *net_dev,
struct ethtool_wolinfo *wol)
{
@@ -720,7 +727,7 @@ static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
}
/* MAC address mask including only I/G bit */
-static const u8 mac_addr_ig_mask[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
+static const u8 mac_addr_ig_mask[ETH_ALEN] __aligned(2) = {0x01, 0, 0, 0, 0, 0};
#define IP4_ADDR_FULL_MASK ((__force __be32)~0)
#define PORT_FULL_MASK ((__force __be16)~0)
@@ -780,16 +787,16 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx,
rule->flow_type = ETHER_FLOW;
if (spec.match_flags &
(EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_MAC_IG)) {
- memcpy(mac_entry->h_dest, spec.loc_mac, ETH_ALEN);
+ ether_addr_copy(mac_entry->h_dest, spec.loc_mac);
if (spec.match_flags & EFX_FILTER_MATCH_LOC_MAC)
- memset(mac_mask->h_dest, ~0, ETH_ALEN);
+ eth_broadcast_addr(mac_mask->h_dest);
else
- memcpy(mac_mask->h_dest, mac_addr_ig_mask,
- ETH_ALEN);
+ ether_addr_copy(mac_mask->h_dest,
+ mac_addr_ig_mask);
}
if (spec.match_flags & EFX_FILTER_MATCH_REM_MAC) {
- memcpy(mac_entry->h_source, spec.rem_mac, ETH_ALEN);
- memset(mac_mask->h_source, ~0, ETH_ALEN);
+ ether_addr_copy(mac_entry->h_source, spec.rem_mac);
+ eth_broadcast_addr(mac_mask->h_source);
}
if (spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE) {
mac_entry->h_proto = spec.ether_type;
@@ -961,13 +968,13 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx,
spec.match_flags |= EFX_FILTER_MATCH_LOC_MAC;
else
return -EINVAL;
- memcpy(spec.loc_mac, mac_entry->h_dest, ETH_ALEN);
+ ether_addr_copy(spec.loc_mac, mac_entry->h_dest);
}
if (!is_zero_ether_addr(mac_mask->h_source)) {
if (!is_broadcast_ether_addr(mac_mask->h_source))
return -EINVAL;
spec.match_flags |= EFX_FILTER_MATCH_REM_MAC;
- memcpy(spec.rem_mac, mac_entry->h_source, ETH_ALEN);
+ ether_addr_copy(spec.rem_mac, mac_entry->h_source);
}
if (mac_mask->h_proto) {
if (mac_mask->h_proto != ETHER_TYPE_FULL_MASK)
diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c
index 18d6f761f4d0..8ec20b713cc6 100644
--- a/drivers/net/ethernet/sfc/falcon.c
+++ b/drivers/net/ethernet/sfc/falcon.c
@@ -422,7 +422,6 @@ static inline void falcon_irq_ack_a1(struct efx_nic *efx)
efx_readd(efx, &reg, FR_AA_WORK_AROUND_BROKEN_PCI_READS);
}
-
static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
{
struct efx_nic *efx = dev_id;
@@ -467,6 +466,7 @@ static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
efx_schedule_channel_irq(efx_get_channel(efx, 1));
return IRQ_HANDLED;
}
+
/**************************************************************************
*
* RSS
@@ -1358,6 +1358,7 @@ static void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
case 100: link_speed = 1; break;
default: link_speed = 0; break;
}
+
/* MAC_LINK_STATUS controls MAC backpressure but doesn't work
* as advertised. Disable to ensure packets are not
* indefinitely held and TX queue can be flushed at any point
@@ -2182,7 +2183,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
}
/* Read the MAC addresses */
- memcpy(efx->net_dev->perm_addr, nvconfig->mac_address[0], ETH_ALEN);
+ ether_addr_copy(efx->net_dev->perm_addr, nvconfig->mac_address[0]);
netif_dbg(efx, probe, efx->net_dev, "PHY is %d phy_id %d\n",
efx->phy_type, efx->mdio.prtad);
@@ -2868,4 +2869,3 @@ const struct efx_nic_type falcon_b0_nic_type = {
.mcdi_max_ver = -1,
.max_rx_ip_filters = FR_BZ_RX_FILTER_TBL0_ROWS,
};
-
diff --git a/drivers/net/ethernet/sfc/farch.c b/drivers/net/ethernet/sfc/farch.c
index f72489a105ca..a08761360cdf 100644
--- a/drivers/net/ethernet/sfc/farch.c
+++ b/drivers/net/ethernet/sfc/farch.c
@@ -311,7 +311,6 @@ static inline void efx_farch_push_tx_desc(struct efx_tx_queue *tx_queue,
*/
void efx_farch_tx_write(struct efx_tx_queue *tx_queue)
{
-
struct efx_tx_buffer *buffer;
efx_qword_t *txd;
unsigned write_ptr;
@@ -1249,6 +1248,9 @@ int efx_farch_ev_process(struct efx_channel *channel, int budget)
int tx_packets = 0;
int spent = 0;
+ if (budget <= 0)
+ return spent;
+
read_ptr = channel->eventq_read_ptr;
for (;;) {
@@ -1609,7 +1611,6 @@ irqreturn_t efx_farch_msi_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-
/* Setup RSS indirection table.
* This maps from the hash value of the packet to RXQ
*/
diff --git a/drivers/net/ethernet/sfc/filter.h b/drivers/net/ethernet/sfc/filter.h
index 3ef298d3c47e..d0ed7f71ea7e 100644
--- a/drivers/net/ethernet/sfc/filter.h
+++ b/drivers/net/ethernet/sfc/filter.h
@@ -243,7 +243,7 @@ static inline int efx_filter_set_eth_local(struct efx_filter_spec *spec,
}
if (addr != NULL) {
spec->match_flags |= EFX_FILTER_MATCH_LOC_MAC;
- memcpy(spec->loc_mac, addr, ETH_ALEN);
+ ether_addr_copy(spec->loc_mac, addr);
}
return 0;
}
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
index eb59abb57e85..7bd4b14bf3b3 100644
--- a/drivers/net/ethernet/sfc/mcdi.c
+++ b/drivers/net/ethernet/sfc/mcdi.c
@@ -1187,6 +1187,9 @@ int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address,
int rc;
BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_IN_LEN != 0);
+ /* we need __aligned(2) for ether_addr_copy */
+ BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0_OFST & 1);
+ BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1_OFST & 1);
rc = efx_mcdi_rpc(efx, MC_CMD_GET_BOARD_CFG, NULL, 0,
outbuf, sizeof(outbuf), &outlen);
@@ -1199,11 +1202,10 @@ int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address,
}
if (mac_address)
- memcpy(mac_address,
- port_num ?
- MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1) :
- MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0),
- ETH_ALEN);
+ ether_addr_copy(mac_address,
+ port_num ?
+ MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1) :
+ MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0));
if (fw_subtype_list) {
for (i = 0;
i < MCDI_VAR_ARRAY_LEN(outlen,
@@ -1532,7 +1534,7 @@ static int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type,
MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_WOL_TYPE, type);
MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_FILTER_MODE,
MC_CMD_FILTER_MODE_SIMPLE);
- memcpy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), mac, ETH_ALEN);
+ ether_addr_copy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), mac);
rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_SET, inbuf, sizeof(inbuf),
outbuf, sizeof(outbuf), &outlen);
diff --git a/drivers/net/ethernet/sfc/mcdi_port.c b/drivers/net/ethernet/sfc/mcdi_port.c
index 91d23252f8fa..e5fc4e1574b5 100644
--- a/drivers/net/ethernet/sfc/mcdi_port.c
+++ b/drivers/net/ethernet/sfc/mcdi_port.c
@@ -854,8 +854,8 @@ int efx_mcdi_set_mac(struct efx_nic *efx)
BUILD_BUG_ON(MC_CMD_SET_MAC_OUT_LEN != 0);
- memcpy(MCDI_PTR(cmdbytes, SET_MAC_IN_ADDR),
- efx->net_dev->dev_addr, ETH_ALEN);
+ ether_addr_copy(MCDI_PTR(cmdbytes, SET_MAC_IN_ADDR),
+ efx->net_dev->dev_addr);
MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_MTU,
EFX_MAX_FRAME_LEN(efx->net_dev->mtu));
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index af2b8c59a903..8a400a0595eb 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -1323,7 +1323,6 @@ static inline struct efx_rx_buffer *efx_rx_buffer(struct efx_rx_queue *rx_queue,
return &rx_queue->buffer[index];
}
-
/**
* EFX_MAX_FRAME_LEN - calculate maximum frame length
*
diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c
index 79226b19e3c4..32d969e857f7 100644
--- a/drivers/net/ethernet/sfc/nic.c
+++ b/drivers/net/ethernet/sfc/nic.c
@@ -530,4 +530,3 @@ void efx_nic_fix_nodesc_drop_stat(struct efx_nic *efx, u64 *rx_nodesc_drops)
efx->rx_nodesc_drops_prev_state = !!(efx->net_dev->flags & IFF_UP);
*rx_nodesc_drops -= efx->rx_nodesc_drops_while_down;
}
-
diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c
index eb75fbd11a01..6b861e3de4b0 100644
--- a/drivers/net/ethernet/sfc/ptp.c
+++ b/drivers/net/ethernet/sfc/ptp.c
@@ -223,7 +223,6 @@ struct efx_ptp_timeset {
* @evt_list: List of MC receive events awaiting packets
* @evt_free_list: List of free events
* @evt_lock: Lock for manipulating evt_list and evt_free_list
- * @evt_overflow: Boolean indicating that event list has overflowed
* @rx_evts: Instantiated events (on evt_list and evt_free_list)
* @workwq: Work queue for processing pending PTP operations
* @work: Work task
@@ -275,7 +274,6 @@ struct efx_ptp_data {
struct list_head evt_list;
struct list_head evt_free_list;
spinlock_t evt_lock;
- bool evt_overflow;
struct efx_ptp_event_rx rx_evts[MAX_RECEIVE_EVENTS];
struct workqueue_struct *workwq;
struct work_struct work;
@@ -768,37 +766,36 @@ efx_ptp_process_times(struct efx_nic *efx, MCDI_DECLARE_STRUCT_PTR(synch_buf),
return -EAGAIN;
}
- /* Convert the NIC time into kernel time. No correction is required-
- * this time is the output of a firmware process.
- */
- mc_time = ptp->nic_to_kernel_time(ptp->timeset[last_good].major,
- ptp->timeset[last_good].minor, 0);
-
- /* Calculate delay from actual PPS to last_time */
- delta = ktime_to_timespec(mc_time);
- delta.tv_nsec +=
- last_time->ts_real.tv_nsec -
- (ptp->timeset[last_good].host_start & MC_NANOSECOND_MASK);
-
- /* It is possible that the seconds rolled over between taking
+ /* Calculate delay from last good sync (host time) to last_time.
+ * It is possible that the seconds rolled over between taking
* the start reading and the last value written by the host. The
* timescales are such that a gap of more than one second is never
- * expected.
+ * expected. delta is *not* normalised.
*/
start_sec = ptp->timeset[last_good].host_start >> MC_NANOSECOND_BITS;
last_sec = last_time->ts_real.tv_sec & MC_SECOND_MASK;
- if (start_sec != last_sec) {
- if (((start_sec + 1) & MC_SECOND_MASK) != last_sec) {
- netif_warn(efx, hw, efx->net_dev,
- "PTP bad synchronisation seconds\n");
- return -EAGAIN;
- } else {
- delta.tv_sec = 1;
- }
- } else {
- delta.tv_sec = 0;
+ if (start_sec != last_sec &&
+ ((start_sec + 1) & MC_SECOND_MASK) != last_sec) {
+ netif_warn(efx, hw, efx->net_dev,
+ "PTP bad synchronisation seconds\n");
+ return -EAGAIN;
}
+ delta.tv_sec = (last_sec - start_sec) & 1;
+ delta.tv_nsec =
+ last_time->ts_real.tv_nsec -
+ (ptp->timeset[last_good].host_start & MC_NANOSECOND_MASK);
+
+ /* Convert the NIC time at last good sync into kernel time.
+ * No correction is required - this time is the output of a
+ * firmware process.
+ */
+ mc_time = ptp->nic_to_kernel_time(ptp->timeset[last_good].major,
+ ptp->timeset[last_good].minor, 0);
+
+ /* Calculate delay from NIC top of second to last_time */
+ delta.tv_nsec += ktime_to_timespec(mc_time).tv_nsec;
+ /* Set PPS timestamp to match NIC top of second */
ptp->host_time_pps = *last_time;
pps_sub_ts(&ptp->host_time_pps, delta);
@@ -941,11 +938,6 @@ static void efx_ptp_drop_time_expired_events(struct efx_nic *efx)
}
}
}
- /* If the event overflow flag is set and the event list is now empty
- * clear the flag to re-enable the overflow warning message.
- */
- if (ptp->evt_overflow && list_empty(&ptp->evt_list))
- ptp->evt_overflow = false;
spin_unlock_bh(&ptp->evt_lock);
}
@@ -989,11 +981,6 @@ static enum ptp_packet_state efx_ptp_match_rx(struct efx_nic *efx,
break;
}
}
- /* If the event overflow flag is set and the event list is now empty
- * clear the flag to re-enable the overflow warning message.
- */
- if (ptp->evt_overflow && list_empty(&ptp->evt_list))
- ptp->evt_overflow = false;
spin_unlock_bh(&ptp->evt_lock);
return rc;
@@ -1147,7 +1134,6 @@ static int efx_ptp_stop(struct efx_nic *efx)
list_for_each_safe(cursor, next, &efx->ptp_data->evt_list) {
list_move(cursor, &efx->ptp_data->evt_free_list);
}
- ptp->evt_overflow = false;
spin_unlock_bh(&efx->ptp_data->evt_lock);
return rc;
@@ -1208,6 +1194,7 @@ static const struct ptp_clock_info efx_phc_clock_info = {
.n_alarm = 0,
.n_ext_ts = 0,
.n_per_out = 0,
+ .n_pins = 0,
.pps = 1,
.adjfreq = efx_phc_adjfreq,
.adjtime = efx_phc_adjtime,
@@ -1253,7 +1240,6 @@ int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel)
spin_lock_init(&ptp->evt_lock);
for (pos = 0; pos < MAX_RECEIVE_EVENTS; pos++)
list_add(&ptp->rx_evts[pos].link, &ptp->evt_free_list);
- ptp->evt_overflow = false;
/* Get the NIC PTP attributes and set up time conversions */
rc = efx_ptp_get_attributes(efx);
@@ -1380,6 +1366,7 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
struct efx_ptp_match *match = (struct efx_ptp_match *)skb->cb;
u8 *match_data_012, *match_data_345;
unsigned int version;
+ u8 *data;
match->expiry = jiffies + msecs_to_jiffies(PKT_EVENT_LIFETIME_MS);
@@ -1388,7 +1375,8 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
if (!pskb_may_pull(skb, PTP_V1_MIN_LENGTH)) {
return false;
}
- version = ntohs(*(__be16 *)&skb->data[PTP_V1_VERSION_OFFSET]);
+ data = skb->data;
+ version = ntohs(*(__be16 *)&data[PTP_V1_VERSION_OFFSET]);
if (version != PTP_VERSION_V1) {
return false;
}
@@ -1396,13 +1384,14 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
/* PTP V1 uses all six bytes of the UUID to match the packet
* to the timestamp
*/
- match_data_012 = skb->data + PTP_V1_UUID_OFFSET;
- match_data_345 = skb->data + PTP_V1_UUID_OFFSET + 3;
+ match_data_012 = data + PTP_V1_UUID_OFFSET;
+ match_data_345 = data + PTP_V1_UUID_OFFSET + 3;
} else {
if (!pskb_may_pull(skb, PTP_V2_MIN_LENGTH)) {
return false;
}
- version = skb->data[PTP_V2_VERSION_OFFSET];
+ data = skb->data;
+ version = data[PTP_V2_VERSION_OFFSET];
if ((version & PTP_VERSION_V2_MASK) != PTP_VERSION_V2) {
return false;
}
@@ -1414,17 +1403,17 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
* enhanced mode fixes this issue and uses bytes 0-2
* and byte 5-7 of the UUID.
*/
- match_data_345 = skb->data + PTP_V2_UUID_OFFSET + 5;
+ match_data_345 = data + PTP_V2_UUID_OFFSET + 5;
if (ptp->mode == MC_CMD_PTP_MODE_V2) {
- match_data_012 = skb->data + PTP_V2_UUID_OFFSET + 2;
+ match_data_012 = data + PTP_V2_UUID_OFFSET + 2;
} else {
- match_data_012 = skb->data + PTP_V2_UUID_OFFSET + 0;
+ match_data_012 = data + PTP_V2_UUID_OFFSET + 0;
BUG_ON(ptp->mode != MC_CMD_PTP_MODE_V2_ENHANCED);
}
}
/* Does this packet require timestamping? */
- if (ntohs(*(__be16 *)&skb->data[PTP_DPORT_OFFSET]) == PTP_EVENT_PORT) {
+ if (ntohs(*(__be16 *)&data[PTP_DPORT_OFFSET]) == PTP_EVENT_PORT) {
match->state = PTP_PACKET_STATE_UNMATCHED;
/* We expect the sequence number to be in the same position in
@@ -1440,8 +1429,8 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
(match_data_345[0] << 24));
match->words[1] = (match_data_345[1] |
(match_data_345[2] << 8) |
- (skb->data[PTP_V1_SEQUENCE_OFFSET +
- PTP_V1_SEQUENCE_LENGTH - 1] <<
+ (data[PTP_V1_SEQUENCE_OFFSET +
+ PTP_V1_SEQUENCE_LENGTH - 1] <<
16));
} else {
match->state = PTP_PACKET_STATE_MATCH_UNWANTED;
@@ -1635,13 +1624,9 @@ static void ptp_event_rx(struct efx_nic *efx, struct efx_ptp_data *ptp)
list_add_tail(&evt->link, &ptp->evt_list);
queue_work(ptp->workwq, &ptp->work);
- } else if (!ptp->evt_overflow) {
- /* Log a warning message and set the event overflow flag.
- * The message won't be logged again until the event queue
- * becomes empty.
- */
+ } else if (net_ratelimit()) {
+ /* Log a rate-limited warning message. */
netif_err(efx, rx_err, efx->net_dev, "PTP event queue overflow\n");
- ptp->evt_overflow = true;
}
spin_unlock_bh(&ptp->evt_lock);
}
@@ -1668,6 +1653,13 @@ void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev)
struct efx_ptp_data *ptp = efx->ptp_data;
int code = EFX_QWORD_FIELD(*ev, MCDI_EVENT_CODE);
+ if (!ptp) {
+ if (net_ratelimit())
+ netif_warn(efx, drv, efx->net_dev,
+ "Received PTP event but PTP not set up\n");
+ return;
+ }
+
if (!ptp->enabled)
return;
diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c
index 26641817a9c7..0fc5baef45b1 100644
--- a/drivers/net/ethernet/sfc/selftest.c
+++ b/drivers/net/ethernet/sfc/selftest.c
@@ -50,7 +50,7 @@ struct efx_loopback_payload {
} __packed;
/* Loopback test source MAC address */
-static const unsigned char payload_source[ETH_ALEN] = {
+static const u8 payload_source[ETH_ALEN] __aligned(2) = {
0x00, 0x0f, 0x53, 0x1b, 0x1b, 0x1b,
};
@@ -366,8 +366,8 @@ static void efx_iterate_state(struct efx_nic *efx)
struct efx_loopback_payload *payload = &state->payload;
/* Initialise the layerII header */
- memcpy(&payload->header.h_dest, net_dev->dev_addr, ETH_ALEN);
- memcpy(&payload->header.h_source, &payload_source, ETH_ALEN);
+ ether_addr_copy((u8 *)&payload->header.h_dest, net_dev->dev_addr);
+ ether_addr_copy((u8 *)&payload->header.h_source, payload_source);
payload->header.h_proto = htons(ETH_P_IP);
/* saddr set later and used as incrementing count */
diff --git a/drivers/net/ethernet/sfc/siena_sriov.c b/drivers/net/ethernet/sfc/siena_sriov.c
index 0c38f926871e..9a9205e77896 100644
--- a/drivers/net/ethernet/sfc/siena_sriov.c
+++ b/drivers/net/ethernet/sfc/siena_sriov.c
@@ -1095,7 +1095,7 @@ static void efx_sriov_peer_work(struct work_struct *data)
/* Fill the remaining addresses */
list_for_each_entry(local_addr, &efx->local_addr_list, link) {
- memcpy(peer->mac_addr, local_addr->addr, ETH_ALEN);
+ ether_addr_copy(peer->mac_addr, local_addr->addr);
peer->tci = 0;
++peer;
++peer_count;
@@ -1303,8 +1303,7 @@ int efx_sriov_init(struct efx_nic *efx)
goto fail_vfs;
rtnl_lock();
- memcpy(vfdi_status->peers[0].mac_addr,
- net_dev->dev_addr, ETH_ALEN);
+ ether_addr_copy(vfdi_status->peers[0].mac_addr, net_dev->dev_addr);
efx->vf_init_count = efx->vf_count;
rtnl_unlock();
@@ -1452,8 +1451,8 @@ void efx_sriov_mac_address_changed(struct efx_nic *efx)
if (!efx->vf_init_count)
return;
- memcpy(vfdi_status->peers[0].mac_addr,
- efx->net_dev->dev_addr, ETH_ALEN);
+ ether_addr_copy(vfdi_status->peers[0].mac_addr,
+ efx->net_dev->dev_addr);
queue_work(vfdi_workqueue, &efx->peer_work);
}
@@ -1570,7 +1569,7 @@ int efx_sriov_set_vf_mac(struct net_device *net_dev, int vf_i, u8 *mac)
vf = efx->vf + vf_i;
mutex_lock(&vf->status_lock);
- memcpy(vf->addr.mac_addr, mac, ETH_ALEN);
+ ether_addr_copy(vf->addr.mac_addr, mac);
__efx_sriov_update_vf_addr(vf);
mutex_unlock(&vf->status_lock);
@@ -1633,7 +1632,7 @@ int efx_sriov_get_vf_config(struct net_device *net_dev, int vf_i,
vf = efx->vf + vf_i;
ivi->vf = vf_i;
- memcpy(ivi->mac, vf->addr.mac_addr, ETH_ALEN);
+ ether_addr_copy(ivi->mac, vf->addr.mac_addr);
ivi->tx_rate = 0;
tci = ntohs(vf->addr.tci);
ivi->vlan = tci & VLAN_VID_MASK;
diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c
index c49d1fb16965..fa9475300411 100644
--- a/drivers/net/ethernet/sfc/tx.c
+++ b/drivers/net/ethernet/sfc/tx.c
@@ -429,7 +429,9 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
}
/* Transfer ownership of the skb to the final buffer */
+#ifdef EFX_USE_PIO
finish_packet:
+#endif
buffer->skb = skb;
buffer->flags = EFX_TX_BUF_SKB | dma_flags;
@@ -785,15 +787,6 @@ void efx_remove_tx_queue(struct efx_tx_queue *tx_queue)
* Requires TX checksum offload support.
*/
-/* Number of bytes inserted at the start of a TSO header buffer,
- * similar to NET_IP_ALIGN.
- */
-#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
-#define TSOH_OFFSET 0
-#else
-#define TSOH_OFFSET NET_IP_ALIGN
-#endif
-
#define PTR_DIFF(p1, p2) ((u8 *)(p1) - (u8 *)(p2))
/**
@@ -880,13 +873,13 @@ static u8 *efx_tsoh_get_buffer(struct efx_tx_queue *tx_queue,
EFX_BUG_ON_PARANOID(buffer->flags);
EFX_BUG_ON_PARANOID(buffer->unmap_len);
- if (likely(len <= TSOH_STD_SIZE - TSOH_OFFSET)) {
+ if (likely(len <= TSOH_STD_SIZE - NET_IP_ALIGN)) {
unsigned index =
(tx_queue->insert_count & tx_queue->ptr_mask) / 2;
struct efx_buffer *page_buf =
&tx_queue->tsoh_page[index / TSOH_PER_PAGE];
unsigned offset =
- TSOH_STD_SIZE * (index % TSOH_PER_PAGE) + TSOH_OFFSET;
+ TSOH_STD_SIZE * (index % TSOH_PER_PAGE) + NET_IP_ALIGN;
if (unlikely(!page_buf->addr) &&
efx_nic_alloc_buffer(tx_queue->efx, page_buf, PAGE_SIZE,
@@ -899,10 +892,10 @@ static u8 *efx_tsoh_get_buffer(struct efx_tx_queue *tx_queue,
} else {
tx_queue->tso_long_headers++;
- buffer->heap_buf = kmalloc(TSOH_OFFSET + len, GFP_ATOMIC);
+ buffer->heap_buf = kmalloc(NET_IP_ALIGN + len, GFP_ATOMIC);
if (unlikely(!buffer->heap_buf))
return NULL;
- result = (u8 *)buffer->heap_buf + TSOH_OFFSET;
+ result = (u8 *)buffer->heap_buf + NET_IP_ALIGN;
buffer->flags = EFX_TX_BUF_CONT | EFX_TX_BUF_HEAP;
}
@@ -1009,7 +1002,7 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue)
static int tso_start(struct tso_state *st, struct efx_nic *efx,
const struct sk_buff *skb)
{
- bool use_options = efx_nic_rev(efx) >= EFX_REV_HUNT_A0;
+ bool use_opt_desc = efx_nic_rev(efx) >= EFX_REV_HUNT_A0;
struct device *dma_dev = &efx->pci_dev->dev;
unsigned int header_len, in_len;
dma_addr_t dma_addr;
@@ -1035,7 +1028,7 @@ static int tso_start(struct tso_state *st, struct efx_nic *efx,
st->out_len = skb->len - header_len;
- if (!use_options) {
+ if (!use_opt_desc) {
st->header_unmap_len = 0;
if (likely(in_len == 0)) {
diff --git a/drivers/net/ethernet/silan/sc92031.c b/drivers/net/ethernet/silan/sc92031.c
index 5eb933c97bba..7daa7d433099 100644
--- a/drivers/net/ethernet/silan/sc92031.c
+++ b/drivers/net/ethernet/silan/sc92031.c
@@ -987,7 +987,7 @@ out_unlock:
spin_unlock(&priv->lock);
out:
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c
index ff57a46388ee..6072f093e6b4 100644
--- a/drivers/net/ethernet/sis/sis900.c
+++ b/drivers/net/ethernet/sis/sis900.c
@@ -1614,7 +1614,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
skb->data, skb->len, PCI_DMA_TODEVICE);
if (unlikely(pci_dma_mapping_error(sis_priv->pci_dev,
sis_priv->tx_ring[entry].bufptr))) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
sis_priv->tx_skbuff[entry] = NULL;
net_dev->stats.tx_dropped++;
spin_unlock_irqrestore(&sis_priv->lock, flags);
diff --git a/drivers/net/ethernet/smsc/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c
index c50fb08c9905..66b05e62f70a 100644
--- a/drivers/net/ethernet/smsc/smc911x.c
+++ b/drivers/net/ethernet/smsc/smc911x.c
@@ -551,7 +551,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_errors++;
dev->stats.tx_dropped++;
spin_unlock_irqrestore(&lp->lock, flags);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index 839c0e6cca01..d1b4dca53a9d 100644
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -621,7 +621,7 @@ static void smc_hardware_send_pkt(unsigned long data)
done: if (!THROTTLE_TX_PKTS)
netif_wake_queue(dev);
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
}
/*
@@ -657,7 +657,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
netdev_warn(dev, "Far too big packet error.\n");
dev->stats.tx_errors++;
dev->stats.tx_dropped++;
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c
index 6382b7c416f4..a0fc151da40d 100644
--- a/drivers/net/ethernet/smsc/smsc911x.c
+++ b/drivers/net/ethernet/smsc/smsc911x.c
@@ -439,7 +439,8 @@ static int smsc911x_request_resources(struct platform_device *pdev)
/* Request clock */
pdata->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(pdata->clk))
- netdev_warn(ndev, "couldn't get clock %li\n", PTR_ERR(pdata->clk));
+ dev_dbg(&pdev->dev, "couldn't get clock %li\n",
+ PTR_ERR(pdata->clk));
return ret;
}
@@ -1672,7 +1673,7 @@ static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz);
freespace -= (skb->len + 32);
skb_tx_timestamp(skb);
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
if (unlikely(smsc911x_tx_get_txstatcount(pdata) >= 30))
smsc911x_tx_update_txcounters(dev);
@@ -2379,8 +2380,6 @@ static int smsc911x_drv_probe(struct platform_device *pdev)
int res_size, irq_flags;
int retval;
- pr_info("Driver version %s\n", SMSC_DRV_VERSION);
-
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"smsc911x-memory");
if (!res)
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index e2f202e3932f..2d09c116cbc8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -26,6 +26,16 @@ config STMMAC_PLATFORM
If unsure, say N.
+config DWMAC_SOCFPGA
+ bool "SOCFPGA dwmac support"
+ depends on STMMAC_PLATFORM && MFD_SYSCON && (ARCH_SOCFPGA || COMPILE_TEST)
+ help
+ Support for ethernet controller on Altera SOCFPGA
+
+ This selects the Altera SOCFPGA SoC glue layer support
+ for the stmmac device driver. This driver is used for
+ arria5 and cyclone5 FPGA SoCs.
+
config DWMAC_SUNXI
bool "Allwinner GMAC support"
depends on STMMAC_PLATFORM && ARCH_SUNXI
@@ -37,6 +47,17 @@ config DWMAC_SUNXI
stmmac device driver. This driver is used for A20/A31
GMAC ethernet controller.
+config DWMAC_STI
+ bool "STi GMAC support"
+ depends on STMMAC_PLATFORM && ARCH_STI
+ default y
+ ---help---
+ Support for ethernet controller on STi SOCs.
+
+ This selects STi SoC glue layer support for the stmmac
+ device driver. This driver is used on for the STi series
+ SOCs GMAC ethernet controller.
+
config STMMAC_PCI
bool "STMMAC PCI bus support"
depends on STMMAC_ETH && PCI
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index ecadecea79b2..18695ebef7e4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -2,6 +2,8 @@ obj-$(CONFIG_STMMAC_ETH) += stmmac.o
stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o
stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o
stmmac-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o
+stmmac-$(CONFIG_DWMAC_STI) += dwmac-sti.o
+stmmac-$(CONFIG_DWMAC_SOCFPGA) += dwmac-socfpga.o
stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \
chain_mode.o dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
index 72d282bf33a5..c553f6b5a913 100644
--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
@@ -151,7 +151,7 @@ static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
sizeof(struct dma_desc)));
}
-const struct stmmac_chain_mode_ops chain_mode_ops = {
+const struct stmmac_mode_ops chain_mode_ops = {
.init = stmmac_init_dma_chain,
.is_jumbo_frm = stmmac_is_jumbo_frm,
.jumbo_frm = stmmac_jumbo_frm,
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 7834a3993946..74610f3aca9e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -419,20 +419,13 @@ struct mii_regs {
unsigned int data; /* MII Data */
};
-struct stmmac_ring_mode_ops {
- unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
- unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
- void (*refill_desc3) (void *priv, struct dma_desc *p);
- void (*init_desc3) (struct dma_desc *p);
- void (*clean_desc3) (void *priv, struct dma_desc *p);
- int (*set_16kib_bfsize) (int mtu);
-};
-
-struct stmmac_chain_mode_ops {
+struct stmmac_mode_ops {
void (*init) (void *des, dma_addr_t phy_addr, unsigned int size,
unsigned int extend_desc);
unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
+ int (*set_16kib_bfsize)(int mtu);
+ void (*init_desc3)(struct dma_desc *p);
void (*refill_desc3) (void *priv, struct dma_desc *p);
void (*clean_desc3) (void *priv, struct dma_desc *p);
};
@@ -441,8 +434,7 @@ struct mac_device_info {
const struct stmmac_ops *mac;
const struct stmmac_desc_ops *desc;
const struct stmmac_dma_ops *dma;
- const struct stmmac_ring_mode_ops *ring;
- const struct stmmac_chain_mode_ops *chain;
+ const struct stmmac_mode_ops *mode;
const struct stmmac_hwtimestamp *ptp;
struct mii_regs mii; /* MII register Addresses */
struct mac_link link;
@@ -460,7 +452,7 @@ void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
void stmmac_set_mac(void __iomem *ioaddr, bool enable);
void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
-extern const struct stmmac_ring_mode_ops ring_mode_ops;
-extern const struct stmmac_chain_mode_ops chain_mode_ops;
+extern const struct stmmac_mode_ops ring_mode_ops;
+extern const struct stmmac_mode_ops chain_mode_ops;
#endif /* __COMMON_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
new file mode 100644
index 000000000000..fd8a217556a1
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
@@ -0,0 +1,130 @@
+/* Copyright Altera Corporation (C) 2014. 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/>.
+ *
+ * Adopted from dwmac-sti.c
+ */
+
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_net.h>
+#include <linux/phy.h>
+#include <linux/regmap.h>
+#include <linux/stmmac.h>
+
+#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0
+#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1
+#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII 0x2
+#define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2
+#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003
+
+struct socfpga_dwmac {
+ int interface;
+ u32 reg_offset;
+ u32 reg_shift;
+ struct device *dev;
+ struct regmap *sys_mgr_base_addr;
+};
+
+static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ struct regmap *sys_mgr_base_addr;
+ u32 reg_offset, reg_shift;
+ int ret;
+
+ dwmac->interface = of_get_phy_mode(np);
+
+ sys_mgr_base_addr = syscon_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon");
+ if (IS_ERR(sys_mgr_base_addr)) {
+ dev_info(dev, "No sysmgr-syscon node found\n");
+ return PTR_ERR(sys_mgr_base_addr);
+ }
+
+ ret = of_property_read_u32_index(np, "altr,sysmgr-syscon", 1, &reg_offset);
+ if (ret) {
+ dev_info(dev, "Could not read reg_offset from sysmgr-syscon!\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32_index(np, "altr,sysmgr-syscon", 2, &reg_shift);
+ if (ret) {
+ dev_info(dev, "Could not read reg_shift from sysmgr-syscon!\n");
+ return -EINVAL;
+ }
+
+ dwmac->reg_offset = reg_offset;
+ dwmac->reg_shift = reg_shift;
+ dwmac->sys_mgr_base_addr = sys_mgr_base_addr;
+ dwmac->dev = dev;
+
+ return 0;
+}
+
+static int socfpga_dwmac_setup(struct socfpga_dwmac *dwmac)
+{
+ struct regmap *sys_mgr_base_addr = dwmac->sys_mgr_base_addr;
+ int phymode = dwmac->interface;
+ u32 reg_offset = dwmac->reg_offset;
+ u32 reg_shift = dwmac->reg_shift;
+ u32 ctrl, val;
+
+ switch (phymode) {
+ case PHY_INTERFACE_MODE_RGMII:
+ val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII;
+ break;
+ case PHY_INTERFACE_MODE_MII:
+ case PHY_INTERFACE_MODE_GMII:
+ val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII;
+ break;
+ default:
+ dev_err(dwmac->dev, "bad phy mode %d\n", phymode);
+ return -EINVAL;
+ }
+
+ regmap_read(sys_mgr_base_addr, reg_offset, &ctrl);
+ ctrl &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << reg_shift);
+ ctrl |= val << reg_shift;
+
+ regmap_write(sys_mgr_base_addr, reg_offset, ctrl);
+ return 0;
+}
+
+static void *socfpga_dwmac_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ int ret;
+ struct socfpga_dwmac *dwmac;
+
+ dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL);
+ if (!dwmac)
+ return ERR_PTR(-ENOMEM);
+
+ ret = socfpga_dwmac_parse_data(dwmac, dev);
+ if (ret) {
+ dev_err(dev, "Unable to parse OF data\n");
+ return ERR_PTR(ret);
+ }
+
+ ret = socfpga_dwmac_setup(dwmac);
+ if (ret) {
+ dev_err(dev, "couldn't setup SoC glue (%d)\n", ret);
+ return ERR_PTR(ret);
+ }
+
+ return dwmac;
+}
+
+const struct stmmac_of_data socfpga_gmac_data = {
+ .setup = socfpga_dwmac_probe,
+};
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
new file mode 100644
index 000000000000..552bbc17863c
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
@@ -0,0 +1,330 @@
+/**
+ * dwmac-sti.c - STMicroelectronics DWMAC Specific Glue layer
+ *
+ * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited
+ * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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/slab.h>
+#include <linux/platform_device.h>
+#include <linux/stmmac.h>
+#include <linux/phy.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_net.h>
+
+/**
+ * STi GMAC glue logic.
+ * --------------------
+ *
+ * _
+ * | \
+ * --------|0 \ ETH_SEL_INTERNAL_NOTEXT_PHYCLK
+ * phyclk | |___________________________________________
+ * | | | (phyclk-in)
+ * --------|1 / |
+ * int-clk |_ / |
+ * | _
+ * | | \
+ * |_______|1 \ ETH_SEL_TX_RETIME_CLK
+ * | |___________________________
+ * | | (tx-retime-clk)
+ * _______|0 /
+ * | |_ /
+ * _ |
+ * | \ |
+ * --------|0 \ |
+ * clk_125 | |__|
+ * | | ETH_SEL_TXCLK_NOT_CLK125
+ * --------|1 /
+ * txclk |_ /
+ *
+ *
+ * ETH_SEL_INTERNAL_NOTEXT_PHYCLK is valid only for RMII where PHY can
+ * generate 50MHz clock or MAC can generate it.
+ * This bit is configured by "st,ext-phyclk" property.
+ *
+ * ETH_SEL_TXCLK_NOT_CLK125 is only valid for gigabit modes, where the 125Mhz
+ * clock either comes from clk-125 pin or txclk pin. This configuration is
+ * totally driven by the board wiring. This bit is configured by
+ * "st,tx-retime-src" property.
+ *
+ * TXCLK configuration is different for different phy interface modes
+ * and changes according to link speed in modes like RGMII.
+ *
+ * Below table summarizes the clock requirement and clock sources for
+ * supported phy interface modes with link speeds.
+ * ________________________________________________
+ *| PHY_MODE | 1000 Mbit Link | 100 Mbit Link |
+ * ------------------------------------------------
+ *| MII | n/a | 25Mhz |
+ *| | | txclk |
+ * ------------------------------------------------
+ *| GMII | 125Mhz | 25Mhz |
+ *| | clk-125/txclk | txclk |
+ * ------------------------------------------------
+ *| RGMII | 125Mhz | 25Mhz |
+ *| | clk-125/txclk | clkgen |
+ * ------------------------------------------------
+ *| RMII | n/a | 25Mhz |
+ *| | |clkgen/phyclk-in |
+ * ------------------------------------------------
+ *
+ * TX lines are always retimed with a clk, which can vary depending
+ * on the board configuration. Below is the table of these bits
+ * in eth configuration register depending on source of retime clk.
+ *
+ *---------------------------------------------------------------
+ * src | tx_rt_clk | int_not_ext_phyclk | txclk_n_clk125|
+ *---------------------------------------------------------------
+ * txclk | 0 | n/a | 1 |
+ *---------------------------------------------------------------
+ * ck_125| 0 | n/a | 0 |
+ *---------------------------------------------------------------
+ * phyclk| 1 | 0 | n/a |
+ *---------------------------------------------------------------
+ * clkgen| 1 | 1 | n/a |
+ *---------------------------------------------------------------
+ */
+
+ /* Register definition */
+
+ /* 3 bits [8:6]
+ * [6:6] ETH_SEL_TXCLK_NOT_CLK125
+ * [7:7] ETH_SEL_INTERNAL_NOTEXT_PHYCLK
+ * [8:8] ETH_SEL_TX_RETIME_CLK
+ *
+ */
+
+#define TX_RETIME_SRC_MASK GENMASK(8, 6)
+#define ETH_SEL_TX_RETIME_CLK BIT(8)
+#define ETH_SEL_INTERNAL_NOTEXT_PHYCLK BIT(7)
+#define ETH_SEL_TXCLK_NOT_CLK125 BIT(6)
+
+#define ENMII_MASK GENMASK(5, 5)
+#define ENMII BIT(5)
+
+/**
+ * 3 bits [4:2]
+ * 000-GMII/MII
+ * 001-RGMII
+ * 010-SGMII
+ * 100-RMII
+*/
+#define MII_PHY_SEL_MASK GENMASK(4, 2)
+#define ETH_PHY_SEL_RMII BIT(4)
+#define ETH_PHY_SEL_SGMII BIT(3)
+#define ETH_PHY_SEL_RGMII BIT(2)
+#define ETH_PHY_SEL_GMII 0x0
+#define ETH_PHY_SEL_MII 0x0
+
+#define IS_PHY_IF_MODE_RGMII(iface) (iface == PHY_INTERFACE_MODE_RGMII || \
+ iface == PHY_INTERFACE_MODE_RGMII_ID || \
+ iface == PHY_INTERFACE_MODE_RGMII_RXID || \
+ iface == PHY_INTERFACE_MODE_RGMII_TXID)
+
+#define IS_PHY_IF_MODE_GBIT(iface) (IS_PHY_IF_MODE_RGMII(iface) || \
+ iface == PHY_INTERFACE_MODE_GMII)
+
+struct sti_dwmac {
+ int interface;
+ bool ext_phyclk;
+ bool is_tx_retime_src_clk_125;
+ struct clk *clk;
+ int reg;
+ struct device *dev;
+ struct regmap *regmap;
+};
+
+static u32 phy_intf_sels[] = {
+ [PHY_INTERFACE_MODE_MII] = ETH_PHY_SEL_MII,
+ [PHY_INTERFACE_MODE_GMII] = ETH_PHY_SEL_GMII,
+ [PHY_INTERFACE_MODE_RGMII] = ETH_PHY_SEL_RGMII,
+ [PHY_INTERFACE_MODE_RGMII_ID] = ETH_PHY_SEL_RGMII,
+ [PHY_INTERFACE_MODE_SGMII] = ETH_PHY_SEL_SGMII,
+ [PHY_INTERFACE_MODE_RMII] = ETH_PHY_SEL_RMII,
+};
+
+enum {
+ TX_RETIME_SRC_NA = 0,
+ TX_RETIME_SRC_TXCLK = 1,
+ TX_RETIME_SRC_CLK_125,
+ TX_RETIME_SRC_PHYCLK,
+ TX_RETIME_SRC_CLKGEN,
+};
+
+static const char *const tx_retime_srcs[] = {
+ [TX_RETIME_SRC_NA] = "",
+ [TX_RETIME_SRC_TXCLK] = "txclk",
+ [TX_RETIME_SRC_CLK_125] = "clk_125",
+ [TX_RETIME_SRC_PHYCLK] = "phyclk",
+ [TX_RETIME_SRC_CLKGEN] = "clkgen",
+};
+
+static u32 tx_retime_val[] = {
+ [TX_RETIME_SRC_TXCLK] = ETH_SEL_TXCLK_NOT_CLK125,
+ [TX_RETIME_SRC_CLK_125] = 0x0,
+ [TX_RETIME_SRC_PHYCLK] = ETH_SEL_TX_RETIME_CLK,
+ [TX_RETIME_SRC_CLKGEN] = ETH_SEL_TX_RETIME_CLK |
+ ETH_SEL_INTERNAL_NOTEXT_PHYCLK,
+};
+
+static void setup_retime_src(struct sti_dwmac *dwmac, u32 spd)
+{
+ u32 src = 0, freq = 0;
+
+ if (spd == SPEED_100) {
+ if (dwmac->interface == PHY_INTERFACE_MODE_MII ||
+ dwmac->interface == PHY_INTERFACE_MODE_GMII) {
+ src = TX_RETIME_SRC_TXCLK;
+ } else if (dwmac->interface == PHY_INTERFACE_MODE_RMII) {
+ if (dwmac->ext_phyclk) {
+ src = TX_RETIME_SRC_PHYCLK;
+ } else {
+ src = TX_RETIME_SRC_CLKGEN;
+ freq = 50000000;
+ }
+
+ } else if (IS_PHY_IF_MODE_RGMII(dwmac->interface)) {
+ src = TX_RETIME_SRC_CLKGEN;
+ freq = 25000000;
+ }
+
+ if (src == TX_RETIME_SRC_CLKGEN && dwmac->clk)
+ clk_set_rate(dwmac->clk, freq);
+
+ } else if (spd == SPEED_1000) {
+ if (dwmac->is_tx_retime_src_clk_125)
+ src = TX_RETIME_SRC_CLK_125;
+ else
+ src = TX_RETIME_SRC_TXCLK;
+ }
+
+ regmap_update_bits(dwmac->regmap, dwmac->reg,
+ TX_RETIME_SRC_MASK, tx_retime_val[src]);
+}
+
+static void sti_dwmac_exit(struct platform_device *pdev, void *priv)
+{
+ struct sti_dwmac *dwmac = priv;
+
+ if (dwmac->clk)
+ clk_disable_unprepare(dwmac->clk);
+}
+
+static void sti_fix_mac_speed(void *priv, unsigned int spd)
+{
+ struct sti_dwmac *dwmac = priv;
+
+ setup_retime_src(dwmac, spd);
+
+ return;
+}
+
+static int sti_dwmac_parse_data(struct sti_dwmac *dwmac,
+ struct platform_device *pdev)
+{
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct regmap *regmap;
+ int err;
+
+ if (!np)
+ return -EINVAL;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sti-ethconf");
+ if (!res)
+ return -ENODATA;
+
+ regmap = syscon_regmap_lookup_by_phandle(np, "st,syscon");
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ dwmac->dev = dev;
+ dwmac->interface = of_get_phy_mode(np);
+ dwmac->regmap = regmap;
+ dwmac->reg = res->start;
+ dwmac->ext_phyclk = of_property_read_bool(np, "st,ext-phyclk");
+ dwmac->is_tx_retime_src_clk_125 = false;
+
+ if (IS_PHY_IF_MODE_GBIT(dwmac->interface)) {
+ const char *rs;
+
+ err = of_property_read_string(np, "st,tx-retime-src", &rs);
+ if (err < 0) {
+ dev_err(dev, "st,tx-retime-src not specified\n");
+ return err;
+ }
+
+ if (!strcasecmp(rs, "clk_125"))
+ dwmac->is_tx_retime_src_clk_125 = true;
+ }
+
+ dwmac->clk = devm_clk_get(dev, "sti-ethclk");
+
+ if (IS_ERR(dwmac->clk))
+ dwmac->clk = NULL;
+
+ return 0;
+}
+
+static int sti_dwmac_init(struct platform_device *pdev, void *priv)
+{
+ struct sti_dwmac *dwmac = priv;
+ struct regmap *regmap = dwmac->regmap;
+ int iface = dwmac->interface;
+ u32 reg = dwmac->reg;
+ u32 val, spd;
+
+ if (dwmac->clk)
+ clk_prepare_enable(dwmac->clk);
+
+ regmap_update_bits(regmap, reg, MII_PHY_SEL_MASK, phy_intf_sels[iface]);
+
+ val = (iface == PHY_INTERFACE_MODE_REVMII) ? 0 : ENMII;
+ regmap_update_bits(regmap, reg, ENMII_MASK, val);
+
+ if (IS_PHY_IF_MODE_GBIT(iface))
+ spd = SPEED_1000;
+ else
+ spd = SPEED_100;
+
+ setup_retime_src(dwmac, spd);
+
+ return 0;
+}
+
+static void *sti_dwmac_setup(struct platform_device *pdev)
+{
+ struct sti_dwmac *dwmac;
+ int ret;
+
+ dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
+ if (!dwmac)
+ return ERR_PTR(-ENOMEM);
+
+ ret = sti_dwmac_parse_data(dwmac, pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to parse OF data\n");
+ return ERR_PTR(ret);
+ }
+
+ return dwmac;
+}
+
+const struct stmmac_of_data sti_gmac_data = {
+ .fix_mac_speed = sti_fix_mac_speed,
+ .setup = sti_dwmac_setup,
+ .init = sti_dwmac_init,
+ .exit = sti_dwmac_exit,
+};
diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
index a96c7c2f5f3f..650a4be6bce5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
@@ -100,10 +100,9 @@ static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
{
struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
- if (unlikely(priv->plat->has_gmac))
- /* Fill DES3 in case of RING mode */
- if (priv->dma_buf_sz >= BUF_SIZE_8KiB)
- p->des3 = p->des2 + BUF_SIZE_8KiB;
+ /* Fill DES3 in case of RING mode */
+ if (priv->dma_buf_sz >= BUF_SIZE_8KiB)
+ p->des3 = p->des2 + BUF_SIZE_8KiB;
}
/* In ring mode we need to fill the desc3 because it is used as buffer */
@@ -126,7 +125,7 @@ static int stmmac_set_16kib_bfsize(int mtu)
return ret;
}
-const struct stmmac_ring_mode_ops ring_mode_ops = {
+const struct stmmac_mode_ops ring_mode_ops = {
.is_jumbo_frm = stmmac_is_jumbo_frm,
.jumbo_frm = stmmac_jumbo_frm,
.refill_desc3 = stmmac_refill_desc3,
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index d9af26ed58ee..ca01035634a7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -133,6 +133,12 @@ bool stmmac_eee_init(struct stmmac_priv *priv);
#ifdef CONFIG_DWMAC_SUNXI
extern const struct stmmac_of_data sun7i_gmac_data;
#endif
+#ifdef CONFIG_DWMAC_STI
+extern const struct stmmac_of_data sti_gmac_data;
+#endif
+#ifdef CONFIG_DWMAC_SOCFPGA
+extern const struct stmmac_of_data socfpga_gmac_data;
+#endif
extern struct platform_driver stmmac_pltfr_driver;
static inline int stmmac_register_platform(void)
{
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index a2e7d2c96e36..d940034acdd4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -92,8 +92,8 @@ static int tc = TC_DEFAULT;
module_param(tc, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(tc, "DMA threshold control value");
-#define DMA_BUFFER_SIZE BUF_SIZE_4KiB
-static int buf_sz = DMA_BUFFER_SIZE;
+#define DEFAULT_BUFSIZE 1536
+static int buf_sz = DEFAULT_BUFSIZE;
module_param(buf_sz, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(buf_sz, "DMA buffer size");
@@ -136,8 +136,8 @@ static void stmmac_verify_args(void)
dma_rxsize = DMA_RX_SIZE;
if (unlikely(dma_txsize < 0))
dma_txsize = DMA_TX_SIZE;
- if (unlikely((buf_sz < DMA_BUFFER_SIZE) || (buf_sz > BUF_SIZE_16KiB)))
- buf_sz = DMA_BUFFER_SIZE;
+ if (unlikely((buf_sz < DEFAULT_BUFSIZE) || (buf_sz > BUF_SIZE_16KiB)))
+ buf_sz = DEFAULT_BUFSIZE;
if (unlikely(flow_ctrl > 1))
flow_ctrl = FLOW_AUTO;
else if (likely(flow_ctrl < 0))
@@ -286,10 +286,25 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
/* MAC core supports the EEE feature. */
if (priv->dma_cap.eee) {
+ int tx_lpi_timer = priv->tx_lpi_timer;
+
/* Check if the PHY supports EEE */
- if (phy_init_eee(priv->phydev, 1))
+ if (phy_init_eee(priv->phydev, 1)) {
+ /* To manage at run-time if the EEE cannot be supported
+ * anymore (for example because the lp caps have been
+ * changed).
+ * In that case the driver disable own timers.
+ */
+ if (priv->eee_active) {
+ pr_debug("stmmac: disable EEE\n");
+ del_timer_sync(&priv->eee_ctrl_timer);
+ priv->hw->mac->set_eee_timer(priv->ioaddr, 0,
+ tx_lpi_timer);
+ }
+ priv->eee_active = 0;
goto out;
-
+ }
+ /* Activate the EEE and start timers */
if (!priv->eee_active) {
priv->eee_active = 1;
init_timer(&priv->eee_ctrl_timer);
@@ -300,13 +315,13 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
priv->hw->mac->set_eee_timer(priv->ioaddr,
STMMAC_DEFAULT_LIT_LS,
- priv->tx_lpi_timer);
+ tx_lpi_timer);
} else
/* Set HW EEE according to the speed */
priv->hw->mac->set_eee_pls(priv->ioaddr,
priv->phydev->link);
- pr_info("stmmac: Energy-Efficient Ethernet initialized\n");
+ pr_debug("stmmac: Energy-Efficient Ethernet initialized\n");
ret = true;
}
@@ -886,10 +901,10 @@ static int stmmac_set_bfsize(int mtu, int bufsize)
ret = BUF_SIZE_8KiB;
else if (mtu >= BUF_SIZE_2KiB)
ret = BUF_SIZE_4KiB;
- else if (mtu >= DMA_BUFFER_SIZE)
+ else if (mtu > DEFAULT_BUFSIZE)
ret = BUF_SIZE_2KiB;
else
- ret = DMA_BUFFER_SIZE;
+ ret = DEFAULT_BUFSIZE;
return ret;
}
@@ -951,9 +966,9 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
p->des2 = priv->rx_skbuff_dma[i];
- if ((priv->mode == STMMAC_RING_MODE) &&
+ if ((priv->hw->mode->init_desc3) &&
(priv->dma_buf_sz == BUF_SIZE_16KiB))
- priv->hw->ring->init_desc3(p);
+ priv->hw->mode->init_desc3(p);
return 0;
}
@@ -984,11 +999,8 @@ static int init_dma_desc_rings(struct net_device *dev)
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.
- */
- if (priv->mode == STMMAC_RING_MODE)
- bfsize = priv->hw->ring->set_16kib_bfsize(dev->mtu);
+ if (priv->hw->mode->set_16kib_bfsize)
+ bfsize = priv->hw->mode->set_16kib_bfsize(dev->mtu);
if (bfsize < BUF_SIZE_16KiB)
bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz);
@@ -1029,15 +1041,15 @@ static int init_dma_desc_rings(struct net_device *dev)
/* Setup the chained descriptor addresses */
if (priv->mode == STMMAC_CHAIN_MODE) {
if (priv->extend_desc) {
- priv->hw->chain->init(priv->dma_erx, priv->dma_rx_phy,
- rxsize, 1);
- priv->hw->chain->init(priv->dma_etx, priv->dma_tx_phy,
- txsize, 1);
+ priv->hw->mode->init(priv->dma_erx, priv->dma_rx_phy,
+ rxsize, 1);
+ priv->hw->mode->init(priv->dma_etx, priv->dma_tx_phy,
+ txsize, 1);
} else {
- priv->hw->chain->init(priv->dma_rx, priv->dma_rx_phy,
- rxsize, 0);
- priv->hw->chain->init(priv->dma_tx, priv->dma_tx_phy,
- txsize, 0);
+ priv->hw->mode->init(priv->dma_rx, priv->dma_rx_phy,
+ rxsize, 0);
+ priv->hw->mode->init(priv->dma_tx, priv->dma_tx_phy,
+ txsize, 0);
}
}
@@ -1288,10 +1300,10 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
DMA_TO_DEVICE);
priv->tx_skbuff_dma[entry] = 0;
}
- priv->hw->ring->clean_desc3(priv, p);
+ priv->hw->mode->clean_desc3(priv, p);
if (likely(skb != NULL)) {
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
priv->tx_skbuff[entry] = NULL;
}
@@ -1705,7 +1717,7 @@ static int stmmac_open(struct net_device *dev)
priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize);
priv->dma_buf_sz = STMMAC_ALIGN(buf_sz);
- alloc_dma_desc_resources(priv);
+ ret = alloc_dma_desc_resources(priv);
if (ret < 0) {
pr_err("%s: DMA descriptors allocation failed\n", __func__);
goto dma_desc_error;
@@ -1844,6 +1856,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
int nfrags = skb_shinfo(skb)->nr_frags;
struct dma_desc *desc, *first;
unsigned int nopaged_len = skb_headlen(skb);
+ unsigned int enh_desc = priv->plat->enh_desc;
if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) {
if (!netif_queue_stopped(dev)) {
@@ -1871,27 +1884,19 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
first = desc;
/* To program the descriptors according to the size of the frame */
- if (priv->mode == STMMAC_RING_MODE) {
- is_jumbo = priv->hw->ring->is_jumbo_frm(skb->len,
- priv->plat->enh_desc);
- if (unlikely(is_jumbo))
- entry = priv->hw->ring->jumbo_frm(priv, skb,
- csum_insertion);
- } else {
- is_jumbo = priv->hw->chain->is_jumbo_frm(skb->len,
- priv->plat->enh_desc);
- if (unlikely(is_jumbo))
- entry = priv->hw->chain->jumbo_frm(priv, skb,
- csum_insertion);
- }
+ if (enh_desc)
+ is_jumbo = priv->hw->mode->is_jumbo_frm(skb->len, enh_desc);
+
if (likely(!is_jumbo)) {
desc->des2 = dma_map_single(priv->device, skb->data,
nopaged_len, DMA_TO_DEVICE);
priv->tx_skbuff_dma[entry] = desc->des2;
priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
csum_insertion, priv->mode);
- } else
+ } else {
desc = first;
+ entry = priv->hw->mode->jumbo_frm(priv, skb, csum_insertion);
+ }
for (i = 0; i < nfrags; i++) {
const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
@@ -2029,7 +2034,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
p->des2 = priv->rx_skbuff_dma[entry];
- priv->hw->ring->refill_desc3(priv, p);
+ priv->hw->mode->refill_desc3(priv, p);
if (netif_msg_rx_status(priv))
pr_debug("\trefill entry #%d\n", entry);
@@ -2633,11 +2638,11 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
/* To use the chained or ring mode */
if (chain_mode) {
- priv->hw->chain = &chain_mode_ops;
+ priv->hw->mode = &chain_mode_ops;
pr_info(" Chain mode enabled\n");
priv->mode = STMMAC_CHAIN_MODE;
} else {
- priv->hw->ring = &ring_mode_ops;
+ priv->hw->mode = &ring_mode_ops;
pr_info(" Ring mode enabled\n");
priv->mode = STMMAC_RING_MODE;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 5884a7d2063b..46aef5108bea 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -33,6 +33,14 @@ static const struct of_device_id stmmac_dt_ids[] = {
#ifdef CONFIG_DWMAC_SUNXI
{ .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data},
#endif
+#ifdef CONFIG_DWMAC_STI
+ { .compatible = "st,stih415-dwmac", .data = &sti_gmac_data},
+ { .compatible = "st,stih416-dwmac", .data = &sti_gmac_data},
+ { .compatible = "st,stid127-dwmac", .data = &sti_gmac_data},
+#endif
+#ifdef CONFIG_DWMAC_SOCFPGA
+ { .compatible = "altr,socfpga-stmmac", .data = &socfpga_gmac_data },
+#endif
/* SoC specific glue layers should come before generic bindings */
{ .compatible = "st,spear600-gmac"},
{ .compatible = "snps,dwmac-3.610"},
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
index 7680581ebe12..b7ad3565566c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
@@ -164,6 +164,7 @@ static struct ptp_clock_info stmmac_ptp_clock_ops = {
.n_alarm = 0,
.n_ext_ts = 0,
.n_per_out = 0,
+ .n_pins = 0,
.pps = 0,
.adjfreq = stmmac_adjust_freq,
.adjtime = stmmac_adjust_time,
diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c
index 8e2266e1f260..79606f47a08e 100644
--- a/drivers/net/ethernet/sun/niu.c
+++ b/drivers/net/ethernet/sun/niu.c
@@ -9041,7 +9041,7 @@ static void niu_try_msix(struct niu *np, u8 *ldg_num_map)
struct msix_entry msi_vec[NIU_NUM_LDG];
struct niu_parent *parent = np->parent;
struct pci_dev *pdev = np->pdev;
- int i, num_irqs, err;
+ int i, num_irqs;
u8 first_ldg;
first_ldg = (NIU_NUM_LDG / parent->num_ports) * np->port;
@@ -9053,21 +9053,16 @@ static void niu_try_msix(struct niu *np, u8 *ldg_num_map)
(np->port == 0 ? 3 : 1));
BUG_ON(num_irqs > (NIU_NUM_LDG / parent->num_ports));
-retry:
for (i = 0; i < num_irqs; i++) {
msi_vec[i].vector = 0;
msi_vec[i].entry = i;
}
- err = pci_enable_msix(pdev, msi_vec, num_irqs);
- if (err < 0) {
+ num_irqs = pci_enable_msix_range(pdev, msi_vec, 1, num_irqs);
+ if (num_irqs < 0) {
np->flags &= ~NIU_FLAGS_MSIX;
return;
}
- if (err > 0) {
- num_irqs = err;
- goto retry;
- }
np->flags |= NIU_FLAGS_MSIX;
for (i = 0; i < num_irqs; i++)
diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c
index c2799dc46325..102a66fc54a2 100644
--- a/drivers/net/ethernet/sun/sungem.c
+++ b/drivers/net/ethernet/sun/sungem.c
@@ -688,7 +688,7 @@ static __inline__ void gem_tx(struct net_device *dev, struct gem *gp, u32 gem_st
}
dev->stats.tx_packets++;
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
}
gp->tx_old = entry;
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index bde63e3af96f..5d5fec6c4eb0 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -378,7 +378,6 @@ struct cpsw_priv {
u32 version;
u32 coal_intvl;
u32 bus_freq_mhz;
- struct net_device_stats stats;
int rx_packet_max;
int host_port;
struct clk *clk;
@@ -554,7 +553,7 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable)
* common for both the interface as the interface shares
* the same hardware resource.
*/
- for (i = 0; i <= priv->data.slaves; i++)
+ for (i = 0; i < priv->data.slaves; i++)
if (priv->slaves[i].ndev->flags & IFF_PROMISC)
flag = true;
@@ -578,7 +577,7 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable)
unsigned long timeout = jiffies + HZ;
/* Disable Learn for all ports */
- for (i = 0; i <= priv->data.slaves; i++) {
+ for (i = 0; i < priv->data.slaves; i++) {
cpsw_ale_control_set(ale, i,
ALE_PORT_NOLEARN, 1);
cpsw_ale_control_set(ale, i,
@@ -606,7 +605,7 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable)
cpsw_ale_control_set(ale, 0, ALE_P0_UNI_FLOOD, 0);
/* Enable Learn for all ports */
- for (i = 0; i <= priv->data.slaves; i++) {
+ for (i = 0; i < priv->data.slaves; i++) {
cpsw_ale_control_set(ale, i,
ALE_PORT_NOLEARN, 0);
cpsw_ale_control_set(ale, i,
@@ -673,8 +672,8 @@ static void cpsw_tx_handler(void *token, int len, int status)
if (unlikely(netif_queue_stopped(ndev)))
netif_wake_queue(ndev);
cpts_tx_timestamp(priv->cpts, skb);
- priv->stats.tx_packets++;
- priv->stats.tx_bytes += len;
+ ndev->stats.tx_packets++;
+ ndev->stats.tx_bytes += len;
dev_kfree_skb_any(skb);
}
@@ -700,10 +699,10 @@ static void cpsw_rx_handler(void *token, int len, int status)
cpts_rx_timestamp(priv->cpts, skb);
skb->protocol = eth_type_trans(skb, ndev);
netif_receive_skb(skb);
- priv->stats.rx_bytes += len;
- priv->stats.rx_packets++;
+ ndev->stats.rx_bytes += len;
+ ndev->stats.rx_packets++;
} else {
- priv->stats.rx_dropped++;
+ ndev->stats.rx_dropped++;
new_skb = skb;
}
@@ -1164,11 +1163,17 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv)
{
+ u32 slave_port;
+
+ slave_port = cpsw_get_slave_port(priv, slave->slave_num);
+
if (!slave->phy)
return;
phy_stop(slave->phy);
phy_disconnect(slave->phy);
slave->phy = NULL;
+ cpsw_ale_control_set(priv->ale, slave_port,
+ ALE_PORT_STATE, ALE_PORT_STATE_DISABLE);
}
static int cpsw_ndo_open(struct net_device *ndev)
@@ -1307,7 +1312,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
if (skb_padto(skb, CPSW_MIN_PACKET_SIZE)) {
cpsw_err(priv, tx_err, "packet pad failed\n");
- priv->stats.tx_dropped++;
+ ndev->stats.tx_dropped++;
return NETDEV_TX_OK;
}
@@ -1331,7 +1336,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
fail:
- priv->stats.tx_dropped++;
+ ndev->stats.tx_dropped++;
netif_stop_queue(ndev);
return NETDEV_TX_BUSY;
}
@@ -1471,7 +1476,6 @@ static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr)
static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
{
struct cpsw_priv *priv = netdev_priv(dev);
- struct mii_ioctl_data *data = if_mii(req);
int slave_no = cpsw_slave_index(priv);
if (!netif_running(dev))
@@ -1484,14 +1488,11 @@ static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
case SIOCGHWTSTAMP:
return cpsw_hwtstamp_get(dev, req);
#endif
- case SIOCGMIIPHY:
- data->phy_id = priv->slaves[slave_no].phy->addr;
- break;
- default:
- return -ENOTSUPP;
}
- return 0;
+ if (!priv->slaves[slave_no].phy)
+ return -EOPNOTSUPP;
+ return phy_mii_ioctl(priv->slaves[slave_no].phy, req, cmd);
}
static void cpsw_ndo_tx_timeout(struct net_device *ndev)
@@ -1499,7 +1500,7 @@ static void cpsw_ndo_tx_timeout(struct net_device *ndev)
struct cpsw_priv *priv = netdev_priv(ndev);
cpsw_err(priv, tx_err, "transmit timeout, restarting dma\n");
- priv->stats.tx_errors++;
+ ndev->stats.tx_errors++;
cpsw_intr_disable(priv);
cpdma_ctlr_int_ctrl(priv->dma, false);
cpdma_chan_stop(priv->txch);
@@ -1538,12 +1539,6 @@ static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p)
return 0;
}
-static struct net_device_stats *cpsw_ndo_get_stats(struct net_device *ndev)
-{
- struct cpsw_priv *priv = netdev_priv(ndev);
- return &priv->stats;
-}
-
#ifdef CONFIG_NET_POLL_CONTROLLER
static void cpsw_ndo_poll_controller(struct net_device *ndev)
{
@@ -1636,7 +1631,6 @@ static const struct net_device_ops cpsw_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = eth_change_mtu,
.ndo_tx_timeout = cpsw_ndo_tx_timeout,
- .ndo_get_stats = cpsw_ndo_get_stats,
.ndo_set_rx_mode = cpsw_ndo_set_rx_mode,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = cpsw_ndo_poll_controller,
@@ -1878,14 +1872,29 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
mdio_node = of_find_node_by_phandle(be32_to_cpup(parp));
phyid = be32_to_cpup(parp+1);
mdio = of_find_device_by_node(mdio_node);
- snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
- PHY_ID_FMT, mdio->name, phyid);
+
+ if (strncmp(mdio->name, "gpio", 4) == 0) {
+ /* GPIO bitbang MDIO driver attached */
+ struct mii_bus *bus = dev_get_drvdata(&mdio->dev);
+
+ snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
+ PHY_ID_FMT, bus->id, phyid);
+ } else {
+ /* davinci MDIO driver attached */
+ snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
+ PHY_ID_FMT, mdio->name, phyid);
+ }
mac_addr = of_get_mac_address(slave_node);
if (mac_addr)
memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN);
slave_data->phy_if = of_get_phy_mode(slave_node);
+ if (slave_data->phy_if < 0) {
+ pr_err("Missing or malformed slave[%d] phy-mode property\n",
+ i);
+ return slave_data->phy_if;
+ }
if (data->dual_emac) {
if (of_property_read_u32(slave_node, "dual_emac_res_vlan",
@@ -2208,10 +2217,6 @@ static int cpsw_probe(struct platform_device *pdev)
goto clean_ale_ret;
}
- if (cpts_register(&pdev->dev, priv->cpts,
- data->cpts_clock_mult, data->cpts_clock_shift))
- dev_err(priv->dev, "error registering cpts device\n");
-
cpsw_notice(priv, probe, "initialized device (regs %pa, irq %d)\n",
&ss_res->start, ndev->irq);
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index 8c351f100aca..a3bbf59eaafd 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -31,10 +31,6 @@
#ifdef CONFIG_TI_CPTS
-static struct sock_filter ptp_filter[] = {
- PTP_FILTER
-};
-
#define cpts_read32(c, r) __raw_readl(&c->reg->r)
#define cpts_write32(c, v, r) __raw_writel(v, &c->reg->r)
@@ -217,6 +213,7 @@ static struct ptp_clock_info cpts_info = {
.name = "CTPS timer",
.max_adj = 1000000,
.n_ext_ts = 0,
+ .n_pins = 0,
.pps = 0,
.adjfreq = cpts_ptp_adjfreq,
.adjtime = cpts_ptp_adjtime,
@@ -300,7 +297,7 @@ static u64 cpts_find_ts(struct cpts *cpts, struct sk_buff *skb, int ev_type)
u64 ns = 0;
struct cpts_event *event;
struct list_head *this, *next;
- unsigned int class = sk_run_filter(skb, ptp_filter);
+ unsigned int class = ptp_classify_raw(skb);
unsigned long flags;
u16 seqid;
u8 mtype;
@@ -371,10 +368,6 @@ int cpts_register(struct device *dev, struct cpts *cpts,
int err, i;
unsigned long flags;
- if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter))) {
- pr_err("cpts: bad ptp filter\n");
- return -EINVAL;
- }
cpts->info = cpts_info;
cpts->clock = ptp_clock_register(&cpts->info, dev);
if (IS_ERR(cpts->clock)) {
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c
index 364d0c7952c0..88ef27067bf2 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.c
+++ b/drivers/net/ethernet/ti/davinci_cpdma.c
@@ -355,7 +355,7 @@ int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr)
int i;
spin_lock_irqsave(&ctlr->lock, flags);
- if (ctlr->state != CPDMA_STATE_ACTIVE) {
+ if (ctlr->state == CPDMA_STATE_TEARDOWN) {
spin_unlock_irqrestore(&ctlr->lock, flags);
return -EINVAL;
}
@@ -891,7 +891,7 @@ int cpdma_chan_stop(struct cpdma_chan *chan)
unsigned timeout;
spin_lock_irqsave(&chan->lock, flags);
- if (chan->state != CPDMA_STATE_ACTIVE) {
+ if (chan->state == CPDMA_STATE_TEARDOWN) {
spin_unlock_irqrestore(&chan->lock, flags);
return -EINVAL;
}
diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c
index cd9b164a0434..8f0e69ce07ca 100644
--- a/drivers/net/ethernet/ti/davinci_emac.c
+++ b/drivers/net/ethernet/ti/davinci_emac.c
@@ -1532,9 +1532,9 @@ static int emac_dev_open(struct net_device *ndev)
struct device *emac_dev = &ndev->dev;
u32 cnt;
struct resource *res;
- int ret;
+ int q, m, ret;
+ int res_num = 0, irq_num = 0;
int i = 0;
- int k = 0;
struct emac_priv *priv = netdev_priv(ndev);
pm_runtime_get(&priv->pdev->dev);
@@ -1564,15 +1564,24 @@ static int emac_dev_open(struct net_device *ndev)
}
/* Request IRQ */
+ while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ,
+ res_num))) {
+ for (irq_num = res->start; irq_num <= res->end; irq_num++) {
+ dev_err(emac_dev, "Request IRQ %d\n", irq_num);
+ if (request_irq(irq_num, emac_irq, 0, ndev->name,
+ ndev)) {
+ dev_err(emac_dev,
+ "DaVinci EMAC: request_irq() failed\n");
+ ret = -EBUSY;
- 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,
- 0, ndev->name, ndev))
goto rollback;
+ }
}
- k++;
+ res_num++;
}
+ /* prepare counters for rollback in case of an error */
+ res_num--;
+ irq_num--;
/* Start/Enable EMAC hardware */
emac_hw_enable(priv);
@@ -1639,11 +1648,23 @@ static int emac_dev_open(struct net_device *ndev)
return 0;
-rollback:
-
- dev_err(emac_dev, "DaVinci EMAC: devm_request_irq() failed");
- ret = -EBUSY;
err:
+ emac_int_disable(priv);
+ napi_disable(&priv->napi);
+
+rollback:
+ for (q = res_num; q >= 0; q--) {
+ res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, q);
+ /* at the first iteration, irq_num is already set to the
+ * right value
+ */
+ if (q != res_num)
+ irq_num = res->end;
+
+ for (m = irq_num; m >= res->start; m--)
+ free_irq(m, ndev);
+ }
+ cpdma_ctlr_stop(priv->dma);
pm_runtime_put(&priv->pdev->dev);
return ret;
}
@@ -1659,6 +1680,9 @@ err:
*/
static int emac_dev_stop(struct net_device *ndev)
{
+ struct resource *res;
+ int i = 0;
+ int irq_num;
struct emac_priv *priv = netdev_priv(ndev);
struct device *emac_dev = &ndev->dev;
@@ -1674,6 +1698,13 @@ static int emac_dev_stop(struct net_device *ndev)
if (priv->phydev)
phy_disconnect(priv->phydev);
+ /* Free IRQ */
+ while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, i))) {
+ for (irq_num = res->start; irq_num <= res->end; irq_num++)
+ free_irq(irq_num, priv->ndev);
+ i++;
+ }
+
if (netif_msg_drv(priv))
dev_notice(emac_dev, "DaVinci EMAC: %s stopped\n", ndev->name);
diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c
index 023237a65720..7e1c91d41a87 100644
--- a/drivers/net/ethernet/tile/tilegx.c
+++ b/drivers/net/ethernet/tile/tilegx.c
@@ -659,6 +659,9 @@ static int tile_net_poll(struct napi_struct *napi, int budget)
struct info_mpipe *info_mpipe =
container_of(napi, struct info_mpipe, napi);
+ if (budget <= 0)
+ goto done;
+
instance = info_mpipe->instance;
while ((n = gxio_mpipe_iqueue_try_peek(
&info_mpipe->iqueue,
@@ -870,6 +873,7 @@ static struct ptp_clock_info ptp_mpipe_caps = {
.name = "mPIPE clock",
.max_adj = 999999999,
.n_ext_ts = 0,
+ .n_pins = 0,
.pps = 0,
.adjfreq = ptp_mpipe_adjfreq,
.adjtime = ptp_mpipe_adjtime,
@@ -2071,7 +2075,7 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
/* Return subqueue id on this core (one per core). */
static u16 tile_net_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv, select_queue_fallback_t fallback)
{
return smp_processor_id();
}
diff --git a/drivers/net/ethernet/tile/tilepro.c b/drivers/net/ethernet/tile/tilepro.c
index edb2e12a0fe2..e5a5c5d4ce0c 100644
--- a/drivers/net/ethernet/tile/tilepro.c
+++ b/drivers/net/ethernet/tile/tilepro.c
@@ -831,6 +831,9 @@ static int tile_net_poll(struct napi_struct *napi, int budget)
unsigned int work = 0;
+ if (budget <= 0)
+ goto done;
+
while (priv->active) {
int index = qup->__packet_receive_read;
if (index == qsp->__packet_receive_queue.__packet_write)
@@ -1821,7 +1824,7 @@ busy:
/* Handle completions. */
for (i = 0; i < nolds; i++)
- kfree_skb(olds[i]);
+ dev_consume_skb_any(olds[i]);
/* Update stats. */
u64_stats_update_begin(&stats->syncp);
@@ -2005,7 +2008,7 @@ busy:
/* Handle completions. */
for (i = 0; i < nolds; i++)
- kfree_skb(olds[i]);
+ dev_consume_skb_any(olds[i]);
/* HACK: Track "expanded" size for short packets (e.g. 42 < 60). */
u64_stats_update_begin(&stats->syncp);
@@ -2068,14 +2071,14 @@ static struct rtnl_link_stats64 *tile_net_get_stats64(struct net_device *dev,
cpu_stats = &priv->cpu[i]->stats;
do {
- start = u64_stats_fetch_begin_bh(&cpu_stats->syncp);
+ start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
trx_packets = cpu_stats->rx_packets;
ttx_packets = cpu_stats->tx_packets;
trx_bytes = cpu_stats->rx_bytes;
ttx_bytes = cpu_stats->tx_bytes;
trx_errors = cpu_stats->rx_errors;
trx_dropped = cpu_stats->rx_dropped;
- } while (u64_stats_fetch_retry_bh(&cpu_stats->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
rx_packets += trx_packets;
tx_packets += ttx_packets;
diff --git a/drivers/net/ethernet/toshiba/spider_net.c b/drivers/net/ethernet/toshiba/spider_net.c
index 3f4a32e39d27..0282d0161859 100644
--- a/drivers/net/ethernet/toshiba/spider_net.c
+++ b/drivers/net/ethernet/toshiba/spider_net.c
@@ -860,7 +860,7 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
if (skb) {
pci_unmap_single(card->pdev, buf_addr, skb->len,
PCI_DMA_TODEVICE);
- dev_kfree_skb(skb);
+ dev_consume_skb_any(skb);
}
}
return 0;
diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c
index 88e9c73cebc0..fef5573dbfca 100644
--- a/drivers/net/ethernet/toshiba/tc35815.c
+++ b/drivers/net/ethernet/toshiba/tc35815.c
@@ -1645,6 +1645,9 @@ static int tc35815_poll(struct napi_struct *napi, int budget)
int received = 0, handled;
u32 status;
+ if (budget <= 0)
+ return received;
+
spin_lock(&lp->rx_lock);
status = tc_readl(&tr->Int_Src);
do {
diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c
index ef312bc6b865..f61dc2b72bb2 100644
--- a/drivers/net/ethernet/via/via-rhine.c
+++ b/drivers/net/ethernet/via/via-rhine.c
@@ -923,7 +923,7 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc) {
dev_err(&pdev->dev,
"32-bit PCI DMA addresses not supported by the card!?\n");
- goto err_out;
+ goto err_out_pci_disable;
}
/* sanity check */
@@ -931,7 +931,7 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
(pci_resource_len(pdev, 1) < io_size)) {
rc = -EIO;
dev_err(&pdev->dev, "Insufficient PCI resources, aborting\n");
- goto err_out;
+ goto err_out_pci_disable;
}
pioaddr = pci_resource_start(pdev, 0);
@@ -942,7 +942,7 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev = alloc_etherdev(sizeof(struct rhine_private));
if (!dev) {
rc = -ENOMEM;
- goto err_out;
+ goto err_out_pci_disable;
}
SET_NETDEV_DEV(dev, &pdev->dev);
@@ -1022,7 +1022,7 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* The chip-specific entries in the device structure. */
dev->netdev_ops = &rhine_netdev_ops;
- dev->ethtool_ops = &netdev_ethtool_ops,
+ dev->ethtool_ops = &netdev_ethtool_ops;
dev->watchdog_timeo = TX_TIMEOUT;
netif_napi_add(dev, &rp->napi, rhine_napipoll, 64);
@@ -1084,6 +1084,8 @@ err_out_free_res:
pci_release_regions(pdev);
err_out_free_netdev:
free_netdev(dev);
+err_out_pci_disable:
+ pci_disable_device(pdev);
err_out:
return rc;
}
@@ -1676,7 +1678,7 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
/* Must use alignment buffer. */
if (skb->len > PKT_BUF_SZ) {
/* packet too long, drop it */
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
rp->tx_skbuff[entry] = NULL;
dev->stats.tx_dropped++;
return NETDEV_TX_OK;
@@ -1696,7 +1698,7 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
pci_map_single(rp->pdev, skb->data, skb->len,
PCI_DMA_TODEVICE);
if (dma_mapping_error(&rp->pdev->dev, rp->tx_skbuff_dma[entry])) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
rp->tx_skbuff_dma[entry] = 0;
dev->stats.tx_dropped++;
return NETDEV_TX_OK;
@@ -1834,7 +1836,7 @@ static void rhine_tx(struct net_device *dev)
rp->tx_skbuff[entry]->len,
PCI_DMA_TODEVICE);
}
- dev_kfree_skb(rp->tx_skbuff[entry]);
+ dev_consume_skb_any(rp->tx_skbuff[entry]);
rp->tx_skbuff[entry] = NULL;
entry = (++rp->dirty_tx) % TX_RING_SIZE;
}
@@ -2070,16 +2072,16 @@ rhine_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
netdev_stats_to_stats64(stats, &dev->stats);
do {
- start = u64_stats_fetch_begin_bh(&rp->rx_stats.syncp);
+ start = u64_stats_fetch_begin_irq(&rp->rx_stats.syncp);
stats->rx_packets = rp->rx_stats.packets;
stats->rx_bytes = rp->rx_stats.bytes;
- } while (u64_stats_fetch_retry_bh(&rp->rx_stats.syncp, start));
+ } while (u64_stats_fetch_retry_irq(&rp->rx_stats.syncp, start));
do {
- start = u64_stats_fetch_begin_bh(&rp->tx_stats.syncp);
+ start = u64_stats_fetch_begin_irq(&rp->tx_stats.syncp);
stats->tx_packets = rp->tx_stats.packets;
stats->tx_bytes = rp->tx_stats.bytes;
- } while (u64_stats_fetch_retry_bh(&rp->tx_stats.syncp, start));
+ } while (u64_stats_fetch_retry_irq(&rp->tx_stats.syncp, start));
return stats;
}
diff --git a/drivers/net/ethernet/via/via-velocity.c b/drivers/net/ethernet/via/via-velocity.c
index ad61d26a44f3..de08e86db209 100644
--- a/drivers/net/ethernet/via/via-velocity.c
+++ b/drivers/net/ethernet/via/via-velocity.c
@@ -2565,7 +2565,7 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb,
/* The hardware can handle at most 7 memory segments, so merge
* the skb if there are more */
if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) {
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/wiznet/w5100.c b/drivers/net/ethernet/wiznet/w5100.c
index 0df36c6ec7f4..104d46f37969 100644
--- a/drivers/net/ethernet/wiznet/w5100.c
+++ b/drivers/net/ethernet/wiznet/w5100.c
@@ -641,11 +641,10 @@ static int w5100_hw_probe(struct platform_device *pdev)
if (!mem)
return -ENXIO;
mem_size = resource_size(mem);
- if (!devm_request_mem_region(&pdev->dev, mem->start, mem_size, name))
- return -EBUSY;
- priv->base = devm_ioremap(&pdev->dev, mem->start, mem_size);
- if (!priv->base)
- return -EBUSY;
+
+ priv->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
spin_lock_init(&priv->reg_lock);
priv->indirect = mem_size < W5100_BUS_DIRECT_SIZE;
diff --git a/drivers/net/ethernet/wiznet/w5300.c b/drivers/net/ethernet/wiznet/w5300.c
index 71c27b3292f1..1f33c4c86c20 100644
--- a/drivers/net/ethernet/wiznet/w5300.c
+++ b/drivers/net/ethernet/wiznet/w5300.c
@@ -561,11 +561,10 @@ static int w5300_hw_probe(struct platform_device *pdev)
if (!mem)
return -ENXIO;
mem_size = resource_size(mem);
- if (!devm_request_mem_region(&pdev->dev, mem->start, mem_size, name))
- return -EBUSY;
- priv->base = devm_ioremap(&pdev->dev, mem->start, mem_size);
- if (!priv->base)
- return -EBUSY;
+
+ priv->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
spin_lock_init(&priv->reg_lock);
priv->indirect = mem_size < W5300_BUS_DIRECT_SIZE;
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index a4347508031c..fa193c4688da 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -771,8 +771,8 @@ static void ll_temac_recv(struct net_device *ndev)
/* if we're doing rx csum offload, set it up */
if (((lp->temac_features & TEMAC_FEATURE_RX_CSUM) != 0) &&
- (skb->protocol == __constant_htons(ETH_P_IP)) &&
- (skb->len > 64)) {
+ (skb->protocol == htons(ETH_P_IP)) &&
+ (skb->len > 64)) {
skb->csum = cur_p->app3 & 0xFFFF;
skb->ip_summed = CHECKSUM_COMPLETE;
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 1ec65feebb9e..7b0a73556264 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -26,6 +26,7 @@
#include <linux/netdevice.h>
#include <linux/of_mdio.h>
#include <linux/of_platform.h>
+#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
@@ -600,7 +601,8 @@ static void axienet_start_xmit_done(struct net_device *ndev)
size += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
packets++;
- lp->tx_bd_ci = ++lp->tx_bd_ci % TX_BD_NUM;
+ ++lp->tx_bd_ci;
+ lp->tx_bd_ci %= TX_BD_NUM;
cur_p = &lp->tx_bd_v[lp->tx_bd_ci];
status = cur_p->status;
}
@@ -686,7 +688,8 @@ static int axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
skb_headlen(skb), DMA_TO_DEVICE);
for (ii = 0; ii < num_frag; ii++) {
- lp->tx_bd_tail = ++lp->tx_bd_tail % TX_BD_NUM;
+ ++lp->tx_bd_tail;
+ lp->tx_bd_tail %= TX_BD_NUM;
cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
frag = &skb_shinfo(skb)->frags[ii];
cur_p->phys = dma_map_single(ndev->dev.parent,
@@ -702,7 +705,8 @@ static int axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
/* Start the transfer */
axienet_dma_out32(lp, XAXIDMA_TX_TDESC_OFFSET, tail_p);
- lp->tx_bd_tail = ++lp->tx_bd_tail % TX_BD_NUM;
+ ++lp->tx_bd_tail;
+ lp->tx_bd_tail %= TX_BD_NUM;
return NETDEV_TX_OK;
}
@@ -752,7 +756,7 @@ static void axienet_recv(struct net_device *ndev)
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
} else if ((lp->features & XAE_FEATURE_PARTIAL_RX_CSUM) != 0 &&
- skb->protocol == __constant_htons(ETH_P_IP) &&
+ skb->protocol == htons(ETH_P_IP) &&
skb->len > 64) {
skb->csum = be32_to_cpu(cur_p->app3 & 0xFFFF);
skb->ip_summed = CHECKSUM_COMPLETE;
@@ -774,7 +778,8 @@ static void axienet_recv(struct net_device *ndev)
cur_p->status = 0;
cur_p->sw_id_offset = (u32) new_skb;
- lp->rx_bd_ci = ++lp->rx_bd_ci % RX_BD_NUM;
+ ++lp->rx_bd_ci;
+ lp->rx_bd_ci %= RX_BD_NUM;
cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
}
diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
index 36052b98b3fc..0d87c67a5ff7 100644
--- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c
+++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
@@ -795,18 +795,6 @@ static int xemaclite_mdio_write(struct mii_bus *bus, int phy_id, int reg,
}
/**
- * xemaclite_mdio_reset - Reset the mdio bus.
- * @bus: Pointer to the MII bus
- *
- * This function is required(?) as per Documentation/networking/phy.txt.
- * There is no reset in this device; this function always returns 0.
- */
-static int xemaclite_mdio_reset(struct mii_bus *bus)
-{
- return 0;
-}
-
-/**
* xemaclite_mdio_setup - Register mii_bus for the Emaclite device
* @lp: Pointer to the Emaclite device private data
* @ofdev: Pointer to OF device structure
@@ -861,7 +849,6 @@ static int xemaclite_mdio_setup(struct net_local *lp, struct device *dev)
bus->name = "Xilinx Emaclite MDIO";
bus->read = xemaclite_mdio_read;
bus->write = xemaclite_mdio_write;
- bus->reset = xemaclite_mdio_reset;
bus->parent = dev;
bus->irq = lp->mdio_irqs; /* preallocated IRQ table */
@@ -1037,7 +1024,7 @@ static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev)
skb_tx_timestamp(new_skb);
dev->stats.tx_bytes += len;
- dev_kfree_skb(new_skb);
+ dev_consume_skb_any(new_skb);
return 0;
}
diff --git a/drivers/net/ethernet/xscale/Kconfig b/drivers/net/ethernet/xscale/Kconfig
index 3f431019e615..b81bc9fca378 100644
--- a/drivers/net/ethernet/xscale/Kconfig
+++ b/drivers/net/ethernet/xscale/Kconfig
@@ -23,6 +23,7 @@ config IXP4XX_ETH
tristate "Intel IXP4xx Ethernet support"
depends on ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR
select PHYLIB
+ select NET_PTP_CLASSIFY
---help---
Say Y here if you want to use built-in Ethernet ports
on IXP4xx processor.
diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c
index 25283f17d82f..f7e0f0f7c2e2 100644
--- a/drivers/net/ethernet/xscale/ixp4xx_eth.c
+++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c
@@ -256,10 +256,6 @@ static int ports_open;
static struct port *npe_port_tab[MAX_NPES];
static struct dma_pool *dma_pool;
-static struct sock_filter ptp_filter[] = {
- PTP_FILTER
-};
-
static int ixp_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid)
{
u8 *data = skb->data;
@@ -267,7 +263,7 @@ static int ixp_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid)
u16 *hi, *id;
u32 lo;
- if (sk_run_filter(skb, ptp_filter) != PTP_CLASS_V1_IPV4)
+ if (ptp_classify_raw(skb) != PTP_CLASS_V1_IPV4)
return 0;
offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN;
@@ -1413,11 +1409,6 @@ static int eth_init_one(struct platform_device *pdev)
char phy_id[MII_BUS_ID_SIZE + 3];
int err;
- if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter))) {
- pr_err("ixp4xx_eth: bad ptp filter\n");
- return -EINVAL;
- }
-
if (!(dev = alloc_etherdev(sizeof(struct port))))
return -ENOMEM;
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index 61dd2447e1bb..81901659cc9e 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -1184,7 +1184,7 @@ static void __exit yam_cleanup_driver(void)
struct yam_mcs *p;
int i;
- del_timer(&yam_timer);
+ del_timer_sync(&yam_timer);
for (i = 0; i < NR_PORTS; i++) {
struct net_device *dev = yam_devs[i];
if (dev) {
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 7b594ce3f21d..13010b4dae5b 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -30,6 +30,7 @@
/* Fwd declaration */
struct hv_netvsc_packet;
+struct ndis_tcp_ip_checksum_info;
/* Represent the xfer page packet which contains 1 or more netvsc packet */
struct xferpage_packet {
@@ -73,7 +74,7 @@ struct hv_netvsc_packet {
} completion;
/* This points to the memory after page_buf */
- void *extension;
+ struct rndis_message *rndis_msg;
u32 total_data_buflen;
/* Points to the send/receive buffer where the ethernet frame is */
@@ -117,7 +118,8 @@ int netvsc_send(struct hv_device *device,
void netvsc_linkstatus_callback(struct hv_device *device_obj,
unsigned int status);
int netvsc_recv_callback(struct hv_device *device_obj,
- struct hv_netvsc_packet *packet);
+ struct hv_netvsc_packet *packet,
+ struct ndis_tcp_ip_checksum_info *csum_info);
int rndis_filter_open(struct hv_device *dev);
int rndis_filter_close(struct hv_device *dev);
int rndis_filter_device_add(struct hv_device *dev,
@@ -126,11 +128,6 @@ void rndis_filter_device_remove(struct hv_device *dev);
int rndis_filter_receive(struct hv_device *dev,
struct hv_netvsc_packet *pkt);
-
-
-int rndis_filter_send(struct hv_device *dev,
- struct hv_netvsc_packet *pkt);
-
int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter);
int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac);
@@ -139,6 +136,8 @@ int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac);
#define NVSP_PROTOCOL_VERSION_1 2
#define NVSP_PROTOCOL_VERSION_2 0x30002
+#define NVSP_PROTOCOL_VERSION_4 0x40000
+#define NVSP_PROTOCOL_VERSION_5 0x50000
enum {
NVSP_MSG_TYPE_NONE = 0,
@@ -193,6 +192,23 @@ enum {
NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE,
NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE_COMP,
+
+ NVSP_MSG2_MAX = NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE_COMP,
+
+ /* Version 4 messages */
+ NVSP_MSG4_TYPE_SEND_VF_ASSOCIATION,
+ NVSP_MSG4_TYPE_SWITCH_DATA_PATH,
+ NVSP_MSG4_TYPE_UPLINK_CONNECT_STATE_DEPRECATED,
+
+ NVSP_MSG4_MAX = NVSP_MSG4_TYPE_UPLINK_CONNECT_STATE_DEPRECATED,
+
+ /* Version 5 messages */
+ NVSP_MSG5_TYPE_OID_QUERY_EX,
+ NVSP_MSG5_TYPE_OID_QUERY_EX_COMP,
+ NVSP_MSG5_TYPE_SUBCHANNEL,
+ NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE,
+
+ NVSP_MSG5_MAX = NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE,
};
enum {
@@ -447,10 +463,44 @@ union nvsp_2_message_uber {
struct nvsp_2_free_rxbuf free_rxbuf;
} __packed;
+enum nvsp_subchannel_operation {
+ NVSP_SUBCHANNEL_NONE = 0,
+ NVSP_SUBCHANNEL_ALLOCATE,
+ NVSP_SUBCHANNEL_MAX
+};
+
+struct nvsp_5_subchannel_request {
+ u32 op;
+ u32 num_subchannels;
+} __packed;
+
+struct nvsp_5_subchannel_complete {
+ u32 status;
+ u32 num_subchannels; /* Actual number of subchannels allocated */
+} __packed;
+
+struct nvsp_5_send_indirect_table {
+ /* The number of entries in the send indirection table */
+ u32 count;
+
+ /* The offset of the send indireciton table from top of this struct.
+ * The send indirection table tells which channel to put the send
+ * traffic on. Each entry is a channel number.
+ */
+ u32 offset;
+} __packed;
+
+union nvsp_5_message_uber {
+ struct nvsp_5_subchannel_request subchn_req;
+ struct nvsp_5_subchannel_complete subchn_comp;
+ struct nvsp_5_send_indirect_table send_table;
+} __packed;
+
union nvsp_all_messages {
union nvsp_message_init_uber init_msg;
union nvsp_1_message_uber v1_msg;
union nvsp_2_message_uber v2_msg;
+ union nvsp_5_message_uber v5_msg;
} __packed;
/* ALL Messages */
@@ -463,6 +513,7 @@ struct nvsp_message {
#define NETVSC_MTU 65536
#define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024*16) /* 16MB */
+#define NETVSC_RECEIVE_BUFFER_SIZE_LEGACY (1024*1024*15) /* 15MB */
#define NETVSC_RECEIVE_BUFFER_ID 0xcafe
@@ -506,6 +557,8 @@ struct netvsc_device {
/* Holds rndis device info */
void *extension;
+ /* The recive buffer for this device */
+ unsigned char cb_buffer[NETVSC_PACKET_SIZE];
};
/* NdisInitialize message */
@@ -671,9 +724,133 @@ struct ndis_pkt_8021q_info {
};
};
+struct ndis_oject_header {
+ u8 type;
+ u8 revision;
+ u16 size;
+};
+
+#define NDIS_OBJECT_TYPE_DEFAULT 0x80
+#define NDIS_OFFLOAD_PARAMETERS_REVISION_3 3
+#define NDIS_OFFLOAD_PARAMETERS_NO_CHANGE 0
+#define NDIS_OFFLOAD_PARAMETERS_LSOV2_DISABLED 1
+#define NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED 2
+#define NDIS_OFFLOAD_PARAMETERS_LSOV1_ENABLED 2
+#define NDIS_OFFLOAD_PARAMETERS_RSC_DISABLED 1
+#define NDIS_OFFLOAD_PARAMETERS_RSC_ENABLED 2
+#define NDIS_OFFLOAD_PARAMETERS_TX_RX_DISABLED 1
+#define NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED 2
+#define NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED 3
+#define NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED 4
+
+#define NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE 1
+#define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4 0
+#define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6 1
+
+/*
+ * New offload OIDs for NDIS 6
+ */
+#define OID_TCP_OFFLOAD_CURRENT_CONFIG 0xFC01020B /* query only */
+#define OID_TCP_OFFLOAD_PARAMETERS 0xFC01020C /* set only */
+#define OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES 0xFC01020D/* query only */
+#define OID_TCP_CONNECTION_OFFLOAD_CURRENT_CONFIG 0xFC01020E /* query only */
+#define OID_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES 0xFC01020F /* query */
+#define OID_OFFLOAD_ENCAPSULATION 0x0101010A /* set/query */
+
+struct ndis_offload_params {
+ struct ndis_oject_header header;
+ u8 ip_v4_csum;
+ u8 tcp_ip_v4_csum;
+ u8 udp_ip_v4_csum;
+ u8 tcp_ip_v6_csum;
+ u8 udp_ip_v6_csum;
+ u8 lso_v1;
+ u8 ip_sec_v1;
+ u8 lso_v2_ipv4;
+ u8 lso_v2_ipv6;
+ u8 tcp_connection_ip_v4;
+ u8 tcp_connection_ip_v6;
+ u32 flags;
+ u8 ip_sec_v2;
+ u8 ip_sec_v2_ip_v4;
+ struct {
+ u8 rsc_ip_v4;
+ u8 rsc_ip_v6;
+ };
+ struct {
+ u8 encapsulated_packet_task_offload;
+ u8 encapsulation_types;
+ };
+};
+
+struct ndis_tcp_ip_checksum_info {
+ union {
+ struct {
+ u32 is_ipv4:1;
+ u32 is_ipv6:1;
+ u32 tcp_checksum:1;
+ u32 udp_checksum:1;
+ u32 ip_header_checksum:1;
+ u32 reserved:11;
+ u32 tcp_header_offset:10;
+ } transmit;
+ struct {
+ u32 tcp_checksum_failed:1;
+ u32 udp_checksum_failed:1;
+ u32 ip_checksum_failed:1;
+ u32 tcp_checksum_succeeded:1;
+ u32 udp_checksum_succeeded:1;
+ u32 ip_checksum_succeeded:1;
+ u32 loopback:1;
+ u32 tcp_checksum_value_invalid:1;
+ u32 ip_checksum_value_invalid:1;
+ } receive;
+ u32 value;
+ };
+};
+
+struct ndis_tcp_lso_info {
+ union {
+ struct {
+ u32 unused:30;
+ u32 type:1;
+ u32 reserved2:1;
+ } transmit;
+ struct {
+ u32 mss:20;
+ u32 tcp_header_offset:10;
+ u32 type:1;
+ u32 reserved2:1;
+ } lso_v1_transmit;
+ struct {
+ u32 tcp_payload:30;
+ u32 type:1;
+ u32 reserved2:1;
+ } lso_v1_transmit_complete;
+ struct {
+ u32 mss:20;
+ u32 tcp_header_offset:10;
+ u32 type:1;
+ u32 ip_version:1;
+ } lso_v2_transmit;
+ struct {
+ u32 reserved:30;
+ u32 type:1;
+ u32 reserved2:1;
+ } lso_v2_transmit_complete;
+ u32 value;
+ };
+};
+
#define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \
sizeof(struct ndis_pkt_8021q_info))
+#define NDIS_CSUM_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \
+ sizeof(struct ndis_tcp_ip_checksum_info))
+
+#define NDIS_LSO_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \
+ sizeof(struct ndis_tcp_lso_info))
+
/* Format of Information buffer passed in a SetRequest for the OID */
/* OID_GEN_RNDIS_CONFIG_PARAMETER. */
struct rndis_config_parameter_info {
@@ -846,12 +1023,6 @@ struct rndis_message {
};
-struct rndis_filter_packet {
- void *completion_ctx;
- void (*completion)(void *context);
- struct rndis_message msg;
-};
-
/* Handy macros */
/* get the size of an RNDIS message. Pass in the message type, */
@@ -905,6 +1076,16 @@ struct rndis_filter_packet {
#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400
#define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800
+#define INFO_IPV4 2
+#define INFO_IPV6 4
+#define INFO_TCP 2
+#define INFO_UDP 4
+
+#define TRANSPORT_INFO_NOT_IP 0
+#define TRANSPORT_INFO_IPV4_TCP ((INFO_IPV4 << 16) | INFO_TCP)
+#define TRANSPORT_INFO_IPV4_UDP ((INFO_IPV4 << 16) | INFO_UDP)
+#define TRANSPORT_INFO_IPV6_TCP ((INFO_IPV6 << 16) | INFO_TCP)
+#define TRANSPORT_INFO_IPV6_UDP ((INFO_IPV6 << 16) | INFO_UDP)
#endif /* _HYPERV_NET_H */
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 03a2c6e17158..daddea2654ce 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -290,7 +290,7 @@ static int negotiate_nvsp_ver(struct hv_device *device,
NVSP_STAT_SUCCESS)
return -EINVAL;
- if (nvsp_ver != NVSP_PROTOCOL_VERSION_2)
+ if (nvsp_ver == NVSP_PROTOCOL_VERSION_1)
return 0;
/* NVSPv2 only: Send NDIS config */
@@ -314,6 +314,9 @@ static int netvsc_connect_vsp(struct hv_device *device)
struct nvsp_message *init_packet;
int ndis_version;
struct net_device *ndev;
+ u32 ver_list[] = { NVSP_PROTOCOL_VERSION_1, NVSP_PROTOCOL_VERSION_2,
+ NVSP_PROTOCOL_VERSION_4, NVSP_PROTOCOL_VERSION_5 };
+ int i, num_ver = 4; /* number of different NVSP versions */
net_device = get_outbound_net_device(device);
if (!net_device)
@@ -323,13 +326,14 @@ static int netvsc_connect_vsp(struct hv_device *device)
init_packet = &net_device->channel_init_pkt;
/* Negotiate the latest NVSP protocol supported */
- if (negotiate_nvsp_ver(device, net_device, init_packet,
- NVSP_PROTOCOL_VERSION_2) == 0) {
- net_device->nvsp_version = NVSP_PROTOCOL_VERSION_2;
- } else if (negotiate_nvsp_ver(device, net_device, init_packet,
- NVSP_PROTOCOL_VERSION_1) == 0) {
- net_device->nvsp_version = NVSP_PROTOCOL_VERSION_1;
- } else {
+ for (i = num_ver - 1; i >= 0; i--)
+ if (negotiate_nvsp_ver(device, net_device, init_packet,
+ ver_list[i]) == 0) {
+ net_device->nvsp_version = ver_list[i];
+ break;
+ }
+
+ if (i < 0) {
ret = -EPROTO;
goto cleanup;
}
@@ -339,7 +343,10 @@ static int netvsc_connect_vsp(struct hv_device *device)
/* Send the ndis version */
memset(init_packet, 0, sizeof(struct nvsp_message));
- ndis_version = 0x00050001;
+ if (net_device->nvsp_version <= NVSP_PROTOCOL_VERSION_4)
+ ndis_version = 0x00050001;
+ else
+ ndis_version = 0x0006001e;
init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_NDIS_VER;
init_packet->msg.v1_msg.
@@ -358,6 +365,11 @@ static int netvsc_connect_vsp(struct hv_device *device)
goto cleanup;
/* Post the big receive buffer to NetVSP */
+ if (net_device->nvsp_version <= NVSP_PROTOCOL_VERSION_2)
+ net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY;
+ else
+ net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE;
+
ret = netvsc_init_recv_buf(device);
cleanup:
@@ -432,17 +444,14 @@ static inline u32 hv_ringbuf_avail_percent(
return avail_write * 100 / ring_info->ring_datasize;
}
-static void netvsc_send_completion(struct hv_device *device,
+static void netvsc_send_completion(struct netvsc_device *net_device,
+ struct hv_device *device,
struct vmpacket_descriptor *packet)
{
- struct netvsc_device *net_device;
struct nvsp_message *nvsp_packet;
struct hv_netvsc_packet *nvsc_packet;
struct net_device *ndev;
- net_device = get_inbound_net_device(device);
- if (!net_device)
- return;
ndev = net_device->ndev;
nvsp_packet = (struct nvsp_message *)((unsigned long)packet +
@@ -561,13 +570,13 @@ int netvsc_send(struct hv_device *device,
}
static void netvsc_send_recv_completion(struct hv_device *device,
+ struct netvsc_device *net_device,
u64 transaction_id, u32 status)
{
struct nvsp_message recvcompMessage;
int retries = 0;
int ret;
struct net_device *ndev;
- struct netvsc_device *net_device = hv_get_drvdata(device);
ndev = net_device->ndev;
@@ -653,14 +662,15 @@ static void netvsc_receive_completion(void *context)
/* Send a receive completion for the xfer page packet */
if (fsend_receive_comp)
- netvsc_send_recv_completion(device, transaction_id, status);
+ netvsc_send_recv_completion(device, net_device, transaction_id,
+ status);
}
-static void netvsc_receive(struct hv_device *device,
- struct vmpacket_descriptor *packet)
+static void netvsc_receive(struct netvsc_device *net_device,
+ struct hv_device *device,
+ struct vmpacket_descriptor *packet)
{
- struct netvsc_device *net_device;
struct vmtransfer_page_packet_header *vmxferpage_packet;
struct nvsp_message *nvsp_packet;
struct hv_netvsc_packet *netvsc_packet = NULL;
@@ -673,9 +683,6 @@ static void netvsc_receive(struct hv_device *device,
LIST_HEAD(listHead);
- net_device = get_inbound_net_device(device);
- if (!net_device)
- return;
ndev = net_device->ndev;
/*
@@ -741,7 +748,7 @@ static void netvsc_receive(struct hv_device *device,
spin_unlock_irqrestore(&net_device->recv_pkt_list_lock,
flags);
- netvsc_send_recv_completion(device,
+ netvsc_send_recv_completion(device, net_device,
vmxferpage_packet->d.trans_id,
NVSP_STAT_FAIL);
@@ -800,22 +807,16 @@ static void netvsc_channel_cb(void *context)
struct netvsc_device *net_device;
u32 bytes_recvd;
u64 request_id;
- unsigned char *packet;
struct vmpacket_descriptor *desc;
unsigned char *buffer;
int bufferlen = NETVSC_PACKET_SIZE;
struct net_device *ndev;
- packet = kzalloc(NETVSC_PACKET_SIZE * sizeof(unsigned char),
- GFP_ATOMIC);
- if (!packet)
- return;
- buffer = packet;
-
net_device = get_inbound_net_device(device);
if (!net_device)
- goto out;
+ return;
ndev = net_device->ndev;
+ buffer = net_device->cb_buffer;
do {
ret = vmbus_recvpacket_raw(device->channel, buffer, bufferlen,
@@ -825,11 +826,13 @@ static void netvsc_channel_cb(void *context)
desc = (struct vmpacket_descriptor *)buffer;
switch (desc->type) {
case VM_PKT_COMP:
- netvsc_send_completion(device, desc);
+ netvsc_send_completion(net_device,
+ device, desc);
break;
case VM_PKT_DATA_USING_XFER_PAGES:
- netvsc_receive(device, desc);
+ netvsc_receive(net_device,
+ device, desc);
break;
default:
@@ -841,23 +844,16 @@ static void netvsc_channel_cb(void *context)
break;
}
- /* reset */
- if (bufferlen > NETVSC_PACKET_SIZE) {
- kfree(buffer);
- buffer = packet;
- bufferlen = NETVSC_PACKET_SIZE;
- }
} else {
- /* reset */
- if (bufferlen > NETVSC_PACKET_SIZE) {
- kfree(buffer);
- buffer = packet;
- bufferlen = NETVSC_PACKET_SIZE;
- }
-
+ /*
+ * We are done for this pass.
+ */
break;
}
+
} else if (ret == -ENOBUFS) {
+ if (bufferlen > NETVSC_PACKET_SIZE)
+ kfree(buffer);
/* Handle large packet */
buffer = kmalloc(bytes_recvd, GFP_ATOMIC);
if (buffer == NULL) {
@@ -872,8 +868,8 @@ static void netvsc_channel_cb(void *context)
}
} while (1);
-out:
- kfree(buffer);
+ if (bufferlen > NETVSC_PACKET_SIZE)
+ kfree(buffer);
return;
}
@@ -907,7 +903,6 @@ int netvsc_device_add(struct hv_device *device, void *additional_info)
ndev = net_device->ndev;
/* Initialize the NetVSC channel extension */
- net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE;
spin_lock_init(&net_device->recv_pkt_list_lock);
INIT_LIST_HEAD(&net_device->recv_pkt_list);
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 7756118c2f0a..4e4cf9e0c8d7 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -88,8 +88,12 @@ static int netvsc_open(struct net_device *net)
{
struct net_device_context *net_device_ctx = netdev_priv(net);
struct hv_device *device_obj = net_device_ctx->device_ctx;
+ struct netvsc_device *nvdev;
+ struct rndis_device *rdev;
int ret = 0;
+ netif_carrier_off(net);
+
/* Open up the device */
ret = rndis_filter_open(device_obj);
if (ret != 0) {
@@ -99,6 +103,11 @@ static int netvsc_open(struct net_device *net)
netif_start_queue(net);
+ nvdev = hv_get_drvdata(device_obj);
+ rdev = nvdev->extension;
+ if (!rdev->link_state)
+ netif_carrier_on(net);
+
return ret;
}
@@ -119,6 +128,27 @@ static int netvsc_close(struct net_device *net)
return ret;
}
+static void *init_ppi_data(struct rndis_message *msg, u32 ppi_size,
+ int pkt_type)
+{
+ struct rndis_packet *rndis_pkt;
+ struct rndis_per_packet_info *ppi;
+
+ rndis_pkt = &msg->msg.pkt;
+ rndis_pkt->data_offset += ppi_size;
+
+ ppi = (struct rndis_per_packet_info *)((void *)rndis_pkt +
+ rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_len);
+
+ ppi->size = ppi_size;
+ ppi->type = pkt_type;
+ ppi->ppi_offset = sizeof(struct rndis_per_packet_info);
+
+ rndis_pkt->per_pkt_info_len += ppi_size;
+
+ return ppi;
+}
+
static void netvsc_xmit_completion(void *context)
{
struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context;
@@ -131,22 +161,164 @@ static void netvsc_xmit_completion(void *context)
dev_kfree_skb_any(skb);
}
+static u32 fill_pg_buf(struct page *page, u32 offset, u32 len,
+ struct hv_page_buffer *pb)
+{
+ int j = 0;
+
+ /* Deal with compund pages by ignoring unused part
+ * of the page.
+ */
+ page += (offset >> PAGE_SHIFT);
+ offset &= ~PAGE_MASK;
+
+ while (len > 0) {
+ unsigned long bytes;
+
+ bytes = PAGE_SIZE - offset;
+ if (bytes > len)
+ bytes = len;
+ pb[j].pfn = page_to_pfn(page);
+ pb[j].offset = offset;
+ pb[j].len = bytes;
+
+ offset += bytes;
+ len -= bytes;
+
+ if (offset == PAGE_SIZE && len) {
+ page++;
+ offset = 0;
+ j++;
+ }
+ }
+
+ return j + 1;
+}
+
+static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb,
+ struct hv_page_buffer *pb)
+{
+ u32 slots_used = 0;
+ char *data = skb->data;
+ int frags = skb_shinfo(skb)->nr_frags;
+ int i;
+
+ /* The packet is laid out thus:
+ * 1. hdr
+ * 2. skb linear data
+ * 3. skb fragment data
+ */
+ if (hdr != NULL)
+ slots_used += fill_pg_buf(virt_to_page(hdr),
+ offset_in_page(hdr),
+ len, &pb[slots_used]);
+
+ slots_used += fill_pg_buf(virt_to_page(data),
+ offset_in_page(data),
+ skb_headlen(skb), &pb[slots_used]);
+
+ for (i = 0; i < frags; i++) {
+ skb_frag_t *frag = skb_shinfo(skb)->frags + i;
+
+ slots_used += fill_pg_buf(skb_frag_page(frag),
+ frag->page_offset,
+ skb_frag_size(frag), &pb[slots_used]);
+ }
+ return slots_used;
+}
+
+static int count_skb_frag_slots(struct sk_buff *skb)
+{
+ int i, frags = skb_shinfo(skb)->nr_frags;
+ int pages = 0;
+
+ for (i = 0; i < frags; i++) {
+ skb_frag_t *frag = skb_shinfo(skb)->frags + i;
+ unsigned long size = skb_frag_size(frag);
+ unsigned long offset = frag->page_offset;
+
+ /* Skip unused frames from start of page */
+ offset &= ~PAGE_MASK;
+ pages += PFN_UP(offset + size);
+ }
+ return pages;
+}
+
+static int netvsc_get_slots(struct sk_buff *skb)
+{
+ char *data = skb->data;
+ unsigned int offset = offset_in_page(data);
+ unsigned int len = skb_headlen(skb);
+ int slots;
+ int frag_slots;
+
+ slots = DIV_ROUND_UP(offset + len, PAGE_SIZE);
+ frag_slots = count_skb_frag_slots(skb);
+ return slots + frag_slots;
+}
+
+static u32 get_net_transport_info(struct sk_buff *skb, u32 *trans_off)
+{
+ u32 ret_val = TRANSPORT_INFO_NOT_IP;
+
+ if ((eth_hdr(skb)->h_proto != htons(ETH_P_IP)) &&
+ (eth_hdr(skb)->h_proto != htons(ETH_P_IPV6))) {
+ goto not_ip;
+ }
+
+ *trans_off = skb_transport_offset(skb);
+
+ if ((eth_hdr(skb)->h_proto == htons(ETH_P_IP))) {
+ struct iphdr *iphdr = ip_hdr(skb);
+
+ if (iphdr->protocol == IPPROTO_TCP)
+ ret_val = TRANSPORT_INFO_IPV4_TCP;
+ else if (iphdr->protocol == IPPROTO_UDP)
+ ret_val = TRANSPORT_INFO_IPV4_UDP;
+ } else {
+ if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
+ ret_val = TRANSPORT_INFO_IPV6_TCP;
+ else if (ipv6_hdr(skb)->nexthdr == IPPROTO_UDP)
+ ret_val = TRANSPORT_INFO_IPV6_UDP;
+ }
+
+not_ip:
+ return ret_val;
+}
+
static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
{
struct net_device_context *net_device_ctx = netdev_priv(net);
struct hv_netvsc_packet *packet;
int ret;
- unsigned int i, num_pages, npg_data;
-
- /* Add multipages for skb->data and additional 2 for RNDIS */
- npg_data = (((unsigned long)skb->data + skb_headlen(skb) - 1)
- >> PAGE_SHIFT) - ((unsigned long)skb->data >> PAGE_SHIFT) + 1;
- num_pages = skb_shinfo(skb)->nr_frags + npg_data + 2;
+ unsigned int num_data_pgs;
+ struct rndis_message *rndis_msg;
+ struct rndis_packet *rndis_pkt;
+ u32 rndis_msg_size;
+ bool isvlan;
+ struct rndis_per_packet_info *ppi;
+ struct ndis_tcp_ip_checksum_info *csum_info;
+ struct ndis_tcp_lso_info *lso_info;
+ int hdr_offset;
+ u32 net_trans_info;
+
+
+ /* We will atmost need two pages to describe the rndis
+ * header. We can only transmit MAX_PAGE_BUFFER_COUNT number
+ * of pages in a single packet.
+ */
+ num_data_pgs = netvsc_get_slots(skb) + 2;
+ if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) {
+ netdev_err(net, "Packet too big: %u\n", skb->len);
+ dev_kfree_skb(skb);
+ net->stats.tx_dropped++;
+ return NETDEV_TX_OK;
+ }
/* Allocate a netvsc packet based on # of frags. */
packet = kzalloc(sizeof(struct hv_netvsc_packet) +
- (num_pages * sizeof(struct hv_page_buffer)) +
- sizeof(struct rndis_filter_packet) +
+ (num_data_pgs * sizeof(struct hv_page_buffer)) +
+ sizeof(struct rndis_message) +
NDIS_VLAN_PPI_SIZE, GFP_ATOMIC);
if (!packet) {
/* out of memory, drop packet */
@@ -159,53 +331,111 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
packet->vlan_tci = skb->vlan_tci;
- packet->extension = (void *)(unsigned long)packet +
+ packet->is_data_pkt = true;
+ packet->total_data_buflen = skb->len;
+
+ packet->rndis_msg = (struct rndis_message *)((unsigned long)packet +
sizeof(struct hv_netvsc_packet) +
- (num_pages * sizeof(struct hv_page_buffer));
+ (num_data_pgs * sizeof(struct hv_page_buffer)));
- /* If the rndis msg goes beyond 1 page, we will add 1 later */
- packet->page_buf_cnt = num_pages - 1;
+ /* Set the completion routine */
+ packet->completion.send.send_completion = netvsc_xmit_completion;
+ packet->completion.send.send_completion_ctx = packet;
+ packet->completion.send.send_completion_tid = (unsigned long)skb;
- /* Initialize it from the skb */
- packet->total_data_buflen = skb->len;
+ isvlan = packet->vlan_tci & VLAN_TAG_PRESENT;
+
+ /* Add the rndis header */
+ rndis_msg = packet->rndis_msg;
+ rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET;
+ rndis_msg->msg_len = packet->total_data_buflen;
+ rndis_pkt = &rndis_msg->msg.pkt;
+ rndis_pkt->data_offset = sizeof(struct rndis_packet);
+ rndis_pkt->data_len = packet->total_data_buflen;
+ rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet);
+
+ rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet);
+
+ if (isvlan) {
+ struct ndis_pkt_8021q_info *vlan;
+
+ rndis_msg_size += NDIS_VLAN_PPI_SIZE;
+ ppi = init_ppi_data(rndis_msg, NDIS_VLAN_PPI_SIZE,
+ IEEE_8021Q_INFO);
+ vlan = (struct ndis_pkt_8021q_info *)((void *)ppi +
+ ppi->ppi_offset);
+ vlan->vlanid = packet->vlan_tci & VLAN_VID_MASK;
+ vlan->pri = (packet->vlan_tci & VLAN_PRIO_MASK) >>
+ VLAN_PRIO_SHIFT;
+ }
+
+ net_trans_info = get_net_transport_info(skb, &hdr_offset);
+ if (net_trans_info == TRANSPORT_INFO_NOT_IP)
+ goto do_send;
+
+ /*
+ * Setup the sendside checksum offload only if this is not a
+ * GSO packet.
+ */
+ if (skb_is_gso(skb))
+ goto do_lso;
- /* Start filling in the page buffers starting after RNDIS buffer. */
- packet->page_buf[1].pfn = virt_to_phys(skb->data) >> PAGE_SHIFT;
- packet->page_buf[1].offset
- = (unsigned long)skb->data & (PAGE_SIZE - 1);
- if (npg_data == 1)
- packet->page_buf[1].len = skb_headlen(skb);
+ rndis_msg_size += NDIS_CSUM_PPI_SIZE;
+ ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE,
+ TCPIP_CHKSUM_PKTINFO);
+
+ csum_info = (struct ndis_tcp_ip_checksum_info *)((void *)ppi +
+ ppi->ppi_offset);
+
+ if (net_trans_info & (INFO_IPV4 << 16))
+ csum_info->transmit.is_ipv4 = 1;
else
- packet->page_buf[1].len = PAGE_SIZE
- - packet->page_buf[1].offset;
-
- for (i = 2; i <= npg_data; i++) {
- packet->page_buf[i].pfn = virt_to_phys(skb->data
- + PAGE_SIZE * (i-1)) >> PAGE_SHIFT;
- packet->page_buf[i].offset = 0;
- packet->page_buf[i].len = PAGE_SIZE;
+ csum_info->transmit.is_ipv6 = 1;
+
+ if (net_trans_info & INFO_TCP) {
+ csum_info->transmit.tcp_checksum = 1;
+ csum_info->transmit.tcp_header_offset = hdr_offset;
+ } else if (net_trans_info & INFO_UDP) {
+ csum_info->transmit.udp_checksum = 1;
}
- if (npg_data > 1)
- packet->page_buf[npg_data].len = (((unsigned long)skb->data
- + skb_headlen(skb) - 1) & (PAGE_SIZE - 1)) + 1;
-
- /* Additional fragments are after SKB data */
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- const skb_frag_t *f = &skb_shinfo(skb)->frags[i];
-
- packet->page_buf[i+npg_data+1].pfn =
- page_to_pfn(skb_frag_page(f));
- packet->page_buf[i+npg_data+1].offset = f->page_offset;
- packet->page_buf[i+npg_data+1].len = skb_frag_size(f);
+ goto do_send;
+
+do_lso:
+ rndis_msg_size += NDIS_LSO_PPI_SIZE;
+ ppi = init_ppi_data(rndis_msg, NDIS_LSO_PPI_SIZE,
+ TCP_LARGESEND_PKTINFO);
+
+ lso_info = (struct ndis_tcp_lso_info *)((void *)ppi +
+ ppi->ppi_offset);
+
+ lso_info->lso_v2_transmit.type = NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE;
+ if (net_trans_info & (INFO_IPV4 << 16)) {
+ lso_info->lso_v2_transmit.ip_version =
+ NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4;
+ ip_hdr(skb)->tot_len = 0;
+ ip_hdr(skb)->check = 0;
+ tcp_hdr(skb)->check =
+ ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
+ ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
+ } else {
+ lso_info->lso_v2_transmit.ip_version =
+ NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6;
+ ipv6_hdr(skb)->payload_len = 0;
+ tcp_hdr(skb)->check =
+ ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+ &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
}
+ lso_info->lso_v2_transmit.tcp_header_offset = hdr_offset;
+ lso_info->lso_v2_transmit.mss = skb_shinfo(skb)->gso_size;
- /* Set the completion routine */
- packet->completion.send.send_completion = netvsc_xmit_completion;
- packet->completion.send.send_completion_ctx = packet;
- packet->completion.send.send_completion_tid = (unsigned long)skb;
+do_send:
+ /* Start filling in the page buffers with the rndis hdr */
+ rndis_msg->msg_len += rndis_msg_size;
+ packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size,
+ skb, &packet->page_buf[0]);
+
+ ret = netvsc_send(net_device_ctx->device_ctx, packet);
- ret = rndis_filter_send(net_device_ctx->device_ctx,
- packet);
if (ret == 0) {
net->stats.tx_bytes += skb->len;
net->stats.tx_packets++;
@@ -229,23 +459,24 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj,
struct net_device *net;
struct net_device_context *ndev_ctx;
struct netvsc_device *net_device;
+ struct rndis_device *rdev;
net_device = hv_get_drvdata(device_obj);
+ rdev = net_device->extension;
+
+ rdev->link_state = status != 1;
+
net = net_device->ndev;
- if (!net) {
- netdev_err(net, "got link status but net device "
- "not initialized yet\n");
+ if (!net || net->reg_state != NETREG_REGISTERED)
return;
- }
+ ndev_ctx = netdev_priv(net);
if (status == 1) {
- netif_carrier_on(net);
- ndev_ctx = netdev_priv(net);
schedule_delayed_work(&ndev_ctx->dwork, 0);
schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20));
} else {
- netif_carrier_off(net);
+ schedule_delayed_work(&ndev_ctx->dwork, 0);
}
}
@@ -254,7 +485,8 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj,
* "wire" on the specified device.
*/
int netvsc_recv_callback(struct hv_device *device_obj,
- struct hv_netvsc_packet *packet)
+ struct hv_netvsc_packet *packet,
+ struct ndis_tcp_ip_checksum_info *csum_info)
{
struct net_device *net;
struct sk_buff *skb;
@@ -281,7 +513,17 @@ int netvsc_recv_callback(struct hv_device *device_obj,
packet->total_data_buflen);
skb->protocol = eth_type_trans(skb, net);
- skb->ip_summed = CHECKSUM_NONE;
+ if (csum_info) {
+ /* We only look at the IP checksum here.
+ * Should we be dropping the packet if checksum
+ * failed? How do we deal with other checksums - TCP/UDP?
+ */
+ if (csum_info->receive.ip_checksum_succeeded)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+
if (packet->vlan_tci & VLAN_TAG_PRESENT)
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
packet->vlan_tci);
@@ -317,7 +559,7 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
if (nvdev == NULL || nvdev->destroy)
return -ENODEV;
- if (nvdev->nvsp_version == NVSP_PROTOCOL_VERSION_2)
+ if (nvdev->nvsp_version >= NVSP_PROTOCOL_VERSION_2)
limit = NETVSC_MTU;
if (mtu < 68 || mtu > limit)
@@ -388,17 +630,35 @@ static const struct net_device_ops device_ops = {
* current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, add
* another netif_notify_peers() into a delayed work, otherwise GARP packet
* will not be sent after quick migration, and cause network disconnection.
+ * Also, we update the carrier status here.
*/
-static void netvsc_send_garp(struct work_struct *w)
+static void netvsc_link_change(struct work_struct *w)
{
struct net_device_context *ndev_ctx;
struct net_device *net;
struct netvsc_device *net_device;
+ struct rndis_device *rdev;
+ bool notify;
+
+ rtnl_lock();
ndev_ctx = container_of(w, struct net_device_context, dwork.work);
net_device = hv_get_drvdata(ndev_ctx->device_ctx);
+ rdev = net_device->extension;
net = net_device->ndev;
- netdev_notify_peers(net);
+
+ if (rdev->link_state) {
+ netif_carrier_off(net);
+ notify = false;
+ } else {
+ netif_carrier_on(net);
+ notify = true;
+ }
+
+ rtnl_unlock();
+
+ if (notify)
+ netdev_notify_peers(net);
}
@@ -414,20 +674,20 @@ static int netvsc_probe(struct hv_device *dev,
if (!net)
return -ENOMEM;
- /* Set initial state */
netif_carrier_off(net);
net_device_ctx = netdev_priv(net);
net_device_ctx->device_ctx = dev;
hv_set_drvdata(dev, net);
- INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_send_garp);
+ INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change);
INIT_WORK(&net_device_ctx->work, do_set_multicast);
net->netdev_ops = &device_ops;
- /* TODO: Add GSO and Checksum offload */
- net->hw_features = 0;
- net->features = NETIF_F_HW_VLAN_CTAG_TX;
+ net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM |
+ NETIF_F_TSO;
+ net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG | NETIF_F_RXCSUM |
+ NETIF_F_IP_CSUM | NETIF_F_TSO;
SET_ETHTOOL_OPS(net, &ethtool_ops);
SET_NETDEV_DEV(net, &dev->device);
@@ -443,13 +703,13 @@ static int netvsc_probe(struct hv_device *dev,
}
memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN);
- netif_carrier_on(net);
-
ret = register_netdev(net);
if (ret != 0) {
pr_err("Unable to register netdev.\n");
rndis_filter_device_remove(dev);
free_netdev(net);
+ } else {
+ schedule_delayed_work(&net_device_ctx->dwork, 0);
}
return ret;
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index 1084e5de3ceb..4a37e3db9e32 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -58,9 +58,6 @@ struct rndis_request {
u8 request_ext[RNDIS_EXT_LEN];
};
-static void rndis_filter_send_completion(void *ctx);
-
-
static struct rndis_device *get_rndis_device(void)
{
struct rndis_device *device;
@@ -243,6 +240,22 @@ static int rndis_filter_send_request(struct rndis_device *dev,
return ret;
}
+static void rndis_set_link_state(struct rndis_device *rdev,
+ struct rndis_request *request)
+{
+ u32 link_status;
+ struct rndis_query_complete *query_complete;
+
+ query_complete = &request->response_msg.msg.query_complete;
+
+ if (query_complete->status == RNDIS_STATUS_SUCCESS &&
+ query_complete->info_buflen == sizeof(u32)) {
+ memcpy(&link_status, (void *)((unsigned long)query_complete +
+ query_complete->info_buf_offset), sizeof(u32));
+ rdev->link_state = link_status != 0;
+ }
+}
+
static void rndis_filter_receive_response(struct rndis_device *dev,
struct rndis_message *resp)
{
@@ -272,12 +285,16 @@ static void rndis_filter_receive_response(struct rndis_device *dev,
sizeof(struct rndis_message) + RNDIS_EXT_LEN) {
memcpy(&request->response_msg, resp,
resp->msg_len);
+ if (request->request_msg.ndis_msg_type ==
+ RNDIS_MSG_QUERY && request->request_msg.msg.
+ query_req.oid == RNDIS_OID_GEN_MEDIA_CONNECT_STATUS)
+ rndis_set_link_state(dev, request);
} else {
netdev_err(ndev,
"rndis response buffer overflow "
"detected (size %u max %zu)\n",
resp->msg_len,
- sizeof(struct rndis_filter_packet));
+ sizeof(struct rndis_message));
if (resp->ndis_msg_type ==
RNDIS_MSG_RESET_C) {
@@ -353,6 +370,7 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
struct rndis_packet *rndis_pkt;
u32 data_offset;
struct ndis_pkt_8021q_info *vlan;
+ struct ndis_tcp_ip_checksum_info *csum_info;
rndis_pkt = &msg->msg.pkt;
@@ -391,7 +409,8 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
pkt->vlan_tci = 0;
}
- netvsc_recv_callback(dev->net_dev->dev, pkt);
+ csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO);
+ netvsc_recv_callback(dev->net_dev->dev, pkt, csum_info);
}
int rndis_filter_receive(struct hv_device *dev,
@@ -610,6 +629,61 @@ cleanup:
return ret;
}
+int rndis_filter_set_offload_params(struct hv_device *hdev,
+ struct ndis_offload_params *req_offloads)
+{
+ struct netvsc_device *nvdev = hv_get_drvdata(hdev);
+ struct rndis_device *rdev = nvdev->extension;
+ struct net_device *ndev = nvdev->ndev;
+ struct rndis_request *request;
+ struct rndis_set_request *set;
+ struct ndis_offload_params *offload_params;
+ struct rndis_set_complete *set_complete;
+ u32 extlen = sizeof(struct ndis_offload_params);
+ int ret, t;
+
+ request = get_rndis_request(rdev, RNDIS_MSG_SET,
+ RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
+ if (!request)
+ return -ENOMEM;
+
+ set = &request->request_msg.msg.set_req;
+ set->oid = OID_TCP_OFFLOAD_PARAMETERS;
+ set->info_buflen = extlen;
+ set->info_buf_offset = sizeof(struct rndis_set_request);
+ set->dev_vc_handle = 0;
+
+ offload_params = (struct ndis_offload_params *)((ulong)set +
+ set->info_buf_offset);
+ *offload_params = *req_offloads;
+ offload_params->header.type = NDIS_OBJECT_TYPE_DEFAULT;
+ offload_params->header.revision = NDIS_OFFLOAD_PARAMETERS_REVISION_3;
+ offload_params->header.size = extlen;
+
+ ret = rndis_filter_send_request(rdev, request);
+ if (ret != 0)
+ goto cleanup;
+
+ t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
+ if (t == 0) {
+ netdev_err(ndev, "timeout before we got aOFFLOAD set response...\n");
+ /* can't put_rndis_request, since we may still receive a
+ * send-completion.
+ */
+ return -EBUSY;
+ } else {
+ set_complete = &request->response_msg.msg.set_complete;
+ if (set_complete->status != RNDIS_STATUS_SUCCESS) {
+ netdev_err(ndev, "Fail to set MAC on host side:0x%x\n",
+ set_complete->status);
+ ret = -EINVAL;
+ }
+ }
+
+cleanup:
+ put_rndis_request(rdev, request);
+ return ret;
+}
static int rndis_filter_query_device_link_status(struct rndis_device *dev)
{
@@ -620,7 +694,6 @@ static int rndis_filter_query_device_link_status(struct rndis_device *dev)
ret = rndis_filter_query_device(dev,
RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
&link_status, &size);
- dev->link_state = (link_status != 0) ? true : false;
return ret;
}
@@ -810,6 +883,7 @@ int rndis_filter_device_add(struct hv_device *dev,
struct netvsc_device *net_device;
struct rndis_device *rndis_device;
struct netvsc_device_info *device_info = additional_info;
+ struct ndis_offload_params offloads;
rndis_device = get_rndis_device();
if (!rndis_device)
@@ -849,6 +923,26 @@ int rndis_filter_device_add(struct hv_device *dev,
memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN);
+ /* Turn on the offloads; the host supports all of the relevant
+ * offloads.
+ */
+ memset(&offloads, 0, sizeof(struct ndis_offload_params));
+ /* A value of zero means "no change"; now turn on what we
+ * want.
+ */
+ offloads.ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
+ offloads.tcp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
+ offloads.udp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
+ offloads.tcp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
+ offloads.udp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
+ offloads.lso_v2_ipv4 = NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED;
+
+
+ ret = rndis_filter_set_offload_params(dev, &offloads);
+ if (ret)
+ goto err_dev_remv;
+
+
rndis_filter_query_device_link_status(rndis_device);
device_info->link_state = rndis_device->link_state;
@@ -858,6 +952,10 @@ int rndis_filter_device_add(struct hv_device *dev,
device_info->link_state ? "down" : "up");
return ret;
+
+err_dev_remv:
+ rndis_filter_device_remove(dev);
+ return ret;
}
void rndis_filter_device_remove(struct hv_device *dev)
@@ -894,101 +992,3 @@ int rndis_filter_close(struct hv_device *dev)
return rndis_filter_close_device(nvdev->extension);
}
-
-int rndis_filter_send(struct hv_device *dev,
- struct hv_netvsc_packet *pkt)
-{
- int ret;
- struct rndis_filter_packet *filter_pkt;
- struct rndis_message *rndis_msg;
- struct rndis_packet *rndis_pkt;
- u32 rndis_msg_size;
- bool isvlan = pkt->vlan_tci & VLAN_TAG_PRESENT;
-
- /* Add the rndis header */
- filter_pkt = (struct rndis_filter_packet *)pkt->extension;
-
- rndis_msg = &filter_pkt->msg;
- rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet);
- if (isvlan)
- rndis_msg_size += NDIS_VLAN_PPI_SIZE;
-
- rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET;
- rndis_msg->msg_len = pkt->total_data_buflen +
- rndis_msg_size;
-
- rndis_pkt = &rndis_msg->msg.pkt;
- rndis_pkt->data_offset = sizeof(struct rndis_packet);
- if (isvlan)
- rndis_pkt->data_offset += NDIS_VLAN_PPI_SIZE;
- rndis_pkt->data_len = pkt->total_data_buflen;
-
- if (isvlan) {
- struct rndis_per_packet_info *ppi;
- struct ndis_pkt_8021q_info *vlan;
-
- rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet);
- rndis_pkt->per_pkt_info_len = NDIS_VLAN_PPI_SIZE;
-
- ppi = (struct rndis_per_packet_info *)((ulong)rndis_pkt +
- rndis_pkt->per_pkt_info_offset);
- ppi->size = NDIS_VLAN_PPI_SIZE;
- ppi->type = IEEE_8021Q_INFO;
- ppi->ppi_offset = sizeof(struct rndis_per_packet_info);
-
- vlan = (struct ndis_pkt_8021q_info *)((ulong)ppi +
- ppi->ppi_offset);
- vlan->vlanid = pkt->vlan_tci & VLAN_VID_MASK;
- vlan->pri = (pkt->vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
- }
-
- pkt->is_data_pkt = true;
- pkt->page_buf[0].pfn = virt_to_phys(rndis_msg) >> PAGE_SHIFT;
- pkt->page_buf[0].offset =
- (unsigned long)rndis_msg & (PAGE_SIZE-1);
- pkt->page_buf[0].len = rndis_msg_size;
-
- /* Add one page_buf if the rndis msg goes beyond page boundary */
- if (pkt->page_buf[0].offset + rndis_msg_size > PAGE_SIZE) {
- int i;
- for (i = pkt->page_buf_cnt; i > 1; i--)
- pkt->page_buf[i] = pkt->page_buf[i-1];
- pkt->page_buf_cnt++;
- pkt->page_buf[0].len = PAGE_SIZE - pkt->page_buf[0].offset;
- pkt->page_buf[1].pfn = virt_to_phys((void *)((ulong)
- rndis_msg + pkt->page_buf[0].len)) >> PAGE_SHIFT;
- pkt->page_buf[1].offset = 0;
- pkt->page_buf[1].len = rndis_msg_size - pkt->page_buf[0].len;
- }
-
- /* Save the packet send completion and context */
- filter_pkt->completion = pkt->completion.send.send_completion;
- filter_pkt->completion_ctx =
- pkt->completion.send.send_completion_ctx;
-
- /* Use ours */
- pkt->completion.send.send_completion = rndis_filter_send_completion;
- pkt->completion.send.send_completion_ctx = filter_pkt;
-
- ret = netvsc_send(dev, pkt);
- if (ret != 0) {
- /*
- * Reset the completion to originals to allow retries from
- * above
- */
- pkt->completion.send.send_completion =
- filter_pkt->completion;
- pkt->completion.send.send_completion_ctx =
- filter_pkt->completion_ctx;
- }
-
- return ret;
-}
-
-static void rndis_filter_send_completion(void *ctx)
-{
- struct rndis_filter_packet *filter_pkt = ctx;
-
- /* Pass it back to the original handler */
- filter_pkt->completion(filter_pkt->completion_ctx);
-}
diff --git a/drivers/net/ieee802154/Kconfig b/drivers/net/ieee802154/Kconfig
index 08ae4655423a..3e89beab64fd 100644
--- a/drivers/net/ieee802154/Kconfig
+++ b/drivers/net/ieee802154/Kconfig
@@ -15,9 +15,9 @@ config IEEE802154_FAKEHARD
depends on IEEE802154_DRIVERS
---help---
Say Y here to enable the fake driver that serves as an example
- of HardMAC device driver.
+ of HardMAC device driver.
- This driver can also be built as a module. To do so say M here.
+ This driver can also be built as a module. To do so say M here.
The module will be called 'fakehard'.
config IEEE802154_FAKELB
@@ -31,17 +31,23 @@ config IEEE802154_FAKELB
The module will be called 'fakelb'.
config IEEE802154_AT86RF230
- depends on IEEE802154_DRIVERS && MAC802154
- tristate "AT86RF230/231 transceiver driver"
- depends on SPI
+ depends on IEEE802154_DRIVERS && MAC802154
+ tristate "AT86RF230/231/233/212 transceiver driver"
+ depends on SPI
+ ---help---
+ Say Y here to enable the at86rf230/231/233/212 SPI 802.15.4 wireless
+ controller.
+
+ This driver can also be built as a module. To do so, say M here.
+ the module will be called 'at86rf230'.
config IEEE802154_MRF24J40
- tristate "Microchip MRF24J40 transceiver driver"
- depends on IEEE802154_DRIVERS && MAC802154
- depends on SPI
- ---help---
- Say Y here to enable the MRF24J20 SPI 802.15.4 wireless
- controller.
-
- This driver can also be built as a module. To do so, say M here.
- the module will be called 'mrf24j40'.
+ tristate "Microchip MRF24J40 transceiver driver"
+ depends on IEEE802154_DRIVERS && MAC802154
+ depends on SPI
+ ---help---
+ Say Y here to enable the MRF24J20 SPI 802.15.4 wireless
+ controller.
+
+ This driver can also be built as a module. To do so, say M here.
+ the module will be called 'mrf24j40'.
diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c
index ab31544bc254..89417ac41083 100644
--- a/drivers/net/ieee802154/at86rf230.c
+++ b/drivers/net/ieee802154/at86rf230.c
@@ -31,13 +31,13 @@
#include <linux/spi/spi.h>
#include <linux/spi/at86rf230.h>
#include <linux/skbuff.h>
+#include <linux/of_gpio.h>
#include <net/mac802154.h>
#include <net/wpan-phy.h>
struct at86rf230_local {
struct spi_device *spi;
- int rstn, slp_tr, dig2;
u8 part;
u8 vers;
@@ -53,8 +53,16 @@ struct at86rf230_local {
spinlock_t lock;
bool irq_busy;
bool is_tx;
+ bool tx_aret;
+
+ int rssi_base_val;
};
+static bool is_rf212(struct at86rf230_local *local)
+{
+ return local->part == 7;
+}
+
#define RG_TRX_STATUS (0x01)
#define SR_TRX_STATUS 0x01, 0x1f, 0
#define SR_RESERVED_01_3 0x01, 0x20, 5
@@ -100,7 +108,10 @@ struct at86rf230_local {
#define SR_SFD_VALUE 0x0b, 0xff, 0
#define RG_TRX_CTRL_2 (0x0c)
#define SR_OQPSK_DATA_RATE 0x0c, 0x03, 0
-#define SR_RESERVED_0c_2 0x0c, 0x7c, 2
+#define SR_SUB_MODE 0x0c, 0x04, 2
+#define SR_BPSK_QPSK 0x0c, 0x08, 3
+#define SR_OQPSK_SUB1_RC_EN 0x0c, 0x10, 4
+#define SR_RESERVED_0c_5 0x0c, 0x60, 5
#define SR_RX_SAFE_MODE 0x0c, 0x80, 7
#define RG_ANT_DIV (0x0d)
#define SR_ANT_CTRL 0x0d, 0x03, 0
@@ -145,7 +156,7 @@ struct at86rf230_local {
#define SR_RESERVED_17_5 0x17, 0x08, 3
#define SR_AACK_UPLD_RES_FT 0x17, 0x10, 4
#define SR_AACK_FLTR_RES_FT 0x17, 0x20, 5
-#define SR_RESERVED_17_2 0x17, 0x40, 6
+#define SR_CSMA_LBT_MODE 0x17, 0x40, 6
#define SR_RESERVED_17_1 0x17, 0x80, 7
#define RG_FTN_CTRL (0x18)
#define SR_RESERVED_18_2 0x18, 0x7f, 0
@@ -234,6 +245,7 @@ struct at86rf230_local {
#define STATE_TX_ON 0x09
/* 0x0a - 0x0e */ /* 0x0a - UNSUPPORTED_ATTRIBUTE */
#define STATE_SLEEP 0x0F
+#define STATE_PREP_DEEP_SLEEP 0x10
#define STATE_BUSY_RX_AACK 0x11
#define STATE_BUSY_TX_ARET 0x12
#define STATE_RX_AACK_ON 0x16
@@ -244,6 +256,57 @@ struct at86rf230_local {
#define STATE_TRANSITION_IN_PROGRESS 0x1F
static int
+__at86rf230_detect_device(struct spi_device *spi, u16 *man_id, u8 *part,
+ u8 *version)
+{
+ u8 data[4];
+ u8 *buf = kmalloc(2, GFP_KERNEL);
+ int status;
+ struct spi_message msg;
+ struct spi_transfer xfer = {
+ .len = 2,
+ .tx_buf = buf,
+ .rx_buf = buf,
+ };
+ u8 reg;
+
+ if (!buf)
+ return -ENOMEM;
+
+ for (reg = RG_PART_NUM; reg <= RG_MAN_ID_1; reg++) {
+ buf[0] = (reg & CMD_REG_MASK) | CMD_REG;
+ buf[1] = 0xff;
+ dev_vdbg(&spi->dev, "buf[0] = %02x\n", buf[0]);
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+
+ status = spi_sync(spi, &msg);
+ dev_vdbg(&spi->dev, "status = %d\n", status);
+ if (msg.status)
+ status = msg.status;
+
+ dev_vdbg(&spi->dev, "status = %d\n", status);
+ dev_vdbg(&spi->dev, "buf[0] = %02x\n", buf[0]);
+ dev_vdbg(&spi->dev, "buf[1] = %02x\n", buf[1]);
+
+ if (status == 0)
+ data[reg - RG_PART_NUM] = buf[1];
+ else
+ break;
+ }
+
+ if (status == 0) {
+ *part = data[0];
+ *version = data[1];
+ *man_id = (data[3] << 8) | data[2];
+ }
+
+ kfree(buf);
+
+ return status;
+}
+
+static int
__at86rf230_write(struct at86rf230_local *lp, u8 addr, u8 data)
{
u8 *buf = lp->buf;
@@ -489,7 +552,9 @@ at86rf230_state(struct ieee802154_dev *dev, int state)
} while (val == STATE_TRANSITION_IN_PROGRESS);
- if (val == desired_status)
+ if (val == desired_status ||
+ (desired_status == STATE_RX_ON && val == STATE_BUSY_RX) ||
+ (desired_status == STATE_RX_AACK_ON && val == STATE_BUSY_RX_AACK))
return 0;
pr_err("unexpected state change: %d, asked for %d\n", val, state);
@@ -510,7 +575,11 @@ at86rf230_start(struct ieee802154_dev *dev)
if (rc)
return rc;
- return at86rf230_state(dev, STATE_RX_ON);
+ rc = at86rf230_state(dev, STATE_TX_ON);
+ if (rc)
+ return rc;
+
+ return at86rf230_state(dev, STATE_RX_AACK_ON);
}
static void
@@ -520,6 +589,39 @@ at86rf230_stop(struct ieee802154_dev *dev)
}
static int
+at86rf230_set_channel(struct at86rf230_local *lp, int page, int channel)
+{
+ lp->rssi_base_val = -91;
+
+ return at86rf230_write_subreg(lp, SR_CHANNEL, channel);
+}
+
+static int
+at86rf212_set_channel(struct at86rf230_local *lp, int page, int channel)
+{
+ int rc;
+
+ if (channel == 0)
+ rc = at86rf230_write_subreg(lp, SR_SUB_MODE, 0);
+ else
+ rc = at86rf230_write_subreg(lp, SR_SUB_MODE, 1);
+ if (rc < 0)
+ return rc;
+
+ if (page == 0) {
+ rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 0);
+ lp->rssi_base_val = -100;
+ } else {
+ rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 1);
+ lp->rssi_base_val = -98;
+ }
+ if (rc < 0)
+ return rc;
+
+ return at86rf230_write_subreg(lp, SR_CHANNEL, channel);
+}
+
+static int
at86rf230_channel(struct ieee802154_dev *dev, int page, int channel)
{
struct at86rf230_local *lp = dev->priv;
@@ -527,14 +629,22 @@ at86rf230_channel(struct ieee802154_dev *dev, int page, int channel)
might_sleep();
- if (page != 0 || channel < 11 || channel > 26) {
+ if (page < 0 || page > 31 ||
+ !(lp->dev->phy->channels_supported[page] & BIT(channel))) {
WARN_ON(1);
return -EINVAL;
}
- rc = at86rf230_write_subreg(lp, SR_CHANNEL, channel);
+ if (is_rf212(lp))
+ rc = at86rf212_set_channel(lp, page, channel);
+ else
+ rc = at86rf230_set_channel(lp, page, channel);
+ if (rc < 0)
+ return rc;
+
msleep(1); /* Wait for PLL */
dev->phy->current_channel = channel;
+ dev->phy->current_page = page;
return 0;
}
@@ -546,12 +656,12 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
int rc;
unsigned long flags;
- spin_lock(&lp->lock);
+ spin_lock_irqsave(&lp->lock, flags);
if (lp->irq_busy) {
- spin_unlock(&lp->lock);
+ spin_unlock_irqrestore(&lp->lock, flags);
return -EBUSY;
}
- spin_unlock(&lp->lock);
+ spin_unlock_irqrestore(&lp->lock, flags);
might_sleep();
@@ -568,6 +678,12 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
if (rc)
goto err_rx;
+ if (lp->tx_aret) {
+ rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TX_ARET_ON);
+ if (rc)
+ goto err_rx;
+ }
+
rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_BUSY_TX);
if (rc)
goto err_rx;
@@ -630,30 +746,31 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev,
struct at86rf230_local *lp = dev->priv;
if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
+ u16 addr = le16_to_cpu(filt->short_addr);
+
dev_vdbg(&lp->spi->dev,
"at86rf230_set_hw_addr_filt called for saddr\n");
- __at86rf230_write(lp, RG_SHORT_ADDR_0, filt->short_addr);
- __at86rf230_write(lp, RG_SHORT_ADDR_1, filt->short_addr >> 8);
+ __at86rf230_write(lp, RG_SHORT_ADDR_0, addr);
+ __at86rf230_write(lp, RG_SHORT_ADDR_1, addr >> 8);
}
if (changed & IEEE802515_AFILT_PANID_CHANGED) {
+ u16 pan = le16_to_cpu(filt->pan_id);
+
dev_vdbg(&lp->spi->dev,
"at86rf230_set_hw_addr_filt called for pan id\n");
- __at86rf230_write(lp, RG_PAN_ID_0, filt->pan_id);
- __at86rf230_write(lp, RG_PAN_ID_1, filt->pan_id >> 8);
+ __at86rf230_write(lp, RG_PAN_ID_0, pan);
+ __at86rf230_write(lp, RG_PAN_ID_1, pan >> 8);
}
if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
+ u8 i, addr[8];
+
+ memcpy(addr, &filt->ieee_addr, 8);
dev_vdbg(&lp->spi->dev,
"at86rf230_set_hw_addr_filt called for IEEE addr\n");
- at86rf230_write_subreg(lp, SR_IEEE_ADDR_0, filt->ieee_addr[7]);
- at86rf230_write_subreg(lp, SR_IEEE_ADDR_1, filt->ieee_addr[6]);
- at86rf230_write_subreg(lp, SR_IEEE_ADDR_2, filt->ieee_addr[5]);
- at86rf230_write_subreg(lp, SR_IEEE_ADDR_3, filt->ieee_addr[4]);
- at86rf230_write_subreg(lp, SR_IEEE_ADDR_4, filt->ieee_addr[3]);
- at86rf230_write_subreg(lp, SR_IEEE_ADDR_5, filt->ieee_addr[2]);
- at86rf230_write_subreg(lp, SR_IEEE_ADDR_6, filt->ieee_addr[1]);
- at86rf230_write_subreg(lp, SR_IEEE_ADDR_7, filt->ieee_addr[0]);
+ for (i = 0; i < 8; i++)
+ __at86rf230_write(lp, RG_IEEE_ADDR_0 + i, addr[i]);
}
if (changed & IEEE802515_AFILT_PANC_CHANGED) {
@@ -668,6 +785,93 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev,
return 0;
}
+static int
+at86rf212_set_txpower(struct ieee802154_dev *dev, int db)
+{
+ struct at86rf230_local *lp = dev->priv;
+
+ /* typical maximum output is 5dBm with RG_PHY_TX_PWR 0x60, lower five
+ * bits decrease power in 1dB steps. 0x60 represents extra PA gain of
+ * 0dB.
+ * thus, supported values for db range from -26 to 5, for 31dB of
+ * reduction to 0dB of reduction.
+ */
+ if (db > 5 || db < -26)
+ return -EINVAL;
+
+ db = -(db - 5);
+
+ return __at86rf230_write(lp, RG_PHY_TX_PWR, 0x60 | db);
+}
+
+static int
+at86rf212_set_lbt(struct ieee802154_dev *dev, bool on)
+{
+ struct at86rf230_local *lp = dev->priv;
+
+ return at86rf230_write_subreg(lp, SR_CSMA_LBT_MODE, on);
+}
+
+static int
+at86rf212_set_cca_mode(struct ieee802154_dev *dev, u8 mode)
+{
+ struct at86rf230_local *lp = dev->priv;
+
+ return at86rf230_write_subreg(lp, SR_CCA_MODE, mode);
+}
+
+static int
+at86rf212_set_cca_ed_level(struct ieee802154_dev *dev, s32 level)
+{
+ struct at86rf230_local *lp = dev->priv;
+ int desens_steps;
+
+ if (level < lp->rssi_base_val || level > 30)
+ return -EINVAL;
+
+ desens_steps = (level - lp->rssi_base_val) * 100 / 207;
+
+ return at86rf230_write_subreg(lp, SR_CCA_ED_THRES, desens_steps);
+}
+
+static int
+at86rf212_set_csma_params(struct ieee802154_dev *dev, u8 min_be, u8 max_be,
+ u8 retries)
+{
+ struct at86rf230_local *lp = dev->priv;
+ int rc;
+
+ if (min_be > max_be || max_be > 8 || retries > 5)
+ return -EINVAL;
+
+ rc = at86rf230_write_subreg(lp, SR_MIN_BE, min_be);
+ if (rc)
+ return rc;
+
+ rc = at86rf230_write_subreg(lp, SR_MAX_BE, max_be);
+ if (rc)
+ return rc;
+
+ return at86rf230_write_subreg(lp, SR_MAX_CSMA_RETRIES, max_be);
+}
+
+static int
+at86rf212_set_frame_retries(struct ieee802154_dev *dev, s8 retries)
+{
+ struct at86rf230_local *lp = dev->priv;
+ int rc = 0;
+
+ if (retries < -1 || retries > 15)
+ return -EINVAL;
+
+ lp->tx_aret = retries >= 0;
+
+ if (retries >= 0)
+ rc = at86rf230_write_subreg(lp, SR_MAX_FRAME_RETRIES, retries);
+
+ return rc;
+}
+
static struct ieee802154_ops at86rf230_ops = {
.owner = THIS_MODULE,
.xmit = at86rf230_xmit,
@@ -678,6 +882,22 @@ static struct ieee802154_ops at86rf230_ops = {
.set_hw_addr_filt = at86rf230_set_hw_addr_filt,
};
+static struct ieee802154_ops at86rf212_ops = {
+ .owner = THIS_MODULE,
+ .xmit = at86rf230_xmit,
+ .ed = at86rf230_ed,
+ .set_channel = at86rf230_channel,
+ .start = at86rf230_start,
+ .stop = at86rf230_stop,
+ .set_hw_addr_filt = at86rf230_set_hw_addr_filt,
+ .set_txpower = at86rf212_set_txpower,
+ .set_lbt = at86rf212_set_lbt,
+ .set_cca_mode = at86rf212_set_cca_mode,
+ .set_cca_ed_level = at86rf212_set_cca_ed_level,
+ .set_csma_params = at86rf212_set_csma_params,
+ .set_frame_retries = at86rf212_set_frame_retries,
+};
+
static void at86rf230_irqwork(struct work_struct *work)
{
struct at86rf230_local *lp =
@@ -695,8 +915,8 @@ static void at86rf230_irqwork(struct work_struct *work)
status &= ~IRQ_TRX_UR; /* FIXME: possibly handle ???*/
if (status & IRQ_TRX_END) {
- spin_lock_irqsave(&lp->lock, flags);
status &= ~IRQ_TRX_END;
+ spin_lock_irqsave(&lp->lock, flags);
if (lp->is_tx) {
lp->is_tx = 0;
spin_unlock_irqrestore(&lp->lock, flags);
@@ -725,10 +945,11 @@ static void at86rf230_irqwork_level(struct work_struct *work)
static irqreturn_t at86rf230_isr(int irq, void *data)
{
struct at86rf230_local *lp = data;
+ unsigned long flags;
- spin_lock(&lp->lock);
+ spin_lock_irqsave(&lp->lock, flags);
lp->irq_busy = 1;
- spin_unlock(&lp->lock);
+ spin_unlock_irqrestore(&lp->lock, flags);
schedule_work(&lp->irqwork);
@@ -752,22 +973,15 @@ static int at86rf230_hw_init(struct at86rf230_local *lp)
struct at86rf230_platform_data *pdata = lp->spi->dev.platform_data;
int rc, irq_pol;
u8 status;
+ u8 csma_seed[2];
rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
if (rc)
return rc;
- dev_info(&lp->spi->dev, "Status: %02x\n", status);
- if (status == STATE_P_ON) {
- rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TRX_OFF);
- if (rc)
- return rc;
- msleep(1);
- rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
- if (rc)
- return rc;
- dev_info(&lp->spi->dev, "Status: %02x\n", status);
- }
+ rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_FORCE_TRX_OFF);
+ if (rc)
+ return rc;
/* configure irq polarity, defaults to high active */
if (pdata->irq_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW))
@@ -783,6 +997,14 @@ static int at86rf230_hw_init(struct at86rf230_local *lp)
if (rc)
return rc;
+ get_random_bytes(csma_seed, ARRAY_SIZE(csma_seed));
+ rc = at86rf230_write_subreg(lp, SR_CSMA_SEED_0, csma_seed[0]);
+ if (rc)
+ return rc;
+ rc = at86rf230_write_subreg(lp, SR_CSMA_SEED_1, csma_seed[1]);
+ if (rc)
+ return rc;
+
/* CLKM changes are applied immediately */
rc = at86rf230_write_subreg(lp, SR_CLKM_SHA_SEL, 0x00);
if (rc)
@@ -795,16 +1017,6 @@ static int at86rf230_hw_init(struct at86rf230_local *lp)
/* Wait the next SLEEP cycle */
msleep(100);
- rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TX_ON);
- if (rc)
- return rc;
- msleep(1);
-
- rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
- if (rc)
- return rc;
- dev_info(&lp->spi->dev, "Status: %02x\n", status);
-
rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &status);
if (rc)
return rc;
@@ -824,14 +1036,38 @@ static int at86rf230_hw_init(struct at86rf230_local *lp)
return 0;
}
-static void at86rf230_fill_data(struct spi_device *spi)
+static struct at86rf230_platform_data *
+at86rf230_get_pdata(struct spi_device *spi)
{
- struct at86rf230_local *lp = spi_get_drvdata(spi);
- struct at86rf230_platform_data *pdata = spi->dev.platform_data;
+ struct at86rf230_platform_data *pdata;
+ const char *irq_type;
+
+ if (!IS_ENABLED(CONFIG_OF) || !spi->dev.of_node)
+ return spi->dev.platform_data;
+
+ pdata = devm_kzalloc(&spi->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ goto done;
+
+ pdata->rstn = of_get_named_gpio(spi->dev.of_node, "reset-gpio", 0);
+ pdata->slp_tr = of_get_named_gpio(spi->dev.of_node, "sleep-gpio", 0);
+
+ pdata->irq_type = IRQF_TRIGGER_RISING;
+ of_property_read_string(spi->dev.of_node, "irq-type", &irq_type);
+ if (!strcmp(irq_type, "level-high"))
+ pdata->irq_type = IRQF_TRIGGER_HIGH;
+ else if (!strcmp(irq_type, "level-low"))
+ pdata->irq_type = IRQF_TRIGGER_LOW;
+ else if (!strcmp(irq_type, "edge-rising"))
+ pdata->irq_type = IRQF_TRIGGER_RISING;
+ else if (!strcmp(irq_type, "edge-falling"))
+ pdata->irq_type = IRQF_TRIGGER_FALLING;
+ else
+ dev_warn(&spi->dev, "wrong irq-type specified using edge-rising\n");
- lp->rstn = pdata->rstn;
- lp->slp_tr = pdata->slp_tr;
- lp->dig2 = pdata->dig2;
+ spi->dev.platform_data = pdata;
+done:
+ return pdata;
}
static int at86rf230_probe(struct spi_device *spi)
@@ -839,133 +1075,146 @@ static int at86rf230_probe(struct spi_device *spi)
struct at86rf230_platform_data *pdata;
struct ieee802154_dev *dev;
struct at86rf230_local *lp;
- u8 man_id_0, man_id_1, status;
+ u16 man_id = 0;
+ u8 part = 0, version = 0, status;
irq_handler_t irq_handler;
work_func_t irq_worker;
- int rc, supported = 0;
+ int rc;
const char *chip;
+ struct ieee802154_ops *ops = NULL;
if (!spi->irq) {
dev_err(&spi->dev, "no IRQ specified\n");
return -EINVAL;
}
- pdata = spi->dev.platform_data;
+ pdata = at86rf230_get_pdata(spi);
if (!pdata) {
dev_err(&spi->dev, "no platform_data\n");
return -EINVAL;
}
- dev = ieee802154_alloc_device(sizeof(*lp), &at86rf230_ops);
- if (!dev)
- return -ENOMEM;
-
- lp = dev->priv;
- lp->dev = dev;
-
- lp->spi = spi;
-
- dev->parent = &spi->dev;
- dev->extra_tx_headroom = 0;
- /* We do support only 2.4 Ghz */
- dev->phy->channels_supported[0] = 0x7FFF800;
- dev->flags = IEEE802154_HW_OMIT_CKSUM;
-
- if (pdata->irq_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
- irq_worker = at86rf230_irqwork;
- irq_handler = at86rf230_isr;
- } else {
- irq_worker = at86rf230_irqwork_level;
- irq_handler = at86rf230_isr_level;
+ if (gpio_is_valid(pdata->rstn)) {
+ rc = gpio_request(pdata->rstn, "rstn");
+ if (rc)
+ return rc;
}
- mutex_init(&lp->bmux);
- INIT_WORK(&lp->irqwork, irq_worker);
- spin_lock_init(&lp->lock);
- init_completion(&lp->tx_complete);
-
- spi_set_drvdata(spi, lp);
-
- at86rf230_fill_data(spi);
-
- rc = gpio_request(lp->rstn, "rstn");
- if (rc)
- goto err_rstn;
-
- if (gpio_is_valid(lp->slp_tr)) {
- rc = gpio_request(lp->slp_tr, "slp_tr");
+ if (gpio_is_valid(pdata->slp_tr)) {
+ rc = gpio_request(pdata->slp_tr, "slp_tr");
if (rc)
goto err_slp_tr;
}
- rc = gpio_direction_output(lp->rstn, 1);
- if (rc)
- goto err_gpio_dir;
+ if (gpio_is_valid(pdata->rstn)) {
+ rc = gpio_direction_output(pdata->rstn, 1);
+ if (rc)
+ goto err_gpio_dir;
+ }
- if (gpio_is_valid(lp->slp_tr)) {
- rc = gpio_direction_output(lp->slp_tr, 0);
+ if (gpio_is_valid(pdata->slp_tr)) {
+ rc = gpio_direction_output(pdata->slp_tr, 0);
if (rc)
goto err_gpio_dir;
}
/* Reset */
- msleep(1);
- gpio_set_value(lp->rstn, 0);
- msleep(1);
- gpio_set_value(lp->rstn, 1);
- msleep(1);
+ if (gpio_is_valid(pdata->rstn)) {
+ udelay(1);
+ gpio_set_value(pdata->rstn, 0);
+ udelay(1);
+ gpio_set_value(pdata->rstn, 1);
+ usleep_range(120, 240);
+ }
- rc = at86rf230_read_subreg(lp, SR_MAN_ID_0, &man_id_0);
- if (rc)
- goto err_gpio_dir;
- rc = at86rf230_read_subreg(lp, SR_MAN_ID_1, &man_id_1);
- if (rc)
+ rc = __at86rf230_detect_device(spi, &man_id, &part, &version);
+ if (rc < 0)
goto err_gpio_dir;
- if (man_id_1 != 0x00 || man_id_0 != 0x1f) {
+ if (man_id != 0x001f) {
dev_err(&spi->dev, "Non-Atmel dev found (MAN_ID %02x %02x)\n",
- man_id_1, man_id_0);
+ man_id >> 8, man_id & 0xFF);
rc = -EINVAL;
goto err_gpio_dir;
}
- rc = at86rf230_read_subreg(lp, SR_PART_NUM, &lp->part);
- if (rc)
- goto err_gpio_dir;
-
- rc = at86rf230_read_subreg(lp, SR_VERSION_NUM, &lp->vers);
- if (rc)
- goto err_gpio_dir;
-
- switch (lp->part) {
+ switch (part) {
case 2:
chip = "at86rf230";
- /* supported = 1; FIXME: should be easy to support; */
+ /* FIXME: should be easy to support; */
break;
case 3:
chip = "at86rf231";
- supported = 1;
+ ops = &at86rf230_ops;
+ break;
+ case 7:
+ chip = "at86rf212";
+ if (version == 1)
+ ops = &at86rf212_ops;
+ break;
+ case 11:
+ chip = "at86rf233";
+ ops = &at86rf230_ops;
break;
default:
chip = "UNKNOWN";
break;
}
- dev_info(&spi->dev, "Detected %s chip version %d\n", chip, lp->vers);
- if (!supported) {
+ dev_info(&spi->dev, "Detected %s chip version %d\n", chip, version);
+ if (!ops) {
rc = -ENOTSUPP;
goto err_gpio_dir;
}
+ dev = ieee802154_alloc_device(sizeof(*lp), ops);
+ if (!dev) {
+ rc = -ENOMEM;
+ goto err_gpio_dir;
+ }
+
+ lp = dev->priv;
+ lp->dev = dev;
+ lp->part = part;
+ lp->vers = version;
+
+ lp->spi = spi;
+
+ dev->parent = &spi->dev;
+ dev->extra_tx_headroom = 0;
+ dev->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK;
+
+ if (pdata->irq_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+ irq_worker = at86rf230_irqwork;
+ irq_handler = at86rf230_isr;
+ } else {
+ irq_worker = at86rf230_irqwork_level;
+ irq_handler = at86rf230_isr_level;
+ }
+
+ mutex_init(&lp->bmux);
+ INIT_WORK(&lp->irqwork, irq_worker);
+ spin_lock_init(&lp->lock);
+ init_completion(&lp->tx_complete);
+
+ spi_set_drvdata(spi, lp);
+
+ if (is_rf212(lp)) {
+ dev->phy->channels_supported[0] = 0x00007FF;
+ dev->phy->channels_supported[2] = 0x00007FF;
+ } else {
+ dev->phy->channels_supported[0] = 0x7FFF800;
+ }
+
rc = at86rf230_hw_init(lp);
if (rc)
- goto err_gpio_dir;
+ goto err_hw_init;
rc = request_irq(spi->irq, irq_handler,
IRQF_SHARED | pdata->irq_type,
dev_name(&spi->dev), lp);
if (rc)
- goto err_gpio_dir;
+ goto err_hw_init;
/* Read irq status register to reset irq line */
rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &status);
@@ -980,30 +1229,37 @@ static int at86rf230_probe(struct spi_device *spi)
err_irq:
free_irq(spi->irq, lp);
+err_hw_init:
flush_work(&lp->irqwork);
-err_gpio_dir:
- if (gpio_is_valid(lp->slp_tr))
- gpio_free(lp->slp_tr);
-err_slp_tr:
- gpio_free(lp->rstn);
-err_rstn:
+ spi_set_drvdata(spi, NULL);
mutex_destroy(&lp->bmux);
ieee802154_free_device(lp->dev);
+
+err_gpio_dir:
+ if (gpio_is_valid(pdata->slp_tr))
+ gpio_free(pdata->slp_tr);
+err_slp_tr:
+ if (gpio_is_valid(pdata->rstn))
+ gpio_free(pdata->rstn);
return rc;
}
static int at86rf230_remove(struct spi_device *spi)
{
struct at86rf230_local *lp = spi_get_drvdata(spi);
+ struct at86rf230_platform_data *pdata = spi->dev.platform_data;
+ /* mask all at86rf230 irq's */
+ at86rf230_write_subreg(lp, SR_IRQ_MASK, 0);
ieee802154_unregister_device(lp->dev);
free_irq(spi->irq, lp);
flush_work(&lp->irqwork);
- if (gpio_is_valid(lp->slp_tr))
- gpio_free(lp->slp_tr);
- gpio_free(lp->rstn);
+ if (gpio_is_valid(pdata->slp_tr))
+ gpio_free(pdata->slp_tr);
+ if (gpio_is_valid(pdata->rstn))
+ gpio_free(pdata->rstn);
mutex_destroy(&lp->bmux);
ieee802154_free_device(lp->dev);
@@ -1012,8 +1268,19 @@ static int at86rf230_remove(struct spi_device *spi)
return 0;
}
+#if IS_ENABLED(CONFIG_OF)
+static struct of_device_id at86rf230_of_match[] = {
+ { .compatible = "atmel,at86rf230", },
+ { .compatible = "atmel,at86rf231", },
+ { .compatible = "atmel,at86rf233", },
+ { .compatible = "atmel,at86rf212", },
+ { },
+};
+#endif
+
static struct spi_driver at86rf230_driver = {
.driver = {
+ .of_match_table = of_match_ptr(at86rf230_of_match),
.name = "at86rf230",
.owner = THIS_MODULE,
},
diff --git a/drivers/net/ieee802154/fakehard.c b/drivers/net/ieee802154/fakehard.c
index bf0d55e2dd63..78f18be3bbf2 100644
--- a/drivers/net/ieee802154/fakehard.c
+++ b/drivers/net/ieee802154/fakehard.c
@@ -63,11 +63,11 @@ static struct wpan_phy *fake_get_phy(const struct net_device *dev)
*
* Return the ID of the PAN from the PIB.
*/
-static u16 fake_get_pan_id(const struct net_device *dev)
+static __le16 fake_get_pan_id(const struct net_device *dev)
{
BUG_ON(dev->type != ARPHRD_IEEE802154);
- return 0xeba1;
+ return cpu_to_le16(0xeba1);
}
/**
@@ -78,11 +78,11 @@ static u16 fake_get_pan_id(const struct net_device *dev)
* device. If the device has not yet had a short address assigned
* then this should return 0xFFFF to indicate a lack of association.
*/
-static u16 fake_get_short_addr(const struct net_device *dev)
+static __le16 fake_get_short_addr(const struct net_device *dev)
{
BUG_ON(dev->type != ARPHRD_IEEE802154);
- return 0x1;
+ return cpu_to_le16(0x1);
}
/**
@@ -149,7 +149,7 @@ static int fake_assoc_req(struct net_device *dev,
* 802.15.4-2006 document.
*/
static int fake_assoc_resp(struct net_device *dev,
- struct ieee802154_addr *addr, u16 short_addr, u8 status)
+ struct ieee802154_addr *addr, __le16 short_addr, u8 status)
{
return 0;
}
@@ -191,10 +191,10 @@ static int fake_disassoc_req(struct net_device *dev,
* Note: This is in section 7.5.2.3 of the IEEE 802.15.4-2006
* document, with 7.3.8 describing coordinator realignment.
*/
-static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr,
- u8 channel, u8 page,
- u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
- u8 coord_realign)
+static int fake_start_req(struct net_device *dev,
+ struct ieee802154_addr *addr, u8 channel, u8 page,
+ u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
+ u8 coord_realign)
{
struct wpan_phy *phy = fake_to_phy(dev);
@@ -281,8 +281,8 @@ static int ieee802154_fake_ioctl(struct net_device *dev, struct ifreq *ifr,
switch (cmd) {
case SIOCGIFADDR:
/* FIXME: fixed here, get from device IRL */
- pan_id = fake_get_pan_id(dev);
- short_addr = fake_get_short_addr(dev);
+ pan_id = le16_to_cpu(fake_get_pan_id(dev));
+ short_addr = le16_to_cpu(fake_get_short_addr(dev));
if (pan_id == IEEE802154_PANID_BROADCAST ||
short_addr == IEEE802154_ADDR_BROADCAST)
return -EADDRNOTAVAIL;
diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c
index 246befa4ba05..78a6552ed707 100644
--- a/drivers/net/ieee802154/mrf24j40.c
+++ b/drivers/net/ieee802154/mrf24j40.c
@@ -465,8 +465,8 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
/* Short Addr */
u8 addrh, addrl;
- addrh = filt->short_addr >> 8 & 0xff;
- addrl = filt->short_addr & 0xff;
+ addrh = le16_to_cpu(filt->short_addr) >> 8 & 0xff;
+ addrl = le16_to_cpu(filt->short_addr) & 0xff;
write_short_reg(devrec, REG_SADRH, addrh);
write_short_reg(devrec, REG_SADRL, addrl);
@@ -476,15 +476,16 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
/* Device Address */
- int i;
+ u8 i, addr[8];
+
+ memcpy(addr, &filt->ieee_addr, 8);
for (i = 0; i < 8; i++)
- write_short_reg(devrec, REG_EADR0+i,
- filt->ieee_addr[7-i]);
+ write_short_reg(devrec, REG_EADR0 + i, addr[i]);
#ifdef DEBUG
printk(KERN_DEBUG "Set long addr to: ");
for (i = 0; i < 8; i++)
- printk("%02hhx ", filt->ieee_addr[i]);
+ printk("%02hhx ", addr[7 - i]);
printk(KERN_DEBUG "\n");
#endif
}
@@ -492,8 +493,8 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
if (changed & IEEE802515_AFILT_PANID_CHANGED) {
/* PAN ID */
u8 panidl, panidh;
- panidh = filt->pan_id >> 8 & 0xff;
- panidl = filt->pan_id & 0xff;
+ panidh = le16_to_cpu(filt->pan_id) >> 8 & 0xff;
+ panidl = le16_to_cpu(filt->pan_id) & 0xff;
write_short_reg(devrec, REG_PANIDH, panidh);
write_short_reg(devrec, REG_PANIDL, panidl);
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index c14d39bf32d0..46a7790be004 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -136,18 +136,18 @@ static struct rtnl_link_stats64 *ifb_stats64(struct net_device *dev,
unsigned int start;
do {
- start = u64_stats_fetch_begin_bh(&dp->rsync);
+ start = u64_stats_fetch_begin_irq(&dp->rsync);
stats->rx_packets = dp->rx_packets;
stats->rx_bytes = dp->rx_bytes;
- } while (u64_stats_fetch_retry_bh(&dp->rsync, start));
+ } while (u64_stats_fetch_retry_irq(&dp->rsync, start));
do {
- start = u64_stats_fetch_begin_bh(&dp->tsync);
+ start = u64_stats_fetch_begin_irq(&dp->tsync);
stats->tx_packets = dp->tx_packets;
stats->tx_bytes = dp->tx_bytes;
- } while (u64_stats_fetch_retry_bh(&dp->tsync, start));
+ } while (u64_stats_fetch_retry_irq(&dp->tsync, start));
stats->rx_dropped = dev->stats.rx_dropped;
stats->tx_dropped = dev->stats.tx_dropped;
@@ -180,7 +180,8 @@ static void ifb_setup(struct net_device *dev)
dev->tx_queue_len = TX_Q_LIMIT;
dev->features |= IFB_FEATURES;
- dev->vlan_features |= IFB_FEATURES;
+ dev->vlan_features |= IFB_FEATURES & ~(NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_STAG_TX);
dev->flags |= IFF_NOARP;
dev->flags &= ~IFF_MULTICAST;
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index 2dc82f1d2e70..3da44d5d9149 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -210,13 +210,6 @@ config KINGSUN_DONGLE
To compile it as a module, choose M here: the module will be called
kingsun-sir.
-config EP7211_DONGLE
- tristate "Cirrus Logic clps711x I/R support"
- depends on IRTTY_SIR && ARCH_CLPS711X && IRDA
- help
- Say Y here if you want to build support for the Cirrus logic
- EP7211 chipset's infrared module.
-
config KSDAZZLE_DONGLE
tristate "KingSun Dazzle IrDA-USB dongle"
depends on IRDA && USB
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
index dfc64537f62f..be8ab5b9a4a2 100644
--- a/drivers/net/irda/Makefile
+++ b/drivers/net/irda/Makefile
@@ -35,7 +35,6 @@ obj-$(CONFIG_MCP2120_DONGLE) += mcp2120-sir.o
obj-$(CONFIG_ACT200L_DONGLE) += act200l-sir.o
obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o
obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o
-obj-$(CONFIG_EP7211_DONGLE) += ep7211-sir.o
obj-$(CONFIG_KINGSUN_DONGLE) += kingsun-sir.o
obj-$(CONFIG_KSDAZZLE_DONGLE) += ksdazzle-sir.o
obj-$(CONFIG_KS959_DONGLE) += ks959-sir.o
diff --git a/drivers/net/irda/ep7211-sir.c b/drivers/net/irda/ep7211-sir.c
deleted file mode 100644
index 5fe1f4dd3369..000000000000
--- a/drivers/net/irda/ep7211-sir.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * IR port driver for the Cirrus Logic CLPS711X processors
- *
- * Copyright 2001, Blue Mug Inc. All rights reserved.
- * Copyright 2007, Samuel Ortiz <samuel@sortiz.org>
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include <mach/hardware.h>
-
-#include "sir-dev.h"
-
-static int clps711x_dongle_open(struct sir_dev *dev)
-{
- unsigned int syscon;
-
- /* Turn on the SIR encoder. */
- syscon = clps_readl(SYSCON1);
- syscon |= SYSCON1_SIREN;
- clps_writel(syscon, SYSCON1);
-
- return 0;
-}
-
-static int clps711x_dongle_close(struct sir_dev *dev)
-{
- unsigned int syscon;
-
- /* Turn off the SIR encoder. */
- syscon = clps_readl(SYSCON1);
- syscon &= ~SYSCON1_SIREN;
- clps_writel(syscon, SYSCON1);
-
- return 0;
-}
-
-static struct dongle_driver clps711x_dongle = {
- .owner = THIS_MODULE,
- .driver_name = "EP7211 IR driver",
- .type = IRDA_EP7211_DONGLE,
- .open = clps711x_dongle_open,
- .close = clps711x_dongle_close,
-};
-
-static int clps711x_sir_probe(struct platform_device *pdev)
-{
- return irda_register_dongle(&clps711x_dongle);
-}
-
-static int clps711x_sir_remove(struct platform_device *pdev)
-{
- return irda_unregister_dongle(&clps711x_dongle);
-}
-
-static struct platform_driver clps711x_sir_driver = {
- .driver = {
- .name = "sir-clps711x",
- .owner = THIS_MODULE,
- },
- .probe = clps711x_sir_probe,
- .remove = clps711x_sir_remove,
-};
-module_platform_driver(clps711x_sir_driver);
-
-MODULE_AUTHOR("Samuel Ortiz <samuel@sortiz.org>");
-MODULE_DESCRIPTION("EP7211 IR dongle driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-13"); /* IRDA_EP7211_DONGLE */
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index 177441afeb96..24b6dddd7f2f 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -522,7 +522,6 @@ static void irtty_close(struct tty_struct *tty)
sirdev_put_instance(priv->dev);
/* Stop tty */
- irtty_stop_receiver(tty, TRUE);
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
if (tty->ops->stop)
tty->ops->stop(tty);
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index c5011e078e1b..bb96409f8c05 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -111,10 +111,10 @@ static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev,
lb_stats = per_cpu_ptr(dev->lstats, i);
do {
- start = u64_stats_fetch_begin_bh(&lb_stats->syncp);
+ start = u64_stats_fetch_begin_irq(&lb_stats->syncp);
tbytes = lb_stats->bytes;
tpackets = lb_stats->packets;
- } while (u64_stats_fetch_retry_bh(&lb_stats->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&lb_stats->syncp, start));
bytes += tbytes;
packets += tpackets;
}
@@ -136,16 +136,9 @@ static const struct ethtool_ops loopback_ethtool_ops = {
static int loopback_dev_init(struct net_device *dev)
{
- int i;
- dev->lstats = alloc_percpu(struct pcpu_lstats);
+ dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats);
if (!dev->lstats)
return -ENOMEM;
-
- for_each_possible_cpu(i) {
- struct pcpu_lstats *lb_stats;
- lb_stats = per_cpu_ptr(dev->lstats, i);
- u64_stats_init(&lb_stats->syncp);
- }
return 0;
}
@@ -160,6 +153,7 @@ static const struct net_device_ops loopback_ops = {
.ndo_init = loopback_dev_init,
.ndo_start_xmit= loopback_xmit,
.ndo_get_stats64 = loopback_get_stats64,
+ .ndo_set_mac_address = eth_mac_addr,
};
/*
@@ -174,6 +168,7 @@ static void loopback_setup(struct net_device *dev)
dev->tx_queue_len = 0;
dev->type = ARPHRD_LOOPBACK; /* 0x0001*/
dev->flags = IFF_LOOPBACK;
+ dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
dev->hw_features = NETIF_F_ALL_TSO | NETIF_F_UFO;
dev->features = NETIF_F_SG | NETIF_F_FRAGLIST
@@ -181,6 +176,7 @@ static void loopback_setup(struct net_device *dev)
| NETIF_F_UFO
| NETIF_F_HW_CSUM
| NETIF_F_RXCSUM
+ | NETIF_F_SCTP_CSUM
| NETIF_F_HIGHDMA
| NETIF_F_LLTX
| NETIF_F_NETNS_LOCAL
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 8433de4509c7..753a8c23d15d 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -506,6 +506,9 @@ static int macvlan_change_mtu(struct net_device *dev, int new_mtu)
static struct lock_class_key macvlan_netdev_xmit_lock_key;
static struct lock_class_key macvlan_netdev_addr_lock_key;
+#define ALWAYS_ON_FEATURES \
+ (NETIF_F_SG | NETIF_F_GEN_CSUM | NETIF_F_GSO_SOFTWARE | NETIF_F_LLTX)
+
#define MACVLAN_FEATURES \
(NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \
@@ -534,28 +537,21 @@ static int macvlan_init(struct net_device *dev)
{
struct macvlan_dev *vlan = netdev_priv(dev);
const struct net_device *lowerdev = vlan->lowerdev;
- int i;
dev->state = (dev->state & ~MACVLAN_STATE_MASK) |
(lowerdev->state & MACVLAN_STATE_MASK);
dev->features = lowerdev->features & MACVLAN_FEATURES;
- dev->features |= NETIF_F_LLTX;
+ dev->features |= ALWAYS_ON_FEATURES;
dev->gso_max_size = lowerdev->gso_max_size;
dev->iflink = lowerdev->ifindex;
dev->hard_header_len = lowerdev->hard_header_len;
macvlan_set_lockdep_class(dev);
- vlan->pcpu_stats = alloc_percpu(struct vlan_pcpu_stats);
+ vlan->pcpu_stats = netdev_alloc_pcpu_stats(struct vlan_pcpu_stats);
if (!vlan->pcpu_stats)
return -ENOMEM;
- for_each_possible_cpu(i) {
- struct vlan_pcpu_stats *mvlstats;
- mvlstats = per_cpu_ptr(vlan->pcpu_stats, i);
- u64_stats_init(&mvlstats->syncp);
- }
-
return 0;
}
@@ -586,13 +582,13 @@ static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev,
for_each_possible_cpu(i) {
p = per_cpu_ptr(vlan->pcpu_stats, i);
do {
- start = u64_stats_fetch_begin_bh(&p->syncp);
+ start = u64_stats_fetch_begin_irq(&p->syncp);
rx_packets = p->rx_packets;
rx_bytes = p->rx_bytes;
rx_multicast = p->rx_multicast;
tx_packets = p->tx_packets;
tx_bytes = p->tx_bytes;
- } while (u64_stats_fetch_retry_bh(&p->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&p->syncp, start));
stats->rx_packets += rx_packets;
stats->rx_bytes += rx_bytes;
@@ -699,7 +695,7 @@ static netdev_features_t macvlan_fix_features(struct net_device *dev,
features = netdev_increment_features(vlan->lowerdev->features,
features,
mask);
- features |= NETIF_F_LLTX;
+ features |= ALWAYS_ON_FEATURES;
return features;
}
@@ -879,14 +875,15 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
dev->priv_flags |= IFF_MACVLAN;
err = netdev_upper_dev_link(lowerdev, dev);
if (err)
- goto destroy_port;
-
+ goto unregister_netdev;
list_add_tail_rcu(&vlan->list, &port->vlans);
netif_stacked_transfer_operstate(lowerdev, dev);
return 0;
+unregister_netdev:
+ unregister_netdevice(dev);
destroy_port:
port->count -= 1;
if (!port->count)
diff --git a/drivers/net/nlmon.c b/drivers/net/nlmon.c
index d2bb12bfabd5..34924dfadd00 100644
--- a/drivers/net/nlmon.c
+++ b/drivers/net/nlmon.c
@@ -47,16 +47,7 @@ static int nlmon_change_mtu(struct net_device *dev, int new_mtu)
static int nlmon_dev_init(struct net_device *dev)
{
- int i;
-
- dev->lstats = alloc_percpu(struct pcpu_lstats);
-
- for_each_possible_cpu(i) {
- struct pcpu_lstats *nlmstats;
- nlmstats = per_cpu_ptr(dev->lstats, i);
- u64_stats_init(&nlmstats->syncp);
- }
-
+ dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats);
return dev->lstats == NULL ? -ENOMEM : 0;
}
@@ -99,10 +90,10 @@ nlmon_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
nl_stats = per_cpu_ptr(dev->lstats, i);
do {
- start = u64_stats_fetch_begin_bh(&nl_stats->syncp);
+ start = u64_stats_fetch_begin_irq(&nl_stats->syncp);
tbytes = nl_stats->bytes;
tpackets = nl_stats->packets;
- } while (u64_stats_fetch_retry_bh(&nl_stats->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&nl_stats->syncp, start));
packets += tpackets;
bytes += tbytes;
@@ -145,7 +136,8 @@ static void nlmon_setup(struct net_device *dev)
dev->ethtool_ops = &nlmon_ethtool_ops;
dev->destructor = free_netdev;
- dev->features = NETIF_F_FRAGLIST | NETIF_F_HIGHDMA;
+ dev->features = NETIF_F_SG | NETIF_F_FRAGLIST |
+ NETIF_F_HIGHDMA | NETIF_F_LLTX;
dev->flags = IFF_NOARP;
/* That's rather a softlimit here, which, of course,
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 9b5d46c03eed..6a17f92153b3 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -71,6 +71,12 @@ config BCM63XX_PHY
---help---
Currently supports the 6348 and 6358 PHYs.
+config BCM7XXX_PHY
+ tristate "Drivers for Broadcom 7xxx SOCs internal PHYs"
+ ---help---
+ Currently supports the BCM7366, BCM7439, BCM7445, and
+ 40nm and 65nm generation of BCM7xxx Set Top Box SoCs.
+
config BCM87XX_PHY
tristate "Driver for Broadcom BCM8706 and BCM8727 PHYs"
help
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 9013dfa12aa3..07d24024863e 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_SMSC_PHY) += smsc.o
obj-$(CONFIG_VITESSE_PHY) += vitesse.o
obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o
+obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o
obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o
obj-$(CONFIG_ICPLUS_PHY) += icplus.o
obj-$(CONFIG_REALTEK_PHY) += realtek.o
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index bc71947b1ec3..643464d5a727 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -27,6 +27,9 @@
#define AT803X_MMD_ACCESS_CONTROL 0x0D
#define AT803X_MMD_ACCESS_CONTROL_DATA 0x0E
#define AT803X_FUNC_DATA 0x4003
+#define AT803X_INER 0x0012
+#define AT803X_INER_INIT 0xec00
+#define AT803X_INSR 0x0013
#define AT803X_DEBUG_ADDR 0x1D
#define AT803X_DEBUG_DATA 0x1E
#define AT803X_DEBUG_SYSTEM_MODE_CTRL 0x05
@@ -191,6 +194,31 @@ static int at803x_config_init(struct phy_device *phydev)
return 0;
}
+static int at803x_ack_interrupt(struct phy_device *phydev)
+{
+ int err;
+
+ err = phy_read(phydev, AT803X_INSR);
+
+ return (err < 0) ? err : 0;
+}
+
+static int at803x_config_intr(struct phy_device *phydev)
+{
+ int err;
+ int value;
+
+ value = phy_read(phydev, AT803X_INER);
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ err = phy_write(phydev, AT803X_INER,
+ value | AT803X_INER_INIT);
+ else
+ err = phy_write(phydev, AT803X_INER, 0);
+
+ return err;
+}
+
static struct phy_driver at803x_driver[] = {
{
/* ATHEROS 8035 */
@@ -240,6 +268,8 @@ static struct phy_driver at803x_driver[] = {
.flags = PHY_HAS_INTERRUPT,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
+ .ack_interrupt = &at803x_ack_interrupt,
+ .config_intr = &at803x_config_intr,
.driver = {
.owner = THIS_MODULE,
},
diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c
new file mode 100644
index 000000000000..526b94cea569
--- /dev/null
+++ b/drivers/net/phy/bcm7xxx.c
@@ -0,0 +1,359 @@
+/*
+ * Broadcom BCM7xxx internal transceivers support.
+ *
+ * Copyright (C) 2014, 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 the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/phy.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/brcmphy.h>
+
+/* Broadcom BCM7xxx internal PHY registers */
+#define MII_BCM7XXX_CHANNEL_WIDTH 0x2000
+
+/* 40nm only register definitions */
+#define MII_BCM7XXX_100TX_AUX_CTL 0x10
+#define MII_BCM7XXX_100TX_FALSE_CAR 0x13
+#define MII_BCM7XXX_100TX_DISC 0x14
+#define MII_BCM7XXX_AUX_MODE 0x1d
+#define MII_BCM7XX_64CLK_MDIO BIT(12)
+#define MII_BCM7XXX_CORE_BASE1E 0x1e
+#define MII_BCM7XXX_TEST 0x1f
+#define MII_BCM7XXX_SHD_MODE_2 BIT(2)
+
+/* 28nm only register definitions */
+#define MISC_ADDR(base, channel) base, channel
+
+#define DSP_TAP10 MISC_ADDR(0x0a, 0)
+#define PLL_PLLCTRL_1 MISC_ADDR(0x32, 1)
+#define PLL_PLLCTRL_2 MISC_ADDR(0x32, 2)
+#define PLL_PLLCTRL_4 MISC_ADDR(0x33, 0)
+
+#define AFE_RXCONFIG_0 MISC_ADDR(0x38, 0)
+#define AFE_RXCONFIG_1 MISC_ADDR(0x38, 1)
+#define AFE_RX_LP_COUNTER MISC_ADDR(0x38, 3)
+#define AFE_TX_CONFIG MISC_ADDR(0x39, 0)
+#define AFE_HPF_TRIM_OTHERS MISC_ADDR(0x3a, 0)
+
+#define CORE_EXPB0 0xb0
+
+static int bcm7445_config_init(struct phy_device *phydev)
+{
+ int ret;
+ const struct bcm7445_regs {
+ int reg;
+ u16 value;
+ } bcm7445_regs_cfg[] = {
+ /* increases ADC latency by 24ns */
+ { MII_BCM54XX_EXP_SEL, 0x0038 },
+ { MII_BCM54XX_EXP_DATA, 0xAB95 },
+ /* increases internal 1V LDO voltage by 5% */
+ { MII_BCM54XX_EXP_SEL, 0x2038 },
+ { MII_BCM54XX_EXP_DATA, 0xBB22 },
+ /* reduce RX low pass filter corner frequency */
+ { MII_BCM54XX_EXP_SEL, 0x6038 },
+ { MII_BCM54XX_EXP_DATA, 0xFFC5 },
+ /* reduce RX high pass filter corner frequency */
+ { MII_BCM54XX_EXP_SEL, 0x003a },
+ { MII_BCM54XX_EXP_DATA, 0x2002 },
+ };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(bcm7445_regs_cfg); i++) {
+ ret = phy_write(phydev,
+ bcm7445_regs_cfg[i].reg,
+ bcm7445_regs_cfg[i].value);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void phy_write_exp(struct phy_device *phydev,
+ u16 reg, u16 value)
+{
+ phy_write(phydev, MII_BCM54XX_EXP_SEL, MII_BCM54XX_EXP_SEL_ER | reg);
+ phy_write(phydev, MII_BCM54XX_EXP_DATA, value);
+}
+
+static void phy_write_misc(struct phy_device *phydev,
+ u16 reg, u16 chl, u16 value)
+{
+ int tmp;
+
+ phy_write(phydev, MII_BCM54XX_AUX_CTL, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
+
+ tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL);
+ tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA;
+ phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp);
+
+ tmp = (chl * MII_BCM7XXX_CHANNEL_WIDTH) | reg;
+ phy_write(phydev, MII_BCM54XX_EXP_SEL, tmp);
+
+ phy_write(phydev, MII_BCM54XX_EXP_DATA, value);
+}
+
+static int bcm7xxx_28nm_afe_config_init(struct phy_device *phydev)
+{
+ /* Increase VCO range to prevent unlocking problem of PLL at low
+ * temp
+ */
+ phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048);
+
+ /* Change Ki to 011 */
+ phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b);
+
+ /* Disable loading of TVCO buffer to bandgap, set bandgap trim
+ * to 111
+ */
+ phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20);
+
+ /* Adjust bias current trim by -3 */
+ phy_write_misc(phydev, DSP_TAP10, 0x690b);
+
+ /* Switch to CORE_BASE1E */
+ phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0xd);
+
+ /* Reset R_CAL/RC_CAL Engine */
+ phy_write_exp(phydev, CORE_EXPB0, 0x0010);
+
+ /* Disable Reset R_CAL/RC_CAL Engine */
+ phy_write_exp(phydev, CORE_EXPB0, 0x0000);
+
+ /* write AFE_RXCONFIG_0 */
+ phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19);
+
+ /* write AFE_RXCONFIG_1 */
+ phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f);
+
+ /* write AFE_RX_LP_COUNTER */
+ phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
+
+ /* write AFE_HPF_TRIM_OTHERS */
+ phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b);
+
+ /* write AFTE_TX_CONFIG */
+ phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800);
+
+ return 0;
+}
+
+static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = bcm7445_config_init(phydev);
+ if (ret)
+ return ret;
+
+ return bcm7xxx_28nm_afe_config_init(phydev);
+}
+
+static int phy_set_clr_bits(struct phy_device *dev, int location,
+ int set_mask, int clr_mask)
+{
+ int v, ret;
+
+ v = phy_read(dev, location);
+ if (v < 0)
+ return v;
+
+ v &= ~clr_mask;
+ v |= set_mask;
+
+ ret = phy_write(dev, location, v);
+ if (ret < 0)
+ return ret;
+
+ return v;
+}
+
+static int bcm7xxx_config_init(struct phy_device *phydev)
+{
+ int ret;
+
+ /* Enable 64 clock MDIO */
+ phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XX_64CLK_MDIO);
+ phy_read(phydev, MII_BCM7XXX_AUX_MODE);
+
+ /* Workaround only required for 100Mbits/sec */
+ if (!(phydev->dev_flags & PHY_BRCM_100MBPS_WAR))
+ return 0;
+
+ /* set shadow mode 2 */
+ ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
+ MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2);
+ if (ret < 0)
+ return ret;
+
+ /* set iddq_clkbias */
+ phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0F00);
+ udelay(10);
+
+ /* reset iddq_clkbias */
+ phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0C00);
+
+ phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555);
+
+ /* reset shadow mode 2 */
+ ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, MII_BCM7XXX_SHD_MODE_2, 0);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/* Workaround for putting the PHY in IDDQ mode, required
+ * for all BCM7XXX PHYs
+ */
+static int bcm7xxx_suspend(struct phy_device *phydev)
+{
+ int ret;
+ const struct bcm7xxx_regs {
+ int reg;
+ u16 value;
+ } bcm7xxx_suspend_cfg[] = {
+ { MII_BCM7XXX_TEST, 0x008b },
+ { MII_BCM7XXX_100TX_AUX_CTL, 0x01c0 },
+ { MII_BCM7XXX_100TX_DISC, 0x7000 },
+ { MII_BCM7XXX_TEST, 0x000f },
+ { MII_BCM7XXX_100TX_AUX_CTL, 0x20d0 },
+ { MII_BCM7XXX_TEST, 0x000b },
+ };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(bcm7xxx_suspend_cfg); i++) {
+ ret = phy_write(phydev,
+ bcm7xxx_suspend_cfg[i].reg,
+ bcm7xxx_suspend_cfg[i].value);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int bcm7xxx_dummy_config_init(struct phy_device *phydev)
+{
+ return 0;
+}
+
+static struct phy_driver bcm7xxx_driver[] = {
+{
+ .phy_id = PHY_ID_BCM7366,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Broadcom BCM7366",
+ .features = PHY_GBIT_FEATURES |
+ SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+ .flags = PHY_IS_INTERNAL,
+ .config_init = bcm7xxx_28nm_afe_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .suspend = bcm7xxx_suspend,
+ .resume = bcm7xxx_28nm_afe_config_init,
+ .driver = { .owner = THIS_MODULE },
+}, {
+ .phy_id = PHY_ID_BCM7439,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Broadcom BCM7439",
+ .features = PHY_GBIT_FEATURES |
+ SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+ .flags = PHY_IS_INTERNAL,
+ .config_init = bcm7xxx_28nm_afe_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .suspend = bcm7xxx_suspend,
+ .resume = bcm7xxx_28nm_afe_config_init,
+ .driver = { .owner = THIS_MODULE },
+}, {
+ .phy_id = PHY_ID_BCM7445,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Broadcom BCM7445",
+ .features = PHY_GBIT_FEATURES |
+ SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+ .flags = PHY_IS_INTERNAL,
+ .config_init = bcm7xxx_28nm_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .suspend = bcm7xxx_suspend,
+ .resume = bcm7xxx_28nm_config_init,
+ .driver = { .owner = THIS_MODULE },
+}, {
+ .name = "Broadcom BCM7XXX 28nm",
+ .phy_id = PHY_ID_BCM7XXX_28,
+ .phy_id_mask = PHY_BCM_OUI_MASK,
+ .features = PHY_GBIT_FEATURES |
+ SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+ .flags = PHY_IS_INTERNAL,
+ .config_init = bcm7xxx_28nm_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .suspend = bcm7xxx_suspend,
+ .resume = bcm7xxx_28nm_config_init,
+ .driver = { .owner = THIS_MODULE },
+}, {
+ .phy_id = PHY_BCM_OUI_4,
+ .phy_id_mask = 0xffff0000,
+ .name = "Broadcom BCM7XXX 40nm",
+ .features = PHY_GBIT_FEATURES |
+ SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+ .flags = PHY_IS_INTERNAL,
+ .config_init = bcm7xxx_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .suspend = bcm7xxx_suspend,
+ .resume = bcm7xxx_config_init,
+ .driver = { .owner = THIS_MODULE },
+}, {
+ .phy_id = PHY_BCM_OUI_5,
+ .phy_id_mask = 0xffffff00,
+ .name = "Broadcom BCM7XXX 65nm",
+ .features = PHY_BASIC_FEATURES |
+ SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+ .flags = PHY_IS_INTERNAL,
+ .config_init = bcm7xxx_dummy_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .suspend = bcm7xxx_suspend,
+ .resume = bcm7xxx_config_init,
+ .driver = { .owner = THIS_MODULE },
+} };
+
+static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
+ { PHY_ID_BCM7366, 0xfffffff0, },
+ { PHY_ID_BCM7439, 0xfffffff0, },
+ { PHY_ID_BCM7445, 0xfffffff0, },
+ { PHY_ID_BCM7XXX_28, 0xfffffc00 },
+ { PHY_BCM_OUI_4, 0xffff0000 },
+ { PHY_BCM_OUI_5, 0xffffff00 },
+ { }
+};
+
+static int __init bcm7xxx_phy_init(void)
+{
+ return phy_drivers_register(bcm7xxx_driver,
+ ARRAY_SIZE(bcm7xxx_driver));
+}
+
+static void __exit bcm7xxx_phy_exit(void)
+{
+ phy_drivers_unregister(bcm7xxx_driver,
+ ARRAY_SIZE(bcm7xxx_driver));
+}
+
+module_init(bcm7xxx_phy_init);
+module_exit(bcm7xxx_phy_exit);
+
+MODULE_DEVICE_TABLE(mdio, bcm7xxx_tbl);
+
+MODULE_DESCRIPTION("Broadcom BCM7xxx internal PHY driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Broadcom Corporation");
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index f8c90ea75108..34088d60da74 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -25,58 +25,6 @@
#define BRCM_PHY_REV(phydev) \
((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask))
-
-#define MII_BCM54XX_ECR 0x10 /* BCM54xx extended control register */
-#define MII_BCM54XX_ECR_IM 0x1000 /* Interrupt mask */
-#define MII_BCM54XX_ECR_IF 0x0800 /* Interrupt force */
-
-#define MII_BCM54XX_ESR 0x11 /* BCM54xx extended status register */
-#define MII_BCM54XX_ESR_IS 0x1000 /* Interrupt status */
-
-#define MII_BCM54XX_EXP_DATA 0x15 /* Expansion register data */
-#define MII_BCM54XX_EXP_SEL 0x17 /* Expansion register select */
-#define MII_BCM54XX_EXP_SEL_SSD 0x0e00 /* Secondary SerDes select */
-#define MII_BCM54XX_EXP_SEL_ER 0x0f00 /* Expansion register select */
-
-#define MII_BCM54XX_AUX_CTL 0x18 /* Auxiliary control register */
-#define MII_BCM54XX_ISR 0x1a /* BCM54xx interrupt status register */
-#define MII_BCM54XX_IMR 0x1b /* BCM54xx interrupt mask register */
-#define MII_BCM54XX_INT_CRCERR 0x0001 /* CRC error */
-#define MII_BCM54XX_INT_LINK 0x0002 /* Link status changed */
-#define MII_BCM54XX_INT_SPEED 0x0004 /* Link speed change */
-#define MII_BCM54XX_INT_DUPLEX 0x0008 /* Duplex mode changed */
-#define MII_BCM54XX_INT_LRS 0x0010 /* Local receiver status changed */
-#define MII_BCM54XX_INT_RRS 0x0020 /* Remote receiver status changed */
-#define MII_BCM54XX_INT_SSERR 0x0040 /* Scrambler synchronization error */
-#define MII_BCM54XX_INT_UHCD 0x0080 /* Unsupported HCD negotiated */
-#define MII_BCM54XX_INT_NHCD 0x0100 /* No HCD */
-#define MII_BCM54XX_INT_NHCDL 0x0200 /* No HCD link */
-#define MII_BCM54XX_INT_ANPR 0x0400 /* Auto-negotiation page received */
-#define MII_BCM54XX_INT_LC 0x0800 /* All counters below 128 */
-#define MII_BCM54XX_INT_HC 0x1000 /* Counter above 32768 */
-#define MII_BCM54XX_INT_MDIX 0x2000 /* MDIX status change */
-#define MII_BCM54XX_INT_PSERR 0x4000 /* Pair swap error */
-
-#define MII_BCM54XX_SHD 0x1c /* 0x1c shadow registers */
-#define MII_BCM54XX_SHD_WRITE 0x8000
-#define MII_BCM54XX_SHD_VAL(x) ((x & 0x1f) << 10)
-#define MII_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0)
-
-/*
- * AUXILIARY CONTROL SHADOW ACCESS REGISTERS. (PHY REG 0x18)
- */
-#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL 0x0000
-#define MII_BCM54XX_AUXCTL_ACTL_TX_6DB 0x0400
-#define MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA 0x0800
-
-#define MII_BCM54XX_AUXCTL_MISC_WREN 0x8000
-#define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX 0x0200
-#define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC 0x7000
-#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x0007
-
-#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL 0x0000
-
-
/*
* Broadcom LED source encodings. These are used in BCM5461, BCM5481,
* BCM5482, and possibly some others.
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
index 547725fa8671..6a999e6814a0 100644
--- a/drivers/net/phy/dp83640.c
+++ b/drivers/net/phy/dp83640.c
@@ -27,6 +27,7 @@
#include <linux/module.h>
#include <linux/net_tstamp.h>
#include <linux/netdevice.h>
+#include <linux/if_vlan.h>
#include <linux/phy.h>
#include <linux/ptp_classify.h>
#include <linux/ptp_clock_kernel.h>
@@ -47,6 +48,7 @@
#define CAL_EVENT 7
#define CAL_TRIGGER 7
#define PER_TRIGGER 6
+#define DP83640_N_PINS 12
#define MII_DP83640_MICR 0x11
#define MII_DP83640_MISR 0x12
@@ -173,6 +175,37 @@ MODULE_PARM_DESC(chosen_phy, \
MODULE_PARM_DESC(gpio_tab, \
"Which GPIO line to use for which purpose: cal,perout,extts1,...,extts6");
+static void dp83640_gpio_defaults(struct ptp_pin_desc *pd)
+{
+ int i, index;
+
+ for (i = 0; i < DP83640_N_PINS; i++) {
+ snprintf(pd[i].name, sizeof(pd[i].name), "GPIO%d", 1 + i);
+ pd[i].index = i;
+ }
+
+ for (i = 0; i < GPIO_TABLE_SIZE; i++) {
+ if (gpio_tab[i] < 1 || gpio_tab[i] > DP83640_N_PINS) {
+ pr_err("gpio_tab[%d]=%hu out of range", i, gpio_tab[i]);
+ return;
+ }
+ }
+
+ index = gpio_tab[CALIBRATE_GPIO] - 1;
+ pd[index].func = PTP_PF_PHYSYNC;
+ pd[index].chan = 0;
+
+ index = gpio_tab[PEROUT_GPIO] - 1;
+ pd[index].func = PTP_PF_PEROUT;
+ pd[index].chan = 0;
+
+ for (i = EXTTS0_GPIO; i < GPIO_TABLE_SIZE; i++) {
+ index = gpio_tab[i] - 1;
+ pd[index].func = PTP_PF_EXTTS;
+ pd[index].chan = i - EXTTS0_GPIO;
+ }
+}
+
/* a list of clocks and a mutex to protect it */
static LIST_HEAD(phyter_clocks);
static DEFINE_MUTEX(phyter_clocks_lock);
@@ -266,15 +299,22 @@ static u64 phy2txts(struct phy_txts *p)
return ns;
}
-static void periodic_output(struct dp83640_clock *clock,
- struct ptp_clock_request *clkreq, bool on)
+static int periodic_output(struct dp83640_clock *clock,
+ struct ptp_clock_request *clkreq, bool on)
{
struct dp83640_private *dp83640 = clock->chosen;
struct phy_device *phydev = dp83640->phydev;
- u32 sec, nsec, period;
+ u32 sec, nsec, pwidth;
u16 gpio, ptp_trig, trigger, val;
- gpio = on ? gpio_tab[PEROUT_GPIO] : 0;
+ if (on) {
+ gpio = 1 + ptp_find_pin(clock->ptp_clock, PTP_PF_PEROUT, 0);
+ if (gpio < 1)
+ return -EINVAL;
+ } else {
+ gpio = 0;
+ }
+
trigger = PER_TRIGGER;
ptp_trig = TRIG_WR |
@@ -291,13 +331,14 @@ static void periodic_output(struct dp83640_clock *clock,
ext_write(0, phydev, PAGE5, PTP_TRIG, ptp_trig);
ext_write(0, phydev, PAGE4, PTP_CTL, val);
mutex_unlock(&clock->extreg_lock);
- return;
+ return 0;
}
sec = clkreq->perout.start.sec;
nsec = clkreq->perout.start.nsec;
- period = clkreq->perout.period.sec * 1000000000UL;
- period += clkreq->perout.period.nsec;
+ pwidth = clkreq->perout.period.sec * 1000000000UL;
+ pwidth += clkreq->perout.period.nsec;
+ pwidth /= 2;
mutex_lock(&clock->extreg_lock);
@@ -310,8 +351,8 @@ static void periodic_output(struct dp83640_clock *clock,
ext_write(0, phydev, PAGE4, PTP_TDR, nsec >> 16); /* ns[31:16] */
ext_write(0, phydev, PAGE4, PTP_TDR, sec & 0xffff); /* sec[15:0] */
ext_write(0, phydev, PAGE4, PTP_TDR, sec >> 16); /* sec[31:16] */
- ext_write(0, phydev, PAGE4, PTP_TDR, period & 0xffff); /* ns[15:0] */
- ext_write(0, phydev, PAGE4, PTP_TDR, period >> 16); /* ns[31:16] */
+ ext_write(0, phydev, PAGE4, PTP_TDR, pwidth & 0xffff); /* ns[15:0] */
+ ext_write(0, phydev, PAGE4, PTP_TDR, pwidth >> 16); /* ns[31:16] */
/*enable trigger*/
val &= ~TRIG_LOAD;
@@ -319,6 +360,7 @@ static void periodic_output(struct dp83640_clock *clock,
ext_write(0, phydev, PAGE4, PTP_CTL, val);
mutex_unlock(&clock->extreg_lock);
+ return 0;
}
/* ptp clock methods */
@@ -424,20 +466,26 @@ static int ptp_dp83640_enable(struct ptp_clock_info *ptp,
struct dp83640_clock *clock =
container_of(ptp, struct dp83640_clock, caps);
struct phy_device *phydev = clock->chosen->phydev;
- int index;
+ unsigned int index;
u16 evnt, event_num, gpio_num;
switch (rq->type) {
case PTP_CLK_REQ_EXTTS:
index = rq->extts.index;
- if (index < 0 || index >= N_EXT_TS)
+ if (index >= N_EXT_TS)
return -EINVAL;
event_num = EXT_EVENT + index;
evnt = EVNT_WR | (event_num & EVNT_SEL_MASK) << EVNT_SEL_SHIFT;
if (on) {
- gpio_num = gpio_tab[EXTTS0_GPIO + index];
+ gpio_num = 1 + ptp_find_pin(clock->ptp_clock,
+ PTP_PF_EXTTS, index);
+ if (gpio_num < 1)
+ return -EINVAL;
evnt |= (gpio_num & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT;
- evnt |= EVNT_RISE;
+ if (rq->extts.flags & PTP_FALLING_EDGE)
+ evnt |= EVNT_FALL;
+ else
+ evnt |= EVNT_RISE;
}
ext_write(0, phydev, PAGE5, PTP_EVNT, evnt);
return 0;
@@ -445,8 +493,7 @@ static int ptp_dp83640_enable(struct ptp_clock_info *ptp,
case PTP_CLK_REQ_PEROUT:
if (rq->perout.index != 0)
return -EINVAL;
- periodic_output(clock, rq, on);
- return 0;
+ return periodic_output(clock, rq, on);
default:
break;
@@ -455,6 +502,12 @@ static int ptp_dp83640_enable(struct ptp_clock_info *ptp,
return -EOPNOTSUPP;
}
+static int ptp_dp83640_verify(struct ptp_clock_info *ptp, unsigned int pin,
+ enum ptp_pin_function func, unsigned int chan)
+{
+ return 0;
+}
+
static u8 status_frame_dst[6] = { 0x01, 0x1B, 0x19, 0x00, 0x00, 0x00 };
static u8 status_frame_src[6] = { 0x08, 0x00, 0x17, 0x0B, 0x6B, 0x0F };
@@ -872,6 +925,7 @@ static void dp83640_free_clocks(void)
mutex_destroy(&clock->extreg_lock);
mutex_destroy(&clock->clock_lock);
put_device(&clock->bus->dev);
+ kfree(clock->caps.pin_config);
kfree(clock);
}
@@ -891,12 +945,18 @@ static void dp83640_clock_init(struct dp83640_clock *clock, struct mii_bus *bus)
clock->caps.n_alarm = 0;
clock->caps.n_ext_ts = N_EXT_TS;
clock->caps.n_per_out = 1;
+ clock->caps.n_pins = DP83640_N_PINS;
clock->caps.pps = 0;
clock->caps.adjfreq = ptp_dp83640_adjfreq;
clock->caps.adjtime = ptp_dp83640_adjtime;
clock->caps.gettime = ptp_dp83640_gettime;
clock->caps.settime = ptp_dp83640_settime;
clock->caps.enable = ptp_dp83640_enable;
+ clock->caps.verify = ptp_dp83640_verify;
+ /*
+ * Convert the module param defaults into a dynamic pin configuration.
+ */
+ dp83640_gpio_defaults(clock->caps.pin_config);
/*
* Get a reference to this bus instance.
*/
@@ -947,6 +1007,13 @@ static struct dp83640_clock *dp83640_clock_get_bus(struct mii_bus *bus)
if (!clock)
goto out;
+ clock->caps.pin_config = kzalloc(sizeof(struct ptp_pin_desc) *
+ DP83640_N_PINS, GFP_KERNEL);
+ if (!clock->caps.pin_config) {
+ kfree(clock);
+ clock = NULL;
+ goto out;
+ }
dp83640_clock_init(clock, bus);
list_add_tail(&phyter_clocks, &clock->list);
out:
@@ -1003,11 +1070,6 @@ static int dp83640_probe(struct phy_device *phydev)
} else
list_add_tail(&dp83640->list, &clock->phylist);
- if (clock->chosen && !list_empty(&clock->phylist))
- recalibrate(clock);
- else
- enable_broadcast(dp83640->phydev, clock->page, 1);
-
dp83640_clock_put(clock);
return 0;
@@ -1058,6 +1120,21 @@ static void dp83640_remove(struct phy_device *phydev)
kfree(dp83640);
}
+static int dp83640_config_init(struct phy_device *phydev)
+{
+ struct dp83640_private *dp83640 = phydev->priv;
+ struct dp83640_clock *clock = dp83640->clock;
+
+ if (clock->chosen && !list_empty(&clock->phylist))
+ recalibrate(clock);
+ else
+ enable_broadcast(phydev, clock->page, 1);
+
+ enable_status_frames(phydev, true);
+ ext_write(0, phydev, PAGE4, PTP_CTL, PTP_ENABLE);
+ return 0;
+}
+
static int dp83640_ack_interrupt(struct phy_device *phydev)
{
int err = phy_read(phydev, MII_DP83640_MISR);
@@ -1195,11 +1272,6 @@ static int dp83640_hwtstamp(struct phy_device *phydev, struct ifreq *ifr)
mutex_lock(&dp83640->clock->extreg_lock);
- if (dp83640->hwts_tx_en || dp83640->hwts_rx_en) {
- enable_status_frames(phydev, true);
- ext_write(0, phydev, PAGE4, PTP_CTL, PTP_ENABLE);
- }
-
ext_write(0, phydev, PAGE5, PTP_TXCFG0, txcfg0);
ext_write(0, phydev, PAGE5, PTP_RXCFG0, rxcfg0);
@@ -1281,6 +1353,7 @@ static void dp83640_txtstamp(struct phy_device *phydev,
}
/* fall through */
case HWTSTAMP_TX_ON:
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
skb_queue_tail(&dp83640->tx_queue, skb);
schedule_work(&dp83640->ts_work);
break;
@@ -1330,6 +1403,7 @@ static struct phy_driver dp83640_driver = {
.flags = PHY_HAS_INTERRUPT,
.probe = dp83640_probe,
.remove = dp83640_remove,
+ .config_init = dp83640_config_init,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.ack_interrupt = dp83640_ack_interrupt,
@@ -1353,7 +1427,7 @@ static void __exit dp83640_exit(void)
}
MODULE_DESCRIPTION("National Semiconductor DP83640 PHY driver");
-MODULE_AUTHOR("Richard Cochran <richardcochran@gmail.at>");
+MODULE_AUTHOR("Richard Cochran <richardcochran@gmail.com>");
MODULE_LICENSE("GPL");
module_init(dp83640_init);
diff --git a/drivers/net/phy/mdio-sun4i.c b/drivers/net/phy/mdio-sun4i.c
index bb88bc7d81fb..15bc7f9ea224 100644
--- a/drivers/net/phy/mdio-sun4i.c
+++ b/drivers/net/phy/mdio-sun4i.c
@@ -90,11 +90,6 @@ static int sun4i_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
return 0;
}
-static int sun4i_mdio_reset(struct mii_bus *bus)
-{
- return 0;
-}
-
static int sun4i_mdio_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -110,7 +105,6 @@ static int sun4i_mdio_probe(struct platform_device *pdev)
bus->name = "sun4i_mii_bus";
bus->read = &sun4i_mdio_read;
bus->write = &sun4i_mdio_write;
- bus->reset = &sun4i_mdio_reset;
snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
bus->parent = &pdev->dev;
@@ -170,6 +164,9 @@ static int sun4i_mdio_remove(struct platform_device *pdev)
}
static const struct of_device_id sun4i_mdio_dt_ids[] = {
+ { .compatible = "allwinner,sun4i-a10-mdio" },
+
+ /* Deprecated */
{ .compatible = "allwinner,sun4i-mdio" },
{ }
};
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 71e49000fbf3..76f54b32a120 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -432,8 +432,28 @@ phy_id_show(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR_RO(phy_id);
+static ssize_t
+phy_interface_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+
+ return sprintf(buf, "%s\n", phy_modes(phydev->interface));
+}
+static DEVICE_ATTR_RO(phy_interface);
+
+static ssize_t
+phy_has_fixups_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+
+ return sprintf(buf, "%d\n", phydev->has_fixups);
+}
+static DEVICE_ATTR_RO(phy_has_fixups);
+
static struct attribute *mdio_dev_attrs[] = {
&dev_attr_phy_id.attr,
+ &dev_attr_phy_interface.attr,
+ &dev_attr_phy_has_fixups.attr,
NULL,
};
ATTRIBUTE_GROUPS(mdio_dev);
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 5a8993b0cafc..5ad971a55c5d 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -148,15 +148,52 @@ static int ks8737_config_intr(struct phy_device *phydev)
return rc < 0 ? rc : 0;
}
+static int kszphy_setup_led(struct phy_device *phydev,
+ unsigned int reg, unsigned int shift)
+{
+
+ struct device *dev = &phydev->dev;
+ struct device_node *of_node = dev->of_node;
+ int rc, temp;
+ u32 val;
+
+ if (!of_node && dev->parent->of_node)
+ of_node = dev->parent->of_node;
+
+ if (of_property_read_u32(of_node, "micrel,led-mode", &val))
+ return 0;
+
+ temp = phy_read(phydev, reg);
+ if (temp < 0)
+ return temp;
+
+ temp &= ~(3 << shift);
+ temp |= val << shift;
+ rc = phy_write(phydev, reg, temp);
+
+ return rc < 0 ? rc : 0;
+}
+
static int kszphy_config_init(struct phy_device *phydev)
{
return 0;
}
+static int kszphy_config_init_led8041(struct phy_device *phydev)
+{
+ /* single led control, register 0x1e bits 15..14 */
+ return kszphy_setup_led(phydev, 0x1e, 14);
+}
+
static int ksz8021_config_init(struct phy_device *phydev)
{
- int rc;
const u16 val = KSZPHY_OMSO_B_CAST_OFF | KSZPHY_OMSO_RMII_OVERRIDE;
+ int rc;
+
+ rc = kszphy_setup_led(phydev, 0x1f, 4);
+ if (rc)
+ dev_err(&phydev->dev, "failed to set led mode\n");
+
phy_write(phydev, MII_KSZPHY_OMSO, val);
rc = ksz_config_flags(phydev);
return rc < 0 ? rc : 0;
@@ -166,6 +203,10 @@ static int ks8051_config_init(struct phy_device *phydev)
{
int rc;
+ rc = kszphy_setup_led(phydev, 0x1f, 4);
+ if (rc)
+ dev_err(&phydev->dev, "failed to set led mode\n");
+
rc = ksz_config_flags(phydev);
return rc < 0 ? rc : 0;
}
@@ -327,7 +368,7 @@ static struct phy_driver ksphy_driver[] = {
.features = (PHY_BASIC_FEATURES | SUPPORTED_Pause
| SUPPORTED_Asym_Pause),
.flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
- .config_init = kszphy_config_init,
+ .config_init = kszphy_config_init_led8041,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.ack_interrupt = kszphy_ack_interrupt,
@@ -342,7 +383,7 @@ static struct phy_driver ksphy_driver[] = {
.features = PHY_BASIC_FEATURES |
SUPPORTED_Pause | SUPPORTED_Asym_Pause,
.flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
- .config_init = kszphy_config_init,
+ .config_init = kszphy_config_init_led8041,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.ack_interrupt = kszphy_ack_interrupt,
@@ -371,7 +412,7 @@ static struct phy_driver ksphy_driver[] = {
.phy_id_mask = 0x00ffffff,
.features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
.flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
- .config_init = kszphy_config_init,
+ .config_init = kszphy_config_init_led8041,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.ack_interrupt = kszphy_ack_interrupt,
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 19c9eca0ef26..1d788f19135b 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -38,6 +38,26 @@
#include <asm/irq.h>
+static const char *phy_speed_to_str(int speed)
+{
+ switch (speed) {
+ case SPEED_10:
+ return "10Mbps";
+ case SPEED_100:
+ return "100Mbps";
+ case SPEED_1000:
+ return "1Gbps";
+ case SPEED_2500:
+ return "2.5Gbps";
+ case SPEED_10000:
+ return "10Gbps";
+ case SPEED_UNKNOWN:
+ return "Unknown";
+ default:
+ return "Unsupported (update phy.c)";
+ }
+}
+
/**
* phy_print_status - Convenience function to print out the current phy status
* @phydev: the phy_device struct
@@ -45,12 +65,13 @@
void phy_print_status(struct phy_device *phydev)
{
if (phydev->link) {
- pr_info("%s - Link is Up - %d/%s\n",
- dev_name(&phydev->dev),
- phydev->speed,
- DUPLEX_FULL == phydev->duplex ? "Full" : "Half");
+ netdev_info(phydev->attached_dev,
+ "Link is Up - %s/%s - flow control %s\n",
+ phy_speed_to_str(phydev->speed),
+ DUPLEX_FULL == phydev->duplex ? "Full" : "Half",
+ phydev->pause ? "rx/tx" : "off");
} else {
- pr_info("%s - Link is Down\n", dev_name(&phydev->dev));
+ netdev_info(phydev->attached_dev, "Link is Down\n");
}
}
EXPORT_SYMBOL(phy_print_status);
@@ -62,7 +83,7 @@ EXPORT_SYMBOL(phy_print_status);
* If the @phydev driver has an ack_interrupt function, call it to
* ack and clear the phy device's interrupt.
*
- * Returns 0 on success on < 0 on error.
+ * Returns 0 on success or < 0 on error.
*/
static int phy_clear_interrupt(struct phy_device *phydev)
{
@@ -77,7 +98,7 @@ static int phy_clear_interrupt(struct phy_device *phydev)
* @phydev: the phy_device struct
* @interrupts: interrupt flags to configure for this @phydev
*
- * Returns 0 on success on < 0 on error.
+ * Returns 0 on success or < 0 on error.
*/
static int phy_config_interrupt(struct phy_device *phydev, u32 interrupts)
{
@@ -93,15 +114,16 @@ static int phy_config_interrupt(struct phy_device *phydev, u32 interrupts)
* phy_aneg_done - return auto-negotiation status
* @phydev: target phy_device struct
*
- * Description: Reads the status register and returns 0 either if
- * auto-negotiation is incomplete, or if there was an error.
- * Returns BMSR_ANEGCOMPLETE if auto-negotiation is done.
+ * Description: Return the auto-negotiation status from this @phydev
+ * Returns > 0 on success or < 0 on error. 0 means that auto-negotiation
+ * is still pending.
*/
static inline int phy_aneg_done(struct phy_device *phydev)
{
- int retval = phy_read(phydev, MII_BMSR);
+ if (phydev->drv->aneg_done)
+ return phydev->drv->aneg_done(phydev);
- return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE);
+ return genphy_aneg_done(phydev);
}
/* A structure for mapping a particular speed and duplex
@@ -164,9 +186,9 @@ static const struct phy_setting settings[] = {
* of that setting. Returns the index of the last setting if
* none of the others match.
*/
-static inline int phy_find_setting(int speed, int duplex)
+static inline unsigned int phy_find_setting(int speed, int duplex)
{
- int idx = 0;
+ unsigned int idx = 0;
while (idx < ARRAY_SIZE(settings) &&
(settings[idx].speed != speed || settings[idx].duplex != duplex))
@@ -185,7 +207,7 @@ static inline int phy_find_setting(int speed, int duplex)
* the mask in features. Returns the index of the last setting
* if nothing else matches.
*/
-static inline int phy_find_valid(int idx, u32 features)
+static inline unsigned int phy_find_valid(unsigned int idx, u32 features)
{
while (idx < MAX_NUM_SETTINGS && !(settings[idx].setting & features))
idx++;
@@ -204,7 +226,7 @@ static inline int phy_find_valid(int idx, u32 features)
static void phy_sanitize_settings(struct phy_device *phydev)
{
u32 features = phydev->supported;
- int idx;
+ unsigned int idx;
/* Sanitize settings based on PHY capabilities */
if ((features & SUPPORTED_Autoneg) == 0)
@@ -283,7 +305,10 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
ethtool_cmd_speed_set(cmd, phydev->speed);
cmd->duplex = phydev->duplex;
- cmd->port = PORT_MII;
+ if (phydev->interface == PHY_INTERFACE_MODE_MOCA)
+ cmd->port = PORT_BNC;
+ else
+ cmd->port = PORT_MII;
cmd->phy_address = phydev->addr;
cmd->transceiver = phy_is_internal(phydev) ?
XCVR_INTERNAL : XCVR_EXTERNAL;
@@ -954,7 +979,8 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
(phydev->interface == PHY_INTERFACE_MODE_RGMII))) {
int eee_lp, eee_cap, eee_adv;
u32 lp, cap, adv;
- int idx, status;
+ int status;
+ unsigned int idx;
/* Read phy status to properly get the right settings */
status = phy_read_status(phydev);
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 4b03e63639b7..0ce606624296 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -139,6 +139,7 @@ static int phy_scan_fixups(struct phy_device *phydev)
mutex_unlock(&phy_fixup_lock);
return err;
}
+ phydev->has_fixups = true;
}
}
mutex_unlock(&phy_fixup_lock);
@@ -534,16 +535,16 @@ static int phy_poll_reset(struct phy_device *phydev)
int phy_init_hw(struct phy_device *phydev)
{
- int ret;
+ int ret = 0;
if (!phydev->drv || !phydev->drv->config_init)
return 0;
- ret = phy_write(phydev, MII_BMCR, BMCR_RESET);
- if (ret < 0)
- return ret;
+ if (phydev->drv->soft_reset)
+ ret = phydev->drv->soft_reset(phydev);
+ else
+ ret = genphy_soft_reset(phydev);
- ret = phy_poll_reset(phydev);
if (ret < 0)
return ret;
@@ -683,10 +684,9 @@ EXPORT_SYMBOL(phy_detach);
int phy_suspend(struct phy_device *phydev)
{
struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver);
- struct ethtool_wolinfo wol;
+ struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
/* If the device has WOL enabled, we cannot suspend the PHY */
- wol.cmd = ETHTOOL_GWOL;
phy_ethtool_get_wol(phydev, &wol);
if (wol.wolopts)
return -EBUSY;
@@ -719,7 +719,7 @@ int phy_resume(struct phy_device *phydev)
static int genphy_config_advert(struct phy_device *phydev)
{
u32 advertise;
- int oldadv, adv;
+ int oldadv, adv, bmsr;
int err, changed = 0;
/* Only allow advertising what this PHY supports */
@@ -744,26 +744,36 @@ static int genphy_config_advert(struct phy_device *phydev)
changed = 1;
}
+ bmsr = phy_read(phydev, MII_BMSR);
+ if (bmsr < 0)
+ return bmsr;
+
+ /* Per 802.3-2008, Section 22.2.4.2.16 Extended status all
+ * 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a
+ * logical 1.
+ */
+ if (!(bmsr & BMSR_ESTATEN))
+ return changed;
+
/* Configure gigabit if it's supported */
+ adv = phy_read(phydev, MII_CTRL1000);
+ if (adv < 0)
+ return adv;
+
+ oldadv = adv;
+ adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+
if (phydev->supported & (SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full)) {
- adv = phy_read(phydev, MII_CTRL1000);
- if (adv < 0)
- return adv;
-
- oldadv = adv;
- adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
adv |= ethtool_adv_to_mii_ctrl1000_t(advertise);
-
- if (adv != oldadv) {
- err = phy_write(phydev, MII_CTRL1000, adv);
-
- if (err < 0)
- return err;
+ if (adv != oldadv)
changed = 1;
- }
}
+ err = phy_write(phydev, MII_CTRL1000, adv);
+ if (err < 0)
+ return err;
+
return changed;
}
@@ -855,6 +865,22 @@ int genphy_config_aneg(struct phy_device *phydev)
}
EXPORT_SYMBOL(genphy_config_aneg);
+/**
+ * genphy_aneg_done - return auto-negotiation status
+ * @phydev: target phy_device struct
+ *
+ * Description: Reads the status register and returns 0 either if
+ * auto-negotiation is incomplete, or if there was an error.
+ * Returns BMSR_ANEGCOMPLETE if auto-negotiation is done.
+ */
+int genphy_aneg_done(struct phy_device *phydev)
+{
+ int retval = phy_read(phydev, MII_BMSR);
+
+ return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE);
+}
+EXPORT_SYMBOL(genphy_aneg_done);
+
static int gen10g_config_aneg(struct phy_device *phydev)
{
return 0;
@@ -906,6 +932,8 @@ int genphy_read_status(struct phy_device *phydev)
int err;
int lpa;
int lpagb = 0;
+ int common_adv;
+ int common_adv_gb = 0;
/* Update the link, but return if there was an error */
err = genphy_update_link(phydev);
@@ -927,7 +955,7 @@ int genphy_read_status(struct phy_device *phydev)
phydev->lp_advertising =
mii_stat1000_to_ethtool_lpa_t(lpagb);
- lpagb &= adv << 2;
+ common_adv_gb = lpagb & adv << 2;
}
lpa = phy_read(phydev, MII_LPA);
@@ -940,25 +968,25 @@ int genphy_read_status(struct phy_device *phydev)
if (adv < 0)
return adv;
- lpa &= adv;
+ common_adv = lpa & adv;
phydev->speed = SPEED_10;
phydev->duplex = DUPLEX_HALF;
phydev->pause = 0;
phydev->asym_pause = 0;
- if (lpagb & (LPA_1000FULL | LPA_1000HALF)) {
+ if (common_adv_gb & (LPA_1000FULL | LPA_1000HALF)) {
phydev->speed = SPEED_1000;
- if (lpagb & LPA_1000FULL)
+ if (common_adv_gb & LPA_1000FULL)
phydev->duplex = DUPLEX_FULL;
- } else if (lpa & (LPA_100FULL | LPA_100HALF)) {
+ } else if (common_adv & (LPA_100FULL | LPA_100HALF)) {
phydev->speed = SPEED_100;
- if (lpa & LPA_100FULL)
+ if (common_adv & LPA_100FULL)
phydev->duplex = DUPLEX_FULL;
} else
- if (lpa & LPA_10FULL)
+ if (common_adv & LPA_10FULL)
phydev->duplex = DUPLEX_FULL;
if (phydev->duplex == DUPLEX_FULL) {
@@ -1018,6 +1046,27 @@ static int gen10g_read_status(struct phy_device *phydev)
return 0;
}
+/**
+ * genphy_soft_reset - software reset the PHY via BMCR_RESET bit
+ * @phydev: target phy_device struct
+ *
+ * Description: Perform a software PHY reset using the standard
+ * BMCR_RESET bit and poll for the reset bit to be cleared.
+ *
+ * Returns: 0 on success, < 0 on failure
+ */
+int genphy_soft_reset(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = phy_write(phydev, MII_BMCR, BMCR_RESET);
+ if (ret < 0)
+ return ret;
+
+ return phy_poll_reset(phydev);
+}
+EXPORT_SYMBOL(genphy_soft_reset);
+
static int genphy_config_init(struct phy_device *phydev)
{
int val;
@@ -1064,6 +1113,12 @@ static int genphy_config_init(struct phy_device *phydev)
return 0;
}
+static int gen10g_soft_reset(struct phy_device *phydev)
+{
+ /* Do nothing for now */
+ return 0;
+}
+
static int gen10g_config_init(struct phy_device *phydev)
{
/* Temporarily just say we support everything */
@@ -1238,9 +1293,11 @@ static struct phy_driver genphy_driver[] = {
.phy_id = 0xffffffff,
.phy_id_mask = 0xffffffff,
.name = "Generic PHY",
+ .soft_reset = genphy_soft_reset,
.config_init = genphy_config_init,
.features = 0,
.config_aneg = genphy_config_aneg,
+ .aneg_done = genphy_aneg_done,
.read_status = genphy_read_status,
.suspend = genphy_suspend,
.resume = genphy_resume,
@@ -1249,6 +1306,7 @@ static struct phy_driver genphy_driver[] = {
.phy_id = 0xffffffff,
.phy_id_mask = 0xffffffff,
.name = "Generic 10G PHY",
+ .soft_reset = gen10g_soft_reset,
.config_init = gen10g_config_init,
.features = 0,
.config_aneg = gen10g_config_aneg,
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 72ff14b811c6..e3923ebb693f 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -143,9 +143,8 @@ struct ppp {
struct sk_buff_head mrq; /* MP: receive reconstruction queue */
#endif /* CONFIG_PPP_MULTILINK */
#ifdef CONFIG_PPP_FILTER
- struct sock_filter *pass_filter; /* filter for packets to pass */
- struct sock_filter *active_filter;/* filter for pkts to reset idle */
- unsigned pass_len, active_len;
+ struct sk_filter *pass_filter; /* filter for packets to pass */
+ struct sk_filter *active_filter;/* filter for pkts to reset idle */
#endif /* CONFIG_PPP_FILTER */
struct net *ppp_net; /* the net we belong to */
struct ppp_link_stats stats64; /* 64 bit network stats */
@@ -755,28 +754,42 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case PPPIOCSPASS:
{
struct sock_filter *code;
+
err = get_filter(argp, &code);
if (err >= 0) {
+ struct sock_fprog fprog = {
+ .len = err,
+ .filter = code,
+ };
+
ppp_lock(ppp);
- kfree(ppp->pass_filter);
- ppp->pass_filter = code;
- ppp->pass_len = err;
+ if (ppp->pass_filter)
+ sk_unattached_filter_destroy(ppp->pass_filter);
+ err = sk_unattached_filter_create(&ppp->pass_filter,
+ &fprog);
+ kfree(code);
ppp_unlock(ppp);
- err = 0;
}
break;
}
case PPPIOCSACTIVE:
{
struct sock_filter *code;
+
err = get_filter(argp, &code);
if (err >= 0) {
+ struct sock_fprog fprog = {
+ .len = err,
+ .filter = code,
+ };
+
ppp_lock(ppp);
- kfree(ppp->active_filter);
- ppp->active_filter = code;
- ppp->active_len = err;
+ if (ppp->active_filter)
+ sk_unattached_filter_destroy(ppp->active_filter);
+ err = sk_unattached_filter_create(&ppp->active_filter,
+ &fprog);
+ kfree(code);
ppp_unlock(ppp);
- err = 0;
}
break;
}
@@ -1184,7 +1197,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
a four-byte PPP header on each packet */
*skb_push(skb, 2) = 1;
if (ppp->pass_filter &&
- sk_run_filter(skb, ppp->pass_filter) == 0) {
+ SK_RUN_FILTER(ppp->pass_filter, skb) == 0) {
if (ppp->debug & 1)
netdev_printk(KERN_DEBUG, ppp->dev,
"PPP: outbound frame "
@@ -1194,7 +1207,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
}
/* if this packet passes the active filter, record the time */
if (!(ppp->active_filter &&
- sk_run_filter(skb, ppp->active_filter) == 0))
+ SK_RUN_FILTER(ppp->active_filter, skb) == 0))
ppp->last_xmit = jiffies;
skb_pull(skb, 2);
#else
@@ -1818,7 +1831,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
*skb_push(skb, 2) = 0;
if (ppp->pass_filter &&
- sk_run_filter(skb, ppp->pass_filter) == 0) {
+ SK_RUN_FILTER(ppp->pass_filter, skb) == 0) {
if (ppp->debug & 1)
netdev_printk(KERN_DEBUG, ppp->dev,
"PPP: inbound frame "
@@ -1827,7 +1840,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
return;
}
if (!(ppp->active_filter &&
- sk_run_filter(skb, ppp->active_filter) == 0))
+ SK_RUN_FILTER(ppp->active_filter, skb) == 0))
ppp->last_recv = jiffies;
__skb_pull(skb, 2);
} else
@@ -2672,6 +2685,10 @@ ppp_create_interface(struct net *net, int unit, int *retp)
ppp->minseq = -1;
skb_queue_head_init(&ppp->mrq);
#endif /* CONFIG_PPP_MULTILINK */
+#ifdef CONFIG_PPP_FILTER
+ ppp->pass_filter = NULL;
+ ppp->active_filter = NULL;
+#endif /* CONFIG_PPP_FILTER */
/*
* drum roll: don't forget to set
@@ -2802,10 +2819,15 @@ static void ppp_destroy_interface(struct ppp *ppp)
skb_queue_purge(&ppp->mrq);
#endif /* CONFIG_PPP_MULTILINK */
#ifdef CONFIG_PPP_FILTER
- kfree(ppp->pass_filter);
- ppp->pass_filter = NULL;
- kfree(ppp->active_filter);
- ppp->active_filter = NULL;
+ if (ppp->pass_filter) {
+ sk_unattached_filter_destroy(ppp->pass_filter);
+ ppp->pass_filter = NULL;
+ }
+
+ if (ppp->active_filter) {
+ sk_unattached_filter_destroy(ppp->active_filter);
+ ppp->active_filter = NULL;
+ }
#endif /* CONFIG_PPP_FILTER */
kfree_skb(ppp->xmit_pending);
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 28407426fd6f..33008c1d1d67 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -1031,8 +1031,7 @@ static void team_port_leave(struct team *team, struct team_port *port)
}
#ifdef CONFIG_NET_POLL_CONTROLLER
-static int team_port_enable_netpoll(struct team *team, struct team_port *port,
- gfp_t gfp)
+static int team_port_enable_netpoll(struct team *team, struct team_port *port)
{
struct netpoll *np;
int err;
@@ -1040,11 +1039,11 @@ static int team_port_enable_netpoll(struct team *team, struct team_port *port,
if (!team->dev->npinfo)
return 0;
- np = kzalloc(sizeof(*np), gfp);
+ np = kzalloc(sizeof(*np), GFP_KERNEL);
if (!np)
return -ENOMEM;
- err = __netpoll_setup(np, port->dev, gfp);
+ err = __netpoll_setup(np, port->dev);
if (err) {
kfree(np);
return err;
@@ -1067,8 +1066,7 @@ static void team_port_disable_netpoll(struct team_port *port)
kfree(np);
}
#else
-static int team_port_enable_netpoll(struct team *team, struct team_port *port,
- gfp_t gfp)
+static int team_port_enable_netpoll(struct team *team, struct team_port *port)
{
return 0;
}
@@ -1156,7 +1154,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
goto err_vids_add;
}
- err = team_port_enable_netpoll(team, port, GFP_KERNEL);
+ err = team_port_enable_netpoll(team, port);
if (err) {
netdev_err(dev, "Failed to enable netpoll on device %s\n",
portname);
@@ -1540,16 +1538,10 @@ static int team_init(struct net_device *dev)
mutex_init(&team->lock);
team_set_no_mode(team);
- team->pcpu_stats = alloc_percpu(struct team_pcpu_stats);
+ team->pcpu_stats = netdev_alloc_pcpu_stats(struct team_pcpu_stats);
if (!team->pcpu_stats)
return -ENOMEM;
- for_each_possible_cpu(i) {
- struct team_pcpu_stats *team_stats;
- team_stats = per_cpu_ptr(team->pcpu_stats, i);
- u64_stats_init(&team_stats->syncp);
- }
-
for (i = 0; i < TEAM_PORT_HASHENTRIES; i++)
INIT_HLIST_HEAD(&team->en_port_hlist[i]);
INIT_LIST_HEAD(&team->port_list);
@@ -1648,7 +1640,7 @@ static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev)
}
static u16 team_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv, select_queue_fallback_t fallback)
{
/*
* This helper function exists to help dev_pick_tx get the correct
@@ -1767,13 +1759,13 @@ team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
for_each_possible_cpu(i) {
p = per_cpu_ptr(team->pcpu_stats, i);
do {
- start = u64_stats_fetch_begin_bh(&p->syncp);
+ start = u64_stats_fetch_begin_irq(&p->syncp);
rx_packets = p->rx_packets;
rx_bytes = p->rx_bytes;
rx_multicast = p->rx_multicast;
tx_packets = p->tx_packets;
tx_bytes = p->tx_bytes;
- } while (u64_stats_fetch_retry_bh(&p->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&p->syncp, start));
stats->rx_packets += rx_packets;
stats->rx_bytes += rx_bytes;
@@ -1856,7 +1848,7 @@ static void team_netpoll_cleanup(struct net_device *dev)
}
static int team_netpoll_setup(struct net_device *dev,
- struct netpoll_info *npifo, gfp_t gfp)
+ struct netpoll_info *npifo)
{
struct team *team = netdev_priv(dev);
struct team_port *port;
@@ -1864,7 +1856,7 @@ static int team_netpoll_setup(struct net_device *dev,
mutex_lock(&team->lock);
list_for_each_entry(port, &team->port_list, list) {
- err = team_port_enable_netpoll(team, port, gfp);
+ err = team_port_enable_netpoll(team, port);
if (err) {
__team_netpoll_cleanup(team);
break;
diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c
index d671fc3ac5ac..dbde3412ee5e 100644
--- a/drivers/net/team/team_mode_loadbalance.c
+++ b/drivers/net/team/team_mode_loadbalance.c
@@ -432,9 +432,9 @@ static void __lb_one_cpu_stats_add(struct lb_stats *acc_stats,
struct lb_stats tmp;
do {
- start = u64_stats_fetch_begin_bh(syncp);
+ start = u64_stats_fetch_begin_irq(syncp);
tmp.tx_bytes = cpu_stats->tx_bytes;
- } while (u64_stats_fetch_retry_bh(syncp, start));
+ } while (u64_stats_fetch_retry_irq(syncp, start));
acc_stats->tx_bytes += tmp.tx_bytes;
}
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 44c4db8450f0..ee328ba101e7 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -366,7 +366,7 @@ static inline void tun_flow_save_rps_rxhash(struct tun_flow_entry *e, u32 hash)
* hope the rxq no. may help here.
*/
static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv, select_queue_fallback_t fallback)
{
struct tun_struct *tun = netdev_priv(dev);
struct tun_flow_entry *e;
@@ -452,7 +452,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
--tun->numqueues;
if (clean) {
- rcu_assign_pointer(tfile->tun, NULL);
+ RCU_INIT_POINTER(tfile->tun, NULL);
sock_put(&tfile->sk);
} else
tun_disable_queue(tun, tfile);
@@ -499,12 +499,12 @@ static void tun_detach_all(struct net_device *dev)
tfile = rtnl_dereference(tun->tfiles[i]);
BUG_ON(!tfile);
wake_up_all(&tfile->wq.wait);
- rcu_assign_pointer(tfile->tun, NULL);
+ RCU_INIT_POINTER(tfile->tun, NULL);
--tun->numqueues;
}
list_for_each_entry(tfile, &tun->disabled, next) {
wake_up_all(&tfile->wq.wait);
- rcu_assign_pointer(tfile->tun, NULL);
+ RCU_INIT_POINTER(tfile->tun, NULL);
}
BUG_ON(tun->numqueues != 0);
@@ -1686,7 +1686,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_STAG_TX;
dev->features = dev->hw_features;
- dev->vlan_features = dev->features;
+ dev->vlan_features = dev->features &
+ ~(NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_STAG_TX);
INIT_LIST_HEAD(&tun->disabled);
err = tun_attach(tun, file, false);
@@ -2192,7 +2194,7 @@ static int tun_chr_open(struct inode *inode, struct file * file)
&tun_proto);
if (!tfile)
return -ENOMEM;
- rcu_assign_pointer(tfile->tun, NULL);
+ RCU_INIT_POINTER(tfile->tun, NULL);
tfile->net = get_net(current->nsproxy->net_ns);
tfile->flags = 0;
tfile->ifindex = 0;
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 6b638a066c1d..7e7269fd3707 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -292,6 +292,21 @@ config USB_NET_SR9700
This option adds support for CoreChip-sz SR9700 based USB 1.1
10/100 Ethernet adapters.
+config USB_NET_SR9800
+ tristate "CoreChip-sz SR9800 based USB 2.0 10/100 ethernet devices"
+ depends on USB_USBNET
+ select CRC32
+ ---help---
+ Say Y if you want to use one of the following 100Mbps USB Ethernet
+ device based on the CoreChip-sz SR9800 chip.
+
+ This driver makes the adapter appear as a normal Ethernet interface,
+ typically on eth0, if it is the only ethernet device, or perhaps on
+ eth1, if you have a PCI or ISA ethernet card installed.
+
+ To compile this driver as a module, choose M here: the
+ module will be called sr9800.
+
config USB_NET_SMSC75XX
tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices"
depends on USB_USBNET
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index b17b5e88bbaf..e2797f1e1b31 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -11,10 +11,11 @@ obj-$(CONFIG_USB_HSO) += hso.o
obj-$(CONFIG_USB_NET_AX8817X) += asix.o
asix-y := asix_devices.o asix_common.o ax88172a.o
obj-$(CONFIG_USB_NET_AX88179_178A) += ax88179_178a.o
-obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o r815x.o
+obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o
obj-$(CONFIG_USB_NET_CDC_EEM) += cdc_eem.o
obj-$(CONFIG_USB_NET_DM9601) += dm9601.o
obj-$(CONFIG_USB_NET_SR9700) += sr9700.o
+obj-$(CONFIG_USB_NET_SR9800) += sr9800.o
obj-$(CONFIG_USB_NET_SMSC75XX) += smsc75xx.o
obj-$(CONFIG_USB_NET_SMSC95XX) += smsc95xx.o
obj-$(CONFIG_USB_NET_GL620A) += gl620a.o
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c
index 9765a7d4766d..5d194093f3e1 100644
--- a/drivers/net/usb/asix_devices.c
+++ b/drivers/net/usb/asix_devices.c
@@ -917,7 +917,8 @@ static const struct driver_info ax88178_info = {
.status = asix_status,
.link_reset = ax88178_link_reset,
.reset = ax88178_reset,
- .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR,
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
+ FLAG_MULTI_PACKET,
.rx_fixup = asix_rx_fixup_common,
.tx_fixup = asix_tx_fixup,
};
diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c
index d6f64dad05bc..054e59ca6946 100644
--- a/drivers/net/usb/ax88179_178a.c
+++ b/drivers/net/usb/ax88179_178a.c
@@ -1029,20 +1029,12 @@ 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;
dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
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 |
AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
@@ -1118,6 +1110,10 @@ static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
u16 hdr_off;
u32 *pkt_hdr;
+ /* This check is no longer done by usbnet */
+ if (skb->len < dev->net->hard_header_len)
+ return 0;
+
skb_trim(skb, skb->len - 4);
memcpy(&rx_hdr, skb_tail_pointer(skb), 4);
le32_to_cpus(&rx_hdr);
@@ -1391,6 +1387,19 @@ static const struct driver_info ax88178a_info = {
.tx_fixup = ax88179_tx_fixup,
};
+static const struct driver_info dlink_dub1312_info = {
+ .description = "D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter",
+ .bind = ax88179_bind,
+ .unbind = ax88179_unbind,
+ .status = ax88179_status,
+ .link_reset = ax88179_link_reset,
+ .reset = ax88179_reset,
+ .stop = ax88179_stop,
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+ .rx_fixup = ax88179_rx_fixup,
+ .tx_fixup = ax88179_tx_fixup,
+};
+
static const struct driver_info sitecom_info = {
.description = "Sitecom USB 3.0 to Gigabit Adapter",
.bind = ax88179_bind,
@@ -1417,6 +1426,19 @@ static const struct driver_info samsung_info = {
.tx_fixup = ax88179_tx_fixup,
};
+static const struct driver_info lenovo_info = {
+ .description = "Lenovo OneLinkDock Gigabit LAN",
+ .bind = ax88179_bind,
+ .unbind = ax88179_unbind,
+ .status = ax88179_status,
+ .link_reset = ax88179_link_reset,
+ .reset = ax88179_reset,
+ .stop = ax88179_stop,
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+ .rx_fixup = ax88179_rx_fixup,
+ .tx_fixup = ax88179_tx_fixup,
+};
+
static const struct usb_device_id products[] = {
{
/* ASIX AX88179 10/100/1000 */
@@ -1427,6 +1449,10 @@ static const struct usb_device_id products[] = {
USB_DEVICE(0x0b95, 0x178a),
.driver_info = (unsigned long)&ax88178a_info,
}, {
+ /* D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter */
+ USB_DEVICE(0x2001, 0x4a00),
+ .driver_info = (unsigned long)&dlink_dub1312_info,
+}, {
/* Sitecom USB 3.0 to Gigabit Adapter */
USB_DEVICE(0x0df6, 0x0072),
.driver_info = (unsigned long)&sitecom_info,
@@ -1434,6 +1460,10 @@ static const struct usb_device_id products[] = {
/* Samsung USB Ethernet Adapter */
USB_DEVICE(0x04e8, 0xa100),
.driver_info = (unsigned long)&samsung_info,
+}, {
+ /* Lenovo OneLinkDock Gigabit LAN */
+ USB_DEVICE(0x17ef, 0x304b),
+ .driver_info = (unsigned long)&lenovo_info,
},
{ },
};
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index 42e176912c8e..9ea4bfe5d318 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -625,6 +625,13 @@ static const struct usb_device_id products[] = {
.driver_info = 0,
},
+/* Novatel Expedite E371 - handled by qmi_wwan */
+{
+ USB_DEVICE_AND_INTERFACE_INFO(NOVATEL_VENDOR_ID, 0x9011, USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+ .driver_info = 0,
+},
+
/* AnyDATA ADU960S - handled by qmi_wwan */
{
USB_DEVICE_AND_INTERFACE_INFO(0x16d5, 0x650a, USB_CLASS_COMM,
@@ -652,6 +659,13 @@ static const struct usb_device_id products[] = {
.driver_info = 0,
},
+/* Samsung USB Ethernet Adapters */
+{
+ USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, 0xa101, USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+ .driver_info = 0,
+},
+
/* WHITELIST!!!
*
* CDC Ether uses two interfaces, not necessarily consecutive.
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index dbff290ed0e4..549dbac710ed 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -68,12 +68,12 @@ static struct usb_driver cdc_ncm_driver;
static int cdc_ncm_setup(struct usbnet *dev)
{
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
- struct usb_cdc_ncm_ntb_parameters ncm_parm;
u32 val;
u8 flags;
u8 iface_no;
int err;
int eth_hlen;
+ u16 mbim_mtu;
u16 ntb_fmt_supported;
__le16 max_datagram_size;
@@ -82,22 +82,22 @@ static int cdc_ncm_setup(struct usbnet *dev)
err = usbnet_read_cmd(dev, USB_CDC_GET_NTB_PARAMETERS,
USB_TYPE_CLASS | USB_DIR_IN
|USB_RECIP_INTERFACE,
- 0, iface_no, &ncm_parm,
- sizeof(ncm_parm));
+ 0, iface_no, &ctx->ncm_parm,
+ sizeof(ctx->ncm_parm));
if (err < 0) {
dev_err(&dev->intf->dev, "failed GET_NTB_PARAMETERS\n");
return err; /* GET_NTB_PARAMETERS is required */
}
/* read correct set of parameters according to device mode */
- ctx->rx_max = le32_to_cpu(ncm_parm.dwNtbInMaxSize);
- ctx->tx_max = le32_to_cpu(ncm_parm.dwNtbOutMaxSize);
- ctx->tx_remainder = le16_to_cpu(ncm_parm.wNdpOutPayloadRemainder);
- ctx->tx_modulus = le16_to_cpu(ncm_parm.wNdpOutDivisor);
- ctx->tx_ndp_modulus = le16_to_cpu(ncm_parm.wNdpOutAlignment);
+ ctx->rx_max = le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize);
+ ctx->tx_max = le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize);
+ ctx->tx_remainder = le16_to_cpu(ctx->ncm_parm.wNdpOutPayloadRemainder);
+ ctx->tx_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutDivisor);
+ ctx->tx_ndp_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutAlignment);
/* devices prior to NCM Errata shall set this field to zero */
- ctx->tx_max_datagrams = le16_to_cpu(ncm_parm.wNtbOutMaxDatagrams);
- ntb_fmt_supported = le16_to_cpu(ncm_parm.bmNtbFormatsSupported);
+ ctx->tx_max_datagrams = le16_to_cpu(ctx->ncm_parm.wNtbOutMaxDatagrams);
+ ntb_fmt_supported = le16_to_cpu(ctx->ncm_parm.bmNtbFormatsSupported);
/* there are some minor differences in NCM and MBIM defaults */
if (cdc_ncm_comm_intf_is_mbim(ctx->control->cur_altsetting)) {
@@ -146,7 +146,7 @@ static int cdc_ncm_setup(struct usbnet *dev)
}
/* inform device about NTB input size changes */
- if (ctx->rx_max != le32_to_cpu(ncm_parm.dwNtbInMaxSize)) {
+ if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) {
__le32 dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_INPUT_SIZE,
@@ -162,14 +162,6 @@ static int cdc_ncm_setup(struct usbnet *dev)
dev_dbg(&dev->intf->dev, "Using default maximum transmit length=%d\n",
CDC_NCM_NTB_MAX_SIZE_TX);
ctx->tx_max = CDC_NCM_NTB_MAX_SIZE_TX;
-
- /* Adding a pad byte here simplifies the handling in
- * cdc_ncm_fill_tx_frame, by making tx_max always
- * represent the real skb max size.
- */
- if (ctx->tx_max % usb_maxpacket(dev->udev, dev->out, 1) == 0)
- ctx->tx_max++;
-
}
/*
@@ -261,6 +253,14 @@ out:
/* set MTU to max supported by the device if necessary */
if (dev->net->mtu > ctx->max_datagram_size - eth_hlen)
dev->net->mtu = ctx->max_datagram_size - eth_hlen;
+
+ /* do not exceed operater preferred MTU */
+ if (ctx->mbim_extended_desc) {
+ mbim_mtu = le16_to_cpu(ctx->mbim_extended_desc->wMTU);
+ if (mbim_mtu != 0 && mbim_mtu < dev->net->mtu)
+ dev->net->mtu = mbim_mtu;
+ }
+
return 0;
}
@@ -399,6 +399,14 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
ctx->mbim_desc = (const struct usb_cdc_mbim_desc *)buf;
break;
+ case USB_CDC_MBIM_EXTENDED_TYPE:
+ if (buf[0] < sizeof(*(ctx->mbim_extended_desc)))
+ break;
+
+ ctx->mbim_extended_desc =
+ (const struct usb_cdc_mbim_extended_desc *)buf;
+ break;
+
default:
break;
}
@@ -439,6 +447,10 @@ advance:
goto error2;
}
+ /* initialize data interface */
+ if (cdc_ncm_setup(dev))
+ goto error2;
+
/* configure data interface */
temp = usb_set_interface(dev->udev, iface_no, data_altsetting);
if (temp) {
@@ -453,12 +465,6 @@ advance:
goto error2;
}
- /* initialize data interface */
- if (cdc_ncm_setup(dev)) {
- dev_dbg(&intf->dev, "cdc_ncm_setup() failed\n");
- goto error2;
- }
-
usb_set_intfdata(ctx->data, dev);
usb_set_intfdata(ctx->control, dev);
@@ -475,6 +481,15 @@ advance:
dev->hard_mtu = ctx->tx_max;
dev->rx_urb_size = ctx->rx_max;
+ /* cdc_ncm_setup will override dwNtbOutMaxSize if it is
+ * outside the sane range. Adding a pad byte here if necessary
+ * simplifies the handling in cdc_ncm_fill_tx_frame, making
+ * tx_max always represent the real skb max size.
+ */
+ if (ctx->tx_max != le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize) &&
+ ctx->tx_max % usb_maxpacket(dev->udev, dev->out, 1) == 0)
+ ctx->tx_max++;
+
return 0;
error2:
diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c
index e4a8a93fbaf7..1cc24e6f23e2 100644
--- a/drivers/net/usb/gl620a.c
+++ b/drivers/net/usb/gl620a.c
@@ -84,6 +84,10 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
u32 size;
u32 count;
+ /* This check is no longer done by usbnet */
+ if (skb->len < dev->net->hard_header_len)
+ return 0;
+
header = (struct gl_header *) skb->data;
// get the packet count of the received skb
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 1a482344b3f5..660bd5ea9fc0 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -1201,16 +1201,18 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb)
struct hso_serial *serial = urb->context;
int status = urb->status;
+ D4("\n--- Got serial_read_bulk callback %02x ---", status);
+
/* sanity check */
if (!serial) {
D1("serial == NULL");
return;
- } else if (status) {
+ }
+ if (status) {
handle_usb_error(status, __func__, serial->parent);
return;
}
- D4("\n--- Got serial_read_bulk callback %02x ---", status);
D1("Actual length = %d\n", urb->actual_length);
DUMP1(urb->transfer_buffer, urb->actual_length);
@@ -1218,25 +1220,13 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb)
if (serial->port.count == 0)
return;
- if (status == 0) {
- if (serial->parent->port_spec & HSO_INFO_CRC_BUG)
- fix_crc_bug(urb, serial->in_endp->wMaxPacketSize);
- /* Valid data, handle RX data */
- spin_lock(&serial->serial_lock);
- serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1;
- put_rxbuf_data_and_resubmit_bulk_urb(serial);
- spin_unlock(&serial->serial_lock);
- } else if (status == -ENOENT || status == -ECONNRESET) {
- /* Unlinked - check for throttled port. */
- D2("Port %d, successfully unlinked urb", serial->minor);
- spin_lock(&serial->serial_lock);
- serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
- hso_resubmit_rx_bulk_urb(serial, urb);
- spin_unlock(&serial->serial_lock);
- } else {
- D2("Port %d, status = %d for read urb", serial->minor, status);
- return;
- }
+ if (serial->parent->port_spec & HSO_INFO_CRC_BUG)
+ fix_crc_bug(urb, serial->in_endp->wMaxPacketSize);
+ /* Valid data, handle RX data */
+ spin_lock(&serial->serial_lock);
+ serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1;
+ put_rxbuf_data_and_resubmit_bulk_urb(serial);
+ spin_unlock(&serial->serial_lock);
}
/*
diff --git a/drivers/net/usb/lg-vl600.c b/drivers/net/usb/lg-vl600.c
index acfcc32b323d..8f37efd2d2fb 100644
--- a/drivers/net/usb/lg-vl600.c
+++ b/drivers/net/usb/lg-vl600.c
@@ -210,7 +210,7 @@ static int vl600_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
* (0x86dd) so Linux can understand it.
*/
if ((buf->data[sizeof(*ethhdr)] & 0xf0) == 0x60)
- ethhdr->h_proto = __constant_htons(ETH_P_IPV6);
+ ethhdr->h_proto = htons(ETH_P_IPV6);
}
if (count) {
diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c
index a305a7b2dae6..82d844a8ebd0 100644
--- a/drivers/net/usb/mcs7830.c
+++ b/drivers/net/usb/mcs7830.c
@@ -526,8 +526,9 @@ static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
u8 status;
- if (skb->len == 0) {
- dev_err(&dev->udev->dev, "unexpected empty rx frame\n");
+ /* This check is no longer done by usbnet */
+ if (skb->len < dev->net->hard_header_len) {
+ dev_err(&dev->udev->dev, "unexpected tiny rx frame\n");
return 0;
}
diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c
index 0a85d9227775..4cbdb1307f3e 100644
--- a/drivers/net/usb/net1080.c
+++ b/drivers/net/usb/net1080.c
@@ -364,6 +364,10 @@ static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
struct nc_trailer *trailer;
u16 hdr_len, packet_len;
+ /* This check is no longer done by usbnet */
+ if (skb->len < dev->net->hard_header_len)
+ return 0;
+
if (!(skb->len & 0x01)) {
netdev_dbg(dev->net, "rx framesize %d range %d..%d mtu %d\n",
skb->len, dev->net->hard_header_len, dev->hard_mtu,
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 23bdd5b9274d..e3458e3c44f1 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -80,10 +80,10 @@ static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
__be16 proto;
- /* usbnet rx_complete guarantees that skb->len is at least
- * hard_header_len, so we can inspect the dest address without
- * checking skb->len
- */
+ /* This check is no longer done by usbnet */
+ if (skb->len < dev->net->hard_header_len)
+ return 0;
+
switch (skb->data[0] & 0xf0) {
case 0x40:
proto = htons(ETH_P_IP);
@@ -500,6 +500,13 @@ static const struct usb_device_id products[] = {
USB_CDC_PROTO_NONE),
.driver_info = (unsigned long)&qmi_wwan_info,
},
+ { /* Novatel Expedite E371 */
+ USB_DEVICE_AND_INTERFACE_INFO(0x1410, 0x9011,
+ USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_ETHERNET,
+ USB_CDC_PROTO_NONE),
+ .driver_info = (unsigned long)&qmi_wwan_info,
+ },
{ /* Dell Wireless 5800 (Novatel E362) */
USB_DEVICE_AND_INTERFACE_INFO(0x413C, 0x8195,
USB_CLASS_COMM,
@@ -712,6 +719,7 @@ static const struct usb_device_id products[] = {
{QMI_FIXED_INTF(0x19d2, 0x1255, 3)},
{QMI_FIXED_INTF(0x19d2, 0x1255, 4)},
{QMI_FIXED_INTF(0x19d2, 0x1256, 4)},
+ {QMI_FIXED_INTF(0x19d2, 0x1270, 5)}, /* ZTE MF667 */
{QMI_FIXED_INTF(0x19d2, 0x1401, 2)},
{QMI_FIXED_INTF(0x19d2, 0x1402, 2)}, /* ZTE MF60 */
{QMI_FIXED_INTF(0x19d2, 0x1424, 2)},
@@ -723,6 +731,7 @@ static const struct usb_device_id products[] = {
{QMI_FIXED_INTF(0x1199, 0x68a2, 8)}, /* Sierra Wireless MC7710 in QMI mode */
{QMI_FIXED_INTF(0x1199, 0x68a2, 19)}, /* Sierra Wireless MC7710 in QMI mode */
{QMI_FIXED_INTF(0x1199, 0x901c, 8)}, /* Sierra Wireless EM7700 */
+ {QMI_FIXED_INTF(0x1199, 0x9051, 8)}, /* Netgear AirCard 340U */
{QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */
{QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */
{QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */
@@ -730,6 +739,7 @@ static const struct usb_device_id products[] = {
{QMI_FIXED_INTF(0x1bc7, 0x1201, 2)}, /* Telit LE920 */
{QMI_FIXED_INTF(0x0b3c, 0xc005, 6)}, /* Olivetti Olicard 200 */
{QMI_FIXED_INTF(0x1e2d, 0x0060, 4)}, /* Cinterion PLxx */
+ {QMI_FIXED_INTF(0x1e2d, 0x0053, 4)}, /* Cinterion PHxx,PXxx */
/* 4. Gobi 1000 devices */
{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index e8fac732c6f1..18e12a3f7fc3 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -21,9 +21,10 @@
#include <linux/list.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
+#include <net/ip6_checksum.h>
/* Version Information */
-#define DRIVER_VERSION "v1.04.0 (2014/01/15)"
+#define DRIVER_VERSION "v1.06.0 (2014/03/03)"
#define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
#define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
#define MODULENAME "r8152"
@@ -59,9 +60,11 @@
#define PLA_TCR0 0xe610
#define PLA_TCR1 0xe612
#define PLA_TXFIFO_CTRL 0xe618
-#define PLA_RSTTELLY 0xe800
+#define PLA_RSTTALLY 0xe800
#define PLA_CR 0xe813
#define PLA_CRWECR 0xe81c
+#define PLA_CONFIG12 0xe81e /* CONFIG1, CONFIG2 */
+#define PLA_CONFIG34 0xe820 /* CONFIG3, CONFIG4 */
#define PLA_CONFIG5 0xe822
#define PLA_PHY_PWR 0xe84c
#define PLA_OOB_CTRL 0xe84f
@@ -69,7 +72,7 @@
#define PLA_MISC_0 0xe858
#define PLA_MISC_1 0xe85a
#define PLA_OCP_GPHY_BASE 0xe86c
-#define PLA_TELLYCNT 0xe890
+#define PLA_TALLYCNT 0xe890
#define PLA_SFF_STS_7 0xe8de
#define PLA_PHYSTATUS 0xe908
#define PLA_BP_BA 0xfc26
@@ -177,6 +180,9 @@
/* PLA_TCR1 */
#define VERSION_MASK 0x7cf0
+/* PLA_RSTTALLY */
+#define TALLY_RESET 0x0001
+
/* PLA_CR */
#define CR_RST 0x10
#define CR_RE 0x08
@@ -216,7 +222,14 @@
/* PAL_BDC_CR */
#define ALDPS_PROXY_MODE 0x0001
+/* PLA_CONFIG34 */
+#define LINK_ON_WAKE_EN 0x0010
+#define LINK_OFF_WAKE_EN 0x0008
+
/* PLA_CONFIG5 */
+#define BWF_EN 0x0040
+#define MWF_EN 0x0020
+#define UWF_EN 0x0010
#define LAN_WAKE_EN 0x0002
/* PLA_LED_FEATURE */
@@ -436,6 +449,9 @@ enum rtl8152_flags {
RTL8152_SET_RX_MODE,
WORK_ENABLE,
RTL8152_LINK_CHG,
+ SELECTIVE_SUSPEND,
+ PHY_RESET,
+ SCHEDULE_TASKLET,
};
/* Define these values to match your device */
@@ -452,11 +468,37 @@ enum rtl8152_flags {
#define REALTEK_USB_DEVICE(vend, prod) \
USB_DEVICE_INTERFACE_CLASS(vend, prod, USB_CLASS_VENDOR_SPEC)
+struct tally_counter {
+ __le64 tx_packets;
+ __le64 rx_packets;
+ __le64 tx_errors;
+ __le32 rx_errors;
+ __le16 rx_missed;
+ __le16 align_errors;
+ __le32 tx_one_collision;
+ __le32 tx_multi_collision;
+ __le64 rx_unicast;
+ __le64 rx_broadcast;
+ __le32 rx_multicast;
+ __le16 tx_aborted;
+ __le16 tx_underun;
+};
+
struct rx_desc {
__le32 opts1;
#define RX_LEN_MASK 0x7fff
+
__le32 opts2;
+#define RD_UDP_CS (1 << 23)
+#define RD_TCP_CS (1 << 22)
+#define RD_IPV6_CS (1 << 20)
+#define RD_IPV4_CS (1 << 19)
+
__le32 opts3;
+#define IPF (1 << 23) /* IP checksum fail */
+#define UDPF (1 << 22) /* UDP checksum fail */
+#define TCPF (1 << 21) /* TCP checksum fail */
+
__le32 opts4;
__le32 opts5;
__le32 opts6;
@@ -466,13 +508,21 @@ struct tx_desc {
__le32 opts1;
#define TX_FS (1 << 31) /* First segment of a packet */
#define TX_LS (1 << 30) /* Final segment of a packet */
-#define TX_LEN_MASK 0x3ffff
+#define GTSENDV4 (1 << 28)
+#define GTSENDV6 (1 << 27)
+#define GTTCPHO_SHIFT 18
+#define GTTCPHO_MAX 0x7fU
+#define TX_LEN_MAX 0x3ffffU
__le32 opts2;
#define UDP_CS (1 << 31) /* Calculate UDP/IP checksum */
#define TCP_CS (1 << 30) /* Calculate TCP/IP checksum */
#define IPV4_CS (1 << 29) /* Calculate IPv4 checksum */
#define IPV6_CS (1 << 28) /* Calculate IPv6 checksum */
+#define MSS_SHIFT 17
+#define MSS_MAX 0x7ffU
+#define TCPHO_SHIFT 17
+#define TCPHO_MAX 0x7ffU
};
struct r8152;
@@ -514,11 +564,13 @@ struct r8152 {
void (*init)(struct r8152 *);
int (*enable)(struct r8152 *);
void (*disable)(struct r8152 *);
+ void (*up)(struct r8152 *);
void (*down)(struct r8152 *);
void (*unload)(struct r8152 *);
} rtl_ops;
int intr_interval;
+ u32 saved_wolopts;
u32 msg_enable;
u32 tx_qlen;
u16 ocp_base;
@@ -537,12 +589,21 @@ enum rtl_version {
RTL_VER_MAX
};
+enum tx_csum_stat {
+ TX_CSUM_SUCCESS = 0,
+ TX_CSUM_TSO,
+ TX_CSUM_NONE
+};
+
/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
* The RTL chips use a 64 element hash table based on the Ethernet CRC.
*/
static const int multicast_filter_limit = 32;
static unsigned int rx_buf_sz = 16384;
+#define RTL_LIMITED_TSO_SIZE (rx_buf_sz - sizeof(struct tx_desc) - \
+ VLAN_ETH_HLEN - VLAN_HLEN)
+
static
int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
{
@@ -580,6 +641,7 @@ int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
value, index, tmp, size, 500);
kfree(tmp);
+
return ret;
}
@@ -865,11 +927,21 @@ static u16 sram_read(struct r8152 *tp, u16 addr)
static int read_mii_word(struct net_device *netdev, int phy_id, int reg)
{
struct r8152 *tp = netdev_priv(netdev);
+ int ret;
if (phy_id != R8152_PHY_ID)
return -EINVAL;
- return r8152_mdio_read(tp, reg);
+ ret = usb_autopm_get_interface(tp->intf);
+ if (ret < 0)
+ goto out;
+
+ ret = r8152_mdio_read(tp, reg);
+
+ usb_autopm_put_interface(tp->intf);
+
+out:
+ return ret;
}
static
@@ -880,7 +952,12 @@ void write_mii_word(struct net_device *netdev, int phy_id, int reg, int val)
if (phy_id != R8152_PHY_ID)
return;
+ if (usb_autopm_get_interface(tp->intf) < 0)
+ return;
+
r8152_mdio_write(tp, reg, val);
+
+ usb_autopm_put_interface(tp->intf);
}
static
@@ -889,11 +966,26 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags);
static inline void set_ethernet_addr(struct r8152 *tp)
{
struct net_device *dev = tp->netdev;
+ int ret;
u8 node_id[8] = {0};
- if (pla_ocp_read(tp, PLA_IDR, sizeof(node_id), node_id) < 0)
+ if (tp->version == RTL_VER_01)
+ ret = pla_ocp_read(tp, PLA_IDR, sizeof(node_id), node_id);
+ else
+ ret = pla_ocp_read(tp, PLA_BACKUP, sizeof(node_id), node_id);
+
+ if (ret < 0) {
netif_notice(tp, probe, dev, "inet addr fail\n");
- else {
+ } else {
+ if (tp->version != RTL_VER_01) {
+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR,
+ CRWECR_CONFIG);
+ pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES,
+ sizeof(node_id), node_id);
+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR,
+ CRWECR_NORAML);
+ }
+
memcpy(dev->dev_addr, node_id, dev->addr_len);
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
}
@@ -916,15 +1008,9 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
return 0;
}
-static struct net_device_stats *rtl8152_get_stats(struct net_device *dev)
-{
- return &dev->stats;
-}
-
static void read_bulk_callback(struct urb *urb)
{
struct net_device *netdev;
- unsigned long flags;
int status = urb->status;
struct rx_agg *agg;
struct r8152 *tp;
@@ -951,14 +1037,16 @@ static void read_bulk_callback(struct urb *urb)
if (!netif_carrier_ok(netdev))
return;
+ usb_mark_last_busy(tp->udev);
+
switch (status) {
case 0:
if (urb->actual_length < ETH_ZLEN)
break;
- spin_lock_irqsave(&tp->rx_lock, flags);
+ spin_lock(&tp->rx_lock);
list_add_tail(&agg->list, &tp->rx_done);
- spin_unlock_irqrestore(&tp->rx_lock, flags);
+ spin_unlock(&tp->rx_lock);
tasklet_schedule(&tp->tl);
return;
case -ESHUTDOWN:
@@ -981,9 +1069,9 @@ static void read_bulk_callback(struct urb *urb)
if (result == -ENODEV) {
netif_device_detach(tp->netdev);
} else if (result) {
- spin_lock_irqsave(&tp->rx_lock, flags);
+ spin_lock(&tp->rx_lock);
list_add_tail(&agg->list, &tp->rx_done);
- spin_unlock_irqrestore(&tp->rx_lock, flags);
+ spin_unlock(&tp->rx_lock);
tasklet_schedule(&tp->tl);
}
}
@@ -991,7 +1079,7 @@ static void read_bulk_callback(struct urb *urb)
static void write_bulk_callback(struct urb *urb)
{
struct net_device_stats *stats;
- unsigned long flags;
+ struct net_device *netdev;
struct tx_agg *agg;
struct r8152 *tp;
int status = urb->status;
@@ -1004,21 +1092,24 @@ static void write_bulk_callback(struct urb *urb)
if (!tp)
return;
- stats = rtl8152_get_stats(tp->netdev);
+ netdev = tp->netdev;
+ stats = &netdev->stats;
if (status) {
if (net_ratelimit())
- netdev_warn(tp->netdev, "Tx status %d\n", status);
+ netdev_warn(netdev, "Tx status %d\n", status);
stats->tx_errors += agg->skb_num;
} else {
stats->tx_packets += agg->skb_num;
stats->tx_bytes += agg->skb_len;
}
- spin_lock_irqsave(&tp->tx_lock, flags);
+ spin_lock(&tp->tx_lock);
list_add_tail(&agg->list, &tp->tx_free);
- spin_unlock_irqrestore(&tp->tx_lock, flags);
+ spin_unlock(&tp->tx_lock);
- if (!netif_carrier_ok(tp->netdev))
+ usb_autopm_put_interface_async(tp->intf);
+
+ if (!netif_carrier_ok(netdev))
return;
if (!test_bit(WORK_ENABLE, &tp->flags))
@@ -1223,6 +1314,9 @@ static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp)
struct tx_agg *agg = NULL;
unsigned long flags;
+ if (list_empty(&tp->tx_free))
+ return NULL;
+
spin_lock_irqsave(&tp->tx_lock, flags);
if (!list_empty(&tp->tx_free)) {
struct list_head *cursor;
@@ -1236,24 +1330,138 @@ static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp)
return agg;
}
-static void
-r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb)
+static inline __be16 get_protocol(struct sk_buff *skb)
+{
+ __be16 protocol;
+
+ if (skb->protocol == htons(ETH_P_8021Q))
+ protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
+ else
+ protocol = skb->protocol;
+
+ return protocol;
+}
+
+/*
+ * r8152_csum_workaround()
+ * The hw limites the value the transport offset. When the offset is out of the
+ * range, calculate the checksum by sw.
+ */
+static void r8152_csum_workaround(struct r8152 *tp, struct sk_buff *skb,
+ struct sk_buff_head *list)
+{
+ if (skb_shinfo(skb)->gso_size) {
+ netdev_features_t features = tp->netdev->features;
+ struct sk_buff_head seg_list;
+ struct sk_buff *segs, *nskb;
+
+ features &= ~(NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO);
+ segs = skb_gso_segment(skb, features);
+ if (IS_ERR(segs) || !segs)
+ goto drop;
+
+ __skb_queue_head_init(&seg_list);
+
+ do {
+ nskb = segs;
+ segs = segs->next;
+ nskb->next = NULL;
+ __skb_queue_tail(&seg_list, nskb);
+ } while (segs);
+
+ skb_queue_splice(&seg_list, list);
+ dev_kfree_skb(skb);
+ } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (skb_checksum_help(skb) < 0)
+ goto drop;
+
+ __skb_queue_head(list, skb);
+ } else {
+ struct net_device_stats *stats;
+
+drop:
+ stats = &tp->netdev->stats;
+ stats->tx_dropped++;
+ dev_kfree_skb(skb);
+ }
+}
+
+/*
+ * msdn_giant_send_check()
+ * According to the document of microsoft, the TCP Pseudo Header excludes the
+ * packet length for IPv6 TCP large packets.
+ */
+static int msdn_giant_send_check(struct sk_buff *skb)
+{
+ const struct ipv6hdr *ipv6h;
+ struct tcphdr *th;
+ int ret;
+
+ ret = skb_cow_head(skb, 0);
+ if (ret)
+ return ret;
+
+ ipv6h = ipv6_hdr(skb);
+ th = tcp_hdr(skb);
+
+ th->check = 0;
+ th->check = ~tcp_v6_check(0, &ipv6h->saddr, &ipv6h->daddr, 0);
+
+ return ret;
+}
+
+static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc,
+ struct sk_buff *skb, u32 len, u32 transport_offset)
{
- memset(desc, 0, sizeof(*desc));
+ u32 mss = skb_shinfo(skb)->gso_size;
+ u32 opts1, opts2 = 0;
+ int ret = TX_CSUM_SUCCESS;
+
+ WARN_ON_ONCE(len > TX_LEN_MAX);
+
+ opts1 = len | TX_FS | TX_LS;
+
+ if (mss) {
+ if (transport_offset > GTTCPHO_MAX) {
+ netif_warn(tp, tx_err, tp->netdev,
+ "Invalid transport offset 0x%x for TSO\n",
+ transport_offset);
+ ret = TX_CSUM_TSO;
+ goto unavailable;
+ }
+
+ switch (get_protocol(skb)) {
+ case htons(ETH_P_IP):
+ opts1 |= GTSENDV4;
+ break;
+
+ case htons(ETH_P_IPV6):
+ if (msdn_giant_send_check(skb)) {
+ ret = TX_CSUM_TSO;
+ goto unavailable;
+ }
+ opts1 |= GTSENDV6;
+ break;
- desc->opts1 = cpu_to_le32((skb->len & TX_LEN_MASK) | TX_FS | TX_LS);
+ default:
+ WARN_ON_ONCE(1);
+ break;
+ }
- if (skb->ip_summed == CHECKSUM_PARTIAL) {
- __be16 protocol;
+ opts1 |= transport_offset << GTTCPHO_SHIFT;
+ opts2 |= min(mss, MSS_MAX) << MSS_SHIFT;
+ } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
u8 ip_protocol;
- u32 opts2 = 0;
- if (skb->protocol == htons(ETH_P_8021Q))
- protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
- else
- protocol = skb->protocol;
+ if (transport_offset > TCPHO_MAX) {
+ netif_warn(tp, tx_err, tp->netdev,
+ "Invalid transport offset 0x%x\n",
+ transport_offset);
+ ret = TX_CSUM_NONE;
+ goto unavailable;
+ }
- switch (protocol) {
+ switch (get_protocol(skb)) {
case htons(ETH_P_IP):
opts2 |= IPV4_CS;
ip_protocol = ip_hdr(skb)->protocol;
@@ -1269,24 +1477,34 @@ r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb)
break;
}
- if (ip_protocol == IPPROTO_TCP) {
+ if (ip_protocol == IPPROTO_TCP)
opts2 |= TCP_CS;
- opts2 |= (skb_transport_offset(skb) & 0x7fff) << 17;
- } else if (ip_protocol == IPPROTO_UDP) {
+ else if (ip_protocol == IPPROTO_UDP)
opts2 |= UDP_CS;
- } else {
+ else
WARN_ON_ONCE(1);
- }
- desc->opts2 = cpu_to_le32(opts2);
+ opts2 |= transport_offset << TCPHO_SHIFT;
}
+
+ desc->opts2 = cpu_to_le32(opts2);
+ desc->opts1 = cpu_to_le32(opts1);
+
+unavailable:
+ return ret;
}
static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
{
- int remain;
+ struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue;
+ int remain, ret;
u8 *tx_data;
+ __skb_queue_head_init(&skb_head);
+ spin_lock(&tx_queue->lock);
+ skb_queue_splice_init(tx_queue, &skb_head);
+ spin_unlock(&tx_queue->lock);
+
tx_data = agg->head;
agg->skb_num = agg->skb_len = 0;
remain = rx_buf_sz;
@@ -1295,32 +1513,56 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
struct tx_desc *tx_desc;
struct sk_buff *skb;
unsigned int len;
+ u32 offset;
- skb = skb_dequeue(&tp->tx_queue);
+ skb = __skb_dequeue(&skb_head);
if (!skb)
break;
- remain -= sizeof(*tx_desc);
- len = skb->len;
- if (remain < len) {
- skb_queue_head(&tp->tx_queue, skb);
+ len = skb->len + sizeof(*tx_desc);
+
+ if (len > remain) {
+ __skb_queue_head(&skb_head, skb);
break;
}
tx_data = tx_agg_align(tx_data);
tx_desc = (struct tx_desc *)tx_data;
+
+ offset = (u32)skb_transport_offset(skb);
+
+ if (r8152_tx_csum(tp, tx_desc, skb, skb->len, offset)) {
+ r8152_csum_workaround(tp, skb, &skb_head);
+ continue;
+ }
+
tx_data += sizeof(*tx_desc);
- r8152_tx_csum(tp, tx_desc, skb);
- memcpy(tx_data, skb->data, len);
- agg->skb_num++;
+ len = skb->len;
+ if (skb_copy_bits(skb, 0, tx_data, len) < 0) {
+ struct net_device_stats *stats = &tp->netdev->stats;
+
+ stats->tx_dropped++;
+ dev_kfree_skb_any(skb);
+ tx_data -= sizeof(*tx_desc);
+ continue;
+ }
+
+ tx_data += len;
agg->skb_len += len;
+ agg->skb_num++;
+
dev_kfree_skb_any(skb);
- tx_data += len;
remain = rx_buf_sz - (int)(tx_agg_align(tx_data) - agg->head);
}
+ if (!skb_queue_empty(&skb_head)) {
+ spin_lock(&tx_queue->lock);
+ skb_queue_splice(&skb_head, tx_queue);
+ spin_unlock(&tx_queue->lock);
+ }
+
netif_tx_lock(tp->netdev);
if (netif_queue_stopped(tp->netdev) &&
@@ -1329,20 +1571,67 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
netif_tx_unlock(tp->netdev);
+ ret = usb_autopm_get_interface_async(tp->intf);
+ if (ret < 0)
+ goto out_tx_fill;
+
usb_fill_bulk_urb(agg->urb, tp->udev, usb_sndbulkpipe(tp->udev, 2),
agg->head, (int)(tx_data - (u8 *)agg->head),
(usb_complete_t)write_bulk_callback, agg);
- return usb_submit_urb(agg->urb, GFP_ATOMIC);
+ ret = usb_submit_urb(agg->urb, GFP_ATOMIC);
+ if (ret < 0)
+ usb_autopm_put_interface_async(tp->intf);
+
+out_tx_fill:
+ return ret;
+}
+
+static u8 r8152_rx_csum(struct r8152 *tp, struct rx_desc *rx_desc)
+{
+ u8 checksum = CHECKSUM_NONE;
+ u32 opts2, opts3;
+
+ if (tp->version == RTL_VER_01)
+ goto return_result;
+
+ opts2 = le32_to_cpu(rx_desc->opts2);
+ opts3 = le32_to_cpu(rx_desc->opts3);
+
+ if (opts2 & RD_IPV4_CS) {
+ if (opts3 & IPF)
+ checksum = CHECKSUM_NONE;
+ else if ((opts2 & RD_UDP_CS) && (opts3 & UDPF))
+ checksum = CHECKSUM_NONE;
+ else if ((opts2 & RD_TCP_CS) && (opts3 & TCPF))
+ checksum = CHECKSUM_NONE;
+ else
+ checksum = CHECKSUM_UNNECESSARY;
+ } else if (RD_IPV6_CS) {
+ if ((opts2 & RD_UDP_CS) && !(opts3 & UDPF))
+ checksum = CHECKSUM_UNNECESSARY;
+ else if ((opts2 & RD_TCP_CS) && !(opts3 & TCPF))
+ checksum = CHECKSUM_UNNECESSARY;
+ }
+
+return_result:
+ return checksum;
}
static void rx_bottom(struct r8152 *tp)
{
unsigned long flags;
- struct list_head *cursor, *next;
+ struct list_head *cursor, *next, rx_queue;
+
+ if (list_empty(&tp->rx_done))
+ return;
+ INIT_LIST_HEAD(&rx_queue);
spin_lock_irqsave(&tp->rx_lock, flags);
- list_for_each_safe(cursor, next, &tp->rx_done) {
+ list_splice_init(&tp->rx_done, &rx_queue);
+ spin_unlock_irqrestore(&tp->rx_lock, flags);
+
+ list_for_each_safe(cursor, next, &rx_queue) {
struct rx_desc *rx_desc;
struct rx_agg *agg;
int len_used = 0;
@@ -1351,7 +1640,6 @@ static void rx_bottom(struct r8152 *tp)
int ret;
list_del_init(cursor);
- spin_unlock_irqrestore(&tp->rx_lock, flags);
agg = list_entry(cursor, struct rx_agg, list);
urb = agg->urb;
@@ -1364,7 +1652,7 @@ static void rx_bottom(struct r8152 *tp)
while (urb->actual_length > len_used) {
struct net_device *netdev = tp->netdev;
- struct net_device_stats *stats;
+ struct net_device_stats *stats = &netdev->stats;
unsigned int pkt_len;
struct sk_buff *skb;
@@ -1376,23 +1664,24 @@ static void rx_bottom(struct r8152 *tp)
if (urb->actual_length < len_used)
break;
- stats = rtl8152_get_stats(netdev);
-
pkt_len -= CRC_SIZE;
rx_data += sizeof(struct rx_desc);
skb = netdev_alloc_skb_ip_align(netdev, pkt_len);
if (!skb) {
stats->rx_dropped++;
- break;
+ goto find_next_rx;
}
+
+ skb->ip_summed = r8152_rx_csum(tp, rx_desc);
memcpy(skb->data, rx_data, pkt_len);
skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, netdev);
- netif_rx(skb);
+ netif_receive_skb(skb);
stats->rx_packets++;
stats->rx_bytes += pkt_len;
+find_next_rx:
rx_data = rx_agg_align(rx_data + pkt_len + CRC_SIZE);
rx_desc = (struct rx_desc *)rx_data;
len_used = (int)(rx_data - (u8 *)agg->head);
@@ -1401,13 +1690,13 @@ static void rx_bottom(struct r8152 *tp)
submit:
ret = r8152_submit_rx(tp, agg, GFP_ATOMIC);
- spin_lock_irqsave(&tp->rx_lock, flags);
if (ret && ret != -ENODEV) {
- list_add_tail(&agg->list, next);
+ spin_lock_irqsave(&tp->rx_lock, flags);
+ list_add_tail(&agg->list, &tp->rx_done);
+ spin_unlock_irqrestore(&tp->rx_lock, flags);
tasklet_schedule(&tp->tl);
}
}
- spin_unlock_irqrestore(&tp->rx_lock, flags);
}
static void tx_bottom(struct r8152 *tp)
@@ -1426,19 +1715,18 @@ static void tx_bottom(struct r8152 *tp)
res = r8152_tx_agg_fill(tp, agg);
if (res) {
- struct net_device_stats *stats;
- struct net_device *netdev;
- unsigned long flags;
-
- netdev = tp->netdev;
- stats = rtl8152_get_stats(netdev);
+ struct net_device *netdev = tp->netdev;
if (res == -ENODEV) {
netif_device_detach(netdev);
} else {
+ struct net_device_stats *stats = &netdev->stats;
+ unsigned long flags;
+
netif_warn(tp, tx_err, netdev,
"failed tx_urb %d\n", res);
stats->tx_dropped += agg->skb_num;
+
spin_lock_irqsave(&tp->tx_lock, flags);
list_add_tail(&agg->list, &tp->tx_free);
spin_unlock_irqrestore(&tp->tx_lock, flags);
@@ -1478,6 +1766,26 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags)
return usb_submit_urb(agg->urb, mem_flags);
}
+static void rtl_drop_queued_tx(struct r8152 *tp)
+{
+ struct net_device_stats *stats = &tp->netdev->stats;
+ struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue;
+ struct sk_buff *skb;
+
+ if (skb_queue_empty(tx_queue))
+ return;
+
+ __skb_queue_head_init(&skb_head);
+ spin_lock_bh(&tx_queue->lock);
+ skb_queue_splice_init(tx_queue, &skb_head);
+ spin_unlock_bh(&tx_queue->lock);
+
+ while ((skb = __skb_dequeue(&skb_head))) {
+ dev_kfree_skb(skb);
+ stats->tx_dropped++;
+ }
+}
+
static void rtl8152_tx_timeout(struct net_device *netdev)
{
struct r8152 *tp = netdev_priv(netdev);
@@ -1541,7 +1849,7 @@ static void _rtl8152_set_rx_mode(struct net_device *netdev)
}
static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
- struct net_device *netdev)
+ struct net_device *netdev)
{
struct r8152 *tp = netdev_priv(netdev);
@@ -1549,13 +1857,17 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
skb_queue_tail(&tp->tx_queue, skb);
- if (list_empty(&tp->tx_free) &&
- skb_queue_len(&tp->tx_queue) > tp->tx_qlen)
+ if (!list_empty(&tp->tx_free)) {
+ if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
+ set_bit(SCHEDULE_TASKLET, &tp->flags);
+ schedule_delayed_work(&tp->schedule, 0);
+ } else {
+ usb_mark_last_busy(tp->udev);
+ tasklet_schedule(&tp->tl);
+ }
+ } else if (skb_queue_len(&tp->tx_queue) > tp->tx_qlen)
netif_stop_queue(netdev);
- if (!list_empty(&tp->tx_free))
- tasklet_schedule(&tp->tl);
-
return NETDEV_TX_OK;
}
@@ -1613,6 +1925,18 @@ static void rtl_set_eee_plus(struct r8152 *tp)
}
}
+static void rxdy_gated_en(struct r8152 *tp, bool enable)
+{
+ u32 ocp_data;
+
+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
+ if (enable)
+ ocp_data |= RXDY_GATED_EN;
+ else
+ ocp_data &= ~RXDY_GATED_EN;
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
+}
+
static int rtl_enable(struct r8152 *tp)
{
u32 ocp_data;
@@ -1624,9 +1948,7 @@ static int rtl_enable(struct r8152 *tp)
ocp_data |= CR_RE | CR_TE;
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data);
- ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
- ocp_data &= ~RXDY_GATED_EN;
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
+ rxdy_gated_en(tp, false);
INIT_LIST_HEAD(&tp->rx_done);
ret = 0;
@@ -1681,8 +2003,6 @@ static int rtl8153_enable(struct r8152 *tp)
static void rtl8152_disable(struct r8152 *tp)
{
- struct net_device_stats *stats = rtl8152_get_stats(tp->netdev);
- struct sk_buff *skb;
u32 ocp_data;
int i;
@@ -1690,17 +2010,12 @@ static void rtl8152_disable(struct r8152 *tp)
ocp_data &= ~RCR_ACPT_ALL;
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
- while ((skb = skb_dequeue(&tp->tx_queue))) {
- dev_kfree_skb(skb);
- stats->tx_dropped++;
- }
+ rtl_drop_queued_tx(tp);
for (i = 0; i < RTL8152_MAX_TX; i++)
usb_kill_urb(tp->tx_info[i].urb);
- ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
- ocp_data |= RXDY_GATED_EN;
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
+ rxdy_gated_en(tp, true);
for (i = 0; i < 1000; i++) {
ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
@@ -1721,18 +2036,209 @@ static void rtl8152_disable(struct r8152 *tp)
rtl8152_nic_reset(tp);
}
+static void r8152_power_cut_en(struct r8152 *tp, bool enable)
+{
+ u32 ocp_data;
+
+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL);
+ if (enable)
+ ocp_data |= POWER_CUT;
+ else
+ ocp_data &= ~POWER_CUT;
+ ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data);
+
+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS);
+ ocp_data &= ~RESUME_INDICATE;
+ ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data);
+}
+
+#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
+
+static u32 __rtl_get_wol(struct r8152 *tp)
+{
+ u32 ocp_data;
+ u32 wolopts = 0;
+
+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5);
+ if (!(ocp_data & LAN_WAKE_EN))
+ return 0;
+
+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34);
+ if (ocp_data & LINK_ON_WAKE_EN)
+ wolopts |= WAKE_PHY;
+
+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5);
+ if (ocp_data & UWF_EN)
+ wolopts |= WAKE_UCAST;
+ if (ocp_data & BWF_EN)
+ wolopts |= WAKE_BCAST;
+ if (ocp_data & MWF_EN)
+ wolopts |= WAKE_MCAST;
+
+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL);
+ if (ocp_data & MAGIC_EN)
+ wolopts |= WAKE_MAGIC;
+
+ return wolopts;
+}
+
+static void __rtl_set_wol(struct r8152 *tp, u32 wolopts)
+{
+ u32 ocp_data;
+
+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
+
+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34);
+ ocp_data &= ~LINK_ON_WAKE_EN;
+ if (wolopts & WAKE_PHY)
+ ocp_data |= LINK_ON_WAKE_EN;
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data);
+
+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5);
+ ocp_data &= ~(UWF_EN | BWF_EN | MWF_EN | LAN_WAKE_EN);
+ if (wolopts & WAKE_UCAST)
+ ocp_data |= UWF_EN;
+ if (wolopts & WAKE_BCAST)
+ ocp_data |= BWF_EN;
+ if (wolopts & WAKE_MCAST)
+ ocp_data |= MWF_EN;
+ if (wolopts & WAKE_ANY)
+ ocp_data |= LAN_WAKE_EN;
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG5, ocp_data);
+
+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
+
+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL);
+ ocp_data &= ~MAGIC_EN;
+ if (wolopts & WAKE_MAGIC)
+ ocp_data |= MAGIC_EN;
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data);
+
+ if (wolopts & WAKE_ANY)
+ device_set_wakeup_enable(&tp->udev->dev, true);
+ else
+ device_set_wakeup_enable(&tp->udev->dev, false);
+}
+
+static void rtl_runtime_suspend_enable(struct r8152 *tp, bool enable)
+{
+ if (enable) {
+ u32 ocp_data;
+
+ __rtl_set_wol(tp, WAKE_ANY);
+
+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
+
+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34);
+ ocp_data |= LINK_OFF_WAKE_EN;
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data);
+
+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
+ } else {
+ __rtl_set_wol(tp, tp->saved_wolopts);
+ }
+}
+
+static void rtl_phy_reset(struct r8152 *tp)
+{
+ u16 data;
+ int i;
+
+ clear_bit(PHY_RESET, &tp->flags);
+
+ data = r8152_mdio_read(tp, MII_BMCR);
+
+ /* don't reset again before the previous one complete */
+ if (data & BMCR_RESET)
+ return;
+
+ data |= BMCR_RESET;
+ r8152_mdio_write(tp, MII_BMCR, data);
+
+ for (i = 0; i < 50; i++) {
+ msleep(20);
+ if ((r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET) == 0)
+ break;
+ }
+}
+
+static void rtl_clear_bp(struct r8152 *tp)
+{
+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_0, 0);
+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_2, 0);
+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_4, 0);
+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_6, 0);
+ ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_0, 0);
+ ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_2, 0);
+ ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_4, 0);
+ ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_6, 0);
+ mdelay(3);
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_BA, 0);
+ ocp_write_word(tp, MCU_TYPE_USB, USB_BP_BA, 0);
+}
+
+static void r8153_clear_bp(struct r8152 *tp)
+{
+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0);
+ ocp_write_byte(tp, MCU_TYPE_USB, USB_BP_EN, 0);
+ rtl_clear_bp(tp);
+}
+
+static void r8153_teredo_off(struct r8152 *tp)
+{
+ u32 ocp_data;
+
+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG);
+ ocp_data &= ~(TEREDO_SEL | TEREDO_RS_EVENT_MASK | OOB_TEREDO_EN);
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data);
+
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_WDT6_CTRL, WDT6_SET_MODE);
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_REALWOW_TIMER, 0);
+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TEREDO_TIMER, 0);
+}
+
+static void r8152b_disable_aldps(struct r8152 *tp)
+{
+ ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA | DIS_SDSAVE);
+ msleep(20);
+}
+
+static inline void r8152b_enable_aldps(struct r8152 *tp)
+{
+ ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS |
+ LINKENA | DIS_SDSAVE);
+}
+
+static void r8152b_hw_phy_cfg(struct r8152 *tp)
+{
+ u16 data;
+
+ data = r8152_mdio_read(tp, MII_BMCR);
+ if (data & BMCR_PDOWN) {
+ data &= ~BMCR_PDOWN;
+ r8152_mdio_write(tp, MII_BMCR, data);
+ }
+
+ r8152b_disable_aldps(tp);
+
+ rtl_clear_bp(tp);
+
+ r8152b_enable_aldps(tp);
+ set_bit(PHY_RESET, &tp->flags);
+}
+
static void r8152b_exit_oob(struct r8152 *tp)
{
- u32 ocp_data;
- int i;
+ u32 ocp_data;
+ int i;
ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
ocp_data &= ~RCR_ACPT_ALL;
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
- ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
- ocp_data |= RXDY_GATED_EN;
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
+ rxdy_gated_en(tp, true);
+ r8153_teredo_off(tp);
+ r8152b_hw_phy_cfg(tp);
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, 0x00);
@@ -1838,10 +2344,6 @@ static void r8152b_enter_oob(struct r8152 *tp)
ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
- ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL);
- ocp_data |= MAGIC_EN;
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data);
-
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
ocp_data |= CPCR_RX_VLAN;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
@@ -1854,36 +2356,26 @@ static void r8152b_enter_oob(struct r8152 *tp)
ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
- ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5, LAN_WAKE_EN);
-
- ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
- ocp_data &= ~RXDY_GATED_EN;
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
+ rxdy_gated_en(tp, false);
ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
ocp_data |= RCR_APM | RCR_AM | RCR_AB;
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
}
-static void r8152b_disable_aldps(struct r8152 *tp)
-{
- ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA | DIS_SDSAVE);
- msleep(20);
-}
-
-static inline void r8152b_enable_aldps(struct r8152 *tp)
-{
- ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS |
- LINKENA | DIS_SDSAVE);
-}
-
static void r8153_hw_phy_cfg(struct r8152 *tp)
{
u32 ocp_data;
u16 data;
ocp_reg_write(tp, OCP_ADC_CFG, CKADSEL_L | ADC_EN | EN_EMI_L);
- r8152_mdio_write(tp, MII_BMCR, BMCR_ANENABLE);
+ data = r8152_mdio_read(tp, MII_BMCR);
+ if (data & BMCR_PDOWN) {
+ data &= ~BMCR_PDOWN;
+ r8152_mdio_write(tp, MII_BMCR, data);
+ }
+
+ r8153_clear_bp(tp);
if (tp->version == RTL_VER_03) {
data = ocp_reg_read(tp, OCP_EEE_CFG);
@@ -1919,9 +2411,11 @@ static void r8153_hw_phy_cfg(struct r8152 *tp)
data = sram_read(tp, SRAM_10M_AMP2);
data |= AMP_DN;
sram_write(tp, SRAM_10M_AMP2, data);
+
+ set_bit(PHY_RESET, &tp->flags);
}
-static void r8153_u1u2en(struct r8152 *tp, int enable)
+static void r8153_u1u2en(struct r8152 *tp, bool enable)
{
u8 u1u2[8];
@@ -1933,7 +2427,7 @@ static void r8153_u1u2en(struct r8152 *tp, int enable)
usb_ocp_write(tp, USB_TOLERANCE, BYTE_EN_SIX_BYTES, sizeof(u1u2), u1u2);
}
-static void r8153_u2p3en(struct r8152 *tp, int enable)
+static void r8153_u2p3en(struct r8152 *tp, bool enable)
{
u32 ocp_data;
@@ -1945,7 +2439,7 @@ static void r8153_u2p3en(struct r8152 *tp, int enable)
ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data);
}
-static void r8153_power_cut_en(struct r8152 *tp, int enable)
+static void r8153_power_cut_en(struct r8152 *tp, bool enable)
{
u32 ocp_data;
@@ -1961,28 +2455,12 @@ static void r8153_power_cut_en(struct r8152 *tp, int enable)
ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data);
}
-static void r8153_teredo_off(struct r8152 *tp)
-{
- u32 ocp_data;
-
- ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG);
- ocp_data &= ~(TEREDO_SEL | TEREDO_RS_EVENT_MASK | OOB_TEREDO_EN);
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data);
-
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_WDT6_CTRL, WDT6_SET_MODE);
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_REALWOW_TIMER, 0);
- ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TEREDO_TIMER, 0);
-}
-
static void r8153_first_init(struct r8152 *tp)
{
u32 ocp_data;
int i;
- ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
- ocp_data |= RXDY_GATED_EN;
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
-
+ rxdy_gated_en(tp, true);
r8153_teredo_off(tp);
ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
@@ -2075,10 +2553,6 @@ static void r8153_enter_oob(struct r8152 *tp)
ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
- ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL);
- ocp_data |= MAGIC_EN;
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data);
-
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG);
ocp_data &= ~TEREDO_WAKE_MASK;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data);
@@ -2095,11 +2569,7 @@ static void r8153_enter_oob(struct r8152 *tp)
ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
- ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5, LAN_WAKE_EN);
-
- ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
- ocp_data &= ~RXDY_GATED_EN;
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
+ rxdy_gated_en(tp, false);
ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
ocp_data |= RCR_APM | RCR_AM | RCR_AB;
@@ -2190,12 +2660,26 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
}
+ if (test_bit(PHY_RESET, &tp->flags))
+ bmcr |= BMCR_RESET;
+
if (tp->mii.supports_gmii)
r8152_mdio_write(tp, MII_CTRL1000, gbcr);
r8152_mdio_write(tp, MII_ADVERTISE, anar);
r8152_mdio_write(tp, MII_BMCR, bmcr);
+ if (test_bit(PHY_RESET, &tp->flags)) {
+ int i;
+
+ clear_bit(PHY_RESET, &tp->flags);
+ for (i = 0; i < 50; i++) {
+ msleep(20);
+ if ((r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET) == 0)
+ break;
+ }
+ }
+
out:
return ret;
@@ -2203,12 +2687,7 @@ out:
static void rtl8152_down(struct r8152 *tp)
{
- u32 ocp_data;
-
- ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL);
- ocp_data &= ~POWER_CUT;
- ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data);
-
+ r8152_power_cut_en(tp, false);
r8152b_disable_aldps(tp);
r8152b_enter_oob(tp);
r8152b_enable_aldps(tp);
@@ -2216,8 +2695,8 @@ static void rtl8152_down(struct r8152 *tp)
static void rtl8153_down(struct r8152 *tp)
{
- r8153_u1u2en(tp, 0);
- r8153_power_cut_en(tp, 0);
+ r8153_u1u2en(tp, false);
+ r8153_power_cut_en(tp, false);
r8153_disable_aldps(tp);
r8153_enter_oob(tp);
r8153_enable_aldps(tp);
@@ -2252,6 +2731,9 @@ static void rtl_work_func_t(struct work_struct *work)
{
struct r8152 *tp = container_of(work, struct r8152, schedule.work);
+ if (usb_autopm_get_interface(tp->intf) < 0)
+ return;
+
if (!test_bit(WORK_ENABLE, &tp->flags))
goto out1;
@@ -2264,8 +2746,17 @@ static void rtl_work_func_t(struct work_struct *work)
if (test_bit(RTL8152_SET_RX_MODE, &tp->flags))
_rtl8152_set_rx_mode(tp->netdev);
+ if (test_bit(SCHEDULE_TASKLET, &tp->flags) &&
+ (tp->speed & LINK_STATUS)) {
+ clear_bit(SCHEDULE_TASKLET, &tp->flags);
+ tasklet_schedule(&tp->tl);
+ }
+
+ if (test_bit(PHY_RESET, &tp->flags))
+ rtl_phy_reset(tp);
+
out1:
- return;
+ usb_autopm_put_interface(tp->intf);
}
static int rtl8152_open(struct net_device *netdev)
@@ -2273,15 +2764,27 @@ static int rtl8152_open(struct net_device *netdev)
struct r8152 *tp = netdev_priv(netdev);
int res = 0;
- res = usb_submit_urb(tp->intr_urb, GFP_KERNEL);
- if (res) {
- if (res == -ENODEV)
- netif_device_detach(tp->netdev);
- netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n",
- res);
- return res;
+ res = alloc_all_mem(tp);
+ if (res)
+ goto out;
+
+ res = usb_autopm_get_interface(tp->intf);
+ if (res < 0) {
+ free_all_mem(tp);
+ goto out;
}
+ /* The WORK_ENABLE may be set when autoresume occurs */
+ if (test_bit(WORK_ENABLE, &tp->flags)) {
+ clear_bit(WORK_ENABLE, &tp->flags);
+ usb_kill_urb(tp->intr_urb);
+ cancel_delayed_work_sync(&tp->schedule);
+ if (tp->speed & LINK_STATUS)
+ tp->rtl_ops.disable(tp);
+ }
+
+ tp->rtl_ops.up(tp);
+
rtl8152_set_speed(tp, AUTONEG_ENABLE,
tp->mii.supports_gmii ? SPEED_1000 : SPEED_100,
DUPLEX_FULL);
@@ -2290,6 +2793,18 @@ static int rtl8152_open(struct net_device *netdev)
netif_start_queue(netdev);
set_bit(WORK_ENABLE, &tp->flags);
+ res = usb_submit_urb(tp->intr_urb, GFP_KERNEL);
+ if (res) {
+ if (res == -ENODEV)
+ netif_device_detach(tp->netdev);
+ netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n",
+ res);
+ free_all_mem(tp);
+ }
+
+ usb_autopm_put_interface(tp->intf);
+
+out:
return res;
}
@@ -2298,37 +2813,34 @@ static int rtl8152_close(struct net_device *netdev)
struct r8152 *tp = netdev_priv(netdev);
int res = 0;
- usb_kill_urb(tp->intr_urb);
clear_bit(WORK_ENABLE, &tp->flags);
+ usb_kill_urb(tp->intr_urb);
cancel_delayed_work_sync(&tp->schedule);
netif_stop_queue(netdev);
- tasklet_disable(&tp->tl);
- tp->rtl_ops.disable(tp);
- tasklet_enable(&tp->tl);
- return res;
-}
+ res = usb_autopm_get_interface(tp->intf);
+ if (res < 0) {
+ rtl_drop_queued_tx(tp);
+ } else {
+ /*
+ * The autosuspend may have been enabled and wouldn't
+ * be disable when autoresume occurs, because the
+ * netif_running() would be false.
+ */
+ if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
+ rtl_runtime_suspend_enable(tp, false);
+ clear_bit(SELECTIVE_SUSPEND, &tp->flags);
+ }
-static void rtl_clear_bp(struct r8152 *tp)
-{
- ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_0, 0);
- ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_2, 0);
- ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_4, 0);
- ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_6, 0);
- ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_0, 0);
- ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_2, 0);
- ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_4, 0);
- ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_6, 0);
- mdelay(3);
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_BA, 0);
- ocp_write_word(tp, MCU_TYPE_USB, USB_BP_BA, 0);
-}
+ tasklet_disable(&tp->tl);
+ tp->rtl_ops.down(tp);
+ tasklet_enable(&tp->tl);
+ usb_autopm_put_interface(tp->intf);
+ }
-static void r8153_clear_bp(struct r8152 *tp)
-{
- ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0);
- ocp_write_byte(tp, MCU_TYPE_USB, USB_BP_EN, 0);
- rtl_clear_bp(tp);
+ free_all_mem(tp);
+
+ return res;
}
static void r8152b_enable_eee(struct r8152 *tp)
@@ -2379,18 +2891,18 @@ static void r8152b_enable_fc(struct r8152 *tp)
r8152_mdio_write(tp, MII_ADVERTISE, anar);
}
-static void r8152b_hw_phy_cfg(struct r8152 *tp)
+static void rtl_tally_reset(struct r8152 *tp)
{
- r8152_mdio_write(tp, MII_BMCR, BMCR_ANENABLE);
- r8152b_disable_aldps(tp);
+ u32 ocp_data;
+
+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY);
+ ocp_data |= TALLY_RESET;
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data);
}
static void r8152b_init(struct r8152 *tp)
{
u32 ocp_data;
- int i;
-
- rtl_clear_bp(tp);
if (tp->version == RTL_VER_01) {
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
@@ -2398,17 +2910,7 @@ static void r8152b_init(struct r8152 *tp)
ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data);
}
- r8152b_hw_phy_cfg(tp);
-
- ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL);
- ocp_data &= ~POWER_CUT;
- ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data);
-
- ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS);
- ocp_data &= ~RESUME_INDICATE;
- ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data);
-
- r8152b_exit_oob(tp);
+ r8152_power_cut_en(tp, false);
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
ocp_data |= TX_10M_IDLE_EN | PFM_PWM_SWITCH;
@@ -2424,14 +2926,7 @@ static void r8152b_init(struct r8152 *tp)
r8152b_enable_eee(tp);
r8152b_enable_aldps(tp);
r8152b_enable_fc(tp);
-
- r8152_mdio_write(tp, MII_BMCR, BMCR_RESET | BMCR_ANENABLE |
- BMCR_ANRESTART);
- for (i = 0; i < 100; i++) {
- udelay(100);
- if (!(r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET))
- break;
- }
+ rtl_tally_reset(tp);
/* enable rx aggregation */
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
@@ -2444,7 +2939,7 @@ static void r8153_init(struct r8152 *tp)
u32 ocp_data;
int i;
- r8153_u1u2en(tp, 0);
+ r8153_u1u2en(tp, false);
for (i = 0; i < 500; i++) {
if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
@@ -2460,14 +2955,12 @@ static void r8153_init(struct r8152 *tp)
msleep(20);
}
- r8153_u2p3en(tp, 0);
+ r8153_u2p3en(tp, false);
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL);
ocp_data &= ~TIMER11_EN;
ocp_write_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL, ocp_data);
- r8153_clear_bp(tp);
-
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
ocp_data &= ~LED_MODE_MASK;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data);
@@ -2485,10 +2978,8 @@ static void r8153_init(struct r8152 *tp)
ocp_data |= SEN_VAL_NORMAL | SEL_RXIDLE;
ocp_write_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2, ocp_data);
- r8153_power_cut_en(tp, 0);
- r8153_u1u2en(tp, 1);
-
- r8153_first_init(tp);
+ r8153_power_cut_en(tp, false);
+ r8153_u1u2en(tp, true);
ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, ALDPS_SPDWN_RATIO);
ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, EEE_SPDWN_RATIO);
@@ -2503,26 +2994,31 @@ static void r8153_init(struct r8152 *tp)
r8153_enable_eee(tp);
r8153_enable_aldps(tp);
r8152b_enable_fc(tp);
-
- r8152_mdio_write(tp, MII_BMCR, BMCR_RESET | BMCR_ANENABLE |
- BMCR_ANRESTART);
+ rtl_tally_reset(tp);
}
static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
{
struct r8152 *tp = usb_get_intfdata(intf);
- netif_device_detach(tp->netdev);
+ if (PMSG_IS_AUTO(message))
+ set_bit(SELECTIVE_SUSPEND, &tp->flags);
+ else
+ netif_device_detach(tp->netdev);
if (netif_running(tp->netdev)) {
clear_bit(WORK_ENABLE, &tp->flags);
usb_kill_urb(tp->intr_urb);
cancel_delayed_work_sync(&tp->schedule);
- tasklet_disable(&tp->tl);
+ if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
+ rtl_runtime_suspend_enable(tp, true);
+ } else {
+ tasklet_disable(&tp->tl);
+ tp->rtl_ops.down(tp);
+ tasklet_enable(&tp->tl);
+ }
}
- tp->rtl_ops.down(tp);
-
return 0;
}
@@ -2530,22 +3026,77 @@ static int rtl8152_resume(struct usb_interface *intf)
{
struct r8152 *tp = usb_get_intfdata(intf);
- tp->rtl_ops.init(tp);
- netif_device_attach(tp->netdev);
+ if (!test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
+ tp->rtl_ops.init(tp);
+ netif_device_attach(tp->netdev);
+ }
+
if (netif_running(tp->netdev)) {
- rtl8152_set_speed(tp, AUTONEG_ENABLE,
+ if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
+ rtl_runtime_suspend_enable(tp, false);
+ clear_bit(SELECTIVE_SUSPEND, &tp->flags);
+ if (tp->speed & LINK_STATUS)
+ tp->rtl_ops.disable(tp);
+ } else {
+ tp->rtl_ops.up(tp);
+ rtl8152_set_speed(tp, AUTONEG_ENABLE,
tp->mii.supports_gmii ? SPEED_1000 : SPEED_100,
DUPLEX_FULL);
+ }
tp->speed = 0;
netif_carrier_off(tp->netdev);
set_bit(WORK_ENABLE, &tp->flags);
usb_submit_urb(tp->intr_urb, GFP_KERNEL);
- tasklet_enable(&tp->tl);
}
return 0;
}
+static void rtl8152_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct r8152 *tp = netdev_priv(dev);
+
+ if (usb_autopm_get_interface(tp->intf) < 0)
+ return;
+
+ wol->supported = WAKE_ANY;
+ wol->wolopts = __rtl_get_wol(tp);
+
+ usb_autopm_put_interface(tp->intf);
+}
+
+static int rtl8152_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct r8152 *tp = netdev_priv(dev);
+ int ret;
+
+ ret = usb_autopm_get_interface(tp->intf);
+ if (ret < 0)
+ goto out_set_wol;
+
+ __rtl_set_wol(tp, wol->wolopts);
+ tp->saved_wolopts = wol->wolopts & WAKE_ANY;
+
+ usb_autopm_put_interface(tp->intf);
+
+out_set_wol:
+ return ret;
+}
+
+static u32 rtl8152_get_msglevel(struct net_device *dev)
+{
+ struct r8152 *tp = netdev_priv(dev);
+
+ return tp->msg_enable;
+}
+
+static void rtl8152_set_msglevel(struct net_device *dev, u32 value)
+{
+ struct r8152 *tp = netdev_priv(dev);
+
+ tp->msg_enable = value;
+}
+
static void rtl8152_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *info)
{
@@ -2570,8 +3121,76 @@ int rtl8152_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
static int rtl8152_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct r8152 *tp = netdev_priv(dev);
+ int ret;
+
+ ret = usb_autopm_get_interface(tp->intf);
+ if (ret < 0)
+ goto out;
+
+ ret = rtl8152_set_speed(tp, cmd->autoneg, cmd->speed, cmd->duplex);
+
+ usb_autopm_put_interface(tp->intf);
- return rtl8152_set_speed(tp, cmd->autoneg, cmd->speed, cmd->duplex);
+out:
+ return ret;
+}
+
+static const char rtl8152_gstrings[][ETH_GSTRING_LEN] = {
+ "tx_packets",
+ "rx_packets",
+ "tx_errors",
+ "rx_errors",
+ "rx_missed",
+ "align_errors",
+ "tx_single_collisions",
+ "tx_multi_collisions",
+ "rx_unicast",
+ "rx_broadcast",
+ "rx_multicast",
+ "tx_aborted",
+ "tx_underrun",
+};
+
+static int rtl8152_get_sset_count(struct net_device *dev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(rtl8152_gstrings);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void rtl8152_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct r8152 *tp = netdev_priv(dev);
+ struct tally_counter tally;
+
+ generic_ocp_read(tp, PLA_TALLYCNT, sizeof(tally), &tally, MCU_TYPE_PLA);
+
+ data[0] = le64_to_cpu(tally.tx_packets);
+ data[1] = le64_to_cpu(tally.rx_packets);
+ data[2] = le64_to_cpu(tally.tx_errors);
+ data[3] = le32_to_cpu(tally.rx_errors);
+ data[4] = le16_to_cpu(tally.rx_missed);
+ data[5] = le16_to_cpu(tally.align_errors);
+ data[6] = le32_to_cpu(tally.tx_one_collision);
+ data[7] = le32_to_cpu(tally.tx_multi_collision);
+ data[8] = le64_to_cpu(tally.rx_unicast);
+ data[9] = le64_to_cpu(tally.rx_broadcast);
+ data[10] = le32_to_cpu(tally.rx_multicast);
+ data[11] = le16_to_cpu(tally.tx_aborted);
+ data[12] = le16_to_cpu(tally.tx_underun);
+}
+
+static void rtl8152_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+ switch (stringset) {
+ case ETH_SS_STATS:
+ memcpy(data, *rtl8152_gstrings, sizeof(rtl8152_gstrings));
+ break;
+ }
}
static struct ethtool_ops ops = {
@@ -2579,13 +3198,24 @@ static struct ethtool_ops ops = {
.get_settings = rtl8152_get_settings,
.set_settings = rtl8152_set_settings,
.get_link = ethtool_op_get_link,
+ .get_msglevel = rtl8152_get_msglevel,
+ .set_msglevel = rtl8152_set_msglevel,
+ .get_wol = rtl8152_get_wol,
+ .set_wol = rtl8152_set_wol,
+ .get_strings = rtl8152_get_strings,
+ .get_sset_count = rtl8152_get_sset_count,
+ .get_ethtool_stats = rtl8152_get_ethtool_stats,
};
static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
{
struct r8152 *tp = netdev_priv(netdev);
struct mii_ioctl_data *data = if_mii(rq);
- int res = 0;
+ int res;
+
+ res = usb_autopm_get_interface(tp->intf);
+ if (res < 0)
+ goto out;
switch (cmd) {
case SIOCGMIIPHY:
@@ -2608,6 +3238,9 @@ static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
res = -EOPNOTSUPP;
}
+ usb_autopm_put_interface(tp->intf);
+
+out:
return res;
}
@@ -2660,22 +3293,13 @@ static void r8152b_get_version(struct r8152 *tp)
static void rtl8152_unload(struct r8152 *tp)
{
- u32 ocp_data;
-
- if (tp->version != RTL_VER_01) {
- ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL);
- ocp_data |= POWER_CUT;
- ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data);
- }
-
- ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS);
- ocp_data &= ~RESUME_INDICATE;
- ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data);
+ if (tp->version != RTL_VER_01)
+ r8152_power_cut_en(tp, true);
}
static void rtl8153_unload(struct r8152 *tp)
{
- r8153_power_cut_en(tp, 1);
+ r8153_power_cut_en(tp, true);
}
static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id)
@@ -2690,6 +3314,7 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id)
ops->init = r8152b_init;
ops->enable = rtl8152_enable;
ops->disable = rtl8152_disable;
+ ops->up = r8152b_exit_oob;
ops->down = rtl8152_down;
ops->unload = rtl8152_unload;
ret = 0;
@@ -2698,6 +3323,7 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id)
ops->init = r8153_init;
ops->enable = rtl8153_enable;
ops->disable = rtl8152_disable;
+ ops->up = r8153_first_init;
ops->down = rtl8153_down;
ops->unload = rtl8153_unload;
ret = 0;
@@ -2713,6 +3339,7 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id)
ops->init = r8153_init;
ops->enable = rtl8153_enable;
ops->disable = rtl8152_disable;
+ ops->up = r8153_first_init;
ops->down = rtl8153_down;
ops->unload = rtl8153_unload;
ret = 0;
@@ -2740,6 +3367,12 @@ static int rtl8152_probe(struct usb_interface *intf,
struct net_device *netdev;
int ret;
+ if (udev->actconfig->desc.bConfigurationValue != 1) {
+ usb_driver_set_configuration(udev, 1);
+ return -ENODEV;
+ }
+
+ usb_reset_device(udev);
netdev = alloc_etherdev(sizeof(struct r8152));
if (!netdev) {
dev_err(&intf->dev, "Out of memory\n");
@@ -2764,9 +3397,15 @@ static int rtl8152_probe(struct usb_interface *intf,
netdev->netdev_ops = &rtl8152_netdev_ops;
netdev->watchdog_timeo = RTL8152_TX_TIMEOUT;
- netdev->features |= NETIF_F_IP_CSUM;
- netdev->hw_features = NETIF_F_IP_CSUM;
+ netdev->features |= NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG |
+ NETIF_F_TSO | NETIF_F_FRAGLIST | NETIF_F_IPV6_CSUM |
+ NETIF_F_TSO6;
+ netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG |
+ NETIF_F_TSO | NETIF_F_FRAGLIST |
+ NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
+
SET_ETHTOOL_OPS(netdev, &ops);
+ netif_set_gso_max_size(netdev, RTL_LIMITED_TSO_SIZE);
tp->mii.dev = netdev;
tp->mii.mdio_read = read_mii_word;
@@ -2776,14 +3415,12 @@ static int rtl8152_probe(struct usb_interface *intf,
tp->mii.phy_id = R8152_PHY_ID;
tp->mii.supports_gmii = 0;
+ intf->needs_remote_wakeup = 1;
+
r8152b_get_version(tp);
tp->rtl_ops.init(tp);
set_ethernet_addr(tp);
- ret = alloc_all_mem(tp);
- if (ret)
- goto out;
-
usb_set_intfdata(intf, tp);
ret = register_netdev(netdev);
@@ -2792,6 +3429,12 @@ static int rtl8152_probe(struct usb_interface *intf,
goto out1;
}
+ tp->saved_wolopts = __rtl_get_wol(tp);
+ if (tp->saved_wolopts)
+ device_set_wakeup_enable(&udev->dev, true);
+ else
+ device_set_wakeup_enable(&udev->dev, false);
+
netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION);
return 0;
@@ -2813,16 +3456,15 @@ static void rtl8152_disconnect(struct usb_interface *intf)
tasklet_kill(&tp->tl);
unregister_netdev(tp->netdev);
tp->rtl_ops.unload(tp);
- free_all_mem(tp);
free_netdev(tp->netdev);
}
}
/* table of devices that work with this driver */
static struct usb_device_id rtl8152_table[] = {
- {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)},
- {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8153)},
- {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG)},
+ {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)},
+ {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8153)},
+ {USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG)},
{}
};
@@ -2836,6 +3478,8 @@ static struct usb_driver rtl8152_driver = {
.suspend = rtl8152_suspend,
.resume = rtl8152_resume,
.reset_resume = rtl8152_resume,
+ .supports_autosuspend = 1,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(rtl8152_driver);
diff --git a/drivers/net/usb/r815x.c b/drivers/net/usb/r815x.c
deleted file mode 100644
index f0a8791b7636..000000000000
--- a/drivers/net/usb/r815x.c
+++ /dev/null
@@ -1,248 +0,0 @@
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/mii.h>
-#include <linux/usb.h>
-#include <linux/usb/cdc.h>
-#include <linux/usb/usbnet.h>
-
-#define RTL815x_REQT_READ 0xc0
-#define RTL815x_REQT_WRITE 0x40
-#define RTL815x_REQ_GET_REGS 0x05
-#define RTL815x_REQ_SET_REGS 0x05
-
-#define MCU_TYPE_PLA 0x0100
-#define OCP_BASE 0xe86c
-#define BASE_MII 0xa400
-
-#define BYTE_EN_DWORD 0xff
-#define BYTE_EN_WORD 0x33
-#define BYTE_EN_BYTE 0x11
-
-#define R815x_PHY_ID 32
-#define REALTEK_VENDOR_ID 0x0bda
-
-
-static int pla_read_word(struct usb_device *udev, u16 index)
-{
- int ret;
- u8 shift = index & 2;
- __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, tmp, sizeof(*tmp), 500);
- if (ret < 0)
- goto out2;
-
- ret = __le32_to_cpu(*tmp);
- ret >>= (shift * 8);
- ret &= 0xffff;
-
-out2:
- kfree(tmp);
- return ret;
-}
-
-static int pla_write_word(struct usb_device *udev, u16 index, u32 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) {
- byen <<= shift;
- mask <<= (shift * 8);
- data <<= (shift * 8);
- index &= ~3;
- }
-
- ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
- index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
- if (ret < 0)
- goto out3;
-
- 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, tmp, sizeof(*tmp),
- 500);
-
-out3:
- kfree(tmp);
- return ret;
-}
-
-static int ocp_reg_read(struct usbnet *dev, u16 addr)
-{
- u16 ocp_base, ocp_index;
- int ret;
-
- ocp_base = addr & 0xf000;
- ret = pla_write_word(dev->udev, OCP_BASE, ocp_base);
- if (ret < 0)
- goto out;
-
- ocp_index = (addr & 0x0fff) | 0xb000;
- ret = pla_read_word(dev->udev, ocp_index);
-
-out:
- return ret;
-}
-
-static int ocp_reg_write(struct usbnet *dev, u16 addr, u16 data)
-{
- u16 ocp_base, ocp_index;
- int ret;
-
- ocp_base = addr & 0xf000;
- ret = pla_write_word(dev->udev, OCP_BASE, ocp_base);
- if (ret < 0)
- goto out1;
-
- ocp_index = (addr & 0x0fff) | 0xb000;
- ret = pla_write_word(dev->udev, ocp_index, data);
-
-out1:
- return ret;
-}
-
-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;
-
- 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
-void r815x_mdio_write(struct net_device *netdev, int phy_id, int reg, int val)
-{
- struct usbnet *dev = netdev_priv(netdev);
-
- 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)
-{
- int status;
-
- status = usbnet_cdc_bind(dev, intf);
- if (status < 0)
- return status;
-
- dev->mii.dev = dev->net;
- dev->mii.mdio_read = r815x_mdio_read;
- dev->mii.mdio_write = r815x_mdio_write;
- dev->mii.phy_id_mask = 0x3f;
- dev->mii.reg_num_mask = 0x1f;
- dev->mii.phy_id = R815x_PHY_ID;
- dev->mii.supports_gmii = 1;
-
- return status;
-}
-
-static int r8152_bind(struct usbnet *dev, struct usb_interface *intf)
-{
- int status;
-
- status = usbnet_cdc_bind(dev, intf);
- if (status < 0)
- return status;
-
- dev->mii.dev = dev->net;
- dev->mii.mdio_read = r815x_mdio_read;
- dev->mii.mdio_write = r815x_mdio_write;
- dev->mii.phy_id_mask = 0x3f;
- dev->mii.reg_num_mask = 0x1f;
- dev->mii.phy_id = R815x_PHY_ID;
- dev->mii.supports_gmii = 0;
-
- return status;
-}
-
-static const struct driver_info r8152_info = {
- .description = "RTL8152 ECM Device",
- .flags = FLAG_ETHER | FLAG_POINTTOPOINT,
- .bind = r8152_bind,
- .unbind = usbnet_cdc_unbind,
- .status = usbnet_cdc_status,
- .manage_power = usbnet_manage_power,
-};
-
-static const struct driver_info r8153_info = {
- .description = "RTL8153 ECM Device",
- .flags = FLAG_ETHER | FLAG_POINTTOPOINT,
- .bind = r8153_bind,
- .unbind = usbnet_cdc_unbind,
- .status = usbnet_cdc_status,
- .manage_power = usbnet_manage_power,
-};
-
-static const struct usb_device_id products[] = {
-{
- USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8152, USB_CLASS_COMM,
- USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
- .driver_info = (unsigned long) &r8152_info,
-},
-
-{
- USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8153, USB_CLASS_COMM,
- USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
- .driver_info = (unsigned long) &r8153_info,
-},
-
- { }, /* END */
-};
-MODULE_DEVICE_TABLE(usb, products);
-
-static struct usb_driver r815x_driver = {
- .name = "r815x",
- .id_table = products,
- .probe = usbnet_probe,
- .disconnect = usbnet_disconnect,
- .suspend = usbnet_suspend,
- .resume = usbnet_resume,
- .reset_resume = usbnet_resume,
- .supports_autosuspend = 1,
- .disable_hub_initiated_lpm = 1,
-};
-
-module_usb_driver(r815x_driver);
-
-MODULE_AUTHOR("Hayes Wang");
-MODULE_DESCRIPTION("Realtek USB ECM device");
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index a48bc0f20c1a..524a47a28120 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -492,6 +492,10 @@ EXPORT_SYMBOL_GPL(rndis_unbind);
*/
int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
+ /* This check is no longer done by usbnet */
+ if (skb->len < dev->net->hard_header_len)
+ return 0;
+
/* peripheral may have batched packets to us... */
while (likely(skb->len)) {
struct rndis_data_hdr *hdr = (void *)skb->data;
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index f17b9e02dd34..d9e7892262fa 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -2106,6 +2106,10 @@ static void smsc75xx_rx_csum_offload(struct usbnet *dev, struct sk_buff *skb,
static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
+ /* This check is no longer done by usbnet */
+ if (skb->len < dev->net->hard_header_len)
+ return 0;
+
while (skb->len > 0) {
u32 rx_cmd_a, rx_cmd_b, align_count, size;
struct sk_buff *ax_skb;
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 8dd54a0f7b29..424db65e4396 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -1723,6 +1723,10 @@ static void smsc95xx_rx_csum_offload(struct sk_buff *skb)
static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
+ /* This check is no longer done by usbnet */
+ if (skb->len < dev->net->hard_header_len)
+ return 0;
+
while (skb->len > 0) {
u32 header, align_count;
struct sk_buff *ax_skb;
diff --git a/drivers/net/usb/sr9800.c b/drivers/net/usb/sr9800.c
new file mode 100644
index 000000000000..b94a0fbb8b3b
--- /dev/null
+++ b/drivers/net/usb/sr9800.c
@@ -0,0 +1,874 @@
+/* CoreChip-sz SR9800 one chip USB 2.0 Ethernet Devices
+ *
+ * Author : Liu Junliang <liujunliang_ljl@163.com>
+ *
+ * Based on asix_common.c, asix_devices.c
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.*
+ */
+
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/crc32.h>
+#include <linux/usb/usbnet.h>
+#include <linux/slab.h>
+#include <linux/if_vlan.h>
+
+#include "sr9800.h"
+
+static int sr_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+ u16 size, void *data)
+{
+ int err;
+
+ err = usbnet_read_cmd(dev, cmd, SR_REQ_RD_REG, value, index,
+ data, size);
+ if ((err != size) && (err >= 0))
+ err = -EINVAL;
+
+ return err;
+}
+
+static int sr_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+ u16 size, void *data)
+{
+ int err;
+
+ err = usbnet_write_cmd(dev, cmd, SR_REQ_WR_REG, value, index,
+ data, size);
+ if ((err != size) && (err >= 0))
+ err = -EINVAL;
+
+ return err;
+}
+
+static void
+sr_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+ u16 size, void *data)
+{
+ usbnet_write_cmd_async(dev, cmd, SR_REQ_WR_REG, value, index, data,
+ size);
+}
+
+static int sr_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+ int offset = 0;
+
+ /* This check is no longer done by usbnet */
+ if (skb->len < dev->net->hard_header_len)
+ return 0;
+
+ while (offset + sizeof(u32) < skb->len) {
+ struct sk_buff *sr_skb;
+ u16 size;
+ u32 header = get_unaligned_le32(skb->data + offset);
+
+ offset += sizeof(u32);
+ /* get the packet length */
+ size = (u16) (header & 0x7ff);
+ if (size != ((~header >> 16) & 0x07ff)) {
+ netdev_err(dev->net, "%s : Bad Header Length\n",
+ __func__);
+ return 0;
+ }
+
+ if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) ||
+ (size + offset > skb->len)) {
+ netdev_err(dev->net, "%s : Bad RX Length %d\n",
+ __func__, size);
+ return 0;
+ }
+ sr_skb = netdev_alloc_skb_ip_align(dev->net, size);
+ if (!sr_skb)
+ return 0;
+
+ skb_put(sr_skb, size);
+ memcpy(sr_skb->data, skb->data + offset, size);
+ usbnet_skb_return(dev, sr_skb);
+
+ offset += (size + 1) & 0xfffe;
+ }
+
+ if (skb->len != offset) {
+ netdev_err(dev->net, "%s : Bad SKB Length %d\n", __func__,
+ skb->len);
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct sk_buff *sr_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
+ gfp_t flags)
+{
+ int headroom = skb_headroom(skb);
+ int tailroom = skb_tailroom(skb);
+ u32 padbytes = 0xffff0000;
+ u32 packet_len;
+ int padlen;
+
+ padlen = ((skb->len + 4) % (dev->maxpacket - 1)) ? 0 : 4;
+
+ if ((!skb_cloned(skb)) && ((headroom + tailroom) >= (4 + padlen))) {
+ if ((headroom < 4) || (tailroom < padlen)) {
+ skb->data = memmove(skb->head + 4, skb->data,
+ skb->len);
+ skb_set_tail_pointer(skb, skb->len);
+ }
+ } else {
+ struct sk_buff *skb2;
+ skb2 = skb_copy_expand(skb, 4, padlen, flags);
+ dev_kfree_skb_any(skb);
+ skb = skb2;
+ if (!skb)
+ return NULL;
+ }
+
+ skb_push(skb, 4);
+ packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
+ cpu_to_le32s(&packet_len);
+ skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len));
+
+ if (padlen) {
+ cpu_to_le32s(&padbytes);
+ memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes));
+ skb_put(skb, sizeof(padbytes));
+ }
+
+ return skb;
+}
+
+static void sr_status(struct usbnet *dev, struct urb *urb)
+{
+ struct sr9800_int_data *event;
+ int link;
+
+ if (urb->actual_length < 8)
+ return;
+
+ event = urb->transfer_buffer;
+ link = event->link & 0x01;
+ if (netif_carrier_ok(dev->net) != link) {
+ usbnet_link_change(dev, link, 1);
+ netdev_dbg(dev->net, "Link Status is: %d\n", link);
+ }
+
+ return;
+}
+
+static inline int sr_set_sw_mii(struct usbnet *dev)
+{
+ int ret;
+
+ ret = sr_write_cmd(dev, SR_CMD_SET_SW_MII, 0x0000, 0, 0, NULL);
+ if (ret < 0)
+ netdev_err(dev->net, "Failed to enable software MII access\n");
+ return ret;
+}
+
+static inline int sr_set_hw_mii(struct usbnet *dev)
+{
+ int ret;
+
+ ret = sr_write_cmd(dev, SR_CMD_SET_HW_MII, 0x0000, 0, 0, NULL);
+ if (ret < 0)
+ netdev_err(dev->net, "Failed to enable hardware MII access\n");
+ return ret;
+}
+
+static inline int sr_get_phy_addr(struct usbnet *dev)
+{
+ u8 buf[2];
+ int ret;
+
+ ret = sr_read_cmd(dev, SR_CMD_READ_PHY_ID, 0, 0, 2, buf);
+ if (ret < 0) {
+ netdev_err(dev->net, "%s : Error reading PHYID register:%02x\n",
+ __func__, ret);
+ goto out;
+ }
+ netdev_dbg(dev->net, "%s : returning 0x%04x\n", __func__,
+ *((__le16 *)buf));
+
+ ret = buf[1];
+
+out:
+ return ret;
+}
+
+static int sr_sw_reset(struct usbnet *dev, u8 flags)
+{
+ int ret;
+
+ ret = sr_write_cmd(dev, SR_CMD_SW_RESET, flags, 0, 0, NULL);
+ if (ret < 0)
+ netdev_err(dev->net, "Failed to send software reset:%02x\n",
+ ret);
+
+ return ret;
+}
+
+static u16 sr_read_rx_ctl(struct usbnet *dev)
+{
+ __le16 v;
+ int ret;
+
+ ret = sr_read_cmd(dev, SR_CMD_READ_RX_CTL, 0, 0, 2, &v);
+ if (ret < 0) {
+ netdev_err(dev->net, "Error reading RX_CTL register:%02x\n",
+ ret);
+ goto out;
+ }
+
+ ret = le16_to_cpu(v);
+out:
+ return ret;
+}
+
+static int sr_write_rx_ctl(struct usbnet *dev, u16 mode)
+{
+ int ret;
+
+ netdev_dbg(dev->net, "%s : mode = 0x%04x\n", __func__, mode);
+ ret = sr_write_cmd(dev, SR_CMD_WRITE_RX_CTL, mode, 0, 0, NULL);
+ if (ret < 0)
+ netdev_err(dev->net,
+ "Failed to write RX_CTL mode to 0x%04x:%02x\n",
+ mode, ret);
+
+ return ret;
+}
+
+static u16 sr_read_medium_status(struct usbnet *dev)
+{
+ __le16 v;
+ int ret;
+
+ ret = sr_read_cmd(dev, SR_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v);
+ if (ret < 0) {
+ netdev_err(dev->net,
+ "Error reading Medium Status register:%02x\n", ret);
+ return ret; /* TODO: callers not checking for error ret */
+ }
+
+ return le16_to_cpu(v);
+}
+
+static int sr_write_medium_mode(struct usbnet *dev, u16 mode)
+{
+ int ret;
+
+ netdev_dbg(dev->net, "%s : mode = 0x%04x\n", __func__, mode);
+ ret = sr_write_cmd(dev, SR_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
+ if (ret < 0)
+ netdev_err(dev->net,
+ "Failed to write Medium Mode mode to 0x%04x:%02x\n",
+ mode, ret);
+ return ret;
+}
+
+static int sr_write_gpio(struct usbnet *dev, u16 value, int sleep)
+{
+ int ret;
+
+ netdev_dbg(dev->net, "%s : value = 0x%04x\n", __func__, value);
+ ret = sr_write_cmd(dev, SR_CMD_WRITE_GPIOS, value, 0, 0, NULL);
+ if (ret < 0)
+ netdev_err(dev->net, "Failed to write GPIO value 0x%04x:%02x\n",
+ value, ret);
+ if (sleep)
+ msleep(sleep);
+
+ return ret;
+}
+
+/* SR9800 have a 16-bit RX_CTL value */
+static void sr_set_multicast(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct sr_data *data = (struct sr_data *)&dev->data;
+ u16 rx_ctl = SR_DEFAULT_RX_CTL;
+
+ if (net->flags & IFF_PROMISC) {
+ rx_ctl |= SR_RX_CTL_PRO;
+ } else if (net->flags & IFF_ALLMULTI ||
+ netdev_mc_count(net) > SR_MAX_MCAST) {
+ rx_ctl |= SR_RX_CTL_AMALL;
+ } else if (netdev_mc_empty(net)) {
+ /* just broadcast and directed */
+ } else {
+ /* We use the 20 byte dev->data
+ * for our 8 byte filter buffer
+ * to avoid allocating memory that
+ * is tricky to free later
+ */
+ struct netdev_hw_addr *ha;
+ u32 crc_bits;
+
+ memset(data->multi_filter, 0, SR_MCAST_FILTER_SIZE);
+
+ /* Build the multicast hash filter. */
+ netdev_for_each_mc_addr(ha, net) {
+ crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
+ data->multi_filter[crc_bits >> 3] |=
+ 1 << (crc_bits & 7);
+ }
+
+ sr_write_cmd_async(dev, SR_CMD_WRITE_MULTI_FILTER, 0, 0,
+ SR_MCAST_FILTER_SIZE, data->multi_filter);
+
+ rx_ctl |= SR_RX_CTL_AM;
+ }
+
+ sr_write_cmd_async(dev, SR_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
+}
+
+static int sr_mdio_read(struct net_device *net, int phy_id, int loc)
+{
+ struct usbnet *dev = netdev_priv(net);
+ __le16 res;
+
+ mutex_lock(&dev->phy_mutex);
+ sr_set_sw_mii(dev);
+ sr_read_cmd(dev, SR_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, &res);
+ sr_set_hw_mii(dev);
+ mutex_unlock(&dev->phy_mutex);
+
+ netdev_dbg(dev->net,
+ "%s : phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", __func__,
+ phy_id, loc, le16_to_cpu(res));
+
+ return le16_to_cpu(res);
+}
+
+static void
+sr_mdio_write(struct net_device *net, int phy_id, int loc, int val)
+{
+ struct usbnet *dev = netdev_priv(net);
+ __le16 res = cpu_to_le16(val);
+
+ netdev_dbg(dev->net,
+ "%s : phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", __func__,
+ phy_id, loc, val);
+ mutex_lock(&dev->phy_mutex);
+ sr_set_sw_mii(dev);
+ sr_write_cmd(dev, SR_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res);
+ sr_set_hw_mii(dev);
+ mutex_unlock(&dev->phy_mutex);
+}
+
+/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */
+static u32 sr_get_phyid(struct usbnet *dev)
+{
+ int phy_reg;
+ u32 phy_id;
+ int i;
+
+ /* Poll for the rare case the FW or phy isn't ready yet. */
+ for (i = 0; i < 100; i++) {
+ phy_reg = sr_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1);
+ if (phy_reg != 0 && phy_reg != 0xFFFF)
+ break;
+ mdelay(1);
+ }
+
+ if (phy_reg <= 0 || phy_reg == 0xFFFF)
+ return 0;
+
+ phy_id = (phy_reg & 0xffff) << 16;
+
+ phy_reg = sr_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2);
+ if (phy_reg < 0)
+ return 0;
+
+ phy_id |= (phy_reg & 0xffff);
+
+ return phy_id;
+}
+
+static void
+sr_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
+{
+ struct usbnet *dev = netdev_priv(net);
+ u8 opt;
+
+ if (sr_read_cmd(dev, SR_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) {
+ wolinfo->supported = 0;
+ wolinfo->wolopts = 0;
+ return;
+ }
+ wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
+ wolinfo->wolopts = 0;
+ if (opt & SR_MONITOR_LINK)
+ wolinfo->wolopts |= WAKE_PHY;
+ if (opt & SR_MONITOR_MAGIC)
+ wolinfo->wolopts |= WAKE_MAGIC;
+}
+
+static int
+sr_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
+{
+ struct usbnet *dev = netdev_priv(net);
+ u8 opt = 0;
+
+ if (wolinfo->wolopts & WAKE_PHY)
+ opt |= SR_MONITOR_LINK;
+ if (wolinfo->wolopts & WAKE_MAGIC)
+ opt |= SR_MONITOR_MAGIC;
+
+ if (sr_write_cmd(dev, SR_CMD_WRITE_MONITOR_MODE,
+ opt, 0, 0, NULL) < 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int sr_get_eeprom_len(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct sr_data *data = (struct sr_data *)&dev->data;
+
+ return data->eeprom_len;
+}
+
+static int sr_get_eeprom(struct net_device *net,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ struct usbnet *dev = netdev_priv(net);
+ __le16 *ebuf = (__le16 *)data;
+ int ret;
+ int i;
+
+ /* Crude hack to ensure that we don't overwrite memory
+ * if an odd length is supplied
+ */
+ if (eeprom->len % 2)
+ return -EINVAL;
+
+ eeprom->magic = SR_EEPROM_MAGIC;
+
+ /* sr9800 returns 2 bytes from eeprom on read */
+ for (i = 0; i < eeprom->len / 2; i++) {
+ ret = sr_read_cmd(dev, SR_CMD_READ_EEPROM, eeprom->offset + i,
+ 0, 2, &ebuf[i]);
+ if (ret < 0)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void sr_get_drvinfo(struct net_device *net,
+ struct ethtool_drvinfo *info)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct sr_data *data = (struct sr_data *)&dev->data;
+
+ /* Inherit standard device info */
+ usbnet_get_drvinfo(net, info);
+ strncpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+ strncpy(info->version, DRIVER_VERSION, sizeof(info->version));
+ info->eedump_len = data->eeprom_len;
+}
+
+static u32 sr_get_link(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ return mii_link_ok(&dev->mii);
+}
+
+static int sr_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+static int sr_set_mac_address(struct net_device *net, void *p)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct sr_data *data = (struct sr_data *)&dev->data;
+ struct sockaddr *addr = p;
+
+ if (netif_running(net))
+ return -EBUSY;
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(net->dev_addr, addr->sa_data, ETH_ALEN);
+
+ /* We use the 20 byte dev->data
+ * for our 6 byte mac buffer
+ * to avoid allocating memory that
+ * is tricky to free later
+ */
+ memcpy(data->mac_addr, addr->sa_data, ETH_ALEN);
+ sr_write_cmd_async(dev, SR_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
+ data->mac_addr);
+
+ return 0;
+}
+
+static const struct ethtool_ops sr9800_ethtool_ops = {
+ .get_drvinfo = sr_get_drvinfo,
+ .get_link = sr_get_link,
+ .get_msglevel = usbnet_get_msglevel,
+ .set_msglevel = usbnet_set_msglevel,
+ .get_wol = sr_get_wol,
+ .set_wol = sr_set_wol,
+ .get_eeprom_len = sr_get_eeprom_len,
+ .get_eeprom = sr_get_eeprom,
+ .get_settings = usbnet_get_settings,
+ .set_settings = usbnet_set_settings,
+ .nway_reset = usbnet_nway_reset,
+};
+
+static int sr9800_link_reset(struct usbnet *dev)
+{
+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
+ u16 mode;
+
+ mii_check_media(&dev->mii, 1, 1);
+ mii_ethtool_gset(&dev->mii, &ecmd);
+ mode = SR9800_MEDIUM_DEFAULT;
+
+ if (ethtool_cmd_speed(&ecmd) != SPEED_100)
+ mode &= ~SR_MEDIUM_PS;
+
+ if (ecmd.duplex != DUPLEX_FULL)
+ mode &= ~SR_MEDIUM_FD;
+
+ netdev_dbg(dev->net, "%s : speed: %u duplex: %d mode: 0x%04x\n",
+ __func__, ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
+
+ sr_write_medium_mode(dev, mode);
+
+ return 0;
+}
+
+
+static int sr9800_set_default_mode(struct usbnet *dev)
+{
+ u16 rx_ctl;
+ int ret;
+
+ sr_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+ sr_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ ADVERTISE_ALL | ADVERTISE_CSMA);
+ mii_nway_restart(&dev->mii);
+
+ ret = sr_write_medium_mode(dev, SR9800_MEDIUM_DEFAULT);
+ if (ret < 0)
+ goto out;
+
+ ret = sr_write_cmd(dev, SR_CMD_WRITE_IPG012,
+ SR9800_IPG0_DEFAULT | SR9800_IPG1_DEFAULT,
+ SR9800_IPG2_DEFAULT, 0, NULL);
+ if (ret < 0) {
+ netdev_dbg(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret);
+ goto out;
+ }
+
+ /* Set RX_CTL to default values with 2k buffer, and enable cactus */
+ ret = sr_write_rx_ctl(dev, SR_DEFAULT_RX_CTL);
+ if (ret < 0)
+ goto out;
+
+ rx_ctl = sr_read_rx_ctl(dev);
+ netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n",
+ rx_ctl);
+
+ rx_ctl = sr_read_medium_status(dev);
+ netdev_dbg(dev->net, "Medium Status:0x%04x after all initializations\n",
+ rx_ctl);
+
+ return 0;
+out:
+ return ret;
+}
+
+static int sr9800_reset(struct usbnet *dev)
+{
+ struct sr_data *data = (struct sr_data *)&dev->data;
+ int ret, embd_phy;
+ u16 rx_ctl;
+
+ ret = sr_write_gpio(dev,
+ SR_GPIO_RSE | SR_GPIO_GPO_2 | SR_GPIO_GPO2EN, 5);
+ if (ret < 0)
+ goto out;
+
+ embd_phy = ((sr_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0);
+
+ ret = sr_write_cmd(dev, SR_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL);
+ if (ret < 0) {
+ netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret);
+ goto out;
+ }
+
+ ret = sr_sw_reset(dev, SR_SWRESET_IPPD | SR_SWRESET_PRL);
+ if (ret < 0)
+ goto out;
+
+ msleep(150);
+
+ ret = sr_sw_reset(dev, SR_SWRESET_CLEAR);
+ if (ret < 0)
+ goto out;
+
+ msleep(150);
+
+ if (embd_phy) {
+ ret = sr_sw_reset(dev, SR_SWRESET_IPRL);
+ if (ret < 0)
+ goto out;
+ } else {
+ ret = sr_sw_reset(dev, SR_SWRESET_PRTE);
+ if (ret < 0)
+ goto out;
+ }
+
+ msleep(150);
+ rx_ctl = sr_read_rx_ctl(dev);
+ netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl);
+ ret = sr_write_rx_ctl(dev, 0x0000);
+ if (ret < 0)
+ goto out;
+
+ rx_ctl = sr_read_rx_ctl(dev);
+ netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl);
+
+ ret = sr_sw_reset(dev, SR_SWRESET_PRL);
+ if (ret < 0)
+ goto out;
+
+ msleep(150);
+
+ ret = sr_sw_reset(dev, SR_SWRESET_IPRL | SR_SWRESET_PRL);
+ if (ret < 0)
+ goto out;
+
+ msleep(150);
+
+ ret = sr9800_set_default_mode(dev);
+ if (ret < 0)
+ goto out;
+
+ /* Rewrite MAC address */
+ memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN);
+ ret = sr_write_cmd(dev, SR_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
+ data->mac_addr);
+ if (ret < 0)
+ goto out;
+
+ return 0;
+
+out:
+ return ret;
+}
+
+static const struct net_device_ops sr9800_netdev_ops = {
+ .ndo_open = usbnet_open,
+ .ndo_stop = usbnet_stop,
+ .ndo_start_xmit = usbnet_start_xmit,
+ .ndo_tx_timeout = usbnet_tx_timeout,
+ .ndo_change_mtu = usbnet_change_mtu,
+ .ndo_set_mac_address = sr_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_do_ioctl = sr_ioctl,
+ .ndo_set_rx_mode = sr_set_multicast,
+};
+
+static int sr9800_phy_powerup(struct usbnet *dev)
+{
+ int ret;
+
+ /* set the embedded Ethernet PHY in power-down state */
+ ret = sr_sw_reset(dev, SR_SWRESET_IPPD | SR_SWRESET_IPRL);
+ if (ret < 0) {
+ netdev_err(dev->net, "Failed to power down PHY : %d\n", ret);
+ return ret;
+ }
+ msleep(20);
+
+ /* set the embedded Ethernet PHY in power-up state */
+ ret = sr_sw_reset(dev, SR_SWRESET_IPRL);
+ if (ret < 0) {
+ netdev_err(dev->net, "Failed to reset PHY: %d\n", ret);
+ return ret;
+ }
+ msleep(600);
+
+ /* set the embedded Ethernet PHY in reset state */
+ ret = sr_sw_reset(dev, SR_SWRESET_CLEAR);
+ if (ret < 0) {
+ netdev_err(dev->net, "Failed to power up PHY: %d\n", ret);
+ return ret;
+ }
+ msleep(20);
+
+ /* set the embedded Ethernet PHY in power-up state */
+ ret = sr_sw_reset(dev, SR_SWRESET_IPRL);
+ if (ret < 0) {
+ netdev_err(dev->net, "Failed to reset PHY: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int sr9800_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+ struct sr_data *data = (struct sr_data *)&dev->data;
+ u16 led01_mux, led23_mux;
+ int ret, embd_phy;
+ u32 phyid;
+ u16 rx_ctl;
+
+ data->eeprom_len = SR9800_EEPROM_LEN;
+
+ usbnet_get_endpoints(dev, intf);
+
+ /* LED Setting Rule :
+ * AABB:CCDD
+ * AA : MFA0(LED0)
+ * BB : MFA1(LED1)
+ * CC : MFA2(LED2), Reserved for SR9800
+ * DD : MFA3(LED3), Reserved for SR9800
+ */
+ led01_mux = (SR_LED_MUX_LINK_ACTIVE << 8) | SR_LED_MUX_LINK;
+ led23_mux = (SR_LED_MUX_LINK_ACTIVE << 8) | SR_LED_MUX_TX_ACTIVE;
+ ret = sr_write_cmd(dev, SR_CMD_LED_MUX, led01_mux, led23_mux, 0, NULL);
+ if (ret < 0) {
+ netdev_err(dev->net, "set LINK LED failed : %d\n", ret);
+ goto out;
+ }
+
+ /* Get the MAC address */
+ ret = sr_read_cmd(dev, SR_CMD_READ_NODE_ID, 0, 0, ETH_ALEN,
+ dev->net->dev_addr);
+ if (ret < 0) {
+ netdev_dbg(dev->net, "Failed to read MAC address: %d\n", ret);
+ return ret;
+ }
+ netdev_dbg(dev->net, "mac addr : %pM\n", dev->net->dev_addr);
+
+ /* Initialize MII structure */
+ dev->mii.dev = dev->net;
+ dev->mii.mdio_read = sr_mdio_read;
+ dev->mii.mdio_write = sr_mdio_write;
+ dev->mii.phy_id_mask = 0x1f;
+ dev->mii.reg_num_mask = 0x1f;
+ dev->mii.phy_id = sr_get_phy_addr(dev);
+
+ dev->net->netdev_ops = &sr9800_netdev_ops;
+ dev->net->ethtool_ops = &sr9800_ethtool_ops;
+
+ embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0);
+ /* Reset the PHY to normal operation mode */
+ ret = sr_write_cmd(dev, SR_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL);
+ if (ret < 0) {
+ netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Init PHY routine */
+ ret = sr9800_phy_powerup(dev);
+ if (ret < 0)
+ goto out;
+
+ rx_ctl = sr_read_rx_ctl(dev);
+ netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl);
+ ret = sr_write_rx_ctl(dev, 0x0000);
+ if (ret < 0)
+ goto out;
+
+ rx_ctl = sr_read_rx_ctl(dev);
+ netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl);
+
+ /* Read PHYID register *AFTER* the PHY was reset properly */
+ phyid = sr_get_phyid(dev);
+ netdev_dbg(dev->net, "PHYID=0x%08x\n", phyid);
+
+ /* medium mode setting */
+ ret = sr9800_set_default_mode(dev);
+ if (ret < 0)
+ goto out;
+
+ if (dev->udev->speed == USB_SPEED_HIGH) {
+ ret = sr_write_cmd(dev, SR_CMD_BULKIN_SIZE,
+ SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].byte_cnt,
+ SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].threshold,
+ 0, NULL);
+ if (ret < 0) {
+ netdev_err(dev->net, "Reset RX_CTL failed: %d\n", ret);
+ goto out;
+ }
+ dev->rx_urb_size =
+ SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].size;
+ } else {
+ ret = sr_write_cmd(dev, SR_CMD_BULKIN_SIZE,
+ SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].byte_cnt,
+ SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].threshold,
+ 0, NULL);
+ if (ret < 0) {
+ netdev_err(dev->net, "Reset RX_CTL failed: %d\n", ret);
+ goto out;
+ }
+ dev->rx_urb_size =
+ SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].size;
+ }
+ netdev_dbg(dev->net, "%s : setting rx_urb_size with : %zu\n", __func__,
+ dev->rx_urb_size);
+ return 0;
+
+out:
+ return ret;
+}
+
+static const struct driver_info sr9800_driver_info = {
+ .description = "CoreChip SR9800 USB 2.0 Ethernet",
+ .bind = sr9800_bind,
+ .status = sr_status,
+ .link_reset = sr9800_link_reset,
+ .reset = sr9800_reset,
+ .flags = DRIVER_FLAG,
+ .rx_fixup = sr_rx_fixup,
+ .tx_fixup = sr_tx_fixup,
+};
+
+static const struct usb_device_id products[] = {
+ {
+ USB_DEVICE(0x0fe6, 0x9800), /* SR9800 Device */
+ .driver_info = (unsigned long) &sr9800_driver_info,
+ },
+ {}, /* END */
+};
+
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver sr_driver = {
+ .name = DRIVER_NAME,
+ .id_table = products,
+ .probe = usbnet_probe,
+ .suspend = usbnet_suspend,
+ .resume = usbnet_resume,
+ .disconnect = usbnet_disconnect,
+ .supports_autosuspend = 1,
+};
+
+module_usb_driver(sr_driver);
+
+MODULE_AUTHOR("Liu Junliang <liujunliang_ljl@163.com");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_DESCRIPTION("SR9800 USB 2.0 USB2NET Dev : http://www.corechip-sz.com");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/sr9800.h b/drivers/net/usb/sr9800.h
new file mode 100644
index 000000000000..18f670251275
--- /dev/null
+++ b/drivers/net/usb/sr9800.h
@@ -0,0 +1,202 @@
+/* CoreChip-sz SR9800 one chip USB 2.0 Ethernet Devices
+ *
+ * Author : Liu Junliang <liujunliang_ljl@163.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _SR9800_H
+#define _SR9800_H
+
+/* SR9800 spec. command table on Linux Platform */
+
+/* command : Software Station Management Control Reg */
+#define SR_CMD_SET_SW_MII 0x06
+/* command : PHY Read Reg */
+#define SR_CMD_READ_MII_REG 0x07
+/* command : PHY Write Reg */
+#define SR_CMD_WRITE_MII_REG 0x08
+/* command : Hardware Station Management Control Reg */
+#define SR_CMD_SET_HW_MII 0x0a
+/* command : SROM Read Reg */
+#define SR_CMD_READ_EEPROM 0x0b
+/* command : SROM Write Reg */
+#define SR_CMD_WRITE_EEPROM 0x0c
+/* command : SROM Write Enable Reg */
+#define SR_CMD_WRITE_ENABLE 0x0d
+/* command : SROM Write Disable Reg */
+#define SR_CMD_WRITE_DISABLE 0x0e
+/* command : RX Control Read Reg */
+#define SR_CMD_READ_RX_CTL 0x0f
+#define SR_RX_CTL_PRO (1 << 0)
+#define SR_RX_CTL_AMALL (1 << 1)
+#define SR_RX_CTL_SEP (1 << 2)
+#define SR_RX_CTL_AB (1 << 3)
+#define SR_RX_CTL_AM (1 << 4)
+#define SR_RX_CTL_AP (1 << 5)
+#define SR_RX_CTL_ARP (1 << 6)
+#define SR_RX_CTL_SO (1 << 7)
+#define SR_RX_CTL_RH1M (1 << 8)
+#define SR_RX_CTL_RH2M (1 << 9)
+#define SR_RX_CTL_RH3M (1 << 10)
+/* command : RX Control Write Reg */
+#define SR_CMD_WRITE_RX_CTL 0x10
+/* command : IPG0/IPG1/IPG2 Control Read Reg */
+#define SR_CMD_READ_IPG012 0x11
+/* command : IPG0/IPG1/IPG2 Control Write Reg */
+#define SR_CMD_WRITE_IPG012 0x12
+/* command : Node ID Read Reg */
+#define SR_CMD_READ_NODE_ID 0x13
+/* command : Node ID Write Reg */
+#define SR_CMD_WRITE_NODE_ID 0x14
+/* command : Multicast Filter Array Read Reg */
+#define SR_CMD_READ_MULTI_FILTER 0x15
+/* command : Multicast Filter Array Write Reg */
+#define SR_CMD_WRITE_MULTI_FILTER 0x16
+/* command : Eth/HomePNA PHY Address Reg */
+#define SR_CMD_READ_PHY_ID 0x19
+/* command : Medium Status Read Reg */
+#define SR_CMD_READ_MEDIUM_STATUS 0x1a
+#define SR_MONITOR_LINK (1 << 1)
+#define SR_MONITOR_MAGIC (1 << 2)
+#define SR_MONITOR_HSFS (1 << 4)
+/* command : Medium Status Write Reg */
+#define SR_CMD_WRITE_MEDIUM_MODE 0x1b
+#define SR_MEDIUM_GM (1 << 0)
+#define SR_MEDIUM_FD (1 << 1)
+#define SR_MEDIUM_AC (1 << 2)
+#define SR_MEDIUM_ENCK (1 << 3)
+#define SR_MEDIUM_RFC (1 << 4)
+#define SR_MEDIUM_TFC (1 << 5)
+#define SR_MEDIUM_JFE (1 << 6)
+#define SR_MEDIUM_PF (1 << 7)
+#define SR_MEDIUM_RE (1 << 8)
+#define SR_MEDIUM_PS (1 << 9)
+#define SR_MEDIUM_RSV (1 << 10)
+#define SR_MEDIUM_SBP (1 << 11)
+#define SR_MEDIUM_SM (1 << 12)
+/* command : Monitor Mode Status Read Reg */
+#define SR_CMD_READ_MONITOR_MODE 0x1c
+/* command : Monitor Mode Status Write Reg */
+#define SR_CMD_WRITE_MONITOR_MODE 0x1d
+/* command : GPIO Status Read Reg */
+#define SR_CMD_READ_GPIOS 0x1e
+#define SR_GPIO_GPO0EN (1 << 0) /* GPIO0 Output enable */
+#define SR_GPIO_GPO_0 (1 << 1) /* GPIO0 Output value */
+#define SR_GPIO_GPO1EN (1 << 2) /* GPIO1 Output enable */
+#define SR_GPIO_GPO_1 (1 << 3) /* GPIO1 Output value */
+#define SR_GPIO_GPO2EN (1 << 4) /* GPIO2 Output enable */
+#define SR_GPIO_GPO_2 (1 << 5) /* GPIO2 Output value */
+#define SR_GPIO_RESERVED (1 << 6) /* Reserved */
+#define SR_GPIO_RSE (1 << 7) /* Reload serial EEPROM */
+/* command : GPIO Status Write Reg */
+#define SR_CMD_WRITE_GPIOS 0x1f
+/* command : Eth PHY Power and Reset Control Reg */
+#define SR_CMD_SW_RESET 0x20
+#define SR_SWRESET_CLEAR 0x00
+#define SR_SWRESET_RR (1 << 0)
+#define SR_SWRESET_RT (1 << 1)
+#define SR_SWRESET_PRTE (1 << 2)
+#define SR_SWRESET_PRL (1 << 3)
+#define SR_SWRESET_BZ (1 << 4)
+#define SR_SWRESET_IPRL (1 << 5)
+#define SR_SWRESET_IPPD (1 << 6)
+/* command : Software Interface Selection Status Read Reg */
+#define SR_CMD_SW_PHY_STATUS 0x21
+/* command : Software Interface Selection Status Write Reg */
+#define SR_CMD_SW_PHY_SELECT 0x22
+/* command : BULK in Buffer Size Reg */
+#define SR_CMD_BULKIN_SIZE 0x2A
+/* command : LED_MUX Control Reg */
+#define SR_CMD_LED_MUX 0x70
+#define SR_LED_MUX_TX_ACTIVE (1 << 0)
+#define SR_LED_MUX_RX_ACTIVE (1 << 1)
+#define SR_LED_MUX_COLLISION (1 << 2)
+#define SR_LED_MUX_DUP_COL (1 << 3)
+#define SR_LED_MUX_DUP (1 << 4)
+#define SR_LED_MUX_SPEED (1 << 5)
+#define SR_LED_MUX_LINK_ACTIVE (1 << 6)
+#define SR_LED_MUX_LINK (1 << 7)
+
+/* Register Access Flags */
+#define SR_REQ_RD_REG (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+#define SR_REQ_WR_REG (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+
+/* Multicast Filter Array size & Max Number */
+#define SR_MCAST_FILTER_SIZE 8
+#define SR_MAX_MCAST 64
+
+/* IPG0/1/2 Default Value */
+#define SR9800_IPG0_DEFAULT 0x15
+#define SR9800_IPG1_DEFAULT 0x0c
+#define SR9800_IPG2_DEFAULT 0x12
+
+/* Medium Status Default Mode */
+#define SR9800_MEDIUM_DEFAULT \
+ (SR_MEDIUM_FD | SR_MEDIUM_RFC | \
+ SR_MEDIUM_TFC | SR_MEDIUM_PS | \
+ SR_MEDIUM_AC | SR_MEDIUM_RE)
+
+/* RX Control Default Setting */
+#define SR_DEFAULT_RX_CTL \
+ (SR_RX_CTL_SO | SR_RX_CTL_AB | SR_RX_CTL_RH1M)
+
+/* EEPROM Magic Number & EEPROM Size */
+#define SR_EEPROM_MAGIC 0xdeadbeef
+#define SR9800_EEPROM_LEN 0xff
+
+/* SR9800 Driver Version and Driver Name */
+#define DRIVER_VERSION "11-Nov-2013"
+#define DRIVER_NAME "CoreChips"
+#define DRIVER_FLAG \
+ (FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET)
+
+/* SR9800 BULKIN Buffer Size */
+#define SR9800_MAX_BULKIN_2K 0
+#define SR9800_MAX_BULKIN_4K 1
+#define SR9800_MAX_BULKIN_6K 2
+#define SR9800_MAX_BULKIN_8K 3
+#define SR9800_MAX_BULKIN_16K 4
+#define SR9800_MAX_BULKIN_20K 5
+#define SR9800_MAX_BULKIN_24K 6
+#define SR9800_MAX_BULKIN_32K 7
+
+struct {unsigned short size, byte_cnt, threshold; } SR9800_BULKIN_SIZE[] = {
+ /* 2k */
+ {2048, 0x8000, 0x8001},
+ /* 4k */
+ {4096, 0x8100, 0x8147},
+ /* 6k */
+ {6144, 0x8200, 0x81EB},
+ /* 8k */
+ {8192, 0x8300, 0x83D7},
+ /* 16 */
+ {16384, 0x8400, 0x851E},
+ /* 20k */
+ {20480, 0x8500, 0x8666},
+ /* 24k */
+ {24576, 0x8600, 0x87AE},
+ /* 32k */
+ {32768, 0x8700, 0x8A3D},
+};
+
+/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
+struct sr_data {
+ u8 multi_filter[SR_MCAST_FILTER_SIZE];
+ u8 mac_addr[ETH_ALEN];
+ u8 phymode;
+ u8 ledmode;
+ u8 eeprom_len;
+};
+
+struct sr9800_int_data {
+ __le16 res1;
+ u8 link;
+ __le16 res2;
+ u8 status;
+ __le16 res3;
+} __packed;
+
+#endif /* _SR9800_H */
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 4671da755e7b..f9e96c427558 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -542,17 +542,19 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
}
// else network stack removes extra byte if we forced a short packet
- if (skb->len) {
- /* all data was already cloned from skb inside the driver */
- if (dev->driver_info->flags & FLAG_MULTI_PACKET)
- dev_kfree_skb_any(skb);
- else
- usbnet_skb_return(dev, skb);
+ /* all data was already cloned from skb inside the driver */
+ if (dev->driver_info->flags & FLAG_MULTI_PACKET)
+ goto done;
+
+ if (skb->len < ETH_HLEN) {
+ dev->net->stats.rx_errors++;
+ dev->net->stats.rx_length_errors++;
+ netif_dbg(dev, rx_err, dev->net, "rx length %d\n", skb->len);
+ } else {
+ usbnet_skb_return(dev, skb);
return;
}
- netif_dbg(dev, rx_err, dev->net, "drop\n");
- dev->net->stats.rx_errors++;
done:
skb_queue_tail(&dev->done, skb);
}
@@ -574,13 +576,6 @@ static void rx_complete (struct urb *urb)
switch (urb_status) {
/* success */
case 0:
- if (skb->len < dev->net->hard_header_len) {
- state = rx_cleanup;
- dev->net->stats.rx_errors++;
- dev->net->stats.rx_length_errors++;
- netif_dbg(dev, rx_err, dev->net,
- "rx length %d\n", skb->len);
- }
break;
/* stalls need manual reset. this is rare ... except that
@@ -757,14 +752,12 @@ EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs);
// precondition: never called in_interrupt
static void usbnet_terminate_urbs(struct usbnet *dev)
{
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(unlink_wakeup);
DECLARE_WAITQUEUE(wait, current);
int temp;
/* ensure there are no more active urbs */
- add_wait_queue(&unlink_wakeup, &wait);
+ add_wait_queue(&dev->wait, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
- dev->wait = &unlink_wakeup;
temp = unlink_urbs(dev, &dev->txq) +
unlink_urbs(dev, &dev->rxq);
@@ -778,15 +771,14 @@ static void usbnet_terminate_urbs(struct usbnet *dev)
"waited for %d urb completions\n", temp);
}
set_current_state(TASK_RUNNING);
- dev->wait = NULL;
- remove_wait_queue(&unlink_wakeup, &wait);
+ remove_wait_queue(&dev->wait, &wait);
}
int usbnet_stop (struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
struct driver_info *info = dev->driver_info;
- int retval;
+ int retval, pm;
clear_bit(EVENT_DEV_OPEN, &dev->flags);
netif_stop_queue (net);
@@ -796,6 +788,8 @@ int usbnet_stop (struct net_device *net)
net->stats.rx_packets, net->stats.tx_packets,
net->stats.rx_errors, net->stats.tx_errors);
+ /* to not race resume */
+ pm = usb_autopm_get_interface(dev->intf);
/* allow minidriver to stop correctly (wireless devices to turn off
* radio etc) */
if (info->stop) {
@@ -822,6 +816,9 @@ int usbnet_stop (struct net_device *net)
dev->flags = 0;
del_timer_sync (&dev->delay);
tasklet_kill (&dev->bh);
+ if (!pm)
+ usb_autopm_put_interface(dev->intf);
+
if (info->manage_power &&
!test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags))
info->manage_power(dev, 0);
@@ -1442,11 +1439,12 @@ static void usbnet_bh (unsigned long param)
/* restart RX again after disabling due to high error rate */
clear_bit(EVENT_RX_KILL, &dev->flags);
- // waiting for all pending urbs to complete?
- if (dev->wait) {
- if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) {
- wake_up (dev->wait);
- }
+ /* waiting for all pending urbs to complete?
+ * only then can we forgo submitting anew
+ */
+ if (waitqueue_active(&dev->wait)) {
+ if (dev->txq.qlen + dev->rxq.qlen + dev->done.qlen == 0)
+ wake_up_all(&dev->wait);
// or are we maybe short a few urbs?
} else if (netif_running (dev->net) &&
@@ -1585,6 +1583,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
dev->driver_name = name;
dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
| NETIF_MSG_PROBE | NETIF_MSG_LINK);
+ init_waitqueue_head(&dev->wait);
skb_queue_head_init (&dev->rxq);
skb_queue_head_init (&dev->txq);
skb_queue_head_init (&dev->done);
@@ -1796,9 +1795,10 @@ int usbnet_resume (struct usb_interface *intf)
spin_unlock_irq(&dev->txq.lock);
if (test_bit(EVENT_DEV_OPEN, &dev->flags)) {
- /* handle remote wakeup ASAP */
- if (!dev->wait &&
- netif_device_present(dev->net) &&
+ /* handle remote wakeup ASAP
+ * we cannot race against stop
+ */
+ if (netif_device_present(dev->net) &&
!timer_pending(&dev->delay) &&
!test_bit(EVENT_RX_HALT, &dev->flags))
rx_alloc_submit(dev, GFP_NOIO);
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 2ec2041b62d4..b4a10bcb66a0 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -14,6 +14,7 @@
#include <linux/etherdevice.h>
#include <linux/u64_stats_sync.h>
+#include <net/rtnetlink.h>
#include <net/dst.h>
#include <net/xfrm.h>
#include <linux/veth.h>
@@ -155,10 +156,10 @@ static u64 veth_stats_one(struct pcpu_vstats *result, struct net_device *dev)
unsigned int start;
do {
- start = u64_stats_fetch_begin_bh(&stats->syncp);
+ start = u64_stats_fetch_begin_irq(&stats->syncp);
packets = stats->packets;
bytes = stats->bytes;
- } while (u64_stats_fetch_retry_bh(&stats->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&stats->syncp, start));
result->packets += packets;
result->bytes += bytes;
}
@@ -235,18 +236,9 @@ static int veth_change_mtu(struct net_device *dev, int new_mtu)
static int veth_dev_init(struct net_device *dev)
{
- int i;
-
- dev->vstats = alloc_percpu(struct pcpu_vstats);
+ dev->vstats = netdev_alloc_pcpu_stats(struct pcpu_vstats);
if (!dev->vstats)
return -ENOMEM;
-
- for_each_possible_cpu(i) {
- struct pcpu_vstats *veth_stats;
- veth_stats = per_cpu_ptr(dev->vstats, i);
- u64_stats_init(&veth_stats->syncp);
- }
-
return 0;
}
@@ -285,7 +277,11 @@ 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->vlan_features = dev->features &
+ ~(NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_STAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_VLAN_STAG_RX);
dev->destructor = veth_dev_free;
dev->hw_features = VETH_FEATURES;
@@ -332,10 +328,9 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
nla_peer = data[VETH_INFO_PEER];
ifmp = nla_data(nla_peer);
- err = nla_parse(peer_tb, IFLA_MAX,
- nla_data(nla_peer) + sizeof(struct ifinfomsg),
- nla_len(nla_peer) - sizeof(struct ifinfomsg),
- ifla_policy);
+ err = rtnl_nla_parse_ifla(peer_tb,
+ nla_data(nla_peer) + sizeof(struct ifinfomsg),
+ nla_len(nla_peer) - sizeof(struct ifinfomsg));
if (err < 0)
return err;
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index d75f8edf4fb3..7b687469199b 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -671,8 +671,7 @@ static bool try_fill_recv(struct receive_queue *rq, gfp_t gfp)
if (err)
break;
} while (rq->vq->num_free);
- if (unlikely(!virtqueue_kick(rq->vq)))
- return false;
+ virtqueue_kick(rq->vq);
return !oom;
}
@@ -877,15 +876,16 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
err = xmit_skb(sq, skb);
/* This should not happen! */
- if (unlikely(err) || unlikely(!virtqueue_kick(sq->vq))) {
+ if (unlikely(err)) {
dev->stats.tx_fifo_errors++;
if (net_ratelimit())
dev_warn(&dev->dev,
"Unexpected TXQ (%d) queue failure: %d\n", qnum, err);
dev->stats.tx_dropped++;
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
+ virtqueue_kick(sq->vq);
/* Don't wait up for transmitted skbs to be freed. */
skb_orphan(skb);
@@ -938,7 +938,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
sgs[out_num] = &stat;
BUG_ON(out_num + 1 > ARRAY_SIZE(sgs));
- BUG_ON(virtqueue_add_sgs(vi->cvq, sgs, out_num, 1, vi, GFP_ATOMIC) < 0);
+ virtqueue_add_sgs(vi->cvq, sgs, out_num, 1, vi, GFP_ATOMIC);
if (unlikely(!virtqueue_kick(vi->cvq)))
return status == VIRTIO_NET_OK;
@@ -1000,16 +1000,16 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
u64 tpackets, tbytes, rpackets, rbytes;
do {
- start = u64_stats_fetch_begin_bh(&stats->tx_syncp);
+ start = u64_stats_fetch_begin_irq(&stats->tx_syncp);
tpackets = stats->tx_packets;
tbytes = stats->tx_bytes;
- } while (u64_stats_fetch_retry_bh(&stats->tx_syncp, start));
+ } while (u64_stats_fetch_retry_irq(&stats->tx_syncp, start));
do {
- start = u64_stats_fetch_begin_bh(&stats->rx_syncp);
+ start = u64_stats_fetch_begin_irq(&stats->rx_syncp);
rpackets = stats->rx_packets;
rbytes = stats->rx_bytes;
- } while (u64_stats_fetch_retry_bh(&stats->rx_syncp, start));
+ } while (u64_stats_fetch_retry_irq(&stats->rx_syncp, start));
tot->rx_packets += rpackets;
tot->tx_packets += tpackets;
@@ -1711,7 +1711,8 @@ static int virtnet_probe(struct virtio_device *vdev)
/* If we can receive ANY GSO packets, we must allocate large ones. */
if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) ||
- virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN))
+ virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN) ||
+ virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UFO))
vi->big_packets = true;
if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 3be786faaaec..97394345e5dd 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -1078,7 +1078,7 @@ unlock_drop_pkt:
spin_unlock_irqrestore(&tq->tx_lock, flags);
drop_pkt:
tq->stats.drop_total++;
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -1762,11 +1762,20 @@ vmxnet3_netpoll(struct net_device *netdev)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
- if (adapter->intr.mask_mode == VMXNET3_IMM_ACTIVE)
- vmxnet3_disable_all_intrs(adapter);
-
- vmxnet3_do_poll(adapter, adapter->rx_queue[0].rx_ring[0].size);
- vmxnet3_enable_all_intrs(adapter);
+ switch (adapter->intr.type) {
+#ifdef CONFIG_PCI_MSI
+ case VMXNET3_IT_MSIX: {
+ int i;
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ vmxnet3_msix_rx(0, &adapter->rx_queue[i]);
+ break;
+ }
+#endif
+ case VMXNET3_IT_MSI:
+ default:
+ vmxnet3_intr(0, adapter->netdev);
+ break;
+ }
}
#endif /* CONFIG_NET_POLL_CONTROLLER */
@@ -2729,47 +2738,35 @@ vmxnet3_read_mac_addr(struct vmxnet3_adapter *adapter, u8 *mac)
/*
* Enable MSIx vectors.
* Returns :
- * 0 on successful enabling of required vectors,
* VMXNET3_LINUX_MIN_MSIX_VECT when only minimum number of vectors required
- * could be enabled.
- * number of vectors which can be enabled otherwise (this number is smaller
+ * were enabled.
+ * number of vectors which were enabled otherwise (this number is greater
* than VMXNET3_LINUX_MIN_MSIX_VECT)
*/
static int
-vmxnet3_acquire_msix_vectors(struct vmxnet3_adapter *adapter,
- int vectors)
-{
- int err = 0, vector_threshold;
- vector_threshold = VMXNET3_LINUX_MIN_MSIX_VECT;
-
- while (vectors >= vector_threshold) {
- err = pci_enable_msix(adapter->pdev, adapter->intr.msix_entries,
- vectors);
- if (!err) {
- adapter->intr.num_intrs = vectors;
- return 0;
- } else if (err < 0) {
- dev_err(&adapter->netdev->dev,
- "Failed to enable MSI-X, error: %d\n", err);
- vectors = 0;
- } else if (err < vector_threshold) {
- break;
- } else {
- /* If fails to enable required number of MSI-x vectors
- * try enabling minimum number of vectors required.
- */
- dev_err(&adapter->netdev->dev,
- "Failed to enable %d MSI-X, trying %d instead\n",
- vectors, vector_threshold);
- vectors = vector_threshold;
- }
+vmxnet3_acquire_msix_vectors(struct vmxnet3_adapter *adapter, int nvec)
+{
+ int ret = pci_enable_msix_range(adapter->pdev,
+ adapter->intr.msix_entries, nvec, nvec);
+
+ if (ret == -ENOSPC && nvec > VMXNET3_LINUX_MIN_MSIX_VECT) {
+ dev_err(&adapter->netdev->dev,
+ "Failed to enable %d MSI-X, trying %d\n",
+ nvec, VMXNET3_LINUX_MIN_MSIX_VECT);
+
+ ret = pci_enable_msix_range(adapter->pdev,
+ adapter->intr.msix_entries,
+ VMXNET3_LINUX_MIN_MSIX_VECT,
+ VMXNET3_LINUX_MIN_MSIX_VECT);
}
- dev_info(&adapter->pdev->dev,
- "Number of MSI-X interrupts which can be allocated "
- "is lower than min threshold required.\n");
- return err;
+ if (ret < 0) {
+ dev_err(&adapter->netdev->dev,
+ "Failed to enable MSI-X, error: %d\n", ret);
+ }
+
+ return ret;
}
@@ -2796,56 +2793,50 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
#ifdef CONFIG_PCI_MSI
if (adapter->intr.type == VMXNET3_IT_MSIX) {
- int vector, err = 0;
-
- adapter->intr.num_intrs = (adapter->share_intr ==
- VMXNET3_INTR_TXSHARE) ? 1 :
- adapter->num_tx_queues;
- adapter->intr.num_intrs += (adapter->share_intr ==
- VMXNET3_INTR_BUDDYSHARE) ? 0 :
- adapter->num_rx_queues;
- adapter->intr.num_intrs += 1; /* for link event */
-
- adapter->intr.num_intrs = (adapter->intr.num_intrs >
- VMXNET3_LINUX_MIN_MSIX_VECT
- ? adapter->intr.num_intrs :
- VMXNET3_LINUX_MIN_MSIX_VECT);
-
- for (vector = 0; vector < adapter->intr.num_intrs; vector++)
- adapter->intr.msix_entries[vector].entry = vector;
-
- err = vmxnet3_acquire_msix_vectors(adapter,
- adapter->intr.num_intrs);
+ int i, nvec;
+
+ nvec = adapter->share_intr == VMXNET3_INTR_TXSHARE ?
+ 1 : adapter->num_tx_queues;
+ nvec += adapter->share_intr == VMXNET3_INTR_BUDDYSHARE ?
+ 0 : adapter->num_rx_queues;
+ nvec += 1; /* for link event */
+ nvec = nvec > VMXNET3_LINUX_MIN_MSIX_VECT ?
+ nvec : VMXNET3_LINUX_MIN_MSIX_VECT;
+
+ for (i = 0; i < nvec; i++)
+ adapter->intr.msix_entries[i].entry = i;
+
+ nvec = vmxnet3_acquire_msix_vectors(adapter, nvec);
+ if (nvec < 0)
+ goto msix_err;
+
/* If we cannot allocate one MSIx vector per queue
* then limit the number of rx queues to 1
*/
- if (err == VMXNET3_LINUX_MIN_MSIX_VECT) {
+ if (nvec == VMXNET3_LINUX_MIN_MSIX_VECT) {
if (adapter->share_intr != VMXNET3_INTR_BUDDYSHARE
|| adapter->num_rx_queues != 1) {
adapter->share_intr = VMXNET3_INTR_TXSHARE;
netdev_err(adapter->netdev,
"Number of rx queues : 1\n");
adapter->num_rx_queues = 1;
- adapter->intr.num_intrs =
- VMXNET3_LINUX_MIN_MSIX_VECT;
}
- return;
}
- if (!err)
- return;
+ adapter->intr.num_intrs = nvec;
+ return;
+
+msix_err:
/* If we cannot allocate MSIx vectors use only one rx queue */
dev_info(&adapter->pdev->dev,
"Failed to enable MSI-X, error %d. "
- "Limiting #rx queues to 1, try MSI.\n", err);
+ "Limiting #rx queues to 1, try MSI.\n", nvec);
adapter->intr.type = VMXNET3_IT_MSI;
}
if (adapter->intr.type == VMXNET3_IT_MSI) {
- int err;
- err = pci_enable_msi(adapter->pdev);
- if (!err) {
+ if (!pci_enable_msi(adapter->pdev)) {
adapter->num_rx_queues = 1;
adapter->intr.num_intrs = 1;
return;
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 026a313c2d2d..0d862a5077ab 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -469,7 +469,6 @@ static inline struct hlist_head *vxlan_fdb_head(struct vxlan_dev *vxlan,
/* Look up Ethernet address in forwarding table */
static struct vxlan_fdb *__vxlan_find_mac(struct vxlan_dev *vxlan,
const u8 *mac)
-
{
struct hlist_head *head = vxlan_fdb_head(vxlan, mac);
struct vxlan_fdb *f;
@@ -596,10 +595,8 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff
NAPI_GRO_CB(p)->same_flow = 0;
continue;
}
- goto found;
}
-found:
type = eh->h_proto;
rcu_read_lock();
@@ -1135,7 +1132,6 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
{
struct vxlan_sock *vs;
struct vxlanhdr *vxh;
- __be16 port;
/* Need Vxlan and inner Ethernet header to be present */
if (!pskb_may_pull(skb, VXLAN_HLEN))
@@ -1153,8 +1149,6 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB)))
goto drop;
- port = inet_sk(sk)->inet_sport;
-
vs = rcu_dereference_sk_user_data(sk);
if (!vs)
goto drop;
@@ -1321,6 +1315,9 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb)
neigh_release(n);
+ if (reply == NULL)
+ goto out;
+
skb_reset_mac_header(reply);
__skb_pull(reply, skb_network_offset(reply));
reply->ip_summed = CHECKSUM_UNNECESSARY;
@@ -1342,15 +1339,103 @@ out:
}
#if IS_ENABLED(CONFIG_IPV6)
+
+static struct sk_buff *vxlan_na_create(struct sk_buff *request,
+ struct neighbour *n, bool isrouter)
+{
+ struct net_device *dev = request->dev;
+ struct sk_buff *reply;
+ struct nd_msg *ns, *na;
+ struct ipv6hdr *pip6;
+ u8 *daddr;
+ int na_olen = 8; /* opt hdr + ETH_ALEN for target */
+ int ns_olen;
+ int i, len;
+
+ if (dev == NULL)
+ return NULL;
+
+ len = LL_RESERVED_SPACE(dev) + sizeof(struct ipv6hdr) +
+ sizeof(*na) + na_olen + dev->needed_tailroom;
+ reply = alloc_skb(len, GFP_ATOMIC);
+ if (reply == NULL)
+ return NULL;
+
+ reply->protocol = htons(ETH_P_IPV6);
+ reply->dev = dev;
+ skb_reserve(reply, LL_RESERVED_SPACE(request->dev));
+ skb_push(reply, sizeof(struct ethhdr));
+ skb_set_mac_header(reply, 0);
+
+ ns = (struct nd_msg *)skb_transport_header(request);
+
+ daddr = eth_hdr(request)->h_source;
+ ns_olen = request->len - skb_transport_offset(request) - sizeof(*ns);
+ for (i = 0; i < ns_olen-1; i += (ns->opt[i+1]<<3)) {
+ if (ns->opt[i] == ND_OPT_SOURCE_LL_ADDR) {
+ daddr = ns->opt + i + sizeof(struct nd_opt_hdr);
+ break;
+ }
+ }
+
+ /* Ethernet header */
+ ether_addr_copy(eth_hdr(reply)->h_dest, daddr);
+ ether_addr_copy(eth_hdr(reply)->h_source, n->ha);
+ eth_hdr(reply)->h_proto = htons(ETH_P_IPV6);
+ reply->protocol = htons(ETH_P_IPV6);
+
+ skb_pull(reply, sizeof(struct ethhdr));
+ skb_set_network_header(reply, 0);
+ skb_put(reply, sizeof(struct ipv6hdr));
+
+ /* IPv6 header */
+
+ pip6 = ipv6_hdr(reply);
+ memset(pip6, 0, sizeof(struct ipv6hdr));
+ pip6->version = 6;
+ pip6->priority = ipv6_hdr(request)->priority;
+ pip6->nexthdr = IPPROTO_ICMPV6;
+ pip6->hop_limit = 255;
+ pip6->daddr = ipv6_hdr(request)->saddr;
+ pip6->saddr = *(struct in6_addr *)n->primary_key;
+
+ skb_pull(reply, sizeof(struct ipv6hdr));
+ skb_set_transport_header(reply, 0);
+
+ na = (struct nd_msg *)skb_put(reply, sizeof(*na) + na_olen);
+
+ /* Neighbor Advertisement */
+ memset(na, 0, sizeof(*na)+na_olen);
+ na->icmph.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
+ na->icmph.icmp6_router = isrouter;
+ na->icmph.icmp6_override = 1;
+ na->icmph.icmp6_solicited = 1;
+ na->target = ns->target;
+ ether_addr_copy(&na->opt[2], n->ha);
+ na->opt[0] = ND_OPT_TARGET_LL_ADDR;
+ na->opt[1] = na_olen >> 3;
+
+ na->icmph.icmp6_cksum = csum_ipv6_magic(&pip6->saddr,
+ &pip6->daddr, sizeof(*na)+na_olen, IPPROTO_ICMPV6,
+ csum_partial(na, sizeof(*na)+na_olen, 0));
+
+ pip6->payload_len = htons(sizeof(*na)+na_olen);
+
+ skb_push(reply, sizeof(struct ipv6hdr));
+
+ reply->ip_summed = CHECKSUM_UNNECESSARY;
+
+ return reply;
+}
+
static int neigh_reduce(struct net_device *dev, struct sk_buff *skb)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
- struct neighbour *n;
- union vxlan_addr ipa;
+ struct nd_msg *msg;
const struct ipv6hdr *iphdr;
const struct in6_addr *saddr, *daddr;
- struct nd_msg *msg;
- struct inet6_dev *in6_dev = NULL;
+ struct neighbour *n;
+ struct inet6_dev *in6_dev;
in6_dev = __in6_dev_get(dev);
if (!in6_dev)
@@ -1363,19 +1448,20 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb)
saddr = &iphdr->saddr;
daddr = &iphdr->daddr;
- if (ipv6_addr_loopback(daddr) ||
- ipv6_addr_is_multicast(daddr))
- goto out;
-
msg = (struct nd_msg *)skb_transport_header(skb);
if (msg->icmph.icmp6_code != 0 ||
msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION)
goto out;
- n = neigh_lookup(ipv6_stub->nd_tbl, daddr, dev);
+ if (ipv6_addr_loopback(daddr) ||
+ ipv6_addr_is_multicast(&msg->target))
+ goto out;
+
+ n = neigh_lookup(ipv6_stub->nd_tbl, &msg->target, dev);
if (n) {
struct vxlan_fdb *f;
+ struct sk_buff *reply;
if (!(n->nud_state & NUD_CONNECTED)) {
neigh_release(n);
@@ -1389,13 +1475,23 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb)
goto out;
}
- ipv6_stub->ndisc_send_na(dev, n, saddr, &msg->target,
- !!in6_dev->cnf.forwarding,
- true, false, false);
+ reply = vxlan_na_create(skb, n,
+ !!(f ? f->flags & NTF_ROUTER : 0));
+
neigh_release(n);
+
+ if (reply == NULL)
+ goto out;
+
+ if (netif_rx_ni(reply) == NET_RX_DROP)
+ dev->stats.rx_dropped++;
+
} else if (vxlan->flags & VXLAN_F_L3MISS) {
- ipa.sin6.sin6_addr = *daddr;
- ipa.sa.sa_family = AF_INET6;
+ union vxlan_addr ipa = {
+ .sin6.sin6_addr = msg->target,
+ .sa.sa_family = AF_INET6,
+ };
+
vxlan_ip_miss(dev, &ipa);
}
@@ -1981,19 +2077,11 @@ static int vxlan_init(struct net_device *dev)
struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
struct vxlan_sock *vs;
- int i;
- dev->tstats = alloc_percpu(struct pcpu_sw_netstats);
+ dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
if (!dev->tstats)
return -ENOMEM;
- for_each_possible_cpu(i) {
- struct pcpu_sw_netstats *vxlan_stats;
- vxlan_stats = per_cpu_ptr(dev->tstats, i);
- u64_stats_init(&vxlan_stats->syncp);
- }
-
-
spin_lock(&vn->sock_lock);
vs = vxlan_find_sock(dev_net(dev), vxlan->dst_port);
if (vs) {
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index 0d1c7592efa0..19f7cb2cdef3 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -71,12 +71,9 @@ static int dlci_header(struct sk_buff *skb, struct net_device *dev,
const void *saddr, unsigned len)
{
struct frhdr hdr;
- struct dlci_local *dlp;
unsigned int hlen;
char *dest;
- dlp = netdev_priv(dev);
-
hdr.control = FRAD_I_UI;
switch (type)
{
@@ -107,11 +104,9 @@ static int dlci_header(struct sk_buff *skb, struct net_device *dev,
static void dlci_receive(struct sk_buff *skb, struct net_device *dev)
{
- struct dlci_local *dlp;
struct frhdr *hdr;
int process, header;
- dlp = netdev_priv(dev);
if (!pskb_may_pull(skb, sizeof(*hdr))) {
netdev_notice(dev, "invalid data no header\n");
dev->stats.rx_errors++;
diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c
index 48896138418f..a9970f1af976 100644
--- a/drivers/net/wimax/i2400m/netdev.c
+++ b/drivers/net/wimax/i2400m/netdev.c
@@ -374,8 +374,7 @@ netdev_tx_t i2400m_hard_start_xmit(struct sk_buff *skb,
d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev);
- if (skb_header_cloned(skb) &&
- pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ if (skb_cow_head(skb, 0))
goto drop;
if (i2400m->state == I2400M_SS_IDLE)
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 200020eb3005..b2137e8f7ca6 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -53,7 +53,7 @@ config LIBERTAS_THINFIRM_USB
config AIRO
tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards"
- depends on ISA_DMA_API && (PCI || BROKEN)
+ depends on CFG80211 && ISA_DMA_API && (PCI || BROKEN)
select WIRELESS_EXT
select CRYPTO
select WEXT_SPY
@@ -73,7 +73,7 @@ config AIRO
config ATMEL
tristate "Atmel at76c50x chipset 802.11b support"
- depends on (PCI || PCMCIA)
+ depends on CFG80211 && (PCI || PCMCIA)
select WIRELESS_EXT
select WEXT_PRIV
select FW_LOADER
@@ -116,7 +116,7 @@ config AT76C50X_USB
config AIRO_CS
tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards"
- depends on PCMCIA && (BROKEN || !M32R)
+ depends on CFG80211 && PCMCIA && (BROKEN || !M32R)
select WIRELESS_EXT
select WEXT_SPY
select WEXT_PRIV
@@ -138,7 +138,7 @@ config AIRO_CS
config PCMCIA_WL3501
tristate "Planet WL3501 PCMCIA cards"
- depends on PCMCIA
+ depends on CFG80211 && PCMCIA
select WIRELESS_EXT
select WEXT_SPY
help
@@ -168,7 +168,7 @@ config PRISM54
config USB_ZD1201
tristate "USB ZD1201 based Wireless device support"
- depends on USB
+ depends on CFG80211 && USB
select WIRELESS_EXT
select WEXT_PRIV
select FW_LOADER
@@ -281,5 +281,6 @@ source "drivers/net/wireless/ti/Kconfig"
source "drivers/net/wireless/zd1211rw/Kconfig"
source "drivers/net/wireless/mwifiex/Kconfig"
source "drivers/net/wireless/cw1200/Kconfig"
+source "drivers/net/wireless/rsi/Kconfig"
endif # WLAN
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 0fab227025be..0c8891686718 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -59,3 +59,4 @@ obj-$(CONFIG_BRCMFMAC) += brcm80211/
obj-$(CONFIG_BRCMSMAC) += brcm80211/
obj-$(CONFIG_CW1200) += cw1200/
+obj-$(CONFIG_RSI_91X) += rsi/
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index edf4b57c4aaa..64747d457bb3 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -36,7 +36,7 @@
#include <linux/bitops.h>
#include <linux/scatterlist.h>
#include <linux/crypto.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/unaligned.h>
#include <linux/netdevice.h>
@@ -45,11 +45,11 @@
#include <linux/if_arp.h>
#include <linux/ioport.h>
#include <linux/pci.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
-#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
#include <net/iw_handler.h>
#include "airo.h"
@@ -5797,7 +5797,7 @@ static int airo_set_freq(struct net_device *dev,
/* Hack to fall through... */
fwrq->e = 0;
- fwrq->m = ieee80211_freq_to_dsss_chan(f);
+ fwrq->m = ieee80211_frequency_to_channel(f);
}
/* Setting by channel number */
if((fwrq->m > 1000) || (fwrq->e > 0))
@@ -5841,7 +5841,8 @@ static int airo_get_freq(struct net_device *dev,
ch = le16_to_cpu(status_rid.channel);
if((ch > 0) && (ch < 15)) {
- fwrq->m = ieee80211_dsss_chan_to_freq(ch) * 100000;
+ fwrq->m = 100000 *
+ ieee80211_channel_to_frequency(ch, IEEE80211_BAND_2GHZ);
fwrq->e = 1;
} else {
fwrq->m = ch;
@@ -6898,7 +6899,8 @@ static int airo_get_range(struct net_device *dev,
k = 0;
for(i = 0; i < 14; i++) {
range->freq[k].i = i + 1; /* List index */
- range->freq[k].m = ieee80211_dsss_chan_to_freq(i + 1) * 100000;
+ range->freq[k].m = 100000 *
+ ieee80211_channel_to_frequency(i + 1, IEEE80211_BAND_2GHZ);
range->freq[k++].e = 1; /* Values in MHz -> * 10^5 * 10 */
}
range->num_frequency = k;
@@ -7297,7 +7299,8 @@ static inline char *airo_translate_scan(struct net_device *dev,
/* Add frequency */
iwe.cmd = SIOCGIWFREQ;
iwe.u.freq.m = le16_to_cpu(bss->dsChannel);
- iwe.u.freq.m = ieee80211_dsss_chan_to_freq(iwe.u.freq.m) * 100000;
+ iwe.u.freq.m = 100000 *
+ ieee80211_channel_to_frequency(iwe.u.freq.m, IEEE80211_BAND_2GHZ);
iwe.u.freq.e = 1;
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
&iwe, IW_EV_FREQ_LEN);
diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c
index 8aa20df55e50..507d9a9ee69a 100644
--- a/drivers/net/wireless/ath/ar5523/ar5523.c
+++ b/drivers/net/wireless/ath/ar5523/ar5523.c
@@ -1764,7 +1764,7 @@ static struct usb_device_id ar5523_id_table[] = {
AR5523_DEVICE_UG(0x07d1, 0x3a07), /* D-Link / WUA-2340 rev A1 */
AR5523_DEVICE_UG(0x1690, 0x0712), /* Gigaset / AR5523 */
AR5523_DEVICE_UG(0x1690, 0x0710), /* Gigaset / SMCWUSBTG */
- AR5523_DEVICE_UG(0x129b, 0x160c), /* Gigaset / USB stick 108
+ AR5523_DEVICE_UG(0x129b, 0x160b), /* Gigaset / USB stick 108
(CyberTAN Technology) */
AR5523_DEVICE_UG(0x16ab, 0x7801), /* Globalsun / AR5523_1 */
AR5523_DEVICE_UX(0x16ab, 0x7811), /* Globalsun / AR5523_2 */
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index b59cfbe0276b..a889fd66fc63 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -56,6 +56,15 @@ enum ath_device_state {
ATH_HW_INITIALIZED,
};
+enum ath_op_flags {
+ ATH_OP_INVALID,
+ ATH_OP_BEACONS,
+ ATH_OP_ANI_RUN,
+ ATH_OP_PRIM_STA_VIF,
+ ATH_OP_HW_RESET,
+ ATH_OP_SCANNING,
+};
+
enum ath_bus_type {
ATH_PCI,
ATH_AHB,
@@ -63,7 +72,7 @@ enum ath_bus_type {
};
struct reg_dmn_pair_mapping {
- u16 regDmnEnum;
+ u16 reg_domain;
u16 reg_5ghz_ctl;
u16 reg_2ghz_ctl;
};
@@ -130,6 +139,7 @@ struct ath_common {
struct ieee80211_hw *hw;
int debug_mask;
enum ath_device_state state;
+ unsigned long op_flags;
struct ath_ani ani;
@@ -161,6 +171,9 @@ struct ath_common {
bool btcoex_enabled;
bool disable_ani;
bool bt_ant_diversity;
+
+ int last_rssi;
+ struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
};
struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index d44d618b05f9..a79499c82350 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -266,12 +266,12 @@ static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar,
* ath10k_ce_sendlist_send.
* The caller takes responsibility for any needed locking.
*/
-static int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
- void *per_transfer_context,
- u32 buffer,
- unsigned int nbytes,
- unsigned int transfer_id,
- unsigned int flags)
+int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
+ void *per_transfer_context,
+ u32 buffer,
+ unsigned int nbytes,
+ unsigned int transfer_id,
+ unsigned int flags)
{
struct ath10k *ar = ce_state->ar;
struct ath10k_ce_ring *src_ring = ce_state->src_ring;
@@ -1067,9 +1067,9 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
*
* For the lack of a better place do the check here.
*/
- BUILD_BUG_ON(TARGET_NUM_MSDU_DESC >
+ BUILD_BUG_ON(2*TARGET_NUM_MSDU_DESC >
(CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
- BUILD_BUG_ON(TARGET_10X_NUM_MSDU_DESC >
+ BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC >
(CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
ret = ath10k_pci_wake(ar);
diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h
index 67dbde6a5c74..8eb7f99ed992 100644
--- a/drivers/net/wireless/ath/ath10k/ce.h
+++ b/drivers/net/wireless/ath/ath10k/ce.h
@@ -23,7 +23,7 @@
/* Maximum number of Copy Engine's supported */
#define CE_COUNT_MAX 8
-#define CE_HTT_H2T_MSG_SRC_NENTRIES 2048
+#define CE_HTT_H2T_MSG_SRC_NENTRIES 4096
/* Descriptor rings must be aligned to this boundary */
#define CE_DESC_RING_ALIGN 8
@@ -152,6 +152,13 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,
unsigned int transfer_id,
unsigned int flags);
+int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
+ void *per_transfer_context,
+ u32 buffer,
+ unsigned int nbytes,
+ unsigned int transfer_id,
+ unsigned int flags);
+
void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
void (*send_cb)(struct ath10k_ce_pipe *),
int disable_interrupts);
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 3b59af3bddf4..ebc5fc2ede75 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -55,8 +55,7 @@ static void ath10k_send_suspend_complete(struct ath10k *ar)
{
ath10k_dbg(ATH10K_DBG_BOOT, "boot suspend complete\n");
- ar->is_target_paused = true;
- wake_up(&ar->event_queue);
+ complete(&ar->target_suspend);
}
static int ath10k_init_connect_htc(struct ath10k *ar)
@@ -470,8 +469,12 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
if (index == ie_len)
break;
- if (data[index] & (1 << bit))
+ if (data[index] & (1 << bit)) {
+ ath10k_dbg(ATH10K_DBG_BOOT,
+ "Enabling feature bit: %i\n",
+ i);
__set_bit(i, ar->fw_features);
+ }
}
ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "",
@@ -699,6 +702,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
init_completion(&ar->scan.started);
init_completion(&ar->scan.completed);
init_completion(&ar->scan.on_channel);
+ init_completion(&ar->target_suspend);
init_completion(&ar->install_key_done);
init_completion(&ar->vdev_setup_done);
@@ -722,8 +726,6 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work);
skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
- init_waitqueue_head(&ar->event_queue);
-
INIT_WORK(&ar->restart_work, ath10k_core_restart);
return ar;
@@ -856,10 +858,34 @@ err:
}
EXPORT_SYMBOL(ath10k_core_start);
+int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt)
+{
+ int ret;
+
+ reinit_completion(&ar->target_suspend);
+
+ ret = ath10k_wmi_pdev_suspend_target(ar, suspend_opt);
+ if (ret) {
+ ath10k_warn("could not suspend target (%d)\n", ret);
+ return ret;
+ }
+
+ ret = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ);
+
+ if (ret == 0) {
+ ath10k_warn("suspend timed out - target pause event never came\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
void ath10k_core_stop(struct ath10k *ar)
{
lockdep_assert_held(&ar->conf_mutex);
+ /* try to suspend target */
+ ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR);
ath10k_debug_stop(ar);
ath10k_htc_stop(&ar->htc);
ath10k_htt_detach(&ar->htt);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index ade1781c7186..0e71979d837c 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -46,21 +46,35 @@
#define ATH10K_MAX_NUM_MGMT_PENDING 128
+/* number of failed packets */
+#define ATH10K_KICKOUT_THRESHOLD 50
+
+/*
+ * Use insanely high numbers to make sure that the firmware implementation
+ * won't start, we have the same functionality already in hostapd. Unit
+ * is seconds.
+ */
+#define ATH10K_KEEPALIVE_MIN_IDLE 3747
+#define ATH10K_KEEPALIVE_MAX_IDLE 3895
+#define ATH10K_KEEPALIVE_MAX_UNRESPONSIVE 3900
+
struct ath10k;
struct ath10k_skb_cb {
dma_addr_t paddr;
- bool is_mapped;
- bool is_aborted;
u8 vdev_id;
struct {
u8 tid;
bool is_offchan;
-
- u8 frag_len;
- u8 pad_len;
+ struct ath10k_htt_txbuf *txbuf;
+ u32 txbuf_paddr;
} __packed htt;
+
+ struct {
+ bool dtim_zero;
+ bool deliver_cab;
+ } bcn;
} __packed;
static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb)
@@ -70,32 +84,6 @@ static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb)
return (struct ath10k_skb_cb *)&IEEE80211_SKB_CB(skb)->driver_data;
}
-static inline int ath10k_skb_map(struct device *dev, struct sk_buff *skb)
-{
- if (ATH10K_SKB_CB(skb)->is_mapped)
- return -EINVAL;
-
- ATH10K_SKB_CB(skb)->paddr = dma_map_single(dev, skb->data, skb->len,
- DMA_TO_DEVICE);
-
- if (unlikely(dma_mapping_error(dev, ATH10K_SKB_CB(skb)->paddr)))
- return -EIO;
-
- ATH10K_SKB_CB(skb)->is_mapped = true;
- return 0;
-}
-
-static inline int ath10k_skb_unmap(struct device *dev, struct sk_buff *skb)
-{
- if (!ATH10K_SKB_CB(skb)->is_mapped)
- return -EINVAL;
-
- dma_unmap_single(dev, ATH10K_SKB_CB(skb)->paddr, skb->len,
- DMA_TO_DEVICE);
- ATH10K_SKB_CB(skb)->is_mapped = false;
- return 0;
-}
-
static inline u32 host_interest_item_address(u32 item_offset)
{
return QCA988X_HOST_INTEREST_ADDRESS + item_offset;
@@ -211,6 +199,18 @@ struct ath10k_peer {
struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
};
+struct ath10k_sta {
+ struct ath10k_vif *arvif;
+
+ /* the following are protected by ar->data_lock */
+ u32 changed; /* IEEE80211_RC_* */
+ u32 bw;
+ u32 nss;
+ u32 smps;
+
+ struct work_struct update_wk;
+};
+
#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ)
struct ath10k_vif {
@@ -222,10 +222,17 @@ struct ath10k_vif {
u32 beacon_interval;
u32 dtim_period;
struct sk_buff *beacon;
+ /* protected by data_lock */
+ bool beacon_sent;
struct ath10k *ar;
struct ieee80211_vif *vif;
+ bool is_started;
+ bool is_up;
+ u32 aid;
+ u8 bssid[ETH_ALEN];
+
struct work_struct wep_key_work;
struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1];
u8 def_wep_key_idx;
@@ -235,7 +242,6 @@ struct ath10k_vif {
union {
struct {
- u8 bssid[ETH_ALEN];
u32 uapsd;
} sta;
struct {
@@ -249,13 +255,11 @@ struct ath10k_vif {
u32 noa_len;
u8 *noa_data;
} ap;
- struct {
- u8 bssid[ETH_ALEN];
- } ibss;
} u;
u8 fixed_rate;
u8 fixed_nss;
+ u8 force_sgi;
};
struct ath10k_vif_iter {
@@ -355,8 +359,7 @@ struct ath10k {
const struct ath10k_hif_ops *ops;
} hif;
- wait_queue_head_t event_queue;
- bool is_target_paused;
+ struct completion target_suspend;
struct ath10k_bmi bmi;
struct ath10k_wmi wmi;
@@ -412,6 +415,9 @@ struct ath10k {
/* valid during scan; needed for mgmt rx during scan */
struct ieee80211_channel *scan_channel;
+ /* current operating channel definition */
+ struct cfg80211_chan_def chandef;
+
int free_vdev_map;
int monitor_vdev_id;
bool monitor_enabled;
@@ -470,6 +476,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
void ath10k_core_destroy(struct ath10k *ar);
int ath10k_core_start(struct ath10k *ar);
+int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt);
void ath10k_core_stop(struct ath10k *ar);
int ath10k_core_register(struct ath10k *ar, u32 chip_id);
void ath10k_core_unregister(struct ath10k *ar);
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index 1773c36c71a0..a5824990bd2a 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -92,7 +92,7 @@ static inline void ath10k_debug_read_target_stats(struct ath10k *ar,
#ifdef CONFIG_ATH10K_DEBUG
__printf(2, 3) void ath10k_dbg(enum ath10k_debug_mask mask,
- const char *fmt, ...);
+ const char *fmt, ...);
void ath10k_dbg_dump(enum ath10k_debug_mask mask,
const char *msg, const char *prefix,
const void *buf, size_t len);
diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h
index dcdea68bcc0a..2ac7beacddca 100644
--- a/drivers/net/wireless/ath/ath10k/hif.h
+++ b/drivers/net/wireless/ath/ath10k/hif.h
@@ -21,6 +21,14 @@
#include <linux/kernel.h>
#include "core.h"
+struct ath10k_hif_sg_item {
+ u16 transfer_id;
+ void *transfer_context; /* NULL = tx completion callback not called */
+ void *vaddr; /* for debugging mostly */
+ u32 paddr;
+ u16 len;
+};
+
struct ath10k_hif_cb {
int (*tx_completion)(struct ath10k *ar,
struct sk_buff *wbuf,
@@ -31,11 +39,9 @@ struct ath10k_hif_cb {
};
struct ath10k_hif_ops {
- /* Send the head of a buffer to HIF for transmission to the target. */
- int (*send_head)(struct ath10k *ar, u8 pipe_id,
- unsigned int transfer_id,
- unsigned int nbytes,
- struct sk_buff *buf);
+ /* send a scatter-gather list to the target */
+ int (*tx_sg)(struct ath10k *ar, u8 pipe_id,
+ struct ath10k_hif_sg_item *items, int n_items);
/*
* API to handle HIF-specific BMI message exchanges, this API is
@@ -86,12 +92,11 @@ struct ath10k_hif_ops {
};
-static inline int ath10k_hif_send_head(struct ath10k *ar, u8 pipe_id,
- unsigned int transfer_id,
- unsigned int nbytes,
- struct sk_buff *buf)
+static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
+ struct ath10k_hif_sg_item *items,
+ int n_items)
{
- return ar->hif.ops->send_head(ar, pipe_id, transfer_id, nbytes, buf);
+ return ar->hif.ops->tx_sg(ar, pipe_id, items, n_items);
}
static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar,
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index edc57ab505c8..7f1bccd3597f 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -63,7 +63,9 @@ static struct sk_buff *ath10k_htc_build_tx_ctrl_skb(void *ar)
static inline void ath10k_htc_restore_tx_skb(struct ath10k_htc *htc,
struct sk_buff *skb)
{
- ath10k_skb_unmap(htc->ar->dev, skb);
+ struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
+
+ dma_unmap_single(htc->ar->dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE);
skb_pull(skb, sizeof(struct ath10k_htc_hdr));
}
@@ -122,6 +124,9 @@ int ath10k_htc_send(struct ath10k_htc *htc,
struct sk_buff *skb)
{
struct ath10k_htc_ep *ep = &htc->endpoint[eid];
+ struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
+ struct ath10k_hif_sg_item sg_item;
+ struct device *dev = htc->ar->dev;
int credits = 0;
int ret;
@@ -157,19 +162,25 @@ int ath10k_htc_send(struct ath10k_htc *htc,
ath10k_htc_prepare_tx_skb(ep, skb);
- ret = ath10k_skb_map(htc->ar->dev, skb);
+ skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE);
+ ret = dma_mapping_error(dev, skb_cb->paddr);
if (ret)
goto err_credits;
- ret = ath10k_hif_send_head(htc->ar, ep->ul_pipe_id, ep->eid,
- skb->len, skb);
+ sg_item.transfer_id = ep->eid;
+ sg_item.transfer_context = skb;
+ sg_item.vaddr = skb->data;
+ sg_item.paddr = skb_cb->paddr;
+ sg_item.len = skb->len;
+
+ ret = ath10k_hif_tx_sg(htc->ar, ep->ul_pipe_id, &sg_item, 1);
if (ret)
goto err_unmap;
return 0;
err_unmap:
- ath10k_skb_unmap(htc->ar->dev, skb);
+ dma_unmap_single(dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE);
err_credits:
if (ep->tx_credit_flow_enabled) {
spin_lock_bh(&htc->tx_lock);
@@ -191,10 +202,8 @@ static int ath10k_htc_tx_completion_handler(struct ath10k *ar,
struct ath10k_htc *htc = &ar->htc;
struct ath10k_htc_ep *ep = &htc->endpoint[eid];
- if (!skb) {
- ath10k_warn("invalid sk_buff completion - NULL pointer. firmware crashed?\n");
+ if (WARN_ON_ONCE(!skb))
return 0;
- }
ath10k_htc_notify_tx_completion(ep, skb);
/* the skb now belongs to the completion handler */
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index b93ae355bc08..654867fc1ae7 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -20,6 +20,7 @@
#include <linux/bug.h>
#include <linux/interrupt.h>
+#include <linux/dmapool.h>
#include "htc.h"
#include "rx_desc.h"
@@ -1181,11 +1182,20 @@ struct htt_rx_info {
u32 info1;
u32 info2;
} rate;
+
+ u32 tsf;
bool fcs_err;
bool amsdu_more;
bool mic_err;
};
+struct ath10k_htt_txbuf {
+ struct htt_data_tx_desc_frag frags[2];
+ struct ath10k_htc_hdr htc_hdr;
+ struct htt_cmd_hdr cmd_hdr;
+ struct htt_data_tx_desc cmd_tx;
+} __packed;
+
struct ath10k_htt {
struct ath10k *ar;
enum ath10k_htc_ep_id eid;
@@ -1267,11 +1277,18 @@ struct ath10k_htt {
struct sk_buff **pending_tx;
unsigned long *used_msdu_ids; /* bitmap */
wait_queue_head_t empty_tx_wq;
+ struct dma_pool *tx_pool;
/* set if host-fw communication goes haywire
* used to avoid further failures */
bool rx_confused;
struct tasklet_struct rx_replenish_task;
+
+ /* This is used to group tx/rx completions separately and process them
+ * in batches to reduce cache stalls */
+ struct tasklet_struct txrx_compl_task;
+ struct sk_buff_head tx_compl_q;
+ struct sk_buff_head rx_compl_q;
};
#define RX_HTT_HDR_STATUS_LEN 64
@@ -1343,4 +1360,5 @@ int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt);
void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id);
int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *);
int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *);
+
#endif
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index fe8bd1b59f0e..cdcbe2de95f9 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -43,7 +43,7 @@
static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb);
-
+static void ath10k_htt_txrx_compl_task(unsigned long ptr);
static int ath10k_htt_rx_ring_size(struct ath10k_htt *htt)
{
@@ -225,18 +225,16 @@ static void ath10k_htt_rx_ring_refill_retry(unsigned long arg)
ath10k_htt_rx_msdu_buff_replenish(htt);
}
-static unsigned ath10k_htt_rx_ring_elems(struct ath10k_htt *htt)
-{
- return (__le32_to_cpu(*htt->rx_ring.alloc_idx.vaddr) -
- htt->rx_ring.sw_rd_idx.msdu_payld) & htt->rx_ring.size_mask;
-}
-
void ath10k_htt_rx_detach(struct ath10k_htt *htt)
{
int sw_rd_idx = htt->rx_ring.sw_rd_idx.msdu_payld;
del_timer_sync(&htt->rx_ring.refill_retry_timer);
tasklet_kill(&htt->rx_replenish_task);
+ tasklet_kill(&htt->txrx_compl_task);
+
+ skb_queue_purge(&htt->tx_compl_q);
+ skb_queue_purge(&htt->rx_compl_q);
while (sw_rd_idx != __le32_to_cpu(*(htt->rx_ring.alloc_idx.vaddr))) {
struct sk_buff *skb =
@@ -270,10 +268,12 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)
int idx;
struct sk_buff *msdu;
- spin_lock_bh(&htt->rx_ring.lock);
+ lockdep_assert_held(&htt->rx_ring.lock);
- if (ath10k_htt_rx_ring_elems(htt) == 0)
- ath10k_warn("htt rx ring is empty!\n");
+ if (htt->rx_ring.fill_cnt == 0) {
+ ath10k_warn("tried to pop sk_buff from an empty rx ring\n");
+ return NULL;
+ }
idx = htt->rx_ring.sw_rd_idx.msdu_payld;
msdu = htt->rx_ring.netbufs_ring[idx];
@@ -283,7 +283,6 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)
htt->rx_ring.sw_rd_idx.msdu_payld = idx;
htt->rx_ring.fill_cnt--;
- spin_unlock_bh(&htt->rx_ring.lock);
return msdu;
}
@@ -307,8 +306,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
struct sk_buff *msdu;
struct htt_rx_desc *rx_desc;
- if (ath10k_htt_rx_ring_elems(htt) == 0)
- ath10k_warn("htt rx ring is empty!\n");
+ lockdep_assert_held(&htt->rx_ring.lock);
if (htt->rx_confused) {
ath10k_warn("htt is confused. refusing rx\n");
@@ -324,7 +322,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
msdu->len + skb_tailroom(msdu),
DMA_FROM_DEVICE);
- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx: ",
+ ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ",
msdu->data, msdu->len + skb_tailroom(msdu));
rx_desc = (struct htt_rx_desc *)msdu->data;
@@ -400,6 +398,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
msdu_len = MS(__le32_to_cpu(rx_desc->msdu_start.info0),
RX_MSDU_START_INFO0_MSDU_LENGTH);
msdu_chained = rx_desc->frag_info.ring2_more_count;
+ msdu_chaining = msdu_chained;
if (msdu_len_invalid)
msdu_len = 0;
@@ -417,8 +416,8 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
next->len + skb_tailroom(next),
DMA_FROM_DEVICE);
- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx: ",
- next->data,
+ ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL,
+ "htt rx chained: ", next->data,
next->len + skb_tailroom(next));
skb_trim(next, 0);
@@ -427,13 +426,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
msdu->next = next;
msdu = next;
- msdu_chaining = 1;
- }
-
- if (msdu_len > 0) {
- /* This may suggest FW bug? */
- ath10k_warn("htt rx msdu len not consumed (%d)\n",
- msdu_len);
}
last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) &
@@ -535,6 +527,12 @@ int ath10k_htt_rx_attach(struct ath10k_htt *htt)
tasklet_init(&htt->rx_replenish_task, ath10k_htt_rx_replenish_task,
(unsigned long)htt);
+ skb_queue_head_init(&htt->tx_compl_q);
+ skb_queue_head_init(&htt->rx_compl_q);
+
+ tasklet_init(&htt->txrx_compl_task, ath10k_htt_txrx_compl_task,
+ (unsigned long)htt);
+
ath10k_dbg(ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n",
htt->rx_ring.size, htt->rx_ring.fill_level);
return 0;
@@ -638,6 +636,12 @@ struct amsdu_subframe_hdr {
__be16 len;
} __packed;
+static int ath10k_htt_rx_nwifi_hdrlen(struct ieee80211_hdr *hdr)
+{
+ /* nwifi header is padded to 4 bytes. this fixes 4addr rx */
+ return round_up(ieee80211_hdrlen(hdr->frame_control), 4);
+}
+
static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
struct htt_rx_info *info)
{
@@ -687,7 +691,7 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
case RX_MSDU_DECAP_NATIVE_WIFI:
/* pull decapped header and copy DA */
hdr = (struct ieee80211_hdr *)skb->data;
- hdr_len = ieee80211_hdrlen(hdr->frame_control);
+ hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr);
memcpy(addr, ieee80211_get_DA(hdr), ETH_ALEN);
skb_pull(skb, hdr_len);
@@ -751,7 +755,7 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info)
/* This shouldn't happen. If it does than it may be a FW bug. */
if (skb->next) {
- ath10k_warn("received chained non A-MSDU frame\n");
+ ath10k_warn("htt rx received chained non A-MSDU frame\n");
ath10k_htt_rx_free_msdu_chain(skb->next);
skb->next = NULL;
}
@@ -774,7 +778,7 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info)
case RX_MSDU_DECAP_NATIVE_WIFI:
/* Pull decapped header */
hdr = (struct ieee80211_hdr *)skb->data;
- hdr_len = ieee80211_hdrlen(hdr->frame_control);
+ hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr);
skb_pull(skb, hdr_len);
/* Push original header */
@@ -852,6 +856,20 @@ static bool ath10k_htt_rx_has_mic_err(struct sk_buff *skb)
return false;
}
+static bool ath10k_htt_rx_is_mgmt(struct sk_buff *skb)
+{
+ struct htt_rx_desc *rxd;
+ u32 flags;
+
+ rxd = (void *)skb->data - sizeof(*rxd);
+ flags = __le32_to_cpu(rxd->attention.flags);
+
+ if (flags & RX_ATTENTION_FLAGS_MGMT_TYPE)
+ return true;
+
+ return false;
+}
+
static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb)
{
struct htt_rx_desc *rxd;
@@ -883,6 +901,57 @@ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb)
return CHECKSUM_UNNECESSARY;
}
+static int ath10k_unchain_msdu(struct sk_buff *msdu_head)
+{
+ struct sk_buff *next = msdu_head->next;
+ struct sk_buff *to_free = next;
+ int space;
+ int total_len = 0;
+
+ /* TODO: Might could optimize this by using
+ * skb_try_coalesce or similar method to
+ * decrease copying, or maybe get mac80211 to
+ * provide a way to just receive a list of
+ * skb?
+ */
+
+ msdu_head->next = NULL;
+
+ /* Allocate total length all at once. */
+ while (next) {
+ total_len += next->len;
+ next = next->next;
+ }
+
+ space = total_len - skb_tailroom(msdu_head);
+ if ((space > 0) &&
+ (pskb_expand_head(msdu_head, 0, space, GFP_ATOMIC) < 0)) {
+ /* TODO: bump some rx-oom error stat */
+ /* put it back together so we can free the
+ * whole list at once.
+ */
+ msdu_head->next = to_free;
+ return -1;
+ }
+
+ /* Walk list again, copying contents into
+ * msdu_head
+ */
+ next = to_free;
+ while (next) {
+ skb_copy_from_linear_data(next, skb_put(msdu_head, next->len),
+ next->len);
+ next = next->next;
+ }
+
+ /* If here, we have consolidated skb. Free the
+ * fragments and pass the main skb on up the
+ * stack.
+ */
+ ath10k_htt_rx_free_msdu_chain(to_free);
+ return 0;
+}
+
static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
struct htt_rx_indication *rx)
{
@@ -894,6 +963,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
u8 *fw_desc;
int i, j;
+ lockdep_assert_held(&htt->rx_ring.lock);
+
memset(&info, 0, sizeof(info));
fw_desc_len = __le16_to_cpu(rx->prefix.fw_rx_desc_bytes);
@@ -937,6 +1008,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
}
if (ath10k_htt_rx_has_decrypt_err(msdu_head)) {
+ ath10k_dbg(ATH10K_DBG_HTT,
+ "htt rx dropping due to decrypt-err\n");
ath10k_htt_rx_free_msdu_chain(msdu_head);
continue;
}
@@ -944,13 +1017,16 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
status = info.status;
/* Skip mgmt frames while we handle this in WMI */
- if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL) {
+ if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL ||
+ ath10k_htt_rx_is_mgmt(msdu_head)) {
+ ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
ath10k_htt_rx_free_msdu_chain(msdu_head);
continue;
}
if (status != HTT_RX_IND_MPDU_STATUS_OK &&
status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR &&
+ status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER &&
!htt->ar->monitor_enabled) {
ath10k_dbg(ATH10K_DBG_HTT,
"htt rx ignoring frame w/ status %d\n",
@@ -960,14 +1036,14 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
}
if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) {
+ ath10k_dbg(ATH10K_DBG_HTT,
+ "htt rx CAC running\n");
ath10k_htt_rx_free_msdu_chain(msdu_head);
continue;
}
- /* FIXME: we do not support chaining yet.
- * this needs investigation */
- if (msdu_chaining) {
- ath10k_warn("msdu_chaining is true\n");
+ if (msdu_chaining &&
+ (ath10k_unchain_msdu(msdu_head) < 0)) {
ath10k_htt_rx_free_msdu_chain(msdu_head);
continue;
}
@@ -975,12 +1051,22 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
info.skb = msdu_head;
info.fcs_err = ath10k_htt_rx_has_fcs_err(msdu_head);
info.mic_err = ath10k_htt_rx_has_mic_err(msdu_head);
+
+ if (info.fcs_err)
+ ath10k_dbg(ATH10K_DBG_HTT,
+ "htt rx has FCS err\n");
+
+ if (info.mic_err)
+ ath10k_dbg(ATH10K_DBG_HTT,
+ "htt rx has MIC err\n");
+
info.signal = ATH10K_DEFAULT_NOISE_FLOOR;
info.signal += rx->ppdu.combined_rssi;
info.rate.info0 = rx->ppdu.info0;
info.rate.info1 = __le32_to_cpu(rx->ppdu.info1);
info.rate.info2 = __le32_to_cpu(rx->ppdu.info2);
+ info.tsf = __le32_to_cpu(rx->ppdu.tsf);
hdr = ath10k_htt_rx_skb_get_hdr(msdu_head);
@@ -1014,8 +1100,11 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
msdu_head = NULL;
msdu_tail = NULL;
+
+ spin_lock_bh(&htt->rx_ring.lock);
msdu_chaining = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len,
&msdu_head, &msdu_tail);
+ spin_unlock_bh(&htt->rx_ring.lock);
ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n");
@@ -1095,7 +1184,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
skb_trim(info.skb, info.skb->len - trim);
- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt frag mpdu: ",
+ ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ",
info.skb->data, info.skb->len);
ath10k_process_rx(htt->ar, &info);
@@ -1107,6 +1196,45 @@ end:
}
}
+static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar,
+ struct sk_buff *skb)
+{
+ struct ath10k_htt *htt = &ar->htt;
+ struct htt_resp *resp = (struct htt_resp *)skb->data;
+ struct htt_tx_done tx_done = {};
+ int status = MS(resp->data_tx_completion.flags, HTT_DATA_TX_STATUS);
+ __le16 msdu_id;
+ int i;
+
+ lockdep_assert_held(&htt->tx_lock);
+
+ switch (status) {
+ case HTT_DATA_TX_STATUS_NO_ACK:
+ tx_done.no_ack = true;
+ break;
+ case HTT_DATA_TX_STATUS_OK:
+ break;
+ case HTT_DATA_TX_STATUS_DISCARD:
+ case HTT_DATA_TX_STATUS_POSTPONE:
+ case HTT_DATA_TX_STATUS_DOWNLOAD_FAIL:
+ tx_done.discard = true;
+ break;
+ default:
+ ath10k_warn("unhandled tx completion status %d\n", status);
+ tx_done.discard = true;
+ break;
+ }
+
+ ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n",
+ resp->data_tx_completion.num_msdus);
+
+ for (i = 0; i < resp->data_tx_completion.num_msdus; i++) {
+ msdu_id = resp->data_tx_completion.msdus[i];
+ tx_done.msdu_id = __le16_to_cpu(msdu_id);
+ ath10k_txrx_tx_unref(htt, &tx_done);
+ }
+}
+
void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
{
struct ath10k_htt *htt = &ar->htt;
@@ -1116,7 +1244,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
if (!IS_ALIGNED((unsigned long)skb->data, 4))
ath10k_warn("unaligned htt message, expect trouble\n");
- ath10k_dbg(ATH10K_DBG_HTT, "HTT RX, msg_type: 0x%0X\n",
+ ath10k_dbg(ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n",
resp->hdr.msg_type);
switch (resp->hdr.msg_type) {
case HTT_T2H_MSG_TYPE_VERSION_CONF: {
@@ -1125,10 +1253,12 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
complete(&htt->target_version_received);
break;
}
- case HTT_T2H_MSG_TYPE_RX_IND: {
- ath10k_htt_rx_handler(htt, &resp->rx_ind);
- break;
- }
+ case HTT_T2H_MSG_TYPE_RX_IND:
+ spin_lock_bh(&htt->rx_ring.lock);
+ __skb_queue_tail(&htt->rx_compl_q, skb);
+ spin_unlock_bh(&htt->rx_ring.lock);
+ tasklet_schedule(&htt->txrx_compl_task);
+ return;
case HTT_T2H_MSG_TYPE_PEER_MAP: {
struct htt_peer_map_event ev = {
.vdev_id = resp->peer_map.vdev_id,
@@ -1163,44 +1293,17 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
break;
}
+ spin_lock_bh(&htt->tx_lock);
ath10k_txrx_tx_unref(htt, &tx_done);
+ spin_unlock_bh(&htt->tx_lock);
break;
}
- case HTT_T2H_MSG_TYPE_TX_COMPL_IND: {
- struct htt_tx_done tx_done = {};
- int status = MS(resp->data_tx_completion.flags,
- HTT_DATA_TX_STATUS);
- __le16 msdu_id;
- int i;
-
- switch (status) {
- case HTT_DATA_TX_STATUS_NO_ACK:
- tx_done.no_ack = true;
- break;
- case HTT_DATA_TX_STATUS_OK:
- break;
- case HTT_DATA_TX_STATUS_DISCARD:
- case HTT_DATA_TX_STATUS_POSTPONE:
- case HTT_DATA_TX_STATUS_DOWNLOAD_FAIL:
- tx_done.discard = true;
- break;
- default:
- ath10k_warn("unhandled tx completion status %d\n",
- status);
- tx_done.discard = true;
- break;
- }
-
- ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n",
- resp->data_tx_completion.num_msdus);
-
- for (i = 0; i < resp->data_tx_completion.num_msdus; i++) {
- msdu_id = resp->data_tx_completion.msdus[i];
- tx_done.msdu_id = __le16_to_cpu(msdu_id);
- ath10k_txrx_tx_unref(htt, &tx_done);
- }
- break;
- }
+ case HTT_T2H_MSG_TYPE_TX_COMPL_IND:
+ spin_lock_bh(&htt->tx_lock);
+ __skb_queue_tail(&htt->tx_compl_q, skb);
+ spin_unlock_bh(&htt->tx_lock);
+ tasklet_schedule(&htt->txrx_compl_task);
+ return;
case HTT_T2H_MSG_TYPE_SEC_IND: {
struct ath10k *ar = htt->ar;
struct htt_security_indication *ev = &resp->security_indication;
@@ -1240,3 +1343,25 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
/* Free the indication buffer */
dev_kfree_skb_any(skb);
}
+
+static void ath10k_htt_txrx_compl_task(unsigned long ptr)
+{
+ struct ath10k_htt *htt = (struct ath10k_htt *)ptr;
+ struct htt_resp *resp;
+ struct sk_buff *skb;
+
+ spin_lock_bh(&htt->tx_lock);
+ while ((skb = __skb_dequeue(&htt->tx_compl_q))) {
+ ath10k_htt_rx_frm_tx_compl(htt->ar, skb);
+ dev_kfree_skb_any(skb);
+ }
+ spin_unlock_bh(&htt->tx_lock);
+
+ spin_lock_bh(&htt->rx_ring.lock);
+ while ((skb = __skb_dequeue(&htt->rx_compl_q))) {
+ resp = (struct htt_resp *)skb->data;
+ ath10k_htt_rx_handler(htt, &resp->rx_ind);
+ dev_kfree_skb_any(skb);
+ }
+ spin_unlock_bh(&htt->rx_ring.lock);
+}
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index f1d36d2d2723..7a3e2e40dd5c 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -109,6 +109,14 @@ int ath10k_htt_tx_attach(struct ath10k_htt *htt)
return -ENOMEM;
}
+ htt->tx_pool = dma_pool_create("ath10k htt tx pool", htt->ar->dev,
+ sizeof(struct ath10k_htt_txbuf), 4, 0);
+ if (!htt->tx_pool) {
+ kfree(htt->used_msdu_ids);
+ kfree(htt->pending_tx);
+ return -ENOMEM;
+ }
+
return 0;
}
@@ -117,9 +125,7 @@ static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt)
struct htt_tx_done tx_done = {0};
int msdu_id;
- /* No locks needed. Called after communication with the device has
- * been stopped. */
-
+ spin_lock_bh(&htt->tx_lock);
for (msdu_id = 0; msdu_id < htt->max_num_pending_tx; msdu_id++) {
if (!test_bit(msdu_id, htt->used_msdu_ids))
continue;
@@ -132,6 +138,7 @@ static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt)
ath10k_txrx_tx_unref(htt, &tx_done);
}
+ spin_unlock_bh(&htt->tx_lock);
}
void ath10k_htt_tx_detach(struct ath10k_htt *htt)
@@ -139,6 +146,7 @@ void ath10k_htt_tx_detach(struct ath10k_htt *htt)
ath10k_htt_tx_cleanup_pending(htt);
kfree(htt->pending_tx);
kfree(htt->used_msdu_ids);
+ dma_pool_destroy(htt->tx_pool);
return;
}
@@ -334,7 +342,9 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
goto err_free_msdu_id;
}
- res = ath10k_skb_map(dev, msdu);
+ skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len,
+ DMA_TO_DEVICE);
+ res = dma_mapping_error(dev, skb_cb->paddr);
if (res)
goto err_free_txdesc;
@@ -348,8 +358,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
memcpy(cmd->mgmt_tx.hdr, msdu->data,
min_t(int, msdu->len, HTT_MGMT_FRM_HDR_DOWNLOAD_LEN));
- skb_cb->htt.frag_len = 0;
- skb_cb->htt.pad_len = 0;
+ skb_cb->htt.txbuf = NULL;
res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc);
if (res)
@@ -358,7 +367,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
return 0;
err_unmap_msdu:
- ath10k_skb_unmap(dev, msdu);
+ dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
err_free_txdesc:
dev_kfree_skb_any(txdesc);
err_free_msdu_id:
@@ -375,19 +384,19 @@ err:
int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
{
struct device *dev = htt->ar->dev;
- struct htt_cmd *cmd;
- struct htt_data_tx_desc_frag *tx_frags;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
- struct sk_buff *txdesc = NULL;
- bool use_frags;
- u8 vdev_id = ATH10K_SKB_CB(msdu)->vdev_id;
- u8 tid;
- int prefetch_len, desc_len;
- int msdu_id = -1;
+ struct ath10k_hif_sg_item sg_items[2];
+ struct htt_data_tx_desc_frag *frags;
+ u8 vdev_id = skb_cb->vdev_id;
+ u8 tid = skb_cb->htt.tid;
+ int prefetch_len;
int res;
- u8 flags0;
- u16 flags1;
+ u8 flags0 = 0;
+ u16 msdu_id, flags1 = 0;
+ dma_addr_t paddr;
+ u32 frags_paddr;
+ bool use_frags;
res = ath10k_htt_tx_inc_pending(htt);
if (res)
@@ -406,114 +415,120 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
prefetch_len = min(htt->prefetch_len, msdu->len);
prefetch_len = roundup(prefetch_len, 4);
- desc_len = sizeof(cmd->hdr) + sizeof(cmd->data_tx) + prefetch_len;
-
- txdesc = ath10k_htc_alloc_skb(desc_len);
- if (!txdesc) {
- res = -ENOMEM;
- goto err_free_msdu_id;
- }
-
/* Since HTT 3.0 there is no separate mgmt tx command. However in case
* of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
* fragment list host driver specifies directly frame pointer. */
use_frags = htt->target_version_major < 3 ||
!ieee80211_is_mgmt(hdr->frame_control);
- if (!IS_ALIGNED((unsigned long)txdesc->data, 4)) {
- ath10k_warn("htt alignment check failed. dropping packet.\n");
- res = -EIO;
- goto err_free_txdesc;
- }
+ skb_cb->htt.txbuf = dma_pool_alloc(htt->tx_pool, GFP_ATOMIC,
+ &paddr);
+ if (!skb_cb->htt.txbuf)
+ goto err_free_msdu_id;
+ skb_cb->htt.txbuf_paddr = paddr;
- if (use_frags) {
- skb_cb->htt.frag_len = sizeof(*tx_frags) * 2;
- skb_cb->htt.pad_len = (unsigned long)msdu->data -
- round_down((unsigned long)msdu->data, 4);
+ skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len,
+ DMA_TO_DEVICE);
+ res = dma_mapping_error(dev, skb_cb->paddr);
+ if (res)
+ goto err_free_txbuf;
- skb_push(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len);
- } else {
- skb_cb->htt.frag_len = 0;
- skb_cb->htt.pad_len = 0;
- }
+ if (likely(use_frags)) {
+ frags = skb_cb->htt.txbuf->frags;
- res = ath10k_skb_map(dev, msdu);
- if (res)
- goto err_pull_txfrag;
-
- if (use_frags) {
- dma_sync_single_for_cpu(dev, skb_cb->paddr, msdu->len,
- DMA_TO_DEVICE);
-
- /* tx fragment list must be terminated with zero-entry */
- tx_frags = (struct htt_data_tx_desc_frag *)msdu->data;
- tx_frags[0].paddr = __cpu_to_le32(skb_cb->paddr +
- skb_cb->htt.frag_len +
- skb_cb->htt.pad_len);
- tx_frags[0].len = __cpu_to_le32(msdu->len -
- skb_cb->htt.frag_len -
- skb_cb->htt.pad_len);
- tx_frags[1].paddr = __cpu_to_le32(0);
- tx_frags[1].len = __cpu_to_le32(0);
-
- dma_sync_single_for_device(dev, skb_cb->paddr, msdu->len,
- DMA_TO_DEVICE);
- }
+ frags[0].paddr = __cpu_to_le32(skb_cb->paddr);
+ frags[0].len = __cpu_to_le32(msdu->len);
+ frags[1].paddr = 0;
+ frags[1].len = 0;
- ath10k_dbg(ATH10K_DBG_HTT, "msdu 0x%llx\n",
- (unsigned long long) ATH10K_SKB_CB(msdu)->paddr);
- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "msdu: ",
- msdu->data, msdu->len);
+ flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI,
+ HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
- skb_put(txdesc, desc_len);
- cmd = (struct htt_cmd *)txdesc->data;
+ frags_paddr = skb_cb->htt.txbuf_paddr;
+ } else {
+ flags0 |= SM(ATH10K_HW_TXRX_MGMT,
+ HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
- tid = ATH10K_SKB_CB(msdu)->htt.tid;
+ frags_paddr = skb_cb->paddr;
+ }
- ath10k_dbg(ATH10K_DBG_HTT, "htt data tx using tid %hhu\n", tid);
+ /* Normally all commands go through HTC which manages tx credits for
+ * each endpoint and notifies when tx is completed.
+ *
+ * HTT endpoint is creditless so there's no need to care about HTC
+ * flags. In that case it is trivial to fill the HTC header here.
+ *
+ * MSDU transmission is considered completed upon HTT event. This
+ * implies no relevant resources can be freed until after the event is
+ * received. That's why HTC tx completion handler itself is ignored by
+ * setting NULL to transfer_context for all sg items.
+ *
+ * There is simply no point in pushing HTT TX_FRM through HTC tx path
+ * as it's a waste of resources. By bypassing HTC it is possible to
+ * avoid extra memory allocations, compress data structures and thus
+ * improve performance. */
+
+ skb_cb->htt.txbuf->htc_hdr.eid = htt->eid;
+ skb_cb->htt.txbuf->htc_hdr.len = __cpu_to_le16(
+ sizeof(skb_cb->htt.txbuf->cmd_hdr) +
+ sizeof(skb_cb->htt.txbuf->cmd_tx) +
+ prefetch_len);
+ skb_cb->htt.txbuf->htc_hdr.flags = 0;
- flags0 = 0;
if (!ieee80211_has_protected(hdr->frame_control))
flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT;
- flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
- if (use_frags)
- flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI,
- HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
- else
- flags0 |= SM(ATH10K_HW_TXRX_MGMT,
- HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
+ flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
- flags1 = 0;
flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID);
flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID);
flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD;
flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD;
- cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM;
- cmd->data_tx.flags0 = flags0;
- cmd->data_tx.flags1 = __cpu_to_le16(flags1);
- cmd->data_tx.len = __cpu_to_le16(msdu->len -
- skb_cb->htt.frag_len -
- skb_cb->htt.pad_len);
- cmd->data_tx.id = __cpu_to_le16(msdu_id);
- cmd->data_tx.frags_paddr = __cpu_to_le32(skb_cb->paddr);
- cmd->data_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID);
-
- memcpy(cmd->data_tx.prefetch, hdr, prefetch_len);
+ skb_cb->htt.txbuf->cmd_hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM;
+ skb_cb->htt.txbuf->cmd_tx.flags0 = flags0;
+ skb_cb->htt.txbuf->cmd_tx.flags1 = __cpu_to_le16(flags1);
+ skb_cb->htt.txbuf->cmd_tx.len = __cpu_to_le16(msdu->len);
+ skb_cb->htt.txbuf->cmd_tx.id = __cpu_to_le16(msdu_id);
+ skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr);
+ skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID);
+
+ ath10k_dbg(ATH10K_DBG_HTT,
+ "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu\n",
+ flags0, flags1, msdu->len, msdu_id, frags_paddr,
+ (u32)skb_cb->paddr, vdev_id, tid);
+ ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
+ msdu->data, msdu->len);
- res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc);
+ sg_items[0].transfer_id = 0;
+ sg_items[0].transfer_context = NULL;
+ sg_items[0].vaddr = &skb_cb->htt.txbuf->htc_hdr;
+ sg_items[0].paddr = skb_cb->htt.txbuf_paddr +
+ sizeof(skb_cb->htt.txbuf->frags);
+ sg_items[0].len = sizeof(skb_cb->htt.txbuf->htc_hdr) +
+ sizeof(skb_cb->htt.txbuf->cmd_hdr) +
+ sizeof(skb_cb->htt.txbuf->cmd_tx);
+
+ sg_items[1].transfer_id = 0;
+ sg_items[1].transfer_context = NULL;
+ sg_items[1].vaddr = msdu->data;
+ sg_items[1].paddr = skb_cb->paddr;
+ sg_items[1].len = prefetch_len;
+
+ res = ath10k_hif_tx_sg(htt->ar,
+ htt->ar->htc.endpoint[htt->eid].ul_pipe_id,
+ sg_items, ARRAY_SIZE(sg_items));
if (res)
goto err_unmap_msdu;
return 0;
err_unmap_msdu:
- ath10k_skb_unmap(dev, msdu);
-err_pull_txfrag:
- skb_pull(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len);
-err_free_txdesc:
- dev_kfree_skb_any(txdesc);
+ dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
+err_free_txbuf:
+ dma_pool_free(htt->tx_pool,
+ skb_cb->htt.txbuf,
+ skb_cb->htt.txbuf_paddr);
err_free_msdu_id:
spin_lock_bh(&htt->tx_lock);
htt->pending_tx[msdu_id] = NULL;
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index f1505a25d810..35fc44e281f5 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -205,8 +205,11 @@ enum ath10k_mcast2ucast_mode {
#define WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x0006c000
#define PCIE_LOCAL_BASE_ADDRESS 0x00080000
+#define SOC_RESET_CONTROL_ADDRESS 0x00000000
#define SOC_RESET_CONTROL_OFFSET 0x00000000
#define SOC_RESET_CONTROL_SI0_RST_MASK 0x00000001
+#define SOC_RESET_CONTROL_CE_RST_MASK 0x00040000
+#define SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040
#define SOC_CPU_CLOCK_OFFSET 0x00000020
#define SOC_CPU_CLOCK_STANDARD_LSB 0
#define SOC_CPU_CLOCK_STANDARD_MASK 0x00000003
@@ -216,6 +219,8 @@ enum ath10k_mcast2ucast_mode {
#define SOC_LPO_CAL_OFFSET 0x000000e0
#define SOC_LPO_CAL_ENABLE_LSB 20
#define SOC_LPO_CAL_ENABLE_MASK 0x00100000
+#define SOC_LF_TIMER_CONTROL0_ADDRESS 0x00000050
+#define SOC_LF_TIMER_CONTROL0_ENABLE_MASK 0x00000004
#define SOC_CHIP_ID_ADDRESS 0x000000ec
#define SOC_CHIP_ID_REV_LSB 8
@@ -273,6 +278,7 @@ enum ath10k_mcast2ucast_mode {
#define PCIE_INTR_CAUSE_ADDRESS 0x000c
#define PCIE_INTR_CLR_ADDRESS 0x0014
#define SCRATCH_3_ADDRESS 0x0030
+#define CPU_INTR_ADDRESS 0x0010
/* Firmware indications to the Host via SCRATCH_3 register. */
#define FW_INDICATOR_ADDRESS (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS)
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 776e364eadcd..511a2f81e7af 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -323,13 +323,15 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
ret = ath10k_wmi_peer_create(ar, vdev_id, addr);
if (ret) {
- ath10k_warn("Failed to create wmi peer: %i\n", ret);
+ ath10k_warn("Failed to create wmi peer %pM on vdev %i: %i\n",
+ addr, vdev_id, ret);
return ret;
}
ret = ath10k_wait_for_peer_created(ar, vdev_id, addr);
if (ret) {
- ath10k_warn("Failed to wait for created wmi peer: %i\n", ret);
+ ath10k_warn("Failed to wait for created wmi peer %pM on vdev %i: %i\n",
+ addr, vdev_id, ret);
return ret;
}
spin_lock_bh(&ar->data_lock);
@@ -339,6 +341,51 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
return 0;
}
+static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
+{
+ struct ath10k *ar = arvif->ar;
+ u32 param;
+ int ret;
+
+ param = ar->wmi.pdev_param->sta_kickout_th;
+ ret = ath10k_wmi_pdev_set_param(ar, param,
+ ATH10K_KICKOUT_THRESHOLD);
+ if (ret) {
+ ath10k_warn("Failed to set kickout threshold on vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ param = ar->wmi.vdev_param->ap_keepalive_min_idle_inactive_time_secs;
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
+ ATH10K_KEEPALIVE_MIN_IDLE);
+ if (ret) {
+ ath10k_warn("Failed to set keepalive minimum idle time on vdev %i : %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ param = ar->wmi.vdev_param->ap_keepalive_max_idle_inactive_time_secs;
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
+ ATH10K_KEEPALIVE_MAX_IDLE);
+ if (ret) {
+ ath10k_warn("Failed to set keepalive maximum idle time on vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ param = ar->wmi.vdev_param->ap_keepalive_max_unresponsive_time_secs;
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
+ ATH10K_KEEPALIVE_MAX_UNRESPONSIVE);
+ if (ret) {
+ ath10k_warn("Failed to set keepalive maximum unresponsive time on vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)
{
struct ath10k *ar = arvif->ar;
@@ -444,8 +491,7 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
static int ath10k_vdev_start(struct ath10k_vif *arvif)
{
struct ath10k *ar = arvif->ar;
- struct ieee80211_conf *conf = &ar->hw->conf;
- struct ieee80211_channel *channel = conf->chandef.chan;
+ struct cfg80211_chan_def *chandef = &ar->chandef;
struct wmi_vdev_start_request_arg arg = {};
int ret = 0;
@@ -457,16 +503,14 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
arg.dtim_period = arvif->dtim_period;
arg.bcn_intval = arvif->beacon_interval;
- arg.channel.freq = channel->center_freq;
-
- arg.channel.band_center_freq1 = conf->chandef.center_freq1;
-
- arg.channel.mode = chan_to_phymode(&conf->chandef);
+ arg.channel.freq = chandef->chan->center_freq;
+ arg.channel.band_center_freq1 = chandef->center_freq1;
+ arg.channel.mode = chan_to_phymode(chandef);
arg.channel.min_power = 0;
- arg.channel.max_power = channel->max_power * 2;
- arg.channel.max_reg_power = channel->max_reg_power * 2;
- arg.channel.max_antenna_gain = channel->max_antenna_gain * 2;
+ arg.channel.max_power = chandef->chan->max_power * 2;
+ arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
+ arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2;
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
arg.ssid = arvif->u.ap.ssid;
@@ -475,7 +519,7 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
/* For now allow DFS for AP mode */
arg.channel.chan_radar =
- !!(channel->flags & IEEE80211_CHAN_RADAR);
+ !!(chandef->chan->flags & IEEE80211_CHAN_RADAR);
} else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
arg.ssid = arvif->vif->bss_conf.ssid;
arg.ssid_len = arvif->vif->bss_conf.ssid_len;
@@ -488,13 +532,15 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
ret = ath10k_wmi_vdev_start(ar, &arg);
if (ret) {
- ath10k_warn("WMI vdev start failed: ret %d\n", ret);
+ ath10k_warn("WMI vdev %i start failed: ret %d\n",
+ arg.vdev_id, ret);
return ret;
}
ret = ath10k_vdev_setup_sync(ar);
if (ret) {
- ath10k_warn("vdev setup failed %d\n", ret);
+ ath10k_warn("vdev %i setup failed %d\n",
+ arg.vdev_id, ret);
return ret;
}
@@ -512,13 +558,15 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif)
ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id);
if (ret) {
- ath10k_warn("WMI vdev stop failed: ret %d\n", ret);
+ ath10k_warn("WMI vdev %i stop failed: ret %d\n",
+ arvif->vdev_id, ret);
return ret;
}
ret = ath10k_vdev_setup_sync(ar);
if (ret) {
- ath10k_warn("vdev setup failed %d\n", ret);
+ ath10k_warn("vdev %i setup sync failed %d\n",
+ arvif->vdev_id, ret);
return ret;
}
@@ -527,7 +575,8 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif)
static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
{
- struct ieee80211_channel *channel = ar->hw->conf.chandef.chan;
+ struct cfg80211_chan_def *chandef = &ar->chandef;
+ struct ieee80211_channel *channel = chandef->chan;
struct wmi_vdev_start_request_arg arg = {};
int ret = 0;
@@ -540,11 +589,11 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
arg.vdev_id = vdev_id;
arg.channel.freq = channel->center_freq;
- arg.channel.band_center_freq1 = ar->hw->conf.chandef.center_freq1;
+ arg.channel.band_center_freq1 = chandef->center_freq1;
/* TODO setup this dynamically, what in case we
don't have any vifs? */
- arg.channel.mode = chan_to_phymode(&ar->hw->conf.chandef);
+ arg.channel.mode = chan_to_phymode(chandef);
arg.channel.chan_radar =
!!(channel->flags & IEEE80211_CHAN_RADAR);
@@ -555,19 +604,22 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
ret = ath10k_wmi_vdev_start(ar, &arg);
if (ret) {
- ath10k_warn("Monitor vdev start failed: ret %d\n", ret);
+ ath10k_warn("Monitor vdev %i start failed: ret %d\n",
+ vdev_id, ret);
return ret;
}
ret = ath10k_vdev_setup_sync(ar);
if (ret) {
- ath10k_warn("Monitor vdev setup failed %d\n", ret);
+ ath10k_warn("Monitor vdev %i setup failed %d\n",
+ vdev_id, ret);
return ret;
}
ret = ath10k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr);
if (ret) {
- ath10k_warn("Monitor vdev up failed: %d\n", ret);
+ ath10k_warn("Monitor vdev %i up failed: %d\n",
+ vdev_id, ret);
goto vdev_stop;
}
@@ -579,7 +631,8 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
vdev_stop:
ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
if (ret)
- ath10k_warn("Monitor vdev stop failed: %d\n", ret);
+ ath10k_warn("Monitor vdev %i stop failed: %d\n",
+ ar->monitor_vdev_id, ret);
return ret;
}
@@ -602,15 +655,18 @@ static int ath10k_monitor_stop(struct ath10k *ar)
ret = ath10k_wmi_vdev_down(ar, ar->monitor_vdev_id);
if (ret)
- ath10k_warn("Monitor vdev down failed: %d\n", ret);
+ ath10k_warn("Monitor vdev %i down failed: %d\n",
+ ar->monitor_vdev_id, ret);
ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
if (ret)
- ath10k_warn("Monitor vdev stop failed: %d\n", ret);
+ ath10k_warn("Monitor vdev %i stop failed: %d\n",
+ ar->monitor_vdev_id, ret);
ret = ath10k_vdev_setup_sync(ar);
if (ret)
- ath10k_warn("Monitor_down sync failed: %d\n", ret);
+ ath10k_warn("Monitor_down sync failed, vdev %i: %d\n",
+ ar->monitor_vdev_id, ret);
ar->monitor_enabled = false;
return ret;
@@ -640,7 +696,8 @@ static int ath10k_monitor_create(struct ath10k *ar)
WMI_VDEV_TYPE_MONITOR,
0, ar->mac_addr);
if (ret) {
- ath10k_warn("WMI vdev monitor create failed: ret %d\n", ret);
+ ath10k_warn("WMI vdev %i monitor create failed: ret %d\n",
+ ar->monitor_vdev_id, ret);
goto vdev_fail;
}
@@ -669,7 +726,8 @@ static int ath10k_monitor_destroy(struct ath10k *ar)
ret = ath10k_wmi_vdev_delete(ar, ar->monitor_vdev_id);
if (ret) {
- ath10k_warn("WMI vdev monitor delete failed: %d\n", ret);
+ ath10k_warn("WMI vdev %i monitor delete failed: %d\n",
+ ar->monitor_vdev_id, ret);
return ret;
}
@@ -791,6 +849,22 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
if (!info->enable_beacon) {
ath10k_vdev_stop(arvif);
+
+ arvif->is_started = false;
+ arvif->is_up = false;
+
+ spin_lock_bh(&arvif->ar->data_lock);
+ if (arvif->beacon) {
+ dma_unmap_single(arvif->ar->dev,
+ ATH10K_SKB_CB(arvif->beacon)->paddr,
+ arvif->beacon->len, DMA_TO_DEVICE);
+ dev_kfree_skb_any(arvif->beacon);
+
+ arvif->beacon = NULL;
+ arvif->beacon_sent = false;
+ }
+ spin_unlock_bh(&arvif->ar->data_lock);
+
return;
}
@@ -800,12 +874,21 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
if (ret)
return;
- ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, 0, info->bssid);
+ arvif->aid = 0;
+ memcpy(arvif->bssid, info->bssid, ETH_ALEN);
+
+ ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
+ arvif->bssid);
if (ret) {
- ath10k_warn("Failed to bring up VDEV: %d\n",
- arvif->vdev_id);
+ ath10k_warn("Failed to bring up vdev %d: %i\n",
+ arvif->vdev_id, ret);
+ ath10k_vdev_stop(arvif);
return;
}
+
+ arvif->is_started = true;
+ arvif->is_up = true;
+
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
}
@@ -824,18 +907,18 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
ath10k_warn("Failed to delete IBSS self peer:%pM for VDEV:%d ret:%d\n",
self_peer, arvif->vdev_id, ret);
- if (is_zero_ether_addr(arvif->u.ibss.bssid))
+ if (is_zero_ether_addr(arvif->bssid))
return;
ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id,
- arvif->u.ibss.bssid);
+ arvif->bssid);
if (ret) {
ath10k_warn("Failed to delete IBSS BSSID peer:%pM for VDEV:%d ret:%d\n",
- arvif->u.ibss.bssid, arvif->vdev_id, ret);
+ arvif->bssid, arvif->vdev_id, ret);
return;
}
- memset(arvif->u.ibss.bssid, 0, ETH_ALEN);
+ memset(arvif->bssid, 0, ETH_ALEN);
return;
}
@@ -878,8 +961,8 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param,
conf->dynamic_ps_timeout);
if (ret) {
- ath10k_warn("Failed to set inactivity time for VDEV: %d\n",
- arvif->vdev_id);
+ ath10k_warn("Failed to set inactivity time for vdev %d: %i\n",
+ arvif->vdev_id, ret);
return ret;
}
} else {
@@ -1017,7 +1100,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
struct wmi_peer_assoc_complete_arg *arg)
{
const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
- int smps;
int i, n;
lockdep_assert_held(&ar->conf_mutex);
@@ -1063,17 +1145,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
arg->peer_flags |= WMI_PEER_STBC;
}
- smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS;
- smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT;
-
- if (smps == WLAN_HT_CAP_SM_PS_STATIC) {
- arg->peer_flags |= WMI_PEER_SPATIAL_MUX;
- arg->peer_flags |= WMI_PEER_STATIC_MIMOPS;
- } else if (smps == WLAN_HT_CAP_SM_PS_DYNAMIC) {
- arg->peer_flags |= WMI_PEER_SPATIAL_MUX;
- arg->peer_flags |= WMI_PEER_DYN_MIMOPS;
- }
-
if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2])
arg->peer_rate_caps |= WMI_RC_TS_FLAG;
else if (ht_cap->mcs.rx_mask[1])
@@ -1083,8 +1154,23 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
if (ht_cap->mcs.rx_mask[i/8] & (1 << i%8))
arg->peer_ht_rates.rates[n++] = i;
- arg->peer_ht_rates.num_rates = n;
- arg->peer_num_spatial_streams = max((n+7) / 8, 1);
+ /*
+ * This is a workaround for HT-enabled STAs which break the spec
+ * and have no HT capabilities RX mask (no HT RX MCS map).
+ *
+ * As per spec, in section 20.3.5 Modulation and coding scheme (MCS),
+ * MCS 0 through 7 are mandatory in 20MHz with 800 ns GI at all STAs.
+ *
+ * Firmware asserts if such situation occurs.
+ */
+ if (n == 0) {
+ arg->peer_ht_rates.num_rates = 8;
+ for (i = 0; i < arg->peer_ht_rates.num_rates; i++)
+ arg->peer_ht_rates.rates[i] = i;
+ } else {
+ arg->peer_ht_rates.num_rates = n;
+ arg->peer_num_spatial_streams = sta->rx_nss;
+ }
ath10k_dbg(ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
arg->addr,
@@ -1092,27 +1178,20 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
arg->peer_num_spatial_streams);
}
-static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar,
- struct ath10k_vif *arvif,
- struct ieee80211_sta *sta,
- struct ieee80211_bss_conf *bss_conf,
- struct wmi_peer_assoc_complete_arg *arg)
+static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
+ struct ath10k_vif *arvif,
+ struct ieee80211_sta *sta)
{
u32 uapsd = 0;
u32 max_sp = 0;
+ int ret = 0;
lockdep_assert_held(&ar->conf_mutex);
- if (sta->wme)
- arg->peer_flags |= WMI_PEER_QOS;
-
if (sta->wme && sta->uapsd_queues) {
ath10k_dbg(ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n",
sta->uapsd_queues, sta->max_sp);
- arg->peer_flags |= WMI_PEER_APSD;
- arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG;
-
if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN |
WMI_AP_PS_UAPSD_AC3_TRIGGER_EN;
@@ -1130,35 +1209,40 @@ static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar,
if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP)
max_sp = sta->max_sp;
- ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
- sta->addr,
- WMI_AP_PS_PEER_PARAM_UAPSD,
- uapsd);
+ ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
+ sta->addr,
+ WMI_AP_PS_PEER_PARAM_UAPSD,
+ uapsd);
+ if (ret) {
+ ath10k_warn("failed to set ap ps peer param uapsd for vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
- ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
- sta->addr,
- WMI_AP_PS_PEER_PARAM_MAX_SP,
- max_sp);
+ ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
+ sta->addr,
+ WMI_AP_PS_PEER_PARAM_MAX_SP,
+ max_sp);
+ if (ret) {
+ ath10k_warn("failed to set ap ps peer param max sp for vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
/* TODO setup this based on STA listen interval and
beacon interval. Currently we don't know
sta->listen_interval - mac80211 patch required.
Currently use 10 seconds */
- ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
- sta->addr,
- WMI_AP_PS_PEER_PARAM_AGEOUT_TIME,
- 10);
+ ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr,
+ WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, 10);
+ if (ret) {
+ ath10k_warn("failed to set ap ps peer param ageout time for vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
}
-}
-static void ath10k_peer_assoc_h_qos_sta(struct ath10k *ar,
- struct ath10k_vif *arvif,
- struct ieee80211_sta *sta,
- struct ieee80211_bss_conf *bss_conf,
- struct wmi_peer_assoc_complete_arg *arg)
-{
- if (bss_conf->qos)
- arg->peer_flags |= WMI_PEER_QOS;
+ return 0;
}
static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
@@ -1211,10 +1295,17 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
{
switch (arvif->vdev_type) {
case WMI_VDEV_TYPE_AP:
- ath10k_peer_assoc_h_qos_ap(ar, arvif, sta, bss_conf, arg);
+ if (sta->wme)
+ arg->peer_flags |= WMI_PEER_QOS;
+
+ if (sta->wme && sta->uapsd_queues) {
+ arg->peer_flags |= WMI_PEER_APSD;
+ arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG;
+ }
break;
case WMI_VDEV_TYPE_STA:
- ath10k_peer_assoc_h_qos_sta(ar, arvif, sta, bss_conf, arg);
+ if (bss_conf->qos)
+ arg->peer_flags |= WMI_PEER_QOS;
break;
default:
break;
@@ -1293,6 +1384,33 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar,
return 0;
}
+static const u32 ath10k_smps_map[] = {
+ [WLAN_HT_CAP_SM_PS_STATIC] = WMI_PEER_SMPS_STATIC,
+ [WLAN_HT_CAP_SM_PS_DYNAMIC] = WMI_PEER_SMPS_DYNAMIC,
+ [WLAN_HT_CAP_SM_PS_INVALID] = WMI_PEER_SMPS_PS_NONE,
+ [WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE,
+};
+
+static int ath10k_setup_peer_smps(struct ath10k *ar, struct ath10k_vif *arvif,
+ const u8 *addr,
+ const struct ieee80211_sta_ht_cap *ht_cap)
+{
+ int smps;
+
+ if (!ht_cap->ht_supported)
+ return 0;
+
+ smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS;
+ smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT;
+
+ if (smps >= ARRAY_SIZE(ath10k_smps_map))
+ return -EINVAL;
+
+ return ath10k_wmi_peer_set_param(ar, arvif->vdev_id, addr,
+ WMI_PEER_SMPS_STATE,
+ ath10k_smps_map[smps]);
+}
+
/* can be called only in mac80211 callbacks due to `key_count` usage */
static void ath10k_bss_assoc(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
@@ -1300,6 +1418,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
{
struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ struct ieee80211_sta_ht_cap ht_cap;
struct wmi_peer_assoc_complete_arg peer_arg;
struct ieee80211_sta *ap_sta;
int ret;
@@ -1310,17 +1429,21 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
ap_sta = ieee80211_find_sta(vif, bss_conf->bssid);
if (!ap_sta) {
- ath10k_warn("Failed to find station entry for %pM\n",
- bss_conf->bssid);
+ ath10k_warn("Failed to find station entry for %pM, vdev %i\n",
+ bss_conf->bssid, arvif->vdev_id);
rcu_read_unlock();
return;
}
+ /* ap_sta must be accessed only within rcu section which must be left
+ * before calling ath10k_setup_peer_smps() which might sleep. */
+ ht_cap = ap_sta->ht_cap;
+
ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
bss_conf, &peer_arg);
if (ret) {
- ath10k_warn("Peer assoc prepare failed for %pM\n: %d",
- bss_conf->bssid, ret);
+ ath10k_warn("Peer assoc prepare failed for %pM vdev %i\n: %d",
+ bss_conf->bssid, arvif->vdev_id, ret);
rcu_read_unlock();
return;
}
@@ -1329,8 +1452,15 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
ret = ath10k_wmi_peer_assoc(ar, &peer_arg);
if (ret) {
- ath10k_warn("Peer assoc failed for %pM\n: %d",
- bss_conf->bssid, ret);
+ ath10k_warn("Peer assoc failed for %pM vdev %i\n: %d",
+ bss_conf->bssid, arvif->vdev_id, ret);
+ return;
+ }
+
+ ret = ath10k_setup_peer_smps(ar, arvif, bss_conf->bssid, &ht_cap);
+ if (ret) {
+ ath10k_warn("failed to setup peer SMPS for vdev %i: %d\n",
+ arvif->vdev_id, ret);
return;
}
@@ -1338,11 +1468,17 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
"mac vdev %d up (associated) bssid %pM aid %d\n",
arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
- ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, bss_conf->aid,
- bss_conf->bssid);
- if (ret)
+ arvif->aid = bss_conf->aid;
+ memcpy(arvif->bssid, bss_conf->bssid, ETH_ALEN);
+
+ ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid);
+ if (ret) {
ath10k_warn("VDEV: %d up failed: ret %d\n",
arvif->vdev_id, ret);
+ return;
+ }
+
+ arvif->is_up = true;
}
/*
@@ -1382,6 +1518,9 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
arvif->def_wep_key_idx = 0;
+
+ arvif->is_started = false;
+ arvif->is_up = false;
}
static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
@@ -1394,21 +1533,35 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg);
if (ret) {
- ath10k_warn("WMI peer assoc prepare failed for %pM\n",
- sta->addr);
+ ath10k_warn("WMI peer assoc prepare failed for %pM vdev %i: %i\n",
+ sta->addr, arvif->vdev_id, ret);
return ret;
}
ret = ath10k_wmi_peer_assoc(ar, &peer_arg);
if (ret) {
- ath10k_warn("Peer assoc failed for STA %pM\n: %d",
- sta->addr, ret);
+ ath10k_warn("Peer assoc failed for STA %pM vdev %i: %d\n",
+ sta->addr, arvif->vdev_id, ret);
+ return ret;
+ }
+
+ ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap);
+ if (ret) {
+ ath10k_warn("failed to setup peer SMPS for vdev: %d\n", ret);
return ret;
}
ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
if (ret) {
- ath10k_warn("could not install peer wep keys (%d)\n", ret);
+ ath10k_warn("could not install peer wep keys for vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta);
+ if (ret) {
+ ath10k_warn("could not set qos params for STA %pM for vdev %i: %d\n",
+ sta->addr, arvif->vdev_id, ret);
return ret;
}
@@ -1424,7 +1577,8 @@ static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif,
ret = ath10k_clear_peer_keys(arvif, sta->addr);
if (ret) {
- ath10k_warn("could not clear all peer wep keys (%d)\n", ret);
+ ath10k_warn("could not clear all peer wep keys for vdev %i: %d\n",
+ arvif->vdev_id, ret);
return ret;
}
@@ -1547,9 +1701,9 @@ static void ath10k_regd_update(struct ath10k *ar)
/* Target allows setting up per-band regdomain but ath_common provides
* a combined one only */
ret = ath10k_wmi_pdev_set_regdomain(ar,
- regpair->regDmnEnum,
- regpair->regDmnEnum, /* 2ghz */
- regpair->regDmnEnum, /* 5ghz */
+ regpair->reg_domain,
+ regpair->reg_domain, /* 2ghz */
+ regpair->reg_domain, /* 5ghz */
regpair->reg_2ghz_ctl,
regpair->reg_5ghz_ctl);
if (ret)
@@ -2100,11 +2254,29 @@ static int ath10k_start(struct ieee80211_hw *hw)
ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n",
ret);
+ /*
+ * By default FW set ARP frames ac to voice (6). In that case ARP
+ * exchange is not working properly for UAPSD enabled AP. ARP requests
+ * which arrives with access category 0 are processed by network stack
+ * and send back with access category 0, but FW changes access category
+ * to 6. Set ARP frames access category to best effort (0) solves
+ * this problem.
+ */
+
+ ret = ath10k_wmi_pdev_set_param(ar,
+ ar->wmi.pdev_param->arp_ac_override, 0);
+ if (ret) {
+ ath10k_warn("could not set arp ac override parameter: %d\n",
+ ret);
+ goto exit;
+ }
+
ath10k_regd_update(ar);
+ ret = 0;
exit:
mutex_unlock(&ar->conf_mutex);
- return 0;
+ return ret;
}
static void ath10k_stop(struct ieee80211_hw *hw)
@@ -2145,6 +2317,98 @@ static int ath10k_config_ps(struct ath10k *ar)
return ret;
}
+static const char *chandef_get_width(enum nl80211_chan_width width)
+{
+ switch (width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ return "20 (noht)";
+ case NL80211_CHAN_WIDTH_20:
+ return "20";
+ case NL80211_CHAN_WIDTH_40:
+ return "40";
+ case NL80211_CHAN_WIDTH_80:
+ return "80";
+ case NL80211_CHAN_WIDTH_80P80:
+ return "80+80";
+ case NL80211_CHAN_WIDTH_160:
+ return "160";
+ case NL80211_CHAN_WIDTH_5:
+ return "5";
+ case NL80211_CHAN_WIDTH_10:
+ return "10";
+ }
+ return "?";
+}
+
+static void ath10k_config_chan(struct ath10k *ar)
+{
+ struct ath10k_vif *arvif;
+ bool monitor_was_enabled;
+ int ret;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ ath10k_dbg(ATH10K_DBG_MAC,
+ "mac config channel to %dMHz (cf1 %dMHz cf2 %dMHz width %s)\n",
+ ar->chandef.chan->center_freq,
+ ar->chandef.center_freq1,
+ ar->chandef.center_freq2,
+ chandef_get_width(ar->chandef.width));
+
+ /* First stop monitor interface. Some FW versions crash if there's a
+ * lone monitor interface. */
+ monitor_was_enabled = ar->monitor_enabled;
+
+ if (ar->monitor_enabled)
+ ath10k_monitor_stop(ar);
+
+ list_for_each_entry(arvif, &ar->arvifs, list) {
+ if (!arvif->is_started)
+ continue;
+
+ if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
+ continue;
+
+ ret = ath10k_vdev_stop(arvif);
+ if (ret) {
+ ath10k_warn("could not stop vdev %d (%d)\n",
+ arvif->vdev_id, ret);
+ continue;
+ }
+ }
+
+ /* all vdevs are now stopped - now attempt to restart them */
+
+ list_for_each_entry(arvif, &ar->arvifs, list) {
+ if (!arvif->is_started)
+ continue;
+
+ if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
+ continue;
+
+ ret = ath10k_vdev_start(arvif);
+ if (ret) {
+ ath10k_warn("could not start vdev %d (%d)\n",
+ arvif->vdev_id, ret);
+ continue;
+ }
+
+ if (!arvif->is_up)
+ continue;
+
+ ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
+ arvif->bssid);
+ if (ret) {
+ ath10k_warn("could not bring vdev up %d (%d)\n",
+ arvif->vdev_id, ret);
+ continue;
+ }
+ }
+
+ if (monitor_was_enabled)
+ ath10k_monitor_start(ar, ar->monitor_vdev_id);
+}
+
static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
{
struct ath10k *ar = hw->priv;
@@ -2165,6 +2429,11 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
spin_unlock_bh(&ar->data_lock);
ath10k_config_radar_detection(ar);
+
+ if (!cfg80211_chandef_identical(&ar->chandef, &conf->chandef)) {
+ ar->chandef = conf->chandef;
+ ath10k_config_chan(ar);
+ }
}
if (changed & IEEE80211_CONF_CHANGE_POWER) {
@@ -2214,7 +2483,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
enum wmi_sta_powersave_param param;
int ret = 0;
- u32 value, param_id;
+ u32 value;
int bit;
u32 vdev_param;
@@ -2276,7 +2545,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type,
arvif->vdev_subtype, vif->addr);
if (ret) {
- ath10k_warn("WMI vdev create failed: ret %d\n", ret);
+ ath10k_warn("WMI vdev %i create failed: ret %d\n",
+ arvif->vdev_id, ret);
goto err;
}
@@ -2287,7 +2557,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param,
arvif->def_wep_key_idx);
if (ret) {
- ath10k_warn("Failed to set default keyid: %d\n", ret);
+ ath10k_warn("Failed to set vdev %i default keyid: %d\n",
+ arvif->vdev_id, ret);
goto err_vdev_delete;
}
@@ -2296,23 +2567,25 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
ATH10K_HW_TXRX_NATIVE_WIFI);
/* 10.X firmware does not support this VDEV parameter. Do not warn */
if (ret && ret != -EOPNOTSUPP) {
- ath10k_warn("Failed to set TX encap: %d\n", ret);
+ ath10k_warn("Failed to set vdev %i TX encap: %d\n",
+ arvif->vdev_id, ret);
goto err_vdev_delete;
}
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr);
if (ret) {
- ath10k_warn("Failed to create peer for AP: %d\n", ret);
+ ath10k_warn("Failed to create vdev %i peer for AP: %d\n",
+ arvif->vdev_id, ret);
goto err_vdev_delete;
}
- param_id = ar->wmi.pdev_param->sta_kickout_th;
-
- /* Disable STA KICKOUT functionality in FW */
- ret = ath10k_wmi_pdev_set_param(ar, param_id, 0);
- if (ret)
- ath10k_warn("Failed to disable STA KICKOUT\n");
+ ret = ath10k_mac_set_kickout(arvif);
+ if (ret) {
+ ath10k_warn("Failed to set vdev %i kickout parameters: %d\n",
+ arvif->vdev_id, ret);
+ goto err_peer_delete;
+ }
}
if (arvif->vdev_type == WMI_VDEV_TYPE_STA) {
@@ -2321,7 +2594,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
param, value);
if (ret) {
- ath10k_warn("Failed to set RX wake policy: %d\n", ret);
+ ath10k_warn("Failed to set vdev %i RX wake policy: %d\n",
+ arvif->vdev_id, ret);
goto err_peer_delete;
}
@@ -2330,7 +2604,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
param, value);
if (ret) {
- ath10k_warn("Failed to set TX wake thresh: %d\n", ret);
+ ath10k_warn("Failed to set vdev %i TX wake thresh: %d\n",
+ arvif->vdev_id, ret);
goto err_peer_delete;
}
@@ -2339,7 +2614,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
param, value);
if (ret) {
- ath10k_warn("Failed to set PSPOLL count: %d\n", ret);
+ ath10k_warn("Failed to set vdev %i PSPOLL count: %d\n",
+ arvif->vdev_id, ret);
goto err_peer_delete;
}
}
@@ -2403,17 +2679,19 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, vif->addr);
if (ret)
- ath10k_warn("Failed to remove peer for AP: %d\n", ret);
+ ath10k_warn("Failed to remove peer for AP vdev %i: %d\n",
+ arvif->vdev_id, ret);
kfree(arvif->u.ap.noa_data);
}
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev delete %d (remove interface)\n",
+ ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %i delete (remove interface)\n",
arvif->vdev_id);
ret = ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
if (ret)
- ath10k_warn("WMI vdev delete failed: %d\n", ret);
+ ath10k_warn("WMI vdev %i delete failed: %d\n",
+ arvif->vdev_id, ret);
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
ar->monitor_present = false;
@@ -2502,8 +2780,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
arvif->vdev_id, arvif->beacon_interval);
if (ret)
- ath10k_warn("Failed to set beacon interval for VDEV: %d\n",
- arvif->vdev_id);
+ ath10k_warn("Failed to set beacon interval for vdev %d: %i\n",
+ arvif->vdev_id, ret);
}
if (changed & BSS_CHANGED_BEACON) {
@@ -2515,8 +2793,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
ret = ath10k_wmi_pdev_set_param(ar, pdev_param,
WMI_BEACON_STAGGERED_MODE);
if (ret)
- ath10k_warn("Failed to set beacon mode for VDEV: %d\n",
- arvif->vdev_id);
+ ath10k_warn("Failed to set beacon mode for vdev %d: %i\n",
+ arvif->vdev_id, ret);
}
if (changed & BSS_CHANGED_BEACON_INFO) {
@@ -2530,8 +2808,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
arvif->dtim_period);
if (ret)
- ath10k_warn("Failed to set dtim period for VDEV: %d\n",
- arvif->vdev_id);
+ ath10k_warn("Failed to set dtim period for vdev %d: %i\n",
+ arvif->vdev_id, ret);
}
if (changed & BSS_CHANGED_SSID &&
@@ -2551,7 +2829,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
ret = ath10k_peer_create(ar, arvif->vdev_id,
info->bssid);
if (ret)
- ath10k_warn("Failed to add peer %pM for vdev %d when changin bssid: %i\n",
+ ath10k_warn("Failed to add peer %pM for vdev %d when changing bssid: %i\n",
info->bssid, arvif->vdev_id, ret);
if (vif->type == NL80211_IFTYPE_STATION) {
@@ -2559,15 +2837,20 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
* this is never erased as we it for crypto key
* clearing; this is FW requirement
*/
- memcpy(arvif->u.sta.bssid, info->bssid,
- ETH_ALEN);
+ memcpy(arvif->bssid, info->bssid, ETH_ALEN);
ath10k_dbg(ATH10K_DBG_MAC,
"mac vdev %d start %pM\n",
arvif->vdev_id, info->bssid);
- /* FIXME: check return value */
ret = ath10k_vdev_start(arvif);
+ if (ret) {
+ ath10k_warn("failed to start vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ goto exit;
+ }
+
+ arvif->is_started = true;
}
/*
@@ -2576,7 +2859,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
* IBSS in order to remove BSSID peer.
*/
if (vif->type == NL80211_IFTYPE_ADHOC)
- memcpy(arvif->u.ibss.bssid, info->bssid,
+ memcpy(arvif->bssid, info->bssid,
ETH_ALEN);
}
}
@@ -2598,8 +2881,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
cts_prot);
if (ret)
- ath10k_warn("Failed to set CTS prot for VDEV: %d\n",
- arvif->vdev_id);
+ ath10k_warn("Failed to set CTS prot for vdev %d: %d\n",
+ arvif->vdev_id, ret);
}
if (changed & BSS_CHANGED_ERP_SLOT) {
@@ -2617,8 +2900,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
slottime);
if (ret)
- ath10k_warn("Failed to set erp slot for VDEV: %d\n",
- arvif->vdev_id);
+ ath10k_warn("Failed to set erp slot for vdev %d: %i\n",
+ arvif->vdev_id, ret);
}
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
@@ -2636,8 +2919,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
preamble);
if (ret)
- ath10k_warn("Failed to set preamble for VDEV: %d\n",
- arvif->vdev_id);
+ ath10k_warn("Failed to set preamble for vdev %d: %i\n",
+ arvif->vdev_id, ret);
}
if (changed & BSS_CHANGED_ASSOC) {
@@ -2645,6 +2928,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
ath10k_bss_assoc(hw, vif, info);
}
+exit:
mutex_unlock(&ar->conf_mutex);
}
@@ -2767,8 +3051,8 @@ static void ath10k_set_key_h_def_keyidx(struct ath10k *ar,
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
key->keyidx);
if (ret)
- ath10k_warn("failed to set group key as default key: %d\n",
- ret);
+ ath10k_warn("failed to set vdev %i group key as default key: %d\n",
+ arvif->vdev_id, ret);
}
static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
@@ -2828,7 +3112,8 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
ret = ath10k_install_key(arvif, key, cmd, peer_addr);
if (ret) {
- ath10k_warn("ath10k_install_key failed (%d)\n", ret);
+ ath10k_warn("key installation failed for vdev %i peer %pM: %d\n",
+ arvif->vdev_id, peer_addr, ret);
goto exit;
}
@@ -2850,6 +3135,69 @@ exit:
return ret;
}
+static void ath10k_sta_rc_update_wk(struct work_struct *wk)
+{
+ struct ath10k *ar;
+ struct ath10k_vif *arvif;
+ struct ath10k_sta *arsta;
+ struct ieee80211_sta *sta;
+ u32 changed, bw, nss, smps;
+ int err;
+
+ arsta = container_of(wk, struct ath10k_sta, update_wk);
+ sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv);
+ arvif = arsta->arvif;
+ ar = arvif->ar;
+
+ spin_lock_bh(&ar->data_lock);
+
+ changed = arsta->changed;
+ arsta->changed = 0;
+
+ bw = arsta->bw;
+ nss = arsta->nss;
+ smps = arsta->smps;
+
+ spin_unlock_bh(&ar->data_lock);
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (changed & IEEE80211_RC_BW_CHANGED) {
+ ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n",
+ sta->addr, bw);
+
+ err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
+ WMI_PEER_CHAN_WIDTH, bw);
+ if (err)
+ ath10k_warn("failed to update STA %pM peer bw %d: %d\n",
+ sta->addr, bw, err);
+ }
+
+ if (changed & IEEE80211_RC_NSS_CHANGED) {
+ ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM nss %d\n",
+ sta->addr, nss);
+
+ err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
+ WMI_PEER_NSS, nss);
+ if (err)
+ ath10k_warn("failed to update STA %pM nss %d: %d\n",
+ sta->addr, nss, err);
+ }
+
+ if (changed & IEEE80211_RC_SMPS_CHANGED) {
+ ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM smps %d\n",
+ sta->addr, smps);
+
+ err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
+ WMI_PEER_SMPS_STATE, smps);
+ if (err)
+ ath10k_warn("failed to update STA %pM smps %d: %d\n",
+ sta->addr, smps, err);
+ }
+
+ mutex_unlock(&ar->conf_mutex);
+}
+
static int ath10k_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -2858,9 +3206,22 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
{
struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
int max_num_peers;
int ret = 0;
+ if (old_state == IEEE80211_STA_NOTEXIST &&
+ new_state == IEEE80211_STA_NONE) {
+ memset(arsta, 0, sizeof(*arsta));
+ arsta->arvif = arvif;
+ INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk);
+ }
+
+ /* cancel must be done outside the mutex to avoid deadlock */
+ if ((old_state == IEEE80211_STA_NONE &&
+ new_state == IEEE80211_STA_NOTEXIST))
+ cancel_work_sync(&arsta->update_wk);
+
mutex_lock(&ar->conf_mutex);
if (old_state == IEEE80211_STA_NOTEXIST &&
@@ -2899,8 +3260,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
arvif->vdev_id, sta->addr);
ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
if (ret)
- ath10k_warn("Failed to delete peer: %pM for VDEV: %d\n",
- sta->addr, arvif->vdev_id);
+ ath10k_warn("Failed to delete peer %pM for vdev %d: %i\n",
+ sta->addr, arvif->vdev_id, ret);
if (vif->type == NL80211_IFTYPE_STATION)
ath10k_bss_disassoc(hw, vif);
@@ -2916,8 +3277,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
ret = ath10k_station_assoc(ar, arvif, sta);
if (ret)
- ath10k_warn("Failed to associate station: %pM\n",
- sta->addr);
+ ath10k_warn("Failed to associate station %pM for vdev %i: %i\n",
+ sta->addr, arvif->vdev_id, ret);
} else if (old_state == IEEE80211_STA_ASSOC &&
new_state == IEEE80211_STA_AUTH &&
(vif->type == NL80211_IFTYPE_AP ||
@@ -2930,8 +3291,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
ret = ath10k_station_disassoc(ar, arvif, sta);
if (ret)
- ath10k_warn("Failed to disassociate station: %pM\n",
- sta->addr);
+ ath10k_warn("Failed to disassociate station: %pM vdev %i ret %i\n",
+ sta->addr, arvif->vdev_id, ret);
}
exit:
mutex_unlock(&ar->conf_mutex);
@@ -3212,7 +3573,8 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
}), ATH10K_FLUSH_TIMEOUT_HZ);
if (ret <= 0 || skip)
- ath10k_warn("tx not flushed\n");
+ ath10k_warn("tx not flushed (skip %i ar-state %i): %i\n",
+ skip, ar->state, ret);
skip:
mutex_unlock(&ar->conf_mutex);
@@ -3234,23 +3596,14 @@ static int ath10k_suspend(struct ieee80211_hw *hw,
struct ath10k *ar = hw->priv;
int ret;
- ar->is_target_paused = false;
+ mutex_lock(&ar->conf_mutex);
- ret = ath10k_wmi_pdev_suspend_target(ar);
+ ret = ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND);
if (ret) {
- ath10k_warn("could not suspend target (%d)\n", ret);
- return 1;
- }
-
- ret = wait_event_interruptible_timeout(ar->event_queue,
- ar->is_target_paused == true,
- 1 * HZ);
- if (ret < 0) {
- ath10k_warn("suspend interrupted (%d)\n", ret);
- goto resume;
- } else if (ret == 0) {
- ath10k_warn("suspend timed out - target pause event never came\n");
- goto resume;
+ if (ret == -ETIMEDOUT)
+ goto resume;
+ ret = 1;
+ goto exit;
}
ret = ath10k_hif_suspend(ar);
@@ -3259,12 +3612,17 @@ static int ath10k_suspend(struct ieee80211_hw *hw,
goto resume;
}
- return 0;
+ ret = 0;
+ goto exit;
resume:
ret = ath10k_wmi_pdev_resume_target(ar);
if (ret)
ath10k_warn("could not resume target (%d)\n", ret);
- return 1;
+
+ ret = 1;
+exit:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
}
static int ath10k_resume(struct ieee80211_hw *hw)
@@ -3272,19 +3630,26 @@ static int ath10k_resume(struct ieee80211_hw *hw)
struct ath10k *ar = hw->priv;
int ret;
+ mutex_lock(&ar->conf_mutex);
+
ret = ath10k_hif_resume(ar);
if (ret) {
ath10k_warn("could not resume hif (%d)\n", ret);
- return 1;
+ ret = 1;
+ goto exit;
}
ret = ath10k_wmi_pdev_resume_target(ar);
if (ret) {
ath10k_warn("could not resume target (%d)\n", ret);
- return 1;
+ ret = 1;
+ goto exit;
}
- return 0;
+ ret = 0;
+exit:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
}
#endif
@@ -3575,7 +3940,8 @@ static bool ath10k_get_fixed_rate_nss(const struct cfg80211_bitrate_mask *mask,
static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
u8 fixed_rate,
- u8 fixed_nss)
+ u8 fixed_nss,
+ u8 force_sgi)
{
struct ath10k *ar = arvif->ar;
u32 vdev_param;
@@ -3584,12 +3950,16 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
mutex_lock(&ar->conf_mutex);
if (arvif->fixed_rate == fixed_rate &&
- arvif->fixed_nss == fixed_nss)
+ arvif->fixed_nss == fixed_nss &&
+ arvif->force_sgi == force_sgi)
goto exit;
if (fixed_rate == WMI_FIXED_RATE_NONE)
ath10k_dbg(ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n");
+ if (force_sgi)
+ ath10k_dbg(ATH10K_DBG_MAC, "mac force sgi\n");
+
vdev_param = ar->wmi.vdev_param->fixed_rate;
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
vdev_param, fixed_rate);
@@ -3615,6 +3985,19 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
arvif->fixed_nss = fixed_nss;
+ vdev_param = ar->wmi.vdev_param->sgi;
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
+ force_sgi);
+
+ if (ret) {
+ ath10k_warn("Could not set sgi param %d: %d\n",
+ force_sgi, ret);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ arvif->force_sgi = force_sgi;
+
exit:
mutex_unlock(&ar->conf_mutex);
return ret;
@@ -3629,6 +4012,11 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw,
enum ieee80211_band band = ar->hw->conf.chandef.chan->band;
u8 fixed_rate = WMI_FIXED_RATE_NONE;
u8 fixed_nss = ar->num_rf_chains;
+ u8 force_sgi;
+
+ force_sgi = mask->control[band].gi;
+ if (force_sgi == NL80211_TXRATE_FORCE_LGI)
+ return -EINVAL;
if (!ath10k_default_bitrate_mask(ar, band, mask)) {
if (!ath10k_get_fixed_rate_nss(mask, band,
@@ -3637,7 +4025,113 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw,
return -EINVAL;
}
- return ath10k_set_fixed_rate_param(arvif, fixed_rate, fixed_nss);
+ if (fixed_rate == WMI_FIXED_RATE_NONE && force_sgi) {
+ ath10k_warn("Could not force SGI usage for default rate settings\n");
+ return -EINVAL;
+ }
+
+ return ath10k_set_fixed_rate_param(arvif, fixed_rate,
+ fixed_nss, force_sgi);
+}
+
+static void ath10k_channel_switch_beacon(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_chan_def *chandef)
+{
+ /* there's no need to do anything here. vif->csa_active is enough */
+ return;
+}
+
+static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ u32 changed)
+{
+ struct ath10k *ar = hw->priv;
+ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+ u32 bw, smps;
+
+ spin_lock_bh(&ar->data_lock);
+
+ ath10k_dbg(ATH10K_DBG_MAC,
+ "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n",
+ sta->addr, changed, sta->bandwidth, sta->rx_nss,
+ sta->smps_mode);
+
+ if (changed & IEEE80211_RC_BW_CHANGED) {
+ bw = WMI_PEER_CHWIDTH_20MHZ;
+
+ switch (sta->bandwidth) {
+ case IEEE80211_STA_RX_BW_20:
+ bw = WMI_PEER_CHWIDTH_20MHZ;
+ break;
+ case IEEE80211_STA_RX_BW_40:
+ bw = WMI_PEER_CHWIDTH_40MHZ;
+ break;
+ case IEEE80211_STA_RX_BW_80:
+ bw = WMI_PEER_CHWIDTH_80MHZ;
+ break;
+ case IEEE80211_STA_RX_BW_160:
+ ath10k_warn("mac sta rc update for %pM: invalid bw %d\n",
+ sta->addr, sta->bandwidth);
+ bw = WMI_PEER_CHWIDTH_20MHZ;
+ break;
+ }
+
+ arsta->bw = bw;
+ }
+
+ if (changed & IEEE80211_RC_NSS_CHANGED)
+ arsta->nss = sta->rx_nss;
+
+ if (changed & IEEE80211_RC_SMPS_CHANGED) {
+ smps = WMI_PEER_SMPS_PS_NONE;
+
+ switch (sta->smps_mode) {
+ case IEEE80211_SMPS_AUTOMATIC:
+ case IEEE80211_SMPS_OFF:
+ smps = WMI_PEER_SMPS_PS_NONE;
+ break;
+ case IEEE80211_SMPS_STATIC:
+ smps = WMI_PEER_SMPS_STATIC;
+ break;
+ case IEEE80211_SMPS_DYNAMIC:
+ smps = WMI_PEER_SMPS_DYNAMIC;
+ break;
+ case IEEE80211_SMPS_NUM_MODES:
+ ath10k_warn("mac sta rc update for %pM: invalid smps: %d\n",
+ sta->addr, sta->smps_mode);
+ smps = WMI_PEER_SMPS_PS_NONE;
+ break;
+ }
+
+ arsta->smps = smps;
+ }
+
+ if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
+ /* FIXME: Not implemented. Probably the only way to do it would
+ * be to re-assoc the peer. */
+ changed &= ~IEEE80211_RC_SUPP_RATES_CHANGED;
+ ath10k_dbg(ATH10K_DBG_MAC,
+ "mac sta rc update for %pM: changing supported rates not implemented\n",
+ sta->addr);
+ }
+
+ arsta->changed |= changed;
+
+ spin_unlock_bh(&ar->data_lock);
+
+ ieee80211_queue_work(hw, &arsta->update_wk);
+}
+
+static u64 ath10k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+ /*
+ * FIXME: Return 0 for time being. Need to figure out whether FW
+ * has the API to fetch 64-bit local TSF
+ */
+
+ return 0;
}
static const struct ieee80211_ops ath10k_ops = {
@@ -3663,6 +4157,9 @@ static const struct ieee80211_ops ath10k_ops = {
.restart_complete = ath10k_restart_complete,
.get_survey = ath10k_get_survey,
.set_bitrate_mask = ath10k_set_bitrate_mask,
+ .channel_switch_beacon = ath10k_channel_switch_beacon,
+ .sta_rc_update = ath10k_sta_rc_update,
+ .get_tsf = ath10k_get_tsf,
#ifdef CONFIG_PM
.suspend = ath10k_suspend,
.resume = ath10k_resume,
@@ -3939,7 +4436,7 @@ struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id)
ath10k_get_arvif_iter,
&arvif_iter);
if (!arvif_iter.arvif) {
- ath10k_warn("No VIF found for VDEV: %d\n", vdev_id);
+ ath10k_warn("No VIF found for vdev %d\n", vdev_id);
return NULL;
}
@@ -4020,7 +4517,8 @@ int ath10k_mac_register(struct ath10k *ar)
IEEE80211_HW_HAS_RATE_CONTROL |
IEEE80211_HW_SUPPORTS_STATIC_SMPS |
IEEE80211_HW_WANT_MONITOR_VIF |
- IEEE80211_HW_AP_LINK_PS;
+ IEEE80211_HW_AP_LINK_PS |
+ IEEE80211_HW_SPECTRUM_MGMT;
/* MSDU can have HTT TX fragment pushed in front. The additional 4
* bytes is used for padding/alignment if necessary. */
@@ -4038,10 +4536,12 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN;
ar->hw->vif_data_size = sizeof(struct ath10k_vif);
+ ar->hw->sta_data_size = sizeof(struct ath10k_sta);
ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL;
ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+ ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
ar->hw->wiphy->max_remain_on_channel_duration = 5000;
ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
@@ -4076,7 +4576,7 @@ int ath10k_mac_register(struct ath10k *ar)
ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy,
ath10k_reg_notifier);
if (ret) {
- ath10k_err("Regulatory initialization failed\n");
+ ath10k_err("Regulatory initialization failed: %i\n", ret);
goto err_free;
}
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 29fd197d1fd8..9d242d801d9d 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -58,13 +58,12 @@ static DEFINE_PCI_DEVICE_TABLE(ath10k_pci_id_table) = {
static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address,
u32 *data);
-static void ath10k_pci_process_ce(struct ath10k *ar);
static int ath10k_pci_post_rx(struct ath10k *ar);
static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
int num);
static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info);
-static void ath10k_pci_stop_ce(struct ath10k *ar);
-static int ath10k_pci_device_reset(struct ath10k *ar);
+static int ath10k_pci_cold_reset(struct ath10k *ar);
+static int ath10k_pci_warm_reset(struct ath10k *ar);
static int ath10k_pci_wait_for_target_init(struct ath10k *ar);
static int ath10k_pci_init_irq(struct ath10k *ar);
static int ath10k_pci_deinit_irq(struct ath10k *ar);
@@ -73,7 +72,6 @@ static void ath10k_pci_free_irq(struct ath10k *ar);
static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe,
struct ath10k_ce_pipe *rx_pipe,
struct bmi_xfer *xfer);
-static void ath10k_pci_cleanup_ce(struct ath10k *ar);
static const struct ce_attr host_ce_config_wlan[] = {
/* CE0: host->target HTC control and raw streams */
@@ -678,34 +676,12 @@ void ath10k_do_pci_sleep(struct ath10k *ar)
}
}
-/*
- * FIXME: Handle OOM properly.
- */
-static inline
-struct ath10k_pci_compl *get_free_compl(struct ath10k_pci_pipe *pipe_info)
-{
- struct ath10k_pci_compl *compl = NULL;
-
- spin_lock_bh(&pipe_info->pipe_lock);
- if (list_empty(&pipe_info->compl_free)) {
- ath10k_warn("Completion buffers are full\n");
- goto exit;
- }
- compl = list_first_entry(&pipe_info->compl_free,
- struct ath10k_pci_compl, list);
- list_del(&compl->list);
-exit:
- spin_unlock_bh(&pipe_info->pipe_lock);
- return compl;
-}
-
/* Called by lower (CE) layer when a send to Target completes. */
static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state)
{
struct ath10k *ar = ce_state->ar;
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id];
- struct ath10k_pci_compl *compl;
+ struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current;
void *transfer_context;
u32 ce_data;
unsigned int nbytes;
@@ -714,27 +690,12 @@ static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state)
while (ath10k_ce_completed_send_next(ce_state, &transfer_context,
&ce_data, &nbytes,
&transfer_id) == 0) {
- compl = get_free_compl(pipe_info);
- if (!compl)
- break;
-
- compl->state = ATH10K_PCI_COMPL_SEND;
- compl->ce_state = ce_state;
- compl->pipe_info = pipe_info;
- compl->skb = transfer_context;
- compl->nbytes = nbytes;
- compl->transfer_id = transfer_id;
- compl->flags = 0;
+ /* no need to call tx completion for NULL pointers */
+ if (transfer_context == NULL)
+ continue;
- /*
- * Add the completion to the processing queue.
- */
- spin_lock_bh(&ar_pci->compl_lock);
- list_add_tail(&compl->list, &ar_pci->compl_process);
- spin_unlock_bh(&ar_pci->compl_lock);
+ cb->tx_completion(ar, transfer_context, transfer_id);
}
-
- ath10k_pci_process_ce(ar);
}
/* Called by lower (CE) layer when data is received from the Target. */
@@ -743,77 +704,100 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
struct ath10k *ar = ce_state->ar;
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id];
- struct ath10k_pci_compl *compl;
+ struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current;
struct sk_buff *skb;
void *transfer_context;
u32 ce_data;
- unsigned int nbytes;
+ unsigned int nbytes, max_nbytes;
unsigned int transfer_id;
unsigned int flags;
+ int err;
while (ath10k_ce_completed_recv_next(ce_state, &transfer_context,
&ce_data, &nbytes, &transfer_id,
&flags) == 0) {
- compl = get_free_compl(pipe_info);
- if (!compl)
- break;
-
- compl->state = ATH10K_PCI_COMPL_RECV;
- compl->ce_state = ce_state;
- compl->pipe_info = pipe_info;
- compl->skb = transfer_context;
- compl->nbytes = nbytes;
- compl->transfer_id = transfer_id;
- compl->flags = flags;
+ err = ath10k_pci_post_rx_pipe(pipe_info, 1);
+ if (unlikely(err)) {
+ /* FIXME: retry */
+ ath10k_warn("failed to replenish CE rx ring %d: %d\n",
+ pipe_info->pipe_num, err);
+ }
skb = transfer_context;
+ max_nbytes = skb->len + skb_tailroom(skb);
dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr,
- skb->len + skb_tailroom(skb),
- DMA_FROM_DEVICE);
- /*
- * Add the completion to the processing queue.
- */
- spin_lock_bh(&ar_pci->compl_lock);
- list_add_tail(&compl->list, &ar_pci->compl_process);
- spin_unlock_bh(&ar_pci->compl_lock);
- }
+ max_nbytes, DMA_FROM_DEVICE);
+
+ if (unlikely(max_nbytes < nbytes)) {
+ ath10k_warn("rxed more than expected (nbytes %d, max %d)",
+ nbytes, max_nbytes);
+ dev_kfree_skb_any(skb);
+ continue;
+ }
- ath10k_pci_process_ce(ar);
+ skb_put(skb, nbytes);
+ cb->rx_completion(ar, skb, pipe_info->pipe_num);
+ }
}
-/* Send the first nbytes bytes of the buffer */
-static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id,
- unsigned int transfer_id,
- unsigned int bytes, struct sk_buff *nbuf)
+static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
+ struct ath10k_hif_sg_item *items, int n_items)
{
- struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(nbuf);
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- struct ath10k_pci_pipe *pipe_info = &(ar_pci->pipe_info[pipe_id]);
- struct ath10k_ce_pipe *ce_hdl = pipe_info->ce_hdl;
- unsigned int len;
- u32 flags = 0;
- int ret;
+ struct ath10k_pci_pipe *pci_pipe = &ar_pci->pipe_info[pipe_id];
+ struct ath10k_ce_pipe *ce_pipe = pci_pipe->ce_hdl;
+ struct ath10k_ce_ring *src_ring = ce_pipe->src_ring;
+ unsigned int nentries_mask = src_ring->nentries_mask;
+ unsigned int sw_index = src_ring->sw_index;
+ unsigned int write_index = src_ring->write_index;
+ int err, i;
- len = min(bytes, nbuf->len);
- bytes -= len;
+ spin_lock_bh(&ar_pci->ce_lock);
- if (len & 3)
- ath10k_warn("skb not aligned to 4-byte boundary (%d)\n", len);
+ if (unlikely(CE_RING_DELTA(nentries_mask,
+ write_index, sw_index - 1) < n_items)) {
+ err = -ENOBUFS;
+ goto unlock;
+ }
- ath10k_dbg(ATH10K_DBG_PCI,
- "pci send data vaddr %p paddr 0x%llx len %d as %d bytes\n",
- nbuf->data, (unsigned long long) skb_cb->paddr,
- nbuf->len, len);
- ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL,
- "ath10k tx: data: ",
- nbuf->data, nbuf->len);
-
- ret = ath10k_ce_send(ce_hdl, nbuf, skb_cb->paddr, len, transfer_id,
- flags);
- if (ret)
- ath10k_warn("failed to send sk_buff to CE: %p\n", nbuf);
+ for (i = 0; i < n_items - 1; i++) {
+ ath10k_dbg(ATH10K_DBG_PCI,
+ "pci tx item %d paddr 0x%08x len %d n_items %d\n",
+ i, items[i].paddr, items[i].len, n_items);
+ ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ",
+ items[i].vaddr, items[i].len);
- return ret;
+ err = ath10k_ce_send_nolock(ce_pipe,
+ items[i].transfer_context,
+ items[i].paddr,
+ items[i].len,
+ items[i].transfer_id,
+ CE_SEND_FLAG_GATHER);
+ if (err)
+ goto unlock;
+ }
+
+ /* `i` is equal to `n_items -1` after for() */
+
+ ath10k_dbg(ATH10K_DBG_PCI,
+ "pci tx item %d paddr 0x%08x len %d n_items %d\n",
+ i, items[i].paddr, items[i].len, n_items);
+ ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ",
+ items[i].vaddr, items[i].len);
+
+ err = ath10k_ce_send_nolock(ce_pipe,
+ items[i].transfer_context,
+ items[i].paddr,
+ items[i].len,
+ items[i].transfer_id,
+ 0);
+ if (err)
+ goto unlock;
+
+ err = 0;
+unlock:
+ spin_unlock_bh(&ar_pci->ce_lock);
+ return err;
}
static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
@@ -833,9 +817,7 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar)
ath10k_err("firmware crashed!\n");
ath10k_err("hardware name %s version 0x%x\n",
ar->hw_params.name, ar->target_version);
- ath10k_err("firmware version: %u.%u.%u.%u\n", ar->fw_version_major,
- ar->fw_version_minor, ar->fw_version_release,
- ar->fw_version_build);
+ ath10k_err("firmware version: %s\n", ar->hw->wiphy->fw_version);
host_addr = host_interest_item_address(HI_ITEM(hi_failure_state));
ret = ath10k_pci_diag_read_mem(ar, host_addr,
@@ -904,52 +886,6 @@ static void ath10k_pci_hif_set_callbacks(struct ath10k *ar,
sizeof(ar_pci->msg_callbacks_current));
}
-static int ath10k_pci_alloc_compl(struct ath10k *ar)
-{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- const struct ce_attr *attr;
- struct ath10k_pci_pipe *pipe_info;
- struct ath10k_pci_compl *compl;
- int i, pipe_num, completions;
-
- spin_lock_init(&ar_pci->compl_lock);
- INIT_LIST_HEAD(&ar_pci->compl_process);
-
- for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
- pipe_info = &ar_pci->pipe_info[pipe_num];
-
- spin_lock_init(&pipe_info->pipe_lock);
- INIT_LIST_HEAD(&pipe_info->compl_free);
-
- /* Handle Diagnostic CE specially */
- if (pipe_info->ce_hdl == ar_pci->ce_diag)
- continue;
-
- attr = &host_ce_config_wlan[pipe_num];
- completions = 0;
-
- if (attr->src_nentries)
- completions += attr->src_nentries;
-
- if (attr->dest_nentries)
- completions += attr->dest_nentries;
-
- for (i = 0; i < completions; i++) {
- compl = kmalloc(sizeof(*compl), GFP_KERNEL);
- if (!compl) {
- ath10k_warn("No memory for completion state\n");
- ath10k_pci_cleanup_ce(ar);
- return -ENOMEM;
- }
-
- compl->state = ATH10K_PCI_COMPL_FREE;
- list_add_tail(&compl->list, &pipe_info->compl_free);
- }
- }
-
- return 0;
-}
-
static int ath10k_pci_setup_ce_irq(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -994,147 +930,6 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar)
tasklet_kill(&ar_pci->pipe_info[i].intr);
}
-static void ath10k_pci_stop_ce(struct ath10k *ar)
-{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- struct ath10k_pci_compl *compl;
- struct sk_buff *skb;
-
- /* Mark pending completions as aborted, so that upper layers free up
- * their associated resources */
- spin_lock_bh(&ar_pci->compl_lock);
- list_for_each_entry(compl, &ar_pci->compl_process, list) {
- skb = compl->skb;
- ATH10K_SKB_CB(skb)->is_aborted = true;
- }
- spin_unlock_bh(&ar_pci->compl_lock);
-}
-
-static void ath10k_pci_cleanup_ce(struct ath10k *ar)
-{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- struct ath10k_pci_compl *compl, *tmp;
- struct ath10k_pci_pipe *pipe_info;
- struct sk_buff *netbuf;
- int pipe_num;
-
- /* Free pending completions. */
- spin_lock_bh(&ar_pci->compl_lock);
- if (!list_empty(&ar_pci->compl_process))
- ath10k_warn("pending completions still present! possible memory leaks.\n");
-
- list_for_each_entry_safe(compl, tmp, &ar_pci->compl_process, list) {
- list_del(&compl->list);
- netbuf = compl->skb;
- dev_kfree_skb_any(netbuf);
- kfree(compl);
- }
- spin_unlock_bh(&ar_pci->compl_lock);
-
- /* Free unused completions for each pipe. */
- for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
- pipe_info = &ar_pci->pipe_info[pipe_num];
-
- spin_lock_bh(&pipe_info->pipe_lock);
- list_for_each_entry_safe(compl, tmp,
- &pipe_info->compl_free, list) {
- list_del(&compl->list);
- kfree(compl);
- }
- spin_unlock_bh(&pipe_info->pipe_lock);
- }
-}
-
-static void ath10k_pci_process_ce(struct ath10k *ar)
-{
- struct ath10k_pci *ar_pci = ar->hif.priv;
- struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current;
- struct ath10k_pci_compl *compl;
- struct sk_buff *skb;
- unsigned int nbytes;
- int ret, send_done = 0;
-
- /* Upper layers aren't ready to handle tx/rx completions in parallel so
- * we must serialize all completion processing. */
-
- spin_lock_bh(&ar_pci->compl_lock);
- if (ar_pci->compl_processing) {
- spin_unlock_bh(&ar_pci->compl_lock);
- return;
- }
- ar_pci->compl_processing = true;
- spin_unlock_bh(&ar_pci->compl_lock);
-
- for (;;) {
- spin_lock_bh(&ar_pci->compl_lock);
- if (list_empty(&ar_pci->compl_process)) {
- spin_unlock_bh(&ar_pci->compl_lock);
- break;
- }
- compl = list_first_entry(&ar_pci->compl_process,
- struct ath10k_pci_compl, list);
- list_del(&compl->list);
- spin_unlock_bh(&ar_pci->compl_lock);
-
- switch (compl->state) {
- case ATH10K_PCI_COMPL_SEND:
- cb->tx_completion(ar,
- compl->skb,
- compl->transfer_id);
- send_done = 1;
- break;
- case ATH10K_PCI_COMPL_RECV:
- ret = ath10k_pci_post_rx_pipe(compl->pipe_info, 1);
- if (ret) {
- ath10k_warn("failed to post RX buffer for pipe %d: %d\n",
- compl->pipe_info->pipe_num, ret);
- break;
- }
-
- skb = compl->skb;
- nbytes = compl->nbytes;
-
- ath10k_dbg(ATH10K_DBG_PCI,
- "ath10k_pci_ce_recv_data netbuf=%p nbytes=%d\n",
- skb, nbytes);
- ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL,
- "ath10k rx: ", skb->data, nbytes);
-
- if (skb->len + skb_tailroom(skb) >= nbytes) {
- skb_trim(skb, 0);
- skb_put(skb, nbytes);
- cb->rx_completion(ar, skb,
- compl->pipe_info->pipe_num);
- } else {
- ath10k_warn("rxed more than expected (nbytes %d, max %d)",
- nbytes,
- skb->len + skb_tailroom(skb));
- }
- break;
- case ATH10K_PCI_COMPL_FREE:
- ath10k_warn("free completion cannot be processed\n");
- break;
- default:
- ath10k_warn("invalid completion state (%d)\n",
- compl->state);
- break;
- }
-
- compl->state = ATH10K_PCI_COMPL_FREE;
-
- /*
- * Add completion back to the pipe's free list.
- */
- spin_lock_bh(&compl->pipe_info->pipe_lock);
- list_add_tail(&compl->list, &compl->pipe_info->compl_free);
- spin_unlock_bh(&compl->pipe_info->pipe_lock);
- }
-
- spin_lock_bh(&ar_pci->compl_lock);
- ar_pci->compl_processing = false;
- spin_unlock_bh(&ar_pci->compl_lock);
-}
-
/* TODO - temporary mapping while we have too few CE's */
static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar,
u16 service_id, u8 *ul_pipe,
@@ -1306,17 +1101,11 @@ static int ath10k_pci_hif_start(struct ath10k *ar)
ath10k_pci_free_early_irq(ar);
ath10k_pci_kill_tasklet(ar);
- ret = ath10k_pci_alloc_compl(ar);
- if (ret) {
- ath10k_warn("failed to allocate CE completions: %d\n", ret);
- goto err_early_irq;
- }
-
ret = ath10k_pci_request_irq(ar);
if (ret) {
ath10k_warn("failed to post RX buffers for all pipes: %d\n",
ret);
- goto err_free_compl;
+ goto err_early_irq;
}
ret = ath10k_pci_setup_ce_irq(ar);
@@ -1340,10 +1129,6 @@ err_stop:
ath10k_ce_disable_interrupts(ar);
ath10k_pci_free_irq(ar);
ath10k_pci_kill_tasklet(ar);
- ath10k_pci_stop_ce(ar);
- ath10k_pci_process_ce(ar);
-err_free_compl:
- ath10k_pci_cleanup_ce(ar);
err_early_irq:
/* Though there should be no interrupts (device was reset)
* power_down() expects the early IRQ to be installed as per the
@@ -1414,18 +1199,10 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
while (ath10k_ce_cancel_send_next(ce_hdl, (void **)&netbuf,
&ce_data, &nbytes, &id) == 0) {
- /*
- * Indicate the completion to higer layer to free
- * the buffer
- */
-
- if (!netbuf) {
- ath10k_warn("invalid sk_buff on CE %d - NULL pointer. firmware crashed?\n",
- ce_hdl->id);
+ /* no need to call tx completion for NULL pointers */
+ if (!netbuf)
continue;
- }
- ATH10K_SKB_CB(netbuf)->is_aborted = true;
ar_pci->msg_callbacks_current.tx_completion(ar,
netbuf,
id);
@@ -1483,7 +1260,6 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
ath10k_pci_free_irq(ar);
ath10k_pci_kill_tasklet(ar);
- ath10k_pci_stop_ce(ar);
ret = ath10k_pci_request_early_irq(ar);
if (ret)
@@ -1493,8 +1269,6 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
* not DMA nor interrupt. We process the leftovers and then free
* everything else up. */
- ath10k_pci_process_ce(ar);
- ath10k_pci_cleanup_ce(ar);
ath10k_pci_buffer_cleanup(ar);
/* Make the sure the device won't access any structures on the host by
@@ -1502,7 +1276,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
* configuration during init. If ringbuffers are freed and the device
* were to access them this could lead to memory corruption on the
* host. */
- ath10k_pci_device_reset(ar);
+ ath10k_pci_warm_reset(ar);
ar_pci->started = 0;
}
@@ -1993,7 +1767,94 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
ath10k_pci_sleep(ar);
}
-static int ath10k_pci_hif_power_up(struct ath10k *ar)
+static int ath10k_pci_warm_reset(struct ath10k *ar)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ int ret = 0;
+ u32 val;
+
+ ath10k_dbg(ATH10K_DBG_BOOT, "boot performing warm chip reset\n");
+
+ ret = ath10k_do_pci_wake(ar);
+ if (ret) {
+ ath10k_err("failed to wake up target: %d\n", ret);
+ return ret;
+ }
+
+ /* debug */
+ val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+ PCIE_INTR_CAUSE_ADDRESS);
+ ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val);
+
+ val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+ CPU_INTR_ADDRESS);
+ ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
+ val);
+
+ /* disable pending irqs */
+ ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
+ PCIE_INTR_ENABLE_ADDRESS, 0);
+
+ ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
+ PCIE_INTR_CLR_ADDRESS, ~0);
+
+ msleep(100);
+
+ /* clear fw indicator */
+ ath10k_pci_write32(ar, ar_pci->fw_indicator_address, 0);
+
+ /* clear target LF timer interrupts */
+ val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
+ SOC_LF_TIMER_CONTROL0_ADDRESS);
+ ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS +
+ SOC_LF_TIMER_CONTROL0_ADDRESS,
+ val & ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK);
+
+ /* reset CE */
+ val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
+ SOC_RESET_CONTROL_ADDRESS);
+ ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS,
+ val | SOC_RESET_CONTROL_CE_RST_MASK);
+ val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
+ SOC_RESET_CONTROL_ADDRESS);
+ msleep(10);
+
+ /* unreset CE */
+ ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS,
+ val & ~SOC_RESET_CONTROL_CE_RST_MASK);
+ val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
+ SOC_RESET_CONTROL_ADDRESS);
+ msleep(10);
+
+ /* debug */
+ val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+ PCIE_INTR_CAUSE_ADDRESS);
+ ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val);
+
+ val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+ CPU_INTR_ADDRESS);
+ ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
+ val);
+
+ /* CPU warm reset */
+ val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
+ SOC_RESET_CONTROL_ADDRESS);
+ ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS,
+ val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK);
+
+ val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
+ SOC_RESET_CONTROL_ADDRESS);
+ ath10k_dbg(ATH10K_DBG_BOOT, "boot target reset state: 0x%08x\n", val);
+
+ msleep(100);
+
+ ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset complete\n");
+
+ ath10k_do_pci_sleep(ar);
+ return ret;
+}
+
+static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
const char *irq_mode;
@@ -2009,7 +1870,11 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
* is in an unexpected state. We try to catch that here in order to
* reset the Target and retry the probe.
*/
- ret = ath10k_pci_device_reset(ar);
+ if (cold_reset)
+ ret = ath10k_pci_cold_reset(ar);
+ else
+ ret = ath10k_pci_warm_reset(ar);
+
if (ret) {
ath10k_err("failed to reset target: %d\n", ret);
goto err;
@@ -2079,7 +1944,7 @@ err_deinit_irq:
ath10k_pci_deinit_irq(ar);
err_ce:
ath10k_pci_ce_deinit(ar);
- ath10k_pci_device_reset(ar);
+ ath10k_pci_warm_reset(ar);
err_ps:
if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
ath10k_do_pci_sleep(ar);
@@ -2087,6 +1952,34 @@ err:
return ret;
}
+static int ath10k_pci_hif_power_up(struct ath10k *ar)
+{
+ int ret;
+
+ /*
+ * Hardware CUS232 version 2 has some issues with cold reset and the
+ * preferred (and safer) way to perform a device reset is through a
+ * warm reset.
+ *
+ * Warm reset doesn't always work though (notably after a firmware
+ * crash) so fall back to cold reset if necessary.
+ */
+ ret = __ath10k_pci_hif_power_up(ar, false);
+ if (ret) {
+ ath10k_warn("failed to power up target using warm reset (%d), trying cold reset\n",
+ ret);
+
+ ret = __ath10k_pci_hif_power_up(ar, true);
+ if (ret) {
+ ath10k_err("failed to power up target using cold reset too (%d)\n",
+ ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static void ath10k_pci_hif_power_down(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -2094,7 +1987,7 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar)
ath10k_pci_free_early_irq(ar);
ath10k_pci_kill_tasklet(ar);
ath10k_pci_deinit_irq(ar);
- ath10k_pci_device_reset(ar);
+ ath10k_pci_warm_reset(ar);
ath10k_pci_ce_deinit(ar);
if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
@@ -2151,7 +2044,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
#endif
static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
- .send_head = ath10k_pci_hif_send_head,
+ .tx_sg = ath10k_pci_hif_tx_sg,
.exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg,
.start = ath10k_pci_hif_start,
.stop = ath10k_pci_hif_stop,
@@ -2411,11 +2304,10 @@ static int ath10k_pci_init_irq(struct ath10k *ar)
/* Try MSI-X */
if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO && msix_supported) {
ar_pci->num_msi_intrs = MSI_NUM_REQUEST;
- ret = pci_enable_msi_block(ar_pci->pdev, ar_pci->num_msi_intrs);
- if (ret == 0)
- return 0;
+ ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs,
+ ar_pci->num_msi_intrs);
if (ret > 0)
- pci_disable_msi(ar_pci->pdev);
+ return 0;
/* fall-through */
}
@@ -2482,6 +2374,8 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
case MSI_NUM_REQUEST:
pci_disable_msi(ar_pci->pdev);
return 0;
+ default:
+ pci_disable_msi(ar_pci->pdev);
}
ath10k_warn("unknown irq configuration upon deinit\n");
@@ -2523,7 +2417,7 @@ out:
return ret;
}
-static int ath10k_pci_device_reset(struct ath10k *ar)
+static int ath10k_pci_cold_reset(struct ath10k *ar)
{
int i, ret;
u32 val;
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h
index a4f32038c440..b43fdb4f7319 100644
--- a/drivers/net/wireless/ath/ath10k/pci.h
+++ b/drivers/net/wireless/ath/ath10k/pci.h
@@ -43,23 +43,6 @@ struct bmi_xfer {
u32 resp_len;
};
-enum ath10k_pci_compl_state {
- ATH10K_PCI_COMPL_FREE = 0,
- ATH10K_PCI_COMPL_SEND,
- ATH10K_PCI_COMPL_RECV,
-};
-
-struct ath10k_pci_compl {
- struct list_head list;
- enum ath10k_pci_compl_state state;
- struct ath10k_ce_pipe *ce_state;
- struct ath10k_pci_pipe *pipe_info;
- struct sk_buff *skb;
- unsigned int nbytes;
- unsigned int transfer_id;
- unsigned int flags;
-};
-
/*
* PCI-specific Target state
*
@@ -175,9 +158,6 @@ struct ath10k_pci_pipe {
/* protects compl_free and num_send_allowed */
spinlock_t pipe_lock;
- /* List of free CE completion slots */
- struct list_head compl_free;
-
struct ath10k_pci *ar_pci;
struct tasklet_struct intr;
};
@@ -205,14 +185,6 @@ struct ath10k_pci {
atomic_t keep_awake_count;
bool verified_awake;
- /* List of CE completions to be processed */
- struct list_head compl_process;
-
- /* protects compl_processing and compl_process */
- spinlock_t compl_lock;
-
- bool compl_processing;
-
struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX];
struct ath10k_hif_cb msg_callbacks_current;
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index 74f45fa6f428..0541dd939ce9 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -51,7 +51,8 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
struct ieee80211_tx_info *info;
struct ath10k_skb_cb *skb_cb;
struct sk_buff *msdu;
- int ret;
+
+ lockdep_assert_held(&htt->tx_lock);
ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n",
tx_done->msdu_id, !!tx_done->discard, !!tx_done->no_ack);
@@ -65,12 +66,12 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
msdu = htt->pending_tx[tx_done->msdu_id];
skb_cb = ATH10K_SKB_CB(msdu);
- ret = ath10k_skb_unmap(dev, msdu);
- if (ret)
- ath10k_warn("data skb unmap failed (%d)\n", ret);
+ dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
- if (skb_cb->htt.frag_len)
- skb_pull(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len);
+ if (skb_cb->htt.txbuf)
+ dma_pool_free(htt->tx_pool,
+ skb_cb->htt.txbuf,
+ skb_cb->htt.txbuf_paddr);
ath10k_report_offchan_tx(htt->ar, msdu);
@@ -92,13 +93,11 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
/* we do not own the msdu anymore */
exit:
- spin_lock_bh(&htt->tx_lock);
htt->pending_tx[tx_done->msdu_id] = NULL;
ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
__ath10k_htt_tx_dec_pending(htt);
if (htt->num_pending_tx == 0)
wake_up(&htt->empty_tx_wq);
- spin_unlock_bh(&htt->tx_lock);
}
static const u8 rx_legacy_rate_idx[] = {
@@ -204,7 +203,7 @@ static void process_rx_rates(struct ath10k *ar, struct htt_rx_info *info,
break;
/* 80MHZ */
case 2:
- status->flag |= RX_FLAG_80MHZ;
+ status->vht_flag |= RX_VHT_FLAG_80MHZ;
}
status->flag |= RX_FLAG_VHT;
@@ -258,20 +257,26 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info)
status->band = ch->band;
status->freq = ch->center_freq;
+ if (info->rate.info0 & HTT_RX_INDICATION_INFO0_END_VALID) {
+ /* TSF available only in 32-bit */
+ status->mactime = info->tsf & 0xffffffff;
+ status->flag |= RX_FLAG_MACTIME_END;
+ }
+
ath10k_dbg(ATH10K_DBG_DATA,
- "rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u\n",
+ "rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i\n",
info->skb,
info->skb->len,
status->flag == 0 ? "legacy" : "",
status->flag & RX_FLAG_HT ? "ht" : "",
status->flag & RX_FLAG_VHT ? "vht" : "",
status->flag & RX_FLAG_40MHZ ? "40" : "",
- status->flag & RX_FLAG_80MHZ ? "80" : "",
+ status->vht_flag & RX_VHT_FLAG_80MHZ ? "80" : "",
status->flag & RX_FLAG_SHORT_GI ? "sgi " : "",
status->rate_idx,
status->vht_nss,
status->freq,
- status->band);
+ status->band, status->flag, info->fcs_err);
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
info->skb->data, info->skb->len);
@@ -378,7 +383,8 @@ void ath10k_peer_unmap_event(struct ath10k_htt *htt,
spin_lock_bh(&ar->data_lock);
peer = ath10k_peer_find_by_id(ar, ev->peer_id);
if (!peer) {
- ath10k_warn("unknown peer id %d\n", ev->peer_id);
+ ath10k_warn("peer-unmap-event: unknown peer id %d\n",
+ ev->peer_id);
goto exit;
}
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 712a606a080a..cb1f7b5bcf4c 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -213,7 +213,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = {
.p2p_go_set_beacon_ie = WMI_10X_P2P_GO_SET_BEACON_IE,
.p2p_go_set_probe_resp_ie = WMI_10X_P2P_GO_SET_PROBE_RESP_IE,
.p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED,
- .ap_ps_peer_param_cmdid = WMI_CMD_UNSUPPORTED,
+ .ap_ps_peer_param_cmdid = WMI_10X_AP_PS_PEER_PARAM_CMDID,
.ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED,
.peer_rate_retry_sched_cmdid = WMI_10X_PEER_RATE_RETRY_SCHED_CMDID,
.wlan_profile_trigger_cmdid = WMI_10X_WLAN_PROFILE_TRIGGER_CMDID,
@@ -420,7 +420,6 @@ static struct wmi_pdev_param_map wmi_pdev_param_map = {
.bcnflt_stats_update_period = WMI_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD,
.pmf_qos = WMI_PDEV_PARAM_PMF_QOS,
.arp_ac_override = WMI_PDEV_PARAM_ARP_AC_OVERRIDE,
- .arpdhcp_ac_override = WMI_PDEV_PARAM_UNSUPPORTED,
.dcs = WMI_PDEV_PARAM_DCS,
.ani_enable = WMI_PDEV_PARAM_ANI_ENABLE,
.ani_poll_period = WMI_PDEV_PARAM_ANI_POLL_PERIOD,
@@ -472,8 +471,7 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = {
.bcnflt_stats_update_period =
WMI_10X_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD,
.pmf_qos = WMI_10X_PDEV_PARAM_PMF_QOS,
- .arp_ac_override = WMI_PDEV_PARAM_UNSUPPORTED,
- .arpdhcp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE,
+ .arp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE,
.dcs = WMI_10X_PDEV_PARAM_DCS,
.ani_enable = WMI_10X_PDEV_PARAM_ANI_ENABLE,
.ani_poll_period = WMI_10X_PDEV_PARAM_ANI_POLL_PERIOD,
@@ -561,7 +559,6 @@ err_pull:
static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif)
{
- struct wmi_bcn_tx_arg arg = {0};
int ret;
lockdep_assert_held(&arvif->ar->data_lock);
@@ -569,18 +566,16 @@ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif)
if (arvif->beacon == NULL)
return;
- arg.vdev_id = arvif->vdev_id;
- arg.tx_rate = 0;
- arg.tx_power = 0;
- arg.bcn = arvif->beacon->data;
- arg.bcn_len = arvif->beacon->len;
+ if (arvif->beacon_sent)
+ return;
- ret = ath10k_wmi_beacon_send_nowait(arvif->ar, &arg);
+ ret = ath10k_wmi_beacon_send_ref_nowait(arvif);
if (ret)
return;
- dev_kfree_skb_any(arvif->beacon);
- arvif->beacon = NULL;
+ /* We need to retain the arvif->beacon reference for DMA unmapping and
+ * freeing the skbuff later. */
+ arvif->beacon_sent = true;
}
static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac,
@@ -1116,7 +1111,27 @@ static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar,
static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_PEER_STA_KICKOUT_EVENTID\n");
+ struct wmi_peer_sta_kickout_event *ev;
+ struct ieee80211_sta *sta;
+
+ ev = (struct wmi_peer_sta_kickout_event *)skb->data;
+
+ ath10k_dbg(ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n",
+ ev->peer_macaddr.addr);
+
+ rcu_read_lock();
+
+ sta = ieee80211_find_sta_by_ifaddr(ar->hw, ev->peer_macaddr.addr, NULL);
+ if (!sta) {
+ ath10k_warn("Spurious quick kickout for STA %pM\n",
+ ev->peer_macaddr.addr);
+ goto exit;
+ }
+
+ ieee80211_report_low_ack(sta, 10);
+
+exit:
+ rcu_read_unlock();
}
/*
@@ -1217,6 +1232,13 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
tim->bitmap_ctrl = !!__le32_to_cpu(bcn_info->tim_info.tim_mcast);
memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len);
+ if (tim->dtim_count == 0) {
+ ATH10K_SKB_CB(bcn)->bcn.dtim_zero = true;
+
+ if (__le32_to_cpu(bcn_info->tim_info.tim_mcast) == 1)
+ ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true;
+ }
+
ath10k_dbg(ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n",
tim->dtim_count, tim->dtim_period,
tim->bitmap_ctrl, pvm_len);
@@ -1338,7 +1360,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
struct wmi_bcn_info *bcn_info;
struct ath10k_vif *arvif;
struct sk_buff *bcn;
- int vdev_id = 0;
+ int ret, vdev_id = 0;
ath10k_dbg(ATH10K_DBG_MGMT, "WMI_HOST_SWBA_EVENTID\n");
@@ -1385,6 +1407,17 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
continue;
}
+ /* There are no completions for beacons so wait for next SWBA
+ * before telling mac80211 to decrement CSA counter
+ *
+ * Once CSA counter is completed stop sending beacons until
+ * actual channel switch is done */
+ if (arvif->vif->csa_active &&
+ ieee80211_csa_is_complete(arvif->vif)) {
+ ieee80211_csa_finish(arvif->vif);
+ continue;
+ }
+
bcn = ieee80211_beacon_get(ar->hw, arvif->vif);
if (!bcn) {
ath10k_warn("could not get mac80211 beacon\n");
@@ -1396,15 +1429,33 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info);
spin_lock_bh(&ar->data_lock);
+
if (arvif->beacon) {
- ath10k_warn("SWBA overrun on vdev %d\n",
- arvif->vdev_id);
+ if (!arvif->beacon_sent)
+ ath10k_warn("SWBA overrun on vdev %d\n",
+ arvif->vdev_id);
+
+ dma_unmap_single(arvif->ar->dev,
+ ATH10K_SKB_CB(arvif->beacon)->paddr,
+ arvif->beacon->len, DMA_TO_DEVICE);
dev_kfree_skb_any(arvif->beacon);
}
+ ATH10K_SKB_CB(bcn)->paddr = dma_map_single(arvif->ar->dev,
+ bcn->data, bcn->len,
+ DMA_TO_DEVICE);
+ ret = dma_mapping_error(arvif->ar->dev,
+ ATH10K_SKB_CB(bcn)->paddr);
+ if (ret) {
+ ath10k_warn("failed to map beacon: %d\n", ret);
+ goto skip;
+ }
+
arvif->beacon = bcn;
+ arvif->beacon_sent = false;
ath10k_wmi_tx_beacon_nowait(arvif);
+skip:
spin_unlock_bh(&ar->data_lock);
}
}
@@ -2031,11 +2082,11 @@ static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb)
memcpy(ar->mac_addr, ev->mac_addr.addr, ETH_ALEN);
ath10k_dbg(ATH10K_DBG_WMI,
- "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d\n",
+ "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d skb->len %i ev-sz %zu\n",
__le32_to_cpu(ev->sw_version),
__le32_to_cpu(ev->abi_version),
ev->mac_addr.addr,
- __le32_to_cpu(ev->status));
+ __le32_to_cpu(ev->status), skb->len, sizeof(*ev));
complete(&ar->wmi.unified_ready);
return 0;
@@ -2403,7 +2454,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
ar->wmi.cmd->pdev_set_channel_cmdid);
}
-int ath10k_wmi_pdev_suspend_target(struct ath10k *ar)
+int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt)
{
struct wmi_pdev_suspend_cmd *cmd;
struct sk_buff *skb;
@@ -2413,7 +2464,7 @@ int ath10k_wmi_pdev_suspend_target(struct ath10k *ar)
return -ENOMEM;
cmd = (struct wmi_pdev_suspend_cmd *)skb->data;
- cmd->suspend_opt = WMI_PDEV_SUSPEND;
+ cmd->suspend_opt = __cpu_to_le32(suspend_opt);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_suspend_cmdid);
}
@@ -3342,7 +3393,6 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar,
ci->max_power = ch->max_power;
ci->reg_power = ch->max_reg_power;
ci->antenna_max = ch->max_antenna_gain;
- ci->antenna_max = 0;
/* mode & flags share storage */
ci->mode = ch->mode;
@@ -3411,25 +3461,41 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar,
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid);
}
-int ath10k_wmi_beacon_send_nowait(struct ath10k *ar,
- const struct wmi_bcn_tx_arg *arg)
+/* This function assumes the beacon is already DMA mapped */
+int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif)
{
- struct wmi_bcn_tx_cmd *cmd;
+ struct wmi_bcn_tx_ref_cmd *cmd;
struct sk_buff *skb;
+ struct sk_buff *beacon = arvif->beacon;
+ struct ath10k *ar = arvif->ar;
+ struct ieee80211_hdr *hdr;
int ret;
+ u16 fc;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->bcn_len);
+ skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
if (!skb)
return -ENOMEM;
- cmd = (struct wmi_bcn_tx_cmd *)skb->data;
- cmd->hdr.vdev_id = __cpu_to_le32(arg->vdev_id);
- cmd->hdr.tx_rate = __cpu_to_le32(arg->tx_rate);
- cmd->hdr.tx_power = __cpu_to_le32(arg->tx_power);
- cmd->hdr.bcn_len = __cpu_to_le32(arg->bcn_len);
- memcpy(cmd->bcn, arg->bcn, arg->bcn_len);
+ hdr = (struct ieee80211_hdr *)beacon->data;
+ fc = le16_to_cpu(hdr->frame_control);
+
+ cmd = (struct wmi_bcn_tx_ref_cmd *)skb->data;
+ cmd->vdev_id = __cpu_to_le32(arvif->vdev_id);
+ cmd->data_len = __cpu_to_le32(beacon->len);
+ cmd->data_ptr = __cpu_to_le32(ATH10K_SKB_CB(beacon)->paddr);
+ cmd->msdu_id = 0;
+ cmd->frame_control = __cpu_to_le32(fc);
+ cmd->flags = 0;
+
+ if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero)
+ cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO);
+
+ if (ATH10K_SKB_CB(beacon)->bcn.deliver_cab)
+ cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB);
+
+ ret = ath10k_wmi_cmd_send_nowait(ar, skb,
+ ar->wmi.cmd->pdev_send_bcn_cmdid);
- ret = ath10k_wmi_cmd_send_nowait(ar, skb, ar->wmi.cmd->bcn_tx_cmdid);
if (ret)
dev_kfree_skb(skb);
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 4b5e7d3d32b6..4fcc96aa9513 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -2277,7 +2277,6 @@ struct wmi_pdev_param_map {
u32 bcnflt_stats_update_period;
u32 pmf_qos;
u32 arp_ac_override;
- u32 arpdhcp_ac_override;
u32 dcs;
u32 ani_enable;
u32 ani_poll_period;
@@ -3403,6 +3402,24 @@ struct wmi_bcn_tx_arg {
const void *bcn;
};
+enum wmi_bcn_tx_ref_flags {
+ WMI_BCN_TX_REF_FLAG_DTIM_ZERO = 0x1,
+ WMI_BCN_TX_REF_FLAG_DELIVER_CAB = 0x2,
+};
+
+struct wmi_bcn_tx_ref_cmd {
+ __le32 vdev_id;
+ __le32 data_len;
+ /* physical address of the frame - dma pointer */
+ __le32 data_ptr;
+ /* id for host to track */
+ __le32 msdu_id;
+ /* frame ctrl to setup PPDU desc */
+ __le32 frame_control;
+ /* to control CABQ traffic: WMI_BCN_TX_REF_FLAG_ */
+ __le32 flags;
+} __packed;
+
/* Beacon filter */
#define WMI_BCN_FILTER_ALL 0 /* Filter all beacons */
#define WMI_BCN_FILTER_NONE 1 /* Pass all beacons */
@@ -3859,6 +3876,12 @@ enum wmi_peer_smps_state {
WMI_PEER_SMPS_DYNAMIC = 0x2
};
+enum wmi_peer_chwidth {
+ WMI_PEER_CHWIDTH_20MHZ = 0,
+ WMI_PEER_CHWIDTH_40MHZ = 1,
+ WMI_PEER_CHWIDTH_80MHZ = 2,
+};
+
enum wmi_peer_param {
WMI_PEER_SMPS_STATE = 0x1, /* see %wmi_peer_smps_state */
WMI_PEER_AMPDU = 0x2,
@@ -4039,6 +4062,10 @@ struct wmi_chan_info_event {
__le32 cycle_count;
} __packed;
+struct wmi_peer_sta_kickout_event {
+ struct wmi_mac_addr peer_macaddr;
+} __packed;
+
#define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0)
/* FIXME: empirically extrapolated */
@@ -4172,7 +4199,7 @@ int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar);
int ath10k_wmi_connect_htc_service(struct ath10k *ar);
int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
const struct wmi_channel_arg *);
-int ath10k_wmi_pdev_suspend_target(struct ath10k *ar);
+int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt);
int ath10k_wmi_pdev_resume_target(struct ath10k *ar);
int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
u16 rd5g, u16 ctl2g, u16 ctl5g);
@@ -4219,8 +4246,7 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
enum wmi_ap_ps_peer_param param_id, u32 value);
int ath10k_wmi_scan_chan_list(struct ath10k *ar,
const struct wmi_scan_chan_list_arg *arg);
-int ath10k_wmi_beacon_send_nowait(struct ath10k *ar,
- const struct wmi_bcn_tx_arg *arg);
+int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif);
int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
const struct wmi_pdev_set_wmm_params_arg *arg);
int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id);
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index ef35da84f63b..4b18434ba697 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -751,6 +751,9 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf,
bf->skbaddr = dma_map_single(ah->dev, skb->data, skb->len,
DMA_TO_DEVICE);
+ if (dma_mapping_error(ah->dev, bf->skbaddr))
+ return -ENOSPC;
+
ieee80211_get_tx_rates(info->control.vif, (control) ? control->sta : NULL, skb, bf->rates,
ARRAY_SIZE(bf->rates));
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
index 4ee01f654235..afb23b3cc7be 100644
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -681,6 +681,7 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
survey->channel = conf->chandef.chan;
survey->noise = ah->ah_noise_floor;
survey->filled = SURVEY_INFO_NOISE_DBM |
+ SURVEY_INFO_IN_USE |
SURVEY_INFO_CHANNEL_TIME |
SURVEY_INFO_CHANNEL_TIME_BUSY |
SURVEY_INFO_CHANNEL_TIME_RX |
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index d6bc7cb61bfb..1a2973b7acf2 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -110,7 +110,7 @@ ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band)
ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20));
if (ah->ah_version == AR5K_AR5210) {
- srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf;
+ srev = (ath5k_hw_reg_read(ah, AR5K_PHY(256)) >> 28) & 0xf;
ret = (u16)ath5k_hw_bitswap(srev, 4) + 1;
} else {
srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff;
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index fd4c89df67e1..c2c6f4604958 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -790,7 +790,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
if (nw_type & ADHOC_NETWORK) {
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
nw_type & ADHOC_CREATOR ? "creator" : "joiner");
- cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
+ cfg80211_ibss_joined(vif->ndev, bssid, chan, GFP_KERNEL);
cfg80211_put_bss(ar->wiphy, bss);
return;
}
@@ -861,13 +861,9 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
}
if (vif->nw_type & ADHOC_NETWORK) {
- if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
+ if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC)
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"%s: ath6k not in ibss mode\n", __func__);
- return;
- }
- memset(bssid, 0, ETH_ALEN);
- cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
return;
}
@@ -3256,6 +3252,15 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
struct ath6kl_vif *vif = netdev_priv(dev);
u16 interval;
int ret, rssi_thold;
+ int n_match_sets = request->n_match_sets;
+
+ /*
+ * If there's a matchset w/o an SSID, then assume it's just for
+ * the RSSI (nothing else is currently supported) and ignore it.
+ * The device only supports a global RSSI filter that we set below.
+ */
+ if (n_match_sets == 1 && !request->match_sets[0].ssid.ssid_len)
+ n_match_sets = 0;
if (ar->state != ATH6KL_STATE_ON)
return -EIO;
@@ -3268,11 +3273,11 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
request->n_ssids,
request->match_sets,
- request->n_match_sets);
+ n_match_sets);
if (ret < 0)
return ret;
- if (!request->n_match_sets) {
+ if (!n_match_sets) {
ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
ALL_BSS_FILTER, 0);
if (ret < 0)
@@ -3286,12 +3291,12 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD,
ar->fw_capabilities)) {
- if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)
+ if (request->min_rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)
rssi_thold = 0;
- else if (request->rssi_thold < -127)
+ else if (request->min_rssi_thold < -127)
rssi_thold = -127;
else
- rssi_thold = request->rssi_thold;
+ rssi_thold = request->min_rssi_thold;
ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx,
rssi_thold);
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c
index f38ff6a6255e..56c3fd5cef65 100644
--- a/drivers/net/wireless/ath/ath6kl/usb.c
+++ b/drivers/net/wireless/ath/ath6kl/usb.c
@@ -24,7 +24,7 @@
/* constants */
#define TX_URB_COUNT 32
#define RX_URB_COUNT 32
-#define ATH6KL_USB_RX_BUFFER_SIZE 1700
+#define ATH6KL_USB_RX_BUFFER_SIZE 4096
/* tx/rx pipes for usb */
enum ATH6KL_USB_PIPE_ID {
@@ -481,8 +481,8 @@ static void ath6kl_usb_start_recv_pipes(struct ath6kl_usb *ar_usb)
* ATH6KL_USB_RX_BUFFER_SIZE);
*/
- ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh =
- ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_alloc / 2;
+ ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh = 1;
+
ath6kl_usb_post_recv_transfers(&ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA],
ATH6KL_USB_RX_BUFFER_SIZE);
}
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 4f16d79c9eb1..8b4ce28e3ce8 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -914,7 +914,7 @@ ath6kl_get_regpair(u16 regdmn)
return NULL;
for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
- if (regDomainPairs[i].regDmnEnum == regdmn)
+ if (regDomainPairs[i].reg_domain == regdmn)
return &regDomainPairs[i];
}
@@ -954,7 +954,7 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)
country = ath6kl_regd_find_country_by_rd((u16) reg_code);
if (regpair)
ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n",
- regpair->regDmnEnum);
+ regpair->reg_domain);
else
ath6kl_warn("Regpair not found reg_code 0x%0x\n",
reg_code);
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index 7b96b3e5712d..8fcc029a76a6 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -120,18 +120,6 @@ config ATH9K_WOW
This option enables Wake on Wireless LAN support for certain cards.
Currently, AR9462 is supported.
-config ATH9K_LEGACY_RATE_CONTROL
- bool "Atheros ath9k rate control"
- depends on ATH9K
- default n
- ---help---
- Say Y, if you want to use the ath9k specific rate control
- module instead of minstrel_ht. Be warned that there are various
- issues with the ath9k RC and minstrel is a more robust algorithm.
- Note that even if this option is selected, "ath9k_rate_control"
- has to be passed to mac80211 using the module parameter,
- ieee80211_default_rc_algo.
-
config ATH9K_RFKILL
bool "Atheros ath9k rfkill support" if EXPERT
depends on ATH9K
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index a40e5c5d7418..8e1c7b0fe76c 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -8,7 +8,6 @@ ath9k-y += beacon.o \
antenna.o
ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o
-ath9k-$(CONFIG_ATH9K_LEGACY_RATE_CONTROL) += rc.o
ath9k-$(CONFIG_ATH9K_PCI) += pci.o
ath9k-$(CONFIG_ATH9K_AHB) += ahb.o
ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o
@@ -52,7 +51,9 @@ ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \
obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o
obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o
-ath9k_common-y:= common.o
+ath9k_common-y:= common.o \
+ common-init.o \
+ common-beacon.o
ath9k_htc-y += htc_hst.o \
hif_usb.o \
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 2dff2765769b..a0398fe3eb28 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -39,6 +39,10 @@ static const struct platform_device_id ath9k_platform_id_table[] = {
.name = "qca955x_wmac",
.driver_data = AR9300_DEVID_QCA955X,
},
+ {
+ .name = "qca953x_wmac",
+ .driver_data = AR9300_DEVID_AR953X,
+ },
{},
};
@@ -82,6 +86,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
int irq;
int ret = 0;
struct ath_hw *ah;
+ struct ath_common *common;
char hw_name[64];
if (!dev_get_platdata(&pdev->dev)) {
@@ -124,9 +129,6 @@ static int ath_ahb_probe(struct platform_device *pdev)
sc->mem = mem;
sc->irq = irq;
- /* Will be cleared in ath9k_start() */
- set_bit(SC_OP_INVALID, &sc->sc_flags);
-
ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc);
if (ret) {
dev_err(&pdev->dev, "request_irq failed\n");
@@ -144,6 +146,9 @@ static int ath_ahb_probe(struct platform_device *pdev)
wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n",
hw_name, (unsigned long)mem, irq);
+ common = ath9k_hw_common(sc->sc_ah);
+ /* Will be cleared in ath9k_start() */
+ set_bit(ATH_OP_INVALID, &common->op_flags);
return 0;
err_irq:
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index d28923b7435b..6d47783f2e5b 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -176,16 +176,26 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,
if (ah->opmode == NL80211_IFTYPE_STATION &&
BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH)
weak_sig = true;
-
/*
- * OFDM Weak signal detection is always enabled for AP mode.
+ * Newer chipsets are better at dealing with high PHY error counts -
+ * keep weak signal detection enabled when no RSSI threshold is
+ * available to determine if it is needed (mode != STA)
*/
- if (ah->opmode != NL80211_IFTYPE_AP &&
- aniState->ofdmWeakSigDetect != weak_sig) {
- ath9k_hw_ani_control(ah,
- ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
- entry_ofdm->ofdm_weak_signal_on);
- }
+ else if (AR_SREV_9300_20_OR_LATER(ah) &&
+ ah->opmode != NL80211_IFTYPE_STATION)
+ weak_sig = true;
+
+ /* Older chipsets are more sensitive to high PHY error counts */
+ else if (!AR_SREV_9300_20_OR_LATER(ah) &&
+ aniState->ofdmNoiseImmunityLevel >= 8)
+ weak_sig = false;
+
+ if (aniState->ofdmWeakSigDetect != weak_sig)
+ ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+ weak_sig);
+
+ if (!AR_SREV_9300_20_OR_LATER(ah))
+ return;
if (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) {
ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
@@ -308,17 +318,6 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
BUG_ON(aniState == NULL);
ah->stats.ast_ani_reset++;
- /* only allow a subset of functions in AP mode */
- if (ah->opmode == NL80211_IFTYPE_AP) {
- if (IS_CHAN_2GHZ(chan)) {
- ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
- ATH9K_ANI_FIRSTEP_LEVEL);
- if (AR_SREV_9300_20_OR_LATER(ah))
- ah->ani_function |= ATH9K_ANI_MRC_CCK;
- } else
- ah->ani_function = 0;
- }
-
ofdm_nil = max_t(int, ATH9K_ANI_OFDM_DEF_LEVEL,
aniState->ofdmNoiseImmunityLevel);
cck_nil = max_t(int, ATH9K_ANI_CCK_DEF_LEVEL,
@@ -483,10 +482,17 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
ath_dbg(common, ANI, "Initialize ANI\n");
- ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
- ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
- ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
- ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW;
+ if (AR_SREV_9300_20_OR_LATER(ah)) {
+ ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
+ ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
+ ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
+ ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW;
+ } else {
+ ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
+ ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
+ ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
+ ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD;
+ }
ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h
index 21e7b83c3f6a..c40965b4c1e2 100644
--- a/drivers/net/wireless/ath/ath9k/ani.h
+++ b/drivers/net/wireless/ath/ath9k/ani.h
@@ -22,12 +22,16 @@
/* units are errors per second */
#define ATH9K_ANI_OFDM_TRIG_HIGH 3500
#define ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI 1000
+#define ATH9K_ANI_OFDM_TRIG_HIGH_OLD 500
#define ATH9K_ANI_OFDM_TRIG_LOW 400
#define ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI 900
+#define ATH9K_ANI_OFDM_TRIG_LOW_OLD 200
#define ATH9K_ANI_CCK_TRIG_HIGH 600
+#define ATH9K_ANI_CCK_TRIG_HIGH_OLD 200
#define ATH9K_ANI_CCK_TRIG_LOW 300
+#define ATH9K_ANI_CCK_TRIG_LOW_OLD 100
#define ATH9K_ANI_SPUR_IMMUNE_LVL 3
#define ATH9K_ANI_FIRSTEP_LVL 2
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index ff415e863ee9..3b3e91057a4c 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -26,10 +26,6 @@ static const int firstep_table[] =
/* level: 0 1 2 3 4 5 6 7 8 */
{ -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */
-static const int cycpwrThr1_table[] =
-/* level: 0 1 2 3 4 5 6 7 8 */
- { -6, -4, -2, 0, 2, 4, 6, 8 }; /* lvl 0-7, default 3 */
-
/*
* register values to turn OFDM weak signal detection OFF
*/
@@ -921,7 +917,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_channel *chan = ah->curchan;
struct ar5416AniState *aniState = &ah->ani;
- s32 value, value2;
+ s32 value;
switch (cmd & ah->ani_function) {
case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
@@ -1008,42 +1004,11 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
case ATH9K_ANI_FIRSTEP_LEVEL:{
u32 level = param;
- if (level >= ARRAY_SIZE(firstep_table)) {
- ath_dbg(common, ANI,
- "ATH9K_ANI_FIRSTEP_LEVEL: level out of range (%u > %zu)\n",
- level, ARRAY_SIZE(firstep_table));
- return false;
- }
-
- /*
- * make register setting relative to default
- * from INI file & cap value
- */
- value = firstep_table[level] -
- firstep_table[ATH9K_ANI_FIRSTEP_LVL] +
- aniState->iniDef.firstep;
- if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN)
- value = ATH9K_SIG_FIRSTEP_SETTING_MIN;
- if (value > ATH9K_SIG_FIRSTEP_SETTING_MAX)
- value = ATH9K_SIG_FIRSTEP_SETTING_MAX;
+ value = level * 2;
REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
- AR_PHY_FIND_SIG_FIRSTEP,
- value);
- /*
- * we need to set first step low register too
- * make register setting relative to default
- * from INI file & cap value
- */
- value2 = firstep_table[level] -
- firstep_table[ATH9K_ANI_FIRSTEP_LVL] +
- aniState->iniDef.firstepLow;
- if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN)
- value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN;
- if (value2 > ATH9K_SIG_FIRSTEP_SETTING_MAX)
- value2 = ATH9K_SIG_FIRSTEP_SETTING_MAX;
-
+ AR_PHY_FIND_SIG_FIRSTEP, value);
REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW,
- AR_PHY_FIND_SIG_FIRSTEP_LOW, value2);
+ AR_PHY_FIND_SIG_FIRSTEP_LOW, value);
if (level != aniState->firstepLevel) {
ath_dbg(common, ANI,
@@ -1060,7 +1025,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
aniState->firstepLevel,
level,
ATH9K_ANI_FIRSTEP_LVL,
- value2,
+ value,
aniState->iniDef.firstepLow);
if (level > aniState->firstepLevel)
ah->stats.ast_ani_stepup++;
@@ -1073,41 +1038,13 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
u32 level = param;
- if (level >= ARRAY_SIZE(cycpwrThr1_table)) {
- ath_dbg(common, ANI,
- "ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level out of range (%u > %zu)\n",
- level, ARRAY_SIZE(cycpwrThr1_table));
- return false;
- }
- /*
- * make register setting relative to default
- * from INI file & cap value
- */
- value = cycpwrThr1_table[level] -
- cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] +
- aniState->iniDef.cycpwrThr1;
- if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
- value = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
- if (value > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
- value = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
+ value = (level + 1) * 2;
REG_RMW_FIELD(ah, AR_PHY_TIMING5,
- AR_PHY_TIMING5_CYCPWR_THR1,
- value);
+ AR_PHY_TIMING5_CYCPWR_THR1, value);
- /*
- * set AR_PHY_EXT_CCA for extension channel
- * make register setting relative to default
- * from INI file & cap value
- */
- value2 = cycpwrThr1_table[level] -
- cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] +
- aniState->iniDef.cycpwrThr1Ext;
- if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
- value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
- if (value2 > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
- value2 = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
- REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
- AR_PHY_EXT_TIMING5_CYCPWR_THR1, value2);
+ if (IS_CHAN_HT40(ah->curchan))
+ REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
+ AR_PHY_EXT_TIMING5_CYCPWR_THR1, value);
if (level != aniState->spurImmunityLevel) {
ath_dbg(common, ANI,
@@ -1124,7 +1061,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
aniState->spurImmunityLevel,
level,
ATH9K_ANI_SPUR_IMMUNE_LVL,
- value2,
+ value,
aniState->iniDef.cycpwrThr1Ext);
if (level > aniState->spurImmunityLevel)
ah->stats.ast_ani_spurup++;
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index a352128c40ad..ac8301ef5242 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -23,10 +23,11 @@
#define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT
#define MAX_MAG_DELTA 11
#define MAX_PHS_DELTA 10
+#define MAXIQCAL 3
struct coeff {
- int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
- int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
+ int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];
+ int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];
int iqc_coeff[2];
};
@@ -655,9 +656,6 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
if (i2_m_q2_a0_d1 > 0x800)
i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1);
- if (i2_p_q2_a0_d1 > 0x1000)
- i2_p_q2_a0_d1 = -((0x1fff - i2_p_q2_a0_d1) + 1);
-
if (iq_corr_a0_d1 > 0x800)
iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1);
@@ -800,7 +798,7 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
if (q_q_coff > 63)
q_q_coff = 63;
- iqc_coeff[0] = (q_q_coff * 128) + q_i_coff;
+ iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff);
ath_dbg(common, CALIBRATE, "tx chain %d: iq corr coeff=%x\n",
chain_idx, iqc_coeff[0]);
@@ -831,7 +829,7 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
if (q_q_coff > 63)
q_q_coff = 63;
- iqc_coeff[1] = (q_q_coff * 128) + q_i_coff;
+ iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff);
ath_dbg(common, CALIBRATE, "rx chain %d: iq corr coeff=%x\n",
chain_idx, iqc_coeff[1]);
@@ -839,7 +837,8 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
return true;
}
-static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
+static void ar9003_hw_detect_outlier(int mp_coeff[][MAXIQCAL],
+ int nmeasurement,
int max_delta)
{
int mp_max = -64, max_idx = 0;
@@ -848,20 +847,20 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
/* find min/max mismatch across all calibrated gains */
for (i = 0; i < nmeasurement; i++) {
- if (mp_coeff[i] > mp_max) {
- mp_max = mp_coeff[i];
+ if (mp_coeff[i][0] > mp_max) {
+ mp_max = mp_coeff[i][0];
max_idx = i;
- } else if (mp_coeff[i] < mp_min) {
- mp_min = mp_coeff[i];
+ } else if (mp_coeff[i][0] < mp_min) {
+ mp_min = mp_coeff[i][0];
min_idx = i;
}
}
/* find average (exclude max abs value) */
for (i = 0; i < nmeasurement; i++) {
- if ((abs(mp_coeff[i]) < abs(mp_max)) ||
- (abs(mp_coeff[i]) < abs(mp_min))) {
- mp_avg += mp_coeff[i];
+ if ((abs(mp_coeff[i][0]) < abs(mp_max)) ||
+ (abs(mp_coeff[i][0]) < abs(mp_min))) {
+ mp_avg += mp_coeff[i][0];
mp_count++;
}
}
@@ -873,7 +872,7 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
if (mp_count)
mp_avg /= mp_count;
else
- mp_avg = mp_coeff[nmeasurement - 1];
+ mp_avg = mp_coeff[nmeasurement - 1][0];
/* detect outlier */
if (abs(mp_max - mp_min) > max_delta) {
@@ -882,15 +881,16 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
else
outlier_idx = min_idx;
- mp_coeff[outlier_idx] = mp_avg;
+ mp_coeff[outlier_idx][0] = mp_avg;
}
}
-static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
- struct coeff *coeff,
- bool is_reusable)
+static void ar9003_hw_tx_iq_cal_outlier_detection(struct ath_hw *ah,
+ struct coeff *coeff,
+ bool is_reusable)
{
int i, im, nmeasurement;
+ int magnitude, phase;
u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];
struct ath9k_hw_cal_data *caldata = ah->caldata;
@@ -920,21 +920,30 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
if (nmeasurement > MAX_MEASUREMENT)
nmeasurement = MAX_MEASUREMENT;
- /* detect outlier only if nmeasurement > 1 */
- if (nmeasurement > 1) {
- /* Detect magnitude outlier */
- ar9003_hw_detect_outlier(coeff->mag_coeff[i],
- nmeasurement, MAX_MAG_DELTA);
-
- /* Detect phase outlier */
- ar9003_hw_detect_outlier(coeff->phs_coeff[i],
- nmeasurement, MAX_PHS_DELTA);
+ /*
+ * Skip normal outlier detection for AR9550.
+ */
+ if (!AR_SREV_9550(ah)) {
+ /* detect outlier only if nmeasurement > 1 */
+ if (nmeasurement > 1) {
+ /* Detect magnitude outlier */
+ ar9003_hw_detect_outlier(coeff->mag_coeff[i],
+ nmeasurement,
+ MAX_MAG_DELTA);
+
+ /* Detect phase outlier */
+ ar9003_hw_detect_outlier(coeff->phs_coeff[i],
+ nmeasurement,
+ MAX_PHS_DELTA);
+ }
}
for (im = 0; im < nmeasurement; im++) {
+ magnitude = coeff->mag_coeff[i][im][0];
+ phase = coeff->phs_coeff[i][im][0];
- coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) |
- ((coeff->phs_coeff[i][im] & 0x7f) << 7);
+ coeff->iqc_coeff[0] =
+ (phase & 0x7f) | ((magnitude & 0x7f) << 7);
if ((im % 2) == 0)
REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
@@ -991,7 +1000,63 @@ static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
return true;
}
-static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
+static void __ar955x_tx_iq_cal_sort(struct ath_hw *ah,
+ struct coeff *coeff,
+ int i, int nmeasurement)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ int im, ix, iy, temp;
+
+ for (im = 0; im < nmeasurement; im++) {
+ for (ix = 0; ix < MAXIQCAL - 1; ix++) {
+ for (iy = ix + 1; iy <= MAXIQCAL - 1; iy++) {
+ if (coeff->mag_coeff[i][im][iy] <
+ coeff->mag_coeff[i][im][ix]) {
+ temp = coeff->mag_coeff[i][im][ix];
+ coeff->mag_coeff[i][im][ix] =
+ coeff->mag_coeff[i][im][iy];
+ coeff->mag_coeff[i][im][iy] = temp;
+ }
+ if (coeff->phs_coeff[i][im][iy] <
+ coeff->phs_coeff[i][im][ix]) {
+ temp = coeff->phs_coeff[i][im][ix];
+ coeff->phs_coeff[i][im][ix] =
+ coeff->phs_coeff[i][im][iy];
+ coeff->phs_coeff[i][im][iy] = temp;
+ }
+ }
+ }
+ coeff->mag_coeff[i][im][0] = coeff->mag_coeff[i][im][MAXIQCAL / 2];
+ coeff->phs_coeff[i][im][0] = coeff->phs_coeff[i][im][MAXIQCAL / 2];
+
+ ath_dbg(common, CALIBRATE,
+ "IQCAL: Median [ch%d][gain%d]: mag = %d phase = %d\n",
+ i, im,
+ coeff->mag_coeff[i][im][0],
+ coeff->phs_coeff[i][im][0]);
+ }
+}
+
+static bool ar955x_tx_iq_cal_median(struct ath_hw *ah,
+ struct coeff *coeff,
+ int iqcal_idx,
+ int nmeasurement)
+{
+ int i;
+
+ if ((iqcal_idx + 1) != MAXIQCAL)
+ return false;
+
+ for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+ __ar955x_tx_iq_cal_sort(ah, coeff, i, nmeasurement);
+ }
+
+ return true;
+}
+
+static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah,
+ int iqcal_idx,
+ bool is_reusable)
{
struct ath_common *common = ath9k_hw_common(ah);
const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
@@ -1004,10 +1069,11 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
AR_PHY_CHAN_INFO_TAB_1,
AR_PHY_CHAN_INFO_TAB_2,
};
- struct coeff coeff;
+ static struct coeff coeff;
s32 iq_res[6];
int i, im, j;
- int nmeasurement;
+ int nmeasurement = 0;
+ bool outlier_detect = true;
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
if (!(ah->txchainmask & (1 << i)))
@@ -1065,17 +1131,23 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
goto tx_iqcal_fail;
}
- coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f;
- coeff.phs_coeff[i][im] =
+ coeff.phs_coeff[i][im][iqcal_idx] =
+ coeff.iqc_coeff[0] & 0x7f;
+ coeff.mag_coeff[i][im][iqcal_idx] =
(coeff.iqc_coeff[0] >> 7) & 0x7f;
- if (coeff.mag_coeff[i][im] > 63)
- coeff.mag_coeff[i][im] -= 128;
- if (coeff.phs_coeff[i][im] > 63)
- coeff.phs_coeff[i][im] -= 128;
+ if (coeff.mag_coeff[i][im][iqcal_idx] > 63)
+ coeff.mag_coeff[i][im][iqcal_idx] -= 128;
+ if (coeff.phs_coeff[i][im][iqcal_idx] > 63)
+ coeff.phs_coeff[i][im][iqcal_idx] -= 128;
}
}
- ar9003_hw_tx_iqcal_load_avg_2_passes(ah, &coeff, is_reusable);
+
+ if (AR_SREV_9550(ah))
+ outlier_detect = ar955x_tx_iq_cal_median(ah, &coeff,
+ iqcal_idx, nmeasurement);
+ if (outlier_detect)
+ ar9003_hw_tx_iq_cal_outlier_detection(ah, &coeff, is_reusable);
return;
@@ -1409,7 +1481,7 @@ skip_tx_iqcal:
}
if (txiqcal_done)
- ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable);
+ ar9003_hw_tx_iq_cal_post_proc(ah, 0, is_reusable);
else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags))
ar9003_hw_tx_iq_cal_reload(ah);
@@ -1455,14 +1527,38 @@ skip_tx_iqcal:
return true;
}
+static bool do_ar9003_agc_cal(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ bool status;
+
+ REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+ REG_READ(ah, AR_PHY_AGC_CONTROL) |
+ AR_PHY_AGC_CONTROL_CAL);
+
+ status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
+ AR_PHY_AGC_CONTROL_CAL,
+ 0, AH_WAIT_TIMEOUT);
+ if (!status) {
+ ath_dbg(common, CALIBRATE,
+ "offset calibration failed to complete in %d ms,"
+ "noisy environment?\n",
+ AH_WAIT_TIMEOUT / 1000);
+ return false;
+ }
+
+ return true;
+}
+
static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
struct ath9k_channel *chan)
{
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_cal_data *caldata = ah->caldata;
bool txiqcal_done = false;
- bool is_reusable = true, status = true;
+ bool status = true;
bool run_agc_cal = false, sep_iq_cal = false;
+ int i = 0;
/* Use chip chainmask only for calibration */
ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);
@@ -1485,7 +1581,12 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
* AGC calibration. Specifically, AR9550 in SoC chips.
*/
if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) {
- txiqcal_done = true;
+ if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0,
+ AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)) {
+ txiqcal_done = true;
+ } else {
+ txiqcal_done = false;
+ }
run_agc_cal = true;
} else {
sep_iq_cal = true;
@@ -1512,27 +1613,37 @@ skip_tx_iqcal:
if (AR_SREV_9330_11(ah))
ar9003_hw_manual_peak_cal(ah, 0, IS_CHAN_2GHZ(chan));
- /* Calibrate the AGC */
- REG_WRITE(ah, AR_PHY_AGC_CONTROL,
- REG_READ(ah, AR_PHY_AGC_CONTROL) |
- AR_PHY_AGC_CONTROL_CAL);
-
- /* Poll for offset calibration complete */
- status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
- AR_PHY_AGC_CONTROL_CAL,
- 0, AH_WAIT_TIMEOUT);
- }
+ /*
+ * For non-AR9550 chips, we just trigger AGC calibration
+ * in the HW, poll for completion and then process
+ * the results.
+ *
+ * For AR955x, we run it multiple times and use
+ * median IQ correction.
+ */
+ if (!AR_SREV_9550(ah)) {
+ status = do_ar9003_agc_cal(ah);
+ if (!status)
+ return false;
- if (!status) {
- ath_dbg(common, CALIBRATE,
- "offset calibration failed to complete in %d ms; noisy environment?\n",
- AH_WAIT_TIMEOUT / 1000);
- return false;
+ if (txiqcal_done)
+ ar9003_hw_tx_iq_cal_post_proc(ah, 0, false);
+ } else {
+ if (!txiqcal_done) {
+ status = do_ar9003_agc_cal(ah);
+ if (!status)
+ return false;
+ } else {
+ for (i = 0; i < MAXIQCAL; i++) {
+ status = do_ar9003_agc_cal(ah);
+ if (!status)
+ return false;
+ ar9003_hw_tx_iq_cal_post_proc(ah, i, false);
+ }
+ }
+ }
}
- if (txiqcal_done)
- ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable);
-
/* Revert chainmask to runtime parameters */
ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index 25243cbc07f0..235053ba7737 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -23,8 +23,8 @@
#define COMP_HDR_LEN 4
#define COMP_CKSUM_LEN 2
-#define LE16(x) __constant_cpu_to_le16(x)
-#define LE32(x) __constant_cpu_to_le32(x)
+#define LE16(x) cpu_to_le16(x)
+#define LE32(x) cpu_to_le32(x)
/* Local defines to distinguish between extension and control CTL's */
#define EXT_ADDITIVE (0x8000)
@@ -4792,43 +4792,54 @@ static void ar9003_hw_power_control_override(struct ath_hw *ah,
tempslope:
if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
+ u8 txmask = (eep->baseEepHeader.txrxMask & 0xf0) >> 4;
+
/*
* AR955x has tempSlope register for each chain.
* Check whether temp_compensation feature is enabled or not.
*/
if (eep->baseEepHeader.featureEnable & 0x1) {
if (frequency < 4000) {
- REG_RMW_FIELD(ah, AR_PHY_TPC_19,
- AR_PHY_TPC_19_ALPHA_THERM,
- eep->base_ext2.tempSlopeLow);
- REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
- AR_PHY_TPC_19_ALPHA_THERM,
- temp_slope);
- REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2,
- AR_PHY_TPC_19_ALPHA_THERM,
- eep->base_ext2.tempSlopeHigh);
+ if (txmask & BIT(0))
+ REG_RMW_FIELD(ah, AR_PHY_TPC_19,
+ AR_PHY_TPC_19_ALPHA_THERM,
+ eep->base_ext2.tempSlopeLow);
+ if (txmask & BIT(1))
+ REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
+ AR_PHY_TPC_19_ALPHA_THERM,
+ temp_slope);
+ if (txmask & BIT(2))
+ REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2,
+ AR_PHY_TPC_19_ALPHA_THERM,
+ eep->base_ext2.tempSlopeHigh);
} else {
- REG_RMW_FIELD(ah, AR_PHY_TPC_19,
- AR_PHY_TPC_19_ALPHA_THERM,
- temp_slope);
- REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
- AR_PHY_TPC_19_ALPHA_THERM,
- temp_slope1);
- REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2,
- AR_PHY_TPC_19_ALPHA_THERM,
- temp_slope2);
+ if (txmask & BIT(0))
+ REG_RMW_FIELD(ah, AR_PHY_TPC_19,
+ AR_PHY_TPC_19_ALPHA_THERM,
+ temp_slope);
+ if (txmask & BIT(1))
+ REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
+ AR_PHY_TPC_19_ALPHA_THERM,
+ temp_slope1);
+ if (txmask & BIT(2))
+ REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2,
+ AR_PHY_TPC_19_ALPHA_THERM,
+ temp_slope2);
}
} else {
/*
* If temp compensation is not enabled,
* set all registers to 0.
*/
- REG_RMW_FIELD(ah, AR_PHY_TPC_19,
- AR_PHY_TPC_19_ALPHA_THERM, 0);
- REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
- AR_PHY_TPC_19_ALPHA_THERM, 0);
- REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2,
- AR_PHY_TPC_19_ALPHA_THERM, 0);
+ if (txmask & BIT(0))
+ REG_RMW_FIELD(ah, AR_PHY_TPC_19,
+ AR_PHY_TPC_19_ALPHA_THERM, 0);
+ if (txmask & BIT(1))
+ REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
+ AR_PHY_TPC_19_ALPHA_THERM, 0);
+ if (txmask & BIT(2))
+ REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2,
+ AR_PHY_TPC_19_ALPHA_THERM, 0);
}
} else {
REG_RMW_FIELD(ah, AR_PHY_TPC_19,
@@ -5065,6 +5076,10 @@ static u16 ar9003_hw_get_max_edge_power(struct ar9300_eeprom *eep,
break;
}
}
+
+ if (is2GHz && !twiceMaxEdgePower)
+ twiceMaxEdgePower = 60;
+
return twiceMaxEdgePower;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index 09facba1dc6d..8927fc34d84c 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -868,10 +868,6 @@ static void ar9003_hw_set_rfmode(struct ath_hw *ah,
if (IS_CHAN_A_FAST_CLOCK(ah, chan))
rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
- if (IS_CHAN_QUARTER_RATE(chan))
- rfMode |= AR_PHY_MODE_QUARTER;
- if (IS_CHAN_HALF_RATE(chan))
- rfMode |= AR_PHY_MODE_HALF;
if (rfMode & (AR_PHY_MODE_QUARTER | AR_PHY_MODE_HALF))
REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL,
diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
index 1cc13569b17b..1b6b4d0cfa97 100644
--- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
@@ -57,7 +57,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32365a5e},
{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
- {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
+ {0x00009e20, 0x000003a5, 0x000003a5, 0x000003a5, 0x000003a5},
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282},
{0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27},
@@ -96,7 +96,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
{0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000},
{0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
- {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+ {0x0000ae20, 0x000001a6, 0x000001a6, 0x000001aa, 0x000001aa},
{0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550},
};
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index b5ac32cfbeb8..44d74495c4de 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -30,7 +30,6 @@
#include "spectral.h"
struct ath_node;
-struct ath_rate_table;
extern struct ieee80211_ops ath9k_ops;
extern int ath9k_modparam_nohwcrypt;
@@ -150,6 +149,11 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
#define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e))
#define IS_OFDM_RATE(rate) ((rate >= 0x8) && (rate <= 0xf))
+enum {
+ WLAN_RC_PHY_OFDM,
+ WLAN_RC_PHY_CCK,
+};
+
struct ath_txq {
int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */
u32 axq_qnum; /* ath9k hardware queue number */
@@ -399,21 +403,10 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
#define ATH_BCBUF 8
#define ATH_DEFAULT_BINTVAL 100 /* TU */
#define ATH_DEFAULT_BMISS_LIMIT 10
-#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024)
#define TSF_TO_TU(_h,_l) \
((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
-struct ath_beacon_config {
- int beacon_interval;
- u16 listen_interval;
- u16 dtim_period;
- u16 bmiss_timeout;
- u8 dtim_count;
- bool enable_beacon;
- bool ibss_creator;
-};
-
struct ath_beacon {
enum {
OK, /* no change needed */
@@ -423,11 +416,9 @@ struct ath_beacon {
u32 beaconq;
u32 bmisscnt;
- u32 bc_tstamp;
struct ieee80211_vif *bslot[ATH_BCBUF];
int slottime;
int slotupdate;
- struct ath9k_tx_queue_info beacon_qi;
struct ath_descdma bdma;
struct ath_txq *cabq;
struct list_head bbuf;
@@ -442,7 +433,8 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
void ath9k_set_beacon(struct ath_softc *sc);
-bool ath9k_csa_is_finished(struct ath_softc *sc);
+bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif);
+void ath9k_csa_update(struct ath_softc *sc);
/*******************/
/* Link Monitoring */
@@ -693,15 +685,6 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs);
#define ATH_TXPOWER_MAX 100 /* .5 dBm units */
#define MAX_GTT_CNT 5
-enum sc_op_flags {
- SC_OP_INVALID,
- SC_OP_BEACONS,
- SC_OP_ANI_RUN,
- SC_OP_PRIM_STA_VIF,
- SC_OP_HW_RESET,
- SC_OP_SCANNING,
-};
-
/* Powersave flags */
#define PS_WAIT_FOR_BEACON BIT(0)
#define PS_WAIT_FOR_CAB BIT(1)
@@ -731,7 +714,6 @@ struct ath_softc {
struct completion paprd_complete;
wait_queue_head_t tx_wait;
- unsigned long sc_flags;
unsigned long driver_data;
u8 gtt_cnt;
@@ -748,7 +730,6 @@ struct ath_softc {
struct ath_rx rx;
struct ath_tx tx;
struct ath_beacon beacon;
- struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
#ifdef CONFIG_MAC80211_LEDS
bool led_registered;
@@ -757,7 +738,6 @@ struct ath_softc {
#endif
struct ath9k_hw_cal_data caldata;
- int last_rssi;
#ifdef CONFIG_ATH9K_DEBUGFS
struct ath9k_debug debug;
@@ -774,7 +754,6 @@ struct ath_softc {
#endif
struct ath_descdma txsdma;
- struct ieee80211_vif *csa_vif;
struct ath_ant_comb ant_comb;
u8 ant_tx, ant_rx;
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 2e8bba0eb361..471e0f624e81 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -80,7 +80,7 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
u8 chainmask = ah->txchainmask;
u8 rate = 0;
- sband = &sc->sbands[common->hw->conf.chandef.chan->band];
+ sband = &common->sbands[common->hw->conf.chandef.chan->band];
rate = sband->bitrates[rateidx].hw_value;
if (vif->bss_conf.use_short_preamble)
rate |= sband->bitrates[rateidx].hw_value_short;
@@ -292,11 +292,8 @@ static void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif)
(unsigned long long)tsfadjust, avp->av_bslot);
}
-bool ath9k_csa_is_finished(struct ath_softc *sc)
+bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif)
{
- struct ieee80211_vif *vif;
-
- vif = sc->csa_vif;
if (!vif || !vif->csa_active)
return false;
@@ -304,11 +301,23 @@ bool ath9k_csa_is_finished(struct ath_softc *sc)
return false;
ieee80211_csa_finish(vif);
-
- sc->csa_vif = NULL;
return true;
}
+static void ath9k_csa_update_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
+{
+ struct ath_softc *sc = data;
+ ath9k_csa_is_finished(sc, vif);
+}
+
+void ath9k_csa_update(struct ath_softc *sc)
+{
+ ieee80211_iterate_active_interfaces(sc->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ ath9k_csa_update_vif,
+ sc);
+}
+
void ath9k_beacon_tasklet(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *)data;
@@ -319,7 +328,7 @@ void ath9k_beacon_tasklet(unsigned long data)
bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
int slot;
- if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) {
+ if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) {
ath_dbg(common, RESET,
"reset work is pending, skip beaconing now\n");
return;
@@ -362,13 +371,13 @@ void ath9k_beacon_tasklet(unsigned long data)
return;
}
- /* EDMA devices check that in the tx completion function. */
- if (!edma && ath9k_csa_is_finished(sc))
- return;
-
slot = ath9k_beacon_choose_slot(sc);
vif = sc->beacon.bslot[slot];
+ /* EDMA devices check that in the tx completion function. */
+ if (!edma && ath9k_csa_is_finished(sc, vif))
+ return;
+
if (!vif || !vif->bss_conf.enable_beacon)
return;
@@ -438,33 +447,6 @@ static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt,
ath9k_hw_enable_interrupts(ah);
}
-/* Calculate the modulo of a 64 bit TSF snapshot with a TU divisor */
-static u32 ath9k_mod_tsf64_tu(u64 tsf, u32 div_tu)
-{
- u32 tsf_mod, tsf_hi, tsf_lo, mod_hi, mod_lo;
-
- tsf_mod = tsf & (BIT(10) - 1);
- tsf_hi = tsf >> 32;
- tsf_lo = ((u32) tsf) >> 10;
-
- mod_hi = tsf_hi % div_tu;
- mod_lo = ((mod_hi << 22) + tsf_lo) % div_tu;
-
- return (mod_lo << 10) | tsf_mod;
-}
-
-static u32 ath9k_get_next_tbtt(struct ath_softc *sc, u64 tsf,
- unsigned int interval)
-{
- struct ath_hw *ah = sc->sc_ah;
- unsigned int offset;
-
- tsf += TU_TO_USEC(FUDGE + ah->config.sw_beacon_response_time);
- offset = ath9k_mod_tsf64_tu(tsf, interval);
-
- return (u32) tsf + TU_TO_USEC(interval) - offset;
-}
-
/*
* For multi-bss ap support beacons are either staggered evenly over N slots or
* burst together. For the former arrange for the SWBA to be delivered for each
@@ -474,115 +456,18 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc,
struct ath_beacon_config *conf)
{
struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(ah);
- u32 nexttbtt, intval;
-
- /* NB: the beacon interval is kept internally in TU's */
- intval = TU_TO_USEC(conf->beacon_interval);
- intval /= ATH_BCBUF;
- nexttbtt = ath9k_get_next_tbtt(sc, ath9k_hw_gettsf64(ah),
- conf->beacon_interval);
-
- if (conf->enable_beacon)
- ah->imask |= ATH9K_INT_SWBA;
- else
- ah->imask &= ~ATH9K_INT_SWBA;
-
- ath_dbg(common, BEACON,
- "AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n",
- (conf->enable_beacon) ? "Enable" : "Disable",
- nexttbtt, intval, conf->beacon_interval);
- ath9k_beacon_init(sc, nexttbtt, intval, false);
+ ath9k_cmn_beacon_config_ap(ah, conf, ATH_BCBUF);
+ ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, false);
}
-/*
- * This sets up the beacon timers according to the timestamp of the last
- * received beacon and the current TSF, configures PCF and DTIM
- * handling, programs the sleep registers so the hardware will wakeup in
- * time to receive beacons, and configures the beacon miss handling so
- * we'll receive a BMISS interrupt when we stop seeing beacons from the AP
- * we've associated with.
- */
-static void ath9k_beacon_config_sta(struct ath_softc *sc,
+static void ath9k_beacon_config_sta(struct ath_hw *ah,
struct ath_beacon_config *conf)
{
- struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_beacon_state bs;
- int dtim_intval, sleepduration;
- u32 nexttbtt = 0, intval;
- u64 tsf;
- /* No need to configure beacon if we are not associated */
- if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
- ath_dbg(common, BEACON,
- "STA is not yet associated..skipping beacon config\n");
+ if (ath9k_cmn_beacon_config_sta(ah, conf, &bs) == -EPERM)
return;
- }
-
- memset(&bs, 0, sizeof(bs));
- intval = conf->beacon_interval;
-
- /*
- * Setup dtim parameters according to
- * last beacon we received (which may be none).
- */
- dtim_intval = intval * conf->dtim_period;
- sleepduration = conf->listen_interval * intval;
-
- /*
- * Pull nexttbtt forward to reflect the current
- * TSF and calculate dtim state for the result.
- */
- tsf = ath9k_hw_gettsf64(ah);
- nexttbtt = ath9k_get_next_tbtt(sc, tsf, intval);
-
- bs.bs_intval = TU_TO_USEC(intval);
- bs.bs_dtimperiod = conf->dtim_period * bs.bs_intval;
- bs.bs_nexttbtt = nexttbtt;
- bs.bs_nextdtim = nexttbtt;
- if (conf->dtim_period > 1)
- bs.bs_nextdtim = ath9k_get_next_tbtt(sc, tsf, dtim_intval);
-
- /*
- * Calculate the number of consecutive beacons to miss* before taking
- * a BMISS interrupt. The configuration is specified in TU so we only
- * need calculate based on the beacon interval. Note that we clamp the
- * result to at most 15 beacons.
- */
- if (sleepduration > intval) {
- bs.bs_bmissthreshold = conf->listen_interval *
- ATH_DEFAULT_BMISS_LIMIT / 2;
- } else {
- bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval);
- if (bs.bs_bmissthreshold > 15)
- bs.bs_bmissthreshold = 15;
- else if (bs.bs_bmissthreshold <= 0)
- bs.bs_bmissthreshold = 1;
- }
-
- /*
- * Calculate sleep duration. The configuration is given in ms.
- * We ensure a multiple of the beacon period is used. Also, if the sleep
- * duration is greater than the DTIM period then it makes senses
- * to make it a multiple of that.
- *
- * XXX fixed at 100ms
- */
-
- bs.bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100),
- sleepduration));
- if (bs.bs_sleepduration > bs.bs_dtimperiod)
- bs.bs_sleepduration = bs.bs_dtimperiod;
-
- /* TSF out of range threshold fixed at 1 second */
- bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
-
- ath_dbg(common, BEACON, "bmiss: %u sleep: %u\n",
- bs.bs_bmissthreshold, bs.bs_sleepduration);
-
- /* Set the computed STA beacon timers */
ath9k_hw_disable_interrupts(ah);
ath9k_hw_set_sta_beacon_timers(ah, &bs);
@@ -597,36 +482,19 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
- u32 intval, nexttbtt;
ath9k_reset_beacon_status(sc);
- intval = TU_TO_USEC(conf->beacon_interval);
-
- if (conf->ibss_creator)
- nexttbtt = intval;
- else
- nexttbtt = ath9k_get_next_tbtt(sc, ath9k_hw_gettsf64(ah),
- conf->beacon_interval);
-
- if (conf->enable_beacon)
- ah->imask |= ATH9K_INT_SWBA;
- else
- ah->imask &= ~ATH9K_INT_SWBA;
-
- ath_dbg(common, BEACON,
- "IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n",
- (conf->enable_beacon) ? "Enable" : "Disable",
- nexttbtt, intval, conf->beacon_interval);
+ ath9k_cmn_beacon_config_adhoc(ah, conf);
- ath9k_beacon_init(sc, nexttbtt, intval, conf->ibss_creator);
+ ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, conf->ibss_creator);
/*
* Set the global 'beacon has been configured' flag for the
* joiner case in IBSS mode.
*/
if (!conf->ibss_creator && conf->enable_beacon)
- set_bit(SC_OP_BEACONS, &sc->sc_flags);
+ set_bit(ATH_OP_BEACONS, &common->op_flags);
}
static bool ath9k_allow_beacon_config(struct ath_softc *sc,
@@ -646,7 +514,7 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc,
if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
if ((vif->type == NL80211_IFTYPE_STATION) &&
- test_bit(SC_OP_BEACONS, &sc->sc_flags) &&
+ test_bit(ATH_OP_BEACONS, &common->op_flags) &&
!avp->primary_sta_vif) {
ath_dbg(common, CONFIG,
"Beacon already configured for a station interface\n");
@@ -668,7 +536,6 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc,
cur_conf->beacon_interval = bss_conf->beacon_int;
cur_conf->dtim_period = bss_conf->dtim_period;
- cur_conf->listen_interval = 1;
cur_conf->dtim_count = 1;
cur_conf->ibss_creator = bss_conf->ibss_creator;
cur_conf->bmiss_timeout =
@@ -698,6 +565,8 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
{
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
unsigned long flags;
bool skip_beacon = false;
@@ -710,7 +579,7 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
ath9k_cache_beacon_config(sc, bss_conf);
ath9k_set_beacon(sc);
- set_bit(SC_OP_BEACONS, &sc->sc_flags);
+ set_bit(ATH_OP_BEACONS, &common->op_flags);
return;
}
@@ -749,13 +618,13 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
}
/*
- * Do not set the SC_OP_BEACONS flag for IBSS joiner mode
+ * Do not set the ATH_OP_BEACONS flag for IBSS joiner mode
* here, it is done in ath9k_beacon_config_adhoc().
*/
if (cur_conf->enable_beacon && !skip_beacon)
- set_bit(SC_OP_BEACONS, &sc->sc_flags);
+ set_bit(ATH_OP_BEACONS, &common->op_flags);
else
- clear_bit(SC_OP_BEACONS, &sc->sc_flags);
+ clear_bit(ATH_OP_BEACONS, &common->op_flags);
}
}
@@ -773,7 +642,7 @@ void ath9k_set_beacon(struct ath_softc *sc)
ath9k_beacon_config_adhoc(sc, cur_conf);
break;
case NL80211_IFTYPE_STATION:
- ath9k_beacon_config_sta(sc, cur_conf);
+ ath9k_beacon_config_sta(sc->sc_ah, cur_conf);
break;
default:
ath_dbg(common, CONFIG, "Unsupported beaconing mode\n");
diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.c b/drivers/net/wireless/ath/ath9k/common-beacon.c
new file mode 100644
index 000000000000..775d1d20ce0b
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/common-beacon.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "common.h"
+
+#define FUDGE 2
+
+/* Calculate the modulo of a 64 bit TSF snapshot with a TU divisor */
+static u32 ath9k_mod_tsf64_tu(u64 tsf, u32 div_tu)
+{
+ u32 tsf_mod, tsf_hi, tsf_lo, mod_hi, mod_lo;
+
+ tsf_mod = tsf & (BIT(10) - 1);
+ tsf_hi = tsf >> 32;
+ tsf_lo = ((u32) tsf) >> 10;
+
+ mod_hi = tsf_hi % div_tu;
+ mod_lo = ((mod_hi << 22) + tsf_lo) % div_tu;
+
+ return (mod_lo << 10) | tsf_mod;
+}
+
+static u32 ath9k_get_next_tbtt(struct ath_hw *ah, u64 tsf,
+ unsigned int interval)
+{
+ unsigned int offset;
+
+ tsf += TU_TO_USEC(FUDGE + ah->config.sw_beacon_response_time);
+ offset = ath9k_mod_tsf64_tu(tsf, interval);
+
+ return (u32) tsf + TU_TO_USEC(interval) - offset;
+}
+
+/*
+ * This sets up the beacon timers according to the timestamp of the last
+ * received beacon and the current TSF, configures PCF and DTIM
+ * handling, programs the sleep registers so the hardware will wakeup in
+ * time to receive beacons, and configures the beacon miss handling so
+ * we'll receive a BMISS interrupt when we stop seeing beacons from the AP
+ * we've associated with.
+ */
+int ath9k_cmn_beacon_config_sta(struct ath_hw *ah,
+ struct ath_beacon_config *conf,
+ struct ath9k_beacon_state *bs)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ int dtim_intval;
+ u64 tsf;
+
+ /* No need to configure beacon if we are not associated */
+ if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) {
+ ath_dbg(common, BEACON,
+ "STA is not yet associated..skipping beacon config\n");
+ return -EPERM;
+ }
+
+ memset(bs, 0, sizeof(*bs));
+ conf->intval = conf->beacon_interval;
+
+ /*
+ * Setup dtim parameters according to
+ * last beacon we received (which may be none).
+ */
+ dtim_intval = conf->intval * conf->dtim_period;
+
+ /*
+ * Pull nexttbtt forward to reflect the current
+ * TSF and calculate dtim state for the result.
+ */
+ tsf = ath9k_hw_gettsf64(ah);
+ conf->nexttbtt = ath9k_get_next_tbtt(ah, tsf, conf->intval);
+
+ bs->bs_intval = TU_TO_USEC(conf->intval);
+ bs->bs_dtimperiod = conf->dtim_period * bs->bs_intval;
+ bs->bs_nexttbtt = conf->nexttbtt;
+ bs->bs_nextdtim = conf->nexttbtt;
+ if (conf->dtim_period > 1)
+ bs->bs_nextdtim = ath9k_get_next_tbtt(ah, tsf, dtim_intval);
+
+ /*
+ * Calculate the number of consecutive beacons to miss* before taking
+ * a BMISS interrupt. The configuration is specified in TU so we only
+ * need calculate based on the beacon interval. Note that we clamp the
+ * result to at most 15 beacons.
+ */
+ bs->bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, conf->intval);
+ if (bs->bs_bmissthreshold > 15)
+ bs->bs_bmissthreshold = 15;
+ else if (bs->bs_bmissthreshold <= 0)
+ bs->bs_bmissthreshold = 1;
+
+ /*
+ * Calculate sleep duration. The configuration is given in ms.
+ * We ensure a multiple of the beacon period is used. Also, if the sleep
+ * duration is greater than the DTIM period then it makes senses
+ * to make it a multiple of that.
+ *
+ * XXX fixed at 100ms
+ */
+
+ bs->bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100),
+ conf->intval));
+ if (bs->bs_sleepduration > bs->bs_dtimperiod)
+ bs->bs_sleepduration = bs->bs_dtimperiod;
+
+ /* TSF out of range threshold fixed at 1 second */
+ bs->bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
+
+ ath_dbg(common, BEACON, "bmiss: %u sleep: %u\n",
+ bs->bs_bmissthreshold, bs->bs_sleepduration);
+ return 0;
+}
+EXPORT_SYMBOL(ath9k_cmn_beacon_config_sta);
+
+void ath9k_cmn_beacon_config_adhoc(struct ath_hw *ah,
+ struct ath_beacon_config *conf)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ conf->intval = TU_TO_USEC(conf->beacon_interval);
+
+ if (conf->ibss_creator)
+ conf->nexttbtt = conf->intval;
+ else
+ conf->nexttbtt = ath9k_get_next_tbtt(ah, ath9k_hw_gettsf64(ah),
+ conf->beacon_interval);
+
+ if (conf->enable_beacon)
+ ah->imask |= ATH9K_INT_SWBA;
+ else
+ ah->imask &= ~ATH9K_INT_SWBA;
+
+ ath_dbg(common, BEACON,
+ "IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n",
+ (conf->enable_beacon) ? "Enable" : "Disable",
+ conf->nexttbtt, conf->intval, conf->beacon_interval);
+}
+EXPORT_SYMBOL(ath9k_cmn_beacon_config_adhoc);
+
+/*
+ * For multi-bss ap support beacons are either staggered evenly over N slots or
+ * burst together. For the former arrange for the SWBA to be delivered for each
+ * slot. Slots that are not occupied will generate nothing.
+ */
+void ath9k_cmn_beacon_config_ap(struct ath_hw *ah,
+ struct ath_beacon_config *conf,
+ unsigned int bc_buf)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ /* NB: the beacon interval is kept internally in TU's */
+ conf->intval = TU_TO_USEC(conf->beacon_interval);
+ conf->intval /= bc_buf;
+ conf->nexttbtt = ath9k_get_next_tbtt(ah, ath9k_hw_gettsf64(ah),
+ conf->beacon_interval);
+
+ if (conf->enable_beacon)
+ ah->imask |= ATH9K_INT_SWBA;
+ else
+ ah->imask &= ~ATH9K_INT_SWBA;
+
+ ath_dbg(common, BEACON,
+ "AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n",
+ (conf->enable_beacon) ? "Enable" : "Disable",
+ conf->nexttbtt, conf->intval, conf->beacon_interval);
+}
+EXPORT_SYMBOL(ath9k_cmn_beacon_config_ap);
diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.h b/drivers/net/wireless/ath/ath9k/common-beacon.h
new file mode 100644
index 000000000000..3665d27f0dc7
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/common-beacon.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2009-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+struct ath_beacon_config;
+
+int ath9k_cmn_beacon_config_sta(struct ath_hw *ah,
+ struct ath_beacon_config *conf,
+ struct ath9k_beacon_state *bs);
+void ath9k_cmn_beacon_config_adhoc(struct ath_hw *ah,
+ struct ath_beacon_config *conf);
+void ath9k_cmn_beacon_config_ap(struct ath_hw *ah,
+ struct ath_beacon_config *conf,
+ unsigned int bc_buf);
diff --git a/drivers/net/wireless/ath/ath9k/common-init.c b/drivers/net/wireless/ath/ath9k/common-init.c
new file mode 100644
index 000000000000..a006c1499728
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/common-init.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* We use the hw_value as an index into our private channel structure */
+
+#include "common.h"
+
+#define CHAN2G(_freq, _idx) { \
+ .band = IEEE80211_BAND_2GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_idx), \
+ .max_power = 20, \
+}
+
+#define CHAN5G(_freq, _idx) { \
+ .band = IEEE80211_BAND_5GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_idx), \
+ .max_power = 20, \
+}
+
+/* Some 2 GHz radios are actually tunable on 2312-2732
+ * on 5 MHz steps, we support the channels which we know
+ * we have calibration data for all cards though to make
+ * this static */
+static const struct ieee80211_channel ath9k_2ghz_chantable[] = {
+ CHAN2G(2412, 0), /* Channel 1 */
+ CHAN2G(2417, 1), /* Channel 2 */
+ CHAN2G(2422, 2), /* Channel 3 */
+ CHAN2G(2427, 3), /* Channel 4 */
+ CHAN2G(2432, 4), /* Channel 5 */
+ CHAN2G(2437, 5), /* Channel 6 */
+ CHAN2G(2442, 6), /* Channel 7 */
+ CHAN2G(2447, 7), /* Channel 8 */
+ CHAN2G(2452, 8), /* Channel 9 */
+ CHAN2G(2457, 9), /* Channel 10 */
+ CHAN2G(2462, 10), /* Channel 11 */
+ CHAN2G(2467, 11), /* Channel 12 */
+ CHAN2G(2472, 12), /* Channel 13 */
+ CHAN2G(2484, 13), /* Channel 14 */
+};
+
+/* Some 5 GHz radios are actually tunable on XXXX-YYYY
+ * on 5 MHz steps, we support the channels which we know
+ * we have calibration data for all cards though to make
+ * this static */
+static const struct ieee80211_channel ath9k_5ghz_chantable[] = {
+ /* _We_ call this UNII 1 */
+ CHAN5G(5180, 14), /* Channel 36 */
+ CHAN5G(5200, 15), /* Channel 40 */
+ CHAN5G(5220, 16), /* Channel 44 */
+ CHAN5G(5240, 17), /* Channel 48 */
+ /* _We_ call this UNII 2 */
+ CHAN5G(5260, 18), /* Channel 52 */
+ CHAN5G(5280, 19), /* Channel 56 */
+ CHAN5G(5300, 20), /* Channel 60 */
+ CHAN5G(5320, 21), /* Channel 64 */
+ /* _We_ call this "Middle band" */
+ CHAN5G(5500, 22), /* Channel 100 */
+ CHAN5G(5520, 23), /* Channel 104 */
+ CHAN5G(5540, 24), /* Channel 108 */
+ CHAN5G(5560, 25), /* Channel 112 */
+ CHAN5G(5580, 26), /* Channel 116 */
+ CHAN5G(5600, 27), /* Channel 120 */
+ CHAN5G(5620, 28), /* Channel 124 */
+ CHAN5G(5640, 29), /* Channel 128 */
+ CHAN5G(5660, 30), /* Channel 132 */
+ CHAN5G(5680, 31), /* Channel 136 */
+ CHAN5G(5700, 32), /* Channel 140 */
+ /* _We_ call this UNII 3 */
+ CHAN5G(5745, 33), /* Channel 149 */
+ CHAN5G(5765, 34), /* Channel 153 */
+ CHAN5G(5785, 35), /* Channel 157 */
+ CHAN5G(5805, 36), /* Channel 161 */
+ CHAN5G(5825, 37), /* Channel 165 */
+};
+
+/* Atheros hardware rate code addition for short premble */
+#define SHPCHECK(__hw_rate, __flags) \
+ ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0)
+
+#define RATE(_bitrate, _hw_rate, _flags) { \
+ .bitrate = (_bitrate), \
+ .flags = (_flags), \
+ .hw_value = (_hw_rate), \
+ .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \
+}
+
+static struct ieee80211_rate ath9k_legacy_rates[] = {
+ RATE(10, 0x1b, 0),
+ RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATE(60, 0x0b, (IEEE80211_RATE_SUPPORTS_5MHZ |
+ IEEE80211_RATE_SUPPORTS_10MHZ)),
+ RATE(90, 0x0f, (IEEE80211_RATE_SUPPORTS_5MHZ |
+ IEEE80211_RATE_SUPPORTS_10MHZ)),
+ RATE(120, 0x0a, (IEEE80211_RATE_SUPPORTS_5MHZ |
+ IEEE80211_RATE_SUPPORTS_10MHZ)),
+ RATE(180, 0x0e, (IEEE80211_RATE_SUPPORTS_5MHZ |
+ IEEE80211_RATE_SUPPORTS_10MHZ)),
+ RATE(240, 0x09, (IEEE80211_RATE_SUPPORTS_5MHZ |
+ IEEE80211_RATE_SUPPORTS_10MHZ)),
+ RATE(360, 0x0d, (IEEE80211_RATE_SUPPORTS_5MHZ |
+ IEEE80211_RATE_SUPPORTS_10MHZ)),
+ RATE(480, 0x08, (IEEE80211_RATE_SUPPORTS_5MHZ |
+ IEEE80211_RATE_SUPPORTS_10MHZ)),
+ RATE(540, 0x0c, (IEEE80211_RATE_SUPPORTS_5MHZ |
+ IEEE80211_RATE_SUPPORTS_10MHZ)),
+};
+
+int ath9k_cmn_init_channels_rates(struct ath_common *common)
+{
+ struct ath_hw *ah = (struct ath_hw *)common->ah;
+ void *channels;
+
+ BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) +
+ ARRAY_SIZE(ath9k_5ghz_chantable) !=
+ ATH9K_NUM_CHANNELS);
+
+ if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
+ channels = devm_kzalloc(ah->dev,
+ sizeof(ath9k_2ghz_chantable), GFP_KERNEL);
+ if (!channels)
+ return -ENOMEM;
+
+ memcpy(channels, ath9k_2ghz_chantable,
+ sizeof(ath9k_2ghz_chantable));
+ common->sbands[IEEE80211_BAND_2GHZ].channels = channels;
+ common->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
+ common->sbands[IEEE80211_BAND_2GHZ].n_channels =
+ ARRAY_SIZE(ath9k_2ghz_chantable);
+ common->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
+ common->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
+ ARRAY_SIZE(ath9k_legacy_rates);
+ }
+
+ if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
+ channels = devm_kzalloc(ah->dev,
+ sizeof(ath9k_5ghz_chantable), GFP_KERNEL);
+ if (!channels)
+ return -ENOMEM;
+
+ memcpy(channels, ath9k_5ghz_chantable,
+ sizeof(ath9k_5ghz_chantable));
+ common->sbands[IEEE80211_BAND_5GHZ].channels = channels;
+ common->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
+ common->sbands[IEEE80211_BAND_5GHZ].n_channels =
+ ARRAY_SIZE(ath9k_5ghz_chantable);
+ common->sbands[IEEE80211_BAND_5GHZ].bitrates =
+ ath9k_legacy_rates + 4;
+ common->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
+ ARRAY_SIZE(ath9k_legacy_rates) - 4;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(ath9k_cmn_init_channels_rates);
+
+void ath9k_cmn_setup_ht_cap(struct ath_hw *ah,
+ struct ieee80211_sta_ht_cap *ht_info)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ u8 tx_streams, rx_streams;
+ int i, max_streams;
+
+ ht_info->ht_supported = true;
+ ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+ IEEE80211_HT_CAP_SM_PS |
+ IEEE80211_HT_CAP_SGI_40 |
+ IEEE80211_HT_CAP_DSSSCCK40;
+
+ if (ah->caps.hw_caps & ATH9K_HW_CAP_LDPC)
+ ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
+
+ if (ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
+ ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
+
+ ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+ ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
+
+ if (AR_SREV_9271(ah) || AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah))
+ max_streams = 1;
+ else if (AR_SREV_9462(ah))
+ max_streams = 2;
+ else if (AR_SREV_9300_20_OR_LATER(ah))
+ max_streams = 3;
+ else
+ max_streams = 2;
+
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
+ if (max_streams >= 2)
+ ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
+ ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+ }
+
+ /* set up supported mcs set */
+ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
+ tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams);
+ rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams);
+
+ ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n",
+ tx_streams, rx_streams);
+
+ if (tx_streams != rx_streams) {
+ ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
+ ht_info->mcs.tx_params |= ((tx_streams - 1) <<
+ IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
+ }
+
+ for (i = 0; i < rx_streams; i++)
+ ht_info->mcs.rx_mask[i] = 0xff;
+
+ ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
+}
+EXPORT_SYMBOL(ath9k_cmn_setup_ht_cap);
+
+void ath9k_cmn_reload_chainmask(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ if (!(ah->caps.hw_caps & ATH9K_HW_CAP_HT))
+ return;
+
+ if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
+ ath9k_cmn_setup_ht_cap(ah,
+ &common->sbands[IEEE80211_BAND_2GHZ].ht_cap);
+ if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
+ ath9k_cmn_setup_ht_cap(ah,
+ &common->sbands[IEEE80211_BAND_5GHZ].ht_cap);
+}
+EXPORT_SYMBOL(ath9k_cmn_reload_chainmask);
diff --git a/drivers/net/wireless/ath/ath9k/common-init.h b/drivers/net/wireless/ath/ath9k/common-init.h
new file mode 100644
index 000000000000..ac03fca5ffdd
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/common-init.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2009-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+int ath9k_cmn_init_channels_rates(struct ath_common *common);
+void ath9k_cmn_setup_ht_cap(struct ath_hw *ah,
+ struct ieee80211_sta_ht_cap *ht_info);
+void ath9k_cmn_reload_chainmask(struct ath_hw *ah);
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
index 768c733cad31..c6dd7f1fed65 100644
--- a/drivers/net/wireless/ath/ath9k/common.c
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -27,6 +27,250 @@ MODULE_AUTHOR("Atheros Communications");
MODULE_DESCRIPTION("Shared library for Atheros wireless 802.11n LAN cards.");
MODULE_LICENSE("Dual BSD/GPL");
+/* Assumes you've already done the endian to CPU conversion */
+bool ath9k_cmn_rx_accept(struct ath_common *common,
+ struct ieee80211_hdr *hdr,
+ struct ieee80211_rx_status *rxs,
+ struct ath_rx_status *rx_stats,
+ bool *decrypt_error,
+ unsigned int rxfilter)
+{
+ struct ath_hw *ah = common->ah;
+ bool is_mc, is_valid_tkip, strip_mic, mic_error;
+ __le16 fc;
+
+ fc = hdr->frame_control;
+
+ is_mc = !!is_multicast_ether_addr(hdr->addr1);
+ is_valid_tkip = rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID &&
+ test_bit(rx_stats->rs_keyix, common->tkip_keymap);
+ strip_mic = is_valid_tkip && ieee80211_is_data(fc) &&
+ ieee80211_has_protected(fc) &&
+ !(rx_stats->rs_status &
+ (ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC |
+ ATH9K_RXERR_KEYMISS));
+
+ /*
+ * Key miss events are only relevant for pairwise keys where the
+ * descriptor does contain a valid key index. This has been observed
+ * mostly with CCMP encryption.
+ */
+ if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID ||
+ !test_bit(rx_stats->rs_keyix, common->ccmp_keymap))
+ rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS;
+
+ mic_error = is_valid_tkip && !ieee80211_is_ctl(fc) &&
+ !ieee80211_has_morefrags(fc) &&
+ !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) &&
+ (rx_stats->rs_status & ATH9K_RXERR_MIC);
+
+ /*
+ * The rx_stats->rs_status will not be set until the end of the
+ * chained descriptors so it can be ignored if rs_more is set. The
+ * rs_more will be false at the last element of the chained
+ * descriptors.
+ */
+ if (rx_stats->rs_status != 0) {
+ u8 status_mask;
+
+ if (rx_stats->rs_status & ATH9K_RXERR_CRC) {
+ rxs->flag |= RX_FLAG_FAILED_FCS_CRC;
+ mic_error = false;
+ }
+
+ if ((rx_stats->rs_status & ATH9K_RXERR_DECRYPT) ||
+ (!is_mc && (rx_stats->rs_status & ATH9K_RXERR_KEYMISS))) {
+ *decrypt_error = true;
+ mic_error = false;
+ }
+
+
+ /*
+ * Reject error frames with the exception of
+ * decryption and MIC failures. For monitor mode,
+ * we also ignore the CRC error.
+ */
+ status_mask = ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
+ ATH9K_RXERR_KEYMISS;
+
+ if (ah->is_monitoring && (rxfilter & FIF_FCSFAIL))
+ status_mask |= ATH9K_RXERR_CRC;
+
+ if (rx_stats->rs_status & ~status_mask)
+ return false;
+ }
+
+ /*
+ * For unicast frames the MIC error bit can have false positives,
+ * so all MIC error reports need to be validated in software.
+ * False negatives are not common, so skip software verification
+ * if the hardware considers the MIC valid.
+ */
+ if (strip_mic)
+ rxs->flag |= RX_FLAG_MMIC_STRIPPED;
+ else if (is_mc && mic_error)
+ rxs->flag |= RX_FLAG_MMIC_ERROR;
+
+ return true;
+}
+EXPORT_SYMBOL(ath9k_cmn_rx_accept);
+
+void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
+ struct sk_buff *skb,
+ struct ath_rx_status *rx_stats,
+ struct ieee80211_rx_status *rxs,
+ bool decrypt_error)
+{
+ struct ath_hw *ah = common->ah;
+ struct ieee80211_hdr *hdr;
+ int hdrlen, padpos, padsize;
+ u8 keyix;
+ __le16 fc;
+
+ /* see if any padding is done by the hw and remove it */
+ hdr = (struct ieee80211_hdr *) skb->data;
+ hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+ fc = hdr->frame_control;
+ padpos = ieee80211_hdrlen(fc);
+
+ /* The MAC header is padded to have 32-bit boundary if the
+ * packet payload is non-zero. The general calculation for
+ * padsize would take into account odd header lengths:
+ * padsize = (4 - padpos % 4) % 4; However, since only
+ * even-length headers are used, padding can only be 0 or 2
+ * bytes and we can optimize this a bit. In addition, we must
+ * not try to remove padding from short control frames that do
+ * not have payload. */
+ padsize = padpos & 3;
+ if (padsize && skb->len>=padpos+padsize+FCS_LEN) {
+ memmove(skb->data + padsize, skb->data, padpos);
+ skb_pull(skb, padsize);
+ }
+
+ keyix = rx_stats->rs_keyix;
+
+ if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error &&
+ ieee80211_has_protected(fc)) {
+ rxs->flag |= RX_FLAG_DECRYPTED;
+ } else if (ieee80211_has_protected(fc)
+ && !decrypt_error && skb->len >= hdrlen + 4) {
+ keyix = skb->data[hdrlen + 3] >> 6;
+
+ if (test_bit(keyix, common->keymap))
+ rxs->flag |= RX_FLAG_DECRYPTED;
+ }
+ if (ah->sw_mgmt_crypto &&
+ (rxs->flag & RX_FLAG_DECRYPTED) &&
+ ieee80211_is_mgmt(fc))
+ /* Use software decrypt for management frames. */
+ rxs->flag &= ~RX_FLAG_DECRYPTED;
+}
+EXPORT_SYMBOL(ath9k_cmn_rx_skb_postprocess);
+
+int ath9k_cmn_process_rate(struct ath_common *common,
+ struct ieee80211_hw *hw,
+ struct ath_rx_status *rx_stats,
+ struct ieee80211_rx_status *rxs)
+{
+ struct ieee80211_supported_band *sband;
+ enum ieee80211_band band;
+ unsigned int i = 0;
+ struct ath_hw *ah = common->ah;
+
+ band = ah->curchan->chan->band;
+ sband = hw->wiphy->bands[band];
+
+ if (IS_CHAN_QUARTER_RATE(ah->curchan))
+ rxs->flag |= RX_FLAG_5MHZ;
+ else if (IS_CHAN_HALF_RATE(ah->curchan))
+ rxs->flag |= RX_FLAG_10MHZ;
+
+ if (rx_stats->rs_rate & 0x80) {
+ /* HT rate */
+ rxs->flag |= RX_FLAG_HT;
+ rxs->flag |= rx_stats->flag;
+ rxs->rate_idx = rx_stats->rs_rate & 0x7f;
+ return 0;
+ }
+
+ for (i = 0; i < sband->n_bitrates; i++) {
+ if (sband->bitrates[i].hw_value == rx_stats->rs_rate) {
+ rxs->rate_idx = i;
+ return 0;
+ }
+ if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) {
+ rxs->flag |= RX_FLAG_SHORTPRE;
+ rxs->rate_idx = i;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(ath9k_cmn_process_rate);
+
+void ath9k_cmn_process_rssi(struct ath_common *common,
+ struct ieee80211_hw *hw,
+ struct ath_rx_status *rx_stats,
+ struct ieee80211_rx_status *rxs)
+{
+ struct ath_hw *ah = common->ah;
+ int last_rssi;
+ int rssi = rx_stats->rs_rssi;
+ int i, j;
+
+ /*
+ * RSSI is not available for subframes in an A-MPDU.
+ */
+ if (rx_stats->rs_moreaggr) {
+ rxs->flag |= RX_FLAG_NO_SIGNAL_VAL;
+ return;
+ }
+
+ /*
+ * Check if the RSSI for the last subframe in an A-MPDU
+ * or an unaggregated frame is valid.
+ */
+ if (rx_stats->rs_rssi == ATH9K_RSSI_BAD) {
+ rxs->flag |= RX_FLAG_NO_SIGNAL_VAL;
+ return;
+ }
+
+ for (i = 0, j = 0; i < ARRAY_SIZE(rx_stats->rs_rssi_ctl); i++) {
+ s8 rssi;
+
+ if (!(ah->rxchainmask & BIT(i)))
+ continue;
+
+ rssi = rx_stats->rs_rssi_ctl[i];
+ if (rssi != ATH9K_RSSI_BAD) {
+ rxs->chains |= BIT(j);
+ rxs->chain_signal[j] = ah->noise + rssi;
+ }
+ j++;
+ }
+
+ /*
+ * Update Beacon RSSI, this is used by ANI.
+ */
+ if (rx_stats->is_mybeacon &&
+ ((ah->opmode == NL80211_IFTYPE_STATION) ||
+ (ah->opmode == NL80211_IFTYPE_ADHOC))) {
+ ATH_RSSI_LPF(common->last_rssi, rx_stats->rs_rssi);
+ last_rssi = common->last_rssi;
+
+ if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
+ rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER);
+ if (rssi < 0)
+ rssi = 0;
+
+ ah->stats.avgbrssi = rssi;
+ }
+
+ rxs->signal = ah->noise + rx_stats->rs_rssi;
+}
+EXPORT_SYMBOL(ath9k_cmn_process_rssi);
+
int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h
index eb85e1bdca88..ca38116838f0 100644
--- a/drivers/net/wireless/ath/ath9k/common.h
+++ b/drivers/net/wireless/ath/ath9k/common.h
@@ -21,6 +21,9 @@
#include "hw.h"
#include "hw-ops.h"
+#include "common-init.h"
+#include "common-beacon.h"
+
/* Common header for Atheros 802.11n base driver cores */
#define WME_BA_BMP_SIZE 64
@@ -42,6 +45,38 @@
#define ATH_EP_RND(x, mul) \
(((x) + ((mul)/2)) / (mul))
+#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024)
+
+struct ath_beacon_config {
+ int beacon_interval;
+ u16 dtim_period;
+ u16 bmiss_timeout;
+ u8 dtim_count;
+ bool enable_beacon;
+ bool ibss_creator;
+ u32 nexttbtt;
+ u32 intval;
+};
+
+bool ath9k_cmn_rx_accept(struct ath_common *common,
+ struct ieee80211_hdr *hdr,
+ struct ieee80211_rx_status *rxs,
+ struct ath_rx_status *rx_stats,
+ bool *decrypt_error,
+ unsigned int rxfilter);
+void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
+ struct sk_buff *skb,
+ struct ath_rx_status *rx_stats,
+ struct ieee80211_rx_status *rxs,
+ bool decrypt_error);
+int ath9k_cmn_process_rate(struct ath_common *common,
+ struct ieee80211_hw *hw,
+ struct ath_rx_status *rx_stats,
+ struct ieee80211_rx_status *rxs);
+void ath9k_cmn_process_rssi(struct ath_common *common,
+ struct ieee80211_hw *hw,
+ struct ath_rx_status *rx_stats,
+ struct ieee80211_rx_status *rxs);
int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb);
struct ath9k_channel *ath9k_cmn_get_channel(struct ieee80211_hw *hw,
struct ath_hw *ah,
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index ab7264c1d8f7..780ff1bee6f6 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -135,46 +135,45 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf,
struct ath_softc *sc = file->private_data;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_hw *ah = sc->sc_ah;
- unsigned int len = 0, size = 1024;
+ unsigned int len = 0;
+ const unsigned int size = 1024;
ssize_t retval = 0;
char *buf;
+ int i;
+ struct {
+ const char *name;
+ unsigned int val;
+ } ani_info[] = {
+ { "ANI RESET", ah->stats.ast_ani_reset },
+ { "OFDM LEVEL", ah->ani.ofdmNoiseImmunityLevel },
+ { "CCK LEVEL", ah->ani.cckNoiseImmunityLevel },
+ { "SPUR UP", ah->stats.ast_ani_spurup },
+ { "SPUR DOWN", ah->stats.ast_ani_spurup },
+ { "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon },
+ { "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff },
+ { "MRC-CCK ON", ah->stats.ast_ani_ccklow },
+ { "MRC-CCK OFF", ah->stats.ast_ani_cckhigh },
+ { "FIR-STEP UP", ah->stats.ast_ani_stepup },
+ { "FIR-STEP DOWN", ah->stats.ast_ani_stepdown },
+ { "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero },
+ { "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs },
+ { "CCK ERRORS", ah->stats.ast_ani_cckerrs },
+ };
buf = kzalloc(size, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
- if (common->disable_ani) {
- len += scnprintf(buf + len, size - len, "%s: %s\n",
- "ANI", "DISABLED");
+ len += scnprintf(buf + len, size - len, "%15s: %s\n", "ANI",
+ common->disable_ani ? "DISABLED" : "ENABLED");
+
+ if (common->disable_ani)
goto exit;
- }
- len += scnprintf(buf + len, size - len, "%15s: %s\n",
- "ANI", "ENABLED");
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
- "ANI RESET", ah->stats.ast_ani_reset);
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
- "SPUR UP", ah->stats.ast_ani_spurup);
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
- "SPUR DOWN", ah->stats.ast_ani_spurup);
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
- "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon);
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
- "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff);
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
- "MRC-CCK ON", ah->stats.ast_ani_ccklow);
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
- "MRC-CCK OFF", ah->stats.ast_ani_cckhigh);
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
- "FIR-STEP UP", ah->stats.ast_ani_stepup);
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
- "FIR-STEP DOWN", ah->stats.ast_ani_stepdown);
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
- "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero);
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
- "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs);
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
- "CCK ERRORS", ah->stats.ast_ani_cckerrs);
+ for (i = 0; i < ARRAY_SIZE(ani_info); i++)
+ len += scnprintf(buf + len, size - len, "%15s: %u\n",
+ ani_info[i].name, ani_info[i].val);
+
exit:
if (len > size)
len = size;
@@ -209,7 +208,7 @@ static ssize_t write_file_ani(struct file *file,
common->disable_ani = !ani;
if (common->disable_ani) {
- clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
+ clear_bit(ATH_OP_ANI_RUN, &common->op_flags);
ath_stop_ani(sc);
} else {
ath_check_ani(sc);
@@ -307,13 +306,13 @@ static ssize_t read_file_antenna_diversity(struct file *file,
struct ath_antenna_stats *as_main = &sc->debug.stats.ant_stats[ANT_MAIN];
struct ath_antenna_stats *as_alt = &sc->debug.stats.ant_stats[ANT_ALT];
struct ath_hw_antcomb_conf div_ant_conf;
- unsigned int len = 0, size = 1024;
+ unsigned int len = 0;
+ const unsigned int size = 1024;
ssize_t retval = 0;
char *buf;
- char *lna_conf_str[4] = {"LNA1_MINUS_LNA2",
- "LNA2",
- "LNA1",
- "LNA1_PLUS_LNA2"};
+ static const char *lna_conf_str[4] = {
+ "LNA1_MINUS_LNA2", "LNA2", "LNA1", "LNA1_PLUS_LNA2"
+ };
buf = kzalloc(size, GFP_KERNEL);
if (buf == NULL)
@@ -716,10 +715,13 @@ static ssize_t read_file_queues(struct file *file, char __user *user_buf,
struct ath_softc *sc = file->private_data;
struct ath_txq *txq;
char *buf;
- unsigned int len = 0, size = 1024;
+ unsigned int len = 0;
+ const unsigned int size = 1024;
ssize_t retval = 0;
int i;
- char *qname[4] = {"VO", "VI", "BE", "BK"};
+ static const char *qname[4] = {
+ "VO", "VI", "BE", "BK"
+ };
buf = kzalloc(size, GFP_KERNEL);
if (buf == NULL)
@@ -866,6 +868,12 @@ static ssize_t read_file_reset(struct file *file, char __user *user_buf,
"%17s: %2d\n", "PLL RX Hang",
sc->debug.stats.reset[RESET_TYPE_PLL_HANG]);
len += scnprintf(buf + len, sizeof(buf) - len,
+ "%17s: %2d\n", "MAC Hang",
+ sc->debug.stats.reset[RESET_TYPE_MAC_HANG]);
+ len += scnprintf(buf + len, sizeof(buf) - len,
+ "%17s: %2d\n", "Stuck Beacon",
+ sc->debug.stats.reset[RESET_TYPE_BEACON_STUCK]);
+ len += scnprintf(buf + len, sizeof(buf) - len,
"%17s: %2d\n", "MCI Reset",
sc->debug.stats.reset[RESET_TYPE_MCI]);
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index cc7a025d833e..559a68c2709c 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -18,7 +18,6 @@
#define DEBUG_H
#include "hw.h"
-#include "rc.h"
#include "dfs_debug.h"
struct ath_txq;
diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.h b/drivers/net/wireless/ath/ath9k/dfs_debug.h
index 0a7ddf4c88c9..7936c9126a20 100644
--- a/drivers/net/wireless/ath/ath9k/dfs_debug.h
+++ b/drivers/net/wireless/ath/ath9k/dfs_debug.h
@@ -21,6 +21,8 @@
#include "hw.h"
+struct ath_softc;
+
/**
* struct ath_dfs_stats - DFS Statistics per wiphy
* @pulses_total: pulses reported by HW
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 6d5d716adc1b..8e7153b186ed 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -54,6 +54,8 @@ static struct usb_device_id ath9k_hif_usb_ids[] = {
.driver_info = AR9280_USB }, /* SMC Networks */
{ USB_DEVICE(0x0411, 0x017f),
.driver_info = AR9280_USB }, /* Sony UWA-BR100 */
+ { USB_DEVICE(0x0411, 0x0197),
+ .driver_info = AR9280_USB }, /* Buffalo WLI-UV-AG300P */
{ USB_DEVICE(0x04da, 0x3904),
.driver_info = AR9280_USB },
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 58da3468d1f0..dab1f0cab993 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -39,7 +39,6 @@
#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */
#define ATH_DEFAULT_BMISS_LIMIT 10
-#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024)
#define TSF_TO_TU(_h, _l) \
((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
@@ -262,6 +261,8 @@ enum tid_aggr_state {
struct ath9k_htc_sta {
u8 index;
enum tid_aggr_state tid_state[ATH9K_HTC_MAX_TID];
+ struct work_struct rc_update_work;
+ struct ath9k_htc_priv *htc_priv;
};
#define ATH9K_HTC_RXBUF 256
@@ -275,7 +276,6 @@ struct ath9k_htc_rxbuf {
};
struct ath9k_htc_rx {
- int last_rssi; /* FIXME: per-STA */
struct list_head rxbuf;
spinlock_t rxbuflock;
};
@@ -405,12 +405,18 @@ static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,
#define DEFAULT_SWBA_RESPONSE 40 /* in TUs */
#define MIN_SWBA_RESPONSE 10 /* in TUs */
-struct htc_beacon_config {
+struct htc_beacon {
+ enum {
+ OK, /* no change needed */
+ UPDATE, /* update pending */
+ COMMIT /* beacon sent, commit change */
+ } updateslot; /* slot time update fsm */
+
struct ieee80211_vif *bslot[ATH9K_HTC_MAX_BCN_VIF];
- u16 beacon_interval;
- u16 dtim_period;
- u16 bmiss_timeout;
- u32 bmiss_cnt;
+ u32 bmisscnt;
+ u32 beaconq;
+ int slottime;
+ int slotupdate;
};
struct ath_btcoex {
@@ -438,12 +444,8 @@ static inline void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv)
}
#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
-#define OP_INVALID BIT(0)
-#define OP_SCANNING BIT(1)
-#define OP_ENABLE_BEACON BIT(2)
#define OP_BT_PRIORITY_DETECTED BIT(3)
#define OP_BT_SCAN BIT(4)
-#define OP_ANI_RUNNING BIT(5)
#define OP_TSF_RESET BIT(6)
struct ath9k_htc_priv {
@@ -486,10 +488,10 @@ struct ath9k_htc_priv {
unsigned long op_flags;
struct ath9k_hw_cal_data caldata;
- struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
spinlock_t beacon_lock;
- struct htc_beacon_config cur_beacon_conf;
+ struct ath_beacon_config cur_beacon_conf;
+ struct htc_beacon beacon;
struct ath9k_htc_rx rx;
struct ath9k_htc_tx tx;
@@ -514,7 +516,6 @@ struct ath9k_htc_priv {
struct work_struct led_work;
#endif
- int beaconq;
int cabq;
int hwq_map[IEEE80211_NUM_ACS];
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index 8b5757734596..e8b6ec3c1dbb 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -26,7 +26,7 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info));
- ath9k_hw_get_txq_props(ah, priv->beaconq, &qi);
+ ath9k_hw_get_txq_props(ah, priv->beacon.beaconq, &qi);
if (priv->ah->opmode == NL80211_IFTYPE_AP ||
priv->ah->opmode == NL80211_IFTYPE_MESH_POINT) {
@@ -54,220 +54,78 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
}
- if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) {
+ if (!ath9k_hw_set_txq_props(ah, priv->beacon.beaconq, &qi)) {
ath_err(ath9k_hw_common(ah),
- "Unable to update beacon queue %u!\n", priv->beaconq);
+ "Unable to update beacon queue %u!\n", priv->beacon.beaconq);
} else {
- ath9k_hw_resettxqueue(ah, priv->beaconq);
+ ath9k_hw_resettxqueue(ah, priv->beacon.beaconq);
}
}
-
-static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
- struct htc_beacon_config *bss_conf)
+/*
+ * Both nexttbtt and intval have to be in usecs.
+ */
+static void ath9k_htc_beacon_init(struct ath9k_htc_priv *priv,
+ struct ath_beacon_config *conf,
+ bool reset_tsf)
{
- struct ath_common *common = ath9k_hw_common(priv->ah);
- struct ath9k_beacon_state bs;
- enum ath9k_int imask = 0;
- int dtimperiod, dtimcount, sleepduration;
- int bmiss_timeout;
- u32 nexttbtt = 0, intval, tsftu;
- __be32 htc_imask = 0;
- u64 tsf;
- int num_beacons, offset, dtim_dec_count;
+ struct ath_hw *ah = priv->ah;
int ret __attribute__ ((unused));
+ __be32 htc_imask = 0;
u8 cmd_rsp;
- memset(&bs, 0, sizeof(bs));
-
- intval = bss_conf->beacon_interval;
- bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_interval);
-
- /*
- * Setup dtim parameters according to
- * last beacon we received (which may be none).
- */
- dtimperiod = bss_conf->dtim_period;
- if (dtimperiod <= 0) /* NB: 0 if not known */
- dtimperiod = 1;
- dtimcount = 1;
- if (dtimcount >= dtimperiod) /* NB: sanity check */
- dtimcount = 0;
-
- sleepduration = intval;
- if (sleepduration <= 0)
- sleepduration = intval;
-
- /*
- * Pull nexttbtt forward to reflect the current
- * TSF and calculate dtim state for the result.
- */
- tsf = ath9k_hw_gettsf64(priv->ah);
- tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
-
- num_beacons = tsftu / intval + 1;
- offset = tsftu % intval;
- nexttbtt = tsftu - offset;
- if (offset)
- nexttbtt += intval;
-
- /* DTIM Beacon every dtimperiod Beacon */
- dtim_dec_count = num_beacons % dtimperiod;
- dtimcount -= dtim_dec_count;
- if (dtimcount < 0)
- dtimcount += dtimperiod;
-
- bs.bs_intval = TU_TO_USEC(intval);
- bs.bs_nexttbtt = TU_TO_USEC(nexttbtt);
- bs.bs_dtimperiod = dtimperiod * bs.bs_intval;
- bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount * bs.bs_intval;
-
- /*
- * Calculate the number of consecutive beacons to miss* before taking
- * a BMISS interrupt. The configuration is specified in TU so we only
- * need calculate based on the beacon interval. Note that we clamp the
- * result to at most 15 beacons.
- */
- if (sleepduration > intval) {
- bs.bs_bmissthreshold = ATH_DEFAULT_BMISS_LIMIT / 2;
- } else {
- bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval);
- if (bs.bs_bmissthreshold > 15)
- bs.bs_bmissthreshold = 15;
- else if (bs.bs_bmissthreshold <= 0)
- bs.bs_bmissthreshold = 1;
- }
-
- /*
- * Calculate sleep duration. The configuration is given in ms.
- * We ensure a multiple of the beacon period is used. Also, if the sleep
- * duration is greater than the DTIM period then it makes senses
- * to make it a multiple of that.
- *
- * XXX fixed at 100ms
- */
-
- bs.bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100),
- sleepduration));
- if (bs.bs_sleepduration > bs.bs_dtimperiod)
- bs.bs_sleepduration = bs.bs_dtimperiod;
-
- /* TSF out of range threshold fixed at 1 second */
- bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
-
- ath_dbg(common, CONFIG, "intval: %u tsf: %llu tsftu: %u\n",
- intval, tsf, tsftu);
- ath_dbg(common, CONFIG, "bmiss: %u sleep: %u\n",
- bs.bs_bmissthreshold, bs.bs_sleepduration);
-
- /* Set the computed STA beacon timers */
+ if (conf->intval >= TU_TO_USEC(DEFAULT_SWBA_RESPONSE))
+ ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE;
+ else
+ ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;
WMI_CMD(WMI_DISABLE_INTR_CMDID);
- ath9k_hw_set_sta_beacon_timers(priv->ah, &bs);
- imask |= ATH9K_INT_BMISS;
- htc_imask = cpu_to_be32(imask);
+ if (reset_tsf)
+ ath9k_hw_reset_tsf(ah);
+ ath9k_htc_beaconq_config(priv);
+ ath9k_hw_beaconinit(ah, conf->nexttbtt, conf->intval);
+ priv->beacon.bmisscnt = 0;
+ htc_imask = cpu_to_be32(ah->imask);
WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
}
-static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
- struct htc_beacon_config *bss_conf)
+static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
+ struct ath_beacon_config *bss_conf)
{
- struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_beacon_state bs;
enum ath9k_int imask = 0;
- u32 nexttbtt, intval, tsftu;
__be32 htc_imask = 0;
int ret __attribute__ ((unused));
u8 cmd_rsp;
- u64 tsf;
- intval = bss_conf->beacon_interval;
- intval /= ATH9K_HTC_MAX_BCN_VIF;
- nexttbtt = intval;
-
- /*
- * To reduce beacon misses under heavy TX load,
- * set the beacon response time to a larger value.
- */
- if (intval > DEFAULT_SWBA_RESPONSE)
- priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE;
- else
- priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;
-
- if (test_bit(OP_TSF_RESET, &priv->op_flags)) {
- ath9k_hw_reset_tsf(priv->ah);
- clear_bit(OP_TSF_RESET, &priv->op_flags);
- } else {
- /*
- * Pull nexttbtt forward to reflect the current TSF.
- */
- tsf = ath9k_hw_gettsf64(priv->ah);
- tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE;
- do {
- nexttbtt += intval;
- } while (nexttbtt < tsftu);
- }
-
- if (test_bit(OP_ENABLE_BEACON, &priv->op_flags))
- imask |= ATH9K_INT_SWBA;
-
- ath_dbg(common, CONFIG,
- "AP Beacon config, intval: %d, nexttbtt: %u, resp_time: %d imask: 0x%x\n",
- bss_conf->beacon_interval, nexttbtt,
- priv->ah->config.sw_beacon_response_time, imask);
-
- ath9k_htc_beaconq_config(priv);
+ if (ath9k_cmn_beacon_config_sta(priv->ah, bss_conf, &bs) == -EPERM)
+ return;
WMI_CMD(WMI_DISABLE_INTR_CMDID);
- ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
- priv->cur_beacon_conf.bmiss_cnt = 0;
+ ath9k_hw_set_sta_beacon_timers(priv->ah, &bs);
+ imask |= ATH9K_INT_BMISS;
htc_imask = cpu_to_be32(imask);
WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
}
-static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
- struct htc_beacon_config *bss_conf)
+static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
+ struct ath_beacon_config *conf)
{
- struct ath_common *common = ath9k_hw_common(priv->ah);
- enum ath9k_int imask = 0;
- u32 nexttbtt, intval, tsftu;
- __be32 htc_imask = 0;
- int ret __attribute__ ((unused));
- u8 cmd_rsp;
- u64 tsf;
-
- intval = bss_conf->beacon_interval;
- nexttbtt = intval;
-
- /*
- * Pull nexttbtt forward to reflect the current TSF.
- */
- tsf = ath9k_hw_gettsf64(priv->ah);
- tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE;
- do {
- nexttbtt += intval;
- } while (nexttbtt < tsftu);
-
- /*
- * Only one IBSS interfce is allowed.
- */
- if (intval > DEFAULT_SWBA_RESPONSE)
- priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE;
- else
- priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;
+ struct ath_hw *ah = priv->ah;
+ ah->imask = 0;
- if (test_bit(OP_ENABLE_BEACON, &priv->op_flags))
- imask |= ATH9K_INT_SWBA;
+ ath9k_cmn_beacon_config_ap(ah, conf, ATH9K_HTC_MAX_BCN_VIF);
+ ath9k_htc_beacon_init(priv, conf, false);
+}
- ath_dbg(common, CONFIG,
- "IBSS Beacon config, intval: %d, nexttbtt: %u, resp_time: %d, imask: 0x%x\n",
- bss_conf->beacon_interval, nexttbtt,
- priv->ah->config.sw_beacon_response_time, imask);
+static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
+ struct ath_beacon_config *conf)
+{
+ struct ath_hw *ah = priv->ah;
+ ah->imask = 0;
- WMI_CMD(WMI_DISABLE_INTR_CMDID);
- ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
- priv->cur_beacon_conf.bmiss_cnt = 0;
- htc_imask = cpu_to_be32(imask);
- WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
+ ath9k_cmn_beacon_config_adhoc(ah, conf);
+ ath9k_htc_beacon_init(priv, conf, conf->ibss_creator);
}
void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
@@ -287,7 +145,7 @@ static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv,
spin_lock_bh(&priv->beacon_lock);
- vif = priv->cur_beacon_conf.bslot[slot];
+ vif = priv->beacon.bslot[slot];
skb = ieee80211_get_buffered_bc(priv->hw, vif);
@@ -348,10 +206,10 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv,
spin_lock_bh(&priv->beacon_lock);
- vif = priv->cur_beacon_conf.bslot[slot];
+ vif = priv->beacon.bslot[slot];
avp = (struct ath9k_htc_vif *)vif->drv_priv;
- if (unlikely(test_bit(OP_SCANNING, &priv->op_flags))) {
+ if (unlikely(test_bit(ATH_OP_SCANNING, &common->op_flags))) {
spin_unlock_bh(&priv->beacon_lock);
return;
}
@@ -431,8 +289,8 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv,
int slot;
if (swba->beacon_pending != 0) {
- priv->cur_beacon_conf.bmiss_cnt++;
- if (priv->cur_beacon_conf.bmiss_cnt > BSTUCK_THRESHOLD) {
+ priv->beacon.bmisscnt++;
+ if (priv->beacon.bmisscnt > BSTUCK_THRESHOLD) {
ath_dbg(common, BSTUCK, "Beacon stuck, HW reset\n");
ieee80211_queue_work(priv->hw,
&priv->fatal_work);
@@ -440,16 +298,16 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv,
return;
}
- if (priv->cur_beacon_conf.bmiss_cnt) {
+ if (priv->beacon.bmisscnt) {
ath_dbg(common, BSTUCK,
"Resuming beacon xmit after %u misses\n",
- priv->cur_beacon_conf.bmiss_cnt);
- priv->cur_beacon_conf.bmiss_cnt = 0;
+ priv->beacon.bmisscnt);
+ priv->beacon.bmisscnt = 0;
}
slot = ath9k_htc_choose_bslot(priv, swba);
spin_lock_bh(&priv->beacon_lock);
- if (priv->cur_beacon_conf.bslot[slot] == NULL) {
+ if (priv->beacon.bslot[slot] == NULL) {
spin_unlock_bh(&priv->beacon_lock);
return;
}
@@ -468,13 +326,13 @@ void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv,
spin_lock_bh(&priv->beacon_lock);
for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) {
- if (priv->cur_beacon_conf.bslot[i] == NULL) {
+ if (priv->beacon.bslot[i] == NULL) {
avp->bslot = i;
break;
}
}
- priv->cur_beacon_conf.bslot[avp->bslot] = vif;
+ priv->beacon.bslot[avp->bslot] = vif;
spin_unlock_bh(&priv->beacon_lock);
ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n",
@@ -488,7 +346,7 @@ void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv,
struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
spin_lock_bh(&priv->beacon_lock);
- priv->cur_beacon_conf.bslot[avp->bslot] = NULL;
+ priv->beacon.bslot[avp->bslot] = NULL;
spin_unlock_bh(&priv->beacon_lock);
ath_dbg(common, CONFIG, "Removed interface at beacon slot: %d\n",
@@ -504,7 +362,7 @@ void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv,
{
struct ath_common *common = ath9k_hw_common(priv->ah);
struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
- struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
+ struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf;
u64 tsfadjust;
if (avp->bslot == 0)
@@ -536,7 +394,7 @@ static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
- struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
+ struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf;
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
bool beacon_configured;
@@ -591,7 +449,7 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
- struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
+ struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf;
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv;
@@ -627,7 +485,7 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
- struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
+ struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf;
switch (priv->ah->opmode) {
case NL80211_IFTYPE_STATION:
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index f4e1de20d99c..8a3bd5fe3a54 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -34,92 +34,9 @@ static int ath9k_htc_btcoex_enable;
module_param_named(btcoex_enable, ath9k_htc_btcoex_enable, int, 0444);
MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence");
-#define CHAN2G(_freq, _idx) { \
- .center_freq = (_freq), \
- .hw_value = (_idx), \
- .max_power = 20, \
-}
-
-#define CHAN5G(_freq, _idx) { \
- .band = IEEE80211_BAND_5GHZ, \
- .center_freq = (_freq), \
- .hw_value = (_idx), \
- .max_power = 20, \
-}
-
-static struct ieee80211_channel ath9k_2ghz_channels[] = {
- CHAN2G(2412, 0), /* Channel 1 */
- CHAN2G(2417, 1), /* Channel 2 */
- CHAN2G(2422, 2), /* Channel 3 */
- CHAN2G(2427, 3), /* Channel 4 */
- CHAN2G(2432, 4), /* Channel 5 */
- CHAN2G(2437, 5), /* Channel 6 */
- CHAN2G(2442, 6), /* Channel 7 */
- CHAN2G(2447, 7), /* Channel 8 */
- CHAN2G(2452, 8), /* Channel 9 */
- CHAN2G(2457, 9), /* Channel 10 */
- CHAN2G(2462, 10), /* Channel 11 */
- CHAN2G(2467, 11), /* Channel 12 */
- CHAN2G(2472, 12), /* Channel 13 */
- CHAN2G(2484, 13), /* Channel 14 */
-};
-
-static struct ieee80211_channel ath9k_5ghz_channels[] = {
- /* _We_ call this UNII 1 */
- CHAN5G(5180, 14), /* Channel 36 */
- CHAN5G(5200, 15), /* Channel 40 */
- CHAN5G(5220, 16), /* Channel 44 */
- CHAN5G(5240, 17), /* Channel 48 */
- /* _We_ call this UNII 2 */
- CHAN5G(5260, 18), /* Channel 52 */
- CHAN5G(5280, 19), /* Channel 56 */
- CHAN5G(5300, 20), /* Channel 60 */
- CHAN5G(5320, 21), /* Channel 64 */
- /* _We_ call this "Middle band" */
- CHAN5G(5500, 22), /* Channel 100 */
- CHAN5G(5520, 23), /* Channel 104 */
- CHAN5G(5540, 24), /* Channel 108 */
- CHAN5G(5560, 25), /* Channel 112 */
- CHAN5G(5580, 26), /* Channel 116 */
- CHAN5G(5600, 27), /* Channel 120 */
- CHAN5G(5620, 28), /* Channel 124 */
- CHAN5G(5640, 29), /* Channel 128 */
- CHAN5G(5660, 30), /* Channel 132 */
- CHAN5G(5680, 31), /* Channel 136 */
- CHAN5G(5700, 32), /* Channel 140 */
- /* _We_ call this UNII 3 */
- CHAN5G(5745, 33), /* Channel 149 */
- CHAN5G(5765, 34), /* Channel 153 */
- CHAN5G(5785, 35), /* Channel 157 */
- CHAN5G(5805, 36), /* Channel 161 */
- CHAN5G(5825, 37), /* Channel 165 */
-};
-
-/* Atheros hardware rate code addition for short premble */
-#define SHPCHECK(__hw_rate, __flags) \
- ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04) : 0)
-
-#define RATE(_bitrate, _hw_rate, _flags) { \
- .bitrate = (_bitrate), \
- .flags = (_flags), \
- .hw_value = (_hw_rate), \
- .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \
-}
-
-static struct ieee80211_rate ath9k_legacy_rates[] = {
- RATE(10, 0x1b, 0),
- RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp : 0x1e */
- RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp: 0x1d */
- RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), /* short: 0x1c */
- RATE(60, 0x0b, 0),
- RATE(90, 0x0f, 0),
- RATE(120, 0x0a, 0),
- RATE(180, 0x0e, 0),
- RATE(240, 0x09, 0),
- RATE(360, 0x0d, 0),
- RATE(480, 0x08, 0),
- RATE(540, 0x0c, 0),
-};
+static int ath9k_ps_enable;
+module_param_named(ps_enable, ath9k_ps_enable, int, 0444);
+MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave");
#ifdef CONFIG_MAC80211_LEDS
static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = {
@@ -339,6 +256,25 @@ static void ath9k_multi_regread(void *hw_priv, u32 *addr,
}
}
+static void ath9k_regwrite_multi(struct ath_common *common)
+{
+ struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+ u32 rsp_status;
+ int r;
+
+ r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
+ (u8 *) &priv->wmi->multi_write,
+ sizeof(struct register_write) * priv->wmi->multi_write_idx,
+ (u8 *) &rsp_status, sizeof(rsp_status),
+ 100);
+ if (unlikely(r)) {
+ ath_dbg(common, WMI,
+ "REGISTER WRITE FAILED, multi len: %d\n",
+ priv->wmi->multi_write_idx);
+ }
+ priv->wmi->multi_write_idx = 0;
+}
+
static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset)
{
struct ath_hw *ah = (struct ath_hw *) hw_priv;
@@ -365,8 +301,6 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset)
struct ath_hw *ah = (struct ath_hw *) hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
- u32 rsp_status;
- int r;
mutex_lock(&priv->wmi->multi_write_mutex);
@@ -379,19 +313,8 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset)
priv->wmi->multi_write_idx++;
/* If the buffer is full, send it out. */
- if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) {
- r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
- (u8 *) &priv->wmi->multi_write,
- sizeof(struct register_write) * priv->wmi->multi_write_idx,
- (u8 *) &rsp_status, sizeof(rsp_status),
- 100);
- if (unlikely(r)) {
- ath_dbg(common, WMI,
- "REGISTER WRITE FAILED, multi len: %d\n",
- priv->wmi->multi_write_idx);
- }
- priv->wmi->multi_write_idx = 0;
- }
+ if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER)
+ ath9k_regwrite_multi(common);
mutex_unlock(&priv->wmi->multi_write_mutex);
}
@@ -422,26 +345,13 @@ static void ath9k_regwrite_flush(void *hw_priv)
struct ath_hw *ah = (struct ath_hw *) hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
- u32 rsp_status;
- int r;
atomic_dec(&priv->wmi->mwrite_cnt);
mutex_lock(&priv->wmi->multi_write_mutex);
- if (priv->wmi->multi_write_idx) {
- r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
- (u8 *) &priv->wmi->multi_write,
- sizeof(struct register_write) * priv->wmi->multi_write_idx,
- (u8 *) &rsp_status, sizeof(rsp_status),
- 100);
- if (unlikely(r)) {
- ath_dbg(common, WMI,
- "REGISTER WRITE FAILED, multi len: %d\n",
- priv->wmi->multi_write_idx);
- }
- priv->wmi->multi_write_idx = 0;
- }
+ if (priv->wmi->multi_write_idx)
+ ath9k_regwrite_multi(common);
mutex_unlock(&priv->wmi->multi_write_mutex);
}
@@ -487,51 +397,6 @@ static const struct ath_bus_ops ath9k_usb_bus_ops = {
.eeprom_read = ath_usb_eeprom_read,
};
-static void setup_ht_cap(struct ath9k_htc_priv *priv,
- struct ieee80211_sta_ht_cap *ht_info)
-{
- struct ath_common *common = ath9k_hw_common(priv->ah);
- u8 tx_streams, rx_streams;
- int i;
-
- ht_info->ht_supported = true;
- ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
- IEEE80211_HT_CAP_SM_PS |
- IEEE80211_HT_CAP_SGI_40 |
- IEEE80211_HT_CAP_DSSSCCK40;
-
- if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
- ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
-
- ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
-
- ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
- ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
-
- memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
-
- /* ath9k_htc supports only 1 or 2 stream devices */
- tx_streams = ath9k_cmn_count_streams(priv->ah->txchainmask, 2);
- rx_streams = ath9k_cmn_count_streams(priv->ah->rxchainmask, 2);
-
- ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n",
- tx_streams, rx_streams);
-
- if (tx_streams >= 2)
- ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
-
- if (tx_streams != rx_streams) {
- ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
- ht_info->mcs.tx_params |= ((tx_streams - 1) <<
- IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
- }
-
- for (i = 0; i < rx_streams; i++)
- ht_info->mcs.rx_mask[i] = 0xff;
-
- ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
-}
-
static int ath9k_init_queues(struct ath9k_htc_priv *priv)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
@@ -540,8 +405,8 @@ static int ath9k_init_queues(struct ath9k_htc_priv *priv)
for (i = 0; i < ARRAY_SIZE(priv->hwq_map); i++)
priv->hwq_map[i] = -1;
- priv->beaconq = ath9k_hw_beaconq_setup(priv->ah);
- if (priv->beaconq == -1) {
+ priv->beacon.beaconq = ath9k_hw_beaconq_setup(priv->ah);
+ if (priv->beacon.beaconq == -1) {
ath_err(common, "Unable to setup BEACON xmit queue\n");
goto err;
}
@@ -576,37 +441,13 @@ err:
return -EINVAL;
}
-static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv)
-{
- if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
- priv->sbands[IEEE80211_BAND_2GHZ].channels =
- ath9k_2ghz_channels;
- priv->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
- priv->sbands[IEEE80211_BAND_2GHZ].n_channels =
- ARRAY_SIZE(ath9k_2ghz_channels);
- priv->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
- priv->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
- ARRAY_SIZE(ath9k_legacy_rates);
- }
-
- if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
- priv->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_channels;
- priv->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
- priv->sbands[IEEE80211_BAND_5GHZ].n_channels =
- ARRAY_SIZE(ath9k_5ghz_channels);
- priv->sbands[IEEE80211_BAND_5GHZ].bitrates =
- ath9k_legacy_rates + 4;
- priv->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
- ARRAY_SIZE(ath9k_legacy_rates) - 4;
- }
-}
-
static void ath9k_init_misc(struct ath9k_htc_priv *priv)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
+ common->last_rssi = ATH_RSSI_DUMMY_MARKER;
priv->ah->opmode = NL80211_IFTYPE_STATION;
}
@@ -618,12 +459,11 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
struct ath_common *common;
int i, ret = 0, csz = 0;
- set_bit(OP_INVALID, &priv->op_flags);
-
ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
if (!ah)
return -ENOMEM;
+ ah->dev = priv->dev;
ah->hw_version.devid = devid;
ah->hw_version.usbdev = drv_info;
ah->ah_flags |= AH_USE_EEPROM;
@@ -643,6 +483,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
common->priv = priv;
common->debug_mask = ath9k_debug;
common->btcoex_enabled = ath9k_htc_btcoex_enable == 1;
+ set_bit(ATH_OP_INVALID, &common->op_flags);
spin_lock_init(&priv->beacon_lock);
spin_lock_init(&priv->tx.tx_lock);
@@ -678,10 +519,11 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
goto err_queues;
for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++)
- priv->cur_beacon_conf.bslot[i] = NULL;
+ priv->beacon.bslot[i] = NULL;
+ priv->beacon.slottime = ATH9K_SLOT_TIME_9;
+ ath9k_cmn_init_channels_rates(common);
ath9k_cmn_init_crypto(ah);
- ath9k_init_channels_rates(priv);
ath9k_init_misc(priv);
ath9k_htc_init_btcoex(priv, product);
@@ -717,6 +559,7 @@ static const struct ieee80211_iface_combination if_comb = {
static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
struct ieee80211_hw *hw)
{
+ struct ath_hw *ah = priv->ah;
struct ath_common *common = ath9k_hw_common(priv->ah);
struct base_eep_header *pBase;
@@ -725,12 +568,14 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
IEEE80211_HW_SPECTRUM_MGMT |
IEEE80211_HW_HAS_RATE_CONTROL |
IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_MFP_CAPABLE |
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ if (ath9k_ps_enable)
+ hw->flags |= IEEE80211_HW_SUPPORTS_PS;
+
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) |
@@ -759,19 +604,12 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
- &priv->sbands[IEEE80211_BAND_2GHZ];
+ &common->sbands[IEEE80211_BAND_2GHZ];
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
- &priv->sbands[IEEE80211_BAND_5GHZ];
-
- if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
- if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
- setup_ht_cap(priv,
- &priv->sbands[IEEE80211_BAND_2GHZ].ht_cap);
- if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
- setup_ht_cap(priv,
- &priv->sbands[IEEE80211_BAND_5GHZ].ht_cap);
- }
+ &common->sbands[IEEE80211_BAND_5GHZ];
+
+ ath9k_cmn_reload_chainmask(ah);
pBase = ath9k_htc_get_eeprom_base(priv);
if (pBase) {
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 608d739d1378..f46cd0250e48 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -250,7 +250,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
u8 cmd_rsp;
int ret;
- if (test_bit(OP_INVALID, &priv->op_flags))
+ if (test_bit(ATH_OP_INVALID, &common->op_flags))
return -EIO;
fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL);
@@ -304,7 +304,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
htc_start(priv->htc);
- if (!test_bit(OP_SCANNING, &priv->op_flags) &&
+ if (!test_bit(ATH_OP_SCANNING, &common->op_flags) &&
!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
ath9k_htc_vif_reconfig(priv);
@@ -748,7 +748,7 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv)
common->ani.shortcal_timer = timestamp;
common->ani.checkani_timer = timestamp;
- set_bit(OP_ANI_RUNNING, &priv->op_flags);
+ set_bit(ATH_OP_ANI_RUN, &common->op_flags);
ieee80211_queue_delayed_work(common->hw, &priv->ani_work,
msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
@@ -756,8 +756,9 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv)
void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv)
{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
cancel_delayed_work_sync(&priv->ani_work);
- clear_bit(OP_ANI_RUNNING, &priv->op_flags);
+ clear_bit(ATH_OP_ANI_RUN, &common->op_flags);
}
void ath9k_htc_ani_work(struct work_struct *work)
@@ -942,7 +943,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
ath_dbg(common, CONFIG,
"Failed to update capability in target\n");
- clear_bit(OP_INVALID, &priv->op_flags);
+ clear_bit(ATH_OP_INVALID, &common->op_flags);
htc_start(priv->htc);
spin_lock_bh(&priv->tx.tx_lock);
@@ -971,7 +972,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
mutex_lock(&priv->mutex);
- if (test_bit(OP_INVALID, &priv->op_flags)) {
+ if (test_bit(ATH_OP_INVALID, &common->op_flags)) {
ath_dbg(common, ANY, "Device not present\n");
mutex_unlock(&priv->mutex);
return;
@@ -1013,7 +1014,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
ath9k_htc_ps_restore(priv);
ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
- set_bit(OP_INVALID, &priv->op_flags);
+ set_bit(ATH_OP_INVALID, &common->op_flags);
ath_dbg(common, CONFIG, "Driver halt\n");
mutex_unlock(&priv->mutex);
@@ -1087,7 +1088,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
ath9k_htc_set_opmode(priv);
if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
- !test_bit(OP_ANI_RUNNING, &priv->op_flags)) {
+ !test_bit(ATH_OP_ANI_RUN, &common->op_flags)) {
ath9k_hw_set_tsfadjust(priv->ah, true);
ath9k_htc_start_ani(priv);
}
@@ -1245,13 +1246,14 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
u64 multicast)
{
struct ath9k_htc_priv *priv = hw->priv;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
u32 rfilt;
mutex_lock(&priv->mutex);
changed_flags &= SUPPORTED_FILTERS;
*total_flags &= SUPPORTED_FILTERS;
- if (test_bit(OP_INVALID, &priv->op_flags)) {
+ if (test_bit(ATH_OP_INVALID, &common->op_flags)) {
ath_dbg(ath9k_hw_common(priv->ah), ANY,
"Unable to configure filter on invalid state\n");
mutex_unlock(&priv->mutex);
@@ -1270,18 +1272,50 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
mutex_unlock(&priv->mutex);
}
+static void ath9k_htc_sta_rc_update_work(struct work_struct *work)
+{
+ struct ath9k_htc_sta *ista =
+ container_of(work, struct ath9k_htc_sta, rc_update_work);
+ struct ieee80211_sta *sta =
+ container_of((void *)ista, struct ieee80211_sta, drv_priv);
+ struct ath9k_htc_priv *priv = ista->htc_priv;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_htc_target_rate trate;
+
+ mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
+
+ memset(&trate, 0, sizeof(struct ath9k_htc_target_rate));
+ ath9k_htc_setup_rate(priv, sta, &trate);
+ if (!ath9k_htc_send_rate_cmd(priv, &trate))
+ ath_dbg(common, CONFIG,
+ "Supported rates for sta: %pM updated, rate caps: 0x%X\n",
+ sta->addr, be32_to_cpu(trate.capflags));
+ else
+ ath_dbg(common, CONFIG,
+ "Unable to update supported rates for sta: %pM\n",
+ sta->addr);
+
+ ath9k_htc_ps_restore(priv);
+ mutex_unlock(&priv->mutex);
+}
+
static int ath9k_htc_sta_add(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct ath9k_htc_priv *priv = hw->priv;
+ struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv;
int ret;
mutex_lock(&priv->mutex);
ath9k_htc_ps_wakeup(priv);
ret = ath9k_htc_add_station(priv, vif, sta);
- if (!ret)
+ if (!ret) {
+ INIT_WORK(&ista->rc_update_work, ath9k_htc_sta_rc_update_work);
+ ista->htc_priv = priv;
ath9k_htc_init_rate(priv, sta);
+ }
ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
@@ -1293,12 +1327,13 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_sta *sta)
{
struct ath9k_htc_priv *priv = hw->priv;
- struct ath9k_htc_sta *ista;
+ struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv;
int ret;
+ cancel_work_sync(&ista->rc_update_work);
+
mutex_lock(&priv->mutex);
ath9k_htc_ps_wakeup(priv);
- ista = (struct ath9k_htc_sta *) sta->drv_priv;
htc_sta_drain(priv->htc, ista->index);
ret = ath9k_htc_remove_station(priv, vif, sta);
ath9k_htc_ps_restore(priv);
@@ -1311,28 +1346,12 @@ static void ath9k_htc_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u32 changed)
{
- struct ath9k_htc_priv *priv = hw->priv;
- struct ath_common *common = ath9k_hw_common(priv->ah);
- struct ath9k_htc_target_rate trate;
-
- mutex_lock(&priv->mutex);
- ath9k_htc_ps_wakeup(priv);
+ struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv;
- if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
- memset(&trate, 0, sizeof(struct ath9k_htc_target_rate));
- ath9k_htc_setup_rate(priv, sta, &trate);
- if (!ath9k_htc_send_rate_cmd(priv, &trate))
- ath_dbg(common, CONFIG,
- "Supported rates for sta: %pM updated, rate caps: 0x%X\n",
- sta->addr, be32_to_cpu(trate.capflags));
- else
- ath_dbg(common, CONFIG,
- "Unable to update supported rates for sta: %pM\n",
- sta->addr);
- }
+ if (!(changed & IEEE80211_RC_SUPP_RATES_CHANGED))
+ return;
- ath9k_htc_ps_restore(priv);
- mutex_unlock(&priv->mutex);
+ schedule_work(&ista->rc_update_work);
}
static int ath9k_htc_conf_tx(struct ieee80211_hw *hw,
@@ -1457,7 +1476,9 @@ static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
if ((vif->type == NL80211_IFTYPE_STATION) && bss_conf->assoc) {
common->curaid = bss_conf->aid;
+ common->last_rssi = ATH_RSSI_DUMMY_MARKER;
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
+ set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags);
}
}
@@ -1479,6 +1500,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
struct ath9k_htc_priv *priv = hw->priv;
struct ath_hw *ah = priv->ah;
struct ath_common *common = ath9k_hw_common(ah);
+ int slottime;
mutex_lock(&priv->mutex);
ath9k_htc_ps_wakeup(priv);
@@ -1490,6 +1512,9 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
bss_conf->assoc ?
priv->num_sta_assoc_vif++ : priv->num_sta_assoc_vif--;
+ if (!bss_conf->assoc)
+ clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags);
+
if (priv->ah->opmode == NL80211_IFTYPE_STATION) {
ath9k_htc_choose_set_bssid(priv);
if (bss_conf->assoc && (priv->num_sta_assoc_vif == 1))
@@ -1511,7 +1536,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
ath_dbg(common, CONFIG, "Beacon enabled for BSS: %pM\n",
bss_conf->bssid);
ath9k_htc_set_tsfadjust(priv, vif);
- set_bit(OP_ENABLE_BEACON, &priv->op_flags);
+ priv->cur_beacon_conf.enable_beacon = 1;
ath9k_htc_beacon_config(priv, vif);
}
@@ -1525,7 +1550,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
ath_dbg(common, CONFIG,
"Beacon disabled for BSS: %pM\n",
bss_conf->bssid);
- clear_bit(OP_ENABLE_BEACON, &priv->op_flags);
+ priv->cur_beacon_conf.enable_beacon = 0;
ath9k_htc_beacon_config(priv, vif);
}
}
@@ -1551,11 +1576,21 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_ERP_SLOT) {
if (bss_conf->use_short_slot)
- ah->slottime = 9;
+ slottime = 9;
else
- ah->slottime = 20;
-
- ath9k_hw_init_global_settings(ah);
+ slottime = 20;
+ if (vif->type == NL80211_IFTYPE_AP) {
+ /*
+ * Defer update, so that connected stations can adjust
+ * their settings at the same time.
+ * See beacon.c for more details
+ */
+ priv->beacon.slottime = slottime;
+ priv->beacon.updateslot = UPDATE;
+ } else {
+ ah->slottime = slottime;
+ ath9k_hw_init_global_settings(ah);
+ }
}
if (changed & BSS_CHANGED_HT)
@@ -1652,10 +1687,11 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
{
struct ath9k_htc_priv *priv = hw->priv;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
mutex_lock(&priv->mutex);
spin_lock_bh(&priv->beacon_lock);
- set_bit(OP_SCANNING, &priv->op_flags);
+ set_bit(ATH_OP_SCANNING, &common->op_flags);
spin_unlock_bh(&priv->beacon_lock);
cancel_work_sync(&priv->ps_work);
ath9k_htc_stop_ani(priv);
@@ -1665,10 +1701,11 @@ static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
{
struct ath9k_htc_priv *priv = hw->priv;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
mutex_lock(&priv->mutex);
spin_lock_bh(&priv->beacon_lock);
- clear_bit(OP_SCANNING, &priv->op_flags);
+ clear_bit(ATH_OP_SCANNING, &common->op_flags);
spin_unlock_bh(&priv->beacon_lock);
ath9k_htc_ps_wakeup(priv);
ath9k_htc_vif_reconfig(priv);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index 12e0f32a4905..e8149e3dbdd5 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -924,46 +924,43 @@ static void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv)
void ath9k_host_rx_init(struct ath9k_htc_priv *priv)
{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
ath9k_hw_rxena(priv->ah);
ath9k_htc_opmode_init(priv);
- ath9k_hw_startpcureceive(priv->ah, test_bit(OP_SCANNING, &priv->op_flags));
- priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER;
+ ath9k_hw_startpcureceive(priv->ah, test_bit(ATH_OP_SCANNING, &common->op_flags));
}
-static void ath9k_process_rate(struct ieee80211_hw *hw,
- struct ieee80211_rx_status *rxs,
- u8 rx_rate, u8 rs_flags)
+static inline void convert_htc_flag(struct ath_rx_status *rx_stats,
+ struct ath_htc_rx_status *rxstatus)
{
- struct ieee80211_supported_band *sband;
- enum ieee80211_band band;
- unsigned int i = 0;
-
- if (rx_rate & 0x80) {
- /* HT rate */
- rxs->flag |= RX_FLAG_HT;
- if (rs_flags & ATH9K_RX_2040)
- rxs->flag |= RX_FLAG_40MHZ;
- if (rs_flags & ATH9K_RX_GI)
- rxs->flag |= RX_FLAG_SHORT_GI;
- rxs->rate_idx = rx_rate & 0x7f;
- return;
- }
-
- band = hw->conf.chandef.chan->band;
- sband = hw->wiphy->bands[band];
-
- for (i = 0; i < sband->n_bitrates; i++) {
- if (sband->bitrates[i].hw_value == rx_rate) {
- rxs->rate_idx = i;
- return;
- }
- if (sband->bitrates[i].hw_value_short == rx_rate) {
- rxs->rate_idx = i;
- rxs->flag |= RX_FLAG_SHORTPRE;
- return;
- }
- }
+ rx_stats->flag = 0;
+ if (rxstatus->rs_flags & ATH9K_RX_2040)
+ rx_stats->flag |= RX_FLAG_40MHZ;
+ if (rxstatus->rs_flags & ATH9K_RX_GI)
+ rx_stats->flag |= RX_FLAG_SHORT_GI;
+}
+static void rx_status_htc_to_ath(struct ath_rx_status *rx_stats,
+ struct ath_htc_rx_status *rxstatus)
+{
+ rx_stats->rs_datalen = rxstatus->rs_datalen;
+ rx_stats->rs_status = rxstatus->rs_status;
+ rx_stats->rs_phyerr = rxstatus->rs_phyerr;
+ rx_stats->rs_rssi = rxstatus->rs_rssi;
+ rx_stats->rs_keyix = rxstatus->rs_keyix;
+ rx_stats->rs_rate = rxstatus->rs_rate;
+ rx_stats->rs_antenna = rxstatus->rs_antenna;
+ rx_stats->rs_more = rxstatus->rs_more;
+
+ memcpy(rx_stats->rs_rssi_ctl, rxstatus->rs_rssi_ctl,
+ sizeof(rx_stats->rs_rssi_ctl));
+ memcpy(rx_stats->rs_rssi_ext, rxstatus->rs_rssi_ext,
+ sizeof(rx_stats->rs_rssi_ext));
+
+ rx_stats->rs_isaggr = rxstatus->rs_isaggr;
+ rx_stats->rs_moreaggr = rxstatus->rs_moreaggr;
+ rx_stats->rs_num_delims = rxstatus->rs_num_delims;
+ convert_htc_flag(rx_stats, rxstatus);
}
static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
@@ -975,10 +972,10 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
struct ieee80211_hw *hw = priv->hw;
struct sk_buff *skb = rxbuf->skb;
struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath_hw *ah = common->ah;
struct ath_htc_rx_status *rxstatus;
- int hdrlen, padsize;
- int last_rssi = ATH_RSSI_DUMMY_MARKER;
- __le16 fc;
+ struct ath_rx_status rx_stats;
+ bool decrypt_error;
if (skb->len < HTC_RX_FRAME_HEADER_SIZE) {
ath_err(common, "Corrupted RX frame, dropping (len: %d)\n",
@@ -999,103 +996,39 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
ath9k_htc_err_stat_rx(priv, rxstatus);
/* Get the RX status information */
- memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE);
- skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE);
-
- hdr = (struct ieee80211_hdr *)skb->data;
- fc = hdr->frame_control;
- hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-
- padsize = hdrlen & 3;
- if (padsize && skb->len >= hdrlen+padsize+FCS_LEN) {
- memmove(skb->data + padsize, skb->data, hdrlen);
- skb_pull(skb, padsize);
- }
memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
- if (rxbuf->rxstatus.rs_status != 0) {
- if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_CRC)
- rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
- if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_PHY)
- goto rx_next;
-
- if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT) {
- /* FIXME */
- } else if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_MIC) {
- if (ieee80211_is_ctl(fc))
- /*
- * Sometimes, we get invalid
- * MIC failures on valid control frames.
- * Remove these mic errors.
- */
- rxbuf->rxstatus.rs_status &= ~ATH9K_RXERR_MIC;
- else
- rx_status->flag |= RX_FLAG_MMIC_ERROR;
- }
-
- /*
- * Reject error frames with the exception of
- * decryption and MIC failures. For monitor mode,
- * we also ignore the CRC error.
- */
- if (priv->ah->opmode == NL80211_IFTYPE_MONITOR) {
- if (rxbuf->rxstatus.rs_status &
- ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
- ATH9K_RXERR_CRC))
- goto rx_next;
- } else {
- if (rxbuf->rxstatus.rs_status &
- ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
- goto rx_next;
- }
- }
- }
-
- if (!(rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT)) {
- u8 keyix;
- keyix = rxbuf->rxstatus.rs_keyix;
- if (keyix != ATH9K_RXKEYIX_INVALID) {
- rx_status->flag |= RX_FLAG_DECRYPTED;
- } else if (ieee80211_has_protected(fc) &&
- skb->len >= hdrlen + 4) {
- keyix = skb->data[hdrlen + 3] >> 6;
- if (test_bit(keyix, common->keymap))
- rx_status->flag |= RX_FLAG_DECRYPTED;
- }
- }
-
- ath9k_process_rate(hw, rx_status, rxbuf->rxstatus.rs_rate,
- rxbuf->rxstatus.rs_flags);
-
- if (rxbuf->rxstatus.rs_rssi != ATH9K_RSSI_BAD &&
- !rxbuf->rxstatus.rs_moreaggr)
- ATH_RSSI_LPF(priv->rx.last_rssi,
- rxbuf->rxstatus.rs_rssi);
-
- last_rssi = priv->rx.last_rssi;
+ /* Copy everything from ath_htc_rx_status (HTC_RX_FRAME_HEADER).
+ * After this, we can drop this part of skb. */
+ rx_status_htc_to_ath(&rx_stats, rxstatus);
+ rx_status->mactime = be64_to_cpu(rxstatus->rs_tstamp);
+ skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE);
- if (ath_is_mybeacon(common, hdr)) {
- s8 rssi = rxbuf->rxstatus.rs_rssi;
+ /*
+ * everything but the rate is checked here, the rate check is done
+ * separately to avoid doing two lookups for a rate for each frame.
+ */
+ hdr = (struct ieee80211_hdr *)skb->data;
+ if (!ath9k_cmn_rx_accept(common, hdr, rx_status, &rx_stats,
+ &decrypt_error, priv->rxfilter))
+ goto rx_next;
- if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
- rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER);
+ ath9k_cmn_rx_skb_postprocess(common, skb, &rx_stats,
+ rx_status, decrypt_error);
- if (rssi < 0)
- rssi = 0;
+ if (ath9k_cmn_process_rate(common, hw, &rx_stats, rx_status))
+ goto rx_next;
- priv->ah->stats.avgbrssi = rssi;
- }
+ rx_stats.is_mybeacon = ath_is_mybeacon(common, hdr);
+ ath9k_cmn_process_rssi(common, hw, &rx_stats, rx_status);
- rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp);
- rx_status->band = hw->conf.chandef.chan->band;
- rx_status->freq = hw->conf.chandef.chan->center_freq;
- rx_status->signal = rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR;
- rx_status->antenna = rxbuf->rxstatus.rs_antenna;
+ rx_status->band = ah->curchan->chan->band;
+ rx_status->freq = ah->curchan->chan->center_freq;
+ rx_status->antenna = rx_stats.rs_antenna;
rx_status->flag |= RX_FLAG_MACTIME_END;
return true;
-
rx_next:
return false;
}
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index aac4a406a513..a0ff5b637054 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -358,6 +358,36 @@ ret:
kfree_skb(skb);
}
+static void ath9k_htc_fw_panic_report(struct htc_target *htc_handle,
+ struct sk_buff *skb)
+{
+ uint32_t *pattern = (uint32_t *)skb->data;
+
+ switch (*pattern) {
+ case 0x33221199:
+ {
+ struct htc_panic_bad_vaddr *htc_panic;
+ htc_panic = (struct htc_panic_bad_vaddr *) skb->data;
+ dev_err(htc_handle->dev, "ath: firmware panic! "
+ "exccause: 0x%08x; pc: 0x%08x; badvaddr: 0x%08x.\n",
+ htc_panic->exccause, htc_panic->pc,
+ htc_panic->badvaddr);
+ break;
+ }
+ case 0x33221299:
+ {
+ struct htc_panic_bad_epid *htc_panic;
+ htc_panic = (struct htc_panic_bad_epid *) skb->data;
+ dev_err(htc_handle->dev, "ath: firmware panic! "
+ "bad epid: 0x%08x\n", htc_panic->epid);
+ break;
+ }
+ default:
+ dev_err(htc_handle->dev, "ath: uknown panic pattern!\n");
+ break;
+ }
+}
+
/*
* HTC Messages are handled directly here and the obtained SKB
* is freed.
@@ -379,6 +409,12 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle,
htc_hdr = (struct htc_frame_hdr *) skb->data;
epid = htc_hdr->endpoint_id;
+ if (epid == 0x99) {
+ ath9k_htc_fw_panic_report(htc_handle, skb);
+ kfree_skb(skb);
+ return;
+ }
+
if (epid >= ENDPOINT_MAX) {
if (pipe_id != USB_REG_IN_PIPE)
dev_kfree_skb_any(skb);
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h
index e1ffbb6bd636..06474ccc7696 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.h
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.h
@@ -77,6 +77,18 @@ struct htc_config_pipe_msg {
u8 credits;
} __packed;
+struct htc_panic_bad_vaddr {
+ __be32 pattern;
+ __be32 exccause;
+ __be32 pc;
+ __be32 badvaddr;
+} __packed;
+
+struct htc_panic_bad_epid {
+ __be32 pattern;
+ __be32 epid;
+} __packed;
+
struct htc_ep_callbacks {
void *priv;
void (*tx) (void *, struct sk_buff *, enum htc_endpoint_id, bool txok);
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index fbf43c05713f..c8a9dfab1fee 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -23,7 +23,6 @@
#include "hw.h"
#include "hw-ops.h"
-#include "rc.h"
#include "ar9003_mac.h"
#include "ar9003_mci.h"
#include "ar9003_phy.h"
@@ -883,7 +882,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
AR_IMR_RXORN |
AR_IMR_BCNMISC;
- if (AR_SREV_9340(ah) || AR_SREV_9550(ah))
+ if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah))
sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
if (AR_SREV_9300_20_OR_LATER(ah)) {
@@ -1316,7 +1315,7 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
if (AR_SREV_9300_20_OR_LATER(ah))
udelay(50);
else if (AR_SREV_9100(ah))
- udelay(10000);
+ mdelay(10);
else
udelay(100);
@@ -1534,7 +1533,7 @@ EXPORT_SYMBOL(ath9k_hw_check_nav);
bool ath9k_hw_check_alive(struct ath_hw *ah)
{
int count = 50;
- u32 reg;
+ u32 reg, last_val;
if (AR_SREV_9300(ah))
return !ath9k_hw_detect_mac_hang(ah);
@@ -1542,9 +1541,14 @@ bool ath9k_hw_check_alive(struct ath_hw *ah)
if (AR_SREV_9285_12_OR_LATER(ah))
return true;
+ last_val = REG_READ(ah, AR_OBS_BUS_1);
do {
reg = REG_READ(ah, AR_OBS_BUS_1);
+ if (reg != last_val)
+ return true;
+ udelay(1);
+ last_val = reg;
if ((reg & 0x7E7FFFEF) == 0x00702400)
continue;
@@ -2051,9 +2055,8 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah)
REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
AR_RTC_FORCE_WAKE_EN);
-
if (AR_SREV_9100(ah))
- udelay(10000);
+ mdelay(10);
else
udelay(50);
@@ -3044,6 +3047,7 @@ static struct {
{ AR_SREV_VERSION_9462, "9462" },
{ AR_SREV_VERSION_9550, "9550" },
{ AR_SREV_VERSION_9565, "9565" },
+ { AR_SREV_VERSION_9531, "9531" },
};
/* For devices with external radios */
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index c36de303c8f3..c0a4e866edca 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -57,112 +57,11 @@ static int ath9k_bt_ant_diversity;
module_param_named(bt_ant_diversity, ath9k_bt_ant_diversity, int, 0444);
MODULE_PARM_DESC(bt_ant_diversity, "Enable WLAN/BT RX antenna diversity");
-bool is_ath9k_unloaded;
-/* We use the hw_value as an index into our private channel structure */
-
-#define CHAN2G(_freq, _idx) { \
- .band = IEEE80211_BAND_2GHZ, \
- .center_freq = (_freq), \
- .hw_value = (_idx), \
- .max_power = 20, \
-}
-
-#define CHAN5G(_freq, _idx) { \
- .band = IEEE80211_BAND_5GHZ, \
- .center_freq = (_freq), \
- .hw_value = (_idx), \
- .max_power = 20, \
-}
-
-/* Some 2 GHz radios are actually tunable on 2312-2732
- * on 5 MHz steps, we support the channels which we know
- * we have calibration data for all cards though to make
- * this static */
-static const struct ieee80211_channel ath9k_2ghz_chantable[] = {
- CHAN2G(2412, 0), /* Channel 1 */
- CHAN2G(2417, 1), /* Channel 2 */
- CHAN2G(2422, 2), /* Channel 3 */
- CHAN2G(2427, 3), /* Channel 4 */
- CHAN2G(2432, 4), /* Channel 5 */
- CHAN2G(2437, 5), /* Channel 6 */
- CHAN2G(2442, 6), /* Channel 7 */
- CHAN2G(2447, 7), /* Channel 8 */
- CHAN2G(2452, 8), /* Channel 9 */
- CHAN2G(2457, 9), /* Channel 10 */
- CHAN2G(2462, 10), /* Channel 11 */
- CHAN2G(2467, 11), /* Channel 12 */
- CHAN2G(2472, 12), /* Channel 13 */
- CHAN2G(2484, 13), /* Channel 14 */
-};
+static int ath9k_ps_enable;
+module_param_named(ps_enable, ath9k_ps_enable, int, 0444);
+MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave");
-/* Some 5 GHz radios are actually tunable on XXXX-YYYY
- * on 5 MHz steps, we support the channels which we know
- * we have calibration data for all cards though to make
- * this static */
-static const struct ieee80211_channel ath9k_5ghz_chantable[] = {
- /* _We_ call this UNII 1 */
- CHAN5G(5180, 14), /* Channel 36 */
- CHAN5G(5200, 15), /* Channel 40 */
- CHAN5G(5220, 16), /* Channel 44 */
- CHAN5G(5240, 17), /* Channel 48 */
- /* _We_ call this UNII 2 */
- CHAN5G(5260, 18), /* Channel 52 */
- CHAN5G(5280, 19), /* Channel 56 */
- CHAN5G(5300, 20), /* Channel 60 */
- CHAN5G(5320, 21), /* Channel 64 */
- /* _We_ call this "Middle band" */
- CHAN5G(5500, 22), /* Channel 100 */
- CHAN5G(5520, 23), /* Channel 104 */
- CHAN5G(5540, 24), /* Channel 108 */
- CHAN5G(5560, 25), /* Channel 112 */
- CHAN5G(5580, 26), /* Channel 116 */
- CHAN5G(5600, 27), /* Channel 120 */
- CHAN5G(5620, 28), /* Channel 124 */
- CHAN5G(5640, 29), /* Channel 128 */
- CHAN5G(5660, 30), /* Channel 132 */
- CHAN5G(5680, 31), /* Channel 136 */
- CHAN5G(5700, 32), /* Channel 140 */
- /* _We_ call this UNII 3 */
- CHAN5G(5745, 33), /* Channel 149 */
- CHAN5G(5765, 34), /* Channel 153 */
- CHAN5G(5785, 35), /* Channel 157 */
- CHAN5G(5805, 36), /* Channel 161 */
- CHAN5G(5825, 37), /* Channel 165 */
-};
-
-/* Atheros hardware rate code addition for short premble */
-#define SHPCHECK(__hw_rate, __flags) \
- ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0)
-
-#define RATE(_bitrate, _hw_rate, _flags) { \
- .bitrate = (_bitrate), \
- .flags = (_flags), \
- .hw_value = (_hw_rate), \
- .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \
-}
-
-static struct ieee80211_rate ath9k_legacy_rates[] = {
- RATE(10, 0x1b, 0),
- RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE),
- RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE),
- RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE),
- RATE(60, 0x0b, (IEEE80211_RATE_SUPPORTS_5MHZ |
- IEEE80211_RATE_SUPPORTS_10MHZ)),
- RATE(90, 0x0f, (IEEE80211_RATE_SUPPORTS_5MHZ |
- IEEE80211_RATE_SUPPORTS_10MHZ)),
- RATE(120, 0x0a, (IEEE80211_RATE_SUPPORTS_5MHZ |
- IEEE80211_RATE_SUPPORTS_10MHZ)),
- RATE(180, 0x0e, (IEEE80211_RATE_SUPPORTS_5MHZ |
- IEEE80211_RATE_SUPPORTS_10MHZ)),
- RATE(240, 0x09, (IEEE80211_RATE_SUPPORTS_5MHZ |
- IEEE80211_RATE_SUPPORTS_10MHZ)),
- RATE(360, 0x0d, (IEEE80211_RATE_SUPPORTS_5MHZ |
- IEEE80211_RATE_SUPPORTS_10MHZ)),
- RATE(480, 0x08, (IEEE80211_RATE_SUPPORTS_5MHZ |
- IEEE80211_RATE_SUPPORTS_10MHZ)),
- RATE(540, 0x0c, (IEEE80211_RATE_SUPPORTS_5MHZ |
- IEEE80211_RATE_SUPPORTS_10MHZ)),
-};
+bool is_ath9k_unloaded;
#ifdef CONFIG_MAC80211_LEDS
static const struct ieee80211_tpt_blink ath9k_tpt_blink[] = {
@@ -254,64 +153,6 @@ static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 cl
/* Initialization */
/**************************/
-static void setup_ht_cap(struct ath_softc *sc,
- struct ieee80211_sta_ht_cap *ht_info)
-{
- struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(ah);
- u8 tx_streams, rx_streams;
- int i, max_streams;
-
- ht_info->ht_supported = true;
- ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
- IEEE80211_HT_CAP_SM_PS |
- IEEE80211_HT_CAP_SGI_40 |
- IEEE80211_HT_CAP_DSSSCCK40;
-
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_LDPC)
- ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
-
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
- ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
-
- ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
- ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
-
- if (AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah))
- max_streams = 1;
- else if (AR_SREV_9462(ah))
- max_streams = 2;
- else if (AR_SREV_9300_20_OR_LATER(ah))
- max_streams = 3;
- else
- max_streams = 2;
-
- if (AR_SREV_9280_20_OR_LATER(ah)) {
- if (max_streams >= 2)
- ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
- ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
- }
-
- /* set up supported mcs set */
- memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
- tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams);
- rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams);
-
- ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n",
- tx_streams, rx_streams);
-
- if (tx_streams != rx_streams) {
- ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
- ht_info->mcs.tx_params |= ((tx_streams - 1) <<
- IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
- }
-
- for (i = 0; i < rx_streams; i++)
- ht_info->mcs.rx_mask[i] = 0xff;
-
- ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
-}
-
static void ath9k_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
@@ -482,51 +323,6 @@ static int ath9k_init_queues(struct ath_softc *sc)
return 0;
}
-static int ath9k_init_channels_rates(struct ath_softc *sc)
-{
- void *channels;
-
- BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) +
- ARRAY_SIZE(ath9k_5ghz_chantable) !=
- ATH9K_NUM_CHANNELS);
-
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
- channels = devm_kzalloc(sc->dev,
- sizeof(ath9k_2ghz_chantable), GFP_KERNEL);
- if (!channels)
- return -ENOMEM;
-
- memcpy(channels, ath9k_2ghz_chantable,
- sizeof(ath9k_2ghz_chantable));
- sc->sbands[IEEE80211_BAND_2GHZ].channels = channels;
- sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
- sc->sbands[IEEE80211_BAND_2GHZ].n_channels =
- ARRAY_SIZE(ath9k_2ghz_chantable);
- sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
- sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
- ARRAY_SIZE(ath9k_legacy_rates);
- }
-
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
- channels = devm_kzalloc(sc->dev,
- sizeof(ath9k_5ghz_chantable), GFP_KERNEL);
- if (!channels)
- return -ENOMEM;
-
- memcpy(channels, ath9k_5ghz_chantable,
- sizeof(ath9k_5ghz_chantable));
- sc->sbands[IEEE80211_BAND_5GHZ].channels = channels;
- sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
- sc->sbands[IEEE80211_BAND_5GHZ].n_channels =
- ARRAY_SIZE(ath9k_5ghz_chantable);
- sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
- ath9k_legacy_rates + 4;
- sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
- ARRAY_SIZE(ath9k_legacy_rates) - 4;
- }
- return 0;
-}
-
static void ath9k_init_misc(struct ath_softc *sc)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -534,7 +330,7 @@ static void ath9k_init_misc(struct ath_softc *sc)
setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc);
- sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
+ common->last_rssi = ATH_RSSI_DUMMY_MARKER;
sc->config.txpowlimit = ATH_TXPOWER_MAX;
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
sc->beacon.slottime = ATH9K_SLOT_TIME_9;
@@ -789,7 +585,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
if (ret)
goto err_btcoex;
- ret = ath9k_init_channels_rates(sc);
+ ret = ath9k_cmn_init_channels_rates(common);
if (ret)
goto err_btcoex;
@@ -819,10 +615,11 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band)
struct ieee80211_supported_band *sband;
struct ieee80211_channel *chan;
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct cfg80211_chan_def chandef;
int i;
- sband = &sc->sbands[band];
+ sband = &common->sbands[band];
for (i = 0; i < sband->n_channels; i++) {
chan = &sband->channels[i];
ah->curchan = &ah->channels[chan->hw_value];
@@ -845,17 +642,6 @@ static void ath9k_init_txpower_limits(struct ath_softc *sc)
ah->curchan = curchan;
}
-void ath9k_reload_chainmask_settings(struct ath_softc *sc)
-{
- if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT))
- return;
-
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
- setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
- setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
-}
-
static const struct ieee80211_iface_limit if_limits[] = {
{ .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_P2P_CLIENT) |
@@ -903,13 +689,15 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK |
IEEE80211_HW_SPECTRUM_MGMT |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_SUPPORTS_RC_TABLE |
IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
+ if (ath9k_ps_enable)
+ hw->flags |= IEEE80211_HW_SUPPORTS_PS;
+
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
@@ -943,6 +731,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ;
hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
+ hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
hw->queues = 4;
hw->max_rates = 4;
@@ -963,13 +752,13 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
- &sc->sbands[IEEE80211_BAND_2GHZ];
+ &common->sbands[IEEE80211_BAND_2GHZ];
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
- &sc->sbands[IEEE80211_BAND_5GHZ];
+ &common->sbands[IEEE80211_BAND_5GHZ];
ath9k_init_wow(hw);
- ath9k_reload_chainmask_settings(sc);
+ ath9k_cmn_reload_chainmask(ah);
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
}
@@ -1100,19 +889,11 @@ static int __init ath9k_init(void)
{
int error;
- /* Register rate control algorithm */
- error = ath_rate_control_register();
- if (error != 0) {
- pr_err("Unable to register rate control algorithm: %d\n",
- error);
- goto err_out;
- }
-
error = ath_pci_init();
if (error < 0) {
pr_err("No PCI devices found, driver not installed\n");
error = -ENODEV;
- goto err_rate_unregister;
+ goto err_out;
}
error = ath_ahb_init();
@@ -1125,9 +906,6 @@ static int __init ath9k_init(void)
err_pci_exit:
ath_pci_exit();
-
- err_rate_unregister:
- ath_rate_control_unregister();
err_out:
return error;
}
@@ -1138,7 +916,6 @@ static void __exit ath9k_exit(void)
is_ath9k_unloaded = true;
ath_ahb_exit();
ath_pci_exit();
- ath_rate_control_unregister();
pr_info("%s: Driver unloaded\n", dev_info);
}
module_exit(ath9k_exit);
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c
index 30dcef5aba10..72a715fe8f24 100644
--- a/drivers/net/wireless/ath/ath9k/link.c
+++ b/drivers/net/wireless/ath/ath9k/link.c
@@ -115,13 +115,14 @@ void ath_hw_pll_work(struct work_struct *work)
u32 pll_sqsum;
struct ath_softc *sc = container_of(work, struct ath_softc,
hw_pll_work.work);
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
/*
* ensure that the PLL WAR is executed only
* after the STA is associated (or) if the
* beaconing had started in interfaces that
* uses beacons.
*/
- if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
+ if (!test_bit(ATH_OP_BEACONS, &common->op_flags))
return;
if (sc->tx99_state)
@@ -414,7 +415,7 @@ void ath_start_ani(struct ath_softc *sc)
unsigned long timestamp = jiffies_to_msecs(jiffies);
if (common->disable_ani ||
- !test_bit(SC_OP_ANI_RUN, &sc->sc_flags) ||
+ !test_bit(ATH_OP_ANI_RUN, &common->op_flags) ||
(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
return;
@@ -438,6 +439,7 @@ void ath_stop_ani(struct ath_softc *sc)
void ath_check_ani(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
/*
@@ -453,23 +455,23 @@ void ath_check_ani(struct ath_softc *sc)
* Disable ANI only when there are no
* associated stations.
*/
- if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
+ if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags))
goto stop_ani;
}
} else if (ah->opmode == NL80211_IFTYPE_STATION) {
- if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
+ if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags))
goto stop_ani;
}
- if (!test_bit(SC_OP_ANI_RUN, &sc->sc_flags)) {
- set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
+ if (!test_bit(ATH_OP_ANI_RUN, &common->op_flags)) {
+ set_bit(ATH_OP_ANI_RUN, &common->op_flags);
ath_start_ani(sc);
}
return;
stop_ani:
- clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
+ clear_bit(ATH_OP_ANI_RUN, &common->op_flags);
ath_stop_ani(sc);
}
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 5f727588ca27..51ce36f108f9 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -827,7 +827,7 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
return;
}
- if (AR_SREV_9340(ah) || AR_SREV_9550(ah))
+ if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah))
sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
async_mask = AR_INTR_MAC_IRQ;
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 10271373a0cd..89df634e81f9 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -155,12 +155,8 @@ struct ath_htc_rx_status {
u8 rs_status;
u8 rs_phyerr;
int8_t rs_rssi;
- int8_t rs_rssi_ctl0;
- int8_t rs_rssi_ctl1;
- int8_t rs_rssi_ctl2;
- int8_t rs_rssi_ext0;
- int8_t rs_rssi_ext1;
- int8_t rs_rssi_ext2;
+ int8_t rs_rssi_ctl[3];
+ int8_t rs_rssi_ext[3];
u8 rs_keyix;
u8 rs_rate;
u8 rs_antenna;
@@ -170,6 +166,7 @@ struct ath_htc_rx_status {
u8 rs_num_delims;
u8 rs_flags;
u8 rs_dummy;
+ /* FIXME: evm* never used? */
__be32 evm0;
__be32 evm1;
__be32 evm2;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 5924f72dd493..d69853b848ce 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -229,16 +229,16 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
ath9k_cmn_update_txpow(ah, sc->curtxpow,
sc->config.txpowlimit, &sc->curtxpow);
- clear_bit(SC_OP_HW_RESET, &sc->sc_flags);
+ clear_bit(ATH_OP_HW_RESET, &common->op_flags);
ath9k_hw_set_interrupts(ah);
ath9k_hw_enable_interrupts(ah);
if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && start) {
- if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
+ if (!test_bit(ATH_OP_BEACONS, &common->op_flags))
goto work;
if (ah->opmode == NL80211_IFTYPE_STATION &&
- test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
+ test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) {
spin_lock_irqsave(&sc->sc_pm_lock, flags);
sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
@@ -336,7 +336,7 @@ static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chand
int old_pos = -1;
int r;
- if (test_bit(SC_OP_INVALID, &sc->sc_flags))
+ if (test_bit(ATH_OP_INVALID, &common->op_flags))
return -EIO;
offchannel = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL);
@@ -402,7 +402,7 @@ static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chand
chan->center_freq);
} else {
/* perform spectral scan if requested. */
- if (test_bit(SC_OP_SCANNING, &sc->sc_flags) &&
+ if (test_bit(ATH_OP_SCANNING, &common->op_flags) &&
sc->spectral_mode == SPECTRAL_CHANSCAN)
ath9k_spectral_scan_trigger(hw);
}
@@ -451,7 +451,7 @@ void ath9k_tasklet(unsigned long data)
* interrupts are enabled in the reset routine.
*/
atomic_inc(&ah->intr_ref_cnt);
- ath_dbg(common, ANY, "FATAL: Skipping interrupts\n");
+ ath_dbg(common, RESET, "FATAL: Skipping interrupts\n");
goto out;
}
@@ -471,7 +471,7 @@ void ath9k_tasklet(unsigned long data)
* interrupts are enabled in the reset routine.
*/
atomic_inc(&ah->intr_ref_cnt);
- ath_dbg(common, ANY,
+ ath_dbg(common, RESET,
"BB_WATCHDOG: Skipping interrupts\n");
goto out;
}
@@ -484,7 +484,7 @@ void ath9k_tasklet(unsigned long data)
type = RESET_TYPE_TX_GTT;
ath9k_queue_reset(sc, type);
atomic_inc(&ah->intr_ref_cnt);
- ath_dbg(common, ANY,
+ ath_dbg(common, RESET,
"GTT: Skipping interrupts\n");
goto out;
}
@@ -566,6 +566,7 @@ irqreturn_t ath_isr(int irq, void *dev)
struct ath_softc *sc = dev;
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
enum ath9k_int status;
u32 sync_cause = 0;
bool sched = false;
@@ -575,7 +576,7 @@ irqreturn_t ath_isr(int irq, void *dev)
* touch anything. Note this can happen early
* on if the IRQ is shared.
*/
- if (test_bit(SC_OP_INVALID, &sc->sc_flags))
+ if (test_bit(ATH_OP_INVALID, &common->op_flags))
return IRQ_NONE;
/* shared irq, not for us */
@@ -583,7 +584,7 @@ irqreturn_t ath_isr(int irq, void *dev)
if (!ath9k_hw_intrpend(ah))
return IRQ_NONE;
- if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) {
+ if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) {
ath9k_hw_kill_interrupts(ah);
return IRQ_HANDLED;
}
@@ -684,10 +685,11 @@ int ath_reset(struct ath_softc *sc)
void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
#ifdef CONFIG_ATH9K_DEBUGFS
RESET_STAT_INC(sc, type);
#endif
- set_bit(SC_OP_HW_RESET, &sc->sc_flags);
+ set_bit(ATH_OP_HW_RESET, &common->op_flags);
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
}
@@ -768,7 +770,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
ath_mci_enable(sc);
- clear_bit(SC_OP_INVALID, &sc->sc_flags);
+ clear_bit(ATH_OP_INVALID, &common->op_flags);
sc->sc_ah->is_monitoring = false;
if (!ath_complete_reset(sc, false))
@@ -885,7 +887,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
ath_cancel_work(sc);
- if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
+ if (test_bit(ATH_OP_INVALID, &common->op_flags)) {
ath_dbg(common, ANY, "Device not present\n");
mutex_unlock(&sc->mutex);
return;
@@ -940,7 +942,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
ath9k_ps_restore(sc);
- set_bit(SC_OP_INVALID, &sc->sc_flags);
+ set_bit(ATH_OP_INVALID, &common->op_flags);
sc->ps_idle = prev_idle;
mutex_unlock(&sc->mutex);
@@ -1081,7 +1083,7 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
*/
if (ah->opmode == NL80211_IFTYPE_STATION &&
old_opmode == NL80211_IFTYPE_AP &&
- test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
+ test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) {
ieee80211_iterate_active_interfaces_atomic(
sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath9k_sta_vif_iter, sc);
@@ -1178,9 +1180,6 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
if (ath9k_uses_beacons(vif->type))
ath9k_beacon_remove_slot(sc, vif);
- if (sc->csa_vif == vif)
- sc->csa_vif = NULL;
-
ath9k_ps_wakeup(sc);
ath9k_calculate_summary_state(hw, NULL);
ath9k_ps_restore(sc);
@@ -1593,7 +1592,7 @@ static void ath9k_set_assoc_state(struct ath_softc *sc,
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
unsigned long flags;
- set_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
+ set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags);
avp->primary_sta_vif = true;
/*
@@ -1609,7 +1608,7 @@ static void ath9k_set_assoc_state(struct ath_softc *sc,
common->curaid = bss_conf->aid;
ath9k_hw_write_associd(sc->sc_ah);
- sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
+ common->last_rssi = ATH_RSSI_DUMMY_MARKER;
sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
spin_lock_irqsave(&sc->sc_pm_lock, flags);
@@ -1628,8 +1627,9 @@ static void ath9k_bss_assoc_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
{
struct ath_softc *sc = data;
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- if (test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
+ if (test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags))
return;
if (bss_conf->assoc)
@@ -1660,18 +1660,18 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
bss_conf->bssid, bss_conf->assoc);
if (avp->primary_sta_vif && !bss_conf->assoc) {
- clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
+ clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags);
avp->primary_sta_vif = false;
if (ah->opmode == NL80211_IFTYPE_STATION)
- clear_bit(SC_OP_BEACONS, &sc->sc_flags);
+ clear_bit(ATH_OP_BEACONS, &common->op_flags);
}
ieee80211_iterate_active_interfaces_atomic(
sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath9k_bss_assoc_iter, sc);
- if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags) &&
+ if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags) &&
ah->opmode == NL80211_IFTYPE_STATION) {
memset(common->curbssid, 0, ETH_ALEN);
common->curaid = 0;
@@ -1866,7 +1866,7 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
static bool ath9k_has_tx_pending(struct ath_softc *sc)
{
- int i, npend;
+ int i, npend = 0;
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (!ATH_TXQ_SETUP(sc, i))
@@ -1900,7 +1900,7 @@ static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
return;
}
- if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
+ if (test_bit(ATH_OP_INVALID, &common->op_flags)) {
ath_dbg(common, ANY, "Device not present\n");
mutex_unlock(&sc->mutex);
return;
@@ -2056,7 +2056,7 @@ static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant);
ah->txchainmask = fill_chainmask(ah->caps.tx_chainmask, tx_ant);
- ath9k_reload_chainmask_settings(sc);
+ ath9k_cmn_reload_chainmask(ah);
return 0;
}
@@ -2073,26 +2073,23 @@ static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
- set_bit(SC_OP_SCANNING, &sc->sc_flags);
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ set_bit(ATH_OP_SCANNING, &common->op_flags);
}
static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
- clear_bit(SC_OP_SCANNING, &sc->sc_flags);
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ clear_bit(ATH_OP_SCANNING, &common->op_flags);
}
static void ath9k_channel_switch_beacon(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_chan_def *chandef)
{
- struct ath_softc *sc = hw->priv;
-
- /* mac80211 does not support CSA in multi-if cases (yet) */
- if (WARN_ON(sc->csa_vif))
- return;
-
- sc->csa_vif = vif;
+ /* depend on vif->csa_active only */
+ return;
}
struct ieee80211_ops ath9k_ops = {
diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c
index 71799fcade54..a0dbcc412384 100644
--- a/drivers/net/wireless/ath/ath9k/mci.c
+++ b/drivers/net/wireless/ath/ath9k/mci.c
@@ -555,7 +555,7 @@ void ath_mci_intr(struct ath_softc *sc)
mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_GPM;
while (more_data == MCI_GPM_MORE) {
- if (test_bit(SC_OP_HW_RESET, &sc->sc_flags))
+ if (test_bit(ATH_OP_HW_RESET, &common->op_flags))
return;
pgpm = mci->gpm_buf.bf_addr;
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index 55724b02316b..25304adece57 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -784,6 +784,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct ath_softc *sc;
struct ieee80211_hw *hw;
+ struct ath_common *common;
u8 csz;
u32 val;
int ret = 0;
@@ -858,9 +859,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sc->mem = pcim_iomap_table(pdev)[0];
sc->driver_data = id->driver_data;
- /* Will be cleared in ath9k_start() */
- set_bit(SC_OP_INVALID, &sc->sc_flags);
-
ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc);
if (ret) {
dev_err(&pdev->dev, "request_irq failed\n");
@@ -879,6 +877,10 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n",
hw_name, (unsigned long)sc->mem, pdev->irq);
+ /* Will be cleared in ath9k_start() */
+ common = ath9k_hw_common(sc->sc_ah);
+ set_bit(ATH_OP_INVALID, &common->op_flags);
+
return 0;
err_init:
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
deleted file mode 100644
index d829bb62a3fc..000000000000
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ /dev/null
@@ -1,1495 +0,0 @@
-/*
- * Copyright (c) 2004 Video54 Technologies, Inc.
- * Copyright (c) 2004-2011 Atheros Communications, Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <linux/slab.h>
-#include <linux/export.h>
-
-#include "ath9k.h"
-
-static const struct ath_rate_table ar5416_11na_ratetable = {
- 68,
- 8, /* MCS start */
- {
- [0] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 6000,
- 5400, 0, 12 }, /* 6 Mb */
- [1] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 9000,
- 7800, 1, 18 }, /* 9 Mb */
- [2] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000,
- 10000, 2, 24 }, /* 12 Mb */
- [3] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000,
- 13900, 3, 36 }, /* 18 Mb */
- [4] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000,
- 17300, 4, 48 }, /* 24 Mb */
- [5] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000,
- 23000, 5, 72 }, /* 36 Mb */
- [6] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000,
- 27400, 6, 96 }, /* 48 Mb */
- [7] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000,
- 29300, 7, 108 }, /* 54 Mb */
- [8] = { RC_HT_SDT_2040, WLAN_RC_PHY_HT_20_SS, 6500,
- 6400, 0, 0 }, /* 6.5 Mb */
- [9] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 13000,
- 12700, 1, 1 }, /* 13 Mb */
- [10] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 19500,
- 18800, 2, 2 }, /* 19.5 Mb */
- [11] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 26000,
- 25000, 3, 3 }, /* 26 Mb */
- [12] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 39000,
- 36700, 4, 4 }, /* 39 Mb */
- [13] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 52000,
- 48100, 5, 5 }, /* 52 Mb */
- [14] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 58500,
- 53500, 6, 6 }, /* 58.5 Mb */
- [15] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 65000,
- 59000, 7, 7 }, /* 65 Mb */
- [16] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS_HGI, 72200,
- 65400, 7, 7 }, /* 75 Mb */
- [17] = { RC_INVALID, WLAN_RC_PHY_HT_20_DS, 13000,
- 12700, 8, 8 }, /* 13 Mb */
- [18] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 26000,
- 24800, 9, 9 }, /* 26 Mb */
- [19] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 39000,
- 36600, 10, 10 }, /* 39 Mb */
- [20] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 52000,
- 48100, 11, 11 }, /* 52 Mb */
- [21] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 78000,
- 69500, 12, 12 }, /* 78 Mb */
- [22] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 104000,
- 89500, 13, 13 }, /* 104 Mb */
- [23] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 117000,
- 98900, 14, 14 }, /* 117 Mb */
- [24] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 130000,
- 108300, 15, 15 }, /* 130 Mb */
- [25] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS_HGI, 144400,
- 120000, 15, 15 }, /* 144.4 Mb */
- [26] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 19500,
- 17400, 16, 16 }, /* 19.5 Mb */
- [27] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 39000,
- 35100, 17, 17 }, /* 39 Mb */
- [28] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 58500,
- 52600, 18, 18 }, /* 58.5 Mb */
- [29] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 78000,
- 70400, 19, 19 }, /* 78 Mb */
- [30] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 117000,
- 104900, 20, 20 }, /* 117 Mb */
- [31] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS_HGI, 130000,
- 115800, 20, 20 }, /* 130 Mb*/
- [32] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 156000,
- 137200, 21, 21 }, /* 156 Mb */
- [33] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 173300,
- 151100, 21, 21 }, /* 173.3 Mb */
- [34] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 175500,
- 152800, 22, 22 }, /* 175.5 Mb */
- [35] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 195000,
- 168400, 22, 22 }, /* 195 Mb*/
- [36] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 195000,
- 168400, 23, 23 }, /* 195 Mb */
- [37] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 216700,
- 185000, 23, 23 }, /* 216.7 Mb */
- [38] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 13500,
- 13200, 0, 0 }, /* 13.5 Mb*/
- [39] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 27500,
- 25900, 1, 1 }, /* 27.0 Mb*/
- [40] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 40500,
- 38600, 2, 2 }, /* 40.5 Mb*/
- [41] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 54000,
- 49800, 3, 3 }, /* 54 Mb */
- [42] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 81500,
- 72200, 4, 4 }, /* 81 Mb */
- [43] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 108000,
- 92900, 5, 5 }, /* 108 Mb */
- [44] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 121500,
- 102700, 6, 6 }, /* 121.5 Mb*/
- [45] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 135000,
- 112000, 7, 7 }, /* 135 Mb */
- [46] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000,
- 122000, 7, 7 }, /* 150 Mb */
- [47] = { RC_INVALID, WLAN_RC_PHY_HT_40_DS, 27000,
- 25800, 8, 8 }, /* 27 Mb */
- [48] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 54000,
- 49800, 9, 9 }, /* 54 Mb */
- [49] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 81000,
- 71900, 10, 10 }, /* 81 Mb */
- [50] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 108000,
- 92500, 11, 11 }, /* 108 Mb */
- [51] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 162000,
- 130300, 12, 12 }, /* 162 Mb */
- [52] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 216000,
- 162800, 13, 13 }, /* 216 Mb */
- [53] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 243000,
- 178200, 14, 14 }, /* 243 Mb */
- [54] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 270000,
- 192100, 15, 15 }, /* 270 Mb */
- [55] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS_HGI, 300000,
- 207000, 15, 15 }, /* 300 Mb */
- [56] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 40500,
- 36100, 16, 16 }, /* 40.5 Mb */
- [57] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 81000,
- 72900, 17, 17 }, /* 81 Mb */
- [58] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 121500,
- 108300, 18, 18 }, /* 121.5 Mb */
- [59] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 162000,
- 142000, 19, 19 }, /* 162 Mb */
- [60] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000,
- 205100, 20, 20 }, /* 243 Mb */
- [61] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000,
- 224700, 20, 20 }, /* 270 Mb */
- [62] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000,
- 263100, 21, 21 }, /* 324 Mb */
- [63] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000,
- 288000, 21, 21 }, /* 360 Mb */
- [64] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 364500,
- 290700, 22, 22 }, /* 364.5 Mb */
- [65] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 405000,
- 317200, 22, 22 }, /* 405 Mb */
- [66] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 405000,
- 317200, 23, 23 }, /* 405 Mb */
- [67] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 450000,
- 346400, 23, 23 }, /* 450 Mb */
- },
- 50, /* probe interval */
- WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
-};
-
-/* 4ms frame limit not used for NG mode. The values filled
- * for HT are the 64K max aggregate limit */
-
-static const struct ath_rate_table ar5416_11ng_ratetable = {
- 72,
- 12, /* MCS start */
- {
- [0] = { RC_ALL, WLAN_RC_PHY_CCK, 1000,
- 900, 0, 2 }, /* 1 Mb */
- [1] = { RC_ALL, WLAN_RC_PHY_CCK, 2000,
- 1900, 1, 4 }, /* 2 Mb */
- [2] = { RC_ALL, WLAN_RC_PHY_CCK, 5500,
- 4900, 2, 11 }, /* 5.5 Mb */
- [3] = { RC_ALL, WLAN_RC_PHY_CCK, 11000,
- 8100, 3, 22 }, /* 11 Mb */
- [4] = { RC_INVALID, WLAN_RC_PHY_OFDM, 6000,
- 5400, 4, 12 }, /* 6 Mb */
- [5] = { RC_INVALID, WLAN_RC_PHY_OFDM, 9000,
- 7800, 5, 18 }, /* 9 Mb */
- [6] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000,
- 10100, 6, 24 }, /* 12 Mb */
- [7] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000,
- 14100, 7, 36 }, /* 18 Mb */
- [8] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000,
- 17700, 8, 48 }, /* 24 Mb */
- [9] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000,
- 23700, 9, 72 }, /* 36 Mb */
- [10] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000,
- 27400, 10, 96 }, /* 48 Mb */
- [11] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000,
- 30900, 11, 108 }, /* 54 Mb */
- [12] = { RC_INVALID, WLAN_RC_PHY_HT_20_SS, 6500,
- 6400, 0, 0 }, /* 6.5 Mb */
- [13] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 13000,
- 12700, 1, 1 }, /* 13 Mb */
- [14] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 19500,
- 18800, 2, 2 }, /* 19.5 Mb*/
- [15] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 26000,
- 25000, 3, 3 }, /* 26 Mb */
- [16] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 39000,
- 36700, 4, 4 }, /* 39 Mb */
- [17] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 52000,
- 48100, 5, 5 }, /* 52 Mb */
- [18] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 58500,
- 53500, 6, 6 }, /* 58.5 Mb */
- [19] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 65000,
- 59000, 7, 7 }, /* 65 Mb */
- [20] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS_HGI, 72200,
- 65400, 7, 7 }, /* 65 Mb*/
- [21] = { RC_INVALID, WLAN_RC_PHY_HT_20_DS, 13000,
- 12700, 8, 8 }, /* 13 Mb */
- [22] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 26000,
- 24800, 9, 9 }, /* 26 Mb */
- [23] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 39000,
- 36600, 10, 10 }, /* 39 Mb */
- [24] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 52000,
- 48100, 11, 11 }, /* 52 Mb */
- [25] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 78000,
- 69500, 12, 12 }, /* 78 Mb */
- [26] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 104000,
- 89500, 13, 13 }, /* 104 Mb */
- [27] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 117000,
- 98900, 14, 14 }, /* 117 Mb */
- [28] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 130000,
- 108300, 15, 15 }, /* 130 Mb */
- [29] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS_HGI, 144400,
- 120000, 15, 15 }, /* 144.4 Mb */
- [30] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 19500,
- 17400, 16, 16 }, /* 19.5 Mb */
- [31] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 39000,
- 35100, 17, 17 }, /* 39 Mb */
- [32] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 58500,
- 52600, 18, 18 }, /* 58.5 Mb */
- [33] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 78000,
- 70400, 19, 19 }, /* 78 Mb */
- [34] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 117000,
- 104900, 20, 20 }, /* 117 Mb */
- [35] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS_HGI, 130000,
- 115800, 20, 20 }, /* 130 Mb */
- [36] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 156000,
- 137200, 21, 21 }, /* 156 Mb */
- [37] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 173300,
- 151100, 21, 21 }, /* 173.3 Mb */
- [38] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 175500,
- 152800, 22, 22 }, /* 175.5 Mb */
- [39] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 195000,
- 168400, 22, 22 }, /* 195 Mb */
- [40] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 195000,
- 168400, 23, 23 }, /* 195 Mb */
- [41] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 216700,
- 185000, 23, 23 }, /* 216.7 Mb */
- [42] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 13500,
- 13200, 0, 0 }, /* 13.5 Mb */
- [43] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 27500,
- 25900, 1, 1 }, /* 27.0 Mb */
- [44] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 40500,
- 38600, 2, 2 }, /* 40.5 Mb */
- [45] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 54000,
- 49800, 3, 3 }, /* 54 Mb */
- [46] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 81500,
- 72200, 4, 4 }, /* 81 Mb */
- [47] = { RC_HT_S_40 , WLAN_RC_PHY_HT_40_SS, 108000,
- 92900, 5, 5 }, /* 108 Mb */
- [48] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 121500,
- 102700, 6, 6 }, /* 121.5 Mb */
- [49] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 135000,
- 112000, 7, 7 }, /* 135 Mb */
- [50] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000,
- 122000, 7, 7 }, /* 150 Mb */
- [51] = { RC_INVALID, WLAN_RC_PHY_HT_40_DS, 27000,
- 25800, 8, 8 }, /* 27 Mb */
- [52] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 54000,
- 49800, 9, 9 }, /* 54 Mb */
- [53] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 81000,
- 71900, 10, 10 }, /* 81 Mb */
- [54] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 108000,
- 92500, 11, 11 }, /* 108 Mb */
- [55] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 162000,
- 130300, 12, 12 }, /* 162 Mb */
- [56] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 216000,
- 162800, 13, 13 }, /* 216 Mb */
- [57] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 243000,
- 178200, 14, 14 }, /* 243 Mb */
- [58] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 270000,
- 192100, 15, 15 }, /* 270 Mb */
- [59] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS_HGI, 300000,
- 207000, 15, 15 }, /* 300 Mb */
- [60] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 40500,
- 36100, 16, 16 }, /* 40.5 Mb */
- [61] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 81000,
- 72900, 17, 17 }, /* 81 Mb */
- [62] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 121500,
- 108300, 18, 18 }, /* 121.5 Mb */
- [63] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 162000,
- 142000, 19, 19 }, /* 162 Mb */
- [64] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000,
- 205100, 20, 20 }, /* 243 Mb */
- [65] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000,
- 224700, 20, 20 }, /* 270 Mb */
- [66] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000,
- 263100, 21, 21 }, /* 324 Mb */
- [67] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000,
- 288000, 21, 21 }, /* 360 Mb */
- [68] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 364500,
- 290700, 22, 22 }, /* 364.5 Mb */
- [69] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 405000,
- 317200, 22, 22 }, /* 405 Mb */
- [70] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 405000,
- 317200, 23, 23 }, /* 405 Mb */
- [71] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 450000,
- 346400, 23, 23 }, /* 450 Mb */
- },
- 50, /* probe interval */
- WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
-};
-
-static const struct ath_rate_table ar5416_11a_ratetable = {
- 8,
- 0,
- {
- { RC_L_SDT, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
- 5400, 0, 12},
- { RC_L_SDT, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
- 7800, 1, 18},
- { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
- 10000, 2, 24},
- { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
- 13900, 3, 36},
- { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
- 17300, 4, 48},
- { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
- 23000, 5, 72},
- { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
- 27400, 6, 96},
- { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
- 29300, 7, 108},
- },
- 50, /* probe interval */
- 0, /* Phy rates allowed initially */
-};
-
-static const struct ath_rate_table ar5416_11g_ratetable = {
- 12,
- 0,
- {
- { RC_L_SDT, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
- 900, 0, 2},
- { RC_L_SDT, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
- 1900, 1, 4},
- { RC_L_SDT, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
- 4900, 2, 11},
- { RC_L_SDT, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
- 8100, 3, 22},
- { RC_INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
- 5400, 4, 12},
- { RC_INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
- 7800, 5, 18},
- { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
- 10000, 6, 24},
- { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
- 13900, 7, 36},
- { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
- 17300, 8, 48},
- { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
- 23000, 9, 72},
- { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
- 27400, 10, 96},
- { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
- 29300, 11, 108},
- },
- 50, /* probe interval */
- 0, /* Phy rates allowed initially */
-};
-
-static int ath_rc_get_rateindex(struct ath_rate_priv *ath_rc_priv,
- struct ieee80211_tx_rate *rate)
-{
- const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
- int rix, i, idx = 0;
-
- if (!(rate->flags & IEEE80211_TX_RC_MCS))
- return rate->idx;
-
- for (i = 0; i < ath_rc_priv->max_valid_rate; i++) {
- idx = ath_rc_priv->valid_rate_index[i];
-
- if (WLAN_RC_PHY_HT(rate_table->info[idx].phy) &&
- rate_table->info[idx].ratecode == rate->idx)
- break;
- }
-
- rix = idx;
-
- if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
- rix++;
-
- return rix;
-}
-
-static void ath_rc_sort_validrates(struct ath_rate_priv *ath_rc_priv)
-{
- const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
- u8 i, j, idx, idx_next;
-
- for (i = ath_rc_priv->max_valid_rate - 1; i > 0; i--) {
- for (j = 0; j <= i-1; j++) {
- idx = ath_rc_priv->valid_rate_index[j];
- idx_next = ath_rc_priv->valid_rate_index[j+1];
-
- if (rate_table->info[idx].ratekbps >
- rate_table->info[idx_next].ratekbps) {
- ath_rc_priv->valid_rate_index[j] = idx_next;
- ath_rc_priv->valid_rate_index[j+1] = idx;
- }
- }
- }
-}
-
-static inline
-int ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table,
- struct ath_rate_priv *ath_rc_priv,
- u8 cur_valid_txrate,
- u8 *next_idx)
-{
- u8 i;
-
- for (i = 0; i < ath_rc_priv->max_valid_rate - 1; i++) {
- if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) {
- *next_idx = ath_rc_priv->valid_rate_index[i+1];
- return 1;
- }
- }
-
- /* No more valid rates */
- *next_idx = 0;
-
- return 0;
-}
-
-/* Return true only for single stream */
-
-static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw)
-{
- if (WLAN_RC_PHY_HT(phy) && !(capflag & WLAN_RC_HT_FLAG))
- return 0;
- if (WLAN_RC_PHY_DS(phy) && !(capflag & WLAN_RC_DS_FLAG))
- return 0;
- if (WLAN_RC_PHY_TS(phy) && !(capflag & WLAN_RC_TS_FLAG))
- return 0;
- if (WLAN_RC_PHY_SGI(phy) && !(capflag & WLAN_RC_SGI_FLAG))
- return 0;
- if (!ignore_cw && WLAN_RC_PHY_HT(phy))
- if (WLAN_RC_PHY_40(phy) && !(capflag & WLAN_RC_40_FLAG))
- return 0;
- return 1;
-}
-
-static inline int
-ath_rc_get_lower_rix(struct ath_rate_priv *ath_rc_priv,
- u8 cur_valid_txrate, u8 *next_idx)
-{
- int8_t i;
-
- for (i = 1; i < ath_rc_priv->max_valid_rate ; i++) {
- if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) {
- *next_idx = ath_rc_priv->valid_rate_index[i-1];
- return 1;
- }
- }
-
- return 0;
-}
-
-static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv)
-{
- const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
- u8 i, hi = 0;
-
- for (i = 0; i < rate_table->rate_cnt; i++) {
- if (rate_table->info[i].rate_flags & RC_LEGACY) {
- u32 phy = rate_table->info[i].phy;
- u8 valid_rate_count = 0;
-
- if (!ath_rc_valid_phyrate(phy, ath_rc_priv->ht_cap, 0))
- continue;
-
- valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy];
-
- ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i;
- ath_rc_priv->valid_phy_ratecnt[phy] += 1;
- ath_rc_priv->valid_rate_index[i] = true;
- hi = i;
- }
- }
-
- return hi;
-}
-
-static inline bool ath_rc_check_legacy(u8 rate, u8 dot11rate, u16 rate_flags,
- u32 phy, u32 capflag)
-{
- if (rate != dot11rate || WLAN_RC_PHY_HT(phy))
- return false;
-
- if ((rate_flags & WLAN_RC_CAP_MODE(capflag)) != WLAN_RC_CAP_MODE(capflag))
- return false;
-
- if (!(rate_flags & WLAN_RC_CAP_STREAM(capflag)))
- return false;
-
- return true;
-}
-
-static inline bool ath_rc_check_ht(u8 rate, u8 dot11rate, u16 rate_flags,
- u32 phy, u32 capflag)
-{
- if (rate != dot11rate || !WLAN_RC_PHY_HT(phy))
- return false;
-
- if (!WLAN_RC_PHY_HT_VALID(rate_flags, capflag))
- return false;
-
- if (!(rate_flags & WLAN_RC_CAP_STREAM(capflag)))
- return false;
-
- return true;
-}
-
-static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, bool legacy)
-{
- const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
- struct ath_rateset *rateset;
- u32 phy, capflag = ath_rc_priv->ht_cap;
- u16 rate_flags;
- u8 i, j, hi = 0, rate, dot11rate, valid_rate_count;
-
- if (legacy)
- rateset = &ath_rc_priv->neg_rates;
- else
- rateset = &ath_rc_priv->neg_ht_rates;
-
- for (i = 0; i < rateset->rs_nrates; i++) {
- for (j = 0; j < rate_table->rate_cnt; j++) {
- phy = rate_table->info[j].phy;
- rate_flags = rate_table->info[j].rate_flags;
- rate = rateset->rs_rates[i];
- dot11rate = rate_table->info[j].dot11rate;
-
- if (legacy &&
- !ath_rc_check_legacy(rate, dot11rate,
- rate_flags, phy, capflag))
- continue;
-
- if (!legacy &&
- !ath_rc_check_ht(rate, dot11rate,
- rate_flags, phy, capflag))
- continue;
-
- if (!ath_rc_valid_phyrate(phy, capflag, 0))
- continue;
-
- valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy];
- ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = j;
- ath_rc_priv->valid_phy_ratecnt[phy] += 1;
- ath_rc_priv->valid_rate_index[j] = true;
- hi = max(hi, j);
- }
- }
-
- return hi;
-}
-
-static u8 ath_rc_get_highest_rix(struct ath_rate_priv *ath_rc_priv,
- int *is_probing)
-{
- const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
- u32 best_thruput, this_thruput, now_msec;
- u8 rate, next_rate, best_rate, maxindex, minindex;
- int8_t index = 0;
-
- now_msec = jiffies_to_msecs(jiffies);
- *is_probing = 0;
- best_thruput = 0;
- maxindex = ath_rc_priv->max_valid_rate-1;
- minindex = 0;
- best_rate = minindex;
-
- /*
- * Try the higher rate first. It will reduce memory moving time
- * if we have very good channel characteristics.
- */
- for (index = maxindex; index >= minindex ; index--) {
- u8 per_thres;
-
- rate = ath_rc_priv->valid_rate_index[index];
- if (rate > ath_rc_priv->rate_max_phy)
- continue;
-
- /*
- * For TCP the average collision rate is around 11%,
- * so we ignore PERs less than this. This is to
- * prevent the rate we are currently using (whose
- * PER might be in the 10-15 range because of TCP
- * collisions) looking worse than the next lower
- * rate whose PER has decayed close to 0. If we
- * used to next lower rate, its PER would grow to
- * 10-15 and we would be worse off then staying
- * at the current rate.
- */
- per_thres = ath_rc_priv->per[rate];
- if (per_thres < 12)
- per_thres = 12;
-
- this_thruput = rate_table->info[rate].user_ratekbps *
- (100 - per_thres);
-
- if (best_thruput <= this_thruput) {
- best_thruput = this_thruput;
- best_rate = rate;
- }
- }
-
- rate = best_rate;
-
- /*
- * Must check the actual rate (ratekbps) to account for
- * non-monoticity of 11g's rate table
- */
-
- if (rate >= ath_rc_priv->rate_max_phy) {
- rate = ath_rc_priv->rate_max_phy;
-
- /* Probe the next allowed phy state */
- if (ath_rc_get_nextvalid_txrate(rate_table,
- ath_rc_priv, rate, &next_rate) &&
- (now_msec - ath_rc_priv->probe_time >
- rate_table->probe_interval) &&
- (ath_rc_priv->hw_maxretry_pktcnt >= 1)) {
- rate = next_rate;
- ath_rc_priv->probe_rate = rate;
- ath_rc_priv->probe_time = now_msec;
- ath_rc_priv->hw_maxretry_pktcnt = 0;
- *is_probing = 1;
- }
- }
-
- if (rate > (ath_rc_priv->rate_table_size - 1))
- rate = ath_rc_priv->rate_table_size - 1;
-
- if (RC_TS_ONLY(rate_table->info[rate].rate_flags) &&
- (ath_rc_priv->ht_cap & WLAN_RC_TS_FLAG))
- return rate;
-
- if (RC_DS_OR_LATER(rate_table->info[rate].rate_flags) &&
- (ath_rc_priv->ht_cap & (WLAN_RC_DS_FLAG | WLAN_RC_TS_FLAG)))
- return rate;
-
- if (RC_SS_OR_LEGACY(rate_table->info[rate].rate_flags))
- return rate;
-
- /* This should not happen */
- WARN_ON_ONCE(1);
-
- rate = ath_rc_priv->valid_rate_index[0];
-
- return rate;
-}
-
-static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table,
- struct ieee80211_tx_rate *rate,
- struct ieee80211_tx_rate_control *txrc,
- u8 tries, u8 rix, int rtsctsenable)
-{
- rate->count = tries;
- rate->idx = rate_table->info[rix].ratecode;
-
- if (txrc->rts || rtsctsenable)
- rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
-
- if (WLAN_RC_PHY_HT(rate_table->info[rix].phy)) {
- rate->flags |= IEEE80211_TX_RC_MCS;
- if (WLAN_RC_PHY_40(rate_table->info[rix].phy) &&
- conf_is_ht40(&txrc->hw->conf))
- rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
- if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy))
- rate->flags |= IEEE80211_TX_RC_SHORT_GI;
- }
-}
-
-static void ath_rc_rate_set_rtscts(struct ath_softc *sc,
- const struct ath_rate_table *rate_table,
- struct ieee80211_tx_info *tx_info)
-{
- struct ieee80211_bss_conf *bss_conf;
-
- if (!tx_info->control.vif)
- return;
- /*
- * For legacy frames, mac80211 takes care of CTS protection.
- */
- if (!(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS))
- return;
-
- bss_conf = &tx_info->control.vif->bss_conf;
-
- if (!bss_conf->basic_rates)
- return;
-
- /*
- * For now, use the lowest allowed basic rate for HT frames.
- */
- tx_info->control.rts_cts_rate_idx = __ffs(bss_conf->basic_rates);
-}
-
-static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
- struct ieee80211_tx_rate_control *txrc)
-{
- struct ath_softc *sc = priv;
- struct ath_rate_priv *ath_rc_priv = priv_sta;
- const struct ath_rate_table *rate_table;
- struct sk_buff *skb = txrc->skb;
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ieee80211_tx_rate *rates = tx_info->control.rates;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- __le16 fc = hdr->frame_control;
- u8 try_per_rate, i = 0, rix;
- int is_probe = 0;
-
- if (rate_control_send_low(sta, priv_sta, txrc))
- return;
-
- /*
- * For Multi Rate Retry we use a different number of
- * retry attempt counts. This ends up looking like this:
- *
- * MRR[0] = 4
- * MRR[1] = 4
- * MRR[2] = 4
- * MRR[3] = 8
- *
- */
- try_per_rate = 4;
-
- rate_table = ath_rc_priv->rate_table;
- rix = ath_rc_get_highest_rix(ath_rc_priv, &is_probe);
-
- if (conf_is_ht(&sc->hw->conf) &&
- (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
- tx_info->flags |= IEEE80211_TX_CTL_LDPC;
-
- if (conf_is_ht(&sc->hw->conf) &&
- (sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC))
- tx_info->flags |= (1 << IEEE80211_TX_CTL_STBC_SHIFT);
-
- if (is_probe) {
- /*
- * Set one try for probe rates. For the
- * probes don't enable RTS.
- */
- ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
- 1, rix, 0);
- /*
- * Get the next tried/allowed rate.
- * No RTS for the next series after the probe rate.
- */
- ath_rc_get_lower_rix(ath_rc_priv, rix, &rix);
- ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
- try_per_rate, rix, 0);
-
- tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
- } else {
- /*
- * Set the chosen rate. No RTS for first series entry.
- */
- ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
- try_per_rate, rix, 0);
- }
-
- for ( ; i < 4; i++) {
- /*
- * Use twice the number of tries for the last MRR segment.
- */
- if (i + 1 == 4)
- try_per_rate = 8;
-
- ath_rc_get_lower_rix(ath_rc_priv, rix, &rix);
-
- /*
- * All other rates in the series have RTS enabled.
- */
- ath_rc_rate_set_series(rate_table, &rates[i], txrc,
- try_per_rate, rix, 1);
- }
-
- /*
- * NB:Change rate series to enable aggregation when operating
- * at lower MCS rates. When first rate in series is MCS2
- * in HT40 @ 2.4GHz, series should look like:
- *
- * {MCS2, MCS1, MCS0, MCS0}.
- *
- * When first rate in series is MCS3 in HT20 @ 2.4GHz, series should
- * look like:
- *
- * {MCS3, MCS2, MCS1, MCS1}
- *
- * So, set fourth rate in series to be same as third one for
- * above conditions.
- */
- if ((sc->hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ) &&
- (conf_is_ht(&sc->hw->conf))) {
- u8 dot11rate = rate_table->info[rix].dot11rate;
- u8 phy = rate_table->info[rix].phy;
- if (i == 4 &&
- ((dot11rate == 2 && phy == WLAN_RC_PHY_HT_40_SS) ||
- (dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) {
- rates[3].idx = rates[2].idx;
- rates[3].flags = rates[2].flags;
- }
- }
-
- /*
- * Force hardware to use computed duration for next
- * fragment by disabling multi-rate retry, which
- * updates duration based on the multi-rate duration table.
- *
- * FIXME: Fix duration
- */
- if (ieee80211_has_morefrags(fc) ||
- (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
- rates[1].count = rates[2].count = rates[3].count = 0;
- rates[1].idx = rates[2].idx = rates[3].idx = 0;
- rates[0].count = ATH_TXMAXTRY;
- }
-
- ath_rc_rate_set_rtscts(sc, rate_table, tx_info);
-}
-
-static void ath_rc_update_per(struct ath_softc *sc,
- const struct ath_rate_table *rate_table,
- struct ath_rate_priv *ath_rc_priv,
- struct ieee80211_tx_info *tx_info,
- int tx_rate, int xretries, int retries,
- u32 now_msec)
-{
- int count, n_bad_frames;
- u8 last_per;
- static const u32 nretry_to_per_lookup[10] = {
- 100 * 0 / 1,
- 100 * 1 / 4,
- 100 * 1 / 2,
- 100 * 3 / 4,
- 100 * 4 / 5,
- 100 * 5 / 6,
- 100 * 6 / 7,
- 100 * 7 / 8,
- 100 * 8 / 9,
- 100 * 9 / 10
- };
-
- last_per = ath_rc_priv->per[tx_rate];
- n_bad_frames = tx_info->status.ampdu_len - tx_info->status.ampdu_ack_len;
-
- if (xretries) {
- if (xretries == 1) {
- ath_rc_priv->per[tx_rate] += 30;
- if (ath_rc_priv->per[tx_rate] > 100)
- ath_rc_priv->per[tx_rate] = 100;
- } else {
- /* xretries == 2 */
- count = ARRAY_SIZE(nretry_to_per_lookup);
- if (retries >= count)
- retries = count - 1;
-
- /* new_PER = 7/8*old_PER + 1/8*(currentPER) */
- ath_rc_priv->per[tx_rate] =
- (u8)(last_per - (last_per >> 3) + (100 >> 3));
- }
-
- /* xretries == 1 or 2 */
-
- if (ath_rc_priv->probe_rate == tx_rate)
- ath_rc_priv->probe_rate = 0;
-
- } else { /* xretries == 0 */
- count = ARRAY_SIZE(nretry_to_per_lookup);
- if (retries >= count)
- retries = count - 1;
-
- if (n_bad_frames) {
- /* new_PER = 7/8*old_PER + 1/8*(currentPER)
- * Assuming that n_frames is not 0. The current PER
- * from the retries is 100 * retries / (retries+1),
- * since the first retries attempts failed, and the
- * next one worked. For the one that worked,
- * n_bad_frames subframes out of n_frames wored,
- * so the PER for that part is
- * 100 * n_bad_frames / n_frames, and it contributes
- * 100 * n_bad_frames / (n_frames * (retries+1)) to
- * the above PER. The expression below is a
- * simplified version of the sum of these two terms.
- */
- if (tx_info->status.ampdu_len > 0) {
- int n_frames, n_bad_tries;
- u8 cur_per, new_per;
-
- n_bad_tries = retries * tx_info->status.ampdu_len +
- n_bad_frames;
- n_frames = tx_info->status.ampdu_len * (retries + 1);
- cur_per = (100 * n_bad_tries / n_frames) >> 3;
- new_per = (u8)(last_per - (last_per >> 3) + cur_per);
- ath_rc_priv->per[tx_rate] = new_per;
- }
- } else {
- ath_rc_priv->per[tx_rate] =
- (u8)(last_per - (last_per >> 3) +
- (nretry_to_per_lookup[retries] >> 3));
- }
-
-
- /*
- * If we got at most one retry then increase the max rate if
- * this was a probe. Otherwise, ignore the probe.
- */
- if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) {
- if (retries > 0 || 2 * n_bad_frames > tx_info->status.ampdu_len) {
- /*
- * Since we probed with just a single attempt,
- * any retries means the probe failed. Also,
- * if the attempt worked, but more than half
- * the subframes were bad then also consider
- * the probe a failure.
- */
- ath_rc_priv->probe_rate = 0;
- } else {
- u8 probe_rate = 0;
-
- ath_rc_priv->rate_max_phy =
- ath_rc_priv->probe_rate;
- probe_rate = ath_rc_priv->probe_rate;
-
- if (ath_rc_priv->per[probe_rate] > 30)
- ath_rc_priv->per[probe_rate] = 20;
-
- ath_rc_priv->probe_rate = 0;
-
- /*
- * Since this probe succeeded, we allow the next
- * probe twice as soon. This allows the maxRate
- * to move up faster if the probes are
- * successful.
- */
- ath_rc_priv->probe_time =
- now_msec - rate_table->probe_interval / 2;
- }
- }
-
- if (retries > 0) {
- /*
- * Don't update anything. We don't know if
- * this was because of collisions or poor signal.
- */
- ath_rc_priv->hw_maxretry_pktcnt = 0;
- } else {
- /*
- * It worked with no retries. First ignore bogus (small)
- * rssi_ack values.
- */
- if (tx_rate == ath_rc_priv->rate_max_phy &&
- ath_rc_priv->hw_maxretry_pktcnt < 255) {
- ath_rc_priv->hw_maxretry_pktcnt++;
- }
-
- }
- }
-}
-
-static void ath_rc_update_ht(struct ath_softc *sc,
- struct ath_rate_priv *ath_rc_priv,
- struct ieee80211_tx_info *tx_info,
- int tx_rate, int xretries, int retries)
-{
- u32 now_msec = jiffies_to_msecs(jiffies);
- int rate;
- u8 last_per;
- const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
- int size = ath_rc_priv->rate_table_size;
-
- if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt))
- return;
-
- last_per = ath_rc_priv->per[tx_rate];
-
- /* Update PER first */
- ath_rc_update_per(sc, rate_table, ath_rc_priv,
- tx_info, tx_rate, xretries,
- retries, now_msec);
-
- /*
- * If this rate looks bad (high PER) then stop using it for
- * a while (except if we are probing).
- */
- if (ath_rc_priv->per[tx_rate] >= 55 && tx_rate > 0 &&
- rate_table->info[tx_rate].ratekbps <=
- rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) {
- ath_rc_get_lower_rix(ath_rc_priv, (u8)tx_rate,
- &ath_rc_priv->rate_max_phy);
-
- /* Don't probe for a little while. */
- ath_rc_priv->probe_time = now_msec;
- }
-
- /* Make sure the rates below this have lower PER */
- /* Monotonicity is kept only for rates below the current rate. */
- if (ath_rc_priv->per[tx_rate] < last_per) {
- for (rate = tx_rate - 1; rate >= 0; rate--) {
-
- if (ath_rc_priv->per[rate] >
- ath_rc_priv->per[rate+1]) {
- ath_rc_priv->per[rate] =
- ath_rc_priv->per[rate+1];
- }
- }
- }
-
- /* Maintain monotonicity for rates above the current rate */
- for (rate = tx_rate; rate < size - 1; rate++) {
- if (ath_rc_priv->per[rate+1] <
- ath_rc_priv->per[rate])
- ath_rc_priv->per[rate+1] =
- ath_rc_priv->per[rate];
- }
-
- /* Every so often, we reduce the thresholds
- * and PER (different for CCK and OFDM). */
- if (now_msec - ath_rc_priv->per_down_time >=
- rate_table->probe_interval) {
- for (rate = 0; rate < size; rate++) {
- ath_rc_priv->per[rate] =
- 7 * ath_rc_priv->per[rate] / 8;
- }
-
- ath_rc_priv->per_down_time = now_msec;
- }
-
- ath_debug_stat_retries(ath_rc_priv, tx_rate, xretries, retries,
- ath_rc_priv->per[tx_rate]);
-
-}
-
-static void ath_rc_tx_status(struct ath_softc *sc,
- struct ath_rate_priv *ath_rc_priv,
- struct sk_buff *skb)
-{
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ieee80211_tx_rate *rates = tx_info->status.rates;
- struct ieee80211_tx_rate *rate;
- int final_ts_idx = 0, xretries = 0, long_retry = 0;
- u8 flags;
- u32 i = 0, rix;
-
- for (i = 0; i < sc->hw->max_rates; i++) {
- rate = &tx_info->status.rates[i];
- if (rate->idx < 0 || !rate->count)
- break;
-
- final_ts_idx = i;
- long_retry = rate->count - 1;
- }
-
- if (!(tx_info->flags & IEEE80211_TX_STAT_ACK))
- xretries = 1;
-
- /*
- * If the first rate is not the final index, there
- * are intermediate rate failures to be processed.
- */
- if (final_ts_idx != 0) {
- for (i = 0; i < final_ts_idx ; i++) {
- if (rates[i].count != 0 && (rates[i].idx >= 0)) {
- flags = rates[i].flags;
-
- /* If HT40 and we have switched mode from
- * 40 to 20 => don't update */
-
- if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
- !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG))
- return;
-
- rix = ath_rc_get_rateindex(ath_rc_priv, &rates[i]);
- ath_rc_update_ht(sc, ath_rc_priv, tx_info,
- rix, xretries ? 1 : 2,
- rates[i].count);
- }
- }
- }
-
- flags = rates[final_ts_idx].flags;
-
- /* If HT40 and we have switched mode from 40 to 20 => don't update */
- if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
- !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG))
- return;
-
- rix = ath_rc_get_rateindex(ath_rc_priv, &rates[final_ts_idx]);
- ath_rc_update_ht(sc, ath_rc_priv, tx_info, rix, xretries, long_retry);
- ath_debug_stat_rc(ath_rc_priv, rix);
-}
-
-static const
-struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc,
- enum ieee80211_band band,
- bool is_ht)
-{
- switch(band) {
- case IEEE80211_BAND_2GHZ:
- if (is_ht)
- return &ar5416_11ng_ratetable;
- return &ar5416_11g_ratetable;
- case IEEE80211_BAND_5GHZ:
- if (is_ht)
- return &ar5416_11na_ratetable;
- return &ar5416_11a_ratetable;
- default:
- return NULL;
- }
-}
-
-static void ath_rc_init(struct ath_softc *sc,
- struct ath_rate_priv *ath_rc_priv)
-{
- const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
- struct ath_rateset *rateset = &ath_rc_priv->neg_rates;
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- u8 i, j, k, hi = 0, hthi = 0;
-
- ath_rc_priv->rate_table_size = RATE_TABLE_SIZE;
-
- for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) {
- ath_rc_priv->per[i] = 0;
- ath_rc_priv->valid_rate_index[i] = 0;
- }
-
- for (i = 0; i < WLAN_RC_PHY_MAX; i++) {
- for (j = 0; j < RATE_TABLE_SIZE; j++)
- ath_rc_priv->valid_phy_rateidx[i][j] = 0;
- ath_rc_priv->valid_phy_ratecnt[i] = 0;
- }
-
- if (!rateset->rs_nrates) {
- hi = ath_rc_init_validrates(ath_rc_priv);
- } else {
- hi = ath_rc_setvalid_rates(ath_rc_priv, true);
-
- if (ath_rc_priv->ht_cap & WLAN_RC_HT_FLAG)
- hthi = ath_rc_setvalid_rates(ath_rc_priv, false);
-
- hi = max(hi, hthi);
- }
-
- ath_rc_priv->rate_table_size = hi + 1;
- ath_rc_priv->rate_max_phy = 0;
- WARN_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE);
-
- for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) {
- for (j = 0; j < ath_rc_priv->valid_phy_ratecnt[i]; j++) {
- ath_rc_priv->valid_rate_index[k++] =
- ath_rc_priv->valid_phy_rateidx[i][j];
- }
-
- if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, 1) ||
- !ath_rc_priv->valid_phy_ratecnt[i])
- continue;
-
- ath_rc_priv->rate_max_phy = ath_rc_priv->valid_phy_rateidx[i][j-1];
- }
- WARN_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE);
- WARN_ON(k > RATE_TABLE_SIZE);
-
- ath_rc_priv->max_valid_rate = k;
- ath_rc_sort_validrates(ath_rc_priv);
- ath_rc_priv->rate_max_phy = (k > 4) ?
- ath_rc_priv->valid_rate_index[k-4] :
- ath_rc_priv->valid_rate_index[k-1];
-
- ath_dbg(common, CONFIG, "RC Initialized with capabilities: 0x%x\n",
- ath_rc_priv->ht_cap);
-}
-
-static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta)
-{
- u8 caps = 0;
-
- if (sta->ht_cap.ht_supported) {
- caps = WLAN_RC_HT_FLAG;
- if (sta->ht_cap.mcs.rx_mask[1] && sta->ht_cap.mcs.rx_mask[2])
- caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG;
- else if (sta->ht_cap.mcs.rx_mask[1])
- caps |= WLAN_RC_DS_FLAG;
- if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) {
- caps |= WLAN_RC_40_FLAG;
- if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
- caps |= WLAN_RC_SGI_FLAG;
- } else {
- if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
- caps |= WLAN_RC_SGI_FLAG;
- }
- }
-
- return caps;
-}
-
-static bool ath_tx_aggr_check(struct ath_softc *sc, struct ieee80211_sta *sta,
- u8 tidno)
-{
- struct ath_node *an = (struct ath_node *)sta->drv_priv;
- struct ath_atx_tid *txtid;
-
- if (!sta->ht_cap.ht_supported)
- return false;
-
- txtid = ATH_AN_2_TID(an, tidno);
- return !txtid->active;
-}
-
-
-/***********************************/
-/* mac80211 Rate Control callbacks */
-/***********************************/
-
-static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
- struct ieee80211_sta *sta, void *priv_sta,
- struct sk_buff *skb)
-{
- struct ath_softc *sc = priv;
- struct ath_rate_priv *ath_rc_priv = priv_sta;
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- __le16 fc = hdr->frame_control;
-
- if (!priv_sta || !ieee80211_is_data(fc))
- return;
-
- /* This packet was aggregated but doesn't carry status info */
- if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
- !(tx_info->flags & IEEE80211_TX_STAT_AMPDU))
- return;
-
- if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED)
- return;
-
- ath_rc_tx_status(sc, ath_rc_priv, skb);
-
- /* Check if aggregation has to be enabled for this tid */
- if (conf_is_ht(&sc->hw->conf) &&
- !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
- if (ieee80211_is_data_qos(fc) &&
- skb_get_queue_mapping(skb) != IEEE80211_AC_VO) {
- u8 *qc, tid;
-
- qc = ieee80211_get_qos_ctl(hdr);
- tid = qc[0] & 0xf;
-
- if(ath_tx_aggr_check(sc, sta, tid))
- ieee80211_start_tx_ba_session(sta, tid, 0);
- }
- }
-}
-
-static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
- struct cfg80211_chan_def *chandef,
- struct ieee80211_sta *sta, void *priv_sta)
-{
- struct ath_softc *sc = priv;
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- struct ath_rate_priv *ath_rc_priv = priv_sta;
- int i, j = 0;
- u32 rate_flags = ieee80211_chandef_rate_flags(&sc->hw->conf.chandef);
-
- for (i = 0; i < sband->n_bitrates; i++) {
- if (sta->supp_rates[sband->band] & BIT(i)) {
- if ((rate_flags & sband->bitrates[i].flags)
- != rate_flags)
- continue;
-
- ath_rc_priv->neg_rates.rs_rates[j]
- = (sband->bitrates[i].bitrate * 2) / 10;
- j++;
- }
- }
- ath_rc_priv->neg_rates.rs_nrates = j;
-
- if (sta->ht_cap.ht_supported) {
- for (i = 0, j = 0; i < 77; i++) {
- if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8)))
- ath_rc_priv->neg_ht_rates.rs_rates[j++] = i;
- if (j == ATH_RATE_MAX)
- break;
- }
- ath_rc_priv->neg_ht_rates.rs_nrates = j;
- }
-
- ath_rc_priv->rate_table = ath_choose_rate_table(sc, sband->band,
- sta->ht_cap.ht_supported);
- if (!ath_rc_priv->rate_table) {
- ath_err(common, "No rate table chosen\n");
- return;
- }
-
- ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta);
- ath_rc_init(sc, priv_sta);
-}
-
-static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
- struct cfg80211_chan_def *chandef,
- struct ieee80211_sta *sta, void *priv_sta,
- u32 changed)
-{
- struct ath_softc *sc = priv;
- struct ath_rate_priv *ath_rc_priv = priv_sta;
-
- if (changed & IEEE80211_RC_BW_CHANGED) {
- ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta);
- ath_rc_init(sc, priv_sta);
-
- ath_dbg(ath9k_hw_common(sc->sc_ah), CONFIG,
- "Operating Bandwidth changed to: %d\n",
- sc->hw->conf.chandef.width);
- }
-}
-
-#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS)
-
-void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate)
-{
- struct ath_rc_stats *stats;
-
- stats = &rc->rcstats[final_rate];
- stats->success++;
-}
-
-void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix,
- int xretries, int retries, u8 per)
-{
- struct ath_rc_stats *stats = &rc->rcstats[rix];
-
- stats->xretries += xretries;
- stats->retries += retries;
- stats->per = per;
-}
-
-static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ath_rate_priv *rc = file->private_data;
- char *buf;
- unsigned int len = 0, max;
- int rix;
- ssize_t retval;
-
- if (rc->rate_table == NULL)
- return 0;
-
- max = 80 + rc->rate_table_size * 1024 + 1;
- buf = kmalloc(max, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- len += sprintf(buf, "%6s %6s %6s "
- "%10s %10s %10s %10s\n",
- "HT", "MCS", "Rate",
- "Success", "Retries", "XRetries", "PER");
-
- for (rix = 0; rix < rc->max_valid_rate; rix++) {
- u8 i = rc->valid_rate_index[rix];
- u32 ratekbps = rc->rate_table->info[i].ratekbps;
- struct ath_rc_stats *stats = &rc->rcstats[i];
- char mcs[5];
- char htmode[5];
- int used_mcs = 0, used_htmode = 0;
-
- if (WLAN_RC_PHY_HT(rc->rate_table->info[i].phy)) {
- used_mcs = scnprintf(mcs, 5, "%d",
- rc->rate_table->info[i].ratecode);
-
- if (WLAN_RC_PHY_40(rc->rate_table->info[i].phy))
- used_htmode = scnprintf(htmode, 5, "HT40");
- else if (WLAN_RC_PHY_20(rc->rate_table->info[i].phy))
- used_htmode = scnprintf(htmode, 5, "HT20");
- else
- used_htmode = scnprintf(htmode, 5, "????");
- }
-
- mcs[used_mcs] = '\0';
- htmode[used_htmode] = '\0';
-
- len += scnprintf(buf + len, max - len,
- "%6s %6s %3u.%d: "
- "%10u %10u %10u %10u\n",
- htmode,
- mcs,
- ratekbps / 1000,
- (ratekbps % 1000) / 100,
- stats->success,
- stats->retries,
- stats->xretries,
- stats->per);
- }
-
- if (len > max)
- len = max;
-
- retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
- kfree(buf);
- return retval;
-}
-
-static const struct file_operations fops_rcstat = {
- .read = read_file_rcstat,
- .open = simple_open,
- .owner = THIS_MODULE
-};
-
-static void ath_rate_add_sta_debugfs(void *priv, void *priv_sta,
- struct dentry *dir)
-{
- struct ath_rate_priv *rc = priv_sta;
- rc->debugfs_rcstats = debugfs_create_file("rc_stats", S_IRUGO,
- dir, rc, &fops_rcstat);
-}
-
-static void ath_rate_remove_sta_debugfs(void *priv, void *priv_sta)
-{
- struct ath_rate_priv *rc = priv_sta;
- debugfs_remove(rc->debugfs_rcstats);
-}
-
-#endif /* CONFIG_MAC80211_DEBUGFS && CONFIG_ATH9K_DEBUGFS */
-
-static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
-{
- return hw->priv;
-}
-
-static void ath_rate_free(void *priv)
-{
- return;
-}
-
-static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
-{
- return kzalloc(sizeof(struct ath_rate_priv), gfp);
-}
-
-static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta,
- void *priv_sta)
-{
- struct ath_rate_priv *rate_priv = priv_sta;
- kfree(rate_priv);
-}
-
-static struct rate_control_ops ath_rate_ops = {
- .module = NULL,
- .name = "ath9k_rate_control",
- .tx_status = ath_tx_status,
- .get_rate = ath_get_rate,
- .rate_init = ath_rate_init,
- .rate_update = ath_rate_update,
- .alloc = ath_rate_alloc,
- .free = ath_rate_free,
- .alloc_sta = ath_rate_alloc_sta,
- .free_sta = ath_rate_free_sta,
-
-#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS)
- .add_sta_debugfs = ath_rate_add_sta_debugfs,
- .remove_sta_debugfs = ath_rate_remove_sta_debugfs,
-#endif
-};
-
-int ath_rate_control_register(void)
-{
- return ieee80211_rate_control_register(&ath_rate_ops);
-}
-
-void ath_rate_control_unregister(void)
-{
- ieee80211_rate_control_unregister(&ath_rate_ops);
-}
diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h
deleted file mode 100644
index b9a87383cb43..000000000000
--- a/drivers/net/wireless/ath/ath9k/rc.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (c) 2004 Sam Leffler, Errno Consulting
- * Copyright (c) 2004 Video54 Technologies, Inc.
- * Copyright (c) 2008-2011 Atheros Communications Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef RC_H
-#define RC_H
-
-#include "hw.h"
-
-struct ath_softc;
-
-#define ATH_RATE_MAX 30
-#define RATE_TABLE_SIZE 72
-
-#define RC_INVALID 0x0000
-#define RC_LEGACY 0x0001
-#define RC_SS 0x0002
-#define RC_DS 0x0004
-#define RC_TS 0x0008
-#define RC_HT_20 0x0010
-#define RC_HT_40 0x0020
-
-#define RC_STREAM_MASK 0xe
-#define RC_DS_OR_LATER(f) ((((f) & RC_STREAM_MASK) == RC_DS) || \
- (((f) & RC_STREAM_MASK) == (RC_DS | RC_TS)))
-#define RC_TS_ONLY(f) (((f) & RC_STREAM_MASK) == RC_TS)
-#define RC_SS_OR_LEGACY(f) ((f) & (RC_SS | RC_LEGACY))
-
-#define RC_HT_2040 (RC_HT_20 | RC_HT_40)
-#define RC_ALL_STREAM (RC_SS | RC_DS | RC_TS)
-#define RC_L_SD (RC_LEGACY | RC_SS | RC_DS)
-#define RC_L_SDT (RC_LEGACY | RC_SS | RC_DS | RC_TS)
-#define RC_HT_S_20 (RC_HT_20 | RC_SS)
-#define RC_HT_D_20 (RC_HT_20 | RC_DS)
-#define RC_HT_T_20 (RC_HT_20 | RC_TS)
-#define RC_HT_S_40 (RC_HT_40 | RC_SS)
-#define RC_HT_D_40 (RC_HT_40 | RC_DS)
-#define RC_HT_T_40 (RC_HT_40 | RC_TS)
-
-#define RC_HT_SD_20 (RC_HT_20 | RC_SS | RC_DS)
-#define RC_HT_DT_20 (RC_HT_20 | RC_DS | RC_TS)
-#define RC_HT_SD_40 (RC_HT_40 | RC_SS | RC_DS)
-#define RC_HT_DT_40 (RC_HT_40 | RC_DS | RC_TS)
-
-#define RC_HT_SD_2040 (RC_HT_2040 | RC_SS | RC_DS)
-#define RC_HT_SDT_2040 (RC_HT_2040 | RC_SS | RC_DS | RC_TS)
-
-#define RC_HT_SDT_20 (RC_HT_20 | RC_SS | RC_DS | RC_TS)
-#define RC_HT_SDT_40 (RC_HT_40 | RC_SS | RC_DS | RC_TS)
-
-#define RC_ALL (RC_LEGACY | RC_HT_2040 | RC_ALL_STREAM)
-
-enum {
- WLAN_RC_PHY_OFDM,
- WLAN_RC_PHY_CCK,
- WLAN_RC_PHY_HT_20_SS,
- WLAN_RC_PHY_HT_20_DS,
- WLAN_RC_PHY_HT_20_TS,
- WLAN_RC_PHY_HT_40_SS,
- WLAN_RC_PHY_HT_40_DS,
- WLAN_RC_PHY_HT_40_TS,
- WLAN_RC_PHY_HT_20_SS_HGI,
- WLAN_RC_PHY_HT_20_DS_HGI,
- WLAN_RC_PHY_HT_20_TS_HGI,
- WLAN_RC_PHY_HT_40_SS_HGI,
- WLAN_RC_PHY_HT_40_DS_HGI,
- WLAN_RC_PHY_HT_40_TS_HGI,
- WLAN_RC_PHY_MAX
-};
-
-#define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \
- || (_phy == WLAN_RC_PHY_HT_40_DS) \
- || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \
- || (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
-#define WLAN_RC_PHY_TS(_phy) ((_phy == WLAN_RC_PHY_HT_20_TS) \
- || (_phy == WLAN_RC_PHY_HT_40_TS) \
- || (_phy == WLAN_RC_PHY_HT_20_TS_HGI) \
- || (_phy == WLAN_RC_PHY_HT_40_TS_HGI))
-#define WLAN_RC_PHY_20(_phy) ((_phy == WLAN_RC_PHY_HT_20_SS) \
- || (_phy == WLAN_RC_PHY_HT_20_DS) \
- || (_phy == WLAN_RC_PHY_HT_20_TS) \
- || (_phy == WLAN_RC_PHY_HT_20_SS_HGI) \
- || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \
- || (_phy == WLAN_RC_PHY_HT_20_TS_HGI))
-#define WLAN_RC_PHY_40(_phy) ((_phy == WLAN_RC_PHY_HT_40_SS) \
- || (_phy == WLAN_RC_PHY_HT_40_DS) \
- || (_phy == WLAN_RC_PHY_HT_40_TS) \
- || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \
- || (_phy == WLAN_RC_PHY_HT_40_DS_HGI) \
- || (_phy == WLAN_RC_PHY_HT_40_TS_HGI))
-#define WLAN_RC_PHY_SGI(_phy) ((_phy == WLAN_RC_PHY_HT_20_SS_HGI) \
- || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \
- || (_phy == WLAN_RC_PHY_HT_20_TS_HGI) \
- || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \
- || (_phy == WLAN_RC_PHY_HT_40_DS_HGI) \
- || (_phy == WLAN_RC_PHY_HT_40_TS_HGI))
-
-#define WLAN_RC_PHY_HT(_phy) (_phy >= WLAN_RC_PHY_HT_20_SS)
-
-#define WLAN_RC_CAP_MODE(capflag) (((capflag & WLAN_RC_HT_FLAG) ? \
- ((capflag & WLAN_RC_40_FLAG) ? RC_HT_40 : RC_HT_20) : RC_LEGACY))
-
-#define WLAN_RC_CAP_STREAM(capflag) (((capflag & WLAN_RC_TS_FLAG) ? \
- (RC_TS) : ((capflag & WLAN_RC_DS_FLAG) ? RC_DS : RC_SS)))
-
-/* Return TRUE if flag supports HT20 && client supports HT20 or
- * return TRUE if flag supports HT40 && client supports HT40.
- * This is used becos some rates overlap between HT20/HT40.
- */
-#define WLAN_RC_PHY_HT_VALID(flag, capflag) \
- (((flag & RC_HT_20) && !(capflag & WLAN_RC_40_FLAG)) || \
- ((flag & RC_HT_40) && (capflag & WLAN_RC_40_FLAG)))
-
-#define WLAN_RC_DS_FLAG (0x01)
-#define WLAN_RC_TS_FLAG (0x02)
-#define WLAN_RC_40_FLAG (0x04)
-#define WLAN_RC_SGI_FLAG (0x08)
-#define WLAN_RC_HT_FLAG (0x10)
-
-/**
- * struct ath_rate_table - Rate Control table
- * @rate_cnt: total number of rates for the given wireless mode
- * @mcs_start: MCS rate index offset
- * @rate_flags: Rate Control flags
- * @phy: CCK/OFDM/HT20/HT40
- * @ratekbps: rate in Kbits per second
- * @user_ratekbps: user rate in Kbits per second
- * @ratecode: rate that goes into HW descriptors
- * @dot11rate: value that goes into supported
- * rates info element of MLME
- * @ctrl_rate: Index of next lower basic rate, used for duration computation
- * @cw40index: Index of rates having 40MHz channel width
- * @sgi_index: Index of rates having Short Guard Interval
- * @ht_index: high throughput rates having 40MHz channel width and
- * Short Guard Interval
- * @probe_interval: interval for rate control to probe for other rates
- * @initial_ratemax: initial ratemax value
- */
-struct ath_rate_table {
- int rate_cnt;
- int mcs_start;
- struct {
- u16 rate_flags;
- u8 phy;
- u32 ratekbps;
- u32 user_ratekbps;
- u8 ratecode;
- u8 dot11rate;
- } info[RATE_TABLE_SIZE];
- u32 probe_interval;
- u8 initial_ratemax;
-};
-
-struct ath_rateset {
- u8 rs_nrates;
- u8 rs_rates[ATH_RATE_MAX];
-};
-
-struct ath_rc_stats {
- u32 success;
- u32 retries;
- u32 xretries;
- u8 per;
-};
-
-/**
- * struct ath_rate_priv - Rate Control priv data
- * @state: RC state
- * @probe_rate: rate we are probing at
- * @probe_time: msec timestamp for last probe
- * @hw_maxretry_pktcnt: num of packets since we got HW max retry error
- * @max_valid_rate: maximum number of valid rate
- * @per_down_time: msec timestamp for last PER down step
- * @valid_phy_ratecnt: valid rate count
- * @rate_max_phy: phy index for the max rate
- * @per: PER for every valid rate in %
- * @probe_interval: interval for ratectrl to probe for other rates
- * @ht_cap: HT capabilities
- * @neg_rates: Negotatied rates
- * @neg_ht_rates: Negotiated HT rates
- */
-struct ath_rate_priv {
- u8 rate_table_size;
- u8 probe_rate;
- u8 hw_maxretry_pktcnt;
- u8 max_valid_rate;
- u8 valid_rate_index[RATE_TABLE_SIZE];
- u8 ht_cap;
- u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX];
- u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE];
- u8 rate_max_phy;
- u8 per[RATE_TABLE_SIZE];
- u32 probe_time;
- u32 per_down_time;
- u32 probe_interval;
- struct ath_rateset neg_rates;
- struct ath_rateset neg_ht_rates;
- const struct ath_rate_table *rate_table;
-
-#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS)
- struct dentry *debugfs_rcstats;
- struct ath_rc_stats rcstats[RATE_TABLE_SIZE];
-#endif
-};
-
-#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS)
-void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate);
-void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix,
- int xretries, int retries, u8 per);
-#else
-static inline void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate)
-{
-}
-static inline void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix,
- int xretries, int retries, u8 per)
-{
-}
-#endif
-
-#ifdef CONFIG_ATH9K_LEGACY_RATE_CONTROL
-int ath_rate_control_register(void);
-void ath_rate_control_unregister(void);
-#else
-static inline int ath_rate_control_register(void)
-{
- return 0;
-}
-
-static inline void ath_rate_control_unregister(void)
-{
-}
-#endif
-
-#endif /* RC_H */
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index a0ebdd000fc2..6c9accdb52e4 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -732,11 +732,18 @@ static struct ath_rxbuf *ath_get_next_rx_buf(struct ath_softc *sc,
return NULL;
/*
- * mark descriptor as zero-length and set the 'more'
- * flag to ensure that both buffers get discarded
+ * Re-check previous descriptor, in case it has been filled
+ * in the mean time.
*/
- rs->rs_datalen = 0;
- rs->rs_more = true;
+ ret = ath9k_hw_rxprocdesc(ah, ds, rs);
+ if (ret == -EINPROGRESS) {
+ /*
+ * mark descriptor as zero-length and set the 'more'
+ * flag to ensure that both buffers get discarded
+ */
+ rs->rs_datalen = 0;
+ rs->rs_more = true;
+ }
}
list_del(&bf->list);
@@ -755,204 +762,6 @@ static struct ath_rxbuf *ath_get_next_rx_buf(struct ath_softc *sc,
return bf;
}
-/* Assumes you've already done the endian to CPU conversion */
-static bool ath9k_rx_accept(struct ath_common *common,
- struct ieee80211_hdr *hdr,
- struct ieee80211_rx_status *rxs,
- struct ath_rx_status *rx_stats,
- bool *decrypt_error)
-{
- struct ath_softc *sc = (struct ath_softc *) common->priv;
- bool is_mc, is_valid_tkip, strip_mic, mic_error;
- struct ath_hw *ah = common->ah;
- __le16 fc;
-
- fc = hdr->frame_control;
-
- is_mc = !!is_multicast_ether_addr(hdr->addr1);
- is_valid_tkip = rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID &&
- test_bit(rx_stats->rs_keyix, common->tkip_keymap);
- strip_mic = is_valid_tkip && ieee80211_is_data(fc) &&
- ieee80211_has_protected(fc) &&
- !(rx_stats->rs_status &
- (ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC |
- ATH9K_RXERR_KEYMISS));
-
- /*
- * Key miss events are only relevant for pairwise keys where the
- * descriptor does contain a valid key index. This has been observed
- * mostly with CCMP encryption.
- */
- if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID ||
- !test_bit(rx_stats->rs_keyix, common->ccmp_keymap))
- rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS;
-
- mic_error = is_valid_tkip && !ieee80211_is_ctl(fc) &&
- !ieee80211_has_morefrags(fc) &&
- !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) &&
- (rx_stats->rs_status & ATH9K_RXERR_MIC);
-
- /*
- * The rx_stats->rs_status will not be set until the end of the
- * chained descriptors so it can be ignored if rs_more is set. The
- * rs_more will be false at the last element of the chained
- * descriptors.
- */
- if (rx_stats->rs_status != 0) {
- u8 status_mask;
-
- if (rx_stats->rs_status & ATH9K_RXERR_CRC) {
- rxs->flag |= RX_FLAG_FAILED_FCS_CRC;
- mic_error = false;
- }
-
- if ((rx_stats->rs_status & ATH9K_RXERR_DECRYPT) ||
- (!is_mc && (rx_stats->rs_status & ATH9K_RXERR_KEYMISS))) {
- *decrypt_error = true;
- mic_error = false;
- }
-
- /*
- * Reject error frames with the exception of
- * decryption and MIC failures. For monitor mode,
- * we also ignore the CRC error.
- */
- status_mask = ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
- ATH9K_RXERR_KEYMISS;
-
- if (ah->is_monitoring && (sc->rx.rxfilter & FIF_FCSFAIL))
- status_mask |= ATH9K_RXERR_CRC;
-
- if (rx_stats->rs_status & ~status_mask)
- return false;
- }
-
- /*
- * For unicast frames the MIC error bit can have false positives,
- * so all MIC error reports need to be validated in software.
- * False negatives are not common, so skip software verification
- * if the hardware considers the MIC valid.
- */
- if (strip_mic)
- rxs->flag |= RX_FLAG_MMIC_STRIPPED;
- else if (is_mc && mic_error)
- rxs->flag |= RX_FLAG_MMIC_ERROR;
-
- return true;
-}
-
-static int ath9k_process_rate(struct ath_common *common,
- struct ieee80211_hw *hw,
- struct ath_rx_status *rx_stats,
- struct ieee80211_rx_status *rxs)
-{
- struct ieee80211_supported_band *sband;
- enum ieee80211_band band;
- unsigned int i = 0;
- struct ath_softc __maybe_unused *sc = common->priv;
- struct ath_hw *ah = sc->sc_ah;
-
- band = ah->curchan->chan->band;
- sband = hw->wiphy->bands[band];
-
- if (IS_CHAN_QUARTER_RATE(ah->curchan))
- rxs->flag |= RX_FLAG_5MHZ;
- else if (IS_CHAN_HALF_RATE(ah->curchan))
- rxs->flag |= RX_FLAG_10MHZ;
-
- if (rx_stats->rs_rate & 0x80) {
- /* HT rate */
- rxs->flag |= RX_FLAG_HT;
- rxs->flag |= rx_stats->flag;
- rxs->rate_idx = rx_stats->rs_rate & 0x7f;
- return 0;
- }
-
- for (i = 0; i < sband->n_bitrates; i++) {
- if (sband->bitrates[i].hw_value == rx_stats->rs_rate) {
- rxs->rate_idx = i;
- return 0;
- }
- if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) {
- rxs->flag |= RX_FLAG_SHORTPRE;
- rxs->rate_idx = i;
- return 0;
- }
- }
-
- /*
- * No valid hardware bitrate found -- we should not get here
- * because hardware has already validated this frame as OK.
- */
- ath_dbg(common, ANY,
- "unsupported hw bitrate detected 0x%02x using 1 Mbit\n",
- rx_stats->rs_rate);
- RX_STAT_INC(rx_rate_err);
- return -EINVAL;
-}
-
-static void ath9k_process_rssi(struct ath_common *common,
- struct ieee80211_hw *hw,
- struct ath_rx_status *rx_stats,
- struct ieee80211_rx_status *rxs)
-{
- struct ath_softc *sc = hw->priv;
- struct ath_hw *ah = common->ah;
- int last_rssi;
- int rssi = rx_stats->rs_rssi;
- int i, j;
-
- /*
- * RSSI is not available for subframes in an A-MPDU.
- */
- if (rx_stats->rs_moreaggr) {
- rxs->flag |= RX_FLAG_NO_SIGNAL_VAL;
- return;
- }
-
- /*
- * Check if the RSSI for the last subframe in an A-MPDU
- * or an unaggregated frame is valid.
- */
- if (rx_stats->rs_rssi == ATH9K_RSSI_BAD) {
- rxs->flag |= RX_FLAG_NO_SIGNAL_VAL;
- return;
- }
-
- for (i = 0, j = 0; i < ARRAY_SIZE(rx_stats->rs_rssi_ctl); i++) {
- s8 rssi;
-
- if (!(ah->rxchainmask & BIT(i)))
- continue;
-
- rssi = rx_stats->rs_rssi_ctl[i];
- if (rssi != ATH9K_RSSI_BAD) {
- rxs->chains |= BIT(j);
- rxs->chain_signal[j] = ah->noise + rssi;
- }
- j++;
- }
-
- /*
- * Update Beacon RSSI, this is used by ANI.
- */
- if (rx_stats->is_mybeacon &&
- ((ah->opmode == NL80211_IFTYPE_STATION) ||
- (ah->opmode == NL80211_IFTYPE_ADHOC))) {
- ATH_RSSI_LPF(sc->last_rssi, rx_stats->rs_rssi);
- last_rssi = sc->last_rssi;
-
- if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
- rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER);
- if (rssi < 0)
- rssi = 0;
-
- ah->stats.avgbrssi = rssi;
- }
-
- rxs->signal = ah->noise + rx_stats->rs_rssi;
-}
-
static void ath9k_process_tsf(struct ath_rx_status *rs,
struct ieee80211_rx_status *rxs,
u64 tsf)
@@ -985,32 +794,32 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_hdr *hdr;
bool discard_current = sc->rx.discard_next;
- int ret = 0;
/*
* Discard corrupt descriptors which are marked in
* ath_get_next_rx_buf().
*/
- sc->rx.discard_next = rx_stats->rs_more;
if (discard_current)
- return -EINVAL;
+ goto corrupt;
+
+ sc->rx.discard_next = false;
/*
* Discard zero-length packets.
*/
if (!rx_stats->rs_datalen) {
RX_STAT_INC(rx_len_err);
- return -EINVAL;
+ goto corrupt;
}
- /*
- * rs_status follows rs_datalen so if rs_datalen is too large
- * we can take a hint that hardware corrupted it, so ignore
- * those frames.
- */
+ /*
+ * rs_status follows rs_datalen so if rs_datalen is too large
+ * we can take a hint that hardware corrupted it, so ignore
+ * those frames.
+ */
if (rx_stats->rs_datalen > (common->rx_bufsize - ah->caps.rx_status_len)) {
RX_STAT_INC(rx_len_err);
- return -EINVAL;
+ goto corrupt;
}
/* Only use status info from the last fragment */
@@ -1024,10 +833,8 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
* This is different from the other corrupt descriptor
* condition handled above.
*/
- if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) {
- ret = -EINVAL;
- goto exit;
- }
+ if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC)
+ goto corrupt;
hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len);
@@ -1043,18 +850,15 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime))
RX_STAT_INC(rx_spectral);
- ret = -EINVAL;
- goto exit;
+ return -EINVAL;
}
/*
* everything but the rate is checked here, the rate check is done
* separately to avoid doing two lookups for a rate for each frame.
*/
- if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) {
- ret = -EINVAL;
- goto exit;
- }
+ if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error, sc->rx.rxfilter))
+ return -EINVAL;
if (ath_is_mybeacon(common, hdr)) {
RX_STAT_INC(rx_beacons);
@@ -1064,17 +868,21 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
/*
* This shouldn't happen, but have a safety check anyway.
*/
- if (WARN_ON(!ah->curchan)) {
- ret = -EINVAL;
- goto exit;
- }
+ if (WARN_ON(!ah->curchan))
+ return -EINVAL;
- if (ath9k_process_rate(common, hw, rx_stats, rx_status)) {
- ret =-EINVAL;
- goto exit;
+ if (ath9k_cmn_process_rate(common, hw, rx_stats, rx_status)) {
+ /*
+ * No valid hardware bitrate found -- we should not get here
+ * because hardware has already validated this frame as OK.
+ */
+ ath_dbg(common, ANY, "unsupported hw bitrate detected 0x%02x using 1 Mbit\n",
+ rx_stats->rs_rate);
+ RX_STAT_INC(rx_rate_err);
+ return -EINVAL;
}
- ath9k_process_rssi(common, hw, rx_stats, rx_status);
+ ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status);
rx_status->band = ah->curchan->chan->band;
rx_status->freq = ah->curchan->chan->center_freq;
@@ -1087,60 +895,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
sc->rx.num_pkts++;
#endif
-exit:
- sc->rx.discard_next = false;
- return ret;
-}
-
-static void ath9k_rx_skb_postprocess(struct ath_common *common,
- struct sk_buff *skb,
- struct ath_rx_status *rx_stats,
- struct ieee80211_rx_status *rxs,
- bool decrypt_error)
-{
- struct ath_hw *ah = common->ah;
- struct ieee80211_hdr *hdr;
- int hdrlen, padpos, padsize;
- u8 keyix;
- __le16 fc;
-
- /* see if any padding is done by the hw and remove it */
- hdr = (struct ieee80211_hdr *) skb->data;
- hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- fc = hdr->frame_control;
- padpos = ieee80211_hdrlen(fc);
-
- /* The MAC header is padded to have 32-bit boundary if the
- * packet payload is non-zero. The general calculation for
- * padsize would take into account odd header lengths:
- * padsize = (4 - padpos % 4) % 4; However, since only
- * even-length headers are used, padding can only be 0 or 2
- * bytes and we can optimize this a bit. In addition, we must
- * not try to remove padding from short control frames that do
- * not have payload. */
- padsize = padpos & 3;
- if (padsize && skb->len>=padpos+padsize+FCS_LEN) {
- memmove(skb->data + padsize, skb->data, padpos);
- skb_pull(skb, padsize);
- }
-
- keyix = rx_stats->rs_keyix;
-
- if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error &&
- ieee80211_has_protected(fc)) {
- rxs->flag |= RX_FLAG_DECRYPTED;
- } else if (ieee80211_has_protected(fc)
- && !decrypt_error && skb->len >= hdrlen + 4) {
- keyix = skb->data[hdrlen + 3] >> 6;
+ return 0;
- if (test_bit(keyix, common->keymap))
- rxs->flag |= RX_FLAG_DECRYPTED;
- }
- if (ah->sw_mgmt_crypto &&
- (rxs->flag & RX_FLAG_DECRYPTED) &&
- ieee80211_is_mgmt(fc))
- /* Use software decrypt for management frames. */
- rxs->flag &= ~RX_FLAG_DECRYPTED;
+corrupt:
+ sc->rx.discard_next = rx_stats->rs_more;
+ return -EINVAL;
}
/*
@@ -1292,8 +1051,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
skb_pull(skb, ah->caps.rx_status_len);
if (!rs.rs_more)
- ath9k_rx_skb_postprocess(common, hdr_skb, &rs,
- rxs, decrypt_error);
+ ath9k_cmn_rx_skb_postprocess(common, hdr_skb, &rs,
+ rxs, decrypt_error);
if (rs.rs_more) {
RX_STAT_INC(rx_frags);
diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c
index b686a7498450..a65cfb91adca 100644
--- a/drivers/net/wireless/ath/ath9k/tx99.c
+++ b/drivers/net/wireless/ath/ath9k/tx99.c
@@ -108,7 +108,7 @@ static int ath9k_tx99_init(struct ath_softc *sc)
struct ath_tx_control txctl;
int r;
- if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
+ if (test_bit(ATH_OP_INVALID, &common->op_flags)) {
ath_err(common,
"driver is in invalid state unable to use TX99");
return -EINVAL;
diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c
index 1b3230fa3651..2879887f5691 100644
--- a/drivers/net/wireless/ath/ath9k/wow.c
+++ b/drivers/net/wireless/ath/ath9k/wow.c
@@ -198,7 +198,7 @@ int ath9k_suspend(struct ieee80211_hw *hw,
ath_cancel_work(sc);
ath_stop_ani(sc);
- if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
+ if (test_bit(ATH_OP_INVALID, &common->op_flags)) {
ath_dbg(common, ANY, "Device not present\n");
ret = -EINVAL;
goto fail_wow;
@@ -224,7 +224,7 @@ int ath9k_suspend(struct ieee80211_hw *hw,
* STA.
*/
- if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
+ if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) {
ath_dbg(common, WOW, "None of the STA vifs are associated\n");
ret = 1;
goto fail_wow;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 0a75e2f68c9d..87cbec47fb48 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1040,11 +1040,11 @@ static int ath_max_framelen(int usec, int mcs, bool ht40, bool sgi)
int symbols, bits;
int bytes = 0;
+ usec -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
symbols = sgi ? TIME_SYMBOLS_HALFGI(usec) : TIME_SYMBOLS(usec);
bits = symbols * bits_per_symbol[mcs % 8][ht40] * streams;
bits -= OFDM_PLCP_BITS;
bytes = bits / 8;
- bytes -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
if (bytes > 65532)
bytes = 65532;
@@ -1076,6 +1076,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
struct ath_tx_info *info, int len, bool rts)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct sk_buff *skb;
struct ieee80211_tx_info *tx_info;
struct ieee80211_tx_rate *rates;
@@ -1145,7 +1146,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
}
/* legacy rates */
- rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
+ rate = &common->sbands[tx_info->band].bitrates[rates[i].idx];
if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
!(rate->flags & IEEE80211_RATE_ERP_G))
phy = WLAN_RC_PHY_CCK;
@@ -1444,14 +1445,16 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
for (tidno = 0, tid = &an->tid[tidno];
tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
- if (!tid->sched)
- continue;
-
ac = tid->ac;
txq = ac->txq;
ath_txq_lock(sc, txq);
+ if (!tid->sched) {
+ ath_txq_unlock(sc, txq);
+ continue;
+ }
+
buffered = ath_tid_has_buffered(tid);
tid->sched = false;
@@ -1696,7 +1699,7 @@ int ath_cabq_update(struct ath_softc *sc)
ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
- qi.tqi_readyTime = (cur_conf->beacon_interval *
+ qi.tqi_readyTime = (TU_TO_USEC(cur_conf->beacon_interval) *
ATH_CABQ_READY_TIME) / 100;
ath_txq_update(sc, qnum, &qi);
@@ -1766,7 +1769,7 @@ bool ath_drain_all_txq(struct ath_softc *sc)
int i;
u32 npend = 0;
- if (test_bit(SC_OP_INVALID, &sc->sc_flags))
+ if (test_bit(ATH_OP_INVALID, &common->op_flags))
return true;
ath9k_hw_abort_tx_dma(ah);
@@ -1814,11 +1817,12 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
*/
void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_atx_ac *ac, *last_ac;
struct ath_atx_tid *tid, *last_tid;
bool sent = false;
- if (test_bit(SC_OP_HW_RESET, &sc->sc_flags) ||
+ if (test_bit(ATH_OP_HW_RESET, &common->op_flags) ||
list_empty(&txq->axq_acq))
return;
@@ -2061,7 +2065,7 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
ATH_TXBUF_RESET(bf);
- if (tid) {
+ if (tid && ieee80211_is_data_present(hdr->frame_control)) {
fragno = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
seqno = tid->seq_next;
hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
@@ -2184,14 +2188,15 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
txq->stopped = true;
}
+ if (txctl->an && ieee80211_is_data_present(hdr->frame_control))
+ tid = ath_get_skb_tid(sc, txctl->an, skb);
+
if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) {
ath_txq_unlock(sc, txq);
txq = sc->tx.uapsdq;
ath_txq_lock(sc, txq);
} else if (txctl->an &&
ieee80211_is_data_present(hdr->frame_control)) {
- tid = ath_get_skb_tid(sc, txctl->an, skb);
-
WARN_ON(tid->ac->txq != txctl->txq);
if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
@@ -2467,7 +2472,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
ath_txq_lock(sc, txq);
for (;;) {
- if (test_bit(SC_OP_HW_RESET, &sc->sc_flags))
+ if (test_bit(ATH_OP_HW_RESET, &common->op_flags))
break;
if (list_empty(&txq->axq_q)) {
@@ -2550,7 +2555,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
int status;
for (;;) {
- if (test_bit(SC_OP_HW_RESET, &sc->sc_flags))
+ if (test_bit(ATH_OP_HW_RESET, &common->op_flags))
break;
status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts);
@@ -2566,7 +2571,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
sc->beacon.tx_processed = true;
sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK);
- ath9k_csa_is_finished(sc);
+ ath9k_csa_update(sc);
continue;
}
diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
index 536bc46a2912..924135b8e575 100644
--- a/drivers/net/wireless/ath/carl9170/rx.c
+++ b/drivers/net/wireless/ath/carl9170/rx.c
@@ -572,7 +572,7 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len)
static void carl9170_ba_check(struct ar9170 *ar, void *data, unsigned int len)
{
- struct ieee80211_bar *bar = (void *) data;
+ struct ieee80211_bar *bar = data;
struct carl9170_bar_list_entry *entry;
unsigned int queue;
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index e5e905910db4..415393dfb6fc 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -222,7 +222,7 @@ static const struct ieee80211_regdomain *ath_default_world_regdomain(void)
static const struct
ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)
{
- switch (reg->regpair->regDmnEnum) {
+ switch (reg->regpair->reg_domain) {
case 0x60:
case 0x61:
case 0x62:
@@ -431,7 +431,7 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy,
enum nl80211_reg_initiator initiator,
struct ath_regulatory *reg)
{
- switch (reg->regpair->regDmnEnum) {
+ switch (reg->regpair->reg_domain) {
case 0x60:
case 0x63:
case 0x66:
@@ -560,7 +560,7 @@ static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg)
printk(KERN_DEBUG "ath: EEPROM indicates we "
"should expect a direct regpair map\n");
for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
- if (regDomainPairs[i].regDmnEnum == rd)
+ if (regDomainPairs[i].reg_domain == rd)
return true;
}
printk(KERN_DEBUG
@@ -617,7 +617,7 @@ ath_get_regpair(int regdmn)
if (regdmn == NO_ENUMRD)
return NULL;
for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
- if (regDomainPairs[i].regDmnEnum == regdmn)
+ if (regDomainPairs[i].reg_domain == regdmn)
return &regDomainPairs[i];
}
return NULL;
@@ -741,7 +741,7 @@ static int __ath_regd_init(struct ath_regulatory *reg)
printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n",
reg->alpha2[0], reg->alpha2[1]);
printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n",
- reg->regpair->regDmnEnum);
+ reg->regpair->reg_domain);
return 0;
}
diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c
index ee25786b4447..73f12f196f14 100644
--- a/drivers/net/wireless/ath/wcn36xx/dxe.c
+++ b/drivers/net/wireless/ath/wcn36xx/dxe.c
@@ -44,6 +44,14 @@ static void wcn36xx_dxe_write_register(struct wcn36xx *wcn, int addr, int data)
writel(data, wcn->mmio + addr);
}
+#define wcn36xx_dxe_write_register_x(wcn, reg, reg_data) \
+do { \
+ if (wcn->chip_version == WCN36XX_CHIP_3680) \
+ wcn36xx_dxe_write_register(wcn, reg ## _3680, reg_data); \
+ else \
+ wcn36xx_dxe_write_register(wcn, reg ## _3660, reg_data); \
+} while (0) \
+
static void wcn36xx_dxe_read_register(struct wcn36xx *wcn, int addr, int *data)
{
*data = readl(wcn->mmio + addr);
@@ -680,7 +688,7 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn)
/* Setting interrupt path */
reg_data = WCN36XX_DXE_CCU_INT;
- wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_REG_CCU_INT, reg_data);
+ wcn36xx_dxe_write_register_x(wcn, WCN36XX_DXE_REG_CCU_INT, reg_data);
/***************************************/
/* Init descriptors for TX LOW channel */
diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.h b/drivers/net/wireless/ath/wcn36xx/dxe.h
index c88562f85de1..35ee7e966bd2 100644
--- a/drivers/net/wireless/ath/wcn36xx/dxe.h
+++ b/drivers/net/wireless/ath/wcn36xx/dxe.h
@@ -28,11 +28,11 @@ H2H_TEST_RX_TX = DMA2
*/
/* DXE registers */
-#define WCN36XX_DXE_MEM_BASE 0x03000000
#define WCN36XX_DXE_MEM_REG 0x202000
#define WCN36XX_DXE_CCU_INT 0xA0011
-#define WCN36XX_DXE_REG_CCU_INT 0x200b10
+#define WCN36XX_DXE_REG_CCU_INT_3660 0x200b10
+#define WCN36XX_DXE_REG_CCU_INT_3680 0x2050dc
/* TODO This must calculated properly but not hardcoded */
#define WCN36XX_DXE_CTRL_TX_L 0x328a44
diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h
index 3c2ef0c32f72..a1f1127d7808 100644
--- a/drivers/net/wireless/ath/wcn36xx/hal.h
+++ b/drivers/net/wireless/ath/wcn36xx/hal.h
@@ -4384,11 +4384,13 @@ enum place_holder_in_cap_bitmap {
MAX_FEATURE_SUPPORTED = 128,
};
+#define WCN36XX_HAL_CAPS_SIZE 4
+
struct wcn36xx_hal_feat_caps_msg {
struct wcn36xx_hal_msg_header header;
- u32 feat_caps[4];
+ u32 feat_caps[WCN36XX_HAL_CAPS_SIZE];
} __packed;
/* status codes to help debug rekey failures */
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index e64a6784079e..4ab5370ab7a6 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -17,6 +17,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
+#include <linux/firmware.h>
#include <linux/platform_device.h>
#include "wcn36xx.h"
@@ -177,6 +178,60 @@ static inline u8 get_sta_index(struct ieee80211_vif *vif,
sta_priv->sta_index;
}
+static const char * const wcn36xx_caps_names[] = {
+ "MCC", /* 0 */
+ "P2P", /* 1 */
+ "DOT11AC", /* 2 */
+ "SLM_SESSIONIZATION", /* 3 */
+ "DOT11AC_OPMODE", /* 4 */
+ "SAP32STA", /* 5 */
+ "TDLS", /* 6 */
+ "P2P_GO_NOA_DECOUPLE_INIT_SCAN",/* 7 */
+ "WLANACTIVE_OFFLOAD", /* 8 */
+ "BEACON_OFFLOAD", /* 9 */
+ "SCAN_OFFLOAD", /* 10 */
+ "ROAM_OFFLOAD", /* 11 */
+ "BCN_MISS_OFFLOAD", /* 12 */
+ "STA_POWERSAVE", /* 13 */
+ "STA_ADVANCED_PWRSAVE", /* 14 */
+ "AP_UAPSD", /* 15 */
+ "AP_DFS", /* 16 */
+ "BLOCKACK", /* 17 */
+ "PHY_ERR", /* 18 */
+ "BCN_FILTER", /* 19 */
+ "RTT", /* 20 */
+ "RATECTRL", /* 21 */
+ "WOW" /* 22 */
+};
+
+static const char *wcn36xx_get_cap_name(enum place_holder_in_cap_bitmap x)
+{
+ if (x >= ARRAY_SIZE(wcn36xx_caps_names))
+ return "UNKNOWN";
+ return wcn36xx_caps_names[x];
+}
+
+static void wcn36xx_feat_caps_info(struct wcn36xx *wcn)
+{
+ int i;
+
+ for (i = 0; i < MAX_FEATURE_SUPPORTED; i++) {
+ if (get_feat_caps(wcn->fw_feat_caps, i))
+ wcn36xx_info("FW Cap %s\n", wcn36xx_get_cap_name(i));
+ }
+}
+
+static void wcn36xx_detect_chip_version(struct wcn36xx *wcn)
+{
+ if (get_feat_caps(wcn->fw_feat_caps, DOT11AC)) {
+ wcn36xx_info("Chip is 3680\n");
+ wcn->chip_version = WCN36XX_CHIP_3680;
+ } else {
+ wcn36xx_info("Chip is 3660\n");
+ wcn->chip_version = WCN36XX_CHIP_3660;
+ }
+}
+
static int wcn36xx_start(struct ieee80211_hw *hw)
{
struct wcn36xx *wcn = hw->priv;
@@ -223,6 +278,16 @@ static int wcn36xx_start(struct ieee80211_hw *hw)
goto out_free_smd_buf;
}
+ if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) {
+ ret = wcn36xx_smd_feature_caps_exchange(wcn);
+ if (ret)
+ wcn36xx_warn("Exchange feature caps failed\n");
+ else
+ wcn36xx_feat_caps_info(wcn);
+ }
+
+ wcn36xx_detect_chip_version(wcn);
+
/* DMA channel initialization */
ret = wcn36xx_dxe_init(wcn);
if (ret) {
@@ -232,11 +297,6 @@ static int wcn36xx_start(struct ieee80211_hw *hw)
wcn36xx_debugfs_init(wcn);
- if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) {
- ret = wcn36xx_smd_feature_caps_exchange(wcn);
- if (ret)
- wcn36xx_warn("Exchange feature caps failed\n");
- }
INIT_LIST_HEAD(&wcn->vif_list);
return 0;
@@ -648,6 +708,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
bss_conf->enable_beacon);
if (bss_conf->enable_beacon) {
+ vif_priv->dtim_period = bss_conf->dtim_period;
vif_priv->bss_index = 0xff;
wcn36xx_smd_config_bss(wcn, vif, NULL,
vif->addr, false);
@@ -992,6 +1053,7 @@ static int wcn36xx_remove(struct platform_device *pdev)
struct wcn36xx *wcn = hw->priv;
wcn36xx_dbg(WCN36XX_DBG_MAC, "platform remove\n");
+ release_firmware(wcn->nv);
mutex_destroy(&wcn->hal_mutex);
ieee80211_unregister_hw(hw);
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index 750626b0e22d..7bf0ef8a1f56 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -195,9 +195,11 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn,
static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len)
{
int ret = 0;
+ unsigned long start;
wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "HAL >>> ", wcn->hal_buf, len);
init_completion(&wcn->hal_rsp_compl);
+ start = jiffies;
ret = wcn->ctrl_ops->tx(wcn->hal_buf, len);
if (ret) {
wcn36xx_err("HAL TX failed\n");
@@ -205,10 +207,13 @@ static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len)
}
if (wait_for_completion_timeout(&wcn->hal_rsp_compl,
msecs_to_jiffies(HAL_MSG_TIMEOUT)) <= 0) {
- wcn36xx_err("Timeout while waiting SMD response\n");
+ wcn36xx_err("Timeout! No SMD response in %dms\n",
+ HAL_MSG_TIMEOUT);
ret = -ETIME;
goto out;
}
+ wcn36xx_dbg(WCN36XX_DBG_SMD, "SMD command completed in %dms",
+ jiffies_to_msecs(jiffies - start));
out:
return ret;
}
@@ -246,21 +251,22 @@ static int wcn36xx_smd_rsp_status_check(void *buf, size_t len)
int wcn36xx_smd_load_nv(struct wcn36xx *wcn)
{
- const struct firmware *nv;
struct nv_data *nv_d;
struct wcn36xx_hal_nv_img_download_req_msg msg_body;
int fw_bytes_left;
int ret;
u16 fm_offset = 0;
- ret = request_firmware(&nv, WLAN_NV_FILE, wcn->dev);
- if (ret) {
- wcn36xx_err("Failed to load nv file %s: %d\n",
- WLAN_NV_FILE, ret);
- goto out_free_nv;
+ if (!wcn->nv) {
+ ret = request_firmware(&wcn->nv, WLAN_NV_FILE, wcn->dev);
+ if (ret) {
+ wcn36xx_err("Failed to load nv file %s: %d\n",
+ WLAN_NV_FILE, ret);
+ goto out;
+ }
}
- nv_d = (struct nv_data *)nv->data;
+ nv_d = (struct nv_data *)wcn->nv->data;
INIT_HAL_MSG(msg_body, WCN36XX_HAL_DOWNLOAD_NV_REQ);
msg_body.header.len += WCN36XX_NV_FRAGMENT_SIZE;
@@ -270,7 +276,7 @@ int wcn36xx_smd_load_nv(struct wcn36xx *wcn)
mutex_lock(&wcn->hal_mutex);
do {
- fw_bytes_left = nv->size - fm_offset - 4;
+ fw_bytes_left = wcn->nv->size - fm_offset - 4;
if (fw_bytes_left > WCN36XX_NV_FRAGMENT_SIZE) {
msg_body.last_fragment = 0;
msg_body.nv_img_buffer_size = WCN36XX_NV_FRAGMENT_SIZE;
@@ -308,10 +314,7 @@ int wcn36xx_smd_load_nv(struct wcn36xx *wcn)
out_unlock:
mutex_unlock(&wcn->hal_mutex);
-out_free_nv:
- release_firmware(nv);
-
- return ret;
+out: return ret;
}
static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len)
@@ -899,11 +902,12 @@ static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn,
sta_priv->sta_index = params->sta_index;
sta_priv->dpu_desc_index = params->dpu_index;
+ sta_priv->ucast_dpu_sign = params->uc_ucast_sig;
wcn36xx_dbg(WCN36XX_DBG_HAL,
- "hal config sta rsp status %d sta_index %d bssid_index %d p2p %d\n",
+ "hal config sta rsp status %d sta_index %d bssid_index %d uc_ucast_sig %d p2p %d\n",
params->status, params->sta_index, params->bssid_index,
- params->p2p);
+ params->uc_ucast_sig, params->p2p);
return 0;
}
@@ -1118,7 +1122,7 @@ static int wcn36xx_smd_config_bss_rsp(struct wcn36xx *wcn,
priv_vif->sta->bss_dpu_desc_index = params->dpu_desc_index;
}
- priv_vif->ucast_dpu_signature = params->ucast_dpu_signature;
+ priv_vif->self_ucast_dpu_sign = params->ucast_dpu_signature;
return 0;
}
@@ -1637,12 +1641,12 @@ int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn,
ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
if (ret) {
- wcn36xx_err("Sending hal_exit_bmps failed\n");
+ wcn36xx_err("Sending hal_keep_alive failed\n");
goto out;
}
ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
if (ret) {
- wcn36xx_err("hal_exit_bmps response failed err=%d\n", ret);
+ wcn36xx_err("hal_keep_alive response failed err=%d\n", ret);
goto out;
}
out:
@@ -1682,8 +1686,7 @@ out:
return ret;
}
-static inline void set_feat_caps(u32 *bitmap,
- enum place_holder_in_cap_bitmap cap)
+void set_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap)
{
int arr_idx, bit_idx;
@@ -1697,8 +1700,7 @@ static inline void set_feat_caps(u32 *bitmap,
bitmap[arr_idx] |= (1 << bit_idx);
}
-static inline int get_feat_caps(u32 *bitmap,
- enum place_holder_in_cap_bitmap cap)
+int get_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap)
{
int arr_idx, bit_idx;
int ret = 0;
@@ -1714,8 +1716,7 @@ static inline int get_feat_caps(u32 *bitmap,
return ret;
}
-static inline void clear_feat_caps(u32 *bitmap,
- enum place_holder_in_cap_bitmap cap)
+void clear_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap)
{
int arr_idx, bit_idx;
@@ -1731,8 +1732,8 @@ static inline void clear_feat_caps(u32 *bitmap,
int wcn36xx_smd_feature_caps_exchange(struct wcn36xx *wcn)
{
- struct wcn36xx_hal_feat_caps_msg msg_body;
- int ret = 0;
+ struct wcn36xx_hal_feat_caps_msg msg_body, *rsp;
+ int ret = 0, i;
mutex_lock(&wcn->hal_mutex);
INIT_HAL_MSG(msg_body, WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_REQ);
@@ -1746,12 +1747,15 @@ int wcn36xx_smd_feature_caps_exchange(struct wcn36xx *wcn)
wcn36xx_err("Sending hal_feature_caps_exchange failed\n");
goto out;
}
- ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
- if (ret) {
- wcn36xx_err("hal_feature_caps_exchange response failed err=%d\n",
- ret);
+ if (wcn->hal_rsp_len != sizeof(*rsp)) {
+ wcn36xx_err("Invalid hal_feature_caps_exchange response");
goto out;
}
+
+ rsp = (struct wcn36xx_hal_feat_caps_msg *) wcn->hal_buf;
+
+ for (i = 0; i < WCN36XX_HAL_CAPS_SIZE; i++)
+ wcn->fw_feat_caps[i] = rsp->feat_caps[i];
out:
mutex_unlock(&wcn->hal_mutex);
return ret;
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h
index e7c39019c6f1..008d03423dbf 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.h
+++ b/drivers/net/wireless/ath/wcn36xx/smd.h
@@ -24,7 +24,7 @@
#define WCN36XX_HAL_BUF_SIZE 4096
-#define HAL_MSG_TIMEOUT 200
+#define HAL_MSG_TIMEOUT 500
#define WCN36XX_SMSM_WLAN_TX_ENABLE 0x00000400
#define WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY 0x00000200
/* The PNO version info be contained in the rsp msg */
@@ -112,6 +112,9 @@ int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn,
int wcn36xx_smd_dump_cmd_req(struct wcn36xx *wcn, u32 arg1, u32 arg2,
u32 arg3, u32 arg4, u32 arg5);
int wcn36xx_smd_feature_caps_exchange(struct wcn36xx *wcn);
+void set_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap);
+int get_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap);
+void clear_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap);
int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn,
struct ieee80211_sta *sta,
diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c
index b2b60e30caaf..32bb26a0db2a 100644
--- a/drivers/net/wireless/ath/wcn36xx/txrx.c
+++ b/drivers/net/wireless/ath/wcn36xx/txrx.c
@@ -57,8 +57,7 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb)
RX_FLAG_MMIC_STRIPPED |
RX_FLAG_DECRYPTED;
- wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x status->vendor_radiotap_len=%x\n",
- status.flag, status.vendor_radiotap_len);
+ wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x\n", status.flag);
memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
@@ -132,6 +131,7 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
struct ieee80211_vif,
drv_priv);
+ bd->dpu_sign = sta_priv->ucast_dpu_sign;
if (vif->type == NL80211_IFTYPE_STATION) {
bd->sta_index = sta_priv->bss_sta_index;
bd->dpu_desc_idx = sta_priv->bss_dpu_desc_index;
@@ -145,10 +145,9 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
__vif_priv = get_vif_by_addr(wcn, hdr->addr2);
bd->sta_index = __vif_priv->self_sta_index;
bd->dpu_desc_idx = __vif_priv->self_dpu_desc_index;
+ bd->dpu_sign = __vif_priv->self_ucast_dpu_sign;
}
- bd->dpu_sign = __vif_priv->ucast_dpu_signature;
-
if (ieee80211_is_nullfunc(hdr->frame_control) ||
(sta_priv && !sta_priv->is_data_encrypted))
bd->dpu_ne = 1;
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
index 8fa5cbace5ab..f0fb81dfd17b 100644
--- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
+++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
@@ -125,10 +125,10 @@ struct wcn36xx_vif {
enum wcn36xx_power_state pw_state;
u8 bss_index;
- u8 ucast_dpu_signature;
/* Returned from WCN36XX_HAL_ADD_STA_SELF_RSP */
u8 self_sta_index;
u8 self_dpu_desc_index;
+ u8 self_ucast_dpu_sign;
};
/**
@@ -159,6 +159,7 @@ struct wcn36xx_sta {
u16 tid;
u8 sta_index;
u8 dpu_desc_index;
+ u8 ucast_dpu_sign;
u8 bss_sta_index;
u8 bss_dpu_desc_index;
bool is_data_encrypted;
@@ -171,10 +172,14 @@ struct wcn36xx {
struct device *dev;
struct list_head vif_list;
+ const struct firmware *nv;
+
u8 fw_revision;
u8 fw_version;
u8 fw_minor;
u8 fw_major;
+ u32 fw_feat_caps[WCN36XX_HAL_CAPS_SIZE];
+ u32 chip_version;
/* extra byte for the NULL termination */
u8 crm_version[WCN36XX_HAL_VERSION_LENGTH + 1];
@@ -222,6 +227,9 @@ struct wcn36xx {
};
+#define WCN36XX_CHIP_3660 0
+#define WCN36XX_CHIP_3680 1
+
static inline bool wcn36xx_is_fw_version(struct wcn36xx *wcn,
u8 major,
u8 minor,
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile
index 990dd42ae79e..c7a3465fd02a 100644
--- a/drivers/net/wireless/ath/wil6210/Makefile
+++ b/drivers/net/wireless/ath/wil6210/Makefile
@@ -9,6 +9,7 @@ wil6210-y += wmi.o
wil6210-y += interrupt.o
wil6210-y += txrx.o
wil6210-y += debug.o
+wil6210-y += rx_reorder.o
wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
# for tracing framework to find trace.h
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 5b340769d5bb..4806a49cb61b 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -104,41 +104,125 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type)
return -EOPNOTSUPP;
}
-static int wil_cfg80211_get_station(struct wiphy *wiphy,
- struct net_device *ndev,
- u8 *mac, struct station_info *sinfo)
+static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
+ struct station_info *sinfo)
{
- struct wil6210_priv *wil = wiphy_to_wil(wiphy);
- int rc;
struct wmi_notify_req_cmd cmd = {
- .cid = 0,
+ .cid = cid,
.interval_usec = 0,
};
+ struct {
+ struct wil6210_mbox_hdr_wmi wmi;
+ struct wmi_notify_req_done_event evt;
+ } __packed reply;
+ struct wil_net_stats *stats = &wil->sta[cid].stats;
+ int rc;
- if (memcmp(mac, wil->dst_addr[0], ETH_ALEN))
- return -ENOENT;
-
- /* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */
rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
- WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20);
+ WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20);
if (rc)
return rc;
+ wil_dbg_wmi(wil, "Link status for CID %d: {\n"
+ " MCS %d TSF 0x%016llx\n"
+ " BF status 0x%08x SNR 0x%08x SQI %d%%\n"
+ " Tx Tpt %d goodput %d Rx goodput %d\n"
+ " Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n",
+ cid, le16_to_cpu(reply.evt.bf_mcs),
+ le64_to_cpu(reply.evt.tsf), reply.evt.status,
+ le32_to_cpu(reply.evt.snr_val),
+ reply.evt.sqi,
+ le32_to_cpu(reply.evt.tx_tpt),
+ le32_to_cpu(reply.evt.tx_goodput),
+ le32_to_cpu(reply.evt.rx_goodput),
+ le16_to_cpu(reply.evt.my_rx_sector),
+ le16_to_cpu(reply.evt.my_tx_sector),
+ le16_to_cpu(reply.evt.other_rx_sector),
+ le16_to_cpu(reply.evt.other_tx_sector));
+
sinfo->generation = wil->sinfo_gen;
- sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->filled = STATION_INFO_RX_BYTES |
+ STATION_INFO_TX_BYTES |
+ STATION_INFO_RX_PACKETS |
+ STATION_INFO_TX_PACKETS |
+ STATION_INFO_RX_BITRATE |
+ STATION_INFO_TX_BITRATE |
+ STATION_INFO_RX_DROP_MISC |
+ STATION_INFO_TX_FAILED;
+
sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
- sinfo->txrate.mcs = wil->stats.bf_mcs;
- sinfo->filled |= STATION_INFO_RX_BITRATE;
+ sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs);
sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
- sinfo->rxrate.mcs = wil->stats.last_mcs_rx;
+ sinfo->rxrate.mcs = stats->last_mcs_rx;
+ sinfo->rx_bytes = stats->rx_bytes;
+ sinfo->rx_packets = stats->rx_packets;
+ sinfo->rx_dropped_misc = stats->rx_dropped;
+ sinfo->tx_bytes = stats->tx_bytes;
+ sinfo->tx_packets = stats->tx_packets;
+ sinfo->tx_failed = stats->tx_errors;
if (test_bit(wil_status_fwconnected, &wil->status)) {
sinfo->filled |= STATION_INFO_SIGNAL;
- sinfo->signal = 12; /* TODO: provide real value */
+ sinfo->signal = reply.evt.sqi;
}
- return 0;
+ return rc;
+}
+
+static int wil_cfg80211_get_station(struct wiphy *wiphy,
+ struct net_device *ndev,
+ u8 *mac, struct station_info *sinfo)
+{
+ struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ int rc;
+
+ int cid = wil_find_cid(wil, mac);
+
+ wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid);
+ if (cid < 0)
+ return cid;
+
+ rc = wil_cid_fill_sinfo(wil, cid, sinfo);
+
+ return rc;
+}
+
+/*
+ * Find @idx-th active STA for station dump.
+ */
+static int wil_find_cid_by_idx(struct wil6210_priv *wil, int idx)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
+ if (wil->sta[i].status == wil_sta_unused)
+ continue;
+ if (idx == 0)
+ return i;
+ idx--;
+ }
+
+ return -ENOENT;
+}
+
+static int wil_cfg80211_dump_station(struct wiphy *wiphy,
+ struct net_device *dev, int idx,
+ u8 *mac, struct station_info *sinfo)
+{
+ struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ int rc;
+ int cid = wil_find_cid_by_idx(wil, idx);
+
+ if (cid < 0)
+ return -ENOENT;
+
+ memcpy(mac, wil->sta[cid].addr, ETH_ALEN);
+ wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid);
+
+ rc = wil_cid_fill_sinfo(wil, cid, sinfo);
+
+ return rc;
}
static int wil_cfg80211_change_iface(struct wiphy *wiphy,
@@ -181,6 +265,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
u16 chnl[4];
} __packed cmd;
uint i, n;
+ int rc;
if (wil->scan_request) {
wil_err(wil, "Already scanning\n");
@@ -198,7 +283,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
/* FW don't support scan after connection attempt */
if (test_bit(wil_status_dontscan, &wil->status)) {
- wil_err(wil, "Scan after connect attempt not supported\n");
+ wil_err(wil, "Can't scan now\n");
return -EBUSY;
}
@@ -221,8 +306,13 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
request->channels[i]->center_freq);
}
- return wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
+ rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
+
+ if (rc)
+ wil->scan_request = NULL;
+
+ return rc;
}
static int wil_cfg80211_connect(struct wiphy *wiphy,
@@ -237,6 +327,10 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
int ch;
int rc = 0;
+ if (test_bit(wil_status_fwconnecting, &wil->status) ||
+ test_bit(wil_status_fwconnected, &wil->status))
+ return -EALREADY;
+
bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
sme->ssid, sme->ssid_len,
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
@@ -318,10 +412,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
memcpy(conn.bssid, bss->bssid, ETH_ALEN);
memcpy(conn.dst_mac, bss->bssid, ETH_ALEN);
- /*
- * FW don't support scan after connection attempt
- */
- set_bit(wil_status_dontscan, &wil->status);
+
set_bit(wil_status_fwconnecting, &wil->status);
rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn));
@@ -330,7 +421,6 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
mod_timer(&wil->connect_timer,
jiffies + msecs_to_jiffies(2000));
} else {
- clear_bit(wil_status_dontscan, &wil->status);
clear_bit(wil_status_fwconnecting, &wil->status);
}
@@ -352,6 +442,40 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
return rc;
}
+static int wil_cfg80211_mgmt_tx(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct cfg80211_mgmt_tx_params *params,
+ u64 *cookie)
+{
+ const u8 *buf = params->buf;
+ size_t len = params->len;
+ struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ int rc;
+ struct ieee80211_mgmt *mgmt_frame = (void *)buf;
+ struct wmi_sw_tx_req_cmd *cmd;
+ struct {
+ struct wil6210_mbox_hdr_wmi wmi;
+ struct wmi_sw_tx_complete_event evt;
+ } __packed evt;
+
+ cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN);
+ cmd->len = cpu_to_le16(len);
+ memcpy(cmd->payload, buf, len);
+
+ rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len,
+ WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
+ if (rc == 0)
+ rc = evt.evt.status;
+
+ kfree(cmd);
+
+ return rc;
+}
+
static int wil_cfg80211_set_channel(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef)
{
@@ -402,6 +526,41 @@ static int wil_cfg80211_set_default_key(struct wiphy *wiphy,
return 0;
}
+static int wil_remain_on_channel(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct ieee80211_channel *chan,
+ unsigned int duration,
+ u64 *cookie)
+{
+ struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ int rc;
+
+ /* TODO: handle duration */
+ wil_info(wil, "%s(%d, %d ms)\n", __func__, chan->center_freq, duration);
+
+ rc = wmi_set_channel(wil, chan->hw_value);
+ if (rc)
+ return rc;
+
+ rc = wmi_rxon(wil, true);
+
+ return rc;
+}
+
+static int wil_cancel_remain_on_channel(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ u64 cookie)
+{
+ struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ int rc;
+
+ wil_info(wil, "%s()\n", __func__);
+
+ rc = wmi_rxon(wil, false);
+
+ return rc;
+}
+
static int wil_fix_bcon(struct wil6210_priv *wil,
struct cfg80211_beacon_data *bcon)
{
@@ -450,18 +609,20 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
if (wil_fix_bcon(wil, bcon))
wil_dbg_misc(wil, "Fixed bcon\n");
+ mutex_lock(&wil->mutex);
+
rc = wil_reset(wil);
if (rc)
- return rc;
+ goto out;
/* Rx VRING. */
rc = wil_rx_init(wil);
if (rc)
- return rc;
+ goto out;
rc = wmi_set_ssid(wil, info->ssid_len, info->ssid);
if (rc)
- return rc;
+ goto out;
/* MAC address - pre-requisite for other commands */
wmi_set_mac_address(wil, ndev->dev_addr);
@@ -485,11 +646,13 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype,
channel->hw_value);
if (rc)
- return rc;
+ goto out;
netif_carrier_on(ndev);
+out:
+ mutex_unlock(&wil->mutex);
return rc;
}
@@ -499,17 +662,36 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
int rc = 0;
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ mutex_lock(&wil->mutex);
+
rc = wmi_pcp_stop(wil);
+ mutex_unlock(&wil->mutex);
return rc;
}
+static int wil_cfg80211_del_station(struct wiphy *wiphy,
+ struct net_device *dev, u8 *mac)
+{
+ struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+
+ mutex_lock(&wil->mutex);
+ wil6210_disconnect(wil, mac);
+ mutex_unlock(&wil->mutex);
+
+ return 0;
+}
+
static struct cfg80211_ops wil_cfg80211_ops = {
.scan = wil_cfg80211_scan,
.connect = wil_cfg80211_connect,
.disconnect = wil_cfg80211_disconnect,
.change_virtual_intf = wil_cfg80211_change_iface,
.get_station = wil_cfg80211_get_station,
+ .dump_station = wil_cfg80211_dump_station,
+ .remain_on_channel = wil_remain_on_channel,
+ .cancel_remain_on_channel = wil_cancel_remain_on_channel,
+ .mgmt_tx = wil_cfg80211_mgmt_tx,
.set_monitor_channel = wil_cfg80211_set_channel,
.add_key = wil_cfg80211_add_key,
.del_key = wil_cfg80211_del_key,
@@ -517,6 +699,7 @@ static struct cfg80211_ops wil_cfg80211_ops = {
/* AP mode */
.start_ap = wil_cfg80211_start_ap,
.stop_ap = wil_cfg80211_stop_ap,
+ .del_station = wil_cfg80211_del_station,
};
static void wil_wiphy_init(struct wiphy *wiphy)
@@ -542,7 +725,7 @@ static void wil_wiphy_init(struct wiphy *wiphy)
wiphy->bands[IEEE80211_BAND_60GHZ] = &wil_band_60ghz;
/* TODO: figure this out */
- wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
wiphy->cipher_suites = wil_cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites);
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 1caa31992a7e..ecdabe4adec3 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -26,9 +26,11 @@
/* Nasty hack. Better have per device instances */
static u32 mem_addr;
static u32 dbg_txdesc_index;
+static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */
static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
- const char *name, struct vring *vring)
+ const char *name, struct vring *vring,
+ char _s, char _h)
{
void __iomem *x = wmi_addr(wil, vring->hwtail);
@@ -50,8 +52,8 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
volatile struct vring_tx_desc *d = &vring->va[i].tx;
if ((i % 64) == 0 && (i != 0))
seq_printf(s, "\n");
- seq_printf(s, "%s", (d->dma.status & BIT(0)) ?
- "S" : (vring->ctx[i].skb ? "H" : "h"));
+ seq_printf(s, "%c", (d->dma.status & BIT(0)) ?
+ _s : (vring->ctx[i].skb ? _h : 'h'));
}
seq_printf(s, "\n");
}
@@ -63,14 +65,19 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)
uint i;
struct wil6210_priv *wil = s->private;
- wil_print_vring(s, wil, "rx", &wil->vring_rx);
+ wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_');
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
struct vring *vring = &(wil->vring_tx[i]);
if (vring->va) {
+ int cid = wil->vring2cid_tid[i][0];
+ int tid = wil->vring2cid_tid[i][1];
char name[10];
snprintf(name, sizeof(name), "tx_%2d", i);
- wil_print_vring(s, wil, name, vring);
+
+ seq_printf(s, "\n%pM CID %d TID %d\n",
+ wil->sta[cid].addr, cid, tid);
+ wil_print_vring(s, wil, name, vring, '_', 'H');
}
}
@@ -390,25 +397,78 @@ static const struct file_operations fops_reset = {
.write = wil_write_file_reset,
.open = simple_open,
};
-/*---------Tx descriptor------------*/
+static void wil_seq_hexdump(struct seq_file *s, void *p, int len,
+ const char *prefix)
+{
+ char printbuf[16 * 3 + 2];
+ int i = 0;
+ while (i < len) {
+ int l = min(len - i, 16);
+ hex_dump_to_buffer(p + i, l, 16, 1, printbuf,
+ sizeof(printbuf), false);
+ seq_printf(s, "%s%s\n", prefix, printbuf);
+ i += l;
+ }
+}
+
+static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb)
+{
+ int i = 0;
+ int len = skb_headlen(skb);
+ void *p = skb->data;
+ int nr_frags = skb_shinfo(skb)->nr_frags;
+
+ seq_printf(s, " len = %d\n", len);
+ wil_seq_hexdump(s, p, len, " : ");
+
+ if (nr_frags) {
+ seq_printf(s, " nr_frags = %d\n", nr_frags);
+ for (i = 0; i < nr_frags; i++) {
+ const struct skb_frag_struct *frag =
+ &skb_shinfo(skb)->frags[i];
+
+ len = skb_frag_size(frag);
+ p = skb_frag_address_safe(frag);
+ seq_printf(s, " [%2d] : len = %d\n", i, len);
+ wil_seq_hexdump(s, p, len, " : ");
+ }
+ }
+}
+
+/*---------Tx/Rx descriptor------------*/
static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
{
struct wil6210_priv *wil = s->private;
- struct vring *vring = &(wil->vring_tx[0]);
+ struct vring *vring;
+ bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS);
+ if (tx)
+ vring = &(wil->vring_tx[dbg_vring_index]);
+ else
+ vring = &wil->vring_rx;
if (!vring->va) {
- seq_printf(s, "No Tx VRING\n");
+ if (tx)
+ seq_printf(s, "No Tx[%2d] VRING\n", dbg_vring_index);
+ else
+ seq_puts(s, "No Rx VRING\n");
return 0;
}
if (dbg_txdesc_index < vring->size) {
+ /* use struct vring_tx_desc for Rx as well,
+ * only field used, .dma.length, is the same
+ */
volatile struct vring_tx_desc *d =
&(vring->va[dbg_txdesc_index].tx);
volatile u32 *u = (volatile u32 *)d;
struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb;
- seq_printf(s, "Tx[%3d] = {\n", dbg_txdesc_index);
+ if (tx)
+ seq_printf(s, "Tx[%2d][%3d] = {\n", dbg_vring_index,
+ dbg_txdesc_index);
+ else
+ seq_printf(s, "Rx[%3d] = {\n", dbg_txdesc_index);
seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
u[0], u[1], u[2], u[3]);
seq_printf(s, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
@@ -416,31 +476,19 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
seq_printf(s, " SKB = %p\n", skb);
if (skb) {
- char printbuf[16 * 3 + 2];
- int i = 0;
- int len = le16_to_cpu(d->dma.length);
- void *p = skb->data;
-
- if (len != skb_headlen(skb)) {
- seq_printf(s, "!!! len: desc = %d skb = %d\n",
- len, skb_headlen(skb));
- len = min_t(int, len, skb_headlen(skb));
- }
-
- seq_printf(s, " len = %d\n", len);
-
- while (i < len) {
- int l = min(len - i, 16);
- hex_dump_to_buffer(p + i, l, 16, 1, printbuf,
- sizeof(printbuf), false);
- seq_printf(s, " : %s\n", printbuf);
- i += l;
- }
+ skb_get(skb);
+ wil_seq_print_skb(s, skb);
+ kfree_skb(skb);
}
seq_printf(s, "}\n");
} else {
- seq_printf(s, "TxDesc index (%d) >= size (%d)\n",
- dbg_txdesc_index, vring->size);
+ if (tx)
+ seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n",
+ dbg_vring_index, dbg_txdesc_index,
+ vring->size);
+ else
+ seq_printf(s, "RxDesc index (%d) >= size (%d)\n",
+ dbg_txdesc_index, vring->size);
}
return 0;
@@ -570,6 +618,69 @@ static const struct file_operations fops_temp = {
.llseek = seq_lseek,
};
+/*---------Station matrix------------*/
+static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
+{
+ int i;
+ u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
+ seq_printf(s, "0x%03x [", r->head_seq_num);
+ for (i = 0; i < r->buf_size; i++) {
+ if (i == index)
+ seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|');
+ else
+ seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_');
+ }
+ seq_puts(s, "]\n");
+}
+
+static int wil_sta_debugfs_show(struct seq_file *s, void *data)
+{
+ struct wil6210_priv *wil = s->private;
+ int i, tid;
+
+ for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
+ struct wil_sta_info *p = &wil->sta[i];
+ char *status = "unknown";
+ switch (p->status) {
+ case wil_sta_unused:
+ status = "unused ";
+ break;
+ case wil_sta_conn_pending:
+ status = "pending ";
+ break;
+ case wil_sta_connected:
+ status = "connected";
+ break;
+ }
+ seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status,
+ (p->data_port_open ? " data_port_open" : ""));
+
+ if (p->status == wil_sta_connected) {
+ for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
+ struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
+ if (r) {
+ seq_printf(s, "[%2d] ", tid);
+ wil_print_rxtid(s, r);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int wil_sta_seq_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, wil_sta_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations fops_sta = {
+ .open = wil_sta_seq_open,
+ .release = single_release,
+ .read = seq_read,
+ .llseek = seq_lseek,
+};
+
/*----------------*/
int wil6210_debugfs_init(struct wil6210_priv *wil)
{
@@ -581,9 +692,13 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox);
debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring);
- debugfs_create_file("txdesc", S_IRUGO, dbg, wil, &fops_txdesc);
- debugfs_create_u32("txdesc_index", S_IRUGO | S_IWUSR, dbg,
+ debugfs_create_file("stations", S_IRUGO, dbg, wil, &fops_sta);
+ debugfs_create_file("desc", S_IRUGO, dbg, wil, &fops_txdesc);
+ debugfs_create_u32("desc_index", S_IRUGO | S_IWUSR, dbg,
&dbg_txdesc_index);
+ debugfs_create_u32("vring_index", S_IRUGO | S_IWUSR, dbg,
+ &dbg_vring_index);
+
debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf);
debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid);
debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg,
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 10919f95a83c..5824cd41e4ba 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -195,8 +195,12 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) {
wil_dbg_irq(wil, "RX done\n");
isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE;
- wil_dbg_txrx(wil, "NAPI schedule\n");
- napi_schedule(&wil->napi_rx);
+ if (test_bit(wil_status_reset_done, &wil->status)) {
+ wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
+ napi_schedule(&wil->napi_rx);
+ } else {
+ wil_err(wil, "Got Rx interrupt while in reset\n");
+ }
}
if (isr)
@@ -226,10 +230,15 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) {
wil_dbg_irq(wil, "TX done\n");
- napi_schedule(&wil->napi_tx);
isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE;
/* clear also all VRING interrupts */
isr &= ~(BIT(25) - 1UL);
+ if (test_bit(wil_status_reset_done, &wil->status)) {
+ wil_dbg_txrx(wil, "NAPI(Tx) schedule\n");
+ napi_schedule(&wil->napi_tx);
+ } else {
+ wil_err(wil, "Got Tx interrupt while in reset\n");
+ }
}
if (isr)
@@ -319,6 +328,7 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
if (isr & ISR_MISC_FW_ERROR) {
wil_notify_fw_error(wil);
isr &= ~ISR_MISC_FW_ERROR;
+ wil_fw_error_recovery(wil);
}
if (isr & ISR_MISC_MBOX_EVT) {
@@ -493,6 +503,23 @@ free0:
return rc;
}
+/* can't use wil_ioread32_and_clear because ICC value is not ser yet */
+static inline void wil_clear32(void __iomem *addr)
+{
+ u32 x = ioread32(addr);
+
+ iowrite32(x, addr);
+}
+
+void wil6210_clear_irq(struct wil6210_priv *wil)
+{
+ wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) +
+ offsetof(struct RGF_ICR, ICR));
+ wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) +
+ offsetof(struct RGF_ICR, ICR));
+ wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) +
+ offsetof(struct RGF_ICR, ICR));
+}
int wil6210_init_irq(struct wil6210_priv *wil, int irq)
{
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index fd30cddd5882..95f4efe9ef37 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -16,8 +16,14 @@
#include <linux/moduleparam.h>
#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
#include "wil6210.h"
+#include "txrx.h"
+
+static bool no_fw_recovery;
+module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(no_fw_recovery, " disable FW error recovery");
/*
* Due to a hardware issue,
@@ -52,29 +58,74 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
__raw_writel(*s++, d++);
}
-static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
+static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
{
uint i;
- struct net_device *ndev = wil_to_ndev(wil);
+ struct wil_sta_info *sta = &wil->sta[cid];
- wil_dbg_misc(wil, "%s()\n", __func__);
+ sta->data_port_open = false;
+ if (sta->status != wil_sta_unused) {
+ wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING);
+ sta->status = wil_sta_unused;
+ }
- wil_link_off(wil);
- if (test_bit(wil_status_fwconnected, &wil->status)) {
- clear_bit(wil_status_fwconnected, &wil->status);
- cfg80211_disconnected(ndev,
- WLAN_STATUS_UNSPECIFIED_FAILURE,
- NULL, 0, GFP_KERNEL);
- } else if (test_bit(wil_status_fwconnecting, &wil->status)) {
- cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
- WLAN_STATUS_UNSPECIFIED_FAILURE,
- GFP_KERNEL);
+ for (i = 0; i < WIL_STA_TID_NUM; i++) {
+ struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
+ sta->tid_rx[i] = NULL;
+ wil_tid_ampdu_rx_free(wil, r);
+ }
+ for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
+ if (wil->vring2cid_tid[i][0] == cid)
+ wil_vring_fini_tx(wil, i);
}
- clear_bit(wil_status_fwconnecting, &wil->status);
- for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++)
- wil_vring_fini_tx(wil, i);
+ memset(&sta->stats, 0, sizeof(sta->stats));
+}
- clear_bit(wil_status_dontscan, &wil->status);
+static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
+{
+ int cid = -ENOENT;
+ struct net_device *ndev = wil_to_ndev(wil);
+ struct wireless_dev *wdev = wil->wdev;
+
+ might_sleep();
+ if (bssid) {
+ cid = wil_find_cid(wil, bssid);
+ wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid);
+ } else {
+ wil_dbg_misc(wil, "%s(all)\n", __func__);
+ }
+
+ if (cid >= 0) /* disconnect 1 peer */
+ wil_disconnect_cid(wil, cid);
+ else /* disconnect all */
+ for (cid = 0; cid < WIL6210_MAX_CID; cid++)
+ wil_disconnect_cid(wil, cid);
+
+ /* link state */
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ wil_link_off(wil);
+ if (test_bit(wil_status_fwconnected, &wil->status)) {
+ clear_bit(wil_status_fwconnected, &wil->status);
+ cfg80211_disconnected(ndev,
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ NULL, 0, GFP_KERNEL);
+ } else if (test_bit(wil_status_fwconnecting, &wil->status)) {
+ cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ GFP_KERNEL);
+ }
+ clear_bit(wil_status_fwconnecting, &wil->status);
+ break;
+ default:
+ /* AP-like interface and monitor:
+ * never scan, always connected
+ */
+ if (bssid)
+ cfg80211_del_sta(ndev, bssid, GFP_KERNEL);
+ break;
+ }
}
static void wil_disconnect_worker(struct work_struct *work)
@@ -82,7 +133,9 @@ static void wil_disconnect_worker(struct work_struct *work)
struct wil6210_priv *wil = container_of(work,
struct wil6210_priv, disconnect_worker);
+ mutex_lock(&wil->mutex);
_wil6210_disconnect(wil, NULL);
+ mutex_unlock(&wil->mutex);
}
static void wil_connect_timer_fn(ulong x)
@@ -97,12 +150,55 @@ static void wil_connect_timer_fn(ulong x)
schedule_work(&wil->disconnect_worker);
}
+static void wil_fw_error_worker(struct work_struct *work)
+{
+ struct wil6210_priv *wil = container_of(work,
+ struct wil6210_priv, fw_error_worker);
+ struct wireless_dev *wdev = wil->wdev;
+
+ wil_dbg_misc(wil, "fw error worker\n");
+
+ if (no_fw_recovery)
+ return;
+
+ mutex_lock(&wil->mutex);
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_MONITOR:
+ wil_info(wil, "fw error recovery started...\n");
+ wil_reset(wil);
+
+ /* need to re-allocate Rx ring after reset */
+ wil_rx_init(wil);
+ break;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ /* recovery in these modes is done by upper layers */
+ break;
+ default:
+ break;
+ }
+ mutex_unlock(&wil->mutex);
+}
+
+static int wil_find_free_vring(struct wil6210_priv *wil)
+{
+ int i;
+ for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
+ if (!wil->vring_tx[i].va)
+ return i;
+ }
+ return -EINVAL;
+}
+
static void wil_connect_worker(struct work_struct *work)
{
int rc;
struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
connect_worker);
int cid = wil->pending_connect_cid;
+ int ringid = wil_find_free_vring(wil);
if (cid < 0) {
wil_err(wil, "No connection pending\n");
@@ -111,16 +207,22 @@ static void wil_connect_worker(struct work_struct *work)
wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid);
- rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, cid, 0);
+ rc = wil_vring_init_tx(wil, ringid, WIL6210_TX_RING_SIZE, cid, 0);
wil->pending_connect_cid = -1;
- if (rc == 0)
+ if (rc == 0) {
+ wil->sta[cid].status = wil_sta_connected;
wil_link_on(wil);
+ } else {
+ wil->sta[cid].status = wil_sta_unused;
+ }
}
int wil_priv_init(struct wil6210_priv *wil)
{
wil_dbg_misc(wil, "%s()\n", __func__);
+ memset(wil->sta, 0, sizeof(wil->sta));
+
mutex_init(&wil->mutex);
mutex_init(&wil->wmi_mutex);
@@ -132,6 +234,7 @@ int wil_priv_init(struct wil6210_priv *wil)
INIT_WORK(&wil->connect_worker, wil_connect_worker);
INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
+ INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
INIT_LIST_HEAD(&wil->pending_wmi_ev);
spin_lock_init(&wil->wmi_ev_lock);
@@ -158,7 +261,10 @@ void wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
void wil_priv_deinit(struct wil6210_priv *wil)
{
cancel_work_sync(&wil->disconnect_worker);
+ cancel_work_sync(&wil->fw_error_worker);
+ mutex_lock(&wil->mutex);
wil6210_disconnect(wil, NULL);
+ mutex_unlock(&wil->mutex);
wmi_event_flush(wil);
destroy_workqueue(wil->wmi_wq_conn);
destroy_workqueue(wil->wmi_wq);
@@ -166,40 +272,78 @@ void wil_priv_deinit(struct wil6210_priv *wil)
static void wil_target_reset(struct wil6210_priv *wil)
{
+ int delay = 0;
+ u32 hw_state;
+ u32 rev_id;
+
wil_dbg_misc(wil, "Resetting...\n");
+ /* register read */
+#define R(a) ioread32(wil->csr + HOSTADDR(a))
/* register write */
#define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a))
/* register set = read, OR, write */
-#define S(a, v) iowrite32(ioread32(wil->csr + HOSTADDR(a)) | v, \
- wil->csr + HOSTADDR(a))
+#define S(a, v) W(a, R(a) | v)
+ /* register clear = read, AND with inverted, write */
+#define C(a, v) W(a, R(a) & ~v)
+ wil->hw_version = R(RGF_USER_FW_REV_ID);
+ rev_id = wil->hw_version & 0xff;
/* hpal_perst_from_pad_src_n_mask */
S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6));
/* car_perst_rst_src_n_mask */
S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7));
+ wmb(); /* order is important here */
W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */
W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */
+ wmb(); /* order is important here */
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000170);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00);
+ wmb(); /* order is important here */
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
+ wmb(); /* order is important here */
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001);
- W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080);
+ if (rev_id == 1) {
+ W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080);
+ } else {
+ W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8));
+ W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
+ }
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
+ wmb(); /* order is important here */
+
+ /* wait until device ready */
+ do {
+ msleep(1);
+ hw_state = R(RGF_USER_HW_MACHINE_STATE);
+ if (delay++ > 100) {
+ wil_err(wil, "Reset not completed, hw_state 0x%08x\n",
+ hw_state);
+ return;
+ }
+ } while (hw_state != HW_MACHINE_BOOT_DONE);
+
+ if (rev_id == 2)
+ W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8));
+
+ C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
+ wmb(); /* order is important here */
- wil_dbg_misc(wil, "Reset completed\n");
+ wil_dbg_misc(wil, "Reset completed in %d ms\n", delay);
+#undef R
#undef W
#undef S
+#undef C
}
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
@@ -234,11 +378,24 @@ int wil_reset(struct wil6210_priv *wil)
{
int rc;
+ WARN_ON(!mutex_is_locked(&wil->mutex));
+
cancel_work_sync(&wil->disconnect_worker);
wil6210_disconnect(wil, NULL);
+ wil->status = 0; /* prevent NAPI from being scheduled */
+ if (test_bit(wil_status_napi_en, &wil->status)) {
+ napi_synchronize(&wil->napi_rx);
+ }
+
+ if (wil->scan_request) {
+ wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
+ wil->scan_request);
+ cfg80211_scan_done(wil->scan_request, true);
+ wil->scan_request = NULL;
+ }
+
wil6210_disable_irq(wil);
- wil->status = 0;
wmi_event_flush(wil);
@@ -248,6 +405,8 @@ int wil_reset(struct wil6210_priv *wil)
/* TODO: put MAC in reset */
wil_target_reset(wil);
+ wil_rx_fini(wil);
+
/* init after reset */
wil->pending_connect_cid = -1;
reinit_completion(&wil->wmi_ready);
@@ -261,6 +420,11 @@ int wil_reset(struct wil6210_priv *wil)
return rc;
}
+void wil_fw_error_recovery(struct wil6210_priv *wil)
+{
+ wil_dbg_misc(wil, "starting fw error recovery\n");
+ schedule_work(&wil->fw_error_worker);
+}
void wil_link_on(struct wil6210_priv *wil)
{
@@ -288,6 +452,8 @@ static int __wil_up(struct wil6210_priv *wil)
struct wireless_dev *wdev = wil->wdev;
int rc;
+ WARN_ON(!mutex_is_locked(&wil->mutex));
+
rc = wil_reset(wil);
if (rc)
return rc;
@@ -329,6 +495,7 @@ static int __wil_up(struct wil6210_priv *wil)
napi_enable(&wil->napi_rx);
napi_enable(&wil->napi_tx);
+ set_bit(wil_status_napi_en, &wil->status);
return 0;
}
@@ -346,6 +513,9 @@ int wil_up(struct wil6210_priv *wil)
static int __wil_down(struct wil6210_priv *wil)
{
+ WARN_ON(!mutex_is_locked(&wil->mutex));
+
+ clear_bit(wil_status_napi_en, &wil->status);
napi_disable(&wil->napi_rx);
napi_disable(&wil->napi_tx);
@@ -370,3 +540,19 @@ int wil_down(struct wil6210_priv *wil)
return rc;
}
+
+int wil_find_cid(struct wil6210_priv *wil, const u8 *mac)
+{
+ int i;
+ int rc = -ENOENT;
+
+ for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
+ if ((wil->sta[i].status != wil_sta_unused) &&
+ ether_addr_equal(wil->sta[i].addr, mac)) {
+ rc = i;
+ break;
+ }
+ }
+
+ return rc;
+}
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index 717178f09aa8..fdcaeb820e75 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -127,8 +127,9 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
ndev->netdev_ops = &wil_netdev_ops;
ndev->ieee80211_ptr = wdev;
- ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
- ndev->features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
+ ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM |
+ NETIF_F_SG | NETIF_F_GRO;
+ ndev->features |= ndev->hw_features;
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
wdev->netdev = ndev;
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index eeceab39cda2..f1e1bb338d68 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -41,39 +41,41 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
switch (use_msi) {
case 3:
case 1:
+ wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi);
+ break;
case 0:
+ wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n");
break;
default:
- wil_err(wil, "Invalid use_msi=%d, default to 1\n",
- use_msi);
+ wil_err(wil, "Invalid use_msi=%d, default to 1\n", use_msi);
use_msi = 1;
}
- wil->n_msi = use_msi;
- if (wil->n_msi) {
- wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi);
- rc = pci_enable_msi_block(pdev, wil->n_msi);
- if (rc && (wil->n_msi == 3)) {
- wil_err(wil, "3 MSI mode failed, try 1 MSI\n");
- wil->n_msi = 1;
- rc = pci_enable_msi_block(pdev, wil->n_msi);
- }
- if (rc) {
- wil_err(wil, "pci_enable_msi failed, use INTx\n");
- wil->n_msi = 0;
- }
- } else {
- wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n");
+
+ if (use_msi == 3 && pci_enable_msi_range(pdev, 3, 3) < 0) {
+ wil_err(wil, "3 MSI mode failed, try 1 MSI\n");
+ use_msi = 1;
+ }
+
+ if (use_msi == 1 && pci_enable_msi(pdev)) {
+ wil_err(wil, "pci_enable_msi failed, use INTx\n");
+ use_msi = 0;
}
+ wil->n_msi = use_msi;
+
rc = wil6210_init_irq(wil, pdev->irq);
if (rc)
goto stop_master;
/* need reset here to obtain MAC */
+ mutex_lock(&wil->mutex);
rc = wil_reset(wil);
+ mutex_unlock(&wil->mutex);
if (rc)
goto release_irq;
+ wil_info(wil, "HW version: 0x%08x\n", wil->hw_version);
+
return 0;
release_irq:
@@ -151,6 +153,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pci_set_drvdata(pdev, wil);
wil->pdev = pdev;
+ wil6210_clear_irq(wil);
/* FW should raise IRQ when ready */
rc = wil_if_pcie_enable(wil);
if (rc) {
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
new file mode 100644
index 000000000000..d04629fe053f
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -0,0 +1,177 @@
+#include "wil6210.h"
+#include "txrx.h"
+
+#define SEQ_MODULO 0x1000
+#define SEQ_MASK 0xfff
+
+static inline int seq_less(u16 sq1, u16 sq2)
+{
+ return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1);
+}
+
+static inline u16 seq_inc(u16 sq)
+{
+ return (sq + 1) & SEQ_MASK;
+}
+
+static inline u16 seq_sub(u16 sq1, u16 sq2)
+{
+ return (sq1 - sq2) & SEQ_MASK;
+}
+
+static inline int reorder_index(struct wil_tid_ampdu_rx *r, u16 seq)
+{
+ return seq_sub(seq, r->ssn) % r->buf_size;
+}
+
+static void wil_release_reorder_frame(struct wil6210_priv *wil,
+ struct wil_tid_ampdu_rx *r,
+ int index)
+{
+ struct net_device *ndev = wil_to_ndev(wil);
+ struct sk_buff *skb = r->reorder_buf[index];
+
+ if (!skb)
+ goto no_frame;
+
+ /* release the frame from the reorder ring buffer */
+ r->stored_mpdu_num--;
+ r->reorder_buf[index] = NULL;
+ wil_netif_rx_any(skb, ndev);
+
+no_frame:
+ r->head_seq_num = seq_inc(r->head_seq_num);
+}
+
+static void wil_release_reorder_frames(struct wil6210_priv *wil,
+ struct wil_tid_ampdu_rx *r,
+ u16 hseq)
+{
+ int index;
+
+ while (seq_less(r->head_seq_num, hseq)) {
+ index = reorder_index(r, r->head_seq_num);
+ wil_release_reorder_frame(wil, r, index);
+ }
+}
+
+static void wil_reorder_release(struct wil6210_priv *wil,
+ struct wil_tid_ampdu_rx *r)
+{
+ int index = reorder_index(r, r->head_seq_num);
+
+ while (r->reorder_buf[index]) {
+ wil_release_reorder_frame(wil, r, index);
+ index = reorder_index(r, r->head_seq_num);
+ }
+}
+
+void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
+{
+ struct net_device *ndev = wil_to_ndev(wil);
+ struct vring_rx_desc *d = wil_skb_rxdesc(skb);
+ int tid = wil_rxdesc_tid(d);
+ int cid = wil_rxdesc_cid(d);
+ int mid = wil_rxdesc_mid(d);
+ u16 seq = wil_rxdesc_seq(d);
+ struct wil_sta_info *sta = &wil->sta[cid];
+ struct wil_tid_ampdu_rx *r = sta->tid_rx[tid];
+ u16 hseq;
+ int index;
+
+ wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n",
+ mid, cid, tid, seq);
+
+ if (!r) {
+ wil_netif_rx_any(skb, ndev);
+ return;
+ }
+
+ hseq = r->head_seq_num;
+
+ spin_lock(&r->reorder_lock);
+
+ /* frame with out of date sequence number */
+ if (seq_less(seq, r->head_seq_num)) {
+ dev_kfree_skb(skb);
+ goto out;
+ }
+
+ /*
+ * If frame the sequence number exceeds our buffering window
+ * size release some previous frames to make room for this one.
+ */
+ if (!seq_less(seq, r->head_seq_num + r->buf_size)) {
+ hseq = seq_inc(seq_sub(seq, r->buf_size));
+ /* release stored frames up to new head to stack */
+ wil_release_reorder_frames(wil, r, hseq);
+ }
+
+ /* Now the new frame is always in the range of the reordering buffer */
+
+ index = reorder_index(r, seq);
+
+ /* check if we already stored this frame */
+ if (r->reorder_buf[index]) {
+ dev_kfree_skb(skb);
+ goto out;
+ }
+
+ /*
+ * If the current MPDU is in the right order and nothing else
+ * is stored we can process it directly, no need to buffer it.
+ * If it is first but there's something stored, we may be able
+ * to release frames after this one.
+ */
+ if (seq == r->head_seq_num && r->stored_mpdu_num == 0) {
+ r->head_seq_num = seq_inc(r->head_seq_num);
+ wil_netif_rx_any(skb, ndev);
+ goto out;
+ }
+
+ /* put the frame in the reordering buffer */
+ r->reorder_buf[index] = skb;
+ r->reorder_time[index] = jiffies;
+ r->stored_mpdu_num++;
+ wil_reorder_release(wil, r);
+
+out:
+ spin_unlock(&r->reorder_lock);
+}
+
+struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
+ int size, u16 ssn)
+{
+ struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL);
+ if (!r)
+ return NULL;
+
+ r->reorder_buf =
+ kcalloc(size, sizeof(struct sk_buff *), GFP_KERNEL);
+ r->reorder_time =
+ kcalloc(size, sizeof(unsigned long), GFP_KERNEL);
+ if (!r->reorder_buf || !r->reorder_time) {
+ kfree(r->reorder_buf);
+ kfree(r->reorder_time);
+ kfree(r);
+ return NULL;
+ }
+
+ spin_lock_init(&r->reorder_lock);
+ r->ssn = ssn;
+ r->head_seq_num = ssn;
+ r->buf_size = size;
+ r->stored_mpdu_num = 0;
+ return r;
+}
+
+void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
+ struct wil_tid_ampdu_rx *r)
+{
+ if (!r)
+ return;
+ wil_release_reorder_frames(wil, r, r->head_seq_num + r->buf_size);
+ kfree(r->reorder_buf);
+ kfree(r->reorder_time);
+ kfree(r);
+}
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 0b0975d88b43..c8c547457eb4 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -104,6 +104,23 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring)
return 0;
}
+static void wil_txdesc_unmap(struct device *dev, struct vring_tx_desc *d,
+ struct wil_ctx *ctx)
+{
+ dma_addr_t pa = wil_desc_addr(&d->dma.addr);
+ u16 dmalen = le16_to_cpu(d->dma.length);
+ switch (ctx->mapped_as) {
+ case wil_mapped_as_single:
+ dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE);
+ break;
+ case wil_mapped_as_page:
+ dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE);
+ break;
+ default:
+ break;
+ }
+}
+
static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring,
int tx)
{
@@ -122,15 +139,7 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring,
ctx = &vring->ctx[vring->swtail];
*d = *_d;
- pa = wil_desc_addr(&d->dma.addr);
- dmalen = le16_to_cpu(d->dma.length);
- if (vring->ctx[vring->swtail].mapped_as_page) {
- dma_unmap_page(dev, pa, dmalen,
- DMA_TO_DEVICE);
- } else {
- dma_unmap_single(dev, pa, dmalen,
- DMA_TO_DEVICE);
- }
+ wil_txdesc_unmap(dev, d, ctx);
if (ctx->skb)
dev_kfree_skb_any(ctx->skb);
vring->swtail = wil_vring_next_tail(vring);
@@ -344,6 +353,9 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
u16 dmalen;
u8 ftype;
u8 ds_bits;
+ int cid;
+ struct wil_net_stats *stats;
+
BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb));
@@ -383,8 +395,10 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
skb->data, skb_headlen(skb), false);
-
- wil->stats.last_mcs_rx = wil_rxdesc_mcs(d);
+ cid = wil_rxdesc_cid(d);
+ stats = &wil->sta[cid].stats;
+ stats->last_mcs_rx = wil_rxdesc_mcs(d);
+ wil->stats.last_mcs_rx = stats->last_mcs_rx;
/* use radiotap header only if required */
if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
@@ -472,21 +486,28 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count)
* Pass Rx packet to the netif. Update statistics.
* Called in softirq context (NAPI poll).
*/
-static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
+void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
{
- int rc;
+ gro_result_t rc;
+ struct wil6210_priv *wil = ndev_to_wil(ndev);
unsigned int len = skb->len;
+ struct vring_rx_desc *d = wil_skb_rxdesc(skb);
+ int cid = wil_rxdesc_cid(d);
+ struct wil_net_stats *stats = &wil->sta[cid].stats;
skb_orphan(skb);
- rc = netif_receive_skb(skb);
+ rc = napi_gro_receive(&wil->napi_rx, skb);
- if (likely(rc == NET_RX_SUCCESS)) {
+ if (unlikely(rc == GRO_DROP)) {
+ ndev->stats.rx_dropped++;
+ stats->rx_dropped++;
+ wil_dbg_txrx(wil, "Rx drop %d bytes\n", len);
+ } else {
ndev->stats.rx_packets++;
+ stats->rx_packets++;
ndev->stats.rx_bytes += len;
-
- } else {
- ndev->stats.rx_dropped++;
+ stats->rx_bytes += len;
}
}
@@ -515,12 +536,18 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota)
skb->ip_summed = CHECKSUM_UNNECESSARY;
skb->pkt_type = PACKET_OTHERHOST;
skb->protocol = htons(ETH_P_802_2);
-
+ wil_netif_rx_any(skb, ndev);
} else {
+ struct ethhdr *eth = (void *)skb->data;
+
skb->protocol = eth_type_trans(skb, ndev);
+
+ if (is_unicast_ether_addr(eth->h_dest))
+ wil_rx_reorder(wil, skb);
+ else
+ wil_netif_rx_any(skb, ndev);
}
- wil_netif_rx_any(skb, ndev);
}
wil_rx_refill(wil, v->size);
}
@@ -530,6 +557,11 @@ int wil_rx_init(struct wil6210_priv *wil)
struct vring *vring = &wil->vring_rx;
int rc;
+ if (vring->va) {
+ wil_err(wil, "Rx ring already allocated\n");
+ return -EINVAL;
+ }
+
vring->size = WIL6210_RX_RING_SIZE;
rc = wil_vring_alloc(wil, vring);
if (rc)
@@ -570,7 +602,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
.ring_size = cpu_to_le16(size),
},
.ringid = id,
- .cidxtid = (cid & 0xf) | ((tid & 0xf) << 4),
+ .cidxtid = mk_cidxtid(cid, tid),
.encap_trans_type = WMI_VRING_ENC_TYPE_802_3,
.mac_ctrl = 0,
.to_resolution = 0,
@@ -586,6 +618,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
struct wmi_vring_cfg_done_event cmd;
} __packed reply;
struct vring *vring = &wil->vring_tx[id];
+ struct vring_tx_data *txdata = &wil->vring_tx_data[id];
if (vring->va) {
wil_err(wil, "Tx ring [%d] already allocated\n", id);
@@ -593,11 +626,15 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
goto out;
}
+ memset(txdata, 0, sizeof(*txdata));
vring->size = size;
rc = wil_vring_alloc(wil, vring);
if (rc)
goto out;
+ wil->vring2cid_tid[id][0] = cid;
+ wil->vring2cid_tid[id][1] = tid;
+
cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd),
@@ -613,6 +650,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
}
vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
+ txdata->enabled = 1;
+
return 0;
out_free:
wil_vring_free(wil, vring, 1);
@@ -625,23 +664,116 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
{
struct vring *vring = &wil->vring_tx[id];
+ WARN_ON(!mutex_is_locked(&wil->mutex));
+
if (!vring->va)
return;
+ /* make sure NAPI won't touch this vring */
+ wil->vring_tx_data[id].enabled = 0;
+ if (test_bit(wil_status_napi_en, &wil->status))
+ napi_synchronize(&wil->napi_tx);
+
wil_vring_free(wil, vring, 1);
}
static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
struct sk_buff *skb)
{
- struct vring *v = &wil->vring_tx[0];
+ int i;
+ struct ethhdr *eth = (void *)skb->data;
+ int cid = wil_find_cid(wil, eth->h_dest);
+
+ if (cid < 0)
+ return NULL;
- if (v->va)
- return v;
+ if (!wil->sta[cid].data_port_open &&
+ (skb->protocol != cpu_to_be16(ETH_P_PAE)))
+ return NULL;
+
+ /* TODO: fix for multiple TID */
+ for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
+ if (wil->vring2cid_tid[i][0] == cid) {
+ struct vring *v = &wil->vring_tx[i];
+ wil_dbg_txrx(wil, "%s(%pM) -> [%d]\n",
+ __func__, eth->h_dest, i);
+ if (v->va) {
+ return v;
+ } else {
+ wil_dbg_txrx(wil, "vring[%d] not valid\n", i);
+ return NULL;
+ }
+ }
+ }
return NULL;
}
+static void wil_set_da_for_vring(struct wil6210_priv *wil,
+ struct sk_buff *skb, int vring_index)
+{
+ struct ethhdr *eth = (void *)skb->data;
+ int cid = wil->vring2cid_tid[vring_index][0];
+ memcpy(eth->h_dest, wil->sta[cid].addr, ETH_ALEN);
+}
+
+static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
+ struct sk_buff *skb);
+/*
+ * Find 1-st vring and return it; set dest address for this vring in skb
+ * duplicate skb and send it to other active vrings
+ */
+static struct vring *wil_tx_bcast(struct wil6210_priv *wil,
+ struct sk_buff *skb)
+{
+ struct vring *v, *v2;
+ struct sk_buff *skb2;
+ int i;
+ u8 cid;
+
+ /* find 1-st vring eligible for data */
+ for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
+ v = &wil->vring_tx[i];
+ if (!v->va)
+ continue;
+
+ cid = wil->vring2cid_tid[i][0];
+ if (!wil->sta[cid].data_port_open)
+ continue;
+
+ goto found;
+ }
+
+ wil_err(wil, "Tx while no vrings active?\n");
+
+ return NULL;
+
+found:
+ wil_dbg_txrx(wil, "BCAST -> ring %d\n", i);
+ wil_set_da_for_vring(wil, skb, i);
+
+ /* find other active vrings and duplicate skb for each */
+ for (i++; i < WIL6210_MAX_TX_RINGS; i++) {
+ v2 = &wil->vring_tx[i];
+ if (!v2->va)
+ continue;
+ cid = wil->vring2cid_tid[i][0];
+ if (!wil->sta[cid].data_port_open)
+ continue;
+
+ skb2 = skb_copy(skb, GFP_ATOMIC);
+ if (skb2) {
+ wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i);
+ wil_set_da_for_vring(wil, skb2, i);
+ wil_tx_vring(wil, v2, skb2);
+ } else {
+ wil_err(wil, "skb_copy failed\n");
+ }
+ }
+
+ return v;
+}
+
static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len,
int vring_index)
{
@@ -667,6 +799,13 @@ static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len,
return 0;
}
+static inline
+void wil_tx_desc_set_nr_frags(struct vring_tx_desc *d, int nr_frags)
+{
+ d->mac.d[2] |= ((nr_frags + 1) <<
+ MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS);
+}
+
static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil,
struct vring_tx_desc *d,
struct sk_buff *skb)
@@ -731,8 +870,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
wil_dbg_txrx(wil, "%s()\n", __func__);
- if (avail < vring->size/8)
- netif_tx_stop_all_queues(wil_to_ndev(wil));
if (avail < 1 + nr_frags) {
wil_err(wil, "Tx ring full. No space for %d fragments\n",
1 + nr_frags);
@@ -740,9 +877,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
}
_d = &(vring->va[i].tx);
- /* FIXME FW can accept only unicast frames for the peer */
- memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN);
-
pa = dma_map_single(dev, skb->data,
skb_headlen(skb), DMA_TO_DEVICE);
@@ -753,6 +887,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
if (unlikely(dma_mapping_error(dev, pa)))
return -EINVAL;
+ vring->ctx[i].mapped_as = wil_mapped_as_single;
/* 1-st segment */
wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index);
/* Process TCP/UDP checksum offloading */
@@ -762,8 +897,8 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
goto dma_error;
}
- d->mac.d[2] |= ((nr_frags + 1) <<
- MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS);
+ vring->ctx[i].nr_frags = nr_frags;
+ wil_tx_desc_set_nr_frags(d, nr_frags);
if (nr_frags)
*_d = *d;
@@ -778,8 +913,13 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(dev, pa)))
goto dma_error;
+ vring->ctx[i].mapped_as = wil_mapped_as_page;
wil_tx_desc_map(d, pa, len, vring_index);
- vring->ctx[i].mapped_as_page = 1;
+ /* no need to check return code -
+ * if it succeeded for 1-st descriptor,
+ * it will succeed here too
+ */
+ wil_tx_desc_offload_cksum_set(wil, d, skb);
*_d = *d;
}
/* for the last seg only */
@@ -808,7 +948,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
/* unmap what we have mapped */
nr_frags = f + 1; /* frags mapped + one for skb head */
for (f = 0; f < nr_frags; f++) {
- u16 dmalen;
struct wil_ctx *ctx;
i = (swhead + f) % vring->size;
@@ -816,12 +955,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
_d = &(vring->va[i].tx);
*d = *_d;
_d->dma.status = TX_DMA_STATUS_DU;
- pa = wil_desc_addr(&d->dma.addr);
- dmalen = le16_to_cpu(d->dma.length);
- if (ctx->mapped_as_page)
- dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE);
- else
- dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE);
+ wil_txdesc_unmap(dev, d, ctx);
if (ctx->skb)
dev_kfree_skb_any(ctx->skb);
@@ -836,12 +970,17 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
+ struct ethhdr *eth = (void *)skb->data;
struct vring *vring;
+ static bool pr_once_fw;
int rc;
wil_dbg_txrx(wil, "%s()\n", __func__);
if (!test_bit(wil_status_fwready, &wil->status)) {
- wil_err(wil, "FW not ready\n");
+ if (!pr_once_fw) {
+ wil_err(wil, "FW not ready\n");
+ pr_once_fw = true;
+ }
goto drop;
}
if (!test_bit(wil_status_fwconnected, &wil->status)) {
@@ -852,16 +991,25 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
wil_err(wil, "Xmit in monitor mode not supported\n");
goto drop;
}
+ pr_once_fw = false;
/* find vring */
- vring = wil_find_tx_vring(wil, skb);
+ if (is_unicast_ether_addr(eth->h_dest)) {
+ vring = wil_find_tx_vring(wil, skb);
+ } else {
+ vring = wil_tx_bcast(wil, skb);
+ }
if (!vring) {
- wil_err(wil, "No Tx VRING available\n");
+ wil_err(wil, "No Tx VRING found for %pM\n", eth->h_dest);
goto drop;
}
/* set up vring entry */
rc = wil_tx_vring(wil, vring, skb);
+ /* do we still have enough room in the vring? */
+ if (wil_vring_avail_tx(vring) < vring->size/8)
+ netif_tx_stop_all_queues(wil_to_ndev(wil));
+
switch (rc) {
case 0:
/* statistics will be updated on the tx_complete */
@@ -891,64 +1039,82 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
struct net_device *ndev = wil_to_ndev(wil);
struct device *dev = wil_to_dev(wil);
struct vring *vring = &wil->vring_tx[ringid];
+ struct vring_tx_data *txdata = &wil->vring_tx_data[ringid];
int done = 0;
+ int cid = wil->vring2cid_tid[ringid][0];
+ struct wil_net_stats *stats = &wil->sta[cid].stats;
+ volatile struct vring_tx_desc *_d;
if (!vring->va) {
wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid);
return 0;
}
+ if (!txdata->enabled) {
+ wil_info(wil, "Tx irq[%d]: vring disabled\n", ringid);
+ return 0;
+ }
+
wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid);
while (!wil_vring_is_empty(vring)) {
- volatile struct vring_tx_desc *_d =
- &vring->va[vring->swtail].tx;
- struct vring_tx_desc dd, *d = &dd;
- dma_addr_t pa;
- u16 dmalen;
+ int new_swtail;
struct wil_ctx *ctx = &vring->ctx[vring->swtail];
- struct sk_buff *skb = ctx->skb;
-
- *d = *_d;
+ /**
+ * For the fragmented skb, HW will set DU bit only for the
+ * last fragment. look for it
+ */
+ int lf = (vring->swtail + ctx->nr_frags) % vring->size;
+ /* TODO: check we are not past head */
- if (!(d->dma.status & TX_DMA_STATUS_DU))
+ _d = &vring->va[lf].tx;
+ if (!(_d->dma.status & TX_DMA_STATUS_DU))
break;
- dmalen = le16_to_cpu(d->dma.length);
- trace_wil6210_tx_done(ringid, vring->swtail, dmalen,
- d->dma.error);
- wil_dbg_txrx(wil,
- "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n",
- vring->swtail, dmalen, d->dma.status,
- d->dma.error);
- wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4,
- (const void *)d, sizeof(*d), false);
-
- pa = wil_desc_addr(&d->dma.addr);
- if (ctx->mapped_as_page)
- dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE);
- else
- dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE);
-
- if (skb) {
- if (d->dma.error == 0) {
- ndev->stats.tx_packets++;
- ndev->stats.tx_bytes += skb->len;
- } else {
- ndev->stats.tx_errors++;
- }
+ new_swtail = (lf + 1) % vring->size;
+ while (vring->swtail != new_swtail) {
+ struct vring_tx_desc dd, *d = &dd;
+ u16 dmalen;
+ struct wil_ctx *ctx = &vring->ctx[vring->swtail];
+ struct sk_buff *skb = ctx->skb;
+ _d = &vring->va[vring->swtail].tx;
+
+ *d = *_d;
+
+ dmalen = le16_to_cpu(d->dma.length);
+ trace_wil6210_tx_done(ringid, vring->swtail, dmalen,
+ d->dma.error);
+ wil_dbg_txrx(wil,
+ "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n",
+ vring->swtail, dmalen, d->dma.status,
+ d->dma.error);
+ wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4,
+ (const void *)d, sizeof(*d), false);
+
+ wil_txdesc_unmap(dev, d, ctx);
+
+ if (skb) {
+ if (d->dma.error == 0) {
+ ndev->stats.tx_packets++;
+ stats->tx_packets++;
+ ndev->stats.tx_bytes += skb->len;
+ stats->tx_bytes += skb->len;
+ } else {
+ ndev->stats.tx_errors++;
+ stats->tx_errors++;
+ }
- dev_kfree_skb_any(skb);
+ dev_kfree_skb_any(skb);
+ }
+ memset(ctx, 0, sizeof(*ctx));
+ /* There is no need to touch HW descriptor:
+ * - ststus bit TX_DMA_STATUS_DU is set by design,
+ * so hardware will not try to process this desc.,
+ * - rest of descriptor will be initialized on Tx.
+ */
+ vring->swtail = wil_vring_next_tail(vring);
+ done++;
}
- memset(ctx, 0, sizeof(*ctx));
- /*
- * There is no need to touch HW descriptor:
- * - ststus bit TX_DMA_STATUS_DU is set by design,
- * so hardware will not try to process this desc.,
- * - rest of descriptor will be initialized on Tx.
- */
- vring->swtail = wil_vring_next_tail(vring);
- done++;
}
if (wil_vring_avail_tx(vring) > vring->size/4)
netif_tx_wake_all_queues(wil_to_ndev(wil));
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
index b3828279204c..bc5706a4f007 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.h
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -436,4 +436,11 @@ static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb)
return (void *)skb->cb;
}
+void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev);
+void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb);
+struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
+ int size, u16 ssn);
+void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
+ struct wil_tid_ampdu_rx *r);
+
#endif /* WIL6210_TXRX_H */
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 1f91eaf95bbe..2a2dec75f026 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -74,23 +74,21 @@ struct RGF_ICR {
} __packed;
/* registers - FW addresses */
-#define RGF_USER_USER_SCRATCH_PAD (0x8802bc)
-#define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */
- #define BIT_USER_USER_ICR_SW_INT_2 BIT(18)
-#define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14)
-#define RGF_USER_MAC_CPU_0 (0x8801fc)
+#define RGF_USER_HW_MACHINE_STATE (0x8801dc)
+ #define HW_MACHINE_BOOT_DONE (0x3fffffd)
#define RGF_USER_USER_CPU_0 (0x8801e0)
+#define RGF_USER_MAC_CPU_0 (0x8801fc)
+#define RGF_USER_USER_SCRATCH_PAD (0x8802bc)
+#define RGF_USER_FW_REV_ID (0x880a8c) /* chip revision */
+#define RGF_USER_CLKS_CTL_0 (0x880abc)
+ #define BIT_USER_CLKS_RST_PWGD BIT(11) /* reset on "power good" */
#define RGF_USER_CLKS_CTL_SW_RST_VEC_0 (0x880b04)
#define RGF_USER_CLKS_CTL_SW_RST_VEC_1 (0x880b08)
#define RGF_USER_CLKS_CTL_SW_RST_VEC_2 (0x880b0c)
#define RGF_USER_CLKS_CTL_SW_RST_VEC_3 (0x880b10)
-
-#define RGF_DMA_PSEUDO_CAUSE (0x881c68)
-#define RGF_DMA_PSEUDO_CAUSE_MASK_SW (0x881c6c)
-#define RGF_DMA_PSEUDO_CAUSE_MASK_FW (0x881c70)
- #define BIT_DMA_PSEUDO_CAUSE_RX BIT(0)
- #define BIT_DMA_PSEUDO_CAUSE_TX BIT(1)
- #define BIT_DMA_PSEUDO_CAUSE_MISC BIT(2)
+#define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14)
+#define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */
+ #define BIT_USER_USER_ICR_SW_INT_2 BIT(18)
#define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */
#define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0)
@@ -105,13 +103,22 @@ struct RGF_ICR {
/* Interrupt moderation control */
#define RGF_DMA_ITR_CNT_TRSH (0x881c5c)
#define RGF_DMA_ITR_CNT_DATA (0x881c60)
-#define RGF_DMA_ITR_CNT_CRL (0x881C64)
+#define RGF_DMA_ITR_CNT_CRL (0x881c64)
#define BIT_DMA_ITR_CNT_CRL_EN BIT(0)
#define BIT_DMA_ITR_CNT_CRL_EXT_TICK BIT(1)
#define BIT_DMA_ITR_CNT_CRL_FOREVER BIT(2)
#define BIT_DMA_ITR_CNT_CRL_CLR BIT(3)
#define BIT_DMA_ITR_CNT_CRL_REACH_TRSH BIT(4)
+#define RGF_DMA_PSEUDO_CAUSE (0x881c68)
+#define RGF_DMA_PSEUDO_CAUSE_MASK_SW (0x881c6c)
+#define RGF_DMA_PSEUDO_CAUSE_MASK_FW (0x881c70)
+ #define BIT_DMA_PSEUDO_CAUSE_RX BIT(0)
+ #define BIT_DMA_PSEUDO_CAUSE_TX BIT(1)
+ #define BIT_DMA_PSEUDO_CAUSE_MISC BIT(2)
+
+#define RGF_PCIE_LOS_COUNTER_CTL (0x882dc4)
+
/* popular locations */
#define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD)
#define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \
@@ -125,6 +132,31 @@ struct RGF_ICR {
/* Hardware definitions end */
+/**
+ * mk_cidxtid - construct @cidxtid field
+ * @cid: CID value
+ * @tid: TID value
+ *
+ * @cidxtid field encoded as bits 0..3 - CID; 4..7 - TID
+ */
+static inline u8 mk_cidxtid(u8 cid, u8 tid)
+{
+ return ((tid & 0xf) << 4) | (cid & 0xf);
+}
+
+/**
+ * parse_cidxtid - parse @cidxtid field
+ * @cid: store CID value here
+ * @tid: store TID value here
+ *
+ * @cidxtid field encoded as bits 0..3 - CID; 4..7 - TID
+ */
+static inline void parse_cidxtid(u8 cidxtid, u8 *cid, u8 *tid)
+{
+ *cid = cidxtid & 0xf;
+ *tid = (cidxtid >> 4) & 0xf;
+}
+
struct wil6210_mbox_ring {
u32 base;
u16 entry_size; /* max. size of mbox entry, incl. all headers */
@@ -184,12 +216,19 @@ struct pending_wmi_event {
} __packed event;
};
+enum { /* for wil_ctx.mapped_as */
+ wil_mapped_as_none = 0,
+ wil_mapped_as_single = 1,
+ wil_mapped_as_page = 2,
+};
+
/**
* struct wil_ctx - software context for Vring descriptor
*/
struct wil_ctx {
struct sk_buff *skb;
- u8 mapped_as_page:1;
+ u8 nr_frags;
+ u8 mapped_as;
};
union vring_desc;
@@ -204,6 +243,14 @@ struct vring {
struct wil_ctx *ctx; /* ctx[size] - software context */
};
+/**
+ * Additional data for Tx Vring
+ */
+struct vring_tx_data {
+ int enabled;
+
+};
+
enum { /* for wil6210_priv.status */
wil_status_fwready = 0,
wil_status_fwconnecting,
@@ -211,10 +258,51 @@ enum { /* for wil6210_priv.status */
wil_status_dontscan,
wil_status_reset_done,
wil_status_irqen, /* FIXME: interrupts enabled - for debug */
+ wil_status_napi_en, /* NAPI enabled protected by wil->mutex */
};
struct pci_dev;
+/**
+ * struct tid_ampdu_rx - TID aggregation information (Rx).
+ *
+ * @reorder_buf: buffer to reorder incoming aggregated MPDUs
+ * @reorder_time: jiffies when skb was added
+ * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
+ * @reorder_timer: releases expired frames from the reorder buffer.
+ * @last_rx: jiffies of last rx activity
+ * @head_seq_num: head sequence number in reordering buffer.
+ * @stored_mpdu_num: number of MPDUs in reordering buffer
+ * @ssn: Starting Sequence Number expected to be aggregated.
+ * @buf_size: buffer size for incoming A-MPDUs
+ * @timeout: reset timer value (in TUs).
+ * @dialog_token: dialog token for aggregation session
+ * @rcu_head: RCU head used for freeing this struct
+ * @reorder_lock: serializes access to reorder buffer, see below.
+ *
+ * This structure's lifetime is managed by RCU, assignments to
+ * the array holding it must hold the aggregation mutex.
+ *
+ * The @reorder_lock is used to protect the members of this
+ * struct, except for @timeout, @buf_size and @dialog_token,
+ * which are constant across the lifetime of the struct (the
+ * dialog token being used only for debugging).
+ */
+struct wil_tid_ampdu_rx {
+ spinlock_t reorder_lock; /* see above */
+ struct sk_buff **reorder_buf;
+ unsigned long *reorder_time;
+ struct timer_list session_timer;
+ struct timer_list reorder_timer;
+ unsigned long last_rx;
+ u16 head_seq_num;
+ u16 stored_mpdu_num;
+ u16 ssn;
+ u16 buf_size;
+ u16 timeout;
+ u8 dialog_token;
+};
+
struct wil6210_stats {
u64 tsf;
u32 snr;
@@ -226,6 +314,43 @@ struct wil6210_stats {
u16 peer_tx_sector;
};
+enum wil_sta_status {
+ wil_sta_unused = 0,
+ wil_sta_conn_pending = 1,
+ wil_sta_connected = 2,
+};
+
+#define WIL_STA_TID_NUM (16)
+
+struct wil_net_stats {
+ unsigned long rx_packets;
+ unsigned long tx_packets;
+ unsigned long rx_bytes;
+ unsigned long tx_bytes;
+ unsigned long tx_errors;
+ unsigned long rx_dropped;
+ u16 last_mcs_rx;
+};
+
+/**
+ * struct wil_sta_info - data for peer
+ *
+ * Peer identified by its CID (connection ID)
+ * NIC performs beam forming for each peer;
+ * if no beam forming done, frame exchange is not
+ * possible.
+ */
+struct wil_sta_info {
+ u8 addr[ETH_ALEN];
+ enum wil_sta_status status;
+ struct wil_net_stats stats;
+ bool data_port_open; /* can send any data, not only EAPOL */
+ /* Rx BACK */
+ struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM];
+ unsigned long tid_rx_timer_expired[BITS_TO_LONGS(WIL_STA_TID_NUM)];
+ unsigned long tid_rx_stop_requested[BITS_TO_LONGS(WIL_STA_TID_NUM)];
+};
+
struct wil6210_priv {
struct pci_dev *pdev;
int n_msi;
@@ -233,6 +358,7 @@ struct wil6210_priv {
void __iomem *csr;
ulong status;
u32 fw_version;
+ u32 hw_version;
u8 n_mids; /* number of additional MIDs as reported by FW */
/* profile */
u32 monitor_flags;
@@ -253,6 +379,7 @@ struct wil6210_priv {
struct workqueue_struct *wmi_wq_conn; /* for connect worker */
struct work_struct connect_worker;
struct work_struct disconnect_worker;
+ struct work_struct fw_error_worker; /* for FW error recovery */
struct timer_list connect_timer;
int pending_connect_cid;
struct list_head pending_wmi_ev;
@@ -267,7 +394,9 @@ struct wil6210_priv {
/* DMA related */
struct vring vring_rx;
struct vring vring_tx[WIL6210_MAX_TX_RINGS];
- u8 dst_addr[WIL6210_MAX_TX_RINGS][ETH_ALEN];
+ struct vring_tx_data vring_tx_data[WIL6210_MAX_TX_RINGS];
+ u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */
+ struct wil_sta_info sta[WIL6210_MAX_CID];
/* scan */
struct cfg80211_scan_request *scan_request;
@@ -329,11 +458,13 @@ void wil_if_remove(struct wil6210_priv *wil);
int wil_priv_init(struct wil6210_priv *wil);
void wil_priv_deinit(struct wil6210_priv *wil);
int wil_reset(struct wil6210_priv *wil);
+void wil_fw_error_recovery(struct wil6210_priv *wil);
void wil_link_on(struct wil6210_priv *wil);
void wil_link_off(struct wil6210_priv *wil);
int wil_up(struct wil6210_priv *wil);
int wil_down(struct wil6210_priv *wil);
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
+int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr);
void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
@@ -357,8 +488,11 @@ int wmi_echo(struct wil6210_priv *wil);
int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie);
int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
int wmi_p2p_cfg(struct wil6210_priv *wil, int channel);
+int wmi_rxon(struct wil6210_priv *wil, bool on);
int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
+int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason);
+void wil6210_clear_irq(struct wil6210_priv *wil);
int wil6210_init_irq(struct wil6210_priv *wil, int irq);
void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
void wil6210_disable_irq(struct wil6210_priv *wil);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 063963ee422a..2ba56eef0c45 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -307,14 +307,14 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
u32 freq = ieee80211_channel_to_frequency(ch_no,
IEEE80211_BAND_60GHZ);
struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq);
- /* TODO convert LE to CPU */
- s32 signal = 0; /* TODO */
+ s32 signal = data->info.sqi;
__le16 fc = rx_mgmt_frame->frame_control;
u32 d_len = le32_to_cpu(data->info.len);
u16 d_status = le16_to_cpu(data->info.status);
- wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d\n",
- data->info.channel, data->info.mcs, data->info.snr);
+ wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d SQI %d%%\n",
+ data->info.channel, data->info.mcs, data->info.snr,
+ data->info.sqi);
wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len,
le16_to_cpu(fc));
wil_dbg_wmi(wil, "qid %d mid %d cid %d\n",
@@ -384,6 +384,11 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
evt->assoc_req_len, evt->assoc_resp_len);
return;
}
+ if (evt->cid >= WIL6210_MAX_CID) {
+ wil_err(wil, "Connect CID invalid : %d\n", evt->cid);
+ return;
+ }
+
ch = evt->channel + 1;
wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n",
evt->bssid, ch, evt->cid);
@@ -439,7 +444,8 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
/* FIXME FW can transmit only ucast frames to peer */
/* FIXME real ring_id instead of hard coded 0 */
- memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN);
+ memcpy(wil->sta[evt->cid].addr, evt->bssid, ETH_ALEN);
+ wil->sta[evt->cid].status = wil_sta_conn_pending;
wil->pending_connect_cid = evt->cid;
queue_work(wil->wmi_wq_conn, &wil->connect_worker);
@@ -456,7 +462,9 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
wil->sinfo_gen++;
+ mutex_lock(&wil->mutex);
wil6210_disconnect(wil, evt->bssid);
+ mutex_unlock(&wil->mutex);
}
static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len)
@@ -476,11 +484,11 @@ static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len)
wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector);
wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector);
wil_dbg_wmi(wil, "Link status, MCS %d TSF 0x%016llx\n"
- "BF status 0x%08x SNR 0x%08x\n"
+ "BF status 0x%08x SNR 0x%08x SQI %d%%\n"
"Tx Tpt %d goodput %d Rx goodput %d\n"
"Sectors(rx:tx) my %d:%d peer %d:%d\n",
wil->stats.bf_mcs, wil->stats.tsf, evt->status,
- wil->stats.snr, le32_to_cpu(evt->tx_tpt),
+ wil->stats.snr, evt->sqi, le32_to_cpu(evt->tx_tpt),
le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput),
wil->stats.my_rx_sector, wil->stats.my_tx_sector,
wil->stats.peer_rx_sector, wil->stats.peer_tx_sector);
@@ -499,10 +507,16 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
int sz = eapol_len + ETH_HLEN;
struct sk_buff *skb;
struct ethhdr *eth;
+ int cid;
+ struct wil_net_stats *stats = NULL;
wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len,
evt->src_mac);
+ cid = wil_find_cid(wil, evt->src_mac);
+ if (cid >= 0)
+ stats = &wil->sta[cid].stats;
+
if (eapol_len > 196) { /* TODO: revisit size limit */
wil_err(wil, "EAPOL too large\n");
return;
@@ -513,6 +527,7 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
wil_err(wil, "Failed to allocate skb\n");
return;
}
+
eth = (struct ethhdr *)skb_put(skb, ETH_HLEN);
memcpy(eth->h_dest, ndev->dev_addr, ETH_ALEN);
memcpy(eth->h_source, evt->src_mac, ETH_ALEN);
@@ -521,9 +536,15 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
skb->protocol = eth_type_trans(skb, ndev);
if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) {
ndev->stats.rx_packets++;
- ndev->stats.rx_bytes += skb->len;
+ ndev->stats.rx_bytes += sz;
+ if (stats) {
+ stats->rx_packets++;
+ stats->rx_bytes += sz;
+ }
} else {
ndev->stats.rx_dropped++;
+ if (stats)
+ stats->rx_dropped++;
}
}
@@ -531,9 +552,16 @@ static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len)
{
struct net_device *ndev = wil_to_ndev(wil);
struct wmi_data_port_open_event *evt = d;
+ u8 cid = evt->cid;
- wil_dbg_wmi(wil, "Link UP for CID %d\n", evt->cid);
+ wil_dbg_wmi(wil, "Link UP for CID %d\n", cid);
+ if (cid >= ARRAY_SIZE(wil->sta)) {
+ wil_err(wil, "Link UP for invalid CID %d\n", cid);
+ return;
+ }
+
+ wil->sta[cid].data_port_open = true;
netif_carrier_on(ndev);
}
@@ -541,10 +569,17 @@ static void wmi_evt_linkdown(struct wil6210_priv *wil, int id, void *d, int len)
{
struct net_device *ndev = wil_to_ndev(wil);
struct wmi_wbe_link_down_event *evt = d;
+ u8 cid = evt->cid;
wil_dbg_wmi(wil, "Link DOWN for CID %d, reason %d\n",
- evt->cid, le32_to_cpu(evt->reason));
+ cid, le32_to_cpu(evt->reason));
+
+ if (cid >= ARRAY_SIZE(wil->sta)) {
+ wil_err(wil, "Link DOWN for invalid CID %d\n", cid);
+ return;
+ }
+ wil->sta[cid].data_port_open = false;
netif_carrier_off(ndev);
}
@@ -552,10 +587,42 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
int len)
{
struct wmi_vring_ba_status_event *evt = d;
+ struct wil_sta_info *sta;
+ uint i, cid;
+
+ /* TODO: use Rx BA status, not Tx one */
wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n",
- evt->ringid, evt->status ? "N/A" : "OK", evt->agg_wsize,
- __le16_to_cpu(evt->ba_timeout));
+ evt->ringid,
+ evt->status == WMI_BA_AGREED ? "OK" : "N/A",
+ evt->agg_wsize, __le16_to_cpu(evt->ba_timeout));
+
+ if (evt->ringid >= WIL6210_MAX_TX_RINGS) {
+ wil_err(wil, "invalid ring id %d\n", evt->ringid);
+ return;
+ }
+
+ cid = wil->vring2cid_tid[evt->ringid][0];
+ if (cid >= WIL6210_MAX_CID) {
+ wil_err(wil, "invalid CID %d for vring %d\n", cid, evt->ringid);
+ return;
+ }
+
+ sta = &wil->sta[cid];
+ if (sta->status == wil_sta_unused) {
+ wil_err(wil, "CID %d unused\n", cid);
+ return;
+ }
+
+ wil_dbg_wmi(wil, "BACK for CID %d %pM\n", cid, sta->addr);
+ for (i = 0; i < WIL_STA_TID_NUM; i++) {
+ struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
+ sta->tid_rx[i] = NULL;
+ wil_tid_ampdu_rx_free(wil, r);
+ if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize)
+ sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil,
+ evt->agg_wsize, 0);
+ }
}
static const struct {
@@ -893,6 +960,38 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
return rc;
}
+/**
+ * wmi_rxon - turn radio on/off
+ * @on: turn on if true, off otherwise
+ *
+ * Only switch radio. Channel should be set separately.
+ * No timeout for rxon - radio turned on forever unless some other call
+ * turns it off
+ */
+int wmi_rxon(struct wil6210_priv *wil, bool on)
+{
+ int rc;
+ struct {
+ struct wil6210_mbox_hdr_wmi wmi;
+ struct wmi_listen_started_event evt;
+ } __packed reply;
+
+ wil_info(wil, "%s(%s)\n", __func__, on ? "on" : "off");
+
+ if (on) {
+ rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0,
+ WMI_LISTEN_STARTED_EVENTID,
+ &reply, sizeof(reply), 100);
+ if ((rc == 0) && (reply.evt.status != WMI_FW_STATUS_SUCCESS))
+ rc = -EINVAL;
+ } else {
+ rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0,
+ WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 20);
+ }
+
+ return rc;
+}
+
int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
{
struct wireless_dev *wdev = wil->wdev;
@@ -906,6 +1005,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
},
.mid = 0, /* TODO - what is it? */
.decap_trans_type = WMI_DECAP_TYPE_802_3,
+ .reorder_type = WMI_RX_SW_REORDER,
};
struct {
struct wil6210_mbox_hdr_wmi wmi;
@@ -973,6 +1073,18 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r)
return 0;
}
+int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason)
+{
+ struct wmi_disconnect_sta_cmd cmd = {
+ .disconnect_reason = cpu_to_le16(reason),
+ };
+ memcpy(cmd.dst_mac, mac, ETH_ALEN);
+
+ wil_dbg_wmi(wil, "%s(%pM, reason %d)\n", __func__, mac, reason);
+
+ return wmi_send(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd));
+}
+
void wmi_event_flush(struct wil6210_priv *wil)
{
struct pending_wmi_event *evt, *t;
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index bf93ea859f2d..1fe41af81a59 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -67,7 +67,7 @@
#include <linux/moduleparam.h>
#include <linux/firmware.h>
#include <linux/jiffies.h>
-#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
#include "atmel.h"
#define DRIVER_MAJOR 0
@@ -2273,7 +2273,7 @@ static int atmel_set_freq(struct net_device *dev,
/* Hack to fall through... */
fwrq->e = 0;
- fwrq->m = ieee80211_freq_to_dsss_chan(f);
+ fwrq->m = ieee80211_frequency_to_channel(f);
}
/* Setting by channel number */
if ((fwrq->m > 1000) || (fwrq->e > 0))
@@ -2434,8 +2434,8 @@ static int atmel_get_range(struct net_device *dev,
range->freq[k].i = i; /* List index */
/* Values in MHz -> * 10^5 * 10 */
- range->freq[k].m = (ieee80211_dsss_chan_to_freq(i) *
- 100000);
+ range->freq[k].m = 100000 *
+ ieee80211_channel_to_frequency(i, IEEE80211_BAND_2GHZ);
range->freq[k++].e = 1;
}
range->num_frequency = k;
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index 51ff0b198d0a..088d544ec63f 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -92,7 +92,7 @@ config B43_SDIO
# if we can do DMA.
config B43_BCMA_PIO
bool
- depends on B43_BCMA
+ depends on B43 && B43_BCMA
select BCMA_BLOCKIO
default y
diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h
index 822aad8842f4..50517b801cb4 100644
--- a/drivers/net/wireless/b43/debugfs.h
+++ b/drivers/net/wireless/b43/debugfs.h
@@ -86,7 +86,7 @@ void b43_debugfs_log_txstat(struct b43_wldev *dev,
static inline bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
{
- return 0;
+ return false;
}
static inline void b43_debugfs_init(void)
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index c75237eb55a1..69fc3d65531a 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -1549,7 +1549,7 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon);
bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
- len = min((size_t) dev->wl->current_beacon->len,
+ len = min_t(size_t, dev->wl->current_beacon->len,
0x200 - sizeof(struct b43_plcp_hdr6));
rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h
index abac25ee958d..f476fc337d64 100644
--- a/drivers/net/wireless/b43/main.h
+++ b/drivers/net/wireless/b43/main.h
@@ -58,41 +58,6 @@ enum b43_verbosity {
#endif
};
-
-/* Lightweight function to convert a frequency (in Mhz) to a channel number. */
-static inline u8 b43_freq_to_channel_5ghz(int freq)
-{
- return ((freq - 5000) / 5);
-}
-static inline u8 b43_freq_to_channel_2ghz(int freq)
-{
- u8 channel;
-
- if (freq == 2484)
- channel = 14;
- else
- channel = (freq - 2407) / 5;
-
- return channel;
-}
-
-/* Lightweight function to convert a channel number to a frequency (in Mhz). */
-static inline int b43_channel_to_freq_5ghz(u8 channel)
-{
- return (5000 + (5 * channel));
-}
-static inline int b43_channel_to_freq_2ghz(u8 channel)
-{
- int freq;
-
- if (channel == 14)
- freq = 2484;
- else
- freq = 2407 + (5 * channel);
-
- return freq;
-}
-
static inline int b43_is_cck_rate(int rate)
{
return (rate == B43_CCK_RATE_1MB ||
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index f01676ac481b..dbaa51890198 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -133,9 +133,9 @@ void b43_phy_exit(struct b43_wldev *dev)
bool b43_has_hardware_pctl(struct b43_wldev *dev)
{
if (!dev->phy.hardware_power_control)
- return 0;
+ return false;
if (!dev->phy.ops->supports_hwpctl)
- return 0;
+ return false;
return dev->phy.ops->supports_hwpctl(dev);
}
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c
index a73ff8c9deb5..a4ff5e2a42b9 100644
--- a/drivers/net/wireless/b43/pio.c
+++ b/drivers/net/wireless/b43/pio.c
@@ -637,7 +637,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
ctl = b43_piorx_read32(q, B43_PIO8_RXCTL);
if (!(ctl & B43_PIO8_RXCTL_FRAMERDY))
- return 0;
+ return false;
b43_piorx_write32(q, B43_PIO8_RXCTL,
B43_PIO8_RXCTL_FRAMERDY);
for (i = 0; i < 10; i++) {
@@ -651,7 +651,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
ctl = b43_piorx_read16(q, B43_PIO_RXCTL);
if (!(ctl & B43_PIO_RXCTL_FRAMERDY))
- return 0;
+ return false;
b43_piorx_write16(q, B43_PIO_RXCTL,
B43_PIO_RXCTL_FRAMERDY);
for (i = 0; i < 10; i++) {
@@ -662,7 +662,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
}
}
b43dbg(q->dev->wl, "PIO RX timed out\n");
- return 1;
+ return true;
data_ready:
/* Get the preamble (RX header) */
@@ -759,7 +759,7 @@ data_ready:
b43_rx(q->dev, skb, rxhdr);
- return 1;
+ return true;
rx_error:
if (err_msg)
@@ -769,7 +769,7 @@ rx_error:
else
b43_piorx_write16(q, B43_PIO_RXCTL, B43_PIO_RXCTL_DATARDY);
- return 1;
+ return true;
}
void b43_pio_rx(struct b43_pio_rxqueue *q)
diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c
index 8e8431d4eb0c..3190493bd07f 100644
--- a/drivers/net/wireless/b43/sysfs.c
+++ b/drivers/net/wireless/b43/sysfs.c
@@ -40,7 +40,7 @@ static int get_integer(const char *buf, size_t count)
if (count == 0)
goto out;
- count = min(count, (size_t) 10);
+ count = min_t(size_t, count, 10);
memcpy(tmp, buf, count);
ret = simple_strtol(tmp, NULL, 10);
out:
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index 50e5ddb12fb3..31adb8cf0291 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -337,7 +337,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
/* iv16 */
memcpy(txhdr->iv + 10, ((u8 *) wlhdr) + wlhdr_len, 3);
} else {
- iv_len = min((size_t) info->control.hw_key->iv_len,
+ iv_len = min_t(size_t, info->control.hw_key->iv_len,
ARRAY_SIZE(txhdr->iv));
memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
}
@@ -806,7 +806,8 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
B43_WARN_ON(1);
/* FIXME: We don't really know which value the "chanid" contains.
* So the following assignment might be wrong. */
- status.freq = b43_channel_to_freq_5ghz(chanid);
+ status.freq =
+ ieee80211_channel_to_frequency(chanid, status.band);
break;
case B43_PHYTYPE_G:
status.band = IEEE80211_BAND_2GHZ;
@@ -819,13 +820,12 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
case B43_PHYTYPE_HT:
/* chanid is the SHM channel cookie. Which is the plain
* channel number in b43. */
- if (chanstat & B43_RX_CHAN_5GHZ) {
+ if (chanstat & B43_RX_CHAN_5GHZ)
status.band = IEEE80211_BAND_5GHZ;
- status.freq = b43_channel_to_freq_5ghz(chanid);
- } else {
+ else
status.band = IEEE80211_BAND_2GHZ;
- status.freq = b43_channel_to_freq_2ghz(chanid);
- }
+ status.freq =
+ ieee80211_channel_to_frequency(chanid, status.band);
break;
default:
B43_WARN_ON(1);
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 349c77605231..1aec2146a2bf 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -978,7 +978,7 @@ static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon);
bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
- len = min((size_t)dev->wl->current_beacon->len,
+ len = min_t(size_t, dev->wl->current_beacon->len,
0x200 - sizeof(struct b43legacy_plcp_hdr6));
rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
@@ -1155,7 +1155,7 @@ static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev,
b43legacy_write_probe_resp_plcp(dev, 0x350, size,
&b43legacy_b_ratetable[3]);
- size = min((size_t)size,
+ size = min_t(size_t, size,
0x200 - sizeof(struct b43legacy_plcp_hdr6));
b43legacy_write_template_common(dev, probe_resp_data,
size, ram_offset,
diff --git a/drivers/net/wireless/b43legacy/sysfs.c b/drivers/net/wireless/b43legacy/sysfs.c
index 57f8b089767c..2a1da15c913b 100644
--- a/drivers/net/wireless/b43legacy/sysfs.c
+++ b/drivers/net/wireless/b43legacy/sysfs.c
@@ -42,7 +42,7 @@ static int get_integer(const char *buf, size_t count)
if (count == 0)
goto out;
- count = min(count, (size_t)10);
+ count = min_t(size_t, count, 10);
memcpy(tmp, buf, count);
ret = simple_strtol(tmp, NULL, 10);
out:
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
index 86588c9ff0f2..34bf3f0b729f 100644
--- a/drivers/net/wireless/b43legacy/xmit.c
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -254,7 +254,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
B43legacy_TX4_MAC_KEYALG_SHIFT) &
B43legacy_TX4_MAC_KEYALG;
wlhdr_len = ieee80211_hdrlen(wlhdr->frame_control);
- iv_len = min((size_t)info->control.hw_key->iv_len,
+ iv_len = min_t(size_t, info->control.hw_key->iv_len,
ARRAY_SIZE(txhdr->iv));
memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len);
} else {
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
index 57cddee03252..1d2ceac3a221 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile
+++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
@@ -24,6 +24,7 @@ ccflags-y += -D__CHECK_ENDIAN__
obj-$(CONFIG_BRCMFMAC) += brcmfmac.o
brcmfmac-objs += \
wl_cfg80211.o \
+ chip.o \
fwil.o \
fweh.o \
fwsignal.o \
@@ -36,8 +37,7 @@ brcmfmac-objs += \
btcoex.o
brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
dhd_sdio.o \
- bcmsdh.o \
- sdio_chip.o
+ bcmsdh.o
brcmfmac-$(CONFIG_BRCMFMAC_USB) += \
usb.o
brcmfmac-$(CONFIG_BRCMDBG) += \
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
index fa35b23bbaa7..a16e644e7c08 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
@@ -43,7 +43,6 @@
#include "dhd_bus.h"
#include "dhd_dbg.h"
#include "sdio_host.h"
-#include "sdio_chip.h"
#define SDIOH_API_ACCESS_RETRY_LIMIT 2
@@ -54,6 +53,12 @@
/* Maximum milliseconds to wait for F2 to come up */
#define SDIO_WAIT_F2RDY 3000
+#define BRCMF_DEFAULT_TXGLOM_SIZE 32 /* max tx frames in glom chain */
+#define BRCMF_DEFAULT_RXGLOM_SIZE 32 /* max rx frames in glom chain */
+
+static int brcmf_sdiod_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE;
+module_param_named(txglomsz, brcmf_sdiod_txglomsz, int, 0);
+MODULE_PARM_DESC(txglomsz, "maximum tx packet chain size [SDIO]");
static irqreturn_t brcmf_sdiod_oob_irqhandler(int irq, void *dev_id)
{
@@ -264,26 +269,17 @@ static int brcmf_sdiod_request_data(struct brcmf_sdio_dev *sdiodev, u8 fn,
break;
}
- if (ret) {
- /*
- * SleepCSR register access can fail when
- * waking up the device so reduce this noise
- * in the logs.
- */
- if (addr != SBSDIO_FUNC1_SLEEPCSR)
- brcmf_err("failed to %s data F%d@0x%05x, err: %d\n",
- write ? "write" : "read", fn, addr, ret);
- else
- brcmf_dbg(SDIO, "failed to %s data F%d@0x%05x, err: %d\n",
- write ? "write" : "read", fn, addr, ret);
- }
+ if (ret)
+ brcmf_dbg(SDIO, "failed to %s data F%d@0x%05x, err: %d\n",
+ write ? "write" : "read", fn, addr, ret);
+
return ret;
}
static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
u8 regsz, void *data, bool write)
{
- u8 func_num;
+ u8 func;
s32 retry = 0;
int ret;
@@ -297,9 +293,9 @@ static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
* The rest: function 1 silicon backplane core registers
*/
if ((addr & ~REG_F0_REG_MASK) == 0)
- func_num = SDIO_FUNC_0;
+ func = SDIO_FUNC_0;
else
- func_num = SDIO_FUNC_1;
+ func = SDIO_FUNC_1;
do {
if (!write)
@@ -307,16 +303,26 @@ static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
/* for retry wait for 1 ms till bus get settled down */
if (retry)
usleep_range(1000, 2000);
- ret = brcmf_sdiod_request_data(sdiodev, func_num, addr, regsz,
+ ret = brcmf_sdiod_request_data(sdiodev, func, addr, regsz,
data, write);
} while (ret != 0 && ret != -ENOMEDIUM &&
retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
if (ret == -ENOMEDIUM)
brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_NOMEDIUM);
- else if (ret != 0)
- brcmf_err("failed with %d\n", ret);
-
+ else if (ret != 0) {
+ /*
+ * SleepCSR register access can fail when
+ * waking up the device so reduce this noise
+ * in the logs.
+ */
+ if (addr != SBSDIO_FUNC1_SLEEPCSR)
+ brcmf_err("failed to %s data F%d@0x%05x, err: %d\n",
+ write ? "write" : "read", func, addr, ret);
+ else
+ brcmf_dbg(SDIO, "failed to %s data F%d@0x%05x, err: %d\n",
+ write ? "write" : "read", func, addr, ret);
+ }
return ret;
}
@@ -488,7 +494,6 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
struct mmc_request mmc_req;
struct mmc_command mmc_cmd;
struct mmc_data mmc_dat;
- struct sg_table st;
struct scatterlist *sgl;
int ret = 0;
@@ -533,16 +538,11 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
pkt_offset = 0;
pkt_next = target_list->next;
- if (sg_alloc_table(&st, max_seg_cnt, GFP_KERNEL)) {
- ret = -ENOMEM;
- goto exit;
- }
-
memset(&mmc_req, 0, sizeof(struct mmc_request));
memset(&mmc_cmd, 0, sizeof(struct mmc_command));
memset(&mmc_dat, 0, sizeof(struct mmc_data));
- mmc_dat.sg = st.sgl;
+ mmc_dat.sg = sdiodev->sgtable.sgl;
mmc_dat.blksz = func_blk_sz;
mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
mmc_cmd.opcode = SD_IO_RW_EXTENDED;
@@ -558,7 +558,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
while (seg_sz) {
req_sz = 0;
sg_cnt = 0;
- sgl = st.sgl;
+ sgl = sdiodev->sgtable.sgl;
/* prep sg table */
while (pkt_next != (struct sk_buff *)target_list) {
pkt_data = pkt_next->data + pkt_offset;
@@ -640,7 +640,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
}
exit:
- sg_free_table(&st);
+ sg_init_table(sdiodev->sgtable.sgl, sdiodev->sgtable.orig_nents);
while ((pkt_next = __skb_dequeue(&local_list)) != NULL)
brcmu_pkt_buf_free_skb(pkt_next);
@@ -827,7 +827,7 @@ brcmf_sdiod_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
}
if (!write)
memcpy(data, pkt->data, dsize);
- skb_trim(pkt, dsize);
+ skb_trim(pkt, 0);
/* Adjust for next transfer (if any) */
size -= dsize;
@@ -864,6 +864,29 @@ int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
return 0;
}
+static void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)
+{
+ uint nents;
+ int err;
+
+ if (!sdiodev->sg_support)
+ return;
+
+ nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE, brcmf_sdiod_txglomsz);
+ nents += (nents >> 4) + 1;
+
+ WARN_ON(nents > sdiodev->max_segment_count);
+
+ brcmf_dbg(TRACE, "nents=%d\n", nents);
+ err = sg_alloc_table(&sdiodev->sgtable, nents, GFP_KERNEL);
+ if (err < 0) {
+ brcmf_err("allocation failed: disable scatter-gather");
+ sdiodev->sg_support = false;
+ }
+
+ sdiodev->txglomsz = brcmf_sdiod_txglomsz;
+}
+
static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
{
if (sdiodev->bus) {
@@ -881,6 +904,7 @@ static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
sdio_disable_func(sdiodev->func[1]);
sdio_release_host(sdiodev->func[1]);
+ sg_free_table(&sdiodev->sgtable);
sdiodev->sbwad = 0;
return 0;
@@ -936,6 +960,11 @@ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
SG_MAX_SINGLE_ALLOC);
sdiodev->max_segment_size = host->max_seg_size;
+ /* allocate scatter-gather table. sg support
+ * will be disabled upon allocation failure.
+ */
+ brcmf_sdiod_sgtable_alloc(sdiodev);
+
/* try to attach to the target device */
sdiodev->bus = brcmf_sdio_probe(sdiodev);
if (!sdiodev->bus) {
@@ -960,6 +989,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = {
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43362)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM,
SDIO_DEVICE_ID_BROADCOM_4335_4339)},
+ {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4354)},
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
@@ -1073,9 +1103,7 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
int ret = 0;
- brcmf_dbg(SDIO, "\n");
-
- atomic_set(&sdiodev->suspend, true);
+ brcmf_dbg(SDIO, "Enter\n");
sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]);
if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
@@ -1083,9 +1111,12 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
return -EINVAL;
}
+ atomic_set(&sdiodev->suspend, true);
+
ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER);
if (ret) {
brcmf_err("Failed to set pm_flags\n");
+ atomic_set(&sdiodev->suspend, false);
return ret;
}
@@ -1099,6 +1130,7 @@ static int brcmf_ops_sdio_resume(struct device *dev)
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+ brcmf_dbg(SDIO, "Enter\n");
brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
atomic_set(&sdiodev->suspend, false);
return 0;
@@ -1115,14 +1147,15 @@ static struct sdio_driver brcmf_sdmmc_driver = {
.remove = brcmf_ops_sdio_remove,
.name = BRCMFMAC_SDIO_PDATA_NAME,
.id_table = brcmf_sdmmc_ids,
-#ifdef CONFIG_PM_SLEEP
.drv = {
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM_SLEEP
.pm = &brcmf_sdio_pm_ops,
- },
#endif /* CONFIG_PM_SLEEP */
+ },
};
-static int brcmf_sdio_pd_probe(struct platform_device *pdev)
+static int __init brcmf_sdio_pd_probe(struct platform_device *pdev)
{
brcmf_dbg(SDIO, "Enter\n");
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/brcm80211/brcmfmac/chip.c
new file mode 100644
index 000000000000..df130ef53d1c
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c
@@ -0,0 +1,1034 @@
+/*
+ * Copyright (c) 2014 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/ssb/ssb_regs.h>
+#include <linux/bcma/bcma.h>
+#include <linux/bcma/bcma_regs.h>
+
+#include <defs.h>
+#include <soc.h>
+#include <brcm_hw_ids.h>
+#include <brcmu_utils.h>
+#include <chipcommon.h>
+#include "dhd_dbg.h"
+#include "chip.h"
+
+/* SOC Interconnect types (aka chip types) */
+#define SOCI_SB 0
+#define SOCI_AI 1
+
+/* PL-368 DMP definitions */
+#define DMP_DESC_TYPE_MSK 0x0000000F
+#define DMP_DESC_EMPTY 0x00000000
+#define DMP_DESC_VALID 0x00000001
+#define DMP_DESC_COMPONENT 0x00000001
+#define DMP_DESC_MASTER_PORT 0x00000003
+#define DMP_DESC_ADDRESS 0x00000005
+#define DMP_DESC_ADDRSIZE_GT32 0x00000008
+#define DMP_DESC_EOT 0x0000000F
+
+#define DMP_COMP_DESIGNER 0xFFF00000
+#define DMP_COMP_DESIGNER_S 20
+#define DMP_COMP_PARTNUM 0x000FFF00
+#define DMP_COMP_PARTNUM_S 8
+#define DMP_COMP_CLASS 0x000000F0
+#define DMP_COMP_CLASS_S 4
+#define DMP_COMP_REVISION 0xFF000000
+#define DMP_COMP_REVISION_S 24
+#define DMP_COMP_NUM_SWRAP 0x00F80000
+#define DMP_COMP_NUM_SWRAP_S 19
+#define DMP_COMP_NUM_MWRAP 0x0007C000
+#define DMP_COMP_NUM_MWRAP_S 14
+#define DMP_COMP_NUM_SPORT 0x00003E00
+#define DMP_COMP_NUM_SPORT_S 9
+#define DMP_COMP_NUM_MPORT 0x000001F0
+#define DMP_COMP_NUM_MPORT_S 4
+
+#define DMP_MASTER_PORT_UID 0x0000FF00
+#define DMP_MASTER_PORT_UID_S 8
+#define DMP_MASTER_PORT_NUM 0x000000F0
+#define DMP_MASTER_PORT_NUM_S 4
+
+#define DMP_SLAVE_ADDR_BASE 0xFFFFF000
+#define DMP_SLAVE_ADDR_BASE_S 12
+#define DMP_SLAVE_PORT_NUM 0x00000F00
+#define DMP_SLAVE_PORT_NUM_S 8
+#define DMP_SLAVE_TYPE 0x000000C0
+#define DMP_SLAVE_TYPE_S 6
+#define DMP_SLAVE_TYPE_SLAVE 0
+#define DMP_SLAVE_TYPE_BRIDGE 1
+#define DMP_SLAVE_TYPE_SWRAP 2
+#define DMP_SLAVE_TYPE_MWRAP 3
+#define DMP_SLAVE_SIZE_TYPE 0x00000030
+#define DMP_SLAVE_SIZE_TYPE_S 4
+#define DMP_SLAVE_SIZE_4K 0
+#define DMP_SLAVE_SIZE_8K 1
+#define DMP_SLAVE_SIZE_16K 2
+#define DMP_SLAVE_SIZE_DESC 3
+
+/* EROM CompIdentB */
+#define CIB_REV_MASK 0xff000000
+#define CIB_REV_SHIFT 24
+
+/* ARM CR4 core specific control flag bits */
+#define ARMCR4_BCMA_IOCTL_CPUHALT 0x0020
+
+/* D11 core specific control flag bits */
+#define D11_BCMA_IOCTL_PHYCLOCKEN 0x0004
+#define D11_BCMA_IOCTL_PHYRESET 0x0008
+
+/* chip core base & ramsize */
+/* bcm4329 */
+/* SDIO device core, ID 0x829 */
+#define BCM4329_CORE_BUS_BASE 0x18011000
+/* internal memory core, ID 0x80e */
+#define BCM4329_CORE_SOCRAM_BASE 0x18003000
+/* ARM Cortex M3 core, ID 0x82a */
+#define BCM4329_CORE_ARM_BASE 0x18002000
+#define BCM4329_RAMSIZE 0x48000
+
+/* bcm43143 */
+/* SDIO device core */
+#define BCM43143_CORE_BUS_BASE 0x18002000
+/* internal memory core */
+#define BCM43143_CORE_SOCRAM_BASE 0x18004000
+/* ARM Cortex M3 core, ID 0x82a */
+#define BCM43143_CORE_ARM_BASE 0x18003000
+#define BCM43143_RAMSIZE 0x70000
+
+#define CORE_SB(base, field) \
+ (base + SBCONFIGOFF + offsetof(struct sbconfig, field))
+#define SBCOREREV(sbidh) \
+ ((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \
+ ((sbidh) & SSB_IDHIGH_RCLO))
+
+struct sbconfig {
+ u32 PAD[2];
+ u32 sbipsflag; /* initiator port ocp slave flag */
+ u32 PAD[3];
+ u32 sbtpsflag; /* target port ocp slave flag */
+ u32 PAD[11];
+ u32 sbtmerrloga; /* (sonics >= 2.3) */
+ u32 PAD;
+ u32 sbtmerrlog; /* (sonics >= 2.3) */
+ u32 PAD[3];
+ u32 sbadmatch3; /* address match3 */
+ u32 PAD;
+ u32 sbadmatch2; /* address match2 */
+ u32 PAD;
+ u32 sbadmatch1; /* address match1 */
+ u32 PAD[7];
+ u32 sbimstate; /* initiator agent state */
+ u32 sbintvec; /* interrupt mask */
+ u32 sbtmstatelow; /* target state */
+ u32 sbtmstatehigh; /* target state */
+ u32 sbbwa0; /* bandwidth allocation table0 */
+ u32 PAD;
+ u32 sbimconfiglow; /* initiator configuration */
+ u32 sbimconfighigh; /* initiator configuration */
+ u32 sbadmatch0; /* address match0 */
+ u32 PAD;
+ u32 sbtmconfiglow; /* target configuration */
+ u32 sbtmconfighigh; /* target configuration */
+ u32 sbbconfig; /* broadcast configuration */
+ u32 PAD;
+ u32 sbbstate; /* broadcast state */
+ u32 PAD[3];
+ u32 sbactcnfg; /* activate configuration */
+ u32 PAD[3];
+ u32 sbflagst; /* current sbflags */
+ u32 PAD[3];
+ u32 sbidlow; /* identification */
+ u32 sbidhigh; /* identification */
+};
+
+struct brcmf_core_priv {
+ struct brcmf_core pub;
+ u32 wrapbase;
+ struct list_head list;
+ struct brcmf_chip_priv *chip;
+};
+
+/* ARM CR4 core specific control flag bits */
+#define ARMCR4_BCMA_IOCTL_CPUHALT 0x0020
+
+/* D11 core specific control flag bits */
+#define D11_BCMA_IOCTL_PHYCLOCKEN 0x0004
+#define D11_BCMA_IOCTL_PHYRESET 0x0008
+
+struct brcmf_chip_priv {
+ struct brcmf_chip pub;
+ const struct brcmf_buscore_ops *ops;
+ void *ctx;
+ /* assured first core is chipcommon, second core is buscore */
+ struct list_head cores;
+ u16 num_cores;
+
+ bool (*iscoreup)(struct brcmf_core_priv *core);
+ void (*coredisable)(struct brcmf_core_priv *core, u32 prereset,
+ u32 reset);
+ void (*resetcore)(struct brcmf_core_priv *core, u32 prereset, u32 reset,
+ u32 postreset);
+};
+
+static void brcmf_chip_sb_corerev(struct brcmf_chip_priv *ci,
+ struct brcmf_core *core)
+{
+ u32 regdata;
+
+ regdata = ci->ops->read32(ci->ctx, CORE_SB(core->base, sbidhigh));
+ core->rev = SBCOREREV(regdata);
+}
+
+static bool brcmf_chip_sb_iscoreup(struct brcmf_core_priv *core)
+{
+ struct brcmf_chip_priv *ci;
+ u32 regdata;
+ u32 address;
+
+ ci = core->chip;
+ address = CORE_SB(core->pub.base, sbtmstatelow);
+ regdata = ci->ops->read32(ci->ctx, address);
+ regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
+ SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
+ return SSB_TMSLOW_CLOCK == regdata;
+}
+
+static bool brcmf_chip_ai_iscoreup(struct brcmf_core_priv *core)
+{
+ struct brcmf_chip_priv *ci;
+ u32 regdata;
+ bool ret;
+
+ ci = core->chip;
+ regdata = ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL);
+ ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
+
+ regdata = ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL);
+ ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
+
+ return ret;
+}
+
+static void brcmf_chip_sb_coredisable(struct brcmf_core_priv *core,
+ u32 prereset, u32 reset)
+{
+ struct brcmf_chip_priv *ci;
+ u32 val, base;
+
+ ci = core->chip;
+ base = core->pub.base;
+ val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow));
+ if (val & SSB_TMSLOW_RESET)
+ return;
+
+ val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow));
+ if ((val & SSB_TMSLOW_CLOCK) != 0) {
+ /*
+ * set target reject and spin until busy is clear
+ * (preserve core-specific bits)
+ */
+ val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow));
+ ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow),
+ val | SSB_TMSLOW_REJECT);
+
+ val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow));
+ udelay(1);
+ SPINWAIT((ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatehigh))
+ & SSB_TMSHIGH_BUSY), 100000);
+
+ val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatehigh));
+ if (val & SSB_TMSHIGH_BUSY)
+ brcmf_err("core state still busy\n");
+
+ val = ci->ops->read32(ci->ctx, CORE_SB(base, sbidlow));
+ if (val & SSB_IDLOW_INITIATOR) {
+ val = ci->ops->read32(ci->ctx,
+ CORE_SB(base, sbimstate));
+ val |= SSB_IMSTATE_REJECT;
+ ci->ops->write32(ci->ctx,
+ CORE_SB(base, sbimstate), val);
+ val = ci->ops->read32(ci->ctx,
+ CORE_SB(base, sbimstate));
+ udelay(1);
+ SPINWAIT((ci->ops->read32(ci->ctx,
+ CORE_SB(base, sbimstate)) &
+ SSB_IMSTATE_BUSY), 100000);
+ }
+
+ /* set reset and reject while enabling the clocks */
+ val = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
+ SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET;
+ ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow), val);
+ val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow));
+ udelay(10);
+
+ /* clear the initiator reject bit */
+ val = ci->ops->read32(ci->ctx, CORE_SB(base, sbidlow));
+ if (val & SSB_IDLOW_INITIATOR) {
+ val = ci->ops->read32(ci->ctx,
+ CORE_SB(base, sbimstate));
+ val &= ~SSB_IMSTATE_REJECT;
+ ci->ops->write32(ci->ctx,
+ CORE_SB(base, sbimstate), val);
+ }
+ }
+
+ /* leave reset and reject asserted */
+ ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow),
+ (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
+ udelay(1);
+}
+
+static void brcmf_chip_ai_coredisable(struct brcmf_core_priv *core,
+ u32 prereset, u32 reset)
+{
+ struct brcmf_chip_priv *ci;
+ u32 regdata;
+
+ ci = core->chip;
+
+ /* if core is already in reset, just return */
+ regdata = ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL);
+ if ((regdata & BCMA_RESET_CTL_RESET) != 0)
+ return;
+
+ /* configure reset */
+ ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL,
+ prereset | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK);
+ ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL);
+
+ /* put in reset */
+ ci->ops->write32(ci->ctx, core->wrapbase + BCMA_RESET_CTL,
+ BCMA_RESET_CTL_RESET);
+ usleep_range(10, 20);
+
+ /* wait till reset is 1 */
+ SPINWAIT(ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL) !=
+ BCMA_RESET_CTL_RESET, 300);
+
+ /* in-reset configure */
+ ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL,
+ reset | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK);
+ ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL);
+}
+
+static void brcmf_chip_sb_resetcore(struct brcmf_core_priv *core, u32 prereset,
+ u32 reset, u32 postreset)
+{
+ struct brcmf_chip_priv *ci;
+ u32 regdata;
+ u32 base;
+
+ ci = core->chip;
+ base = core->pub.base;
+ /*
+ * Must do the disable sequence first to work for
+ * arbitrary current core state.
+ */
+ brcmf_chip_sb_coredisable(core, 0, 0);
+
+ /*
+ * Now do the initialization sequence.
+ * set reset while enabling the clock and
+ * forcing them on throughout the core
+ */
+ ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow),
+ SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
+ SSB_TMSLOW_RESET);
+ regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow));
+ udelay(1);
+
+ /* clear any serror */
+ regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatehigh));
+ if (regdata & SSB_TMSHIGH_SERR)
+ ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatehigh), 0);
+
+ regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbimstate));
+ if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO)) {
+ regdata &= ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO);
+ ci->ops->write32(ci->ctx, CORE_SB(base, sbimstate), regdata);
+ }
+
+ /* clear reset and allow it to propagate throughout the core */
+ ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow),
+ SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK);
+ regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow));
+ udelay(1);
+
+ /* leave clock enabled */
+ ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow),
+ SSB_TMSLOW_CLOCK);
+ regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow));
+ udelay(1);
+}
+
+static void brcmf_chip_ai_resetcore(struct brcmf_core_priv *core, u32 prereset,
+ u32 reset, u32 postreset)
+{
+ struct brcmf_chip_priv *ci;
+ int count;
+
+ ci = core->chip;
+
+ /* must disable first to work for arbitrary current core state */
+ brcmf_chip_ai_coredisable(core, prereset, reset);
+
+ count = 0;
+ while (ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL) &
+ BCMA_RESET_CTL_RESET) {
+ ci->ops->write32(ci->ctx, core->wrapbase + BCMA_RESET_CTL, 0);
+ count++;
+ if (count > 50)
+ break;
+ usleep_range(40, 60);
+ }
+
+ ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL,
+ postreset | BCMA_IOCTL_CLK);
+ ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL);
+}
+
+static char *brcmf_chip_name(uint chipid, char *buf, uint len)
+{
+ const char *fmt;
+
+ fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
+ snprintf(buf, len, fmt, chipid);
+ return buf;
+}
+
+static struct brcmf_core *brcmf_chip_add_core(struct brcmf_chip_priv *ci,
+ u16 coreid, u32 base,
+ u32 wrapbase)
+{
+ struct brcmf_core_priv *core;
+
+ core = kzalloc(sizeof(*core), GFP_KERNEL);
+ if (!core)
+ return ERR_PTR(-ENOMEM);
+
+ core->pub.id = coreid;
+ core->pub.base = base;
+ core->chip = ci;
+ core->wrapbase = wrapbase;
+
+ list_add_tail(&core->list, &ci->cores);
+ return &core->pub;
+}
+
+#ifdef DEBUG
+/* safety check for chipinfo */
+static int brcmf_chip_cores_check(struct brcmf_chip_priv *ci)
+{
+ struct brcmf_core_priv *core;
+ bool need_socram = false;
+ bool has_socram = false;
+ int idx = 1;
+
+ list_for_each_entry(core, &ci->cores, list) {
+ brcmf_dbg(INFO, " [%-2d] core 0x%x:%-2d base 0x%08x wrap 0x%08x\n",
+ idx++, core->pub.id, core->pub.rev, core->pub.base,
+ core->wrapbase);
+
+ switch (core->pub.id) {
+ case BCMA_CORE_ARM_CM3:
+ need_socram = true;
+ break;
+ case BCMA_CORE_INTERNAL_MEM:
+ has_socram = true;
+ break;
+ case BCMA_CORE_ARM_CR4:
+ if (ci->pub.rambase == 0) {
+ brcmf_err("RAM base not provided with ARM CR4 core\n");
+ return -ENOMEM;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* check RAM core presence for ARM CM3 core */
+ if (need_socram && !has_socram) {
+ brcmf_err("RAM core not provided with ARM CM3 core\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+#else /* DEBUG */
+static inline int brcmf_chip_cores_check(struct brcmf_chip_priv *ci)
+{
+ return 0;
+}
+#endif
+
+static void brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci)
+{
+ switch (ci->pub.chip) {
+ case BCM4329_CHIP_ID:
+ ci->pub.ramsize = BCM4329_RAMSIZE;
+ break;
+ case BCM43143_CHIP_ID:
+ ci->pub.ramsize = BCM43143_RAMSIZE;
+ break;
+ case BCM43241_CHIP_ID:
+ ci->pub.ramsize = 0x90000;
+ break;
+ case BCM4330_CHIP_ID:
+ ci->pub.ramsize = 0x48000;
+ break;
+ case BCM4334_CHIP_ID:
+ ci->pub.ramsize = 0x80000;
+ break;
+ case BCM4335_CHIP_ID:
+ ci->pub.ramsize = 0xc0000;
+ ci->pub.rambase = 0x180000;
+ break;
+ case BCM43362_CHIP_ID:
+ ci->pub.ramsize = 0x3c000;
+ break;
+ case BCM4339_CHIP_ID:
+ case BCM4354_CHIP_ID:
+ ci->pub.ramsize = 0xc0000;
+ ci->pub.rambase = 0x180000;
+ break;
+ default:
+ brcmf_err("unknown chip: %s\n", ci->pub.name);
+ break;
+ }
+}
+
+static u32 brcmf_chip_dmp_get_desc(struct brcmf_chip_priv *ci, u32 *eromaddr,
+ u8 *type)
+{
+ u32 val;
+
+ /* read next descriptor */
+ val = ci->ops->read32(ci->ctx, *eromaddr);
+ *eromaddr += 4;
+
+ if (!type)
+ return val;
+
+ /* determine descriptor type */
+ *type = (val & DMP_DESC_TYPE_MSK);
+ if ((*type & ~DMP_DESC_ADDRSIZE_GT32) == DMP_DESC_ADDRESS)
+ *type = DMP_DESC_ADDRESS;
+
+ return val;
+}
+
+static int brcmf_chip_dmp_get_regaddr(struct brcmf_chip_priv *ci, u32 *eromaddr,
+ u32 *regbase, u32 *wrapbase)
+{
+ u8 desc;
+ u32 val;
+ u8 mpnum = 0;
+ u8 stype, sztype, wraptype;
+
+ *regbase = 0;
+ *wrapbase = 0;
+
+ val = brcmf_chip_dmp_get_desc(ci, eromaddr, &desc);
+ if (desc == DMP_DESC_MASTER_PORT) {
+ mpnum = (val & DMP_MASTER_PORT_NUM) >> DMP_MASTER_PORT_NUM_S;
+ wraptype = DMP_SLAVE_TYPE_MWRAP;
+ } else if (desc == DMP_DESC_ADDRESS) {
+ /* revert erom address */
+ *eromaddr -= 4;
+ wraptype = DMP_SLAVE_TYPE_SWRAP;
+ } else {
+ *eromaddr -= 4;
+ return -EILSEQ;
+ }
+
+ do {
+ /* locate address descriptor */
+ do {
+ val = brcmf_chip_dmp_get_desc(ci, eromaddr, &desc);
+ /* unexpected table end */
+ if (desc == DMP_DESC_EOT) {
+ *eromaddr -= 4;
+ return -EFAULT;
+ }
+ } while (desc != DMP_DESC_ADDRESS);
+
+ /* skip upper 32-bit address descriptor */
+ if (val & DMP_DESC_ADDRSIZE_GT32)
+ brcmf_chip_dmp_get_desc(ci, eromaddr, NULL);
+
+ sztype = (val & DMP_SLAVE_SIZE_TYPE) >> DMP_SLAVE_SIZE_TYPE_S;
+
+ /* next size descriptor can be skipped */
+ if (sztype == DMP_SLAVE_SIZE_DESC) {
+ val = brcmf_chip_dmp_get_desc(ci, eromaddr, NULL);
+ /* skip upper size descriptor if present */
+ if (val & DMP_DESC_ADDRSIZE_GT32)
+ brcmf_chip_dmp_get_desc(ci, eromaddr, NULL);
+ }
+
+ /* only look for 4K register regions */
+ if (sztype != DMP_SLAVE_SIZE_4K)
+ continue;
+
+ stype = (val & DMP_SLAVE_TYPE) >> DMP_SLAVE_TYPE_S;
+
+ /* only regular slave and wrapper */
+ if (*regbase == 0 && stype == DMP_SLAVE_TYPE_SLAVE)
+ *regbase = val & DMP_SLAVE_ADDR_BASE;
+ if (*wrapbase == 0 && stype == wraptype)
+ *wrapbase = val & DMP_SLAVE_ADDR_BASE;
+ } while (*regbase == 0 || *wrapbase == 0);
+
+ return 0;
+}
+
+static
+int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci)
+{
+ struct brcmf_core *core;
+ u32 eromaddr;
+ u8 desc_type = 0;
+ u32 val;
+ u16 id;
+ u8 nmp, nsp, nmw, nsw, rev;
+ u32 base, wrap;
+ int err;
+
+ eromaddr = ci->ops->read32(ci->ctx, CORE_CC_REG(SI_ENUM_BASE, eromptr));
+
+ while (desc_type != DMP_DESC_EOT) {
+ val = brcmf_chip_dmp_get_desc(ci, &eromaddr, &desc_type);
+ if (!(val & DMP_DESC_VALID))
+ continue;
+
+ if (desc_type == DMP_DESC_EMPTY)
+ continue;
+
+ /* need a component descriptor */
+ if (desc_type != DMP_DESC_COMPONENT)
+ continue;
+
+ id = (val & DMP_COMP_PARTNUM) >> DMP_COMP_PARTNUM_S;
+
+ /* next descriptor must be component as well */
+ val = brcmf_chip_dmp_get_desc(ci, &eromaddr, &desc_type);
+ if (WARN_ON((val & DMP_DESC_TYPE_MSK) != DMP_DESC_COMPONENT))
+ return -EFAULT;
+
+ /* only look at cores with master port(s) */
+ nmp = (val & DMP_COMP_NUM_MPORT) >> DMP_COMP_NUM_MPORT_S;
+ nsp = (val & DMP_COMP_NUM_SPORT) >> DMP_COMP_NUM_SPORT_S;
+ nmw = (val & DMP_COMP_NUM_MWRAP) >> DMP_COMP_NUM_MWRAP_S;
+ nsw = (val & DMP_COMP_NUM_SWRAP) >> DMP_COMP_NUM_SWRAP_S;
+ rev = (val & DMP_COMP_REVISION) >> DMP_COMP_REVISION_S;
+
+ /* need core with ports */
+ if (nmw + nsw == 0)
+ continue;
+
+ /* try to obtain register address info */
+ err = brcmf_chip_dmp_get_regaddr(ci, &eromaddr, &base, &wrap);
+ if (err)
+ continue;
+
+ /* finally a core to be added */
+ core = brcmf_chip_add_core(ci, id, base, wrap);
+ if (IS_ERR(core))
+ return PTR_ERR(core);
+
+ core->rev = rev;
+ }
+
+ return 0;
+}
+
+static int brcmf_chip_recognition(struct brcmf_chip_priv *ci)
+{
+ struct brcmf_core *core;
+ u32 regdata;
+ u32 socitype;
+
+ /* Get CC core rev
+ * Chipid is assume to be at offset 0 from SI_ENUM_BASE
+ * For different chiptypes or old sdio hosts w/o chipcommon,
+ * other ways of recognition should be added here.
+ */
+ regdata = ci->ops->read32(ci->ctx, CORE_CC_REG(SI_ENUM_BASE, chipid));
+ ci->pub.chip = regdata & CID_ID_MASK;
+ ci->pub.chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
+ socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
+
+ brcmf_chip_name(ci->pub.chip, ci->pub.name, sizeof(ci->pub.name));
+ brcmf_dbg(INFO, "found %s chip: BCM%s, rev=%d\n",
+ socitype == SOCI_SB ? "SB" : "AXI", ci->pub.name,
+ ci->pub.chiprev);
+
+ if (socitype == SOCI_SB) {
+ if (ci->pub.chip != BCM4329_CHIP_ID) {
+ brcmf_err("SB chip is not supported\n");
+ return -ENODEV;
+ }
+ ci->iscoreup = brcmf_chip_sb_iscoreup;
+ ci->coredisable = brcmf_chip_sb_coredisable;
+ ci->resetcore = brcmf_chip_sb_resetcore;
+
+ core = brcmf_chip_add_core(ci, BCMA_CORE_CHIPCOMMON,
+ SI_ENUM_BASE, 0);
+ brcmf_chip_sb_corerev(ci, core);
+ core = brcmf_chip_add_core(ci, BCMA_CORE_SDIO_DEV,
+ BCM4329_CORE_BUS_BASE, 0);
+ brcmf_chip_sb_corerev(ci, core);
+ core = brcmf_chip_add_core(ci, BCMA_CORE_INTERNAL_MEM,
+ BCM4329_CORE_SOCRAM_BASE, 0);
+ brcmf_chip_sb_corerev(ci, core);
+ core = brcmf_chip_add_core(ci, BCMA_CORE_ARM_CM3,
+ BCM4329_CORE_ARM_BASE, 0);
+ brcmf_chip_sb_corerev(ci, core);
+
+ core = brcmf_chip_add_core(ci, BCMA_CORE_80211, 0x18001000, 0);
+ brcmf_chip_sb_corerev(ci, core);
+ } else if (socitype == SOCI_AI) {
+ ci->iscoreup = brcmf_chip_ai_iscoreup;
+ ci->coredisable = brcmf_chip_ai_coredisable;
+ ci->resetcore = brcmf_chip_ai_resetcore;
+
+ brcmf_chip_dmp_erom_scan(ci);
+ } else {
+ brcmf_err("chip backplane type %u is not supported\n",
+ socitype);
+ return -ENODEV;
+ }
+
+ brcmf_chip_get_raminfo(ci);
+
+ return brcmf_chip_cores_check(ci);
+}
+
+static void brcmf_chip_disable_arm(struct brcmf_chip_priv *chip, u16 id)
+{
+ struct brcmf_core *core;
+ struct brcmf_core_priv *cr4;
+ u32 val;
+
+
+ core = brcmf_chip_get_core(&chip->pub, id);
+ if (!core)
+ return;
+
+ switch (id) {
+ case BCMA_CORE_ARM_CM3:
+ brcmf_chip_coredisable(core, 0, 0);
+ break;
+ case BCMA_CORE_ARM_CR4:
+ cr4 = container_of(core, struct brcmf_core_priv, pub);
+
+ /* clear all IOCTL bits except HALT bit */
+ val = chip->ops->read32(chip->ctx, cr4->wrapbase + BCMA_IOCTL);
+ val &= ARMCR4_BCMA_IOCTL_CPUHALT;
+ brcmf_chip_resetcore(core, val, ARMCR4_BCMA_IOCTL_CPUHALT,
+ ARMCR4_BCMA_IOCTL_CPUHALT);
+ break;
+ default:
+ brcmf_err("unknown id: %u\n", id);
+ break;
+ }
+}
+
+static int brcmf_chip_setup(struct brcmf_chip_priv *chip)
+{
+ struct brcmf_chip *pub;
+ struct brcmf_core_priv *cc;
+ u32 base;
+ u32 val;
+ int ret = 0;
+
+ pub = &chip->pub;
+ cc = list_first_entry(&chip->cores, struct brcmf_core_priv, list);
+ base = cc->pub.base;
+
+ /* get chipcommon capabilites */
+ pub->cc_caps = chip->ops->read32(chip->ctx,
+ CORE_CC_REG(base, capabilities));
+
+ /* get pmu caps & rev */
+ if (pub->cc_caps & CC_CAP_PMU) {
+ val = chip->ops->read32(chip->ctx,
+ CORE_CC_REG(base, pmucapabilities));
+ pub->pmurev = val & PCAP_REV_MASK;
+ pub->pmucaps = val;
+ }
+
+ brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, pmucaps=0x%x\n",
+ cc->pub.rev, pub->pmurev, pub->pmucaps);
+
+ /* execute bus core specific setup */
+ if (chip->ops->setup)
+ ret = chip->ops->setup(chip->ctx, pub);
+
+ /*
+ * Make sure any on-chip ARM is off (in case strapping is wrong),
+ * or downloaded code was already running.
+ */
+ brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CM3);
+ brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CR4);
+ return ret;
+}
+
+struct brcmf_chip *brcmf_chip_attach(void *ctx,
+ const struct brcmf_buscore_ops *ops)
+{
+ struct brcmf_chip_priv *chip;
+ int err = 0;
+
+ if (WARN_ON(!ops->read32))
+ err = -EINVAL;
+ if (WARN_ON(!ops->write32))
+ err = -EINVAL;
+ if (WARN_ON(!ops->prepare))
+ err = -EINVAL;
+ if (WARN_ON(!ops->exit_dl))
+ err = -EINVAL;
+ if (err < 0)
+ return ERR_PTR(-EINVAL);
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&chip->cores);
+ chip->num_cores = 0;
+ chip->ops = ops;
+ chip->ctx = ctx;
+
+ err = ops->prepare(ctx);
+ if (err < 0)
+ goto fail;
+
+ err = brcmf_chip_recognition(chip);
+ if (err < 0)
+ goto fail;
+
+ err = brcmf_chip_setup(chip);
+ if (err < 0)
+ goto fail;
+
+ return &chip->pub;
+
+fail:
+ brcmf_chip_detach(&chip->pub);
+ return ERR_PTR(err);
+}
+
+void brcmf_chip_detach(struct brcmf_chip *pub)
+{
+ struct brcmf_chip_priv *chip;
+ struct brcmf_core_priv *core;
+ struct brcmf_core_priv *tmp;
+
+ chip = container_of(pub, struct brcmf_chip_priv, pub);
+ list_for_each_entry_safe(core, tmp, &chip->cores, list) {
+ list_del(&core->list);
+ kfree(core);
+ }
+ kfree(chip);
+}
+
+struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *pub, u16 coreid)
+{
+ struct brcmf_chip_priv *chip;
+ struct brcmf_core_priv *core;
+
+ chip = container_of(pub, struct brcmf_chip_priv, pub);
+ list_for_each_entry(core, &chip->cores, list)
+ if (core->pub.id == coreid)
+ return &core->pub;
+
+ return NULL;
+}
+
+struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *pub)
+{
+ struct brcmf_chip_priv *chip;
+ struct brcmf_core_priv *cc;
+
+ chip = container_of(pub, struct brcmf_chip_priv, pub);
+ cc = list_first_entry(&chip->cores, struct brcmf_core_priv, list);
+ if (WARN_ON(!cc || cc->pub.id != BCMA_CORE_CHIPCOMMON))
+ return brcmf_chip_get_core(pub, BCMA_CORE_CHIPCOMMON);
+ return &cc->pub;
+}
+
+bool brcmf_chip_iscoreup(struct brcmf_core *pub)
+{
+ struct brcmf_core_priv *core;
+
+ core = container_of(pub, struct brcmf_core_priv, pub);
+ return core->chip->iscoreup(core);
+}
+
+void brcmf_chip_coredisable(struct brcmf_core *pub, u32 prereset, u32 reset)
+{
+ struct brcmf_core_priv *core;
+
+ core = container_of(pub, struct brcmf_core_priv, pub);
+ core->chip->coredisable(core, prereset, reset);
+}
+
+void brcmf_chip_resetcore(struct brcmf_core *pub, u32 prereset, u32 reset,
+ u32 postreset)
+{
+ struct brcmf_core_priv *core;
+
+ core = container_of(pub, struct brcmf_core_priv, pub);
+ core->chip->resetcore(core, prereset, reset, postreset);
+}
+
+static void
+brcmf_chip_cm3_enterdl(struct brcmf_chip_priv *chip)
+{
+ struct brcmf_core *core;
+
+ brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CM3);
+ core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_80211);
+ brcmf_chip_resetcore(core, D11_BCMA_IOCTL_PHYRESET |
+ D11_BCMA_IOCTL_PHYCLOCKEN,
+ D11_BCMA_IOCTL_PHYCLOCKEN,
+ D11_BCMA_IOCTL_PHYCLOCKEN);
+ core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_INTERNAL_MEM);
+ brcmf_chip_resetcore(core, 0, 0, 0);
+}
+
+static bool brcmf_chip_cm3_exitdl(struct brcmf_chip_priv *chip)
+{
+ struct brcmf_core *core;
+
+ core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_INTERNAL_MEM);
+ if (!brcmf_chip_iscoreup(core)) {
+ brcmf_err("SOCRAM core is down after reset?\n");
+ return false;
+ }
+
+ chip->ops->exit_dl(chip->ctx, &chip->pub, 0);
+
+ core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_ARM_CM3);
+ brcmf_chip_resetcore(core, 0, 0, 0);
+
+ return true;
+}
+
+static inline void
+brcmf_chip_cr4_enterdl(struct brcmf_chip_priv *chip)
+{
+ struct brcmf_core *core;
+
+ brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CR4);
+
+ core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_80211);
+ brcmf_chip_resetcore(core, D11_BCMA_IOCTL_PHYRESET |
+ D11_BCMA_IOCTL_PHYCLOCKEN,
+ D11_BCMA_IOCTL_PHYCLOCKEN,
+ D11_BCMA_IOCTL_PHYCLOCKEN);
+}
+
+static bool brcmf_chip_cr4_exitdl(struct brcmf_chip_priv *chip, u32 rstvec)
+{
+ struct brcmf_core *core;
+
+ chip->ops->exit_dl(chip->ctx, &chip->pub, rstvec);
+
+ /* restore ARM */
+ core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_ARM_CR4);
+ brcmf_chip_resetcore(core, ARMCR4_BCMA_IOCTL_CPUHALT, 0, 0);
+
+ return true;
+}
+
+void brcmf_chip_enter_download(struct brcmf_chip *pub)
+{
+ struct brcmf_chip_priv *chip;
+ struct brcmf_core *arm;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ chip = container_of(pub, struct brcmf_chip_priv, pub);
+ arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CR4);
+ if (arm) {
+ brcmf_chip_cr4_enterdl(chip);
+ return;
+ }
+
+ brcmf_chip_cm3_enterdl(chip);
+}
+
+bool brcmf_chip_exit_download(struct brcmf_chip *pub, u32 rstvec)
+{
+ struct brcmf_chip_priv *chip;
+ struct brcmf_core *arm;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ chip = container_of(pub, struct brcmf_chip_priv, pub);
+ arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CR4);
+ if (arm)
+ return brcmf_chip_cr4_exitdl(chip, rstvec);
+
+ return brcmf_chip_cm3_exitdl(chip);
+}
+
+bool brcmf_chip_sr_capable(struct brcmf_chip *pub)
+{
+ u32 base, addr, reg, pmu_cc3_mask = ~0;
+ struct brcmf_chip_priv *chip;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* old chips with PMU version less than 17 don't support save restore */
+ if (pub->pmurev < 17)
+ return false;
+
+ base = brcmf_chip_get_chipcommon(pub)->base;
+ chip = container_of(pub, struct brcmf_chip_priv, pub);
+
+ switch (pub->chip) {
+ case BCM4354_CHIP_ID:
+ /* explicitly check SR engine enable bit */
+ pmu_cc3_mask = BIT(2);
+ /* fall-through */
+ case BCM43241_CHIP_ID:
+ case BCM4335_CHIP_ID:
+ case BCM4339_CHIP_ID:
+ /* read PMU chipcontrol register 3 */
+ addr = CORE_CC_REG(base, chipcontrol_addr);
+ chip->ops->write32(chip->ctx, addr, 3);
+ addr = CORE_CC_REG(base, chipcontrol_data);
+ reg = chip->ops->read32(chip->ctx, addr);
+ return (reg & pmu_cc3_mask) != 0;
+ default:
+ addr = CORE_CC_REG(base, pmucapabilities_ext);
+ reg = chip->ops->read32(chip->ctx, addr);
+ if ((reg & PCAPEXT_SR_SUPPORTED_MASK) == 0)
+ return false;
+
+ addr = CORE_CC_REG(base, retention_ctl);
+ reg = chip->ops->read32(chip->ctx, addr);
+ return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK |
+ PMU_RCTL_LOGIC_DISABLE_MASK)) == 0;
+ }
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.h b/drivers/net/wireless/brcm80211/brcmfmac/chip.h
new file mode 100644
index 000000000000..c32908da90c8
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2014 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef BRCMF_CHIP_H
+#define BRCMF_CHIP_H
+
+#include <linux/types.h>
+
+#define CORE_CC_REG(base, field) \
+ (base + offsetof(struct chipcregs, field))
+
+/**
+ * struct brcmf_chip - chip level information.
+ *
+ * @chip: chip identifier.
+ * @chiprev: chip revision.
+ * @cc_caps: chipcommon core capabilities.
+ * @pmucaps: PMU capabilities.
+ * @pmurev: PMU revision.
+ * @rambase: RAM base address (only applicable for ARM CR4 chips).
+ * @ramsize: amount of RAM on chip.
+ * @name: string representation of the chip identifier.
+ */
+struct brcmf_chip {
+ u32 chip;
+ u32 chiprev;
+ u32 cc_caps;
+ u32 pmucaps;
+ u32 pmurev;
+ u32 rambase;
+ u32 ramsize;
+ char name[8];
+};
+
+/**
+ * struct brcmf_core - core related information.
+ *
+ * @id: core identifier.
+ * @rev: core revision.
+ * @base: base address of core register space.
+ */
+struct brcmf_core {
+ u16 id;
+ u16 rev;
+ u32 base;
+};
+
+/**
+ * struct brcmf_buscore_ops - buscore specific callbacks.
+ *
+ * @read32: read 32-bit value over bus.
+ * @write32: write 32-bit value over bus.
+ * @prepare: prepare bus for core configuration.
+ * @setup: bus-specific core setup.
+ * @exit_dl: exit download state.
+ * The callback should use the provided @rstvec when non-zero.
+ */
+struct brcmf_buscore_ops {
+ u32 (*read32)(void *ctx, u32 addr);
+ void (*write32)(void *ctx, u32 addr, u32 value);
+ int (*prepare)(void *ctx);
+ int (*setup)(void *ctx, struct brcmf_chip *chip);
+ void (*exit_dl)(void *ctx, struct brcmf_chip *chip, u32 rstvec);
+};
+
+struct brcmf_chip *brcmf_chip_attach(void *ctx,
+ const struct brcmf_buscore_ops *ops);
+void brcmf_chip_detach(struct brcmf_chip *chip);
+struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *chip, u16 coreid);
+struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *chip);
+bool brcmf_chip_iscoreup(struct brcmf_core *core);
+void brcmf_chip_coredisable(struct brcmf_core *core, u32 prereset, u32 reset);
+void brcmf_chip_resetcore(struct brcmf_core *core, u32 prereset, u32 reset,
+ u32 postreset);
+void brcmf_chip_enter_download(struct brcmf_chip *ci);
+bool brcmf_chip_exit_download(struct brcmf_chip *ci, u32 rstvec);
+bool brcmf_chip_sr_capable(struct brcmf_chip *pub);
+
+#endif /* BRCMF_AXIDMP_H */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
index d4d966beb840..7d28cd385092 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
@@ -1040,12 +1040,12 @@ void brcmf_detach(struct device *dev)
brcmf_cfg80211_detach(drvr->config);
+ brcmf_fws_deinit(drvr);
+
brcmf_bus_detach(drvr);
brcmf_proto_detach(drvr);
- brcmf_fws_deinit(drvr);
-
brcmf_debugfs_detach(drvr);
bus_if->drvr = NULL;
kfree(drvr);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index 3e991897d7ca..13c89a0c4ba7 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -23,6 +23,7 @@
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/card.h>
#include <linux/semaphore.h>
@@ -40,7 +41,7 @@
#include <brcm_hw_ids.h>
#include <soc.h>
#include "sdio_host.h"
-#include "sdio_chip.h"
+#include "chip.h"
#include "nvram.h"
#define DCMD_RESP_TIMEOUT 2000 /* In milli second */
@@ -112,8 +113,6 @@ struct rte_console {
#define BRCMF_TXBOUND 20 /* Default for max tx frames in
one scheduling */
-#define BRCMF_DEFAULT_TXGLOM_SIZE 32 /* max tx frames in glom chain */
-
#define BRCMF_TXMINMAX 1 /* Max tx frames if rx still pending */
#define MEMBLOCK 2048 /* Block size used for downloading
@@ -156,6 +155,34 @@ struct rte_console {
/* manfid tuple length, include tuple, link bytes */
#define SBSDIO_CIS_MANFID_TUPLE_LEN 6
+#define CORE_BUS_REG(base, field) \
+ (base + offsetof(struct sdpcmd_regs, field))
+
+/* SDIO function 1 register CHIPCLKCSR */
+/* Force ALP request to backplane */
+#define SBSDIO_FORCE_ALP 0x01
+/* Force HT request to backplane */
+#define SBSDIO_FORCE_HT 0x02
+/* Force ILP request to backplane */
+#define SBSDIO_FORCE_ILP 0x04
+/* Make ALP ready (power up xtal) */
+#define SBSDIO_ALP_AVAIL_REQ 0x08
+/* Make HT ready (power up PLL) */
+#define SBSDIO_HT_AVAIL_REQ 0x10
+/* Squelch clock requests from HW */
+#define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20
+/* Status: ALP is ready */
+#define SBSDIO_ALP_AVAIL 0x40
+/* Status: HT is ready */
+#define SBSDIO_HT_AVAIL 0x80
+#define SBSDIO_CSR_MASK 0x1F
+#define SBSDIO_AVBITS (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL)
+#define SBSDIO_ALPAV(regval) ((regval) & SBSDIO_AVBITS)
+#define SBSDIO_HTAV(regval) (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS)
+#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval))
+#define SBSDIO_CLKAV(regval, alponly) \
+ (SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval)))
+
/* intstatus */
#define I_SMB_SW0 (1 << 0) /* To SB Mail S/W interrupt 0 */
#define I_SMB_SW1 (1 << 1) /* To SB Mail S/W interrupt 1 */
@@ -276,7 +303,6 @@ struct rte_console {
/* Flags for SDH calls */
#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
-#define BRCMF_IDLE_IMMEDIATE (-1) /* Enter idle immediately */
#define BRCMF_IDLE_ACTIVE 0 /* Do not request any SD clock change
* when idle
*/
@@ -433,10 +459,11 @@ struct brcmf_sdio {
bool alp_only; /* Don't use HT clock (ALP only) */
u8 *ctrl_frame_buf;
- u32 ctrl_frame_len;
+ u16 ctrl_frame_len;
bool ctrl_frame_stat;
- spinlock_t txqlock;
+ spinlock_t txq_lock; /* protect bus->txq */
+ struct semaphore tx_seq_lock; /* protect bus->tx_seq */
wait_queue_head_t ctrl_wait;
wait_queue_head_t dcmd_resp_wait;
@@ -457,7 +484,6 @@ struct brcmf_sdio {
u8 tx_hdrlen; /* sdio bus header length for tx packet */
bool txglom; /* host tx glomming enable flag */
- struct sk_buff *txglom_sgpad; /* scatter-gather padding buffer */
u16 head_align; /* buffer pointer alignment */
u16 sgentry_align; /* scatter-gather buffer alignment */
};
@@ -484,16 +510,58 @@ static const uint max_roundup = 512;
#define ALIGNMENT 4
-static int brcmf_sdio_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE;
-module_param_named(txglomsz, brcmf_sdio_txglomsz, int, 0);
-MODULE_PARM_DESC(txglomsz, "maximum tx packet chain size [SDIO]");
-
enum brcmf_sdio_frmtype {
BRCMF_SDIO_FT_NORMAL,
BRCMF_SDIO_FT_SUPER,
BRCMF_SDIO_FT_SUB,
};
+#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
+
+/* SDIO Pad drive strength to select value mappings */
+struct sdiod_drive_str {
+ u8 strength; /* Pad Drive Strength in mA */
+ u8 sel; /* Chip-specific select value */
+};
+
+/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8V) */
+static const struct sdiod_drive_str sdiod_drvstr_tab1_1v8[] = {
+ {32, 0x6},
+ {26, 0x7},
+ {22, 0x4},
+ {16, 0x5},
+ {12, 0x2},
+ {8, 0x3},
+ {4, 0x0},
+ {0, 0x1}
+};
+
+/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */
+static const struct sdiod_drive_str sdiod_drive_strength_tab5_1v8[] = {
+ {6, 0x7},
+ {5, 0x6},
+ {4, 0x5},
+ {3, 0x4},
+ {2, 0x2},
+ {1, 0x1},
+ {0, 0x0}
+};
+
+/* SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */
+static const struct sdiod_drive_str sdiod_drvstr_tab6_1v8[] = {
+ {3, 0x3},
+ {2, 0x2},
+ {1, 0x1},
+ {0, 0x0} };
+
+/* SDIO Drive Strength to sel value table for 43143 PMU Rev 17 (3.3V) */
+static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = {
+ {16, 0x7},
+ {12, 0x5},
+ {8, 0x3},
+ {4, 0x1}
+};
+
#define BCM43143_FIRMWARE_NAME "brcm/brcmfmac43143-sdio.bin"
#define BCM43143_NVRAM_NAME "brcm/brcmfmac43143-sdio.txt"
#define BCM43241B0_FIRMWARE_NAME "brcm/brcmfmac43241b0-sdio.bin"
@@ -512,6 +580,8 @@ enum brcmf_sdio_frmtype {
#define BCM43362_NVRAM_NAME "brcm/brcmfmac43362-sdio.txt"
#define BCM4339_FIRMWARE_NAME "brcm/brcmfmac4339-sdio.bin"
#define BCM4339_NVRAM_NAME "brcm/brcmfmac4339-sdio.txt"
+#define BCM4354_FIRMWARE_NAME "brcm/brcmfmac4354-sdio.bin"
+#define BCM4354_NVRAM_NAME "brcm/brcmfmac4354-sdio.txt"
MODULE_FIRMWARE(BCM43143_FIRMWARE_NAME);
MODULE_FIRMWARE(BCM43143_NVRAM_NAME);
@@ -531,6 +601,8 @@ MODULE_FIRMWARE(BCM43362_FIRMWARE_NAME);
MODULE_FIRMWARE(BCM43362_NVRAM_NAME);
MODULE_FIRMWARE(BCM4339_FIRMWARE_NAME);
MODULE_FIRMWARE(BCM4339_NVRAM_NAME);
+MODULE_FIRMWARE(BCM4354_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM4354_NVRAM_NAME);
struct brcmf_firmware_names {
u32 chipid;
@@ -556,7 +628,8 @@ static const struct brcmf_firmware_names brcmf_fwname_data[] = {
{ BCM4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) },
{ BCM4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) },
{ BCM43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) },
- { BCM4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) }
+ { BCM4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) },
+ { BCM4354_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4354) }
};
@@ -619,27 +692,24 @@ static bool data_ok(struct brcmf_sdio *bus)
* Reads a register in the SDIO hardware block. This block occupies a series of
* adresses on the 32 bit backplane bus.
*/
-static int
-r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 offset)
+static int r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 offset)
{
- u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
+ struct brcmf_core *core;
int ret;
- *regvar = brcmf_sdiod_regrl(bus->sdiodev,
- bus->ci->c_inf[idx].base + offset, &ret);
+ core = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV);
+ *regvar = brcmf_sdiod_regrl(bus->sdiodev, core->base + offset, &ret);
return ret;
}
-static int
-w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset)
+static int w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset)
{
- u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
+ struct brcmf_core *core;
int ret;
- brcmf_sdiod_regwl(bus->sdiodev,
- bus->ci->c_inf[idx].base + reg_offset,
- regval, &ret);
+ core = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV);
+ brcmf_sdiod_regwl(bus->sdiodev, core->base + reg_offset, regval, &ret);
return ret;
}
@@ -651,16 +721,12 @@ brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on)
int err = 0;
int try_cnt = 0;
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(TRACE, "Enter: on=%d\n", on);
wr_val = (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
/* 1st KSO write goes to AOS wake up core if device is asleep */
brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
wr_val, &err);
- if (err) {
- brcmf_err("SDIO_AOS KSO write error: %d\n", err);
- return err;
- }
if (on) {
/* device WAKEUP through KSO:
@@ -690,18 +756,22 @@ brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on)
&err);
if (((rd_val & bmask) == cmp_val) && !err)
break;
- brcmf_dbg(SDIO, "KSO wr/rd retry:%d (max: %d) ERR:%x\n",
- try_cnt, MAX_KSO_ATTEMPTS, err);
+
udelay(KSO_WAIT_US);
brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
wr_val, &err);
} while (try_cnt++ < MAX_KSO_ATTEMPTS);
+ if (try_cnt > 2)
+ brcmf_dbg(SDIO, "try_cnt=%d rd_val=0x%x err=%d\n", try_cnt,
+ rd_val, err);
+
+ if (try_cnt > MAX_KSO_ATTEMPTS)
+ brcmf_err("max tries: rd_val=0x%x err=%d\n", rd_val, err);
+
return err;
}
-#define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND)
-
#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
/* Turn backplane clock on or off */
@@ -800,7 +870,6 @@ static int brcmf_sdio_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
}
#endif /* defined (DEBUG) */
- bus->activity = true;
} else {
clkreq = 0;
@@ -900,8 +969,9 @@ static int
brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)
{
int err = 0;
- brcmf_dbg(TRACE, "Enter\n");
- brcmf_dbg(SDIO, "request %s currently %s\n",
+ u8 clkcsr;
+
+ brcmf_dbg(SDIO, "Enter: request %s currently %s\n",
(sleep ? "SLEEP" : "WAKE"),
(bus->sleeping ? "SLEEP" : "WAKE"));
@@ -918,8 +988,20 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)
atomic_read(&bus->ipend) > 0 ||
(!atomic_read(&bus->fcstate) &&
brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) &&
- data_ok(bus)))
- return -EBUSY;
+ data_ok(bus))) {
+ err = -EBUSY;
+ goto done;
+ }
+
+ clkcsr = brcmf_sdiod_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ &err);
+ if ((clkcsr & SBSDIO_CSR_MASK) == 0) {
+ brcmf_dbg(SDIO, "no clock, set ALP\n");
+ brcmf_sdiod_regwb(bus->sdiodev,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ SBSDIO_ALP_AVAIL_REQ, &err);
+ }
err = brcmf_sdio_kso_control(bus, false);
/* disable watchdog */
if (!err)
@@ -936,7 +1018,7 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)
} else {
brcmf_err("error while changing bus sleep state %d\n",
err);
- return err;
+ goto done;
}
}
@@ -948,11 +1030,92 @@ end:
} else {
brcmf_sdio_clkctl(bus, CLK_AVAIL, pendok);
}
-
+done:
+ brcmf_dbg(SDIO, "Exit: err=%d\n", err);
return err;
}
+#ifdef DEBUG
+static inline bool brcmf_sdio_valid_shared_address(u32 addr)
+{
+ return !(addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff));
+}
+
+static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
+ struct sdpcm_shared *sh)
+{
+ u32 addr;
+ int rv;
+ u32 shaddr = 0;
+ struct sdpcm_shared_le sh_le;
+ __le32 addr_le;
+
+ shaddr = bus->ci->rambase + bus->ramsize - 4;
+
+ /*
+ * Read last word in socram to determine
+ * address of sdpcm_shared structure
+ */
+ sdio_claim_host(bus->sdiodev->func[1]);
+ brcmf_sdio_bus_sleep(bus, false, false);
+ rv = brcmf_sdiod_ramrw(bus->sdiodev, false, shaddr, (u8 *)&addr_le, 4);
+ sdio_release_host(bus->sdiodev->func[1]);
+ if (rv < 0)
+ return rv;
+
+ addr = le32_to_cpu(addr_le);
+
+ brcmf_dbg(SDIO, "sdpcm_shared address 0x%08X\n", addr);
+
+ /*
+ * Check if addr is valid.
+ * NVRAM length at the end of memory should have been overwritten.
+ */
+ if (!brcmf_sdio_valid_shared_address(addr)) {
+ brcmf_err("invalid sdpcm_shared address 0x%08X\n",
+ addr);
+ return -EINVAL;
+ }
+
+ /* Read hndrte_shared structure */
+ rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, (u8 *)&sh_le,
+ sizeof(struct sdpcm_shared_le));
+ if (rv < 0)
+ return rv;
+
+ /* Endianness */
+ sh->flags = le32_to_cpu(sh_le.flags);
+ sh->trap_addr = le32_to_cpu(sh_le.trap_addr);
+ sh->assert_exp_addr = le32_to_cpu(sh_le.assert_exp_addr);
+ sh->assert_file_addr = le32_to_cpu(sh_le.assert_file_addr);
+ sh->assert_line = le32_to_cpu(sh_le.assert_line);
+ sh->console_addr = le32_to_cpu(sh_le.console_addr);
+ sh->msgtrace_addr = le32_to_cpu(sh_le.msgtrace_addr);
+
+ if ((sh->flags & SDPCM_SHARED_VERSION_MASK) > SDPCM_SHARED_VERSION) {
+ brcmf_err("sdpcm shared version unsupported: dhd %d dongle %d\n",
+ SDPCM_SHARED_VERSION,
+ sh->flags & SDPCM_SHARED_VERSION_MASK);
+ return -EPROTO;
+ }
+
+ return 0;
+}
+
+static void brcmf_sdio_get_console_addr(struct brcmf_sdio *bus)
+{
+ struct sdpcm_shared sh;
+
+ if (brcmf_sdio_readshared(bus, &sh) == 0)
+ bus->console_addr = sh.console_addr;
+}
+#else
+static void brcmf_sdio_get_console_addr(struct brcmf_sdio *bus)
+{
+}
+#endif /* DEBUG */
+
static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus)
{
u32 intstatus = 0;
@@ -996,6 +1159,12 @@ static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus)
else
brcmf_dbg(SDIO, "Dongle ready, protocol version %d\n",
bus->sdpcm_ver);
+
+ /*
+ * Retrieve console state address now that firmware should have
+ * updated it.
+ */
+ brcmf_sdio_get_console_addr(bus);
}
/*
@@ -1084,6 +1253,28 @@ static void brcmf_sdio_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
bus->cur_read.len = 0;
}
+static void brcmf_sdio_txfail(struct brcmf_sdio *bus)
+{
+ struct brcmf_sdio_dev *sdiodev = bus->sdiodev;
+ u8 i, hi, lo;
+
+ /* On failure, abort the command and terminate the frame */
+ brcmf_err("sdio error, abort command and terminate frame\n");
+ bus->sdcnt.tx_sderrs++;
+
+ brcmf_sdiod_abort(sdiodev, SDIO_FUNC_2);
+ brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, NULL);
+ bus->sdcnt.f1regdata++;
+
+ for (i = 0; i < 3; i++) {
+ hi = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_WFRAMEBCHI, NULL);
+ lo = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_WFRAMEBCLO, NULL);
+ bus->sdcnt.f1regdata += 2;
+ if ((hi == 0) && (lo == 0))
+ break;
+ }
+}
+
/* return total length of buffer chain */
static uint brcmf_sdio_glom_len(struct brcmf_sdio *bus)
{
@@ -1944,19 +2135,21 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus,
if (lastfrm && chain_pad)
tail_pad += blksize - chain_pad;
if (skb_tailroom(pkt) < tail_pad && pkt->len > blksize) {
- pkt_pad = bus->txglom_sgpad;
- if (pkt_pad == NULL)
- brcmu_pkt_buf_get_skb(tail_pad + tail_chop);
+ pkt_pad = brcmu_pkt_buf_get_skb(tail_pad + tail_chop +
+ bus->head_align);
if (pkt_pad == NULL)
return -ENOMEM;
ret = brcmf_sdio_txpkt_hdalign(bus, pkt_pad);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ kfree_skb(pkt_pad);
return ret;
+ }
memcpy(pkt_pad->data,
pkt->data + pkt->len - tail_chop,
tail_chop);
- *(u32 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop;
+ *(u16 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop;
skb_trim(pkt, pkt->len - tail_chop);
+ skb_trim(pkt_pad, tail_pad + tail_chop);
__skb_queue_after(pktq, pkt, pkt_pad);
} else {
ntail = pkt->data_len + tail_pad -
@@ -2002,7 +2195,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
* already properly aligned and does not
* need an sdpcm header.
*/
- if (*(u32 *)(pkt_next->cb) & ALIGN_SKB_FLAG)
+ if (*(u16 *)(pkt_next->cb) & ALIGN_SKB_FLAG)
continue;
/* align packet data pointer */
@@ -2011,7 +2204,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
return ret;
head_pad = (u16)ret;
if (head_pad)
- memset(pkt_next->data, 0, head_pad + bus->tx_hdrlen);
+ memset(pkt_next->data + bus->tx_hdrlen, 0, head_pad);
total_len += pkt_next->len;
@@ -2036,10 +2229,10 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
if (BRCMF_BYTES_ON() &&
((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) ||
(BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL)))
- brcmf_dbg_hex_dump(true, pkt_next, hd_info.len,
+ brcmf_dbg_hex_dump(true, pkt_next->data, hd_info.len,
"Tx Frame:\n");
else if (BRCMF_HDRS_ON())
- brcmf_dbg_hex_dump(true, pkt_next,
+ brcmf_dbg_hex_dump(true, pkt_next->data,
head_pad + bus->tx_hdrlen,
"Tx Header:\n");
}
@@ -2066,11 +2259,11 @@ brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq)
u8 *hdr;
u32 dat_offset;
u16 tail_pad;
- u32 dummy_flags, chop_len;
+ u16 dummy_flags, chop_len;
struct sk_buff *pkt_next, *tmp, *pkt_prev;
skb_queue_walk_safe(pktq, pkt_next, tmp) {
- dummy_flags = *(u32 *)(pkt_next->cb);
+ dummy_flags = *(u16 *)(pkt_next->cb);
if (dummy_flags & ALIGN_SKB_FLAG) {
chop_len = dummy_flags & ALIGN_SKB_CHOP_LEN_MASK;
if (chop_len) {
@@ -2099,7 +2292,6 @@ static int brcmf_sdio_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
uint chan)
{
int ret;
- int i;
struct sk_buff *pkt_next, *tmp;
brcmf_dbg(TRACE, "Enter\n");
@@ -2112,28 +2304,9 @@ static int brcmf_sdio_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
ret = brcmf_sdiod_send_pkt(bus->sdiodev, pktq);
bus->sdcnt.f2txdata++;
- if (ret < 0) {
- /* On failure, abort the command and terminate the frame */
- brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
- ret);
- bus->sdcnt.tx_sderrs++;
-
- brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2);
- brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
- SFC_WF_TERM, NULL);
- bus->sdcnt.f1regdata++;
+ if (ret < 0)
+ brcmf_sdio_txfail(bus);
- for (i = 0; i < 3; i++) {
- u8 hi, lo;
- hi = brcmf_sdiod_regrb(bus->sdiodev,
- SBSDIO_FUNC1_WFRAMEBCHI, NULL);
- lo = brcmf_sdiod_regrb(bus->sdiodev,
- SBSDIO_FUNC1_WFRAMEBCLO, NULL);
- bus->sdcnt.f1regdata += 2;
- if ((hi == 0) && (lo == 0))
- break;
- }
- }
sdio_release_host(bus->sdiodev->func[1]);
done:
@@ -2163,13 +2336,15 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
/* Send frames until the limit or some other event */
for (cnt = 0; (cnt < maxframes) && data_ok(bus);) {
pkt_num = 1;
- __skb_queue_head_init(&pktq);
+ if (down_interruptible(&bus->tx_seq_lock))
+ return cnt;
if (bus->txglom)
pkt_num = min_t(u8, bus->tx_max - bus->tx_seq,
- brcmf_sdio_txglomsz);
+ bus->sdiodev->txglomsz);
pkt_num = min_t(u32, pkt_num,
brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol));
- spin_lock_bh(&bus->txqlock);
+ __skb_queue_head_init(&pktq);
+ spin_lock_bh(&bus->txq_lock);
for (i = 0; i < pkt_num; i++) {
pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map,
&prec_out);
@@ -2177,15 +2352,19 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
break;
__skb_queue_tail(&pktq, pkt);
}
- spin_unlock_bh(&bus->txqlock);
- if (i == 0)
+ spin_unlock_bh(&bus->txq_lock);
+ if (i == 0) {
+ up(&bus->tx_seq_lock);
break;
+ }
ret = brcmf_sdio_txpkt(bus, &pktq, SDPCM_DATA_CHANNEL);
+ up(&bus->tx_seq_lock);
+
cnt += i;
/* In poll mode, need to check for other events */
- if (!bus->intr && cnt) {
+ if (!bus->intr) {
/* Check device status, signal pending interrupt */
sdio_claim_host(bus->sdiodev->func[1]);
ret = r_sdreg32(bus, &intstatus,
@@ -2210,6 +2389,68 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
return cnt;
}
+static int brcmf_sdio_tx_ctrlframe(struct brcmf_sdio *bus, u8 *frame, u16 len)
+{
+ u8 doff;
+ u16 pad;
+ uint retries = 0;
+ struct brcmf_sdio_hdrinfo hd_info = {0};
+ int ret;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Back the pointer to make room for bus header */
+ frame -= bus->tx_hdrlen;
+ len += bus->tx_hdrlen;
+
+ /* Add alignment padding (optional for ctl frames) */
+ doff = ((unsigned long)frame % bus->head_align);
+ if (doff) {
+ frame -= doff;
+ len += doff;
+ memset(frame + bus->tx_hdrlen, 0, doff);
+ }
+
+ /* Round send length to next SDIO block */
+ pad = 0;
+ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
+ pad = bus->blocksize - (len % bus->blocksize);
+ if ((pad > bus->roundup) || (pad >= bus->blocksize))
+ pad = 0;
+ } else if (len % bus->head_align) {
+ pad = bus->head_align - (len % bus->head_align);
+ }
+ len += pad;
+
+ hd_info.len = len - pad;
+ hd_info.channel = SDPCM_CONTROL_CHANNEL;
+ hd_info.dat_offset = doff + bus->tx_hdrlen;
+ hd_info.seq_num = bus->tx_seq;
+ hd_info.lastfrm = true;
+ hd_info.tail_pad = pad;
+ brcmf_sdio_hdpack(bus, frame, &hd_info);
+
+ if (bus->txglom)
+ brcmf_sdio_update_hwhdr(frame, len);
+
+ brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(),
+ frame, len, "Tx Frame:\n");
+ brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && BRCMF_CTL_ON()) &&
+ BRCMF_HDRS_ON(),
+ frame, min_t(u16, len, 16), "TxHdr:\n");
+
+ do {
+ ret = brcmf_sdiod_send_buf(bus->sdiodev, frame, len);
+
+ if (ret < 0)
+ brcmf_sdio_txfail(bus);
+ else
+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;
+ } while (ret < 0 && retries++ < TXRETRIES);
+
+ return ret;
+}
+
static void brcmf_sdio_bus_stop(struct device *dev)
{
u32 local_hostintmask;
@@ -2291,21 +2532,29 @@ static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus)
}
}
+static void atomic_orr(int val, atomic_t *v)
+{
+ int old_val;
+
+ old_val = atomic_read(v);
+ while (atomic_cmpxchg(v, old_val, val | old_val) != old_val)
+ old_val = atomic_read(v);
+}
+
static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
{
- u8 idx;
+ struct brcmf_core *buscore;
u32 addr;
unsigned long val;
- int n, ret;
+ int ret;
- idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
- addr = bus->ci->c_inf[idx].base +
- offsetof(struct sdpcmd_regs, intstatus);
+ buscore = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV);
+ addr = buscore->base + offsetof(struct sdpcmd_regs, intstatus);
val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret);
bus->sdcnt.f1regdata++;
if (ret != 0)
- val = 0;
+ return ret;
val &= bus->hostintmask;
atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE));
@@ -2314,13 +2563,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
if (val) {
brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret);
bus->sdcnt.f1regdata++;
- }
-
- if (ret) {
- atomic_set(&bus->intstatus, 0);
- } else if (val) {
- for_each_set_bit(n, &val, 32)
- set_bit(n, (unsigned long *)&bus->intstatus.counter);
+ atomic_orr(val, &bus->intstatus);
}
return ret;
@@ -2330,10 +2573,9 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
{
u32 newstatus = 0;
unsigned long intstatus;
- uint rxlimit = bus->rxbound; /* Rx frames to read before resched */
uint txlimit = bus->txbound; /* Tx frames to send before resched */
- uint framecnt = 0; /* Temporary counter of tx/rx frames */
- int err = 0, n;
+ uint framecnt; /* Temporary counter of tx/rx frames */
+ int err = 0;
brcmf_dbg(TRACE, "Enter\n");
@@ -2430,70 +2672,38 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
intstatus &= ~I_HMB_FRAME_IND;
/* On frame indication, read available frames */
- if (PKT_AVAILABLE() && bus->clkstate == CLK_AVAIL) {
- framecnt = brcmf_sdio_readframes(bus, rxlimit);
+ if ((intstatus & I_HMB_FRAME_IND) && (bus->clkstate == CLK_AVAIL)) {
+ brcmf_sdio_readframes(bus, bus->rxbound);
if (!bus->rxpending)
intstatus &= ~I_HMB_FRAME_IND;
- rxlimit -= min(framecnt, rxlimit);
}
/* Keep still-pending events for next scheduling */
- if (intstatus) {
- for_each_set_bit(n, &intstatus, 32)
- set_bit(n, (unsigned long *)&bus->intstatus.counter);
- }
+ if (intstatus)
+ atomic_orr(intstatus, &bus->intstatus);
brcmf_sdio_clrintr(bus);
- if (data_ok(bus) && bus->ctrl_frame_stat &&
- (bus->clkstate == CLK_AVAIL)) {
- int i;
-
- sdio_claim_host(bus->sdiodev->func[1]);
- err = brcmf_sdiod_send_buf(bus->sdiodev, bus->ctrl_frame_buf,
- (u32)bus->ctrl_frame_len);
-
- if (err < 0) {
- /* On failure, abort the command and
- terminate the frame */
- brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
- err);
- bus->sdcnt.tx_sderrs++;
-
- brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2);
-
- brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
- SFC_WF_TERM, &err);
- bus->sdcnt.f1regdata++;
-
- for (i = 0; i < 3; i++) {
- u8 hi, lo;
- hi = brcmf_sdiod_regrb(bus->sdiodev,
- SBSDIO_FUNC1_WFRAMEBCHI,
- &err);
- lo = brcmf_sdiod_regrb(bus->sdiodev,
- SBSDIO_FUNC1_WFRAMEBCLO,
- &err);
- bus->sdcnt.f1regdata += 2;
- if ((hi == 0) && (lo == 0))
- break;
- }
+ if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) &&
+ (down_interruptible(&bus->tx_seq_lock) == 0)) {
+ if (data_ok(bus)) {
+ sdio_claim_host(bus->sdiodev->func[1]);
+ err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf,
+ bus->ctrl_frame_len);
+ sdio_release_host(bus->sdiodev->func[1]);
- } else {
- bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;
+ bus->ctrl_frame_stat = false;
+ brcmf_sdio_wait_event_wakeup(bus);
}
- sdio_release_host(bus->sdiodev->func[1]);
- bus->ctrl_frame_stat = false;
- brcmf_sdio_wait_event_wakeup(bus);
+ up(&bus->tx_seq_lock);
}
/* Send queued frames (limit 1 if rx may still be pending) */
- else if ((bus->clkstate == CLK_AVAIL) && !atomic_read(&bus->fcstate) &&
- brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit
- && data_ok(bus)) {
+ if ((bus->clkstate == CLK_AVAIL) && !atomic_read(&bus->fcstate) &&
+ brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit &&
+ data_ok(bus)) {
framecnt = bus->rxpending ? min(txlimit, bus->txminmax) :
txlimit;
- framecnt = brcmf_sdio_sendfromq(bus, framecnt);
- txlimit -= framecnt;
+ brcmf_sdio_sendfromq(bus, framecnt);
}
if (!brcmf_bus_ready(bus->sdiodev->bus_if) || (err != 0)) {
@@ -2503,19 +2713,9 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
atomic_read(&bus->ipend) > 0 ||
(!atomic_read(&bus->fcstate) &&
brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) &&
- data_ok(bus)) || PKT_AVAILABLE()) {
+ data_ok(bus))) {
atomic_inc(&bus->dpc_tskcnt);
}
-
- /* If we're done for now, turn off clock request. */
- if ((bus->clkstate != CLK_PENDING)
- && bus->idletime == BRCMF_IDLE_IMMEDIATE) {
- bus->activity = false;
- brcmf_dbg(SDIO, "idle state\n");
- sdio_claim_host(bus->sdiodev->func[1]);
- brcmf_sdio_bus_sleep(bus, true, false);
- sdio_release_host(bus->sdiodev->func[1]);
- }
}
static struct pktq *brcmf_sdio_bus_gettxq(struct device *dev)
@@ -2530,15 +2730,12 @@ static struct pktq *brcmf_sdio_bus_gettxq(struct device *dev)
static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
{
int ret = -EBADE;
- uint datalen, prec;
+ uint prec;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
struct brcmf_sdio *bus = sdiodev->bus;
- ulong flags;
- brcmf_dbg(TRACE, "Enter\n");
-
- datalen = pkt->len;
+ brcmf_dbg(TRACE, "Enter: pkt: data %p len %d\n", pkt->data, pkt->len);
/* Add space for the header */
skb_push(pkt, bus->tx_hdrlen);
@@ -2552,7 +2749,9 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
bus->sdcnt.fcqueued++;
/* Priority based enq */
- spin_lock_irqsave(&bus->txqlock, flags);
+ spin_lock_bh(&bus->txq_lock);
+ /* reset bus_flags in packet cb */
+ *(u16 *)(pkt->cb) = 0;
if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) {
skb_pull(pkt, bus->tx_hdrlen);
brcmf_err("out of bus->txq !!!\n");
@@ -2565,7 +2764,7 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
bus->txoff = true;
brcmf_txflowblock(bus->sdiodev->dev, true);
}
- spin_unlock_irqrestore(&bus->txqlock, flags);
+ spin_unlock_bh(&bus->txq_lock);
#ifdef DEBUG
if (pktq_plen(&bus->txq, prec) > qcount[prec])
@@ -2660,110 +2859,27 @@ break2:
}
#endif /* DEBUG */
-static int brcmf_sdio_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
-{
- int i;
- int ret;
-
- bus->ctrl_frame_stat = false;
- ret = brcmf_sdiod_send_buf(bus->sdiodev, frame, len);
-
- if (ret < 0) {
- /* On failure, abort the command and terminate the frame */
- brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
- ret);
- bus->sdcnt.tx_sderrs++;
-
- brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2);
-
- brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
- SFC_WF_TERM, NULL);
- bus->sdcnt.f1regdata++;
-
- for (i = 0; i < 3; i++) {
- u8 hi, lo;
- hi = brcmf_sdiod_regrb(bus->sdiodev,
- SBSDIO_FUNC1_WFRAMEBCHI, NULL);
- lo = brcmf_sdiod_regrb(bus->sdiodev,
- SBSDIO_FUNC1_WFRAMEBCLO, NULL);
- bus->sdcnt.f1regdata += 2;
- if (hi == 0 && lo == 0)
- break;
- }
- return ret;
- }
-
- bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;
-
- return ret;
-}
-
static int
brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
{
- u8 *frame;
- u16 len, pad;
- uint retries = 0;
- u8 doff = 0;
- int ret = -1;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
struct brcmf_sdio *bus = sdiodev->bus;
- struct brcmf_sdio_hdrinfo hd_info = {0};
+ int ret = -1;
brcmf_dbg(TRACE, "Enter\n");
- /* Back the pointer to make a room for bus header */
- frame = msg - bus->tx_hdrlen;
- len = (msglen += bus->tx_hdrlen);
-
- /* Add alignment padding (optional for ctl frames) */
- doff = ((unsigned long)frame % bus->head_align);
- if (doff) {
- frame -= doff;
- len += doff;
- msglen += doff;
- memset(frame, 0, doff + bus->tx_hdrlen);
- }
- /* precondition: doff < bus->head_align */
- doff += bus->tx_hdrlen;
-
- /* Round send length to next SDIO block */
- pad = 0;
- if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
- pad = bus->blocksize - (len % bus->blocksize);
- if ((pad > bus->roundup) || (pad >= bus->blocksize))
- pad = 0;
- } else if (len % bus->head_align) {
- pad = bus->head_align - (len % bus->head_align);
- }
- len += pad;
-
- /* precondition: IS_ALIGNED((unsigned long)frame, 2) */
-
- /* Make sure backplane clock is on */
- sdio_claim_host(bus->sdiodev->func[1]);
- brcmf_sdio_bus_sleep(bus, false, false);
- sdio_release_host(bus->sdiodev->func[1]);
-
- hd_info.len = (u16)msglen;
- hd_info.channel = SDPCM_CONTROL_CHANNEL;
- hd_info.dat_offset = doff;
- hd_info.seq_num = bus->tx_seq;
- hd_info.lastfrm = true;
- hd_info.tail_pad = pad;
- brcmf_sdio_hdpack(bus, frame, &hd_info);
-
- if (bus->txglom)
- brcmf_sdio_update_hwhdr(frame, len);
+ if (down_interruptible(&bus->tx_seq_lock))
+ return -EINTR;
if (!data_ok(bus)) {
brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n",
bus->tx_max, bus->tx_seq);
- bus->ctrl_frame_stat = true;
+ up(&bus->tx_seq_lock);
/* Send from dpc */
- bus->ctrl_frame_buf = frame;
- bus->ctrl_frame_len = len;
+ bus->ctrl_frame_buf = msg;
+ bus->ctrl_frame_len = msglen;
+ bus->ctrl_frame_stat = true;
wait_event_interruptible_timeout(bus->ctrl_wait,
!bus->ctrl_frame_stat,
@@ -2774,31 +2890,18 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
ret = 0;
} else {
brcmf_dbg(SDIO, "ctrl_frame_stat == true\n");
+ bus->ctrl_frame_stat = false;
+ if (down_interruptible(&bus->tx_seq_lock))
+ return -EINTR;
ret = -1;
}
}
-
if (ret == -1) {
- brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(),
- frame, len, "Tx Frame:\n");
- brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && BRCMF_CTL_ON()) &&
- BRCMF_HDRS_ON(),
- frame, min_t(u16, len, 16), "TxHdr:\n");
-
- do {
- sdio_claim_host(bus->sdiodev->func[1]);
- ret = brcmf_sdio_tx_frame(bus, frame, len);
- sdio_release_host(bus->sdiodev->func[1]);
- } while (ret < 0 && retries++ < TXRETRIES);
- }
-
- if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) &&
- atomic_read(&bus->dpc_tskcnt) == 0) {
- bus->activity = false;
sdio_claim_host(bus->sdiodev->func[1]);
- brcmf_dbg(INFO, "idle\n");
- brcmf_sdio_clkctl(bus, CLK_NONE, true);
+ brcmf_sdio_bus_sleep(bus, false, false);
+ ret = brcmf_sdio_tx_ctrlframe(bus, msg, msglen);
sdio_release_host(bus->sdiodev->func[1]);
+ up(&bus->tx_seq_lock);
}
if (ret)
@@ -2810,72 +2913,6 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
}
#ifdef DEBUG
-static inline bool brcmf_sdio_valid_shared_address(u32 addr)
-{
- return !(addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff));
-}
-
-static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
- struct sdpcm_shared *sh)
-{
- u32 addr;
- int rv;
- u32 shaddr = 0;
- struct sdpcm_shared_le sh_le;
- __le32 addr_le;
-
- shaddr = bus->ci->rambase + bus->ramsize - 4;
-
- /*
- * Read last word in socram to determine
- * address of sdpcm_shared structure
- */
- sdio_claim_host(bus->sdiodev->func[1]);
- brcmf_sdio_bus_sleep(bus, false, false);
- rv = brcmf_sdiod_ramrw(bus->sdiodev, false, shaddr, (u8 *)&addr_le, 4);
- sdio_release_host(bus->sdiodev->func[1]);
- if (rv < 0)
- return rv;
-
- addr = le32_to_cpu(addr_le);
-
- brcmf_dbg(SDIO, "sdpcm_shared address 0x%08X\n", addr);
-
- /*
- * Check if addr is valid.
- * NVRAM length at the end of memory should have been overwritten.
- */
- if (!brcmf_sdio_valid_shared_address(addr)) {
- brcmf_err("invalid sdpcm_shared address 0x%08X\n",
- addr);
- return -EINVAL;
- }
-
- /* Read hndrte_shared structure */
- rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, (u8 *)&sh_le,
- sizeof(struct sdpcm_shared_le));
- if (rv < 0)
- return rv;
-
- /* Endianness */
- sh->flags = le32_to_cpu(sh_le.flags);
- sh->trap_addr = le32_to_cpu(sh_le.trap_addr);
- sh->assert_exp_addr = le32_to_cpu(sh_le.assert_exp_addr);
- sh->assert_file_addr = le32_to_cpu(sh_le.assert_file_addr);
- sh->assert_line = le32_to_cpu(sh_le.assert_line);
- sh->console_addr = le32_to_cpu(sh_le.console_addr);
- sh->msgtrace_addr = le32_to_cpu(sh_le.msgtrace_addr);
-
- if ((sh->flags & SDPCM_SHARED_VERSION_MASK) > SDPCM_SHARED_VERSION) {
- brcmf_err("sdpcm shared version unsupported: dhd %d dongle %d\n",
- SDPCM_SHARED_VERSION,
- sh->flags & SDPCM_SHARED_VERSION_MASK);
- return -EPROTO;
- }
-
- return 0;
-}
-
static int brcmf_sdio_dump_console(struct brcmf_sdio *bus,
struct sdpcm_shared *sh, char __user *data,
size_t count)
@@ -3105,6 +3142,8 @@ static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
debugfs_create_file("forensics", S_IRUGO, dentry, bus,
&brcmf_sdio_forensic_ops);
brcmf_debugfs_create_sdio_count(drvr, &bus->sdcnt);
+ debugfs_create_u32("console_interval", 0644, dentry,
+ &bus->console_interval);
}
#else
static int brcmf_sdio_checkdied(struct brcmf_sdio *bus)
@@ -3223,32 +3262,17 @@ static int brcmf_sdio_download_code_file(struct brcmf_sdio *bus,
const struct firmware *fw)
{
int err;
- int offset;
- int address;
- int len;
brcmf_dbg(TRACE, "Enter\n");
- err = 0;
- offset = 0;
- address = bus->ci->rambase;
- while (offset < fw->size) {
- len = ((offset + MEMBLOCK) < fw->size) ? MEMBLOCK :
- fw->size - offset;
- err = brcmf_sdiod_ramrw(bus->sdiodev, true, address,
- (u8 *)&fw->data[offset], len);
- if (err) {
- brcmf_err("error %d on writing %d membytes at 0x%08x\n",
- err, len, address);
- return err;
- }
- offset += len;
- address += len;
- }
- if (!err)
- if (!brcmf_sdio_verifymemory(bus->sdiodev, bus->ci->rambase,
- (u8 *)fw->data, fw->size))
- err = -EIO;
+ err = brcmf_sdiod_ramrw(bus->sdiodev, true, bus->ci->rambase,
+ (u8 *)fw->data, fw->size);
+ if (err)
+ brcmf_err("error %d on writing %d membytes at 0x%08x\n",
+ err, (int)fw->size, bus->ci->rambase);
+ else if (!brcmf_sdio_verifymemory(bus->sdiodev, bus->ci->rambase,
+ (u8 *)fw->data, fw->size))
+ err = -EIO;
return err;
}
@@ -3291,7 +3315,7 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus)
brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
/* Keep arm in reset */
- brcmf_sdio_chip_enter_download(bus->sdiodev, bus->ci);
+ brcmf_chip_enter_download(bus->ci);
fw = brcmf_sdio_get_fw(bus, BRCMF_FIRMWARE_BIN);
if (fw == NULL) {
@@ -3323,7 +3347,7 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus)
}
/* Take arm out of reset */
- if (!brcmf_sdio_chip_exit_download(bus->sdiodev, bus->ci, rstvec)) {
+ if (!brcmf_chip_exit_download(bus->ci, rstvec)) {
brcmf_err("error getting out of ARM core reset\n");
goto err;
}
@@ -3338,40 +3362,6 @@ err:
return bcmerror;
}
-static bool brcmf_sdio_sr_capable(struct brcmf_sdio *bus)
-{
- u32 addr, reg, pmu_cc3_mask = ~0;
- int err;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- /* old chips with PMU version less than 17 don't support save restore */
- if (bus->ci->pmurev < 17)
- return false;
-
- switch (bus->ci->chip) {
- case BCM43241_CHIP_ID:
- case BCM4335_CHIP_ID:
- case BCM4339_CHIP_ID:
- /* read PMU chipcontrol register 3 */
- addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_addr);
- brcmf_sdiod_regwl(bus->sdiodev, addr, 3, NULL);
- addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_data);
- reg = brcmf_sdiod_regrl(bus->sdiodev, addr, NULL);
- return (reg & pmu_cc3_mask) != 0;
- default:
- addr = CORE_CC_REG(bus->ci->c_inf[0].base, pmucapabilities_ext);
- reg = brcmf_sdiod_regrl(bus->sdiodev, addr, &err);
- if ((reg & PCAPEXT_SR_SUPPORTED_MASK) == 0)
- return false;
-
- addr = CORE_CC_REG(bus->ci->c_inf[0].base, retention_ctl);
- reg = brcmf_sdiod_regrl(bus->sdiodev, addr, NULL);
- return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK |
- PMU_RCTL_LOGIC_DISABLE_MASK)) == 0;
- }
-}
-
static void brcmf_sdio_sr_init(struct brcmf_sdio *bus)
{
int err = 0;
@@ -3423,7 +3413,7 @@ static int brcmf_sdio_kso_init(struct brcmf_sdio *bus)
brcmf_dbg(TRACE, "Enter\n");
/* KSO bit added in SDIO core rev 12 */
- if (bus->ci->c_inf[1].rev < 12)
+ if (brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV)->rev < 12)
return 0;
val = brcmf_sdiod_regrb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, &err);
@@ -3454,15 +3444,13 @@ static int brcmf_sdio_bus_preinit(struct device *dev)
struct brcmf_sdio *bus = sdiodev->bus;
uint pad_size;
u32 value;
- u8 idx;
int err;
/* the commands below use the terms tx and rx from
* a device perspective, ie. bus:txglom affects the
* bus transfers from device to host.
*/
- idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
- if (bus->ci->c_inf[idx].rev < 12) {
+ if (brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV)->rev < 12) {
/* for sdio core rev < 12, disable txgloming */
value = 0;
err = brcmf_iovar_data_set(dev, "bus:txglom", &value,
@@ -3486,10 +3474,6 @@ static int brcmf_sdio_bus_preinit(struct device *dev)
bus->txglom = false;
value = 1;
pad_size = bus->sdiodev->func[2]->cur_blksize << 1;
- bus->txglom_sgpad = brcmu_pkt_buf_get_skb(pad_size);
- if (!bus->txglom_sgpad)
- brcmf_err("allocating txglom padding skb failed, reduced performance\n");
-
err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom",
&value, sizeof(u32));
if (err < 0) {
@@ -3573,7 +3557,7 @@ static int brcmf_sdio_bus_init(struct device *dev)
ret = -ENODEV;
}
- if (brcmf_sdio_sr_capable(bus)) {
+ if (brcmf_chip_sr_capable(bus->ci)) {
brcmf_sdio_sr_init(bus);
} else {
/* Restore previous clock setting */
@@ -3717,11 +3701,175 @@ static void brcmf_sdio_dataworker(struct work_struct *work)
datawork);
while (atomic_read(&bus->dpc_tskcnt)) {
+ atomic_set(&bus->dpc_tskcnt, 0);
brcmf_sdio_dpc(bus);
- atomic_dec(&bus->dpc_tskcnt);
}
}
+static void
+brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
+ struct brcmf_chip *ci, u32 drivestrength)
+{
+ const struct sdiod_drive_str *str_tab = NULL;
+ u32 str_mask;
+ u32 str_shift;
+ u32 base;
+ u32 i;
+ u32 drivestrength_sel = 0;
+ u32 cc_data_temp;
+ u32 addr;
+
+ if (!(ci->cc_caps & CC_CAP_PMU))
+ return;
+
+ switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
+ case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12):
+ str_tab = sdiod_drvstr_tab1_1v8;
+ str_mask = 0x00003800;
+ str_shift = 11;
+ break;
+ case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17):
+ str_tab = sdiod_drvstr_tab6_1v8;
+ str_mask = 0x00001800;
+ str_shift = 11;
+ break;
+ case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17):
+ /* note: 43143 does not support tristate */
+ i = ARRAY_SIZE(sdiod_drvstr_tab2_3v3) - 1;
+ if (drivestrength >= sdiod_drvstr_tab2_3v3[i].strength) {
+ str_tab = sdiod_drvstr_tab2_3v3;
+ str_mask = 0x00000007;
+ str_shift = 0;
+ } else
+ brcmf_err("Invalid SDIO Drive strength for chip %s, strength=%d\n",
+ ci->name, drivestrength);
+ break;
+ case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13):
+ str_tab = sdiod_drive_strength_tab5_1v8;
+ str_mask = 0x00003800;
+ str_shift = 11;
+ break;
+ default:
+ brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
+ ci->name, ci->chiprev, ci->pmurev);
+ break;
+ }
+
+ if (str_tab != NULL) {
+ for (i = 0; str_tab[i].strength != 0; i++) {
+ if (drivestrength >= str_tab[i].strength) {
+ drivestrength_sel = str_tab[i].sel;
+ break;
+ }
+ }
+ base = brcmf_chip_get_chipcommon(ci)->base;
+ addr = CORE_CC_REG(base, chipcontrol_addr);
+ brcmf_sdiod_regwl(sdiodev, addr, 1, NULL);
+ cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL);
+ cc_data_temp &= ~str_mask;
+ drivestrength_sel <<= str_shift;
+ cc_data_temp |= drivestrength_sel;
+ brcmf_sdiod_regwl(sdiodev, addr, cc_data_temp, NULL);
+
+ brcmf_dbg(INFO, "SDIO: %d mA (req=%d mA) drive strength selected, set to 0x%08x\n",
+ str_tab[i].strength, drivestrength, cc_data_temp);
+ }
+}
+
+static int brcmf_sdio_buscoreprep(void *ctx)
+{
+ struct brcmf_sdio_dev *sdiodev = ctx;
+ int err = 0;
+ u8 clkval, clkset;
+
+ /* Try forcing SDIO core to do ALPAvail request only */
+ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
+ brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
+ if (err) {
+ brcmf_err("error writing for HT off\n");
+ return err;
+ }
+
+ /* If register supported, wait for ALPAvail and then force ALP */
+ /* This may take up to 15 milliseconds */
+ clkval = brcmf_sdiod_regrb(sdiodev,
+ SBSDIO_FUNC1_CHIPCLKCSR, NULL);
+
+ if ((clkval & ~SBSDIO_AVBITS) != clkset) {
+ brcmf_err("ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
+ clkset, clkval);
+ return -EACCES;
+ }
+
+ SPINWAIT(((clkval = brcmf_sdiod_regrb(sdiodev,
+ SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
+ !SBSDIO_ALPAV(clkval)),
+ PMU_MAX_TRANSITION_DLY);
+ if (!SBSDIO_ALPAV(clkval)) {
+ brcmf_err("timeout on ALPAV wait, clkval 0x%02x\n",
+ clkval);
+ return -EBUSY;
+ }
+
+ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
+ brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
+ udelay(65);
+
+ /* Also, disable the extra SDIO pull-ups */
+ brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
+
+ return 0;
+}
+
+static void brcmf_sdio_buscore_exitdl(void *ctx, struct brcmf_chip *chip,
+ u32 rstvec)
+{
+ struct brcmf_sdio_dev *sdiodev = ctx;
+ struct brcmf_core *core;
+ u32 reg_addr;
+
+ /* clear all interrupts */
+ core = brcmf_chip_get_core(chip, BCMA_CORE_SDIO_DEV);
+ reg_addr = core->base + offsetof(struct sdpcmd_regs, intstatus);
+ brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
+
+ if (rstvec)
+ /* Write reset vector to address 0 */
+ brcmf_sdiod_ramrw(sdiodev, true, 0, (void *)&rstvec,
+ sizeof(rstvec));
+}
+
+static u32 brcmf_sdio_buscore_read32(void *ctx, u32 addr)
+{
+ struct brcmf_sdio_dev *sdiodev = ctx;
+ u32 val, rev;
+
+ val = brcmf_sdiod_regrl(sdiodev, addr, NULL);
+ if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 &&
+ addr == CORE_CC_REG(SI_ENUM_BASE, chipid)) {
+ rev = (val & CID_REV_MASK) >> CID_REV_SHIFT;
+ if (rev >= 2) {
+ val &= ~CID_ID_MASK;
+ val |= BCM4339_CHIP_ID;
+ }
+ }
+ return val;
+}
+
+static void brcmf_sdio_buscore_write32(void *ctx, u32 addr, u32 val)
+{
+ struct brcmf_sdio_dev *sdiodev = ctx;
+
+ brcmf_sdiod_regwl(sdiodev, addr, val, NULL);
+}
+
+static const struct brcmf_buscore_ops brcmf_sdio_buscore_ops = {
+ .prepare = brcmf_sdio_buscoreprep,
+ .exit_dl = brcmf_sdio_buscore_exitdl,
+ .read32 = brcmf_sdio_buscore_read32,
+ .write32 = brcmf_sdio_buscore_write32,
+};
+
static bool
brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
{
@@ -3737,7 +3885,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
brcmf_sdiod_regrl(bus->sdiodev, SI_ENUM_BASE, NULL));
/*
- * Force PLL off until brcmf_sdio_chip_attach()
+ * Force PLL off until brcmf_chip_attach()
* programs PLL control regs
*/
@@ -3758,8 +3906,10 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
*/
brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_DOWN);
- if (brcmf_sdio_chip_attach(bus->sdiodev, &bus->ci)) {
- brcmf_err("brcmf_sdio_chip_attach failed!\n");
+ bus->ci = brcmf_chip_attach(bus->sdiodev, &brcmf_sdio_buscore_ops);
+ if (IS_ERR(bus->ci)) {
+ brcmf_err("brcmf_chip_attach failed!\n");
+ bus->ci = NULL;
goto fail;
}
@@ -3772,7 +3922,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
drivestrength = bus->sdiodev->pdata->drive_strength;
else
drivestrength = DEFAULT_SDIO_DRIVE_STRENGTH;
- brcmf_sdio_chip_drivestrengthinit(bus->sdiodev, bus->ci, drivestrength);
+ brcmf_sdio_drivestrengthinit(bus->sdiodev, bus->ci, drivestrength);
/* Get info on the SOCRAM cores... */
bus->ramsize = bus->ci->ramsize;
@@ -3795,24 +3945,18 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
goto fail;
/* set PMUControl so a backplane reset does PMU state reload */
- reg_addr = CORE_CC_REG(bus->ci->c_inf[0].base,
+ reg_addr = CORE_CC_REG(brcmf_chip_get_chipcommon(bus->ci)->base,
pmucontrol);
- reg_val = brcmf_sdiod_regrl(bus->sdiodev,
- reg_addr,
- &err);
+ reg_val = brcmf_sdiod_regrl(bus->sdiodev, reg_addr, &err);
if (err)
goto fail;
reg_val |= (BCMA_CC_PMU_CTL_RES_RELOAD << BCMA_CC_PMU_CTL_RES_SHIFT);
- brcmf_sdiod_regwl(bus->sdiodev,
- reg_addr,
- reg_val,
- &err);
+ brcmf_sdiod_regwl(bus->sdiodev, reg_addr, reg_val, &err);
if (err)
goto fail;
-
sdio_release_host(bus->sdiodev->func[1]);
brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
@@ -3852,6 +3996,7 @@ brcmf_sdio_watchdog_thread(void *data)
brcmf_sdio_bus_watchdog(bus);
/* Count the tick for reference */
bus->sdcnt.tickcnt++;
+ reinit_completion(&bus->watchdog_wait);
} else
break;
}
@@ -3928,7 +4073,8 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
}
spin_lock_init(&bus->rxctl_lock);
- spin_lock_init(&bus->txqlock);
+ spin_lock_init(&bus->txq_lock);
+ sema_init(&bus->tx_seq_lock, 1);
init_waitqueue_head(&bus->ctrl_wait);
init_waitqueue_head(&bus->dcmd_resp_wait);
@@ -4027,14 +4173,14 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
/* De-register interrupt handler */
brcmf_sdiod_intr_unregister(bus->sdiodev);
- cancel_work_sync(&bus->datawork);
- if (bus->brcmf_wq)
- destroy_workqueue(bus->brcmf_wq);
-
if (bus->sdiodev->bus_if->drvr) {
brcmf_detach(bus->sdiodev->dev);
}
+ cancel_work_sync(&bus->datawork);
+ if (bus->brcmf_wq)
+ destroy_workqueue(bus->brcmf_wq);
+
if (bus->ci) {
if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) {
sdio_claim_host(bus->sdiodev->func[1]);
@@ -4045,15 +4191,13 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
* all necessary cores.
*/
msleep(20);
- brcmf_sdio_chip_enter_download(bus->sdiodev,
- bus->ci);
+ brcmf_chip_enter_download(bus->ci);
brcmf_sdio_clkctl(bus, CLK_NONE, false);
sdio_release_host(bus->sdiodev->func[1]);
}
- brcmf_sdio_chip_detach(&bus->ci);
+ brcmf_chip_detach(bus->ci);
}
- brcmu_pkt_buf_free_skb(bus->txglom_sgpad);
kfree(bus->rxbuf);
kfree(bus->hdrbuf);
kfree(bus);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
index 22adbe311d20..59a5af5bf994 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
@@ -124,7 +124,8 @@ brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data)
}
static u32
-brcmf_create_iovar(char *name, char *data, u32 datalen, char *buf, u32 buflen)
+brcmf_create_iovar(char *name, const char *data, u32 datalen,
+ char *buf, u32 buflen)
{
u32 len;
@@ -144,7 +145,7 @@ brcmf_create_iovar(char *name, char *data, u32 datalen, char *buf, u32 buflen)
s32
-brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data,
+brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, const void *data,
u32 len)
{
struct brcmf_pub *drvr = ifp->drvr;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h
index 77eae86e55c2..a30be683f4a1 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h
@@ -83,7 +83,7 @@ s32 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len);
s32 brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data);
s32 brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data);
-s32 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data,
+s32 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, const void *data,
u32 len);
s32 brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data,
u32 len);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
index af17a5bc8b83..614e4888504f 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
@@ -48,6 +48,11 @@
#define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */
+/* OBSS Coex Auto/On/Off */
+#define BRCMF_OBSS_COEX_AUTO (-1)
+#define BRCMF_OBSS_COEX_OFF 0
+#define BRCMF_OBSS_COEX_ON 1
+
enum brcmf_fil_p2p_if_types {
BRCMF_FIL_P2P_IF_CLIENT,
BRCMF_FIL_P2P_IF_GO,
@@ -87,6 +92,11 @@ struct brcmf_fil_bss_enable_le {
__le32 enable;
};
+struct brcmf_fil_bwcap_le {
+ __le32 band;
+ __le32 bw_cap;
+};
+
/**
* struct tdls_iovar - common structure for tdls iovars.
*
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
index fc4f98b275d7..f3445ac627e4 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
@@ -797,7 +797,8 @@ static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg,
/* SOCIAL CHANNELS 1, 6, 11 */
search_state = WL_P2P_DISC_ST_SEARCH;
brcmf_dbg(INFO, "P2P SEARCH PHASE START\n");
- } else if (dev != NULL && vif->mode == WL_MODE_AP) {
+ } else if (dev != NULL &&
+ vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
/* If you are already a GO, then do SEARCH only */
brcmf_dbg(INFO, "Already a GO. Do SEARCH Only\n");
search_state = WL_P2P_DISC_ST_SEARCH;
@@ -2256,7 +2257,6 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
struct brcmf_cfg80211_vif *vif;
enum brcmf_fil_p2p_if_types iftype;
- enum wl_mode mode;
int err;
if (brcmf_cfg80211_vif_event_armed(cfg))
@@ -2267,11 +2267,9 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
switch (type) {
case NL80211_IFTYPE_P2P_CLIENT:
iftype = BRCMF_FIL_P2P_IF_CLIENT;
- mode = WL_MODE_BSS;
break;
case NL80211_IFTYPE_P2P_GO:
iftype = BRCMF_FIL_P2P_IF_GO;
- mode = WL_MODE_AP;
break;
case NL80211_IFTYPE_P2P_DEVICE:
return brcmf_p2p_create_p2pdev(&cfg->p2p, wiphy,
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
deleted file mode 100644
index 82bf3c5d3cdc..000000000000
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
+++ /dev/null
@@ -1,972 +0,0 @@
-/*
- * Copyright (c) 2011 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-/* ***** SDIO interface chip backplane handle functions ***** */
-
-#include <linux/types.h>
-#include <linux/netdevice.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/sdio_ids.h>
-#include <linux/ssb/ssb_regs.h>
-#include <linux/bcma/bcma.h>
-
-#include <chipcommon.h>
-#include <brcm_hw_ids.h>
-#include <brcmu_wifi.h>
-#include <brcmu_utils.h>
-#include <soc.h>
-#include "dhd_dbg.h"
-#include "sdio_host.h"
-#include "sdio_chip.h"
-
-/* chip core base & ramsize */
-/* bcm4329 */
-/* SDIO device core, ID 0x829 */
-#define BCM4329_CORE_BUS_BASE 0x18011000
-/* internal memory core, ID 0x80e */
-#define BCM4329_CORE_SOCRAM_BASE 0x18003000
-/* ARM Cortex M3 core, ID 0x82a */
-#define BCM4329_CORE_ARM_BASE 0x18002000
-#define BCM4329_RAMSIZE 0x48000
-
-/* bcm43143 */
-/* SDIO device core */
-#define BCM43143_CORE_BUS_BASE 0x18002000
-/* internal memory core */
-#define BCM43143_CORE_SOCRAM_BASE 0x18004000
-/* ARM Cortex M3 core, ID 0x82a */
-#define BCM43143_CORE_ARM_BASE 0x18003000
-#define BCM43143_RAMSIZE 0x70000
-
-/* All D11 cores, ID 0x812 */
-#define BCM43xx_CORE_D11_BASE 0x18001000
-
-#define SBCOREREV(sbidh) \
- ((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \
- ((sbidh) & SSB_IDHIGH_RCLO))
-
-/* SOC Interconnect types (aka chip types) */
-#define SOCI_SB 0
-#define SOCI_AI 1
-
-/* EROM CompIdentB */
-#define CIB_REV_MASK 0xff000000
-#define CIB_REV_SHIFT 24
-
-/* ARM CR4 core specific control flag bits */
-#define ARMCR4_BCMA_IOCTL_CPUHALT 0x0020
-
-/* D11 core specific control flag bits */
-#define D11_BCMA_IOCTL_PHYCLOCKEN 0x0004
-#define D11_BCMA_IOCTL_PHYRESET 0x0008
-
-#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
-/* SDIO Pad drive strength to select value mappings */
-struct sdiod_drive_str {
- u8 strength; /* Pad Drive Strength in mA */
- u8 sel; /* Chip-specific select value */
-};
-/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8V) */
-static const struct sdiod_drive_str sdiod_drvstr_tab1_1v8[] = {
- {32, 0x6},
- {26, 0x7},
- {22, 0x4},
- {16, 0x5},
- {12, 0x2},
- {8, 0x3},
- {4, 0x0},
- {0, 0x1}
-};
-
-/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */
-static const struct sdiod_drive_str sdiod_drive_strength_tab5_1v8[] = {
- {6, 0x7},
- {5, 0x6},
- {4, 0x5},
- {3, 0x4},
- {2, 0x2},
- {1, 0x1},
- {0, 0x0}
-};
-
-/* SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */
-static const struct sdiod_drive_str sdiod_drvstr_tab6_1v8[] = {
- {3, 0x3},
- {2, 0x2},
- {1, 0x1},
- {0, 0x0} };
-
-/* SDIO Drive Strength to sel value table for 43143 PMU Rev 17 (3.3V) */
-static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = {
- {16, 0x7},
- {12, 0x5},
- {8, 0x3},
- {4, 0x1}
-};
-
-u8
-brcmf_sdio_chip_getinfidx(struct brcmf_chip *ci, u16 coreid)
-{
- u8 idx;
-
- for (idx = 0; idx < BRCMF_MAX_CORENUM; idx++)
- if (coreid == ci->c_inf[idx].id)
- return idx;
-
- return BRCMF_MAX_CORENUM;
-}
-
-static u32
-brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci, u16 coreid)
-{
- u32 regdata;
- u8 idx;
-
- idx = brcmf_sdio_chip_getinfidx(ci, coreid);
-
- regdata = brcmf_sdiod_regrl(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbidhigh),
- NULL);
- return SBCOREREV(regdata);
-}
-
-static u32
-brcmf_sdio_ai_corerev(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci, u16 coreid)
-{
- u8 idx;
-
- idx = brcmf_sdio_chip_getinfidx(ci, coreid);
-
- return (ci->c_inf[idx].cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
-}
-
-static bool
-brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci, u16 coreid)
-{
- u32 regdata;
- u8 idx;
-
- idx = brcmf_sdio_chip_getinfidx(ci, coreid);
- if (idx == BRCMF_MAX_CORENUM)
- return false;
-
- regdata = brcmf_sdiod_regrl(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
- NULL);
- regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
- SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
- return (SSB_TMSLOW_CLOCK == regdata);
-}
-
-static bool
-brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci, u16 coreid)
-{
- u32 regdata;
- u8 idx;
- bool ret;
-
- idx = brcmf_sdio_chip_getinfidx(ci, coreid);
- if (idx == BRCMF_MAX_CORENUM)
- return false;
-
- regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
- NULL);
- ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
-
- regdata = brcmf_sdiod_regrl(sdiodev,
- ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
- NULL);
- ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
-
- return ret;
-}
-
-static void
-brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits,
- u32 in_resetbits)
-{
- u32 regdata, base;
- u8 idx;
-
- idx = brcmf_sdio_chip_getinfidx(ci, coreid);
- base = ci->c_inf[idx].base;
-
- regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
- if (regdata & SSB_TMSLOW_RESET)
- return;
-
- regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
- if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
- /*
- * set target reject and spin until busy is clear
- * (preserve core-specific bits)
- */
- regdata = brcmf_sdiod_regrl(sdiodev,
- CORE_SB(base, sbtmstatelow), NULL);
- brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
- regdata | SSB_TMSLOW_REJECT, NULL);
-
- regdata = brcmf_sdiod_regrl(sdiodev,
- CORE_SB(base, sbtmstatelow), NULL);
- udelay(1);
- SPINWAIT((brcmf_sdiod_regrl(sdiodev,
- CORE_SB(base, sbtmstatehigh),
- NULL) &
- SSB_TMSHIGH_BUSY), 100000);
-
- regdata = brcmf_sdiod_regrl(sdiodev,
- CORE_SB(base, sbtmstatehigh),
- NULL);
- if (regdata & SSB_TMSHIGH_BUSY)
- brcmf_err("core state still busy\n");
-
- regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbidlow),
- NULL);
- if (regdata & SSB_IDLOW_INITIATOR) {
- regdata = brcmf_sdiod_regrl(sdiodev,
- CORE_SB(base, sbimstate),
- NULL);
- regdata |= SSB_IMSTATE_REJECT;
- brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbimstate),
- regdata, NULL);
- regdata = brcmf_sdiod_regrl(sdiodev,
- CORE_SB(base, sbimstate),
- NULL);
- udelay(1);
- SPINWAIT((brcmf_sdiod_regrl(sdiodev,
- CORE_SB(base, sbimstate),
- NULL) &
- SSB_IMSTATE_BUSY), 100000);
- }
-
- /* set reset and reject while enabling the clocks */
- regdata = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
- SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET;
- brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
- regdata, NULL);
- regdata = brcmf_sdiod_regrl(sdiodev,
- CORE_SB(base, sbtmstatelow), NULL);
- udelay(10);
-
- /* clear the initiator reject bit */
- regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbidlow),
- NULL);
- if (regdata & SSB_IDLOW_INITIATOR) {
- regdata = brcmf_sdiod_regrl(sdiodev,
- CORE_SB(base, sbimstate),
- NULL);
- regdata &= ~SSB_IMSTATE_REJECT;
- brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbimstate),
- regdata, NULL);
- }
- }
-
- /* leave reset and reject asserted */
- brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
- (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET), NULL);
- udelay(1);
-}
-
-static void
-brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits,
- u32 in_resetbits)
-{
- u8 idx;
- u32 regdata;
- u32 wrapbase;
-
- idx = brcmf_sdio_chip_getinfidx(ci, coreid);
- if (idx == BRCMF_MAX_CORENUM)
- return;
-
- wrapbase = ci->c_inf[idx].wrapbase;
-
- /* if core is already in reset, just return */
- regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_RESET_CTL, NULL);
- if ((regdata & BCMA_RESET_CTL_RESET) != 0)
- return;
-
- /* configure reset */
- brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_IOCTL, pre_resetbits |
- BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
- regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL);
-
- /* put in reset */
- brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_RESET_CTL,
- BCMA_RESET_CTL_RESET, NULL);
- usleep_range(10, 20);
-
- /* wait till reset is 1 */
- SPINWAIT(brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_RESET_CTL, NULL) !=
- BCMA_RESET_CTL_RESET, 300);
-
- /* post reset configure */
- brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_IOCTL, pre_resetbits |
- BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
- regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL);
-}
-
-static void
-brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits,
- u32 in_resetbits, u32 post_resetbits)
-{
- u32 regdata;
- u8 idx;
-
- idx = brcmf_sdio_chip_getinfidx(ci, coreid);
- if (idx == BRCMF_MAX_CORENUM)
- return;
-
- /*
- * Must do the disable sequence first to work for
- * arbitrary current core state.
- */
- brcmf_sdio_sb_coredisable(sdiodev, ci, coreid, pre_resetbits,
- in_resetbits);
-
- /*
- * Now do the initialization sequence.
- * set reset while enabling the clock and
- * forcing them on throughout the core
- */
- brcmf_sdiod_regwl(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
- SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET,
- NULL);
- regdata = brcmf_sdiod_regrl(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
- NULL);
- udelay(1);
-
- /* clear any serror */
- regdata = brcmf_sdiod_regrl(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
- NULL);
- if (regdata & SSB_TMSHIGH_SERR)
- brcmf_sdiod_regwl(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
- 0, NULL);
-
- regdata = brcmf_sdiod_regrl(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbimstate),
- NULL);
- if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO))
- brcmf_sdiod_regwl(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbimstate),
- regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO),
- NULL);
-
- /* clear reset and allow it to propagate throughout the core */
- brcmf_sdiod_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
- SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK, NULL);
- regdata = brcmf_sdiod_regrl(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
- NULL);
- udelay(1);
-
- /* leave clock enabled */
- brcmf_sdiod_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
- SSB_TMSLOW_CLOCK, NULL);
- regdata = brcmf_sdiod_regrl(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
- NULL);
- udelay(1);
-}
-
-static void
-brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits,
- u32 in_resetbits, u32 post_resetbits)
-{
- u8 idx;
- u32 regdata;
- u32 wrapbase;
-
- idx = brcmf_sdio_chip_getinfidx(ci, coreid);
- if (idx == BRCMF_MAX_CORENUM)
- return;
-
- wrapbase = ci->c_inf[idx].wrapbase;
-
- /* must disable first to work for arbitrary current core state */
- brcmf_sdio_ai_coredisable(sdiodev, ci, coreid, pre_resetbits,
- in_resetbits);
-
- while (brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_RESET_CTL, NULL) &
- BCMA_RESET_CTL_RESET) {
- brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_RESET_CTL, 0, NULL);
- usleep_range(40, 60);
- }
-
- brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_IOCTL, post_resetbits |
- BCMA_IOCTL_CLK, NULL);
- regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL);
-}
-
-#ifdef DEBUG
-/* safety check for chipinfo */
-static int brcmf_sdio_chip_cichk(struct brcmf_chip *ci)
-{
- u8 core_idx;
-
- /* check RAM core presence for ARM CM3 core */
- core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
- if (BRCMF_MAX_CORENUM != core_idx) {
- core_idx = brcmf_sdio_chip_getinfidx(ci,
- BCMA_CORE_INTERNAL_MEM);
- if (BRCMF_MAX_CORENUM == core_idx) {
- brcmf_err("RAM core not provided with ARM CM3 core\n");
- return -ENODEV;
- }
- }
-
- /* check RAM base for ARM CR4 core */
- core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CR4);
- if (BRCMF_MAX_CORENUM != core_idx) {
- if (ci->rambase == 0) {
- brcmf_err("RAM base not provided with ARM CR4 core\n");
- return -ENOMEM;
- }
- }
-
- return 0;
-}
-#else /* DEBUG */
-static inline int brcmf_sdio_chip_cichk(struct brcmf_chip *ci)
-{
- return 0;
-}
-#endif
-
-static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci)
-{
- u32 regdata;
- u32 socitype;
-
- /* Get CC core rev
- * Chipid is assume to be at offset 0 from SI_ENUM_BASE
- * For different chiptypes or old sdio hosts w/o chipcommon,
- * other ways of recognition should be added here.
- */
- regdata = brcmf_sdiod_regrl(sdiodev,
- CORE_CC_REG(SI_ENUM_BASE, chipid),
- NULL);
- ci->chip = regdata & CID_ID_MASK;
- ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
- if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 &&
- ci->chiprev >= 2)
- ci->chip = BCM4339_CHIP_ID;
- socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
-
- brcmf_dbg(INFO, "found %s chip: id=0x%x, rev=%d\n",
- socitype == SOCI_SB ? "SB" : "AXI", ci->chip, ci->chiprev);
-
- if (socitype == SOCI_SB) {
- if (ci->chip != BCM4329_CHIP_ID) {
- brcmf_err("SB chip is not supported\n");
- return -ENODEV;
- }
- ci->iscoreup = brcmf_sdio_sb_iscoreup;
- ci->corerev = brcmf_sdio_sb_corerev;
- ci->coredisable = brcmf_sdio_sb_coredisable;
- ci->resetcore = brcmf_sdio_sb_resetcore;
-
- ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
- ci->c_inf[0].base = SI_ENUM_BASE;
- ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
- ci->c_inf[1].base = BCM4329_CORE_BUS_BASE;
- ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
- ci->c_inf[2].base = BCM4329_CORE_SOCRAM_BASE;
- ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
- ci->c_inf[3].base = BCM4329_CORE_ARM_BASE;
- ci->c_inf[4].id = BCMA_CORE_80211;
- ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
- ci->ramsize = BCM4329_RAMSIZE;
- } else if (socitype == SOCI_AI) {
- ci->iscoreup = brcmf_sdio_ai_iscoreup;
- ci->corerev = brcmf_sdio_ai_corerev;
- ci->coredisable = brcmf_sdio_ai_coredisable;
- ci->resetcore = brcmf_sdio_ai_resetcore;
-
- ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
- ci->c_inf[0].base = SI_ENUM_BASE;
-
- /* Address of cores for new chips should be added here */
- switch (ci->chip) {
- case BCM43143_CHIP_ID:
- ci->c_inf[0].wrapbase = ci->c_inf[0].base + 0x00100000;
- ci->c_inf[0].cib = 0x2b000000;
- ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
- ci->c_inf[1].base = BCM43143_CORE_BUS_BASE;
- ci->c_inf[1].wrapbase = ci->c_inf[1].base + 0x00100000;
- ci->c_inf[1].cib = 0x18000000;
- ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
- ci->c_inf[2].base = BCM43143_CORE_SOCRAM_BASE;
- ci->c_inf[2].wrapbase = ci->c_inf[2].base + 0x00100000;
- ci->c_inf[2].cib = 0x14000000;
- ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
- ci->c_inf[3].base = BCM43143_CORE_ARM_BASE;
- ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000;
- ci->c_inf[3].cib = 0x07000000;
- ci->c_inf[4].id = BCMA_CORE_80211;
- ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
- ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000;
- ci->ramsize = BCM43143_RAMSIZE;
- break;
- case BCM43241_CHIP_ID:
- ci->c_inf[0].wrapbase = 0x18100000;
- ci->c_inf[0].cib = 0x2a084411;
- ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
- ci->c_inf[1].base = 0x18002000;
- ci->c_inf[1].wrapbase = 0x18102000;
- ci->c_inf[1].cib = 0x0e004211;
- ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
- ci->c_inf[2].base = 0x18004000;
- ci->c_inf[2].wrapbase = 0x18104000;
- ci->c_inf[2].cib = 0x14080401;
- ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
- ci->c_inf[3].base = 0x18003000;
- ci->c_inf[3].wrapbase = 0x18103000;
- ci->c_inf[3].cib = 0x07004211;
- ci->c_inf[4].id = BCMA_CORE_80211;
- ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
- ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000;
- ci->ramsize = 0x90000;
- break;
- case BCM4330_CHIP_ID:
- ci->c_inf[0].wrapbase = 0x18100000;
- ci->c_inf[0].cib = 0x27004211;
- ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
- ci->c_inf[1].base = 0x18002000;
- ci->c_inf[1].wrapbase = 0x18102000;
- ci->c_inf[1].cib = 0x07004211;
- ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
- ci->c_inf[2].base = 0x18004000;
- ci->c_inf[2].wrapbase = 0x18104000;
- ci->c_inf[2].cib = 0x0d080401;
- ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
- ci->c_inf[3].base = 0x18003000;
- ci->c_inf[3].wrapbase = 0x18103000;
- ci->c_inf[3].cib = 0x03004211;
- ci->c_inf[4].id = BCMA_CORE_80211;
- ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
- ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000;
- ci->ramsize = 0x48000;
- break;
- case BCM4334_CHIP_ID:
- ci->c_inf[0].wrapbase = 0x18100000;
- ci->c_inf[0].cib = 0x29004211;
- ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
- ci->c_inf[1].base = 0x18002000;
- ci->c_inf[1].wrapbase = 0x18102000;
- ci->c_inf[1].cib = 0x0d004211;
- ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
- ci->c_inf[2].base = 0x18004000;
- ci->c_inf[2].wrapbase = 0x18104000;
- ci->c_inf[2].cib = 0x13080401;
- ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
- ci->c_inf[3].base = 0x18003000;
- ci->c_inf[3].wrapbase = 0x18103000;
- ci->c_inf[3].cib = 0x07004211;
- ci->c_inf[4].id = BCMA_CORE_80211;
- ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
- ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000;
- ci->ramsize = 0x80000;
- break;
- case BCM4335_CHIP_ID:
- ci->c_inf[0].wrapbase = 0x18100000;
- ci->c_inf[0].cib = 0x2b084411;
- ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
- ci->c_inf[1].base = 0x18005000;
- ci->c_inf[1].wrapbase = 0x18105000;
- ci->c_inf[1].cib = 0x0f004211;
- ci->c_inf[2].id = BCMA_CORE_ARM_CR4;
- ci->c_inf[2].base = 0x18002000;
- ci->c_inf[2].wrapbase = 0x18102000;
- ci->c_inf[2].cib = 0x01084411;
- ci->c_inf[3].id = BCMA_CORE_80211;
- ci->c_inf[3].base = BCM43xx_CORE_D11_BASE;
- ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000;
- ci->ramsize = 0xc0000;
- ci->rambase = 0x180000;
- break;
- case BCM43362_CHIP_ID:
- ci->c_inf[0].wrapbase = 0x18100000;
- ci->c_inf[0].cib = 0x27004211;
- ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
- ci->c_inf[1].base = 0x18002000;
- ci->c_inf[1].wrapbase = 0x18102000;
- ci->c_inf[1].cib = 0x0a004211;
- ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
- ci->c_inf[2].base = 0x18004000;
- ci->c_inf[2].wrapbase = 0x18104000;
- ci->c_inf[2].cib = 0x08080401;
- ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
- ci->c_inf[3].base = 0x18003000;
- ci->c_inf[3].wrapbase = 0x18103000;
- ci->c_inf[3].cib = 0x03004211;
- ci->c_inf[4].id = BCMA_CORE_80211;
- ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
- ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000;
- ci->ramsize = 0x3C000;
- break;
- case BCM4339_CHIP_ID:
- ci->c_inf[0].wrapbase = 0x18100000;
- ci->c_inf[0].cib = 0x2e084411;
- ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
- ci->c_inf[1].base = 0x18005000;
- ci->c_inf[1].wrapbase = 0x18105000;
- ci->c_inf[1].cib = 0x15004211;
- ci->c_inf[2].id = BCMA_CORE_ARM_CR4;
- ci->c_inf[2].base = 0x18002000;
- ci->c_inf[2].wrapbase = 0x18102000;
- ci->c_inf[2].cib = 0x04084411;
- ci->c_inf[3].id = BCMA_CORE_80211;
- ci->c_inf[3].base = BCM43xx_CORE_D11_BASE;
- ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000;
- ci->ramsize = 0xc0000;
- ci->rambase = 0x180000;
- break;
- default:
- brcmf_err("AXI chip is not supported\n");
- return -ENODEV;
- }
- } else {
- brcmf_err("chip backplane type %u is not supported\n",
- socitype);
- return -ENODEV;
- }
-
- return brcmf_sdio_chip_cichk(ci);
-}
-
-static int
-brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
-{
- int err = 0;
- u8 clkval, clkset;
-
- /* Try forcing SDIO core to do ALPAvail request only */
- clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
- brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
- if (err) {
- brcmf_err("error writing for HT off\n");
- return err;
- }
-
- /* If register supported, wait for ALPAvail and then force ALP */
- /* This may take up to 15 milliseconds */
- clkval = brcmf_sdiod_regrb(sdiodev,
- SBSDIO_FUNC1_CHIPCLKCSR, NULL);
-
- if ((clkval & ~SBSDIO_AVBITS) != clkset) {
- brcmf_err("ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
- clkset, clkval);
- return -EACCES;
- }
-
- SPINWAIT(((clkval = brcmf_sdiod_regrb(sdiodev,
- SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
- !SBSDIO_ALPAV(clkval)),
- PMU_MAX_TRANSITION_DLY);
- if (!SBSDIO_ALPAV(clkval)) {
- brcmf_err("timeout on ALPAV wait, clkval 0x%02x\n",
- clkval);
- return -EBUSY;
- }
-
- clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
- brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
- udelay(65);
-
- /* Also, disable the extra SDIO pull-ups */
- brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
-
- return 0;
-}
-
-static void
-brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci)
-{
- u32 base = ci->c_inf[0].base;
-
- /* get chipcommon rev */
- ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
-
- /* get chipcommon capabilites */
- ci->c_inf[0].caps = brcmf_sdiod_regrl(sdiodev,
- CORE_CC_REG(base, capabilities),
- NULL);
-
- /* get pmu caps & rev */
- if (ci->c_inf[0].caps & CC_CAP_PMU) {
- ci->pmucaps =
- brcmf_sdiod_regrl(sdiodev,
- CORE_CC_REG(base, pmucapabilities),
- NULL);
- ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
- }
-
- ci->c_inf[1].rev = ci->corerev(sdiodev, ci, ci->c_inf[1].id);
-
- brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
- ci->c_inf[0].rev, ci->pmurev,
- ci->c_inf[1].rev, ci->c_inf[1].id);
-
- /*
- * Make sure any on-chip ARM is off (in case strapping is wrong),
- * or downloaded code was already running.
- */
- ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0, 0);
-}
-
-int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip **ci_ptr)
-{
- int ret;
- struct brcmf_chip *ci;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- ci = kzalloc(sizeof(*ci), GFP_ATOMIC);
- if (!ci)
- return -ENOMEM;
-
- ret = brcmf_sdio_chip_buscoreprep(sdiodev);
- if (ret != 0)
- goto err;
-
- ret = brcmf_sdio_chip_recognition(sdiodev, ci);
- if (ret != 0)
- goto err;
-
- brcmf_sdio_chip_buscoresetup(sdiodev, ci);
-
- brcmf_sdiod_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopullup),
- 0, NULL);
- brcmf_sdiod_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopulldown),
- 0, NULL);
-
- *ci_ptr = ci;
- return 0;
-
-err:
- kfree(ci);
- return ret;
-}
-
-void
-brcmf_sdio_chip_detach(struct brcmf_chip **ci_ptr)
-{
- brcmf_dbg(TRACE, "Enter\n");
-
- kfree(*ci_ptr);
- *ci_ptr = NULL;
-}
-
-static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len)
-{
- const char *fmt;
-
- fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
- snprintf(buf, len, fmt, chipid);
- return buf;
-}
-
-void
-brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci, u32 drivestrength)
-{
- const struct sdiod_drive_str *str_tab = NULL;
- u32 str_mask;
- u32 str_shift;
- char chn[8];
- u32 base = ci->c_inf[0].base;
- u32 i;
- u32 drivestrength_sel = 0;
- u32 cc_data_temp;
- u32 addr;
-
- if (!(ci->c_inf[0].caps & CC_CAP_PMU))
- return;
-
- switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
- case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12):
- str_tab = sdiod_drvstr_tab1_1v8;
- str_mask = 0x00003800;
- str_shift = 11;
- break;
- case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17):
- str_tab = sdiod_drvstr_tab6_1v8;
- str_mask = 0x00001800;
- str_shift = 11;
- break;
- case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17):
- /* note: 43143 does not support tristate */
- i = ARRAY_SIZE(sdiod_drvstr_tab2_3v3) - 1;
- if (drivestrength >= sdiod_drvstr_tab2_3v3[i].strength) {
- str_tab = sdiod_drvstr_tab2_3v3;
- str_mask = 0x00000007;
- str_shift = 0;
- } else
- brcmf_err("Invalid SDIO Drive strength for chip %s, strength=%d\n",
- brcmf_sdio_chip_name(ci->chip, chn, 8),
- drivestrength);
- break;
- case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13):
- str_tab = sdiod_drive_strength_tab5_1v8;
- str_mask = 0x00003800;
- str_shift = 11;
- break;
- default:
- brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
- brcmf_sdio_chip_name(ci->chip, chn, 8),
- ci->chiprev, ci->pmurev);
- break;
- }
-
- if (str_tab != NULL) {
- for (i = 0; str_tab[i].strength != 0; i++) {
- if (drivestrength >= str_tab[i].strength) {
- drivestrength_sel = str_tab[i].sel;
- break;
- }
- }
- addr = CORE_CC_REG(base, chipcontrol_addr);
- brcmf_sdiod_regwl(sdiodev, addr, 1, NULL);
- cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL);
- cc_data_temp &= ~str_mask;
- drivestrength_sel <<= str_shift;
- cc_data_temp |= drivestrength_sel;
- brcmf_sdiod_regwl(sdiodev, addr, cc_data_temp, NULL);
-
- brcmf_dbg(INFO, "SDIO: %d mA (req=%d mA) drive strength selected, set to 0x%08x\n",
- str_tab[i].strength, drivestrength, cc_data_temp);
- }
-}
-
-static void
-brcmf_sdio_chip_cm3_enterdl(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci)
-{
- ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0, 0);
- ci->resetcore(sdiodev, ci, BCMA_CORE_80211,
- D11_BCMA_IOCTL_PHYRESET | D11_BCMA_IOCTL_PHYCLOCKEN,
- D11_BCMA_IOCTL_PHYCLOCKEN, D11_BCMA_IOCTL_PHYCLOCKEN);
- ci->resetcore(sdiodev, ci, BCMA_CORE_INTERNAL_MEM, 0, 0, 0);
-}
-
-static bool brcmf_sdio_chip_cm3_exitdl(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci)
-{
- u8 core_idx;
- u32 reg_addr;
-
- if (!ci->iscoreup(sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) {
- brcmf_err("SOCRAM core is down after reset?\n");
- return false;
- }
-
- /* clear all interrupts */
- core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
- reg_addr = ci->c_inf[core_idx].base;
- reg_addr += offsetof(struct sdpcmd_regs, intstatus);
- brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
-
- ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CM3, 0, 0, 0);
-
- return true;
-}
-
-static inline void
-brcmf_sdio_chip_cr4_enterdl(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci)
-{
- u8 idx;
- u32 regdata;
- u32 wrapbase;
- idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CR4);
-
- if (idx == BRCMF_MAX_CORENUM)
- return;
-
- wrapbase = ci->c_inf[idx].wrapbase;
- regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL);
- regdata &= ARMCR4_BCMA_IOCTL_CPUHALT;
- ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, regdata,
- ARMCR4_BCMA_IOCTL_CPUHALT, ARMCR4_BCMA_IOCTL_CPUHALT);
- ci->resetcore(sdiodev, ci, BCMA_CORE_80211,
- D11_BCMA_IOCTL_PHYRESET | D11_BCMA_IOCTL_PHYCLOCKEN,
- D11_BCMA_IOCTL_PHYCLOCKEN, D11_BCMA_IOCTL_PHYCLOCKEN);
-}
-
-static bool brcmf_sdio_chip_cr4_exitdl(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci, u32 rstvec)
-{
- u8 core_idx;
- u32 reg_addr;
-
- /* clear all interrupts */
- core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
- reg_addr = ci->c_inf[core_idx].base;
- reg_addr += offsetof(struct sdpcmd_regs, intstatus);
- brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
-
- /* Write reset vector to address 0 */
- brcmf_sdiod_ramrw(sdiodev, true, 0, (void *)&rstvec,
- sizeof(rstvec));
-
- /* restore ARM */
- ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, ARMCR4_BCMA_IOCTL_CPUHALT,
- 0, 0);
-
- return true;
-}
-
-void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci)
-{
- u8 arm_core_idx;
-
- arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
- if (BRCMF_MAX_CORENUM != arm_core_idx) {
- brcmf_sdio_chip_cm3_enterdl(sdiodev, ci);
- return;
- }
-
- brcmf_sdio_chip_cr4_enterdl(sdiodev, ci);
-}
-
-bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci, u32 rstvec)
-{
- u8 arm_core_idx;
-
- arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
- if (BRCMF_MAX_CORENUM != arm_core_idx)
- return brcmf_sdio_chip_cm3_exitdl(sdiodev, ci);
-
- return brcmf_sdio_chip_cr4_exitdl(sdiodev, ci, rstvec);
-}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h
deleted file mode 100644
index fb0614329ede..000000000000
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Copyright (c) 2011 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _BRCMFMAC_SDIO_CHIP_H_
-#define _BRCMFMAC_SDIO_CHIP_H_
-
-/*
- * Core reg address translation.
- * Both macro's returns a 32 bits byte address on the backplane bus.
- */
-#define CORE_CC_REG(base, field) \
- (base + offsetof(struct chipcregs, field))
-#define CORE_BUS_REG(base, field) \
- (base + offsetof(struct sdpcmd_regs, field))
-#define CORE_SB(base, field) \
- (base + SBCONFIGOFF + offsetof(struct sbconfig, field))
-
-/* SDIO function 1 register CHIPCLKCSR */
-/* Force ALP request to backplane */
-#define SBSDIO_FORCE_ALP 0x01
-/* Force HT request to backplane */
-#define SBSDIO_FORCE_HT 0x02
-/* Force ILP request to backplane */
-#define SBSDIO_FORCE_ILP 0x04
-/* Make ALP ready (power up xtal) */
-#define SBSDIO_ALP_AVAIL_REQ 0x08
-/* Make HT ready (power up PLL) */
-#define SBSDIO_HT_AVAIL_REQ 0x10
-/* Squelch clock requests from HW */
-#define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20
-/* Status: ALP is ready */
-#define SBSDIO_ALP_AVAIL 0x40
-/* Status: HT is ready */
-#define SBSDIO_HT_AVAIL 0x80
-#define SBSDIO_AVBITS (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL)
-#define SBSDIO_ALPAV(regval) ((regval) & SBSDIO_AVBITS)
-#define SBSDIO_HTAV(regval) (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS)
-#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval))
-#define SBSDIO_CLKAV(regval, alponly) \
- (SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval)))
-
-#define BRCMF_MAX_CORENUM 6
-
-struct brcmf_core {
- u16 id;
- u16 rev;
- u32 base;
- u32 wrapbase;
- u32 caps;
- u32 cib;
-};
-
-struct brcmf_chip {
- u32 chip;
- u32 chiprev;
- /* core info */
- /* always put chipcommon core at 0, bus core at 1 */
- struct brcmf_core c_inf[BRCMF_MAX_CORENUM];
- u32 pmurev;
- u32 pmucaps;
- u32 ramsize;
- u32 rambase;
- u32 rst_vec; /* reset vertor for ARM CR4 core */
-
- bool (*iscoreup)(struct brcmf_sdio_dev *sdiodev, struct brcmf_chip *ci,
- u16 coreid);
- u32 (*corerev)(struct brcmf_sdio_dev *sdiodev, struct brcmf_chip *ci,
- u16 coreid);
- void (*coredisable)(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits,
- u32 in_resetbits);
- void (*resetcore)(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits,
- u32 in_resetbits, u32 post_resetbits);
-};
-
-struct sbconfig {
- u32 PAD[2];
- u32 sbipsflag; /* initiator port ocp slave flag */
- u32 PAD[3];
- u32 sbtpsflag; /* target port ocp slave flag */
- u32 PAD[11];
- u32 sbtmerrloga; /* (sonics >= 2.3) */
- u32 PAD;
- u32 sbtmerrlog; /* (sonics >= 2.3) */
- u32 PAD[3];
- u32 sbadmatch3; /* address match3 */
- u32 PAD;
- u32 sbadmatch2; /* address match2 */
- u32 PAD;
- u32 sbadmatch1; /* address match1 */
- u32 PAD[7];
- u32 sbimstate; /* initiator agent state */
- u32 sbintvec; /* interrupt mask */
- u32 sbtmstatelow; /* target state */
- u32 sbtmstatehigh; /* target state */
- u32 sbbwa0; /* bandwidth allocation table0 */
- u32 PAD;
- u32 sbimconfiglow; /* initiator configuration */
- u32 sbimconfighigh; /* initiator configuration */
- u32 sbadmatch0; /* address match0 */
- u32 PAD;
- u32 sbtmconfiglow; /* target configuration */
- u32 sbtmconfighigh; /* target configuration */
- u32 sbbconfig; /* broadcast configuration */
- u32 PAD;
- u32 sbbstate; /* broadcast state */
- u32 PAD[3];
- u32 sbactcnfg; /* activate configuration */
- u32 PAD[3];
- u32 sbflagst; /* current sbflags */
- u32 PAD[3];
- u32 sbidlow; /* identification */
- u32 sbidhigh; /* identification */
-};
-
-/* sdio core registers */
-struct sdpcmd_regs {
- u32 corecontrol; /* 0x00, rev8 */
- u32 corestatus; /* rev8 */
- u32 PAD[1];
- u32 biststatus; /* rev8 */
-
- /* PCMCIA access */
- u16 pcmciamesportaladdr; /* 0x010, rev8 */
- u16 PAD[1];
- u16 pcmciamesportalmask; /* rev8 */
- u16 PAD[1];
- u16 pcmciawrframebc; /* rev8 */
- u16 PAD[1];
- u16 pcmciaunderflowtimer; /* rev8 */
- u16 PAD[1];
-
- /* interrupt */
- u32 intstatus; /* 0x020, rev8 */
- u32 hostintmask; /* rev8 */
- u32 intmask; /* rev8 */
- u32 sbintstatus; /* rev8 */
- u32 sbintmask; /* rev8 */
- u32 funcintmask; /* rev4 */
- u32 PAD[2];
- u32 tosbmailbox; /* 0x040, rev8 */
- u32 tohostmailbox; /* rev8 */
- u32 tosbmailboxdata; /* rev8 */
- u32 tohostmailboxdata; /* rev8 */
-
- /* synchronized access to registers in SDIO clock domain */
- u32 sdioaccess; /* 0x050, rev8 */
- u32 PAD[3];
-
- /* PCMCIA frame control */
- u8 pcmciaframectrl; /* 0x060, rev8 */
- u8 PAD[3];
- u8 pcmciawatermark; /* rev8 */
- u8 PAD[155];
-
- /* interrupt batching control */
- u32 intrcvlazy; /* 0x100, rev8 */
- u32 PAD[3];
-
- /* counters */
- u32 cmd52rd; /* 0x110, rev8 */
- u32 cmd52wr; /* rev8 */
- u32 cmd53rd; /* rev8 */
- u32 cmd53wr; /* rev8 */
- u32 abort; /* rev8 */
- u32 datacrcerror; /* rev8 */
- u32 rdoutofsync; /* rev8 */
- u32 wroutofsync; /* rev8 */
- u32 writebusy; /* rev8 */
- u32 readwait; /* rev8 */
- u32 readterm; /* rev8 */
- u32 writeterm; /* rev8 */
- u32 PAD[40];
- u32 clockctlstatus; /* rev8 */
- u32 PAD[7];
-
- u32 PAD[128]; /* DMA engines */
-
- /* SDIO/PCMCIA CIS region */
- char cis[512]; /* 0x400-0x5ff, rev6 */
-
- /* PCMCIA function control registers */
- char pcmciafcr[256]; /* 0x600-6ff, rev6 */
- u16 PAD[55];
-
- /* PCMCIA backplane access */
- u16 backplanecsr; /* 0x76E, rev6 */
- u16 backplaneaddr0; /* rev6 */
- u16 backplaneaddr1; /* rev6 */
- u16 backplaneaddr2; /* rev6 */
- u16 backplaneaddr3; /* rev6 */
- u16 backplanedata0; /* rev6 */
- u16 backplanedata1; /* rev6 */
- u16 backplanedata2; /* rev6 */
- u16 backplanedata3; /* rev6 */
- u16 PAD[31];
-
- /* sprom "size" & "blank" info */
- u16 spromstatus; /* 0x7BE, rev2 */
- u32 PAD[464];
-
- u16 PAD[0x80];
-};
-
-int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip **ci_ptr);
-void brcmf_sdio_chip_detach(struct brcmf_chip **ci_ptr);
-void brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci,
- u32 drivestrength);
-u8 brcmf_sdio_chip_getinfidx(struct brcmf_chip *ci, u16 coreid);
-void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci);
-bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci, u32 rstvec);
-
-#endif /* _BRCMFMAC_SDIO_CHIP_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
index 092e9c824992..3deab7959a0d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
@@ -180,6 +180,97 @@ struct brcmf_sdio_dev {
uint max_request_size;
ushort max_segment_count;
uint max_segment_size;
+ uint txglomsz;
+ struct sg_table sgtable;
+};
+
+/* sdio core registers */
+struct sdpcmd_regs {
+ u32 corecontrol; /* 0x00, rev8 */
+ u32 corestatus; /* rev8 */
+ u32 PAD[1];
+ u32 biststatus; /* rev8 */
+
+ /* PCMCIA access */
+ u16 pcmciamesportaladdr; /* 0x010, rev8 */
+ u16 PAD[1];
+ u16 pcmciamesportalmask; /* rev8 */
+ u16 PAD[1];
+ u16 pcmciawrframebc; /* rev8 */
+ u16 PAD[1];
+ u16 pcmciaunderflowtimer; /* rev8 */
+ u16 PAD[1];
+
+ /* interrupt */
+ u32 intstatus; /* 0x020, rev8 */
+ u32 hostintmask; /* rev8 */
+ u32 intmask; /* rev8 */
+ u32 sbintstatus; /* rev8 */
+ u32 sbintmask; /* rev8 */
+ u32 funcintmask; /* rev4 */
+ u32 PAD[2];
+ u32 tosbmailbox; /* 0x040, rev8 */
+ u32 tohostmailbox; /* rev8 */
+ u32 tosbmailboxdata; /* rev8 */
+ u32 tohostmailboxdata; /* rev8 */
+
+ /* synchronized access to registers in SDIO clock domain */
+ u32 sdioaccess; /* 0x050, rev8 */
+ u32 PAD[3];
+
+ /* PCMCIA frame control */
+ u8 pcmciaframectrl; /* 0x060, rev8 */
+ u8 PAD[3];
+ u8 pcmciawatermark; /* rev8 */
+ u8 PAD[155];
+
+ /* interrupt batching control */
+ u32 intrcvlazy; /* 0x100, rev8 */
+ u32 PAD[3];
+
+ /* counters */
+ u32 cmd52rd; /* 0x110, rev8 */
+ u32 cmd52wr; /* rev8 */
+ u32 cmd53rd; /* rev8 */
+ u32 cmd53wr; /* rev8 */
+ u32 abort; /* rev8 */
+ u32 datacrcerror; /* rev8 */
+ u32 rdoutofsync; /* rev8 */
+ u32 wroutofsync; /* rev8 */
+ u32 writebusy; /* rev8 */
+ u32 readwait; /* rev8 */
+ u32 readterm; /* rev8 */
+ u32 writeterm; /* rev8 */
+ u32 PAD[40];
+ u32 clockctlstatus; /* rev8 */
+ u32 PAD[7];
+
+ u32 PAD[128]; /* DMA engines */
+
+ /* SDIO/PCMCIA CIS region */
+ char cis[512]; /* 0x400-0x5ff, rev6 */
+
+ /* PCMCIA function control registers */
+ char pcmciafcr[256]; /* 0x600-6ff, rev6 */
+ u16 PAD[55];
+
+ /* PCMCIA backplane access */
+ u16 backplanecsr; /* 0x76E, rev6 */
+ u16 backplaneaddr0; /* rev6 */
+ u16 backplaneaddr1; /* rev6 */
+ u16 backplaneaddr2; /* rev6 */
+ u16 backplaneaddr3; /* rev6 */
+ u16 backplanedata0; /* rev6 */
+ u16 backplanedata1; /* rev6 */
+ u16 backplanedata2; /* rev6 */
+ u16 backplanedata3; /* rev6 */
+ u16 PAD[31];
+
+ /* sprom "size" & "blank" info */
+ u16 spromstatus; /* 0x7BE, rev2 */
+ u32 PAD[464];
+
+ u16 PAD[0x80];
};
/* Register/deregister interrupt handler. */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index d7718a5fa2f0..afb3d15e38ff 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -18,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/etherdevice.h>
+#include <linux/module.h>
#include <net/cfg80211.h>
#include <net/netlink.h>
@@ -190,6 +191,7 @@ static struct ieee80211_supported_band __wl_band_2ghz = {
.n_channels = ARRAY_SIZE(__wl_2ghz_channels),
.bitrates = wl_g_rates,
.n_bitrates = wl_g_rates_size,
+ .ht_cap = {IEEE80211_HT_CAP_SUP_WIDTH_20_40, true},
};
static struct ieee80211_supported_band __wl_band_5ghz_a = {
@@ -251,6 +253,10 @@ struct parsed_vndr_ies {
struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
};
+static int brcmf_roamoff;
+module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
+MODULE_PARM_DESC(roamoff, "do not use internal roaming engine");
+
/* Quarter dBm units to mW
* Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
* Table is offset so the last entry is largest mW value that fits in
@@ -351,13 +357,11 @@ u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
* triples, returning a pointer to the substring whose first element
* matches tag
*/
-struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
+const struct brcmf_tlv *
+brcmf_parse_tlvs(const void *buf, int buflen, uint key)
{
- struct brcmf_tlv *elt;
- int totlen;
-
- elt = (struct brcmf_tlv *)buf;
- totlen = buflen;
+ const struct brcmf_tlv *elt = buf;
+ int totlen = buflen;
/* find tagged parameter */
while (totlen >= TLV_HDR_LEN) {
@@ -378,8 +382,8 @@ struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
* not update the tlvs buffer pointer/length.
*/
static bool
-brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
- u8 *oui, u32 oui_len, u8 type)
+brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
+ const u8 *oui, u32 oui_len, u8 type)
{
/* If the contents match the OUI and the type */
if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
@@ -401,12 +405,12 @@ brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
}
static struct brcmf_vs_tlv *
-brcmf_find_wpaie(u8 *parse, u32 len)
+brcmf_find_wpaie(const u8 *parse, u32 len)
{
- struct brcmf_tlv *ie;
+ const struct brcmf_tlv *ie;
while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
- if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
+ if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
return (struct brcmf_vs_tlv *)ie;
}
@@ -414,9 +418,9 @@ brcmf_find_wpaie(u8 *parse, u32 len)
}
static struct brcmf_vs_tlv *
-brcmf_find_wpsie(u8 *parse, u32 len)
+brcmf_find_wpsie(const u8 *parse, u32 len)
{
- struct brcmf_tlv *ie;
+ const struct brcmf_tlv *ie;
while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
@@ -491,6 +495,19 @@ brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
return err;
}
+static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif)
+{
+ enum nl80211_iftype iftype;
+
+ iftype = vif->wdev.iftype;
+ return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO;
+}
+
+static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
+{
+ return vif->wdev.iftype == NL80211_IFTYPE_ADHOC;
+}
+
static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
const char *name,
enum nl80211_iftype type,
@@ -651,7 +668,6 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
type);
return -EOPNOTSUPP;
case NL80211_IFTYPE_ADHOC:
- vif->mode = WL_MODE_IBSS;
infra = 0;
break;
case NL80211_IFTYPE_STATION:
@@ -667,12 +683,10 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
*/
return 0;
}
- vif->mode = WL_MODE_BSS;
infra = 1;
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
- vif->mode = WL_MODE_AP;
ap = 1;
break;
default:
@@ -696,7 +710,7 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
err = -EAGAIN;
goto done;
}
- brcmf_dbg(INFO, "IF Type = %s\n", (vif->mode == WL_MODE_IBSS) ?
+ brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ?
"Adhoc" : "Infra");
}
ndev->ieee80211_ptr->iftype = type;
@@ -1340,13 +1354,14 @@ static s32 brcmf_set_auth_type(struct net_device *ndev,
}
static s32
-brcmf_set_set_cipher(struct net_device *ndev,
- struct cfg80211_connect_params *sme)
+brcmf_set_wsec_mode(struct net_device *ndev,
+ struct cfg80211_connect_params *sme, bool mfp)
{
struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
struct brcmf_cfg80211_security *sec;
s32 pval = 0;
s32 gval = 0;
+ s32 wsec;
s32 err = 0;
if (sme->crypto.n_ciphers_pairwise) {
@@ -1398,7 +1413,12 @@ brcmf_set_set_cipher(struct net_device *ndev,
if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
sme->privacy)
pval = AES_ENABLED;
- err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", pval | gval);
+
+ if (mfp)
+ wsec = pval | gval | MFP_CAPABLE;
+ else
+ wsec = pval | gval;
+ err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
if (err) {
brcmf_err("error (%d)\n", err);
return err;
@@ -1562,13 +1582,12 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
struct ieee80211_channel *chan = sme->channel;
struct brcmf_join_params join_params;
size_t join_params_size;
- struct brcmf_tlv *rsn_ie;
- struct brcmf_vs_tlv *wpa_ie;
- void *ie;
+ const struct brcmf_tlv *rsn_ie;
+ const struct brcmf_vs_tlv *wpa_ie;
+ const void *ie;
u32 ie_len;
struct brcmf_ext_join_params_le *ext_join_params;
u16 chanspec;
-
s32 err = 0;
brcmf_dbg(TRACE, "Enter\n");
@@ -1591,7 +1610,8 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
ie_len = wpa_ie->len + TLV_HDR_LEN;
} else {
/* find the RSN_IE */
- rsn_ie = brcmf_parse_tlvs((u8 *)sme->ie, sme->ie_len,
+ rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
+ sme->ie_len,
WLAN_EID_RSN);
if (rsn_ie) {
ie = rsn_ie;
@@ -1636,7 +1656,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
goto done;
}
- err = brcmf_set_set_cipher(ndev, sme);
+ err = brcmf_set_wsec_mode(ndev, sme, sme->mfp == NL80211_MFP_REQUIRED);
if (err) {
brcmf_err("wl_set_set_cipher failed (%d)\n", err);
goto done;
@@ -1678,22 +1698,9 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
memcpy(&ext_join_params->ssid_le.SSID, sme->ssid,
profile->ssid.SSID_len);
- /*increase dwell time to receive probe response or detect Beacon
- * from target AP at a noisy air only during connect command
- */
- ext_join_params->scan_le.active_time =
- cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
- ext_join_params->scan_le.passive_time =
- cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
+
/* Set up join scan parameters */
ext_join_params->scan_le.scan_type = -1;
- /* to sync with presence period of VSDB GO.
- * Send probe request more frequently. Probe request will be stopped
- * when it gets probe response from target AP/GO.
- */
- ext_join_params->scan_le.nprobes =
- cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
- BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
ext_join_params->scan_le.home_time = cpu_to_le32(-1);
if (sme->bssid)
@@ -1706,6 +1713,25 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
ext_join_params->assoc_le.chanspec_list[0] =
cpu_to_le16(chanspec);
+ /* Increase dwell time to receive probe response or detect
+ * beacon from target AP at a noisy air only during connect
+ * command.
+ */
+ ext_join_params->scan_le.active_time =
+ cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
+ ext_join_params->scan_le.passive_time =
+ cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
+ /* To sync with presence period of VSDB GO send probe request
+ * more frequently. Probe request will be stopped when it gets
+ * probe response from target AP/GO.
+ */
+ ext_join_params->scan_le.nprobes =
+ cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
+ BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
+ } else {
+ ext_join_params->scan_le.active_time = cpu_to_le32(-1);
+ ext_join_params->scan_le.passive_time = cpu_to_le32(-1);
+ ext_join_params->scan_le.nprobes = cpu_to_le32(-1);
}
err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
@@ -1913,7 +1939,7 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
memcpy(key.data, params->key, key.len);
- if ((ifp->vif->mode != WL_MODE_AP) &&
+ if (!brcmf_is_apmode(ifp->vif) &&
(params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
memcpy(keybuf, &key.data[24], sizeof(keybuf));
@@ -1981,7 +2007,9 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
if (!check_vif_up(ifp->vif))
return -EIO;
- if (mac_addr) {
+ if (mac_addr &&
+ (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
+ (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
brcmf_dbg(TRACE, "Exit");
return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
}
@@ -2010,7 +2038,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
break;
case WLAN_CIPHER_SUITE_TKIP:
- if (ifp->vif->mode != WL_MODE_AP) {
+ if (!brcmf_is_apmode(ifp->vif)) {
brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
memcpy(keybuf, &key.data[24], sizeof(keybuf));
memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
@@ -2164,12 +2192,14 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
s32 err = 0;
u8 *bssid = profile->bssid;
struct brcmf_sta_info_le sta_info_le;
+ u32 beacon_period;
+ u32 dtim_period;
brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
if (!check_vif_up(ifp->vif))
return -EIO;
- if (ifp->vif->mode == WL_MODE_AP) {
+ if (brcmf_is_apmode(ifp->vif)) {
memcpy(&sta_info_le, mac, ETH_ALEN);
err = brcmf_fil_iovar_data_get(ifp, "sta_info",
&sta_info_le,
@@ -2186,7 +2216,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
}
brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
sinfo->inactive_time, sinfo->connected_time);
- } else if (ifp->vif->mode == WL_MODE_BSS) {
+ } else if (ifp->vif->wdev.iftype == NL80211_IFTYPE_STATION) {
if (memcmp(mac, bssid, ETH_ALEN)) {
brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
mac, bssid);
@@ -2218,6 +2248,30 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
sinfo->signal = rssi;
brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
}
+ err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_BCNPRD,
+ &beacon_period);
+ if (err) {
+ brcmf_err("Could not get beacon period (%d)\n",
+ err);
+ goto done;
+ } else {
+ sinfo->bss_param.beacon_interval =
+ beacon_period;
+ brcmf_dbg(CONN, "Beacon peroid %d\n",
+ beacon_period);
+ }
+ err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_DTIMPRD,
+ &dtim_period);
+ if (err) {
+ brcmf_err("Could not get DTIM period (%d)\n",
+ err);
+ goto done;
+ } else {
+ sinfo->bss_param.dtim_period = dtim_period;
+ brcmf_dbg(CONN, "DTIM peroid %d\n",
+ dtim_period);
+ }
+ sinfo->filled |= STATION_INFO_BSS_PARAM;
}
} else
err = -EPERM;
@@ -2444,18 +2498,13 @@ CleanUp:
return err;
}
-static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
-{
- return vif->mode == WL_MODE_IBSS;
-}
-
static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
struct brcmf_if *ifp)
{
struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
struct brcmf_bss_info_le *bi;
struct brcmf_ssid *ssid;
- struct brcmf_tlv *tim;
+ const struct brcmf_tlv *tim;
u16 beacon_interval;
u8 dtim_period;
size_t ie_len;
@@ -3220,8 +3269,9 @@ static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
}
static s32
-brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
- bool is_rsn_ie)
+brcmf_configure_wpaie(struct net_device *ndev,
+ const struct brcmf_vs_tlv *wpa_ie,
+ bool is_rsn_ie)
{
struct brcmf_if *ifp = netdev_priv(ndev);
u32 auth = 0; /* d11 open authentication */
@@ -3707,11 +3757,11 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
s32 ie_offset;
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_tlv *ssid_ie;
+ const struct brcmf_tlv *ssid_ie;
struct brcmf_ssid_le ssid_le;
s32 err = -EPERM;
- struct brcmf_tlv *rsn_ie;
- struct brcmf_vs_tlv *wpa_ie;
+ const struct brcmf_tlv *rsn_ie;
+ const struct brcmf_vs_tlv *wpa_ie;
struct brcmf_join_params join_params;
enum nl80211_iftype dev_role;
struct brcmf_fil_bss_enable_le bss_enable;
@@ -4220,32 +4270,6 @@ static struct cfg80211_ops wl_cfg80211_ops = {
CFG80211_TESTMODE_CMD(brcmf_cfg80211_testmode)
};
-static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type)
-{
- switch (type) {
- case NL80211_IFTYPE_AP_VLAN:
- case NL80211_IFTYPE_WDS:
- case NL80211_IFTYPE_MONITOR:
- case NL80211_IFTYPE_MESH_POINT:
- return -ENOTSUPP;
- case NL80211_IFTYPE_ADHOC:
- return WL_MODE_IBSS;
- case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_P2P_CLIENT:
- return WL_MODE_BSS;
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_P2P_GO:
- return WL_MODE_AP;
- case NL80211_IFTYPE_P2P_DEVICE:
- return WL_MODE_P2P;
- case NL80211_IFTYPE_UNSPECIFIED:
- default:
- break;
- }
-
- return -EINVAL;
-}
-
static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
{
/* scheduled scan settings */
@@ -4370,7 +4394,6 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
vif->wdev.wiphy = cfg->wiphy;
vif->wdev.iftype = type;
- vif->mode = brcmf_nl80211_iftype_to_mode(type);
vif->pm_block = pm_block;
vif->roam_off = -1;
@@ -4416,7 +4439,9 @@ static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
u32 event = e->event_code;
u16 flags = e->flags;
- if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
+ if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
+ (event == BRCMF_E_DISASSOC_IND) ||
+ ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
brcmf_dbg(CONN, "Processing link down\n");
return true;
}
@@ -4658,16 +4683,19 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
struct net_device *ndev = ifp->ndev;
struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
+ struct ieee80211_channel *chan;
s32 err = 0;
+ u16 reason;
- if (ifp->vif->mode == WL_MODE_AP) {
+ if (brcmf_is_apmode(ifp->vif)) {
err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
} else if (brcmf_is_linkup(e)) {
brcmf_dbg(CONN, "Linkup\n");
if (brcmf_is_ibssmode(ifp->vif)) {
+ chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
memcpy(profile->bssid, e->addr, ETH_ALEN);
wl_inform_ibss(cfg, ndev, e->addr);
- cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
+ cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
clear_bit(BRCMF_VIF_STATUS_CONNECTING,
&ifp->vif->sme_state);
set_bit(BRCMF_VIF_STATUS_CONNECTED,
@@ -4679,9 +4707,15 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
if (!brcmf_is_ibssmode(ifp->vif)) {
brcmf_bss_connect_done(cfg, ndev, e, false);
if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
- &ifp->vif->sme_state))
- cfg80211_disconnected(ndev, 0, NULL, 0,
+ &ifp->vif->sme_state)) {
+ reason = 0;
+ if (((e->event_code == BRCMF_E_DEAUTH_IND) ||
+ (e->event_code == BRCMF_E_DISASSOC_IND)) &&
+ (e->reason != WLAN_REASON_UNSPECIFIED))
+ reason = e->reason;
+ cfg80211_disconnected(ndev, reason, NULL, 0,
GFP_KERNEL);
+ }
}
brcmf_link_down(ifp->vif);
brcmf_init_prof(ndev_to_prof(ndev));
@@ -4875,11 +4909,8 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
cfg->scan_request = NULL;
cfg->pwr_save = true;
- cfg->roam_on = true; /* roam on & off switch.
- we enable roam per default */
- cfg->active_scan = true; /* we do active scan for
- specific scan per default */
- cfg->dongle_up = false; /* dongle is not up yet */
+ cfg->active_scan = true; /* we do active scan per default */
+ cfg->dongle_up = false; /* dongle is not up yet */
err = brcmf_init_priv_mem(cfg);
if (err)
return err;
@@ -4904,6 +4935,30 @@ static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
mutex_init(&event->vif_event_lock);
}
+static int brcmf_enable_bw40_2g(struct brcmf_if *ifp)
+{
+ struct brcmf_fil_bwcap_le band_bwcap;
+ u32 val;
+ int err;
+
+ /* verify support for bw_cap command */
+ val = WLC_BAND_5G;
+ err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
+
+ if (!err) {
+ /* only set 2G bandwidth using bw_cap command */
+ band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
+ band_bwcap.bw_cap = cpu_to_le32(WLC_BW_40MHZ_BIT);
+ err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
+ sizeof(band_bwcap));
+ } else {
+ brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
+ val = WLC_N_BW_40ALL;
+ err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
+ }
+ return err;
+}
+
struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
struct device *busdev)
{
@@ -4961,6 +5016,17 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
goto cfg80211_p2p_attach_out;
}
+ /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
+ * setup 40MHz in 2GHz band and enable OBSS scanning.
+ */
+ if (wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap &
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
+ err = brcmf_enable_bw40_2g(ifp);
+ if (!err)
+ err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
+ BRCMF_OBSS_COEX_AUTO);
+ }
+
err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
if (err) {
brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
@@ -4999,7 +5065,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
}
static s32
-brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
+brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout)
{
s32 err = 0;
__le32 roamtrigger[2];
@@ -5009,7 +5075,7 @@ brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
* Setup timeout if Beacons are lost and roam is
* off to report link down
*/
- if (roamvar) {
+ if (brcmf_roamoff) {
err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
if (err) {
brcmf_err("bcn_timeout error (%d)\n", err);
@@ -5021,8 +5087,9 @@ brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
* Enable/Disable built-in roaming to allow supplicant
* to take care of roaming
*/
- brcmf_dbg(INFO, "Internal Roaming = %s\n", roamvar ? "Off" : "On");
- err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
+ brcmf_dbg(INFO, "Internal Roaming = %s\n",
+ brcmf_roamoff ? "Off" : "On");
+ err = brcmf_fil_iovar_int_set(ifp, "roam_off", !!(brcmf_roamoff));
if (err) {
brcmf_err("roam_off error (%d)\n", err);
goto dongle_rom_out;
@@ -5164,9 +5231,6 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg,
ieee80211_channel_to_frequency(ch.chnum, band);
band_chan_arr[index].hw_value = ch.chnum;
- brcmf_err("channel %d: f=%d bw=%d sb=%d\n",
- ch.chnum, band_chan_arr[index].center_freq,
- ch.bw, ch.sb);
if (ch.bw == BRCMU_CHAN_BW_40) {
/* assuming the order is HT20, HT40 Upper,
* HT40 lower from chanspecs
@@ -5267,6 +5331,8 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
u32 band_list[3];
u32 nmode;
u32 bw_cap[2] = { 0, 0 };
+ u32 rxchain;
+ u32 nchain;
s8 phy;
s32 err;
u32 nband;
@@ -5303,6 +5369,16 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
brcmf_dbg(INFO, "nmode=%d, bw_cap=(%d, %d)\n", nmode,
bw_cap[IEEE80211_BAND_2GHZ], bw_cap[IEEE80211_BAND_5GHZ]);
+ err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
+ if (err) {
+ brcmf_err("rxchain error (%d)\n", err);
+ nchain = 1;
+ } else {
+ for (nchain = 0; rxchain; nchain++)
+ rxchain = rxchain & (rxchain - 1);
+ }
+ brcmf_dbg(INFO, "nchain=%d\n", nchain);
+
err = brcmf_construct_reginfo(cfg, bw_cap);
if (err) {
brcmf_err("brcmf_construct_reginfo failed (%d)\n", err);
@@ -5331,10 +5407,7 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
band->ht_cap.ht_supported = true;
band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
- /* An HT shall support all EQM rates for one spatial
- * stream
- */
- band->ht_cap.mcs.rx_mask[0] = 0xff;
+ memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
bands[band->band] = band;
}
@@ -5381,7 +5454,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
brcmf_dbg(INFO, "power save set to %s\n",
(power_mode ? "enabled" : "disabled"));
- err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
+ err = brcmf_dongle_roam(ifp, WL_BEACON_TIMEOUT);
if (err)
goto default_conf_out;
err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
index 2dc6a074e8ed..283c525a44f7 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
@@ -89,21 +89,6 @@ enum brcmf_scan_status {
BRCMF_SCAN_STATUS_SUPPRESS,
};
-/**
- * enum wl_mode - driver mode of virtual interface.
- *
- * @WL_MODE_BSS: connects to BSS.
- * @WL_MODE_IBSS: operate as ad-hoc.
- * @WL_MODE_AP: operate as access-point.
- * @WL_MODE_P2P: provide P2P discovery.
- */
-enum wl_mode {
- WL_MODE_BSS,
- WL_MODE_IBSS,
- WL_MODE_AP,
- WL_MODE_P2P
-};
-
/* dongle configuration */
struct brcmf_cfg80211_conf {
u32 frag_threshold;
@@ -193,7 +178,6 @@ struct vif_saved_ie {
* @ifp: lower layer interface pointer
* @wdev: wireless device.
* @profile: profile information.
- * @mode: operating mode.
* @roam_off: roaming state.
* @sme_state: SME state using enum brcmf_vif_status bits.
* @pm_block: power-management blocked.
@@ -204,7 +188,6 @@ struct brcmf_cfg80211_vif {
struct brcmf_if *ifp;
struct wireless_dev wdev;
struct brcmf_cfg80211_profile profile;
- s32 mode;
s32 roam_off;
unsigned long sme_state;
bool pm_block;
@@ -402,7 +385,6 @@ struct brcmf_cfg80211_info {
bool ibss_starter;
bool pwr_save;
bool dongle_up;
- bool roam_on;
bool scan_tried;
u8 *dcmd_buf;
u8 *extra_buf;
@@ -491,7 +473,8 @@ void brcmf_free_vif(struct brcmf_cfg80211_vif *vif);
s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
const u8 *vndr_ie_buf, u32 vndr_ie_len);
s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif);
-struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key);
+const struct brcmf_tlv *
+brcmf_parse_tlvs(const void *buf, int buflen, uint key);
u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
struct ieee80211_channel *ch);
u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index 925034b80e9c..8c5fa4e58139 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -426,6 +426,12 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
bool blocked;
int err;
+ if (!wl->ucode.bcm43xx_bomminor) {
+ err = brcms_request_fw(wl, wl->wlc->hw->d11core);
+ if (err)
+ return -ENOENT;
+ }
+
ieee80211_wake_queues(hw);
spin_lock_bh(&wl->lock);
blocked = brcms_rfkill_set_hw_state(wl);
@@ -433,14 +439,6 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
if (!blocked)
wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
- if (!wl->ucode.bcm43xx_bomminor) {
- err = brcms_request_fw(wl, wl->wlc->hw->d11core);
- if (err) {
- brcms_remove(wl->wlc->hw->d11core);
- return -ENOENT;
- }
- }
-
spin_lock_bh(&wl->lock);
/* avoid acknowledging frames before a non-monitor device is added */
wl->mute_tx = true;
@@ -1094,12 +1092,6 @@ static int ieee_hw_init(struct ieee80211_hw *hw)
* Attach to the WL device identified by vendor and device parameters.
* regs is a host accessible memory address pointing to WL device registers.
*
- * brcms_attach is not defined as static because in the case where no bus
- * is defined, wl_attach will never be called, and thus, gcc will issue
- * a warning that this function is defined but not used if we declare
- * it as static.
- *
- *
* is called in brcms_bcma_probe() context, therefore no locking required.
*/
static struct brcms_info *brcms_attach(struct bcma_device *pdev)
diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
index 6fa5d4863782..d816270db3be 100644
--- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
+++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
@@ -43,5 +43,6 @@
#define BCM4335_CHIP_ID 0x4335
#define BCM43362_CHIP_ID 43362
#define BCM4339_CHIP_ID 0x4339
+#define BCM4354_CHIP_ID 0x4354
#endif /* _BRCM_HW_IDS_H_ */
diff --git a/drivers/net/wireless/brcm80211/include/brcmu_wifi.h b/drivers/net/wireless/brcm80211/include/brcmu_wifi.h
index 7ca2aa1035b2..74419d4bd123 100644
--- a/drivers/net/wireless/brcm80211/include/brcmu_wifi.h
+++ b/drivers/net/wireless/brcm80211/include/brcmu_wifi.h
@@ -217,6 +217,9 @@ static inline bool ac_bitmap_tst(u8 bitmap, int prec)
#define WSEC_SWFLAG 0x0008
/* to go into transition mode without setting wep */
#define SES_OW_ENABLED 0x0040
+/* MFP */
+#define MFP_CAPABLE 0x0200
+#define MFP_REQUIRED 0x0400
/* WPA authentication mode bitvec */
#define WPA_AUTH_DISABLED 0x0000 /* Legacy (i.e., non-WPA) */
diff --git a/drivers/net/wireless/cw1200/fwio.c b/drivers/net/wireless/cw1200/fwio.c
index 5a9ffd3a6a6c..e23d67e0bfe6 100644
--- a/drivers/net/wireless/cw1200/fwio.c
+++ b/drivers/net/wireless/cw1200/fwio.c
@@ -202,8 +202,8 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
}
/* calculate the block size */
- tx_size = block_size = min((size_t)(firmware->size - put),
- (size_t)DOWNLOAD_BLOCK_SIZE);
+ tx_size = block_size = min_t(size_t, firmware->size - put,
+ DOWNLOAD_BLOCK_SIZE);
memcpy(buf, &firmware->data[put], block_size);
if (block_size < DOWNLOAD_BLOCK_SIZE) {
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index d36e252d2ccb..596525528f50 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -147,7 +147,7 @@ static void ap_free_sta(struct ap_data *ap, struct sta_info *sta)
if (!sta->ap && sta->u.sta.challenge)
kfree(sta->u.sta.challenge);
- del_timer(&sta->timer);
+ del_timer_sync(&sta->timer);
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
kfree(sta);
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 9f825f2620da..b6ec51923b20 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -677,6 +677,8 @@ static const struct pcmcia_device_id hostap_cs_ids[] = {
PCMCIA_DEVICE_PROD_ID12(
"ZoomAir 11Mbps High", "Rate wireless Networking",
0x273fe3db, 0x32a1eaee),
+ PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card",
+ 0xa37434e9, 0x9762e8f1),
PCMCIA_DEVICE_PROD_ID123(
"Pretec", "CompactWLAN Card 802.11b", "2.5",
0x1cadd3e5, 0xe697636c, 0x7a5bfcf1),
diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c
index aa7ad3a7a69b..4e5c0f8c9496 100644
--- a/drivers/net/wireless/hostap/hostap_proc.c
+++ b/drivers/net/wireless/hostap/hostap_proc.c
@@ -496,7 +496,7 @@ void hostap_init_proc(local_info_t *local)
void hostap_remove_proc(local_info_t *local)
{
- remove_proc_subtree(local->ddev->name, hostap_proc);
+ proc_remove(local->proc);
}
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index 3aba49259ef1..dfc6dfc56d52 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -7065,7 +7065,7 @@ static int ipw2100_wx_set_nick(struct net_device *dev,
if (wrqu->data.length > IW_ESSID_MAX_SIZE)
return -E2BIG;
- wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
+ wrqu->data.length = min_t(size_t, wrqu->data.length, sizeof(priv->nick));
memset(priv->nick, 0, sizeof(priv->nick));
memcpy(priv->nick, extra, wrqu->data.length);
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 139326065bd9..c5aa404069f3 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -9169,7 +9169,7 @@ static int ipw_wx_set_nick(struct net_device *dev,
if (wrqu->data.length > IW_ESSID_MAX_SIZE)
return -E2BIG;
mutex_lock(&priv->mutex);
- wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
+ wrqu->data.length = min_t(size_t, wrqu->data.length, sizeof(priv->nick));
memset(priv->nick, 0, sizeof(priv->nick));
memcpy(priv->nick, extra, wrqu->data.length);
IPW_DEBUG_TRACE("<<\n");
diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c
index 0487461ae4da..dc1d20cf64ee 100644
--- a/drivers/net/wireless/iwlegacy/3945-mac.c
+++ b/drivers/net/wireless/iwlegacy/3945-mac.c
@@ -1248,14 +1248,7 @@ il3945_rx_handle(struct il_priv *il)
len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK;
len += sizeof(u32); /* account for status word */
- /* Reclaim a command buffer only if this packet is a response
- * to a (driver-originated) command.
- * If the packet (e.g. Rx frame) originated from uCode,
- * there is no command buffer to reclaim.
- * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
- * but apparently a few don't get set; catch them here. */
- reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
- pkt->hdr.cmd != N_STATS && pkt->hdr.cmd != C_TX;
+ reclaim = il_need_reclaim(il, pkt);
/* Based on type of command response or notification,
* handle those that need handling via function in
@@ -1495,12 +1488,14 @@ il3945_irq_tasklet(struct il_priv *il)
if (inta & CSR_INT_BIT_WAKEUP) {
D_ISR("Wakeup interrupt\n");
il_rx_queue_update_write_ptr(il, &il->rxq);
+
+ spin_lock_irqsave(&il->lock, flags);
il_txq_update_write_ptr(il, &il->txq[0]);
il_txq_update_write_ptr(il, &il->txq[1]);
il_txq_update_write_ptr(il, &il->txq[2]);
il_txq_update_write_ptr(il, &il->txq[3]);
il_txq_update_write_ptr(il, &il->txq[4]);
- il_txq_update_write_ptr(il, &il->txq[5]);
+ spin_unlock_irqrestore(&il->lock, flags);
il->isr_stats.wakeup++;
handled |= CSR_INT_BIT_WAKEUP;
diff --git a/drivers/net/wireless/iwlegacy/3945-rs.c b/drivers/net/wireless/iwlegacy/3945-rs.c
index 9a45f6f626f6..76b0729ade17 100644
--- a/drivers/net/wireless/iwlegacy/3945-rs.c
+++ b/drivers/net/wireless/iwlegacy/3945-rs.c
@@ -891,8 +891,7 @@ il3945_rs_rate_init_stub(void *il_r, struct ieee80211_supported_band *sband,
{
}
-static struct rate_control_ops rs_ops = {
- .module = NULL,
+static const struct rate_control_ops rs_ops = {
.name = RS_NAME,
.tx_status = il3945_rs_tx_status,
.get_rate = il3945_rs_get_rate,
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index 43f488a8cda2..888ad5c74639 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -92,7 +92,6 @@ il4965_check_abort_status(struct il_priv *il, u8 frame_count, u32 status)
* EEPROM
*/
struct il_mod_params il4965_mod_params = {
- .amsdu_size_8K = 1,
.restart_fw = 1,
/* the rest are 0 by default */
};
@@ -4274,17 +4273,7 @@ il4965_rx_handle(struct il_priv *il)
len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK;
len += sizeof(u32); /* account for status word */
- /* Reclaim a command buffer only if this packet is a response
- * to a (driver-originated) command.
- * If the packet (e.g. Rx frame) originated from uCode,
- * there is no command buffer to reclaim.
- * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
- * but apparently a few don't get set; catch them here. */
- reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
- (pkt->hdr.cmd != N_RX_PHY) && (pkt->hdr.cmd != N_RX) &&
- (pkt->hdr.cmd != N_RX_MPDU) &&
- (pkt->hdr.cmd != N_COMPRESSED_BA) &&
- (pkt->hdr.cmd != N_STATS) && (pkt->hdr.cmd != C_TX);
+ reclaim = il_need_reclaim(il, pkt);
/* Based on type of command response or notification,
* handle those that need handling via function in
@@ -6876,6 +6865,6 @@ module_param_named(11n_disable, il4965_mod_params.disable_11n, int, S_IRUGO);
MODULE_PARM_DESC(11n_disable, "disable 11n functionality");
module_param_named(amsdu_size_8K, il4965_mod_params.amsdu_size_8K, int,
S_IRUGO);
-MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
+MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0 [disabled])");
module_param_named(fw_restart, il4965_mod_params.restart_fw, int, S_IRUGO);
MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");
diff --git a/drivers/net/wireless/iwlegacy/4965-rs.c b/drivers/net/wireless/iwlegacy/4965-rs.c
index 4d5e33259ca8..eaaeea19d8c5 100644
--- a/drivers/net/wireless/iwlegacy/4965-rs.c
+++ b/drivers/net/wireless/iwlegacy/4965-rs.c
@@ -2807,8 +2807,7 @@ il4965_rs_rate_init_stub(void *il_r, struct ieee80211_supported_band *sband,
{
}
-static struct rate_control_ops rs_4965_ops = {
- .module = NULL,
+static const struct rate_control_ops rs_4965_ops = {
.name = IL4965_RS_NAME,
.tx_status = il4965_rs_tx_status,
.get_rate = il4965_rs_get_rate,
diff --git a/drivers/net/wireless/iwlegacy/commands.h b/drivers/net/wireless/iwlegacy/commands.h
index 048421511988..dd744135c956 100644
--- a/drivers/net/wireless/iwlegacy/commands.h
+++ b/drivers/net/wireless/iwlegacy/commands.h
@@ -2270,7 +2270,8 @@ struct il_spectrum_notification {
*/
#define IL_POWER_VEC_SIZE 5
-#define IL_POWER_DRIVER_ALLOW_SLEEP_MSK cpu_to_le16(BIT(0))
+#define IL_POWER_DRIVER_ALLOW_SLEEP_MSK cpu_to_le16(BIT(0))
+#define IL_POWER_SLEEP_OVER_DTIM_MSK cpu_to_le16(BIT(2))
#define IL_POWER_PCI_PM_MSK cpu_to_le16(BIT(3))
struct il3945_powertable_cmd {
diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c
index 02e8233ccf29..4f42174d9994 100644
--- a/drivers/net/wireless/iwlegacy/common.c
+++ b/drivers/net/wireless/iwlegacy/common.c
@@ -1078,29 +1078,82 @@ EXPORT_SYMBOL(il_get_channel_info);
* Setting power level allows the card to go to sleep when not busy.
*
* We calculate a sleep command based on the required latency, which
- * we get from mac80211. In order to handle thermal throttling, we can
- * also use pre-defined power levels.
+ * we get from mac80211.
*/
-/*
- * This defines the old power levels. They are still used by default
- * (level 1) and for thermal throttle (levels 3 through 5)
- */
-
-struct il_power_vec_entry {
- struct il_powertable_cmd cmd;
- u8 no_dtim; /* number of skip dtim */
-};
+#define SLP_VEC(X0, X1, X2, X3, X4) { \
+ cpu_to_le32(X0), \
+ cpu_to_le32(X1), \
+ cpu_to_le32(X2), \
+ cpu_to_le32(X3), \
+ cpu_to_le32(X4) \
+}
static void
-il_power_sleep_cam_cmd(struct il_priv *il, struct il_powertable_cmd *cmd)
+il_build_powertable_cmd(struct il_priv *il, struct il_powertable_cmd *cmd)
{
+ const __le32 interval[3][IL_POWER_VEC_SIZE] = {
+ SLP_VEC(2, 2, 4, 6, 0xFF),
+ SLP_VEC(2, 4, 7, 10, 10),
+ SLP_VEC(4, 7, 10, 10, 0xFF)
+ };
+ int i, dtim_period, no_dtim;
+ u32 max_sleep;
+ bool skip;
+
memset(cmd, 0, sizeof(*cmd));
if (il->power_data.pci_pm)
cmd->flags |= IL_POWER_PCI_PM_MSK;
- D_POWER("Sleep command for CAM\n");
+ /* if no Power Save, we are done */
+ if (il->power_data.ps_disabled)
+ return;
+
+ cmd->flags = IL_POWER_DRIVER_ALLOW_SLEEP_MSK;
+ cmd->keep_alive_seconds = 0;
+ cmd->debug_flags = 0;
+ cmd->rx_data_timeout = cpu_to_le32(25 * 1024);
+ cmd->tx_data_timeout = cpu_to_le32(25 * 1024);
+ cmd->keep_alive_beacons = 0;
+
+ dtim_period = il->vif ? il->vif->bss_conf.dtim_period : 0;
+
+ if (dtim_period <= 2) {
+ memcpy(cmd->sleep_interval, interval[0], sizeof(interval[0]));
+ no_dtim = 2;
+ } else if (dtim_period <= 10) {
+ memcpy(cmd->sleep_interval, interval[1], sizeof(interval[1]));
+ no_dtim = 2;
+ } else {
+ memcpy(cmd->sleep_interval, interval[2], sizeof(interval[2]));
+ no_dtim = 0;
+ }
+
+ if (dtim_period == 0) {
+ dtim_period = 1;
+ skip = false;
+ } else {
+ skip = !!no_dtim;
+ }
+
+ if (skip) {
+ __le32 tmp = cmd->sleep_interval[IL_POWER_VEC_SIZE - 1];
+
+ max_sleep = le32_to_cpu(tmp);
+ if (max_sleep == 0xFF)
+ max_sleep = dtim_period * (skip + 1);
+ else if (max_sleep > dtim_period)
+ max_sleep = (max_sleep / dtim_period) * dtim_period;
+ cmd->flags |= IL_POWER_SLEEP_OVER_DTIM_MSK;
+ } else {
+ max_sleep = dtim_period;
+ cmd->flags &= ~IL_POWER_SLEEP_OVER_DTIM_MSK;
+ }
+
+ for (i = 0; i < IL_POWER_VEC_SIZE; i++)
+ if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
+ cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
}
static int
@@ -1173,7 +1226,8 @@ il_power_update_mode(struct il_priv *il, bool force)
{
struct il_powertable_cmd cmd;
- il_power_sleep_cam_cmd(il, &cmd);
+ il_build_powertable_cmd(il, &cmd);
+
return il_power_set_mode(il, &cmd, force);
}
EXPORT_SYMBOL(il_power_update_mode);
@@ -5081,6 +5135,7 @@ set_ch_out:
}
if (changed & (IEEE80211_CONF_CHANGE_PS | IEEE80211_CONF_CHANGE_IDLE)) {
+ il->power_data.ps_disabled = !(conf->flags & IEEE80211_CONF_PS);
ret = il_power_update_mode(il, false);
if (ret)
D_MAC80211("Error setting sleep level\n");
diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h
index ad123d66ab6c..dfb13c70efe8 100644
--- a/drivers/net/wireless/iwlegacy/common.h
+++ b/drivers/net/wireless/iwlegacy/common.h
@@ -1123,6 +1123,7 @@ struct il_power_mgr {
struct il_powertable_cmd sleep_cmd_next;
int debug_sleep_level_override;
bool pci_pm;
+ bool ps_disabled;
};
struct il_priv {
@@ -1597,7 +1598,7 @@ struct il_mod_params {
int disable_hw_scan; /* def: 0 = use h/w scan */
int num_of_queues; /* def: HW dependent */
int disable_11n; /* def: 0 = 11n capabilities enabled */
- int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */
+ int amsdu_size_8K; /* def: 0 = disable 8K amsdu size */
int antenna; /* def: 0 = both antennas (use diversity) */
int restart_fw; /* def: 1 = restart firmware */
};
@@ -1978,6 +1979,20 @@ void il_wr_prph(struct il_priv *il, u32 addr, u32 val);
u32 il_read_targ_mem(struct il_priv *il, u32 addr);
void il_write_targ_mem(struct il_priv *il, u32 addr, u32 val);
+static inline bool il_need_reclaim(struct il_priv *il, struct il_rx_pkt *pkt)
+{
+ /* Reclaim a command buffer only if this packet is a response
+ * to a (driver-originated) command. If the packet (e.g. Rx frame)
+ * originated from uCode, there is no command buffer to reclaim.
+ * Ucode should set SEQ_RX_FRAME bit if ucode-originated, but
+ * apparently a few don't get set; catch them here.
+ */
+ return !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
+ pkt->hdr.cmd != N_STATS && pkt->hdr.cmd != C_TX &&
+ pkt->hdr.cmd != N_RX_PHY && pkt->hdr.cmd != N_RX &&
+ pkt->hdr.cmd != N_RX_MPDU && pkt->hdr.cmd != N_COMPRESSED_BA;
+}
+
static inline void
_il_write8(struct il_priv *il, u32 ofs, u8 val)
{
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 3eb2102ce236..74b3b4de7bb7 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -68,6 +68,19 @@ config IWLWIFI_OPMODE_MODULAR
comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM"
depends on IWLWIFI && IWLDVM=n && IWLMVM=n
+config IWLWIFI_BCAST_FILTERING
+ bool "Enable broadcast filtering"
+ depends on IWLMVM
+ help
+ Say Y here to enable default bcast filtering configuration.
+
+ Enabling broadcast filtering will drop any incoming wireless
+ broadcast frames, except some very specific predefined
+ patterns (e.g. incoming arp requests).
+
+ If unsure, don't enable this option, as some programs might
+ expect incoming broadcasts for their normal operations.
+
menu "Debugging Options"
depends on IWLWIFI
@@ -111,6 +124,7 @@ config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
Enable use of experimental ucode for testing and debugging.
config IWLWIFI_DEVICE_TRACING
+
bool "iwlwifi device access tracing"
depends on IWLWIFI
depends on EVENT_TRACING
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 1fa64429bcc2..3d32f4120174 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -8,7 +8,7 @@ iwlwifi-objs += iwl-eeprom-read.o iwl-eeprom-parse.o
iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o
iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o
iwlwifi-$(CONFIG_IWLDVM) += iwl-1000.o iwl-2000.o iwl-5000.o iwl-6000.o
-iwlwifi-$(CONFIG_IWLMVM) += iwl-7000.o
+iwlwifi-$(CONFIG_IWLMVM) += iwl-7000.o iwl-8000.o
iwlwifi-objs += $(iwlwifi-m)
diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h
index 562772d85102..c160dad03037 100644
--- a/drivers/net/wireless/iwlwifi/dvm/agn.h
+++ b/drivers/net/wireless/iwlwifi/dvm/agn.h
@@ -109,7 +109,7 @@ extern const struct iwl_dvm_cfg iwl_dvm_6030_cfg;
struct iwl_ucode_capabilities;
-extern struct ieee80211_ops iwlagn_hw_ops;
+extern const struct ieee80211_ops iwlagn_hw_ops;
static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd)
{
@@ -480,7 +480,7 @@ do { \
} while (0)
#endif /* CONFIG_IWLWIFI_DEBUG */
-extern const char *iwl_dvm_cmd_strings[REPLY_MAX];
+extern const char *const iwl_dvm_cmd_strings[REPLY_MAX];
static inline const char *iwl_dvm_get_cmd_string(u8 cmd)
{
diff --git a/drivers/net/wireless/iwlwifi/dvm/devices.c b/drivers/net/wireless/iwlwifi/dvm/devices.c
index 7b140e487deb..758c54eeb206 100644
--- a/drivers/net/wireless/iwlwifi/dvm/devices.c
+++ b/drivers/net/wireless/iwlwifi/dvm/devices.c
@@ -317,7 +317,7 @@ static const struct iwl_sensitivity_ranges iwl5000_sensitivity = {
.nrg_th_cca = 62,
};
-static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
+static const struct iwl_sensitivity_ranges iwl5150_sensitivity = {
.min_nrg_cck = 95,
.auto_corr_min_ofdm = 90,
.auto_corr_min_ofdm_mrc = 170,
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index c24d1d3d55f6..dd55c9cf7ba8 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -696,6 +696,24 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return ret;
}
+static inline bool iwl_enable_rx_ampdu(const struct iwl_cfg *cfg)
+{
+ if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG)
+ return false;
+ return true;
+}
+
+static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg)
+{
+ if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG)
+ return false;
+ if (iwlwifi_mod_params.disable_11n & IWL_ENABLE_HT_TXAGG)
+ return true;
+
+ /* disabled by default */
+ return false;
+}
+
static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action,
@@ -717,7 +735,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
switch (action) {
case IEEE80211_AMPDU_RX_START:
- if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG)
+ if (!iwl_enable_rx_ampdu(priv->cfg))
break;
IWL_DEBUG_HT(priv, "start Rx\n");
ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
@@ -729,7 +747,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_TX_START:
if (!priv->trans->ops->txq_enable)
break;
- if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG)
+ if (!iwl_enable_tx_ampdu(priv->cfg))
break;
IWL_DEBUG_HT(priv, "start Tx\n");
ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
@@ -1564,7 +1582,7 @@ static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
IWL_DEBUG_MAC80211(priv, "leave\n");
}
-struct ieee80211_ops iwlagn_hw_ops = {
+const struct ieee80211_ops iwlagn_hw_ops = {
.tx = iwlagn_mac_tx,
.start = iwlagn_mac_start,
.stop = iwlagn_mac_stop,
diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c
index ba1b1ea54252..6a6df71af1d7 100644
--- a/drivers/net/wireless/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/iwlwifi/dvm/main.c
@@ -252,13 +252,17 @@ static void iwl_bg_bt_runtime_config(struct work_struct *work)
struct iwl_priv *priv =
container_of(work, struct iwl_priv, bt_runtime_config);
+ mutex_lock(&priv->mutex);
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
+ goto out;
/* dont send host command if rf-kill is on */
if (!iwl_is_ready_rf(priv))
- return;
+ goto out;
+
iwlagn_send_advance_bt_config(priv);
+out:
+ mutex_unlock(&priv->mutex);
}
static void iwl_bg_bt_full_concurrency(struct work_struct *work)
@@ -2035,7 +2039,7 @@ static void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
ieee80211_free_txskb(priv->hw, skb);
}
-static void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
+static bool iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
{
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
@@ -2045,6 +2049,8 @@ static void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
clear_bit(STATUS_RF_KILL_HW, &priv->status);
wiphy_rfkill_set_hw_state(priv->hw->wiphy, state);
+
+ return false;
}
static const struct iwl_op_mode_ops iwl_dvm_ops = {
diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c
index 0977d93b529d..aa773a2da4ab 100644
--- a/drivers/net/wireless/iwlwifi/dvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/dvm/rs.c
@@ -176,46 +176,46 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
* (2.4 GHz) band.
*/
-static s32 expected_tpt_legacy[IWL_RATE_COUNT] = {
+static const u16 expected_tpt_legacy[IWL_RATE_COUNT] = {
7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0
};
-static s32 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = {
+static const u16 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = {
{0, 0, 0, 0, 42, 0, 76, 102, 124, 159, 183, 193, 202}, /* Norm */
{0, 0, 0, 0, 46, 0, 82, 110, 132, 168, 192, 202, 210}, /* SGI */
{0, 0, 0, 0, 47, 0, 91, 133, 171, 242, 305, 334, 362}, /* AGG */
{0, 0, 0, 0, 52, 0, 101, 145, 187, 264, 330, 361, 390}, /* AGG+SGI */
};
-static s32 expected_tpt_siso40MHz[4][IWL_RATE_COUNT] = {
+static const u16 expected_tpt_siso40MHz[4][IWL_RATE_COUNT] = {
{0, 0, 0, 0, 77, 0, 127, 160, 184, 220, 242, 250, 257}, /* Norm */
{0, 0, 0, 0, 83, 0, 135, 169, 193, 229, 250, 257, 264}, /* SGI */
{0, 0, 0, 0, 94, 0, 177, 249, 313, 423, 512, 550, 586}, /* AGG */
{0, 0, 0, 0, 104, 0, 193, 270, 338, 454, 545, 584, 620}, /* AGG+SGI */
};
-static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = {
+static const u16 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = {
{0, 0, 0, 0, 74, 0, 123, 155, 179, 214, 236, 244, 251}, /* Norm */
{0, 0, 0, 0, 81, 0, 131, 164, 188, 223, 243, 251, 257}, /* SGI */
{0, 0, 0, 0, 89, 0, 167, 235, 296, 402, 488, 526, 560}, /* AGG */
{0, 0, 0, 0, 97, 0, 182, 255, 320, 431, 520, 558, 593}, /* AGG+SGI*/
};
-static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = {
+static const u16 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = {
{0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289}, /* Norm */
{0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293}, /* SGI */
{0, 0, 0, 0, 171, 0, 305, 410, 496, 634, 731, 771, 805}, /* AGG */
{0, 0, 0, 0, 186, 0, 329, 439, 527, 667, 764, 803, 838}, /* AGG+SGI */
};
-static s32 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = {
+static const u16 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = {
{0, 0, 0, 0, 99, 0, 153, 186, 208, 239, 256, 263, 268}, /* Norm */
{0, 0, 0, 0, 106, 0, 162, 194, 215, 246, 262, 268, 273}, /* SGI */
{0, 0, 0, 0, 134, 0, 249, 346, 431, 574, 685, 732, 775}, /* AGG */
{0, 0, 0, 0, 148, 0, 272, 376, 465, 614, 727, 775, 818}, /* AGG+SGI */
};
-static s32 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = {
+static const u16 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = {
{0, 0, 0, 0, 152, 0, 211, 239, 255, 279, 290, 294, 297}, /* Norm */
{0, 0, 0, 0, 160, 0, 219, 245, 261, 284, 294, 297, 300}, /* SGI */
{0, 0, 0, 0, 254, 0, 443, 584, 695, 868, 984, 1030, 1070}, /* AGG */
@@ -1111,7 +1111,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
struct iwl_scale_tbl_info *tbl)
{
/* Used to choose among HT tables */
- s32 (*ht_tbl_pointer)[IWL_RATE_COUNT];
+ const u16 (*ht_tbl_pointer)[IWL_RATE_COUNT];
/* Check for invalid LQ type */
if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_Ht(tbl->lq_type))) {
@@ -1173,9 +1173,8 @@ static s32 rs_get_best_rate(struct iwl_priv *priv,
&(lq_sta->lq_info[lq_sta->active_tbl]);
s32 active_sr = active_tbl->win[index].success_ratio;
s32 active_tpt = active_tbl->expected_tpt[index];
-
/* expected "search" throughput */
- s32 *tpt_tbl = tbl->expected_tpt;
+ const u16 *tpt_tbl = tbl->expected_tpt;
s32 new_rate, high, low, start_hi;
u16 high_low;
@@ -3319,8 +3318,8 @@ static void rs_rate_init_stub(void *priv_r, struct ieee80211_supported_band *sba
struct ieee80211_sta *sta, void *priv_sta)
{
}
-static struct rate_control_ops rs_ops = {
- .module = NULL,
+
+static const struct rate_control_ops rs_ops = {
.name = RS_NAME,
.tx_status = rs_tx_status,
.get_rate = rs_get_rate,
diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.h b/drivers/net/wireless/iwlwifi/dvm/rs.h
index bdd5644a400b..f6bd25cad203 100644
--- a/drivers/net/wireless/iwlwifi/dvm/rs.h
+++ b/drivers/net/wireless/iwlwifi/dvm/rs.h
@@ -315,7 +315,7 @@ struct iwl_scale_tbl_info {
u8 is_dup; /* 1 = duplicated data streams */
u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
u8 max_search; /* maximun number of tables we can search */
- s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
+ const u16 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
u32 current_rate; /* rate_n_flags, uCode API format */
struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
};
diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c
index 7a1bc1c547e1..cd8377346aff 100644
--- a/drivers/net/wireless/iwlwifi/dvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/dvm/rx.c
@@ -39,7 +39,7 @@
#define IWL_CMD_ENTRY(x) [x] = #x
-const char *iwl_dvm_cmd_strings[REPLY_MAX] = {
+const char *const iwl_dvm_cmd_strings[REPLY_MAX] = {
IWL_CMD_ENTRY(REPLY_ALIVE),
IWL_CMD_ENTRY(REPLY_ERROR),
IWL_CMD_ENTRY(REPLY_ECHO),
diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c
index c0d070c5df5e..9cdd91cdf661 100644
--- a/drivers/net/wireless/iwlwifi/dvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/dvm/sta.c
@@ -590,6 +590,7 @@ void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id,
sizeof(priv->tid_data[sta_id][tid]));
priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
+ priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
priv->num_stations--;
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c
index a6839dfcb82d..398dd096674c 100644
--- a/drivers/net/wireless/iwlwifi/dvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/dvm/tx.c
@@ -1291,8 +1291,6 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
struct iwl_compressed_ba_resp *ba_resp = (void *)pkt->data;
struct iwl_ht_agg *agg;
struct sk_buff_head reclaimed_skbs;
- struct ieee80211_tx_info *info;
- struct ieee80211_hdr *hdr;
struct sk_buff *skb;
int sta_id;
int tid;
@@ -1379,22 +1377,28 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
freed = 0;
skb_queue_walk(&reclaimed_skbs, skb) {
- hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_hdr *hdr = (void *)skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (ieee80211_is_data_qos(hdr->frame_control))
freed++;
else
WARN_ON_ONCE(1);
- info = IEEE80211_SKB_CB(skb);
iwl_trans_free_tx_cmd(priv->trans, info->driver_data[1]);
+ memset(&info->status, 0, sizeof(info->status));
+ /* Packet was transmitted successfully, failures come as single
+ * frames because before failing a frame the firmware transmits
+ * it without aggregation at least once.
+ */
+ info->flags |= IEEE80211_TX_STAT_ACK;
+
if (freed == 1) {
/* this is the first skb we deliver in this batch */
/* put the rate scaling data there */
info = IEEE80211_SKB_CB(skb);
memset(&info->status, 0, sizeof(info->status));
- info->flags |= IEEE80211_TX_STAT_ACK;
info->flags |= IEEE80211_TX_STAT_AMPDU;
info->status.ampdu_ack_len = ba_resp->txed_2_done;
info->status.ampdu_len = ba_resp->txed;
diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c
index 2a59da2ff87a..003a546571d4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-7000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-7000.c
@@ -71,8 +71,8 @@
#define IWL3160_UCODE_API_MAX 8
/* Oldest version we won't warn about */
-#define IWL7260_UCODE_API_OK 7
-#define IWL3160_UCODE_API_OK 7
+#define IWL7260_UCODE_API_OK 8
+#define IWL3160_UCODE_API_OK 8
/* Lowest firmware API version supported */
#define IWL7260_UCODE_API_MIN 7
@@ -95,6 +95,8 @@
#define IWL7265_FW_PRE "iwlwifi-7265-"
#define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode"
+#define NVM_HW_SECTION_NUM_FAMILY_7000 0
+
static const struct iwl_base_params iwl7000_base_params = {
.eeprom_size = OTP_LOW_IMAGE_SIZE,
.num_of_queues = IWLAGN_NUM_QUEUES,
@@ -120,7 +122,8 @@ static const struct iwl_ht_params iwl7000_ht_params = {
.max_inst_size = IWL60_RTC_INST_SIZE, \
.max_data_size = IWL60_RTC_DATA_SIZE, \
.base_params = &iwl7000_base_params, \
- .led_mode = IWL_LED_RF_STATE
+ .led_mode = IWL_LED_RF_STATE, \
+ .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000
const struct iwl_cfg iwl7260_2ac_cfg = {
@@ -131,6 +134,7 @@ const struct iwl_cfg iwl7260_2ac_cfg = {
.nvm_ver = IWL7260_NVM_VERSION,
.nvm_calib_ver = IWL7260_TX_POWER_VERSION,
.host_interrupt_operation_mode = true,
+ .lp_xtal_workaround = true,
};
const struct iwl_cfg iwl7260_2ac_cfg_high_temp = {
@@ -142,6 +146,7 @@ const struct iwl_cfg iwl7260_2ac_cfg_high_temp = {
.nvm_calib_ver = IWL7260_TX_POWER_VERSION,
.high_temp = true,
.host_interrupt_operation_mode = true,
+ .lp_xtal_workaround = true,
};
const struct iwl_cfg iwl7260_2n_cfg = {
@@ -152,6 +157,7 @@ const struct iwl_cfg iwl7260_2n_cfg = {
.nvm_ver = IWL7260_NVM_VERSION,
.nvm_calib_ver = IWL7260_TX_POWER_VERSION,
.host_interrupt_operation_mode = true,
+ .lp_xtal_workaround = true,
};
const struct iwl_cfg iwl7260_n_cfg = {
@@ -162,6 +168,7 @@ const struct iwl_cfg iwl7260_n_cfg = {
.nvm_ver = IWL7260_NVM_VERSION,
.nvm_calib_ver = IWL7260_TX_POWER_VERSION,
.host_interrupt_operation_mode = true,
+ .lp_xtal_workaround = true,
};
const struct iwl_cfg iwl3160_2ac_cfg = {
@@ -194,6 +201,17 @@ const struct iwl_cfg iwl3160_n_cfg = {
.host_interrupt_operation_mode = true,
};
+static const struct iwl_pwr_tx_backoff iwl7265_pwr_tx_backoffs[] = {
+ {.pwr = 1600, .backoff = 0},
+ {.pwr = 1300, .backoff = 467},
+ {.pwr = 900, .backoff = 1900},
+ {.pwr = 800, .backoff = 2630},
+ {.pwr = 700, .backoff = 3720},
+ {.pwr = 600, .backoff = 5550},
+ {.pwr = 500, .backoff = 9350},
+ {0},
+};
+
const struct iwl_cfg iwl7265_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 7265",
.fw_name_pre = IWL7265_FW_PRE,
@@ -201,6 +219,7 @@ const struct iwl_cfg iwl7265_2ac_cfg = {
.ht_params = &iwl7000_ht_params,
.nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
+ .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
};
const struct iwl_cfg iwl7265_2n_cfg = {
@@ -210,6 +229,7 @@ const struct iwl_cfg iwl7265_2n_cfg = {
.ht_params = &iwl7000_ht_params,
.nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
+ .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
};
const struct iwl_cfg iwl7265_n_cfg = {
@@ -219,6 +239,7 @@ const struct iwl_cfg iwl7265_n_cfg = {
.ht_params = &iwl7000_ht_params,
.nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
+ .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
};
MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c
new file mode 100644
index 000000000000..f5bd82b88592
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-8000.c
@@ -0,0 +1,132 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel 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 full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/stringify.h>
+#include "iwl-config.h"
+#include "iwl-agn-hw.h"
+
+/* Highest firmware API version supported */
+#define IWL8000_UCODE_API_MAX 8
+
+/* Oldest version we won't warn about */
+#define IWL8000_UCODE_API_OK 8
+
+/* Lowest firmware API version supported */
+#define IWL8000_UCODE_API_MIN 8
+
+/* NVM versions */
+#define IWL8000_NVM_VERSION 0x0a1d
+#define IWL8000_TX_POWER_VERSION 0xffff /* meaningless */
+
+#define IWL8000_FW_PRE "iwlwifi-8000-"
+#define IWL8000_MODULE_FIRMWARE(api) IWL8000_FW_PRE __stringify(api) ".ucode"
+
+#define NVM_HW_SECTION_NUM_FAMILY_8000 10
+
+static const struct iwl_base_params iwl8000_base_params = {
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .num_of_queues = IWLAGN_NUM_QUEUES,
+ .pll_cfg_val = 0,
+ .shadow_ram_support = true,
+ .led_compensation = 57,
+ .wd_timeout = IWL_LONG_WD_TIMEOUT,
+ .max_event_log_size = 512,
+ .shadow_reg_enable = true,
+ .pcie_l1_allowed = true,
+};
+
+static const struct iwl_ht_params iwl8000_ht_params = {
+ .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
+};
+
+#define IWL_DEVICE_8000 \
+ .ucode_api_max = IWL8000_UCODE_API_MAX, \
+ .ucode_api_ok = IWL8000_UCODE_API_OK, \
+ .ucode_api_min = IWL8000_UCODE_API_MIN, \
+ .device_family = IWL_DEVICE_FAMILY_8000, \
+ .max_inst_size = IWL60_RTC_INST_SIZE, \
+ .max_data_size = IWL60_RTC_DATA_SIZE, \
+ .base_params = &iwl8000_base_params, \
+ .led_mode = IWL_LED_RF_STATE, \
+ .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000
+
+const struct iwl_cfg iwl8260_2ac_cfg = {
+ .name = "Intel(R) Dual Band Wireless AC 8260",
+ .fw_name_pre = IWL8000_FW_PRE,
+ IWL_DEVICE_8000,
+ .ht_params = &iwl8000_ht_params,
+ .nvm_ver = IWL8000_NVM_VERSION,
+ .nvm_calib_ver = IWL8000_TX_POWER_VERSION,
+};
+
+const struct iwl_cfg iwl8260_n_cfg = {
+ .name = "Intel(R) Dual Band Wireless-AC 8260",
+ .fw_name_pre = IWL8000_FW_PRE,
+ IWL_DEVICE_8000,
+ .ht_params = &iwl8000_ht_params,
+ .nvm_ver = IWL8000_NVM_VERSION,
+ .nvm_calib_ver = IWL8000_TX_POWER_VERSION,
+};
+
+MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h
index 1ced525157dc..3f17dc3f2c8a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/iwlwifi/iwl-config.h
@@ -84,6 +84,7 @@ enum iwl_device_family {
IWL_DEVICE_FAMILY_6050,
IWL_DEVICE_FAMILY_6150,
IWL_DEVICE_FAMILY_7000,
+ IWL_DEVICE_FAMILY_8000,
};
/*
@@ -192,6 +193,15 @@ struct iwl_eeprom_params {
bool enhanced_txpower;
};
+/* Tx-backoff power threshold
+ * @pwr: The power limit in mw
+ * @backoff: The tx-backoff in uSec
+ */
+struct iwl_pwr_tx_backoff {
+ u32 pwr;
+ u32 backoff;
+};
+
/**
* struct iwl_cfg
* @name: Offical name of the device
@@ -217,6 +227,9 @@ struct iwl_eeprom_params {
* @high_temp: Is this NIC is designated to be in high temperature.
* @host_interrupt_operation_mode: device needs host interrupt operation
* mode set
+ * @d0i3: device uses d0i3 instead of d3
+ * @nvm_hw_section_num: the ID of the HW NVM section
+ * @pwr_tx_backoffs: translation table between power limits and backoffs
*
* We enable the driver to be backward compatible wrt. hardware features.
* API differences in uCode shouldn't be handled here but through TLVs
@@ -247,6 +260,10 @@ struct iwl_cfg {
const bool internal_wimax_coex;
const bool host_interrupt_operation_mode;
bool high_temp;
+ bool d0i3;
+ u8 nvm_hw_section_num;
+ bool lp_xtal_workaround;
+ const struct iwl_pwr_tx_backoff *pwr_tx_backoffs;
};
/*
@@ -307,6 +324,8 @@ extern const struct iwl_cfg iwl3160_n_cfg;
extern const struct iwl_cfg iwl7265_2ac_cfg;
extern const struct iwl_cfg iwl7265_2n_cfg;
extern const struct iwl_cfg iwl7265_n_cfg;
+extern const struct iwl_cfg iwl8260_2ac_cfg;
+extern const struct iwl_cfg iwl8260_n_cfg;
#endif /* CONFIG_IWLMVM */
#endif /* __IWL_CONFIG_H__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index 9d325516c42d..fe129c94ae3e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -139,6 +139,13 @@
#define CSR_ANA_PLL_CFG (CSR_BASE+0x20c)
/*
+ * CSR HW resources monitor registers
+ */
+#define CSR_MONITOR_CFG_REG (CSR_BASE+0x214)
+#define CSR_MONITOR_STATUS_REG (CSR_BASE+0x228)
+#define CSR_MONITOR_XTAL_RESOURCES (0x00000010)
+
+/*
* CSR Hardware Revision Workaround Register. Indicates hardware rev;
* "step" determines CCK backoff for txpower calculation. Used for 4965 only.
* See also CSR_HW_REV register.
@@ -173,6 +180,7 @@
#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */
#define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */
#define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */
+#define CSR_HW_IF_CONFIG_REG_PERSIST_MODE (0x40000000) /* PERSISTENCE */
#define CSR_INT_PERIODIC_DIS (0x00) /* disable periodic int*/
#define CSR_INT_PERIODIC_ENA (0xFF) /* 255*32 usec ~ 8 msec*/
@@ -240,6 +248,7 @@
* 001 -- MAC power-down
* 010 -- PHY (radio) power-down
* 011 -- Error
+ * 10: XTAL ON request
* 9-6: SYS_CONFIG
* Indicates current system configuration, reflecting pins on chip
* as forced high/low by device circuit board.
@@ -271,6 +280,7 @@
#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004)
#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008)
#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010)
+#define CSR_GP_CNTRL_REG_FLAG_XTAL_ON (0x00000400)
#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001)
@@ -395,37 +405,33 @@
#define CSR_DRAM_INT_TBL_ENABLE (1 << 31)
#define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27)
-/* SECURE boot registers */
-#define CSR_SECURE_BOOT_CONFIG_ADDR (0x100)
-enum secure_boot_config_reg {
- CSR_SECURE_BOOT_CONFIG_INSPECTOR_BURNED_IN_OTP = 0x00000001,
- CSR_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ = 0x00000002,
-};
-
-#define CSR_SECURE_BOOT_CPU1_STATUS_ADDR (0x100)
-#define CSR_SECURE_BOOT_CPU2_STATUS_ADDR (0x100)
-enum secure_boot_status_reg {
- CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS = 0x00000003,
- CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED = 0x00000002,
- CSR_SECURE_BOOT_CPU_STATUS_VERF_SUCCESS = 0x00000004,
- CSR_SECURE_BOOT_CPU_STATUS_VERF_FAIL = 0x00000008,
- CSR_SECURE_BOOT_CPU_STATUS_SIGN_VERF_FAIL = 0x00000010,
-};
-
-#define CSR_UCODE_LOAD_STATUS_ADDR (0x100)
-enum secure_load_status_reg {
- CSR_CPU_STATUS_LOADING_STARTED = 0x00000001,
- CSR_CPU_STATUS_LOADING_COMPLETED = 0x00000002,
- CSR_CPU_STATUS_NUM_OF_LAST_COMPLETED = 0x000000F8,
- CSR_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK = 0x0000FF00,
-};
-
-#define CSR_SECURE_INSPECTOR_CODE_ADDR (0x100)
-#define CSR_SECURE_INSPECTOR_DATA_ADDR (0x100)
-
-#define CSR_SECURE_TIME_OUT (100)
+/*
+ * SHR target access (Shared block memory space)
+ *
+ * Shared internal registers can be accessed directly from PCI bus through SHR
+ * arbiter without need for the MAC HW to be powered up. This is possible due to
+ * indirect read/write via HEEP_CTRL_WRD_PCIEX_CTRL (0xEC) and
+ * HEEP_CTRL_WRD_PCIEX_DATA (0xF4) registers.
+ *
+ * Use iwl_write32()/iwl_read32() family to access these registers. The MAC HW
+ * need not be powered up so no "grab inc access" is required.
+ */
-#define FH_TCSR_0_REG0 (0x1D00)
+/*
+ * Registers for accessing shared registers (e.g. SHR_APMG_GP1,
+ * SHR_APMG_XTAL_CFG). For example, to read from SHR_APMG_GP1 register (0x1DC),
+ * first, write to the control register:
+ * HEEP_CTRL_WRD_PCIEX_CTRL[15:0] = 0x1DC (offset of the SHR_APMG_GP1 register)
+ * HEEP_CTRL_WRD_PCIEX_CTRL[29:28] = 2 (read access)
+ * second, read from the data register HEEP_CTRL_WRD_PCIEX_DATA[31:0].
+ *
+ * To write the register, first, write to the data register
+ * HEEP_CTRL_WRD_PCIEX_DATA[31:0] and then:
+ * HEEP_CTRL_WRD_PCIEX_CTRL[15:0] = 0x1DC (offset of the SHR_APMG_GP1 register)
+ * HEEP_CTRL_WRD_PCIEX_CTRL[29:28] = 3 (write access)
+ */
+#define HEEP_CTRL_WRD_PCIEX_CTRL_REG (CSR_BASE+0x0ec)
+#define HEEP_CTRL_WRD_PCIEX_DATA_REG (CSR_BASE+0x0f4)
/*
* HBUS (Host-side Bus)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index a75aac986a23..c8cbdbe15924 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -126,6 +126,7 @@ do { \
/* 0x00000F00 - 0x00000100 */
#define IWL_DL_POWER 0x00000100
#define IWL_DL_TEMP 0x00000200
+#define IWL_DL_RPM 0x00000400
#define IWL_DL_SCAN 0x00000800
/* 0x0000F000 - 0x00001000 */
#define IWL_DL_ASSOC 0x00001000
@@ -189,5 +190,6 @@ do { \
#define IWL_DEBUG_RADIO(p, f, a...) IWL_DEBUG(p, IWL_DL_RADIO, f, ## a)
#define IWL_DEBUG_POWER(p, f, a...) IWL_DEBUG(p, IWL_DL_POWER, f, ## a)
#define IWL_DEBUG_11H(p, f, a...) IWL_DEBUG(p, IWL_DL_11H, f, ## a)
+#define IWL_DEBUG_RPM(p, f, a...) IWL_DEBUG(p, IWL_DL_RPM, f, ## a)
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index c3728163be46..0a3e841b44a9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -128,7 +128,7 @@ struct iwl_drv {
const struct iwl_cfg *cfg;
int fw_index; /* firmware we're trying to load */
- char firmware_name[25]; /* name of firmware file to load */
+ char firmware_name[32]; /* name of firmware file to load */
struct completion request_firmware_complete;
@@ -237,7 +237,8 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first)
return -ENOENT;
}
- sprintf(drv->firmware_name, "%s%s%s", name_pre, tag, ".ucode");
+ snprintf(drv->firmware_name, sizeof(drv->firmware_name), "%s%s.ucode",
+ name_pre, tag);
IWL_DEBUG_INFO(drv, "attempting to load firmware %s'%s'\n",
(drv->fw_index == UCODE_EXPERIMENTAL_INDEX)
@@ -403,6 +404,38 @@ static int iwl_set_default_calib(struct iwl_drv *drv, const u8 *data)
return 0;
}
+static int iwl_set_ucode_api_flags(struct iwl_drv *drv, const u8 *data,
+ struct iwl_ucode_capabilities *capa)
+{
+ const struct iwl_ucode_api *ucode_api = (void *)data;
+ u32 api_index = le32_to_cpu(ucode_api->api_index);
+
+ if (api_index >= IWL_API_ARRAY_SIZE) {
+ IWL_ERR(drv, "api_index larger than supported by driver\n");
+ return -EINVAL;
+ }
+
+ capa->api[api_index] = le32_to_cpu(ucode_api->api_flags);
+
+ return 0;
+}
+
+static int iwl_set_ucode_capabilities(struct iwl_drv *drv, const u8 *data,
+ struct iwl_ucode_capabilities *capa)
+{
+ const struct iwl_ucode_capa *ucode_capa = (void *)data;
+ u32 api_index = le32_to_cpu(ucode_capa->api_index);
+
+ if (api_index >= IWL_CAPABILITIES_ARRAY_SIZE) {
+ IWL_ERR(drv, "api_index larger than supported by driver\n");
+ return -EINVAL;
+ }
+
+ capa->capa[api_index] = le32_to_cpu(ucode_capa->api_capa);
+
+ return 0;
+}
+
static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv,
const struct firmware *ucode_raw,
struct iwl_firmware_pieces *pieces)
@@ -637,6 +670,18 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
*/
capa->flags = le32_to_cpup((__le32 *)tlv_data);
break;
+ case IWL_UCODE_TLV_API_CHANGES_SET:
+ if (tlv_len != sizeof(struct iwl_ucode_api))
+ goto invalid_tlv_len;
+ if (iwl_set_ucode_api_flags(drv, tlv_data, capa))
+ goto tlv_error;
+ break;
+ case IWL_UCODE_TLV_ENABLED_CAPABILITIES:
+ if (tlv_len != sizeof(struct iwl_ucode_capa))
+ goto invalid_tlv_len;
+ if (iwl_set_ucode_capabilities(drv, tlv_data, capa))
+ goto tlv_error;
+ break;
case IWL_UCODE_TLV_INIT_EVTLOG_PTR:
if (tlv_len != sizeof(u32))
goto invalid_tlv_len;
@@ -727,6 +772,12 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
if (tlv_len != sizeof(u32))
goto invalid_tlv_len;
drv->fw.phy_config = le32_to_cpup((__le32 *)tlv_data);
+ drv->fw.valid_tx_ant = (drv->fw.phy_config &
+ FW_PHY_CFG_TX_CHAIN) >>
+ FW_PHY_CFG_TX_CHAIN_POS;
+ drv->fw.valid_rx_ant = (drv->fw.phy_config &
+ FW_PHY_CFG_RX_CHAIN) >>
+ FW_PHY_CFG_RX_CHAIN_POS;
break;
case IWL_UCODE_TLV_SECURE_SEC_RT:
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR,
@@ -1286,7 +1337,7 @@ module_param_named(swcrypto, iwlwifi_mod_params.sw_crypto, int, S_IRUGO);
MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
module_param_named(11n_disable, iwlwifi_mod_params.disable_11n, uint, S_IRUGO);
MODULE_PARM_DESC(11n_disable,
- "disable 11n functionality, bitmap: 1: full, 2: agg TX, 4: agg RX");
+ "disable 11n functionality, bitmap: 1: full, 2: disable agg TX, 4: disable agg RX, 8 enable agg TX");
module_param_named(amsdu_size_8K, iwlwifi_mod_params.amsdu_size_8K,
int, S_IRUGO);
MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0)");
@@ -1300,8 +1351,7 @@ MODULE_PARM_DESC(antenna_coupling,
module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO);
MODULE_PARM_DESC(wd_disable,
- "Disable stuck queue watchdog timer 0=system default, "
- "1=disable, 2=enable (default: 0)");
+ "Disable stuck queue watchdog timer 0=system default, 1=disable (default: 1)");
module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO);
MODULE_PARM_DESC(nvm_file, "NVM file name");
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h
index 592c01e11013..3c72cb710b0c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.h
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.h
@@ -70,6 +70,20 @@
#define DRV_COPYRIGHT "Copyright(c) 2003- 2014 Intel Corporation"
#define DRV_AUTHOR "<ilw@linux.intel.com>"
+/* radio config bits (actual values from NVM definition) */
+#define NVM_RF_CFG_DASH_MSK(x) (x & 0x3) /* bits 0-1 */
+#define NVM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */
+#define NVM_RF_CFG_TYPE_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */
+#define NVM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */
+#define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */
+#define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
+
+#define NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(x) (x & 0xF)
+#define NVM_RF_CFG_DASH_MSK_FAMILY_8000(x) ((x >> 4) & 0xF)
+#define NVM_RF_CFG_STEP_MSK_FAMILY_8000(x) ((x >> 8) & 0xF)
+#define NVM_RF_CFG_TYPE_MSK_FAMILY_8000(x) ((x >> 12) & 0xFFF)
+#define NVM_RF_CFG_TX_ANT_MSK_FAMILY_8000(x) ((x >> 24) & 0xF)
+#define NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(x) ((x >> 28) & 0xF)
/**
* DOC: Driver system flows - drv component
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
index e3c7deafabe6..f0548b8a64b0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
@@ -81,16 +81,17 @@ struct iwl_nvm_data {
bool sku_cap_band_24GHz_enable;
bool sku_cap_band_52GHz_enable;
bool sku_cap_11n_enable;
+ bool sku_cap_11ac_enable;
bool sku_cap_amt_enable;
bool sku_cap_ipan_enable;
- u8 radio_cfg_type;
+ u16 radio_cfg_type;
u8 radio_cfg_step;
u8 radio_cfg_dash;
u8 radio_cfg_pnum;
u8 valid_tx_ant, valid_rx_ant;
- u16 nvm_version;
+ u32 nvm_version;
s8 max_tx_pwr_half_dbm;
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 88e2d6eb569f..b45e576a4b57 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -126,6 +126,8 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_SECURE_SEC_WOWLAN = 26,
IWL_UCODE_TLV_NUM_OF_CPU = 27,
IWL_UCODE_TLV_CSCHEME = 28,
+ IWL_UCODE_TLV_API_CHANGES_SET = 29,
+ IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30,
};
struct iwl_ucode_tlv {
@@ -158,4 +160,19 @@ struct iwl_tlv_ucode_header {
u8 data[0];
};
+/*
+ * ucode TLVs
+ *
+ * ability to get extension for: flags & capabilities from ucode binaries files
+ */
+struct iwl_ucode_api {
+ __le32 api_index;
+ __le32 api_flags;
+} __packed;
+
+struct iwl_ucode_capa {
+ __le32 api_index;
+ __le32 api_capa;
+} __packed;
+
#endif /* __iwl_fw_file_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index 5f1493c44097..d14f19339d61 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -92,9 +92,11 @@
* @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API
* @IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command
* containing CAM (Continuous Active Mode) indication.
- * @IWL_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a
- * single bound interface).
+ * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_DCM: support power save on BSS station and
+ * P2P client interfaces simultaneously if they are in different bindings.
* @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save
+ * @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering.
+ * @IWL_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients
*/
enum iwl_ucode_tlv_flag {
IWL_UCODE_TLV_FLAGS_PAN = BIT(0),
@@ -116,9 +118,27 @@ enum iwl_ucode_tlv_flag {
IWL_UCODE_TLV_FLAGS_SCHED_SCAN = BIT(17),
IWL_UCODE_TLV_FLAGS_STA_KEY_CMD = BIT(19),
IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD = BIT(20),
- IWL_UCODE_TLV_FLAGS_P2P_PS = BIT(21),
+ IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM = BIT(22),
IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24),
IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26),
+ IWL_UCODE_TLV_FLAGS_BCAST_FILTERING = BIT(29),
+ IWL_UCODE_TLV_FLAGS_GO_UAPSD = BIT(30),
+};
+
+/**
+ * enum iwl_ucode_tlv_api - ucode api
+ * @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field.
+ */
+enum iwl_ucode_tlv_api {
+ IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0),
+};
+
+/**
+ * enum iwl_ucode_tlv_capa - ucode capabilities
+ * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3
+ */
+enum iwl_ucode_tlv_capa {
+ IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0),
};
/* The default calibrate table size if not specified by firmware file */
@@ -160,13 +180,16 @@ enum iwl_ucode_sec {
* For 16.0 uCode and above, there is no differentiation between sections,
* just an offset to the HW address.
*/
-#define IWL_UCODE_SECTION_MAX 6
-#define IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU (IWL_UCODE_SECTION_MAX/2)
+#define IWL_UCODE_SECTION_MAX 12
+#define IWL_API_ARRAY_SIZE 1
+#define IWL_CAPABILITIES_ARRAY_SIZE 1
struct iwl_ucode_capabilities {
u32 max_probe_length;
u32 standard_phy_calibration_size;
u32 flags;
+ u32 api[IWL_API_ARRAY_SIZE];
+ u32 capa[IWL_CAPABILITIES_ARRAY_SIZE];
};
/* one for each uCode image (inst/data, init/runtime/wowlan) */
@@ -285,22 +308,12 @@ struct iwl_fw {
struct iwl_tlv_calib_ctrl default_calib[IWL_UCODE_TYPE_MAX];
u32 phy_config;
+ u8 valid_tx_ant;
+ u8 valid_rx_ant;
bool mvm_fw;
struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS];
};
-static inline u8 iwl_fw_valid_tx_ant(const struct iwl_fw *fw)
-{
- return (fw->phy_config & FW_PHY_CFG_TX_CHAIN) >>
- FW_PHY_CFG_TX_CHAIN_POS;
-}
-
-static inline u8 iwl_fw_valid_rx_ant(const struct iwl_fw *fw)
-{
- return (fw->phy_config & FW_PHY_CFG_RX_CHAIN) >>
- FW_PHY_CFG_RX_CHAIN_POS;
-}
-
#endif /* __iwl_fw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c
index f98175a0d35b..44cc3cf45762 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.c
+++ b/drivers/net/wireless/iwlwifi/iwl-io.c
@@ -93,14 +93,14 @@ int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
}
IWL_EXPORT_SYMBOL(iwl_poll_direct_bit);
-static inline u32 __iwl_read_prph(struct iwl_trans *trans, u32 ofs)
+u32 __iwl_read_prph(struct iwl_trans *trans, u32 ofs)
{
u32 val = iwl_trans_read_prph(trans, ofs);
trace_iwlwifi_dev_ioread_prph32(trans->dev, ofs, val);
return val;
}
-static inline void __iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
+void __iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
{
trace_iwlwifi_dev_iowrite_prph32(trans->dev, ofs, val);
iwl_trans_write_prph(trans, ofs, val);
@@ -130,6 +130,21 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
}
IWL_EXPORT_SYMBOL(iwl_write_prph);
+int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr,
+ u32 bits, u32 mask, int timeout)
+{
+ int t = 0;
+
+ do {
+ if ((iwl_read_prph(trans, addr) & mask) == (bits & mask))
+ return t;
+ udelay(IWL_POLL_INTERVAL);
+ t += IWL_POLL_INTERVAL;
+ } while (t < timeout);
+
+ return -ETIMEDOUT;
+}
+
void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
{
unsigned long flags;
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
index c339c1bed080..665ddd9dbbc4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -70,8 +70,12 @@ u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg);
void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value);
+u32 __iwl_read_prph(struct iwl_trans *trans, u32 ofs);
u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs);
+void __iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val);
void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val);
+int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr,
+ u32 bits, u32 mask, int timeout);
void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask);
void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
u32 bits, u32 mask);
diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h
index 0a84ade7edac..d994317db85b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-modparams.h
+++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h
@@ -79,9 +79,12 @@ enum iwl_power_level {
IWL_POWER_NUM
};
-#define IWL_DISABLE_HT_ALL BIT(0)
-#define IWL_DISABLE_HT_TXAGG BIT(1)
-#define IWL_DISABLE_HT_RXAGG BIT(2)
+enum iwl_disable_11n {
+ IWL_DISABLE_HT_ALL = BIT(0),
+ IWL_DISABLE_HT_TXAGG = BIT(1),
+ IWL_DISABLE_HT_RXAGG = BIT(2),
+ IWL_ENABLE_HT_TXAGG = BIT(3),
+};
/**
* struct iwl_mod_params
@@ -90,10 +93,10 @@ enum iwl_power_level {
*
* @sw_crypto: using hardware encryption, default = 0
* @disable_11n: disable 11n capabilities, default = 0,
- * use IWL_DISABLE_HT_* constants
+ * use IWL_[DIS,EN]ABLE_HT_* constants
* @amsdu_size_8K: enable 8K amsdu size, default = 0
* @restart_fw: restart firmware, default = 1
- * @wd_disable: enable stuck queue check, default = 0
+ * @wd_disable: disable stuck queue check, default = 1
* @bt_coex_active: enable bt coex, default = true
* @led_mode: system default, default = 0
* @power_save: disable power save, default = false
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
index f06f4cbe1317..6be30c698506 100644
--- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
@@ -71,7 +71,7 @@ enum wkp_nvm_offsets {
/* NVM HW-Section offset (in words) definitions */
HW_ADDR = 0x15,
-/* NVM SW-Section offset (in words) definitions */
+ /* NVM SW-Section offset (in words) definitions */
NVM_SW_SECTION = 0x1C0,
NVM_VERSION = 0,
RADIO_CFG = 1,
@@ -79,11 +79,32 @@ enum wkp_nvm_offsets {
N_HW_ADDRS = 3,
NVM_CHANNELS = 0x1E0 - NVM_SW_SECTION,
-/* NVM calibration section offset (in words) definitions */
+ /* NVM calibration section offset (in words) definitions */
NVM_CALIB_SECTION = 0x2B8,
XTAL_CALIB = 0x316 - NVM_CALIB_SECTION
};
+enum family_8000_nvm_offsets {
+ /* NVM HW-Section offset (in words) definitions */
+ HW_ADDR0_FAMILY_8000 = 0x12,
+ HW_ADDR1_FAMILY_8000 = 0x16,
+ MAC_ADDRESS_OVERRIDE_FAMILY_8000 = 1,
+
+ /* NVM SW-Section offset (in words) definitions */
+ NVM_SW_SECTION_FAMILY_8000 = 0x1C0,
+ NVM_VERSION_FAMILY_8000 = 0,
+ RADIO_CFG_FAMILY_8000 = 2,
+ SKU_FAMILY_8000 = 4,
+ N_HW_ADDRS_FAMILY_8000 = 5,
+
+ /* NVM REGULATORY -Section offset (in words) definitions */
+ NVM_CHANNELS_FAMILY_8000 = 0,
+
+ /* NVM calibration section offset (in words) definitions */
+ NVM_CALIB_SECTION_FAMILY_8000 = 0x2B8,
+ XTAL_CALIB_FAMILY_8000 = 0x316 - NVM_CALIB_SECTION_FAMILY_8000
+};
+
/* SKU Capabilities (actual values from NVM definition) */
enum nvm_sku_bits {
NVM_SKU_CAP_BAND_24GHZ = BIT(0),
@@ -92,14 +113,6 @@ enum nvm_sku_bits {
NVM_SKU_CAP_11AC_ENABLE = BIT(3),
};
-/* radio config bits (actual values from NVM definition) */
-#define NVM_RF_CFG_DASH_MSK(x) (x & 0x3) /* bits 0-1 */
-#define NVM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */
-#define NVM_RF_CFG_TYPE_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */
-#define NVM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */
-#define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */
-#define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
-
/*
* These are the channel numbers in the order that they are stored in the NVM
*/
@@ -112,7 +125,17 @@ static const u8 iwl_nvm_channels[] = {
149, 153, 157, 161, 165
};
+static const u8 iwl_nvm_channels_family_8000[] = {
+ /* 2.4 GHz */
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ /* 5 GHz */
+ 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92,
+ 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
+ 149, 153, 157, 161, 165, 169, 173, 177, 181
+};
+
#define IWL_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels)
+#define IWL_NUM_CHANNELS_FAMILY_8000 ARRAY_SIZE(iwl_nvm_channels_family_8000)
#define NUM_2GHZ_CHANNELS 14
#define FIRST_2GHZ_HT_MINUS 5
#define LAST_2GHZ_HT_PLUS 9
@@ -179,13 +202,28 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
struct ieee80211_channel *channel;
u16 ch_flags;
bool is_5ghz;
+ int num_of_ch;
+ const u8 *nvm_chan;
+
+ if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+ num_of_ch = IWL_NUM_CHANNELS;
+ nvm_chan = &iwl_nvm_channels[0];
+ } else {
+ num_of_ch = IWL_NUM_CHANNELS_FAMILY_8000;
+ nvm_chan = &iwl_nvm_channels_family_8000[0];
+ }
- for (ch_idx = 0; ch_idx < IWL_NUM_CHANNELS; ch_idx++) {
+ for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
+
+ if (ch_idx >= NUM_2GHZ_CHANNELS &&
+ !data->sku_cap_band_52GHz_enable)
+ ch_flags &= ~NVM_CHANNEL_VALID;
+
if (!(ch_flags & NVM_CHANNEL_VALID)) {
IWL_DEBUG_EEPROM(dev,
"Ch. %d Flags %x [%sGHz] - No traffic\n",
- iwl_nvm_channels[ch_idx],
+ nvm_chan[ch_idx],
ch_flags,
(ch_idx >= NUM_2GHZ_CHANNELS) ?
"5.2" : "2.4");
@@ -195,7 +233,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
channel = &data->channels[n_channels];
n_channels++;
- channel->hw_value = iwl_nvm_channels[ch_idx];
+ channel->hw_value = nvm_chan[ch_idx];
channel->band = (ch_idx < NUM_2GHZ_CHANNELS) ?
IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
channel->center_freq =
@@ -206,11 +244,11 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
channel->flags = IEEE80211_CHAN_NO_HT40;
if (ch_idx < NUM_2GHZ_CHANNELS &&
(ch_flags & NVM_CHANNEL_40MHZ)) {
- if (iwl_nvm_channels[ch_idx] <= LAST_2GHZ_HT_PLUS)
+ if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS)
channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
- if (iwl_nvm_channels[ch_idx] >= FIRST_2GHZ_HT_MINUS)
+ if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS)
channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
- } else if (iwl_nvm_channels[ch_idx] <= LAST_5GHZ_HT &&
+ } else if (nvm_chan[ch_idx] <= LAST_5GHZ_HT &&
(ch_flags & NVM_CHANNEL_40MHZ)) {
if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
@@ -261,9 +299,11 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
struct iwl_nvm_data *data,
- struct ieee80211_sta_vht_cap *vht_cap)
+ struct ieee80211_sta_vht_cap *vht_cap,
+ u8 tx_chains, u8 rx_chains)
{
- int num_ants = num_of_ant(data->valid_rx_ant);
+ int num_rx_ants = num_of_ant(rx_chains);
+ int num_tx_ants = num_of_ant(tx_chains);
vht_cap->vht_supported = true;
@@ -273,8 +313,10 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT |
7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
- if (num_ants > 1)
+ if (num_tx_ants > 1)
vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
+ else
+ vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
if (iwlwifi_mod_params.amsdu_size_8K)
vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
@@ -289,10 +331,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
IEEE80211_VHT_MCS_NOT_SUPPORTED << 14);
- if (num_ants == 1 ||
- cfg->rx_with_siso_diversity) {
- vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
- IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
+ if (num_rx_ants == 1 || cfg->rx_with_siso_diversity) {
+ vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN;
/* this works because NOT_SUPPORTED == 3 */
vht_cap->vht_mcs.rx_mcs_map |=
cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2);
@@ -302,14 +342,23 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
}
static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
- struct iwl_nvm_data *data, const __le16 *nvm_sw,
- bool enable_vht, u8 tx_chains, u8 rx_chains)
+ struct iwl_nvm_data *data,
+ const __le16 *ch_section, bool enable_vht,
+ u8 tx_chains, u8 rx_chains)
{
- int n_channels = iwl_init_channel_map(dev, cfg, data,
- &nvm_sw[NVM_CHANNELS]);
+ int n_channels;
int n_used = 0;
struct ieee80211_supported_band *sband;
+ if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
+ n_channels = iwl_init_channel_map(
+ dev, cfg, data,
+ &ch_section[NVM_CHANNELS]);
+ else
+ n_channels = iwl_init_channel_map(
+ dev, cfg, data,
+ &ch_section[NVM_CHANNELS_FAMILY_8000]);
+
sband = &data->bands[IEEE80211_BAND_2GHZ];
sband->band = IEEE80211_BAND_2GHZ;
sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS];
@@ -328,80 +377,160 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ,
tx_chains, rx_chains);
if (enable_vht)
- iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap);
+ iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap,
+ tx_chains, rx_chains);
if (n_channels != n_used)
IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n",
n_used, n_channels);
}
+static int iwl_get_sku(const struct iwl_cfg *cfg,
+ const __le16 *nvm_sw)
+{
+ if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
+ return le16_to_cpup(nvm_sw + SKU);
+ else
+ return le32_to_cpup((__le32 *)(nvm_sw + SKU_FAMILY_8000));
+}
+
+static int iwl_get_nvm_version(const struct iwl_cfg *cfg,
+ const __le16 *nvm_sw)
+{
+ if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
+ return le16_to_cpup(nvm_sw + NVM_VERSION);
+ else
+ return le32_to_cpup((__le32 *)(nvm_sw +
+ NVM_VERSION_FAMILY_8000));
+}
+
+static int iwl_get_radio_cfg(const struct iwl_cfg *cfg,
+ const __le16 *nvm_sw)
+{
+ if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
+ return le16_to_cpup(nvm_sw + RADIO_CFG);
+ else
+ return le32_to_cpup((__le32 *)(nvm_sw + RADIO_CFG_FAMILY_8000));
+}
+
+#define N_HW_ADDRS_MASK_FAMILY_8000 0xF
+static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg,
+ const __le16 *nvm_sw)
+{
+ if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
+ return le16_to_cpup(nvm_sw + N_HW_ADDRS);
+ else
+ return le32_to_cpup((__le32 *)(nvm_sw + N_HW_ADDRS_FAMILY_8000))
+ & N_HW_ADDRS_MASK_FAMILY_8000;
+}
+
+static void iwl_set_radio_cfg(const struct iwl_cfg *cfg,
+ struct iwl_nvm_data *data,
+ u32 radio_cfg)
+{
+ if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+ data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg);
+ data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg);
+ data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg);
+ data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg);
+ return;
+ }
+
+ /* set the radio configuration for family 8000 */
+ data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK_FAMILY_8000(radio_cfg);
+ data->radio_cfg_step = NVM_RF_CFG_STEP_MSK_FAMILY_8000(radio_cfg);
+ data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK_FAMILY_8000(radio_cfg);
+ data->radio_cfg_pnum = NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(radio_cfg);
+}
+
+static void iwl_set_hw_address(const struct iwl_cfg *cfg,
+ struct iwl_nvm_data *data,
+ const __le16 *nvm_sec)
+{
+ u8 hw_addr[ETH_ALEN];
+
+ if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
+ memcpy(hw_addr, nvm_sec + HW_ADDR, ETH_ALEN);
+ else
+ memcpy(hw_addr, nvm_sec + MAC_ADDRESS_OVERRIDE_FAMILY_8000,
+ ETH_ALEN);
+
+ /* The byte order is little endian 16 bit, meaning 214365 */
+ data->hw_addr[0] = hw_addr[1];
+ data->hw_addr[1] = hw_addr[0];
+ data->hw_addr[2] = hw_addr[3];
+ data->hw_addr[3] = hw_addr[2];
+ data->hw_addr[4] = hw_addr[5];
+ data->hw_addr[5] = hw_addr[4];
+}
+
struct iwl_nvm_data *
iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
const __le16 *nvm_hw, const __le16 *nvm_sw,
- const __le16 *nvm_calib, u8 tx_chains, u8 rx_chains)
+ const __le16 *nvm_calib, const __le16 *regulatory,
+ const __le16 *mac_override, u8 tx_chains, u8 rx_chains)
{
struct iwl_nvm_data *data;
- u8 hw_addr[ETH_ALEN];
- u16 radio_cfg, sku;
-
- data = kzalloc(sizeof(*data) +
- sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS,
- GFP_KERNEL);
+ u32 sku;
+ u32 radio_cfg;
+
+ if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
+ data = kzalloc(sizeof(*data) +
+ sizeof(struct ieee80211_channel) *
+ IWL_NUM_CHANNELS,
+ GFP_KERNEL);
+ else
+ data = kzalloc(sizeof(*data) +
+ sizeof(struct ieee80211_channel) *
+ IWL_NUM_CHANNELS_FAMILY_8000,
+ GFP_KERNEL);
if (!data)
return NULL;
- data->nvm_version = le16_to_cpup(nvm_sw + NVM_VERSION);
+ data->nvm_version = iwl_get_nvm_version(cfg, nvm_sw);
- radio_cfg = le16_to_cpup(nvm_sw + RADIO_CFG);
- data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg);
- data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg);
- data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg);
- data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg);
- data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK(radio_cfg);
- data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK(radio_cfg);
+ radio_cfg = iwl_get_radio_cfg(cfg, nvm_sw);
+ iwl_set_radio_cfg(cfg, data, radio_cfg);
- sku = le16_to_cpup(nvm_sw + SKU);
+ sku = iwl_get_sku(cfg, nvm_sw);
data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ;
data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ;
data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE;
+ data->sku_cap_11ac_enable = sku & NVM_SKU_CAP_11AC_ENABLE;
if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
data->sku_cap_11n_enable = false;
- /* check overrides (some devices have wrong NVM) */
- if (cfg->valid_tx_ant)
- data->valid_tx_ant = cfg->valid_tx_ant;
- if (cfg->valid_rx_ant)
- data->valid_rx_ant = cfg->valid_rx_ant;
+ data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw);
- if (!data->valid_tx_ant || !data->valid_rx_ant) {
- IWL_ERR_DEV(dev, "invalid antennas (0x%x, 0x%x)\n",
- data->valid_tx_ant, data->valid_rx_ant);
- kfree(data);
- return NULL;
+ if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+ /* Checking for required sections */
+ if (!nvm_calib) {
+ IWL_ERR_DEV(dev,
+ "Can't parse empty Calib NVM sections\n");
+ kfree(data);
+ return NULL;
+ }
+ /* in family 8000 Xtal calibration values moved to OTP */
+ data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB);
+ data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1);
}
- data->n_hw_addrs = le16_to_cpup(nvm_sw + N_HW_ADDRS);
+ if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+ iwl_set_hw_address(cfg, data, nvm_hw);
- data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB);
- data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1);
+ iwl_init_sbands(dev, cfg, data, nvm_sw,
+ sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains,
+ rx_chains);
+ } else {
+ /* MAC address in family 8000 */
+ iwl_set_hw_address(cfg, data, mac_override);
- /* The byte order is little endian 16 bit, meaning 214365 */
- memcpy(hw_addr, nvm_hw + HW_ADDR, ETH_ALEN);
- data->hw_addr[0] = hw_addr[1];
- data->hw_addr[1] = hw_addr[0];
- data->hw_addr[2] = hw_addr[3];
- data->hw_addr[3] = hw_addr[2];
- data->hw_addr[4] = hw_addr[5];
- data->hw_addr[5] = hw_addr[4];
-
- iwl_init_sbands(dev, cfg, data, nvm_sw, sku & NVM_SKU_CAP_11AC_ENABLE,
- tx_chains, rx_chains);
+ iwl_init_sbands(dev, cfg, data, regulatory,
+ sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains,
+ rx_chains);
+ }
- data->calib_version = 255; /* TODO:
- this value will prevent some checks from
- failing, we need to check if this
- field is still needed, and if it does,
- where is it in the NVM*/
+ data->calib_version = 255;
return data;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h
index 0c4399aba8c6..c9c45a39d212 100644
--- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h
@@ -75,6 +75,7 @@
struct iwl_nvm_data *
iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
const __le16 *nvm_hw, const __le16 *nvm_sw,
- const __le16 *nvm_calib, u8 tx_chains, u8 rx_chains);
+ const __le16 *nvm_calib, const __le16 *regulatory,
+ const __le16 *mac_override, u8 tx_chains, u8 rx_chains);
#endif /* __iwl_nvm_parse_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
index b5be51f3cd3d..ea29504ac617 100644
--- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h
+++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
@@ -119,7 +119,8 @@ struct iwl_cfg;
* @queue_not_full: notifies that a HW queue is not full any more.
* Must be atomic and called with BH disabled.
* @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that
- * the radio is killed. May sleep.
+ * the radio is killed. Return %true if the device should be stopped by
+ * the transport immediately after the call. May sleep.
* @free_skb: allows the transport layer to free skbs that haven't been
* reclaimed by the op_mode. This can happen when the driver is freed and
* there are Tx packets pending in the transport layer.
@@ -131,6 +132,8 @@ struct iwl_cfg;
* @nic_config: configure NIC, called before firmware is started.
* May sleep
* @wimax_active: invoked when WiMax becomes active. May sleep
+ * @enter_d0i3: configure the fw to enter d0i3. May sleep.
+ * @exit_d0i3: configure the fw to exit d0i3. May sleep.
*/
struct iwl_op_mode_ops {
struct iwl_op_mode *(*start)(struct iwl_trans *trans,
@@ -142,12 +145,14 @@ struct iwl_op_mode_ops {
struct iwl_device_cmd *cmd);
void (*queue_full)(struct iwl_op_mode *op_mode, int queue);
void (*queue_not_full)(struct iwl_op_mode *op_mode, int queue);
- void (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state);
+ bool (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state);
void (*free_skb)(struct iwl_op_mode *op_mode, struct sk_buff *skb);
void (*nic_error)(struct iwl_op_mode *op_mode);
void (*cmd_queue_full)(struct iwl_op_mode *op_mode);
void (*nic_config)(struct iwl_op_mode *op_mode);
void (*wimax_active)(struct iwl_op_mode *op_mode);
+ int (*enter_d0i3)(struct iwl_op_mode *op_mode);
+ int (*exit_d0i3)(struct iwl_op_mode *op_mode);
};
int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops);
@@ -155,7 +160,7 @@ void iwl_opmode_deregister(const char *name);
/**
* struct iwl_op_mode - operational mode
- * @ops - pointer to its own ops
+ * @ops: pointer to its own ops
*
* This holds an implementation of the mac80211 / fw API.
*/
@@ -191,11 +196,11 @@ static inline void iwl_op_mode_queue_not_full(struct iwl_op_mode *op_mode,
op_mode->ops->queue_not_full(op_mode, queue);
}
-static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode,
- bool state)
+static inline bool __must_check
+iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode, bool state)
{
might_sleep();
- op_mode->ops->hw_rf_kill(op_mode, state);
+ return op_mode->ops->hw_rf_kill(op_mode, state);
}
static inline void iwl_op_mode_free_skb(struct iwl_op_mode *op_mode,
@@ -226,4 +231,22 @@ static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode)
op_mode->ops->wimax_active(op_mode);
}
+static inline int iwl_op_mode_enter_d0i3(struct iwl_op_mode *op_mode)
+{
+ might_sleep();
+
+ if (!op_mode->ops->enter_d0i3)
+ return 0;
+ return op_mode->ops->enter_d0i3(op_mode);
+}
+
+static inline int iwl_op_mode_exit_d0i3(struct iwl_op_mode *op_mode)
+{
+ might_sleep();
+
+ if (!op_mode->ops->exit_d0i3)
+ return 0;
+ return op_mode->ops->exit_d0i3(op_mode);
+}
+
#endif /* __iwl_op_mode_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/iwlwifi/iwl-phy-db.c
index fa77d63a277a..b761ac4822a3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-phy-db.c
+++ b/drivers/net/wireless/iwlwifi/iwl-phy-db.c
@@ -72,7 +72,7 @@
#include "iwl-trans.h"
#define CHANNEL_NUM_SIZE 4 /* num of channels in calib_ch size */
-#define IWL_NUM_PAPD_CH_GROUPS 4
+#define IWL_NUM_PAPD_CH_GROUPS 7
#define IWL_NUM_TXP_CH_GROUPS 9
struct iwl_phy_db_entry {
@@ -383,7 +383,7 @@ static int iwl_phy_db_send_all_channel_groups(
if (!entry)
return -EINVAL;
- if (WARN_ON_ONCE(!entry->size))
+ if (!entry->size)
continue;
/* Send the requested PHY DB section */
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 100bd0d79681..5f657c501406 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -95,7 +95,8 @@
#define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */
#define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060)
-#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)
+#define APMG_PCIDEV_STT_VAL_PERSIST_DIS (0x00000200)
+#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)
#define APMG_RTC_INT_STT_RFKILL (0x10000000)
@@ -105,6 +106,33 @@
/* Device NMI register */
#define DEVICE_SET_NMI_REG 0x00a01c30
+/* Shared registers (0x0..0x3ff, via target indirect or periphery */
+#define SHR_BASE 0x00a10000
+
+/* Shared GP1 register */
+#define SHR_APMG_GP1_REG 0x01dc
+#define SHR_APMG_GP1_REG_PRPH (SHR_BASE + SHR_APMG_GP1_REG)
+#define SHR_APMG_GP1_WF_XTAL_LP_EN 0x00000004
+#define SHR_APMG_GP1_CHICKEN_BIT_SELECT 0x80000000
+
+/* Shared DL_CFG register */
+#define SHR_APMG_DL_CFG_REG 0x01c4
+#define SHR_APMG_DL_CFG_REG_PRPH (SHR_BASE + SHR_APMG_DL_CFG_REG)
+#define SHR_APMG_DL_CFG_RTCS_CLK_SELECTOR_MSK 0x000000c0
+#define SHR_APMG_DL_CFG_RTCS_CLK_INTERNAL_XTAL 0x00000080
+#define SHR_APMG_DL_CFG_DL_CLOCK_POWER_UP 0x00000100
+
+/* Shared APMG_XTAL_CFG register */
+#define SHR_APMG_XTAL_CFG_REG 0x1c0
+#define SHR_APMG_XTAL_CFG_XTAL_ON_REQ 0x80000000
+
+/*
+ * Device reset for family 8000
+ * write to bit 24 in order to reset the CPU
+*/
+#define RELEASE_CPU_RESET (0x300C)
+#define RELEASE_CPU_RESET_BIT BIT(24)
+
/*****************************************************************************
* 7000/3000 series SHR DTS addresses *
*****************************************************************************/
@@ -281,4 +309,43 @@ static inline unsigned int SCD_QUEUE_STATUS_BITS(unsigned int chnl)
#define OSC_CLK (0xa04068)
#define OSC_CLK_FORCE_CONTROL (0x8)
+/* SECURE boot registers */
+#define LMPM_SECURE_BOOT_CONFIG_ADDR (0x100)
+enum secure_boot_config_reg {
+ LMPM_SECURE_BOOT_CONFIG_INSPECTOR_BURNED_IN_OTP = 0x00000001,
+ LMPM_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ = 0x00000002,
+};
+
+#define LMPM_SECURE_BOOT_CPU1_STATUS_ADDR (0x1E30)
+#define LMPM_SECURE_BOOT_CPU2_STATUS_ADDR (0x1E34)
+enum secure_boot_status_reg {
+ LMPM_SECURE_BOOT_CPU_STATUS_VERF_STATUS = 0x00000001,
+ LMPM_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED = 0x00000002,
+ LMPM_SECURE_BOOT_CPU_STATUS_VERF_SUCCESS = 0x00000004,
+ LMPM_SECURE_BOOT_CPU_STATUS_VERF_FAIL = 0x00000008,
+ LMPM_SECURE_BOOT_CPU_STATUS_SIGN_VERF_FAIL = 0x00000010,
+ LMPM_SECURE_BOOT_STATUS_SUCCESS = 0x00000003,
+};
+
+#define CSR_UCODE_LOAD_STATUS_ADDR (0x1E70)
+enum secure_load_status_reg {
+ LMPM_CPU_UCODE_LOADING_STARTED = 0x00000001,
+ LMPM_CPU_HDRS_LOADING_COMPLETED = 0x00000003,
+ LMPM_CPU_UCODE_LOADING_COMPLETED = 0x00000007,
+ LMPM_CPU_STATUS_NUM_OF_LAST_COMPLETED = 0x000000F8,
+ LMPM_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK = 0x0000FF00,
+};
+
+#define LMPM_SECURE_INSPECTOR_CODE_ADDR (0x1E38)
+#define LMPM_SECURE_INSPECTOR_DATA_ADDR (0x1E3C)
+#define LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR (0x1E78)
+#define LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR (0x1E7C)
+
+#define LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE (0x400000)
+#define LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE (0x402000)
+#define LMPM_SECURE_CPU1_HDR_MEM_SPACE (0x420000)
+#define LMPM_SECURE_CPU2_HDR_MEM_SPACE (0x420400)
+
+#define LMPM_SECURE_TIME_OUT (100)
+
#endif /* __iwl_prph_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 1f065cf4a4ba..8cdb0dd618a6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -193,12 +193,23 @@ static inline u32 iwl_rx_packet_payload_len(const struct iwl_rx_packet *pkt)
* @CMD_ASYNC: Return right away and don't wait for the response
* @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the
* response. The caller needs to call iwl_free_resp when done.
+ * @CMD_HIGH_PRIO: The command is high priority - it goes to the front of the
+ * command queue, but after other high priority commands. valid only
+ * with CMD_ASYNC.
+ * @CMD_SEND_IN_IDLE: The command should be sent even when the trans is idle.
+ * @CMD_MAKE_TRANS_IDLE: The command response should mark the trans as idle.
+ * @CMD_WAKE_UP_TRANS: The command response should wake up the trans
+ * (i.e. mark it as non-idle).
*/
enum CMD_MODE {
CMD_SYNC = 0,
CMD_ASYNC = BIT(0),
CMD_WANT_SKB = BIT(1),
CMD_SEND_IN_RFKILL = BIT(2),
+ CMD_HIGH_PRIO = BIT(3),
+ CMD_SEND_IN_IDLE = BIT(4),
+ CMD_MAKE_TRANS_IDLE = BIT(5),
+ CMD_WAKE_UP_TRANS = BIT(6),
};
#define DEF_CMD_PAYLOAD_SIZE 320
@@ -335,6 +346,9 @@ enum iwl_d3_status {
* @STATUS_INT_ENABLED: interrupts are enabled
* @STATUS_RFKILL: the HW RFkill switch is in KILL position
* @STATUS_FW_ERROR: the fw is in error state
+ * @STATUS_TRANS_GOING_IDLE: shutting down the trans, only special commands
+ * are sent
+ * @STATUS_TRANS_IDLE: the trans is idle - general commands are not to be sent
*/
enum iwl_trans_status {
STATUS_SYNC_HCMD_ACTIVE,
@@ -343,6 +357,8 @@ enum iwl_trans_status {
STATUS_INT_ENABLED,
STATUS_RFKILL,
STATUS_FW_ERROR,
+ STATUS_TRANS_GOING_IDLE,
+ STATUS_TRANS_IDLE,
};
/**
@@ -377,7 +393,7 @@ struct iwl_trans_config {
bool rx_buf_size_8k;
bool bc_table_dword;
unsigned int queue_watchdog_timeout;
- const char **command_names;
+ const char *const *command_names;
};
struct iwl_trans;
@@ -443,6 +459,11 @@ struct iwl_trans;
* @release_nic_access: let the NIC go to sleep. The "flags" parameter
* must be the same one that was sent before to the grab_nic_access.
* @set_bits_mask - set SRAM register according to value and mask.
+ * @ref: grab a reference to the transport/FW layers, disallowing
+ * certain low power states
+ * @unref: release a reference previously taken with @ref. Note that
+ * initially the reference count is 1, making an initial @unref
+ * necessary to allow low power states.
*/
struct iwl_trans_ops {
@@ -489,6 +510,8 @@ struct iwl_trans_ops {
unsigned long *flags);
void (*set_bits_mask)(struct iwl_trans *trans, u32 reg, u32 mask,
u32 value);
+ void (*ref)(struct iwl_trans *trans);
+ void (*unref)(struct iwl_trans *trans);
};
/**
@@ -523,6 +546,7 @@ enum iwl_trans_state {
* starting the firmware, used for tracing
* @rx_mpdu_cmd_hdr_size: used for tracing, amount of data before the
* start of the 802.11 header in the @rx_mpdu_cmd
+ * @dflt_pwr_limit: default power limit fetched from the platform (ACPI)
*/
struct iwl_trans {
const struct iwl_trans_ops *ops;
@@ -551,6 +575,8 @@ struct iwl_trans {
struct lockdep_map sync_cmd_lockdep_map;
#endif
+ u64 dflt_pwr_limit;
+
/* pointer to trans specific struct */
/*Ensure that this pointer will always be aligned to sizeof pointer */
char trans_specific[0] __aligned(sizeof(void *));
@@ -627,6 +653,18 @@ static inline int iwl_trans_d3_resume(struct iwl_trans *trans,
return trans->ops->d3_resume(trans, status, test);
}
+static inline void iwl_trans_ref(struct iwl_trans *trans)
+{
+ if (trans->ops->ref)
+ trans->ops->ref(trans);
+}
+
+static inline void iwl_trans_unref(struct iwl_trans *trans)
+{
+ if (trans->ops->unref)
+ trans->ops->unref(trans);
+}
+
static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
struct iwl_host_cmd *cmd)
{
diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile
index f98ec2b23898..ccdd3b7c4cce 100644
--- a/drivers/net/wireless/iwlwifi/mvm/Makefile
+++ b/drivers/net/wireless/iwlwifi/mvm/Makefile
@@ -2,8 +2,8 @@ obj-$(CONFIG_IWLMVM) += iwlmvm.o
iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o
iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o
iwlmvm-y += scan.o time-event.o rs.o
-iwlmvm-y += power.o power_legacy.o bt-coex.o
-iwlmvm-y += led.o tt.o
+iwlmvm-y += power.o coex.o
+iwlmvm-y += led.o tt.o offloading.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o
iwlmvm-$(CONFIG_PM_SLEEP) += d3.o
diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c
index 76cde6ce6551..685f7e8e6943 100644
--- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex.c
@@ -61,9 +61,11 @@
*
*****************************************************************************/
+#include <linux/ieee80211.h>
+#include <linux/etherdevice.h>
#include <net/mac80211.h>
-#include "fw-api-bt-coex.h"
+#include "fw-api-coex.h"
#include "iwl-modparams.h"
#include "mvm.h"
#include "iwl-debug.h"
@@ -305,6 +307,215 @@ static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = {
cpu_to_le32(0x33113311),
};
+struct corunning_block_luts {
+ u8 range;
+ __le32 lut20[BT_COEX_CORUN_LUT_SIZE];
+};
+
+/*
+ * Ranges for the antenna coupling calibration / co-running block LUT:
+ * LUT0: [ 0, 12[
+ * LUT1: [12, 20[
+ * LUT2: [20, 21[
+ * LUT3: [21, 23[
+ * LUT4: [23, 27[
+ * LUT5: [27, 30[
+ * LUT6: [30, 32[
+ * LUT7: [32, 33[
+ * LUT8: [33, - [
+ */
+static const struct corunning_block_luts antenna_coupling_ranges[] = {
+ {
+ .range = 0,
+ .lut20 = {
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ },
+ },
+ {
+ .range = 12,
+ .lut20 = {
+ cpu_to_le32(0x00000001), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ },
+ },
+ {
+ .range = 20,
+ .lut20 = {
+ cpu_to_le32(0x00000002), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ },
+ },
+ {
+ .range = 21,
+ .lut20 = {
+ cpu_to_le32(0x00000003), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ },
+ },
+ {
+ .range = 23,
+ .lut20 = {
+ cpu_to_le32(0x00000004), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ },
+ },
+ {
+ .range = 27,
+ .lut20 = {
+ cpu_to_le32(0x00000005), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ },
+ },
+ {
+ .range = 30,
+ .lut20 = {
+ cpu_to_le32(0x00000006), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ },
+ },
+ {
+ .range = 32,
+ .lut20 = {
+ cpu_to_le32(0x00000007), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ },
+ },
+ {
+ .range = 33,
+ .lut20 = {
+ cpu_to_le32(0x00000008), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
+ },
+ },
+};
+
static enum iwl_bt_coex_lut_type
iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif)
{
@@ -378,7 +589,6 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
flags = iwlwifi_mod_params.bt_coex_active ?
BT_COEX_NW : BT_COEX_DISABLE;
- flags |= BT_CH_PRIMARY_EN | BT_CH_SECONDARY_EN | BT_SYNC_2_BT_DISABLE;
bt_cmd->flags = cpu_to_le32(flags);
bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE |
@@ -391,14 +601,26 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
BT_VALID_LUT |
BT_VALID_WIFI_RX_SW_PRIO_BOOST |
BT_VALID_WIFI_TX_SW_PRIO_BOOST |
- BT_VALID_CORUN_LUT_20 |
- BT_VALID_CORUN_LUT_40 |
BT_VALID_ANT_ISOLATION |
BT_VALID_ANT_ISOLATION_THRS |
BT_VALID_TXTX_DELTA_FREQ_THRS |
BT_VALID_TXRX_MAX_FREQ_0 |
BT_VALID_SYNC_TO_SCO);
+ if (IWL_MVM_BT_COEX_SYNC2SCO)
+ bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO);
+
+ if (IWL_MVM_BT_COEX_CORUNNING) {
+ bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_CORUN_LUT_20 |
+ BT_VALID_CORUN_LUT_40);
+ bt_cmd->flags |= cpu_to_le32(BT_COEX_CORUNNING);
+ }
+
+ if (IWL_MVM_BT_COEX_MPLUT) {
+ bt_cmd->flags |= cpu_to_le32(BT_COEX_MPLUT);
+ bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_MULTI_PRIO_LUT);
+ }
+
if (mvm->cfg->bt_shared_single_ant)
memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant,
sizeof(iwl_single_shared_ant));
@@ -406,6 +628,12 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
memcpy(&bt_cmd->decision_lut, iwl_combined_lookup,
sizeof(iwl_combined_lookup));
+ /* Take first Co-running block LUT to get started */
+ memcpy(bt_cmd->bt4_corun_lut20, antenna_coupling_ranges[0].lut20,
+ sizeof(bt_cmd->bt4_corun_lut20));
+ memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[0].lut20,
+ sizeof(bt_cmd->bt4_corun_lut40));
+
memcpy(&bt_cmd->bt_prio_boost, iwl_bt_prio_boost,
sizeof(iwl_bt_prio_boost));
memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut,
@@ -489,36 +717,26 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm,
return ret;
}
-static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
- bool enable)
+int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable)
{
struct iwl_bt_coex_cmd *bt_cmd;
/* Send ASYNC since this can be sent from an atomic context */
struct iwl_host_cmd cmd = {
.id = BT_CONFIG,
.len = { sizeof(*bt_cmd), },
- .dataflags = { IWL_HCMD_DFL_DUP, },
+ .dataflags = { IWL_HCMD_DFL_NOCOPY, },
.flags = CMD_ASYNC,
};
-
- struct ieee80211_sta *sta;
struct iwl_mvm_sta *mvmsta;
int ret;
- if (sta_id == IWL_MVM_STATION_COUNT)
- return 0;
-
- sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
- lockdep_is_held(&mvm->mutex));
-
- /* This can happen if the station has been removed right now */
- if (IS_ERR_OR_NULL(sta))
+ mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id);
+ if (!mvmsta)
return 0;
- mvmsta = iwl_mvm_sta_from_mac80211(sta);
-
/* nothing to do */
- if (mvmsta->bt_reduced_txpower == enable)
+ if (mvmsta->bt_reduced_txpower_dbg ||
+ mvmsta->bt_reduced_txpower == enable)
return 0;
bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_ATOMIC);
@@ -552,6 +770,7 @@ struct iwl_bt_iterator_data {
bool reduced_tx_power;
struct ieee80211_chanctx_conf *primary;
struct ieee80211_chanctx_conf *secondary;
+ bool primary_ll;
};
static inline
@@ -577,72 +796,113 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
struct iwl_mvm *mvm = data->mvm;
struct ieee80211_chanctx_conf *chanctx_conf;
enum ieee80211_smps_mode smps_mode;
+ u32 bt_activity_grading;
int ave_rssi;
lockdep_assert_held(&mvm->mutex);
- if (vif->type != NL80211_IFTYPE_STATION &&
- vif->type != NL80211_IFTYPE_AP)
- return;
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ /* default smps_mode for BSS / P2P client is AUTOMATIC */
+ smps_mode = IEEE80211_SMPS_AUTOMATIC;
+ data->num_bss_ifaces++;
- smps_mode = IEEE80211_SMPS_AUTOMATIC;
+ /*
+ * Count unassoc BSSes, relax SMSP constraints
+ * and disable reduced Tx Power
+ */
+ if (!vif->bss_conf.assoc) {
+ iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
+ smps_mode);
+ if (iwl_mvm_bt_coex_reduced_txp(mvm,
+ mvmvif->ap_sta_id,
+ false))
+ IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
+ return;
+ }
+ break;
+ case NL80211_IFTYPE_AP:
+ /* default smps_mode for AP / GO is OFF */
+ smps_mode = IEEE80211_SMPS_OFF;
+ if (!mvmvif->ap_ibss_active) {
+ iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
+ smps_mode);
+ return;
+ }
+
+ /* the Ack / Cts kill mask must be default if AP / GO */
+ data->reduced_tx_power = false;
+ break;
+ default:
+ return;
+ }
chanctx_conf = rcu_dereference(vif->chanctx_conf);
/* If channel context is invalid or not on 2.4GHz .. */
if ((!chanctx_conf ||
chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) {
- /* ... and it is an associated STATION, relax constraints */
- if (vif->type == NL80211_IFTYPE_STATION && vif->bss_conf.assoc)
- iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
- smps_mode);
- iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
+ /* ... relax constraints and disable rssi events */
+ iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
+ smps_mode);
+ if (vif->type == NL80211_IFTYPE_STATION)
+ iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
return;
}
- /* SoftAP / GO will always be primary */
- if (vif->type == NL80211_IFTYPE_AP) {
- if (!mvmvif->ap_ibss_active)
- return;
+ bt_activity_grading = le32_to_cpu(data->notif->bt_activity_grading);
+ if (bt_activity_grading >= BT_HIGH_TRAFFIC)
+ smps_mode = IEEE80211_SMPS_STATIC;
+ else if (bt_activity_grading >= BT_LOW_TRAFFIC)
+ smps_mode = vif->type == NL80211_IFTYPE_AP ?
+ IEEE80211_SMPS_OFF :
+ IEEE80211_SMPS_DYNAMIC;
+ IWL_DEBUG_COEX(data->mvm,
+ "mac %d: bt_status %d bt_activity_grading %d smps_req %d\n",
+ mvmvif->id, data->notif->bt_status, bt_activity_grading,
+ smps_mode);
- /* the Ack / Cts kill mask must be default if AP / GO */
- data->reduced_tx_power = false;
+ iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode);
- if (chanctx_conf == data->primary)
- return;
+ /* low latency is always primary */
+ if (iwl_mvm_vif_low_latency(mvmvif)) {
+ data->primary_ll = true;
- /* downgrade the current primary no matter what its type is */
data->secondary = data->primary;
data->primary = chanctx_conf;
- return;
}
- data->num_bss_ifaces++;
+ if (vif->type == NL80211_IFTYPE_AP) {
+ if (!mvmvif->ap_ibss_active)
+ return;
- /* we are now a STA / P2P Client, and take associated ones only */
- if (!vif->bss_conf.assoc)
+ if (chanctx_conf == data->primary)
+ return;
+
+ if (!data->primary_ll) {
+ /*
+ * downgrade the current primary no matter what its
+ * type is.
+ */
+ data->secondary = data->primary;
+ data->primary = chanctx_conf;
+ } else {
+ /* there is low latency vif - we will be secondary */
+ data->secondary = chanctx_conf;
+ }
return;
+ }
- /* STA / P2P Client, try to be primary if first vif */
+ /*
+ * STA / P2P Client, try to be primary if first vif. If we are in low
+ * latency mode, we are already in primary and just don't do much
+ */
if (!data->primary || data->primary == chanctx_conf)
data->primary = chanctx_conf;
else if (!data->secondary)
/* if secondary is not NULL, it might be a GO */
data->secondary = chanctx_conf;
- if (le32_to_cpu(data->notif->bt_activity_grading) >= BT_HIGH_TRAFFIC)
- smps_mode = IEEE80211_SMPS_STATIC;
- else if (le32_to_cpu(data->notif->bt_activity_grading) >=
- BT_LOW_TRAFFIC)
- smps_mode = IEEE80211_SMPS_DYNAMIC;
-
- IWL_DEBUG_COEX(data->mvm,
- "mac %d: bt_status %d bt_activity_grading %d smps_req %d\n",
- mvmvif->id, data->notif->bt_status,
- data->notif->bt_activity_grading, smps_mode);
-
- iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode);
-
/* don't reduce the Tx power if in loose scheme */
if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT ||
mvm->cfg->bt_shared_single_ant) {
@@ -872,8 +1132,11 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
lockdep_assert_held(&mvm->mutex);
- /* Rssi update while not associated ?! */
- if (WARN_ON_ONCE(mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT))
+ /*
+ * Rssi update while not associated - can happen since the statistics
+ * are handled asynchronously
+ */
+ if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
return;
/* No BT - reports should be disabled */
@@ -915,8 +1178,8 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000)
#define LINK_QUAL_AGG_TIME_LIMIT_BT_ACT (1200)
-u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm,
- struct ieee80211_sta *sta)
+u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta)
{
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
enum iwl_bt_coex_lut_type lut_type;
@@ -952,6 +1215,38 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
return iwl_get_coex_type(mvm, mvmsta->vif) == BT_COEX_TIGHT_LUT;
}
+u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
+ struct ieee80211_tx_info *info, u8 ac)
+{
+ __le16 fc = hdr->frame_control;
+
+ if (info->band != IEEE80211_BAND_2GHZ)
+ return 0;
+
+ if (unlikely(mvm->bt_tx_prio))
+ return mvm->bt_tx_prio - 1;
+
+ /* High prio packet (wrt. BT coex) if it is EAPOL, MCAST or MGMT */
+ if (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO ||
+ is_multicast_ether_addr(hdr->addr1) ||
+ ieee80211_is_ctl(fc) || ieee80211_is_mgmt(fc) ||
+ ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc))
+ return 3;
+
+ switch (ac) {
+ case IEEE80211_AC_BE:
+ return 1;
+ case IEEE80211_AC_VO:
+ return 3;
+ case IEEE80211_AC_VI:
+ return 2;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm)
{
if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX))
@@ -959,3 +1254,69 @@ void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm)
iwl_mvm_bt_coex_notif_handle(mvm);
}
+
+int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *dev_cmd)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ u32 ant_isolation = le32_to_cpup((void *)pkt->data);
+ u8 __maybe_unused lower_bound, upper_bound;
+ u8 lut;
+
+ struct iwl_bt_coex_cmd *bt_cmd;
+ struct iwl_host_cmd cmd = {
+ .id = BT_CONFIG,
+ .len = { sizeof(*bt_cmd), },
+ .dataflags = { IWL_HCMD_DFL_NOCOPY, },
+ .flags = CMD_SYNC,
+ };
+
+ if (!IWL_MVM_BT_COEX_CORUNNING)
+ return 0;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (ant_isolation == mvm->last_ant_isol)
+ return 0;
+
+ for (lut = 0; lut < ARRAY_SIZE(antenna_coupling_ranges) - 1; lut++)
+ if (ant_isolation < antenna_coupling_ranges[lut + 1].range)
+ break;
+
+ lower_bound = antenna_coupling_ranges[lut].range;
+
+ if (lut < ARRAY_SIZE(antenna_coupling_ranges) - 1)
+ upper_bound = antenna_coupling_ranges[lut + 1].range;
+ else
+ upper_bound = antenna_coupling_ranges[lut].range;
+
+ IWL_DEBUG_COEX(mvm, "Antenna isolation=%d in range [%d,%d[, lut=%d\n",
+ ant_isolation, lower_bound, upper_bound, lut);
+
+ mvm->last_ant_isol = ant_isolation;
+
+ if (mvm->last_corun_lut == lut)
+ return 0;
+
+ mvm->last_corun_lut = lut;
+
+ bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL);
+ if (!bt_cmd)
+ return 0;
+ cmd.data[0] = bt_cmd;
+
+ bt_cmd->flags = cpu_to_le32(BT_COEX_NW);
+ bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE |
+ BT_VALID_CORUN_LUT_20 |
+ BT_VALID_CORUN_LUT_40);
+
+ /* For the moment, use the same LUT for 20GHz and 40GHz */
+ memcpy(bt_cmd->bt4_corun_lut20, antenna_coupling_ranges[lut].lut20,
+ sizeof(bt_cmd->bt4_corun_lut20));
+
+ memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[lut].lut20,
+ sizeof(bt_cmd->bt4_corun_lut40));
+
+ return 0;
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h
index 036857698565..51685693af2e 100644
--- a/drivers/net/wireless/iwlwifi/mvm/constants.h
+++ b/drivers/net/wireless/iwlwifi/mvm/constants.h
@@ -78,5 +78,9 @@
#define IWL_MVM_PS_SNOOZE_INTERVAL 25
#define IWL_MVM_PS_SNOOZE_WINDOW 50
#define IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW 25
+#define IWL_MVM_LOWLAT_QUOTA_MIN_PERCENT 64
+#define IWL_MVM_BT_COEX_SYNC2SCO 1
+#define IWL_MVM_BT_COEX_CORUNNING 1
+#define IWL_MVM_BT_COEX_MPLUT 1
#endif /* __MVM_CONSTANTS_H */
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
index f36a7ee0267f..e56f5a0edf85 100644
--- a/drivers/net/wireless/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -376,139 +376,6 @@ static int iwl_mvm_send_patterns(struct iwl_mvm *mvm,
return err;
}
-static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
-{
- union {
- struct iwl_proto_offload_cmd_v1 v1;
- struct iwl_proto_offload_cmd_v2 v2;
- struct iwl_proto_offload_cmd_v3_small v3s;
- struct iwl_proto_offload_cmd_v3_large v3l;
- } cmd = {};
- struct iwl_host_cmd hcmd = {
- .id = PROT_OFFLOAD_CONFIG_CMD,
- .flags = CMD_SYNC,
- .data[0] = &cmd,
- .dataflags[0] = IWL_HCMD_DFL_DUP,
- };
- struct iwl_proto_offload_cmd_common *common;
- u32 enabled = 0, size;
- u32 capa_flags = mvm->fw->ucode_capa.flags;
-#if IS_ENABLED(CONFIG_IPV6)
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- int i;
-
- if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL ||
- capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) {
- struct iwl_ns_config *nsc;
- struct iwl_targ_addr *addrs;
- int n_nsc, n_addrs;
- int c;
-
- if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) {
- nsc = cmd.v3s.ns_config;
- n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S;
- addrs = cmd.v3s.targ_addrs;
- n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S;
- } else {
- nsc = cmd.v3l.ns_config;
- n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L;
- addrs = cmd.v3l.targ_addrs;
- n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L;
- }
-
- if (mvmvif->num_target_ipv6_addrs)
- enabled |= IWL_D3_PROTO_OFFLOAD_NS;
-
- /*
- * For each address we have (and that will fit) fill a target
- * address struct and combine for NS offload structs with the
- * solicited node addresses.
- */
- for (i = 0, c = 0;
- i < mvmvif->num_target_ipv6_addrs &&
- i < n_addrs && c < n_nsc; i++) {
- struct in6_addr solicited_addr;
- int j;
-
- addrconf_addr_solict_mult(&mvmvif->target_ipv6_addrs[i],
- &solicited_addr);
- for (j = 0; j < c; j++)
- if (ipv6_addr_cmp(&nsc[j].dest_ipv6_addr,
- &solicited_addr) == 0)
- break;
- if (j == c)
- c++;
- addrs[i].addr = mvmvif->target_ipv6_addrs[i];
- addrs[i].config_num = cpu_to_le32(j);
- nsc[j].dest_ipv6_addr = solicited_addr;
- memcpy(nsc[j].target_mac_addr, vif->addr, ETH_ALEN);
- }
-
- if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL)
- cmd.v3s.num_valid_ipv6_addrs = cpu_to_le32(i);
- else
- cmd.v3l.num_valid_ipv6_addrs = cpu_to_le32(i);
- } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
- if (mvmvif->num_target_ipv6_addrs) {
- enabled |= IWL_D3_PROTO_OFFLOAD_NS;
- memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN);
- }
-
- BUILD_BUG_ON(sizeof(cmd.v2.target_ipv6_addr[0]) !=
- sizeof(mvmvif->target_ipv6_addrs[0]));
-
- for (i = 0; i < min(mvmvif->num_target_ipv6_addrs,
- IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2); i++)
- memcpy(cmd.v2.target_ipv6_addr[i],
- &mvmvif->target_ipv6_addrs[i],
- sizeof(cmd.v2.target_ipv6_addr[i]));
- } else {
- if (mvmvif->num_target_ipv6_addrs) {
- enabled |= IWL_D3_PROTO_OFFLOAD_NS;
- memcpy(cmd.v1.ndp_mac_addr, vif->addr, ETH_ALEN);
- }
-
- BUILD_BUG_ON(sizeof(cmd.v1.target_ipv6_addr[0]) !=
- sizeof(mvmvif->target_ipv6_addrs[0]));
-
- for (i = 0; i < min(mvmvif->num_target_ipv6_addrs,
- IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1); i++)
- memcpy(cmd.v1.target_ipv6_addr[i],
- &mvmvif->target_ipv6_addrs[i],
- sizeof(cmd.v1.target_ipv6_addr[i]));
- }
-#endif
-
- if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) {
- common = &cmd.v3s.common;
- size = sizeof(cmd.v3s);
- } else if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) {
- common = &cmd.v3l.common;
- size = sizeof(cmd.v3l);
- } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
- common = &cmd.v2.common;
- size = sizeof(cmd.v2);
- } else {
- common = &cmd.v1.common;
- size = sizeof(cmd.v1);
- }
-
- if (vif->bss_conf.arp_addr_cnt) {
- enabled |= IWL_D3_PROTO_OFFLOAD_ARP;
- common->host_ipv4_addr = vif->bss_conf.arp_addr_list[0];
- memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN);
- }
-
- if (!enabled)
- return 0;
-
- common->enabled = cpu_to_le32(enabled);
-
- hcmd.len[0] = size;
- return iwl_mvm_send_cmd(mvm, &hcmd);
-}
-
enum iwl_mvm_tcp_packet_type {
MVM_TCP_TX_SYN,
MVM_TCP_RX_SYNACK,
@@ -846,8 +713,8 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
quota_cmd.quotas[0].id_and_color =
cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id,
mvmvif->phy_ctxt->color));
- quota_cmd.quotas[0].quota = cpu_to_le32(100);
- quota_cmd.quotas[0].max_duration = cpu_to_le32(1000);
+ quota_cmd.quotas[0].quota = cpu_to_le32(IWL_MVM_MAX_QUOTA);
+ quota_cmd.quotas[0].max_duration = cpu_to_le32(IWL_MVM_MAX_QUOTA);
for (i = 1; i < MAX_BINDINGS; i++)
quota_cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID);
@@ -927,6 +794,20 @@ void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
IWL_ERR(mvm, "failed to set non-QoS seqno\n");
}
+static int
+iwl_mvm_send_wowlan_config_cmd(struct iwl_mvm *mvm,
+ const struct iwl_wowlan_config_cmd_v3 *cmd)
+{
+ /* start only with the v2 part of the command */
+ u16 cmd_len = sizeof(cmd->common);
+
+ if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID)
+ cmd_len = sizeof(*cmd);
+
+ return iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, CMD_SYNC,
+ cmd_len, cmd);
+}
+
static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
struct cfg80211_wowlan *wowlan,
bool test)
@@ -939,7 +820,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
struct iwl_mvm_vif *mvmvif;
struct ieee80211_sta *ap_sta;
struct iwl_mvm_sta *mvm_ap_sta;
- struct iwl_wowlan_config_cmd wowlan_config_cmd = {};
+ struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {};
struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
struct iwl_d3_manager_config d3_cfg_cmd_data = {
@@ -961,9 +842,8 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
.tkip = &tkip_cmd,
.use_tkip = false,
};
- int ret, i;
+ int ret;
int len __maybe_unused;
- u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT;
if (!wowlan) {
/*
@@ -980,8 +860,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
mutex_lock(&mvm->mutex);
- old_aux_sta_id = mvm->aux_sta.sta_id;
-
/* see if there's only a single BSS vif and it's associated */
ieee80211_iterate_active_interfaces_atomic(
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
@@ -1005,49 +883,41 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
- /* TODO: wowlan_config_cmd.wowlan_ba_teardown_tids */
+ /* TODO: wowlan_config_cmd.common.wowlan_ba_teardown_tids */
- wowlan_config_cmd.is_11n_connection = ap_sta->ht_cap.ht_supported;
+ wowlan_config_cmd.common.is_11n_connection =
+ ap_sta->ht_cap.ht_supported;
/* Query the last used seqno and set it */
ret = iwl_mvm_get_last_nonqos_seq(mvm, vif);
if (ret < 0)
goto out_noreset;
- wowlan_config_cmd.non_qos_seq = cpu_to_le16(ret);
+ wowlan_config_cmd.common.non_qos_seq = cpu_to_le16(ret);
- /*
- * For QoS counters, we store the one to use next, so subtract 0x10
- * since the uCode will add 0x10 *before* using the value while we
- * increment after using the value (i.e. store the next value to use).
- */
- for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
- u16 seq = mvm_ap_sta->tid_data[i].seq_number;
- seq -= 0x10;
- wowlan_config_cmd.qos_seq[i] = cpu_to_le16(seq);
- }
+ iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &wowlan_config_cmd.common);
if (wowlan->disconnect)
- wowlan_config_cmd.wakeup_filter |=
+ wowlan_config_cmd.common.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS |
IWL_WOWLAN_WAKEUP_LINK_CHANGE);
if (wowlan->magic_pkt)
- wowlan_config_cmd.wakeup_filter |=
+ wowlan_config_cmd.common.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET);
if (wowlan->gtk_rekey_failure)
- wowlan_config_cmd.wakeup_filter |=
+ wowlan_config_cmd.common.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
if (wowlan->eap_identity_req)
- wowlan_config_cmd.wakeup_filter |=
+ wowlan_config_cmd.common.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ);
if (wowlan->four_way_handshake)
- wowlan_config_cmd.wakeup_filter |=
+ wowlan_config_cmd.common.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
if (wowlan->n_patterns)
- wowlan_config_cmd.wakeup_filter |=
+ wowlan_config_cmd.common.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH);
if (wowlan->rfkill_release)
- wowlan_config_cmd.wakeup_filter |=
+ wowlan_config_cmd.common.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT);
if (wowlan->tcp) {
@@ -1055,7 +925,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
* Set the "link change" (really "link lost") flag as well
* since that implies losing the TCP connection.
*/
- wowlan_config_cmd.wakeup_filter |=
+ wowlan_config_cmd.common.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS |
IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE |
IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET |
@@ -1067,16 +937,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
iwl_trans_stop_device(mvm->trans);
/*
- * The D3 firmware still hardcodes the AP station ID for the
- * BSS we're associated with as 0. Store the real STA ID here
- * and assign 0. When we leave this function, we'll restore
- * the original value for the resume code.
- */
- old_ap_sta_id = mvm_ap_sta->sta_id;
- mvm_ap_sta->sta_id = 0;
- mvmvif->ap_sta_id = 0;
-
- /*
* Set the HW restart bit -- this is mostly true as we're
* going to load new firmware and reprogram that, though
* the reprogramming is going to be manual to avoid adding
@@ -1096,16 +956,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
mvm->ptk_ivlen = 0;
mvm->ptk_icvlen = 0;
- /*
- * The D3 firmware still hardcodes the AP station ID for the
- * BSS we're associated with as 0. As a result, we have to move
- * the auxiliary station to ID 1 so the ID 0 remains free for
- * the AP station for later.
- * We set the sta_id to 1 here, and reset it to its previous
- * value (that we stored above) later.
- */
- mvm->aux_sta.sta_id = 1;
-
ret = iwl_mvm_load_d3_fw(mvm);
if (ret)
goto out;
@@ -1173,9 +1023,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
}
}
- ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION,
- CMD_SYNC, sizeof(wowlan_config_cmd),
- &wowlan_config_cmd);
+ ret = iwl_mvm_send_wowlan_config_cmd(mvm, &wowlan_config_cmd);
if (ret)
goto out;
@@ -1183,7 +1031,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
if (ret)
goto out;
- ret = iwl_mvm_send_proto_offload(mvm, vif);
+ ret = iwl_mvm_send_proto_offload(mvm, vif, false, CMD_SYNC);
if (ret)
goto out;
@@ -1191,11 +1039,11 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
if (ret)
goto out;
- ret = iwl_mvm_power_update_device_mode(mvm);
+ ret = iwl_mvm_power_update_device(mvm);
if (ret)
goto out;
- ret = iwl_mvm_power_update_mode(mvm, vif);
+ ret = iwl_mvm_power_update_mac(mvm, vif);
if (ret)
goto out;
@@ -1222,10 +1070,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
iwl_trans_d3_suspend(mvm->trans, test);
out:
- mvm->aux_sta.sta_id = old_aux_sta_id;
- mvm_ap_sta->sta_id = old_ap_sta_id;
- mvmvif->ap_sta_id = old_ap_sta_id;
-
if (ret < 0)
ieee80211_restart_hw(mvm->hw);
out_noreset:
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
index 0e29cd83a06a..9b59e1d7ae71 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
@@ -185,7 +185,7 @@ static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf,
mutex_lock(&mvm->mutex);
iwl_dbgfs_update_pm(mvm, vif, param, val);
- ret = iwl_mvm_power_update_mode(mvm, vif);
+ ret = iwl_mvm_power_update_mac(mvm, vif);
mutex_unlock(&mvm->mutex);
return ret ?: count;
@@ -202,7 +202,7 @@ static ssize_t iwl_dbgfs_pm_params_read(struct file *file,
int bufsz = sizeof(buf);
int pos;
- pos = iwl_mvm_power_dbgfs_read(mvm, vif, buf, bufsz);
+ pos = iwl_mvm_power_mac_dbgfs_read(mvm, vif, buf, bufsz);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
@@ -225,6 +225,29 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
ap_sta_id = mvmvif->ap_sta_id;
+ switch (ieee80211_vif_type_p2p(vif)) {
+ case NL80211_IFTYPE_ADHOC:
+ pos += scnprintf(buf+pos, bufsz-pos, "type: ibss\n");
+ break;
+ case NL80211_IFTYPE_STATION:
+ pos += scnprintf(buf+pos, bufsz-pos, "type: bss\n");
+ break;
+ case NL80211_IFTYPE_AP:
+ pos += scnprintf(buf+pos, bufsz-pos, "type: ap\n");
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ pos += scnprintf(buf+pos, bufsz-pos, "type: p2p client\n");
+ break;
+ case NL80211_IFTYPE_P2P_GO:
+ pos += scnprintf(buf+pos, bufsz-pos, "type: p2p go\n");
+ break;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ pos += scnprintf(buf+pos, bufsz-pos, "type: p2p dev\n");
+ break;
+ default:
+ break;
+ }
+
pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n",
mvmvif->id, mvmvif->color);
pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n",
@@ -249,9 +272,10 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
pos += scnprintf(buf+pos, bufsz-pos,
- "ap_sta_id %d - reduced Tx power %d\n",
+ "ap_sta_id %d - reduced Tx power %d force %d\n",
ap_sta_id,
- mvm_sta->bt_reduced_txpower);
+ mvm_sta->bt_reduced_txpower,
+ mvm_sta->bt_reduced_txpower_dbg);
}
}
@@ -269,6 +293,41 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
+static ssize_t iwl_dbgfs_reduced_txp_write(struct ieee80211_vif *vif,
+ char *buf, size_t count,
+ loff_t *ppos)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm *mvm = mvmvif->mvm;
+ struct iwl_mvm_sta *mvmsta;
+ bool reduced_tx_power;
+ int ret;
+
+ if (mvmvif->ap_sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id))
+ return -ENOTCONN;
+
+ if (strtobool(buf, &reduced_tx_power) != 0)
+ return -EINVAL;
+
+ mutex_lock(&mvm->mutex);
+
+ mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id);
+ if (IS_ERR_OR_NULL(mvmsta)) {
+ mutex_unlock(&mvm->mutex);
+ return -ENOTCONN;
+ }
+
+ mvmsta->bt_reduced_txpower_dbg = false;
+ ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
+ reduced_tx_power);
+ if (!ret)
+ mvmsta->bt_reduced_txpower_dbg = true;
+
+ mutex_unlock(&mvm->mutex);
+
+ return ret ? : count;
+}
+
static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif,
enum iwl_dbgfs_bf_mask param, int value)
{
@@ -403,9 +462,9 @@ static ssize_t iwl_dbgfs_bf_params_write(struct ieee80211_vif *vif, char *buf,
mutex_lock(&mvm->mutex);
iwl_dbgfs_update_bf(vif, param, value);
if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value)
- ret = iwl_mvm_disable_beacon_filter(mvm, vif);
+ ret = iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC);
else
- ret = iwl_mvm_enable_beacon_filter(mvm, vif);
+ ret = iwl_mvm_enable_beacon_filter(mvm, vif, CMD_SYNC);
mutex_unlock(&mvm->mutex);
return ret ?: count;
@@ -460,6 +519,41 @@ static ssize_t iwl_dbgfs_bf_params_read(struct file *file,
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
+static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm *mvm = mvmvif->mvm;
+ u8 value;
+ int ret;
+
+ ret = kstrtou8(buf, 0, &value);
+ if (ret)
+ return ret;
+ if (value > 1)
+ return -EINVAL;
+
+ mutex_lock(&mvm->mutex);
+ iwl_mvm_update_low_latency(mvm, vif, value);
+ mutex_unlock(&mvm->mutex);
+
+ return count;
+}
+
+static ssize_t iwl_dbgfs_low_latency_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_vif *vif = file->private_data;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ char buf[3];
+
+ buf[0] = mvmvif->low_latency ? '1' : '0';
+ buf[1] = '\n';
+ buf[2] = '\0';
+ return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf));
+}
+
#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
_MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
@@ -473,6 +567,8 @@ static ssize_t iwl_dbgfs_bf_params_read(struct file *file,
MVM_DEBUGFS_READ_FILE_OPS(mac_params);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10);
+MVM_DEBUGFS_WRITE_FILE_OPS(reduced_txp, 10);
void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
@@ -496,15 +592,18 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
return;
}
- if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
+ if ((mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT) &&
+ iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
(vif->type == NL80211_IFTYPE_STATION && vif->p2p &&
- mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS)))
+ mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)))
MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR |
S_IRUSR);
- MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir,
- S_IRUSR);
+ MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, S_IRUSR);
+ MVM_DEBUGFS_ADD_FILE_VIF(reduced_txp, mvmvif->dbgfs_dir, S_IWUSR);
+ MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir,
+ S_IRUSR | S_IWUSR);
if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
mvmvif == mvm->bf_allowed_vif)
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
index 369d4c90e669..1b52deea6081 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
@@ -60,11 +60,14 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
+#include <linux/vmalloc.h>
+
#include "mvm.h"
#include "sta.h"
#include "iwl-io.h"
#include "iwl-prph.h"
#include "debugfs.h"
+#include "fw-error-dump.h"
static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf,
size_t count, loff_t *ppos)
@@ -90,7 +93,7 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf,
static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf,
size_t count, loff_t *ppos)
{
- struct ieee80211_sta *sta;
+ struct iwl_mvm_sta *mvmsta;
int sta_id, drain, ret;
if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
@@ -105,19 +108,63 @@ static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf,
mutex_lock(&mvm->mutex);
- sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
- lockdep_is_held(&mvm->mutex));
- if (IS_ERR_OR_NULL(sta))
+ mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id);
+
+ if (!mvmsta)
ret = -ENOENT;
else
- ret = iwl_mvm_drain_sta(mvm, (void *)sta->drv_priv, drain) ? :
- count;
+ ret = iwl_mvm_drain_sta(mvm, mvmsta, drain) ? : count;
mutex_unlock(&mvm->mutex);
return ret;
}
+static int iwl_dbgfs_fw_error_dump_open(struct inode *inode, struct file *file)
+{
+ struct iwl_mvm *mvm = inode->i_private;
+ int ret;
+
+ if (!mvm)
+ return -EINVAL;
+
+ mutex_lock(&mvm->mutex);
+ if (!mvm->fw_error_dump) {
+ ret = -ENODATA;
+ goto out;
+ }
+
+ file->private_data = mvm->fw_error_dump;
+ mvm->fw_error_dump = NULL;
+ kfree(mvm->fw_error_sram);
+ mvm->fw_error_sram = NULL;
+ mvm->fw_error_sram_len = 0;
+ ret = 0;
+
+out:
+ mutex_unlock(&mvm->mutex);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_fw_error_dump_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_fw_error_dump_file *dump_file = file->private_data;
+
+ return simple_read_from_buffer(user_buf, count, ppos,
+ dump_file,
+ le32_to_cpu(dump_file->file_len));
+}
+
+static int iwl_dbgfs_fw_error_dump_release(struct inode *inode,
+ struct file *file)
+{
+ vfree(file->private_data);
+
+ return 0;
+}
+
static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -251,7 +298,7 @@ static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf,
}
mutex_lock(&mvm->mutex);
- ret = iwl_mvm_power_update_device_mode(mvm);
+ ret = iwl_mvm_power_update_device(mvm);
mutex_unlock(&mvm->mutex);
return ret ?: count;
@@ -351,6 +398,9 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
le32_to_cpu(notif->secondary_ch_lut));
pos += scnprintf(buf+pos, bufsz-pos, "bt_activity_grading = %d\n",
le32_to_cpu(notif->bt_activity_grading));
+ pos += scnprintf(buf+pos, bufsz-pos,
+ "antenna isolation = %d CORUN LUT index = %d\n",
+ mvm->last_ant_isol, mvm->last_corun_lut);
mutex_unlock(&mvm->mutex);
@@ -393,6 +443,22 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf,
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
+static ssize_t
+iwl_dbgfs_bt_tx_prio_write(struct iwl_mvm *mvm, char *buf,
+ size_t count, loff_t *ppos)
+{
+ u32 bt_tx_prio;
+
+ if (sscanf(buf, "%u", &bt_tx_prio) != 1)
+ return -EINVAL;
+ if (bt_tx_prio > 4)
+ return -EINVAL;
+
+ mvm->bt_tx_prio = bt_tx_prio;
+
+ return count;
+}
+
#define PRINT_STATS_LE32(_str, _val) \
pos += scnprintf(buf + pos, bufsz - pos, \
fmt_table, _str, \
@@ -532,6 +598,80 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file,
}
#undef PRINT_STAT_LE32
+static ssize_t iwl_dbgfs_frame_stats_read(struct iwl_mvm *mvm,
+ char __user *user_buf, size_t count,
+ loff_t *ppos,
+ struct iwl_mvm_frame_stats *stats)
+{
+ char *buff, *pos, *endpos;
+ int idx, i;
+ int ret;
+ static const size_t bufsz = 1024;
+
+ buff = kmalloc(bufsz, GFP_KERNEL);
+ if (!buff)
+ return -ENOMEM;
+
+ spin_lock_bh(&mvm->drv_stats_lock);
+
+ pos = buff;
+ endpos = pos + bufsz;
+
+ pos += scnprintf(pos, endpos - pos,
+ "Legacy/HT/VHT\t:\t%d/%d/%d\n",
+ stats->legacy_frames,
+ stats->ht_frames,
+ stats->vht_frames);
+ pos += scnprintf(pos, endpos - pos, "20/40/80\t:\t%d/%d/%d\n",
+ stats->bw_20_frames,
+ stats->bw_40_frames,
+ stats->bw_80_frames);
+ pos += scnprintf(pos, endpos - pos, "NGI/SGI\t\t:\t%d/%d\n",
+ stats->ngi_frames,
+ stats->sgi_frames);
+ pos += scnprintf(pos, endpos - pos, "SISO/MIMO2\t:\t%d/%d\n",
+ stats->siso_frames,
+ stats->mimo2_frames);
+ pos += scnprintf(pos, endpos - pos, "FAIL/SCSS\t:\t%d/%d\n",
+ stats->fail_frames,
+ stats->success_frames);
+ pos += scnprintf(pos, endpos - pos, "MPDUs agg\t:\t%d\n",
+ stats->agg_frames);
+ pos += scnprintf(pos, endpos - pos, "A-MPDUs\t\t:\t%d\n",
+ stats->ampdu_count);
+ pos += scnprintf(pos, endpos - pos, "Avg MPDUs/A-MPDU:\t%d\n",
+ stats->ampdu_count > 0 ?
+ (stats->agg_frames / stats->ampdu_count) : 0);
+
+ pos += scnprintf(pos, endpos - pos, "Last Rates\n");
+
+ idx = stats->last_frame_idx - 1;
+ for (i = 0; i < ARRAY_SIZE(stats->last_rates); i++) {
+ idx = (idx + 1) % ARRAY_SIZE(stats->last_rates);
+ if (stats->last_rates[idx] == 0)
+ continue;
+ pos += scnprintf(pos, endpos - pos, "Rate[%d]: ",
+ (int)(ARRAY_SIZE(stats->last_rates) - i));
+ pos += rs_pretty_print_rate(pos, stats->last_rates[idx]);
+ }
+ spin_unlock_bh(&mvm->drv_stats_lock);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos - buff);
+ kfree(buff);
+
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_drv_rx_stats_read(struct file *file,
+ char __user *user_buf, size_t count,
+ loff_t *ppos)
+{
+ struct iwl_mvm *mvm = file->private_data;
+
+ return iwl_dbgfs_frame_stats_read(mvm, user_buf, count, ppos,
+ &mvm->drv_rx_stats);
+}
+
static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf,
size_t count, loff_t *ppos)
{
@@ -592,7 +732,7 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
return -EINVAL;
if (scan_rx_ant > ANT_ABC)
return -EINVAL;
- if (scan_rx_ant & ~iwl_fw_valid_rx_ant(mvm->fw))
+ if (scan_rx_ant & ~mvm->fw->valid_rx_ant)
return -EINVAL;
mvm->scan_rx_ant = scan_rx_ant;
@@ -600,6 +740,187 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
return count;
}
+#define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__)
+#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
+static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm *mvm = file->private_data;
+ struct iwl_bcast_filter_cmd cmd;
+ const struct iwl_fw_bcast_filter *filter;
+ char *buf;
+ int bufsz = 1024;
+ int i, j, pos = 0;
+ ssize_t ret;
+
+ buf = kzalloc(bufsz, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ mutex_lock(&mvm->mutex);
+ if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) {
+ ADD_TEXT("None\n");
+ mutex_unlock(&mvm->mutex);
+ goto out;
+ }
+ mutex_unlock(&mvm->mutex);
+
+ for (i = 0; cmd.filters[i].attrs[0].mask; i++) {
+ filter = &cmd.filters[i];
+
+ ADD_TEXT("Filter [%d]:\n", i);
+ ADD_TEXT("\tDiscard=%d\n", filter->discard);
+ ADD_TEXT("\tFrame Type: %s\n",
+ filter->frame_type ? "IPv4" : "Generic");
+
+ for (j = 0; j < ARRAY_SIZE(filter->attrs); j++) {
+ const struct iwl_fw_bcast_filter_attr *attr;
+
+ attr = &filter->attrs[j];
+ if (!attr->mask)
+ break;
+
+ ADD_TEXT("\tAttr [%d]: offset=%d (from %s), mask=0x%x, value=0x%x reserved=0x%x\n",
+ j, attr->offset,
+ attr->offset_type ? "IP End" :
+ "Payload Start",
+ be32_to_cpu(attr->mask),
+ be32_to_cpu(attr->val),
+ le16_to_cpu(attr->reserved1));
+ }
+ }
+out:
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_bcast_filters_write(struct iwl_mvm *mvm, char *buf,
+ size_t count, loff_t *ppos)
+{
+ int pos, next_pos;
+ struct iwl_fw_bcast_filter filter = {};
+ struct iwl_bcast_filter_cmd cmd;
+ u32 filter_id, attr_id, mask, value;
+ int err = 0;
+
+ if (sscanf(buf, "%d %hhi %hhi %n", &filter_id, &filter.discard,
+ &filter.frame_type, &pos) != 3)
+ return -EINVAL;
+
+ if (filter_id >= ARRAY_SIZE(mvm->dbgfs_bcast_filtering.cmd.filters) ||
+ filter.frame_type > BCAST_FILTER_FRAME_TYPE_IPV4)
+ return -EINVAL;
+
+ for (attr_id = 0; attr_id < ARRAY_SIZE(filter.attrs);
+ attr_id++) {
+ struct iwl_fw_bcast_filter_attr *attr =
+ &filter.attrs[attr_id];
+
+ if (pos >= count)
+ break;
+
+ if (sscanf(&buf[pos], "%hhi %hhi %i %i %n",
+ &attr->offset, &attr->offset_type,
+ &mask, &value, &next_pos) != 4)
+ return -EINVAL;
+
+ attr->mask = cpu_to_be32(mask);
+ attr->val = cpu_to_be32(value);
+ if (mask)
+ filter.num_attrs++;
+
+ pos += next_pos;
+ }
+
+ mutex_lock(&mvm->mutex);
+ memcpy(&mvm->dbgfs_bcast_filtering.cmd.filters[filter_id],
+ &filter, sizeof(filter));
+
+ /* send updated bcast filtering configuration */
+ if (mvm->dbgfs_bcast_filtering.override &&
+ iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
+ err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, CMD_SYNC,
+ sizeof(cmd), &cmd);
+ mutex_unlock(&mvm->mutex);
+
+ return err ?: count;
+}
+
+static ssize_t iwl_dbgfs_bcast_filters_macs_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm *mvm = file->private_data;
+ struct iwl_bcast_filter_cmd cmd;
+ char *buf;
+ int bufsz = 1024;
+ int i, pos = 0;
+ ssize_t ret;
+
+ buf = kzalloc(bufsz, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ mutex_lock(&mvm->mutex);
+ if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) {
+ ADD_TEXT("None\n");
+ mutex_unlock(&mvm->mutex);
+ goto out;
+ }
+ mutex_unlock(&mvm->mutex);
+
+ for (i = 0; i < ARRAY_SIZE(cmd.macs); i++) {
+ const struct iwl_fw_bcast_mac *mac = &cmd.macs[i];
+
+ ADD_TEXT("Mac [%d]: discard=%d attached_filters=0x%x\n",
+ i, mac->default_discard, mac->attached_filters);
+ }
+out:
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_bcast_filters_macs_write(struct iwl_mvm *mvm,
+ char *buf, size_t count,
+ loff_t *ppos)
+{
+ struct iwl_bcast_filter_cmd cmd;
+ struct iwl_fw_bcast_mac mac = {};
+ u32 mac_id, attached_filters;
+ int err = 0;
+
+ if (!mvm->bcast_filters)
+ return -ENOENT;
+
+ if (sscanf(buf, "%d %hhi %i", &mac_id, &mac.default_discard,
+ &attached_filters) != 3)
+ return -EINVAL;
+
+ if (mac_id >= ARRAY_SIZE(cmd.macs) ||
+ mac.default_discard > 1 ||
+ attached_filters >= BIT(ARRAY_SIZE(cmd.filters)))
+ return -EINVAL;
+
+ mac.attached_filters = cpu_to_le16(attached_filters);
+
+ mutex_lock(&mvm->mutex);
+ memcpy(&mvm->dbgfs_bcast_filtering.cmd.macs[mac_id],
+ &mac, sizeof(mac));
+
+ /* send updated bcast filtering configuration */
+ if (mvm->dbgfs_bcast_filtering.override &&
+ iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
+ err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, CMD_SYNC,
+ sizeof(cmd), &cmd);
+ mutex_unlock(&mvm->mutex);
+
+ return err ?: count;
+}
+#endif
+
#ifdef CONFIG_PM_SLEEP
static ssize_t iwl_dbgfs_d3_sram_write(struct iwl_mvm *mvm, char *buf,
size_t count, loff_t *ppos)
@@ -658,15 +979,117 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf,
}
#endif
+#define PRINT_MVM_REF(ref) do { \
+ if (test_bit(ref, mvm->ref_bitmap)) \
+ pos += scnprintf(buf + pos, bufsz - pos, \
+ "\t(0x%lx) %s\n", \
+ BIT(ref), #ref); \
+} while (0)
+
+static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm *mvm = file->private_data;
+ int pos = 0;
+ char buf[256];
+ const size_t bufsz = sizeof(buf);
+
+ pos += scnprintf(buf + pos, bufsz - pos, "taken mvm refs: 0x%lx\n",
+ mvm->ref_bitmap[0]);
+
+ PRINT_MVM_REF(IWL_MVM_REF_UCODE_DOWN);
+ PRINT_MVM_REF(IWL_MVM_REF_SCAN);
+ PRINT_MVM_REF(IWL_MVM_REF_ROC);
+ PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT);
+ PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS);
+ PRINT_MVM_REF(IWL_MVM_REF_USER);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_d0i3_refs_write(struct iwl_mvm *mvm, char *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned long value;
+ int ret;
+ bool taken;
+
+ ret = kstrtoul(buf, 10, &value);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&mvm->mutex);
+
+ taken = test_bit(IWL_MVM_REF_USER, mvm->ref_bitmap);
+ if (value == 1 && !taken)
+ iwl_mvm_ref(mvm, IWL_MVM_REF_USER);
+ else if (value == 0 && taken)
+ iwl_mvm_unref(mvm, IWL_MVM_REF_USER);
+ else
+ ret = -EINVAL;
+
+ mutex_unlock(&mvm->mutex);
+
+ if (ret < 0)
+ return ret;
+ return count;
+}
+
#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
_MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm)
#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
_MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm)
-#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) do { \
- if (!debugfs_create_file(#name, mode, parent, mvm, \
+#define MVM_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) do { \
+ if (!debugfs_create_file(alias, mode, parent, mvm, \
&iwl_dbgfs_##name##_ops)) \
goto err; \
} while (0)
+#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \
+ MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode)
+
+static ssize_t
+iwl_dbgfs_prph_reg_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm *mvm = file->private_data;
+ int pos = 0;
+ char buf[32];
+ const size_t bufsz = sizeof(buf);
+
+ if (!mvm->dbgfs_prph_reg_addr)
+ return -EINVAL;
+
+ pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n",
+ mvm->dbgfs_prph_reg_addr,
+ iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr));
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t
+iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf,
+ size_t count, loff_t *ppos)
+{
+ u8 args;
+ u32 value;
+
+ args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value);
+ /* if we only want to set the reg address - nothing more to do */
+ if (args == 1)
+ goto out;
+
+ /* otherwise, make sure we have both address and value */
+ if (args != 2)
+ return -EINVAL;
+
+ iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value);
+out:
+ return count;
+}
+
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64);
/* Device wide debugfs entries */
MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16);
@@ -677,9 +1100,23 @@ MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
MVM_DEBUGFS_READ_FILE_OPS(bt_cmd);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64);
MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats);
+MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats);
MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10);
MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10);
+MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
+
+static const struct file_operations iwl_dbgfs_fw_error_dump_ops = {
+ .open = iwl_dbgfs_fw_error_dump_open,
+ .read = iwl_dbgfs_fw_error_dump_read,
+ .release = iwl_dbgfs_fw_error_dump_release,
+};
+
+#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
+#endif
#ifdef CONFIG_PM_SLEEP
MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
@@ -687,24 +1124,52 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
{
+ struct dentry *bcast_dir __maybe_unused;
char buf[100];
+ spin_lock_init(&mvm->drv_stats_lock);
+
mvm->debugfs_dir = dbgfs_dir;
MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
+ MVM_DEBUGFS_ADD_FILE(fw_error_dump, dbgfs_dir, S_IRUSR);
MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR);
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)
MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
S_IRUSR | S_IWUSR);
MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR);
+ MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, S_IRUSR);
MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR);
+ MVM_DEBUGFS_ADD_FILE(bt_tx_prio, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir,
S_IWUSR | S_IRUSR);
+ MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
+ MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
+
+#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
+ if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) {
+ bcast_dir = debugfs_create_dir("bcast_filtering",
+ mvm->debugfs_dir);
+ if (!bcast_dir)
+ goto err;
+
+ if (!debugfs_create_bool("override", S_IRUSR | S_IWUSR,
+ bcast_dir,
+ &mvm->dbgfs_bcast_filtering.override))
+ goto err;
+
+ MVM_DEBUGFS_ADD_FILE_ALIAS("filters", bcast_filters,
+ bcast_dir, S_IWUSR | S_IRUSR);
+ MVM_DEBUGFS_ADD_FILE_ALIAS("macs", bcast_filters_macs,
+ bcast_dir, S_IWUSR | S_IRUSR);
+ }
+#endif
+
#ifdef CONFIG_PM_SLEEP
MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR);
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h
index 1b4e54d416b0..21877e5966a8 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h
@@ -70,37 +70,28 @@
/**
* enum iwl_bt_coex_flags - flags for BT_COEX command
- * @BT_CH_PRIMARY_EN:
- * @BT_CH_SECONDARY_EN:
- * @BT_NOTIF_COEX_OFF:
* @BT_COEX_MODE_POS:
* @BT_COEX_MODE_MSK:
* @BT_COEX_DISABLE:
* @BT_COEX_2W:
* @BT_COEX_3W:
* @BT_COEX_NW:
- * @BT_USE_DEFAULTS:
- * @BT_SYNC_2_BT_DISABLE:
- * @BT_COEX_CORUNNING_TBL_EN:
+ * @BT_COEX_SYNC2SCO:
+ * @BT_COEX_CORUNNING:
+ * @BT_COEX_MPLUT:
*
* The COEX_MODE must be set for each command. Even if it is not changed.
*/
enum iwl_bt_coex_flags {
- BT_CH_PRIMARY_EN = BIT(0),
- BT_CH_SECONDARY_EN = BIT(1),
- BT_NOTIF_COEX_OFF = BIT(2),
BT_COEX_MODE_POS = 3,
BT_COEX_MODE_MSK = BITS(3) << BT_COEX_MODE_POS,
BT_COEX_DISABLE = 0x0 << BT_COEX_MODE_POS,
BT_COEX_2W = 0x1 << BT_COEX_MODE_POS,
BT_COEX_3W = 0x2 << BT_COEX_MODE_POS,
BT_COEX_NW = 0x3 << BT_COEX_MODE_POS,
- BT_USE_DEFAULTS = BIT(6),
- BT_SYNC_2_BT_DISABLE = BIT(7),
- BT_COEX_CORUNNING_TBL_EN = BIT(8),
- BT_COEX_MPLUT_TBL_EN = BIT(9),
- /* Bit 10 is reserved */
- BT_COEX_WF_PRIO_BOOST_CHECK_EN = BIT(11),
+ BT_COEX_SYNC2SCO = BIT(7),
+ BT_COEX_CORUNNING = BIT(8),
+ BT_COEX_MPLUT = BIT(9),
};
/*
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
index 8415ff312d0e..10fcc1a79ebd 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
@@ -231,11 +231,15 @@ enum iwl_wowlan_wakeup_filters {
IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT = BIT(8),
IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS = BIT(9),
IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE = BIT(10),
- /* BIT(11) reserved */
+ IWL_WOWLAN_WAKEUP_REMOTE_TCP_EXTERNAL = BIT(11),
IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET = BIT(12),
+ IWL_WOWLAN_WAKEUP_IOAC_MAGIC_PACKET = BIT(13),
+ IWL_WOWLAN_WAKEUP_HOST_TIMER = BIT(14),
+ IWL_WOWLAN_WAKEUP_RX_FRAME = BIT(15),
+ IWL_WOWLAN_WAKEUP_BCN_FILTERING = BIT(16),
}; /* WOWLAN_WAKEUP_FILTER_API_E_VER_4 */
-struct iwl_wowlan_config_cmd {
+struct iwl_wowlan_config_cmd_v2 {
__le32 wakeup_filter;
__le16 non_qos_seq;
__le16 qos_seq[8];
@@ -243,6 +247,12 @@ struct iwl_wowlan_config_cmd {
u8 is_11n_connection;
} __packed; /* WOWLAN_CONFIG_API_S_VER_2 */
+struct iwl_wowlan_config_cmd_v3 {
+ struct iwl_wowlan_config_cmd_v2 common;
+ u8 offloading_tid;
+ u8 reserved[3];
+} __packed; /* WOWLAN_CONFIG_API_S_VER_3 */
+
/*
* WOWLAN_TSC_RSC_PARAMS
*/
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
index 884c08725308..cbbcd8e284e4 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
@@ -301,54 +301,65 @@ struct iwl_beacon_filter_cmd {
/* Beacon filtering and beacon abort */
#define IWL_BF_ENERGY_DELTA_DEFAULT 5
+#define IWL_BF_ENERGY_DELTA_D0I3 20
#define IWL_BF_ENERGY_DELTA_MAX 255
#define IWL_BF_ENERGY_DELTA_MIN 0
#define IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT 1
+#define IWL_BF_ROAMING_ENERGY_DELTA_D0I3 20
#define IWL_BF_ROAMING_ENERGY_DELTA_MAX 255
#define IWL_BF_ROAMING_ENERGY_DELTA_MIN 0
#define IWL_BF_ROAMING_STATE_DEFAULT 72
+#define IWL_BF_ROAMING_STATE_D0I3 72
#define IWL_BF_ROAMING_STATE_MAX 255
#define IWL_BF_ROAMING_STATE_MIN 0
#define IWL_BF_TEMP_THRESHOLD_DEFAULT 112
+#define IWL_BF_TEMP_THRESHOLD_D0I3 112
#define IWL_BF_TEMP_THRESHOLD_MAX 255
#define IWL_BF_TEMP_THRESHOLD_MIN 0
#define IWL_BF_TEMP_FAST_FILTER_DEFAULT 1
+#define IWL_BF_TEMP_FAST_FILTER_D0I3 1
#define IWL_BF_TEMP_FAST_FILTER_MAX 255
#define IWL_BF_TEMP_FAST_FILTER_MIN 0
#define IWL_BF_TEMP_SLOW_FILTER_DEFAULT 5
+#define IWL_BF_TEMP_SLOW_FILTER_D0I3 5
#define IWL_BF_TEMP_SLOW_FILTER_MAX 255
#define IWL_BF_TEMP_SLOW_FILTER_MIN 0
#define IWL_BF_ENABLE_BEACON_FILTER_DEFAULT 1
#define IWL_BF_DEBUG_FLAG_DEFAULT 0
+#define IWL_BF_DEBUG_FLAG_D0I3 0
#define IWL_BF_ESCAPE_TIMER_DEFAULT 50
+#define IWL_BF_ESCAPE_TIMER_D0I3 1024
#define IWL_BF_ESCAPE_TIMER_MAX 1024
#define IWL_BF_ESCAPE_TIMER_MIN 0
#define IWL_BA_ESCAPE_TIMER_DEFAULT 6
+#define IWL_BA_ESCAPE_TIMER_D0I3 6
#define IWL_BA_ESCAPE_TIMER_D3 9
#define IWL_BA_ESCAPE_TIMER_MAX 1024
#define IWL_BA_ESCAPE_TIMER_MIN 0
#define IWL_BA_ENABLE_BEACON_ABORT_DEFAULT 1
-#define IWL_BF_CMD_CONFIG_DEFAULTS \
- .bf_energy_delta = cpu_to_le32(IWL_BF_ENERGY_DELTA_DEFAULT), \
- .bf_roaming_energy_delta = \
- cpu_to_le32(IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT), \
- .bf_roaming_state = cpu_to_le32(IWL_BF_ROAMING_STATE_DEFAULT), \
- .bf_temp_threshold = cpu_to_le32(IWL_BF_TEMP_THRESHOLD_DEFAULT), \
- .bf_temp_fast_filter = cpu_to_le32(IWL_BF_TEMP_FAST_FILTER_DEFAULT), \
- .bf_temp_slow_filter = cpu_to_le32(IWL_BF_TEMP_SLOW_FILTER_DEFAULT), \
- .bf_debug_flag = cpu_to_le32(IWL_BF_DEBUG_FLAG_DEFAULT), \
- .bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER_DEFAULT), \
- .ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_DEFAULT)
+#define IWL_BF_CMD_CONFIG(mode) \
+ .bf_energy_delta = cpu_to_le32(IWL_BF_ENERGY_DELTA ## mode), \
+ .bf_roaming_energy_delta = \
+ cpu_to_le32(IWL_BF_ROAMING_ENERGY_DELTA ## mode), \
+ .bf_roaming_state = cpu_to_le32(IWL_BF_ROAMING_STATE ## mode), \
+ .bf_temp_threshold = cpu_to_le32(IWL_BF_TEMP_THRESHOLD ## mode), \
+ .bf_temp_fast_filter = cpu_to_le32(IWL_BF_TEMP_FAST_FILTER ## mode), \
+ .bf_temp_slow_filter = cpu_to_le32(IWL_BF_TEMP_SLOW_FILTER ## mode), \
+ .bf_debug_flag = cpu_to_le32(IWL_BF_DEBUG_FLAG ## mode), \
+ .bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER ## mode), \
+ .ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER ## mode)
+#define IWL_BF_CMD_CONFIG_DEFAULTS IWL_BF_CMD_CONFIG(_DEFAULT)
+#define IWL_BF_CMD_CONFIG_D0I3 IWL_BF_CMD_CONFIG(_D0I3)
#endif
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
index 85057219cc43..39148b5bb332 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
@@ -257,7 +257,8 @@ enum {
/* Bit 17-18: (0) SS, (1) SS*2 */
#define RATE_MCS_STBC_POS 17
-#define RATE_MCS_STBC_MSK (1 << RATE_MCS_STBC_POS)
+#define RATE_MCS_HT_STBC_MSK (3 << RATE_MCS_STBC_POS)
+#define RATE_MCS_VHT_STBC_MSK (1 << RATE_MCS_STBC_POS)
/* Bit 19: (0) Beamforming is off, (1) Beamforming is on */
#define RATE_MCS_BF_POS 19
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
index 73cbba7424f2..9426905de6b2 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
@@ -504,6 +504,7 @@ struct iwl_scan_offload_profile {
* @match_notify: clients waiting for match found notification
* @pass_match: clients waiting for the results
* @active_clients: active clients bitmap - enum scan_framework_client
+ * @any_beacon_notify: clients waiting for match notification without match
*/
struct iwl_scan_offload_profile_cfg {
struct iwl_scan_offload_profile profiles[IWL_SCAN_MAX_PROFILES];
@@ -512,7 +513,8 @@ struct iwl_scan_offload_profile_cfg {
u8 match_notify;
u8 pass_match;
u8 active_clients;
- u8 reserved[3];
+ u8 any_beacon_notify;
+ u8 reserved[2];
} __packed;
/**
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
index 1b60fdff6a56..d63647867262 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
@@ -199,11 +199,14 @@ enum iwl_sta_modify_flag {
* @STA_SLEEP_STATE_AWAKE:
* @STA_SLEEP_STATE_PS_POLL:
* @STA_SLEEP_STATE_UAPSD:
+ * @STA_SLEEP_STATE_MOREDATA: set more-data bit on
+ * (last) released frame
*/
enum iwl_sta_sleep_flag {
- STA_SLEEP_STATE_AWAKE = 0,
- STA_SLEEP_STATE_PS_POLL = BIT(0),
- STA_SLEEP_STATE_UAPSD = BIT(1),
+ STA_SLEEP_STATE_AWAKE = 0,
+ STA_SLEEP_STATE_PS_POLL = BIT(0),
+ STA_SLEEP_STATE_UAPSD = BIT(1),
+ STA_SLEEP_STATE_MOREDATA = BIT(2),
};
/* STA ID and color bits definitions */
@@ -318,13 +321,15 @@ struct iwl_mvm_add_sta_cmd_v5 {
} __packed; /* ADD_STA_CMD_API_S_VER_5 */
/**
- * struct iwl_mvm_add_sta_cmd_v6 - Add / modify a station
- * VER_6 of this command is quite similar to VER_5 except
+ * struct iwl_mvm_add_sta_cmd_v7 - Add / modify a station
+ * VER_7 of this command is quite similar to VER_5 except
* exclusion of all fields related to the security key installation.
+ * It only differs from VER_6 by the "awake_acs" field that is
+ * reserved and ignored in VER_6.
*/
-struct iwl_mvm_add_sta_cmd_v6 {
+struct iwl_mvm_add_sta_cmd_v7 {
u8 add_modify;
- u8 reserved1;
+ u8 awake_acs;
__le16 tid_disable_tx;
__le32 mac_id_n_color;
u8 addr[ETH_ALEN]; /* _STA_ID_MODIFY_INFO_API_S_VER_1 */
@@ -342,7 +347,7 @@ struct iwl_mvm_add_sta_cmd_v6 {
__le16 assoc_id;
__le16 beamform_flags;
__le32 tfd_queue_msk;
-} __packed; /* ADD_STA_CMD_API_S_VER_6 */
+} __packed; /* ADD_STA_CMD_API_S_VER_7 */
/**
* struct iwl_mvm_add_sta_key_cmd - add/modify sta key
@@ -432,5 +437,15 @@ struct iwl_mvm_wep_key_cmd {
struct iwl_mvm_wep_key wep_key[0];
} __packed; /* SEC_CURR_WEP_KEY_CMD_API_S_VER_2 */
+/**
+ * struct iwl_mvm_eosp_notification - EOSP notification from firmware
+ * @remain_frame_count: # of frames remaining, non-zero if SP was cut
+ * short by GO absence
+ * @sta_id: station ID
+ */
+struct iwl_mvm_eosp_notification {
+ __le32 remain_frame_count;
+ __le32 sta_id;
+} __packed; /* UAPSD_EOSP_NTFY_API_S_VER_1 */
#endif /* __fw_api_sta_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
index b674c2a2b51c..8e122f3a7a74 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
@@ -76,6 +76,8 @@
* @TX_CMD_FLG_VHT_NDPA: mark frame is NDPA for VHT beamformer sequence
* @TX_CMD_FLG_HT_NDPA: mark frame is NDPA for HT beamformer sequence
* @TX_CMD_FLG_CSI_FDBK2HOST: mark to send feedback to host (only if good CRC)
+ * @TX_CMD_FLG_BT_PRIO_POS: the position of the BT priority (bit 11 is ignored
+ * on old firmwares).
* @TX_CMD_FLG_BT_DIS: disable BT priority for this frame
* @TX_CMD_FLG_SEQ_CTL: set if FW should override the sequence control.
* Should be set for mgmt, non-QOS data, mcast, bcast and in scan command
@@ -107,6 +109,7 @@ enum iwl_tx_flags {
TX_CMD_FLG_VHT_NDPA = BIT(8),
TX_CMD_FLG_HT_NDPA = BIT(9),
TX_CMD_FLG_CSI_FDBK2HOST = BIT(10),
+ TX_CMD_FLG_BT_PRIO_POS = 11,
TX_CMD_FLG_BT_DIS = BIT(12),
TX_CMD_FLG_SEQ_CTL = BIT(13),
TX_CMD_FLG_MORE_FRAG = BIT(14),
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index 989d7dbdca6c..6e75b52588de 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -70,7 +70,7 @@
#include "fw-api-mac.h"
#include "fw-api-power.h"
#include "fw-api-d3.h"
-#include "fw-api-bt-coex.h"
+#include "fw-api-coex.h"
/* maximal number of Tx queues in any platform */
#define IWL_MVM_MAX_QUEUES 20
@@ -95,6 +95,7 @@ enum {
/* PHY context commands */
PHY_CONTEXT_CMD = 0x8,
DBG_CFG = 0x9,
+ ANTENNA_COUPLING_NOTIFICATION = 0xa,
/* station table */
ADD_STA_KEY = 0x17,
@@ -163,6 +164,7 @@ enum {
TX_ANT_CONFIGURATION_CMD = 0x98,
BT_CONFIG = 0x9b,
STATISTICS_NOTIFICATION = 0x9d,
+ EOSP_NOTIFICATION = 0x9e,
REDUCE_TX_POWER_CMD = 0x9f,
/* RF-KILL commands and notifications */
@@ -190,6 +192,7 @@ enum {
REPLY_DEBUG_CMD = 0xf0,
DEBUG_LOG_MSG = 0xf7,
+ BCAST_FILTER_CMD = 0xcf,
MCAST_FILTER_CMD = 0xd0,
/* D3 commands/notifications */
@@ -197,6 +200,7 @@ enum {
PROT_OFFLOAD_CONFIG_CMD = 0xd4,
OFFLOADS_QUERY_CMD = 0xd5,
REMOTE_WAKE_CONFIG_CMD = 0xd6,
+ D0I3_END_CMD = 0xed,
/* for WoWLAN in particular */
WOWLAN_PATTERNS = 0xe0,
@@ -313,14 +317,12 @@ enum {
/* Section types for NVM_ACCESS_CMD */
enum {
- NVM_SECTION_TYPE_HW = 0,
- NVM_SECTION_TYPE_SW,
- NVM_SECTION_TYPE_PAPD,
- NVM_SECTION_TYPE_BT,
- NVM_SECTION_TYPE_CALIBRATION,
- NVM_SECTION_TYPE_PRODUCTION,
- NVM_SECTION_TYPE_POST_FCS_CALIB,
- NVM_NUM_OF_SECTIONS,
+ NVM_SECTION_TYPE_SW = 1,
+ NVM_SECTION_TYPE_REGULATORY = 3,
+ NVM_SECTION_TYPE_CALIBRATION = 4,
+ NVM_SECTION_TYPE_PRODUCTION = 5,
+ NVM_SECTION_TYPE_MAC_OVERRIDE = 11,
+ NVM_MAX_NUM_SECTIONS = 12,
};
/**
@@ -412,6 +414,35 @@ struct mvm_alive_resp {
__le32 scd_base_ptr; /* SRAM address for SCD */
} __packed; /* ALIVE_RES_API_S_VER_1 */
+struct mvm_alive_resp_ver2 {
+ __le16 status;
+ __le16 flags;
+ u8 ucode_minor;
+ u8 ucode_major;
+ __le16 id;
+ u8 api_minor;
+ u8 api_major;
+ u8 ver_subtype;
+ u8 ver_type;
+ u8 mac;
+ u8 opt;
+ __le16 reserved2;
+ __le32 timestamp;
+ __le32 error_event_table_ptr; /* SRAM address for error log */
+ __le32 log_event_table_ptr; /* SRAM address for LMAC event log */
+ __le32 cpu_register_ptr;
+ __le32 dbgm_config_ptr;
+ __le32 alive_counter_ptr;
+ __le32 scd_base_ptr; /* SRAM address for SCD */
+ __le32 st_fwrd_addr; /* pointer to Store and forward */
+ __le32 st_fwrd_size;
+ u8 umac_minor; /* UMAC version: minor */
+ u8 umac_major; /* UMAC version: major */
+ __le16 umac_id; /* UMAC version: id */
+ __le32 error_info_addr; /* SRAM address for UMAC error log */
+ __le32 dbg_print_buff_addr;
+} __packed; /* ALIVE_RES_API_S_VER_2 */
+
/* Error response/notification */
enum {
FW_ERR_UNKNOWN_CMD = 0x0,
@@ -682,6 +713,7 @@ enum {
TE_V2_NOTIF_HOST_FRAG_END = BIT(5),
TE_V2_NOTIF_INTERNAL_FRAG_START = BIT(6),
TE_V2_NOTIF_INTERNAL_FRAG_END = BIT(7),
+ T2_V2_START_IMMEDIATELY = BIT(11),
TE_V2_NOTIF_MSK = 0xff,
@@ -1159,6 +1191,90 @@ struct iwl_mcast_filter_cmd {
u8 addr_list[0];
} __packed; /* MCAST_FILTERING_CMD_API_S_VER_1 */
+#define MAX_BCAST_FILTERS 8
+#define MAX_BCAST_FILTER_ATTRS 2
+
+/**
+ * enum iwl_mvm_bcast_filter_attr_offset - written by fw for each Rx packet
+ * @BCAST_FILTER_OFFSET_PAYLOAD_START: offset is from payload start.
+ * @BCAST_FILTER_OFFSET_IP_END: offset is from ip header end (i.e.
+ * start of ip payload).
+ */
+enum iwl_mvm_bcast_filter_attr_offset {
+ BCAST_FILTER_OFFSET_PAYLOAD_START = 0,
+ BCAST_FILTER_OFFSET_IP_END = 1,
+};
+
+/**
+ * struct iwl_fw_bcast_filter_attr - broadcast filter attribute
+ * @offset_type: &enum iwl_mvm_bcast_filter_attr_offset.
+ * @offset: starting offset of this pattern.
+ * @val: value to match - big endian (MSB is the first
+ * byte to match from offset pos).
+ * @mask: mask to match (big endian).
+ */
+struct iwl_fw_bcast_filter_attr {
+ u8 offset_type;
+ u8 offset;
+ __le16 reserved1;
+ __be32 val;
+ __be32 mask;
+} __packed; /* BCAST_FILTER_ATT_S_VER_1 */
+
+/**
+ * enum iwl_mvm_bcast_filter_frame_type - filter frame type
+ * @BCAST_FILTER_FRAME_TYPE_ALL: consider all frames.
+ * @BCAST_FILTER_FRAME_TYPE_IPV4: consider only ipv4 frames
+ */
+enum iwl_mvm_bcast_filter_frame_type {
+ BCAST_FILTER_FRAME_TYPE_ALL = 0,
+ BCAST_FILTER_FRAME_TYPE_IPV4 = 1,
+};
+
+/**
+ * struct iwl_fw_bcast_filter - broadcast filter
+ * @discard: discard frame (1) or let it pass (0).
+ * @frame_type: &enum iwl_mvm_bcast_filter_frame_type.
+ * @num_attrs: number of valid attributes in this filter.
+ * @attrs: attributes of this filter. a filter is considered matched
+ * only when all its attributes are matched (i.e. AND relationship)
+ */
+struct iwl_fw_bcast_filter {
+ u8 discard;
+ u8 frame_type;
+ u8 num_attrs;
+ u8 reserved1;
+ struct iwl_fw_bcast_filter_attr attrs[MAX_BCAST_FILTER_ATTRS];
+} __packed; /* BCAST_FILTER_S_VER_1 */
+
+/**
+ * struct iwl_fw_bcast_mac - per-mac broadcast filtering configuration.
+ * @default_discard: default action for this mac (discard (1) / pass (0)).
+ * @attached_filters: bitmap of relevant filters for this mac.
+ */
+struct iwl_fw_bcast_mac {
+ u8 default_discard;
+ u8 reserved1;
+ __le16 attached_filters;
+} __packed; /* BCAST_MAC_CONTEXT_S_VER_1 */
+
+/**
+ * struct iwl_bcast_filter_cmd - broadcast filtering configuration
+ * @disable: enable (0) / disable (1)
+ * @max_bcast_filters: max number of filters (MAX_BCAST_FILTERS)
+ * @max_macs: max number of macs (NUM_MAC_INDEX_DRIVER)
+ * @filters: broadcast filters
+ * @macs: broadcast filtering configuration per-mac
+ */
+struct iwl_bcast_filter_cmd {
+ u8 disable;
+ u8 max_bcast_filters;
+ u8 max_macs;
+ u8 reserved1;
+ struct iwl_fw_bcast_filter filters[MAX_BCAST_FILTERS];
+ struct iwl_fw_bcast_mac macs[NUM_MAC_INDEX_DRIVER];
+} __packed; /* BCAST_FILTERING_HCMD_API_S_VER_1 */
+
struct mvm_statistics_dbg {
__le32 burst_check;
__le32 burst_count;
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h b/drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h
new file mode 100644
index 000000000000..58c8941c0d95
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h
@@ -0,0 +1,106 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel 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 full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifndef __fw_error_dump_h__
+#define __fw_error_dump_h__
+
+#include <linux/types.h>
+
+#define IWL_FW_ERROR_DUMP_BARKER 0x14789632
+
+/**
+ * enum iwl_fw_error_dump_type - types of data in the dump file
+ * @IWL_FW_ERROR_DUMP_SRAM:
+ * @IWL_FW_ERROR_DUMP_REG:
+ */
+enum iwl_fw_error_dump_type {
+ IWL_FW_ERROR_DUMP_SRAM = 0,
+ IWL_FW_ERROR_DUMP_REG = 1,
+
+ IWL_FW_ERROR_DUMP_MAX,
+};
+
+/**
+ * struct iwl_fw_error_dump_data - data for one type
+ * @type: %enum iwl_fw_error_dump_type
+ * @len: the length starting from %data - must be a multiplier of 4.
+ * @data: the data itself padded to be a multiplier of 4.
+ */
+struct iwl_fw_error_dump_data {
+ __le32 type;
+ __le32 len;
+ __u8 data[];
+} __packed __aligned(4);
+
+/**
+ * struct iwl_fw_error_dump_file - the layout of the header of the file
+ * @barker: must be %IWL_FW_ERROR_DUMP_BARKER
+ * @file_len: the length of all the file starting from %barker
+ * @data: array of %struct iwl_fw_error_dump_data
+ */
+struct iwl_fw_error_dump_file {
+ __le32 barker;
+ __le32 file_len;
+ u8 data[0];
+} __packed __aligned(4);
+
+#endif /* __fw_error_dump_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
index c03d39541f9e..7ce20062f32d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -110,18 +110,48 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
container_of(notif_wait, struct iwl_mvm, notif_wait);
struct iwl_mvm_alive_data *alive_data = data;
struct mvm_alive_resp *palive;
-
- palive = (void *)pkt->data;
-
- mvm->error_event_table = le32_to_cpu(palive->error_event_table_ptr);
- mvm->log_event_table = le32_to_cpu(palive->log_event_table_ptr);
- alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr);
-
- alive_data->valid = le16_to_cpu(palive->status) == IWL_ALIVE_STATUS_OK;
- IWL_DEBUG_FW(mvm,
- "Alive ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n",
- le16_to_cpu(palive->status), palive->ver_type,
- palive->ver_subtype, palive->flags);
+ struct mvm_alive_resp_ver2 *palive2;
+
+ if (iwl_rx_packet_payload_len(pkt) == sizeof(*palive)) {
+ palive = (void *)pkt->data;
+
+ mvm->support_umac_log = false;
+ mvm->error_event_table =
+ le32_to_cpu(palive->error_event_table_ptr);
+ mvm->log_event_table = le32_to_cpu(palive->log_event_table_ptr);
+ alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr);
+
+ alive_data->valid = le16_to_cpu(palive->status) ==
+ IWL_ALIVE_STATUS_OK;
+ IWL_DEBUG_FW(mvm,
+ "Alive VER1 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n",
+ le16_to_cpu(palive->status), palive->ver_type,
+ palive->ver_subtype, palive->flags);
+ } else {
+ palive2 = (void *)pkt->data;
+
+ mvm->error_event_table =
+ le32_to_cpu(palive2->error_event_table_ptr);
+ mvm->log_event_table =
+ le32_to_cpu(palive2->log_event_table_ptr);
+ alive_data->scd_base_addr = le32_to_cpu(palive2->scd_base_ptr);
+ mvm->umac_error_event_table =
+ le32_to_cpu(palive2->error_info_addr);
+
+ alive_data->valid = le16_to_cpu(palive2->status) ==
+ IWL_ALIVE_STATUS_OK;
+ if (mvm->umac_error_event_table)
+ mvm->support_umac_log = true;
+
+ IWL_DEBUG_FW(mvm,
+ "Alive VER2 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n",
+ le16_to_cpu(palive2->status), palive2->ver_type,
+ palive2->ver_subtype, palive2->flags);
+
+ IWL_DEBUG_FW(mvm,
+ "UMAC version: Major - 0x%x, Minor - 0x%x\n",
+ palive2->umac_major, palive2->umac_minor);
+ }
return true;
}
@@ -292,7 +322,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
}
/* Send TX valid antennas before triggering calibrations */
- ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
+ ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
if (ret)
goto error;
@@ -328,8 +358,6 @@ out:
GFP_KERNEL);
if (!mvm->nvm_data)
return -ENOMEM;
- mvm->nvm_data->valid_rx_ant = 1;
- mvm->nvm_data->valid_tx_ant = 1;
mvm->nvm_data->bands[0].channels = mvm->nvm_data->channels;
mvm->nvm_data->bands[0].n_channels = 1;
mvm->nvm_data->bands[0].n_bitrates = 1;
@@ -341,8 +369,6 @@ out:
return ret;
}
-#define UCODE_CALIB_TIMEOUT (2*HZ)
-
int iwl_mvm_up(struct iwl_mvm *mvm)
{
int ret, i;
@@ -394,7 +420,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
if (ret)
IWL_ERR(mvm, "Failed to initialize Smart Fifo\n");
- ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
+ ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
if (ret)
goto error;
@@ -439,10 +465,23 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
goto error;
}
- ret = iwl_mvm_power_update_device_mode(mvm);
+ /* Initialize tx backoffs to the minimal possible */
+ iwl_mvm_tt_tx_backoff(mvm, 0);
+
+ if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) {
+ ret = iwl_power_legacy_set_cam_mode(mvm);
+ if (ret)
+ goto error;
+ }
+
+ ret = iwl_mvm_power_update_device(mvm);
if (ret)
goto error;
+ /* allow FW/transport low power modes if not during restart */
+ if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
+ iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN);
+
IWL_DEBUG_INFO(mvm, "RT uCode started.\n");
return 0;
error:
@@ -466,7 +505,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm)
goto error;
}
- ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
+ ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
if (ret)
goto error;
diff --git a/drivers/net/wireless/iwlwifi/mvm/led.c b/drivers/net/wireless/iwlwifi/mvm/led.c
index 6b4ea6bf8ffe..e3b3cf4dbd77 100644
--- a/drivers/net/wireless/iwlwifi/mvm/led.c
+++ b/drivers/net/wireless/iwlwifi/mvm/led.c
@@ -94,6 +94,8 @@ int iwl_mvm_leds_init(struct iwl_mvm *mvm)
int ret;
switch (mode) {
+ case IWL_LED_BLINK:
+ IWL_ERR(mvm, "Blink led mode not supported, used default\n");
case IWL_LED_DEFAULT:
case IWL_LED_RF_STATE:
mode = IWL_LED_RF_STATE;
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
index ba723d50939a..9ccec10bba16 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
@@ -90,6 +90,7 @@ static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac,
{
struct iwl_mvm_mac_iface_iterator_data *data = _data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ u16 min_bi;
/* Skip the interface for which we are trying to assign a tsf_id */
if (vif == data->vif)
@@ -114,42 +115,57 @@ static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac,
switch (data->vif->type) {
case NL80211_IFTYPE_STATION:
/*
- * The new interface is client, so if the existing one
- * we're iterating is an AP, and both interfaces have the
- * same beacon interval, the same TSF should be used to
- * avoid drift between the new client and existing AP,
- * the existing AP will get drift updates from the new
- * client context in this case
+ * The new interface is a client, so if the one we're iterating
+ * is an AP, and the beacon interval of the AP is a multiple or
+ * divisor of the beacon interval of the client, the same TSF
+ * should be used to avoid drift between the new client and
+ * existing AP. The existing AP will get drift updates from the
+ * new client context in this case.
*/
- if (vif->type == NL80211_IFTYPE_AP) {
- if (data->preferred_tsf == NUM_TSF_IDS &&
- test_bit(mvmvif->tsf_id, data->available_tsf_ids) &&
- (vif->bss_conf.beacon_int ==
- data->vif->bss_conf.beacon_int)) {
- data->preferred_tsf = mvmvif->tsf_id;
- return;
- }
+ if (vif->type != NL80211_IFTYPE_AP ||
+ data->preferred_tsf != NUM_TSF_IDS ||
+ !test_bit(mvmvif->tsf_id, data->available_tsf_ids))
+ break;
+
+ min_bi = min(data->vif->bss_conf.beacon_int,
+ vif->bss_conf.beacon_int);
+
+ if (!min_bi)
+ break;
+
+ if ((data->vif->bss_conf.beacon_int -
+ vif->bss_conf.beacon_int) % min_bi == 0) {
+ data->preferred_tsf = mvmvif->tsf_id;
+ return;
}
break;
+
case NL80211_IFTYPE_AP:
/*
- * The new interface is AP/GO, so in case both interfaces
- * have the same beacon interval, it should get drift
- * updates from an existing client or use the same
- * TSF as an existing GO. There's no drift between
- * TSFs internally but if they used different TSFs
- * then a new client MAC could update one of them
- * and cause drift that way.
+ * The new interface is AP/GO, so if its beacon interval is a
+ * multiple or a divisor of the beacon interval of an existing
+ * interface, it should get drift updates from an existing
+ * client or use the same TSF as an existing GO. There's no
+ * drift between TSFs internally but if they used different
+ * TSFs then a new client MAC could update one of them and
+ * cause drift that way.
*/
- if (vif->type == NL80211_IFTYPE_STATION ||
- vif->type == NL80211_IFTYPE_AP) {
- if (data->preferred_tsf == NUM_TSF_IDS &&
- test_bit(mvmvif->tsf_id, data->available_tsf_ids) &&
- (vif->bss_conf.beacon_int ==
- data->vif->bss_conf.beacon_int)) {
- data->preferred_tsf = mvmvif->tsf_id;
- return;
- }
+ if ((vif->type != NL80211_IFTYPE_AP &&
+ vif->type != NL80211_IFTYPE_STATION) ||
+ data->preferred_tsf != NUM_TSF_IDS ||
+ !test_bit(mvmvif->tsf_id, data->available_tsf_ids))
+ break;
+
+ min_bi = min(data->vif->bss_conf.beacon_int,
+ vif->bss_conf.beacon_int);
+
+ if (!min_bi)
+ break;
+
+ if ((data->vif->bss_conf.beacon_int -
+ vif->bss_conf.beacon_int) % min_bi == 0) {
+ data->preferred_tsf = mvmvif->tsf_id;
+ return;
}
break;
default:
@@ -936,7 +952,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
TX_CMD_FLG_TSF);
mvm->mgmt_last_antenna_idx =
- iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw),
+ iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant,
mvm->mgmt_last_antenna_idx);
beacon_cmd.tx.rate_n_flags =
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index c49b5073c251..4dd9ff43b8b6 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -66,7 +66,9 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ip.h>
+#include <linux/if_arp.h>
#include <net/mac80211.h>
+#include <net/ieee80211_radiotap.h>
#include <net/tcp.h>
#include "iwl-op-mode.h"
@@ -128,6 +130,117 @@ static const struct wiphy_wowlan_tcp_support iwl_mvm_wowlan_tcp_support = {
};
#endif
+#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
+/*
+ * Use the reserved field to indicate magic values.
+ * these values will only be used internally by the driver,
+ * and won't make it to the fw (reserved will be 0).
+ * BC_FILTER_MAGIC_IP - configure the val of this attribute to
+ * be the vif's ip address. in case there is not a single
+ * ip address (0, or more than 1), this attribute will
+ * be skipped.
+ * BC_FILTER_MAGIC_MAC - set the val of this attribute to
+ * the LSB bytes of the vif's mac address
+ */
+enum {
+ BC_FILTER_MAGIC_NONE = 0,
+ BC_FILTER_MAGIC_IP,
+ BC_FILTER_MAGIC_MAC,
+};
+
+static const struct iwl_fw_bcast_filter iwl_mvm_default_bcast_filters[] = {
+ {
+ /* arp */
+ .discard = 0,
+ .frame_type = BCAST_FILTER_FRAME_TYPE_ALL,
+ .attrs = {
+ {
+ /* frame type - arp, hw type - ethernet */
+ .offset_type =
+ BCAST_FILTER_OFFSET_PAYLOAD_START,
+ .offset = sizeof(rfc1042_header),
+ .val = cpu_to_be32(0x08060001),
+ .mask = cpu_to_be32(0xffffffff),
+ },
+ {
+ /* arp dest ip */
+ .offset_type =
+ BCAST_FILTER_OFFSET_PAYLOAD_START,
+ .offset = sizeof(rfc1042_header) + 2 +
+ sizeof(struct arphdr) +
+ ETH_ALEN + sizeof(__be32) +
+ ETH_ALEN,
+ .mask = cpu_to_be32(0xffffffff),
+ /* mark it as special field */
+ .reserved1 = cpu_to_le16(BC_FILTER_MAGIC_IP),
+ },
+ },
+ },
+ {
+ /* dhcp offer bcast */
+ .discard = 0,
+ .frame_type = BCAST_FILTER_FRAME_TYPE_IPV4,
+ .attrs = {
+ {
+ /* udp dest port - 68 (bootp client)*/
+ .offset_type = BCAST_FILTER_OFFSET_IP_END,
+ .offset = offsetof(struct udphdr, dest),
+ .val = cpu_to_be32(0x00440000),
+ .mask = cpu_to_be32(0xffff0000),
+ },
+ {
+ /* dhcp - lsb bytes of client hw address */
+ .offset_type = BCAST_FILTER_OFFSET_IP_END,
+ .offset = 38,
+ .mask = cpu_to_be32(0xffffffff),
+ /* mark it as special field */
+ .reserved1 = cpu_to_le16(BC_FILTER_MAGIC_MAC),
+ },
+ },
+ },
+ /* last filter must be empty */
+ {},
+};
+#endif
+
+void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
+{
+ if (!iwl_mvm_is_d0i3_supported(mvm))
+ return;
+
+ IWL_DEBUG_RPM(mvm, "Take mvm reference - type %d\n", ref_type);
+ WARN_ON(test_and_set_bit(ref_type, mvm->ref_bitmap));
+ iwl_trans_ref(mvm->trans);
+}
+
+void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
+{
+ if (!iwl_mvm_is_d0i3_supported(mvm))
+ return;
+
+ IWL_DEBUG_RPM(mvm, "Leave mvm reference - type %d\n", ref_type);
+ WARN_ON(!test_and_clear_bit(ref_type, mvm->ref_bitmap));
+ iwl_trans_unref(mvm->trans);
+}
+
+static void
+iwl_mvm_unref_all_except(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref)
+{
+ int i;
+
+ if (!iwl_mvm_is_d0i3_supported(mvm))
+ return;
+
+ for_each_set_bit(i, mvm->ref_bitmap, IWL_MVM_REF_COUNT) {
+ if (ref == i)
+ continue;
+
+ IWL_DEBUG_RPM(mvm, "Cleanup: remove mvm ref type %d\n", i);
+ clear_bit(i, mvm->ref_bitmap);
+ iwl_trans_unref(mvm->trans);
+ }
+}
+
static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm)
{
int i;
@@ -168,6 +281,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->queues = mvm->first_agg_queue;
hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;
+ hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC |
+ IEEE80211_RADIOTAP_MCS_HAVE_STBC;
+ hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC;
hw->rate_control_algorithm = "iwl-mvm-rs";
/*
@@ -179,7 +295,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
!iwlwifi_mod_params.sw_crypto)
hw->flags |= IEEE80211_HW_MFP_CAPABLE;
- if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT) {
+ if (0 && mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT) {
hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD;
hw->uapsd_queues = IWL_UAPSD_AC_INFO;
hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
@@ -203,6 +319,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
REGULATORY_DISABLE_BEACON_HINTS;
+ if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD)
+ hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
+
hw->wiphy->iface_combinations = iwl_mvm_iface_combinations;
hw->wiphy->n_iface_combinations =
ARRAY_SIZE(iwl_mvm_iface_combinations);
@@ -256,8 +375,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
}
hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN |
- NL80211_FEATURE_P2P_GO_OPPPS |
- NL80211_FEATURE_LOW_PRIORITY_SCAN;
+ NL80211_FEATURE_P2P_GO_OPPPS;
mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
@@ -289,6 +407,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
}
#endif
+#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
+ /* assign default bcast filtering configuration */
+ mvm->bcast_filters = iwl_mvm_default_bcast_filters;
+#endif
+
ret = iwl_mvm_leds_init(mvm);
if (ret)
return ret;
@@ -300,11 +423,55 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
return ret;
}
+static bool iwl_mvm_defer_tx(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb)
+{
+ struct iwl_mvm_sta *mvmsta;
+ bool defer = false;
+
+ /*
+ * double check the IN_D0I3 flag both before and after
+ * taking the spinlock, in order to prevent taking
+ * the spinlock when not needed.
+ */
+ if (likely(!test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status)))
+ return false;
+
+ spin_lock(&mvm->d0i3_tx_lock);
+ /*
+ * testing the flag again ensures the skb dequeue
+ * loop (on d0i3 exit) hasn't run yet.
+ */
+ if (!test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status))
+ goto out;
+
+ mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ if (mvmsta->sta_id == IWL_MVM_STATION_COUNT ||
+ mvmsta->sta_id != mvm->d0i3_ap_sta_id)
+ goto out;
+
+ __skb_queue_tail(&mvm->d0i3_tx, skb);
+ ieee80211_stop_queues(mvm->hw);
+
+ /* trigger wakeup */
+ iwl_mvm_ref(mvm, IWL_MVM_REF_TX);
+ iwl_mvm_unref(mvm, IWL_MVM_REF_TX);
+
+ defer = true;
+out:
+ spin_unlock(&mvm->d0i3_tx_lock);
+ return defer;
+}
+
static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
struct ieee80211_tx_control *control,
struct sk_buff *skb)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct ieee80211_sta *sta = control->sta;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_hdr *hdr = (void *)skb->data;
if (iwl_mvm_is_radio_killed(mvm)) {
IWL_DEBUG_DROP(mvm, "Dropping - RF/CT KILL\n");
@@ -315,8 +482,18 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
!test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status))
goto drop;
- if (control->sta) {
- if (iwl_mvm_tx_skb(mvm, skb, control->sta))
+ /* treat non-bufferable MMPDUs as broadcast if sta is sleeping */
+ if (unlikely(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER &&
+ ieee80211_is_mgmt(hdr->frame_control) &&
+ !ieee80211_is_deauth(hdr->frame_control) &&
+ !ieee80211_is_disassoc(hdr->frame_control) &&
+ !ieee80211_is_action(hdr->frame_control)))
+ sta = NULL;
+
+ if (sta) {
+ if (iwl_mvm_defer_tx(mvm, sta, skb))
+ return;
+ if (iwl_mvm_tx_skb(mvm, skb, sta))
goto drop;
return;
}
@@ -328,6 +505,24 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
ieee80211_free_txskb(hw, skb);
}
+static inline bool iwl_enable_rx_ampdu(const struct iwl_cfg *cfg)
+{
+ if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG)
+ return false;
+ return true;
+}
+
+static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg)
+{
+ if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG)
+ return false;
+ if (iwlwifi_mod_params.disable_11n & IWL_ENABLE_HT_TXAGG)
+ return true;
+
+ /* enabled by default */
+ return true;
+}
+
static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action,
@@ -336,6 +531,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
int ret;
+ bool tx_agg_ref = false;
IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n",
sta->addr, tid, action);
@@ -343,11 +539,28 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
if (!(mvm->nvm_data->sku_cap_11n_enable))
return -EACCES;
+ /* return from D0i3 before starting a new Tx aggregation */
+ if (action == IEEE80211_AMPDU_TX_START) {
+ iwl_mvm_ref(mvm, IWL_MVM_REF_TX_AGG);
+ tx_agg_ref = true;
+
+ /*
+ * wait synchronously until D0i3 exit to get the correct
+ * sequence number for the tid
+ */
+ if (!wait_event_timeout(mvm->d0i3_exit_waitq,
+ !test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status), HZ)) {
+ WARN_ON_ONCE(1);
+ iwl_mvm_unref(mvm, IWL_MVM_REF_TX_AGG);
+ return -EIO;
+ }
+ }
+
mutex_lock(&mvm->mutex);
switch (action) {
case IEEE80211_AMPDU_RX_START:
- if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) {
+ if (!iwl_enable_rx_ampdu(mvm->cfg)) {
ret = -EINVAL;
break;
}
@@ -357,7 +570,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false);
break;
case IEEE80211_AMPDU_TX_START:
- if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) {
+ if (!iwl_enable_tx_ampdu(mvm->cfg)) {
ret = -EINVAL;
break;
}
@@ -380,6 +593,13 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
}
mutex_unlock(&mvm->mutex);
+ /*
+ * If the tid is marked as started, we won't use it for offloaded
+ * traffic on the next D0i3 entry. It's safe to unref.
+ */
+ if (tx_agg_ref)
+ iwl_mvm_unref(mvm, IWL_MVM_REF_TX_AGG);
+
return ret;
}
@@ -404,6 +624,15 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
{
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL };
+
+ iwl_mvm_fw_error_dump(mvm);
+
+ /* notify the userspace about the error we had */
+ kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env);
+#endif
+
iwl_trans_stop_device(mvm->trans);
mvm->scan_status = IWL_MVM_SCAN_NONE;
@@ -416,6 +645,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
iwl_mvm_cleanup_iterator, mvm);
mvm->p2p_device_vif = NULL;
+ mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
iwl_mvm_reset_phy_ctxts(mvm);
memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
@@ -423,6 +653,10 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
ieee80211_wake_queues(mvm->hw);
+ /* cleanup all stale references (scan, roc), but keep the
+ * ucode_down ref until reconfig is complete */
+ iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN);
+
mvm->vif_count = 0;
mvm->rx_ba_sessions = 0;
}
@@ -452,11 +686,15 @@ static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw)
mutex_lock(&mvm->mutex);
clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
+ iwl_mvm_d0i3_enable_tx(mvm, NULL);
ret = iwl_mvm_update_quotas(mvm, NULL);
if (ret)
IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n",
ret);
+ /* allow transport/FW low power modes */
+ iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN);
+
mutex_unlock(&mvm->mutex);
}
@@ -464,9 +702,14 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ flush_work(&mvm->d0i3_exit_work);
flush_work(&mvm->async_handlers_wk);
mutex_lock(&mvm->mutex);
+
+ /* disallow low power states when the FW is down */
+ iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
+
/* async_handlers_wk is now blocked */
/*
@@ -492,14 +735,6 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
cancel_work_sync(&mvm->async_handlers_wk);
}
-static void iwl_mvm_power_update_iterator(void *data, u8 *mac,
- struct ieee80211_vif *vif)
-{
- struct iwl_mvm *mvm = data;
-
- iwl_mvm_power_update_mode(mvm, vif);
-}
-
static struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm)
{
u16 i;
@@ -567,7 +802,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
vif->type == NL80211_IFTYPE_ADHOC) {
u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta,
- qmask);
+ qmask,
+ ieee80211_vif_type_p2p(vif));
if (ret) {
IWL_ERR(mvm, "Failed to allocate bcast sta\n");
goto out_release;
@@ -581,10 +817,12 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
if (ret)
goto out_release;
- iwl_mvm_power_disable(mvm, vif);
+ ret = iwl_mvm_power_update_mac(mvm, vif);
+ if (ret)
+ goto out_release;
/* beacon filtering */
- ret = iwl_mvm_disable_beacon_filter(mvm, vif);
+ ret = iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC);
if (ret)
goto out_remove_mac;
@@ -643,11 +881,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
mvm->vif_count--;
- /* TODO: remove this when legacy PM will be discarded */
- ieee80211_iterate_active_interfaces(
- mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
- iwl_mvm_power_update_iterator, mvm);
-
iwl_mvm_mac_ctxt_release(mvm, vif);
out_unlock:
mutex_unlock(&mvm->mutex);
@@ -736,11 +969,7 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
if (mvm->vif_count && vif->type != NL80211_IFTYPE_P2P_DEVICE)
mvm->vif_count--;
- /* TODO: remove this when legacy PM will be discarded */
- ieee80211_iterate_active_interfaces(
- mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
- iwl_mvm_power_update_iterator, mvm);
-
+ iwl_mvm_power_update_mac(mvm, vif);
iwl_mvm_mac_ctxt_remove(mvm, vif);
out_release:
@@ -858,6 +1087,156 @@ out:
*total_flags = 0;
}
+#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
+struct iwl_bcast_iter_data {
+ struct iwl_mvm *mvm;
+ struct iwl_bcast_filter_cmd *cmd;
+ u8 current_filter;
+};
+
+static void
+iwl_mvm_set_bcast_filter(struct ieee80211_vif *vif,
+ const struct iwl_fw_bcast_filter *in_filter,
+ struct iwl_fw_bcast_filter *out_filter)
+{
+ struct iwl_fw_bcast_filter_attr *attr;
+ int i;
+
+ memcpy(out_filter, in_filter, sizeof(*out_filter));
+
+ for (i = 0; i < ARRAY_SIZE(out_filter->attrs); i++) {
+ attr = &out_filter->attrs[i];
+
+ if (!attr->mask)
+ break;
+
+ switch (attr->reserved1) {
+ case cpu_to_le16(BC_FILTER_MAGIC_IP):
+ if (vif->bss_conf.arp_addr_cnt != 1) {
+ attr->mask = 0;
+ continue;
+ }
+
+ attr->val = vif->bss_conf.arp_addr_list[0];
+ break;
+ case cpu_to_le16(BC_FILTER_MAGIC_MAC):
+ attr->val = *(__be32 *)&vif->addr[2];
+ break;
+ default:
+ break;
+ }
+ attr->reserved1 = 0;
+ out_filter->num_attrs++;
+ }
+}
+
+static void iwl_mvm_bcast_filter_iterator(void *_data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_bcast_iter_data *data = _data;
+ struct iwl_mvm *mvm = data->mvm;
+ struct iwl_bcast_filter_cmd *cmd = data->cmd;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_fw_bcast_mac *bcast_mac;
+ int i;
+
+ if (WARN_ON(mvmvif->id >= ARRAY_SIZE(cmd->macs)))
+ return;
+
+ bcast_mac = &cmd->macs[mvmvif->id];
+
+ /* enable filtering only for associated stations */
+ if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc)
+ return;
+
+ bcast_mac->default_discard = 1;
+
+ /* copy all configured filters */
+ for (i = 0; mvm->bcast_filters[i].attrs[0].mask; i++) {
+ /*
+ * Make sure we don't exceed our filters limit.
+ * if there is still a valid filter to be configured,
+ * be on the safe side and just allow bcast for this mac.
+ */
+ if (WARN_ON_ONCE(data->current_filter >=
+ ARRAY_SIZE(cmd->filters))) {
+ bcast_mac->default_discard = 0;
+ bcast_mac->attached_filters = 0;
+ break;
+ }
+
+ iwl_mvm_set_bcast_filter(vif,
+ &mvm->bcast_filters[i],
+ &cmd->filters[data->current_filter]);
+
+ /* skip current filter if it contains no attributes */
+ if (!cmd->filters[data->current_filter].num_attrs)
+ continue;
+
+ /* attach the filter to current mac */
+ bcast_mac->attached_filters |=
+ cpu_to_le16(BIT(data->current_filter));
+
+ data->current_filter++;
+ }
+}
+
+bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm,
+ struct iwl_bcast_filter_cmd *cmd)
+{
+ struct iwl_bcast_iter_data iter_data = {
+ .mvm = mvm,
+ .cmd = cmd,
+ };
+
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->max_bcast_filters = ARRAY_SIZE(cmd->filters);
+ cmd->max_macs = ARRAY_SIZE(cmd->macs);
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ /* use debugfs filters/macs if override is configured */
+ if (mvm->dbgfs_bcast_filtering.override) {
+ memcpy(cmd->filters, &mvm->dbgfs_bcast_filtering.cmd.filters,
+ sizeof(cmd->filters));
+ memcpy(cmd->macs, &mvm->dbgfs_bcast_filtering.cmd.macs,
+ sizeof(cmd->macs));
+ return true;
+ }
+#endif
+
+ /* if no filters are configured, do nothing */
+ if (!mvm->bcast_filters)
+ return false;
+
+ /* configure and attach these filters for each associated sta vif */
+ ieee80211_iterate_active_interfaces(
+ mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_bcast_filter_iterator, &iter_data);
+
+ return true;
+}
+static int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_bcast_filter_cmd cmd;
+
+ if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING))
+ return 0;
+
+ if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
+ return 0;
+
+ return iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, CMD_SYNC,
+ sizeof(cmd), &cmd);
+}
+#else
+static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
+{
+ return 0;
+}
+#endif
+
static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@@ -910,6 +1289,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
iwl_mvm_sf_update(mvm, vif, false);
iwl_mvm_power_vif_assoc(mvm, vif);
+ if (vif->p2p)
+ iwl_mvm_ref(mvm, IWL_MVM_REF_P2P_CLIENT);
} else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
/*
* If update fails - SF might be running in associated
@@ -922,27 +1303,25 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id);
if (ret)
IWL_ERR(mvm, "failed to remove AP station\n");
+
+ if (mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id)
+ mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
/* remove quota for this interface */
ret = iwl_mvm_update_quotas(mvm, NULL);
if (ret)
IWL_ERR(mvm, "failed to update quotas\n");
+
+ if (vif->p2p)
+ iwl_mvm_unref(mvm, IWL_MVM_REF_P2P_CLIENT);
}
iwl_mvm_recalc_multicast(mvm);
+ iwl_mvm_configure_bcast_filter(mvm, vif);
/* reset rssi values */
mvmvif->bf_data.ave_beacon_signal = 0;
- if (!(mvm->fw->ucode_capa.flags &
- IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) {
- /* Workaround for FW bug, otherwise FW disables device
- * power save upon disassociation
- */
- ret = iwl_mvm_power_update_mode(mvm, vif);
- if (ret)
- IWL_ERR(mvm, "failed to update power mode\n");
- }
iwl_mvm_bt_coex_vif_change(mvm);
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT,
IEEE80211_SMPS_AUTOMATIC);
@@ -953,9 +1332,10 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
*/
iwl_mvm_remove_time_event(mvm, mvmvif,
&mvmvif->time_event_data);
+ WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, CMD_SYNC));
} else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS |
BSS_CHANGED_QOS)) {
- ret = iwl_mvm_power_update_mode(mvm, vif);
+ ret = iwl_mvm_power_update_mac(mvm, vif);
if (ret)
IWL_ERR(mvm, "failed to update power mode\n");
}
@@ -969,10 +1349,15 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
IWL_DEBUG_MAC80211(mvm, "cqm info_changed");
/* reset cqm events tracking */
mvmvif->bf_data.last_cqm_event = 0;
- ret = iwl_mvm_update_beacon_filter(mvm, vif);
+ ret = iwl_mvm_update_beacon_filter(mvm, vif, false, CMD_SYNC);
if (ret)
IWL_ERR(mvm, "failed to update CQM thresholds\n");
}
+
+ if (changes & BSS_CHANGED_ARP_FILTER) {
+ IWL_DEBUG_MAC80211(mvm, "arp filter changed");
+ iwl_mvm_configure_bcast_filter(mvm, vif);
+ }
}
static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
@@ -1006,8 +1391,6 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
if (ret)
goto out_remove;
- mvmvif->ap_ibss_active = true;
-
/* Send the bcast station. At this stage the TBTT and DTIM time events
* are added and applied to the scheduler */
ret = iwl_mvm_send_bcast_sta(mvm, vif, &mvmvif->bcast_sta);
@@ -1018,8 +1401,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
mvmvif->ap_ibss_active = true;
/* power updated needs to be done before quotas */
- mvm->bound_vif_cnt++;
- iwl_mvm_power_update_binding(mvm, vif, true);
+ iwl_mvm_power_update_mac(mvm, vif);
ret = iwl_mvm_update_quotas(mvm, vif);
if (ret)
@@ -1029,14 +1411,15 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
if (vif->p2p && mvm->p2p_device_vif)
iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif);
+ iwl_mvm_ref(mvm, IWL_MVM_REF_AP_IBSS);
+
iwl_mvm_bt_coex_vif_change(mvm);
mutex_unlock(&mvm->mutex);
return 0;
out_quota_failed:
- mvm->bound_vif_cnt--;
- iwl_mvm_power_update_binding(mvm, vif, false);
+ iwl_mvm_power_update_mac(mvm, vif);
mvmvif->ap_ibss_active = false;
iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
out_unbind:
@@ -1062,6 +1445,8 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
iwl_mvm_bt_coex_vif_change(mvm);
+ iwl_mvm_unref(mvm, IWL_MVM_REF_AP_IBSS);
+
/* Need to update the P2P Device MAC (only GO, IBSS is single vif) */
if (vif->p2p && mvm->p2p_device_vif)
iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif);
@@ -1070,8 +1455,7 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
iwl_mvm_binding_remove_vif(mvm, vif);
- mvm->bound_vif_cnt--;
- iwl_mvm_power_update_binding(mvm, vif, false);
+ iwl_mvm_power_update_mac(mvm, vif);
iwl_mvm_mac_ctxt_remove(mvm, vif);
@@ -1085,26 +1469,20 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
u32 changes)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- enum ieee80211_bss_change ht_change = BSS_CHANGED_ERP_CTS_PROT |
- BSS_CHANGED_HT |
- BSS_CHANGED_BANDWIDTH;
- int ret;
/* Changes will be applied when the AP/IBSS is started */
if (!mvmvif->ap_ibss_active)
return;
- if (changes & ht_change) {
- ret = iwl_mvm_mac_ctxt_changed(mvm, vif);
- if (ret)
- IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
- }
+ if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT |
+ BSS_CHANGED_BANDWIDTH) &&
+ iwl_mvm_mac_ctxt_changed(mvm, vif))
+ IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
/* Need to send a new beacon template to the FW */
- if (changes & BSS_CHANGED_BEACON) {
- if (iwl_mvm_mac_ctxt_beacon_changed(mvm, vif))
- IWL_WARN(mvm, "Failed updating beacon data\n");
- }
+ if (changes & BSS_CHANGED_BEACON &&
+ iwl_mvm_mac_ctxt_beacon_changed(mvm, vif))
+ IWL_WARN(mvm, "Failed updating beacon data\n");
}
static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
@@ -1144,13 +1522,30 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
mutex_lock(&mvm->mutex);
- if (mvm->scan_status == IWL_MVM_SCAN_NONE)
- ret = iwl_mvm_scan_request(mvm, vif, req);
- else
+ switch (mvm->scan_status) {
+ case IWL_MVM_SCAN_SCHED:
+ ret = iwl_mvm_sched_scan_stop(mvm);
+ if (ret) {
+ ret = -EBUSY;
+ goto out;
+ }
+ break;
+ case IWL_MVM_SCAN_NONE:
+ break;
+ default:
ret = -EBUSY;
+ goto out;
+ }
- mutex_unlock(&mvm->mutex);
+ iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN);
+ ret = iwl_mvm_scan_request(mvm, vif, req);
+ if (ret)
+ iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
+out:
+ mutex_unlock(&mvm->mutex);
+ /* make sure to flush the Rx handler before the next scan arrives */
+ iwl_mvm_wait_for_async_handlers(mvm);
return ret;
}
@@ -1168,20 +1563,32 @@ static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw,
static void
iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw,
- struct ieee80211_sta *sta, u16 tid,
+ struct ieee80211_sta *sta, u16 tids,
int num_frames,
enum ieee80211_frame_release_type reason,
bool more_data)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
- /* TODO: how do we tell the fw to send frames for a specific TID */
+ /* Called when we need to transmit (a) frame(s) from mac80211 */
- /*
- * The fw will send EOSP notification when the last frame will be
- * transmitted.
- */
- iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames);
+ iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames,
+ tids, more_data, false);
+}
+
+static void
+iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u16 tids,
+ int num_frames,
+ enum ieee80211_frame_release_type reason,
+ bool more_data)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ /* Called when we need to transmit (a) frame(s) from agg queue */
+
+ iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames,
+ tids, more_data, true);
}
static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
@@ -1191,11 +1598,25 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ int tid;
switch (cmd) {
case STA_NOTIFY_SLEEP:
if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0)
ieee80211_sta_block_awake(hw, sta, true);
+ spin_lock_bh(&mvmsta->lock);
+ for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
+ struct iwl_mvm_tid_data *tid_data;
+
+ tid_data = &mvmsta->tid_data[tid];
+ if (tid_data->state != IWL_AGG_ON &&
+ tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA)
+ continue;
+ if (iwl_mvm_tid_queued(tid_data) == 0)
+ continue;
+ ieee80211_sta_set_buffered(sta, tid, true);
+ }
+ spin_unlock_bh(&mvmsta->lock);
/*
* The fw updates the STA to be asleep. Tx packets on the Tx
* queues to this station will not be transmitted. The fw will
@@ -1286,12 +1707,14 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
} else if (old_state == IEEE80211_STA_ASSOC &&
new_state == IEEE80211_STA_AUTHORIZED) {
/* enable beacon filtering */
- WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif));
+ if (vif->bss_conf.dtim_period)
+ WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif,
+ CMD_SYNC));
ret = 0;
} else if (old_state == IEEE80211_STA_AUTHORIZED &&
new_state == IEEE80211_STA_ASSOC) {
/* disable beacon filtering */
- WARN_ON(iwl_mvm_disable_beacon_filter(mvm, vif));
+ WARN_ON(iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC));
ret = 0;
} else if (old_state == IEEE80211_STA_ASSOC &&
new_state == IEEE80211_STA_AUTH) {
@@ -1383,9 +1806,26 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
mutex_lock(&mvm->mutex);
- if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
- IWL_DEBUG_SCAN(mvm,
- "SCHED SCAN request during internal scan - abort\n");
+ switch (mvm->scan_status) {
+ case IWL_MVM_SCAN_OS:
+ IWL_DEBUG_SCAN(mvm, "Stopping previous scan for sched_scan\n");
+ ret = iwl_mvm_cancel_scan(mvm);
+ if (ret) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /*
+ * iwl_mvm_rx_scan_complete() will be called soon but will
+ * not reset the scan status as it won't be IWL_MVM_SCAN_OS
+ * any more since we queue the next scan immediately (below).
+ * We make sure it is called before the next scan starts by
+ * flushing the async-handlers work.
+ */
+ break;
+ case IWL_MVM_SCAN_NONE:
+ break;
+ default:
ret = -EBUSY;
goto out;
}
@@ -1407,17 +1847,23 @@ err:
mvm->scan_status = IWL_MVM_SCAN_NONE;
out:
mutex_unlock(&mvm->mutex);
+ /* make sure to flush the Rx handler before the next scan arrives */
+ iwl_mvm_wait_for_async_handlers(mvm);
return ret;
}
-static void iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
+static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ int ret;
mutex_lock(&mvm->mutex);
- iwl_mvm_sched_scan_stop(mvm);
+ ret = iwl_mvm_sched_scan_stop(mvm);
mutex_unlock(&mvm->mutex);
+ iwl_mvm_wait_for_async_handlers(mvm);
+
+ return ret;
}
static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
@@ -1755,8 +2201,7 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
* Power state must be updated before quotas,
* otherwise fw will complain.
*/
- mvm->bound_vif_cnt++;
- iwl_mvm_power_update_binding(mvm, vif, true);
+ iwl_mvm_power_update_mac(mvm, vif);
/* Setting the quota at this stage is only required for monitor
* interfaces. For the other types, the bss_info changed flow
@@ -1773,8 +2218,7 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
out_remove_binding:
iwl_mvm_binding_remove_vif(mvm, vif);
- mvm->bound_vif_cnt--;
- iwl_mvm_power_update_binding(mvm, vif, false);
+ iwl_mvm_power_update_mac(mvm, vif);
out_unlock:
mutex_unlock(&mvm->mutex);
if (ret)
@@ -1806,8 +2250,7 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
}
iwl_mvm_binding_remove_vif(mvm, vif);
- mvm->bound_vif_cnt--;
- iwl_mvm_power_update_binding(mvm, vif, false);
+ iwl_mvm_power_update_mac(mvm, vif);
out_unlock:
mvmvif->phy_ctxt = NULL;
@@ -1874,8 +2317,9 @@ static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm,
return -EINVAL;
if (nla_get_u32(tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE]))
- return iwl_mvm_enable_beacon_filter(mvm, vif);
- return iwl_mvm_disable_beacon_filter(mvm, vif);
+ return iwl_mvm_enable_beacon_filter(mvm, vif,
+ CMD_SYNC);
+ return iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC);
}
return -EOPNOTSUPP;
@@ -1896,7 +2340,7 @@ static int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw,
}
#endif
-struct ieee80211_ops iwl_mvm_hw_ops = {
+const struct ieee80211_ops iwl_mvm_hw_ops = {
.tx = iwl_mvm_mac_tx,
.ampdu_action = iwl_mvm_mac_ampdu_action,
.start = iwl_mvm_mac_start,
@@ -1914,6 +2358,7 @@ struct ieee80211_ops iwl_mvm_hw_ops = {
.sta_state = iwl_mvm_mac_sta_state,
.sta_notify = iwl_mvm_mac_sta_notify,
.allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames,
+ .release_buffered_frames = iwl_mvm_mac_release_buffered_frames,
.set_rts_threshold = iwl_mvm_mac_set_rts_threshold,
.sta_rc_update = iwl_mvm_sta_rc_update,
.conf_tx = iwl_mvm_mac_conf_tx,
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index e4ead86f06d6..d564233a65da 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -91,9 +91,7 @@ enum iwl_mvm_tx_fifo {
IWL_MVM_TX_FIFO_MCAST = 5,
};
-extern struct ieee80211_ops iwl_mvm_hw_ops;
-extern const struct iwl_mvm_power_ops pm_legacy_ops;
-extern const struct iwl_mvm_power_ops pm_mac_ops;
+extern const struct ieee80211_ops iwl_mvm_hw_ops;
/**
* struct iwl_mvm_mod_params - module parameters for iwlmvm
@@ -152,27 +150,13 @@ enum iwl_power_scheme {
IWL_POWER_SCHEME_LP
};
-#define IWL_CONN_MAX_LISTEN_INTERVAL 70
+#define IWL_CONN_MAX_LISTEN_INTERVAL 10
#define IWL_UAPSD_AC_INFO (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\
IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\
IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\
IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
#define IWL_UAPSD_MAX_SP IEEE80211_WMM_IE_STA_QOSINFO_SP_2
-struct iwl_mvm_power_ops {
- int (*power_update_mode)(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif);
- int (*power_update_device_mode)(struct iwl_mvm *mvm);
- int (*power_disable)(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
- void (*power_update_binding)(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif, bool assign);
-#ifdef CONFIG_IWLWIFI_DEBUGFS
- int (*power_dbgfs_read)(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- char *buf, int bufsz);
-#endif
-};
-
-
#ifdef CONFIG_IWLWIFI_DEBUGFS
enum iwl_dbgfs_pm_mask {
MVM_DEBUGFS_PM_KEEP_ALIVE = BIT(0),
@@ -239,6 +223,19 @@ enum iwl_mvm_smps_type_request {
NUM_IWL_MVM_SMPS_REQ,
};
+enum iwl_mvm_ref_type {
+ IWL_MVM_REF_UCODE_DOWN,
+ IWL_MVM_REF_SCAN,
+ IWL_MVM_REF_ROC,
+ IWL_MVM_REF_P2P_CLIENT,
+ IWL_MVM_REF_AP_IBSS,
+ IWL_MVM_REF_USER,
+ IWL_MVM_REF_TX,
+ IWL_MVM_REF_TX_AGG,
+
+ IWL_MVM_REF_COUNT,
+};
+
/**
* struct iwl_mvm_vif_bf_data - beacon filtering related data
* @bf_enabled: indicates if beacon filtering is enabled
@@ -269,7 +266,9 @@ struct iwl_mvm_vif_bf_data {
* @ap_ibss_active: indicates that AP/IBSS is configured and that the interface
* should get quota etc.
* @monitor_active: indicates that monitor context is configured, and that the
- * interface should get quota etc.
+ * interface should get quota etc.
+ * @low_latency: indicates that this interface is in low-latency mode
+ * (VMACLowLatencyMode)
* @queue_params: QoS params for this MAC
* @bcast_sta: station used for broadcast packets. Used by the following
* vifs: P2P_DEVICE, GO and AP.
@@ -285,6 +284,7 @@ struct iwl_mvm_vif {
bool uploaded;
bool ap_ibss_active;
bool monitor_active;
+ bool low_latency;
struct iwl_mvm_vif_bf_data bf_data;
u32 ap_beacon_time;
@@ -319,13 +319,13 @@ struct iwl_mvm_vif {
bool seqno_valid;
u16 seqno;
+#endif
#if IS_ENABLED(CONFIG_IPV6)
/* IPv6 addresses for WoWLAN */
struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX];
int num_target_ipv6_addrs;
#endif
-#endif
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct iwl_mvm *mvm;
@@ -333,14 +333,13 @@ struct iwl_mvm_vif {
struct dentry *dbgfs_slink;
struct iwl_dbgfs_pm dbgfs_pm;
struct iwl_dbgfs_bf dbgfs_bf;
+ struct iwl_mac_power_cmd mac_pwr_cmd;
#endif
enum ieee80211_smps_mode smps_requests[NUM_IWL_MVM_SMPS_REQ];
/* FW identified misbehaving AP */
u8 uapsd_misbehaving_bssid[ETH_ALEN];
-
- bool pm_prevented;
};
static inline struct iwl_mvm_vif *
@@ -349,6 +348,8 @@ iwl_mvm_vif_from_mac80211(struct ieee80211_vif *vif)
return (void *)vif->drv_priv;
}
+extern const u8 tid_to_mac80211_ac[];
+
enum iwl_scan_status {
IWL_MVM_SCAN_NONE,
IWL_MVM_SCAN_OS,
@@ -415,6 +416,7 @@ struct iwl_tt_params {
* @ct_kill_exit: worker to exit thermal kill
* @dynamic_smps: Is thermal throttling enabled dynamic_smps?
* @tx_backoff: The current thremal throttling tx backoff in uSec.
+ * @min_backoff: The minimal tx backoff due to power restrictions
* @params: Parameters to configure the thermal throttling algorithm.
* @throttle: Is thermal throttling is active?
*/
@@ -422,10 +424,33 @@ struct iwl_mvm_tt_mgmt {
struct delayed_work ct_kill_exit;
bool dynamic_smps;
u32 tx_backoff;
+ u32 min_backoff;
const struct iwl_tt_params *params;
bool throttle;
};
+#define IWL_MVM_NUM_LAST_FRAMES_UCODE_RATES 8
+
+struct iwl_mvm_frame_stats {
+ u32 legacy_frames;
+ u32 ht_frames;
+ u32 vht_frames;
+ u32 bw_20_frames;
+ u32 bw_40_frames;
+ u32 bw_80_frames;
+ u32 bw_160_frames;
+ u32 sgi_frames;
+ u32 ngi_frames;
+ u32 siso_frames;
+ u32 mimo2_frames;
+ u32 agg_frames;
+ u32 ampdu_count;
+ u32 success_frames;
+ u32 fail_frames;
+ u32 last_rates[IWL_MVM_NUM_LAST_FRAMES_UCODE_RATES];
+ int last_frame_idx;
+};
+
struct iwl_mvm {
/* for logger access */
struct device *dev;
@@ -457,6 +482,8 @@ struct iwl_mvm {
bool init_ucode_complete;
u32 error_event_table;
u32 log_event_table;
+ u32 umac_error_event_table;
+ bool support_umac_log;
u32 ampdu_ref;
@@ -470,7 +497,7 @@ struct iwl_mvm {
struct iwl_nvm_data *nvm_data;
/* NVM sections */
- struct iwl_nvm_section nvm_sections[NVM_NUM_OF_SECTIONS];
+ struct iwl_nvm_section nvm_sections[NVM_MAX_NUM_SECTIONS];
/* EEPROM MAC addresses */
struct mac_address addresses[IWL_MVM_MAX_ADDRESSES];
@@ -494,6 +521,17 @@ struct iwl_mvm {
/* rx chain antennas set through debugfs for the scan command */
u8 scan_rx_ant;
+#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
+ /* broadcast filters to configure for each associated station */
+ const struct iwl_fw_bcast_filter *bcast_filters;
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ struct {
+ u32 override; /* u32 for debugfs_create_bool */
+ struct iwl_bcast_filter_cmd cmd;
+ } dbgfs_bcast_filtering;
+#endif
+#endif
+
/* Internal station */
struct iwl_mvm_int_sta aux_sta;
@@ -506,6 +544,7 @@ struct iwl_mvm {
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct dentry *debugfs_dir;
u32 dbgfs_sram_offset, dbgfs_sram_len;
+ u32 dbgfs_prph_reg_addr;
bool disable_power_off;
bool disable_power_off_d3;
@@ -513,6 +552,9 @@ struct iwl_mvm {
struct debugfs_blob_wrapper nvm_sw_blob;
struct debugfs_blob_wrapper nvm_calib_blob;
struct debugfs_blob_wrapper nvm_prod_blob;
+
+ struct iwl_mvm_frame_stats drv_rx_stats;
+ spinlock_t drv_stats_lock;
#endif
struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX];
@@ -526,10 +568,16 @@ struct iwl_mvm {
*/
unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)];
+ /* A bitmap of reference types taken by the driver. */
+ unsigned long ref_bitmap[BITS_TO_LONGS(IWL_MVM_REF_COUNT)];
+
u8 vif_count;
/* -1 for always, 0 for never, >0 for that many times */
s8 restart_fw;
+ void *fw_error_dump;
+ void *fw_error_sram;
+ u32 fw_error_sram_len;
struct led_classdev led;
@@ -548,17 +596,27 @@ struct iwl_mvm {
#endif
#endif
+ /* d0i3 */
+ u8 d0i3_ap_sta_id;
+ bool d0i3_offloading;
+ struct work_struct d0i3_exit_work;
+ struct sk_buff_head d0i3_tx;
+ /* sync d0i3_tx queue and IWL_MVM_STATUS_IN_D0I3 status flag */
+ spinlock_t d0i3_tx_lock;
+ wait_queue_head_t d0i3_exit_waitq;
+
/* BT-Coex */
u8 bt_kill_msk;
struct iwl_bt_coex_profile_notif last_bt_notif;
struct iwl_bt_coex_ci_cmd last_bt_ci_cmd;
+ u32 last_ant_isol;
+ u8 last_corun_lut;
+ u8 bt_tx_prio;
/* Thermal Throttling and CTkill */
struct iwl_mvm_tt_mgmt thermal_throttle;
s32 temperature; /* Celsius */
- const struct iwl_mvm_power_ops *pm_ops;
-
#ifdef CONFIG_NL80211_TESTMODE
u32 noa_duration;
struct ieee80211_vif *noa_vif;
@@ -569,10 +627,10 @@ struct iwl_mvm {
u8 first_agg_queue;
u8 last_agg_queue;
- u8 bound_vif_cnt;
-
/* Indicate if device power save is allowed */
- bool ps_prevented;
+ bool ps_disabled;
+ /* Indicate if device power management is allowed */
+ bool pm_disabled;
};
/* Extract MVM priv from op_mode and _hw */
@@ -587,6 +645,7 @@ enum iwl_mvm_status {
IWL_MVM_STATUS_HW_CTKILL,
IWL_MVM_STATUS_ROC_RUNNING,
IWL_MVM_STATUS_IN_HW_RESTART,
+ IWL_MVM_STATUS_IN_D0I3,
};
static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm)
@@ -595,6 +654,30 @@ static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm)
test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status);
}
+static inline struct iwl_mvm_sta *
+iwl_mvm_sta_from_staid_protected(struct iwl_mvm *mvm, u8 sta_id)
+{
+ struct ieee80211_sta *sta;
+
+ if (sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id))
+ return NULL;
+
+ sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
+ lockdep_is_held(&mvm->mutex));
+
+ /* This can happen if the station has been removed right now */
+ if (IS_ERR_OR_NULL(sta))
+ return NULL;
+
+ return iwl_mvm_sta_from_mac80211(sta);
+}
+
+static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm)
+{
+ return mvm->trans->cfg->d0i3 &&
+ (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT);
+}
+
extern const u8 iwl_mvm_ac_to_tx_fifo[];
struct iwl_rate_info {
@@ -619,7 +702,10 @@ void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,
struct ieee80211_tx_rate *r);
u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx);
void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm);
-void iwl_mvm_dump_sram(struct iwl_mvm *mvm);
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);
+void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm);
+#endif
u8 first_antenna(u8 mask);
u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx);
@@ -645,6 +731,11 @@ static inline const char *iwl_mvm_get_tx_fail_reason(u32 status) { return ""; }
int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync);
void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm);
+static inline void iwl_mvm_wait_for_async_handlers(struct iwl_mvm *mvm)
+{
+ flush_work(&mvm->async_handlers_wk);
+}
+
/* Statistics */
int iwl_mvm_rx_reply_statistics(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
@@ -661,6 +752,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm);
int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm);
int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm);
+bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm,
+ struct iwl_bcast_filter_cmd *cmd);
/*
* FW notifications / CMD responses handlers
@@ -676,6 +769,9 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm,
@@ -730,7 +826,7 @@ int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
-void iwl_mvm_cancel_scan(struct iwl_mvm *mvm);
+int iwl_mvm_cancel_scan(struct iwl_mvm *mvm);
/* Scheduled scan */
int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
@@ -744,7 +840,7 @@ int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
struct cfg80211_sched_scan_request *req);
int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
struct cfg80211_sched_scan_request *req);
-void iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm);
+int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm);
int iwl_mvm_rx_sched_scan_results(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
@@ -772,49 +868,24 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
/* rate scaling */
int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init);
+void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm,
+ struct iwl_mvm_frame_stats *stats,
+ u32 rate, bool agg);
+int rs_pretty_print_rate(char *buf, const u32 rate);
-/* power managment */
-static inline int iwl_mvm_power_update_mode(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
-{
- return mvm->pm_ops->power_update_mode(mvm, vif);
-}
-
-static inline int iwl_mvm_power_disable(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
-{
- return mvm->pm_ops->power_disable(mvm, vif);
-}
-
-static inline int iwl_mvm_power_update_device_mode(struct iwl_mvm *mvm)
-{
- if (mvm->pm_ops->power_update_device_mode)
- return mvm->pm_ops->power_update_device_mode(mvm);
- return 0;
-}
+/* power management */
+int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm);
-static inline void iwl_mvm_power_update_binding(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- bool assign)
-{
- if (mvm->pm_ops->power_update_binding)
- mvm->pm_ops->power_update_binding(mvm, vif, assign);
-}
+int iwl_mvm_power_update_device(struct iwl_mvm *mvm);
+int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ char *buf, int bufsz);
void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-static inline int iwl_mvm_power_dbgfs_read(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- char *buf, int bufsz)
-{
- return mvm->pm_ops->power_dbgfs_read(mvm, vif, buf, bufsz);
-}
-#endif
-
int iwl_mvm_leds_init(struct iwl_mvm *mvm);
void iwl_mvm_leds_exit(struct iwl_mvm *mvm);
@@ -840,6 +911,17 @@ iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
}
#endif
+void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta,
+ struct iwl_wowlan_config_cmd_v2 *cmd);
+int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ bool disable_offloading,
+ u32 cmd_flags);
+
+/* D0i3 */
+void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
+void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
+void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq);
/* BT Coex */
int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm);
@@ -850,10 +932,13 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum ieee80211_rssi_event rssi_event);
void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm);
-u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm,
- struct ieee80211_sta *sta);
+u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta);
bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
struct ieee80211_sta *sta);
+u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
+ struct ieee80211_tx_info *info, u8 ac);
+int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable);
enum iwl_bt_kill_msk {
BT_KILL_MSK_DEFAULT,
@@ -875,25 +960,53 @@ iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif,
struct iwl_beacon_filter_cmd *cmd)
{}
#endif
+int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ bool enable, u32 flags);
int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif);
+ struct ieee80211_vif *vif,
+ u32 flags);
int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif);
-int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm,
- struct iwl_beacon_filter_cmd *cmd);
+ struct ieee80211_vif *vif,
+ u32 flags);
int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, bool enable);
int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif);
+ struct ieee80211_vif *vif,
+ bool force,
+ u32 flags);
/* SMPS */
void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum iwl_mvm_smps_type_request req_type,
enum ieee80211_smps_mode smps_request);
+/* Low latency */
+int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ bool value);
+/* get SystemLowLatencyMode - only needed for beacon threshold? */
+bool iwl_mvm_low_latency(struct iwl_mvm *mvm);
+/* get VMACLowLatencyMode */
+static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif)
+{
+ /*
+ * should this consider associated/active/... state?
+ *
+ * Normally low-latency should only be active on interfaces
+ * that are active, but at least with debugfs it can also be
+ * enabled on interfaces that aren't active. However, when
+ * interface aren't active then they aren't added into the
+ * binding, so this has no real impact. For now, just return
+ * the current desired low-latency state.
+ */
+
+ return mvmvif->low_latency;
+}
+
/* Thermal management and CT-kill */
+void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff);
void iwl_mvm_tt_handler(struct iwl_mvm *mvm);
-void iwl_mvm_tt_initialize(struct iwl_mvm *mvm);
+void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff);
void iwl_mvm_tt_exit(struct iwl_mvm *mvm);
void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state);
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c
index 35b71af78d02..cf2d09f53782 100644
--- a/drivers/net/wireless/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c
@@ -67,14 +67,6 @@
#include "iwl-eeprom-read.h"
#include "iwl-nvm-parse.h"
-/* list of NVM sections we are allowed/need to read */
-static const int nvm_to_read[] = {
- NVM_SECTION_TYPE_HW,
- NVM_SECTION_TYPE_SW,
- NVM_SECTION_TYPE_CALIBRATION,
- NVM_SECTION_TYPE_PRODUCTION,
-};
-
/* Default NVM size to read */
#define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024)
#define IWL_MAX_NVM_SECTION_SIZE 7000
@@ -236,24 +228,39 @@ static struct iwl_nvm_data *
iwl_parse_nvm_sections(struct iwl_mvm *mvm)
{
struct iwl_nvm_section *sections = mvm->nvm_sections;
- const __le16 *hw, *sw, *calib;
+ const __le16 *hw, *sw, *calib, *regulatory, *mac_override;
/* Checking for required sections */
- if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
- !mvm->nvm_sections[NVM_SECTION_TYPE_HW].data) {
- IWL_ERR(mvm, "Can't parse empty NVM sections\n");
- return NULL;
+ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+ if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
+ !mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) {
+ IWL_ERR(mvm, "Can't parse empty NVM sections\n");
+ return NULL;
+ }
+ } else {
+ if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
+ !mvm->nvm_sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data ||
+ !mvm->nvm_sections[NVM_SECTION_TYPE_REGULATORY].data) {
+ IWL_ERR(mvm,
+ "Can't parse empty family 8000 NVM sections\n");
+ return NULL;
+ }
}
if (WARN_ON(!mvm->cfg))
return NULL;
- hw = (const __le16 *)sections[NVM_SECTION_TYPE_HW].data;
+ hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data;
sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data;
calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data;
+ regulatory = (const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY].data;
+ mac_override =
+ (const __le16 *)sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data;
+
return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib,
- iwl_fw_valid_tx_ant(mvm->fw),
- iwl_fw_valid_rx_ant(mvm->fw));
+ regulatory, mac_override,
+ mvm->fw->valid_tx_ant,
+ mvm->fw->valid_rx_ant);
}
#define MAX_NVM_FILE_LEN 16384
@@ -293,6 +300,8 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
#define NVM_WORD1_LEN(x) (8 * (x & 0x03FF))
#define NVM_WORD2_ID(x) (x >> 12)
+#define NVM_WORD2_LEN_FAMILY_8000(x) (2 * ((x & 0xFF) << 8 | x >> 8))
+#define NVM_WORD1_ID_FAMILY_8000(x) (x >> 4)
IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n");
@@ -343,8 +352,16 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
break;
}
- section_size = 2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1));
- section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2));
+ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+ section_size =
+ 2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1));
+ section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2));
+ } else {
+ section_size = 2 * NVM_WORD2_LEN_FAMILY_8000(
+ le16_to_cpu(file_sec->word2));
+ section_id = NVM_WORD1_ID_FAMILY_8000(
+ le16_to_cpu(file_sec->word1));
+ }
if (section_size > IWL_MAX_NVM_SECTION_SIZE) {
IWL_ERR(mvm, "ERROR - section too large (%d)\n",
@@ -367,7 +384,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
break;
}
- if (WARN(section_id >= NVM_NUM_OF_SECTIONS,
+ if (WARN(section_id >= NVM_MAX_NUM_SECTIONS,
"Invalid NVM section ID %d\n", section_id)) {
ret = -EINVAL;
break;
@@ -414,6 +431,11 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
{
int ret, i, section;
u8 *nvm_buffer, *temp;
+ int nvm_to_read[NVM_MAX_NUM_SECTIONS];
+ int num_of_sections_to_read;
+
+ if (WARN_ON_ONCE(mvm->cfg->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS))
+ return -EINVAL;
/* load external NVM if configured */
if (iwlwifi_mod_params.nvm_file) {
@@ -422,6 +444,22 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
if (ret)
return ret;
} else {
+ /* list of NVM sections we are allowed/need to read */
+ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+ nvm_to_read[0] = mvm->cfg->nvm_hw_section_num;
+ nvm_to_read[1] = NVM_SECTION_TYPE_SW;
+ nvm_to_read[2] = NVM_SECTION_TYPE_CALIBRATION;
+ nvm_to_read[3] = NVM_SECTION_TYPE_PRODUCTION;
+ num_of_sections_to_read = 4;
+ } else {
+ nvm_to_read[0] = NVM_SECTION_TYPE_SW;
+ nvm_to_read[1] = NVM_SECTION_TYPE_CALIBRATION;
+ nvm_to_read[2] = NVM_SECTION_TYPE_PRODUCTION;
+ nvm_to_read[3] = NVM_SECTION_TYPE_REGULATORY;
+ nvm_to_read[4] = NVM_SECTION_TYPE_MAC_OVERRIDE;
+ num_of_sections_to_read = 5;
+ }
+
/* Read From FW NVM */
IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n");
@@ -430,7 +468,7 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
GFP_KERNEL);
if (!nvm_buffer)
return -ENOMEM;
- for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) {
+ for (i = 0; i < num_of_sections_to_read; i++) {
section = nvm_to_read[i];
/* we override the constness for initial read */
ret = iwl_nvm_read_section(mvm, section, nvm_buffer);
@@ -446,10 +484,6 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
#ifdef CONFIG_IWLWIFI_DEBUGFS
switch (section) {
- case NVM_SECTION_TYPE_HW:
- mvm->nvm_hw_blob.data = temp;
- mvm->nvm_hw_blob.size = ret;
- break;
case NVM_SECTION_TYPE_SW:
mvm->nvm_sw_blob.data = temp;
mvm->nvm_sw_blob.size = ret;
@@ -463,6 +497,11 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
mvm->nvm_prod_blob.size = ret;
break;
default:
+ if (section == mvm->cfg->nvm_hw_section_num) {
+ mvm->nvm_hw_blob.data = temp;
+ mvm->nvm_hw_blob.size = ret;
+ break;
+ }
WARN(1, "section: %d", section);
}
#endif
diff --git a/drivers/net/wireless/iwlwifi/mvm/offloading.c b/drivers/net/wireless/iwlwifi/mvm/offloading.c
new file mode 100644
index 000000000000..9bfb95e89cfb
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/offloading.c
@@ -0,0 +1,215 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2014 Intel 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 full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *****************************************************************************/
+#include <net/ipv6.h>
+#include <net/addrconf.h>
+#include "mvm.h"
+
+void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta,
+ struct iwl_wowlan_config_cmd_v2 *cmd)
+{
+ int i;
+
+ /*
+ * For QoS counters, we store the one to use next, so subtract 0x10
+ * since the uCode will add 0x10 *before* using the value while we
+ * increment after using the value (i.e. store the next value to use).
+ */
+ for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
+ u16 seq = mvm_ap_sta->tid_data[i].seq_number;
+ seq -= 0x10;
+ cmd->qos_seq[i] = cpu_to_le16(seq);
+ }
+}
+
+int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ bool disable_offloading,
+ u32 cmd_flags)
+{
+ union {
+ struct iwl_proto_offload_cmd_v1 v1;
+ struct iwl_proto_offload_cmd_v2 v2;
+ struct iwl_proto_offload_cmd_v3_small v3s;
+ struct iwl_proto_offload_cmd_v3_large v3l;
+ } cmd = {};
+ struct iwl_host_cmd hcmd = {
+ .id = PROT_OFFLOAD_CONFIG_CMD,
+ .flags = cmd_flags,
+ .data[0] = &cmd,
+ .dataflags[0] = IWL_HCMD_DFL_DUP,
+ };
+ struct iwl_proto_offload_cmd_common *common;
+ u32 enabled = 0, size;
+ u32 capa_flags = mvm->fw->ucode_capa.flags;
+#if IS_ENABLED(CONFIG_IPV6)
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ int i;
+
+ if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL ||
+ capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) {
+ struct iwl_ns_config *nsc;
+ struct iwl_targ_addr *addrs;
+ int n_nsc, n_addrs;
+ int c;
+
+ if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) {
+ nsc = cmd.v3s.ns_config;
+ n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S;
+ addrs = cmd.v3s.targ_addrs;
+ n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S;
+ } else {
+ nsc = cmd.v3l.ns_config;
+ n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L;
+ addrs = cmd.v3l.targ_addrs;
+ n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L;
+ }
+
+ if (mvmvif->num_target_ipv6_addrs)
+ enabled |= IWL_D3_PROTO_OFFLOAD_NS;
+
+ /*
+ * For each address we have (and that will fit) fill a target
+ * address struct and combine for NS offload structs with the
+ * solicited node addresses.
+ */
+ for (i = 0, c = 0;
+ i < mvmvif->num_target_ipv6_addrs &&
+ i < n_addrs && c < n_nsc; i++) {
+ struct in6_addr solicited_addr;
+ int j;
+
+ addrconf_addr_solict_mult(&mvmvif->target_ipv6_addrs[i],
+ &solicited_addr);
+ for (j = 0; j < c; j++)
+ if (ipv6_addr_cmp(&nsc[j].dest_ipv6_addr,
+ &solicited_addr) == 0)
+ break;
+ if (j == c)
+ c++;
+ addrs[i].addr = mvmvif->target_ipv6_addrs[i];
+ addrs[i].config_num = cpu_to_le32(j);
+ nsc[j].dest_ipv6_addr = solicited_addr;
+ memcpy(nsc[j].target_mac_addr, vif->addr, ETH_ALEN);
+ }
+
+ if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL)
+ cmd.v3s.num_valid_ipv6_addrs = cpu_to_le32(i);
+ else
+ cmd.v3l.num_valid_ipv6_addrs = cpu_to_le32(i);
+ } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
+ if (mvmvif->num_target_ipv6_addrs) {
+ enabled |= IWL_D3_PROTO_OFFLOAD_NS;
+ memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN);
+ }
+
+ BUILD_BUG_ON(sizeof(cmd.v2.target_ipv6_addr[0]) !=
+ sizeof(mvmvif->target_ipv6_addrs[0]));
+
+ for (i = 0; i < min(mvmvif->num_target_ipv6_addrs,
+ IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2); i++)
+ memcpy(cmd.v2.target_ipv6_addr[i],
+ &mvmvif->target_ipv6_addrs[i],
+ sizeof(cmd.v2.target_ipv6_addr[i]));
+ } else {
+ if (mvmvif->num_target_ipv6_addrs) {
+ enabled |= IWL_D3_PROTO_OFFLOAD_NS;
+ memcpy(cmd.v1.ndp_mac_addr, vif->addr, ETH_ALEN);
+ }
+
+ BUILD_BUG_ON(sizeof(cmd.v1.target_ipv6_addr[0]) !=
+ sizeof(mvmvif->target_ipv6_addrs[0]));
+
+ for (i = 0; i < min(mvmvif->num_target_ipv6_addrs,
+ IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1); i++)
+ memcpy(cmd.v1.target_ipv6_addr[i],
+ &mvmvif->target_ipv6_addrs[i],
+ sizeof(cmd.v1.target_ipv6_addr[i]));
+ }
+#endif
+
+ if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) {
+ common = &cmd.v3s.common;
+ size = sizeof(cmd.v3s);
+ } else if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) {
+ common = &cmd.v3l.common;
+ size = sizeof(cmd.v3l);
+ } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
+ common = &cmd.v2.common;
+ size = sizeof(cmd.v2);
+ } else {
+ common = &cmd.v1.common;
+ size = sizeof(cmd.v1);
+ }
+
+ if (vif->bss_conf.arp_addr_cnt) {
+ enabled |= IWL_D3_PROTO_OFFLOAD_ARP;
+ common->host_ipv4_addr = vif->bss_conf.arp_addr_list[0];
+ memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN);
+ }
+
+ if (!disable_offloading)
+ common->enabled = cpu_to_le32(enabled);
+
+ hcmd.len[0] = size;
+ return iwl_mvm_send_cmd(mvm, &hcmd);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index a3d43de342d7..9545d7fdd4bf 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -61,6 +61,7 @@
*
*****************************************************************************/
#include <linux/module.h>
+#include <linux/vmalloc.h>
#include <net/mac80211.h>
#include "iwl-notif-wait.h"
@@ -78,6 +79,7 @@
#include "iwl-prph.h"
#include "rs.h"
#include "fw-api-scan.h"
+#include "fw-error-dump.h"
#include "time-event.h"
/*
@@ -185,9 +187,10 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)
* (PCIe power is lost before PERST# is asserted), causing ME FW
* to lose ownership and not being able to obtain it back.
*/
- iwl_set_bits_mask_prph(mvm->trans, APMG_PS_CTRL_REG,
- APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
- ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
+ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
+ iwl_set_bits_mask_prph(mvm->trans, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
+ ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
}
struct iwl_rx_handlers {
@@ -219,13 +222,17 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true),
RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, false),
RX_HANDLER(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, true),
+ RX_HANDLER(ANTENNA_COUPLING_NOTIFICATION,
+ iwl_mvm_rx_ant_coupling_notif, true),
RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false),
+ RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, false),
+
RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false),
- RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false),
+ RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, true),
RX_HANDLER(SCAN_OFFLOAD_COMPLETE,
- iwl_mvm_rx_scan_offload_complete_notif, false),
+ iwl_mvm_rx_scan_offload_complete_notif, true),
RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_sched_scan_results,
false),
@@ -242,7 +249,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
#undef RX_HANDLER
#define CMD(x) [x] = #x
-static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
+static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(MVM_ALIVE),
CMD(REPLY_ERROR),
CMD(INIT_COMPLETE_NOTIF),
@@ -284,9 +291,11 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(BEACON_NOTIFICATION),
CMD(BEACON_TEMPLATE_CMD),
CMD(STATISTICS_NOTIFICATION),
+ CMD(EOSP_NOTIFICATION),
CMD(REDUCE_TX_POWER_CMD),
CMD(TX_ANT_CONFIGURATION_CMD),
CMD(D3_CONFIG_CMD),
+ CMD(D0I3_END_CMD),
CMD(PROT_OFFLOAD_CONFIG_CMD),
CMD(OFFLOADS_QUERY_CMD),
CMD(REMOTE_WAKE_CONFIG_CMD),
@@ -309,17 +318,37 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(BT_PROFILE_NOTIFICATION),
CMD(BT_CONFIG),
CMD(MCAST_FILTER_CMD),
+ CMD(BCAST_FILTER_CMD),
CMD(REPLY_SF_CFG_CMD),
CMD(REPLY_BEACON_FILTERING_CMD),
CMD(REPLY_THERMAL_MNG_BACKOFF),
CMD(MAC_PM_POWER_TABLE),
CMD(BT_COEX_CI),
CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION),
+ CMD(ANTENNA_COUPLING_NOTIFICATION),
};
#undef CMD
/* this forward declaration can avoid to export the function */
static void iwl_mvm_async_handlers_wk(struct work_struct *wk);
+static void iwl_mvm_d0i3_exit_work(struct work_struct *wk);
+
+static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg)
+{
+ const struct iwl_pwr_tx_backoff *pwr_tx_backoff = cfg->pwr_tx_backoffs;
+
+ if (!pwr_tx_backoff)
+ return 0;
+
+ while (pwr_tx_backoff->pwr) {
+ if (trans->dflt_pwr_limit >= pwr_tx_backoff->pwr)
+ return pwr_tx_backoff->backoff;
+
+ pwr_tx_backoff++;
+ }
+
+ return 0;
+}
static struct iwl_op_mode *
iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
@@ -333,6 +362,14 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
TX_CMD,
};
int err, scan_size;
+ u32 min_backoff;
+
+ /*
+ * We use IWL_MVM_STATION_COUNT to check the validity of the station
+ * index all over the driver - check that its value corresponds to the
+ * array size.
+ */
+ BUILD_BUG_ON(ARRAY_SIZE(mvm->fw_id_to_mac_id) != IWL_MVM_STATION_COUNT);
/********************************
* 1. Allocating and configuring HW data
@@ -373,6 +410,11 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk);
INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk);
INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk);
+ INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work);
+
+ spin_lock_init(&mvm->d0i3_tx_lock);
+ skb_queue_head_init(&mvm->d0i3_tx);
+ init_waitqueue_head(&mvm->d0i3_exit_waitq);
SET_IEEE80211_DEV(mvm->hw, mvm->trans->dev);
@@ -421,7 +463,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
IWL_INFO(mvm, "Detected %s, REV=0x%X\n",
mvm->cfg->name, mvm->trans->hw_rev);
- iwl_mvm_tt_initialize(mvm);
+ min_backoff = calc_min_backoff(trans, cfg);
+ iwl_mvm_tt_initialize(mvm, min_backoff);
/*
* If the NVM exists in an external file,
@@ -462,13 +505,11 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
if (err)
goto out_unregister;
- if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)
- mvm->pm_ops = &pm_mac_ops;
- else
- mvm->pm_ops = &pm_legacy_ops;
-
memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx));
+ /* rpm starts with a taken ref. only set the appropriate bit here. */
+ set_bit(IWL_MVM_REF_UCODE_DOWN, mvm->ref_bitmap);
+
return op_mode;
out_unregister:
@@ -495,6 +536,8 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
ieee80211_unregister_hw(mvm->hw);
kfree(mvm->scan_cmd);
+ vfree(mvm->fw_error_dump);
+ kfree(mvm->fw_error_sram);
kfree(mvm->mcast_filter_cmd);
mvm->mcast_filter_cmd = NULL;
@@ -508,7 +551,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
mvm->phy_db = NULL;
iwl_free_nvm_data(mvm->nvm_data);
- for (i = 0; i < NVM_NUM_OF_SECTIONS; i++)
+ for (i = 0; i < NVM_MAX_NUM_SECTIONS; i++)
kfree(mvm->nvm_sections[i].data);
ieee80211_free_hw(mvm->hw);
@@ -658,7 +701,7 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state)
wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm));
}
-static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
+static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
{
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
@@ -667,9 +710,9 @@ static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
else
clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status);
- if (state && mvm->cur_ucode != IWL_UCODE_INIT)
- iwl_trans_stop_device(mvm->trans);
wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm));
+
+ return state && mvm->cur_ucode != IWL_UCODE_INIT;
}
static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
@@ -703,6 +746,29 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm)
iwl_abort_notification_waits(&mvm->notif_wait);
/*
+ * This is a bit racy, but worst case we tell mac80211 about
+ * a stopped/aborted scan when that was already done which
+ * is not a problem. It is necessary to abort any os scan
+ * here because mac80211 requires having the scan cleared
+ * before restarting.
+ * We'll reset the scan_status to NONE in restart cleanup in
+ * the next start() call from mac80211. If restart isn't called
+ * (no fw restart) scan status will stay busy.
+ */
+ switch (mvm->scan_status) {
+ case IWL_MVM_SCAN_NONE:
+ break;
+ case IWL_MVM_SCAN_OS:
+ ieee80211_scan_completed(mvm->hw, true);
+ break;
+ case IWL_MVM_SCAN_SCHED:
+ /* Sched scan will be restarted by mac80211 in restart_hw. */
+ if (!mvm->restart_fw)
+ ieee80211_sched_scan_stopped(mvm->hw);
+ break;
+ }
+
+ /*
* If we're restarting already, don't cycle restarts.
* If INIT fw asserted, it will likely fail again.
* If WoWLAN fw asserted, don't restart either, mac80211
@@ -733,25 +799,8 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm)
INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk);
schedule_work(&reprobe->work);
} else if (mvm->cur_ucode == IWL_UCODE_REGULAR && mvm->restart_fw) {
- /*
- * This is a bit racy, but worst case we tell mac80211 about
- * a stopped/aborted (sched) scan when that was already done
- * which is not a problem. It is necessary to abort any scan
- * here because mac80211 requires having the scan cleared
- * before restarting.
- * We'll reset the scan_status to NONE in restart cleanup in
- * the next start() call from mac80211.
- */
- switch (mvm->scan_status) {
- case IWL_MVM_SCAN_NONE:
- break;
- case IWL_MVM_SCAN_OS:
- ieee80211_scan_completed(mvm->hw, true);
- break;
- case IWL_MVM_SCAN_SCHED:
- ieee80211_sched_scan_stopped(mvm->hw);
- break;
- }
+ /* don't let the transport/FW power down */
+ iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
if (mvm->restart_fw > 0)
mvm->restart_fw--;
@@ -759,13 +808,52 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm)
}
}
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
+{
+ struct iwl_fw_error_dump_file *dump_file;
+ struct iwl_fw_error_dump_data *dump_data;
+ u32 file_len;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (mvm->fw_error_dump)
+ return;
+
+ file_len = mvm->fw_error_sram_len +
+ sizeof(*dump_file) +
+ sizeof(*dump_data);
+
+ dump_file = vmalloc(file_len);
+ if (!dump_file)
+ return;
+
+ mvm->fw_error_dump = dump_file;
+
+ dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER);
+ dump_file->file_len = cpu_to_le32(file_len);
+ dump_data = (void *)dump_file->data;
+ dump_data->type = IWL_FW_ERROR_DUMP_SRAM;
+ dump_data->len = cpu_to_le32(mvm->fw_error_sram_len);
+
+ /*
+ * No need for lock since at the stage the FW isn't loaded. So it
+ * can't assert - we are the only one who can possibly be accessing
+ * mvm->fw_error_sram right now.
+ */
+ memcpy(dump_data->data, mvm->fw_error_sram, mvm->fw_error_sram_len);
+}
+#endif
+
static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode)
{
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
iwl_mvm_dump_nic_error_log(mvm);
- if (!mvm->restart_fw)
- iwl_mvm_dump_sram(mvm);
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ iwl_mvm_fw_error_sram_dump(mvm);
+#endif
iwl_mvm_nic_restart(mvm);
}
@@ -778,6 +866,323 @@ static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode)
iwl_mvm_nic_restart(mvm);
}
+struct iwl_d0i3_iter_data {
+ struct iwl_mvm *mvm;
+ u8 ap_sta_id;
+ u8 vif_count;
+ u8 offloading_tid;
+ bool disable_offloading;
+};
+
+static bool iwl_mvm_disallow_offloading(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct iwl_d0i3_iter_data *iter_data)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct ieee80211_sta *ap_sta;
+ struct iwl_mvm_sta *mvmsta;
+ u32 available_tids = 0;
+ u8 tid;
+
+ if (WARN_ON(vif->type != NL80211_IFTYPE_STATION ||
+ mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT))
+ return false;
+
+ ap_sta = rcu_dereference(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id]);
+ if (IS_ERR_OR_NULL(ap_sta))
+ return false;
+
+ mvmsta = iwl_mvm_sta_from_mac80211(ap_sta);
+ spin_lock_bh(&mvmsta->lock);
+ for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
+ struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
+
+ /*
+ * in case of pending tx packets, don't use this tid
+ * for offloading in order to prevent reuse of the same
+ * qos seq counters.
+ */
+ if (iwl_mvm_tid_queued(tid_data))
+ continue;
+
+ if (tid_data->state != IWL_AGG_OFF)
+ continue;
+
+ available_tids |= BIT(tid);
+ }
+ spin_unlock_bh(&mvmsta->lock);
+
+ /*
+ * disallow protocol offloading if we have no available tid
+ * (with no pending frames and no active aggregation,
+ * as we don't handle "holes" properly - the scheduler needs the
+ * frame's seq number and TFD index to match)
+ */
+ if (!available_tids)
+ return true;
+
+ /* for simplicity, just use the first available tid */
+ iter_data->offloading_tid = ffs(available_tids) - 1;
+ return false;
+}
+
+static void iwl_mvm_enter_d0i3_iterator(void *_data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_d0i3_iter_data *data = _data;
+ struct iwl_mvm *mvm = data->mvm;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE;
+
+ IWL_DEBUG_RPM(mvm, "entering D0i3 - vif %pM\n", vif->addr);
+ if (vif->type != NL80211_IFTYPE_STATION ||
+ !vif->bss_conf.assoc)
+ return;
+
+ /*
+ * in case of pending tx packets or active aggregations,
+ * avoid offloading features in order to prevent reuse of
+ * the same qos seq counters.
+ */
+ if (iwl_mvm_disallow_offloading(mvm, vif, data))
+ data->disable_offloading = true;
+
+ iwl_mvm_update_d0i3_power_mode(mvm, vif, true, flags);
+ iwl_mvm_send_proto_offload(mvm, vif, data->disable_offloading, flags);
+
+ /*
+ * on init/association, mvm already configures POWER_TABLE_CMD
+ * and REPLY_MCAST_FILTER_CMD, so currently don't
+ * reconfigure them (we might want to use different
+ * params later on, though).
+ */
+ data->ap_sta_id = mvmvif->ap_sta_id;
+ data->vif_count++;
+}
+
+static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm,
+ struct iwl_wowlan_config_cmd_v3 *cmd,
+ struct iwl_d0i3_iter_data *iter_data)
+{
+ struct ieee80211_sta *ap_sta;
+ struct iwl_mvm_sta *mvm_ap_sta;
+
+ if (iter_data->ap_sta_id == IWL_MVM_STATION_COUNT)
+ return;
+
+ rcu_read_lock();
+
+ ap_sta = rcu_dereference(mvm->fw_id_to_mac_id[iter_data->ap_sta_id]);
+ if (IS_ERR_OR_NULL(ap_sta))
+ goto out;
+
+ mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta);
+ cmd->common.is_11n_connection = ap_sta->ht_cap.ht_supported;
+ cmd->offloading_tid = iter_data->offloading_tid;
+
+ /*
+ * The d0i3 uCode takes care of the nonqos counters,
+ * so configure only the qos seq ones.
+ */
+ iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &cmd->common);
+out:
+ rcu_read_unlock();
+}
+static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)
+{
+ struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+ u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE;
+ int ret;
+ struct iwl_d0i3_iter_data d0i3_iter_data = {
+ .mvm = mvm,
+ };
+ struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {
+ .common = {
+ .wakeup_filter =
+ cpu_to_le32(IWL_WOWLAN_WAKEUP_RX_FRAME |
+ IWL_WOWLAN_WAKEUP_BEACON_MISS |
+ IWL_WOWLAN_WAKEUP_LINK_CHANGE |
+ IWL_WOWLAN_WAKEUP_BCN_FILTERING),
+ },
+ };
+ struct iwl_d3_manager_config d3_cfg_cmd = {
+ .min_sleep_time = cpu_to_le32(1000),
+ };
+
+ IWL_DEBUG_RPM(mvm, "MVM entering D0i3\n");
+
+ /* make sure we have no running tx while configuring the qos */
+ set_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status);
+ synchronize_net();
+
+ ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_enter_d0i3_iterator,
+ &d0i3_iter_data);
+ if (d0i3_iter_data.vif_count == 1) {
+ mvm->d0i3_ap_sta_id = d0i3_iter_data.ap_sta_id;
+ mvm->d0i3_offloading = !d0i3_iter_data.disable_offloading;
+ } else {
+ WARN_ON_ONCE(d0i3_iter_data.vif_count > 1);
+ mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
+ mvm->d0i3_offloading = false;
+ }
+
+ iwl_mvm_set_wowlan_data(mvm, &wowlan_config_cmd, &d0i3_iter_data);
+ ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, flags,
+ sizeof(wowlan_config_cmd),
+ &wowlan_config_cmd);
+ if (ret)
+ return ret;
+
+ return iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD,
+ flags | CMD_MAKE_TRANS_IDLE,
+ sizeof(d3_cfg_cmd), &d3_cfg_cmd);
+}
+
+static void iwl_mvm_exit_d0i3_iterator(void *_data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm *mvm = _data;
+ u32 flags = CMD_ASYNC | CMD_HIGH_PRIO;
+
+ IWL_DEBUG_RPM(mvm, "exiting D0i3 - vif %pM\n", vif->addr);
+ if (vif->type != NL80211_IFTYPE_STATION ||
+ !vif->bss_conf.assoc)
+ return;
+
+ iwl_mvm_update_d0i3_power_mode(mvm, vif, false, flags);
+}
+
+static void iwl_mvm_d0i3_disconnect_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm *mvm = data;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ if (vif->type == NL80211_IFTYPE_STATION && vif->bss_conf.assoc &&
+ mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id)
+ ieee80211_connection_loss(vif);
+}
+
+void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq)
+{
+ struct ieee80211_sta *sta = NULL;
+ struct iwl_mvm_sta *mvm_ap_sta;
+ int i;
+ bool wake_queues = false;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ spin_lock_bh(&mvm->d0i3_tx_lock);
+
+ if (mvm->d0i3_ap_sta_id == IWL_MVM_STATION_COUNT)
+ goto out;
+
+ IWL_DEBUG_RPM(mvm, "re-enqueue packets\n");
+
+ /* get the sta in order to update seq numbers and re-enqueue skbs */
+ sta = rcu_dereference_protected(
+ mvm->fw_id_to_mac_id[mvm->d0i3_ap_sta_id],
+ lockdep_is_held(&mvm->mutex));
+
+ if (IS_ERR_OR_NULL(sta)) {
+ sta = NULL;
+ goto out;
+ }
+
+ if (mvm->d0i3_offloading && qos_seq) {
+ /* update qos seq numbers if offloading was enabled */
+ mvm_ap_sta = (struct iwl_mvm_sta *)sta->drv_priv;
+ for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
+ u16 seq = le16_to_cpu(qos_seq[i]);
+ /* firmware stores last-used one, we store next one */
+ seq += 0x10;
+ mvm_ap_sta->tid_data[i].seq_number = seq;
+ }
+ }
+out:
+ /* re-enqueue (or drop) all packets */
+ while (!skb_queue_empty(&mvm->d0i3_tx)) {
+ struct sk_buff *skb = __skb_dequeue(&mvm->d0i3_tx);
+
+ if (!sta || iwl_mvm_tx_skb(mvm, skb, sta))
+ ieee80211_free_txskb(mvm->hw, skb);
+
+ /* if the skb_queue is not empty, we need to wake queues */
+ wake_queues = true;
+ }
+ clear_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status);
+ wake_up(&mvm->d0i3_exit_waitq);
+ mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
+ if (wake_queues)
+ ieee80211_wake_queues(mvm->hw);
+
+ spin_unlock_bh(&mvm->d0i3_tx_lock);
+}
+
+static void iwl_mvm_d0i3_exit_work(struct work_struct *wk)
+{
+ struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, d0i3_exit_work);
+ struct iwl_host_cmd get_status_cmd = {
+ .id = WOWLAN_GET_STATUSES,
+ .flags = CMD_SYNC | CMD_HIGH_PRIO | CMD_WANT_SKB,
+ };
+ struct iwl_wowlan_status_v6 *status;
+ int ret;
+ u32 disconnection_reasons, wakeup_reasons;
+ __le16 *qos_seq = NULL;
+
+ mutex_lock(&mvm->mutex);
+ ret = iwl_mvm_send_cmd(mvm, &get_status_cmd);
+ if (ret)
+ goto out;
+
+ if (!get_status_cmd.resp_pkt)
+ goto out;
+
+ status = (void *)get_status_cmd.resp_pkt->data;
+ wakeup_reasons = le32_to_cpu(status->wakeup_reasons);
+ qos_seq = status->qos_seq_ctr;
+
+ IWL_DEBUG_RPM(mvm, "wakeup reasons: 0x%x\n", wakeup_reasons);
+
+ disconnection_reasons =
+ IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON |
+ IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH;
+ if (wakeup_reasons & disconnection_reasons)
+ ieee80211_iterate_active_interfaces(
+ mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_d0i3_disconnect_iter, mvm);
+
+ iwl_free_resp(&get_status_cmd);
+out:
+ iwl_mvm_d0i3_enable_tx(mvm, qos_seq);
+ mutex_unlock(&mvm->mutex);
+}
+
+static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode)
+{
+ struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+ u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE |
+ CMD_WAKE_UP_TRANS;
+ int ret;
+
+ IWL_DEBUG_RPM(mvm, "MVM exiting D0i3\n");
+
+ ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, flags, 0, NULL);
+ if (ret)
+ goto out;
+
+ ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_exit_d0i3_iterator,
+ mvm);
+out:
+ schedule_work(&mvm->d0i3_exit_work);
+ return ret;
+}
+
static const struct iwl_op_mode_ops iwl_mvm_ops = {
.start = iwl_op_mode_mvm_start,
.stop = iwl_op_mode_mvm_stop,
@@ -789,4 +1194,6 @@ static const struct iwl_op_mode_ops iwl_mvm_ops = {
.nic_error = iwl_mvm_nic_error,
.cmd_queue_full = iwl_mvm_cmd_queue_full,
.nic_config = iwl_mvm_nic_config,
+ .enter_d0i3 = iwl_mvm_enter_d0i3,
+ .exit_d0i3 = iwl_mvm_exit_d0i3,
};
diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
index b7268c0b3333..237efe0ac1c4 100644
--- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
@@ -156,13 +156,13 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm,
idle_cnt = chains_static;
active_cnt = chains_dynamic;
- cmd->rxchain_info = cpu_to_le32(iwl_fw_valid_rx_ant(mvm->fw) <<
+ cmd->rxchain_info = cpu_to_le32(mvm->fw->valid_rx_ant <<
PHY_RX_CHAIN_VALID_POS);
cmd->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS);
cmd->rxchain_info |= cpu_to_le32(active_cnt <<
PHY_RX_CHAIN_MIMO_CNT_POS);
- cmd->txchain_info = cpu_to_le32(iwl_fw_valid_tx_ant(mvm->fw));
+ cmd->txchain_info = cpu_to_le32(mvm->fw->valid_tx_ant);
}
/*
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c
index d9eab3b7bb9f..6b636eab3339 100644
--- a/drivers/net/wireless/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/iwlwifi/mvm/power.c
@@ -74,39 +74,36 @@
#define POWER_KEEP_ALIVE_PERIOD_SEC 25
+static
int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm,
- struct iwl_beacon_filter_cmd *cmd)
+ struct iwl_beacon_filter_cmd *cmd,
+ u32 flags)
{
- int ret;
-
- ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, CMD_SYNC,
- sizeof(struct iwl_beacon_filter_cmd), cmd);
-
- if (!ret) {
- IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n",
- le32_to_cpu(cmd->ba_enable_beacon_abort));
- IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n",
- le32_to_cpu(cmd->ba_escape_timer));
- IWL_DEBUG_POWER(mvm, "bf_debug_flag is: %d\n",
- le32_to_cpu(cmd->bf_debug_flag));
- IWL_DEBUG_POWER(mvm, "bf_enable_beacon_filter is: %d\n",
- le32_to_cpu(cmd->bf_enable_beacon_filter));
- IWL_DEBUG_POWER(mvm, "bf_energy_delta is: %d\n",
- le32_to_cpu(cmd->bf_energy_delta));
- IWL_DEBUG_POWER(mvm, "bf_escape_timer is: %d\n",
- le32_to_cpu(cmd->bf_escape_timer));
- IWL_DEBUG_POWER(mvm, "bf_roaming_energy_delta is: %d\n",
- le32_to_cpu(cmd->bf_roaming_energy_delta));
- IWL_DEBUG_POWER(mvm, "bf_roaming_state is: %d\n",
- le32_to_cpu(cmd->bf_roaming_state));
- IWL_DEBUG_POWER(mvm, "bf_temp_threshold is: %d\n",
- le32_to_cpu(cmd->bf_temp_threshold));
- IWL_DEBUG_POWER(mvm, "bf_temp_fast_filter is: %d\n",
- le32_to_cpu(cmd->bf_temp_fast_filter));
- IWL_DEBUG_POWER(mvm, "bf_temp_slow_filter is: %d\n",
- le32_to_cpu(cmd->bf_temp_slow_filter));
- }
- return ret;
+ IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n",
+ le32_to_cpu(cmd->ba_enable_beacon_abort));
+ IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n",
+ le32_to_cpu(cmd->ba_escape_timer));
+ IWL_DEBUG_POWER(mvm, "bf_debug_flag is: %d\n",
+ le32_to_cpu(cmd->bf_debug_flag));
+ IWL_DEBUG_POWER(mvm, "bf_enable_beacon_filter is: %d\n",
+ le32_to_cpu(cmd->bf_enable_beacon_filter));
+ IWL_DEBUG_POWER(mvm, "bf_energy_delta is: %d\n",
+ le32_to_cpu(cmd->bf_energy_delta));
+ IWL_DEBUG_POWER(mvm, "bf_escape_timer is: %d\n",
+ le32_to_cpu(cmd->bf_escape_timer));
+ IWL_DEBUG_POWER(mvm, "bf_roaming_energy_delta is: %d\n",
+ le32_to_cpu(cmd->bf_roaming_energy_delta));
+ IWL_DEBUG_POWER(mvm, "bf_roaming_state is: %d\n",
+ le32_to_cpu(cmd->bf_roaming_state));
+ IWL_DEBUG_POWER(mvm, "bf_temp_threshold is: %d\n",
+ le32_to_cpu(cmd->bf_temp_threshold));
+ IWL_DEBUG_POWER(mvm, "bf_temp_fast_filter is: %d\n",
+ le32_to_cpu(cmd->bf_temp_fast_filter));
+ IWL_DEBUG_POWER(mvm, "bf_temp_slow_filter is: %d\n",
+ le32_to_cpu(cmd->bf_temp_slow_filter));
+
+ return iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, flags,
+ sizeof(struct iwl_beacon_filter_cmd), cmd);
}
static
@@ -145,7 +142,7 @@ int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm,
mvmvif->bf_data.ba_enabled = enable;
iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, &cmd);
iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
- return iwl_mvm_beacon_filter_send_cmd(mvm, &cmd);
+ return iwl_mvm_beacon_filter_send_cmd(mvm, &cmd, CMD_SYNC);
}
static void iwl_mvm_power_log(struct iwl_mvm *mvm,
@@ -301,8 +298,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC);
cmd->keep_alive_seconds = cpu_to_le16(keep_alive);
- if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM ||
- mvm->ps_prevented)
+ if (mvm->ps_disabled)
return;
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
@@ -312,7 +308,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
mvmvif->dbgfs_pm.disable_power_off)
cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK);
#endif
- if (!vif->bss_conf.ps || mvmvif->pm_prevented)
+ if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) ||
+ mvm->pm_disabled)
return;
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
@@ -419,72 +416,44 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
#endif /* CONFIG_IWLWIFI_DEBUGFS */
}
-static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm,
+static int iwl_mvm_power_send_cmd(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
- int ret;
- bool ba_enable;
struct iwl_mac_power_cmd cmd = {};
if (vif->type != NL80211_IFTYPE_STATION)
return 0;
if (vif->p2p &&
- !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS))
+ !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM))
return 0;
iwl_mvm_power_build_cmd(mvm, vif, &cmd);
iwl_mvm_power_log(mvm, &cmd);
-
- ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_SYNC,
- sizeof(cmd), &cmd);
- if (ret)
- return ret;
-
- ba_enable = !!(cmd.flags &
- cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK));
-
- return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable);
-}
-
-static int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
-{
- struct iwl_mac_power_cmd cmd = {};
- struct iwl_mvm_vif *mvmvif __maybe_unused =
- iwl_mvm_vif_from_mac80211(vif);
-
- if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
- return 0;
-
- cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
- mvmvif->color));
-
- if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM)
- cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
-
#ifdef CONFIG_IWLWIFI_DEBUGFS
- if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF &&
- mvmvif->dbgfs_pm.disable_power_off)
- cmd.flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK);
+ memcpy(&iwl_mvm_vif_from_mac80211(vif)->mac_pwr_cmd, &cmd, sizeof(cmd));
#endif
- iwl_mvm_power_log(mvm, &cmd);
- return iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_ASYNC,
+ return iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_SYNC,
sizeof(cmd), &cmd);
}
-static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable)
+int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
{
struct iwl_device_power_cmd cmd = {
.flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK),
};
+ if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT))
+ return 0;
+
if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD))
return 0;
- if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM ||
- force_disable)
+ if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)
+ mvm->ps_disabled = true;
+
+ if (mvm->ps_disabled)
cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_CAM_MSK);
#ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -501,11 +470,6 @@ static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable)
&cmd);
}
-static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
-{
- return _iwl_mvm_power_update_device(mvm, false);
-}
-
void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -544,44 +508,176 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
return 0;
}
-static void iwl_mvm_power_binding_iterator(void *_data, u8 *mac,
- struct ieee80211_vif *vif)
+struct iwl_power_constraint {
+ struct ieee80211_vif *bf_vif;
+ struct ieee80211_vif *bss_vif;
+ struct ieee80211_vif *p2p_vif;
+ u16 bss_phyctx_id;
+ u16 p2p_phyctx_id;
+ bool pm_disabled;
+ bool ps_disabled;
+ struct iwl_mvm *mvm;
+};
+
+static void iwl_mvm_power_iterator(void *_data, u8 *mac,
+ struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_mvm *mvm = _data;
- int ret;
+ struct iwl_power_constraint *power_iterator = _data;
+ struct iwl_mvm *mvm = power_iterator->mvm;
+
+ switch (ieee80211_vif_type_p2p(vif)) {
+ case NL80211_IFTYPE_P2P_DEVICE:
+ break;
+
+ case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_AP:
+ /* no BSS power mgmt if we have an active AP */
+ if (mvmvif->ap_ibss_active)
+ power_iterator->pm_disabled = true;
+ break;
+
+ case NL80211_IFTYPE_MONITOR:
+ /* no BSS power mgmt and no device power save */
+ power_iterator->pm_disabled = true;
+ power_iterator->ps_disabled = true;
+ break;
+
+ case NL80211_IFTYPE_P2P_CLIENT:
+ if (mvmvif->phy_ctxt)
+ power_iterator->p2p_phyctx_id = mvmvif->phy_ctxt->id;
+
+ /* we should have only one P2P vif */
+ WARN_ON(power_iterator->p2p_vif);
+ power_iterator->p2p_vif = vif;
+
+ IWL_DEBUG_POWER(mvm, "p2p: p2p_id=%d, bss_id=%d\n",
+ power_iterator->p2p_phyctx_id,
+ power_iterator->bss_phyctx_id);
+ if (!(mvm->fw->ucode_capa.flags &
+ IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)) {
+ /* no BSS power mgmt if we have a P2P client*/
+ power_iterator->pm_disabled = true;
+ } else if (power_iterator->p2p_phyctx_id < MAX_PHYS &&
+ power_iterator->bss_phyctx_id < MAX_PHYS &&
+ power_iterator->p2p_phyctx_id ==
+ power_iterator->bss_phyctx_id) {
+ power_iterator->pm_disabled = true;
+ }
+ break;
+
+ case NL80211_IFTYPE_STATION:
+ if (mvmvif->phy_ctxt)
+ power_iterator->bss_phyctx_id = mvmvif->phy_ctxt->id;
+
+ /* we should have only one BSS vif */
+ WARN_ON(power_iterator->bss_vif);
+ power_iterator->bss_vif = vif;
+
+ if (mvmvif->bf_data.bf_enabled &&
+ !WARN_ON(power_iterator->bf_vif))
+ power_iterator->bf_vif = vif;
+
+ IWL_DEBUG_POWER(mvm, "bss: p2p_id=%d, bss_id=%d\n",
+ power_iterator->p2p_phyctx_id,
+ power_iterator->bss_phyctx_id);
+ if (mvm->fw->ucode_capa.flags &
+ IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM &&
+ (power_iterator->p2p_phyctx_id < MAX_PHYS &&
+ power_iterator->bss_phyctx_id < MAX_PHYS &&
+ power_iterator->p2p_phyctx_id ==
+ power_iterator->bss_phyctx_id))
+ power_iterator->pm_disabled = true;
+ break;
+
+ default:
+ break;
+ }
+}
- mvmvif->pm_prevented = (mvm->bound_vif_cnt <= 1) ? false : true;
+static void
+iwl_mvm_power_get_global_constraint(struct iwl_mvm *mvm,
+ struct iwl_power_constraint *constraint)
+{
+ lockdep_assert_held(&mvm->mutex);
+
+ if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) {
+ constraint->pm_disabled = true;
+ constraint->ps_disabled = true;
+ }
- ret = iwl_mvm_power_mac_update_mode(mvm, vif);
- WARN_ONCE(ret, "Failed to update power parameters on a specific vif\n");
+ ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_power_iterator, constraint);
}
-static void _iwl_mvm_power_update_binding(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- bool assign)
+int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_power_constraint constraint = {
+ .p2p_phyctx_id = MAX_PHYS,
+ .bss_phyctx_id = MAX_PHYS,
+ .mvm = mvm,
+ };
+ bool ba_enable;
+ int ret;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT))
+ return 0;
+
+ iwl_mvm_power_get_global_constraint(mvm, &constraint);
+ mvm->ps_disabled = constraint.ps_disabled;
+ mvm->pm_disabled = constraint.pm_disabled;
+
+ /* don't update device power state unless we add / remove monitor */
if (vif->type == NL80211_IFTYPE_MONITOR) {
- int ret = _iwl_mvm_power_update_device(mvm, assign);
- mvm->ps_prevented = assign;
- WARN_ONCE(ret, "Failed to update power device state\n");
+ ret = iwl_mvm_power_update_device(mvm);
+ if (ret)
+ return ret;
}
- ieee80211_iterate_active_interfaces(mvm->hw,
- IEEE80211_IFACE_ITER_NORMAL,
- iwl_mvm_power_binding_iterator,
- mvm);
+ if (constraint.bss_vif) {
+ ret = iwl_mvm_power_send_cmd(mvm, constraint.bss_vif);
+ if (ret)
+ return ret;
+ }
+
+ if (constraint.p2p_vif) {
+ ret = iwl_mvm_power_send_cmd(mvm, constraint.p2p_vif);
+ if (ret)
+ return ret;
+ }
+
+ if (!constraint.bf_vif)
+ return 0;
+
+ vif = constraint.bf_vif;
+ mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ ba_enable = !(constraint.pm_disabled || constraint.ps_disabled ||
+ !vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif));
+
+ return iwl_mvm_update_beacon_abort(mvm, constraint.bf_vif, ba_enable);
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
-static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif, char *buf,
- int bufsz)
+int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif, char *buf,
+ int bufsz)
{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mac_power_cmd cmd = {};
int pos = 0;
- iwl_mvm_power_build_cmd(mvm, vif, &cmd);
+ if (WARN_ON(!(mvm->fw->ucode_capa.flags &
+ IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)))
+ return 0;
+
+ mutex_lock(&mvm->mutex);
+ memcpy(&cmd, &mvmvif->mac_pwr_cmd, sizeof(cmd));
+ mutex_unlock(&mvm->mutex);
if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD))
pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n",
@@ -685,32 +781,46 @@ iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif,
}
#endif
-int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
+static int _iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct iwl_beacon_filter_cmd *cmd,
+ u32 cmd_flags,
+ bool d0i3)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_beacon_filter_cmd cmd = {
- IWL_BF_CMD_CONFIG_DEFAULTS,
- .bf_enable_beacon_filter = cpu_to_le32(1),
- };
int ret;
if (mvmvif != mvm->bf_allowed_vif ||
vif->type != NL80211_IFTYPE_STATION || vif->p2p)
return 0;
- iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, &cmd);
- iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
- ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd);
+ iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, cmd);
+ if (!d0i3)
+ iwl_mvm_beacon_filter_debugfs_parameters(vif, cmd);
+ ret = iwl_mvm_beacon_filter_send_cmd(mvm, cmd, cmd_flags);
- if (!ret)
+ /* don't change bf_enabled in case of temporary d0i3 configuration */
+ if (!ret && !d0i3)
mvmvif->bf_data.bf_enabled = true;
return ret;
}
+int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ u32 flags)
+{
+ struct iwl_beacon_filter_cmd cmd = {
+ IWL_BF_CMD_CONFIG_DEFAULTS,
+ .bf_enable_beacon_filter = cpu_to_le32(1),
+ };
+
+ return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, flags, false);
+}
+
int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
+ struct ieee80211_vif *vif,
+ u32 flags)
{
struct iwl_beacon_filter_cmd cmd = {};
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -720,7 +830,7 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
vif->type != NL80211_IFTYPE_STATION || vif->p2p)
return 0;
- ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd);
+ ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd, flags);
if (!ret)
mvmvif->bf_data.bf_enabled = false;
@@ -728,23 +838,89 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
return ret;
}
-int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
+int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ bool enable, u32 flags)
{
+ int ret;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mac_power_cmd cmd = {};
- if (!mvmvif->bf_data.bf_enabled)
+ if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
return 0;
- return iwl_mvm_enable_beacon_filter(mvm, vif);
-}
+ if (!vif->bss_conf.assoc)
+ return 0;
-const struct iwl_mvm_power_ops pm_mac_ops = {
- .power_update_mode = iwl_mvm_power_mac_update_mode,
- .power_update_device_mode = iwl_mvm_power_update_device,
- .power_disable = iwl_mvm_power_mac_disable,
- .power_update_binding = _iwl_mvm_power_update_binding,
+ iwl_mvm_power_build_cmd(mvm, vif, &cmd);
+ if (enable) {
+ /* configure skip over dtim up to 300 msec */
+ int dtimper = mvm->hw->conf.ps_dtim_period ?: 1;
+ int dtimper_msec = dtimper * vif->bss_conf.beacon_int;
+
+ if (WARN_ON(!dtimper_msec))
+ return 0;
+
+ cmd.flags |=
+ cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
+ cmd.skip_dtim_periods = 300 / dtimper_msec;
+ }
+ iwl_mvm_power_log(mvm, &cmd);
#ifdef CONFIG_IWLWIFI_DEBUGFS
- .power_dbgfs_read = iwl_mvm_power_mac_dbgfs_read,
+ memcpy(&mvmvif->mac_pwr_cmd, &cmd, sizeof(cmd));
#endif
-};
+ ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, flags,
+ sizeof(cmd), &cmd);
+ if (ret)
+ return ret;
+
+ /* configure beacon filtering */
+ if (mvmvif != mvm->bf_allowed_vif)
+ return 0;
+
+ if (enable) {
+ struct iwl_beacon_filter_cmd cmd_bf = {
+ IWL_BF_CMD_CONFIG_D0I3,
+ .bf_enable_beacon_filter = cpu_to_le32(1),
+ };
+ ret = _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd_bf,
+ flags, true);
+ } else {
+ if (mvmvif->bf_data.bf_enabled)
+ ret = iwl_mvm_enable_beacon_filter(mvm, vif, flags);
+ else
+ ret = iwl_mvm_disable_beacon_filter(mvm, vif, flags);
+ }
+
+ return ret;
+}
+
+int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ bool force,
+ u32 flags)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ if (mvmvif != mvm->bf_allowed_vif)
+ return 0;
+
+ if (!mvmvif->bf_data.bf_enabled) {
+ /* disable beacon filtering explicitly if force is true */
+ if (force)
+ return iwl_mvm_disable_beacon_filter(mvm, vif, flags);
+ return 0;
+ }
+
+ return iwl_mvm_enable_beacon_filter(mvm, vif, flags);
+}
+
+int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm)
+{
+ struct iwl_powertable_cmd cmd = {
+ .keep_alive_seconds = POWER_KEEP_ALIVE_PERIOD_SEC,
+ };
+
+ return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC,
+ sizeof(cmd), &cmd);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/power_legacy.c b/drivers/net/wireless/iwlwifi/mvm/power_legacy.c
deleted file mode 100644
index ef712ae5bc62..000000000000
--- a/drivers/net/wireless/iwlwifi/mvm/power_legacy.c
+++ /dev/null
@@ -1,319 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license. When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2012 - 2014 Intel 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 full GNU General Public License is included in this distribution
- * in the file called COPYING.
- *
- * Contact Information:
- * Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name Intel Corporation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * 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.
- *
- *****************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-
-#include <net/mac80211.h>
-
-#include "iwl-debug.h"
-#include "mvm.h"
-#include "iwl-modparams.h"
-#include "fw-api-power.h"
-
-#define POWER_KEEP_ALIVE_PERIOD_SEC 25
-
-static void iwl_mvm_power_log(struct iwl_mvm *mvm,
- struct iwl_powertable_cmd *cmd)
-{
- IWL_DEBUG_POWER(mvm,
- "Sending power table command for power level %d, flags = 0x%X\n",
- iwlmvm_mod_params.power_scheme,
- le16_to_cpu(cmd->flags));
- IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n", cmd->keep_alive_seconds);
-
- if (cmd->flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) {
- IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n",
- le32_to_cpu(cmd->rx_data_timeout));
- IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n",
- le32_to_cpu(cmd->tx_data_timeout));
- if (cmd->flags & cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK))
- IWL_DEBUG_POWER(mvm, "DTIM periods to skip = %u\n",
- le32_to_cpu(cmd->skip_dtim_periods));
- if (cmd->flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK))
- IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n",
- le32_to_cpu(cmd->lprx_rssi_threshold));
- }
-}
-
-static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct iwl_powertable_cmd *cmd)
-{
- struct ieee80211_hw *hw = mvm->hw;
- struct ieee80211_chanctx_conf *chanctx_conf;
- struct ieee80211_channel *chan;
- int dtimper, dtimper_msec;
- int keep_alive;
- bool radar_detect = false;
- struct iwl_mvm_vif *mvmvif __maybe_unused =
- iwl_mvm_vif_from_mac80211(vif);
-
- /*
- * Regardless of power management state the driver must set
- * keep alive period. FW will use it for sending keep alive NDPs
- * immediately after association.
- */
- cmd->keep_alive_seconds = POWER_KEEP_ALIVE_PERIOD_SEC;
-
- if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)
- return;
-
- cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
- if (!vif->bss_conf.assoc)
- cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
- if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF &&
- mvmvif->dbgfs_pm.disable_power_off)
- cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK);
-#endif
- if (!vif->bss_conf.ps)
- return;
-
- cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
-
- if (vif->bss_conf.beacon_rate &&
- (vif->bss_conf.beacon_rate->bitrate == 10 ||
- vif->bss_conf.beacon_rate->bitrate == 60)) {
- cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK);
- cmd->lprx_rssi_threshold =
- cpu_to_le32(POWER_LPRX_RSSI_THRESHOLD);
- }
-
- dtimper = hw->conf.ps_dtim_period ?: 1;
-
- /* Check if radar detection is required on current channel */
- rcu_read_lock();
- chanctx_conf = rcu_dereference(vif->chanctx_conf);
- WARN_ON(!chanctx_conf);
- if (chanctx_conf) {
- chan = chanctx_conf->def.chan;
- radar_detect = chan->flags & IEEE80211_CHAN_RADAR;
- }
- rcu_read_unlock();
-
- /* Check skip over DTIM conditions */
- if (!radar_detect && (dtimper <= 10) &&
- (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP ||
- mvm->cur_ucode == IWL_UCODE_WOWLAN)) {
- cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
- cmd->skip_dtim_periods = cpu_to_le32(3);
- }
-
- /* Check that keep alive period is at least 3 * DTIM */
- dtimper_msec = dtimper * vif->bss_conf.beacon_int;
- keep_alive = max_t(int, 3 * dtimper_msec,
- MSEC_PER_SEC * cmd->keep_alive_seconds);
- keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC);
- cmd->keep_alive_seconds = keep_alive;
-
- if (mvm->cur_ucode != IWL_UCODE_WOWLAN) {
- cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC);
- cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC);
- } else {
- cmd->rx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC);
- cmd->tx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC);
- }
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
- if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE)
- cmd->keep_alive_seconds = mvmvif->dbgfs_pm.keep_alive_seconds;
- if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_OVER_DTIM) {
- if (mvmvif->dbgfs_pm.skip_over_dtim)
- cmd->flags |=
- cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
- else
- cmd->flags &=
- cpu_to_le16(~POWER_FLAGS_SKIP_OVER_DTIM_MSK);
- }
- if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_RX_DATA_TIMEOUT)
- cmd->rx_data_timeout =
- cpu_to_le32(mvmvif->dbgfs_pm.rx_data_timeout);
- if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_TX_DATA_TIMEOUT)
- cmd->tx_data_timeout =
- cpu_to_le32(mvmvif->dbgfs_pm.tx_data_timeout);
- if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS)
- cmd->skip_dtim_periods =
- cpu_to_le32(mvmvif->dbgfs_pm.skip_dtim_periods);
- if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_ENA) {
- if (mvmvif->dbgfs_pm.lprx_ena)
- cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK);
- else
- cmd->flags &= cpu_to_le16(~POWER_FLAGS_LPRX_ENA_MSK);
- }
- if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD)
- cmd->lprx_rssi_threshold =
- cpu_to_le32(mvmvif->dbgfs_pm.lprx_rssi_threshold);
-#endif /* CONFIG_IWLWIFI_DEBUGFS */
-}
-
-static int iwl_mvm_power_legacy_update_mode(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
-{
- int ret;
- bool ba_enable;
- struct iwl_powertable_cmd cmd = {};
-
- if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
- return 0;
-
- /*
- * TODO: The following vif_count verification is temporary condition.
- * Avoid power mode update if more than one interface is currently
- * active. Remove this condition when FW will support power management
- * on multiple MACs.
- */
- IWL_DEBUG_POWER(mvm, "Currently %d interfaces active\n",
- mvm->vif_count);
- if (mvm->vif_count > 1)
- return 0;
-
- iwl_mvm_power_build_cmd(mvm, vif, &cmd);
- iwl_mvm_power_log(mvm, &cmd);
-
- ret = iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC,
- sizeof(cmd), &cmd);
- if (ret)
- return ret;
-
- ba_enable = !!(cmd.flags &
- cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK));
-
- return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable);
-}
-
-static int iwl_mvm_power_legacy_disable(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
-{
- struct iwl_powertable_cmd cmd = {};
- struct iwl_mvm_vif *mvmvif __maybe_unused =
- iwl_mvm_vif_from_mac80211(vif);
-
- if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
- return 0;
-
- if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM)
- cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
- if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF &&
- mvmvif->dbgfs_pm.disable_power_off)
- cmd.flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK);
-#endif
- iwl_mvm_power_log(mvm, &cmd);
-
- return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC,
- sizeof(cmd), &cmd);
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-static int iwl_mvm_power_legacy_dbgfs_read(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif, char *buf,
- int bufsz)
-{
- struct iwl_powertable_cmd cmd = {};
- int pos = 0;
-
- iwl_mvm_power_build_cmd(mvm, vif, &cmd);
-
- pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n",
- (cmd.flags &
- cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ?
- 0 : 1);
- pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n",
- le32_to_cpu(cmd.skip_dtim_periods));
- pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n",
- iwlmvm_mod_params.power_scheme);
- pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n",
- le16_to_cpu(cmd.flags));
- pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n",
- cmd.keep_alive_seconds);
-
- if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) {
- pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n",
- (cmd.flags &
- cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ?
- 1 : 0);
- pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n",
- le32_to_cpu(cmd.rx_data_timeout));
- pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n",
- le32_to_cpu(cmd.tx_data_timeout));
- if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK))
- pos += scnprintf(buf+pos, bufsz-pos,
- "lprx_rssi_threshold = %d\n",
- le32_to_cpu(cmd.lprx_rssi_threshold));
- }
- return pos;
-}
-#endif
-
-const struct iwl_mvm_power_ops pm_legacy_ops = {
- .power_update_mode = iwl_mvm_power_legacy_update_mode,
- .power_disable = iwl_mvm_power_legacy_disable,
-#ifdef CONFIG_IWLWIFI_DEBUGFS
- .power_dbgfs_read = iwl_mvm_power_legacy_dbgfs_read,
-#endif
-};
diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c
index ce5db6c4ef7e..35e86e06dffd 100644
--- a/drivers/net/wireless/iwlwifi/mvm/quota.c
+++ b/drivers/net/wireless/iwlwifi/mvm/quota.c
@@ -65,9 +65,14 @@
#include "fw-api.h"
#include "mvm.h"
+#define QUOTA_100 IWL_MVM_MAX_QUOTA
+#define QUOTA_LOWLAT_MIN ((QUOTA_100 * IWL_MVM_LOWLAT_QUOTA_MIN_PERCENT) / 100)
+
struct iwl_mvm_quota_iterator_data {
int n_interfaces[MAX_BINDINGS];
int colors[MAX_BINDINGS];
+ int low_latency[MAX_BINDINGS];
+ int n_low_latency_bindings;
struct ieee80211_vif *new_vif;
};
@@ -107,22 +112,29 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac,
switch (vif->type) {
case NL80211_IFTYPE_STATION:
if (vif->bss_conf.assoc)
- data->n_interfaces[id]++;
- break;
+ break;
+ return;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_ADHOC:
if (mvmvif->ap_ibss_active)
- data->n_interfaces[id]++;
- break;
+ break;
+ return;
case NL80211_IFTYPE_MONITOR:
if (mvmvif->monitor_active)
- data->n_interfaces[id]++;
- break;
+ break;
+ return;
case NL80211_IFTYPE_P2P_DEVICE:
- break;
+ return;
default:
WARN_ON_ONCE(1);
- break;
+ return;
+ }
+
+ data->n_interfaces[id]++;
+
+ if (iwl_mvm_vif_low_latency(mvmvif) && !data->low_latency[id]) {
+ data->n_low_latency_bindings++;
+ data->low_latency[id] = true;
}
}
@@ -162,7 +174,7 @@ static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm,
int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif)
{
struct iwl_time_quota_cmd cmd = {};
- int i, idx, ret, num_active_macs, quota, quota_rem;
+ int i, idx, ret, num_active_macs, quota, quota_rem, n_non_lowlat;
struct iwl_mvm_quota_iterator_data data = {
.n_interfaces = {},
.colors = { -1, -1, -1, -1 },
@@ -197,11 +209,39 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif)
num_active_macs += data.n_interfaces[i];
}
- quota = 0;
- quota_rem = 0;
- if (num_active_macs) {
- quota = IWL_MVM_MAX_QUOTA / num_active_macs;
- quota_rem = IWL_MVM_MAX_QUOTA % num_active_macs;
+ n_non_lowlat = num_active_macs;
+
+ if (data.n_low_latency_bindings == 1) {
+ for (i = 0; i < MAX_BINDINGS; i++) {
+ if (data.low_latency[i]) {
+ n_non_lowlat -= data.n_interfaces[i];
+ break;
+ }
+ }
+ }
+
+ if (data.n_low_latency_bindings == 1 && n_non_lowlat) {
+ /*
+ * Reserve quota for the low latency binding in case that
+ * there are several data bindings but only a single
+ * low latency one. Split the rest of the quota equally
+ * between the other data interfaces.
+ */
+ quota = (QUOTA_100 - QUOTA_LOWLAT_MIN) / n_non_lowlat;
+ quota_rem = QUOTA_100 - n_non_lowlat * quota -
+ QUOTA_LOWLAT_MIN;
+ } else if (num_active_macs) {
+ /*
+ * There are 0 or more than 1 low latency bindings, or all the
+ * data interfaces belong to the single low latency binding.
+ * Split the quota equally between the data interfaces.
+ */
+ quota = QUOTA_100 / num_active_macs;
+ quota_rem = QUOTA_100 % num_active_macs;
+ } else {
+ /* values don't really matter - won't be used */
+ quota = 0;
+ quota_rem = 0;
}
for (idx = 0, i = 0; i < MAX_BINDINGS; i++) {
@@ -211,19 +251,37 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif)
cmd.quotas[idx].id_and_color =
cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i]));
- if (data.n_interfaces[i] <= 0) {
+ if (data.n_interfaces[i] <= 0)
cmd.quotas[idx].quota = cpu_to_le32(0);
- cmd.quotas[idx].max_duration = cpu_to_le32(0);
- } else {
+ else if (data.n_low_latency_bindings == 1 && n_non_lowlat &&
+ data.low_latency[i])
+ /*
+ * There is more than one binding, but only one of the
+ * bindings is in low latency. For this case, allocate
+ * the minimal required quota for the low latency
+ * binding.
+ */
+ cmd.quotas[idx].quota = cpu_to_le32(QUOTA_LOWLAT_MIN);
+ else
cmd.quotas[idx].quota =
cpu_to_le32(quota * data.n_interfaces[i]);
- cmd.quotas[idx].max_duration = cpu_to_le32(0);
- }
+
+ WARN_ONCE(le32_to_cpu(cmd.quotas[idx].quota) > QUOTA_100,
+ "Binding=%d, quota=%u > max=%u\n",
+ idx, le32_to_cpu(cmd.quotas[idx].quota), QUOTA_100);
+
+ cmd.quotas[idx].max_duration = cpu_to_le32(0);
+
idx++;
}
- /* Give the remainder of the session to the first binding */
- le32_add_cpu(&cmd.quotas[0].quota, quota_rem);
+ /* Give the remainder of the session to the first data binding */
+ for (i = 0; i < MAX_BINDINGS; i++) {
+ if (le32_to_cpu(cmd.quotas[i].quota) != 0) {
+ le32_add_cpu(&cmd.quotas[i].quota, quota_rem);
+ break;
+ }
+ }
iwl_mvm_adjust_quota_for_noa(mvm, &cmd);
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 6abf74e1351f..568abd61b14f 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -166,7 +166,7 @@ static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
if (sta->smps_mode == IEEE80211_SMPS_STATIC)
return false;
- if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) < 2)
+ if (num_of_ant(mvm->fw->valid_tx_ant) < 2)
return false;
if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
@@ -211,9 +211,9 @@ static const struct rs_tx_column rs_tx_columns[] = {
.next_columns = {
RS_COLUMN_LEGACY_ANT_B,
RS_COLUMN_SISO_ANT_A,
+ RS_COLUMN_SISO_ANT_B,
RS_COLUMN_MIMO2,
- RS_COLUMN_INVALID,
- RS_COLUMN_INVALID,
+ RS_COLUMN_MIMO2_SGI,
},
},
[RS_COLUMN_LEGACY_ANT_B] = {
@@ -221,10 +221,10 @@ static const struct rs_tx_column rs_tx_columns[] = {
.ant = ANT_B,
.next_columns = {
RS_COLUMN_LEGACY_ANT_A,
+ RS_COLUMN_SISO_ANT_A,
RS_COLUMN_SISO_ANT_B,
RS_COLUMN_MIMO2,
- RS_COLUMN_INVALID,
- RS_COLUMN_INVALID,
+ RS_COLUMN_MIMO2_SGI,
},
},
[RS_COLUMN_SISO_ANT_A] = {
@@ -234,8 +234,8 @@ static const struct rs_tx_column rs_tx_columns[] = {
RS_COLUMN_SISO_ANT_B,
RS_COLUMN_MIMO2,
RS_COLUMN_SISO_ANT_A_SGI,
- RS_COLUMN_INVALID,
- RS_COLUMN_INVALID,
+ RS_COLUMN_SISO_ANT_B_SGI,
+ RS_COLUMN_MIMO2_SGI,
},
.checks = {
rs_siso_allow,
@@ -248,8 +248,8 @@ static const struct rs_tx_column rs_tx_columns[] = {
RS_COLUMN_SISO_ANT_A,
RS_COLUMN_MIMO2,
RS_COLUMN_SISO_ANT_B_SGI,
- RS_COLUMN_INVALID,
- RS_COLUMN_INVALID,
+ RS_COLUMN_SISO_ANT_A_SGI,
+ RS_COLUMN_MIMO2_SGI,
},
.checks = {
rs_siso_allow,
@@ -263,8 +263,8 @@ static const struct rs_tx_column rs_tx_columns[] = {
RS_COLUMN_SISO_ANT_B_SGI,
RS_COLUMN_MIMO2_SGI,
RS_COLUMN_SISO_ANT_A,
- RS_COLUMN_INVALID,
- RS_COLUMN_INVALID,
+ RS_COLUMN_SISO_ANT_B,
+ RS_COLUMN_MIMO2,
},
.checks = {
rs_siso_allow,
@@ -279,8 +279,8 @@ static const struct rs_tx_column rs_tx_columns[] = {
RS_COLUMN_SISO_ANT_A_SGI,
RS_COLUMN_MIMO2_SGI,
RS_COLUMN_SISO_ANT_B,
- RS_COLUMN_INVALID,
- RS_COLUMN_INVALID,
+ RS_COLUMN_SISO_ANT_A,
+ RS_COLUMN_MIMO2,
},
.checks = {
rs_siso_allow,
@@ -292,10 +292,10 @@ static const struct rs_tx_column rs_tx_columns[] = {
.ant = ANT_AB,
.next_columns = {
RS_COLUMN_SISO_ANT_A,
+ RS_COLUMN_SISO_ANT_B,
+ RS_COLUMN_SISO_ANT_A_SGI,
+ RS_COLUMN_SISO_ANT_B_SGI,
RS_COLUMN_MIMO2_SGI,
- RS_COLUMN_INVALID,
- RS_COLUMN_INVALID,
- RS_COLUMN_INVALID,
},
.checks = {
rs_mimo_allow,
@@ -307,10 +307,10 @@ static const struct rs_tx_column rs_tx_columns[] = {
.sgi = true,
.next_columns = {
RS_COLUMN_SISO_ANT_A_SGI,
+ RS_COLUMN_SISO_ANT_B_SGI,
+ RS_COLUMN_SISO_ANT_A,
+ RS_COLUMN_SISO_ANT_B,
RS_COLUMN_MIMO2,
- RS_COLUMN_INVALID,
- RS_COLUMN_INVALID,
- RS_COLUMN_INVALID,
},
.checks = {
rs_mimo_allow,
@@ -380,49 +380,49 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search);
* (2.4 GHz) band.
*/
-static s32 expected_tpt_legacy[IWL_RATE_COUNT] = {
+static const u16 expected_tpt_legacy[IWL_RATE_COUNT] = {
7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0, 0, 0
};
/* Expected TpT tables. 4 indexes:
* 0 - NGI, 1 - SGI, 2 - AGG+NGI, 3 - AGG+SGI
*/
-static s32 expected_tpt_siso_20MHz[4][IWL_RATE_COUNT] = {
+static const u16 expected_tpt_siso_20MHz[4][IWL_RATE_COUNT] = {
{0, 0, 0, 0, 42, 0, 76, 102, 124, 159, 183, 193, 202, 216, 0},
{0, 0, 0, 0, 46, 0, 82, 110, 132, 168, 192, 202, 210, 225, 0},
{0, 0, 0, 0, 49, 0, 97, 145, 192, 285, 375, 420, 464, 551, 0},
{0, 0, 0, 0, 54, 0, 108, 160, 213, 315, 415, 465, 513, 608, 0},
};
-static s32 expected_tpt_siso_40MHz[4][IWL_RATE_COUNT] = {
+static const u16 expected_tpt_siso_40MHz[4][IWL_RATE_COUNT] = {
{0, 0, 0, 0, 77, 0, 127, 160, 184, 220, 242, 250, 257, 269, 275},
{0, 0, 0, 0, 83, 0, 135, 169, 193, 229, 250, 257, 264, 275, 280},
{0, 0, 0, 0, 101, 0, 199, 295, 389, 570, 744, 828, 911, 1070, 1173},
{0, 0, 0, 0, 112, 0, 220, 326, 429, 629, 819, 912, 1000, 1173, 1284},
};
-static s32 expected_tpt_siso_80MHz[4][IWL_RATE_COUNT] = {
+static const u16 expected_tpt_siso_80MHz[4][IWL_RATE_COUNT] = {
{0, 0, 0, 0, 130, 0, 191, 223, 244, 273, 288, 294, 298, 305, 308},
{0, 0, 0, 0, 138, 0, 200, 231, 251, 279, 293, 298, 302, 308, 312},
{0, 0, 0, 0, 217, 0, 429, 634, 834, 1220, 1585, 1760, 1931, 2258, 2466},
{0, 0, 0, 0, 241, 0, 475, 701, 921, 1343, 1741, 1931, 2117, 2468, 2691},
};
-static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = {
+static const u16 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = {
{0, 0, 0, 0, 74, 0, 123, 155, 179, 213, 235, 243, 250, 261, 0},
{0, 0, 0, 0, 81, 0, 131, 164, 187, 221, 242, 250, 256, 267, 0},
{0, 0, 0, 0, 98, 0, 193, 286, 375, 550, 718, 799, 878, 1032, 0},
{0, 0, 0, 0, 109, 0, 214, 316, 414, 607, 790, 879, 965, 1132, 0},
};
-static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = {
+static const u16 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = {
{0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289, 296, 300},
{0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293, 300, 303},
{0, 0, 0, 0, 200, 0, 390, 571, 741, 1067, 1365, 1505, 1640, 1894, 2053},
{0, 0, 0, 0, 221, 0, 430, 630, 816, 1169, 1490, 1641, 1784, 2053, 2221},
};
-static s32 expected_tpt_mimo2_80MHz[4][IWL_RATE_COUNT] = {
+static const u16 expected_tpt_mimo2_80MHz[4][IWL_RATE_COUNT] = {
{0, 0, 0, 0, 182, 0, 240, 264, 278, 299, 308, 311, 313, 317, 319},
{0, 0, 0, 0, 190, 0, 247, 269, 282, 302, 310, 313, 315, 319, 320},
{0, 0, 0, 0, 428, 0, 833, 1215, 1577, 2254, 2863, 3147, 3418, 3913, 4219},
@@ -503,6 +503,14 @@ static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
window->average_tpt = IWL_INVALID_VALUE;
}
+static void rs_rate_scale_clear_tbl_windows(struct iwl_scale_tbl_info *tbl)
+{
+ int i;
+
+ for (i = 0; i < IWL_RATE_COUNT; i++)
+ rs_rate_scale_clear_window(&tbl->win[i]);
+}
+
static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type)
{
return (ant_type & valid_antenna) == ant_type;
@@ -566,19 +574,13 @@ static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index)
* at this rate. window->data contains the bitmask of successful
* packets.
*/
-static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
- int scale_index, int attempts, int successes)
+static int _rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
+ int scale_index, int attempts, int successes,
+ struct iwl_rate_scale_data *window)
{
- struct iwl_rate_scale_data *window = NULL;
static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1));
s32 fail_count, tpt;
- if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
- return -EINVAL;
-
- /* Select window for current tx bit rate */
- window = &(tbl->win[scale_index]);
-
/* Get expected throughput */
tpt = get_expected_tpt(tbl, scale_index);
@@ -636,6 +638,21 @@ static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
return 0;
}
+static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
+ int scale_index, int attempts, int successes)
+{
+ struct iwl_rate_scale_data *window = NULL;
+
+ if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
+ return -EINVAL;
+
+ /* Select window for current tx bit rate */
+ window = &(tbl->win[scale_index]);
+
+ return _rs_collect_tx_data(tbl, scale_index, attempts, successes,
+ window);
+}
+
/* Convert rs_rate object into ucode rate bitmask */
static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm,
struct rs_rate *rate)
@@ -905,7 +922,7 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta,
rate->bw = RATE_MCS_CHAN_WIDTH_20;
- WARN_ON_ONCE(rate->index < IWL_RATE_MCS_0_INDEX &&
+ WARN_ON_ONCE(rate->index < IWL_RATE_MCS_0_INDEX ||
rate->index > IWL_RATE_MCS_9_INDEX);
rate->index = rs_ht_to_legacy[rate->index];
@@ -917,7 +934,7 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta,
if (num_of_ant(rate->ant) > 1)
- rate->ant = first_antenna(iwl_fw_valid_tx_ant(mvm->fw));
+ rate->ant = first_antenna(mvm->fw->valid_tx_ant);
/* Relevant in both switching to SISO or Legacy */
rate->sgi = false;
@@ -1169,12 +1186,12 @@ static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy,
lq_sta->visited_columns = 0;
}
-static s32 *rs_get_expected_tpt_table(struct iwl_lq_sta *lq_sta,
+static const u16 *rs_get_expected_tpt_table(struct iwl_lq_sta *lq_sta,
const struct rs_tx_column *column,
u32 bw)
{
/* Used to choose among HT tables */
- s32 (*ht_tbl_pointer)[IWL_RATE_COUNT];
+ const u16 (*ht_tbl_pointer)[IWL_RATE_COUNT];
if (WARN_ON_ONCE(column->mode != RS_LEGACY &&
column->mode != RS_SISO &&
@@ -1262,9 +1279,8 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm,
&(lq_sta->lq_info[lq_sta->active_tbl]);
s32 active_sr = active_tbl->win[index].success_ratio;
s32 active_tpt = active_tbl->expected_tpt[index];
-
/* expected "search" throughput */
- s32 *tpt_tbl = tbl->expected_tpt;
+ const u16 *tpt_tbl = tbl->expected_tpt;
s32 new_rate, high, low, start_hi;
u16 high_low;
@@ -1362,7 +1378,6 @@ static u32 rs_bw_from_sta_bw(struct ieee80211_sta *sta)
static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
{
struct iwl_scale_tbl_info *tbl;
- int i;
int active_tbl;
int flush_interval_passed = 0;
struct iwl_mvm *mvm;
@@ -1423,9 +1438,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
IWL_DEBUG_RATE(mvm,
"LQ: stay in table clear win\n");
- for (i = 0; i < IWL_RATE_COUNT; i++)
- rs_rate_scale_clear_window(
- &(tbl->win[i]));
+ rs_rate_scale_clear_tbl_windows(tbl);
}
}
@@ -1434,8 +1447,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
* "search" table). */
if (lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_STARTED) {
IWL_DEBUG_RATE(mvm, "Clearing up window stats\n");
- for (i = 0; i < IWL_RATE_COUNT; i++)
- rs_rate_scale_clear_window(&(tbl->win[i]));
+ rs_rate_scale_clear_tbl_windows(tbl);
}
}
}
@@ -1478,8 +1490,8 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,
const struct rs_tx_column *curr_col = &rs_tx_columns[tbl->column];
const struct rs_tx_column *next_col;
allow_column_func_t allow_func;
- u8 valid_ants = iwl_fw_valid_tx_ant(mvm->fw);
- s32 *expected_tpt_tbl;
+ u8 valid_ants = mvm->fw->valid_tx_ant;
+ const u16 *expected_tpt_tbl;
s32 tpt, max_expected_tpt;
for (i = 0; i < MAX_NEXT_COLUMNS; i++) {
@@ -1725,7 +1737,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
int low = IWL_RATE_INVALID;
int high = IWL_RATE_INVALID;
int index;
- int i;
struct iwl_rate_scale_data *window = NULL;
int current_tpt = IWL_INVALID_VALUE;
int low_tpt = IWL_INVALID_VALUE;
@@ -2010,8 +2021,7 @@ lq_update:
if (lq_sta->search_better_tbl) {
/* Access the "search" table, clear its history. */
tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
- for (i = 0; i < IWL_RATE_COUNT; i++)
- rs_rate_scale_clear_window(&(tbl->win[i]));
+ rs_rate_scale_clear_tbl_windows(tbl);
/* Use new "search" start rate */
index = tbl->rate.index;
@@ -2090,7 +2100,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
i = lq_sta->last_txrate_idx;
- valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
+ valid_tx_ant = mvm->fw->valid_tx_ant;
if (!lq_sta->search_better_tbl)
active_tbl = lq_sta->active_tbl;
@@ -2241,6 +2251,73 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta,
}
}
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+static void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm,
+ struct iwl_mvm_frame_stats *stats)
+{
+ spin_lock_bh(&mvm->drv_stats_lock);
+ memset(stats, 0, sizeof(*stats));
+ spin_unlock_bh(&mvm->drv_stats_lock);
+}
+
+void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm,
+ struct iwl_mvm_frame_stats *stats,
+ u32 rate, bool agg)
+{
+ u8 nss = 0, mcs = 0;
+
+ spin_lock(&mvm->drv_stats_lock);
+
+ if (agg)
+ stats->agg_frames++;
+
+ stats->success_frames++;
+
+ switch (rate & RATE_MCS_CHAN_WIDTH_MSK) {
+ case RATE_MCS_CHAN_WIDTH_20:
+ stats->bw_20_frames++;
+ break;
+ case RATE_MCS_CHAN_WIDTH_40:
+ stats->bw_40_frames++;
+ break;
+ case RATE_MCS_CHAN_WIDTH_80:
+ stats->bw_80_frames++;
+ break;
+ default:
+ WARN_ONCE(1, "bad BW. rate 0x%x", rate);
+ }
+
+ if (rate & RATE_MCS_HT_MSK) {
+ stats->ht_frames++;
+ mcs = rate & RATE_HT_MCS_RATE_CODE_MSK;
+ nss = ((rate & RATE_HT_MCS_NSS_MSK) >> RATE_HT_MCS_NSS_POS) + 1;
+ } else if (rate & RATE_MCS_VHT_MSK) {
+ stats->vht_frames++;
+ mcs = rate & RATE_VHT_MCS_RATE_CODE_MSK;
+ nss = ((rate & RATE_VHT_MCS_NSS_MSK) >>
+ RATE_VHT_MCS_NSS_POS) + 1;
+ } else {
+ stats->legacy_frames++;
+ }
+
+ if (nss == 1)
+ stats->siso_frames++;
+ else if (nss == 2)
+ stats->mimo2_frames++;
+
+ if (rate & RATE_MCS_SGI_MSK)
+ stats->sgi_frames++;
+ else
+ stats->ngi_frames++;
+
+ stats->last_rates[stats->last_frame_idx] = rate;
+ stats->last_frame_idx = (stats->last_frame_idx + 1) %
+ ARRAY_SIZE(stats->last_rates);
+
+ spin_unlock(&mvm->drv_stats_lock);
+}
+#endif
+
/*
* Called after adding a new station to initialize rate scaling
*/
@@ -2265,8 +2342,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
lq_sta->lq.sta_id = sta_priv->sta_id;
for (j = 0; j < LQ_SIZE; j++)
- for (i = 0; i < IWL_RATE_COUNT; i++)
- rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
+ rs_rate_scale_clear_tbl_windows(&lq_sta->lq_info[j]);
lq_sta->flush_timer = 0;
@@ -2320,7 +2396,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
/* These values will be overridden later */
lq_sta->lq.single_stream_ant_msk =
- first_antenna(iwl_fw_valid_tx_ant(mvm->fw));
+ first_antenna(mvm->fw->valid_tx_ant);
lq_sta->lq.dual_stream_ant_msk = ANT_AB;
/* as default allow aggregation for all tids */
@@ -2335,7 +2411,9 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
#ifdef CONFIG_MAC80211_DEBUGFS
lq_sta->dbg_fixed_rate = 0;
#endif
-
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ iwl_mvm_reset_frame_stats(mvm, &mvm->drv_rx_stats);
+#endif
rs_initialize_lq(mvm, sta, lq_sta, band, init);
}
@@ -2446,7 +2524,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
memcpy(&rate, initial_rate, sizeof(rate));
- valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
+ valid_tx_ant = mvm->fw->valid_tx_ant;
if (is_siso(&rate)) {
num_rates = RS_INITIAL_SISO_NUM_RATES;
@@ -2523,7 +2601,7 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
if (sta)
lq_cmd->agg_time_limit =
- cpu_to_le16(iwl_mvm_bt_coex_agg_time_limit(mvm, sta));
+ cpu_to_le16(iwl_mvm_coex_agg_time_limit(mvm, sta));
}
static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
@@ -2547,7 +2625,7 @@ static void rs_free_sta(void *mvm_r, struct ieee80211_sta *sta,
}
#ifdef CONFIG_MAC80211_DEBUGFS
-static int rs_pretty_print_rate(char *buf, const u32 rate)
+int rs_pretty_print_rate(char *buf, const u32 rate)
{
char *type, *bw;
@@ -2596,7 +2674,7 @@ static int rs_pretty_print_rate(char *buf, const u32 rate)
return sprintf(buf, "%s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s%s\n",
type, rs_pretty_ant(ant), bw, mcs, nss,
(rate & RATE_MCS_SGI_MSK) ? "SGI " : "NGI ",
- (rate & RATE_MCS_STBC_MSK) ? "STBC " : "",
+ (rate & RATE_MCS_HT_STBC_MSK) ? "STBC " : "",
(rate & RATE_MCS_LDPC_MSK) ? "LDPC " : "",
(rate & RATE_MCS_BF_MSK) ? "BF " : "",
(rate & RATE_MCS_ZLF_MSK) ? "ZLF " : "");
@@ -2677,9 +2755,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
desc += sprintf(buff+desc, "fixed rate 0x%X\n",
lq_sta->dbg_fixed_rate);
desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
- (iwl_fw_valid_tx_ant(mvm->fw) & ANT_A) ? "ANT_A," : "",
- (iwl_fw_valid_tx_ant(mvm->fw) & ANT_B) ? "ANT_B," : "",
- (iwl_fw_valid_tx_ant(mvm->fw) & ANT_C) ? "ANT_C" : "");
+ (mvm->fw->valid_tx_ant & ANT_A) ? "ANT_A," : "",
+ (mvm->fw->valid_tx_ant & ANT_B) ? "ANT_B," : "",
+ (mvm->fw->valid_tx_ant & ANT_C) ? "ANT_C" : "");
desc += sprintf(buff+desc, "lq type %s\n",
(is_legacy(rate)) ? "legacy" :
is_vht(rate) ? "VHT" : "HT");
@@ -2815,8 +2893,8 @@ static void rs_rate_init_stub(void *mvm_r,
struct ieee80211_sta *sta, void *mvm_sta)
{
}
-static struct rate_control_ops rs_mvm_ops = {
- .module = NULL,
+
+static const struct rate_control_ops rs_mvm_ops = {
.name = RS_NAME,
.tx_status = rs_tx_status,
.get_rate = rs_get_rate,
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h
index 7bc6404f6986..3332b396011e 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.h
@@ -277,7 +277,7 @@ enum rs_column {
struct iwl_scale_tbl_info {
struct rs_rate rate;
enum rs_column column;
- s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
+ const u16 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
};
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
index a85b60f7e67e..6061553a5e44 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -77,6 +77,15 @@ int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
memcpy(&mvm->last_phy_info, pkt->data, sizeof(mvm->last_phy_info));
mvm->ampdu_ref++;
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ if (mvm->last_phy_info.phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) {
+ spin_lock(&mvm->drv_stats_lock);
+ mvm->drv_rx_stats.ampdu_count++;
+ spin_unlock(&mvm->drv_stats_lock);
+ }
+#endif
+
return 0;
}
@@ -129,22 +138,16 @@ static void iwl_mvm_calc_rssi(struct iwl_mvm *mvm,
struct ieee80211_rx_status *rx_status)
{
int rssi_a, rssi_b, rssi_a_dbm, rssi_b_dbm, max_rssi_dbm;
- int rssi_all_band_a, rssi_all_band_b;
- u32 agc_a, agc_b, max_agc;
+ u32 agc_a, agc_b;
u32 val;
val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]);
agc_a = (val & IWL_OFDM_AGC_A_MSK) >> IWL_OFDM_AGC_A_POS;
agc_b = (val & IWL_OFDM_AGC_B_MSK) >> IWL_OFDM_AGC_B_POS;
- max_agc = max_t(u32, agc_a, agc_b);
val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_AB_IDX]);
rssi_a = (val & IWL_OFDM_RSSI_INBAND_A_MSK) >> IWL_OFDM_RSSI_A_POS;
rssi_b = (val & IWL_OFDM_RSSI_INBAND_B_MSK) >> IWL_OFDM_RSSI_B_POS;
- rssi_all_band_a = (val & IWL_OFDM_RSSI_ALLBAND_A_MSK) >>
- IWL_OFDM_RSSI_ALLBAND_A_POS;
- rssi_all_band_b = (val & IWL_OFDM_RSSI_ALLBAND_B_MSK) >>
- IWL_OFDM_RSSI_ALLBAND_B_POS;
/*
* dBm = rssi dB - agc dB - constant.
@@ -364,31 +367,43 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
rx_status.flag |= RX_FLAG_40MHZ;
break;
case RATE_MCS_CHAN_WIDTH_80:
- rx_status.flag |= RX_FLAG_80MHZ;
+ rx_status.vht_flag |= RX_VHT_FLAG_80MHZ;
break;
case RATE_MCS_CHAN_WIDTH_160:
- rx_status.flag |= RX_FLAG_160MHZ;
+ rx_status.vht_flag |= RX_VHT_FLAG_160MHZ;
break;
}
if (rate_n_flags & RATE_MCS_SGI_MSK)
rx_status.flag |= RX_FLAG_SHORT_GI;
if (rate_n_flags & RATE_HT_MCS_GF_MSK)
rx_status.flag |= RX_FLAG_HT_GF;
+ if (rate_n_flags & RATE_MCS_LDPC_MSK)
+ rx_status.flag |= RX_FLAG_LDPC;
if (rate_n_flags & RATE_MCS_HT_MSK) {
+ u8 stbc = (rate_n_flags & RATE_MCS_HT_STBC_MSK) >>
+ RATE_MCS_STBC_POS;
rx_status.flag |= RX_FLAG_HT;
rx_status.rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK;
+ rx_status.flag |= stbc << RX_FLAG_STBC_SHIFT;
} else if (rate_n_flags & RATE_MCS_VHT_MSK) {
+ u8 stbc = (rate_n_flags & RATE_MCS_VHT_STBC_MSK) >>
+ RATE_MCS_STBC_POS;
rx_status.vht_nss =
((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>
RATE_VHT_MCS_NSS_POS) + 1;
rx_status.rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK;
rx_status.flag |= RX_FLAG_VHT;
+ rx_status.flag |= stbc << RX_FLAG_STBC_SHIFT;
} else {
rx_status.rate_idx =
iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags,
rx_status.band);
}
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ iwl_mvm_update_frame_stats(mvm, &mvm->drv_rx_stats, rate_n_flags,
+ rx_status.flag & RX_FLAG_AMPDU_DETAILS);
+#endif
iwl_mvm_pass_packet_to_mac80211(mvm, hdr, len, ampdu_status,
rxb, &rx_status);
return 0;
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
index 0e0007960612..c91dc8498852 100644
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -70,9 +70,16 @@
#define IWL_PLCP_QUIET_THRESH 1
#define IWL_ACTIVE_QUIET_TIME 10
-#define LONG_OUT_TIME_PERIOD 600
-#define SHORT_OUT_TIME_PERIOD 200
-#define SUSPEND_TIME_PERIOD 100
+
+struct iwl_mvm_scan_params {
+ u32 max_out_time;
+ u32 suspend_time;
+ bool passive_fragmented;
+ struct _dwell {
+ u16 passive;
+ u16 active;
+ } dwell[IEEE80211_NUM_BANDS];
+};
static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm)
{
@@ -82,7 +89,7 @@ static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm)
if (mvm->scan_rx_ant != ANT_NONE)
rx_ant = mvm->scan_rx_ant;
else
- rx_ant = iwl_fw_valid_rx_ant(mvm->fw);
+ rx_ant = mvm->fw->valid_rx_ant;
rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS;
rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS;
rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_SEL_POS;
@@ -90,24 +97,6 @@ static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm)
return cpu_to_le16(rx_chain);
}
-static inline __le32 iwl_mvm_scan_max_out_time(struct ieee80211_vif *vif,
- u32 flags, bool is_assoc)
-{
- if (!is_assoc)
- return 0;
- if (flags & NL80211_SCAN_FLAG_LOW_PRIORITY)
- return cpu_to_le32(ieee80211_tu_to_usec(SHORT_OUT_TIME_PERIOD));
- return cpu_to_le32(ieee80211_tu_to_usec(LONG_OUT_TIME_PERIOD));
-}
-
-static inline __le32 iwl_mvm_scan_suspend_time(struct ieee80211_vif *vif,
- bool is_assoc)
-{
- if (!is_assoc)
- return 0;
- return cpu_to_le32(ieee80211_tu_to_usec(SUSPEND_TIME_PERIOD));
-}
-
static inline __le32
iwl_mvm_scan_rxon_flags(struct cfg80211_scan_request *req)
{
@@ -124,7 +113,7 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band,
u32 tx_ant;
mvm->scan_last_antenna_idx =
- iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw),
+ iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant,
mvm->scan_last_antenna_idx);
tx_ant = BIT(mvm->scan_last_antenna_idx) << RATE_MCS_ANT_POS;
@@ -181,15 +170,14 @@ static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band)
static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
struct cfg80211_scan_request *req,
- bool basic_ssid)
+ bool basic_ssid,
+ struct iwl_mvm_scan_params *params)
{
- u16 passive_dwell = iwl_mvm_get_passive_dwell(req->channels[0]->band);
- u16 active_dwell = iwl_mvm_get_active_dwell(req->channels[0]->band,
- req->n_ssids);
struct iwl_scan_channel *chan = (struct iwl_scan_channel *)
(cmd->data + le16_to_cpu(cmd->tx_cmd.len));
int i;
int type = BIT(req->n_ssids) - 1;
+ enum ieee80211_band band = req->channels[0]->band;
if (!basic_ssid)
type |= BIT(req->n_ssids);
@@ -199,8 +187,8 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
chan->type = cpu_to_le32(type);
if (req->channels[i]->flags & IEEE80211_CHAN_NO_IR)
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->active_dwell = cpu_to_le16(params->dwell[band].active);
+ chan->passive_dwell = cpu_to_le16(params->dwell[band].passive);
chan->iteration_count = cpu_to_le16(1);
chan++;
}
@@ -267,13 +255,76 @@ static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
return (u16)len;
}
-static void iwl_mvm_vif_assoc_iterator(void *data, u8 *mac,
- struct ieee80211_vif *vif)
+static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
{
- bool *is_assoc = data;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ bool *global_bound = data;
+
+ if (mvmvif->phy_ctxt && mvmvif->phy_ctxt->id < MAX_PHYS)
+ *global_bound = true;
+}
+
+static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ int n_ssids,
+ struct iwl_mvm_scan_params *params)
+{
+ bool global_bound = false;
+ enum ieee80211_band band;
+
+ ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_scan_condition_iterator,
+ &global_bound);
+ /*
+ * Under low latency traffic passive scan is fragmented meaning
+ * that dwell on a particular channel will be fragmented. Each fragment
+ * dwell time is 20ms and fragments period is 105ms. Skipping to next
+ * channel will be delayed by the same period - 105ms. So suspend_time
+ * parameter describing both fragments and channels skipping periods is
+ * set to 105ms. This value is chosen so that overall passive scan
+ * duration will not be too long. Max_out_time in this case is set to
+ * 70ms, so for active scanning operating channel will be left for 70ms
+ * while for passive still for 20ms (fragment dwell).
+ */
+ if (global_bound) {
+ if (!iwl_mvm_low_latency(mvm)) {
+ params->suspend_time = ieee80211_tu_to_usec(100);
+ params->max_out_time = ieee80211_tu_to_usec(600);
+ } else {
+ params->suspend_time = ieee80211_tu_to_usec(105);
+ /* P2P doesn't support fragmented passive scan, so
+ * configure max_out_time to be at least longest dwell
+ * time for passive scan.
+ */
+ if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p) {
+ params->max_out_time = ieee80211_tu_to_usec(70);
+ params->passive_fragmented = true;
+ } else {
+ u32 passive_dwell;
- if (vif->bss_conf.assoc)
- *is_assoc = true;
+ /*
+ * Use band G so that passive channel dwell time
+ * will be assigned with maximum value.
+ */
+ band = IEEE80211_BAND_2GHZ;
+ passive_dwell = iwl_mvm_get_passive_dwell(band);
+ params->max_out_time =
+ ieee80211_tu_to_usec(passive_dwell);
+ }
+ }
+ }
+
+ for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) {
+ if (params->passive_fragmented)
+ params->dwell[band].passive = 20;
+ else
+ params->dwell[band].passive =
+ iwl_mvm_get_passive_dwell(band);
+ params->dwell[band].active = iwl_mvm_get_active_dwell(band,
+ n_ssids);
+ }
}
int iwl_mvm_scan_request(struct iwl_mvm *mvm,
@@ -288,13 +339,13 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
.dataflags = { IWL_HCMD_DFL_NOCOPY, },
};
struct iwl_scan_cmd *cmd = mvm->scan_cmd;
- bool is_assoc = false;
int ret;
u32 status;
int ssid_len = 0;
u8 *ssid = NULL;
bool basic_ssid = !(mvm->fw->ucode_capa.flags &
IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID);
+ struct iwl_mvm_scan_params params = {};
lockdep_assert_held(&mvm->mutex);
BUG_ON(mvm->scan_cmd == NULL);
@@ -304,17 +355,18 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
memset(cmd, 0, sizeof(struct iwl_scan_cmd) +
mvm->fw->ucode_capa.max_probe_length +
(MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel)));
- ieee80211_iterate_active_interfaces_atomic(mvm->hw,
- IEEE80211_IFACE_ITER_NORMAL,
- iwl_mvm_vif_assoc_iterator,
- &is_assoc);
+
cmd->channel_count = (u8)req->n_channels;
cmd->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME);
cmd->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH);
cmd->rxchain_sel_flags = iwl_mvm_scan_rx_chain(mvm);
- cmd->max_out_time = iwl_mvm_scan_max_out_time(vif, req->flags,
- is_assoc);
- cmd->suspend_time = iwl_mvm_scan_suspend_time(vif, is_assoc);
+
+ iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, &params);
+ cmd->max_out_time = cpu_to_le32(params.max_out_time);
+ cmd->suspend_time = cpu_to_le32(params.suspend_time);
+ if (params.passive_fragmented)
+ cmd->scan_flags |= SCAN_FLAGS_FRAGMENTED_SCAN;
+
cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req);
cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
MAC_FILTER_IN_BEACON);
@@ -344,7 +396,8 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
iwl_mvm_scan_fill_ssids(cmd, req, basic_ssid ? 1 : 0);
- cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL);
+ cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL |
+ TX_CMD_FLG_BT_DIS);
cmd->tx_cmd.sta_id = mvm->aux_sta.sta_id;
cmd->tx_cmd.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
cmd->tx_cmd.rate_n_flags =
@@ -359,7 +412,7 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
req->ie, req->ie_len,
mvm->fw->ucode_capa.max_probe_length));
- iwl_mvm_scan_fill_channels(cmd, req, basic_ssid);
+ iwl_mvm_scan_fill_channels(cmd, req, basic_ssid, &params);
cmd->len = cpu_to_le16(sizeof(struct iwl_scan_cmd) +
le16_to_cpu(cmd->tx_cmd.len) +
@@ -401,12 +454,17 @@ int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_scan_complete_notif *notif = (void *)pkt->data;
+ lockdep_assert_held(&mvm->mutex);
+
IWL_DEBUG_SCAN(mvm, "Scan complete: status=0x%x scanned channels=%d\n",
notif->status, notif->scanned_channels);
- mvm->scan_status = IWL_MVM_SCAN_NONE;
+ if (mvm->scan_status == IWL_MVM_SCAN_OS)
+ mvm->scan_status = IWL_MVM_SCAN_NONE;
ieee80211_scan_completed(mvm->hw, notif->status != SCAN_COMP_STATUS_OK);
+ iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
+
return 0;
}
@@ -463,7 +521,7 @@ static bool iwl_mvm_scan_abort_notif(struct iwl_notif_wait_data *notif_wait,
};
}
-void iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
+int iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
{
struct iwl_notification_wait wait_scan_abort;
static const u8 scan_abort_notif[] = { SCAN_ABORT_CMD,
@@ -471,12 +529,13 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
int ret;
if (mvm->scan_status == IWL_MVM_SCAN_NONE)
- return;
+ return 0;
if (iwl_mvm_is_radio_killed(mvm)) {
ieee80211_scan_completed(mvm->hw, true);
+ iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
mvm->scan_status = IWL_MVM_SCAN_NONE;
- return;
+ return 0;
}
iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort,
@@ -487,18 +546,15 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_CMD, CMD_SYNC, 0, NULL);
if (ret) {
IWL_ERR(mvm, "Couldn't send SCAN_ABORT_CMD: %d\n", ret);
- /* mac80211's state will be cleaned in the fw_restart flow */
+ /* mac80211's state will be cleaned in the nic_restart flow */
goto out_remove_notif;
}
- ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_abort, 1 * HZ);
- if (ret)
- IWL_ERR(mvm, "%s - failed on timeout\n", __func__);
-
- return;
+ return iwl_wait_notification(&mvm->notif_wait, &wait_scan_abort, HZ);
out_remove_notif:
iwl_remove_notification(&mvm->notif_wait, &wait_scan_abort);
+ return ret;
}
int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
@@ -508,12 +564,18 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_scan_offload_complete *scan_notif = (void *)pkt->data;
+ /* scan status must be locked for proper checking */
+ lockdep_assert_held(&mvm->mutex);
+
IWL_DEBUG_SCAN(mvm, "Scheduled scan completed, status %s\n",
scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ?
"completed" : "aborted");
- mvm->scan_status = IWL_MVM_SCAN_NONE;
- ieee80211_sched_scan_stopped(mvm->hw);
+ /* only call mac80211 completion if the stop was initiated by FW */
+ if (mvm->scan_status == IWL_MVM_SCAN_SCHED) {
+ mvm->scan_status = IWL_MVM_SCAN_NONE;
+ ieee80211_sched_scan_stopped(mvm->hw);
+ }
return 0;
}
@@ -544,14 +606,9 @@ static void iwl_scan_offload_build_tx_cmd(struct iwl_mvm *mvm,
static void iwl_build_scan_cmd(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct cfg80211_sched_scan_request *req,
- struct iwl_scan_offload_cmd *scan)
+ struct iwl_scan_offload_cmd *scan,
+ struct iwl_mvm_scan_params *params)
{
- bool is_assoc = false;
-
- ieee80211_iterate_active_interfaces_atomic(mvm->hw,
- IEEE80211_IFACE_ITER_NORMAL,
- iwl_mvm_vif_assoc_iterator,
- &is_assoc);
scan->channel_count =
mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels +
mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels;
@@ -559,13 +616,17 @@ static void iwl_build_scan_cmd(struct iwl_mvm *mvm,
scan->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH);
scan->good_CRC_th = IWL_GOOD_CRC_TH_DEFAULT;
scan->rx_chain = iwl_mvm_scan_rx_chain(mvm);
- scan->max_out_time = iwl_mvm_scan_max_out_time(vif, req->flags,
- is_assoc);
- scan->suspend_time = iwl_mvm_scan_suspend_time(vif, is_assoc);
+
+ scan->max_out_time = cpu_to_le32(params->max_out_time);
+ scan->suspend_time = cpu_to_le32(params->suspend_time);
+
scan->filter_flags |= cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
MAC_FILTER_IN_BEACON);
scan->scan_type = cpu_to_le32(SCAN_TYPE_BACKGROUND);
scan->rep_count = cpu_to_le32(1);
+
+ if (params->passive_fragmented)
+ scan->scan_flags |= SCAN_FLAGS_FRAGMENTED_SCAN;
}
static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list)
@@ -595,6 +656,9 @@ static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req,
* config match list.
*/
for (i = 0; i < req->n_match_sets && i < PROBE_OPTION_MAX; i++) {
+ /* skip empty SSID matchsets */
+ if (!req->match_sets[i].ssid.ssid_len)
+ continue;
scan->direct_scan[i].id = WLAN_EID_SSID;
scan->direct_scan[i].len = req->match_sets[i].ssid.ssid_len;
memcpy(scan->direct_scan[i].ssid, req->match_sets[i].ssid.ssid,
@@ -627,12 +691,11 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm,
struct iwl_scan_channel_cfg *channels,
enum ieee80211_band band,
int *head, int *tail,
- u32 ssid_bitmap)
+ u32 ssid_bitmap,
+ struct iwl_mvm_scan_params *params)
{
struct ieee80211_supported_band *s_band;
- int n_probes = req->n_ssids;
int n_channels = req->n_channels;
- u8 active_dwell, passive_dwell;
int i, j, index = 0;
bool partial;
@@ -642,8 +705,6 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm,
* to scan. So add requested channels to head of the list and others to
* the end.
*/
- active_dwell = iwl_mvm_get_active_dwell(band, n_probes);
- passive_dwell = iwl_mvm_get_passive_dwell(band);
s_band = &mvm->nvm_data->bands[band];
for (i = 0; i < s_band->n_channels && *head <= *tail; i++) {
@@ -667,8 +728,8 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm,
channels->channel_number[index] =
cpu_to_le16(ieee80211_frequency_to_channel(
s_band->channels[i].center_freq));
- channels->dwell_time[index][0] = active_dwell;
- channels->dwell_time[index][1] = passive_dwell;
+ channels->dwell_time[index][0] = params->dwell[band].active;
+ channels->dwell_time[index][1] = params->dwell[band].passive;
channels->iter_count[index] = cpu_to_le16(1);
channels->iter_interval[index] = 0;
@@ -697,7 +758,6 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
struct cfg80211_sched_scan_request *req,
struct ieee80211_sched_scan_ies *ies)
{
- int supported_bands = 0;
int band_2ghz = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels;
int band_5ghz = mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels;
int head = 0;
@@ -711,22 +771,19 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
.id = SCAN_OFFLOAD_CONFIG_CMD,
.flags = CMD_SYNC,
};
+ struct iwl_mvm_scan_params params = {};
lockdep_assert_held(&mvm->mutex);
- if (band_2ghz)
- supported_bands++;
- if (band_5ghz)
- supported_bands++;
-
cmd_len = sizeof(struct iwl_scan_offload_cfg) +
- supported_bands * SCAN_OFFLOAD_PROBE_REQ_SIZE;
+ 2 * SCAN_OFFLOAD_PROBE_REQ_SIZE;
scan_cfg = kzalloc(cmd_len, GFP_KERNEL);
if (!scan_cfg)
return -ENOMEM;
- iwl_build_scan_cmd(mvm, vif, req, &scan_cfg->scan_cmd);
+ iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, &params);
+ iwl_build_scan_cmd(mvm, vif, req, &scan_cfg->scan_cmd, &params);
scan_cfg->scan_cmd.len = cpu_to_le16(cmd_len);
iwl_scan_offload_build_ssid(req, &scan_cfg->scan_cmd, &ssid_bitmap);
@@ -738,7 +795,7 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
scan_cfg->data);
iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg,
IEEE80211_BAND_2GHZ, &head, &tail,
- ssid_bitmap);
+ ssid_bitmap, &params);
}
if (band_5ghz) {
iwl_scan_offload_build_tx_cmd(mvm, vif, ies,
@@ -748,7 +805,7 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
SCAN_OFFLOAD_PROBE_REQ_SIZE);
iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg,
IEEE80211_BAND_5GHZ, &head, &tail,
- ssid_bitmap);
+ ssid_bitmap, &params);
}
cmd.data[0] = scan_cfg;
@@ -807,6 +864,8 @@ int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
profile_cfg->active_clients = SCAN_CLIENT_SCHED_SCAN;
profile_cfg->pass_match = SCAN_CLIENT_SCHED_SCAN;
profile_cfg->match_notify = SCAN_CLIENT_SCHED_SCAN;
+ if (!req->n_match_sets || !req->match_sets[0].ssid.ssid_len)
+ profile_cfg->any_beacon_notify = SCAN_CLIENT_SCHED_SCAN;
for (i = 0; i < req->n_match_sets; i++) {
profile = &profile_cfg->profiles[i];
@@ -886,26 +945,49 @@ static int iwl_mvm_send_sched_scan_abort(struct iwl_mvm *mvm)
* microcode has notified us that a scan is completed.
*/
IWL_DEBUG_SCAN(mvm, "SCAN OFFLOAD ABORT ret %d.\n", status);
- ret = -EIO;
+ ret = -ENOENT;
}
return ret;
}
-void iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm)
+int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm)
{
int ret;
+ struct iwl_notification_wait wait_scan_done;
+ static const u8 scan_done_notif[] = { SCAN_OFFLOAD_COMPLETE, };
lockdep_assert_held(&mvm->mutex);
if (mvm->scan_status != IWL_MVM_SCAN_SCHED) {
IWL_DEBUG_SCAN(mvm, "No offloaded scan to stop\n");
- return;
+ return 0;
}
+ iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done,
+ scan_done_notif,
+ ARRAY_SIZE(scan_done_notif),
+ NULL, NULL);
+
ret = iwl_mvm_send_sched_scan_abort(mvm);
- if (ret)
+ if (ret) {
IWL_DEBUG_SCAN(mvm, "Send stop offload scan failed %d\n", ret);
- else
- IWL_DEBUG_SCAN(mvm, "Successfully sent stop offload scan\n");
+ iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
+ return ret;
+ }
+
+ IWL_DEBUG_SCAN(mvm, "Successfully sent stop offload scan\n");
+
+ ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ);
+ if (ret)
+ return ret;
+
+ /*
+ * Clear the scan status so the next scan requests will succeed. This
+ * also ensures the Rx handler doesn't do anything, as the scan was
+ * stopped from above.
+ */
+ mvm->scan_status = IWL_MVM_SCAN_NONE;
+
+ return 0;
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index ec1812133235..f339ef884250 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -66,27 +66,27 @@
#include "sta.h"
#include "rs.h"
-static void iwl_mvm_add_sta_cmd_v6_to_v5(struct iwl_mvm_add_sta_cmd_v6 *cmd_v6,
+static void iwl_mvm_add_sta_cmd_v7_to_v5(struct iwl_mvm_add_sta_cmd_v7 *cmd_v7,
struct iwl_mvm_add_sta_cmd_v5 *cmd_v5)
{
memset(cmd_v5, 0, sizeof(*cmd_v5));
- cmd_v5->add_modify = cmd_v6->add_modify;
- cmd_v5->tid_disable_tx = cmd_v6->tid_disable_tx;
- cmd_v5->mac_id_n_color = cmd_v6->mac_id_n_color;
- memcpy(cmd_v5->addr, cmd_v6->addr, ETH_ALEN);
- cmd_v5->sta_id = cmd_v6->sta_id;
- cmd_v5->modify_mask = cmd_v6->modify_mask;
- cmd_v5->station_flags = cmd_v6->station_flags;
- cmd_v5->station_flags_msk = cmd_v6->station_flags_msk;
- cmd_v5->add_immediate_ba_tid = cmd_v6->add_immediate_ba_tid;
- cmd_v5->remove_immediate_ba_tid = cmd_v6->remove_immediate_ba_tid;
- cmd_v5->add_immediate_ba_ssn = cmd_v6->add_immediate_ba_ssn;
- cmd_v5->sleep_tx_count = cmd_v6->sleep_tx_count;
- cmd_v5->sleep_state_flags = cmd_v6->sleep_state_flags;
- cmd_v5->assoc_id = cmd_v6->assoc_id;
- cmd_v5->beamform_flags = cmd_v6->beamform_flags;
- cmd_v5->tfd_queue_msk = cmd_v6->tfd_queue_msk;
+ cmd_v5->add_modify = cmd_v7->add_modify;
+ cmd_v5->tid_disable_tx = cmd_v7->tid_disable_tx;
+ cmd_v5->mac_id_n_color = cmd_v7->mac_id_n_color;
+ memcpy(cmd_v5->addr, cmd_v7->addr, ETH_ALEN);
+ cmd_v5->sta_id = cmd_v7->sta_id;
+ cmd_v5->modify_mask = cmd_v7->modify_mask;
+ cmd_v5->station_flags = cmd_v7->station_flags;
+ cmd_v5->station_flags_msk = cmd_v7->station_flags_msk;
+ cmd_v5->add_immediate_ba_tid = cmd_v7->add_immediate_ba_tid;
+ cmd_v5->remove_immediate_ba_tid = cmd_v7->remove_immediate_ba_tid;
+ cmd_v5->add_immediate_ba_ssn = cmd_v7->add_immediate_ba_ssn;
+ cmd_v5->sleep_tx_count = cmd_v7->sleep_tx_count;
+ cmd_v5->sleep_state_flags = cmd_v7->sleep_state_flags;
+ cmd_v5->assoc_id = cmd_v7->assoc_id;
+ cmd_v5->beamform_flags = cmd_v7->beamform_flags;
+ cmd_v5->tfd_queue_msk = cmd_v7->tfd_queue_msk;
}
static void
@@ -110,7 +110,7 @@ iwl_mvm_add_sta_key_to_add_sta_cmd_v5(struct iwl_mvm_add_sta_key_cmd *key_cmd,
}
static int iwl_mvm_send_add_sta_cmd_status(struct iwl_mvm *mvm,
- struct iwl_mvm_add_sta_cmd_v6 *cmd,
+ struct iwl_mvm_add_sta_cmd_v7 *cmd,
int *status)
{
struct iwl_mvm_add_sta_cmd_v5 cmd_v5;
@@ -119,14 +119,14 @@ static int iwl_mvm_send_add_sta_cmd_status(struct iwl_mvm *mvm,
return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(*cmd),
cmd, status);
- iwl_mvm_add_sta_cmd_v6_to_v5(cmd, &cmd_v5);
+ iwl_mvm_add_sta_cmd_v7_to_v5(cmd, &cmd_v5);
return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd_v5),
&cmd_v5, status);
}
static int iwl_mvm_send_add_sta_cmd(struct iwl_mvm *mvm, u32 flags,
- struct iwl_mvm_add_sta_cmd_v6 *cmd)
+ struct iwl_mvm_add_sta_cmd_v7 *cmd)
{
struct iwl_mvm_add_sta_cmd_v5 cmd_v5;
@@ -134,7 +134,7 @@ static int iwl_mvm_send_add_sta_cmd(struct iwl_mvm *mvm, u32 flags,
return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags,
sizeof(*cmd), cmd);
- iwl_mvm_add_sta_cmd_v6_to_v5(cmd, &cmd_v5);
+ iwl_mvm_add_sta_cmd_v7_to_v5(cmd, &cmd_v5);
return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, sizeof(cmd_v5),
&cmd_v5);
@@ -175,19 +175,30 @@ static int iwl_mvm_send_add_sta_key_cmd(struct iwl_mvm *mvm,
&sta_cmd);
}
-static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm)
+static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm,
+ enum nl80211_iftype iftype)
{
int sta_id;
+ u32 reserved_ids = 0;
+ BUILD_BUG_ON(IWL_MVM_STATION_COUNT > 32);
WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status));
lockdep_assert_held(&mvm->mutex);
+ /* d0i3/d3 assumes the AP's sta_id (of sta vif) is 0. reserve it. */
+ if (iftype != NL80211_IFTYPE_STATION)
+ reserved_ids = BIT(0);
+
/* Don't take rcu_read_lock() since we are protected by mvm->mutex */
- for (sta_id = 0; sta_id < IWL_MVM_STATION_COUNT; sta_id++)
+ for (sta_id = 0; sta_id < IWL_MVM_STATION_COUNT; sta_id++) {
+ if (BIT(sta_id) & reserved_ids)
+ continue;
+
if (!rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
lockdep_is_held(&mvm->mutex)))
return sta_id;
+ }
return IWL_MVM_STATION_COUNT;
}
@@ -196,7 +207,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
bool update)
{
struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
- struct iwl_mvm_add_sta_cmd_v6 add_sta_cmd;
+ struct iwl_mvm_add_sta_cmd_v7 add_sta_cmd;
int ret;
u32 status;
u32 agg_size = 0, mpdu_dens = 0;
@@ -312,7 +323,8 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
lockdep_assert_held(&mvm->mutex);
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
- sta_id = iwl_mvm_find_free_sta_id(mvm);
+ sta_id = iwl_mvm_find_free_sta_id(mvm,
+ ieee80211_vif_type_p2p(vif));
else
sta_id = mvm_sta->sta_id;
@@ -368,7 +380,7 @@ int iwl_mvm_update_sta(struct iwl_mvm *mvm,
int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
bool drain)
{
- struct iwl_mvm_add_sta_cmd_v6 cmd = {};
+ struct iwl_mvm_add_sta_cmd_v7 cmd = {};
int ret;
u32 status;
@@ -522,6 +534,10 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
/* unassoc - go ahead - remove the AP STA now */
mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
+
+ /* clear d0i3_ap_sta_id if no longer relevant */
+ if (mvm->d0i3_ap_sta_id == mvm_sta->sta_id)
+ mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
}
/*
@@ -560,10 +576,10 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm,
}
int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,
- u32 qmask)
+ u32 qmask, enum nl80211_iftype iftype)
{
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
- sta->sta_id = iwl_mvm_find_free_sta_id(mvm);
+ sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype);
if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_STATION_COUNT))
return -ENOSPC;
}
@@ -587,13 +603,13 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm,
const u8 *addr,
u16 mac_id, u16 color)
{
- struct iwl_mvm_add_sta_cmd_v6 cmd;
+ struct iwl_mvm_add_sta_cmd_v7 cmd;
int ret;
u32 status;
lockdep_assert_held(&mvm->mutex);
- memset(&cmd, 0, sizeof(struct iwl_mvm_add_sta_cmd_v6));
+ memset(&cmd, 0, sizeof(struct iwl_mvm_add_sta_cmd_v7));
cmd.sta_id = sta->sta_id;
cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id,
color));
@@ -627,7 +643,8 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
lockdep_assert_held(&mvm->mutex);
/* Add the aux station, but without any queues */
- ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, 0);
+ ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, 0,
+ NL80211_IFTYPE_UNSPECIFIED);
if (ret)
return ret;
@@ -652,7 +669,7 @@ int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
static const u8 _baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
- static const u8 *baddr = _baddr;
+ const u8 *baddr = _baddr;
lockdep_assert_held(&mvm->mutex);
@@ -699,7 +716,8 @@ int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
lockdep_assert_held(&mvm->mutex);
qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
- ret = iwl_mvm_allocate_int_sta(mvm, bsta, qmask);
+ ret = iwl_mvm_allocate_int_sta(mvm, bsta, qmask,
+ ieee80211_vif_type_p2p(vif));
if (ret)
return ret;
@@ -735,7 +753,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
int tid, u16 ssn, bool start)
{
struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
- struct iwl_mvm_add_sta_cmd_v6 cmd = {};
+ struct iwl_mvm_add_sta_cmd_v7 cmd = {};
int ret;
u32 status;
@@ -794,7 +812,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
int tid, u8 queue, bool start)
{
struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
- struct iwl_mvm_add_sta_cmd_v6 cmd = {};
+ struct iwl_mvm_add_sta_cmd_v7 cmd = {};
int ret;
u32 status;
@@ -833,7 +851,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
return ret;
}
-static const u8 tid_to_ac[] = {
+const u8 tid_to_mac80211_ac[] = {
IEEE80211_AC_BE,
IEEE80211_AC_BK,
IEEE80211_AC_BK,
@@ -844,6 +862,17 @@ static const u8 tid_to_ac[] = {
IEEE80211_AC_VO,
};
+static const u8 tid_to_ucode_ac[] = {
+ AC_BE,
+ AC_BK,
+ AC_BK,
+ AC_BE,
+ AC_VI,
+ AC_VI,
+ AC_VO,
+ AC_VO,
+};
+
int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
{
@@ -873,10 +902,18 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
return -EIO;
}
+ spin_lock_bh(&mvmsta->lock);
+
+ /* possible race condition - we entered D0i3 while starting agg */
+ if (test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status)) {
+ spin_unlock_bh(&mvmsta->lock);
+ IWL_ERR(mvm, "Entered D0i3 while starting Tx agg\n");
+ return -EIO;
+ }
+
/* the new tx queue is still connected to the same mac80211 queue */
- mvm->queue_to_mac80211[txq_id] = vif->hw_queue[tid_to_ac[tid]];
+ mvm->queue_to_mac80211[txq_id] = vif->hw_queue[tid_to_mac80211_ac[tid]];
- spin_lock_bh(&mvmsta->lock);
tid_data = &mvmsta->tid_data[tid];
tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
tid_data->txq_id = txq_id;
@@ -916,7 +953,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
tid_data->ssn = 0xffff;
spin_unlock_bh(&mvmsta->lock);
- fifo = iwl_mvm_ac_to_tx_fifo[tid_to_ac[tid]];
+ fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]];
ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true);
if (ret)
@@ -1411,7 +1448,7 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
struct ieee80211_sta *sta)
{
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
- struct iwl_mvm_add_sta_cmd_v6 cmd = {
+ struct iwl_mvm_add_sta_cmd_v7 cmd = {
.add_modify = STA_MODE_MODIFY,
.sta_id = mvmsta->sta_id,
.station_flags_msk = cpu_to_le32(STA_FLG_PS),
@@ -1427,28 +1464,102 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
enum ieee80211_frame_release_type reason,
- u16 cnt)
+ u16 cnt, u16 tids, bool more_data,
+ bool agg)
{
- u16 sleep_state_flags =
- (reason == IEEE80211_FRAME_RELEASE_UAPSD) ?
- STA_SLEEP_STATE_UAPSD : STA_SLEEP_STATE_PS_POLL;
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
- struct iwl_mvm_add_sta_cmd_v6 cmd = {
+ struct iwl_mvm_add_sta_cmd_v7 cmd = {
.add_modify = STA_MODE_MODIFY,
.sta_id = mvmsta->sta_id,
.modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT,
.sleep_tx_count = cpu_to_le16(cnt),
.mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color),
- /*
- * Same modify mask for sleep_tx_count and sleep_state_flags so
- * we must set the sleep_state_flags too.
- */
- .sleep_state_flags = cpu_to_le16(sleep_state_flags),
};
- int ret;
+ int tid, ret;
+ unsigned long _tids = tids;
+
+ /* convert TIDs to ACs - we don't support TSPEC so that's OK
+ * Note that this field is reserved and unused by firmware not
+ * supporting GO uAPSD, so it's safe to always do this.
+ */
+ for_each_set_bit(tid, &_tids, IWL_MAX_TID_COUNT)
+ cmd.awake_acs |= BIT(tid_to_ucode_ac[tid]);
+
+ /* If we're releasing frames from aggregation queues then check if the
+ * all queues combined that we're releasing frames from have
+ * - more frames than the service period, in which case more_data
+ * needs to be set
+ * - fewer than 'cnt' frames, in which case we need to adjust the
+ * firmware command (but do that unconditionally)
+ */
+ if (agg) {
+ int remaining = cnt;
+
+ spin_lock_bh(&mvmsta->lock);
+ for_each_set_bit(tid, &_tids, IWL_MAX_TID_COUNT) {
+ struct iwl_mvm_tid_data *tid_data;
+ u16 n_queued;
+
+ tid_data = &mvmsta->tid_data[tid];
+ if (WARN(tid_data->state != IWL_AGG_ON &&
+ tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA,
+ "TID %d state is %d\n",
+ tid, tid_data->state)) {
+ spin_unlock_bh(&mvmsta->lock);
+ ieee80211_sta_eosp(sta);
+ return;
+ }
+
+ n_queued = iwl_mvm_tid_queued(tid_data);
+ if (n_queued > remaining) {
+ more_data = true;
+ remaining = 0;
+ break;
+ }
+ remaining -= n_queued;
+ }
+ spin_unlock_bh(&mvmsta->lock);
+
+ cmd.sleep_tx_count = cpu_to_le16(cnt - remaining);
+ if (WARN_ON(cnt - remaining == 0)) {
+ ieee80211_sta_eosp(sta);
+ return;
+ }
+ }
+
+ /* Note: this is ignored by firmware not supporting GO uAPSD */
+ if (more_data)
+ cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_MOREDATA);
+
+ if (reason == IEEE80211_FRAME_RELEASE_PSPOLL) {
+ mvmsta->next_status_eosp = true;
+ cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_PS_POLL);
+ } else {
+ cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_UAPSD);
+ }
- /* TODO: somehow the fw doesn't seem to take PS_POLL into account */
ret = iwl_mvm_send_add_sta_cmd(mvm, CMD_ASYNC, &cmd);
if (ret)
IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
}
+
+int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_mvm_eosp_notification *notif = (void *)pkt->data;
+ struct ieee80211_sta *sta;
+ u32 sta_id = le32_to_cpu(notif->sta_id);
+
+ if (WARN_ON_ONCE(sta_id >= IWL_MVM_STATION_COUNT))
+ return 0;
+
+ rcu_read_lock();
+ sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
+ if (!IS_ERR_OR_NULL(sta))
+ ieee80211_sta_eosp(sta);
+ rcu_read_unlock();
+
+ return 0;
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h
index 4968d0237dc5..2ed84c421481 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.h
@@ -195,24 +195,33 @@ struct iwl_mvm;
/**
* DOC: AP mode - PS
*
- * When a station is asleep, the fw will set it as "asleep". All the
- * non-aggregation frames to that station will be dropped by the fw
- * (%TX_STATUS_FAIL_DEST_PS failure code).
+ * When a station is asleep, the fw will set it as "asleep". All frames on
+ * shared queues (i.e. non-aggregation queues) to that station will be dropped
+ * by the fw (%TX_STATUS_FAIL_DEST_PS failure code).
+ *
* AMPDUs are in a separate queue that is stopped by the fw. We just need to
- * let mac80211 know how many frames we have in these queues so that it can
+ * let mac80211 know when there are frames in these queues so that it can
* properly handle trigger frames.
- * When the a trigger frame is received, mac80211 tells the driver to send
- * frames from the AMPDU queues or AC queue depending on which queue are
- * delivery-enabled and what TID has frames to transmit (Note that mac80211 has
- * all the knowledege since all the non-agg frames are buffered / filtered, and
- * the driver tells mac80211 about agg frames). The driver needs to tell the fw
- * to let frames out even if the station is asleep. This is done by
- * %iwl_mvm_sta_modify_sleep_tx_count.
- * When we receive a frame from that station with PM bit unset, the
- * driver needs to let the fw know that this station isn't alseep any more.
- * This is done by %iwl_mvm_sta_modify_ps_wake.
- *
- * TODO - EOSP handling
+ *
+ * When a trigger frame is received, mac80211 tells the driver to send frames
+ * from the AMPDU queues or sends frames to non-aggregation queues itself,
+ * depending on which ACs are delivery-enabled and what TID has frames to
+ * transmit. Note that mac80211 has all the knowledege since all the non-agg
+ * frames are buffered / filtered, and the driver tells mac80211 about agg
+ * frames). The driver needs to tell the fw to let frames out even if the
+ * station is asleep. This is done by %iwl_mvm_sta_modify_sleep_tx_count.
+ *
+ * When we receive a frame from that station with PM bit unset, the driver
+ * needs to let the fw know that this station isn't asleep any more. This is
+ * done by %iwl_mvm_sta_modify_ps_wake in response to mac80211 signalling the
+ * station's wakeup.
+ *
+ * For a GO, the Service Period might be cut short due to an absence period
+ * of the GO. In this (and all other cases) the firmware notifies us with the
+ * EOSP_NOTIFICATION, and we notify mac80211 of that. Further frames that we
+ * already sent to the device will be rejected again.
+ *
+ * See also "AP support for powersaving clients" in mac80211.h.
*/
/**
@@ -261,6 +270,12 @@ struct iwl_mvm_tid_data {
u16 ssn;
};
+static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data)
+{
+ return ieee80211_sn_sub(IEEE80211_SEQ_TO_SN(tid_data->seq_number),
+ tid_data->next_reclaimed);
+}
+
/**
* struct iwl_mvm_sta - representation of a station in the driver
* @sta_id: the index of the station in the fw (will be replaced by id_n_color)
@@ -269,7 +284,11 @@ struct iwl_mvm_tid_data {
* @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for
* tid.
* @max_agg_bufsize: the maximal size of the AGG buffer for this station
+ * @bt_reduced_txpower_dbg: debug mode in which %bt_reduced_txpower is forced
+ * by debugfs.
* @bt_reduced_txpower: is reduced tx power enabled for this station
+ * @next_status_eosp: the next reclaimed packet is a PS-Poll response and
+ * we need to signal the EOSP
* @lock: lock to protect the whole struct. Since %tid_data is access from Tx
* and from Tx response flow, it needs a spinlock.
* @tid_data: per tid data. Look at %iwl_mvm_tid_data.
@@ -287,7 +306,9 @@ struct iwl_mvm_sta {
u32 mac_id_n_color;
u16 tid_disable_agg;
u8 max_agg_bufsize;
+ bool bt_reduced_txpower_dbg;
bool bt_reduced_txpower;
+ bool next_status_eosp;
spinlock_t lock;
struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT];
struct iwl_lq_sta lq_sta;
@@ -345,6 +366,10 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
struct ieee80211_sta *sta, u32 iv32,
u16 *phase1key);
+int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+
/* AMPDU */
int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
int tid, u16 ssn, bool start);
@@ -359,7 +384,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm);
int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,
- u32 qmask);
+ u32 qmask, enum nl80211_iftype iftype);
void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm,
struct iwl_mvm_int_sta *sta);
int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
@@ -375,7 +400,8 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
enum ieee80211_frame_release_type reason,
- u16 cnt);
+ u16 cnt, u16 tids, bool more_data,
+ bool agg);
int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
bool drain);
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c
index b4c2abaa297b..61331245ad93 100644
--- a/drivers/net/wireless/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c
@@ -126,6 +126,7 @@ static void iwl_mvm_roc_finished(struct iwl_mvm *mvm)
* in iwl_mvm_te_handle_notif).
*/
clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
+ iwl_mvm_unref(mvm, IWL_MVM_REF_ROC);
/*
* Of course, our status bit is just as racy as mac80211, so in
@@ -210,6 +211,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
+ iwl_mvm_ref(mvm, IWL_MVM_REF_ROC);
ieee80211_ready_on_channel(mvm->hw);
}
} else {
@@ -436,7 +438,8 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
time_cmd.duration = cpu_to_le32(duration);
time_cmd.repeat = 1;
time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |
- TE_V2_NOTIF_HOST_EVENT_END);
+ TE_V2_NOTIF_HOST_EVENT_END |
+ T2_V2_START_IMMEDIATELY);
iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
}
@@ -551,7 +554,8 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration));
time_cmd.repeat = 1;
time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |
- TE_V2_NOTIF_HOST_EVENT_END);
+ TE_V2_NOTIF_HOST_EVENT_END |
+ T2_V2_START_IMMEDIATELY);
return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c
index 3afa6b6bf835..7a99fa361954 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tt.c
@@ -403,7 +403,7 @@ static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable)
}
}
-static void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff)
+void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff)
{
struct iwl_host_cmd cmd = {
.id = REPLY_THERMAL_MNG_BACKOFF,
@@ -412,6 +412,8 @@ static void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff)
.flags = CMD_SYNC,
};
+ backoff = max(backoff, mvm->thermal_throttle.min_backoff);
+
if (iwl_mvm_send_cmd(mvm, &cmd) == 0) {
IWL_DEBUG_TEMP(mvm, "Set Thermal Tx backoff to: %u\n",
backoff);
@@ -534,7 +536,7 @@ static const struct iwl_tt_params iwl7000_high_temp_tt_params = {
.support_tx_backoff = true,
};
-void iwl_mvm_tt_initialize(struct iwl_mvm *mvm)
+void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff)
{
struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
@@ -546,6 +548,7 @@ void iwl_mvm_tt_initialize(struct iwl_mvm *mvm)
tt->params = &iwl7000_tt_params;
tt->throttle = false;
+ tt->min_backoff = min_backoff;
INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill);
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
index 90378c217bc7..879aeac46cc1 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -79,6 +79,7 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
__le16 fc = hdr->frame_control;
u32 tx_flags = le32_to_cpu(tx_cmd->tx_flags);
u32 len = skb->len + FCS_LEN;
+ u8 ac;
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
tx_flags |= TX_CMD_FLG_ACK;
@@ -90,13 +91,6 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
else if (ieee80211_is_back_req(fc))
tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR;
- /* High prio packet (wrt. BT coex) if it is EAPOL, MCAST or MGMT */
- if (info->band == IEEE80211_BAND_2GHZ &&
- (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO ||
- is_multicast_ether_addr(hdr->addr1) ||
- ieee80211_is_back_req(fc) || ieee80211_is_mgmt(fc)))
- tx_flags |= TX_CMD_FLG_BT_DIS;
-
if (ieee80211_has_morefrags(fc))
tx_flags |= TX_CMD_FLG_MORE_FRAG;
@@ -112,6 +106,11 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
tx_flags &= ~TX_CMD_FLG_SEQ_CTL;
}
+ /* tid_tspec will default to 0 = BE when QOS isn't enabled */
+ ac = tid_to_mac80211_ac[tx_cmd->tid_tspec];
+ tx_flags |= iwl_mvm_bt_coex_tx_prio(mvm, hdr, info, ac) <<
+ TX_CMD_FLG_BT_PRIO_POS;
+
if (ieee80211_is_mgmt(fc)) {
if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc))
tx_cmd->pm_frame_timeout = cpu_to_le16(3);
@@ -122,15 +121,12 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
* it
*/
WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU);
- } else if (skb->protocol == cpu_to_be16(ETH_P_PAE)) {
+ } else if (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO) {
tx_cmd->pm_frame_timeout = cpu_to_le16(2);
} else {
tx_cmd->pm_frame_timeout = 0;
}
- if (info->flags & IEEE80211_TX_CTL_AMPDU)
- tx_flags |= TX_CMD_FLG_PROT_REQUIRE;
-
if (ieee80211_is_data(fc) && len > mvm->rts_threshold &&
!is_multicast_ether_addr(ieee80211_get_DA(hdr)))
tx_flags |= TX_CMD_FLG_PROT_REQUIRE;
@@ -207,7 +203,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm,
rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(rate_idx);
mvm->mgmt_last_antenna_idx =
- iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw),
+ iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant,
mvm->mgmt_last_antenna_idx);
rate_flags = BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS;
@@ -377,6 +373,13 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload;
/* From now on, we cannot access info->control */
+ /*
+ * we handle that entirely ourselves -- for uAPSD the firmware
+ * will always send a notification, and for PS-Poll responses
+ * we'll notify mac80211 when getting frame status
+ */
+ info->flags &= ~IEEE80211_TX_STATUS_EOSP;
+
spin_lock(&mvmsta->lock);
if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) {
@@ -437,6 +440,17 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,
lockdep_assert_held(&mvmsta->lock);
+ if ((tid_data->state == IWL_AGG_ON ||
+ tid_data->state == IWL_EMPTYING_HW_QUEUE_DELBA) &&
+ iwl_mvm_tid_queued(tid_data) == 0) {
+ /*
+ * Now that this aggregation queue is empty tell mac80211 so it
+ * knows we no longer have frames buffered for the station on
+ * this TID (for the TIM bitmap calculation.)
+ */
+ ieee80211_sta_set_buffered(sta, tid, false);
+ }
+
if (tid_data->ssn != tid_data->next_reclaimed)
return;
@@ -659,8 +673,14 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
rcu_read_lock();
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
+ /*
+ * sta can't be NULL otherwise it'd mean that the sta has been freed in
+ * the firmware while we still have packets for it in the Tx queues.
+ */
+ if (WARN_ON_ONCE(!sta))
+ goto out;
- if (!IS_ERR_OR_NULL(sta)) {
+ if (!IS_ERR(sta)) {
mvmsta = iwl_mvm_sta_from_mac80211(sta);
if (tid != IWL_TID_NON_QOS) {
@@ -674,8 +694,12 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
iwl_mvm_check_ratid_empty(mvm, sta, tid);
spin_unlock_bh(&mvmsta->lock);
}
+
+ if (mvmsta->next_status_eosp) {
+ mvmsta->next_status_eosp = false;
+ ieee80211_sta_eosp(sta);
+ }
} else {
- sta = NULL;
mvmsta = NULL;
}
@@ -683,42 +707,38 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
* If the txq is not an AMPDU queue, there is no chance we freed
* several skbs. Check that out...
*/
- if (txq_id < mvm->first_agg_queue && !WARN_ON(skb_freed > 1) &&
- atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id])) {
- if (mvmsta) {
- /*
- * If there are no pending frames for this STA, notify
- * mac80211 that this station can go to sleep in its
- * STA table.
- */
- if (mvmsta->vif->type == NL80211_IFTYPE_AP)
- ieee80211_sta_block_awake(mvm->hw, sta, false);
- /*
- * We might very well have taken mvmsta pointer while
- * the station was being removed. The remove flow might
- * have seen a pending_frame (because we didn't take
- * the lock) even if now the queues are drained. So make
- * really sure now that this the station is not being
- * removed. If it is, run the drain worker to remove it.
- */
- spin_lock_bh(&mvmsta->lock);
- sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
- if (!sta || PTR_ERR(sta) == -EBUSY) {
- /*
- * Station disappeared in the meantime:
- * so we are draining.
- */
- set_bit(sta_id, mvm->sta_drained);
- schedule_work(&mvm->sta_drained_wk);
- }
- spin_unlock_bh(&mvmsta->lock);
- } else if (!mvmsta && PTR_ERR(sta) == -EBUSY) {
- /* Tx response without STA, so we are draining */
- set_bit(sta_id, mvm->sta_drained);
- schedule_work(&mvm->sta_drained_wk);
- }
+ if (txq_id >= mvm->first_agg_queue)
+ goto out;
+
+ /* We can't free more than one frame at once on a shared queue */
+ WARN_ON(skb_freed > 1);
+
+ /* If we have still frames from this STA nothing to do here */
+ if (!atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id]))
+ goto out;
+
+ if (mvmsta && mvmsta->vif->type == NL80211_IFTYPE_AP) {
+ /*
+ * If there are no pending frames for this STA, notify
+ * mac80211 that this station can go to sleep in its
+ * STA table.
+ * If mvmsta is not NULL, sta is valid.
+ */
+ ieee80211_sta_block_awake(mvm->hw, sta, false);
}
+ if (PTR_ERR(sta) == -EBUSY || PTR_ERR(sta) == -ENOENT) {
+ /*
+ * We are draining and this was the last packet - pre_rcu_remove
+ * has been called already. We might be after the
+ * synchronize_net already.
+ * Don't rely on iwl_mvm_rm_sta to see the empty Tx queues.
+ */
+ set_bit(sta_id, mvm->sta_drained);
+ schedule_work(&mvm->sta_drained_wk);
+ }
+
+out:
rcu_read_unlock();
}
@@ -821,16 +841,12 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_mvm_ba_notif *ba_notif = (void *)pkt->data;
struct sk_buff_head reclaimed_skbs;
struct iwl_mvm_tid_data *tid_data;
- struct ieee80211_tx_info *info;
struct ieee80211_sta *sta;
struct iwl_mvm_sta *mvmsta;
- struct ieee80211_hdr *hdr;
struct sk_buff *skb;
int sta_id, tid, freed;
-
/* "flow" corresponds to Tx queue */
u16 scd_flow = le16_to_cpu(ba_notif->scd_flow);
-
/* "ssn" is start of block-ack Tx window, corresponds to index
* (in Tx queue's circular buffer) of first TFD/frame in window */
u16 ba_resp_scd_ssn = le16_to_cpu(ba_notif->scd_ssn);
@@ -887,22 +903,26 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
freed = 0;
skb_queue_walk(&reclaimed_skbs, skb) {
- hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_hdr *hdr = (void *)skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (ieee80211_is_data_qos(hdr->frame_control))
freed++;
else
WARN_ON_ONCE(1);
- info = IEEE80211_SKB_CB(skb);
iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]);
+ memset(&info->status, 0, sizeof(info->status));
+ /* Packet was transmitted successfully, failures come as single
+ * frames because before failing a frame the firmware transmits
+ * it without aggregation at least once.
+ */
+ info->flags |= IEEE80211_TX_STAT_ACK;
+
if (freed == 1) {
/* this is the first skb we deliver in this batch */
/* put the rate scaling data there */
- info = IEEE80211_SKB_CB(skb);
- memset(&info->status, 0, sizeof(info->status));
- info->flags |= IEEE80211_TX_STAT_ACK;
info->flags |= IEEE80211_TX_STAT_AMPDU;
info->status.ampdu_ack_len = ba_notif->txed_2_done;
info->status.ampdu_len = ba_notif->txed;
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c
index a4a5e25623c3..d619851745a1 100644
--- a/drivers/net/wireless/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/iwlwifi/mvm/utils.c
@@ -289,8 +289,8 @@ u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx)
return last_idx;
}
-static struct {
- char *name;
+static const struct {
+ const char *name;
u8 num;
} advanced_lookup[] = {
{ "NMI_INTERRUPT_WDG", 0x34 },
@@ -376,9 +376,67 @@ struct iwl_error_event_table {
u32 flow_handler; /* FH read/write pointers, RX credit */
} __packed;
+/*
+ * UMAC error struct - relevant starting from family 8000 chip.
+ * Note: This structure is read from the device with IO accesses,
+ * and the reading already does the endian conversion. As it is
+ * read with u32-sized accesses, any members with a different size
+ * need to be ordered correctly though!
+ */
+struct iwl_umac_error_event_table {
+ u32 valid; /* (nonzero) valid, (0) log is empty */
+ u32 error_id; /* type of error */
+ u32 pc; /* program counter */
+ u32 blink1; /* branch link */
+ u32 blink2; /* branch link */
+ u32 ilink1; /* interrupt link */
+ u32 ilink2; /* interrupt link */
+ u32 data1; /* error-specific data */
+ u32 data2; /* error-specific data */
+ u32 line; /* source code line of error */
+ u32 umac_ver; /* umac version */
+} __packed;
+
#define ERROR_START_OFFSET (1 * sizeof(u32))
#define ERROR_ELEM_SIZE (7 * sizeof(u32))
+static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm)
+{
+ struct iwl_trans *trans = mvm->trans;
+ struct iwl_umac_error_event_table table;
+ u32 base;
+
+ base = mvm->umac_error_event_table;
+
+ if (base < 0x800000 || base >= 0x80C000) {
+ IWL_ERR(mvm,
+ "Not valid error log pointer 0x%08X for %s uCode\n",
+ base,
+ (mvm->cur_ucode == IWL_UCODE_INIT)
+ ? "Init" : "RT");
+ return;
+ }
+
+ iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
+
+ if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
+ IWL_ERR(trans, "Start IWL Error Log Dump:\n");
+ IWL_ERR(trans, "Status: 0x%08lX, count: %d\n",
+ mvm->status, table.valid);
+ }
+
+ IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id,
+ desc_lookup(table.error_id));
+ IWL_ERR(mvm, "0x%08X | umac uPc\n", table.pc);
+ IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1);
+ IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2);
+ IWL_ERR(mvm, "0x%08X | umac interruptlink1\n", table.ilink1);
+ IWL_ERR(mvm, "0x%08X | umac interruptlink2\n", table.ilink2);
+ IWL_ERR(mvm, "0x%08X | umac data1\n", table.data1);
+ IWL_ERR(mvm, "0x%08X | umac data2\n", table.data2);
+ IWL_ERR(mvm, "0x%08X | umac version\n", table.umac_ver);
+}
+
void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
{
struct iwl_trans *trans = mvm->trans;
@@ -394,7 +452,7 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
base = mvm->fw->inst_errlog_ptr;
}
- if (base < 0x800000 || base >= 0x80C000) {
+ if (base < 0x800000) {
IWL_ERR(mvm,
"Not valid error log pointer 0x%08X for %s uCode\n",
base,
@@ -411,6 +469,8 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
mvm->status, table.valid);
}
+ IWL_ERR(mvm, "Loaded firmware version: %s\n", mvm->fw->fw_version);
+
trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low,
table.data1, table.data2, table.data3,
table.blink1, table.blink2, table.ilink1,
@@ -451,29 +511,31 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
IWL_ERR(mvm, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel);
IWL_ERR(mvm, "0x%08X | timestamp\n", table.u_timestamp);
IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler);
+
+ if (mvm->support_umac_log)
+ iwl_mvm_dump_umac_error_log(mvm);
}
-void iwl_mvm_dump_sram(struct iwl_mvm *mvm)
+void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm)
{
const struct fw_img *img;
- int ofs, len = 0;
- u8 *buf;
+ u32 ofs, sram_len;
+ void *sram;
- if (!mvm->ucode_loaded)
+ if (!mvm->ucode_loaded || mvm->fw_error_sram)
return;
img = &mvm->fw->img[mvm->cur_ucode];
ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
- len = img->sec[IWL_UCODE_SECTION_DATA].len;
+ sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
- buf = kzalloc(len, GFP_ATOMIC);
- if (!buf)
+ sram = kzalloc(sram_len, GFP_ATOMIC);
+ if (!sram)
return;
- iwl_trans_read_mem_bytes(mvm->trans, ofs, buf, len);
- iwl_print_hex_error(mvm->trans, buf, len);
-
- kfree(buf);
+ iwl_trans_read_mem_bytes(mvm->trans, ofs, sram, sram_len);
+ mvm->fw_error_sram = sram;
+ mvm->fw_error_sram_len = sram_len;
}
/**
@@ -514,15 +576,20 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum ieee80211_smps_mode smps_request)
{
struct iwl_mvm_vif *mvmvif;
- enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC;
+ enum ieee80211_smps_mode smps_mode;
int i;
lockdep_assert_held(&mvm->mutex);
/* SMPS is irrelevant for NICs that don't have at least 2 RX antenna */
- if (num_of_ant(iwl_fw_valid_rx_ant(mvm->fw)) == 1)
+ if (num_of_ant(mvm->fw->valid_rx_ant) == 1)
return;
+ if (vif->type == NL80211_IFTYPE_AP)
+ smps_mode = IEEE80211_SMPS_OFF;
+ else
+ smps_mode = IEEE80211_SMPS_AUTOMATIC;
+
mvmvif = iwl_mvm_vif_from_mac80211(vif);
mvmvif->smps_requests[req_type] = smps_request;
for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) {
@@ -536,3 +603,44 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
ieee80211_request_smps(vif, smps_mode);
}
+
+int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ bool value)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ int res;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (mvmvif->low_latency == value)
+ return 0;
+
+ mvmvif->low_latency = value;
+
+ res = iwl_mvm_update_quotas(mvm, NULL);
+ if (res)
+ return res;
+
+ iwl_mvm_bt_coex_vif_change(mvm);
+
+ return iwl_mvm_power_update_mac(mvm, vif);
+}
+
+static void iwl_mvm_ll_iter(void *_data, u8 *mac, struct ieee80211_vif *vif)
+{
+ bool *result = _data;
+
+ if (iwl_mvm_vif_low_latency(iwl_mvm_vif_from_mac80211(vif)))
+ *result = true;
+}
+
+bool iwl_mvm_low_latency(struct iwl_mvm *mvm)
+{
+ bool result = false;
+
+ ieee80211_iterate_active_interfaces_atomic(
+ mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_ll_iter, &result);
+
+ return result;
+}
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c
index 3040924f5f3c..edb015c99049 100644
--- a/drivers/net/wireless/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/iwlwifi/pcie/drv.c
@@ -66,6 +66,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pci-aspm.h>
+#include <linux/acpi.h>
#include "iwl-trans.h"
#include "iwl-drv.h"
@@ -359,20 +360,24 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
/* 7265 Series */
{IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5110, iwl7265_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x095A, 0x5100, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095B, 0x5310, iwl7265_2ac_cfg)},
- {IWL_PCI_DEVICE(0x095B, 0x5302, iwl7265_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x095B, 0x5302, iwl7265_n_cfg)},
{IWL_PCI_DEVICE(0x095B, 0x5210, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5012, iwl7265_2ac_cfg)},
- {IWL_PCI_DEVICE(0x095A, 0x500A, iwl7265_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x095A, 0x5412, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5410, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5400, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x1010, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5000, iwl7265_2n_cfg)},
+ {IWL_PCI_DEVICE(0x095A, 0x500A, iwl7265_2n_cfg)},
{IWL_PCI_DEVICE(0x095B, 0x5200, iwl7265_2n_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5002, iwl7265_n_cfg)},
{IWL_PCI_DEVICE(0x095B, 0x5202, iwl7265_n_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9010, iwl7265_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x095A, 0x9012, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9110, iwl7265_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x095A, 0x9112, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9210, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9510, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9310, iwl7265_2ac_cfg)},
@@ -385,12 +390,92 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{IWL_PCI_DEVICE(0x095A, 0x5590, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095B, 0x5290, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5490, iwl7265_2ac_cfg)},
+
+/* 8000 Series */
+ {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)},
#endif /* CONFIG_IWLMVM */
{0}
};
MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
+#ifdef CONFIG_ACPI
+#define SPL_METHOD "SPLC"
+#define SPL_DOMAINTYPE_MODULE BIT(0)
+#define SPL_DOMAINTYPE_WIFI BIT(1)
+#define SPL_DOMAINTYPE_WIGIG BIT(2)
+#define SPL_DOMAINTYPE_RFEM BIT(3)
+
+static u64 splx_get_pwr_limit(struct iwl_trans *trans, union acpi_object *splx)
+{
+ union acpi_object *limits, *domain_type, *power_limit;
+
+ if (splx->type != ACPI_TYPE_PACKAGE ||
+ splx->package.count != 2 ||
+ splx->package.elements[0].type != ACPI_TYPE_INTEGER ||
+ splx->package.elements[0].integer.value != 0) {
+ IWL_ERR(trans, "Unsupported splx structure");
+ return 0;
+ }
+
+ limits = &splx->package.elements[1];
+ if (limits->type != ACPI_TYPE_PACKAGE ||
+ limits->package.count < 2 ||
+ limits->package.elements[0].type != ACPI_TYPE_INTEGER ||
+ limits->package.elements[1].type != ACPI_TYPE_INTEGER) {
+ IWL_ERR(trans, "Invalid limits element");
+ return 0;
+ }
+
+ domain_type = &limits->package.elements[0];
+ power_limit = &limits->package.elements[1];
+ if (!(domain_type->integer.value & SPL_DOMAINTYPE_WIFI)) {
+ IWL_DEBUG_INFO(trans, "WiFi power is not limited");
+ return 0;
+ }
+
+ return power_limit->integer.value;
+}
+
+static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev)
+{
+ acpi_handle pxsx_handle;
+ acpi_handle handle;
+ struct acpi_buffer splx = {ACPI_ALLOCATE_BUFFER, NULL};
+ acpi_status status;
+
+ pxsx_handle = ACPI_HANDLE(&pdev->dev);
+ if (!pxsx_handle) {
+ IWL_DEBUG_INFO(trans,
+ "Could not retrieve root port ACPI handle");
+ return;
+ }
+
+ /* Get the method's handle */
+ status = acpi_get_handle(pxsx_handle, (acpi_string)SPL_METHOD, &handle);
+ if (ACPI_FAILURE(status)) {
+ IWL_DEBUG_INFO(trans, "SPL method not found");
+ return;
+ }
+
+ /* Call SPLC with no arguments */
+ status = acpi_evaluate_object(handle, NULL, NULL, &splx);
+ if (ACPI_FAILURE(status)) {
+ IWL_ERR(trans, "SPLC invocation failed (0x%x)", status);
+ return;
+ }
+
+ trans->dflt_pwr_limit = splx_get_pwr_limit(trans, splx.pointer);
+ IWL_DEBUG_INFO(trans, "Default power limit set to %lld",
+ trans->dflt_pwr_limit);
+ kfree(splx.pointer);
+}
+
+#else /* CONFIG_ACPI */
+static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev) {}
+#endif
+
/* PCI registers */
#define PCI_CFG_RETRY_TIMEOUT 0x041
@@ -415,6 +500,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_free_trans;
}
+ set_dflt_pwr_limit(iwl_trans, pdev);
+
/* register transport layer debugfs here */
ret = iwl_trans_dbgfs_register(iwl_trans, iwl_trans->dbgfs_dir);
if (ret)
@@ -473,7 +560,7 @@ static int iwl_pci_resume(struct device *device)
iwl_enable_rfkill_int(trans);
hw_rfkill = iwl_is_rfkill_set(trans);
- iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
+ iwl_trans_pcie_rf_kill(trans, hw_rfkill);
return 0;
}
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
index e851f26fd44c..9091513ea738 100644
--- a/drivers/net/wireless/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/iwlwifi/pcie/internal.h
@@ -304,7 +304,7 @@ struct iwl_trans_pcie {
bool bc_table_dword;
u32 rx_page_order;
- const char **command_names;
+ const char *const *command_names;
/* queue watchdog */
unsigned long wd_timeout;
@@ -488,4 +488,6 @@ static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans,
__iwl_trans_pcie_set_bits_mask(trans, reg, mask, mask);
}
+void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state);
+
#endif /* __iwl_trans_int_pcie_h__ */
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c
index 08c23d497a02..fdfa3969cac9 100644
--- a/drivers/net/wireless/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/rx.c
@@ -155,37 +155,26 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans,
if (rxq->need_update == 0)
goto exit_unlock;
- if (trans->cfg->base_params->shadow_reg_enable) {
- /* shadow register enabled */
- /* Device expects a multiple of 8 */
- rxq->write_actual = (rxq->write & ~0x7);
- iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual);
- } else {
- /* If power-saving is in use, make sure device is awake */
- if (test_bit(STATUS_TPOWER_PMI, &trans->status)) {
- reg = iwl_read32(trans, CSR_UCODE_DRV_GP1);
-
- if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
- IWL_DEBUG_INFO(trans,
- "Rx queue requesting wakeup,"
- " GP1 = 0x%x\n", reg);
- iwl_set_bit(trans, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
- goto exit_unlock;
- }
-
- rxq->write_actual = (rxq->write & ~0x7);
- iwl_write_direct32(trans, FH_RSCSR_CHNL0_WPTR,
- rxq->write_actual);
-
- /* Else device is assumed to be awake */
- } else {
- /* Device expects a multiple of 8 */
- rxq->write_actual = (rxq->write & ~0x7);
- iwl_write_direct32(trans, FH_RSCSR_CHNL0_WPTR,
- rxq->write_actual);
+ /*
+ * explicitly wake up the NIC if:
+ * 1. shadow registers aren't enabled
+ * 2. there is a chance that the NIC is asleep
+ */
+ if (!trans->cfg->base_params->shadow_reg_enable &&
+ test_bit(STATUS_TPOWER_PMI, &trans->status)) {
+ reg = iwl_read32(trans, CSR_UCODE_DRV_GP1);
+
+ if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+ IWL_DEBUG_INFO(trans, "Rx queue requesting wakeup, GP1 = 0x%x\n",
+ reg);
+ iwl_set_bit(trans, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ goto exit_unlock;
}
}
+
+ rxq->write_actual = round_down(rxq->write, 8);
+ iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual);
rxq->need_update = 0;
exit_unlock:
@@ -802,10 +791,9 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
static u32 iwl_pcie_int_cause_non_ict(struct iwl_trans *trans)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
u32 inta;
- lockdep_assert_held(&trans_pcie->irq_lock);
+ lockdep_assert_held(&IWL_TRANS_GET_PCIE_TRANS(trans)->irq_lock);
trace_iwlwifi_dev_irq(trans->dev);
@@ -1006,7 +994,7 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
isr_stats->rfkill++;
- iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
+ iwl_trans_pcie_rf_kill(trans, hw_rfkill);
if (hw_rfkill) {
set_bit(STATUS_RFKILL, &trans->status);
if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE,
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index f9507807b486..dcfd6d866d09 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -75,6 +75,20 @@
#include "iwl-agn-hw.h"
#include "internal.h"
+static u32 iwl_trans_pcie_read_shr(struct iwl_trans *trans, u32 reg)
+{
+ iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_CTRL_REG,
+ ((reg & 0x0000ffff) | (2 << 28)));
+ return iwl_read32(trans, HEEP_CTRL_WRD_PCIEX_DATA_REG);
+}
+
+static void iwl_trans_pcie_write_shr(struct iwl_trans *trans, u32 reg, u32 val)
+{
+ iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_DATA_REG, val);
+ iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_CTRL_REG,
+ ((reg & 0x0000ffff) | (3 << 28)));
+}
+
static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux)
{
if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold))
@@ -89,6 +103,7 @@ static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux)
/* PCI registers */
#define PCI_CFG_RETRY_TIMEOUT 0x041
+#define CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC
static void iwl_pcie_apm_config(struct iwl_trans *trans)
{
@@ -132,8 +147,9 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans)
*/
/* Disable L0S exit timer (platform NMI Work/Around) */
- iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS,
- CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+ if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
+ iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS,
+ CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
/*
* Disable L0s without affecting L1;
@@ -203,19 +219,23 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans)
/*
* Enable DMA clock and wait for it to stabilize.
*
- * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits
- * do not disable clocks. This preserves any hardware bits already
- * set by default in "CLK_CTRL_REG" after reset.
+ * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0"
+ * bits do not disable clocks. This preserves any hardware
+ * bits already set by default in "CLK_CTRL_REG" after reset.
*/
- iwl_write_prph(trans, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
- udelay(20);
+ if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+ iwl_write_prph(trans, APMG_CLK_EN_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT);
+ udelay(20);
- /* Disable L1-Active */
- iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG,
- APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+ /* Disable L1-Active */
+ iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG,
+ APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
- /* Clear the interrupt in APMG if the NIC is in RFKILL */
- iwl_write_prph(trans, APMG_RTC_INT_STT_REG, APMG_RTC_INT_STT_RFKILL);
+ /* Clear the interrupt in APMG if the NIC is in RFKILL */
+ iwl_write_prph(trans, APMG_RTC_INT_STT_REG,
+ APMG_RTC_INT_STT_RFKILL);
+ }
set_bit(STATUS_DEVICE_ENABLED, &trans->status);
@@ -223,6 +243,116 @@ out:
return ret;
}
+/*
+ * Enable LP XTAL to avoid HW bug where device may consume much power if
+ * FW is not loaded after device reset. LP XTAL is disabled by default
+ * after device HW reset. Do it only if XTAL is fed by internal source.
+ * Configure device's "persistence" mode to avoid resetting XTAL again when
+ * SHRD_HW_RST occurs in S3.
+ */
+static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans)
+{
+ int ret;
+ u32 apmg_gp1_reg;
+ u32 apmg_xtal_cfg_reg;
+ u32 dl_cfg_reg;
+
+ /* Force XTAL ON */
+ __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_XTAL_ON);
+
+ /* Reset entire device - do controller reset (results in SHRD_HW_RST) */
+ iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+ udelay(10);
+
+ /*
+ * Set "initialization complete" bit to move adapter from
+ * D0U* --> D0A* (powered-up active) state.
+ */
+ iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+ /*
+ * Wait for clock stabilization; once stabilized, access to
+ * device-internal resources is possible.
+ */
+ ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ 25000);
+ if (WARN_ON(ret < 0)) {
+ IWL_ERR(trans, "Access time out - failed to enable LP XTAL\n");
+ /* Release XTAL ON request */
+ __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_XTAL_ON);
+ return;
+ }
+
+ /*
+ * Clear "disable persistence" to avoid LP XTAL resetting when
+ * SHRD_HW_RST is applied in S3.
+ */
+ iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG,
+ APMG_PCIDEV_STT_VAL_PERSIST_DIS);
+
+ /*
+ * Force APMG XTAL to be active to prevent its disabling by HW
+ * caused by APMG idle state.
+ */
+ apmg_xtal_cfg_reg = iwl_trans_pcie_read_shr(trans,
+ SHR_APMG_XTAL_CFG_REG);
+ iwl_trans_pcie_write_shr(trans, SHR_APMG_XTAL_CFG_REG,
+ apmg_xtal_cfg_reg |
+ SHR_APMG_XTAL_CFG_XTAL_ON_REQ);
+
+ /*
+ * Reset entire device again - do controller reset (results in
+ * SHRD_HW_RST). Turn MAC off before proceeding.
+ */
+ iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+ udelay(10);
+
+ /* Enable LP XTAL by indirect access through CSR */
+ apmg_gp1_reg = iwl_trans_pcie_read_shr(trans, SHR_APMG_GP1_REG);
+ iwl_trans_pcie_write_shr(trans, SHR_APMG_GP1_REG, apmg_gp1_reg |
+ SHR_APMG_GP1_WF_XTAL_LP_EN |
+ SHR_APMG_GP1_CHICKEN_BIT_SELECT);
+
+ /* Clear delay line clock power up */
+ dl_cfg_reg = iwl_trans_pcie_read_shr(trans, SHR_APMG_DL_CFG_REG);
+ iwl_trans_pcie_write_shr(trans, SHR_APMG_DL_CFG_REG, dl_cfg_reg &
+ ~SHR_APMG_DL_CFG_DL_CLOCK_POWER_UP);
+
+ /*
+ * Enable persistence mode to avoid LP XTAL resetting when
+ * SHRD_HW_RST is applied in S3.
+ */
+ iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_PERSIST_MODE);
+
+ /*
+ * Clear "initialization complete" bit to move adapter from
+ * D0A* (powered-up Active) --> D0U* (Uninitialized) state.
+ */
+ iwl_clear_bit(trans, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+ /* Activates XTAL resources monitor */
+ __iwl_trans_pcie_set_bit(trans, CSR_MONITOR_CFG_REG,
+ CSR_MONITOR_XTAL_RESOURCES);
+
+ /* Release XTAL ON request */
+ __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_XTAL_ON);
+ udelay(10);
+
+ /* Release APMG XTAL */
+ iwl_trans_pcie_write_shr(trans, SHR_APMG_XTAL_CFG_REG,
+ apmg_xtal_cfg_reg &
+ ~SHR_APMG_XTAL_CFG_XTAL_ON_REQ);
+}
+
static int iwl_pcie_apm_stop_master(struct iwl_trans *trans)
{
int ret = 0;
@@ -250,6 +380,11 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans)
/* Stop device's DMA activity */
iwl_pcie_apm_stop_master(trans);
+ if (trans->cfg->lp_xtal_workaround) {
+ iwl_pcie_apm_lp_xtal_enable(trans);
+ return;
+ }
+
/* Reset the entire device */
iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
@@ -273,7 +408,8 @@ static int iwl_pcie_nic_init(struct iwl_trans *trans)
spin_unlock(&trans_pcie->irq_lock);
- iwl_pcie_set_pwr(trans, false);
+ if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
+ iwl_pcie_set_pwr(trans, false);
iwl_op_mode_nic_config(trans->op_mode);
@@ -435,78 +571,106 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num,
return ret;
}
-static int iwl_pcie_secure_set(struct iwl_trans *trans, int cpu)
+static int iwl_pcie_load_cpu_secured_sections(struct iwl_trans *trans,
+ const struct fw_img *image,
+ int cpu,
+ int *first_ucode_section)
{
int shift_param;
- u32 address;
- int ret = 0;
+ int i, ret = 0;
+ u32 last_read_idx = 0;
if (cpu == 1) {
shift_param = 0;
- address = CSR_SECURE_BOOT_CPU1_STATUS_ADDR;
+ *first_ucode_section = 0;
} else {
shift_param = 16;
- address = CSR_SECURE_BOOT_CPU2_STATUS_ADDR;
+ (*first_ucode_section)++;
}
- /* set CPU to started */
- iwl_trans_set_bits_mask(trans,
- CSR_UCODE_LOAD_STATUS_ADDR,
- CSR_CPU_STATUS_LOADING_STARTED << shift_param,
- 1);
-
- /* set last complete descriptor number */
- iwl_trans_set_bits_mask(trans,
- CSR_UCODE_LOAD_STATUS_ADDR,
- CSR_CPU_STATUS_NUM_OF_LAST_COMPLETED
- << shift_param,
- 1);
-
- /* set last loaded block */
- iwl_trans_set_bits_mask(trans,
- CSR_UCODE_LOAD_STATUS_ADDR,
- CSR_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK
- << shift_param,
- 1);
+ for (i = *first_ucode_section; i < IWL_UCODE_SECTION_MAX; i++) {
+ last_read_idx = i;
+ if (!image->sec[i].data ||
+ image->sec[i].offset == CPU1_CPU2_SEPARATOR_SECTION) {
+ IWL_DEBUG_FW(trans,
+ "Break since Data not valid or Empty section, sec = %d\n",
+ i);
+ break;
+ }
+
+ if (i == (*first_ucode_section) + 1)
+ /* set CPU to started */
+ iwl_set_bits_prph(trans,
+ CSR_UCODE_LOAD_STATUS_ADDR,
+ LMPM_CPU_HDRS_LOADING_COMPLETED
+ << shift_param);
+
+ ret = iwl_pcie_load_section(trans, i, &image->sec[i]);
+ if (ret)
+ return ret;
+ }
/* image loading complete */
- iwl_trans_set_bits_mask(trans,
- CSR_UCODE_LOAD_STATUS_ADDR,
- CSR_CPU_STATUS_LOADING_COMPLETED
- << shift_param,
- 1);
-
- /* set FH_TCSR_0_REG */
- iwl_trans_set_bits_mask(trans, FH_TCSR_0_REG0, 0x00400000, 1);
-
- /* verify image verification started */
- ret = iwl_poll_bit(trans, address,
- CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS,
- CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS,
- CSR_SECURE_TIME_OUT);
- if (ret < 0) {
- IWL_ERR(trans, "secure boot process didn't start\n");
- return ret;
+ iwl_set_bits_prph(trans,
+ CSR_UCODE_LOAD_STATUS_ADDR,
+ LMPM_CPU_UCODE_LOADING_COMPLETED << shift_param);
+
+ *first_ucode_section = last_read_idx;
+
+ return 0;
+}
+
+static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans,
+ const struct fw_img *image,
+ int cpu,
+ int *first_ucode_section)
+{
+ int shift_param;
+ int i, ret = 0;
+ u32 last_read_idx = 0;
+
+ if (cpu == 1) {
+ shift_param = 0;
+ *first_ucode_section = 0;
+ } else {
+ shift_param = 16;
+ (*first_ucode_section)++;
}
- /* wait for image verification to complete */
- ret = iwl_poll_bit(trans, address,
- CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED,
- CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED,
- CSR_SECURE_TIME_OUT);
+ for (i = *first_ucode_section; i < IWL_UCODE_SECTION_MAX; i++) {
+ last_read_idx = i;
- if (ret < 0) {
- IWL_ERR(trans, "Time out on secure boot process\n");
- return ret;
+ if (!image->sec[i].data ||
+ image->sec[i].offset == CPU1_CPU2_SEPARATOR_SECTION) {
+ IWL_DEBUG_FW(trans,
+ "Break since Data not valid or Empty section, sec = %d\n",
+ i);
+ break;
+ }
+
+ ret = iwl_pcie_load_section(trans, i, &image->sec[i]);
+ if (ret)
+ return ret;
}
+ if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
+ iwl_set_bits_prph(trans,
+ CSR_UCODE_LOAD_STATUS_ADDR,
+ (LMPM_CPU_UCODE_LOADING_COMPLETED |
+ LMPM_CPU_HDRS_LOADING_COMPLETED |
+ LMPM_CPU_UCODE_LOADING_STARTED) <<
+ shift_param);
+
+ *first_ucode_section = last_read_idx;
+
return 0;
}
static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
const struct fw_img *image)
{
- int i, ret = 0;
+ int ret = 0;
+ int first_ucode_section;
IWL_DEBUG_FW(trans,
"working with %s image\n",
@@ -518,53 +682,68 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
/* configure the ucode to be ready to get the secured image */
if (image->is_secure) {
/* set secure boot inspector addresses */
- iwl_write32(trans, CSR_SECURE_INSPECTOR_CODE_ADDR, 0);
- iwl_write32(trans, CSR_SECURE_INSPECTOR_DATA_ADDR, 0);
-
- /* release CPU1 reset if secure inspector image burned in OTP */
- iwl_write32(trans, CSR_RESET, 0);
- }
-
- /* load to FW the binary sections of CPU1 */
- IWL_DEBUG_INFO(trans, "Loading CPU1\n");
- for (i = 0;
- i < IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU;
- i++) {
- if (!image->sec[i].data)
- break;
- ret = iwl_pcie_load_section(trans, i, &image->sec[i]);
+ iwl_write_prph(trans,
+ LMPM_SECURE_INSPECTOR_CODE_ADDR,
+ LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE);
+
+ iwl_write_prph(trans,
+ LMPM_SECURE_INSPECTOR_DATA_ADDR,
+ LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE);
+
+ /* set CPU1 header address */
+ iwl_write_prph(trans,
+ LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR,
+ LMPM_SECURE_CPU1_HDR_MEM_SPACE);
+
+ /* load to FW the binary Secured sections of CPU1 */
+ ret = iwl_pcie_load_cpu_secured_sections(trans, image, 1,
+ &first_ucode_section);
if (ret)
return ret;
- }
- /* configure the ucode to start secure process on CPU1 */
- if (image->is_secure) {
- /* config CPU1 to start secure protocol */
- ret = iwl_pcie_secure_set(trans, 1);
+ } else {
+ /* load to FW the binary Non secured sections of CPU1 */
+ ret = iwl_pcie_load_cpu_sections(trans, image, 1,
+ &first_ucode_section);
if (ret)
return ret;
- } else {
- /* Remove all resets to allow NIC to operate */
- iwl_write32(trans, CSR_RESET, 0);
}
if (image->is_dual_cpus) {
+ /* set CPU2 header address */
+ iwl_write_prph(trans,
+ LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR,
+ LMPM_SECURE_CPU2_HDR_MEM_SPACE);
+
/* load to FW the binary sections of CPU2 */
- IWL_DEBUG_INFO(trans, "working w/ DUAL CPUs - Loading CPU2\n");
- for (i = IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU;
- i < IWL_UCODE_SECTION_MAX; i++) {
- if (!image->sec[i].data)
- break;
- ret = iwl_pcie_load_section(trans, i, &image->sec[i]);
- if (ret)
- return ret;
- }
+ if (image->is_secure)
+ ret = iwl_pcie_load_cpu_secured_sections(
+ trans, image, 2,
+ &first_ucode_section);
+ else
+ ret = iwl_pcie_load_cpu_sections(trans, image, 2,
+ &first_ucode_section);
+ if (ret)
+ return ret;
+ }
+
+ /* release CPU reset */
+ if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
+ iwl_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT);
+ else
+ iwl_write32(trans, CSR_RESET, 0);
- if (image->is_secure) {
- /* set CPU2 for secure protocol */
- ret = iwl_pcie_secure_set(trans, 2);
- if (ret)
- return ret;
+ if (image->is_secure) {
+ /* wait for image verification to complete */
+ ret = iwl_poll_prph_bit(trans,
+ LMPM_SECURE_BOOT_CPU1_STATUS_ADDR,
+ LMPM_SECURE_BOOT_STATUS_SUCCESS,
+ LMPM_SECURE_BOOT_STATUS_SUCCESS,
+ LMPM_SECURE_TIME_OUT);
+
+ if (ret < 0) {
+ IWL_ERR(trans, "Time out on secure boot process\n");
+ return ret;
}
}
@@ -591,7 +770,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
set_bit(STATUS_RFKILL, &trans->status);
else
clear_bit(STATUS_RFKILL, &trans->status);
- iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
+ iwl_trans_pcie_rf_kill(trans, hw_rfkill);
if (hw_rfkill && !run_in_rfkill)
return -ERFKILL;
@@ -706,7 +885,13 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
else
clear_bit(STATUS_RFKILL, &trans->status);
if (hw_rfkill != was_hw_rfkill)
- iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
+ iwl_trans_pcie_rf_kill(trans, hw_rfkill);
+}
+
+void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state)
+{
+ if (iwl_op_mode_hw_rf_kill(trans->op_mode, state))
+ iwl_trans_pcie_stop_device(trans);
}
static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)
@@ -815,7 +1000,7 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
set_bit(STATUS_RFKILL, &trans->status);
else
clear_bit(STATUS_RFKILL, &trans->status);
- iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
+ iwl_trans_pcie_rf_kill(trans, hw_rfkill);
return 0;
}
@@ -1158,6 +1343,7 @@ static const char *get_csr_string(int cmd)
IWL_CMD(CSR_GIO_CHICKEN_BITS);
IWL_CMD(CSR_ANA_PLL_CFG);
IWL_CMD(CSR_HW_REV_WA_REG);
+ IWL_CMD(CSR_MONITOR_STATUS_REG);
IWL_CMD(CSR_DBG_HPET_MEM_REG);
default:
return "UNKNOWN";
@@ -1190,6 +1376,7 @@ void iwl_pcie_dump_csr(struct iwl_trans *trans)
CSR_DRAM_INT_TBL_REG,
CSR_GIO_CHICKEN_BITS,
CSR_ANA_PLL_CFG,
+ CSR_MONITOR_STATUS_REG,
CSR_HW_REV_WA_REG,
CSR_DBG_HPET_MEM_REG
};
@@ -1407,16 +1594,15 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
{
struct iwl_trans *trans = file->private_data;
char *buf = NULL;
- int pos = 0;
- ssize_t ret = -EFAULT;
-
- ret = pos = iwl_dump_fh(trans, &buf);
- if (buf) {
- ret = simple_read_from_buffer(user_buf,
- count, ppos, buf, pos);
- kfree(buf);
- }
+ ssize_t ret;
+ ret = iwl_dump_fh(trans, &buf);
+ if (ret < 0)
+ return ret;
+ if (!buf)
+ return -EINVAL;
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+ kfree(buf);
return ret;
}
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index 3d549008b3e2..3b0c72c10054 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -207,7 +207,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
IWL_ERR(trans, "scratch %d = 0x%08x\n", i,
le32_to_cpu(txq->scratchbufs[i].scratch));
- iwl_trans_fw_error(trans);
+ iwl_write_prph(trans, DEVICE_SET_NMI_REG, 1);
}
/*
@@ -296,43 +296,38 @@ void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq)
if (txq->need_update == 0)
return;
- if (trans->cfg->base_params->shadow_reg_enable ||
- txq_id == trans_pcie->cmd_queue) {
- /* shadow register enabled */
- iwl_write32(trans, HBUS_TARG_WRPTR,
- txq->q.write_ptr | (txq_id << 8));
- } else {
- /* if we're trying to save power */
- if (test_bit(STATUS_TPOWER_PMI, &trans->status)) {
- /* wake up nic if it's powered down ...
- * uCode will wake up, and interrupt us again, so next
- * time we'll skip this part. */
- reg = iwl_read32(trans, CSR_UCODE_DRV_GP1);
-
- if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
- IWL_DEBUG_INFO(trans,
- "Tx queue %d requesting wakeup,"
- " GP1 = 0x%x\n", txq_id, reg);
- iwl_set_bit(trans, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
- return;
- }
-
- IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id,
- txq->q.write_ptr);
-
- iwl_write_direct32(trans, HBUS_TARG_WRPTR,
- txq->q.write_ptr | (txq_id << 8));
-
+ /*
+ * explicitly wake up the NIC if:
+ * 1. shadow registers aren't enabled
+ * 2. NIC is woken up for CMD regardless of shadow outside this function
+ * 3. there is a chance that the NIC is asleep
+ */
+ if (!trans->cfg->base_params->shadow_reg_enable &&
+ txq_id != trans_pcie->cmd_queue &&
+ test_bit(STATUS_TPOWER_PMI, &trans->status)) {
/*
- * else not in power-save mode,
- * uCode will never sleep when we're
- * trying to tx (during RFKILL, we're not trying to tx).
+ * wake up nic if it's powered down ...
+ * uCode will wake up, and interrupt us again, so next
+ * time we'll skip this part.
*/
- } else
- iwl_write32(trans, HBUS_TARG_WRPTR,
- txq->q.write_ptr | (txq_id << 8));
+ reg = iwl_read32(trans, CSR_UCODE_DRV_GP1);
+
+ if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+ IWL_DEBUG_INFO(trans, "Tx queue %d requesting wakeup, GP1 = 0x%x\n",
+ txq_id, reg);
+ iwl_set_bit(trans, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ return;
+ }
}
+
+ /*
+ * if not in power-save mode, uCode will never sleep when we're
+ * trying to tx (during RFKILL, we're not trying to tx).
+ */
+ IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id, txq->q.write_ptr);
+ iwl_write32(trans, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8));
+
txq->need_update = 0;
}
@@ -705,8 +700,9 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
/* Enable L1-Active */
- iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG,
- APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+ if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
+ iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG,
+ APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
}
void iwl_trans_pcie_tx_reset(struct iwl_trans *trans)
@@ -1028,7 +1024,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
if (nfreed++ > 0) {
IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n",
idx, q->write_ptr, q->read_ptr);
- iwl_trans_fw_error(trans);
+ iwl_write_prph(trans, DEVICE_SET_NMI_REG, 1);
}
}
@@ -1587,6 +1583,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
get_cmd_string(trans_pcie, cmd->id));
ret = -ETIMEDOUT;
+ iwl_write_prph(trans, DEVICE_SET_NMI_REG, 1);
iwl_trans_fw_error(trans);
goto cancel;
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 32f75007a825..54e344aed6e0 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -621,7 +621,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
id = *pos++;
elen = *pos++;
left -= 2;
- if (elen > left || elen == 0) {
+ if (elen > left) {
lbs_deb_scan("scan response: invalid IE fmt\n");
goto done;
}
@@ -1766,7 +1766,8 @@ static void lbs_join_post(struct lbs_private *priv,
memcpy(priv->wdev->ssid, params->ssid, params->ssid_len);
priv->wdev->ssid_len = params->ssid_len;
- cfg80211_ibss_joined(priv->dev, bssid, GFP_KERNEL);
+ cfg80211_ibss_joined(priv->dev, bssid, params->chandef.chan,
+ GFP_KERNEL);
/* TODO: consider doing this at MACREG_INT_CODE_LINK_SENSED time */
priv->connect_status = LBS_CONNECTED;
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 58c6ee5de98f..33ceda296c9c 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -498,7 +498,7 @@ static int if_sdio_prog_helper(struct if_sdio_card *card,
*/
mdelay(2);
- chunk_size = min(size, (size_t)60);
+ chunk_size = min_t(size_t, size, 60);
*((__le32*)chunk_buffer) = cpu_to_le32(chunk_size);
memcpy(chunk_buffer + 4, firmware, chunk_size);
@@ -639,7 +639,7 @@ static int if_sdio_prog_real(struct if_sdio_card *card,
req_size = size;
while (req_size) {
- chunk_size = min(req_size, (size_t)512);
+ chunk_size = min_t(size_t, req_size, 512);
memcpy(chunk_buffer, firmware, chunk_size);
/*
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 69d4c3179d04..9d7a52f5a410 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -57,6 +57,10 @@ static bool rctbl = false;
module_param(rctbl, bool, 0444);
MODULE_PARM_DESC(rctbl, "Handle rate control table");
+static bool support_p2p_device = true;
+module_param(support_p2p_device, bool, 0444);
+MODULE_PARM_DESC(support_p2p_device, "Support P2P-Device interface type");
+
/**
* enum hwsim_regtest - the type of regulatory tests we offer
*
@@ -335,7 +339,8 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = {
#endif
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_GO) },
- { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) },
+ /* must be last, see hwsim_if_comb */
+ { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }
};
static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = {
@@ -345,6 +350,27 @@ static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = {
static const struct ieee80211_iface_combination hwsim_if_comb[] = {
{
.limits = hwsim_if_limits,
+ /* remove the last entry which is P2P_DEVICE */
+ .n_limits = ARRAY_SIZE(hwsim_if_limits) - 1,
+ .max_interfaces = 2048,
+ .num_different_channels = 1,
+ },
+ {
+ .limits = hwsim_if_dfs_limits,
+ .n_limits = ARRAY_SIZE(hwsim_if_dfs_limits),
+ .max_interfaces = 8,
+ .num_different_channels = 1,
+ .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+ BIT(NL80211_CHAN_WIDTH_20) |
+ BIT(NL80211_CHAN_WIDTH_40) |
+ BIT(NL80211_CHAN_WIDTH_80) |
+ BIT(NL80211_CHAN_WIDTH_160),
+ }
+};
+
+static const struct ieee80211_iface_combination hwsim_if_comb_p2p_dev[] = {
+ {
+ .limits = hwsim_if_limits,
.n_limits = ARRAY_SIZE(hwsim_if_limits),
.max_interfaces = 2048,
.num_different_channels = 1,
@@ -385,6 +411,7 @@ struct mac80211_hwsim_data {
struct mac_address addresses[2];
int channels, idx;
+ bool use_chanctx;
struct ieee80211_channel *tmp_chan;
struct delayed_work roc_done;
@@ -451,7 +478,7 @@ static struct genl_family hwsim_genl_family = {
/* MAC80211_HWSIM netlink policy */
-static struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
+static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
[HWSIM_ATTR_ADDR_RECEIVER] = { .type = NLA_UNSPEC, .len = ETH_ALEN },
[HWSIM_ATTR_ADDR_TRANSMITTER] = { .type = NLA_UNSPEC, .len = ETH_ALEN },
[HWSIM_ATTR_FRAME] = { .type = NLA_BINARY,
@@ -468,6 +495,7 @@ static struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
[HWSIM_ATTR_REG_HINT_ALPHA2] = { .type = NLA_STRING, .len = 2 },
[HWSIM_ATTR_REG_CUSTOM_REG] = { .type = NLA_U32 },
[HWSIM_ATTR_REG_STRICT_REG] = { .type = NLA_FLAG },
+ [HWSIM_ATTR_SUPPORT_P2P_DEVICE] = { .type = NLA_FLAG },
};
static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
@@ -1035,32 +1063,6 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
ack = true;
rx_status.mactime = now + data2->tsf_offset;
-#if 0
- /*
- * Don't enable this code by default as the OUI 00:00:00
- * is registered to Xerox so we shouldn't use it here, it
- * might find its way into pcap files.
- * Note that this code requires the headroom in the SKB
- * that was allocated earlier.
- */
- rx_status.vendor_radiotap_oui[0] = 0x00;
- rx_status.vendor_radiotap_oui[1] = 0x00;
- rx_status.vendor_radiotap_oui[2] = 0x00;
- rx_status.vendor_radiotap_subns = 127;
- /*
- * Radiotap vendor namespaces can (and should) also be
- * split into fields by using the standard radiotap
- * presence bitmap mechanism. Use just BIT(0) here for
- * the presence bitmap.
- */
- rx_status.vendor_radiotap_bitmap = BIT(0);
- /* We have 8 bytes of (dummy) data */
- rx_status.vendor_radiotap_len = 8;
- /* For testing, also require it to be aligned */
- rx_status.vendor_radiotap_align = 8;
- /* push the data */
- memcpy(skb_push(nskb, 8), "ABCDEFGH", 8);
-#endif
memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status));
ieee80211_rx_irqsafe(data2->hw, nskb);
@@ -1087,7 +1089,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
return;
}
- if (data->channels == 1) {
+ if (!data->use_chanctx) {
channel = data->channel;
} else if (txi->hw_queue == 4) {
channel = data->tmp_chan;
@@ -1275,6 +1277,9 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
mac80211_hwsim_tx_frame(hw, skb,
rcu_dereference(vif->chanctx_conf)->def.chan);
+
+ if (vif->csa_active && ieee80211_csa_is_complete(vif))
+ ieee80211_csa_finish(vif);
}
static enum hrtimer_restart
@@ -1350,7 +1355,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
data->channel = conf->chandef.chan;
- WARN_ON(data->channel && data->channels > 1);
+ WARN_ON(data->channel && data->use_chanctx);
data->power_level = conf->power_level;
if (!data->started || !data->beacon_int)
@@ -1936,7 +1941,8 @@ static struct ieee80211_ops mac80211_hwsim_mchan_ops;
static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
const struct ieee80211_regdomain *regd,
- bool reg_strict)
+ bool reg_strict, bool p2p_device,
+ bool use_chanctx)
{
int err;
u8 addr[ETH_ALEN];
@@ -1946,11 +1952,14 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
const struct ieee80211_ops *ops = &mac80211_hwsim_ops;
int idx;
+ if (WARN_ON(channels > 1 && !use_chanctx))
+ return -EINVAL;
+
spin_lock_bh(&hwsim_radio_lock);
idx = hwsim_radio_idx++;
spin_unlock_bh(&hwsim_radio_lock);
- if (channels > 1)
+ if (use_chanctx)
ops = &mac80211_hwsim_mchan_ops;
hw = ieee80211_alloc_hw(sizeof(*data), ops);
if (!hw) {
@@ -1991,17 +2000,25 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
hw->wiphy->addresses = data->addresses;
data->channels = channels;
+ data->use_chanctx = use_chanctx;
data->idx = idx;
- if (data->channels > 1) {
+ if (data->use_chanctx) {
hw->wiphy->max_scan_ssids = 255;
hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
hw->wiphy->max_remain_on_channel_duration = 1000;
/* For channels > 1 DFS is not allowed */
hw->wiphy->n_iface_combinations = 1;
hw->wiphy->iface_combinations = &data->if_combination;
- data->if_combination = hwsim_if_comb[0];
+ if (p2p_device)
+ data->if_combination = hwsim_if_comb_p2p_dev[0];
+ else
+ data->if_combination = hwsim_if_comb[0];
data->if_combination.num_different_channels = data->channels;
+ } else if (p2p_device) {
+ hw->wiphy->iface_combinations = hwsim_if_comb_p2p_dev;
+ hw->wiphy->n_iface_combinations =
+ ARRAY_SIZE(hwsim_if_comb_p2p_dev);
} else {
hw->wiphy->iface_combinations = hwsim_if_comb;
hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb);
@@ -2017,8 +2034,10 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_MESH_POINT) |
- BIT(NL80211_IFTYPE_P2P_DEVICE);
+ BIT(NL80211_IFTYPE_MESH_POINT);
+
+ if (p2p_device)
+ hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_DEVICE);
hw->flags = IEEE80211_HW_MFP_CAPABLE |
IEEE80211_HW_SIGNAL_DBM |
@@ -2027,13 +2046,15 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_WANT_MONITOR_VIF |
IEEE80211_HW_QUEUE_CONTROL |
- IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
+ IEEE80211_HW_SUPPORTS_HT_CCK_RATES |
+ IEEE80211_HW_CHANCTX_STA_CSA;
if (rctbl)
hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE;
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
- WIPHY_FLAG_AP_UAPSD;
+ WIPHY_FLAG_AP_UAPSD |
+ WIPHY_FLAG_HAS_CHANNEL_SWITCH;
hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
/* ask mac80211 to reserve space for magic */
@@ -2141,7 +2162,7 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps);
debugfs_create_file("group", 0666, data->debugfs, data,
&hwsim_fops_group);
- if (data->channels == 1)
+ if (!data->use_chanctx)
debugfs_create_file("dfs_simulate_radar", 0222,
data->debugfs,
data, &hwsim_simulate_radar);
@@ -2407,10 +2428,17 @@ static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info)
const char *alpha2 = NULL;
const struct ieee80211_regdomain *regd = NULL;
bool reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG];
+ bool p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE];
+ bool use_chanctx;
if (info->attrs[HWSIM_ATTR_CHANNELS])
chans = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]);
+ if (info->attrs[HWSIM_ATTR_USE_CHANCTX])
+ use_chanctx = true;
+ else
+ use_chanctx = (chans > 1);
+
if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2])
alpha2 = nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]);
@@ -2422,7 +2450,8 @@ static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info)
regd = hwsim_world_regdom_custom[idx];
}
- return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict);
+ return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict,
+ p2p_device, use_chanctx);
}
static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info)
@@ -2640,7 +2669,9 @@ static int __init init_mac80211_hwsim(void)
}
err = mac80211_hwsim_create_radio(channels, reg_alpha2,
- regd, reg_strict);
+ regd, reg_strict,
+ support_p2p_device,
+ channels > 1);
if (err < 0)
goto out_free_radios;
}
diff --git a/drivers/net/wireless/mac80211_hwsim.h b/drivers/net/wireless/mac80211_hwsim.h
index 2747cce5a269..c9d0315575ba 100644
--- a/drivers/net/wireless/mac80211_hwsim.h
+++ b/drivers/net/wireless/mac80211_hwsim.h
@@ -107,6 +107,10 @@ enum {
* (nla string, length 2)
* @HWSIM_ATTR_REG_CUSTOM_REG: custom regulatory domain index (u32 attribute)
* @HWSIM_ATTR_REG_STRICT_REG: request REGULATORY_STRICT_REG (flag attribute)
+ * @HWSIM_ATTR_SUPPORT_P2P_DEVICE: support P2P Device virtual interface (flag)
+ * @HWSIM_ATTR_USE_CHANCTX: used with the %HWSIM_CMD_CREATE_RADIO
+ * command to force use of channel contexts even when only a
+ * single channel is supported
* @__HWSIM_ATTR_MAX: enum limit
*/
@@ -126,6 +130,8 @@ enum {
HWSIM_ATTR_REG_HINT_ALPHA2,
HWSIM_ATTR_REG_CUSTOM_REG,
HWSIM_ATTR_REG_STRICT_REG,
+ HWSIM_ATTR_SUPPORT_P2P_DEVICE,
+ HWSIM_ATTR_USE_CHANCTX,
__HWSIM_ATTR_MAX,
};
#define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
diff --git a/drivers/net/wireless/mwifiex/11ac.c b/drivers/net/wireless/mwifiex/11ac.c
index 5e0eec4d71c7..c92f27aa71ed 100644
--- a/drivers/net/wireless/mwifiex/11ac.c
+++ b/drivers/net/wireless/mwifiex/11ac.c
@@ -23,6 +23,31 @@
#include "main.h"
#include "11ac.h"
+/* Tables of the MCS map to the highest data rate (in Mbps) supported
+ * for long GI.
+ */
+static const u16 max_rate_lgi_80MHZ[8][3] = {
+ {0x124, 0x15F, 0x186}, /* NSS = 1 */
+ {0x249, 0x2BE, 0x30C}, /* NSS = 2 */
+ {0x36D, 0x41D, 0x492}, /* NSS = 3 */
+ {0x492, 0x57C, 0x618}, /* NSS = 4 */
+ {0x5B6, 0x6DB, 0x79E}, /* NSS = 5 */
+ {0x6DB, 0x83A, 0x0}, /* NSS = 6 */
+ {0x7FF, 0x999, 0xAAA}, /* NSS = 7 */
+ {0x924, 0xAF8, 0xC30} /* NSS = 8 */
+};
+
+static const u16 max_rate_lgi_160MHZ[8][3] = {
+ {0x249, 0x2BE, 0x30C}, /* NSS = 1 */
+ {0x492, 0x57C, 0x618}, /* NSS = 2 */
+ {0x6DB, 0x83A, 0x0}, /* NSS = 3 */
+ {0x924, 0xAF8, 0xC30}, /* NSS = 4 */
+ {0xB6D, 0xDB6, 0xF3C}, /* NSS = 5 */
+ {0xDB6, 0x1074, 0x1248}, /* NSS = 6 */
+ {0xFFF, 0x1332, 0x1554}, /* NSS = 7 */
+ {0x1248, 0x15F0, 0x1860} /* NSS = 8 */
+};
+
/* This function converts the 2-bit MCS map to the highest long GI
* VHT data rate.
*/
@@ -30,33 +55,10 @@ static u16
mwifiex_convert_mcsmap_to_maxrate(struct mwifiex_private *priv,
u8 bands, u16 mcs_map)
{
- u8 i, nss, max_mcs;
+ u8 i, nss, mcs;
u16 max_rate = 0;
u32 usr_vht_cap_info = 0;
struct mwifiex_adapter *adapter = priv->adapter;
- /* tables of the MCS map to the highest data rate (in Mbps)
- * supported for long GI
- */
- u16 max_rate_lgi_80MHZ[8][3] = {
- {0x124, 0x15F, 0x186}, /* NSS = 1 */
- {0x249, 0x2BE, 0x30C}, /* NSS = 2 */
- {0x36D, 0x41D, 0x492}, /* NSS = 3 */
- {0x492, 0x57C, 0x618}, /* NSS = 4 */
- {0x5B6, 0x6DB, 0x79E}, /* NSS = 5 */
- {0x6DB, 0x83A, 0x0}, /* NSS = 6 */
- {0x7FF, 0x999, 0xAAA}, /* NSS = 7 */
- {0x924, 0xAF8, 0xC30} /* NSS = 8 */
- };
- u16 max_rate_lgi_160MHZ[8][3] = {
- {0x249, 0x2BE, 0x30C}, /* NSS = 1 */
- {0x492, 0x57C, 0x618}, /* NSS = 2 */
- {0x6DB, 0x83A, 0x0}, /* NSS = 3 */
- {0x924, 0xAF8, 0xC30}, /* NSS = 4 */
- {0xB6D, 0xDB6, 0xF3C}, /* NSS = 5 */
- {0xDB6, 0x1074, 0x1248}, /* NSS = 6 */
- {0xFFF, 0x1332, 0x1554}, /* NSS = 7 */
- {0x1248, 0x15F0, 0x1860} /* NSS = 8 */
- };
if (bands & BAND_AAC)
usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a;
@@ -64,29 +66,29 @@ mwifiex_convert_mcsmap_to_maxrate(struct mwifiex_private *priv,
usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg;
/* find the max NSS supported */
- nss = 0;
- for (i = 0; i < 8; i++) {
- max_mcs = (mcs_map >> (2 * i)) & 0x3;
- if (max_mcs < 3)
+ nss = 1;
+ for (i = 1; i <= 8; i++) {
+ mcs = GET_VHTNSSMCS(mcs_map, i);
+ if (mcs < IEEE80211_VHT_MCS_NOT_SUPPORTED)
nss = i;
}
- max_mcs = (mcs_map >> (2 * nss)) & 0x3;
+ mcs = GET_VHTNSSMCS(mcs_map, nss);
- /* if max_mcs is 3, nss must be 0 (SS = 1). Thus, max mcs is MCS 9 */
- if (max_mcs >= 3)
- max_mcs = 2;
+ /* if mcs is 3, nss must be 1 (NSS = 1). Default mcs to MCS 0~9 */
+ if (mcs == IEEE80211_VHT_MCS_NOT_SUPPORTED)
+ mcs = IEEE80211_VHT_MCS_SUPPORT_0_9;
if (GET_VHTCAP_CHWDSET(usr_vht_cap_info)) {
/* support 160 MHz */
- max_rate = max_rate_lgi_160MHZ[nss][max_mcs];
+ max_rate = max_rate_lgi_160MHZ[nss - 1][mcs];
if (!max_rate)
/* MCS9 is not supported in NSS6 */
- max_rate = max_rate_lgi_160MHZ[nss][max_mcs - 1];
+ max_rate = max_rate_lgi_160MHZ[nss - 1][mcs - 1];
} else {
- max_rate = max_rate_lgi_80MHZ[nss][max_mcs];
+ max_rate = max_rate_lgi_80MHZ[nss - 1][mcs];
if (!max_rate)
/* MCS9 is not supported in NSS3 */
- max_rate = max_rate_lgi_80MHZ[nss][max_mcs - 1];
+ max_rate = max_rate_lgi_80MHZ[nss - 1][mcs - 1];
}
return max_rate;
@@ -94,21 +96,20 @@ mwifiex_convert_mcsmap_to_maxrate(struct mwifiex_private *priv,
static void
mwifiex_fill_vht_cap_info(struct mwifiex_private *priv,
- struct mwifiex_ie_types_vhtcap *vht_cap, u8 bands)
+ struct ieee80211_vht_cap *vht_cap, u8 bands)
{
struct mwifiex_adapter *adapter = priv->adapter;
if (bands & BAND_A)
- vht_cap->vht_cap.vht_cap_info =
+ vht_cap->vht_cap_info =
cpu_to_le32(adapter->usr_dot_11ac_dev_cap_a);
else
- vht_cap->vht_cap.vht_cap_info =
+ vht_cap->vht_cap_info =
cpu_to_le32(adapter->usr_dot_11ac_dev_cap_bg);
}
-static void
-mwifiex_fill_vht_cap_tlv(struct mwifiex_private *priv,
- struct mwifiex_ie_types_vhtcap *vht_cap, u8 bands)
+void mwifiex_fill_vht_cap_tlv(struct mwifiex_private *priv,
+ struct ieee80211_vht_cap *vht_cap, u8 bands)
{
struct mwifiex_adapter *adapter = priv->adapter;
u16 mcs_map_user, mcs_map_resp, mcs_map_result;
@@ -119,46 +120,48 @@ mwifiex_fill_vht_cap_tlv(struct mwifiex_private *priv,
/* rx MCS Set: find the minimum of the user rx mcs and ap rx mcs */
mcs_map_user = GET_DEVRXMCSMAP(adapter->usr_dot_11ac_mcs_support);
- mcs_map_resp = le16_to_cpu(vht_cap->vht_cap.supp_mcs.rx_mcs_map);
+ mcs_map_resp = le16_to_cpu(vht_cap->supp_mcs.rx_mcs_map);
mcs_map_result = 0;
for (nss = 1; nss <= 8; nss++) {
mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
- if ((mcs_user == NO_NSS_SUPPORT) ||
- (mcs_resp == NO_NSS_SUPPORT))
- SET_VHTNSSMCS(mcs_map_result, nss, NO_NSS_SUPPORT);
+ if ((mcs_user == IEEE80211_VHT_MCS_NOT_SUPPORTED) ||
+ (mcs_resp == IEEE80211_VHT_MCS_NOT_SUPPORTED))
+ SET_VHTNSSMCS(mcs_map_result, nss,
+ IEEE80211_VHT_MCS_NOT_SUPPORTED);
else
SET_VHTNSSMCS(mcs_map_result, nss,
min(mcs_user, mcs_resp));
}
- vht_cap->vht_cap.supp_mcs.rx_mcs_map = cpu_to_le16(mcs_map_result);
+ vht_cap->supp_mcs.rx_mcs_map = cpu_to_le16(mcs_map_result);
tmp = mwifiex_convert_mcsmap_to_maxrate(priv, bands, mcs_map_result);
- vht_cap->vht_cap.supp_mcs.rx_highest = cpu_to_le16(tmp);
+ vht_cap->supp_mcs.rx_highest = cpu_to_le16(tmp);
/* tx MCS Set: find the minimum of the user tx mcs and ap tx mcs */
mcs_map_user = GET_DEVTXMCSMAP(adapter->usr_dot_11ac_mcs_support);
- mcs_map_resp = le16_to_cpu(vht_cap->vht_cap.supp_mcs.tx_mcs_map);
+ mcs_map_resp = le16_to_cpu(vht_cap->supp_mcs.tx_mcs_map);
mcs_map_result = 0;
for (nss = 1; nss <= 8; nss++) {
mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
- if ((mcs_user == NO_NSS_SUPPORT) ||
- (mcs_resp == NO_NSS_SUPPORT))
- SET_VHTNSSMCS(mcs_map_result, nss, NO_NSS_SUPPORT);
+ if ((mcs_user == IEEE80211_VHT_MCS_NOT_SUPPORTED) ||
+ (mcs_resp == IEEE80211_VHT_MCS_NOT_SUPPORTED))
+ SET_VHTNSSMCS(mcs_map_result, nss,
+ IEEE80211_VHT_MCS_NOT_SUPPORTED);
else
SET_VHTNSSMCS(mcs_map_result, nss,
min(mcs_user, mcs_resp));
}
- vht_cap->vht_cap.supp_mcs.tx_mcs_map = cpu_to_le16(mcs_map_result);
+ vht_cap->supp_mcs.tx_mcs_map = cpu_to_le16(mcs_map_result);
tmp = mwifiex_convert_mcsmap_to_maxrate(priv, bands, mcs_map_result);
- vht_cap->vht_cap.supp_mcs.tx_highest = cpu_to_le16(tmp);
+ vht_cap->supp_mcs.tx_highest = cpu_to_le16(tmp);
return;
}
@@ -189,11 +192,11 @@ int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
vht_cap->header.len =
cpu_to_le16(sizeof(struct ieee80211_vht_cap));
memcpy((u8 *)vht_cap + sizeof(struct mwifiex_ie_types_header),
- (u8 *)bss_desc->bcn_vht_cap +
- sizeof(struct ieee_types_header),
+ (u8 *)bss_desc->bcn_vht_cap,
le16_to_cpu(vht_cap->header.len));
- mwifiex_fill_vht_cap_tlv(priv, vht_cap, bss_desc->bss_band);
+ mwifiex_fill_vht_cap_tlv(priv, &vht_cap->vht_cap,
+ bss_desc->bss_band);
*buffer += sizeof(*vht_cap);
ret_len += sizeof(*vht_cap);
}
@@ -300,3 +303,81 @@ void mwifiex_set_11ac_ba_params(struct mwifiex_private *priv)
return;
}
+
+bool mwifiex_is_bss_in_11ac_mode(struct mwifiex_private *priv)
+{
+ struct mwifiex_bssdescriptor *bss_desc;
+ struct ieee80211_vht_operation *vht_oper;
+
+ bss_desc = &priv->curr_bss_params.bss_descriptor;
+ vht_oper = bss_desc->bcn_vht_oper;
+
+ if (!bss_desc->bcn_vht_cap || !vht_oper)
+ return false;
+
+ if (vht_oper->chan_width == IEEE80211_VHT_CHANWIDTH_USE_HT)
+ return false;
+
+ return true;
+}
+
+u8 mwifiex_get_center_freq_index(struct mwifiex_private *priv, u8 band,
+ u32 pri_chan, u8 chan_bw)
+{
+ u8 center_freq_idx = 0;
+
+ if (band & BAND_AAC) {
+ switch (pri_chan) {
+ case 36:
+ case 40:
+ case 44:
+ case 48:
+ if (chan_bw == IEEE80211_VHT_CHANWIDTH_80MHZ)
+ center_freq_idx = 42;
+ break;
+ case 52:
+ case 56:
+ case 60:
+ case 64:
+ if (chan_bw == IEEE80211_VHT_CHANWIDTH_80MHZ)
+ center_freq_idx = 58;
+ else if (chan_bw == IEEE80211_VHT_CHANWIDTH_160MHZ)
+ center_freq_idx = 50;
+ break;
+ case 100:
+ case 104:
+ case 108:
+ case 112:
+ if (chan_bw == IEEE80211_VHT_CHANWIDTH_80MHZ)
+ center_freq_idx = 106;
+ break;
+ case 116:
+ case 120:
+ case 124:
+ case 128:
+ if (chan_bw == IEEE80211_VHT_CHANWIDTH_80MHZ)
+ center_freq_idx = 122;
+ else if (chan_bw == IEEE80211_VHT_CHANWIDTH_160MHZ)
+ center_freq_idx = 114;
+ break;
+ case 132:
+ case 136:
+ case 140:
+ case 144:
+ if (chan_bw == IEEE80211_VHT_CHANWIDTH_80MHZ)
+ center_freq_idx = 138;
+ break;
+ case 149:
+ case 153:
+ case 157:
+ case 161:
+ if (chan_bw == IEEE80211_VHT_CHANWIDTH_80MHZ)
+ center_freq_idx = 155;
+ break;
+ default:
+ center_freq_idx = 42;
+ }
+ }
+
+ return center_freq_idx;
+}
diff --git a/drivers/net/wireless/mwifiex/11ac.h b/drivers/net/wireless/mwifiex/11ac.h
index 7c2c69b5b3eb..0b02cb6cfcb4 100644
--- a/drivers/net/wireless/mwifiex/11ac.h
+++ b/drivers/net/wireless/mwifiex/11ac.h
@@ -40,4 +40,6 @@ int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
int mwifiex_cmd_11ac_cfg(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd, u16 cmd_action,
struct mwifiex_11ac_vht_cfg *cfg);
+void mwifiex_fill_vht_cap_tlv(struct mwifiex_private *priv,
+ struct ieee80211_vht_cap *vht_cap, u8 bands);
#endif /* _MWIFIEX_11AC_H_ */
diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c
index 8d683070bdb3..e76b0db4e3e6 100644
--- a/drivers/net/wireless/mwifiex/11h.c
+++ b/drivers/net/wireless/mwifiex/11h.c
@@ -73,8 +73,8 @@ static int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag)
{
u32 enable = flag;
- return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
- HostCmd_ACT_GEN_SET, DOT11H_I, &enable);
+ return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, DOT11H_I, &enable, true);
}
/* This functions processes TLV buffer for a pending BSS Join command.
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c
index 6261f8c53d44..d14ead8beca8 100644
--- a/drivers/net/wireless/mwifiex/11n.c
+++ b/drivers/net/wireless/mwifiex/11n.c
@@ -34,22 +34,26 @@
*
* RD responder bit to set to clear in the extended capability header.
*/
-void
-mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type,
- struct mwifiex_ie_types_htcap *ht_cap)
+int mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type,
+ struct ieee80211_ht_cap *ht_cap)
{
- uint16_t ht_ext_cap = le16_to_cpu(ht_cap->ht_cap.extended_ht_cap_info);
+ uint16_t ht_ext_cap = le16_to_cpu(ht_cap->extended_ht_cap_info);
struct ieee80211_supported_band *sband =
priv->wdev->wiphy->bands[radio_type];
- ht_cap->ht_cap.ampdu_params_info =
+ if (WARN_ON_ONCE(!sband)) {
+ dev_err(priv->adapter->dev, "Invalid radio type!\n");
+ return -EINVAL;
+ }
+
+ ht_cap->ampdu_params_info =
(sband->ht_cap.ampdu_factor &
IEEE80211_HT_AMPDU_PARM_FACTOR) |
((sband->ht_cap.ampdu_density <<
IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT) &
IEEE80211_HT_AMPDU_PARM_DENSITY);
- memcpy((u8 *) &ht_cap->ht_cap.mcs, &sband->ht_cap.mcs,
+ memcpy((u8 *)&ht_cap->mcs, &sband->ht_cap.mcs,
sizeof(sband->ht_cap.mcs));
if (priv->bss_mode == NL80211_IFTYPE_STATION ||
@@ -57,13 +61,18 @@ mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type,
(priv->adapter->sec_chan_offset !=
IEEE80211_HT_PARAM_CHA_SEC_NONE)))
/* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */
- SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask);
+ SETHT_MCS32(ht_cap->mcs.rx_mask);
/* Clear RD responder bit */
ht_ext_cap &= ~IEEE80211_HT_EXT_CAP_RD_RESPONDER;
- ht_cap->ht_cap.cap_info = cpu_to_le16(sband->ht_cap.cap);
- ht_cap->ht_cap.extended_ht_cap_info = cpu_to_le16(ht_ext_cap);
+ ht_cap->cap_info = cpu_to_le16(sband->ht_cap.cap);
+ ht_cap->extended_ht_cap_info = cpu_to_le16(ht_ext_cap);
+
+ if (ISSUPP_BEAMFORMING(priv->adapter->hw_dot_11n_dev_cap))
+ ht_cap->tx_BF_cap_info = cpu_to_le32(MWIFIEX_DEF_11N_TX_BF_CAP);
+
+ return 0;
}
/*
@@ -150,28 +159,34 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
int tid;
struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &resp->params.add_ba_rsp;
struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl;
+ u16 block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set);
add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn))
& SSN_MASK);
- tid = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
- & IEEE80211_ADDBA_PARAM_TID_MASK)
- >> BLOCKACKPARAM_TID_POS;
- if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) {
- tx_ba_tbl = mwifiex_get_ba_tbl(priv, tid,
- add_ba_rsp->peer_mac_addr);
- if (tx_ba_tbl) {
- dev_dbg(priv->adapter->dev, "info: BA stream complete\n");
- tx_ba_tbl->ba_status = BA_SETUP_COMPLETE;
- } else {
- dev_err(priv->adapter->dev, "BA stream not created\n");
- }
- } else {
+ tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
+ >> BLOCKACKPARAM_TID_POS;
+ if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) {
mwifiex_del_ba_tbl(priv, tid, add_ba_rsp->peer_mac_addr,
TYPE_DELBA_SENT, true);
if (add_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT)
priv->aggr_prio_tbl[tid].ampdu_ap =
BA_STREAM_NOT_ALLOWED;
+ return 0;
+ }
+
+ tx_ba_tbl = mwifiex_get_ba_tbl(priv, tid, add_ba_rsp->peer_mac_addr);
+ if (tx_ba_tbl) {
+ dev_dbg(priv->adapter->dev, "info: BA stream complete\n");
+ tx_ba_tbl->ba_status = BA_SETUP_COMPLETE;
+ if ((block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) &&
+ priv->add_ba_param.tx_amsdu &&
+ (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED))
+ tx_ba_tbl->amsdu = true;
+ else
+ tx_ba_tbl->amsdu = false;
+ } else {
+ dev_err(priv->adapter->dev, "BA stream not created\n");
}
return 0;
@@ -308,11 +323,10 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
ht_cap->header.len =
cpu_to_le16(sizeof(struct ieee80211_ht_cap));
memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header),
- (u8 *) bss_desc->bcn_ht_cap +
- sizeof(struct ieee_types_header),
+ (u8 *)bss_desc->bcn_ht_cap,
le16_to_cpu(ht_cap->header.len));
- mwifiex_fill_cap_info(priv, radio_type, ht_cap);
+ mwifiex_fill_cap_info(priv, radio_type, &ht_cap->ht_cap);
*buffer += sizeof(struct mwifiex_ie_types_htcap);
ret_len += sizeof(struct mwifiex_ie_types_htcap);
@@ -528,16 +542,39 @@ void mwifiex_create_ba_tbl(struct mwifiex_private *priv, u8 *ra, int tid,
int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
{
struct host_cmd_ds_11n_addba_req add_ba_req;
+ struct mwifiex_sta_node *sta_ptr;
+ u32 tx_win_size = priv->add_ba_param.tx_win_size;
static u8 dialog_tok;
int ret;
+ u16 block_ack_param_set;
dev_dbg(priv->adapter->dev, "cmd: %s: tid %d\n", __func__, tid);
- add_ba_req.block_ack_param_set = cpu_to_le16(
- (u16) ((tid << BLOCKACKPARAM_TID_POS) |
- (priv->add_ba_param.
- tx_win_size << BLOCKACKPARAM_WINSIZE_POS) |
- IMMEDIATE_BLOCK_ACK));
+ if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
+ ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
+ priv->adapter->is_hw_11ac_capable &&
+ memcmp(priv->cfg_bssid, peer_mac, ETH_ALEN)) {
+ sta_ptr = mwifiex_get_sta_entry(priv, peer_mac);
+ if (!sta_ptr) {
+ dev_warn(priv->adapter->dev,
+ "BA setup with unknown TDLS peer %pM!\n",
+ peer_mac);
+ return -1;
+ }
+ if (sta_ptr->is_11ac_enabled)
+ tx_win_size = MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE;
+ }
+
+ block_ack_param_set = (u16)((tid << BLOCKACKPARAM_TID_POS) |
+ tx_win_size << BLOCKACKPARAM_WINSIZE_POS |
+ IMMEDIATE_BLOCK_ACK);
+
+ /* enable AMSDU inside AMPDU */
+ if (priv->add_ba_param.tx_amsdu &&
+ (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED))
+ block_ack_param_set |= BLOCKACKPARAM_AMSDU_SUPP_MASK;
+
+ add_ba_req.block_ack_param_set = cpu_to_le16(block_ack_param_set);
add_ba_req.block_ack_tmo = cpu_to_le16((u16)priv->add_ba_param.timeout);
++dialog_tok;
@@ -549,8 +586,8 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN);
/* We don't wait for the response of this command */
- ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_REQ,
- 0, 0, &add_ba_req);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_ADDBA_REQ,
+ 0, 0, &add_ba_req, false);
return ret;
}
@@ -577,8 +614,8 @@ int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN);
/* We don't wait for the response of this command */
- ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA,
- HostCmd_ACT_GEN_SET, 0, &delba);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_DELBA,
+ HostCmd_ACT_GEN_SET, 0, &delba, false);
return ret;
}
@@ -652,6 +689,7 @@ int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
dev_dbg(priv->adapter->dev, "data: %s tid=%d\n",
__func__, rx_reo_tbl->tid);
memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN);
+ rx_reo_tbl->amsdu = tx_ba_tsr_tbl->amsdu;
rx_reo_tbl++;
count++;
if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED)
@@ -707,5 +745,8 @@ void mwifiex_set_ba_params(struct mwifiex_private *priv)
MWIFIEX_STA_AMPDU_DEF_RXWINSIZE;
}
+ priv->add_ba_param.tx_amsdu = true;
+ priv->add_ba_param.rx_amsdu = true;
+
return;
}
diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h
index 375db01442bf..40b007a00f4b 100644
--- a/drivers/net/wireless/mwifiex/11n.h
+++ b/drivers/net/wireless/mwifiex/11n.h
@@ -34,8 +34,8 @@ int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv,
int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
struct mwifiex_bssdescriptor *bss_desc,
u8 **buffer);
-void mwifiex_fill_cap_info(struct mwifiex_private *, u8 radio_type,
- struct mwifiex_ie_types_htcap *);
+int mwifiex_fill_cap_info(struct mwifiex_private *, u8 radio_type,
+ struct ieee80211_ht_cap *);
int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv,
u16 action, int *htcap_cfg);
void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv,
@@ -64,14 +64,46 @@ int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd,
struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl);
void mwifiex_del_tx_ba_stream_tbl_by_ra(struct mwifiex_private *priv, u8 *ra);
-/*
- * This function checks whether AMPDU is allowed or not for a particular TID.
- */
static inline u8
-mwifiex_is_ampdu_allowed(struct mwifiex_private *priv, int tid)
+mwifiex_is_station_ampdu_allowed(struct mwifiex_private *priv,
+ struct mwifiex_ra_list_tbl *ptr, int tid)
{
- return ((priv->aggr_prio_tbl[tid].ampdu_ap != BA_STREAM_NOT_ALLOWED)
- ? true : false);
+ struct mwifiex_sta_node *node = mwifiex_get_sta_entry(priv, ptr->ra);
+
+ if (unlikely(!node))
+ return false;
+
+ return (node->ampdu_sta[tid] != BA_STREAM_NOT_ALLOWED) ? true : false;
+}
+
+/* This function checks whether AMSDU is allowed for BA stream. */
+static inline u8
+mwifiex_is_amsdu_in_ampdu_allowed(struct mwifiex_private *priv,
+ struct mwifiex_ra_list_tbl *ptr, int tid)
+{
+ struct mwifiex_tx_ba_stream_tbl *tx_tbl;
+
+ tx_tbl = mwifiex_get_ba_tbl(priv, tid, ptr->ra);
+ if (tx_tbl)
+ return tx_tbl->amsdu;
+
+ return false;
+}
+
+/* This function checks whether AMPDU is allowed or not for a particular TID. */
+static inline u8
+mwifiex_is_ampdu_allowed(struct mwifiex_private *priv,
+ struct mwifiex_ra_list_tbl *ptr, int tid)
+{
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
+ return mwifiex_is_station_ampdu_allowed(priv, ptr, tid);
+ } else {
+ if (ptr->tdls_link)
+ return mwifiex_is_station_ampdu_allowed(priv, ptr, tid);
+
+ return (priv->aggr_prio_tbl[tid].ampdu_ap !=
+ BA_STREAM_NOT_ALLOWED) ? true : false;
+ }
}
/*
@@ -165,4 +197,14 @@ static inline int mwifiex_is_sta_11n_enabled(struct mwifiex_private *priv,
return node->is_11n_enabled;
}
+
+static inline u8
+mwifiex_tdls_peer_11n_enabled(struct mwifiex_private *priv, u8 *ra)
+{
+ struct mwifiex_sta_node *node = mwifiex_get_sta_entry(priv, ra);
+ if (node)
+ return node->is_11n_enabled;
+
+ return false;
+}
#endif /* !_MWIFIEX_11N_H_ */
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c
index ada809f576fe..0c3571f830b0 100644
--- a/drivers/net/wireless/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c
@@ -26,6 +26,56 @@
#include "11n.h"
#include "11n_rxreorder.h"
+/* This function will dispatch amsdu packet and forward it to kernel/upper
+ * layer.
+ */
+static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv,
+ struct sk_buff *skb)
+{
+ struct rxpd *local_rx_pd = (struct rxpd *)(skb->data);
+ int ret;
+
+ if (le16_to_cpu(local_rx_pd->rx_pkt_type) == PKT_TYPE_AMSDU) {
+ struct sk_buff_head list;
+ struct sk_buff *rx_skb;
+
+ __skb_queue_head_init(&list);
+
+ skb_pull(skb, le16_to_cpu(local_rx_pd->rx_pkt_offset));
+ skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length));
+
+ ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
+ priv->wdev->iftype, 0, false);
+
+ while (!skb_queue_empty(&list)) {
+ rx_skb = __skb_dequeue(&list);
+ ret = mwifiex_recv_packet(priv, rx_skb);
+ if (ret == -1)
+ dev_err(priv->adapter->dev,
+ "Rx of A-MSDU failed");
+ }
+ return 0;
+ }
+
+ return -1;
+}
+
+/* This function will process the rx packet and forward it to kernel/upper
+ * layer.
+ */
+static int mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv, void *payload)
+{
+ int ret = mwifiex_11n_dispatch_amsdu_pkt(priv, payload);
+
+ if (!ret)
+ return 0;
+
+ if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
+ return mwifiex_handle_uap_rx_forward(priv, payload);
+
+ return mwifiex_process_rx_packet(priv, payload);
+}
+
/*
* This function dispatches all packets in the Rx reorder table until the
* start window.
@@ -35,8 +85,9 @@
* circular buffer.
*/
static void
-mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv,
- struct mwifiex_rx_reorder_tbl *tbl, int start_win)
+mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
+ struct mwifiex_rx_reorder_tbl *tbl,
+ int start_win)
{
int pkt_to_send, i;
void *rx_tmp_ptr;
@@ -54,12 +105,8 @@ mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv,
tbl->rx_reorder_ptr[i] = NULL;
}
spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
- if (rx_tmp_ptr) {
- if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
- mwifiex_handle_uap_rx_forward(priv, rx_tmp_ptr);
- else
- mwifiex_process_rx_packet(priv, rx_tmp_ptr);
- }
+ if (rx_tmp_ptr)
+ mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr);
}
spin_lock_irqsave(&priv->rx_pkt_lock, flags);
@@ -101,11 +148,7 @@ mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
rx_tmp_ptr = tbl->rx_reorder_ptr[i];
tbl->rx_reorder_ptr[i] = NULL;
spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
-
- if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
- mwifiex_handle_uap_rx_forward(priv, rx_tmp_ptr);
- else
- mwifiex_process_rx_packet(priv, rx_tmp_ptr);
+ mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr);
}
spin_lock_irqsave(&priv->rx_pkt_lock, flags);
@@ -135,14 +178,15 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
struct mwifiex_rx_reorder_tbl *tbl)
{
unsigned long flags;
+ int start_win;
if (!tbl)
return;
- mwifiex_11n_dispatch_pkt(priv, tbl, (tbl->start_win + tbl->win_size) &
- (MAX_TID_VALUE - 1));
+ start_win = (tbl->start_win + tbl->win_size) & (MAX_TID_VALUE - 1);
+ mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win);
- del_timer(&tbl->timer_context.timer);
+ del_timer_sync(&tbl->timer_context.timer);
spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
list_del(&tbl->list);
@@ -228,17 +272,17 @@ mwifiex_flush_data(unsigned long context)
{
struct reorder_tmr_cnxt *ctx =
(struct reorder_tmr_cnxt *) context;
- int start_win;
+ int start_win, seq_num;
- start_win = mwifiex_11n_find_last_seq_num(ctx->ptr);
+ seq_num = mwifiex_11n_find_last_seq_num(ctx->ptr);
- if (start_win < 0)
+ if (seq_num < 0)
return;
- dev_dbg(ctx->priv->adapter->dev, "info: flush data %d\n", start_win);
- mwifiex_11n_dispatch_pkt(ctx->priv, ctx->ptr,
- (ctx->ptr->start_win + start_win + 1) &
- (MAX_TID_VALUE - 1));
+ dev_dbg(ctx->priv->adapter->dev, "info: flush data %d\n", seq_num);
+ start_win = (ctx->ptr->start_win + seq_num + 1) & (MAX_TID_VALUE - 1);
+ mwifiex_11n_dispatch_pkt_until_start_win(ctx->priv, ctx->ptr,
+ start_win);
}
/*
@@ -267,7 +311,7 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
*/
tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
if (tbl) {
- mwifiex_11n_dispatch_pkt(priv, tbl, seq_num);
+ mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, seq_num);
return;
}
/* if !tbl then create one */
@@ -279,6 +323,8 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
new_node->tid = tid;
memcpy(new_node->ta, ta, ETH_ALEN);
new_node->start_win = seq_num;
+ new_node->init_win = seq_num;
+ new_node->flags = 0;
if (mwifiex_queuing_ra_based(priv)) {
dev_dbg(priv->adapter->dev,
@@ -290,15 +336,20 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
last_seq = node->rx_seq[tid];
}
} else {
- last_seq = priv->rx_seq[tid];
+ node = mwifiex_get_sta_entry(priv, ta);
+ if (node)
+ last_seq = node->rx_seq[tid];
+ else
+ last_seq = priv->rx_seq[tid];
}
if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM &&
- last_seq >= new_node->start_win)
+ last_seq >= new_node->start_win) {
new_node->start_win = last_seq + 1;
+ new_node->flags |= RXREOR_INIT_WINDOW_SHIFT;
+ }
new_node->win_size = win_size;
- new_node->flags = 0;
new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size,
GFP_KERNEL);
@@ -358,10 +409,28 @@ int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
*cmd_addba_req)
{
struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &cmd->params.add_ba_rsp;
+ struct mwifiex_sta_node *sta_ptr;
+ u32 rx_win_size = priv->add_ba_param.rx_win_size;
u8 tid;
int win_size;
uint16_t block_ack_param_set;
+ if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
+ ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
+ priv->adapter->is_hw_11ac_capable &&
+ memcmp(priv->cfg_bssid, cmd_addba_req->peer_mac_addr, ETH_ALEN)) {
+ sta_ptr = mwifiex_get_sta_entry(priv,
+ cmd_addba_req->peer_mac_addr);
+ if (!sta_ptr) {
+ dev_warn(priv->adapter->dev,
+ "BA setup with unknown TDLS peer %pM!\n",
+ cmd_addba_req->peer_mac_addr);
+ return -1;
+ }
+ if (sta_ptr->is_11ac_enabled)
+ rx_win_size = MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE;
+ }
+
cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN);
@@ -376,10 +445,12 @@ int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
>> BLOCKACKPARAM_TID_POS;
add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT);
block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
- /* We donot support AMSDU inside AMPDU, hence reset the bit */
- block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
- block_ack_param_set |= (priv->add_ba_param.rx_win_size <<
- BLOCKACKPARAM_WINSIZE_POS);
+
+ /* If we don't support AMSDU inside AMPDU, reset the bit */
+ if (!priv->add_ba_param.rx_amsdu ||
+ (priv->aggr_prio_tbl[tid].amsdu == BA_STREAM_NOT_ALLOWED))
+ block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
+ block_ack_param_set |= rx_win_size << BLOCKACKPARAM_WINSIZE_POS;
add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set);
win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
& IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
@@ -431,33 +502,46 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
struct mwifiex_rx_reorder_tbl *tbl;
int start_win, end_win, win_size;
u16 pkt_index;
+ bool init_window_shift = false;
tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
if (!tbl) {
- if (pkt_type != PKT_TYPE_BAR) {
- if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
- mwifiex_handle_uap_rx_forward(priv, payload);
- else
- mwifiex_process_rx_packet(priv, payload);
- }
+ if (pkt_type != PKT_TYPE_BAR)
+ mwifiex_11n_dispatch_pkt(priv, payload);
return 0;
}
+
+ if ((pkt_type == PKT_TYPE_AMSDU) && !tbl->amsdu) {
+ mwifiex_11n_dispatch_pkt(priv, payload);
+ return 0;
+ }
+
start_win = tbl->start_win;
win_size = tbl->win_size;
end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
- del_timer(&tbl->timer_context.timer);
+ if (tbl->flags & RXREOR_INIT_WINDOW_SHIFT) {
+ init_window_shift = true;
+ tbl->flags &= ~RXREOR_INIT_WINDOW_SHIFT;
+ }
mod_timer(&tbl->timer_context.timer,
jiffies + msecs_to_jiffies(MIN_FLUSH_TIMER_MS * win_size));
- /*
- * If seq_num is less then starting win then ignore and drop the
- * packet
- */
if (tbl->flags & RXREOR_FORCE_NO_DROP) {
dev_dbg(priv->adapter->dev,
"RXREOR_FORCE_NO_DROP when HS is activated\n");
tbl->flags &= ~RXREOR_FORCE_NO_DROP;
+ } else if (init_window_shift && seq_num < start_win &&
+ seq_num >= tbl->init_win) {
+ dev_dbg(priv->adapter->dev,
+ "Sender TID sequence number reset %d->%d for SSN %d\n",
+ start_win, seq_num, tbl->init_win);
+ tbl->start_win = start_win = seq_num;
+ end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
} else {
+ /*
+ * If seq_num is less then starting win then ignore and drop
+ * the packet
+ */
if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {
if (seq_num >= ((start_win + TWOPOW11) &
(MAX_TID_VALUE - 1)) &&
@@ -485,7 +569,7 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
start_win = (end_win - win_size) + 1;
else
start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1;
- mwifiex_11n_dispatch_pkt(priv, tbl, start_win);
+ mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win);
}
if (pkt_type != PKT_TYPE_BAR) {
@@ -576,16 +660,7 @@ int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
* Check if we had rejected the ADDBA, if yes then do not create
* the stream
*/
- if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) {
- win_size = (block_ack_param_set &
- IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
- >> BLOCKACKPARAM_WINSIZE_POS;
-
- dev_dbg(priv->adapter->dev,
- "cmd: ADDBA RSP: %pM tid=%d ssn=%d win_size=%d\n",
- add_ba_rsp->peer_mac_addr, tid,
- add_ba_rsp->ssn, win_size);
- } else {
+ if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) {
dev_err(priv->adapter->dev, "ADDBA RSP: failed %pM tid=%d)\n",
add_ba_rsp->peer_mac_addr, tid);
@@ -593,8 +668,28 @@ int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
add_ba_rsp->peer_mac_addr);
if (tbl)
mwifiex_del_rx_reorder_entry(priv, tbl);
+
+ return 0;
}
+ win_size = (block_ack_param_set & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
+ >> BLOCKACKPARAM_WINSIZE_POS;
+
+ tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
+ add_ba_rsp->peer_mac_addr);
+ if (tbl) {
+ if ((block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) &&
+ priv->add_ba_param.rx_amsdu &&
+ (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED))
+ tbl->amsdu = true;
+ else
+ tbl->amsdu = false;
+ }
+
+ dev_dbg(priv->adapter->dev,
+ "cmd: ADDBA RSP: %pM tid=%d ssn=%d win_size=%d\n",
+ add_ba_rsp->peer_mac_addr, tid, add_ba_rsp->ssn, win_size);
+
return 0;
}
@@ -615,7 +710,7 @@ void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv,
delba.del_ba_param_set |= cpu_to_le16(
(u16) event->origninator << DELBA_INITIATOR_POS);
delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT);
- mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba);
+ mwifiex_send_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba, false);
}
/*
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.h b/drivers/net/wireless/mwifiex/11n_rxreorder.h
index 4064041ac852..0fc76e4a60f8 100644
--- a/drivers/net/wireless/mwifiex/11n_rxreorder.h
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.h
@@ -42,7 +42,8 @@
#define BA_SETUP_PACKET_OFFSET 16
enum mwifiex_rxreor_flags {
- RXREOR_FORCE_NO_DROP = 1<<0,
+ RXREOR_FORCE_NO_DROP = 1<<0,
+ RXREOR_INIT_WINDOW_SHIFT = 1<<1,
};
static inline void mwifiex_reset_11n_rx_seq_num(struct mwifiex_private *priv)
diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile
index a42a506fd32b..2aa208ffbe23 100644
--- a/drivers/net/wireless/mwifiex/Makefile
+++ b/drivers/net/wireless/mwifiex/Makefile
@@ -41,6 +41,7 @@ mwifiex-y += uap_txrx.o
mwifiex-y += cfg80211.o
mwifiex-y += ethtool.o
mwifiex-y += 11h.o
+mwifiex-y += tdls.o
mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o
obj-$(CONFIG_MWIFIEX) += mwifiex.o
diff --git a/drivers/net/wireless/mwifiex/README b/drivers/net/wireless/mwifiex/README
index 3d64613ebb29..b9242c3dca43 100644
--- a/drivers/net/wireless/mwifiex/README
+++ b/drivers/net/wireless/mwifiex/README
@@ -131,7 +131,7 @@ info
hs_configured = <0/1, host sleep not configured/configured>
hs_activated = <0/1, extended host sleep not activated/activated>
num_tx_timeout = <number of Tx timeout>
- num_cmd_timeout = <number of timeout commands>
+ is_cmd_timedout = <0/1 command timeout not occurred/occurred>
timeout_cmd_id = <command id of the last timeout command>
timeout_cmd_act = <command action of the last timeout command>
last_cmd_id = <command id of the last several commands sent to device>
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 8bfc07cd330e..21ee27ab7b74 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -252,9 +252,9 @@ mwifiex_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
if (mask != priv->mgmt_frame_mask) {
priv->mgmt_frame_mask = mask;
- mwifiex_send_cmd_async(priv, HostCmd_CMD_MGMT_FRAME_REG,
- HostCmd_ACT_GEN_SET, 0,
- &priv->mgmt_frame_mask);
+ mwifiex_send_cmd(priv, HostCmd_CMD_MGMT_FRAME_REG,
+ HostCmd_ACT_GEN_SET, 0,
+ &priv->mgmt_frame_mask, false);
wiphy_dbg(wiphy, "info: mgmt frame registered\n");
}
}
@@ -515,8 +515,8 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
- if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
- HostCmd_ACT_GEN_SET, 0, NULL)) {
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
+ HostCmd_ACT_GEN_SET, 0, NULL, false)) {
wiphy_err(wiphy, "11D: setting domain info in FW\n");
return -1;
}
@@ -580,9 +580,9 @@ mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr)
frag_thr > MWIFIEX_FRAG_MAX_VALUE)
frag_thr = MWIFIEX_FRAG_MAX_VALUE;
- return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
- HostCmd_ACT_GEN_SET, FRAG_THRESH_I,
- &frag_thr);
+ return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, FRAG_THRESH_I,
+ &frag_thr, true);
}
/*
@@ -597,9 +597,9 @@ mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr)
if (rts_thr < MWIFIEX_RTS_MIN_VALUE || rts_thr > MWIFIEX_RTS_MAX_VALUE)
rts_thr = MWIFIEX_RTS_MAX_VALUE;
- return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
- HostCmd_ACT_GEN_SET, RTS_THRESH_I,
- &rts_thr);
+ return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, RTS_THRESH_I,
+ &rts_thr, true);
}
/*
@@ -637,20 +637,19 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
bss_started = priv->bss_started;
- ret = mwifiex_send_cmd_sync(priv,
- HostCmd_CMD_UAP_BSS_STOP,
- HostCmd_ACT_GEN_SET, 0,
- NULL);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
+ HostCmd_ACT_GEN_SET, 0,
+ NULL, true);
if (ret) {
wiphy_err(wiphy, "Failed to stop the BSS\n");
kfree(bss_cfg);
return ret;
}
- ret = mwifiex_send_cmd_async(priv,
- HostCmd_CMD_UAP_SYS_CONFIG,
- HostCmd_ACT_GEN_SET,
- UAP_BSS_PARAMS_I, bss_cfg);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
+ HostCmd_ACT_GEN_SET,
+ UAP_BSS_PARAMS_I, bss_cfg,
+ false);
kfree(bss_cfg);
@@ -662,10 +661,9 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
if (!bss_started)
break;
- ret = mwifiex_send_cmd_async(priv,
- HostCmd_CMD_UAP_BSS_START,
- HostCmd_ACT_GEN_SET, 0,
- NULL);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START,
+ HostCmd_ACT_GEN_SET, 0,
+ NULL, false);
if (ret) {
wiphy_err(wiphy, "Failed to start BSS\n");
return ret;
@@ -700,8 +698,8 @@ mwifiex_cfg80211_deinit_p2p(struct mwifiex_private *priv)
if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA)
mwifiex_set_bss_role(priv, MWIFIEX_BSS_ROLE_STA);
- if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
- HostCmd_ACT_GEN_SET, 0, &mode))
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG,
+ HostCmd_ACT_GEN_SET, 0, &mode, true))
return -1;
return 0;
@@ -721,13 +719,13 @@ mwifiex_cfg80211_init_p2p_client(struct mwifiex_private *priv)
return -1;
mode = P2P_MODE_DEVICE;
- if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
- HostCmd_ACT_GEN_SET, 0, &mode))
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG,
+ HostCmd_ACT_GEN_SET, 0, &mode, true))
return -1;
mode = P2P_MODE_CLIENT;
- if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
- HostCmd_ACT_GEN_SET, 0, &mode))
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG,
+ HostCmd_ACT_GEN_SET, 0, &mode, true))
return -1;
return 0;
@@ -747,13 +745,13 @@ mwifiex_cfg80211_init_p2p_go(struct mwifiex_private *priv)
return -1;
mode = P2P_MODE_DEVICE;
- if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
- HostCmd_ACT_GEN_SET, 0, &mode))
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG,
+ HostCmd_ACT_GEN_SET, 0, &mode, true))
return -1;
mode = P2P_MODE_GO;
- if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
- HostCmd_ACT_GEN_SET, 0, &mode))
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG,
+ HostCmd_ACT_GEN_SET, 0, &mode, true))
return -1;
if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP)
@@ -853,8 +851,8 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM;
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_SET_BSS_MODE,
- HostCmd_ACT_GEN_SET, 0, NULL);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
+ HostCmd_ACT_GEN_SET, 0, NULL, true);
return ret;
}
@@ -942,8 +940,8 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG;
/* Get signal information from the firmware */
- if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_RSSI_INFO,
- HostCmd_ACT_GEN_GET, 0, NULL)) {
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
+ HostCmd_ACT_GEN_GET, 0, NULL, true)) {
dev_err(priv->adapter->dev, "failed to get signal information\n");
return -EFAULT;
}
@@ -954,9 +952,9 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
}
/* Get DTIM period information from firmware */
- mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
- HostCmd_ACT_GEN_GET, DTIM_PERIOD_I,
- &priv->dtim_period);
+ mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_GET, DTIM_PERIOD_I,
+ &priv->dtim_period, true);
mwifiex_parse_htinfo(priv, priv->tx_htinfo, &sinfo->txrate);
@@ -1160,9 +1158,10 @@ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
enum ieee80211_band band;
+ struct mwifiex_adapter *adapter = priv->adapter;
if (!priv->media_connected) {
- dev_err(priv->adapter->dev,
+ dev_err(adapter->dev,
"Can not set Tx data rate in disconnected state\n");
return -EINVAL;
}
@@ -1183,11 +1182,18 @@ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
/* Fill HT MCS rates */
bitmap_rates[2] = mask->control[band].ht_mcs[0];
- if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2)
+ if (adapter->hw_dev_mcs_support == HT_STREAM_2X2)
bitmap_rates[2] |= mask->control[band].ht_mcs[1] << 8;
- return mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG,
- HostCmd_ACT_GEN_SET, 0, bitmap_rates);
+ /* Fill VHT MCS rates */
+ if (adapter->fw_api_ver == MWIFIEX_FW_V15) {
+ bitmap_rates[10] = mask->control[band].vht_mcs[0];
+ if (adapter->hw_dev_mcs_support == HT_STREAM_2X2)
+ bitmap_rates[11] = mask->control[band].vht_mcs[1];
+ }
+
+ return mwifiex_send_cmd(priv, HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_SET, 0, bitmap_rates, true);
}
/*
@@ -1216,14 +1222,14 @@ static int mwifiex_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy,
subsc_evt.bcn_h_rssi_cfg.abs_value = abs(rssi_thold);
subsc_evt.bcn_l_rssi_cfg.evt_freq = 1;
subsc_evt.bcn_h_rssi_cfg.evt_freq = 1;
- return mwifiex_send_cmd_sync(priv,
- HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
- 0, 0, &subsc_evt);
+ return mwifiex_send_cmd(priv,
+ HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
+ 0, 0, &subsc_evt, true);
} else {
subsc_evt.action = HostCmd_ACT_BITWISE_CLR;
- return mwifiex_send_cmd_sync(priv,
- HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
- 0, 0, &subsc_evt);
+ return mwifiex_send_cmd(priv,
+ HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
+ 0, 0, &subsc_evt, true);
}
return 0;
@@ -1276,10 +1282,9 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,
if (!mac || is_broadcast_ether_addr(mac)) {
wiphy_dbg(wiphy, "%s: NULL/broadcast mac address\n", __func__);
list_for_each_entry(sta_node, &priv->sta_list, list) {
- if (mwifiex_send_cmd_sync(priv,
- HostCmd_CMD_UAP_STA_DEAUTH,
- HostCmd_ACT_GEN_SET, 0,
- sta_node->mac_addr))
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_STA_DEAUTH,
+ HostCmd_ACT_GEN_SET, 0,
+ sta_node->mac_addr, true))
return -1;
mwifiex_uap_del_sta_data(priv, sta_node);
}
@@ -1289,10 +1294,9 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,
sta_node = mwifiex_get_sta_entry(priv, mac);
spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
if (sta_node) {
- if (mwifiex_send_cmd_sync(priv,
- HostCmd_CMD_UAP_STA_DEAUTH,
- HostCmd_ACT_GEN_SET, 0,
- sta_node->mac_addr))
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_STA_DEAUTH,
+ HostCmd_ACT_GEN_SET, 0,
+ sta_node->mac_addr, true))
return -1;
mwifiex_uap_del_sta_data(priv, sta_node);
}
@@ -1328,13 +1332,40 @@ mwifiex_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant)
tx_ant = RF_ANTENNA_AUTO;
rx_ant = RF_ANTENNA_AUTO;
}
+ } else {
+ struct ieee80211_sta_ht_cap *ht_info;
+ int rx_mcs_supp;
+ enum ieee80211_band band;
+
+ if ((tx_ant == 0x1 && rx_ant == 0x1)) {
+ adapter->user_dev_mcs_support = HT_STREAM_1X1;
+ if (adapter->is_hw_11ac_capable)
+ adapter->usr_dot_11ac_mcs_support =
+ MWIFIEX_11AC_MCS_MAP_1X1;
+ } else {
+ adapter->user_dev_mcs_support = HT_STREAM_2X2;
+ if (adapter->is_hw_11ac_capable)
+ adapter->usr_dot_11ac_mcs_support =
+ MWIFIEX_11AC_MCS_MAP_2X2;
+ }
+
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ if (!adapter->wiphy->bands[band])
+ continue;
+
+ ht_info = &adapter->wiphy->bands[band]->ht_cap;
+ rx_mcs_supp =
+ GET_RXMCSSUPP(adapter->user_dev_mcs_support);
+ memset(&ht_info->mcs, 0, adapter->number_of_antenna);
+ memset(&ht_info->mcs, 0xff, rx_mcs_supp);
+ }
}
ant_cfg.tx_ant = tx_ant;
ant_cfg.rx_ant = rx_ant;
- return mwifiex_send_cmd_sync(priv, HostCmd_CMD_RF_ANTENNA,
- HostCmd_ACT_GEN_SET, 0, &ant_cfg);
+ return mwifiex_send_cmd(priv, HostCmd_CMD_RF_ANTENNA,
+ HostCmd_ACT_GEN_SET, 0, &ant_cfg, true);
}
/* cfg80211 operation handler for stop ap.
@@ -1349,8 +1380,8 @@ static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
priv->ap_11n_enabled = 0;
- if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
- HostCmd_ACT_GEN_SET, 0, NULL)) {
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
+ HostCmd_ACT_GEN_SET, 0, NULL, true)) {
wiphy_err(wiphy, "Failed to stop the BSS\n");
return -1;
}
@@ -1416,9 +1447,6 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
config_bands |= BAND_GN;
-
- if (params->chandef.width > NL80211_CHAN_WIDTH_40)
- config_bands |= BAND_GAC;
} else {
bss_cfg->band_cfg = BAND_CONFIG_A;
config_bands = BAND_A;
@@ -1464,16 +1492,16 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
bss_cfg->ps_sta_ao_timer = 10 * params->inactivity_timeout;
}
- if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
- HostCmd_ACT_GEN_SET, 0, NULL)) {
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
+ HostCmd_ACT_GEN_SET, 0, NULL, true)) {
wiphy_err(wiphy, "Failed to stop the BSS\n");
kfree(bss_cfg);
return -1;
}
- if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG,
- HostCmd_ACT_GEN_SET,
- UAP_BSS_PARAMS_I, bss_cfg)) {
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
+ HostCmd_ACT_GEN_SET,
+ UAP_BSS_PARAMS_I, bss_cfg, false)) {
wiphy_err(wiphy, "Failed to set the SSID\n");
kfree(bss_cfg);
return -1;
@@ -1481,8 +1509,8 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
kfree(bss_cfg);
- if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_BSS_START,
- HostCmd_ACT_GEN_SET, 0, NULL)) {
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START,
+ HostCmd_ACT_GEN_SET, 0, NULL, false)) {
wiphy_err(wiphy, "Failed to start the BSS\n");
return -1;
}
@@ -1492,9 +1520,9 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
else
priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
- if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL,
- HostCmd_ACT_GEN_SET, 0,
- &priv->curr_pkt_filter))
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0,
+ &priv->curr_pkt_filter, true))
return -1;
return 0;
@@ -1583,8 +1611,9 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
* the function notifies the CFG802.11 subsystem of the new BSS connection.
*/
static int
-mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
- u8 *bssid, int mode, struct ieee80211_channel *channel,
+mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len,
+ const u8 *ssid, const u8 *bssid, int mode,
+ struct ieee80211_channel *channel,
struct cfg80211_connect_params *sme, bool privacy)
{
struct cfg80211_ssid req_ssid;
@@ -1881,7 +1910,8 @@ mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
params->privacy);
done:
if (!ret) {
- cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL);
+ cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid,
+ params->chandef.chan, GFP_KERNEL);
dev_dbg(priv->adapter->dev,
"info: joined/created adhoc network with bssid"
" %pM successfully\n", priv->cfg_bssid);
@@ -2070,10 +2100,10 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info,
else
ht_info->cap &= ~IEEE80211_HT_CAP_SGI_40;
- if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap))
- ht_info->cap |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT;
+ if (adapter->user_dev_mcs_support == HT_STREAM_2X2)
+ ht_info->cap |= 3 << IEEE80211_HT_CAP_RX_STBC_SHIFT;
else
- ht_info->cap &= ~(3 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+ ht_info->cap |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT;
if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap))
ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
@@ -2098,8 +2128,8 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info,
ht_info->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU;
ht_info->cap |= IEEE80211_HT_CAP_SM_PS;
- rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support);
- /* Set MCS for 1x1 */
+ rx_mcs_supp = GET_RXMCSSUPP(adapter->user_dev_mcs_support);
+ /* Set MCS for 1x1/2x2 */
memset(mcs, 0xff, rx_mcs_supp);
/* Clear all the other values */
memset(&mcs[rx_mcs_supp], 0,
@@ -2460,9 +2490,8 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
MWIFIEX_CRITERIA_UNICAST |
MWIFIEX_CRITERIA_MULTICAST;
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MEF_CFG,
- HostCmd_ACT_GEN_SET, 0,
- &mef_cfg);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_MEF_CFG,
+ HostCmd_ACT_GEN_SET, 0, &mef_cfg, true);
kfree(mef_entry);
return ret;
@@ -2574,9 +2603,9 @@ static int mwifiex_cfg80211_set_coalesce(struct wiphy *wiphy,
if (!coalesce) {
dev_dbg(adapter->dev,
"Disable coalesce and reset all previous rules\n");
- return mwifiex_send_cmd_sync(priv, HostCmd_CMD_COALESCE_CFG,
- HostCmd_ACT_GEN_SET, 0,
- &coalesce_cfg);
+ return mwifiex_send_cmd(priv, HostCmd_CMD_COALESCE_CFG,
+ HostCmd_ACT_GEN_SET, 0,
+ &coalesce_cfg, true);
}
coalesce_cfg.num_of_rules = coalesce->n_rules;
@@ -2591,8 +2620,172 @@ static int mwifiex_cfg80211_set_coalesce(struct wiphy *wiphy,
}
}
- return mwifiex_send_cmd_sync(priv, HostCmd_CMD_COALESCE_CFG,
- HostCmd_ACT_GEN_SET, 0, &coalesce_cfg);
+ return mwifiex_send_cmd(priv, HostCmd_CMD_COALESCE_CFG,
+ HostCmd_ACT_GEN_SET, 0, &coalesce_cfg, true);
+}
+
+/* cfg80211 ops handler for tdls_mgmt.
+ * Function prepares TDLS action frame packets and forwards them to FW
+ */
+static int
+mwifiex_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token,
+ u16 status_code, u32 peer_capability,
+ const u8 *extra_ies, size_t extra_ies_len)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ int ret;
+
+ if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
+ return -ENOTSUPP;
+
+ /* make sure we are in station mode and connected */
+ if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected))
+ return -ENOTSUPP;
+
+ switch (action_code) {
+ case WLAN_TDLS_SETUP_REQUEST:
+ dev_dbg(priv->adapter->dev,
+ "Send TDLS Setup Request to %pM status_code=%d\n", peer,
+ status_code);
+ ret = mwifiex_send_tdls_data_frame(priv, peer, action_code,
+ dialog_token, status_code,
+ extra_ies, extra_ies_len);
+ break;
+ case WLAN_TDLS_SETUP_RESPONSE:
+ dev_dbg(priv->adapter->dev,
+ "Send TDLS Setup Response to %pM status_code=%d\n",
+ peer, status_code);
+ ret = mwifiex_send_tdls_data_frame(priv, peer, action_code,
+ dialog_token, status_code,
+ extra_ies, extra_ies_len);
+ break;
+ case WLAN_TDLS_SETUP_CONFIRM:
+ dev_dbg(priv->adapter->dev,
+ "Send TDLS Confirm to %pM status_code=%d\n", peer,
+ status_code);
+ ret = mwifiex_send_tdls_data_frame(priv, peer, action_code,
+ dialog_token, status_code,
+ extra_ies, extra_ies_len);
+ break;
+ case WLAN_TDLS_TEARDOWN:
+ dev_dbg(priv->adapter->dev, "Send TDLS Tear down to %pM\n",
+ peer);
+ ret = mwifiex_send_tdls_data_frame(priv, peer, action_code,
+ dialog_token, status_code,
+ extra_ies, extra_ies_len);
+ break;
+ case WLAN_TDLS_DISCOVERY_REQUEST:
+ dev_dbg(priv->adapter->dev,
+ "Send TDLS Discovery Request to %pM\n", peer);
+ ret = mwifiex_send_tdls_data_frame(priv, peer, action_code,
+ dialog_token, status_code,
+ extra_ies, extra_ies_len);
+ break;
+ case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
+ dev_dbg(priv->adapter->dev,
+ "Send TDLS Discovery Response to %pM\n", peer);
+ ret = mwifiex_send_tdls_action_frame(priv, peer, action_code,
+ dialog_token, status_code,
+ extra_ies, extra_ies_len);
+ break;
+ default:
+ dev_warn(priv->adapter->dev,
+ "Unknown TDLS mgmt/action frame %pM\n", peer);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int
+mwifiex_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, enum nl80211_tdls_operation action)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+ if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
+ !(wiphy->flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))
+ return -ENOTSUPP;
+
+ /* make sure we are in station mode and connected */
+ if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected))
+ return -ENOTSUPP;
+
+ dev_dbg(priv->adapter->dev,
+ "TDLS peer=%pM, oper=%d\n", peer, action);
+
+ switch (action) {
+ case NL80211_TDLS_ENABLE_LINK:
+ action = MWIFIEX_TDLS_ENABLE_LINK;
+ break;
+ case NL80211_TDLS_DISABLE_LINK:
+ action = MWIFIEX_TDLS_DISABLE_LINK;
+ break;
+ case NL80211_TDLS_TEARDOWN:
+ /* shouldn't happen!*/
+ dev_warn(priv->adapter->dev,
+ "tdls_oper: teardown from driver not supported\n");
+ return -EINVAL;
+ case NL80211_TDLS_SETUP:
+ /* shouldn't happen!*/
+ dev_warn(priv->adapter->dev,
+ "tdls_oper: setup from driver not supported\n");
+ return -EINVAL;
+ case NL80211_TDLS_DISCOVERY_REQ:
+ /* shouldn't happen!*/
+ dev_warn(priv->adapter->dev,
+ "tdls_oper: discovery from driver not supported\n");
+ return -EINVAL;
+ default:
+ dev_err(priv->adapter->dev,
+ "tdls_oper: operation not supported\n");
+ return -ENOTSUPP;
+ }
+
+ return mwifiex_tdls_oper(priv, peer, action);
+}
+
+static int
+mwifiex_cfg80211_add_station(struct wiphy *wiphy,
+ struct net_device *dev,
+ u8 *mac, struct station_parameters *params)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+ if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
+ return -ENOTSUPP;
+
+ /* make sure we are in station mode and connected */
+ if ((priv->bss_type != MWIFIEX_BSS_TYPE_STA) || !priv->media_connected)
+ return -ENOTSUPP;
+
+ return mwifiex_tdls_oper(priv, mac, MWIFIEX_TDLS_CREATE_LINK);
+}
+
+static int
+mwifiex_cfg80211_change_station(struct wiphy *wiphy,
+ struct net_device *dev,
+ u8 *mac, struct station_parameters *params)
+{
+ int ret;
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+ /* we support change_station handler only for TDLS peers*/
+ if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
+ return -ENOTSUPP;
+
+ /* make sure we are in station mode and connected */
+ if ((priv->bss_type != MWIFIEX_BSS_TYPE_STA) || !priv->media_connected)
+ return -ENOTSUPP;
+
+ priv->sta_params = params;
+
+ ret = mwifiex_tdls_oper(priv, mac, MWIFIEX_TDLS_CONFIG_LINK);
+ priv->sta_params = NULL;
+
+ return ret;
}
/* station cfg80211 operations */
@@ -2630,6 +2823,10 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
.set_wakeup = mwifiex_cfg80211_set_wakeup,
#endif
.set_coalesce = mwifiex_cfg80211_set_coalesce,
+ .tdls_mgmt = mwifiex_cfg80211_tdls_mgmt,
+ .tdls_oper = mwifiex_cfg80211_tdls_oper,
+ .add_station = mwifiex_cfg80211_add_station,
+ .change_station = mwifiex_cfg80211_change_station,
};
#ifdef CONFIG_PM
@@ -2715,6 +2912,11 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
WIPHY_FLAG_AP_UAPSD |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+
+ if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info))
+ wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
+ WIPHY_FLAG_TDLS_EXTERNAL_SETUP;
+
wiphy->regulatory_flags |=
REGULATORY_CUSTOM_REG |
REGULATORY_STRICT_REG;
@@ -2736,7 +2938,8 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
wiphy->features |= NL80211_FEATURE_HT_IBSS |
NL80211_FEATURE_INACTIVITY_TIMER |
- NL80211_FEATURE_LOW_PRIORITY_SCAN;
+ NL80211_FEATURE_LOW_PRIORITY_SCAN |
+ NL80211_FEATURE_NEED_OBSS_SCAN;
/* Reserve space for mwifiex specific private data for BSS */
wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv);
@@ -2767,17 +2970,17 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
country_code);
}
- mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
- HostCmd_ACT_GEN_GET, FRAG_THRESH_I, &thr);
+ mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_GET, FRAG_THRESH_I, &thr, true);
wiphy->frag_threshold = thr;
- mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
- HostCmd_ACT_GEN_GET, RTS_THRESH_I, &thr);
+ mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_GET, RTS_THRESH_I, &thr, true);
wiphy->rts_threshold = thr;
- mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
- HostCmd_ACT_GEN_GET, SHORT_RETRY_LIM_I, &retry);
+ mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_GET, SHORT_RETRY_LIM_I, &retry, true);
wiphy->retry_short = (u8) retry;
- mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
- HostCmd_ACT_GEN_GET, LONG_RETRY_LIM_I, &retry);
+ mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_GET, LONG_RETRY_LIM_I, &retry, true);
wiphy->retry_long = (u8) retry;
adapter->wiphy = wiphy;
diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c
index 9eefacbc844b..0ddec3d4b059 100644
--- a/drivers/net/wireless/mwifiex/cfp.c
+++ b/drivers/net/wireless/mwifiex/cfp.c
@@ -71,6 +71,95 @@ u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x10, 0x20, 0x30,
static u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 };
+/* For every mcs_rate line, the first 8 bytes are for stream 1x1,
+ * and all 16 bytes are for stream 2x2.
+ */
+static const u16 mcs_rate[4][16] = {
+ /* LGI 40M */
+ { 0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e,
+ 0x36, 0x6c, 0xa2, 0xd8, 0x144, 0x1b0, 0x1e6, 0x21c },
+
+ /* SGI 40M */
+ { 0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c,
+ 0x3c, 0x78, 0xb4, 0xf0, 0x168, 0x1e0, 0x21c, 0x258 },
+
+ /* LGI 20M */
+ { 0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82,
+ 0x1a, 0x34, 0x4e, 0x68, 0x9c, 0xd0, 0xea, 0x104 },
+
+ /* SGI 20M */
+ { 0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90,
+ 0x1c, 0x39, 0x56, 0x73, 0xad, 0xe7, 0x104, 0x120 }
+};
+
+/* AC rates */
+static const u16 ac_mcs_rate_nss1[8][10] = {
+ /* LG 160M */
+ { 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D,
+ 0x492, 0x57C, 0x618 },
+
+ /* SG 160M */
+ { 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492,
+ 0x514, 0x618, 0x6C6 },
+
+ /* LG 80M */
+ { 0x3B, 0x75, 0xB0, 0xEA, 0x15F, 0x1D4, 0x20F,
+ 0x249, 0x2BE, 0x30C },
+
+ /* SG 80M */
+ { 0x41, 0x82, 0xC3, 0x104, 0x186, 0x208, 0x249,
+ 0x28A, 0x30C, 0x363 },
+
+ /* LG 40M */
+ { 0x1B, 0x36, 0x51, 0x6C, 0xA2, 0xD8, 0xF3,
+ 0x10E, 0x144, 0x168 },
+
+ /* SG 40M */
+ { 0x1E, 0x3C, 0x5A, 0x78, 0xB4, 0xF0, 0x10E,
+ 0x12C, 0x168, 0x190 },
+
+ /* LG 20M */
+ { 0xD, 0x1A, 0x27, 0x34, 0x4E, 0x68, 0x75, 0x82, 0x9C, 0x00 },
+
+ /* SG 20M */
+ { 0xF, 0x1D, 0x2C, 0x3A, 0x57, 0x74, 0x82, 0x91, 0xAE, 0x00 },
+};
+
+/* NSS2 note: the value in the table is 2 multiplier of the actual rate */
+static const u16 ac_mcs_rate_nss2[8][10] = {
+ /* LG 160M */
+ { 0xEA, 0x1D4, 0x2BE, 0x3A8, 0x57C, 0x750, 0x83A,
+ 0x924, 0xAF8, 0xC30 },
+
+ /* SG 160M */
+ { 0x104, 0x208, 0x30C, 0x410, 0x618, 0x820, 0x924,
+ 0xA28, 0xC30, 0xD8B },
+
+ /* LG 80M */
+ { 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D,
+ 0x492, 0x57C, 0x618 },
+
+ /* SG 80M */
+ { 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492,
+ 0x514, 0x618, 0x6C6 },
+
+ /* LG 40M */
+ { 0x36, 0x6C, 0xA2, 0xD8, 0x144, 0x1B0, 0x1E6,
+ 0x21C, 0x288, 0x2D0 },
+
+ /* SG 40M */
+ { 0x3C, 0x78, 0xB4, 0xF0, 0x168, 0x1E0, 0x21C,
+ 0x258, 0x2D0, 0x320 },
+
+ /* LG 20M */
+ { 0x1A, 0x34, 0x4A, 0x68, 0x9C, 0xD0, 0xEA, 0x104,
+ 0x138, 0x00 },
+
+ /* SG 20M */
+ { 0x1D, 0x3A, 0x57, 0x74, 0xAE, 0xE6, 0x104, 0x121,
+ 0x15B, 0x00 },
+};
+
struct region_code_mapping {
u8 code;
u8 region[IEEE80211_COUNTRY_STRING_LEN];
@@ -109,95 +198,6 @@ u8 *mwifiex_11d_code_2_region(u8 code)
u32 mwifiex_index_to_acs_data_rate(struct mwifiex_private *priv,
u8 index, u8 ht_info)
{
- /*
- * For every mcs_rate line, the first 8 bytes are for stream 1x1,
- * and all 16 bytes are for stream 2x2.
- */
- u16 mcs_rate[4][16] = {
- /* LGI 40M */
- { 0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e,
- 0x36, 0x6c, 0xa2, 0xd8, 0x144, 0x1b0, 0x1e6, 0x21c },
-
- /* SGI 40M */
- { 0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c,
- 0x3c, 0x78, 0xb4, 0xf0, 0x168, 0x1e0, 0x21c, 0x258 },
-
- /* LGI 20M */
- { 0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82,
- 0x1a, 0x34, 0x4e, 0x68, 0x9c, 0xd0, 0xea, 0x104 },
-
- /* SGI 20M */
- { 0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90,
- 0x1c, 0x39, 0x56, 0x73, 0xad, 0xe7, 0x104, 0x120 }
- };
- /* AC rates */
- u16 ac_mcs_rate_nss1[8][10] = {
- /* LG 160M */
- { 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D,
- 0x492, 0x57C, 0x618 },
-
- /* SG 160M */
- { 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492,
- 0x514, 0x618, 0x6C6 },
-
- /* LG 80M */
- { 0x3B, 0x75, 0xB0, 0xEA, 0x15F, 0x1D4, 0x20F,
- 0x249, 0x2BE, 0x30C },
-
- /* SG 80M */
- { 0x41, 0x82, 0xC3, 0x104, 0x186, 0x208, 0x249,
- 0x28A, 0x30C, 0x363 },
-
- /* LG 40M */
- { 0x1B, 0x36, 0x51, 0x6C, 0xA2, 0xD8, 0xF3,
- 0x10E, 0x144, 0x168 },
-
- /* SG 40M */
- { 0x1E, 0x3C, 0x5A, 0x78, 0xB4, 0xF0, 0x10E,
- 0x12C, 0x168, 0x190 },
-
- /* LG 20M */
- { 0xD, 0x1A, 0x27, 0x34, 0x4E, 0x68, 0x75, 0x82, 0x9C, 0x00 },
-
- /* SG 20M */
- { 0xF, 0x1D, 0x2C, 0x3A, 0x57, 0x74, 0x82, 0x91, 0xAE, 0x00 },
- };
- /* NSS2 note: the value in the table is 2 multiplier of the actual
- * rate
- */
- u16 ac_mcs_rate_nss2[8][10] = {
- /* LG 160M */
- { 0xEA, 0x1D4, 0x2BE, 0x3A8, 0x57C, 0x750, 0x83A,
- 0x924, 0xAF8, 0xC30 },
-
- /* SG 160M */
- { 0x104, 0x208, 0x30C, 0x410, 0x618, 0x820, 0x924,
- 0xA28, 0xC30, 0xD8B },
-
- /* LG 80M */
- { 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D,
- 0x492, 0x57C, 0x618 },
-
- /* SG 80M */
- { 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492,
- 0x514, 0x618, 0x6C6 },
-
- /* LG 40M */
- { 0x36, 0x6C, 0xA2, 0xD8, 0x144, 0x1B0, 0x1E6,
- 0x21C, 0x288, 0x2D0 },
-
- /* SG 40M */
- { 0x3C, 0x78, 0xB4, 0xF0, 0x168, 0x1E0, 0x21C,
- 0x258, 0x2D0, 0x320 },
-
- /* LG 20M */
- { 0x1A, 0x34, 0x4A, 0x68, 0x9C, 0xD0, 0xEA, 0x104,
- 0x138, 0x00 },
-
- /* SG 20M */
- { 0x1D, 0x3A, 0x57, 0x74, 0xAE, 0xE6, 0x104, 0x121,
- 0x15B, 0x00 },
- };
u32 rate = 0;
u8 mcs_index = 0;
u8 bw = 0;
@@ -252,28 +252,8 @@ u32 mwifiex_index_to_acs_data_rate(struct mwifiex_private *priv,
u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv,
u8 index, u8 ht_info)
{
- /* For every mcs_rate line, the first 8 bytes are for stream 1x1,
- * and all 16 bytes are for stream 2x2.
- */
- u16 mcs_rate[4][16] = {
- /* LGI 40M */
- { 0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e,
- 0x36, 0x6c, 0xa2, 0xd8, 0x144, 0x1b0, 0x1e6, 0x21c },
-
- /* SGI 40M */
- { 0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c,
- 0x3c, 0x78, 0xb4, 0xf0, 0x168, 0x1e0, 0x21c, 0x258 },
-
- /* LGI 20M */
- { 0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82,
- 0x1a, 0x34, 0x4e, 0x68, 0x9c, 0xd0, 0xea, 0x104 },
-
- /* SGI 20M */
- { 0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90,
- 0x1c, 0x39, 0x56, 0x73, 0xad, 0xe7, 0x104, 0x120 }
- };
u32 mcs_num_supp =
- (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) ? 16 : 8;
+ (priv->adapter->user_dev_mcs_support == HT_STREAM_2X2) ? 16 : 8;
u32 rate;
if (priv->adapter->is_hw_11ac_capable)
@@ -458,7 +438,6 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
break;
case BAND_G:
case BAND_G | BAND_GN:
- case BAND_G | BAND_GN | BAND_GAC:
dev_dbg(adapter->dev, "info: infra band=%d "
"supported_rates_g\n", adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_g,
@@ -469,10 +448,7 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
case BAND_A | BAND_B:
case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN:
case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN | BAND_AAC:
- case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN |
- BAND_AAC | BAND_GAC:
case BAND_B | BAND_G | BAND_GN:
- case BAND_B | BAND_G | BAND_GN | BAND_GAC:
dev_dbg(adapter->dev, "info: infra band=%d "
"supported_rates_bg\n", adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_bg,
@@ -496,7 +472,6 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
sizeof(supported_rates_a));
break;
case BAND_GN:
- case BAND_GN | BAND_GAC:
dev_dbg(adapter->dev, "info: infra band=%d "
"supported_rates_n\n", adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_n,
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index 1ddc8b2e3722..1062c918a7bf 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -37,13 +37,12 @@
static void
mwifiex_init_cmd_node(struct mwifiex_private *priv,
struct cmd_ctrl_node *cmd_node,
- u32 cmd_oid, void *data_buf)
+ u32 cmd_oid, void *data_buf, bool sync)
{
cmd_node->priv = priv;
cmd_node->cmd_oid = cmd_oid;
- if (priv->adapter->cmd_wait_q_required) {
- cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required;
- priv->adapter->cmd_wait_q_required = false;
+ if (sync) {
+ cmd_node->wait_q_enabled = true;
cmd_node->cmd_wait_q_woken = false;
cmd_node->condition = &cmd_node->cmd_wait_q_woken;
}
@@ -166,8 +165,10 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
dev_err(adapter->dev,
"DNLD_CMD: FW in reset state, ignore cmd %#x\n",
cmd_code);
- mwifiex_complete_cmd(adapter, cmd_node);
+ if (cmd_node->wait_q_enabled)
+ mwifiex_complete_cmd(adapter, cmd_node);
mwifiex_recycle_cmd_node(adapter, cmd_node);
+ queue_work(adapter->workqueue, &adapter->main_work);
return -1;
}
@@ -276,11 +277,11 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+ adapter->seq_num++;
sleep_cfm_buf->seq_num =
cpu_to_le16((HostCmd_SET_SEQ_NO_BSS_INFO
(adapter->seq_num, priv->bss_num,
priv->bss_type)));
- adapter->seq_num++;
if (adapter->iface_type == MWIFIEX_USB) {
sleep_cfm_tmp =
@@ -480,28 +481,7 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
}
/*
- * This function is used to send synchronous command to the firmware.
- *
- * it allocates a wait queue for the command and wait for the command
- * response.
- */
-int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no,
- u16 cmd_action, u32 cmd_oid, void *data_buf)
-{
- int ret = 0;
- struct mwifiex_adapter *adapter = priv->adapter;
-
- adapter->cmd_wait_q_required = true;
-
- ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid,
- data_buf);
-
- return ret;
-}
-
-
-/*
- * This function prepares a command and asynchronously send it to the firmware.
+ * This function prepares a command and send it to the firmware.
*
* Preparation includes -
* - Sanity tests to make sure the card is still present or the FW
@@ -511,8 +491,8 @@ int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no,
* - Fill up the non-default parameters and buffer pointers
* - Add the command to pending queue
*/
-int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
- u16 cmd_action, u32 cmd_oid, void *data_buf)
+int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no,
+ u16 cmd_action, u32 cmd_oid, void *data_buf, bool sync)
{
int ret;
struct mwifiex_adapter *adapter = priv->adapter;
@@ -529,11 +509,21 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
return -1;
}
+ if (adapter->hs_enabling && cmd_no != HostCmd_CMD_802_11_HS_CFG_ENH) {
+ dev_err(adapter->dev, "PREP_CMD: host entering sleep state\n");
+ return -1;
+ }
+
if (adapter->surprise_removed) {
dev_err(adapter->dev, "PREP_CMD: card is removed\n");
return -1;
}
+ if (adapter->is_cmd_timedout) {
+ dev_err(adapter->dev, "PREP_CMD: FW is in bad state\n");
+ return -1;
+ }
+
if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET) {
if (cmd_no != HostCmd_CMD_FUNC_INIT) {
dev_err(adapter->dev, "PREP_CMD: FW in reset state\n");
@@ -550,7 +540,7 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
}
/* Initialize the command node */
- mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, data_buf);
+ mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, data_buf, sync);
if (!cmd_node->cmd_skb) {
dev_err(adapter->dev, "PREP_CMD: no free cmd buf\n");
@@ -595,7 +585,8 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
}
/* Send command */
- if (cmd_no == HostCmd_CMD_802_11_SCAN) {
+ if (cmd_no == HostCmd_CMD_802_11_SCAN ||
+ cmd_no == HostCmd_CMD_802_11_SCAN_EXT) {
mwifiex_queue_scan_cmd(priv, cmd_node);
} else {
mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
@@ -785,7 +776,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
unsigned long flags;
/* Now we got response from FW, cancel the command timer */
- del_timer(&adapter->cmd_timer);
+ del_timer_sync(&adapter->cmd_timer);
if (!adapter->curr_cmd || !adapter->curr_cmd->resp_skb) {
resp = (struct host_cmd_ds_command *) adapter->upld_buf;
@@ -794,7 +785,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
return -1;
}
- adapter->num_cmd_timeout = 0;
+ adapter->is_cmd_timedout = 0;
resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data;
if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) {
@@ -905,8 +896,7 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
struct cmd_ctrl_node *cmd_node;
struct timeval tstamp;
- adapter->num_cmd_timeout++;
- adapter->dbg.num_cmd_timeout++;
+ adapter->is_cmd_timedout = 1;
if (!adapter->curr_cmd) {
dev_dbg(adapter->dev, "cmd: empty curr_cmd\n");
return;
@@ -929,8 +919,8 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
dev_err(adapter->dev, "num_cmd_h2c_failure = %d\n",
adapter->dbg.num_cmd_host_to_card_failure);
- dev_err(adapter->dev, "num_cmd_timeout = %d\n",
- adapter->dbg.num_cmd_timeout);
+ dev_err(adapter->dev, "is_cmd_timedout = %d\n",
+ adapter->is_cmd_timedout);
dev_err(adapter->dev, "num_tx_timeout = %d\n",
adapter->dbg.num_tx_timeout);
@@ -987,13 +977,14 @@ void
mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
{
struct cmd_ctrl_node *cmd_node = NULL, *tmp_node;
- unsigned long flags;
+ unsigned long flags, cmd_flags;
+ struct mwifiex_private *priv;
+ int i;
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
/* Cancel current cmd */
if ((adapter->curr_cmd) && (adapter->curr_cmd->wait_q_enabled)) {
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->curr_cmd->wait_q_enabled = false;
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
adapter->cmd_wait_q.status = -1;
mwifiex_complete_cmd(adapter, adapter->curr_cmd);
}
@@ -1013,6 +1004,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
}
spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
/* Cancel all pending scan command */
spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
@@ -1027,9 +1019,21 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
}
spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
- adapter->scan_processing = false;
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+ if (adapter->scan_processing) {
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
+ adapter->scan_processing = false;
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+ for (i = 0; i < adapter->priv_num; i++) {
+ priv = adapter->priv[i];
+ if (!priv)
+ continue;
+ if (priv->scan_request) {
+ dev_dbg(adapter->dev, "info: aborting scan\n");
+ cfg80211_scan_done(priv->scan_request, 1);
+ priv->scan_request = NULL;
+ }
+ }
+ }
}
/*
@@ -1048,7 +1052,8 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL;
unsigned long cmd_flags;
unsigned long scan_pending_q_flags;
- bool cancel_scan_cmd = false;
+ struct mwifiex_private *priv;
+ int i;
if ((adapter->curr_cmd) &&
(adapter->curr_cmd->wait_q_enabled)) {
@@ -1074,15 +1079,24 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
spin_lock_irqsave(&adapter->scan_pending_q_lock,
scan_pending_q_flags);
- cancel_scan_cmd = true;
}
spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
scan_pending_q_flags);
- if (cancel_scan_cmd) {
+ if (adapter->scan_processing) {
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
adapter->scan_processing = false;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+ for (i = 0; i < adapter->priv_num; i++) {
+ priv = adapter->priv[i];
+ if (!priv)
+ continue;
+ if (priv->scan_request) {
+ dev_dbg(adapter->dev, "info: aborting scan\n");
+ cfg80211_scan_done(priv->scan_request, 1);
+ priv->scan_request = NULL;
+ }
+ }
}
adapter->cmd_wait_q.status = -1;
}
@@ -1454,7 +1468,10 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
{
struct host_cmd_ds_get_hw_spec *hw_spec = &resp->params.hw_spec;
struct mwifiex_adapter *adapter = priv->adapter;
- int i;
+ struct mwifiex_ie_types_header *tlv;
+ struct hw_spec_fw_api_rev *api_rev;
+ u16 resp_size, api_id;
+ int i, left_len, parsed_len = 0;
adapter->fw_cap_info = le32_to_cpu(hw_spec->fw_cap_info);
@@ -1490,6 +1507,7 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
}
adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number);
+ adapter->fw_api_ver = (adapter->fw_release_number >> 16) & 0xff;
adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna);
if (le32_to_cpu(hw_spec->dot_11ac_dev_cap)) {
@@ -1498,8 +1516,10 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
/* Copy 11AC cap */
adapter->hw_dot_11ac_dev_cap =
le32_to_cpu(hw_spec->dot_11ac_dev_cap);
- adapter->usr_dot_11ac_dev_cap_bg = adapter->hw_dot_11ac_dev_cap;
- adapter->usr_dot_11ac_dev_cap_a = adapter->hw_dot_11ac_dev_cap;
+ adapter->usr_dot_11ac_dev_cap_bg = adapter->hw_dot_11ac_dev_cap
+ & ~MWIFIEX_DEF_11AC_CAP_BF_RESET_MASK;
+ adapter->usr_dot_11ac_dev_cap_a = adapter->hw_dot_11ac_dev_cap
+ & ~MWIFIEX_DEF_11AC_CAP_BF_RESET_MASK;
/* Copy 11AC mcs */
adapter->hw_dot_11ac_mcs_support =
@@ -1510,6 +1530,46 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
adapter->is_hw_11ac_capable = false;
}
+ resp_size = le16_to_cpu(resp->size) - S_DS_GEN;
+ if (resp_size > sizeof(struct host_cmd_ds_get_hw_spec)) {
+ /* we have variable HW SPEC information */
+ left_len = resp_size - sizeof(struct host_cmd_ds_get_hw_spec);
+ while (left_len > sizeof(struct mwifiex_ie_types_header)) {
+ tlv = (void *)&hw_spec->tlvs + parsed_len;
+ switch (le16_to_cpu(tlv->type)) {
+ case TLV_TYPE_FW_API_REV:
+ api_rev = (struct hw_spec_fw_api_rev *)tlv;
+ api_id = le16_to_cpu(api_rev->api_id);
+ switch (api_id) {
+ case KEY_API_VER_ID:
+ adapter->fw_key_api_major_ver =
+ api_rev->major_ver;
+ adapter->fw_key_api_minor_ver =
+ api_rev->minor_ver;
+ dev_dbg(adapter->dev,
+ "fw_key_api v%d.%d\n",
+ adapter->fw_key_api_major_ver,
+ adapter->fw_key_api_minor_ver);
+ break;
+ default:
+ dev_warn(adapter->dev,
+ "Unknown FW api_id: %d\n",
+ api_id);
+ break;
+ }
+ break;
+ default:
+ dev_warn(adapter->dev,
+ "Unknown GET_HW_SPEC TLV type: %#x\n",
+ le16_to_cpu(tlv->type));
+ break;
+ }
+ parsed_len += le16_to_cpu(tlv->len) +
+ sizeof(struct mwifiex_ie_types_header);
+ left_len -= parsed_len;
+ }
+ }
+
dev_dbg(adapter->dev, "info: GET_HW_SPEC: fw_release_number- %#x\n",
adapter->fw_release_number);
dev_dbg(adapter->dev, "info: GET_HW_SPEC: permanent addr: %pM\n",
@@ -1538,6 +1598,7 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
adapter->hw_dot_11n_dev_cap = le32_to_cpu(hw_spec->dot_11n_dev_cap);
adapter->hw_dev_mcs_support = hw_spec->dev_mcs_support;
+ adapter->user_dev_mcs_support = adapter->hw_dev_mcs_support;
if (adapter->if_ops.update_mp_end_port)
adapter->if_ops.update_mp_end_port(adapter,
diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c
index a5f9875cfd6e..b8a49aad12fd 100644
--- a/drivers/net/wireless/mwifiex/debugfs.c
+++ b/drivers/net/wireless/mwifiex/debugfs.c
@@ -85,8 +85,8 @@ static struct mwifiex_debug_data items[] = {
item_addr(hs_activated), 1},
{"num_tx_timeout", item_size(num_tx_timeout),
item_addr(num_tx_timeout), 1},
- {"num_cmd_timeout", item_size(num_cmd_timeout),
- item_addr(num_cmd_timeout), 1},
+ {"is_cmd_timedout", item_size(is_cmd_timedout),
+ item_addr(is_cmd_timedout), 1},
{"timeout_cmd_id", item_size(timeout_cmd_id),
item_addr(timeout_cmd_id), 1},
{"timeout_cmd_act", item_size(timeout_cmd_act),
@@ -493,7 +493,7 @@ mwifiex_regrdwr_write(struct file *file,
{
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *) addr;
- size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1));
+ size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
int ret;
u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX;
@@ -594,7 +594,7 @@ mwifiex_rdeeprom_write(struct file *file,
{
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *) addr;
- size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1));
+ size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
int ret = 0;
int offset = -1, bytes = -1;
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
index 3a21bd03d6db..e7b3e16e5d34 100644
--- a/drivers/net/wireless/mwifiex/decl.h
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -75,10 +75,16 @@
#define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0)
#define MWIFIEX_BUF_FLAG_BRIDGED_PKT BIT(1)
+#define MWIFIEX_BUF_FLAG_TDLS_PKT BIT(2)
#define MWIFIEX_BRIDGED_PKTS_THR_HIGH 1024
#define MWIFIEX_BRIDGED_PKTS_THR_LOW 128
+#define MWIFIEX_TDLS_DISABLE_LINK 0x00
+#define MWIFIEX_TDLS_ENABLE_LINK 0x01
+#define MWIFIEX_TDLS_CREATE_LINK 0x02
+#define MWIFIEX_TDLS_CONFIG_LINK 0x03
+
enum mwifiex_bss_type {
MWIFIEX_BSS_TYPE_STA = 0,
MWIFIEX_BSS_TYPE_UAP = 1,
@@ -92,6 +98,23 @@ enum mwifiex_bss_role {
MWIFIEX_BSS_ROLE_ANY = 0xff,
};
+enum mwifiex_tdls_status {
+ TDLS_NOT_SETUP = 0,
+ TDLS_SETUP_INPROGRESS,
+ TDLS_SETUP_COMPLETE,
+ TDLS_SETUP_FAILURE,
+ TDLS_LINK_TEARDOWN,
+};
+
+enum mwifiex_tdls_error_code {
+ TDLS_ERR_NO_ERROR = 0,
+ TDLS_ERR_INTERNAL_ERROR,
+ TDLS_ERR_MAX_LINKS_EST,
+ TDLS_ERR_LINK_EXISTS,
+ TDLS_ERR_LINK_NONEXISTENT,
+ TDLS_ERR_PEER_STA_UNREACHABLE = 25,
+};
+
#define BSS_ROLE_BIT_MASK BIT(0)
#define GET_BSS_ROLE(priv) ((priv)->bss_role & BSS_ROLE_BIT_MASK)
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 5fa932d5f905..b485dc1ae5eb 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -50,21 +50,23 @@ struct tx_packet_hdr {
#define HOSTCMD_SUPPORTED_RATES 14
#define N_SUPPORTED_RATES 3
#define ALL_802_11_BANDS (BAND_A | BAND_B | BAND_G | BAND_GN | \
- BAND_AN | BAND_GAC | BAND_AAC)
+ BAND_AN | BAND_AAC)
#define FW_MULTI_BANDS_SUPPORT (BIT(8) | BIT(9) | BIT(10) | BIT(11) | \
- BIT(12) | BIT(13))
+ BIT(13))
#define IS_SUPPORT_MULTI_BANDS(adapter) \
(adapter->fw_cap_info & FW_MULTI_BANDS_SUPPORT)
-/* shift bit 12 and bit 13 in fw_cap_info from the firmware to bit 13 and 14
- * for 11ac so that bit 11 is for GN, bit 12 for AN, bit 13 for GAC, and bit
- * bit 14 for AAC, in order to be compatible with the band capability
- * defined in the driver after right shift of 8 bits.
+/* bit 13: 11ac BAND_AAC
+ * bit 12: reserved for lab testing, will be reused for BAND_AN
+ * bit 11: 11n BAND_GN
+ * bit 10: 11a BAND_A
+ * bit 9: 11g BAND_G
+ * bit 8: 11b BAND_B
+ * Map these bits to band capability by right shifting 8 bits.
*/
#define GET_FW_DEFAULT_BANDS(adapter) \
- (((((adapter->fw_cap_info & 0x3000) << 1) | \
- (adapter->fw_cap_info & ~0xF000)) >> 8) & \
+ (((adapter->fw_cap_info & 0x2f00) >> 8) & \
ALL_802_11_BANDS)
#define HostCmd_WEP_KEY_INDEX_MASK 0x3fff
@@ -77,12 +79,21 @@ enum KEY_TYPE_ID {
KEY_TYPE_ID_WAPI,
KEY_TYPE_ID_AES_CMAC,
};
+
+#define WPA_PN_SIZE 8
+#define KEY_PARAMS_FIXED_LEN 10
+#define KEY_INDEX_MASK 0xf
+#define FW_KEY_API_VER_MAJOR_V2 2
+
#define KEY_MCAST BIT(0)
#define KEY_UNICAST BIT(1)
#define KEY_ENABLED BIT(2)
+#define KEY_DEFAULT BIT(3)
+#define KEY_TX_KEY BIT(4)
+#define KEY_RX_KEY BIT(5)
#define KEY_IGTK BIT(10)
-#define WAPI_KEY_LEN 50
+#define WAPI_KEY_LEN (WLAN_KEY_LEN_SMS4 + PN_LEN + 2)
#define MAX_POLL_TRIES 100
#define MAX_FIRMWARE_POLL_TRIES 100
@@ -130,6 +141,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22)
#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31)
#define TLV_TYPE_STA_MAC_ADDR (PROPRIETARY_TLV_BASE_ID + 32)
+#define TLV_TYPE_BSSID (PROPRIETARY_TLV_BASE_ID + 35)
#define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42)
#define TLV_TYPE_UAP_BEACON_PERIOD (PROPRIETARY_TLV_BASE_ID + 44)
#define TLV_TYPE_UAP_DTIM_PERIOD (PROPRIETARY_TLV_BASE_ID + 45)
@@ -144,6 +156,8 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_RATE_DROP_CONTROL (PROPRIETARY_TLV_BASE_ID + 82)
#define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 83)
#define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84)
+#define TLV_TYPE_BSS_SCAN_RSP (PROPRIETARY_TLV_BASE_ID + 86)
+#define TLV_TYPE_BSS_SCAN_INFO (PROPRIETARY_TLV_BASE_ID + 87)
#define TLV_TYPE_UAP_RETRY_LIMIT (PROPRIETARY_TLV_BASE_ID + 93)
#define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94)
#define TLV_TYPE_UAP_MGMT_FRAME (PROPRIETARY_TLV_BASE_ID + 104)
@@ -154,6 +168,8 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_PWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 145)
#define TLV_TYPE_GWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 146)
#define TLV_TYPE_COALESCE_RULE (PROPRIETARY_TLV_BASE_ID + 154)
+#define TLV_TYPE_KEY_PARAM_V2 (PROPRIETARY_TLV_BASE_ID + 156)
+#define TLV_TYPE_FW_API_REV (PROPRIETARY_TLV_BASE_ID + 199)
#define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048
@@ -176,13 +192,21 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define MWIFIEX_TX_DATA_BUF_SIZE_8K 8192
#define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11))
+#define ISSUPP_TDLS_ENABLED(FwCapInfo) (FwCapInfo & BIT(14))
#define MWIFIEX_DEF_HT_CAP (IEEE80211_HT_CAP_DSSSCCK40 | \
(1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) | \
IEEE80211_HT_CAP_SM_PS)
+#define MWIFIEX_DEF_11N_TX_BF_CAP 0x09E1E008
+
#define MWIFIEX_DEF_AMPDU IEEE80211_HT_AMPDU_PARM_FACTOR
+#define GET_RXSTBC(x) (x & IEEE80211_HT_CAP_RX_STBC)
+#define MWIFIEX_RX_STBC1 0x0100
+#define MWIFIEX_RX_STBC12 0x0200
+#define MWIFIEX_RX_STBC123 0x0300
+
/* dev_cap bitmap
* BIT
* 0-16 reserved
@@ -204,6 +228,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & BIT(29))
#define ISENABLED_40MHZ_INTOLERANT(Dot11nDevCap) (Dot11nDevCap & BIT(8))
#define ISSUPP_RXLDPC(Dot11nDevCap) (Dot11nDevCap & BIT(22))
+#define ISSUPP_BEAMFORMING(Dot11nDevCap) (Dot11nDevCap & BIT(30))
/* httxcfg bitmap
* 0 reserved
@@ -216,8 +241,21 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
*/
#define MWIFIEX_FW_DEF_HTTXCFG (BIT(1) | BIT(4) | BIT(5) | BIT(6))
+/* 11AC Tx and Rx MCS map for 1x1 mode:
+ * IEEE80211_VHT_MCS_SUPPORT_0_9 for stream 1
+ * IEEE80211_VHT_MCS_NOT_SUPPORTED for remaining 7 streams
+ */
+#define MWIFIEX_11AC_MCS_MAP_1X1 0xfffefffe
+
+/* 11AC Tx and Rx MCS map for 2x2 mode:
+ * IEEE80211_VHT_MCS_SUPPORT_0_9 for stream 1 and 2
+ * IEEE80211_VHT_MCS_NOT_SUPPORTED for remaining 6 streams
+ */
+#define MWIFIEX_11AC_MCS_MAP_2X2 0xfffafffa
+
#define GET_RXMCSSUPP(DevMCSSupported) (DevMCSSupported & 0x0f)
#define SETHT_MCS32(x) (x[4] |= 1)
+#define HT_STREAM_1X1 0x11
#define HT_STREAM_2X2 0x22
#define SET_SECONDARYCHAN(RadioType, SECCHAN) (RadioType |= (SECCHAN << 4))
@@ -226,17 +264,24 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
/* HW_SPEC fw_cap_info */
-#define ISSUPP_11ACENABLED(fw_cap_info) (fw_cap_info & (BIT(12)|BIT(13)))
+#define ISSUPP_11ACENABLED(fw_cap_info) (fw_cap_info & BIT(13))
#define GET_VHTCAP_CHWDSET(vht_cap_info) ((vht_cap_info >> 2) & 0x3)
#define GET_VHTNSSMCS(mcs_mapset, nss) ((mcs_mapset >> (2 * (nss - 1))) & 0x3)
#define SET_VHTNSSMCS(mcs_mapset, nss, value) (mcs_mapset |= (value & 0x3) << \
(2 * (nss - 1)))
-#define NO_NSS_SUPPORT 0x3
-
#define GET_DEVTXMCSMAP(dev_mcs_map) (dev_mcs_map >> 16)
#define GET_DEVRXMCSMAP(dev_mcs_map) (dev_mcs_map & 0xFFFF)
+/* Clear SU Beanformer, MU beanformer, MU beanformee and
+ * sounding dimensions bits
+ */
+#define MWIFIEX_DEF_11AC_CAP_BF_RESET_MASK \
+ (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | \
+ IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE | \
+ IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | \
+ IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK)
+
#define MOD_CLASS_HR_DSSS 0x03
#define MOD_CLASS_OFDM 0x07
#define MOD_CLASS_HT 0x08
@@ -295,10 +340,12 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed
#define HostCmd_CMD_SET_BSS_MODE 0x00f7
#define HostCmd_CMD_PCIE_DESC_DETAILS 0x00fa
+#define HostCmd_CMD_802_11_SCAN_EXT 0x0107
#define HostCmd_CMD_COALESCE_CFG 0x010a
#define HostCmd_CMD_MGMT_FRAME_REG 0x010c
#define HostCmd_CMD_REMAIN_ON_CHAN 0x010d
#define HostCmd_CMD_11AC_CFG 0x0112
+#define HostCmd_CMD_TDLS_OPER 0x0122
#define PROTOCOL_NO_SECURITY 0x01
#define PROTOCOL_STATIC_WEP 0x02
@@ -440,6 +487,7 @@ enum P2P_MODES {
#define EVENT_UAP_MIC_COUNTERMEASURES 0x0000004c
#define EVENT_HOSTWAKE_STAIE 0x0000004d
#define EVENT_CHANNEL_SWITCH_ANN 0x00000050
+#define EVENT_EXT_SCAN_REPORT 0x00000058
#define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f
#define EVENT_ID_MASK 0xffff
@@ -468,6 +516,12 @@ enum P2P_MODES {
#define MWIFIEX_CRITERIA_UNICAST BIT(1)
#define MWIFIEX_CRITERIA_MULTICAST BIT(3)
+#define ACT_TDLS_DELETE 0x00
+#define ACT_TDLS_CREATE 0x01
+#define ACT_TDLS_CONFIG 0x02
+
+#define MWIFIEX_FW_V15 15
+
struct mwifiex_ie_types_header {
__le16 type;
__le16 len;
@@ -480,6 +534,7 @@ struct mwifiex_ie_types_data {
#define MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET 0x01
#define MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET 0x08
+#define MWIFIEX_TXPD_FLAGS_TDLS_PACKET 0x10
struct txpd {
u8 bss_type;
@@ -676,6 +731,56 @@ struct mwifiex_cmac_param {
u8 key[WLAN_KEY_LEN_AES_CMAC];
} __packed;
+struct mwifiex_wep_param {
+ __le16 key_len;
+ u8 key[WLAN_KEY_LEN_WEP104];
+} __packed;
+
+struct mwifiex_tkip_param {
+ u8 pn[WPA_PN_SIZE];
+ __le16 key_len;
+ u8 key[WLAN_KEY_LEN_TKIP];
+} __packed;
+
+struct mwifiex_aes_param {
+ u8 pn[WPA_PN_SIZE];
+ __le16 key_len;
+ u8 key[WLAN_KEY_LEN_CCMP];
+} __packed;
+
+struct mwifiex_wapi_param {
+ u8 pn[PN_LEN];
+ __le16 key_len;
+ u8 key[WLAN_KEY_LEN_SMS4];
+} __packed;
+
+struct mwifiex_cmac_aes_param {
+ u8 ipn[IGTK_PN_LEN];
+ __le16 key_len;
+ u8 key[WLAN_KEY_LEN_AES_CMAC];
+} __packed;
+
+struct mwifiex_ie_type_key_param_set_v2 {
+ __le16 type;
+ __le16 len;
+ u8 mac_addr[ETH_ALEN];
+ u8 key_idx;
+ u8 key_type;
+ __le16 key_info;
+ union {
+ struct mwifiex_wep_param wep;
+ struct mwifiex_tkip_param tkip;
+ struct mwifiex_aes_param aes;
+ struct mwifiex_wapi_param wapi;
+ struct mwifiex_cmac_aes_param cmac_aes;
+ } key_params;
+} __packed;
+
+struct host_cmd_ds_802_11_key_material_v2 {
+ __le16 action;
+ struct mwifiex_ie_type_key_param_set_v2 key_param_set;
+} __packed;
+
struct host_cmd_ds_802_11_key_material {
__le16 action;
struct mwifiex_ie_type_key_param_set key_param_set;
@@ -727,6 +832,17 @@ struct host_cmd_ds_802_11_ps_mode_enh {
} params;
} __packed;
+enum FW_API_VER_ID {
+ KEY_API_VER_ID = 1,
+};
+
+struct hw_spec_fw_api_rev {
+ struct mwifiex_ie_types_header header;
+ __le16 api_id;
+ u8 major_ver;
+ u8 minor_ver;
+} __packed;
+
struct host_cmd_ds_get_hw_spec {
__le16 hw_if_version;
__le16 version;
@@ -748,6 +864,7 @@ struct host_cmd_ds_get_hw_spec {
__le32 reserved_6;
__le32 dot_11ac_dev_cap;
__le32 dot_11ac_mcs_support;
+ u8 tlvs[0];
} __packed;
struct host_cmd_ds_802_11_rssi_info {
@@ -993,6 +1110,7 @@ struct mwifiex_rate_scope {
__le16 hr_dsss_rate_bitmap;
__le16 ofdm_rate_bitmap;
__le16 ht_mcs_rate_bitmap[8];
+ __le16 vht_mcs_rate_bitmap[8];
} __packed;
struct mwifiex_rate_drop_pattern {
@@ -1047,14 +1165,28 @@ struct host_cmd_ds_rf_ant_siso {
__le16 ant_mode;
};
-struct mwifiex_bcn_param {
- u8 bssid[ETH_ALEN];
- u8 rssi;
+struct host_cmd_ds_tdls_oper {
+ __le16 tdls_action;
+ __le16 reason;
+ u8 peer_mac[ETH_ALEN];
+} __packed;
+
+struct mwifiex_fixed_bcn_param {
__le64 timestamp;
__le16 beacon_period;
__le16 cap_info_bitmap;
} __packed;
+struct mwifiex_event_scan_result {
+ __le16 event_id;
+ u8 bss_index;
+ u8 bss_type;
+ u8 more_event;
+ u8 reserved[3];
+ __le16 buf_size;
+ u8 num_of_set;
+} __packed;
+
#define MWIFIEX_USER_SCAN_CHAN_MAX 50
#define MWIFIEX_MAX_SSID_LIST_LENGTH 10
@@ -1124,6 +1256,28 @@ struct host_cmd_ds_802_11_scan_rsp {
u8 bss_desc_and_tlv_buffer[1];
} __packed;
+struct host_cmd_ds_802_11_scan_ext {
+ u32 reserved;
+ u8 tlv_buffer[1];
+} __packed;
+
+struct mwifiex_ie_types_bss_scan_rsp {
+ struct mwifiex_ie_types_header header;
+ u8 bssid[ETH_ALEN];
+ u8 frame_body[1];
+} __packed;
+
+struct mwifiex_ie_types_bss_scan_info {
+ struct mwifiex_ie_types_header header;
+ __le16 rssi;
+ __le16 anpi;
+ u8 cca_busy_fraction;
+ u8 radio_type;
+ u8 channel;
+ u8 reserved;
+ __le64 tsf;
+} __packed;
+
struct host_cmd_ds_802_11_bg_scan_query {
u8 flush;
} __packed;
@@ -1296,6 +1450,11 @@ struct mwifiex_ie_types_vhtcap {
struct ieee80211_vht_cap vht_cap;
} __packed;
+struct mwifiex_ie_types_aid {
+ struct mwifiex_ie_types_header header;
+ __le16 aid;
+} __packed;
+
struct mwifiex_ie_types_oper_mode_ntf {
struct mwifiex_ie_types_header header;
u8 oper_mode;
@@ -1331,6 +1490,11 @@ struct mwifiex_ie_types_extcap {
u8 ext_capab[0];
} __packed;
+struct mwifiex_ie_types_qos_info {
+ struct mwifiex_ie_types_header header;
+ u8 qos_info;
+} __packed;
+
struct host_cmd_ds_mac_reg_access {
__le16 action;
__le16 offset;
@@ -1441,6 +1605,11 @@ struct host_cmd_tlv_rates {
u8 rates[0];
} __packed;
+struct mwifiex_ie_types_bssid_list {
+ struct mwifiex_ie_types_header header;
+ u8 bssid[ETH_ALEN];
+} __packed;
+
struct host_cmd_tlv_bcast_ssid {
struct mwifiex_ie_types_header header;
u8 bcast_ctl;
@@ -1634,6 +1803,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_802_11_ps_mode_enh psmode_enh;
struct host_cmd_ds_802_11_hs_cfg_enh opt_hs_cfg;
struct host_cmd_ds_802_11_scan scan;
+ struct host_cmd_ds_802_11_scan_ext ext_scan;
struct host_cmd_ds_802_11_scan_rsp scan_resp;
struct host_cmd_ds_802_11_bg_scan_query bg_scan_query;
struct host_cmd_ds_802_11_bg_scan_query_rsp bg_scan_query_resp;
@@ -1653,6 +1823,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_11n_cfg htcfg;
struct host_cmd_ds_wmm_get_status get_wmm_status;
struct host_cmd_ds_802_11_key_material key_material;
+ struct host_cmd_ds_802_11_key_material_v2 key_material_v2;
struct host_cmd_ds_version_ext verext;
struct host_cmd_ds_mgmt_frame_reg reg_mask;
struct host_cmd_ds_remain_on_chan roc_cfg;
@@ -1671,6 +1842,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_sta_deauth sta_deauth;
struct host_cmd_11ac_vht_cfg vht_cfg;
struct host_cmd_ds_coalesce_cfg coalesce_cfg;
+ struct host_cmd_ds_tdls_oper tdls_oper;
} params;
} __packed;
diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c
index 81ac001ee741..3bf3d58bbc02 100644
--- a/drivers/net/wireless/mwifiex/ie.c
+++ b/drivers/net/wireless/mwifiex/ie.c
@@ -138,9 +138,9 @@ mwifiex_update_autoindex_ies(struct mwifiex_private *priv,
}
if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP)
- return mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG,
- HostCmd_ACT_GEN_SET,
- UAP_CUSTOM_IE_I, ie_list);
+ return mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
+ HostCmd_ACT_GEN_SET,
+ UAP_CUSTOM_IE_I, ie_list, false);
return 0;
}
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index 1d0a817f2bf0..4ecd0b208ac6 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -137,6 +137,7 @@ int mwifiex_init_priv(struct mwifiex_private *priv)
priv->csa_expire_time = 0;
priv->del_list_idx = 0;
priv->hs2_enabled = false;
+ memcpy(priv->tos_to_tid_inv, tos_to_tid_inv, MAX_NUM_TID);
return mwifiex_add_bss_prio_tbl(priv);
}
@@ -233,7 +234,6 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
adapter->pm_wakeup_fw_try = false;
- adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
adapter->is_hs_configured = false;
@@ -281,6 +281,9 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
adapter->arp_filter_size = 0;
adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX;
adapter->empty_tx_q_cnt = 0;
+ adapter->ext_scan = true;
+ adapter->fw_key_api_major_ver = 0;
+ adapter->fw_key_api_minor_ver = 0;
}
/*
@@ -450,6 +453,7 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
INIT_LIST_HEAD(&priv->sta_list);
+ skb_queue_head_init(&priv->tdls_txq);
spin_lock_init(&priv->tx_ba_stream_tbl_lock);
spin_lock_init(&priv->rx_reorder_tbl_lock);
@@ -615,7 +619,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
/* cancel current command */
if (adapter->curr_cmd) {
dev_warn(adapter->dev, "curr_cmd is still in processing\n");
- del_timer(&adapter->cmd_timer);
+ del_timer_sync(&adapter->cmd_timer);
mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
adapter->curr_cmd = NULL;
}
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
index 00a95f4c6a6c..ee494db54060 100644
--- a/drivers/net/wireless/mwifiex/ioctl.h
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -60,8 +60,7 @@ enum {
BAND_A = 4,
BAND_GN = 8,
BAND_AN = 16,
- BAND_GAC = 32,
- BAND_AAC = 64,
+ BAND_AAC = 32,
};
#define MWIFIEX_WPA_PASSHPHRASE_LEN 64
@@ -86,6 +85,10 @@ struct wep_key {
#define BAND_CONFIG_A 0x01
#define MWIFIEX_SUPPORTED_RATES 14
#define MWIFIEX_SUPPORTED_RATES_EXT 32
+#define MWIFIEX_TDLS_SUPPORTED_RATES 8
+#define MWIFIEX_TDLS_DEF_QOS_CAPAB 0xf
+#define MWIFIEX_PRIO_BK 2
+#define MWIFIEX_PRIO_VI 5
struct mwifiex_uap_bss_param {
u8 channel;
@@ -174,6 +177,7 @@ struct mwifiex_ds_rx_reorder_tbl {
struct mwifiex_ds_tx_ba_stream_tbl {
u16 tid;
u8 ra[ETH_ALEN];
+ u8 amsdu;
};
#define DBG_CMD_NUM 5
@@ -206,7 +210,7 @@ struct mwifiex_debug_info {
u32 num_cmd_assoc_success;
u32 num_cmd_assoc_failure;
u32 num_tx_timeout;
- u32 num_cmd_timeout;
+ u8 is_cmd_timedout;
u16 timeout_cmd_id;
u16 timeout_cmd_act;
u16 last_cmd_id[DBG_CMD_NUM];
@@ -233,7 +237,10 @@ struct mwifiex_ds_encrypt_key {
u8 mac_addr[ETH_ALEN];
u32 is_wapi_key;
u8 pn[PN_LEN]; /* packet number */
+ u8 pn_len;
u8 is_igtk_key;
+ u8 is_current_wep_key;
+ u8 is_rx_seq_valid;
};
struct mwifiex_power_cfg {
@@ -432,4 +439,16 @@ struct mwifiex_ds_coalesce_cfg {
struct mwifiex_coalesce_rule rule[MWIFIEX_COALESCE_MAX_RULES];
};
+struct mwifiex_ds_tdls_oper {
+ u16 tdls_action;
+ u8 peer_mac[ETH_ALEN];
+ u16 capability;
+ u8 qos_info;
+ u8 *ext_capab;
+ u8 ext_capab_len;
+ u8 *supp_rates;
+ u8 supp_rates_len;
+ u8 *ht_capab;
+};
+
#endif /* !_MWIFIEX_IOCTL_H_ */
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index 4e4686e6ac09..89dc62a467f4 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -515,8 +515,7 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
!bss_desc->disable_11n && !bss_desc->disable_11ac &&
- (priv->adapter->config_bands & BAND_GAC ||
- priv->adapter->config_bands & BAND_AAC))
+ priv->adapter->config_bands & BAND_AAC)
mwifiex_cmd_append_11ac_tlv(priv, bss_desc, &pos);
/* Append vendor specific IE TLV */
@@ -902,9 +901,9 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
mwifiex_get_active_data_rates(priv, adhoc_start->data_rate);
if ((adapter->adhoc_start_band & BAND_G) &&
(priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) {
- if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
- HostCmd_ACT_GEN_SET, 0,
- &priv->curr_pkt_filter)) {
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0,
+ &priv->curr_pkt_filter, false)) {
dev_err(adapter->dev,
"ADHOC_S_CMD: G Protection config failed\n");
return -1;
@@ -983,7 +982,7 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
cpu_to_le16(sizeof(struct ieee80211_ht_cap));
radio_type = mwifiex_band_to_radio_type(
priv->adapter->config_bands);
- mwifiex_fill_cap_info(priv, radio_type, ht_cap);
+ mwifiex_fill_cap_info(priv, radio_type, &ht_cap->ht_cap);
if (adapter->sec_chan_offset ==
IEEE80211_HT_PARAM_CHA_SEC_NONE) {
@@ -1074,9 +1073,9 @@ mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,
priv->
curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
- if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
- HostCmd_ACT_GEN_SET, 0,
- &curr_pkt_filter)) {
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0,
+ &curr_pkt_filter, false)) {
dev_err(priv->adapter->dev,
"ADHOC_J_CMD: G Protection config failed\n");
return -1;
@@ -1300,8 +1299,7 @@ int mwifiex_associate(struct mwifiex_private *priv,
if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
!bss_desc->disable_11n && !bss_desc->disable_11ac &&
- (priv->adapter->config_bands & BAND_GAC ||
- priv->adapter->config_bands & BAND_AAC))
+ priv->adapter->config_bands & BAND_AAC)
mwifiex_set_11ac_ba_params(priv);
else
mwifiex_set_ba_params(priv);
@@ -1314,8 +1312,8 @@ int mwifiex_associate(struct mwifiex_private *priv,
retrieval */
priv->assoc_rsp_size = 0;
- return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_ASSOCIATE,
- HostCmd_ACT_GEN_SET, 0, bss_desc);
+ return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_ASSOCIATE,
+ HostCmd_ACT_GEN_SET, 0, bss_desc, true);
}
/*
@@ -1335,14 +1333,13 @@ mwifiex_adhoc_start(struct mwifiex_private *priv,
priv->curr_bss_params.band);
if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
- (priv->adapter->config_bands & BAND_GAC ||
- priv->adapter->config_bands & BAND_AAC))
+ priv->adapter->config_bands & BAND_AAC)
mwifiex_set_11ac_ba_params(priv);
else
mwifiex_set_ba_params(priv);
- return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_START,
- HostCmd_ACT_GEN_SET, 0, adhoc_ssid);
+ return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_START,
+ HostCmd_ACT_GEN_SET, 0, adhoc_ssid, true);
}
/*
@@ -1376,8 +1373,7 @@ int mwifiex_adhoc_join(struct mwifiex_private *priv,
if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
!bss_desc->disable_11n && !bss_desc->disable_11ac &&
- (priv->adapter->config_bands & BAND_GAC ||
- priv->adapter->config_bands & BAND_AAC))
+ priv->adapter->config_bands & BAND_AAC)
mwifiex_set_11ac_ba_params(priv);
else
mwifiex_set_ba_params(priv);
@@ -1387,8 +1383,8 @@ int mwifiex_adhoc_join(struct mwifiex_private *priv,
dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %c\n",
priv->curr_bss_params.band);
- return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_JOIN,
- HostCmd_ACT_GEN_SET, 0, bss_desc);
+ return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_JOIN,
+ HostCmd_ACT_GEN_SET, 0, bss_desc, true);
}
/*
@@ -1407,8 +1403,8 @@ static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac)
else
memcpy(mac_address, mac, ETH_ALEN);
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_DEAUTHENTICATE,
- HostCmd_ACT_GEN_SET, 0, mac_address);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_DEAUTHENTICATE,
+ HostCmd_ACT_GEN_SET, 0, mac_address, true);
return ret;
}
@@ -1436,19 +1432,31 @@ int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac)
GFP_KERNEL);
break;
case NL80211_IFTYPE_ADHOC:
- return mwifiex_send_cmd_sync(priv,
- HostCmd_CMD_802_11_AD_HOC_STOP,
- HostCmd_ACT_GEN_SET, 0, NULL);
+ return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_STOP,
+ HostCmd_ACT_GEN_SET, 0, NULL, true);
case NL80211_IFTYPE_AP:
- return mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
- HostCmd_ACT_GEN_SET, 0, NULL);
+ return mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
+ HostCmd_ACT_GEN_SET, 0, NULL, true);
default:
break;
}
return ret;
}
-EXPORT_SYMBOL_GPL(mwifiex_deauthenticate);
+
+/* This function deauthenticates/disconnects from all BSS. */
+void mwifiex_deauthenticate_all(struct mwifiex_adapter *adapter)
+{
+ struct mwifiex_private *priv;
+ int i;
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ priv = adapter->priv[i];
+ if (priv)
+ mwifiex_deauthenticate(priv, NULL);
+ }
+}
+EXPORT_SYMBOL_GPL(mwifiex_deauthenticate_all);
/*
* This function converts band to radio type used in channel TLV.
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index 4d79761b9c87..77db0886c6e2 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -38,7 +38,8 @@ static void scan_delay_timer_fn(unsigned long data)
if (adapter->surprise_removed)
return;
- if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) {
+ if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT ||
+ !adapter->scan_processing) {
/*
* Abort scan operation by cancelling all pending scan
* commands
@@ -194,7 +195,7 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter)
if (adapter->if_ops.cleanup_if)
adapter->if_ops.cleanup_if(adapter);
- del_timer(&adapter->cmd_timer);
+ del_timer_sync(&adapter->cmd_timer);
/* Free private structures */
for (i = 0; i < adapter->priv_num; i++) {
@@ -678,8 +679,8 @@ mwifiex_set_mac_address(struct net_device *dev, void *addr)
memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN);
/* Send request to firmware */
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_MAC_ADDRESS,
- HostCmd_ACT_GEN_SET, 0, NULL);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_MAC_ADDRESS,
+ HostCmd_ACT_GEN_SET, 0, NULL, true);
if (!ret)
memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN);
@@ -748,7 +749,7 @@ static struct net_device_stats *mwifiex_get_stats(struct net_device *dev)
static u16
mwifiex_netdev_select_wmm_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv, select_queue_fallback_t fallback)
{
skb->priority = cfg80211_classify8021d(skb, NULL);
return mwifiex_1d_to_wmm_queue[skb->priority];
@@ -871,7 +872,6 @@ mwifiex_add_card(void *card, struct semaphore *sem,
adapter->is_suspended = false;
adapter->hs_activated = false;
init_waitqueue_head(&adapter->hs_activate_wait_q);
- adapter->cmd_wait_q_required = false;
init_waitqueue_head(&adapter->cmd_wait_q.wait);
adapter->cmd_wait_q.status = 0;
adapter->scan_wait_q_woken = false;
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index d8ad554ce39f..d53e1e8c9467 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -59,7 +59,7 @@ enum {
#define MWIFIEX_UPLD_SIZE (2312)
-#define MAX_EVENT_SIZE 1024
+#define MAX_EVENT_SIZE 2048
#define ARP_FILTER_MAX_BUF_SIZE 68
@@ -116,7 +116,7 @@ enum {
#define MWIFIEX_TYPE_DATA 0
#define MWIFIEX_TYPE_EVENT 3
-#define MAX_BITMAP_RATES_SIZE 10
+#define MAX_BITMAP_RATES_SIZE 18
#define MAX_CHANNEL_BAND_BG 14
#define MAX_CHANNEL_BAND_A 165
@@ -145,7 +145,6 @@ struct mwifiex_dbg {
u32 num_cmd_assoc_success;
u32 num_cmd_assoc_failure;
u32 num_tx_timeout;
- u32 num_cmd_timeout;
u16 timeout_cmd_id;
u16 timeout_cmd_act;
u16 last_cmd_id[DBG_CMD_NUM];
@@ -193,6 +192,8 @@ struct mwifiex_add_ba_param {
u32 tx_win_size;
u32 rx_win_size;
u32 timeout;
+ u8 tx_amsdu;
+ u8 rx_amsdu;
};
struct mwifiex_tx_aggr {
@@ -210,6 +211,7 @@ struct mwifiex_ra_list_tbl {
u16 ba_pkt_count;
u8 ba_packet_thr;
u16 total_pkt_count;
+ bool tdls_link;
};
struct mwifiex_tid_tbl {
@@ -262,6 +264,31 @@ struct ieee_types_generic {
u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_header)];
} __packed;
+struct ieee_types_bss_co_2040 {
+ struct ieee_types_header ieee_hdr;
+ u8 bss_2040co;
+} __packed;
+
+struct ieee_types_extcap {
+ struct ieee_types_header ieee_hdr;
+ u8 ext_capab[8];
+} __packed;
+
+struct ieee_types_vht_cap {
+ struct ieee_types_header ieee_hdr;
+ struct ieee80211_vht_cap vhtcap;
+} __packed;
+
+struct ieee_types_vht_oper {
+ struct ieee_types_header ieee_hdr;
+ struct ieee80211_vht_operation vhtoper;
+} __packed;
+
+struct ieee_types_aid {
+ struct ieee_types_header ieee_hdr;
+ u16 aid;
+} __packed;
+
struct mwifiex_bssdescriptor {
u8 mac_address[ETH_ALEN];
struct cfg80211_ssid ssid;
@@ -443,6 +470,7 @@ struct mwifiex_private {
u8 wpa_ie_len;
u8 wpa_is_gtk_set;
struct host_cmd_ds_802_11_key_material aes_key;
+ struct host_cmd_ds_802_11_key_material_v2 aes_key_v2;
u8 wapi_ie[256];
u8 wapi_ie_len;
u8 *wps_ie;
@@ -461,6 +489,7 @@ struct mwifiex_private {
struct mwifiex_tx_aggr aggr_prio_tbl[MAX_NUM_TID];
struct mwifiex_add_ba_param add_ba_param;
u16 rx_seq[MAX_NUM_TID];
+ u8 tos_to_tid_inv[MAX_NUM_TID];
struct list_head rx_reorder_tbl_ptr;
/* spin lock for rx_reorder_tbl_ptr queue */
spinlock_t rx_reorder_tbl_lock;
@@ -518,6 +547,8 @@ struct mwifiex_private {
unsigned long csa_expire_time;
u8 del_list_idx;
bool hs2_enabled;
+ struct station_parameters *sta_params;
+ struct sk_buff_head tdls_txq;
};
enum mwifiex_ba_status {
@@ -531,6 +562,7 @@ struct mwifiex_tx_ba_stream_tbl {
int tid;
u8 ra[ETH_ALEN];
enum mwifiex_ba_status ba_status;
+ u8 amsdu;
};
struct mwifiex_rx_reorder_tbl;
@@ -545,10 +577,12 @@ struct mwifiex_rx_reorder_tbl {
struct list_head list;
int tid;
u8 ta[ETH_ALEN];
+ int init_win;
int start_win;
int win_size;
void **rx_reorder_ptr;
struct reorder_tmr_cnxt timer_context;
+ u8 amsdu;
u8 flags;
};
@@ -583,17 +617,35 @@ struct mwifiex_bss_priv {
u64 fw_tsf;
};
-/* This is AP specific structure which stores information
- * about associated STA
+struct mwifiex_tdls_capab {
+ __le16 capab;
+ u8 rates[32];
+ u8 rates_len;
+ u8 qos_info;
+ u8 coex_2040;
+ u16 aid;
+ struct ieee80211_ht_cap ht_capb;
+ struct ieee80211_ht_operation ht_oper;
+ struct ieee_types_extcap extcap;
+ struct ieee_types_generic rsn_ie;
+ struct ieee80211_vht_cap vhtcap;
+ struct ieee80211_vht_operation vhtoper;
+};
+
+/* This is AP/TDLS specific structure which stores information
+ * about associated/peer STA
*/
struct mwifiex_sta_node {
struct list_head list;
u8 mac_addr[ETH_ALEN];
u8 is_wmm_enabled;
u8 is_11n_enabled;
+ u8 is_11ac_enabled;
u8 ampdu_sta[MAX_NUM_TID];
u16 rx_seq[MAX_NUM_TID];
u16 max_amsdu;
+ u8 tdls_status;
+ struct mwifiex_tdls_capab tdls_cap;
};
struct mwifiex_if_ops {
@@ -671,7 +723,7 @@ struct mwifiex_adapter {
struct cmd_ctrl_node *curr_cmd;
/* spin lock for command */
spinlock_t mwifiex_cmd_lock;
- u32 num_cmd_timeout;
+ u8 is_cmd_timedout;
u16 last_init_cmd;
struct timer_list cmd_timer;
struct list_head cmd_free_q;
@@ -722,15 +774,16 @@ struct mwifiex_adapter {
u16 hs_activate_wait_q_woken;
wait_queue_head_t hs_activate_wait_q;
bool is_suspended;
+ bool hs_enabling;
u8 event_body[MAX_EVENT_SIZE];
u32 hw_dot_11n_dev_cap;
u8 hw_dev_mcs_support;
+ u8 user_dev_mcs_support;
u8 adhoc_11n_enabled;
u8 sec_chan_offset;
struct mwifiex_dbg dbg;
u8 arp_filter[ARP_FILTER_MAX_BUF_SIZE];
u32 arp_filter_size;
- u16 cmd_wait_q_required;
struct mwifiex_wait_queue cmd_wait_q;
u8 scan_wait_q_woken;
spinlock_t queue_lock; /* lock for tx queues */
@@ -753,6 +806,9 @@ struct mwifiex_adapter {
atomic_t is_tx_received;
atomic_t pending_bridged_pkts;
struct semaphore *card_sem;
+ bool ext_scan;
+ u8 fw_api_ver;
+ u8 fw_key_api_major_ver, fw_key_api_minor_ver;
};
int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
@@ -788,11 +844,8 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter);
int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,
struct cmd_ctrl_node *cmd_node);
-int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
- u16 cmd_action, u32 cmd_oid, void *data_buf);
-
-int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no,
- u16 cmd_action, u32 cmd_oid, void *data_buf);
+int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no,
+ u16 cmd_action, u32 cmd_oid, void *data_buf, bool sync);
void mwifiex_cmd_timeout_func(unsigned long function_context);
@@ -880,6 +933,7 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
void mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason);
u8 mwifiex_band_to_radio_type(u8 band);
int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac);
+void mwifiex_deauthenticate_all(struct mwifiex_adapter *adapter);
int mwifiex_adhoc_start(struct mwifiex_private *priv,
struct cfg80211_ssid *adhoc_ssid);
int mwifiex_adhoc_join(struct mwifiex_private *priv,
@@ -938,6 +992,12 @@ mwifiex_set_wmm_params(struct mwifiex_private *priv,
struct cfg80211_ap_settings *params);
void mwifiex_set_ba_params(struct mwifiex_private *priv);
void mwifiex_set_11ac_ba_params(struct mwifiex_private *priv);
+int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ void *data_buf);
+int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv);
+int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv,
+ void *buf);
/*
* This function checks if the queuing is RA based or not.
@@ -1078,7 +1138,7 @@ int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp,
const u8 *key, int key_len, u8 key_index,
const u8 *mac_addr, int disable);
-int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len);
+int mwifiex_set_gen_ie(struct mwifiex_private *priv, const u8 *ie, int ie_len);
int mwifiex_get_ver_ext(struct mwifiex_private *priv);
@@ -1159,6 +1219,32 @@ void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv);
extern const struct ethtool_ops mwifiex_ethtool_ops;
+void mwifiex_del_all_sta_list(struct mwifiex_private *priv);
+void mwifiex_del_sta_entry(struct mwifiex_private *priv, u8 *mac);
+void
+mwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies,
+ int ies_len, struct mwifiex_sta_node *node);
+struct mwifiex_sta_node *
+mwifiex_add_sta_entry(struct mwifiex_private *priv, u8 *mac);
+struct mwifiex_sta_node *
+mwifiex_get_sta_entry(struct mwifiex_private *priv, u8 *mac);
+int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, u8 *peer,
+ u8 action_code, u8 dialog_token,
+ u16 status_code, const u8 *extra_ies,
+ size_t extra_ies_len);
+int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv,
+ u8 *peer, u8 action_code, u8 dialog_token,
+ u16 status_code, const u8 *extra_ies,
+ size_t extra_ies_len);
+void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
+ u8 *buf, int len);
+int mwifiex_tdls_oper(struct mwifiex_private *priv, u8 *peer, u8 action);
+int mwifiex_get_tdls_link_status(struct mwifiex_private *priv, u8 *mac);
+void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv);
+bool mwifiex_is_bss_in_11ac_mode(struct mwifiex_private *priv);
+u8 mwifiex_get_center_freq_index(struct mwifiex_private *priv, u8 band,
+ u32 pri_chan, u8 chan_bw);
+
#ifdef CONFIG_DEBUG_FS
void mwifiex_debugfs_init(void);
void mwifiex_debugfs_remove(void);
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
index 03688aa14e8a..a7e8b96b2d90 100644
--- a/drivers/net/wireless/mwifiex/pcie.c
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -39,20 +39,31 @@ static struct semaphore add_remove_card_sem;
static int
mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
- int size, int flags)
+ size_t size, int flags)
{
struct pcie_service_card *card = adapter->card;
- dma_addr_t buf_pa;
+ struct mwifiex_dma_mapping mapping;
- buf_pa = pci_map_single(card->dev, skb->data, size, flags);
- if (pci_dma_mapping_error(card->dev, buf_pa)) {
+ mapping.addr = pci_map_single(card->dev, skb->data, size, flags);
+ if (pci_dma_mapping_error(card->dev, mapping.addr)) {
dev_err(adapter->dev, "failed to map pci memory!\n");
return -1;
}
- memcpy(skb->cb, &buf_pa, sizeof(dma_addr_t));
+ mapping.len = size;
+ memcpy(skb->cb, &mapping, sizeof(mapping));
return 0;
}
+static void mwifiex_unmap_pci_memory(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb, int flags)
+{
+ struct pcie_service_card *card = adapter->card;
+ struct mwifiex_dma_mapping mapping;
+
+ MWIFIEX_SKB_PACB(skb, &mapping);
+ pci_unmap_single(card->dev, mapping.addr, mapping.len, flags);
+}
+
/*
* This function reads sleep cookie and checks if FW is ready
*/
@@ -109,6 +120,7 @@ static int mwifiex_pcie_suspend(struct device *dev)
/* Indicate device suspended */
adapter->is_suspended = true;
+ adapter->hs_enabling = false;
return 0;
}
@@ -179,6 +191,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
card->pcie.firmware = data->firmware;
card->pcie.reg = data->reg;
card->pcie.blksz_fw_dl = data->blksz_fw_dl;
+ card->pcie.tx_buf_size = data->tx_buf_size;
}
if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
@@ -199,7 +212,6 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
struct pcie_service_card *card;
struct mwifiex_adapter *adapter;
struct mwifiex_private *priv;
- int i;
card = pci_get_drvdata(pdev);
if (!card)
@@ -218,11 +230,7 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
mwifiex_pcie_resume(&pdev->dev);
#endif
- for (i = 0; i < adapter->priv_num; i++)
- if ((GET_BSS_ROLE(adapter->priv[i]) ==
- MWIFIEX_BSS_ROLE_STA) &&
- adapter->priv[i]->media_connected)
- mwifiex_deauthenticate(adapter->priv[i], NULL);
+ mwifiex_deauthenticate_all(adapter);
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
@@ -320,6 +328,30 @@ static void mwifiex_pcie_dev_wakeup_delay(struct mwifiex_adapter *adapter)
return;
}
+static void mwifiex_delay_for_sleep_cookie(struct mwifiex_adapter *adapter,
+ u32 max_delay_loop_cnt)
+{
+ struct pcie_service_card *card = adapter->card;
+ u8 *buffer;
+ u32 sleep_cookie, count;
+
+ for (count = 0; count < max_delay_loop_cnt; count++) {
+ buffer = card->cmdrsp_buf->data - INTF_HEADER_LEN;
+ sleep_cookie = *(u32 *)buffer;
+
+ if (sleep_cookie == MWIFIEX_DEF_SLEEP_COOKIE) {
+ dev_dbg(adapter->dev,
+ "sleep cookie found at count %d\n", count);
+ break;
+ }
+ usleep_range(20, 30);
+ }
+
+ if (count >= max_delay_loop_cnt)
+ dev_dbg(adapter->dev,
+ "max count reached while accessing sleep cookie\n");
+}
+
/* This function wakes up the card by reading fw_status register. */
static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
{
@@ -456,7 +488,7 @@ static int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter)
PCI_DMA_FROMDEVICE))
return -1;
- MWIFIEX_SKB_PACB(skb, &buf_pa);
+ buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
dev_dbg(adapter->dev,
"info: RX ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n",
@@ -513,7 +545,7 @@ static int mwifiex_pcie_init_evt_ring(struct mwifiex_adapter *adapter)
PCI_DMA_FROMDEVICE))
return -1;
- MWIFIEX_SKB_PACB(skb, &buf_pa);
+ buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
dev_dbg(adapter->dev,
"info: EVT ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n",
@@ -549,8 +581,8 @@ static void mwifiex_cleanup_txq_ring(struct mwifiex_adapter *adapter)
desc2 = card->txbd_ring[i];
if (card->tx_buf_list[i]) {
skb = card->tx_buf_list[i];
- pci_unmap_single(card->dev, desc2->paddr,
- skb->len, PCI_DMA_TODEVICE);
+ mwifiex_unmap_pci_memory(adapter, skb,
+ PCI_DMA_TODEVICE);
dev_kfree_skb_any(skb);
}
memset(desc2, 0, sizeof(*desc2));
@@ -558,8 +590,8 @@ static void mwifiex_cleanup_txq_ring(struct mwifiex_adapter *adapter)
desc = card->txbd_ring[i];
if (card->tx_buf_list[i]) {
skb = card->tx_buf_list[i];
- pci_unmap_single(card->dev, desc->paddr,
- skb->len, PCI_DMA_TODEVICE);
+ mwifiex_unmap_pci_memory(adapter, skb,
+ PCI_DMA_TODEVICE);
dev_kfree_skb_any(skb);
}
memset(desc, 0, sizeof(*desc));
@@ -587,8 +619,8 @@ static void mwifiex_cleanup_rxq_ring(struct mwifiex_adapter *adapter)
desc2 = card->rxbd_ring[i];
if (card->rx_buf_list[i]) {
skb = card->rx_buf_list[i];
- pci_unmap_single(card->dev, desc2->paddr,
- skb->len, PCI_DMA_FROMDEVICE);
+ mwifiex_unmap_pci_memory(adapter, skb,
+ PCI_DMA_FROMDEVICE);
dev_kfree_skb_any(skb);
}
memset(desc2, 0, sizeof(*desc2));
@@ -596,8 +628,8 @@ static void mwifiex_cleanup_rxq_ring(struct mwifiex_adapter *adapter)
desc = card->rxbd_ring[i];
if (card->rx_buf_list[i]) {
skb = card->rx_buf_list[i];
- pci_unmap_single(card->dev, desc->paddr,
- skb->len, PCI_DMA_FROMDEVICE);
+ mwifiex_unmap_pci_memory(adapter, skb,
+ PCI_DMA_FROMDEVICE);
dev_kfree_skb_any(skb);
}
memset(desc, 0, sizeof(*desc));
@@ -622,8 +654,8 @@ static void mwifiex_cleanup_evt_ring(struct mwifiex_adapter *adapter)
desc = card->evtbd_ring[i];
if (card->evt_buf_list[i]) {
skb = card->evt_buf_list[i];
- pci_unmap_single(card->dev, desc->paddr, MAX_EVENT_SIZE,
- PCI_DMA_FROMDEVICE);
+ mwifiex_unmap_pci_memory(adapter, skb,
+ PCI_DMA_FROMDEVICE);
dev_kfree_skb_any(skb);
}
card->evt_buf_list[i] = NULL;
@@ -861,7 +893,6 @@ static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter)
static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card;
- dma_addr_t buf_pa;
if (!adapter)
return 0;
@@ -869,16 +900,14 @@ static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter)
card = adapter->card;
if (card && card->cmdrsp_buf) {
- MWIFIEX_SKB_PACB(card->cmdrsp_buf, &buf_pa);
- pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
- PCI_DMA_FROMDEVICE);
+ mwifiex_unmap_pci_memory(adapter, card->cmdrsp_buf,
+ PCI_DMA_FROMDEVICE);
dev_kfree_skb_any(card->cmdrsp_buf);
}
if (card && card->cmd_buf) {
- MWIFIEX_SKB_PACB(card->cmd_buf, &buf_pa);
- pci_unmap_single(card->dev, buf_pa, card->cmd_buf->len,
- PCI_DMA_TODEVICE);
+ mwifiex_unmap_pci_memory(adapter, card->cmd_buf,
+ PCI_DMA_TODEVICE);
}
return 0;
}
@@ -956,7 +985,6 @@ static int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter)
static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
{
struct sk_buff *skb;
- dma_addr_t buf_pa;
u32 wrdoneidx, rdptr, num_tx_buffs, unmap_count = 0;
struct mwifiex_pcie_buf_desc *desc;
struct mwifiex_pfu_buf_desc *desc2;
@@ -986,13 +1014,13 @@ static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
reg->tx_start_ptr;
skb = card->tx_buf_list[wrdoneidx];
+
if (skb) {
dev_dbg(adapter->dev,
"SEND COMP: Detach skb %p at txbd_rdidx=%d\n",
skb, wrdoneidx);
- MWIFIEX_SKB_PACB(skb, &buf_pa);
- pci_unmap_single(card->dev, buf_pa, skb->len,
- PCI_DMA_TODEVICE);
+ mwifiex_unmap_pci_memory(adapter, skb,
+ PCI_DMA_TODEVICE);
unmap_count++;
@@ -1006,7 +1034,7 @@ static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
card->tx_buf_list[wrdoneidx] = NULL;
if (reg->pfu_enabled) {
- desc2 = (void *)card->txbd_ring[wrdoneidx];
+ desc2 = card->txbd_ring[wrdoneidx];
memset(desc2, 0, sizeof(*desc2));
} else {
desc = card->txbd_ring[wrdoneidx];
@@ -1082,16 +1110,16 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
tmp = (__le16 *)&payload[2];
*tmp = cpu_to_le16(MWIFIEX_TYPE_DATA);
- if (mwifiex_map_pci_memory(adapter, skb, skb->len ,
+ if (mwifiex_map_pci_memory(adapter, skb, skb->len,
PCI_DMA_TODEVICE))
return -1;
wrindx = (card->txbd_wrptr & reg->tx_mask) >> reg->tx_start_ptr;
- MWIFIEX_SKB_PACB(skb, &buf_pa);
+ buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
card->tx_buf_list[wrindx] = skb;
if (reg->pfu_enabled) {
- desc2 = (void *)card->txbd_ring[wrindx];
+ desc2 = card->txbd_ring[wrindx];
desc2->paddr = buf_pa;
desc2->len = (u16)skb->len;
desc2->frag_len = (u16)skb->len;
@@ -1162,8 +1190,7 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
return -EINPROGRESS;
done_unmap:
- MWIFIEX_SKB_PACB(skb, &buf_pa);
- pci_unmap_single(card->dev, buf_pa, skb->len, PCI_DMA_TODEVICE);
+ mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_TODEVICE);
card->tx_buf_list[wrindx] = NULL;
if (reg->pfu_enabled)
memset(desc2, 0, sizeof(*desc2));
@@ -1211,9 +1238,13 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
rd_index = card->rxbd_rdptr & reg->rx_mask;
skb_data = card->rx_buf_list[rd_index];
- MWIFIEX_SKB_PACB(skb_data, &buf_pa);
- pci_unmap_single(card->dev, buf_pa, MWIFIEX_RX_DATA_BUF_SIZE,
- PCI_DMA_FROMDEVICE);
+ /* If skb allocation was failed earlier for Rx packet,
+ * rx_buf_list[rd_index] would have been left with a NULL.
+ */
+ if (!skb_data)
+ return -ENOMEM;
+
+ mwifiex_unmap_pci_memory(adapter, skb_data, PCI_DMA_FROMDEVICE);
card->rx_buf_list[rd_index] = NULL;
/* Get data length from interface header -
@@ -1240,7 +1271,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
PCI_DMA_FROMDEVICE))
return -1;
- MWIFIEX_SKB_PACB(skb_tmp, &buf_pa);
+ buf_pa = MWIFIEX_SKB_DMA_ADDR(skb_tmp);
dev_dbg(adapter->dev,
"RECV DATA: Attach new sk_buff %p at rxbd_rdidx=%d\n",
@@ -1248,7 +1279,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
card->rx_buf_list[rd_index] = skb_tmp;
if (reg->pfu_enabled) {
- desc2 = (void *)card->rxbd_ring[rd_index];
+ desc2 = card->rxbd_ring[rd_index];
desc2->paddr = buf_pa;
desc2->len = skb_tmp->len;
desc2->frag_len = skb_tmp->len;
@@ -1316,7 +1347,7 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
if (mwifiex_map_pci_memory(adapter, skb, skb->len , PCI_DMA_TODEVICE))
return -1;
- MWIFIEX_SKB_PACB(skb, &buf_pa);
+ buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
/* Write the lower 32bits of the physical address to low command
* address scratch register
@@ -1325,8 +1356,7 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
dev_err(adapter->dev,
"%s: failed to write download command to boot code.\n",
__func__);
- pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
- PCI_DMA_TODEVICE);
+ mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_TODEVICE);
return -1;
}
@@ -1338,8 +1368,7 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
dev_err(adapter->dev,
"%s: failed to write download command to boot code.\n",
__func__);
- pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
- PCI_DMA_TODEVICE);
+ mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_TODEVICE);
return -1;
}
@@ -1348,8 +1377,7 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
dev_err(adapter->dev,
"%s: failed to write command len to cmd_size scratch reg\n",
__func__);
- pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
- PCI_DMA_TODEVICE);
+ mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_TODEVICE);
return -1;
}
@@ -1358,8 +1386,7 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
CPU_INTR_DOOR_BELL)) {
dev_err(adapter->dev,
"%s: failed to assert door-bell intr\n", __func__);
- pci_unmap_single(card->dev, buf_pa,
- MWIFIEX_UPLD_SIZE, PCI_DMA_TODEVICE);
+ mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_TODEVICE);
return -1;
}
@@ -1433,7 +1460,7 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
*/
if (card->cmdrsp_buf) {
- MWIFIEX_SKB_PACB(card->cmdrsp_buf, &cmdrsp_buf_pa);
+ cmdrsp_buf_pa = MWIFIEX_SKB_DMA_ADDR(card->cmdrsp_buf);
/* Write the lower 32bits of the cmdrsp buffer physical
address */
if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo,
@@ -1454,7 +1481,7 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
}
}
- MWIFIEX_SKB_PACB(card->cmd_buf, &cmd_buf_pa);
+ cmd_buf_pa = MWIFIEX_SKB_DMA_ADDR(card->cmd_buf);
/* Write the lower 32bits of the physical address to reg->cmd_addr_lo */
if (mwifiex_write_reg(adapter, reg->cmd_addr_lo,
(u32)cmd_buf_pa)) {
@@ -1508,13 +1535,17 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
int count = 0;
u16 rx_len;
__le16 pkt_len;
- dma_addr_t buf_pa;
dev_dbg(adapter->dev, "info: Rx CMD Response\n");
- MWIFIEX_SKB_PACB(skb, &buf_pa);
- pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
- PCI_DMA_FROMDEVICE);
+ mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_FROMDEVICE);
+
+ /* Unmap the command as a response has been received. */
+ if (card->cmd_buf) {
+ mwifiex_unmap_pci_memory(adapter, card->cmd_buf,
+ PCI_DMA_TODEVICE);
+ card->cmd_buf = NULL;
+ }
pkt_len = *((__le16 *)skb->data);
rx_len = le16_to_cpu(pkt_len);
@@ -1525,6 +1556,16 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
if (adapter->ps_state == PS_STATE_SLEEP_CFM) {
mwifiex_process_sleep_confirm_resp(adapter, skb->data,
skb->len);
+ mwifiex_pcie_enable_host_int(adapter);
+ if (mwifiex_write_reg(adapter,
+ PCIE_CPU_INT_EVENT,
+ CPU_INTR_SLEEP_CFM_DONE)) {
+ dev_warn(adapter->dev,
+ "Write register failed\n");
+ return -1;
+ }
+ mwifiex_delay_for_sleep_cookie(adapter,
+ MWIFIEX_MAX_DELAY_COUNT);
while (reg->sleep_cookie && (count++ < 10) &&
mwifiex_pcie_ok_to_access_hw(adapter))
usleep_range(50, 60);
@@ -1538,8 +1579,6 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
PCI_DMA_FROMDEVICE))
return -1;
-
- MWIFIEX_SKB_PACB(skb, &buf_pa);
} else if (mwifiex_pcie_ok_to_access_hw(adapter)) {
adapter->curr_cmd->resp_skb = skb;
adapter->cmd_resp_received = true;
@@ -1574,8 +1613,6 @@ static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter,
struct sk_buff *skb)
{
struct pcie_service_card *card = adapter->card;
- dma_addr_t buf_pa;
- struct sk_buff *skb_tmp;
if (skb) {
card->cmdrsp_buf = skb;
@@ -1585,14 +1622,6 @@ static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter,
return -1;
}
- skb_tmp = card->cmd_buf;
- if (skb_tmp) {
- MWIFIEX_SKB_PACB(skb_tmp, &buf_pa);
- pci_unmap_single(card->dev, buf_pa, skb_tmp->len,
- PCI_DMA_FROMDEVICE);
- card->cmd_buf = NULL;
- }
-
return 0;
}
@@ -1605,7 +1634,6 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
u32 wrptr, event;
- dma_addr_t buf_pa;
struct mwifiex_evt_buf_desc *desc;
if (!mwifiex_pcie_ok_to_access_hw(adapter))
@@ -1641,9 +1669,7 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
dev_dbg(adapter->dev, "info: Read Index: %d\n", rdptr);
skb_cmd = card->evt_buf_list[rdptr];
- MWIFIEX_SKB_PACB(skb_cmd, &buf_pa);
- pci_unmap_single(card->dev, buf_pa, MAX_EVENT_SIZE,
- PCI_DMA_FROMDEVICE);
+ mwifiex_unmap_pci_memory(adapter, skb_cmd, PCI_DMA_FROMDEVICE);
/* Take the pointer and set it to event pointer in adapter
and will return back after event handling callback */
@@ -1689,7 +1715,6 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
int ret = 0;
u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
u32 wrptr;
- dma_addr_t buf_pa;
struct mwifiex_evt_buf_desc *desc;
if (!skb)
@@ -1714,11 +1739,9 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
MAX_EVENT_SIZE,
PCI_DMA_FROMDEVICE))
return -1;
- MWIFIEX_SKB_PACB(skb, &buf_pa);
card->evt_buf_list[rdptr] = skb;
- MWIFIEX_SKB_PACB(skb, &buf_pa);
desc = card->evtbd_ring[rdptr];
- desc->paddr = buf_pa;
+ desc->paddr = MWIFIEX_SKB_DMA_ADDR(skb);
desc->len = (u16)skb->len;
desc->flags = 0;
skb = NULL;
@@ -1768,7 +1791,6 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
struct sk_buff *skb;
u32 txlen, tx_blocks = 0, tries, len;
u32 block_retry_cnt = 0;
- dma_addr_t buf_pa;
struct pcie_service_card *card = adapter->card;
const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
@@ -1866,8 +1888,6 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
goto done;
}
- MWIFIEX_SKB_PACB(skb, &buf_pa);
-
/* Wait for the command done interrupt */
do {
if (mwifiex_read_reg(adapter, PCIE_CPU_INT_STATUS,
@@ -1875,16 +1895,15 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
dev_err(adapter->dev, "%s: Failed to read "
"interrupt status during fw dnld.\n",
__func__);
- pci_unmap_single(card->dev, buf_pa, skb->len,
- PCI_DMA_TODEVICE);
+ mwifiex_unmap_pci_memory(adapter, skb,
+ PCI_DMA_TODEVICE);
ret = -1;
goto done;
}
} while ((ireg_intr & CPU_INTR_DOOR_BELL) ==
CPU_INTR_DOOR_BELL);
- pci_unmap_single(card->dev, buf_pa, skb->len,
- PCI_DMA_TODEVICE);
+ mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_TODEVICE);
offset += txlen;
} while (true);
@@ -1993,23 +2012,9 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
adapter->int_status |= pcie_ireg;
spin_unlock_irqrestore(&adapter->int_lock, flags);
- if (pcie_ireg & HOST_INTR_CMD_DONE) {
- if ((adapter->ps_state == PS_STATE_SLEEP_CFM) ||
- (adapter->ps_state == PS_STATE_SLEEP)) {
- mwifiex_pcie_enable_host_int(adapter);
- if (mwifiex_write_reg(adapter,
- PCIE_CPU_INT_EVENT,
- CPU_INTR_SLEEP_CFM_DONE)
- ) {
- dev_warn(adapter->dev,
- "Write register failed\n");
- return;
-
- }
- }
- } else if (!adapter->pps_uapsd_mode &&
- adapter->ps_state == PS_STATE_SLEEP &&
- mwifiex_pcie_ok_to_access_hw(adapter)) {
+ if (!adapter->pps_uapsd_mode &&
+ adapter->ps_state == PS_STATE_SLEEP &&
+ mwifiex_pcie_ok_to_access_hw(adapter)) {
/* Potentially for PCIe we could get other
* interrupts like shared. Don't change power
* state until cookie is set */
@@ -2338,6 +2343,7 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
}
adapter->dev = &pdev->dev;
+ adapter->tx_buf_size = card->pcie.tx_buf_size;
strcpy(adapter->fw_name, card->pcie.firmware);
return 0;
diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h
index d322ab8604ea..e8ec561f8a64 100644
--- a/drivers/net/wireless/mwifiex/pcie.h
+++ b/drivers/net/wireless/mwifiex/pcie.h
@@ -97,6 +97,8 @@
#define MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD 256
/* FW awake cookie after FW ready */
#define FW_AWAKE_COOKIE (0xAA55AA55)
+#define MWIFIEX_DEF_SLEEP_COOKIE 0xBEEFBEEF
+#define MWIFIEX_MAX_DELAY_COUNT 5
struct mwifiex_pcie_card_reg {
u16 cmd_addr_lo;
@@ -195,18 +197,21 @@ struct mwifiex_pcie_device {
const char *firmware;
const struct mwifiex_pcie_card_reg *reg;
u16 blksz_fw_dl;
+ u16 tx_buf_size;
};
static const struct mwifiex_pcie_device mwifiex_pcie8766 = {
.firmware = PCIE8766_DEFAULT_FW_NAME,
.reg = &mwifiex_reg_8766,
.blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
+ .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
};
static const struct mwifiex_pcie_device mwifiex_pcie8897 = {
.firmware = PCIE8897_DEFAULT_FW_NAME,
.reg = &mwifiex_reg_8897,
.blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
+ .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K,
};
struct mwifiex_evt_buf_desc {
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 0a8a26e10f01..7b3af3d29ded 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -591,11 +591,13 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
*chan_tlv_out,
struct mwifiex_chan_scan_param_set *scan_chan_list)
{
+ struct mwifiex_adapter *adapter = priv->adapter;
int ret = 0;
struct mwifiex_chan_scan_param_set *tmp_chan_list;
struct mwifiex_chan_scan_param_set *start_chan;
-
- u32 tlv_idx, rates_size;
+ struct cmd_ctrl_node *cmd_node, *tmp_node;
+ unsigned long flags;
+ u32 tlv_idx, rates_size, cmd_no;
u32 total_scan_time;
u32 done_early;
u8 radio_type;
@@ -733,9 +735,13 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
/* Send the scan command to the firmware with the specified
cfg */
- ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SCAN,
- HostCmd_ACT_GEN_SET, 0,
- scan_cfg_out);
+ if (priv->adapter->ext_scan)
+ cmd_no = HostCmd_CMD_802_11_SCAN_EXT;
+ else
+ cmd_no = HostCmd_CMD_802_11_SCAN;
+
+ ret = mwifiex_send_cmd(priv, cmd_no, HostCmd_ACT_GEN_SET,
+ 0, scan_cfg_out, false);
/* rate IE is updated per scan command but same starting
* pointer is used each time so that rate IE from earlier
@@ -744,8 +750,19 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
scan_cfg_out->tlv_buf_len -=
sizeof(struct mwifiex_ie_types_header) + rates_size;
- if (ret)
+ if (ret) {
+ spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+ list_for_each_entry_safe(cmd_node, tmp_node,
+ &adapter->scan_pending_q,
+ list) {
+ list_del(&cmd_node->list);
+ cmd_node->wait_q_enabled = false;
+ mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+ }
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+ flags);
break;
+ }
}
if (ret)
@@ -786,6 +803,7 @@ mwifiex_config_scan(struct mwifiex_private *priv,
struct mwifiex_adapter *adapter = priv->adapter;
struct mwifiex_ie_types_num_probes *num_probes_tlv;
struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv;
+ struct mwifiex_ie_types_bssid_list *bssid_tlv;
u8 *tlv_pos;
u32 num_probes;
u32 ssid_len;
@@ -848,6 +866,17 @@ mwifiex_config_scan(struct mwifiex_private *priv,
user_scan_in->specific_bssid,
sizeof(scan_cfg_out->specific_bssid));
+ if (adapter->ext_scan &&
+ !is_zero_ether_addr(scan_cfg_out->specific_bssid)) {
+ bssid_tlv =
+ (struct mwifiex_ie_types_bssid_list *)tlv_pos;
+ bssid_tlv->header.type = cpu_to_le16(TLV_TYPE_BSSID);
+ bssid_tlv->header.len = cpu_to_le16(ETH_ALEN);
+ memcpy(bssid_tlv->bssid, user_scan_in->specific_bssid,
+ ETH_ALEN);
+ tlv_pos += sizeof(struct mwifiex_ie_types_bssid_list);
+ }
+
for (i = 0; i < user_scan_in->num_ssids; i++) {
ssid_len = user_scan_in->ssid_list[i].ssid_len;
@@ -941,7 +970,7 @@ mwifiex_config_scan(struct mwifiex_private *priv,
cpu_to_le16(sizeof(struct ieee80211_ht_cap));
radio_type =
mwifiex_band_to_radio_type(priv->adapter->config_bands);
- mwifiex_fill_cap_info(priv, radio_type, ht_cap);
+ mwifiex_fill_cap_info(priv, radio_type, &ht_cap->ht_cap);
tlv_pos += sizeof(struct mwifiex_ie_types_htcap);
}
@@ -1576,6 +1605,228 @@ done:
return 0;
}
+static int
+mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
+ u32 *bytes_left, u64 fw_tsf, u8 *radio_type,
+ bool ext_scan, s32 rssi_val)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_chan_freq_power *cfp;
+ struct cfg80211_bss *bss;
+ u8 bssid[ETH_ALEN];
+ s32 rssi;
+ const u8 *ie_buf;
+ size_t ie_len;
+ u16 channel = 0;
+ u16 beacon_size = 0;
+ u32 curr_bcn_bytes;
+ u32 freq;
+ u16 beacon_period;
+ u16 cap_info_bitmap;
+ u8 *current_ptr;
+ u64 timestamp;
+ struct mwifiex_fixed_bcn_param *bcn_param;
+ struct mwifiex_bss_priv *bss_priv;
+
+ if (*bytes_left >= sizeof(beacon_size)) {
+ /* Extract & convert beacon size from command buffer */
+ memcpy(&beacon_size, *bss_info, sizeof(beacon_size));
+ *bytes_left -= sizeof(beacon_size);
+ *bss_info += sizeof(beacon_size);
+ }
+
+ if (!beacon_size || beacon_size > *bytes_left) {
+ *bss_info += *bytes_left;
+ *bytes_left = 0;
+ return -EFAULT;
+ }
+
+ /* Initialize the current working beacon pointer for this BSS
+ * iteration
+ */
+ current_ptr = *bss_info;
+
+ /* Advance the return beacon pointer past the current beacon */
+ *bss_info += beacon_size;
+ *bytes_left -= beacon_size;
+
+ curr_bcn_bytes = beacon_size;
+
+ /* First 5 fields are bssid, RSSI(for legacy scan only),
+ * time stamp, beacon interval, and capability information
+ */
+ if (curr_bcn_bytes < ETH_ALEN + sizeof(u8) +
+ sizeof(struct mwifiex_fixed_bcn_param)) {
+ dev_err(adapter->dev, "InterpretIE: not enough bytes left\n");
+ return -EFAULT;
+ }
+
+ memcpy(bssid, current_ptr, ETH_ALEN);
+ current_ptr += ETH_ALEN;
+ curr_bcn_bytes -= ETH_ALEN;
+
+ if (!ext_scan) {
+ rssi = (s32) *current_ptr;
+ rssi = (-rssi) * 100; /* Convert dBm to mBm */
+ current_ptr += sizeof(u8);
+ curr_bcn_bytes -= sizeof(u8);
+ dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%d\n", rssi);
+ } else {
+ rssi = rssi_val;
+ }
+
+ bcn_param = (struct mwifiex_fixed_bcn_param *)current_ptr;
+ current_ptr += sizeof(*bcn_param);
+ curr_bcn_bytes -= sizeof(*bcn_param);
+
+ timestamp = le64_to_cpu(bcn_param->timestamp);
+ beacon_period = le16_to_cpu(bcn_param->beacon_period);
+
+ cap_info_bitmap = le16_to_cpu(bcn_param->cap_info_bitmap);
+ dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n",
+ cap_info_bitmap);
+
+ /* Rest of the current buffer are IE's */
+ ie_buf = current_ptr;
+ ie_len = curr_bcn_bytes;
+ dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP = %d\n",
+ curr_bcn_bytes);
+
+ while (curr_bcn_bytes >= sizeof(struct ieee_types_header)) {
+ u8 element_id, element_len;
+
+ element_id = *current_ptr;
+ element_len = *(current_ptr + 1);
+ if (curr_bcn_bytes < element_len +
+ sizeof(struct ieee_types_header)) {
+ dev_err(adapter->dev,
+ "%s: bytes left < IE length\n", __func__);
+ return -EFAULT;
+ }
+ if (element_id == WLAN_EID_DS_PARAMS) {
+ channel = *(current_ptr +
+ sizeof(struct ieee_types_header));
+ break;
+ }
+
+ current_ptr += element_len + sizeof(struct ieee_types_header);
+ curr_bcn_bytes -= element_len +
+ sizeof(struct ieee_types_header);
+ }
+
+ if (channel) {
+ struct ieee80211_channel *chan;
+ u8 band;
+
+ /* Skip entry if on csa closed channel */
+ if (channel == priv->csa_chan) {
+ dev_dbg(adapter->dev,
+ "Dropping entry on csa closed channel\n");
+ return 0;
+ }
+
+ band = BAND_G;
+ if (radio_type)
+ band = mwifiex_radio_type_to_band(*radio_type &
+ (BIT(0) | BIT(1)));
+
+ cfp = mwifiex_get_cfp(priv, band, channel, 0);
+
+ freq = cfp ? cfp->freq : 0;
+
+ chan = ieee80211_get_channel(priv->wdev->wiphy, freq);
+
+ if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
+ bss = cfg80211_inform_bss(priv->wdev->wiphy,
+ chan, bssid, timestamp,
+ cap_info_bitmap, beacon_period,
+ ie_buf, ie_len, rssi, GFP_KERNEL);
+ bss_priv = (struct mwifiex_bss_priv *)bss->priv;
+ bss_priv->band = band;
+ bss_priv->fw_tsf = fw_tsf;
+ if (priv->media_connected &&
+ !memcmp(bssid, priv->curr_bss_params.bss_descriptor
+ .mac_address, ETH_ALEN))
+ mwifiex_update_curr_bss_params(priv, bss);
+ cfg80211_put_bss(priv->wdev->wiphy, bss);
+ }
+ } else {
+ dev_dbg(adapter->dev, "missing BSS channel IE\n");
+ }
+
+ return 0;
+}
+
+static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *cmd_node;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+ if (list_empty(&adapter->scan_pending_q)) {
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ adapter->scan_processing = false;
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+
+ /* Need to indicate IOCTL complete */
+ if (adapter->curr_cmd->wait_q_enabled) {
+ adapter->cmd_wait_q.status = 0;
+ if (!priv->scan_request) {
+ dev_dbg(adapter->dev,
+ "complete internal scan\n");
+ mwifiex_complete_cmd(adapter,
+ adapter->curr_cmd);
+ }
+ }
+ if (priv->report_scan_result)
+ priv->report_scan_result = false;
+
+ if (priv->scan_request) {
+ dev_dbg(adapter->dev, "info: notifying scan done\n");
+ cfg80211_scan_done(priv->scan_request, 0);
+ priv->scan_request = NULL;
+ } else {
+ priv->scan_aborting = false;
+ dev_dbg(adapter->dev, "info: scan already aborted\n");
+ }
+ } else {
+ if ((priv->scan_aborting && !priv->scan_request) ||
+ priv->scan_block) {
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+ flags);
+ adapter->scan_delay_cnt = MWIFIEX_MAX_SCAN_DELAY_CNT;
+ mod_timer(&priv->scan_delay_timer, jiffies);
+ dev_dbg(priv->adapter->dev,
+ "info: %s: triggerring scan abort\n", __func__);
+ } else if (!mwifiex_wmm_lists_empty(adapter) &&
+ (priv->scan_request && (priv->scan_request->flags &
+ NL80211_SCAN_FLAG_LOW_PRIORITY))) {
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+ flags);
+ adapter->scan_delay_cnt = 1;
+ mod_timer(&priv->scan_delay_timer, jiffies +
+ msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
+ dev_dbg(priv->adapter->dev,
+ "info: %s: deferring scan\n", __func__);
+ } else {
+ /* Get scan command from scan_pending_q and put to
+ * cmd_pending_q
+ */
+ cmd_node = list_first_entry(&adapter->scan_pending_q,
+ struct cmd_ctrl_node, list);
+ list_del(&cmd_node->list);
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+ flags);
+ mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
+ true);
+ }
+ }
+
+ return;
+}
+
/*
* This function handles the command response of scan.
*
@@ -1600,7 +1851,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
{
int ret = 0;
struct mwifiex_adapter *adapter = priv->adapter;
- struct cmd_ctrl_node *cmd_node;
struct host_cmd_ds_802_11_scan_rsp *scan_rsp;
struct mwifiex_ie_types_data *tlv_data;
struct mwifiex_ie_types_tsf_timestamp *tsf_tlv;
@@ -1609,12 +1859,11 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
u32 bytes_left;
u32 idx;
u32 tlv_buf_size;
- struct mwifiex_chan_freq_power *cfp;
struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv;
struct chan_band_param_set *chan_band;
u8 is_bgscan_resp;
- unsigned long flags;
- struct cfg80211_bss *bss;
+ __le64 fw_tsf = 0;
+ u8 *radio_type;
is_bgscan_resp = (le16_to_cpu(resp->command)
== HostCmd_CMD_802_11_BG_SCAN_QUERY);
@@ -1676,220 +1925,194 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
&chan_band_tlv);
for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) {
- u8 bssid[ETH_ALEN];
- s32 rssi;
- const u8 *ie_buf;
- size_t ie_len;
- u16 channel = 0;
- __le64 fw_tsf = 0;
- u16 beacon_size = 0;
- u32 curr_bcn_bytes;
- u32 freq;
- u16 beacon_period;
- u16 cap_info_bitmap;
- u8 *current_ptr;
- u64 timestamp;
- struct mwifiex_bcn_param *bcn_param;
- struct mwifiex_bss_priv *bss_priv;
-
- if (bytes_left >= sizeof(beacon_size)) {
- /* Extract & convert beacon size from command buffer */
- memcpy(&beacon_size, bss_info, sizeof(beacon_size));
- bytes_left -= sizeof(beacon_size);
- bss_info += sizeof(beacon_size);
- }
+ /*
+ * If the TSF TLV was appended to the scan results, save this
+ * entry's TSF value in the fw_tsf field. It is the firmware's
+ * TSF value at the time the beacon or probe response was
+ * received.
+ */
+ if (tsf_tlv)
+ memcpy(&fw_tsf, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE],
+ sizeof(fw_tsf));
- if (!beacon_size || beacon_size > bytes_left) {
- bss_info += bytes_left;
- bytes_left = 0;
- ret = -1;
- goto check_next_scan;
+ if (chan_band_tlv) {
+ chan_band = &chan_band_tlv->chan_band_param[idx];
+ radio_type = &chan_band->radio_type;
+ } else {
+ radio_type = NULL;
}
- /* Initialize the current working beacon pointer for this BSS
- * iteration */
- current_ptr = bss_info;
+ ret = mwifiex_parse_single_response_buf(priv, &bss_info,
+ &bytes_left,
+ le64_to_cpu(fw_tsf),
+ radio_type, false, 0);
+ if (ret)
+ goto check_next_scan;
+ }
- /* Advance the return beacon pointer past the current beacon */
- bss_info += beacon_size;
- bytes_left -= beacon_size;
+check_next_scan:
+ mwifiex_check_next_scan_command(priv);
+ return ret;
+}
- curr_bcn_bytes = beacon_size;
+/*
+ * This function prepares an extended scan command to be sent to the firmware
+ *
+ * This uses the scan command configuration sent to the command processing
+ * module in command preparation stage to configure a extended scan command
+ * structure to send to firmware.
+ */
+int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ void *data_buf)
+{
+ struct host_cmd_ds_802_11_scan_ext *ext_scan = &cmd->params.ext_scan;
+ struct mwifiex_scan_cmd_config *scan_cfg = data_buf;
- /*
- * First 5 fields are bssid, RSSI, time stamp, beacon interval,
- * and capability information
- */
- if (curr_bcn_bytes < sizeof(struct mwifiex_bcn_param)) {
- dev_err(adapter->dev,
- "InterpretIE: not enough bytes left\n");
- continue;
- }
- bcn_param = (struct mwifiex_bcn_param *)current_ptr;
- current_ptr += sizeof(*bcn_param);
- curr_bcn_bytes -= sizeof(*bcn_param);
+ memcpy(ext_scan->tlv_buffer, scan_cfg->tlv_buf, scan_cfg->tlv_buf_len);
- memcpy(bssid, bcn_param->bssid, ETH_ALEN);
+ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SCAN_EXT);
- rssi = (s32) bcn_param->rssi;
- rssi = (-rssi) * 100; /* Convert dBm to mBm */
- dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%d\n", rssi);
+ /* Size is equal to the sizeof(fixed portions) + the TLV len + header */
+ cmd->size = cpu_to_le16((u16)(sizeof(ext_scan->reserved)
+ + scan_cfg->tlv_buf_len + S_DS_GEN));
- timestamp = le64_to_cpu(bcn_param->timestamp);
- beacon_period = le16_to_cpu(bcn_param->beacon_period);
+ return 0;
+}
- cap_info_bitmap = le16_to_cpu(bcn_param->cap_info_bitmap);
- dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n",
- cap_info_bitmap);
+/* This function handles the command response of extended scan */
+int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv)
+{
+ dev_dbg(priv->adapter->dev, "info: EXT scan returns successfully\n");
+ return 0;
+}
- /* Rest of the current buffer are IE's */
- ie_buf = current_ptr;
- ie_len = curr_bcn_bytes;
- dev_dbg(adapter->dev,
- "info: InterpretIE: IELength for this AP = %d\n",
- curr_bcn_bytes);
+/* This function This function handles the event extended scan report. It
+ * parses extended scan results and informs to cfg80211 stack.
+ */
+int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv,
+ void *buf)
+{
+ int ret = 0;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ u8 *bss_info;
+ u32 bytes_left, bytes_left_for_tlv, idx;
+ u16 type, len;
+ struct mwifiex_ie_types_data *tlv;
+ struct mwifiex_ie_types_bss_scan_rsp *scan_rsp_tlv;
+ struct mwifiex_ie_types_bss_scan_info *scan_info_tlv;
+ u8 *radio_type;
+ u64 fw_tsf = 0;
+ s32 rssi = 0;
+ struct mwifiex_event_scan_result *event_scan = buf;
+ u8 num_of_set = event_scan->num_of_set;
+ u8 *scan_resp = buf + sizeof(struct mwifiex_event_scan_result);
+ u16 scan_resp_size = le16_to_cpu(event_scan->buf_size);
+
+ if (num_of_set > MWIFIEX_MAX_AP) {
+ dev_err(adapter->dev,
+ "EXT_SCAN: Invalid number of AP returned (%d)!!\n",
+ num_of_set);
+ ret = -1;
+ goto check_next_scan;
+ }
- while (curr_bcn_bytes >= sizeof(struct ieee_types_header)) {
- u8 element_id, element_len;
+ bytes_left = scan_resp_size;
+ dev_dbg(adapter->dev,
+ "EXT_SCAN: size %d, returned %d APs...",
+ scan_resp_size, num_of_set);
- element_id = *current_ptr;
- element_len = *(current_ptr + 1);
- if (curr_bcn_bytes < element_len +
- sizeof(struct ieee_types_header)) {
- dev_err(priv->adapter->dev,
- "%s: bytes left < IE length\n",
- __func__);
- goto check_next_scan;
- }
- if (element_id == WLAN_EID_DS_PARAMS) {
- channel = *(current_ptr + sizeof(struct ieee_types_header));
- break;
- }
+ tlv = (struct mwifiex_ie_types_data *)scan_resp;
- current_ptr += element_len +
- sizeof(struct ieee_types_header);
- curr_bcn_bytes -= element_len +
- sizeof(struct ieee_types_header);
+ for (idx = 0; idx < num_of_set && bytes_left; idx++) {
+ type = le16_to_cpu(tlv->header.type);
+ len = le16_to_cpu(tlv->header.len);
+ if (bytes_left < sizeof(struct mwifiex_ie_types_header) + len) {
+ dev_err(adapter->dev, "EXT_SCAN: Error bytes left < TLV length\n");
+ break;
}
+ scan_rsp_tlv = NULL;
+ scan_info_tlv = NULL;
+ bytes_left_for_tlv = bytes_left;
- /*
- * If the TSF TLV was appended to the scan results, save this
- * entry's TSF value in the fw_tsf field. It is the firmware's
- * TSF value at the time the beacon or probe response was
- * received.
+ /* BSS response TLV with beacon or probe response buffer
+ * at the initial position of each descriptor
*/
- if (tsf_tlv)
- memcpy(&fw_tsf, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE],
- sizeof(fw_tsf));
-
- if (channel) {
- struct ieee80211_channel *chan;
- u8 band;
+ if (type != TLV_TYPE_BSS_SCAN_RSP)
+ break;
- /* Skip entry if on csa closed channel */
- if (channel == priv->csa_chan) {
- dev_dbg(adapter->dev,
- "Dropping entry on csa closed channel\n");
+ bss_info = (u8 *)tlv;
+ scan_rsp_tlv = (struct mwifiex_ie_types_bss_scan_rsp *)tlv;
+ tlv = (struct mwifiex_ie_types_data *)(tlv->data + len);
+ bytes_left_for_tlv -=
+ (len + sizeof(struct mwifiex_ie_types_header));
+
+ while (bytes_left_for_tlv >=
+ sizeof(struct mwifiex_ie_types_header) &&
+ le16_to_cpu(tlv->header.type) != TLV_TYPE_BSS_SCAN_RSP) {
+ type = le16_to_cpu(tlv->header.type);
+ len = le16_to_cpu(tlv->header.len);
+ if (bytes_left_for_tlv <
+ sizeof(struct mwifiex_ie_types_header) + len) {
+ dev_err(adapter->dev,
+ "EXT_SCAN: Error in processing TLV, bytes left < TLV length\n");
+ scan_rsp_tlv = NULL;
+ bytes_left_for_tlv = 0;
continue;
}
-
- band = BAND_G;
- if (chan_band_tlv) {
- chan_band =
- &chan_band_tlv->chan_band_param[idx];
- band = mwifiex_radio_type_to_band(
- chan_band->radio_type
- & (BIT(0) | BIT(1)));
- }
-
- cfp = mwifiex_get_cfp(priv, band, channel, 0);
-
- freq = cfp ? cfp->freq : 0;
-
- chan = ieee80211_get_channel(priv->wdev->wiphy, freq);
-
- if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
- bss = cfg80211_inform_bss(priv->wdev->wiphy,
- chan, bssid, timestamp,
- cap_info_bitmap, beacon_period,
- ie_buf, ie_len, rssi, GFP_KERNEL);
- bss_priv = (struct mwifiex_bss_priv *)bss->priv;
- bss_priv->band = band;
- bss_priv->fw_tsf = le64_to_cpu(fw_tsf);
- if (priv->media_connected &&
- !memcmp(bssid,
- priv->curr_bss_params.bss_descriptor
- .mac_address, ETH_ALEN))
- mwifiex_update_curr_bss_params(priv,
- bss);
- cfg80211_put_bss(priv->wdev->wiphy, bss);
+ switch (type) {
+ case TLV_TYPE_BSS_SCAN_INFO:
+ scan_info_tlv =
+ (struct mwifiex_ie_types_bss_scan_info *)tlv;
+ if (len !=
+ sizeof(struct mwifiex_ie_types_bss_scan_info) -
+ sizeof(struct mwifiex_ie_types_header)) {
+ bytes_left_for_tlv = 0;
+ continue;
+ }
+ break;
+ default:
+ break;
}
- } else {
- dev_dbg(adapter->dev, "missing BSS channel IE\n");
+ tlv = (struct mwifiex_ie_types_data *)(tlv->data + len);
+ bytes_left -=
+ (len + sizeof(struct mwifiex_ie_types_header));
+ bytes_left_for_tlv -=
+ (len + sizeof(struct mwifiex_ie_types_header));
}
- }
-check_next_scan:
- spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
- if (list_empty(&adapter->scan_pending_q)) {
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
- adapter->scan_processing = false;
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+ if (!scan_rsp_tlv)
+ break;
- /* Need to indicate IOCTL complete */
- if (adapter->curr_cmd->wait_q_enabled) {
- adapter->cmd_wait_q.status = 0;
- if (!priv->scan_request) {
- dev_dbg(adapter->dev,
- "complete internal scan\n");
- mwifiex_complete_cmd(adapter,
- adapter->curr_cmd);
- }
- }
- if (priv->report_scan_result)
- priv->report_scan_result = false;
+ /* Advance pointer to the beacon buffer length and
+ * update the bytes count so that the function
+ * wlan_interpret_bss_desc_with_ie() can handle the
+ * scan buffer withut any change
+ */
+ bss_info += sizeof(u16);
+ bytes_left -= sizeof(u16);
- if (priv->scan_request) {
- dev_dbg(adapter->dev, "info: notifying scan done\n");
- cfg80211_scan_done(priv->scan_request, 0);
- priv->scan_request = NULL;
- } else {
- priv->scan_aborting = false;
- dev_dbg(adapter->dev, "info: scan already aborted\n");
- }
- } else {
- if ((priv->scan_aborting && !priv->scan_request) ||
- priv->scan_block) {
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
- flags);
- adapter->scan_delay_cnt = MWIFIEX_MAX_SCAN_DELAY_CNT;
- mod_timer(&priv->scan_delay_timer, jiffies);
- dev_dbg(priv->adapter->dev,
- "info: %s: triggerring scan abort\n", __func__);
- } else if (!mwifiex_wmm_lists_empty(adapter) &&
- (priv->scan_request && (priv->scan_request->flags &
- NL80211_SCAN_FLAG_LOW_PRIORITY))) {
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
- flags);
- adapter->scan_delay_cnt = 1;
- mod_timer(&priv->scan_delay_timer, jiffies +
- msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
- dev_dbg(priv->adapter->dev,
- "info: %s: deferring scan\n", __func__);
+ if (scan_info_tlv) {
+ rssi = (s32)(s16)(le16_to_cpu(scan_info_tlv->rssi));
+ rssi *= 100; /* Convert dBm to mBm */
+ dev_dbg(adapter->dev,
+ "info: InterpretIE: RSSI=%d\n", rssi);
+ fw_tsf = le64_to_cpu(scan_info_tlv->tsf);
+ radio_type = &scan_info_tlv->radio_type;
} else {
- /* Get scan command from scan_pending_q and put to
- cmd_pending_q */
- cmd_node = list_first_entry(&adapter->scan_pending_q,
- struct cmd_ctrl_node, list);
- list_del(&cmd_node->list);
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
- flags);
- mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
- true);
+ radio_type = NULL;
}
+ ret = mwifiex_parse_single_response_buf(priv, &bss_info,
+ &bytes_left, fw_tsf,
+ radio_type, true, rssi);
+ if (ret)
+ goto check_next_scan;
}
+check_next_scan:
+ if (!event_scan->more_event)
+ mwifiex_check_next_scan_command(priv);
+
return ret;
}
@@ -2101,12 +2324,12 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv)
curr_bss->ht_info_offset);
if (curr_bss->bcn_vht_cap)
- curr_bss->bcn_ht_cap = (void *)(curr_bss->beacon_buf +
- curr_bss->vht_cap_offset);
+ curr_bss->bcn_vht_cap = (void *)(curr_bss->beacon_buf +
+ curr_bss->vht_cap_offset);
if (curr_bss->bcn_vht_oper)
- curr_bss->bcn_ht_oper = (void *)(curr_bss->beacon_buf +
- curr_bss->vht_info_offset);
+ curr_bss->bcn_vht_oper = (void *)(curr_bss->beacon_buf +
+ curr_bss->vht_info_offset);
if (curr_bss->bcn_bss_co_2040)
curr_bss->bcn_bss_co_2040 =
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index b44a31523461..d206f04d4994 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -84,6 +84,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
card->mp_agg_pkt_limit = data->mp_agg_pkt_limit;
card->supports_sdio_new_mode = data->supports_sdio_new_mode;
card->has_control_mask = data->has_control_mask;
+ card->tx_buf_size = data->tx_buf_size;
}
sdio_claim_host(func);
@@ -165,7 +166,6 @@ mwifiex_sdio_remove(struct sdio_func *func)
struct sdio_mmc_card *card;
struct mwifiex_adapter *adapter;
struct mwifiex_private *priv;
- int i;
pr_debug("info: SDIO func num=%d\n", func->num);
@@ -184,11 +184,7 @@ mwifiex_sdio_remove(struct sdio_func *func)
if (adapter->is_suspended)
mwifiex_sdio_resume(adapter->dev);
- for (i = 0; i < adapter->priv_num; i++)
- if ((GET_BSS_ROLE(adapter->priv[i]) ==
- MWIFIEX_BSS_ROLE_STA) &&
- adapter->priv[i]->media_connected)
- mwifiex_deauthenticate(adapter->priv[i], NULL);
+ mwifiex_deauthenticate_all(adapter);
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
mwifiex_disable_auto_ds(priv);
@@ -241,6 +237,7 @@ static int mwifiex_sdio_suspend(struct device *dev)
/* Enable the Host Sleep */
if (!mwifiex_enable_hs(adapter)) {
dev_err(adapter->dev, "cmd: failed to suspend\n");
+ adapter->hs_enabling = false;
return -EFAULT;
}
@@ -249,6 +246,7 @@ static int mwifiex_sdio_suspend(struct device *dev)
/* Indicate device suspended */
adapter->is_suspended = true;
+ adapter->hs_enabling = false;
return ret;
}
@@ -1760,6 +1758,7 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
/* save adapter pointer in card */
card->adapter = adapter;
+ adapter->tx_buf_size = card->tx_buf_size;
sdio_claim_host(func);
diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h
index 532ae0ac4dfb..c71201b2e2a3 100644
--- a/drivers/net/wireless/mwifiex/sdio.h
+++ b/drivers/net/wireless/mwifiex/sdio.h
@@ -233,6 +233,7 @@ struct sdio_mmc_card {
u8 mp_agg_pkt_limit;
bool supports_sdio_new_mode;
bool has_control_mask;
+ u16 tx_buf_size;
u32 mp_rd_bitmap;
u32 mp_wr_bitmap;
@@ -256,6 +257,7 @@ struct mwifiex_sdio_device {
u8 mp_agg_pkt_limit;
bool supports_sdio_new_mode;
bool has_control_mask;
+ u16 tx_buf_size;
};
static const struct mwifiex_sdio_card_reg mwifiex_reg_sd87xx = {
@@ -312,6 +314,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = {
.mp_agg_pkt_limit = 8,
.supports_sdio_new_mode = false,
.has_control_mask = true,
+ .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = {
@@ -321,6 +324,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = {
.mp_agg_pkt_limit = 8,
.supports_sdio_new_mode = false,
.has_control_mask = true,
+ .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = {
@@ -330,6 +334,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = {
.mp_agg_pkt_limit = 8,
.supports_sdio_new_mode = false,
.has_control_mask = true,
+ .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = {
@@ -339,6 +344,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = {
.mp_agg_pkt_limit = 16,
.supports_sdio_new_mode = true,
.has_control_mask = false,
+ .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K,
};
/*
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index 9208a8816b80..e3cac1495cc7 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -185,6 +185,13 @@ static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv,
i++)
rate_scope->ht_mcs_rate_bitmap[i] =
cpu_to_le16(pbitmap_rates[2 + i]);
+ if (priv->adapter->fw_api_ver == MWIFIEX_FW_V15) {
+ for (i = 0;
+ i < ARRAY_SIZE(rate_scope->vht_mcs_rate_bitmap);
+ i++)
+ rate_scope->vht_mcs_rate_bitmap[i] =
+ cpu_to_le16(pbitmap_rates[10 + i]);
+ }
} else {
rate_scope->hr_dsss_rate_bitmap =
cpu_to_le16(priv->bitmap_rates[0]);
@@ -195,6 +202,13 @@ static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv,
i++)
rate_scope->ht_mcs_rate_bitmap[i] =
cpu_to_le16(priv->bitmap_rates[2 + i]);
+ if (priv->adapter->fw_api_ver == MWIFIEX_FW_V15) {
+ for (i = 0;
+ i < ARRAY_SIZE(rate_scope->vht_mcs_rate_bitmap);
+ i++)
+ rate_scope->vht_mcs_rate_bitmap[i] =
+ cpu_to_le16(priv->bitmap_rates[10 + i]);
+ }
}
rate_drop = (struct mwifiex_rate_drop_pattern *) ((u8 *) rate_scope +
@@ -532,8 +546,228 @@ mwifiex_set_keyparamset_wep(struct mwifiex_private *priv,
return 0;
}
+/* This function populates key material v2 command
+ * to set network key for AES & CMAC AES.
+ */
+static int mwifiex_set_aes_key_v2(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ struct mwifiex_ds_encrypt_key *enc_key,
+ struct host_cmd_ds_802_11_key_material_v2 *km)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ u16 size, len = KEY_PARAMS_FIXED_LEN;
+
+ if (enc_key->is_igtk_key) {
+ dev_dbg(adapter->dev, "%s: Set CMAC AES Key\n", __func__);
+ if (enc_key->is_rx_seq_valid)
+ memcpy(km->key_param_set.key_params.cmac_aes.ipn,
+ enc_key->pn, enc_key->pn_len);
+ km->key_param_set.key_info &= cpu_to_le16(~KEY_MCAST);
+ km->key_param_set.key_info |= cpu_to_le16(KEY_IGTK);
+ km->key_param_set.key_type = KEY_TYPE_ID_AES_CMAC;
+ km->key_param_set.key_params.cmac_aes.key_len =
+ cpu_to_le16(enc_key->key_len);
+ memcpy(km->key_param_set.key_params.cmac_aes.key,
+ enc_key->key_material, enc_key->key_len);
+ len += sizeof(struct mwifiex_cmac_aes_param);
+ } else {
+ dev_dbg(adapter->dev, "%s: Set AES Key\n", __func__);
+ if (enc_key->is_rx_seq_valid)
+ memcpy(km->key_param_set.key_params.aes.pn,
+ enc_key->pn, enc_key->pn_len);
+ km->key_param_set.key_type = KEY_TYPE_ID_AES;
+ km->key_param_set.key_params.aes.key_len =
+ cpu_to_le16(enc_key->key_len);
+ memcpy(km->key_param_set.key_params.aes.key,
+ enc_key->key_material, enc_key->key_len);
+ len += sizeof(struct mwifiex_aes_param);
+ }
+
+ km->key_param_set.len = cpu_to_le16(len);
+ size = len + sizeof(struct mwifiex_ie_types_header) +
+ sizeof(km->action) + S_DS_GEN;
+ cmd->size = cpu_to_le16(size);
+
+ return 0;
+}
+
+/* This function prepares command to set/get/reset network key(s).
+ * This function prepares key material command for V2 format.
+ * Preparation includes -
+ * - Setting command ID, action and proper size
+ * - Setting WEP keys, WAPI keys or WPA keys along with required
+ * encryption (TKIP, AES) (as required)
+ * - Ensuring correct endian-ness
+ */
+static int
+mwifiex_cmd_802_11_key_material_v2(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ u16 cmd_action, u32 cmd_oid,
+ struct mwifiex_ds_encrypt_key *enc_key)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ u8 *mac = enc_key->mac_addr;
+ u16 key_info, len = KEY_PARAMS_FIXED_LEN;
+ struct host_cmd_ds_802_11_key_material_v2 *km =
+ &cmd->params.key_material_v2;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
+ km->action = cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ dev_dbg(adapter->dev, "%s: Get key\n", __func__);
+ km->key_param_set.key_idx =
+ enc_key->key_index & KEY_INDEX_MASK;
+ km->key_param_set.type = cpu_to_le16(TLV_TYPE_KEY_PARAM_V2);
+ km->key_param_set.len = cpu_to_le16(KEY_PARAMS_FIXED_LEN);
+ memcpy(km->key_param_set.mac_addr, mac, ETH_ALEN);
+
+ if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
+ key_info = KEY_UNICAST;
+ else
+ key_info = KEY_MCAST;
+
+ if (enc_key->is_igtk_key)
+ key_info |= KEY_IGTK;
+
+ km->key_param_set.key_info = cpu_to_le16(key_info);
+
+ cmd->size = cpu_to_le16(sizeof(struct mwifiex_ie_types_header) +
+ S_DS_GEN + KEY_PARAMS_FIXED_LEN +
+ sizeof(km->action));
+ return 0;
+ }
+
+ memset(&km->key_param_set, 0,
+ sizeof(struct mwifiex_ie_type_key_param_set_v2));
+
+ if (enc_key->key_disable) {
+ dev_dbg(adapter->dev, "%s: Remove key\n", __func__);
+ km->action = cpu_to_le16(HostCmd_ACT_GEN_REMOVE);
+ km->key_param_set.type = cpu_to_le16(TLV_TYPE_KEY_PARAM_V2);
+ km->key_param_set.len = cpu_to_le16(KEY_PARAMS_FIXED_LEN);
+ km->key_param_set.key_idx = enc_key->key_index & KEY_INDEX_MASK;
+ key_info = KEY_MCAST | KEY_UNICAST;
+ km->key_param_set.key_info = cpu_to_le16(key_info);
+ memcpy(km->key_param_set.mac_addr, mac, ETH_ALEN);
+ cmd->size = cpu_to_le16(sizeof(struct mwifiex_ie_types_header) +
+ S_DS_GEN + KEY_PARAMS_FIXED_LEN +
+ sizeof(km->action));
+ return 0;
+ }
+
+ km->action = cpu_to_le16(HostCmd_ACT_GEN_SET);
+ km->key_param_set.key_idx = enc_key->key_index & KEY_INDEX_MASK;
+ km->key_param_set.type = cpu_to_le16(TLV_TYPE_KEY_PARAM_V2);
+ key_info = KEY_ENABLED;
+ memcpy(km->key_param_set.mac_addr, mac, ETH_ALEN);
+
+ if (enc_key->key_len <= WLAN_KEY_LEN_WEP104) {
+ dev_dbg(adapter->dev, "%s: Set WEP Key\n", __func__);
+ len += sizeof(struct mwifiex_wep_param);
+ km->key_param_set.len = cpu_to_le16(len);
+ km->key_param_set.key_type = KEY_TYPE_ID_WEP;
+
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
+ key_info |= KEY_MCAST | KEY_UNICAST;
+ } else {
+ if (enc_key->is_current_wep_key) {
+ key_info |= KEY_MCAST | KEY_UNICAST;
+ if (km->key_param_set.key_idx ==
+ (priv->wep_key_curr_index & KEY_INDEX_MASK))
+ key_info |= KEY_DEFAULT;
+ } else {
+ if (mac) {
+ if (is_broadcast_ether_addr(mac))
+ key_info |= KEY_MCAST;
+ else
+ key_info |= KEY_UNICAST |
+ KEY_DEFAULT;
+ } else {
+ key_info |= KEY_MCAST;
+ }
+ }
+ }
+ km->key_param_set.key_info = cpu_to_le16(key_info);
+
+ km->key_param_set.key_params.wep.key_len =
+ cpu_to_le16(enc_key->key_len);
+ memcpy(km->key_param_set.key_params.wep.key,
+ enc_key->key_material, enc_key->key_len);
+
+ cmd->size = cpu_to_le16(sizeof(struct mwifiex_ie_types_header) +
+ len + sizeof(km->action) + S_DS_GEN);
+ return 0;
+ }
+
+ if (is_broadcast_ether_addr(mac))
+ key_info |= KEY_MCAST | KEY_RX_KEY;
+ else
+ key_info |= KEY_UNICAST | KEY_TX_KEY | KEY_RX_KEY;
+
+ if (enc_key->is_wapi_key) {
+ dev_dbg(adapter->dev, "%s: Set WAPI Key\n", __func__);
+ km->key_param_set.key_type = KEY_TYPE_ID_WAPI;
+ memcpy(km->key_param_set.key_params.wapi.pn, enc_key->pn,
+ PN_LEN);
+ km->key_param_set.key_params.wapi.key_len =
+ cpu_to_le16(enc_key->key_len);
+ memcpy(km->key_param_set.key_params.wapi.key,
+ enc_key->key_material, enc_key->key_len);
+ if (is_broadcast_ether_addr(mac))
+ priv->sec_info.wapi_key_on = true;
+
+ if (!priv->sec_info.wapi_key_on)
+ key_info |= KEY_DEFAULT;
+ km->key_param_set.key_info = cpu_to_le16(key_info);
+
+ len += sizeof(struct mwifiex_wapi_param);
+ km->key_param_set.len = cpu_to_le16(len);
+ cmd->size = cpu_to_le16(sizeof(struct mwifiex_ie_types_header) +
+ len + sizeof(km->action) + S_DS_GEN);
+ return 0;
+ }
+
+ if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
+ key_info |= KEY_DEFAULT;
+ /* Enable unicast bit for WPA-NONE/ADHOC_AES */
+ if (!priv->sec_info.wpa2_enabled &&
+ !is_broadcast_ether_addr(mac))
+ key_info |= KEY_UNICAST;
+ } else {
+ /* Enable default key for WPA/WPA2 */
+ if (!priv->wpa_is_gtk_set)
+ key_info |= KEY_DEFAULT;
+ }
+
+ km->key_param_set.key_info = cpu_to_le16(key_info);
+
+ if (enc_key->key_len == WLAN_KEY_LEN_CCMP)
+ return mwifiex_set_aes_key_v2(priv, cmd, enc_key, km);
+
+ if (enc_key->key_len == WLAN_KEY_LEN_TKIP) {
+ dev_dbg(adapter->dev, "%s: Set TKIP Key\n", __func__);
+ if (enc_key->is_rx_seq_valid)
+ memcpy(km->key_param_set.key_params.tkip.pn,
+ enc_key->pn, enc_key->pn_len);
+ km->key_param_set.key_type = KEY_TYPE_ID_TKIP;
+ km->key_param_set.key_params.tkip.key_len =
+ cpu_to_le16(enc_key->key_len);
+ memcpy(km->key_param_set.key_params.tkip.key,
+ enc_key->key_material, enc_key->key_len);
+
+ len += sizeof(struct mwifiex_tkip_param);
+ km->key_param_set.len = cpu_to_le16(len);
+ cmd->size = cpu_to_le16(sizeof(struct mwifiex_ie_types_header) +
+ len + sizeof(km->action) + S_DS_GEN);
+ }
+
+ return 0;
+}
+
/*
* This function prepares command to set/get/reset network key(s).
+ * This function prepares key material command for V1 format.
*
* Preparation includes -
* - Setting command ID, action and proper size
@@ -542,10 +776,10 @@ mwifiex_set_keyparamset_wep(struct mwifiex_private *priv,
* - Ensuring correct endian-ness
*/
static int
-mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
- struct host_cmd_ds_command *cmd,
- u16 cmd_action, u32 cmd_oid,
- struct mwifiex_ds_encrypt_key *enc_key)
+mwifiex_cmd_802_11_key_material_v1(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ u16 cmd_action, u32 cmd_oid,
+ struct mwifiex_ds_encrypt_key *enc_key)
{
struct host_cmd_ds_802_11_key_material *key_material =
&cmd->params.key_material;
@@ -724,6 +958,24 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
return ret;
}
+/* Wrapper function for setting network key depending upon FW KEY API version */
+static int
+mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ u16 cmd_action, u32 cmd_oid,
+ struct mwifiex_ds_encrypt_key *enc_key)
+{
+ if (priv->adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2)
+ return mwifiex_cmd_802_11_key_material_v2(priv, cmd,
+ cmd_action, cmd_oid,
+ enc_key);
+
+ else
+ return mwifiex_cmd_802_11_key_material_v1(priv, cmd,
+ cmd_action, cmd_oid,
+ enc_key);
+}
+
/*
* This function prepares command to set/get 11d domain information.
*
@@ -1173,9 +1425,9 @@ int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv,
/* property header is 6 bytes, data must fit in cmd buffer */
if (prop && prop->value && prop->length > 6 &&
prop->length <= MWIFIEX_SIZE_OF_CMD_BUFFER - S_DS_GEN) {
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_CFG_DATA,
- HostCmd_ACT_GEN_SET, 0,
- prop);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_CFG_DATA,
+ HostCmd_ACT_GEN_SET, 0,
+ prop, true);
if (ret)
return ret;
}
@@ -1280,6 +1532,127 @@ mwifiex_cmd_coalesce_cfg(struct mwifiex_private *priv,
return 0;
}
+static int
+mwifiex_cmd_tdls_oper(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ void *data_buf)
+{
+ struct host_cmd_ds_tdls_oper *tdls_oper = &cmd->params.tdls_oper;
+ struct mwifiex_ds_tdls_oper *oper = data_buf;
+ struct mwifiex_sta_node *sta_ptr;
+ struct host_cmd_tlv_rates *tlv_rates;
+ struct mwifiex_ie_types_htcap *ht_capab;
+ struct mwifiex_ie_types_qos_info *wmm_qos_info;
+ struct mwifiex_ie_types_extcap *extcap;
+ struct mwifiex_ie_types_vhtcap *vht_capab;
+ struct mwifiex_ie_types_aid *aid;
+ u8 *pos, qos_info;
+ u16 config_len = 0;
+ struct station_parameters *params = priv->sta_params;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_TDLS_OPER);
+ cmd->size = cpu_to_le16(S_DS_GEN);
+ le16_add_cpu(&cmd->size, sizeof(struct host_cmd_ds_tdls_oper));
+
+ tdls_oper->reason = 0;
+ memcpy(tdls_oper->peer_mac, oper->peer_mac, ETH_ALEN);
+ sta_ptr = mwifiex_get_sta_entry(priv, oper->peer_mac);
+
+ pos = (u8 *)tdls_oper + sizeof(struct host_cmd_ds_tdls_oper);
+
+ switch (oper->tdls_action) {
+ case MWIFIEX_TDLS_DISABLE_LINK:
+ tdls_oper->tdls_action = cpu_to_le16(ACT_TDLS_DELETE);
+ break;
+ case MWIFIEX_TDLS_CREATE_LINK:
+ tdls_oper->tdls_action = cpu_to_le16(ACT_TDLS_CREATE);
+ break;
+ case MWIFIEX_TDLS_CONFIG_LINK:
+ tdls_oper->tdls_action = cpu_to_le16(ACT_TDLS_CONFIG);
+
+ if (!params) {
+ dev_err(priv->adapter->dev,
+ "TDLS config params not available for %pM\n",
+ oper->peer_mac);
+ return -ENODATA;
+ }
+
+ *(__le16 *)pos = cpu_to_le16(params->capability);
+ config_len += sizeof(params->capability);
+
+ qos_info = params->uapsd_queues | (params->max_sp << 5);
+ wmm_qos_info = (struct mwifiex_ie_types_qos_info *)(pos +
+ config_len);
+ wmm_qos_info->header.type = cpu_to_le16(WLAN_EID_QOS_CAPA);
+ wmm_qos_info->header.len = cpu_to_le16(sizeof(qos_info));
+ wmm_qos_info->qos_info = qos_info;
+ config_len += sizeof(struct mwifiex_ie_types_qos_info);
+
+ if (params->ht_capa) {
+ ht_capab = (struct mwifiex_ie_types_htcap *)(pos +
+ config_len);
+ ht_capab->header.type =
+ cpu_to_le16(WLAN_EID_HT_CAPABILITY);
+ ht_capab->header.len =
+ cpu_to_le16(sizeof(struct ieee80211_ht_cap));
+ memcpy(&ht_capab->ht_cap, params->ht_capa,
+ sizeof(struct ieee80211_ht_cap));
+ config_len += sizeof(struct mwifiex_ie_types_htcap);
+ }
+
+ if (params->supported_rates && params->supported_rates_len) {
+ tlv_rates = (struct host_cmd_tlv_rates *)(pos +
+ config_len);
+ tlv_rates->header.type =
+ cpu_to_le16(WLAN_EID_SUPP_RATES);
+ tlv_rates->header.len =
+ cpu_to_le16(params->supported_rates_len);
+ memcpy(tlv_rates->rates, params->supported_rates,
+ params->supported_rates_len);
+ config_len += sizeof(struct host_cmd_tlv_rates) +
+ params->supported_rates_len;
+ }
+
+ if (params->ext_capab && params->ext_capab_len) {
+ extcap = (struct mwifiex_ie_types_extcap *)(pos +
+ config_len);
+ extcap->header.type =
+ cpu_to_le16(WLAN_EID_EXT_CAPABILITY);
+ extcap->header.len = cpu_to_le16(params->ext_capab_len);
+ memcpy(extcap->ext_capab, params->ext_capab,
+ params->ext_capab_len);
+ config_len += sizeof(struct mwifiex_ie_types_extcap) +
+ params->ext_capab_len;
+ }
+ if (params->vht_capa) {
+ vht_capab = (struct mwifiex_ie_types_vhtcap *)(pos +
+ config_len);
+ vht_capab->header.type =
+ cpu_to_le16(WLAN_EID_VHT_CAPABILITY);
+ vht_capab->header.len =
+ cpu_to_le16(sizeof(struct ieee80211_vht_cap));
+ memcpy(&vht_capab->vht_cap, params->vht_capa,
+ sizeof(struct ieee80211_vht_cap));
+ config_len += sizeof(struct mwifiex_ie_types_vhtcap);
+ }
+ if (params->aid) {
+ aid = (struct mwifiex_ie_types_aid *)(pos + config_len);
+ aid->header.type = cpu_to_le16(WLAN_EID_AID);
+ aid->header.len = cpu_to_le16(sizeof(params->aid));
+ aid->aid = cpu_to_le16(params->aid);
+ config_len += sizeof(struct mwifiex_ie_types_aid);
+ }
+
+ break;
+ default:
+ dev_err(priv->adapter->dev, "Unknown TDLS operation\n");
+ return -ENOTSUPP;
+ }
+
+ le16_add_cpu(&cmd->size, config_len);
+
+ return 0;
+}
/*
* This function prepares the commands before sending them to the firmware.
*
@@ -1472,6 +1845,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
ret = mwifiex_cmd_ibss_coalescing_status(cmd_ptr, cmd_action,
data_buf);
break;
+ case HostCmd_CMD_802_11_SCAN_EXT:
+ ret = mwifiex_cmd_802_11_scan_ext(priv, cmd_ptr, data_buf);
+ break;
case HostCmd_CMD_MAC_REG_ACCESS:
case HostCmd_CMD_BBP_REG_ACCESS:
case HostCmd_CMD_RF_REG_ACCESS:
@@ -1507,6 +1883,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
ret = mwifiex_cmd_coalesce_cfg(priv, cmd_ptr, cmd_action,
data_buf);
break;
+ case HostCmd_CMD_TDLS_OPER:
+ ret = mwifiex_cmd_tdls_oper(priv, cmd_ptr, data_buf);
+ break;
default:
dev_err(priv->adapter->dev,
"PREP_CMD: unknown cmd- %#x\n", cmd_no);
@@ -1547,15 +1926,16 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
if (first_sta) {
if (priv->adapter->iface_type == MWIFIEX_PCIE) {
- ret = mwifiex_send_cmd_sync(priv,
- HostCmd_CMD_PCIE_DESC_DETAILS,
- HostCmd_ACT_GEN_SET, 0, NULL);
+ ret = mwifiex_send_cmd(priv,
+ HostCmd_CMD_PCIE_DESC_DETAILS,
+ HostCmd_ACT_GEN_SET, 0, NULL,
+ true);
if (ret)
return -1;
}
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_FUNC_INIT,
- HostCmd_ACT_GEN_SET, 0, NULL);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_FUNC_INIT,
+ HostCmd_ACT_GEN_SET, 0, NULL, true);
if (ret)
return -1;
@@ -1573,55 +1953,57 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
}
if (adapter->cal_data) {
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_CFG_DATA,
- HostCmd_ACT_GEN_SET, 0, NULL);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_CFG_DATA,
+ HostCmd_ACT_GEN_SET, 0, NULL,
+ true);
if (ret)
return -1;
}
/* Read MAC address from HW */
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_GET_HW_SPEC,
- HostCmd_ACT_GEN_GET, 0, NULL);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_GET_HW_SPEC,
+ HostCmd_ACT_GEN_GET, 0, NULL, true);
if (ret)
return -1;
/* Reconfigure tx buf size */
- ret = mwifiex_send_cmd_sync(priv,
- HostCmd_CMD_RECONFIGURE_TX_BUFF,
- HostCmd_ACT_GEN_SET, 0,
- &priv->adapter->tx_buf_size);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
+ HostCmd_ACT_GEN_SET, 0,
+ &priv->adapter->tx_buf_size, true);
if (ret)
return -1;
if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
/* Enable IEEE PS by default */
priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
- ret = mwifiex_send_cmd_sync(
- priv, HostCmd_CMD_802_11_PS_MODE_ENH,
- EN_AUTO_PS, BITMAP_STA_PS, NULL);
+ ret = mwifiex_send_cmd(priv,
+ HostCmd_CMD_802_11_PS_MODE_ENH,
+ EN_AUTO_PS, BITMAP_STA_PS, NULL,
+ true);
if (ret)
return -1;
}
}
/* get tx rate */
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG,
- HostCmd_ACT_GEN_GET, 0, NULL);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_GET, 0, NULL, true);
if (ret)
return -1;
priv->data_rate = 0;
/* get tx power */
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_RF_TX_PWR,
- HostCmd_ACT_GEN_GET, 0, NULL);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_RF_TX_PWR,
+ HostCmd_ACT_GEN_GET, 0, NULL, true);
if (ret)
return -1;
if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) {
/* set ibss coalescing_status */
- ret = mwifiex_send_cmd_sync(
- priv, HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
- HostCmd_ACT_GEN_SET, 0, &enable);
+ ret = mwifiex_send_cmd(
+ priv,
+ HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+ HostCmd_ACT_GEN_SET, 0, &enable, true);
if (ret)
return -1;
}
@@ -1629,16 +2011,16 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl));
amsdu_aggr_ctrl.enable = true;
/* Send request to firmware */
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_AMSDU_AGGR_CTRL,
- HostCmd_ACT_GEN_SET, 0,
- &amsdu_aggr_ctrl);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_AMSDU_AGGR_CTRL,
+ HostCmd_ACT_GEN_SET, 0,
+ &amsdu_aggr_ctrl, true);
if (ret)
return -1;
/* MAC Control must be the last command in init_fw */
/* set MAC Control */
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL,
- HostCmd_ACT_GEN_SET, 0,
- &priv->curr_pkt_filter);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0,
+ &priv->curr_pkt_filter, true);
if (ret)
return -1;
@@ -1647,10 +2029,9 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
/* Enable auto deep sleep */
auto_ds.auto_ds = DEEP_SLEEP_ON;
auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME;
- ret = mwifiex_send_cmd_sync(priv,
- HostCmd_CMD_802_11_PS_MODE_ENH,
- EN_AUTO_PS, BITMAP_AUTO_DS,
- &auto_ds);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
+ EN_AUTO_PS, BITMAP_AUTO_DS,
+ &auto_ds, true);
if (ret)
return -1;
}
@@ -1658,9 +2039,9 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
/* Send cmd to FW to enable/disable 11D function */
state_11d = ENABLE_11D;
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
- HostCmd_ACT_GEN_SET, DOT11D_I,
- &state_11d);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, DOT11D_I,
+ &state_11d, true);
if (ret)
dev_err(priv->adapter->dev,
"11D: failed to enable 11D\n");
@@ -1673,8 +2054,8 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
* (Short GI, Channel BW, Green field support etc.) for transmit
*/
tx_cfg.tx_htcap = MWIFIEX_FW_DEF_HTTXCFG;
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_11N_CFG,
- HostCmd_ACT_GEN_SET, 0, &tx_cfg);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_CFG,
+ HostCmd_ACT_GEN_SET, 0, &tx_cfg, true);
ret = -EINPROGRESS;
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 24523e4015cb..bfebb0144df5 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -69,6 +69,7 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
break;
case HostCmd_CMD_802_11_SCAN:
+ case HostCmd_CMD_802_11_SCAN_EXT:
/* Cancel all pending scan command */
spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
list_for_each_entry_safe(cmd_node, tmp_node,
@@ -157,8 +158,8 @@ static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv,
priv->subsc_evt_rssi_state = EVENT_HANDLED;
- mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
- 0, 0, subsc_evt);
+ mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
+ 0, 0, subsc_evt, false);
return 0;
}
@@ -303,6 +304,15 @@ static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv,
priv->bitmap_rates[2 + i] =
le16_to_cpu(rate_scope->
ht_mcs_rate_bitmap[i]);
+
+ if (priv->adapter->fw_api_ver == MWIFIEX_FW_V15) {
+ for (i = 0; i < ARRAY_SIZE(rate_scope->
+ vht_mcs_rate_bitmap);
+ i++)
+ priv->bitmap_rates[10 + i] =
+ le16_to_cpu(rate_scope->
+ vht_mcs_rate_bitmap[i]);
+ }
break;
/* Add RATE_DROP tlv here */
}
@@ -316,9 +326,8 @@ static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv,
if (priv->is_data_rate_auto)
priv->data_rate = 0;
else
- return mwifiex_send_cmd_async(priv,
- HostCmd_CMD_802_11_TX_RATE_QUERY,
- HostCmd_ACT_GEN_GET, 0, NULL);
+ return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,
+ HostCmd_ACT_GEN_GET, 0, NULL, false);
return 0;
}
@@ -561,13 +570,13 @@ static int mwifiex_ret_802_11_ad_hoc_stop(struct mwifiex_private *priv,
}
/*
- * This function handles the command response of set/get key material.
+ * This function handles the command response of set/get v1 key material.
*
* Handling includes updating the driver parameters to reflect the
* changes.
*/
-static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv,
- struct host_cmd_ds_command *resp)
+static int mwifiex_ret_802_11_key_material_v1(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
{
struct host_cmd_ds_802_11_key_material *key =
&resp->params.key_material;
@@ -590,6 +599,51 @@ static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv,
}
/*
+ * This function handles the command response of set/get v2 key material.
+ *
+ * Handling includes updating the driver parameters to reflect the
+ * changes.
+ */
+static int mwifiex_ret_802_11_key_material_v2(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ struct host_cmd_ds_802_11_key_material_v2 *key_v2;
+ __le16 len;
+
+ key_v2 = &resp->params.key_material_v2;
+ if (le16_to_cpu(key_v2->action) == HostCmd_ACT_GEN_SET) {
+ if ((le16_to_cpu(key_v2->key_param_set.key_info) & KEY_MCAST)) {
+ dev_dbg(priv->adapter->dev, "info: key: GTK is set\n");
+ priv->wpa_is_gtk_set = true;
+ priv->scan_block = false;
+ }
+ }
+
+ if (key_v2->key_param_set.key_type != KEY_TYPE_ID_AES)
+ return 0;
+
+ memset(priv->aes_key_v2.key_param_set.key_params.aes.key, 0,
+ WLAN_KEY_LEN_CCMP);
+ priv->aes_key_v2.key_param_set.key_params.aes.key_len =
+ key_v2->key_param_set.key_params.aes.key_len;
+ len = priv->aes_key_v2.key_param_set.key_params.aes.key_len;
+ memcpy(priv->aes_key_v2.key_param_set.key_params.aes.key,
+ key_v2->key_param_set.key_params.aes.key, le16_to_cpu(len));
+
+ return 0;
+}
+
+/* Wrapper function for processing response of key material command */
+static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ if (priv->adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2)
+ return mwifiex_ret_802_11_key_material_v2(priv, resp);
+ else
+ return mwifiex_ret_802_11_key_material_v1(priv, resp);
+}
+
+/*
* This function handles the command response of get 11d domain information.
*/
static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv,
@@ -800,7 +854,60 @@ static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv,
return 0;
}
+static int mwifiex_ret_tdls_oper(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ struct host_cmd_ds_tdls_oper *cmd_tdls_oper = &resp->params.tdls_oper;
+ u16 reason = le16_to_cpu(cmd_tdls_oper->reason);
+ u16 action = le16_to_cpu(cmd_tdls_oper->tdls_action);
+ struct mwifiex_sta_node *node =
+ mwifiex_get_sta_entry(priv, cmd_tdls_oper->peer_mac);
+ switch (action) {
+ case ACT_TDLS_DELETE:
+ if (reason)
+ dev_err(priv->adapter->dev,
+ "TDLS link delete for %pM failed: reason %d\n",
+ cmd_tdls_oper->peer_mac, reason);
+ else
+ dev_dbg(priv->adapter->dev,
+ "TDLS link config for %pM successful\n",
+ cmd_tdls_oper->peer_mac);
+ break;
+ case ACT_TDLS_CREATE:
+ if (reason) {
+ dev_err(priv->adapter->dev,
+ "TDLS link creation for %pM failed: reason %d",
+ cmd_tdls_oper->peer_mac, reason);
+ if (node && reason != TDLS_ERR_LINK_EXISTS)
+ node->tdls_status = TDLS_SETUP_FAILURE;
+ } else {
+ dev_dbg(priv->adapter->dev,
+ "TDLS link creation for %pM successful",
+ cmd_tdls_oper->peer_mac);
+ }
+ break;
+ case ACT_TDLS_CONFIG:
+ if (reason) {
+ dev_err(priv->adapter->dev,
+ "TDLS link config for %pM failed, reason %d\n",
+ cmd_tdls_oper->peer_mac, reason);
+ if (node)
+ node->tdls_status = TDLS_SETUP_FAILURE;
+ } else {
+ dev_dbg(priv->adapter->dev,
+ "TDLS link config for %pM successful\n",
+ cmd_tdls_oper->peer_mac);
+ }
+ break;
+ default:
+ dev_err(priv->adapter->dev,
+ "Unknown TDLS command action respnse %d", action);
+ return -1;
+ }
+
+ return 0;
+}
/*
* This function handles the command response for subscribe event command.
*/
@@ -871,6 +978,10 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
ret = mwifiex_ret_802_11_scan(priv, resp);
adapter->curr_cmd->wait_q_enabled = false;
break;
+ case HostCmd_CMD_802_11_SCAN_EXT:
+ ret = mwifiex_ret_802_11_scan_ext(priv);
+ adapter->curr_cmd->wait_q_enabled = false;
+ break;
case HostCmd_CMD_802_11_BG_SCAN_QUERY:
ret = mwifiex_ret_802_11_scan(priv, resp);
dev_dbg(adapter->dev,
@@ -999,6 +1110,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
break;
case HostCmd_CMD_COALESCE_CFG:
break;
+ case HostCmd_CMD_TDLS_OPER:
+ ret = mwifiex_ret_tdls_oper(priv, resp);
+ break;
default:
dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
resp->command);
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
index 8c351f71f72f..368450cc56c7 100644
--- a/drivers/net/wireless/mwifiex/sta_event.c
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -54,6 +54,10 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)
priv->scan_block = false;
+ if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
+ ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info))
+ mwifiex_disable_all_tdls_links(priv);
+
/* Free Tx and Rx packets, report disconnect to upper layer */
mwifiex_clean_txrx(priv);
@@ -112,7 +116,7 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)
adapter->tx_lock_flag = false;
adapter->pps_uapsd_mode = false;
- if (adapter->num_cmd_timeout && adapter->curr_cmd)
+ if (adapter->is_cmd_timedout && adapter->curr_cmd)
return;
priv->media_connected = false;
dev_dbg(adapter->dev,
@@ -289,9 +293,8 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
case EVENT_HS_ACT_REQ:
dev_dbg(adapter->dev, "event: HS_ACT_REQ\n");
- ret = mwifiex_send_cmd_async(priv,
- HostCmd_CMD_802_11_HS_CFG_ENH,
- 0, 0, NULL);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_HS_CFG_ENH,
+ 0, 0, NULL, false);
break;
case EVENT_MIC_ERR_UNICAST:
@@ -322,27 +325,34 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
case EVENT_BG_SCAN_REPORT:
dev_dbg(adapter->dev, "event: BGS_REPORT\n");
- ret = mwifiex_send_cmd_async(priv,
- HostCmd_CMD_802_11_BG_SCAN_QUERY,
- HostCmd_ACT_GEN_GET, 0, NULL);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_BG_SCAN_QUERY,
+ HostCmd_ACT_GEN_GET, 0, NULL, false);
break;
case EVENT_PORT_RELEASE:
dev_dbg(adapter->dev, "event: PORT RELEASE\n");
break;
+ case EVENT_EXT_SCAN_REPORT:
+ dev_dbg(adapter->dev, "event: EXT_SCAN Report\n");
+ if (adapter->ext_scan)
+ ret = mwifiex_handle_event_ext_scan_report(priv,
+ adapter->event_skb->data);
+
+ break;
+
case EVENT_WMM_STATUS_CHANGE:
dev_dbg(adapter->dev, "event: WMM status changed\n");
- ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_WMM_GET_STATUS,
- 0, 0, NULL);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_WMM_GET_STATUS,
+ 0, 0, NULL, false);
break;
case EVENT_RSSI_LOW:
cfg80211_cqm_rssi_notify(priv->netdev,
NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
GFP_KERNEL);
- mwifiex_send_cmd_async(priv, HostCmd_CMD_RSSI_INFO,
- HostCmd_ACT_GEN_GET, 0, NULL);
+ mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
+ HostCmd_ACT_GEN_GET, 0, NULL, false);
priv->subsc_evt_rssi_state = RSSI_LOW_RECVD;
dev_dbg(adapter->dev, "event: Beacon RSSI_LOW\n");
break;
@@ -356,8 +366,8 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
cfg80211_cqm_rssi_notify(priv->netdev,
NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
GFP_KERNEL);
- mwifiex_send_cmd_async(priv, HostCmd_CMD_RSSI_INFO,
- HostCmd_ACT_GEN_GET, 0, NULL);
+ mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
+ HostCmd_ACT_GEN_GET, 0, NULL, false);
priv->subsc_evt_rssi_state = RSSI_HIGH_RECVD;
dev_dbg(adapter->dev, "event: Beacon RSSI_HIGH\n");
break;
@@ -384,15 +394,15 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_IBSS_COALESCED:
dev_dbg(adapter->dev, "event: IBSS_COALESCED\n");
- ret = mwifiex_send_cmd_async(priv,
+ ret = mwifiex_send_cmd(priv,
HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
- HostCmd_ACT_GEN_GET, 0, NULL);
+ HostCmd_ACT_GEN_GET, 0, NULL, false);
break;
case EVENT_ADDBA:
dev_dbg(adapter->dev, "event: ADDBA Request\n");
- mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_RSP,
- HostCmd_ACT_GEN_SET, 0,
- adapter->event_body);
+ mwifiex_send_cmd(priv, HostCmd_CMD_11N_ADDBA_RSP,
+ HostCmd_ACT_GEN_SET, 0,
+ adapter->event_body, false);
break;
case EVENT_DELBA:
dev_dbg(adapter->dev, "event: DELBA Request\n");
@@ -443,10 +453,10 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
priv->csa_expire_time =
jiffies + msecs_to_jiffies(DFS_CHAN_MOVE_TIME);
priv->csa_chan = priv->curr_bss_params.bss_descriptor.channel;
- ret = mwifiex_send_cmd_async(priv,
- HostCmd_CMD_802_11_DEAUTHENTICATE,
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_DEAUTHENTICATE,
HostCmd_ACT_GEN_SET, 0,
- priv->curr_bss_params.bss_descriptor.mac_address);
+ priv->curr_bss_params.bss_descriptor.mac_address,
+ false);
break;
default:
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index c5cb2ed19ec2..894270611f2c 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -64,6 +64,7 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter,
*(cmd_queued->condition));
if (status) {
dev_err(adapter->dev, "cmd_wait_q terminated: %d\n", status);
+ mwifiex_cancel_all_pending_cmd(adapter);
return status;
}
@@ -108,19 +109,19 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
"info: Set multicast list=%d\n",
mcast_list->num_multicast_addr);
/* Send multicast addresses to firmware */
- ret = mwifiex_send_cmd_async(priv,
- HostCmd_CMD_MAC_MULTICAST_ADR,
- HostCmd_ACT_GEN_SET, 0,
- mcast_list);
+ ret = mwifiex_send_cmd(priv,
+ HostCmd_CMD_MAC_MULTICAST_ADR,
+ HostCmd_ACT_GEN_SET, 0,
+ mcast_list, false);
}
}
dev_dbg(priv->adapter->dev,
"info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n",
old_pkt_filter, priv->curr_pkt_filter);
if (old_pkt_filter != priv->curr_pkt_filter) {
- ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
- HostCmd_ACT_GEN_SET,
- 0, &priv->curr_pkt_filter);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET,
+ 0, &priv->curr_pkt_filter, false);
}
return ret;
@@ -237,8 +238,8 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv,
rcu_read_unlock();
- if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
- HostCmd_ACT_GEN_SET, 0, NULL)) {
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
+ HostCmd_ACT_GEN_SET, 0, NULL, false)) {
wiphy_err(priv->adapter->wiphy,
"11D: setting domain info in FW\n");
return -1;
@@ -290,7 +291,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
if (mwifiex_band_to_radio_type(bss_desc->bss_band) ==
HostCmd_SCAN_RADIO_TYPE_BG)
- config_bands = BAND_B | BAND_G | BAND_GN | BAND_GAC;
+ config_bands = BAND_B | BAND_G | BAND_GN;
else
config_bands = BAND_A | BAND_AN | BAND_AAC;
@@ -429,16 +430,13 @@ static int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
status = -1;
break;
}
- if (cmd_type == MWIFIEX_SYNC_CMD)
- status = mwifiex_send_cmd_sync(priv,
- HostCmd_CMD_802_11_HS_CFG_ENH,
- HostCmd_ACT_GEN_SET, 0,
- &adapter->hs_cfg);
- else
- status = mwifiex_send_cmd_async(priv,
- HostCmd_CMD_802_11_HS_CFG_ENH,
- HostCmd_ACT_GEN_SET, 0,
- &adapter->hs_cfg);
+
+ status = mwifiex_send_cmd(priv,
+ HostCmd_CMD_802_11_HS_CFG_ENH,
+ HostCmd_ACT_GEN_SET, 0,
+ &adapter->hs_cfg,
+ cmd_type == MWIFIEX_SYNC_CMD);
+
if (hs_cfg->conditions == HS_CFG_CANCEL)
/* Restore previous condition */
adapter->hs_cfg.conditions =
@@ -511,6 +509,9 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
memset(&hscfg, 0, sizeof(struct mwifiex_ds_hs_cfg));
hscfg.is_invoke_hostcmd = true;
+ adapter->hs_enabling = true;
+ mwifiex_cancel_all_pending_cmd(adapter);
+
if (mwifiex_set_hs_params(mwifiex_get_priv(adapter,
MWIFIEX_BSS_ROLE_STA),
HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD,
@@ -519,8 +520,9 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
return false;
}
- if (wait_event_interruptible(adapter->hs_activate_wait_q,
- adapter->hs_activate_wait_q_woken)) {
+ if (wait_event_interruptible_timeout(adapter->hs_activate_wait_q,
+ adapter->hs_activate_wait_q_woken,
+ (10 * HZ)) <= 0) {
dev_err(adapter->dev, "hs_activate_wait_q terminated\n");
return false;
}
@@ -586,8 +588,8 @@ int mwifiex_disable_auto_ds(struct mwifiex_private *priv)
auto_ds.auto_ds = DEEP_SLEEP_OFF;
- return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
- DIS_AUTO_PS, BITMAP_AUTO_DS, &auto_ds);
+ return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
+ DIS_AUTO_PS, BITMAP_AUTO_DS, &auto_ds, true);
}
EXPORT_SYMBOL_GPL(mwifiex_disable_auto_ds);
@@ -601,8 +603,8 @@ int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, u32 *rate)
{
int ret;
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,
- HostCmd_ACT_GEN_GET, 0, NULL);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,
+ HostCmd_ACT_GEN_GET, 0, NULL, true);
if (!ret) {
if (priv->is_data_rate_auto)
@@ -698,8 +700,8 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv,
pg->power_max = (s8) dbm;
pg->ht_bandwidth = HT_BW_40;
}
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TXPWR_CFG,
- HostCmd_ACT_GEN_SET, 0, buf);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_TXPWR_CFG,
+ HostCmd_ACT_GEN_SET, 0, buf, true);
kfree(buf);
return ret;
@@ -722,12 +724,11 @@ int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode)
else
adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS;
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
- sub_cmd, BITMAP_STA_PS, NULL);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
+ sub_cmd, BITMAP_STA_PS, NULL, true);
if ((!ret) && (sub_cmd == DIS_AUTO_PS))
- ret = mwifiex_send_cmd_async(priv,
- HostCmd_CMD_802_11_PS_MODE_ENH,
- GET_PS, 0, NULL);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
+ GET_PS, 0, NULL, false);
return ret;
}
@@ -851,9 +852,9 @@ static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_private *priv,
struct mwifiex_ds_encrypt_key *encrypt_key)
{
- return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
- HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
- encrypt_key);
+ return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
+ encrypt_key, true);
}
/*
@@ -865,6 +866,7 @@ static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_private *priv,
static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
struct mwifiex_ds_encrypt_key *encrypt_key)
{
+ struct mwifiex_adapter *adapter = priv->adapter;
int ret;
struct mwifiex_wep_key *wep_key;
int index;
@@ -879,10 +881,17 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
/* Copy the required key as the current key */
wep_key = &priv->wep_key[index];
if (!wep_key->key_length) {
- dev_err(priv->adapter->dev,
+ dev_err(adapter->dev,
"key not set, so cannot enable it\n");
return -1;
}
+
+ if (adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2) {
+ memcpy(encrypt_key->key_material,
+ wep_key->key_material, wep_key->key_length);
+ encrypt_key->key_len = wep_key->key_length;
+ }
+
priv->wep_key_curr_index = (u16) index;
priv->sec_info.wep_enabled = 1;
} else {
@@ -897,21 +906,32 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
priv->sec_info.wep_enabled = 1;
}
if (wep_key->key_length) {
+ void *enc_key;
+
+ if (encrypt_key->key_disable)
+ memset(&priv->wep_key[index], 0,
+ sizeof(struct mwifiex_wep_key));
+
+ if (adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2)
+ enc_key = encrypt_key;
+ else
+ enc_key = NULL;
+
/* Send request to firmware */
- ret = mwifiex_send_cmd_async(priv,
- HostCmd_CMD_802_11_KEY_MATERIAL,
- HostCmd_ACT_GEN_SET, 0, NULL);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET, 0, enc_key, false);
if (ret)
return ret;
}
+
if (priv->sec_info.wep_enabled)
priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
else
priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL,
- HostCmd_ACT_GEN_SET, 0,
- &priv->curr_pkt_filter);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0,
+ &priv->curr_pkt_filter, true);
return ret;
}
@@ -946,10 +966,9 @@ static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv,
*/
/* Send the key as PTK to firmware */
encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;
- ret = mwifiex_send_cmd_async(priv,
- HostCmd_CMD_802_11_KEY_MATERIAL,
- HostCmd_ACT_GEN_SET,
- KEY_INFO_ENABLED, encrypt_key);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ KEY_INFO_ENABLED, encrypt_key, false);
if (ret)
return ret;
@@ -973,15 +992,13 @@ static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv,
encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;
if (remove_key)
- ret = mwifiex_send_cmd_sync(priv,
- HostCmd_CMD_802_11_KEY_MATERIAL,
- HostCmd_ACT_GEN_SET,
- !KEY_INFO_ENABLED, encrypt_key);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ !KEY_INFO_ENABLED, encrypt_key, true);
else
- ret = mwifiex_send_cmd_sync(priv,
- HostCmd_CMD_802_11_KEY_MATERIAL,
- HostCmd_ACT_GEN_SET,
- KEY_INFO_ENABLED, encrypt_key);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ KEY_INFO_ENABLED, encrypt_key, true);
return ret;
}
@@ -1044,19 +1061,27 @@ int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp,
memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key));
encrypt_key.key_len = key_len;
+ encrypt_key.key_index = key_index;
if (kp && kp->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
encrypt_key.is_igtk_key = true;
if (!disable) {
- encrypt_key.key_index = key_index;
if (key_len)
memcpy(encrypt_key.key_material, key, key_len);
+ else
+ encrypt_key.is_current_wep_key = true;
+
if (mac_addr)
memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
- if (kp && kp->seq && kp->seq_len)
+ if (kp && kp->seq && kp->seq_len) {
memcpy(encrypt_key.pn, kp->seq, kp->seq_len);
+ encrypt_key.pn_len = kp->seq_len;
+ encrypt_key.is_rx_seq_valid = true;
+ }
} else {
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP)
+ return 0;
encrypt_key.key_disable = true;
if (mac_addr)
memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
@@ -1077,8 +1102,8 @@ mwifiex_get_ver_ext(struct mwifiex_private *priv)
struct mwifiex_ver_ext ver_ext;
memset(&ver_ext, 0, sizeof(struct host_cmd_ds_version_ext));
- if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_VERSION_EXT,
- HostCmd_ACT_GEN_GET, 0, &ver_ext))
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_VERSION_EXT,
+ HostCmd_ACT_GEN_GET, 0, &ver_ext, true))
return -1;
return 0;
@@ -1103,8 +1128,8 @@ mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
ieee80211_frequency_to_channel(chan->center_freq);
roc_cfg.duration = cpu_to_le32(duration);
}
- if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_REMAIN_ON_CHAN,
- action, 0, &roc_cfg)) {
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_REMAIN_ON_CHAN,
+ action, 0, &roc_cfg, true)) {
dev_err(priv->adapter->dev, "failed to remain on channel\n");
return -1;
}
@@ -1136,8 +1161,8 @@ mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role)
break;
}
- mwifiex_send_cmd_sync(priv, HostCmd_CMD_SET_BSS_MODE,
- HostCmd_ACT_GEN_SET, 0, NULL);
+ mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
+ HostCmd_ACT_GEN_SET, 0, NULL, true);
return mwifiex_sta_init_cmd(priv, false);
}
@@ -1152,8 +1177,8 @@ int
mwifiex_get_stats_info(struct mwifiex_private *priv,
struct mwifiex_ds_get_stats *log)
{
- return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG,
- HostCmd_ACT_GEN_GET, 0, log);
+ return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_GET_LOG,
+ HostCmd_ACT_GEN_GET, 0, log, true);
}
/*
@@ -1195,8 +1220,7 @@ static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv,
return -1;
}
- return mwifiex_send_cmd_sync(priv, cmd_no, action, 0, reg_rw);
-
+ return mwifiex_send_cmd(priv, cmd_no, action, 0, reg_rw, true);
}
/*
@@ -1261,8 +1285,8 @@ mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes,
rd_eeprom.byte_count = cpu_to_le16((u16) bytes);
/* Send request to firmware */
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_EEPROM_ACCESS,
- HostCmd_ACT_GEN_GET, 0, &rd_eeprom);
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_EEPROM_ACCESS,
+ HostCmd_ACT_GEN_GET, 0, &rd_eeprom, true);
if (!ret)
memcpy(value, rd_eeprom.value, MAX_EEPROM_DATA);
@@ -1391,7 +1415,7 @@ static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv,
* with requisite parameters and calls the IOCTL handler.
*/
int
-mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len)
+mwifiex_set_gen_ie(struct mwifiex_private *priv, const u8 *ie, int ie_len)
{
struct mwifiex_ds_misc_gen_ie gen_ie;
diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c
index 4651d676df38..ed26387eccf5 100644
--- a/drivers/net/wireless/mwifiex/sta_rx.c
+++ b/drivers/net/wireless/mwifiex/sta_rx.c
@@ -88,11 +88,14 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv,
struct rxpd *local_rx_pd;
int hdr_chop;
struct ethhdr *eth;
+ u16 rx_pkt_off, rx_pkt_len;
+ u8 *offset;
local_rx_pd = (struct rxpd *) (skb->data);
- rx_pkt_hdr = (void *)local_rx_pd +
- le16_to_cpu(local_rx_pd->rx_pkt_offset);
+ rx_pkt_off = le16_to_cpu(local_rx_pd->rx_pkt_offset);
+ rx_pkt_len = le16_to_cpu(local_rx_pd->rx_pkt_length);
+ rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_off;
if ((!memcmp(&rx_pkt_hdr->rfc1042_hdr, bridge_tunnel_header,
sizeof(bridge_tunnel_header))) ||
@@ -142,6 +145,12 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv,
return 0;
}
+ if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
+ ntohs(rx_pkt_hdr->eth803_hdr.h_proto) == ETH_P_TDLS) {
+ offset = (u8 *)local_rx_pd + rx_pkt_off;
+ mwifiex_process_tdls_action_frame(priv, offset, rx_pkt_len);
+ }
+
priv->rxpd_rate = local_rx_pd->rx_rate;
priv->rxpd_htinfo = local_rx_pd->ht_info;
@@ -192,26 +201,7 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_private *priv,
return ret;
}
- if (rx_pkt_type == PKT_TYPE_AMSDU) {
- struct sk_buff_head list;
- struct sk_buff *rx_skb;
-
- __skb_queue_head_init(&list);
-
- skb_pull(skb, rx_pkt_offset);
- skb_trim(skb, rx_pkt_length);
-
- ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
- priv->wdev->iftype, 0, false);
-
- while (!skb_queue_empty(&list)) {
- rx_skb = __skb_dequeue(&list);
- ret = mwifiex_recv_packet(priv, rx_skb);
- if (ret == -1)
- dev_err(adapter->dev, "Rx of A-MSDU failed");
- }
- return 0;
- } else if (rx_pkt_type == PKT_TYPE_MGMT) {
+ if (rx_pkt_type == PKT_TYPE_MGMT) {
ret = mwifiex_process_mgmt_packet(priv, skb);
if (ret)
dev_err(adapter->dev, "Rx of mgmt packet failed");
diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c
index 354d64c9606f..1236a5de7bca 100644
--- a/drivers/net/wireless/mwifiex/sta_tx.c
+++ b/drivers/net/wireless/mwifiex/sta_tx.c
@@ -95,6 +95,9 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
}
}
+ if (tx_info->flags & MWIFIEX_BUF_FLAG_TDLS_PKT)
+ local_tx_pd->flags |= MWIFIEX_TXPD_FLAGS_TDLS_PACKET;
+
/* Offset of actual data */
pkt_offset = sizeof(struct txpd) + pad;
if (pkt_type == PKT_TYPE_MGMT) {
diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c
new file mode 100644
index 000000000000..97662a1ba58c
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/tdls.c
@@ -0,0 +1,1044 @@
+/* Marvell Wireless LAN device driver: TDLS handling
+ *
+ * Copyright (C) 2014, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available on the worldwide web at
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+#include "11n_rxreorder.h"
+#include "11ac.h"
+
+#define TDLS_REQ_FIX_LEN 6
+#define TDLS_RESP_FIX_LEN 8
+#define TDLS_CONFIRM_FIX_LEN 6
+
+static void
+mwifiex_restore_tdls_packets(struct mwifiex_private *priv, u8 *mac, u8 status)
+{
+ struct mwifiex_ra_list_tbl *ra_list;
+ struct list_head *tid_list;
+ struct sk_buff *skb, *tmp;
+ struct mwifiex_txinfo *tx_info;
+ unsigned long flags;
+ u32 tid;
+ u8 tid_down;
+
+ dev_dbg(priv->adapter->dev, "%s: %pM\n", __func__, mac);
+ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
+
+ skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) {
+ if (!ether_addr_equal(mac, skb->data))
+ continue;
+
+ __skb_unlink(skb, &priv->tdls_txq);
+ tx_info = MWIFIEX_SKB_TXCB(skb);
+ tid = skb->priority;
+ tid_down = mwifiex_wmm_downgrade_tid(priv, tid);
+
+ if (status == TDLS_SETUP_COMPLETE) {
+ ra_list = mwifiex_wmm_get_queue_raptr(priv, tid, mac);
+ ra_list->tdls_link = true;
+ tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT;
+ } else {
+ tid_list = &priv->wmm.tid_tbl_ptr[tid_down].ra_list;
+ if (!list_empty(tid_list))
+ ra_list = list_first_entry(tid_list,
+ struct mwifiex_ra_list_tbl, list);
+ else
+ ra_list = NULL;
+ tx_info->flags &= ~MWIFIEX_BUF_FLAG_TDLS_PKT;
+ }
+
+ if (!ra_list) {
+ mwifiex_write_data_complete(priv->adapter, skb, 0, -1);
+ continue;
+ }
+
+ skb_queue_tail(&ra_list->skb_head, skb);
+
+ ra_list->ba_pkt_count++;
+ ra_list->total_pkt_count++;
+
+ if (atomic_read(&priv->wmm.highest_queued_prio) <
+ tos_to_tid_inv[tid_down])
+ atomic_set(&priv->wmm.highest_queued_prio,
+ tos_to_tid_inv[tid_down]);
+
+ atomic_inc(&priv->wmm.tx_pkts_queued);
+ }
+
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+ return;
+}
+
+static void mwifiex_hold_tdls_packets(struct mwifiex_private *priv, u8 *mac)
+{
+ struct mwifiex_ra_list_tbl *ra_list;
+ struct list_head *ra_list_head;
+ struct sk_buff *skb, *tmp;
+ unsigned long flags;
+ int i;
+
+ dev_dbg(priv->adapter->dev, "%s: %pM\n", __func__, mac);
+ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
+
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ if (!list_empty(&priv->wmm.tid_tbl_ptr[i].ra_list)) {
+ ra_list_head = &priv->wmm.tid_tbl_ptr[i].ra_list;
+ list_for_each_entry(ra_list, ra_list_head, list) {
+ skb_queue_walk_safe(&ra_list->skb_head, skb,
+ tmp) {
+ if (!ether_addr_equal(mac, skb->data))
+ continue;
+ __skb_unlink(skb, &ra_list->skb_head);
+ atomic_dec(&priv->wmm.tx_pkts_queued);
+ ra_list->total_pkt_count--;
+ skb_queue_tail(&priv->tdls_txq, skb);
+ }
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+ return;
+}
+
+/* This function appends rate TLV to scan config command. */
+static int
+mwifiex_tdls_append_rates_ie(struct mwifiex_private *priv,
+ struct sk_buff *skb)
+{
+ u8 rates[MWIFIEX_SUPPORTED_RATES], *pos;
+ u16 rates_size, supp_rates_size, ext_rates_size;
+
+ memset(rates, 0, sizeof(rates));
+ rates_size = mwifiex_get_supported_rates(priv, rates);
+
+ supp_rates_size = min_t(u16, rates_size, MWIFIEX_TDLS_SUPPORTED_RATES);
+
+ if (skb_tailroom(skb) < rates_size + 4) {
+ dev_err(priv->adapter->dev,
+ "Insuffient space while adding rates\n");
+ return -ENOMEM;
+ }
+
+ pos = skb_put(skb, supp_rates_size + 2);
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = supp_rates_size;
+ memcpy(pos, rates, supp_rates_size);
+
+ if (rates_size > MWIFIEX_TDLS_SUPPORTED_RATES) {
+ ext_rates_size = rates_size - MWIFIEX_TDLS_SUPPORTED_RATES;
+ pos = skb_put(skb, ext_rates_size + 2);
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
+ *pos++ = ext_rates_size;
+ memcpy(pos, rates + MWIFIEX_TDLS_SUPPORTED_RATES,
+ ext_rates_size);
+ }
+
+ return 0;
+}
+
+static void mwifiex_tdls_add_aid(struct mwifiex_private *priv,
+ struct sk_buff *skb)
+{
+ struct ieee_types_assoc_rsp *assoc_rsp;
+ u8 *pos;
+
+ assoc_rsp = (struct ieee_types_assoc_rsp *)&priv->assoc_rsp_buf;
+ pos = (void *)skb_put(skb, 4);
+ *pos++ = WLAN_EID_AID;
+ *pos++ = 2;
+ *pos++ = le16_to_cpu(assoc_rsp->a_id);
+
+ return;
+}
+
+static int mwifiex_tdls_add_vht_capab(struct mwifiex_private *priv,
+ struct sk_buff *skb)
+{
+ struct ieee80211_vht_cap vht_cap;
+ u8 *pos;
+
+ pos = (void *)skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2);
+ *pos++ = WLAN_EID_VHT_CAPABILITY;
+ *pos++ = sizeof(struct ieee80211_vht_cap);
+
+ memset(&vht_cap, 0, sizeof(struct ieee80211_vht_cap));
+
+ mwifiex_fill_vht_cap_tlv(priv, &vht_cap, priv->curr_bss_params.band);
+ memcpy(pos, &vht_cap, sizeof(vht_cap));
+
+ return 0;
+}
+
+static int mwifiex_tdls_add_vht_oper(struct mwifiex_private *priv,
+ u8 *mac, struct sk_buff *skb)
+{
+ struct mwifiex_bssdescriptor *bss_desc;
+ struct ieee80211_vht_operation *vht_oper;
+ struct ieee80211_vht_cap *vht_cap, *ap_vht_cap = NULL;
+ struct mwifiex_sta_node *sta_ptr;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ u8 supp_chwd_set, peer_supp_chwd_set;
+ u8 *pos, ap_supp_chwd_set, chan_bw;
+ u16 mcs_map_user, mcs_map_resp, mcs_map_result;
+ u16 mcs_user, mcs_resp, nss;
+ u32 usr_vht_cap_info;
+
+ bss_desc = &priv->curr_bss_params.bss_descriptor;
+
+ sta_ptr = mwifiex_get_sta_entry(priv, mac);
+ if (unlikely(!sta_ptr)) {
+ dev_warn(adapter->dev, "TDLS peer station not found in list\n");
+ return -1;
+ }
+
+ if (!mwifiex_is_bss_in_11ac_mode(priv)) {
+ if (sta_ptr->tdls_cap.extcap.ext_capab[7] &
+ WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED) {
+ dev_dbg(adapter->dev,
+ "TDLS peer doesn't support wider bandwitdh\n");
+ return 0;
+ }
+ } else {
+ ap_vht_cap = bss_desc->bcn_vht_cap;
+ }
+
+ pos = (void *)skb_put(skb, sizeof(struct ieee80211_vht_operation) + 2);
+ *pos++ = WLAN_EID_VHT_OPERATION;
+ *pos++ = sizeof(struct ieee80211_vht_operation);
+ vht_oper = (struct ieee80211_vht_operation *)pos;
+
+ if (bss_desc->bss_band & BAND_A)
+ usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a;
+ else
+ usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg;
+
+ /* find the minmum bandwith between AP/TDLS peers */
+ vht_cap = &sta_ptr->tdls_cap.vhtcap;
+ supp_chwd_set = GET_VHTCAP_CHWDSET(usr_vht_cap_info);
+ peer_supp_chwd_set =
+ GET_VHTCAP_CHWDSET(le32_to_cpu(vht_cap->vht_cap_info));
+ supp_chwd_set = min_t(u8, supp_chwd_set, peer_supp_chwd_set);
+
+ /* We need check AP's bandwidth when TDLS_WIDER_BANDWIDTH is off */
+
+ if (ap_vht_cap && sta_ptr->tdls_cap.extcap.ext_capab[7] &
+ WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED) {
+ ap_supp_chwd_set =
+ GET_VHTCAP_CHWDSET(le32_to_cpu(ap_vht_cap->vht_cap_info));
+ supp_chwd_set = min_t(u8, supp_chwd_set, ap_supp_chwd_set);
+ }
+
+ switch (supp_chwd_set) {
+ case IEEE80211_VHT_CHANWIDTH_80MHZ:
+ vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
+ break;
+ case IEEE80211_VHT_CHANWIDTH_160MHZ:
+ vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_160MHZ;
+ break;
+ case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
+ vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80P80MHZ;
+ break;
+ default:
+ vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_USE_HT;
+ break;
+ }
+
+ mcs_map_user = GET_DEVRXMCSMAP(adapter->usr_dot_11ac_mcs_support);
+ mcs_map_resp = le16_to_cpu(vht_cap->supp_mcs.rx_mcs_map);
+ mcs_map_result = 0;
+
+ for (nss = 1; nss <= 8; nss++) {
+ mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
+ mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
+
+ if ((mcs_user == IEEE80211_VHT_MCS_NOT_SUPPORTED) ||
+ (mcs_resp == IEEE80211_VHT_MCS_NOT_SUPPORTED))
+ SET_VHTNSSMCS(mcs_map_result, nss,
+ IEEE80211_VHT_MCS_NOT_SUPPORTED);
+ else
+ SET_VHTNSSMCS(mcs_map_result, nss,
+ min_t(u16, mcs_user, mcs_resp));
+ }
+
+ vht_oper->basic_mcs_set = cpu_to_le16(mcs_map_result);
+
+ switch (vht_oper->chan_width) {
+ case IEEE80211_VHT_CHANWIDTH_80MHZ:
+ chan_bw = IEEE80211_VHT_CHANWIDTH_80MHZ;
+ break;
+ case IEEE80211_VHT_CHANWIDTH_160MHZ:
+ chan_bw = IEEE80211_VHT_CHANWIDTH_160MHZ;
+ break;
+ case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
+ chan_bw = IEEE80211_VHT_CHANWIDTH_80MHZ;
+ break;
+ default:
+ chan_bw = IEEE80211_VHT_CHANWIDTH_USE_HT;
+ break;
+ }
+ vht_oper->center_freq_seg1_idx =
+ mwifiex_get_center_freq_index(priv, BAND_AAC,
+ bss_desc->channel,
+ chan_bw);
+
+ return 0;
+}
+
+static void mwifiex_tdls_add_ext_capab(struct mwifiex_private *priv,
+ struct sk_buff *skb)
+{
+ struct ieee_types_extcap *extcap;
+
+ extcap = (void *)skb_put(skb, sizeof(struct ieee_types_extcap));
+ extcap->ieee_hdr.element_id = WLAN_EID_EXT_CAPABILITY;
+ extcap->ieee_hdr.len = 8;
+ memset(extcap->ext_capab, 0, 8);
+ extcap->ext_capab[4] |= WLAN_EXT_CAPA5_TDLS_ENABLED;
+
+ if (priv->adapter->is_hw_11ac_capable)
+ extcap->ext_capab[7] |= WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED;
+}
+
+static void mwifiex_tdls_add_qos_capab(struct sk_buff *skb)
+{
+ u8 *pos = (void *)skb_put(skb, 3);
+
+ *pos++ = WLAN_EID_QOS_CAPA;
+ *pos++ = 1;
+ *pos++ = MWIFIEX_TDLS_DEF_QOS_CAPAB;
+}
+
+static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv,
+ u8 *peer, u8 action_code, u8 dialog_token,
+ u16 status_code, struct sk_buff *skb)
+{
+ struct ieee80211_tdls_data *tf;
+ int ret;
+ u16 capab;
+ struct ieee80211_ht_cap *ht_cap;
+ u8 radio, *pos;
+
+ capab = priv->curr_bss_params.bss_descriptor.cap_info_bitmap;
+
+ tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
+ memcpy(tf->da, peer, ETH_ALEN);
+ memcpy(tf->sa, priv->curr_addr, ETH_ALEN);
+ tf->ether_type = cpu_to_be16(ETH_P_TDLS);
+ tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
+
+ switch (action_code) {
+ case WLAN_TDLS_SETUP_REQUEST:
+ tf->category = WLAN_CATEGORY_TDLS;
+ tf->action_code = WLAN_TDLS_SETUP_REQUEST;
+ skb_put(skb, sizeof(tf->u.setup_req));
+ tf->u.setup_req.dialog_token = dialog_token;
+ tf->u.setup_req.capability = cpu_to_le16(capab);
+ ret = mwifiex_tdls_append_rates_ie(priv, skb);
+ if (ret) {
+ dev_kfree_skb_any(skb);
+ return ret;
+ }
+
+ pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
+ *pos++ = WLAN_EID_HT_CAPABILITY;
+ *pos++ = sizeof(struct ieee80211_ht_cap);
+ ht_cap = (void *)pos;
+ radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
+ ret = mwifiex_fill_cap_info(priv, radio, ht_cap);
+ if (ret) {
+ dev_kfree_skb_any(skb);
+ return ret;
+ }
+
+ if (priv->adapter->is_hw_11ac_capable) {
+ ret = mwifiex_tdls_add_vht_capab(priv, skb);
+ if (ret) {
+ dev_kfree_skb_any(skb);
+ return ret;
+ }
+ mwifiex_tdls_add_aid(priv, skb);
+ }
+
+ mwifiex_tdls_add_ext_capab(priv, skb);
+ mwifiex_tdls_add_qos_capab(skb);
+ break;
+
+ case WLAN_TDLS_SETUP_RESPONSE:
+ tf->category = WLAN_CATEGORY_TDLS;
+ tf->action_code = WLAN_TDLS_SETUP_RESPONSE;
+ skb_put(skb, sizeof(tf->u.setup_resp));
+ tf->u.setup_resp.status_code = cpu_to_le16(status_code);
+ tf->u.setup_resp.dialog_token = dialog_token;
+ tf->u.setup_resp.capability = cpu_to_le16(capab);
+ ret = mwifiex_tdls_append_rates_ie(priv, skb);
+ if (ret) {
+ dev_kfree_skb_any(skb);
+ return ret;
+ }
+
+ pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
+ *pos++ = WLAN_EID_HT_CAPABILITY;
+ *pos++ = sizeof(struct ieee80211_ht_cap);
+ ht_cap = (void *)pos;
+ radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
+ ret = mwifiex_fill_cap_info(priv, radio, ht_cap);
+ if (ret) {
+ dev_kfree_skb_any(skb);
+ return ret;
+ }
+
+ if (priv->adapter->is_hw_11ac_capable) {
+ ret = mwifiex_tdls_add_vht_capab(priv, skb);
+ if (ret) {
+ dev_kfree_skb_any(skb);
+ return ret;
+ }
+ mwifiex_tdls_add_aid(priv, skb);
+ }
+
+ mwifiex_tdls_add_ext_capab(priv, skb);
+ mwifiex_tdls_add_qos_capab(skb);
+ break;
+
+ case WLAN_TDLS_SETUP_CONFIRM:
+ tf->category = WLAN_CATEGORY_TDLS;
+ tf->action_code = WLAN_TDLS_SETUP_CONFIRM;
+ skb_put(skb, sizeof(tf->u.setup_cfm));
+ tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
+ tf->u.setup_cfm.dialog_token = dialog_token;
+ if (priv->adapter->is_hw_11ac_capable) {
+ ret = mwifiex_tdls_add_vht_oper(priv, peer, skb);
+ if (ret) {
+ dev_kfree_skb_any(skb);
+ return ret;
+ }
+ }
+ break;
+
+ case WLAN_TDLS_TEARDOWN:
+ tf->category = WLAN_CATEGORY_TDLS;
+ tf->action_code = WLAN_TDLS_TEARDOWN;
+ skb_put(skb, sizeof(tf->u.teardown));
+ tf->u.teardown.reason_code = cpu_to_le16(status_code);
+ break;
+
+ case WLAN_TDLS_DISCOVERY_REQUEST:
+ tf->category = WLAN_CATEGORY_TDLS;
+ tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST;
+ skb_put(skb, sizeof(tf->u.discover_req));
+ tf->u.discover_req.dialog_token = dialog_token;
+ break;
+ default:
+ dev_err(priv->adapter->dev, "Unknown TDLS frame type.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void
+mwifiex_tdls_add_link_ie(struct sk_buff *skb, u8 *src_addr, u8 *peer, u8 *bssid)
+{
+ struct ieee80211_tdls_lnkie *lnkid;
+
+ lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
+ lnkid->ie_type = WLAN_EID_LINK_ID;
+ lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) -
+ sizeof(struct ieee_types_header);
+
+ memcpy(lnkid->bssid, bssid, ETH_ALEN);
+ memcpy(lnkid->init_sta, src_addr, ETH_ALEN);
+ memcpy(lnkid->resp_sta, peer, ETH_ALEN);
+}
+
+int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv,
+ u8 *peer, u8 action_code, u8 dialog_token,
+ u16 status_code, const u8 *extra_ies,
+ size_t extra_ies_len)
+{
+ struct sk_buff *skb;
+ struct mwifiex_txinfo *tx_info;
+ struct timeval tv;
+ int ret;
+ u16 skb_len;
+
+ skb_len = MWIFIEX_MIN_DATA_HEADER_LEN +
+ max(sizeof(struct ieee80211_mgmt),
+ sizeof(struct ieee80211_tdls_data)) +
+ MWIFIEX_MGMT_FRAME_HEADER_SIZE +
+ MWIFIEX_SUPPORTED_RATES +
+ 3 + /* Qos Info */
+ sizeof(struct ieee_types_extcap) +
+ sizeof(struct ieee80211_ht_cap) +
+ sizeof(struct ieee_types_bss_co_2040) +
+ sizeof(struct ieee80211_ht_operation) +
+ sizeof(struct ieee80211_tdls_lnkie) +
+ extra_ies_len;
+
+ if (priv->adapter->is_hw_11ac_capable)
+ skb_len += sizeof(struct ieee_types_vht_cap) +
+ sizeof(struct ieee_types_vht_oper) +
+ sizeof(struct ieee_types_aid);
+
+ skb = dev_alloc_skb(skb_len);
+ if (!skb) {
+ dev_err(priv->adapter->dev,
+ "allocate skb failed for management frame\n");
+ return -ENOMEM;
+ }
+ skb_reserve(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
+
+ switch (action_code) {
+ case WLAN_TDLS_SETUP_REQUEST:
+ case WLAN_TDLS_SETUP_CONFIRM:
+ case WLAN_TDLS_TEARDOWN:
+ case WLAN_TDLS_DISCOVERY_REQUEST:
+ ret = mwifiex_prep_tdls_encap_data(priv, peer, action_code,
+ dialog_token, status_code,
+ skb);
+ if (ret) {
+ dev_kfree_skb_any(skb);
+ return ret;
+ }
+ if (extra_ies_len)
+ memcpy(skb_put(skb, extra_ies_len), extra_ies,
+ extra_ies_len);
+ mwifiex_tdls_add_link_ie(skb, priv->curr_addr, peer,
+ priv->cfg_bssid);
+ break;
+ case WLAN_TDLS_SETUP_RESPONSE:
+ ret = mwifiex_prep_tdls_encap_data(priv, peer, action_code,
+ dialog_token, status_code,
+ skb);
+ if (ret) {
+ dev_kfree_skb_any(skb);
+ return ret;
+ }
+ if (extra_ies_len)
+ memcpy(skb_put(skb, extra_ies_len), extra_ies,
+ extra_ies_len);
+ mwifiex_tdls_add_link_ie(skb, peer, priv->curr_addr,
+ priv->cfg_bssid);
+ break;
+ }
+
+ switch (action_code) {
+ case WLAN_TDLS_SETUP_REQUEST:
+ case WLAN_TDLS_SETUP_RESPONSE:
+ skb->priority = MWIFIEX_PRIO_BK;
+ break;
+ default:
+ skb->priority = MWIFIEX_PRIO_VI;
+ break;
+ }
+
+ tx_info = MWIFIEX_SKB_TXCB(skb);
+ tx_info->bss_num = priv->bss_num;
+ tx_info->bss_type = priv->bss_type;
+
+ do_gettimeofday(&tv);
+ skb->tstamp = timeval_to_ktime(tv);
+ mwifiex_queue_tx_pkt(priv, skb);
+
+ return 0;
+}
+
+static int
+mwifiex_construct_tdls_action_frame(struct mwifiex_private *priv, u8 *peer,
+ u8 action_code, u8 dialog_token,
+ u16 status_code, struct sk_buff *skb)
+{
+ struct ieee80211_mgmt *mgmt;
+ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ int ret;
+ u16 capab;
+ struct ieee80211_ht_cap *ht_cap;
+ u8 radio, *pos;
+
+ capab = priv->curr_bss_params.bss_descriptor.cap_info_bitmap;
+
+ mgmt = (void *)skb_put(skb, offsetof(struct ieee80211_mgmt, u));
+
+ memset(mgmt, 0, 24);
+ memcpy(mgmt->da, peer, ETH_ALEN);
+ memcpy(mgmt->sa, priv->curr_addr, ETH_ALEN);
+ memcpy(mgmt->bssid, priv->cfg_bssid, ETH_ALEN);
+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION);
+
+ /* add address 4 */
+ pos = skb_put(skb, ETH_ALEN);
+
+ switch (action_code) {
+ case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
+ skb_put(skb, sizeof(mgmt->u.action.u.tdls_discover_resp) + 1);
+ mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
+ mgmt->u.action.u.tdls_discover_resp.action_code =
+ WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
+ mgmt->u.action.u.tdls_discover_resp.dialog_token =
+ dialog_token;
+ mgmt->u.action.u.tdls_discover_resp.capability =
+ cpu_to_le16(capab);
+ /* move back for addr4 */
+ memmove(pos + ETH_ALEN, &mgmt->u.action.category,
+ sizeof(mgmt->u.action.u.tdls_discover_resp));
+ /* init address 4 */
+ memcpy(pos, bc_addr, ETH_ALEN);
+
+ ret = mwifiex_tdls_append_rates_ie(priv, skb);
+ if (ret) {
+ dev_kfree_skb_any(skb);
+ return ret;
+ }
+
+ pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
+ *pos++ = WLAN_EID_HT_CAPABILITY;
+ *pos++ = sizeof(struct ieee80211_ht_cap);
+ ht_cap = (void *)pos;
+ radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
+ ret = mwifiex_fill_cap_info(priv, radio, ht_cap);
+ if (ret) {
+ dev_kfree_skb_any(skb);
+ return ret;
+ }
+
+ if (priv->adapter->is_hw_11ac_capable) {
+ ret = mwifiex_tdls_add_vht_capab(priv, skb);
+ if (ret) {
+ dev_kfree_skb_any(skb);
+ return ret;
+ }
+ mwifiex_tdls_add_aid(priv, skb);
+ }
+
+ mwifiex_tdls_add_ext_capab(priv, skb);
+ mwifiex_tdls_add_qos_capab(skb);
+ break;
+ default:
+ dev_err(priv->adapter->dev, "Unknown TDLS action frame type\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv,
+ u8 *peer, u8 action_code, u8 dialog_token,
+ u16 status_code, const u8 *extra_ies,
+ size_t extra_ies_len)
+{
+ struct sk_buff *skb;
+ struct mwifiex_txinfo *tx_info;
+ struct timeval tv;
+ u8 *pos;
+ u32 pkt_type, tx_control;
+ u16 pkt_len, skb_len;
+
+ skb_len = MWIFIEX_MIN_DATA_HEADER_LEN +
+ max(sizeof(struct ieee80211_mgmt),
+ sizeof(struct ieee80211_tdls_data)) +
+ MWIFIEX_MGMT_FRAME_HEADER_SIZE +
+ MWIFIEX_SUPPORTED_RATES +
+ sizeof(struct ieee_types_extcap) +
+ sizeof(struct ieee80211_ht_cap) +
+ sizeof(struct ieee_types_bss_co_2040) +
+ sizeof(struct ieee80211_ht_operation) +
+ sizeof(struct ieee80211_tdls_lnkie) +
+ extra_ies_len +
+ 3 + /* Qos Info */
+ ETH_ALEN; /* Address4 */
+
+ if (priv->adapter->is_hw_11ac_capable)
+ skb_len += sizeof(struct ieee_types_vht_cap) +
+ sizeof(struct ieee_types_vht_oper) +
+ sizeof(struct ieee_types_aid);
+
+ skb = dev_alloc_skb(skb_len);
+ if (!skb) {
+ dev_err(priv->adapter->dev,
+ "allocate skb failed for management frame\n");
+ return -ENOMEM;
+ }
+
+ skb_reserve(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
+
+ pkt_type = PKT_TYPE_MGMT;
+ tx_control = 0;
+ pos = skb_put(skb, MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len));
+ memset(pos, 0, MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len));
+ memcpy(pos, &pkt_type, sizeof(pkt_type));
+ memcpy(pos + sizeof(pkt_type), &tx_control, sizeof(tx_control));
+
+ if (mwifiex_construct_tdls_action_frame(priv, peer, action_code,
+ dialog_token, status_code,
+ skb)) {
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+ }
+
+ if (extra_ies_len)
+ memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len);
+
+ /* the TDLS link IE is always added last we are the responder */
+
+ mwifiex_tdls_add_link_ie(skb, peer, priv->curr_addr,
+ priv->cfg_bssid);
+
+ skb->priority = MWIFIEX_PRIO_VI;
+
+ tx_info = MWIFIEX_SKB_TXCB(skb);
+ tx_info->bss_num = priv->bss_num;
+ tx_info->bss_type = priv->bss_type;
+ tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT;
+
+ pkt_len = skb->len - MWIFIEX_MGMT_FRAME_HEADER_SIZE - sizeof(pkt_len);
+ memcpy(skb->data + MWIFIEX_MGMT_FRAME_HEADER_SIZE, &pkt_len,
+ sizeof(pkt_len));
+ do_gettimeofday(&tv);
+ skb->tstamp = timeval_to_ktime(tv);
+ mwifiex_queue_tx_pkt(priv, skb);
+
+ return 0;
+}
+
+/* This function process tdls action frame from peer.
+ * Peer capabilities are stored into station node structure.
+ */
+void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
+ u8 *buf, int len)
+{
+ struct mwifiex_sta_node *sta_ptr;
+ u8 *peer, *pos, *end;
+ u8 i, action, basic;
+ int ie_len = 0;
+
+ if (len < (sizeof(struct ethhdr) + 3))
+ return;
+ if (*(buf + sizeof(struct ethhdr)) != WLAN_TDLS_SNAP_RFTYPE)
+ return;
+ if (*(buf + sizeof(struct ethhdr) + 1) != WLAN_CATEGORY_TDLS)
+ return;
+
+ peer = buf + ETH_ALEN;
+ action = *(buf + sizeof(struct ethhdr) + 2);
+
+ /* just handle TDLS setup request/response/confirm */
+ if (action > WLAN_TDLS_SETUP_CONFIRM)
+ return;
+
+ dev_dbg(priv->adapter->dev,
+ "rx:tdls action: peer=%pM, action=%d\n", peer, action);
+
+ sta_ptr = mwifiex_add_sta_entry(priv, peer);
+ if (!sta_ptr)
+ return;
+
+ switch (action) {
+ case WLAN_TDLS_SETUP_REQUEST:
+ if (len < (sizeof(struct ethhdr) + TDLS_REQ_FIX_LEN))
+ return;
+
+ pos = buf + sizeof(struct ethhdr) + 4;
+ /* payload 1+ category 1 + action 1 + dialog 1 */
+ sta_ptr->tdls_cap.capab = cpu_to_le16(*(u16 *)pos);
+ ie_len = len - sizeof(struct ethhdr) - TDLS_REQ_FIX_LEN;
+ pos += 2;
+ break;
+
+ case WLAN_TDLS_SETUP_RESPONSE:
+ if (len < (sizeof(struct ethhdr) + TDLS_RESP_FIX_LEN))
+ return;
+ /* payload 1+ category 1 + action 1 + dialog 1 + status code 2*/
+ pos = buf + sizeof(struct ethhdr) + 6;
+ sta_ptr->tdls_cap.capab = cpu_to_le16(*(u16 *)pos);
+ ie_len = len - sizeof(struct ethhdr) - TDLS_RESP_FIX_LEN;
+ pos += 2;
+ break;
+
+ case WLAN_TDLS_SETUP_CONFIRM:
+ if (len < (sizeof(struct ethhdr) + TDLS_CONFIRM_FIX_LEN))
+ return;
+ pos = buf + sizeof(struct ethhdr) + TDLS_CONFIRM_FIX_LEN;
+ ie_len = len - sizeof(struct ethhdr) - TDLS_CONFIRM_FIX_LEN;
+ break;
+ default:
+ dev_warn(priv->adapter->dev, "Unknown TDLS frame type.\n");
+ return;
+ }
+
+ for (end = pos + ie_len; pos + 1 < end; pos += 2 + pos[1]) {
+ if (pos + 2 + pos[1] > end)
+ break;
+
+ switch (*pos) {
+ case WLAN_EID_SUPP_RATES:
+ sta_ptr->tdls_cap.rates_len = pos[1];
+ for (i = 0; i < pos[1]; i++)
+ sta_ptr->tdls_cap.rates[i] = pos[i + 2];
+ break;
+
+ case WLAN_EID_EXT_SUPP_RATES:
+ basic = sta_ptr->tdls_cap.rates_len;
+ for (i = 0; i < pos[1]; i++)
+ sta_ptr->tdls_cap.rates[basic + i] = pos[i + 2];
+ sta_ptr->tdls_cap.rates_len += pos[1];
+ break;
+ case WLAN_EID_HT_CAPABILITY:
+ memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos,
+ sizeof(struct ieee80211_ht_cap));
+ sta_ptr->is_11n_enabled = 1;
+ break;
+ case WLAN_EID_HT_OPERATION:
+ memcpy(&sta_ptr->tdls_cap.ht_oper, pos,
+ sizeof(struct ieee80211_ht_operation));
+ break;
+ case WLAN_EID_BSS_COEX_2040:
+ sta_ptr->tdls_cap.coex_2040 = pos[2];
+ break;
+ case WLAN_EID_EXT_CAPABILITY:
+ memcpy((u8 *)&sta_ptr->tdls_cap.extcap, pos,
+ sizeof(struct ieee_types_header) +
+ min_t(u8, pos[1], 8));
+ break;
+ case WLAN_EID_RSN:
+ memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos,
+ sizeof(struct ieee_types_header) + pos[1]);
+ break;
+ case WLAN_EID_QOS_CAPA:
+ sta_ptr->tdls_cap.qos_info = pos[2];
+ break;
+ case WLAN_EID_VHT_OPERATION:
+ if (priv->adapter->is_hw_11ac_capable)
+ memcpy(&sta_ptr->tdls_cap.vhtoper, pos,
+ sizeof(struct ieee80211_vht_operation));
+ break;
+ case WLAN_EID_VHT_CAPABILITY:
+ if (priv->adapter->is_hw_11ac_capable) {
+ memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos,
+ sizeof(struct ieee80211_vht_cap));
+ sta_ptr->is_11ac_enabled = 1;
+ }
+ break;
+ case WLAN_EID_AID:
+ if (priv->adapter->is_hw_11ac_capable)
+ sta_ptr->tdls_cap.aid =
+ le16_to_cpu(*(__le16 *)(pos + 2));
+ default:
+ break;
+ }
+ }
+
+ return;
+}
+
+static int
+mwifiex_tdls_process_config_link(struct mwifiex_private *priv, u8 *peer)
+{
+ struct mwifiex_sta_node *sta_ptr;
+ struct mwifiex_ds_tdls_oper tdls_oper;
+
+ memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
+ sta_ptr = mwifiex_get_sta_entry(priv, peer);
+
+ if (!sta_ptr || sta_ptr->tdls_status == TDLS_SETUP_FAILURE) {
+ dev_err(priv->adapter->dev,
+ "link absent for peer %pM; cannot config\n", peer);
+ return -EINVAL;
+ }
+
+ memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
+ tdls_oper.tdls_action = MWIFIEX_TDLS_CONFIG_LINK;
+ return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
+ HostCmd_ACT_GEN_SET, 0, &tdls_oper, true);
+}
+
+static int
+mwifiex_tdls_process_create_link(struct mwifiex_private *priv, u8 *peer)
+{
+ struct mwifiex_sta_node *sta_ptr;
+ struct mwifiex_ds_tdls_oper tdls_oper;
+
+ memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
+ sta_ptr = mwifiex_get_sta_entry(priv, peer);
+
+ if (sta_ptr && sta_ptr->tdls_status == TDLS_SETUP_INPROGRESS) {
+ dev_dbg(priv->adapter->dev,
+ "Setup already in progress for peer %pM\n", peer);
+ return 0;
+ }
+
+ sta_ptr = mwifiex_add_sta_entry(priv, peer);
+ if (!sta_ptr)
+ return -ENOMEM;
+
+ sta_ptr->tdls_status = TDLS_SETUP_INPROGRESS;
+ mwifiex_hold_tdls_packets(priv, peer);
+ memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
+ tdls_oper.tdls_action = MWIFIEX_TDLS_CREATE_LINK;
+ return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
+ HostCmd_ACT_GEN_SET, 0, &tdls_oper, true);
+}
+
+static int
+mwifiex_tdls_process_disable_link(struct mwifiex_private *priv, u8 *peer)
+{
+ struct mwifiex_sta_node *sta_ptr;
+ struct mwifiex_ds_tdls_oper tdls_oper;
+ unsigned long flags;
+
+ memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
+ sta_ptr = mwifiex_get_sta_entry(priv, peer);
+
+ if (sta_ptr) {
+ if (sta_ptr->is_11n_enabled) {
+ mwifiex_11n_cleanup_reorder_tbl(priv);
+ spin_lock_irqsave(&priv->wmm.ra_list_spinlock,
+ flags);
+ mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+ flags);
+ }
+ mwifiex_del_sta_entry(priv, peer);
+ }
+
+ mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN);
+ memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
+ tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK;
+ return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
+ HostCmd_ACT_GEN_SET, 0, &tdls_oper, true);
+}
+
+static int
+mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, u8 *peer)
+{
+ struct mwifiex_sta_node *sta_ptr;
+ struct ieee80211_mcs_info mcs;
+ unsigned long flags;
+ int i;
+
+ sta_ptr = mwifiex_get_sta_entry(priv, peer);
+
+ if (sta_ptr && (sta_ptr->tdls_status != TDLS_SETUP_FAILURE)) {
+ dev_dbg(priv->adapter->dev,
+ "tdls: enable link %pM success\n", peer);
+
+ sta_ptr->tdls_status = TDLS_SETUP_COMPLETE;
+
+ mcs = sta_ptr->tdls_cap.ht_capb.mcs;
+ if (mcs.rx_mask[0] != 0xff)
+ sta_ptr->is_11n_enabled = true;
+ if (sta_ptr->is_11n_enabled) {
+ if (le16_to_cpu(sta_ptr->tdls_cap.ht_capb.cap_info) &
+ IEEE80211_HT_CAP_MAX_AMSDU)
+ sta_ptr->max_amsdu =
+ MWIFIEX_TX_DATA_BUF_SIZE_8K;
+ else
+ sta_ptr->max_amsdu =
+ MWIFIEX_TX_DATA_BUF_SIZE_4K;
+
+ for (i = 0; i < MAX_NUM_TID; i++)
+ sta_ptr->ampdu_sta[i] =
+ priv->aggr_prio_tbl[i].ampdu_user;
+ } else {
+ for (i = 0; i < MAX_NUM_TID; i++)
+ sta_ptr->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED;
+ }
+
+ memset(sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq));
+ mwifiex_restore_tdls_packets(priv, peer, TDLS_SETUP_COMPLETE);
+ } else {
+ dev_dbg(priv->adapter->dev,
+ "tdls: enable link %pM failed\n", peer);
+ if (sta_ptr) {
+ mwifiex_11n_cleanup_reorder_tbl(priv);
+ spin_lock_irqsave(&priv->wmm.ra_list_spinlock,
+ flags);
+ mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+ flags);
+ mwifiex_del_sta_entry(priv, peer);
+ }
+ mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+int mwifiex_tdls_oper(struct mwifiex_private *priv, u8 *peer, u8 action)
+{
+ switch (action) {
+ case MWIFIEX_TDLS_ENABLE_LINK:
+ return mwifiex_tdls_process_enable_link(priv, peer);
+ case MWIFIEX_TDLS_DISABLE_LINK:
+ return mwifiex_tdls_process_disable_link(priv, peer);
+ case MWIFIEX_TDLS_CREATE_LINK:
+ return mwifiex_tdls_process_create_link(priv, peer);
+ case MWIFIEX_TDLS_CONFIG_LINK:
+ return mwifiex_tdls_process_config_link(priv, peer);
+ }
+ return 0;
+}
+
+int mwifiex_get_tdls_link_status(struct mwifiex_private *priv, u8 *mac)
+{
+ struct mwifiex_sta_node *sta_ptr;
+
+ sta_ptr = mwifiex_get_sta_entry(priv, mac);
+ if (sta_ptr)
+ return sta_ptr->tdls_status;
+
+ return TDLS_NOT_SETUP;
+}
+
+void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv)
+{
+ struct mwifiex_sta_node *sta_ptr;
+ struct mwifiex_ds_tdls_oper tdls_oper;
+ unsigned long flags;
+
+ if (list_empty(&priv->sta_list))
+ return;
+
+ list_for_each_entry(sta_ptr, &priv->sta_list, list) {
+ memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
+
+ if (sta_ptr->is_11n_enabled) {
+ mwifiex_11n_cleanup_reorder_tbl(priv);
+ spin_lock_irqsave(&priv->wmm.ra_list_spinlock,
+ flags);
+ mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+ flags);
+ }
+
+ mwifiex_restore_tdls_packets(priv, sta_ptr->mac_addr,
+ TDLS_LINK_TEARDOWN);
+ memcpy(&tdls_oper.peer_mac, sta_ptr->mac_addr, ETH_ALEN);
+ tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK;
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
+ HostCmd_ACT_GEN_SET, 0, &tdls_oper, false))
+ dev_warn(priv->adapter->dev,
+ "Disable link failed for TDLS peer %pM",
+ sta_ptr->mac_addr);
+ }
+
+ mwifiex_del_all_sta_list(priv);
+}
diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c
index 64424c81b44f..9be6544bdded 100644
--- a/drivers/net/wireless/mwifiex/uap_cmd.c
+++ b/drivers/net/wireless/mwifiex/uap_cmd.c
@@ -159,6 +159,7 @@ mwifiex_set_ht_params(struct mwifiex_private *priv,
struct cfg80211_ap_settings *params)
{
const u8 *ht_ie;
+ u16 cap_info;
if (!ISSUPP_11NENABLED(priv->adapter->fw_cap_info))
return;
@@ -168,6 +169,25 @@ mwifiex_set_ht_params(struct mwifiex_private *priv,
if (ht_ie) {
memcpy(&bss_cfg->ht_cap, ht_ie + 2,
sizeof(struct ieee80211_ht_cap));
+ cap_info = le16_to_cpu(bss_cfg->ht_cap.cap_info);
+ memset(&bss_cfg->ht_cap.mcs, 0,
+ priv->adapter->number_of_antenna);
+ switch (GET_RXSTBC(cap_info)) {
+ case MWIFIEX_RX_STBC1:
+ /* HT_CAP 1X1 mode */
+ memset(&bss_cfg->ht_cap.mcs, 0xff, 1);
+ break;
+ case MWIFIEX_RX_STBC12: /* fall through */
+ case MWIFIEX_RX_STBC123:
+ /* HT_CAP 2X2 mode */
+ memset(&bss_cfg->ht_cap.mcs, 0xff, 2);
+ break;
+ default:
+ dev_warn(priv->adapter->dev,
+ "Unsupported RX-STBC, default to 2x2\n");
+ memset(&bss_cfg->ht_cap.mcs, 0xff, 2);
+ break;
+ }
priv->ap_11n_enabled = 1;
} else {
memset(&bss_cfg->ht_cap , 0, sizeof(struct ieee80211_ht_cap));
@@ -226,8 +246,8 @@ void mwifiex_set_vht_width(struct mwifiex_private *priv,
if (ap_11ac_enable && width >= NL80211_CHAN_WIDTH_80)
vht_cfg.misc_config |= VHT_BW_80_160_80P80;
- mwifiex_send_cmd_sync(priv, HostCmd_CMD_11AC_CFG,
- HostCmd_ACT_GEN_SET, 0, &vht_cfg);
+ mwifiex_send_cmd(priv, HostCmd_CMD_11AC_CFG,
+ HostCmd_ACT_GEN_SET, 0, &vht_cfg, true);
return;
}
diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c
index 718066577c6c..92e77a398ecf 100644
--- a/drivers/net/wireless/mwifiex/uap_event.c
+++ b/drivers/net/wireless/mwifiex/uap_event.c
@@ -21,126 +21,8 @@
#include "main.h"
#include "11n.h"
-/*
- * This function will return the pointer to station entry in station list
- * table which matches specified mac address.
- * This function should be called after acquiring RA list spinlock.
- * NULL is returned if station entry is not found in associated STA list.
- */
-struct mwifiex_sta_node *
-mwifiex_get_sta_entry(struct mwifiex_private *priv, u8 *mac)
-{
- struct mwifiex_sta_node *node;
-
- if (!mac)
- return NULL;
-
- list_for_each_entry(node, &priv->sta_list, list) {
- if (!memcmp(node->mac_addr, mac, ETH_ALEN))
- return node;
- }
-
- return NULL;
-}
-
-/*
- * This function will add a sta_node entry to associated station list
- * table with the given mac address.
- * If entry exist already, existing entry is returned.
- * If received mac address is NULL, NULL is returned.
- */
-static struct mwifiex_sta_node *
-mwifiex_add_sta_entry(struct mwifiex_private *priv, u8 *mac)
-{
- struct mwifiex_sta_node *node;
- unsigned long flags;
-
- if (!mac)
- return NULL;
-
- spin_lock_irqsave(&priv->sta_list_spinlock, flags);
- node = mwifiex_get_sta_entry(priv, mac);
- if (node)
- goto done;
-
- node = kzalloc(sizeof(struct mwifiex_sta_node), GFP_ATOMIC);
- if (!node)
- goto done;
-
- memcpy(node->mac_addr, mac, ETH_ALEN);
- list_add_tail(&node->list, &priv->sta_list);
-
-done:
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
- return node;
-}
-
-/*
- * This function will search for HT IE in association request IEs
- * and set station HT parameters accordingly.
- */
-static void
-mwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies,
- int ies_len, struct mwifiex_sta_node *node)
-{
- const struct ieee80211_ht_cap *ht_cap;
-
- if (!ies)
- return;
- ht_cap = (void *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
- if (ht_cap) {
- node->is_11n_enabled = 1;
- node->max_amsdu = le16_to_cpu(ht_cap->cap_info) &
- IEEE80211_HT_CAP_MAX_AMSDU ?
- MWIFIEX_TX_DATA_BUF_SIZE_8K :
- MWIFIEX_TX_DATA_BUF_SIZE_4K;
- } else {
- node->is_11n_enabled = 0;
- }
- return;
-}
-
-/*
- * This function will delete a station entry from station list
- */
-static void mwifiex_del_sta_entry(struct mwifiex_private *priv, u8 *mac)
-{
- struct mwifiex_sta_node *node;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->sta_list_spinlock, flags);
-
- node = mwifiex_get_sta_entry(priv, mac);
- if (node) {
- list_del(&node->list);
- kfree(node);
- }
-
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
- return;
-}
-
-/*
- * This function will delete all stations from associated station list.
- */
-static void mwifiex_del_all_sta_list(struct mwifiex_private *priv)
-{
- struct mwifiex_sta_node *node, *tmp;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->sta_list_spinlock, flags);
-
- list_for_each_entry_safe(node, tmp, &priv->sta_list, list) {
- list_del(&node->list);
- kfree(node);
- }
-
- INIT_LIST_HEAD(&priv->sta_list);
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
- return;
-}
/*
* This function handles AP interface specific events generated by firmware.
@@ -268,9 +150,9 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
case EVENT_ADDBA:
dev_dbg(adapter->dev, "event: ADDBA Request\n");
if (priv->media_connected)
- mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_RSP,
- HostCmd_ACT_GEN_SET, 0,
- adapter->event_body);
+ mwifiex_send_cmd(priv, HostCmd_CMD_11N_ADDBA_RSP,
+ HostCmd_ACT_GEN_SET, 0,
+ adapter->event_body, false);
break;
case EVENT_DELBA:
dev_dbg(adapter->dev, "event: DELBA Request\n");
@@ -284,6 +166,12 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
mwifiex_11n_ba_stream_timeout(priv, ba_timeout);
}
break;
+ case EVENT_EXT_SCAN_REPORT:
+ dev_dbg(adapter->dev, "event: EXT_SCAN Report\n");
+ if (adapter->ext_scan)
+ return mwifiex_handle_event_ext_scan_report(priv,
+ adapter->event_skb->data);
+ break;
default:
dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
eventcause);
diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c
index 3c74eb254927..9a56bc61cb1d 100644
--- a/drivers/net/wireless/mwifiex/uap_txrx.c
+++ b/drivers/net/wireless/mwifiex/uap_txrx.c
@@ -284,27 +284,7 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv,
return 0;
}
- if (le16_to_cpu(uap_rx_pd->rx_pkt_type) == PKT_TYPE_AMSDU) {
- struct sk_buff_head list;
- struct sk_buff *rx_skb;
-
- __skb_queue_head_init(&list);
- skb_pull(skb, le16_to_cpu(uap_rx_pd->rx_pkt_offset));
- skb_trim(skb, le16_to_cpu(uap_rx_pd->rx_pkt_length));
-
- ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
- priv->wdev->iftype, 0, false);
-
- while (!skb_queue_empty(&list)) {
- rx_skb = __skb_dequeue(&list);
- ret = mwifiex_recv_packet(priv, rx_skb);
- if (ret)
- dev_err(adapter->dev,
- "AP:Rx A-MSDU failed");
- }
-
- return 0;
- } else if (rx_pkt_type == PKT_TYPE_MGMT) {
+ if (rx_pkt_type == PKT_TYPE_MGMT) {
ret = mwifiex_process_mgmt_packet(priv, skb);
if (ret)
dev_err(adapter->dev, "Rx of mgmt packet failed");
diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c
index e8ebbd4bc3cd..edbe4aff00d8 100644
--- a/drivers/net/wireless/mwifiex/usb.c
+++ b/drivers/net/wireless/mwifiex/usb.c
@@ -22,8 +22,6 @@
#define USB_VERSION "1.0"
-static const char usbdriver_name[] = "usb8xxx";
-
static struct mwifiex_if_ops usb_ops;
static struct semaphore add_remove_card_sem;
static struct usb_card_rec *usb_card;
@@ -461,6 +459,7 @@ static int mwifiex_usb_suspend(struct usb_interface *intf, pm_message_t message)
* 'suspended' state and a 'disconnect' one.
*/
adapter->is_suspended = true;
+ adapter->hs_enabling = false;
if (atomic_read(&card->rx_cmd_urb_pending) && card->rx_cmd.urb)
usb_kill_urb(card->rx_cmd.urb);
@@ -527,13 +526,6 @@ static int mwifiex_usb_resume(struct usb_interface *intf)
MWIFIEX_BSS_ROLE_ANY),
MWIFIEX_ASYNC_CMD);
-#ifdef CONFIG_PM
- /* Resume handler may be called due to remote wakeup,
- * force to exit suspend anyway
- */
- usb_disable_autosuspend(card->udev);
-#endif /* CONFIG_PM */
-
return 0;
}
@@ -567,13 +559,12 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf)
}
static struct usb_driver mwifiex_usb_driver = {
- .name = usbdriver_name,
+ .name = "mwifiex_usb",
.probe = mwifiex_usb_probe,
.disconnect = mwifiex_usb_disconnect,
.id_table = mwifiex_usb_table,
.suspend = mwifiex_usb_suspend,
.resume = mwifiex_usb_resume,
- .supports_autosuspend = 1,
};
static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter)
@@ -776,11 +767,13 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
switch (le16_to_cpu(card->udev->descriptor.idProduct)) {
case USB8897_PID_1:
case USB8897_PID_2:
+ adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K;
strcpy(adapter->fw_name, USB8897_DEFAULT_FW_NAME);
break;
case USB8797_PID_1:
case USB8797_PID_2:
default:
+ adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
strcpy(adapter->fw_name, USB8797_DEFAULT_FW_NAME);
break;
}
@@ -1034,7 +1027,6 @@ static void mwifiex_usb_cleanup_module(void)
if (usb_card && usb_card->adapter) {
struct mwifiex_adapter *adapter = usb_card->adapter;
- int i;
/* In case driver is removed when asynchronous FW downloading is
* in progress
@@ -1045,11 +1037,8 @@ static void mwifiex_usb_cleanup_module(void)
if (adapter->is_suspended)
mwifiex_usb_resume(usb_card->intf);
#endif
- for (i = 0; i < adapter->priv_num; i++)
- if ((GET_BSS_ROLE(adapter->priv[i]) ==
- MWIFIEX_BSS_ROLE_STA) &&
- adapter->priv[i]->media_connected)
- mwifiex_deauthenticate(adapter->priv[i], NULL);
+
+ mwifiex_deauthenticate_all(adapter);
mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter,
MWIFIEX_BSS_ROLE_ANY),
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
index 9b82e225880c..c3824e37f3f2 100644
--- a/drivers/net/wireless/mwifiex/util.c
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -72,7 +72,7 @@ int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
return -1;
}
- return mwifiex_send_cmd_sync(priv, cmd, HostCmd_ACT_GEN_SET, 0, NULL);
+ return mwifiex_send_cmd(priv, cmd, HostCmd_ACT_GEN_SET, 0, NULL, true);
}
EXPORT_SYMBOL_GPL(mwifiex_init_shutdown_fw);
@@ -104,6 +104,7 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv,
info->pm_wakeup_fw_try = adapter->pm_wakeup_fw_try;
info->is_hs_configured = adapter->is_hs_configured;
info->hs_activated = adapter->hs_activated;
+ info->is_cmd_timedout = adapter->is_cmd_timedout;
info->num_cmd_host_to_card_failure
= adapter->dbg.num_cmd_host_to_card_failure;
info->num_cmd_sleep_cfm_host_to_card_failure
@@ -119,7 +120,6 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv,
info->num_cmd_assoc_failure =
adapter->dbg.num_cmd_assoc_failure;
info->num_tx_timeout = adapter->dbg.num_tx_timeout;
- info->num_cmd_timeout = adapter->dbg.num_cmd_timeout;
info->timeout_cmd_id = adapter->dbg.timeout_cmd_id;
info->timeout_cmd_act = adapter->dbg.timeout_cmd_act;
memcpy(info->last_cmd_id, adapter->dbg.last_cmd_id,
@@ -252,3 +252,117 @@ int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,
return 0;
}
+
+/* This function will return the pointer to station entry in station list
+ * table which matches specified mac address.
+ * This function should be called after acquiring RA list spinlock.
+ * NULL is returned if station entry is not found in associated STA list.
+ */
+struct mwifiex_sta_node *
+mwifiex_get_sta_entry(struct mwifiex_private *priv, u8 *mac)
+{
+ struct mwifiex_sta_node *node;
+
+ if (!mac)
+ return NULL;
+
+ list_for_each_entry(node, &priv->sta_list, list) {
+ if (!memcmp(node->mac_addr, mac, ETH_ALEN))
+ return node;
+ }
+
+ return NULL;
+}
+
+/* This function will add a sta_node entry to associated station list
+ * table with the given mac address.
+ * If entry exist already, existing entry is returned.
+ * If received mac address is NULL, NULL is returned.
+ */
+struct mwifiex_sta_node *
+mwifiex_add_sta_entry(struct mwifiex_private *priv, u8 *mac)
+{
+ struct mwifiex_sta_node *node;
+ unsigned long flags;
+
+ if (!mac)
+ return NULL;
+
+ spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+ node = mwifiex_get_sta_entry(priv, mac);
+ if (node)
+ goto done;
+
+ node = kzalloc(sizeof(*node), GFP_ATOMIC);
+ if (!node)
+ goto done;
+
+ memcpy(node->mac_addr, mac, ETH_ALEN);
+ list_add_tail(&node->list, &priv->sta_list);
+
+done:
+ spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ return node;
+}
+
+/* This function will search for HT IE in association request IEs
+ * and set station HT parameters accordingly.
+ */
+void
+mwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies,
+ int ies_len, struct mwifiex_sta_node *node)
+{
+ const struct ieee80211_ht_cap *ht_cap;
+
+ if (!ies)
+ return;
+
+ ht_cap = (void *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
+ if (ht_cap) {
+ node->is_11n_enabled = 1;
+ node->max_amsdu = le16_to_cpu(ht_cap->cap_info) &
+ IEEE80211_HT_CAP_MAX_AMSDU ?
+ MWIFIEX_TX_DATA_BUF_SIZE_8K :
+ MWIFIEX_TX_DATA_BUF_SIZE_4K;
+ } else {
+ node->is_11n_enabled = 0;
+ }
+
+ return;
+}
+
+/* This function will delete a station entry from station list */
+void mwifiex_del_sta_entry(struct mwifiex_private *priv, u8 *mac)
+{
+ struct mwifiex_sta_node *node;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+
+ node = mwifiex_get_sta_entry(priv, mac);
+ if (node) {
+ list_del(&node->list);
+ kfree(node);
+ }
+
+ spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ return;
+}
+
+/* This function will delete all stations from associated station list. */
+void mwifiex_del_all_sta_list(struct mwifiex_private *priv)
+{
+ struct mwifiex_sta_node *node, *tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+
+ list_for_each_entry_safe(node, tmp, &priv->sta_list, list) {
+ list_del(&node->list);
+ kfree(node);
+ }
+
+ INIT_LIST_HEAD(&priv->sta_list);
+ spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ return;
+}
diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h
index cb2d0582bd36..ddae57021397 100644
--- a/drivers/net/wireless/mwifiex/util.h
+++ b/drivers/net/wireless/mwifiex/util.h
@@ -30,8 +30,24 @@ static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb)
return (struct mwifiex_txinfo *)(skb->cb + sizeof(dma_addr_t));
}
-static inline void MWIFIEX_SKB_PACB(struct sk_buff *skb, dma_addr_t *buf_pa)
+struct mwifiex_dma_mapping {
+ dma_addr_t addr;
+ size_t len;
+};
+
+static inline void MWIFIEX_SKB_PACB(struct sk_buff *skb,
+ struct mwifiex_dma_mapping *mapping)
{
- memcpy(buf_pa, skb->cb, sizeof(dma_addr_t));
+ memcpy(mapping, skb->cb, sizeof(*mapping));
}
+
+static inline dma_addr_t MWIFIEX_SKB_DMA_ADDR(struct sk_buff *skb)
+{
+ struct mwifiex_dma_mapping mapping;
+
+ MWIFIEX_SKB_PACB(skb, &mapping);
+
+ return mapping.addr;
+}
+
#endif /* !_MWIFIEX_UTIL_H_ */
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index 13eaeed03898..0a7cc742aed7 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -37,8 +37,8 @@
/* Offset for TOS field in the IP header */
#define IPTOS_OFFSET 5
-static bool enable_tx_amsdu;
-module_param(enable_tx_amsdu, bool, 0644);
+static bool disable_tx_amsdu;
+module_param(disable_tx_amsdu, bool, 0644);
/* WMM information IE */
static const u8 wmm_info_ie[] = { WLAN_EID_VENDOR_SPECIFIC, 0x07,
@@ -64,21 +64,6 @@ static u8 tos_to_tid[] = {
0x07 /* 1 1 1 AC_VO */
};
-/*
- * This table inverses the tos_to_tid operation to get a priority
- * which is in sequential order, and can be compared.
- * Use this to compare the priority of two different TIDs.
- */
-static u8 tos_to_tid_inv[] = {
- 0x02, /* from tos_to_tid[2] = 0 */
- 0x00, /* from tos_to_tid[0] = 1 */
- 0x01, /* from tos_to_tid[1] = 2 */
- 0x03,
- 0x04,
- 0x05,
- 0x06,
- 0x07};
-
static u8 ac_to_tid[4][2] = { {1, 2}, {0, 3}, {4, 5}, {6, 7} };
/*
@@ -175,8 +160,15 @@ mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra)
break;
ra_list->is_11n_enabled = 0;
+ ra_list->tdls_link = false;
if (!mwifiex_queuing_ra_based(priv)) {
- ra_list->is_11n_enabled = IS_11N_ENABLED(priv);
+ if (mwifiex_get_tdls_link_status(priv, ra) ==
+ TDLS_SETUP_COMPLETE) {
+ ra_list->is_11n_enabled =
+ mwifiex_tdls_peer_11n_enabled(priv, ra);
+ } else {
+ ra_list->is_11n_enabled = IS_11N_ENABLED(priv);
+ }
} else {
ra_list->is_11n_enabled =
mwifiex_is_sta_11n_enabled(priv, node);
@@ -213,8 +205,9 @@ static void mwifiex_wmm_default_queue_priorities(struct mwifiex_private *priv)
* This function map ACs to TIDs.
*/
static void
-mwifiex_wmm_queue_priorities_tid(struct mwifiex_wmm_desc *wmm)
+mwifiex_wmm_queue_priorities_tid(struct mwifiex_private *priv)
{
+ struct mwifiex_wmm_desc *wmm = &priv->wmm;
u8 *queue_priority = wmm->queue_priority;
int i;
@@ -224,7 +217,7 @@ mwifiex_wmm_queue_priorities_tid(struct mwifiex_wmm_desc *wmm)
}
for (i = 0; i < MAX_NUM_TID; ++i)
- tos_to_tid_inv[tos_to_tid[i]] = (u8)i;
+ priv->tos_to_tid_inv[tos_to_tid[i]] = (u8)i;
atomic_set(&wmm->highest_queued_prio, HIGH_PRIO_TID);
}
@@ -285,7 +278,7 @@ mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
}
}
- mwifiex_wmm_queue_priorities_tid(&priv->wmm);
+ mwifiex_wmm_queue_priorities_tid(priv);
}
/*
@@ -388,8 +381,7 @@ mwifiex_wmm_convert_tos_to_ac(struct mwifiex_adapter *adapter, u32 tos)
* AP is disabled (due to call admission control (ACM bit). Mapping
* of TID to AC is taken care of internally.
*/
-static u8
-mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid)
+u8 mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid)
{
enum mwifiex_wmm_ac_e ac, ac_down;
u8 new_tid;
@@ -421,9 +413,17 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)
continue;
for (i = 0; i < MAX_NUM_TID; ++i) {
- priv->aggr_prio_tbl[i].amsdu = tos_to_tid_inv[i];
- priv->aggr_prio_tbl[i].ampdu_ap = tos_to_tid_inv[i];
- priv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i];
+ if (!disable_tx_amsdu &&
+ adapter->tx_buf_size > MWIFIEX_TX_DATA_BUF_SIZE_2K)
+ priv->aggr_prio_tbl[i].amsdu =
+ priv->tos_to_tid_inv[i];
+ else
+ priv->aggr_prio_tbl[i].amsdu =
+ BA_STREAM_NOT_ALLOWED;
+ priv->aggr_prio_tbl[i].ampdu_ap =
+ priv->tos_to_tid_inv[i];
+ priv->aggr_prio_tbl[i].ampdu_user =
+ priv->tos_to_tid_inv[i];
}
priv->aggr_prio_tbl[6].amsdu
@@ -546,6 +546,7 @@ void
mwifiex_clean_txrx(struct mwifiex_private *priv)
{
unsigned long flags;
+ struct sk_buff *skb, *tmp;
mwifiex_11n_cleanup_reorder_tbl(priv);
spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
@@ -559,9 +560,13 @@ mwifiex_clean_txrx(struct mwifiex_private *priv)
mwifiex_wmm_delete_all_ralist(priv);
memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid));
- if (priv->adapter->if_ops.clean_pcie_ring)
+ if (priv->adapter->if_ops.clean_pcie_ring &&
+ !priv->adapter->surprise_removed)
priv->adapter->if_ops.clean_pcie_ring(priv->adapter);
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+
+ skb_queue_walk_safe(&priv->tdls_txq, skb, tmp)
+ mwifiex_write_data_complete(priv->adapter, skb, 0, -1);
}
/*
@@ -590,7 +595,7 @@ mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid,
* If no such node is found, a new node is added first and then
* retrieved.
*/
-static struct mwifiex_ra_list_tbl *
+struct mwifiex_ra_list_tbl *
mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, u8 *ra_addr)
{
struct mwifiex_ra_list_tbl *ra_list;
@@ -640,6 +645,21 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
struct mwifiex_ra_list_tbl *ra_list;
u8 ra[ETH_ALEN], tid_down;
unsigned long flags;
+ struct list_head list_head;
+ int tdls_status = TDLS_NOT_SETUP;
+ struct ethhdr *eth_hdr = (struct ethhdr *)skb->data;
+ struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
+
+ memcpy(ra, eth_hdr->h_dest, ETH_ALEN);
+
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA &&
+ ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) {
+ if (ntohs(eth_hdr->h_proto) == ETH_P_TDLS)
+ dev_dbg(adapter->dev,
+ "TDLS setup packet for %pM. Don't block\n", ra);
+ else
+ tdls_status = mwifiex_get_tdls_link_status(priv, ra);
+ }
if (!priv->media_connected && !mwifiex_is_skb_mgmt_frame(skb)) {
dev_dbg(adapter->dev, "data: drop packet in disconnect\n");
@@ -658,12 +678,27 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
have only 1 raptr for a tid in case of infra */
if (!mwifiex_queuing_ra_based(priv) &&
!mwifiex_is_skb_mgmt_frame(skb)) {
- if (!list_empty(&priv->wmm.tid_tbl_ptr[tid_down].ra_list))
- ra_list = list_first_entry(
- &priv->wmm.tid_tbl_ptr[tid_down].ra_list,
- struct mwifiex_ra_list_tbl, list);
- else
- ra_list = NULL;
+ switch (tdls_status) {
+ case TDLS_SETUP_COMPLETE:
+ ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down,
+ ra);
+ tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT;
+ break;
+ case TDLS_SETUP_INPROGRESS:
+ skb_queue_tail(&priv->tdls_txq, skb);
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+ flags);
+ return;
+ default:
+ list_head = priv->wmm.tid_tbl_ptr[tid_down].ra_list;
+ if (!list_empty(&list_head))
+ ra_list = list_first_entry(
+ &list_head, struct mwifiex_ra_list_tbl,
+ list);
+ else
+ ra_list = NULL;
+ break;
+ }
} else {
memcpy(ra, skb->data, ETH_ALEN);
if (ra[0] & 0x01 || mwifiex_is_skb_mgmt_frame(skb))
@@ -683,9 +718,9 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
ra_list->total_pkt_count++;
if (atomic_read(&priv->wmm.highest_queued_prio) <
- tos_to_tid_inv[tid_down])
+ priv->tos_to_tid_inv[tid_down])
atomic_set(&priv->wmm.highest_queued_prio,
- tos_to_tid_inv[tid_down]);
+ priv->tos_to_tid_inv[tid_down]);
atomic_inc(&priv->wmm.tx_pkts_queued);
@@ -1218,15 +1253,24 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
if (!ptr->is_11n_enabled ||
mwifiex_is_ba_stream_setup(priv, ptr, tid) ||
- priv->wps.session_enable ||
- ((priv->sec_info.wpa_enabled ||
- priv->sec_info.wpa2_enabled) &&
- !priv->wpa_is_gtk_set)) {
- mwifiex_send_single_packet(priv, ptr, ptr_index, flags);
- /* ra_list_spinlock has been freed in
- mwifiex_send_single_packet() */
+ priv->wps.session_enable) {
+ if (ptr->is_11n_enabled &&
+ mwifiex_is_ba_stream_setup(priv, ptr, tid) &&
+ mwifiex_is_amsdu_in_ampdu_allowed(priv, ptr, tid) &&
+ mwifiex_is_amsdu_allowed(priv, tid) &&
+ mwifiex_is_11n_aggragation_possible(priv, ptr,
+ adapter->tx_buf_size))
+ mwifiex_11n_aggregate_pkt(priv, ptr, ptr_index, flags);
+ /* ra_list_spinlock has been freed in
+ * mwifiex_11n_aggregate_pkt()
+ */
+ else
+ mwifiex_send_single_packet(priv, ptr, ptr_index, flags);
+ /* ra_list_spinlock has been freed in
+ * mwifiex_send_single_packet()
+ */
} else {
- if (mwifiex_is_ampdu_allowed(priv, tid) &&
+ if (mwifiex_is_ampdu_allowed(priv, ptr, tid) &&
ptr->ba_pkt_count > ptr->ba_packet_thr) {
if (mwifiex_space_avail_for_new_ba_stream(adapter)) {
mwifiex_create_ba_tbl(priv, ptr->ra, tid,
@@ -1239,7 +1283,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
mwifiex_send_delba(priv, tid_del, ra, 1);
}
}
- if (enable_tx_amsdu && mwifiex_is_amsdu_allowed(priv, tid) &&
+ if (mwifiex_is_amsdu_allowed(priv, tid) &&
mwifiex_is_11n_aggragation_possible(priv, ptr,
adapter->tx_buf_size))
mwifiex_11n_aggregate_pkt(priv, ptr, ptr_index, flags);
diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h
index 0f129d498fb1..83e42083ebff 100644
--- a/drivers/net/wireless/mwifiex/wmm.h
+++ b/drivers/net/wireless/mwifiex/wmm.h
@@ -34,6 +34,21 @@ enum ieee_types_wmm_ecw_bitmasks {
static const u16 mwifiex_1d_to_wmm_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
/*
+ * This table inverses the tos_to_tid operation to get a priority
+ * which is in sequential order, and can be compared.
+ * Use this to compare the priority of two different TIDs.
+ */
+static const u8 tos_to_tid_inv[] = {
+ 0x02, /* from tos_to_tid[2] = 0 */
+ 0x00, /* from tos_to_tid[0] = 1 */
+ 0x01, /* from tos_to_tid[1] = 2 */
+ 0x03,
+ 0x04,
+ 0x05,
+ 0x06,
+ 0x07};
+
+/*
* This function retrieves the TID of the given RA list.
*/
static inline int
@@ -107,5 +122,8 @@ void mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
void mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv);
int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
const struct host_cmd_ds_command *resp);
+struct mwifiex_ra_list_tbl *
+mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, u8 *ra_addr);
+u8 mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid);
#endif /* !_MWIFIEX_WMM_H_ */
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 4987c3f942ce..3c0a0a86ba12 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -81,6 +81,9 @@ MODULE_PARM_DESC(ap_mode_default,
*/
#define MWL8K_HW_TIMER_REGISTER 0x0000a600
+#define BBU_RXRDY_CNT_REG 0x0000a860
+#define NOK_CCA_CNT_REG 0x0000a6a0
+#define BBU_AVG_NOISE_VAL 0x67
#define MWL8K_A2H_EVENTS (MWL8K_A2H_INT_DUMMY | \
MWL8K_A2H_INT_CHNL_SWITCHED | \
@@ -112,6 +115,8 @@ MODULE_PARM_DESC(ap_mode_default,
*/
#define MWL8K_NUM_AMPDU_STREAMS (TOTAL_HW_TX_QUEUES - 1)
+#define MWL8K_NUM_CHANS 18
+
struct rxd_ops {
int rxd_size;
void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr);
@@ -289,6 +294,12 @@ struct mwl8k_priv {
/* bitmap of running BSSes */
u32 running_bsses;
+
+ /* ACS related */
+ bool sw_scan_start;
+ struct ieee80211_channel *acs_chan;
+ unsigned long channel_time;
+ struct survey_info survey[MWL8K_NUM_CHANS];
};
#define MAX_WEP_KEY_LEN 13
@@ -396,6 +407,7 @@ static const struct ieee80211_rate mwl8k_rates_50[] = {
#define MWL8K_CMD_SET_HW_SPEC 0x0004
#define MWL8K_CMD_MAC_MULTICAST_ADR 0x0010
#define MWL8K_CMD_GET_STAT 0x0014
+#define MWL8K_CMD_BBP_REG_ACCESS 0x001a
#define MWL8K_CMD_RADIO_CONTROL 0x001c
#define MWL8K_CMD_RF_TX_POWER 0x001e
#define MWL8K_CMD_TX_POWER 0x001f
@@ -2987,6 +2999,47 @@ static int mwl8k_cmd_set_pre_scan(struct ieee80211_hw *hw)
}
/*
+ * CMD_BBP_REG_ACCESS.
+ */
+struct mwl8k_cmd_bbp_reg_access {
+ struct mwl8k_cmd_pkt header;
+ __le16 action;
+ __le16 offset;
+ u8 value;
+ u8 rsrv[3];
+} __packed;
+
+static int
+mwl8k_cmd_bbp_reg_access(struct ieee80211_hw *hw,
+ u16 action,
+ u16 offset,
+ u8 *value)
+{
+ struct mwl8k_cmd_bbp_reg_access *cmd;
+ int rc;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_BBP_REG_ACCESS);
+ cmd->header.length = cpu_to_le16(sizeof(*cmd));
+ cmd->action = cpu_to_le16(action);
+ cmd->offset = cpu_to_le16(offset);
+
+ rc = mwl8k_post_cmd(hw, &cmd->header);
+
+ if (!rc)
+ *value = cmd->value;
+ else
+ *value = 0;
+
+ kfree(cmd);
+
+ return rc;
+}
+
+/*
* CMD_SET_POST_SCAN.
*/
struct mwl8k_cmd_set_post_scan {
@@ -3016,6 +3069,64 @@ mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, const __u8 *mac)
return rc;
}
+static int freq_to_idx(struct mwl8k_priv *priv, int freq)
+{
+ struct ieee80211_supported_band *sband;
+ int band, ch, idx = 0;
+
+ for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) {
+ sband = priv->hw->wiphy->bands[band];
+ if (!sband)
+ continue;
+
+ for (ch = 0; ch < sband->n_channels; ch++, idx++)
+ if (sband->channels[ch].center_freq == freq)
+ goto exit;
+ }
+
+exit:
+ return idx;
+}
+
+static void mwl8k_update_survey(struct mwl8k_priv *priv,
+ struct ieee80211_channel *channel)
+{
+ u32 cca_cnt, rx_rdy;
+ s8 nf = 0, idx;
+ struct survey_info *survey;
+
+ idx = freq_to_idx(priv, priv->acs_chan->center_freq);
+ if (idx >= MWL8K_NUM_CHANS) {
+ wiphy_err(priv->hw->wiphy, "Failed to update survey\n");
+ return;
+ }
+
+ survey = &priv->survey[idx];
+
+ cca_cnt = ioread32(priv->regs + NOK_CCA_CNT_REG);
+ cca_cnt /= 1000; /* uSecs to mSecs */
+ survey->channel_time_busy = (u64) cca_cnt;
+
+ rx_rdy = ioread32(priv->regs + BBU_RXRDY_CNT_REG);
+ rx_rdy /= 1000; /* uSecs to mSecs */
+ survey->channel_time_rx = (u64) rx_rdy;
+
+ priv->channel_time = jiffies - priv->channel_time;
+ survey->channel_time = jiffies_to_msecs(priv->channel_time);
+
+ survey->channel = channel;
+
+ mwl8k_cmd_bbp_reg_access(priv->hw, 0, BBU_AVG_NOISE_VAL, &nf);
+
+ /* Make sure sign is negative else ACS at hostapd fails */
+ survey->noise = nf * -1;
+
+ survey->filled = SURVEY_INFO_NOISE_DBM |
+ SURVEY_INFO_CHANNEL_TIME |
+ SURVEY_INFO_CHANNEL_TIME_BUSY |
+ SURVEY_INFO_CHANNEL_TIME_RX;
+}
+
/*
* CMD_SET_RF_CHANNEL.
*/
@@ -3033,6 +3144,7 @@ static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw,
enum nl80211_channel_type channel_type =
cfg80211_get_chandef_type(&conf->chandef);
struct mwl8k_cmd_set_rf_channel *cmd;
+ struct mwl8k_priv *priv = hw->priv;
int rc;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
@@ -3049,13 +3161,29 @@ static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw,
else if (channel->band == IEEE80211_BAND_5GHZ)
cmd->channel_flags |= cpu_to_le32(0x00000004);
- if (channel_type == NL80211_CHAN_NO_HT ||
- channel_type == NL80211_CHAN_HT20)
+ if (!priv->sw_scan_start) {
+ if (channel_type == NL80211_CHAN_NO_HT ||
+ channel_type == NL80211_CHAN_HT20)
+ cmd->channel_flags |= cpu_to_le32(0x00000080);
+ else if (channel_type == NL80211_CHAN_HT40MINUS)
+ cmd->channel_flags |= cpu_to_le32(0x000001900);
+ else if (channel_type == NL80211_CHAN_HT40PLUS)
+ cmd->channel_flags |= cpu_to_le32(0x000000900);
+ } else {
cmd->channel_flags |= cpu_to_le32(0x00000080);
- else if (channel_type == NL80211_CHAN_HT40MINUS)
- cmd->channel_flags |= cpu_to_le32(0x000001900);
- else if (channel_type == NL80211_CHAN_HT40PLUS)
- cmd->channel_flags |= cpu_to_le32(0x000000900);
+ }
+
+ if (priv->sw_scan_start) {
+ /* Store current channel stats
+ * before switching to newer one.
+ * This will be processed only for AP fw.
+ */
+ if (priv->channel_time != 0)
+ mwl8k_update_survey(priv, priv->acs_chan);
+
+ priv->channel_time = jiffies;
+ priv->acs_chan = channel;
+ }
rc = mwl8k_post_cmd(hw, &cmd->header);
kfree(cmd);
@@ -5263,6 +5391,27 @@ static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx,
{
struct mwl8k_priv *priv = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
+ struct ieee80211_supported_band *sband;
+
+ if (priv->ap_fw) {
+ sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ];
+
+ if (sband && idx >= sband->n_channels) {
+ idx -= sband->n_channels;
+ sband = NULL;
+ }
+
+ if (!sband)
+ sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ];
+
+ if (!sband || idx >= sband->n_channels)
+ return -ENOENT;
+
+ memcpy(survey, &priv->survey[idx], sizeof(*survey));
+ survey->channel = &sband->channels[idx];
+
+ return 0;
+ }
if (idx != 0)
return -ENOENT;
@@ -5406,6 +5555,40 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
return rc;
}
+static void mwl8k_sw_scan_start(struct ieee80211_hw *hw)
+{
+ struct mwl8k_priv *priv = hw->priv;
+ u8 tmp;
+
+ if (!priv->ap_fw)
+ return;
+
+ /* clear all stats */
+ priv->channel_time = 0;
+ ioread32(priv->regs + BBU_RXRDY_CNT_REG);
+ ioread32(priv->regs + NOK_CCA_CNT_REG);
+ mwl8k_cmd_bbp_reg_access(priv->hw, 0, BBU_AVG_NOISE_VAL, &tmp);
+
+ priv->sw_scan_start = true;
+}
+
+static void mwl8k_sw_scan_complete(struct ieee80211_hw *hw)
+{
+ struct mwl8k_priv *priv = hw->priv;
+ u8 tmp;
+
+ if (!priv->ap_fw)
+ return;
+
+ priv->sw_scan_start = false;
+
+ /* clear all stats */
+ priv->channel_time = 0;
+ ioread32(priv->regs + BBU_RXRDY_CNT_REG);
+ ioread32(priv->regs + NOK_CCA_CNT_REG);
+ mwl8k_cmd_bbp_reg_access(priv->hw, 0, BBU_AVG_NOISE_VAL, &tmp);
+}
+
static const struct ieee80211_ops mwl8k_ops = {
.tx = mwl8k_tx,
.start = mwl8k_start,
@@ -5424,6 +5607,8 @@ static const struct ieee80211_ops mwl8k_ops = {
.get_stats = mwl8k_get_stats,
.get_survey = mwl8k_get_survey,
.ampdu_action = mwl8k_ampdu_action,
+ .sw_scan_start = mwl8k_sw_scan_start,
+ .sw_scan_complete = mwl8k_sw_scan_complete,
};
static void mwl8k_finalize_join_worker(struct work_struct *work)
diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
index d01edd2c50c5..a9e94b6db5b7 100644
--- a/drivers/net/wireless/orinoco/cfg.c
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -59,7 +59,8 @@ int orinoco_wiphy_register(struct wiphy *wiphy)
for (i = 0; i < NUM_CHANNELS; i++) {
if (priv->channel_mask & (1 << i)) {
priv->channels[i].center_freq =
- ieee80211_dsss_chan_to_freq(i + 1);
+ ieee80211_channel_to_frequency(i + 1,
+ IEEE80211_BAND_2GHZ);
channels++;
}
}
@@ -177,7 +178,7 @@ static int orinoco_set_monitor_channel(struct wiphy *wiphy,
if (chandef->chan->band != IEEE80211_BAND_2GHZ)
return -EINVAL;
- channel = ieee80211_freq_to_dsss_chan(chandef->chan->center_freq);
+ channel = ieee80211_frequency_to_channel(chandef->chan->center_freq);
if ((channel < 1) || (channel > NUM_CHANNELS) ||
!(priv->channel_mask & (1 << (channel - 1))))
diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c
index c09c8437c0b8..49300d04efdf 100644
--- a/drivers/net/wireless/orinoco/hw.c
+++ b/drivers/net/wireless/orinoco/hw.c
@@ -1193,7 +1193,7 @@ int orinoco_hw_get_freq(struct orinoco_private *priv)
goto out;
}
- freq = ieee80211_dsss_chan_to_freq(channel);
+ freq = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
out:
orinoco_unlock(priv, &flags);
diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c
index e8c5714bfd11..e175b9b8561b 100644
--- a/drivers/net/wireless/orinoco/scan.c
+++ b/drivers/net/wireless/orinoco/scan.c
@@ -110,7 +110,8 @@ static void orinoco_add_hostscan_result(struct orinoco_private *priv,
break;
}
- freq = ieee80211_dsss_chan_to_freq(le16_to_cpu(bss->a.channel));
+ freq = ieee80211_channel_to_frequency(
+ le16_to_cpu(bss->a.channel), IEEE80211_BAND_2GHZ);
channel = ieee80211_get_channel(wiphy, freq);
if (!channel) {
printk(KERN_DEBUG "Invalid channel designation %04X(%04X)",
@@ -146,7 +147,7 @@ void orinoco_add_extscan_result(struct orinoco_private *priv,
ie_len = len - sizeof(*bss);
ie = cfg80211_find_ie(WLAN_EID_DS_PARAMS, bss->data, ie_len);
chan = ie ? ie[2] : 0;
- freq = ieee80211_dsss_chan_to_freq(chan);
+ freq = ieee80211_channel_to_frequency(chan, IEEE80211_BAND_2GHZ);
channel = ieee80211_get_channel(wiphy, freq);
timestamp = le64_to_cpu(bss->timestamp);
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c
index 3b5508f982e8..b7a867b50b94 100644
--- a/drivers/net/wireless/orinoco/wext.c
+++ b/drivers/net/wireless/orinoco/wext.c
@@ -444,7 +444,7 @@ static int orinoco_ioctl_setfreq(struct net_device *dev,
for (i = 0; i < (6 - frq->e); i++)
denom *= 10;
- chan = ieee80211_freq_to_dsss_chan(frq->m / denom);
+ chan = ieee80211_frequency_to_channel(frq->m / denom);
}
if ((chan < 1) || (chan > NUM_CHANNELS) ||
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index 6e635cfa24c8..043bd1c23c19 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -513,7 +513,7 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
if (!buf)
return -ENOMEM;
- left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size);
+ left = block_size = min_t(size_t, P54U_FW_BLOCK, priv->fw->size);
strcpy(buf, p54u_firmware_upload_3887);
left -= strlen(p54u_firmware_upload_3887);
tmp += strlen(p54u_firmware_upload_3887);
@@ -1053,6 +1053,10 @@ static int p54u_probe(struct usb_interface *intf,
priv->upload_fw = p54u_upload_firmware_net2280;
}
err = p54u_load_firmware(dev, intf);
+ if (err) {
+ usb_put_dev(udev);
+ p54_free_common(dev);
+ }
return err;
}
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 78fa64d3f223..ecbb0546cf3e 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -644,7 +644,7 @@ prism54_translate_bss(struct net_device *ndev, struct iw_request_info *info,
wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie);
if (wpa_ie_len > 0) {
iwe.cmd = IWEVGENIE;
- iwe.u.data.length = min(wpa_ie_len, (size_t)MAX_WPA_IE_LEN);
+ iwe.u.data.length = min_t(size_t, wpa_ie_len, MAX_WPA_IE_LEN);
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
&iwe, wpa_ie);
}
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 5028557aa18a..39d22a154341 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -1290,7 +1290,8 @@ static int set_channel(struct usbnet *usbdev, int channel)
if (is_associated(usbdev))
return 0;
- dsconfig = ieee80211_dsss_chan_to_freq(channel) * 1000;
+ dsconfig = 1000 *
+ ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
len = sizeof(config);
ret = rndis_query_oid(usbdev,
@@ -2835,7 +2836,9 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
bssid, req_ie, req_ie_len,
resp_ie, resp_ie_len, GFP_KERNEL);
} else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
- cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL);
+ cfg80211_ibss_joined(usbdev->net, bssid,
+ get_current_channel(usbdev, NULL),
+ GFP_KERNEL);
kfree(info);
diff --git a/drivers/net/wireless/rsi/Kconfig b/drivers/net/wireless/rsi/Kconfig
new file mode 100644
index 000000000000..35245f994c10
--- /dev/null
+++ b/drivers/net/wireless/rsi/Kconfig
@@ -0,0 +1,30 @@
+config RSI_91X
+ tristate "Redpine Signals Inc 91x WLAN driver support"
+ depends on MAC80211
+ ---help---
+ This option enabes support for RSI 1x1 devices.
+ Select M (recommended), if you have a RSI 1x1 wireless module.
+
+config RSI_DEBUGFS
+ bool "Redpine Signals Inc debug support"
+ depends on RSI_91X
+ default y
+ ---help---
+ Say Y, if you would like to enable debug support. This option
+ creates debugfs entries
+
+config RSI_SDIO
+ tristate "Redpine Signals SDIO bus support"
+ depends on MMC && RSI_91X
+ default m
+ ---help---
+ This option enables the SDIO bus support in rsi drivers.
+ Select M (recommended), if you have a RSI 1x1 wireless module.
+
+config RSI_USB
+ tristate "Redpine Signals USB bus support"
+ depends on USB && RSI_91X
+ default m
+ ---help---
+ This option enables the USB bus support in rsi drivers.
+ Select M (recommended), if you have a RSI 1x1 wireless module.
diff --git a/drivers/net/wireless/rsi/Makefile b/drivers/net/wireless/rsi/Makefile
new file mode 100644
index 000000000000..25828b692756
--- /dev/null
+++ b/drivers/net/wireless/rsi/Makefile
@@ -0,0 +1,12 @@
+rsi_91x-y += rsi_91x_main.o
+rsi_91x-y += rsi_91x_core.o
+rsi_91x-y += rsi_91x_mac80211.o
+rsi_91x-y += rsi_91x_mgmt.o
+rsi_91x-y += rsi_91x_pkt.o
+rsi_91x-$(CONFIG_RSI_DEBUGFS) += rsi_91x_debugfs.o
+
+rsi_usb-y += rsi_91x_usb.o rsi_91x_usb_ops.o
+rsi_sdio-y += rsi_91x_sdio.o rsi_91x_sdio_ops.o
+obj-$(CONFIG_RSI_91X) += rsi_91x.o
+obj-$(CONFIG_RSI_SDIO) += rsi_sdio.o
+obj-$(CONFIG_RSI_USB) += rsi_usb.o
diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c
new file mode 100644
index 000000000000..e89535e86caf
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_91x_core.c
@@ -0,0 +1,342 @@
+/**
+ * Copyright (c) 2014 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "rsi_mgmt.h"
+#include "rsi_common.h"
+
+/**
+ * rsi_determine_min_weight_queue() - This function determines the queue with
+ * the min weight.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: q_num: Corresponding queue number.
+ */
+static u8 rsi_determine_min_weight_queue(struct rsi_common *common)
+{
+ struct wmm_qinfo *tx_qinfo = common->tx_qinfo;
+ u32 q_len = 0;
+ u8 ii = 0;
+
+ for (ii = 0; ii < NUM_EDCA_QUEUES; ii++) {
+ q_len = skb_queue_len(&common->tx_queue[ii]);
+ if ((tx_qinfo[ii].pkt_contended) && q_len) {
+ common->min_weight = tx_qinfo[ii].weight;
+ break;
+ }
+ }
+ return ii;
+}
+
+/**
+ * rsi_recalculate_weights() - This function recalculates the weights
+ * corresponding to each queue.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: recontend_queue bool variable
+ */
+static bool rsi_recalculate_weights(struct rsi_common *common)
+{
+ struct wmm_qinfo *tx_qinfo = common->tx_qinfo;
+ bool recontend_queue = false;
+ u8 ii = 0;
+ u32 q_len = 0;
+
+ for (ii = 0; ii < NUM_EDCA_QUEUES; ii++) {
+ q_len = skb_queue_len(&common->tx_queue[ii]);
+ /* Check for the need of contention */
+ if (q_len) {
+ if (tx_qinfo[ii].pkt_contended) {
+ tx_qinfo[ii].weight =
+ ((tx_qinfo[ii].weight > common->min_weight) ?
+ tx_qinfo[ii].weight - common->min_weight : 0);
+ } else {
+ tx_qinfo[ii].pkt_contended = 1;
+ tx_qinfo[ii].weight = tx_qinfo[ii].wme_params;
+ recontend_queue = true;
+ }
+ } else { /* No packets so no contention */
+ tx_qinfo[ii].weight = 0;
+ tx_qinfo[ii].pkt_contended = 0;
+ }
+ }
+
+ return recontend_queue;
+}
+
+/**
+ * rsi_core_determine_hal_queue() - This function determines the queue from
+ * which packet has to be dequeued.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: q_num: Corresponding queue number on success.
+ */
+static u8 rsi_core_determine_hal_queue(struct rsi_common *common)
+{
+ bool recontend_queue = false;
+ u32 q_len = 0;
+ u8 q_num = INVALID_QUEUE;
+ u8 ii, min = 0;
+
+ if (skb_queue_len(&common->tx_queue[MGMT_SOFT_Q])) {
+ if (!common->mgmt_q_block)
+ q_num = MGMT_SOFT_Q;
+ return q_num;
+ }
+
+ if (common->pkt_cnt != 0) {
+ --common->pkt_cnt;
+ return common->selected_qnum;
+ }
+
+get_queue_num:
+ q_num = 0;
+ recontend_queue = false;
+
+ q_num = rsi_determine_min_weight_queue(common);
+ q_len = skb_queue_len(&common->tx_queue[ii]);
+ ii = q_num;
+
+ /* Selecting the queue with least back off */
+ for (; ii < NUM_EDCA_QUEUES; ii++) {
+ if (((common->tx_qinfo[ii].pkt_contended) &&
+ (common->tx_qinfo[ii].weight < min)) && q_len) {
+ min = common->tx_qinfo[ii].weight;
+ q_num = ii;
+ }
+ }
+
+ common->tx_qinfo[q_num].pkt_contended = 0;
+ /* Adjust the back off values for all queues again */
+ recontend_queue = rsi_recalculate_weights(common);
+
+ q_len = skb_queue_len(&common->tx_queue[q_num]);
+ if (!q_len) {
+ /* If any queues are freshly contended and the selected queue
+ * doesn't have any packets
+ * then get the queue number again with fresh values
+ */
+ if (recontend_queue)
+ goto get_queue_num;
+
+ q_num = INVALID_QUEUE;
+ return q_num;
+ }
+
+ common->selected_qnum = q_num;
+ q_len = skb_queue_len(&common->tx_queue[q_num]);
+
+ switch (common->selected_qnum) {
+ case VO_Q:
+ if (q_len > MAX_CONTINUOUS_VO_PKTS)
+ common->pkt_cnt = (MAX_CONTINUOUS_VO_PKTS - 1);
+ else
+ common->pkt_cnt = --q_len;
+ break;
+
+ case VI_Q:
+ if (q_len > MAX_CONTINUOUS_VI_PKTS)
+ common->pkt_cnt = (MAX_CONTINUOUS_VI_PKTS - 1);
+ else
+ common->pkt_cnt = --q_len;
+
+ break;
+
+ default:
+ common->pkt_cnt = 0;
+ break;
+ }
+
+ return q_num;
+}
+
+/**
+ * rsi_core_queue_pkt() - This functions enqueues the packet to the queue
+ * specified by the queue number.
+ * @common: Pointer to the driver private structure.
+ * @skb: Pointer to the socket buffer structure.
+ *
+ * Return: None.
+ */
+static void rsi_core_queue_pkt(struct rsi_common *common,
+ struct sk_buff *skb)
+{
+ u8 q_num = skb->priority;
+ if (q_num >= NUM_SOFT_QUEUES) {
+ rsi_dbg(ERR_ZONE, "%s: Invalid Queue Number: q_num = %d\n",
+ __func__, q_num);
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ skb_queue_tail(&common->tx_queue[q_num], skb);
+}
+
+/**
+ * rsi_core_dequeue_pkt() - This functions dequeues the packet from the queue
+ * specified by the queue number.
+ * @common: Pointer to the driver private structure.
+ * @q_num: Queue number.
+ *
+ * Return: Pointer to sk_buff structure.
+ */
+static struct sk_buff *rsi_core_dequeue_pkt(struct rsi_common *common,
+ u8 q_num)
+{
+ if (q_num >= NUM_SOFT_QUEUES) {
+ rsi_dbg(ERR_ZONE, "%s: Invalid Queue Number: q_num = %d\n",
+ __func__, q_num);
+ return NULL;
+ }
+
+ return skb_dequeue(&common->tx_queue[q_num]);
+}
+
+/**
+ * rsi_core_qos_processor() - This function is used to determine the wmm queue
+ * based on the backoff procedure. Data packets are
+ * dequeued from the selected hal queue and sent to
+ * the below layers.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: None.
+ */
+void rsi_core_qos_processor(struct rsi_common *common)
+{
+ struct rsi_hw *adapter = common->priv;
+ struct sk_buff *skb;
+ unsigned long tstamp_1, tstamp_2;
+ u8 q_num;
+ int status;
+
+ tstamp_1 = jiffies;
+ while (1) {
+ q_num = rsi_core_determine_hal_queue(common);
+ rsi_dbg(DATA_TX_ZONE,
+ "%s: Queue number = %d\n", __func__, q_num);
+
+ if (q_num == INVALID_QUEUE) {
+ rsi_dbg(DATA_TX_ZONE, "%s: No More Pkt\n", __func__);
+ break;
+ }
+
+ mutex_lock(&common->tx_rxlock);
+
+ status = adapter->check_hw_queue_status(adapter, q_num);
+ if ((status <= 0)) {
+ mutex_unlock(&common->tx_rxlock);
+ break;
+ }
+
+ if ((q_num < MGMT_SOFT_Q) &&
+ ((skb_queue_len(&common->tx_queue[q_num])) <=
+ MIN_DATA_QUEUE_WATER_MARK)) {
+ if (ieee80211_queue_stopped(adapter->hw, WME_AC(q_num)))
+ ieee80211_wake_queue(adapter->hw,
+ WME_AC(q_num));
+ }
+
+ skb = rsi_core_dequeue_pkt(common, q_num);
+ if (skb == NULL) {
+ mutex_unlock(&common->tx_rxlock);
+ break;
+ }
+
+ if (q_num == MGMT_SOFT_Q)
+ status = rsi_send_mgmt_pkt(common, skb);
+ else
+ status = rsi_send_data_pkt(common, skb);
+
+ if (status) {
+ mutex_unlock(&common->tx_rxlock);
+ break;
+ }
+
+ common->tx_stats.total_tx_pkt_send[q_num]++;
+
+ tstamp_2 = jiffies;
+ mutex_unlock(&common->tx_rxlock);
+
+ if (tstamp_2 > tstamp_1 + (300 * HZ / 1000))
+ schedule();
+ }
+}
+
+/**
+ * rsi_core_xmit() - This function transmits the packets received from mac80211
+ * @common: Pointer to the driver private structure.
+ * @skb: Pointer to the socket buffer structure.
+ *
+ * Return: None.
+ */
+void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb)
+{
+ struct rsi_hw *adapter = common->priv;
+ struct ieee80211_tx_info *info;
+ struct skb_info *tx_params;
+ struct ieee80211_hdr *tmp_hdr = NULL;
+ u8 q_num, tid = 0;
+
+ if ((!skb) || (!skb->len)) {
+ rsi_dbg(ERR_ZONE, "%s: Null skb/zero Length packet\n",
+ __func__);
+ goto xmit_fail;
+ }
+ info = IEEE80211_SKB_CB(skb);
+ tx_params = (struct skb_info *)info->driver_data;
+ tmp_hdr = (struct ieee80211_hdr *)&skb->data[0];
+
+ if (common->fsm_state != FSM_MAC_INIT_DONE) {
+ rsi_dbg(ERR_ZONE, "%s: FSM state not open\n", __func__);
+ goto xmit_fail;
+ }
+
+ if ((ieee80211_is_mgmt(tmp_hdr->frame_control)) ||
+ (ieee80211_is_ctl(tmp_hdr->frame_control))) {
+ q_num = MGMT_SOFT_Q;
+ skb->priority = q_num;
+ } else {
+ if (ieee80211_is_data_qos(tmp_hdr->frame_control)) {
+ tid = (skb->data[24] & IEEE80211_QOS_TID);
+ skb->priority = TID_TO_WME_AC(tid);
+ } else {
+ tid = IEEE80211_NONQOS_TID;
+ skb->priority = BE_Q;
+ }
+ q_num = skb->priority;
+ tx_params->tid = tid;
+ tx_params->sta_id = 0;
+ }
+
+ if ((q_num != MGMT_SOFT_Q) &&
+ ((skb_queue_len(&common->tx_queue[q_num]) + 1) >=
+ DATA_QUEUE_WATER_MARK)) {
+ if (!ieee80211_queue_stopped(adapter->hw, WME_AC(q_num)))
+ ieee80211_stop_queue(adapter->hw, WME_AC(q_num));
+ rsi_set_event(&common->tx_thread.event);
+ goto xmit_fail;
+ }
+
+ rsi_core_queue_pkt(common, skb);
+ rsi_dbg(DATA_TX_ZONE, "%s: ===> Scheduling TX thead <===\n", __func__);
+ rsi_set_event(&common->tx_thread.event);
+
+ return;
+
+xmit_fail:
+ rsi_dbg(ERR_ZONE, "%s: Failed to queue packet\n", __func__);
+ /* Dropping pkt here */
+ ieee80211_free_txskb(common->priv->hw, skb);
+}
diff --git a/drivers/net/wireless/rsi/rsi_91x_debugfs.c b/drivers/net/wireless/rsi/rsi_91x_debugfs.c
new file mode 100644
index 000000000000..7e4ef4554411
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_91x_debugfs.c
@@ -0,0 +1,339 @@
+/**
+ * Copyright (c) 2014 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "rsi_debugfs.h"
+#include "rsi_sdio.h"
+
+/**
+ * rsi_sdio_stats_read() - This function returns the sdio status of the driver.
+ * @seq: Pointer to the sequence file structure.
+ * @data: Pointer to the data.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int rsi_sdio_stats_read(struct seq_file *seq, void *data)
+{
+ struct rsi_common *common = seq->private;
+ struct rsi_hw *adapter = common->priv;
+ struct rsi_91x_sdiodev *dev =
+ (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+
+ seq_printf(seq, "total_sdio_interrupts: %d\n",
+ dev->rx_info.sdio_int_counter);
+ seq_printf(seq, "sdio_msdu_pending_intr_count: %d\n",
+ dev->rx_info.total_sdio_msdu_pending_intr);
+ seq_printf(seq, "sdio_buff_full_count : %d\n",
+ dev->rx_info.buf_full_counter);
+ seq_printf(seq, "sdio_buf_semi_full_count %d\n",
+ dev->rx_info.buf_semi_full_counter);
+ seq_printf(seq, "sdio_unknown_intr_count: %d\n",
+ dev->rx_info.total_sdio_unknown_intr);
+ /* RX Path Stats */
+ seq_printf(seq, "BUFFER FULL STATUS : %d\n",
+ dev->rx_info.buffer_full);
+ seq_printf(seq, "SEMI BUFFER FULL STATUS : %d\n",
+ dev->rx_info.semi_buffer_full);
+ seq_printf(seq, "MGMT BUFFER FULL STATUS : %d\n",
+ dev->rx_info.mgmt_buffer_full);
+ seq_printf(seq, "BUFFER FULL COUNTER : %d\n",
+ dev->rx_info.buf_full_counter);
+ seq_printf(seq, "BUFFER SEMI FULL COUNTER : %d\n",
+ dev->rx_info.buf_semi_full_counter);
+ seq_printf(seq, "MGMT BUFFER FULL COUNTER : %d\n",
+ dev->rx_info.mgmt_buf_full_counter);
+
+ return 0;
+}
+
+/**
+ * rsi_sdio_stats_open() - This funtion calls single open function of seq_file
+ * to open file and read contents from it.
+ * @inode: Pointer to the inode structure.
+ * @file: Pointer to the file structure.
+ *
+ * Return: Pointer to the opened file status: 0 on success, ENOMEM on failure.
+ */
+static int rsi_sdio_stats_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, rsi_sdio_stats_read, inode->i_private);
+}
+
+/**
+ * rsi_version_read() - This function gives driver and firmware version number.
+ * @seq: Pointer to the sequence file structure.
+ * @data: Pointer to the data.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int rsi_version_read(struct seq_file *seq, void *data)
+{
+ struct rsi_common *common = seq->private;
+
+ common->driver_ver.major = 0;
+ common->driver_ver.minor = 1;
+ common->driver_ver.release_num = 0;
+ common->driver_ver.patch_num = 0;
+ seq_printf(seq, "Driver : %x.%d.%d.%d\nLMAC : %d.%d.%d.%d\n",
+ common->driver_ver.major,
+ common->driver_ver.minor,
+ common->driver_ver.release_num,
+ common->driver_ver.patch_num,
+ common->fw_ver.major,
+ common->fw_ver.minor,
+ common->fw_ver.release_num,
+ common->fw_ver.patch_num);
+ return 0;
+}
+
+/**
+ * rsi_version_open() - This funtion calls single open function of seq_file to
+ * open file and read contents from it.
+ * @inode: Pointer to the inode structure.
+ * @file: Pointer to the file structure.
+ *
+ * Return: Pointer to the opened file status: 0 on success, ENOMEM on failure.
+ */
+static int rsi_version_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, rsi_version_read, inode->i_private);
+}
+
+/**
+ * rsi_stats_read() - This function return the status of the driver.
+ * @seq: Pointer to the sequence file structure.
+ * @data: Pointer to the data.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int rsi_stats_read(struct seq_file *seq, void *data)
+{
+ struct rsi_common *common = seq->private;
+
+ unsigned char fsm_state[][32] = {
+ "FSM_CARD_NOT_READY",
+ "FSM_BOOT_PARAMS_SENT",
+ "FSM_EEPROM_READ_MAC_ADDR",
+ "FSM_RESET_MAC_SENT",
+ "FSM_RADIO_CAPS_SENT",
+ "FSM_BB_RF_PROG_SENT",
+ "FSM_MAC_INIT_DONE"
+ };
+ seq_puts(seq, "==> RSI STA DRIVER STATUS <==\n");
+ seq_puts(seq, "DRIVER_FSM_STATE: ");
+
+ if (common->fsm_state <= FSM_MAC_INIT_DONE)
+ seq_printf(seq, "%s", fsm_state[common->fsm_state]);
+
+ seq_printf(seq, "(%d)\n\n", common->fsm_state);
+
+ /* Mgmt TX Path Stats */
+ seq_printf(seq, "total_mgmt_pkt_send : %d\n",
+ common->tx_stats.total_tx_pkt_send[MGMT_SOFT_Q]);
+ seq_printf(seq, "total_mgmt_pkt_queued : %d\n",
+ skb_queue_len(&common->tx_queue[4]));
+ seq_printf(seq, "total_mgmt_pkt_freed : %d\n",
+ common->tx_stats.total_tx_pkt_freed[MGMT_SOFT_Q]);
+
+ /* Data TX Path Stats */
+ seq_printf(seq, "total_data_vo_pkt_send: %8d\t",
+ common->tx_stats.total_tx_pkt_send[VO_Q]);
+ seq_printf(seq, "total_data_vo_pkt_queued: %8d\t",
+ skb_queue_len(&common->tx_queue[0]));
+ seq_printf(seq, "total_vo_pkt_freed: %8d\n",
+ common->tx_stats.total_tx_pkt_freed[VO_Q]);
+ seq_printf(seq, "total_data_vi_pkt_send: %8d\t",
+ common->tx_stats.total_tx_pkt_send[VI_Q]);
+ seq_printf(seq, "total_data_vi_pkt_queued: %8d\t",
+ skb_queue_len(&common->tx_queue[1]));
+ seq_printf(seq, "total_vi_pkt_freed: %8d\n",
+ common->tx_stats.total_tx_pkt_freed[VI_Q]);
+ seq_printf(seq, "total_data_be_pkt_send: %8d\t",
+ common->tx_stats.total_tx_pkt_send[BE_Q]);
+ seq_printf(seq, "total_data_be_pkt_queued: %8d\t",
+ skb_queue_len(&common->tx_queue[2]));
+ seq_printf(seq, "total_be_pkt_freed: %8d\n",
+ common->tx_stats.total_tx_pkt_freed[BE_Q]);
+ seq_printf(seq, "total_data_bk_pkt_send: %8d\t",
+ common->tx_stats.total_tx_pkt_send[BK_Q]);
+ seq_printf(seq, "total_data_bk_pkt_queued: %8d\t",
+ skb_queue_len(&common->tx_queue[3]));
+ seq_printf(seq, "total_bk_pkt_freed: %8d\n",
+ common->tx_stats.total_tx_pkt_freed[BK_Q]);
+
+ seq_puts(seq, "\n");
+ return 0;
+}
+
+/**
+ * rsi_stats_open() - This funtion calls single open function of seq_file to
+ * open file and read contents from it.
+ * @inode: Pointer to the inode structure.
+ * @file: Pointer to the file structure.
+ *
+ * Return: Pointer to the opened file status: 0 on success, ENOMEM on failure.
+ */
+static int rsi_stats_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, rsi_stats_read, inode->i_private);
+}
+
+/**
+ * rsi_debug_zone_read() - This function display the currently enabled debug zones.
+ * @seq: Pointer to the sequence file structure.
+ * @data: Pointer to the data.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int rsi_debug_zone_read(struct seq_file *seq, void *data)
+{
+ rsi_dbg(FSM_ZONE, "%x: rsi_enabled zone", rsi_zone_enabled);
+ seq_printf(seq, "The zones available are %#x\n",
+ rsi_zone_enabled);
+ return 0;
+}
+
+/**
+ * rsi_debug_read() - This funtion calls single open function of seq_file to
+ * open file and read contents from it.
+ * @inode: Pointer to the inode structure.
+ * @file: Pointer to the file structure.
+ *
+ * Return: Pointer to the opened file status: 0 on success, ENOMEM on failure.
+ */
+static int rsi_debug_read(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, rsi_debug_zone_read, inode->i_private);
+}
+
+/**
+ * rsi_debug_zone_write() - This function writes into hal queues as per user
+ * requirement.
+ * @filp: Pointer to the file structure.
+ * @buff: Pointer to the character buffer.
+ * @len: Length of the data to be written into buffer.
+ * @data: Pointer to the data.
+ *
+ * Return: len: Number of bytes read.
+ */
+static ssize_t rsi_debug_zone_write(struct file *filp,
+ const char __user *buff,
+ size_t len,
+ loff_t *data)
+{
+ unsigned long dbg_zone;
+ int ret;
+
+ if (!len)
+ return 0;
+
+ ret = kstrtoul_from_user(buff, len, 16, &dbg_zone);
+
+ if (ret)
+ return ret;
+
+ rsi_zone_enabled = dbg_zone;
+ return len;
+}
+
+#define FOPS(fopen) { \
+ .owner = THIS_MODULE, \
+ .open = (fopen), \
+ .read = seq_read, \
+ .llseek = seq_lseek, \
+}
+
+#define FOPS_RW(fopen, fwrite) { \
+ .owner = THIS_MODULE, \
+ .open = (fopen), \
+ .read = seq_read, \
+ .llseek = seq_lseek, \
+ .write = (fwrite), \
+}
+
+static const struct rsi_dbg_files dev_debugfs_files[] = {
+ {"version", 0644, FOPS(rsi_version_open),},
+ {"stats", 0644, FOPS(rsi_stats_open),},
+ {"debug_zone", 0666, FOPS_RW(rsi_debug_read, rsi_debug_zone_write),},
+ {"sdio_stats", 0644, FOPS(rsi_sdio_stats_open),},
+};
+
+/**
+ * rsi_init_dbgfs() - This function initializes the dbgfs entry.
+ * @adapter: Pointer to the adapter structure.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+int rsi_init_dbgfs(struct rsi_hw *adapter)
+{
+ struct rsi_common *common = adapter->priv;
+ struct rsi_debugfs *dev_dbgfs;
+ char devdir[6];
+ int ii;
+ const struct rsi_dbg_files *files;
+
+ dev_dbgfs = kzalloc(sizeof(*dev_dbgfs), GFP_KERNEL);
+ adapter->dfsentry = dev_dbgfs;
+
+ snprintf(devdir, sizeof(devdir), "%s",
+ wiphy_name(adapter->hw->wiphy));
+ dev_dbgfs->subdir = debugfs_create_dir(devdir, NULL);
+
+ if (IS_ERR(dev_dbgfs->subdir)) {
+ if (dev_dbgfs->subdir == ERR_PTR(-ENODEV))
+ rsi_dbg(ERR_ZONE,
+ "%s:Debugfs has not been mounted\n", __func__);
+ else
+ rsi_dbg(ERR_ZONE, "debugfs:%s not created\n", devdir);
+
+ adapter->dfsentry = NULL;
+ kfree(dev_dbgfs);
+ return (int)PTR_ERR(dev_dbgfs->subdir);
+ } else {
+ for (ii = 0; ii < adapter->num_debugfs_entries; ii++) {
+ files = &dev_debugfs_files[ii];
+ dev_dbgfs->rsi_files[ii] =
+ debugfs_create_file(files->name,
+ files->perms,
+ dev_dbgfs->subdir,
+ common,
+ &files->fops);
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rsi_init_dbgfs);
+
+/**
+ * rsi_remove_dbgfs() - Removes the previously created dbgfs file entries
+ * in the reverse order of creation.
+ * @adapter: Pointer to the adapter structure.
+ *
+ * Return: None.
+ */
+void rsi_remove_dbgfs(struct rsi_hw *adapter)
+{
+ struct rsi_debugfs *dev_dbgfs = adapter->dfsentry;
+
+ if (!dev_dbgfs)
+ return;
+
+ debugfs_remove_recursive(dev_dbgfs->subdir);
+}
+EXPORT_SYMBOL_GPL(rsi_remove_dbgfs);
diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
new file mode 100644
index 000000000000..84164747ace0
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -0,0 +1,1008 @@
+/**
+ * Copyright (c) 2014 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/etherdevice.h>
+#include "rsi_debugfs.h"
+#include "rsi_mgmt.h"
+#include "rsi_common.h"
+
+static const struct ieee80211_channel rsi_2ghz_channels[] = {
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2412,
+ .hw_value = 1 }, /* Channel 1 */
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2417,
+ .hw_value = 2 }, /* Channel 2 */
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2422,
+ .hw_value = 3 }, /* Channel 3 */
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2427,
+ .hw_value = 4 }, /* Channel 4 */
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2432,
+ .hw_value = 5 }, /* Channel 5 */
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2437,
+ .hw_value = 6 }, /* Channel 6 */
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2442,
+ .hw_value = 7 }, /* Channel 7 */
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2447,
+ .hw_value = 8 }, /* Channel 8 */
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2452,
+ .hw_value = 9 }, /* Channel 9 */
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2457,
+ .hw_value = 10 }, /* Channel 10 */
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2462,
+ .hw_value = 11 }, /* Channel 11 */
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2467,
+ .hw_value = 12 }, /* Channel 12 */
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2472,
+ .hw_value = 13 }, /* Channel 13 */
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2484,
+ .hw_value = 14 }, /* Channel 14 */
+};
+
+static const struct ieee80211_channel rsi_5ghz_channels[] = {
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5180,
+ .hw_value = 36, }, /* Channel 36 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5200,
+ .hw_value = 40, }, /* Channel 40 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5220,
+ .hw_value = 44, }, /* Channel 44 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5240,
+ .hw_value = 48, }, /* Channel 48 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5260,
+ .hw_value = 52, }, /* Channel 52 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5280,
+ .hw_value = 56, }, /* Channel 56 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5300,
+ .hw_value = 60, }, /* Channel 60 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5320,
+ .hw_value = 64, }, /* Channel 64 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5500,
+ .hw_value = 100, }, /* Channel 100 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5520,
+ .hw_value = 104, }, /* Channel 104 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5540,
+ .hw_value = 108, }, /* Channel 108 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5560,
+ .hw_value = 112, }, /* Channel 112 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5580,
+ .hw_value = 116, }, /* Channel 116 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5600,
+ .hw_value = 120, }, /* Channel 120 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5620,
+ .hw_value = 124, }, /* Channel 124 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5640,
+ .hw_value = 128, }, /* Channel 128 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5660,
+ .hw_value = 132, }, /* Channel 132 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5680,
+ .hw_value = 136, }, /* Channel 136 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5700,
+ .hw_value = 140, }, /* Channel 140 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5745,
+ .hw_value = 149, }, /* Channel 149 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5765,
+ .hw_value = 153, }, /* Channel 153 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5785,
+ .hw_value = 157, }, /* Channel 157 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5805,
+ .hw_value = 161, }, /* Channel 161 */
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5825,
+ .hw_value = 165, }, /* Channel 165 */
+};
+
+struct ieee80211_rate rsi_rates[12] = {
+ { .bitrate = STD_RATE_01 * 5, .hw_value = RSI_RATE_1 },
+ { .bitrate = STD_RATE_02 * 5, .hw_value = RSI_RATE_2 },
+ { .bitrate = STD_RATE_5_5 * 5, .hw_value = RSI_RATE_5_5 },
+ { .bitrate = STD_RATE_11 * 5, .hw_value = RSI_RATE_11 },
+ { .bitrate = STD_RATE_06 * 5, .hw_value = RSI_RATE_6 },
+ { .bitrate = STD_RATE_09 * 5, .hw_value = RSI_RATE_9 },
+ { .bitrate = STD_RATE_12 * 5, .hw_value = RSI_RATE_12 },
+ { .bitrate = STD_RATE_18 * 5, .hw_value = RSI_RATE_18 },
+ { .bitrate = STD_RATE_24 * 5, .hw_value = RSI_RATE_24 },
+ { .bitrate = STD_RATE_36 * 5, .hw_value = RSI_RATE_36 },
+ { .bitrate = STD_RATE_48 * 5, .hw_value = RSI_RATE_48 },
+ { .bitrate = STD_RATE_54 * 5, .hw_value = RSI_RATE_54 },
+};
+
+const u16 rsi_mcsrates[8] = {
+ RSI_RATE_MCS0, RSI_RATE_MCS1, RSI_RATE_MCS2, RSI_RATE_MCS3,
+ RSI_RATE_MCS4, RSI_RATE_MCS5, RSI_RATE_MCS6, RSI_RATE_MCS7
+};
+
+/**
+ * rsi_is_cipher_wep() - This function determines if the cipher is WEP or not.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: If cipher type is WEP, a value of 1 is returned, else 0.
+ */
+
+bool rsi_is_cipher_wep(struct rsi_common *common)
+{
+ if (((common->secinfo.gtk_cipher == WLAN_CIPHER_SUITE_WEP104) ||
+ (common->secinfo.gtk_cipher == WLAN_CIPHER_SUITE_WEP40)) &&
+ (!common->secinfo.ptk_cipher))
+ return true;
+ else
+ return false;
+}
+
+/**
+ * rsi_register_rates_channels() - This function registers channels and rates.
+ * @adapter: Pointer to the adapter structure.
+ * @band: Operating band to be set.
+ *
+ * Return: None.
+ */
+static void rsi_register_rates_channels(struct rsi_hw *adapter, int band)
+{
+ struct ieee80211_supported_band *sbands = &adapter->sbands[band];
+ void *channels = NULL;
+
+ if (band == IEEE80211_BAND_2GHZ) {
+ channels = kmalloc(sizeof(rsi_2ghz_channels), GFP_KERNEL);
+ memcpy(channels,
+ rsi_2ghz_channels,
+ sizeof(rsi_2ghz_channels));
+ sbands->band = IEEE80211_BAND_2GHZ;
+ sbands->n_channels = ARRAY_SIZE(rsi_2ghz_channels);
+ sbands->bitrates = rsi_rates;
+ sbands->n_bitrates = ARRAY_SIZE(rsi_rates);
+ } else {
+ channels = kmalloc(sizeof(rsi_5ghz_channels), GFP_KERNEL);
+ memcpy(channels,
+ rsi_5ghz_channels,
+ sizeof(rsi_5ghz_channels));
+ sbands->band = IEEE80211_BAND_5GHZ;
+ sbands->n_channels = ARRAY_SIZE(rsi_5ghz_channels);
+ sbands->bitrates = &rsi_rates[4];
+ sbands->n_bitrates = ARRAY_SIZE(rsi_rates) - 4;
+ }
+
+ sbands->channels = channels;
+
+ memset(&sbands->ht_cap, 0, sizeof(struct ieee80211_sta_ht_cap));
+ sbands->ht_cap.ht_supported = true;
+ sbands->ht_cap.cap = (IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+ IEEE80211_HT_CAP_SGI_20 |
+ IEEE80211_HT_CAP_SGI_40);
+ sbands->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K;
+ sbands->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
+ sbands->ht_cap.mcs.rx_mask[0] = 0xff;
+ sbands->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+ /* sbands->ht_cap.mcs.rx_highest = 0x82; */
+}
+
+/**
+ * rsi_mac80211_attach() - This function is used to de-initialize the
+ * Mac80211 stack.
+ * @adapter: Pointer to the adapter structure.
+ *
+ * Return: None.
+ */
+void rsi_mac80211_detach(struct rsi_hw *adapter)
+{
+ struct ieee80211_hw *hw = adapter->hw;
+
+ if (hw) {
+ ieee80211_stop_queues(hw);
+ ieee80211_unregister_hw(hw);
+ ieee80211_free_hw(hw);
+ }
+
+ rsi_remove_dbgfs(adapter);
+}
+EXPORT_SYMBOL_GPL(rsi_mac80211_detach);
+
+/**
+ * rsi_indicate_tx_status() - This function indicates the transmit status.
+ * @adapter: Pointer to the adapter structure.
+ * @skb: Pointer to the socket buffer structure.
+ * @status: Status
+ *
+ * Return: None.
+ */
+void rsi_indicate_tx_status(struct rsi_hw *adapter,
+ struct sk_buff *skb,
+ int status)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ memset(info->driver_data, 0, IEEE80211_TX_INFO_DRIVER_DATA_SIZE);
+
+ if (!status)
+ info->flags |= IEEE80211_TX_STAT_ACK;
+
+ ieee80211_tx_status_irqsafe(adapter->hw, skb);
+}
+
+/**
+ * rsi_mac80211_tx() - This is the handler that 802.11 module calls for each
+ * transmitted frame.SKB contains the buffer starting
+ * from the IEEE 802.11 header.
+ * @hw: Pointer to the ieee80211_hw structure.
+ * @control: Pointer to the ieee80211_tx_control structure
+ * @skb: Pointer to the socket buffer structure.
+ *
+ * Return: None
+ */
+static void rsi_mac80211_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
+{
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+
+ rsi_core_xmit(common, skb);
+}
+
+/**
+ * rsi_mac80211_start() - This is first handler that 802.11 module calls, since
+ * the driver init is complete by then, just
+ * returns success.
+ * @hw: Pointer to the ieee80211_hw structure.
+ *
+ * Return: 0 as success.
+ */
+static int rsi_mac80211_start(struct ieee80211_hw *hw)
+{
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+
+ mutex_lock(&common->mutex);
+ common->iface_down = false;
+ mutex_unlock(&common->mutex);
+
+ return 0;
+}
+
+/**
+ * rsi_mac80211_stop() - This is the last handler that 802.11 module calls.
+ * @hw: Pointer to the ieee80211_hw structure.
+ *
+ * Return: None.
+ */
+static void rsi_mac80211_stop(struct ieee80211_hw *hw)
+{
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+
+ mutex_lock(&common->mutex);
+ common->iface_down = true;
+ mutex_unlock(&common->mutex);
+}
+
+/**
+ * rsi_mac80211_add_interface() - This function is called when a netdevice
+ * attached to the hardware is enabled.
+ * @hw: Pointer to the ieee80211_hw structure.
+ * @vif: Pointer to the ieee80211_vif structure.
+ *
+ * Return: ret: 0 on success, negative error code on failure.
+ */
+static int rsi_mac80211_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+ int ret = -EOPNOTSUPP;
+
+ mutex_lock(&common->mutex);
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ if (!adapter->sc_nvifs) {
+ ++adapter->sc_nvifs;
+ adapter->vifs[0] = vif;
+ ret = rsi_set_vap_capabilities(common, STA_OPMODE);
+ }
+ break;
+ default:
+ rsi_dbg(ERR_ZONE,
+ "%s: Interface type %d not supported\n", __func__,
+ vif->type);
+ }
+ mutex_unlock(&common->mutex);
+
+ return ret;
+}
+
+/**
+ * rsi_mac80211_remove_interface() - This function notifies driver that an
+ * interface is going down.
+ * @hw: Pointer to the ieee80211_hw structure.
+ * @vif: Pointer to the ieee80211_vif structure.
+ *
+ * Return: None.
+ */
+static void rsi_mac80211_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+
+ mutex_lock(&common->mutex);
+ if (vif->type == NL80211_IFTYPE_STATION)
+ adapter->sc_nvifs--;
+
+ if (!memcmp(adapter->vifs[0], vif, sizeof(struct ieee80211_vif)))
+ adapter->vifs[0] = NULL;
+ mutex_unlock(&common->mutex);
+}
+
+/**
+ * rsi_mac80211_config() - This function is a handler for configuration
+ * requests. The stack calls this function to
+ * change hardware configuration, e.g., channel.
+ * @hw: Pointer to the ieee80211_hw structure.
+ * @changed: Changed flags set.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+static int rsi_mac80211_config(struct ieee80211_hw *hw,
+ u32 changed)
+{
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+ int status = -EOPNOTSUPP;
+
+ mutex_lock(&common->mutex);
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ struct ieee80211_channel *curchan = hw->conf.chandef.chan;
+ u16 channel = curchan->hw_value;
+
+ rsi_dbg(INFO_ZONE,
+ "%s: Set channel: %d MHz type: %d channel_no %d\n",
+ __func__, curchan->center_freq,
+ curchan->flags, channel);
+ common->band = curchan->band;
+ status = rsi_set_channel(adapter->priv, channel);
+ }
+ mutex_unlock(&common->mutex);
+
+ return status;
+}
+
+/**
+ * rsi_get_connected_channel() - This function is used to get the current
+ * connected channel number.
+ * @adapter: Pointer to the adapter structure.
+ *
+ * Return: Current connected AP's channel number is returned.
+ */
+u16 rsi_get_connected_channel(struct rsi_hw *adapter)
+{
+ struct ieee80211_vif *vif = adapter->vifs[0];
+ if (vif) {
+ struct ieee80211_bss_conf *bss = &vif->bss_conf;
+ struct ieee80211_channel *channel = bss->chandef.chan;
+ return channel->hw_value;
+ }
+
+ return 0;
+}
+
+/**
+ * rsi_mac80211_bss_info_changed() - This function is a handler for config
+ * requests related to BSS parameters that
+ * may vary during BSS's lifespan.
+ * @hw: Pointer to the ieee80211_hw structure.
+ * @vif: Pointer to the ieee80211_vif structure.
+ * @bss_conf: Pointer to the ieee80211_bss_conf structure.
+ * @changed: Changed flags set.
+ *
+ * Return: None.
+ */
+static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf,
+ u32 changed)
+{
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+
+ mutex_lock(&common->mutex);
+ if (changed & BSS_CHANGED_ASSOC) {
+ rsi_dbg(INFO_ZONE, "%s: Changed Association status: %d\n",
+ __func__, bss_conf->assoc);
+ rsi_inform_bss_status(common,
+ bss_conf->assoc,
+ bss_conf->bssid,
+ bss_conf->qos,
+ bss_conf->aid);
+ }
+ mutex_unlock(&common->mutex);
+}
+
+/**
+ * rsi_mac80211_conf_filter() - This function configure the device's RX filter.
+ * @hw: Pointer to the ieee80211_hw structure.
+ * @changed: Changed flags set.
+ * @total_flags: Total initial flags set.
+ * @multicast: Multicast.
+ *
+ * Return: None.
+ */
+static void rsi_mac80211_conf_filter(struct ieee80211_hw *hw,
+ u32 changed_flags,
+ u32 *total_flags,
+ u64 multicast)
+{
+ /* Not doing much here as of now */
+ *total_flags &= RSI_SUPP_FILTERS;
+}
+
+/**
+ * rsi_mac80211_conf_tx() - This function configures TX queue parameters
+ * (EDCF (aifs, cw_min, cw_max), bursting)
+ * for a hardware TX queue.
+ * @hw: Pointer to the ieee80211_hw structure
+ * @vif: Pointer to the ieee80211_vif structure.
+ * @queue: Queue number.
+ * @params: Pointer to ieee80211_tx_queue_params structure.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+static int rsi_mac80211_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+ u8 idx = 0;
+
+ if (queue >= IEEE80211_NUM_ACS)
+ return 0;
+
+ rsi_dbg(INFO_ZONE,
+ "%s: Conf queue %d, aifs: %d, cwmin: %d cwmax: %d, txop: %d\n",
+ __func__, queue, params->aifs,
+ params->cw_min, params->cw_max, params->txop);
+
+ mutex_lock(&common->mutex);
+ /* Map into the way the f/w expects */
+ switch (queue) {
+ case IEEE80211_AC_VO:
+ idx = VO_Q;
+ break;
+ case IEEE80211_AC_VI:
+ idx = VI_Q;
+ break;
+ case IEEE80211_AC_BE:
+ idx = BE_Q;
+ break;
+ case IEEE80211_AC_BK:
+ idx = BK_Q;
+ break;
+ default:
+ idx = BE_Q;
+ break;
+ }
+
+ memcpy(&common->edca_params[idx],
+ params,
+ sizeof(struct ieee80211_tx_queue_params));
+ mutex_unlock(&common->mutex);
+
+ return 0;
+}
+
+/**
+ * rsi_hal_key_config() - This function loads the keys into the firmware.
+ * @hw: Pointer to the ieee80211_hw structure.
+ * @vif: Pointer to the ieee80211_vif structure.
+ * @key: Pointer to the ieee80211_key_conf structure.
+ *
+ * Return: status: 0 on success, -1 on failure.
+ */
+static int rsi_hal_key_config(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_key_conf *key)
+{
+ struct rsi_hw *adapter = hw->priv;
+ int status;
+ u8 key_type;
+
+ if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+ key_type = RSI_PAIRWISE_KEY;
+ else
+ key_type = RSI_GROUP_KEY;
+
+ rsi_dbg(ERR_ZONE, "%s: Cipher 0x%x key_type: %d key_len: %d\n",
+ __func__, key->cipher, key_type, key->keylen);
+
+ if ((key->cipher == WLAN_CIPHER_SUITE_WEP104) ||
+ (key->cipher == WLAN_CIPHER_SUITE_WEP40)) {
+ status = rsi_hal_load_key(adapter->priv,
+ key->key,
+ key->keylen,
+ RSI_PAIRWISE_KEY,
+ key->keyidx,
+ key->cipher);
+ if (status)
+ return status;
+ }
+ return rsi_hal_load_key(adapter->priv,
+ key->key,
+ key->keylen,
+ key_type,
+ key->keyidx,
+ key->cipher);
+}
+
+/**
+ * rsi_mac80211_set_key() - This function sets type of key to be loaded.
+ * @hw: Pointer to the ieee80211_hw structure.
+ * @cmd: enum set_key_cmd.
+ * @vif: Pointer to the ieee80211_vif structure.
+ * @sta: Pointer to the ieee80211_sta structure.
+ * @key: Pointer to the ieee80211_key_conf structure.
+ *
+ * Return: status: 0 on success, negative error code on failure.
+ */
+static int rsi_mac80211_set_key(struct ieee80211_hw *hw,
+ enum set_key_cmd cmd,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+ struct security_info *secinfo = &common->secinfo;
+ int status;
+
+ mutex_lock(&common->mutex);
+ switch (cmd) {
+ case SET_KEY:
+ secinfo->security_enable = true;
+ status = rsi_hal_key_config(hw, vif, key);
+ if (status) {
+ mutex_unlock(&common->mutex);
+ return status;
+ }
+
+ if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+ secinfo->ptk_cipher = key->cipher;
+ else
+ secinfo->gtk_cipher = key->cipher;
+
+ key->hw_key_idx = key->keyidx;
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+
+ rsi_dbg(ERR_ZONE, "%s: RSI set_key\n", __func__);
+ break;
+
+ case DISABLE_KEY:
+ secinfo->security_enable = false;
+ rsi_dbg(ERR_ZONE, "%s: RSI del key\n", __func__);
+ memset(key, 0, sizeof(struct ieee80211_key_conf));
+ status = rsi_hal_key_config(hw, vif, key);
+ break;
+
+ default:
+ status = -EOPNOTSUPP;
+ break;
+ }
+
+ mutex_unlock(&common->mutex);
+ return status;
+}
+
+/**
+ * rsi_mac80211_ampdu_action() - This function selects the AMPDU action for
+ * the corresponding mlme_action flag and
+ * informs the f/w regarding this.
+ * @hw: Pointer to the ieee80211_hw structure.
+ * @vif: Pointer to the ieee80211_vif structure.
+ * @action: ieee80211_ampdu_mlme_action enum.
+ * @sta: Pointer to the ieee80211_sta structure.
+ * @tid: Traffic identifier.
+ * @ssn: Pointer to ssn value.
+ * @buf_size: Buffer size (for kernel version > 2.6.38).
+ *
+ * Return: status: 0 on success, negative error code on failure.
+ */
+static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum ieee80211_ampdu_mlme_action action,
+ struct ieee80211_sta *sta,
+ unsigned short tid,
+ unsigned short *ssn,
+ unsigned char buf_size)
+{
+ int status = -EOPNOTSUPP;
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+ u16 seq_no = 0;
+ u8 ii = 0;
+
+ for (ii = 0; ii < RSI_MAX_VIFS; ii++) {
+ if (vif == adapter->vifs[ii])
+ break;
+ }
+
+ mutex_lock(&common->mutex);
+ rsi_dbg(INFO_ZONE, "%s: AMPDU action %d called\n", __func__, action);
+ if (ssn != NULL)
+ seq_no = *ssn;
+
+ switch (action) {
+ case IEEE80211_AMPDU_RX_START:
+ status = rsi_send_aggregation_params_frame(common,
+ tid,
+ seq_no,
+ buf_size,
+ STA_RX_ADDBA_DONE);
+ break;
+
+ case IEEE80211_AMPDU_RX_STOP:
+ status = rsi_send_aggregation_params_frame(common,
+ tid,
+ 0,
+ buf_size,
+ STA_RX_DELBA);
+ break;
+
+ case IEEE80211_AMPDU_TX_START:
+ common->vif_info[ii].seq_start = seq_no;
+ ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ break;
+
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+ status = rsi_send_aggregation_params_frame(common,
+ tid,
+ seq_no,
+ buf_size,
+ STA_TX_DELBA);
+ if (!status)
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ break;
+
+ case IEEE80211_AMPDU_TX_OPERATIONAL:
+ status = rsi_send_aggregation_params_frame(common,
+ tid,
+ common->vif_info[ii]
+ .seq_start,
+ buf_size,
+ STA_TX_ADDBA_DONE);
+ break;
+
+ default:
+ rsi_dbg(ERR_ZONE, "%s: Uknown AMPDU action\n", __func__);
+ break;
+ }
+
+ mutex_unlock(&common->mutex);
+ return status;
+}
+
+/**
+ * rsi_mac80211_set_rts_threshold() - This function sets rts threshold value.
+ * @hw: Pointer to the ieee80211_hw structure.
+ * @value: Rts threshold value.
+ *
+ * Return: 0 on success.
+ */
+static int rsi_mac80211_set_rts_threshold(struct ieee80211_hw *hw,
+ u32 value)
+{
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+
+ mutex_lock(&common->mutex);
+ common->rts_threshold = value;
+ mutex_unlock(&common->mutex);
+
+ return 0;
+}
+
+/**
+ * rsi_mac80211_set_rate_mask() - This function sets bitrate_mask to be used.
+ * @hw: Pointer to the ieee80211_hw structure
+ * @vif: Pointer to the ieee80211_vif structure.
+ * @mask: Pointer to the cfg80211_bitrate_mask structure.
+ *
+ * Return: 0 on success.
+ */
+static int rsi_mac80211_set_rate_mask(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ const struct cfg80211_bitrate_mask *mask)
+{
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+
+ mutex_lock(&common->mutex);
+
+ common->fixedrate_mask[IEEE80211_BAND_2GHZ] = 0;
+
+ if (mask->control[IEEE80211_BAND_2GHZ].legacy == 0xfff) {
+ common->fixedrate_mask[IEEE80211_BAND_2GHZ] =
+ (mask->control[IEEE80211_BAND_2GHZ].ht_mcs[0] << 12);
+ } else {
+ common->fixedrate_mask[IEEE80211_BAND_2GHZ] =
+ mask->control[IEEE80211_BAND_2GHZ].legacy;
+ }
+ mutex_unlock(&common->mutex);
+
+ return 0;
+}
+
+/**
+ * rsi_fill_rx_status() - This function fills rx status in
+ * ieee80211_rx_status structure.
+ * @hw: Pointer to the ieee80211_hw structure.
+ * @skb: Pointer to the socket buffer structure.
+ * @common: Pointer to the driver private structure.
+ * @rxs: Pointer to the ieee80211_rx_status structure.
+ *
+ * Return: None.
+ */
+static void rsi_fill_rx_status(struct ieee80211_hw *hw,
+ struct sk_buff *skb,
+ struct rsi_common *common,
+ struct ieee80211_rx_status *rxs)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct skb_info *rx_params = (struct skb_info *)info->driver_data;
+ struct ieee80211_hdr *hdr;
+ char rssi = rx_params->rssi;
+ u8 hdrlen = 0;
+ u8 channel = rx_params->channel;
+ s32 freq;
+
+ hdr = ((struct ieee80211_hdr *)(skb->data));
+ hdrlen = ieee80211_hdrlen(hdr->frame_control);
+
+ memset(info, 0, sizeof(struct ieee80211_tx_info));
+
+ rxs->signal = -(rssi);
+
+ if (channel <= 14)
+ rxs->band = IEEE80211_BAND_2GHZ;
+ else
+ rxs->band = IEEE80211_BAND_5GHZ;
+
+ freq = ieee80211_channel_to_frequency(channel, rxs->band);
+
+ if (freq)
+ rxs->freq = freq;
+
+ if (ieee80211_has_protected(hdr->frame_control)) {
+ if (rsi_is_cipher_wep(common)) {
+ memmove(skb->data + 4, skb->data, hdrlen);
+ skb_pull(skb, 4);
+ } else {
+ memmove(skb->data + 8, skb->data, hdrlen);
+ skb_pull(skb, 8);
+ rxs->flag |= RX_FLAG_MMIC_STRIPPED;
+ }
+ rxs->flag |= RX_FLAG_DECRYPTED;
+ rxs->flag |= RX_FLAG_IV_STRIPPED;
+ }
+}
+
+/**
+ * rsi_indicate_pkt_to_os() - This function sends recieved packet to mac80211.
+ * @common: Pointer to the driver private structure.
+ * @skb: Pointer to the socket buffer structure.
+ *
+ * Return: None.
+ */
+void rsi_indicate_pkt_to_os(struct rsi_common *common,
+ struct sk_buff *skb)
+{
+ struct rsi_hw *adapter = common->priv;
+ struct ieee80211_hw *hw = adapter->hw;
+ struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+
+ if ((common->iface_down) || (!adapter->sc_nvifs)) {
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ /* filling in the ieee80211_rx_status flags */
+ rsi_fill_rx_status(hw, skb, common, rx_status);
+
+ ieee80211_rx_irqsafe(hw, skb);
+}
+
+static void rsi_set_min_rate(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ struct rsi_common *common)
+{
+ u8 band = hw->conf.chandef.chan->band;
+ u8 ii;
+ u32 rate_bitmap;
+ bool matched = false;
+
+ common->bitrate_mask[band] = sta->supp_rates[band];
+
+ rate_bitmap = (common->fixedrate_mask[band] & sta->supp_rates[band]);
+
+ if (rate_bitmap & 0xfff) {
+ /* Find out the min rate */
+ for (ii = 0; ii < ARRAY_SIZE(rsi_rates); ii++) {
+ if (rate_bitmap & BIT(ii)) {
+ common->min_rate = rsi_rates[ii].hw_value;
+ matched = true;
+ break;
+ }
+ }
+ }
+
+ common->vif_info[0].is_ht = sta->ht_cap.ht_supported;
+
+ if ((common->vif_info[0].is_ht) && (rate_bitmap >> 12)) {
+ for (ii = 0; ii < ARRAY_SIZE(rsi_mcsrates); ii++) {
+ if ((rate_bitmap >> 12) & BIT(ii)) {
+ common->min_rate = rsi_mcsrates[ii];
+ matched = true;
+ break;
+ }
+ }
+ }
+
+ if (!matched)
+ common->min_rate = 0xffff;
+}
+
+/**
+ * rsi_mac80211_sta_add() - This function notifies driver about a peer getting
+ * connected.
+ * @hw: pointer to the ieee80211_hw structure.
+ * @vif: Pointer to the ieee80211_vif structure.
+ * @sta: Pointer to the ieee80211_sta structure.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int rsi_mac80211_sta_add(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+
+ mutex_lock(&common->mutex);
+
+ rsi_set_min_rate(hw, sta, common);
+
+ if ((sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ||
+ (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)) {
+ common->vif_info[0].sgi = true;
+ }
+
+ if (sta->ht_cap.ht_supported)
+ ieee80211_start_tx_ba_session(sta, 0, 0);
+
+ mutex_unlock(&common->mutex);
+
+ return 0;
+}
+
+/**
+ * rsi_mac80211_sta_remove() - This function notifies driver about a peer
+ * getting disconnected.
+ * @hw: Pointer to the ieee80211_hw structure.
+ * @vif: Pointer to the ieee80211_vif structure.
+ * @sta: Pointer to the ieee80211_sta structure.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int rsi_mac80211_sta_remove(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+
+ mutex_lock(&common->mutex);
+ /* Resetting all the fields to default values */
+ common->bitrate_mask[IEEE80211_BAND_2GHZ] = 0;
+ common->bitrate_mask[IEEE80211_BAND_5GHZ] = 0;
+ common->min_rate = 0xffff;
+ common->vif_info[0].is_ht = false;
+ common->vif_info[0].sgi = false;
+ common->vif_info[0].seq_start = 0;
+ common->secinfo.ptk_cipher = 0;
+ common->secinfo.gtk_cipher = 0;
+ mutex_unlock(&common->mutex);
+
+ return 0;
+}
+
+static struct ieee80211_ops mac80211_ops = {
+ .tx = rsi_mac80211_tx,
+ .start = rsi_mac80211_start,
+ .stop = rsi_mac80211_stop,
+ .add_interface = rsi_mac80211_add_interface,
+ .remove_interface = rsi_mac80211_remove_interface,
+ .config = rsi_mac80211_config,
+ .bss_info_changed = rsi_mac80211_bss_info_changed,
+ .conf_tx = rsi_mac80211_conf_tx,
+ .configure_filter = rsi_mac80211_conf_filter,
+ .set_key = rsi_mac80211_set_key,
+ .set_rts_threshold = rsi_mac80211_set_rts_threshold,
+ .set_bitrate_mask = rsi_mac80211_set_rate_mask,
+ .ampdu_action = rsi_mac80211_ampdu_action,
+ .sta_add = rsi_mac80211_sta_add,
+ .sta_remove = rsi_mac80211_sta_remove,
+};
+
+/**
+ * rsi_mac80211_attach() - This function is used to initialize Mac80211 stack.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+int rsi_mac80211_attach(struct rsi_common *common)
+{
+ int status = 0;
+ struct ieee80211_hw *hw = NULL;
+ struct wiphy *wiphy = NULL;
+ struct rsi_hw *adapter = common->priv;
+ u8 addr_mask[ETH_ALEN] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x3};
+
+ rsi_dbg(INIT_ZONE, "%s: Performing mac80211 attach\n", __func__);
+
+ hw = ieee80211_alloc_hw(sizeof(struct rsi_hw), &mac80211_ops);
+ if (!hw) {
+ rsi_dbg(ERR_ZONE, "%s: ieee80211 hw alloc failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ wiphy = hw->wiphy;
+
+ SET_IEEE80211_DEV(hw, adapter->device);
+
+ hw->priv = adapter;
+ adapter->hw = hw;
+
+ hw->flags = IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_HAS_RATE_CONTROL |
+ IEEE80211_HW_AMPDU_AGGREGATION |
+ 0;
+
+ hw->queues = MAX_HW_QUEUES;
+ hw->extra_tx_headroom = RSI_NEEDED_HEADROOM;
+
+ hw->max_rates = 1;
+ hw->max_rate_tries = MAX_RETRIES;
+
+ hw->max_tx_aggregation_subframes = 6;
+ rsi_register_rates_channels(adapter, IEEE80211_BAND_2GHZ);
+ hw->rate_control_algorithm = "AARF";
+
+ SET_IEEE80211_PERM_ADDR(hw, common->mac_addr);
+ ether_addr_copy(hw->wiphy->addr_mask, addr_mask);
+
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ wiphy->retry_short = RETRY_SHORT;
+ wiphy->retry_long = RETRY_LONG;
+ wiphy->frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
+ wiphy->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
+ wiphy->flags = 0;
+
+ wiphy->available_antennas_rx = 1;
+ wiphy->available_antennas_tx = 1;
+ wiphy->bands[IEEE80211_BAND_2GHZ] =
+ &adapter->sbands[IEEE80211_BAND_2GHZ];
+
+ status = ieee80211_register_hw(hw);
+ if (status)
+ return status;
+
+ return rsi_init_dbgfs(adapter);
+}
diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c
new file mode 100644
index 000000000000..8810862ae826
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_91x_main.c
@@ -0,0 +1,295 @@
+/**
+ * Copyright (c) 2014 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include "rsi_mgmt.h"
+#include "rsi_common.h"
+
+u32 rsi_zone_enabled = /* INFO_ZONE |
+ INIT_ZONE |
+ MGMT_TX_ZONE |
+ MGMT_RX_ZONE |
+ DATA_TX_ZONE |
+ DATA_RX_ZONE |
+ FSM_ZONE |
+ ISR_ZONE | */
+ ERR_ZONE |
+ 0;
+EXPORT_SYMBOL_GPL(rsi_zone_enabled);
+
+/**
+ * rsi_dbg() - This function outputs informational messages.
+ * @zone: Zone of interest for output message.
+ * @fmt: printf-style format for output message.
+ *
+ * Return: none
+ */
+void rsi_dbg(u32 zone, const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ if (zone & rsi_zone_enabled)
+ pr_info("%pV", &vaf);
+ va_end(args);
+}
+EXPORT_SYMBOL_GPL(rsi_dbg);
+
+/**
+ * rsi_prepare_skb() - This function prepares the skb.
+ * @common: Pointer to the driver private structure.
+ * @buffer: Pointer to the packet data.
+ * @pkt_len: Length of the packet.
+ * @extended_desc: Extended descriptor.
+ *
+ * Return: Successfully skb.
+ */
+static struct sk_buff *rsi_prepare_skb(struct rsi_common *common,
+ u8 *buffer,
+ u32 pkt_len,
+ u8 extended_desc)
+{
+ struct ieee80211_tx_info *info;
+ struct skb_info *rx_params;
+ struct sk_buff *skb = NULL;
+ u8 payload_offset;
+
+ if (WARN(!pkt_len, "%s: Dummy pkt received", __func__))
+ return NULL;
+
+ if (pkt_len > (RSI_RCV_BUFFER_LEN * 4)) {
+ rsi_dbg(ERR_ZONE, "%s: Pkt size > max rx buf size %d\n",
+ __func__, pkt_len);
+ pkt_len = RSI_RCV_BUFFER_LEN * 4;
+ }
+
+ pkt_len -= extended_desc;
+ skb = dev_alloc_skb(pkt_len + FRAME_DESC_SZ);
+ if (skb == NULL)
+ return NULL;
+
+ payload_offset = (extended_desc + FRAME_DESC_SZ);
+ skb_put(skb, pkt_len);
+ memcpy((skb->data), (buffer + payload_offset), skb->len);
+
+ info = IEEE80211_SKB_CB(skb);
+ rx_params = (struct skb_info *)info->driver_data;
+ rx_params->rssi = rsi_get_rssi(buffer);
+ rx_params->channel = rsi_get_connected_channel(common->priv);
+
+ return skb;
+}
+
+/**
+ * rsi_read_pkt() - This function reads frames from the card.
+ * @common: Pointer to the driver private structure.
+ * @rcv_pkt_len: Received pkt length. In case of USB it is 0.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len)
+{
+ u8 *frame_desc = NULL, extended_desc = 0;
+ u32 index, length = 0, queueno = 0;
+ u16 actual_length = 0, offset;
+ struct sk_buff *skb = NULL;
+
+ index = 0;
+ do {
+ frame_desc = &common->rx_data_pkt[index];
+ actual_length = *(u16 *)&frame_desc[0];
+ offset = *(u16 *)&frame_desc[2];
+
+ queueno = rsi_get_queueno(frame_desc, offset);
+ length = rsi_get_length(frame_desc, offset);
+ extended_desc = rsi_get_extended_desc(frame_desc, offset);
+
+ switch (queueno) {
+ case RSI_WIFI_DATA_Q:
+ skb = rsi_prepare_skb(common,
+ (frame_desc + offset),
+ length,
+ extended_desc);
+ if (skb == NULL)
+ goto fail;
+
+ rsi_indicate_pkt_to_os(common, skb);
+ break;
+
+ case RSI_WIFI_MGMT_Q:
+ rsi_mgmt_pkt_recv(common, (frame_desc + offset));
+ break;
+
+ default:
+ rsi_dbg(ERR_ZONE, "%s: pkt from invalid queue: %d\n",
+ __func__, queueno);
+ goto fail;
+ }
+
+ index += actual_length;
+ rcv_pkt_len -= actual_length;
+ } while (rcv_pkt_len > 0);
+
+ return 0;
+fail:
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(rsi_read_pkt);
+
+/**
+ * rsi_tx_scheduler_thread() - This function is a kernel thread to send the
+ * packets to the device.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: None.
+ */
+static void rsi_tx_scheduler_thread(struct rsi_common *common)
+{
+ struct rsi_hw *adapter = common->priv;
+ u32 timeout = EVENT_WAIT_FOREVER;
+
+ do {
+ if (adapter->determine_event_timeout)
+ timeout = adapter->determine_event_timeout(adapter);
+ rsi_wait_event(&common->tx_thread.event, timeout);
+ rsi_reset_event(&common->tx_thread.event);
+
+ if (common->init_done)
+ rsi_core_qos_processor(common);
+ } while (atomic_read(&common->tx_thread.thread_done) == 0);
+ complete_and_exit(&common->tx_thread.completion, 0);
+}
+
+/**
+ * rsi_91x_init() - This function initializes os interface operations.
+ * @void: Void.
+ *
+ * Return: Pointer to the adapter structure on success, NULL on failure .
+ */
+struct rsi_hw *rsi_91x_init(void)
+{
+ struct rsi_hw *adapter = NULL;
+ struct rsi_common *common = NULL;
+ u8 ii = 0;
+
+ adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
+ if (!adapter)
+ return NULL;
+
+ adapter->priv = kzalloc(sizeof(*common), GFP_KERNEL);
+ if (adapter->priv == NULL) {
+ rsi_dbg(ERR_ZONE, "%s: Failed in allocation of memory\n",
+ __func__);
+ kfree(adapter);
+ return NULL;
+ } else {
+ common = adapter->priv;
+ common->priv = adapter;
+ }
+
+ for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
+ skb_queue_head_init(&common->tx_queue[ii]);
+
+ rsi_init_event(&common->tx_thread.event);
+ mutex_init(&common->mutex);
+ mutex_init(&common->tx_rxlock);
+
+ if (rsi_create_kthread(common,
+ &common->tx_thread,
+ rsi_tx_scheduler_thread,
+ "Tx-Thread")) {
+ rsi_dbg(ERR_ZONE, "%s: Unable to init tx thrd\n", __func__);
+ goto err;
+ }
+
+ common->init_done = true;
+ return adapter;
+
+err:
+ kfree(common);
+ kfree(adapter);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(rsi_91x_init);
+
+/**
+ * rsi_91x_deinit() - This function de-intializes os intf operations.
+ * @adapter: Pointer to the adapter structure.
+ *
+ * Return: None.
+ */
+void rsi_91x_deinit(struct rsi_hw *adapter)
+{
+ struct rsi_common *common = adapter->priv;
+ u8 ii;
+
+ rsi_dbg(INFO_ZONE, "%s: Performing deinit os ops\n", __func__);
+
+ rsi_kill_thread(&common->tx_thread);
+
+ for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
+ skb_queue_purge(&common->tx_queue[ii]);
+
+ common->init_done = false;
+
+ kfree(common);
+ kfree(adapter->rsi_dev);
+ kfree(adapter);
+}
+EXPORT_SYMBOL_GPL(rsi_91x_deinit);
+
+/**
+ * rsi_91x_hal_module_init() - This function is invoked when the module is
+ * loaded into the kernel.
+ * It registers the client driver.
+ * @void: Void.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int rsi_91x_hal_module_init(void)
+{
+ rsi_dbg(INIT_ZONE, "%s: Module init called\n", __func__);
+ return 0;
+}
+
+/**
+ * rsi_91x_hal_module_exit() - This function is called at the time of
+ * removing/unloading the module.
+ * It unregisters the client driver.
+ * @void: Void.
+ *
+ * Return: None.
+ */
+static void rsi_91x_hal_module_exit(void)
+{
+ rsi_dbg(INIT_ZONE, "%s: Module exit called\n", __func__);
+}
+
+module_init(rsi_91x_hal_module_init);
+module_exit(rsi_91x_hal_module_exit);
+MODULE_AUTHOR("Redpine Signals Inc");
+MODULE_DESCRIPTION("Station driver for RSI 91x devices");
+MODULE_SUPPORTED_DEVICE("RSI-91x");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
new file mode 100644
index 000000000000..2361a6849ad7
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
@@ -0,0 +1,1304 @@
+/**
+ * Copyright (c) 2014 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/etherdevice.h>
+#include "rsi_mgmt.h"
+#include "rsi_common.h"
+
+static struct bootup_params boot_params_20 = {
+ .magic_number = cpu_to_le16(0x5aa5),
+ .crystal_good_time = 0x0,
+ .valid = cpu_to_le32(VALID_20),
+ .reserved_for_valids = 0x0,
+ .bootup_mode_info = 0x0,
+ .digital_loop_back_params = 0x0,
+ .rtls_timestamp_en = 0x0,
+ .host_spi_intr_cfg = 0x0,
+ .device_clk_info = {{
+ .pll_config_g = {
+ .tapll_info_g = {
+ .pll_reg_1 = cpu_to_le16((TA_PLL_N_VAL_20 << 8)|
+ (TA_PLL_M_VAL_20)),
+ .pll_reg_2 = cpu_to_le16(TA_PLL_P_VAL_20),
+ },
+ .pll960_info_g = {
+ .pll_reg_1 = cpu_to_le16((PLL960_P_VAL_20 << 8)|
+ (PLL960_N_VAL_20)),
+ .pll_reg_2 = cpu_to_le16(PLL960_M_VAL_20),
+ .pll_reg_3 = 0x0,
+ },
+ .afepll_info_g = {
+ .pll_reg = cpu_to_le16(0x9f0),
+ }
+ },
+ .switch_clk_g = {
+ .switch_clk_info = cpu_to_le16(BIT(3)),
+ .bbp_lmac_clk_reg_val = cpu_to_le16(0x121),
+ .umac_clock_reg_config = 0x0,
+ .qspi_uart_clock_reg_config = 0x0
+ }
+ },
+ {
+ .pll_config_g = {
+ .tapll_info_g = {
+ .pll_reg_1 = cpu_to_le16((TA_PLL_N_VAL_20 << 8)|
+ (TA_PLL_M_VAL_20)),
+ .pll_reg_2 = cpu_to_le16(TA_PLL_P_VAL_20),
+ },
+ .pll960_info_g = {
+ .pll_reg_1 = cpu_to_le16((PLL960_P_VAL_20 << 8)|
+ (PLL960_N_VAL_20)),
+ .pll_reg_2 = cpu_to_le16(PLL960_M_VAL_20),
+ .pll_reg_3 = 0x0,
+ },
+ .afepll_info_g = {
+ .pll_reg = cpu_to_le16(0x9f0),
+ }
+ },
+ .switch_clk_g = {
+ .switch_clk_info = 0x0,
+ .bbp_lmac_clk_reg_val = 0x0,
+ .umac_clock_reg_config = 0x0,
+ .qspi_uart_clock_reg_config = 0x0
+ }
+ },
+ {
+ .pll_config_g = {
+ .tapll_info_g = {
+ .pll_reg_1 = cpu_to_le16((TA_PLL_N_VAL_20 << 8)|
+ (TA_PLL_M_VAL_20)),
+ .pll_reg_2 = cpu_to_le16(TA_PLL_P_VAL_20),
+ },
+ .pll960_info_g = {
+ .pll_reg_1 = cpu_to_le16((PLL960_P_VAL_20 << 8)|
+ (PLL960_N_VAL_20)),
+ .pll_reg_2 = cpu_to_le16(PLL960_M_VAL_20),
+ .pll_reg_3 = 0x0,
+ },
+ .afepll_info_g = {
+ .pll_reg = cpu_to_le16(0x9f0),
+ }
+ },
+ .switch_clk_g = {
+ .switch_clk_info = 0x0,
+ .bbp_lmac_clk_reg_val = 0x0,
+ .umac_clock_reg_config = 0x0,
+ .qspi_uart_clock_reg_config = 0x0
+ }
+ } },
+ .buckboost_wakeup_cnt = 0x0,
+ .pmu_wakeup_wait = 0x0,
+ .shutdown_wait_time = 0x0,
+ .pmu_slp_clkout_sel = 0x0,
+ .wdt_prog_value = 0x0,
+ .wdt_soc_rst_delay = 0x0,
+ .dcdc_operation_mode = 0x0,
+ .soc_reset_wait_cnt = 0x0
+};
+
+static struct bootup_params boot_params_40 = {
+ .magic_number = cpu_to_le16(0x5aa5),
+ .crystal_good_time = 0x0,
+ .valid = cpu_to_le32(VALID_40),
+ .reserved_for_valids = 0x0,
+ .bootup_mode_info = 0x0,
+ .digital_loop_back_params = 0x0,
+ .rtls_timestamp_en = 0x0,
+ .host_spi_intr_cfg = 0x0,
+ .device_clk_info = {{
+ .pll_config_g = {
+ .tapll_info_g = {
+ .pll_reg_1 = cpu_to_le16((TA_PLL_N_VAL_40 << 8)|
+ (TA_PLL_M_VAL_40)),
+ .pll_reg_2 = cpu_to_le16(TA_PLL_P_VAL_40),
+ },
+ .pll960_info_g = {
+ .pll_reg_1 = cpu_to_le16((PLL960_P_VAL_40 << 8)|
+ (PLL960_N_VAL_40)),
+ .pll_reg_2 = cpu_to_le16(PLL960_M_VAL_40),
+ .pll_reg_3 = 0x0,
+ },
+ .afepll_info_g = {
+ .pll_reg = cpu_to_le16(0x9f0),
+ }
+ },
+ .switch_clk_g = {
+ .switch_clk_info = cpu_to_le16(0x09),
+ .bbp_lmac_clk_reg_val = cpu_to_le16(0x1121),
+ .umac_clock_reg_config = cpu_to_le16(0x48),
+ .qspi_uart_clock_reg_config = 0x0
+ }
+ },
+ {
+ .pll_config_g = {
+ .tapll_info_g = {
+ .pll_reg_1 = cpu_to_le16((TA_PLL_N_VAL_40 << 8)|
+ (TA_PLL_M_VAL_40)),
+ .pll_reg_2 = cpu_to_le16(TA_PLL_P_VAL_40),
+ },
+ .pll960_info_g = {
+ .pll_reg_1 = cpu_to_le16((PLL960_P_VAL_40 << 8)|
+ (PLL960_N_VAL_40)),
+ .pll_reg_2 = cpu_to_le16(PLL960_M_VAL_40),
+ .pll_reg_3 = 0x0,
+ },
+ .afepll_info_g = {
+ .pll_reg = cpu_to_le16(0x9f0),
+ }
+ },
+ .switch_clk_g = {
+ .switch_clk_info = 0x0,
+ .bbp_lmac_clk_reg_val = 0x0,
+ .umac_clock_reg_config = 0x0,
+ .qspi_uart_clock_reg_config = 0x0
+ }
+ },
+ {
+ .pll_config_g = {
+ .tapll_info_g = {
+ .pll_reg_1 = cpu_to_le16((TA_PLL_N_VAL_40 << 8)|
+ (TA_PLL_M_VAL_40)),
+ .pll_reg_2 = cpu_to_le16(TA_PLL_P_VAL_40),
+ },
+ .pll960_info_g = {
+ .pll_reg_1 = cpu_to_le16((PLL960_P_VAL_40 << 8)|
+ (PLL960_N_VAL_40)),
+ .pll_reg_2 = cpu_to_le16(PLL960_M_VAL_40),
+ .pll_reg_3 = 0x0,
+ },
+ .afepll_info_g = {
+ .pll_reg = cpu_to_le16(0x9f0),
+ }
+ },
+ .switch_clk_g = {
+ .switch_clk_info = 0x0,
+ .bbp_lmac_clk_reg_val = 0x0,
+ .umac_clock_reg_config = 0x0,
+ .qspi_uart_clock_reg_config = 0x0
+ }
+ } },
+ .buckboost_wakeup_cnt = 0x0,
+ .pmu_wakeup_wait = 0x0,
+ .shutdown_wait_time = 0x0,
+ .pmu_slp_clkout_sel = 0x0,
+ .wdt_prog_value = 0x0,
+ .wdt_soc_rst_delay = 0x0,
+ .dcdc_operation_mode = 0x0,
+ .soc_reset_wait_cnt = 0x0
+};
+
+static u16 mcs[] = {13, 26, 39, 52, 78, 104, 117, 130};
+
+/**
+ * rsi_set_default_parameters() - This function sets default parameters.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: none
+ */
+static void rsi_set_default_parameters(struct rsi_common *common)
+{
+ common->band = IEEE80211_BAND_2GHZ;
+ common->channel_width = BW_20MHZ;
+ common->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
+ common->channel = 1;
+ common->min_rate = 0xffff;
+ common->fsm_state = FSM_CARD_NOT_READY;
+ common->iface_down = true;
+}
+
+/**
+ * rsi_set_contention_vals() - This function sets the contention values for the
+ * backoff procedure.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: None.
+ */
+static void rsi_set_contention_vals(struct rsi_common *common)
+{
+ u8 ii = 0;
+
+ for (; ii < NUM_EDCA_QUEUES; ii++) {
+ common->tx_qinfo[ii].wme_params =
+ (((common->edca_params[ii].cw_min / 2) +
+ (common->edca_params[ii].aifs)) *
+ WMM_SHORT_SLOT_TIME + SIFS_DURATION);
+ common->tx_qinfo[ii].weight = common->tx_qinfo[ii].wme_params;
+ common->tx_qinfo[ii].pkt_contended = 0;
+ }
+}
+
+/**
+ * rsi_send_internal_mgmt_frame() - This function sends management frames to
+ * firmware.Also schedules packet to queue
+ * for transmission.
+ * @common: Pointer to the driver private structure.
+ * @skb: Pointer to the socket buffer structure.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int rsi_send_internal_mgmt_frame(struct rsi_common *common,
+ struct sk_buff *skb)
+{
+ struct skb_info *tx_params;
+
+ if (skb == NULL) {
+ rsi_dbg(ERR_ZONE, "%s: Unable to allocate skb\n", __func__);
+ return -ENOMEM;
+ }
+ tx_params = (struct skb_info *)&IEEE80211_SKB_CB(skb)->driver_data;
+ tx_params->flags |= INTERNAL_MGMT_PKT;
+ skb_queue_tail(&common->tx_queue[MGMT_SOFT_Q], skb);
+ rsi_set_event(&common->tx_thread.event);
+ return 0;
+}
+
+/**
+ * rsi_load_radio_caps() - This function is used to send radio capabilities
+ * values to firmware.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: 0 on success, corresponding negative error code on failure.
+ */
+static int rsi_load_radio_caps(struct rsi_common *common)
+{
+ struct rsi_radio_caps *radio_caps;
+ struct rsi_hw *adapter = common->priv;
+ struct ieee80211_hw *hw = adapter->hw;
+ u16 inx = 0;
+ u8 ii;
+ u8 radio_id = 0;
+ u16 gc[20] = {0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0};
+ struct ieee80211_conf *conf = &hw->conf;
+ struct sk_buff *skb;
+
+ rsi_dbg(INFO_ZONE, "%s: Sending rate symbol req frame\n", __func__);
+
+ skb = dev_alloc_skb(sizeof(struct rsi_radio_caps));
+
+ if (!skb) {
+ rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ memset(skb->data, 0, sizeof(struct rsi_radio_caps));
+ radio_caps = (struct rsi_radio_caps *)skb->data;
+
+ radio_caps->desc_word[1] = cpu_to_le16(RADIO_CAPABILITIES);
+ radio_caps->desc_word[4] = cpu_to_le16(RSI_RF_TYPE << 8);
+
+ if (common->channel_width == BW_40MHZ) {
+ radio_caps->desc_word[7] |= cpu_to_le16(RSI_LMAC_CLOCK_80MHZ);
+ radio_caps->desc_word[7] |= cpu_to_le16(RSI_ENABLE_40MHZ);
+ if (common->channel_width) {
+ radio_caps->desc_word[5] =
+ cpu_to_le16(common->channel_width << 12);
+ radio_caps->desc_word[5] |= cpu_to_le16(FULL40M_ENABLE);
+ }
+
+ if (conf_is_ht40_minus(conf)) {
+ radio_caps->desc_word[5] = 0;
+ radio_caps->desc_word[5] |=
+ cpu_to_le16(LOWER_20_ENABLE);
+ radio_caps->desc_word[5] |=
+ cpu_to_le16(LOWER_20_ENABLE >> 12);
+ }
+
+ if (conf_is_ht40_plus(conf)) {
+ radio_caps->desc_word[5] = 0;
+ radio_caps->desc_word[5] |=
+ cpu_to_le16(UPPER_20_ENABLE);
+ radio_caps->desc_word[5] |=
+ cpu_to_le16(UPPER_20_ENABLE >> 12);
+ }
+ }
+
+ radio_caps->desc_word[7] |= cpu_to_le16(radio_id << 8);
+
+ for (ii = 0; ii < MAX_HW_QUEUES; ii++) {
+ radio_caps->qos_params[ii].cont_win_min_q = cpu_to_le16(3);
+ radio_caps->qos_params[ii].cont_win_max_q = cpu_to_le16(0x3f);
+ radio_caps->qos_params[ii].aifsn_val_q = cpu_to_le16(2);
+ radio_caps->qos_params[ii].txop_q = 0;
+ }
+
+ for (ii = 0; ii < MAX_HW_QUEUES - 4; ii++) {
+ radio_caps->qos_params[ii].cont_win_min_q =
+ cpu_to_le16(common->edca_params[ii].cw_min);
+ radio_caps->qos_params[ii].cont_win_max_q =
+ cpu_to_le16(common->edca_params[ii].cw_max);
+ radio_caps->qos_params[ii].aifsn_val_q =
+ cpu_to_le16((common->edca_params[ii].aifs) << 8);
+ radio_caps->qos_params[ii].txop_q =
+ cpu_to_le16(common->edca_params[ii].txop);
+ }
+
+ memcpy(&common->rate_pwr[0], &gc[0], 40);
+ for (ii = 0; ii < 20; ii++)
+ radio_caps->gcpd_per_rate[inx++] =
+ cpu_to_le16(common->rate_pwr[ii] & 0x00FF);
+
+ radio_caps->desc_word[0] = cpu_to_le16((sizeof(struct rsi_radio_caps) -
+ FRAME_DESC_SZ) |
+ (RSI_WIFI_MGMT_Q << 12));
+
+
+ skb_put(skb, (sizeof(struct rsi_radio_caps)));
+
+ return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * rsi_mgmt_pkt_to_core() - This function is the entry point for Mgmt module.
+ * @common: Pointer to the driver private structure.
+ * @msg: Pointer to received packet.
+ * @msg_len: Length of the recieved packet.
+ * @type: Type of recieved packet.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int rsi_mgmt_pkt_to_core(struct rsi_common *common,
+ u8 *msg,
+ s32 msg_len,
+ u8 type)
+{
+ struct rsi_hw *adapter = common->priv;
+ struct ieee80211_tx_info *info;
+ struct skb_info *rx_params;
+ u8 pad_bytes = msg[4];
+ u8 pkt_recv;
+ struct sk_buff *skb;
+ char *buffer;
+
+ if (type == RX_DOT11_MGMT) {
+ if (!adapter->sc_nvifs)
+ return -ENOLINK;
+
+ msg_len -= pad_bytes;
+ if ((msg_len <= 0) || (!msg)) {
+ rsi_dbg(MGMT_RX_ZONE,
+ "%s: Invalid rx msg of len = %d\n",
+ __func__, msg_len);
+ return -EINVAL;
+ }
+
+ skb = dev_alloc_skb(msg_len);
+ if (!skb) {
+ rsi_dbg(ERR_ZONE, "%s: Failed to allocate skb\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ buffer = skb_put(skb, msg_len);
+
+ memcpy(buffer,
+ (u8 *)(msg + FRAME_DESC_SZ + pad_bytes),
+ msg_len);
+
+ pkt_recv = buffer[0];
+
+ info = IEEE80211_SKB_CB(skb);
+ rx_params = (struct skb_info *)info->driver_data;
+ rx_params->rssi = rsi_get_rssi(msg);
+ rx_params->channel = rsi_get_channel(msg);
+ rsi_indicate_pkt_to_os(common, skb);
+ } else {
+ rsi_dbg(MGMT_TX_ZONE, "%s: Internal Packet\n", __func__);
+ }
+
+ return 0;
+}
+
+/**
+ * rsi_hal_send_sta_notify_frame() - This function sends the station notify
+ * frame to firmware.
+ * @common: Pointer to the driver private structure.
+ * @opmode: Operating mode of device.
+ * @notify_event: Notification about station connection.
+ * @bssid: bssid.
+ * @qos_enable: Qos is enabled.
+ * @aid: Aid (unique for all STA).
+ *
+ * Return: status: 0 on success, corresponding negative error code on failure.
+ */
+static int rsi_hal_send_sta_notify_frame(struct rsi_common *common,
+ u8 opmode,
+ u8 notify_event,
+ const unsigned char *bssid,
+ u8 qos_enable,
+ u16 aid)
+{
+ struct sk_buff *skb = NULL;
+ struct rsi_peer_notify *peer_notify;
+ u16 vap_id = 0;
+ int status;
+
+ rsi_dbg(MGMT_TX_ZONE, "%s: Sending sta notify frame\n", __func__);
+
+ skb = dev_alloc_skb(sizeof(struct rsi_peer_notify));
+
+ if (!skb) {
+ rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ memset(skb->data, 0, sizeof(struct rsi_peer_notify));
+ peer_notify = (struct rsi_peer_notify *)skb->data;
+
+ peer_notify->command = cpu_to_le16(opmode << 1);
+
+ switch (notify_event) {
+ case STA_CONNECTED:
+ peer_notify->command |= cpu_to_le16(RSI_ADD_PEER);
+ break;
+ case STA_DISCONNECTED:
+ peer_notify->command |= cpu_to_le16(RSI_DELETE_PEER);
+ break;
+ default:
+ break;
+ }
+
+ peer_notify->command |= cpu_to_le16((aid & 0xfff) << 4);
+ ether_addr_copy(peer_notify->mac_addr, bssid);
+
+ peer_notify->sta_flags = cpu_to_le32((qos_enable) ? 1 : 0);
+
+ peer_notify->desc_word[0] =
+ cpu_to_le16((sizeof(struct rsi_peer_notify) - FRAME_DESC_SZ) |
+ (RSI_WIFI_MGMT_Q << 12));
+ peer_notify->desc_word[1] = cpu_to_le16(PEER_NOTIFY);
+ peer_notify->desc_word[7] |= cpu_to_le16(vap_id << 8);
+
+ skb_put(skb, sizeof(struct rsi_peer_notify));
+
+ status = rsi_send_internal_mgmt_frame(common, skb);
+
+ if (!status && qos_enable) {
+ rsi_set_contention_vals(common);
+ status = rsi_load_radio_caps(common);
+ }
+ return status;
+}
+
+/**
+ * rsi_send_aggregation_params_frame() - This function sends the ampdu
+ * indication frame to firmware.
+ * @common: Pointer to the driver private structure.
+ * @tid: traffic identifier.
+ * @ssn: ssn.
+ * @buf_size: buffer size.
+ * @event: notification about station connection.
+ *
+ * Return: 0 on success, corresponding negative error code on failure.
+ */
+int rsi_send_aggregation_params_frame(struct rsi_common *common,
+ u16 tid,
+ u16 ssn,
+ u8 buf_size,
+ u8 event)
+{
+ struct sk_buff *skb = NULL;
+ struct rsi_mac_frame *mgmt_frame;
+ u8 peer_id = 0;
+
+ skb = dev_alloc_skb(FRAME_DESC_SZ);
+
+ if (!skb) {
+ rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ memset(skb->data, 0, FRAME_DESC_SZ);
+ mgmt_frame = (struct rsi_mac_frame *)skb->data;
+
+ rsi_dbg(MGMT_TX_ZONE, "%s: Sending AMPDU indication frame\n", __func__);
+
+ mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12);
+ mgmt_frame->desc_word[1] = cpu_to_le16(AMPDU_IND);
+
+ if (event == STA_TX_ADDBA_DONE) {
+ mgmt_frame->desc_word[4] = cpu_to_le16(ssn);
+ mgmt_frame->desc_word[5] = cpu_to_le16(buf_size);
+ mgmt_frame->desc_word[7] =
+ cpu_to_le16((tid | (START_AMPDU_AGGR << 4) | (peer_id << 8)));
+ } else if (event == STA_RX_ADDBA_DONE) {
+ mgmt_frame->desc_word[4] = cpu_to_le16(ssn);
+ mgmt_frame->desc_word[7] = cpu_to_le16(tid |
+ (START_AMPDU_AGGR << 4) |
+ (RX_BA_INDICATION << 5) |
+ (peer_id << 8));
+ } else if (event == STA_TX_DELBA) {
+ mgmt_frame->desc_word[7] = cpu_to_le16(tid |
+ (STOP_AMPDU_AGGR << 4) |
+ (peer_id << 8));
+ } else if (event == STA_RX_DELBA) {
+ mgmt_frame->desc_word[7] = cpu_to_le16(tid |
+ (STOP_AMPDU_AGGR << 4) |
+ (RX_BA_INDICATION << 5) |
+ (peer_id << 8));
+ }
+
+ skb_put(skb, FRAME_DESC_SZ);
+
+ return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * rsi_program_bb_rf() - This function starts base band and RF programming.
+ * This is called after initial configurations are done.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: 0 on success, corresponding negative error code on failure.
+ */
+static int rsi_program_bb_rf(struct rsi_common *common)
+{
+ struct sk_buff *skb;
+ struct rsi_mac_frame *mgmt_frame;
+
+ rsi_dbg(MGMT_TX_ZONE, "%s: Sending program BB/RF frame\n", __func__);
+
+ skb = dev_alloc_skb(FRAME_DESC_SZ);
+ if (!skb) {
+ rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ memset(skb->data, 0, FRAME_DESC_SZ);
+ mgmt_frame = (struct rsi_mac_frame *)skb->data;
+
+ mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12);
+ mgmt_frame->desc_word[1] = cpu_to_le16(BBP_PROG_IN_TA);
+ mgmt_frame->desc_word[4] = cpu_to_le16(common->endpoint << 8);
+
+ if (common->rf_reset) {
+ mgmt_frame->desc_word[7] = cpu_to_le16(RF_RESET_ENABLE);
+ rsi_dbg(MGMT_TX_ZONE, "%s: ===> RF RESET REQUEST SENT <===\n",
+ __func__);
+ common->rf_reset = 0;
+ }
+ common->bb_rf_prog_count = 1;
+ mgmt_frame->desc_word[7] |= cpu_to_le16(PUT_BBP_RESET |
+ BBP_REG_WRITE | (RSI_RF_TYPE << 4));
+ skb_put(skb, FRAME_DESC_SZ);
+
+ return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * rsi_set_vap_capabilities() - This function send vap capability to firmware.
+ * @common: Pointer to the driver private structure.
+ * @opmode: Operating mode of device.
+ *
+ * Return: 0 on success, corresponding negative error code on failure.
+ */
+int rsi_set_vap_capabilities(struct rsi_common *common, enum opmode mode)
+{
+ struct sk_buff *skb = NULL;
+ struct rsi_vap_caps *vap_caps;
+ u16 vap_id = 0;
+
+ rsi_dbg(MGMT_TX_ZONE, "%s: Sending VAP capabilities frame\n", __func__);
+
+ skb = dev_alloc_skb(sizeof(struct rsi_vap_caps));
+ if (!skb) {
+ rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ memset(skb->data, 0, sizeof(struct rsi_vap_caps));
+ vap_caps = (struct rsi_vap_caps *)skb->data;
+
+ vap_caps->desc_word[0] = cpu_to_le16((sizeof(struct rsi_vap_caps) -
+ FRAME_DESC_SZ) |
+ (RSI_WIFI_MGMT_Q << 12));
+ vap_caps->desc_word[1] = cpu_to_le16(VAP_CAPABILITIES);
+ vap_caps->desc_word[4] = cpu_to_le16(mode |
+ (common->channel_width << 8));
+ vap_caps->desc_word[7] = cpu_to_le16((vap_id << 8) |
+ (common->mac_id << 4) |
+ common->radio_id);
+
+ memcpy(vap_caps->mac_addr, common->mac_addr, IEEE80211_ADDR_LEN);
+ vap_caps->keep_alive_period = cpu_to_le16(90);
+ vap_caps->frag_threshold = cpu_to_le16(IEEE80211_MAX_FRAG_THRESHOLD);
+
+ vap_caps->rts_threshold = cpu_to_le16(common->rts_threshold);
+ vap_caps->default_mgmt_rate = 0;
+ if (conf_is_ht40(&common->priv->hw->conf)) {
+ vap_caps->default_ctrl_rate =
+ cpu_to_le32(RSI_RATE_6 | FULL40M_ENABLE << 16);
+ } else {
+ vap_caps->default_ctrl_rate = cpu_to_le32(RSI_RATE_6);
+ }
+ vap_caps->default_data_rate = 0;
+ vap_caps->beacon_interval = cpu_to_le16(200);
+ vap_caps->dtim_period = cpu_to_le16(4);
+
+ skb_put(skb, sizeof(*vap_caps));
+
+ return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * rsi_hal_load_key() - This function is used to load keys within the firmware.
+ * @common: Pointer to the driver private structure.
+ * @data: Pointer to the key data.
+ * @key_len: Key length to be loaded.
+ * @key_type: Type of key: GROUP/PAIRWISE.
+ * @key_id: Key index.
+ * @cipher: Type of cipher used.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+int rsi_hal_load_key(struct rsi_common *common,
+ u8 *data,
+ u16 key_len,
+ u8 key_type,
+ u8 key_id,
+ u32 cipher)
+{
+ struct sk_buff *skb = NULL;
+ struct rsi_set_key *set_key;
+ u16 key_descriptor = 0;
+
+ rsi_dbg(MGMT_TX_ZONE, "%s: Sending load key frame\n", __func__);
+
+ skb = dev_alloc_skb(sizeof(struct rsi_set_key));
+ if (!skb) {
+ rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ memset(skb->data, 0, sizeof(struct rsi_set_key));
+ set_key = (struct rsi_set_key *)skb->data;
+
+ if ((cipher == WLAN_CIPHER_SUITE_WEP40) ||
+ (cipher == WLAN_CIPHER_SUITE_WEP104)) {
+ key_len += 1;
+ key_descriptor |= BIT(2);
+ if (key_len >= 13)
+ key_descriptor |= BIT(3);
+ } else if (cipher != KEY_TYPE_CLEAR) {
+ key_descriptor |= BIT(4);
+ if (key_type == RSI_PAIRWISE_KEY)
+ key_id = 0;
+ if (cipher == WLAN_CIPHER_SUITE_TKIP)
+ key_descriptor |= BIT(5);
+ }
+ key_descriptor |= (key_type | BIT(13) | (key_id << 14));
+
+ set_key->desc_word[0] = cpu_to_le16((sizeof(struct rsi_set_key) -
+ FRAME_DESC_SZ) |
+ (RSI_WIFI_MGMT_Q << 12));
+ set_key->desc_word[1] = cpu_to_le16(SET_KEY_REQ);
+ set_key->desc_word[4] = cpu_to_le16(key_descriptor);
+
+ if ((cipher == WLAN_CIPHER_SUITE_WEP40) ||
+ (cipher == WLAN_CIPHER_SUITE_WEP104)) {
+ memcpy(&set_key->key[key_id][1],
+ data,
+ key_len * 2);
+ } else {
+ memcpy(&set_key->key[0][0], data, key_len);
+ }
+
+ memcpy(set_key->tx_mic_key, &data[16], 8);
+ memcpy(set_key->rx_mic_key, &data[24], 8);
+
+ skb_put(skb, sizeof(struct rsi_set_key));
+
+ return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/*
+ * rsi_load_bootup_params() - This function send bootup params to the firmware.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: 0 on success, corresponding error code on failure.
+ */
+static u8 rsi_load_bootup_params(struct rsi_common *common)
+{
+ struct sk_buff *skb;
+ struct rsi_boot_params *boot_params;
+
+ rsi_dbg(MGMT_TX_ZONE, "%s: Sending boot params frame\n", __func__);
+ skb = dev_alloc_skb(sizeof(struct rsi_boot_params));
+ if (!skb) {
+ rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ memset(skb->data, 0, sizeof(struct rsi_boot_params));
+ boot_params = (struct rsi_boot_params *)skb->data;
+
+ rsi_dbg(MGMT_TX_ZONE, "%s:\n", __func__);
+
+ if (common->channel_width == BW_40MHZ) {
+ memcpy(&boot_params->bootup_params,
+ &boot_params_40,
+ sizeof(struct bootup_params));
+ rsi_dbg(MGMT_TX_ZONE, "%s: Packet 40MHZ <=== %d\n", __func__,
+ UMAC_CLK_40BW);
+ boot_params->desc_word[7] = cpu_to_le16(UMAC_CLK_40BW);
+ } else {
+ memcpy(&boot_params->bootup_params,
+ &boot_params_20,
+ sizeof(struct bootup_params));
+ if (boot_params_20.valid != cpu_to_le32(VALID_20)) {
+ boot_params->desc_word[7] = cpu_to_le16(UMAC_CLK_20BW);
+ rsi_dbg(MGMT_TX_ZONE,
+ "%s: Packet 20MHZ <=== %d\n", __func__,
+ UMAC_CLK_20BW);
+ } else {
+ boot_params->desc_word[7] = cpu_to_le16(UMAC_CLK_40MHZ);
+ rsi_dbg(MGMT_TX_ZONE,
+ "%s: Packet 20MHZ <=== %d\n", __func__,
+ UMAC_CLK_40MHZ);
+ }
+ }
+
+ /**
+ * Bit{0:11} indicates length of the Packet
+ * Bit{12:15} indicates host queue number
+ */
+ boot_params->desc_word[0] = cpu_to_le16(sizeof(struct bootup_params) |
+ (RSI_WIFI_MGMT_Q << 12));
+ boot_params->desc_word[1] = cpu_to_le16(BOOTUP_PARAMS_REQUEST);
+
+ skb_put(skb, sizeof(struct rsi_boot_params));
+
+ return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * rsi_send_reset_mac() - This function prepares reset MAC request and sends an
+ * internal management frame to indicate it to firmware.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: 0 on success, corresponding error code on failure.
+ */
+static int rsi_send_reset_mac(struct rsi_common *common)
+{
+ struct sk_buff *skb;
+ struct rsi_mac_frame *mgmt_frame;
+
+ rsi_dbg(MGMT_TX_ZONE, "%s: Sending reset MAC frame\n", __func__);
+
+ skb = dev_alloc_skb(FRAME_DESC_SZ);
+ if (!skb) {
+ rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ memset(skb->data, 0, FRAME_DESC_SZ);
+ mgmt_frame = (struct rsi_mac_frame *)skb->data;
+
+ mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12);
+ mgmt_frame->desc_word[1] = cpu_to_le16(RESET_MAC_REQ);
+ mgmt_frame->desc_word[4] = cpu_to_le16(RETRY_COUNT << 8);
+
+ skb_put(skb, FRAME_DESC_SZ);
+
+ return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * rsi_set_channel() - This function programs the channel.
+ * @common: Pointer to the driver private structure.
+ * @channel: Channel value to be set.
+ *
+ * Return: 0 on success, corresponding error code on failure.
+ */
+int rsi_set_channel(struct rsi_common *common, u16 channel)
+{
+ struct sk_buff *skb = NULL;
+ struct rsi_mac_frame *mgmt_frame;
+
+ rsi_dbg(MGMT_TX_ZONE,
+ "%s: Sending scan req frame\n", __func__);
+
+ skb = dev_alloc_skb(FRAME_DESC_SZ);
+ if (!skb) {
+ rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ memset(skb->data, 0, FRAME_DESC_SZ);
+ mgmt_frame = (struct rsi_mac_frame *)skb->data;
+
+ if (common->band == IEEE80211_BAND_5GHZ) {
+ if ((channel >= 36) && (channel <= 64))
+ channel = ((channel - 32) / 4);
+ else if ((channel > 64) && (channel <= 140))
+ channel = ((channel - 102) / 4) + 8;
+ else if (channel >= 149)
+ channel = ((channel - 151) / 4) + 18;
+ else
+ return -EINVAL;
+ } else {
+ if (channel > 14) {
+ rsi_dbg(ERR_ZONE, "%s: Invalid chno %d, band = %d\n",
+ __func__, channel, common->band);
+ return -EINVAL;
+ }
+ }
+
+ mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12);
+ mgmt_frame->desc_word[1] = cpu_to_le16(SCAN_REQUEST);
+ mgmt_frame->desc_word[4] = cpu_to_le16(channel);
+
+ mgmt_frame->desc_word[7] = cpu_to_le16(PUT_BBP_RESET |
+ BBP_REG_WRITE |
+ (RSI_RF_TYPE << 4));
+
+ mgmt_frame->desc_word[5] = cpu_to_le16(0x01);
+
+ if (common->channel_width == BW_40MHZ)
+ mgmt_frame->desc_word[5] |= cpu_to_le16(0x1 << 8);
+
+ common->channel = channel;
+
+ skb_put(skb, FRAME_DESC_SZ);
+
+ return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * rsi_compare() - This function is used to compare two integers
+ * @a: pointer to the first integer
+ * @b: pointer to the second integer
+ *
+ * Return: 0 if both are equal, -1 if the first is smaller, else 1
+ */
+static int rsi_compare(const void *a, const void *b)
+{
+ u16 _a = *(const u16 *)(a);
+ u16 _b = *(const u16 *)(b);
+
+ if (_a > _b)
+ return -1;
+
+ if (_a < _b)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * rsi_map_rates() - This function is used to map selected rates to hw rates.
+ * @rate: The standard rate to be mapped.
+ * @offset: Offset that will be returned.
+ *
+ * Return: 0 if it is a mcs rate, else 1
+ */
+static bool rsi_map_rates(u16 rate, int *offset)
+{
+ int kk;
+ for (kk = 0; kk < ARRAY_SIZE(rsi_mcsrates); kk++) {
+ if (rate == mcs[kk]) {
+ *offset = kk;
+ return false;
+ }
+ }
+
+ for (kk = 0; kk < ARRAY_SIZE(rsi_rates); kk++) {
+ if (rate == rsi_rates[kk].bitrate / 5) {
+ *offset = kk;
+ break;
+ }
+ }
+ return true;
+}
+
+/**
+ * rsi_send_auto_rate_request() - This function is to set rates for connection
+ * and send autorate request to firmware.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: 0 on success, corresponding error code on failure.
+ */
+static int rsi_send_auto_rate_request(struct rsi_common *common)
+{
+ struct sk_buff *skb;
+ struct rsi_auto_rate *auto_rate;
+ int ii = 0, jj = 0, kk = 0;
+ struct ieee80211_hw *hw = common->priv->hw;
+ u8 band = hw->conf.chandef.chan->band;
+ u8 num_supported_rates = 0;
+ u8 rate_offset = 0;
+ u32 rate_bitmap = common->bitrate_mask[band];
+
+ u16 *selected_rates, min_rate;
+
+ skb = dev_alloc_skb(sizeof(struct rsi_auto_rate));
+ if (!skb) {
+ rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ selected_rates = kmalloc(2 * RSI_TBL_SZ, GFP_KERNEL);
+ if (!selected_rates) {
+ rsi_dbg(ERR_ZONE, "%s: Failed in allocation of mem\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ memset(skb->data, 0, sizeof(struct rsi_auto_rate));
+ memset(selected_rates, 0, 2 * RSI_TBL_SZ);
+
+ auto_rate = (struct rsi_auto_rate *)skb->data;
+
+ auto_rate->aarf_rssi = cpu_to_le16(((u16)3 << 6) | (u16)(18 & 0x3f));
+ auto_rate->collision_tolerance = cpu_to_le16(3);
+ auto_rate->failure_limit = cpu_to_le16(3);
+ auto_rate->initial_boundary = cpu_to_le16(3);
+ auto_rate->max_threshold_limt = cpu_to_le16(27);
+
+ auto_rate->desc_word[1] = cpu_to_le16(AUTO_RATE_IND);
+
+ if (common->channel_width == BW_40MHZ)
+ auto_rate->desc_word[7] |= cpu_to_le16(1);
+
+ if (band == IEEE80211_BAND_2GHZ)
+ min_rate = STD_RATE_01;
+ else
+ min_rate = STD_RATE_06;
+
+ for (ii = 0, jj = 0; ii < ARRAY_SIZE(rsi_rates); ii++) {
+ if (rate_bitmap & BIT(ii)) {
+ selected_rates[jj++] = (rsi_rates[ii].bitrate / 5);
+ rate_offset++;
+ }
+ }
+ num_supported_rates = jj;
+
+ if (common->vif_info[0].is_ht) {
+ for (ii = 0; ii < ARRAY_SIZE(mcs); ii++)
+ selected_rates[jj++] = mcs[ii];
+ num_supported_rates += ARRAY_SIZE(mcs);
+ rate_offset += ARRAY_SIZE(mcs);
+ }
+
+ if (rate_offset < (RSI_TBL_SZ / 2) - 1) {
+ for (ii = jj; ii < (RSI_TBL_SZ / 2); ii++) {
+ selected_rates[jj++] = min_rate;
+ rate_offset++;
+ }
+ }
+
+ sort(selected_rates, jj, sizeof(u16), &rsi_compare, NULL);
+
+ /* mapping the rates to RSI rates */
+ for (ii = 0; ii < jj; ii++) {
+ if (rsi_map_rates(selected_rates[ii], &kk)) {
+ auto_rate->supported_rates[ii] =
+ cpu_to_le16(rsi_rates[kk].hw_value);
+ } else {
+ auto_rate->supported_rates[ii] =
+ cpu_to_le16(rsi_mcsrates[kk]);
+ }
+ }
+
+ /* loading HT rates in the bottom half of the auto rate table */
+ if (common->vif_info[0].is_ht) {
+ if (common->vif_info[0].sgi)
+ auto_rate->supported_rates[rate_offset++] =
+ cpu_to_le16(RSI_RATE_MCS7_SG);
+
+ for (ii = rate_offset, kk = ARRAY_SIZE(rsi_mcsrates) - 1;
+ ii < rate_offset + 2 * ARRAY_SIZE(rsi_mcsrates); ii++) {
+ if (common->vif_info[0].sgi)
+ auto_rate->supported_rates[ii++] =
+ cpu_to_le16(rsi_mcsrates[kk] | BIT(9));
+ auto_rate->supported_rates[ii] =
+ cpu_to_le16(rsi_mcsrates[kk--]);
+ }
+
+ for (; ii < RSI_TBL_SZ; ii++) {
+ auto_rate->supported_rates[ii] =
+ cpu_to_le16(rsi_mcsrates[0]);
+ }
+ }
+
+ auto_rate->num_supported_rates = cpu_to_le16(num_supported_rates * 2);
+ auto_rate->moderate_rate_inx = cpu_to_le16(num_supported_rates / 2);
+ auto_rate->desc_word[7] |= cpu_to_le16(0 << 8);
+ num_supported_rates *= 2;
+
+ auto_rate->desc_word[0] = cpu_to_le16((sizeof(*auto_rate) -
+ FRAME_DESC_SZ) |
+ (RSI_WIFI_MGMT_Q << 12));
+
+ skb_put(skb,
+ sizeof(struct rsi_auto_rate));
+ kfree(selected_rates);
+
+ return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * rsi_inform_bss_status() - This function informs about bss status with the
+ * help of sta notify params by sending an internal
+ * management frame to firmware.
+ * @common: Pointer to the driver private structure.
+ * @status: Bss status type.
+ * @bssid: Bssid.
+ * @qos_enable: Qos is enabled.
+ * @aid: Aid (unique for all STAs).
+ *
+ * Return: None.
+ */
+void rsi_inform_bss_status(struct rsi_common *common,
+ u8 status,
+ const unsigned char *bssid,
+ u8 qos_enable,
+ u16 aid)
+{
+ if (status) {
+ rsi_hal_send_sta_notify_frame(common,
+ NL80211_IFTYPE_STATION,
+ STA_CONNECTED,
+ bssid,
+ qos_enable,
+ aid);
+ if (common->min_rate == 0xffff)
+ rsi_send_auto_rate_request(common);
+ } else {
+ rsi_hal_send_sta_notify_frame(common,
+ NL80211_IFTYPE_STATION,
+ STA_DISCONNECTED,
+ bssid,
+ qos_enable,
+ aid);
+ }
+}
+
+/**
+ * rsi_eeprom_read() - This function sends a frame to read the mac address
+ * from the eeprom.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int rsi_eeprom_read(struct rsi_common *common)
+{
+ struct rsi_mac_frame *mgmt_frame;
+ struct sk_buff *skb;
+
+ rsi_dbg(MGMT_TX_ZONE, "%s: Sending EEPROM read req frame\n", __func__);
+
+ skb = dev_alloc_skb(FRAME_DESC_SZ);
+ if (!skb) {
+ rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ memset(skb->data, 0, FRAME_DESC_SZ);
+ mgmt_frame = (struct rsi_mac_frame *)skb->data;
+
+ /* FrameType */
+ mgmt_frame->desc_word[1] = cpu_to_le16(EEPROM_READ_TYPE);
+ mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12);
+ /* Number of bytes to read */
+ mgmt_frame->desc_word[3] = cpu_to_le16(ETH_ALEN +
+ WLAN_MAC_MAGIC_WORD_LEN +
+ WLAN_HOST_MODE_LEN +
+ WLAN_FW_VERSION_LEN);
+ /* Address to read */
+ mgmt_frame->desc_word[4] = cpu_to_le16(WLAN_MAC_EEPROM_ADDR);
+
+ skb_put(skb, FRAME_DESC_SZ);
+
+ return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * rsi_handle_ta_confirm_type() - This function handles the confirm frames.
+ * @common: Pointer to the driver private structure.
+ * @msg: Pointer to received packet.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int rsi_handle_ta_confirm_type(struct rsi_common *common,
+ u8 *msg)
+{
+ u8 sub_type = (msg[15] & 0xff);
+
+ switch (sub_type) {
+ case BOOTUP_PARAMS_REQUEST:
+ rsi_dbg(FSM_ZONE, "%s: Boot up params confirm received\n",
+ __func__);
+ if (common->fsm_state == FSM_BOOT_PARAMS_SENT) {
+ if (rsi_eeprom_read(common)) {
+ common->fsm_state = FSM_CARD_NOT_READY;
+ goto out;
+ } else {
+ common->fsm_state = FSM_EEPROM_READ_MAC_ADDR;
+ }
+ } else {
+ rsi_dbg(ERR_ZONE,
+ "%s: Received bootup params cfm in %d state\n",
+ __func__, common->fsm_state);
+ return 0;
+ }
+ break;
+
+ case EEPROM_READ_TYPE:
+ if (common->fsm_state == FSM_EEPROM_READ_MAC_ADDR) {
+ if (msg[16] == MAGIC_WORD) {
+ u8 offset = (FRAME_DESC_SZ + WLAN_HOST_MODE_LEN
+ + WLAN_MAC_MAGIC_WORD_LEN);
+ memcpy(common->mac_addr,
+ &msg[offset],
+ ETH_ALEN);
+ memcpy(&common->fw_ver,
+ &msg[offset + ETH_ALEN],
+ sizeof(struct version_info));
+
+ } else {
+ common->fsm_state = FSM_CARD_NOT_READY;
+ break;
+ }
+ if (rsi_send_reset_mac(common))
+ goto out;
+ else
+ common->fsm_state = FSM_RESET_MAC_SENT;
+ } else {
+ rsi_dbg(ERR_ZONE,
+ "%s: Received eeprom mac addr in %d state\n",
+ __func__, common->fsm_state);
+ return 0;
+ }
+ break;
+
+ case RESET_MAC_REQ:
+ if (common->fsm_state == FSM_RESET_MAC_SENT) {
+ rsi_dbg(FSM_ZONE, "%s: Reset MAC cfm received\n",
+ __func__);
+
+ if (rsi_load_radio_caps(common))
+ goto out;
+ else
+ common->fsm_state = FSM_RADIO_CAPS_SENT;
+ } else {
+ rsi_dbg(ERR_ZONE,
+ "%s: Received reset mac cfm in %d state\n",
+ __func__, common->fsm_state);
+ return 0;
+ }
+ break;
+
+ case RADIO_CAPABILITIES:
+ if (common->fsm_state == FSM_RADIO_CAPS_SENT) {
+ common->rf_reset = 1;
+ if (rsi_program_bb_rf(common)) {
+ goto out;
+ } else {
+ common->fsm_state = FSM_BB_RF_PROG_SENT;
+ rsi_dbg(FSM_ZONE, "%s: Radio cap cfm received\n",
+ __func__);
+ }
+ } else {
+ rsi_dbg(ERR_ZONE,
+ "%s: Received radio caps cfm in %d state\n",
+ __func__, common->fsm_state);
+ return 0;
+ }
+ break;
+
+ case BB_PROG_VALUES_REQUEST:
+ case RF_PROG_VALUES_REQUEST:
+ case BBP_PROG_IN_TA:
+ rsi_dbg(FSM_ZONE, "%s: BB/RF cfm received\n", __func__);
+ if (common->fsm_state == FSM_BB_RF_PROG_SENT) {
+ common->bb_rf_prog_count--;
+ if (!common->bb_rf_prog_count) {
+ common->fsm_state = FSM_MAC_INIT_DONE;
+ return rsi_mac80211_attach(common);
+ }
+ } else {
+ goto out;
+ }
+ break;
+
+ default:
+ rsi_dbg(INFO_ZONE, "%s: Invalid TA confirm pkt received\n",
+ __func__);
+ break;
+ }
+ return 0;
+out:
+ rsi_dbg(ERR_ZONE, "%s: Unable to send pkt/Invalid frame received\n",
+ __func__);
+ return -EINVAL;
+}
+
+/**
+ * rsi_mgmt_pkt_recv() - This function processes the management packets
+ * recieved from the hardware.
+ * @common: Pointer to the driver private structure.
+ * @msg: Pointer to the received packet.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg)
+{
+ s32 msg_len = (le16_to_cpu(*(__le16 *)&msg[0]) & 0x0fff);
+ u16 msg_type = (msg[2]);
+
+ rsi_dbg(FSM_ZONE, "%s: Msg Len: %d, Msg Type: %4x\n",
+ __func__, msg_len, msg_type);
+
+ if (msg_type == TA_CONFIRM_TYPE) {
+ return rsi_handle_ta_confirm_type(common, msg);
+ } else if (msg_type == CARD_READY_IND) {
+ rsi_dbg(FSM_ZONE, "%s: Card ready indication received\n",
+ __func__);
+ if (common->fsm_state == FSM_CARD_NOT_READY) {
+ rsi_set_default_parameters(common);
+
+ if (rsi_load_bootup_params(common))
+ return -ENOMEM;
+ else
+ common->fsm_state = FSM_BOOT_PARAMS_SENT;
+ } else {
+ return -EINVAL;
+ }
+ } else if (msg_type == TX_STATUS_IND) {
+ if (msg[15] == PROBEREQ_CONFIRM) {
+ common->mgmt_q_block = false;
+ rsi_dbg(FSM_ZONE, "%s: Probe confirm received\n",
+ __func__);
+ }
+ } else {
+ return rsi_mgmt_pkt_to_core(common, msg, msg_len, msg_type);
+ }
+ return 0;
+}
diff --git a/drivers/net/wireless/rsi/rsi_91x_pkt.c b/drivers/net/wireless/rsi/rsi_91x_pkt.c
new file mode 100644
index 000000000000..8e48e72bae20
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_91x_pkt.c
@@ -0,0 +1,196 @@
+/**
+ * Copyright (c) 2014 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "rsi_mgmt.h"
+
+/**
+ * rsi_send_data_pkt() - This function sends the recieved data packet from
+ * driver to device.
+ * @common: Pointer to the driver private structure.
+ * @skb: Pointer to the socket buffer structure.
+ *
+ * Return: status: 0 on success, -1 on failure.
+ */
+int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb)
+{
+ struct rsi_hw *adapter = common->priv;
+ struct ieee80211_hdr *tmp_hdr = NULL;
+ struct ieee80211_tx_info *info;
+ struct skb_info *tx_params;
+ struct ieee80211_bss_conf *bss = NULL;
+ int status = -EINVAL;
+ u8 ieee80211_size = MIN_802_11_HDR_LEN;
+ u8 extnd_size = 0;
+ __le16 *frame_desc;
+ u16 seq_num = 0;
+
+ info = IEEE80211_SKB_CB(skb);
+ bss = &info->control.vif->bss_conf;
+ tx_params = (struct skb_info *)info->driver_data;
+
+ if (!bss->assoc)
+ goto err;
+
+ tmp_hdr = (struct ieee80211_hdr *)&skb->data[0];
+ seq_num = (le16_to_cpu(tmp_hdr->seq_ctrl) >> 4);
+
+ extnd_size = ((uintptr_t)skb->data & 0x3);
+
+ if ((FRAME_DESC_SZ + extnd_size) > skb_headroom(skb)) {
+ rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__);
+ status = -ENOSPC;
+ goto err;
+ }
+
+ skb_push(skb, (FRAME_DESC_SZ + extnd_size));
+ frame_desc = (__le16 *)&skb->data[0];
+ memset((u8 *)frame_desc, 0, FRAME_DESC_SZ);
+
+ if (ieee80211_is_data_qos(tmp_hdr->frame_control)) {
+ ieee80211_size += 2;
+ frame_desc[6] |= cpu_to_le16(BIT(12));
+ }
+
+ if ((!(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) &&
+ (common->secinfo.security_enable)) {
+ if (rsi_is_cipher_wep(common))
+ ieee80211_size += 4;
+ else
+ ieee80211_size += 8;
+ frame_desc[6] |= cpu_to_le16(BIT(15));
+ }
+
+ frame_desc[0] = cpu_to_le16((skb->len - FRAME_DESC_SZ) |
+ (RSI_WIFI_DATA_Q << 12));
+ frame_desc[2] = cpu_to_le16((extnd_size) | (ieee80211_size) << 8);
+
+ if (common->min_rate != 0xffff) {
+ /* Send fixed rate */
+ frame_desc[3] = cpu_to_le16(RATE_INFO_ENABLE);
+ frame_desc[4] = cpu_to_le16(common->min_rate);
+ }
+
+ frame_desc[6] |= cpu_to_le16(seq_num & 0xfff);
+ frame_desc[7] = cpu_to_le16(((tx_params->tid & 0xf) << 4) |
+ (skb->priority & 0xf) |
+ (tx_params->sta_id << 8));
+
+ status = adapter->host_intf_write_pkt(common->priv,
+ skb->data,
+ skb->len);
+ if (status)
+ rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n",
+ __func__);
+
+err:
+ ++common->tx_stats.total_tx_pkt_freed[skb->priority];
+ rsi_indicate_tx_status(common->priv, skb, status);
+ return status;
+}
+
+/**
+ * rsi_send_mgmt_pkt() - This functions sends the received management packet
+ * from driver to device.
+ * @common: Pointer to the driver private structure.
+ * @skb: Pointer to the socket buffer structure.
+ *
+ * Return: status: 0 on success, -1 on failure.
+ */
+int rsi_send_mgmt_pkt(struct rsi_common *common,
+ struct sk_buff *skb)
+{
+ struct rsi_hw *adapter = common->priv;
+ struct ieee80211_hdr *wh = NULL;
+ struct ieee80211_tx_info *info;
+ struct ieee80211_bss_conf *bss = NULL;
+ struct skb_info *tx_params;
+ int status = -E2BIG;
+ __le16 *msg = NULL;
+ u8 extnd_size = 0;
+ u8 vap_id = 0;
+
+ info = IEEE80211_SKB_CB(skb);
+ tx_params = (struct skb_info *)info->driver_data;
+ extnd_size = ((uintptr_t)skb->data & 0x3);
+
+ if (tx_params->flags & INTERNAL_MGMT_PKT) {
+ if ((extnd_size) > skb_headroom(skb)) {
+ rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__);
+ dev_kfree_skb(skb);
+ return -ENOSPC;
+ }
+ skb_push(skb, extnd_size);
+ skb->data[extnd_size + 4] = extnd_size;
+ status = adapter->host_intf_write_pkt(common->priv,
+ (u8 *)skb->data,
+ skb->len);
+ if (status) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to write the packet\n", __func__);
+ }
+ dev_kfree_skb(skb);
+ return status;
+ }
+
+ bss = &info->control.vif->bss_conf;
+ wh = (struct ieee80211_hdr *)&skb->data[0];
+
+ if (FRAME_DESC_SZ > skb_headroom(skb))
+ goto err;
+
+ skb_push(skb, FRAME_DESC_SZ);
+ memset(skb->data, 0, FRAME_DESC_SZ);
+ msg = (__le16 *)skb->data;
+
+ if (skb->len > MAX_MGMT_PKT_SIZE) {
+ rsi_dbg(INFO_ZONE, "%s: Dropping mgmt pkt > 512\n", __func__);
+ goto err;
+ }
+
+ msg[0] = cpu_to_le16((skb->len - FRAME_DESC_SZ) |
+ (RSI_WIFI_MGMT_Q << 12));
+ msg[1] = cpu_to_le16(TX_DOT11_MGMT);
+ msg[2] = cpu_to_le16(MIN_802_11_HDR_LEN << 8);
+ msg[3] = cpu_to_le16(RATE_INFO_ENABLE);
+ msg[6] = cpu_to_le16(le16_to_cpu(wh->seq_ctrl) >> 4);
+
+ if (wh->addr1[0] & BIT(0))
+ msg[3] |= cpu_to_le16(RSI_BROADCAST_PKT);
+
+ if (common->band == IEEE80211_BAND_2GHZ)
+ msg[4] = cpu_to_le16(RSI_11B_MODE);
+ else
+ msg[4] = cpu_to_le16((RSI_RATE_6 & 0x0f) | RSI_11G_MODE);
+
+ /* Indicate to firmware to give cfm */
+ if ((skb->data[16] == IEEE80211_STYPE_PROBE_REQ) && (!bss->assoc)) {
+ msg[1] |= cpu_to_le16(BIT(10));
+ msg[7] = cpu_to_le16(PROBEREQ_CONFIRM);
+ common->mgmt_q_block = true;
+ }
+
+ msg[7] |= cpu_to_le16(vap_id << 8);
+
+ status = adapter->host_intf_write_pkt(common->priv,
+ (u8 *)msg,
+ skb->len);
+ if (status)
+ rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__);
+
+err:
+ rsi_indicate_tx_status(common->priv, skb, status);
+ return status;
+}
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
new file mode 100644
index 000000000000..852453f386e2
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -0,0 +1,850 @@
+/**
+ * Copyright (c) 2014 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/module.h>
+#include "rsi_sdio.h"
+#include "rsi_common.h"
+
+/**
+ * rsi_sdio_set_cmd52_arg() - This function prepares cmd 52 read/write arg.
+ * @rw: Read/write
+ * @func: function number
+ * @raw: indicates whether to perform read after write
+ * @address: address to which to read/write
+ * @writedata: data to write
+ *
+ * Return: argument
+ */
+static u32 rsi_sdio_set_cmd52_arg(bool rw,
+ u8 func,
+ u8 raw,
+ u32 address,
+ u8 writedata)
+{
+ return ((rw & 1) << 31) | ((func & 0x7) << 28) |
+ ((raw & 1) << 27) | (1 << 26) |
+ ((address & 0x1FFFF) << 9) | (1 << 8) |
+ (writedata & 0xFF);
+}
+
+/**
+ * rsi_cmd52writebyte() - This function issues cmd52 byte write onto the card.
+ * @card: Pointer to the mmc_card.
+ * @address: Address to write.
+ * @byte: Data to write.
+ *
+ * Return: Write status.
+ */
+static int rsi_cmd52writebyte(struct mmc_card *card,
+ u32 address,
+ u8 byte)
+{
+ struct mmc_command io_cmd;
+ u32 arg;
+
+ memset(&io_cmd, 0, sizeof(io_cmd));
+ arg = rsi_sdio_set_cmd52_arg(1, 0, 0, address, byte);
+ io_cmd.opcode = SD_IO_RW_DIRECT;
+ io_cmd.arg = arg;
+ io_cmd.flags = MMC_RSP_R5 | MMC_CMD_AC;
+
+ return mmc_wait_for_cmd(card->host, &io_cmd, 0);
+}
+
+/**
+ * rsi_cmd52readbyte() - This function issues cmd52 byte read onto the card.
+ * @card: Pointer to the mmc_card.
+ * @address: Address to read from.
+ * @byte: Variable to store read value.
+ *
+ * Return: Read status.
+ */
+static int rsi_cmd52readbyte(struct mmc_card *card,
+ u32 address,
+ u8 *byte)
+{
+ struct mmc_command io_cmd;
+ u32 arg;
+ int err;
+
+ memset(&io_cmd, 0, sizeof(io_cmd));
+ arg = rsi_sdio_set_cmd52_arg(0, 0, 0, address, 0);
+ io_cmd.opcode = SD_IO_RW_DIRECT;
+ io_cmd.arg = arg;
+ io_cmd.flags = MMC_RSP_R5 | MMC_CMD_AC;
+
+ err = mmc_wait_for_cmd(card->host, &io_cmd, 0);
+ if ((!err) && (byte))
+ *byte = io_cmd.resp[0] & 0xFF;
+ return err;
+}
+
+/**
+ * rsi_issue_sdiocommand() - This function issues sdio commands.
+ * @func: Pointer to the sdio_func structure.
+ * @opcode: Opcode value.
+ * @arg: Arguments to pass.
+ * @flags: Flags which are set.
+ * @resp: Pointer to store response.
+ *
+ * Return: err: command status as 0 or -1.
+ */
+static int rsi_issue_sdiocommand(struct sdio_func *func,
+ u32 opcode,
+ u32 arg,
+ u32 flags,
+ u32 *resp)
+{
+ struct mmc_command cmd;
+ struct mmc_host *host;
+ int err;
+
+ host = func->card->host;
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+ cmd.opcode = opcode;
+ cmd.arg = arg;
+ cmd.flags = flags;
+ err = mmc_wait_for_cmd(host, &cmd, 3);
+
+ if ((!err) && (resp))
+ *resp = cmd.resp[0];
+
+ return err;
+}
+
+/**
+ * rsi_handle_interrupt() - This function is called upon the occurence
+ * of an interrupt.
+ * @function: Pointer to the sdio_func structure.
+ *
+ * Return: None.
+ */
+static void rsi_handle_interrupt(struct sdio_func *function)
+{
+ struct rsi_hw *adapter = sdio_get_drvdata(function);
+
+ sdio_release_host(function);
+ rsi_interrupt_handler(adapter);
+ sdio_claim_host(function);
+}
+
+/**
+ * rsi_reset_card() - This function resets and re-initializes the card.
+ * @pfunction: Pointer to the sdio_func structure.
+ *
+ * Return: None.
+ */
+static void rsi_reset_card(struct sdio_func *pfunction)
+{
+ int ret = 0;
+ int err;
+ struct mmc_card *card = pfunction->card;
+ struct mmc_host *host = card->host;
+ s32 bit = (fls(host->ocr_avail) - 1);
+ u8 cmd52_resp;
+ u32 clock, resp, i;
+ u16 rca;
+
+ /* Reset 9110 chip */
+ ret = rsi_cmd52writebyte(pfunction->card,
+ SDIO_CCCR_ABORT,
+ (1 << 3));
+
+ /* Card will not send any response as it is getting reset immediately
+ * Hence expect a timeout status from host controller
+ */
+ if (ret != -ETIMEDOUT)
+ rsi_dbg(ERR_ZONE, "%s: Reset failed : %d\n", __func__, ret);
+
+ /* Wait for few milli seconds to get rid of residue charges if any */
+ msleep(20);
+
+ /* Initialize the SDIO card */
+ host->ios.vdd = bit;
+ host->ios.chip_select = MMC_CS_DONTCARE;
+ host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+ host->ios.power_mode = MMC_POWER_UP;
+ host->ios.bus_width = MMC_BUS_WIDTH_1;
+ host->ios.timing = MMC_TIMING_LEGACY;
+ host->ops->set_ios(host, &host->ios);
+
+ /*
+ * This delay should be sufficient to allow the power supply
+ * to reach the minimum voltage.
+ */
+ msleep(20);
+
+ host->ios.clock = host->f_min;
+ host->ios.power_mode = MMC_POWER_ON;
+ host->ops->set_ios(host, &host->ios);
+
+ /*
+ * This delay must be at least 74 clock sizes, or 1 ms, or the
+ * time required to reach a stable voltage.
+ */
+ msleep(20);
+
+ /* Issue CMD0. Goto idle state */
+ host->ios.chip_select = MMC_CS_HIGH;
+ host->ops->set_ios(host, &host->ios);
+ msleep(20);
+ err = rsi_issue_sdiocommand(pfunction,
+ MMC_GO_IDLE_STATE,
+ 0,
+ (MMC_RSP_NONE | MMC_CMD_BC),
+ NULL);
+ host->ios.chip_select = MMC_CS_DONTCARE;
+ host->ops->set_ios(host, &host->ios);
+ msleep(20);
+ host->use_spi_crc = 0;
+
+ if (err)
+ rsi_dbg(ERR_ZONE, "%s: CMD0 failed : %d\n", __func__, err);
+
+ if (!host->ocr_avail) {
+ /* Issue CMD5, arg = 0 */
+ err = rsi_issue_sdiocommand(pfunction,
+ SD_IO_SEND_OP_COND,
+ 0,
+ (MMC_RSP_R4 | MMC_CMD_BCR),
+ &resp);
+ if (err)
+ rsi_dbg(ERR_ZONE, "%s: CMD5 failed : %d\n",
+ __func__, err);
+ host->ocr_avail = resp;
+ }
+
+ /* Issue CMD5, arg = ocr. Wait till card is ready */
+ for (i = 0; i < 100; i++) {
+ err = rsi_issue_sdiocommand(pfunction,
+ SD_IO_SEND_OP_COND,
+ host->ocr_avail,
+ (MMC_RSP_R4 | MMC_CMD_BCR),
+ &resp);
+ if (err) {
+ rsi_dbg(ERR_ZONE, "%s: CMD5 failed : %d\n",
+ __func__, err);
+ break;
+ }
+
+ if (resp & MMC_CARD_BUSY)
+ break;
+ msleep(20);
+ }
+
+ if ((i == 100) || (err)) {
+ rsi_dbg(ERR_ZONE, "%s: card in not ready : %d %d\n",
+ __func__, i, err);
+ return;
+ }
+
+ /* Issue CMD3, get RCA */
+ err = rsi_issue_sdiocommand(pfunction,
+ SD_SEND_RELATIVE_ADDR,
+ 0,
+ (MMC_RSP_R6 | MMC_CMD_BCR),
+ &resp);
+ if (err) {
+ rsi_dbg(ERR_ZONE, "%s: CMD3 failed : %d\n", __func__, err);
+ return;
+ }
+ rca = resp >> 16;
+ host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
+ host->ops->set_ios(host, &host->ios);
+
+ /* Issue CMD7, select card */
+ err = rsi_issue_sdiocommand(pfunction,
+ MMC_SELECT_CARD,
+ (rca << 16),
+ (MMC_RSP_R1 | MMC_CMD_AC),
+ NULL);
+ if (err) {
+ rsi_dbg(ERR_ZONE, "%s: CMD7 failed : %d\n", __func__, err);
+ return;
+ }
+
+ /* Enable high speed */
+ if (card->host->caps & MMC_CAP_SD_HIGHSPEED) {
+ rsi_dbg(ERR_ZONE, "%s: Set high speed mode\n", __func__);
+ err = rsi_cmd52readbyte(card, SDIO_CCCR_SPEED, &cmd52_resp);
+ if (err) {
+ rsi_dbg(ERR_ZONE, "%s: CCCR speed reg read failed: %d\n",
+ __func__, err);
+ card->state &= ~MMC_STATE_HIGHSPEED;
+ } else {
+ err = rsi_cmd52writebyte(card,
+ SDIO_CCCR_SPEED,
+ (cmd52_resp | SDIO_SPEED_EHS));
+ if (err) {
+ rsi_dbg(ERR_ZONE,
+ "%s: CCR speed regwrite failed %d\n",
+ __func__, err);
+ return;
+ }
+ mmc_card_set_highspeed(card);
+ host->ios.timing = MMC_TIMING_SD_HS;
+ host->ops->set_ios(host, &host->ios);
+ }
+ }
+
+ /* Set clock */
+ if (mmc_card_highspeed(card))
+ clock = 50000000;
+ else
+ clock = card->cis.max_dtr;
+
+ if (clock > host->f_max)
+ clock = host->f_max;
+
+ host->ios.clock = clock;
+ host->ops->set_ios(host, &host->ios);
+
+ if (card->host->caps & MMC_CAP_4_BIT_DATA) {
+ /* CMD52: Set bus width & disable card detect resistor */
+ err = rsi_cmd52writebyte(card,
+ SDIO_CCCR_IF,
+ (SDIO_BUS_CD_DISABLE |
+ SDIO_BUS_WIDTH_4BIT));
+ if (err) {
+ rsi_dbg(ERR_ZONE, "%s: Set bus mode failed : %d\n",
+ __func__, err);
+ return;
+ }
+ host->ios.bus_width = MMC_BUS_WIDTH_4;
+ host->ops->set_ios(host, &host->ios);
+ }
+}
+
+/**
+ * rsi_setclock() - This function sets the clock frequency.
+ * @adapter: Pointer to the adapter structure.
+ * @freq: Clock frequency.
+ *
+ * Return: None.
+ */
+static void rsi_setclock(struct rsi_hw *adapter, u32 freq)
+{
+ struct rsi_91x_sdiodev *dev =
+ (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ struct mmc_host *host = dev->pfunction->card->host;
+ u32 clock;
+
+ clock = freq * 1000;
+ if (clock > host->f_max)
+ clock = host->f_max;
+ host->ios.clock = clock;
+ host->ops->set_ios(host, &host->ios);
+}
+
+/**
+ * rsi_setblocklength() - This function sets the host block length.
+ * @adapter: Pointer to the adapter structure.
+ * @length: Block length to be set.
+ *
+ * Return: status: 0 on success, -1 on failure.
+ */
+static int rsi_setblocklength(struct rsi_hw *adapter, u32 length)
+{
+ struct rsi_91x_sdiodev *dev =
+ (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ int status;
+ rsi_dbg(INIT_ZONE, "%s: Setting the block length\n", __func__);
+
+ status = sdio_set_block_size(dev->pfunction, length);
+ dev->pfunction->max_blksize = 256;
+
+ rsi_dbg(INFO_ZONE,
+ "%s: Operational blk length is %d\n", __func__, length);
+ return status;
+}
+
+/**
+ * rsi_setupcard() - This function queries and sets the card's features.
+ * @adapter: Pointer to the adapter structure.
+ *
+ * Return: status: 0 on success, -1 on failure.
+ */
+static int rsi_setupcard(struct rsi_hw *adapter)
+{
+ struct rsi_91x_sdiodev *dev =
+ (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ int status = 0;
+
+ rsi_setclock(adapter, 50000);
+
+ dev->tx_blk_size = 256;
+ status = rsi_setblocklength(adapter, dev->tx_blk_size);
+ if (status)
+ rsi_dbg(ERR_ZONE,
+ "%s: Unable to set block length\n", __func__);
+ return status;
+}
+
+/**
+ * rsi_sdio_read_register() - This function reads one byte of information
+ * from a register.
+ * @adapter: Pointer to the adapter structure.
+ * @addr: Address of the register.
+ * @data: Pointer to the data that stores the data read.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+int rsi_sdio_read_register(struct rsi_hw *adapter,
+ u32 addr,
+ u8 *data)
+{
+ struct rsi_91x_sdiodev *dev =
+ (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ u8 fun_num = 0;
+ int status;
+
+ sdio_claim_host(dev->pfunction);
+
+ if (fun_num == 0)
+ *data = sdio_f0_readb(dev->pfunction, addr, &status);
+ else
+ *data = sdio_readb(dev->pfunction, addr, &status);
+
+ sdio_release_host(dev->pfunction);
+
+ return status;
+}
+
+/**
+ * rsi_sdio_write_register() - This function writes one byte of information
+ * into a register.
+ * @adapter: Pointer to the adapter structure.
+ * @function: Function Number.
+ * @addr: Address of the register.
+ * @data: Pointer to the data tha has to be written.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+int rsi_sdio_write_register(struct rsi_hw *adapter,
+ u8 function,
+ u32 addr,
+ u8 *data)
+{
+ struct rsi_91x_sdiodev *dev =
+ (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ int status = 0;
+
+ sdio_claim_host(dev->pfunction);
+
+ if (function == 0)
+ sdio_f0_writeb(dev->pfunction, *data, addr, &status);
+ else
+ sdio_writeb(dev->pfunction, *data, addr, &status);
+
+ sdio_release_host(dev->pfunction);
+
+ return status;
+}
+
+/**
+ * rsi_sdio_ack_intr() - This function acks the interrupt received.
+ * @adapter: Pointer to the adapter structure.
+ * @int_bit: Interrupt bit to write into register.
+ *
+ * Return: None.
+ */
+void rsi_sdio_ack_intr(struct rsi_hw *adapter, u8 int_bit)
+{
+ int status;
+ status = rsi_sdio_write_register(adapter,
+ 1,
+ (SDIO_FUN1_INTR_CLR_REG |
+ RSI_SD_REQUEST_MASTER),
+ &int_bit);
+ if (status)
+ rsi_dbg(ERR_ZONE, "%s: unable to send ack\n", __func__);
+}
+
+
+
+/**
+ * rsi_sdio_read_register_multiple() - This function read multiple bytes of
+ * information from the SD card.
+ * @adapter: Pointer to the adapter structure.
+ * @addr: Address of the register.
+ * @count: Number of multiple bytes to be read.
+ * @data: Pointer to the read data.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int rsi_sdio_read_register_multiple(struct rsi_hw *adapter,
+ u32 addr,
+ u32 count,
+ u8 *data)
+{
+ struct rsi_91x_sdiodev *dev =
+ (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ u32 status;
+
+ sdio_claim_host(dev->pfunction);
+
+ status = sdio_readsb(dev->pfunction, data, addr, count);
+
+ sdio_release_host(dev->pfunction);
+
+ if (status != 0)
+ rsi_dbg(ERR_ZONE, "%s: Synch Cmd53 read failed\n", __func__);
+ return status;
+}
+
+/**
+ * rsi_sdio_write_register_multiple() - This function writes multiple bytes of
+ * information to the SD card.
+ * @adapter: Pointer to the adapter structure.
+ * @addr: Address of the register.
+ * @data: Pointer to the data that has to be written.
+ * @count: Number of multiple bytes to be written.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+int rsi_sdio_write_register_multiple(struct rsi_hw *adapter,
+ u32 addr,
+ u8 *data,
+ u32 count)
+{
+ struct rsi_91x_sdiodev *dev =
+ (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ int status;
+
+ if (dev->write_fail > 1) {
+ rsi_dbg(ERR_ZONE, "%s: Stopping card writes\n", __func__);
+ return 0;
+ } else if (dev->write_fail == 1) {
+ /**
+ * Assuming it is a CRC failure, we want to allow another
+ * card write
+ */
+ rsi_dbg(ERR_ZONE, "%s: Continue card writes\n", __func__);
+ dev->write_fail++;
+ }
+
+ sdio_claim_host(dev->pfunction);
+
+ status = sdio_writesb(dev->pfunction, addr, data, count);
+
+ sdio_release_host(dev->pfunction);
+
+ if (status) {
+ rsi_dbg(ERR_ZONE, "%s: Synch Cmd53 write failed %d\n",
+ __func__, status);
+ dev->write_fail = 2;
+ } else {
+ memcpy(dev->prev_desc, data, FRAME_DESC_SZ);
+ }
+ return status;
+}
+
+/**
+ * rsi_sdio_host_intf_write_pkt() - This function writes the packet to device.
+ * @adapter: Pointer to the adapter structure.
+ * @pkt: Pointer to the data to be written on to the device.
+ * @len: length of the data to be written on to the device.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int rsi_sdio_host_intf_write_pkt(struct rsi_hw *adapter,
+ u8 *pkt,
+ u32 len)
+{
+ struct rsi_91x_sdiodev *dev =
+ (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ u32 block_size = dev->tx_blk_size;
+ u32 num_blocks, address, length;
+ u32 queueno;
+ int status;
+
+ queueno = ((pkt[1] >> 4) & 0xf);
+
+ num_blocks = len / block_size;
+
+ if (len % block_size)
+ num_blocks++;
+
+ address = (num_blocks * block_size | (queueno << 12));
+ length = num_blocks * block_size;
+
+ status = rsi_sdio_write_register_multiple(adapter,
+ address,
+ (u8 *)pkt,
+ length);
+ if (status)
+ rsi_dbg(ERR_ZONE, "%s: Unable to write onto the card: %d\n",
+ __func__, status);
+ rsi_dbg(DATA_TX_ZONE, "%s: Successfully written onto card\n", __func__);
+ return status;
+}
+
+/**
+ * rsi_sdio_host_intf_read_pkt() - This function reads the packet
+ from the device.
+ * @adapter: Pointer to the adapter data structure.
+ * @pkt: Pointer to the packet data to be read from the the device.
+ * @length: Length of the data to be read from the device.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+int rsi_sdio_host_intf_read_pkt(struct rsi_hw *adapter,
+ u8 *pkt,
+ u32 length)
+{
+ int status = -EINVAL;
+
+ if (!length) {
+ rsi_dbg(ERR_ZONE, "%s: Pkt size is zero\n", __func__);
+ return status;
+ }
+
+ status = rsi_sdio_read_register_multiple(adapter,
+ length,
+ length, /*num of bytes*/
+ (u8 *)pkt);
+
+ if (status)
+ rsi_dbg(ERR_ZONE, "%s: Failed to read frame: %d\n", __func__,
+ status);
+ return status;
+}
+
+/**
+ * rsi_init_sdio_interface() - This function does init specific to SDIO.
+ *
+ * @adapter: Pointer to the adapter data structure.
+ * @pkt: Pointer to the packet data to be read from the the device.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+
+static int rsi_init_sdio_interface(struct rsi_hw *adapter,
+ struct sdio_func *pfunction)
+{
+ struct rsi_91x_sdiodev *rsi_91x_dev;
+ int status = -ENOMEM;
+
+ rsi_91x_dev = kzalloc(sizeof(*rsi_91x_dev), GFP_KERNEL);
+ if (!rsi_91x_dev)
+ return status;
+
+ adapter->rsi_dev = rsi_91x_dev;
+
+ sdio_claim_host(pfunction);
+
+ pfunction->enable_timeout = 100;
+ status = sdio_enable_func(pfunction);
+ if (status) {
+ rsi_dbg(ERR_ZONE, "%s: Failed to enable interface\n", __func__);
+ sdio_release_host(pfunction);
+ return status;
+ }
+
+ rsi_dbg(INIT_ZONE, "%s: Enabled the interface\n", __func__);
+
+ rsi_91x_dev->pfunction = pfunction;
+ adapter->device = &pfunction->dev;
+
+ sdio_set_drvdata(pfunction, adapter);
+
+ status = rsi_setupcard(adapter);
+ if (status) {
+ rsi_dbg(ERR_ZONE, "%s: Failed to setup card\n", __func__);
+ goto fail;
+ }
+
+ rsi_dbg(INIT_ZONE, "%s: Setup card succesfully\n", __func__);
+
+ status = rsi_init_sdio_slave_regs(adapter);
+ if (status) {
+ rsi_dbg(ERR_ZONE, "%s: Failed to init slave regs\n", __func__);
+ goto fail;
+ }
+ sdio_release_host(pfunction);
+
+ adapter->host_intf_write_pkt = rsi_sdio_host_intf_write_pkt;
+ adapter->host_intf_read_pkt = rsi_sdio_host_intf_read_pkt;
+ adapter->determine_event_timeout = rsi_sdio_determine_event_timeout;
+ adapter->check_hw_queue_status = rsi_sdio_read_buffer_status_register;
+
+#ifdef CONFIG_RSI_DEBUGFS
+ adapter->num_debugfs_entries = MAX_DEBUGFS_ENTRIES;
+#endif
+ return status;
+fail:
+ sdio_disable_func(pfunction);
+ sdio_release_host(pfunction);
+ return status;
+}
+
+/**
+ * rsi_probe() - This function is called by kernel when the driver provided
+ * Vendor and device IDs are matched. All the initialization
+ * work is done here.
+ * @pfunction: Pointer to the sdio_func structure.
+ * @id: Pointer to sdio_device_id structure.
+ *
+ * Return: 0 on success, 1 on failure.
+ */
+static int rsi_probe(struct sdio_func *pfunction,
+ const struct sdio_device_id *id)
+{
+ struct rsi_hw *adapter;
+
+ rsi_dbg(INIT_ZONE, "%s: Init function called\n", __func__);
+
+ adapter = rsi_91x_init();
+ if (!adapter) {
+ rsi_dbg(ERR_ZONE, "%s: Failed to init os intf ops\n",
+ __func__);
+ return 1;
+ }
+
+ if (rsi_init_sdio_interface(adapter, pfunction)) {
+ rsi_dbg(ERR_ZONE, "%s: Failed to init sdio interface\n",
+ __func__);
+ goto fail;
+ }
+
+ if (rsi_sdio_device_init(adapter->priv)) {
+ rsi_dbg(ERR_ZONE, "%s: Failed in device init\n", __func__);
+ sdio_claim_host(pfunction);
+ sdio_disable_func(pfunction);
+ sdio_release_host(pfunction);
+ goto fail;
+ }
+
+ sdio_claim_host(pfunction);
+ if (sdio_claim_irq(pfunction, rsi_handle_interrupt)) {
+ rsi_dbg(ERR_ZONE, "%s: Failed to request IRQ\n", __func__);
+ sdio_release_host(pfunction);
+ goto fail;
+ }
+
+ sdio_release_host(pfunction);
+ rsi_dbg(INIT_ZONE, "%s: Registered Interrupt handler\n", __func__);
+
+ return 0;
+fail:
+ rsi_91x_deinit(adapter);
+ rsi_dbg(ERR_ZONE, "%s: Failed in probe...Exiting\n", __func__);
+ return 1;
+}
+
+/**
+ * rsi_disconnect() - This function performs the reverse of the probe function.
+ * @pfunction: Pointer to the sdio_func structure.
+ *
+ * Return: void.
+ */
+static void rsi_disconnect(struct sdio_func *pfunction)
+{
+ struct rsi_hw *adapter = sdio_get_drvdata(pfunction);
+ struct rsi_91x_sdiodev *dev =
+ (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+
+ if (!adapter)
+ return;
+
+ dev->write_fail = 2;
+ rsi_mac80211_detach(adapter);
+
+ sdio_claim_host(pfunction);
+ sdio_release_irq(pfunction);
+ sdio_disable_func(pfunction);
+ rsi_91x_deinit(adapter);
+ /* Resetting to take care of the case, where-in driver is re-loaded */
+ rsi_reset_card(pfunction);
+ sdio_release_host(pfunction);
+}
+
+#ifdef CONFIG_PM
+static int rsi_suspend(struct device *dev)
+{
+ /* Not yet implemented */
+ return -ENOSYS;
+}
+
+static int rsi_resume(struct device *dev)
+{
+ /* Not yet implemented */
+ return -ENOSYS;
+}
+
+static const struct dev_pm_ops rsi_pm_ops = {
+ .suspend = rsi_suspend,
+ .resume = rsi_resume,
+};
+#endif
+
+static const struct sdio_device_id rsi_dev_table[] = {
+ { SDIO_DEVICE(0x303, 0x100) },
+ { SDIO_DEVICE(0x041B, 0x0301) },
+ { SDIO_DEVICE(0x041B, 0x0201) },
+ { SDIO_DEVICE(0x041B, 0x9330) },
+ { /* Blank */},
+};
+
+static struct sdio_driver rsi_driver = {
+ .name = "RSI-SDIO WLAN",
+ .probe = rsi_probe,
+ .remove = rsi_disconnect,
+ .id_table = rsi_dev_table,
+#ifdef CONFIG_PM
+ .drv = {
+ .pm = &rsi_pm_ops,
+ }
+#endif
+};
+
+/**
+ * rsi_module_init() - This function registers the sdio module.
+ * @void: Void.
+ *
+ * Return: 0 on success.
+ */
+static int rsi_module_init(void)
+{
+ sdio_register_driver(&rsi_driver);
+ rsi_dbg(INIT_ZONE, "%s: Registering driver\n", __func__);
+ return 0;
+}
+
+/**
+ * rsi_module_exit() - This function unregisters the sdio module.
+ * @void: Void.
+ *
+ * Return: None.
+ */
+static void rsi_module_exit(void)
+{
+ sdio_unregister_driver(&rsi_driver);
+ rsi_dbg(INFO_ZONE, "%s: Unregistering driver\n", __func__);
+}
+
+module_init(rsi_module_init);
+module_exit(rsi_module_exit);
+
+MODULE_AUTHOR("Redpine Signals Inc");
+MODULE_DESCRIPTION("Common SDIO layer for RSI drivers");
+MODULE_SUPPORTED_DEVICE("RSI-91x");
+MODULE_DEVICE_TABLE(sdio, rsi_dev_table);
+MODULE_FIRMWARE(FIRMWARE_RSI9113);
+MODULE_VERSION("0.1");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
new file mode 100644
index 000000000000..f1cb99cafed8
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
@@ -0,0 +1,566 @@
+/**
+ * Copyright (c) 2014 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/firmware.h>
+#include "rsi_sdio.h"
+#include "rsi_common.h"
+
+/**
+ * rsi_sdio_master_access_msword() - This function sets the AHB master access
+ * MS word in the SDIO slave registers.
+ * @adapter: Pointer to the adapter structure.
+ * @ms_word: ms word need to be initialized.
+ *
+ * Return: status: 0 on success, -1 on failure.
+ */
+static int rsi_sdio_master_access_msword(struct rsi_hw *adapter,
+ u16 ms_word)
+{
+ u8 byte;
+ u8 function = 0;
+ int status = 0;
+
+ byte = (u8)(ms_word & 0x00FF);
+
+ rsi_dbg(INIT_ZONE,
+ "%s: MASTER_ACCESS_MSBYTE:0x%x\n", __func__, byte);
+
+ status = rsi_sdio_write_register(adapter,
+ function,
+ SDIO_MASTER_ACCESS_MSBYTE,
+ &byte);
+ if (status) {
+ rsi_dbg(ERR_ZONE,
+ "%s: fail to access MASTER_ACCESS_MSBYTE\n",
+ __func__);
+ return -1;
+ }
+
+ byte = (u8)(ms_word >> 8);
+
+ rsi_dbg(INIT_ZONE, "%s:MASTER_ACCESS_LSBYTE:0x%x\n", __func__, byte);
+ status = rsi_sdio_write_register(adapter,
+ function,
+ SDIO_MASTER_ACCESS_LSBYTE,
+ &byte);
+ return status;
+}
+
+/**
+ * rsi_copy_to_card() - This function includes the actual funtionality of
+ * copying the TA firmware to the card.Basically this
+ * function includes opening the TA file,reading the
+ * TA file and writing their values in blocks of data.
+ * @common: Pointer to the driver private structure.
+ * @fw: Pointer to the firmware value to be written.
+ * @len: length of firmware file.
+ * @num_blocks: Number of blocks to be written to the card.
+ *
+ * Return: 0 on success and -1 on failure.
+ */
+static int rsi_copy_to_card(struct rsi_common *common,
+ const u8 *fw,
+ u32 len,
+ u32 num_blocks)
+{
+ struct rsi_hw *adapter = common->priv;
+ struct rsi_91x_sdiodev *dev =
+ (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ u32 indx, ii;
+ u32 block_size = dev->tx_blk_size;
+ u32 lsb_address;
+ __le32 data[] = { TA_HOLD_THREAD_VALUE, TA_SOFT_RST_CLR,
+ TA_PC_ZERO, TA_RELEASE_THREAD_VALUE };
+ u32 address[] = { TA_HOLD_THREAD_REG, TA_SOFT_RESET_REG,
+ TA_TH0_PC_REG, TA_RELEASE_THREAD_REG };
+ u32 base_address;
+ u16 msb_address;
+
+ base_address = TA_LOAD_ADDRESS;
+ msb_address = base_address >> 16;
+
+ for (indx = 0, ii = 0; ii < num_blocks; ii++, indx += block_size) {
+ lsb_address = ((u16) base_address | RSI_SD_REQUEST_MASTER);
+ if (rsi_sdio_write_register_multiple(adapter,
+ lsb_address,
+ (u8 *)(fw + indx),
+ block_size)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Unable to load %s blk\n", __func__,
+ FIRMWARE_RSI9113);
+ return -1;
+ }
+ rsi_dbg(INIT_ZONE, "%s: loading block: %d\n", __func__, ii);
+ base_address += block_size;
+ if ((base_address >> 16) != msb_address) {
+ msb_address += 1;
+ if (rsi_sdio_master_access_msword(adapter,
+ msb_address)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Unable to set ms word reg\n",
+ __func__);
+ return -1;
+ }
+ }
+ }
+
+ if (len % block_size) {
+ lsb_address = ((u16) base_address | RSI_SD_REQUEST_MASTER);
+ if (rsi_sdio_write_register_multiple(adapter,
+ lsb_address,
+ (u8 *)(fw + indx),
+ len % block_size)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Unable to load f/w\n", __func__);
+ return -1;
+ }
+ }
+ rsi_dbg(INIT_ZONE,
+ "%s: Succesfully loaded TA instructions\n", __func__);
+
+ if (rsi_sdio_master_access_msword(adapter, TA_BASE_ADDR)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Unable to set ms word to common reg\n",
+ __func__);
+ return -1;
+ }
+
+ for (ii = 0; ii < ARRAY_SIZE(data); ii++) {
+ /* Bringing TA out of reset */
+ if (rsi_sdio_write_register_multiple(adapter,
+ (address[ii] |
+ RSI_SD_REQUEST_MASTER),
+ (u8 *)&data[ii],
+ 4)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Unable to hold TA threads\n", __func__);
+ return -1;
+ }
+ }
+
+ rsi_dbg(INIT_ZONE, "%s: loaded firmware\n", __func__);
+ return 0;
+}
+
+/**
+ * rsi_load_ta_instructions() - This function includes the actual funtionality
+ * of loading the TA firmware.This function also
+ * includes opening the TA file,reading the TA
+ * file and writing their value in blocks of data.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: status: 0 on success, -1 on failure.
+ */
+static int rsi_load_ta_instructions(struct rsi_common *common)
+{
+ struct rsi_hw *adapter = common->priv;
+ struct rsi_91x_sdiodev *dev =
+ (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ u32 len;
+ u32 num_blocks;
+ const u8 *fw;
+ const struct firmware *fw_entry = NULL;
+ u32 block_size = dev->tx_blk_size;
+ int status = 0;
+ u32 base_address;
+ u16 msb_address;
+
+ if (rsi_sdio_master_access_msword(adapter, TA_BASE_ADDR)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Unable to set ms word to common reg\n",
+ __func__);
+ return -1;
+ }
+ base_address = TA_LOAD_ADDRESS;
+ msb_address = (base_address >> 16);
+
+ if (rsi_sdio_master_access_msword(adapter, msb_address)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Unable to set ms word reg\n", __func__);
+ return -1;
+ }
+
+ status = request_firmware(&fw_entry, FIRMWARE_RSI9113, adapter->device);
+ if (status < 0) {
+ rsi_dbg(ERR_ZONE, "%s Firmware file %s not found\n",
+ __func__, FIRMWARE_RSI9113);
+ return status;
+ }
+
+ fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
+ len = fw_entry->size;
+
+ if (len % 4)
+ len += (4 - (len % 4));
+
+ num_blocks = (len / block_size);
+
+ rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len);
+ rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks);
+
+ status = rsi_copy_to_card(common, fw, len, num_blocks);
+ release_firmware(fw_entry);
+ return status;
+}
+
+/**
+ * rsi_process_pkt() - This Function reads rx_blocks register and figures out
+ * the size of the rx pkt.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int rsi_process_pkt(struct rsi_common *common)
+{
+ struct rsi_hw *adapter = common->priv;
+ u8 num_blks = 0;
+ u32 rcv_pkt_len = 0;
+ int status = 0;
+
+ status = rsi_sdio_read_register(adapter,
+ SDIO_RX_NUM_BLOCKS_REG,
+ &num_blks);
+
+ if (status) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to read pkt length from the card:\n",
+ __func__);
+ return status;
+ }
+ rcv_pkt_len = (num_blks * 256);
+
+ common->rx_data_pkt = kmalloc(rcv_pkt_len, GFP_KERNEL);
+ if (!common->rx_data_pkt) {
+ rsi_dbg(ERR_ZONE, "%s: Failed in memory allocation\n",
+ __func__);
+ return -1;
+ }
+
+ status = rsi_sdio_host_intf_read_pkt(adapter,
+ common->rx_data_pkt,
+ rcv_pkt_len);
+ if (status) {
+ rsi_dbg(ERR_ZONE, "%s: Failed to read packet from card\n",
+ __func__);
+ goto fail;
+ }
+
+ status = rsi_read_pkt(common, rcv_pkt_len);
+ kfree(common->rx_data_pkt);
+ return status;
+
+fail:
+ kfree(common->rx_data_pkt);
+ return -1;
+}
+
+/**
+ * rsi_init_sdio_slave_regs() - This function does the actual initialization
+ * of SDBUS slave registers.
+ * @adapter: Pointer to the adapter structure.
+ *
+ * Return: status: 0 on success, -1 on failure.
+ */
+int rsi_init_sdio_slave_regs(struct rsi_hw *adapter)
+{
+ struct rsi_91x_sdiodev *dev =
+ (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ u8 function = 0;
+ u8 byte;
+ int status = 0;
+
+ if (dev->next_read_delay) {
+ byte = dev->next_read_delay;
+ status = rsi_sdio_write_register(adapter,
+ function,
+ SDIO_NXT_RD_DELAY2,
+ &byte);
+ if (status) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to write SDIO_NXT_RD_DELAY2\n",
+ __func__);
+ return -1;
+ }
+ }
+
+ if (dev->sdio_high_speed_enable) {
+ rsi_dbg(INIT_ZONE, "%s: Enabling SDIO High speed\n", __func__);
+ byte = 0x3;
+
+ status = rsi_sdio_write_register(adapter,
+ function,
+ SDIO_REG_HIGH_SPEED,
+ &byte);
+ if (status) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to enable SDIO high speed\n",
+ __func__);
+ return -1;
+ }
+ }
+
+ /* This tells SDIO FIFO when to start read to host */
+ rsi_dbg(INIT_ZONE, "%s: Initialzing SDIO read start level\n", __func__);
+ byte = 0x24;
+
+ status = rsi_sdio_write_register(adapter,
+ function,
+ SDIO_READ_START_LVL,
+ &byte);
+ if (status) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to write SDIO_READ_START_LVL\n", __func__);
+ return -1;
+ }
+
+ rsi_dbg(INIT_ZONE, "%s: Initialzing FIFO ctrl registers\n", __func__);
+ byte = (128 - 32);
+
+ status = rsi_sdio_write_register(adapter,
+ function,
+ SDIO_READ_FIFO_CTL,
+ &byte);
+ if (status) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to write SDIO_READ_FIFO_CTL\n", __func__);
+ return -1;
+ }
+
+ byte = 32;
+ status = rsi_sdio_write_register(adapter,
+ function,
+ SDIO_WRITE_FIFO_CTL,
+ &byte);
+ if (status) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to write SDIO_WRITE_FIFO_CTL\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * rsi_interrupt_handler() - This function read and process SDIO interrupts.
+ * @adapter: Pointer to the adapter structure.
+ *
+ * Return: None.
+ */
+void rsi_interrupt_handler(struct rsi_hw *adapter)
+{
+ struct rsi_common *common = adapter->priv;
+ struct rsi_91x_sdiodev *dev =
+ (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ int status;
+ enum sdio_interrupt_type isr_type;
+ u8 isr_status = 0;
+ u8 fw_status = 0;
+
+ dev->rx_info.sdio_int_counter++;
+
+ do {
+ mutex_lock(&common->tx_rxlock);
+ status = rsi_sdio_read_register(common->priv,
+ RSI_FN1_INT_REGISTER,
+ &isr_status);
+ if (status) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to Read Intr Status Register\n",
+ __func__);
+ mutex_unlock(&common->tx_rxlock);
+ return;
+ }
+
+ if (isr_status == 0) {
+ rsi_set_event(&common->tx_thread.event);
+ dev->rx_info.sdio_intr_status_zero++;
+ mutex_unlock(&common->tx_rxlock);
+ return;
+ }
+
+ rsi_dbg(ISR_ZONE, "%s: Intr_status = %x %d %d\n",
+ __func__, isr_status, (1 << MSDU_PKT_PENDING),
+ (1 << FW_ASSERT_IND));
+
+ do {
+ RSI_GET_SDIO_INTERRUPT_TYPE(isr_status, isr_type);
+
+ switch (isr_type) {
+ case BUFFER_AVAILABLE:
+ dev->rx_info.watch_bufferfull_count = 0;
+ dev->rx_info.buffer_full = false;
+ dev->rx_info.mgmt_buffer_full = false;
+ rsi_sdio_ack_intr(common->priv,
+ (1 << PKT_BUFF_AVAILABLE));
+ rsi_set_event((&common->tx_thread.event));
+ rsi_dbg(ISR_ZONE,
+ "%s: ==> BUFFER_AVILABLE <==\n",
+ __func__);
+ dev->rx_info.buf_avilable_counter++;
+ break;
+
+ case FIRMWARE_ASSERT_IND:
+ rsi_dbg(ERR_ZONE,
+ "%s: ==> FIRMWARE Assert <==\n",
+ __func__);
+ status = rsi_sdio_read_register(common->priv,
+ SDIO_FW_STATUS_REG,
+ &fw_status);
+ if (status) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to read f/w reg\n",
+ __func__);
+ } else {
+ rsi_dbg(ERR_ZONE,
+ "%s: Firmware Status is 0x%x\n",
+ __func__ , fw_status);
+ rsi_sdio_ack_intr(common->priv,
+ (1 << FW_ASSERT_IND));
+ }
+
+ common->fsm_state = FSM_CARD_NOT_READY;
+ break;
+
+ case MSDU_PACKET_PENDING:
+ rsi_dbg(ISR_ZONE, "Pkt pending interrupt\n");
+ dev->rx_info.total_sdio_msdu_pending_intr++;
+
+ status = rsi_process_pkt(common);
+ if (status) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to read pkt\n",
+ __func__);
+ mutex_unlock(&common->tx_rxlock);
+ return;
+ }
+ break;
+ default:
+ rsi_sdio_ack_intr(common->priv, isr_status);
+ dev->rx_info.total_sdio_unknown_intr++;
+ isr_status = 0;
+ rsi_dbg(ISR_ZONE,
+ "Unknown Interrupt %x\n",
+ isr_status);
+ break;
+ }
+ isr_status ^= BIT(isr_type - 1);
+ } while (isr_status);
+ mutex_unlock(&common->tx_rxlock);
+ } while (1);
+}
+
+/**
+ * rsi_device_init() - This Function Initializes The HAL.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+int rsi_sdio_device_init(struct rsi_common *common)
+{
+ if (rsi_load_ta_instructions(common))
+ return -1;
+
+ if (rsi_sdio_master_access_msword(common->priv, MISC_CFG_BASE_ADDR)) {
+ rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n",
+ __func__);
+ return -1;
+ }
+ rsi_dbg(INIT_ZONE,
+ "%s: Setting ms word to 0x41050000\n", __func__);
+
+ return 0;
+}
+
+/**
+ * rsi_sdio_read_buffer_status_register() - This function is used to the read
+ * buffer status register and set
+ * relevant fields in
+ * rsi_91x_sdiodev struct.
+ * @adapter: Pointer to the driver hw structure.
+ * @q_num: The Q number whose status is to be found.
+ *
+ * Return: status: -1 on failure or else queue full/stop is indicated.
+ */
+int rsi_sdio_read_buffer_status_register(struct rsi_hw *adapter, u8 q_num)
+{
+ struct rsi_common *common = adapter->priv;
+ struct rsi_91x_sdiodev *dev =
+ (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ u8 buf_status = 0;
+ int status = 0;
+
+ status = rsi_sdio_read_register(common->priv,
+ RSI_DEVICE_BUFFER_STATUS_REGISTER,
+ &buf_status);
+
+ if (status) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to read status register\n", __func__);
+ return -1;
+ }
+
+ if (buf_status & (BIT(PKT_MGMT_BUFF_FULL))) {
+ if (!dev->rx_info.mgmt_buffer_full)
+ dev->rx_info.mgmt_buf_full_counter++;
+ dev->rx_info.mgmt_buffer_full = true;
+ } else {
+ dev->rx_info.mgmt_buffer_full = false;
+ }
+
+ if (buf_status & (BIT(PKT_BUFF_FULL))) {
+ if (!dev->rx_info.buffer_full)
+ dev->rx_info.buf_full_counter++;
+ dev->rx_info.buffer_full = true;
+ } else {
+ dev->rx_info.buffer_full = false;
+ }
+
+ if (buf_status & (BIT(PKT_BUFF_SEMI_FULL))) {
+ if (!dev->rx_info.semi_buffer_full)
+ dev->rx_info.buf_semi_full_counter++;
+ dev->rx_info.semi_buffer_full = true;
+ } else {
+ dev->rx_info.semi_buffer_full = false;
+ }
+
+ if ((q_num == MGMT_SOFT_Q) && (dev->rx_info.mgmt_buffer_full))
+ return QUEUE_FULL;
+
+ if (dev->rx_info.buffer_full)
+ return QUEUE_FULL;
+
+ return QUEUE_NOT_FULL;
+}
+
+/**
+ * rsi_sdio_determine_event_timeout() - This Function determines the event
+ * timeout duration.
+ * @adapter: Pointer to the adapter structure.
+ *
+ * Return: timeout duration is returned.
+ */
+int rsi_sdio_determine_event_timeout(struct rsi_hw *adapter)
+{
+ struct rsi_91x_sdiodev *dev =
+ (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+
+ /* Once buffer full is seen, event timeout to occur every 2 msecs */
+ if (dev->rx_info.buffer_full)
+ return 2;
+
+ return EVENT_WAIT_FOREVER;
+}
diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c
new file mode 100644
index 000000000000..bb1bf96670eb
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_91x_usb.c
@@ -0,0 +1,575 @@
+/**
+ * Copyright (c) 2014 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/module.h>
+#include "rsi_usb.h"
+
+/**
+ * rsi_usb_card_write() - This function writes to the USB Card.
+ * @adapter: Pointer to the adapter structure.
+ * @buf: Pointer to the buffer from where the data has to be taken.
+ * @len: Length to be written.
+ * @endpoint: Type of endpoint.
+ *
+ * Return: status: 0 on success, -1 on failure.
+ */
+static int rsi_usb_card_write(struct rsi_hw *adapter,
+ void *buf,
+ u16 len,
+ u8 endpoint)
+{
+ struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ int status;
+ s32 transfer;
+
+ status = usb_bulk_msg(dev->usbdev,
+ usb_sndbulkpipe(dev->usbdev,
+ dev->bulkout_endpoint_addr[endpoint - 1]),
+ buf,
+ len,
+ &transfer,
+ HZ * 5);
+
+ if (status < 0) {
+ rsi_dbg(ERR_ZONE,
+ "Card write failed with error code :%10d\n", status);
+ dev->write_fail = 1;
+ }
+ return status;
+}
+
+/**
+ * rsi_write_multiple() - This function writes multiple bytes of information
+ * to the USB card.
+ * @adapter: Pointer to the adapter structure.
+ * @addr: Address of the register.
+ * @data: Pointer to the data that has to be written.
+ * @count: Number of multiple bytes to be written.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int rsi_write_multiple(struct rsi_hw *adapter,
+ u8 endpoint,
+ u8 *data,
+ u32 count)
+{
+ struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ u8 *seg = dev->tx_buffer;
+
+ if (dev->write_fail)
+ return 0;
+
+ if (endpoint == MGMT_EP) {
+ memset(seg, 0, RSI_USB_TX_HEAD_ROOM);
+ memcpy(seg + RSI_USB_TX_HEAD_ROOM, data, count);
+ } else {
+ seg = ((u8 *)data - RSI_USB_TX_HEAD_ROOM);
+ }
+
+ return rsi_usb_card_write(adapter,
+ seg,
+ count + RSI_USB_TX_HEAD_ROOM,
+ endpoint);
+}
+
+/**
+ * rsi_find_bulk_in_and_out_endpoints() - This function initializes the bulk
+ * endpoints to the device.
+ * @interface: Pointer to the USB interface structure.
+ * @adapter: Pointer to the adapter structure.
+ *
+ * Return: ret_val: 0 on success, -ENOMEM on failure.
+ */
+static int rsi_find_bulk_in_and_out_endpoints(struct usb_interface *interface,
+ struct rsi_hw *adapter)
+{
+ struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ __le16 buffer_size;
+ int ii, bep_found = 0;
+
+ iface_desc = &(interface->altsetting[0]);
+
+ for (ii = 0; ii < iface_desc->desc.bNumEndpoints; ++ii) {
+ endpoint = &(iface_desc->endpoint[ii].desc);
+
+ if ((!(dev->bulkin_endpoint_addr)) &&
+ (endpoint->bEndpointAddress & USB_DIR_IN) &&
+ ((endpoint->bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_BULK)) {
+ buffer_size = endpoint->wMaxPacketSize;
+ dev->bulkin_size = buffer_size;
+ dev->bulkin_endpoint_addr =
+ endpoint->bEndpointAddress;
+ }
+
+ if (!dev->bulkout_endpoint_addr[bep_found] &&
+ !(endpoint->bEndpointAddress & USB_DIR_IN) &&
+ ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_BULK)) {
+ dev->bulkout_endpoint_addr[bep_found] =
+ endpoint->bEndpointAddress;
+ buffer_size = endpoint->wMaxPacketSize;
+ dev->bulkout_size[bep_found] = buffer_size;
+ bep_found++;
+ }
+
+ if (bep_found >= MAX_BULK_EP)
+ break;
+ }
+
+ if (!(dev->bulkin_endpoint_addr) &&
+ (dev->bulkout_endpoint_addr[0]))
+ return -EINVAL;
+
+ return 0;
+}
+
+/* rsi_usb_reg_read() - This function reads data from given register address.
+ * @usbdev: Pointer to the usb_device structure.
+ * @reg: Address of the register to be read.
+ * @value: Value to be read.
+ * @len: length of data to be read.
+ *
+ * Return: status: 0 on success, -1 on failure.
+ */
+static int rsi_usb_reg_read(struct usb_device *usbdev,
+ u32 reg,
+ u16 *value,
+ u16 len)
+{
+ u8 temp_buf[4];
+ int status = 0;
+
+ status = usb_control_msg(usbdev,
+ usb_rcvctrlpipe(usbdev, 0),
+ USB_VENDOR_REGISTER_READ,
+ USB_TYPE_VENDOR,
+ ((reg & 0xffff0000) >> 16), (reg & 0xffff),
+ (void *)temp_buf,
+ len,
+ HZ * 5);
+
+ *value = (temp_buf[0] | (temp_buf[1] << 8));
+ if (status < 0) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Reg read failed with error code :%d\n",
+ __func__, status);
+ }
+ return status;
+}
+
+/**
+ * rsi_usb_reg_write() - This function writes the given data into the given
+ * register address.
+ * @usbdev: Pointer to the usb_device structure.
+ * @reg: Address of the register.
+ * @value: Value to write.
+ * @len: Length of data to be written.
+ *
+ * Return: status: 0 on success, -1 on failure.
+ */
+static int rsi_usb_reg_write(struct usb_device *usbdev,
+ u32 reg,
+ u16 value,
+ u16 len)
+{
+ u8 usb_reg_buf[4];
+ int status = 0;
+
+ usb_reg_buf[0] = (value & 0x00ff);
+ usb_reg_buf[1] = (value & 0xff00) >> 8;
+ usb_reg_buf[2] = 0x0;
+ usb_reg_buf[3] = 0x0;
+
+ status = usb_control_msg(usbdev,
+ usb_sndctrlpipe(usbdev, 0),
+ USB_VENDOR_REGISTER_WRITE,
+ USB_TYPE_VENDOR,
+ ((reg & 0xffff0000) >> 16),
+ (reg & 0xffff),
+ (void *)usb_reg_buf,
+ len,
+ HZ * 5);
+ if (status < 0) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Reg write failed with error code :%d\n",
+ __func__, status);
+ }
+ return status;
+}
+
+/**
+ * rsi_rx_done_handler() - This function is called when a packet is received
+ * from USB stack. This is callback to recieve done.
+ * @urb: Received URB.
+ *
+ * Return: None.
+ */
+static void rsi_rx_done_handler(struct urb *urb)
+{
+ struct rsi_hw *adapter = urb->context;
+ struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+
+ if (urb->status)
+ return;
+
+ rsi_set_event(&dev->rx_thread.event);
+}
+
+/**
+ * rsi_rx_urb_submit() - This function submits the given URB to the USB stack.
+ * @adapter: Pointer to the adapter structure.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int rsi_rx_urb_submit(struct rsi_hw *adapter)
+{
+ struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ struct urb *urb = dev->rx_usb_urb[0];
+ int status;
+
+ usb_fill_bulk_urb(urb,
+ dev->usbdev,
+ usb_rcvbulkpipe(dev->usbdev,
+ dev->bulkin_endpoint_addr),
+ urb->transfer_buffer,
+ 3000,
+ rsi_rx_done_handler,
+ adapter);
+
+ status = usb_submit_urb(urb, GFP_KERNEL);
+ if (status)
+ rsi_dbg(ERR_ZONE, "%s: Failed in urb submission\n", __func__);
+
+ return status;
+}
+
+/**
+ * rsi_usb_write_register_multiple() - This function writes multiple bytes of
+ * information to multiple registers.
+ * @adapter: Pointer to the adapter structure.
+ * @addr: Address of the register.
+ * @data: Pointer to the data that has to be written.
+ * @count: Number of multiple bytes to be written on to the registers.
+ *
+ * Return: status: 0 on success, -1 on failure.
+ */
+int rsi_usb_write_register_multiple(struct rsi_hw *adapter,
+ u32 addr,
+ u8 *data,
+ u32 count)
+{
+ struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ u8 *buf;
+ u8 transfer;
+ int status = 0;
+
+ buf = kzalloc(4096, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ while (count) {
+ transfer = min_t(int, count, 4096);
+ memcpy(buf, data, transfer);
+ status = usb_control_msg(dev->usbdev,
+ usb_sndctrlpipe(dev->usbdev, 0),
+ USB_VENDOR_REGISTER_WRITE,
+ USB_TYPE_VENDOR,
+ ((addr & 0xffff0000) >> 16),
+ (addr & 0xffff),
+ (void *)buf,
+ transfer,
+ HZ * 5);
+ if (status < 0) {
+ rsi_dbg(ERR_ZONE,
+ "Reg write failed with error code :%d\n",
+ status);
+ } else {
+ count -= transfer;
+ data += transfer;
+ addr += transfer;
+ }
+ }
+
+ kfree(buf);
+ return 0;
+}
+
+/**
+ *rsi_usb_host_intf_write_pkt() - This function writes the packet to the
+ * USB card.
+ * @adapter: Pointer to the adapter structure.
+ * @pkt: Pointer to the data to be written on to the card.
+ * @len: Length of the data to be written on to the card.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int rsi_usb_host_intf_write_pkt(struct rsi_hw *adapter,
+ u8 *pkt,
+ u32 len)
+{
+ u32 queueno = ((pkt[1] >> 4) & 0xf);
+ u8 endpoint;
+
+ endpoint = ((queueno == RSI_WIFI_MGMT_Q) ? MGMT_EP : DATA_EP);
+
+ return rsi_write_multiple(adapter,
+ endpoint,
+ (u8 *)pkt,
+ len);
+}
+
+/**
+ * rsi_deinit_usb_interface() - This function deinitializes the usb interface.
+ * @adapter: Pointer to the adapter structure.
+ *
+ * Return: None.
+ */
+static void rsi_deinit_usb_interface(struct rsi_hw *adapter)
+{
+ struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+
+ rsi_kill_thread(&dev->rx_thread);
+ kfree(adapter->priv->rx_data_pkt);
+ kfree(dev->tx_buffer);
+}
+
+/**
+ * rsi_init_usb_interface() - This function initializes the usb interface.
+ * @adapter: Pointer to the adapter structure.
+ * @pfunction: Pointer to USB interface structure.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int rsi_init_usb_interface(struct rsi_hw *adapter,
+ struct usb_interface *pfunction)
+{
+ struct rsi_91x_usbdev *rsi_dev;
+ struct rsi_common *common = adapter->priv;
+ int status;
+
+ rsi_dev = kzalloc(sizeof(*rsi_dev), GFP_KERNEL);
+ if (!rsi_dev)
+ return -ENOMEM;
+
+ adapter->rsi_dev = rsi_dev;
+ rsi_dev->usbdev = interface_to_usbdev(pfunction);
+
+ if (rsi_find_bulk_in_and_out_endpoints(pfunction, adapter))
+ return -EINVAL;
+
+ adapter->device = &pfunction->dev;
+ usb_set_intfdata(pfunction, adapter);
+
+ common->rx_data_pkt = kmalloc(2048, GFP_KERNEL);
+ if (!common->rx_data_pkt) {
+ rsi_dbg(ERR_ZONE, "%s: Failed to allocate memory\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ rsi_dev->tx_buffer = kmalloc(2048, GFP_ATOMIC);
+ rsi_dev->rx_usb_urb[0] = usb_alloc_urb(0, GFP_KERNEL);
+ rsi_dev->rx_usb_urb[0]->transfer_buffer = adapter->priv->rx_data_pkt;
+ rsi_dev->tx_blk_size = 252;
+
+ /* Initializing function callbacks */
+ adapter->rx_urb_submit = rsi_rx_urb_submit;
+ adapter->host_intf_write_pkt = rsi_usb_host_intf_write_pkt;
+ adapter->check_hw_queue_status = rsi_usb_check_queue_status;
+ adapter->determine_event_timeout = rsi_usb_event_timeout;
+
+ rsi_init_event(&rsi_dev->rx_thread.event);
+ status = rsi_create_kthread(common, &rsi_dev->rx_thread,
+ rsi_usb_rx_thread, "RX-Thread");
+ if (status) {
+ rsi_dbg(ERR_ZONE, "%s: Unable to init rx thrd\n", __func__);
+ goto fail;
+ }
+
+#ifdef CONFIG_RSI_DEBUGFS
+ /* In USB, one less than the MAX_DEBUGFS_ENTRIES entries is required */
+ adapter->num_debugfs_entries = (MAX_DEBUGFS_ENTRIES - 1);
+#endif
+
+ rsi_dbg(INIT_ZONE, "%s: Enabled the interface\n", __func__);
+ return 0;
+
+fail:
+ kfree(rsi_dev->tx_buffer);
+ kfree(common->rx_data_pkt);
+ return status;
+}
+
+/**
+ * rsi_probe() - This function is called by kernel when the driver provided
+ * Vendor and device IDs are matched. All the initialization
+ * work is done here.
+ * @pfunction: Pointer to the USB interface structure.
+ * @id: Pointer to the usb_device_id structure.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int rsi_probe(struct usb_interface *pfunction,
+ const struct usb_device_id *id)
+{
+ struct rsi_hw *adapter;
+ struct rsi_91x_usbdev *dev;
+ u16 fw_status;
+
+ rsi_dbg(INIT_ZONE, "%s: Init function called\n", __func__);
+
+ adapter = rsi_91x_init();
+ if (!adapter) {
+ rsi_dbg(ERR_ZONE, "%s: Failed to init os intf ops\n",
+ __func__);
+ return 1;
+ }
+
+ if (rsi_init_usb_interface(adapter, pfunction)) {
+ rsi_dbg(ERR_ZONE, "%s: Failed to init usb interface\n",
+ __func__);
+ goto err;
+ }
+
+ rsi_dbg(ERR_ZONE, "%s: Initialized os intf ops\n", __func__);
+
+ dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+
+ if (rsi_usb_reg_read(dev->usbdev, FW_STATUS_REG, &fw_status, 2) < 0)
+ goto err1;
+ else
+ fw_status &= 1;
+
+ if (!fw_status) {
+ if (rsi_usb_device_init(adapter->priv)) {
+ rsi_dbg(ERR_ZONE, "%s: Failed in device init\n",
+ __func__);
+ goto err1;
+ }
+
+ if (rsi_usb_reg_write(dev->usbdev,
+ USB_INTERNAL_REG_1,
+ RSI_USB_READY_MAGIC_NUM, 1) < 0)
+ goto err1;
+ rsi_dbg(INIT_ZONE, "%s: Performed device init\n", __func__);
+ }
+
+ if (rsi_rx_urb_submit(adapter))
+ goto err1;
+
+ return 0;
+err1:
+ rsi_deinit_usb_interface(adapter);
+err:
+ rsi_91x_deinit(adapter);
+ rsi_dbg(ERR_ZONE, "%s: Failed in probe...Exiting\n", __func__);
+ return 1;
+}
+
+/**
+ * rsi_disconnect() - This function performs the reverse of the probe function,
+ * it deintialize the driver structure.
+ * @pfunction: Pointer to the USB interface structure.
+ *
+ * Return: None.
+ */
+static void rsi_disconnect(struct usb_interface *pfunction)
+{
+ struct rsi_hw *adapter = usb_get_intfdata(pfunction);
+
+ if (!adapter)
+ return;
+
+ rsi_mac80211_detach(adapter);
+ rsi_deinit_usb_interface(adapter);
+ rsi_91x_deinit(adapter);
+
+ rsi_dbg(INFO_ZONE, "%s: Deinitialization completed\n", __func__);
+}
+
+#ifdef CONFIG_PM
+static int rsi_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ /* Not yet implemented */
+ return -ENOSYS;
+}
+
+static int rsi_resume(struct usb_interface *intf)
+{
+ /* Not yet implemented */
+ return -ENOSYS;
+}
+#endif
+
+static const struct usb_device_id rsi_dev_table[] = {
+ { USB_DEVICE(0x0303, 0x0100) },
+ { USB_DEVICE(0x041B, 0x0301) },
+ { USB_DEVICE(0x041B, 0x0201) },
+ { USB_DEVICE(0x041B, 0x9330) },
+ { /* Blank */},
+};
+
+static struct usb_driver rsi_driver = {
+ .name = "RSI-USB WLAN",
+ .probe = rsi_probe,
+ .disconnect = rsi_disconnect,
+ .id_table = rsi_dev_table,
+#ifdef CONFIG_PM
+ .suspend = rsi_suspend,
+ .resume = rsi_resume,
+#endif
+};
+
+/**
+ * rsi_module_init() - This function registers the client driver.
+ * @void: Void.
+ *
+ * Return: 0 on success.
+ */
+static int rsi_module_init(void)
+{
+ usb_register(&rsi_driver);
+ rsi_dbg(INIT_ZONE, "%s: Registering driver\n", __func__);
+ return 0;
+}
+
+/**
+ * rsi_module_exit() - This function unregisters the client driver.
+ * @void: Void.
+ *
+ * Return: None.
+ */
+static void rsi_module_exit(void)
+{
+ usb_deregister(&rsi_driver);
+ rsi_dbg(INFO_ZONE, "%s: Unregistering driver\n", __func__);
+}
+
+module_init(rsi_module_init);
+module_exit(rsi_module_exit);
+
+MODULE_AUTHOR("Redpine Signals Inc");
+MODULE_DESCRIPTION("Common USB layer for RSI drivers");
+MODULE_SUPPORTED_DEVICE("RSI-91x");
+MODULE_DEVICE_TABLE(usb, rsi_dev_table);
+MODULE_FIRMWARE(FIRMWARE_RSI9113);
+MODULE_VERSION("0.1");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c
new file mode 100644
index 000000000000..1106ce76707e
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c
@@ -0,0 +1,177 @@
+/**
+ * Copyright (c) 2014 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/firmware.h>
+#include "rsi_usb.h"
+
+/**
+ * rsi_copy_to_card() - This function includes the actual funtionality of
+ * copying the TA firmware to the card.Basically this
+ * function includes opening the TA file,reading the TA
+ * file and writing their values in blocks of data.
+ * @common: Pointer to the driver private structure.
+ * @fw: Pointer to the firmware value to be written.
+ * @len: length of firmware file.
+ * @num_blocks: Number of blocks to be written to the card.
+ *
+ * Return: 0 on success and -1 on failure.
+ */
+static int rsi_copy_to_card(struct rsi_common *common,
+ const u8 *fw,
+ u32 len,
+ u32 num_blocks)
+{
+ struct rsi_hw *adapter = common->priv;
+ struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ u32 indx, ii;
+ u32 block_size = dev->tx_blk_size;
+ u32 lsb_address;
+ u32 base_address;
+
+ base_address = TA_LOAD_ADDRESS;
+
+ for (indx = 0, ii = 0; ii < num_blocks; ii++, indx += block_size) {
+ lsb_address = base_address;
+ if (rsi_usb_write_register_multiple(adapter,
+ lsb_address,
+ (u8 *)(fw + indx),
+ block_size)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Unable to load %s blk\n", __func__,
+ FIRMWARE_RSI9113);
+ return -EIO;
+ }
+ rsi_dbg(INIT_ZONE, "%s: loading block: %d\n", __func__, ii);
+ base_address += block_size;
+ }
+
+ if (len % block_size) {
+ lsb_address = base_address;
+ if (rsi_usb_write_register_multiple(adapter,
+ lsb_address,
+ (u8 *)(fw + indx),
+ len % block_size)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Unable to load %s blk\n", __func__,
+ FIRMWARE_RSI9113);
+ return -EIO;
+ }
+ }
+ rsi_dbg(INIT_ZONE,
+ "%s: Succesfully loaded %s instructions\n", __func__,
+ FIRMWARE_RSI9113);
+
+ rsi_dbg(INIT_ZONE, "%s: loaded firmware\n", __func__);
+ return 0;
+}
+
+/**
+ * rsi_usb_rx_thread() - This is a kernel thread to receive the packets from
+ * the USB device.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: None.
+ */
+void rsi_usb_rx_thread(struct rsi_common *common)
+{
+ struct rsi_hw *adapter = common->priv;
+ struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ int status;
+
+ do {
+ rsi_wait_event(&dev->rx_thread.event, EVENT_WAIT_FOREVER);
+
+ if (atomic_read(&dev->rx_thread.thread_done))
+ goto out;
+
+ mutex_lock(&common->tx_rxlock);
+ status = rsi_read_pkt(common, 0);
+ if (status) {
+ rsi_dbg(ERR_ZONE, "%s: Failed To read data", __func__);
+ mutex_unlock(&common->tx_rxlock);
+ return;
+ }
+ mutex_unlock(&common->tx_rxlock);
+ rsi_reset_event(&dev->rx_thread.event);
+ if (adapter->rx_urb_submit(adapter)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed in urb submission", __func__);
+ return;
+ }
+ } while (1);
+
+out:
+ rsi_dbg(INFO_ZONE, "%s: Terminated thread\n", __func__);
+ complete_and_exit(&dev->rx_thread.completion, 0);
+}
+
+
+/**
+ * rsi_load_ta_instructions() - This function includes the actual funtionality
+ * of loading the TA firmware.This function also
+ * includes opening the TA file,reading the TA
+ * file and writing their value in blocks of data.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: status: 0 on success, -1 on failure.
+ */
+static int rsi_load_ta_instructions(struct rsi_common *common)
+{
+ struct rsi_hw *adapter = common->priv;
+ struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ const struct firmware *fw_entry = NULL;
+ u32 block_size = dev->tx_blk_size;
+ const u8 *fw;
+ u32 num_blocks, len;
+ int status = 0;
+
+ status = request_firmware(&fw_entry, FIRMWARE_RSI9113, adapter->device);
+ if (status < 0) {
+ rsi_dbg(ERR_ZONE, "%s Firmware file %s not found\n",
+ __func__, FIRMWARE_RSI9113);
+ return status;
+ }
+
+ fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
+ len = fw_entry->size;
+
+ if (len % 4)
+ len += (4 - (len % 4));
+
+ num_blocks = (len / block_size);
+
+ rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len);
+ rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks);
+
+ status = rsi_copy_to_card(common, fw, len, num_blocks);
+ release_firmware(fw_entry);
+ return status;
+}
+
+/**
+ * rsi_device_init() - This Function Initializes The HAL.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+int rsi_usb_device_init(struct rsi_common *common)
+{
+ if (rsi_load_ta_instructions(common))
+ return -EIO;
+
+ return 0;
+ }
diff --git a/drivers/net/wireless/rsi/rsi_boot_params.h b/drivers/net/wireless/rsi/rsi_boot_params.h
new file mode 100644
index 000000000000..5e2721f7909c
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_boot_params.h
@@ -0,0 +1,126 @@
+/**
+ * Copyright (c) 2014 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __RSI_BOOTPARAMS_HEADER_H__
+#define __RSI_BOOTPARAMS_HEADER_H__
+
+#define CRYSTAL_GOOD_TIME BIT(0)
+#define BOOTUP_MODE_INFO BIT(1)
+#define WIFI_TAPLL_CONFIGS BIT(5)
+#define WIFI_PLL960_CONFIGS BIT(6)
+#define WIFI_AFEPLL_CONFIGS BIT(7)
+#define WIFI_SWITCH_CLK_CONFIGS BIT(8)
+
+#define TA_PLL_M_VAL_20 8
+#define TA_PLL_N_VAL_20 1
+#define TA_PLL_P_VAL_20 4
+
+#define PLL960_M_VAL_20 0x14
+#define PLL960_N_VAL_20 0
+#define PLL960_P_VAL_20 5
+
+#define UMAC_CLK_40MHZ 40
+
+#define TA_PLL_M_VAL_40 46
+#define TA_PLL_N_VAL_40 3
+#define TA_PLL_P_VAL_40 3
+
+#define PLL960_M_VAL_40 0x14
+#define PLL960_N_VAL_40 0
+#define PLL960_P_VAL_40 5
+
+#define UMAC_CLK_20BW \
+ (((TA_PLL_M_VAL_20 + 1) * 40) / \
+ ((TA_PLL_N_VAL_20 + 1) * (TA_PLL_P_VAL_20 + 1)))
+#define VALID_20 \
+ (WIFI_PLL960_CONFIGS | WIFI_AFEPLL_CONFIGS | WIFI_SWITCH_CLK_CONFIGS)
+#define UMAC_CLK_40BW \
+ (((TA_PLL_M_VAL_40 + 1) * 40) / \
+ ((TA_PLL_N_VAL_40 + 1) * (TA_PLL_P_VAL_40 + 1)))
+#define VALID_40 \
+ (WIFI_PLL960_CONFIGS | WIFI_AFEPLL_CONFIGS | WIFI_SWITCH_CLK_CONFIGS | \
+ WIFI_TAPLL_CONFIGS | CRYSTAL_GOOD_TIME | BOOTUP_MODE_INFO)
+
+/* structure to store configs related to TAPLL programming */
+struct tapll_info {
+ __le16 pll_reg_1;
+ __le16 pll_reg_2;
+} __packed;
+
+/* structure to store configs related to PLL960 programming */
+struct pll960_info {
+ __le16 pll_reg_1;
+ __le16 pll_reg_2;
+ __le16 pll_reg_3;
+} __packed;
+
+/* structure to store configs related to AFEPLL programming */
+struct afepll_info {
+ __le16 pll_reg;
+} __packed;
+
+/* structure to store configs related to pll configs */
+struct pll_config {
+ struct tapll_info tapll_info_g;
+ struct pll960_info pll960_info_g;
+ struct afepll_info afepll_info_g;
+} __packed;
+
+/* structure to store configs related to UMAC clk programming */
+struct switch_clk {
+ __le16 switch_clk_info;
+ /* If switch_bbp_lmac_clk_reg is set then this value will be programmed
+ * into reg
+ */
+ __le16 bbp_lmac_clk_reg_val;
+ /* if switch_umac_clk is set then this value will be programmed */
+ __le16 umac_clock_reg_config;
+ /* if switch_qspi_clk is set then this value will be programmed */
+ __le16 qspi_uart_clock_reg_config;
+} __packed;
+
+struct device_clk_info {
+ struct pll_config pll_config_g;
+ struct switch_clk switch_clk_g;
+} __packed;
+
+struct bootup_params {
+ __le16 magic_number;
+ __le16 crystal_good_time;
+ __le32 valid;
+ __le32 reserved_for_valids;
+ __le16 bootup_mode_info;
+ /* configuration used for digital loop back */
+ __le16 digital_loop_back_params;
+ __le16 rtls_timestamp_en;
+ __le16 host_spi_intr_cfg;
+ struct device_clk_info device_clk_info[3];
+ /* ulp buckboost wait time */
+ __le32 buckboost_wakeup_cnt;
+ /* pmu wakeup wait time & WDT EN info */
+ __le16 pmu_wakeup_wait;
+ u8 shutdown_wait_time;
+ /* Sleep clock source selection */
+ u8 pmu_slp_clkout_sel;
+ /* WDT programming values */
+ __le32 wdt_prog_value;
+ /* WDT soc reset delay */
+ __le32 wdt_soc_rst_delay;
+ /* dcdc modes configs */
+ __le32 dcdc_operation_mode;
+ __le32 soc_reset_wait_cnt;
+} __packed;
+#endif
diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h
new file mode 100644
index 000000000000..f2f70784d4ad
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_common.h
@@ -0,0 +1,87 @@
+/**
+ * Copyright (c) 2014 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __RSI_COMMON_H__
+#define __RSI_COMMON_H__
+
+#include <linux/kthread.h>
+
+#define EVENT_WAIT_FOREVER 0
+#define TA_LOAD_ADDRESS 0x00
+#define FIRMWARE_RSI9113 "rsi_91x.fw"
+#define QUEUE_NOT_FULL 1
+#define QUEUE_FULL 0
+
+static inline int rsi_init_event(struct rsi_event *pevent)
+{
+ atomic_set(&pevent->event_condition, 1);
+ init_waitqueue_head(&pevent->event_queue);
+ return 0;
+}
+
+static inline int rsi_wait_event(struct rsi_event *event, u32 timeout)
+{
+ int status = 0;
+
+ if (!timeout)
+ status = wait_event_interruptible(event->event_queue,
+ (atomic_read(&event->event_condition) == 0));
+ else
+ status = wait_event_interruptible_timeout(event->event_queue,
+ (atomic_read(&event->event_condition) == 0),
+ timeout);
+ return status;
+}
+
+static inline void rsi_set_event(struct rsi_event *event)
+{
+ atomic_set(&event->event_condition, 0);
+ wake_up_interruptible(&event->event_queue);
+}
+
+static inline void rsi_reset_event(struct rsi_event *event)
+{
+ atomic_set(&event->event_condition, 1);
+}
+
+static inline int rsi_create_kthread(struct rsi_common *common,
+ struct rsi_thread *thread,
+ void *func_ptr,
+ u8 *name)
+{
+ init_completion(&thread->completion);
+ thread->task = kthread_run(func_ptr, common, name);
+ if (IS_ERR(thread->task))
+ return (int)PTR_ERR(thread->task);
+
+ return 0;
+}
+
+static inline int rsi_kill_thread(struct rsi_thread *handle)
+{
+ atomic_inc(&handle->thread_done);
+ rsi_set_event(&handle->event);
+
+ wait_for_completion(&handle->completion);
+ return kthread_stop(handle->task);
+}
+
+void rsi_mac80211_detach(struct rsi_hw *hw);
+u16 rsi_get_connected_channel(struct rsi_hw *adapter);
+struct rsi_hw *rsi_91x_init(void);
+void rsi_91x_deinit(struct rsi_hw *adapter);
+int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len);
+#endif
diff --git a/drivers/net/wireless/rsi/rsi_debugfs.h b/drivers/net/wireless/rsi/rsi_debugfs.h
new file mode 100644
index 000000000000..580ad3b3f710
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_debugfs.h
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2014 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __RSI_DEBUGFS_H__
+#define __RSI_DEBUGFS_H__
+
+#include "rsi_main.h"
+#include <linux/debugfs.h>
+
+#ifndef CONFIG_RSI_DEBUGFS
+static inline int rsi_init_dbgfs(struct rsi_hw *adapter)
+{
+ return 0;
+}
+
+static inline void rsi_remove_dbgfs(struct rsi_hw *adapter)
+{
+ return;
+}
+#else
+struct rsi_dbg_files {
+ const char *name;
+ umode_t perms;
+ const struct file_operations fops;
+};
+
+struct rsi_debugfs {
+ struct dentry *subdir;
+ struct rsi_dbg_ops *dfs_get_ops;
+ struct dentry *rsi_files[MAX_DEBUGFS_ENTRIES];
+};
+int rsi_init_dbgfs(struct rsi_hw *adapter);
+void rsi_remove_dbgfs(struct rsi_hw *adapter);
+#endif
+#endif
diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
new file mode 100644
index 000000000000..2cb73e7edb98
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -0,0 +1,218 @@
+/**
+ * Copyright (c) 2014 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __RSI_MAIN_H__
+#define __RSI_MAIN_H__
+
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <net/mac80211.h>
+
+#define ERR_ZONE BIT(0) /* For Error Msgs */
+#define INFO_ZONE BIT(1) /* For General Status Msgs */
+#define INIT_ZONE BIT(2) /* For Driver Init Seq Msgs */
+#define MGMT_TX_ZONE BIT(3) /* For TX Mgmt Path Msgs */
+#define MGMT_RX_ZONE BIT(4) /* For RX Mgmt Path Msgs */
+#define DATA_TX_ZONE BIT(5) /* For TX Data Path Msgs */
+#define DATA_RX_ZONE BIT(6) /* For RX Data Path Msgs */
+#define FSM_ZONE BIT(7) /* For State Machine Msgs */
+#define ISR_ZONE BIT(8) /* For Interrupt Msgs */
+
+#define FSM_CARD_NOT_READY 0
+#define FSM_BOOT_PARAMS_SENT 1
+#define FSM_EEPROM_READ_MAC_ADDR 2
+#define FSM_RESET_MAC_SENT 3
+#define FSM_RADIO_CAPS_SENT 4
+#define FSM_BB_RF_PROG_SENT 5
+#define FSM_MAC_INIT_DONE 6
+
+extern u32 rsi_zone_enabled;
+extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...);
+
+#define RSI_MAX_VIFS 1
+#define NUM_EDCA_QUEUES 4
+#define IEEE80211_ADDR_LEN 6
+#define FRAME_DESC_SZ 16
+#define MIN_802_11_HDR_LEN 24
+
+#define DATA_QUEUE_WATER_MARK 400
+#define MIN_DATA_QUEUE_WATER_MARK 300
+#define MULTICAST_WATER_MARK 200
+#define MAC_80211_HDR_FRAME_CONTROL 0
+#define WME_NUM_AC 4
+#define NUM_SOFT_QUEUES 5
+#define MAX_HW_QUEUES 8
+#define INVALID_QUEUE 0xff
+#define MAX_CONTINUOUS_VO_PKTS 8
+#define MAX_CONTINUOUS_VI_PKTS 4
+
+/* Queue information */
+#define RSI_WIFI_MGMT_Q 0x4
+#define RSI_WIFI_DATA_Q 0x5
+#define IEEE80211_MGMT_FRAME 0x00
+#define IEEE80211_CTL_FRAME 0x04
+
+#define IEEE80211_QOS_TID 0x0f
+#define IEEE80211_NONQOS_TID 16
+
+#define MAX_DEBUGFS_ENTRIES 4
+
+#define TID_TO_WME_AC(_tid) ( \
+ ((_tid) == 0 || (_tid) == 3) ? BE_Q : \
+ ((_tid) < 3) ? BK_Q : \
+ ((_tid) < 6) ? VI_Q : \
+ VO_Q)
+
+#define WME_AC(_q) ( \
+ ((_q) == BK_Q) ? IEEE80211_AC_BK : \
+ ((_q) == BE_Q) ? IEEE80211_AC_BE : \
+ ((_q) == VI_Q) ? IEEE80211_AC_VI : \
+ IEEE80211_AC_VO)
+
+struct version_info {
+ u16 major;
+ u16 minor;
+ u16 release_num;
+ u16 patch_num;
+} __packed;
+
+struct skb_info {
+ s8 rssi;
+ u32 flags;
+ u16 channel;
+ s8 tid;
+ s8 sta_id;
+};
+
+enum edca_queue {
+ BK_Q,
+ BE_Q,
+ VI_Q,
+ VO_Q,
+ MGMT_SOFT_Q
+};
+
+struct security_info {
+ bool security_enable;
+ u32 ptk_cipher;
+ u32 gtk_cipher;
+};
+
+struct wmm_qinfo {
+ s32 weight;
+ s32 wme_params;
+ s32 pkt_contended;
+};
+
+struct transmit_q_stats {
+ u32 total_tx_pkt_send[NUM_EDCA_QUEUES + 1];
+ u32 total_tx_pkt_freed[NUM_EDCA_QUEUES + 1];
+};
+
+struct vif_priv {
+ bool is_ht;
+ bool sgi;
+ u16 seq_start;
+};
+
+struct rsi_event {
+ atomic_t event_condition;
+ wait_queue_head_t event_queue;
+};
+
+struct rsi_thread {
+ void (*thread_function)(void *);
+ struct completion completion;
+ struct task_struct *task;
+ struct rsi_event event;
+ atomic_t thread_done;
+};
+
+struct rsi_hw;
+
+struct rsi_common {
+ struct rsi_hw *priv;
+ struct vif_priv vif_info[RSI_MAX_VIFS];
+
+ bool mgmt_q_block;
+ struct version_info driver_ver;
+ struct version_info fw_ver;
+
+ struct rsi_thread tx_thread;
+ struct sk_buff_head tx_queue[NUM_EDCA_QUEUES + 1];
+ /* Mutex declaration */
+ struct mutex mutex;
+ /* Mutex used between tx/rx threads */
+ struct mutex tx_rxlock;
+ u8 endpoint;
+
+ /* Channel/band related */
+ u8 band;
+ u8 channel_width;
+
+ u16 rts_threshold;
+ u16 bitrate_mask[2];
+ u32 fixedrate_mask[2];
+
+ u8 rf_reset;
+ struct transmit_q_stats tx_stats;
+ struct security_info secinfo;
+ struct wmm_qinfo tx_qinfo[NUM_EDCA_QUEUES];
+ struct ieee80211_tx_queue_params edca_params[NUM_EDCA_QUEUES];
+ u8 mac_addr[IEEE80211_ADDR_LEN];
+
+ /* state related */
+ u32 fsm_state;
+ bool init_done;
+ u8 bb_rf_prog_count;
+ bool iface_down;
+
+ /* Generic */
+ u8 channel;
+ u8 *rx_data_pkt;
+ u8 mac_id;
+ u8 radio_id;
+ u16 rate_pwr[20];
+ u16 min_rate;
+
+ /* WMM algo related */
+ u8 selected_qnum;
+ u32 pkt_cnt;
+ u8 min_weight;
+};
+
+struct rsi_hw {
+ struct rsi_common *priv;
+ struct ieee80211_hw *hw;
+ struct ieee80211_vif *vifs[RSI_MAX_VIFS];
+ struct ieee80211_tx_queue_params edca_params[NUM_EDCA_QUEUES];
+ struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
+
+ struct device *device;
+ u8 sc_nvifs;
+
+#ifdef CONFIG_RSI_DEBUGFS
+ struct rsi_debugfs *dfsentry;
+ u8 num_debugfs_entries;
+#endif
+ void *rsi_dev;
+ int (*host_intf_read_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len);
+ int (*host_intf_write_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len);
+ int (*check_hw_queue_status)(struct rsi_hw *adapter, u8 q_num);
+ int (*rx_urb_submit)(struct rsi_hw *adapter);
+ int (*determine_event_timeout)(struct rsi_hw *adapter);
+};
+#endif
diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h
new file mode 100644
index 000000000000..ac67c4ad63c2
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_mgmt.h
@@ -0,0 +1,285 @@
+/**
+ * Copyright (c) 2014 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __RSI_MGMT_H__
+#define __RSI_MGMT_H__
+
+#include <linux/sort.h>
+#include "rsi_boot_params.h"
+#include "rsi_main.h"
+
+#define MAX_MGMT_PKT_SIZE 512
+#define RSI_NEEDED_HEADROOM 80
+#define RSI_RCV_BUFFER_LEN 2000
+
+#define RSI_11B_MODE 0
+#define RSI_11G_MODE BIT(7)
+#define RETRY_COUNT 8
+#define RETRY_LONG 4
+#define RETRY_SHORT 7
+#define WMM_SHORT_SLOT_TIME 9
+#define SIFS_DURATION 16
+
+#define KEY_TYPE_CLEAR 0
+#define RSI_PAIRWISE_KEY 1
+#define RSI_GROUP_KEY 2
+
+/* EPPROM_READ_ADDRESS */
+#define WLAN_MAC_EEPROM_ADDR 40
+#define WLAN_MAC_MAGIC_WORD_LEN 0x01
+#define WLAN_HOST_MODE_LEN 0x04
+#define WLAN_FW_VERSION_LEN 0x08
+#define MAGIC_WORD 0x5A
+
+/* Receive Frame Types */
+#define TA_CONFIRM_TYPE 0x01
+#define RX_DOT11_MGMT 0x02
+#define TX_STATUS_IND 0x04
+#define PROBEREQ_CONFIRM 2
+#define CARD_READY_IND 0x00
+
+#define RSI_DELETE_PEER 0x0
+#define RSI_ADD_PEER 0x1
+#define START_AMPDU_AGGR 0x1
+#define STOP_AMPDU_AGGR 0x0
+#define INTERNAL_MGMT_PKT 0x99
+
+#define PUT_BBP_RESET 0
+#define BBP_REG_WRITE 0
+#define RF_RESET_ENABLE BIT(3)
+#define RATE_INFO_ENABLE BIT(0)
+#define RSI_BROADCAST_PKT BIT(9)
+
+#define UPPER_20_ENABLE (0x2 << 12)
+#define LOWER_20_ENABLE (0x4 << 12)
+#define FULL40M_ENABLE 0x6
+
+#define RSI_LMAC_CLOCK_80MHZ 0x1
+#define RSI_ENABLE_40MHZ (0x1 << 3)
+
+#define RX_BA_INDICATION 1
+#define RSI_TBL_SZ 40
+#define MAX_RETRIES 8
+
+#define STD_RATE_MCS7 0x07
+#define STD_RATE_MCS6 0x06
+#define STD_RATE_MCS5 0x05
+#define STD_RATE_MCS4 0x04
+#define STD_RATE_MCS3 0x03
+#define STD_RATE_MCS2 0x02
+#define STD_RATE_MCS1 0x01
+#define STD_RATE_MCS0 0x00
+#define STD_RATE_54 0x6c
+#define STD_RATE_48 0x60
+#define STD_RATE_36 0x48
+#define STD_RATE_24 0x30
+#define STD_RATE_18 0x24
+#define STD_RATE_12 0x18
+#define STD_RATE_11 0x16
+#define STD_RATE_09 0x12
+#define STD_RATE_06 0x0C
+#define STD_RATE_5_5 0x0B
+#define STD_RATE_02 0x04
+#define STD_RATE_01 0x02
+
+#define RSI_RF_TYPE 1
+#define RSI_RATE_00 0x00
+#define RSI_RATE_1 0x0
+#define RSI_RATE_2 0x2
+#define RSI_RATE_5_5 0x4
+#define RSI_RATE_11 0x6
+#define RSI_RATE_6 0x8b
+#define RSI_RATE_9 0x8f
+#define RSI_RATE_12 0x8a
+#define RSI_RATE_18 0x8e
+#define RSI_RATE_24 0x89
+#define RSI_RATE_36 0x8d
+#define RSI_RATE_48 0x88
+#define RSI_RATE_54 0x8c
+#define RSI_RATE_MCS0 0x100
+#define RSI_RATE_MCS1 0x101
+#define RSI_RATE_MCS2 0x102
+#define RSI_RATE_MCS3 0x103
+#define RSI_RATE_MCS4 0x104
+#define RSI_RATE_MCS5 0x105
+#define RSI_RATE_MCS6 0x106
+#define RSI_RATE_MCS7 0x107
+#define RSI_RATE_MCS7_SG 0x307
+
+#define BW_20MHZ 0
+#define BW_40MHZ 1
+
+#define RSI_SUPP_FILTERS (FIF_ALLMULTI | FIF_PROBE_REQ |\
+ FIF_BCN_PRBRESP_PROMISC)
+enum opmode {
+ STA_OPMODE = 1,
+ AP_OPMODE = 2
+};
+
+extern struct ieee80211_rate rsi_rates[12];
+extern const u16 rsi_mcsrates[8];
+
+enum sta_notify_events {
+ STA_CONNECTED = 0,
+ STA_DISCONNECTED,
+ STA_TX_ADDBA_DONE,
+ STA_TX_DELBA,
+ STA_RX_ADDBA_DONE,
+ STA_RX_DELBA
+};
+
+/* Send Frames Types */
+enum cmd_frame_type {
+ TX_DOT11_MGMT,
+ RESET_MAC_REQ,
+ RADIO_CAPABILITIES,
+ BB_PROG_VALUES_REQUEST,
+ RF_PROG_VALUES_REQUEST,
+ WAKEUP_SLEEP_REQUEST,
+ SCAN_REQUEST,
+ TSF_UPDATE,
+ PEER_NOTIFY,
+ BLOCK_UNBLOCK,
+ SET_KEY_REQ,
+ AUTO_RATE_IND,
+ BOOTUP_PARAMS_REQUEST,
+ VAP_CAPABILITIES,
+ EEPROM_READ_TYPE ,
+ EEPROM_WRITE,
+ GPIO_PIN_CONFIG ,
+ SET_RX_FILTER,
+ AMPDU_IND,
+ STATS_REQUEST_FRAME,
+ BB_BUF_PROG_VALUES_REQ,
+ BBP_PROG_IN_TA,
+ BG_SCAN_PARAMS,
+ BG_SCAN_PROBE_REQ,
+ CW_MODE_REQ,
+ PER_CMD_PKT
+};
+
+struct rsi_mac_frame {
+ __le16 desc_word[8];
+} __packed;
+
+struct rsi_boot_params {
+ __le16 desc_word[8];
+ struct bootup_params bootup_params;
+} __packed;
+
+struct rsi_peer_notify {
+ __le16 desc_word[8];
+ u8 mac_addr[6];
+ __le16 command;
+ __le16 mpdu_density;
+ __le16 reserved;
+ __le32 sta_flags;
+} __packed;
+
+struct rsi_vap_caps {
+ __le16 desc_word[8];
+ u8 mac_addr[6];
+ __le16 keep_alive_period;
+ u8 bssid[6];
+ __le16 reserved;
+ __le32 flags;
+ __le16 frag_threshold;
+ __le16 rts_threshold;
+ __le32 default_mgmt_rate;
+ __le32 default_ctrl_rate;
+ __le32 default_data_rate;
+ __le16 beacon_interval;
+ __le16 dtim_period;
+} __packed;
+
+struct rsi_set_key {
+ __le16 desc_word[8];
+ u8 key[4][32];
+ u8 tx_mic_key[8];
+ u8 rx_mic_key[8];
+} __packed;
+
+struct rsi_auto_rate {
+ __le16 desc_word[8];
+ __le16 failure_limit;
+ __le16 initial_boundary;
+ __le16 max_threshold_limt;
+ __le16 num_supported_rates;
+ __le16 aarf_rssi;
+ __le16 moderate_rate_inx;
+ __le16 collision_tolerance;
+ __le16 supported_rates[40];
+} __packed;
+
+struct qos_params {
+ __le16 cont_win_min_q;
+ __le16 cont_win_max_q;
+ __le16 aifsn_val_q;
+ __le16 txop_q;
+} __packed;
+
+struct rsi_radio_caps {
+ __le16 desc_word[8];
+ struct qos_params qos_params[MAX_HW_QUEUES];
+ u8 num_11n_rates;
+ u8 num_11ac_rates;
+ __le16 gcpd_per_rate[20];
+} __packed;
+
+static inline u32 rsi_get_queueno(u8 *addr, u16 offset)
+{
+ return (le16_to_cpu(*(__le16 *)&addr[offset]) & 0x7000) >> 12;
+}
+
+static inline u32 rsi_get_length(u8 *addr, u16 offset)
+{
+ return (le16_to_cpu(*(__le16 *)&addr[offset])) & 0x0fff;
+}
+
+static inline u8 rsi_get_extended_desc(u8 *addr, u16 offset)
+{
+ return le16_to_cpu(*((__le16 *)&addr[offset + 4])) & 0x00ff;
+}
+
+static inline u8 rsi_get_rssi(u8 *addr)
+{
+ return *(u8 *)(addr + FRAME_DESC_SZ);
+}
+
+static inline u8 rsi_get_channel(u8 *addr)
+{
+ return *(char *)(addr + 15);
+}
+
+int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg);
+int rsi_set_vap_capabilities(struct rsi_common *common, enum opmode mode);
+int rsi_send_aggregation_params_frame(struct rsi_common *common, u16 tid,
+ u16 ssn, u8 buf_size, u8 event);
+int rsi_hal_load_key(struct rsi_common *common, u8 *data, u16 key_len,
+ u8 key_type, u8 key_id, u32 cipher);
+int rsi_set_channel(struct rsi_common *common, u16 chno);
+void rsi_inform_bss_status(struct rsi_common *common, u8 status,
+ const u8 *bssid, u8 qos_enable, u16 aid);
+void rsi_indicate_pkt_to_os(struct rsi_common *common, struct sk_buff *skb);
+int rsi_mac80211_attach(struct rsi_common *common);
+void rsi_indicate_tx_status(struct rsi_hw *common, struct sk_buff *skb,
+ int status);
+bool rsi_is_cipher_wep(struct rsi_common *common);
+void rsi_core_qos_processor(struct rsi_common *common);
+void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb);
+int rsi_send_mgmt_pkt(struct rsi_common *common, struct sk_buff *skb);
+int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb);
+#endif
diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h
new file mode 100644
index 000000000000..df4b5e20e05f
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_sdio.h
@@ -0,0 +1,129 @@
+/**
+ * @section LICENSE
+ * Copyright (c) 2014 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef __RSI_SDIO_INTF__
+#define __RSI_SDIO_INTF__
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sd.h>
+#include <linux/mmc/sdio_ids.h>
+#include "rsi_main.h"
+
+enum sdio_interrupt_type {
+ BUFFER_FULL = 0x0,
+ BUFFER_AVAILABLE = 0x1,
+ FIRMWARE_ASSERT_IND = 0x3,
+ MSDU_PACKET_PENDING = 0x4,
+ UNKNOWN_INT = 0XE
+};
+
+/* Buffer status register related info */
+#define PKT_BUFF_SEMI_FULL 0
+#define PKT_BUFF_FULL 1
+#define PKT_MGMT_BUFF_FULL 2
+#define MSDU_PKT_PENDING 3
+/* Interrupt Bit Related Macros */
+#define PKT_BUFF_AVAILABLE 0
+#define FW_ASSERT_IND 2
+
+#define RSI_DEVICE_BUFFER_STATUS_REGISTER 0xf3
+#define RSI_FN1_INT_REGISTER 0xf9
+#define RSI_SD_REQUEST_MASTER 0x10000
+
+/* FOR SD CARD ONLY */
+#define SDIO_RX_NUM_BLOCKS_REG 0x000F1
+#define SDIO_FW_STATUS_REG 0x000F2
+#define SDIO_NXT_RD_DELAY2 0x000F5
+#define SDIO_MASTER_ACCESS_MSBYTE 0x000FA
+#define SDIO_MASTER_ACCESS_LSBYTE 0x000FB
+#define SDIO_READ_START_LVL 0x000FC
+#define SDIO_READ_FIFO_CTL 0x000FD
+#define SDIO_WRITE_FIFO_CTL 0x000FE
+#define SDIO_FUN1_INTR_CLR_REG 0x0008
+#define SDIO_REG_HIGH_SPEED 0x0013
+
+#define RSI_GET_SDIO_INTERRUPT_TYPE(_I, TYPE) \
+ { \
+ TYPE = \
+ (_I & (1 << PKT_BUFF_AVAILABLE)) ? \
+ BUFFER_AVAILABLE : \
+ (_I & (1 << MSDU_PKT_PENDING)) ? \
+ MSDU_PACKET_PENDING : \
+ (_I & (1 << FW_ASSERT_IND)) ? \
+ FIRMWARE_ASSERT_IND : UNKNOWN_INT; \
+ }
+
+/* common registers in SDIO function1 */
+#define TA_SOFT_RESET_REG 0x0004
+#define TA_TH0_PC_REG 0x0400
+#define TA_HOLD_THREAD_REG 0x0844
+#define TA_RELEASE_THREAD_REG 0x0848
+
+#define TA_SOFT_RST_CLR 0
+#define TA_SOFT_RST_SET BIT(0)
+#define TA_PC_ZERO 0
+#define TA_HOLD_THREAD_VALUE cpu_to_le32(0xF)
+#define TA_RELEASE_THREAD_VALUE cpu_to_le32(0xF)
+#define TA_BASE_ADDR 0x2200
+#define MISC_CFG_BASE_ADDR 0x4150
+
+struct receive_info {
+ bool buffer_full;
+ bool semi_buffer_full;
+ bool mgmt_buffer_full;
+ u32 mgmt_buf_full_counter;
+ u32 buf_semi_full_counter;
+ u8 watch_bufferfull_count;
+ u32 sdio_intr_status_zero;
+ u32 sdio_int_counter;
+ u32 total_sdio_msdu_pending_intr;
+ u32 total_sdio_unknown_intr;
+ u32 buf_full_counter;
+ u32 buf_avilable_counter;
+};
+
+struct rsi_91x_sdiodev {
+ struct sdio_func *pfunction;
+ struct task_struct *in_sdio_litefi_irq;
+ struct receive_info rx_info;
+ u32 next_read_delay;
+ u32 sdio_high_speed_enable;
+ u8 sdio_clock_speed;
+ u32 cardcapability;
+ u8 prev_desc[16];
+ u32 tx_blk_size;
+ u8 write_fail;
+};
+
+void rsi_interrupt_handler(struct rsi_hw *adapter);
+int rsi_init_sdio_slave_regs(struct rsi_hw *adapter);
+int rsi_sdio_device_init(struct rsi_common *common);
+int rsi_sdio_read_register(struct rsi_hw *adapter, u32 addr, u8 *data);
+int rsi_sdio_host_intf_read_pkt(struct rsi_hw *adapter, u8 *pkt, u32 length);
+int rsi_sdio_write_register(struct rsi_hw *adapter, u8 function,
+ u32 addr, u8 *data);
+int rsi_sdio_write_register_multiple(struct rsi_hw *adapter, u32 addr,
+ u8 *data, u32 count);
+void rsi_sdio_ack_intr(struct rsi_hw *adapter, u8 int_bit);
+int rsi_sdio_determine_event_timeout(struct rsi_hw *adapter);
+int rsi_sdio_read_buffer_status_register(struct rsi_hw *adapter, u8 q_num);
+#endif
diff --git a/drivers/net/wireless/rsi/rsi_usb.h b/drivers/net/wireless/rsi/rsi_usb.h
new file mode 100644
index 000000000000..ebea0c411ead
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_usb.h
@@ -0,0 +1,68 @@
+/**
+ * @section LICENSE
+ * Copyright (c) 2014 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __RSI_USB_INTF__
+#define __RSI_USB_INTF__
+
+#include <linux/usb.h>
+#include "rsi_main.h"
+#include "rsi_common.h"
+
+#define USB_INTERNAL_REG_1 0x25000
+#define RSI_USB_READY_MAGIC_NUM 0xab
+#define FW_STATUS_REG 0x41050012
+
+#define USB_VENDOR_REGISTER_READ 0x15
+#define USB_VENDOR_REGISTER_WRITE 0x16
+#define RSI_USB_TX_HEAD_ROOM 128
+
+#define MAX_RX_URBS 1
+#define MAX_BULK_EP 8
+#define MGMT_EP 1
+#define DATA_EP 2
+
+struct rsi_91x_usbdev {
+ struct rsi_thread rx_thread;
+ u8 endpoint;
+ struct usb_device *usbdev;
+ struct usb_interface *pfunction;
+ struct urb *rx_usb_urb[MAX_RX_URBS];
+ u8 *tx_buffer;
+ __le16 bulkin_size;
+ u8 bulkin_endpoint_addr;
+ __le16 bulkout_size[MAX_BULK_EP];
+ u8 bulkout_endpoint_addr[MAX_BULK_EP];
+ u32 tx_blk_size;
+ u8 write_fail;
+};
+
+static inline int rsi_usb_check_queue_status(struct rsi_hw *adapter, u8 q_num)
+{
+ /* In USB, there isn't any need to check the queue status */
+ return QUEUE_NOT_FULL;
+}
+
+static inline int rsi_usb_event_timeout(struct rsi_hw *adapter)
+{
+ return EVENT_WAIT_FOREVER;
+}
+
+int rsi_usb_device_init(struct rsi_common *common);
+int rsi_usb_write_register_multiple(struct rsi_hw *adapter, u32 addr,
+ u8 *data, u32 count);
+void rsi_usb_rx_thread(struct rsi_common *common);
+#endif
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index abc5f56f29fe..2f1cd929c6f6 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1877,6 +1877,11 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
EEPROM_MAC_ADDR_0));
/*
+ * Disable powersaving as default.
+ */
+ rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
+ /*
* Initialize hw_mode information.
*/
spec->supported_bands = SUPPORT_BAND_2GHZ;
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 9f16824cd1bc..d849d590de25 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1706,6 +1706,11 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK;
+ /*
+ * Disable powersaving as default.
+ */
+ rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
rt2x00_eeprom_addr(rt2x00dev,
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index b8f5b06006c4..41d4a8167dc3 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -5460,14 +5460,15 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev)
rt2800_bbp_write(rt2x00dev, 68, 0x0b);
- rt2800_bbp_write(rt2x00dev, 69, 0x0d);
- rt2800_bbp_write(rt2x00dev, 70, 0x06);
+ rt2800_bbp_write(rt2x00dev, 69, 0x12);
rt2800_bbp_write(rt2x00dev, 73, 0x13);
rt2800_bbp_write(rt2x00dev, 75, 0x46);
rt2800_bbp_write(rt2x00dev, 76, 0x28);
rt2800_bbp_write(rt2x00dev, 77, 0x59);
+ rt2800_bbp_write(rt2x00dev, 70, 0x0a);
+
rt2800_bbp_write(rt2x00dev, 79, 0x13);
rt2800_bbp_write(rt2x00dev, 80, 0x05);
rt2800_bbp_write(rt2x00dev, 81, 0x33);
@@ -5510,7 +5511,6 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev)
if (rt2x00_rt(rt2x00dev, RT5392)) {
rt2800_bbp_write(rt2x00dev, 134, 0xd0);
rt2800_bbp_write(rt2x00dev, 135, 0xf6);
- rt2800_bbp_write(rt2x00dev, 148, 0x84);
}
rt2800_disable_unused_dac_adc(rt2x00dev);
@@ -7458,10 +7458,9 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
u32 reg;
/*
- * Disable powersaving as default on PCI devices.
+ * Disable powersaving as default.
*/
- if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
- rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+ rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
/*
* Initialize all hw fields.
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index caddc1b427a9..a49c3d73ea2c 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -125,9 +125,9 @@ static inline bool rt2800usb_entry_txstatus_timeout(struct queue_entry *entry)
tout = time_after(jiffies, entry->last_action + msecs_to_jiffies(100));
if (unlikely(tout))
- rt2x00_warn(entry->queue->rt2x00dev,
- "TX status timeout for entry %d in queue %d\n",
- entry->entry_idx, entry->queue->qid);
+ rt2x00_dbg(entry->queue->rt2x00dev,
+ "TX status timeout for entry %d in queue %d\n",
+ entry->entry_idx, entry->queue->qid);
return tout;
}
@@ -566,8 +566,8 @@ static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev)
queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
if (unlikely(rt2x00queue_empty(queue))) {
- rt2x00_warn(rt2x00dev, "Got TX status for an empty queue %u, dropping\n",
- qid);
+ rt2x00_dbg(rt2x00dev, "Got TX status for an empty queue %u, dropping\n",
+ qid);
break;
}
@@ -764,7 +764,7 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* Overwrite TX done handler
*/
- PREPARE_WORK(&rt2x00dev->txdone_work, rt2800usb_work_txdone);
+ INIT_WORK(&rt2x00dev->txdone_work, rt2800usb_work_txdone);
return 0;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 2e3d1645e68b..90fdb02b55e7 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -286,7 +286,7 @@ static ssize_t rt2x00debug_read_queue_dump(struct file *file,
if (retval)
return retval;
- status = min((size_t)skb->len, length);
+ status = min_t(size_t, skb->len, length);
if (copy_to_user(buf, skb->data, status)) {
status = -EFAULT;
goto exit;
diff --git a/drivers/net/wireless/rtl818x/Kconfig b/drivers/net/wireless/rtl818x/Kconfig
index 30332175bcd8..1ce1d55f0010 100644
--- a/drivers/net/wireless/rtl818x/Kconfig
+++ b/drivers/net/wireless/rtl818x/Kconfig
@@ -2,11 +2,11 @@
# RTL818X Wireless LAN device configuration
#
config RTL8180
- tristate "Realtek 8180/8185 PCI support"
+ tristate "Realtek 8180/8185/8187SE PCI support"
depends on MAC80211 && PCI
select EEPROM_93CX6
---help---
- This is a driver for RTL8180 and RTL8185 based cards.
+ This is a driver for RTL8180, RTL8185 and RTL8187SE based cards.
These are PCI based chips found in cards such as:
(RTL8185 802.11g)
diff --git a/drivers/net/wireless/rtl818x/rtl8180/Makefile b/drivers/net/wireless/rtl818x/rtl8180/Makefile
index cb4fb8596f0b..08b056db4a3b 100644
--- a/drivers/net/wireless/rtl818x/rtl8180/Makefile
+++ b/drivers/net/wireless/rtl818x/rtl8180/Makefile
@@ -1,4 +1,4 @@
-rtl8180-objs := dev.o rtl8225.o sa2400.o max2820.o grf5101.o
+rtl8180-objs := dev.o rtl8225.o sa2400.o max2820.o grf5101.o rtl8225se.o
obj-$(CONFIG_RTL8180) += rtl8180.o
diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c
index 8ec17aad0e52..98d8256f0377 100644
--- a/drivers/net/wireless/rtl818x/rtl8180/dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c
@@ -1,15 +1,42 @@
-/*
- * Linux device driver for RTL8180 / RTL8185
+/* Linux device driver for RTL8180 / RTL8185 / RTL8187SE
*
* Copyright 2007 Michael Wu <flamingice@sourmilk.net>
- * Copyright 2007 Andrea Merello <andrea.merello@gmail.com>
+ * Copyright 2007,2014 Andrea Merello <andrea.merello@gmail.com>
*
* Based on the r8180 driver, which is:
* Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
*
* Thanks to Realtek for their support!
*
+ ************************************************************************
+ *
+ * The driver was extended to the RTL8187SE in 2014 by
+ * Andrea Merello <andrea.merello@gmail.com>
+ *
+ * based also on:
+ * - portions of rtl8187se Linux staging driver, Copyright Realtek corp.
+ * - other GPL, unpublished (until now), Linux driver code,
+ * Copyright Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ * A huge thanks goes to Sara V. Nari who forgives me when I'm
+ * sitting in front of my laptop at evening, week-end, night...
+ *
+ * A special thanks goes to Antonio Cuni, who helped me with
+ * some python userspace stuff I used to debug RTL8187SE code, and who
+ * bought a laptop with an unsupported Wi-Fi card some years ago...
+ *
+ * Thanks to Larry Finger for writing some code for rtl8187se and for
+ * his suggestions.
+ *
+ * Thanks to Dan Carpenter for reviewing my initial patch and for his
+ * suggestions.
+ *
+ * Thanks to Bernhard Schiffner for his help in testing and for his
+ * suggestions.
+ *
+ ************************************************************************
+ *
* 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.
@@ -29,13 +56,18 @@
#include "sa2400.h"
#include "max2820.h"
#include "grf5101.h"
+#include "rtl8225se.h"
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
MODULE_AUTHOR("Andrea Merello <andrea.merello@gmail.com>");
-MODULE_DESCRIPTION("RTL8180 / RTL8185 PCI wireless driver");
+MODULE_DESCRIPTION("RTL8180 / RTL8185 / RTL8187SE PCI wireless driver");
MODULE_LICENSE("GPL");
static DEFINE_PCI_DEVICE_TABLE(rtl8180_table) = {
+
+ /* rtl8187se */
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8199) },
+
/* rtl8185 */
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8185) },
{ PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x700f) },
@@ -85,6 +117,76 @@ static const struct ieee80211_channel rtl818x_channels[] = {
{ .center_freq = 2484 },
};
+/* Queues for rtl8187se card
+ *
+ * name | reg | queue
+ * BC | 7 | 6
+ * MG | 1 | 0
+ * HI | 6 | 1
+ * VO | 5 | 2
+ * VI | 4 | 3
+ * BE | 3 | 4
+ * BK | 2 | 5
+ *
+ * The complete map for DMA kick reg using use all queue is:
+ * static const int rtl8187se_queues_map[RTL8187SE_NR_TX_QUEUES] =
+ * {1, 6, 5, 4, 3, 2, 7};
+ *
+ * .. but.. Because for mac80211 4 queues are enough for QoS we use this
+ *
+ * name | reg | queue
+ * BC | 7 | 4 <- currently not used yet
+ * MG | 1 | x <- Not used
+ * HI | 6 | x <- Not used
+ * VO | 5 | 0 <- used
+ * VI | 4 | 1 <- used
+ * BE | 3 | 2 <- used
+ * BK | 2 | 3 <- used
+ *
+ * Beacon queue could be used, but this is not finished yet.
+ *
+ * I thougth about using the other two queues but I decided not to do this:
+ *
+ * - I'm unsure whether the mac80211 will ever try to use more than 4 queues
+ * by itself.
+ *
+ * - I could route MGMT frames (currently sent over VO queue) to the MGMT
+ * queue but since mac80211 will do not know about it, I will probably gain
+ * some HW priority whenever the VO queue is not empty, but this gain is
+ * limited by the fact that I had to stop the mac80211 queue whenever one of
+ * the VO or MGMT queues is full, stopping also submitting of MGMT frame
+ * to the driver.
+ *
+ * - I don't know how to set in the HW the contention window params for MGMT
+ * and HI-prio queues.
+ */
+
+static const int rtl8187se_queues_map[RTL8187SE_NR_TX_QUEUES] = {5, 4, 3, 2, 7};
+
+/* Queues for rtl8180/rtl8185 cards
+ *
+ * name | reg | prio
+ * BC | 7 | 3
+ * HI | 6 | 0
+ * NO | 5 | 1
+ * LO | 4 | 2
+ *
+ * The complete map for DMA kick reg using all queue is:
+ * static const int rtl8180_queues_map[RTL8180_NR_TX_QUEUES] = {6, 5, 4, 7};
+ *
+ * .. but .. Because the mac80211 needs at least 4 queues for QoS or
+ * otherwise QoS can't be done, we use just one.
+ * Beacon queue could be used, but this is not finished yet.
+ * Actual map is:
+ *
+ * name | reg | prio
+ * BC | 7 | 1 <- currently not used yet.
+ * HI | 6 | x <- not used
+ * NO | 5 | x <- not used
+ * LO | 4 | 0 <- used
+ */
+
+static const int rtl8180_queues_map[RTL8180_NR_TX_QUEUES] = {4, 7};
void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
{
@@ -105,13 +207,30 @@ void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
static void rtl8180_handle_rx(struct ieee80211_hw *dev)
{
struct rtl8180_priv *priv = dev->priv;
+ struct rtl818x_rx_cmd_desc *cmd_desc;
unsigned int count = 32;
u8 signal, agc, sq;
+ dma_addr_t mapping;
while (count--) {
- struct rtl8180_rx_desc *entry = &priv->rx_ring[priv->rx_idx];
+ void *entry = priv->rx_ring + priv->rx_idx * priv->rx_ring_sz;
struct sk_buff *skb = priv->rx_buf[priv->rx_idx];
- u32 flags = le32_to_cpu(entry->flags);
+ u32 flags, flags2;
+ u64 tsft;
+
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+ struct rtl8187se_rx_desc *desc = entry;
+
+ flags = le32_to_cpu(desc->flags);
+ flags2 = le32_to_cpu(desc->flags2);
+ tsft = le64_to_cpu(desc->tsft);
+ } else {
+ struct rtl8180_rx_desc *desc = entry;
+
+ flags = le32_to_cpu(desc->flags);
+ flags2 = le32_to_cpu(desc->flags2);
+ tsft = le64_to_cpu(desc->tsft);
+ }
if (flags & RTL818X_RX_DESC_FLAG_OWN)
return;
@@ -121,13 +240,23 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
RTL818X_RX_DESC_FLAG_RX_ERR)))
goto done;
else {
- u32 flags2 = le32_to_cpu(entry->flags2);
struct ieee80211_rx_status rx_status = {0};
struct sk_buff *new_skb = dev_alloc_skb(MAX_RX_SIZE);
if (unlikely(!new_skb))
goto done;
+ mapping = pci_map_single(priv->pdev,
+ skb_tail_pointer(new_skb),
+ MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
+
+ if (pci_dma_mapping_error(priv->pdev, mapping)) {
+ kfree_skb(new_skb);
+ dev_err(&priv->pdev->dev, "RX DMA map error\n");
+
+ goto done;
+ }
+
pci_unmap_single(priv->pdev,
*((dma_addr_t *)skb->cb),
MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
@@ -136,19 +265,24 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
rx_status.antenna = (flags2 >> 15) & 1;
rx_status.rate_idx = (flags >> 20) & 0xF;
agc = (flags2 >> 17) & 0x7F;
- if (priv->r8185) {
+
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8185) {
if (rx_status.rate_idx > 3)
signal = 90 - clamp_t(u8, agc, 25, 90);
else
signal = 95 - clamp_t(u8, agc, 30, 95);
- } else {
+ } else if (priv->chip_family ==
+ RTL818X_CHIP_FAMILY_RTL8180) {
sq = flags2 & 0xff;
signal = priv->rf->calc_rssi(agc, sq);
+ } else {
+ /* TODO: rtl8187se rssi */
+ signal = 10;
}
rx_status.signal = signal;
rx_status.freq = dev->conf.chandef.chan->center_freq;
rx_status.band = dev->conf.chandef.chan->band;
- rx_status.mactime = le64_to_cpu(entry->tsft);
+ rx_status.mactime = tsft;
rx_status.flag |= RX_FLAG_MACTIME_START;
if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
@@ -158,17 +292,17 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
skb = new_skb;
priv->rx_buf[priv->rx_idx] = skb;
- *((dma_addr_t *) skb->cb) =
- pci_map_single(priv->pdev, skb_tail_pointer(skb),
- MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
+ *((dma_addr_t *) skb->cb) = mapping;
}
done:
- entry->rx_buf = cpu_to_le32(*((dma_addr_t *)skb->cb));
- entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN |
+ cmd_desc = entry;
+ cmd_desc->rx_buf = cpu_to_le32(*((dma_addr_t *)skb->cb));
+ cmd_desc->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN |
MAX_RX_SIZE);
if (priv->rx_idx == 31)
- entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR);
+ cmd_desc->flags |=
+ cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR);
priv->rx_idx = (priv->rx_idx + 1) % 32;
}
}
@@ -208,6 +342,55 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio)
}
}
+static irqreturn_t rtl8187se_interrupt(int irq, void *dev_id)
+{
+ struct ieee80211_hw *dev = dev_id;
+ struct rtl8180_priv *priv = dev->priv;
+ u32 reg;
+ unsigned long flags;
+ static int desc_err;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ /* Note: 32-bit interrupt status */
+ reg = rtl818x_ioread32(priv, &priv->map->INT_STATUS_SE);
+ if (unlikely(reg == 0xFFFFFFFF)) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return IRQ_HANDLED;
+ }
+
+ rtl818x_iowrite32(priv, &priv->map->INT_STATUS_SE, reg);
+
+ if (reg & IMR_TIMEOUT1)
+ rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0);
+
+ if (reg & (IMR_TBDOK | IMR_TBDER))
+ rtl8180_handle_tx(dev, 4);
+
+ if (reg & (IMR_TVODOK | IMR_TVODER))
+ rtl8180_handle_tx(dev, 0);
+
+ if (reg & (IMR_TVIDOK | IMR_TVIDER))
+ rtl8180_handle_tx(dev, 1);
+
+ if (reg & (IMR_TBEDOK | IMR_TBEDER))
+ rtl8180_handle_tx(dev, 2);
+
+ if (reg & (IMR_TBKDOK | IMR_TBKDER))
+ rtl8180_handle_tx(dev, 3);
+
+ if (reg & (IMR_ROK | IMR_RER | RTL818X_INT_SE_RX_DU | IMR_RQOSOK))
+ rtl8180_handle_rx(dev);
+ /* The interface sometimes generates several RX DMA descriptor errors
+ * at startup. Do not report these.
+ */
+ if ((reg & RTL818X_INT_SE_RX_DU) && desc_err++ > 2)
+ if (net_ratelimit())
+ wiphy_err(dev->wiphy, "No RX DMA Descriptor avail\n");
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return IRQ_HANDLED;
+}
+
static irqreturn_t rtl8180_interrupt(int irq, void *dev_id)
{
struct ieee80211_hw *dev = dev_id;
@@ -224,12 +407,6 @@ static irqreturn_t rtl8180_interrupt(int irq, void *dev_id)
rtl818x_iowrite16(priv, &priv->map->INT_STATUS, reg);
if (reg & (RTL818X_INT_TXB_OK | RTL818X_INT_TXB_ERR))
- rtl8180_handle_tx(dev, 3);
-
- if (reg & (RTL818X_INT_TXH_OK | RTL818X_INT_TXH_ERR))
- rtl8180_handle_tx(dev, 2);
-
- if (reg & (RTL818X_INT_TXN_OK | RTL818X_INT_TXN_ERR))
rtl8180_handle_tx(dev, 1);
if (reg & (RTL818X_INT_TXL_OK | RTL818X_INT_TXL_ERR))
@@ -253,12 +430,14 @@ static void rtl8180_tx(struct ieee80211_hw *dev,
struct rtl8180_tx_ring *ring;
struct rtl8180_tx_desc *entry;
unsigned long flags;
- unsigned int idx, prio;
+ unsigned int idx, prio, hw_prio;
dma_addr_t mapping;
u32 tx_flags;
u8 rc_flags;
u16 plcp_len = 0;
__le16 rts_duration = 0;
+ /* do arithmetic and then convert to le16 */
+ u16 frame_duration = 0;
prio = skb_get_queue_mapping(skb);
ring = &priv->tx_ring[prio];
@@ -266,12 +445,18 @@ static void rtl8180_tx(struct ieee80211_hw *dev,
mapping = pci_map_single(priv->pdev, skb->data,
skb->len, PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(priv->pdev, mapping)) {
+ kfree_skb(skb);
+ dev_err(&priv->pdev->dev, "TX DMA mapping error\n");
+ return;
+ }
+
tx_flags = RTL818X_TX_DESC_FLAG_OWN | RTL818X_TX_DESC_FLAG_FS |
RTL818X_TX_DESC_FLAG_LS |
(ieee80211_get_tx_rate(dev, info)->hw_value << 24) |
skb->len;
- if (priv->r8185)
+ if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180)
tx_flags |= RTL818X_TX_DESC_FLAG_DMA |
RTL818X_TX_DESC_FLAG_NO_ENC;
@@ -288,7 +473,7 @@ static void rtl8180_tx(struct ieee80211_hw *dev,
rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len,
info);
- if (!priv->r8185) {
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180) {
unsigned int remainder;
plcp_len = DIV_ROUND_UP(16 * (skb->len + 4),
@@ -299,6 +484,18 @@ static void rtl8180_tx(struct ieee80211_hw *dev,
plcp_len |= 1 << 15;
}
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+ __le16 duration;
+ /* SIFS time (required by HW) is already included by
+ * ieee80211_generic_frame_duration
+ */
+ duration = ieee80211_generic_frame_duration(dev, priv->vif,
+ IEEE80211_BAND_2GHZ, skb->len,
+ ieee80211_get_tx_rate(dev, info));
+
+ frame_duration = priv->ack_time + le16_to_cpu(duration);
+ }
+
spin_lock_irqsave(&priv->lock, flags);
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
@@ -311,21 +508,91 @@ static void rtl8180_tx(struct ieee80211_hw *dev,
idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries;
entry = &ring->desc[idx];
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+ entry->frame_duration = cpu_to_le16(frame_duration);
+ entry->frame_len_se = cpu_to_le16(skb->len);
+
+ /* tpc polarity */
+ entry->flags3 = cpu_to_le16(1<<4);
+ } else
+ entry->frame_len = cpu_to_le32(skb->len);
+
entry->rts_duration = rts_duration;
entry->plcp_len = cpu_to_le16(plcp_len);
entry->tx_buf = cpu_to_le32(mapping);
- entry->frame_len = cpu_to_le32(skb->len);
+
entry->flags2 = info->control.rates[1].idx >= 0 ?
ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0;
entry->retry_limit = info->control.rates[0].count;
+
+ /* We must be sure that tx_flags is written last because the HW
+ * looks at it to check if the rest of data is valid or not
+ */
+ wmb();
entry->flags = cpu_to_le32(tx_flags);
+ /* We must be sure this has been written before followings HW
+ * register write, because this write will made the HW attempts
+ * to DMA the just-written data
+ */
+ wmb();
+
__skb_queue_tail(&ring->queue, skb);
if (ring->entries - skb_queue_len(&ring->queue) < 2)
ieee80211_stop_queue(dev, prio);
spin_unlock_irqrestore(&priv->lock, flags);
- rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4)));
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+ /* just poll: rings are stopped with TPPollStop reg */
+ hw_prio = rtl8187se_queues_map[prio];
+ rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING,
+ (1 << hw_prio));
+ } else {
+ hw_prio = rtl8180_queues_map[prio];
+ rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING,
+ (1 << hw_prio) | /* ring to poll */
+ (1<<1) | (1<<2));/* stopped rings */
+ }
+}
+
+static void rtl8180_set_anaparam3(struct rtl8180_priv *priv, u16 anaparam3)
+{
+ u8 reg;
+
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
+ RTL818X_EEPROM_CMD_CONFIG);
+
+ reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+ rtl818x_iowrite8(priv, &priv->map->CONFIG3,
+ reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+
+ rtl818x_iowrite16(priv, &priv->map->ANAPARAM3, anaparam3);
+
+ rtl818x_iowrite8(priv, &priv->map->CONFIG3,
+ reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
+ RTL818X_EEPROM_CMD_NORMAL);
+}
+
+void rtl8180_set_anaparam2(struct rtl8180_priv *priv, u32 anaparam2)
+{
+ u8 reg;
+
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
+ RTL818X_EEPROM_CMD_CONFIG);
+
+ reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+ rtl818x_iowrite8(priv, &priv->map->CONFIG3,
+ reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, anaparam2);
+
+ rtl818x_iowrite8(priv, &priv->map->CONFIG3,
+ reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
+ RTL818X_EEPROM_CMD_NORMAL);
}
void rtl8180_set_anaparam(struct rtl8180_priv *priv, u32 anaparam)
@@ -342,17 +609,171 @@ void rtl8180_set_anaparam(struct rtl8180_priv *priv, u32 anaparam)
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
}
+static void rtl8187se_mac_config(struct ieee80211_hw *dev)
+{
+ struct rtl8180_priv *priv = dev->priv;
+ u8 reg;
+
+ rtl818x_iowrite32(priv, REG_ADDR4(0x1F0), 0);
+ rtl818x_ioread32(priv, REG_ADDR4(0x1F0));
+ rtl818x_iowrite32(priv, REG_ADDR4(0x1F4), 0);
+ rtl818x_ioread32(priv, REG_ADDR4(0x1F4));
+ rtl818x_iowrite8(priv, REG_ADDR1(0x1F8), 0);
+ rtl818x_ioread8(priv, REG_ADDR1(0x1F8));
+ /* Enable DA10 TX power saving */
+ reg = rtl818x_ioread8(priv, &priv->map->PHY_PR);
+ rtl818x_iowrite8(priv, &priv->map->PHY_PR, reg | 0x04);
+ /* Power */
+ rtl818x_iowrite16(priv, PI_DATA_REG, 0x1000);
+ rtl818x_iowrite16(priv, SI_DATA_REG, 0x1000);
+ /* AFE - default to power ON */
+ rtl818x_iowrite16(priv, REG_ADDR2(0x370), 0x0560);
+ rtl818x_iowrite16(priv, REG_ADDR2(0x372), 0x0560);
+ rtl818x_iowrite16(priv, REG_ADDR2(0x374), 0x0DA4);
+ rtl818x_iowrite16(priv, REG_ADDR2(0x376), 0x0DA4);
+ rtl818x_iowrite16(priv, REG_ADDR2(0x378), 0x0560);
+ rtl818x_iowrite16(priv, REG_ADDR2(0x37A), 0x0560);
+ rtl818x_iowrite16(priv, REG_ADDR2(0x37C), 0x00EC);
+ rtl818x_iowrite16(priv, REG_ADDR2(0x37E), 0x00EC);
+ rtl818x_iowrite8(priv, REG_ADDR1(0x24E), 0x01);
+ /* unknown, needed for suspend to RAM resume */
+ rtl818x_iowrite8(priv, REG_ADDR1(0x0A), 0x72);
+}
+
+static void rtl8187se_set_antenna_config(struct ieee80211_hw *dev, u8 def_ant,
+ bool diversity)
+{
+ struct rtl8180_priv *priv = dev->priv;
+
+ rtl8225_write_phy_cck(dev, 0x0C, 0x09);
+ if (diversity) {
+ if (def_ant == 1) {
+ rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x00);
+ rtl8225_write_phy_cck(dev, 0x11, 0xBB);
+ rtl8225_write_phy_cck(dev, 0x01, 0xC7);
+ rtl8225_write_phy_ofdm(dev, 0x0D, 0x54);
+ rtl8225_write_phy_ofdm(dev, 0x18, 0xB2);
+ } else { /* main antenna */
+ rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);
+ rtl8225_write_phy_cck(dev, 0x11, 0x9B);
+ rtl8225_write_phy_cck(dev, 0x01, 0xC7);
+ rtl8225_write_phy_ofdm(dev, 0x0D, 0x5C);
+ rtl8225_write_phy_ofdm(dev, 0x18, 0xB2);
+ }
+ } else { /* disable antenna diversity */
+ if (def_ant == 1) {
+ rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x00);
+ rtl8225_write_phy_cck(dev, 0x11, 0xBB);
+ rtl8225_write_phy_cck(dev, 0x01, 0x47);
+ rtl8225_write_phy_ofdm(dev, 0x0D, 0x54);
+ rtl8225_write_phy_ofdm(dev, 0x18, 0x32);
+ } else { /* main antenna */
+ rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);
+ rtl8225_write_phy_cck(dev, 0x11, 0x9B);
+ rtl8225_write_phy_cck(dev, 0x01, 0x47);
+ rtl8225_write_phy_ofdm(dev, 0x0D, 0x5C);
+ rtl8225_write_phy_ofdm(dev, 0x18, 0x32);
+ }
+ }
+ /* priv->curr_ant = def_ant; */
+}
+
+static void rtl8180_int_enable(struct ieee80211_hw *dev)
+{
+ struct rtl8180_priv *priv = dev->priv;
+
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+ rtl818x_iowrite32(priv, &priv->map->IMR, IMR_TMGDOK |
+ IMR_TBDER | IMR_THPDER |
+ IMR_THPDER | IMR_THPDOK |
+ IMR_TVODER | IMR_TVODOK |
+ IMR_TVIDER | IMR_TVIDOK |
+ IMR_TBEDER | IMR_TBEDOK |
+ IMR_TBKDER | IMR_TBKDOK |
+ IMR_RDU | IMR_RER |
+ IMR_ROK | IMR_RQOSOK);
+ } else {
+ rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
+ }
+}
+
+static void rtl8180_int_disable(struct ieee80211_hw *dev)
+{
+ struct rtl8180_priv *priv = dev->priv;
+
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+ rtl818x_iowrite32(priv, &priv->map->IMR, 0);
+ } else {
+ rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
+ }
+}
+
+static void rtl8180_conf_basic_rates(struct ieee80211_hw *dev,
+ u32 rates_mask)
+{
+ struct rtl8180_priv *priv = dev->priv;
+
+ u8 max, min;
+ u16 reg;
+
+ max = fls(rates_mask) - 1;
+ min = ffs(rates_mask) - 1;
+
+ switch (priv->chip_family) {
+
+ case RTL818X_CHIP_FAMILY_RTL8180:
+ /* in 8180 this is NOT a BITMAP */
+ reg = rtl818x_ioread16(priv, &priv->map->BRSR);
+ reg &= ~3;
+ reg |= max;
+ rtl818x_iowrite16(priv, &priv->map->BRSR, reg);
+ break;
+
+ case RTL818X_CHIP_FAMILY_RTL8185:
+ /* in 8185 this is a BITMAP */
+ rtl818x_iowrite16(priv, &priv->map->BRSR, rates_mask);
+ rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (max << 4) | min);
+ break;
+
+ case RTL818X_CHIP_FAMILY_RTL8187SE:
+ /* in 8187se this is a BITMAP */
+ rtl818x_iowrite16(priv, &priv->map->BRSR_8187SE, rates_mask);
+ break;
+ }
+}
+
+static void rtl8180_config_cardbus(struct ieee80211_hw *dev)
+{
+ struct rtl8180_priv *priv = dev->priv;
+ u16 reg16;
+ u8 reg8;
+
+ reg8 = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+ reg8 |= 1 << 1;
+ rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg8);
+
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+ rtl818x_iowrite16(priv, FEMR_SE, 0xffff);
+ } else {
+ reg16 = rtl818x_ioread16(priv, &priv->map->FEMR);
+ reg16 |= (1 << 15) | (1 << 14) | (1 << 4);
+ rtl818x_iowrite16(priv, &priv->map->FEMR, reg16);
+ }
+
+}
+
static int rtl8180_init_hw(struct ieee80211_hw *dev)
{
struct rtl8180_priv *priv = dev->priv;
u16 reg;
+ u32 reg32;
rtl818x_iowrite8(priv, &priv->map->CMD, 0);
rtl818x_ioread8(priv, &priv->map->CMD);
msleep(10);
/* reset */
- rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
+ rtl8180_int_disable(dev);
rtl818x_ioread8(priv, &priv->map->CMD);
reg = rtl818x_ioread8(priv, &priv->map->CMD);
@@ -373,31 +794,45 @@ static int rtl8180_init_hw(struct ieee80211_hw *dev)
msleep(200);
if (rtl818x_ioread8(priv, &priv->map->CONFIG3) & (1 << 3)) {
- /* For cardbus */
- reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
- reg |= 1 << 1;
- rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg);
- reg = rtl818x_ioread16(priv, &priv->map->FEMR);
- reg |= (1 << 15) | (1 << 14) | (1 << 4);
- rtl818x_iowrite16(priv, &priv->map->FEMR, reg);
+ rtl8180_config_cardbus(dev);
}
- rtl818x_iowrite8(priv, &priv->map->MSR, 0);
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE)
+ rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_ENEDCA);
+ else
+ rtl818x_iowrite8(priv, &priv->map->MSR, 0);
- if (!priv->r8185)
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180)
rtl8180_set_anaparam(priv, priv->anaparam);
rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma);
- rtl818x_iowrite32(priv, &priv->map->TBDA, priv->tx_ring[3].dma);
- rtl818x_iowrite32(priv, &priv->map->THPDA, priv->tx_ring[2].dma);
- rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring[1].dma);
- rtl818x_iowrite32(priv, &priv->map->TLPDA, priv->tx_ring[0].dma);
+ /* mac80211 queue have higher prio for lower index. The last queue
+ * (that mac80211 is not aware of) is reserved for beacons (and have
+ * the highest priority on the NIC)
+ */
+ if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8187SE) {
+ rtl818x_iowrite32(priv, &priv->map->TBDA,
+ priv->tx_ring[1].dma);
+ rtl818x_iowrite32(priv, &priv->map->TLPDA,
+ priv->tx_ring[0].dma);
+ } else {
+ rtl818x_iowrite32(priv, &priv->map->TBDA,
+ priv->tx_ring[4].dma);
+ rtl818x_iowrite32(priv, &priv->map->TVODA,
+ priv->tx_ring[0].dma);
+ rtl818x_iowrite32(priv, &priv->map->TVIDA,
+ priv->tx_ring[1].dma);
+ rtl818x_iowrite32(priv, &priv->map->TBEDA,
+ priv->tx_ring[2].dma);
+ rtl818x_iowrite32(priv, &priv->map->TBKDA,
+ priv->tx_ring[3].dma);
+ }
/* TODO: necessary? specs indicate not */
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
reg = rtl818x_ioread8(priv, &priv->map->CONFIG2);
rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg & ~(1 << 3));
- if (priv->r8185) {
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8185) {
reg = rtl818x_ioread8(priv, &priv->map->CONFIG2);
rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg | (1 << 4));
}
@@ -409,13 +844,17 @@ static int rtl8180_init_hw(struct ieee80211_hw *dev)
rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0);
- if (priv->r8185) {
+ if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) {
rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0);
rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81);
- rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0);
+ } else {
+ rtl818x_iowrite8(priv, &priv->map->SECURITY, 0);
- rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3);
+ rtl818x_iowrite8(priv, &priv->map->PHY_DELAY, 0x6);
+ rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, 0x4C);
+ }
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8185) {
/* TODO: set ClkRun enable? necessary? */
reg = rtl818x_ioread8(priv, &priv->map->GP_ENABLE);
rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, reg & ~(1 << 6));
@@ -423,28 +862,90 @@ static int rtl8180_init_hw(struct ieee80211_hw *dev)
reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | (1 << 2));
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
- } else {
- rtl818x_iowrite16(priv, &priv->map->BRSR, 0x1);
- rtl818x_iowrite8(priv, &priv->map->SECURITY, 0);
+ }
- rtl818x_iowrite8(priv, &priv->map->PHY_DELAY, 0x6);
- rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, 0x4C);
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+
+ /* the set auto rate fallback bitmask from 1M to 54 Mb/s */
+ rtl818x_iowrite16(priv, ARFR, 0xFFF);
+ rtl818x_ioread16(priv, ARFR);
+
+ /* stop unused queus (no dma alloc) */
+ rtl818x_iowrite8(priv, &priv->map->TPPOLL_STOP,
+ RTL818x_TPPOLL_STOP_MG | RTL818x_TPPOLL_STOP_HI);
+
+ rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0x00);
+ rtl818x_iowrite16(priv, &priv->map->TID_AC_MAP, 0xFA50);
+
+ rtl818x_iowrite16(priv, &priv->map->INT_MIG, 0);
+
+ /* some black magic here.. */
+ rtl8187se_mac_config(dev);
+
+ rtl818x_iowrite16(priv, RFSW_CTRL, 0x569A);
+ rtl818x_ioread16(priv, RFSW_CTRL);
+
+ rtl8180_set_anaparam(priv, RTL8225SE_ANAPARAM_ON);
+ rtl8180_set_anaparam2(priv, RTL8225SE_ANAPARAM2_ON);
+ rtl8180_set_anaparam3(priv, RTL8225SE_ANAPARAM3);
+
+
+ rtl818x_iowrite8(priv, &priv->map->CONFIG5,
+ rtl818x_ioread8(priv, &priv->map->CONFIG5) & 0x7F);
+
+ /*probably this switch led on */
+ rtl818x_iowrite8(priv, &priv->map->PGSELECT,
+ rtl818x_ioread8(priv, &priv->map->PGSELECT) | 0x08);
+
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480);
+ rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1BFF);
+ rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x2488);
+
+ rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x4003);
+
+ /* the reference code mac hardcode table write
+ * this reg by doing byte-wide accesses.
+ * It does it just for lowest and highest byte..
+ */
+ reg32 = rtl818x_ioread32(priv, &priv->map->RF_PARA);
+ reg32 &= 0x00ffff00;
+ reg32 |= 0xb8000054;
+ rtl818x_iowrite32(priv, &priv->map->RF_PARA, reg32);
}
priv->rf->init(dev);
- if (priv->r8185)
- rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3);
+
+ /* default basic rates are 1,2 Mbps for rtl8180. 1,2,6,9,12,18,24 Mbps
+ * otherwise. bitmask 0x3 and 0x01f3 respectively.
+ * NOTE: currenty rtl8225 RF code changes basic rates, so we need to do
+ * this after rf init.
+ * TODO: try to find out whether RF code really needs to do this..
+ */
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180)
+ rtl8180_conf_basic_rates(dev, 0x3);
+ else
+ rtl8180_conf_basic_rates(dev, 0x1f3);
+
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE)
+ rtl8187se_set_antenna_config(dev,
+ priv->antenna_diversity_default,
+ priv->antenna_diversity_en);
return 0;
}
static int rtl8180_init_rx_ring(struct ieee80211_hw *dev)
{
struct rtl8180_priv *priv = dev->priv;
- struct rtl8180_rx_desc *entry;
+ struct rtl818x_rx_cmd_desc *entry;
int i;
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE)
+ priv->rx_ring_sz = sizeof(struct rtl8187se_rx_desc);
+ else
+ priv->rx_ring_sz = sizeof(struct rtl8180_rx_desc);
+
priv->rx_ring = pci_alloc_consistent(priv->pdev,
- sizeof(*priv->rx_ring) * 32,
+ priv->rx_ring_sz * 32,
&priv->rx_ring_dma);
if (!priv->rx_ring || (unsigned long)priv->rx_ring & 0xFF) {
@@ -452,20 +953,28 @@ static int rtl8180_init_rx_ring(struct ieee80211_hw *dev)
return -ENOMEM;
}
- memset(priv->rx_ring, 0, sizeof(*priv->rx_ring) * 32);
+ memset(priv->rx_ring, 0, priv->rx_ring_sz * 32);
priv->rx_idx = 0;
for (i = 0; i < 32; i++) {
struct sk_buff *skb = dev_alloc_skb(MAX_RX_SIZE);
dma_addr_t *mapping;
- entry = &priv->rx_ring[i];
- if (!skb)
- return 0;
-
+ entry = priv->rx_ring + priv->rx_ring_sz*i;
+ if (!skb) {
+ wiphy_err(dev->wiphy, "Cannot allocate RX skb\n");
+ return -ENOMEM;
+ }
priv->rx_buf[i] = skb;
mapping = (dma_addr_t *)skb->cb;
*mapping = pci_map_single(priv->pdev, skb_tail_pointer(skb),
MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
+
+ if (pci_dma_mapping_error(priv->pdev, *mapping)) {
+ kfree_skb(skb);
+ wiphy_err(dev->wiphy, "Cannot map DMA for RX skb\n");
+ return -ENOMEM;
+ }
+
entry->rx_buf = cpu_to_le32(*mapping);
entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN |
MAX_RX_SIZE);
@@ -490,7 +999,7 @@ static void rtl8180_free_rx_ring(struct ieee80211_hw *dev)
kfree_skb(skb);
}
- pci_free_consistent(priv->pdev, sizeof(*priv->rx_ring) * 32,
+ pci_free_consistent(priv->pdev, priv->rx_ring_sz * 32,
priv->rx_ring, priv->rx_ring_dma);
priv->rx_ring = NULL;
}
@@ -554,7 +1063,7 @@ static int rtl8180_start(struct ieee80211_hw *dev)
if (ret)
return ret;
- for (i = 0; i < 4; i++)
+ for (i = 0; i < (dev->queues + 1); i++)
if ((ret = rtl8180_init_tx_ring(dev, i, 16)))
goto err_free_rings;
@@ -562,23 +1071,28 @@ static int rtl8180_start(struct ieee80211_hw *dev)
if (ret)
goto err_free_rings;
- rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma);
- rtl818x_iowrite32(priv, &priv->map->TBDA, priv->tx_ring[3].dma);
- rtl818x_iowrite32(priv, &priv->map->THPDA, priv->tx_ring[2].dma);
- rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring[1].dma);
- rtl818x_iowrite32(priv, &priv->map->TLPDA, priv->tx_ring[0].dma);
-
- ret = request_irq(priv->pdev->irq, rtl8180_interrupt,
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+ ret = request_irq(priv->pdev->irq, rtl8187se_interrupt,
+ IRQF_SHARED, KBUILD_MODNAME, dev);
+ } else {
+ ret = request_irq(priv->pdev->irq, rtl8180_interrupt,
IRQF_SHARED, KBUILD_MODNAME, dev);
+ }
+
if (ret) {
wiphy_err(dev->wiphy, "failed to register IRQ handler\n");
goto err_free_rings;
}
- rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
+ rtl8180_int_enable(dev);
- rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0);
- rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0);
+ /* in rtl8187se at MAR regs offset there is the management
+ * TX descriptor DMA addres..
+ */
+ if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8187SE) {
+ rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0);
+ rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0);
+ }
reg = RTL818X_RX_CONF_ONLYERLPKT |
RTL818X_RX_CONF_RX_AUTORESETPHY |
@@ -588,27 +1102,42 @@ static int rtl8180_start(struct ieee80211_hw *dev)
RTL818X_RX_CONF_BROADCAST |
RTL818X_RX_CONF_NICMAC;
- if (priv->r8185)
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8185)
reg |= RTL818X_RX_CONF_CSDM1 | RTL818X_RX_CONF_CSDM2;
- else {
+ else if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180) {
reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE1)
? RTL818X_RX_CONF_CSDM1 : 0;
reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE2)
? RTL818X_RX_CONF_CSDM2 : 0;
+ } else {
+ reg &= ~(RTL818X_RX_CONF_CSDM1 | RTL818X_RX_CONF_CSDM2);
}
priv->rx_conf = reg;
rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg);
- if (priv->r8185) {
+ if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) {
reg = rtl818x_ioread8(priv, &priv->map->CW_CONF);
- reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT;
- reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT;
+
+ /* CW is not on per-packet basis.
+ * in rtl8185 the CW_VALUE reg is used.
+ * in rtl8187se the AC param regs are used.
+ */
+ reg &= ~RTL818X_CW_CONF_PERPACKET_CW;
+ /* retry limit IS on per-packet basis.
+ * the short and long retry limit in TX_CONF
+ * reg are ignored
+ */
+ reg |= RTL818X_CW_CONF_PERPACKET_RETRY;
rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg);
reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL);
- reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT;
- reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT;
+ /* TX antenna and TX gain are not on per-packet basis.
+ * TX Antenna is selected by ANTSEL reg (RX in BB regs).
+ * TX gain is selected with CCK_TX_AGC and OFDM_TX_AGC regs
+ */
+ reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN;
+ reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL;
reg |= RTL818X_TX_AGC_CTL_FEEDBACK_ANT;
rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg);
@@ -620,11 +1149,16 @@ static int rtl8180_start(struct ieee80211_hw *dev)
reg |= (6 << 21 /* MAX TX DMA */) |
RTL818X_TX_CONF_NO_ICV;
- if (priv->r8185)
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE)
+ reg |= 1<<30; /* "duration procedure mode" */
+
+ if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180)
reg &= ~RTL818X_TX_CONF_PROBE_DTS;
else
reg &= ~RTL818X_TX_CONF_HW_SEQNUM;
+ reg &= ~RTL818X_TX_CONF_DISCW;
+
/* different meaning, same value on both rtl8185 and rtl8180 */
reg &= ~RTL818X_TX_CONF_SAT_HWPLCP;
@@ -639,7 +1173,7 @@ static int rtl8180_start(struct ieee80211_hw *dev)
err_free_rings:
rtl8180_free_rx_ring(dev);
- for (i = 0; i < 4; i++)
+ for (i = 0; i < (dev->queues + 1); i++)
if (priv->tx_ring[i].desc)
rtl8180_free_tx_ring(dev, i);
@@ -652,7 +1186,7 @@ static void rtl8180_stop(struct ieee80211_hw *dev)
u8 reg;
int i;
- rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
+ rtl8180_int_disable(dev);
reg = rtl818x_ioread8(priv, &priv->map->CMD);
reg &= ~RTL818X_CMD_TX_ENABLE;
@@ -669,7 +1203,7 @@ static void rtl8180_stop(struct ieee80211_hw *dev)
free_irq(priv->pdev->irq, dev);
rtl8180_free_rx_ring(dev);
- for (i = 0; i < 4; i++)
+ for (i = 0; i < (dev->queues + 1); i++)
rtl8180_free_tx_ring(dev, i);
}
@@ -777,6 +1311,123 @@ static int rtl8180_config(struct ieee80211_hw *dev, u32 changed)
return 0;
}
+static void rtl8187se_conf_ac_parm(struct ieee80211_hw *dev, u8 queue)
+{
+ const struct ieee80211_tx_queue_params *params;
+ struct rtl8180_priv *priv = dev->priv;
+
+ /* hw value */
+ u32 ac_param;
+
+ u8 aifs;
+ u8 txop;
+ u8 cw_min, cw_max;
+
+ params = &priv->queue_param[queue];
+
+ cw_min = fls(params->cw_min);
+ cw_max = fls(params->cw_max);
+
+ aifs = 10 + params->aifs * priv->slot_time;
+
+ /* TODO: check if txop HW is in us (mult by 32) */
+ txop = params->txop;
+
+ ac_param = txop << AC_PARAM_TXOP_LIMIT_SHIFT |
+ cw_max << AC_PARAM_ECW_MAX_SHIFT |
+ cw_min << AC_PARAM_ECW_MIN_SHIFT |
+ aifs << AC_PARAM_AIFS_SHIFT;
+
+ switch (queue) {
+ case IEEE80211_AC_BK:
+ rtl818x_iowrite32(priv, &priv->map->AC_BK_PARAM, ac_param);
+ break;
+ case IEEE80211_AC_BE:
+ rtl818x_iowrite32(priv, &priv->map->AC_BE_PARAM, ac_param);
+ break;
+ case IEEE80211_AC_VI:
+ rtl818x_iowrite32(priv, &priv->map->AC_VI_PARAM, ac_param);
+ break;
+ case IEEE80211_AC_VO:
+ rtl818x_iowrite32(priv, &priv->map->AC_VO_PARAM, ac_param);
+ break;
+ }
+}
+
+static int rtl8180_conf_tx(struct ieee80211_hw *dev,
+ struct ieee80211_vif *vif, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct rtl8180_priv *priv = dev->priv;
+ u8 cw_min, cw_max;
+
+ /* nothing to do ? */
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180)
+ return 0;
+
+ cw_min = fls(params->cw_min);
+ cw_max = fls(params->cw_max);
+
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+ priv->queue_param[queue] = *params;
+ rtl8187se_conf_ac_parm(dev, queue);
+ } else
+ rtl818x_iowrite8(priv, &priv->map->CW_VAL,
+ (cw_max << 4) | cw_min);
+ return 0;
+}
+
+static void rtl8180_conf_erp(struct ieee80211_hw *dev,
+ struct ieee80211_bss_conf *info)
+{
+ struct rtl8180_priv *priv = dev->priv;
+ u8 sifs, difs;
+ int eifs;
+ u8 hw_eifs;
+
+ /* TODO: should we do something ? */
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180)
+ return;
+
+ /* I _hope_ this means 10uS for the HW.
+ * In reference code it is 0x22 for
+ * both rtl8187L and rtl8187SE
+ */
+ sifs = 0x22;
+
+ if (info->use_short_slot)
+ priv->slot_time = 9;
+ else
+ priv->slot_time = 20;
+
+ /* 10 is SIFS time in uS */
+ difs = 10 + 2 * priv->slot_time;
+ eifs = 10 + difs + priv->ack_time;
+
+ /* HW should use 4uS units for EIFS (I'm sure for rtl8185)*/
+ hw_eifs = DIV_ROUND_UP(eifs, 4);
+
+
+ rtl818x_iowrite8(priv, &priv->map->SLOT, priv->slot_time);
+ rtl818x_iowrite8(priv, &priv->map->SIFS, sifs);
+ rtl818x_iowrite8(priv, &priv->map->DIFS, difs);
+
+ /* from reference code. set ack timeout reg = eifs reg */
+ rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, hw_eifs);
+
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE)
+ rtl818x_iowrite8(priv, &priv->map->EIFS_8187SE, hw_eifs);
+ else if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8185) {
+ /* rtl8187/rtl8185 HW bug. After EIFS is elapsed,
+ * the HW still wait for DIFS.
+ * HW uses 4uS units for EIFS.
+ */
+ hw_eifs = DIV_ROUND_UP(eifs - difs, 4);
+
+ rtl818x_iowrite8(priv, &priv->map->EIFS, hw_eifs);
+ }
+}
+
static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info,
@@ -801,11 +1452,40 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,
reg = RTL818X_MSR_INFRA;
} else
reg = RTL818X_MSR_NO_LINK;
+
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE)
+ reg |= RTL818X_MSR_ENEDCA;
+
rtl818x_iowrite8(priv, &priv->map->MSR, reg);
}
- if (changed & BSS_CHANGED_ERP_SLOT && priv->rf->conf_erp)
- priv->rf->conf_erp(dev, info);
+ if (changed & BSS_CHANGED_BASIC_RATES)
+ rtl8180_conf_basic_rates(dev, info->basic_rates);
+
+ if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_ERP_PREAMBLE)) {
+
+ /* when preamble changes, acktime duration changes, and erp must
+ * be recalculated. ACK time is calculated at lowest rate.
+ * Since mac80211 include SIFS time we remove it (-10)
+ */
+ priv->ack_time =
+ le16_to_cpu(ieee80211_generic_frame_duration(dev,
+ priv->vif,
+ IEEE80211_BAND_2GHZ, 10,
+ &priv->rates[0])) - 10;
+
+ rtl8180_conf_erp(dev, info);
+
+ /* mac80211 supplies aifs_n to driver and calls
+ * conf_tx callback whether aifs_n changes, NOT
+ * when aifs changes.
+ * Aifs should be recalculated if slot changes.
+ */
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+ for (i = 0; i < 4; i++)
+ rtl8187se_conf_ac_parm(dev, i);
+ }
+ }
if (changed & BSS_CHANGED_BEACON_ENABLED)
vif_priv->enable_beacon = info->enable_beacon;
@@ -863,6 +1543,7 @@ static const struct ieee80211_ops rtl8180_ops = {
.remove_interface = rtl8180_remove_interface,
.config = rtl8180_config,
.bss_info_changed = rtl8180_bss_info_changed,
+ .conf_tx = rtl8180_conf_tx,
.prepare_multicast = rtl8180_prepare_multicast,
.configure_filter = rtl8180_configure_filter,
.get_tsf = rtl8180_get_tsf,
@@ -870,8 +1551,7 @@ static const struct ieee80211_ops rtl8180_ops = {
static void rtl8180_eeprom_register_read(struct eeprom_93cx6 *eeprom)
{
- struct ieee80211_hw *dev = eeprom->data;
- struct rtl8180_priv *priv = dev->priv;
+ struct rtl8180_priv *priv = eeprom->data;
u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE;
@@ -882,8 +1562,7 @@ static void rtl8180_eeprom_register_read(struct eeprom_93cx6 *eeprom)
static void rtl8180_eeprom_register_write(struct eeprom_93cx6 *eeprom)
{
- struct ieee80211_hw *dev = eeprom->data;
- struct rtl8180_priv *priv = dev->priv;
+ struct rtl8180_priv *priv = eeprom->data;
u8 reg = 2 << 6;
if (eeprom->reg_data_in)
@@ -900,6 +1579,83 @@ static void rtl8180_eeprom_register_write(struct eeprom_93cx6 *eeprom)
udelay(10);
}
+static void rtl8180_eeprom_read(struct rtl8180_priv *priv)
+{
+ struct eeprom_93cx6 eeprom;
+ int eeprom_cck_table_adr;
+ u16 eeprom_val;
+ int i;
+
+ eeprom.data = priv;
+ eeprom.register_read = rtl8180_eeprom_register_read;
+ eeprom.register_write = rtl8180_eeprom_register_write;
+ if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6))
+ eeprom.width = PCI_EEPROM_WIDTH_93C66;
+ else
+ eeprom.width = PCI_EEPROM_WIDTH_93C46;
+
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
+ RTL818X_EEPROM_CMD_PROGRAM);
+ rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+ udelay(10);
+
+ eeprom_93cx6_read(&eeprom, 0x06, &eeprom_val);
+ eeprom_val &= 0xFF;
+ priv->rf_type = eeprom_val;
+
+ eeprom_93cx6_read(&eeprom, 0x17, &eeprom_val);
+ priv->csthreshold = eeprom_val >> 8;
+
+ eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *)priv->mac_addr, 3);
+
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE)
+ eeprom_cck_table_adr = 0x30;
+ else
+ eeprom_cck_table_adr = 0x10;
+
+ /* CCK TX power */
+ for (i = 0; i < 14; i += 2) {
+ u16 txpwr;
+ eeprom_93cx6_read(&eeprom, eeprom_cck_table_adr + (i >> 1),
+ &txpwr);
+ priv->channels[i].hw_value = txpwr & 0xFF;
+ priv->channels[i + 1].hw_value = txpwr >> 8;
+ }
+
+ /* OFDM TX power */
+ if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) {
+ for (i = 0; i < 14; i += 2) {
+ u16 txpwr;
+ eeprom_93cx6_read(&eeprom, 0x20 + (i >> 1), &txpwr);
+ priv->channels[i].hw_value |= (txpwr & 0xFF) << 8;
+ priv->channels[i + 1].hw_value |= txpwr & 0xFF00;
+ }
+ }
+
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180) {
+ __le32 anaparam;
+ eeprom_93cx6_multiread(&eeprom, 0xD, (__le16 *)&anaparam, 2);
+ priv->anaparam = le32_to_cpu(anaparam);
+ eeprom_93cx6_read(&eeprom, 0x19, &priv->rfparam);
+ }
+
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
+ eeprom_93cx6_read(&eeprom, 0x3F, &eeprom_val);
+ priv->antenna_diversity_en = !!(eeprom_val & 0x100);
+ priv->antenna_diversity_default = (eeprom_val & 0xC00) == 0x400;
+
+ eeprom_93cx6_read(&eeprom, 0x7C, &eeprom_val);
+ priv->xtal_out = eeprom_val & 0xF;
+ priv->xtal_in = (eeprom_val & 0xF0) >> 4;
+ priv->xtal_cal = !!(eeprom_val & 0x1000);
+ priv->thermal_meter_val = (eeprom_val & 0xF00) >> 8;
+ priv->thermal_meter_en = !!(eeprom_val & 0x2000);
+ }
+
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
+ RTL818X_EEPROM_CMD_NORMAL);
+}
+
static int rtl8180_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
@@ -907,12 +1663,9 @@ static int rtl8180_probe(struct pci_dev *pdev,
struct rtl8180_priv *priv;
unsigned long mem_addr, mem_len;
unsigned int io_addr, io_len;
- int err, i;
- struct eeprom_93cx6 eeprom;
+ int err;
const char *chip_name, *rf_name = NULL;
u32 reg;
- u16 eeprom_val;
- u8 mac_addr[ETH_ALEN];
err = pci_enable_device(pdev);
if (err) {
@@ -994,7 +1747,6 @@ static int rtl8180_probe(struct pci_dev *pdev,
dev->vif_data_size = sizeof(struct rtl8180_vif);
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
- dev->queues = 1;
dev->max_signal = 65;
reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
@@ -1002,43 +1754,55 @@ static int rtl8180_probe(struct pci_dev *pdev,
switch (reg) {
case RTL818X_TX_CONF_R8180_ABCD:
chip_name = "RTL8180";
+ priv->chip_family = RTL818X_CHIP_FAMILY_RTL8180;
break;
+
case RTL818X_TX_CONF_R8180_F:
chip_name = "RTL8180vF";
+ priv->chip_family = RTL818X_CHIP_FAMILY_RTL8180;
break;
+
case RTL818X_TX_CONF_R8185_ABC:
chip_name = "RTL8185";
+ priv->chip_family = RTL818X_CHIP_FAMILY_RTL8185;
break;
+
case RTL818X_TX_CONF_R8185_D:
chip_name = "RTL8185vD";
+ priv->chip_family = RTL818X_CHIP_FAMILY_RTL8185;
+ break;
+
+ case RTL818X_TX_CONF_RTL8187SE:
+ chip_name = "RTL8187SE";
+ priv->chip_family = RTL818X_CHIP_FAMILY_RTL8187SE;
break;
+
default:
printk(KERN_ERR "%s (rtl8180): Unknown chip! (0x%x)\n",
pci_name(pdev), reg >> 25);
goto err_iounmap;
}
- priv->r8185 = reg & RTL818X_TX_CONF_R8185_ABC;
- if (priv->r8185) {
+ /* we declare to MAC80211 all the queues except for beacon queue
+ * that will be eventually handled by DRV.
+ * TX rings are arranged in such a way that lower is the IDX,
+ * higher is the priority, in order to achieve direct mapping
+ * with mac80211, however the beacon queue is an exception and it
+ * is mapped on the highst tx ring IDX.
+ */
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE)
+ dev->queues = RTL8187SE_NR_TX_QUEUES - 1;
+ else
+ dev->queues = RTL8180_NR_TX_QUEUES - 1;
+
+ if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) {
priv->band.n_bitrates = ARRAY_SIZE(rtl818x_rates);
pci_try_set_mwi(pdev);
}
- eeprom.data = dev;
- eeprom.register_read = rtl8180_eeprom_register_read;
- eeprom.register_write = rtl8180_eeprom_register_write;
- if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6))
- eeprom.width = PCI_EEPROM_WIDTH_93C66;
- else
- eeprom.width = PCI_EEPROM_WIDTH_93C46;
-
- rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_PROGRAM);
- rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
- udelay(10);
+ rtl8180_eeprom_read(priv);
- eeprom_93cx6_read(&eeprom, 0x06, &eeprom_val);
- eeprom_val &= 0xFF;
- switch (eeprom_val) {
+ switch (priv->rf_type) {
case 1: rf_name = "Intersil";
break;
case 2: rf_name = "RFMD";
@@ -1049,14 +1813,18 @@ static int rtl8180_probe(struct pci_dev *pdev,
break;
case 5: priv->rf = &grf5101_rf_ops;
break;
- case 9: priv->rf = rtl8180_detect_rf(dev);
+ case 9:
+ if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE)
+ priv->rf = rtl8187se_detect_rf(dev);
+ else
+ priv->rf = rtl8180_detect_rf(dev);
break;
case 10:
rf_name = "RTL8255";
break;
default:
printk(KERN_ERR "%s (rtl8180): Unknown RF! (0x%x)\n",
- pci_name(pdev), eeprom_val);
+ pci_name(pdev), priv->rf_type);
goto err_iounmap;
}
@@ -1066,42 +1834,12 @@ static int rtl8180_probe(struct pci_dev *pdev,
goto err_iounmap;
}
- eeprom_93cx6_read(&eeprom, 0x17, &eeprom_val);
- priv->csthreshold = eeprom_val >> 8;
- if (!priv->r8185) {
- __le32 anaparam;
- eeprom_93cx6_multiread(&eeprom, 0xD, (__le16 *)&anaparam, 2);
- priv->anaparam = le32_to_cpu(anaparam);
- eeprom_93cx6_read(&eeprom, 0x19, &priv->rfparam);
- }
-
- eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *)mac_addr, 3);
- if (!is_valid_ether_addr(mac_addr)) {
+ if (!is_valid_ether_addr(priv->mac_addr)) {
printk(KERN_WARNING "%s (rtl8180): Invalid hwaddr! Using"
" randomly generated MAC addr\n", pci_name(pdev));
- eth_random_addr(mac_addr);
- }
- SET_IEEE80211_PERM_ADDR(dev, mac_addr);
-
- /* CCK TX power */
- for (i = 0; i < 14; i += 2) {
- u16 txpwr;
- eeprom_93cx6_read(&eeprom, 0x10 + (i >> 1), &txpwr);
- priv->channels[i].hw_value = txpwr & 0xFF;
- priv->channels[i + 1].hw_value = txpwr >> 8;
+ eth_random_addr(priv->mac_addr);
}
-
- /* OFDM TX power */
- if (priv->r8185) {
- for (i = 0; i < 14; i += 2) {
- u16 txpwr;
- eeprom_93cx6_read(&eeprom, 0x20 + (i >> 1), &txpwr);
- priv->channels[i].hw_value |= (txpwr & 0xFF) << 8;
- priv->channels[i + 1].hw_value |= txpwr & 0xFF00;
- }
- }
-
- rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+ SET_IEEE80211_PERM_ADDR(dev, priv->mac_addr);
spin_lock_init(&priv->lock);
@@ -1113,12 +1851,12 @@ static int rtl8180_probe(struct pci_dev *pdev,
}
wiphy_info(dev->wiphy, "hwaddr %pm, %s + %s\n",
- mac_addr, chip_name, priv->rf->name);
+ priv->mac_addr, chip_name, priv->rf->name);
return 0;
err_iounmap:
- iounmap(priv->map);
+ pci_iounmap(pdev, priv->map);
err_free_dev:
ieee80211_free_hw(dev);
diff --git a/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h b/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h
index 30523314da43..291a55970d1a 100644
--- a/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h
+++ b/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h
@@ -24,27 +24,64 @@
#define ANAPARAM_PWR1_SHIFT 20
#define ANAPARAM_PWR1_MASK (0x7F << ANAPARAM_PWR1_SHIFT)
+/* rtl8180/rtl8185 have 3 queue + beacon queue.
+ * mac80211 can use just one, + beacon = 2 tot.
+ */
+#define RTL8180_NR_TX_QUEUES 2
+
+/* rtl8187SE have 6 queues + beacon queues
+ * mac80211 can use 4 QoS data queue, + beacon = 5 tot
+ */
+#define RTL8187SE_NR_TX_QUEUES 5
+
+/* for array static allocation, it is the max of above */
+#define RTL818X_NR_TX_QUEUES 5
+
struct rtl8180_tx_desc {
__le32 flags;
__le16 rts_duration;
__le16 plcp_len;
__le32 tx_buf;
- __le32 frame_len;
+ union{
+ __le32 frame_len;
+ struct {
+ __le16 frame_len_se;
+ __le16 frame_duration;
+ } __packed;
+ } __packed;
__le32 next_tx_desc;
u8 cw;
u8 retry_limit;
u8 agc;
u8 flags2;
- u32 reserved[2];
+ /* rsvd for 8180/8185.
+ * valid for 8187se but we dont use it
+ */
+ u32 reserved;
+ /* all rsvd for 8180/8185 */
+ __le16 flags3;
+ __le16 frag_qsize;
+} __packed;
+
+struct rtl818x_rx_cmd_desc {
+ __le32 flags;
+ u32 reserved;
+ __le32 rx_buf;
} __packed;
struct rtl8180_rx_desc {
__le32 flags;
__le32 flags2;
- union {
- __le32 rx_buf;
- __le64 tsft;
- };
+ __le64 tsft;
+
+} __packed;
+
+struct rtl8187se_rx_desc {
+ __le32 flags;
+ __le64 tsft;
+ __le32 flags2;
+ __le32 flags3;
+ u32 reserved[3];
} __packed;
struct rtl8180_tx_ring {
@@ -71,28 +108,45 @@ struct rtl8180_priv {
/* rtl8180 driver specific */
spinlock_t lock;
- struct rtl8180_rx_desc *rx_ring;
+ void *rx_ring;
+ u8 rx_ring_sz;
dma_addr_t rx_ring_dma;
unsigned int rx_idx;
struct sk_buff *rx_buf[32];
- struct rtl8180_tx_ring tx_ring[4];
+ struct rtl8180_tx_ring tx_ring[RTL818X_NR_TX_QUEUES];
struct ieee80211_channel channels[14];
struct ieee80211_rate rates[12];
struct ieee80211_supported_band band;
+ struct ieee80211_tx_queue_params queue_param[4];
struct pci_dev *pdev;
u32 rx_conf;
-
- int r8185;
+ u8 slot_time;
+ u16 ack_time;
+
+ enum {
+ RTL818X_CHIP_FAMILY_RTL8180,
+ RTL818X_CHIP_FAMILY_RTL8185,
+ RTL818X_CHIP_FAMILY_RTL8187SE,
+ } chip_family;
u32 anaparam;
u16 rfparam;
u8 csthreshold;
-
+ u8 mac_addr[ETH_ALEN];
+ u8 rf_type;
+ u8 xtal_out;
+ u8 xtal_in;
+ u8 xtal_cal;
+ u8 thermal_meter_val;
+ u8 thermal_meter_en;
+ u8 antenna_diversity_en;
+ u8 antenna_diversity_default;
/* sequence # */
u16 seqno;
};
void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);
void rtl8180_set_anaparam(struct rtl8180_priv *priv, u32 anaparam);
+void rtl8180_set_anaparam2(struct rtl8180_priv *priv, u32 anaparam2);
static inline u8 rtl818x_ioread8(struct rtl8180_priv *priv, u8 __iomem *addr)
{
diff --git a/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c b/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c
index d60a5f399022..9bda5bc78eda 100644
--- a/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c
+++ b/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c
@@ -282,6 +282,7 @@ static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
msleep(1); /* FIXME: optional? */
+ /* TODO: use set_anaparam2 dev.c_func*/
/* anaparam2 on */
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
@@ -730,32 +731,11 @@ static void rtl8225_rf_set_channel(struct ieee80211_hw *dev,
msleep(10);
}
-static void rtl8225_rf_conf_erp(struct ieee80211_hw *dev,
- struct ieee80211_bss_conf *info)
-{
- struct rtl8180_priv *priv = dev->priv;
-
- if (info->use_short_slot) {
- rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9);
- rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
- rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14);
- rtl818x_iowrite8(priv, &priv->map->EIFS, 81);
- rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73);
- } else {
- rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14);
- rtl818x_iowrite8(priv, &priv->map->SIFS, 0x44);
- rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24);
- rtl818x_iowrite8(priv, &priv->map->EIFS, 81);
- rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5);
- }
-}
-
static const struct rtl818x_rf_ops rtl8225_ops = {
.name = "rtl8225",
.init = rtl8225_rf_init,
.stop = rtl8225_rf_stop,
.set_chan = rtl8225_rf_set_channel,
- .conf_erp = rtl8225_rf_conf_erp,
};
static const struct rtl818x_rf_ops rtl8225z2_ops = {
@@ -763,7 +743,6 @@ static const struct rtl818x_rf_ops rtl8225z2_ops = {
.init = rtl8225z2_rf_init,
.stop = rtl8225_rf_stop,
.set_chan = rtl8225_rf_set_channel,
- .conf_erp = rtl8225_rf_conf_erp,
};
const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *dev)
diff --git a/drivers/net/wireless/rtl818x/rtl8180/rtl8225se.c b/drivers/net/wireless/rtl818x/rtl8180/rtl8225se.c
new file mode 100644
index 000000000000..fde89866fa8d
--- /dev/null
+++ b/drivers/net/wireless/rtl818x/rtl8180/rtl8225se.c
@@ -0,0 +1,475 @@
+
+/* Radio tuning for RTL8225 on RTL8187SE
+ *
+ * Copyright 2009 Larry Finger <Larry.Finger@lwfinger.net>
+ * Copyright 2014 Andrea Merello <andrea.merello@gmail.com>
+ *
+ * Based on the r8180 and Realtek r8187se drivers, which are:
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
+ *
+ * Also based on the rtl8187 driver, which is:
+ * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007 Andrea Merello <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
+ * published by the Free Software Foundation.
+ */
+
+#include <net/mac80211.h>
+
+#include "rtl8180.h"
+#include "rtl8225se.h"
+
+#define PFX "rtl8225 (se) "
+
+static const u32 RF_GAIN_TABLE[] = {
+ 0x0096, 0x0076, 0x0056, 0x0036, 0x0016, 0x01f6, 0x01d6, 0x01b6,
+ 0x0196, 0x0176, 0x00F7, 0x00D7, 0x00B7, 0x0097, 0x0077, 0x0057,
+ 0x0037, 0x00FB, 0x00DB, 0x00BB, 0x00FF, 0x00E3, 0x00C3, 0x00A3,
+ 0x0083, 0x0063, 0x0043, 0x0023, 0x0003, 0x01E3, 0x01C3, 0x01A3,
+ 0x0183, 0x0163, 0x0143, 0x0123, 0x0103
+};
+
+static const u8 cck_ofdm_gain_settings[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
+ 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+ 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+};
+
+static const u8 rtl8225se_tx_gain_cck_ofdm[] = {
+ 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
+};
+
+static const u8 rtl8225se_tx_power_cck[] = {
+ 0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
+ 0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
+ 0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
+ 0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
+ 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
+ 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
+};
+
+static const u8 rtl8225se_tx_power_cck_ch14[] = {
+ 0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
+ 0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
+ 0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
+};
+
+static const u8 rtl8225se_tx_power_ofdm[] = {
+ 0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
+};
+
+static const u32 rtl8225se_chan[] = {
+ 0x0080, 0x0100, 0x0180, 0x0200, 0x0280, 0x0300, 0x0380,
+ 0x0400, 0x0480, 0x0500, 0x0580, 0x0600, 0x0680, 0x074A,
+};
+
+static const u8 rtl8225sez2_tx_power_cck_ch14[] = {
+ 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00
+};
+
+static const u8 rtl8225sez2_tx_power_cck_B[] = {
+ 0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x04
+};
+
+static const u8 rtl8225sez2_tx_power_cck_A[] = {
+ 0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04
+};
+
+static const u8 rtl8225sez2_tx_power_cck[] = {
+ 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04
+};
+
+static const u8 ZEBRA_AGC[] = {
+ 0x7E, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A,
+ 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72,
+ 0x71, 0x70, 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A,
+ 0x69, 0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62,
+ 0x48, 0x47, 0x46, 0x45, 0x44, 0x29, 0x28, 0x27,
+ 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x08, 0x07,
+ 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x15, 0x16,
+ 0x17, 0x17, 0x18, 0x18, 0x19, 0x1a, 0x1a, 0x1b,
+ 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e,
+ 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x21,
+ 0x21, 0x21, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24,
+ 0x24, 0x25, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
+ 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F
+};
+
+static const u8 OFDM_CONFIG[] = {
+ 0x10, 0x0F, 0x0A, 0x0C, 0x14, 0xFA, 0xFF, 0x50,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00,
+ 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xA8, 0x26,
+ 0x32, 0x33, 0x06, 0xA5, 0x6F, 0x55, 0xC8, 0xBB,
+ 0x0A, 0xE1, 0x2C, 0x4A, 0x86, 0x83, 0x34, 0x00,
+ 0x4F, 0x24, 0x6F, 0xC2, 0x03, 0x40, 0x80, 0x00,
+ 0xC0, 0xC1, 0x58, 0xF1, 0x00, 0xC4, 0x90, 0x3e,
+ 0xD8, 0x3C, 0x7B, 0x10, 0x10
+};
+
+static void rtl8187se_three_wire_io(struct ieee80211_hw *dev, u8 *data,
+ u8 len, bool write)
+{
+ struct rtl8180_priv *priv = dev->priv;
+ int i;
+ u8 tmp;
+
+ do {
+ for (i = 0; i < 5; i++) {
+ tmp = rtl818x_ioread8(priv, SW_3W_CMD1);
+ if (!(tmp & 0x3))
+ break;
+ udelay(10);
+ }
+ if (i == 5)
+ wiphy_err(dev->wiphy, PFX
+ "CmdReg: 0x%x RE/WE bits aren't clear\n", tmp);
+
+ tmp = rtl818x_ioread8(priv, &priv->map->rf_sw_config) | 0x02;
+ rtl818x_iowrite8(priv, &priv->map->rf_sw_config, tmp);
+
+ tmp = rtl818x_ioread8(priv, REG_ADDR1(0x84)) & 0xF7;
+ rtl818x_iowrite8(priv, REG_ADDR1(0x84), tmp);
+ if (write) {
+ if (len == 16) {
+ rtl818x_iowrite16(priv, SW_3W_DB0,
+ *(u16 *)data);
+ } else if (len == 64) {
+ rtl818x_iowrite32(priv, SW_3W_DB0_4,
+ *((u32 *)data));
+ rtl818x_iowrite32(priv, SW_3W_DB1_4,
+ *((u32 *)(data + 4)));
+ } else
+ wiphy_err(dev->wiphy, PFX
+ "Unimplemented length\n");
+ } else {
+ rtl818x_iowrite16(priv, SW_3W_DB0, *(u16 *)data);
+ }
+ if (write)
+ tmp = 2;
+ else
+ tmp = 1;
+ rtl818x_iowrite8(priv, SW_3W_CMD1, tmp);
+ for (i = 0; i < 5; i++) {
+ tmp = rtl818x_ioread8(priv, SW_3W_CMD1);
+ if (!(tmp & 0x3))
+ break;
+ udelay(10);
+ }
+ rtl818x_iowrite8(priv, SW_3W_CMD1, 0);
+ if (!write) {
+ *((u16 *)data) = rtl818x_ioread16(priv, SI_DATA_REG);
+ *((u16 *)data) &= 0x0FFF;
+ }
+ } while (0);
+}
+
+static u32 rtl8187se_rf_readreg(struct ieee80211_hw *dev, u8 addr)
+{
+ u32 dataread = addr & 0x0F;
+ rtl8187se_three_wire_io(dev, (u8 *)&dataread, 16, 0);
+ return dataread;
+}
+
+static void rtl8187se_rf_writereg(struct ieee80211_hw *dev, u8 addr, u32 data)
+{
+ u32 outdata = (data << 4) | (u32)(addr & 0x0F);
+ rtl8187se_three_wire_io(dev, (u8 *)&outdata, 16, 1);
+}
+
+
+static void rtl8225se_write_zebra_agc(struct ieee80211_hw *dev)
+{
+ int i;
+
+ for (i = 0; i < 128; i++) {
+ rtl8225se_write_phy_ofdm(dev, 0xF, ZEBRA_AGC[i]);
+ rtl8225se_write_phy_ofdm(dev, 0xE, i+0x80);
+ rtl8225se_write_phy_ofdm(dev, 0xE, 0);
+ }
+}
+
+static void rtl8187se_write_ofdm_config(struct ieee80211_hw *dev)
+{
+ /* write OFDM_CONFIG table */
+ int i;
+
+ for (i = 0; i < 60; i++)
+ rtl8225se_write_phy_ofdm(dev, i, OFDM_CONFIG[i]);
+
+}
+
+static void rtl8225sez2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
+{
+ struct rtl8180_priv *priv = dev->priv;
+ u8 cck_power, ofdm_power;
+
+ cck_power = priv->channels[channel - 1].hw_value & 0xFF;
+ if (cck_power > 35)
+ cck_power = 35;
+ rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
+ cck_ofdm_gain_settings[cck_power]);
+
+ usleep_range(1000, 5000);
+ ofdm_power = priv->channels[channel - 1].hw_value >> 8;
+ if (ofdm_power > 35)
+ ofdm_power = 35;
+
+ rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
+ cck_ofdm_gain_settings[ofdm_power]);
+ if (ofdm_power < 12) {
+ rtl8225se_write_phy_ofdm(dev, 7, 0x5C);
+ rtl8225se_write_phy_ofdm(dev, 9, 0x5C);
+ }
+ if (ofdm_power < 18) {
+ rtl8225se_write_phy_ofdm(dev, 7, 0x54);
+ rtl8225se_write_phy_ofdm(dev, 9, 0x54);
+ } else {
+ rtl8225se_write_phy_ofdm(dev, 7, 0x50);
+ rtl8225se_write_phy_ofdm(dev, 9, 0x50);
+ }
+
+ usleep_range(1000, 5000);
+}
+
+static void rtl8187se_write_rf_gain(struct ieee80211_hw *dev)
+{
+ int i;
+
+ for (i = 0; i <= 36; i++) {
+ rtl8187se_rf_writereg(dev, 0x01, i); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x02, RF_GAIN_TABLE[i]); mdelay(1);
+ }
+}
+
+static void rtl8187se_write_initial_gain(struct ieee80211_hw *dev,
+ int init_gain)
+{
+ switch (init_gain) {
+ default:
+ rtl8225se_write_phy_ofdm(dev, 0x17, 0x26); mdelay(1);
+ rtl8225se_write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
+ rtl8225se_write_phy_ofdm(dev, 0x05, 0xFA); mdelay(1);
+ break;
+ case 2:
+ rtl8225se_write_phy_ofdm(dev, 0x17, 0x36); mdelay(1);
+ rtl8225se_write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
+ rtl8225se_write_phy_ofdm(dev, 0x05, 0xFA); mdelay(1);
+ break;
+ case 3:
+ rtl8225se_write_phy_ofdm(dev, 0x17, 0x36); mdelay(1);
+ rtl8225se_write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
+ rtl8225se_write_phy_ofdm(dev, 0x05, 0xFB); mdelay(1);
+ break;
+ case 4:
+ rtl8225se_write_phy_ofdm(dev, 0x17, 0x46); mdelay(1);
+ rtl8225se_write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
+ rtl8225se_write_phy_ofdm(dev, 0x05, 0xFB); mdelay(1);
+ break;
+ case 5:
+ rtl8225se_write_phy_ofdm(dev, 0x17, 0x46); mdelay(1);
+ rtl8225se_write_phy_ofdm(dev, 0x24, 0x96); mdelay(1);
+ rtl8225se_write_phy_ofdm(dev, 0x05, 0xFB); mdelay(1);
+ break;
+ case 6:
+ rtl8225se_write_phy_ofdm(dev, 0x17, 0x56); mdelay(1);
+ rtl8225se_write_phy_ofdm(dev, 0x24, 0x96); mdelay(1);
+ rtl8225se_write_phy_ofdm(dev, 0x05, 0xFC); mdelay(1);
+ break;
+ case 7:
+ rtl8225se_write_phy_ofdm(dev, 0x17, 0x56); mdelay(1);
+ rtl8225se_write_phy_ofdm(dev, 0x24, 0xA6); mdelay(1);
+ rtl8225se_write_phy_ofdm(dev, 0x05, 0xFC); mdelay(1);
+ break;
+ case 8:
+ rtl8225se_write_phy_ofdm(dev, 0x17, 0x66); mdelay(1);
+ rtl8225se_write_phy_ofdm(dev, 0x24, 0xB6); mdelay(1);
+ rtl8225se_write_phy_ofdm(dev, 0x05, 0xFC); mdelay(1);
+ break;
+ }
+}
+
+void rtl8225se_rf_init(struct ieee80211_hw *dev)
+{
+ struct rtl8180_priv *priv = dev->priv;
+ u32 rf23, rf24;
+ u8 d_cut = 0;
+ u8 tmp;
+
+ /* Page 1 */
+ rtl8187se_rf_writereg(dev, 0x00, 0x013F); mdelay(1);
+ rf23 = rtl8187se_rf_readreg(dev, 0x08); mdelay(1);
+ rf24 = rtl8187se_rf_readreg(dev, 0x09); mdelay(1);
+ if (rf23 == 0x0818 && rf24 == 0x070C)
+ d_cut = 1;
+
+ wiphy_info(dev->wiphy, "RTL8225-SE version %s\n",
+ d_cut ? "D" : "not-D");
+
+ /* Page 0: reg 0 - 15 */
+ rtl8187se_rf_writereg(dev, 0x00, 0x009F); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x01, 0x06E0); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x02, 0x004D); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x03, 0x07F1); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x04, 0x0975); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x05, 0x0C72); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x06, 0x0AE6); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x07, 0x00CA); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x08, 0x0E1C); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x09, 0x02F0); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x0A, 0x09D0); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x0B, 0x01BA); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x0C, 0x0640); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x0D, 0x08DF); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x0E, 0x0020); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x0F, 0x0990); mdelay(1);
+ /* page 1: reg 16-30 */
+ rtl8187se_rf_writereg(dev, 0x00, 0x013F); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x03, 0x0806); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x04, 0x03A7); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x05, 0x059B); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x06, 0x0081); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x07, 0x01A0); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x0A, 0x0001); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x0B, 0x0418); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x0C, 0x0FBE); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x0D, 0x0008); mdelay(1);
+ if (d_cut)
+ rtl8187se_rf_writereg(dev, 0x0E, 0x0807);
+ else
+ rtl8187se_rf_writereg(dev, 0x0E, 0x0806);
+ mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x0F, 0x0ACC); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x00, 0x01D7); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x03, 0x0E00); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x04, 0x0E50); mdelay(1);
+
+ rtl8187se_write_rf_gain(dev);
+
+ rtl8187se_rf_writereg(dev, 0x05, 0x0203); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x06, 0x0200); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x00, 0x0137); mdelay(11);
+ rtl8187se_rf_writereg(dev, 0x0D, 0x0008); mdelay(11);
+ rtl8187se_rf_writereg(dev, 0x00, 0x0037); mdelay(11);
+ rtl8187se_rf_writereg(dev, 0x04, 0x0160); mdelay(11);
+ rtl8187se_rf_writereg(dev, 0x07, 0x0080); mdelay(11);
+ rtl8187se_rf_writereg(dev, 0x02, 0x088D); mdelay(221);
+ rtl8187se_rf_writereg(dev, 0x00, 0x0137); mdelay(11);
+ rtl8187se_rf_writereg(dev, 0x07, 0x0000); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x07, 0x0180); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x07, 0x0220); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x07, 0x03E0); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x06, 0x00C1); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x0A, 0x0001); mdelay(1);
+ if (priv->xtal_cal) {
+ tmp = (priv->xtal_in << 4) | (priv->xtal_out << 1) |
+ (1 << 11) | (1 << 9);
+ rtl8187se_rf_writereg(dev, 0x0F, tmp);
+ wiphy_info(dev->wiphy, "Xtal cal\n");
+ mdelay(1);
+ } else {
+ wiphy_info(dev->wiphy, "NO Xtal cal\n");
+ rtl8187se_rf_writereg(dev, 0x0F, 0x0ACC);
+ mdelay(1);
+ }
+ /* page 0 */
+ rtl8187se_rf_writereg(dev, 0x00, 0x00BF); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x0D, 0x08DF); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x02, 0x004D); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x04, 0x0975); mdelay(31);
+ rtl8187se_rf_writereg(dev, 0x00, 0x0197); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x05, 0x05AB); mdelay(1);
+
+ rtl8187se_rf_writereg(dev, 0x00, 0x009F); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x01, 0x0000); mdelay(1);
+ rtl8187se_rf_writereg(dev, 0x02, 0x0000); mdelay(1);
+ /* power save parameters */
+ /* TODO: move to dev.c */
+ rtl818x_iowrite8(priv, REG_ADDR1(0x024E),
+ rtl818x_ioread8(priv, REG_ADDR1(0x24E)) & 0x9F);
+ rtl8225se_write_phy_cck(dev, 0x00, 0xC8);
+ rtl8225se_write_phy_cck(dev, 0x06, 0x1C);
+ rtl8225se_write_phy_cck(dev, 0x10, 0x78);
+ rtl8225se_write_phy_cck(dev, 0x2E, 0xD0);
+ rtl8225se_write_phy_cck(dev, 0x2F, 0x06);
+ rtl8225se_write_phy_cck(dev, 0x01, 0x46);
+
+ /* power control */
+ rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, 0x10);
+ rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, 0x1B);
+
+ rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);
+ rtl8225se_write_phy_ofdm(dev, 0x00, 0x12);
+
+ rtl8225se_write_zebra_agc(dev);
+
+ rtl8225se_write_phy_ofdm(dev, 0x10, 0x00);
+
+ rtl8187se_write_ofdm_config(dev);
+
+ /* turn on RF */
+ rtl8187se_rf_writereg(dev, 0x00, 0x009F); udelay(500);
+ rtl8187se_rf_writereg(dev, 0x04, 0x0972); udelay(500);
+ /* turn on RF again */
+ rtl8187se_rf_writereg(dev, 0x00, 0x009F); udelay(500);
+ rtl8187se_rf_writereg(dev, 0x04, 0x0972); udelay(500);
+ /* turn on BB */
+ rtl8225se_write_phy_ofdm(dev, 0x10, 0x40);
+ rtl8225se_write_phy_ofdm(dev, 0x12, 0x40);
+
+ rtl8187se_write_initial_gain(dev, 4);
+}
+
+void rtl8225se_rf_stop(struct ieee80211_hw *dev)
+{
+ /* checked for 8187se */
+ struct rtl8180_priv *priv = dev->priv;
+
+ /* turn off BB RXIQ matrix to cut off rx signal */
+ rtl8225se_write_phy_ofdm(dev, 0x10, 0x00);
+ rtl8225se_write_phy_ofdm(dev, 0x12, 0x00);
+ /* turn off RF */
+ rtl8187se_rf_writereg(dev, 0x04, 0x0000);
+ rtl8187se_rf_writereg(dev, 0x00, 0x0000);
+
+ usleep_range(1000, 5000);
+ /* turn off A/D and D/A */
+ rtl8180_set_anaparam(priv, RTL8225SE_ANAPARAM_OFF);
+ rtl8180_set_anaparam2(priv, RTL8225SE_ANAPARAM2_OFF);
+}
+
+void rtl8225se_rf_set_channel(struct ieee80211_hw *dev,
+ struct ieee80211_conf *conf)
+{
+ int chan =
+ ieee80211_frequency_to_channel(conf->chandef.chan->center_freq);
+
+ rtl8225sez2_rf_set_tx_power(dev, chan);
+ rtl8187se_rf_writereg(dev, 0x7, rtl8225se_chan[chan - 1]);
+ if ((rtl8187se_rf_readreg(dev, 0x7) & 0x0F80) !=
+ rtl8225se_chan[chan - 1])
+ rtl8187se_rf_writereg(dev, 0x7, rtl8225se_chan[chan - 1]);
+ usleep_range(10000, 20000);
+}
+
+static const struct rtl818x_rf_ops rtl8225se_ops = {
+ .name = "rtl8225-se",
+ .init = rtl8225se_rf_init,
+ .stop = rtl8225se_rf_stop,
+ .set_chan = rtl8225se_rf_set_channel,
+};
+
+const struct rtl818x_rf_ops *rtl8187se_detect_rf(struct ieee80211_hw *dev)
+{
+ return &rtl8225se_ops;
+}
diff --git a/drivers/net/wireless/rtl818x/rtl8180/rtl8225se.h b/drivers/net/wireless/rtl818x/rtl8180/rtl8225se.h
new file mode 100644
index 000000000000..229400264088
--- /dev/null
+++ b/drivers/net/wireless/rtl818x/rtl8180/rtl8225se.h
@@ -0,0 +1,61 @@
+
+/* Definitions for RTL8187SE hardware
+ *
+ * Copyright 2009 Larry Finger <Larry.Finger@lwfinger.net>
+ * Copyright 2014 Andrea Merello <andrea.merello@gmail.com>
+ *
+ * Based on the r8180 and Realtek r8187se drivers, which are:
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
+ *
+ * Also based on the rtl8187 driver, which is:
+ * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007 Andrea Merello <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
+ * published by the Free Software Foundation.
+ */
+
+#ifndef RTL8187SE_RTL8225_H
+#define RTL8187SE_RTL8225_H
+
+#define RTL8225SE_ANAPARAM_ON 0xb0054d00
+#define RTL8225SE_ANAPARAM2_ON 0x000004c6
+
+/* all off except PLL */
+#define RTL8225SE_ANAPARAM_OFF 0xb0054dec
+/* all on including PLL */
+#define RTL8225SE_ANAPARAM_OFF2 0xb0054dfc
+
+#define RTL8225SE_ANAPARAM2_OFF 0x00ff04c6
+
+#define RTL8225SE_ANAPARAM3 0x10
+
+enum rtl8187se_power_state {
+ RTL8187SE_POWER_ON,
+ RTL8187SE_POWER_OFF,
+ RTL8187SE_POWER_SLEEP
+};
+
+static inline void rtl8225se_write_phy_ofdm(struct ieee80211_hw *dev,
+ u8 addr, u8 data)
+{
+ rtl8180_write_phy(dev, addr, data);
+}
+
+static inline void rtl8225se_write_phy_cck(struct ieee80211_hw *dev,
+ u8 addr, u8 data)
+{
+ rtl8180_write_phy(dev, addr, data | 0x10000);
+}
+
+
+const struct rtl818x_rf_ops *rtl8187se_detect_rf(struct ieee80211_hw *);
+void rtl8225se_rf_stop(struct ieee80211_hw *dev);
+void rtl8225se_rf_set_channel(struct ieee80211_hw *dev,
+ struct ieee80211_conf *conf);
+void rtl8225se_rf_conf_erp(struct ieee80211_hw *dev,
+ struct ieee80211_bss_conf *info);
+void rtl8225se_rf_init(struct ieee80211_hw *dev);
+
+#endif /* RTL8187SE_RTL8225_H */
diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c
index fd78df813a85..0ca17cda48fa 100644
--- a/drivers/net/wireless/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c
@@ -592,7 +592,7 @@ static void rtl8187_set_anaparam(struct rtl8187_priv *priv, bool rfon)
rtl818x_iowrite32(priv, &priv->map->ANAPARAM, anaparam);
rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, anaparam2);
if (priv->is_rtl8187b)
- rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, anaparam3);
+ rtl818x_iowrite8(priv, &priv->map->ANAPARAM3A, anaparam3);
reg &= ~RTL818X_CONFIG3_ANAPARAM_WRITE;
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg);
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
@@ -785,7 +785,7 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev)
rtl818x_iowrite16(priv, (__le16 *)0xFF34, 0x0FFF);
reg = rtl818x_ioread8(priv, &priv->map->CW_CONF);
- reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT;
+ reg |= RTL818X_CW_CONF_PERPACKET_RETRY;
rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg);
/* Auto Rate Fallback Register (ARFR): 1M-54M setting */
@@ -943,8 +943,8 @@ static int rtl8187_start(struct ieee80211_hw *dev)
rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg);
reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL);
- reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT;
- reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT;
+ reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN;
+ reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL;
reg &= ~RTL818X_TX_AGC_CTL_FEEDBACK_ANT;
rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg);
@@ -986,13 +986,13 @@ static int rtl8187_start(struct ieee80211_hw *dev)
rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg);
reg = rtl818x_ioread8(priv, &priv->map->CW_CONF);
- reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT;
- reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT;
+ reg &= ~RTL818X_CW_CONF_PERPACKET_CW;
+ reg |= RTL818X_CW_CONF_PERPACKET_RETRY;
rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg);
reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL);
- reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT;
- reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT;
+ reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN;
+ reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL;
reg &= ~RTL818X_TX_AGC_CTL_FEEDBACK_ANT;
rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg);
@@ -1636,10 +1636,10 @@ static int rtl8187_probe(struct usb_interface *intf,
err_free_dmabuf:
kfree(priv->io_dmabuf);
- err_free_dev:
- ieee80211_free_hw(dev);
usb_set_intfdata(intf, NULL);
usb_put_dev(udev);
+ err_free_dev:
+ ieee80211_free_hw(dev);
return err;
}
diff --git a/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h
index 56aee067f324..a6ad79f61bf9 100644
--- a/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h
+++ b/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h
@@ -15,6 +15,8 @@
#ifndef RTL8187_H
#define RTL8187_H
+#include <linux/cache.h>
+
#include "rtl818x.h"
#include "leds.h"
@@ -139,7 +141,10 @@ struct rtl8187_priv {
u8 aifsn[4];
u8 rfkill_mask;
struct {
- __le64 buf;
+ union {
+ __le64 buf;
+ u8 dummy1[L1_CACHE_BYTES];
+ } ____cacheline_aligned;
struct sk_buff_head queue;
} b_tx_status; /* This queue is used by both -b and non-b devices */
struct mutex io_mutex;
@@ -147,7 +152,8 @@ struct rtl8187_priv {
u8 bits8;
__le16 bits16;
__le32 bits32;
- } *io_dmabuf;
+ u8 dummy2[L1_CACHE_BYTES];
+ } *io_dmabuf ____cacheline_aligned;
bool rfkill_off;
u16 seqno;
};
diff --git a/drivers/net/wireless/rtl818x/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h
index ce23dfd42381..45ea4e1c4abe 100644
--- a/drivers/net/wireless/rtl818x/rtl818x.h
+++ b/drivers/net/wireless/rtl818x/rtl818x.h
@@ -16,30 +16,82 @@
#define RTL818X_H
struct rtl818x_csr {
+
u8 MAC[6];
u8 reserved_0[2];
- __le32 MAR[2];
- u8 RX_FIFO_COUNT;
- u8 reserved_1;
- u8 TX_FIFO_COUNT;
- u8 BQREQ;
- u8 reserved_2[4];
+
+ union {
+ __le32 MAR[2]; /* 0x8 */
+
+ struct{ /* rtl8187se */
+ u8 rf_sw_config; /* 0x8 */
+ u8 reserved_01[3];
+ __le32 TMGDA; /* 0xc */
+ } __packed;
+ } __packed;
+
+ union { /* 0x10 */
+ struct {
+ u8 RX_FIFO_COUNT;
+ u8 reserved_1;
+ u8 TX_FIFO_COUNT;
+ u8 BQREQ;
+ } __packed;
+
+ __le32 TBKDA; /* for 8187se */
+ } __packed;
+
+ __le32 TBEDA; /* 0x14 - for rtl8187se */
+
__le32 TSFT[2];
- __le32 TLPDA;
- __le32 TNPDA;
- __le32 THPDA;
- __le16 BRSR;
- u8 BSSID[6];
- u8 RESP_RATE;
- u8 EIFS;
- u8 reserved_3[1];
- u8 CMD;
+
+ union { /* 0x20 */
+ __le32 TLPDA;
+ __le32 TVIDA; /* for 8187se */
+ } __packed;
+
+ union { /* 0x24 */
+ __le32 TNPDA;
+ __le32 TVODA; /* for 8187se */
+ } __packed;
+
+ /* hi pri ring for all cards */
+ __le32 THPDA; /* 0x28 */
+
+ union { /* 0x2c */
+ struct {
+ u8 reserved_2a;
+ u8 EIFS_8187SE;
+ } __packed;
+
+ __le16 BRSR;
+ } __packed;
+
+ u8 BSSID[6]; /* 0x2e */
+
+ union { /* 0x34 */
+ struct {
+ u8 RESP_RATE;
+ u8 EIFS;
+ } __packed;
+ __le16 BRSR_8187SE;
+ } __packed;
+
+ u8 reserved_3[1]; /* 0x36 */
+ u8 CMD; /* 0x37 */
#define RTL818X_CMD_TX_ENABLE (1 << 2)
#define RTL818X_CMD_RX_ENABLE (1 << 3)
#define RTL818X_CMD_RESET (1 << 4)
- u8 reserved_4[4];
- __le16 INT_MASK;
- __le16 INT_STATUS;
+ u8 reserved_4[4]; /* 0x38 */
+ union {
+ struct {
+ __le16 INT_MASK;
+ __le16 INT_STATUS;
+ } __packed;
+
+ __le32 INT_STATUS_SE; /* 0x3c */
+ } __packed;
+/* status bits for rtl8187 and rtl8180/8185 */
#define RTL818X_INT_RX_OK (1 << 0)
#define RTL818X_INT_RX_ERR (1 << 1)
#define RTL818X_INT_TXL_OK (1 << 2)
@@ -56,7 +108,34 @@ struct rtl818x_csr {
#define RTL818X_INT_BEACON (1 << 13)
#define RTL818X_INT_TIME_OUT (1 << 14)
#define RTL818X_INT_TX_FO (1 << 15)
- __le32 TX_CONF;
+/* status bits for rtl8187se */
+#define RTL818X_INT_SE_TIMER3 (1 << 0)
+#define RTL818X_INT_SE_TIMER2 (1 << 1)
+#define RTL818X_INT_SE_RQ0SOR (1 << 2)
+#define RTL818X_INT_SE_TXBED_OK (1 << 3)
+#define RTL818X_INT_SE_TXBED_ERR (1 << 4)
+#define RTL818X_INT_SE_TXBE_OK (1 << 5)
+#define RTL818X_INT_SE_TXBE_ERR (1 << 6)
+#define RTL818X_INT_SE_RX_OK (1 << 7)
+#define RTL818X_INT_SE_RX_ERR (1 << 8)
+#define RTL818X_INT_SE_TXL_OK (1 << 9)
+#define RTL818X_INT_SE_TXL_ERR (1 << 10)
+#define RTL818X_INT_SE_RX_DU (1 << 11)
+#define RTL818X_INT_SE_RX_FIFO (1 << 12)
+#define RTL818X_INT_SE_TXN_OK (1 << 13)
+#define RTL818X_INT_SE_TXN_ERR (1 << 14)
+#define RTL818X_INT_SE_TXH_OK (1 << 15)
+#define RTL818X_INT_SE_TXH_ERR (1 << 16)
+#define RTL818X_INT_SE_TXB_OK (1 << 17)
+#define RTL818X_INT_SE_TXB_ERR (1 << 18)
+#define RTL818X_INT_SE_ATIM_TO (1 << 19)
+#define RTL818X_INT_SE_BK_TO (1 << 20)
+#define RTL818X_INT_SE_TIMER1 (1 << 21)
+#define RTL818X_INT_SE_TX_FIFO (1 << 22)
+#define RTL818X_INT_SE_WAKEUP (1 << 23)
+#define RTL818X_INT_SE_BK_DMA (1 << 24)
+#define RTL818X_INT_SE_TMGD_OK (1 << 30)
+ __le32 TX_CONF; /* 0x40 */
#define RTL818X_TX_CONF_LOOPBACK_MAC (1 << 17)
#define RTL818X_TX_CONF_LOOPBACK_CONT (3 << 17)
#define RTL818X_TX_CONF_NO_ICV (1 << 19)
@@ -68,6 +147,7 @@ struct rtl818x_csr {
#define RTL818X_TX_CONF_R8185_D (5 << 25)
#define RTL818X_TX_CONF_R8187vD (5 << 25)
#define RTL818X_TX_CONF_R8187vD_B (6 << 25)
+#define RTL818X_TX_CONF_RTL8187SE (6 << 25)
#define RTL818X_TX_CONF_HWVER_MASK (7 << 25)
#define RTL818X_TX_CONF_DISREQQSIZE (1 << 28)
#define RTL818X_TX_CONF_PROBE_DTS (1 << 29)
@@ -122,31 +202,67 @@ struct rtl818x_csr {
u8 PGSELECT;
u8 SECURITY;
__le32 ANAPARAM2;
- u8 reserved_10[12];
- __le16 BEACON_INTERVAL;
- __le16 ATIM_WND;
- __le16 BEACON_INTERVAL_TIME;
- __le16 ATIMTR_INTERVAL;
- u8 PHY_DELAY;
- u8 CARRIER_SENSE_COUNTER;
- u8 reserved_11[2];
- u8 PHY[4];
- __le16 RFPinsOutput;
- __le16 RFPinsEnable;
- __le16 RFPinsSelect;
- __le16 RFPinsInput;
- __le32 RF_PARA;
- __le32 RF_TIMING;
- u8 GP_ENABLE;
- u8 GPIO0;
- u8 GPIO1;
- u8 reserved_12;
- __le32 HSSI_PARA;
- u8 reserved_13[4];
- u8 TX_AGC_CTL;
-#define RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT (1 << 0)
-#define RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT (1 << 1)
-#define RTL818X_TX_AGC_CTL_FEEDBACK_ANT (1 << 2)
+ u8 reserved_10[8];
+ __le32 IMR; /* 0x6c - Interrupt mask reg for 8187se */
+#define IMR_TMGDOK ((1 << 30))
+#define IMR_DOT11HINT ((1 << 25)) /* 802.11h Measurement Interrupt */
+#define IMR_BCNDMAINT ((1 << 24)) /* Beacon DMA Interrupt */
+#define IMR_WAKEINT ((1 << 23)) /* Wake Up Interrupt */
+#define IMR_TXFOVW ((1 << 22)) /* Tx FIFO Overflow */
+#define IMR_TIMEOUT1 ((1 << 21)) /* Time Out Interrupt 1 */
+#define IMR_BCNINT ((1 << 20)) /* Beacon Time out */
+#define IMR_ATIMINT ((1 << 19)) /* ATIM Time Out */
+#define IMR_TBDER ((1 << 18)) /* Tx Beacon Descriptor Error */
+#define IMR_TBDOK ((1 << 17)) /* Tx Beacon Descriptor OK */
+#define IMR_THPDER ((1 << 16)) /* Tx High Priority Descriptor Error */
+#define IMR_THPDOK ((1 << 15)) /* Tx High Priority Descriptor OK */
+#define IMR_TVODER ((1 << 14)) /* Tx AC_VO Descriptor Error Int */
+#define IMR_TVODOK ((1 << 13)) /* Tx AC_VO Descriptor OK Interrupt */
+#define IMR_FOVW ((1 << 12)) /* Rx FIFO Overflow Interrupt */
+#define IMR_RDU ((1 << 11)) /* Rx Descriptor Unavailable */
+#define IMR_TVIDER ((1 << 10)) /* Tx AC_VI Descriptor Error */
+#define IMR_TVIDOK ((1 << 9)) /* Tx AC_VI Descriptor OK Interrupt */
+#define IMR_RER ((1 << 8)) /* Rx Error Interrupt */
+#define IMR_ROK ((1 << 7)) /* Receive OK Interrupt */
+#define IMR_TBEDER ((1 << 6)) /* Tx AC_BE Descriptor Error */
+#define IMR_TBEDOK ((1 << 5)) /* Tx AC_BE Descriptor OK */
+#define IMR_TBKDER ((1 << 4)) /* Tx AC_BK Descriptor Error */
+#define IMR_TBKDOK ((1 << 3)) /* Tx AC_BK Descriptor OK */
+#define IMR_RQOSOK ((1 << 2)) /* Rx QoS OK Interrupt */
+#define IMR_TIMEOUT2 ((1 << 1)) /* Time Out Interrupt 2 */
+#define IMR_TIMEOUT3 ((1 << 0)) /* Time Out Interrupt 3 */
+ __le16 BEACON_INTERVAL; /* 0x70 */
+ __le16 ATIM_WND; /* 0x72 */
+ __le16 BEACON_INTERVAL_TIME; /* 0x74 */
+ __le16 ATIMTR_INTERVAL; /* 0x76 */
+ u8 PHY_DELAY; /* 0x78 */
+ u8 CARRIER_SENSE_COUNTER; /* 0x79 */
+ u8 reserved_11[2]; /* 0x7a */
+ u8 PHY[4]; /* 0x7c */
+ __le16 RFPinsOutput; /* 0x80 */
+ __le16 RFPinsEnable; /* 0x82 */
+ __le16 RFPinsSelect; /* 0x84 */
+ __le16 RFPinsInput; /* 0x86 */
+ __le32 RF_PARA; /* 0x88 */
+ __le32 RF_TIMING; /* 0x8c */
+ u8 GP_ENABLE; /* 0x90 */
+ u8 GPIO0; /* 0x91 */
+ u8 GPIO1; /* 0x92 */
+ u8 TPPOLL_STOP; /* 0x93 - rtl8187se only */
+#define RTL818x_TPPOLL_STOP_BQ (1 << 7)
+#define RTL818x_TPPOLL_STOP_VI (1 << 4)
+#define RTL818x_TPPOLL_STOP_VO (1 << 5)
+#define RTL818x_TPPOLL_STOP_BE (1 << 3)
+#define RTL818x_TPPOLL_STOP_BK (1 << 2)
+#define RTL818x_TPPOLL_STOP_MG (1 << 1)
+#define RTL818x_TPPOLL_STOP_HI (1 << 6)
+
+ __le32 HSSI_PARA; /* 0x94 */
+ u8 reserved_13[4]; /* 0x98 */
+ u8 TX_AGC_CTL; /* 0x9c */
+#define RTL818X_TX_AGC_CTL_PERPACKET_GAIN (1 << 0)
+#define RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL (1 << 1)
+#define RTL818X_TX_AGC_CTL_FEEDBACK_ANT (1 << 2)
u8 TX_GAIN_CCK;
u8 TX_GAIN_OFDM;
u8 TX_ANTENNA;
@@ -158,8 +274,8 @@ struct rtl818x_csr {
u8 SLOT;
u8 reserved_16[5];
u8 CW_CONF;
-#define RTL818X_CW_CONF_PERPACKET_CW_SHIFT (1 << 0)
-#define RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT (1 << 1)
+#define RTL818X_CW_CONF_PERPACKET_CW (1 << 0)
+#define RTL818X_CW_CONF_PERPACKET_RETRY (1 << 1)
u8 CW_VAL;
u8 RATE_FALLBACK;
#define RTL818X_RATE_FALLBACK_ENABLE (1 << 7)
@@ -167,7 +283,8 @@ struct rtl818x_csr {
u8 reserved_17[24];
u8 CONFIG5;
u8 TX_DMA_POLLING;
- u8 reserved_18[2];
+ u8 PHY_PR;
+ u8 reserved_18;
__le16 CWR;
u8 RETRY_CTR;
u8 reserved_19[3];
@@ -179,20 +296,64 @@ struct rtl818x_csr {
__le32 RDSAR;
__le16 TID_AC_MAP;
u8 reserved_20[4];
- u8 ANAPARAM3;
- u8 reserved_21[5];
- __le16 FEMR;
- u8 reserved_22[4];
- __le16 TALLY_CNT;
- u8 TALLY_SEL;
+ union {
+ __le16 ANAPARAM3; /* 0xee */
+ u8 ANAPARAM3A; /* for rtl8187 */
+ };
+
+#define AC_PARAM_TXOP_LIMIT_SHIFT 16
+#define AC_PARAM_ECW_MAX_SHIFT 12
+#define AC_PARAM_ECW_MIN_SHIFT 8
+#define AC_PARAM_AIFS_SHIFT 0
+
+ __le32 AC_VO_PARAM; /* 0xf0 */
+
+ union { /* 0xf4 */
+ __le32 AC_VI_PARAM;
+ __le16 FEMR;
+ } __packed;
+
+ union{ /* 0xf8 */
+ __le32 AC_BE_PARAM; /* rtl8187se */
+ struct{
+ u8 reserved_21[2];
+ __le16 TALLY_CNT; /* 0xfa */
+ } __packed;
+ } __packed;
+
+ union {
+ u8 TALLY_SEL; /* 0xfc */
+ __le32 AC_BK_PARAM;
+
+ } __packed;
+
} __packed;
+/* These are addresses with NON-standard usage.
+ * They have offsets very far from this struct.
+ * I don't like to introduce a ton of "reserved"..
+ * They are for RTL8187SE
+ */
+#define REG_ADDR1(addr) ((u8 __iomem *)priv->map + addr)
+#define REG_ADDR2(addr) ((__le16 __iomem *)priv->map + (addr >> 1))
+#define REG_ADDR4(addr) ((__le32 __iomem *)priv->map + (addr >> 2))
+
+#define FEMR_SE REG_ADDR2(0x1D4)
+#define ARFR REG_ADDR2(0x1E0)
+#define RFSW_CTRL REG_ADDR2(0x272)
+#define SW_3W_DB0 REG_ADDR2(0x274)
+#define SW_3W_DB0_4 REG_ADDR4(0x274)
+#define SW_3W_DB1 REG_ADDR2(0x278)
+#define SW_3W_DB1_4 REG_ADDR4(0x278)
+#define SW_3W_CMD1 REG_ADDR1(0x27D)
+#define PI_DATA_REG REG_ADDR2(0x360)
+#define SI_DATA_REG REG_ADDR2(0x362)
+
struct rtl818x_rf_ops {
char *name;
void (*init)(struct ieee80211_hw *);
void (*stop)(struct ieee80211_hw *);
void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *);
- void (*conf_erp)(struct ieee80211_hw *, struct ieee80211_bss_conf *);
u8 (*calc_rssi)(u8 agc, u8 sq);
};
diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig
index c2ffce7a907c..bf3cf124e4ea 100644
--- a/drivers/net/wireless/rtlwifi/Kconfig
+++ b/drivers/net/wireless/rtlwifi/Kconfig
@@ -5,7 +5,7 @@ menuconfig RTL_CARDS
---help---
This option will enable support for the Realtek mac80211-based
wireless drivers. Drivers rtl8192ce, rtl8192cu, rtl8192se, rtl8192de,
- rtl8723eu, and rtl8188eu share some common code.
+ rtl8723ae, rtl8723be, and rtl8188ae share some common code.
if RTL_CARDS
@@ -48,12 +48,27 @@ config RTL8723AE
depends on PCI
select RTLWIFI
select RTLWIFI_PCI
+ select RTL8723_COMMON
+ select RTLBTCOEXIST
---help---
This is the driver for Realtek RTL8723AE 802.11n PCIe
wireless network adapters.
If you choose to build it as a module, it will be called rtl8723ae
+config RTL8723BE
+ tristate "Realtek RTL8723BE PCIe Wireless Network Adapter"
+ depends on PCI
+ select RTLWIFI
+ select RTLWIFI_PCI
+ select RTL8723_COMMON
+ select RTLBTCOEXIST
+ ---help---
+ This is the driver for Realtek RTL8723BE 802.11n PCIe
+ wireless network adapters.
+
+ If you choose to build it as a module, it will be called rtl8723be
+
config RTL8188EE
tristate "Realtek RTL8188EE Wireless Network Adapter"
depends on PCI
@@ -101,4 +116,14 @@ config RTL8192C_COMMON
depends on RTL8192CE || RTL8192CU
default y
+config RTL8723_COMMON
+ tristate
+ depends on RTL8723AE || RTL8723BE
+ default y
+
+config RTLBTCOEXIST
+ tristate
+ depends on RTL8723AE || RTL8723BE
+ default y
+
endif
diff --git a/drivers/net/wireless/rtlwifi/Makefile b/drivers/net/wireless/rtlwifi/Makefile
index d56f023a4b90..bba36a06abcc 100644
--- a/drivers/net/wireless/rtlwifi/Makefile
+++ b/drivers/net/wireless/rtlwifi/Makefile
@@ -24,6 +24,9 @@ obj-$(CONFIG_RTL8192CU) += rtl8192cu/
obj-$(CONFIG_RTL8192SE) += rtl8192se/
obj-$(CONFIG_RTL8192DE) += rtl8192de/
obj-$(CONFIG_RTL8723AE) += rtl8723ae/
+obj-$(CONFIG_RTL8723BE) += rtl8723be/
obj-$(CONFIG_RTL8188EE) += rtl8188ee/
+obj-$(CONFIG_RTLBTCOEXIST) += btcoexist/
+obj-$(CONFIG_RTL8723_COMMON) += rtl8723com/
ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/Makefile b/drivers/net/wireless/rtlwifi/btcoexist/Makefile
new file mode 100644
index 000000000000..47ceecfcb7dc
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/Makefile
@@ -0,0 +1,7 @@
+btcoexist-objs := halbtc8723b2ant.o \
+ halbtcoutsrc.o \
+ rtl_btc.o
+
+obj-$(CONFIG_RTLBTCOEXIST) += btcoexist.o
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h b/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h
new file mode 100644
index 000000000000..d76684eb24d0
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h
@@ -0,0 +1,75 @@
+/******************************************************************************
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ ******************************************************************************/
+
+#ifndef __HALBT_PRECOMP_H__
+#define __HALBT_PRECOMP_H__
+/*************************************************************
+ * include files
+ *************************************************************/
+#include "../wifi.h"
+#include "../efuse.h"
+#include "../base.h"
+#include "../regd.h"
+#include "../cam.h"
+#include "../ps.h"
+#include "../pci.h"
+
+#include "halbtcoutsrc.h"
+
+#include "halbtc8723b2ant.h"
+
+#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
+
+#endif /* __HALBT_PRECOMP_H__ */
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c
new file mode 100644
index 000000000000..d916ab9f3c38
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c
@@ -0,0 +1,3698 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+/***************************************************************
+ * Description:
+ *
+ * This file is for RTL8723B Co-exist mechanism
+ *
+ * History
+ * 2012/11/15 Cosa first check in.
+ *
+ **************************************************************/
+/**************************************************************
+ * include files
+ **************************************************************/
+#include "halbt_precomp.h"
+/**************************************************************
+ * Global variables, these are static variables
+ **************************************************************/
+static struct coex_dm_8723b_2ant glcoex_dm_8723b_2ant;
+static struct coex_dm_8723b_2ant *coex_dm = &glcoex_dm_8723b_2ant;
+static struct coex_sta_8723b_2ant glcoex_sta_8723b_2ant;
+static struct coex_sta_8723b_2ant *coex_sta = &glcoex_sta_8723b_2ant;
+
+static const char *const glbt_info_src_8723b_2ant[] = {
+ "BT Info[wifi fw]",
+ "BT Info[bt rsp]",
+ "BT Info[bt auto report]",
+};
+
+static u32 glcoex_ver_date_8723b_2ant = 20130731;
+static u32 glcoex_ver_8723b_2ant = 0x3b;
+
+/**************************************************************
+ * local function proto type if needed
+ **************************************************************/
+/**************************************************************
+ * local function start with btc8723b2ant_
+ **************************************************************/
+static u8 btc8723b2ant_bt_rssi_state(u8 level_num, u8 rssi_thresh,
+ u8 rssi_thresh1)
+{
+ s32 bt_rssi = 0;
+ u8 bt_rssi_state = coex_sta->pre_bt_rssi_state;
+
+ bt_rssi = coex_sta->bt_rssi;
+
+ if (level_num == 2) {
+ if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ if (bt_rssi >= rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) {
+ bt_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state "
+ "switch to High\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state "
+ "stay at Low\n");
+ }
+ } else {
+ if (bt_rssi < rssi_thresh) {
+ bt_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state "
+ "switch to Low\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state "
+ "stay at High\n");
+ }
+ }
+ } else if (level_num == 3) {
+ if (rssi_thresh > rssi_thresh1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi thresh error!!\n");
+ return coex_sta->pre_bt_rssi_state;
+ }
+
+ if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ if (bt_rssi >= rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) {
+ bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state "
+ "switch to Medium\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state "
+ "stay at Low\n");
+ }
+ } else if ((coex_sta->pre_bt_rssi_state ==
+ BTC_RSSI_STATE_MEDIUM) ||
+ (coex_sta->pre_bt_rssi_state ==
+ BTC_RSSI_STATE_STAY_MEDIUM)) {
+ if (bt_rssi >= rssi_thresh1 +
+ BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) {
+ bt_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state "
+ "switch to High\n");
+ } else if (bt_rssi < rssi_thresh) {
+ bt_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state "
+ "switch to Low\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state "
+ "stay at Medium\n");
+ }
+ } else {
+ if (bt_rssi < rssi_thresh1) {
+ bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state "
+ "switch to Medium\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state "
+ "stay at High\n");
+ }
+ }
+ }
+
+ coex_sta->pre_bt_rssi_state = bt_rssi_state;
+
+ return bt_rssi_state;
+}
+
+static u8 btc8723b2ant_wifi_rssi_state(struct btc_coexist *btcoexist,
+ u8 index, u8 level_num,
+ u8 rssi_thresh, u8 rssi_thresh1)
+{
+ s32 wifi_rssi = 0;
+ u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index];
+
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+
+ if (level_num == 2) {
+ if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_LOW)) {
+ if (wifi_rssi >= rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) {
+ wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state "
+ "switch to High\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state "
+ "stay at Low\n");
+ }
+ } else {
+ if (wifi_rssi < rssi_thresh) {
+ wifi_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state "
+ "switch to Low\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state "
+ "stay at High\n");
+ }
+ }
+ } else if (level_num == 3) {
+ if (rssi_thresh > rssi_thresh1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI thresh error!!\n");
+ return coex_sta->pre_wifi_rssi_state[index];
+ }
+
+ if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_LOW)) {
+ if (wifi_rssi >= rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) {
+ wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state "
+ "switch to Medium\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state "
+ "stay at Low\n");
+ }
+ } else if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_MEDIUM) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_MEDIUM)) {
+ if (wifi_rssi >= rssi_thresh1 +
+ BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) {
+ wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state "
+ "switch to High\n");
+ } else if (wifi_rssi < rssi_thresh) {
+ wifi_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state "
+ "switch to Low\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state "
+ "stay at Medium\n");
+ }
+ } else {
+ if (wifi_rssi < rssi_thresh1) {
+ wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state "
+ "switch to Medium\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state "
+ "stay at High\n");
+ }
+ }
+ }
+
+ coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state;
+
+ return wifi_rssi_state;
+}
+
+static void btc8723b2ant_monitor_bt_ctr(struct btc_coexist *btcoexist)
+{
+ u32 reg_hp_txrx, reg_lp_txrx, u32tmp;
+ u32 reg_hp_tx = 0, reg_hp_rx = 0;
+ u32 reg_lp_tx = 0, reg_lp_rx = 0;
+
+ reg_hp_txrx = 0x770;
+ reg_lp_txrx = 0x774;
+
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx);
+ reg_hp_tx = u32tmp & MASKLWORD;
+ reg_hp_rx = (u32tmp & MASKHWORD) >> 16;
+
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx);
+ reg_lp_tx = u32tmp & MASKLWORD;
+ reg_lp_rx = (u32tmp & MASKHWORD) >> 16;
+
+ coex_sta->high_priority_tx = reg_hp_tx;
+ coex_sta->high_priority_rx = reg_hp_rx;
+ coex_sta->low_priority_tx = reg_lp_tx;
+ coex_sta->low_priority_rx = reg_lp_rx;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], High Priority Tx/Rx(reg 0x%x)=0x%x(%d)/0x%x(%d)\n",
+ reg_hp_txrx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], Low Priority Tx/Rx(reg 0x%x)=0x%x(%d)/0x%x(%d)\n",
+ reg_lp_txrx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx);
+
+ /* reset counter */
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+}
+
+static bool btc8723b2ant_is_wifi_status_changed(struct btc_coexist *btcoexist)
+{
+ static bool pre_wifi_busy;
+ static bool pre_under_4way;
+ static bool pre_bt_hs_on;
+ bool wifi_busy = false, under_4way = false, bt_hs_on = false;
+ bool wifi_connected = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS,
+ &under_4way);
+
+ if (wifi_connected) {
+ if (wifi_busy != pre_wifi_busy) {
+ pre_wifi_busy = wifi_busy;
+ return true;
+ }
+
+ if (under_4way != pre_under_4way) {
+ pre_under_4way = under_4way;
+ return true;
+ }
+
+ if (bt_hs_on != pre_bt_hs_on) {
+ pre_bt_hs_on = bt_hs_on;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void btc8723b2ant_update_bt_link_info(struct btc_coexist *btcoexist)
+{
+ /*struct btc_stack_info *stack_info = &btcoexist->stack_info;*/
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool bt_hs_on = false;
+
+#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 1) /* profile from bt patch */
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+ bt_link_info->bt_link_exist = coex_sta->bt_link_exist;
+ bt_link_info->sco_exist = coex_sta->sco_exist;
+ bt_link_info->a2dp_exist = coex_sta->a2dp_exist;
+ bt_link_info->pan_exist = coex_sta->pan_exist;
+ bt_link_info->hid_exist = coex_sta->hid_exist;
+
+ /* work around for HS mode. */
+ if (bt_hs_on) {
+ bt_link_info->pan_exist = true;
+ bt_link_info->bt_link_exist = true;
+ }
+#else /* profile from bt stack */
+ bt_link_info->bt_link_exist = stack_info->bt_link_exist;
+ bt_link_info->sco_exist = stack_info->sco_exist;
+ bt_link_info->a2dp_exist = stack_info->a2dp_exist;
+ bt_link_info->pan_exist = stack_info->pan_exist;
+ bt_link_info->hid_exist = stack_info->hid_exist;
+
+ /*for win-8 stack HID report error*/
+ if (!stack_info->hid_exist)
+ stack_info->hid_exist = coex_sta->hid_exist;
+ /*sync BTInfo with BT firmware and stack*/
+ /* when stack HID report error, here we use the info from bt fw.*/
+ if (!stack_info->bt_link_exist)
+ stack_info->bt_link_exist = coex_sta->bt_link_exist;
+#endif
+ /* check if Sco only */
+ if (bt_link_info->sco_exist && !bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist && !bt_link_info->hid_exist)
+ bt_link_info->sco_only = true;
+ else
+ bt_link_info->sco_only = false;
+
+ /* check if A2dp only */
+ if (!bt_link_info->sco_exist && bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist && !bt_link_info->hid_exist)
+ bt_link_info->a2dp_only = true;
+ else
+ bt_link_info->a2dp_only = false;
+
+ /* check if Pan only */
+ if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist &&
+ bt_link_info->pan_exist && !bt_link_info->hid_exist)
+ bt_link_info->pan_only = true;
+ else
+ bt_link_info->pan_only = false;
+
+ /* check if Hid only */
+ if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist && bt_link_info->hid_exist)
+ bt_link_info->hid_only = true;
+ else
+ bt_link_info->hid_only = false;
+}
+
+static u8 btc8723b2ant_action_algorithm(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool bt_hs_on = false;
+ u8 algorithm = BT_8723B_2ANT_COEX_ALGO_UNDEFINED;
+ u8 num_of_diff_profile = 0;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+ if (!bt_link_info->bt_link_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], No BT link exists!!!\n");
+ return algorithm;
+ }
+
+ if (bt_link_info->sco_exist)
+ num_of_diff_profile++;
+ if (bt_link_info->hid_exist)
+ num_of_diff_profile++;
+ if (bt_link_info->pan_exist)
+ num_of_diff_profile++;
+ if (bt_link_info->a2dp_exist)
+ num_of_diff_profile++;
+
+ if (num_of_diff_profile == 1) {
+ if (bt_link_info->sco_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO only\n");
+ algorithm = BT_8723B_2ANT_COEX_ALGO_SCO;
+ } else {
+ if (bt_link_info->hid_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], HID only\n");
+ algorithm = BT_8723B_2ANT_COEX_ALGO_HID;
+ } else if (bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], A2DP only\n");
+ algorithm = BT_8723B_2ANT_COEX_ALGO_A2DP;
+ } else if (bt_link_info->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], PAN(HS) only\n");
+ algorithm =
+ BT_8723B_2ANT_COEX_ALGO_PANHS;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], PAN(EDR) only\n");
+ algorithm =
+ BT_8723B_2ANT_COEX_ALGO_PANEDR;
+ }
+ }
+ }
+ } else if (num_of_diff_profile == 2) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + HID\n");
+ algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
+ } else if (bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + A2DP ==> SCO\n");
+ algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
+ } else if (bt_link_info->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + PAN(HS)\n");
+ algorithm = BT_8723B_2ANT_COEX_ALGO_SCO;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + PAN(EDR)\n");
+ algorithm =
+ BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ } else {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], HID + A2DP\n");
+ algorithm = BT_8723B_2ANT_COEX_ALGO_HID_A2DP;
+ } else if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], HID + PAN(HS)\n");
+ algorithm = BT_8723B_2ANT_COEX_ALGO_HID;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], HID + PAN(EDR)\n");
+ algorithm =
+ BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ } else if (bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], A2DP + PAN(HS)\n");
+ algorithm =
+ BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex],A2DP + PAN(EDR)\n");
+ algorithm =
+ BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP;
+ }
+ }
+ }
+ } else if (num_of_diff_profile == 3) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + HID + A2DP"
+ " ==> HID\n");
+ algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
+ } else if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + HID + "
+ "PAN(HS)\n");
+ algorithm =
+ BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + HID + "
+ "PAN(EDR)\n");
+ algorithm =
+ BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ } else if (bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + A2DP + "
+ "PAN(HS)\n");
+ algorithm =
+ BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + A2DP + "
+ "PAN(EDR) ==> HID\n");
+ algorithm =
+ BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ } else {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], HID + A2DP + "
+ "PAN(HS)\n");
+ algorithm =
+ BT_8723B_2ANT_COEX_ALGO_HID_A2DP;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], HID + A2DP + "
+ "PAN(EDR)\n");
+ algorithm =
+ BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR;
+ }
+ }
+ }
+ } else if (num_of_diff_profile >= 3) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Error!!! SCO + HID"
+ " + A2DP + PAN(HS)\n");
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + HID + A2DP +"
+ " PAN(EDR)==>PAN(EDR)+HID\n");
+ algorithm =
+ BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ }
+ }
+ return algorithm;
+}
+
+static bool btc8723b_need_dec_pwr(struct btc_coexist *btcoexist)
+{
+ bool ret = false;
+ bool bt_hs_on = false, wifi_connected = false;
+ s32 bt_hs_rssi = 0;
+ u8 bt_rssi_state;
+
+ if (!btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on))
+ return false;
+ if (!btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected))
+ return false;
+ if (!btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi))
+ return false;
+
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+
+ if (wifi_connected) {
+ if (bt_hs_on) {
+ if (bt_hs_rssi > 37) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], Need to decrease bt "
+ "power for HS mode!!\n");
+ ret = true;
+ }
+ } else {
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], Need to decrease bt "
+ "power for Wifi is connected!!\n");
+ ret = true;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static void btc8723b2ant_set_fw_dac_swing_level(struct btc_coexist *btcoexist,
+ u8 dac_swing_lvl)
+{
+ u8 h2c_parameter[1] = {0};
+
+ /* There are several type of dacswing
+ * 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6
+ */
+ h2c_parameter[0] = dac_swing_lvl;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], Set Dac Swing Level=0x%x\n", dac_swing_lvl);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], FW write 0x64=0x%x\n", h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter);
+}
+
+static void btc8723b2ant_set_fw_dec_bt_pwr(struct btc_coexist *btcoexist,
+ bool dec_bt_pwr)
+{
+ u8 h2c_parameter[1] = {0};
+
+ h2c_parameter[0] = 0;
+
+ if (dec_bt_pwr)
+ h2c_parameter[0] |= BIT1;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], decrease Bt Power : %s, FW write 0x62=0x%x\n",
+ (dec_bt_pwr ? "Yes!!" : "No!!"), h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter);
+}
+
+static void btc8723b2ant_dec_bt_pwr(struct btc_coexist *btcoexist,
+ bool force_exec, bool dec_bt_pwr)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s Dec BT power = %s\n",
+ (force_exec ? "force to" : ""), (dec_bt_pwr ? "ON" : "OFF"));
+ coex_dm->cur_dec_bt_pwr = dec_bt_pwr;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], bPreDecBtPwr=%d, bCurDecBtPwr=%d\n",
+ coex_dm->pre_dec_bt_pwr, coex_dm->cur_dec_bt_pwr);
+
+ if (coex_dm->pre_dec_bt_pwr == coex_dm->cur_dec_bt_pwr)
+ return;
+ }
+ btc8723b2ant_set_fw_dec_bt_pwr(btcoexist, coex_dm->cur_dec_bt_pwr);
+
+ coex_dm->pre_dec_bt_pwr = coex_dm->cur_dec_bt_pwr;
+}
+
+static void btc8723b2ant_fw_dac_swing_lvl(struct btc_coexist *btcoexist,
+ bool force_exec, u8 fw_dac_swing_lvl)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s set FW Dac Swing level = %d\n",
+ (force_exec ? "force to" : ""), fw_dac_swing_lvl);
+ coex_dm->cur_fw_dac_swing_lvl = fw_dac_swing_lvl;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], preFwDacSwingLvl=%d, "
+ "curFwDacSwingLvl=%d\n",
+ coex_dm->pre_fw_dac_swing_lvl,
+ coex_dm->cur_fw_dac_swing_lvl);
+
+ if (coex_dm->pre_fw_dac_swing_lvl ==
+ coex_dm->cur_fw_dac_swing_lvl)
+ return;
+ }
+
+ btc8723b2ant_set_fw_dac_swing_level(btcoexist,
+ coex_dm->cur_fw_dac_swing_lvl);
+ coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl;
+}
+
+static void btc8723b2ant_set_sw_rf_rx_lpf_corner(struct btc_coexist *btcoexist,
+ bool rx_rf_shrink_on)
+{
+ if (rx_rf_shrink_on) {
+ /* Shrink RF Rx LPF corner */
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], Shrink RF Rx LPF corner!!\n");
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e,
+ 0xfffff, 0xffffc);
+ } else {
+ /* Resume RF Rx LPF corner */
+ /* After initialized, we can use coex_dm->btRf0x1eBackup */
+ if (btcoexist->initilized) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], Resume RF Rx LPF corner!!\n");
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e,
+ 0xfffff,
+ coex_dm->bt_rf0x1e_backup);
+ }
+ }
+}
+
+static void btc8723b2ant_rf_shrink(struct btc_coexist *btcoexist,
+ bool force_exec, bool rx_rf_shrink_on)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s turn Rx RF Shrink = %s\n",
+ (force_exec ? "force to" : ""), (rx_rf_shrink_on ?
+ "ON" : "OFF"));
+ coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], bPreRfRxLpfShrink=%d, "
+ "bCurRfRxLpfShrink=%d\n",
+ coex_dm->pre_rf_rx_lpf_shrink,
+ coex_dm->cur_rf_rx_lpf_shrink);
+
+ if (coex_dm->pre_rf_rx_lpf_shrink ==
+ coex_dm->cur_rf_rx_lpf_shrink)
+ return;
+ }
+ btc8723b2ant_set_sw_rf_rx_lpf_corner(btcoexist,
+ coex_dm->cur_rf_rx_lpf_shrink);
+
+ coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink;
+}
+
+static void btc8723b_set_penalty_txrate(struct btc_coexist *btcoexist,
+ bool low_penalty_ra)
+{
+ u8 h2c_parameter[6] = {0};
+
+ h2c_parameter[0] = 0x6; /* opCode, 0x6= Retry_Penalty*/
+
+ if (low_penalty_ra) {
+ h2c_parameter[1] |= BIT0;
+ /*normal rate except MCS7/6/5, OFDM54/48/36*/
+ h2c_parameter[2] = 0x00;
+ h2c_parameter[3] = 0xf7; /*MCS7 or OFDM54*/
+ h2c_parameter[4] = 0xf8; /*MCS6 or OFDM48*/
+ h2c_parameter[5] = 0xf9; /*MCS5 or OFDM36*/
+ }
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], set WiFi Low-Penalty Retry: %s",
+ (low_penalty_ra ? "ON!!" : "OFF!!"));
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter);
+}
+
+static void btc8723b2ant_low_penalty_ra(struct btc_coexist *btcoexist,
+ bool force_exec, bool low_penalty_ra)
+{
+ /*return; */
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s turn LowPenaltyRA = %s\n",
+ (force_exec ? "force to" : ""), (low_penalty_ra ?
+ "ON" : "OFF"));
+ coex_dm->cur_low_penalty_ra = low_penalty_ra;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], bPreLowPenaltyRa=%d, "
+ "bCurLowPenaltyRa=%d\n",
+ coex_dm->pre_low_penalty_ra,
+ coex_dm->cur_low_penalty_ra);
+
+ if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra)
+ return;
+ }
+ btc8723b_set_penalty_txrate(btcoexist, coex_dm->cur_low_penalty_ra);
+
+ coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra;
+}
+
+static void btc8723b2ant_set_dac_swing_reg(struct btc_coexist *btcoexist,
+ u32 level)
+{
+ u8 val = (u8) level;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], Write SwDacSwing = 0x%x\n", level);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x883, 0x3e, val);
+}
+
+static void btc8723b2ant_set_sw_fulltime_dac_swing(struct btc_coexist *btcoex,
+ bool sw_dac_swing_on,
+ u32 sw_dac_swing_lvl)
+{
+ if (sw_dac_swing_on)
+ btc8723b2ant_set_dac_swing_reg(btcoex, sw_dac_swing_lvl);
+ else
+ btc8723b2ant_set_dac_swing_reg(btcoex, 0x18);
+}
+
+
+static void btc8723b2ant_dac_swing(struct btc_coexist *btcoexist,
+ bool force_exec, bool dac_swing_on,
+ u32 dac_swing_lvl)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s turn DacSwing=%s, dac_swing_lvl=0x%x\n",
+ (force_exec ? "force to" : ""),
+ (dac_swing_on ? "ON" : "OFF"), dac_swing_lvl);
+ coex_dm->cur_dac_swing_on = dac_swing_on;
+ coex_dm->cur_dac_swing_lvl = dac_swing_lvl;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], bPreDacSwingOn=%d, preDacSwingLvl=0x%x,"
+ " bCurDacSwingOn=%d, curDacSwingLvl=0x%x\n",
+ coex_dm->pre_dac_swing_on, coex_dm->pre_dac_swing_lvl,
+ coex_dm->cur_dac_swing_on,
+ coex_dm->cur_dac_swing_lvl);
+
+ if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) &&
+ (coex_dm->pre_dac_swing_lvl == coex_dm->cur_dac_swing_lvl))
+ return;
+ }
+ mdelay(30);
+ btc8723b2ant_set_sw_fulltime_dac_swing(btcoexist, dac_swing_on,
+ dac_swing_lvl);
+
+ coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on;
+ coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl;
+}
+
+static void btc8723b2ant_set_agc_table(struct btc_coexist *btcoexist,
+ bool agc_table_en)
+{
+ u8 rssi_adjust_val = 0;
+
+ /* BB AGC Gain Table */
+ if (agc_table_en) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], BB Agc Table On!\n");
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6e1A0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6d1B0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6c1C0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6b1D0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6a1E0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x691F0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x68200001);
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], BB Agc Table Off!\n");
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xaa1A0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa91B0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa81C0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa71D0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa61E0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa51F0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa4200001);
+ }
+
+
+ /* RF Gain */
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x02000);
+ if (agc_table_en) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], Agc Table On!\n");
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b,
+ 0xfffff, 0x38fff);
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b,
+ 0xfffff, 0x38ffe);
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], Agc Table Off!\n");
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b,
+ 0xfffff, 0x380c3);
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b,
+ 0xfffff, 0x28ce6);
+ }
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x0);
+
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xed, 0xfffff, 0x1);
+
+ if (agc_table_en) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], Agc Table On!\n");
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40,
+ 0xfffff, 0x38fff);
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40,
+ 0xfffff, 0x38ffe);
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], Agc Table Off!\n");
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40,
+ 0xfffff, 0x380c3);
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40,
+ 0xfffff, 0x28ce6);
+ }
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xed, 0xfffff, 0x0);
+
+ /* set rssiAdjustVal for wifi module. */
+ if (agc_table_en)
+ rssi_adjust_val = 8;
+ btcoexist->btc_set(btcoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON,
+ &rssi_adjust_val);
+}
+
+static void btc8723b2ant_agc_table(struct btc_coexist *btcoexist,
+ bool force_exec, bool agc_table_en)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s %s Agc Table\n",
+ (force_exec ? "force to" : ""),
+ (agc_table_en ? "Enable" : "Disable"));
+ coex_dm->cur_agc_table_en = agc_table_en;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], bPreAgcTableEn=%d, bCurAgcTableEn=%d\n",
+ coex_dm->pre_agc_table_en, coex_dm->cur_agc_table_en);
+
+ if (coex_dm->pre_agc_table_en == coex_dm->cur_agc_table_en)
+ return;
+ }
+ btc8723b2ant_set_agc_table(btcoexist, agc_table_en);
+
+ coex_dm->pre_agc_table_en = coex_dm->cur_agc_table_en;
+}
+
+static void btc8723b2ant_set_coex_table(struct btc_coexist *btcoexist,
+ u32 val0x6c0, u32 val0x6c4,
+ u32 val0x6c8, u8 val0x6cc)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c4=0x%x\n", val0x6c4);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc);
+ btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc);
+}
+
+static void btc8723b2ant_coex_table(struct btc_coexist *btcoexist,
+ bool force_exec, u32 val0x6c0,
+ u32 val0x6c4, u32 val0x6c8,
+ u8 val0x6cc)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s write Coex Table 0x6c0=0x%x,"
+ " 0x6c4=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n",
+ (force_exec ? "force to" : ""), val0x6c0,
+ val0x6c4, val0x6c8, val0x6cc);
+ coex_dm->cur_val0x6c0 = val0x6c0;
+ coex_dm->cur_val0x6c4 = val0x6c4;
+ coex_dm->cur_val0x6c8 = val0x6c8;
+ coex_dm->cur_val0x6cc = val0x6cc;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], preVal0x6c0=0x%x, "
+ "preVal0x6c4=0x%x, preVal0x6c8=0x%x, "
+ "preVal0x6cc=0x%x !!\n",
+ coex_dm->pre_val0x6c0, coex_dm->pre_val0x6c4,
+ coex_dm->pre_val0x6c8, coex_dm->pre_val0x6cc);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], curVal0x6c0=0x%x, "
+ "curVal0x6c4=0x%x, curVal0x6c8=0x%x, "
+ "curVal0x6cc=0x%x !!\n",
+ coex_dm->cur_val0x6c0, coex_dm->cur_val0x6c4,
+ coex_dm->cur_val0x6c8, coex_dm->cur_val0x6cc);
+
+ if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) &&
+ (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) &&
+ (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) &&
+ (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc))
+ return;
+ }
+ btc8723b2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4,
+ val0x6c8, val0x6cc);
+
+ coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0;
+ coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4;
+ coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8;
+ coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc;
+}
+
+static void btc8723b_coex_tbl_type(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ switch (type) {
+ case 0:
+ btc8723b2ant_coex_table(btcoexist, force_exec, 0x55555555,
+ 0x55555555, 0xffff, 0x3);
+ break;
+ case 1:
+ btc8723b2ant_coex_table(btcoexist, force_exec, 0x55555555,
+ 0x5afa5afa, 0xffff, 0x3);
+ break;
+ case 2:
+ btc8723b2ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a,
+ 0x5a5a5a5a, 0xffff, 0x3);
+ break;
+ case 3:
+ btc8723b2ant_coex_table(btcoexist, force_exec, 0xaaaaaaaa,
+ 0xaaaaaaaa, 0xffff, 0x3);
+ break;
+ case 4:
+ btc8723b2ant_coex_table(btcoexist, force_exec, 0xffffffff,
+ 0xffffffff, 0xffff, 0x3);
+ break;
+ case 5:
+ btc8723b2ant_coex_table(btcoexist, force_exec, 0x5fff5fff,
+ 0x5fff5fff, 0xffff, 0x3);
+ break;
+ case 6:
+ btc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff,
+ 0x5a5a5a5a, 0xffff, 0x3);
+ break;
+ case 7:
+ btc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff,
+ 0x5afa5afa, 0xffff, 0x3);
+ break;
+ case 8:
+ btc8723b2ant_coex_table(btcoexist, force_exec, 0x5aea5aea,
+ 0x5aea5aea, 0xffff, 0x3);
+ break;
+ case 9:
+ btc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff,
+ 0x5aea5aea, 0xffff, 0x3);
+ break;
+ case 10:
+ btc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff,
+ 0x5aff5aff, 0xffff, 0x3);
+ break;
+ case 11:
+ btc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff,
+ 0x5a5f5a5f, 0xffff, 0x3);
+ break;
+ case 12:
+ btc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff,
+ 0x5f5f5f5f, 0xffff, 0x3);
+ break;
+ default:
+ break;
+ }
+}
+
+static void btc8723b2ant_set_fw_ignore_wlan_act(struct btc_coexist *btcoexist,
+ bool enable)
+{
+ u8 h2c_parameter[1] = {0};
+
+ if (enable)
+ h2c_parameter[0] |= BIT0;/* function enable*/
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], set FW for BT Ignore Wlan_Act, "
+ "FW write 0x63=0x%x\n", h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter);
+}
+
+static void btc8723b2ant_ignore_wlan_act(struct btc_coexist *btcoexist,
+ bool force_exec, bool enable)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s turn Ignore WlanAct %s\n",
+ (force_exec ? "force to" : ""), (enable ? "ON" : "OFF"));
+ coex_dm->cur_ignore_wlan_act = enable;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], bPreIgnoreWlanAct = %d, "
+ "bCurIgnoreWlanAct = %d!!\n",
+ coex_dm->pre_ignore_wlan_act,
+ coex_dm->cur_ignore_wlan_act);
+
+ if (coex_dm->pre_ignore_wlan_act ==
+ coex_dm->cur_ignore_wlan_act)
+ return;
+ }
+ btc8723b2ant_set_fw_ignore_wlan_act(btcoexist, enable);
+
+ coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act;
+}
+
+static void btc8723b2ant_set_fw_ps_tdma(struct btc_coexist *btcoexist, u8 byte1,
+ u8 byte2, u8 byte3, u8 byte4, u8 byte5)
+{
+ u8 h2c_parameter[5];
+
+ h2c_parameter[0] = byte1;
+ h2c_parameter[1] = byte2;
+ h2c_parameter[2] = byte3;
+ h2c_parameter[3] = byte4;
+ h2c_parameter[4] = byte5;
+
+ coex_dm->ps_tdma_para[0] = byte1;
+ coex_dm->ps_tdma_para[1] = byte2;
+ coex_dm->ps_tdma_para[2] = byte3;
+ coex_dm->ps_tdma_para[3] = byte4;
+ coex_dm->ps_tdma_para[4] = byte5;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], FW write 0x60(5bytes)=0x%x%08x\n",
+ h2c_parameter[0],
+ h2c_parameter[1] << 24 | h2c_parameter[2] << 16 |
+ h2c_parameter[3] << 8 | h2c_parameter[4]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter);
+}
+
+static void btc8723b2ant_sw_mechanism1(struct btc_coexist *btcoexist,
+ bool shrink_rx_lpf, bool low_penalty_ra,
+ bool limited_dig, bool bt_lna_constrain)
+{
+ btc8723b2ant_rf_shrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf);
+ btc8723b2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra);
+}
+
+static void btc8723b2ant_sw_mechanism2(struct btc_coexist *btcoexist,
+ bool agc_table_shift, bool adc_backoff,
+ bool sw_dac_swing, u32 dac_swing_lvl)
+{
+ btc8723b2ant_agc_table(btcoexist, NORMAL_EXEC, agc_table_shift);
+ btc8723b2ant_dac_swing(btcoexist, NORMAL_EXEC, sw_dac_swing,
+ dac_swing_lvl);
+}
+
+static void btc8723b2ant_ps_tdma(struct btc_coexist *btcoexist, bool force_exec,
+ bool turn_on, u8 type)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s turn %s PS TDMA, type=%d\n",
+ (force_exec ? "force to" : ""),
+ (turn_on ? "ON" : "OFF"), type);
+ coex_dm->cur_ps_tdma_on = turn_on;
+ coex_dm->cur_ps_tdma = type;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n",
+ coex_dm->pre_ps_tdma_on, coex_dm->cur_ps_tdma_on);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n",
+ coex_dm->pre_ps_tdma, coex_dm->cur_ps_tdma);
+
+ if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) &&
+ (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma))
+ return;
+ }
+ if (turn_on) {
+ switch (type) {
+ case 1:
+ default:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0xe1, 0x90);
+ break;
+ case 2:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x12,
+ 0x12, 0xe1, 0x90);
+ break;
+ case 3:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1c,
+ 0x3, 0xf1, 0x90);
+ break;
+ case 4:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x10,
+ 0x03, 0xf1, 0x90);
+ break;
+ case 5:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0x60, 0x90);
+ break;
+ case 6:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x12,
+ 0x12, 0x60, 0x90);
+ break;
+ case 7:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1c,
+ 0x3, 0x70, 0x90);
+ break;
+ case 8:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xa3, 0x10,
+ 0x3, 0x70, 0x90);
+ break;
+ case 9:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0xe1, 0x90);
+ break;
+ case 10:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x12,
+ 0x12, 0xe1, 0x90);
+ break;
+ case 11:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa,
+ 0xa, 0xe1, 0x90);
+ break;
+ case 12:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x5,
+ 0x5, 0xe1, 0x90);
+ break;
+ case 13:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0x60, 0x90);
+ break;
+ case 14:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x12,
+ 0x12, 0x60, 0x90);
+ break;
+ case 15:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa,
+ 0xa, 0x60, 0x90);
+ break;
+ case 16:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x5,
+ 0x5, 0x60, 0x90);
+ break;
+ case 17:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xa3, 0x2f,
+ 0x2f, 0x60, 0x90);
+ break;
+ case 18:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x5,
+ 0x5, 0xe1, 0x90);
+ break;
+ case 19:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25,
+ 0x25, 0xe1, 0x90);
+ break;
+ case 20:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25,
+ 0x25, 0x60, 0x90);
+ break;
+ case 21:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x15,
+ 0x03, 0x70, 0x90);
+ break;
+ case 71:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0xe1, 0x90);
+ break;
+ }
+ } else {
+ /* disable PS tdma */
+ switch (type) {
+ case 0:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, 0x0,
+ 0x40, 0x0);
+ break;
+ case 1:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, 0x0,
+ 0x48, 0x0);
+ break;
+ default:
+ btc8723b2ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, 0x0,
+ 0x40, 0x0);
+ break;
+ }
+ }
+
+ /* update pre state */
+ coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on;
+ coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma;
+}
+
+static void btc8723b2ant_coex_alloff(struct btc_coexist *btcoexist)
+{
+ /* fw all off */
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ /* sw all off */
+ btc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18);
+
+ /* hw all off */
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 0);
+}
+
+static void btc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+ /* force to reset coex mechanism*/
+
+ btc8723b2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1);
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6);
+ btc8723b2ant_dec_bt_pwr(btcoexist, FORCE_EXEC, false);
+
+ btc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18);
+}
+
+static void btc8723b2ant_action_bt_inquiry(struct btc_coexist *btcoexist)
+{
+ bool wifi_connected = false;
+ bool low_pwr_disable = true;
+
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+
+ if (wifi_connected) {
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7);
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+ } else {
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 0);
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+ }
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6);
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18);
+
+ coex_dm->need_recover_0x948 = true;
+ coex_dm->backup_0x948 = btcoexist->btc_read_2byte(btcoexist, 0x948);
+
+ btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280);
+}
+
+static bool btc8723b2ant_is_common_action(struct btc_coexist *btcoexist)
+{
+ bool common = false, wifi_connected = false;
+ bool wifi_busy = false;
+ bool bt_hs_on = false, low_pwr_disable = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+
+ if (!wifi_connected) {
+ low_pwr_disable = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi non-connected idle!!\n");
+
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff,
+ 0x0);
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 0);
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btc8723b2ant_sw_mechanism1(btcoexist, false, false, false,
+ false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false, false,
+ 0x18);
+
+ common = true;
+ } else {
+ if (BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+ coex_dm->bt_status) {
+ low_pwr_disable = false;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi connected + "
+ "BT non connected-idle!!\n");
+
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1,
+ 0xfffff, 0x0);
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 0);
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC,
+ 0xb);
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC,
+ false);
+
+ btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ false, 0x18);
+
+ common = true;
+ } else if (BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE ==
+ coex_dm->bt_status) {
+ low_pwr_disable = true;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ if (bt_hs_on)
+ return false;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi connected + "
+ "BT connected-idle!!\n");
+
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1,
+ 0xfffff, 0x0);
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 0);
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC,
+ 0xb);
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC,
+ false);
+
+ btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ false, 0x18);
+
+ common = true;
+ } else {
+ low_pwr_disable = true;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ if (wifi_busy) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi Connected-Busy + "
+ "BT Busy!!\n");
+ common = false;
+ } else {
+ if (bt_hs_on)
+ return false;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi Connected-Idle + "
+ "BT Busy!!\n");
+
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A,
+ 0x1, 0xfffff, 0x0);
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC,
+ 7);
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 21);
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist,
+ NORMAL_EXEC,
+ 0xb);
+ if (btc8723b_need_dec_pwr(btcoexist))
+ btc8723b2ant_dec_bt_pwr(btcoexist,
+ NORMAL_EXEC,
+ true);
+ else
+ btc8723b2ant_dec_bt_pwr(btcoexist,
+ NORMAL_EXEC,
+ false);
+ btc8723b2ant_sw_mechanism1(btcoexist, false,
+ false, false,
+ false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false,
+ false, false,
+ 0x18);
+ common = true;
+ }
+ }
+ }
+
+ return common;
+}
+
+static void set_tdma_int1(struct btc_coexist *btcoexist, bool tx_pause,
+ s32 result)
+{
+ /* Set PS TDMA for max interval == 1 */
+ if (tx_pause) {
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 1\n");
+
+ if (coex_dm->cur_ps_tdma == 71) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ coex_dm->tdma_adj_type = 5;
+ } else if (coex_dm->cur_ps_tdma == 1) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ coex_dm->tdma_adj_type = 5;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 4) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 13);
+ coex_dm->tdma_adj_type = 13;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 5) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ } else if (coex_dm->cur_ps_tdma == 13) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 8) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ coex_dm->tdma_adj_type = 5;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 13);
+ coex_dm->tdma_adj_type = 13;
+ }
+ }
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 0\n");
+ if (coex_dm->cur_ps_tdma == 5) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 71);
+ coex_dm->tdma_adj_type = 71;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 8) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4);
+ coex_dm->tdma_adj_type = 4;
+ } else if (coex_dm->cur_ps_tdma == 13) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 71) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 1);
+ coex_dm->tdma_adj_type = 1;
+ } else if (coex_dm->cur_ps_tdma == 1) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ } else if (result == 1) {
+ int tmp = coex_dm->cur_ps_tdma;
+ switch (tmp) {
+ case 4:
+ case 3:
+ case 2:
+ case 12:
+ case 11:
+ case 10:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, tmp - 1);
+ coex_dm->tdma_adj_type = tmp - 1;
+ break;
+ case 1:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 71);
+ coex_dm->tdma_adj_type = 71;
+ break;
+ }
+ }
+ }
+}
+
+static void set_tdma_int2(struct btc_coexist *btcoexist, bool tx_pause,
+ s32 result)
+{
+ /* Set PS TDMA for max interval == 2 */
+ if (tx_pause) {
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 1\n");
+ if (coex_dm->cur_ps_tdma == 1) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 4) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 8);
+ coex_dm->tdma_adj_type = 8;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 5) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ } else if (coex_dm->cur_ps_tdma == 13) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 8) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ }
+ }
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 0\n");
+ if (coex_dm->cur_ps_tdma == 5) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 8) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4);
+ coex_dm->tdma_adj_type = 4;
+ } else if (coex_dm->cur_ps_tdma == 13) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 1) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 4) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ }
+ }
+ }
+}
+
+static void set_tdma_int3(struct btc_coexist *btcoexist, bool tx_pause,
+ s32 result)
+{
+ /* Set PS TDMA for max interval == 3 */
+ if (tx_pause) {
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 1\n");
+ if (coex_dm->cur_ps_tdma == 1) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 4) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 8);
+ coex_dm->tdma_adj_type = 8;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 5) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ } else if (coex_dm->cur_ps_tdma == 13) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 8) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ }
+ }
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 0\n");
+ switch (coex_dm->cur_ps_tdma) {
+ case 5:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+ coex_dm->tdma_adj_type = 3;
+ break;
+ case 6:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+ coex_dm->tdma_adj_type = 3;
+ break;
+ case 7:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+ coex_dm->tdma_adj_type = 3;
+ break;
+ case 8:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4);
+ coex_dm->tdma_adj_type = 4;
+ break;
+ case 13:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
+ coex_dm->tdma_adj_type = 11;
+ break;
+ case 14:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
+ coex_dm->tdma_adj_type = 11;
+ break;
+ case 15:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
+ coex_dm->tdma_adj_type = 11;
+ break;
+ case 16:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 12);
+ coex_dm->tdma_adj_type = 12;
+ break;
+ }
+ if (result == -1) {
+ switch (coex_dm->cur_ps_tdma) {
+ case 1:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ break;
+ case 2:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ break;
+ case 3:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ break;
+ case 9:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ break;
+ case 10:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ break;
+ case 11:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ break;
+ }
+ } else if (result == 1) {
+ switch (coex_dm->cur_ps_tdma) {
+ case 4:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ break;
+ case 3:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ break;
+ case 2:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ break;
+ case 12:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ break;
+ case 11:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ break;
+ case 10:
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ }
+ }
+ }
+}
+
+static void btc8723b2ant_tdma_duration_adjust(struct btc_coexist *btcoexist,
+ bool sco_hid, bool tx_pause,
+ u8 max_interval)
+{
+ static s32 up, dn, m, n, wait_count;
+ /*0: no change, +1: increase WiFi duration, -1: decrease WiFi duration*/
+ s32 result;
+ u8 retry_count = 0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], TdmaDurationAdjust()\n");
+
+ if (!coex_dm->auto_tdma_adjust) {
+ coex_dm->auto_tdma_adjust = true;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], first run TdmaDurationAdjust()!!\n");
+ if (sco_hid) {
+ if (tx_pause) {
+ if (max_interval == 1) {
+ btc8723b2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 13);
+ coex_dm->tdma_adj_type = 13;
+ } else if (max_interval == 2) {
+ btc8723b2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (max_interval == 3) {
+ btc8723b2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else {
+ btc8723b2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ }
+ } else {
+ if (max_interval == 1) {
+ btc8723b2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (max_interval == 2) {
+ btc8723b2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (max_interval == 3) {
+ btc8723b2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else {
+ btc8723b2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ }
+ }
+ } else {
+ if (tx_pause) {
+ if (max_interval == 1) {
+ btc8723b2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 5);
+ coex_dm->tdma_adj_type = 5;
+ } else if (max_interval == 2) {
+ btc8723b2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (max_interval == 3) {
+ btc8723b2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else {
+ btc8723b2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ }
+ } else {
+ if (max_interval == 1) {
+ btc8723b2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 1);
+ coex_dm->tdma_adj_type = 1;
+ } else if (max_interval == 2) {
+ btc8723b2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (max_interval == 3) {
+ btc8723b2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else {
+ btc8723b2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ }
+ }
+ }
+
+ up = 0;
+ dn = 0;
+ m = 1;
+ n = 3;
+ result = 0;
+ wait_count = 0;
+ } else {
+ /*accquire the BT TRx retry count from BT_Info byte2*/
+ retry_count = coex_sta->bt_retry_cnt;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], retry_count = %d\n", retry_count);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], up=%d, dn=%d, m=%d, n=%d, wait_count=%d\n",
+ up, dn, m, n, wait_count);
+ result = 0;
+ wait_count++;
+ /* no retry in the last 2-second duration*/
+ if (retry_count == 0) {
+ up++;
+ dn--;
+
+ if (dn <= 0)
+ dn = 0;
+
+ if (up >= n) {
+ wait_count = 0;
+ n = 3;
+ up = 0;
+ dn = 0;
+ result = 1;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Increase wifi "
+ "duration!!\n");
+ } /* <=3 retry in the last 2-second duration*/
+ } else if (retry_count <= 3) {
+ up--;
+ dn++;
+
+ if (up <= 0)
+ up = 0;
+
+ if (dn == 2) {
+ if (wait_count <= 2)
+ m++;
+ else
+ m = 1;
+
+ if (m >= 20)
+ m = 20;
+
+ n = 3 * m;
+ up = 0;
+ dn = 0;
+ wait_count = 0;
+ result = -1;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Decrease wifi duration "
+ "for retry_counter<3!!\n");
+ }
+ } else {
+ if (wait_count == 1)
+ m++;
+ else
+ m = 1;
+
+ if (m >= 20)
+ m = 20;
+
+ n = 3 * m;
+ up = 0;
+ dn = 0;
+ wait_count = 0;
+ result = -1;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Decrease wifi duration "
+ "for retry_counter>3!!\n");
+ }
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], max Interval = %d\n", max_interval);
+ if (max_interval == 1)
+ set_tdma_int1(btcoexist, tx_pause, result);
+ else if (max_interval == 2)
+ set_tdma_int2(btcoexist, tx_pause, result);
+ else if (max_interval == 3)
+ set_tdma_int3(btcoexist, tx_pause, result);
+ }
+
+ /*if current PsTdma not match with the recorded one (when scan, dhcp..),
+ *then we have to adjust it back to the previous recorded one.
+ */
+ if (coex_dm->cur_ps_tdma != coex_dm->tdma_adj_type) {
+ bool scan = false, link = false, roam = false;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], PsTdma type dismatch!!!, "
+ "curPsTdma=%d, recordPsTdma=%d\n",
+ coex_dm->cur_ps_tdma, coex_dm->tdma_adj_type);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+
+ if (!scan && !link && !roam)
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true,
+ coex_dm->tdma_adj_type);
+ else
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], roaming/link/scan is under"
+ " progress, will adjust next time!!!\n");
+ }
+}
+
+/* SCO only or SCO+PAN(HS) */
+static void btc8723b2ant_action_sco(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
+ 0, 2, 15, 0);
+
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 4);
+
+ if (btc8723b_need_dec_pwr(btcoexist))
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ /*for SCO quality at 11b/g mode*/
+ if (BTC_WIFI_BW_LEGACY == wifi_bw)
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 2);
+ else /*for SCO quality & wifi performance balance at 11n mode*/
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 8);
+
+ /*for voice quality */
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0);
+
+ /* sw mechanism */
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, true,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ true, 0x4);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, true,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ true, 0x4);
+ }
+ } else {
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, true,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ true, 0x4);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, true,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ true, 0x4);
+ }
+ }
+}
+
+static void btc8723b2ant_action_hid(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
+ 0, 2, 15, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+ if (btc8723b_need_dec_pwr(btcoexist))
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_LEGACY == wifi_bw) /*/for HID at 11b/g mode*/
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7);
+ else /*for HID quality & wifi performance balance at 11n mode*/
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 9);
+
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH))
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9);
+ else
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13);
+
+ /* sw mechanism */
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, true,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, true,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, true,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, true,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+/*A2DP only / PAN(EDR) only/ A2DP+PAN(HS)*/
+static void btc8723b2ant_action_a2dp(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
+ 0, 2, 15, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+ if (btc8723b_need_dec_pwr(btcoexist))
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7);
+
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH))
+ btc8723b2ant_tdma_duration_adjust(btcoexist, false,
+ false, 1);
+ else
+ btc8723b2ant_tdma_duration_adjust(btcoexist, false, true, 1);
+
+ /* sw mechanism */
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void btc8723b2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
+ 0, 2, 15, 0);
+
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+ if (btc8723b_need_dec_pwr(btcoexist))
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7);
+
+ btc8723b2ant_tdma_duration_adjust(btcoexist, false, true, 2);
+
+ /* sw mechanism */
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void btc8723b2ant_action_pan_edr(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
+ 0, 2, 15, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+ if (btc8723b_need_dec_pwr(btcoexist))
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 10);
+
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH))
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1);
+ else
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+
+ /* sw mechanism */
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+/*PAN(HS) only*/
+static void btc8723b2ant_action_pan_hs(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
+ 0, 2, 15, 0);
+
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH))
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7);
+
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+/*PAN(EDR)+A2DP*/
+static void btc8723b2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
+ 0, 2, 15, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+ if (btc8723b_need_dec_pwr(btcoexist))
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 12);
+ if (BTC_WIFI_BW_HT40 == wifi_bw)
+ btc8723b2ant_tdma_duration_adjust(btcoexist, false,
+ true, 3);
+ else
+ btc8723b2ant_tdma_duration_adjust(btcoexist, false,
+ false, 3);
+ } else {
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7);
+ btc8723b2ant_tdma_duration_adjust(btcoexist, false, true, 3);
+ }
+
+ /* sw mechanism */
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void btc8723b2ant_action_pan_edr_hid(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
+ 0, 2, 15, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (btc8723b_need_dec_pwr(btcoexist))
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC,
+ 3);
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 11);
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1,
+ 0xfffff, 0x780);
+ } else {
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC,
+ 6);
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7);
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1,
+ 0xfffff, 0x0);
+ }
+ btc8723b2ant_tdma_duration_adjust(btcoexist, true, false, 2);
+ } else {
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 11);
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff,
+ 0x0);
+ btc8723b2ant_tdma_duration_adjust(btcoexist, true, true, 2);
+ }
+
+ /* sw mechanism */
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, true,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, true,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, true,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, true,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+/* HID+A2DP+PAN(EDR) */
+static void btc8723b2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
+ 0, 2, 15, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+ if (btc8723b_need_dec_pwr(btcoexist))
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7);
+
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ if (BTC_WIFI_BW_HT40 == wifi_bw)
+ btc8723b2ant_tdma_duration_adjust(btcoexist, true,
+ true, 2);
+ else
+ btc8723b2ant_tdma_duration_adjust(btcoexist, true,
+ false, 3);
+ } else {
+ btc8723b2ant_tdma_duration_adjust(btcoexist, true, true, 3);
+ }
+
+ /* sw mechanism */
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, true,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, true,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, true,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, true,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void btc8723b2ant_action_hid_a2dp(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
+ 0, 2, 15, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+ if (btc8723b_need_dec_pwr(btcoexist))
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7);
+
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH))
+ btc8723b2ant_tdma_duration_adjust(btcoexist, true, false, 2);
+ else
+ btc8723b2ant_tdma_duration_adjust(btcoexist, true, true, 2);
+
+ /* sw mechanism */
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, true,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, true,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, true,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, true,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void btc8723b2ant_run_coexist_mechanism(struct btc_coexist *btcoexist)
+{
+ u8 algorithm = 0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], RunCoexistMechanism()===>\n");
+
+ if (btcoexist->manual_control) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], RunCoexistMechanism(), "
+ "return for Manual CTRL <===\n");
+ return;
+ }
+
+ if (coex_sta->under_ips) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], wifi is under IPS !!!\n");
+ return;
+ }
+
+ algorithm = btc8723b2ant_action_algorithm(btcoexist);
+ if (coex_sta->c2h_bt_inquiry_page &&
+ (BT_8723B_2ANT_COEX_ALGO_PANHS != algorithm)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT is under inquiry/page scan !!\n");
+ btc8723b2ant_action_bt_inquiry(btcoexist);
+ return;
+ } else {
+ if (coex_dm->need_recover_0x948) {
+ coex_dm->need_recover_0x948 = false;
+ btcoexist->btc_write_2byte(btcoexist, 0x948,
+ coex_dm->backup_0x948);
+ }
+ }
+
+ coex_dm->cur_algorithm = algorithm;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], Algorithm = %d\n",
+ coex_dm->cur_algorithm);
+
+ if (btc8723b2ant_is_common_action(btcoexist)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant common.\n");
+ coex_dm->auto_tdma_adjust = false;
+ } else {
+ if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], preAlgorithm=%d, "
+ "curAlgorithm=%d\n", coex_dm->pre_algorithm,
+ coex_dm->cur_algorithm);
+ coex_dm->auto_tdma_adjust = false;
+ }
+ switch (coex_dm->cur_algorithm) {
+ case BT_8723B_2ANT_COEX_ALGO_SCO:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = SCO.\n");
+ btc8723b2ant_action_sco(btcoexist);
+ break;
+ case BT_8723B_2ANT_COEX_ALGO_HID:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = HID.\n");
+ btc8723b2ant_action_hid(btcoexist);
+ break;
+ case BT_8723B_2ANT_COEX_ALGO_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, "
+ "algorithm = A2DP.\n");
+ btc8723b2ant_action_a2dp(btcoexist);
+ break;
+ case BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, "
+ "algorithm = A2DP+PAN(HS).\n");
+ btc8723b2ant_action_a2dp_pan_hs(btcoexist);
+ break;
+ case BT_8723B_2ANT_COEX_ALGO_PANEDR:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, "
+ "algorithm = PAN(EDR).\n");
+ btc8723b2ant_action_pan_edr(btcoexist);
+ break;
+ case BT_8723B_2ANT_COEX_ALGO_PANHS:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, "
+ "algorithm = HS mode.\n");
+ btc8723b2ant_action_pan_hs(btcoexist);
+ break;
+ case BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, "
+ "algorithm = PAN+A2DP.\n");
+ btc8723b2ant_action_pan_edr_a2dp(btcoexist);
+ break;
+ case BT_8723B_2ANT_COEX_ALGO_PANEDR_HID:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, "
+ "algorithm = PAN(EDR)+HID.\n");
+ btc8723b2ant_action_pan_edr_hid(btcoexist);
+ break;
+ case BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, "
+ "algorithm = HID+A2DP+PAN.\n");
+ btc8723b2ant_action_hid_a2dp_pan_edr(btcoexist);
+ break;
+ case BT_8723B_2ANT_COEX_ALGO_HID_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, "
+ "algorithm = HID+A2DP.\n");
+ btc8723b2ant_action_hid_a2dp(btcoexist);
+ break;
+ default:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, "
+ "algorithm = coexist All Off!!\n");
+ btc8723b2ant_coex_alloff(btcoexist);
+ break;
+ }
+ coex_dm->pre_algorithm = coex_dm->cur_algorithm;
+ }
+}
+
+
+
+/*********************************************************************
+ * work around function start with wa_btc8723b2ant_
+ *********************************************************************/
+/*********************************************************************
+ * extern function start with EXbtc8723b2ant_
+ *********************************************************************/
+void ex_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist)
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ u32 u32tmp = 0, fw_ver;
+ u8 u8tmp = 0;
+ u8 h2c_parameter[2] = {0};
+
+
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], 2Ant Init HW Config!!\n");
+
+ /* backup rf 0x1e value */
+ coex_dm->bt_rf0x1e_backup = btcoexist->btc_get_rf_reg(btcoexist,
+ BTC_RF_A, 0x1e,
+ 0xfffff);
+
+ /* 0x4c[23]=0, 0x4c[24]=1 Antenna control by WL/BT */
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u32tmp &= ~BIT23;
+ u32tmp |= BIT24;
+ btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp);
+
+ btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3);
+ btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1);
+
+ /* Antenna switch control parameter */
+ /* btcoexist->btc_write_4byte(btcoexist, 0x858, 0x55555555);*/
+
+ /*Force GNT_BT to low*/
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0);
+ btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
+
+ /* 0x790[5:0]=0x5 */
+ u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790);
+ u8tmp &= 0xc0;
+ u8tmp |= 0x5;
+ btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp);
+
+
+ /*Antenna config */
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+
+ /*ext switch for fw ver < 0xc */
+ if (fw_ver < 0xc00) {
+ if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) {
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c,
+ 0x3, 0x1);
+ /*Main Ant to BT for IPS case 0x4c[23]=1*/
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1,
+ 0x1);
+
+ /*tell firmware "no antenna inverse"*/
+ h2c_parameter[0] = 0;
+ h2c_parameter[1] = 1; /* ext switch type */
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ } else {
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c,
+ 0x3, 0x2);
+ /*Aux Ant to BT for IPS case 0x4c[23]=1*/
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1,
+ 0x0);
+
+ /*tell firmware "antenna inverse"*/
+ h2c_parameter[0] = 1;
+ h2c_parameter[1] = 1; /*ext switch type*/
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ }
+ } else {
+ /*ext switch always at s1 (if exist) */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, 0x3, 0x1);
+ /*Main Ant to BT for IPS case 0x4c[23]=1*/
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, 0x1);
+
+ if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) {
+ /*tell firmware "no antenna inverse"*/
+ h2c_parameter[0] = 0;
+ h2c_parameter[1] = 0; /*ext switch type*/
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ } else {
+ /*tell firmware "antenna inverse"*/
+ h2c_parameter[0] = 1;
+ h2c_parameter[1] = 0; /*ext switch type*/
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ }
+ }
+
+ /* PTA parameter */
+ btc8723b_coex_tbl_type(btcoexist, FORCE_EXEC, 0);
+
+ /* Enable counter statistics */
+ /*0x76e[3] =1, WLAN_Act control by PTA*/
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+ btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1);
+}
+
+void ex_halbtc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], Coex Mechanism Init!!\n");
+ btc8723b2ant_init_coex_dm(btcoexist);
+}
+
+void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist)
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ u8 *cli_buf = btcoexist->cli_buf;
+ u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0;
+ u32 u32tmp[4];
+ bool roam = false, scan = false;
+ bool link = false, wifi_under_5g = false;
+ bool bt_hs_on = false, wifi_busy = false;
+ s32 wifi_rssi = 0, bt_hs_rssi = 0;
+ u32 wifi_bw, wifi_traffic_dir, fa_ofdm, fa_cck;
+ u8 wifi_dot11_chnl, wifi_hs_chnl;
+ u32 fw_ver = 0, bt_patch_ver = 0;
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n ============[BT Coexist info]============");
+ CL_PRINTF(cli_buf);
+
+ if (btcoexist->manual_control) {
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n ==========[Under Manual Control]============");
+ CL_PRINTF(cli_buf);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n ==========================================");
+ CL_PRINTF(cli_buf);
+ }
+
+ if (!board_info->bt_exist) {
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!");
+ CL_PRINTF(cli_buf);
+ return;
+ }
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ",
+ "Ant PG number/ Ant mechanism:",
+ board_info->pg_ant_num, board_info->btdm_ant_num);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d",
+ "BT stack/ hci ext ver",
+ ((stack_info->profile_notified) ? "Yes" : "No"),
+ stack_info->hci_version);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)",
+ "CoexVer/ FwVer/ PatchVer",
+ glcoex_ver_date_8723b_2ant, glcoex_ver_8723b_2ant,
+ fw_ver, bt_patch_ver, bt_patch_ver);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL,
+ &wifi_dot11_chnl);
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)",
+ "Dot11 channel / HsChnl(HsMode)",
+ wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ",
+ "H2C Wifi inform bt chnl Info", coex_dm->wifi_chnl_info[0],
+ coex_dm->wifi_chnl_info[1], coex_dm->wifi_chnl_info[2]);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
+ "Wifi rssi/ HS rssi", wifi_rssi, bt_hs_rssi);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ",
+ "Wifi link/ roam/ scan", link, roam, scan);
+ CL_PRINTF(cli_buf);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION,
+ &wifi_traffic_dir);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ",
+ "Wifi status", (wifi_under_5g ? "5G" : "2.4G"),
+ ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" :
+ (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))),
+ ((!wifi_busy) ? "idle" :
+ ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ?
+ "uplink" : "downlink")));
+ CL_PRINTF(cli_buf);
+
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d",
+ "SCO/HID/PAN/A2DP",
+ bt_link_info->sco_exist, bt_link_info->hid_exist,
+ bt_link_info->pan_exist, bt_link_info->a2dp_exist);
+ CL_PRINTF(cli_buf);
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO);
+
+ bt_info_ext = coex_sta->bt_info_ext;
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s",
+ "BT Info A2DP rate",
+ (bt_info_ext&BIT0) ? "Basic rate" : "EDR rate");
+ CL_PRINTF(cli_buf);
+
+ for (i = 0; i < BT_INFO_SRC_8723B_2ANT_MAX; i++) {
+ if (coex_sta->bt_info_c2h_cnt[i]) {
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %02x %02x %02x "
+ "%02x %02x %02x %02x(%d)",
+ glbt_info_src_8723b_2ant[i],
+ coex_sta->bt_info_c2h[i][0],
+ coex_sta->bt_info_c2h[i][1],
+ coex_sta->bt_info_c2h[i][2],
+ coex_sta->bt_info_c2h[i][3],
+ coex_sta->bt_info_c2h[i][4],
+ coex_sta->bt_info_c2h[i][5],
+ coex_sta->bt_info_c2h[i][6],
+ coex_sta->bt_info_c2h_cnt[i]);
+ CL_PRINTF(cli_buf);
+ }
+ }
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s",
+ "PS state, IPS/LPS",
+ ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")),
+ ((coex_sta->under_lps ? "LPS ON" : "LPS OFF")));
+ CL_PRINTF(cli_buf);
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD);
+
+ /* Sw mechanism */
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s", "============[Sw mechanism]============");
+ CL_PRINTF(cli_buf);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ",
+ "SM1[ShRf/ LpRA/ LimDig]", coex_dm->cur_rf_rx_lpf_shrink,
+ coex_dm->cur_low_penalty_ra, coex_dm->limited_dig);
+ CL_PRINTF(cli_buf);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ",
+ "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]",
+ coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off,
+ coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl);
+ CL_PRINTF(cli_buf);
+
+ /* Fw mechanism */
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
+ "============[Fw mechanism]============");
+ CL_PRINTF(cli_buf);
+
+ ps_tdma_case = coex_dm->cur_ps_tdma;
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)",
+ "PS TDMA", coex_dm->ps_tdma_para[0],
+ coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2],
+ coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4],
+ ps_tdma_case, coex_dm->auto_tdma_adjust);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ",
+ "DecBtPwr/ IgnWlanAct", coex_dm->cur_dec_bt_pwr,
+ coex_dm->cur_ignore_wlan_act);
+ CL_PRINTF(cli_buf);
+
+ /* Hw setting */
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
+ "============[Hw setting]============");
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x",
+ "RF-A, 0x1e initVal", coex_dm->bt_rf0x1e_backup);
+ CL_PRINTF(cli_buf);
+
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778);
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x880);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+ "0x778/0x880[29:25]", u8tmp[0],
+ (u32tmp[0]&0x3e000000) >> 25);
+ CL_PRINTF(cli_buf);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x948);
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x67);
+ u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x765);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "0x948/ 0x67[5] / 0x765",
+ u32tmp[0], ((u8tmp[0]&0x20) >> 5), u8tmp[1]);
+ CL_PRINTF(cli_buf);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x92c);
+ u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x930);
+ u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x944);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]",
+ u32tmp[0]&0x3, u32tmp[1]&0xff, u32tmp[2]&0x3);
+ CL_PRINTF(cli_buf);
+
+
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x39);
+ u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40);
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x",
+ "0x38[11]/0x40/0x4c[24:23]/0x64[0]",
+ ((u8tmp[0] & 0x8)>>3), u8tmp[1],
+ ((u32tmp[0]&0x01800000)>>23), u8tmp[2]&0x1);
+ CL_PRINTF(cli_buf);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550);
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+ "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]);
+ CL_PRINTF(cli_buf);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50);
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x49c);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+ "0xc50(dig)/0x49c(null-drop)", u32tmp[0]&0xff, u8tmp[0]);
+ CL_PRINTF(cli_buf);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xda0);
+ u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xda4);
+ u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0xda8);
+ u32tmp[3] = btcoexist->btc_read_4byte(btcoexist, 0xcf0);
+
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5b);
+ u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c);
+
+ fa_ofdm = ((u32tmp[0]&0xffff0000) >> 16) +
+ ((u32tmp[1]&0xffff0000) >> 16) +
+ (u32tmp[1] & 0xffff) +
+ (u32tmp[2] & 0xffff) +
+ ((u32tmp[3]&0xffff0000) >> 16) +
+ (u32tmp[3] & 0xffff);
+ fa_cck = (u8tmp[0] << 8) + u8tmp[1];
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "OFDM-CCA/OFDM-FA/CCK-FA",
+ u32tmp[0]&0xffff, fa_ofdm, fa_cck);
+ CL_PRINTF(cli_buf);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0);
+ u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4);
+ u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8);
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x",
+ "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)",
+ u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]);
+ CL_PRINTF(cli_buf);
+
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
+ "0x770(high-pri rx/tx)",
+ coex_sta->high_priority_rx, coex_sta->high_priority_tx);
+ CL_PRINTF(cli_buf);
+ CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
+ "0x774(low-pri rx/tx)", coex_sta->low_priority_rx,
+ coex_sta->low_priority_tx);
+ CL_PRINTF(cli_buf);
+#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 1)
+ btc8723b2ant_monitor_bt_ctr(btcoexist);
+#endif
+ btcoexist->btc_disp_dbg_msg(btcoexist,
+ BTC_DBG_DISP_COEX_STATISTICS);
+}
+
+
+void ex_halbtc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (BTC_IPS_ENTER == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], IPS ENTER notify\n");
+ coex_sta->under_ips = true;
+ btc8723b2ant_coex_alloff(btcoexist);
+ } else if (BTC_IPS_LEAVE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], IPS LEAVE notify\n");
+ coex_sta->under_ips = false;
+ }
+}
+
+void ex_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (BTC_LPS_ENABLE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], LPS ENABLE notify\n");
+ coex_sta->under_lps = true;
+ } else if (BTC_LPS_DISABLE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], LPS DISABLE notify\n");
+ coex_sta->under_lps = false;
+ }
+}
+
+void ex_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (BTC_SCAN_START == type)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], SCAN START notify\n");
+ else if (BTC_SCAN_FINISH == type)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], SCAN FINISH notify\n");
+}
+
+void ex_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (BTC_ASSOCIATE_START == type)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], CONNECT START notify\n");
+ else if (BTC_ASSOCIATE_FINISH == type)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], CONNECT FINISH notify\n");
+}
+
+void btc8723b_med_stat_notify(struct btc_coexist *btcoexist,
+ u8 type)
+{
+ u8 h2c_parameter[3] = {0};
+ u32 wifi_bw;
+ u8 wifi_central_chnl;
+
+ if (BTC_MEDIA_CONNECT == type)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], MEDIA connect notify\n");
+ else
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], MEDIA disconnect notify\n");
+
+ /* only 2.4G we need to inform bt the chnl mask */
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifi_central_chnl);
+ if ((BTC_MEDIA_CONNECT == type) &&
+ (wifi_central_chnl <= 14)) {
+ h2c_parameter[0] = 0x1;
+ h2c_parameter[1] = wifi_central_chnl;
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw)
+ h2c_parameter[2] = 0x30;
+ else
+ h2c_parameter[2] = 0x20;
+ }
+
+ coex_dm->wifi_chnl_info[0] = h2c_parameter[0];
+ coex_dm->wifi_chnl_info[1] = h2c_parameter[1];
+ coex_dm->wifi_chnl_info[2] = h2c_parameter[2];
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], FW write 0x66=0x%x\n",
+ h2c_parameter[0] << 16 | h2c_parameter[1] << 8 |
+ h2c_parameter[2]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter);
+}
+
+void ex_halbtc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist,
+ u8 type)
+{
+ if (type == BTC_PACKET_DHCP)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], DHCP Packet notify\n");
+}
+
+void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmpbuf, u8 length)
+{
+ u8 bt_info = 0;
+ u8 i, rsp_source = 0;
+ bool bt_busy = false, limited_dig = false;
+ bool wifi_connected = false;
+
+ coex_sta->c2h_bt_info_req_sent = false;
+
+ rsp_source = tmpbuf[0]&0xf;
+ if (rsp_source >= BT_INFO_SRC_8723B_2ANT_MAX)
+ rsp_source = BT_INFO_SRC_8723B_2ANT_WIFI_FW;
+ coex_sta->bt_info_c2h_cnt[rsp_source]++;
+
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Bt info[%d], length=%d, hex data=[",
+ rsp_source, length);
+ for (i = 0; i < length; i++) {
+ coex_sta->bt_info_c2h[rsp_source][i] = tmpbuf[i];
+ if (i == 1)
+ bt_info = tmpbuf[i];
+ if (i == length-1)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "0x%02x]\n", tmpbuf[i]);
+ else
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "0x%02x, ", tmpbuf[i]);
+ }
+
+ if (btcoexist->manual_control) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), "
+ "return for Manual CTRL<===\n");
+ return;
+ }
+
+ if (BT_INFO_SRC_8723B_2ANT_WIFI_FW != rsp_source) {
+ coex_sta->bt_retry_cnt = /* [3:0]*/
+ coex_sta->bt_info_c2h[rsp_source][2] & 0xf;
+
+ coex_sta->bt_rssi =
+ coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10;
+
+ coex_sta->bt_info_ext =
+ coex_sta->bt_info_c2h[rsp_source][4];
+
+ /* Here we need to resend some wifi info to BT
+ * because bt is reset and loss of the info.
+ */
+ if ((coex_sta->bt_info_ext & BIT1)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT ext info bit1 check,"
+ " send wifi BW&Chnl to BT!!\n");
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ if (wifi_connected)
+ btc8723b_med_stat_notify(btcoexist,
+ BTC_MEDIA_CONNECT);
+ else
+ btc8723b_med_stat_notify(btcoexist,
+ BTC_MEDIA_DISCONNECT);
+ }
+
+ if ((coex_sta->bt_info_ext & BIT3)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT ext info bit3 check, "
+ "set BT NOT to ignore Wlan active!!\n");
+ btc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC,
+ false);
+ } else {
+ /* BT already NOT ignore Wlan active, do nothing here.*/
+ }
+#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 0)
+ if ((coex_sta->bt_info_ext & BIT4)) {
+ /* BT auto report already enabled, do nothing*/
+ } else {
+ btc8723b2ant_bt_auto_report(btcoexist, FORCE_EXEC,
+ true);
+ }
+#endif
+ }
+
+ /* check BIT2 first ==> check if bt is under inquiry or page scan*/
+ if (bt_info & BT_INFO_8723B_2ANT_B_INQ_PAGE)
+ coex_sta->c2h_bt_inquiry_page = true;
+ else
+ coex_sta->c2h_bt_inquiry_page = false;
+
+ /* set link exist status*/
+ if (!(bt_info & BT_INFO_8723B_2ANT_B_CONNECTION)) {
+ coex_sta->bt_link_exist = false;
+ coex_sta->pan_exist = false;
+ coex_sta->a2dp_exist = false;
+ coex_sta->hid_exist = false;
+ coex_sta->sco_exist = false;
+ } else { /* connection exists */
+ coex_sta->bt_link_exist = true;
+ if (bt_info & BT_INFO_8723B_2ANT_B_FTP)
+ coex_sta->pan_exist = true;
+ else
+ coex_sta->pan_exist = false;
+ if (bt_info & BT_INFO_8723B_2ANT_B_A2DP)
+ coex_sta->a2dp_exist = true;
+ else
+ coex_sta->a2dp_exist = false;
+ if (bt_info & BT_INFO_8723B_2ANT_B_HID)
+ coex_sta->hid_exist = true;
+ else
+ coex_sta->hid_exist = false;
+ if (bt_info & BT_INFO_8723B_2ANT_B_SCO_ESCO)
+ coex_sta->sco_exist = true;
+ else
+ coex_sta->sco_exist = false;
+ }
+
+ btc8723b2ant_update_bt_link_info(btcoexist);
+
+ if (!(bt_info & BT_INFO_8723B_2ANT_B_CONNECTION)) {
+ coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), "
+ "BT Non-Connected idle!!!\n");
+ /* connection exists but no busy */
+ } else if (bt_info == BT_INFO_8723B_2ANT_B_CONNECTION) {
+ coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n");
+ } else if ((bt_info & BT_INFO_8723B_2ANT_B_SCO_ESCO) ||
+ (bt_info & BT_INFO_8723B_2ANT_B_SCO_BUSY)) {
+ coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_SCO_BUSY;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n");
+ } else if (bt_info & BT_INFO_8723B_2ANT_B_ACL_BUSY) {
+ coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_ACL_BUSY;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n");
+ } else {
+ coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_MAX;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), "
+ "BT Non-Defined state!!!\n");
+ }
+
+ if ((BT_8723B_2ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) ||
+ (BT_8723B_2ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+ (BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) {
+ bt_busy = true;
+ limited_dig = true;
+ } else {
+ bt_busy = false;
+ limited_dig = false;
+ }
+
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy);
+
+ coex_dm->limited_dig = limited_dig;
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig);
+
+ btc8723b2ant_run_coexist_mechanism(btcoexist);
+}
+
+void ex_halbtc8723b2ant_stack_operation_notify(struct btc_coexist *btcoexist,
+ u8 type)
+{
+ if (BTC_STACK_OP_INQ_PAGE_PAIR_START == type)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex],StackOP Inquiry/page/pair start notify\n");
+ else if (BTC_STACK_OP_INQ_PAGE_PAIR_FINISH == type)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex],StackOP Inquiry/page/pair finish notify\n");
+}
+
+void ex_halbtc8723b2ant_halt_notify(struct btc_coexist *btcoexist)
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n");
+
+ btc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true);
+ btc8723b_med_stat_notify(btcoexist, BTC_MEDIA_DISCONNECT);
+}
+
+void ex_halbtc8723b2ant_periodical(struct btc_coexist *btcoexist)
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+ static u8 dis_ver_info_cnt;
+ u32 fw_ver = 0, bt_patch_ver = 0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], =========================="
+ "Periodical===========================\n");
+
+ if (dis_ver_info_cnt <= 5) {
+ dis_ver_info_cnt += 1;
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], ****************************"
+ "************************************\n");
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], Ant PG Num/ Ant Mech/ "
+ "Ant Pos = %d/ %d/ %d\n", board_info->pg_ant_num,
+ board_info->btdm_ant_num, board_info->btdm_ant_pos);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], BT stack/ hci ext ver = %s / %d\n",
+ ((stack_info->profile_notified) ? "Yes" : "No"),
+ stack_info->hci_version);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER,
+ &bt_patch_ver);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], CoexVer/ FwVer/ PatchVer = "
+ "%d_%x/ 0x%x/ 0x%x(%d)\n",
+ glcoex_ver_date_8723b_2ant, glcoex_ver_8723b_2ant,
+ fw_ver, bt_patch_ver, bt_patch_ver);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], *****************************"
+ "***********************************\n");
+ }
+
+#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 0)
+ btc8723b2ant_query_bt_info(btcoexist);
+ btc8723b2ant_monitor_bt_ctr(btcoexist);
+ btc8723b2ant_monitor_bt_enable_disable(btcoexist);
+#else
+ if (btc8723b2ant_is_wifi_status_changed(btcoexist) ||
+ coex_dm->auto_tdma_adjust)
+ btc8723b2ant_run_coexist_mechanism(btcoexist);
+#endif
+}
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h
new file mode 100644
index 000000000000..e0ad8e545f82
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h
@@ -0,0 +1,173 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef _HAL8723B_2_ANT
+#define _HAL8723B_2_ANT
+
+/************************************************************************
+ * The following is for 8723B 2Ant BT Co-exist definition
+ ************************************************************************/
+#define BT_AUTO_REPORT_ONLY_8723B_2ANT 1
+
+#define BT_INFO_8723B_2ANT_B_FTP BIT7
+#define BT_INFO_8723B_2ANT_B_A2DP BIT6
+#define BT_INFO_8723B_2ANT_B_HID BIT5
+#define BT_INFO_8723B_2ANT_B_SCO_BUSY BIT4
+#define BT_INFO_8723B_2ANT_B_ACL_BUSY BIT3
+#define BT_INFO_8723B_2ANT_B_INQ_PAGE BIT2
+#define BT_INFO_8723B_2ANT_B_SCO_ESCO BIT1
+#define BT_INFO_8723B_2ANT_B_CONNECTION BIT0
+
+#define BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT 2
+
+enum BT_INFO_SRC_8723B_2ANT {
+ BT_INFO_SRC_8723B_2ANT_WIFI_FW = 0x0,
+ BT_INFO_SRC_8723B_2ANT_BT_RSP = 0x1,
+ BT_INFO_SRC_8723B_2ANT_BT_ACTIVE_SEND = 0x2,
+ BT_INFO_SRC_8723B_2ANT_MAX
+};
+
+enum BT_8723B_2ANT_BT_STATUS {
+ BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0,
+ BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1,
+ BT_8723B_2ANT_BT_STATUS_INQ_PAGE = 0x2,
+ BT_8723B_2ANT_BT_STATUS_ACL_BUSY = 0x3,
+ BT_8723B_2ANT_BT_STATUS_SCO_BUSY = 0x4,
+ BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5,
+ BT_8723B_2ANT_BT_STATUS_MAX
+};
+
+enum BT_8723B_2ANT_COEX_ALGO {
+ BT_8723B_2ANT_COEX_ALGO_UNDEFINED = 0x0,
+ BT_8723B_2ANT_COEX_ALGO_SCO = 0x1,
+ BT_8723B_2ANT_COEX_ALGO_HID = 0x2,
+ BT_8723B_2ANT_COEX_ALGO_A2DP = 0x3,
+ BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS = 0x4,
+ BT_8723B_2ANT_COEX_ALGO_PANEDR = 0x5,
+ BT_8723B_2ANT_COEX_ALGO_PANHS = 0x6,
+ BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP = 0x7,
+ BT_8723B_2ANT_COEX_ALGO_PANEDR_HID = 0x8,
+ BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9,
+ BT_8723B_2ANT_COEX_ALGO_HID_A2DP = 0xa,
+ BT_8723B_2ANT_COEX_ALGO_MAX = 0xb,
+};
+
+struct coex_dm_8723b_2ant {
+ /* fw mechanism */
+ bool pre_dec_bt_pwr;
+ bool cur_dec_bt_pwr;
+ u8 pre_fw_dac_swing_lvl;
+ u8 cur_fw_dac_swing_lvl;
+ bool cur_ignore_wlan_act;
+ bool pre_ignore_wlan_act;
+ u8 pre_ps_tdma;
+ u8 cur_ps_tdma;
+ u8 ps_tdma_para[5];
+ u8 tdma_adj_type;
+ bool reset_tdma_adjust;
+ bool auto_tdma_adjust;
+ bool pre_ps_tdma_on;
+ bool cur_ps_tdma_on;
+ bool pre_bt_auto_report;
+ bool cur_bt_auto_report;
+
+ /* sw mechanism */
+ bool pre_rf_rx_lpf_shrink;
+ bool cur_rf_rx_lpf_shrink;
+ u32 bt_rf0x1e_backup;
+ bool pre_low_penalty_ra;
+ bool cur_low_penalty_ra;
+ bool pre_dac_swing_on;
+ u32 pre_dac_swing_lvl;
+ bool cur_dac_swing_on;
+ u32 cur_dac_swing_lvl;
+ bool pre_adc_back_off;
+ bool cur_adc_back_off;
+ bool pre_agc_table_en;
+ bool cur_agc_table_en;
+ u32 pre_val0x6c0;
+ u32 cur_val0x6c0;
+ u32 pre_val0x6c4;
+ u32 cur_val0x6c4;
+ u32 pre_val0x6c8;
+ u32 cur_val0x6c8;
+ u8 pre_val0x6cc;
+ u8 cur_val0x6cc;
+ bool limited_dig;
+
+ /* algorithm related */
+ u8 pre_algorithm;
+ u8 cur_algorithm;
+ u8 bt_status;
+ u8 wifi_chnl_info[3];
+
+ bool need_recover_0x948;
+ u16 backup_0x948;
+};
+
+struct coex_sta_8723b_2ant {
+ bool bt_link_exist;
+ bool sco_exist;
+ bool a2dp_exist;
+ bool hid_exist;
+ bool pan_exist;
+
+ bool under_lps;
+ bool under_ips;
+ u32 high_priority_tx;
+ u32 high_priority_rx;
+ u32 low_priority_tx;
+ u32 low_priority_rx;
+ u8 bt_rssi;
+ u8 pre_bt_rssi_state;
+ u8 pre_wifi_rssi_state[4];
+ bool c2h_bt_info_req_sent;
+ u8 bt_info_c2h[BT_INFO_SRC_8723B_2ANT_MAX][10];
+ u32 bt_info_c2h_cnt[BT_INFO_SRC_8723B_2ANT_MAX];
+ bool c2h_bt_inquiry_page;
+ u8 bt_retry_cnt;
+ u8 bt_info_ext;
+};
+
+/*********************************************************************
+ * The following is interface which will notify coex module.
+ *********************************************************************/
+void ex_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist);
+void ex_halbtc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist);
+void ex_halbtc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type);
+void btc8723b_med_stat_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist,
+ u8 type);
+void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmpbuf, u8 length);
+void ex_halbtc8723b2ant_stack_operation_notify(struct btc_coexist *btcoexist,
+ u8 type);
+void ex_halbtc8723b2ant_halt_notify(struct btc_coexist *btcoexist);
+void ex_halbtc8723b2ant_periodical(struct btc_coexist *btcoexist);
+void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c
new file mode 100644
index 000000000000..b6722de64a31
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c
@@ -0,0 +1,1011 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2013 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ ******************************************************************************/
+
+#include "halbt_precomp.h"
+
+/***********************************************
+ * Global variables
+ ***********************************************/
+
+struct btc_coexist gl_bt_coexist;
+
+u32 btc_dbg_type[BTC_MSG_MAX];
+static u8 btc_dbg_buf[100];
+
+/***************************************************
+ * Debug related function
+ ***************************************************/
+static bool halbtc_is_bt_coexist_available(struct btc_coexist *btcoexist)
+{
+ if (!btcoexist->binded || NULL == btcoexist->adapter)
+ return false;
+
+ return true;
+}
+
+static bool halbtc_is_wifi_busy(struct rtl_priv *rtlpriv)
+{
+ if (rtlpriv->link_info.busytraffic)
+ return true;
+ else
+ return false;
+}
+
+static void halbtc_dbg_init(void)
+{
+ u8 i;
+
+ for (i = 0; i < BTC_MSG_MAX; i++)
+ btc_dbg_type[i] = 0;
+
+ btc_dbg_type[BTC_MSG_INTERFACE] =
+/* INTF_INIT | */
+/* INTF_NOTIFY | */
+ 0;
+
+ btc_dbg_type[BTC_MSG_ALGORITHM] =
+/* ALGO_BT_RSSI_STATE | */
+/* ALGO_WIFI_RSSI_STATE | */
+/* ALGO_BT_MONITOR | */
+/* ALGO_TRACE | */
+/* ALGO_TRACE_FW | */
+/* ALGO_TRACE_FW_DETAIL | */
+/* ALGO_TRACE_FW_EXEC | */
+/* ALGO_TRACE_SW | */
+/* ALGO_TRACE_SW_DETAIL | */
+/* ALGO_TRACE_SW_EXEC | */
+ 0;
+}
+
+static bool halbtc_is_bt40(struct rtl_priv *adapter)
+{
+ struct rtl_priv *rtlpriv = adapter;
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ bool is_ht40 = true;
+ enum ht_channel_width bw = rtlphy->current_chan_bw;
+
+ if (bw == HT_CHANNEL_WIDTH_20)
+ is_ht40 = false;
+ else if (bw == HT_CHANNEL_WIDTH_20_40)
+ is_ht40 = true;
+
+ return is_ht40;
+}
+
+static bool halbtc_legacy(struct rtl_priv *adapter)
+{
+ struct rtl_priv *rtlpriv = adapter;
+ struct rtl_mac *mac = rtl_mac(rtlpriv);
+
+ bool is_legacy = false;
+
+ if ((mac->mode == WIRELESS_MODE_B) || (mac->mode == WIRELESS_MODE_B))
+ is_legacy = true;
+
+ return is_legacy;
+}
+
+bool halbtc_is_wifi_uplink(struct rtl_priv *adapter)
+{
+ struct rtl_priv *rtlpriv = adapter;
+
+ if (rtlpriv->link_info.tx_busy_traffic)
+ return true;
+ else
+ return false;
+}
+
+static u32 halbtc_get_wifi_bw(struct btc_coexist *btcoexist)
+{
+ struct rtl_priv *rtlpriv =
+ (struct rtl_priv *)btcoexist->adapter;
+ u32 wifi_bw = BTC_WIFI_BW_HT20;
+
+ if (halbtc_is_bt40(rtlpriv)) {
+ wifi_bw = BTC_WIFI_BW_HT40;
+ } else {
+ if (halbtc_legacy(rtlpriv))
+ wifi_bw = BTC_WIFI_BW_LEGACY;
+ else
+ wifi_bw = BTC_WIFI_BW_HT20;
+ }
+ return wifi_bw;
+}
+
+static u8 halbtc_get_wifi_central_chnl(struct btc_coexist *btcoexist)
+{
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u8 chnl = 1;
+
+ if (rtlphy->current_channel != 0)
+ chnl = rtlphy->current_channel;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "static halbtc_get_wifi_central_chnl:%d\n", chnl);
+ return chnl;
+}
+
+static void halbtc_leave_lps(struct btc_coexist *btcoexist)
+{
+ struct rtl_priv *rtlpriv;
+ struct rtl_ps_ctl *ppsc;
+ bool ap_enable = false;
+
+ rtlpriv = btcoexist->adapter;
+ ppsc = rtl_psc(rtlpriv);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE,
+ &ap_enable);
+
+ if (ap_enable) {
+ pr_info("halbtc_leave_lps()<--dont leave lps under AP mode\n");
+ return;
+ }
+
+ btcoexist->bt_info.bt_ctrl_lps = true;
+ btcoexist->bt_info.bt_lps_on = false;
+}
+
+static void halbtc_enter_lps(struct btc_coexist *btcoexist)
+{
+ struct rtl_priv *rtlpriv;
+ struct rtl_ps_ctl *ppsc;
+ bool ap_enable = false;
+
+ rtlpriv = btcoexist->adapter;
+ ppsc = rtl_psc(rtlpriv);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE,
+ &ap_enable);
+
+ if (ap_enable) {
+ pr_info("halbtc_enter_lps()<--dont enter lps under AP mode\n");
+ return;
+ }
+
+ btcoexist->bt_info.bt_ctrl_lps = true;
+ btcoexist->bt_info.bt_lps_on = false;
+}
+
+static void halbtc_normal_lps(struct btc_coexist *btcoexist)
+{
+ if (btcoexist->bt_info.bt_ctrl_lps) {
+ btcoexist->bt_info.bt_lps_on = false;
+ btcoexist->bt_info.bt_ctrl_lps = false;
+ }
+}
+
+static void halbtc_leave_low_power(void)
+{
+}
+
+static void halbtc_nomal_low_power(void)
+{
+}
+
+static void halbtc_disable_low_power(void)
+{
+}
+
+static void halbtc_aggregation_check(void)
+{
+}
+
+static u32 halbtc_get_bt_patch_version(struct btc_coexist *btcoexist)
+{
+ return 0;
+}
+
+static s32 halbtc_get_wifi_rssi(struct rtl_priv *adapter)
+{
+ struct rtl_priv *rtlpriv = adapter;
+ s32 undec_sm_pwdb = 0;
+
+ if (rtlpriv->mac80211.link_state >= MAC80211_LINKED)
+ undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;
+ else /* associated entry pwdb */
+ undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;
+ return undec_sm_pwdb;
+}
+
+static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf)
+{
+ struct btc_coexist *btcoexist = (struct btc_coexist *)void_btcoexist;
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtlpriv);
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+ bool *bool_tmp = (bool *)out_buf;
+ int *s32_tmp = (int *)out_buf;
+ u32 *u32_tmp = (u32 *)out_buf;
+ u8 *u8_tmp = (u8 *)out_buf;
+ bool tmp = false;
+
+ if (!halbtc_is_bt_coexist_available(btcoexist))
+ return false;
+
+ switch (get_type) {
+ case BTC_GET_BL_HS_OPERATION:
+ *bool_tmp = false;
+ break;
+ case BTC_GET_BL_HS_CONNECTING:
+ *bool_tmp = false;
+ break;
+ case BTC_GET_BL_WIFI_CONNECTED:
+ if (rtlpriv->mac80211.link_state >= MAC80211_LINKED)
+ tmp = true;
+ *bool_tmp = tmp;
+ break;
+ case BTC_GET_BL_WIFI_BUSY:
+ if (halbtc_is_wifi_busy(rtlpriv))
+ *bool_tmp = true;
+ else
+ *bool_tmp = false;
+ break;
+ case BTC_GET_BL_WIFI_SCAN:
+ if (mac->act_scanning)
+ *bool_tmp = true;
+ else
+ *bool_tmp = false;
+ break;
+ case BTC_GET_BL_WIFI_LINK:
+ if (mac->link_state == MAC80211_LINKING)
+ *bool_tmp = true;
+ else
+ *bool_tmp = false;
+ break;
+ case BTC_GET_BL_WIFI_ROAM: /*TODO*/
+ if (mac->link_state == MAC80211_LINKING)
+ *bool_tmp = true;
+ else
+ *bool_tmp = false;
+ break;
+ case BTC_GET_BL_WIFI_4_WAY_PROGRESS: /*TODO*/
+ *bool_tmp = false;
+
+ break;
+ case BTC_GET_BL_WIFI_UNDER_5G:
+ *bool_tmp = false; /*TODO*/
+
+ case BTC_GET_BL_WIFI_DHCP: /*TODO*/
+ break;
+ case BTC_GET_BL_WIFI_SOFTAP_IDLE:
+ *bool_tmp = true;
+ break;
+ case BTC_GET_BL_WIFI_SOFTAP_LINKING:
+ *bool_tmp = false;
+ break;
+ case BTC_GET_BL_WIFI_IN_EARLY_SUSPEND:
+ *bool_tmp = false;
+ break;
+ case BTC_GET_BL_WIFI_AP_MODE_ENABLE:
+ *bool_tmp = false;
+ break;
+ case BTC_GET_BL_WIFI_ENABLE_ENCRYPTION:
+ if (NO_ENCRYPTION == rtlpriv->sec.pairwise_enc_algorithm)
+ *bool_tmp = false;
+ else
+ *bool_tmp = true;
+ break;
+ case BTC_GET_BL_WIFI_UNDER_B_MODE:
+ *bool_tmp = false; /*TODO*/
+ break;
+ case BTC_GET_BL_EXT_SWITCH:
+ *bool_tmp = false;
+ break;
+ case BTC_GET_S4_WIFI_RSSI:
+ *s32_tmp = halbtc_get_wifi_rssi(rtlpriv);
+ break;
+ case BTC_GET_S4_HS_RSSI: /*TODO*/
+ *s32_tmp = halbtc_get_wifi_rssi(rtlpriv);
+ break;
+ case BTC_GET_U4_WIFI_BW:
+ *u32_tmp = halbtc_get_wifi_bw(btcoexist);
+ break;
+ case BTC_GET_U4_WIFI_TRAFFIC_DIRECTION:
+ if (halbtc_is_wifi_uplink(rtlpriv))
+ *u32_tmp = BTC_WIFI_TRAFFIC_TX;
+ else
+ *u32_tmp = BTC_WIFI_TRAFFIC_RX;
+ break;
+ case BTC_GET_U4_WIFI_FW_VER:
+ *u32_tmp = rtlhal->fw_version;
+ break;
+ case BTC_GET_U4_BT_PATCH_VER:
+ *u32_tmp = halbtc_get_bt_patch_version(btcoexist);
+ break;
+ case BTC_GET_U1_WIFI_DOT11_CHNL:
+ *u8_tmp = rtlphy->current_channel;
+ break;
+ case BTC_GET_U1_WIFI_CENTRAL_CHNL:
+ *u8_tmp = halbtc_get_wifi_central_chnl(btcoexist);
+ break;
+ case BTC_GET_U1_WIFI_HS_CHNL:
+ *u8_tmp = 1;/*BT_OperateChnl(rtlpriv);*/
+ break;
+ case BTC_GET_U1_MAC_PHY_MODE:
+ *u8_tmp = BTC_MP_UNKNOWN;
+ break;
+
+ /************* 1Ant **************/
+ case BTC_GET_U1_LPS_MODE:
+ *u8_tmp = btcoexist->pwr_mode_val[0];
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf)
+{
+ struct btc_coexist *btcoexist = (struct btc_coexist *)void_btcoexist;
+ bool *bool_tmp = (bool *)in_buf;
+ u8 *u8_tmp = (u8 *)in_buf;
+ u32 *u32_tmp = (u32 *)in_buf;
+
+ if (!halbtc_is_bt_coexist_available(btcoexist))
+ return false;
+
+ switch (set_type) {
+ /* set some bool type variables. */
+ case BTC_SET_BL_BT_DISABLE:
+ btcoexist->bt_info.bt_disabled = *bool_tmp;
+ break;
+ case BTC_SET_BL_BT_TRAFFIC_BUSY:
+ btcoexist->bt_info.bt_busy = *bool_tmp;
+ break;
+ case BTC_SET_BL_BT_LIMITED_DIG:
+ btcoexist->bt_info.limited_dig = *bool_tmp;
+ break;
+ case BTC_SET_BL_FORCE_TO_ROAM:
+ btcoexist->bt_info.force_to_roam = *bool_tmp;
+ break;
+ case BTC_SET_BL_TO_REJ_AP_AGG_PKT:
+ btcoexist->bt_info.reject_agg_pkt = *bool_tmp;
+ break;
+ case BTC_SET_BL_BT_CTRL_AGG_SIZE:
+ btcoexist->bt_info.b_bt_ctrl_buf_size = *bool_tmp;
+ break;
+ case BTC_SET_BL_INC_SCAN_DEV_NUM:
+ btcoexist->bt_info.increase_scan_dev_num = *bool_tmp;
+ break;
+ /* set some u1Byte type variables. */
+ case BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON:
+ btcoexist->bt_info.rssi_adjust_for_agc_table_on = *u8_tmp;
+ break;
+ case BTC_SET_U1_AGG_BUF_SIZE:
+ btcoexist->bt_info.agg_buf_size = *u8_tmp;
+ break;
+ /* the following are some action which will be triggered */
+ case BTC_SET_ACT_GET_BT_RSSI:
+ /*BTHCI_SendGetBtRssiEvent(rtlpriv);*/
+ break;
+ case BTC_SET_ACT_AGGREGATE_CTRL:
+ halbtc_aggregation_check();
+ break;
+
+ /* 1Ant */
+ case BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE:
+ btcoexist->bt_info.rssi_adjust_for_1ant_coex_type = *u8_tmp;
+ break;
+ case BTC_SET_UI_SCAN_SIG_COMPENSATION:
+ /* rtlpriv->mlmepriv.scan_compensation = *u8_tmp; */
+ break;
+ case BTC_SET_U1_1ANT_LPS:
+ btcoexist->bt_info.lps_1ant = *u8_tmp;
+ break;
+ case BTC_SET_U1_1ANT_RPWM:
+ btcoexist->bt_info.rpwm_1ant = *u8_tmp;
+ break;
+ /* the following are some action which will be triggered */
+ case BTC_SET_ACT_LEAVE_LPS:
+ halbtc_leave_lps(btcoexist);
+ break;
+ case BTC_SET_ACT_ENTER_LPS:
+ halbtc_enter_lps(btcoexist);
+ break;
+ case BTC_SET_ACT_NORMAL_LPS:
+ halbtc_normal_lps(btcoexist);
+ break;
+ case BTC_SET_ACT_DISABLE_LOW_POWER:
+ halbtc_disable_low_power();
+ break;
+ case BTC_SET_ACT_UPDATE_ra_mask:
+ btcoexist->bt_info.ra_mask = *u32_tmp;
+ break;
+ case BTC_SET_ACT_SEND_MIMO_PS:
+ break;
+ case BTC_SET_ACT_INC_FORCE_EXEC_PWR_CMD_CNT:
+ btcoexist->bt_info.force_exec_pwr_cmd_cnt++;
+ break;
+ case BTC_SET_ACT_CTRL_BT_INFO: /*wait for 8812/8821*/
+ break;
+ case BTC_SET_ACT_CTRL_BT_COEX:
+ break;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+static void halbtc_display_coex_statistics(struct btc_coexist *btcoexist)
+{
+}
+
+static void halbtc_display_bt_link_info(struct btc_coexist *btcoexist)
+{
+}
+
+static void halbtc_display_bt_fw_info(struct btc_coexist *btcoexist)
+{
+}
+
+static void halbtc_display_fw_pwr_mode_cmd(struct btc_coexist *btcoexist)
+{
+}
+
+/************************************************************
+ * IO related function
+ ************************************************************/
+static u8 halbtc_read_1byte(void *bt_context, u32 reg_addr)
+{
+ struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+ return rtl_read_byte(rtlpriv, reg_addr);
+}
+
+static u16 halbtc_read_2byte(void *bt_context, u32 reg_addr)
+{
+ struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+ return rtl_read_word(rtlpriv, reg_addr);
+}
+
+static u32 halbtc_read_4byte(void *bt_context, u32 reg_addr)
+{
+ struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+ return rtl_read_dword(rtlpriv, reg_addr);
+}
+
+static void halbtc_write_1byte(void *bt_context, u32 reg_addr, u8 data)
+{
+ struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+ rtl_write_byte(rtlpriv, reg_addr, data);
+}
+
+static void halbtc_bitmask_write_1byte(void *bt_context, u32 reg_addr,
+ u32 bit_mask, u8 data)
+{
+ struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+ u8 original_value, bit_shift = 0;
+ u8 i;
+
+ if (bit_mask != MASKDWORD) {/*if not "double word" write*/
+ original_value = rtl_read_byte(rtlpriv, reg_addr);
+ for (i = 0; i <= 7; i++) {
+ if ((bit_mask>>i) & 0x1)
+ break;
+ }
+ bit_shift = i;
+ data = (original_value & (~bit_mask)) |
+ ((data << bit_shift) & bit_mask);
+ }
+ rtl_write_byte(rtlpriv, reg_addr, data);
+}
+
+static void halbtc_write_2byte(void *bt_context, u32 reg_addr, u16 data)
+{
+ struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+ rtl_write_word(rtlpriv, reg_addr, data);
+}
+
+static void halbtc_write_4byte(void *bt_context, u32 reg_addr, u32 data)
+{
+ struct btc_coexist *btcoexist =
+ (struct btc_coexist *)bt_context;
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+ rtl_write_dword(rtlpriv, reg_addr, data);
+}
+
+static void halbtc_set_bbreg(void *bt_context, u32 reg_addr, u32 bit_mask,
+ u32 data)
+{
+ struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+ rtl_set_bbreg(rtlpriv->mac80211.hw, reg_addr, bit_mask, data);
+}
+
+static u32 halbtc_get_bbreg(void *bt_context, u32 reg_addr, u32 bit_mask)
+{
+ struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+ return rtl_get_bbreg(rtlpriv->mac80211.hw, reg_addr, bit_mask);
+}
+
+static void halbtc_set_rfreg(void *bt_context, u8 rf_path, u32 reg_addr,
+ u32 bit_mask, u32 data)
+{
+ struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+ rtl_set_rfreg(rtlpriv->mac80211.hw, rf_path, reg_addr, bit_mask, data);
+}
+
+static u32 halbtc_get_rfreg(void *bt_context, u8 rf_path, u32 reg_addr,
+ u32 bit_mask)
+{
+ struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+ return rtl_get_rfreg(rtlpriv->mac80211.hw, rf_path, reg_addr, bit_mask);
+}
+
+static void halbtc_fill_h2c_cmd(void *bt_context, u8 element_id,
+ u32 cmd_len, u8 *cmd_buf)
+{
+ struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+ rtlpriv->cfg->ops->fill_h2c_cmd(rtlpriv->mac80211.hw, element_id,
+ cmd_len, cmd_buf);
+}
+
+static void halbtc_display_dbg_msg(void *bt_context, u8 disp_type)
+{
+ struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+ switch (disp_type) {
+ case BTC_DBG_DISP_COEX_STATISTICS:
+ halbtc_display_coex_statistics(btcoexist);
+ break;
+ case BTC_DBG_DISP_BT_LINK_INFO:
+ halbtc_display_bt_link_info(btcoexist);
+ break;
+ case BTC_DBG_DISP_BT_FW_VER:
+ halbtc_display_bt_fw_info(btcoexist);
+ break;
+ case BTC_DBG_DISP_FW_PWR_MODE_CMD:
+ halbtc_display_fw_pwr_mode_cmd(btcoexist);
+ break;
+ default:
+ break;
+ }
+}
+
+/*****************************************************************
+ * Extern functions called by other module
+ *****************************************************************/
+bool exhalbtc_initlize_variables(struct rtl_priv *adapter)
+{
+ struct btc_coexist *btcoexist = &gl_bt_coexist;
+
+ btcoexist->statistics.cnt_bind++;
+
+ halbtc_dbg_init();
+
+ if (btcoexist->binded)
+ return false;
+ else
+ btcoexist->binded = true;
+
+#if (defined(CONFIG_PCI_HCI))
+ btcoexist->chip_interface = BTC_INTF_PCI;
+#elif (defined(CONFIG_USB_HCI))
+ btcoexist->chip_interface = BTC_INTF_USB;
+#elif (defined(CONFIG_SDIO_HCI))
+ btcoexist->chip_interface = BTC_INTF_SDIO;
+#elif (defined(CONFIG_GSPI_HCI))
+ btcoexist->chip_interface = BTC_INTF_GSPI;
+#else
+ btcoexist->chip_interface = BTC_INTF_UNKNOWN;
+#endif
+
+ if (NULL == btcoexist->adapter)
+ btcoexist->adapter = adapter;
+
+ btcoexist->stack_info.profile_notified = false;
+
+ btcoexist->btc_read_1byte = halbtc_read_1byte;
+ btcoexist->btc_write_1byte = halbtc_write_1byte;
+ btcoexist->btc_write_1byte_bitmask = halbtc_bitmask_write_1byte;
+ btcoexist->btc_read_2byte = halbtc_read_2byte;
+ btcoexist->btc_write_2byte = halbtc_write_2byte;
+ btcoexist->btc_read_4byte = halbtc_read_4byte;
+ btcoexist->btc_write_4byte = halbtc_write_4byte;
+
+ btcoexist->btc_set_bb_reg = halbtc_set_bbreg;
+ btcoexist->btc_get_bb_reg = halbtc_get_bbreg;
+
+ btcoexist->btc_set_rf_reg = halbtc_set_rfreg;
+ btcoexist->btc_get_rf_reg = halbtc_get_rfreg;
+
+ btcoexist->btc_fill_h2c = halbtc_fill_h2c_cmd;
+ btcoexist->btc_disp_dbg_msg = halbtc_display_dbg_msg;
+
+ btcoexist->btc_get = halbtc_get;
+ btcoexist->btc_set = halbtc_set;
+
+ btcoexist->cli_buf = &btc_dbg_buf[0];
+
+ btcoexist->bt_info.b_bt_ctrl_buf_size = false;
+ btcoexist->bt_info.agg_buf_size = 5;
+
+ btcoexist->bt_info.increase_scan_dev_num = false;
+ return true;
+}
+
+void exhalbtc_init_hw_config(struct btc_coexist *btcoexist)
+{
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+
+ if (!halbtc_is_bt_coexist_available(btcoexist))
+ return;
+
+ btcoexist->statistics.cnt_init_hw_config++;
+
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+ ex_halbtc8723b2ant_init_hwconfig(btcoexist);
+}
+
+void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist)
+{
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+
+ if (!halbtc_is_bt_coexist_available(btcoexist))
+ return;
+
+ btcoexist->statistics.cnt_init_coex_dm++;
+
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+ ex_halbtc8723b2ant_init_coex_dm(btcoexist);
+
+ btcoexist->initilized = true;
+}
+
+void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+ u8 ips_type;
+
+ if (!halbtc_is_bt_coexist_available(btcoexist))
+ return;
+ btcoexist->statistics.cnt_ips_notify++;
+ if (btcoexist->manual_control)
+ return;
+
+ if (ERFOFF == type)
+ ips_type = BTC_IPS_ENTER;
+ else
+ ips_type = BTC_IPS_LEAVE;
+
+ halbtc_leave_low_power();
+
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+ ex_halbtc8723b2ant_ips_notify(btcoexist, ips_type);
+
+ halbtc_nomal_low_power();
+}
+
+void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+ u8 lps_type;
+
+ if (!halbtc_is_bt_coexist_available(btcoexist))
+ return;
+ btcoexist->statistics.cnt_lps_notify++;
+ if (btcoexist->manual_control)
+ return;
+
+ if (EACTIVE == type)
+ lps_type = BTC_LPS_DISABLE;
+ else
+ lps_type = BTC_LPS_ENABLE;
+
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+ ex_halbtc8723b2ant_lps_notify(btcoexist, lps_type);
+}
+
+void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+ u8 scan_type;
+
+ if (!halbtc_is_bt_coexist_available(btcoexist))
+ return;
+ btcoexist->statistics.cnt_scan_notify++;
+ if (btcoexist->manual_control)
+ return;
+
+ if (type)
+ scan_type = BTC_SCAN_START;
+ else
+ scan_type = BTC_SCAN_FINISH;
+
+ halbtc_leave_low_power();
+
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+ ex_halbtc8723b2ant_scan_notify(btcoexist, scan_type);
+
+ halbtc_nomal_low_power();
+}
+
+void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action)
+{
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+ u8 asso_type;
+
+ if (!halbtc_is_bt_coexist_available(btcoexist))
+ return;
+ btcoexist->statistics.cnt_connect_notify++;
+ if (btcoexist->manual_control)
+ return;
+
+ if (action)
+ asso_type = BTC_ASSOCIATE_START;
+ else
+ asso_type = BTC_ASSOCIATE_FINISH;
+
+ halbtc_leave_low_power();
+
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+ ex_halbtc8723b2ant_connect_notify(btcoexist, asso_type);
+}
+
+void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist,
+ enum _RT_MEDIA_STATUS media_status)
+{
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+ u8 status;
+
+ if (!halbtc_is_bt_coexist_available(btcoexist))
+ return;
+ btcoexist->statistics.cnt_media_status_notify++;
+ if (btcoexist->manual_control)
+ return;
+
+ if (RT_MEDIA_CONNECT == media_status)
+ status = BTC_MEDIA_CONNECT;
+ else
+ status = BTC_MEDIA_DISCONNECT;
+
+ halbtc_leave_low_power();
+
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+ btc8723b_med_stat_notify(btcoexist, status);
+
+ halbtc_nomal_low_power();
+}
+
+void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type)
+{
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+ u8 packet_type;
+
+ if (!halbtc_is_bt_coexist_available(btcoexist))
+ return;
+ btcoexist->statistics.cnt_special_packet_notify++;
+ if (btcoexist->manual_control)
+ return;
+
+ packet_type = BTC_PACKET_DHCP;
+
+ halbtc_leave_low_power();
+
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+ ex_halbtc8723b2ant_special_packet_notify(btcoexist,
+ packet_type);
+
+ halbtc_nomal_low_power();
+}
+
+void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmp_buf, u8 length)
+{
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+ if (!halbtc_is_bt_coexist_available(btcoexist))
+ return;
+ btcoexist->statistics.cnt_bt_info_notify++;
+
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+ ex_halbtc8723b2ant_bt_info_notify(btcoexist, tmp_buf, length);
+}
+
+void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+ u8 stack_op_type;
+
+ if (!halbtc_is_bt_coexist_available(btcoexist))
+ return;
+ btcoexist->statistics.cnt_stack_operation_notify++;
+ if (btcoexist->manual_control)
+ return;
+
+ stack_op_type = BTC_STACK_OP_NONE;
+
+ halbtc_leave_low_power();
+
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+ ex_halbtc8723b2ant_stack_operation_notify(btcoexist,
+ stack_op_type);
+
+ halbtc_nomal_low_power();
+}
+
+void exhalbtc_halt_notify(struct btc_coexist *btcoexist)
+{
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+ if (!halbtc_is_bt_coexist_available(btcoexist))
+ return;
+
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+ ex_halbtc8723b2ant_halt_notify(btcoexist);
+}
+
+void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state)
+{
+ if (!halbtc_is_bt_coexist_available(btcoexist))
+ return;
+}
+
+void exhalbtc_periodical(struct btc_coexist *btcoexist)
+{
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+ if (!halbtc_is_bt_coexist_available(btcoexist))
+ return;
+ btcoexist->statistics.cnt_periodical++;
+
+ halbtc_leave_low_power();
+
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+ ex_halbtc8723b2ant_periodical(btcoexist);
+
+ halbtc_nomal_low_power();
+}
+
+void exhalbtc_dbg_control(struct btc_coexist *btcoexist,
+ u8 code, u8 len, u8 *data)
+{
+ if (!halbtc_is_bt_coexist_available(btcoexist))
+ return;
+ btcoexist->statistics.cnt_dbg_ctrl++;
+}
+
+void exhalbtc_stack_update_profile_info(void)
+{
+}
+
+void exhalbtc_update_min_bt_rssi(char bt_rssi)
+{
+ struct btc_coexist *btcoexist = &gl_bt_coexist;
+
+ if (!halbtc_is_bt_coexist_available(btcoexist))
+ return;
+
+ btcoexist->stack_info.min_bt_rssi = bt_rssi;
+}
+
+void exhalbtc_set_hci_version(u16 hci_version)
+{
+ struct btc_coexist *btcoexist = &gl_bt_coexist;
+
+ if (!halbtc_is_bt_coexist_available(btcoexist))
+ return;
+
+ btcoexist->stack_info.hci_version = hci_version;
+}
+
+void exhalbtc_set_bt_patch_version(u16 bt_hci_version, u16 bt_patch_version)
+{
+ struct btc_coexist *btcoexist = &gl_bt_coexist;
+
+ if (!halbtc_is_bt_coexist_available(btcoexist))
+ return;
+
+ btcoexist->bt_info.bt_real_fw_ver = bt_patch_version;
+ btcoexist->bt_info.bt_hci_ver = bt_hci_version;
+}
+
+void exhalbtc_set_bt_exist(bool bt_exist)
+{
+ gl_bt_coexist.board_info.bt_exist = bt_exist;
+}
+
+void exhalbtc_set_chip_type(u8 chip_type)
+{
+ switch (chip_type) {
+ default:
+ case BT_2WIRE:
+ case BT_ISSC_3WIRE:
+ case BT_ACCEL:
+ case BT_RTL8756:
+ gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_UNDEF;
+ break;
+ case BT_CSR_BC4:
+ gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_CSR_BC4;
+ break;
+ case BT_CSR_BC8:
+ gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_CSR_BC8;
+ break;
+ case BT_RTL8723A:
+ gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_RTL8723A;
+ break;
+ case BT_RTL8821A:
+ gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_RTL8821;
+ break;
+ case BT_RTL8723B:
+ gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_RTL8723B;
+ break;
+ }
+}
+
+void exhalbtc_set_ant_num(u8 type, u8 ant_num)
+{
+ if (BT_COEX_ANT_TYPE_PG == type) {
+ gl_bt_coexist.board_info.pg_ant_num = ant_num;
+ gl_bt_coexist.board_info.btdm_ant_num = ant_num;
+ } else if (BT_COEX_ANT_TYPE_ANTDIV == type) {
+ gl_bt_coexist.board_info.btdm_ant_num = ant_num;
+ }
+}
+
+void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist)
+{
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+ if (!halbtc_is_bt_coexist_available(btcoexist))
+ return;
+
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+ ex_halbtc8723b2ant_display_coex_info(btcoexist);
+}
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h
new file mode 100644
index 000000000000..871fc3c6d559
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h
@@ -0,0 +1,559 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef __HALBTC_OUT_SRC_H__
+#define __HALBTC_OUT_SRC_H__
+
+#include "../wifi.h"
+
+#define NORMAL_EXEC false
+#define FORCE_EXEC true
+
+#define BTC_RF_A RF90_PATH_A
+#define BTC_RF_B RF90_PATH_B
+#define BTC_RF_C RF90_PATH_C
+#define BTC_RF_D RF90_PATH_D
+
+#define BTC_SMSP SINGLEMAC_SINGLEPHY
+#define BTC_DMDP DUALMAC_DUALPHY
+#define BTC_DMSP DUALMAC_SINGLEPHY
+#define BTC_MP_UNKNOWN 0xff
+
+#define IN
+#define OUT
+
+#define BT_TMP_BUF_SIZE 100
+
+#define BT_COEX_ANT_TYPE_PG 0
+#define BT_COEX_ANT_TYPE_ANTDIV 1
+#define BT_COEX_ANT_TYPE_DETECTED 2
+
+#define BTC_MIMO_PS_STATIC 0
+#define BTC_MIMO_PS_DYNAMIC 1
+
+#define BTC_RATE_DISABLE 0
+#define BTC_RATE_ENABLE 1
+
+#define BTC_ANT_PATH_WIFI 0
+#define BTC_ANT_PATH_BT 1
+#define BTC_ANT_PATH_PTA 2
+
+enum btc_chip_interface {
+ BTC_INTF_UNKNOWN = 0,
+ BTC_INTF_PCI = 1,
+ BTC_INTF_USB = 2,
+ BTC_INTF_SDIO = 3,
+ BTC_INTF_GSPI = 4,
+ BTC_INTF_MAX
+};
+
+enum BTC_CHIP_TYPE {
+ BTC_CHIP_UNDEF = 0,
+ BTC_CHIP_CSR_BC4 = 1,
+ BTC_CHIP_CSR_BC8 = 2,
+ BTC_CHIP_RTL8723A = 3,
+ BTC_CHIP_RTL8821 = 4,
+ BTC_CHIP_RTL8723B = 5,
+ BTC_CHIP_MAX
+};
+
+enum BTC_MSG_TYPE {
+ BTC_MSG_INTERFACE = 0x0,
+ BTC_MSG_ALGORITHM = 0x1,
+ BTC_MSG_MAX
+};
+extern u32 btc_dbg_type[];
+
+/* following is for BTC_MSG_INTERFACE */
+#define INTF_INIT BIT0
+#define INTF_NOTIFY BIT2
+
+/* following is for BTC_ALGORITHM */
+#define ALGO_BT_RSSI_STATE BIT0
+#define ALGO_WIFI_RSSI_STATE BIT1
+#define ALGO_BT_MONITOR BIT2
+#define ALGO_TRACE BIT3
+#define ALGO_TRACE_FW BIT4
+#define ALGO_TRACE_FW_DETAIL BIT5
+#define ALGO_TRACE_FW_EXEC BIT6
+#define ALGO_TRACE_SW BIT7
+#define ALGO_TRACE_SW_DETAIL BIT8
+#define ALGO_TRACE_SW_EXEC BIT9
+
+#define BT_COEX_ANT_TYPE_PG 0
+#define BT_COEX_ANT_TYPE_ANTDIV 1
+#define BT_COEX_ANT_TYPE_DETECTED 2
+#define BTC_MIMO_PS_STATIC 0
+#define BTC_MIMO_PS_DYNAMIC 1
+#define BTC_RATE_DISABLE 0
+#define BTC_RATE_ENABLE 1
+#define BTC_ANT_PATH_WIFI 0
+#define BTC_ANT_PATH_BT 1
+#define BTC_ANT_PATH_PTA 2
+
+
+#define CL_SPRINTF snprintf
+#define CL_PRINTF printk
+
+#define BTC_PRINT(dbgtype, dbgflag, printstr, ...) \
+ do { \
+ if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) {\
+ printk(printstr, ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+#define BTC_PRINT_F(dbgtype, dbgflag, printstr, ...) \
+ do { \
+ if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) {\
+ pr_info("%s: ", __func__); \
+ printk(printstr, ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+#define BTC_PRINT_ADDR(dbgtype, dbgflag, printstr, _ptr) \
+ do { \
+ if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) { \
+ int __i; \
+ u8 *__ptr = (u8 *)_ptr; \
+ printk printstr; \
+ for (__i = 0; __i < 6; __i++) \
+ printk("%02X%s", __ptr[__i], (__i == 5) ? \
+ "" : "-"); \
+ pr_info("\n"); \
+ } \
+ } while (0)
+
+#define BTC_PRINT_DATA(dbgtype, dbgflag, _titlestring, _hexdata, _hexdatalen) \
+ do { \
+ if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) { \
+ int __i; \
+ u8 *__ptr = (u8 *)_hexdata; \
+ printk(_titlestring); \
+ for (__i = 0; __i < (int)_hexdatalen; __i++) { \
+ printk("%02X%s", __ptr[__i], (((__i + 1) % 4) \
+ == 0) ? " " : " ");\
+ if (((__i + 1) % 16) == 0) \
+ printk("\n"); \
+ } \
+ pr_debug("\n"); \
+ } \
+ } while (0)
+
+#define BTC_ANT_PATH_WIFI 0
+#define BTC_ANT_PATH_BT 1
+#define BTC_ANT_PATH_PTA 2
+
+enum btc_power_save_type {
+ BTC_PS_WIFI_NATIVE = 0,
+ BTC_PS_LPS_ON = 1,
+ BTC_PS_LPS_OFF = 2,
+ BTC_PS_LPS_MAX
+};
+
+struct btc_board_info {
+ /* The following is some board information */
+ u8 bt_chip_type;
+ u8 pg_ant_num; /* pg ant number */
+ u8 btdm_ant_num; /* ant number for btdm */
+ u8 btdm_ant_pos;
+ bool bt_exist;
+};
+
+enum btc_dbg_opcode {
+ BTC_DBG_SET_COEX_NORMAL = 0x0,
+ BTC_DBG_SET_COEX_WIFI_ONLY = 0x1,
+ BTC_DBG_SET_COEX_BT_ONLY = 0x2,
+ BTC_DBG_MAX
+};
+
+enum btc_rssi_state {
+ BTC_RSSI_STATE_HIGH = 0x0,
+ BTC_RSSI_STATE_MEDIUM = 0x1,
+ BTC_RSSI_STATE_LOW = 0x2,
+ BTC_RSSI_STATE_STAY_HIGH = 0x3,
+ BTC_RSSI_STATE_STAY_MEDIUM = 0x4,
+ BTC_RSSI_STATE_STAY_LOW = 0x5,
+ BTC_RSSI_MAX
+};
+
+enum btc_wifi_role {
+ BTC_ROLE_STATION = 0x0,
+ BTC_ROLE_AP = 0x1,
+ BTC_ROLE_IBSS = 0x2,
+ BTC_ROLE_HS_MODE = 0x3,
+ BTC_ROLE_MAX
+};
+
+enum btc_wifi_bw_mode {
+ BTC_WIFI_BW_LEGACY = 0x0,
+ BTC_WIFI_BW_HT20 = 0x1,
+ BTC_WIFI_BW_HT40 = 0x2,
+ BTC_WIFI_BW_MAX
+};
+
+enum btc_wifi_traffic_dir {
+ BTC_WIFI_TRAFFIC_TX = 0x0,
+ BTC_WIFI_TRAFFIC_RX = 0x1,
+ BTC_WIFI_TRAFFIC_MAX
+};
+
+enum btc_wifi_pnp {
+ BTC_WIFI_PNP_WAKE_UP = 0x0,
+ BTC_WIFI_PNP_SLEEP = 0x1,
+ BTC_WIFI_PNP_MAX
+};
+
+
+enum btc_get_type {
+ /* type bool */
+ BTC_GET_BL_HS_OPERATION,
+ BTC_GET_BL_HS_CONNECTING,
+ BTC_GET_BL_WIFI_CONNECTED,
+ BTC_GET_BL_WIFI_BUSY,
+ BTC_GET_BL_WIFI_SCAN,
+ BTC_GET_BL_WIFI_LINK,
+ BTC_GET_BL_WIFI_DHCP,
+ BTC_GET_BL_WIFI_SOFTAP_IDLE,
+ BTC_GET_BL_WIFI_SOFTAP_LINKING,
+ BTC_GET_BL_WIFI_IN_EARLY_SUSPEND,
+ BTC_GET_BL_WIFI_ROAM,
+ BTC_GET_BL_WIFI_4_WAY_PROGRESS,
+ BTC_GET_BL_WIFI_UNDER_5G,
+ BTC_GET_BL_WIFI_AP_MODE_ENABLE,
+ BTC_GET_BL_WIFI_ENABLE_ENCRYPTION,
+ BTC_GET_BL_WIFI_UNDER_B_MODE,
+ BTC_GET_BL_EXT_SWITCH,
+
+ /* type s4Byte */
+ BTC_GET_S4_WIFI_RSSI,
+ BTC_GET_S4_HS_RSSI,
+
+ /* type u32 */
+ BTC_GET_U4_WIFI_BW,
+ BTC_GET_U4_WIFI_TRAFFIC_DIRECTION,
+ BTC_GET_U4_WIFI_FW_VER,
+ BTC_GET_U4_BT_PATCH_VER,
+
+ /* type u1Byte */
+ BTC_GET_U1_WIFI_DOT11_CHNL,
+ BTC_GET_U1_WIFI_CENTRAL_CHNL,
+ BTC_GET_U1_WIFI_HS_CHNL,
+ BTC_GET_U1_MAC_PHY_MODE,
+
+ /* for 1Ant */
+ BTC_GET_U1_LPS_MODE,
+ BTC_GET_BL_BT_SCO_BUSY,
+
+ /* for test mode */
+ BTC_GET_DRIVER_TEST_CFG,
+ BTC_GET_MAX
+};
+
+
+enum btc_set_type {
+ /* type bool */
+ BTC_SET_BL_BT_DISABLE,
+ BTC_SET_BL_BT_TRAFFIC_BUSY,
+ BTC_SET_BL_BT_LIMITED_DIG,
+ BTC_SET_BL_FORCE_TO_ROAM,
+ BTC_SET_BL_TO_REJ_AP_AGG_PKT,
+ BTC_SET_BL_BT_CTRL_AGG_SIZE,
+ BTC_SET_BL_INC_SCAN_DEV_NUM,
+
+ /* type u1Byte */
+ BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON,
+ BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE,
+ BTC_SET_UI_SCAN_SIG_COMPENSATION,
+ BTC_SET_U1_AGG_BUF_SIZE,
+
+ /* type trigger some action */
+ BTC_SET_ACT_GET_BT_RSSI,
+ BTC_SET_ACT_AGGREGATE_CTRL,
+
+ /********* for 1Ant **********/
+ /* type bool */
+ BTC_SET_BL_BT_SCO_BUSY,
+ /* type u1Byte */
+ BTC_SET_U1_1ANT_LPS,
+ BTC_SET_U1_1ANT_RPWM,
+ /* type trigger some action */
+ BTC_SET_ACT_LEAVE_LPS,
+ BTC_SET_ACT_ENTER_LPS,
+ BTC_SET_ACT_NORMAL_LPS,
+ BTC_SET_ACT_INC_FORCE_EXEC_PWR_CMD_CNT,
+ BTC_SET_ACT_DISABLE_LOW_POWER,
+ BTC_SET_ACT_UPDATE_ra_mask,
+ BTC_SET_ACT_SEND_MIMO_PS,
+ /* BT Coex related */
+ BTC_SET_ACT_CTRL_BT_INFO,
+ BTC_SET_ACT_CTRL_BT_COEX,
+ /***************************/
+ BTC_SET_MAX
+};
+
+enum btc_dbg_disp_type {
+ BTC_DBG_DISP_COEX_STATISTICS = 0x0,
+ BTC_DBG_DISP_BT_LINK_INFO = 0x1,
+ BTC_DBG_DISP_BT_FW_VER = 0x2,
+ BTC_DBG_DISP_FW_PWR_MODE_CMD = 0x3,
+ BTC_DBG_DISP_MAX
+};
+
+enum btc_notify_type_ips {
+ BTC_IPS_LEAVE = 0x0,
+ BTC_IPS_ENTER = 0x1,
+ BTC_IPS_MAX
+};
+
+enum btc_notify_type_lps {
+ BTC_LPS_DISABLE = 0x0,
+ BTC_LPS_ENABLE = 0x1,
+ BTC_LPS_MAX
+};
+
+enum btc_notify_type_scan {
+ BTC_SCAN_FINISH = 0x0,
+ BTC_SCAN_START = 0x1,
+ BTC_SCAN_MAX
+};
+
+enum btc_notify_type_associate {
+ BTC_ASSOCIATE_FINISH = 0x0,
+ BTC_ASSOCIATE_START = 0x1,
+ BTC_ASSOCIATE_MAX
+};
+
+enum btc_notify_type_media_status {
+ BTC_MEDIA_DISCONNECT = 0x0,
+ BTC_MEDIA_CONNECT = 0x1,
+ BTC_MEDIA_MAX
+};
+
+enum btc_notify_type_special_packet {
+ BTC_PACKET_UNKNOWN = 0x0,
+ BTC_PACKET_DHCP = 0x1,
+ BTC_PACKET_ARP = 0x2,
+ BTC_PACKET_EAPOL = 0x3,
+ BTC_PACKET_MAX
+};
+
+enum btc_notify_type_stack_operation {
+ BTC_STACK_OP_NONE = 0x0,
+ BTC_STACK_OP_INQ_PAGE_PAIR_START = 0x1,
+ BTC_STACK_OP_INQ_PAGE_PAIR_FINISH = 0x2,
+ BTC_STACK_OP_MAX
+};
+
+
+typedef u8 (*bfp_btc_r1)(void *btc_context, u32 reg_addr);
+
+typedef u16 (*bfp_btc_r2)(void *btc_context, u32 reg_addr);
+
+typedef u32 (*bfp_btc_r4)(void *btc_context, u32 reg_addr);
+
+typedef void (*bfp_btc_w1)(void *btc_context, u32 reg_addr, u8 data);
+
+typedef void (*bfp_btc_w1_bit_mak)(void *btc_context, u32 reg_addr,
+ u32 bit_mask, u8 data1b);
+
+typedef void (*bfp_btc_w2)(void *btc_context, u32 reg_addr, u16 data);
+
+typedef void (*bfp_btc_w4)(void *btc_context, u32 reg_addr, u32 data);
+
+typedef void (*bfp_btc_wr_1byte_bit_mask)(void *btc_context, u32 reg_addr,
+ u8 bit_mask, u8 data);
+
+typedef void (*bfp_btc_set_bb_reg)(void *btc_context, u32 reg_addr,
+ u32 bit_mask, u32 data);
+
+typedef u32 (*bfp_btc_get_bb_reg)(void *btc_context, u32 reg_addr,
+ u32 bit_mask);
+
+typedef void (*bfp_btc_set_rf_reg)(void *btc_context, u8 rf_path, u32 reg_addr,
+ u32 bit_mask, u32 data);
+
+typedef u32 (*bfp_btc_get_rf_reg)(void *btc_context, u8 rf_path,
+ u32 reg_addr, u32 bit_mask);
+
+typedef void (*bfp_btc_fill_h2c)(void *btc_context, u8 element_id,
+ u32 cmd_len, u8 *cmd_buffer);
+
+typedef bool (*bfp_btc_get)(void *btcoexist, u8 get_type, void *out_buf);
+
+typedef bool (*bfp_btc_set)(void *btcoexist, u8 set_type, void *in_buf);
+
+typedef void (*bfp_btc_disp_dbg_msg)(void *btcoexist, u8 disp_type);
+
+struct btc_bt_info {
+ bool bt_disabled;
+ u8 rssi_adjust_for_agc_table_on;
+ u8 rssi_adjust_for_1ant_coex_type;
+ bool bt_busy;
+ u8 agg_buf_size;
+ bool limited_dig;
+ bool reject_agg_pkt;
+ bool b_bt_ctrl_buf_size;
+ bool increase_scan_dev_num;
+ u16 bt_hci_ver;
+ u16 bt_real_fw_ver;
+ u8 bt_fw_ver;
+
+ /* the following is for 1Ant solution */
+ bool bt_ctrl_lps;
+ bool bt_pwr_save_mode;
+ bool bt_lps_on;
+ bool force_to_roam;
+ u8 force_exec_pwr_cmd_cnt;
+ u8 lps_1ant;
+ u8 rpwm_1ant;
+ u32 ra_mask;
+};
+
+struct btc_stack_info {
+ bool profile_notified;
+ u16 hci_version; /* stack hci version */
+ u8 num_of_link;
+ bool bt_link_exist;
+ bool sco_exist;
+ bool acl_exist;
+ bool a2dp_exist;
+ bool hid_exist;
+ u8 num_of_hid;
+ bool pan_exist;
+ bool unknown_acl_exist;
+ char min_bt_rssi;
+};
+
+struct btc_statistics {
+ u32 cnt_bind;
+ u32 cnt_init_hw_config;
+ u32 cnt_init_coex_dm;
+ u32 cnt_ips_notify;
+ u32 cnt_lps_notify;
+ u32 cnt_scan_notify;
+ u32 cnt_connect_notify;
+ u32 cnt_media_status_notify;
+ u32 cnt_special_packet_notify;
+ u32 cnt_bt_info_notify;
+ u32 cnt_periodical;
+ u32 cnt_stack_operation_notify;
+ u32 cnt_dbg_ctrl;
+};
+
+struct btc_bt_link_info {
+ bool bt_link_exist;
+ bool sco_exist;
+ bool sco_only;
+ bool a2dp_exist;
+ bool a2dp_only;
+ bool hid_exist;
+ bool hid_only;
+ bool pan_exist;
+ bool pan_only;
+};
+
+enum btc_antenna_pos {
+ BTC_ANTENNA_AT_MAIN_PORT = 0x1,
+ BTC_ANTENNA_AT_AUX_PORT = 0x2,
+};
+
+struct btc_coexist {
+ /* make sure only one adapter can bind the data context */
+ bool binded;
+ /* default adapter */
+ void *adapter;
+ struct btc_board_info board_info;
+ /* some bt info referenced by non-bt module */
+ struct btc_bt_info bt_info;
+ struct btc_stack_info stack_info;
+ enum btc_chip_interface chip_interface;
+ struct btc_bt_link_info bt_link_info;
+
+ bool initilized;
+ bool stop_coex_dm;
+ bool manual_control;
+ u8 *cli_buf;
+ struct btc_statistics statistics;
+ u8 pwr_mode_val[10];
+
+ /* function pointers - io related */
+ bfp_btc_r1 btc_read_1byte;
+ bfp_btc_w1 btc_write_1byte;
+ bfp_btc_w1_bit_mak btc_write_1byte_bitmask;
+ bfp_btc_r2 btc_read_2byte;
+ bfp_btc_w2 btc_write_2byte;
+ bfp_btc_r4 btc_read_4byte;
+ bfp_btc_w4 btc_write_4byte;
+
+ bfp_btc_set_bb_reg btc_set_bb_reg;
+ bfp_btc_get_bb_reg btc_get_bb_reg;
+
+
+ bfp_btc_set_rf_reg btc_set_rf_reg;
+ bfp_btc_get_rf_reg btc_get_rf_reg;
+
+ bfp_btc_fill_h2c btc_fill_h2c;
+
+ bfp_btc_disp_dbg_msg btc_disp_dbg_msg;
+
+ bfp_btc_get btc_get;
+ bfp_btc_set btc_set;
+};
+
+bool halbtc_is_wifi_uplink(struct rtl_priv *adapter);
+
+extern struct btc_coexist gl_bt_coexist;
+
+bool exhalbtc_initlize_variables(struct rtl_priv *adapter);
+void exhalbtc_init_hw_config(struct btc_coexist *btcoexist);
+void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist);
+void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type);
+void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type);
+void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type);
+void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action);
+void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist,
+ enum _RT_MEDIA_STATUS media_status);
+void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type);
+void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf,
+ u8 length);
+void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type);
+void exhalbtc_halt_notify(struct btc_coexist *btcoexist);
+void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state);
+void exhalbtc_periodical(struct btc_coexist *btcoexist);
+void exhalbtc_dbg_control(struct btc_coexist *btcoexist, u8 code, u8 len,
+ u8 *data);
+void exhalbtc_stack_update_profile_info(void);
+void exhalbtc_set_hci_version(u16 hci_version);
+void exhalbtc_set_bt_patch_version(u16 bt_hci_version, u16 bt_patch_version);
+void exhalbtc_update_min_bt_rssi(char bt_rssi);
+void exhalbtc_set_bt_exist(bool bt_exist);
+void exhalbtc_set_chip_type(u8 chip_type);
+void exhalbtc_set_ant_num(u8 type, u8 ant_num);
+void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist);
+void exhalbtc_signal_compensation(struct btc_coexist *btcoexist,
+ u8 *rssi_wifi, u8 *rssi_bt);
+void exhalbtc_lps_leave(struct btc_coexist *btcoexist);
+void exhalbtc_low_wifi_traffic_notify(struct btc_coexist *btcoexist);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c
new file mode 100644
index 000000000000..0ab94fe4cbbe
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c
@@ -0,0 +1,218 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "rtl_btc.h"
+#include "halbt_precomp.h"
+
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+
+static struct rtl_btc_ops rtl_btc_operation = {
+ .btc_init_variables = rtl_btc_init_variables,
+ .btc_init_hal_vars = rtl_btc_init_hal_vars,
+ .btc_init_hw_config = rtl_btc_init_hw_config,
+ .btc_ips_notify = rtl_btc_ips_notify,
+ .btc_scan_notify = rtl_btc_scan_notify,
+ .btc_connect_notify = rtl_btc_connect_notify,
+ .btc_mediastatus_notify = rtl_btc_mediastatus_notify,
+ .btc_periodical = rtl_btc_periodical,
+ .btc_halt_notify = rtl_btc_halt_notify,
+ .btc_btinfo_notify = rtl_btc_btinfo_notify,
+ .btc_is_limited_dig = rtl_btc_is_limited_dig,
+ .btc_is_disable_edca_turbo = rtl_btc_is_disable_edca_turbo,
+ .btc_is_bt_disabled = rtl_btc_is_bt_disabled,
+};
+
+void rtl_btc_init_variables(struct rtl_priv *rtlpriv)
+{
+ exhalbtc_initlize_variables(rtlpriv);
+}
+
+void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv)
+{
+ u8 ant_num;
+ u8 bt_exist;
+ u8 bt_type;
+
+ ant_num = rtl_get_hwpg_ant_num(rtlpriv);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "%s, antNum is %d\n", __func__, ant_num);
+
+ bt_exist = rtl_get_hwpg_bt_exist(rtlpriv);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "%s, bt_exist is %d\n", __func__, bt_exist);
+ exhalbtc_set_bt_exist(bt_exist);
+
+ bt_type = rtl_get_hwpg_bt_type(rtlpriv);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "%s, bt_type is %d\n",
+ __func__, bt_type);
+ exhalbtc_set_chip_type(bt_type);
+
+ exhalbtc_set_ant_num(BT_COEX_ANT_TYPE_PG, ant_num);
+}
+
+void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv)
+{
+ exhalbtc_init_hw_config(&gl_bt_coexist);
+ exhalbtc_init_coex_dm(&gl_bt_coexist);
+}
+
+void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type)
+{
+ exhalbtc_ips_notify(&gl_bt_coexist, type);
+}
+
+void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype)
+{
+ exhalbtc_scan_notify(&gl_bt_coexist, scantype);
+}
+
+void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action)
+{
+ exhalbtc_connect_notify(&gl_bt_coexist, action);
+}
+
+void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv,
+ enum _RT_MEDIA_STATUS mstatus)
+{
+ exhalbtc_mediastatus_notify(&gl_bt_coexist, mstatus);
+}
+
+void rtl_btc_periodical(struct rtl_priv *rtlpriv)
+{
+ exhalbtc_periodical(&gl_bt_coexist);
+}
+
+void rtl_btc_halt_notify(void)
+{
+ exhalbtc_halt_notify(&gl_bt_coexist);
+}
+
+void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length)
+{
+ exhalbtc_bt_info_notify(&gl_bt_coexist, tmp_buf, length);
+}
+
+bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv)
+{
+ return gl_bt_coexist.bt_info.limited_dig;
+}
+
+bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv)
+{
+ bool bt_change_edca = false;
+ u32 cur_edca_val;
+ u32 edca_bt_hs_uplink = 0x5ea42b, edca_bt_hs_downlink = 0x5ea42b;
+ u32 edca_hs;
+ u32 edca_addr = 0x504;
+
+ cur_edca_val = rtl_read_dword(rtlpriv, edca_addr);
+ if (halbtc_is_wifi_uplink(rtlpriv)) {
+ if (cur_edca_val != edca_bt_hs_uplink) {
+ edca_hs = edca_bt_hs_uplink;
+ bt_change_edca = true;
+ }
+ } else {
+ if (cur_edca_val != edca_bt_hs_downlink) {
+ edca_hs = edca_bt_hs_downlink;
+ bt_change_edca = true;
+ }
+ }
+
+ if (bt_change_edca)
+ rtl_write_dword(rtlpriv, edca_addr, edca_hs);
+
+ return true;
+}
+
+bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv)
+{
+ if (gl_bt_coexist.bt_info.bt_disabled)
+ return true;
+ else
+ return false;
+}
+
+struct rtl_btc_ops *rtl_btc_get_ops_pointer(void)
+{
+ return &rtl_btc_operation;
+}
+EXPORT_SYMBOL(rtl_btc_get_ops_pointer);
+
+u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv)
+{
+ u8 num;
+
+ if (rtlpriv->btcoexist.btc_info.ant_num == ANT_X2)
+ num = 2;
+ else
+ num = 1;
+
+ return num;
+}
+
+enum _RT_MEDIA_STATUS mgnt_link_status_query(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ enum _RT_MEDIA_STATUS m_status = RT_MEDIA_DISCONNECT;
+
+ u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0;
+
+ if (bibss || rtlpriv->mac80211.link_state >= MAC80211_LINKED)
+ m_status = RT_MEDIA_CONNECT;
+
+ return m_status;
+}
+
+u8 rtl_get_hwpg_bt_exist(struct rtl_priv *rtlpriv)
+{
+ return rtlpriv->btcoexist.btc_info.btcoexist;
+}
+
+u8 rtl_get_hwpg_bt_type(struct rtl_priv *rtlpriv)
+{
+ return rtlpriv->btcoexist.btc_info.bt_type;
+}
+
+MODULE_AUTHOR("Page He <page_he@realsil.com.cn>");
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core");
+
+static int __init rtl_btcoexist_module_init(void)
+{
+ return 0;
+}
+
+static void __exit rtl_btcoexist_module_exit(void)
+{
+ return;
+}
+
+module_init(rtl_btcoexist_module_init);
+module_exit(rtl_btcoexist_module_exit);
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h
new file mode 100644
index 000000000000..805b22cc8fc8
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h
@@ -0,0 +1,52 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL_BTC_H__
+#define __RTL_BTC_H__
+
+#include "halbt_precomp.h"
+
+void rtl_btc_init_variables(struct rtl_priv *rtlpriv);
+void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv);
+void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv);
+void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type);
+void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype);
+void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action);
+void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv,
+ enum _RT_MEDIA_STATUS mstatus);
+void rtl_btc_periodical(struct rtl_priv *rtlpriv);
+void rtl_btc_halt_notify(void);
+void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmpbuf, u8 length);
+bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv);
+bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv);
+bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv);
+
+struct rtl_btc_ops *rtl_btc_get_ops_pointer(void);
+
+u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv);
+u8 rtl_get_hwpg_bt_exist(struct rtl_priv *rtlpriv);
+u8 rtl_get_hwpg_bt_type(struct rtl_priv *rtlpriv);
+enum _RT_MEDIA_STATUS mgnt_link_status_query(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index 2d337a0c3df0..4ec424f26672 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -36,6 +36,66 @@
#include <linux/export.h>
+void rtl_addr_delay(u32 addr)
+{
+ if (addr == 0xfe)
+ mdelay(50);
+ else if (addr == 0xfd)
+ mdelay(5);
+ else if (addr == 0xfc)
+ mdelay(1);
+ else if (addr == 0xfb)
+ udelay(50);
+ else if (addr == 0xfa)
+ udelay(5);
+ else if (addr == 0xf9)
+ udelay(1);
+}
+EXPORT_SYMBOL(rtl_addr_delay);
+
+void rtl_rfreg_delay(struct ieee80211_hw *hw, enum radio_path rfpath, u32 addr,
+ u32 mask, u32 data)
+{
+ if (addr == 0xfe) {
+ mdelay(50);
+ } else if (addr == 0xfd) {
+ mdelay(5);
+ } else if (addr == 0xfc) {
+ mdelay(1);
+ } else if (addr == 0xfb) {
+ udelay(50);
+ } else if (addr == 0xfa) {
+ udelay(5);
+ } else if (addr == 0xf9) {
+ udelay(1);
+ } else {
+ rtl_set_rfreg(hw, rfpath, addr, mask, data);
+ udelay(1);
+ }
+}
+EXPORT_SYMBOL(rtl_rfreg_delay);
+
+void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data)
+{
+ if (addr == 0xfe) {
+ mdelay(50);
+ } else if (addr == 0xfd) {
+ mdelay(5);
+ } else if (addr == 0xfc) {
+ mdelay(1);
+ } else if (addr == 0xfb) {
+ udelay(50);
+ } else if (addr == 0xfa) {
+ udelay(5);
+ } else if (addr == 0xf9) {
+ udelay(1);
+ } else {
+ rtl_set_bbreg(hw, addr, MASKDWORD, data);
+ udelay(1);
+ }
+}
+EXPORT_SYMBOL(rtl_bb_delay);
+
void rtl_fw_cb(const struct firmware *firmware, void *context)
{
struct ieee80211_hw *hw = context;
@@ -475,20 +535,40 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u32 rx_conf;
*new_flags &= RTL_SUPPORTED_FILTERS;
if (!changed_flags)
return;
+ /* if ssid not set to hw don't check bssid
+ * here just used for linked scanning, & linked
+ * and nolink check bssid is set in set network_type */
+ if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) &&
+ (mac->link_state >= MAC80211_LINKED)) {
+ if (mac->opmode != NL80211_IFTYPE_AP &&
+ mac->opmode != NL80211_IFTYPE_MESH_POINT) {
+ if (*new_flags & FIF_BCN_PRBRESP_PROMISC) {
+ rtlpriv->cfg->ops->set_chk_bssid(hw, false);
+ } else {
+ rtlpriv->cfg->ops->set_chk_bssid(hw, true);
+ }
+ }
+ }
+
+ /* must be called after set_chk_bssid since that function modifies the
+ * RCR register too. */
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&rx_conf));
+
/*TODO: we disable broadcase now, so enable here */
if (changed_flags & FIF_ALLMULTI) {
if (*new_flags & FIF_ALLMULTI) {
- mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AM] |
+ rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AM] |
rtlpriv->cfg->maps[MAC_RCR_AB];
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
"Enable receive multicast frame\n");
} else {
- mac->rx_conf &= ~(rtlpriv->cfg->maps[MAC_RCR_AM] |
+ rx_conf &= ~(rtlpriv->cfg->maps[MAC_RCR_AM] |
rtlpriv->cfg->maps[MAC_RCR_AB]);
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
"Disable receive multicast frame\n");
@@ -497,39 +577,25 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw,
if (changed_flags & FIF_FCSFAIL) {
if (*new_flags & FIF_FCSFAIL) {
- mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACRC32];
+ rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACRC32];
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
"Enable receive FCS error frame\n");
} else {
- mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACRC32];
+ rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACRC32];
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
"Disable receive FCS error frame\n");
}
}
- /* if ssid not set to hw don't check bssid
- * here just used for linked scanning, & linked
- * and nolink check bssid is set in set network_type */
- if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) &&
- (mac->link_state >= MAC80211_LINKED)) {
- if (mac->opmode != NL80211_IFTYPE_AP &&
- mac->opmode != NL80211_IFTYPE_MESH_POINT) {
- if (*new_flags & FIF_BCN_PRBRESP_PROMISC) {
- rtlpriv->cfg->ops->set_chk_bssid(hw, false);
- } else {
- rtlpriv->cfg->ops->set_chk_bssid(hw, true);
- }
- }
- }
if (changed_flags & FIF_CONTROL) {
if (*new_flags & FIF_CONTROL) {
- mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF];
+ rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF];
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
"Enable receive control frame\n");
} else {
- mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF];
+ rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF];
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
"Disable receive control frame\n");
}
@@ -537,15 +603,17 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw,
if (changed_flags & FIF_OTHER_BSS) {
if (*new_flags & FIF_OTHER_BSS) {
- mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AAP];
+ rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AAP];
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
"Enable receive other BSS's frame\n");
} else {
- mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_AAP];
+ rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_AAP];
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
"Disable receive other BSS's frame\n");
}
}
+
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(&rx_conf));
}
static int rtl_op_sta_add(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
@@ -738,6 +806,11 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
rtlpriv->cfg->ops->linked_set_reg(hw);
rcu_read_lock();
sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid);
+ if (!sta) {
+ pr_err("ieee80211_find_sta returned NULL\n");
+ rcu_read_unlock();
+ goto out;
+ }
if (vif->type == NL80211_IFTYPE_STATION && sta)
rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
@@ -892,7 +965,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
mac->basic_rates = basic_rates;
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
- (u8 *) (&basic_rates));
+ (u8 *)(&basic_rates));
}
rcu_read_unlock();
}
@@ -906,6 +979,11 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
if (bss_conf->assoc) {
if (ppsc->fwctrl_lps) {
u8 mstatus = RT_MEDIA_CONNECT;
+ u8 keep_alive = 10;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_KEEP_ALIVE,
+ &keep_alive);
+
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_H2C_FW_JOINBSSRPT,
&mstatus);
diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h
index 2fe46a1b4f1f..027e75374dcc 100644
--- a/drivers/net/wireless/rtlwifi/core.h
+++ b/drivers/net/wireless/rtlwifi/core.h
@@ -41,5 +41,9 @@
extern const struct ieee80211_ops rtl_ops;
void rtl_fw_cb(const struct firmware *firmware, void *context);
+void rtl_addr_delay(u32 addr);
+void rtl_rfreg_delay(struct ieee80211_hw *hw, enum radio_path rfpath, u32 addr,
+ u32 mask, u32 data);
+void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data);
#endif
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index d7aa165fe677..dae55257f0e8 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -811,19 +811,19 @@ done:
if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress))
return;
tmp_one = 1;
- rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false,
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false,
HW_DESC_RXBUFF_ADDR,
(u8 *)&bufferaddress);
- rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false,
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false,
HW_DESC_RXPKT_LEN,
(u8 *)&rtlpci->rxbuffersize);
if (index == rtlpci->rxringcount - 1)
- rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false,
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false,
HW_DESC_RXERO,
&tmp_one);
- rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXOWN,
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false, HW_DESC_RXOWN,
&tmp_one);
index = (index + 1) % rtlpci->rxringcount;
@@ -983,6 +983,8 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
struct sk_buff *pskb = NULL;
struct rtl_tx_desc *pdesc = NULL;
struct rtl_tcb_desc tcb_desc;
+ /*This is for new trx flow*/
+ struct rtl_tx_buffer_desc *pbuffer_desc = NULL;
u8 temp_one = 1;
memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
@@ -1004,11 +1006,12 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
info = IEEE80211_SKB_CB(pskb);
pdesc = &ring->desc[0];
rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
- info, NULL, pskb, BEACON_QUEUE, &tcb_desc);
+ (u8 *)pbuffer_desc, info, NULL, pskb,
+ BEACON_QUEUE, &tcb_desc);
__skb_queue_tail(&ring->queue, pskb);
- rtlpriv->cfg->ops->set_desc((u8 *) pdesc, true, HW_DESC_OWN,
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, HW_DESC_OWN,
&temp_one);
return;
@@ -1066,7 +1069,7 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw,
mac->current_ampdu_factor = 3;
/*QOS*/
- rtlpci->acm_method = eAcmWay2_SW;
+ rtlpci->acm_method = EACMWAY2_SW;
/*task */
tasklet_init(&rtlpriv->works.irq_tasklet,
@@ -1113,7 +1116,7 @@ static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw,
((i + 1) % entries) *
sizeof(*ring);
- rtlpriv->cfg->ops->set_desc((u8 *)&(ring[i]),
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)&(ring[i]),
true, HW_DESC_TX_NEXTDESC_ADDR,
(u8 *)&nextdescaddress);
}
@@ -1188,19 +1191,19 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw)
dev_kfree_skb_any(skb);
return 1;
}
- rtlpriv->cfg->ops->set_desc((u8 *)entry, false,
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
HW_DESC_RXBUFF_ADDR,
(u8 *)&bufferaddress);
- rtlpriv->cfg->ops->set_desc((u8 *)entry, false,
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
HW_DESC_RXPKT_LEN,
(u8 *)&rtlpci->
rxbuffersize);
- rtlpriv->cfg->ops->set_desc((u8 *) entry, false,
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
HW_DESC_RXOWN,
&tmp_one);
}
- rtlpriv->cfg->ops->set_desc((u8 *) entry, false,
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
HW_DESC_RXERO, &tmp_one);
}
return 0;
@@ -1331,7 +1334,7 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw)
for (i = 0; i < rtlpci->rxringcount; i++) {
entry = &rtlpci->rx_ring[rx_queue_idx].desc[i];
- rtlpriv->cfg->ops->set_desc((u8 *) entry,
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry,
false,
HW_DESC_RXOWN,
&tmp_one);
@@ -1424,6 +1427,7 @@ static int rtl_pci_tx(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct rtl8192_tx_ring *ring;
struct rtl_tx_desc *pdesc;
+ struct rtl_tx_buffer_desc *ptx_bd_desc = NULL;
u8 idx;
u8 hw_queue = _rtl_mac_to_hwqueue(hw, skb);
unsigned long flags;
@@ -1464,17 +1468,22 @@ static int rtl_pci_tx(struct ieee80211_hw *hw,
idx = 0;
pdesc = &ring->desc[idx];
- own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc,
- true, HW_DESC_OWN);
+ if (rtlpriv->use_new_trx_flow) {
+ ptx_bd_desc = &ring->buffer_desc[idx];
+ } else {
+ own = (u8) rtlpriv->cfg->ops->get_desc((u8 *)pdesc,
+ true, HW_DESC_OWN);
- if ((own == 1) && (hw_queue != BEACON_QUEUE)) {
- RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
- "No more TX desc@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n",
- hw_queue, ring->idx, idx,
- skb_queue_len(&ring->queue));
+ if ((own == 1) && (hw_queue != BEACON_QUEUE)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "No more TX desc@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n",
+ hw_queue, ring->idx, idx,
+ skb_queue_len(&ring->queue));
- spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
- return skb->len;
+ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock,
+ flags);
+ return skb->len;
+ }
}
if (ieee80211_is_data_qos(fc)) {
@@ -1494,17 +1503,20 @@ static int rtl_pci_tx(struct ieee80211_hw *hw,
rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX);
rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc,
- info, sta, skb, hw_queue, ptcb_desc);
+ (u8 *)ptx_bd_desc, info, sta, skb, hw_queue, ptcb_desc);
__skb_queue_tail(&ring->queue, skb);
- rtlpriv->cfg->ops->set_desc((u8 *)pdesc, true,
- HW_DESC_OWN, &temp_one);
-
+ if (rtlpriv->use_new_trx_flow) {
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true,
+ HW_DESC_OWN, &hw_queue);
+ } else {
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true,
+ HW_DESC_OWN, &temp_one);
+ }
if ((ring->entries - skb_queue_len(&ring->queue)) < 2 &&
hw_queue != BEACON_QUEUE) {
-
RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
"less desc left, stop skb_queue@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n",
hw_queue, ring->idx, idx,
@@ -1841,6 +1853,65 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
return true;
}
+static int rtl_pci_intr_mode_msi(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
+ int ret;
+
+ ret = pci_enable_msi(rtlpci->pdev);
+ if (ret < 0)
+ return ret;
+
+ ret = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt,
+ IRQF_SHARED, KBUILD_MODNAME, hw);
+ if (ret < 0) {
+ pci_disable_msi(rtlpci->pdev);
+ return ret;
+ }
+
+ rtlpci->using_msi = true;
+
+ RT_TRACE(rtlpriv, COMP_INIT|COMP_INTR, DBG_DMESG,
+ "MSI Interrupt Mode!\n");
+ return 0;
+}
+
+static int rtl_pci_intr_mode_legacy(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
+ int ret;
+
+ ret = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt,
+ IRQF_SHARED, KBUILD_MODNAME, hw);
+ if (ret < 0)
+ return ret;
+
+ rtlpci->using_msi = false;
+ RT_TRACE(rtlpriv, COMP_INIT|COMP_INTR, DBG_DMESG,
+ "Pin-based Interrupt Mode!\n");
+ return 0;
+}
+
+static int rtl_pci_intr_mode_decide(struct ieee80211_hw *hw)
+{
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
+ int ret;
+
+ if (rtlpci->msi_support) {
+ ret = rtl_pci_intr_mode_msi(hw);
+ if (ret < 0)
+ ret = rtl_pci_intr_mode_legacy(hw);
+ } else {
+ ret = rtl_pci_intr_mode_legacy(hw);
+ }
+ return ret;
+}
+
int rtl_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
@@ -1983,8 +2054,7 @@ int rtl_pci_probe(struct pci_dev *pdev,
}
rtlpci = rtl_pcidev(pcipriv);
- err = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt,
- IRQF_SHARED, KBUILD_MODNAME, hw);
+ err = rtl_pci_intr_mode_decide(hw);
if (err) {
RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
"%s: failed to register IRQ handler\n",
@@ -2052,6 +2122,9 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
rtlpci->irq_alloc = 0;
}
+ if (rtlpci->using_msi)
+ pci_disable_msi(rtlpci->pdev);
+
list_del(&rtlpriv->list);
if (rtlpriv->io.pci_mem_start != 0) {
pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);
diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h
index d3262ec45d23..90174a814a6d 100644
--- a/drivers/net/wireless/rtlwifi/pci.h
+++ b/drivers/net/wireless/rtlwifi/pci.h
@@ -137,12 +137,22 @@ struct rtl_tx_cmd_desc {
u32 dword[16];
} __packed;
+/* In new TRX flow, Buffer_desc is new concept
+ * But TX wifi info == TX descriptor in old flow
+ * RX wifi info == RX descriptor in old flow
+ */
+struct rtl_tx_buffer_desc {
+ u32 dword[8]; /*seg = 4*/
+} __packed;
+
struct rtl8192_tx_ring {
struct rtl_tx_desc *desc;
dma_addr_t dma;
unsigned int idx;
unsigned int entries;
struct sk_buff_head queue;
+ /*add for new trx flow*/
+ struct rtl_tx_buffer_desc *buffer_desc; /*tx buffer descriptor*/
};
struct rtl8192_rx_ring {
@@ -199,6 +209,10 @@ struct rtl_pci {
u16 shortretry_limit;
u16 longretry_limit;
+
+ /* MSI support */
+ bool msi_support;
+ bool using_msi;
};
struct mp_adapter {
diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c
index deedae3c5449..50504942ded1 100644
--- a/drivers/net/wireless/rtlwifi/ps.c
+++ b/drivers/net/wireless/rtlwifi/ps.c
@@ -32,6 +32,106 @@
#include "base.h"
#include "ps.h"
+/* Description:
+ * This routine deals with the Power Configuration CMD
+ * parsing for RTL8723/RTL8188E Series IC.
+ * Assumption:
+ * We should follow specific format that was released from HW SD.
+ */
+bool rtl_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
+ u8 faversion, u8 interface_type,
+ struct wlan_pwr_cfg pwrcfgcmd[])
+{
+ struct wlan_pwr_cfg cfg_cmd = {0};
+ bool polling_bit = false;
+ u32 ary_idx = 0;
+ u8 value = 0;
+ u32 offset = 0;
+ u32 polling_count = 0;
+ u32 max_polling_cnt = 5000;
+
+ do {
+ cfg_cmd = pwrcfgcmd[ary_idx];
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtl_hal_pwrseqcmdparsing(): offset(%#x),cut_msk(%#x), famsk(%#x),"
+ "interface_msk(%#x), base(%#x), cmd(%#x), msk(%#x), value(%#x)\n",
+ GET_PWR_CFG_OFFSET(cfg_cmd),
+ GET_PWR_CFG_CUT_MASK(cfg_cmd),
+ GET_PWR_CFG_FAB_MASK(cfg_cmd),
+ GET_PWR_CFG_INTF_MASK(cfg_cmd),
+ GET_PWR_CFG_BASE(cfg_cmd), GET_PWR_CFG_CMD(cfg_cmd),
+ GET_PWR_CFG_MASK(cfg_cmd), GET_PWR_CFG_VALUE(cfg_cmd));
+
+ if ((GET_PWR_CFG_FAB_MASK(cfg_cmd)&faversion) &&
+ (GET_PWR_CFG_CUT_MASK(cfg_cmd)&cut_version) &&
+ (GET_PWR_CFG_INTF_MASK(cfg_cmd)&interface_type)) {
+ switch (GET_PWR_CFG_CMD(cfg_cmd)) {
+ case PWR_CMD_READ:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtl_hal_pwrseqcmdparsing(): PWR_CMD_READ\n");
+ break;
+ case PWR_CMD_WRITE:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtl_hal_pwrseqcmdparsing(): PWR_CMD_WRITE\n");
+ offset = GET_PWR_CFG_OFFSET(cfg_cmd);
+
+ /*Read the value from system register*/
+ value = rtl_read_byte(rtlpriv, offset);
+ value &= (~(GET_PWR_CFG_MASK(cfg_cmd)));
+ value |= (GET_PWR_CFG_VALUE(cfg_cmd) &
+ GET_PWR_CFG_MASK(cfg_cmd));
+
+ /*Write the value back to sytem register*/
+ rtl_write_byte(rtlpriv, offset, value);
+ break;
+ case PWR_CMD_POLLING:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtl_hal_pwrseqcmdparsing(): PWR_CMD_POLLING\n");
+ polling_bit = false;
+ offset = GET_PWR_CFG_OFFSET(cfg_cmd);
+
+ do {
+ value = rtl_read_byte(rtlpriv, offset);
+
+ value &= GET_PWR_CFG_MASK(cfg_cmd);
+ if (value ==
+ (GET_PWR_CFG_VALUE(cfg_cmd)
+ & GET_PWR_CFG_MASK(cfg_cmd)))
+ polling_bit = true;
+ else
+ udelay(10);
+
+ if (polling_count++ > max_polling_cnt)
+ return false;
+ } while (!polling_bit);
+ break;
+ case PWR_CMD_DELAY:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtl_hal_pwrseqcmdparsing(): PWR_CMD_DELAY\n");
+ if (GET_PWR_CFG_VALUE(cfg_cmd) ==
+ PWRSEQ_DELAY_US)
+ udelay(GET_PWR_CFG_OFFSET(cfg_cmd));
+ else
+ mdelay(GET_PWR_CFG_OFFSET(cfg_cmd));
+ break;
+ case PWR_CMD_END:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtl_hal_pwrseqcmdparsing(): PWR_CMD_END\n");
+ return true;
+ default:
+ RT_ASSERT(false,
+ "rtl_hal_pwrseqcmdparsing(): Unknown CMD!!\n");
+ break;
+ }
+
+ }
+ ary_idx++;
+ } while (1);
+
+ return true;
+}
+EXPORT_SYMBOL(rtl_hal_pwrseqcmdparsing);
+
bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -48,7 +148,7 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
/*<2> Enable Adapter */
if (rtlpriv->cfg->ops->hw_init(hw))
- return 1;
+ return false;
RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
/*<3> Enable Interrupt */
@@ -659,7 +759,7 @@ static void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data,
unsigned int len)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct ieee80211_mgmt *mgmt = (void *)data;
+ struct ieee80211_mgmt *mgmt = data;
struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
u8 *pos, *end, *ie;
u16 noa_len;
@@ -758,7 +858,7 @@ static void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data,
unsigned int len)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct ieee80211_mgmt *mgmt = (void *)data;
+ struct ieee80211_mgmt *mgmt = data;
struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
u8 noa_num, index, i, noa_index = 0;
u8 *pos, *end, *ie;
@@ -850,9 +950,8 @@ void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
switch (p2p_ps_state) {
case P2P_PS_DISABLE:
p2pinfo->p2p_ps_state = p2p_ps_state;
- rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
- (u8 *)(&p2p_ps_state));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
+ &p2p_ps_state);
p2pinfo->noa_index = 0;
p2pinfo->ctwindow = 0;
@@ -864,7 +963,7 @@ void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
rtlps->smart_ps = 2;
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_H2C_FW_PWRMODE,
- (u8 *)(&rtlps->pwr_mode));
+ &rtlps->pwr_mode);
}
}
break;
@@ -877,12 +976,12 @@ void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
rtlps->smart_ps = 0;
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_H2C_FW_PWRMODE,
- (u8 *)(&rtlps->pwr_mode));
+ &rtlps->pwr_mode);
}
}
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
- (u8 *)(&p2p_ps_state));
+ &p2p_ps_state);
}
break;
case P2P_PS_SCAN:
@@ -892,7 +991,7 @@ void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
p2pinfo->p2p_ps_state = p2p_ps_state;
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
- (u8 *)(&p2p_ps_state));
+ &p2p_ps_state);
}
break;
default:
@@ -912,7 +1011,7 @@ void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- struct ieee80211_hdr *hdr = (void *)data;
+ struct ieee80211_hdr *hdr = data;
if (!mac->p2p)
return;
diff --git a/drivers/net/wireless/rtlwifi/ps.h b/drivers/net/wireless/rtlwifi/ps.h
index 88bd76ea88f7..3bd41f958974 100644
--- a/drivers/net/wireless/rtlwifi/ps.h
+++ b/drivers/net/wireless/rtlwifi/ps.h
@@ -32,6 +32,66 @@
#define MAX_SW_LPS_SLEEP_INTV 5
+/*---------------------------------------------
+ * 3 The value of cmd: 4 bits
+ *---------------------------------------------
+ */
+#define PWR_CMD_READ 0x00
+#define PWR_CMD_WRITE 0x01
+#define PWR_CMD_POLLING 0x02
+#define PWR_CMD_DELAY 0x03
+#define PWR_CMD_END 0x04
+
+/* 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
+
+#define PWR_FAB_ALL_MSK (BIT(0)|BIT(1)|BIT(2)|BIT(3))
+#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
+#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))
+
+enum pwrseq_delay_unit {
+ PWRSEQ_DELAY_US,
+ PWRSEQ_DELAY_MS,
+};
+
+struct wlan_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)
+
+bool rtl_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
+ u8 fab_version, u8 interface_type,
+ struct wlan_pwr_cfg pwrcfgcmd[]);
+
bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
enum rf_pwrstate state_toset, u32 changesource);
bool rtl_ps_enable_nic(struct ieee80211_hw *hw);
diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c
index a98acefb8c06..ee28a1a3d010 100644
--- a/drivers/net/wireless/rtlwifi/rc.c
+++ b/drivers/net/wireless/rtlwifi/rc.c
@@ -260,8 +260,7 @@ static void rtl_rate_free_sta(void *rtlpriv,
kfree(rate_priv);
}
-static struct rate_control_ops rtl_rate_ops = {
- .module = NULL,
+static const struct rate_control_ops rtl_rate_ops = {
.name = "rtl_rc",
.alloc = rtl_rate_alloc,
.free = rtl_rate_free,
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/Makefile b/drivers/net/wireless/rtlwifi/rtl8188ee/Makefile
index 5b194e97f4b3..a85419a37651 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/Makefile
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/Makefile
@@ -5,7 +5,6 @@ rtl8188ee-objs := \
led.o \
phy.o \
pwrseq.o \
- pwrseqcmd.o \
rf.o \
sw.o \
table.o \
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
index a6184b6e1d57..f8daa61cf1c3 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
@@ -235,7 +235,7 @@ void rtl88e_dm_txpower_track_adjust(struct ieee80211_hw *hw,
u8 pwr_val = 0;
u8 cck_base = rtldm->swing_idx_cck_base;
u8 cck_val = rtldm->swing_idx_cck;
- u8 ofdm_base = rtldm->swing_idx_ofdm_base;
+ u8 ofdm_base = rtldm->swing_idx_ofdm_base[0];
u8 ofdm_val = rtlpriv->dm.swing_idx_ofdm[RF90_PATH_A];
if (type == 0) {
@@ -726,7 +726,7 @@ static void rtl88e_dm_pwdb_monitor(struct ieee80211_hw *hw)
static u64 last_rx;
long tmp_entry_max_pwdb = 0, tmp_entry_min_pwdb = 0xff;
- if (rtlhal->oem_id == RT_CID_819x_HP) {
+ if (rtlhal->oem_id == RT_CID_819X_HP) {
u64 cur_txok_cnt = 0;
u64 cur_rxok_cnt = 0;
cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok;
@@ -851,9 +851,8 @@ static void rtl88e_dm_check_edca_turbo(struct ieee80211_hw *hw)
} else {
if (rtlpriv->dm.current_turbo_edca) {
u8 tmp = AC0_BE;
- rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_AC_PARAM,
- (u8 *)(&tmp));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
+ &tmp);
rtlpriv->dm.current_turbo_edca = false;
}
}
@@ -912,7 +911,7 @@ static void rtl88e_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
for (i = 0; i < OFDM_TABLE_LENGTH; i++) {
if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) {
ofdm_old[0] = (u8) i;
- rtldm->swing_idx_ofdm_base = (u8)i;
+ rtldm->swing_idx_ofdm_base[0] = (u8)i;
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Initial pathA ele_d reg0x%x = 0x%lx, ofdm_index = 0x%x\n",
ROFDM0_XATXIQIMBAL,
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c
index 557bc5b8327e..4f9376ad4739 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c
@@ -119,7 +119,7 @@ static void _rtl88e_write_fw(struct ieee80211_hw *hw,
enum version_8188e version, u8 *buffer, u32 size)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- u8 *buf_ptr = (u8 *)buffer;
+ u8 *buf_ptr = buffer;
u32 page_no, remain;
u32 page, offset;
@@ -213,7 +213,7 @@ int rtl88e_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)
return 1;
pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
- pfwdata = (u8 *)rtlhal->pfirmware;
+ pfwdata = rtlhal->pfirmware;
fwsize = rtlhal->fwsize;
RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
"normal Firmware SIZE %d\n", fwsize);
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
index e06971be7df7..94cd9df98381 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
@@ -41,7 +41,6 @@
#include "fw.h"
#include "led.h"
#include "hw.h"
-#include "pwrseqcmd.h"
#include "pwrseq.h"
#define LLT_CONFIG 5
@@ -148,8 +147,7 @@ static void _rtl88ee_set_fw_clock_on(struct ieee80211_hw *hw,
}
if (IS_IN_LOW_POWER_STATE_88E(rtlhal->fw_ps_state)) {
- rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_SET_RPWM,
- (u8 *)(&rpwm_val));
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_SET_RPWM, &rpwm_val);
if (FW_PS_IS_ACK(rpwm_val)) {
isr_regaddr = REG_HISR;
content = rtl_read_dword(rtlpriv, isr_regaddr);
@@ -226,7 +224,7 @@ static void _rtl88ee_set_fw_clock_off(struct ieee80211_hw *hw,
rtlhal->fw_ps_state = FW_PS_STATE(rpwm_val);
rtl_write_word(rtlpriv, REG_HISR, 0x0100);
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
- (u8 *)(&rpwm_val));
+ &rpwm_val);
spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
rtlhal->fw_clk_change_in_progress = false;
spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
@@ -274,15 +272,14 @@ static void _rtl88ee_fwlps_leave(struct ieee80211_hw *hw)
_rtl88ee_set_fw_clock_on(hw, rpwm_val, false);
rtlhal->allow_sw_to_change_hwclc = false;
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
- (u8 *)(&fw_pwrmode));
+ &fw_pwrmode);
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
(u8 *)(&fw_current_inps));
} else {
rpwm_val = FW_PS_STATE_ALL_ON_88E; /* RF on */
- rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
- (u8 *)(&rpwm_val));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, &rpwm_val);
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
- (u8 *)(&fw_pwrmode));
+ &fw_pwrmode);
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
(u8 *)(&fw_current_inps));
}
@@ -301,7 +298,7 @@ static void _rtl88ee_fwlps_enter(struct ieee80211_hw *hw)
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
(u8 *)(&fw_current_inps));
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
- (u8 *)(&ppsc->fwctrl_psmode));
+ &ppsc->fwctrl_psmode);
rtlhal->allow_sw_to_change_hwclc = true;
_rtl88ee_set_fw_clock_off(hw, rpwm_val);
} else {
@@ -309,9 +306,8 @@ static void _rtl88ee_fwlps_enter(struct ieee80211_hw *hw)
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
(u8 *)(&fw_current_inps));
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
- (u8 *)(&ppsc->fwctrl_psmode));
- rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
- (u8 *)(&rpwm_val));
+ &ppsc->fwctrl_psmode);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, &rpwm_val);
}
}
@@ -420,12 +416,12 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
for (e_aci = 0; e_aci < AC_MAX; e_aci++) {
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
- (u8 *)(&e_aci));
+ &e_aci);
}
break; }
case HW_VAR_ACK_PREAMBLE:{
u8 reg_tmp;
- u8 short_preamble = (bool) (*(u8 *)val);
+ u8 short_preamble = (bool)*val;
reg_tmp = rtl_read_byte(rtlpriv, REG_TRXPTCL_CTL+2);
if (short_preamble) {
reg_tmp |= 0x02;
@@ -436,13 +432,13 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
}
break; }
case HW_VAR_WPA_CONFIG:
- rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *)val));
+ rtl_write_byte(rtlpriv, REG_SECCFG, *val);
break;
case HW_VAR_AMPDU_MIN_SPACE:{
u8 min_spacing_to_set;
u8 sec_min_space;
- min_spacing_to_set = *((u8 *)val);
+ min_spacing_to_set = *val;
if (min_spacing_to_set <= 7) {
sec_min_space = 0;
@@ -465,7 +461,7 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
case HW_VAR_SHORTGI_DENSITY:{
u8 density_to_set;
- density_to_set = *((u8 *)val);
+ density_to_set = *val;
mac->min_space_cfg |= (density_to_set << 3);
RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
@@ -483,7 +479,7 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
reg = regtoset_normal;
- factor = *((u8 *)val);
+ factor = *val;
if (factor <= 3) {
factor = (1 << (factor + 2));
if (factor > 0xf)
@@ -506,15 +502,15 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
}
break; }
case HW_VAR_AC_PARAM:{
- u8 e_aci = *((u8 *)val);
+ u8 e_aci = *val;
rtl88e_dm_init_edca_turbo(hw);
- if (rtlpci->acm_method != eAcmWay2_SW)
+ if (rtlpci->acm_method != EACMWAY2_SW)
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL,
- (u8 *)(&e_aci));
+ &e_aci);
break; }
case HW_VAR_ACM_CTRL:{
- u8 e_aci = *((u8 *)val);
+ u8 e_aci = *val;
union aci_aifsn *p_aci_aifsn =
(union aci_aifsn *)(&(mac->ac[0].aifs));
u8 acm = p_aci_aifsn->f.acm;
@@ -567,7 +563,7 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
rtlpci->receive_config = ((u32 *)(val))[0];
break;
case HW_VAR_RETRY_LIMIT:{
- u8 retry_limit = ((u8 *)(val))[0];
+ u8 retry_limit = *val;
rtl_write_word(rtlpriv, REG_RL,
retry_limit << RETRY_LIMIT_SHORT_SHIFT |
@@ -580,7 +576,7 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
rtlefuse->efuse_usedbytes = *((u16 *)val);
break;
case HW_VAR_EFUSE_USAGE:
- rtlefuse->efuse_usedpercentage = *((u8 *)val);
+ rtlefuse->efuse_usedpercentage = *val;
break;
case HW_VAR_IO_CMD:
rtl88e_phy_set_io_cmd(hw, (*(enum io_type *)val));
@@ -592,15 +588,13 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
udelay(1);
if (rpwm_val & BIT(7)) {
- rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
- (*(u8 *)val));
+ rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, *val);
} else {
- rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
- ((*(u8 *)val) | BIT(7)));
+ rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, *val | BIT(7));
}
break; }
case HW_VAR_H2C_FW_PWRMODE:
- rtl88e_set_fw_pwrmode_cmd(hw, (*(u8 *)val));
+ rtl88e_set_fw_pwrmode_cmd(hw, *val);
break;
case HW_VAR_FW_PSMODE_STATUS:
ppsc->fw_current_inpsmode = *((bool *)val);
@@ -617,7 +611,7 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
_rtl88ee_fwlps_leave(hw);
break; }
case HW_VAR_H2C_FW_JOINBSSRPT:{
- u8 mstatus = (*(u8 *)val);
+ u8 mstatus = *val;
u8 tmp, tmp_reg422, uval;
u8 count = 0, dlbcn_count = 0;
bool recover = false;
@@ -668,10 +662,10 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
}
rtl_write_byte(rtlpriv, REG_CR + 1, (tmp & ~(BIT(0))));
}
- rtl88e_set_fw_joinbss_report_cmd(hw, (*(u8 *)val));
+ rtl88e_set_fw_joinbss_report_cmd(hw, *val);
break; }
case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
- rtl88e_set_p2p_ps_offload_cmd(hw, (*(u8 *)val));
+ rtl88e_set_p2p_ps_offload_cmd(hw, *val);
break;
case HW_VAR_AID:{
u16 u2btmp;
@@ -681,7 +675,7 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
mac->assoc_id));
break; }
case HW_VAR_CORRECT_TSF:{
- u8 btype_ibss = ((u8 *)(val))[0];
+ u8 btype_ibss = *val;
if (btype_ibss == true)
_rtl88ee_stop_tx_beacon(hw);
@@ -815,11 +809,11 @@ static bool _rtl88ee_init_mac(struct ieee80211_hw *hw)
rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00);
/* HW Power on sequence */
- if (!rtl88_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK,
- PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,
- Rtl8188E_NIC_ENABLE_FLOW)) {
+ if (!rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK,
+ PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,
+ Rtl8188E_NIC_ENABLE_FLOW)) {
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
- "init MAC Fail as rtl88_hal_pwrseqcmdparsing\n");
+ "init MAC Fail as rtl_hal_pwrseqcmdparsing\n");
return false;
}
@@ -1025,9 +1019,20 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw)
bool rtstatus = true;
int err = 0;
u8 tmp_u1b, u1byte;
+ unsigned long flags;
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Rtl8188EE hw init\n");
rtlpriv->rtlhal.being_init_adapter = true;
+ /* As this function can take a very long time (up to 350 ms)
+ * and can be called with irqs disabled, reenable the irqs
+ * to let the other devices continue being serviced.
+ *
+ * It is safe doing so since our own interrupts will only be enabled
+ * in a subsequent step.
+ */
+ local_save_flags(flags);
+ local_irq_enable();
+
rtlpriv->intf_ops->disable_aspm(hw);
tmp_u1b = rtl_read_byte(rtlpriv, REG_SYS_CLKR+1);
@@ -1043,7 +1048,7 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw)
if (rtstatus != true) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n");
err = 1;
- return err;
+ goto exit;
}
err = rtl88e_download_fw(hw, false);
@@ -1051,8 +1056,7 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"Failed to download FW. Init HW without FW now..\n");
err = 1;
- rtlhal->fw_ready = false;
- return err;
+ goto exit;
} else {
rtlhal->fw_ready = true;
}
@@ -1097,7 +1101,7 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw)
if (ppsc->rfpwr_state == ERFON) {
if ((rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV) ||
((rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) &&
- (rtlhal->oem_id == RT_CID_819x_HP))) {
+ (rtlhal->oem_id == RT_CID_819X_HP))) {
rtl88e_phy_set_rfpath_switch(hw, true);
rtlpriv->dm.fat_table.rx_idle_ant = MAIN_ANT;
} else {
@@ -1135,10 +1139,12 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw)
}
rtl_write_byte(rtlpriv, REG_NAV_CTRL+2, ((30000+127)/128));
rtl88e_dm_init(hw);
+exit:
+ local_irq_restore(flags);
rtlpriv->rtlhal.being_init_adapter = false;
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "end of Rtl8188EE hw init %x\n",
err);
- return 0;
+ return err;
}
static enum version_8188e _rtl88ee_read_chip_version(struct ieee80211_hw *hw)
@@ -1235,12 +1241,13 @@ static int _rtl88ee_set_media_status(struct ieee80211_hw *hw,
void rtl88ee_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- u32 reg_rcr = rtlpci->receive_config;
+ u32 reg_rcr;
if (rtlpriv->psc.rfpwr_state != ERFON)
return;
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
+
if (check_bssid == true) {
reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
@@ -1345,9 +1352,9 @@ static void _rtl88ee_poweroff_adapter(struct ieee80211_hw *hw)
}
rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG+1, 0xFF);
- rtl88_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
- PWR_INTF_PCI_MSK,
- Rtl8188E_NIC_LPS_ENTER_FLOW);
+ rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+ PWR_INTF_PCI_MSK,
+ Rtl8188E_NIC_LPS_ENTER_FLOW);
rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00);
@@ -1361,8 +1368,8 @@ static void _rtl88ee_poweroff_adapter(struct ieee80211_hw *hw)
u1b_tmp = rtl_read_byte(rtlpriv, REG_32K_CTRL);
rtl_write_byte(rtlpriv, REG_32K_CTRL, (u1b_tmp & (~BIT(0))));
- rtl88_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
- PWR_INTF_PCI_MSK, Rtl8188E_NIC_DISABLE_FLOW);
+ rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+ PWR_INTF_PCI_MSK, Rtl8188E_NIC_DISABLE_FLOW);
u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL+1);
rtl_write_byte(rtlpriv, REG_RSV_CTRL+1, (u1b_tmp & (~BIT(3))));
@@ -1816,7 +1823,7 @@ static void _rtl88ee_read_adapter_info(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
"EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid);
/*customer ID*/
- rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID];
+ rtlefuse->eeprom_oemid = hwinfo[EEPROM_CUSTOMER_ID];
if (rtlefuse->eeprom_oemid == 0xFF)
rtlefuse->eeprom_oemid = 0;
@@ -1833,7 +1840,7 @@ static void _rtl88ee_read_adapter_info(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
"dev_addr: %pM\n", rtlefuse->dev_addr);
/*channel plan */
- rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
+ rtlefuse->eeprom_channelplan = hwinfo[EEPROM_CHANNELPLAN];
/* set channel paln to world wide 13 */
rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13;
/*tx power*/
@@ -1845,7 +1852,7 @@ static void _rtl88ee_read_adapter_info(struct ieee80211_hw *hw)
rtlefuse->autoload_failflag,
hwinfo);
/*board type*/
- rtlefuse->board_type = (((*(u8 *)&hwinfo[jj]) & 0xE0) >> 5);
+ rtlefuse->board_type = (hwinfo[jj] & 0xE0) >> 5;
/*Wake on wlan*/
rtlefuse->wowlan_enable = ((hwinfo[kk] & 0x40) >> 6);
/*parse xtal*/
@@ -1872,15 +1879,15 @@ static void _rtl88ee_read_adapter_info(struct ieee80211_hw *hw)
case EEPROM_CID_DEFAULT:
if (rtlefuse->eeprom_did == 0x8179) {
if (rtlefuse->eeprom_svid == 0x1025) {
- rtlhal->oem_id = RT_CID_819x_Acer;
+ rtlhal->oem_id = RT_CID_819X_ACER;
} else if ((rtlefuse->eeprom_svid == 0x10EC &&
rtlefuse->eeprom_smid == 0x0179) ||
(rtlefuse->eeprom_svid == 0x17AA &&
rtlefuse->eeprom_smid == 0x0179)) {
- rtlhal->oem_id = RT_CID_819x_Lenovo;
+ rtlhal->oem_id = RT_CID_819X_LENOVO;
} else if (rtlefuse->eeprom_svid == 0x103c &&
rtlefuse->eeprom_smid == 0x197d) {
- rtlhal->oem_id = RT_CID_819x_HP;
+ rtlhal->oem_id = RT_CID_819X_HP;
} else {
rtlhal->oem_id = RT_CID_DEFAULT;
}
@@ -1892,7 +1899,7 @@ static void _rtl88ee_read_adapter_info(struct ieee80211_hw *hw)
rtlhal->oem_id = RT_CID_TOSHIBA;
break;
case EEPROM_CID_QMI:
- rtlhal->oem_id = RT_CID_819x_QMI;
+ rtlhal->oem_id = RT_CID_819X_QMI;
break;
case EEPROM_CID_WHQL:
default:
@@ -1911,14 +1918,14 @@ static void _rtl88ee_hal_customized_behavior(struct ieee80211_hw *hw)
pcipriv->ledctl.led_opendrain = true;
switch (rtlhal->oem_id) {
- case RT_CID_819x_HP:
+ case RT_CID_819X_HP:
pcipriv->ledctl.led_opendrain = true;
break;
- case RT_CID_819x_Lenovo:
+ case RT_CID_819X_LENOVO:
case RT_CID_DEFAULT:
case RT_CID_TOSHIBA:
case RT_CID_CCX:
- case RT_CID_819x_Acer:
+ case RT_CID_819X_ACER:
case RT_CID_WHQL:
default:
break;
@@ -2211,8 +2218,7 @@ void rtl88ee_update_channel_access_setting(struct ieee80211_hw *hw)
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
u16 sifs_timer;
- rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
- (u8 *)&mac->slot_time);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME, &mac->slot_time);
if (!mac->ht_enable)
sifs_timer = 0x0a0a;
else
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c b/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c
index d67f9c731cc4..1cd6c16d597e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c
@@ -29,6 +29,7 @@
#include "../wifi.h"
#include "../pci.h"
+#include "../core.h"
#include "../ps.h"
#include "reg.h"
#include "def.h"
@@ -151,18 +152,7 @@ static bool config_bb_with_pgheader(struct ieee80211_hw *hw,
v2 = table_pg[i + 1];
if (v1 < 0xcdcdcdcd) {
- if (table_pg[i] == 0xfe)
- mdelay(50);
- else if (table_pg[i] == 0xfd)
- mdelay(5);
- else if (table_pg[i] == 0xfc)
- mdelay(1);
- else if (table_pg[i] == 0xfb)
- udelay(50);
- else if (table_pg[i] == 0xfa)
- udelay(5);
- else if (table_pg[i] == 0xf9)
- udelay(1);
+ rtl_addr_delay(table_pg[i]);
store_pwrindex_offset(hw, table_pg[i],
table_pg[i + 1],
@@ -672,24 +662,9 @@ static void _rtl8188e_config_rf_reg(struct ieee80211_hw *hw,
u32 addr, u32 data, enum radio_path rfpath,
u32 regaddr)
{
- if (addr == 0xffe) {
- mdelay(50);
- } else if (addr == 0xfd) {
- mdelay(5);
- } else if (addr == 0xfc) {
- mdelay(1);
- } else if (addr == 0xfb) {
- udelay(50);
- } else if (addr == 0xfa) {
- udelay(5);
- } else if (addr == 0xf9) {
- udelay(1);
- } else {
- rtl_set_rfreg(hw, rfpath, regaddr,
- RFREG_OFFSET_MASK,
- data);
- udelay(1);
- }
+ rtl_rfreg_delay(hw, rfpath, regaddr,
+ RFREG_OFFSET_MASK,
+ data);
}
static void rtl88_config_s(struct ieee80211_hw *hw,
@@ -702,28 +677,6 @@ static void rtl88_config_s(struct ieee80211_hw *hw,
addr | maskforphyset);
}
-static void _rtl8188e_config_bb_reg(struct ieee80211_hw *hw,
- u32 addr, u32 data)
-{
- if (addr == 0xfe) {
- mdelay(50);
- } else if (addr == 0xfd) {
- mdelay(5);
- } else if (addr == 0xfc) {
- mdelay(1);
- } else if (addr == 0xfb) {
- udelay(50);
- } else if (addr == 0xfa) {
- udelay(5);
- } else if (addr == 0xf9) {
- udelay(1);
- } else {
- rtl_set_bbreg(hw, addr, MASKDWORD, data);
- udelay(1);
- }
-}
-
-
#define NEXT_PAIR(v1, v2, i) \
do { \
i += 2; v1 = array_table[i]; \
@@ -795,7 +748,7 @@ static void set_baseband_phy_config(struct ieee80211_hw *hw)
v1 = array_table[i];
v2 = array_table[i + 1];
if (v1 < 0xcdcdcdcd) {
- _rtl8188e_config_bb_reg(hw, v1, v2);
+ rtl_bb_delay(hw, v1, v2);
} else {/*This line is the start line of branch.*/
if (!check_cond(hw, array_table[i])) {
/*Discard the following (offset, data) pairs*/
@@ -811,7 +764,7 @@ static void set_baseband_phy_config(struct ieee80211_hw *hw)
while (v2 != 0xDEAD &&
v2 != 0xCDEF &&
v2 != 0xCDCD && i < arraylen - 2) {
- _rtl8188e_config_bb_reg(hw, v1, v2);
+ rtl_bb_delay(hw, v1, v2);
NEXT_PAIR(v1, v2, i);
}
@@ -1002,7 +955,7 @@ bool rtl88e_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
}
}
- if (rtlhal->oem_id == RT_CID_819x_HP)
+ if (rtlhal->oem_id == RT_CID_819X_HP)
rtl88_config_s(hw, 0x52, 0x7E4BD);
break;
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h
index 028ec6dd52b4..32e135ab9a63 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h
@@ -30,7 +30,6 @@
#ifndef __RTL8723E_PWRSEQ_H__
#define __RTL8723E_PWRSEQ_H__
-#include "pwrseqcmd.h"
/*
Check document WM-20110607-Paul-RTL8188E_Power_Architecture-R02.vsd
There are 6 HW Power States:
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h b/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h
index d849abf7d94a..7af85cfa8f87 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h
@@ -2215,22 +2215,6 @@
#define BWORD1 0xc
#define BWORD 0xf
-#define MASKBYTE0 0xff
-#define MASKBYTE1 0xff00
-#define MASKBYTE2 0xff0000
-#define MASKBYTE3 0xff000000
-#define MASKHWORD 0xffff0000
-#define MASKLWORD 0x0000ffff
-#define MASKDWORD 0xffffffff
-#define MASK12BITS 0xfff
-#define MASKH4BITS 0xf0000000
-#define MASKOFDM_D 0xffc00000
-#define MASKCCK 0x3f3f3f3f
-
-#define MASK4BITS 0x0f
-#define MASK20BITS 0xfffff
-#define RFREG_OFFSET_MASK 0xfffff
-
#define BENABLE 0x1
#define BDISABLE 0x0
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/sw.c
index 347af1e4f438..1b4101bf9974 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/sw.c
@@ -93,6 +93,7 @@ int rtl88e_init_sw_vars(struct ieee80211_hw *hw)
u8 tid;
rtl8188ee_bt_reg_init(hw);
+ rtlpci->msi_support = true;
rtlpriv->dm.dm_initialgain_enable = 1;
rtlpriv->dm.dm_flag = 0;
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
index aece6c9cccf1..06ef47cd6203 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
@@ -452,7 +452,7 @@ bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw,
/* During testing, hdr was NULL */
return false;
}
- if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
+ if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
(ieee80211_has_protected(hdr->frame_control)))
rx_status->flag &= ~RX_FLAG_DECRYPTED;
else
@@ -489,16 +489,15 @@ bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw,
void rtl88ee_tx_fill_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr, u8 *pdesc_tx,
- struct ieee80211_tx_info *info,
- struct ieee80211_sta *sta,
- struct sk_buff *skb,
+ u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta, struct sk_buff *skb,
u8 hw_queue, struct rtl_tcb_desc *ptcb_desc)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
- u8 *pdesc = (u8 *)pdesc_tx;
+ u8 *pdesc = pdesc_tx;
u16 seq_number;
__le16 fc = hdr->frame_control;
unsigned int buf_len = 0;
@@ -717,7 +716,7 @@ void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw,
SET_TX_DESC_OWN(pdesc, 1);
- SET_TX_DESC_PKT_SIZE((u8 *)pdesc, (u16)(skb->len));
+ SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len));
SET_TX_DESC_FIRST_SEG(pdesc, 1);
SET_TX_DESC_LAST_SEG(pdesc, 1);
@@ -734,7 +733,8 @@ void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw,
pdesc, TX_DESC_SIZE);
}
-void rtl88ee_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
+void rtl88ee_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+ u8 desc_name, u8 *val)
{
if (istx == true) {
switch (desc_name) {
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h
index 21ca33a7c770..8c2609412d2c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h
@@ -777,15 +777,15 @@ struct rx_desc_88e {
void rtl88ee_tx_fill_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr, u8 *pdesc_tx,
- struct ieee80211_tx_info *info,
- struct ieee80211_sta *sta,
- struct sk_buff *skb,
+ u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta, struct sk_buff *skb,
u8 hw_queue, struct rtl_tcb_desc *ptcb_desc);
bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw,
struct rtl_stats *status,
struct ieee80211_rx_status *rx_status,
u8 *pdesc, struct sk_buff *skb);
-void rtl88ee_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val);
+void rtl88ee_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+ u8 desc_name, u8 *val);
u32 rtl88ee_get_desc(u8 *pdesc, bool istx, u8 desc_name);
void rtl88ee_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
index a82b30a1996c..55adf043aef7 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
@@ -319,7 +319,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
u8 e_aci = *(val);
rtl92c_dm_init_edca_turbo(hw);
- if (rtlpci->acm_method != eAcmWay2_SW)
+ if (rtlpci->acm_method != EACMWAY2_SW)
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_ACM_CTRL,
(&e_aci));
@@ -476,7 +476,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
break;
}
case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
- rtl92c_set_p2p_ps_offload_cmd(hw, (*(u8 *)val));
+ rtl92c_set_p2p_ps_offload_cmd(hw, *val);
break;
case HW_VAR_AID:{
u16 u2btmp;
@@ -521,30 +521,32 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
(u8 *)(&fw_current_inps));
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_H2C_FW_PWRMODE,
- (u8 *)(&ppsc->fwctrl_psmode));
+ &ppsc->fwctrl_psmode);
rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_SET_RPWM,
- (u8 *)(&rpwm_val));
+ HW_VAR_SET_RPWM,
+ &rpwm_val);
} else {
rpwm_val = 0x0C; /* RF on */
fw_pwrmode = FW_PS_ACTIVE_MODE;
fw_current_inps = false;
rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_SET_RPWM,
- (u8 *)(&rpwm_val));
+ HW_VAR_SET_RPWM,
+ &rpwm_val);
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_H2C_FW_PWRMODE,
- (u8 *)(&fw_pwrmode));
+ &fw_pwrmode);
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_FW_PSMODE_STATUS,
(u8 *)(&fw_current_inps));
}
break; }
+ case HW_VAR_KEEP_ALIVE:
+ break;
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
- "switch case not processed\n");
+ "switch case %d not processed\n", variable);
break;
}
}
@@ -937,14 +939,26 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
bool is92c;
int err;
u8 tmp_u1b;
+ unsigned long flags;
rtlpci->being_init_adapter = true;
+
+ /* Since this function can take a very long time (up to 350 ms)
+ * and can be called with irqs disabled, reenable the irqs
+ * to let the other devices continue being serviced.
+ *
+ * It is safe doing so since our own interrupts will only be enabled
+ * in a subsequent step.
+ */
+ local_save_flags(flags);
+ local_irq_enable();
+
rtlpriv->intf_ops->disable_aspm(hw);
rtstatus = _rtl92ce_init_mac(hw);
if (!rtstatus) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n");
err = 1;
- return err;
+ goto exit;
}
err = rtl92c_download_fw(hw);
@@ -952,7 +966,7 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"Failed to download FW. Init HW without FW now..\n");
err = 1;
- return err;
+ goto exit;
}
rtlhal->last_hmeboxnum = 0;
@@ -1032,6 +1046,8 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "under 1.5V\n");
}
rtl92c_dm_init(hw);
+exit:
+ local_irq_restore(flags);
rtlpci->being_init_adapter = false;
return err;
}
@@ -1200,11 +1216,13 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw,
void rtl92ce_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR);
+ u32 reg_rcr;
if (rtlpriv->psc.rfpwr_state != ERFON)
return;
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
+
if (check_bssid) {
reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
@@ -1720,7 +1738,7 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw)
if (rtlefuse->eeprom_did == 0x8176) {
if ((rtlefuse->eeprom_svid == 0x103C &&
rtlefuse->eeprom_smid == 0x1629))
- rtlhal->oem_id = RT_CID_819x_HP;
+ rtlhal->oem_id = RT_CID_819X_HP;
else
rtlhal->oem_id = RT_CID_DEFAULT;
} else {
@@ -1731,7 +1749,7 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw)
rtlhal->oem_id = RT_CID_TOSHIBA;
break;
case EEPROM_CID_QMI:
- rtlhal->oem_id = RT_CID_819x_QMI;
+ rtlhal->oem_id = RT_CID_819X_QMI;
break;
case EEPROM_CID_WHQL:
default:
@@ -1750,14 +1768,14 @@ static void _rtl92ce_hal_customized_behavior(struct ieee80211_hw *hw)
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
switch (rtlhal->oem_id) {
- case RT_CID_819x_HP:
+ case RT_CID_819X_HP:
pcipriv->ledctl.led_opendrain = true;
break;
- case RT_CID_819x_Lenovo:
+ case RT_CID_819X_LENOVO:
case RT_CID_DEFAULT:
case RT_CID_TOSHIBA:
case RT_CID_CCX:
- case RT_CID_819x_Acer:
+ case RT_CID_819X_ACER:
case RT_CID_WHQL:
default:
break;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
index 73262ca3864b..98b22303c84d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
@@ -30,6 +30,7 @@
#include "../wifi.h"
#include "../pci.h"
#include "../ps.h"
+#include "../core.h"
#include "reg.h"
#include "def.h"
#include "hw.h"
@@ -198,18 +199,7 @@ bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
}
if (configtype == BASEBAND_CONFIG_PHY_REG) {
for (i = 0; i < phy_reg_arraylen; i = i + 2) {
- if (phy_regarray_table[i] == 0xfe)
- mdelay(50);
- else if (phy_regarray_table[i] == 0xfd)
- mdelay(5);
- else if (phy_regarray_table[i] == 0xfc)
- mdelay(1);
- else if (phy_regarray_table[i] == 0xfb)
- udelay(50);
- else if (phy_regarray_table[i] == 0xfa)
- udelay(5);
- else if (phy_regarray_table[i] == 0xf9)
- udelay(1);
+ rtl_addr_delay(phy_regarray_table[i]);
rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD,
phy_regarray_table[i + 1]);
udelay(1);
@@ -245,18 +235,7 @@ bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
if (configtype == BASEBAND_CONFIG_PHY_REG) {
for (i = 0; i < phy_regarray_pg_len; i = i + 3) {
- if (phy_regarray_table_pg[i] == 0xfe)
- mdelay(50);
- else if (phy_regarray_table_pg[i] == 0xfd)
- mdelay(5);
- else if (phy_regarray_table_pg[i] == 0xfc)
- mdelay(1);
- else if (phy_regarray_table_pg[i] == 0xfb)
- udelay(50);
- else if (phy_regarray_table_pg[i] == 0xfa)
- udelay(5);
- else if (phy_regarray_table_pg[i] == 0xf9)
- udelay(1);
+ rtl_addr_delay(phy_regarray_table_pg[i]);
_rtl92c_store_pwrIndex_diffrate_offset(hw,
phy_regarray_table_pg[i],
@@ -305,46 +284,16 @@ bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
switch (rfpath) {
case RF90_PATH_A:
for (i = 0; i < radioa_arraylen; i = i + 2) {
- if (radioa_array_table[i] == 0xfe)
- mdelay(50);
- else if (radioa_array_table[i] == 0xfd)
- mdelay(5);
- else if (radioa_array_table[i] == 0xfc)
- mdelay(1);
- else if (radioa_array_table[i] == 0xfb)
- udelay(50);
- else if (radioa_array_table[i] == 0xfa)
- udelay(5);
- else if (radioa_array_table[i] == 0xf9)
- udelay(1);
- else {
- rtl_set_rfreg(hw, rfpath, radioa_array_table[i],
- RFREG_OFFSET_MASK,
- radioa_array_table[i + 1]);
- udelay(1);
- }
+ rtl_rfreg_delay(hw, rfpath, radioa_array_table[i],
+ RFREG_OFFSET_MASK,
+ radioa_array_table[i + 1]);
}
break;
case RF90_PATH_B:
for (i = 0; i < radiob_arraylen; i = i + 2) {
- if (radiob_array_table[i] == 0xfe) {
- mdelay(50);
- } else if (radiob_array_table[i] == 0xfd)
- mdelay(5);
- else if (radiob_array_table[i] == 0xfc)
- mdelay(1);
- else if (radiob_array_table[i] == 0xfb)
- udelay(50);
- else if (radiob_array_table[i] == 0xfa)
- udelay(5);
- else if (radiob_array_table[i] == 0xf9)
- udelay(1);
- else {
- rtl_set_rfreg(hw, rfpath, radiob_array_table[i],
- RFREG_OFFSET_MASK,
- radiob_array_table[i + 1]);
- udelay(1);
- }
+ rtl_rfreg_delay(hw, rfpath, radiob_array_table[i],
+ RFREG_OFFSET_MASK,
+ radiob_array_table[i + 1]);
}
break;
case RF90_PATH_C:
@@ -355,6 +304,8 @@ bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"switch case not processed\n");
break;
+ default:
+ break;
}
return true;
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h
index 8922ecb47ad2..ed703a1b3b7c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h
@@ -2044,22 +2044,6 @@
#define BWORD1 0xc
#define BWORD 0xf
-#define MASKBYTE0 0xff
-#define MASKBYTE1 0xff00
-#define MASKBYTE2 0xff0000
-#define MASKBYTE3 0xff000000
-#define MASKHWORD 0xffff0000
-#define MASKLWORD 0x0000ffff
-#define MASKDWORD 0xffffffff
-#define MASK12BITS 0xfff
-#define MASKH4BITS 0xf0000000
-#define MASKOFDM_D 0xffc00000
-#define MASKCCK 0x3f3f3f3f
-
-#define MASK4BITS 0x0f
-#define MASK20BITS 0xfffff
-#define RFREG_OFFSET_MASK 0xfffff
-
#define BENABLE 0x1
#define BDISABLE 0x0
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
index 52abf0a862fa..8f04817cb7ec 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
@@ -393,7 +393,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
/* In testing, hdr was NULL here */
return false;
}
- if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
+ if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
(ieee80211_has_protected(hdr->frame_control)))
rx_status->flag &= ~RX_FLAG_DECRYPTED;
else
@@ -426,7 +426,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr, u8 *pdesc_tx,
- struct ieee80211_tx_info *info,
+ u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
struct ieee80211_sta *sta,
struct sk_buff *skb,
u8 hw_queue, struct rtl_tcb_desc *tcb_desc)
@@ -666,7 +666,8 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw,
"H2C Tx Cmd Content", pdesc, TX_DESC_SIZE);
}
-void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
+void rtl92ce_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+ u8 desc_name, u8 *val)
{
if (istx) {
switch (desc_name) {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
index a7cdd514cb2e..9a39ec4204dd 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
@@ -711,8 +711,8 @@ struct rx_desc_92c {
} __packed;
void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
- struct ieee80211_hdr *hdr,
- u8 *pdesc, struct ieee80211_tx_info *info,
+ struct ieee80211_hdr *hdr, u8 *pdesc,
+ u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
struct ieee80211_sta *sta,
struct sk_buff *skb, u8 hw_queue,
struct rtl_tcb_desc *ptcb_desc);
@@ -720,7 +720,8 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
struct rtl_stats *stats,
struct ieee80211_rx_status *rx_status,
u8 *pdesc, struct sk_buff *skb);
-void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val);
+void rtl92ce_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+ u8 desc_name, u8 *val);
u32 rtl92ce_get_desc(u8 *pdesc, bool istx, u8 desc_name);
void rtl92ce_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
index 468bf73cc883..68b5c7e92cfb 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
@@ -394,7 +394,7 @@ static void _rtl92cu_read_adapter_info(struct ieee80211_hw *hw)
if (rtlefuse->eeprom_did == 0x8176) {
if ((rtlefuse->eeprom_svid == 0x103C &&
rtlefuse->eeprom_smid == 0x1629))
- rtlhal->oem_id = RT_CID_819x_HP;
+ rtlhal->oem_id = RT_CID_819X_HP;
else
rtlhal->oem_id = RT_CID_DEFAULT;
} else {
@@ -405,7 +405,7 @@ static void _rtl92cu_read_adapter_info(struct ieee80211_hw *hw)
rtlhal->oem_id = RT_CID_TOSHIBA;
break;
case EEPROM_CID_QMI:
- rtlhal->oem_id = RT_CID_819x_QMI;
+ rtlhal->oem_id = RT_CID_819X_QMI;
break;
case EEPROM_CID_WHQL:
default:
@@ -423,14 +423,14 @@ static void _rtl92cu_hal_customized_behavior(struct ieee80211_hw *hw)
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
switch (rtlhal->oem_id) {
- case RT_CID_819x_HP:
+ case RT_CID_819X_HP:
usb_priv->ledctl.led_opendrain = true;
break;
- case RT_CID_819x_Lenovo:
+ case RT_CID_819X_LENOVO:
case RT_CID_DEFAULT:
case RT_CID_TOSHIBA:
case RT_CID_CCX:
- case RT_CID_819x_Acer:
+ case RT_CID_819X_ACER:
case RT_CID_WHQL:
default:
break;
@@ -985,6 +985,17 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
int err = 0;
static bool iqk_initialized;
+ unsigned long flags;
+
+ /* As this function can take a very long time (up to 350 ms)
+ * and can be called with irqs disabled, reenable the irqs
+ * to let the other devices continue being serviced.
+ *
+ * It is safe doing so since our own interrupts will only be enabled
+ * in a subsequent step.
+ */
+ local_save_flags(flags);
+ local_irq_enable();
rtlhal->hw_type = HARDWARE_TYPE_RTL8192CU;
err = _rtl92cu_init_mac(hw);
@@ -997,7 +1008,7 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"Failed to download FW. Init HW without FW now..\n");
err = 1;
- return err;
+ goto exit;
}
rtlhal->last_hmeboxnum = 0; /* h2c */
_rtl92cu_phy_param_tab_init(hw);
@@ -1034,6 +1045,8 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
_InitPABias(hw);
_update_mac_setting(hw);
rtl92c_dm_init(hw);
+exit:
+ local_irq_restore(flags);
return err;
}
@@ -1379,11 +1392,13 @@ void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
- u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR);
+ u32 reg_rcr;
if (rtlpriv->psc.rfpwr_state != ERFON)
return;
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
+
if (check_bssid) {
u8 tmp;
if (IS_NORMAL_CHIP(rtlhal->version)) {
@@ -1795,7 +1810,7 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
e_aci);
break;
}
- if (rtlusb->acm_method != eAcmWay2_SW)
+ if (rtlusb->acm_method != EACMWAY2_SW)
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_ACM_CTRL, &e_aci);
break;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
index 0c09240eadcc..9831ff1128ca 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
@@ -30,6 +30,7 @@
#include "../wifi.h"
#include "../pci.h"
#include "../ps.h"
+#include "../core.h"
#include "reg.h"
#include "def.h"
#include "phy.h"
@@ -188,18 +189,7 @@ bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
}
if (configtype == BASEBAND_CONFIG_PHY_REG) {
for (i = 0; i < phy_reg_arraylen; i = i + 2) {
- if (phy_regarray_table[i] == 0xfe)
- mdelay(50);
- else if (phy_regarray_table[i] == 0xfd)
- mdelay(5);
- else if (phy_regarray_table[i] == 0xfc)
- mdelay(1);
- else if (phy_regarray_table[i] == 0xfb)
- udelay(50);
- else if (phy_regarray_table[i] == 0xfa)
- udelay(5);
- else if (phy_regarray_table[i] == 0xf9)
- udelay(1);
+ rtl_addr_delay(phy_regarray_table[i]);
rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD,
phy_regarray_table[i + 1]);
udelay(1);
@@ -236,18 +226,7 @@ bool _rtl92cu_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
phy_regarray_table_pg = rtlphy->hwparam_tables[PHY_REG_PG].pdata;
if (configtype == BASEBAND_CONFIG_PHY_REG) {
for (i = 0; i < phy_regarray_pg_len; i = i + 3) {
- if (phy_regarray_table_pg[i] == 0xfe)
- mdelay(50);
- else if (phy_regarray_table_pg[i] == 0xfd)
- mdelay(5);
- else if (phy_regarray_table_pg[i] == 0xfc)
- mdelay(1);
- else if (phy_regarray_table_pg[i] == 0xfb)
- udelay(50);
- else if (phy_regarray_table_pg[i] == 0xfa)
- udelay(5);
- else if (phy_regarray_table_pg[i] == 0xf9)
- udelay(1);
+ rtl_addr_delay(phy_regarray_table_pg[i]);
_rtl92c_store_pwrIndex_diffrate_offset(hw,
phy_regarray_table_pg[i],
phy_regarray_table_pg[i + 1],
@@ -294,46 +273,16 @@ bool rtl92cu_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
switch (rfpath) {
case RF90_PATH_A:
for (i = 0; i < radioa_arraylen; i = i + 2) {
- if (radioa_array_table[i] == 0xfe)
- mdelay(50);
- else if (radioa_array_table[i] == 0xfd)
- mdelay(5);
- else if (radioa_array_table[i] == 0xfc)
- mdelay(1);
- else if (radioa_array_table[i] == 0xfb)
- udelay(50);
- else if (radioa_array_table[i] == 0xfa)
- udelay(5);
- else if (radioa_array_table[i] == 0xf9)
- udelay(1);
- else {
- rtl_set_rfreg(hw, rfpath, radioa_array_table[i],
- RFREG_OFFSET_MASK,
- radioa_array_table[i + 1]);
- udelay(1);
- }
+ rtl_rfreg_delay(hw, rfpath, radioa_array_table[i],
+ RFREG_OFFSET_MASK,
+ radioa_array_table[i + 1]);
}
break;
case RF90_PATH_B:
for (i = 0; i < radiob_arraylen; i = i + 2) {
- if (radiob_array_table[i] == 0xfe) {
- mdelay(50);
- } else if (radiob_array_table[i] == 0xfd)
- mdelay(5);
- else if (radiob_array_table[i] == 0xfc)
- mdelay(1);
- else if (radiob_array_table[i] == 0xfb)
- udelay(50);
- else if (radiob_array_table[i] == 0xfa)
- udelay(5);
- else if (radiob_array_table[i] == 0xf9)
- udelay(1);
- else {
- rtl_set_rfreg(hw, rfpath, radiob_array_table[i],
- RFREG_OFFSET_MASK,
- radiob_array_table[i + 1]);
- udelay(1);
- }
+ rtl_rfreg_delay(hw, rfpath, radiob_array_table[i],
+ RFREG_OFFSET_MASK,
+ radiob_array_table[i + 1]);
}
break;
case RF90_PATH_C:
@@ -344,6 +293,8 @@ bool rtl92cu_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"switch case not processed\n");
break;
+ default:
+ break;
}
return true;
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
index 1bc21ccfa71b..035e0dc3922c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
@@ -495,7 +495,7 @@ static void _rtl_tx_desc_checksum(u8 *txdesc)
void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr, u8 *pdesc_tx,
- struct ieee80211_tx_info *info,
+ u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
struct ieee80211_sta *sta,
struct sk_buff *skb,
u8 queue_index,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h
index 725c53accc58..fd8051dcd98a 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h
@@ -420,7 +420,7 @@ struct sk_buff *rtl8192c_tx_aggregate_hdl(struct ieee80211_hw *,
struct sk_buff_head *);
void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr, u8 *pdesc_tx,
- struct ieee80211_tx_info *info,
+ u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
struct ieee80211_sta *sta,
struct sk_buff *skb,
u8 queue_index,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
index 7908e1c85819..304c443b89b2 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
@@ -194,15 +194,15 @@ static void rtl92d_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
rtl_set_bbreg(hw, ROFDM0_LSTF, BIT(31), 1); /* hold page C counter */
rtl_set_bbreg(hw, ROFDM1_LSTF, BIT(31), 1); /*hold page D counter */
- ret_value = rtl_get_bbreg(hw, ROFDM0_FRAMESYNC, BMASKDWORD);
+ ret_value = rtl_get_bbreg(hw, ROFDM0_FRAMESYNC, MASKDWORD);
falsealm_cnt->cnt_fast_fsync_fail = (ret_value & 0xffff);
falsealm_cnt->cnt_sb_search_fail = ((ret_value & 0xffff0000) >> 16);
- ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, BMASKDWORD);
+ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, MASKDWORD);
falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16);
- ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, BMASKDWORD);
+ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, MASKDWORD);
falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff);
falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16);
- ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, BMASKDWORD);
+ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD);
falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff);
falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail +
falsealm_cnt->cnt_rate_illegal +
@@ -214,9 +214,9 @@ static void rtl92d_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
if (rtlpriv->rtlhal.current_bandtype != BAND_ON_5G) {
/* hold cck counter */
rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag);
- ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, BMASKBYTE0);
+ ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, MASKBYTE0);
falsealm_cnt->cnt_cck_fail = ret_value;
- ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERUPPER, BMASKBYTE3);
+ ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERUPPER, MASKBYTE3);
falsealm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8;
rtl92d_release_cckandrw_pagea_ctl(hw, &flag);
} else {
@@ -331,11 +331,11 @@ static void rtl92d_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
if (de_digtable->pre_cck_pd_state != de_digtable->cur_cck_pd_state) {
if (de_digtable->cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI) {
rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag);
- rtl_set_bbreg(hw, RCCK0_CCA, BMASKBYTE2, 0x83);
+ rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x83);
rtl92d_release_cckandrw_pagea_ctl(hw, &flag);
} else {
rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag);
- rtl_set_bbreg(hw, RCCK0_CCA, BMASKBYTE2, 0xcd);
+ rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd);
rtl92d_release_cckandrw_pagea_ctl(hw, &flag);
}
de_digtable->pre_cck_pd_state = de_digtable->cur_cck_pd_state;
@@ -722,7 +722,7 @@ static void rtl92d_dm_rxgain_tracking_thermalmeter(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"===> Rx Gain %x\n", u4tmp);
for (i = RF90_PATH_A; i < rtlpriv->phy.num_total_rfpath; i++)
- rtl_set_rfreg(hw, i, 0x3C, BRFREGOFFSETMASK,
+ rtl_set_rfreg(hw, i, 0x3C, RFREG_OFFSET_MASK,
(rtlpriv->phy.reg_rf3c[i] & (~(0xF000))) | u4tmp);
}
@@ -737,7 +737,7 @@ static void rtl92d_bandtype_2_4G(struct ieee80211_hw *hw, long *temp_cckg,
/* Query CCK default setting From 0xa24 */
rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag);
temp_cck = rtl_get_bbreg(hw, RCCK0_TXFILTER2,
- BMASKDWORD) & BMASKCCK;
+ MASKDWORD) & MASKCCK;
rtl92d_release_cckandrw_pagea_ctl(hw, &flag);
for (i = 0; i < CCK_TABLE_LENGTH; i++) {
if (rtlpriv->dm.cck_inch14) {
@@ -896,9 +896,9 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
rf = 1;
if (thermalvalue) {
ele_d = rtl_get_bbreg(hw, ROFDM0_XATxIQIMBALANCE,
- BMASKDWORD) & BMASKOFDM_D;
+ MASKDWORD) & MASKOFDM_D;
for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) {
- if (ele_d == (ofdmswing_table[i] & BMASKOFDM_D)) {
+ if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) {
ofdm_index_old[0] = (u8) i;
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
@@ -910,10 +910,10 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
}
if (is2t) {
ele_d = rtl_get_bbreg(hw, ROFDM0_XBTxIQIMBALANCE,
- BMASKDWORD) & BMASKOFDM_D;
+ MASKDWORD) & MASKOFDM_D;
for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) {
if (ele_d ==
- (ofdmswing_table[i] & BMASKOFDM_D)) {
+ (ofdmswing_table[i] & MASKOFDM_D)) {
ofdm_index_old[1] = (u8) i;
RT_TRACE(rtlpriv, COMP_POWER_TRACKING,
DBG_LOUD,
@@ -1091,10 +1091,10 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
value32 = (ele_d << 22) | ((ele_c & 0x3F) <<
16) | ele_a;
rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE,
- BMASKDWORD, value32);
+ MASKDWORD, value32);
value32 = (ele_c & 0x000003C0) >> 6;
- rtl_set_bbreg(hw, ROFDM0_XCTxAFE, BMASKH4BITS,
+ rtl_set_bbreg(hw, ROFDM0_XCTxAFE, MASKH4BITS,
value32);
value32 = ((val_x * ele_d) >> 7) & 0x01;
@@ -1103,10 +1103,10 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
} else {
rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE,
- BMASKDWORD,
+ MASKDWORD,
ofdmswing_table
[(u8)ofdm_index[0]]);
- rtl_set_bbreg(hw, ROFDM0_XCTxAFE, BMASKH4BITS,
+ rtl_set_bbreg(hw, ROFDM0_XCTxAFE, MASKH4BITS,
0x00);
rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD,
BIT(24), 0x00);
@@ -1204,21 +1204,21 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
ele_a;
rtl_set_bbreg(hw,
ROFDM0_XBTxIQIMBALANCE,
- BMASKDWORD, value32);
+ MASKDWORD, value32);
value32 = (ele_c & 0x000003C0) >> 6;
rtl_set_bbreg(hw, ROFDM0_XDTxAFE,
- BMASKH4BITS, value32);
+ MASKH4BITS, value32);
value32 = ((val_x * ele_d) >> 7) & 0x01;
rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD,
BIT(28), value32);
} else {
rtl_set_bbreg(hw,
ROFDM0_XBTxIQIMBALANCE,
- BMASKDWORD,
+ MASKDWORD,
ofdmswing_table
[(u8) ofdm_index[1]]);
rtl_set_bbreg(hw, ROFDM0_XDTxAFE,
- BMASKH4BITS, 0x00);
+ MASKH4BITS, 0x00);
rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD,
BIT(28), 0x00);
}
@@ -1229,10 +1229,10 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
}
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"TxPwrTracking 0xc80 = 0x%x, 0xc94 = 0x%x RF 0x24 = 0x%x\n",
- rtl_get_bbreg(hw, 0xc80, BMASKDWORD),
- rtl_get_bbreg(hw, 0xc94, BMASKDWORD),
+ rtl_get_bbreg(hw, 0xc80, MASKDWORD),
+ rtl_get_bbreg(hw, 0xc94, MASKDWORD),
rtl_get_rfreg(hw, RF90_PATH_A, 0x24,
- BRFREGOFFSETMASK));
+ RFREG_OFFSET_MASK));
}
if ((delta_iqk > rtlefuse->delta_iqk) &&
(rtlefuse->delta_iqk != 0)) {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
index c4a7db9135d6..2b08671004a0 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
@@ -318,7 +318,7 @@ void rtl92de_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
case HW_VAR_AC_PARAM: {
u8 e_aci = *val;
rtl92d_dm_init_edca_turbo(hw);
- if (rtlpci->acm_method != eAcmWay2_SW)
+ if (rtlpci->acm_method != EACMWAY2_SW)
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL,
&e_aci);
break;
@@ -985,9 +985,9 @@ int rtl92de_hw_init(struct ieee80211_hw *hw)
/* set default value after initialize RF, */
rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0);
rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0,
- RF_CHNLBW, BRFREGOFFSETMASK);
+ RF_CHNLBW, RFREG_OFFSET_MASK);
rtlphy->rfreg_chnlval[1] = rtl_get_rfreg(hw, (enum radio_path)1,
- RF_CHNLBW, BRFREGOFFSETMASK);
+ RF_CHNLBW, RFREG_OFFSET_MASK);
/*---- Set CCK and OFDM Block "ON"----*/
if (rtlhal->current_bandtype == BAND_ON_2_4G)
@@ -1035,7 +1035,7 @@ int rtl92de_hw_init(struct ieee80211_hw *hw)
tmp_rega = rtl_get_rfreg(hw,
(enum radio_path)RF90_PATH_A,
- 0x2a, BMASKDWORD);
+ 0x2a, MASKDWORD);
if (((tmp_rega & BIT(11)) == BIT(11)))
break;
@@ -1138,11 +1138,13 @@ static int _rtl92de_set_media_status(struct ieee80211_hw *hw,
void rtl92de_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- u32 reg_rcr = rtlpci->receive_config;
+ u32 reg_rcr;
if (rtlpriv->psc.rfpwr_state != ERFON)
return;
+
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
+
if (check_bssid) {
reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
@@ -1332,13 +1334,13 @@ void rtl92de_card_disable(struct ieee80211_hw *hw)
/* c. ========RF OFF sequence========== */
/* 0x88c[23:20] = 0xf. */
rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0xf);
- rtl_set_rfreg(hw, RF90_PATH_A, 0x00, BRFREGOFFSETMASK, 0x00);
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00);
/* APSD_CTRL 0x600[7:0] = 0x40 */
rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40);
/* Close antenna 0,0xc04,0xd04 */
- rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0);
+ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0);
rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0);
/* SYS_FUNC_EN 0x02[7:0] = 0xE2 reset BB state machine */
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
index 13196cc4b1d3..3d1f0dd4e52d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
@@ -30,6 +30,7 @@
#include "../wifi.h"
#include "../pci.h"
#include "../ps.h"
+#include "../core.h"
#include "reg.h"
#include "def.h"
#include "phy.h"
@@ -242,7 +243,7 @@ void rtl92d_phy_set_bb_reg(struct ieee80211_hw *hw,
else if (rtlhal->during_mac0init_radiob)
/* mac0 use phy1 write radio_b. */
dbi_direct = BIT(3) | BIT(2);
- if (bitmask != BMASKDWORD) {
+ if (bitmask != MASKDWORD) {
if (rtlhal->during_mac1init_radioa ||
rtlhal->during_mac0init_radiob)
originalvalue = rtl92de_read_dword_dbi(hw,
@@ -275,20 +276,20 @@ static u32 _rtl92d_phy_rf_serial_read(struct ieee80211_hw *hw,
u32 retvalue;
newoffset = offset;
- tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, BMASKDWORD);
+ tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD);
if (rfpath == RF90_PATH_A)
tmplong2 = tmplong;
else
- tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, BMASKDWORD);
+ tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD);
tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) |
(newoffset << 23) | BLSSIREADEDGE;
- rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, BMASKDWORD,
+ rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
tmplong & (~BLSSIREADEDGE));
udelay(10);
- rtl_set_bbreg(hw, pphyreg->rfhssi_para2, BMASKDWORD, tmplong2);
+ rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2);
udelay(50);
udelay(50);
- rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, BMASKDWORD,
+ rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
tmplong | BLSSIREADEDGE);
udelay(10);
if (rfpath == RF90_PATH_A)
@@ -321,7 +322,7 @@ static void _rtl92d_phy_rf_serial_write(struct ieee80211_hw *hw,
newoffset = offset;
/* T65 RF */
data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff;
- rtl_set_bbreg(hw, pphyreg->rf3wire_offset, BMASKDWORD, data_and_addr);
+ rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr);
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFW-%d Addr[0x%x]=0x%x\n",
rfpath, pphyreg->rf3wire_offset, data_and_addr);
}
@@ -362,7 +363,7 @@ void rtl92d_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
return;
spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
if (rtlphy->rf_mode != RF_OP_BY_FW) {
- if (bitmask != BRFREGOFFSETMASK) {
+ if (bitmask != RFREG_OFFSET_MASK) {
original_value = _rtl92d_phy_rf_serial_read(hw,
rfpath, regaddr);
bitshift = _rtl92d_phy_calculate_bit_shift(bitmask);
@@ -567,19 +568,8 @@ static bool _rtl92d_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
" ===> phy:Rtl819XPHY_REG_Array_PG\n");
if (configtype == BASEBAND_CONFIG_PHY_REG) {
for (i = 0; i < phy_reg_arraylen; i = i + 2) {
- if (phy_regarray_table[i] == 0xfe)
- mdelay(50);
- else if (phy_regarray_table[i] == 0xfd)
- mdelay(5);
- else if (phy_regarray_table[i] == 0xfc)
- mdelay(1);
- else if (phy_regarray_table[i] == 0xfb)
- udelay(50);
- else if (phy_regarray_table[i] == 0xfa)
- udelay(5);
- else if (phy_regarray_table[i] == 0xf9)
- udelay(1);
- rtl_set_bbreg(hw, phy_regarray_table[i], BMASKDWORD,
+ rtl_addr_delay(phy_regarray_table[i]);
+ rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD,
phy_regarray_table[i + 1]);
udelay(1);
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
@@ -591,7 +581,7 @@ static bool _rtl92d_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
if (rtlhal->interfaceindex == 0) {
for (i = 0; i < agctab_arraylen; i = i + 2) {
rtl_set_bbreg(hw, agctab_array_table[i],
- BMASKDWORD,
+ MASKDWORD,
agctab_array_table[i + 1]);
/* Add 1us delay between BB/RF register
* setting. */
@@ -607,7 +597,7 @@ static bool _rtl92d_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
if (rtlhal->current_bandtype == BAND_ON_2_4G) {
for (i = 0; i < agctab_arraylen; i = i + 2) {
rtl_set_bbreg(hw, agctab_array_table[i],
- BMASKDWORD,
+ MASKDWORD,
agctab_array_table[i + 1]);
/* Add 1us delay between BB/RF register
* setting. */
@@ -623,7 +613,7 @@ static bool _rtl92d_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
for (i = 0; i < agctab_5garraylen; i = i + 2) {
rtl_set_bbreg(hw,
agctab_5garray_table[i],
- BMASKDWORD,
+ MASKDWORD,
agctab_5garray_table[i + 1]);
/* Add 1us delay between BB/RF registeri
* setting. */
@@ -705,18 +695,7 @@ static bool _rtl92d_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
phy_regarray_table_pg = rtl8192de_phy_reg_array_pg;
if (configtype == BASEBAND_CONFIG_PHY_REG) {
for (i = 0; i < phy_regarray_pg_len; i = i + 3) {
- if (phy_regarray_table_pg[i] == 0xfe)
- mdelay(50);
- else if (phy_regarray_table_pg[i] == 0xfd)
- mdelay(5);
- else if (phy_regarray_table_pg[i] == 0xfc)
- mdelay(1);
- else if (phy_regarray_table_pg[i] == 0xfb)
- udelay(50);
- else if (phy_regarray_table_pg[i] == 0xfa)
- udelay(5);
- else if (phy_regarray_table_pg[i] == 0xf9)
- udelay(1);
+ rtl_addr_delay(phy_regarray_table_pg[i]);
_rtl92d_store_pwrindex_diffrate_offset(hw,
phy_regarray_table_pg[i],
phy_regarray_table_pg[i + 1],
@@ -843,54 +822,16 @@ bool rtl92d_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
switch (rfpath) {
case RF90_PATH_A:
for (i = 0; i < radioa_arraylen; i = i + 2) {
- if (radioa_array_table[i] == 0xfe) {
- mdelay(50);
- } else if (radioa_array_table[i] == 0xfd) {
- /* delay_ms(5); */
- mdelay(5);
- } else if (radioa_array_table[i] == 0xfc) {
- /* delay_ms(1); */
- mdelay(1);
- } else if (radioa_array_table[i] == 0xfb) {
- udelay(50);
- } else if (radioa_array_table[i] == 0xfa) {
- udelay(5);
- } else if (radioa_array_table[i] == 0xf9) {
- udelay(1);
- } else {
- rtl_set_rfreg(hw, rfpath, radioa_array_table[i],
- BRFREGOFFSETMASK,
- radioa_array_table[i + 1]);
- /* Add 1us delay between BB/RF register set. */
- udelay(1);
- }
+ rtl_rfreg_delay(hw, rfpath, radioa_array_table[i],
+ RFREG_OFFSET_MASK,
+ radioa_array_table[i + 1]);
}
break;
case RF90_PATH_B:
for (i = 0; i < radiob_arraylen; i = i + 2) {
- if (radiob_array_table[i] == 0xfe) {
- /* Delay specific ms. Only RF configuration
- * requires delay. */
- mdelay(50);
- } else if (radiob_array_table[i] == 0xfd) {
- /* delay_ms(5); */
- mdelay(5);
- } else if (radiob_array_table[i] == 0xfc) {
- /* delay_ms(1); */
- mdelay(1);
- } else if (radiob_array_table[i] == 0xfb) {
- udelay(50);
- } else if (radiob_array_table[i] == 0xfa) {
- udelay(5);
- } else if (radiob_array_table[i] == 0xf9) {
- udelay(1);
- } else {
- rtl_set_rfreg(hw, rfpath, radiob_array_table[i],
- BRFREGOFFSETMASK,
- radiob_array_table[i + 1]);
- /* Add 1us delay between BB/RF register set. */
- udelay(1);
- }
+ rtl_rfreg_delay(hw, rfpath, radiob_array_table[i],
+ RFREG_OFFSET_MASK,
+ radiob_array_table[i + 1]);
}
break;
case RF90_PATH_C:
@@ -911,13 +852,13 @@ void rtl92d_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
struct rtl_phy *rtlphy = &(rtlpriv->phy);
rtlphy->default_initialgain[0] =
- (u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, BMASKBYTE0);
+ (u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0);
rtlphy->default_initialgain[1] =
- (u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, BMASKBYTE0);
+ (u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0);
rtlphy->default_initialgain[2] =
- (u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, BMASKBYTE0);
+ (u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, MASKBYTE0);
rtlphy->default_initialgain[3] =
- (u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, BMASKBYTE0);
+ (u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, MASKBYTE0);
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
"Default initial gain (c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x\n",
rtlphy->default_initialgain[0],
@@ -925,9 +866,9 @@ void rtl92d_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
rtlphy->default_initialgain[2],
rtlphy->default_initialgain[3]);
rtlphy->framesync = (u8)rtl_get_bbreg(hw, ROFDM0_RXDETECTOR3,
- BMASKBYTE0);
+ MASKBYTE0);
rtlphy->framesync_c34 = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR2,
- BMASKDWORD);
+ MASKDWORD);
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
"Default framesync (0x%x) = 0x%x\n",
ROFDM0_RXDETECTOR3, rtlphy->framesync);
@@ -1106,7 +1047,7 @@ static void _rtl92d_phy_stop_trx_before_changeband(struct ieee80211_hw *hw)
{
rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0);
rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0);
- rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0x00);
+ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0x00);
rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0x0);
}
@@ -1168,7 +1109,7 @@ static void _rtl92d_phy_reload_imr_setting(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 imr_num = MAX_RF_IMR_INDEX;
- u32 rfmask = BRFREGOFFSETMASK;
+ u32 rfmask = RFREG_OFFSET_MASK;
u8 group, i;
unsigned long flag = 0;
@@ -1211,7 +1152,7 @@ static void _rtl92d_phy_reload_imr_setting(struct ieee80211_hw *hw,
for (i = 0; i < imr_num; i++) {
rtl_set_rfreg(hw, (enum radio_path)rfpath,
rf_reg_for_5g_swchnl_normal[i],
- BRFREGOFFSETMASK,
+ RFREG_OFFSET_MASK,
rf_imr_param_normal[0][0][i]);
}
rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4,
@@ -1329,7 +1270,7 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel)
if (i == 0 && (rtlhal->macphymode == DUALMAC_DUALPHY)) {
rtl_set_rfreg(hw, (enum radio_path)path,
rf_reg_for_c_cut_5g[i],
- BRFREGOFFSETMASK, 0xE439D);
+ RFREG_OFFSET_MASK, 0xE439D);
} else if (rf_reg_for_c_cut_5g[i] == RF_SYN_G4) {
u4tmp2 = (rf_reg_pram_c_5g[index][i] &
0x7FF) | (u4tmp << 11);
@@ -1337,11 +1278,11 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel)
u4tmp2 &= ~(BIT(7) | BIT(6));
rtl_set_rfreg(hw, (enum radio_path)path,
rf_reg_for_c_cut_5g[i],
- BRFREGOFFSETMASK, u4tmp2);
+ RFREG_OFFSET_MASK, u4tmp2);
} else {
rtl_set_rfreg(hw, (enum radio_path)path,
rf_reg_for_c_cut_5g[i],
- BRFREGOFFSETMASK,
+ RFREG_OFFSET_MASK,
rf_reg_pram_c_5g[index][i]);
}
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
@@ -1351,7 +1292,7 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel)
path, index,
rtl_get_rfreg(hw, (enum radio_path)path,
rf_reg_for_c_cut_5g[i],
- BRFREGOFFSETMASK));
+ RFREG_OFFSET_MASK));
}
if (need_pwr_down)
_rtl92d_phy_restore_rf_env(hw, path, &u4regvalue);
@@ -1381,7 +1322,7 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel)
i++) {
rtl_set_rfreg(hw, rfpath,
rf_for_c_cut_5g_internal_pa[i],
- BRFREGOFFSETMASK,
+ RFREG_OFFSET_MASK,
rf_pram_c_5g_int_pa[index][i]);
RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD,
"offset 0x%x value 0x%x path %d index %d\n",
@@ -1422,13 +1363,13 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel)
if (rf_reg_for_c_cut_2g[i] == RF_SYN_G7)
rtl_set_rfreg(hw, (enum radio_path)path,
rf_reg_for_c_cut_2g[i],
- BRFREGOFFSETMASK,
+ RFREG_OFFSET_MASK,
(rf_reg_param_for_c_cut_2g[index][i] |
BIT(17)));
else
rtl_set_rfreg(hw, (enum radio_path)path,
rf_reg_for_c_cut_2g[i],
- BRFREGOFFSETMASK,
+ RFREG_OFFSET_MASK,
rf_reg_param_for_c_cut_2g
[index][i]);
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
@@ -1438,14 +1379,14 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel)
rf_reg_mask_for_c_cut_2g[i], path, index,
rtl_get_rfreg(hw, (enum radio_path)path,
rf_reg_for_c_cut_2g[i],
- BRFREGOFFSETMASK));
+ RFREG_OFFSET_MASK));
}
RTPRINT(rtlpriv, FINIT, INIT_IQK,
"cosa ver 3 set RF-B, 2G, 0x28 = 0x%x !!\n",
rf_syn_g4_for_c_cut_2g | (u4tmp << 11));
rtl_set_rfreg(hw, (enum radio_path)path, RF_SYN_G4,
- BRFREGOFFSETMASK,
+ RFREG_OFFSET_MASK,
rf_syn_g4_for_c_cut_2g | (u4tmp << 11));
if (need_pwr_down)
_rtl92d_phy_restore_rf_env(hw, path, &u4regvalue);
@@ -1493,41 +1434,41 @@ static u8 _rtl92d_phy_patha_iqk(struct ieee80211_hw *hw, bool configpathb)
/* path-A IQK setting */
RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path-A IQK setting!\n");
if (rtlhal->interfaceindex == 0) {
- rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x10008c1f);
- rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x10008c1f);
+ rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c1f);
+ rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x10008c1f);
} else {
- rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x10008c22);
- rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x10008c22);
+ rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c22);
+ rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x10008c22);
}
- rtl_set_bbreg(hw, 0xe38, BMASKDWORD, 0x82140102);
- rtl_set_bbreg(hw, 0xe3c, BMASKDWORD, 0x28160206);
+ rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x82140102);
+ rtl_set_bbreg(hw, 0xe3c, MASKDWORD, 0x28160206);
/* path-B IQK setting */
if (configpathb) {
- rtl_set_bbreg(hw, 0xe50, BMASKDWORD, 0x10008c22);
- rtl_set_bbreg(hw, 0xe54, BMASKDWORD, 0x10008c22);
- rtl_set_bbreg(hw, 0xe58, BMASKDWORD, 0x82140102);
- rtl_set_bbreg(hw, 0xe5c, BMASKDWORD, 0x28160206);
+ rtl_set_bbreg(hw, 0xe50, MASKDWORD, 0x10008c22);
+ rtl_set_bbreg(hw, 0xe54, MASKDWORD, 0x10008c22);
+ rtl_set_bbreg(hw, 0xe58, MASKDWORD, 0x82140102);
+ rtl_set_bbreg(hw, 0xe5c, MASKDWORD, 0x28160206);
}
/* LO calibration setting */
RTPRINT(rtlpriv, FINIT, INIT_IQK, "LO calibration setting!\n");
- rtl_set_bbreg(hw, 0xe4c, BMASKDWORD, 0x00462911);
+ rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x00462911);
/* One shot, path A LOK & IQK */
RTPRINT(rtlpriv, FINIT, INIT_IQK, "One shot, path A LOK & IQK!\n");
- rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf9000000);
- rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf8000000);
+ rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf9000000);
+ rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000);
/* delay x ms */
RTPRINT(rtlpriv, FINIT, INIT_IQK,
"Delay %d ms for One shot, path A LOK & IQK\n",
IQK_DELAY_TIME);
mdelay(IQK_DELAY_TIME);
/* Check failed */
- regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD);
+ regeac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeac = 0x%x\n", regeac);
- rege94 = rtl_get_bbreg(hw, 0xe94, BMASKDWORD);
+ rege94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xe94 = 0x%x\n", rege94);
- rege9c = rtl_get_bbreg(hw, 0xe9c, BMASKDWORD);
+ rege9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xe9c = 0x%x\n", rege9c);
- regea4 = rtl_get_bbreg(hw, 0xea4, BMASKDWORD);
+ regea4 = rtl_get_bbreg(hw, 0xea4, MASKDWORD);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xea4 = 0x%x\n", regea4);
if (!(regeac & BIT(28)) && (((rege94 & 0x03FF0000) >> 16) != 0x142) &&
(((rege9c & 0x03FF0000) >> 16) != 0x42))
@@ -1563,42 +1504,42 @@ static u8 _rtl92d_phy_patha_iqk_5g_normal(struct ieee80211_hw *hw,
RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A IQK!\n");
/* path-A IQK setting */
RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path-A IQK setting!\n");
- rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x18008c1f);
- rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x18008c1f);
- rtl_set_bbreg(hw, 0xe38, BMASKDWORD, 0x82140307);
- rtl_set_bbreg(hw, 0xe3c, BMASKDWORD, 0x68160960);
+ rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x18008c1f);
+ rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x18008c1f);
+ rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x82140307);
+ rtl_set_bbreg(hw, 0xe3c, MASKDWORD, 0x68160960);
/* path-B IQK setting */
if (configpathb) {
- rtl_set_bbreg(hw, 0xe50, BMASKDWORD, 0x18008c2f);
- rtl_set_bbreg(hw, 0xe54, BMASKDWORD, 0x18008c2f);
- rtl_set_bbreg(hw, 0xe58, BMASKDWORD, 0x82110000);
- rtl_set_bbreg(hw, 0xe5c, BMASKDWORD, 0x68110000);
+ rtl_set_bbreg(hw, 0xe50, MASKDWORD, 0x18008c2f);
+ rtl_set_bbreg(hw, 0xe54, MASKDWORD, 0x18008c2f);
+ rtl_set_bbreg(hw, 0xe58, MASKDWORD, 0x82110000);
+ rtl_set_bbreg(hw, 0xe5c, MASKDWORD, 0x68110000);
}
/* LO calibration setting */
RTPRINT(rtlpriv, FINIT, INIT_IQK, "LO calibration setting!\n");
- rtl_set_bbreg(hw, 0xe4c, BMASKDWORD, 0x00462911);
+ rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x00462911);
/* path-A PA on */
- rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD, 0x07000f60);
- rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BMASKDWORD, 0x66e60e30);
+ rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, MASKDWORD, 0x07000f60);
+ rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, MASKDWORD, 0x66e60e30);
for (i = 0; i < retrycount; i++) {
/* One shot, path A LOK & IQK */
RTPRINT(rtlpriv, FINIT, INIT_IQK,
"One shot, path A LOK & IQK!\n");
- rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf9000000);
- rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf8000000);
+ rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf9000000);
+ rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000);
/* delay x ms */
RTPRINT(rtlpriv, FINIT, INIT_IQK,
"Delay %d ms for One shot, path A LOK & IQK.\n",
IQK_DELAY_TIME);
mdelay(IQK_DELAY_TIME * 10);
/* Check failed */
- regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD);
+ regeac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeac = 0x%x\n", regeac);
- rege94 = rtl_get_bbreg(hw, 0xe94, BMASKDWORD);
+ rege94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xe94 = 0x%x\n", rege94);
- rege9c = rtl_get_bbreg(hw, 0xe9c, BMASKDWORD);
+ rege9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xe9c = 0x%x\n", rege9c);
- regea4 = rtl_get_bbreg(hw, 0xea4, BMASKDWORD);
+ regea4 = rtl_get_bbreg(hw, 0xea4, MASKDWORD);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xea4 = 0x%x\n", regea4);
if (!(regeac & TxOKBit) &&
(((rege94 & 0x03FF0000) >> 16) != 0x142)) {
@@ -1620,9 +1561,9 @@ static u8 _rtl92d_phy_patha_iqk_5g_normal(struct ieee80211_hw *hw,
}
}
/* path A PA off */
- rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD,
+ rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, MASKDWORD,
rtlphy->iqk_bb_backup[0]);
- rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BMASKDWORD,
+ rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, MASKDWORD,
rtlphy->iqk_bb_backup[1]);
return result;
}
@@ -1637,22 +1578,22 @@ static u8 _rtl92d_phy_pathb_iqk(struct ieee80211_hw *hw)
RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path B IQK!\n");
/* One shot, path B LOK & IQK */
RTPRINT(rtlpriv, FINIT, INIT_IQK, "One shot, path A LOK & IQK!\n");
- rtl_set_bbreg(hw, 0xe60, BMASKDWORD, 0x00000002);
- rtl_set_bbreg(hw, 0xe60, BMASKDWORD, 0x00000000);
+ rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000002);
+ rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000000);
/* delay x ms */
RTPRINT(rtlpriv, FINIT, INIT_IQK,
"Delay %d ms for One shot, path B LOK & IQK\n", IQK_DELAY_TIME);
mdelay(IQK_DELAY_TIME);
/* Check failed */
- regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD);
+ regeac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeac = 0x%x\n", regeac);
- regeb4 = rtl_get_bbreg(hw, 0xeb4, BMASKDWORD);
+ regeb4 = rtl_get_bbreg(hw, 0xeb4, MASKDWORD);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeb4 = 0x%x\n", regeb4);
- regebc = rtl_get_bbreg(hw, 0xebc, BMASKDWORD);
+ regebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xebc = 0x%x\n", regebc);
- regec4 = rtl_get_bbreg(hw, 0xec4, BMASKDWORD);
+ regec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xec4 = 0x%x\n", regec4);
- regecc = rtl_get_bbreg(hw, 0xecc, BMASKDWORD);
+ regecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xecc = 0x%x\n", regecc);
if (!(regeac & BIT(31)) && (((regeb4 & 0x03FF0000) >> 16) != 0x142) &&
(((regebc & 0x03FF0000) >> 16) != 0x42))
@@ -1680,31 +1621,31 @@ static u8 _rtl92d_phy_pathb_iqk_5g_normal(struct ieee80211_hw *hw)
RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path B IQK!\n");
/* path-A IQK setting */
RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path-A IQK setting!\n");
- rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x18008c1f);
- rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x18008c1f);
- rtl_set_bbreg(hw, 0xe38, BMASKDWORD, 0x82110000);
- rtl_set_bbreg(hw, 0xe3c, BMASKDWORD, 0x68110000);
+ rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x18008c1f);
+ rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x18008c1f);
+ rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x82110000);
+ rtl_set_bbreg(hw, 0xe3c, MASKDWORD, 0x68110000);
/* path-B IQK setting */
- rtl_set_bbreg(hw, 0xe50, BMASKDWORD, 0x18008c2f);
- rtl_set_bbreg(hw, 0xe54, BMASKDWORD, 0x18008c2f);
- rtl_set_bbreg(hw, 0xe58, BMASKDWORD, 0x82140307);
- rtl_set_bbreg(hw, 0xe5c, BMASKDWORD, 0x68160960);
+ rtl_set_bbreg(hw, 0xe50, MASKDWORD, 0x18008c2f);
+ rtl_set_bbreg(hw, 0xe54, MASKDWORD, 0x18008c2f);
+ rtl_set_bbreg(hw, 0xe58, MASKDWORD, 0x82140307);
+ rtl_set_bbreg(hw, 0xe5c, MASKDWORD, 0x68160960);
/* LO calibration setting */
RTPRINT(rtlpriv, FINIT, INIT_IQK, "LO calibration setting!\n");
- rtl_set_bbreg(hw, 0xe4c, BMASKDWORD, 0x00462911);
+ rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x00462911);
/* path-B PA on */
- rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD, 0x0f600700);
- rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BMASKDWORD, 0x061f0d30);
+ rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, MASKDWORD, 0x0f600700);
+ rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, MASKDWORD, 0x061f0d30);
for (i = 0; i < retrycount; i++) {
/* One shot, path B LOK & IQK */
RTPRINT(rtlpriv, FINIT, INIT_IQK,
"One shot, path A LOK & IQK!\n");
- rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xfa000000);
- rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf8000000);
+ rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xfa000000);
+ rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000);
/* delay x ms */
RTPRINT(rtlpriv, FINIT, INIT_IQK,
@@ -1712,15 +1653,15 @@ static u8 _rtl92d_phy_pathb_iqk_5g_normal(struct ieee80211_hw *hw)
mdelay(IQK_DELAY_TIME * 10);
/* Check failed */
- regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD);
+ regeac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeac = 0x%x\n", regeac);
- regeb4 = rtl_get_bbreg(hw, 0xeb4, BMASKDWORD);
+ regeb4 = rtl_get_bbreg(hw, 0xeb4, MASKDWORD);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeb4 = 0x%x\n", regeb4);
- regebc = rtl_get_bbreg(hw, 0xebc, BMASKDWORD);
+ regebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xebc = 0x%x\n", regebc);
- regec4 = rtl_get_bbreg(hw, 0xec4, BMASKDWORD);
+ regec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xec4 = 0x%x\n", regec4);
- regecc = rtl_get_bbreg(hw, 0xecc, BMASKDWORD);
+ regecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xecc = 0x%x\n", regecc);
if (!(regeac & BIT(31)) &&
(((regeb4 & 0x03FF0000) >> 16) != 0x142))
@@ -1738,9 +1679,9 @@ static u8 _rtl92d_phy_pathb_iqk_5g_normal(struct ieee80211_hw *hw)
}
/* path B PA off */
- rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD,
+ rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, MASKDWORD,
rtlphy->iqk_bb_backup[0]);
- rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BMASKDWORD,
+ rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, MASKDWORD,
rtlphy->iqk_bb_backup[2]);
return result;
}
@@ -1754,7 +1695,7 @@ static void _rtl92d_phy_save_adda_registers(struct ieee80211_hw *hw,
RTPRINT(rtlpriv, FINIT, INIT_IQK, "Save ADDA parameters.\n");
for (i = 0; i < regnum; i++)
- adda_backup[i] = rtl_get_bbreg(hw, adda_reg[i], BMASKDWORD);
+ adda_backup[i] = rtl_get_bbreg(hw, adda_reg[i], MASKDWORD);
}
static void _rtl92d_phy_save_mac_registers(struct ieee80211_hw *hw,
@@ -1779,7 +1720,7 @@ static void _rtl92d_phy_reload_adda_registers(struct ieee80211_hw *hw,
RTPRINT(rtlpriv, FINIT, INIT_IQK,
"Reload ADDA power saving parameters !\n");
for (i = 0; i < regnum; i++)
- rtl_set_bbreg(hw, adda_reg[i], BMASKDWORD, adda_backup[i]);
+ rtl_set_bbreg(hw, adda_reg[i], MASKDWORD, adda_backup[i]);
}
static void _rtl92d_phy_reload_mac_registers(struct ieee80211_hw *hw,
@@ -1807,7 +1748,7 @@ static void _rtl92d_phy_path_adda_on(struct ieee80211_hw *hw,
pathon = rtlpriv->rtlhal.interfaceindex == 0 ?
0x04db25a4 : 0x0b1b25a4;
for (i = 0; i < IQK_ADDA_REG_NUM; i++)
- rtl_set_bbreg(hw, adda_reg[i], BMASKDWORD, pathon);
+ rtl_set_bbreg(hw, adda_reg[i], MASKDWORD, pathon);
}
static void _rtl92d_phy_mac_setting_calibration(struct ieee80211_hw *hw,
@@ -1830,9 +1771,9 @@ static void _rtl92d_phy_patha_standby(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path-A standby mode!\n");
- rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x0);
- rtl_set_bbreg(hw, RFPGA0_XA_LSSIPARAMETER, BMASKDWORD, 0x00010000);
- rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x80800000);
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x0);
+ rtl_set_bbreg(hw, RFPGA0_XA_LSSIPARAMETER, MASKDWORD, 0x00010000);
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
}
static void _rtl92d_phy_pimode_switch(struct ieee80211_hw *hw, bool pi_mode)
@@ -1843,8 +1784,8 @@ static void _rtl92d_phy_pimode_switch(struct ieee80211_hw *hw, bool pi_mode)
RTPRINT(rtlpriv, FINIT, INIT_IQK,
"BB Switch to %s mode!\n", pi_mode ? "PI" : "SI");
mode = pi_mode ? 0x01000100 : 0x01000000;
- rtl_set_bbreg(hw, 0x820, BMASKDWORD, mode);
- rtl_set_bbreg(hw, 0x828, BMASKDWORD, mode);
+ rtl_set_bbreg(hw, 0x820, MASKDWORD, mode);
+ rtl_set_bbreg(hw, 0x828, MASKDWORD, mode);
}
static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8],
@@ -1875,7 +1816,7 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8],
RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQK for 2.4G :Start!!!\n");
if (t == 0) {
- bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, BMASKDWORD);
+ bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, MASKDWORD);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "==>0x%08x\n", bbvalue);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQ Calibration for %s\n",
is2t ? "2T2R" : "1T1R");
@@ -1898,40 +1839,40 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8],
_rtl92d_phy_pimode_switch(hw, true);
rtl_set_bbreg(hw, RFPGA0_RFMOD, BIT(24), 0x00);
- rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKDWORD, 0x03a05600);
- rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, BMASKDWORD, 0x000800e4);
- rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, BMASKDWORD, 0x22204000);
+ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKDWORD, 0x03a05600);
+ rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, MASKDWORD, 0x000800e4);
+ rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, MASKDWORD, 0x22204000);
rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0xf00000, 0x0f);
if (is2t) {
- rtl_set_bbreg(hw, RFPGA0_XA_LSSIPARAMETER, BMASKDWORD,
+ rtl_set_bbreg(hw, RFPGA0_XA_LSSIPARAMETER, MASKDWORD,
0x00010000);
- rtl_set_bbreg(hw, RFPGA0_XB_LSSIPARAMETER, BMASKDWORD,
+ rtl_set_bbreg(hw, RFPGA0_XB_LSSIPARAMETER, MASKDWORD,
0x00010000);
}
/* MAC settings */
_rtl92d_phy_mac_setting_calibration(hw, iqk_mac_reg,
rtlphy->iqk_mac_backup);
/* Page B init */
- rtl_set_bbreg(hw, 0xb68, BMASKDWORD, 0x0f600000);
+ rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x0f600000);
if (is2t)
- rtl_set_bbreg(hw, 0xb6c, BMASKDWORD, 0x0f600000);
+ rtl_set_bbreg(hw, 0xb6c, MASKDWORD, 0x0f600000);
/* IQ calibration setting */
RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQK setting!\n");
- rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x80800000);
- rtl_set_bbreg(hw, 0xe40, BMASKDWORD, 0x01007c00);
- rtl_set_bbreg(hw, 0xe44, BMASKDWORD, 0x01004800);
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
+ rtl_set_bbreg(hw, 0xe40, MASKDWORD, 0x01007c00);
+ rtl_set_bbreg(hw, 0xe44, MASKDWORD, 0x01004800);
for (i = 0; i < retrycount; i++) {
patha_ok = _rtl92d_phy_patha_iqk(hw, is2t);
if (patha_ok == 0x03) {
RTPRINT(rtlpriv, FINIT, INIT_IQK,
"Path A IQK Success!!\n");
- result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) &
+ result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) &
0x3FF0000) >> 16;
- result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) &
+ result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) &
0x3FF0000) >> 16;
- result[t][2] = (rtl_get_bbreg(hw, 0xea4, BMASKDWORD) &
+ result[t][2] = (rtl_get_bbreg(hw, 0xea4, MASKDWORD) &
0x3FF0000) >> 16;
- result[t][3] = (rtl_get_bbreg(hw, 0xeac, BMASKDWORD) &
+ result[t][3] = (rtl_get_bbreg(hw, 0xeac, MASKDWORD) &
0x3FF0000) >> 16;
break;
} else if (i == (retrycount - 1) && patha_ok == 0x01) {
@@ -1939,9 +1880,9 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8],
RTPRINT(rtlpriv, FINIT, INIT_IQK,
"Path A IQK Only Tx Success!!\n");
- result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) &
+ result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) &
0x3FF0000) >> 16;
- result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) &
+ result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) &
0x3FF0000) >> 16;
}
}
@@ -1957,22 +1898,22 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8],
RTPRINT(rtlpriv, FINIT, INIT_IQK,
"Path B IQK Success!!\n");
result[t][4] = (rtl_get_bbreg(hw, 0xeb4,
- BMASKDWORD) & 0x3FF0000) >> 16;
+ MASKDWORD) & 0x3FF0000) >> 16;
result[t][5] = (rtl_get_bbreg(hw, 0xebc,
- BMASKDWORD) & 0x3FF0000) >> 16;
+ MASKDWORD) & 0x3FF0000) >> 16;
result[t][6] = (rtl_get_bbreg(hw, 0xec4,
- BMASKDWORD) & 0x3FF0000) >> 16;
+ MASKDWORD) & 0x3FF0000) >> 16;
result[t][7] = (rtl_get_bbreg(hw, 0xecc,
- BMASKDWORD) & 0x3FF0000) >> 16;
+ MASKDWORD) & 0x3FF0000) >> 16;
break;
} else if (i == (retrycount - 1) && pathb_ok == 0x01) {
/* Tx IQK OK */
RTPRINT(rtlpriv, FINIT, INIT_IQK,
"Path B Only Tx IQK Success!!\n");
result[t][4] = (rtl_get_bbreg(hw, 0xeb4,
- BMASKDWORD) & 0x3FF0000) >> 16;
+ MASKDWORD) & 0x3FF0000) >> 16;
result[t][5] = (rtl_get_bbreg(hw, 0xebc,
- BMASKDWORD) & 0x3FF0000) >> 16;
+ MASKDWORD) & 0x3FF0000) >> 16;
}
}
if (0x00 == pathb_ok)
@@ -1984,7 +1925,7 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8],
RTPRINT(rtlpriv, FINIT, INIT_IQK,
"IQK:Back to BB mode, load original value!\n");
- rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0);
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0);
if (t != 0) {
/* Switch back BB to SI mode after finish IQ Calibration. */
if (!rtlphy->rfpi_enable)
@@ -2004,8 +1945,8 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8],
rtlphy->iqk_bb_backup,
IQK_BB_REG_NUM - 1);
/* load 0xe30 IQC default value */
- rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x01008c00);
- rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x01008c00);
+ rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x01008c00);
+ rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x01008c00);
}
RTPRINT(rtlpriv, FINIT, INIT_IQK, "<==\n");
}
@@ -2042,7 +1983,7 @@ static void _rtl92d_phy_iq_calibrate_5g_normal(struct ieee80211_hw *hw,
RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQK for 5G NORMAL:Start!!!\n");
mdelay(IQK_DELAY_TIME * 20);
if (t == 0) {
- bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, BMASKDWORD);
+ bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, MASKDWORD);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "==>0x%08x\n", bbvalue);
RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQ Calibration for %s\n",
is2t ? "2T2R" : "1T1R");
@@ -2072,38 +2013,38 @@ static void _rtl92d_phy_iq_calibrate_5g_normal(struct ieee80211_hw *hw,
if (!rtlphy->rfpi_enable)
_rtl92d_phy_pimode_switch(hw, true);
rtl_set_bbreg(hw, RFPGA0_RFMOD, BIT(24), 0x00);
- rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKDWORD, 0x03a05600);
- rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, BMASKDWORD, 0x000800e4);
- rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, BMASKDWORD, 0x22208000);
+ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKDWORD, 0x03a05600);
+ rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, MASKDWORD, 0x000800e4);
+ rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, MASKDWORD, 0x22208000);
rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0xf00000, 0x0f);
/* Page B init */
- rtl_set_bbreg(hw, 0xb68, BMASKDWORD, 0x0f600000);
+ rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x0f600000);
if (is2t)
- rtl_set_bbreg(hw, 0xb6c, BMASKDWORD, 0x0f600000);
+ rtl_set_bbreg(hw, 0xb6c, MASKDWORD, 0x0f600000);
/* IQ calibration setting */
RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQK setting!\n");
- rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x80800000);
- rtl_set_bbreg(hw, 0xe40, BMASKDWORD, 0x10007c00);
- rtl_set_bbreg(hw, 0xe44, BMASKDWORD, 0x01004800);
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
+ rtl_set_bbreg(hw, 0xe40, MASKDWORD, 0x10007c00);
+ rtl_set_bbreg(hw, 0xe44, MASKDWORD, 0x01004800);
patha_ok = _rtl92d_phy_patha_iqk_5g_normal(hw, is2t);
if (patha_ok == 0x03) {
RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A IQK Success!!\n");
- result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) &
+ result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) &
0x3FF0000) >> 16;
- result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) &
+ result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) &
0x3FF0000) >> 16;
- result[t][2] = (rtl_get_bbreg(hw, 0xea4, BMASKDWORD) &
+ result[t][2] = (rtl_get_bbreg(hw, 0xea4, MASKDWORD) &
0x3FF0000) >> 16;
- result[t][3] = (rtl_get_bbreg(hw, 0xeac, BMASKDWORD) &
+ result[t][3] = (rtl_get_bbreg(hw, 0xeac, MASKDWORD) &
0x3FF0000) >> 16;
} else if (patha_ok == 0x01) { /* Tx IQK OK */
RTPRINT(rtlpriv, FINIT, INIT_IQK,
"Path A IQK Only Tx Success!!\n");
- result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) &
+ result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) &
0x3FF0000) >> 16;
- result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) &
+ result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) &
0x3FF0000) >> 16;
} else {
RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A IQK Fail!!\n");
@@ -2116,20 +2057,20 @@ static void _rtl92d_phy_iq_calibrate_5g_normal(struct ieee80211_hw *hw,
if (pathb_ok == 0x03) {
RTPRINT(rtlpriv, FINIT, INIT_IQK,
"Path B IQK Success!!\n");
- result[t][4] = (rtl_get_bbreg(hw, 0xeb4, BMASKDWORD) &
+ result[t][4] = (rtl_get_bbreg(hw, 0xeb4, MASKDWORD) &
0x3FF0000) >> 16;
- result[t][5] = (rtl_get_bbreg(hw, 0xebc, BMASKDWORD) &
+ result[t][5] = (rtl_get_bbreg(hw, 0xebc, MASKDWORD) &
0x3FF0000) >> 16;
- result[t][6] = (rtl_get_bbreg(hw, 0xec4, BMASKDWORD) &
+ result[t][6] = (rtl_get_bbreg(hw, 0xec4, MASKDWORD) &
0x3FF0000) >> 16;
- result[t][7] = (rtl_get_bbreg(hw, 0xecc, BMASKDWORD) &
+ result[t][7] = (rtl_get_bbreg(hw, 0xecc, MASKDWORD) &
0x3FF0000) >> 16;
} else if (pathb_ok == 0x01) { /* Tx IQK OK */
RTPRINT(rtlpriv, FINIT, INIT_IQK,
"Path B Only Tx IQK Success!!\n");
- result[t][4] = (rtl_get_bbreg(hw, 0xeb4, BMASKDWORD) &
+ result[t][4] = (rtl_get_bbreg(hw, 0xeb4, MASKDWORD) &
0x3FF0000) >> 16;
- result[t][5] = (rtl_get_bbreg(hw, 0xebc, BMASKDWORD) &
+ result[t][5] = (rtl_get_bbreg(hw, 0xebc, MASKDWORD) &
0x3FF0000) >> 16;
} else {
RTPRINT(rtlpriv, FINIT, INIT_IQK,
@@ -2140,7 +2081,7 @@ static void _rtl92d_phy_iq_calibrate_5g_normal(struct ieee80211_hw *hw,
/* Back to BB mode, load original value */
RTPRINT(rtlpriv, FINIT, INIT_IQK,
"IQK:Back to BB mode, load original value!\n");
- rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0);
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0);
if (t != 0) {
if (is2t)
_rtl92d_phy_reload_adda_registers(hw, iqk_bb_reg,
@@ -2240,7 +2181,7 @@ static void _rtl92d_phy_patha_fill_iqk_matrix(struct ieee80211_hw *hw,
return;
} else if (iqk_ok) {
oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATxIQIMBALANCE,
- BMASKDWORD) >> 22) & 0x3FF; /* OFDM0_D */
+ MASKDWORD) >> 22) & 0x3FF; /* OFDM0_D */
val_x = result[final_candidate][0];
if ((val_x & 0x00000200) != 0)
val_x = val_x | 0xFFFFFC00;
@@ -2271,7 +2212,7 @@ static void _rtl92d_phy_patha_fill_iqk_matrix(struct ieee80211_hw *hw,
((val_y * oldval_0 >> 7) & 0x1));
RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xC80 = 0x%x\n",
rtl_get_bbreg(hw, ROFDM0_XATxIQIMBALANCE,
- BMASKDWORD));
+ MASKDWORD));
if (txonly) {
RTPRINT(rtlpriv, FINIT, INIT_IQK, "only Tx OK\n");
return;
@@ -2299,7 +2240,7 @@ static void _rtl92d_phy_pathb_fill_iqk_matrix(struct ieee80211_hw *hw,
return;
} else if (iqk_ok) {
oldval_1 = (rtl_get_bbreg(hw, ROFDM0_XBTxIQIMBALANCE,
- BMASKDWORD) >> 22) & 0x3FF;
+ MASKDWORD) >> 22) & 0x3FF;
val_x = result[final_candidate][4];
if ((val_x & 0x00000200) != 0)
val_x = val_x | 0xFFFFFC00;
@@ -2657,7 +2598,7 @@ static void _rtl92d_phy_lc_calibrate_sw(struct ieee80211_hw *hw, bool is2t)
rf_mode[index] = rtl_read_byte(rtlpriv, offset);
/* 2. Set RF mode = standby mode */
rtl_set_rfreg(hw, (enum radio_path)index, RF_AC,
- BRFREGOFFSETMASK, 0x010000);
+ RFREG_OFFSET_MASK, 0x010000);
if (rtlpci->init_ready) {
/* switch CV-curve control by LC-calibration */
rtl_set_rfreg(hw, (enum radio_path)index, RF_SYN_G7,
@@ -2667,16 +2608,16 @@ static void _rtl92d_phy_lc_calibrate_sw(struct ieee80211_hw *hw, bool is2t)
0x08000, 0x01);
}
u4tmp = rtl_get_rfreg(hw, (enum radio_path)index, RF_SYN_G6,
- BRFREGOFFSETMASK);
+ RFREG_OFFSET_MASK);
while ((!(u4tmp & BIT(11))) && timecount <= timeout) {
mdelay(50);
timecount += 50;
u4tmp = rtl_get_rfreg(hw, (enum radio_path)index,
- RF_SYN_G6, BRFREGOFFSETMASK);
+ RF_SYN_G6, RFREG_OFFSET_MASK);
}
RTPRINT(rtlpriv, FINIT, INIT_IQK,
"PHY_LCK finish delay for %d ms=2\n", timecount);
- u4tmp = rtl_get_rfreg(hw, index, RF_SYN_G4, BRFREGOFFSETMASK);
+ u4tmp = rtl_get_rfreg(hw, index, RF_SYN_G4, RFREG_OFFSET_MASK);
if (index == 0 && rtlhal->interfaceindex == 0) {
RTPRINT(rtlpriv, FINIT, INIT_IQK,
"path-A / 5G LCK\n");
@@ -2696,9 +2637,9 @@ static void _rtl92d_phy_lc_calibrate_sw(struct ieee80211_hw *hw, bool is2t)
0x7f, i);
rtl_set_rfreg(hw, (enum radio_path)index, 0x4D,
- BRFREGOFFSETMASK, 0x0);
+ RFREG_OFFSET_MASK, 0x0);
readval = rtl_get_rfreg(hw, (enum radio_path)index,
- 0x4F, BRFREGOFFSETMASK);
+ 0x4F, RFREG_OFFSET_MASK);
curvecount_val[2 * i + 1] = (readval & 0xfffe0) >> 5;
/* reg 0x4f [4:0] */
/* reg 0x50 [19:10] */
@@ -2912,7 +2853,7 @@ static bool _rtl92d_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
}
rtl_set_rfreg(hw, (enum radio_path)rfpath,
currentcmd->para1,
- BRFREGOFFSETMASK,
+ RFREG_OFFSET_MASK,
rtlphy->rfreg_chnlval[rfpath]);
_rtl92d_phy_reload_imr_setting(hw, channel,
rfpath);
@@ -2960,7 +2901,7 @@ u8 rtl92d_phy_sw_chnl(struct ieee80211_hw *hw)
if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY &&
rtlhal->bandset == BAND_ON_BOTH) {
ret_value = rtl_get_bbreg(hw, RFPGA0_XAB_RFPARAMETER,
- BMASKDWORD);
+ MASKDWORD);
if (rtlphy->current_channel > 14 && !(ret_value & BIT(0)))
rtl92d_phy_switch_wirelessband(hw, BAND_ON_5G);
else if (rtlphy->current_channel <= 14 && (ret_value & BIT(0)))
@@ -3112,7 +3053,7 @@ static void _rtl92d_phy_set_rfsleep(struct ieee80211_hw *hw)
/* a. TXPAUSE 0x522[7:0] = 0xFF Pause MAC TX queue */
rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
/* b. RF path 0 offset 0x00 = 0x00 disable RF */
- rtl_set_rfreg(hw, RF90_PATH_A, 0x00, BRFREGOFFSETMASK, 0x00);
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00);
/* c. APSD_CTRL 0x600[7:0] = 0x40 */
rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40);
/* d. APSD_CTRL 0x600[7:0] = 0x00
@@ -3120,12 +3061,12 @@ static void _rtl92d_phy_set_rfsleep(struct ieee80211_hw *hw)
* RF path 0 offset 0x00 = 0x00
* APSD_CTRL 0x600[7:0] = 0x40
* */
- u4btmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, BRFREGOFFSETMASK);
+ u4btmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK);
while (u4btmp != 0 && delay > 0) {
rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x0);
- rtl_set_rfreg(hw, RF90_PATH_A, 0x00, BRFREGOFFSETMASK, 0x00);
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00);
rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40);
- u4btmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, BRFREGOFFSETMASK);
+ u4btmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK);
delay--;
}
if (delay == 0) {
@@ -3468,9 +3409,9 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw)
/* 5G LAN ON */
rtl_set_bbreg(hw, 0xB30, 0x00F00000, 0xa);
/* TX BB gain shift*1,Just for testchip,0xc80,0xc88 */
- rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, BMASKDWORD,
+ rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, MASKDWORD,
0x40000100);
- rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, BMASKDWORD,
+ rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, MASKDWORD,
0x40000100);
if (rtlhal->macphymode == DUALMAC_DUALPHY) {
rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW,
@@ -3524,16 +3465,16 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw)
rtl_set_bbreg(hw, 0xB30, 0x00F00000, 0x0);
/* TX BB gain shift,Just for testchip,0xc80,0xc88 */
if (rtlefuse->internal_pa_5g[0])
- rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, BMASKDWORD,
+ rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, MASKDWORD,
0x2d4000b5);
else
- rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, BMASKDWORD,
+ rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, MASKDWORD,
0x20000080);
if (rtlefuse->internal_pa_5g[1])
- rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, BMASKDWORD,
+ rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, MASKDWORD,
0x2d4000b5);
else
- rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, BMASKDWORD,
+ rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, MASKDWORD,
0x20000080);
if (rtlhal->macphymode == DUALMAC_DUALPHY) {
rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW,
@@ -3560,8 +3501,8 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw)
}
}
/* update IQK related settings */
- rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, BMASKDWORD, 0x40000100);
- rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, BMASKDWORD, 0x40000100);
+ rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, MASKDWORD, 0x40000100);
+ rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, MASKDWORD, 0x40000100);
rtl_set_bbreg(hw, ROFDM0_XCTxAFE, 0xF0000000, 0x00);
rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(30) | BIT(28) |
BIT(26) | BIT(24), 0x00);
@@ -3590,7 +3531,7 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw)
/* DMDP */
if (rtlphy->rf_type == RF_1T1R) {
/* Use antenna 0,0xc04,0xd04 */
- rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0x11);
+ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0x11);
rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0x1);
/* enable ad/da clock1 for dual-phy reg0x888 */
@@ -3612,7 +3553,7 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw)
} else {
/* Single PHY */
/* Use antenna 0 & 1,0xc04,0xd04 */
- rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0x33);
+ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0x33);
rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0x3);
/* disable ad/da clock1,0x888 */
rtl_set_bbreg(hw, RFPGA0_ADDALLOCKEN, BIT(12) | BIT(13), 0);
@@ -3620,9 +3561,9 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw)
for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath;
rfpath++) {
rtlphy->rfreg_chnlval[rfpath] = rtl_get_rfreg(hw, rfpath,
- RF_CHNLBW, BRFREGOFFSETMASK);
+ RF_CHNLBW, RFREG_OFFSET_MASK);
rtlphy->reg_rf3c[rfpath] = rtl_get_rfreg(hw, rfpath, 0x3C,
- BRFREGOFFSETMASK);
+ RFREG_OFFSET_MASK);
}
for (i = 0; i < 2; i++)
RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, "RF 0x18 = 0x%x\n",
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/reg.h b/drivers/net/wireless/rtlwifi/rtl8192de/reg.h
index b7498c5bafc5..7f29b8d765b3 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/reg.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/reg.h
@@ -1295,18 +1295,4 @@
#define BWORD1 0xc
#define BDWORD 0xf
-#define BMASKBYTE0 0xff
-#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
-
-#define BRFREGOFFSETMASK 0xfffff
-
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/rf.c b/drivers/net/wireless/rtlwifi/rtl8192de/rf.c
index 20144e0b4142..6a6ac540d5b5 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/rf.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/rf.c
@@ -125,7 +125,7 @@ void rtl92d_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
}
tmpval = tx_agc[RF90_PATH_A] & 0xff;
- rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, BMASKBYTE1, tmpval);
+ rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval);
RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
"CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n",
tmpval, RTXAGC_A_CCK1_MCS32);
@@ -135,7 +135,7 @@ void rtl92d_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
"CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n",
tmpval, RTXAGC_B_CCK11_A_CCK2_11);
tmpval = tx_agc[RF90_PATH_B] >> 24;
- rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, BMASKBYTE0, tmpval);
+ rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval);
RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
"CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n",
tmpval, RTXAGC_B_CCK11_A_CCK2_11);
@@ -360,7 +360,7 @@ static void _rtl92d_write_ofdm_power_reg(struct ieee80211_hw *hw,
regoffset = regoffset_a[index];
else
regoffset = regoffset_b[index];
- rtl_set_bbreg(hw, regoffset, BMASKDWORD, writeval);
+ rtl_set_bbreg(hw, regoffset, MASKDWORD, writeval);
RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
"Set 0x%x = %08x\n", regoffset, writeval);
if (((get_rf_type(rtlphy) == RF_2T2R) &&
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
index 0eb0f4ae5920..99c2ab5dfceb 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
@@ -545,7 +545,7 @@ static void _rtl92de_insert_emcontent(struct rtl_tcb_desc *ptcb_desc,
void rtl92de_tx_fill_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr, u8 *pdesc_tx,
- struct ieee80211_tx_info *info,
+ u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
struct ieee80211_sta *sta,
struct sk_buff *skb,
u8 hw_queue, struct rtl_tcb_desc *ptcb_desc)
@@ -786,7 +786,8 @@ void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw,
SET_TX_DESC_OWN(pdesc, 1);
}
-void rtl92de_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
+void rtl92de_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+ u8 desc_name, u8 *val)
{
if (istx) {
switch (desc_name) {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.h b/drivers/net/wireless/rtlwifi/rtl8192de/trx.h
index c1b5dfb79d53..fb5cf0634e8d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.h
@@ -728,8 +728,8 @@ struct rx_desc_92d {
} __packed;
void rtl92de_tx_fill_desc(struct ieee80211_hw *hw,
- struct ieee80211_hdr *hdr,
- u8 *pdesc, struct ieee80211_tx_info *info,
+ struct ieee80211_hdr *hdr, u8 *pdesc,
+ u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
struct ieee80211_sta *sta,
struct sk_buff *skb, u8 hw_queue,
struct rtl_tcb_desc *ptcb_desc);
@@ -737,7 +737,8 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw,
struct rtl_stats *stats,
struct ieee80211_rx_status *rx_status,
u8 *pdesc, struct sk_buff *skb);
-void rtl92de_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val);
+void rtl92de_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+ u8 desc_name, u8 *val);
u32 rtl92de_get_desc(u8 *pdesc, bool istx, u8 desc_name);
void rtl92de_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
index 4f461786a7eb..9098558d916d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
@@ -251,7 +251,7 @@ void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
u8 e_aci = *val;
rtl92s_dm_init_edca_turbo(hw);
- if (rtlpci->acm_method != eAcmWay2_SW)
+ if (rtlpci->acm_method != EACMWAY2_SW)
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_ACM_CTRL,
&e_aci);
@@ -413,20 +413,18 @@ void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
(u8 *)(&fw_current_inps));
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_H2C_FW_PWRMODE,
- (u8 *)(&ppsc->fwctrl_psmode));
+ &ppsc->fwctrl_psmode);
- rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_SET_RPWM,
- (u8 *)(&rpwm_val));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+ &rpwm_val);
} else {
rpwm_val = 0x0C; /* RF on */
fw_pwrmode = FW_PS_ACTIVE_MODE;
fw_current_inps = false;
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
- (u8 *)(&rpwm_val));
- rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_H2C_FW_PWRMODE,
- (u8 *)(&fw_pwrmode));
+ &rpwm_val);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+ &fw_pwrmode);
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_FW_PSMODE_STATUS,
@@ -955,7 +953,7 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
u8 tmp_byte = 0;
-
+ unsigned long flags;
bool rtstatus = true;
u8 tmp_u1b;
int err = false;
@@ -967,6 +965,16 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
rtlpci->being_init_adapter = true;
+ /* As this function can take a very long time (up to 350 ms)
+ * and can be called with irqs disabled, reenable the irqs
+ * to let the other devices continue being serviced.
+ *
+ * It is safe doing so since our own interrupts will only be enabled
+ * in a subsequent step.
+ */
+ local_save_flags(flags);
+ local_irq_enable();
+
rtlpriv->intf_ops->disable_aspm(hw);
/* 1. MAC Initialize */
@@ -984,7 +992,8 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"Failed to download FW. Init HW without FW now... "
"Please copy FW into /lib/firmware/rtlwifi\n");
- return 1;
+ err = 1;
+ goto exit;
}
/* After FW download, we have to reset MAC register */
@@ -997,7 +1006,8 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
/* 3. Initialize MAC/PHY Config by MACPHY_reg.txt */
if (!rtl92s_phy_mac_config(hw)) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "MAC Config failed\n");
- return rtstatus;
+ err = rtstatus;
+ goto exit;
}
/* because last function modify RCR, so we update
@@ -1016,7 +1026,8 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
/* 4. Initialize BB After MAC Config PHY_reg.txt, AGC_Tab.txt */
if (!rtl92s_phy_bb_config(hw)) {
RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, "BB Config failed\n");
- return rtstatus;
+ err = rtstatus;
+ goto exit;
}
/* 5. Initiailze RF RAIO_A.txt RF RAIO_B.txt */
@@ -1033,7 +1044,8 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
if (!rtl92s_phy_rf_config(hw)) {
RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "RF Config failed\n");
- return rtstatus;
+ err = rtstatus;
+ goto exit;
}
/* After read predefined TXT, we must set BB/MAC/RF
@@ -1122,8 +1134,9 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_ON);
rtl92s_dm_init(hw);
+exit:
+ local_irq_restore(flags);
rtlpci->being_init_adapter = false;
-
return err;
}
@@ -1135,12 +1148,13 @@ void rtl92se_set_mac_addr(struct rtl_io *io, const u8 *addr)
void rtl92se_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- u32 reg_rcr = rtlpci->receive_config;
+ u32 reg_rcr;
if (rtlpriv->psc.rfpwr_state != ERFON)
return;
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
+
if (check_bssid) {
reg_rcr |= (RCR_CBSSID);
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
index 9c092e6eb3fe..77c5b5f35244 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
@@ -30,6 +30,7 @@
#include "../wifi.h"
#include "../pci.h"
#include "../ps.h"
+#include "../core.h"
#include "reg.h"
#include "def.h"
#include "phy.h"
@@ -833,18 +834,7 @@ static bool _rtl92s_phy_config_bb(struct ieee80211_hw *hw, u8 configtype)
if (configtype == BASEBAND_CONFIG_PHY_REG) {
for (i = 0; i < phy_reg_len; i = i + 2) {
- if (phy_reg_table[i] == 0xfe)
- mdelay(50);
- else if (phy_reg_table[i] == 0xfd)
- mdelay(5);
- else if (phy_reg_table[i] == 0xfc)
- mdelay(1);
- else if (phy_reg_table[i] == 0xfb)
- udelay(50);
- else if (phy_reg_table[i] == 0xfa)
- udelay(5);
- else if (phy_reg_table[i] == 0xf9)
- udelay(1);
+ rtl_addr_delay(phy_reg_table[i]);
/* Add delay for ECS T20 & LG malow platform, */
udelay(1);
@@ -886,18 +876,7 @@ static bool _rtl92s_phy_set_bb_to_diff_rf(struct ieee80211_hw *hw,
if (configtype == BASEBAND_CONFIG_PHY_REG) {
for (i = 0; i < phy_regarray2xtxr_len; i = i + 3) {
- if (phy_regarray2xtxr_table[i] == 0xfe)
- mdelay(50);
- else if (phy_regarray2xtxr_table[i] == 0xfd)
- mdelay(5);
- else if (phy_regarray2xtxr_table[i] == 0xfc)
- mdelay(1);
- else if (phy_regarray2xtxr_table[i] == 0xfb)
- udelay(50);
- else if (phy_regarray2xtxr_table[i] == 0xfa)
- udelay(5);
- else if (phy_regarray2xtxr_table[i] == 0xf9)
- udelay(1);
+ rtl_addr_delay(phy_regarray2xtxr_table[i]);
rtl92s_phy_set_bb_reg(hw, phy_regarray2xtxr_table[i],
phy_regarray2xtxr_table[i + 1],
@@ -920,18 +899,7 @@ static bool _rtl92s_phy_config_bb_with_pg(struct ieee80211_hw *hw,
if (configtype == BASEBAND_CONFIG_PHY_REG) {
for (i = 0; i < phy_pg_len; i = i + 3) {
- if (phy_table_pg[i] == 0xfe)
- mdelay(50);
- else if (phy_table_pg[i] == 0xfd)
- mdelay(5);
- else if (phy_table_pg[i] == 0xfc)
- mdelay(1);
- else if (phy_table_pg[i] == 0xfb)
- udelay(50);
- else if (phy_table_pg[i] == 0xfa)
- udelay(5);
- else if (phy_table_pg[i] == 0xf9)
- udelay(1);
+ rtl_addr_delay(phy_table_pg[i]);
_rtl92s_store_pwrindex_diffrate_offset(hw,
phy_table_pg[i],
@@ -1034,28 +1002,9 @@ u8 rtl92s_phy_config_rf(struct ieee80211_hw *hw, enum radio_path rfpath)
switch (rfpath) {
case RF90_PATH_A:
for (i = 0; i < radio_a_tblen; i = i + 2) {
- if (radio_a_table[i] == 0xfe)
- /* Delay specific ms. Only RF configuration
- * requires delay. */
- mdelay(50);
- else if (radio_a_table[i] == 0xfd)
- mdelay(5);
- else if (radio_a_table[i] == 0xfc)
- mdelay(1);
- else if (radio_a_table[i] == 0xfb)
- udelay(50);
- else if (radio_a_table[i] == 0xfa)
- udelay(5);
- else if (radio_a_table[i] == 0xf9)
- udelay(1);
- else
- rtl92s_phy_set_rf_reg(hw, rfpath,
- radio_a_table[i],
- MASK20BITS,
- radio_a_table[i + 1]);
+ rtl_rfreg_delay(hw, rfpath, radio_a_table[i],
+ MASK20BITS, radio_a_table[i + 1]);
- /* Add delay for ECS T20 & LG malow platform */
- udelay(1);
}
/* PA Bias current for inferiority IC */
@@ -1063,28 +1012,8 @@ u8 rtl92s_phy_config_rf(struct ieee80211_hw *hw, enum radio_path rfpath)
break;
case RF90_PATH_B:
for (i = 0; i < radio_b_tblen; i = i + 2) {
- if (radio_b_table[i] == 0xfe)
- /* Delay specific ms. Only RF configuration
- * requires delay.*/
- mdelay(50);
- else if (radio_b_table[i] == 0xfd)
- mdelay(5);
- else if (radio_b_table[i] == 0xfc)
- mdelay(1);
- else if (radio_b_table[i] == 0xfb)
- udelay(50);
- else if (radio_b_table[i] == 0xfa)
- udelay(5);
- else if (radio_b_table[i] == 0xf9)
- udelay(1);
- else
- rtl92s_phy_set_rf_reg(hw, rfpath,
- radio_b_table[i],
- MASK20BITS,
- radio_b_table[i + 1]);
-
- /* Add delay for ECS T20 & LG malow platform */
- udelay(1);
+ rtl_rfreg_delay(hw, rfpath, radio_b_table[i],
+ MASK20BITS, radio_b_table[i + 1]);
}
break;
case RF90_PATH_C:
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/reg.h b/drivers/net/wireless/rtlwifi/rtl8192se/reg.h
index c81c83591940..e13043479b71 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/reg.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/reg.h
@@ -1165,16 +1165,4 @@
#define BTX_AGCRATECCK 0x7f00
-#define MASKBYTE0 0xff
-#define MASKBYTE1 0xff00
-#define MASKBYTE2 0xff0000
-#define MASKBYTE3 0xff000000
-#define MASKHWORD 0xffff0000
-#define MASKLWORD 0x0000ffff
-#define MASKDWORD 0xffffffff
-
-#define MAKS12BITS 0xfffff
-#define MASK20BITS 0xfffff
-#define RFREG_OFFSET_MASK 0xfffff
-
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/rf.c b/drivers/net/wireless/rtlwifi/rtl8192se/rf.c
index 92d38ab3c60e..78a81c1e390b 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/rf.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/rf.c
@@ -52,7 +52,7 @@ static void _rtl92s_get_powerbase(struct ieee80211_hw *hw, u8 *p_pwrlevel,
/* We only care about the path A for legacy. */
if (rtlefuse->eeprom_version < 2) {
pwrbase0 = pwrlevel[0] + (rtlefuse->legacy_httxpowerdiff & 0xf);
- } else if (rtlefuse->eeprom_version >= 2) {
+ } else {
legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff
[RF90_PATH_A][chnl - 1];
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
index 27efbcdac6a9..36b48be8329c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
@@ -310,7 +310,7 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
/* during testing, hdr was NULL here */
return false;
}
- if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
+ if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
(ieee80211_has_protected(hdr->frame_control)))
rx_status->flag &= ~RX_FLAG_DECRYPTED;
else
@@ -336,7 +336,7 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
void rtl92se_tx_fill_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr, u8 *pdesc_tx,
- struct ieee80211_tx_info *info,
+ u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
struct ieee80211_sta *sta,
struct sk_buff *skb,
u8 hw_queue, struct rtl_tcb_desc *ptcb_desc)
@@ -573,7 +573,8 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
}
}
-void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
+void rtl92se_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+ u8 desc_name, u8 *val)
{
if (istx) {
switch (desc_name) {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.h b/drivers/net/wireless/rtlwifi/rtl8192se/trx.h
index 64dd66f287c1..5a13f17e3b41 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.h
@@ -29,8 +29,9 @@
#ifndef __REALTEK_PCI92SE_TRX_H__
#define __REALTEK_PCI92SE_TRX_H__
-void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,
- u8 *pdesc, struct ieee80211_tx_info *info,
+void rtl92se_tx_fill_desc(struct ieee80211_hw *hw,
+ struct ieee80211_hdr *hdr, u8 *pdesc,
+ u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
struct ieee80211_sta *sta,
struct sk_buff *skb, u8 hw_queue,
struct rtl_tcb_desc *ptcb_desc);
@@ -39,7 +40,8 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg,
bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
struct ieee80211_rx_status *rx_status, u8 *pdesc,
struct sk_buff *skb);
-void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val);
+void rtl92se_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+ u8 desc_name, u8 *val);
u32 rtl92se_get_desc(u8 *pdesc, bool istx, u8 desc_name);
void rtl92se_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile b/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile
index 4ed731f09b1f..9c34a85fdb89 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile
@@ -10,7 +10,6 @@ rtl8723ae-objs := \
led.o \
phy.o \
pwrseq.o \
- pwrseqcmd.o \
rf.o \
sw.o \
table.o \
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/def.h b/drivers/net/wireless/rtlwifi/rtl8723ae/def.h
index 8c110356dff9..debe261a7eeb 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/def.h
@@ -46,11 +46,6 @@
#define E_CUT_VERSION BIT(14)
#define RF_RL_ID (BIT(31)|BIT(30)|BIT(29)|BIT(28))
-enum version_8723e {
- VERSION_TEST_UMC_CHIP_8723 = 0x0081,
- VERSION_NORMAL_UMC_CHIP_8723_1T1R_A_CUT = 0x0089,
- VERSION_NORMAL_UMC_CHIP_8723_1T1R_B_CUT = 0x1089,
-};
/* MASK */
#define IC_TYPE_MASK (BIT(0)|BIT(1)|BIT(2))
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c
index a36eee28f9e7..25cc83058b01 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c
@@ -35,6 +35,7 @@
#include "def.h"
#include "phy.h"
#include "dm.h"
+#include "../rtl8723com/dm_common.h"
#include "fw.h"
#include "hal_btc.h"
@@ -483,16 +484,6 @@ static void rtl8723ae_dm_dig(struct ieee80211_hw *hw)
rtl8723ae_dm_ctrl_initgain_by_twoport(hw);
}
-static void rtl8723ae_dm_init_dynamic_txpower(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
-
- rtlpriv->dm.dynamic_txpower_enable = false;
-
- rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL;
- rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
-}
-
static void rtl8723ae_dm_dynamic_txpower(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -585,19 +576,6 @@ void rtl8723ae_dm_write_dig(struct ieee80211_hw *hw)
}
}
-static void rtl8723ae_dm_pwdmonitor(struct ieee80211_hw *hw)
-{
-}
-
-void rtl8723ae_dm_init_edca_turbo(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
-
- rtlpriv->dm.current_turbo_edca = false;
- rtlpriv->dm.is_any_nonbepkts = false;
- rtlpriv->dm.is_cur_rdlstate = false;
-}
-
static void rtl8723ae_dm_check_edca_turbo(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -669,9 +647,8 @@ static void rtl8723ae_dm_check_edca_turbo(struct ieee80211_hw *hw)
} else {
if (rtlpriv->dm.current_turbo_edca) {
u8 tmp = AC0_BE;
- rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_AC_PARAM,
- (u8 *) (&tmp));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
+ &tmp);
rtlpriv->dm.current_turbo_edca = false;
}
}
@@ -778,17 +755,6 @@ static void rtl8723ae_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
}
}
-static void rtl8723ae_dm_init_dynamic_bpowersaving(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
-
- rtlpriv->dm_pstable.pre_ccastate = CCA_MAX;
- rtlpriv->dm_pstable.cur_ccasate = CCA_MAX;
- rtlpriv->dm_pstable.pre_rfstate = RF_MAX;
- rtlpriv->dm_pstable.cur_rfstate = RF_MAX;
- rtlpriv->dm_pstable.rssi_val_min = 0;
-}
-
void rtl8723ae_dm_rf_saving(struct ieee80211_hw *hw, u8 force_in_normal)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -905,11 +871,11 @@ void rtl8723ae_dm_init(struct ieee80211_hw *hw)
rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
rtl8723ae_dm_diginit(hw);
- rtl8723ae_dm_init_dynamic_txpower(hw);
- rtl8723ae_dm_init_edca_turbo(hw);
+ rtl8723_dm_init_dynamic_txpower(hw);
+ rtl8723_dm_init_edca_turbo(hw);
rtl8723ae_dm_init_rate_adaptive_mask(hw);
rtl8723ae_dm_initialize_txpower_tracking(hw);
- rtl8723ae_dm_init_dynamic_bpowersaving(hw);
+ rtl8723_dm_init_dynamic_bb_powersaving(hw);
}
void rtl8723ae_dm_watchdog(struct ieee80211_hw *hw)
@@ -930,7 +896,6 @@ void rtl8723ae_dm_watchdog(struct ieee80211_hw *hw)
if ((ppsc->rfpwr_state == ERFON) &&
((!fw_current_inpsmode) && fw_ps_awake) &&
(!ppsc->rfchange_inprogress)) {
- rtl8723ae_dm_pwdmonitor(hw);
rtl8723ae_dm_dig(hw);
rtl8723ae_dm_false_alarm_counter_statistics(hw);
rtl8723ae_dm_dynamic_bpowersaving(hw);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h
index a372b0204456..d253bb53d03e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h
@@ -147,7 +147,6 @@ enum dm_dig_connect_e {
void rtl8723ae_dm_init(struct ieee80211_hw *hw);
void rtl8723ae_dm_watchdog(struct ieee80211_hw *hw);
void rtl8723ae_dm_write_dig(struct ieee80211_hw *hw);
-void rtl8723ae_dm_init_edca_turbo(struct ieee80211_hw *hw);
void rtl8723ae_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw);
void rtl8723ae_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal);
void rtl8723ae_dm_bt_coexist(struct ieee80211_hw *hw);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
index ba1502b172a6..728b7563ad36 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
@@ -34,199 +34,7 @@
#include "reg.h"
#include "def.h"
#include "fw.h"
-
-static void _rtl8723ae_enable_fw_download(struct ieee80211_hw *hw, bool enable)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u8 tmp;
- if (enable) {
- tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
- rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
-
- tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
- rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
-
- tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
- rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
- } else {
- tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
- rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
-
- rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
- }
-}
-
-static void _rtl8723ae_fw_block_write(struct ieee80211_hw *hw,
- const u8 *buffer, u32 size)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 blockSize = sizeof(u32);
- u8 *bufferPtr = (u8 *) buffer;
- u32 *pu4BytePtr = (u32 *) buffer;
- u32 i, offset, blockCount, remainSize;
-
- blockCount = size / blockSize;
- remainSize = size % blockSize;
-
- for (i = 0; i < blockCount; i++) {
- offset = i * blockSize;
- rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
- *(pu4BytePtr + i));
- }
-
- if (remainSize) {
- offset = blockCount * blockSize;
- bufferPtr += offset;
- for (i = 0; i < remainSize; i++) {
- rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS +
- offset + i), *(bufferPtr + i));
- }
- }
-}
-
-static void _rtl8723ae_fw_page_write(struct ieee80211_hw *hw,
- u32 page, const u8 *buffer, u32 size)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u8 value8;
- u8 u8page = (u8) (page & 0x07);
-
- value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
-
- rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
- _rtl8723ae_fw_block_write(hw, buffer, size);
-}
-
-static void _rtl8723ae_write_fw(struct ieee80211_hw *hw,
- enum version_8723e version, u8 *buffer,
- u32 size)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u8 *bufferPtr = (u8 *) buffer;
- u32 page_nums, remain_size;
- u32 page, offset;
-
- RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);
-
- page_nums = size / FW_8192C_PAGE_SIZE;
- remain_size = size % FW_8192C_PAGE_SIZE;
-
- if (page_nums > 6) {
- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
- "Page numbers should not be greater then 6\n");
- }
-
- for (page = 0; page < page_nums; page++) {
- offset = page * FW_8192C_PAGE_SIZE;
- _rtl8723ae_fw_page_write(hw, page, (bufferPtr + offset),
- FW_8192C_PAGE_SIZE);
- }
-
- if (remain_size) {
- offset = page_nums * FW_8192C_PAGE_SIZE;
- page = page_nums;
- _rtl8723ae_fw_page_write(hw, page, (bufferPtr + offset),
- remain_size);
- }
-
- RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW write done.\n");
-}
-
-static int _rtl8723ae_fw_free_to_go(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- int err = -EIO;
- u32 counter = 0;
- u32 value32;
-
- do {
- value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
- } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
- (!(value32 & FWDL_ChkSum_rpt)));
-
- if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
- "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
- value32);
- goto exit;
- }
-
- RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
- "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
-
- value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
- value32 |= MCUFWDL_RDY;
- value32 &= ~WINTINI_RDY;
- rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
-
- counter = 0;
-
- do {
- value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
- if (value32 & WINTINI_RDY) {
- RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
- "Polling FW ready success!! REG_MCUFWDL:0x%08x .\n",
- value32);
- err = 0;
- goto exit;
- }
-
- mdelay(FW_8192C_POLLING_DELAY);
-
- } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
-
- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
- "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32);
-
-exit:
- return err;
-}
-
-int rtl8723ae_download_fw(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
- struct rtl8723ae_firmware_header *pfwheader;
- u8 *pfwdata;
- u32 fwsize;
- int err;
- enum version_8723e version = rtlhal->version;
-
- if (!rtlhal->pfirmware)
- return 1;
-
- pfwheader = (struct rtl8723ae_firmware_header *)rtlhal->pfirmware;
- pfwdata = (u8 *) rtlhal->pfirmware;
- fwsize = rtlhal->fwsize;
-
- if (IS_FW_HEADER_EXIST(pfwheader)) {
- RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
- "Firmware Version(%d), Signature(%#x),Size(%d)\n",
- pfwheader->version, pfwheader->signature,
- (int)sizeof(struct rtl8723ae_firmware_header));
-
- pfwdata = pfwdata + sizeof(struct rtl8723ae_firmware_header);
- fwsize = fwsize - sizeof(struct rtl8723ae_firmware_header);
- }
-
- if (rtl_read_byte(rtlpriv, REG_MCUFWDL)&BIT(7)) {
- rtl8723ae_firmware_selfreset(hw);
- rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
- }
- _rtl8723ae_enable_fw_download(hw, true);
- _rtl8723ae_write_fw(hw, version, pfwdata, fwsize);
- _rtl8723ae_enable_fw_download(hw, false);
-
- err = _rtl8723ae_fw_free_to_go(hw);
- if (err) {
- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
- "Firmware is not ready to run!\n");
- } else {
- RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
- "Firmware is ready to run!\n");
- }
- return 0;
-}
+#include "../rtl8723com/fw_common.h"
static bool rtl8723ae_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
{
@@ -463,50 +271,6 @@ void rtl8723ae_fill_h2c_cmd(struct ieee80211_hw *hw,
return;
}
-void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw)
-{
- u8 u1tmp;
- u8 delay = 100;
- struct rtl_priv *rtlpriv = rtl_priv(hw);
-
- rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
- u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
-
- while (u1tmp & BIT(2)) {
- delay--;
- if (delay == 0)
- break;
- udelay(50);
- u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
- }
- if (delay == 0) {
- u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
- rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, u1tmp&(~BIT(2)));
- }
-}
-
-void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u8 u1_h2c_set_pwrmode[3] = { 0 };
- struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
-
- RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
-
- SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
- SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
- (rtlpriv->mac80211.p2p) ?
- ppsc->smart_ps : 1);
- SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
- ppsc->reg_max_lps_awakeintvl);
-
- RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
- "rtl8723ae_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
- u1_h2c_set_pwrmode, 3);
- rtl8723ae_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
-
-}
-
static bool _rtl8723ae_cmd_send_packet(struct ieee80211_hw *hw,
struct sk_buff *skb)
{
@@ -812,7 +576,6 @@ void rtl8723ae_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
p2p_ps_offload->offload_en = 1;
-
if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
p2p_ps_offload->role = 1;
p2p_ps_offload->allstasleep = 0;
@@ -836,3 +599,24 @@ void rtl8723ae_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
}
rtl8723ae_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
}
+
+void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 u1_h2c_set_pwrmode[3] = { 0 };
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
+
+ SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
+ SET_H2CCMD_PWRMODE_PARM_SMART_PS_23A(u1_h2c_set_pwrmode,
+ (rtlpriv->mac80211.p2p) ?
+ ppsc->smart_ps : 1);
+ SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
+ ppsc->reg_max_lps_awakeintvl);
+
+ RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+ "rtl8723ae_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
+ u1_h2c_set_pwrmode, 3);
+ rtl8723ae_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h
index ed3b795e6980..d355b85dd9fe 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h
@@ -34,7 +34,7 @@
#define FW_8192C_END_ADDRESS 0x3FFF
#define FW_8192C_PAGE_SIZE 4096
#define FW_8192C_POLLING_DELAY 5
-#define FW_8192C_POLLING_TIMEOUT_COUNT 1000
+#define FW_8192C_POLLING_TIMEOUT_COUNT 6000
#define BEACON_PG 0
#define PSPOLL_PG 2
@@ -65,21 +65,9 @@ struct rtl8723ae_firmware_header {
u32 rsvd5;
};
-enum rtl8192c_h2c_cmd {
- H2C_AP_OFFLOAD = 0,
- H2C_SETPWRMODE = 1,
- H2C_JOINBSSRPT = 2,
- H2C_RSVDPAGE = 3,
- H2C_RSSI_REPORT = 4,
- H2C_P2P_PS_CTW_CMD = 5,
- H2C_P2P_PS_OFFLOAD = 6,
- H2C_RA_MASK = 7,
- MAX_H2CCMD
-};
-
#define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val) \
SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
-#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__ph2ccmd, __val) \
+#define SET_H2CCMD_PWRMODE_PARM_SMART_PS_23A(__ph2ccmd, __val) \
SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
#define SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(__ph2ccmd, __val) \
SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
@@ -92,10 +80,8 @@ enum rtl8192c_h2c_cmd {
#define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val) \
SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
-int rtl8723ae_download_fw(struct ieee80211_hw *hw);
void rtl8723ae_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,
u32 cmd_len, u8 *p_cmdbuffer);
-void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw);
void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
void rtl8723ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
void rtl8723ae_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.c
index 3d092e4b0b7f..48fee1be78c2 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.c
@@ -31,6 +31,8 @@
#include "../pci.h"
#include "dm.h"
#include "fw.h"
+#include "../rtl8723com/fw_common.h"
+#include "../rtl8723com/fw_common.h"
#include "phy.h"
#include "reg.h"
#include "hal_btc.h"
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
index 68c28340f791..5d534df8d90c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
@@ -30,7 +30,9 @@
#include "hal_btc.h"
#include "../pci.h"
#include "phy.h"
+#include "../rtl8723com/phy_common.h"
#include "fw.h"
+#include "../rtl8723com/fw_common.h"
#include "reg.h"
#include "def.h"
@@ -391,13 +393,13 @@ static void rtl8723ae_dm_bt_set_sw_full_time_dac_swing(struct ieee80211_hw *hw,
if (sw_dac_swing_on) {
RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
"[BTCoex], SwDacSwing = 0x%x\n", sw_dac_swing_lvl);
- rtl8723ae_phy_set_bb_reg(hw, 0x880, 0xff000000,
- sw_dac_swing_lvl);
+ rtl8723_phy_set_bb_reg(hw, 0x880, 0xff000000,
+ sw_dac_swing_lvl);
rtlpcipriv->bt_coexist.sw_coexist_all_off = false;
} else {
RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
"[BTCoex], SwDacSwing Off!\n");
- rtl8723ae_phy_set_bb_reg(hw, 0x880, 0xff000000, 0xc0);
+ rtl8723_phy_set_bb_reg(hw, 0x880, 0xff000000, 0xc0);
}
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
index c333dfd116b8..65c9e80e1f78 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
@@ -38,10 +38,11 @@
#include "def.h"
#include "phy.h"
#include "dm.h"
+#include "../rtl8723com/dm_common.h"
#include "fw.h"
+#include "../rtl8723com/fw_common.h"
#include "led.h"
#include "hw.h"
-#include "pwrseqcmd.h"
#include "pwrseq.h"
#include "btc.h"
@@ -206,14 +207,13 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
rtl_write_byte(rtlpriv, REG_SLOT, val[0]);
for (e_aci = 0; e_aci < AC_MAX; e_aci++) {
- rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_AC_PARAM,
- (u8 *) (&e_aci));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
+ &e_aci);
}
break; }
case HW_VAR_ACK_PREAMBLE:{
u8 reg_tmp;
- u8 short_preamble = (bool) (*(u8 *) val);
+ u8 short_preamble = (bool)*val;
reg_tmp = (mac->cur_40_prime_sc) << 5;
if (short_preamble)
reg_tmp |= 0x80;
@@ -224,7 +224,7 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
u8 min_spacing_to_set;
u8 sec_min_space;
- min_spacing_to_set = *((u8 *) val);
+ min_spacing_to_set = *val;
if (min_spacing_to_set <= 7) {
sec_min_space = 0;
@@ -248,7 +248,7 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
case HW_VAR_SHORTGI_DENSITY:{
u8 density_to_set;
- density_to_set = *((u8 *) val);
+ density_to_set = *val;
mac->min_space_cfg |= (density_to_set << 3);
RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
@@ -272,7 +272,7 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
else
p_regtoset = regtoset_normal;
- factor_toset = *((u8 *) val);
+ factor_toset = *val;
if (factor_toset <= 3) {
factor_toset = (1 << (factor_toset + 2));
if (factor_toset > 0xf)
@@ -303,16 +303,15 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
}
break; }
case HW_VAR_AC_PARAM:{
- u8 e_aci = *((u8 *) val);
- rtl8723ae_dm_init_edca_turbo(hw);
+ u8 e_aci = *val;
+ rtl8723_dm_init_edca_turbo(hw);
- if (rtlpci->acm_method != eAcmWay2_SW)
- rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_ACM_CTRL,
- (u8 *) (&e_aci));
+ if (rtlpci->acm_method != EACMWAY2_SW)
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL,
+ &e_aci);
break; }
case HW_VAR_ACM_CTRL:{
- u8 e_aci = *((u8 *) val);
+ u8 e_aci = *val;
union aci_aifsn *p_aci_aifsn =
(union aci_aifsn *)(&(mac->ac[0].aifs));
u8 acm = p_aci_aifsn->f.acm;
@@ -365,7 +364,7 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
rtlpci->receive_config = ((u32 *) (val))[0];
break;
case HW_VAR_RETRY_LIMIT:{
- u8 retry_limit = ((u8 *) (val))[0];
+ u8 retry_limit = *val;
rtl_write_word(rtlpriv, REG_RL,
retry_limit << RETRY_LIMIT_SHORT_SHIFT |
@@ -378,13 +377,13 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
rtlefuse->efuse_usedbytes = *((u16 *) val);
break;
case HW_VAR_EFUSE_USAGE:
- rtlefuse->efuse_usedpercentage = *((u8 *) val);
+ rtlefuse->efuse_usedpercentage = *val;
break;
case HW_VAR_IO_CMD:
rtl8723ae_phy_set_io_cmd(hw, (*(enum io_type *)val));
break;
case HW_VAR_WPA_CONFIG:
- rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *) val));
+ rtl_write_byte(rtlpriv, REG_SECCFG, *val);
break;
case HW_VAR_SET_RPWM:{
u8 rpwm_val;
@@ -393,27 +392,25 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
udelay(1);
if (rpwm_val & BIT(7)) {
- rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
- (*(u8 *) val));
+ rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, *val);
} else {
- rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
- ((*(u8 *) val) | BIT(7)));
+ rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, *val | BIT(7));
}
break; }
case HW_VAR_H2C_FW_PWRMODE:{
- u8 psmode = (*(u8 *) val);
+ u8 psmode = *val;
if (psmode != FW_PS_ACTIVE_MODE)
rtl8723ae_dm_rf_saving(hw, true);
- rtl8723ae_set_fw_pwrmode_cmd(hw, (*(u8 *) val));
+ rtl8723ae_set_fw_pwrmode_cmd(hw, *val);
break; }
case HW_VAR_FW_PSMODE_STATUS:
ppsc->fw_current_inpsmode = *((bool *) val);
break;
case HW_VAR_H2C_FW_JOINBSSRPT:{
- u8 mstatus = (*(u8 *) val);
+ u8 mstatus = *val;
u8 tmp_regcr, tmp_reg422;
bool recover = false;
@@ -446,11 +443,11 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
rtl_write_byte(rtlpriv, REG_CR + 1,
(tmp_regcr & ~(BIT(0))));
}
- rtl8723ae_set_fw_joinbss_report_cmd(hw, (*(u8 *) val));
+ rtl8723ae_set_fw_joinbss_report_cmd(hw, *val);
break; }
case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
- rtl8723ae_set_p2p_ps_offload_cmd(hw, (*(u8 *)val));
+ rtl8723ae_set_p2p_ps_offload_cmd(hw, *val);
break;
case HW_VAR_AID:{
u16 u2btmp;
@@ -460,7 +457,7 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
mac->assoc_id));
break; }
case HW_VAR_CORRECT_TSF:{
- u8 btype_ibss = ((u8 *) (val))[0];
+ u8 btype_ibss = *val;
if (btype_ibss == true)
_rtl8723ae_stop_tx_beacon(hw);
@@ -490,20 +487,18 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
(u8 *)(&fw_current_inps));
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_H2C_FW_PWRMODE,
- (u8 *)(&ppsc->fwctrl_psmode));
+ &ppsc->fwctrl_psmode);
- rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_SET_RPWM,
- (u8 *)(&rpwm_val));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+ &rpwm_val);
} else {
rpwm_val = 0x0C; /* RF on */
fw_pwrmode = FW_PS_ACTIVE_MODE;
fw_current_inps = false;
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
- (u8 *)(&rpwm_val));
- rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_H2C_FW_PWRMODE,
- (u8 *)(&fw_pwrmode));
+ &rpwm_val);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+ &fw_pwrmode);
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_FW_PSMODE_STATUS,
@@ -880,23 +875,33 @@ int rtl8723ae_hw_init(struct ieee80211_hw *hw)
bool rtstatus = true;
int err;
u8 tmp_u1b;
+ unsigned long flags;
rtlpriv->rtlhal.being_init_adapter = true;
+ /* As this function can take a very long time (up to 350 ms)
+ * and can be called with irqs disabled, reenable the irqs
+ * to let the other devices continue being serviced.
+ *
+ * It is safe doing so since our own interrupts will only be enabled
+ * in a subsequent step.
+ */
+ local_save_flags(flags);
+ local_irq_enable();
+
rtlpriv->intf_ops->disable_aspm(hw);
rtstatus = _rtl8712e_init_mac(hw);
if (rtstatus != true) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n");
err = 1;
- return err;
+ goto exit;
}
- err = rtl8723ae_download_fw(hw);
+ err = rtl8723_download_fw(hw, false);
if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"Failed to download FW. Init HW without FW now..\n");
err = 1;
- rtlhal->fw_ready = false;
- return err;
+ goto exit;
} else {
rtlhal->fw_ready = true;
}
@@ -971,6 +976,8 @@ int rtl8723ae_hw_init(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "under 1.5V\n");
}
rtl8723ae_dm_init(hw);
+exit:
+ local_irq_restore(flags);
rtlpriv->rtlhal.being_init_adapter = false;
return err;
}
@@ -1112,12 +1119,13 @@ static int _rtl8723ae_set_media_status(struct ieee80211_hw *hw,
void rtl8723ae_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- u32 reg_rcr = rtlpci->receive_config;
+ u32 reg_rcr;
if (rtlpriv->psc.rfpwr_state != ERFON)
return;
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
+
if (check_bssid == true) {
reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
@@ -1153,7 +1161,7 @@ void rtl8723ae_set_qos(struct ieee80211_hw *hw, int aci)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- rtl8723ae_dm_init_edca_turbo(hw);
+ rtl8723_dm_init_edca_turbo(hw);
switch (aci) {
case AC1_BK:
rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f);
@@ -1614,10 +1622,10 @@ static void _rtl8723ae_read_adapter_info(struct ieee80211_hw *hw,
rtl8723ae_read_bt_coexist_info_from_hwpg(hw,
rtlefuse->autoload_failflag, hwinfo);
- rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
+ rtlefuse->eeprom_channelplan = hwinfo[EEPROM_CHANNELPLAN];
rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION];
rtlefuse->txpwr_fromeprom = true;
- rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID];
+ rtlefuse->eeprom_oemid = hwinfo[EEPROM_CUSTOMER_ID];
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
"EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid);
@@ -1655,7 +1663,7 @@ static void _rtl8723ae_read_adapter_info(struct ieee80211_hw *hw,
CHK_SVID_SMID(0x10EC, 0x9185))
rtlhal->oem_id = RT_CID_TOSHIBA;
else if (rtlefuse->eeprom_svid == 0x1025)
- rtlhal->oem_id = RT_CID_819x_Acer;
+ rtlhal->oem_id = RT_CID_819X_ACER;
else if (CHK_SVID_SMID(0x10EC, 0x6191) ||
CHK_SVID_SMID(0x10EC, 0x6192) ||
CHK_SVID_SMID(0x10EC, 0x6193) ||
@@ -1665,7 +1673,7 @@ static void _rtl8723ae_read_adapter_info(struct ieee80211_hw *hw,
CHK_SVID_SMID(0x10EC, 0x8191) ||
CHK_SVID_SMID(0x10EC, 0x8192) ||
CHK_SVID_SMID(0x10EC, 0x8193))
- rtlhal->oem_id = RT_CID_819x_SAMSUNG;
+ rtlhal->oem_id = RT_CID_819X_SAMSUNG;
else if (CHK_SVID_SMID(0x10EC, 0x8195) ||
CHK_SVID_SMID(0x10EC, 0x9195) ||
CHK_SVID_SMID(0x10EC, 0x7194) ||
@@ -1673,24 +1681,24 @@ static void _rtl8723ae_read_adapter_info(struct ieee80211_hw *hw,
CHK_SVID_SMID(0x10EC, 0x8201) ||
CHK_SVID_SMID(0x10EC, 0x8202) ||
CHK_SVID_SMID(0x10EC, 0x9200))
- rtlhal->oem_id = RT_CID_819x_Lenovo;
+ rtlhal->oem_id = RT_CID_819X_LENOVO;
else if (CHK_SVID_SMID(0x10EC, 0x8197) ||
CHK_SVID_SMID(0x10EC, 0x9196))
- rtlhal->oem_id = RT_CID_819x_CLEVO;
+ rtlhal->oem_id = RT_CID_819X_CLEVO;
else if (CHK_SVID_SMID(0x1028, 0x8194) ||
CHK_SVID_SMID(0x1028, 0x8198) ||
CHK_SVID_SMID(0x1028, 0x9197) ||
CHK_SVID_SMID(0x1028, 0x9198))
- rtlhal->oem_id = RT_CID_819x_DELL;
+ rtlhal->oem_id = RT_CID_819X_DELL;
else if (CHK_SVID_SMID(0x103C, 0x1629))
- rtlhal->oem_id = RT_CID_819x_HP;
+ rtlhal->oem_id = RT_CID_819X_HP;
else if (CHK_SVID_SMID(0x1A32, 0x2315))
- rtlhal->oem_id = RT_CID_819x_QMI;
+ rtlhal->oem_id = RT_CID_819X_QMI;
else if (CHK_SVID_SMID(0x10EC, 0x8203))
- rtlhal->oem_id = RT_CID_819x_PRONETS;
+ rtlhal->oem_id = RT_CID_819X_PRONETS;
else if (CHK_SVID_SMID(0x1043, 0x84B5))
rtlhal->oem_id =
- RT_CID_819x_Edimax_ASUS;
+ RT_CID_819X_EDIMAX_ASUS;
else
rtlhal->oem_id = RT_CID_DEFAULT;
} else if (rtlefuse->eeprom_did == 0x8178) {
@@ -1712,12 +1720,12 @@ static void _rtl8723ae_read_adapter_info(struct ieee80211_hw *hw,
CHK_SVID_SMID(0x10EC, 0x9185))
rtlhal->oem_id = RT_CID_TOSHIBA;
else if (rtlefuse->eeprom_svid == 0x1025)
- rtlhal->oem_id = RT_CID_819x_Acer;
+ rtlhal->oem_id = RT_CID_819X_ACER;
else if (CHK_SVID_SMID(0x10EC, 0x8186))
- rtlhal->oem_id = RT_CID_819x_PRONETS;
+ rtlhal->oem_id = RT_CID_819X_PRONETS;
else if (CHK_SVID_SMID(0x1043, 0x8486))
rtlhal->oem_id =
- RT_CID_819x_Edimax_ASUS;
+ RT_CID_819X_EDIMAX_ASUS;
else
rtlhal->oem_id = RT_CID_DEFAULT;
} else {
@@ -1731,7 +1739,7 @@ static void _rtl8723ae_read_adapter_info(struct ieee80211_hw *hw,
rtlhal->oem_id = RT_CID_CCX;
break;
case EEPROM_CID_QMI:
- rtlhal->oem_id = RT_CID_819x_QMI;
+ rtlhal->oem_id = RT_CID_819X_QMI;
break;
case EEPROM_CID_WHQL:
break;
@@ -2037,8 +2045,7 @@ void rtl8723ae_update_channel_access_setting(struct ieee80211_hw *hw)
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
u16 sifs_timer;
- rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
- (u8 *)&mac->slot_time);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME, &mac->slot_time);
if (!mac->ht_enable)
sifs_timer = 0x0a0a;
else
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c
index 5d318a85eda4..3ea78afdec73 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c
@@ -30,12 +30,14 @@
#include "../wifi.h"
#include "../pci.h"
#include "../ps.h"
+#include "../core.h"
#include "reg.h"
#include "def.h"
#include "phy.h"
#include "rf.h"
#include "dm.h"
#include "table.h"
+#include "../rtl8723com/phy_common.h"
/* static forward definitions */
static u32 _phy_fw_rf_serial_read(struct ieee80211_hw *hw,
@@ -43,72 +45,17 @@ static u32 _phy_fw_rf_serial_read(struct ieee80211_hw *hw,
static void _phy_fw_rf_serial_write(struct ieee80211_hw *hw,
enum radio_path rfpath,
u32 offset, u32 data);
-static u32 _phy_rf_serial_read(struct ieee80211_hw *hw,
- enum radio_path rfpath, u32 offset);
-static void _phy_rf_serial_write(struct ieee80211_hw *hw,
- enum radio_path rfpath, u32 offset, u32 data);
-static u32 _phy_calculate_bit_shift(u32 bitmask);
static bool _phy_bb8192c_config_parafile(struct ieee80211_hw *hw);
static bool _phy_cfg_mac_w_header(struct ieee80211_hw *hw);
static bool _phy_cfg_bb_w_header(struct ieee80211_hw *hw, u8 configtype);
static bool _phy_cfg_bb_w_pgheader(struct ieee80211_hw *hw, u8 configtype);
-static void _phy_init_bb_rf_reg_def(struct ieee80211_hw *hw);
-static bool _phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
- u32 cmdtableidx, u32 cmdtablesz,
- enum swchnlcmd_id cmdid,
- u32 para1, u32 para2,
- u32 msdelay);
static bool _phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, u8 channel,
u8 *stage, u8 *step, u32 *delay);
static u8 _phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw,
enum wireless_mode wirelessmode,
long power_indbm);
-static long _phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
- enum wireless_mode wirelessmode, u8 txpwridx);
static void rtl8723ae_phy_set_io(struct ieee80211_hw *hw);
-u32 rtl8723ae_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr,
- u32 bitmask)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 returnvalue, originalvalue, bitshift;
-
- RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
- "regaddr(%#x), bitmask(%#x)\n", regaddr, bitmask);
- originalvalue = rtl_read_dword(rtlpriv, regaddr);
- bitshift = _phy_calculate_bit_shift(bitmask);
- returnvalue = (originalvalue & bitmask) >> bitshift;
-
- RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
- "BBR MASK=0x%x Addr[0x%x]=0x%x\n", bitmask, regaddr,
- originalvalue);
-
- return returnvalue;
-}
-
-void rtl8723ae_phy_set_bb_reg(struct ieee80211_hw *hw,
- u32 regaddr, u32 bitmask, u32 data)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 originalvalue, bitshift;
-
- RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
- "regaddr(%#x), bitmask(%#x), data(%#x)\n", regaddr,
- bitmask, data);
-
- if (bitmask != MASKDWORD) {
- originalvalue = rtl_read_dword(rtlpriv, regaddr);
- bitshift = _phy_calculate_bit_shift(bitmask);
- data = ((originalvalue & (~bitmask)) | (data << bitshift));
- }
-
- rtl_write_dword(rtlpriv, regaddr, data);
-
- RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
- "regaddr(%#x), bitmask(%#x), data(%#x)\n",
- regaddr, bitmask, data);
-}
-
u32 rtl8723ae_phy_query_rf_reg(struct ieee80211_hw *hw,
enum radio_path rfpath, u32 regaddr, u32 bitmask)
{
@@ -124,11 +71,11 @@ u32 rtl8723ae_phy_query_rf_reg(struct ieee80211_hw *hw,
spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
if (rtlphy->rf_mode != RF_OP_BY_FW)
- original_value = _phy_rf_serial_read(hw, rfpath, regaddr);
+ original_value = rtl8723_phy_rf_serial_read(hw, rfpath, regaddr);
else
original_value = _phy_fw_rf_serial_read(hw, rfpath, regaddr);
- bitshift = _phy_calculate_bit_shift(bitmask);
+ bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
readback_value = (original_value & bitmask) >> bitshift;
spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
@@ -157,19 +104,19 @@ void rtl8723ae_phy_set_rf_reg(struct ieee80211_hw *hw,
if (rtlphy->rf_mode != RF_OP_BY_FW) {
if (bitmask != RFREG_OFFSET_MASK) {
- original_value = _phy_rf_serial_read(hw, rfpath,
- regaddr);
- bitshift = _phy_calculate_bit_shift(bitmask);
+ original_value = rtl8723_phy_rf_serial_read(hw, rfpath,
+ regaddr);
+ bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
data = ((original_value & (~bitmask)) |
(data << bitshift));
}
- _phy_rf_serial_write(hw, rfpath, regaddr, data);
+ rtl8723_phy_rf_serial_write(hw, rfpath, regaddr, data);
} else {
if (bitmask != RFREG_OFFSET_MASK) {
original_value = _phy_fw_rf_serial_read(hw, rfpath,
regaddr);
- bitshift = _phy_calculate_bit_shift(bitmask);
+ bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
data = ((original_value & (~bitmask)) |
(data << bitshift));
}
@@ -197,87 +144,6 @@ static void _phy_fw_rf_serial_write(struct ieee80211_hw *hw,
RT_ASSERT(false, "deprecated!\n");
}
-static u32 _phy_rf_serial_read(struct ieee80211_hw *hw,
- enum radio_path rfpath, u32 offset)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_phy *rtlphy = &(rtlpriv->phy);
- struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
- u32 newoffset;
- u32 tmplong, tmplong2;
- u8 rfpi_enable = 0;
- u32 retvalue;
-
- offset &= 0x3f;
- newoffset = offset;
- if (RT_CANNOT_IO(hw)) {
- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "return all one\n");
- return 0xFFFFFFFF;
- }
- tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD);
- if (rfpath == RF90_PATH_A)
- tmplong2 = tmplong;
- else
- tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD);
- tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) |
- (newoffset << 23) | BLSSIREADEDGE;
- rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
- tmplong & (~BLSSIREADEDGE));
- mdelay(1);
- rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2);
- mdelay(1);
- rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
- tmplong | BLSSIREADEDGE);
- mdelay(1);
- if (rfpath == RF90_PATH_A)
- rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1,
- BIT(8));
- else if (rfpath == RF90_PATH_B)
- rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1,
- BIT(8));
- if (rfpi_enable)
- retvalue = rtl_get_bbreg(hw, pphyreg->rf_rbpi,
- BLSSIREADBACKDATA);
- else
- retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb,
- BLSSIREADBACKDATA);
- RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFR-%d Addr[0x%x]=0x%x\n",
- rfpath, pphyreg->rf_rb, retvalue);
- return retvalue;
-}
-
-static void _phy_rf_serial_write(struct ieee80211_hw *hw,
- enum radio_path rfpath, u32 offset, u32 data)
-{
- u32 data_and_addr;
- u32 newoffset;
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_phy *rtlphy = &(rtlpriv->phy);
- struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
-
- if (RT_CANNOT_IO(hw)) {
- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "stop\n");
- return;
- }
- offset &= 0x3f;
- newoffset = offset;
- data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff;
- rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr);
- RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFW-%d Addr[0x%x]=0x%x\n",
- rfpath, pphyreg->rf3wire_offset, data_and_addr);
-}
-
-static u32 _phy_calculate_bit_shift(u32 bitmask)
-{
- u32 i;
-
- for (i = 0; i <= 31; i++) {
- if (((bitmask >> i) & 0x1) == 1)
- break;
- }
- return i;
-}
-
static void _rtl8723ae_phy_bb_config_1t(struct ieee80211_hw *hw)
{
rtl_set_bbreg(hw, RFPGA0_TXINFO, 0x3, 0x2);
@@ -307,7 +173,7 @@ bool rtl8723ae_phy_bb_config(struct ieee80211_hw *hw)
u8 tmpu1b;
u8 reg_hwparafile = 1;
- _phy_init_bb_rf_reg_def(hw);
+ rtl8723_phy_init_bb_rf_reg_def(hw);
/* 1. 0x28[1] = 1 */
tmpu1b = rtl_read_byte(rtlpriv, REG_AFE_PLL_CTRL);
@@ -412,18 +278,7 @@ static bool _phy_cfg_bb_w_header(struct ieee80211_hw *hw, u8 configtype)
phy_regarray_table = RTL8723EPHY_REG_1TARRAY;
if (configtype == BASEBAND_CONFIG_PHY_REG) {
for (i = 0; i < phy_reg_arraylen; i = i + 2) {
- if (phy_regarray_table[i] == 0xfe)
- mdelay(50);
- else if (phy_regarray_table[i] == 0xfd)
- mdelay(5);
- else if (phy_regarray_table[i] == 0xfc)
- mdelay(1);
- else if (phy_regarray_table[i] == 0xfb)
- udelay(50);
- else if (phy_regarray_table[i] == 0xfa)
- udelay(5);
- else if (phy_regarray_table[i] == 0xf9)
- udelay(1);
+ rtl_addr_delay(phy_regarray_table[i]);
rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD,
phy_regarray_table[i + 1]);
udelay(1);
@@ -585,18 +440,7 @@ static bool _phy_cfg_bb_w_pgheader(struct ieee80211_hw *hw, u8 configtype)
if (configtype == BASEBAND_CONFIG_PHY_REG) {
for (i = 0; i < phy_regarray_pg_len; i = i + 3) {
- if (phy_regarray_table_pg[i] == 0xfe)
- mdelay(50);
- else if (phy_regarray_table_pg[i] == 0xfd)
- mdelay(5);
- else if (phy_regarray_table_pg[i] == 0xfc)
- mdelay(1);
- else if (phy_regarray_table_pg[i] == 0xfb)
- udelay(50);
- else if (phy_regarray_table_pg[i] == 0xfa)
- udelay(5);
- else if (phy_regarray_table_pg[i] == 0xf9)
- udelay(1);
+ rtl_addr_delay(phy_regarray_table_pg[i]);
_st_pwrIdx_dfrate_off(hw, phy_regarray_table_pg[i],
phy_regarray_table_pg[i + 1],
@@ -623,24 +467,9 @@ bool rtl8723ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
switch (rfpath) {
case RF90_PATH_A:
for (i = 0; i < radioa_arraylen; i = i + 2) {
- if (radioa_array_table[i] == 0xfe)
- mdelay(50);
- else if (radioa_array_table[i] == 0xfd)
- mdelay(5);
- else if (radioa_array_table[i] == 0xfc)
- mdelay(1);
- else if (radioa_array_table[i] == 0xfb)
- udelay(50);
- else if (radioa_array_table[i] == 0xfa)
- udelay(5);
- else if (radioa_array_table[i] == 0xf9)
- udelay(1);
- else {
- rtl_set_rfreg(hw, rfpath, radioa_array_table[i],
- RFREG_OFFSET_MASK,
- radioa_array_table[i + 1]);
- udelay(1);
- }
+ rtl_rfreg_delay(hw, rfpath, radioa_array_table[i],
+ RFREG_OFFSET_MASK,
+ radioa_array_table[i + 1]);
}
break;
case RF90_PATH_B:
@@ -690,92 +519,6 @@ void rtl8723ae_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
ROFDM0_RXDETECTOR3, rtlphy->framesync);
}
-static void _phy_init_bb_rf_reg_def(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_phy *rtlphy = &(rtlpriv->phy);
-
- rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW;
- rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW;
- rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW;
- rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW;
-
- rtlphy->phyreg_def[RF90_PATH_A].rfintfi = RFPGA0_XAB_RFINTERFACERB;
- rtlphy->phyreg_def[RF90_PATH_B].rfintfi = RFPGA0_XAB_RFINTERFACERB;
- rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB;
- rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB;
-
- rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE;
- rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE;
-
- rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE;
- rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE;
-
- rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset =
- RFPGA0_XA_LSSIPARAMETER;
- rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset =
- RFPGA0_XB_LSSIPARAMETER;
-
- rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = rFPGA0_XAB_RFPARAMETER;
- rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = rFPGA0_XAB_RFPARAMETER;
- rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = rFPGA0_XCD_RFPARAMETER;
- rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = rFPGA0_XCD_RFPARAMETER;
-
- rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE;
- rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE;
- rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE;
- rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE;
-
- rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1;
- rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1;
-
- rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2;
- rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2;
-
- rtlphy->phyreg_def[RF90_PATH_A].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
- rtlphy->phyreg_def[RF90_PATH_B].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
- rtlphy->phyreg_def[RF90_PATH_C].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
- rtlphy->phyreg_def[RF90_PATH_D].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
-
- rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1;
- rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1;
- rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1;
- rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1;
-
- rtlphy->phyreg_def[RF90_PATH_A].rfagc_control2 = ROFDM0_XAAGCCORE2;
- rtlphy->phyreg_def[RF90_PATH_B].rfagc_control2 = ROFDM0_XBAGCCORE2;
- rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2;
- rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2;
-
- rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbal = ROFDM0_XARXIQIMBALANCE;
- rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbal = ROFDM0_XBRXIQIMBALANCE;
- rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbal = ROFDM0_XCRXIQIMBANLANCE;
- rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbal = ROFDM0_XDRXIQIMBALANCE;
-
- rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE;
- rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE;
- rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE;
- rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE;
-
- rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbal = ROFDM0_XATXIQIMBALANCE;
- rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbal = ROFDM0_XBTXIQIMBALANCE;
- rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbal = ROFDM0_XCTXIQIMBALANCE;
- rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbal = ROFDM0_XDTXIQIMBALANCE;
-
- rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE;
- rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTXAFE;
- rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTXAFE;
- rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE;
-
- rtlphy->phyreg_def[RF90_PATH_A].rf_rb = RFPGA0_XA_LSSIREADBACK;
- rtlphy->phyreg_def[RF90_PATH_B].rf_rb = RFPGA0_XB_LSSIREADBACK;
- rtlphy->phyreg_def[RF90_PATH_C].rf_rb = RFPGA0_XC_LSSIREADBACK;
- rtlphy->phyreg_def[RF90_PATH_D].rf_rb = RFPGA0_XD_LSSIREADBACK;
-
- rtlphy->phyreg_def[RF90_PATH_A].rf_rbpi = TRANSCEIVEA_HSPI_READBACK;
- rtlphy->phyreg_def[RF90_PATH_B].rf_rbpi = TRANSCEIVEB_HSPI_READBACK;
-}
-
void rtl8723ae_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -785,17 +528,17 @@ void rtl8723ae_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel)
long txpwr_dbm;
txpwr_level = rtlphy->cur_cck_txpwridx;
- txpwr_dbm = _phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_B, txpwr_level);
+ txpwr_dbm = rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_B, txpwr_level);
txpwr_level = rtlphy->cur_ofdm24g_txpwridx +
rtlefuse->legacy_ht_txpowerdiff;
- if (_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, txpwr_level) > txpwr_dbm)
- txpwr_dbm = _phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G,
+ if (rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, txpwr_level) > txpwr_dbm)
+ txpwr_dbm = rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G,
txpwr_level);
txpwr_level = rtlphy->cur_ofdm24g_txpwridx;
- if (_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, txpwr_level) >
+ if (rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, txpwr_level) >
txpwr_dbm)
- txpwr_dbm = _phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G,
- txpwr_level);
+ txpwr_dbm = rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G,
+ txpwr_level);
*powerlevel = txpwr_dbm;
}
@@ -912,28 +655,6 @@ static u8 _phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw,
return txpwridx;
}
-static long _phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
- enum wireless_mode wirelessmode, u8 txpwridx)
-{
- long offset;
- long pwrout_dbm;
-
- switch (wirelessmode) {
- case WIRELESS_MODE_B:
- offset = -7;
- break;
- case WIRELESS_MODE_G:
- case WIRELESS_MODE_N_24G:
- offset = -8;
- break;
- default:
- offset = -8;
- break;
- }
- pwrout_dbm = txpwridx / 2 + offset;
- return pwrout_dbm;
-}
-
void rtl8723ae_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1117,26 +838,26 @@ static bool _phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, u8 channel,
u8 num_total_rfpath = rtlphy->num_total_rfpath;
precommoncmdcnt = 0;
- _phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
- MAX_PRECMD_CNT, CMDID_SET_TXPOWEROWER_LEVEL,
- 0, 0, 0);
- _phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
- MAX_PRECMD_CNT, CMDID_END, 0, 0, 0);
+ rtl8723_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+ MAX_PRECMD_CNT, CMDID_SET_TXPOWEROWER_LEVEL,
+ 0, 0, 0);
+ rtl8723_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+ MAX_PRECMD_CNT, CMDID_END, 0, 0, 0);
postcommoncmdcnt = 0;
- _phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++,
- MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0);
+ rtl8723_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++,
+ MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0);
rfdependcmdcnt = 0;
RT_ASSERT((channel >= 1 && channel <= 14),
"illegal channel for Zebra: %d\n", channel);
- _phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
- MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG,
+ rtl8723_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+ MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG,
RF_CHNLBW, channel, 10);
- _phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
- MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0, 0);
+ rtl8723_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+ MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0, 0);
do {
switch (*stage) {
@@ -1204,29 +925,6 @@ static bool _phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, u8 channel,
return false;
}
-static bool _phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
- u32 cmdtableidx, u32 cmdtablesz,
- enum swchnlcmd_id cmdid, u32 para1,
- u32 para2, u32 msdelay)
-{
- struct swchnlcmd *pcmd;
-
- if (cmdtable == NULL) {
- RT_ASSERT(false, "cmdtable cannot be NULL.\n");
- return false;
- }
-
- if (cmdtableidx >= cmdtablesz)
- return false;
-
- pcmd = cmdtable + cmdtableidx;
- pcmd->cmdid = cmdid;
- pcmd->para1 = para1;
- pcmd->para2 = para2;
- pcmd->msdelay = msdelay;
- return true;
-}
-
static u8 _rtl8723ae_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb)
{
u32 reg_eac, reg_e94, reg_e9c, reg_ea4;
@@ -1297,136 +995,6 @@ static u8 _rtl8723ae_phy_path_b_iqk(struct ieee80211_hw *hw)
return result;
}
-static void phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw, bool iqk_ok,
- long result[][8], u8 final_candidate,
- bool btxonly)
-{
- u32 oldval_0, x, tx0_a, reg;
- long y, tx0_c;
-
- if (final_candidate == 0xFF) {
- return;
- } else if (iqk_ok) {
- oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
- MASKDWORD) >> 22) & 0x3FF;
- x = result[final_candidate][0];
- if ((x & 0x00000200) != 0)
- x = x | 0xFFFFFC00;
- tx0_a = (x * oldval_0) >> 8;
- rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x3FF, tx0_a);
- rtl_set_bbreg(hw, 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;
- rtl_set_bbreg(hw, ROFDM0_XCTXAFE, 0xF0000000,
- ((tx0_c & 0x3C0) >> 6));
- rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x003F0000,
- (tx0_c & 0x3F));
- rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(29),
- ((y * oldval_0 >> 7) & 0x1));
- if (btxonly)
- return;
- reg = result[final_candidate][2];
- rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0x3FF, reg);
- reg = result[final_candidate][3] & 0x3F;
- rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0xFC00, reg);
- reg = (result[final_candidate][3] >> 6) & 0xF;
- rtl_set_bbreg(hw, 0xca0, 0xF0000000, reg);
- }
-}
-
-static void phy_save_adda_regs(struct ieee80211_hw *hw,
- u32 *addareg, u32 *addabackup,
- u32 registernum)
-{
- u32 i;
-
- for (i = 0; i < registernum; i++)
- addabackup[i] = rtl_get_bbreg(hw, addareg[i], MASKDWORD);
-}
-
-static void phy_save_mac_regs(struct ieee80211_hw *hw, u32 *macreg,
- u32 *macbackup)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 i;
-
- for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++)
- macbackup[i] = rtl_read_byte(rtlpriv, macreg[i]);
- macbackup[i] = rtl_read_dword(rtlpriv, macreg[i]);
-}
-
-static void phy_reload_adda_regs(struct ieee80211_hw *hw, u32 *addareg,
- u32 *addabackup, u32 regiesternum)
-{
- u32 i;
-
- for (i = 0; i < regiesternum; i++)
- rtl_set_bbreg(hw, addareg[i], MASKDWORD, addabackup[i]);
-}
-
-static void phy_reload_mac_regs(struct ieee80211_hw *hw, u32 *macreg,
- u32 *macbackup)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 i;
-
- for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++)
- rtl_write_byte(rtlpriv, macreg[i], (u8) macbackup[i]);
- rtl_write_dword(rtlpriv, macreg[i], macbackup[i]);
-}
-
-static void _rtl8723ae_phy_path_adda_on(struct ieee80211_hw *hw,
- u32 *addareg, bool is_patha_on,
- bool is2t)
-{
- u32 pathOn;
- u32 i;
-
- pathOn = is_patha_on ? 0x04db25a4 : 0x0b1b25a4;
- if (false == is2t) {
- pathOn = 0x0bdb25a0;
- rtl_set_bbreg(hw, addareg[0], MASKDWORD, 0x0b1b25a0);
- } else {
- rtl_set_bbreg(hw, addareg[0], MASKDWORD, pathOn);
- }
-
- for (i = 1; i < IQK_ADDA_REG_NUM; i++)
- rtl_set_bbreg(hw, addareg[i], MASKDWORD, pathOn);
-}
-
-static void _rtl8723ae_phy_mac_setting_calibration(struct ieee80211_hw *hw,
- u32 *macreg, u32 *macbackup)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 i = 0;
-
- rtl_write_byte(rtlpriv, macreg[i], 0x3F);
-
- for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++)
- rtl_write_byte(rtlpriv, macreg[i],
- (u8) (macbackup[i] & (~BIT(3))));
- rtl_write_byte(rtlpriv, macreg[i], (u8) (macbackup[i] & (~BIT(5))));
-}
-
-static void _rtl8723ae_phy_path_a_standby(struct ieee80211_hw *hw)
-{
- rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x0);
- rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000);
- rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
-}
-
-static void _rtl8723ae_phy_pi_mode_switch(struct ieee80211_hw *hw, bool pi_mode)
-{
- u32 mode;
-
- mode = pi_mode ? 0x01000100 : 0x01000000;
- rtl_set_bbreg(hw, 0x820, MASKDWORD, mode);
- rtl_set_bbreg(hw, 0x828, MASKDWORD, mode);
-}
-
static bool phy_simularity_comp(struct ieee80211_hw *hw, long result[][8],
u8 c1, u8 c2)
{
@@ -1498,10 +1066,12 @@ static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw,
const u32 retrycount = 2;
if (t == 0) {
- phy_save_adda_regs(hw, adda_reg, rtlphy->adda_backup, 16);
- phy_save_mac_regs(hw, iqk_mac_reg, rtlphy->iqk_mac_backup);
+ rtl8723_save_adda_registers(hw, adda_reg, rtlphy->adda_backup,
+ 16);
+ rtl8723_phy_save_mac_registers(hw, iqk_mac_reg,
+ rtlphy->iqk_mac_backup);
}
- _rtl8723ae_phy_path_adda_on(hw, adda_reg, true, is2t);
+ rtl8723_phy_path_adda_on(hw, adda_reg, true, is2t);
if (t == 0) {
rtlphy->rfpi_enable = (u8) rtl_get_bbreg(hw,
RFPGA0_XA_HSSIPARAMETER1,
@@ -1509,7 +1079,7 @@ static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw,
}
if (!rtlphy->rfpi_enable)
- _rtl8723ae_phy_pi_mode_switch(hw, true);
+ rtl8723_phy_pi_mode_switch(hw, true);
if (t == 0) {
rtlphy->reg_c04 = rtl_get_bbreg(hw, 0xc04, MASKDWORD);
rtlphy->reg_c08 = rtl_get_bbreg(hw, 0xc08, MASKDWORD);
@@ -1522,7 +1092,7 @@ static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw,
rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000);
rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00010000);
}
- _rtl8723ae_phy_mac_setting_calibration(hw, iqk_mac_reg,
+ rtl8723_phy_mac_setting_calibration(hw, iqk_mac_reg,
rtlphy->iqk_mac_backup);
rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x00080000);
if (is2t)
@@ -1552,8 +1122,8 @@ static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw,
}
if (is2t) {
- _rtl8723ae_phy_path_a_standby(hw);
- _rtl8723ae_phy_path_adda_on(hw, adda_reg, false, is2t);
+ rtl8723_phy_path_a_standby(hw);
+ rtl8723_phy_path_adda_on(hw, adda_reg, false, is2t);
for (i = 0; i < retrycount; i++) {
pathb_ok = _rtl8723ae_phy_path_b_iqk(hw);
if (pathb_ok == 0x03) {
@@ -1588,9 +1158,11 @@ static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw,
rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00032ed3);
if (t != 0) {
if (!rtlphy->rfpi_enable)
- _rtl8723ae_phy_pi_mode_switch(hw, false);
- phy_reload_adda_regs(hw, adda_reg, rtlphy->adda_backup, 16);
- phy_reload_mac_regs(hw, iqk_mac_reg, rtlphy->iqk_mac_backup);
+ rtl8723_phy_pi_mode_switch(hw, false);
+ rtl8723_phy_reload_adda_registers(hw, adda_reg,
+ rtlphy->adda_backup, 16);
+ rtl8723_phy_reload_mac_registers(hw, iqk_mac_reg,
+ rtlphy->iqk_mac_backup);
}
}
@@ -1691,7 +1263,8 @@ void rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery)
};
if (recovery) {
- phy_reload_adda_regs(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 10);
+ rtl8723_phy_reload_adda_registers(hw, iqk_bb_reg,
+ rtlphy->iqk_bb_backup, 10);
return;
}
if (start_conttx || singletone)
@@ -1756,9 +1329,10 @@ void rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery)
rtlphy->reg_e9c = rtlphy->reg_ebc = 0x0;
}
if (reg_e94 != 0) /*&&(reg_ea4 != 0) */
- phy_path_a_fill_iqk_matrix(hw, patha_ok, result,
- final_candidate, (reg_ea4 == 0));
- phy_save_adda_regs(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 10);
+ rtl8723_phy_path_a_fill_iqk_matrix(hw, patha_ok, result,
+ final_candidate,
+ (reg_ea4 == 0));
+ rtl8723_save_adda_registers(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 10);
}
void rtl8723ae_phy_lc_calibrate(struct ieee80211_hw *hw)
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.h b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.h
index 007ebdbbe108..cd43139ed332 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.h
@@ -76,23 +76,6 @@
#define RTL92C_MAX_PATH_NUM 2
-enum swchnlcmd_id {
- CMDID_END,
- CMDID_SET_TXPOWEROWER_LEVEL,
- CMDID_BBREGWRITE10,
- CMDID_WRITEPORT_ULONG,
- CMDID_WRITEPORT_USHORT,
- CMDID_WRITEPORT_UCHAR,
- CMDID_RF_WRITEREG,
-};
-
-struct swchnlcmd {
- enum swchnlcmd_id cmdid;
- u32 para1;
- u32 para2;
- u32 msdelay;
-};
-
enum hw90_block_e {
HW90_BLOCK_MAC = 0,
HW90_BLOCK_PHY0 = 1,
@@ -183,10 +166,6 @@ struct tx_power_struct {
u32 mcs_original_offset[4][16];
};
-u32 rtl8723ae_phy_query_bb_reg(struct ieee80211_hw *hw,
- u32 regaddr, u32 bitmask);
-void rtl8723ae_phy_set_bb_reg(struct ieee80211_hw *hw,
- u32 regaddr, u32 bitmask, u32 data);
u32 rtl8723ae_phy_query_rf_reg(struct ieee80211_hw *hw,
enum radio_path rfpath, u32 regaddr,
u32 bitmask);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h
index 7a46f9fdf558..a418acb4d0ca 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h
@@ -30,7 +30,6 @@
#ifndef __RTL8723E_PWRSEQ_H__
#define __RTL8723E_PWRSEQ_H__
-#include "pwrseqcmd.h"
/*
Check document WM-20110607-Paul-RTL8723A_Power_Architecture-R02.vsd
There are 6 HW Power States:
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h b/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h
index 199da366c6da..64376b38708b 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h
@@ -2059,22 +2059,6 @@
#define BWORD1 0xc
#define BWORD 0xf
-#define MASKBYTE0 0xff
-#define MASKBYTE1 0xff00
-#define MASKBYTE2 0xff0000
-#define MASKBYTE3 0xff000000
-#define MASKHWORD 0xffff0000
-#define MASKLWORD 0x0000ffff
-#define MASKDWORD 0xffffffff
-#define MASK12BITS 0xfff
-#define MASKH4BITS 0xf0000000
-#define MASKOFDM_D 0xffc00000
-#define MASKCCK 0x3f3f3f3f
-
-#define MASK4BITS 0x0f
-#define MASK20BITS 0xfffff
-#define RFREG_OFFSET_MASK 0xfffff
-
#define BENABLE 0x1
#define BDISABLE 0x0
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c
index 62b204faf773..1087a3bd07fa 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c
@@ -37,8 +37,11 @@
#include "reg.h"
#include "def.h"
#include "phy.h"
+#include "../rtl8723com/phy_common.h"
#include "dm.h"
#include "hw.h"
+#include "fw.h"
+#include "../rtl8723com/fw_common.h"
#include "sw.h"
#include "trx.h"
#include "led.h"
@@ -193,6 +196,11 @@ void rtl8723ae_deinit_sw_vars(struct ieee80211_hw *hw)
}
}
+static bool is_fw_header(struct rtl92c_firmware_header *hdr)
+{
+ return (hdr->signature & 0xfff0) == 0x2300;
+}
+
static struct rtl_hal_ops rtl8723ae_hal_ops = {
.init_sw_vars = rtl8723ae_init_sw_vars,
.deinit_sw_vars = rtl8723ae_deinit_sw_vars,
@@ -231,13 +239,14 @@ static struct rtl_hal_ops rtl8723ae_hal_ops = {
.set_key = rtl8723ae_set_key,
.init_sw_leds = rtl8723ae_init_sw_leds,
.allow_all_destaddr = rtl8723ae_allow_all_destaddr,
- .get_bbreg = rtl8723ae_phy_query_bb_reg,
- .set_bbreg = rtl8723ae_phy_set_bb_reg,
+ .get_bbreg = rtl8723_phy_query_bb_reg,
+ .set_bbreg = rtl8723_phy_set_bb_reg,
.get_rfreg = rtl8723ae_phy_query_rf_reg,
.set_rfreg = rtl8723ae_phy_set_rf_reg,
.c2h_command_handle = rtl_8723e_c2h_command_handle,
.bt_wifi_media_status_notify = rtl_8723e_bt_wifi_media_status_notify,
.bt_coex_off_before_lps = rtl8723ae_bt_coex_off_before_lps,
+ .is_fw_header = is_fw_header,
};
static struct rtl_mod_params rtl8723ae_mod_params = {
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
index 50b7be3f3a60..10b7577b6ae5 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
@@ -334,7 +334,7 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw,
/* during testing, hdr could be NULL here */
return false;
}
- if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
+ if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
(ieee80211_has_protected(hdr->frame_control)))
rx_status->flag &= ~RX_FLAG_DECRYPTED;
else
@@ -365,7 +365,7 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw,
void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr, u8 *pdesc_tx,
- struct ieee80211_tx_info *info,
+ u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
struct ieee80211_sta *sta,
struct sk_buff *skb, u8 hw_queue,
struct rtl_tcb_desc *ptcdesc)
@@ -375,7 +375,7 @@ void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw,
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
bool defaultadapter = true;
- u8 *pdesc = (u8 *) pdesc_tx;
+ u8 *pdesc = pdesc_tx;
u16 seq_number;
__le16 fc = hdr->frame_control;
u8 fw_qsel = _rtl8723ae_map_hwqueue_to_fwqueue(skb, hw_queue);
@@ -577,7 +577,7 @@ void rtl8723ae_tx_fill_cmddesc(struct ieee80211_hw *hw,
SET_TX_DESC_OWN(pdesc, 1);
- SET_TX_DESC_PKT_SIZE((u8 *) pdesc, (u16) (skb->len));
+ SET_TX_DESC_PKT_SIZE(pdesc, (u16) (skb->len));
SET_TX_DESC_FIRST_SEG(pdesc, 1);
SET_TX_DESC_LAST_SEG(pdesc, 1);
@@ -597,7 +597,8 @@ void rtl8723ae_tx_fill_cmddesc(struct ieee80211_hw *hw,
pdesc, TX_DESC_SIZE);
}
-void rtl8723ae_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
+void rtl8723ae_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+ u8 desc_name, u8 *val)
{
if (istx == true) {
switch (desc_name) {
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h
index ad05b54bc0f1..4380b7d3a91a 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h
@@ -521,12 +521,6 @@ do { \
memset(__pdesc, 0, _size); \
} while (0)
-#define RTL8723E_RX_HAL_IS_CCK_RATE(rxmcs) \
- ((rxmcs) == DESC92_RATE1M || \
- (rxmcs) == DESC92_RATE2M || \
- (rxmcs) == DESC92_RATE5_5M || \
- (rxmcs) == DESC92_RATE11M)
-
struct rx_fwinfo_8723e {
u8 gain_trsw[4];
u8 pwdb_all;
@@ -706,8 +700,8 @@ struct rx_desc_8723e {
} __packed;
void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw,
- struct ieee80211_hdr *hdr, u8 *pdesc_tx,
- struct ieee80211_tx_info *info,
+ struct ieee80211_hdr *hdr, u8 *pdesc,
+ u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
struct ieee80211_sta *sta,
struct sk_buff *skb, u8 hw_queue,
struct rtl_tcb_desc *ptcb_desc);
@@ -715,7 +709,8 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw,
struct rtl_stats *status,
struct ieee80211_rx_status *rx_status,
u8 *pdesc, struct sk_buff *skb);
-void rtl8723ae_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val);
+void rtl8723ae_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+ u8 desc_name, u8 *val);
u32 rtl8723ae_get_desc(u8 *pdesc, bool istx, u8 desc_name);
void rtl8723ae_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
void rtl8723ae_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/Makefile b/drivers/net/wireless/rtlwifi/rtl8723be/Makefile
new file mode 100644
index 000000000000..59e416abd93a
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/Makefile
@@ -0,0 +1,19 @@
+obj-m := rtl8723be.o
+
+
+rtl8723be-objs := \
+ dm.o \
+ fw.o \
+ hw.o \
+ led.o \
+ phy.o \
+ pwrseq.o \
+ rf.o \
+ sw.o \
+ table.o \
+ trx.o \
+
+
+obj-$(CONFIG_RTL8723BE) += rtl8723be.o
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/def.h b/drivers/net/wireless/rtlwifi/rtl8723be/def.h
new file mode 100644
index 000000000000..3c30b74e983d
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/def.h
@@ -0,0 +1,248 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_DEF_H__
+#define __RTL8723BE_DEF_H__
+
+#define HAL_RETRY_LIMIT_INFRA 48
+#define HAL_RETRY_LIMIT_AP_ADHOC 7
+
+#define RESET_DELAY_8185 20
+
+#define RT_IBSS_INT_MASKS (IMR_BCNINT | IMR_TBDOK | IMR_TBDER)
+#define RT_AC_INT_MASKS (IMR_VIDOK | IMR_VODOK | IMR_BEDOK|IMR_BKDOK)
+
+#define NUM_OF_FIRMWARE_QUEUE 10
+#define NUM_OF_PAGES_IN_FW 0x100
+#define NUM_OF_PAGE_IN_FW_QUEUE_BK 0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_BE 0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_VI 0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_VO 0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_HCCA 0x0
+#define NUM_OF_PAGE_IN_FW_QUEUE_CMD 0x0
+#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT 0x02
+#define NUM_OF_PAGE_IN_FW_QUEUE_HIGH 0x02
+#define NUM_OF_PAGE_IN_FW_QUEUE_BCN 0x2
+#define NUM_OF_PAGE_IN_FW_QUEUE_PUB 0xA1
+
+#define NUM_OF_PAGE_IN_FW_QUEUE_BK_DTM 0x026
+#define NUM_OF_PAGE_IN_FW_QUEUE_BE_DTM 0x048
+#define NUM_OF_PAGE_IN_FW_QUEUE_VI_DTM 0x048
+#define NUM_OF_PAGE_IN_FW_QUEUE_VO_DTM 0x026
+#define NUM_OF_PAGE_IN_FW_QUEUE_PUB_DTM 0x00
+
+#define MAX_LINES_HWCONFIG_TXT 1000
+#define MAX_BYTES_LINE_HWCONFIG_TXT 256
+
+#define SW_THREE_WIRE 0
+#define HW_THREE_WIRE 2
+
+#define BT_DEMO_BOARD 0
+#define BT_QA_BOARD 1
+#define BT_FPGA 2
+
+#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0
+#define HAL_PRIME_CHNL_OFFSET_LOWER 1
+#define HAL_PRIME_CHNL_OFFSET_UPPER 2
+
+#define MAX_H2C_QUEUE_NUM 10
+
+#define RX_MPDU_QUEUE 0
+#define RX_CMD_QUEUE 1
+#define RX_MAX_QUEUE 2
+#define AC2QUEUEID(_AC) (_AC)
+
+#define C2H_RX_CMD_HDR_LEN 8
+#define GET_C2H_CMD_CMD_LEN(__prxhdr) \
+ LE_BITS_TO_4BYTE((__prxhdr), 0, 16)
+#define GET_C2H_CMD_ELEMENT_ID(__prxhdr) \
+ LE_BITS_TO_4BYTE((__prxhdr), 16, 8)
+#define GET_C2H_CMD_CMD_SEQ(__prxhdr) \
+ LE_BITS_TO_4BYTE((__prxhdr), 24, 7)
+#define GET_C2H_CMD_CONTINUE(__prxhdr) \
+ LE_BITS_TO_4BYTE((__prxhdr), 31, 1)
+#define GET_C2H_CMD_CONTENT(__prxhdr) \
+ ((u8 *)(__prxhdr) + C2H_RX_CMD_HDR_LEN)
+
+#define GET_C2H_CMD_FEEDBACK_ELEMENT_ID(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE((__pcmdfbhdr), 0, 8)
+#define GET_C2H_CMD_FEEDBACK_CCX_LEN(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE((__pcmdfbhdr), 8, 8)
+#define GET_C2H_CMD_FEEDBACK_CCX_CMD_CNT(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE((__pcmdfbhdr), 16, 16)
+#define GET_C2H_CMD_FEEDBACK_CCX_MAC_ID(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 0, 5)
+#define GET_C2H_CMD_FEEDBACK_CCX_VALID(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 7, 1)
+#define GET_C2H_CMD_FEEDBACK_CCX_RETRY_CNT(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 8, 5)
+#define GET_C2H_CMD_FEEDBACK_CCX_TOK(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 15, 1)
+#define GET_C2H_CMD_FEEDBACK_CCX_QSEL(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 16, 4)
+#define GET_C2H_CMD_FEEDBACK_CCX_SEQ(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12)
+
+#define CHIP_BONDING_IDENTIFIER(_value) (((_value)>>22)&0x3)
+#define CHIP_BONDING_92C_1T2R 0x1
+
+#define CHIP_8723 BIT(0)
+#define CHIP_8723B (BIT(1) | BIT(2))
+#define NORMAL_CHIP BIT(3)
+#define RF_TYPE_1T1R (~(BIT(4) | BIT(5) | BIT(6)))
+#define RF_TYPE_1T2R BIT(4)
+#define RF_TYPE_2T2R BIT(5)
+#define CHIP_VENDOR_UMC BIT(7)
+#define B_CUT_VERSION BIT(12)
+#define C_CUT_VERSION BIT(13)
+#define D_CUT_VERSION ((BIT(12) | BIT(13)))
+#define E_CUT_VERSION BIT(14)
+#define RF_RL_ID (BIT(31) | BIT(30) | BIT(29) | BIT(28))
+
+/* MASK */
+#define IC_TYPE_MASK (BIT(0) | BIT(1) | BIT(2))
+#define CHIP_TYPE_MASK BIT(3)
+#define RF_TYPE_MASK (BIT(4) | BIT(5) | BIT(6))
+#define MANUFACTUER_MASK BIT(7)
+#define ROM_VERSION_MASK (BIT(11) | BIT(10) | BIT(9) | BIT(8))
+#define CUT_VERSION_MASK (BIT(15) | BIT(14) | BIT(13) | BIT(12))
+
+/* Get element */
+#define GET_CVID_IC_TYPE(version) ((version) & IC_TYPE_MASK)
+#define GET_CVID_CHIP_TYPE(version) ((version) & CHIP_TYPE_MASK)
+#define GET_CVID_RF_TYPE(version) ((version) & RF_TYPE_MASK)
+#define GET_CVID_MANUFACTUER(version) ((version) & MANUFACTUER_MASK)
+#define GET_CVID_ROM_VERSION(version) ((version) & ROM_VERSION_MASK)
+#define GET_CVID_CUT_VERSION(version) ((version) & CUT_VERSION_MASK)
+
+#define IS_92C_SERIAL(version) ((IS_81XXC(version) && IS_2T2R(version)) ?\
+ true : false)
+#define IS_81XXC(version) ((GET_CVID_IC_TYPE(version) == 0) ?\
+ true : false)
+#define IS_8723_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8723) ?\
+ true : false)
+#define IS_1T1R(version) ((GET_CVID_RF_TYPE(version)) ? false : true)
+#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)
+enum rf_optype {
+ RF_OP_BY_SW_3WIRE = 0,
+ RF_OP_BY_FW,
+ RF_OP_MAX
+};
+
+enum rf_power_state {
+ RF_ON,
+ RF_OFF,
+ RF_SLEEP,
+ RF_SHUT_DOWN,
+};
+
+enum power_save_mode {
+ POWER_SAVE_MODE_ACTIVE,
+ POWER_SAVE_MODE_SAVE,
+};
+
+enum power_polocy_config {
+ POWERCFG_MAX_POWER_SAVINGS,
+ POWERCFG_GLOBAL_POWER_SAVINGS,
+ POWERCFG_LOCAL_POWER_SAVINGS,
+ POWERCFG_LENOVO,
+};
+
+enum interface_select_pci {
+ INTF_SEL1_MINICARD = 0,
+ INTF_SEL0_PCIE = 1,
+ INTF_SEL2_RSV = 2,
+ INTF_SEL3_RSV = 3,
+};
+
+enum rtl_desc_qsel {
+ QSLT_BK = 0x2,
+ QSLT_BE = 0x0,
+ QSLT_VI = 0x5,
+ QSLT_VO = 0x7,
+ QSLT_BEACON = 0x10,
+ QSLT_HIGH = 0x11,
+ QSLT_MGNT = 0x12,
+ QSLT_CMD = 0x13,
+};
+
+enum rtl_desc8723e_rate {
+ DESC92C_RATE1M = 0x00,
+ DESC92C_RATE2M = 0x01,
+ DESC92C_RATE5_5M = 0x02,
+ DESC92C_RATE11M = 0x03,
+
+ DESC92C_RATE6M = 0x04,
+ DESC92C_RATE9M = 0x05,
+ DESC92C_RATE12M = 0x06,
+ DESC92C_RATE18M = 0x07,
+ DESC92C_RATE24M = 0x08,
+ DESC92C_RATE36M = 0x09,
+ DESC92C_RATE48M = 0x0a,
+ DESC92C_RATE54M = 0x0b,
+
+ DESC92C_RATEMCS0 = 0x0c,
+ DESC92C_RATEMCS1 = 0x0d,
+ DESC92C_RATEMCS2 = 0x0e,
+ DESC92C_RATEMCS3 = 0x0f,
+ DESC92C_RATEMCS4 = 0x10,
+ DESC92C_RATEMCS5 = 0x11,
+ DESC92C_RATEMCS6 = 0x12,
+ DESC92C_RATEMCS7 = 0x13,
+ DESC92C_RATEMCS8 = 0x14,
+ DESC92C_RATEMCS9 = 0x15,
+ DESC92C_RATEMCS10 = 0x16,
+ DESC92C_RATEMCS11 = 0x17,
+ DESC92C_RATEMCS12 = 0x18,
+ DESC92C_RATEMCS13 = 0x19,
+ DESC92C_RATEMCS14 = 0x1a,
+ DESC92C_RATEMCS15 = 0x1b,
+ DESC92C_RATEMCS15_SG = 0x1c,
+ DESC92C_RATEMCS32 = 0x20,
+};
+
+enum rx_packet_type {
+ NORMAL_RX,
+ TX_REPORT1,
+ TX_REPORT2,
+ HIS_REPORT,
+};
+
+struct phy_sts_cck_8723e_t {
+ u8 adc_pwdb_X[4];
+ u8 sq_rpt;
+ u8 cck_agc_rpt;
+};
+
+struct h2c_cmd_8723e {
+ u8 element_id;
+ u32 cmd_len;
+ u8 *p_cmdbuffer;
+};
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c
new file mode 100644
index 000000000000..13d53a1df789
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c
@@ -0,0 +1,1325 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../base.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "../rtl8723com/dm_common.h"
+#include "fw.h"
+#include "../rtl8723com/fw_common.h"
+#include "trx.h"
+#include "../btcoexist/rtl_btc.h"
+
+static const u32 ofdmswing_table[] = {
+ 0x0b40002d, /* 0, -15.0dB */
+ 0x0c000030, /* 1, -14.5dB */
+ 0x0cc00033, /* 2, -14.0dB */
+ 0x0d800036, /* 3, -13.5dB */
+ 0x0e400039, /* 4, -13.0dB */
+ 0x0f00003c, /* 5, -12.5dB */
+ 0x10000040, /* 6, -12.0dB */
+ 0x11000044, /* 7, -11.5dB */
+ 0x12000048, /* 8, -11.0dB */
+ 0x1300004c, /* 9, -10.5dB */
+ 0x14400051, /* 10, -10.0dB */
+ 0x15800056, /* 11, -9.5dB */
+ 0x16c0005b, /* 12, -9.0dB */
+ 0x18000060, /* 13, -8.5dB */
+ 0x19800066, /* 14, -8.0dB */
+ 0x1b00006c, /* 15, -7.5dB */
+ 0x1c800072, /* 16, -7.0dB */
+ 0x1e400079, /* 17, -6.5dB */
+ 0x20000080, /* 18, -6.0dB */
+ 0x22000088, /* 19, -5.5dB */
+ 0x24000090, /* 20, -5.0dB */
+ 0x26000098, /* 21, -4.5dB */
+ 0x288000a2, /* 22, -4.0dB */
+ 0x2ac000ab, /* 23, -3.5dB */
+ 0x2d4000b5, /* 24, -3.0dB */
+ 0x300000c0, /* 25, -2.5dB */
+ 0x32c000cb, /* 26, -2.0dB */
+ 0x35c000d7, /* 27, -1.5dB */
+ 0x390000e4, /* 28, -1.0dB */
+ 0x3c8000f2, /* 29, -0.5dB */
+ 0x40000100, /* 30, +0dB */
+ 0x43c0010f, /* 31, +0.5dB */
+ 0x47c0011f, /* 32, +1.0dB */
+ 0x4c000130, /* 33, +1.5dB */
+ 0x50800142, /* 34, +2.0dB */
+ 0x55400155, /* 35, +2.5dB */
+ 0x5a400169, /* 36, +3.0dB */
+ 0x5fc0017f, /* 37, +3.5dB */
+ 0x65400195, /* 38, +4.0dB */
+ 0x6b8001ae, /* 39, +4.5dB */
+ 0x71c001c7, /* 40, +5.0dB */
+ 0x788001e2, /* 41, +5.5dB */
+ 0x7f8001fe /* 42, +6.0dB */
+};
+
+static const u8 cckswing_table_ch1ch13[CCK_TABLE_SIZE][8] = {
+ {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01}, /* 0, -16.0dB */
+ {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /* 1, -15.5dB */
+ {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 2, -15.0dB */
+ {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 3, -14.5dB */
+ {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 4, -14.0dB */
+ {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 5, -13.5dB */
+ {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /* 6, -13.0dB */
+ {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /* 7, -12.5dB */
+ {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /* 8, -12.0dB */
+ {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /* 9, -11.5dB */
+ {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 10, -11.0dB */
+ {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 11, -10.5dB */
+ {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 12, -10.0dB */
+ {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 13, -9.5dB */
+ {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /* 14, -9.0dB */
+ {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /* 15, -8.5dB */
+ {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /* 16, -8.0dB */
+ {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /* 17, -7.5dB */
+ {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /* 18, -7.0dB */
+ {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /* 19, -6.5dB */
+ {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /* 20, -6.0dB */
+ {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /* 21, -5.5dB */
+ {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /* 22, -5.0dB */
+ {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /* 23, -4.5dB */
+ {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /* 24, -4.0dB */
+ {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /* 25, -3.5dB */
+ {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /* 26, -3.0dB */
+ {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /* 27, -2.5dB */
+ {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /* 28, -2.0dB */
+ {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /* 29, -1.5dB */
+ {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /* 30, -1.0dB */
+ {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /* 31, -0.5dB */
+ {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04} /* 32, +0dB */
+};
+
+static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = {
+ {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00}, /* 0, -16.0dB */
+ {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 1, -15.5dB */
+ {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 2, -15.0dB */
+ {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 3, -14.5dB */
+ {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 4, -14.0dB */
+ {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 5, -13.5dB */
+ {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 6, -13.0dB */
+ {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 7, -12.5dB */
+ {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 8, -12.0dB */
+ {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 9, -11.5dB */
+ {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 10, -11.0dB */
+ {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 11, -10.5dB */
+ {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 12, -10.0dB */
+ {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 13, -9.5dB */
+ {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 14, -9.0dB */
+ {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 15, -8.5dB */
+ {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 16, -8.0dB */
+ {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 17, -7.5dB */
+ {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /* 18, -7.0dB */
+ {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /* 19, -6.5dB */
+ {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 20, -6.0dB */
+ {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 21, -5.5dB */
+ {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /* 22, -5.0dB */
+ {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /* 23, -4.5dB */
+ {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /* 24, -4.0dB */
+ {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /* 25, -3.5dB */
+ {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /* 26, -3.0dB */
+ {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /* 27, -2.5dB */
+ {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /* 28, -2.0dB */
+ {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /* 29, -1.5dB */
+ {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /* 30, -1.0dB */
+ {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /* 31, -0.5dB */
+ {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00} /* 32, +0dB */
+};
+
+static const u32 edca_setting_dl[PEER_MAX] = {
+ 0xa44f, /* 0 UNKNOWN */
+ 0x5ea44f, /* 1 REALTEK_90 */
+ 0x5e4322, /* 2 REALTEK_92SE */
+ 0x5ea42b, /* 3 BROAD */
+ 0xa44f, /* 4 RAL */
+ 0xa630, /* 5 ATH */
+ 0x5ea630, /* 6 CISCO */
+ 0x5ea42b, /* 7 MARVELL */
+};
+
+static const u32 edca_setting_ul[PEER_MAX] = {
+ 0x5e4322, /* 0 UNKNOWN */
+ 0xa44f, /* 1 REALTEK_90 */
+ 0x5ea44f, /* 2 REALTEK_92SE */
+ 0x5ea32b, /* 3 BROAD */
+ 0x5ea422, /* 4 RAL */
+ 0x5ea322, /* 5 ATH */
+ 0x3ea430, /* 6 CISCO */
+ 0x5ea44f, /* 7 MARV */
+};
+
+void rtl8723be_dm_txpower_track_adjust(struct ieee80211_hw *hw, u8 type,
+ u8 *pdirection, u32 *poutwrite_val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ u8 pwr_val = 0;
+ u8 ofdm_base = rtlpriv->dm.swing_idx_ofdm_base[RF90_PATH_A];
+ u8 ofdm_val = rtlpriv->dm.swing_idx_ofdm[RF90_PATH_A];
+ u8 cck_base = rtldm->swing_idx_cck_base;
+ u8 cck_val = rtldm->swing_idx_cck;
+
+ if (type == 0) {
+ if (ofdm_val <= ofdm_base) {
+ *pdirection = 1;
+ pwr_val = ofdm_base - ofdm_val;
+ } else {
+ *pdirection = 2;
+ pwr_val = ofdm_val - ofdm_base;
+ }
+ } else if (type == 1) {
+ if (cck_val <= cck_base) {
+ *pdirection = 1;
+ pwr_val = cck_base - cck_val;
+ } else {
+ *pdirection = 2;
+ pwr_val = cck_val - cck_base;
+ }
+ }
+
+ if (pwr_val >= TXPWRTRACK_MAX_IDX && (*pdirection == 1))
+ pwr_val = TXPWRTRACK_MAX_IDX;
+
+ *poutwrite_val = pwr_val | (pwr_val << 8) |
+ (pwr_val << 16) | (pwr_val << 24);
+}
+
+static void rtl8723be_dm_diginit(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+
+ dm_digtable->dig_enable_flag = true;
+ dm_digtable->cur_igvalue = rtl_get_bbreg(hw,
+ ROFDM0_XAAGCCORE1, 0x7f);
+ dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW;
+ dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
+ dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
+ dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
+ dm_digtable->rx_gain_max = DM_DIG_MAX;
+ dm_digtable->rx_gain_min = DM_DIG_MIN;
+ dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
+ dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX;
+ dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN;
+ dm_digtable->pre_cck_cca_thres = 0xff;
+ dm_digtable->cur_cck_cca_thres = 0x83;
+ dm_digtable->forbidden_igi = DM_DIG_MIN;
+ dm_digtable->large_fa_hit = 0;
+ dm_digtable->recover_cnt = 0;
+ dm_digtable->dig_min_0 = DM_DIG_MIN;
+ dm_digtable->dig_min_1 = DM_DIG_MIN;
+ dm_digtable->media_connect_0 = false;
+ dm_digtable->media_connect_1 = false;
+ rtlpriv->dm.dm_initialgain_enable = true;
+ dm_digtable->bt30_cur_igi = 0x32;
+}
+
+void rtl8723be_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rate_adaptive *ra = &(rtlpriv->ra);
+
+ ra->ratr_state = DM_RATR_STA_INIT;
+ ra->pre_ratr_state = DM_RATR_STA_INIT;
+
+ if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER)
+ rtlpriv->dm.useramask = true;
+ else
+ rtlpriv->dm.useramask = false;
+
+ ra->high_rssi_thresh_for_ra = 50;
+ ra->low_rssi_thresh_for_ra40m = 20;
+}
+
+static void rtl8723be_dm_init_txpower_tracking(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.txpower_tracking = true;
+ rtlpriv->dm.txpower_track_control = true;
+ rtlpriv->dm.thermalvalue = 0;
+
+ rtlpriv->dm.ofdm_index[0] = 30;
+ rtlpriv->dm.cck_index = 20;
+
+ rtlpriv->dm.swing_idx_cck_base = rtlpriv->dm.cck_index;
+
+ rtlpriv->dm.swing_idx_ofdm_base[0] = rtlpriv->dm.ofdm_index[0];
+ rtlpriv->dm.delta_power_index[RF90_PATH_A] = 0;
+ rtlpriv->dm.delta_power_index_last[RF90_PATH_A] = 0;
+ rtlpriv->dm.power_index_offset[RF90_PATH_A] = 0;
+
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ " rtlpriv->dm.txpower_tracking = %d\n",
+ rtlpriv->dm.txpower_tracking);
+}
+
+static void rtl8723be_dm_init_dynamic_atc_switch(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.crystal_cap = rtlpriv->efuse.crystalcap;
+ rtlpriv->dm.atc_status = rtl_get_bbreg(hw, ROFDM1_CFOTRACKING, 0x800);
+ rtlpriv->dm.cfo_threshold = CFO_THRESHOLD_XTAL;
+}
+
+void rtl8723be_dm_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
+ rtl8723be_dm_diginit(hw);
+ rtl8723be_dm_init_rate_adaptive_mask(hw);
+ rtl8723_dm_init_edca_turbo(hw);
+ rtl8723_dm_init_dynamic_bb_powersaving(hw);
+ rtl8723_dm_init_dynamic_txpower(hw);
+ rtl8723be_dm_init_txpower_tracking(hw);
+ rtl8723be_dm_init_dynamic_atc_switch(hw);
+}
+
+static void rtl8723be_dm_find_minimum_rssi(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct dig_t *rtl_dm_dig = &(rtlpriv->dm_digtable);
+ struct rtl_mac *mac = rtl_mac(rtlpriv);
+
+ /* Determine the minimum RSSI */
+ if ((mac->link_state < MAC80211_LINKED) &&
+ (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {
+ rtl_dm_dig->min_undec_pwdb_for_dm = 0;
+ RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
+ "Not connected to any\n");
+ }
+ if (mac->link_state >= MAC80211_LINKED) {
+ if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_ADHOC) {
+ rtl_dm_dig->min_undec_pwdb_for_dm =
+ rtlpriv->dm.entry_min_undec_sm_pwdb;
+ RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
+ "AP Client PWDB = 0x%lx\n",
+ rtlpriv->dm.entry_min_undec_sm_pwdb);
+ } else {
+ rtl_dm_dig->min_undec_pwdb_for_dm =
+ rtlpriv->dm.undec_sm_pwdb;
+ RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
+ "STA Default Port PWDB = 0x%x\n",
+ rtl_dm_dig->min_undec_pwdb_for_dm);
+ }
+ } else {
+ rtl_dm_dig->min_undec_pwdb_for_dm =
+ rtlpriv->dm.entry_min_undec_sm_pwdb;
+ RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
+ "AP Ext Port or disconnet PWDB = 0x%x\n",
+ rtl_dm_dig->min_undec_pwdb_for_dm);
+ }
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "MinUndecoratedPWDBForDM =%d\n",
+ rtl_dm_dig->min_undec_pwdb_for_dm);
+}
+
+static void rtl8723be_dm_check_rssi_monitor(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_sta_info *drv_priv;
+ u8 h2c_parameter[3] = { 0 };
+ long tmp_entry_max_pwdb = 0, tmp_entry_min_pwdb = 0xff;
+
+ /* AP & ADHOC & MESH */
+ spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+ list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) {
+ if (drv_priv->rssi_stat.undec_sm_pwdb <
+ tmp_entry_min_pwdb)
+ tmp_entry_min_pwdb =
+ drv_priv->rssi_stat.undec_sm_pwdb;
+ if (drv_priv->rssi_stat.undec_sm_pwdb >
+ tmp_entry_max_pwdb)
+ tmp_entry_max_pwdb =
+ drv_priv->rssi_stat.undec_sm_pwdb;
+ }
+ spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
+
+ /* If associated entry is found */
+ if (tmp_entry_max_pwdb != 0) {
+ rtlpriv->dm.entry_max_undec_sm_pwdb = tmp_entry_max_pwdb;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "EntryMaxPWDB = 0x%lx(%ld)\n",
+ tmp_entry_max_pwdb, tmp_entry_max_pwdb);
+ } else {
+ rtlpriv->dm.entry_max_undec_sm_pwdb = 0;
+ }
+ /* If associated entry is found */
+ if (tmp_entry_min_pwdb != 0xff) {
+ rtlpriv->dm.entry_min_undec_sm_pwdb = tmp_entry_min_pwdb;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "EntryMinPWDB = 0x%lx(%ld)\n",
+ tmp_entry_min_pwdb, tmp_entry_min_pwdb);
+ } else {
+ rtlpriv->dm.entry_min_undec_sm_pwdb = 0;
+ }
+ /* Indicate Rx signal strength to FW. */
+ if (rtlpriv->dm.useramask) {
+ h2c_parameter[2] = (u8) (rtlpriv->dm.undec_sm_pwdb & 0xFF);
+ h2c_parameter[1] = 0x20;
+ h2c_parameter[0] = 0;
+ rtl8723be_fill_h2c_cmd(hw, H2C_RSSI_REPORT, 3, h2c_parameter);
+ } else {
+ rtl_write_byte(rtlpriv, 0x4fe, rtlpriv->dm.undec_sm_pwdb);
+ }
+ rtl8723be_dm_find_minimum_rssi(hw);
+ rtlpriv->dm_digtable.rssi_val_min =
+ rtlpriv->dm_digtable.min_undec_pwdb_for_dm;
+}
+
+void rtl8723be_dm_write_dig(struct ieee80211_hw *hw, u8 current_igi)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->dm_digtable.cur_igvalue != current_igi) {
+ rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f, current_igi);
+ if (rtlpriv->phy.rf_type != RF_1T1R)
+ rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, 0x7f, current_igi);
+ }
+ rtlpriv->dm_digtable.pre_igvalue = rtlpriv->dm_digtable.cur_igvalue;
+ rtlpriv->dm_digtable.cur_igvalue = current_igi;
+}
+
+static void rtl8723be_dm_dig(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct dig_t *dm_digtable = &(rtlpriv->dm_digtable);
+ u8 dig_dynamic_min, dig_maxofmin;
+ bool firstconnect, firstdisconnect;
+ u8 dm_dig_max, dm_dig_min;
+ u8 current_igi = dm_digtable->cur_igvalue;
+ u8 offset;
+
+ /* AP, BT */
+ if (mac->act_scanning)
+ return;
+
+ dig_dynamic_min = dm_digtable->dig_min_0;
+ firstconnect = (mac->link_state >= MAC80211_LINKED) &&
+ !dm_digtable->media_connect_0;
+ firstdisconnect = (mac->link_state < MAC80211_LINKED) &&
+ dm_digtable->media_connect_0;
+
+ dm_dig_max = 0x5a;
+ dm_dig_min = DM_DIG_MIN;
+ dig_maxofmin = DM_DIG_MAX_AP;
+
+ if (mac->link_state >= MAC80211_LINKED) {
+ if ((dm_digtable->rssi_val_min + 10) > dm_dig_max)
+ dm_digtable->rx_gain_max = dm_dig_max;
+ else if ((dm_digtable->rssi_val_min + 10) < dm_dig_min)
+ dm_digtable->rx_gain_max = dm_dig_min;
+ else
+ dm_digtable->rx_gain_max =
+ dm_digtable->rssi_val_min + 10;
+
+ if (rtlpriv->dm.one_entry_only) {
+ offset = 12;
+ if (dm_digtable->rssi_val_min - offset < dm_dig_min)
+ dig_dynamic_min = dm_dig_min;
+ else if (dm_digtable->rssi_val_min - offset >
+ dig_maxofmin)
+ dig_dynamic_min = dig_maxofmin;
+ else
+ dig_dynamic_min =
+ dm_digtable->rssi_val_min - offset;
+ } else {
+ dig_dynamic_min = dm_dig_min;
+ }
+ } else {
+ dm_digtable->rx_gain_max = dm_dig_max;
+ dig_dynamic_min = dm_dig_min;
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "no link\n");
+ }
+
+ if (rtlpriv->falsealm_cnt.cnt_all > 10000) {
+ if (dm_digtable->large_fa_hit != 3)
+ dm_digtable->large_fa_hit++;
+ if (dm_digtable->forbidden_igi < current_igi) {
+ dm_digtable->forbidden_igi = current_igi;
+ dm_digtable->large_fa_hit = 1;
+ }
+
+ if (dm_digtable->large_fa_hit >= 3) {
+ if ((dm_digtable->forbidden_igi + 1) >
+ dm_digtable->rx_gain_max)
+ dm_digtable->rx_gain_min =
+ dm_digtable->rx_gain_max;
+ else
+ dm_digtable->rx_gain_min =
+ dm_digtable->forbidden_igi + 1;
+ dm_digtable->recover_cnt = 3600;
+ }
+ } else {
+ if (dm_digtable->recover_cnt != 0) {
+ dm_digtable->recover_cnt--;
+ } else {
+ if (dm_digtable->large_fa_hit < 3) {
+ if ((dm_digtable->forbidden_igi - 1) <
+ dig_dynamic_min) {
+ dm_digtable->forbidden_igi =
+ dig_dynamic_min;
+ dm_digtable->rx_gain_min =
+ dig_dynamic_min;
+ } else {
+ dm_digtable->forbidden_igi--;
+ dm_digtable->rx_gain_min =
+ dm_digtable->forbidden_igi + 1;
+ }
+ } else {
+ dm_digtable->large_fa_hit = 0;
+ }
+ }
+ }
+ if (dm_digtable->rx_gain_min > dm_digtable->rx_gain_max)
+ dm_digtable->rx_gain_min = dm_digtable->rx_gain_max;
+
+ if (mac->link_state >= MAC80211_LINKED) {
+ if (firstconnect) {
+ if (dm_digtable->rssi_val_min <= dig_maxofmin)
+ current_igi = dm_digtable->rssi_val_min;
+ else
+ current_igi = dig_maxofmin;
+
+ dm_digtable->large_fa_hit = 0;
+ } else {
+ if (rtlpriv->falsealm_cnt.cnt_all > DM_DIG_FA_TH2)
+ current_igi += 4;
+ else if (rtlpriv->falsealm_cnt.cnt_all > DM_DIG_FA_TH1)
+ current_igi += 2;
+ else if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH0)
+ current_igi -= 2;
+ }
+ } else {
+ if (firstdisconnect) {
+ current_igi = dm_digtable->rx_gain_min;
+ } else {
+ if (rtlpriv->falsealm_cnt.cnt_all > 10000)
+ current_igi += 4;
+ else if (rtlpriv->falsealm_cnt.cnt_all > 8000)
+ current_igi += 2;
+ else if (rtlpriv->falsealm_cnt.cnt_all < 500)
+ current_igi -= 2;
+ }
+ }
+
+ if (current_igi > dm_digtable->rx_gain_max)
+ current_igi = dm_digtable->rx_gain_max;
+ else if (current_igi < dm_digtable->rx_gain_min)
+ current_igi = dm_digtable->rx_gain_min;
+
+ rtl8723be_dm_write_dig(hw, current_igi);
+ dm_digtable->media_connect_0 =
+ ((mac->link_state >= MAC80211_LINKED) ? true : false);
+ dm_digtable->dig_min_0 = dig_dynamic_min;
+}
+
+static void rtl8723be_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
+{
+ u32 ret_value;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt);
+
+ rtl_set_bbreg(hw, DM_REG_OFDM_FA_HOLDC_11N, BIT(31), 1);
+ rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(31), 1);
+
+ ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE1_11N, MASKDWORD);
+ falsealm_cnt->cnt_fast_fsync_fail = ret_value & 0xffff;
+ falsealm_cnt->cnt_sb_search_fail = (ret_value & 0xffff0000) >> 16;
+
+ ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE2_11N, MASKDWORD);
+ falsealm_cnt->cnt_ofdm_cca = ret_value & 0xffff;
+ falsealm_cnt->cnt_parity_fail = (ret_value & 0xffff0000) >> 16;
+
+ ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE3_11N, MASKDWORD);
+ falsealm_cnt->cnt_rate_illegal = ret_value & 0xffff;
+ falsealm_cnt->cnt_crc8_fail = (ret_value & 0xffff0000) >> 16;
+
+ ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE4_11N, MASKDWORD);
+ falsealm_cnt->cnt_mcs_fail = ret_value & 0xffff;
+
+ falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail +
+ falsealm_cnt->cnt_rate_illegal +
+ falsealm_cnt->cnt_crc8_fail +
+ falsealm_cnt->cnt_mcs_fail +
+ falsealm_cnt->cnt_fast_fsync_fail +
+ falsealm_cnt->cnt_sb_search_fail;
+
+ rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(12), 1);
+ rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(14), 1);
+
+ ret_value = rtl_get_bbreg(hw, DM_REG_CCK_FA_RST_11N, MASKBYTE0);
+ falsealm_cnt->cnt_cck_fail = ret_value;
+
+ ret_value = rtl_get_bbreg(hw, DM_REG_CCK_FA_MSB_11N, MASKBYTE3);
+ falsealm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8;
+
+ ret_value = rtl_get_bbreg(hw, DM_REG_CCK_CCA_CNT_11N, MASKDWORD);
+ falsealm_cnt->cnt_cck_cca = ((ret_value & 0xff) << 8) |
+ ((ret_value & 0xff00) >> 8);
+
+ falsealm_cnt->cnt_all = falsealm_cnt->cnt_fast_fsync_fail +
+ falsealm_cnt->cnt_sb_search_fail +
+ falsealm_cnt->cnt_parity_fail +
+ falsealm_cnt->cnt_rate_illegal +
+ falsealm_cnt->cnt_crc8_fail +
+ falsealm_cnt->cnt_mcs_fail +
+ falsealm_cnt->cnt_cck_fail;
+
+ falsealm_cnt->cnt_cca_all = falsealm_cnt->cnt_ofdm_cca +
+ falsealm_cnt->cnt_cck_cca;
+
+ rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTC_11N, BIT(31), 1);
+ rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTC_11N, BIT(31), 0);
+ rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(27), 1);
+ rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(27), 0);
+
+ rtl_set_bbreg(hw, DM_REG_OFDM_FA_HOLDC_11N, BIT(31), 0);
+ rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(31), 0);
+
+ rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(13) | BIT(12), 0);
+ rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(13) | BIT(12), 2);
+
+ rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(15) | BIT(14), 0);
+ rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(15) | BIT(14), 2);
+
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+ "cnt_parity_fail = %d, cnt_rate_illegal = %d, "
+ "cnt_crc8_fail = %d, cnt_mcs_fail = %d\n",
+ falsealm_cnt->cnt_parity_fail,
+ falsealm_cnt->cnt_rate_illegal,
+ falsealm_cnt->cnt_crc8_fail,
+ falsealm_cnt->cnt_mcs_fail);
+
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+ "cnt_ofdm_fail = %x, cnt_cck_fail = %x,"
+ " cnt_all = %x\n",
+ falsealm_cnt->cnt_ofdm_fail,
+ falsealm_cnt->cnt_cck_fail,
+ falsealm_cnt->cnt_all);
+}
+
+static void rtl8723be_dm_dynamic_txpower(struct ieee80211_hw *hw)
+{
+ /* 8723BE does not support ODM_BB_DYNAMIC_TXPWR*/
+ return;
+}
+
+static void rtl8723be_set_iqk_matrix(struct ieee80211_hw *hw, u8 ofdm_index,
+ u8 rfpath, long iqk_result_x,
+ long iqk_result_y)
+{
+ long ele_a = 0, ele_d, ele_c = 0, value32;
+
+ if (ofdm_index >= 43)
+ ofdm_index = 43 - 1;
+
+ ele_d = (ofdmswing_table[ofdm_index] & 0xFFC00000) >> 22;
+
+ if (iqk_result_x != 0) {
+ if ((iqk_result_x & 0x00000200) != 0)
+ iqk_result_x = iqk_result_x | 0xFFFFFC00;
+ ele_a = ((iqk_result_x * ele_d) >> 8) & 0x000003FF;
+
+ if ((iqk_result_y & 0x00000200) != 0)
+ iqk_result_y = iqk_result_y | 0xFFFFFC00;
+ ele_c = ((iqk_result_y * ele_d) >> 8) & 0x000003FF;
+
+ switch (rfpath) {
+ case RF90_PATH_A:
+ value32 = (ele_d << 22) |
+ ((ele_c & 0x3F) << 16) | ele_a;
+ rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, MASKDWORD,
+ value32);
+ value32 = (ele_c & 0x000003C0) >> 6;
+ rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS, value32);
+ value32 = ((iqk_result_x * ele_d) >> 7) & 0x01;
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(24),
+ value32);
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (rfpath) {
+ case RF90_PATH_A:
+ rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, MASKDWORD,
+ ofdmswing_table[ofdm_index]);
+ rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS, 0x00);
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(24), 0x00);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void rtl8723be_dm_tx_power_track_set_power(struct ieee80211_hw *hw,
+ enum pwr_track_control_method method,
+ u8 rfpath, u8 idx)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ u8 swing_idx_ofdm_limit = 36;
+
+ if (method == TXAGC) {
+ rtl8723be_phy_set_txpower_level(hw, rtlphy->current_channel);
+ } else if (method == BBSWING) {
+ if (rtldm->swing_idx_cck >= CCK_TABLE_SIZE)
+ rtldm->swing_idx_cck = CCK_TABLE_SIZE - 1;
+
+ if (!rtldm->cck_inch14) {
+ rtl_write_byte(rtlpriv, 0xa22,
+ cckswing_table_ch1ch13[rtldm->swing_idx_cck][0]);
+ rtl_write_byte(rtlpriv, 0xa23,
+ cckswing_table_ch1ch13[rtldm->swing_idx_cck][1]);
+ rtl_write_byte(rtlpriv, 0xa24,
+ cckswing_table_ch1ch13[rtldm->swing_idx_cck][2]);
+ rtl_write_byte(rtlpriv, 0xa25,
+ cckswing_table_ch1ch13[rtldm->swing_idx_cck][3]);
+ rtl_write_byte(rtlpriv, 0xa26,
+ cckswing_table_ch1ch13[rtldm->swing_idx_cck][4]);
+ rtl_write_byte(rtlpriv, 0xa27,
+ cckswing_table_ch1ch13[rtldm->swing_idx_cck][5]);
+ rtl_write_byte(rtlpriv, 0xa28,
+ cckswing_table_ch1ch13[rtldm->swing_idx_cck][6]);
+ rtl_write_byte(rtlpriv, 0xa29,
+ cckswing_table_ch1ch13[rtldm->swing_idx_cck][7]);
+ } else {
+ rtl_write_byte(rtlpriv, 0xa22,
+ cckswing_table_ch14[rtldm->swing_idx_cck][0]);
+ rtl_write_byte(rtlpriv, 0xa23,
+ cckswing_table_ch14[rtldm->swing_idx_cck][1]);
+ rtl_write_byte(rtlpriv, 0xa24,
+ cckswing_table_ch14[rtldm->swing_idx_cck][2]);
+ rtl_write_byte(rtlpriv, 0xa25,
+ cckswing_table_ch14[rtldm->swing_idx_cck][3]);
+ rtl_write_byte(rtlpriv, 0xa26,
+ cckswing_table_ch14[rtldm->swing_idx_cck][4]);
+ rtl_write_byte(rtlpriv, 0xa27,
+ cckswing_table_ch14[rtldm->swing_idx_cck][5]);
+ rtl_write_byte(rtlpriv, 0xa28,
+ cckswing_table_ch14[rtldm->swing_idx_cck][6]);
+ rtl_write_byte(rtlpriv, 0xa29,
+ cckswing_table_ch14[rtldm->swing_idx_cck][7]);
+ }
+
+ if (rfpath == RF90_PATH_A) {
+ if (rtldm->swing_idx_ofdm[RF90_PATH_A] <
+ swing_idx_ofdm_limit)
+ swing_idx_ofdm_limit =
+ rtldm->swing_idx_ofdm[RF90_PATH_A];
+
+ rtl8723be_set_iqk_matrix(hw,
+ rtldm->swing_idx_ofdm[rfpath], rfpath,
+ rtlphy->iqk_matrix[idx].value[0][0],
+ rtlphy->iqk_matrix[idx].value[0][1]);
+ } else if (rfpath == RF90_PATH_B) {
+ if (rtldm->swing_idx_ofdm[RF90_PATH_B] <
+ swing_idx_ofdm_limit)
+ swing_idx_ofdm_limit =
+ rtldm->swing_idx_ofdm[RF90_PATH_B];
+
+ rtl8723be_set_iqk_matrix(hw,
+ rtldm->swing_idx_ofdm[rfpath], rfpath,
+ rtlphy->iqk_matrix[idx].value[0][4],
+ rtlphy->iqk_matrix[idx].value[0][5]);
+ }
+ } else {
+ return;
+ }
+}
+
+static void txpwr_track_cb_therm(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ u8 thermalvalue = 0, delta, delta_lck, delta_iqk;
+ u8 thermalvalue_avg_count = 0;
+ u32 thermalvalue_avg = 0;
+ int i = 0;
+
+ u8 ofdm_min_index = 6;
+ u8 index = 0;
+
+ char delta_swing_table_idx_tup_a[] = {
+ 0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 5,
+ 5, 6, 6, 7, 7, 8, 8, 9, 9, 9, 10,
+ 10, 11, 11, 12, 12, 13, 14, 15};
+ char delta_swing_table_idx_tdown_a[] = {
+ 0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 5,
+ 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 9,
+ 9, 10, 10, 11, 12, 13, 14, 15};
+
+ /*Initilization ( 7 steps in total)*/
+ rtlpriv->dm.txpower_trackinginit = true;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "rtl8723be_dm_txpower_tracking"
+ "_callback_thermalmeter\n");
+
+ thermalvalue = (u8)rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER, 0xfc00);
+ if (!rtlpriv->dm.txpower_track_control || thermalvalue == 0 ||
+ rtlefuse->eeprom_thermalmeter == 0xFF)
+ return;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Readback Thermal Meter = 0x%x pre thermal meter 0x%x "
+ "eeprom_thermalmeter 0x%x\n",
+ thermalvalue, rtldm->thermalvalue,
+ rtlefuse->eeprom_thermalmeter);
+ /*3 Initialize ThermalValues of RFCalibrateInfo*/
+ if (!rtldm->thermalvalue) {
+ rtlpriv->dm.thermalvalue_lck = thermalvalue;
+ rtlpriv->dm.thermalvalue_iqk = thermalvalue;
+ }
+
+ /*4 Calculate average thermal meter*/
+ rtldm->thermalvalue_avg[rtldm->thermalvalue_avg_index] = thermalvalue;
+ rtldm->thermalvalue_avg_index++;
+ if (rtldm->thermalvalue_avg_index == AVG_THERMAL_NUM_8723BE)
+ rtldm->thermalvalue_avg_index = 0;
+
+ for (i = 0; i < AVG_THERMAL_NUM_8723BE; i++) {
+ if (rtldm->thermalvalue_avg[i]) {
+ thermalvalue_avg += rtldm->thermalvalue_avg[i];
+ thermalvalue_avg_count++;
+ }
+ }
+
+ if (thermalvalue_avg_count)
+ thermalvalue = (u8)(thermalvalue_avg / thermalvalue_avg_count);
+
+ /* 5 Calculate delta, delta_LCK, delta_IQK.*/
+ delta = (thermalvalue > rtlpriv->dm.thermalvalue) ?
+ (thermalvalue - rtlpriv->dm.thermalvalue) :
+ (rtlpriv->dm.thermalvalue - thermalvalue);
+ delta_lck = (thermalvalue > rtlpriv->dm.thermalvalue_lck) ?
+ (thermalvalue - rtlpriv->dm.thermalvalue_lck) :
+ (rtlpriv->dm.thermalvalue_lck - thermalvalue);
+ delta_iqk = (thermalvalue > rtlpriv->dm.thermalvalue_iqk) ?
+ (thermalvalue - rtlpriv->dm.thermalvalue_iqk) :
+ (rtlpriv->dm.thermalvalue_iqk - thermalvalue);
+
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Readback Thermal Meter = 0x%x pre thermal meter 0x%x "
+ "eeprom_thermalmeter 0x%x delta 0x%x "
+ "delta_lck 0x%x delta_iqk 0x%x\n",
+ thermalvalue, rtlpriv->dm.thermalvalue,
+ rtlefuse->eeprom_thermalmeter, delta, delta_lck, delta_iqk);
+ /* 6 If necessary, do LCK.*/
+ if (delta_lck >= IQK_THRESHOLD) {
+ rtlpriv->dm.thermalvalue_lck = thermalvalue;
+ rtl8723be_phy_lc_calibrate(hw);
+ }
+
+ /* 7 If necessary, move the index of
+ * swing table to adjust Tx power.
+ */
+ if (delta > 0 && rtlpriv->dm.txpower_track_control) {
+ delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ?
+ (thermalvalue - rtlefuse->eeprom_thermalmeter) :
+ (rtlefuse->eeprom_thermalmeter - thermalvalue);
+
+ if (delta >= TXSCALE_TABLE_SIZE)
+ delta = TXSCALE_TABLE_SIZE - 1;
+ /* 7.1 Get the final CCK_index and
+ * OFDM_index for each swing table.
+ */
+ if (thermalvalue > rtlefuse->eeprom_thermalmeter) {
+ rtldm->delta_power_index_last[RF90_PATH_A] =
+ rtldm->delta_power_index[RF90_PATH_A];
+ rtldm->delta_power_index[RF90_PATH_A] =
+ delta_swing_table_idx_tup_a[delta];
+ } else {
+ rtldm->delta_power_index_last[RF90_PATH_A] =
+ rtldm->delta_power_index[RF90_PATH_A];
+ rtldm->delta_power_index[RF90_PATH_A] =
+ -1 * delta_swing_table_idx_tdown_a[delta];
+ }
+
+ /* 7.2 Handle boundary conditions of index.*/
+ if (rtldm->delta_power_index[RF90_PATH_A] ==
+ rtldm->delta_power_index_last[RF90_PATH_A])
+ rtldm->power_index_offset[RF90_PATH_A] = 0;
+ else
+ rtldm->power_index_offset[RF90_PATH_A] =
+ rtldm->delta_power_index[RF90_PATH_A] -
+ rtldm->delta_power_index_last[RF90_PATH_A];
+
+ rtldm->ofdm_index[0] =
+ rtldm->swing_idx_ofdm_base[RF90_PATH_A] +
+ rtldm->power_index_offset[RF90_PATH_A];
+ rtldm->cck_index = rtldm->swing_idx_cck_base +
+ rtldm->power_index_offset[RF90_PATH_A];
+
+ rtldm->swing_idx_cck = rtldm->cck_index;
+ rtldm->swing_idx_ofdm[0] = rtldm->ofdm_index[0];
+
+ if (rtldm->ofdm_index[0] > OFDM_TABLE_SIZE - 1)
+ rtldm->ofdm_index[0] = OFDM_TABLE_SIZE - 1;
+ else if (rtldm->ofdm_index[0] < ofdm_min_index)
+ rtldm->ofdm_index[0] = ofdm_min_index;
+
+ if (rtldm->cck_index > CCK_TABLE_SIZE - 1)
+ rtldm->cck_index = CCK_TABLE_SIZE - 1;
+ else if (rtldm->cck_index < 0)
+ rtldm->cck_index = 0;
+ } else {
+ rtldm->power_index_offset[RF90_PATH_A] = 0;
+ }
+
+ if ((rtldm->power_index_offset[RF90_PATH_A] != 0) &&
+ (rtldm->txpower_track_control)) {
+ rtldm->done_txpower = true;
+ if (thermalvalue > rtlefuse->eeprom_thermalmeter)
+ rtl8723be_dm_tx_power_track_set_power(hw, BBSWING, 0,
+ index);
+ else
+ rtl8723be_dm_tx_power_track_set_power(hw, BBSWING, 0,
+ index);
+
+ rtldm->swing_idx_cck_base = rtldm->swing_idx_cck;
+ rtldm->swing_idx_ofdm_base[RF90_PATH_A] =
+ rtldm->swing_idx_ofdm[0];
+ rtldm->thermalvalue = thermalvalue;
+ }
+
+ if (delta_iqk >= IQK_THRESHOLD) {
+ rtldm->thermalvalue_iqk = thermalvalue;
+ rtl8723be_phy_iq_calibrate(hw, false);
+ }
+
+ rtldm->txpowercount = 0;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "end\n");
+}
+
+void rtl8723be_dm_check_txpower_tracking(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ static u8 tm_trigger;
+
+ if (!rtlpriv->dm.txpower_tracking)
+ return;
+
+ if (!tm_trigger) {
+ rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, BIT(17) | BIT(16),
+ 0x03);
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Trigger 8723be Thermal Meter!!\n");
+ tm_trigger = 1;
+ return;
+ } else {
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Schedule TxPowerTracking !!\n");
+ txpwr_track_cb_therm(hw);
+ tm_trigger = 0;
+ }
+}
+
+static void rtl8723be_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rate_adaptive *ra = &(rtlpriv->ra);
+ struct ieee80211_sta *sta = NULL;
+ u32 low_rssithresh_for_ra = ra->low2high_rssi_thresh_for_ra40m;
+ u32 high_rssithresh_for_ra = ra->high_rssi_thresh_for_ra;
+ u8 go_up_gap = 5;
+
+ if (is_hal_stop(rtlhal)) {
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "driver is going to unload\n");
+ return;
+ }
+
+ if (!rtlpriv->dm.useramask) {
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "driver does not control rate adaptive mask\n");
+ return;
+ }
+
+ if (mac->link_state == MAC80211_LINKED &&
+ mac->opmode == NL80211_IFTYPE_STATION) {
+ switch (ra->pre_ratr_state) {
+ case DM_RATR_STA_MIDDLE:
+ high_rssithresh_for_ra += go_up_gap;
+ break;
+ case DM_RATR_STA_LOW:
+ high_rssithresh_for_ra += go_up_gap;
+ low_rssithresh_for_ra += go_up_gap;
+ break;
+ default:
+ break;
+ }
+
+ if (rtlpriv->dm.undec_sm_pwdb >
+ (long)high_rssithresh_for_ra)
+ ra->ratr_state = DM_RATR_STA_HIGH;
+ else if (rtlpriv->dm.undec_sm_pwdb >
+ (long)low_rssithresh_for_ra)
+ ra->ratr_state = DM_RATR_STA_MIDDLE;
+ else
+ ra->ratr_state = DM_RATR_STA_LOW;
+
+ if (ra->pre_ratr_state != ra->ratr_state) {
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "RSSI = %ld\n",
+ rtlpriv->dm.undec_sm_pwdb);
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "RSSI_LEVEL = %d\n", ra->ratr_state);
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "PreState = %d, CurState = %d\n",
+ ra->pre_ratr_state, ra->ratr_state);
+
+ rcu_read_lock();
+ sta = rtl_find_sta(hw, mac->bssid);
+ if (sta)
+ rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
+ ra->ratr_state);
+ rcu_read_unlock();
+
+ ra->pre_ratr_state = ra->ratr_state;
+ }
+ }
+}
+
+static bool rtl8723be_dm_is_edca_turbo_disable(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->cfg->ops->get_btc_status()) {
+ if (rtlpriv->btcoexist.btc_ops->btc_is_disable_edca_turbo(rtlpriv))
+ return true;
+ }
+ if (rtlpriv->mac80211.mode == WIRELESS_MODE_B)
+ return true;
+
+ return false;
+}
+
+static void rtl8723be_dm_check_edca_turbo(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ static u64 last_txok_cnt;
+ static u64 last_rxok_cnt;
+ u64 cur_txok_cnt = 0;
+ u64 cur_rxok_cnt = 0;
+ u32 edca_be_ul = 0x6ea42b;
+ u32 edca_be_dl = 0x6ea42b;/*not sure*/
+ u32 edca_be = 0x5ea42b;
+ u32 iot_peer = 0;
+ bool is_cur_rdlstate;
+ bool last_is_cur_rdlstate = false;
+ bool bias_on_rx = false;
+ bool edca_turbo_on = false;
+
+ last_is_cur_rdlstate = rtlpriv->dm.is_cur_rdlstate;
+
+ cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt;
+ cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt;
+
+ iot_peer = rtlpriv->mac80211.vendor;
+ bias_on_rx = (iot_peer == PEER_RAL || iot_peer == PEER_ATH) ?
+ true : false;
+ edca_turbo_on = ((!rtlpriv->dm.is_any_nonbepkts) &&
+ (!rtlpriv->dm.disable_framebursting)) ?
+ true : false;
+
+ if ((iot_peer == PEER_CISCO) &&
+ (mac->mode == WIRELESS_MODE_N_24G)) {
+ edca_be_dl = edca_setting_dl[iot_peer];
+ edca_be_ul = edca_setting_ul[iot_peer];
+ }
+ if (rtl8723be_dm_is_edca_turbo_disable(hw))
+ goto exit;
+
+ if (edca_turbo_on) {
+ if (bias_on_rx)
+ is_cur_rdlstate = (cur_txok_cnt > cur_rxok_cnt * 4) ?
+ false : true;
+ else
+ is_cur_rdlstate = (cur_rxok_cnt > cur_txok_cnt * 4) ?
+ true : false;
+
+ edca_be = (is_cur_rdlstate) ? edca_be_dl : edca_be_ul;
+ rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, edca_be);
+ rtlpriv->dm.is_cur_rdlstate = is_cur_rdlstate;
+ rtlpriv->dm.current_turbo_edca = true;
+ } else {
+ if (rtlpriv->dm.current_turbo_edca) {
+ u8 tmp = AC0_BE;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
+ &tmp);
+ }
+ rtlpriv->dm.current_turbo_edca = false;
+ }
+
+exit:
+ rtlpriv->dm.is_any_nonbepkts = false;
+ last_txok_cnt = rtlpriv->stats.txbytesunicast;
+ last_rxok_cnt = rtlpriv->stats.rxbytesunicast;
+}
+
+static void rtl8723be_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 cur_cck_cca_thresh;
+
+ if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) {
+ if (rtlpriv->dm_digtable.rssi_val_min > 25) {
+ cur_cck_cca_thresh = 0xcd;
+ } else if ((rtlpriv->dm_digtable.rssi_val_min <= 25) &&
+ (rtlpriv->dm_digtable.rssi_val_min > 10)) {
+ cur_cck_cca_thresh = 0x83;
+ } else {
+ if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000)
+ cur_cck_cca_thresh = 0x83;
+ else
+ cur_cck_cca_thresh = 0x40;
+ }
+ } else {
+ if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000)
+ cur_cck_cca_thresh = 0x83;
+ else
+ cur_cck_cca_thresh = 0x40;
+ }
+
+ if (rtlpriv->dm_digtable.cur_cck_cca_thres != cur_cck_cca_thresh)
+ rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, cur_cck_cca_thresh);
+
+ rtlpriv->dm_digtable.pre_cck_cca_thres = rtlpriv->dm_digtable.cur_cck_cca_thres;
+ rtlpriv->dm_digtable.cur_cck_cca_thres = cur_cck_cca_thresh;
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+ "CCK cca thresh hold =%x\n",
+ rtlpriv->dm_digtable.cur_cck_cca_thres);
+}
+
+static void rtl8723be_dm_dynamic_edcca(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 reg_c50, reg_c58;
+ bool fw_current_in_ps_mode = false;
+
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_in_ps_mode));
+ if (fw_current_in_ps_mode)
+ return;
+
+ reg_c50 = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0);
+ reg_c58 = rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0);
+
+ if (reg_c50 > 0x28 && reg_c58 > 0x28) {
+ if (!rtlpriv->rtlhal.pre_edcca_enable) {
+ rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD, 0x03);
+ rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD + 2, 0x00);
+ }
+ } else if (reg_c50 < 0x25 && reg_c58 < 0x25) {
+ if (rtlpriv->rtlhal.pre_edcca_enable) {
+ rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD, 0x7f);
+ rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD + 2, 0x7f);
+ }
+ }
+}
+
+static void rtl8723be_dm_dynamic_atc_switch(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ u8 crystal_cap;
+ u32 packet_count;
+ int cfo_khz_a, cfo_khz_b, cfo_ave = 0, adjust_xtal = 0;
+ int cfo_ave_diff;
+
+ if (rtlpriv->mac80211.link_state < MAC80211_LINKED) {
+ if (rtldm->atc_status == ATC_STATUS_OFF) {
+ rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11),
+ ATC_STATUS_ON);
+ rtldm->atc_status = ATC_STATUS_ON;
+ }
+ if (rtlpriv->cfg->ops->get_btc_status()) {
+ if (!rtlpriv->btcoexist.btc_ops->btc_is_bt_disabled(rtlpriv)) {
+ RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD,
+ "odm_DynamicATCSwitch(): Disable"
+ " CFO tracking for BT!!\n");
+ return;
+ }
+ }
+
+ if (rtldm->crystal_cap != rtlpriv->efuse.crystalcap) {
+ rtldm->crystal_cap = rtlpriv->efuse.crystalcap;
+ crystal_cap = rtldm->crystal_cap & 0x3f;
+ rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0xFFF000,
+ (crystal_cap | (crystal_cap << 6)));
+ }
+ } else {
+ cfo_khz_a = (int)(rtldm->cfo_tail[0] * 3125) / 1280;
+ cfo_khz_b = (int)(rtldm->cfo_tail[1] * 3125) / 1280;
+ packet_count = rtldm->packet_count;
+
+ if (packet_count == rtldm->packet_count_pre)
+ return;
+
+ rtldm->packet_count_pre = packet_count;
+
+ if (rtlpriv->phy.rf_type == RF_1T1R)
+ cfo_ave = cfo_khz_a;
+ else
+ cfo_ave = (int)(cfo_khz_a + cfo_khz_b) >> 1;
+
+ cfo_ave_diff = (rtldm->cfo_ave_pre >= cfo_ave) ?
+ (rtldm->cfo_ave_pre - cfo_ave) :
+ (cfo_ave - rtldm->cfo_ave_pre);
+
+ if (cfo_ave_diff > 20 && rtldm->large_cfo_hit == 0) {
+ rtldm->large_cfo_hit = 1;
+ return;
+ } else {
+ rtldm->large_cfo_hit = 0;
+ }
+
+ rtldm->cfo_ave_pre = cfo_ave;
+
+ if (cfo_ave >= -rtldm->cfo_threshold &&
+ cfo_ave <= rtldm->cfo_threshold && rtldm->is_freeze == 0) {
+ if (rtldm->cfo_threshold == CFO_THRESHOLD_XTAL) {
+ rtldm->cfo_threshold = CFO_THRESHOLD_XTAL + 10;
+ rtldm->is_freeze = 1;
+ } else {
+ rtldm->cfo_threshold = CFO_THRESHOLD_XTAL;
+ }
+ }
+
+ if (cfo_ave > rtldm->cfo_threshold && rtldm->crystal_cap < 0x3f)
+ adjust_xtal = ((cfo_ave - CFO_THRESHOLD_XTAL) >> 1) + 1;
+ else if ((cfo_ave < -rtlpriv->dm.cfo_threshold) &&
+ rtlpriv->dm.crystal_cap > 0)
+ adjust_xtal = ((cfo_ave + CFO_THRESHOLD_XTAL) >> 1) - 1;
+
+ if (adjust_xtal != 0) {
+ rtldm->is_freeze = 0;
+ rtldm->crystal_cap += adjust_xtal;
+
+ if (rtldm->crystal_cap > 0x3f)
+ rtldm->crystal_cap = 0x3f;
+ else if (rtldm->crystal_cap < 0)
+ rtldm->crystal_cap = 0;
+
+ crystal_cap = rtldm->crystal_cap & 0x3f;
+ rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0xFFF000,
+ (crystal_cap | (crystal_cap << 6)));
+ }
+
+ if (cfo_ave < CFO_THRESHOLD_ATC &&
+ cfo_ave > -CFO_THRESHOLD_ATC) {
+ if (rtldm->atc_status == ATC_STATUS_ON) {
+ rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11),
+ ATC_STATUS_OFF);
+ rtldm->atc_status = ATC_STATUS_OFF;
+ }
+ } else {
+ if (rtldm->atc_status == ATC_STATUS_OFF) {
+ rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11),
+ ATC_STATUS_ON);
+ rtldm->atc_status = ATC_STATUS_ON;
+ }
+ }
+ }
+}
+
+static void rtl8723be_dm_common_info_self_update(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_sta_info *drv_priv;
+ u8 cnt = 0;
+
+ rtlpriv->dm.one_entry_only = false;
+
+ if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_STATION &&
+ rtlpriv->mac80211.link_state >= MAC80211_LINKED) {
+ rtlpriv->dm.one_entry_only = true;
+ return;
+ }
+
+ if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP ||
+ rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC ||
+ rtlpriv->mac80211.opmode == NL80211_IFTYPE_MESH_POINT) {
+ spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+ list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) {
+ cnt++;
+ }
+ spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
+
+ if (cnt == 1)
+ rtlpriv->dm.one_entry_only = true;
+ }
+}
+
+void rtl8723be_dm_watchdog(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ bool fw_current_inpsmode = false;
+ bool fw_ps_awake = true;
+
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inpsmode));
+
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON,
+ (u8 *)(&fw_ps_awake));
+
+ if (ppsc->p2p_ps_info.p2p_ps_mode)
+ fw_ps_awake = false;
+
+ if ((ppsc->rfpwr_state == ERFON) &&
+ ((!fw_current_inpsmode) && fw_ps_awake) &&
+ (!ppsc->rfchange_inprogress)) {
+ rtl8723be_dm_common_info_self_update(hw);
+ rtl8723be_dm_false_alarm_counter_statistics(hw);
+ rtl8723be_dm_check_rssi_monitor(hw);
+ rtl8723be_dm_dig(hw);
+ rtl8723be_dm_dynamic_edcca(hw);
+ rtl8723be_dm_cck_packet_detection_thresh(hw);
+ rtl8723be_dm_refresh_rate_adaptive_mask(hw);
+ rtl8723be_dm_check_edca_turbo(hw);
+ rtl8723be_dm_dynamic_atc_switch(hw);
+ rtl8723be_dm_check_txpower_tracking(hw);
+ rtl8723be_dm_dynamic_txpower(hw);
+ if (rtlpriv->cfg->ops->get_btc_status())
+ rtlpriv->btcoexist.btc_ops->btc_periodical(rtlpriv);
+ }
+ rtlpriv->dm.dbginfo.num_qry_beacon_pkt = 0;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.h b/drivers/net/wireless/rtlwifi/rtl8723be/dm.h
new file mode 100644
index 000000000000..c6c2f2a78a66
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/dm.h
@@ -0,0 +1,310 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_DM_H__
+#define __RTL8723BE_DM_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
+
+#define TXSCALE_TABLE_SIZE 30
+
+/*RF REG LIST*/
+#define DM_REG_RF_MODE_11N 0x00
+#define DM_REG_RF_0B_11N 0x0B
+#define DM_REG_CHNBW_11N 0x18
+#define DM_REG_T_METER_11N 0x24
+#define DM_REG_RF_25_11N 0x25
+#define DM_REG_RF_26_11N 0x26
+#define DM_REG_RF_27_11N 0x27
+#define DM_REG_RF_2B_11N 0x2B
+#define DM_REG_RF_2C_11N 0x2C
+#define DM_REG_RXRF_A3_11N 0x3C
+#define DM_REG_T_METER_92D_11N 0x42
+#define DM_REG_T_METER_88E_11N 0x42
+
+/*BB REG LIST*/
+/*PAGE 8 */
+#define DM_REG_BB_CTRL_11N 0x800
+#define DM_REG_RF_PIN_11N 0x804
+#define DM_REG_PSD_CTRL_11N 0x808
+#define DM_REG_TX_ANT_CTRL_11N 0x80C
+#define DM_REG_BB_PWR_SAV5_11N 0x818
+#define DM_REG_CCK_RPT_FORMAT_11N 0x824
+#define DM_REG_RX_DEFUALT_A_11N 0x858
+#define DM_REG_RX_DEFUALT_B_11N 0x85A
+#define DM_REG_BB_PWR_SAV3_11N 0x85C
+#define DM_REG_ANTSEL_CTRL_11N 0x860
+#define DM_REG_RX_ANT_CTRL_11N 0x864
+#define DM_REG_PIN_CTRL_11N 0x870
+#define DM_REG_BB_PWR_SAV1_11N 0x874
+#define DM_REG_ANTSEL_PATH_11N 0x878
+#define DM_REG_BB_3WIRE_11N 0x88C
+#define DM_REG_SC_CNT_11N 0x8C4
+#define DM_REG_PSD_DATA_11N 0x8B4
+/*PAGE 9*/
+#define DM_REG_ANT_MAPPING1_11N 0x914
+#define DM_REG_ANT_MAPPING2_11N 0x918
+/*PAGE A*/
+#define DM_REG_CCK_ANTDIV_PARA1_11N 0xA00
+#define DM_REG_CCK_CCA_11N 0xA0A
+#define DM_REG_CCK_ANTDIV_PARA2_11N 0xA0C
+#define DM_REG_CCK_ANTDIV_PARA3_11N 0xA10
+#define DM_REG_CCK_ANTDIV_PARA4_11N 0xA14
+#define DM_REG_CCK_FILTER_PARA1_11N 0xA22
+#define DM_REG_CCK_FILTER_PARA2_11N 0xA23
+#define DM_REG_CCK_FILTER_PARA3_11N 0xA24
+#define DM_REG_CCK_FILTER_PARA4_11N 0xA25
+#define DM_REG_CCK_FILTER_PARA5_11N 0xA26
+#define DM_REG_CCK_FILTER_PARA6_11N 0xA27
+#define DM_REG_CCK_FILTER_PARA7_11N 0xA28
+#define DM_REG_CCK_FILTER_PARA8_11N 0xA29
+#define DM_REG_CCK_FA_RST_11N 0xA2C
+#define DM_REG_CCK_FA_MSB_11N 0xA58
+#define DM_REG_CCK_FA_LSB_11N 0xA5C
+#define DM_REG_CCK_CCA_CNT_11N 0xA60
+#define DM_REG_BB_PWR_SAV4_11N 0xA74
+/*PAGE B */
+#define DM_REG_LNA_SWITCH_11N 0xB2C
+#define DM_REG_PATH_SWITCH_11N 0xB30
+#define DM_REG_RSSI_CTRL_11N 0xB38
+#define DM_REG_CONFIG_ANTA_11N 0xB68
+#define DM_REG_RSSI_BT_11N 0xB9C
+/*PAGE C */
+#define DM_REG_OFDM_FA_HOLDC_11N 0xC00
+#define DM_REG_RX_PATH_11N 0xC04
+#define DM_REG_TRMUX_11N 0xC08
+#define DM_REG_OFDM_FA_RSTC_11N 0xC0C
+#define DM_REG_RXIQI_MATRIX_11N 0xC14
+#define DM_REG_TXIQK_MATRIX_LSB1_11N 0xC4C
+#define DM_REG_IGI_A_11N 0xC50
+#define DM_REG_ANTDIV_PARA2_11N 0xC54
+#define DM_REG_IGI_B_11N 0xC58
+#define DM_REG_ANTDIV_PARA3_11N 0xC5C
+#define DM_REG_BB_PWR_SAV2_11N 0xC70
+#define DM_REG_RX_OFF_11N 0xC7C
+#define DM_REG_TXIQK_MATRIXA_11N 0xC80
+#define DM_REG_TXIQK_MATRIXB_11N 0xC88
+#define DM_REG_TXIQK_MATRIXA_LSB2_11N 0xC94
+#define DM_REG_TXIQK_MATRIXB_LSB2_11N 0xC9C
+#define DM_REG_RXIQK_MATRIX_LSB_11N 0xCA0
+#define DM_REG_ANTDIV_PARA1_11N 0xCA4
+#define DM_REG_OFDM_FA_TYPE1_11N 0xCF0
+/*PAGE D */
+#define DM_REG_OFDM_FA_RSTD_11N 0xD00
+#define DM_REG_OFDM_FA_TYPE2_11N 0xDA0
+#define DM_REG_OFDM_FA_TYPE3_11N 0xDA4
+#define DM_REG_OFDM_FA_TYPE4_11N 0xDA8
+/*PAGE E */
+#define DM_REG_TXAGC_A_6_18_11N 0xE00
+#define DM_REG_TXAGC_A_24_54_11N 0xE04
+#define DM_REG_TXAGC_A_1_MCS32_11N 0xE08
+#define DM_REG_TXAGC_A_MCS0_3_11N 0xE10
+#define DM_REG_TXAGC_A_MCS4_7_11N 0xE14
+#define DM_REG_TXAGC_A_MCS8_11_11N 0xE18
+#define DM_REG_TXAGC_A_MCS12_15_11N 0xE1C
+#define DM_REG_FPGA0_IQK_11N 0xE28
+#define DM_REG_TXIQK_TONE_A_11N 0xE30
+#define DM_REG_RXIQK_TONE_A_11N 0xE34
+#define DM_REG_TXIQK_PI_A_11N 0xE38
+#define DM_REG_RXIQK_PI_A_11N 0xE3C
+#define DM_REG_TXIQK_11N 0xE40
+#define DM_REG_RXIQK_11N 0xE44
+#define DM_REG_IQK_AGC_PTS_11N 0xE48
+#define DM_REG_IQK_AGC_RSP_11N 0xE4C
+#define DM_REG_BLUETOOTH_11N 0xE6C
+#define DM_REG_RX_WAIT_CCA_11N 0xE70
+#define DM_REG_TX_CCK_RFON_11N 0xE74
+#define DM_REG_TX_CCK_BBON_11N 0xE78
+#define DM_REG_OFDM_RFON_11N 0xE7C
+#define DM_REG_OFDM_BBON_11N 0xE80
+#define DM_REG_TX2RX_11N 0xE84
+#define DM_REG_TX2TX_11N 0xE88
+#define DM_REG_RX_CCK_11N 0xE8C
+#define DM_REG_RX_OFDM_11N 0xED0
+#define DM_REG_RX_WAIT_RIFS_11N 0xED4
+#define DM_REG_RX2RX_11N 0xED8
+#define DM_REG_STANDBY_11N 0xEDC
+#define DM_REG_SLEEP_11N 0xEE0
+#define DM_REG_PMPD_ANAEN_11N 0xEEC
+
+/*MAC REG LIST*/
+#define DM_REG_BB_RST_11N 0x02
+#define DM_REG_ANTSEL_PIN_11N 0x4C
+#define DM_REG_EARLY_MODE_11N 0x4D0
+#define DM_REG_RSSI_MONITOR_11N 0x4FE
+#define DM_REG_EDCA_VO_11N 0x500
+#define DM_REG_EDCA_VI_11N 0x504
+#define DM_REG_EDCA_BE_11N 0x508
+#define DM_REG_EDCA_BK_11N 0x50C
+#define DM_REG_TXPAUSE_11N 0x522
+#define DM_REG_RESP_TX_11N 0x6D8
+#define DM_REG_ANT_TRAIN_PARA1_11N 0x7b0
+#define DM_REG_ANT_TRAIN_PARA2_11N 0x7b4
+
+/*DIG Related*/
+#define DM_BIT_IGI_11N 0x0000007F
+
+#define HAL_DM_DIG_DISABLE BIT(0)
+#define HAL_DM_HIPWR_DISABLE BIT(1)
+
+#define OFDM_TABLE_LENGTH 43
+#define CCK_TABLE_LENGTH 33
+
+#define OFDM_TABLE_SIZE 37
+#define CCK_TABLE_SIZE 33
+
+#define BW_AUTO_SWITCH_HIGH_LOW 25
+#define BW_AUTO_SWITCH_LOW_HIGH 30
+
+#define DM_DIG_THRESH_HIGH 40
+#define DM_DIG_THRESH_LOW 35
+
+#define DM_FALSEALARM_THRESH_LOW 400
+#define DM_FALSEALARM_THRESH_HIGH 1000
+
+#define DM_DIG_MAX 0x3e
+#define DM_DIG_MIN 0x1e
+
+#define DM_DIG_MAX_AP 0x32
+#define DM_DIG_MIN_AP 0x20
+
+#define DM_DIG_FA_UPPER 0x3e
+#define DM_DIG_FA_LOWER 0x1e
+#define DM_DIG_FA_TH0 0x200
+#define DM_DIG_FA_TH1 0x300
+#define DM_DIG_FA_TH2 0x400
+
+#define DM_DIG_BACKOFF_MAX 12
+#define DM_DIG_BACKOFF_MIN -4
+#define DM_DIG_BACKOFF_DEFAULT 10
+
+#define RXPATHSELECTION_DIFF_TH 18
+
+#define DM_RATR_STA_INIT 0
+#define DM_RATR_STA_HIGH 1
+#define DM_RATR_STA_MIDDLE 2
+#define DM_RATR_STA_LOW 3
+
+#define CTS2SELF_THVAL 30
+#define REGC38_TH 20
+
+#define TXHIGHPWRLEVEL_NORMAL 0
+#define TXHIGHPWRLEVEL_LEVEL1 1
+#define TXHIGHPWRLEVEL_LEVEL2 2
+#define TXHIGHPWRLEVEL_BT1 3
+#define TXHIGHPWRLEVEL_BT2 4
+
+#define DM_TYPE_BYFW 0
+#define DM_TYPE_BYDRIVER 1
+
+#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74
+#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67
+#define TXPWRTRACK_MAX_IDX 6
+
+/* Dynamic ATC switch */
+#define ATC_STATUS_OFF 0x0 /* enable */
+#define ATC_STATUS_ON 0x1 /* disable */
+#define CFO_THRESHOLD_XTAL 10 /* kHz */
+#define CFO_THRESHOLD_ATC 80 /* kHz */
+
+enum FAT_STATE {
+ FAT_NORMAL_STATE = 0,
+ FAT_TRAINING_STATE = 1,
+};
+
+enum tag_dynamic_init_gain_operation_type_definition {
+ DIG_TYPE_THRESH_HIGH = 0,
+ DIG_TYPE_THRESH_LOW = 1,
+ DIG_TYPE_BACKOFF = 2,
+ DIG_TYPE_RX_GAIN_MIN = 3,
+ DIG_TYPE_RX_GAIN_MAX = 4,
+ DIG_TYPE_ENABLE = 5,
+ DIG_TYPE_DISABLE = 6,
+ DIG_OP_TYPE_MAX
+};
+
+enum dm_1r_cca_e {
+ CCA_1R = 0,
+ CCA_2R = 1,
+ CCA_MAX = 2,
+};
+
+enum dm_rf_e {
+ RF_SAVE = 0,
+ RF_NORMAL = 1,
+ RF_MAX = 2,
+};
+
+enum dm_sw_ant_switch_e {
+ ANS_ANTENNA_B = 1,
+ ANS_ANTENNA_A = 2,
+ ANS_ANTENNA_MAX = 3,
+};
+
+enum dm_dig_ext_port_alg_e {
+ DIG_EXT_PORT_STAGE_0 = 0,
+ DIG_EXT_PORT_STAGE_1 = 1,
+ DIG_EXT_PORT_STAGE_2 = 2,
+ DIG_EXT_PORT_STAGE_3 = 3,
+ DIG_EXT_PORT_STAGE_MAX = 4,
+};
+
+enum dm_dig_connect_e {
+ DIG_STA_DISCONNECT = 0,
+ DIG_STA_CONNECT = 1,
+ DIG_STA_BEFORE_CONNECT = 2,
+ DIG_MULTISTA_DISCONNECT = 3,
+ DIG_MULTISTA_CONNECT = 4,
+ DIG_CONNECT_MAX
+};
+
+enum pwr_track_control_method {
+ BBSWING,
+ TXAGC
+};
+
+#define BT_RSSI_STATE_NORMAL_POWER BIT_OFFSET_LEN_MASK_32(0, 1)
+#define BT_RSSI_STATE_AMDPU_OFF BIT_OFFSET_LEN_MASK_32(1, 1)
+#define BT_RSSI_STATE_SPECIAL_LOW BIT_OFFSET_LEN_MASK_32(2, 1)
+#define BT_RSSI_STATE_BG_EDCA_LOW BIT_OFFSET_LEN_MASK_32(3, 1)
+#define BT_RSSI_STATE_TXPOWER_LOW BIT_OFFSET_LEN_MASK_32(4, 1)
+
+void rtl8723be_dm_set_tx_ant_by_tx_info(struct ieee80211_hw *hw, u8 *pdesc,
+ u32 mac_id);
+void rtl8723be_dm_ant_sel_statistics(struct ieee80211_hw *hw, u8 antsel_tr_mux,
+ u32 mac_id, u32 rx_pwdb_all);
+void rtl8723be_dm_fast_antenna_trainning_callback(unsigned long data);
+void rtl8723be_dm_init(struct ieee80211_hw *hw);
+void rtl8723be_dm_watchdog(struct ieee80211_hw *hw);
+void rtl8723be_dm_write_dig(struct ieee80211_hw *hw, u8 current_igi);
+void rtl8723be_dm_check_txpower_tracking(struct ieee80211_hw *hw);
+void rtl8723be_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw);
+void rtl8723be_dm_txpower_track_adjust(struct ieee80211_hw *hw, u8 type,
+ u8 *pdirection, u32 *poutwrite_val);
+void rtl8723be_dm_init_edca_turbo(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/fw.c b/drivers/net/wireless/rtlwifi/rtl8723be/fw.c
new file mode 100644
index 000000000000..f856be6fc138
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/fw.c
@@ -0,0 +1,620 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "reg.h"
+#include "def.h"
+#include "fw.h"
+#include "../rtl8723com/fw_common.h"
+
+static bool _rtl8723be_check_fw_read_last_h2c(struct ieee80211_hw *hw,
+ u8 boxnum)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 val_hmetfr;
+ bool result = false;
+
+ val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
+ if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
+ result = true;
+ return result;
+}
+
+static void _rtl8723be_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id,
+ u32 cmd_len, u8 *p_cmdbuffer)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 boxnum;
+ u16 box_reg = 0, box_extreg = 0;
+ u8 u1b_tmp;
+ bool isfw_read = false;
+ u8 buf_index = 0;
+ bool bwrite_sucess = false;
+ u8 wait_h2c_limit = 100;
+ u8 wait_writeh2c_limit = 100;
+ u8 boxcontent[4], boxextcontent[4];
+ u32 h2c_waitcounter = 0;
+ unsigned long flag;
+ u8 idx;
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
+
+ while (true) {
+ spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
+ if (rtlhal->h2c_setinprogress) {
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "H2C set in progress! Wait to set.."
+ "element_id(%d).\n", element_id);
+
+ while (rtlhal->h2c_setinprogress) {
+ spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
+ flag);
+ h2c_waitcounter++;
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "Wait 100 us (%d times)...\n",
+ h2c_waitcounter);
+ udelay(100);
+
+ if (h2c_waitcounter > 1000)
+ return;
+ spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
+ flag);
+ }
+ spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+ } else {
+ rtlhal->h2c_setinprogress = true;
+ spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+ break;
+ }
+ }
+ while (!bwrite_sucess) {
+ wait_writeh2c_limit--;
+ if (wait_writeh2c_limit == 0) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Write H2C fail because no trigger "
+ "for FW INT!\n");
+ break;
+ }
+ boxnum = rtlhal->last_hmeboxnum;
+ switch (boxnum) {
+ case 0:
+ box_reg = REG_HMEBOX_0;
+ box_extreg = REG_HMEBOX_EXT_0;
+ break;
+ case 1:
+ box_reg = REG_HMEBOX_1;
+ box_extreg = REG_HMEBOX_EXT_1;
+ break;
+ case 2:
+ box_reg = REG_HMEBOX_2;
+ box_extreg = REG_HMEBOX_EXT_2;
+ break;
+ case 3:
+ box_reg = REG_HMEBOX_3;
+ box_extreg = REG_HMEBOX_EXT_3;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ break;
+ }
+ isfw_read = _rtl8723be_check_fw_read_last_h2c(hw, boxnum);
+ while (!isfw_read) {
+ wait_h2c_limit--;
+ if (wait_h2c_limit == 0) {
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "Wating too long for FW read "
+ "clear HMEBox(%d)!\n", boxnum);
+ break;
+ }
+ udelay(10);
+
+ isfw_read = _rtl8723be_check_fw_read_last_h2c(hw,
+ boxnum);
+ u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "Wating for FW read clear HMEBox(%d)!!! 0x130 = %2x\n",
+ boxnum, u1b_tmp);
+ }
+ if (!isfw_read) {
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "Write H2C register BOX[%d] fail!!!!! "
+ "Fw do not read.\n", boxnum);
+ break;
+ }
+ memset(boxcontent, 0, sizeof(boxcontent));
+ memset(boxextcontent, 0, sizeof(boxextcontent));
+ boxcontent[0] = element_id;
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "Write element_id box_reg(%4x) = %2x\n",
+ box_reg, element_id);
+
+ switch (cmd_len) {
+ case 1:
+ case 2:
+ case 3:
+ /*boxcontent[0] &= ~(BIT(7));*/
+ memcpy((u8 *)(boxcontent) + 1,
+ p_cmdbuffer + buf_index, cmd_len);
+
+ for (idx = 0; idx < 4; idx++) {
+ rtl_write_byte(rtlpriv, box_reg + idx,
+ boxcontent[idx]);
+ }
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ /*boxcontent[0] |= (BIT(7));*/
+ memcpy((u8 *)(boxextcontent),
+ p_cmdbuffer + buf_index+3, cmd_len-3);
+ memcpy((u8 *)(boxcontent) + 1,
+ p_cmdbuffer + buf_index, 3);
+
+ for (idx = 0; idx < 4; idx++) {
+ rtl_write_byte(rtlpriv, box_extreg + idx,
+ boxextcontent[idx]);
+ }
+ for (idx = 0; idx < 4; idx++) {
+ rtl_write_byte(rtlpriv, box_reg + idx,
+ boxcontent[idx]);
+ }
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not process\n");
+ break;
+ }
+ bwrite_sucess = true;
+
+ rtlhal->last_hmeboxnum = boxnum + 1;
+ if (rtlhal->last_hmeboxnum == 4)
+ rtlhal->last_hmeboxnum = 0;
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "pHalData->last_hmeboxnum = %d\n",
+ rtlhal->last_hmeboxnum);
+ }
+ spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
+ rtlhal->h2c_setinprogress = false;
+ spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
+}
+
+void rtl8723be_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,
+ u32 cmd_len, u8 *p_cmdbuffer)
+{
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u32 tmp_cmdbuf[2];
+
+ if (!rtlhal->fw_ready) {
+ RT_ASSERT(false,
+ "return H2C cmd because of Fw download fail!!!\n");
+ return;
+ }
+ memset(tmp_cmdbuf, 0, 8);
+ memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
+ _rtl8723be_fill_h2c_command(hw, element_id, cmd_len,
+ (u8 *)&tmp_cmdbuf);
+ return;
+}
+
+void rtl8723be_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 u1_h2c_set_pwrmode[H2C_8723BE_PWEMODE_LENGTH] = { 0 };
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ u8 rlbm, power_state = 0;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
+
+ SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
+ rlbm = 0;/*YJ, temp, 120316. FW now not support RLBM = 2.*/
+ SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm);
+ SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
+ (rtlpriv->mac80211.p2p) ?
+ ppsc->smart_ps : 1);
+ SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
+ ppsc->reg_max_lps_awakeintvl);
+ SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
+ if (mode == FW_PS_ACTIVE_MODE)
+ power_state |= FW_PWR_STATE_ACTIVE;
+ else
+ power_state |= FW_PWR_STATE_RF_OFF;
+ SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
+
+ RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+ "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
+ u1_h2c_set_pwrmode, H2C_8723BE_PWEMODE_LENGTH);
+ rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_SETPWRMODE,
+ H2C_8723BE_PWEMODE_LENGTH,
+ u1_h2c_set_pwrmode);
+}
+
+static bool _rtl8723be_cmd_send_packet(struct ieee80211_hw *hw,
+ struct sk_buff *skb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl8192_tx_ring *ring;
+ struct rtl_tx_desc *pdesc;
+ struct sk_buff *pskb = NULL;
+ u8 own;
+ unsigned long flags;
+
+ ring = &rtlpci->tx_ring[BEACON_QUEUE];
+
+ pskb = __skb_dequeue(&ring->queue);
+ if (pskb)
+ kfree_skb(pskb);
+
+ spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+
+ pdesc = &ring->desc[0];
+ own = (u8) rtlpriv->cfg->ops->get_desc((u8 *)pdesc, true, HW_DESC_OWN);
+
+ rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb);
+
+ __skb_queue_tail(&ring->queue, skb);
+
+ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+
+ rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
+
+ return true;
+}
+#define BEACON_PG 0 /* ->1 */
+#define PSPOLL_PG 2
+#define NULL_PG 3
+#define PROBERSP_PG 4 /* ->5 */
+
+#define TOTAL_RESERVED_PKT_LEN 768
+
+static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
+ /* page 0 beacon */
+ 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
+ 0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x20, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x10, 0x04, 0x00, 0x05, 0x54, 0x65,
+ 0x73, 0x74, 0x32, 0x01, 0x08, 0x82, 0x84, 0x0B,
+ 0x16, 0x24, 0x30, 0x48, 0x6C, 0x03, 0x01, 0x06,
+ 0x06, 0x02, 0x00, 0x00, 0x2A, 0x01, 0x02, 0x32,
+ 0x04, 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C,
+ 0x09, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3D, 0x00, 0xDD, 0x07, 0x00, 0xE0, 0x4C,
+ 0x02, 0x02, 0x00, 0x00, 0xDD, 0x18, 0x00, 0x50,
+ 0xF2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xF2, 0x04,
+ 0x01, 0x00, 0x00, 0x50, 0xF2, 0x04, 0x01, 0x00,
+
+ /* page 1 beacon */
+ 0x00, 0x50, 0xF2, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* page 2 ps-poll */
+ 0xA4, 0x10, 0x01, 0xC0, 0xEC, 0x1A, 0x59, 0x0B,
+ 0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* page 3 null */
+ 0x48, 0x01, 0x00, 0x00, 0xEC, 0x1A, 0x59, 0x0B,
+ 0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
+ 0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x72, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* page 4 probe_resp */
+ 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
+ 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
+ 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
+ 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
+ 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
+ 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
+ 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
+ 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
+ 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
+ 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
+ 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* page 5 probe_resp */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+void rtl8723be_set_fw_rsvdpagepkt(struct ieee80211_hw *hw,
+ bool dl_finished)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct sk_buff *skb = NULL;
+
+ u32 totalpacketlen;
+ bool rtstatus;
+ u8 u1rsvdpageloc[5] = { 0 };
+ bool dlok = false;
+
+ u8 *beacon;
+ u8 *p_pspoll;
+ u8 *nullfunc;
+ u8 *p_probersp;
+ /*---------------------------------------------------------
+ * (1) beacon
+ *---------------------------------------------------------
+ */
+ beacon = &reserved_page_packet[BEACON_PG * 128];
+ SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
+ SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
+
+ /*-------------------------------------------------------
+ * (2) ps-poll
+ *-------------------------------------------------------
+ */
+ p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
+ SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
+ SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
+ SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
+
+ SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
+
+ /*--------------------------------------------------------
+ * (3) null data
+ *--------------------------------------------------------
+ */
+ nullfunc = &reserved_page_packet[NULL_PG * 128];
+ SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
+ SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
+ SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
+
+ SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
+
+ /*---------------------------------------------------------
+ * (4) probe response
+ *---------------------------------------------------------
+ */
+ p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
+ SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
+ SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
+ SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
+
+ SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
+
+ totalpacketlen = TOTAL_RESERVED_PKT_LEN;
+
+ RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
+ "rtl8723be_set_fw_rsvdpagepkt(): "
+ "HW_VAR_SET_TX_CMD: ALL\n",
+ &reserved_page_packet[0], totalpacketlen);
+ RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+ "rtl8723be_set_fw_rsvdpagepkt(): "
+ "HW_VAR_SET_TX_CMD: ALL\n", u1rsvdpageloc, 3);
+
+
+ skb = dev_alloc_skb(totalpacketlen);
+ memcpy((u8 *)skb_put(skb, totalpacketlen),
+ &reserved_page_packet, totalpacketlen);
+
+ rtstatus = _rtl8723be_cmd_send_packet(hw, skb);
+
+ if (rtstatus)
+ dlok = true;
+
+ if (dlok) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "Set RSVD page location to Fw.\n");
+ RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, "H2C_RSVDPAGE:\n",
+ u1rsvdpageloc, 3);
+ rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_RSVDPAGE,
+ sizeof(u1rsvdpageloc), u1rsvdpageloc);
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "Set RSVD page location to Fw FAIL!!!!!!.\n");
+ }
+}
+
+/*Should check FW support p2p or not.*/
+static void rtl8723be_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw,
+ u8 ctwindow)
+{
+ u8 u1_ctwindow_period[1] = {ctwindow};
+
+ rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_P2P_PS_CTW_CMD, 1,
+ u1_ctwindow_period);
+}
+
+void rtl8723be_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw,
+ u8 p2p_ps_state)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
+ struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
+ u8 i;
+ u16 ctwindow;
+ u32 start_time, tsf_low;
+
+ switch (p2p_ps_state) {
+ case P2P_PS_DISABLE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
+ memset(p2p_ps_offload, 0, sizeof(struct p2p_ps_offload_t));
+ break;
+ case P2P_PS_ENABLE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
+ /* update CTWindow value. */
+ if (p2pinfo->ctwindow > 0) {
+ p2p_ps_offload->ctwindow_en = 1;
+ ctwindow = p2pinfo->ctwindow;
+ rtl8723be_set_p2p_ctw_period_cmd(hw, ctwindow);
+ }
+ /* hw only support 2 set of NoA */
+ for (i = 0; i < p2pinfo->noa_num; i++) {
+ /* To control the register setting
+ * for which NOA
+ */
+ rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
+ if (i == 0)
+ p2p_ps_offload->noa0_en = 1;
+ else
+ p2p_ps_offload->noa1_en = 1;
+
+ /* config P2P NoA Descriptor Register */
+ rtl_write_dword(rtlpriv, 0x5E0,
+ p2pinfo->noa_duration[i]);
+ rtl_write_dword(rtlpriv, 0x5E4,
+ p2pinfo->noa_interval[i]);
+
+ /*Get Current TSF value */
+ tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+
+ start_time = p2pinfo->noa_start_time[i];
+ if (p2pinfo->noa_count_type[i] != 1) {
+ while (start_time <= (tsf_low + (50 * 1024))) {
+ start_time += p2pinfo->noa_interval[i];
+ if (p2pinfo->noa_count_type[i] != 255)
+ p2pinfo->noa_count_type[i]--;
+ }
+ }
+ rtl_write_dword(rtlpriv, 0x5E8, start_time);
+ rtl_write_dword(rtlpriv, 0x5EC,
+ p2pinfo->noa_count_type[i]);
+ }
+ if ((p2pinfo->opp_ps == 1) ||
+ (p2pinfo->noa_num > 0)) {
+ /* rst p2p circuit */
+ rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
+
+ p2p_ps_offload->offload_en = 1;
+
+ if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
+ 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:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
+ p2p_ps_offload->discovery = 1;
+ break;
+ case P2P_PS_SCAN_DONE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
+ p2p_ps_offload->discovery = 0;
+ p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
+ break;
+ default:
+ break;
+ }
+ rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_P2P_PS_OFFLOAD, 1,
+ (u8 *)p2p_ps_offload);
+}
+
+void rtl8723be_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
+{
+ u8 u1_joinbssrpt_parm[1] = { 0 };
+
+ SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
+
+ rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_JOINBSSRPT, 1,
+ u1_joinbssrpt_parm);
+}
+
+void rtl8723be_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw,
+ u8 ap_offload_enable)
+{
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u8 u1_apoffload_parm[H2C_8723BE_AP_OFFLOAD_LENGTH] = { 0 };
+
+ SET_H2CCMD_AP_OFFLOAD_ON(u1_apoffload_parm, ap_offload_enable);
+ SET_H2CCMD_AP_OFFLOAD_HIDDEN(u1_apoffload_parm, mac->hiddenssid);
+ SET_H2CCMD_AP_OFFLOAD_DENYANY(u1_apoffload_parm, 0);
+
+ rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_AP_OFFLOAD,
+ H2C_8723BE_AP_OFFLOAD_LENGTH, u1_apoffload_parm);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/fw.h b/drivers/net/wireless/rtlwifi/rtl8723be/fw.h
new file mode 100644
index 000000000000..31eec281e446
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/fw.h
@@ -0,0 +1,248 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE__FW__H__
+#define __RTL8723BE__FW__H__
+
+#define FW_8192C_SIZE 0x8000
+#define FW_8192C_START_ADDRESS 0x1000
+#define FW_8192C_END_ADDRESS 0x5FFF
+#define FW_8192C_PAGE_SIZE 4096
+#define FW_8192C_POLLING_DELAY 5
+#define FW_8192C_POLLING_TIMEOUT_COUNT 6000
+
+#define IS_FW_HEADER_EXIST(_pfwhdr) \
+ ((_pfwhdr->signature&0xFFF0) == 0x5300)
+#define USE_OLD_WOWLAN_DEBUG_FW 0
+
+#define H2C_8723BE_RSVDPAGE_LOC_LEN 5
+#define H2C_8723BE_PWEMODE_LENGTH 5
+#define H2C_8723BE_JOINBSSRPT_LENGTH 1
+#define H2C_8723BE_AP_OFFLOAD_LENGTH 3
+#define H2C_8723BE_WOWLAN_LENGTH 3
+#define H2C_8723BE_KEEP_ALIVE_CTRL_LENGTH 3
+#if (USE_OLD_WOWLAN_DEBUG_FW == 0)
+#define H2C_8723BE_REMOTE_WAKE_CTRL_LEN 1
+#else
+#define H2C_8723BE_REMOTE_WAKE_CTRL_LEN 3
+#endif
+#define H2C_8723BE_AOAC_GLOBAL_INFO_LEN 2
+#define H2C_8723BE_AOAC_RSVDPAGE_LOC_LEN 7
+
+
+/* Fw PS state for RPWM.
+*BIT[2:0] = HW state
+*BIT[3] = Protocol PS state, 1: register active state , 0: register sleep state
+*BIT[4] = sub-state
+*/
+#define FW_PS_GO_ON BIT(0)
+#define FW_PS_TX_NULL BIT(1)
+#define FW_PS_RF_ON BIT(2)
+#define FW_PS_REGISTER_ACTIVE BIT(3)
+
+#define FW_PS_DPS BIT(0)
+#define FW_PS_LCLK (FW_PS_DPS)
+#define FW_PS_RF_OFF BIT(1)
+#define FW_PS_ALL_ON BIT(2)
+#define FW_PS_ST_ACTIVE BIT(3)
+#define FW_PS_ISR_ENABLE BIT(4)
+#define FW_PS_IMR_ENABLE BIT(5)
+
+
+#define FW_PS_ACK BIT(6)
+#define FW_PS_TOGGLE BIT(7)
+
+ /* 88E RPWM value*/
+ /* BIT[0] = 1: 32k, 0: 40M*/
+#define FW_PS_CLOCK_OFF BIT(0) /* 32k*/
+#define FW_PS_CLOCK_ON 0 /*40M*/
+
+#define FW_PS_STATE_MASK (0x0F)
+#define FW_PS_STATE_HW_MASK (0x07)
+/*ISR_ENABLE, IMR_ENABLE, and PS mode should be inherited.*/
+#define FW_PS_STATE_INT_MASK (0x3F)
+
+#define FW_PS_STATE(x) (FW_PS_STATE_MASK & (x))
+#define FW_PS_STATE_HW(x) (FW_PS_STATE_HW_MASK & (x))
+#define FW_PS_STATE_INT(x) (FW_PS_STATE_INT_MASK & (x))
+#define FW_PS_ISR_VAL(x) ((x) & 0x70)
+#define FW_PS_IMR_MASK(x) ((x) & 0xDF)
+#define FW_PS_KEEP_IMR(x) ((x) & 0x20)
+
+
+#define FW_PS_STATE_S0 (FW_PS_DPS)
+#define FW_PS_STATE_S1 (FW_PS_LCLK)
+#define FW_PS_STATE_S2 (FW_PS_RF_OFF)
+#define FW_PS_STATE_S3 (FW_PS_ALL_ON)
+#define FW_PS_STATE_S4 ((FW_PS_ST_ACTIVE) | (FW_PS_ALL_ON))
+
+/* ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))*/
+#define FW_PS_STATE_ALL_ON_88E (FW_PS_CLOCK_ON)
+/* (FW_PS_RF_ON)*/
+#define FW_PS_STATE_RF_ON_88E (FW_PS_CLOCK_ON)
+/* 0x0*/
+#define FW_PS_STATE_RF_OFF_88E (FW_PS_CLOCK_ON)
+/* (FW_PS_STATE_RF_OFF)*/
+#define FW_PS_STATE_RF_OFF_LOW_PWR_88E (FW_PS_CLOCK_OFF)
+
+#define FW_PS_STATE_ALL_ON_92C (FW_PS_STATE_S4)
+#define FW_PS_STATE_RF_ON_92C (FW_PS_STATE_S3)
+#define FW_PS_STATE_RF_OFF_92C (FW_PS_STATE_S2)
+#define FW_PS_STATE_RF_OFF_LOW_PWR_92C (FW_PS_STATE_S1)
+
+
+/* For 88E H2C PwrMode Cmd ID 5.*/
+#define FW_PWR_STATE_ACTIVE ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))
+#define FW_PWR_STATE_RF_OFF 0
+
+#define FW_PS_IS_ACK(x) ((x) & FW_PS_ACK)
+#define FW_PS_IS_CLK_ON(x) ((x) & (FW_PS_RF_OFF | FW_PS_ALL_ON))
+#define FW_PS_IS_RF_ON(x) ((x) & (FW_PS_ALL_ON))
+#define FW_PS_IS_ACTIVE(x) ((x) & (FW_PS_ST_ACTIVE))
+#define FW_PS_IS_CPWM_INT(x) ((x) & 0x40)
+
+#define FW_CLR_PS_STATE(x) ((x) = ((x) & (0xF0)))
+
+#define IS_IN_LOW_POWER_STATE_88E(fwpsstate) \
+ (FW_PS_STATE(fwpsstate) == FW_PS_CLOCK_OFF)
+
+#define FW_PWR_STATE_ACTIVE ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))
+#define FW_PWR_STATE_RF_OFF 0
+
+#define pagenum_128(_len) (u32)(((_len)>>7) + ((_len)&0x7F ? 1 : 0))
+
+#define SET_88E_H2CCMD_WOWLAN_FUNC_ENABLE(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 1, __val)
+#define SET_88E_H2CCMD_WOWLAN_PATTERN_MATCH_ENABLE(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 1, 1, __val)
+#define SET_88E_H2CCMD_WOWLAN_MAGIC_PKT_ENABLE(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 2, 1, __val)
+#define SET_88E_H2CCMD_WOWLAN_UNICAST_PKT_ENABLE(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 3, 1, __val)
+#define SET_88E_H2CCMD_WOWLAN_ALL_PKT_DROP(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 4, 1, __val)
+#define SET_88E_H2CCMD_WOWLAN_GPIO_ACTIVE(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 5, 1, __val)
+#define SET_88E_H2CCMD_WOWLAN_REKEY_WAKE_UP(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 6, 1, __val)
+#define SET_88E_H2CCMD_WOWLAN_DISCONNECT_WAKE_UP(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 7, 1, __val)
+#define SET_88E_H2CCMD_WOWLAN_GPIONUM(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+#define SET_88E_H2CCMD_WOWLAN_GPIO_DURATION(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+
+
+#define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_PWRMODE_PARM_RLBM(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 4, __val)
+#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 4, 4, __val)
+#define SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+#define SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+3, 0, 8, __val)
+#define SET_H2CCMD_PWRMODE_PARM_PWR_STATE(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+4, 0, 8, __val)
+#define GET_88E_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd) \
+ LE_BITS_TO_1BYTE(__ph2ccmd, 0, 8)
+
+#define SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+
+/* AP_OFFLOAD */
+#define SET_H2CCMD_AP_OFFLOAD_ON(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_AP_OFFLOAD_HIDDEN(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+#define SET_H2CCMD_AP_OFFLOAD_DENYANY(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+#define SET_H2CCMD_AP_OFFLOAD_WAKEUP_EVT_RPT(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+3, 0, 8, __val)
+
+/* Keep Alive Control*/
+#define SET_88E_H2CCMD_KEEP_ALIVE_ENABLE(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 1, __val)
+#define SET_88E_H2CCMD_KEEP_ALIVE_ACCPEPT_USER_DEFINED(__ph2ccmd, __val)\
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 1, 1, __val)
+#define SET_88E_H2CCMD_KEEP_ALIVE_PERIOD(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+
+/*REMOTE_WAKE_CTRL */
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_EN(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 1, __val)
+#if (USE_OLD_WOWLAN_DEBUG_FW == 0)
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_ARP_OFFLOAD_EN(__ph2ccmd, __val)\
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 1, 1, __val)
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_NDP_OFFLOAD_EN(__ph2ccmd, __val)\
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 2, 1, __val)
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_GTK_OFFLOAD_EN(__ph2ccmd, __val)\
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 3, 1, __val)
+#else
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_PAIRWISE_ENC_ALG(__ph2ccmd, __val)\
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_GROUP_ENC_ALG(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+#endif
+
+/* GTK_OFFLOAD */
+#define SET_88E_H2CCMD_AOAC_GLOBAL_INFO_PAIRWISE_ENC_ALG(__ph2ccmd, __val)\
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_88E_H2CCMD_AOAC_GLOBAL_INFO_GROUP_ENC_ALG(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+
+/* AOAC_RSVDPAGE_LOC */
+#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_REM_WAKE_CTRL_INFO(__ph2ccmd, __val)\
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd), 0, 8, __val)
+#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_ARP_RSP(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_NEIGHBOR_ADV(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_RSP(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+3, 0, 8, __val)
+#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_INFO(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+4, 0, 8, __val)
+
+void rtl8723be_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
+void rtl8723be_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw,
+ u8 ap_offload_enable);
+void rtl8723be_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,
+ u32 cmd_len, u8 *p_cmdbuffer);
+void rtl8723be_firmware_selfreset(struct ieee80211_hw *hw);
+void rtl8723be_set_fw_rsvdpagepkt(struct ieee80211_hw *hw,
+ bool dl_finished);
+void rtl8723be_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
+int rtl8723be_download_fw(struct ieee80211_hw *hw,
+ bool buse_wake_on_wlan_fw);
+void rtl8723be_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw,
+ u8 p2p_ps_state);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c
new file mode 100644
index 000000000000..0fdf0909321f
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c
@@ -0,0 +1,2523 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../efuse.h"
+#include "../base.h"
+#include "../regd.h"
+#include "../cam.h"
+#include "../ps.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "../rtl8723com/dm_common.h"
+#include "fw.h"
+#include "../rtl8723com/fw_common.h"
+#include "led.h"
+#include "hw.h"
+#include "pwrseq.h"
+#include "../btcoexist/rtl_btc.h"
+
+#define LLT_CONFIG 5
+
+static void _rtl8723be_return_beacon_queue_skb(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE];
+
+ while (skb_queue_len(&ring->queue)) {
+ struct rtl_tx_desc *entry = &ring->desc[ring->idx];
+ struct sk_buff *skb = __skb_dequeue(&ring->queue);
+
+ pci_unmap_single(rtlpci->pdev,
+ rtlpriv->cfg->ops->get_desc(
+ (u8 *)entry, true, HW_DESC_TXBUFF_ADDR),
+ skb->len, PCI_DMA_TODEVICE);
+ kfree_skb(skb);
+ ring->idx = (ring->idx + 1) % ring->entries;
+ }
+}
+
+static void _rtl8723be_set_bcn_ctrl_reg(struct ieee80211_hw *hw,
+ u8 set_bits, u8 clear_bits)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpci->reg_bcn_ctrl_val |= set_bits;
+ rtlpci->reg_bcn_ctrl_val &= ~clear_bits;
+
+ rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlpci->reg_bcn_ctrl_val);
+}
+
+static void _rtl8723be_stop_tx_beacon(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 tmp1byte;
+
+ tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2);
+ rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte & (~BIT(6)));
+ rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0x64);
+ tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2);
+ tmp1byte &= ~(BIT(0));
+ rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte);
+}
+
+static void _rtl8723be_resume_tx_beacon(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 tmp1byte;
+
+ tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2);
+ rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte | BIT(6));
+ rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff);
+ tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2);
+ tmp1byte |= BIT(1);
+ rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte);
+}
+
+static void _rtl8723be_enable_bcn_sub_func(struct ieee80211_hw *hw)
+{
+ _rtl8723be_set_bcn_ctrl_reg(hw, 0, BIT(1));
+}
+
+static void _rtl8723be_disable_bcn_sub_func(struct ieee80211_hw *hw)
+{
+ _rtl8723be_set_bcn_ctrl_reg(hw, BIT(1), 0);
+}
+
+static void _rtl8723be_set_fw_clock_on(struct ieee80211_hw *hw, u8 rpwm_val,
+ bool need_turn_off_ckk)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ bool support_remote_wake_up;
+ u32 count = 0, isr_regaddr, content;
+ bool schedule_timer = need_turn_off_ckk;
+ rtlpriv->cfg->ops->get_hw_reg(hw, HAL_DEF_WOWLAN,
+ (u8 *)(&support_remote_wake_up));
+
+ if (!rtlhal->fw_ready)
+ return;
+ if (!rtlpriv->psc.fw_current_inpsmode)
+ return;
+
+ while (1) {
+ spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+ if (rtlhal->fw_clk_change_in_progress) {
+ while (rtlhal->fw_clk_change_in_progress) {
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ count++;
+ udelay(100);
+ if (count > 1000)
+ return;
+ spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+ }
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ } else {
+ rtlhal->fw_clk_change_in_progress = false;
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ break;
+ }
+ }
+ if (IS_IN_LOW_POWER_STATE_88E(rtlhal->fw_ps_state)) {
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_SET_RPWM,
+ &rpwm_val);
+ if (FW_PS_IS_ACK(rpwm_val)) {
+ isr_regaddr = REG_HISR;
+ content = rtl_read_dword(rtlpriv, isr_regaddr);
+ while (!(content & IMR_CPWM) && (count < 500)) {
+ udelay(50);
+ count++;
+ content = rtl_read_dword(rtlpriv, isr_regaddr);
+ }
+
+ if (content & IMR_CPWM) {
+ rtl_write_word(rtlpriv, isr_regaddr, 0x0100);
+ rtlhal->fw_ps_state = FW_PS_STATE_RF_ON_88E;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "Receive CPWM INT!!! Set "
+ "pHalData->FwPSState = %X\n",
+ rtlhal->fw_ps_state);
+ }
+ }
+ spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+ rtlhal->fw_clk_change_in_progress = false;
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ if (schedule_timer) {
+ mod_timer(&rtlpriv->works.fw_clockoff_timer,
+ jiffies + MSECS(10));
+ }
+ } else {
+ spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+ rtlhal->fw_clk_change_in_progress = false;
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ }
+}
+
+static void _rtl8723be_set_fw_clock_off(struct ieee80211_hw *hw, u8 rpwm_val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl8192_tx_ring *ring;
+ enum rf_pwrstate rtstate;
+ bool schedule_timer = false;
+ u8 queue;
+
+ if (!rtlhal->fw_ready)
+ return;
+ if (!rtlpriv->psc.fw_current_inpsmode)
+ return;
+ if (!rtlhal->allow_sw_to_change_hwclc)
+ return;
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RF_STATE, (u8 *)(&rtstate));
+ if (rtstate == ERFOFF || rtlpriv->psc.inactive_pwrstate == ERFOFF)
+ return;
+
+ for (queue = 0; queue < RTL_PCI_MAX_TX_QUEUE_COUNT; queue++) {
+ ring = &rtlpci->tx_ring[queue];
+ if (skb_queue_len(&ring->queue)) {
+ schedule_timer = true;
+ break;
+ }
+ }
+ if (schedule_timer) {
+ mod_timer(&rtlpriv->works.fw_clockoff_timer,
+ jiffies + MSECS(10));
+ return;
+ }
+ if (FW_PS_STATE(rtlhal->fw_ps_state) !=
+ FW_PS_STATE_RF_OFF_LOW_PWR_88E) {
+ spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+ if (!rtlhal->fw_clk_change_in_progress) {
+ rtlhal->fw_clk_change_in_progress = true;
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ rtlhal->fw_ps_state = FW_PS_STATE(rpwm_val);
+ rtl_write_word(rtlpriv, REG_HISR, 0x0100);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+ &rpwm_val);
+ spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+ rtlhal->fw_clk_change_in_progress = false;
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ } else {
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ mod_timer(&rtlpriv->works.fw_clockoff_timer,
+ jiffies + MSECS(10));
+ }
+ }
+}
+
+static void _rtl8723be_set_fw_ps_rf_on(struct ieee80211_hw *hw)
+{
+ u8 rpwm_val = 0;
+ rpwm_val |= (FW_PS_STATE_RF_OFF_88E | FW_PS_ACK);
+ _rtl8723be_set_fw_clock_on(hw, rpwm_val, true);
+}
+
+static void _rtl8723be_fwlps_leave(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ bool fw_current_inps = false;
+ u8 rpwm_val = 0, fw_pwrmode = FW_PS_ACTIVE_MODE;
+
+ if (ppsc->low_power_enable) {
+ rpwm_val = (FW_PS_STATE_ALL_ON_88E | FW_PS_ACK);/* RF on */
+ _rtl8723be_set_fw_clock_on(hw, rpwm_val, false);
+ rtlhal->allow_sw_to_change_hwclc = false;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+ &fw_pwrmode);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ } else {
+ rpwm_val = FW_PS_STATE_ALL_ON_88E; /* RF on */
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, &rpwm_val);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+ &fw_pwrmode);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ }
+}
+
+static void _rtl8723be_fwlps_enter(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ bool fw_current_inps = true;
+ u8 rpwm_val;
+
+ if (ppsc->low_power_enable) {
+ rpwm_val = FW_PS_STATE_RF_OFF_LOW_PWR_88E; /* RF off */
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+ &ppsc->fwctrl_psmode);
+ rtlhal->allow_sw_to_change_hwclc = true;
+ _rtl8723be_set_fw_clock_off(hw, rpwm_val);
+
+ } else {
+ rpwm_val = FW_PS_STATE_RF_OFF_88E; /* RF off */
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+ &ppsc->fwctrl_psmode);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, &rpwm_val);
+ }
+}
+
+void rtl8723be_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ switch (variable) {
+ case HW_VAR_RCR:
+ *((u32 *)(val)) = rtlpci->receive_config;
+ break;
+ case HW_VAR_RF_STATE:
+ *((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state;
+ break;
+ case HW_VAR_FWLPS_RF_ON: {
+ enum rf_pwrstate rfstate;
+ u32 val_rcr;
+
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RF_STATE,
+ (u8 *)(&rfstate));
+ if (rfstate == ERFOFF) {
+ *((bool *)(val)) = true;
+ } else {
+ val_rcr = rtl_read_dword(rtlpriv, REG_RCR);
+ val_rcr &= 0x00070000;
+ if (val_rcr)
+ *((bool *)(val)) = false;
+ else
+ *((bool *)(val)) = true;
+ }
+ break; }
+ case HW_VAR_FW_PSMODE_STATUS:
+ *((bool *)(val)) = ppsc->fw_current_inpsmode;
+ break;
+ case HW_VAR_CORRECT_TSF: {
+ u64 tsf;
+ u32 *ptsf_low = (u32 *)&tsf;
+ u32 *ptsf_high = ((u32 *)&tsf) + 1;
+
+ *ptsf_high = rtl_read_dword(rtlpriv, (REG_TSFTR + 4));
+ *ptsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+
+ *((u64 *)(val)) = tsf;
+
+ break; }
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not process %x\n", variable);
+ break;
+ }
+}
+
+void rtl8723be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ u8 idx;
+
+ switch (variable) {
+ case HW_VAR_ETHER_ADDR:
+ for (idx = 0; idx < ETH_ALEN; idx++)
+ rtl_write_byte(rtlpriv, (REG_MACID + idx), val[idx]);
+ break;
+ case HW_VAR_BASIC_RATE: {
+ u16 rate_cfg = ((u16 *)val)[0];
+ u8 rate_index = 0;
+ rate_cfg = rate_cfg & 0x15f;
+ rate_cfg |= 0x01;
+ rtl_write_byte(rtlpriv, REG_RRSR, rate_cfg & 0xff);
+ rtl_write_byte(rtlpriv, REG_RRSR + 1, (rate_cfg >> 8) & 0xff);
+ while (rate_cfg > 0x1) {
+ rate_cfg = (rate_cfg >> 1);
+ rate_index++;
+ }
+ rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, rate_index);
+ break; }
+ case HW_VAR_BSSID:
+ for (idx = 0; idx < ETH_ALEN; idx++)
+ rtl_write_byte(rtlpriv, (REG_BSSID + idx), val[idx]);
+ break;
+ case HW_VAR_SIFS:
+ rtl_write_byte(rtlpriv, REG_SIFS_CTX + 1, val[0]);
+ rtl_write_byte(rtlpriv, REG_SIFS_TRX + 1, val[1]);
+
+ rtl_write_byte(rtlpriv, REG_SPEC_SIFS + 1, val[0]);
+ rtl_write_byte(rtlpriv, REG_MAC_SPEC_SIFS + 1, val[0]);
+
+ if (!mac->ht_enable)
+ rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM, 0x0e0e);
+ else
+ rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM,
+ *((u16 *)val));
+ break;
+ case HW_VAR_SLOT_TIME: {
+ u8 e_aci;
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ "HW_VAR_SLOT_TIME %x\n", val[0]);
+
+ rtl_write_byte(rtlpriv, REG_SLOT, val[0]);
+
+ for (e_aci = 0; e_aci < AC_MAX; e_aci++) {
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
+ &e_aci);
+ }
+ break; }
+ case HW_VAR_ACK_PREAMBLE: {
+ u8 reg_tmp;
+ u8 short_preamble = (bool)*val;
+ reg_tmp = rtl_read_byte(rtlpriv, REG_TRXPTCL_CTL + 2);
+ if (short_preamble) {
+ reg_tmp |= 0x02;
+ rtl_write_byte(rtlpriv, REG_TRXPTCL_CTL + 2, reg_tmp);
+ } else {
+ reg_tmp &= 0xFD;
+ rtl_write_byte(rtlpriv, REG_TRXPTCL_CTL + 2, reg_tmp);
+ }
+ break; }
+ case HW_VAR_WPA_CONFIG:
+ rtl_write_byte(rtlpriv, REG_SECCFG, *val);
+ break;
+ case HW_VAR_AMPDU_MIN_SPACE: {
+ u8 min_spacing_to_set;
+ u8 sec_min_space;
+
+ min_spacing_to_set = *val;
+ if (min_spacing_to_set <= 7) {
+ sec_min_space = 0;
+
+ if (min_spacing_to_set < sec_min_space)
+ min_spacing_to_set = sec_min_space;
+
+ mac->min_space_cfg = ((mac->min_space_cfg & 0xf8) |
+ min_spacing_to_set);
+
+ *val = min_spacing_to_set;
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ "Set HW_VAR_AMPDU_MIN_SPACE: %#x\n",
+ mac->min_space_cfg);
+
+ rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE,
+ mac->min_space_cfg);
+ }
+ break; }
+ case HW_VAR_SHORTGI_DENSITY: {
+ u8 density_to_set;
+
+ density_to_set = *val;
+ mac->min_space_cfg |= (density_to_set << 3);
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ "Set HW_VAR_SHORTGI_DENSITY: %#x\n",
+ mac->min_space_cfg);
+
+ rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE,
+ mac->min_space_cfg);
+ break; }
+ case HW_VAR_AMPDU_FACTOR: {
+ u8 regtoset_normal[4] = {0x41, 0xa8, 0x72, 0xb9};
+ u8 factor_toset;
+ u8 *p_regtoset = NULL;
+ u8 index = 0;
+
+ p_regtoset = regtoset_normal;
+
+ factor_toset = *val;
+ if (factor_toset <= 3) {
+ factor_toset = (1 << (factor_toset + 2));
+ if (factor_toset > 0xf)
+ factor_toset = 0xf;
+
+ for (index = 0; index < 4; index++) {
+ if ((p_regtoset[index] & 0xf0) >
+ (factor_toset << 4))
+ p_regtoset[index] =
+ (p_regtoset[index] & 0x0f) |
+ (factor_toset << 4);
+
+ if ((p_regtoset[index] & 0x0f) > factor_toset)
+ p_regtoset[index] =
+ (p_regtoset[index] & 0xf0) |
+ (factor_toset);
+
+ rtl_write_byte(rtlpriv,
+ (REG_AGGLEN_LMT + index),
+ p_regtoset[index]);
+ }
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ "Set HW_VAR_AMPDU_FACTOR: %#x\n",
+ factor_toset);
+ }
+ break; }
+ case HW_VAR_AC_PARAM: {
+ u8 e_aci = *val;
+ rtl8723_dm_init_edca_turbo(hw);
+
+ if (rtlpci->acm_method != EACMWAY2_SW)
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL,
+ &e_aci);
+ break; }
+ case HW_VAR_ACM_CTRL: {
+ u8 e_aci = *val;
+ union aci_aifsn *p_aci_aifsn =
+ (union aci_aifsn *)(&(mac->ac[0].aifs));
+ u8 acm = p_aci_aifsn->f.acm;
+ u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL);
+
+ acm_ctrl =
+ acm_ctrl | ((rtlpci->acm_method == 2) ? 0x0 : 0x1);
+
+ if (acm) {
+ switch (e_aci) {
+ case AC0_BE:
+ acm_ctrl |= ACMHW_BEQEN;
+ break;
+ case AC2_VI:
+ acm_ctrl |= ACMHW_VIQEN;
+ break;
+ case AC3_VO:
+ acm_ctrl |= ACMHW_VOQEN;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "HW_VAR_ACM_CTRL acm set "
+ "failed: eACI is %d\n", acm);
+ break;
+ }
+ } else {
+ switch (e_aci) {
+ case AC0_BE:
+ acm_ctrl &= (~ACMHW_BEQEN);
+ break;
+ case AC2_VI:
+ acm_ctrl &= (~ACMHW_VIQEN);
+ break;
+ case AC3_VO:
+ acm_ctrl &= (~ACMHW_BEQEN);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not process\n");
+ break;
+ }
+ }
+ RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE,
+ "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] "
+ "Write 0x%X\n", acm_ctrl);
+ rtl_write_byte(rtlpriv, REG_ACMHWCTRL, acm_ctrl);
+ break; }
+ case HW_VAR_RCR:
+ rtl_write_dword(rtlpriv, REG_RCR, ((u32 *)(val))[0]);
+ rtlpci->receive_config = ((u32 *)(val))[0];
+ break;
+ case HW_VAR_RETRY_LIMIT: {
+ u8 retry_limit = *val;
+
+ rtl_write_word(rtlpriv, REG_RL,
+ retry_limit << RETRY_LIMIT_SHORT_SHIFT |
+ retry_limit << RETRY_LIMIT_LONG_SHIFT);
+ break; }
+ case HW_VAR_DUAL_TSF_RST:
+ rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, (BIT(0) | BIT(1)));
+ break;
+ case HW_VAR_EFUSE_BYTES:
+ rtlefuse->efuse_usedbytes = *((u16 *)val);
+ break;
+ case HW_VAR_EFUSE_USAGE:
+ rtlefuse->efuse_usedpercentage = *val;
+ break;
+ case HW_VAR_IO_CMD:
+ rtl8723be_phy_set_io_cmd(hw, (*(enum io_type *)val));
+ break;
+ case HW_VAR_SET_RPWM: {
+ u8 rpwm_val;
+
+ rpwm_val = rtl_read_byte(rtlpriv, REG_PCIE_HRPWM);
+ udelay(1);
+
+ if (rpwm_val & BIT(7)) {
+ rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, *val);
+ } else {
+ rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, *val | BIT(7));
+ }
+ break; }
+ case HW_VAR_H2C_FW_PWRMODE:
+ rtl8723be_set_fw_pwrmode_cmd(hw, *val);
+ break;
+ case HW_VAR_FW_PSMODE_STATUS:
+ ppsc->fw_current_inpsmode = *((bool *)val);
+ break;
+ case HW_VAR_RESUME_CLK_ON:
+ _rtl8723be_set_fw_ps_rf_on(hw);
+ break;
+ case HW_VAR_FW_LPS_ACTION: {
+ bool enter_fwlps = *((bool *)val);
+
+ if (enter_fwlps)
+ _rtl8723be_fwlps_enter(hw);
+ else
+ _rtl8723be_fwlps_leave(hw);
+
+ break; }
+ case HW_VAR_H2C_FW_JOINBSSRPT: {
+ u8 mstatus = *val;
+ u8 tmp_regcr, tmp_reg422, bcnvalid_reg;
+ u8 count = 0, dlbcn_count = 0;
+ bool recover = false;
+
+ if (mstatus == RT_MEDIA_CONNECT) {
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID, NULL);
+
+ tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1);
+ rtl_write_byte(rtlpriv, REG_CR + 1,
+ (tmp_regcr | BIT(0)));
+
+ _rtl8723be_set_bcn_ctrl_reg(hw, 0, BIT(3));
+ _rtl8723be_set_bcn_ctrl_reg(hw, BIT(4), 0);
+
+ tmp_reg422 = rtl_read_byte(rtlpriv,
+ REG_FWHW_TXQ_CTRL + 2);
+ rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2,
+ tmp_reg422 & (~BIT(6)));
+ if (tmp_reg422 & BIT(6))
+ recover = true;
+
+ do {
+ bcnvalid_reg = rtl_read_byte(rtlpriv,
+ REG_TDECTRL + 2);
+ rtl_write_byte(rtlpriv, REG_TDECTRL + 2,
+ (bcnvalid_reg | BIT(0)));
+ _rtl8723be_return_beacon_queue_skb(hw);
+
+ rtl8723be_set_fw_rsvdpagepkt(hw, 0);
+ bcnvalid_reg = rtl_read_byte(rtlpriv,
+ REG_TDECTRL + 2);
+ count = 0;
+ while (!(bcnvalid_reg & BIT(0)) && count < 20) {
+ count++;
+ udelay(10);
+ bcnvalid_reg = rtl_read_byte(rtlpriv,
+ REG_TDECTRL + 2);
+ }
+ dlbcn_count++;
+ } while (!(bcnvalid_reg & BIT(0)) && dlbcn_count < 5);
+
+ if (bcnvalid_reg & BIT(0))
+ rtl_write_byte(rtlpriv, REG_TDECTRL+2, BIT(0));
+
+ _rtl8723be_set_bcn_ctrl_reg(hw, BIT(3), 0);
+ _rtl8723be_set_bcn_ctrl_reg(hw, 0, BIT(4));
+
+ if (recover) {
+ rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2,
+ tmp_reg422);
+ }
+ rtl_write_byte(rtlpriv, REG_CR + 1,
+ (tmp_regcr & ~(BIT(0))));
+ }
+ rtl8723be_set_fw_joinbss_report_cmd(hw, *val);
+ break; }
+ case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
+ rtl8723be_set_p2p_ps_offload_cmd(hw, *val);
+ break;
+ case HW_VAR_AID: {
+ u16 u2btmp;
+ u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT);
+ u2btmp &= 0xC000;
+ rtl_write_word(rtlpriv, REG_BCN_PSR_RPT,
+ (u2btmp | mac->assoc_id));
+ break; }
+ case HW_VAR_CORRECT_TSF: {
+ u8 btype_ibss = *val;
+
+ if (btype_ibss)
+ _rtl8723be_stop_tx_beacon(hw);
+
+ _rtl8723be_set_bcn_ctrl_reg(hw, 0, BIT(3));
+
+ rtl_write_dword(rtlpriv, REG_TSFTR,
+ (u32) (mac->tsf & 0xffffffff));
+ rtl_write_dword(rtlpriv, REG_TSFTR + 4,
+ (u32) ((mac->tsf >> 32) & 0xffffffff));
+
+ _rtl8723be_set_bcn_ctrl_reg(hw, BIT(3), 0);
+
+ if (btype_ibss)
+ _rtl8723be_resume_tx_beacon(hw);
+ break; }
+ case HW_VAR_KEEP_ALIVE: {
+ u8 array[2];
+ array[0] = 0xff;
+ array[1] = *val;
+ rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_KEEP_ALIVE_CTRL,
+ 2, array);
+ break; }
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not process %x\n",
+ variable);
+ break;
+ }
+}
+
+static bool _rtl8723be_llt_write(struct ieee80211_hw *hw, u32 address, u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ bool status = true;
+ int count = 0;
+ u32 value = _LLT_INIT_ADDR(address) | _LLT_INIT_DATA(data) |
+ _LLT_OP(_LLT_WRITE_ACCESS);
+
+ rtl_write_dword(rtlpriv, REG_LLT_INIT, value);
+
+ do {
+ value = rtl_read_dword(rtlpriv, REG_LLT_INIT);
+ if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value))
+ break;
+
+ if (count > POLLING_LLT_THRESHOLD) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Failed to polling write LLT done at "
+ "address %d!\n", address);
+ status = false;
+ break;
+ }
+ } while (++count);
+
+ return status;
+}
+
+static bool _rtl8723be_llt_table_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ unsigned short i;
+ u8 txpktbuf_bndy;
+ u8 maxpage;
+ bool status;
+
+ maxpage = 255;
+ txpktbuf_bndy = 245;
+
+ rtl_write_dword(rtlpriv, REG_TRXFF_BNDY,
+ (0x27FF0000 | txpktbuf_bndy));
+ rtl_write_byte(rtlpriv, REG_TDECTRL + 1, txpktbuf_bndy);
+
+ rtl_write_byte(rtlpriv, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy);
+ rtl_write_byte(rtlpriv, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy);
+
+ rtl_write_byte(rtlpriv, 0x45D, txpktbuf_bndy);
+ rtl_write_byte(rtlpriv, REG_PBP, 0x31);
+ rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ, 0x4);
+
+ for (i = 0; i < (txpktbuf_bndy - 1); i++) {
+ status = _rtl8723be_llt_write(hw, i, i + 1);
+ if (!status)
+ return status;
+ }
+ status = _rtl8723be_llt_write(hw, (txpktbuf_bndy - 1), 0xFF);
+
+ if (!status)
+ return status;
+
+ for (i = txpktbuf_bndy; i < maxpage; i++) {
+ status = _rtl8723be_llt_write(hw, i, (i + 1));
+ if (!status)
+ return status;
+ }
+ status = _rtl8723be_llt_write(hw, maxpage, txpktbuf_bndy);
+ if (!status)
+ return status;
+
+ rtl_write_dword(rtlpriv, REG_RQPN, 0x80e40808);
+ rtl_write_byte(rtlpriv, REG_RQPN_NPQ, 0x00);
+
+ return true;
+}
+
+static void _rtl8723be_gen_refresh_led_state(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_led *pled0 = &(pcipriv->ledctl.sw_led0);
+
+ if (rtlpriv->rtlhal.up_first_time)
+ return;
+
+ if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS)
+ rtl8723be_sw_led_on(hw, pled0);
+ else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT)
+ rtl8723be_sw_led_on(hw, pled0);
+ else
+ rtl8723be_sw_led_off(hw, pled0);
+}
+
+static bool _rtl8723be_init_mac(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ unsigned char bytetmp;
+ unsigned short wordtmp;
+ u16 retry = 0;
+ bool mac_func_enable;
+
+ rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00);
+
+ /*Auto Power Down to CHIP-off State*/
+ bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1) & (~BIT(7));
+ rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, bytetmp);
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_CR);
+ if (bytetmp == 0xFF)
+ mac_func_enable = true;
+ else
+ mac_func_enable = false;
+
+ /* HW Power on sequence */
+ if (!rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK,
+ PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,
+ RTL8723_NIC_ENABLE_FLOW)) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "init MAC Fail as power on failure\n");
+ return false;
+ }
+ bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO) | BIT(4);
+ rtl_write_byte(rtlpriv, REG_APS_FSMCO, bytetmp);
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_CR);
+ bytetmp = 0xff;
+ rtl_write_byte(rtlpriv, REG_CR, bytetmp);
+ mdelay(2);
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_HWSEQ_CTRL);
+ bytetmp |= 0x7f;
+ rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, bytetmp);
+ mdelay(2);
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_SYS_CFG + 3);
+ if (bytetmp & BIT(0)) {
+ bytetmp = rtl_read_byte(rtlpriv, 0x7c);
+ bytetmp |= BIT(6);
+ rtl_write_byte(rtlpriv, 0x7c, bytetmp);
+ }
+ bytetmp = rtl_read_byte(rtlpriv, REG_SYS_CLKR);
+ bytetmp |= BIT(3);
+ rtl_write_byte(rtlpriv, REG_SYS_CLKR, bytetmp);
+ bytetmp = rtl_read_byte(rtlpriv, REG_GPIO_MUXCFG + 1);
+ bytetmp &= ~BIT(4);
+ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG + 1, bytetmp);
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG+3);
+ rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG+3, bytetmp | 0x77);
+
+ rtl_write_word(rtlpriv, REG_CR, 0x2ff);
+
+ if (!mac_func_enable) {
+ if (!_rtl8723be_llt_table_init(hw))
+ return false;
+ }
+ rtl_write_dword(rtlpriv, REG_HISR, 0xffffffff);
+ rtl_write_dword(rtlpriv, REG_HISRE, 0xffffffff);
+
+ /* Enable FW Beamformer Interrupt */
+ bytetmp = rtl_read_byte(rtlpriv, REG_FWIMR + 3);
+ rtl_write_byte(rtlpriv, REG_FWIMR + 3, bytetmp | BIT(6));
+
+ wordtmp = rtl_read_word(rtlpriv, REG_TRXDMA_CTRL);
+ wordtmp &= 0xf;
+ wordtmp |= 0xF5B1;
+ rtl_write_word(rtlpriv, REG_TRXDMA_CTRL, wordtmp);
+
+ rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 1, 0x1F);
+ rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+ rtl_write_word(rtlpriv, REG_RXFLTMAP2, 0xFFFF);
+ rtl_write_dword(rtlpriv, REG_TCR, rtlpci->transmit_config);
+
+ rtl_write_byte(rtlpriv, 0x4d0, 0x0);
+
+ rtl_write_dword(rtlpriv, REG_BCNQ_DESA,
+ ((u64) rtlpci->tx_ring[BEACON_QUEUE].dma) &
+ DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_MGQ_DESA,
+ (u64) rtlpci->tx_ring[MGNT_QUEUE].dma &
+ DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_VOQ_DESA,
+ (u64) rtlpci->tx_ring[VO_QUEUE].dma & DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_VIQ_DESA,
+ (u64) rtlpci->tx_ring[VI_QUEUE].dma & DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_BEQ_DESA,
+ (u64) rtlpci->tx_ring[BE_QUEUE].dma & DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_BKQ_DESA,
+ (u64) rtlpci->tx_ring[BK_QUEUE].dma & DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_HQ_DESA,
+ (u64) rtlpci->tx_ring[HIGH_QUEUE].dma &
+ DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_RX_DESA,
+ (u64) rtlpci->rx_ring[RX_MPDU_QUEUE].dma &
+ DMA_BIT_MASK(32));
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG + 3);
+ rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 3, bytetmp | 0x77);
+
+ rtl_write_dword(rtlpriv, REG_INT_MIG, 0);
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL);
+ rtl_write_byte(rtlpriv, REG_APSD_CTRL, bytetmp & ~BIT(6));
+
+ rtl_write_byte(rtlpriv, REG_SECONDARY_CCA_CTRL, 0x3);
+
+ do {
+ retry++;
+ bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL);
+ } while ((retry < 200) && (bytetmp & BIT(7)));
+
+ _rtl8723be_gen_refresh_led_state(hw);
+
+ rtl_write_dword(rtlpriv, REG_MCUTST_1, 0x0);
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+ rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, bytetmp & ~BIT(2));
+
+ return true;
+}
+
+static void _rtl8723be_hw_configure(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 reg_bw_opmode;
+ u32 reg_ratr, reg_prsr;
+
+ reg_bw_opmode = BW_OPMODE_20MHZ;
+ reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG |
+ RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
+ reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
+
+ rtl_write_dword(rtlpriv, REG_RRSR, reg_prsr);
+ rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, 0xFF);
+}
+
+static void _rtl8723be_enable_aspm_back_door(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ rtl_write_byte(rtlpriv, 0x34b, 0x93);
+ rtl_write_word(rtlpriv, 0x350, 0x870c);
+ rtl_write_byte(rtlpriv, 0x352, 0x1);
+
+ if (ppsc->support_backdoor)
+ rtl_write_byte(rtlpriv, 0x349, 0x1b);
+ else
+ rtl_write_byte(rtlpriv, 0x349, 0x03);
+
+ rtl_write_word(rtlpriv, 0x350, 0x2718);
+ rtl_write_byte(rtlpriv, 0x352, 0x1);
+}
+
+void rtl8723be_enable_hw_security_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 sec_reg_value;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "PairwiseEncAlgorithm = %d GroupEncAlgorithm = %d\n",
+ rtlpriv->sec.pairwise_enc_algorithm,
+ rtlpriv->sec.group_enc_algorithm);
+
+ if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ "not open hw encryption\n");
+ return;
+ }
+ sec_reg_value = SCR_TXENCENABLE | SCR_RXDECENABLE;
+
+ if (rtlpriv->sec.use_defaultkey) {
+ sec_reg_value |= SCR_TXUSEDK;
+ sec_reg_value |= SCR_RXUSEDK;
+ }
+ sec_reg_value |= (SCR_RXBCUSEDK | SCR_TXBCUSEDK);
+
+ rtl_write_byte(rtlpriv, REG_CR + 1, 0x02);
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "The SECR-value %x\n",
+ sec_reg_value);
+
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value);
+}
+
+int rtl8723be_hw_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ bool rtstatus = true;
+ int err;
+ u8 tmp_u1b;
+ unsigned long flags;
+
+ /* reenable interrupts to not interfere with other devices */
+ local_save_flags(flags);
+ local_irq_enable();
+
+ rtlpriv->rtlhal.being_init_adapter = true;
+ rtlpriv->intf_ops->disable_aspm(hw);
+ rtstatus = _rtl8723be_init_mac(hw);
+ if (!rtstatus) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n");
+ err = 1;
+ goto exit;
+ }
+ tmp_u1b = rtl_read_byte(rtlpriv, REG_SYS_CFG);
+ tmp_u1b &= 0x7F;
+ rtl_write_byte(rtlpriv, REG_SYS_CFG, tmp_u1b);
+
+ err = rtl8723_download_fw(hw, true);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "Failed to download FW. Init HW without FW now..\n");
+ err = 1;
+ rtlhal->fw_ready = false;
+ goto exit;
+ } else {
+ rtlhal->fw_ready = true;
+ }
+ rtlhal->last_hmeboxnum = 0;
+ rtl8723be_phy_mac_config(hw);
+ /* because last function modify RCR, so we update
+ * rcr var here, or TP will unstable for receive_config
+ * is wrong, RX RCR_ACRC32 will cause TP unstabel & Rx
+ * RCR_APP_ICV will cause mac80211 unassoc for cisco 1252
+ */
+ rtlpci->receive_config = rtl_read_dword(rtlpriv, REG_RCR);
+ rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV);
+ rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+
+ rtl8723be_phy_bb_config(hw);
+ rtlphy->rf_mode = RF_OP_BY_SW_3WIRE;
+ rtl8723be_phy_rf_config(hw);
+
+ rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0,
+ RF_CHNLBW, RFREG_OFFSET_MASK);
+ rtlphy->rfreg_chnlval[1] = rtl_get_rfreg(hw, (enum radio_path)1,
+ RF_CHNLBW, RFREG_OFFSET_MASK);
+ rtlphy->rfreg_chnlval[0] &= 0xFFF03FF;
+ rtlphy->rfreg_chnlval[0] |= (BIT(10) | BIT(11));
+
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1);
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1);
+ rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1);
+ _rtl8723be_hw_configure(hw);
+ rtl_cam_reset_all_entry(hw);
+ rtl8723be_enable_hw_security_config(hw);
+
+ ppsc->rfpwr_state = ERFON;
+
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr);
+ _rtl8723be_enable_aspm_back_door(hw);
+ rtlpriv->intf_ops->enable_aspm(hw);
+
+ rtl8723be_bt_hw_init(hw);
+
+ rtl_set_bbreg(hw, 0x64, BIT(20), 0);
+ rtl_set_bbreg(hw, 0x64, BIT(24), 0);
+
+ rtl_set_bbreg(hw, 0x40, BIT(4), 0);
+ rtl_set_bbreg(hw, 0x40, BIT(3), 1);
+
+ rtl_set_bbreg(hw, 0x944, BIT(0)|BIT(1), 0x3);
+ rtl_set_bbreg(hw, 0x930, 0xff, 0x77);
+
+ rtl_set_bbreg(hw, 0x38, BIT(11), 0x1);
+
+ rtl_set_bbreg(hw, 0xb2c, 0xffffffff, 0x80000000);
+
+ if (ppsc->rfpwr_state == ERFON) {
+ rtl8723be_dm_check_txpower_tracking(hw);
+ rtl8723be_phy_lc_calibrate(hw);
+ }
+ tmp_u1b = efuse_read_1byte(hw, 0x1FA);
+ if (!(tmp_u1b & BIT(0))) {
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x15, 0x0F, 0x05);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "PA BIAS path A\n");
+ }
+ if (!(tmp_u1b & BIT(4))) {
+ tmp_u1b = rtl_read_byte(rtlpriv, 0x16);
+ tmp_u1b &= 0x0F;
+ rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x80);
+ udelay(10);
+ rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x90);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "under 1.5V\n");
+ }
+ rtl8723be_dm_init(hw);
+exit:
+ local_irq_restore(flags);
+ rtlpriv->rtlhal.being_init_adapter = false;
+ return err;
+}
+
+static enum version_8723e _rtl8723be_read_chip_version(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ enum version_8723e version = VERSION_UNKNOWN;
+ u8 count = 0;
+ u8 value8;
+ u32 value32;
+
+ rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0);
+
+ value8 = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 2);
+ rtl_write_byte(rtlpriv, REG_APS_FSMCO + 2, value8 | BIT(0));
+
+ value8 = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1);
+ rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, value8 | BIT(0));
+
+ value8 = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1);
+ while (((value8 & BIT(0))) && (count++ < 100)) {
+ udelay(10);
+ value8 = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1);
+ }
+ count = 0;
+ value8 = rtl_read_byte(rtlpriv, REG_ROM_VERSION);
+ while ((value8 == 0) && (count++ < 50)) {
+ value8 = rtl_read_byte(rtlpriv, REG_ROM_VERSION);
+ mdelay(1);
+ }
+ value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG1);
+ if ((value32 & (CHIP_8723B)) != CHIP_8723B)
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "unkown chip version\n");
+ else
+ version = (enum version_8723e) VERSION_TEST_CHIP_1T1R_8723B;
+
+ rtlphy->rf_type = RF_1T1R;
+
+ value8 = rtl_read_byte(rtlpriv, REG_ROM_VERSION);
+ if (value8 >= 0x02)
+ version |= BIT(3);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Chip RF Type: %s\n", (rtlphy->rf_type == RF_2T2R) ?
+ "RF_2T2R" : "RF_1T1R");
+
+ return version;
+}
+
+static int _rtl8723be_set_media_status(struct ieee80211_hw *hw,
+ enum nl80211_iftype type)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 bt_msr = rtl_read_byte(rtlpriv, MSR) & 0xfc;
+ enum led_ctl_mode ledaction = LED_CTL_NO_LINK;
+
+ rtl_write_dword(rtlpriv, REG_BCN_CTRL, 0);
+ RT_TRACE(rtlpriv, COMP_BEACON, DBG_LOUD,
+ "clear 0x550 when set HW_VAR_MEDIA_STATUS\n");
+
+ if (type == NL80211_IFTYPE_UNSPECIFIED ||
+ type == NL80211_IFTYPE_STATION) {
+ _rtl8723be_stop_tx_beacon(hw);
+ _rtl8723be_enable_bcn_sub_func(hw);
+ } else if (type == NL80211_IFTYPE_ADHOC || type == NL80211_IFTYPE_AP) {
+ _rtl8723be_resume_tx_beacon(hw);
+ _rtl8723be_disable_bcn_sub_func(hw);
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "Set HW_VAR_MEDIA_STATUS: "
+ "No such media status(%x).\n", type);
+ }
+ switch (type) {
+ case NL80211_IFTYPE_UNSPECIFIED:
+ bt_msr |= MSR_NOLINK;
+ ledaction = LED_CTL_LINK;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Set Network type to NO LINK!\n");
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ bt_msr |= MSR_ADHOC;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Set Network type to Ad Hoc!\n");
+ break;
+ case NL80211_IFTYPE_STATION:
+ bt_msr |= MSR_INFRA;
+ ledaction = LED_CTL_LINK;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Set Network type to STA!\n");
+ break;
+ case NL80211_IFTYPE_AP:
+ bt_msr |= MSR_AP;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Set Network type to AP!\n");
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Network type %d not support!\n", type);
+ return 1;
+ }
+ rtl_write_byte(rtlpriv, (MSR), bt_msr);
+ rtlpriv->cfg->ops->led_control(hw, ledaction);
+ if ((bt_msr & 0x03) == MSR_AP)
+ rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00);
+ else
+ rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66);
+ return 0;
+}
+
+void rtl8723be_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u32 reg_rcr = rtlpci->receive_config;
+
+ if (rtlpriv->psc.rfpwr_state != ERFON)
+ return;
+
+ if (check_bssid) {
+ reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
+ (u8 *)(&reg_rcr));
+ _rtl8723be_set_bcn_ctrl_reg(hw, 0, BIT(4));
+ } else if (!check_bssid) {
+ reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN));
+ _rtl8723be_set_bcn_ctrl_reg(hw, BIT(4), 0);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
+ (u8 *)(&reg_rcr));
+ }
+}
+
+int rtl8723be_set_network_type(struct ieee80211_hw *hw,
+ enum nl80211_iftype type)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (_rtl8723be_set_media_status(hw, type))
+ return -EOPNOTSUPP;
+
+ if (rtlpriv->mac80211.link_state == MAC80211_LINKED) {
+ if (type != NL80211_IFTYPE_AP)
+ rtl8723be_set_check_bssid(hw, true);
+ } else {
+ rtl8723be_set_check_bssid(hw, false);
+ }
+ return 0;
+}
+
+/* don't set REG_EDCA_BE_PARAM here
+ * because mac80211 will send pkt when scan
+ */
+void rtl8723be_set_qos(struct ieee80211_hw *hw, int aci)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ rtl8723_dm_init_edca_turbo(hw);
+ switch (aci) {
+ case AC1_BK:
+ rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f);
+ break;
+ case AC0_BE:
+ break;
+ case AC2_VI:
+ rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322);
+ break;
+ case AC3_VO:
+ rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x2f3222);
+ break;
+ default:
+ RT_ASSERT(false, "invalid aci: %d !\n", aci);
+ break;
+ }
+}
+
+void rtl8723be_enable_interrupt(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
+ rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
+ rtlpci->irq_enabled = true;
+ /* there are some C2H CMDs have been sent
+ * before system interrupt is enabled, e.g., C2H, CPWM.
+ * So we need to clear all C2H events that FW has notified,
+ * otherwise FW won't schedule any commands anymore.
+ */
+ rtl_write_byte(rtlpriv, REG_C2HEVT_CLEAR, 0);
+ /*enable system interrupt*/
+ rtl_write_dword(rtlpriv, REG_HSIMR, rtlpci->sys_irq_mask & 0xFFFFFFFF);
+}
+
+void rtl8723be_disable_interrupt(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ rtl_write_dword(rtlpriv, REG_HIMR, IMR_DISABLED);
+ rtl_write_dword(rtlpriv, REG_HIMRE, IMR_DISABLED);
+ rtlpci->irq_enabled = false;
+ synchronize_irq(rtlpci->pdev->irq);
+}
+
+static void _rtl8723be_poweroff_adapter(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 u1b_tmp;
+
+ /* Combo (PCIe + USB) Card and PCIe-MF Card */
+ /* 1. Run LPS WL RFOFF flow */
+ rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+ PWR_INTF_PCI_MSK, RTL8723_NIC_LPS_ENTER_FLOW);
+
+ /* 2. 0x1F[7:0] = 0 */
+ /* turn off RF */
+ rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00);
+ if ((rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) &&
+ rtlhal->fw_ready)
+ rtl8723be_firmware_selfreset(hw);
+
+ /* Reset MCU. Suggested by Filen. */
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));
+
+ /* g. MCUFWDL 0x80[1:0]= 0 */
+ /* reset MCU ready status */
+ rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
+
+ /* HW card disable configuration. */
+ rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+ PWR_INTF_PCI_MSK, RTL8723_NIC_DISABLE_FLOW);
+
+ /* Reset MCU IO Wrapper */
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
+ rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0))));
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
+ rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, u1b_tmp | BIT(0));
+
+ /* 7. RSV_CTRL 0x1C[7:0] = 0x0E */
+ /* lock ISO/CLK/Power control register */
+ rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e);
+}
+
+void rtl8723be_card_disable(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ enum nl80211_iftype opmode;
+
+ mac->link_state = MAC80211_NOLINK;
+ opmode = NL80211_IFTYPE_UNSPECIFIED;
+ _rtl8723be_set_media_status(hw, opmode);
+ if (rtlpriv->rtlhal.driver_is_goingto_unload ||
+ ppsc->rfoff_reason > RF_CHANGE_BY_PS)
+ rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+ _rtl8723be_poweroff_adapter(hw);
+
+ /* after power off we should do iqk again */
+ rtlpriv->phy.iqk_initialized = false;
+}
+
+void rtl8723be_interrupt_recognized(struct ieee80211_hw *hw,
+ u32 *p_inta, u32 *p_intb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ *p_inta = rtl_read_dword(rtlpriv, ISR) & rtlpci->irq_mask[0];
+ rtl_write_dword(rtlpriv, ISR, *p_inta);
+
+ *p_intb = rtl_read_dword(rtlpriv, REG_HISRE) &
+ rtlpci->irq_mask[1];
+ rtl_write_dword(rtlpriv, REG_HISRE, *p_intb);
+}
+
+void rtl8723be_set_beacon_related_registers(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u16 bcn_interval, atim_window;
+
+ bcn_interval = mac->beacon_interval;
+ atim_window = 2; /*FIX MERGE */
+ rtl8723be_disable_interrupt(hw);
+ rtl_write_word(rtlpriv, REG_ATIMWND, atim_window);
+ rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
+ rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660f);
+ rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x18);
+ rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x18);
+ rtl_write_byte(rtlpriv, 0x606, 0x30);
+ rtl8723be_enable_interrupt(hw);
+}
+
+void rtl8723be_set_beacon_interval(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u16 bcn_interval = mac->beacon_interval;
+
+ RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG,
+ "beacon_interval:%d\n", bcn_interval);
+ rtl8723be_disable_interrupt(hw);
+ rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
+ rtl8723be_enable_interrupt(hw);
+}
+
+void rtl8723be_update_interrupt_mask(struct ieee80211_hw *hw,
+ u32 add_msr, u32 rm_msr)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD,
+ "add_msr:%x, rm_msr:%x\n", add_msr, rm_msr);
+
+ if (add_msr)
+ rtlpci->irq_mask[0] |= add_msr;
+ if (rm_msr)
+ rtlpci->irq_mask[0] &= (~rm_msr);
+ rtl8723be_disable_interrupt(hw);
+ rtl8723be_enable_interrupt(hw);
+}
+
+static u8 _rtl8723be_get_chnl_group(u8 chnl)
+{
+ u8 group;
+
+ if (chnl < 3)
+ group = 0;
+ else if (chnl < 9)
+ group = 1;
+ else
+ group = 2;
+ return group;
+}
+
+static void _rtl8723be_read_power_value_fromprom(struct ieee80211_hw *hw,
+ struct txpower_info_2g *pw2g,
+ struct txpower_info_5g *pw5g,
+ bool autoload_fail, u8 *hwinfo)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 path, addr = EEPROM_TX_PWR_INX, group, cnt = 0;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "hal_ReadPowerValueFromPROM8723BE(): "
+ "PROMContent[0x%x]= 0x%x\n",
+ (addr + 1), hwinfo[addr + 1]);
+ if (0xFF == hwinfo[addr + 1]) /*YJ, add, 120316*/
+ autoload_fail = true;
+
+ if (autoload_fail) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "auto load fail : Use Default value!\n");
+ for (path = 0; path < MAX_RF_PATH; path++) {
+ /* 2.4G default value */
+ for (group = 0; group < MAX_CHNL_GROUP_24G; group++) {
+ pw2g->index_cck_base[path][group] = 0x2D;
+ pw2g->index_bw40_base[path][group] = 0x2D;
+ }
+ for (cnt = 0; cnt < MAX_TX_COUNT; cnt++) {
+ if (cnt == 0) {
+ pw2g->bw20_diff[path][0] = 0x02;
+ pw2g->ofdm_diff[path][0] = 0x04;
+ } else {
+ pw2g->bw20_diff[path][cnt] = 0xFE;
+ pw2g->bw40_diff[path][cnt] = 0xFE;
+ pw2g->cck_diff[path][cnt] = 0xFE;
+ pw2g->ofdm_diff[path][cnt] = 0xFE;
+ }
+ }
+ }
+ return;
+ }
+ for (path = 0; path < MAX_RF_PATH; path++) {
+ /*2.4G default value*/
+ for (group = 0; group < MAX_CHNL_GROUP_24G; group++) {
+ pw2g->index_cck_base[path][group] = hwinfo[addr++];
+ if (pw2g->index_cck_base[path][group] == 0xFF)
+ pw2g->index_cck_base[path][group] = 0x2D;
+ }
+ for (group = 0; group < MAX_CHNL_GROUP_24G - 1; group++) {
+ pw2g->index_bw40_base[path][group] = hwinfo[addr++];
+ if (pw2g->index_bw40_base[path][group] == 0xFF)
+ pw2g->index_bw40_base[path][group] = 0x2D;
+ }
+ for (cnt = 0; cnt < MAX_TX_COUNT; cnt++) {
+ if (cnt == 0) {
+ pw2g->bw40_diff[path][cnt] = 0;
+ if (hwinfo[addr] == 0xFF) {
+ pw2g->bw20_diff[path][cnt] = 0x02;
+ } else {
+ pw2g->bw20_diff[path][cnt] =
+ (hwinfo[addr] & 0xf0) >> 4;
+ /*bit sign number to 8 bit sign number*/
+ if (pw2g->bw20_diff[path][cnt] & BIT(3))
+ pw2g->bw20_diff[path][cnt] |= 0xF0;
+ }
+ if (hwinfo[addr] == 0xFF) {
+ pw2g->ofdm_diff[path][cnt] = 0x04;
+ } else {
+ pw2g->ofdm_diff[path][cnt] =
+ (hwinfo[addr] & 0x0f);
+ /*bit sign number to 8 bit sign number*/
+ if (pw2g->ofdm_diff[path][cnt] & BIT(3))
+ pw2g->ofdm_diff[path][cnt] |=
+ 0xF0;
+ }
+ pw2g->cck_diff[path][cnt] = 0;
+ addr++;
+ } else {
+ if (hwinfo[addr] == 0xFF) {
+ pw2g->bw40_diff[path][cnt] = 0xFE;
+ } else {
+ pw2g->bw40_diff[path][cnt] =
+ (hwinfo[addr] & 0xf0) >> 4;
+ if (pw2g->bw40_diff[path][cnt] & BIT(3))
+ pw2g->bw40_diff[path][cnt] |=
+ 0xF0;
+ }
+ if (hwinfo[addr] == 0xFF) {
+ pw2g->bw20_diff[path][cnt] = 0xFE;
+ } else {
+ pw2g->bw20_diff[path][cnt] =
+ (hwinfo[addr] & 0x0f);
+ if (pw2g->bw20_diff[path][cnt] & BIT(3))
+ pw2g->bw20_diff[path][cnt] |=
+ 0xF0;
+ }
+ addr++;
+
+ if (hwinfo[addr] == 0xFF) {
+ pw2g->ofdm_diff[path][cnt] = 0xFE;
+ } else {
+ pw2g->ofdm_diff[path][cnt] =
+ (hwinfo[addr] & 0xf0) >> 4;
+ if (pw2g->ofdm_diff[path][cnt] & BIT(3))
+ pw2g->ofdm_diff[path][cnt] |=
+ 0xF0;
+ }
+ if (hwinfo[addr] == 0xFF) {
+ pw2g->cck_diff[path][cnt] = 0xFE;
+ } else {
+ pw2g->cck_diff[path][cnt] =
+ (hwinfo[addr] & 0x0f);
+ if (pw2g->cck_diff[path][cnt] & BIT(3))
+ pw2g->cck_diff[path][cnt] |=
+ 0xF0;
+ }
+ addr++;
+ }
+ }
+ /*5G default value*/
+ for (group = 0; group < MAX_CHNL_GROUP_5G; group++) {
+ pw5g->index_bw40_base[path][group] = hwinfo[addr++];
+ if (pw5g->index_bw40_base[path][group] == 0xFF)
+ pw5g->index_bw40_base[path][group] = 0xFE;
+ }
+ for (cnt = 0; cnt < MAX_TX_COUNT; cnt++) {
+ if (cnt == 0) {
+ pw5g->bw40_diff[path][cnt] = 0;
+
+ if (hwinfo[addr] == 0xFF) {
+ pw5g->bw20_diff[path][cnt] = 0;
+ } else {
+ pw5g->bw20_diff[path][0] =
+ (hwinfo[addr] & 0xf0) >> 4;
+ if (pw5g->bw20_diff[path][cnt] & BIT(3))
+ pw5g->bw20_diff[path][cnt] |=
+ 0xF0;
+ }
+ if (hwinfo[addr] == 0xFF) {
+ pw5g->ofdm_diff[path][cnt] = 0x04;
+ } else {
+ pw5g->ofdm_diff[path][0] =
+ (hwinfo[addr] & 0x0f);
+ if (pw5g->ofdm_diff[path][cnt] & BIT(3))
+ pw5g->ofdm_diff[path][cnt] |=
+ 0xF0;
+ }
+ addr++;
+ } else {
+ if (hwinfo[addr] == 0xFF) {
+ pw5g->bw40_diff[path][cnt] = 0xFE;
+ } else {
+ pw5g->bw40_diff[path][cnt] =
+ (hwinfo[addr] & 0xf0) >> 4;
+ if (pw5g->bw40_diff[path][cnt] & BIT(3))
+ pw5g->bw40_diff[path][cnt] |= 0xF0;
+ }
+ if (hwinfo[addr] == 0xFF) {
+ pw5g->bw20_diff[path][cnt] = 0xFE;
+ } else {
+ pw5g->bw20_diff[path][cnt] =
+ (hwinfo[addr] & 0x0f);
+ if (pw5g->bw20_diff[path][cnt] & BIT(3))
+ pw5g->bw20_diff[path][cnt] |= 0xF0;
+ }
+ addr++;
+ }
+ }
+ if (hwinfo[addr] == 0xFF) {
+ pw5g->ofdm_diff[path][1] = 0xFE;
+ pw5g->ofdm_diff[path][2] = 0xFE;
+ } else {
+ pw5g->ofdm_diff[path][1] = (hwinfo[addr] & 0xf0) >> 4;
+ pw5g->ofdm_diff[path][2] = (hwinfo[addr] & 0x0f);
+ }
+ addr++;
+
+ if (hwinfo[addr] == 0xFF)
+ pw5g->ofdm_diff[path][3] = 0xFE;
+ else
+ pw5g->ofdm_diff[path][3] = (hwinfo[addr] & 0x0f);
+ addr++;
+
+ for (cnt = 1; cnt < MAX_TX_COUNT; cnt++) {
+ if (pw5g->ofdm_diff[path][cnt] == 0xFF)
+ pw5g->ofdm_diff[path][cnt] = 0xFE;
+ else if (pw5g->ofdm_diff[path][cnt] & BIT(3))
+ pw5g->ofdm_diff[path][cnt] |= 0xF0;
+ }
+ }
+}
+
+static void _rtl8723be_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
+ bool autoload_fail,
+ u8 *hwinfo)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct txpower_info_2g pw2g;
+ struct txpower_info_5g pw5g;
+ u8 rf_path, index;
+ u8 i;
+
+ _rtl8723be_read_power_value_fromprom(hw, &pw2g, &pw5g, autoload_fail,
+ hwinfo);
+
+ for (rf_path = 0; rf_path < 2; rf_path++) {
+ for (i = 0; i < 14; i++) {
+ index = _rtl8723be_get_chnl_group(i+1);
+
+ rtlefuse->txpwrlevel_cck[rf_path][i] =
+ pw2g.index_cck_base[rf_path][index];
+ rtlefuse->txpwrlevel_ht40_1s[rf_path][i] =
+ pw2g.index_bw40_base[rf_path][index];
+ }
+ for (i = 0; i < MAX_TX_COUNT; i++) {
+ rtlefuse->txpwr_ht20diff[rf_path][i] =
+ pw2g.bw20_diff[rf_path][i];
+ rtlefuse->txpwr_ht40diff[rf_path][i] =
+ pw2g.bw40_diff[rf_path][i];
+ rtlefuse->txpwr_legacyhtdiff[rf_path][i] =
+ pw2g.ofdm_diff[rf_path][i];
+ }
+ for (i = 0; i < 14; i++) {
+ RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+ "RF(%d)-Ch(%d) [CCK / HT40_1S ] = "
+ "[0x%x / 0x%x ]\n", rf_path, i,
+ rtlefuse->txpwrlevel_cck[rf_path][i],
+ rtlefuse->txpwrlevel_ht40_1s[rf_path][i]);
+ }
+ }
+ if (!autoload_fail)
+ rtlefuse->eeprom_thermalmeter =
+ hwinfo[EEPROM_THERMAL_METER_88E];
+ else
+ rtlefuse->eeprom_thermalmeter = EEPROM_DEFAULT_THERMALMETER;
+
+ if (rtlefuse->eeprom_thermalmeter == 0xff || autoload_fail) {
+ rtlefuse->apk_thermalmeterignore = true;
+ rtlefuse->eeprom_thermalmeter = EEPROM_DEFAULT_THERMALMETER;
+ }
+ rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter;
+ RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+ "thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter);
+
+ if (!autoload_fail) {
+ rtlefuse->eeprom_regulatory =
+ hwinfo[EEPROM_RF_BOARD_OPTION_88E] & 0x07;/*bit0~2*/
+ if (hwinfo[EEPROM_RF_BOARD_OPTION_88E] == 0xFF)
+ rtlefuse->eeprom_regulatory = 0;
+ } else {
+ rtlefuse->eeprom_regulatory = 0;
+ }
+ RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+ "eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory);
+}
+
+static void _rtl8723be_read_adapter_info(struct ieee80211_hw *hw,
+ bool pseudo_test)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u16 i, usvalue;
+ u8 hwinfo[HWSET_MAX_SIZE];
+ u16 eeprom_id;
+ bool is_toshiba_smid1 = false;
+ bool is_toshiba_smid2 = false;
+ bool is_samsung_smid = false;
+ bool is_lenovo_smid = false;
+ u16 toshiba_smid1[] = {
+ 0x6151, 0x6152, 0x6154, 0x6155, 0x6177, 0x6178, 0x6179, 0x6180,
+ 0x7151, 0x7152, 0x7154, 0x7155, 0x7177, 0x7178, 0x7179, 0x7180,
+ 0x8151, 0x8152, 0x8154, 0x8155, 0x8181, 0x8182, 0x8184, 0x8185,
+ 0x9151, 0x9152, 0x9154, 0x9155, 0x9181, 0x9182, 0x9184, 0x9185
+ };
+ u16 toshiba_smid2[] = {
+ 0x6181, 0x6184, 0x6185, 0x7181, 0x7182, 0x7184, 0x7185, 0x8181,
+ 0x8182, 0x8184, 0x8185, 0x9181, 0x9182, 0x9184, 0x9185
+ };
+ u16 samsung_smid[] = {
+ 0x6191, 0x6192, 0x6193, 0x7191, 0x7192, 0x7193, 0x8191, 0x8192,
+ 0x8193, 0x9191, 0x9192, 0x9193
+ };
+ u16 lenovo_smid[] = {
+ 0x8195, 0x9195, 0x7194, 0x8200, 0x8201, 0x8202, 0x9199, 0x9200
+ };
+
+ if (pseudo_test) {
+ /* needs to be added */
+ return;
+ }
+ if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) {
+ rtl_efuse_shadow_map_update(hw);
+
+ memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0],
+ HWSET_MAX_SIZE);
+ } else if (rtlefuse->epromtype == EEPROM_93C46) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "RTL819X Not boot from eeprom, check it !!");
+ }
+ RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"),
+ hwinfo, HWSET_MAX_SIZE);
+
+ eeprom_id = *((u16 *)&hwinfo[0]);
+ if (eeprom_id != RTL8723BE_EEPROM_ID) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "EEPROM ID(%#x) is invalid!!\n", eeprom_id);
+ rtlefuse->autoload_failflag = true;
+ } else {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n");
+ rtlefuse->autoload_failflag = false;
+ }
+ if (rtlefuse->autoload_failflag)
+ return;
+
+ rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID];
+ rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID];
+ rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID];
+ rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID];
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROMId = 0x%4x\n", eeprom_id);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid);
+
+ for (i = 0; i < 6; i += 2) {
+ usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i];
+ *((u16 *)(&rtlefuse->dev_addr[i])) = usvalue;
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "dev_addr: %pM\n",
+ rtlefuse->dev_addr);
+
+ /*parse xtal*/
+ rtlefuse->crystalcap = hwinfo[EEPROM_XTAL_8723BE];
+ if (rtlefuse->crystalcap == 0xFF)
+ rtlefuse->crystalcap = 0x20;
+
+ _rtl8723be_read_txpower_info_from_hwpg(hw, rtlefuse->autoload_failflag,
+ hwinfo);
+
+ rtl8723be_read_bt_coexist_info_from_hwpg(hw,
+ rtlefuse->autoload_failflag,
+ hwinfo);
+
+ rtlefuse->eeprom_channelplan = hwinfo[EEPROM_CHANNELPLAN];
+ rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION];
+ rtlefuse->txpwr_fromeprom = true;
+ rtlefuse->eeprom_oemid = hwinfo[EEPROM_CUSTOMER_ID];
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid);
+
+ /* set channel plan to world wide 13 */
+ rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13;
+
+ if (rtlhal->oem_id == RT_CID_DEFAULT) {
+ /* Does this one have a Toshiba SMID from group 1? */
+ for (i = 0; i < sizeof(toshiba_smid1) / sizeof(u16); i++) {
+ if (rtlefuse->eeprom_smid == toshiba_smid1[i]) {
+ is_toshiba_smid1 = true;
+ break;
+ }
+ }
+ /* Does this one have a Toshiba SMID from group 2? */
+ for (i = 0; i < sizeof(toshiba_smid2) / sizeof(u16); i++) {
+ if (rtlefuse->eeprom_smid == toshiba_smid2[i]) {
+ is_toshiba_smid2 = true;
+ break;
+ }
+ }
+ /* Does this one have a Samsung SMID? */
+ for (i = 0; i < sizeof(samsung_smid) / sizeof(u16); i++) {
+ if (rtlefuse->eeprom_smid == samsung_smid[i]) {
+ is_samsung_smid = true;
+ break;
+ }
+ }
+ /* Does this one have a Lenovo SMID? */
+ for (i = 0; i < sizeof(lenovo_smid) / sizeof(u16); i++) {
+ if (rtlefuse->eeprom_smid == lenovo_smid[i]) {
+ is_lenovo_smid = true;
+ break;
+ }
+ }
+ switch (rtlefuse->eeprom_oemid) {
+ case EEPROM_CID_DEFAULT:
+ if (rtlefuse->eeprom_did == 0x8176) {
+ if (rtlefuse->eeprom_svid == 0x10EC &&
+ is_toshiba_smid1) {
+ rtlhal->oem_id = RT_CID_TOSHIBA;
+ } else if (rtlefuse->eeprom_svid == 0x1025) {
+ rtlhal->oem_id = RT_CID_819X_ACER;
+ } else if (rtlefuse->eeprom_svid == 0x10EC &&
+ is_samsung_smid) {
+ rtlhal->oem_id = RT_CID_819X_SAMSUNG;
+ } else if (rtlefuse->eeprom_svid == 0x10EC &&
+ is_lenovo_smid) {
+ rtlhal->oem_id = RT_CID_819X_LENOVO;
+ } else if ((rtlefuse->eeprom_svid == 0x10EC &&
+ rtlefuse->eeprom_smid == 0x8197) ||
+ (rtlefuse->eeprom_svid == 0x10EC &&
+ rtlefuse->eeprom_smid == 0x9196)) {
+ rtlhal->oem_id = RT_CID_819X_CLEVO;
+ } else if ((rtlefuse->eeprom_svid == 0x1028 &&
+ rtlefuse->eeprom_smid == 0x8194) ||
+ (rtlefuse->eeprom_svid == 0x1028 &&
+ rtlefuse->eeprom_smid == 0x8198) ||
+ (rtlefuse->eeprom_svid == 0x1028 &&
+ rtlefuse->eeprom_smid == 0x9197) ||
+ (rtlefuse->eeprom_svid == 0x1028 &&
+ rtlefuse->eeprom_smid == 0x9198)) {
+ rtlhal->oem_id = RT_CID_819X_DELL;
+ } else if ((rtlefuse->eeprom_svid == 0x103C &&
+ rtlefuse->eeprom_smid == 0x1629)) {
+ rtlhal->oem_id = RT_CID_819X_HP;
+ } else if ((rtlefuse->eeprom_svid == 0x1A32 &&
+ rtlefuse->eeprom_smid == 0x2315)) {
+ rtlhal->oem_id = RT_CID_819X_QMI;
+ } else if ((rtlefuse->eeprom_svid == 0x10EC &&
+ rtlefuse->eeprom_smid == 0x8203)) {
+ rtlhal->oem_id = RT_CID_819X_PRONETS;
+ } else if ((rtlefuse->eeprom_svid == 0x1043 &&
+ rtlefuse->eeprom_smid == 0x84B5)) {
+ rtlhal->oem_id = RT_CID_819X_EDIMAX_ASUS;
+ } else {
+ rtlhal->oem_id = RT_CID_DEFAULT;
+ }
+ } else if (rtlefuse->eeprom_did == 0x8178) {
+ if (rtlefuse->eeprom_svid == 0x10EC &&
+ is_toshiba_smid2)
+ rtlhal->oem_id = RT_CID_TOSHIBA;
+ else if (rtlefuse->eeprom_svid == 0x1025)
+ rtlhal->oem_id = RT_CID_819X_ACER;
+ else if ((rtlefuse->eeprom_svid == 0x10EC &&
+ rtlefuse->eeprom_smid == 0x8186))
+ rtlhal->oem_id = RT_CID_819X_PRONETS;
+ else if ((rtlefuse->eeprom_svid == 0x1043 &&
+ rtlefuse->eeprom_smid == 0x84B6))
+ rtlhal->oem_id =
+ RT_CID_819X_EDIMAX_ASUS;
+ else
+ rtlhal->oem_id = RT_CID_DEFAULT;
+ } else {
+ rtlhal->oem_id = RT_CID_DEFAULT;
+ }
+ break;
+ case EEPROM_CID_TOSHIBA:
+ rtlhal->oem_id = RT_CID_TOSHIBA;
+ break;
+ case EEPROM_CID_CCX:
+ rtlhal->oem_id = RT_CID_CCX;
+ break;
+ case EEPROM_CID_QMI:
+ rtlhal->oem_id = RT_CID_819X_QMI;
+ break;
+ case EEPROM_CID_WHQL:
+ break;
+ default:
+ rtlhal->oem_id = RT_CID_DEFAULT;
+ break;
+ }
+ }
+}
+
+static void _rtl8723be_hal_customized_behavior(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ pcipriv->ledctl.led_opendrain = true;
+ switch (rtlhal->oem_id) {
+ case RT_CID_819X_HP:
+ pcipriv->ledctl.led_opendrain = true;
+ break;
+ case RT_CID_819X_LENOVO:
+ case RT_CID_DEFAULT:
+ case RT_CID_TOSHIBA:
+ case RT_CID_CCX:
+ case RT_CID_819X_ACER:
+ case RT_CID_WHQL:
+ default:
+ break;
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "RT Customized ID: 0x%02X\n", rtlhal->oem_id);
+}
+
+void rtl8723be_read_eeprom_info(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 tmp_u1b;
+
+ rtlhal->version = _rtl8723be_read_chip_version(hw);
+ if (get_rf_type(rtlphy) == RF_1T1R)
+ rtlpriv->dm.rfpath_rxenable[0] = true;
+ else
+ rtlpriv->dm.rfpath_rxenable[0] =
+ rtlpriv->dm.rfpath_rxenable[1] = true;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "VersionID = 0x%4x\n",
+ rtlhal->version);
+ tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR);
+ if (tmp_u1b & BIT(4)) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EEPROM\n");
+ rtlefuse->epromtype = EEPROM_93C46;
+ } else {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EFUSE\n");
+ rtlefuse->epromtype = EEPROM_BOOT_EFUSE;
+ }
+ if (tmp_u1b & BIT(5)) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n");
+ rtlefuse->autoload_failflag = false;
+ _rtl8723be_read_adapter_info(hw, false);
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Autoload ERR!!\n");
+ }
+ _rtl8723be_hal_customized_behavior(hw);
+}
+
+static void rtl8723be_update_hal_rate_table(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u32 ratr_value;
+ u8 ratr_index = 0;
+ u8 nmode = mac->ht_enable;
+ u8 mimo_ps = IEEE80211_SMPS_OFF;
+ u16 shortgi_rate;
+ u32 tmp_ratr_value;
+ u8 curtxbw_40mhz = mac->bw_40;
+ u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+ 1 : 0;
+ u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+ 1 : 0;
+ enum wireless_mode wirelessmode = mac->mode;
+
+ if (rtlhal->current_bandtype == BAND_ON_5G)
+ ratr_value = sta->supp_rates[1] << 4;
+ else
+ ratr_value = sta->supp_rates[0];
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ ratr_value = 0xfff;
+ ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+ sta->ht_cap.mcs.rx_mask[0] << 12);
+ switch (wirelessmode) {
+ case WIRELESS_MODE_B:
+ if (ratr_value & 0x0000000c)
+ ratr_value &= 0x0000000d;
+ else
+ ratr_value &= 0x0000000f;
+ break;
+ case WIRELESS_MODE_G:
+ ratr_value &= 0x00000FF5;
+ break;
+ case WIRELESS_MODE_N_24G:
+ case WIRELESS_MODE_N_5G:
+ nmode = 1;
+ if (mimo_ps == IEEE80211_SMPS_STATIC) {
+ ratr_value &= 0x0007F005;
+ } else {
+ u32 ratr_mask;
+
+ if (get_rf_type(rtlphy) == RF_1T2R ||
+ get_rf_type(rtlphy) == RF_1T1R)
+ ratr_mask = 0x000ff005;
+ else
+ ratr_mask = 0x0f0ff005;
+ ratr_value &= ratr_mask;
+ }
+ break;
+ default:
+ if (rtlphy->rf_type == RF_1T2R)
+ ratr_value &= 0x000ff0ff;
+ else
+ ratr_value &= 0x0f0ff0ff;
+ break;
+ }
+ if ((rtlpriv->btcoexist.bt_coexistence) &&
+ (rtlpriv->btcoexist.bt_coexist_type == BT_CSR_BC4) &&
+ (rtlpriv->btcoexist.bt_cur_state) &&
+ (rtlpriv->btcoexist.bt_ant_isolation) &&
+ ((rtlpriv->btcoexist.bt_service == BT_SCO) ||
+ (rtlpriv->btcoexist.bt_service == BT_BUSY)))
+ ratr_value &= 0x0fffcfc0;
+ else
+ ratr_value &= 0x0FFFFFFF;
+
+ if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) ||
+ (!curtxbw_40mhz && curshortgi_20mhz))) {
+ ratr_value |= 0x10000000;
+ tmp_ratr_value = (ratr_value >> 12);
+
+ for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) {
+ if ((1 << shortgi_rate) & tmp_ratr_value)
+ break;
+ }
+ shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) |
+ (shortgi_rate << 4) | (shortgi_rate);
+ }
+ rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value);
+
+ RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+ "%x\n", rtl_read_dword(rtlpriv, REG_ARFR0));
+}
+
+static u8 _rtl8723be_mrate_idx_to_arfr_id(struct ieee80211_hw *hw,
+ u8 rate_index)
+{
+ u8 ret = 0;
+
+ switch (rate_index) {
+ case RATR_INX_WIRELESS_NGB:
+ ret = 1;
+ break;
+ case RATR_INX_WIRELESS_N:
+ case RATR_INX_WIRELESS_NG:
+ ret = 5;
+ break;
+ case RATR_INX_WIRELESS_NB:
+ ret = 3;
+ break;
+ case RATR_INX_WIRELESS_GB:
+ ret = 6;
+ break;
+ case RATR_INX_WIRELESS_G:
+ ret = 7;
+ break;
+ case RATR_INX_WIRELESS_B:
+ ret = 8;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static void rtl8723be_update_hal_rate_mask(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ u8 rssi_level)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_sta_info *sta_entry = NULL;
+ u32 ratr_bitmap;
+ u8 ratr_index;
+ u8 curtxbw_40mhz = (sta->ht_cap.cap &
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40) ? 1 : 0;
+ u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+ 1 : 0;
+ u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+ 1 : 0;
+ enum wireless_mode wirelessmode = 0;
+ bool shortgi = false;
+ u8 rate_mask[7];
+ u8 macid = 0;
+ u8 mimo_ps = IEEE80211_SMPS_OFF;
+
+ sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+ wirelessmode = sta_entry->wireless_mode;
+ if (mac->opmode == NL80211_IFTYPE_STATION ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT)
+ curtxbw_40mhz = mac->bw_40;
+ else if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_ADHOC)
+ macid = sta->aid + 1;
+
+ ratr_bitmap = sta->supp_rates[0];
+
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ ratr_bitmap = 0xfff;
+
+ ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+ sta->ht_cap.mcs.rx_mask[0] << 12);
+ switch (wirelessmode) {
+ case WIRELESS_MODE_B:
+ ratr_index = RATR_INX_WIRELESS_B;
+ if (ratr_bitmap & 0x0000000c)
+ ratr_bitmap &= 0x0000000d;
+ else
+ ratr_bitmap &= 0x0000000f;
+ break;
+ case WIRELESS_MODE_G:
+ ratr_index = RATR_INX_WIRELESS_GB;
+
+ if (rssi_level == 1)
+ ratr_bitmap &= 0x00000f00;
+ else if (rssi_level == 2)
+ ratr_bitmap &= 0x00000ff0;
+ else
+ ratr_bitmap &= 0x00000ff5;
+ break;
+ case WIRELESS_MODE_A:
+ ratr_index = RATR_INX_WIRELESS_A;
+ ratr_bitmap &= 0x00000ff0;
+ break;
+ case WIRELESS_MODE_N_24G:
+ case WIRELESS_MODE_N_5G:
+ ratr_index = RATR_INX_WIRELESS_NGB;
+
+ if (mimo_ps == IEEE80211_SMPS_STATIC ||
+ mimo_ps == IEEE80211_SMPS_DYNAMIC) {
+ if (rssi_level == 1)
+ ratr_bitmap &= 0x00070000;
+ else if (rssi_level == 2)
+ ratr_bitmap &= 0x0007f000;
+ else
+ ratr_bitmap &= 0x0007f005;
+ } else {
+ if (rtlphy->rf_type == RF_1T1R) {
+ if (curtxbw_40mhz) {
+ if (rssi_level == 1)
+ ratr_bitmap &= 0x000f0000;
+ else if (rssi_level == 2)
+ ratr_bitmap &= 0x000ff000;
+ else
+ ratr_bitmap &= 0x000ff015;
+ } else {
+ if (rssi_level == 1)
+ ratr_bitmap &= 0x000f0000;
+ else if (rssi_level == 2)
+ ratr_bitmap &= 0x000ff000;
+ else
+ ratr_bitmap &= 0x000ff005;
+ }
+ } else {
+ if (curtxbw_40mhz) {
+ if (rssi_level == 1)
+ ratr_bitmap &= 0x0f8f0000;
+ else if (rssi_level == 2)
+ ratr_bitmap &= 0x0f8ff000;
+ else
+ ratr_bitmap &= 0x0f8ff015;
+ } else {
+ if (rssi_level == 1)
+ ratr_bitmap &= 0x0f8f0000;
+ else if (rssi_level == 2)
+ ratr_bitmap &= 0x0f8ff000;
+ else
+ ratr_bitmap &= 0x0f8ff005;
+ }
+ }
+ }
+ if ((curtxbw_40mhz && curshortgi_40mhz) ||
+ (!curtxbw_40mhz && curshortgi_20mhz)) {
+ if (macid == 0)
+ shortgi = true;
+ else if (macid == 1)
+ shortgi = false;
+ }
+ break;
+ default:
+ ratr_index = RATR_INX_WIRELESS_NGB;
+
+ if (rtlphy->rf_type == RF_1T2R)
+ ratr_bitmap &= 0x000ff0ff;
+ else
+ ratr_bitmap &= 0x0f0ff0ff;
+ break;
+ }
+ sta_entry->ratr_index = ratr_index;
+
+ RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+ "ratr_bitmap :%x\n", ratr_bitmap);
+ *(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) | (ratr_index << 28);
+ rate_mask[0] = macid;
+ rate_mask[1] = _rtl8723be_mrate_idx_to_arfr_id(hw, ratr_index) |
+ (shortgi ? 0x80 : 0x00);
+ rate_mask[2] = curtxbw_40mhz;
+ /* if (prox_priv->proxim_modeinfo->power_output > 0)
+ * rate_mask[2] |= BIT(6);
+ */
+
+ rate_mask[3] = (u8)(ratr_bitmap & 0x000000ff);
+ rate_mask[4] = (u8)((ratr_bitmap & 0x0000ff00) >> 8);
+ rate_mask[5] = (u8)((ratr_bitmap & 0x00ff0000) >> 16);
+ rate_mask[6] = (u8)((ratr_bitmap & 0xff000000) >> 24);
+
+ RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+ "Rate_index:%x, ratr_val:%x, %x:%x:%x:%x:%x:%x:%x\n",
+ ratr_index, ratr_bitmap,
+ rate_mask[0], rate_mask[1],
+ rate_mask[2], rate_mask[3],
+ rate_mask[4], rate_mask[5],
+ rate_mask[6]);
+ rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_RA_MASK, 7, rate_mask);
+ _rtl8723be_set_bcn_ctrl_reg(hw, BIT(3), 0);
+}
+
+void rtl8723be_update_hal_rate_tbl(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ u8 rssi_level)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ if (rtlpriv->dm.useramask)
+ rtl8723be_update_hal_rate_mask(hw, sta, rssi_level);
+ else
+ rtl8723be_update_hal_rate_table(hw, sta);
+}
+
+void rtl8723be_update_channel_access_setting(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u16 sifs_timer;
+
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME, &mac->slot_time);
+ if (!mac->ht_enable)
+ sifs_timer = 0x0a0a;
+ else
+ sifs_timer = 0x0e0e;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer);
+}
+
+bool rtl8723be_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate;
+ u8 u1tmp;
+ bool actuallyset = false;
+
+ if (rtlpriv->rtlhal.being_init_adapter)
+ return false;
+
+ if (ppsc->swrf_processing)
+ return false;
+
+ spin_lock(&rtlpriv->locks.rf_ps_lock);
+ if (ppsc->rfchange_inprogress) {
+ spin_unlock(&rtlpriv->locks.rf_ps_lock);
+ return false;
+ } else {
+ ppsc->rfchange_inprogress = true;
+ spin_unlock(&rtlpriv->locks.rf_ps_lock);
+ }
+ cur_rfstate = ppsc->rfpwr_state;
+
+ rtl_write_byte(rtlpriv, REG_GPIO_IO_SEL_2,
+ rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL_2) & ~(BIT(1)));
+
+ u1tmp = rtl_read_byte(rtlpriv, REG_GPIO_PIN_CTRL_2);
+
+ if (rtlphy->polarity_ctl)
+ e_rfpowerstate_toset = (u1tmp & BIT(1)) ? ERFOFF : ERFON;
+ else
+ e_rfpowerstate_toset = (u1tmp & BIT(1)) ? ERFON : ERFOFF;
+
+ if (ppsc->hwradiooff &&
+ (e_rfpowerstate_toset == ERFON)) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ "GPIOChangeRF - HW Radio ON, RF ON\n");
+
+ e_rfpowerstate_toset = ERFON;
+ ppsc->hwradiooff = false;
+ actuallyset = true;
+ } else if (!ppsc->hwradiooff &&
+ (e_rfpowerstate_toset == ERFOFF)) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ "GPIOChangeRF - HW Radio OFF, RF OFF\n");
+
+ e_rfpowerstate_toset = ERFOFF;
+ ppsc->hwradiooff = true;
+ actuallyset = true;
+ }
+ if (actuallyset) {
+ spin_lock(&rtlpriv->locks.rf_ps_lock);
+ ppsc->rfchange_inprogress = false;
+ spin_unlock(&rtlpriv->locks.rf_ps_lock);
+ } else {
+ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC)
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+
+ spin_lock(&rtlpriv->locks.rf_ps_lock);
+ ppsc->rfchange_inprogress = false;
+ spin_unlock(&rtlpriv->locks.rf_ps_lock);
+ }
+ *valid = 1;
+ return !ppsc->hwradiooff;
+}
+
+void rtl8723be_set_key(struct ieee80211_hw *hw, u32 key_index,
+ u8 *p_macaddr, bool is_group, u8 enc_algo,
+ bool is_wepkey, bool clear_all)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 *macaddr = p_macaddr;
+ u32 entry_id = 0;
+ bool is_pairwise = false;
+
+ static u8 cam_const_addr[4][6] = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x02},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
+ };
+ static u8 cam_const_broad[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+ if (clear_all) {
+ u8 idx = 0;
+ u8 cam_offset = 0;
+ u8 clear_number = 5;
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "clear_all\n");
+
+ for (idx = 0; idx < clear_number; idx++) {
+ rtl_cam_mark_invalid(hw, cam_offset + idx);
+ rtl_cam_empty_entry(hw, cam_offset + idx);
+
+ if (idx < 5) {
+ memset(rtlpriv->sec.key_buf[idx], 0,
+ MAX_KEY_LEN);
+ rtlpriv->sec.key_len[idx] = 0;
+ }
+ }
+ } else {
+ switch (enc_algo) {
+ case WEP40_ENCRYPTION:
+ enc_algo = CAM_WEP40;
+ break;
+ case WEP104_ENCRYPTION:
+ enc_algo = CAM_WEP104;
+ break;
+ case TKIP_ENCRYPTION:
+ enc_algo = CAM_TKIP;
+ break;
+ case AESCCMP_ENCRYPTION:
+ enc_algo = CAM_AES;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not process\n");
+ enc_algo = CAM_TKIP;
+ break;
+ }
+
+ if (is_wepkey || rtlpriv->sec.use_defaultkey) {
+ macaddr = cam_const_addr[key_index];
+ entry_id = key_index;
+ } else {
+ if (is_group) {
+ macaddr = cam_const_broad;
+ entry_id = key_index;
+ } else {
+ if (mac->opmode == NL80211_IFTYPE_AP) {
+ entry_id = rtl_cam_get_free_entry(hw,
+ p_macaddr);
+ if (entry_id >= TOTAL_CAM_ENTRY) {
+ RT_TRACE(rtlpriv, COMP_SEC,
+ DBG_EMERG,
+ "Can not find free"
+ " hw security cam "
+ "entry\n");
+ return;
+ }
+ } else {
+ entry_id = CAM_PAIRWISE_KEY_POSITION;
+ }
+ key_index = PAIRWISE_KEYIDX;
+ is_pairwise = true;
+ }
+ }
+ if (rtlpriv->sec.key_len[key_index] == 0) {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ "delete one entry, entry_id is %d\n",
+ entry_id);
+ if (mac->opmode == NL80211_IFTYPE_AP)
+ rtl_cam_del_entry(hw, p_macaddr);
+ rtl_cam_delete_one_entry(hw, p_macaddr, entry_id);
+ } else {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ "add one entry\n");
+ if (is_pairwise) {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ "set Pairwise key\n");
+
+ rtl_cam_add_one_entry(hw, macaddr, key_index,
+ entry_id, enc_algo,
+ CAM_CONFIG_NO_USEDK,
+ rtlpriv->sec.key_buf[key_index]);
+ } else {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ "set group key\n");
+
+ if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+ rtl_cam_add_one_entry(hw,
+ rtlefuse->dev_addr,
+ PAIRWISE_KEYIDX,
+ CAM_PAIRWISE_KEY_POSITION,
+ enc_algo,
+ CAM_CONFIG_NO_USEDK,
+ rtlpriv->sec.key_buf
+ [entry_id]);
+ }
+ rtl_cam_add_one_entry(hw, macaddr, key_index,
+ entry_id, enc_algo,
+ CAM_CONFIG_NO_USEDK,
+ rtlpriv->sec.key_buf[entry_id]);
+ }
+ }
+ }
+}
+
+void rtl8723be_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
+ bool auto_load_fail, u8 *hwinfo)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 value;
+ u32 tmpu_32;
+
+ if (!auto_load_fail) {
+ tmpu_32 = rtl_read_dword(rtlpriv, REG_MULTI_FUNC_CTRL);
+ if (tmpu_32 & BIT(18))
+ rtlpriv->btcoexist.btc_info.btcoexist = 1;
+ else
+ rtlpriv->btcoexist.btc_info.btcoexist = 0;
+ value = hwinfo[RF_OPTION4];
+ rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8723B;
+ rtlpriv->btcoexist.btc_info.ant_num = (value & 0x1);
+ } else {
+ rtlpriv->btcoexist.btc_info.btcoexist = 0;
+ rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8723B;
+ rtlpriv->btcoexist.btc_info.ant_num = ANT_X2;
+ }
+}
+
+void rtl8723be_bt_reg_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ /* 0:Low, 1:High, 2:From Efuse. */
+ rtlpriv->btcoexist.reg_bt_iso = 2;
+ /* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */
+ rtlpriv->btcoexist.reg_bt_sco = 3;
+ /* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */
+ rtlpriv->btcoexist.reg_bt_sco = 0;
+}
+
+void rtl8723be_bt_hw_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->cfg->ops->get_btc_status())
+ rtlpriv->btcoexist.btc_ops->btc_init_hw_config(rtlpriv);
+}
+
+void rtl8723be_suspend(struct ieee80211_hw *hw)
+{
+}
+
+void rtl8723be_resume(struct ieee80211_hw *hw)
+{
+}
+
+/* Turn on AAP (RCR:bit 0) for promicuous mode. */
+void rtl8723be_allow_all_destaddr(struct ieee80211_hw *hw, bool allow_all_da,
+ bool write_into_reg)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ if (allow_all_da) /* Set BIT0 */
+ rtlpci->receive_config |= RCR_AAP;
+ else /* Clear BIT0 */
+ rtlpci->receive_config &= ~RCR_AAP;
+
+ if (write_into_reg)
+ rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+
+ RT_TRACE(rtlpriv, COMP_TURBO | COMP_INIT, DBG_LOUD,
+ "receive_config = 0x%08X, write_into_reg =%d\n",
+ rtlpci->receive_config, write_into_reg);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/hw.h b/drivers/net/wireless/rtlwifi/rtl8723be/hw.h
new file mode 100644
index 000000000000..b7449a9b57e4
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/hw.h
@@ -0,0 +1,64 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_HW_H__
+#define __RTL8723BE_HW_H__
+
+void rtl8723be_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
+void rtl8723be_read_eeprom_info(struct ieee80211_hw *hw);
+
+void rtl8723be_interrupt_recognized(struct ieee80211_hw *hw,
+ u32 *p_inta, u32 *p_intb);
+int rtl8723be_hw_init(struct ieee80211_hw *hw);
+void rtl8723be_card_disable(struct ieee80211_hw *hw);
+void rtl8723be_enable_interrupt(struct ieee80211_hw *hw);
+void rtl8723be_disable_interrupt(struct ieee80211_hw *hw);
+int rtl8723be_set_network_type(struct ieee80211_hw *hw,
+ enum nl80211_iftype type);
+void rtl8723be_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid);
+void rtl8723be_set_qos(struct ieee80211_hw *hw, int aci);
+void rtl8723be_set_beacon_related_registers(struct ieee80211_hw *hw);
+void rtl8723be_set_beacon_interval(struct ieee80211_hw *hw);
+void rtl8723be_update_interrupt_mask(struct ieee80211_hw *hw,
+ u32 add_msr, u32 rm_msr);
+void rtl8723be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
+void rtl8723be_update_hal_rate_tbl(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ u8 rssi_level);
+void rtl8723be_update_channel_access_setting(struct ieee80211_hw *hw);
+bool rtl8723be_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid);
+void rtl8723be_enable_hw_security_config(struct ieee80211_hw *hw);
+void rtl8723be_set_key(struct ieee80211_hw *hw, u32 key_index,
+ u8 *p_macaddr, bool is_group, u8 enc_algo,
+ bool is_wepkey, bool clear_all);
+void rtl8723be_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
+ bool autoload_fail, u8 *hwinfo);
+void rtl8723be_bt_reg_init(struct ieee80211_hw *hw);
+void rtl8723be_bt_hw_init(struct ieee80211_hw *hw);
+void rtl8723be_suspend(struct ieee80211_hw *hw);
+void rtl8723be_resume(struct ieee80211_hw *hw);
+void rtl8723be_allow_all_destaddr(struct ieee80211_hw *hw, bool allow_all_da,
+ bool write_into_reg);
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/led.c b/drivers/net/wireless/rtlwifi/rtl8723be/led.c
new file mode 100644
index 000000000000..cb931a38dc48
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/led.c
@@ -0,0 +1,153 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "reg.h"
+#include "led.h"
+
+static void _rtl8723be_init_led(struct ieee80211_hw *hw, struct rtl_led *pled,
+ enum rtl_led_pin ledpin)
+{
+ pled->hw = hw;
+ pled->ledpin = ledpin;
+ pled->ledon = false;
+}
+
+void rtl8723be_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+ u8 ledcfg;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+ "LedAddr:%X ledpin =%d\n", REG_LEDCFG2, pled->ledpin);
+
+ switch (pled->ledpin) {
+ case LED_PIN_GPIO0:
+ break;
+ case LED_PIN_LED0:
+ ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
+ ledcfg &= ~BIT(6);
+ rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0xf0) | BIT(5));
+ break;
+ case LED_PIN_LED1:
+ ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1);
+ rtl_write_byte(rtlpriv, REG_LEDCFG1, ledcfg & 0x10);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not process\n");
+ break;
+ }
+ pled->ledon = true;
+}
+
+void rtl8723be_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ u8 ledcfg;
+
+ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+ "LedAddr:%X ledpin =%d\n", REG_LEDCFG2, pled->ledpin);
+
+ ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
+
+ switch (pled->ledpin) {
+ case LED_PIN_GPIO0:
+ break;
+ case LED_PIN_LED0:
+ ledcfg &= 0xf0;
+ if (pcipriv->ledctl.led_opendrain) {
+ ledcfg &= 0x90; /* Set to software control. */
+ rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg|BIT(3)));
+ ledcfg = rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG);
+ ledcfg &= 0xFE;
+ rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, ledcfg);
+ } else {
+ ledcfg &= ~BIT(6);
+ rtl_write_byte(rtlpriv, REG_LEDCFG2,
+ (ledcfg | BIT(3) | BIT(5)));
+ }
+ break;
+ case LED_PIN_LED1:
+ ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1);
+ ledcfg &= 0x10; /* Set to software control. */
+ rtl_write_byte(rtlpriv, REG_LEDCFG1, ledcfg|BIT(3));
+
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ break;
+ }
+ pled->ledon = false;
+}
+
+void rtl8723be_init_sw_leds(struct ieee80211_hw *hw)
+{
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ _rtl8723be_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0);
+ _rtl8723be_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1);
+}
+
+static void _rtl8723be_sw_led_control(struct ieee80211_hw *hw,
+ enum led_ctl_mode ledaction)
+{
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_led *pled0 = &(pcipriv->ledctl.sw_led0);
+ switch (ledaction) {
+ case LED_CTL_POWER_ON:
+ case LED_CTL_LINK:
+ case LED_CTL_NO_LINK:
+ rtl8723be_sw_led_on(hw, pled0);
+ break;
+ case LED_CTL_POWER_OFF:
+ rtl8723be_sw_led_off(hw, pled0);
+ break;
+ default:
+ break;
+ }
+}
+
+void rtl8723be_led_control(struct ieee80211_hw *hw,
+ enum led_ctl_mode ledaction)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ if ((ppsc->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_START_TO_LINK ||
+ ledaction == LED_CTL_POWER_ON)) {
+ return;
+ }
+ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "ledaction %d,\n", ledaction);
+ _rtl8723be_sw_led_control(hw, ledaction);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/led.h b/drivers/net/wireless/rtlwifi/rtl8723be/led.h
new file mode 100644
index 000000000000..c57de379ee8d
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/led.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_LED_H__
+#define __RTL8723BE_LED_H__
+
+void rtl8723be_init_sw_leds(struct ieee80211_hw *hw);
+void rtl8723be_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl8723be_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl8723be_led_control(struct ieee80211_hw *hw,
+ enum led_ctl_mode ledaction);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/phy.c b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c
new file mode 100644
index 000000000000..1575ef9ece9f
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c
@@ -0,0 +1,2156 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../ps.h"
+#include "../core.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "../rtl8723com/phy_common.h"
+#include "rf.h"
+#include "dm.h"
+#include "table.h"
+#include "trx.h"
+
+static bool _rtl8723be_phy_bb8723b_config_parafile(struct ieee80211_hw *hw);
+static bool _rtl8723be_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
+ u8 configtype);
+static bool rtl8723be_phy_sw_chn_step_by_step(struct ieee80211_hw *hw,
+ u8 channel, u8 *stage,
+ u8 *step, u32 *delay);
+static bool _rtl8723be_check_condition(struct ieee80211_hw *hw,
+ const u32 condition)
+{
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u32 _board = rtlefuse->board_type; /*need efuse define*/
+ u32 _interface = rtlhal->interface;
+ u32 _platform = 0x08;/*SupportPlatform */
+ u32 cond = condition;
+
+ if (condition == 0xCDCDCDCD)
+ return true;
+
+ cond = condition & 0xFF;
+ if ((_board & cond) == 0 && cond != 0x1F)
+ return false;
+
+ cond = condition & 0xFF00;
+ cond = cond >> 8;
+ if ((_interface & cond) == 0 && cond != 0x07)
+ return false;
+
+ cond = condition & 0xFF0000;
+ cond = cond >> 16;
+ if ((_platform & cond) == 0 && cond != 0x0F)
+ return false;
+ return true;
+}
+
+static bool _rtl8723be_phy_config_mac_with_headerfile(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 i;
+ u32 arraylength;
+ u32 *ptrarray;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Read rtl8723beMACPHY_Array\n");
+ arraylength = RTL8723BEMAC_1T_ARRAYLEN;
+ ptrarray = RTL8723BEMAC_1T_ARRAY;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Img:RTL8723bEMAC_1T_ARRAY LEN %d\n", arraylength);
+ for (i = 0; i < arraylength; i = i + 2)
+ rtl_write_byte(rtlpriv, ptrarray[i], (u8) ptrarray[i + 1]);
+ return true;
+}
+
+static bool _rtl8723be_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
+ u8 configtype)
+{
+ #define READ_NEXT_PAIR(v1, v2, i) \
+ do { \
+ i += 2; \
+ v1 = array_table[i];\
+ v2 = array_table[i+1]; \
+ } while (0)
+
+ int i;
+ u32 *array_table;
+ u16 arraylen;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 v1 = 0, v2 = 0;
+
+ if (configtype == BASEBAND_CONFIG_PHY_REG) {
+ arraylen = RTL8723BEPHY_REG_1TARRAYLEN;
+ array_table = RTL8723BEPHY_REG_1TARRAY;
+
+ for (i = 0; i < arraylen; i = i + 2) {
+ v1 = array_table[i];
+ v2 = array_table[i+1];
+ if (v1 < 0xcdcdcdcd) {
+ rtl_bb_delay(hw, v1, v2);
+ } else {/*This line is the start line of branch.*/
+ if (!_rtl8723be_check_condition(hw, array_table[i])) {
+ /*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*/
+ /* Configure matched pairs and
+ * skip to end of if-else.
+ */
+ } else {
+ READ_NEXT_PAIR(v1, v2, i);
+ while (v2 != 0xDEAD &&
+ v2 != 0xCDEF &&
+ v2 != 0xCDCD &&
+ i < arraylen - 2) {
+ rtl_bb_delay(hw,
+ v1, v2);
+ READ_NEXT_PAIR(v1, v2, i);
+ }
+
+ while (v2 != 0xDEAD && i < arraylen - 2)
+ READ_NEXT_PAIR(v1, v2, i);
+ }
+ }
+ }
+ } else if (configtype == BASEBAND_CONFIG_AGC_TAB) {
+ arraylen = RTL8723BEAGCTAB_1TARRAYLEN;
+ array_table = RTL8723BEAGCTAB_1TARRAY;
+
+ for (i = 0; i < arraylen; i = i + 2) {
+ v1 = array_table[i];
+ v2 = array_table[i+1];
+ if (v1 < 0xCDCDCDCD) {
+ rtl_set_bbreg(hw, array_table[i],
+ MASKDWORD,
+ array_table[i + 1]);
+ udelay(1);
+ continue;
+ } else {/*This line is the start line of branch.*/
+ if (!_rtl8723be_check_condition(hw, array_table[i])) {
+ /* 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*/
+ /*Configure matched pairs and
+ *skip to end of if-else.
+ */
+ } else {
+ READ_NEXT_PAIR(v1, v2, i);
+ while (v2 != 0xDEAD &&
+ v2 != 0xCDEF &&
+ v2 != 0xCDCD &&
+ i < arraylen - 2) {
+ rtl_set_bbreg(hw, array_table[i],
+ MASKDWORD,
+ array_table[i + 1]);
+ udelay(1);
+ READ_NEXT_PAIR(v1, v2, i);
+ }
+
+ while (v2 != 0xDEAD && i < arraylen - 2)
+ READ_NEXT_PAIR(v1, v2, i);
+ }
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "The agctab_array_table[0] is "
+ "%x Rtl818EEPHY_REGArray[1] is %x\n",
+ array_table[i], array_table[i + 1]);
+ }
+ }
+ return true;
+}
+
+static u8 _rtl8723be_get_rate_section_index(u32 regaddr)
+{
+ u8 index = 0;
+
+ switch (regaddr) {
+ case RTXAGC_A_RATE18_06:
+ case RTXAGC_B_RATE18_06:
+ index = 0;
+ break;
+ case RTXAGC_A_RATE54_24:
+ case RTXAGC_B_RATE54_24:
+ index = 1;
+ break;
+ case RTXAGC_A_CCK1_MCS32:
+ case RTXAGC_B_CCK1_55_MCS32:
+ index = 2;
+ break;
+ case RTXAGC_B_CCK11_A_CCK2_11:
+ index = 3;
+ break;
+ case RTXAGC_A_MCS03_MCS00:
+ case RTXAGC_B_MCS03_MCS00:
+ index = 4;
+ break;
+ case RTXAGC_A_MCS07_MCS04:
+ case RTXAGC_B_MCS07_MCS04:
+ index = 5;
+ break;
+ case RTXAGC_A_MCS11_MCS08:
+ case RTXAGC_B_MCS11_MCS08:
+ index = 6;
+ break;
+ case RTXAGC_A_MCS15_MCS12:
+ case RTXAGC_B_MCS15_MCS12:
+ index = 7;
+ break;
+ default:
+ regaddr &= 0xFFF;
+ if (regaddr >= 0xC20 && regaddr <= 0xC4C)
+ index = (u8) ((regaddr - 0xC20) / 4);
+ else if (regaddr >= 0xE20 && regaddr <= 0xE4C)
+ index = (u8) ((regaddr - 0xE20) / 4);
+ break;
+ };
+ return index;
+}
+
+u32 rtl8723be_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
+ u32 regaddr, u32 bitmask)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 original_value, readback_value, bitshift;
+ unsigned long flags;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), rfpath(%#x), bitmask(%#x)\n",
+ regaddr, rfpath, bitmask);
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+
+ original_value = rtl8723_phy_rf_serial_read(hw, rfpath, regaddr);
+ bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
+ readback_value = (original_value & bitmask) >> bitshift;
+
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), rfpath(%#x), "
+ "bitmask(%#x), original_value(%#x)\n",
+ regaddr, rfpath, bitmask, original_value);
+
+ return readback_value;
+}
+
+void rtl8723be_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path path,
+ u32 regaddr, u32 bitmask, u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 original_value, bitshift;
+ unsigned long flags;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
+ regaddr, bitmask, data, path);
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+
+ if (bitmask != RFREG_OFFSET_MASK) {
+ original_value = rtl8723_phy_rf_serial_read(hw, path,
+ regaddr);
+ bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
+ data = ((original_value & (~bitmask)) |
+ (data << bitshift));
+ }
+
+ rtl8723_phy_rf_serial_write(hw, path, regaddr, data);
+
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
+ regaddr, bitmask, data, path);
+}
+
+bool rtl8723be_phy_mac_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ bool rtstatus = _rtl8723be_phy_config_mac_with_headerfile(hw);
+
+ rtl_write_byte(rtlpriv, 0x04CA, 0x0B);
+ return rtstatus;
+}
+
+bool rtl8723be_phy_bb_config(struct ieee80211_hw *hw)
+{
+ bool rtstatus = true;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u16 regval;
+ u8 reg_hwparafile = 1;
+ u32 tmp;
+ u8 crystalcap = rtlpriv->efuse.crystalcap;
+ rtl8723_phy_init_bb_rf_reg_def(hw);
+ regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
+ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN,
+ regval | BIT(13) | BIT(0) | BIT(1));
+
+ rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN,
+ FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE |
+ FEN_BB_GLB_RSTN | FEN_BBRSTB);
+ tmp = rtl_read_dword(rtlpriv, 0x4c);
+ rtl_write_dword(rtlpriv, 0x4c, tmp | BIT(23));
+
+ rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80);
+
+ if (reg_hwparafile == 1)
+ rtstatus = _rtl8723be_phy_bb8723b_config_parafile(hw);
+
+ crystalcap = crystalcap & 0x3F;
+ rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0xFFF000,
+ (crystalcap | crystalcap << 6));
+
+ return rtstatus;
+}
+
+bool rtl8723be_phy_rf_config(struct ieee80211_hw *hw)
+{
+ return rtl8723be_phy_rf6052_config(hw);
+}
+
+static void _rtl8723be_config_rf_reg(struct ieee80211_hw *hw, u32 addr,
+ u32 data, enum radio_path rfpath,
+ u32 regaddr)
+{
+ if (addr == 0xfe || addr == 0xffe) {
+ mdelay(50);
+ } else {
+ rtl_set_rfreg(hw, rfpath, regaddr, RFREG_OFFSET_MASK, data);
+ udelay(1);
+ }
+}
+
+static void _rtl8723be_config_rf_radio_a(struct ieee80211_hw *hw,
+ u32 addr, u32 data)
+{
+ u32 content = 0x1000; /*RF Content: radio_a_txt*/
+ u32 maskforphyset = (u32)(content & 0xE000);
+
+ _rtl8723be_config_rf_reg(hw, addr, data, RF90_PATH_A,
+ addr | maskforphyset);
+}
+
+static void _rtl8723be_phy_init_tx_power_by_rate(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ u8 band, path, txnum, section;
+
+ for (band = BAND_ON_2_4G; band <= BAND_ON_5G; ++band)
+ for (path = 0; path < TX_PWR_BY_RATE_NUM_RF; ++path)
+ for (txnum = 0; txnum < TX_PWR_BY_RATE_NUM_RF; ++txnum)
+ for (section = 0;
+ section < TX_PWR_BY_RATE_NUM_SECTION;
+ ++section)
+ rtlphy->tx_power_by_rate_offset[band]
+ [path][txnum][section] = 0;
+}
+
+static void phy_set_txpwr_by_rate_base(struct ieee80211_hw *hw, u8 band,
+ u8 path, u8 rate_section,
+ u8 txnum, u8 value)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ if (path > RF90_PATH_D) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Invalid Rf Path %d in phy_SetTxPowerByRatBase()\n",
+ path);
+ return;
+ }
+
+ if (band == BAND_ON_2_4G) {
+ switch (rate_section) {
+ case CCK:
+ rtlphy->txpwr_by_rate_base_24g[path][txnum][0] = value;
+ break;
+ case OFDM:
+ rtlphy->txpwr_by_rate_base_24g[path][txnum][1] = value;
+ break;
+ case HT_MCS0_MCS7:
+ rtlphy->txpwr_by_rate_base_24g[path][txnum][2] = value;
+ break;
+ case HT_MCS8_MCS15:
+ rtlphy->txpwr_by_rate_base_24g[path][txnum][3] = value;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Invalid RateSection %d in Band 2.4G, Rf Path"
+ " %d, %dTx in PHY_SetTxPowerByRateBase()\n",
+ rate_section, path, txnum);
+ break;
+ };
+ } else {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Invalid Band %d in PHY_SetTxPowerByRateBase()\n",
+ band);
+ }
+}
+
+static u8 phy_get_txpwr_by_rate_base(struct ieee80211_hw *hw, u8 band, u8 path,
+ u8 txnum, u8 rate_section)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u8 value = 0;
+ if (path > RF90_PATH_D) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Invalid Rf Path %d in PHY_GetTxPowerByRateBase()\n",
+ path);
+ return 0;
+ }
+
+ if (band == BAND_ON_2_4G) {
+ switch (rate_section) {
+ case CCK:
+ value = rtlphy->txpwr_by_rate_base_24g[path][txnum][0];
+ break;
+ case OFDM:
+ value = rtlphy->txpwr_by_rate_base_24g[path][txnum][1];
+ break;
+ case HT_MCS0_MCS7:
+ value = rtlphy->txpwr_by_rate_base_24g[path][txnum][2];
+ break;
+ case HT_MCS8_MCS15:
+ value = rtlphy->txpwr_by_rate_base_24g[path][txnum][3];
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Invalid RateSection %d in Band 2.4G, Rf Path"
+ " %d, %dTx in PHY_GetTxPowerByRateBase()\n",
+ rate_section, path, txnum);
+ break;
+ };
+ } else {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Invalid Band %d in PHY_GetTxPowerByRateBase()\n",
+ band);
+ }
+
+ return value;
+}
+
+static void _rtl8723be_phy_store_txpower_by_rate_base(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u16 raw_value = 0;
+ u8 base = 0, path = 0;
+
+ for (path = RF90_PATH_A; path <= RF90_PATH_B; ++path) {
+ if (path == RF90_PATH_A) {
+ raw_value = (u16) (rtlphy->tx_power_by_rate_offset
+ [BAND_ON_2_4G][path][RF_1TX][3] >> 24) & 0xFF;
+ base = (raw_value >> 4) * 10 + (raw_value & 0xF);
+ phy_set_txpwr_by_rate_base(hw, BAND_ON_2_4G, path, CCK,
+ RF_1TX, base);
+ } else if (path == RF90_PATH_B) {
+ raw_value = (u16) (rtlphy->tx_power_by_rate_offset
+ [BAND_ON_2_4G][path][RF_1TX][3] >> 0) & 0xFF;
+ base = (raw_value >> 4) * 10 + (raw_value & 0xF);
+ phy_set_txpwr_by_rate_base(hw, BAND_ON_2_4G, path,
+ CCK, RF_1TX, base);
+ }
+ raw_value = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+ [path][RF_1TX][1] >> 24) & 0xFF;
+ base = (raw_value >> 4) * 10 + (raw_value & 0xF);
+ phy_set_txpwr_by_rate_base(hw, BAND_ON_2_4G, path, OFDM, RF_1TX,
+ base);
+
+ raw_value = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+ [path][RF_1TX][5] >> 24) & 0xFF;
+ base = (raw_value >> 4) * 10 + (raw_value & 0xF);
+ phy_set_txpwr_by_rate_base(hw, BAND_ON_2_4G, path, HT_MCS0_MCS7,
+ RF_1TX, base);
+
+ raw_value = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+ [path][RF_2TX][7] >> 24) & 0xFF;
+ base = (raw_value >> 4) * 10 + (raw_value & 0xF);
+ phy_set_txpwr_by_rate_base(hw, BAND_ON_2_4G, path,
+ HT_MCS8_MCS15, RF_2TX, base);
+ }
+}
+
+static void phy_conv_dbm_to_rel(u32 *data, u8 start, u8 end, u8 base_val)
+{
+ char i = 0;
+ u8 temp_value = 0;
+ u32 temp_data = 0;
+
+ for (i = 3; i >= 0; --i) {
+ if (i >= start && i <= end) {
+ /* Get the exact value */
+ temp_value = (u8) (*data >> (i * 8)) & 0xF;
+ temp_value += ((u8) ((*data >> (i*8 + 4)) & 0xF)) * 10;
+
+ /* Change the value to a relative value */
+ temp_value = (temp_value > base_val) ?
+ temp_value - base_val :
+ base_val - temp_value;
+ } else {
+ temp_value = (u8) (*data >> (i * 8)) & 0xFF;
+ }
+ temp_data <<= 8;
+ temp_data |= temp_value;
+ }
+ *data = temp_data;
+}
+
+static void conv_dbm_to_rel(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u8 base = 0, rfpath = RF90_PATH_A;
+
+ base = phy_get_txpwr_by_rate_base(hw, BAND_ON_2_4G, rfpath,
+ RF_1TX, CCK);
+ phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+ [rfpath][RF_1TX][2]), 1, 1, base);
+ phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+ [rfpath][RF_1TX][3]), 1, 3, base);
+
+ base = phy_get_txpwr_by_rate_base(hw, BAND_ON_2_4G, rfpath,
+ RF_1TX, OFDM);
+ phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+ [rfpath][RF_1TX][0]), 0, 3, base);
+ phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+ [rfpath][RF_1TX][1]), 0, 3, base);
+
+ base = phy_get_txpwr_by_rate_base(hw, BAND_ON_2_4G, rfpath,
+ RF_1TX, HT_MCS0_MCS7);
+ phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+ [rfpath][RF_1TX][4]), 0, 3, base);
+ phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+ [rfpath][RF_1TX][5]), 0, 3, base);
+
+ base = phy_get_txpwr_by_rate_base(hw, BAND_ON_2_4G, rfpath,
+ RF_2TX, HT_MCS8_MCS15);
+ phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+ [rfpath][RF_2TX][6]), 0, 3, base);
+
+ phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+ [rfpath][RF_2TX][7]), 0, 3, base);
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+ "<=== conv_dbm_to_rel()\n");
+}
+
+static void _rtl8723be_phy_txpower_by_rate_configuration(
+ struct ieee80211_hw *hw)
+{
+ _rtl8723be_phy_store_txpower_by_rate_base(hw);
+ conv_dbm_to_rel(hw);
+}
+
+static bool _rtl8723be_phy_bb8723b_config_parafile(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ bool rtstatus;
+
+ rtstatus = _rtl8723be_phy_config_bb_with_headerfile(hw,
+ BASEBAND_CONFIG_PHY_REG);
+ if (!rtstatus) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!");
+ return false;
+ }
+ _rtl8723be_phy_init_tx_power_by_rate(hw);
+ if (!rtlefuse->autoload_failflag) {
+ rtlphy->pwrgroup_cnt = 0;
+ rtstatus = _rtl8723be_phy_config_bb_with_pgheaderfile(hw,
+ BASEBAND_CONFIG_PHY_REG);
+ }
+ _rtl8723be_phy_txpower_by_rate_configuration(hw);
+ if (!rtstatus) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!");
+ return false;
+ }
+ rtstatus = _rtl8723be_phy_config_bb_with_headerfile(hw,
+ BASEBAND_CONFIG_AGC_TAB);
+ if (!rtstatus) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AGC Table Fail\n");
+ return false;
+ }
+ rtlphy->cck_high_power = (bool) (rtl_get_bbreg(hw,
+ RFPGA0_XA_HSSIPARAMETER2,
+ 0x200));
+ return true;
+}
+
+static void _rtl8723be_store_tx_power_by_rate(struct ieee80211_hw *hw,
+ u32 band, u32 rfpath,
+ u32 txnum, u32 regaddr,
+ u32 bitmask, u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u8 rate_section = _rtl8723be_get_rate_section_index(regaddr);
+
+ if (band != BAND_ON_2_4G && band != BAND_ON_5G) {
+ RT_TRACE(rtlpriv, COMP_POWER, PHY_TXPWR,
+ "Invalid Band %d\n", band);
+ return;
+ }
+
+ if (rfpath > TX_PWR_BY_RATE_NUM_RF) {
+ RT_TRACE(rtlpriv, COMP_POWER, PHY_TXPWR,
+ "Invalid RfPath %d\n", rfpath);
+ return;
+ }
+ if (txnum > TX_PWR_BY_RATE_NUM_RF) {
+ RT_TRACE(rtlpriv, COMP_POWER, PHY_TXPWR,
+ "Invalid TxNum %d\n", txnum);
+ return;
+ }
+ rtlphy->tx_power_by_rate_offset[band][rfpath][txnum][rate_section] =
+ data;
+}
+
+static bool _rtl8723be_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
+ u8 configtype)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ int i;
+ u32 *phy_regarray_table_pg;
+ u16 phy_regarray_pg_len;
+ u32 v1 = 0, v2 = 0, v3 = 0, v4 = 0, v5 = 0, v6 = 0;
+
+ phy_regarray_pg_len = RTL8723BEPHY_REG_ARRAY_PGLEN;
+ phy_regarray_table_pg = RTL8723BEPHY_REG_ARRAY_PG;
+
+ if (configtype == BASEBAND_CONFIG_PHY_REG) {
+ for (i = 0; i < phy_regarray_pg_len; i = i + 6) {
+ v1 = phy_regarray_table_pg[i];
+ v2 = phy_regarray_table_pg[i+1];
+ v3 = phy_regarray_table_pg[i+2];
+ v4 = phy_regarray_table_pg[i+3];
+ v5 = phy_regarray_table_pg[i+4];
+ v6 = phy_regarray_table_pg[i+5];
+
+ if (v1 < 0xcdcdcdcd) {
+ if (phy_regarray_table_pg[i] == 0xfe ||
+ phy_regarray_table_pg[i] == 0xffe)
+ mdelay(50);
+ else
+ _rtl8723be_store_tx_power_by_rate(hw,
+ v1, v2, v3, v4, v5, v6);
+ continue;
+ } else {
+ /*don't need the hw_body*/
+ if (!_rtl8723be_check_condition(hw,
+ phy_regarray_table_pg[i])) {
+ i += 2; /* skip the pair of expression*/
+ v1 = phy_regarray_table_pg[i];
+ v2 = phy_regarray_table_pg[i+1];
+ v3 = phy_regarray_table_pg[i+2];
+ while (v2 != 0xDEAD) {
+ i += 3;
+ v1 = phy_regarray_table_pg[i];
+ v2 = phy_regarray_table_pg[i+1];
+ v3 = phy_regarray_table_pg[i+2];
+ }
+ }
+ }
+ }
+ } else {
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+ "configtype != BaseBand_Config_PHY_REG\n");
+ }
+ return true;
+}
+
+bool rtl8723be_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+ enum radio_path rfpath)
+{
+ #define READ_NEXT_RF_PAIR(v1, v2, i) \
+ do { \
+ i += 2; \
+ v1 = radioa_array_table[i]; \
+ v2 = radioa_array_table[i+1]; \
+ } while (0)
+
+ int i;
+ bool rtstatus = true;
+ u32 *radioa_array_table;
+ u16 radioa_arraylen;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u32 v1 = 0, v2 = 0;
+
+ radioa_arraylen = RTL8723BE_RADIOA_1TARRAYLEN;
+ radioa_array_table = RTL8723BE_RADIOA_1TARRAY;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Radio_A:RTL8723BE_RADIOA_1TARRAY %d\n", radioa_arraylen);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio No %x\n", rfpath);
+ rtstatus = true;
+ switch (rfpath) {
+ case RF90_PATH_A:
+ for (i = 0; i < radioa_arraylen; i = i + 2) {
+ v1 = radioa_array_table[i];
+ v2 = radioa_array_table[i+1];
+ if (v1 < 0xcdcdcdcd) {
+ _rtl8723be_config_rf_radio_a(hw, v1, v2);
+ } else { /*This line is the start line of branch.*/
+ if (!_rtl8723be_check_condition(hw,
+ radioa_array_table[i])) {
+ /* Discard the following
+ * (offset, data) pairs
+ */
+ READ_NEXT_RF_PAIR(v1, v2, i);
+ while (v2 != 0xDEAD &&
+ v2 != 0xCDEF &&
+ v2 != 0xCDCD &&
+ i < radioa_arraylen - 2)
+ READ_NEXT_RF_PAIR(v1, v2, i);
+ i -= 2; /* prevent from for-loop += 2*/
+ } else {
+ /* Configure matched pairs
+ * and skip to end of if-else.
+ */
+ READ_NEXT_RF_PAIR(v1, v2, i);
+ while (v2 != 0xDEAD &&
+ v2 != 0xCDEF &&
+ v2 != 0xCDCD &&
+ i < radioa_arraylen - 2) {
+ _rtl8723be_config_rf_radio_a(hw,
+ v1, v2);
+ READ_NEXT_RF_PAIR(v1, v2, i);
+ }
+
+ while (v2 != 0xDEAD &&
+ i < radioa_arraylen - 2) {
+ READ_NEXT_RF_PAIR(v1, v2, i);
+ }
+ }
+ }
+ }
+
+ if (rtlhal->oem_id == RT_CID_819X_HP)
+ _rtl8723be_config_rf_radio_a(hw, 0x52, 0x7E4BD);
+
+ break;
+ case RF90_PATH_B:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not process\n");
+ break;
+ case RF90_PATH_C:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not process\n");
+ break;
+ case RF90_PATH_D:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not process\n");
+ break;
+ }
+ return true;
+}
+
+void rtl8723be_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ rtlphy->default_initialgain[0] =
+ (u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0);
+ rtlphy->default_initialgain[1] =
+ (u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0);
+ rtlphy->default_initialgain[2] =
+ (u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, MASKBYTE0);
+ rtlphy->default_initialgain[3] =
+ (u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, MASKBYTE0);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Default initial gain (c50 = 0x%x, "
+ "c58 = 0x%x, c60 = 0x%x, c68 = 0x%x\n",
+ rtlphy->default_initialgain[0],
+ rtlphy->default_initialgain[1],
+ rtlphy->default_initialgain[2],
+ rtlphy->default_initialgain[3]);
+
+ rtlphy->framesync = (u8) rtl_get_bbreg(hw, ROFDM0_RXDETECTOR3,
+ MASKBYTE0);
+ rtlphy->framesync_c34 = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR2,
+ MASKDWORD);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Default framesync (0x%x) = 0x%x\n",
+ ROFDM0_RXDETECTOR3, rtlphy->framesync);
+}
+
+void rtl8723be_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u8 txpwr_level;
+ long txpwr_dbm;
+
+ txpwr_level = rtlphy->cur_cck_txpwridx;
+ txpwr_dbm = rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_B,
+ txpwr_level);
+ txpwr_level = rtlphy->cur_ofdm24g_txpwridx;
+ if (rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, txpwr_level) >
+ txpwr_dbm)
+ txpwr_dbm =
+ rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G,
+ txpwr_level);
+ txpwr_level = rtlphy->cur_ofdm24g_txpwridx;
+ if (rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G,
+ txpwr_level) > txpwr_dbm)
+ txpwr_dbm =
+ rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G,
+ txpwr_level);
+ *powerlevel = txpwr_dbm;
+}
+
+static u8 _rtl8723be_phy_get_ratesection_intxpower_byrate(enum radio_path path,
+ u8 rate)
+{
+ u8 rate_section = 0;
+
+ switch (rate) {
+ case DESC92C_RATE1M:
+ rate_section = 2;
+ break;
+ case DESC92C_RATE2M:
+ case DESC92C_RATE5_5M:
+ if (path == RF90_PATH_A)
+ rate_section = 3;
+ else if (path == RF90_PATH_B)
+ rate_section = 2;
+ break;
+ case DESC92C_RATE11M:
+ rate_section = 3;
+ break;
+ case DESC92C_RATE6M:
+ case DESC92C_RATE9M:
+ case DESC92C_RATE12M:
+ case DESC92C_RATE18M:
+ rate_section = 0;
+ break;
+ case DESC92C_RATE24M:
+ case DESC92C_RATE36M:
+ case DESC92C_RATE48M:
+ case DESC92C_RATE54M:
+ rate_section = 1;
+ break;
+ case DESC92C_RATEMCS0:
+ case DESC92C_RATEMCS1:
+ case DESC92C_RATEMCS2:
+ case DESC92C_RATEMCS3:
+ rate_section = 4;
+ break;
+ case DESC92C_RATEMCS4:
+ case DESC92C_RATEMCS5:
+ case DESC92C_RATEMCS6:
+ case DESC92C_RATEMCS7:
+ rate_section = 5;
+ break;
+ case DESC92C_RATEMCS8:
+ case DESC92C_RATEMCS9:
+ case DESC92C_RATEMCS10:
+ case DESC92C_RATEMCS11:
+ rate_section = 6;
+ break;
+ case DESC92C_RATEMCS12:
+ case DESC92C_RATEMCS13:
+ case DESC92C_RATEMCS14:
+ case DESC92C_RATEMCS15:
+ rate_section = 7;
+ break;
+ default:
+ RT_ASSERT(true, "Rate_Section is Illegal\n");
+ break;
+ }
+ return rate_section;
+}
+
+static u8 _rtl8723be_get_txpower_by_rate(struct ieee80211_hw *hw,
+ enum band_type band,
+ enum radio_path rfpath, u8 rate)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u8 shift = 0, rate_section, tx_num;
+ char tx_pwr_diff = 0;
+
+ rate_section = _rtl8723be_phy_get_ratesection_intxpower_byrate(rfpath,
+ rate);
+ tx_num = RF_TX_NUM_NONIMPLEMENT;
+
+ if (tx_num == RF_TX_NUM_NONIMPLEMENT) {
+ if (rate >= DESC92C_RATEMCS8 && rate <= DESC92C_RATEMCS15)
+ tx_num = RF_2TX;
+ else
+ tx_num = RF_1TX;
+ }
+
+ switch (rate) {
+ case DESC92C_RATE6M:
+ case DESC92C_RATE24M:
+ case DESC92C_RATEMCS0:
+ case DESC92C_RATEMCS4:
+ case DESC92C_RATEMCS8:
+ case DESC92C_RATEMCS12:
+ shift = 0;
+ break;
+ case DESC92C_RATE1M:
+ case DESC92C_RATE2M:
+ case DESC92C_RATE9M:
+ case DESC92C_RATE36M:
+ case DESC92C_RATEMCS1:
+ case DESC92C_RATEMCS5:
+ case DESC92C_RATEMCS9:
+ case DESC92C_RATEMCS13:
+ shift = 8;
+ break;
+ case DESC92C_RATE5_5M:
+ case DESC92C_RATE12M:
+ case DESC92C_RATE48M:
+ case DESC92C_RATEMCS2:
+ case DESC92C_RATEMCS6:
+ case DESC92C_RATEMCS10:
+ case DESC92C_RATEMCS14:
+ shift = 16;
+ break;
+ case DESC92C_RATE11M:
+ case DESC92C_RATE18M:
+ case DESC92C_RATE54M:
+ case DESC92C_RATEMCS3:
+ case DESC92C_RATEMCS7:
+ case DESC92C_RATEMCS11:
+ case DESC92C_RATEMCS15:
+ shift = 24;
+ break;
+ default:
+ RT_ASSERT(true, "Rate_Section is Illegal\n");
+ break;
+ }
+ tx_pwr_diff = (u8)(rtlphy->tx_power_by_rate_offset[band][rfpath][tx_num]
+ [rate_section] >> shift) & 0xff;
+
+ return tx_pwr_diff;
+}
+
+static u8 _rtl8723be_get_txpower_index(struct ieee80211_hw *hw, u8 path,
+ u8 rate, u8 bandwidth, u8 channel)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 index = (channel - 1);
+ u8 txpower;
+ u8 power_diff_byrate = 0;
+
+ if (channel > 14 || channel < 1) {
+ index = 0;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Illegal channel!\n");
+ }
+ if (RTL8723E_RX_HAL_IS_CCK_RATE(rate))
+ txpower = rtlefuse->txpwrlevel_cck[path][index];
+ else if (DESC92C_RATE6M <= rate)
+ txpower = rtlefuse->txpwrlevel_ht40_1s[path][index];
+ else
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "invalid rate\n");
+
+ if (DESC92C_RATE6M <= rate && rate <= DESC92C_RATE54M &&
+ !RTL8723E_RX_HAL_IS_CCK_RATE(rate))
+ txpower += rtlefuse->txpwr_legacyhtdiff[0][TX_1S];
+
+ if (bandwidth == HT_CHANNEL_WIDTH_20) {
+ if (DESC92C_RATEMCS0 <= rate && rate <= DESC92C_RATEMCS15)
+ txpower += rtlefuse->txpwr_ht20diff[0][TX_1S];
+ if (DESC92C_RATEMCS8 <= rate && rate <= DESC92C_RATEMCS15)
+ txpower += rtlefuse->txpwr_ht20diff[0][TX_2S];
+ } else if (bandwidth == HT_CHANNEL_WIDTH_20_40) {
+ if (DESC92C_RATEMCS0 <= rate && rate <= DESC92C_RATEMCS15)
+ txpower += rtlefuse->txpwr_ht40diff[0][TX_1S];
+ if (DESC92C_RATEMCS8 <= rate && rate <= DESC92C_RATEMCS15)
+ txpower += rtlefuse->txpwr_ht40diff[0][TX_2S];
+ }
+ if (rtlefuse->eeprom_regulatory != 2)
+ power_diff_byrate = _rtl8723be_get_txpower_by_rate(hw,
+ BAND_ON_2_4G,
+ path, rate);
+
+ txpower += power_diff_byrate;
+
+ if (txpower > MAX_POWER_INDEX)
+ txpower = MAX_POWER_INDEX;
+
+ return txpower;
+}
+
+static void _rtl8723be_phy_set_txpower_index(struct ieee80211_hw *hw,
+ u8 power_index, u8 path, u8 rate)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ if (path == RF90_PATH_A) {
+ switch (rate) {
+ case DESC92C_RATE1M:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_CCK1_MCS32,
+ MASKBYTE1, power_index);
+ break;
+ case DESC92C_RATE2M:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_B_CCK11_A_CCK2_11,
+ MASKBYTE1, power_index);
+ break;
+ case DESC92C_RATE5_5M:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_B_CCK11_A_CCK2_11,
+ MASKBYTE2, power_index);
+ break;
+ case DESC92C_RATE11M:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_B_CCK11_A_CCK2_11,
+ MASKBYTE3, power_index);
+ break;
+ case DESC92C_RATE6M:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE18_06,
+ MASKBYTE0, power_index);
+ break;
+ case DESC92C_RATE9M:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE18_06,
+ MASKBYTE1, power_index);
+ break;
+ case DESC92C_RATE12M:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE18_06,
+ MASKBYTE2, power_index);
+ break;
+ case DESC92C_RATE18M:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE18_06,
+ MASKBYTE3, power_index);
+ break;
+ case DESC92C_RATE24M:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE54_24,
+ MASKBYTE0, power_index);
+ break;
+ case DESC92C_RATE36M:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE54_24,
+ MASKBYTE1, power_index);
+ break;
+ case DESC92C_RATE48M:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE54_24,
+ MASKBYTE2, power_index);
+ break;
+ case DESC92C_RATE54M:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE54_24,
+ MASKBYTE3, power_index);
+ break;
+ case DESC92C_RATEMCS0:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS03_MCS00,
+ MASKBYTE0, power_index);
+ break;
+ case DESC92C_RATEMCS1:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS03_MCS00,
+ MASKBYTE1, power_index);
+ break;
+ case DESC92C_RATEMCS2:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS03_MCS00,
+ MASKBYTE2, power_index);
+ break;
+ case DESC92C_RATEMCS3:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS03_MCS00,
+ MASKBYTE3, power_index);
+ break;
+ case DESC92C_RATEMCS4:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS07_MCS04,
+ MASKBYTE0, power_index);
+ break;
+ case DESC92C_RATEMCS5:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS07_MCS04,
+ MASKBYTE1, power_index);
+ break;
+ case DESC92C_RATEMCS6:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS07_MCS04,
+ MASKBYTE2, power_index);
+ break;
+ case DESC92C_RATEMCS7:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS07_MCS04,
+ MASKBYTE3, power_index);
+ break;
+ case DESC92C_RATEMCS8:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS11_MCS08,
+ MASKBYTE0, power_index);
+ break;
+ case DESC92C_RATEMCS9:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS11_MCS08,
+ MASKBYTE1, power_index);
+ break;
+ case DESC92C_RATEMCS10:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS11_MCS08,
+ MASKBYTE2, power_index);
+ break;
+ case DESC92C_RATEMCS11:
+ rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS11_MCS08,
+ MASKBYTE3, power_index);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "Invalid Rate!!\n");
+ break;
+ }
+ } else {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "Invalid RFPath!!\n");
+ }
+}
+
+void rtl8723be_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel)
+{
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 cck_rates[] = {DESC92C_RATE1M, DESC92C_RATE2M,
+ DESC92C_RATE5_5M, DESC92C_RATE11M};
+ u8 ofdm_rates[] = {DESC92C_RATE6M, DESC92C_RATE9M,
+ DESC92C_RATE12M, DESC92C_RATE18M,
+ DESC92C_RATE24M, DESC92C_RATE36M,
+ DESC92C_RATE48M, DESC92C_RATE54M};
+ u8 ht_rates_1t[] = {DESC92C_RATEMCS0, DESC92C_RATEMCS1,
+ DESC92C_RATEMCS2, DESC92C_RATEMCS3,
+ DESC92C_RATEMCS4, DESC92C_RATEMCS5,
+ DESC92C_RATEMCS6, DESC92C_RATEMCS7};
+ u8 i, size;
+ u8 power_index;
+
+ if (!rtlefuse->txpwr_fromeprom)
+ return;
+
+ size = sizeof(cck_rates) / sizeof(u8);
+ for (i = 0; i < size; i++) {
+ power_index = _rtl8723be_get_txpower_index(hw, RF90_PATH_A,
+ cck_rates[i],
+ rtl_priv(hw)->phy.current_chan_bw,
+ channel);
+ _rtl8723be_phy_set_txpower_index(hw, power_index, RF90_PATH_A,
+ cck_rates[i]);
+ }
+ size = sizeof(ofdm_rates) / sizeof(u8);
+ for (i = 0; i < size; i++) {
+ power_index = _rtl8723be_get_txpower_index(hw, RF90_PATH_A,
+ ofdm_rates[i],
+ rtl_priv(hw)->phy.current_chan_bw,
+ channel);
+ _rtl8723be_phy_set_txpower_index(hw, power_index, RF90_PATH_A,
+ ofdm_rates[i]);
+ }
+ size = sizeof(ht_rates_1t) / sizeof(u8);
+ for (i = 0; i < size; i++) {
+ power_index = _rtl8723be_get_txpower_index(hw, RF90_PATH_A,
+ ht_rates_1t[i],
+ rtl_priv(hw)->phy.current_chan_bw,
+ channel);
+ _rtl8723be_phy_set_txpower_index(hw, power_index, RF90_PATH_A,
+ ht_rates_1t[i]);
+ }
+}
+
+void rtl8723be_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ enum io_type iotype;
+
+ if (!is_hal_stop(rtlhal)) {
+ switch (operation) {
+ case SCAN_OPT_BACKUP:
+ iotype = IO_CMD_PAUSE_DM_BY_SCAN;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_IO_CMD,
+ (u8 *)&iotype);
+ break;
+ case SCAN_OPT_RESTORE:
+ iotype = IO_CMD_RESUME_DM_BY_SCAN;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_IO_CMD,
+ (u8 *)&iotype);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Unknown Scan Backup operation.\n");
+ break;
+ }
+ }
+}
+
+void rtl8723be_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u8 reg_bw_opmode;
+ u8 reg_prsr_rsc;
+
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+ "Switch to %s bandwidth\n",
+ rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
+ "20MHz" : "40MHz");
+
+ if (is_hal_stop(rtlhal)) {
+ rtlphy->set_bwmode_inprogress = false;
+ return;
+ }
+
+ reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE);
+ reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2);
+
+ switch (rtlphy->current_chan_bw) {
+ case HT_CHANNEL_WIDTH_20:
+ reg_bw_opmode |= BW_OPMODE_20MHZ;
+ rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
+ break;
+ case HT_CHANNEL_WIDTH_20_40:
+ reg_bw_opmode &= ~BW_OPMODE_20MHZ;
+ rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
+ reg_prsr_rsc = (reg_prsr_rsc & 0x90) |
+ (mac->cur_40_prime_sc << 5);
+ rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "unknown bandwidth: %#X\n", rtlphy->current_chan_bw);
+ break;
+ }
+
+ switch (rtlphy->current_chan_bw) {
+ case HT_CHANNEL_WIDTH_20:
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0);
+ rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0);
+ break;
+ case HT_CHANNEL_WIDTH_20_40:
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1);
+ rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1);
+ rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND,
+ (mac->cur_40_prime_sc >> 1));
+ rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc);
+ rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)),
+ (mac->cur_40_prime_sc ==
+ HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "unknown bandwidth: %#X\n", rtlphy->current_chan_bw);
+ break;
+ }
+ rtl8723be_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw);
+ rtlphy->set_bwmode_inprogress = false;
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, "\n");
+}
+
+void rtl8723be_phy_set_bw_mode(struct ieee80211_hw *hw,
+ enum nl80211_channel_type ch_type)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 tmp_bw = rtlphy->current_chan_bw;
+
+ if (rtlphy->set_bwmode_inprogress)
+ return;
+ rtlphy->set_bwmode_inprogress = true;
+ if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
+ rtl8723be_phy_set_bw_mode_callback(hw);
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "false driver sleep or unload\n");
+ rtlphy->set_bwmode_inprogress = false;
+ rtlphy->current_chan_bw = tmp_bw;
+ }
+}
+
+void rtl8723be_phy_sw_chnl_callback(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 delay;
+
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+ "switch to channel%d\n", rtlphy->current_channel);
+ if (is_hal_stop(rtlhal))
+ return;
+ do {
+ if (!rtlphy->sw_chnl_inprogress)
+ break;
+ if (!rtl8723be_phy_sw_chn_step_by_step(hw,
+ rtlphy->current_channel,
+ &rtlphy->sw_chnl_stage,
+ &rtlphy->sw_chnl_step,
+ &delay)) {
+ if (delay > 0)
+ mdelay(delay);
+ else
+ continue;
+ } else {
+ rtlphy->sw_chnl_inprogress = false;
+ }
+ break;
+ } while (true);
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "\n");
+}
+
+u8 rtl8723be_phy_sw_chnl(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ if (rtlphy->sw_chnl_inprogress)
+ return 0;
+ if (rtlphy->set_bwmode_inprogress)
+ return 0;
+ RT_ASSERT((rtlphy->current_channel <= 14),
+ "WIRELESS_MODE_G but channel>14");
+ rtlphy->sw_chnl_inprogress = true;
+ rtlphy->sw_chnl_stage = 0;
+ rtlphy->sw_chnl_step = 0;
+ if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
+ rtl8723be_phy_sw_chnl_callback(hw);
+ RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
+ "sw_chnl_inprogress false schdule "
+ "workitem current channel %d\n",
+ rtlphy->current_channel);
+ rtlphy->sw_chnl_inprogress = false;
+ } else {
+ RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
+ "sw_chnl_inprogress false driver sleep or"
+ " unload\n");
+ rtlphy->sw_chnl_inprogress = false;
+ }
+ return 1;
+}
+
+static bool rtl8723be_phy_sw_chn_step_by_step(struct ieee80211_hw *hw,
+ u8 channel, u8 *stage,
+ u8 *step, u32 *delay)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct swchnlcmd precommoncmd[MAX_PRECMD_CNT];
+ u32 precommoncmdcnt;
+ struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT];
+ u32 postcommoncmdcnt;
+ struct swchnlcmd rfdependcmd[MAX_RFDEPENDCMD_CNT];
+ u32 rfdependcmdcnt;
+ struct swchnlcmd *currentcmd = NULL;
+ u8 rfpath;
+ u8 num_total_rfpath = rtlphy->num_total_rfpath;
+
+ precommoncmdcnt = 0;
+ rtl8723_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+ MAX_PRECMD_CNT,
+ CMDID_SET_TXPOWEROWER_LEVEL,
+ 0, 0, 0);
+ rtl8723_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+ MAX_PRECMD_CNT, CMDID_END, 0, 0, 0);
+ postcommoncmdcnt = 0;
+ rtl8723_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++,
+ MAX_POSTCMD_CNT, CMDID_END,
+ 0, 0, 0);
+ rfdependcmdcnt = 0;
+
+ RT_ASSERT((channel >= 1 && channel <= 14),
+ "illegal channel for Zebra: %d\n", channel);
+
+ rtl8723_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+ MAX_RFDEPENDCMD_CNT,
+ CMDID_RF_WRITEREG,
+ RF_CHNLBW, channel, 10);
+
+ rtl8723_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+ MAX_RFDEPENDCMD_CNT,
+ CMDID_END, 0, 0, 0);
+
+ do {
+ switch (*stage) {
+ case 0:
+ currentcmd = &precommoncmd[*step];
+ break;
+ case 1:
+ currentcmd = &rfdependcmd[*step];
+ break;
+ case 2:
+ currentcmd = &postcommoncmd[*step];
+ break;
+ }
+
+ if (currentcmd->cmdid == CMDID_END) {
+ if ((*stage) == 2) {
+ return true;
+ } else {
+ (*stage)++;
+ (*step) = 0;
+ continue;
+ }
+ }
+
+ switch (currentcmd->cmdid) {
+ case CMDID_SET_TXPOWEROWER_LEVEL:
+ rtl8723be_phy_set_txpower_level(hw, channel);
+ break;
+ case CMDID_WRITEPORT_ULONG:
+ rtl_write_dword(rtlpriv, currentcmd->para1,
+ currentcmd->para2);
+ break;
+ case CMDID_WRITEPORT_USHORT:
+ rtl_write_word(rtlpriv, currentcmd->para1,
+ (u16) currentcmd->para2);
+ break;
+ case CMDID_WRITEPORT_UCHAR:
+ rtl_write_byte(rtlpriv, currentcmd->para1,
+ (u8) currentcmd->para2);
+ break;
+ case CMDID_RF_WRITEREG:
+ for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) {
+ rtlphy->rfreg_chnlval[rfpath] =
+ ((rtlphy->rfreg_chnlval[rfpath] &
+ 0xfffffc00) | currentcmd->para2);
+
+ rtl_set_rfreg(hw, (enum radio_path)rfpath,
+ currentcmd->para1,
+ RFREG_OFFSET_MASK,
+ rtlphy->rfreg_chnlval[rfpath]);
+ }
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not process\n");
+ break;
+ }
+
+ break;
+ } while (true);
+
+ (*delay) = currentcmd->msdelay;
+ (*step)++;
+ return false;
+}
+
+static u8 _rtl8723be_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb)
+{
+ u32 reg_eac, reg_e94, reg_e9c, reg_ea4;
+ u8 result = 0x00;
+
+ rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c1c);
+ rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x30008c1c);
+ rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x8214032a);
+ rtl_set_bbreg(hw, 0xe3c, MASKDWORD, 0x28160000);
+
+ rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x00462911);
+ rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf9000000);
+ rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000);
+
+ mdelay(IQK_DELAY_TIME);
+
+ reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
+ reg_e94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD);
+ reg_e9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD);
+ reg_ea4 = rtl_get_bbreg(hw, 0xea4, MASKDWORD);
+
+ if (!(reg_eac & BIT(28)) &&
+ (((reg_e94 & 0x03FF0000) >> 16) != 0x142) &&
+ (((reg_e9c & 0x03FF0000) >> 16) != 0x42))
+ result |= 0x01;
+ return result;
+}
+
+static bool phy_similarity_cmp(struct ieee80211_hw *hw, long result[][8],
+ u8 c1, u8 c2)
+{
+ u32 i, j, diff, simularity_bitmap, bound;
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ u8 final_candidate[2] = { 0xFF, 0xFF };
+ bool bresult = true, is2t = IS_92C_SERIAL(rtlhal->version);
+
+ if (is2t)
+ bound = 8;
+ else
+ bound = 4;
+
+ simularity_bitmap = 0;
+
+ for (i = 0; i < bound; i++) {
+ diff = (result[c1][i] > result[c2][i]) ?
+ (result[c1][i] - result[c2][i]) :
+ (result[c2][i] - result[c1][i]);
+
+ if (diff > MAX_TOLERANCE) {
+ if ((i == 2 || i == 6) && !simularity_bitmap) {
+ if (result[c1][i] + result[c1][i + 1] == 0)
+ final_candidate[(i / 4)] = c2;
+ else if (result[c2][i] + result[c2][i + 1] == 0)
+ final_candidate[(i / 4)] = c1;
+ else
+ simularity_bitmap |= (1 << i);
+ } else {
+ simularity_bitmap |= (1 << i);
+ }
+ }
+ }
+
+ if (simularity_bitmap == 0) {
+ for (i = 0; i < (bound / 4); i++) {
+ if (final_candidate[i] != 0xFF) {
+ for (j = i * 4; j < (i + 1) * 4 - 2; j++)
+ result[3][j] =
+ result[final_candidate[i]][j];
+ bresult = false;
+ }
+ }
+ return bresult;
+ } else if (!(simularity_bitmap & 0x0F)) {
+ for (i = 0; i < 4; i++)
+ result[3][i] = result[c1][i];
+ return false;
+ } else if (!(simularity_bitmap & 0xF0) && is2t) {
+ for (i = 4; i < 8; i++)
+ result[3][i] = result[c1][i];
+ return false;
+ } else {
+ return false;
+ }
+}
+
+static void _rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw,
+ long result[][8], u8 t, bool is2t)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 i;
+ u8 patha_ok;
+ u32 adda_reg[IQK_ADDA_REG_NUM] = {
+ 0x85c, 0xe6c, 0xe70, 0xe74,
+ 0xe78, 0xe7c, 0xe80, 0xe84,
+ 0xe88, 0xe8c, 0xed0, 0xed4,
+ 0xed8, 0xedc, 0xee0, 0xeec
+ };
+
+ u32 iqk_mac_reg[IQK_MAC_REG_NUM] = {
+ 0x522, 0x550, 0x551, 0x040
+ };
+ u32 iqk_bb_reg[IQK_BB_REG_NUM] = {
+ ROFDM0_TRXPATHENABLE, ROFDM0_TRMUXPAR,
+ RFPGA0_XCD_RFINTERFACESW, 0xb68, 0xb6c,
+ 0x870, 0x860,
+ 0x864, 0x800
+ };
+ const u32 retrycount = 2;
+ u32 path_sel_bb, path_sel_rf;
+ u8 tmp_reg_c50, tmp_reg_c58;
+
+ tmp_reg_c50 = rtl_get_bbreg(hw, 0xc50, MASKBYTE0);
+ tmp_reg_c58 = rtl_get_bbreg(hw, 0xc58, MASKBYTE0);
+
+ if (t == 0) {
+ rtl8723_save_adda_registers(hw, adda_reg,
+ rtlphy->adda_backup, 16);
+ rtl8723_phy_save_mac_registers(hw, iqk_mac_reg,
+ rtlphy->iqk_mac_backup);
+ rtl8723_save_adda_registers(hw, iqk_bb_reg,
+ rtlphy->iqk_bb_backup,
+ IQK_BB_REG_NUM);
+ }
+ rtl8723_phy_path_adda_on(hw, adda_reg, true, is2t);
+ if (t == 0) {
+ rtlphy->rfpi_enable = (u8) rtl_get_bbreg(hw,
+ RFPGA0_XA_HSSIPARAMETER1,
+ BIT(8));
+ }
+ if (!rtlphy->rfpi_enable)
+ rtl8723_phy_pi_mode_switch(hw, true);
+
+ path_sel_bb = rtl_get_bbreg(hw, 0x948, MASKDWORD);
+ path_sel_rf = rtl_get_rfreg(hw, RF90_PATH_A, 0xb0, 0xfffff);
+
+ /*BB Setting*/
+ rtl_set_bbreg(hw, 0x800, BIT(24), 0x00);
+ rtl_set_bbreg(hw, 0xc04, MASKDWORD, 0x03a05600);
+ rtl_set_bbreg(hw, 0xc08, MASKDWORD, 0x000800e4);
+ rtl_set_bbreg(hw, 0x874, MASKDWORD, 0x22204000);
+
+ rtl_set_bbreg(hw, 0x870, BIT(10), 0x01);
+ rtl_set_bbreg(hw, 0x870, BIT(26), 0x01);
+ rtl_set_bbreg(hw, 0x860, BIT(10), 0x00);
+ rtl_set_bbreg(hw, 0x864, BIT(10), 0x00);
+
+ if (is2t)
+ rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASKDWORD, 0x10000);
+ rtl8723_phy_mac_setting_calibration(hw, iqk_mac_reg,
+ rtlphy->iqk_mac_backup);
+ rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x0f600000);
+
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
+ rtl_set_bbreg(hw, 0xe40, MASKDWORD, 0x01007c00);
+ rtl_set_bbreg(hw, 0xe44, MASKDWORD, 0x81004800);
+ for (i = 0; i < retrycount; i++) {
+ patha_ok = _rtl8723be_phy_path_a_iqk(hw, is2t);
+ if (patha_ok == 0x01) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Path A Tx IQK Success!!\n");
+ result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ break;
+ }
+ }
+
+ if (0 == patha_ok)
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Path A IQK Success!!\n");
+ if (is2t) {
+ rtl8723_phy_path_a_standby(hw);
+ rtl8723_phy_path_adda_on(hw, adda_reg, false, is2t);
+ }
+
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0);
+
+ if (t != 0) {
+ if (!rtlphy->rfpi_enable)
+ rtl8723_phy_pi_mode_switch(hw, false);
+ rtl8723_phy_reload_adda_registers(hw, adda_reg,
+ rtlphy->adda_backup, 16);
+ rtl8723_phy_reload_mac_registers(hw, iqk_mac_reg,
+ rtlphy->iqk_mac_backup);
+ rtl8723_phy_reload_adda_registers(hw, iqk_bb_reg,
+ rtlphy->iqk_bb_backup,
+ IQK_BB_REG_NUM);
+
+ rtl_set_bbreg(hw, 0x948, MASKDWORD, path_sel_bb);
+ rtl_set_rfreg(hw, RF90_PATH_B, 0xb0, 0xfffff, path_sel_rf);
+
+ rtl_set_bbreg(hw, 0xc50, MASKBYTE0, 0x50);
+ rtl_set_bbreg(hw, 0xc50, MASKBYTE0, tmp_reg_c50);
+ if (is2t) {
+ rtl_set_bbreg(hw, 0xc58, MASKBYTE0, 0x50);
+ rtl_set_bbreg(hw, 0xc58, MASKBYTE0, tmp_reg_c58);
+ }
+ rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x01008c00);
+ rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x01008c00);
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "8723be IQK Finish!!\n");
+}
+
+static void _rtl8723be_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 tmpreg;
+ u32 rf_a_mode = 0, rf_b_mode = 0, lc_cal;
+
+ tmpreg = rtl_read_byte(rtlpriv, 0xd03);
+
+ if ((tmpreg & 0x70) != 0)
+ rtl_write_byte(rtlpriv, 0xd03, tmpreg & 0x8F);
+ else
+ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
+
+ if ((tmpreg & 0x70) != 0) {
+ rf_a_mode = rtl_get_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS);
+
+ if (is2t)
+ rf_b_mode = rtl_get_rfreg(hw, RF90_PATH_B, 0x00,
+ MASK12BITS);
+
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS,
+ (rf_a_mode & 0x8FFFF) | 0x10000);
+
+ if (is2t)
+ rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASK12BITS,
+ (rf_b_mode & 0x8FFFF) | 0x10000);
+ }
+ lc_cal = rtl_get_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS);
+
+ rtl_set_rfreg(hw, RF90_PATH_A, 0xb0, RFREG_OFFSET_MASK, 0xdfbe0);
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS, 0x8c0a);
+
+ mdelay(100);
+
+ rtl_set_rfreg(hw, RF90_PATH_A, 0xb0, RFREG_OFFSET_MASK, 0xdffe0);
+
+ if ((tmpreg & 0x70) != 0) {
+ rtl_write_byte(rtlpriv, 0xd03, tmpreg);
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS, rf_a_mode);
+
+ if (is2t)
+ rtl_set_rfreg(hw, RF90_PATH_B, 0x00,
+ MASK12BITS, rf_b_mode);
+ } else {
+ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "\n");
+}
+
+static void _rtl8723be_phy_set_rfpath_switch(struct ieee80211_hw *hw,
+ bool bmain, bool is2t)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "\n");
+
+ if (is_hal_stop(rtlhal)) {
+ u8 u1btmp;
+ u1btmp = rtl_read_byte(rtlpriv, REG_LEDCFG0);
+ rtl_write_byte(rtlpriv, REG_LEDCFG0, u1btmp | BIT(7));
+ rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(13), 0x01);
+ }
+ if (is2t) {
+ if (bmain)
+ rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+ BIT(5) | BIT(6), 0x1);
+ else
+ rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+ BIT(5) | BIT(6), 0x2);
+ } else {
+ rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BIT(8) | BIT(9), 0);
+ rtl_set_bbreg(hw, 0x914, MASKLWORD, 0x0201);
+
+ /* We use the RF definition of MAIN and AUX,
+ * left antenna and right antenna repectively.
+ * Default output at AUX.
+ */
+ if (bmain) {
+ rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE,
+ BIT(14) | BIT(13) | BIT(12), 0);
+ rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+ BIT(5) | BIT(4) | BIT(3), 0);
+ if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
+ rtl_set_bbreg(hw, CONFIG_RAM64X16, BIT(31), 0);
+ } else {
+ rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE,
+ BIT(14) | BIT(13) | BIT(12), 1);
+ rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+ BIT(5) | BIT(4) | BIT(3), 1);
+ if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
+ rtl_set_bbreg(hw, CONFIG_RAM64X16, BIT(31), 1);
+ }
+ }
+}
+
+#undef IQK_ADDA_REG_NUM
+#undef IQK_DELAY_TIME
+
+void rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ long result[4][8];
+ u8 i, final_candidate;
+ bool patha_ok, pathb_ok;
+ long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4,
+ reg_ecc, reg_tmp = 0;
+ bool is12simular, is13simular, is23simular;
+ u32 iqk_bb_reg[9] = {
+ ROFDM0_XARXIQIMBALANCE,
+ ROFDM0_XBRXIQIMBALANCE,
+ ROFDM0_ECCATHRESHOLD,
+ ROFDM0_AGCRSSITABLE,
+ ROFDM0_XATXIQIMBALANCE,
+ ROFDM0_XBTXIQIMBALANCE,
+ ROFDM0_XCTXAFE,
+ ROFDM0_XDTXAFE,
+ ROFDM0_RXIQEXTANTA
+ };
+
+ if (recovery) {
+ rtl8723_phy_reload_adda_registers(hw, iqk_bb_reg,
+ rtlphy->iqk_bb_backup, 9);
+ return;
+ }
+
+ for (i = 0; i < 8; i++) {
+ result[0][i] = 0;
+ result[1][i] = 0;
+ result[2][i] = 0;
+ result[3][i] = 0;
+ }
+ final_candidate = 0xff;
+ patha_ok = false;
+ pathb_ok = false;
+ is12simular = false;
+ is23simular = false;
+ is13simular = false;
+ for (i = 0; i < 3; i++) {
+ if (get_rf_type(rtlphy) == RF_2T2R)
+ _rtl8723be_phy_iq_calibrate(hw, result, i, true);
+ else
+ _rtl8723be_phy_iq_calibrate(hw, result, i, false);
+ if (i == 1) {
+ is12simular = phy_similarity_cmp(hw, result, 0, 1);
+ if (is12simular) {
+ final_candidate = 0;
+ break;
+ }
+ }
+ if (i == 2) {
+ is13simular = phy_similarity_cmp(hw, result, 0, 2);
+ if (is13simular) {
+ final_candidate = 0;
+ break;
+ }
+ is23simular = phy_similarity_cmp(hw, result, 1, 2);
+ if (is23simular) {
+ final_candidate = 1;
+ } else {
+ for (i = 0; i < 8; i++)
+ reg_tmp += result[3][i];
+
+ if (reg_tmp != 0)
+ final_candidate = 3;
+ else
+ final_candidate = 0xFF;
+ }
+ }
+ }
+ for (i = 0; i < 4; i++) {
+ reg_e94 = result[i][0];
+ reg_e9c = result[i][1];
+ reg_ea4 = result[i][2];
+ reg_eac = result[i][3];
+ reg_eb4 = result[i][4];
+ reg_ebc = result[i][5];
+ reg_ec4 = result[i][6];
+ reg_ecc = result[i][7];
+ }
+ if (final_candidate != 0xff) {
+ reg_e94 = result[final_candidate][0];
+ rtlphy->reg_e94 = reg_e94;
+ reg_e9c = result[final_candidate][1];
+ rtlphy->reg_e9c = reg_e9c;
+ reg_ea4 = result[final_candidate][2];
+ reg_eac = result[final_candidate][3];
+ reg_eb4 = result[final_candidate][4];
+ rtlphy->reg_eb4 = reg_eb4;
+ reg_ebc = result[final_candidate][5];
+ rtlphy->reg_ebc = reg_ebc;
+ reg_ec4 = result[final_candidate][6];
+ reg_ecc = result[final_candidate][7];
+ patha_ok = true;
+ pathb_ok = true;
+ } else {
+ rtlphy->reg_e94 = 0x100;
+ rtlphy->reg_eb4 = 0x100;
+ rtlphy->reg_e9c = 0x0;
+ rtlphy->reg_ebc = 0x0;
+ }
+ if (reg_e94 != 0) /*&&(reg_ea4 != 0) */
+ rtl8723_phy_path_a_fill_iqk_matrix(hw, patha_ok, result,
+ final_candidate,
+ (reg_ea4 == 0));
+ if (final_candidate != 0xFF) {
+ for (i = 0; i < IQK_MATRIX_REG_NUM; i++)
+ rtlphy->iqk_matrix[0].value[0][i] =
+ result[final_candidate][i];
+ rtlphy->iqk_matrix[0].iqk_done = true;
+ }
+ rtl8723_save_adda_registers(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 9);
+}
+
+void rtl8723be_phy_lc_calibrate(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_hal *rtlhal = &(rtlpriv->rtlhal);
+ u32 timeout = 2000, timecount = 0;
+
+ while (rtlpriv->mac80211.act_scanning && timecount < timeout) {
+ udelay(50);
+ timecount += 50;
+ }
+
+ rtlphy->lck_inprogress = true;
+ RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+ "LCK:Start!!! currentband %x delay %d ms\n",
+ rtlhal->current_bandtype, timecount);
+
+ _rtl8723be_phy_lc_calibrate(hw, false);
+
+ rtlphy->lck_inprogress = false;
+}
+
+void rtl23b_phy_ap_calibrate(struct ieee80211_hw *hw, char delta)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ if (rtlphy->apk_done)
+ return;
+
+ return;
+}
+
+void rtl8723be_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain)
+{
+ _rtl8723be_phy_set_rfpath_switch(hw, bmain, false);
+}
+
+static void rtl8723be_phy_set_io(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+ "--->Cmd(%#x), set_io_inprogress(%d)\n",
+ rtlphy->current_io_type, rtlphy->set_io_inprogress);
+ switch (rtlphy->current_io_type) {
+ case IO_CMD_RESUME_DM_BY_SCAN:
+ rtlpriv->dm_digtable.cur_igvalue =
+ rtlphy->initgain_backup.xaagccore1;
+ /*rtl92c_dm_write_dig(hw);*/
+ rtl8723be_phy_set_txpower_level(hw, rtlphy->current_channel);
+ rtl_set_bbreg(hw, RCCK0_CCA, 0xff0000, 0x83);
+ break;
+ case IO_CMD_PAUSE_DM_BY_SCAN:
+ rtlphy->initgain_backup.xaagccore1 =
+ rtlpriv->dm_digtable.cur_igvalue;
+ rtlpriv->dm_digtable.cur_igvalue = 0x17;
+ rtl_set_bbreg(hw, RCCK0_CCA, 0xff0000, 0x40);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not process\n");
+ break;
+ }
+ rtlphy->set_io_inprogress = false;
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+ "(%#x)\n", rtlphy->current_io_type);
+}
+
+bool rtl8723be_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ bool postprocessing = false;
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+ "-->IO Cmd(%#x), set_io_inprogress(%d)\n",
+ iotype, rtlphy->set_io_inprogress);
+ do {
+ switch (iotype) {
+ case IO_CMD_RESUME_DM_BY_SCAN:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+ "[IO CMD] Resume DM after scan.\n");
+ postprocessing = true;
+ break;
+ case IO_CMD_PAUSE_DM_BY_SCAN:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+ "[IO CMD] Pause DM before scan.\n");
+ postprocessing = true;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not process\n");
+ break;
+ }
+ } while (false);
+ if (postprocessing && !rtlphy->set_io_inprogress) {
+ rtlphy->set_io_inprogress = true;
+ rtlphy->current_io_type = iotype;
+ } else {
+ return false;
+ }
+ rtl8723be_phy_set_io(hw);
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "IO Type(%#x)\n", iotype);
+ return true;
+}
+
+static void rtl8723be_phy_set_rf_on(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
+ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
+}
+
+static void _rtl8723be_phy_set_rf_sleep(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+ rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22);
+}
+
+static bool _rtl8723be_phy_set_rf_power_state(struct ieee80211_hw *hw,
+ enum rf_pwrstate rfpwr_state)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ bool bresult = true;
+ u8 i, queue_id;
+ struct rtl8192_tx_ring *ring = NULL;
+
+ switch (rfpwr_state) {
+ case ERFON:
+ if ((ppsc->rfpwr_state == ERFOFF) &&
+ RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) {
+ bool rtstatus;
+ u32 initialize_count = 0;
+ do {
+ initialize_count++;
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ "IPS Set eRf nic enable\n");
+ rtstatus = rtl_ps_enable_nic(hw);
+ } while (!rtstatus && (initialize_count < 10));
+ RT_CLEAR_PS_LEVEL(ppsc,
+ RT_RF_OFF_LEVL_HALT_NIC);
+ } else {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ "Set ERFON sleeped:%d ms\n",
+ jiffies_to_msecs(jiffies -
+ ppsc->last_sleep_jiffies));
+ ppsc->last_awake_jiffies = jiffies;
+ rtl8723be_phy_set_rf_on(hw);
+ }
+ if (mac->link_state == MAC80211_LINKED)
+ rtlpriv->cfg->ops->led_control(hw, LED_CTL_LINK);
+ else
+ rtlpriv->cfg->ops->led_control(hw, LED_CTL_NO_LINK);
+ break;
+ case ERFOFF:
+ for (queue_id = 0, i = 0;
+ queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
+ ring = &pcipriv->dev.tx_ring[queue_id];
+ if (skb_queue_len(&ring->queue) == 0) {
+ queue_id++;
+ continue;
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "eRf Off/Sleep: %d times "
+ "TcbBusyQueue[%d] =%d before "
+ "doze!\n", (i + 1), queue_id,
+ skb_queue_len(&ring->queue));
+
+ udelay(10);
+ i++;
+ }
+ if (i >= MAX_DOZE_WAITING_TIMES_9x) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "\n ERFSLEEP: %d times "
+ "TcbBusyQueue[%d] = %d !\n",
+ MAX_DOZE_WAITING_TIMES_9x,
+ queue_id,
+ skb_queue_len(&ring->queue));
+ break;
+ }
+ }
+
+ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ "IPS Set eRf nic disable\n");
+ rtl_ps_disable_nic(hw);
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+ } else {
+ if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) {
+ rtlpriv->cfg->ops->led_control(hw,
+ LED_CTL_NO_LINK);
+ } else {
+ rtlpriv->cfg->ops->led_control(hw,
+ LED_CTL_POWER_OFF);
+ }
+ }
+ break;
+ case ERFSLEEP:
+ if (ppsc->rfpwr_state == ERFOFF)
+ break;
+ for (queue_id = 0, i = 0;
+ queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
+ ring = &pcipriv->dev.tx_ring[queue_id];
+ if (skb_queue_len(&ring->queue) == 0) {
+ queue_id++;
+ continue;
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "eRf Off/Sleep: %d times "
+ "TcbBusyQueue[%d] =%d before "
+ "doze!\n", (i + 1), queue_id,
+ skb_queue_len(&ring->queue));
+
+ udelay(10);
+ i++;
+ }
+ if (i >= MAX_DOZE_WAITING_TIMES_9x) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "\n ERFSLEEP: %d times "
+ "TcbBusyQueue[%d] = %d !\n",
+ MAX_DOZE_WAITING_TIMES_9x,
+ queue_id,
+ skb_queue_len(&ring->queue));
+ break;
+ }
+ }
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ "Set ERFSLEEP awaked:%d ms\n",
+ jiffies_to_msecs(jiffies -
+ ppsc->last_awake_jiffies));
+ ppsc->last_sleep_jiffies = jiffies;
+ _rtl8723be_phy_set_rf_sleep(hw);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not process\n");
+ bresult = false;
+ break;
+ }
+ if (bresult)
+ ppsc->rfpwr_state = rfpwr_state;
+ return bresult;
+}
+
+bool rtl8723be_phy_set_rf_power_state(struct ieee80211_hw *hw,
+ enum rf_pwrstate rfpwr_state)
+{
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ bool bresult = false;
+
+ if (rfpwr_state == ppsc->rfpwr_state)
+ return bresult;
+ bresult = _rtl8723be_phy_set_rf_power_state(hw, rfpwr_state);
+ return bresult;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/phy.h b/drivers/net/wireless/rtlwifi/rtl8723be/phy.h
new file mode 100644
index 000000000000..444ef95bb6af
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/phy.h
@@ -0,0 +1,217 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_PHY_H__
+#define __RTL8723BE_PHY_H__
+
+/*It must always set to 4, otherwise read efuse table secquence will be wrong.*/
+#define MAX_TX_COUNT 4
+#define TX_1S 0
+#define TX_2S 1
+
+#define MAX_POWER_INDEX 0x3F
+
+#define MAX_PRECMD_CNT 16
+#define MAX_RFDEPENDCMD_CNT 16
+#define MAX_POSTCMD_CNT 16
+
+#define MAX_DOZE_WAITING_TIMES_9x 64
+
+#define RT_CANNOT_IO(hw) false
+#define HIGHPOWER_RADIOA_ARRAYLEN 22
+
+#define IQK_ADDA_REG_NUM 16
+#define IQK_BB_REG_NUM 9
+#define MAX_TOLERANCE 5
+#define IQK_DELAY_TIME 10
+#define index_mapping_NUM 15
+
+#define APK_BB_REG_NUM 5
+#define APK_AFE_REG_NUM 16
+#define APK_CURVE_REG_NUM 4
+#define PATH_NUM 1
+
+#define LOOP_LIMIT 5
+#define MAX_STALL_TIME 50
+#define ANTENNADIVERSITYVALUE 0x80
+#define MAX_TXPWR_IDX_NMODE_92S 63
+#define RESET_CNT_LIMIT 3
+
+#define IQK_ADDA_REG_NUM 16
+#define IQK_MAC_REG_NUM 4
+
+#define RF6052_MAX_PATH 2
+
+#define CT_OFFSET_MAC_ADDR 0X16
+
+#define CT_OFFSET_CCK_TX_PWR_IDX 0x5A
+#define CT_OFFSET_HT401S_TX_PWR_IDX 0x60
+#define CT_OFFSET_HT402S_TX_PWR_IDX_DIFF 0x66
+#define CT_OFFSET_HT20_TX_PWR_IDX_DIFF 0x69
+#define CT_OFFSET_OFDM_TX_PWR_IDX_DIFF 0x6C
+
+#define CT_OFFSET_HT40_MAX_PWR_OFFSET 0x6F
+#define CT_OFFSET_HT20_MAX_PWR_OFFSET 0x72
+
+#define CT_OFFSET_CHANNEL_PLAH 0x75
+#define CT_OFFSET_THERMAL_METER 0x78
+#define CT_OFFSET_RF_OPTION 0x79
+#define CT_OFFSET_VERSION 0x7E
+#define CT_OFFSET_CUSTOMER_ID 0x7F
+
+#define RTL92C_MAX_PATH_NUM 2
+
+enum hw90_block_e {
+ HW90_BLOCK_MAC = 0,
+ HW90_BLOCK_PHY0 = 1,
+ HW90_BLOCK_PHY1 = 2,
+ HW90_BLOCK_RF = 3,
+ HW90_BLOCK_MAXIMUM = 4,
+};
+
+enum baseband_config_type {
+ BASEBAND_CONFIG_PHY_REG = 0,
+ BASEBAND_CONFIG_AGC_TAB = 1,
+};
+
+enum ra_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,
+};
+
+enum antenna_path {
+ ANTENNA_NONE,
+ 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
+};
+
+struct r_antenna_select_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 r_antenna_select_cck {
+ u8 r_cckrx_enable_2:2;
+ u8 r_cckrx_enable:2;
+ u8 r_ccktx_enable:4;
+};
+
+
+struct efuse_contents {
+ u8 mac_addr[ETH_ALEN];
+ u8 cck_tx_power_idx[6];
+ u8 ht40_1s_tx_power_idx[6];
+ u8 ht40_2s_tx_power_idx_diff[3];
+ u8 ht20_tx_power_idx_diff[3];
+ u8 ofdm_tx_power_idx_diff[3];
+ u8 ht40_max_power_offset[3];
+ u8 ht20_max_power_offset[3];
+ u8 channel_plan;
+ u8 thermal_meter;
+ u8 rf_option[5];
+ u8 version;
+ u8 oem_id;
+ u8 regulatory;
+};
+
+struct tx_power_struct {
+ u8 cck[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 ht40_1s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 ht40_2s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 ht20_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 legacy_ht_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 legacy_ht_txpowerdiff;
+ u8 groupht20[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 groupht40[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 pwrgroup_cnt;
+ u32 mcs_original_offset[4][16];
+};
+
+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,
+};
+
+u32 rtl8723be_phy_query_rf_reg(struct ieee80211_hw *hw,
+ enum radio_path rfpath,
+ u32 regaddr, u32 bitmask);
+void rtl8723be_phy_set_rf_reg(struct ieee80211_hw *hw,
+ enum radio_path rfpath,
+ u32 regaddr, u32 bitmask, u32 data);
+bool rtl8723be_phy_mac_config(struct ieee80211_hw *hw);
+bool rtl8723be_phy_bb_config(struct ieee80211_hw *hw);
+bool rtl8723be_phy_rf_config(struct ieee80211_hw *hw);
+void rtl8723be_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
+void rtl8723be_phy_get_txpower_level(struct ieee80211_hw *hw,
+ long *powerlevel);
+void rtl8723be_phy_set_txpower_level(struct ieee80211_hw *hw,
+ u8 channel);
+void rtl8723be_phy_scan_operation_backup(struct ieee80211_hw *hw,
+ u8 operation);
+void rtl8723be_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
+void rtl8723be_phy_set_bw_mode(struct ieee80211_hw *hw,
+ enum nl80211_channel_type ch_type);
+void rtl8723be_phy_sw_chnl_callback(struct ieee80211_hw *hw);
+u8 rtl8723be_phy_sw_chnl(struct ieee80211_hw *hw);
+void rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw,
+ bool b_recovery);
+void rtl23b_phy_ap_calibrate(struct ieee80211_hw *hw, char delta);
+void rtl8723be_phy_lc_calibrate(struct ieee80211_hw *hw);
+void rtl8723be_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain);
+bool rtl8723be_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+ enum radio_path rfpath);
+bool rtl8723be_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype);
+bool rtl8723be_phy_set_rf_power_state(struct ieee80211_hw *hw,
+ enum rf_pwrstate rfpwr_state);
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.c b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.c
new file mode 100644
index 000000000000..b5167e73fecf
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.c
@@ -0,0 +1,106 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "pwrseqcmd.h"
+#include "pwrseq.h"
+
+
+/* drivers should parse below arrays and do the corresponding actions */
+/*3 Power on Array*/
+struct wlan_pwr_cfg rtl8723B_power_on_flow[RTL8723B_TRANS_CARDEMU_TO_ACT_STEPS +
+ RTL8723B_TRANS_END_STEPS] = {
+ RTL8723B_TRANS_CARDEMU_TO_ACT
+ RTL8723B_TRANS_END
+};
+
+/*3Radio off GPIO Array */
+struct wlan_pwr_cfg rtl8723B_radio_off_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS
+ + RTL8723B_TRANS_END_STEPS] = {
+ RTL8723B_TRANS_ACT_TO_CARDEMU
+ RTL8723B_TRANS_END
+};
+
+/*3Card Disable Array*/
+struct wlan_pwr_cfg rtl8723B_card_disable_flow
+ [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS +
+ RTL8723B_TRANS_END_STEPS] = {
+ RTL8723B_TRANS_ACT_TO_CARDEMU
+ RTL8723B_TRANS_CARDEMU_TO_CARDDIS
+ RTL8723B_TRANS_END
+};
+
+/*3 Card Enable Array*/
+struct wlan_pwr_cfg rtl8723B_card_enable_flow
+ [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS +
+ RTL8723B_TRANS_END_STEPS] = {
+ RTL8723B_TRANS_CARDDIS_TO_CARDEMU
+ RTL8723B_TRANS_CARDEMU_TO_ACT
+ RTL8723B_TRANS_END
+};
+
+/*3Suspend Array*/
+struct wlan_pwr_cfg rtl8723B_suspend_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS +
+ RTL8723B_TRANS_END_STEPS] = {
+ RTL8723B_TRANS_ACT_TO_CARDEMU
+ RTL8723B_TRANS_CARDEMU_TO_SUS
+ RTL8723B_TRANS_END
+};
+
+/*3 Resume Array*/
+struct wlan_pwr_cfg rtl8723B_resume_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS +
+ RTL8723B_TRANS_END_STEPS] = {
+ RTL8723B_TRANS_SUS_TO_CARDEMU
+ RTL8723B_TRANS_CARDEMU_TO_ACT
+ RTL8723B_TRANS_END
+};
+
+/*3HWPDN Array*/
+struct wlan_pwr_cfg rtl8723B_hwpdn_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS +
+ RTL8723B_TRANS_END_STEPS] = {
+ RTL8723B_TRANS_ACT_TO_CARDEMU
+ RTL8723B_TRANS_CARDEMU_TO_PDN
+ RTL8723B_TRANS_END
+};
+
+/*3 Enter LPS */
+struct wlan_pwr_cfg rtl8723B_enter_lps_flow[RTL8723B_TRANS_ACT_TO_LPS_STEPS +
+ RTL8723B_TRANS_END_STEPS] = {
+ /*FW behavior*/
+ RTL8723B_TRANS_ACT_TO_LPS
+ RTL8723B_TRANS_END
+};
+
+/*3 Leave LPS */
+struct wlan_pwr_cfg rtl8723B_leave_lps_flow[RTL8723B_TRANS_LPS_TO_ACT_STEPS +
+ RTL8723B_TRANS_END_STEPS] = {
+ /*FW behavior*/
+ RTL8723B_TRANS_LPS_TO_ACT
+ RTL8723B_TRANS_END
+};
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h
new file mode 100644
index 000000000000..a62f43ed8d32
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h
@@ -0,0 +1,304 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_PWRSEQ_H__
+#define __RTL8723BE_PWRSEQ_H__
+
+/* Check document WM-20130425-JackieLau-RTL8723B_Power_Architecture v05.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 transition 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
+ */
+#define RTL8723B_TRANS_CARDEMU_TO_ACT_STEPS 23
+#define RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS 15
+#define RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS 15
+#define RTL8723B_TRANS_SUS_TO_CARDEMU_STEPS 15
+#define RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS 15
+#define RTL8723B_TRANS_PDN_TO_CARDEMU_STEPS 15
+#define RTL8723B_TRANS_ACT_TO_LPS_STEPS 15
+#define RTL8723B_TRANS_LPS_TO_ACT_STEPS 15
+#define RTL8723B_TRANS_END_STEPS 1
+
+#define RTL8723B_TRANS_CARDEMU_TO_ACT \
+ {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)}, \
+ {0x0067, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, \
+ {0x0001, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_DELAY, 1, PWRSEQ_DELAY_MS}, \
+ {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), 0}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT(4)|BIT(3)|BIT(2)), 0}, \
+ {0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0) , 0}, \
+ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), BIT(1)}, \
+ {0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0) , BIT(0)}, \
+ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT(4)|BIT(3)), 0}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(0), 0}, \
+ {0x0010, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6), BIT(6)}, \
+ {0x0049, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)}, \
+ {0x0063, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)}, \
+ {0x0062, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0}, \
+ {0x0058, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)}, \
+ {0x005A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)}, \
+ {0x0068, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3), BIT(3)}, \
+ {0x0069, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6), BIT(6)},
+
+#define RTL8723B_TRANS_ACT_TO_CARDEMU \
+ {0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, \
+ {0x004F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0}, \
+ {0x0049, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), 0}, \
+ {0x0010, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6), 0}, \
+ {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, \
+ PWR_CMD_WRITE, BIT(5), BIT(5)}, \
+ {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, \
+ PWR_CMD_WRITE, BIT(0), 0},
+
+#define RTL8723B_TRANS_CARDEMU_TO_SUS \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4) | BIT(3), (BIT(4) | BIT(3))}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, \
+ PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3)}, \
+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, \
+ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3) | BIT(4)},\
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)}, \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), 0},
+
+#define RTL8723B_TRANS_SUS_TO_CARDEMU \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3) | BIT(7), 0}, \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0}, \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)}, \
+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0},
+
+#define RTL8723B_TRANS_CARDEMU_TO_CARDDIS \
+ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(2), BIT(2)}, \
+ {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 1}, \
+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)}, \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), 0},
+
+#define RTL8723B_TRANS_CARDDIS_TO_CARDEMU \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3) | BIT(7), 0}, \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0}, \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)}, \
+ {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0}, \
+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, \
+ {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},
+
+#define RTL8723B_TRANS_CARDEMU_TO_PDN \
+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, \
+ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_SDIO_MSK | PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, \
+ PWR_CMD_WRITE, 0xFF, 0x20}, \
+ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)},
+
+#define RTL8723B_TRANS_PDN_TO_CARDEMU \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},
+
+#define RTL8723B_TRANS_ACT_TO_LPS \
+ {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF}, \
+ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF}, \
+ {0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0}, \
+ {0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0}, \
+ {0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0}, \
+ {0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0}, \
+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0}, \
+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US}, \
+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0}, \
+ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x03}, \
+ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0}, \
+ {0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00}, \
+ {0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), BIT(5)},
+
+#define RTL8723B_TRANS_LPS_TO_ACT \
+ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84}, \
+ {0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, \
+ {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, \
+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, \
+ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, \
+ {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(7), 0}, \
+ {0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6)|BIT(7), 0}, \
+ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)}, \
+ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF}, \
+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1) | BIT(0), BIT(1) | BIT(0)}, \
+ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},
+
+#define RTL8723B_TRANS_END \
+ {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, 0, \
+ PWR_CMD_END, 0, 0},
+
+extern struct wlan_pwr_cfg rtl8723B_power_on_flow
+ [RTL8723B_TRANS_CARDEMU_TO_ACT_STEPS +
+ RTL8723B_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723B_radio_off_flow
+ [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8723B_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723B_card_disable_flow
+ [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS +
+ RTL8723B_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723B_card_enable_flow
+ [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS +
+ RTL8723B_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723B_suspend_flow
+ [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS +
+ RTL8723B_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723B_resume_flow
+ [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS +
+ RTL8723B_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723B_hwpdn_flow
+ [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS +
+ RTL8723B_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723B_enter_lps_flow
+ [RTL8723B_TRANS_ACT_TO_LPS_STEPS +
+ RTL8723B_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723B_leave_lps_flow
+ [RTL8723B_TRANS_LPS_TO_ACT_STEPS +
+ RTL8723B_TRANS_END_STEPS];
+
+/* RTL8723 Power Configuration CMDs for PCIe interface */
+#define RTL8723_NIC_PWR_ON_FLOW rtl8723B_power_on_flow
+#define RTL8723_NIC_RF_OFF_FLOW rtl8723B_radio_off_flow
+#define RTL8723_NIC_DISABLE_FLOW rtl8723B_card_disable_flow
+#define RTL8723_NIC_ENABLE_FLOW rtl8723B_card_enable_flow
+#define RTL8723_NIC_SUSPEND_FLOW rtl8723B_suspend_flow
+#define RTL8723_NIC_RESUME_FLOW rtl8723B_resume_flow
+#define RTL8723_NIC_PDN_FLOW rtl8723B_hwpdn_flow
+#define RTL8723_NIC_LPS_ENTER_FLOW rtl8723B_enter_lps_flow
+#define RTL8723_NIC_LPS_LEAVE_FLOW rtl8723B_leave_lps_flow
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.c b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.c
new file mode 100644
index 000000000000..e4a507a756fb
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.c
@@ -0,0 +1,140 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "pwrseq.h"
+
+/* Description:
+ * This routine deal with the Power Configuration CMDs
+ * parsing for RTL8723/RTL8188E Series IC.
+ * Assumption:
+ * We should follow specific format which was released from HW SD.
+ *
+ * 2011.07.07, added by Roger.
+ */
+bool rtlbe_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
+ u8 fab_version, u8 interface_type,
+ struct wlan_pwr_cfg pwrcfgcmd[])
+
+{
+ struct wlan_pwr_cfg pwr_cfg_cmd = {0};
+ bool b_polling_bit = false;
+ u32 ary_idx = 0;
+ u8 value = 0;
+ u32 offset = 0;
+ u32 polling_count = 0;
+ u32 max_polling_cnt = 5000;
+
+ do {
+ pwr_cfg_cmd = pwrcfgcmd[ary_idx];
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtlbe_hal_pwrseqcmdparsing(): "
+ "offset(%#x),cut_msk(%#x), fab_msk(%#x),"
+ "interface_msk(%#x), base(%#x), "
+ "cmd(%#x), msk(%#x), value(%#x)\n",
+ GET_PWR_CFG_OFFSET(pwr_cfg_cmd),
+ GET_PWR_CFG_CUT_MASK(pwr_cfg_cmd),
+ GET_PWR_CFG_FAB_MASK(pwr_cfg_cmd),
+ GET_PWR_CFG_INTF_MASK(pwr_cfg_cmd),
+ GET_PWR_CFG_BASE(pwr_cfg_cmd),
+ GET_PWR_CFG_CMD(pwr_cfg_cmd),
+ GET_PWR_CFG_MASK(pwr_cfg_cmd),
+ GET_PWR_CFG_VALUE(pwr_cfg_cmd));
+
+ if ((GET_PWR_CFG_FAB_MASK(pwr_cfg_cmd)&fab_version) &&
+ (GET_PWR_CFG_CUT_MASK(pwr_cfg_cmd)&cut_version) &&
+ (GET_PWR_CFG_INTF_MASK(pwr_cfg_cmd)&interface_type)) {
+ switch (GET_PWR_CFG_CMD(pwr_cfg_cmd)) {
+ case PWR_CMD_READ:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtlbe_hal_pwrseqcmdparsing(): "
+ "PWR_CMD_READ\n");
+ break;
+ case PWR_CMD_WRITE:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtlbe_hal_pwrseqcmdparsing(): "
+ "PWR_CMD_WRITE\n");
+ offset = GET_PWR_CFG_OFFSET(pwr_cfg_cmd);
+
+ /*Read the value from system register*/
+ value = rtl_read_byte(rtlpriv, offset);
+ value &= (~(GET_PWR_CFG_MASK(pwr_cfg_cmd)));
+ value = value | (GET_PWR_CFG_VALUE(pwr_cfg_cmd)
+ & GET_PWR_CFG_MASK(pwr_cfg_cmd));
+
+ /*Write the value back to sytem register*/
+ rtl_write_byte(rtlpriv, offset, value);
+ break;
+ case PWR_CMD_POLLING:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtlbe_hal_pwrseqcmdparsing(): "
+ "PWR_CMD_POLLING\n");
+ b_polling_bit = false;
+ offset = GET_PWR_CFG_OFFSET(pwr_cfg_cmd);
+
+ do {
+ value = rtl_read_byte(rtlpriv, offset);
+
+ value &= GET_PWR_CFG_MASK(pwr_cfg_cmd);
+ if (value ==
+ (GET_PWR_CFG_VALUE(pwr_cfg_cmd) &
+ GET_PWR_CFG_MASK(pwr_cfg_cmd)))
+ b_polling_bit = true;
+ else
+ udelay(10);
+
+ if (polling_count++ > max_polling_cnt)
+ return false;
+
+ } while (!b_polling_bit);
+ break;
+ case PWR_CMD_DELAY:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtlbe_hal_pwrseqcmdparsing(): "
+ "PWR_CMD_DELAY\n");
+ if (GET_PWR_CFG_VALUE(pwr_cfg_cmd) ==
+ PWRSEQ_DELAY_US)
+ udelay(GET_PWR_CFG_OFFSET(pwr_cfg_cmd));
+ else
+ mdelay(GET_PWR_CFG_OFFSET(pwr_cfg_cmd));
+ break;
+ case PWR_CMD_END:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtlbe_hal_pwrseqcmdparsing(): "
+ "PWR_CMD_END\n");
+ return true;
+ break;
+ default:
+ RT_ASSERT(false,
+ "rtlbe_hal_pwrseqcmdparsing(): "
+ "Unknown CMD!!\n");
+ break;
+ }
+ }
+
+ ary_idx++;
+ } while (1);
+
+ return true;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.h b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.h
new file mode 100644
index 000000000000..ce14a3b5cb71
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.h
@@ -0,0 +1,95 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_PWRSEQCMD_H__
+#define __RTL8723BE_PWRSEQCMD_H__
+
+#include "../wifi.h"
+/*---------------------------------------------*/
+/*The value of cmd: 4 bits */
+/*---------------------------------------------*/
+#define PWR_CMD_READ 0x00
+#define PWR_CMD_WRITE 0x01
+#define PWR_CMD_POLLING 0x02
+#define PWR_CMD_DELAY 0x03
+#define PWR_CMD_END 0x04
+
+/* 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
+
+#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))
+
+#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))
+
+#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_delay_unit {
+ PWRSEQ_DELAY_US,
+ PWRSEQ_DELAY_MS,
+};
+
+struct wlan_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
+
+bool rtlbe_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
+ u8 fab_version, u8 interface_type,
+ struct wlan_pwr_cfg pwrcfgcmd[]);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/reg.h b/drivers/net/wireless/rtlwifi/rtl8723be/reg.h
new file mode 100644
index 000000000000..4c653fab8795
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/reg.h
@@ -0,0 +1,2277 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_REG_H__
+#define __RTL8723BE_REG_H__
+
+#define TXPKT_BUF_SELECT 0x69
+#define RXPKT_BUF_SELECT 0xA5
+#define DISABLE_TRXPKT_BUF_ACCESS 0x0
+
+#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
+/* 1.5v for 8188EE test chip, 1.4v for MP chip */
+#define REG_AFE_LDO_CTRL 0x0027
+#define REG_AFE_PLL_CTRL 0x0028
+#define REG_MAC_PHY_CTRL 0x002c
+#define REG_EFUSE_CTRL 0x0030
+#define REG_EFUSE_TEST 0x0034
+#define REG_PWR_DATA 0x0038
+#define REG_CAL_TIMER 0x003C
+#define REG_ACLK_MON 0x003E
+#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
+#define REG_GPIO_IO_SEL_2 0x0062
+#define REG_MULTI_FUNC_CTRL 0x0068
+#define REG_GPIO_OUTPUT 0x006c
+#define REG_AFE_XTAL_CTRL_EXT 0x0078
+#define REG_XCK_OUT_CTRL 0x007c
+#define REG_MCUFWDL 0x0080
+#define REG_WOL_EVENT 0x0081
+#define REG_MCUTSTCFG 0x0084
+
+
+#define REG_HIMR 0x00B0
+#define REG_HISR 0x00B4
+#define REG_HIMRE 0x00B8
+#define REG_HISRE 0x00BC
+
+#define REG_EFUSE_ACCESS 0x00CF
+
+#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
+#define REG_SYS_CFG1 0x00F0
+#define REG_ROM_VERSION 0x00FD
+
+#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_CPWM 0x012F
+#define REG_FWIMR 0x0130
+#define REG_FWISR 0x0134
+#define REG_PKTBUF_DBG_CTRL 0x0140
+#define REG_PKTBUF_DBG_DATA_L 0x0144
+#define REG_PKTBUF_DBG_DATA_H 0x0148
+#define REG_RXPKTBUF_CTRL (REG_PKTBUF_DBG_CTRL + 2)
+
+#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
+#define REG_C2HEVT_MSG_NORMAL 0x01A0
+#define REG_C2HEVT_CLEAR 0x01AF
+#define REG_C2HEVT_MSG_TEST 0x01B8
+#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
+#define REG_BB_ACCEESS_CTRL 0x01E8
+#define REG_BB_ACCESS_DATA 0x01EC
+
+#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_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
+
+#define REG_RXDMA_AGG_PG_TH 0x0280
+/* FW shall update this register before FW write RXPKT_RELEASE_POLL to 1 */
+#define REG_FW_UPD_RDPTR 0x0284
+/* Control the RX DMA.*/
+#define REG_RXDMA_CONTROL 0x0286
+/* The number of packets in RXPKTBUF. */
+#define REG_RXPKT_NUM 0x0287
+
+#define REG_PCIE_CTRL_REG 0x0300
+#define REG_INT_MIG 0x0304
+#define REG_BCNQ_DESA 0x0308
+#define REG_HQ_DESA 0x0310
+#define REG_MGQ_DESA 0x0318
+#define REG_VOQ_DESA 0x0320
+#define REG_VIQ_DESA 0x0328
+#define REG_BEQ_DESA 0x0330
+#define REG_BKQ_DESA 0x0338
+#define REG_RX_DESA 0x0340
+
+#define REG_DBI 0x0348
+#define REG_MDIO 0x0354
+#define REG_DBG_SEL 0x0360
+#define REG_PCIE_HRPWM 0x0361
+#define REG_PCIE_HCPWM 0x0363
+#define REG_UART_CTRL 0x0364
+#define REG_WATCH_DOG 0x0368
+#define REG_UART_TX_DESA 0x0370
+#define REG_UART_RX_DESA 0x0378
+
+
+#define REG_HDAQ_DESA_NODEF 0x0000
+#define REG_CMDQ_DESA_NODEF 0x0000
+
+#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_MULTI_BCNQ_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_AMPDU_MAX_TIME 0x0456
+#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_LIFE_TIME 0x04C0
+#define REG_STBC_SETTING 0x04C4
+#define REG_PROT_MODE_CTRL 0x04C8
+#define REG_BAR_MODE_CTRL 0x04CC
+#define REG_RA_TRY_RATE_AGG_LMT 0x04CF
+#define REG_EARLY_MODE_CONTROL 0x04D0
+#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
+#define REG_DUMMY 0x04FC
+
+#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_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
+#define REG_TBTT_PROHIBIT 0x0540
+#define REG_RD_NAV_NXT 0x0544
+#define REG_NAV_PROT_LEN 0x0546
+#define REG_BCN_CTRL 0x0550
+#define REG_USTIME_TSF 0x0551
+#define REG_MBID_NUM 0x0552
+#define REG_DUAL_TSF_RST 0x0553
+#define REG_BCN_INTERVAL 0x0554
+#define REG_MBSSID_BCN_SPACE 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_INIT_TSFTR 0x0564
+#define REG_SECONDARY_CCA_CTRL 0x0577
+#define REG_PSTIMER 0x0580
+#define REG_TIMER0 0x0584
+#define REG_TIMER1 0x0588
+#define REG_ACMHWCTRL 0x05C0
+#define REG_ACMRSTCTRL 0x05C1
+#define REG_ACMAVG 0x05C2
+#define REG_VO_ADMTIME 0x05C4
+#define REG_VI_ADMTIME 0x05C6
+#define REG_BE_ADMTIME 0x05C8
+#define REG_EDCA_RANDOM_GEN 0x05CC
+#define REG_SCH_TXCMD 0x05D0
+
+#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
+#define REG_RESP_SIFS_CCK 0x063C
+#define REG_RESP_SIFS_OFDM 0x063E
+#define REG_ACKTO 0x0640
+#define REG_CTS2TO 0x0641
+#define REG_EIFS 0x0642
+
+#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_TRXPTCL_CTL 0x0668
+
+#define REG_CAMCMD 0x0670
+#define REG_CAMWRITE 0x0674
+#define REG_CAMREAD 0x0678
+#define REG_CAMDBG 0x067C
+#define REG_SECCFG 0x0680
+
+#define REG_WOW_CTRL 0x0690
+#define REG_PSSTATUS 0x0691
+#define REG_PS_RX_INFO 0x0692
+#define REG_UAPSD_TID 0x0693
+#define REG_LPNAV_CTRL 0x0694
+#define REG_WKFMCAM_NUM 0x0698
+#define REG_WKFMCAM_RWD 0x069C
+#define REG_RXFLTMAP0 0x06A0
+#define REG_RXFLTMAP1 0x06A2
+#define REG_RXFLTMAP2 0x06A4
+#define REG_BCN_PSR_RPT 0x06A8
+#define REG_CALB32K_CTRL 0x06AC
+#define REG_PKT_MON_CTRL 0x06B4
+#define REG_BT_COEX_TABLE 0x06C0
+#define REG_WMAC_RESP_TXINFO 0x06D8
+
+#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_TEST_USB_TXQS 0xFE48
+#define REG_TEST_SIE_VID 0xFE60
+#define REG_TEST_SIE_PID 0xFE62
+#define REG_TEST_SIE_OPTIONAL 0xFE64
+#define REG_TEST_SIE_CHIRP_K 0xFE65
+#define REG_TEST_SIE_PHY 0xFE66
+#define REG_TEST_SIE_MAC_ADDR 0xFE70
+#define REG_TEST_SIE_STRING 0xFE80
+
+#define REG_NORMAL_SIE_VID 0xFE60
+#define REG_NORMAL_SIE_PID 0xFE62
+#define REG_NORMAL_SIE_OPTIONAL 0xFE64
+#define REG_NORMAL_SIE_EP 0xFE65
+#define REG_NORMAL_SIE_PHY 0xFE68
+#define REG_NORMAL_SIE_MAC_ADDR 0xFE70
+#define REG_NORMAL_SIE_STRING 0xFE80
+
+#define CR9346 REG_9346CR
+#define MSR (REG_CR + 2)
+#define ISR REG_HISR
+#define TSFR REG_TSFTR
+
+#define MACIDR0 REG_MACID
+#define MACIDR4 (REG_MACID + 4)
+
+#define PBP REG_PBP
+
+#define IDR0 MACIDR0
+#define IDR4 MACIDR4
+
+#define UNUSED_REGISTER 0x1BF
+#define DCAM UNUSED_REGISTER
+#define PSR UNUSED_REGISTER
+#define BBADDR UNUSED_REGISTER
+#define PHYDATAR UNUSED_REGISTER
+
+#define INVALID_BBRF_VALUE 0x12345678
+
+#define MAX_MSS_DENSITY_2T 0x13
+#define MAX_MSS_DENSITY_1T 0x0A
+
+#define CMDEEPROM_EN BIT(5)
+#define CMDEEPROM_SEL BIT(4)
+#define CMD9346CR_9356SEL BIT(4)
+#define AUTOLOAD_EEPROM (CMDEEPROM_EN | CMDEEPROM_SEL)
+#define AUTOLOAD_EFUSE CMDEEPROM_EN
+
+#define GPIOSEL_GPIO 0
+#define GPIOSEL_ENBT BIT(5)
+
+#define GPIO_IN REG_GPIO_PIN_CTRL
+#define GPIO_OUT (REG_GPIO_PIN_CTRL + 1)
+#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 BIT(0)
+#define HSIMR_SPS_OCP_INT_EN BIT(5)
+#define HSIMR_RON_INT_EN BIT(6)
+#define HSIMR_PDN_INT_EN BIT(7)
+#define HSIMR_GPIO9_INT_EN BIT(25)
+
+/* 8723/8188E Host System Interrupt Status Register (offset 0x5C, 32 byte) */
+
+#define HSISR_GPIO12_0_INT BIT(0)
+#define HSISR_SPS_OCP_INT BIT(5)
+#define HSISR_RON_INT_EN BIT(6)
+#define HSISR_PDNINT BIT(7)
+#define HSISR_GPIO9_INT BIT(25)
+
+#define MSR_NOLINK 0x00
+#define MSR_ADHOC 0x01
+#define MSR_INFRA 0x02
+#define MSR_AP 0x03
+
+#define RRSR_RSC_OFFSET 21
+#define RRSR_SHORT_OFFSET 23
+#define RRSR_RSC_BW_40M 0x600000
+#define RRSR_RSC_UPSUBCHNL 0x400000
+#define RRSR_RSC_LOWSUBCHNL 0x200000
+#define RRSR_SHORT 0x800000
+#define RRSR_1M BIT(0)
+#define RRSR_2M BIT(1)
+#define RRSR_5_5M BIT(2)
+#define RRSR_11M BIT(3)
+#define RRSR_6M BIT(4)
+#define RRSR_9M BIT(5)
+#define RRSR_12M BIT(6)
+#define RRSR_18M BIT(7)
+#define RRSR_24M BIT(8)
+#define RRSR_36M BIT(9)
+#define RRSR_48M BIT(10)
+#define RRSR_54M BIT(11)
+#define RRSR_MCS0 BIT(12)
+#define RRSR_MCS1 BIT(13)
+#define RRSR_MCS2 BIT(14)
+#define RRSR_MCS3 BIT(15)
+#define RRSR_MCS4 BIT(16)
+#define RRSR_MCS5 BIT(17)
+#define RRSR_MCS6 BIT(18)
+#define RRSR_MCS7 BIT(19)
+#define BRSR_ACKSHORTPMB BIT(23)
+
+#define RATR_1M 0x00000001
+#define RATR_2M 0x00000002
+#define RATR_55M 0x00000004
+#define RATR_11M 0x00000008
+#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
+#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
+#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
+
+#define RATE_1M BIT(0)
+#define RATE_2M BIT(1)
+#define RATE_5_5M BIT(2)
+#define RATE_11M BIT(3)
+#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)
+#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)
+#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)
+
+#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)
+
+#define BW_OPMODE_20MHZ BIT(2)
+#define BW_OPMODE_5G BIT(1)
+#define BW_OPMODE_11J BIT(0)
+
+#define CAM_VALID BIT(15)
+#define CAM_NOTVALID 0x0000
+#define CAM_USEDK BIT(5)
+
+#define CAM_NONE 0x0
+#define CAM_WEP40 0x01
+#define CAM_TKIP 0x02
+#define CAM_AES 0x04
+#define CAM_WEP104 0x05
+
+#define TOTAL_CAM_ENTRY 32
+#define HALF_CAM_ENTRY 16
+
+#define CAM_WRITE BIT(16)
+#define CAM_READ 0x00000000
+#define CAM_POLLINIG BIT(31)
+
+#define SCR_USEDK 0x01
+#define SCR_TXSEC_ENABLE 0x02
+#define SCR_RXSEC_ENABLE 0x04
+
+#define WOW_PMEN BIT(0)
+#define WOW_WOMEN BIT(1)
+#define WOW_MAGIC BIT(2)
+#define WOW_UWF BIT(3)
+
+/*********************************************
+* 8723BE IMR/ISR bits
+**********************************************/
+#define IMR_DISABLED 0x0
+/* IMR DW0(0x0060-0063) Bit 0-31 */
+#define IMR_TXCCK BIT(30) /* TXRPT interrupt when
+ * CCX bit of the packet is set
+ */
+#define IMR_PSTIMEOUT BIT(29) /* Power Save Time Out Interrupt */
+#define IMR_GTINT4 BIT(28) /* When GTIMER4 expires,
+ * this bit is set to 1
+ */
+#define IMR_GTINT3 BIT(27) /* When GTIMER3 expires,
+ * this bit is set to 1
+ */
+#define IMR_TBDER BIT(26) /* Transmit Beacon0 Error */
+#define IMR_TBDOK BIT(25) /* Transmit Beacon0 OK */
+#define IMR_TSF_BIT32_TOGGLE BIT(24) /* TSF Timer BIT32 toggle
+ * indication interrupt
+ */
+#define IMR_BCNDMAINT0 BIT(20) /* Beacon DMA Interrupt 0 */
+#define IMR_BCNDOK0 BIT(16) /* Beacon Queue DMA OK0 */
+#define IMR_HSISR_IND_ON_INT BIT(15) /* HSISR Indicator (HSIMR & HSISR is
+ * true, this bit is set to 1)
+ */
+#define IMR_BCNDMAINT_E BIT(14) /* Beacon DMA Interrupt
+ * Extension for Win7
+ */
+#define IMR_ATIMEND BIT(12) /* CTWidnow End or ATIM Window End */
+#define IMR_HISR1_IND_INT BIT(11) /* HISR1 Indicator (HISR1 & HIMR1 is
+ * true, this bit is set to 1)
+ */
+#define IMR_C2HCMD BIT(10) /* CPU to Host Command INT Status,
+ * Write 1 clear
+ */
+#define IMR_CPWM2 BIT(9) /* CPU power Mode exchange INT Status,
+ * Write 1 clear
+ */
+#define IMR_CPWM BIT(8) /* CPU power Mode exchange INT Status,
+ * Write 1 clear
+ */
+#define IMR_HIGHDOK BIT(7) /* High Queue DMA OK */
+#define IMR_MGNTDOK BIT(6) /* Management Queue DMA OK */
+#define IMR_BKDOK BIT(5) /* AC_BK DMA OK */
+#define IMR_BEDOK BIT(4) /* AC_BE DMA OK */
+#define IMR_VIDOK BIT(3) /* AC_VI DMA OK */
+#define IMR_VODOK BIT(2) /* AC_VO DMA OK */
+#define IMR_RDU BIT(1) /* Rx Descriptor Unavailable */
+#define IMR_ROK BIT(0) /* Receive DMA OK */
+
+/* IMR DW1(0x00B4-00B7) Bit 0-31 */
+#define IMR_BCNDMAINT7 BIT(27) /* Beacon DMA Interrupt 7 */
+#define IMR_BCNDMAINT6 BIT(26) /* Beacon DMA Interrupt 6 */
+#define IMR_BCNDMAINT5 BIT(25) /* Beacon DMA Interrupt 5 */
+#define IMR_BCNDMAINT4 BIT(24) /* Beacon DMA Interrupt 4 */
+#define IMR_BCNDMAINT3 BIT(23) /* Beacon DMA Interrupt 3 */
+#define IMR_BCNDMAINT2 BIT(22) /* Beacon DMA Interrupt 2 */
+#define IMR_BCNDMAINT1 BIT(21) /* Beacon DMA Interrupt 1 */
+#define IMR_BCNDOK7 BIT(20) /* Beacon Queue DMA OK Interrup 7 */
+#define IMR_BCNDOK6 BIT(19) /* Beacon Queue DMA OK Interrup 6 */
+#define IMR_BCNDOK5 BIT(18) /* Beacon Queue DMA OK Interrup 5 */
+#define IMR_BCNDOK4 BIT(17) /* Beacon Queue DMA OK Interrup 4 */
+#define IMR_BCNDOK3 BIT(16) /* Beacon Queue DMA OK Interrup 3 */
+#define IMR_BCNDOK2 BIT(15) /* Beacon Queue DMA OK Interrup 2 */
+#define IMR_BCNDOK1 BIT(14) /* Beacon Queue DMA OK Interrup 1 */
+#define IMR_ATIMEND_E BIT(13) /* ATIM Window End Extension for Win7 */
+#define IMR_TXERR BIT(11) /* Tx Error Flag Interrupt Status,
+ * write 1 clear.
+ */
+#define IMR_RXERR BIT(10) /* Rx Error Flag INT Status,
+ * Write 1 clear
+ */
+#define IMR_TXFOVW BIT(9) /* Transmit FIFO Overflow */
+#define IMR_RXFOVW BIT(8) /* Receive FIFO Overflow */
+
+#define HWSET_MAX_SIZE 512
+#define EFUSE_MAX_SECTION 64
+#define EFUSE_REAL_CONTENT_LEN 256
+#define EFUSE_OOB_PROTECT_BYTES 18 /* PG data exclude header,
+ * dummy 7 bytes frome CP test
+ * and reserved 1byte.
+ */
+
+#define EEPROM_DEFAULT_TSSI 0x0
+#define EEPROM_DEFAULT_TXPOWERDIFF 0x0
+#define EEPROM_DEFAULT_CRYSTALCAP 0x5
+#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 0x18
+#define EEPROM_DEFAULT_ANTTXPOWERDIFF 0x0
+#define EEPROM_DEFAULT_TXPWDIFF_CRYSTALCAP 0x5
+#define EEPROM_DEFAULT_TXPOWERLEVEL 0x22
+#define EEPROM_DEFAULT_HT40_2SDIFF 0x0
+#define EEPROM_DEFAULT_HT20_DIFF 2
+#define EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF 0x3
+#define EEPROM_DEFAULT_HT40_PWRMAXOFFSET 0
+#define EEPROM_DEFAULT_HT20_PWRMAXOFFSET 0
+
+#define RF_OPTION1 0x79
+#define RF_OPTION2 0x7A
+#define RF_OPTION3 0x7B
+#define RF_OPTION4 0xC3
+
+#define EEPROM_DEFAULT_PID 0x1234
+#define EEPROM_DEFAULT_VID 0x5678
+#define EEPROM_DEFAULT_CUSTOMERID 0xAB
+#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_SPAIN 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_DOMAIN 0x9
+#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA
+#define EEPROM_CHANNEL_PLAN_NCC 0xB
+#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80
+
+#define EEPROM_CID_DEFAULT 0x0
+#define EEPROM_CID_TOSHIBA 0x4
+#define EEPROM_CID_CCX 0x10
+#define EEPROM_CID_QMI 0x0D
+#define EEPROM_CID_WHQL 0xFE
+
+#define RTL8723BE_EEPROM_ID 0x8129
+
+#define EEPROM_HPON 0x02
+#define EEPROM_CLK 0x06
+#define EEPROM_TESTR 0x08
+
+
+#define EEPROM_TXPOWERCCK 0x10
+#define EEPROM_TXPOWERHT40_1S 0x16
+#define EEPROM_TXPOWERHT20DIFF 0x1B
+#define EEPROM_TXPOWER_OFDMDIFF 0x1B
+
+
+
+#define EEPROM_TX_PWR_INX 0x10
+
+#define EEPROM_CHANNELPLAN 0xB8
+#define EEPROM_XTAL_8723BE 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 0xC4
+#define EEPROM_CUSTOMER_ID 0xC5
+#define EEPROM_RF_ANTENNA_OPT_88E 0xC9
+
+#define EEPROM_MAC_ADDR 0xD0
+#define EEPROM_VID 0xD6
+#define EEPROM_DID 0xD8
+#define EEPROM_SVID 0xDA
+#define EEPROM_SMID 0xDC
+
+#define STOPBECON BIT(6)
+#define STOPHIGHT BIT(5)
+#define STOPMGT BIT(4)
+#define STOPVO BIT(3)
+#define STOPVI BIT(2)
+#define STOPBE BIT(1)
+#define STOPBK BIT(0)
+
+#define RCR_APPFCS BIT(31)
+#define RCR_APP_MIC BIT(30)
+#define RCR_APP_ICV BIT(29)
+#define RCR_APP_PHYST_RXFF BIT(28)
+#define RCR_APP_BA_SSN BIT(27)
+#define RCR_ENMBID BIT(24)
+#define RCR_LSIGEN BIT(23)
+#define RCR_MFBEN BIT(22)
+#define RCR_HTC_LOC_CTRL BIT(14)
+#define RCR_AMF BIT(13)
+#define RCR_ACF BIT(12)
+#define RCR_ADF BIT(11)
+#define RCR_AICV BIT(9)
+#define RCR_ACRC32 BIT(8)
+#define RCR_CBSSID_BCN BIT(7)
+#define RCR_CBSSID_DATA BIT(6)
+#define RCR_CBSSID RCR_CBSSID_DATA
+#define RCR_APWRMGT BIT(5)
+#define RCR_ADD3 BIT(4)
+#define RCR_AB BIT(3)
+#define RCR_AM BIT(2)
+#define RCR_APM BIT(1)
+#define RCR_AAP BIT(0)
+#define RCR_MXDMA_OFFSET 8
+#define RCR_FIFO_OFFSET 13
+
+#define RSV_CTRL 0x001C
+#define RD_CTRL 0x0524
+
+#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_VID 0xFE60
+#define REG_USB_PID 0xFE62
+#define REG_USB_OPTIONAL 0xFE64
+#define REG_USB_CHIRP_K 0xFE65
+#define REG_USB_PHY 0xFE66
+#define REG_USB_MAC_ADDR 0xFE70
+#define REG_USB_HRPWM 0xFE58
+#define REG_USB_HCPWM 0xFE57
+
+#define SW18_FPWM BIT(3)
+
+#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_EV25V BIT(14)
+#define PWC_EV12V BIT(15)
+
+#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)
+
+#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)
+
+#define ANAD16V_EN BIT(0)
+#define ANA8M BIT(1)
+#define MACSLP BIT(4)
+#define LOADER_CLK_EN BIT(5)
+#define _80M_SSC_DIS BIT(7)
+#define _80M_SSC_EN_HO BIT(8)
+#define PHY_SSC_RSTB BIT(9)
+#define SEC_CLK_EN BIT(10)
+#define MAC_CLK_EN BIT(11)
+#define SYS_CLK_EN BIT(12)
+#define RING_CLK_EN BIT(13)
+
+#define BOOT_FROM_EEPROM BIT(4)
+#define EEPROM_EN BIT(5)
+
+#define AFE_BGEN BIT(0)
+#define AFE_MBEN BIT(1)
+#define MAC_ID_EN BIT(7)
+
+#define WLOCK_ALL BIT(0)
+#define WLOCK_00 BIT(1)
+#define WLOCK_04 BIT(2)
+#define WLOCK_08 BIT(3)
+#define WLOCK_40 BIT(4)
+#define R_DIS_PRST_0 BIT(5)
+#define R_DIS_PRST_1 BIT(6)
+#define LOCK_ALL_EN BIT(7)
+
+#define RF_EN BIT(0)
+#define RF_RSTB BIT(1)
+#define RF_SDMRSTB BIT(2)
+
+#define LDA15_EN BIT(0)
+#define LDA15_STBY BIT(1)
+#define LDA15_OBUF BIT(2)
+#define LDA15_REG_VOS BIT(3)
+#define _LDA15_VOADJ(x) (((x) & 0x7) << 4)
+
+#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)
+
+#define XTAL_EN BIT(0)
+#define XTAL_BSEL BIT(1)
+#define _XTAL_BOSC(x) (((x) & 0x3) << 2)
+#define _XTAL_CADJ(x) (((x) & 0xF) << 4)
+#define XTAL_GATE_USB BIT(8)
+#define _XTAL_USB_DRV(x) (((x) & 0x3) << 9)
+#define XTAL_GATE_AFE BIT(11)
+#define _XTAL_AFE_DRV(x) (((x) & 0x3) << 12)
+#define XTAL_RF_GATE BIT(14)
+#define _XTAL_RF_DRV(x) (((x) & 0x3) << 15)
+#define XTAL_GATE_DIG BIT(17)
+#define _XTAL_DIG_DRV(x) (((x) & 0x3) << 18)
+#define XTAL_BT_GATE BIT(20)
+#define _XTAL_BT_DRV(x) (((x) & 0x3) << 21)
+#define _XTAL_GPIO(x) (((x) & 0x7) << 23)
+
+#define CKDLY_AFE BIT(26)
+#define CKDLY_USB BIT(27)
+#define CKDLY_DIG BIT(28)
+#define CKDLY_BT BIT(29)
+
+#define APLL_EN BIT(0)
+#define APLL_320_EN BIT(1)
+#define APLL_FREF_SEL BIT(2)
+#define APLL_EDGE_SEL BIT(3)
+#define APLL_WDOGB BIT(4)
+#define APLL_LPFEN BIT(5)
+
+#define APLL_REF_CLK_13MHZ 0x1
+#define APLL_REF_CLK_19_2MHZ 0x2
+#define APLL_REF_CLK_20MHZ 0x3
+#define APLL_REF_CLK_25MHZ 0x4
+#define APLL_REF_CLK_26MHZ 0x5
+#define APLL_REF_CLK_38_4MHZ 0x6
+#define APLL_REF_CLK_40MHZ 0x7
+
+#define APLL_320EN BIT(14)
+#define APLL_80EN BIT(15)
+#define APLL_1MEN BIT(24)
+
+#define ALD_EN BIT(18)
+#define EF_PD BIT(19)
+#define EF_FLAG BIT(31)
+
+#define EF_TRPT BIT(7)
+#define LDOE25_EN BIT(31)
+
+#define RSM_EN BIT(0)
+#define TIMER_EN BIT(4)
+
+#define TRSW0EN BIT(2)
+#define TRSW1EN BIT(3)
+#define EROM_EN BIT(4)
+#define ENBT BIT(5)
+#define ENUART BIT(8)
+#define UART_910 BIT(9)
+#define ENPMAC BIT(10)
+#define SIC_SWRST BIT(11)
+#define ENSIC BIT(12)
+#define SIC_23 BIT(13)
+#define ENHDP BIT(14)
+#define SIC_LBK BIT(15)
+
+#define LED0PL BIT(4)
+#define LED1PL BIT(12)
+#define LED0DIS BIT(7)
+
+#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 CPRST BIT(23)
+
+#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 TRP_B15V_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 VENDOR_ID BIT(19)
+#define PAD_HWPD_IDN BIT(22)
+#define TRP_VAUX_EN BIT(23)
+#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
+#define CHIP_VER_RTL_SHIFT 12
+
+#define REG_LBMODE (REG_CR + 3)
+
+#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 _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
+
+#define _LBMODE(x) (((x) & 0xF) << 24)
+#define MASK_LBMODE 0xF000000
+#define LOOPBACK_NORMAL 0x0
+#define LOOPBACK_IMMEDIATELY 0xB
+#define LOOPBACK_MAC_DELAY 0x3
+#define LOOPBACK_PHY 0x1
+#define LOOPBACK_DMA 0x7
+
+#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
+
+#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)
+
+#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
+
+#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)
+
+#define BB_WRITE_READ_MASK (BIT(31) | BIT(30))
+#define BB_WRITE_EN BIT(30)
+#define BB_READ_EN BIT(31)
+
+#define _HPQ(x) ((x) & 0xFF)
+#define _LPQ(x) (((x) & 0xFF) << 8)
+#define _PUBQ(x) (((x) & 0xFF) << 16)
+#define _NPQ(x) ((x) & 0xFF)
+
+#define HPQ_PUBLIC_DIS BIT(24)
+#define LPQ_PUBLIC_DIS BIT(25)
+#define LD_RQPN BIT(31)
+
+#define BCN_VALID BIT(16)
+#define BCN_HEAD(x) (((x) & 0xFF) << 8)
+#define BCN_HEAD_MASK 0xFF00
+
+#define BLK_DESC_NUM_SHIFT 4
+#define BLK_DESC_NUM_MASK 0xF
+
+#define DROP_DATA_EN BIT(9)
+
+#define EN_AMPDU_RTY_NEW BIT(7)
+
+#define _INIRTSMCS_SEL(x) ((x) & 0x3F)
+
+#define _SPEC_SIFS_CCK(x) ((x) & 0xFF)
+#define _SPEC_SIFS_OFDM(x) (((x) & 0xFF) << 8)
+
+#define RATE_REG_BITMAP_ALL 0xFFFFF
+
+#define _RRSC_BITMAP(x) ((x) & 0xFFFFF)
+
+#define _RRSR_RSC(x) (((x) & 0x3) << 21)
+#define RRSR_RSC_RESERVED 0x0
+#define RRSR_RSC_UPPER_SUBCHANNEL 0x1
+#define RRSR_RSC_LOWER_SUBCHANNEL 0x2
+#define RRSR_RSC_DUPLICATE_MODE 0x3
+
+#define USE_SHORT_G1 BIT(20)
+
+#define _AGGLMT_MCS0(x) ((x) & 0xF)
+#define _AGGLMT_MCS1(x) (((x) & 0xF) << 4)
+#define _AGGLMT_MCS2(x) (((x) & 0xF) << 8)
+#define _AGGLMT_MCS3(x) (((x) & 0xF) << 12)
+#define _AGGLMT_MCS4(x) (((x) & 0xF) << 16)
+#define _AGGLMT_MCS5(x) (((x) & 0xF) << 20)
+#define _AGGLMT_MCS6(x) (((x) & 0xF) << 24)
+#define _AGGLMT_MCS7(x) (((x) & 0xF) << 28)
+
+#define RETRY_LIMIT_SHORT_SHIFT 8
+#define RETRY_LIMIT_LONG_SHIFT 0
+
+#define _DARF_RC1(x) ((x) & 0x1F)
+#define _DARF_RC2(x) (((x) & 0x1F) << 8)
+#define _DARF_RC3(x) (((x) & 0x1F) << 16)
+#define _DARF_RC4(x) (((x) & 0x1F) << 24)
+#define _DARF_RC5(x) ((x) & 0x1F)
+#define _DARF_RC6(x) (((x) & 0x1F) << 8)
+#define _DARF_RC7(x) (((x) & 0x1F) << 16)
+#define _DARF_RC8(x) (((x) & 0x1F) << 24)
+
+#define _RARF_RC1(x) ((x) & 0x1F)
+#define _RARF_RC2(x) (((x) & 0x1F) << 8)
+#define _RARF_RC3(x) (((x) & 0x1F) << 16)
+#define _RARF_RC4(x) (((x) & 0x1F) << 24)
+#define _RARF_RC5(x) ((x) & 0x1F)
+#define _RARF_RC6(x) (((x) & 0x1F) << 8)
+#define _RARF_RC7(x) (((x) & 0x1F) << 16)
+#define _RARF_RC8(x) (((x) & 0x1F) << 24)
+
+#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 _AIFS(x) (x)
+#define _ECW_MAX_MIN(x) ((x) << 8)
+#define _TXOP_LIMIT(x) ((x) << 16)
+
+#define _BCNIFS(x) ((x) & 0xFF)
+#define _BCNECW(x) ((((x) & 0xF)) << 8)
+
+#define _LRL(x) ((x) & 0x3F)
+#define _SRL(x) (((x) & 0x3F) << 8)
+
+#define _SIFS_CCK_CTX(x) ((x) & 0xFF)
+#define _SIFS_CCK_TRX(x) (((x) & 0xFF) << 8)
+
+#define _SIFS_OFDM_CTX(x) ((x) & 0xFF)
+#define _SIFS_OFDM_TRX(x) (((x) & 0xFF) << 8)
+
+#define _TBTT_PROHIBIT_HOLD(x) (((x) & 0xFF) << 8)
+
+#define DIS_EDCA_CNT_DWN BIT(11)
+
+#define EN_MBSSID BIT(1)
+#define EN_TXBCN_RPT BIT(2)
+#define EN_BCN_FUNCTION BIT(3)
+
+#define TSFTR_RST BIT(0)
+#define TSFTR1_RST BIT(1)
+
+#define STOP_BCNQ BIT(6)
+
+#define DIS_TSF_UDT0_NORMAL_CHIP BIT(4)
+#define DIS_TSF_UDT0_TEST_CHIP BIT(5)
+
+#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)
+
+#define APSDOFF BIT(6)
+#define APSDOFF_STATUS BIT(7)
+
+#define BW_20MHZ BIT(2)
+
+#define RATE_BITMAP_ALL 0xFFFFF
+
+#define RATE_RRSR_CCK_ONLY_1M 0xFFFF1
+
+#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)
+
+#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)
+
+#define _MIN_SPACE(x) ((x) & 0x7)
+#define _SHORT_GI_PADDING(x) (((x) & 0x1F) << 3)
+
+#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)
+
+#define SCR_TXUSEDK BIT(0)
+#define SCR_RXUSEDK BIT(1)
+#define SCR_TXENCENABLE BIT(2)
+#define SCR_RXDECENABLE BIT(3)
+#define SCR_SKBYA2 BIT(4)
+#define SCR_NOSKMC BIT(5)
+#define SCR_TXBCUSEDK BIT(6)
+#define SCR_RXBCUSEDK BIT(7)
+
+#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 TRP_B15V_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 BT_FUNC BIT(16)
+#define VENDOR_ID BIT(19)
+#define PAD_HWPD_IDN BIT(22)
+#define TRP_VAUX_EN BIT(23)
+#define TRP_BT_EN BIT(24)
+#define BD_PKG_SEL BIT(25)
+#define BD_HCI_SEL BIT(26)
+#define TYPE_ID BIT(27)
+
+#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
+
+#define USB_TEST_EP_MASK 0x30
+#define USB_TEST_EP_SHIFT 4
+
+#define USB_AGG_EN BIT(3)
+
+#define MAC_ADDR_LEN 6
+#define LAST_ENTRY_OF_TX_PKT_BUFFER 175/*255 88e*/
+
+#define POLLING_LLT_THRESHOLD 20
+#define POLLING_READY_TIMEOUT_COUNT 3000
+
+#define MAX_MSS_DENSITY_2T 0x13
+#define MAX_MSS_DENSITY_1T 0x0A
+
+#define EPROM_CMD_OPERATING_MODE_MASK ((1<<7)|(1<<6))
+#define EPROM_CMD_CONFIG 0x3
+#define EPROM_CMD_LOAD 1
+
+#define HWSET_MAX_SIZE_92S HWSET_MAX_SIZE
+
+#define HAL_8192C_HW_GPIO_WPS_BIT BIT(2)
+
+#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_TXDADATYPE 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
+
+#define RFPGA0_RFMOD 0x800
+
+#define RFPGA0_TXINFO 0x804
+#define RFPGA0_PSDFUNCTION 0x808
+
+#define RFPGA0_TXGAINSTAGE 0x80c
+
+#define RFPGA0_RFTIMING1 0x810
+#define RFPGA0_RFTIMING2 0x814
+
+#define RFPGA0_XA_HSSIPARAMETER1 0x820
+#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
+#define RFPGA0_RFSLEEPUPPARAMETER 0x854
+
+#define RFPGA0_XAB_SWITCHCONTROL 0x858
+#define RFPGA0_XCD_SWITCHCONTROL 0x85c
+
+#define RFPGA0_XA_RFINTERFACEOE 0x860
+#define RFPGA0_XB_RFINTERFACEOE 0x864
+
+#define RFPGA0_XAB_RFINTERFACESW 0x870
+#define RFPGA0_XCD_RFINTERFACESW 0x874
+
+#define RFPGA0_XAB_RFPARAMETER 0x878
+#define RFPGA0_XCD_RFPARAMETER 0x87c
+
+#define RFPGA0_ANALOGPARAMETER1 0x880
+#define RFPGA0_ANALOGPARAMETER2 0x884
+#define RFPGA0_ANALOGPARAMETER3 0x888
+#define RFPGA0_ANALOGPARAMETER4 0x88c
+
+#define RFPGA0_XA_LSSIREADBACK 0x8a0
+#define RFPGA0_XB_LSSIREADBACK 0x8a4
+#define RFPGA0_XC_LSSIREADBACK 0x8a8
+#define RFPGA0_XD_LSSIREADBACK 0x8ac
+
+#define RFPGA0_PSDREPORT 0x8b4
+#define TRANSCEIVEA_HSPI_READBACK 0x8b8
+#define TRANSCEIVEB_HSPI_READBACK 0x8bc
+#define REG_SC_CNT 0x8c4
+#define RFPGA0_XAB_RFINTERFACERB 0x8e0
+#define RFPGA0_XCD_RFINTERFACERB 0x8e4
+
+#define RFPGA1_RFMOD 0x900
+
+#define RFPGA1_TXBLOCK 0x904
+#define RFPGA1_DEBUGSELECT 0x908
+#define RFPGA1_TXINFO 0x90c
+
+#define RCCK0_SYSTEM 0xa00
+
+#define RCCK0_AFESETTING 0xa04
+#define RCCK0_CCA 0xa08
+
+#define RCCK0_RXAGC1 0xa0c
+#define RCCK0_RXAGC2 0xa10
+
+#define RCCK0_RXHP 0xa14
+
+#define RCCK0_DSPPARAMETER1 0xa18
+#define RCCK0_DSPPARAMETER2 0xa1c
+
+#define RCCK0_TXFILTER1 0xa20
+#define RCCK0_TXFILTER2 0xa24
+#define RCCK0_DEBUGPORT 0xa28
+#define RCCK0_FALSEALARMREPORT 0xa2c
+#define RCCK0_TRSSIREPORT 0xa50
+#define RCCK0_RXREPORT 0xa54
+#define RCCK0_FACOUNTERLOWER 0xa5c
+#define RCCK0_FACOUNTERUPPER 0xa58
+#define RCCK0_CCA_CNT 0xa60
+
+
+/* PageB(0xB00) */
+#define RPDP_ANTA 0xb00
+#define RPDP_ANTA_4 0xb04
+#define RPDP_ANTA_8 0xb08
+#define RPDP_ANTA_C 0xb0c
+#define RPDP_ANTA_10 0xb10
+#define RPDP_ANTA_14 0xb14
+#define RPDP_ANTA_18 0xb18
+#define RPDP_ANTA_1C 0xb1c
+#define RPDP_ANTA_20 0xb20
+#define RPDP_ANTA_24 0xb24
+
+#define RCONFIG_PMPD_ANTA 0xb28
+#define CONFIG_RAM64X16 0xb2c
+
+#define RBNDA 0xb30
+#define RHSSIPAR 0xb34
+
+#define RCONFIG_ANTA 0xb68
+#define RCONFIG_ANTB 0xb6c
+
+#define RPDP_ANTB 0xb70
+#define RPDP_ANTB_4 0xb74
+#define RPDP_ANTB_8 0xb78
+#define RPDP_ANTB_C 0xb7c
+#define RPDP_ANTB_10 0xb80
+#define RPDP_ANTB_14 0xb84
+#define RPDP_ANTB_18 0xb88
+#define RPDP_ANTB_1C 0xb8c
+#define RPDP_ANTB_20 0xb90
+#define RPDP_ANTB_24 0xb94
+
+#define RCONFIG_PMPD_ANTB 0xb98
+
+#define RBNDB 0xba0
+
+#define RAPK 0xbd8
+#define RPM_RX0_ANTA 0xbdc
+#define RPM_RX1_ANTA 0xbe0
+#define RPM_RX2_ANTA 0xbe4
+#define RPM_RX3_ANTA 0xbe8
+#define RPM_RX0_ANTB 0xbec
+#define RPM_RX1_ANTB 0xbf0
+#define RPM_RX2_ANTB 0xbf4
+#define RPM_RX3_ANTB 0xbf8
+
+/*Page C*/
+#define ROFDM0_LSTF 0xc00
+
+#define ROFDM0_TRXPATHENABLE 0xc04
+#define ROFDM0_TRMUXPAR 0xc08
+#define ROFDM0_TRSWISOLATION 0xc0c
+
+#define ROFDM0_XARXAFE 0xc10
+#define ROFDM0_XARXIQIMBALANCE 0xc14
+#define ROFDM0_XBRXAFE 0xc18
+#define ROFDM0_XBRXIQIMBALANCE 0xc1c
+#define ROFDM0_XCRXAFE 0xc20
+#define ROFDM0_XCRXIQIMBANLANCE 0xc24
+#define ROFDM0_XDRXAFE 0xc28
+#define ROFDM0_XDRXIQIMBALANCE 0xc2c
+
+#define ROFDM0_RXDETECTOR1 0xc30
+#define ROFDM0_RXDETECTOR2 0xc34
+#define ROFDM0_RXDETECTOR3 0xc38
+#define ROFDM0_RXDETECTOR4 0xc3c
+
+#define ROFDM0_RXDSP 0xc40
+#define ROFDM0_CFOANDDAGC 0xc44
+#define ROFDM0_CCADROPTHRESHOLD 0xc48
+#define ROFDM0_ECCATHRESHOLD 0xc4c
+
+#define ROFDM0_XAAGCCORE1 0xc50
+#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
+#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
+
+
+#define ROFDM1_LSTF 0xd00
+#define ROFDM1_TRXPATHENABLE 0xd04
+
+#define ROFDM1_CF0 0xd08
+#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
+#define ROFDM_PHYCOUNTER2 0xda4
+#define ROFDM_PHYCOUNTER3 0xda8
+
+#define ROFDM_SHORTCFOAB 0xdac
+#define ROFDM_SHORTCFOCD 0xdb0
+#define ROFDM_LONGCFOAB 0xdb4
+#define ROFDM_LONGCFOCD 0xdb8
+#define ROFDM_TAILCF0AB 0xdbc
+#define ROFDM_TAILCF0CD 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
+
+#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
+
+#define RZEBRA1_HSSIENABLE 0x0
+#define RZEBRA1_TRXENABLE1 0x1
+#define RZEBRA1_TRXENABLE2 0x2
+#define RZEBRA1_AGC 0x4
+#define RZEBRA1_CHARGEPUMP 0x5
+#define RZEBRA1_CHANNEL 0x7
+
+#define RZEBRA1_TXGAIN 0x8
+#define RZEBRA1_TXLPF 0x9
+#define RZEBRA1_RXLPF 0xb
+#define RZEBRA1_RXHPFCORNER 0xc
+
+#define RGLOBALCTRL 0
+#define RRTL8256_TXLPF 19
+#define RRTL8256_RXLPF 11
+#define RRTL8258_TXLPF 0x11
+#define RRTL8258_RXLPF 0x13
+#define RRTL8258_RSSILPF 0xa
+
+#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_POW_ABILITY 0x17
+#define RF_MODE_AG 0x18
+#define RRFCHANNEL 0x18
+#define RF_CHNLBW 0x18
+#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 0x42
+
+#define RF_SYN_G1 0x25
+#define RF_SYN_G2 0x26
+#define RF_SYN_G3 0x27
+#define RF_SYN_G4 0x28
+#define RF_SYN_G5 0x29
+#define RF_SYN_G6 0x2A
+#define RF_SYN_G7 0x2B
+#define RF_SYN_G8 0x2C
+
+#define RF_RCK_OS 0x30
+#define RF_TXPA_G1 0x31
+#define RF_TXPA_G2 0x32
+#define RF_TXPA_G3 0x33
+
+#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_WE_LUT 0xEF
+
+#define BBBRESETB 0x100
+#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 BCCKTXLENGHT 0xffff0000
+#define BCCKTXCRC16 0xffff
+#define BCCKTXSTATUS 0x1
+#define BOFDMTXSTATUS 0x2
+#define IS_BB_REG_OFFSET_92S(_offset) \
+ ((_offset >= 0x800) && (_offset <= 0xfff))
+
+#define BRFMOD 0x1
+#define BJAPANMODE 0x2
+#define BCCKTXSC 0x30
+#define BCCKEN 0x1000000
+#define BOFDMEN 0x2000000
+
+#define BOFDMRXADCPHASE 0x10000
+#define BOFDMTXDACPHASE 0x40000
+#define BXATXAGC 0x3f
+
+#define BXBTXAGC 0xf00
+#define BXCTXAGC 0xf000
+#define BXDTXAGC 0xf0000
+
+#define BPASTART 0xf0000000
+#define BTRSTART 0x00f00000
+#define BRFSTART 0x0000f000
+#define BBBSTART 0x000000f0
+#define BBBCCKSTART 0x0000000f
+#define BPAEND 0xf
+#define BTREND 0x0f000000
+#define BRFEND 0x000f0000
+#define BCCAMASK 0x000000f0
+#define BR2RCCAMASK 0x00000f00
+#define BHSSI_R2TDELAY 0xf8000000
+#define BHSSI_T2RDELAY 0xf80000
+#define BCONTXHSSI 0x400
+#define BIGFROMCCK 0x200
+#define BAGCADDRESS 0x3f
+#define BRXHPTX 0x7000
+#define BRXHP2RX 0x38000
+#define BRXHPCCKINI 0xc0000
+#define BAGCTXCODE 0xc00000
+#define BAGCRXCODE 0x300000
+
+#define B3WIREDATALENGTH 0x800
+#define B3WIREADDREAALENGTH 0x400
+
+#define B3WIRERFPOWERDOWN 0x1
+#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
+
+#define BRFSI_TRSW 0x20
+#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
+#define BLSSIREADEDGE 0x80000000
+
+#define BLSSIREADBACKDATA 0xfffff
+
+#define BLSSIREADOKFLAG 0x1000
+#define BCCKSAMPLERATE 0x8
+#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
+#define B80MCLKDELAY 0x18000000
+#define BAFEWATCHDOGENABLE 0x20000000
+
+#define BXTALCAP01 0xc0000000
+#define BXTALCAP23 0x3
+#define BXTALCAP92X 0x0f000000
+#define BXTALCAP 0x0f000000
+
+#define BINTDIFCLKENABLE 0x400
+#define BEXTSIGCLKENABLE 0x800
+#define BBANDGAP_MBIAS_POWERUP 0x10000
+#define BAD11SH_GAIN 0xc0000
+#define BAD11NPUT_RANGE 0x700000
+#define BAD110P_CURRENT 0x3800000
+#define BLPATH_LOOPBACK 0x4000000
+#define BQPATH_LOOPBACK 0x8000000
+#define BAFE_LOOPBACK 0x10000000
+#define BDA10_SWING 0x7e0
+#define BDA10_REVERSE 0x800
+#define BDA_CLK_SOURCE 0x1000
+#define BDA7INPUT_RANGE 0x6000
+#define BDA7_GAIN 0x38000
+#define BDA7OUTPUT_CM_MODE 0x40000
+#define BDA7INPUT_CM_MODE 0x380000
+#define BDA7CURRENT 0xc00000
+#define BREGULATOR_ADJUST 0x7000000
+#define BAD11POWERUP_ATTX 0x1
+#define BDA10PS_ATTX 0x10
+#define BAD11POWERUP_ATRX 0x100
+#define BDA10PS_ATRX 0x1000
+#define BCCKRX_AGC_FORMAT 0x200
+#define BPSDFFT_SAMPLE_POINT 0xc000
+#define BPSD_AVERAGE_NUM 0x3000
+#define BIQPATH_CONTROL 0xc00
+#define BPSD_FREQ 0x3ff
+#define BPSD_ANTENNA_PATH 0x30
+#define BPSD_IQ_SWITCH 0x40
+#define BPSD_RX_TRIGGER 0x400000
+#define BPSD_TX_TRIGGER 0x80000000
+#define BPSD_SINE_TONE_SCALE 0x7f000000
+#define BPSD_REPORT 0xffff
+
+#define BOFDM_TXSC 0x30000000
+#define BCCK_TXON 0x1
+#define BOFDM_TXON 0x2
+#define BDEBUG_PAGE 0xfff
+#define BDEBUG_ITEM 0xff
+#define BANTL 0x10
+#define BANT_NONHT 0x100
+#define BANT_HT1 0x1000
+#define BANT_HT2 0x10000
+#define BANT_HT1S1 0x100000
+#define BANT_NONHTS1 0x1000000
+
+#define BCCK_BBMODE 0x3
+#define BCCK_TXPOWERSAVING 0x80
+#define BCCK_RXPOWERSAVING 0x40
+
+#define BCCK_SIDEBAND 0x10
+
+#define BCCK_SCRAMBLE 0x8
+#define BCCK_ANTDIVERSITY 0x8000
+#define BCCK_CARRIER_RECOVERY 0x4000
+#define BCCK_TXRATE 0x3000
+#define BCCK_DCCANCEL 0x0800
+#define BCCK_ISICANCEL 0x0400
+#define BCCK_MATCH_FILTER 0x0200
+#define BCCK_EQUALIZER 0x0100
+#define BCCK_PREAMBLE_DETECT 0x800000
+#define BCCK_FAST_FALSECCA 0x400000
+#define BCCK_CH_ESTSTART 0x300000
+#define BCCK_CCA_COUNT 0x080000
+#define BCCK_CS_LIM 0x070000
+#define BCCK_BIST_MODE 0x80000000
+#define BCCK_CCAMASK 0x40000000
+#define BCCK_TX_DAC_PHASE 0x4
+#define BCCK_RX_ADC_PHASE 0x20000000
+#define BCCKR_CP_MODE 0x0100
+#define BCCK_TXDC_OFFSET 0xf0
+#define BCCK_RXDC_OFFSET 0xf
+#define BCCK_CCA_MODE 0xc000
+#define BCCK_FALSECS_LIM 0x3f00
+#define BCCK_CS_RATIO 0xc00000
+#define BCCK_CORGBIT_SEL 0x300000
+#define BCCK_PD_LIM 0x0f0000
+#define BCCK_NEWCCA 0x80000000
+#define BCCK_RXHP_OF_IG 0x8000
+#define BCCK_RXIG 0x7f00
+#define BCCK_LNA_POLARITY 0x800000
+#define BCCK_RX1ST_BAIN 0x7f0000
+#define BCCK_RF_EXTEND 0x20000000
+#define BCCK_RXAGC_SATLEVEL 0x1f000000
+#define BCCK_RXAGC_SATCOUNT 0xe0
+#define BCCKRXRFSETTLE 0x1f
+#define BCCK_FIXED_RXAGC 0x8000
+#define BCCK_ANTENNA_POLARITY 0x2000
+#define BCCK_TXFILTER_TYPE 0x0c00
+#define BCCK_RXAGC_REPORTTYPE 0x0300
+#define BCCK_RXDAGC_EN 0x80000000
+#define BCCK_RXDAGC_PERIOD 0x20000000
+#define BCCK_RXDAGC_SATLEVEL 0x1f000000
+#define BCCK_TIMING_RECOVERY 0x800000
+#define BCCK_TXC0 0x3f0000
+#define BCCK_TXC1 0x3f000000
+#define BCCK_TXC2 0x3f
+#define BCCK_TXC3 0x3f00
+#define BCCK_TXC4 0x3f0000
+#define BCCK_TXC5 0x3f000000
+#define BCCK_TXC6 0x3f
+#define BCCK_TXC7 0x3f00
+#define BCCK_DEBUGPORT 0xff0000
+#define BCCK_DAC_DEBUG 0x0f000000
+#define BCCK_FALSEALARM_ENABLE 0x8000
+#define BCCK_FALSEALARM_READ 0x4000
+#define BCCK_TRSSI 0x7f
+#define BCCK_RXAGC_REPORT 0xfe
+#define BCCK_RXREPORT_ANTSEL 0x80000000
+#define BCCK_RXREPORT_MFOFF 0x40000000
+#define BCCK_RXREPORT_SQLOSS 0x20000000
+#define BCCK_RXREPORT_PKTLOSS 0x10000000
+#define BCCK_RXREPORT_LOCKEDBIT 0x08000000
+#define BCCK_RXREPORT_RATEERROR 0x04000000
+#define BCCK_RXREPORT_RXRATE 0x03000000
+#define BCCK_RXFA_COUNTER_LOWER 0xff
+#define BCCK_RXFA_COUNTER_UPPER 0xff000000
+#define BCCK_RXHPAGC_START 0xe000
+#define BCCK_RXHPAGC_FINAL 0x1c00
+#define BCCK_RXFALSEALARM_ENABLE 0x8000
+#define BCCK_FACOUNTER_FREEZE 0x4000
+#define BCCK_TXPATH_SEL 0x10000000
+#define BCCK_DEFAULT_RXPATH 0xc000000
+#define BCCK_OPTION_RXPATH 0x3000000
+
+#define BNUM_OFSTF 0x3
+#define BSHIFT_L 0xc0
+#define BGI_TH 0xc
+#define BRXPATH_A 0x1
+#define BRXPATH_B 0x2
+#define BRXPATH_C 0x4
+#define BRXPATH_D 0x8
+#define BTXPATH_A 0x1
+#define BTXPATH_B 0x2
+#define BTXPATH_C 0x4
+#define BTXPATH_D 0x8
+#define BTRSSI_FREQ 0x200
+#define BADC_BACKOFF 0x3000
+#define BDFIR_BACKOFF 0xc000
+#define BTRSSI_LATCH_PHASE 0x10000
+#define BRX_LDC_OFFSET 0xff
+#define BRX_QDC_OFFSET 0xff00
+#define BRX_DFIR_MODE 0x1800000
+#define BRX_DCNF_TYPE 0xe000000
+#define BRXIQIMB_A 0x3ff
+#define BRXIQIMB_B 0xfc00
+#define BRXIQIMB_C 0x3f0000
+#define BRXIQIMB_D 0xffc00000
+#define BDC_DC_NOTCH 0x60000
+#define BRXNB_NOTCH 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 BRADIO_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 BCFOLOOPBACK 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 BTXIQDCOFFSET 0xff00
+#define BTXDFIRMODE 0x10000
+#define BTXPESUDO_NOISEON 0x4000000
+#define BTXPESUDO_NOISE_A 0xff
+#define BTXPESUDO_NOISE_B 0xff00
+#define BTXPESUDO_NOISE_C 0xff0000
+#define BTXPESUDO_NOISE_D 0xff000000
+#define BCCA_DROPOPTION 0x20000
+#define BCCA_DROPTHRES 0xfff00000
+#define BEDCCA_H 0xf
+#define BEDCCA_L 0xf0
+#define BLAMBDA_ED 0x300
+#define BRX_INITIALGAIN 0x7f
+#define BRX_ANTDIV_EN 0x80
+#define BRX_AGC_ADDRESS_FOR_LNA 0x7f00
+#define BRX_HIGHPOWER_FLOW 0x8000
+#define BRX_AGC_FREEZE_THRES 0xc0000
+#define BRX_FREEZESTEP_AGC1 0x300000
+#define BRX_FREEZESTEP_AGC2 0xc00000
+#define BRX_FREEZESTEP_AGC3 0x3000000
+#define BRX_FREEZESTEP_AGC0 0xc000000
+#define BRXRSSI_CMP_EN 0x10000000
+#define BRXQUICK_AGCEN 0x20000000
+#define BRXAGC_FREEZE_THRES_MODE 0x40000000
+#define BRX_OVERFLOW_CHECKTYPE 0x80000000
+#define BRX_AGCSHIFT 0x7f
+#define BTRSW_TRI_ONLY 0x80
+#define BPOWER_THRES 0x300
+#define BRXAGC_EN 0x1
+#define BRXAGC_TOGETHER_EN 0x2
+#define BRXAGC_MIN 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
+#define BRSSI_GEN 0x7f000000
+#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 BRXPROCESS_TIME_DAGC 0x300000
+#define BRXSETTLE_HSSI 0x400000
+#define BRXPROCESS_TIME_BBPPW 0x800000
+#define BRXANTENNA_POWER_SHIFT 0x3000000
+#define BRSSI_TABLE_SELECT 0xc000000
+#define BRXHP_FINAL 0x7000000
+#define BRXHPSETTLE_BBP 0x7
+#define BRXHTSETTLE_HSSI 0x8
+#define BRXHTSETTLE_RXHP 0x70
+#define BRXHTSETTLE_BBPPW 0x80
+#define BRXHTSETTLE_IDLE 0x300
+#define BRXHTSETTLE_RESERVED 0x1c00
+#define BRXHT_RXHP_EN 0x8000
+#define BRXAGC_FREEZE_THRES 0x30000
+#define BRXAGC_TOGETHEREN 0x40000
+#define BRXHTAGC_MIN 0x80000
+#define BRXHTAGC_EN 0x100000
+#define BRXHTDAGC_EN 0x200000
+#define BRXHT_RXHP_BBP 0x1c00000
+#define BRXHT_RXHP_FINAL 0xe0000000
+#define BRXPW_RADIO_TH 0x3
+#define BRXPW_RADIO_EN 0x4
+#define BRXMF_HOLD 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_FUARD_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 BMF_WEIGHT_SUM 0x300000
+#define BMINIDX_TH 0x7f000000
+#define BDAFORMAT 0x40000
+#define BTXCH_EMU_ENABLE 0x01000000
+#define BTRSW_ISOLATION_A 0x7f
+#define BTRSW_ISOLATION_B 0x7f00
+#define BTRSW_ISOLATION_C 0x7f0000
+#define BTRSW_ISOLATION_D 0x7f000000
+#define BEXT_LNA_GAIN 0x7c00
+
+#define BSTBC_EN 0x4
+#define BANTENNA_MAPPING 0x10
+#define BNSS 0x20
+#define BCFO_ANTSUM_ID 0x200
+#define BPHY_COUNTER_RESET 0x8000000
+#define BCFO_REPORT_GET 0x4000000
+#define BOFDM_CONTINUE_TX 0x10000000
+#define BOFDM_SINGLE_CARRIER 0x20000000
+#define BOFDM_SINGLE_TONE 0x40000000
+#define BHT_DETECT 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 BSHORTCFOT_LENGTH 12
+#define BSHORTCFOF_LENGTH 11
+#define BLONGCFO 0x7ff
+#define BLONGCFOT_LENGTH 11
+#define BLONGCFOF_LENGTH 11
+#define BTAILCFO 0x1fff
+#define BTAILCFOT_LENGTH 13
+#define BTAILCFOF_LENGTH 12
+#define BNOISE_EN_PWDB 0xffff
+#define BCC_POWER_DB 0xffff0000
+#define BMOISE_PWDB 0xffff
+#define BPOWERMEAST_LENGTH 10
+#define BPOWERMEASF_LENGTH 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 BSNR_EVMT_LENGTH 8
+#define BSNR_EVMF_LENGTH 1
+#define BCSI1ST 0xff
+#define BCSI2ND 0xff00
+#define BRXEVM1ST 0xff0000
+#define BRXEVM2ND 0xff000000
+#define BSIGEVM 0xff
+#define BPWDB 0xff00
+#define BSGIEN 0x10000
+
+#define BSFACTOR_QMA1 0xf
+#define BSFACTOR_QMA2 0xf0
+#define BSFACTOR_QMA3 0xf00
+#define BSFACTOR_QMA4 0xf000
+#define BSFACTOR_QMA5 0xf0000
+#define BSFACTOR_QMA6 0xf0000
+#define BSFACTOR_QMA7 0xf00000
+#define BSFACTOR_QMA8 0xf000000
+#define BSFACTOR_QMA9 0xf0000000
+#define BCSI_SCHEME 0x100000
+
+#define BNOISE_LVL_TOP_SET 0x3
+#define BCHSMOOTH 0x4
+#define BCHSMOOTH_CFG1 0x38
+#define BCHSMOOTH_CFG2 0x1c0
+#define BCHSMOOTH_CFG3 0xe00
+#define BCHSMOOTH_CFG4 0x7000
+#define BMRCMODE 0x800000
+#define BTHEVMCFG 0x7000000
+
+#define BLOOP_FIT_TYPE 0x1
+#define BUPD_CFO 0x40
+#define BUPD_CFO_OFFDATA 0x80
+#define BADV_UPD_CFO 0x100
+#define BADV_TIME_CTRL 0x800
+#define BUPD_CLKO 0x1000
+#define BFC 0x6000
+#define BTRACKING_MODE 0x8000
+#define BPHCMP_ENABLE 0x10000
+#define BUPD_CLKO_LTF 0x20000
+#define BCOM_CH_CFO 0x40000
+#define BCSI_ESTI_MODE 0x80000
+#define BADV_UPD_EQZ 0x100000
+#define BUCHCFG 0x7000000
+#define BUPDEQZ 0x8000000
+
+#define BRX_PESUDO_NOISE_ON 0x20000000
+#define BRX_PESUDO_NOISE_A 0xff
+#define BRX_PESUDO_NOISE_B 0xff00
+#define BRX_PESUDO_NOISE_C 0xff0000
+#define BRX_PESUDO_NOISE_D 0xff000000
+#define BRX_PESUDO_NOISESTATE_A 0xffff
+#define BRX_PESUDO_NOISESTATE_B 0xffff0000
+#define BRX_PESUDO_NOISESTATE_C 0xffff
+#define BRX_PESUDO_NOISESTATE_D 0xffff0000
+
+#define BZEBRA1_HSSIENABLE 0x8
+#define BZEBRA1_TRXCONTROL 0xc00
+#define BZEBRA1_TRXGAINSETTING 0x07f
+#define BZEBRA1_RXCOUNTER 0xc00
+#define BZEBRA1_TXCHANGEPUMP 0x38
+#define BZEBRA1_RXCHANGEPUMP 0x7
+#define BZEBRA1_CHANNEL_NUM 0xf80
+#define BZEBRA1_TXLPFBW 0x400
+#define BZEBRA1_RXLPFBW 0x600
+
+#define BRTL8256REG_MODE_CTRL1 0x100
+#define BRTL8256REG_MODE_CTRL0 0x40
+#define BRTL8256REG_TXLPFBW 0x18
+#define BRTL8256REG_RXLPFBW 0x600
+
+#define BRTL8258_TXLPFBW 0xc
+#define BRTL8258_RXLPFBW 0xc00
+#define BRTL8258_RSSILPFBW 0xc0
+
+#define BBYTE0 0x1
+#define BBYTE1 0x2
+#define BBYTE2 0x4
+#define BBYTE3 0x8
+#define BWORD0 0x3
+#define BWORD1 0xc
+#define BWORD 0xf
+
+#define BENABLE 0x1
+#define BDISABLE 0x0
+
+#define LEFT_ANTENNA 0x0
+#define RIGHT_ANTENNA 0x1
+
+#define TCHECK_TXSTATUS 500
+#define TUPDATE_RXCOUNTER 100
+
+#define REG_UN_used_register 0x01bf
+
+/* WOL bit information */
+#define HAL92C_WOL_PTK_UPDATE_EVENT BIT(0)
+#define HAL92C_WOL_GTK_UPDATE_EVENT BIT(1)
+#define HAL92C_WOL_DISASSOC_EVENT BIT(2)
+#define HAL92C_WOL_DEAUTH_EVENT BIT(3)
+#define HAL92C_WOL_FW_DISCONNECT_EVENT BIT(4)
+
+#define WOL_REASON_PTK_UPDATE BIT(0)
+#define WOL_REASON_GTK_UPDATE BIT(1)
+#define WOL_REASON_DISASSOC BIT(2)
+#define WOL_REASON_DEAUTH BIT(3)
+#define WOL_REASON_FW_DISCONNECT BIT(4)
+
+/* 2 EFUSE_TEST (For RTL8723 partially) */
+#define EFUSE_SEL(x) (((x) & 0x3) << 8)
+#define EFUSE_SEL_MASK 0x300
+#define EFUSE_WIFI_SEL_0 0x0
+
+#define WL_HWPDN_EN BIT(0) /* Enable GPIO[9] as WiFi HW PDn source*/
+#define WL_HWPDN_SL BIT(1) /* WiFi HW PDn polarity control*/
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/rf.c b/drivers/net/wireless/rtlwifi/rtl8723be/rf.c
new file mode 100644
index 000000000000..486294930a7b
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/rf.c
@@ -0,0 +1,504 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "rf.h"
+#include "dm.h"
+
+static bool _rtl8723be_phy_rf6052_config_parafile(struct ieee80211_hw *hw);
+
+void rtl8723be_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ switch (bandwidth) {
+ case HT_CHANNEL_WIDTH_20:
+ rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
+ 0xfffff3ff) | BIT(10) | BIT(11));
+ rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
+ rtlphy->rfreg_chnlval[0]);
+ break;
+ case HT_CHANNEL_WIDTH_20_40:
+ rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
+ 0xfffff3ff) | BIT(10));
+ rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
+ rtlphy->rfreg_chnlval[0]);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
+ "unknown bandwidth: %#X\n", bandwidth);
+ break;
+ }
+}
+
+void rtl8723be_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
+ u8 *ppowerlevel)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u32 tx_agc[2] = {0, 0}, tmpval;
+ bool turbo_scanoff = false;
+ u8 idx1, idx2;
+ u8 *ptr;
+ u8 direction;
+ u32 pwrtrac_value;
+
+ if (rtlefuse->eeprom_regulatory != 0)
+ turbo_scanoff = true;
+
+ if (mac->act_scanning) {
+ tx_agc[RF90_PATH_A] = 0x3f3f3f3f;
+ tx_agc[RF90_PATH_B] = 0x3f3f3f3f;
+
+ if (turbo_scanoff) {
+ for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+ tx_agc[idx1] = ppowerlevel[idx1] |
+ (ppowerlevel[idx1] << 8) |
+ (ppowerlevel[idx1] << 16) |
+ (ppowerlevel[idx1] << 24);
+ }
+ }
+ } else {
+ for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+ tx_agc[idx1] = ppowerlevel[idx1] |
+ (ppowerlevel[idx1] << 8) |
+ (ppowerlevel[idx1] << 16) |
+ (ppowerlevel[idx1] << 24);
+ }
+ if (rtlefuse->eeprom_regulatory == 0) {
+ tmpval =
+ (rtlphy->mcs_offset[0][6]) +
+ (rtlphy->mcs_offset[0][7] << 8);
+ tx_agc[RF90_PATH_A] += tmpval;
+
+ tmpval = (rtlphy->mcs_offset[0][14]) +
+ (rtlphy->mcs_offset[0][15] <<
+ 24);
+ tx_agc[RF90_PATH_B] += tmpval;
+ }
+ }
+ for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+ ptr = (u8 *)(&(tx_agc[idx1]));
+ for (idx2 = 0; idx2 < 4; idx2++) {
+ if (*ptr > RF6052_MAX_TX_PWR)
+ *ptr = RF6052_MAX_TX_PWR;
+ ptr++;
+ }
+ }
+ rtl8723be_dm_txpower_track_adjust(hw, 1, &direction, &pwrtrac_value);
+ if (direction == 1) {
+ tx_agc[0] += pwrtrac_value;
+ tx_agc[1] += pwrtrac_value;
+ } else if (direction == 2) {
+ tx_agc[0] -= pwrtrac_value;
+ tx_agc[1] -= pwrtrac_value;
+ }
+ tmpval = tx_agc[RF90_PATH_A] & 0xff;
+ rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
+ RTXAGC_A_CCK1_MCS32);
+
+ tmpval = tx_agc[RF90_PATH_A] >> 8;
+
+ rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
+ RTXAGC_B_CCK11_A_CCK2_11);
+
+ tmpval = tx_agc[RF90_PATH_B] >> 24;
+ rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
+ RTXAGC_B_CCK11_A_CCK2_11);
+
+ tmpval = tx_agc[RF90_PATH_B] & 0x00ffffff;
+ rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, 0xffffff00, tmpval);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
+ RTXAGC_B_CCK1_55_MCS32);
+}
+
+static void rtl8723be_phy_get_power_base(struct ieee80211_hw *hw,
+ u8 *ppowerlevel_ofdm,
+ u8 *ppowerlevel_bw20,
+ u8 *ppowerlevel_bw40,
+ u8 channel, u32 *ofdmbase,
+ u32 *mcsbase)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 powerbase0, powerbase1;
+ u8 i, powerlevel[2];
+
+ for (i = 0; i < 2; i++) {
+ powerbase0 = ppowerlevel_ofdm[i];
+
+ powerbase0 = (powerbase0 << 24) | (powerbase0 << 16) |
+ (powerbase0 << 8) | powerbase0;
+ *(ofdmbase + i) = powerbase0;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ " [OFDM power base index rf(%c) = 0x%x]\n",
+ ((i == 0) ? 'A' : 'B'), *(ofdmbase + i));
+ }
+
+ for (i = 0; i < 2; i++) {
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20)
+ powerlevel[i] = ppowerlevel_bw20[i];
+ else
+ powerlevel[i] = ppowerlevel_bw40[i];
+ powerbase1 = powerlevel[i];
+ powerbase1 = (powerbase1 << 24) | (powerbase1 << 16) |
+ (powerbase1 << 8) | powerbase1;
+
+ *(mcsbase + i) = powerbase1;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ " [MCS power base index rf(%c) = 0x%x]\n",
+ ((i == 0) ? 'A' : 'B'), *(mcsbase + i));
+ }
+}
+
+static void txpwr_by_regulatory(struct ieee80211_hw *hw, u8 channel, u8 index,
+ u32 *powerbase0, u32 *powerbase1,
+ u32 *p_outwriteval)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 i, chnlgroup = 0, pwr_diff_limit[4];
+ u8 pwr_diff = 0, customer_pwr_diff;
+ u32 writeval, customer_limit, rf;
+
+ for (rf = 0; rf < 2; rf++) {
+ switch (rtlefuse->eeprom_regulatory) {
+ case 0:
+ chnlgroup = 0;
+
+ writeval =
+ rtlphy->mcs_offset[chnlgroup][index + (rf ? 8 : 0)]
+ + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "RTK better performance, "
+ "writeval(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeval);
+ break;
+ case 1:
+ if (rtlphy->pwrgroup_cnt == 1) {
+ chnlgroup = 0;
+ } else {
+ if (channel < 3)
+ chnlgroup = 0;
+ else if (channel < 6)
+ chnlgroup = 1;
+ else if (channel < 9)
+ chnlgroup = 2;
+ else if (channel < 12)
+ chnlgroup = 3;
+ else if (channel < 14)
+ chnlgroup = 4;
+ else if (channel == 14)
+ chnlgroup = 5;
+ }
+ writeval = rtlphy->mcs_offset[chnlgroup]
+ [index + (rf ? 8 : 0)] + ((index < 2) ?
+ powerbase0[rf] :
+ powerbase1[rf]);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Realtek regulatory, 20MHz, "
+ "writeval(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeval);
+
+ break;
+ case 2:
+ writeval =
+ ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Better regulatory, "
+ "writeval(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeval);
+ break;
+ case 3:
+ chnlgroup = 0;
+
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "customer's limit, 40MHz "
+ "rf(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'),
+ rtlefuse->pwrgroup_ht40[rf]
+ [channel-1]);
+ } else {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "customer's limit, 20MHz "
+ "rf(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'),
+ rtlefuse->pwrgroup_ht20[rf]
+ [channel-1]);
+ }
+
+ if (index < 2)
+ pwr_diff =
+ rtlefuse->txpwr_legacyhtdiff[rf][channel-1];
+ else if (rtlphy->current_chan_bw ==
+ HT_CHANNEL_WIDTH_20)
+ pwr_diff =
+ rtlefuse->txpwr_ht20diff[rf][channel-1];
+
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40)
+ customer_pwr_diff =
+ rtlefuse->pwrgroup_ht40[rf][channel-1];
+ else
+ customer_pwr_diff =
+ rtlefuse->pwrgroup_ht20[rf][channel-1];
+
+ if (pwr_diff > customer_pwr_diff)
+ pwr_diff = 0;
+ else
+ pwr_diff = customer_pwr_diff - pwr_diff;
+
+ for (i = 0; i < 4; i++) {
+ pwr_diff_limit[i] =
+ (u8)((rtlphy->mcs_offset
+ [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]);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Customer's limit rf(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), customer_limit);
+
+ writeval = customer_limit + ((index < 2) ?
+ powerbase0[rf] :
+ powerbase1[rf]);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Customer, writeval rf(%c)= 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeval);
+ break;
+ default:
+ chnlgroup = 0;
+ writeval =
+ rtlphy->mcs_offset[chnlgroup]
+ [index + (rf ? 8 : 0)]
+ + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "RTK better performance, writeval "
+ "rf(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeval);
+ break;
+ }
+
+ if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1)
+ writeval = writeval - 0x06060606;
+ else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
+ TXHIGHPWRLEVEL_BT2)
+ writeval = writeval - 0x0c0c0c0c;
+ *(p_outwriteval + rf) = writeval;
+ }
+}
+
+static void _rtl8723be_write_ofdm_power_reg(struct ieee80211_hw *hw,
+ u8 index, u32 *value)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ 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 = value[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];
+ rtl_set_bbreg(hw, regoffset, MASKDWORD, writeval);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Set 0x%x = %08x\n", regoffset, writeval);
+ }
+}
+
+void rtl8723be_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
+ u8 *ppowerlevel_ofdm,
+ u8 *ppowerlevel_bw20,
+ u8 *ppowerlevel_bw40, u8 channel)
+{
+ u32 writeval[2], powerbase0[2], powerbase1[2];
+ u8 index;
+ u8 direction;
+ u32 pwrtrac_value;
+
+ rtl8723be_phy_get_power_base(hw, ppowerlevel_ofdm, ppowerlevel_bw20,
+ ppowerlevel_bw40, channel,
+ &powerbase0[0], &powerbase1[0]);
+
+ rtl8723be_dm_txpower_track_adjust(hw, 1, &direction, &pwrtrac_value);
+
+ for (index = 0; index < 6; index++) {
+ txpwr_by_regulatory(hw, 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;
+ }
+ _rtl8723be_write_ofdm_power_reg(hw, index, &writeval[0]);
+ }
+}
+
+bool rtl8723be_phy_rf6052_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ if (rtlphy->rf_type == RF_1T1R)
+ rtlphy->num_total_rfpath = 1;
+ else
+ rtlphy->num_total_rfpath = 2;
+
+ return _rtl8723be_phy_rf6052_config_parafile(hw);
+}
+
+static bool _rtl8723be_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct bb_reg_def *pphyreg;
+ u32 u4_regvalue = 0;
+ u8 rfpath;
+ bool rtstatus = true;
+
+ for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
+ pphyreg = &rtlphy->phyreg_def[rfpath];
+
+ switch (rfpath) {
+ case RF90_PATH_A:
+ case RF90_PATH_C:
+ u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs,
+ BRFSI_RFENV);
+ break;
+ case RF90_PATH_B:
+ case RF90_PATH_D:
+ u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs,
+ BRFSI_RFENV << 16);
+ break;
+ }
+
+ rtl_set_bbreg(hw, pphyreg->rfintfe, BRFSI_RFENV << 16, 0x1);
+ udelay(1);
+
+ rtl_set_bbreg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1);
+ udelay(1);
+
+ rtl_set_bbreg(hw, pphyreg->rfhssi_para2,
+ B3WIREADDREAALENGTH, 0x0);
+ udelay(1);
+
+ rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREDATALENGTH, 0x0);
+ udelay(1);
+
+ switch (rfpath) {
+ case RF90_PATH_A:
+ rtstatus = rtl8723be_phy_config_rf_with_headerfile(hw,
+ (enum radio_path)rfpath);
+ break;
+ case RF90_PATH_B:
+ rtstatus = rtl8723be_phy_config_rf_with_headerfile(hw,
+ (enum radio_path)rfpath);
+ break;
+ case RF90_PATH_C:
+ break;
+ case RF90_PATH_D:
+ break;
+ }
+
+ switch (rfpath) {
+ case RF90_PATH_A:
+ case RF90_PATH_C:
+ rtl_set_bbreg(hw, pphyreg->rfintfs,
+ BRFSI_RFENV, u4_regvalue);
+ break;
+ case RF90_PATH_B:
+ case RF90_PATH_D:
+ rtl_set_bbreg(hw, pphyreg->rfintfs,
+ BRFSI_RFENV << 16, u4_regvalue);
+ break;
+ }
+
+ if (!rtstatus) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Radio[%d] Fail!!", rfpath);
+ return false;
+ }
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "\n");
+ return rtstatus;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/rf.h b/drivers/net/wireless/rtlwifi/rtl8723be/rf.h
new file mode 100644
index 000000000000..a6fea106ced4
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/rf.h
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_RF_H__
+#define __RTL8723BE_RF_H__
+
+#define RF6052_MAX_TX_PWR 0x3F
+#define RF6052_MAX_REG 0x3F
+
+void rtl8723be_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw,
+ u8 bandwidth);
+void rtl8723be_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
+ u8 *ppowerlevel);
+void rtl8723be_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
+ u8 *ppowerlevel_ofdm,
+ u8 *ppowerlevel_bw20,
+ u8 *ppowerlevel_bw40,
+ u8 channel);
+bool rtl8723be_phy_rf6052_config(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c
new file mode 100644
index 000000000000..b4577ebc4bb0
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c
@@ -0,0 +1,384 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../core.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "../rtl8723com/phy_common.h"
+#include "dm.h"
+#include "hw.h"
+#include "fw.h"
+#include "../rtl8723com/fw_common.h"
+#include "sw.h"
+#include "trx.h"
+#include "led.h"
+#include "table.h"
+#include "../btcoexist/rtl_btc.h"
+
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+
+static void rtl8723be_init_aspm_vars(struct ieee80211_hw *hw)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ /*close ASPM for AMD defaultly */
+ rtlpci->const_amdpci_aspm = 0;
+
+ /* ASPM PS mode.
+ * 0 - Disable ASPM,
+ * 1 - Enable ASPM without Clock Req,
+ * 2 - Enable ASPM with Clock Req,
+ * 3 - Alwyas Enable ASPM with Clock Req,
+ * 4 - Always Enable ASPM without Clock Req.
+ * set defult to RTL8192CE:3 RTL8192E:2
+ */
+ rtlpci->const_pci_aspm = 3;
+
+ /*Setting for PCI-E device */
+ rtlpci->const_devicepci_aspm_setting = 0x03;
+
+ /*Setting for PCI-E bridge */
+ rtlpci->const_hostpci_aspm_setting = 0x02;
+
+ /* In Hw/Sw Radio Off situation.
+ * 0 - Default,
+ * 1 - From ASPM setting without low Mac Pwr,
+ * 2 - From ASPM setting with low Mac Pwr,
+ * 3 - Bus D3
+ * set default to RTL8192CE:0 RTL8192SE:2
+ */
+ rtlpci->const_hwsw_rfoff_d3 = 0;
+
+ /* This setting works for those device with
+ * backdoor ASPM setting such as EPHY setting.
+ * 0 - Not support ASPM,
+ * 1 - Support ASPM,
+ * 2 - According to chipset.
+ */
+ rtlpci->const_support_pciaspm = 1;
+}
+
+int rtl8723be_init_sw_vars(struct ieee80211_hw *hw)
+{
+ int err = 0;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+ rtl8723be_bt_reg_init(hw);
+ rtlpci->msi_support = true;
+ rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer();
+
+ rtlpriv->dm.dm_initialgain_enable = 1;
+ rtlpriv->dm.dm_flag = 0;
+ rtlpriv->dm.disable_framebursting = 0;
+ rtlpriv->dm.thermalvalue = 0;
+ rtlpci->transmit_config = CFENDFORM | BIT(15) | BIT(24) | BIT(25);
+
+ mac->ht_enable = true;
+
+ /* compatible 5G band 88ce just 2.4G band & smsp */
+ rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G;
+ rtlpriv->rtlhal.bandset = BAND_ON_2_4G;
+ rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY;
+
+ rtlpci->receive_config = (RCR_APPFCS |
+ RCR_APP_MIC |
+ RCR_APP_ICV |
+ RCR_APP_PHYST_RXFF |
+ RCR_HTC_LOC_CTRL |
+ RCR_AMF |
+ RCR_ACF |
+ RCR_ADF |
+ RCR_AICV |
+ RCR_AB |
+ RCR_AM |
+ RCR_APM |
+ 0);
+
+ rtlpci->irq_mask[0] = (u32) (IMR_PSTIMEOUT |
+ IMR_HSISR_IND_ON_INT |
+ IMR_C2HCMD |
+ IMR_HIGHDOK |
+ IMR_MGNTDOK |
+ IMR_BKDOK |
+ IMR_BEDOK |
+ IMR_VIDOK |
+ IMR_VODOK |
+ IMR_RDU |
+ IMR_ROK |
+ 0);
+
+ rtlpci->irq_mask[1] = (u32)(IMR_RXFOVW | 0);
+
+ /* for debug level */
+ rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug;
+ /* for LPS & IPS */
+ rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
+ rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
+ rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+ rtlpriv->psc.reg_fwctrl_lps = 3;
+ rtlpriv->psc.reg_max_lps_awakeintvl = 5;
+ /* for ASPM, you can close aspm through
+ * set const_support_pciaspm = 0
+ */
+ rtl8723be_init_aspm_vars(hw);
+
+ if (rtlpriv->psc.reg_fwctrl_lps == 1)
+ rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE;
+ else if (rtlpriv->psc.reg_fwctrl_lps == 2)
+ rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE;
+ else if (rtlpriv->psc.reg_fwctrl_lps == 3)
+ rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE;
+
+ /* for firmware buf */
+ rtlpriv->rtlhal.pfirmware = vzalloc(0x8000);
+ if (!rtlpriv->rtlhal.pfirmware) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Can't alloc buffer for fw.\n");
+ return 1;
+ }
+
+ rtlpriv->max_fw_size = 0x8000;
+ pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name);
+ err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
+ rtlpriv->io.dev, GFP_KERNEL, hw,
+ rtl_fw_cb);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Failed to request firmware!\n");
+ return 1;
+ }
+ return 0;
+}
+
+void rtl8723be_deinit_sw_vars(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->cfg->ops->get_btc_status())
+ rtlpriv->btcoexist.btc_ops->btc_halt_notify();
+ if (rtlpriv->rtlhal.pfirmware) {
+ vfree(rtlpriv->rtlhal.pfirmware);
+ rtlpriv->rtlhal.pfirmware = NULL;
+ }
+}
+
+/* get bt coexist status */
+bool rtl8723be_get_btc_status(void)
+{
+ return true;
+}
+
+static bool is_fw_header(struct rtl92c_firmware_header *hdr)
+{
+ return (hdr->signature & 0xfff0) == 0x5300;
+}
+
+static struct rtl_hal_ops rtl8723be_hal_ops = {
+ .init_sw_vars = rtl8723be_init_sw_vars,
+ .deinit_sw_vars = rtl8723be_deinit_sw_vars,
+ .read_eeprom_info = rtl8723be_read_eeprom_info,
+ .interrupt_recognized = rtl8723be_interrupt_recognized,
+ .hw_init = rtl8723be_hw_init,
+ .hw_disable = rtl8723be_card_disable,
+ .hw_suspend = rtl8723be_suspend,
+ .hw_resume = rtl8723be_resume,
+ .enable_interrupt = rtl8723be_enable_interrupt,
+ .disable_interrupt = rtl8723be_disable_interrupt,
+ .set_network_type = rtl8723be_set_network_type,
+ .set_chk_bssid = rtl8723be_set_check_bssid,
+ .set_qos = rtl8723be_set_qos,
+ .set_bcn_reg = rtl8723be_set_beacon_related_registers,
+ .set_bcn_intv = rtl8723be_set_beacon_interval,
+ .update_interrupt_mask = rtl8723be_update_interrupt_mask,
+ .get_hw_reg = rtl8723be_get_hw_reg,
+ .set_hw_reg = rtl8723be_set_hw_reg,
+ .update_rate_tbl = rtl8723be_update_hal_rate_tbl,
+ .fill_tx_desc = rtl8723be_tx_fill_desc,
+ .fill_tx_cmddesc = rtl8723be_tx_fill_cmddesc,
+ .query_rx_desc = rtl8723be_rx_query_desc,
+ .set_channel_access = rtl8723be_update_channel_access_setting,
+ .radio_onoff_checking = rtl8723be_gpio_radio_on_off_checking,
+ .set_bw_mode = rtl8723be_phy_set_bw_mode,
+ .switch_channel = rtl8723be_phy_sw_chnl,
+ .dm_watchdog = rtl8723be_dm_watchdog,
+ .scan_operation_backup = rtl8723be_phy_scan_operation_backup,
+ .set_rf_power_state = rtl8723be_phy_set_rf_power_state,
+ .led_control = rtl8723be_led_control,
+ .set_desc = rtl8723be_set_desc,
+ .get_desc = rtl8723be_get_desc,
+ .is_tx_desc_closed = rtl8723be_is_tx_desc_closed,
+ .tx_polling = rtl8723be_tx_polling,
+ .enable_hw_sec = rtl8723be_enable_hw_security_config,
+ .set_key = rtl8723be_set_key,
+ .init_sw_leds = rtl8723be_init_sw_leds,
+ .get_bbreg = rtl8723_phy_query_bb_reg,
+ .set_bbreg = rtl8723_phy_set_bb_reg,
+ .get_rfreg = rtl8723be_phy_query_rf_reg,
+ .set_rfreg = rtl8723be_phy_set_rf_reg,
+ .fill_h2c_cmd = rtl8723be_fill_h2c_cmd,
+ .get_btc_status = rtl8723be_get_btc_status,
+ .is_fw_header = is_fw_header,
+};
+
+static struct rtl_mod_params rtl8723be_mod_params = {
+ .sw_crypto = false,
+ .inactiveps = true,
+ .swctrl_lps = false,
+ .fwctrl_lps = true,
+ .debug = DBG_EMERG,
+};
+
+static struct rtl_hal_cfg rtl8723be_hal_cfg = {
+ .bar_id = 2,
+ .write_readback = true,
+ .name = "rtl8723be_pci",
+ .fw_name = "rtlwifi/rtl8723befw.bin",
+ .ops = &rtl8723be_hal_ops,
+ .mod_params = &rtl8723be_mod_params,
+ .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL,
+ .maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN,
+ .maps[SYS_CLK] = REG_SYS_CLKR,
+ .maps[MAC_RCR_AM] = AM,
+ .maps[MAC_RCR_AB] = AB,
+ .maps[MAC_RCR_ACRC32] = ACRC32,
+ .maps[MAC_RCR_ACF] = ACF,
+ .maps[MAC_RCR_AAP] = AAP,
+
+ .maps[EFUSE_ACCESS] = REG_EFUSE_ACCESS,
+
+ .maps[EFUSE_TEST] = REG_EFUSE_TEST,
+ .maps[EFUSE_CTRL] = REG_EFUSE_CTRL,
+ .maps[EFUSE_CLK] = 0,
+ .maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL,
+ .maps[EFUSE_PWC_EV12V] = PWC_EV12V,
+ .maps[EFUSE_FEN_ELDR] = FEN_ELDR,
+ .maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN,
+ .maps[EFUSE_ANA8M] = ANA8M,
+ .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE,
+ .maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION,
+ .maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN,
+ .maps[EFUSE_OOB_PROTECT_BYTES_LEN] = EFUSE_OOB_PROTECT_BYTES,
+
+ .maps[RWCAM] = REG_CAMCMD,
+ .maps[WCAMI] = REG_CAMWRITE,
+ .maps[RCAMO] = REG_CAMREAD,
+ .maps[CAMDBG] = REG_CAMDBG,
+ .maps[SECR] = REG_SECCFG,
+ .maps[SEC_CAM_NONE] = CAM_NONE,
+ .maps[SEC_CAM_WEP40] = CAM_WEP40,
+ .maps[SEC_CAM_TKIP] = CAM_TKIP,
+ .maps[SEC_CAM_AES] = CAM_AES,
+ .maps[SEC_CAM_WEP104] = CAM_WEP104,
+
+ .maps[RTL_IMR_BCNDMAINT6] = IMR_BCNDMAINT6,
+ .maps[RTL_IMR_BCNDMAINT5] = IMR_BCNDMAINT5,
+ .maps[RTL_IMR_BCNDMAINT4] = IMR_BCNDMAINT4,
+ .maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3,
+ .maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2,
+ .maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1,
+ .maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7,
+ .maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6,
+ .maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5,
+ .maps[RTL_IMR_BCNDOK4] = IMR_BCNDOK4,
+ .maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3,
+ .maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2,
+ .maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1,
+
+ .maps[RTL_IMR_TXFOVW] = IMR_TXFOVW,
+ .maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT,
+ .maps[RTL_IMR_BCNINT] = IMR_BCNDMAINT0,
+ .maps[RTL_IMR_RXFOVW] = IMR_RXFOVW,
+ .maps[RTL_IMR_RDU] = IMR_RDU,
+ .maps[RTL_IMR_ATIMEND] = IMR_ATIMEND,
+ .maps[RTL_IMR_BDOK] = IMR_BCNDOK0,
+ .maps[RTL_IMR_MGNTDOK] = IMR_MGNTDOK,
+ .maps[RTL_IMR_TBDER] = IMR_TBDER,
+ .maps[RTL_IMR_HIGHDOK] = IMR_HIGHDOK,
+ .maps[RTL_IMR_TBDOK] = IMR_TBDOK,
+ .maps[RTL_IMR_BKDOK] = IMR_BKDOK,
+ .maps[RTL_IMR_BEDOK] = IMR_BEDOK,
+ .maps[RTL_IMR_VIDOK] = IMR_VIDOK,
+ .maps[RTL_IMR_VODOK] = IMR_VODOK,
+ .maps[RTL_IMR_ROK] = IMR_ROK,
+ .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNDMAINT0 | IMR_TBDOK | IMR_TBDER),
+
+ .maps[RTL_RC_CCK_RATE1M] = DESC92C_RATE1M,
+ .maps[RTL_RC_CCK_RATE2M] = DESC92C_RATE2M,
+ .maps[RTL_RC_CCK_RATE5_5M] = DESC92C_RATE5_5M,
+ .maps[RTL_RC_CCK_RATE11M] = DESC92C_RATE11M,
+ .maps[RTL_RC_OFDM_RATE6M] = DESC92C_RATE6M,
+ .maps[RTL_RC_OFDM_RATE9M] = DESC92C_RATE9M,
+ .maps[RTL_RC_OFDM_RATE12M] = DESC92C_RATE12M,
+ .maps[RTL_RC_OFDM_RATE18M] = DESC92C_RATE18M,
+ .maps[RTL_RC_OFDM_RATE24M] = DESC92C_RATE24M,
+ .maps[RTL_RC_OFDM_RATE36M] = DESC92C_RATE36M,
+ .maps[RTL_RC_OFDM_RATE48M] = DESC92C_RATE48M,
+ .maps[RTL_RC_OFDM_RATE54M] = DESC92C_RATE54M,
+
+ .maps[RTL_RC_HT_RATEMCS7] = DESC92C_RATEMCS7,
+ .maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(rtl8723be_pci_id) = {
+ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xb723, rtl8723be_hal_cfg)},
+ {},
+};
+
+MODULE_DEVICE_TABLE(pci, rtl8723be_pci_id);
+
+MODULE_AUTHOR("PageHe <page_he@realsil.com.cn>");
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek 8723BE 802.11n PCI wireless");
+MODULE_FIRMWARE("rtlwifi/rtl8723befw.bin");
+
+module_param_named(swenc, rtl8723be_mod_params.sw_crypto, bool, 0444);
+module_param_named(debug, rtl8723be_mod_params.debug, int, 0444);
+module_param_named(ips, rtl8723be_mod_params.inactiveps, bool, 0444);
+module_param_named(swlps, rtl8723be_mod_params.swctrl_lps, bool, 0444);
+module_param_named(fwlps, rtl8723be_mod_params.fwctrl_lps, bool, 0444);
+MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n");
+MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n");
+MODULE_PARM_DESC(fwlps, "using linked fw control power save (default 1 is open)\n");
+MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
+
+static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume);
+
+static struct pci_driver rtl8723be_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = rtl8723be_pci_id,
+ .probe = rtl_pci_probe,
+ .remove = rtl_pci_disconnect,
+
+ .driver.pm = &rtlwifi_pm_ops,
+};
+
+module_pci_driver(rtl8723be_driver);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/sw.h b/drivers/net/wireless/rtlwifi/rtl8723be/sw.h
new file mode 100644
index 000000000000..a7b25e769950
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/sw.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_SW_H__
+#define __RTL8723BE_SW_H__
+
+int rtl8723be_init_sw_vars(struct ieee80211_hw *hw);
+void rtl8723be_deinit_sw_vars(struct ieee80211_hw *hw);
+void rtl8723be_init_var_map(struct ieee80211_hw *hw);
+bool rtl8723be_get_btc_status(void);
+
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/table.c b/drivers/net/wireless/rtlwifi/rtl8723be/table.c
new file mode 100644
index 000000000000..4b283cde042e
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/table.c
@@ -0,0 +1,572 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Created on 2010/ 5/18, 1:41
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "table.h"
+u32 RTL8723BEPHY_REG_1TARRAY[] = {
+ 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,
+ 0x948, 0x00000000,
+ 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, 0x21806490,
+ 0xB2C, 0x00000000,
+ 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, 0x69E9AC44,
+ 0xC34, 0x469652AF,
+ 0xC38, 0x49795994,
+ 0xC3C, 0x0A97971C,
+ 0xC40, 0x1F7C403F,
+ 0xC44, 0x000100B7,
+ 0xC48, 0xEC020107,
+ 0xC4C, 0x007F037F,
+ 0xC50, 0x69553420,
+ 0xC54, 0x43BC0094,
+ 0xC58, 0x00023169,
+ 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, 0x00020E1A,
+ 0xC94, 0x00000000,
+ 0xC98, 0x00020E1A,
+ 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, 0x40020401,
+ 0xD08, 0x0000907F,
+ 0xD0C, 0x20010201,
+ 0xD10, 0xA0633333,
+ 0xD14, 0x3333BC53,
+ 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, 0x001B2556,
+ 0xE6C, 0x00C00096,
+ 0xE70, 0x00C00096,
+ 0xE74, 0x01000056,
+ 0xE78, 0x01000014,
+ 0xE7C, 0x01000056,
+ 0xE80, 0x01000014,
+ 0xE84, 0x00C00096,
+ 0xE88, 0x01000056,
+ 0xE8C, 0x00C00096,
+ 0xED0, 0x00C00096,
+ 0xED4, 0x00C00096,
+ 0xED8, 0x00C00096,
+ 0xEDC, 0x000000D6,
+ 0xEE0, 0x000000D6,
+ 0xEEC, 0x01C00016,
+ 0xF14, 0x00000003,
+ 0xF4C, 0x00000000,
+ 0xF00, 0x00000300,
+ 0x820, 0x01000100,
+ 0x800, 0x83040000,
+};
+
+u32 RTL8723BEPHY_REG_ARRAY_PG[] = {
+ 0, 0, 0, 0x00000e08, 0x0000ff00, 0x00004000,
+ 0, 0, 0, 0x0000086c, 0xffffff00, 0x34363800,
+ 0, 0, 0, 0x00000e00, 0xffffffff, 0x42444646,
+ 0, 0, 0, 0x00000e04, 0xffffffff, 0x30343840,
+ 0, 0, 0, 0x00000e10, 0xffffffff, 0x38404244,
+ 0, 0, 0, 0x00000e14, 0xffffffff, 0x26303436
+};
+
+u32 RTL8723BE_RADIOA_1TARRAY[] = {
+ 0x000, 0x00010000,
+ 0x0B0, 0x000DFFE0,
+ 0x0FE, 0x00000000,
+ 0x0FE, 0x00000000,
+ 0x0FE, 0x00000000,
+ 0x0B1, 0x00000018,
+ 0x0FE, 0x00000000,
+ 0x0FE, 0x00000000,
+ 0x0FE, 0x00000000,
+ 0x0B2, 0x00084C00,
+ 0x0B5, 0x0000D2CC,
+ 0x0B6, 0x000925AA,
+ 0x0B7, 0x00000010,
+ 0x0B8, 0x0000907F,
+ 0x05C, 0x00000002,
+ 0x07C, 0x00000002,
+ 0x07E, 0x00000005,
+ 0x08B, 0x0006FC00,
+ 0x0B0, 0x000FF9F0,
+ 0x01C, 0x000739D2,
+ 0x01E, 0x00000000,
+ 0x0DF, 0x00000780,
+ 0x050, 0x00067435,
+ 0x051, 0x0006B04E,
+ 0x052, 0x000007D2,
+ 0x053, 0x00000000,
+ 0x054, 0x00050400,
+ 0x055, 0x0004026E,
+ 0x0DD, 0x0000004C,
+ 0x070, 0x00067435,
+ 0x071, 0x0006B04E,
+ 0x072, 0x000007D2,
+ 0x073, 0x00000000,
+ 0x074, 0x00050400,
+ 0x075, 0x0004026E,
+ 0x0EF, 0x00000100,
+ 0x034, 0x0000ADD7,
+ 0x035, 0x00005C00,
+ 0x034, 0x00009DD4,
+ 0x035, 0x00005000,
+ 0x034, 0x00008DD1,
+ 0x035, 0x00004400,
+ 0x034, 0x00007DCE,
+ 0x035, 0x00003800,
+ 0x034, 0x00006CD1,
+ 0x035, 0x00004400,
+ 0x034, 0x00005CCE,
+ 0x035, 0x00003800,
+ 0x034, 0x000048CE,
+ 0x035, 0x00004400,
+ 0x034, 0x000034CE,
+ 0x035, 0x00003800,
+ 0x034, 0x00002451,
+ 0x035, 0x00004400,
+ 0x034, 0x0000144E,
+ 0x035, 0x00003800,
+ 0x034, 0x00000051,
+ 0x035, 0x00004400,
+ 0x0EF, 0x00000000,
+ 0x0EF, 0x00000100,
+ 0x0ED, 0x00000010,
+ 0x044, 0x0000ADD7,
+ 0x044, 0x00009DD4,
+ 0x044, 0x00008DD1,
+ 0x044, 0x00007DCE,
+ 0x044, 0x00006CC1,
+ 0x044, 0x00005CCE,
+ 0x044, 0x000044D1,
+ 0x044, 0x000034CE,
+ 0x044, 0x00002451,
+ 0x044, 0x0000144E,
+ 0x044, 0x00000051,
+ 0x0EF, 0x00000000,
+ 0x0ED, 0x00000000,
+ 0x0EF, 0x00002000,
+ 0x03B, 0x000380EF,
+ 0x03B, 0x000302FE,
+ 0x03B, 0x00028CE6,
+ 0x03B, 0x000200BC,
+ 0x03B, 0x000188A5,
+ 0x03B, 0x00010FBC,
+ 0x03B, 0x00008F71,
+ 0x03B, 0x00000900,
+ 0x0EF, 0x00000000,
+ 0x0ED, 0x00000001,
+ 0x040, 0x000380EF,
+ 0x040, 0x000302FE,
+ 0x040, 0x00028CE6,
+ 0x040, 0x000200BC,
+ 0x040, 0x000188A5,
+ 0x040, 0x00010FBC,
+ 0x040, 0x00008F71,
+ 0x040, 0x00000900,
+ 0x0ED, 0x00000000,
+ 0x082, 0x00080000,
+ 0x083, 0x00008000,
+ 0x084, 0x00048D80,
+ 0x085, 0x00068000,
+ 0x0A2, 0x00080000,
+ 0x0A3, 0x00008000,
+ 0x0A4, 0x00048D80,
+ 0x0A5, 0x00068000,
+ 0x000, 0x00033D80,
+};
+
+u32 RTL8723BEMAC_1T_ARRAY[] = {
+ 0x02F, 0x00000030,
+ 0x035, 0x00000000,
+ 0x428, 0x0000000A,
+ 0x429, 0x00000010,
+ 0x430, 0x00000000,
+ 0x431, 0x00000000,
+ 0x432, 0x00000000,
+ 0x433, 0x00000001,
+ 0x434, 0x00000004,
+ 0x435, 0x00000005,
+ 0x436, 0x00000007,
+ 0x437, 0x00000008,
+ 0x43C, 0x00000004,
+ 0x43D, 0x00000005,
+ 0x43E, 0x00000007,
+ 0x43F, 0x00000008,
+ 0x440, 0x0000005D,
+ 0x441, 0x00000001,
+ 0x442, 0x00000000,
+ 0x444, 0x00000010,
+ 0x445, 0x00000000,
+ 0x446, 0x00000000,
+ 0x447, 0x00000000,
+ 0x448, 0x00000000,
+ 0x449, 0x000000F0,
+ 0x44A, 0x0000000F,
+ 0x44B, 0x0000003E,
+ 0x44C, 0x00000010,
+ 0x44D, 0x00000000,
+ 0x44E, 0x00000000,
+ 0x44F, 0x00000000,
+ 0x450, 0x00000000,
+ 0x451, 0x000000F0,
+ 0x452, 0x0000000F,
+ 0x453, 0x00000000,
+ 0x456, 0x0000005E,
+ 0x460, 0x00000066,
+ 0x461, 0x00000066,
+ 0x4C8, 0x000000FF,
+ 0x4C9, 0x00000008,
+ 0x4CC, 0x000000FF,
+ 0x4CD, 0x000000FF,
+ 0x4CE, 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,
+ 0x55C, 0x00000050,
+ 0x55D, 0x000000FF,
+ 0x605, 0x00000030,
+ 0x608, 0x0000000E,
+ 0x609, 0x0000002A,
+ 0x620, 0x000000FF,
+ 0x621, 0x000000FF,
+ 0x622, 0x000000FF,
+ 0x623, 0x000000FF,
+ 0x624, 0x000000FF,
+ 0x625, 0x000000FF,
+ 0x626, 0x000000FF,
+ 0x627, 0x000000FF,
+ 0x638, 0x00000050,
+ 0x63C, 0x0000000A,
+ 0x63D, 0x0000000A,
+ 0x63E, 0x0000000E,
+ 0x63F, 0x0000000E,
+ 0x640, 0x00000040,
+ 0x642, 0x00000040,
+ 0x643, 0x00000000,
+ 0x652, 0x000000C8,
+ 0x66E, 0x00000005,
+ 0x700, 0x00000021,
+ 0x701, 0x00000043,
+ 0x702, 0x00000065,
+ 0x703, 0x00000087,
+ 0x708, 0x00000021,
+ 0x709, 0x00000043,
+ 0x70A, 0x00000065,
+ 0x70B, 0x00000087,
+};
+
+u32 RTL8723BEAGCTAB_1TARRAY[] = {
+ 0xC78, 0xFD000001,
+ 0xC78, 0xFC010001,
+ 0xC78, 0xFB020001,
+ 0xC78, 0xFA030001,
+ 0xC78, 0xF9040001,
+ 0xC78, 0xF8050001,
+ 0xC78, 0xF7060001,
+ 0xC78, 0xF6070001,
+ 0xC78, 0xF5080001,
+ 0xC78, 0xF4090001,
+ 0xC78, 0xF30A0001,
+ 0xC78, 0xF20B0001,
+ 0xC78, 0xF10C0001,
+ 0xC78, 0xF00D0001,
+ 0xC78, 0xEF0E0001,
+ 0xC78, 0xEE0F0001,
+ 0xC78, 0xED100001,
+ 0xC78, 0xEC110001,
+ 0xC78, 0xEB120001,
+ 0xC78, 0xEA130001,
+ 0xC78, 0xE9140001,
+ 0xC78, 0xE8150001,
+ 0xC78, 0xE7160001,
+ 0xC78, 0xAA170001,
+ 0xC78, 0xA9180001,
+ 0xC78, 0xA8190001,
+ 0xC78, 0xA71A0001,
+ 0xC78, 0xA61B0001,
+ 0xC78, 0xA51C0001,
+ 0xC78, 0xA41D0001,
+ 0xC78, 0xA31E0001,
+ 0xC78, 0x671F0001,
+ 0xC78, 0x66200001,
+ 0xC78, 0x65210001,
+ 0xC78, 0x64220001,
+ 0xC78, 0x63230001,
+ 0xC78, 0x62240001,
+ 0xC78, 0x61250001,
+ 0xC78, 0x47260001,
+ 0xC78, 0x46270001,
+ 0xC78, 0x45280001,
+ 0xC78, 0x44290001,
+ 0xC78, 0x432A0001,
+ 0xC78, 0x422B0001,
+ 0xC78, 0x292C0001,
+ 0xC78, 0x282D0001,
+ 0xC78, 0x272E0001,
+ 0xC78, 0x262F0001,
+ 0xC78, 0x25300001,
+ 0xC78, 0x24310001,
+ 0xC78, 0x09320001,
+ 0xC78, 0x08330001,
+ 0xC78, 0x07340001,
+ 0xC78, 0x06350001,
+ 0xC78, 0x05360001,
+ 0xC78, 0x04370001,
+ 0xC78, 0x03380001,
+ 0xC78, 0x02390001,
+ 0xC78, 0x013A0001,
+ 0xC78, 0x003B0001,
+ 0xC78, 0x003C0001,
+ 0xC78, 0x003D0001,
+ 0xC78, 0x003E0001,
+ 0xC78, 0x003F0001,
+ 0xC78, 0xFC400001,
+ 0xC78, 0xFB410001,
+ 0xC78, 0xFA420001,
+ 0xC78, 0xF9430001,
+ 0xC78, 0xF8440001,
+ 0xC78, 0xF7450001,
+ 0xC78, 0xF6460001,
+ 0xC78, 0xF5470001,
+ 0xC78, 0xF4480001,
+ 0xC78, 0xF3490001,
+ 0xC78, 0xF24A0001,
+ 0xC78, 0xF14B0001,
+ 0xC78, 0xF04C0001,
+ 0xC78, 0xEF4D0001,
+ 0xC78, 0xEE4E0001,
+ 0xC78, 0xED4F0001,
+ 0xC78, 0xEC500001,
+ 0xC78, 0xEB510001,
+ 0xC78, 0xEA520001,
+ 0xC78, 0xE9530001,
+ 0xC78, 0xE8540001,
+ 0xC78, 0xE7550001,
+ 0xC78, 0xE6560001,
+ 0xC78, 0xE5570001,
+ 0xC78, 0xAA580001,
+ 0xC78, 0xA9590001,
+ 0xC78, 0xA85A0001,
+ 0xC78, 0xA75B0001,
+ 0xC78, 0xA65C0001,
+ 0xC78, 0xA55D0001,
+ 0xC78, 0xA45E0001,
+ 0xC78, 0x675F0001,
+ 0xC78, 0x66600001,
+ 0xC78, 0x65610001,
+ 0xC78, 0x64620001,
+ 0xC78, 0x63630001,
+ 0xC78, 0x62640001,
+ 0xC78, 0x61650001,
+ 0xC78, 0x47660001,
+ 0xC78, 0x46670001,
+ 0xC78, 0x45680001,
+ 0xC78, 0x44690001,
+ 0xC78, 0x436A0001,
+ 0xC78, 0x426B0001,
+ 0xC78, 0x296C0001,
+ 0xC78, 0x286D0001,
+ 0xC78, 0x276E0001,
+ 0xC78, 0x266F0001,
+ 0xC78, 0x25700001,
+ 0xC78, 0x24710001,
+ 0xC78, 0x09720001,
+ 0xC78, 0x08730001,
+ 0xC78, 0x07740001,
+ 0xC78, 0x06750001,
+ 0xC78, 0x05760001,
+ 0xC78, 0x04770001,
+ 0xC78, 0x03780001,
+ 0xC78, 0x02790001,
+ 0xC78, 0x017A0001,
+ 0xC78, 0x007B0001,
+ 0xC78, 0x007C0001,
+ 0xC78, 0x007D0001,
+ 0xC78, 0x007E0001,
+ 0xC78, 0x007F0001,
+ 0xC50, 0x69553422,
+ 0xC50, 0x69553420,
+};
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/table.h b/drivers/net/wireless/rtlwifi/rtl8723be/table.h
new file mode 100644
index 000000000000..932760a84827
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/table.h
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Created on 2010/ 5/18, 1:41
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_TABLE__H_
+#define __RTL8723BE_TABLE__H_
+
+#include <linux/types.h>
+#define RTL8723BEPHY_REG_1TARRAYLEN 388
+extern u32 RTL8723BEPHY_REG_1TARRAY[];
+#define RTL8723BEPHY_REG_ARRAY_PGLEN 36
+extern u32 RTL8723BEPHY_REG_ARRAY_PG[];
+#define RTL8723BE_RADIOA_1TARRAYLEN 206
+extern u32 RTL8723BE_RADIOA_1TARRAY[];
+#define RTL8723BEMAC_1T_ARRAYLEN 194
+extern u32 RTL8723BEMAC_1T_ARRAY[];
+#define RTL8723BEAGCTAB_1TARRAYLEN 260
+extern u32 RTL8723BEAGCTAB_1TARRAY[];
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/trx.c b/drivers/net/wireless/rtlwifi/rtl8723be/trx.c
new file mode 100644
index 000000000000..e0a0d8c8fed5
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/trx.c
@@ -0,0 +1,960 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "../stats.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "trx.h"
+#include "led.h"
+#include "dm.h"
+#include "phy.h"
+
+static u8 _rtl8723be_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
+{
+ __le16 fc = rtl_get_fc(skb);
+
+ if (unlikely(ieee80211_is_beacon(fc)))
+ return QSLT_BEACON;
+ if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))
+ return QSLT_MGNT;
+
+ return skb->priority;
+}
+
+/* mac80211's rate_idx is like this:
+ *
+ * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ
+ *
+ * B/G rate:
+ * (rx_status->flag & RX_FLAG_HT) = 0,
+ * DESC92C_RATE1M-->DESC92C_RATE54M ==> idx is 0-->11,
+ *
+ * N rate:
+ * (rx_status->flag & RX_FLAG_HT) = 1,
+ * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15
+ *
+ * 5G band:rx_status->band == IEEE80211_BAND_5GHZ
+ * A rate:
+ * (rx_status->flag & RX_FLAG_HT) = 0,
+ * DESC92C_RATE6M-->DESC92C_RATE54M ==> idx is 0-->7,
+ *
+ * N rate:
+ * (rx_status->flag & RX_FLAG_HT) = 1,
+ * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15
+ */
+static int _rtl8723be_rate_mapping(struct ieee80211_hw *hw,
+ bool isht, u8 desc_rate)
+{
+ int rate_idx;
+
+ if (!isht) {
+ if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) {
+ switch (desc_rate) {
+ case DESC92C_RATE1M:
+ rate_idx = 0;
+ break;
+ case DESC92C_RATE2M:
+ rate_idx = 1;
+ break;
+ case DESC92C_RATE5_5M:
+ rate_idx = 2;
+ break;
+ case DESC92C_RATE11M:
+ rate_idx = 3;
+ break;
+ case DESC92C_RATE6M:
+ rate_idx = 4;
+ break;
+ case DESC92C_RATE9M:
+ rate_idx = 5;
+ break;
+ case DESC92C_RATE12M:
+ rate_idx = 6;
+ break;
+ case DESC92C_RATE18M:
+ rate_idx = 7;
+ break;
+ case DESC92C_RATE24M:
+ rate_idx = 8;
+ break;
+ case DESC92C_RATE36M:
+ rate_idx = 9;
+ break;
+ case DESC92C_RATE48M:
+ rate_idx = 10;
+ break;
+ case DESC92C_RATE54M:
+ rate_idx = 11;
+ break;
+ default:
+ rate_idx = 0;
+ break;
+ }
+ } else {
+ switch (desc_rate) {
+ case DESC92C_RATE6M:
+ rate_idx = 0;
+ break;
+ case DESC92C_RATE9M:
+ rate_idx = 1;
+ break;
+ case DESC92C_RATE12M:
+ rate_idx = 2;
+ break;
+ case DESC92C_RATE18M:
+ rate_idx = 3;
+ break;
+ case DESC92C_RATE24M:
+ rate_idx = 4;
+ break;
+ case DESC92C_RATE36M:
+ rate_idx = 5;
+ break;
+ case DESC92C_RATE48M:
+ rate_idx = 6;
+ break;
+ case DESC92C_RATE54M:
+ rate_idx = 7;
+ break;
+ default:
+ rate_idx = 0;
+ break;
+ }
+ }
+ } else {
+ switch (desc_rate) {
+ case DESC92C_RATEMCS0:
+ rate_idx = 0;
+ break;
+ case DESC92C_RATEMCS1:
+ rate_idx = 1;
+ break;
+ case DESC92C_RATEMCS2:
+ rate_idx = 2;
+ break;
+ case DESC92C_RATEMCS3:
+ rate_idx = 3;
+ break;
+ case DESC92C_RATEMCS4:
+ rate_idx = 4;
+ break;
+ case DESC92C_RATEMCS5:
+ rate_idx = 5;
+ break;
+ case DESC92C_RATEMCS6:
+ rate_idx = 6;
+ break;
+ case DESC92C_RATEMCS7:
+ rate_idx = 7;
+ break;
+ case DESC92C_RATEMCS8:
+ rate_idx = 8;
+ break;
+ case DESC92C_RATEMCS9:
+ rate_idx = 9;
+ break;
+ case DESC92C_RATEMCS10:
+ rate_idx = 10;
+ break;
+ case DESC92C_RATEMCS11:
+ rate_idx = 11;
+ break;
+ case DESC92C_RATEMCS12:
+ rate_idx = 12;
+ break;
+ case DESC92C_RATEMCS13:
+ rate_idx = 13;
+ break;
+ case DESC92C_RATEMCS14:
+ rate_idx = 14;
+ break;
+ case DESC92C_RATEMCS15:
+ rate_idx = 15;
+ break;
+ default:
+ rate_idx = 0;
+ break;
+ }
+ }
+ return rate_idx;
+}
+
+static void _rtl8723be_query_rxphystatus(struct ieee80211_hw *hw,
+ struct rtl_stats *pstatus, u8 *pdesc,
+ struct rx_fwinfo_8723be *p_drvinfo,
+ bool packet_match_bssid,
+ bool packet_toself,
+ bool packet_beacon)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
+ struct phy_sts_cck_8723e_t *cck_buf;
+ struct phy_status_rpt *p_phystrpt = (struct phy_status_rpt *)p_drvinfo;
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ char rx_pwr_all = 0, rx_pwr[4];
+ u8 rf_rx_num = 0, evm, pwdb_all;
+ u8 i, max_spatial_stream;
+ u32 rssi, total_rssi = 0;
+ bool is_cck = pstatus->is_cck;
+ u8 lan_idx, vga_idx;
+
+ /* Record it for next packet processing */
+ pstatus->packet_matchbssid = packet_match_bssid;
+ pstatus->packet_toself = packet_toself;
+ pstatus->packet_beacon = packet_beacon;
+ pstatus->rx_mimo_sig_qual[0] = -1;
+ pstatus->rx_mimo_sig_qual[1] = -1;
+
+ if (is_cck) {
+ u8 cck_highpwr;
+ u8 cck_agc_rpt;
+ /* CCK Driver info Structure is not the same as OFDM packet. */
+ cck_buf = (struct phy_sts_cck_8723e_t *)p_drvinfo;
+ cck_agc_rpt = cck_buf->cck_agc_rpt;
+
+ /* (1)Hardware does not provide RSSI for CCK
+ * (2)PWDB, Average PWDB cacluated by
+ * hardware (for rate adaptive)
+ */
+ if (ppsc->rfpwr_state == ERFON)
+ cck_highpwr = (u8) rtl_get_bbreg(hw,
+ RFPGA0_XA_HSSIPARAMETER2,
+ BIT(9));
+ else
+ cck_highpwr = false;
+
+ lan_idx = ((cck_agc_rpt & 0xE0) >> 5);
+ vga_idx = (cck_agc_rpt & 0x1f);
+ switch (lan_idx) {
+ case 7:
+ if (vga_idx <= 27)/*VGA_idx = 27~2*/
+ rx_pwr_all = -100 + 2 * (27 - vga_idx);
+ else
+ rx_pwr_all = -100;
+ break;
+ case 6:/*VGA_idx = 2~0*/
+ rx_pwr_all = -48 + 2 * (2 - vga_idx);
+ break;
+ case 5:/*VGA_idx = 7~5*/
+ rx_pwr_all = -42 + 2 * (7 - vga_idx);
+ break;
+ case 4:/*VGA_idx = 7~4*/
+ rx_pwr_all = -36 + 2 * (7 - vga_idx);
+ break;
+ case 3:/*VGA_idx = 7~0*/
+ rx_pwr_all = -24 + 2 * (7 - vga_idx);
+ break;
+ case 2:
+ if (cck_highpwr)/*VGA_idx = 5~0*/
+ rx_pwr_all = -12 + 2 * (5 - vga_idx);
+ 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 = rtl_query_rxpwrpercentage(rx_pwr_all);
+ /* CCK gain is smaller than OFDM/MCS gain, */
+ /* so we add gain diff by experiences,
+ * the val is 6
+ */
+ pwdb_all += 6;
+ if (pwdb_all > 100)
+ pwdb_all = 100;
+ /* modify the offset to make the same gain index with OFDM. */
+ if (pwdb_all > 34 && pwdb_all <= 42)
+ pwdb_all -= 2;
+ else if (pwdb_all > 26 && pwdb_all <= 34)
+ pwdb_all -= 6;
+ else if (pwdb_all > 14 && pwdb_all <= 26)
+ pwdb_all -= 8;
+ else if (pwdb_all > 4 && pwdb_all <= 14)
+ pwdb_all -= 4;
+ 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;
+ }
+
+ pstatus->rx_pwdb_all = pwdb_all;
+ pstatus->recvsignalpower = rx_pwr_all;
+
+ /* (3) Get Signal Quality (EVM) */
+ if (packet_match_bssid) {
+ u8 sq;
+
+ if (pstatus->rx_pwdb_all > 40) {
+ sq = 100;
+ } else {
+ sq = cck_buf->sq_rpt;
+ if (sq > 64)
+ sq = 0;
+ else if (sq < 20)
+ sq = 100;
+ else
+ sq = ((64 - sq) * 100) / 44;
+ }
+
+ pstatus->signalquality = sq;
+ pstatus->rx_mimo_sig_qual[0] = sq;
+ pstatus->rx_mimo_sig_qual[1] = -1;
+ }
+ } else {
+ rtlpriv->dm.rfpath_rxenable[0] = true;
+ rtlpriv->dm.rfpath_rxenable[1] = true;
+
+ /* (1)Get RSSI for HT rate */
+ for (i = RF90_PATH_A; i < RF6052_MAX_PATH; i++) {
+ /* we will judge RF RX path now. */
+ if (rtlpriv->dm.rfpath_rxenable[i])
+ rf_rx_num++;
+
+ rx_pwr[i] = ((p_drvinfo->gain_trsw[i] & 0x3f)*2) - 110;
+
+ /* Translate DBM to percentage. */
+ rssi = rtl_query_rxpwrpercentage(rx_pwr[i]);
+ total_rssi += rssi;
+
+ /* Get Rx snr value in DB */
+ rtlpriv->stats.rx_snr_db[i] =
+ (long)(p_drvinfo->rxsnr[i] / 2);
+
+ /* Record Signal Strength for next packet */
+ if (packet_match_bssid)
+ pstatus->rx_mimo_signalstrength[i] = (u8) rssi;
+ }
+
+ /* (2)PWDB, Avg cacluated by hardware (for rate adaptive) */
+ rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110;
+
+ pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
+ pstatus->rx_pwdb_all = pwdb_all;
+ pstatus->rxpower = rx_pwr_all;
+ pstatus->recvsignalpower = rx_pwr_all;
+
+ /* (3)EVM of HT rate */
+ if (pstatus->is_ht && pstatus->rate >= DESC92C_RATEMCS8 &&
+ pstatus->rate <= DESC92C_RATEMCS15)
+ max_spatial_stream = 2;
+ else
+ max_spatial_stream = 1;
+
+ for (i = 0; i < max_spatial_stream; i++) {
+ evm = rtl_evm_db_to_percentage(p_drvinfo->rxevm[i]);
+
+ if (packet_match_bssid) {
+ /* Fill value in RFD, Get the first
+ * spatial stream only
+ */
+ if (i == 0)
+ pstatus->signalquality =
+ (u8) (evm & 0xff);
+ pstatus->rx_mimo_sig_qual[i] =
+ (u8) (evm & 0xff);
+ }
+ }
+ if (packet_match_bssid) {
+ for (i = RF90_PATH_A; i <= RF90_PATH_B; i++)
+ rtl_priv(hw)->dm.cfo_tail[i] =
+ (char)p_phystrpt->path_cfotail[i];
+
+ rtl_priv(hw)->dm.packet_count++;
+ if (rtl_priv(hw)->dm.packet_count == 0xffffffff)
+ rtl_priv(hw)->dm.packet_count = 0;
+ }
+ }
+
+ /* UI BSS List signal strength(in percentage),
+ * make it good looking, from 0~100.
+ */
+ if (is_cck)
+ pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw,
+ pwdb_all));
+ else if (rf_rx_num != 0)
+ pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw,
+ total_rssi /= rf_rx_num));
+ /*HW antenna diversity*/
+ rtldm->fat_table.antsel_rx_keep_0 = p_phystrpt->ant_sel;
+ rtldm->fat_table.antsel_rx_keep_1 = p_phystrpt->ant_sel_b;
+ rtldm->fat_table.antsel_rx_keep_2 = p_phystrpt->antsel_rx_keep_2;
+}
+
+static void _rtl8723be_translate_rx_signal_stuff(struct ieee80211_hw *hw,
+ struct sk_buff *skb,
+ struct rtl_stats *pstatus,
+ u8 *pdesc,
+ struct rx_fwinfo_8723be *p_drvinfo)
+{
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct ieee80211_hdr *hdr;
+ u8 *tmp_buf;
+ u8 *praddr;
+ u8 *psaddr;
+ u16 fc, type;
+ bool packet_matchbssid, packet_toself, packet_beacon;
+
+ tmp_buf = skb->data + pstatus->rx_drvinfo_size + pstatus->rx_bufshift;
+
+ hdr = (struct ieee80211_hdr *)tmp_buf;
+ fc = le16_to_cpu(hdr->frame_control);
+ type = WLAN_FC_GET_TYPE(hdr->frame_control);
+ praddr = hdr->addr1;
+ psaddr = ieee80211_get_SA(hdr);
+ memcpy(pstatus->psaddr, psaddr, ETH_ALEN);
+
+ packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) &&
+ (!ether_addr_equal(mac->bssid, (fc & IEEE80211_FCTL_TODS) ?
+ hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS) ?
+ hdr->addr2 : hdr->addr3)) &&
+ (!pstatus->hwerror) &&
+ (!pstatus->crc) && (!pstatus->icv));
+
+ packet_toself = packet_matchbssid &&
+ (!ether_addr_equal(praddr, rtlefuse->dev_addr));
+
+ /* YP: packet_beacon is not initialized,
+ * this assignment is neccesary,
+ * otherwise it counld be true in this case
+ * the situation is much worse in Kernel 3.10
+ */
+ if (ieee80211_is_beacon(hdr->frame_control))
+ packet_beacon = true;
+ else
+ packet_beacon = false;
+
+ if (packet_beacon && packet_matchbssid)
+ rtl_priv(hw)->dm.dbginfo.num_qry_beacon_pkt++;
+
+ _rtl8723be_query_rxphystatus(hw, pstatus, pdesc, p_drvinfo,
+ packet_matchbssid,
+ packet_toself,
+ packet_beacon);
+
+ rtl_process_phyinfo(hw, tmp_buf, pstatus);
+}
+
+static void _rtl8723be_insert_emcontent(struct rtl_tcb_desc *ptcb_desc,
+ u8 *virtualaddress)
+{
+ u32 dwtmp = 0;
+ memset(virtualaddress, 0, 8);
+
+ SET_EARLYMODE_PKTNUM(virtualaddress, ptcb_desc->empkt_num);
+ if (ptcb_desc->empkt_num == 1) {
+ dwtmp = ptcb_desc->empkt_len[0];
+ } else {
+ dwtmp = ptcb_desc->empkt_len[0];
+ dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+ dwtmp += ptcb_desc->empkt_len[1];
+ }
+ SET_EARLYMODE_LEN0(virtualaddress, dwtmp);
+
+ if (ptcb_desc->empkt_num <= 3) {
+ dwtmp = ptcb_desc->empkt_len[2];
+ } else {
+ dwtmp = ptcb_desc->empkt_len[2];
+ dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+ dwtmp += ptcb_desc->empkt_len[3];
+ }
+ SET_EARLYMODE_LEN1(virtualaddress, dwtmp);
+ if (ptcb_desc->empkt_num <= 5) {
+ dwtmp = ptcb_desc->empkt_len[4];
+ } else {
+ dwtmp = ptcb_desc->empkt_len[4];
+ dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+ dwtmp += ptcb_desc->empkt_len[5];
+ }
+ SET_EARLYMODE_LEN2_1(virtualaddress, dwtmp & 0xF);
+ SET_EARLYMODE_LEN2_2(virtualaddress, dwtmp >> 4);
+ if (ptcb_desc->empkt_num <= 7) {
+ dwtmp = ptcb_desc->empkt_len[6];
+ } else {
+ dwtmp = ptcb_desc->empkt_len[6];
+ dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+ dwtmp += ptcb_desc->empkt_len[7];
+ }
+ SET_EARLYMODE_LEN3(virtualaddress, dwtmp);
+ if (ptcb_desc->empkt_num <= 9) {
+ dwtmp = ptcb_desc->empkt_len[8];
+ } else {
+ dwtmp = ptcb_desc->empkt_len[8];
+ dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+ dwtmp += ptcb_desc->empkt_len[9];
+ }
+ SET_EARLYMODE_LEN4(virtualaddress, dwtmp);
+}
+
+bool rtl8723be_rx_query_desc(struct ieee80211_hw *hw,
+ struct rtl_stats *status,
+ struct ieee80211_rx_status *rx_status,
+ u8 *pdesc, struct sk_buff *skb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rx_fwinfo_8723be *p_drvinfo;
+ struct ieee80211_hdr *hdr;
+
+ u32 phystatus = GET_RX_DESC_PHYST(pdesc);
+ status->packet_report_type = (u8)GET_RX_STATUS_DESC_RPT_SEL(pdesc);
+ if (status->packet_report_type == TX_REPORT2)
+ status->length = (u16) GET_RX_RPT2_DESC_PKT_LEN(pdesc);
+ else
+ status->length = (u16) GET_RX_DESC_PKT_LEN(pdesc);
+ status->rx_drvinfo_size = (u8) GET_RX_DESC_DRV_INFO_SIZE(pdesc) *
+ RX_DRV_INFO_SIZE_UNIT;
+ status->rx_bufshift = (u8) (GET_RX_DESC_SHIFT(pdesc) & 0x03);
+ status->icv = (u16) GET_RX_DESC_ICV(pdesc);
+ status->crc = (u16) GET_RX_DESC_CRC32(pdesc);
+ status->hwerror = (status->crc | status->icv);
+ status->decrypted = !GET_RX_DESC_SWDEC(pdesc);
+ status->rate = (u8) GET_RX_DESC_RXMCS(pdesc);
+ status->shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc);
+ status->isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1);
+ status->isfirst_ampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1);
+ if (status->packet_report_type == NORMAL_RX)
+ status->timestamp_low = GET_RX_DESC_TSFL(pdesc);
+ status->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc);
+ status->is_ht = (bool)GET_RX_DESC_RXHT(pdesc);
+
+ status->is_cck = RTL8723E_RX_HAL_IS_CCK_RATE(status->rate);
+
+ status->macid = GET_RX_DESC_MACID(pdesc);
+ if (GET_RX_STATUS_DESC_MAGIC_MATCH(pdesc))
+ status->wake_match = BIT(2);
+ else if (GET_RX_STATUS_DESC_MAGIC_MATCH(pdesc))
+ status->wake_match = BIT(1);
+ else if (GET_RX_STATUS_DESC_UNICAST_MATCH(pdesc))
+ status->wake_match = BIT(0);
+ else
+ status->wake_match = 0;
+ if (status->wake_match)
+ RT_TRACE(rtlpriv, COMP_RXDESC, DBG_LOUD,
+ "GGGGGGGGGGGGGet Wakeup Packet!! WakeMatch=%d\n",
+ status->wake_match);
+ rx_status->freq = hw->conf.chandef.chan->center_freq;
+ rx_status->band = hw->conf.chandef.chan->band;
+
+
+ hdr = (struct ieee80211_hdr *)(skb->data + status->rx_drvinfo_size +
+ status->rx_bufshift);
+
+ if (status->crc)
+ rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+
+ if (status->rx_is40Mhzpacket)
+ rx_status->flag |= RX_FLAG_40MHZ;
+
+ if (status->is_ht)
+ rx_status->flag |= RX_FLAG_HT;
+
+ rx_status->flag |= RX_FLAG_MACTIME_START;
+
+ /* hw will set status->decrypted true, if it finds the
+ * frame is open data frame or mgmt frame.
+ * So hw will not decryption robust managment frame
+ * for IEEE80211w but still set status->decrypted
+ * true, so here we should set it back to undecrypted
+ * for IEEE80211w frame, and mac80211 sw will help
+ * to decrypt it
+ */
+ if (status->decrypted) {
+ if (!hdr) {
+ WARN_ON_ONCE(true);
+ pr_err("decrypted is true but hdr NULL in skb %p\n",
+ rtl_get_hdr(skb));
+ return false;
+ }
+
+ if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
+ (ieee80211_has_protected(hdr->frame_control)))
+ rx_status->flag &= ~RX_FLAG_DECRYPTED;
+ else
+ rx_status->flag |= RX_FLAG_DECRYPTED;
+ }
+
+ /* rate_idx: index of data rate into band's
+ * supported rates or MCS index if HT rates
+ * are use (RX_FLAG_HT)
+ * Notice: this is diff with windows define
+ */
+ rx_status->rate_idx = _rtl8723be_rate_mapping(hw, status->is_ht,
+ status->rate);
+
+ rx_status->mactime = status->timestamp_low;
+ if (phystatus) {
+ p_drvinfo = (struct rx_fwinfo_8723be *)(skb->data +
+ status->rx_bufshift);
+
+ _rtl8723be_translate_rx_signal_stuff(hw, skb, status,
+ pdesc, p_drvinfo);
+ }
+
+ /*rx_status->qual = status->signal; */
+ rx_status->signal = status->recvsignalpower + 10;
+ if (status->packet_report_type == TX_REPORT2) {
+ status->macid_valid_entry[0] =
+ GET_RX_RPT2_DESC_MACID_VALID_1(pdesc);
+ status->macid_valid_entry[1] =
+ GET_RX_RPT2_DESC_MACID_VALID_2(pdesc);
+ }
+ return true;
+}
+
+void rtl8723be_tx_fill_desc(struct ieee80211_hw *hw,
+ struct ieee80211_hdr *hdr, u8 *pdesc_tx,
+ u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta, struct sk_buff *skb,
+ u8 hw_queue, struct rtl_tcb_desc *ptcb_desc)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+ u8 *pdesc = pdesc_tx;
+ u16 seq_number;
+ __le16 fc = hdr->frame_control;
+ unsigned int buf_len = 0;
+ unsigned int skb_len = skb->len;
+ u8 fw_qsel = _rtl8723be_map_hwqueue_to_fwqueue(skb, hw_queue);
+ bool firstseg = ((hdr->seq_ctrl &
+ cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0);
+ bool lastseg = ((hdr->frame_control &
+ cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0);
+ dma_addr_t mapping;
+ u8 bw_40 = 0;
+ u8 short_gi = 0;
+
+ if (mac->opmode == NL80211_IFTYPE_STATION) {
+ bw_40 = mac->bw_40;
+ } else if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_ADHOC) {
+ if (sta)
+ bw_40 = sta->ht_cap.cap &
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ }
+ seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
+ rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc);
+ /* reserve 8 byte for AMPDU early mode */
+ if (rtlhal->earlymode_enable) {
+ skb_push(skb, EM_HDR_LEN);
+ memset(skb->data, 0, EM_HDR_LEN);
+ }
+ buf_len = skb->len;
+ mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "DMA mapping error");
+ return;
+ }
+ CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_8723be));
+ if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) {
+ firstseg = true;
+ lastseg = true;
+ }
+ if (firstseg) {
+ if (rtlhal->earlymode_enable) {
+ SET_TX_DESC_PKT_OFFSET(pdesc, 1);
+ SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN +
+ EM_HDR_LEN);
+ if (ptcb_desc->empkt_num) {
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+ "Insert 8 byte.pTcb->EMPktNum:%d\n",
+ ptcb_desc->empkt_num);
+ _rtl8723be_insert_emcontent(ptcb_desc,
+ (u8 *)(skb->data));
+ }
+ } else {
+ SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
+ }
+
+ /* ptcb_desc->use_driver_rate = true; */
+ SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate);
+ if (ptcb_desc->hw_rate > DESC92C_RATEMCS0)
+ short_gi = (ptcb_desc->use_shortgi) ? 1 : 0;
+ else
+ short_gi = (ptcb_desc->use_shortpreamble) ? 1 : 0;
+
+ SET_TX_DESC_DATA_SHORTGI(pdesc, short_gi);
+
+ if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+ SET_TX_DESC_AGG_ENABLE(pdesc, 1);
+ SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x14);
+ }
+ SET_TX_DESC_SEQ(pdesc, seq_number);
+ SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcb_desc->rts_enable &&
+ !ptcb_desc->cts_enable) ?
+ 1 : 0));
+ SET_TX_DESC_HW_RTS_ENABLE(pdesc, 0);
+ SET_TX_DESC_CTS2SELF(pdesc, ((ptcb_desc->cts_enable) ?
+ 1 : 0));
+
+ SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate);
+
+ SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc);
+ SET_TX_DESC_RTS_SHORT(pdesc,
+ ((ptcb_desc->rts_rate <= DESC92C_RATE54M) ?
+ (ptcb_desc->rts_use_shortpreamble ? 1 : 0) :
+ (ptcb_desc->rts_use_shortgi ? 1 : 0)));
+
+ if (ptcb_desc->btx_enable_sw_calc_duration)
+ SET_TX_DESC_NAV_USE_HDR(pdesc, 1);
+
+ if (bw_40) {
+ if (ptcb_desc->packet_bw) {
+ SET_TX_DESC_DATA_BW(pdesc, 1);
+ SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3);
+ } else {
+ SET_TX_DESC_DATA_BW(pdesc, 0);
+ SET_TX_DESC_TX_SUB_CARRIER(pdesc, mac->cur_40_prime_sc);
+ }
+ } else {
+ SET_TX_DESC_DATA_BW(pdesc, 0);
+ SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0);
+ }
+
+ SET_TX_DESC_LINIP(pdesc, 0);
+ SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb_len);
+ if (sta) {
+ u8 ampdu_density = sta->ht_cap.ampdu_density;
+ SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density);
+ }
+ if (info->control.hw_key) {
+ struct ieee80211_key_conf *keyconf =
+ info->control.hw_key;
+ switch (keyconf->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ case WLAN_CIPHER_SUITE_TKIP:
+ SET_TX_DESC_SEC_TYPE(pdesc, 0x1);
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ SET_TX_DESC_SEC_TYPE(pdesc, 0x3);
+ break;
+ default:
+ SET_TX_DESC_SEC_TYPE(pdesc, 0x0);
+ break;
+ }
+ }
+
+ SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel);
+ SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F);
+ SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF);
+ SET_TX_DESC_DISABLE_FB(pdesc, ptcb_desc->disable_ratefallback ?
+ 1 : 0);
+ SET_TX_DESC_USE_RATE(pdesc, ptcb_desc->use_driver_rate ? 1 : 0);
+
+ if (ieee80211_is_data_qos(fc)) {
+ if (mac->rdg_en) {
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+ "Enable RDG function.\n");
+ SET_TX_DESC_RDG_ENABLE(pdesc, 1);
+ SET_TX_DESC_HTC(pdesc, 1);
+ }
+ }
+ }
+
+ SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0));
+ SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0));
+ SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) buf_len);
+ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
+ SET_TX_DESC_RATE_ID(pdesc, ptcb_desc->ratr_index);
+ SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id);
+
+ if (!ieee80211_is_data_qos(fc)) {
+ SET_TX_DESC_HWSEQ_EN(pdesc, 1);
+ SET_TX_DESC_HWSEQ_SEL(pdesc, 0);
+ }
+ SET_TX_DESC_MORE_FRAG(pdesc, (lastseg ? 0 : 1));
+ if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) ||
+ is_broadcast_ether_addr(ieee80211_get_DA(hdr))) {
+ SET_TX_DESC_BMC(pdesc, 1);
+ }
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "\n");
+}
+
+void rtl8723be_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
+ bool b_firstseg, bool b_lastseg,
+ struct sk_buff *skb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u8 fw_queue = QSLT_BEACON;
+
+ dma_addr_t mapping = pci_map_single(rtlpci->pdev,
+ skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+
+ if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+ "DMA mapping error");
+ return;
+ }
+ CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE);
+
+ SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
+
+ SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M);
+
+ SET_TX_DESC_SEQ(pdesc, 0);
+
+ SET_TX_DESC_LINIP(pdesc, 0);
+
+ SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue);
+
+ SET_TX_DESC_FIRST_SEG(pdesc, 1);
+ SET_TX_DESC_LAST_SEG(pdesc, 1);
+
+ SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len));
+
+ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
+
+ SET_TX_DESC_RATE_ID(pdesc, 0);
+ SET_TX_DESC_MACID(pdesc, 0);
+
+ SET_TX_DESC_OWN(pdesc, 1);
+
+ SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len));
+
+ SET_TX_DESC_FIRST_SEG(pdesc, 1);
+ SET_TX_DESC_LAST_SEG(pdesc, 1);
+
+ SET_TX_DESC_USE_RATE(pdesc, 1);
+}
+
+void rtl8723be_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+ u8 desc_name, u8 *val)
+{
+ if (istx) {
+ switch (desc_name) {
+ case HW_DESC_OWN:
+ SET_TX_DESC_OWN(pdesc, 1);
+ break;
+ case HW_DESC_TX_NEXTDESC_ADDR:
+ SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *)val);
+ break;
+ default:
+ RT_ASSERT(false, "ERR txdesc :%d not process\n",
+ desc_name);
+ break;
+ }
+ } else {
+ switch (desc_name) {
+ case HW_DESC_RXOWN:
+ SET_RX_DESC_OWN(pdesc, 1);
+ break;
+ case HW_DESC_RXBUFF_ADDR:
+ SET_RX_DESC_BUFF_ADDR(pdesc, *(u32 *)val);
+ break;
+ case HW_DESC_RXPKT_LEN:
+ SET_RX_DESC_PKT_LEN(pdesc, *(u32 *)val);
+ break;
+ case HW_DESC_RXERO:
+ SET_RX_DESC_EOR(pdesc, 1);
+ break;
+ default:
+ RT_ASSERT(false, "ERR rxdesc :%d not process\n",
+ desc_name);
+ break;
+ }
+ }
+}
+
+u32 rtl8723be_get_desc(u8 *pdesc, bool istx, u8 desc_name)
+{
+ u32 ret = 0;
+
+ if (istx) {
+ switch (desc_name) {
+ case HW_DESC_OWN:
+ ret = GET_TX_DESC_OWN(pdesc);
+ break;
+ case HW_DESC_TXBUFF_ADDR:
+ ret = GET_TX_DESC_TX_BUFFER_ADDRESS(pdesc);
+ break;
+ default:
+ RT_ASSERT(false, "ERR txdesc :%d not process\n",
+ desc_name);
+ break;
+ }
+ } else {
+ switch (desc_name) {
+ case HW_DESC_OWN:
+ ret = GET_RX_DESC_OWN(pdesc);
+ break;
+ case HW_DESC_RXPKT_LEN:
+ ret = GET_RX_DESC_PKT_LEN(pdesc);
+ break;
+ default:
+ RT_ASSERT(false, "ERR rxdesc :%d not process\n",
+ desc_name);
+ break;
+ }
+ }
+ return ret;
+}
+
+bool rtl8723be_is_tx_desc_closed(struct ieee80211_hw *hw,
+ u8 hw_queue, u16 index)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue];
+ u8 *entry = (u8 *)(&ring->desc[ring->idx]);
+ u8 own = (u8) rtl8723be_get_desc(entry, true, HW_DESC_OWN);
+
+ /*beacon packet will only use the first
+ *descriptor by default, and the own may not
+ *be cleared by the hardware
+ */
+ if (own)
+ return false;
+ else
+ return true;
+}
+
+void rtl8723be_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ if (hw_queue == BEACON_QUEUE) {
+ rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, BIT(4));
+ } else {
+ rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG,
+ BIT(0) << (hw_queue));
+ }
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/trx.h b/drivers/net/wireless/rtlwifi/rtl8723be/trx.h
new file mode 100644
index 000000000000..102f33dcc988
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/trx.h
@@ -0,0 +1,617 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_TRX_H__
+#define __RTL8723BE_TRX_H__
+
+#define TX_DESC_SIZE 40
+#define TX_DESC_AGGR_SUBFRAME_SIZE 32
+
+#define RX_DESC_SIZE 32
+#define RX_DRV_INFO_SIZE_UNIT 8
+
+#define TX_DESC_NEXT_DESC_OFFSET 40
+#define USB_HWDESC_HEADER_LEN 40
+#define CRCLENGTH 4
+
+#define SET_TX_DESC_PKT_SIZE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 0, 16, __val)
+#define SET_TX_DESC_OFFSET(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 16, 8, __val)
+#define SET_TX_DESC_BMC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 24, 1, __val)
+#define SET_TX_DESC_HTC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 25, 1, __val)
+#define SET_TX_DESC_LAST_SEG(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 26, 1, __val)
+#define SET_TX_DESC_FIRST_SEG(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 27, 1, __val)
+#define SET_TX_DESC_LINIP(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 28, 1, __val)
+#define SET_TX_DESC_NO_ACM(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 29, 1, __val)
+#define SET_TX_DESC_GF(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
+#define SET_TX_DESC_OWN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
+
+#define GET_TX_DESC_PKT_SIZE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 0, 16)
+#define GET_TX_DESC_OFFSET(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 16, 8)
+#define GET_TX_DESC_BMC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 24, 1)
+#define GET_TX_DESC_HTC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 25, 1)
+#define GET_TX_DESC_LAST_SEG(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 26, 1)
+#define GET_TX_DESC_FIRST_SEG(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 27, 1)
+#define GET_TX_DESC_LINIP(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 28, 1)
+#define GET_TX_DESC_NO_ACM(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 29, 1)
+#define GET_TX_DESC_GF(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 30, 1)
+#define GET_TX_DESC_OWN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 31, 1)
+
+#define SET_TX_DESC_MACID(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 0, 7, __val)
+#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 8, 5, __val)
+#define SET_TX_DESC_RDG_NAV_EXT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 13, 1, __val)
+#define SET_TX_DESC_LSIG_TXOP_EN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 14, 1, __val)
+#define SET_TX_DESC_PIFS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 15, 1, __val)
+#define SET_TX_DESC_RATE_ID(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 16, 5, __val)
+#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 21, 1, __val)
+#define SET_TX_DESC_SEC_TYPE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 22, 2, __val)
+#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 24, 5, __val)
+
+
+#define SET_TX_DESC_PAID(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 0, 9, __val)
+#define SET_TX_DESC_CCA_RTS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 10, 2, __val)
+#define SET_TX_DESC_AGG_ENABLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 12, 1, __val)
+#define SET_TX_DESC_RDG_ENABLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 13, 1, __val)
+#define SET_TX_DESC_BAR_RTY_TH(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 14, 2, __val)
+#define SET_TX_DESC_AGG_BREAK(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 16, 1, __val)
+#define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 17, 1, __val)
+#define SET_TX_DESC_RAW(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val)
+#define SET_TX_DESC_SPE_RPT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 19, 1, __val)
+#define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val)
+#define SET_TX_DESC_BT_INT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 23, 1, __val)
+#define SET_TX_DESC_GID(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 24, 6, __val)
+
+
+#define SET_TX_DESC_WHEADER_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 0, 4, __val)
+#define SET_TX_DESC_CHK_EN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 4, 1, __val)
+#define SET_TX_DESC_EARLY_MODE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 5, 1, __val)
+#define SET_TX_DESC_HWSEQ_SEL(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 6, 2, __val)
+#define SET_TX_DESC_USE_RATE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 8, 1, __val)
+#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 9, 1, __val)
+#define SET_TX_DESC_DISABLE_FB(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 10, 1, __val)
+#define SET_TX_DESC_CTS2SELF(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 11, 1, __val)
+#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 12, 1, __val)
+#define SET_TX_DESC_HW_RTS_ENABLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 13, 1, __val)
+#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 15, 1, __val)
+#define SET_TX_DESC_USE_MAX_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 16, 1, __val)
+#define SET_TX_DESC_MAX_AGG_NUM(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 17, 5, __val)
+#define SET_TX_DESC_NDPA(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 22, 2, __val)
+#define SET_TX_DESC_AMPDU_MAX_TIME(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 24, 8, __val)
+
+
+#define SET_TX_DESC_TX_RATE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 0, 7, __val)
+#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 8, 5, __val)
+#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 13, 4, __val)
+#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 17, 1, __val)
+#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 18, 6, __val)
+#define SET_TX_DESC_RTS_RATE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 24, 5, __val)
+
+
+#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 0, 4, __val)
+#define SET_TX_DESC_DATA_SHORTGI(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 4, 1, __val)
+#define SET_TX_DESC_DATA_BW(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 5, 2, __val)
+#define SET_TX_DESC_DATA_LDPC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 7, 1, __val)
+#define SET_TX_DESC_DATA_STBC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 8, 2, __val)
+#define SET_TX_DESC_CTROL_STBC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 10, 2, __val)
+#define SET_TX_DESC_RTS_SHORT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 12, 1, __val)
+#define SET_TX_DESC_RTS_SC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 13, 4, __val)
+
+
+#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 16, __val)
+
+#define GET_TX_DESC_TX_BUFFER_SIZE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+28, 0, 16)
+
+#define SET_TX_DESC_HWSEQ_EN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+32, 15, 1, __val)
+
+#define SET_TX_DESC_SEQ(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+36, 12, 12, __val)
+
+#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+40, 0, 32, __val)
+
+#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+40, 0, 32)
+
+
+#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+48, 0, 32, __val)
+
+#define GET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+48, 0, 32)
+
+#define GET_RX_DESC_PKT_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 0, 14)
+#define GET_RX_DESC_CRC32(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 14, 1)
+#define GET_RX_DESC_ICV(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 15, 1)
+#define GET_RX_DESC_DRV_INFO_SIZE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 16, 4)
+#define GET_RX_DESC_SECURITY(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 20, 3)
+#define GET_RX_DESC_QOS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 23, 1)
+#define GET_RX_DESC_SHIFT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 24, 2)
+#define GET_RX_DESC_PHYST(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 26, 1)
+#define GET_RX_DESC_SWDEC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 27, 1)
+#define GET_RX_DESC_LS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 28, 1)
+#define GET_RX_DESC_FS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 29, 1)
+#define GET_RX_DESC_EOR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 30, 1)
+#define GET_RX_DESC_OWN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 31, 1)
+
+#define SET_RX_DESC_PKT_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 0, 14, __val)
+#define SET_RX_DESC_EOR(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
+#define SET_RX_DESC_OWN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
+
+#define GET_RX_DESC_MACID(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 0, 7)
+#define GET_RX_DESC_TID(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 8, 4)
+#define GET_RX_DESC_AMSDU(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 13, 1)
+#define GET_RX_STATUS_DESC_RXID_MATCH(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 14, 1)
+#define GET_RX_DESC_PAGGR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 15, 1)
+#define GET_RX_DESC_A1_FIT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 16, 4)
+#define GET_RX_DESC_CHKERR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 20, 1)
+#define GET_RX_DESC_IPVER(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 21, 1)
+#define GET_RX_STATUS_DESC_IS_TCPUDP(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 22, 1)
+#define GET_RX_STATUS_DESC_CHK_VLD(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 23, 1)
+#define GET_RX_DESC_PAM(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 24, 1)
+#define GET_RX_DESC_PWR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 25, 1)
+#define GET_RX_DESC_MD(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 26, 1)
+#define GET_RX_DESC_MF(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 27, 1)
+#define GET_RX_DESC_TYPE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 28, 2)
+#define GET_RX_DESC_MC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 30, 1)
+#define GET_RX_DESC_BC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 31, 1)
+
+
+#define GET_RX_DESC_SEQ(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 0, 12)
+#define GET_RX_DESC_FRAG(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 12, 4)
+#define GET_RX_STATUS_DESC_RX_IS_QOS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 16, 1)
+#define GET_RX_STATUS_DESC_WLANHD_IV_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 18, 6)
+#define GET_RX_STATUS_DESC_RPT_SEL(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 28, 1)
+
+
+#define GET_RX_DESC_RXMCS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 0, 7)
+#define GET_RX_DESC_RXHT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 6, 1)
+#define GET_RX_STATUS_DESC_RX_GF(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 7, 1)
+#define GET_RX_DESC_HTC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 10, 1)
+#define GET_RX_STATUS_DESC_EOSP(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 11, 1)
+#define GET_RX_STATUS_DESC_BSSID_FIT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 12, 2)
+
+#define GET_RX_STATUS_DESC_PATTERN_MATCH(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 29, 1)
+#define GET_RX_STATUS_DESC_UNICAST_MATCH(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 30, 1)
+#define GET_RX_STATUS_DESC_MAGIC_MATCH(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 31, 1)
+
+#define GET_RX_DESC_SPLCP(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 0, 1)
+#define GET_RX_STATUS_DESC_LDPC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 1, 1)
+#define GET_RX_STATUS_DESC_STBC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 2, 1)
+#define GET_RX_DESC_BW(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 4, 2)
+
+#define GET_RX_DESC_TSFL(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 0, 32)
+
+#define GET_RX_DESC_BUFF_ADDR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 0, 32)
+#define GET_RX_DESC_BUFF_ADDR64(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+28, 0, 32)
+
+#define SET_RX_DESC_BUFF_ADDR(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 32, __val)
+#define SET_RX_DESC_BUFF_ADDR64(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 32, __val)
+
+
+/* TX report 2 format in Rx desc*/
+
+#define GET_RX_RPT2_DESC_PKT_LEN(__rxstatusdesc) \
+ LE_BITS_TO_4BYTE(__rxstatusdesc, 0, 9)
+#define GET_RX_RPT2_DESC_MACID_VALID_1(__rxstatusdesc) \
+ LE_BITS_TO_4BYTE(__rxstatusdesc+16, 0, 32)
+#define GET_RX_RPT2_DESC_MACID_VALID_2(__rxstatusdesc) \
+ LE_BITS_TO_4BYTE(__rxstatusdesc+20, 0, 32)
+
+#define SET_EARLYMODE_PKTNUM(__paddr, __value) \
+ SET_BITS_TO_LE_4BYTE(__paddr, 0, 4, __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)
+
+#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \
+do { \
+ if (_size > TX_DESC_NEXT_DESC_OFFSET) \
+ memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \
+ else \
+ memset(__pdesc, 0, _size); \
+} while (0)
+
+struct phy_rx_agc_info_t {
+ #ifdef __LITTLE_ENDIAN
+ u8 gain:7, trsw:1;
+ #else
+ u8 trsw:1, gain:7;
+ #endif
+};
+struct phy_status_rpt {
+ struct phy_rx_agc_info_t 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;
+ char path_cfotail[2];
+ u8 pcts_mask[2];
+ char 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];
+ u8 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
+} __packed;
+
+struct rx_fwinfo_8723be {
+ u8 gain_trsw[4];
+ u8 pwdb_all;
+ u8 cfosho[4];
+ u8 cfotail[4];
+ char rxevm[2];
+ char rxsnr[4];
+ u8 pdsnr[2];
+ u8 csi_current[2];
+ u8 csi_target[2];
+ u8 sigevm;
+ u8 max_ex_pwr;
+ u8 ex_intf_flag:1;
+ u8 sgi_en:1;
+ u8 rxsc:2;
+ u8 reserve:4;
+} __packed;
+
+struct tx_desc_8723be {
+ u32 pktsize:16;
+ u32 offset:8;
+ u32 bmc:1;
+ u32 htc:1;
+ u32 lastseg:1;
+ u32 firstseg:1;
+ u32 linip:1;
+ u32 noacm:1;
+ u32 gf:1;
+ u32 own:1;
+
+ u32 macid:6;
+ u32 rsvd0:2;
+ u32 queuesel:5;
+ u32 rd_nav_ext:1;
+ u32 lsig_txop_en:1;
+ u32 pifs:1;
+ u32 rateid:4;
+ u32 nav_usehdr:1;
+ u32 en_descid:1;
+ u32 sectype:2;
+ u32 pktoffset:8;
+
+ u32 rts_rc:6;
+ u32 data_rc:6;
+ u32 agg_en:1;
+ u32 rdg_en:1;
+ u32 bar_retryht:2;
+ u32 agg_break:1;
+ u32 morefrag:1;
+ u32 raw:1;
+ u32 ccx:1;
+ u32 ampdudensity:3;
+ u32 bt_int:1;
+ u32 ant_sela:1;
+ u32 ant_selb:1;
+ u32 txant_cck:2;
+ u32 txant_l:2;
+ u32 txant_ht:2;
+
+ u32 nextheadpage:8;
+ u32 tailpage:8;
+ u32 seq:12;
+ u32 cpu_handle:1;
+ u32 tag1:1;
+ u32 trigger_int:1;
+ u32 hwseq_en:1;
+
+ u32 rtsrate:5;
+ u32 apdcfe:1;
+ u32 qos:1;
+ u32 hwseq_ssn:1;
+ u32 userrate:1;
+ u32 dis_rtsfb:1;
+ u32 dis_datafb:1;
+ u32 cts2self:1;
+ u32 rts_en:1;
+ u32 hwrts_en:1;
+ u32 portid:1;
+ u32 pwr_status:3;
+ u32 waitdcts:1;
+ u32 cts2ap_en:1;
+ u32 txsc:2;
+ u32 stbc:2;
+ u32 txshort:1;
+ u32 txbw:1;
+ u32 rtsshort:1;
+ u32 rtsbw:1;
+ u32 rtssc:2;
+ u32 rtsstbc:2;
+
+ u32 txrate:6;
+ u32 shortgi:1;
+ u32 ccxt:1;
+ u32 txrate_fb_lmt:5;
+ u32 rtsrate_fb_lmt:4;
+ u32 retrylmt_en:1;
+ u32 txretrylmt:6;
+ u32 usb_txaggnum:8;
+
+ u32 txagca:5;
+ u32 txagcb:5;
+ u32 usemaxlen:1;
+ u32 maxaggnum:5;
+ u32 mcsg1maxlen:4;
+ u32 mcsg2maxlen:4;
+ u32 mcsg3maxlen:4;
+ u32 mcs7sgimaxlen:4;
+
+ u32 txbuffersize:16;
+ u32 sw_offset30:8;
+ u32 sw_offset31:4;
+ u32 rsvd1:1;
+ u32 antsel_c:1;
+ u32 null_0:1;
+ u32 null_1:1;
+
+ u32 txbuffaddr;
+ u32 txbufferaddr64;
+ u32 nextdescaddress;
+ u32 nextdescaddress64;
+
+ u32 reserve_pass_pcie_mm_limit[4];
+} __packed;
+
+struct rx_desc_8723be {
+ u32 length:14;
+ u32 crc32:1;
+ u32 icverror:1;
+ u32 drv_infosize:4;
+ u32 security:3;
+ u32 qos:1;
+ u32 shift:2;
+ u32 phystatus:1;
+ u32 swdec:1;
+ u32 lastseg:1;
+ u32 firstseg:1;
+ u32 eor:1;
+ u32 own:1;
+
+ u32 macid:6;
+ u32 tid:4;
+ u32 hwrsvd:5;
+ u32 paggr:1;
+ u32 faggr:1;
+ u32 a1_fit:4;
+ u32 a2_fit:4;
+ u32 pam:1;
+ u32 pwr:1;
+ u32 moredata:1;
+ u32 morefrag:1;
+ u32 type:2;
+ u32 mc:1;
+ u32 bc:1;
+
+ u32 seq:12;
+ u32 frag:4;
+ u32 nextpktlen:14;
+ u32 nextind:1;
+ u32 rsvd:1;
+
+ u32 rxmcs:6;
+ u32 rxht:1;
+ u32 amsdu:1;
+ u32 splcp:1;
+ u32 bandwidth:1;
+ u32 htc:1;
+ u32 tcpchk_rpt:1;
+ u32 ipcchk_rpt:1;
+ u32 tcpchk_valid:1;
+ u32 hwpcerr:1;
+ u32 hwpcind:1;
+ u32 iv0:16;
+
+ u32 iv1;
+
+ u32 tsfl;
+
+ u32 bufferaddress;
+ u32 bufferaddress64;
+
+} __packed;
+
+void rtl8723be_tx_fill_desc(struct ieee80211_hw *hw,
+ struct ieee80211_hdr *hdr, u8 *pdesc,
+ u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta, struct sk_buff *skb,
+ u8 hw_queue, struct rtl_tcb_desc *ptcb_desc);
+bool rtl8723be_rx_query_desc(struct ieee80211_hw *hw,
+ struct rtl_stats *status,
+ struct ieee80211_rx_status *rx_status,
+ u8 *pdesc, struct sk_buff *skb);
+void rtl8723be_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+ u8 desc_name, u8 *val);
+u32 rtl8723be_get_desc(u8 *pdesc, bool istx, u8 desc_name);
+bool rtl8723be_is_tx_desc_closed(struct ieee80211_hw *hw,
+ u8 hw_queue, u16 index);
+void rtl8723be_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
+void rtl8723be_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
+ bool b_firstseg, bool b_lastseg,
+ struct sk_buff *skb);
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/Makefile b/drivers/net/wireless/rtlwifi/rtl8723com/Makefile
new file mode 100644
index 000000000000..345a68adcf38
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723com/Makefile
@@ -0,0 +1,9 @@
+rtl8723-common-objs := \
+ main.o \
+ dm_common.o \
+ fw_common.o \
+ phy_common.o
+
+obj-$(CONFIG_RTL8723_COMMON) += rtl8723-common.o
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8723com/dm_common.c
new file mode 100644
index 000000000000..4e254b72bf45
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723com/dm_common.c
@@ -0,0 +1,65 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "dm_common.h"
+#include "../rtl8723ae/dm.h"
+#include <linux/module.h>
+
+/* These routines are common to RTL8723AE and RTL8723bE */
+
+void rtl8723_dm_init_dynamic_txpower(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.dynamic_txpower_enable = false;
+
+ rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL;
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+}
+EXPORT_SYMBOL_GPL(rtl8723_dm_init_dynamic_txpower);
+
+void rtl8723_dm_init_edca_turbo(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.current_turbo_edca = false;
+ rtlpriv->dm.is_any_nonbepkts = false;
+ rtlpriv->dm.is_cur_rdlstate = false;
+}
+EXPORT_SYMBOL_GPL(rtl8723_dm_init_edca_turbo);
+
+void rtl8723_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm_pstable.pre_ccastate = CCA_MAX;
+ rtlpriv->dm_pstable.cur_ccasate = CCA_MAX;
+ rtlpriv->dm_pstable.pre_rfstate = RF_MAX;
+ rtlpriv->dm_pstable.cur_rfstate = RF_MAX;
+ rtlpriv->dm_pstable.rssi_val_min = 0;
+ rtlpriv->dm_pstable.initialize = 0;
+}
+EXPORT_SYMBOL_GPL(rtl8723_dm_init_dynamic_bb_powersaving);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/dm_common.h b/drivers/net/wireless/rtlwifi/rtl8723com/dm_common.h
new file mode 100644
index 000000000000..5c1b94ce2f86
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723com/dm_common.h
@@ -0,0 +1,33 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __DM_COMMON_H__
+#define __DM_COMMON_H__
+
+void rtl8723_dm_init_dynamic_txpower(struct ieee80211_hw *hw);
+void rtl8723_dm_init_edca_turbo(struct ieee80211_hw *hw);
+void rtl8723_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c
new file mode 100644
index 000000000000..540278ff462b
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c
@@ -0,0 +1,329 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "fw_common.h"
+#include <linux/module.h>
+
+void rtl8723_enable_fw_download(struct ieee80211_hw *hw, bool enable)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 tmp;
+
+ if (enable) {
+ tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
+
+ tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
+ rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
+
+ tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
+ rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
+ } else {
+ tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
+ rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
+
+ rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
+ }
+}
+EXPORT_SYMBOL_GPL(rtl8723_enable_fw_download);
+
+void rtl8723_fw_block_write(struct ieee80211_hw *hw,
+ const u8 *buffer, u32 size)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 blocksize = sizeof(u32);
+ u8 *bufferptr = (u8 *)buffer;
+ u32 *pu4byteptr = (u32 *)buffer;
+ u32 i, offset, blockcount, remainsize;
+
+ blockcount = size / blocksize;
+ remainsize = size % blocksize;
+
+ for (i = 0; i < blockcount; i++) {
+ offset = i * blocksize;
+ rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
+ *(pu4byteptr + i));
+ }
+ if (remainsize) {
+ offset = blockcount * blocksize;
+ bufferptr += offset;
+ for (i = 0; i < remainsize; i++) {
+ rtl_write_byte(rtlpriv,
+ (FW_8192C_START_ADDRESS + offset + i),
+ *(bufferptr + i));
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(rtl8723_fw_block_write);
+
+void rtl8723_fw_page_write(struct ieee80211_hw *hw,
+ u32 page, const u8 *buffer, u32 size)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 value8;
+ u8 u8page = (u8) (page & 0x07);
+
+ value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
+
+ rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
+ rtl8723_fw_block_write(hw, buffer, size);
+}
+EXPORT_SYMBOL_GPL(rtl8723_fw_page_write);
+
+static void rtl8723_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
+{
+ u32 fwlen = *pfwlen;
+ u8 remain = (u8) (fwlen % 4);
+
+ remain = (remain == 0) ? 0 : (4 - remain);
+
+ while (remain > 0) {
+ pfwbuf[fwlen] = 0;
+ fwlen++;
+ remain--;
+ }
+ *pfwlen = fwlen;
+}
+
+void rtl8723_write_fw(struct ieee80211_hw *hw,
+ enum version_8723e version,
+ u8 *buffer, u32 size)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 *bufferptr = buffer;
+ u32 pagenums, remainsize;
+ u32 page, offset;
+
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "FW size is %d bytes,\n", size);
+
+ rtl8723_fill_dummy(bufferptr, &size);
+
+ pagenums = size / FW_8192C_PAGE_SIZE;
+ remainsize = size % FW_8192C_PAGE_SIZE;
+
+ if (pagenums > 8) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Page numbers should not greater then 8\n");
+ }
+ for (page = 0; page < pagenums; page++) {
+ offset = page * FW_8192C_PAGE_SIZE;
+ rtl8723_fw_page_write(hw, page, (bufferptr + offset),
+ FW_8192C_PAGE_SIZE);
+ }
+ if (remainsize) {
+ offset = pagenums * FW_8192C_PAGE_SIZE;
+ page = pagenums;
+ rtl8723_fw_page_write(hw, page, (bufferptr + offset),
+ remainsize);
+ }
+}
+EXPORT_SYMBOL_GPL(rtl8723_write_fw);
+
+void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw)
+{
+ u8 u1tmp;
+ u8 delay = 100;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
+ u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+
+ while (u1tmp & BIT(2)) {
+ delay--;
+ if (delay == 0)
+ break;
+ udelay(50);
+ u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+ }
+ if (delay == 0) {
+ u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, u1tmp&(~BIT(2)));
+ }
+}
+EXPORT_SYMBOL_GPL(rtl8723ae_firmware_selfreset);
+
+void rtl8723be_firmware_selfreset(struct ieee80211_hw *hw)
+{
+ u8 u1b_tmp;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
+ rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0))));
+
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));
+ udelay(50);
+
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
+ rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp | BIT(0)));
+
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp | BIT(2)));
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ " _8051Reset8723be(): 8051 reset success .\n");
+}
+EXPORT_SYMBOL_GPL(rtl8723be_firmware_selfreset);
+
+int rtl8723_fw_free_to_go(struct ieee80211_hw *hw, bool is_8723be)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ int err = -EIO;
+ u32 counter = 0;
+ u32 value32;
+
+ do {
+ value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+ } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
+ (!(value32 & FWDL_CHKSUM_RPT)));
+
+ if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "chksum report fail ! REG_MCUFWDL:0x%08x .\n",
+ value32);
+ goto exit;
+ }
+ RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+ "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
+
+ value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL) | MCUFWDL_RDY;
+ value32 &= ~WINTINI_RDY;
+ rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
+
+ if (is_8723be)
+ rtl8723be_firmware_selfreset(hw);
+ counter = 0;
+
+ do {
+ value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+ if (value32 & WINTINI_RDY) {
+ RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+ "Polling FW ready success!! "
+ "REG_MCUFWDL:0x%08x .\n",
+ value32);
+ err = 0;
+ goto exit;
+ }
+ udelay(FW_8192C_POLLING_DELAY);
+
+ } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
+
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n",
+ value32);
+
+exit:
+ return err;
+}
+EXPORT_SYMBOL_GPL(rtl8723_fw_free_to_go);
+
+int rtl8723_download_fw(struct ieee80211_hw *hw,
+ bool is_8723be)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl92c_firmware_header *pfwheader;
+ u8 *pfwdata;
+ u32 fwsize;
+ int err;
+ enum version_8723e version = rtlhal->version;
+
+ if (!rtlhal->pfirmware)
+ return 1;
+
+ pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
+ pfwdata = rtlhal->pfirmware;
+ fwsize = rtlhal->fwsize;
+ RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
+ "normal Firmware SIZE %d\n", fwsize);
+
+ if (rtlpriv->cfg->ops->is_fw_header(pfwheader)) {
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+ "Firmware Version(%d), Signature(%#x), Size(%d)\n",
+ pfwheader->version, pfwheader->signature,
+ (int)sizeof(struct rtl92c_firmware_header));
+
+ pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
+ fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
+ }
+ if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
+ rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
+ if (is_8723be)
+ rtl8723be_firmware_selfreset(hw);
+ else
+ rtl8723ae_firmware_selfreset(hw);
+ }
+ rtl8723_enable_fw_download(hw, true);
+ rtl8723_write_fw(hw, version, pfwdata, fwsize);
+ rtl8723_enable_fw_download(hw, false);
+
+ err = rtl8723_fw_free_to_go(hw, is_8723be);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Firmware is not ready to run!\n");
+ } else {
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+ "Firmware is ready to run!\n");
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rtl8723_download_fw);
+
+bool rtl8723_cmd_send_packet(struct ieee80211_hw *hw,
+ struct sk_buff *skb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl8192_tx_ring *ring;
+ struct rtl_tx_desc *pdesc;
+ struct sk_buff *pskb = NULL;
+ u8 own;
+ unsigned long flags;
+
+ ring = &rtlpci->tx_ring[BEACON_QUEUE];
+
+ pskb = __skb_dequeue(&ring->queue);
+ if (pskb)
+ kfree_skb(pskb);
+
+ spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+
+ pdesc = &ring->desc[0];
+ own = (u8) rtlpriv->cfg->ops->get_desc((u8 *)pdesc, true, HW_DESC_OWN);
+
+ rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb);
+
+ __skb_queue_tail(&ring->queue, skb);
+
+ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+
+ rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(rtl8723_cmd_send_packet);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h
new file mode 100644
index 000000000000..cf1cc5804d06
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h
@@ -0,0 +1,126 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __FW_COMMON_H__
+#define __FW_COMMON_H__
+
+#define REG_SYS_FUNC_EN 0x0002
+#define REG_MCUFWDL 0x0080
+#define FW_8192C_START_ADDRESS 0x1000
+#define FW_8192C_PAGE_SIZE 4096
+#define FW_8192C_POLLING_TIMEOUT_COUNT 6000
+#define FW_8192C_POLLING_DELAY 5
+
+#define MCUFWDL_RDY BIT(1)
+#define FWDL_CHKSUM_RPT BIT(2)
+#define WINTINI_RDY BIT(6)
+
+#define REG_RSV_CTRL 0x001C
+#define REG_HMETFR 0x01CC
+
+enum version_8723e {
+ VERSION_TEST_UMC_CHIP_8723 = 0x0081,
+ VERSION_NORMAL_UMC_CHIP_8723_1T1R_A_CUT = 0x0089,
+ VERSION_NORMAL_UMC_CHIP_8723_1T1R_B_CUT = 0x1089,
+ VERSION_TEST_CHIP_1T1R_8723B = 0x0106,
+ VERSION_NORMAL_SMIC_CHIP_1T1R_8723B = 0x010E,
+ VERSION_UNKNOWN = 0xFF,
+};
+
+enum rtl8723ae_h2c_cmd {
+ H2C_AP_OFFLOAD = 0,
+ H2C_SETPWRMODE = 1,
+ H2C_JOINBSSRPT = 2,
+ H2C_RSVDPAGE = 3,
+ H2C_RSSI_REPORT = 4,
+ H2C_P2P_PS_CTW_CMD = 5,
+ H2C_P2P_PS_OFFLOAD = 6,
+ H2C_RA_MASK = 7,
+ MAX_H2CCMD
+};
+
+enum rtl8723be_cmd {
+ H2C_8723BE_RSVDPAGE = 0,
+ H2C_8723BE_JOINBSSRPT = 1,
+ H2C_8723BE_SCAN = 2,
+ H2C_8723BE_KEEP_ALIVE_CTRL = 3,
+ H2C_8723BE_DISCONNECT_DECISION = 4,
+ H2C_8723BE_INIT_OFFLOAD = 6,
+ H2C_8723BE_AP_OFFLOAD = 8,
+ H2C_8723BE_BCN_RSVDPAGE = 9,
+ H2C_8723BE_PROBERSP_RSVDPAGE = 10,
+
+ H2C_8723BE_SETPWRMODE = 0x20,
+ H2C_8723BE_PS_TUNING_PARA = 0x21,
+ H2C_8723BE_PS_TUNING_PARA2 = 0x22,
+ H2C_8723BE_PS_LPS_PARA = 0x23,
+ H2C_8723BE_P2P_PS_OFFLOAD = 0x24,
+
+ H2C_8723BE_WO_WLAN = 0x80,
+ H2C_8723BE_REMOTE_WAKE_CTRL = 0x81,
+ H2C_8723BE_AOAC_GLOBAL_INFO = 0x82,
+ H2C_8723BE_AOAC_RSVDPAGE = 0x83,
+ H2C_8723BE_RSSI_REPORT = 0x42,
+ H2C_8723BE_RA_MASK = 0x40,
+ H2C_8723BE_SELECTIVE_SUSPEND_ROF_CMD,
+ H2C_8723BE_P2P_PS_MODE,
+ H2C_8723BE_PSD_RESULT,
+ /*Not defined CTW CMD for P2P yet*/
+ H2C_8723BE_P2P_PS_CTW_CMD,
+ MAX_8723BE_H2CCMD
+};
+
+struct rtl92c_firmware_header {
+ u16 signature;
+ u8 category;
+ u8 function;
+ u16 version;
+ u8 subversion;
+ u8 rsvd1;
+ u8 month;
+ u8 date;
+ u8 hour;
+ u8 minute;
+ u16 ramcodesize;
+ u16 rsvd2;
+ u32 svnindex;
+ u32 rsvd3;
+ u32 rsvd4;
+ u32 rsvd5;
+};
+
+void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw);
+void rtl8723be_firmware_selfreset(struct ieee80211_hw *hw);
+void rtl8723_enable_fw_download(struct ieee80211_hw *hw, bool enable);
+void rtl8723_fw_block_write(struct ieee80211_hw *hw,
+ const u8 *buffer, u32 size);
+void rtl8723_fw_page_write(struct ieee80211_hw *hw,
+ u32 page, const u8 *buffer, u32 size);
+void rtl8723_write_fw(struct ieee80211_hw *hw,
+ enum version_8723e version,
+ u8 *buffer, u32 size);
+int rtl8723_fw_free_to_go(struct ieee80211_hw *hw, bool is_8723be);
+int rtl8723_download_fw(struct ieee80211_hw *hw, bool is_8723be);
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/main.c b/drivers/net/wireless/rtlwifi/rtl8723com/main.c
new file mode 100644
index 000000000000..9014a94fac6a
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723com/main.c
@@ -0,0 +1,33 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include <linux/module.h>
+
+
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek RTL8723AE/RTL8723BE 802.11n PCI wireless common routines");
diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.c
new file mode 100644
index 000000000000..d73b659bd2b5
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.c
@@ -0,0 +1,434 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "phy_common.h"
+#include "../rtl8723ae/reg.h"
+#include <linux/module.h>
+
+/* These routines are common to RTL8723AE and RTL8723bE */
+
+u32 rtl8723_phy_query_bb_reg(struct ieee80211_hw *hw,
+ u32 regaddr, u32 bitmask)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 returnvalue, originalvalue, bitshift;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), bitmask(%#x)\n", regaddr, bitmask);
+ originalvalue = rtl_read_dword(rtlpriv, regaddr);
+ bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
+ returnvalue = (originalvalue & bitmask) >> bitshift;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "BBR MASK = 0x%x Addr[0x%x]= 0x%x\n",
+ bitmask, regaddr, originalvalue);
+
+ return returnvalue;
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_query_bb_reg);
+
+void rtl8723_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr,
+ u32 bitmask, u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 originalvalue, bitshift;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), bitmask(%#x), data(%#x)\n",
+ regaddr, bitmask, data);
+
+ if (bitmask != MASKDWORD) {
+ originalvalue = rtl_read_dword(rtlpriv, regaddr);
+ bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
+ data = ((originalvalue & (~bitmask)) | (data << bitshift));
+ }
+
+ rtl_write_dword(rtlpriv, regaddr, data);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), bitmask(%#x), data(%#x)\n",
+ regaddr, bitmask, data);
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_set_bb_reg);
+
+u32 rtl8723_phy_calculate_bit_shift(u32 bitmask)
+{
+ u32 i;
+
+ for (i = 0; i <= 31; i++) {
+ if (((bitmask >> i) & 0x1) == 1)
+ break;
+ }
+ return i;
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_calculate_bit_shift);
+
+u32 rtl8723_phy_rf_serial_read(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
+ u32 newoffset;
+ u32 tmplong, tmplong2;
+ u8 rfpi_enable = 0;
+ u32 retvalue;
+
+ offset &= 0xff;
+ newoffset = offset;
+ if (RT_CANNOT_IO(hw)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "return all one\n");
+ return 0xFFFFFFFF;
+ }
+ tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD);
+ if (rfpath == RF90_PATH_A)
+ tmplong2 = tmplong;
+ else
+ tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD);
+ tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) |
+ (newoffset << 23) | BLSSIREADEDGE;
+ rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
+ tmplong & (~BLSSIREADEDGE));
+ mdelay(1);
+ rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2);
+ mdelay(2);
+ if (rfpath == RF90_PATH_A)
+ rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1,
+ BIT(8));
+ else if (rfpath == RF90_PATH_B)
+ rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1,
+ BIT(8));
+ if (rfpi_enable)
+ retvalue = rtl_get_bbreg(hw, pphyreg->rf_rbpi,
+ BLSSIREADBACKDATA);
+ else
+ retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb,
+ BLSSIREADBACKDATA);
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "RFR-%d Addr[0x%x]= 0x%x\n",
+ rfpath, pphyreg->rf_rb, retvalue);
+ return retvalue;
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_rf_serial_read);
+
+void rtl8723_phy_rf_serial_write(struct ieee80211_hw *hw,
+ enum radio_path rfpath,
+ u32 offset, u32 data)
+{
+ u32 data_and_addr;
+ u32 newoffset;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
+
+ if (RT_CANNOT_IO(hw)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "stop\n");
+ return;
+ }
+ offset &= 0xff;
+ newoffset = offset;
+ data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff;
+ rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr);
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "RFW-%d Addr[0x%x]= 0x%x\n", rfpath,
+ pphyreg->rf3wire_offset, data_and_addr);
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_rf_serial_write);
+
+long rtl8723_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
+ enum wireless_mode wirelessmode,
+ u8 txpwridx)
+{
+ long offset;
+ long pwrout_dbm;
+
+ switch (wirelessmode) {
+ case WIRELESS_MODE_B:
+ offset = -7;
+ break;
+ case WIRELESS_MODE_G:
+ case WIRELESS_MODE_N_24G:
+ default:
+ offset = -8;
+ break;
+ }
+ pwrout_dbm = txpwridx / 2 + offset;
+ return pwrout_dbm;
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_txpwr_idx_to_dbm);
+
+void rtl8723_phy_init_bb_rf_reg_def(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+ rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+ rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW;
+ rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfintfi = RFPGA0_XAB_RFINTERFACERB;
+ rtlphy->phyreg_def[RF90_PATH_B].rfintfi = RFPGA0_XAB_RFINTERFACERB;
+ rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB;
+ rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE;
+ rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE;
+ rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset =
+ RFPGA0_XA_LSSIPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset =
+ RFPGA0_XB_LSSIPARAMETER;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = rFPGA0_XAB_RFPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = rFPGA0_XAB_RFPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = rFPGA0_XCD_RFPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = rFPGA0_XCD_RFPARAMETER;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+ rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+ rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+ rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1;
+ rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2;
+ rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
+ rtlphy->phyreg_def[RF90_PATH_B].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
+ rtlphy->phyreg_def[RF90_PATH_C].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
+ rtlphy->phyreg_def[RF90_PATH_D].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1;
+ rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1;
+ rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1;
+ rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfagc_control2 = ROFDM0_XAAGCCORE2;
+ rtlphy->phyreg_def[RF90_PATH_B].rfagc_control2 = ROFDM0_XBAGCCORE2;
+ rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2;
+ rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbal = ROFDM0_XARXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbal = ROFDM0_XBRXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbal = ROFDM0_XCRXIQIMBANLANCE;
+ rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbal = ROFDM0_XDRXIQIMBALANCE;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE;
+ rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE;
+ rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE;
+ rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbal = ROFDM0_XATXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbal = ROFDM0_XBTXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbal = ROFDM0_XCTXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbal = ROFDM0_XDTXIQIMBALANCE;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE;
+ rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTXAFE;
+ rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTXAFE;
+ rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rf_rb = RFPGA0_XA_LSSIREADBACK;
+ rtlphy->phyreg_def[RF90_PATH_B].rf_rb = RFPGA0_XB_LSSIREADBACK;
+ rtlphy->phyreg_def[RF90_PATH_C].rf_rb = RFPGA0_XC_LSSIREADBACK;
+ rtlphy->phyreg_def[RF90_PATH_D].rf_rb = RFPGA0_XD_LSSIREADBACK;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rf_rbpi = TRANSCEIVEA_HSPI_READBACK;
+ rtlphy->phyreg_def[RF90_PATH_B].rf_rbpi = TRANSCEIVEB_HSPI_READBACK;
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_init_bb_rf_reg_def);
+
+bool rtl8723_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
+ u32 cmdtableidx,
+ u32 cmdtablesz,
+ enum swchnlcmd_id cmdid,
+ u32 para1, u32 para2,
+ u32 msdelay)
+{
+ struct swchnlcmd *pcmd;
+
+ if (cmdtable == NULL) {
+ RT_ASSERT(false, "cmdtable cannot be NULL.\n");
+ return false;
+ }
+
+ if (cmdtableidx >= cmdtablesz)
+ return false;
+
+ pcmd = cmdtable + cmdtableidx;
+ pcmd->cmdid = cmdid;
+ pcmd->para1 = para1;
+ pcmd->para2 = para2;
+ pcmd->msdelay = msdelay;
+ return true;
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_set_sw_chnl_cmdarray);
+
+void rtl8723_phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw,
+ bool iqk_ok,
+ long result[][8],
+ u8 final_candidate,
+ bool btxonly)
+{
+ u32 oldval_0, x, tx0_a, reg;
+ long y, tx0_c;
+
+ if (final_candidate == 0xFF) {
+ return;
+ } else if (iqk_ok) {
+ oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
+ MASKDWORD) >> 22) & 0x3FF;
+ x = result[final_candidate][0];
+ if ((x & 0x00000200) != 0)
+ x = x | 0xFFFFFC00;
+ tx0_a = (x * oldval_0) >> 8;
+ rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x3FF, tx0_a);
+ rtl_set_bbreg(hw, 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;
+ rtl_set_bbreg(hw, ROFDM0_XCTXAFE, 0xF0000000,
+ ((tx0_c & 0x3C0) >> 6));
+ rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x003F0000,
+ (tx0_c & 0x3F));
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(29),
+ ((y * oldval_0 >> 7) & 0x1));
+ if (btxonly)
+ return;
+ reg = result[final_candidate][2];
+ rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0x3FF, reg);
+ reg = result[final_candidate][3] & 0x3F;
+ rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0xFC00, reg);
+ reg = (result[final_candidate][3] >> 6) & 0xF;
+ rtl_set_bbreg(hw, 0xca0, 0xF0000000, reg);
+ }
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_path_a_fill_iqk_matrix);
+
+void rtl8723_save_adda_registers(struct ieee80211_hw *hw, u32 *addareg,
+ u32 *addabackup, u32 registernum)
+{
+ u32 i;
+
+ for (i = 0; i < registernum; i++)
+ addabackup[i] = rtl_get_bbreg(hw, addareg[i], MASKDWORD);
+}
+EXPORT_SYMBOL_GPL(rtl8723_save_adda_registers);
+
+void rtl8723_phy_save_mac_registers(struct ieee80211_hw *hw,
+ u32 *macreg, u32 *macbackup)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 i;
+
+ for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++)
+ macbackup[i] = rtl_read_byte(rtlpriv, macreg[i]);
+ macbackup[i] = rtl_read_dword(rtlpriv, macreg[i]);
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_save_mac_registers);
+
+void rtl8723_phy_reload_adda_registers(struct ieee80211_hw *hw,
+ u32 *addareg, u32 *addabackup,
+ u32 regiesternum)
+{
+ u32 i;
+
+ for (i = 0; i < regiesternum; i++)
+ rtl_set_bbreg(hw, addareg[i], MASKDWORD, addabackup[i]);
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_reload_adda_registers);
+
+void rtl8723_phy_reload_mac_registers(struct ieee80211_hw *hw,
+ u32 *macreg, u32 *macbackup)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 i;
+
+ for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++)
+ rtl_write_byte(rtlpriv, macreg[i], (u8) macbackup[i]);
+ rtl_write_dword(rtlpriv, macreg[i], macbackup[i]);
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_reload_mac_registers);
+
+void rtl8723_phy_path_adda_on(struct ieee80211_hw *hw, u32 *addareg,
+ bool is_patha_on, bool is2t)
+{
+ u32 pathon;
+ u32 i;
+
+ pathon = is_patha_on ? 0x04db25a4 : 0x0b1b25a4;
+ if (!is2t) {
+ pathon = 0x0bdb25a0;
+ rtl_set_bbreg(hw, addareg[0], MASKDWORD, 0x0b1b25a0);
+ } else {
+ rtl_set_bbreg(hw, addareg[0], MASKDWORD, pathon);
+ }
+
+ for (i = 1; i < IQK_ADDA_REG_NUM; i++)
+ rtl_set_bbreg(hw, addareg[i], MASKDWORD, pathon);
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_path_adda_on);
+
+void rtl8723_phy_mac_setting_calibration(struct ieee80211_hw *hw,
+ u32 *macreg, u32 *macbackup)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 i = 0;
+
+ rtl_write_byte(rtlpriv, macreg[i], 0x3F);
+
+ for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++)
+ rtl_write_byte(rtlpriv, macreg[i],
+ (u8) (macbackup[i] & (~BIT(3))));
+ rtl_write_byte(rtlpriv, macreg[i], (u8) (macbackup[i] & (~BIT(5))));
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_mac_setting_calibration);
+
+void rtl8723_phy_path_a_standby(struct ieee80211_hw *hw)
+{
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x0);
+ rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000);
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_path_a_standby);
+
+void rtl8723_phy_pi_mode_switch(struct ieee80211_hw *hw, bool pi_mode)
+{
+ u32 mode;
+
+ mode = pi_mode ? 0x01000100 : 0x01000000;
+ rtl_set_bbreg(hw, 0x820, MASKDWORD, mode);
+ rtl_set_bbreg(hw, 0x828, MASKDWORD, mode);
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_pi_mode_switch);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.h b/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.h
new file mode 100644
index 000000000000..83b891a9adb8
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.h
@@ -0,0 +1,89 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __PHY_COMMON__
+#define __PHY_COMMON__
+
+#define RT_CANNOT_IO(hw) false
+
+enum swchnlcmd_id {
+ CMDID_END,
+ CMDID_SET_TXPOWEROWER_LEVEL,
+ CMDID_BBREGWRITE10,
+ CMDID_WRITEPORT_ULONG,
+ CMDID_WRITEPORT_USHORT,
+ CMDID_WRITEPORT_UCHAR,
+ CMDID_RF_WRITEREG,
+};
+
+struct swchnlcmd {
+ enum swchnlcmd_id cmdid;
+ u32 para1;
+ u32 para2;
+ u32 msdelay;
+};
+
+u32 rtl8723_phy_query_bb_reg(struct ieee80211_hw *hw,
+ u32 regaddr, u32 bitmask);
+void rtl8723_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr,
+ u32 bitmask, u32 data);
+u32 rtl8723_phy_calculate_bit_shift(u32 bitmask);
+u32 rtl8723_phy_rf_serial_read(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset);
+void rtl8723_phy_rf_serial_write(struct ieee80211_hw *hw,
+ enum radio_path rfpath,
+ u32 offset, u32 data);
+long rtl8723_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
+ enum wireless_mode wirelessmode,
+ u8 txpwridx);
+void rtl8723_phy_init_bb_rf_reg_def(struct ieee80211_hw *hw);
+bool rtl8723_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
+ u32 cmdtableidx,
+ u32 cmdtablesz,
+ enum swchnlcmd_id cmdid,
+ u32 para1, u32 para2,
+ u32 msdelay);
+void rtl8723_phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw,
+ bool iqk_ok,
+ long result[][8],
+ u8 final_candidate,
+ bool btxonly);
+void rtl8723_save_adda_registers(struct ieee80211_hw *hw, u32 *addareg,
+ u32 *addabackup, u32 registernum);
+void rtl8723_phy_save_mac_registers(struct ieee80211_hw *hw,
+ u32 *macreg, u32 *macbackup);
+void rtl8723_phy_reload_adda_registers(struct ieee80211_hw *hw,
+ u32 *addareg, u32 *addabackup,
+ u32 regiesternum);
+void rtl8723_phy_reload_mac_registers(struct ieee80211_hw *hw,
+ u32 *macreg, u32 *macbackup);
+void rtl8723_phy_path_adda_on(struct ieee80211_hw *hw, u32 *addareg,
+ bool is_patha_on, bool is2t);
+void rtl8723_phy_mac_setting_calibration(struct ieee80211_hw *hw,
+ u32 *macreg, u32 *macbackup);
+void rtl8723_phy_path_a_standby(struct ieee80211_hw *hw);
+void rtl8723_phy_pi_mode_switch(struct ieee80211_hw *hw, bool pi_mode);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c
index 4933f02ce1d5..0398d3ea15b0 100644
--- a/drivers/net/wireless/rtlwifi/usb.c
+++ b/drivers/net/wireless/rtlwifi/usb.c
@@ -410,7 +410,7 @@ static void rtl_usb_init_sw(struct ieee80211_hw *hw)
mac->current_ampdu_factor = 3;
/* QOS */
- rtlusb->acm_method = eAcmWay2_SW;
+ rtlusb->acm_method = EACMWAY2_SW;
/* IRQ */
/* HIMR - turn all on */
@@ -994,7 +994,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw,
seq_number += 1;
seq_number <<= 4;
}
- rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, info, sta, skb,
+ rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, NULL, info, sta, skb,
hw_queue, &tcb_desc);
if (!ieee80211_has_morefrags(hdr->frame_control)) {
if (qc)
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index 8c647391bedf..6965afdf572a 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -41,6 +41,38 @@
#include <linux/completion.h>
#include "debug.h"
+#define MASKBYTE0 0xff
+#define MASKBYTE1 0xff00
+#define MASKBYTE2 0xff0000
+#define MASKBYTE3 0xff000000
+#define MASKHWORD 0xffff0000
+#define MASKLWORD 0x0000ffff
+#define MASKDWORD 0xffffffff
+#define MASK12BITS 0xfff
+#define MASKH4BITS 0xf0000000
+#define MASKOFDM_D 0xffc00000
+#define MASKCCK 0x3f3f3f3f
+
+#define MASK4BITS 0x0f
+#define MASK20BITS 0xfffff
+#define RFREG_OFFSET_MASK 0xfffff
+
+#define MASKBYTE0 0xff
+#define MASKBYTE1 0xff00
+#define MASKBYTE2 0xff0000
+#define MASKBYTE3 0xff000000
+#define MASKHWORD 0xffff0000
+#define MASKLWORD 0x0000ffff
+#define MASKDWORD 0xffffffff
+#define MASK12BITS 0xfff
+#define MASKH4BITS 0xf0000000
+#define MASKOFDM_D 0xffc00000
+#define MASKCCK 0x3f3f3f3f
+
+#define MASK4BITS 0x0f
+#define MASK20BITS 0xfffff
+#define RFREG_OFFSET_MASK 0xfffff
+
#define RF_CHANGE_BY_INIT 0
#define RF_CHANGE_BY_IPS BIT(28)
#define RF_CHANGE_BY_PS BIT(29)
@@ -49,6 +81,7 @@
#define IQK_ADDA_REG_NUM 16
#define IQK_MAC_REG_NUM 4
+#define IQK_THRESHOLD 8
#define MAX_KEY_LEN 61
#define KEY_BUF_SIZE 5
@@ -86,7 +119,18 @@
#define MAC80211_4ADDR_LEN 30
#define CHANNEL_MAX_NUMBER (14 + 24 + 21) /* 14 is the max channel no */
+#define CHANNEL_MAX_NUMBER_2G 14
+#define CHANNEL_MAX_NUMBER_5G 54 /* Please refer to
+ *"phy_GetChnlGroup8812A" and
+ * "Hal_ReadTxPowerInfo8812A"
+ */
+#define CHANNEL_MAX_NUMBER_5G_80M 7
#define CHANNEL_GROUP_MAX (3 + 9) /* ch1~3, 4~9, 10~14 = three groups */
+#define CHANNEL_MAX_NUMBER_5G 54 /* Please refer to
+ *"phy_GetChnlGroup8812A" and
+ * "Hal_ReadTxPowerInfo8812A"
+ */
+#define CHANNEL_MAX_NUMBER_5G_80M 7
#define MAX_PG_GROUP 13
#define CHANNEL_GROUP_MAX_2G 3
#define CHANNEL_GROUP_IDX_5GL 3
@@ -96,6 +140,7 @@
#define CHANNEL_MAX_NUMBER_2G 14
#define AVG_THERMAL_NUM 8
#define AVG_THERMAL_NUM_88E 4
+#define AVG_THERMAL_NUM_8723BE 4
#define MAX_TID_COUNT 9
/* for early mode */
@@ -107,6 +152,24 @@
#define MAX_CHNL_GROUP_24G 6
#define MAX_CHNL_GROUP_5G 14
+#define TX_PWR_BY_RATE_NUM_BAND 2
+#define TX_PWR_BY_RATE_NUM_RF 4
+#define TX_PWR_BY_RATE_NUM_SECTION 12
+#define MAX_BASE_NUM_IN_PHY_REG_PG_24G 6
+#define MAX_BASE_NUM_IN_PHY_REG_PG_5G 5
+
+#define RTL8192EE_SEG_NUM 1 /* 0:2 seg, 1: 4 seg, 2: 8 seg */
+
+#define DEL_SW_IDX_SZ 30
+#define BAND_NUM 3
+
+enum rf_tx_num {
+ RF_1TX = 0,
+ RF_2TX,
+ RF_MAX_TX_NUM,
+ RF_TX_NUM_NONIMPLEMENT,
+};
+
struct txpower_info_2g {
u8 index_cck_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
@@ -115,6 +178,8 @@ struct txpower_info_2g {
u8 ofdm_diff[MAX_RF_PATH][MAX_TX_COUNT];
u8 bw20_diff[MAX_RF_PATH][MAX_TX_COUNT];
u8 bw40_diff[MAX_RF_PATH][MAX_TX_COUNT];
+ u8 bw80_diff[MAX_RF_PATH][MAX_TX_COUNT];
+ u8 bw160_diff[MAX_RF_PATH][MAX_TX_COUNT];
};
struct txpower_info_5g {
@@ -123,6 +188,17 @@ struct txpower_info_5g {
u8 ofdm_diff[MAX_RF_PATH][MAX_TX_COUNT];
u8 bw20_diff[MAX_RF_PATH][MAX_TX_COUNT];
u8 bw40_diff[MAX_RF_PATH][MAX_TX_COUNT];
+ u8 bw80_diff[MAX_RF_PATH][MAX_TX_COUNT];
+ u8 bw160_diff[MAX_RF_PATH][MAX_TX_COUNT];
+};
+
+enum rate_section {
+ CCK = 0,
+ OFDM,
+ HT_MCS0_MCS7,
+ HT_MCS8_MCS15,
+ VHT_1SSMCS0_1SSMCS9,
+ VHT_2SSMCS0_2SSMCS9,
};
enum intf_type {
@@ -158,7 +234,10 @@ enum hardware_type {
HARDWARE_TYPE_RTL8192DU,
HARDWARE_TYPE_RTL8723AE,
HARDWARE_TYPE_RTL8723U,
+ HARDWARE_TYPE_RTL8723BE,
HARDWARE_TYPE_RTL8188EE,
+ HARDWARE_TYPE_RTL8821AE,
+ HARDWARE_TYPE_RTL8812AE,
/* keep it last */
HARDWARE_TYPE_NUM
@@ -195,8 +274,16 @@ enum hardware_type {
_pdesc->rxmcs == DESC92_RATE5_5M || \
_pdesc->rxmcs == DESC92_RATE11M)
+#define RTL8723E_RX_HAL_IS_CCK_RATE(rxmcs) \
+ ((rxmcs) == DESC92_RATE1M || \
+ (rxmcs) == DESC92_RATE2M || \
+ (rxmcs) == DESC92_RATE5_5M || \
+ (rxmcs) == DESC92_RATE11M)
+
enum scan_operation_backup_opt {
SCAN_OPT_BACKUP = 0,
+ SCAN_OPT_BACKUP_BAND0 = 0,
+ SCAN_OPT_BACKUP_BAND1,
SCAN_OPT_RESTORE,
SCAN_OPT_MAX
};
@@ -231,7 +318,9 @@ struct bb_reg_def {
enum io_type {
IO_CMD_PAUSE_DM_BY_SCAN = 0,
- IO_CMD_RESUME_DM_BY_SCAN = 1,
+ IO_CMD_PAUSE_BAND0_DM_BY_SCAN = 0,
+ IO_CMD_PAUSE_BAND1_DM_BY_SCAN = 1,
+ IO_CMD_RESUME_DM_BY_SCAN = 2,
};
enum hw_variables {
@@ -298,6 +387,7 @@ enum hw_variables {
HW_VAR_SET_RPWM,
HW_VAR_H2C_FW_PWRMODE,
HW_VAR_H2C_FW_JOINBSSRPT,
+ HW_VAR_H2C_FW_MEDIASTATUSRPT,
HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
HW_VAR_FW_PSMODE_STATUS,
HW_VAR_RESUME_CLK_ON,
@@ -330,6 +420,8 @@ enum hw_variables {
HAL_DEF_WOWLAN,
HW_VAR_MRC,
+ HW_VAR_KEEP_ALIVE,
+ HW_VAR_NAV_UPPER,
HW_VAR_MGT_FILTER,
HW_VAR_CTRL_FILTER,
@@ -348,34 +440,34 @@ enum rt_oem_id {
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_819X_CAMEO = 6,
+ RT_CID_819X_RUNTOP = 7,
+ RT_CID_819X_SENAO = 8,
RT_CID_TOSHIBA = 9,
- RT_CID_819x_Netcore = 10,
- RT_CID_Nettronix = 11,
+ RT_CID_819X_NETCORE = 10,
+ RT_CID_NETTRONIX = 11,
RT_CID_DLINK = 12,
RT_CID_PRONET = 13,
RT_CID_COREGA = 14,
- RT_CID_819x_ALPHA = 15,
- RT_CID_819x_Sitecom = 16,
+ RT_CID_819X_ALPHA = 15,
+ RT_CID_819X_SITECOM = 16,
RT_CID_CCX = 17,
- RT_CID_819x_Lenovo = 18,
- RT_CID_819x_QMI = 19,
- RT_CID_819x_Edimax_Belkin = 20,
- RT_CID_819x_Sercomm_Belkin = 21,
- RT_CID_819x_CAMEO1 = 22,
- RT_CID_819x_MSI = 23,
- RT_CID_819x_Acer = 24,
- RT_CID_819x_HP = 27,
- RT_CID_819x_CLEVO = 28,
- RT_CID_819x_Arcadyan_Belkin = 29,
- RT_CID_819x_SAMSUNG = 30,
- RT_CID_819x_WNC_COREGA = 31,
- RT_CID_819x_Foxcoon = 32,
- RT_CID_819x_DELL = 33,
- RT_CID_819x_PRONETS = 34,
- RT_CID_819x_Edimax_ASUS = 35,
+ RT_CID_819X_LENOVO = 18,
+ RT_CID_819X_QMI = 19,
+ RT_CID_819X_EDIMAX_BELKIN = 20,
+ RT_CID_819X_SERCOMM_BELKIN = 21,
+ RT_CID_819X_CAMEO1 = 22,
+ RT_CID_819X_MSI = 23,
+ RT_CID_819X_ACER = 24,
+ RT_CID_819X_HP = 27,
+ RT_CID_819X_CLEVO = 28,
+ RT_CID_819X_ARCADYAN_BELKIN = 29,
+ RT_CID_819X_SAMSUNG = 30,
+ RT_CID_819X_WNC_COREGA = 31,
+ RT_CID_819X_FOXCOON = 32,
+ RT_CID_819X_DELL = 33,
+ RT_CID_819X_PRONETS = 34,
+ RT_CID_819X_EDIMAX_ASUS = 35,
RT_CID_NETGEAR = 36,
RT_CID_PLANEX = 37,
RT_CID_CC_C = 38,
@@ -389,6 +481,7 @@ enum hw_descs {
HW_DESC_RXBUFF_ADDR,
HW_DESC_RXPKT_LEN,
HW_DESC_RXERO,
+ HW_DESC_RX_PREPARE,
};
enum prime_sc {
@@ -407,6 +500,7 @@ enum rf_type {
enum ht_channel_width {
HT_CHANNEL_WIDTH_20 = 0,
HT_CHANNEL_WIDTH_20_40 = 1,
+ HT_CHANNEL_WIDTH_80 = 2,
};
/* Ref: 802.11i sepc D10.0 7.3.2.25.1
@@ -471,6 +565,9 @@ enum rtl_var_map {
MAC_RCR_ACRC32,
MAC_RCR_ACF,
MAC_RCR_AAP,
+ MAC_HIMR,
+ MAC_HIMRE,
+ MAC_HSISR,
/*efuse map */
EFUSE_TEST,
@@ -608,7 +705,7 @@ enum rtl_led_pin {
enum acm_method {
eAcmWay0_SwAndHw = 0,
eAcmWay1_HW = 1,
- eAcmWay2_SW = 2,
+ EACMWAY2_SW = 2,
};
enum macphy_mode {
@@ -645,7 +742,9 @@ enum wireless_mode {
WIRELESS_MODE_G = 0x04,
WIRELESS_MODE_AUTO = 0x08,
WIRELESS_MODE_N_24G = 0x10,
- WIRELESS_MODE_N_5G = 0x20
+ WIRELESS_MODE_N_5G = 0x20,
+ WIRELESS_MODE_AC_5G = 0x40,
+ WIRELESS_MODE_AC_24G = 0x80
};
#define IS_WIRELESS_MODE_A(wirelessmode) \
@@ -669,6 +768,8 @@ enum ratr_table_mode {
RATR_INX_WIRELESS_B = 6,
RATR_INX_WIRELESS_MC = 7,
RATR_INX_WIRELESS_A = 8,
+ RATR_INX_WIRELESS_AC_5N = 8,
+ RATR_INX_WIRELESS_AC_24N = 9,
};
enum rtl_link_state {
@@ -803,8 +904,12 @@ struct wireless_stats {
long signal_strength;
u8 rx_rssi_percentage[4];
+ u8 rx_evm_dbm[4];
u8 rx_evm_percentage[2];
+ u16 rx_cfo_short[4];
+ u16 rx_cfo_tail[4];
+
struct rt_smooth_data ui_rssi;
struct rt_smooth_data ui_link_quality;
};
@@ -817,9 +922,9 @@ struct rate_adaptive {
u32 high_rssi_thresh_for_ra;
u32 high2low_rssi_thresh_for_ra;
u8 low2high_rssi_thresh_for_ra40m;
- u32 low_rssi_thresh_for_ra40M;
+ u32 low_rssi_thresh_for_ra40m;
u8 low2high_rssi_thresh_for_ra20m;
- u32 low_rssi_thresh_for_ra20M;
+ u32 low_rssi_thresh_for_ra20m;
u32 upper_rssi_threshold_ratr;
u32 middleupper_rssi_threshold_ratr;
u32 middle_rssi_threshold_ratr;
@@ -833,6 +938,10 @@ struct rate_adaptive {
u32 ping_rssi_thresh_for_ra;
u32 last_ratr;
u8 pre_ratr_state;
+ u8 ldpc_thres;
+ bool use_ldpc;
+ bool lower_rts_rate;
+ bool is_special_data;
};
struct regd_pair_mapping {
@@ -841,6 +950,16 @@ struct regd_pair_mapping {
u16 reg_2ghz_ctl;
};
+struct dynamic_primary_cca {
+ u8 pricca_flag;
+ u8 intf_flag;
+ u8 intf_type;
+ u8 dup_rts_flag;
+ u8 monitor_flag;
+ u8 ch_offset;
+ u8 mf_state;
+};
+
struct rtl_regulatory {
char alpha2[2];
u16 country_code;
@@ -976,16 +1095,29 @@ struct rtl_phy {
u32 iqk_bb_backup[10];
bool iqk_initialized;
+ bool rfpath_rx_enable[MAX_RF_PATH];
+ u8 reg_837;
/* Dual mac */
bool need_iqk;
struct iqk_matrix_regs iqk_matrix[IQK_MATRIX_SETTINGS_NUM];
bool rfpi_enable;
+ bool iqk_in_progress;
u8 pwrgroup_cnt;
u8 cck_high_power;
/* MAX_PG_GROUP groups of pwr diff by rates */
u32 mcs_offset[MAX_PG_GROUP][16];
+ u32 tx_power_by_rate_offset[TX_PWR_BY_RATE_NUM_BAND]
+ [TX_PWR_BY_RATE_NUM_RF]
+ [TX_PWR_BY_RATE_NUM_RF]
+ [TX_PWR_BY_RATE_NUM_SECTION];
+ u8 txpwr_by_rate_base_24g[TX_PWR_BY_RATE_NUM_RF]
+ [TX_PWR_BY_RATE_NUM_RF]
+ [MAX_BASE_NUM_IN_PHY_REG_PG_24G];
+ u8 txpwr_by_rate_base_5g[TX_PWR_BY_RATE_NUM_RF]
+ [TX_PWR_BY_RATE_NUM_RF]
+ [MAX_BASE_NUM_IN_PHY_REG_PG_5G];
u8 default_initialgain[4];
/* the current Tx power level */
@@ -998,6 +1130,7 @@ struct rtl_phy {
bool apk_done;
u32 reg_rf3c[2]; /* pathA / pathB */
+ u32 backup_rf_0x1a;/*92ee*/
/* bfsync */
u8 framesync;
u32 framesync_c34;
@@ -1006,6 +1139,7 @@ struct rtl_phy {
struct phy_parameters hwparam_tables[MAX_TAB];
u16 rf_pathmap;
+ u8 hw_rof_enable; /*Enable GPIO[9] as WL RF HW PDn source*/
enum rt_polarity_ctl polarity_ctl;
};
@@ -1133,6 +1267,7 @@ struct rtl_mac {
u8 use_cts_protect;
u8 cur_40_prime_sc;
u8 cur_40_prime_sc_bk;
+ u8 cur_80_prime_sc;
u64 tsf;
u8 retry_short;
u8 retry_long;
@@ -1213,6 +1348,7 @@ struct rtl_hal {
bool being_init_adapter;
bool bbrf_ready;
bool mac_func_enable;
+ bool pre_edcca_enable;
struct bt_coexist_8723 hal_coex_8723;
enum intf_type interface;
@@ -1234,6 +1370,7 @@ struct rtl_hal {
/*Reserve page start offset except beacon in TxQ. */
u8 fw_rsvdpage_startoffset;
u8 h2c_txcmd_seq;
+ u8 current_ra_rate;
/* FW Cmd IO related */
u16 fwcmd_iomap;
@@ -1273,6 +1410,9 @@ struct rtl_hal {
bool disable_amsdu_8k;
bool master_of_dmsp;
bool slave_of_dmsp;
+
+ u16 rx_tag;/*for 92ee*/
+ u8 rts_en;
};
struct rtl_security {
@@ -1321,6 +1461,16 @@ struct fast_ant_training {
bool becomelinked;
};
+struct dm_phy_dbg_info {
+ char rx_snrdb[4];
+ u64 num_qry_phy_status;
+ u64 num_qry_phy_status_cck;
+ u64 num_qry_phy_status_ofdm;
+ u16 num_qry_beacon_pkt;
+ u16 num_non_be_pkt;
+ s32 rx_evm[4];
+};
+
struct rtl_dm {
/*PHY status for Dynamic Management */
long entry_min_undec_sm_pwdb;
@@ -1360,29 +1510,84 @@ struct rtl_dm {
u8 txpower_track_control;
bool interrupt_migration;
bool disable_tx_int;
- char ofdm_index[2];
+ char ofdm_index[MAX_RF_PATH];
+ u8 default_ofdm_index;
+ u8 default_cck_index;
char cck_index;
- char delta_power_index;
- char delta_power_index_last;
- char power_index_offset;
+ char delta_power_index[MAX_RF_PATH];
+ char delta_power_index_last[MAX_RF_PATH];
+ char power_index_offset[MAX_RF_PATH];
+ char absolute_ofdm_swing_idx[MAX_RF_PATH];
+ char remnant_ofdm_swing_idx[MAX_RF_PATH];
+ char remnant_cck_idx;
+ bool modify_txagc_flag_path_a;
+ bool modify_txagc_flag_path_b;
+
+ bool one_entry_only;
+ struct dm_phy_dbg_info dbginfo;
+
+ /* Dynamic ATC switch */
+ bool atc_status;
+ bool large_cfo_hit;
+ bool is_freeze;
+ int cfo_tail[2];
+ int cfo_ave_pre;
+ int crystal_cap;
+ u8 cfo_threshold;
+ u32 packet_count;
+ u32 packet_count_pre;
+ u8 tx_rate;
/*88e tx power tracking*/
- u8 swing_idx_ofdm[2];
+ u8 swing_idx_ofdm[MAX_RF_PATH];
u8 swing_idx_ofdm_cur;
- u8 swing_idx_ofdm_base;
+ u8 swing_idx_ofdm_base[MAX_RF_PATH];
bool swing_flag_ofdm;
u8 swing_idx_cck;
u8 swing_idx_cck_cur;
u8 swing_idx_cck_base;
bool swing_flag_cck;
+ char swing_diff_2g;
+ char swing_diff_5g;
+
+ u8 delta_swing_table_idx_24gccka_p[DEL_SW_IDX_SZ];
+ u8 delta_swing_table_idx_24gccka_n[DEL_SW_IDX_SZ];
+ u8 delta_swing_table_idx_24gcckb_p[DEL_SW_IDX_SZ];
+ u8 delta_swing_table_idx_24gcckb_n[DEL_SW_IDX_SZ];
+ u8 delta_swing_table_idx_24ga_p[DEL_SW_IDX_SZ];
+ u8 delta_swing_table_idx_24ga_n[DEL_SW_IDX_SZ];
+ u8 delta_swing_table_idx_24gb_p[DEL_SW_IDX_SZ];
+ u8 delta_swing_table_idx_24gb_n[DEL_SW_IDX_SZ];
+ u8 delta_swing_table_idx_5ga_p[BAND_NUM][DEL_SW_IDX_SZ];
+ u8 delta_swing_table_idx_5ga_n[BAND_NUM][DEL_SW_IDX_SZ];
+ u8 delta_swing_table_idx_5gb_p[BAND_NUM][DEL_SW_IDX_SZ];
+ u8 delta_swing_table_idx_5gb_n[BAND_NUM][DEL_SW_IDX_SZ];
+ u8 delta_swing_table_idx_24ga_p_8188e[DEL_SW_IDX_SZ];
+ u8 delta_swing_table_idx_24ga_n_8188e[DEL_SW_IDX_SZ];
+
/* DMSP */
bool supp_phymode_switch;
+ /* DulMac */
struct fast_ant_training fat_table;
+
+ u8 resp_tx_path;
+ u8 path_sel;
+ u32 patha_sum;
+ u32 pathb_sum;
+ u32 patha_cnt;
+ u32 pathb_cnt;
+
+ u8 pre_channel;
+ u8 *p_channel;
+ u8 linked_interval;
+
+ u64 last_tx_ok_cnt;
+ u64 last_rx_ok_cnt;
};
-#define EFUSE_MAX_LOGICAL_SIZE 256
+#define EFUSE_MAX_LOGICAL_SIZE 512
struct rtl_efuse {
bool autoLoad_ok;
@@ -1422,12 +1627,9 @@ struct rtl_efuse {
u8 eeprom_tssi_5g[3][2]; /* for 5GL/5GM/5GH band. */
u8 eeprom_pwrlimit_ht20[CHANNEL_GROUP_MAX];
u8 eeprom_pwrlimit_ht40[CHANNEL_GROUP_MAX];
- u8 eeprom_chnlarea_txpwr_cck[2][CHANNEL_GROUP_MAX_2G];
- u8 eeprom_chnlarea_txpwr_ht40_1s[2][CHANNEL_GROUP_MAX];
- u8 eprom_chnl_txpwr_ht40_2sdf[2][CHANNEL_GROUP_MAX];
- u8 txpwrlevel_cck[2][CHANNEL_MAX_NUMBER_2G];
- u8 txpwrlevel_ht40_1s[2][CHANNEL_MAX_NUMBER]; /*For HT 40MHZ pwr */
- u8 txpwrlevel_ht40_2s[2][CHANNEL_MAX_NUMBER]; /*For HT 40MHZ pwr */
+ u8 eeprom_chnlarea_txpwr_cck[MAX_RF_PATH][CHANNEL_GROUP_MAX_2G];
+ u8 eeprom_chnlarea_txpwr_ht40_1s[MAX_RF_PATH][CHANNEL_GROUP_MAX];
+ u8 eprom_chnl_txpwr_ht40_2sdf[MAX_RF_PATH][CHANNEL_GROUP_MAX];
u8 internal_pa_5g[2]; /* pathA / pathB */
u8 eeprom_c9;
@@ -1438,9 +1640,38 @@ struct rtl_efuse {
u8 pwrgroup_ht20[2][CHANNEL_MAX_NUMBER];
u8 pwrgroup_ht40[2][CHANNEL_MAX_NUMBER];
- char txpwr_ht20diff[2][CHANNEL_MAX_NUMBER]; /*HT 20<->40 Pwr diff */
- /*For HT<->legacy pwr diff*/
- u8 txpwr_legacyhtdiff[2][CHANNEL_MAX_NUMBER];
+ u8 txpwrlevel_cck[MAX_RF_PATH][CHANNEL_MAX_NUMBER_2G];
+ /*For HT 40MHZ pwr */
+ u8 txpwrlevel_ht40_1s[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+ /*For HT 40MHZ pwr */
+ u8 txpwrlevel_ht40_2s[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+
+ /*--------------------------------------------------------*
+ * 8192CE\8192SE\8192DE\8723AE use the following 4 arrays,
+ * other ICs (8188EE\8723BE\8192EE\8812AE...)
+ * define new arrays in Windows code.
+ * BUT, in linux code, we use the same array for all ICs.
+ *
+ * The Correspondance relation between two arrays is:
+ * txpwr_cckdiff[][] == CCK_24G_Diff[][]
+ * txpwr_ht20diff[][] == BW20_24G_Diff[][]
+ * txpwr_ht40diff[][] == BW40_24G_Diff[][]
+ * txpwr_legacyhtdiff[][] == OFDM_24G_Diff[][]
+ *
+ * Sizes of these arrays are decided by the larger ones.
+ */
+ char txpwr_cckdiff[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+ char txpwr_ht20diff[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+ char txpwr_ht40diff[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+ char txpwr_legacyhtdiff[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+
+ u8 txpwr_5g_bw40base[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+ u8 txpwr_5g_bw80base[MAX_RF_PATH][CHANNEL_MAX_NUMBER_5G_80M];
+ char txpwr_5g_ofdmdiff[MAX_RF_PATH][MAX_TX_COUNT];
+ char txpwr_5g_bw20diff[MAX_RF_PATH][MAX_TX_COUNT];
+ char txpwr_5g_bw40diff[MAX_RF_PATH][MAX_TX_COUNT];
+ char txpwr_5g_bw80diff[MAX_RF_PATH][MAX_TX_COUNT];
+
u8 txpwr_safetyflag; /* Band edge enable flag */
u16 eeprom_txpowerdiff;
u8 legacy_httxpowerdiff; /* Legacy to HT rate power diff */
@@ -1571,7 +1802,9 @@ struct rtl_stats {
bool rx_is40Mhzpacket;
u32 rx_pwdb_all;
u8 rx_mimo_signalstrength[4]; /*in 0~100 index */
- s8 rx_mimo_sig_qual[2];
+ s8 rx_mimo_sig_qual[4];
+ u8 rx_pwr[4]; /* per-path's pwdb */
+ u8 rx_snr[4]; /* per-path's SNR */
bool packet_matchbssid;
bool is_cck;
bool is_ht;
@@ -1644,6 +1877,8 @@ struct rtl_tcb_desc {
bool btx_enable_sw_calc_duration;
};
+struct rtl92c_firmware_header;
+
struct rtl_hal_ops {
int (*init_sw_vars) (struct ieee80211_hw *hw);
void (*deinit_sw_vars) (struct ieee80211_hw *hw);
@@ -1673,9 +1908,17 @@ struct rtl_hal_ops {
void (*set_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val);
void (*update_rate_tbl) (struct ieee80211_hw *hw,
struct ieee80211_sta *sta, u8 rssi_level);
+ void (*pre_fill_tx_bd_desc)(struct ieee80211_hw *hw, u8 *tx_bd_desc,
+ u8 *desc, u8 queue_index,
+ struct sk_buff *skb, dma_addr_t addr);
void (*update_rate_mask) (struct ieee80211_hw *hw, u8 rssi_level);
+ u16 (*rx_desc_buff_remained_cnt)(struct ieee80211_hw *hw,
+ u8 queue_index);
+ void (*rx_check_dma_ok)(struct ieee80211_hw *hw, u8 *header_desc,
+ u8 queue_index);
void (*fill_tx_desc) (struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr, u8 *pdesc_tx,
+ u8 *pbd_desc_tx,
struct ieee80211_tx_info *info,
struct ieee80211_sta *sta,
struct sk_buff *skb, u8 hw_queue,
@@ -1698,8 +1941,11 @@ struct rtl_hal_ops {
enum rf_pwrstate rfpwr_state);
void (*led_control) (struct ieee80211_hw *hw,
enum led_ctl_mode ledaction);
- void (*set_desc) (u8 *pdesc, bool istx, u8 desc_name, u8 *val);
+ void (*set_desc)(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+ u8 desc_name, u8 *val);
u32 (*get_desc) (u8 *pdesc, bool istx, u8 desc_name);
+ bool (*is_tx_desc_closed) (struct ieee80211_hw *hw,
+ u8 hw_queue, u16 index);
void (*tx_polling) (struct ieee80211_hw *hw, u8 hw_queue);
void (*enable_hw_sec) (struct ieee80211_hw *hw);
void (*set_key) (struct ieee80211_hw *hw, u32 key_index,
@@ -1738,6 +1984,10 @@ struct rtl_hal_ops {
void (*bt_coex_off_before_lps) (struct ieee80211_hw *hw);
void (*fill_h2c_cmd) (struct ieee80211_hw *hw, u8 element_id,
u32 cmd_len, u8 *p_cmdbuffer);
+ bool (*get_btc_status) (void);
+ bool (*is_fw_header) (struct rtl92c_firmware_header *hdr);
+ u32 (*rx_command_packet)(struct ieee80211_hw *hw,
+ struct rtl_stats status, struct sk_buff *skb);
};
struct rtl_intf_ops {
@@ -1847,6 +2097,8 @@ struct rtl_locks {
/*Easy concurrent*/
spinlock_t check_sendpkt_lock;
+
+ spinlock_t iqk_lock;
};
struct rtl_works {
@@ -1915,6 +2167,7 @@ struct ps_t {
u8 cur_ccasate;
u8 pre_rfstate;
u8 cur_rfstate;
+ u8 initialize;
long rssi_val_min;
};
@@ -1939,6 +2192,7 @@ struct dig_t {
u8 cursta_cstate;
u8 presta_cstate;
u8 curmultista_cstate;
+ u8 stop_dig;
char back_val;
char back_range_max;
char back_range_min;
@@ -1956,6 +2210,7 @@ struct dig_t {
u8 cur_ccasate;
u8 large_fa_hit;
u8 dig_dynamic_min;
+ u8 dig_dynamic_min_1;
u8 forbidden_igi;
u8 dig_state;
u8 dig_highpwrstate;
@@ -1972,6 +2227,7 @@ struct dig_t {
char backoffval_range_min;
u8 dig_min_0;
u8 dig_min_1;
+ u8 bt30_cur_igi;
bool media_connect_0;
bool media_connect_1;
@@ -1986,6 +2242,96 @@ struct rtl_global_var {
spinlock_t glb_list_lock;
};
+struct rtl_btc_info {
+ u8 bt_type;
+ u8 btcoexist;
+ u8 ant_num;
+};
+
+struct bt_coexist_info {
+ struct rtl_btc_ops *btc_ops;
+ struct rtl_btc_info btc_info;
+ /* EEPROM BT info. */
+ u8 eeprom_bt_coexist;
+ u8 eeprom_bt_type;
+ u8 eeprom_bt_ant_num;
+ u8 eeprom_bt_ant_isol;
+ u8 eeprom_bt_radio_shared;
+
+ u8 bt_coexistence;
+ u8 bt_ant_num;
+ u8 bt_coexist_type;
+ u8 bt_state;
+ u8 bt_cur_state; /* 0:on, 1:off */
+ u8 bt_ant_isolation; /* 0:good, 1:bad */
+ u8 bt_pape_ctrl; /* 0:SW, 1:SW/HW dynamic */
+ u8 bt_service;
+ u8 bt_radio_shared_type;
+ u8 bt_rfreg_origin_1e;
+ u8 bt_rfreg_origin_1f;
+ u8 bt_rssi_state;
+ u32 ratio_tx;
+ u32 ratio_pri;
+ u32 bt_edca_ul;
+ u32 bt_edca_dl;
+
+ bool init_set;
+ bool bt_busy_traffic;
+ bool bt_traffic_mode_set;
+ bool bt_non_traffic_mode_set;
+
+ bool fw_coexist_all_off;
+ bool sw_coexist_all_off;
+ bool hw_coexist_all_off;
+ u32 cstate;
+ u32 previous_state;
+ u32 cstate_h;
+ u32 previous_state_h;
+
+ u8 bt_pre_rssi_state;
+ u8 bt_pre_rssi_state1;
+
+ u8 reg_bt_iso;
+ u8 reg_bt_sco;
+ bool balance_on;
+ u8 bt_active_zero_cnt;
+ bool cur_bt_disabled;
+ bool pre_bt_disabled;
+
+ u8 bt_profile_case;
+ u8 bt_profile_action;
+ bool bt_busy;
+ bool hold_for_bt_operation;
+ u8 lps_counter;
+};
+
+struct rtl_btc_ops {
+ void (*btc_init_variables) (struct rtl_priv *rtlpriv);
+ void (*btc_init_hal_vars) (struct rtl_priv *rtlpriv);
+ void (*btc_init_hw_config) (struct rtl_priv *rtlpriv);
+ void (*btc_ips_notify) (struct rtl_priv *rtlpriv, u8 type);
+ void (*btc_scan_notify) (struct rtl_priv *rtlpriv, u8 scantype);
+ void (*btc_connect_notify) (struct rtl_priv *rtlpriv, u8 action);
+ void (*btc_mediastatus_notify) (struct rtl_priv *rtlpriv,
+ enum _RT_MEDIA_STATUS mstatus);
+ void (*btc_periodical) (struct rtl_priv *rtlpriv);
+ void (*btc_halt_notify) (void);
+ void (*btc_btinfo_notify) (struct rtl_priv *rtlpriv,
+ u8 *tmp_buf, u8 length);
+ bool (*btc_is_limited_dig) (struct rtl_priv *rtlpriv);
+ bool (*btc_is_disable_edca_turbo) (struct rtl_priv *rtlpriv);
+ bool (*btc_is_bt_disabled) (struct rtl_priv *rtlpriv);
+};
+
+struct proxim {
+ bool proxim_on;
+
+ void *proximity_priv;
+ int (*proxim_rx)(struct ieee80211_hw *hw, struct rtl_stats *status,
+ struct sk_buff *skb);
+ u8 (*proxim_get_var)(struct ieee80211_hw *hw, u8 type);
+};
+
struct rtl_priv {
struct ieee80211_hw *hw;
struct completion firmware_loading_complete;
@@ -2008,6 +2354,7 @@ struct rtl_priv {
struct rtl_ps_ctl psc;
struct rate_adaptive ra;
+ struct dynamic_primary_cca primarycca;
struct wireless_stats stats;
struct rt_link_detect link_info;
struct false_alarm_statistics falsealm_cnt;
@@ -2048,6 +2395,20 @@ struct rtl_priv {
bool enter_ps; /* true when entering PS */
u8 rate_mask[5];
+ /* intel Proximity, should be alloc mem
+ * in intel Proximity module and can only
+ * be used in intel Proximity mode
+ */
+ struct proxim proximity;
+
+ /*for bt coexist use*/
+ struct bt_coexist_info btcoexist;
+
+ /* separate 92ee from other ICs,
+ * 92ee use new trx flow.
+ */
+ bool use_new_trx_flow;
+
/*This must be the last item so
that it points to the data allocated
beyond this structure like:
@@ -2079,6 +2440,15 @@ enum bt_co_type {
BT_CSR_BC8 = 4,
BT_RTL8756 = 5,
BT_RTL8723A = 6,
+ BT_RTL8821A = 7,
+ BT_RTL8723B = 8,
+ BT_RTL8192E = 9,
+ BT_RTL8812A = 11,
+};
+
+enum bt_total_ant_num {
+ ANT_TOTAL_X2 = 0,
+ ANT_TOTAL_X1 = 1
};
enum bt_cur_state {
@@ -2104,62 +2474,6 @@ enum bt_radio_shared {
BT_RADIO_INDIVIDUAL = 1,
};
-struct bt_coexist_info {
-
- /* EEPROM BT info. */
- u8 eeprom_bt_coexist;
- u8 eeprom_bt_type;
- u8 eeprom_bt_ant_num;
- u8 eeprom_bt_ant_isol;
- u8 eeprom_bt_radio_shared;
-
- u8 bt_coexistence;
- u8 bt_ant_num;
- u8 bt_coexist_type;
- u8 bt_state;
- u8 bt_cur_state; /* 0:on, 1:off */
- u8 bt_ant_isolation; /* 0:good, 1:bad */
- u8 bt_pape_ctrl; /* 0:SW, 1:SW/HW dynamic */
- u8 bt_service;
- u8 bt_radio_shared_type;
- u8 bt_rfreg_origin_1e;
- u8 bt_rfreg_origin_1f;
- u8 bt_rssi_state;
- u32 ratio_tx;
- u32 ratio_pri;
- u32 bt_edca_ul;
- u32 bt_edca_dl;
-
- bool init_set;
- bool bt_busy_traffic;
- bool bt_traffic_mode_set;
- bool bt_non_traffic_mode_set;
-
- bool fw_coexist_all_off;
- bool sw_coexist_all_off;
- bool hw_coexist_all_off;
- u32 cstate;
- u32 previous_state;
- u32 cstate_h;
- u32 previous_state_h;
-
- u8 bt_pre_rssi_state;
- u8 bt_pre_rssi_state1;
-
- u8 reg_bt_iso;
- u8 reg_bt_sco;
- bool balance_on;
- u8 bt_active_zero_cnt;
- bool cur_bt_disabled;
- bool pre_bt_disabled;
-
- u8 bt_profile_case;
- u8 bt_profile_action;
- bool bt_busy;
- bool hold_for_bt_operation;
- u8 lps_counter;
-};
-
/****************************************
mem access macro define start
diff --git a/drivers/net/wireless/ti/wilink_platform_data.c b/drivers/net/wireless/ti/wilink_platform_data.c
index 998e95895f9d..a92bd3e89796 100644
--- a/drivers/net/wireless/ti/wilink_platform_data.c
+++ b/drivers/net/wireless/ti/wilink_platform_data.c
@@ -23,17 +23,17 @@
#include <linux/err.h>
#include <linux/wl12xx.h>
-static struct wl12xx_platform_data *platform_data;
+static struct wl12xx_platform_data *wl12xx_platform_data;
int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data)
{
- if (platform_data)
+ if (wl12xx_platform_data)
return -EBUSY;
if (!data)
return -EINVAL;
- platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL);
- if (!platform_data)
+ wl12xx_platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL);
+ if (!wl12xx_platform_data)
return -ENOMEM;
return 0;
@@ -41,9 +41,34 @@ int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data)
struct wl12xx_platform_data *wl12xx_get_platform_data(void)
{
- if (!platform_data)
+ if (!wl12xx_platform_data)
return ERR_PTR(-ENODEV);
- return platform_data;
+ return wl12xx_platform_data;
}
EXPORT_SYMBOL(wl12xx_get_platform_data);
+
+static struct wl1251_platform_data *wl1251_platform_data;
+
+int __init wl1251_set_platform_data(const struct wl1251_platform_data *data)
+{
+ if (wl1251_platform_data)
+ return -EBUSY;
+ if (!data)
+ return -EINVAL;
+
+ wl1251_platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL);
+ if (!wl1251_platform_data)
+ return -ENOMEM;
+
+ return 0;
+}
+
+struct wl1251_platform_data *wl1251_get_platform_data(void)
+{
+ if (!wl1251_platform_data)
+ return ERR_PTR(-ENODEV);
+
+ return wl1251_platform_data;
+}
+EXPORT_SYMBOL(wl1251_get_platform_data);
diff --git a/drivers/net/wireless/ti/wl1251/cmd.c b/drivers/net/wireless/ti/wl1251/cmd.c
index 223649bcaa5a..bf1fa18b9786 100644
--- a/drivers/net/wireless/ti/wl1251/cmd.c
+++ b/drivers/net/wireless/ti/wl1251/cmd.c
@@ -448,7 +448,7 @@ int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len,
* Note: This bug may be caused by the fw's DTIM handling.
*/
if (is_zero_ether_addr(wl->bssid))
- cmd->params.scan_options |= WL1251_SCAN_OPT_PRIORITY_HIGH;
+ cmd->params.scan_options |= cpu_to_le16(WL1251_SCAN_OPT_PRIORITY_HIGH);
cmd->params.num_channels = n_channels;
cmd->params.num_probe_requests = n_probes;
cmd->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */
diff --git a/drivers/net/wireless/ti/wl1251/rx.c b/drivers/net/wireless/ti/wl1251/rx.c
index 123c4bb50e0a..cde0eaf99714 100644
--- a/drivers/net/wireless/ti/wl1251/rx.c
+++ b/drivers/net/wireless/ti/wl1251/rx.c
@@ -180,7 +180,7 @@ static void wl1251_rx_body(struct wl1251 *wl,
wl1251_mem_read(wl, rx_packet_ring_addr, rx_buffer, length);
/* The actual length doesn't include the target's alignment */
- skb->len = desc->length - PLCP_HEADER_LENGTH;
+ skb_trim(skb, desc->length - PLCP_HEADER_LENGTH);
fc = (u16 *)skb->data;
diff --git a/drivers/net/wireless/ti/wl1251/sdio.c b/drivers/net/wireless/ti/wl1251/sdio.c
index e2b3d9c541e8..b661f896e9fe 100644
--- a/drivers/net/wireless/ti/wl1251/sdio.c
+++ b/drivers/net/wireless/ti/wl1251/sdio.c
@@ -28,6 +28,7 @@
#include <linux/wl12xx.h>
#include <linux/irq.h>
#include <linux/pm_runtime.h>
+#include <linux/gpio.h>
#include "wl1251.h"
@@ -182,8 +183,9 @@ static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable)
* callback in case it wants to do any additional setup,
* for example enabling clock buffer for the module.
*/
- if (wl->set_power)
- wl->set_power(true);
+ if (gpio_is_valid(wl->power_gpio))
+ gpio_set_value(wl->power_gpio, true);
+
ret = pm_runtime_get_sync(&func->dev);
if (ret < 0) {
@@ -203,8 +205,8 @@ static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable)
if (ret < 0)
goto out;
- if (wl->set_power)
- wl->set_power(false);
+ if (gpio_is_valid(wl->power_gpio))
+ gpio_set_value(wl->power_gpio, false);
}
out:
@@ -227,7 +229,7 @@ static int wl1251_sdio_probe(struct sdio_func *func,
struct wl1251 *wl;
struct ieee80211_hw *hw;
struct wl1251_sdio *wl_sdio;
- const struct wl12xx_platform_data *wl12xx_board_data;
+ const struct wl1251_platform_data *wl1251_board_data;
hw = wl1251_alloc_hw();
if (IS_ERR(hw))
@@ -254,11 +256,20 @@ static int wl1251_sdio_probe(struct sdio_func *func,
wl->if_priv = wl_sdio;
wl->if_ops = &wl1251_sdio_ops;
- wl12xx_board_data = wl12xx_get_platform_data();
- if (!IS_ERR(wl12xx_board_data)) {
- wl->set_power = wl12xx_board_data->set_power;
- wl->irq = wl12xx_board_data->irq;
- wl->use_eeprom = wl12xx_board_data->use_eeprom;
+ wl1251_board_data = wl1251_get_platform_data();
+ if (!IS_ERR(wl1251_board_data)) {
+ wl->power_gpio = wl1251_board_data->power_gpio;
+ wl->irq = wl1251_board_data->irq;
+ wl->use_eeprom = wl1251_board_data->use_eeprom;
+ }
+
+ if (gpio_is_valid(wl->power_gpio)) {
+ ret = devm_gpio_request(&func->dev, wl->power_gpio,
+ "wl1251 power");
+ if (ret) {
+ wl1251_error("Failed to request gpio: %d\n", ret);
+ goto disable;
+ }
}
if (wl->irq) {
diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c
index 1342f81e683d..b06d36d99362 100644
--- a/drivers/net/wireless/ti/wl1251/spi.c
+++ b/drivers/net/wireless/ti/wl1251/spi.c
@@ -26,6 +26,10 @@
#include <linux/crc7.h>
#include <linux/spi/spi.h>
#include <linux/wl12xx.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
#include "wl1251.h"
#include "reg.h"
@@ -221,8 +225,8 @@ static void wl1251_spi_disable_irq(struct wl1251 *wl)
static int wl1251_spi_set_power(struct wl1251 *wl, bool enable)
{
- if (wl->set_power)
- wl->set_power(enable);
+ if (gpio_is_valid(wl->power_gpio))
+ gpio_set_value(wl->power_gpio, enable);
return 0;
}
@@ -238,13 +242,13 @@ static const struct wl1251_if_operations wl1251_spi_ops = {
static int wl1251_spi_probe(struct spi_device *spi)
{
- struct wl12xx_platform_data *pdata;
+ struct wl1251_platform_data *pdata = dev_get_platdata(&spi->dev);
+ struct device_node *np = spi->dev.of_node;
struct ieee80211_hw *hw;
struct wl1251 *wl;
int ret;
- pdata = dev_get_platdata(&spi->dev);
- if (!pdata) {
+ if (!np && !pdata) {
wl1251_error("no platform data");
return -ENODEV;
}
@@ -271,22 +275,42 @@ static int wl1251_spi_probe(struct spi_device *spi)
goto out_free;
}
- wl->set_power = pdata->set_power;
- if (!wl->set_power) {
- wl1251_error("set power function missing in platform data");
- return -ENODEV;
+ if (np) {
+ wl->use_eeprom = of_property_read_bool(np, "ti,wl1251-has-eeprom");
+ wl->power_gpio = of_get_named_gpio(np, "ti,power-gpio", 0);
+ } else if (pdata) {
+ wl->power_gpio = pdata->power_gpio;
+ wl->use_eeprom = pdata->use_eeprom;
+ }
+
+ if (wl->power_gpio == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto out_free;
+ }
+
+ if (gpio_is_valid(wl->power_gpio)) {
+ ret = devm_gpio_request_one(&spi->dev, wl->power_gpio,
+ GPIOF_OUT_INIT_LOW, "wl1251 power");
+ if (ret) {
+ wl1251_error("Failed to request gpio: %d\n", ret);
+ goto out_free;
+ }
+ } else {
+ wl1251_error("set power gpio missing in platform data");
+ ret = -ENODEV;
+ goto out_free;
}
wl->irq = spi->irq;
if (wl->irq < 0) {
wl1251_error("irq missing in platform data");
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_free;
}
- wl->use_eeprom = pdata->use_eeprom;
-
irq_set_status_flags(wl->irq, IRQ_NOAUTOEN);
- ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl);
+ ret = devm_request_irq(&spi->dev, wl->irq, wl1251_irq, 0,
+ DRIVER_NAME, wl);
if (ret < 0) {
wl1251_error("request_irq() failed: %d", ret);
goto out_free;
@@ -294,16 +318,26 @@ static int wl1251_spi_probe(struct spi_device *spi)
irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
+ wl->vio = devm_regulator_get(&spi->dev, "vio");
+ if (IS_ERR(wl->vio)) {
+ ret = PTR_ERR(wl->vio);
+ wl1251_error("vio regulator missing: %d", ret);
+ goto out_free;
+ }
+
+ ret = regulator_enable(wl->vio);
+ if (ret)
+ goto out_free;
+
ret = wl1251_init_ieee80211(wl);
if (ret)
- goto out_irq;
+ goto disable_regulator;
return 0;
- out_irq:
- free_irq(wl->irq, wl);
-
- out_free:
+disable_regulator:
+ regulator_disable(wl->vio);
+out_free:
ieee80211_free_hw(hw);
return ret;
@@ -315,6 +349,7 @@ static int wl1251_spi_remove(struct spi_device *spi)
free_irq(wl->irq, wl);
wl1251_free_hw(wl);
+ regulator_disable(wl->vio);
return 0;
}
diff --git a/drivers/net/wireless/ti/wl1251/wl1251.h b/drivers/net/wireless/ti/wl1251/wl1251.h
index 235617a7716d..16dae5269175 100644
--- a/drivers/net/wireless/ti/wl1251/wl1251.h
+++ b/drivers/net/wireless/ti/wl1251/wl1251.h
@@ -276,10 +276,12 @@ struct wl1251 {
void *if_priv;
const struct wl1251_if_operations *if_ops;
- void (*set_power)(bool enable);
+ int power_gpio;
int irq;
bool use_eeprom;
+ struct regulator *vio;
+
spinlock_t wl_lock;
enum wl1251_state state;
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
index be7129ba16ad..d50dfac91631 100644
--- a/drivers/net/wireless/ti/wl12xx/main.c
+++ b/drivers/net/wireless/ti/wl12xx/main.c
@@ -1378,7 +1378,7 @@ static u32 wl12xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data,
static int wl12xx_tx_delayed_compl(struct wl1271 *wl)
{
- if (wl->fw_status_1->tx_results_counter ==
+ if (wl->fw_status->tx_results_counter ==
(wl->tx_results_count & 0xff))
return 0;
@@ -1438,6 +1438,37 @@ out:
return ret;
}
+static void wl12xx_convert_fw_status(struct wl1271 *wl, void *raw_fw_status,
+ struct wl_fw_status *fw_status)
+{
+ struct wl12xx_fw_status *int_fw_status = raw_fw_status;
+
+ fw_status->intr = le32_to_cpu(int_fw_status->intr);
+ fw_status->fw_rx_counter = int_fw_status->fw_rx_counter;
+ fw_status->drv_rx_counter = int_fw_status->drv_rx_counter;
+ fw_status->tx_results_counter = int_fw_status->tx_results_counter;
+ fw_status->rx_pkt_descs = int_fw_status->rx_pkt_descs;
+
+ fw_status->fw_localtime = le32_to_cpu(int_fw_status->fw_localtime);
+ fw_status->link_ps_bitmap = le32_to_cpu(int_fw_status->link_ps_bitmap);
+ fw_status->link_fast_bitmap =
+ le32_to_cpu(int_fw_status->link_fast_bitmap);
+ fw_status->total_released_blks =
+ le32_to_cpu(int_fw_status->total_released_blks);
+ fw_status->tx_total = le32_to_cpu(int_fw_status->tx_total);
+
+ fw_status->counters.tx_released_pkts =
+ int_fw_status->counters.tx_released_pkts;
+ fw_status->counters.tx_lnk_free_pkts =
+ int_fw_status->counters.tx_lnk_free_pkts;
+ fw_status->counters.tx_voice_released_blks =
+ int_fw_status->counters.tx_voice_released_blks;
+ fw_status->counters.tx_last_rate =
+ int_fw_status->counters.tx_last_rate;
+
+ fw_status->log_start_addr = le32_to_cpu(int_fw_status->log_start_addr);
+}
+
static u32 wl12xx_sta_get_ap_rate_mask(struct wl1271 *wl,
struct wl12xx_vif *wlvif)
{
@@ -1677,6 +1708,7 @@ static struct wlcore_ops wl12xx_ops = {
.tx_delayed_compl = wl12xx_tx_delayed_compl,
.hw_init = wl12xx_hw_init,
.init_vif = NULL,
+ .convert_fw_status = wl12xx_convert_fw_status,
.sta_get_ap_rate_mask = wl12xx_sta_get_ap_rate_mask,
.get_pg_ver = wl12xx_get_pg_ver,
.get_mac = wl12xx_get_mac,
@@ -1711,22 +1743,53 @@ static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
},
};
+static const struct ieee80211_iface_limit wl12xx_iface_limits[] = {
+ {
+ .max = 3,
+ .types = BIT(NL80211_IFTYPE_STATION),
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT),
+ },
+};
+
+static const struct ieee80211_iface_combination
+wl12xx_iface_combinations[] = {
+ {
+ .max_interfaces = 3,
+ .limits = wl12xx_iface_limits,
+ .n_limits = ARRAY_SIZE(wl12xx_iface_limits),
+ .num_different_channels = 1,
+ },
+};
+
static int wl12xx_setup(struct wl1271 *wl)
{
struct wl12xx_priv *priv = wl->priv;
struct wlcore_platdev_data *pdev_data = dev_get_platdata(&wl->pdev->dev);
struct wl12xx_platform_data *pdata = pdev_data->pdata;
+ BUILD_BUG_ON(WL12XX_MAX_LINKS > WLCORE_MAX_LINKS);
+ BUILD_BUG_ON(WL12XX_MAX_AP_STATIONS > WL12XX_MAX_LINKS);
+
wl->rtable = wl12xx_rtable;
wl->num_tx_desc = WL12XX_NUM_TX_DESCRIPTORS;
wl->num_rx_desc = WL12XX_NUM_RX_DESCRIPTORS;
- wl->num_channels = 1;
+ wl->num_links = WL12XX_MAX_LINKS;
+ wl->max_ap_stations = WL12XX_MAX_AP_STATIONS;
+ wl->iface_combinations = wl12xx_iface_combinations;
+ wl->n_iface_combinations = ARRAY_SIZE(wl12xx_iface_combinations);
wl->num_mac_addr = WL12XX_NUM_MAC_ADDRESSES;
wl->band_rate_to_idx = wl12xx_band_rate_to_idx;
wl->hw_tx_rate_tbl_size = WL12XX_CONF_HW_RXTX_RATE_MAX;
wl->hw_min_ht_rate = WL12XX_CONF_HW_RXTX_RATE_MCS0;
+ wl->fw_status_len = sizeof(struct wl12xx_fw_status);
wl->fw_status_priv_len = 0;
wl->stats.fw_stats_len = sizeof(struct wl12xx_acx_statistics);
+ wl->ofdm_only_ap = true;
wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ, &wl12xx_ht_cap);
wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ, &wl12xx_ht_cap);
wl12xx_conf_init(wl);
diff --git a/drivers/net/wireless/ti/wl12xx/wl12xx.h b/drivers/net/wireless/ti/wl12xx/wl12xx.h
index 9e5484a73667..75c92658bfea 100644
--- a/drivers/net/wireless/ti/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h
@@ -65,6 +65,9 @@
#define WL12XX_RX_BA_MAX_SESSIONS 3
+#define WL12XX_MAX_AP_STATIONS 8
+#define WL12XX_MAX_LINKS 12
+
struct wl127x_rx_mem_pool_addr {
u32 addr;
u32 addr_extra;
@@ -79,4 +82,54 @@ struct wl12xx_priv {
struct wl127x_rx_mem_pool_addr *rx_mem_addr;
};
+struct wl12xx_fw_packet_counters {
+ /* Cumulative counter of released packets per AC */
+ u8 tx_released_pkts[NUM_TX_QUEUES];
+
+ /* Cumulative counter of freed packets per HLID */
+ u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS];
+
+ /* Cumulative counter of released Voice memory blocks */
+ u8 tx_voice_released_blks;
+
+ /* Tx rate of the last transmitted packet */
+ u8 tx_last_rate;
+
+ u8 padding[2];
+} __packed;
+
+/* FW status registers */
+struct wl12xx_fw_status {
+ __le32 intr;
+ u8 fw_rx_counter;
+ u8 drv_rx_counter;
+ u8 reserved;
+ u8 tx_results_counter;
+ __le32 rx_pkt_descs[WL12XX_NUM_RX_DESCRIPTORS];
+
+ __le32 fw_localtime;
+
+ /*
+ * A bitmap (where each bit represents a single HLID)
+ * to indicate if the station is in PS mode.
+ */
+ __le32 link_ps_bitmap;
+
+ /*
+ * A bitmap (where each bit represents a single HLID) to indicate
+ * if the station is in Fast mode
+ */
+ __le32 link_fast_bitmap;
+
+ /* Cumulative counter of total released mem blocks since FW-reset */
+ __le32 total_released_blks;
+
+ /* Size (in Memory Blocks) of TX pool */
+ __le32 tx_total;
+
+ struct wl12xx_fw_packet_counters counters;
+
+ __le32 log_start_addr;
+} __packed;
+
#endif /* __WL12XX_PRIV_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index ec37b16585df..de5b4fa5d166 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -648,7 +648,7 @@ static const struct wl18xx_clk_cfg wl18xx_clk_table[NUM_CLOCK_CONFIGS] = {
};
/* TODO: maybe move to a new header file? */
-#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw-2.bin"
+#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw-3.bin"
static int wl18xx_identify_chip(struct wl1271 *wl)
{
@@ -1133,6 +1133,39 @@ static int wl18xx_hw_init(struct wl1271 *wl)
return ret;
}
+static void wl18xx_convert_fw_status(struct wl1271 *wl, void *raw_fw_status,
+ struct wl_fw_status *fw_status)
+{
+ struct wl18xx_fw_status *int_fw_status = raw_fw_status;
+
+ fw_status->intr = le32_to_cpu(int_fw_status->intr);
+ fw_status->fw_rx_counter = int_fw_status->fw_rx_counter;
+ fw_status->drv_rx_counter = int_fw_status->drv_rx_counter;
+ fw_status->tx_results_counter = int_fw_status->tx_results_counter;
+ fw_status->rx_pkt_descs = int_fw_status->rx_pkt_descs;
+
+ fw_status->fw_localtime = le32_to_cpu(int_fw_status->fw_localtime);
+ fw_status->link_ps_bitmap = le32_to_cpu(int_fw_status->link_ps_bitmap);
+ fw_status->link_fast_bitmap =
+ le32_to_cpu(int_fw_status->link_fast_bitmap);
+ fw_status->total_released_blks =
+ le32_to_cpu(int_fw_status->total_released_blks);
+ fw_status->tx_total = le32_to_cpu(int_fw_status->tx_total);
+
+ fw_status->counters.tx_released_pkts =
+ int_fw_status->counters.tx_released_pkts;
+ fw_status->counters.tx_lnk_free_pkts =
+ int_fw_status->counters.tx_lnk_free_pkts;
+ fw_status->counters.tx_voice_released_blks =
+ int_fw_status->counters.tx_voice_released_blks;
+ fw_status->counters.tx_last_rate =
+ int_fw_status->counters.tx_last_rate;
+
+ fw_status->log_start_addr = le32_to_cpu(int_fw_status->log_start_addr);
+
+ fw_status->priv = &int_fw_status->priv;
+}
+
static void wl18xx_set_tx_desc_csum(struct wl1271 *wl,
struct wl1271_tx_hw_descr *desc,
struct sk_buff *skb)
@@ -1572,7 +1605,7 @@ static bool wl18xx_lnk_high_prio(struct wl1271 *wl, u8 hlid,
{
u8 thold;
struct wl18xx_fw_status_priv *status_priv =
- (struct wl18xx_fw_status_priv *)wl->fw_status_2->priv;
+ (struct wl18xx_fw_status_priv *)wl->fw_status->priv;
u32 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap);
/* suspended links are never high priority */
@@ -1594,7 +1627,7 @@ static bool wl18xx_lnk_low_prio(struct wl1271 *wl, u8 hlid,
{
u8 thold;
struct wl18xx_fw_status_priv *status_priv =
- (struct wl18xx_fw_status_priv *)wl->fw_status_2->priv;
+ (struct wl18xx_fw_status_priv *)wl->fw_status->priv;
u32 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap);
if (test_bit(hlid, (unsigned long *)&suspend_bitmap))
@@ -1632,6 +1665,7 @@ static struct wlcore_ops wl18xx_ops = {
.tx_immediate_compl = wl18xx_tx_immediate_completion,
.tx_delayed_compl = NULL,
.hw_init = wl18xx_hw_init,
+ .convert_fw_status = wl18xx_convert_fw_status,
.set_tx_desc_csum = wl18xx_set_tx_desc_csum,
.get_pg_ver = wl18xx_get_pg_ver,
.set_rx_csum = wl18xx_set_rx_csum,
@@ -1713,19 +1747,62 @@ static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_2ghz = {
},
};
+static const struct ieee80211_iface_limit wl18xx_iface_limits[] = {
+ {
+ .max = 3,
+ .types = BIT(NL80211_IFTYPE_STATION),
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT),
+ },
+};
+
+static const struct ieee80211_iface_limit wl18xx_iface_ap_limits[] = {
+ {
+ .max = 2,
+ .types = BIT(NL80211_IFTYPE_AP),
+ },
+};
+
+static const struct ieee80211_iface_combination
+wl18xx_iface_combinations[] = {
+ {
+ .max_interfaces = 3,
+ .limits = wl18xx_iface_limits,
+ .n_limits = ARRAY_SIZE(wl18xx_iface_limits),
+ .num_different_channels = 2,
+ },
+ {
+ .max_interfaces = 2,
+ .limits = wl18xx_iface_ap_limits,
+ .n_limits = ARRAY_SIZE(wl18xx_iface_ap_limits),
+ .num_different_channels = 1,
+ }
+};
+
static int wl18xx_setup(struct wl1271 *wl)
{
struct wl18xx_priv *priv = wl->priv;
int ret;
+ BUILD_BUG_ON(WL18XX_MAX_LINKS > WLCORE_MAX_LINKS);
+ BUILD_BUG_ON(WL18XX_MAX_AP_STATIONS > WL18XX_MAX_LINKS);
+
wl->rtable = wl18xx_rtable;
wl->num_tx_desc = WL18XX_NUM_TX_DESCRIPTORS;
wl->num_rx_desc = WL18XX_NUM_RX_DESCRIPTORS;
- wl->num_channels = 2;
+ wl->num_links = WL18XX_MAX_LINKS;
+ wl->max_ap_stations = WL18XX_MAX_AP_STATIONS;
+ wl->iface_combinations = wl18xx_iface_combinations;
+ wl->n_iface_combinations = ARRAY_SIZE(wl18xx_iface_combinations);
wl->num_mac_addr = WL18XX_NUM_MAC_ADDRESSES;
wl->band_rate_to_idx = wl18xx_band_rate_to_idx;
wl->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX;
wl->hw_min_ht_rate = WL18XX_CONF_HW_RXTX_RATE_MCS0;
+ wl->fw_status_len = sizeof(struct wl18xx_fw_status);
wl->fw_status_priv_len = sizeof(struct wl18xx_fw_status_priv);
wl->stats.fw_stats_len = sizeof(struct wl18xx_acx_statistics);
wl->static_data_priv_len = sizeof(struct wl18xx_static_data_priv);
diff --git a/drivers/net/wireless/ti/wl18xx/tx.c b/drivers/net/wireless/ti/wl18xx/tx.c
index 57c694396647..be1ebd55ac88 100644
--- a/drivers/net/wireless/ti/wl18xx/tx.c
+++ b/drivers/net/wireless/ti/wl18xx/tx.c
@@ -32,7 +32,7 @@ static
void wl18xx_get_last_tx_rate(struct wl1271 *wl, struct ieee80211_vif *vif,
struct ieee80211_tx_rate *rate)
{
- u8 fw_rate = wl->fw_status_2->counters.tx_last_rate;
+ u8 fw_rate = wl->fw_status->counters.tx_last_rate;
if (fw_rate > CONF_HW_RATE_INDEX_MAX) {
wl1271_error("last Tx rate invalid: %d", fw_rate);
@@ -139,7 +139,7 @@ static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte)
void wl18xx_tx_immediate_complete(struct wl1271 *wl)
{
struct wl18xx_fw_status_priv *status_priv =
- (struct wl18xx_fw_status_priv *)wl->fw_status_2->priv;
+ (struct wl18xx_fw_status_priv *)wl->fw_status->priv;
struct wl18xx_priv *priv = wl->priv;
u8 i;
diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h
index 9204e07ee432..eb7cfe817010 100644
--- a/drivers/net/wireless/ti/wl18xx/wl18xx.h
+++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h
@@ -26,10 +26,10 @@
/* minimum FW required for driver */
#define WL18XX_CHIP_VER 8
-#define WL18XX_IFTYPE_VER 5
+#define WL18XX_IFTYPE_VER 8
#define WL18XX_MAJOR_VER WLCORE_FW_VER_IGNORE
#define WL18XX_SUBTYPE_VER WLCORE_FW_VER_IGNORE
-#define WL18XX_MINOR_VER 39
+#define WL18XX_MINOR_VER 13
#define WL18XX_CMD_MAX_SIZE 740
@@ -40,7 +40,10 @@
#define WL18XX_NUM_MAC_ADDRESSES 3
-#define WL18XX_RX_BA_MAX_SESSIONS 5
+#define WL18XX_RX_BA_MAX_SESSIONS 13
+
+#define WL18XX_MAX_AP_STATIONS 10
+#define WL18XX_MAX_LINKS 16
struct wl18xx_priv {
/* buffer for sending commands to FW */
@@ -109,6 +112,59 @@ struct wl18xx_fw_status_priv {
u8 padding[3];
};
+struct wl18xx_fw_packet_counters {
+ /* Cumulative counter of released packets per AC */
+ u8 tx_released_pkts[NUM_TX_QUEUES];
+
+ /* Cumulative counter of freed packets per HLID */
+ u8 tx_lnk_free_pkts[WL18XX_MAX_LINKS];
+
+ /* Cumulative counter of released Voice memory blocks */
+ u8 tx_voice_released_blks;
+
+ /* Tx rate of the last transmitted packet */
+ u8 tx_last_rate;
+
+ u8 padding[2];
+} __packed;
+
+/* FW status registers */
+struct wl18xx_fw_status {
+ __le32 intr;
+ u8 fw_rx_counter;
+ u8 drv_rx_counter;
+ u8 reserved;
+ u8 tx_results_counter;
+ __le32 rx_pkt_descs[WL18XX_NUM_RX_DESCRIPTORS];
+
+ __le32 fw_localtime;
+
+ /*
+ * A bitmap (where each bit represents a single HLID)
+ * to indicate if the station is in PS mode.
+ */
+ __le32 link_ps_bitmap;
+
+ /*
+ * A bitmap (where each bit represents a single HLID) to indicate
+ * if the station is in Fast mode
+ */
+ __le32 link_fast_bitmap;
+
+ /* Cumulative counter of total released mem blocks since FW-reset */
+ __le32 total_released_blks;
+
+ /* Size (in Memory Blocks) of TX pool */
+ __le32 tx_total;
+
+ struct wl18xx_fw_packet_counters counters;
+
+ __le32 log_start_addr;
+
+ /* Private status to be used by the lower drivers */
+ struct wl18xx_fw_status_priv priv;
+} __packed;
+
#define WL18XX_PHY_VERSION_MAX_LEN 20
struct wl18xx_static_data_priv {
diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c
index ec83675a2446..b924ceadc02c 100644
--- a/drivers/net/wireless/ti/wlcore/acx.c
+++ b/drivers/net/wireless/ti/wlcore/acx.c
@@ -358,7 +358,8 @@ int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct acx_beacon_filter_option *beacon_filter = NULL;
int ret = 0;
- wl1271_debug(DEBUG_ACX, "acx beacon filter opt");
+ wl1271_debug(DEBUG_ACX, "acx beacon filter opt enable=%d",
+ enable_filter);
if (enable_filter &&
wl->conf.conn.bcn_filt_mode == CONF_BCN_FILT_MODE_DISABLED)
@@ -1591,7 +1592,8 @@ out:
return ret;
}
-int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr)
+int wl1271_acx_set_inconnection_sta(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif, u8 *addr)
{
struct wl1271_acx_inconnection_sta *acx = NULL;
int ret;
@@ -1603,6 +1605,7 @@ int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr)
return -ENOMEM;
memcpy(acx->addr, addr, ETH_ALEN);
+ acx->role_id = wlvif->role_id;
ret = wl1271_cmd_configure(wl, ACX_UPDATE_INCONNECTION_STA_LIST,
acx, sizeof(*acx));
diff --git a/drivers/net/wireless/ti/wlcore/acx.h b/drivers/net/wireless/ti/wlcore/acx.h
index 6dcfad9b0472..954d57ec98f4 100644
--- a/drivers/net/wireless/ti/wlcore/acx.h
+++ b/drivers/net/wireless/ti/wlcore/acx.h
@@ -824,7 +824,8 @@ struct wl1271_acx_inconnection_sta {
struct acx_header header;
u8 addr[ETH_ALEN];
- u8 padding1[2];
+ u8 role_id;
+ u8 padding;
} __packed;
/*
@@ -1118,7 +1119,8 @@ int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
bool enable);
int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int wl12xx_acx_config_ps(struct wl1271 *wl, struct wl12xx_vif *wlvif);
-int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
+int wl1271_acx_set_inconnection_sta(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif, u8 *addr);
int wl1271_acx_fm_coex(struct wl1271 *wl);
int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl);
int wl12xx_acx_config_hangover(struct wl1271 *wl);
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
index 9b2ecf52449f..40dc30f4faaa 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.c
+++ b/drivers/net/wireless/ti/wlcore/cmd.c
@@ -60,8 +60,8 @@ static int __wlcore_cmd_send(struct wl1271 *wl, u16 id, void *buf,
u16 status;
u16 poll_count = 0;
- if (WARN_ON(wl->state == WLCORE_STATE_RESTARTING &&
- id != CMD_STOP_FWLOGGER))
+ if (unlikely(wl->state == WLCORE_STATE_RESTARTING &&
+ id != CMD_STOP_FWLOGGER))
return -EIO;
cmd = buf;
@@ -312,8 +312,8 @@ static int wlcore_get_new_session_id(struct wl1271 *wl, u8 hlid)
int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
{
unsigned long flags;
- u8 link = find_first_zero_bit(wl->links_map, WL12XX_MAX_LINKS);
- if (link >= WL12XX_MAX_LINKS)
+ u8 link = find_first_zero_bit(wl->links_map, wl->num_links);
+ if (link >= wl->num_links)
return -EBUSY;
wl->session_ids[link] = wlcore_get_new_session_id(wl, link);
@@ -324,9 +324,14 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
__set_bit(link, wlvif->links_map);
spin_unlock_irqrestore(&wl->wl_lock, flags);
- /* take the last "freed packets" value from the current FW status */
- wl->links[link].prev_freed_pkts =
- wl->fw_status_2->counters.tx_lnk_free_pkts[link];
+ /*
+ * take the last "freed packets" value from the current FW status.
+ * on recovery, we might not have fw_status yet, and
+ * tx_lnk_free_pkts will be NULL. check for it.
+ */
+ if (wl->fw_status->counters.tx_lnk_free_pkts)
+ wl->links[link].prev_freed_pkts =
+ wl->fw_status->counters.tx_lnk_free_pkts[link];
wl->links[link].wlvif = wlvif;
/*
@@ -1527,6 +1532,7 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
cmd->sp_len = sta->max_sp;
cmd->wmm = sta->wme ? 1 : 0;
cmd->session_id = wl->session_ids[hlid];
+ cmd->role_id = wlvif->role_id;
for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++)
if (sta->wme && (sta->uapsd_queues & BIT(i)))
@@ -1563,7 +1569,8 @@ out:
return ret;
}
-int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
+int wl12xx_cmd_remove_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 hlid)
{
struct wl12xx_cmd_remove_peer *cmd;
int ret;
@@ -1581,6 +1588,7 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
/* We never send a deauth, mac80211 is in charge of this */
cmd->reason_opcode = 0;
cmd->send_deauth_flag = 0;
+ cmd->role_id = wlvif->role_id;
ret = wl1271_cmd_send(wl, CMD_REMOVE_PEER, cmd, sizeof(*cmd), 0);
if (ret < 0) {
diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h
index 323d4a856e4b..b084830a61cf 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.h
+++ b/drivers/net/wireless/ti/wlcore/cmd.h
@@ -88,7 +88,8 @@ int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id,
int wl12xx_croc(struct wl1271 *wl, u8 role_id);
int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct ieee80211_sta *sta, u8 hlid);
-int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid);
+int wl12xx_cmd_remove_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 hlid);
void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel,
enum ieee80211_band band);
int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl);
@@ -206,7 +207,7 @@ enum cmd_templ {
#define WL1271_COMMAND_TIMEOUT 2000
#define WL1271_CMD_TEMPL_DFLT_SIZE 252
#define WL1271_CMD_TEMPL_MAX_SIZE 512
-#define WL1271_EVENT_TIMEOUT 1500
+#define WL1271_EVENT_TIMEOUT 5000
struct wl1271_cmd_header {
__le16 id;
@@ -594,6 +595,8 @@ struct wl12xx_cmd_add_peer {
u8 sp_len;
u8 wmm;
u8 session_id;
+ u8 role_id;
+ u8 padding[3];
} __packed;
struct wl12xx_cmd_remove_peer {
@@ -602,7 +605,7 @@ struct wl12xx_cmd_remove_peer {
u8 hlid;
u8 reason_opcode;
u8 send_deauth_flag;
- u8 padding1;
+ u8 role_id;
} __packed;
/*
diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c
index 8d3b34965db3..1f9a36031b06 100644
--- a/drivers/net/wireless/ti/wlcore/event.c
+++ b/drivers/net/wireless/ti/wlcore/event.c
@@ -67,7 +67,7 @@ static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif)
u8 hlid;
struct wl1271_link *lnk;
for_each_set_bit(hlid, wlvif->ap.sta_hlid_map,
- WL12XX_MAX_LINKS) {
+ wl->num_links) {
lnk = &wl->links[hlid];
if (!lnk->ba_bitmap)
continue;
@@ -172,7 +172,7 @@ static void wlcore_disconnect_sta(struct wl1271 *wl, unsigned long sta_bitmap)
const u8 *addr;
int h;
- for_each_set_bit(h, &sta_bitmap, WL12XX_MAX_LINKS) {
+ for_each_set_bit(h, &sta_bitmap, wl->num_links) {
bool found = false;
/* find the ap vif connected to this sta */
wl12xx_for_each_wlvif_ap(wl, wlvif) {
diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h
index 51f8d634d32f..1555ff970050 100644
--- a/drivers/net/wireless/ti/wlcore/hw_ops.h
+++ b/drivers/net/wireless/ti/wlcore/hw_ops.h
@@ -106,6 +106,15 @@ wlcore_hw_init_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif)
return 0;
}
+static inline void
+wlcore_hw_convert_fw_status(struct wl1271 *wl, void *raw_fw_status,
+ struct wl_fw_status *fw_status)
+{
+ BUG_ON(!wl->ops->convert_fw_status);
+
+ wl->ops->convert_fw_status(wl, raw_fw_status, fw_status);
+}
+
static inline u32
wlcore_hw_sta_get_ap_rate_mask(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{
diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c
index 7699f9d07e26..199e94120864 100644
--- a/drivers/net/wireless/ti/wlcore/init.c
+++ b/drivers/net/wireless/ti/wlcore/init.c
@@ -287,8 +287,8 @@ static int wl1271_init_sta_beacon_filter(struct wl1271 *wl,
if (ret < 0)
return ret;
- /* enable beacon filtering */
- ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
+ /* disable beacon filtering until we get the first beacon */
+ ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
if (ret < 0)
return ret;
@@ -462,7 +462,7 @@ int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif)
* If the basic rates contain OFDM rates, use OFDM only
* rates for unicast TX as well. Else use all supported rates.
*/
- if ((wlvif->basic_rate_set & CONF_TX_OFDM_RATES))
+ if (wl->ofdm_only_ap && (wlvif->basic_rate_set & CONF_TX_OFDM_RATES))
supported_rates = CONF_TX_OFDM_RATES;
else
supported_rates = CONF_TX_ENABLED_RATES;
diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h
index 07e3d6a049ad..0305729d0986 100644
--- a/drivers/net/wireless/ti/wlcore/io.h
+++ b/drivers/net/wireless/ti/wlcore/io.h
@@ -60,7 +60,9 @@ static inline int __must_check wlcore_raw_write(struct wl1271 *wl, int addr,
{
int ret;
- if (test_bit(WL1271_FLAG_IO_FAILED, &wl->flags))
+ if (test_bit(WL1271_FLAG_IO_FAILED, &wl->flags) ||
+ WARN_ON((test_bit(WL1271_FLAG_IN_ELP, &wl->flags) &&
+ addr != HW_ACCESS_ELP_CTRL_REG)))
return -EIO;
ret = wl->if_ops->write(wl->dev, addr, buf, len, fixed);
@@ -76,7 +78,9 @@ static inline int __must_check wlcore_raw_read(struct wl1271 *wl, int addr,
{
int ret;
- if (test_bit(WL1271_FLAG_IO_FAILED, &wl->flags))
+ if (test_bit(WL1271_FLAG_IO_FAILED, &wl->flags) ||
+ WARN_ON((test_bit(WL1271_FLAG_IN_ELP, &wl->flags) &&
+ addr != HW_ACCESS_ELP_CTRL_REG)))
return -EIO;
ret = wl->if_ops->read(wl->dev, addr, buf, len, fixed);
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index b46b3116cc55..ed88d3913483 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -345,24 +345,24 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
* Start high-level PS if the STA is asleep with enough blocks in FW.
* Make an exception if this is the only connected link. In this
* case FW-memory congestion is less of a problem.
- * Note that a single connected STA means 3 active links, since we must
- * account for the global and broadcast AP links. The "fw_ps" check
- * assures us the third link is a STA connected to the AP. Otherwise
- * the FW would not set the PSM bit.
+ * Note that a single connected STA means 2*ap_count + 1 active links,
+ * since we must account for the global and broadcast AP links
+ * for each AP. The "fw_ps" check assures us the other link is a STA
+ * connected to the AP. Otherwise the FW would not set the PSM bit.
*/
- else if (wl->active_link_count > 3 && fw_ps &&
+ else if (wl->active_link_count > (wl->ap_count*2 + 1) && fw_ps &&
tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl12xx_ps_link_start(wl, wlvif, hlid, true);
}
static void wl12xx_irq_update_links_status(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
- struct wl_fw_status_2 *status)
+ struct wl_fw_status *status)
{
u32 cur_fw_ps_map;
u8 hlid;
- cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
+ cur_fw_ps_map = status->link_ps_bitmap;
if (wl->ap_fw_ps_map != cur_fw_ps_map) {
wl1271_debug(DEBUG_PSM,
"link ps prev 0x%x cur 0x%x changed 0x%x",
@@ -372,77 +372,73 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl,
wl->ap_fw_ps_map = cur_fw_ps_map;
}
- for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS)
+ for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, wl->num_links)
wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
wl->links[hlid].allocated_pkts);
}
-static int wlcore_fw_status(struct wl1271 *wl,
- struct wl_fw_status_1 *status_1,
- struct wl_fw_status_2 *status_2)
+static int wlcore_fw_status(struct wl1271 *wl, struct wl_fw_status *status)
{
struct wl12xx_vif *wlvif;
struct timespec ts;
u32 old_tx_blk_count = wl->tx_blocks_available;
int avail, freed_blocks;
int i;
- size_t status_len;
int ret;
struct wl1271_link *lnk;
- status_len = WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
- sizeof(*status_2) + wl->fw_status_priv_len;
-
- ret = wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status_1,
- status_len, false);
+ ret = wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR,
+ wl->raw_fw_status,
+ wl->fw_status_len, false);
if (ret < 0)
return ret;
+ wlcore_hw_convert_fw_status(wl, wl->raw_fw_status, wl->fw_status);
+
wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
"drv_rx_counter = %d, tx_results_counter = %d)",
- status_1->intr,
- status_1->fw_rx_counter,
- status_1->drv_rx_counter,
- status_1->tx_results_counter);
+ status->intr,
+ status->fw_rx_counter,
+ status->drv_rx_counter,
+ status->tx_results_counter);
for (i = 0; i < NUM_TX_QUEUES; i++) {
/* prevent wrap-around in freed-packets counter */
wl->tx_allocated_pkts[i] -=
- (status_2->counters.tx_released_pkts[i] -
+ (status->counters.tx_released_pkts[i] -
wl->tx_pkts_freed[i]) & 0xff;
- wl->tx_pkts_freed[i] = status_2->counters.tx_released_pkts[i];
+ wl->tx_pkts_freed[i] = status->counters.tx_released_pkts[i];
}
- for_each_set_bit(i, wl->links_map, WL12XX_MAX_LINKS) {
+ for_each_set_bit(i, wl->links_map, wl->num_links) {
u8 diff;
lnk = &wl->links[i];
/* prevent wrap-around in freed-packets counter */
- diff = (status_2->counters.tx_lnk_free_pkts[i] -
+ diff = (status->counters.tx_lnk_free_pkts[i] -
lnk->prev_freed_pkts) & 0xff;
if (diff == 0)
continue;
lnk->allocated_pkts -= diff;
- lnk->prev_freed_pkts = status_2->counters.tx_lnk_free_pkts[i];
+ lnk->prev_freed_pkts = status->counters.tx_lnk_free_pkts[i];
/* accumulate the prev_freed_pkts counter */
lnk->total_freed_pkts += diff;
}
/* prevent wrap-around in total blocks counter */
- if (likely(wl->tx_blocks_freed <=
- le32_to_cpu(status_2->total_released_blks)))
- freed_blocks = le32_to_cpu(status_2->total_released_blks) -
+ if (likely(wl->tx_blocks_freed <= status->total_released_blks))
+ freed_blocks = status->total_released_blks -
wl->tx_blocks_freed;
else
freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
- le32_to_cpu(status_2->total_released_blks);
+ status->total_released_blks;
- wl->tx_blocks_freed = le32_to_cpu(status_2->total_released_blks);
+ wl->tx_blocks_freed = status->total_released_blks;
wl->tx_allocated_blocks -= freed_blocks;
@@ -458,7 +454,7 @@ static int wlcore_fw_status(struct wl1271 *wl,
cancel_delayed_work(&wl->tx_watchdog_work);
}
- avail = le32_to_cpu(status_2->tx_total) - wl->tx_allocated_blocks;
+ avail = status->tx_total - wl->tx_allocated_blocks;
/*
* The FW might change the total number of TX memblocks before
@@ -477,15 +473,15 @@ static int wlcore_fw_status(struct wl1271 *wl,
/* for AP update num of allocated TX blocks per link and ps status */
wl12xx_for_each_wlvif_ap(wl, wlvif) {
- wl12xx_irq_update_links_status(wl, wlvif, status_2);
+ wl12xx_irq_update_links_status(wl, wlvif, status);
}
/* update the host-chipset time offset */
getnstimeofday(&ts);
wl->time_offset = (timespec_to_ns(&ts) >> 10) -
- (s64)le32_to_cpu(status_2->fw_localtime);
+ (s64)(status->fw_localtime);
- wl->fw_fast_lnk_map = le32_to_cpu(status_2->link_fast_bitmap);
+ wl->fw_fast_lnk_map = status->link_fast_bitmap;
return 0;
}
@@ -549,13 +545,13 @@ static int wlcore_irq_locked(struct wl1271 *wl)
clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
smp_mb__after_clear_bit();
- ret = wlcore_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
+ ret = wlcore_fw_status(wl, wl->fw_status);
if (ret < 0)
goto out;
wlcore_hw_tx_immediate_compl(wl);
- intr = le32_to_cpu(wl->fw_status_1->intr);
+ intr = wl->fw_status->intr;
intr &= WLCORE_ALL_INTR_MASK;
if (!intr) {
done = true;
@@ -584,7 +580,7 @@ static int wlcore_irq_locked(struct wl1271 *wl)
if (likely(intr & WL1271_ACX_INTR_DATA)) {
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
- ret = wlcore_rx(wl, wl->fw_status_1);
+ ret = wlcore_rx(wl, wl->fw_status);
if (ret < 0)
goto out;
@@ -786,10 +782,11 @@ out:
void wl12xx_queue_recovery_work(struct wl1271 *wl)
{
- WARN_ON(!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
-
/* Avoid a recursive recovery */
if (wl->state == WLCORE_STATE_ON) {
+ WARN_ON(!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY,
+ &wl->flags));
+
wl->state = WLCORE_STATE_RESTARTING;
set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
wl1271_ps_elp_wakeup(wl);
@@ -803,7 +800,7 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
size_t len;
/* Make sure we have enough room */
- len = min(maxlen, (size_t)(PAGE_SIZE - wl->fwlog_size));
+ len = min_t(size_t, maxlen, PAGE_SIZE - wl->fwlog_size);
/* Fill the FW log file, consumed by the sysfs fwlog entry */
memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
@@ -843,11 +840,11 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
wl12xx_cmd_stop_fwlog(wl);
/* Read the first memory block address */
- ret = wlcore_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
+ ret = wlcore_fw_status(wl, wl->fw_status);
if (ret < 0)
goto out;
- addr = le32_to_cpu(wl->fw_status_2->log_start_addr);
+ addr = wl->fw_status->log_start_addr;
if (!addr)
goto out;
@@ -990,23 +987,23 @@ static int wlcore_fw_wakeup(struct wl1271 *wl)
static int wl1271_setup(struct wl1271 *wl)
{
- wl->fw_status_1 = kzalloc(WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
- sizeof(*wl->fw_status_2) +
- wl->fw_status_priv_len, GFP_KERNEL);
- if (!wl->fw_status_1)
- return -ENOMEM;
+ wl->raw_fw_status = kzalloc(wl->fw_status_len, GFP_KERNEL);
+ if (!wl->raw_fw_status)
+ goto err;
- wl->fw_status_2 = (struct wl_fw_status_2 *)
- (((u8 *) wl->fw_status_1) +
- WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc));
+ wl->fw_status = kzalloc(sizeof(*wl->fw_status), GFP_KERNEL);
+ if (!wl->fw_status)
+ goto err;
wl->tx_res_if = kzalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
- if (!wl->tx_res_if) {
- kfree(wl->fw_status_1);
- return -ENOMEM;
- }
+ if (!wl->tx_res_if)
+ goto err;
return 0;
+err:
+ kfree(wl->fw_status);
+ kfree(wl->raw_fw_status);
+ return -ENOMEM;
}
static int wl12xx_set_power_on(struct wl1271 *wl)
@@ -1767,6 +1764,12 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
flush_work(&wl->tx_work);
flush_delayed_work(&wl->elp_work);
+ /*
+ * Cancel the watchdog even if above tx_flush failed. We will detect
+ * it on resume anyway.
+ */
+ cancel_delayed_work(&wl->tx_watchdog_work);
+
return 0;
}
@@ -1824,6 +1827,13 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
out:
wl->wow_enabled = false;
+
+ /*
+ * Set a flag to re-init the watchdog on the first Tx after resume.
+ * That way we avoid possible conditions where Tx-complete interrupts
+ * fail to arrive and we perform a spurious recovery.
+ */
+ set_bit(WL1271_FLAG_REINIT_TX_WDOG, &wl->flags);
mutex_unlock(&wl->mutex);
return 0;
@@ -1914,6 +1924,7 @@ static void wlcore_op_stop_locked(struct wl1271 *wl)
memset(wl->links_map, 0, sizeof(wl->links_map));
memset(wl->roc_map, 0, sizeof(wl->roc_map));
memset(wl->session_ids, 0, sizeof(wl->session_ids));
+ memset(wl->rx_filter_enabled, 0, sizeof(wl->rx_filter_enabled));
wl->active_sta_count = 0;
wl->active_link_count = 0;
@@ -1938,9 +1949,10 @@ static void wlcore_op_stop_locked(struct wl1271 *wl)
wl1271_debugfs_reset(wl);
- kfree(wl->fw_status_1);
- wl->fw_status_1 = NULL;
- wl->fw_status_2 = NULL;
+ kfree(wl->raw_fw_status);
+ wl->raw_fw_status = NULL;
+ kfree(wl->fw_status);
+ wl->fw_status = NULL;
kfree(wl->tx_res_if);
wl->tx_res_if = NULL;
kfree(wl->target_mem_map);
@@ -2571,10 +2583,8 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
ieee80211_scan_completed(wl->hw, true);
}
- if (wl->sched_vif == wlvif) {
- ieee80211_sched_scan_stopped(wl->hw);
+ if (wl->sched_vif == wlvif)
wl->sched_vif = NULL;
- }
if (wl->roc_vif == vif) {
wl->roc_vif = NULL;
@@ -2931,6 +2941,11 @@ static int wlcore_unset_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
if (ret < 0)
return ret;
+
+ /* disable beacon filtering */
+ ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
+ if (ret < 0)
+ return ret;
}
if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
@@ -3463,6 +3478,10 @@ static void wl1271_op_set_default_key_idx(struct ieee80211_hw *hw,
wl1271_debug(DEBUG_MAC80211, "mac80211 set default key idx %d",
key_idx);
+ /* we don't handle unsetting of default key */
+ if (key_idx == -1)
+ return;
+
mutex_lock(&wl->mutex);
if (unlikely(wl->state != WLCORE_STATE_ON)) {
@@ -3649,8 +3668,8 @@ out:
return ret;
}
-static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
+static int wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
{
struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
@@ -3672,6 +3691,8 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
+
+ return 0;
}
static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
@@ -4298,6 +4319,13 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
}
}
+ if ((changed & BSS_CHANGED_BEACON_INFO) && bss_conf->dtim_period) {
+ /* enable beacon filtering */
+ ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
+ if (ret < 0)
+ goto out;
+ }
+
ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
if (ret < 0)
goto out;
@@ -4651,7 +4679,7 @@ static int wl1271_allocate_sta(struct wl1271 *wl,
int ret;
- if (wl->active_sta_count >= AP_MAX_STATIONS) {
+ if (wl->active_sta_count >= wl->max_ap_stations) {
wl1271_warning("could not allocate HLID - too much stations");
return -EBUSY;
}
@@ -4754,7 +4782,7 @@ static int wl12xx_sta_remove(struct wl1271 *wl,
if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
return -EINVAL;
- ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
+ ret = wl12xx_cmd_remove_peer(wl, wlvif, wl_sta->hlid);
if (ret < 0)
return ret;
@@ -5679,28 +5707,6 @@ static void wl1271_unregister_hw(struct wl1271 *wl)
}
-static const struct ieee80211_iface_limit wlcore_iface_limits[] = {
- {
- .max = 3,
- .types = BIT(NL80211_IFTYPE_STATION),
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_P2P_GO) |
- BIT(NL80211_IFTYPE_P2P_CLIENT),
- },
-};
-
-static struct ieee80211_iface_combination
-wlcore_iface_combinations[] = {
- {
- .max_interfaces = 3,
- .limits = wlcore_iface_limits,
- .n_limits = ARRAY_SIZE(wlcore_iface_limits),
- },
-};
-
static int wl1271_init_ieee80211(struct wl1271 *wl)
{
int i;
@@ -5733,7 +5739,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
IEEE80211_HW_AP_LINK_PS |
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
- IEEE80211_HW_QUEUE_CONTROL;
+ IEEE80211_HW_QUEUE_CONTROL |
+ IEEE80211_HW_CHANCTX_STA_CSA;
wl->hw->wiphy->cipher_suites = cipher_suites;
wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
@@ -5821,10 +5828,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
/* allowed interface combinations */
- wlcore_iface_combinations[0].num_different_channels = wl->num_channels;
- wl->hw->wiphy->iface_combinations = wlcore_iface_combinations;
- wl->hw->wiphy->n_iface_combinations =
- ARRAY_SIZE(wlcore_iface_combinations);
+ wl->hw->wiphy->iface_combinations = wl->iface_combinations;
+ wl->hw->wiphy->n_iface_combinations = wl->n_iface_combinations;
SET_IEEE80211_DEV(wl->hw, wl->dev);
@@ -5844,8 +5849,6 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
int i, j, ret;
unsigned int order;
- BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
-
hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
if (!hw) {
wl1271_error("could not alloc ieee80211_hw");
@@ -5867,8 +5870,12 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
wl->hw = hw;
+ /*
+ * wl->num_links is not configured yet, so just use WLCORE_MAX_LINKS.
+ * we don't allocate any additional resource here, so that's fine.
+ */
for (i = 0; i < NUM_TX_QUEUES; i++)
- for (j = 0; j < WL12XX_MAX_LINKS; j++)
+ for (j = 0; j < WLCORE_MAX_LINKS; j++)
skb_queue_head_init(&wl->links[j].tx_queue[i]);
skb_queue_head_init(&wl->deferred_rx_queue);
@@ -6011,7 +6018,8 @@ int wlcore_free_hw(struct wl1271 *wl)
kfree(wl->nvs);
wl->nvs = NULL;
- kfree(wl->fw_status_1);
+ kfree(wl->raw_fw_status);
+ kfree(wl->fw_status);
kfree(wl->tx_res_if);
destroy_workqueue(wl->freezable_wq);
diff --git a/drivers/net/wireless/ti/wlcore/ps.c b/drivers/net/wireless/ti/wlcore/ps.c
index 26bfc365ba70..b52516eed7b2 100644
--- a/drivers/net/wireless/ti/wlcore/ps.c
+++ b/drivers/net/wireless/ti/wlcore/ps.c
@@ -280,7 +280,11 @@ void wl12xx_ps_link_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct ieee80211_sta *sta;
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
- if (test_bit(hlid, &wl->ap_ps_map))
+ if (WARN_ON_ONCE(wlvif->bss_type != BSS_TYPE_AP_BSS))
+ return;
+
+ if (!test_bit(hlid, wlvif->ap.sta_hlid_map) ||
+ test_bit(hlid, &wl->ap_ps_map))
return;
wl1271_debug(DEBUG_PSM, "start mac80211 PSM on hlid %d pkts %d "
diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c
index 6791a1a6afba..e125974285cc 100644
--- a/drivers/net/wireless/ti/wlcore/rx.c
+++ b/drivers/net/wireless/ti/wlcore/rx.c
@@ -203,9 +203,9 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
return is_data;
}
-int wlcore_rx(struct wl1271 *wl, struct wl_fw_status_1 *status)
+int wlcore_rx(struct wl1271 *wl, struct wl_fw_status *status)
{
- unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
+ unsigned long active_hlids[BITS_TO_LONGS(WLCORE_MAX_LINKS)] = {0};
u32 buf_size;
u32 fw_rx_counter = status->fw_rx_counter % wl->num_rx_desc;
u32 drv_rx_counter = wl->rx_counter % wl->num_rx_desc;
@@ -263,12 +263,12 @@ int wlcore_rx(struct wl1271 *wl, struct wl_fw_status_1 *status)
wl->aggr_buf + pkt_offset,
pkt_len, rx_align,
&hlid) == 1) {
- if (hlid < WL12XX_MAX_LINKS)
+ if (hlid < wl->num_links)
__set_bit(hlid, active_hlids);
else
WARN(1,
- "hlid exceeded WL12XX_MAX_LINKS "
- "(%d)\n", hlid);
+ "hlid (%d) exceeded MAX_LINKS\n",
+ hlid);
}
wl->rx_counter++;
@@ -302,7 +302,7 @@ int wl1271_rx_filter_enable(struct wl1271 *wl,
{
int ret;
- if (wl->rx_filter_enabled[index] == enable) {
+ if (!!test_bit(index, wl->rx_filter_enabled) == enable) {
wl1271_warning("Request to enable an already "
"enabled rx filter %d", index);
return 0;
@@ -316,7 +316,10 @@ int wl1271_rx_filter_enable(struct wl1271 *wl,
return ret;
}
- wl->rx_filter_enabled[index] = enable;
+ if (enable)
+ __set_bit(index, wl->rx_filter_enabled);
+ else
+ __clear_bit(index, wl->rx_filter_enabled);
return 0;
}
@@ -326,7 +329,7 @@ int wl1271_rx_filter_clear_all(struct wl1271 *wl)
int i, ret = 0;
for (i = 0; i < WL1271_MAX_RX_FILTERS; i++) {
- if (!wl->rx_filter_enabled[i])
+ if (!test_bit(i, wl->rx_filter_enabled))
continue;
ret = wl1271_rx_filter_enable(wl, i, 0, NULL);
if (ret)
diff --git a/drivers/net/wireless/ti/wlcore/rx.h b/drivers/net/wireless/ti/wlcore/rx.h
index 3363f60fb7da..a3b1618db27c 100644
--- a/drivers/net/wireless/ti/wlcore/rx.h
+++ b/drivers/net/wireless/ti/wlcore/rx.h
@@ -142,7 +142,7 @@ struct wl1271_rx_descriptor {
u8 reserved;
} __packed;
-int wlcore_rx(struct wl1271 *wl, struct wl_fw_status_1 *status);
+int wlcore_rx(struct wl1271 *wl, struct wl_fw_status *status);
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
int wl1271_rx_filter_enable(struct wl1271 *wl,
int index, bool enable,
diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c
index b2c018dccf18..dbe826dd7c23 100644
--- a/drivers/net/wireless/ti/wlcore/spi.c
+++ b/drivers/net/wireless/ti/wlcore/spi.c
@@ -211,7 +211,7 @@ static int __must_check wl12xx_spi_raw_read(struct device *child, int addr,
u32 chunk_len;
while (len > 0) {
- chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len);
+ chunk_len = min_t(size_t, WSPI_MAX_CHUNK_SIZE, len);
cmd = &wl->buffer_cmd;
busy_buf = wl->buffer_busyword;
@@ -285,7 +285,7 @@ static int __must_check wl12xx_spi_raw_write(struct device *child, int addr,
cmd = &commands[0];
i = 0;
while (len > 0) {
- chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len);
+ chunk_len = min_t(size_t, WSPI_MAX_CHUNK_SIZE, len);
*cmd = 0;
*cmd |= WSPI_CMD_WRITE;
diff --git a/drivers/net/wireless/ti/wlcore/sysfs.c b/drivers/net/wireless/ti/wlcore/sysfs.c
index 8e583497940d..24dd288d6809 100644
--- a/drivers/net/wireless/ti/wlcore/sysfs.c
+++ b/drivers/net/wireless/ti/wlcore/sysfs.c
@@ -152,7 +152,7 @@ static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
}
/* Seeking is not supported - old logs are not kept. Disregard pos. */
- len = min(count, (size_t)wl->fwlog_size);
+ len = min_t(size_t, count, wl->fwlog_size);
wl->fwlog_size -= len;
memcpy(buffer, wl->fwlog, len);
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index 87cd707affa2..40b43115f835 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -101,7 +101,7 @@ static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
* authentication response. this way it won't get de-authed by FW
* when transmitting too soon.
*/
- wl1271_acx_set_inconnection_sta(wl, hdr->addr1);
+ wl1271_acx_set_inconnection_sta(wl, wlvif, hdr->addr1);
/*
* ROC for 1 second on the AP channel for completing the connection.
@@ -134,12 +134,12 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl,
* into high-level PS and clean out its TX queues.
* Make an exception if this is the only connected link. In this
* case FW-memory congestion is less of a problem.
- * Note that a single connected STA means 3 active links, since we must
- * account for the global and broadcast AP links. The "fw_ps" check
- * assures us the third link is a STA connected to the AP. Otherwise
- * the FW would not set the PSM bit.
+ * Note that a single connected STA means 2*ap_count + 1 active links,
+ * since we must account for the global and broadcast AP links
+ * for each AP. The "fw_ps" check assures us the other link is a STA
+ * connected to the AP. Otherwise the FW would not set the PSM bit.
*/
- if (wl->active_link_count > 3 && fw_ps &&
+ if (wl->active_link_count > (wl->ap_count*2 + 1) && fw_ps &&
tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl12xx_ps_link_start(wl, wlvif, hlid, true);
}
@@ -234,8 +234,13 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
wl->tx_blocks_available -= total_blocks;
wl->tx_allocated_blocks += total_blocks;
- /* If the FW was empty before, arm the Tx watchdog */
- if (wl->tx_allocated_blocks == total_blocks)
+ /*
+ * If the FW was empty before, arm the Tx watchdog. Also do
+ * this on the first Tx after resume, as we always cancel the
+ * watchdog on suspend.
+ */
+ if (wl->tx_allocated_blocks == total_blocks ||
+ test_and_clear_bit(WL1271_FLAG_REINIT_TX_WDOG, &wl->flags))
wl12xx_rearm_tx_watchdog_locked(wl);
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
@@ -357,6 +362,10 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
ieee80211_has_protected(frame_control))
tx_attr |= TX_HW_ATTR_HOST_ENCRYPT;
+ /* send EAPOL frames as voice */
+ if (control->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)
+ tx_attr |= TX_HW_ATTR_EAPOL_FRAME;
+
desc->tx_attr = cpu_to_le16(tx_attr);
wlcore_hw_set_tx_desc_csum(wl, desc, skb);
@@ -560,11 +569,11 @@ static struct sk_buff *wlcore_vif_dequeue_high_prio(struct wl1271 *wl,
int i, h, start_hlid;
/* start from the link after the last one */
- start_hlid = (wlvif->last_tx_hlid + 1) % WL12XX_MAX_LINKS;
+ start_hlid = (wlvif->last_tx_hlid + 1) % wl->num_links;
/* dequeue according to AC, round robin on each link */
- for (i = 0; i < WL12XX_MAX_LINKS; i++) {
- h = (start_hlid + i) % WL12XX_MAX_LINKS;
+ for (i = 0; i < wl->num_links; i++) {
+ h = (start_hlid + i) % wl->num_links;
/* only consider connected stations */
if (!test_bit(h, wlvif->links_map))
@@ -688,8 +697,8 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct wl12xx_vif *wlvif,
skb_queue_head(&wl->links[hlid].tx_queue[q], skb);
/* make sure we dequeue the same packet next time */
- wlvif->last_tx_hlid = (hlid + WL12XX_MAX_LINKS - 1) %
- WL12XX_MAX_LINKS;
+ wlvif->last_tx_hlid = (hlid + wl->num_links - 1) %
+ wl->num_links;
}
spin_lock_irqsave(&wl->wl_lock, flags);
@@ -722,7 +731,7 @@ void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids)
timeout = wl->conf.rx_streaming.duration;
wl12xx_for_each_wlvif_sta(wl, wlvif) {
bool found = false;
- for_each_set_bit(hlid, active_hlids, WL12XX_MAX_LINKS) {
+ for_each_set_bit(hlid, active_hlids, wl->num_links) {
if (test_bit(hlid, wlvif->links_map)) {
found = true;
break;
@@ -759,7 +768,7 @@ int wlcore_tx_work_locked(struct wl1271 *wl)
struct wl1271_tx_hw_descr *desc;
u32 buf_offset = 0, last_len = 0;
bool sent_packets = false;
- unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
+ unsigned long active_hlids[BITS_TO_LONGS(WLCORE_MAX_LINKS)] = {0};
int ret = 0;
int bus_ret = 0;
u8 hlid;
@@ -1061,7 +1070,7 @@ void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif)
int i;
/* TX failure */
- for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) {
+ for_each_set_bit(i, wlvif->links_map, wl->num_links) {
if (wlvif->bss_type == BSS_TYPE_AP_BSS &&
i != wlvif->ap.bcast_hlid && i != wlvif->ap.global_hlid) {
/* this calls wl12xx_free_link */
@@ -1085,7 +1094,7 @@ void wl12xx_tx_reset(struct wl1271 *wl)
/* only reset the queues if something bad happened */
if (wl1271_tx_total_queue_count(wl) != 0) {
- for (i = 0; i < WL12XX_MAX_LINKS; i++)
+ for (i = 0; i < wl->num_links; i++)
wl1271_tx_reset_link_queues(wl, i);
for (i = 0; i < NUM_TX_QUEUES; i++)
@@ -1178,7 +1187,7 @@ void wl1271_tx_flush(struct wl1271 *wl)
WL1271_TX_FLUSH_TIMEOUT / 1000);
/* forcibly flush all Tx buffers on our queues */
- for (i = 0; i < WL12XX_MAX_LINKS; i++)
+ for (i = 0; i < wl->num_links; i++)
wl1271_tx_reset_link_queues(wl, i);
out_wake:
diff --git a/drivers/net/wireless/ti/wlcore/tx.h b/drivers/net/wireless/ti/wlcore/tx.h
index 35489c300da1..79cb3ff8b71f 100644
--- a/drivers/net/wireless/ti/wlcore/tx.h
+++ b/drivers/net/wireless/ti/wlcore/tx.h
@@ -37,6 +37,7 @@
#define TX_HW_ATTR_TX_CMPLT_REQ BIT(12)
#define TX_HW_ATTR_TX_DUMMY_REQ BIT(13)
#define TX_HW_ATTR_HOST_ENCRYPT BIT(14)
+#define TX_HW_ATTR_EAPOL_FRAME BIT(15)
#define TX_HW_ATTR_OFST_SAVE_RETRIES 0
#define TX_HW_ATTR_OFST_HEADER_PAD 1
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index 06efc12a39e5..95a54504f0cc 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -73,6 +73,8 @@ struct wlcore_ops {
void (*tx_immediate_compl)(struct wl1271 *wl);
int (*hw_init)(struct wl1271 *wl);
int (*init_vif)(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+ void (*convert_fw_status)(struct wl1271 *wl, void *raw_fw_status,
+ struct wl_fw_status *fw_status);
u32 (*sta_get_ap_rate_mask)(struct wl1271 *wl,
struct wl12xx_vif *wlvif);
int (*get_pg_ver)(struct wl1271 *wl, s8 *ver);
@@ -220,7 +222,7 @@ struct wl1271 {
int channel;
u8 system_hlid;
- unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)];
+ unsigned long links_map[BITS_TO_LONGS(WLCORE_MAX_LINKS)];
unsigned long roles_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)];
unsigned long roc_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)];
unsigned long rate_policies_map[
@@ -228,7 +230,7 @@ struct wl1271 {
unsigned long klv_templates_map[
BITS_TO_LONGS(WLCORE_MAX_KLV_TEMPLATES)];
- u8 session_ids[WL12XX_MAX_LINKS];
+ u8 session_ids[WLCORE_MAX_LINKS];
struct list_head wlvif_list;
@@ -346,8 +348,8 @@ struct wl1271 {
u32 buffer_cmd;
u32 buffer_busyword[WL1271_BUSY_WORD_CNT];
- struct wl_fw_status_1 *fw_status_1;
- struct wl_fw_status_2 *fw_status_2;
+ void *raw_fw_status;
+ struct wl_fw_status *fw_status;
struct wl1271_tx_hw_res_if *tx_res_if;
/* Current chipset configuration */
@@ -376,7 +378,7 @@ struct wl1271 {
* AP-mode - links indexed by HLID. The global and broadcast links
* are always active.
*/
- struct wl1271_link links[WL12XX_MAX_LINKS];
+ struct wl1271_link links[WLCORE_MAX_LINKS];
/* number of currently active links */
int active_link_count;
@@ -405,6 +407,9 @@ struct wl1271 {
/* AP-mode - number of currently connected stations */
int active_sta_count;
+ /* Flag determining whether AP should broadcast OFDM-only rates */
+ bool ofdm_only_ap;
+
/* last wlvif we transmitted from */
struct wl12xx_vif *last_wlvif;
@@ -434,6 +439,10 @@ struct wl1271 {
u32 num_tx_desc;
/* number of RX descriptors the HW supports. */
u32 num_rx_desc;
+ /* number of links the HW supports */
+ u8 num_links;
+ /* max stations a single AP can support */
+ u8 max_ap_stations;
/* translate HW Tx rates to standard rate-indices */
const u8 **band_rate_to_idx;
@@ -448,10 +457,11 @@ struct wl1271 {
struct ieee80211_sta_ht_cap ht_cap[WLCORE_NUM_BANDS];
/* size of the private FW status data */
+ size_t fw_status_len;
size_t fw_status_priv_len;
/* RX Data filter rule state - enabled/disabled */
- bool rx_filter_enabled[WL1271_MAX_RX_FILTERS];
+ unsigned long rx_filter_enabled[BITS_TO_LONGS(WL1271_MAX_RX_FILTERS)];
/* size of the private static data */
size_t static_data_priv_len;
@@ -476,8 +486,9 @@ struct wl1271 {
struct completion nvs_loading_complete;
- /* number of concurrent channels the HW supports */
- u32 num_channels;
+ /* interface combinations supported by the hw */
+ const struct ieee80211_iface_combination *iface_combinations;
+ u8 n_iface_combinations;
};
int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev);
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h
index ce7261ce8b59..756e890bc5ee 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
@@ -58,10 +58,15 @@
#define WL1271_DEFAULT_DTIM_PERIOD 1
#define WL12XX_MAX_ROLES 4
-#define WL12XX_MAX_LINKS 12
#define WL12XX_INVALID_ROLE_ID 0xff
#define WL12XX_INVALID_LINK_ID 0xff
+/*
+ * max number of links allowed by all HWs.
+ * this is NOT the actual max links supported by the current hw.
+ */
+#define WLCORE_MAX_LINKS 16
+
/* the driver supports the 2.4Ghz and 5Ghz bands */
#define WLCORE_NUM_BANDS 2
@@ -118,72 +123,58 @@ struct wl1271_chip {
#define NUM_TX_QUEUES 4
-#define AP_MAX_STATIONS 8
-
-struct wl_fw_packet_counters {
- /* Cumulative counter of released packets per AC */
- u8 tx_released_pkts[NUM_TX_QUEUES];
-
- /* Cumulative counter of freed packets per HLID */
- u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS];
-
- /* Cumulative counter of released Voice memory blocks */
- u8 tx_voice_released_blks;
-
- /* Tx rate of the last transmitted packet */
- u8 tx_last_rate;
-
- u8 padding[2];
-} __packed;
-
-/* FW status registers */
-struct wl_fw_status_1 {
- __le32 intr;
+struct wl_fw_status {
+ u32 intr;
u8 fw_rx_counter;
u8 drv_rx_counter;
- u8 reserved;
u8 tx_results_counter;
- __le32 rx_pkt_descs[0];
-} __packed;
-
-/*
- * Each HW arch has a different number of Rx descriptors.
- * The length of the status depends on it, since it holds an array
- * of descriptors.
- */
-#define WLCORE_FW_STATUS_1_LEN(num_rx_desc) \
- (sizeof(struct wl_fw_status_1) + \
- (sizeof(((struct wl_fw_status_1 *)0)->rx_pkt_descs[0])) * \
- num_rx_desc)
+ __le32 *rx_pkt_descs;
-struct wl_fw_status_2 {
- __le32 fw_localtime;
+ u32 fw_localtime;
/*
* A bitmap (where each bit represents a single HLID)
* to indicate if the station is in PS mode.
*/
- __le32 link_ps_bitmap;
+ u32 link_ps_bitmap;
/*
* A bitmap (where each bit represents a single HLID) to indicate
* if the station is in Fast mode
*/
- __le32 link_fast_bitmap;
+ u32 link_fast_bitmap;
/* Cumulative counter of total released mem blocks since FW-reset */
- __le32 total_released_blks;
+ u32 total_released_blks;
/* Size (in Memory Blocks) of TX pool */
- __le32 tx_total;
+ u32 tx_total;
+
+ struct {
+ /*
+ * Cumulative counter of released packets per AC
+ * (length of the array is NUM_TX_QUEUES)
+ */
+ u8 *tx_released_pkts;
- struct wl_fw_packet_counters counters;
+ /*
+ * Cumulative counter of freed packets per HLID
+ * (length of the array is wl->num_links)
+ */
+ u8 *tx_lnk_free_pkts;
+
+ /* Cumulative counter of released Voice memory blocks */
+ u8 tx_voice_released_blks;
- __le32 log_start_addr;
+ /* Tx rate of the last transmitted packet */
+ u8 tx_last_rate;
+ } counters;
+
+ u32 log_start_addr;
/* Private status to be used by the lower drivers */
- u8 priv[0];
-} __packed;
+ void *priv;
+};
#define WL1271_MAX_CHANNELS 64
struct wl1271_scan {
@@ -240,6 +231,7 @@ enum wl12xx_flags {
WL1271_FLAG_VIF_CHANGE_IN_PROGRESS,
WL1271_FLAG_INTENDED_FW_RECOVERY,
WL1271_FLAG_IO_FAILED,
+ WL1271_FLAG_REINIT_TX_WDOG,
};
enum wl12xx_vif_flags {
@@ -368,7 +360,7 @@ struct wl12xx_vif {
/* HLIDs bitmap of associated stations */
unsigned long sta_hlid_map[BITS_TO_LONGS(
- WL12XX_MAX_LINKS)];
+ WLCORE_MAX_LINKS)];
/* recoreded keys - set here before AP startup */
struct wl1271_ap_key *recorded_keys[MAX_NUM_KEYS];
@@ -385,7 +377,7 @@ struct wl12xx_vif {
/* counters of packets per AC, across all links in the vif */
int tx_queue_count[NUM_TX_QUEUES];
- unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)];
+ unsigned long links_map[BITS_TO_LONGS(WLCORE_MAX_LINKS)];
u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
u8 ssid_len;
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index d24d4a958c67..d5c371d77ddf 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -42,8 +42,7 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/wireless.h>
-#include <linux/ieee80211.h>
-#include <linux/etherdevice.h>
+#include <net/cfg80211.h>
#include <net/iw_handler.h>
@@ -1454,7 +1453,8 @@ static int wl3501_get_freq(struct net_device *dev, struct iw_request_info *info,
{
struct wl3501_card *this = netdev_priv(dev);
- wrqu->freq.m = ieee80211_dsss_chan_to_freq(this->chan) * 100000;
+ wrqu->freq.m = 100000 *
+ ieee80211_channel_to_frequency(this->chan, IEEE80211_BAND_2GHZ);
wrqu->freq.e = 1;
return 0;
}
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index d39c4178c33a..6f5c793a7855 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -18,7 +18,7 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/wireless.h>
-#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
#include <net/iw_handler.h>
#include <linux/string.h>
#include <linux/if_arp.h>
@@ -914,11 +914,8 @@ static int zd1201_set_freq(struct net_device *dev,
if (freq->e == 0)
channel = freq->m;
- else {
- channel = ieee80211_freq_to_dsss_chan(freq->m);
- if (channel < 0)
- channel = 0;
- }
+ else
+ channel = ieee80211_frequency_to_channel(freq->m);
err = zd1201_setconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, channel);
if (err)
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
index 4c76bcb9a879..89d1d0556b6e 100644
--- a/drivers/net/xen-netback/common.h
+++ b/drivers/net/xen-netback/common.h
@@ -48,37 +48,19 @@
typedef unsigned int pending_ring_idx_t;
#define INVALID_PENDING_RING_IDX (~0U)
-/* For the head field in pending_tx_info: it is used to indicate
- * whether this tx info is the head of one or more coalesced requests.
- *
- * When head != INVALID_PENDING_RING_IDX, it means the start of a new
- * tx requests queue and the end of previous queue.
- *
- * An example sequence of head fields (I = INVALID_PENDING_RING_IDX):
- *
- * ...|0 I I I|5 I|9 I I I|...
- * -->|<-INUSE----------------
- *
- * After consuming the first slot(s) we have:
- *
- * ...|V V V V|5 I|9 I I I|...
- * -----FREE->|<-INUSE--------
- *
- * where V stands for "valid pending ring index". Any number other
- * than INVALID_PENDING_RING_IDX is OK. These entries are considered
- * free and can contain any number other than
- * INVALID_PENDING_RING_IDX. In practice we use 0.
- *
- * The in use non-INVALID_PENDING_RING_IDX (say 0, 5 and 9 in the
- * above example) number is the index into pending_tx_info and
- * mmap_pages arrays.
- */
struct pending_tx_info {
- struct xen_netif_tx_request req; /* coalesced tx request */
- pending_ring_idx_t head; /* head != INVALID_PENDING_RING_IDX
- * if it is head of one or more tx
- * reqs
- */
+ struct xen_netif_tx_request req; /* tx request */
+ /* Callback data for released SKBs. The callback is always
+ * xenvif_zerocopy_callback, desc contains the pending_idx, which is
+ * also an index in pending_tx_info array. It is initialized in
+ * xenvif_alloc and it never changes.
+ * skb_shinfo(skb)->destructor_arg points to the first mapped slot's
+ * callback_struct in this array of struct pending_tx_info's, then ctx
+ * to the next, or NULL if there is no more slot for this skb.
+ * ubuf_to_vif is a helper which finds the struct xenvif from a pointer
+ * to this field.
+ */
+ struct ubuf_info callback_struct;
};
#define XEN_NETIF_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE)
@@ -99,7 +81,7 @@ struct xenvif_rx_meta {
#define MAX_BUFFER_OFFSET PAGE_SIZE
-#define MAX_PENDING_REQS 256
+#define MAX_PENDING_REQS XEN_NETIF_TX_RING_SIZE
/* It's possible for an skb to have a maximal number of frags
* but still be less than MAX_BUFFER_OFFSET in size. Thus the
@@ -108,11 +90,25 @@ struct xenvif_rx_meta {
*/
#define MAX_GRANT_COPY_OPS (MAX_SKB_FRAGS * XEN_NETIF_RX_RING_SIZE)
+#define NETBACK_INVALID_HANDLE -1
+
+/* To avoid confusion, we define XEN_NETBK_LEGACY_SLOTS_MAX indicating
+ * the maximum slots a valid packet can use. Now this value is defined
+ * to be XEN_NETIF_NR_SLOTS_MIN, which is supposed to be supported by
+ * all backend.
+ */
+#define XEN_NETBK_LEGACY_SLOTS_MAX XEN_NETIF_NR_SLOTS_MIN
+
struct xenvif {
/* Unique identifier for this interface. */
domid_t domid;
unsigned int handle;
+ /* Is this interface disabled? True when backend discovers
+ * frontend is rogue.
+ */
+ bool disabled;
+
/* Use NAPI for guest TX */
struct napi_struct napi;
/* When feature-split-event-channels = 0, tx_irq = rx_irq. */
@@ -126,13 +122,26 @@ struct xenvif {
pending_ring_idx_t pending_cons;
u16 pending_ring[MAX_PENDING_REQS];
struct pending_tx_info pending_tx_info[MAX_PENDING_REQS];
-
- /* Coalescing tx requests before copying makes number of grant
- * copy ops greater or equal to number of slots required. In
- * worst case a tx request consumes 2 gnttab_copy.
+ grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
+
+ struct gnttab_map_grant_ref tx_map_ops[MAX_PENDING_REQS];
+ struct gnttab_unmap_grant_ref tx_unmap_ops[MAX_PENDING_REQS];
+ /* passed to gnttab_[un]map_refs with pages under (un)mapping */
+ struct page *pages_to_map[MAX_PENDING_REQS];
+ struct page *pages_to_unmap[MAX_PENDING_REQS];
+
+ /* This prevents zerocopy callbacks to race over dealloc_ring */
+ spinlock_t callback_lock;
+ /* This prevents dealloc thread and NAPI instance to race over response
+ * creation and pending_ring in xenvif_idx_release. In xenvif_tx_err
+ * it only protect response creation
*/
- struct gnttab_copy tx_copy_ops[2*MAX_PENDING_REQS];
-
+ spinlock_t response_lock;
+ pending_ring_idx_t dealloc_prod;
+ pending_ring_idx_t dealloc_cons;
+ u16 dealloc_ring[MAX_PENDING_REQS];
+ struct task_struct *dealloc_task;
+ wait_queue_head_t dealloc_wq;
/* Use kthread for guest RX */
struct task_struct *task;
@@ -143,11 +152,10 @@ struct xenvif {
char rx_irq_name[IFNAMSIZ+4]; /* DEVNAME-rx */
struct xen_netif_rx_back_ring rx;
struct sk_buff_head rx_queue;
- bool rx_queue_stopped;
- /* Set when the RX interrupt is triggered by the frontend.
- * The worker thread may need to wake the queue.
- */
- bool rx_event;
+ RING_IDX rx_last_skb_slots;
+ bool rx_queue_purge;
+
+ struct timer_list wake_queue;
/* This array is allocated seperately as it is large */
struct gnttab_copy *grant_copy_op;
@@ -179,6 +187,10 @@ struct xenvif {
/* Statistics */
unsigned long rx_gso_checksum_fixup;
+ unsigned long tx_zerocopy_sent;
+ unsigned long tx_zerocopy_success;
+ unsigned long tx_zerocopy_fail;
+ unsigned long tx_frag_overflow;
/* Miscellaneous private stuff. */
struct net_device *dev;
@@ -220,9 +232,11 @@ void xenvif_carrier_off(struct xenvif *vif);
int xenvif_tx_action(struct xenvif *vif, int budget);
-int xenvif_kthread(void *data);
+int xenvif_kthread_guest_rx(void *data);
void xenvif_kick_thread(struct xenvif *vif);
+int xenvif_dealloc_kthread(void *data);
+
/* Determine whether the needed number of slots (req) are available,
* and set req_event if not.
*/
@@ -230,6 +244,24 @@ bool xenvif_rx_ring_slots_available(struct xenvif *vif, int needed);
void xenvif_stop_queue(struct xenvif *vif);
+/* Callback from stack when TX packet can be released */
+void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success);
+
+/* Unmap a pending page and release it back to the guest */
+void xenvif_idx_unmap(struct xenvif *vif, u16 pending_idx);
+
+static inline pending_ring_idx_t nr_pending_reqs(struct xenvif *vif)
+{
+ return MAX_PENDING_REQS -
+ vif->pending_prod + vif->pending_cons;
+}
+
+/* Callback from stack when TX packet can be released */
+void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success);
+
extern bool separate_tx_rx_irq;
+extern unsigned int rx_drain_timeout_msecs;
+extern unsigned int rx_drain_timeout_jiffies;
+
#endif /* __XEN_NETBACK__COMMON_H__ */
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index b9de31ea7fc4..ef05c5c49d41 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -38,6 +38,7 @@
#include <xen/events.h>
#include <asm/xen/hypercall.h>
+#include <xen/balloon.h>
#define XENVIF_QUEUE_LENGTH 32
#define XENVIF_NAPI_WEIGHT 64
@@ -62,6 +63,15 @@ static int xenvif_poll(struct napi_struct *napi, int budget)
struct xenvif *vif = container_of(napi, struct xenvif, napi);
int work_done;
+ /* This vif is rogue, we pretend we've there is nothing to do
+ * for this vif to deschedule it from NAPI. But this interface
+ * will be turned off in thread context later.
+ */
+ if (unlikely(vif->disabled)) {
+ napi_complete(napi);
+ return 0;
+ }
+
work_done = xenvif_tx_action(vif, budget);
if (work_done < budget) {
@@ -100,7 +110,6 @@ static irqreturn_t xenvif_rx_interrupt(int irq, void *dev_id)
{
struct xenvif *vif = dev_id;
- vif->rx_event = true;
xenvif_kick_thread(vif);
return IRQ_HANDLED;
@@ -114,6 +123,18 @@ static irqreturn_t xenvif_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static void xenvif_wake_queue(unsigned long data)
+{
+ struct xenvif *vif = (struct xenvif *)data;
+
+ if (netif_queue_stopped(vif->dev)) {
+ netdev_err(vif->dev, "draining TX queue\n");
+ vif->rx_queue_purge = true;
+ xenvif_kick_thread(vif);
+ netif_wake_queue(vif->dev);
+ }
+}
+
static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct xenvif *vif = netdev_priv(dev);
@@ -122,7 +143,9 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
BUG_ON(skb->dev != dev);
/* Drop the packet if vif is not ready */
- if (vif->task == NULL || !xenvif_schedulable(vif))
+ if (vif->task == NULL ||
+ vif->dealloc_task == NULL ||
+ !xenvif_schedulable(vif))
goto drop;
/* At best we'll need one slot for the header and one for each
@@ -133,16 +156,20 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* If the skb is GSO then we'll also need an extra slot for the
* metadata.
*/
- if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 ||
- skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+ if (skb_is_gso(skb))
min_slots_needed++;
/* If the skb can't possibly fit in the remaining slots
* then turn off the queue to give the ring a chance to
* drain.
*/
- if (!xenvif_rx_ring_slots_available(vif, min_slots_needed))
+ if (!xenvif_rx_ring_slots_available(vif, min_slots_needed)) {
+ vif->wake_queue.function = xenvif_wake_queue;
+ vif->wake_queue.data = (unsigned long)vif;
xenvif_stop_queue(vif);
+ mod_timer(&vif->wake_queue,
+ jiffies + rx_drain_timeout_jiffies);
+ }
skb_queue_tail(&vif->rx_queue, skb);
xenvif_kick_thread(vif);
@@ -235,6 +262,28 @@ static const struct xenvif_stat {
"rx_gso_checksum_fixup",
offsetof(struct xenvif, rx_gso_checksum_fixup)
},
+ /* If (sent != success + fail), there are probably packets never
+ * freed up properly!
+ */
+ {
+ "tx_zerocopy_sent",
+ offsetof(struct xenvif, tx_zerocopy_sent),
+ },
+ {
+ "tx_zerocopy_success",
+ offsetof(struct xenvif, tx_zerocopy_success),
+ },
+ {
+ "tx_zerocopy_fail",
+ offsetof(struct xenvif, tx_zerocopy_fail)
+ },
+ /* Number of packets exceeding MAX_SKB_FRAG slots. You should use
+ * a guest with the same MAX_SKB_FRAG
+ */
+ {
+ "tx_frag_overflow",
+ offsetof(struct xenvif, tx_frag_overflow)
+ },
};
static int xenvif_get_sset_count(struct net_device *dev, int string_set)
@@ -323,11 +372,15 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
vif->ip_csum = 1;
vif->dev = dev;
+ vif->disabled = false;
+
vif->credit_bytes = vif->remaining_credit = ~0UL;
vif->credit_usec = 0UL;
init_timer(&vif->credit_timeout);
vif->credit_window_start = get_jiffies_64();
+ init_timer(&vif->wake_queue);
+
dev->netdev_ops = &xenvif_netdev_ops;
dev->hw_features = NETIF_F_SG |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
@@ -344,8 +397,26 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
vif->pending_prod = MAX_PENDING_REQS;
for (i = 0; i < MAX_PENDING_REQS; i++)
vif->pending_ring[i] = i;
- for (i = 0; i < MAX_PENDING_REQS; i++)
- vif->mmap_pages[i] = NULL;
+ spin_lock_init(&vif->callback_lock);
+ spin_lock_init(&vif->response_lock);
+ /* If ballooning is disabled, this will consume real memory, so you
+ * better enable it. The long term solution would be to use just a
+ * bunch of valid page descriptors, without dependency on ballooning
+ */
+ err = alloc_xenballooned_pages(MAX_PENDING_REQS,
+ vif->mmap_pages,
+ false);
+ if (err) {
+ netdev_err(dev, "Could not reserve mmap_pages\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ for (i = 0; i < MAX_PENDING_REQS; i++) {
+ vif->pending_tx_info[i].callback_struct = (struct ubuf_info)
+ { .callback = xenvif_zerocopy_callback,
+ .ctx = NULL,
+ .desc = i };
+ vif->grant_tx_handle[i] = NETBACK_INVALID_HANDLE;
+ }
/*
* Initialise a dummy MAC address. We choose the numerically
@@ -383,12 +454,14 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
BUG_ON(vif->tx_irq);
BUG_ON(vif->task);
+ BUG_ON(vif->dealloc_task);
err = xenvif_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref);
if (err < 0)
goto err;
init_waitqueue_head(&vif->wq);
+ init_waitqueue_head(&vif->dealloc_wq);
if (tx_evtchn == rx_evtchn) {
/* feature-split-event-channels == 0 */
@@ -422,8 +495,8 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
disable_irq(vif->rx_irq);
}
- task = kthread_create(xenvif_kthread,
- (void *)vif, "%s", vif->dev->name);
+ task = kthread_create(xenvif_kthread_guest_rx,
+ (void *)vif, "%s-guest-rx", vif->dev->name);
if (IS_ERR(task)) {
pr_warn("Could not allocate kthread for %s\n", vif->dev->name);
err = PTR_ERR(task);
@@ -432,6 +505,16 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
vif->task = task;
+ task = kthread_create(xenvif_dealloc_kthread,
+ (void *)vif, "%s-dealloc", vif->dev->name);
+ if (IS_ERR(task)) {
+ pr_warn("Could not allocate kthread for %s\n", vif->dev->name);
+ err = PTR_ERR(task);
+ goto err_rx_unbind;
+ }
+
+ vif->dealloc_task = task;
+
rtnl_lock();
if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN)
dev_set_mtu(vif->dev, ETH_DATA_LEN);
@@ -442,6 +525,7 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
rtnl_unlock();
wake_up_process(vif->task);
+ wake_up_process(vif->dealloc_task);
return 0;
@@ -475,10 +559,16 @@ void xenvif_disconnect(struct xenvif *vif)
xenvif_carrier_off(vif);
if (vif->task) {
+ del_timer_sync(&vif->wake_queue);
kthread_stop(vif->task);
vif->task = NULL;
}
+ if (vif->dealloc_task) {
+ kthread_stop(vif->dealloc_task);
+ vif->dealloc_task = NULL;
+ }
+
if (vif->tx_irq) {
if (vif->tx_irq == vif->rx_irq)
unbind_from_irqhandler(vif->tx_irq, vif);
@@ -494,6 +584,43 @@ void xenvif_disconnect(struct xenvif *vif)
void xenvif_free(struct xenvif *vif)
{
+ int i, unmap_timeout = 0;
+ /* Here we want to avoid timeout messages if an skb can be legitimately
+ * stuck somewhere else. Realistically this could be an another vif's
+ * internal or QDisc queue. That another vif also has this
+ * rx_drain_timeout_msecs timeout, but the timer only ditches the
+ * internal queue. After that, the QDisc queue can put in worst case
+ * XEN_NETIF_RX_RING_SIZE / MAX_SKB_FRAGS skbs into that another vif's
+ * internal queue, so we need several rounds of such timeouts until we
+ * can be sure that no another vif should have skb's from us. We are
+ * not sending more skb's, so newly stuck packets are not interesting
+ * for us here.
+ */
+ unsigned int worst_case_skb_lifetime = (rx_drain_timeout_msecs/1000) *
+ DIV_ROUND_UP(XENVIF_QUEUE_LENGTH, (XEN_NETIF_RX_RING_SIZE / MAX_SKB_FRAGS));
+
+ for (i = 0; i < MAX_PENDING_REQS; ++i) {
+ if (vif->grant_tx_handle[i] != NETBACK_INVALID_HANDLE) {
+ unmap_timeout++;
+ schedule_timeout(msecs_to_jiffies(1000));
+ if (unmap_timeout > worst_case_skb_lifetime &&
+ net_ratelimit())
+ netdev_err(vif->dev,
+ "Page still granted! Index: %x\n",
+ i);
+ /* If there are still unmapped pages, reset the loop to
+ * start checking again. We shouldn't exit here until
+ * dealloc thread and NAPI instance release all the
+ * pages. If a kernel bug causes the skbs to stall
+ * somewhere, the interface cannot be brought down
+ * properly.
+ */
+ i = -1;
+ }
+ }
+
+ free_xenballooned_pages(MAX_PENDING_REQS, vif->mmap_pages);
+
netif_napi_del(&vif->napi);
unregister_netdev(vif->dev);
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 6b62c3eb8e18..3f021e054ba1 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -37,6 +37,7 @@
#include <linux/kthread.h>
#include <linux/if_vlan.h>
#include <linux/udp.h>
+#include <linux/highmem.h>
#include <net/tcp.h>
@@ -54,6 +55,13 @@
bool separate_tx_rx_irq = 1;
module_param(separate_tx_rx_irq, bool, 0644);
+/* When guest ring is filled up, qdisc queues the packets for us, but we have
+ * to timeout them, otherwise other guests' packets can get stuck there
+ */
+unsigned int rx_drain_timeout_msecs = 10000;
+module_param(rx_drain_timeout_msecs, uint, 0444);
+unsigned int rx_drain_timeout_jiffies;
+
/*
* This is the maximum slots a skb can have. If a guest sends a skb
* which exceeds this limit it is considered malicious.
@@ -62,24 +70,6 @@ module_param(separate_tx_rx_irq, bool, 0644);
static unsigned int fatal_skb_slots = FATAL_SKB_SLOTS_DEFAULT;
module_param(fatal_skb_slots, uint, 0444);
-/*
- * To avoid confusion, we define XEN_NETBK_LEGACY_SLOTS_MAX indicating
- * the maximum slots a valid packet can use. Now this value is defined
- * to be XEN_NETIF_NR_SLOTS_MIN, which is supposed to be supported by
- * all backend.
- */
-#define XEN_NETBK_LEGACY_SLOTS_MAX XEN_NETIF_NR_SLOTS_MIN
-
-/*
- * If head != INVALID_PENDING_RING_IDX, it means this tx request is head of
- * one or more merged tx requests, otherwise it is the continuation of
- * previous tx request.
- */
-static inline int pending_tx_is_head(struct xenvif *vif, RING_IDX idx)
-{
- return vif->pending_tx_info[idx].head != INVALID_PENDING_RING_IDX;
-}
-
static void xenvif_idx_release(struct xenvif *vif, u16 pending_idx,
u8 status);
@@ -109,6 +99,21 @@ static inline unsigned long idx_to_kaddr(struct xenvif *vif,
return (unsigned long)pfn_to_kaddr(idx_to_pfn(vif, idx));
}
+#define callback_param(vif, pending_idx) \
+ (vif->pending_tx_info[pending_idx].callback_struct)
+
+/* Find the containing VIF's structure from a pointer in pending_tx_info array
+ */
+static inline struct xenvif* ubuf_to_vif(struct ubuf_info *ubuf)
+{
+ u16 pending_idx = ubuf->desc;
+ struct pending_tx_info *temp =
+ container_of(ubuf, struct pending_tx_info, callback_struct);
+ return container_of(temp - pending_idx,
+ struct xenvif,
+ pending_tx_info[0]);
+}
+
/* This is a miniumum size for the linear area to avoid lots of
* calls to __pskb_pull_tail() as we set up checksum offsets. The
* value 128 was chosen as it covers all IPv4 and most likely
@@ -131,12 +136,6 @@ static inline pending_ring_idx_t pending_index(unsigned i)
return i & (MAX_PENDING_REQS-1);
}
-static inline pending_ring_idx_t nr_pending_reqs(struct xenvif *vif)
-{
- return MAX_PENDING_REQS -
- vif->pending_prod + vif->pending_cons;
-}
-
bool xenvif_rx_ring_slots_available(struct xenvif *vif, int needed)
{
RING_IDX prod, cons;
@@ -192,8 +191,8 @@ static bool start_new_rx_buffer(int offset, unsigned long size, int head)
* into multiple copies tend to give large frags their
* own buffers as before.
*/
- if ((offset + size > MAX_BUFFER_OFFSET) &&
- (size <= MAX_BUFFER_OFFSET) && offset && !head)
+ BUG_ON(size > MAX_BUFFER_OFFSET);
+ if ((offset + size > MAX_BUFFER_OFFSET) && offset && !head)
return true;
return false;
@@ -235,12 +234,14 @@ static struct xenvif_rx_meta *get_next_rx_buffer(struct xenvif *vif,
static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb,
struct netrx_pending_operations *npo,
struct page *page, unsigned long size,
- unsigned long offset, int *head)
+ unsigned long offset, int *head,
+ struct xenvif *foreign_vif,
+ grant_ref_t foreign_gref)
{
struct gnttab_copy *copy_gop;
struct xenvif_rx_meta *meta;
unsigned long bytes;
- int gso_type;
+ int gso_type = XEN_NETIF_GSO_TYPE_NONE;
/* Data must not cross a page boundary. */
BUG_ON(size + offset > PAGE_SIZE<<compound_order(page));
@@ -277,8 +278,15 @@ static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb,
copy_gop->flags = GNTCOPY_dest_gref;
copy_gop->len = bytes;
- copy_gop->source.domid = DOMID_SELF;
- copy_gop->source.u.gmfn = virt_to_mfn(page_address(page));
+ if (foreign_vif) {
+ copy_gop->source.domid = foreign_vif->domid;
+ copy_gop->source.u.ref = foreign_gref;
+ copy_gop->flags |= GNTCOPY_source_gref;
+ } else {
+ copy_gop->source.domid = DOMID_SELF;
+ copy_gop->source.u.gmfn =
+ virt_to_mfn(page_address(page));
+ }
copy_gop->source.offset = offset;
copy_gop->dest.domid = vif->domid;
@@ -299,12 +307,12 @@ static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb,
}
/* Leave a gap for the GSO descriptor. */
- if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
- gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
- else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
- gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
- else
- gso_type = XEN_NETIF_GSO_TYPE_NONE;
+ if (skb_is_gso(skb)) {
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
+ gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
+ else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+ gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
+ }
if (*head && ((1 << gso_type) & vif->gso_mask))
vif->rx.req_cons++;
@@ -338,19 +346,18 @@ static int xenvif_gop_skb(struct sk_buff *skb,
int head = 1;
int old_meta_prod;
int gso_type;
- int gso_size;
+ struct ubuf_info *ubuf = skb_shinfo(skb)->destructor_arg;
+ grant_ref_t foreign_grefs[MAX_SKB_FRAGS];
+ struct xenvif *foreign_vif = NULL;
old_meta_prod = npo->meta_prod;
- if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) {
- gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
- gso_size = skb_shinfo(skb)->gso_size;
- } else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
- gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
- gso_size = skb_shinfo(skb)->gso_size;
- } else {
- gso_type = XEN_NETIF_GSO_TYPE_NONE;
- gso_size = 0;
+ gso_type = XEN_NETIF_GSO_TYPE_NONE;
+ if (skb_is_gso(skb)) {
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
+ gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
+ else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+ gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
}
/* Set up a GSO prefix descriptor, if necessary */
@@ -358,7 +365,7 @@ static int xenvif_gop_skb(struct sk_buff *skb,
req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++);
meta = npo->meta + npo->meta_prod++;
meta->gso_type = gso_type;
- meta->gso_size = gso_size;
+ meta->gso_size = skb_shinfo(skb)->gso_size;
meta->size = 0;
meta->id = req->id;
}
@@ -368,7 +375,7 @@ static int xenvif_gop_skb(struct sk_buff *skb,
if ((1 << gso_type) & vif->gso_mask) {
meta->gso_type = gso_type;
- meta->gso_size = gso_size;
+ meta->gso_size = skb_shinfo(skb)->gso_size;
} else {
meta->gso_type = XEN_NETIF_GSO_TYPE_NONE;
meta->gso_size = 0;
@@ -379,6 +386,19 @@ static int xenvif_gop_skb(struct sk_buff *skb,
npo->copy_off = 0;
npo->copy_gref = req->gref;
+ if ((skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) &&
+ (ubuf->callback == &xenvif_zerocopy_callback)) {
+ int i = 0;
+ foreign_vif = ubuf_to_vif(ubuf);
+
+ do {
+ u16 pending_idx = ubuf->desc;
+ foreign_grefs[i++] =
+ foreign_vif->pending_tx_info[pending_idx].req.gref;
+ ubuf = (struct ubuf_info *) ubuf->ctx;
+ } while (ubuf);
+ }
+
data = skb->data;
while (data < skb_tail_pointer(skb)) {
unsigned int offset = offset_in_page(data);
@@ -388,7 +408,9 @@ static int xenvif_gop_skb(struct sk_buff *skb,
len = skb_tail_pointer(skb) - data;
xenvif_gop_frag_copy(vif, skb, npo,
- virt_to_page(data), len, offset, &head);
+ virt_to_page(data), len, offset, &head,
+ NULL,
+ 0);
data += len;
}
@@ -397,7 +419,9 @@ static int xenvif_gop_skb(struct sk_buff *skb,
skb_frag_page(&skb_shinfo(skb)->frags[i]),
skb_frag_size(&skb_shinfo(skb)->frags[i]),
skb_shinfo(skb)->frags[i].page_offset,
- &head);
+ &head,
+ foreign_vif,
+ foreign_grefs[i]);
}
return npo->meta_prod - old_meta_prod;
@@ -455,10 +479,12 @@ static void xenvif_add_frag_responses(struct xenvif *vif, int status,
}
}
-struct skb_cb_overlay {
+struct xenvif_rx_cb {
int meta_slots_used;
};
+#define XENVIF_RX_CB(skb) ((struct xenvif_rx_cb *)(skb)->cb)
+
void xenvif_kick_thread(struct xenvif *vif)
{
wake_up(&vif->wq);
@@ -474,9 +500,7 @@ static void xenvif_rx_action(struct xenvif *vif)
LIST_HEAD(notify);
int ret;
unsigned long offset;
- struct skb_cb_overlay *sco;
bool need_to_notify = false;
- bool ring_full = false;
struct netrx_pending_operations npo = {
.copy = vif->grant_copy_op,
@@ -486,7 +510,9 @@ static void xenvif_rx_action(struct xenvif *vif)
skb_queue_head_init(&rxq);
while ((skb = skb_dequeue(&vif->rx_queue)) != NULL) {
- int max_slots_needed;
+ RING_IDX max_slots_needed;
+ RING_IDX old_req_cons;
+ RING_IDX ring_slots_used;
int i;
/* We need a cheap worse case estimate for the number of
@@ -498,32 +524,53 @@ static void xenvif_rx_action(struct xenvif *vif)
PAGE_SIZE);
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
unsigned int size;
+ unsigned int offset;
+
size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
- max_slots_needed += DIV_ROUND_UP(size, PAGE_SIZE);
+ offset = skb_shinfo(skb)->frags[i].page_offset;
+
+ /* For a worse-case estimate we need to factor in
+ * the fragment page offset as this will affect the
+ * number of times xenvif_gop_frag_copy() will
+ * call start_new_rx_buffer().
+ */
+ max_slots_needed += DIV_ROUND_UP(offset + size,
+ PAGE_SIZE);
}
- if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 ||
- skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+
+ /* To avoid the estimate becoming too pessimal for some
+ * frontends that limit posted rx requests, cap the estimate
+ * at MAX_SKB_FRAGS.
+ */
+ if (max_slots_needed > MAX_SKB_FRAGS)
+ max_slots_needed = MAX_SKB_FRAGS;
+
+ /* We may need one more slot for GSO metadata */
+ if (skb_is_gso(skb) &&
+ (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 ||
+ skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6))
max_slots_needed++;
/* If the skb may not fit then bail out now */
if (!xenvif_rx_ring_slots_available(vif, max_slots_needed)) {
skb_queue_head(&vif->rx_queue, skb);
need_to_notify = true;
- ring_full = true;
+ vif->rx_last_skb_slots = max_slots_needed;
break;
- }
+ } else
+ vif->rx_last_skb_slots = 0;
+
+ old_req_cons = vif->rx.req_cons;
+ XENVIF_RX_CB(skb)->meta_slots_used = xenvif_gop_skb(skb, &npo);
+ ring_slots_used = vif->rx.req_cons - old_req_cons;
- sco = (struct skb_cb_overlay *)skb->cb;
- sco->meta_slots_used = xenvif_gop_skb(skb, &npo);
- BUG_ON(sco->meta_slots_used > max_slots_needed);
+ BUG_ON(ring_slots_used > max_slots_needed);
__skb_queue_tail(&rxq, skb);
}
BUG_ON(npo.meta_prod > ARRAY_SIZE(vif->meta));
- vif->rx_queue_stopped = !npo.copy_prod && ring_full;
-
if (!npo.copy_prod)
goto done;
@@ -531,7 +578,6 @@ static void xenvif_rx_action(struct xenvif *vif)
gnttab_batch_copy(vif->grant_copy_op, npo.copy_prod);
while ((skb = __skb_dequeue(&rxq)) != NULL) {
- sco = (struct skb_cb_overlay *)skb->cb;
if ((1 << vif->meta[npo.meta_cons].gso_type) &
vif->gso_prefix_mask) {
@@ -542,19 +588,21 @@ static void xenvif_rx_action(struct xenvif *vif)
resp->offset = vif->meta[npo.meta_cons].gso_size;
resp->id = vif->meta[npo.meta_cons].id;
- resp->status = sco->meta_slots_used;
+ resp->status = XENVIF_RX_CB(skb)->meta_slots_used;
npo.meta_cons++;
- sco->meta_slots_used--;
+ XENVIF_RX_CB(skb)->meta_slots_used--;
}
vif->dev->stats.tx_bytes += skb->len;
vif->dev->stats.tx_packets++;
- status = xenvif_check_gop(vif, sco->meta_slots_used, &npo);
+ status = xenvif_check_gop(vif,
+ XENVIF_RX_CB(skb)->meta_slots_used,
+ &npo);
- if (sco->meta_slots_used == 1)
+ if (XENVIF_RX_CB(skb)->meta_slots_used == 1)
flags = 0;
else
flags = XEN_NETRXF_more_data;
@@ -591,13 +639,13 @@ static void xenvif_rx_action(struct xenvif *vif)
xenvif_add_frag_responses(vif, status,
vif->meta + npo.meta_cons + 1,
- sco->meta_slots_used);
+ XENVIF_RX_CB(skb)->meta_slots_used);
RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->rx, ret);
need_to_notify |= !!ret;
- npo.meta_cons += sco->meta_slots_used;
+ npo.meta_cons += XENVIF_RX_CB(skb)->meta_slots_used;
dev_kfree_skb(skb);
}
@@ -647,9 +695,12 @@ static void xenvif_tx_err(struct xenvif *vif,
struct xen_netif_tx_request *txp, RING_IDX end)
{
RING_IDX cons = vif->tx.req_cons;
+ unsigned long flags;
do {
+ spin_lock_irqsave(&vif->response_lock, flags);
make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
+ spin_unlock_irqrestore(&vif->response_lock, flags);
if (cons == end)
break;
txp = RING_GET_REQUEST(&vif->tx, cons++);
@@ -660,7 +711,8 @@ static void xenvif_tx_err(struct xenvif *vif,
static void xenvif_fatal_tx_err(struct xenvif *vif)
{
netdev_err(vif->dev, "fatal error; disabling device\n");
- xenvif_carrier_off(vif);
+ vif->disabled = true;
+ xenvif_kick_thread(vif);
}
static int xenvif_count_requests(struct xenvif *vif,
@@ -761,180 +813,168 @@ static int xenvif_count_requests(struct xenvif *vif,
return slots;
}
-static struct page *xenvif_alloc_page(struct xenvif *vif,
- u16 pending_idx)
+
+struct xenvif_tx_cb {
+ u16 pending_idx;
+};
+
+#define XENVIF_TX_CB(skb) ((struct xenvif_tx_cb *)(skb)->cb)
+
+static inline void xenvif_tx_create_gop(struct xenvif *vif,
+ u16 pending_idx,
+ struct xen_netif_tx_request *txp,
+ struct gnttab_map_grant_ref *gop)
{
- struct page *page;
+ vif->pages_to_map[gop-vif->tx_map_ops] = vif->mmap_pages[pending_idx];
+ gnttab_set_map_op(gop, idx_to_kaddr(vif, pending_idx),
+ GNTMAP_host_map | GNTMAP_readonly,
+ txp->gref, vif->domid);
+
+ memcpy(&vif->pending_tx_info[pending_idx].req, txp,
+ sizeof(*txp));
+}
- page = alloc_page(GFP_ATOMIC|__GFP_COLD);
- if (!page)
+static inline struct sk_buff *xenvif_alloc_skb(unsigned int size)
+{
+ struct sk_buff *skb =
+ alloc_skb(size + NET_SKB_PAD + NET_IP_ALIGN,
+ GFP_ATOMIC | __GFP_NOWARN);
+ if (unlikely(skb == NULL))
return NULL;
- vif->mmap_pages[pending_idx] = page;
- return page;
+ /* Packets passed to netif_rx() must have some headroom. */
+ skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
+
+ /* Initialize it here to avoid later surprises */
+ skb_shinfo(skb)->destructor_arg = NULL;
+
+ return skb;
}
-static struct gnttab_copy *xenvif_get_requests(struct xenvif *vif,
- struct sk_buff *skb,
- struct xen_netif_tx_request *txp,
- struct gnttab_copy *gop)
+static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif *vif,
+ struct sk_buff *skb,
+ struct xen_netif_tx_request *txp,
+ struct gnttab_map_grant_ref *gop)
{
struct skb_shared_info *shinfo = skb_shinfo(skb);
skb_frag_t *frags = shinfo->frags;
- u16 pending_idx = *((u16 *)skb->data);
- u16 head_idx = 0;
- int slot, start;
- struct page *page;
- pending_ring_idx_t index, start_idx = 0;
- uint16_t dst_offset;
- unsigned int nr_slots;
- struct pending_tx_info *first = NULL;
+ u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx;
+ int start;
+ pending_ring_idx_t index;
+ unsigned int nr_slots, frag_overflow = 0;
/* At this point shinfo->nr_frags is in fact the number of
* slots, which can be as large as XEN_NETBK_LEGACY_SLOTS_MAX.
*/
+ if (shinfo->nr_frags > MAX_SKB_FRAGS) {
+ frag_overflow = shinfo->nr_frags - MAX_SKB_FRAGS;
+ BUG_ON(frag_overflow > MAX_SKB_FRAGS);
+ shinfo->nr_frags = MAX_SKB_FRAGS;
+ }
nr_slots = shinfo->nr_frags;
/* Skip first skb fragment if it is on same page as header fragment. */
start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
- /* Coalesce tx requests, at this point the packet passed in
- * should be <= 64K. Any packets larger than 64K have been
- * handled in xenvif_count_requests().
- */
- for (shinfo->nr_frags = slot = start; slot < nr_slots;
- shinfo->nr_frags++) {
- struct pending_tx_info *pending_tx_info =
- vif->pending_tx_info;
+ for (shinfo->nr_frags = start; shinfo->nr_frags < nr_slots;
+ shinfo->nr_frags++, txp++, gop++) {
+ index = pending_index(vif->pending_cons++);
+ pending_idx = vif->pending_ring[index];
+ xenvif_tx_create_gop(vif, pending_idx, txp, gop);
+ frag_set_pending_idx(&frags[shinfo->nr_frags], pending_idx);
+ }
- page = alloc_page(GFP_ATOMIC|__GFP_COLD);
- if (!page)
- goto err;
-
- dst_offset = 0;
- first = NULL;
- while (dst_offset < PAGE_SIZE && slot < nr_slots) {
- gop->flags = GNTCOPY_source_gref;
-
- gop->source.u.ref = txp->gref;
- gop->source.domid = vif->domid;
- gop->source.offset = txp->offset;
-
- gop->dest.domid = DOMID_SELF;
-
- gop->dest.offset = dst_offset;
- gop->dest.u.gmfn = virt_to_mfn(page_address(page));
-
- if (dst_offset + txp->size > PAGE_SIZE) {
- /* This page can only merge a portion
- * of tx request. Do not increment any
- * pointer / counter here. The txp
- * will be dealt with in future
- * rounds, eventually hitting the
- * `else` branch.
- */
- gop->len = PAGE_SIZE - dst_offset;
- txp->offset += gop->len;
- txp->size -= gop->len;
- dst_offset += gop->len; /* quit loop */
- } else {
- /* This tx request can be merged in the page */
- gop->len = txp->size;
- dst_offset += gop->len;
-
- index = pending_index(vif->pending_cons++);
-
- pending_idx = vif->pending_ring[index];
-
- memcpy(&pending_tx_info[pending_idx].req, txp,
- sizeof(*txp));
-
- /* Poison these fields, corresponding
- * fields for head tx req will be set
- * to correct values after the loop.
- */
- vif->mmap_pages[pending_idx] = (void *)(~0UL);
- pending_tx_info[pending_idx].head =
- INVALID_PENDING_RING_IDX;
-
- if (!first) {
- first = &pending_tx_info[pending_idx];
- start_idx = index;
- head_idx = pending_idx;
- }
-
- txp++;
- slot++;
- }
+ if (frag_overflow) {
+ struct sk_buff *nskb = xenvif_alloc_skb(0);
+ if (unlikely(nskb == NULL)) {
+ if (net_ratelimit())
+ netdev_err(vif->dev,
+ "Can't allocate the frag_list skb.\n");
+ return NULL;
+ }
+
+ shinfo = skb_shinfo(nskb);
+ frags = shinfo->frags;
- gop++;
+ for (shinfo->nr_frags = 0; shinfo->nr_frags < frag_overflow;
+ shinfo->nr_frags++, txp++, gop++) {
+ index = pending_index(vif->pending_cons++);
+ pending_idx = vif->pending_ring[index];
+ xenvif_tx_create_gop(vif, pending_idx, txp, gop);
+ frag_set_pending_idx(&frags[shinfo->nr_frags],
+ pending_idx);
}
- first->req.offset = 0;
- first->req.size = dst_offset;
- first->head = start_idx;
- vif->mmap_pages[head_idx] = page;
- frag_set_pending_idx(&frags[shinfo->nr_frags], head_idx);
+ skb_shinfo(skb)->frag_list = nskb;
}
- BUG_ON(shinfo->nr_frags > MAX_SKB_FRAGS);
-
return gop;
-err:
- /* Unwind, freeing all pages and sending error responses. */
- while (shinfo->nr_frags-- > start) {
- xenvif_idx_release(vif,
- frag_get_pending_idx(&frags[shinfo->nr_frags]),
- XEN_NETIF_RSP_ERROR);
+}
+
+static inline void xenvif_grant_handle_set(struct xenvif *vif,
+ u16 pending_idx,
+ grant_handle_t handle)
+{
+ if (unlikely(vif->grant_tx_handle[pending_idx] !=
+ NETBACK_INVALID_HANDLE)) {
+ netdev_err(vif->dev,
+ "Trying to overwrite active handle! pending_idx: %x\n",
+ pending_idx);
+ BUG();
}
- /* The head too, if necessary. */
- if (start)
- xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR);
+ vif->grant_tx_handle[pending_idx] = handle;
+}
- return NULL;
+static inline void xenvif_grant_handle_reset(struct xenvif *vif,
+ u16 pending_idx)
+{
+ if (unlikely(vif->grant_tx_handle[pending_idx] ==
+ NETBACK_INVALID_HANDLE)) {
+ netdev_err(vif->dev,
+ "Trying to unmap invalid handle! pending_idx: %x\n",
+ pending_idx);
+ BUG();
+ }
+ vif->grant_tx_handle[pending_idx] = NETBACK_INVALID_HANDLE;
}
static int xenvif_tx_check_gop(struct xenvif *vif,
struct sk_buff *skb,
- struct gnttab_copy **gopp)
+ struct gnttab_map_grant_ref **gopp)
{
- struct gnttab_copy *gop = *gopp;
- u16 pending_idx = *((u16 *)skb->data);
+ struct gnttab_map_grant_ref *gop = *gopp;
+ u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx;
struct skb_shared_info *shinfo = skb_shinfo(skb);
struct pending_tx_info *tx_info;
int nr_frags = shinfo->nr_frags;
int i, err, start;
- u16 peek; /* peek into next tx request */
+ struct sk_buff *first_skb = NULL;
/* Check status of header. */
err = gop->status;
if (unlikely(err))
xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR);
+ else
+ xenvif_grant_handle_set(vif, pending_idx , gop->handle);
/* Skip first skb fragment if it is on same page as header fragment. */
start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
+check_frags:
for (i = start; i < nr_frags; i++) {
int j, newerr;
- pending_ring_idx_t head;
pending_idx = frag_get_pending_idx(&shinfo->frags[i]);
tx_info = &vif->pending_tx_info[pending_idx];
- head = tx_info->head;
/* Check error status: if okay then remember grant handle. */
- do {
- newerr = (++gop)->status;
- if (newerr)
- break;
- peek = vif->pending_ring[pending_index(++head)];
- } while (!pending_tx_is_head(vif, peek));
+ newerr = (++gop)->status;
if (likely(!newerr)) {
+ xenvif_grant_handle_set(vif, pending_idx , gop->handle);
/* Had a previous error? Invalidate this fragment. */
if (unlikely(err))
- xenvif_idx_release(vif, pending_idx,
- XEN_NETIF_RSP_OKAY);
+ xenvif_idx_unmap(vif, pending_idx);
continue;
}
@@ -944,20 +984,45 @@ static int xenvif_tx_check_gop(struct xenvif *vif,
/* Not the first error? Preceding frags already invalidated. */
if (err)
continue;
-
/* First error: invalidate header and preceding fragments. */
- pending_idx = *((u16 *)skb->data);
- xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY);
+ if (!first_skb)
+ pending_idx = XENVIF_TX_CB(skb)->pending_idx;
+ else
+ pending_idx = XENVIF_TX_CB(skb)->pending_idx;
+ xenvif_idx_unmap(vif, pending_idx);
for (j = start; j < i; j++) {
pending_idx = frag_get_pending_idx(&shinfo->frags[j]);
- xenvif_idx_release(vif, pending_idx,
- XEN_NETIF_RSP_OKAY);
+ xenvif_idx_unmap(vif, pending_idx);
}
/* Remember the error: invalidate all subsequent fragments. */
err = newerr;
}
+ if (skb_has_frag_list(skb)) {
+ first_skb = skb;
+ skb = shinfo->frag_list;
+ shinfo = skb_shinfo(skb);
+ nr_frags = shinfo->nr_frags;
+ start = 0;
+
+ goto check_frags;
+ }
+
+ /* There was a mapping error in the frag_list skb. We have to unmap
+ * the first skb's frags
+ */
+ if (first_skb && err) {
+ int j;
+ shinfo = skb_shinfo(first_skb);
+ pending_idx = XENVIF_TX_CB(skb)->pending_idx;
+ start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
+ for (j = start; j < shinfo->nr_frags; j++) {
+ pending_idx = frag_get_pending_idx(&shinfo->frags[j]);
+ xenvif_idx_unmap(vif, pending_idx);
+ }
+ }
+
*gopp = gop + 1;
return err;
}
@@ -967,6 +1032,10 @@ static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb)
struct skb_shared_info *shinfo = skb_shinfo(skb);
int nr_frags = shinfo->nr_frags;
int i;
+ u16 prev_pending_idx = INVALID_PENDING_IDX;
+
+ if (skb_shinfo(skb)->destructor_arg)
+ prev_pending_idx = XENVIF_TX_CB(skb)->pending_idx;
for (i = 0; i < nr_frags; i++) {
skb_frag_t *frag = shinfo->frags + i;
@@ -976,6 +1045,17 @@ static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb)
pending_idx = frag_get_pending_idx(frag);
+ /* If this is not the first frag, chain it to the previous*/
+ if (unlikely(prev_pending_idx == INVALID_PENDING_IDX))
+ skb_shinfo(skb)->destructor_arg =
+ &callback_param(vif, pending_idx);
+ else if (likely(pending_idx != prev_pending_idx))
+ callback_param(vif, prev_pending_idx).ctx =
+ &callback_param(vif, pending_idx);
+
+ callback_param(vif, pending_idx).ctx = NULL;
+ prev_pending_idx = pending_idx;
+
txp = &vif->pending_tx_info[pending_idx].req;
page = virt_to_page(idx_to_kaddr(vif, pending_idx));
__skb_fill_page_desc(skb, i, page, txp->offset, txp->size);
@@ -983,10 +1063,15 @@ static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb)
skb->data_len += txp->size;
skb->truesize += txp->size;
- /* Take an extra reference to offset xenvif_idx_release */
+ /* Take an extra reference to offset network stack's put_page */
get_page(vif->mmap_pages[pending_idx]);
- xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY);
}
+ /* FIXME: __skb_fill_page_desc set this to true because page->pfmemalloc
+ * overlaps with "index", and "mapping" is not set. I think mapping
+ * should be set. If delivered to local stack, it would drop this
+ * skb in sk_filter unless the socket has the right to use it.
+ */
+ skb->pfmemalloc = false;
}
static int xenvif_get_extras(struct xenvif *vif,
@@ -1106,16 +1191,13 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)
static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget)
{
- struct gnttab_copy *gop = vif->tx_copy_ops, *request_gop;
+ struct gnttab_map_grant_ref *gop = vif->tx_map_ops, *request_gop;
struct sk_buff *skb;
int ret;
- while ((nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX
- < MAX_PENDING_REQS) &&
- (skb_queue_len(&vif->tx_queue) < budget)) {
+ while (skb_queue_len(&vif->tx_queue) < budget) {
struct xen_netif_tx_request txreq;
struct xen_netif_tx_request txfrags[XEN_NETBK_LEGACY_SLOTS_MAX];
- struct page *page;
struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
u16 pending_idx;
RING_IDX idx;
@@ -1131,7 +1213,7 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget)
vif->tx.sring->req_prod, vif->tx.req_cons,
XEN_NETIF_TX_RING_SIZE);
xenvif_fatal_tx_err(vif);
- continue;
+ break;
}
work_to_do = RING_HAS_UNCONSUMED_REQUESTS(&vif->tx);
@@ -1191,8 +1273,7 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget)
ret < XEN_NETBK_LEGACY_SLOTS_MAX) ?
PKT_PROT_LEN : txreq.size;
- skb = alloc_skb(data_len + NET_SKB_PAD + NET_IP_ALIGN,
- GFP_ATOMIC | __GFP_NOWARN);
+ skb = xenvif_alloc_skb(data_len);
if (unlikely(skb == NULL)) {
netdev_dbg(vif->dev,
"Can't allocate a skb in start_xmit.\n");
@@ -1200,9 +1281,6 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget)
break;
}
- /* Packets passed to netif_rx() must have some headroom. */
- skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
-
if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
struct xen_netif_extra_info *gso;
gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
@@ -1214,31 +1292,11 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget)
}
}
- /* XXX could copy straight to head */
- page = xenvif_alloc_page(vif, pending_idx);
- if (!page) {
- kfree_skb(skb);
- xenvif_tx_err(vif, &txreq, idx);
- break;
- }
-
- gop->source.u.ref = txreq.gref;
- gop->source.domid = vif->domid;
- gop->source.offset = txreq.offset;
-
- gop->dest.u.gmfn = virt_to_mfn(page_address(page));
- gop->dest.domid = DOMID_SELF;
- gop->dest.offset = txreq.offset;
-
- gop->len = txreq.size;
- gop->flags = GNTCOPY_source_gref;
+ xenvif_tx_create_gop(vif, pending_idx, &txreq, gop);
gop++;
- memcpy(&vif->pending_tx_info[pending_idx].req,
- &txreq, sizeof(txreq));
- vif->pending_tx_info[pending_idx].head = index;
- *((u16 *)skb->data) = pending_idx;
+ XENVIF_TX_CB(skb)->pending_idx = pending_idx;
__skb_put(skb, data_len);
@@ -1266,17 +1324,82 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget)
vif->tx.req_cons = idx;
- if ((gop-vif->tx_copy_ops) >= ARRAY_SIZE(vif->tx_copy_ops))
+ if ((gop-vif->tx_map_ops) >= ARRAY_SIZE(vif->tx_map_ops))
break;
}
- return gop - vif->tx_copy_ops;
+ return gop - vif->tx_map_ops;
}
+/* Consolidate skb with a frag_list into a brand new one with local pages on
+ * frags. Returns 0 or -ENOMEM if can't allocate new pages.
+ */
+static int xenvif_handle_frag_list(struct xenvif *vif, struct sk_buff *skb)
+{
+ unsigned int offset = skb_headlen(skb);
+ skb_frag_t frags[MAX_SKB_FRAGS];
+ int i;
+ struct ubuf_info *uarg;
+ struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
+
+ vif->tx_zerocopy_sent += 2;
+ vif->tx_frag_overflow++;
+
+ xenvif_fill_frags(vif, nskb);
+ /* Subtract frags size, we will correct it later */
+ skb->truesize -= skb->data_len;
+ skb->len += nskb->len;
+ skb->data_len += nskb->len;
+
+ /* create a brand new frags array and coalesce there */
+ for (i = 0; offset < skb->len; i++) {
+ struct page *page;
+ unsigned int len;
+
+ BUG_ON(i >= MAX_SKB_FRAGS);
+ page = alloc_page(GFP_ATOMIC|__GFP_COLD);
+ if (!page) {
+ int j;
+ skb->truesize += skb->data_len;
+ for (j = 0; j < i; j++)
+ put_page(frags[j].page.p);
+ return -ENOMEM;
+ }
+
+ if (offset + PAGE_SIZE < skb->len)
+ len = PAGE_SIZE;
+ else
+ len = skb->len - offset;
+ if (skb_copy_bits(skb, offset, page_address(page), len))
+ BUG();
+
+ offset += len;
+ frags[i].page.p = page;
+ frags[i].page_offset = 0;
+ skb_frag_size_set(&frags[i], len);
+ }
+ /* swap out with old one */
+ memcpy(skb_shinfo(skb)->frags,
+ frags,
+ i * sizeof(skb_frag_t));
+ skb_shinfo(skb)->nr_frags = i;
+ skb->truesize += i * PAGE_SIZE;
+
+ /* remove traces of mapped pages and frag_list */
+ skb_frag_list_init(skb);
+ uarg = skb_shinfo(skb)->destructor_arg;
+ uarg->callback(uarg, true);
+ skb_shinfo(skb)->destructor_arg = NULL;
+
+ skb_shinfo(nskb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
+ kfree_skb(nskb);
+
+ return 0;
+}
static int xenvif_tx_submit(struct xenvif *vif)
{
- struct gnttab_copy *gop = vif->tx_copy_ops;
+ struct gnttab_map_grant_ref *gop = vif->tx_map_ops;
struct sk_buff *skb;
int work_done = 0;
@@ -1285,7 +1408,7 @@ static int xenvif_tx_submit(struct xenvif *vif)
u16 pending_idx;
unsigned data_len;
- pending_idx = *((u16 *)skb->data);
+ pending_idx = XENVIF_TX_CB(skb)->pending_idx;
txp = &vif->pending_tx_info[pending_idx].req;
/* Check the remap error code. */
@@ -1300,14 +1423,16 @@ static int xenvif_tx_submit(struct xenvif *vif)
memcpy(skb->data,
(void *)(idx_to_kaddr(vif, pending_idx)|txp->offset),
data_len);
+ callback_param(vif, pending_idx).ctx = NULL;
if (data_len < txp->size) {
/* Append the packet payload as a fragment. */
txp->offset += data_len;
txp->size -= data_len;
+ skb_shinfo(skb)->destructor_arg =
+ &callback_param(vif, pending_idx);
} else {
/* Schedule a response immediately. */
- xenvif_idx_release(vif, pending_idx,
- XEN_NETIF_RSP_OKAY);
+ xenvif_idx_unmap(vif, pending_idx);
}
if (txp->flags & XEN_NETTXF_csum_blank)
@@ -1317,6 +1442,17 @@ static int xenvif_tx_submit(struct xenvif *vif)
xenvif_fill_frags(vif, skb);
+ if (unlikely(skb_has_frag_list(skb))) {
+ if (xenvif_handle_frag_list(vif, skb)) {
+ if (net_ratelimit())
+ netdev_err(vif->dev,
+ "Not enough memory to consolidate frag_list!\n");
+ skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
+ kfree_skb(skb);
+ continue;
+ }
+ }
+
if (skb_is_nonlinear(skb) && skb_headlen(skb) < PKT_PROT_LEN) {
int target = min_t(int, skb->len, PKT_PROT_LEN);
__pskb_pull_tail(skb, target - skb_headlen(skb));
@@ -1329,6 +1465,9 @@ static int xenvif_tx_submit(struct xenvif *vif)
if (checksum_setup(vif, skb)) {
netdev_dbg(vif->dev,
"Can't setup checksum in net_tx_action\n");
+ /* We have to set this flag to trigger the callback */
+ if (skb_shinfo(skb)->destructor_arg)
+ skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
kfree_skb(skb);
continue;
}
@@ -1354,17 +1493,126 @@ static int xenvif_tx_submit(struct xenvif *vif)
work_done++;
+ /* Set this flag right before netif_receive_skb, otherwise
+ * someone might think this packet already left netback, and
+ * do a skb_copy_ubufs while we are still in control of the
+ * skb. E.g. the __pskb_pull_tail earlier can do such thing.
+ */
+ if (skb_shinfo(skb)->destructor_arg) {
+ skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
+ vif->tx_zerocopy_sent++;
+ }
+
netif_receive_skb(skb);
}
return work_done;
}
+void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success)
+{
+ unsigned long flags;
+ pending_ring_idx_t index;
+ struct xenvif *vif = ubuf_to_vif(ubuf);
+
+ /* This is the only place where we grab this lock, to protect callbacks
+ * from each other.
+ */
+ spin_lock_irqsave(&vif->callback_lock, flags);
+ do {
+ u16 pending_idx = ubuf->desc;
+ ubuf = (struct ubuf_info *) ubuf->ctx;
+ BUG_ON(vif->dealloc_prod - vif->dealloc_cons >=
+ MAX_PENDING_REQS);
+ index = pending_index(vif->dealloc_prod);
+ vif->dealloc_ring[index] = pending_idx;
+ /* Sync with xenvif_tx_dealloc_action:
+ * insert idx then incr producer.
+ */
+ smp_wmb();
+ vif->dealloc_prod++;
+ } while (ubuf);
+ wake_up(&vif->dealloc_wq);
+ spin_unlock_irqrestore(&vif->callback_lock, flags);
+
+ if (likely(zerocopy_success))
+ vif->tx_zerocopy_success++;
+ else
+ vif->tx_zerocopy_fail++;
+}
+
+static inline void xenvif_tx_dealloc_action(struct xenvif *vif)
+{
+ struct gnttab_unmap_grant_ref *gop;
+ pending_ring_idx_t dc, dp;
+ u16 pending_idx, pending_idx_release[MAX_PENDING_REQS];
+ unsigned int i = 0;
+
+ dc = vif->dealloc_cons;
+ gop = vif->tx_unmap_ops;
+
+ /* Free up any grants we have finished using */
+ do {
+ dp = vif->dealloc_prod;
+
+ /* Ensure we see all indices enqueued by all
+ * xenvif_zerocopy_callback().
+ */
+ smp_rmb();
+
+ while (dc != dp) {
+ BUG_ON(gop - vif->tx_unmap_ops > MAX_PENDING_REQS);
+ pending_idx =
+ vif->dealloc_ring[pending_index(dc++)];
+
+ pending_idx_release[gop-vif->tx_unmap_ops] =
+ pending_idx;
+ vif->pages_to_unmap[gop-vif->tx_unmap_ops] =
+ vif->mmap_pages[pending_idx];
+ gnttab_set_unmap_op(gop,
+ idx_to_kaddr(vif, pending_idx),
+ GNTMAP_host_map,
+ vif->grant_tx_handle[pending_idx]);
+ xenvif_grant_handle_reset(vif, pending_idx);
+ ++gop;
+ }
+
+ } while (dp != vif->dealloc_prod);
+
+ vif->dealloc_cons = dc;
+
+ if (gop - vif->tx_unmap_ops > 0) {
+ int ret;
+ ret = gnttab_unmap_refs(vif->tx_unmap_ops,
+ NULL,
+ vif->pages_to_unmap,
+ gop - vif->tx_unmap_ops);
+ if (ret) {
+ netdev_err(vif->dev, "Unmap fail: nr_ops %tx ret %d\n",
+ gop - vif->tx_unmap_ops, ret);
+ for (i = 0; i < gop - vif->tx_unmap_ops; ++i) {
+ if (gop[i].status != GNTST_okay)
+ netdev_err(vif->dev,
+ " host_addr: %llx handle: %x status: %d\n",
+ gop[i].host_addr,
+ gop[i].handle,
+ gop[i].status);
+ }
+ BUG();
+ }
+ }
+
+ for (i = 0; i < gop - vif->tx_unmap_ops; ++i)
+ xenvif_idx_release(vif, pending_idx_release[i],
+ XEN_NETIF_RSP_OKAY);
+}
+
+
/* Called after netfront has transmitted */
int xenvif_tx_action(struct xenvif *vif, int budget)
{
unsigned nr_gops;
- int work_done;
+ int work_done, ret;
if (unlikely(!tx_work_todo(vif)))
return 0;
@@ -1374,7 +1622,11 @@ int xenvif_tx_action(struct xenvif *vif, int budget)
if (nr_gops == 0)
return 0;
- gnttab_batch_copy(vif->tx_copy_ops, nr_gops);
+ ret = gnttab_map_refs(vif->tx_map_ops,
+ NULL,
+ vif->pages_to_map,
+ nr_gops);
+ BUG_ON(ret);
work_done = xenvif_tx_submit(vif);
@@ -1385,45 +1637,18 @@ static void xenvif_idx_release(struct xenvif *vif, u16 pending_idx,
u8 status)
{
struct pending_tx_info *pending_tx_info;
- pending_ring_idx_t head;
- u16 peek; /* peek into next tx request */
-
- BUG_ON(vif->mmap_pages[pending_idx] == (void *)(~0UL));
-
- /* Already complete? */
- if (vif->mmap_pages[pending_idx] == NULL)
- return;
+ pending_ring_idx_t index;
+ unsigned long flags;
pending_tx_info = &vif->pending_tx_info[pending_idx];
-
- head = pending_tx_info->head;
-
- BUG_ON(!pending_tx_is_head(vif, head));
- BUG_ON(vif->pending_ring[pending_index(head)] != pending_idx);
-
- do {
- pending_ring_idx_t index;
- pending_ring_idx_t idx = pending_index(head);
- u16 info_idx = vif->pending_ring[idx];
-
- pending_tx_info = &vif->pending_tx_info[info_idx];
- make_tx_response(vif, &pending_tx_info->req, status);
-
- /* Setting any number other than
- * INVALID_PENDING_RING_IDX indicates this slot is
- * starting a new packet / ending a previous packet.
- */
- pending_tx_info->head = 0;
-
- index = pending_index(vif->pending_prod++);
- vif->pending_ring[index] = vif->pending_ring[info_idx];
-
- peek = vif->pending_ring[pending_index(++head)];
-
- } while (!pending_tx_is_head(vif, peek));
-
- put_page(vif->mmap_pages[pending_idx]);
- vif->mmap_pages[pending_idx] = NULL;
+ spin_lock_irqsave(&vif->response_lock, flags);
+ make_tx_response(vif, &pending_tx_info->req, status);
+ index = pending_index(vif->pending_prod);
+ vif->pending_ring[index] = pending_idx;
+ /* TX shouldn't use the index before we give it back here */
+ mb();
+ vif->pending_prod++;
+ spin_unlock_irqrestore(&vif->response_lock, flags);
}
@@ -1471,23 +1696,54 @@ static struct xen_netif_rx_response *make_rx_response(struct xenvif *vif,
return resp;
}
+void xenvif_idx_unmap(struct xenvif *vif, u16 pending_idx)
+{
+ int ret;
+ struct gnttab_unmap_grant_ref tx_unmap_op;
+
+ gnttab_set_unmap_op(&tx_unmap_op,
+ idx_to_kaddr(vif, pending_idx),
+ GNTMAP_host_map,
+ vif->grant_tx_handle[pending_idx]);
+ xenvif_grant_handle_reset(vif, pending_idx);
+
+ ret = gnttab_unmap_refs(&tx_unmap_op, NULL,
+ &vif->mmap_pages[pending_idx], 1);
+ if (ret) {
+ netdev_err(vif->dev,
+ "Unmap fail: ret: %d pending_idx: %d host_addr: %llx handle: %x status: %d\n",
+ ret,
+ pending_idx,
+ tx_unmap_op.host_addr,
+ tx_unmap_op.handle,
+ tx_unmap_op.status);
+ BUG();
+ }
+
+ xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY);
+}
+
static inline int rx_work_todo(struct xenvif *vif)
{
- return (!skb_queue_empty(&vif->rx_queue) && !vif->rx_queue_stopped) ||
- vif->rx_event;
+ return (!skb_queue_empty(&vif->rx_queue) &&
+ xenvif_rx_ring_slots_available(vif, vif->rx_last_skb_slots)) ||
+ vif->rx_queue_purge;
}
static inline int tx_work_todo(struct xenvif *vif)
{
- if (likely(RING_HAS_UNCONSUMED_REQUESTS(&vif->tx)) &&
- (nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX
- < MAX_PENDING_REQS))
+ if (likely(RING_HAS_UNCONSUMED_REQUESTS(&vif->tx)))
return 1;
return 0;
}
+static inline bool tx_dealloc_work_todo(struct xenvif *vif)
+{
+ return vif->dealloc_cons != vif->dealloc_prod;
+}
+
void xenvif_unmap_frontend_rings(struct xenvif *vif)
{
if (vif->tx.sring)
@@ -1545,7 +1801,7 @@ static void xenvif_start_queue(struct xenvif *vif)
netif_wake_queue(vif->dev);
}
-int xenvif_kthread(void *data)
+int xenvif_kthread_guest_rx(void *data)
{
struct xenvif *vif = data;
struct sk_buff *skb;
@@ -1553,18 +1809,34 @@ int xenvif_kthread(void *data)
while (!kthread_should_stop()) {
wait_event_interruptible(vif->wq,
rx_work_todo(vif) ||
+ vif->disabled ||
kthread_should_stop());
+
+ /* This frontend is found to be rogue, disable it in
+ * kthread context. Currently this is only set when
+ * netback finds out frontend sends malformed packet,
+ * but we cannot disable the interface in softirq
+ * context so we defer it here.
+ */
+ if (unlikely(vif->disabled && netif_carrier_ok(vif->dev)))
+ xenvif_carrier_off(vif);
+
if (kthread_should_stop())
break;
+ if (vif->rx_queue_purge) {
+ skb_queue_purge(&vif->rx_queue);
+ vif->rx_queue_purge = false;
+ }
+
if (!skb_queue_empty(&vif->rx_queue))
xenvif_rx_action(vif);
- vif->rx_event = false;
-
if (skb_queue_empty(&vif->rx_queue) &&
- netif_queue_stopped(vif->dev))
+ netif_queue_stopped(vif->dev)) {
+ del_timer_sync(&vif->wake_queue);
xenvif_start_queue(vif);
+ }
cond_resched();
}
@@ -1576,6 +1848,28 @@ int xenvif_kthread(void *data)
return 0;
}
+int xenvif_dealloc_kthread(void *data)
+{
+ struct xenvif *vif = data;
+
+ while (!kthread_should_stop()) {
+ wait_event_interruptible(vif->dealloc_wq,
+ tx_dealloc_work_todo(vif) ||
+ kthread_should_stop());
+ if (kthread_should_stop())
+ break;
+
+ xenvif_tx_dealloc_action(vif);
+ cond_resched();
+ }
+
+ /* Unmap anything remaining*/
+ if (tx_dealloc_work_todo(vif))
+ xenvif_tx_dealloc_action(vif);
+
+ return 0;
+}
+
static int __init netback_init(void)
{
int rc = 0;
@@ -1593,6 +1887,8 @@ static int __init netback_init(void)
if (rc)
goto failed_init;
+ rx_drain_timeout_jiffies = msecs_to_jiffies(rx_drain_timeout_msecs);
+
return 0;
failed_init:
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index ff04d4f95baa..057b05700f8b 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -658,7 +658,7 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
drop:
dev->stats.tx_dropped++;
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -907,6 +907,7 @@ static int handle_incoming_queue(struct net_device *dev,
/* Ethernet work: Delayed to here as it peeks the header. */
skb->protocol = eth_type_trans(skb, dev);
+ skb_reset_network_header(skb);
if (checksum_setup(dev, skb)) {
kfree_skb(skb);
@@ -1059,13 +1060,13 @@ static struct rtnl_link_stats64 *xennet_get_stats64(struct net_device *dev,
unsigned int start;
do {
- start = u64_stats_fetch_begin_bh(&stats->syncp);
+ start = u64_stats_fetch_begin_irq(&stats->syncp);
rx_packets = stats->rx_packets;
tx_packets = stats->tx_packets;
rx_bytes = stats->rx_bytes;
tx_bytes = stats->tx_bytes;
- } while (u64_stats_fetch_retry_bh(&stats->syncp, start));
+ } while (u64_stats_fetch_retry_irq(&stats->syncp, start));
tot->rx_packets += rx_packets;
tot->tx_packets += tx_packets;
@@ -1281,16 +1282,10 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev)
np->rx_refill_timer.function = rx_refill_timeout;
err = -ENOMEM;
- np->stats = alloc_percpu(struct netfront_stats);
+ np->stats = netdev_alloc_pcpu_stats(struct netfront_stats);
if (np->stats == NULL)
goto exit;
- for_each_possible_cpu(i) {
- struct netfront_stats *xen_nf_stats;
- xen_nf_stats = per_cpu_ptr(np->stats, i);
- u64_stats_init(&xen_nf_stats->syncp);
- }
-
/* Initialise tx_skbs as a free chain containing every entry. */
np->tx_skb_freelist = 0;
for (i = 0; i < NET_TX_RING_SIZE; i++) {
@@ -1832,7 +1827,6 @@ static void netback_changed(struct xenbus_device *dev,
case XenbusStateReconfiguring:
case XenbusStateReconfigured:
case XenbusStateUnknown:
- case XenbusStateClosed:
break;
case XenbusStateInitWait:
@@ -1847,6 +1841,10 @@ static void netback_changed(struct xenbus_device *dev,
netdev_notify_peers(netdev);
break;
+ case XenbusStateClosed:
+ if (dev->state == XenbusStateClosed)
+ break;
+ /* Missed the backend's CLOSING state -- fallthrough */
case XenbusStateClosing:
xenbus_frontend_closed(dev);
break;
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index fe20e1cc0545..65d4ca19d132 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -26,6 +26,18 @@ config NFC_WILINK
Say Y here to compile support for Texas Instrument's NFC WiLink driver
into the kernel or say M to compile it as module.
+config NFC_TRF7970A
+ tristate "Texas Instruments TRF7970a NFC driver"
+ depends on SPI && NFC_DIGITAL
+ help
+ This option enables the NFC driver for Texas Instruments' TRF7970a
+ device. Such device supports 5 different protocols: ISO14443A,
+ ISO14443B, FeLiCa, ISO15693 and ISO18000-3.
+
+ Say Y here to compile support for TRF7970a into the kernel or
+ say M to compile it as a module. The module will be called
+ trf7970a.ko.
+
config NFC_MEI_PHY
tristate "MEI bus NFC device support"
depends on INTEL_MEI && NFC_HCI
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index 56ab822ba03d..ae42a3fa60c9 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -10,5 +10,6 @@ obj-$(CONFIG_NFC_MEI_PHY) += mei_phy.o
obj-$(CONFIG_NFC_SIM) += nfcsim.o
obj-$(CONFIG_NFC_PORT100) += port100.o
obj-$(CONFIG_NFC_MRVL) += nfcmrvl/
+obj-$(CONFIG_NFC_TRF7970A) += trf7970a.o
ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index cf1a87bb74f8..d46a700a9637 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -55,26 +55,14 @@
NFC_PROTO_NFC_DEP_MASK)
static const struct usb_device_id pn533_table[] = {
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
- .idVendor = PN533_VENDOR_ID,
- .idProduct = PN533_PRODUCT_ID,
- .driver_info = PN533_DEVICE_STD,
- },
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
- .idVendor = SCM_VENDOR_ID,
- .idProduct = SCL3711_PRODUCT_ID,
- .driver_info = PN533_DEVICE_STD,
- },
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
- .idVendor = SONY_VENDOR_ID,
- .idProduct = PASORI_PRODUCT_ID,
- .driver_info = PN533_DEVICE_PASORI,
- },
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
- .idVendor = ACS_VENDOR_ID,
- .idProduct = ACR122U_PRODUCT_ID,
- .driver_info = PN533_DEVICE_ACR122U,
- },
+ { USB_DEVICE(PN533_VENDOR_ID, PN533_PRODUCT_ID),
+ .driver_info = PN533_DEVICE_STD },
+ { USB_DEVICE(SCM_VENDOR_ID, SCL3711_PRODUCT_ID),
+ .driver_info = PN533_DEVICE_STD },
+ { USB_DEVICE(SONY_VENDOR_ID, PASORI_PRODUCT_ID),
+ .driver_info = PN533_DEVICE_PASORI },
+ { USB_DEVICE(ACS_VENDOR_ID, ACR122U_PRODUCT_ID),
+ .driver_info = PN533_DEVICE_ACR122U },
{ }
};
MODULE_DEVICE_TABLE(usb, pn533_table);
diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c
index d6185ff2f87b..f2acd85be86e 100644
--- a/drivers/nfc/pn544/i2c.c
+++ b/drivers/nfc/pn544/i2c.c
@@ -58,8 +58,19 @@ MODULE_DEVICE_TABLE(i2c, pn544_hci_i2c_id_table);
#define PN544_HCI_I2C_DRIVER_NAME "pn544_hci_i2c"
+/*
+ * Exposed through the 4 most significant bytes
+ * from the HCI SW_VERSION first byte, a.k.a.
+ * SW RomLib.
+ */
+#define PN544_HW_VARIANT_C2 0xa
+#define PN544_HW_VARIANT_C3 0xb
+
+#define PN544_FW_CMD_RESET 0x01
#define PN544_FW_CMD_WRITE 0x08
#define PN544_FW_CMD_CHECK 0x06
+#define PN544_FW_CMD_SECURE_WRITE 0x0C
+#define PN544_FW_CMD_SECURE_CHUNK_WRITE 0x0D
struct pn544_i2c_fw_frame_write {
u8 cmd;
@@ -88,13 +99,31 @@ struct pn544_i2c_fw_blob {
u8 data[];
};
+struct pn544_i2c_fw_secure_frame {
+ u8 cmd;
+ u16 be_datalen;
+ u8 data[];
+} __packed;
+
+struct pn544_i2c_fw_secure_blob {
+ u64 header;
+ u8 data[];
+};
+
#define PN544_FW_CMD_RESULT_TIMEOUT 0x01
#define PN544_FW_CMD_RESULT_BAD_CRC 0x02
#define PN544_FW_CMD_RESULT_ACCESS_DENIED 0x08
#define PN544_FW_CMD_RESULT_PROTOCOL_ERROR 0x0B
#define PN544_FW_CMD_RESULT_INVALID_PARAMETER 0x11
+#define PN544_FW_CMD_RESULT_UNSUPPORTED_COMMAND 0x13
#define PN544_FW_CMD_RESULT_INVALID_LENGTH 0x18
+#define PN544_FW_CMD_RESULT_CRYPTOGRAPHIC_ERROR 0x19
+#define PN544_FW_CMD_RESULT_VERSION_CONDITIONS_ERROR 0x1D
+#define PN544_FW_CMD_RESULT_MEMORY_ERROR 0x20
+#define PN544_FW_CMD_RESULT_CHUNK_OK 0x21
#define PN544_FW_CMD_RESULT_WRITE_FAILED 0x74
+#define PN544_FW_CMD_RESULT_COMMAND_REJECTED 0xE0
+#define PN544_FW_CMD_RESULT_CHUNK_ERROR 0xE6
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
@@ -104,11 +133,17 @@ struct pn544_i2c_fw_blob {
#define PN544_FW_I2C_WRITE_DATA_MAX_LEN MIN((PN544_FW_I2C_MAX_PAYLOAD -\
PN544_FW_I2C_WRITE_FRAME_HEADER_LEN),\
PN544_FW_WRITE_BUFFER_MAX_LEN)
+#define PN544_FW_SECURE_CHUNK_WRITE_HEADER_LEN 3
+#define PN544_FW_SECURE_CHUNK_WRITE_DATA_MAX_LEN (PN544_FW_I2C_MAX_PAYLOAD -\
+ PN544_FW_SECURE_CHUNK_WRITE_HEADER_LEN)
+#define PN544_FW_SECURE_FRAME_HEADER_LEN 3
+#define PN544_FW_SECURE_BLOB_HEADER_LEN 8
#define FW_WORK_STATE_IDLE 1
#define FW_WORK_STATE_START 2
#define FW_WORK_STATE_WAIT_WRITE_ANSWER 3
#define FW_WORK_STATE_WAIT_CHECK_ANSWER 4
+#define FW_WORK_STATE_WAIT_SECURE_WRITE_ANSWER 5
struct pn544_i2c_phy {
struct i2c_client *i2c_dev;
@@ -119,6 +154,8 @@ struct pn544_i2c_phy {
unsigned int gpio_fw;
unsigned int en_polarity;
+ u8 hw_variant;
+
struct work_struct fw_work;
int fw_work_state;
char firmware_name[NFC_FIRMWARE_NAME_MAXSIZE + 1];
@@ -127,6 +164,8 @@ struct pn544_i2c_phy {
size_t fw_blob_size;
const u8 *fw_blob_data;
size_t fw_written;
+ size_t fw_size;
+
int fw_cmd_result;
int powered;
@@ -390,6 +429,8 @@ static int pn544_hci_i2c_fw_read_status(struct pn544_i2c_phy *phy)
switch (response.status) {
case 0:
return 0;
+ case PN544_FW_CMD_RESULT_CHUNK_OK:
+ return response.status;
case PN544_FW_CMD_RESULT_TIMEOUT:
return -ETIMEDOUT;
case PN544_FW_CMD_RESULT_BAD_CRC:
@@ -400,9 +441,20 @@ static int pn544_hci_i2c_fw_read_status(struct pn544_i2c_phy *phy)
return -EPROTO;
case PN544_FW_CMD_RESULT_INVALID_PARAMETER:
return -EINVAL;
+ case PN544_FW_CMD_RESULT_UNSUPPORTED_COMMAND:
+ return -ENOTSUPP;
case PN544_FW_CMD_RESULT_INVALID_LENGTH:
return -EBADMSG;
+ case PN544_FW_CMD_RESULT_CRYPTOGRAPHIC_ERROR:
+ return -ENOKEY;
+ case PN544_FW_CMD_RESULT_VERSION_CONDITIONS_ERROR:
+ return -EINVAL;
+ case PN544_FW_CMD_RESULT_MEMORY_ERROR:
+ return -ENOMEM;
+ case PN544_FW_CMD_RESULT_COMMAND_REJECTED:
+ return -EACCES;
case PN544_FW_CMD_RESULT_WRITE_FAILED:
+ case PN544_FW_CMD_RESULT_CHUNK_ERROR:
return -EIO;
default:
return -EIO;
@@ -469,7 +521,8 @@ static struct nfc_phy_ops i2c_phy_ops = {
.disable = pn544_hci_i2c_disable,
};
-static int pn544_hci_i2c_fw_download(void *phy_id, const char *firmware_name)
+static int pn544_hci_i2c_fw_download(void *phy_id, const char *firmware_name,
+ u8 hw_variant)
{
struct pn544_i2c_phy *phy = phy_id;
@@ -477,6 +530,7 @@ static int pn544_hci_i2c_fw_download(void *phy_id, const char *firmware_name)
strcpy(phy->firmware_name, firmware_name);
+ phy->hw_variant = hw_variant;
phy->fw_work_state = FW_WORK_STATE_START;
schedule_work(&phy->fw_work);
@@ -598,12 +652,93 @@ static int pn544_hci_i2c_fw_write_chunk(struct pn544_i2c_phy *phy)
return 0;
}
+static int pn544_hci_i2c_fw_secure_write_frame_cmd(struct pn544_i2c_phy *phy,
+ const u8 *data, u16 datalen)
+{
+ u8 buf[PN544_FW_I2C_MAX_PAYLOAD];
+ struct pn544_i2c_fw_secure_frame *chunk;
+ int chunklen;
+ int r;
+
+ if (datalen > PN544_FW_SECURE_CHUNK_WRITE_DATA_MAX_LEN)
+ datalen = PN544_FW_SECURE_CHUNK_WRITE_DATA_MAX_LEN;
+
+ chunk = (struct pn544_i2c_fw_secure_frame *) buf;
+
+ chunk->cmd = PN544_FW_CMD_SECURE_CHUNK_WRITE;
+
+ put_unaligned_be16(datalen, &chunk->be_datalen);
+
+ memcpy(chunk->data, data, datalen);
+
+ chunklen = sizeof(chunk->cmd) + sizeof(chunk->be_datalen) + datalen;
+
+ r = i2c_master_send(phy->i2c_dev, buf, chunklen);
+
+ if (r == chunklen)
+ return datalen;
+ else if (r < 0)
+ return r;
+ else
+ return -EIO;
+
+}
+
+static int pn544_hci_i2c_fw_secure_write_frame(struct pn544_i2c_phy *phy)
+{
+ struct pn544_i2c_fw_secure_frame *framep;
+ int r;
+
+ framep = (struct pn544_i2c_fw_secure_frame *) phy->fw_blob_data;
+ if (phy->fw_written == 0)
+ phy->fw_blob_size = get_unaligned_be16(&framep->be_datalen)
+ + PN544_FW_SECURE_FRAME_HEADER_LEN;
+
+ /* Only secure write command can be chunked*/
+ if (phy->fw_blob_size > PN544_FW_I2C_MAX_PAYLOAD &&
+ framep->cmd != PN544_FW_CMD_SECURE_WRITE)
+ return -EINVAL;
+
+ /* The firmware also have other commands, we just send them directly */
+ if (phy->fw_blob_size < PN544_FW_I2C_MAX_PAYLOAD) {
+ r = i2c_master_send(phy->i2c_dev,
+ (const char *) phy->fw_blob_data, phy->fw_blob_size);
+
+ if (r == phy->fw_blob_size)
+ goto exit;
+ else if (r < 0)
+ return r;
+ else
+ return -EIO;
+ }
+
+ r = pn544_hci_i2c_fw_secure_write_frame_cmd(phy,
+ phy->fw_blob_data + phy->fw_written,
+ phy->fw_blob_size - phy->fw_written);
+ if (r < 0)
+ return r;
+
+exit:
+ phy->fw_written += r;
+ phy->fw_work_state = FW_WORK_STATE_WAIT_SECURE_WRITE_ANSWER;
+
+ /* SW reset command will not trig any response from PN544 */
+ if (framep->cmd == PN544_FW_CMD_RESET) {
+ pn544_hci_i2c_enable_mode(phy, PN544_FW_MODE);
+ phy->fw_cmd_result = 0;
+ schedule_work(&phy->fw_work);
+ }
+
+ return 0;
+}
+
static void pn544_hci_i2c_fw_work(struct work_struct *work)
{
struct pn544_i2c_phy *phy = container_of(work, struct pn544_i2c_phy,
fw_work);
int r;
struct pn544_i2c_fw_blob *blob;
+ struct pn544_i2c_fw_secure_blob *secure_blob;
switch (phy->fw_work_state) {
case FW_WORK_STATE_START:
@@ -614,13 +749,29 @@ static void pn544_hci_i2c_fw_work(struct work_struct *work)
if (r < 0)
goto exit_state_start;
- blob = (struct pn544_i2c_fw_blob *) phy->fw->data;
- phy->fw_blob_size = get_unaligned_be32(&blob->be_size);
- phy->fw_blob_dest_addr = get_unaligned_be32(&blob->be_destaddr);
- phy->fw_blob_data = blob->data;
-
phy->fw_written = 0;
- r = pn544_hci_i2c_fw_write_chunk(phy);
+
+ switch (phy->hw_variant) {
+ case PN544_HW_VARIANT_C2:
+ blob = (struct pn544_i2c_fw_blob *) phy->fw->data;
+ phy->fw_blob_size = get_unaligned_be32(&blob->be_size);
+ phy->fw_blob_dest_addr = get_unaligned_be32(
+ &blob->be_destaddr);
+ phy->fw_blob_data = blob->data;
+
+ r = pn544_hci_i2c_fw_write_chunk(phy);
+ break;
+ case PN544_HW_VARIANT_C3:
+ secure_blob = (struct pn544_i2c_fw_secure_blob *)
+ phy->fw->data;
+ phy->fw_blob_data = secure_blob->data;
+ phy->fw_size = phy->fw->size;
+ r = pn544_hci_i2c_fw_secure_write_frame(phy);
+ break;
+ default:
+ r = -ENOTSUPP;
+ break;
+ }
exit_state_start:
if (r < 0)
@@ -672,6 +823,35 @@ exit_state_wait_check_answer:
pn544_hci_i2c_fw_work_complete(phy, r);
break;
+ case FW_WORK_STATE_WAIT_SECURE_WRITE_ANSWER:
+ r = phy->fw_cmd_result;
+ if (r < 0)
+ goto exit_state_wait_secure_write_answer;
+
+ if (r == PN544_FW_CMD_RESULT_CHUNK_OK) {
+ r = pn544_hci_i2c_fw_secure_write_frame(phy);
+ goto exit_state_wait_secure_write_answer;
+ }
+
+ if (phy->fw_written == phy->fw_blob_size) {
+ secure_blob = (struct pn544_i2c_fw_secure_blob *)
+ (phy->fw_blob_data + phy->fw_blob_size);
+ phy->fw_size -= phy->fw_blob_size +
+ PN544_FW_SECURE_BLOB_HEADER_LEN;
+ if (phy->fw_size >= PN544_FW_SECURE_BLOB_HEADER_LEN
+ + PN544_FW_SECURE_FRAME_HEADER_LEN) {
+ phy->fw_blob_data = secure_blob->data;
+
+ phy->fw_written = 0;
+ r = pn544_hci_i2c_fw_secure_write_frame(phy);
+ }
+ }
+
+exit_state_wait_secure_write_answer:
+ if (r < 0 || phy->fw_size == 0)
+ pn544_hci_i2c_fw_work_complete(phy, r);
+ break;
+
default:
break;
}
diff --git a/drivers/nfc/pn544/pn544.c b/drivers/nfc/pn544/pn544.c
index 3df4a109cfad..9c8051d20cea 100644
--- a/drivers/nfc/pn544/pn544.c
+++ b/drivers/nfc/pn544/pn544.c
@@ -786,7 +786,7 @@ static int pn544_hci_fw_download(struct nfc_hci_dev *hdev,
if (info->fw_download == NULL)
return -ENOTSUPP;
- return info->fw_download(info->phy_id, firmware_name);
+ return info->fw_download(info->phy_id, firmware_name, hdev->sw_romlib);
}
static int pn544_hci_discover_se(struct nfc_hci_dev *hdev)
diff --git a/drivers/nfc/pn544/pn544.h b/drivers/nfc/pn544/pn544.h
index 491bf45da358..2aa9233e8086 100644
--- a/drivers/nfc/pn544/pn544.h
+++ b/drivers/nfc/pn544/pn544.h
@@ -25,7 +25,8 @@
#define PN544_HCI_MODE 0
#define PN544_FW_MODE 1
-typedef int (*fw_download_t)(void *context, const char *firmware_name);
+typedef int (*fw_download_t)(void *context, const char *firmware_name,
+ u8 hw_variant);
int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
int phy_headroom, int phy_tailroom, int phy_payload,
diff --git a/drivers/nfc/port100.c b/drivers/nfc/port100.c
index a8555f81cbba..b7a372af5eb7 100644
--- a/drivers/nfc/port100.c
+++ b/drivers/nfc/port100.c
@@ -27,7 +27,8 @@
#define PORT100_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \
NFC_PROTO_MIFARE_MASK | \
NFC_PROTO_FELICA_MASK | \
- NFC_PROTO_NFC_DEP_MASK)
+ NFC_PROTO_NFC_DEP_MASK | \
+ NFC_PROTO_ISO14443_MASK)
#define PORT100_CAPABILITIES (NFC_DIGITAL_DRV_CAPS_IN_CRC | \
NFC_DIGITAL_DRV_CAPS_TG_CRC)
@@ -139,6 +140,8 @@ static const struct port100_in_rf_setting in_rf_settings[] = {
.in_recv_set_number = 15,
.in_recv_comm_type = PORT100_COMM_TYPE_IN_106A,
},
+ /* Ensures the array has NFC_DIGITAL_RF_TECH_LAST elements */
+ [NFC_DIGITAL_RF_TECH_LAST] = { 0 },
};
/**
@@ -174,6 +177,9 @@ static const struct port100_tg_rf_setting tg_rf_settings[] = {
.tg_set_number = 8,
.tg_comm_type = PORT100_COMM_TYPE_TG_424F,
},
+ /* Ensures the array has NFC_DIGITAL_RF_TECH_LAST elements */
+ [NFC_DIGITAL_RF_TECH_LAST] = { 0 },
+
};
#define PORT100_IN_PROT_INITIAL_GUARD_TIME 0x00
@@ -293,6 +299,10 @@ in_protocols[][PORT100_IN_MAX_NUM_PROTOCOLS + 1] = {
{ PORT100_IN_PROT_CHECK_CRC, 0 },
{ PORT100_IN_PROT_END, 0 },
},
+ [NFC_DIGITAL_FRAMING_NFCA_T4T] = {
+ /* nfc_digital_framing_nfca_standard_with_crc_a */
+ { PORT100_IN_PROT_END, 0 },
+ },
[NFC_DIGITAL_FRAMING_NFCA_NFC_DEP] = {
/* nfc_digital_framing_nfca_standard */
{ PORT100_IN_PROT_END, 0 },
@@ -330,6 +340,10 @@ in_protocols[][PORT100_IN_MAX_NUM_PROTOCOLS + 1] = {
[NFC_DIGITAL_FRAMING_NFC_DEP_ACTIVATED] = {
{ PORT100_IN_PROT_END, 0 },
},
+ /* Ensures the array has NFC_DIGITAL_FRAMING_LAST elements */
+ [NFC_DIGITAL_FRAMING_LAST] = {
+ { PORT100_IN_PROT_END, 0 },
+ },
};
static struct port100_protocol
@@ -371,6 +385,10 @@ tg_protocols[][PORT100_TG_MAX_NUM_PROTOCOLS + 1] = {
{ PORT100_TG_PROT_RF_OFF, 1 },
{ PORT100_TG_PROT_END, 0 },
},
+ /* Ensures the array has NFC_DIGITAL_FRAMING_LAST elements */
+ [NFC_DIGITAL_FRAMING_LAST] = {
+ { PORT100_TG_PROT_END, 0 },
+ },
};
struct port100 {
@@ -1356,10 +1374,7 @@ static struct nfc_digital_ops port100_digital_ops = {
};
static const struct usb_device_id port100_table[] = {
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
- .idVendor = SONY_VENDOR_ID,
- .idProduct = RCS380_PRODUCT_ID,
- },
+ { USB_DEVICE(SONY_VENDOR_ID, RCS380_PRODUCT_ID), },
{ }
};
MODULE_DEVICE_TABLE(usb, port100_table);
diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c
new file mode 100644
index 000000000000..d9babe986473
--- /dev/null
+++ b/drivers/nfc/trf7970a.c
@@ -0,0 +1,1370 @@
+/*
+ * TI TRF7970a RFID/NFC Transceiver Driver
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Erick Macias <emacias@ti.com>
+ * Author: Felipe Balbi <balbi@ti.com>
+ * Author: Mark A. Greer <mgreer@animalcreek.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.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/nfc.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+
+#include <net/nfc/nfc.h>
+#include <net/nfc/digital.h>
+
+/* There are 3 ways the host can communicate with the trf7970a:
+ * parallel mode, SPI with Slave Select (SS) mode, and SPI without
+ * SS mode. The driver only supports the two SPI modes.
+ *
+ * The trf7970a is very timing sensitive and the VIN, EN2, and EN
+ * pins must asserted in that order and with specific delays in between.
+ * The delays used in the driver were provided by TI and have been
+ * confirmed to work with this driver.
+ *
+ * Timeouts are implemented using the delayed workqueue kernel facility.
+ * Timeouts are required so things don't hang when there is no response
+ * from the trf7970a (or tag). Using this mechanism creates a race with
+ * interrupts, however. That is, an interrupt and a timeout could occur
+ * closely enough together that one is blocked by the mutex while the other
+ * executes. When the timeout handler executes first and blocks the
+ * interrupt handler, it will eventually set the state to IDLE so the
+ * interrupt handler will check the state and exit with no harm done.
+ * When the interrupt handler executes first and blocks the timeout handler,
+ * the cancel_delayed_work() call will know that it didn't cancel the
+ * work item (i.e., timeout) and will return zero. That return code is
+ * used by the timer handler to indicate that it should ignore the timeout
+ * once its unblocked.
+ *
+ * Aborting an active command isn't as simple as it seems because the only
+ * way to abort a command that's already been sent to the tag is so turn
+ * off power to the tag. If we do that, though, we'd have to go through
+ * the entire anticollision procedure again but the digital layer doesn't
+ * support that. So, if an abort is received before trf7970a_in_send_cmd()
+ * has sent the command to the tag, it simply returns -ECANCELED. If the
+ * command has already been sent to the tag, then the driver continues
+ * normally and recieves the response data (or error) but just before
+ * sending the data upstream, it frees the rx_skb and sends -ECANCELED
+ * upstream instead. If the command failed, that error will be sent
+ * upstream.
+ *
+ * When recieving data from a tag and the interrupt status register has
+ * only the SRX bit set, it means that all of the data has been received
+ * (once what's in the fifo has been read). However, depending on timing
+ * an interrupt status with only the SRX bit set may not be recived. In
+ * those cases, the timeout mechanism is used to wait 5 ms in case more
+ * data arrives. After 5 ms, it is assumed that all of the data has been
+ * received and the accumulated rx data is sent upstream. The
+ * 'TRF7970A_ST_WAIT_FOR_RX_DATA_CONT' state is used for this purpose
+ * (i.e., it indicates that some data has been received but we're not sure
+ * if there is more coming so a timeout in this state means all data has
+ * been received and there isn't an error). The delay is 5 ms since delays
+ * over 2 ms have been observed during testing (a little extra just in case).
+ *
+ * Type 2 write and sector select commands respond with a 4-bit ACK or NACK.
+ * Having only 4 bits in the FIFO won't normally generate an interrupt so
+ * driver enables the '4_bit_RX' bit of the Special Functions register 1
+ * to cause an interrupt in that case. Leaving that bit for a read command
+ * messes up the data returned so it is only enabled when the framing is
+ * 'NFC_DIGITAL_FRAMING_NFCA_T2T' and the command is not a read command.
+ * Unfortunately, that means that the driver has to peek into tx frames
+ * when the framing is 'NFC_DIGITAL_FRAMING_NFCA_T2T'. This is done by
+ * the trf7970a_per_cmd_config() routine.
+ *
+ * ISO/IEC 15693 frames specify whether to use single or double sub-carrier
+ * frequencies and whether to use low or high data rates in the flags byte
+ * of the frame. This means that the driver has to peek at all 15693 frames
+ * to determine what speed to set the communication to. In addition, write
+ * and lock commands use the OPTION flag to indicate that an EOF must be
+ * sent to the tag before it will send its response. So the driver has to
+ * examine all frames for that reason too.
+ *
+ * It is unclear how long to wait before sending the EOF. According to the
+ * Note under Table 1-1 in section 1.6 of
+ * http://www.ti.com/lit/ug/scbu011/scbu011.pdf, that wait should be at least
+ * 10 ms for TI Tag-it HF-I tags; however testing has shown that is not long
+ * enough. For this reason, the driver waits 20 ms which seems to work
+ * reliably.
+ */
+
+#define TRF7970A_SUPPORTED_PROTOCOLS \
+ (NFC_PROTO_MIFARE_MASK | NFC_PROTO_ISO14443_MASK | \
+ NFC_PROTO_ISO15693_MASK)
+
+/* TX data must be prefixed with a FIFO reset cmd, a cmd that depends
+ * on what the current framing is, the address of the TX length byte 1
+ * register (0x1d), and the 2 byte length of the data to be transmitted.
+ * That totals 5 bytes.
+ */
+#define TRF7970A_TX_SKB_HEADROOM 5
+
+#define TRF7970A_RX_SKB_ALLOC_SIZE 256
+
+#define TRF7970A_FIFO_SIZE 128
+
+/* TX length is 3 nibbles long ==> 4KB - 1 bytes max */
+#define TRF7970A_TX_MAX (4096 - 1)
+
+#define TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT 5
+#define TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT 3
+#define TRF7970A_WAIT_TO_ISSUE_ISO15693_EOF 20
+
+/* Quirks */
+/* Erratum: When reading IRQ Status register on trf7970a, we must issue a
+ * read continuous command for IRQ Status and Collision Position registers.
+ */
+#define TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA BIT(0)
+
+/* Direct commands */
+#define TRF7970A_CMD_IDLE 0x00
+#define TRF7970A_CMD_SOFT_INIT 0x03
+#define TRF7970A_CMD_RF_COLLISION 0x04
+#define TRF7970A_CMD_RF_COLLISION_RESPONSE_N 0x05
+#define TRF7970A_CMD_RF_COLLISION_RESPONSE_0 0x06
+#define TRF7970A_CMD_FIFO_RESET 0x0f
+#define TRF7970A_CMD_TRANSMIT_NO_CRC 0x10
+#define TRF7970A_CMD_TRANSMIT 0x11
+#define TRF7970A_CMD_DELAY_TRANSMIT_NO_CRC 0x12
+#define TRF7970A_CMD_DELAY_TRANSMIT 0x13
+#define TRF7970A_CMD_EOF 0x14
+#define TRF7970A_CMD_CLOSE_SLOT 0x15
+#define TRF7970A_CMD_BLOCK_RX 0x16
+#define TRF7970A_CMD_ENABLE_RX 0x17
+#define TRF7970A_CMD_TEST_EXT_RF 0x18
+#define TRF7970A_CMD_TEST_INT_RF 0x19
+#define TRF7970A_CMD_RX_GAIN_ADJUST 0x1a
+
+/* Bits determining whether its a direct command or register R/W,
+ * whether to use a continuous SPI transaction or not, and the actual
+ * direct cmd opcode or regster address.
+ */
+#define TRF7970A_CMD_BIT_CTRL BIT(7)
+#define TRF7970A_CMD_BIT_RW BIT(6)
+#define TRF7970A_CMD_BIT_CONTINUOUS BIT(5)
+#define TRF7970A_CMD_BIT_OPCODE(opcode) ((opcode) & 0x1f)
+
+/* Registers addresses */
+#define TRF7970A_CHIP_STATUS_CTRL 0x00
+#define TRF7970A_ISO_CTRL 0x01
+#define TRF7970A_ISO14443B_TX_OPTIONS 0x02
+#define TRF7970A_ISO14443A_HIGH_BITRATE_OPTIONS 0x03
+#define TRF7970A_TX_TIMER_SETTING_H_BYTE 0x04
+#define TRF7970A_TX_TIMER_SETTING_L_BYTE 0x05
+#define TRF7970A_TX_PULSE_LENGTH_CTRL 0x06
+#define TRF7970A_RX_NO_RESPONSE_WAIT 0x07
+#define TRF7970A_RX_WAIT_TIME 0x08
+#define TRF7970A_MODULATOR_SYS_CLK_CTRL 0x09
+#define TRF7970A_RX_SPECIAL_SETTINGS 0x0a
+#define TRF7970A_REG_IO_CTRL 0x0b
+#define TRF7970A_IRQ_STATUS 0x0c
+#define TRF7970A_COLLISION_IRQ_MASK 0x0d
+#define TRF7970A_COLLISION_POSITION 0x0e
+#define TRF7970A_RSSI_OSC_STATUS 0x0f
+#define TRF7970A_SPECIAL_FCN_REG1 0x10
+#define TRF7970A_SPECIAL_FCN_REG2 0x11
+#define TRF7970A_RAM1 0x12
+#define TRF7970A_RAM2 0x13
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS 0x14
+#define TRF7970A_NFC_LOW_FIELD_LEVEL 0x16
+#define TRF7970A_NFCID1 0x17
+#define TRF7970A_NFC_TARGET_LEVEL 0x18
+#define TRF79070A_NFC_TARGET_PROTOCOL 0x19
+#define TRF7970A_TEST_REGISTER1 0x1a
+#define TRF7970A_TEST_REGISTER2 0x1b
+#define TRF7970A_FIFO_STATUS 0x1c
+#define TRF7970A_TX_LENGTH_BYTE1 0x1d
+#define TRF7970A_TX_LENGTH_BYTE2 0x1e
+#define TRF7970A_FIFO_IO_REGISTER 0x1f
+
+/* Chip Status Control Register Bits */
+#define TRF7970A_CHIP_STATUS_VRS5_3 BIT(0)
+#define TRF7970A_CHIP_STATUS_REC_ON BIT(1)
+#define TRF7970A_CHIP_STATUS_AGC_ON BIT(2)
+#define TRF7970A_CHIP_STATUS_PM_ON BIT(3)
+#define TRF7970A_CHIP_STATUS_RF_PWR BIT(4)
+#define TRF7970A_CHIP_STATUS_RF_ON BIT(5)
+#define TRF7970A_CHIP_STATUS_DIRECT BIT(6)
+#define TRF7970A_CHIP_STATUS_STBY BIT(7)
+
+/* ISO Control Register Bits */
+#define TRF7970A_ISO_CTRL_15693_SGL_1OF4_662 0x00
+#define TRF7970A_ISO_CTRL_15693_SGL_1OF256_662 0x01
+#define TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648 0x02
+#define TRF7970A_ISO_CTRL_15693_SGL_1OF256_2648 0x03
+#define TRF7970A_ISO_CTRL_15693_DBL_1OF4_667a 0x04
+#define TRF7970A_ISO_CTRL_15693_DBL_1OF256_667 0x05
+#define TRF7970A_ISO_CTRL_15693_DBL_1OF4_2669 0x06
+#define TRF7970A_ISO_CTRL_15693_DBL_1OF256_2669 0x07
+#define TRF7970A_ISO_CTRL_14443A_106 0x08
+#define TRF7970A_ISO_CTRL_14443A_212 0x09
+#define TRF7970A_ISO_CTRL_14443A_424 0x0a
+#define TRF7970A_ISO_CTRL_14443A_848 0x0b
+#define TRF7970A_ISO_CTRL_14443B_106 0x0c
+#define TRF7970A_ISO_CTRL_14443B_212 0x0d
+#define TRF7970A_ISO_CTRL_14443B_424 0x0e
+#define TRF7970A_ISO_CTRL_14443B_848 0x0f
+#define TRF7970A_ISO_CTRL_FELICA_212 0x1a
+#define TRF7970A_ISO_CTRL_FELICA_424 0x1b
+#define TRF7970A_ISO_CTRL_RFID BIT(5)
+#define TRF7970A_ISO_CTRL_DIR_MODE BIT(6)
+#define TRF7970A_ISO_CTRL_RX_CRC_N BIT(7) /* true == No CRC */
+
+#define TRF7970A_ISO_CTRL_RFID_SPEED_MASK 0x1f
+
+/* Modulator and SYS_CLK Control Register Bits */
+#define TRF7970A_MODULATOR_DEPTH(n) ((n) & 0x7)
+#define TRF7970A_MODULATOR_DEPTH_ASK10 (TRF7970A_MODULATOR_DEPTH(0))
+#define TRF7970A_MODULATOR_DEPTH_OOK (TRF7970A_MODULATOR_DEPTH(1))
+#define TRF7970A_MODULATOR_DEPTH_ASK7 (TRF7970A_MODULATOR_DEPTH(2))
+#define TRF7970A_MODULATOR_DEPTH_ASK8_5 (TRF7970A_MODULATOR_DEPTH(3))
+#define TRF7970A_MODULATOR_DEPTH_ASK13 (TRF7970A_MODULATOR_DEPTH(4))
+#define TRF7970A_MODULATOR_DEPTH_ASK16 (TRF7970A_MODULATOR_DEPTH(5))
+#define TRF7970A_MODULATOR_DEPTH_ASK22 (TRF7970A_MODULATOR_DEPTH(6))
+#define TRF7970A_MODULATOR_DEPTH_ASK30 (TRF7970A_MODULATOR_DEPTH(7))
+#define TRF7970A_MODULATOR_EN_ANA BIT(3)
+#define TRF7970A_MODULATOR_CLK(n) (((n) & 0x3) << 4)
+#define TRF7970A_MODULATOR_CLK_DISABLED (TRF7970A_MODULATOR_CLK(0))
+#define TRF7970A_MODULATOR_CLK_3_6 (TRF7970A_MODULATOR_CLK(1))
+#define TRF7970A_MODULATOR_CLK_6_13 (TRF7970A_MODULATOR_CLK(2))
+#define TRF7970A_MODULATOR_CLK_13_27 (TRF7970A_MODULATOR_CLK(3))
+#define TRF7970A_MODULATOR_EN_OOK BIT(6)
+#define TRF7970A_MODULATOR_27MHZ BIT(7)
+
+/* IRQ Status Register Bits */
+#define TRF7970A_IRQ_STATUS_NORESP BIT(0) /* ISO15693 only */
+#define TRF7970A_IRQ_STATUS_COL BIT(1)
+#define TRF7970A_IRQ_STATUS_FRAMING_EOF_ERROR BIT(2)
+#define TRF7970A_IRQ_STATUS_PARITY_ERROR BIT(3)
+#define TRF7970A_IRQ_STATUS_CRC_ERROR BIT(4)
+#define TRF7970A_IRQ_STATUS_FIFO BIT(5)
+#define TRF7970A_IRQ_STATUS_SRX BIT(6)
+#define TRF7970A_IRQ_STATUS_TX BIT(7)
+
+#define TRF7970A_IRQ_STATUS_ERROR \
+ (TRF7970A_IRQ_STATUS_COL | \
+ TRF7970A_IRQ_STATUS_FRAMING_EOF_ERROR | \
+ TRF7970A_IRQ_STATUS_PARITY_ERROR | \
+ TRF7970A_IRQ_STATUS_CRC_ERROR)
+
+#define TRF7970A_SPECIAL_FCN_REG1_COL_7_6 BIT(0)
+#define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL BIT(1)
+#define TRF7970A_SPECIAL_FCN_REG1_4_BIT_RX BIT(2)
+#define TRF7970A_SPECIAL_FCN_REG1_SP_DIR_MODE BIT(3)
+#define TRF7970A_SPECIAL_FCN_REG1_NEXT_SLOT_37US BIT(4)
+#define TRF7970A_SPECIAL_FCN_REG1_PAR43 BIT(5)
+
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_124 (0x0 << 2)
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_120 (0x1 << 2)
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_112 (0x2 << 2)
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_96 (0x3 << 2)
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_4 0x0
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_8 0x1
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_16 0x2
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_32 0x3
+
+#define TRF7970A_FIFO_STATUS_OVERFLOW BIT(7)
+
+/* NFC (ISO/IEC 14443A) Type 2 Tag commands */
+#define NFC_T2T_CMD_READ 0x30
+
+/* ISO 15693 commands codes */
+#define ISO15693_CMD_INVENTORY 0x01
+#define ISO15693_CMD_READ_SINGLE_BLOCK 0x20
+#define ISO15693_CMD_WRITE_SINGLE_BLOCK 0x21
+#define ISO15693_CMD_LOCK_BLOCK 0x22
+#define ISO15693_CMD_READ_MULTIPLE_BLOCK 0x23
+#define ISO15693_CMD_WRITE_MULTIPLE_BLOCK 0x24
+#define ISO15693_CMD_SELECT 0x25
+#define ISO15693_CMD_RESET_TO_READY 0x26
+#define ISO15693_CMD_WRITE_AFI 0x27
+#define ISO15693_CMD_LOCK_AFI 0x28
+#define ISO15693_CMD_WRITE_DSFID 0x29
+#define ISO15693_CMD_LOCK_DSFID 0x2a
+#define ISO15693_CMD_GET_SYSTEM_INFO 0x2b
+#define ISO15693_CMD_GET_MULTIPLE_BLOCK_SECURITY_STATUS 0x2c
+
+/* ISO 15693 request and response flags */
+#define ISO15693_REQ_FLAG_SUB_CARRIER BIT(0)
+#define ISO15693_REQ_FLAG_DATA_RATE BIT(1)
+#define ISO15693_REQ_FLAG_INVENTORY BIT(2)
+#define ISO15693_REQ_FLAG_PROTOCOL_EXT BIT(3)
+#define ISO15693_REQ_FLAG_SELECT BIT(4)
+#define ISO15693_REQ_FLAG_AFI BIT(4)
+#define ISO15693_REQ_FLAG_ADDRESS BIT(5)
+#define ISO15693_REQ_FLAG_NB_SLOTS BIT(5)
+#define ISO15693_REQ_FLAG_OPTION BIT(6)
+
+#define ISO15693_REQ_FLAG_SPEED_MASK \
+ (ISO15693_REQ_FLAG_SUB_CARRIER | ISO15693_REQ_FLAG_DATA_RATE)
+
+enum trf7970a_state {
+ TRF7970A_ST_OFF,
+ TRF7970A_ST_IDLE,
+ TRF7970A_ST_IDLE_RX_BLOCKED,
+ TRF7970A_ST_WAIT_FOR_TX_FIFO,
+ TRF7970A_ST_WAIT_FOR_RX_DATA,
+ TRF7970A_ST_WAIT_FOR_RX_DATA_CONT,
+ TRF7970A_ST_WAIT_TO_ISSUE_EOF,
+ TRF7970A_ST_MAX
+};
+
+struct trf7970a {
+ enum trf7970a_state state;
+ struct device *dev;
+ struct spi_device *spi;
+ struct regulator *regulator;
+ struct nfc_digital_dev *ddev;
+ u32 quirks;
+ bool powering_up;
+ bool aborting;
+ struct sk_buff *tx_skb;
+ struct sk_buff *rx_skb;
+ nfc_digital_cmd_complete_t cb;
+ void *cb_arg;
+ u8 iso_ctrl;
+ u8 special_fcn_reg1;
+ int technology;
+ int framing;
+ u8 tx_cmd;
+ bool issue_eof;
+ int en2_gpio;
+ int en_gpio;
+ struct mutex lock;
+ unsigned int timeout;
+ bool ignore_timeout;
+ struct delayed_work timeout_work;
+};
+
+
+static int trf7970a_cmd(struct trf7970a *trf, u8 opcode)
+{
+ u8 cmd = TRF7970A_CMD_BIT_CTRL | TRF7970A_CMD_BIT_OPCODE(opcode);
+ int ret;
+
+ dev_dbg(trf->dev, "cmd: 0x%x\n", cmd);
+
+ ret = spi_write(trf->spi, &cmd, 1);
+ if (ret)
+ dev_err(trf->dev, "%s - cmd: 0x%x, ret: %d\n", __func__, cmd,
+ ret);
+ return ret;
+}
+
+static int trf7970a_read(struct trf7970a *trf, u8 reg, u8 *val)
+{
+ u8 addr = TRF7970A_CMD_BIT_RW | reg;
+ int ret;
+
+ ret = spi_write_then_read(trf->spi, &addr, 1, val, 1);
+ if (ret)
+ dev_err(trf->dev, "%s - addr: 0x%x, ret: %d\n", __func__, addr,
+ ret);
+
+ dev_dbg(trf->dev, "read(0x%x): 0x%x\n", addr, *val);
+
+ return ret;
+}
+
+static int trf7970a_read_cont(struct trf7970a *trf, u8 reg,
+ u8 *buf, size_t len)
+{
+ u8 addr = reg | TRF7970A_CMD_BIT_RW | TRF7970A_CMD_BIT_CONTINUOUS;
+ int ret;
+
+ dev_dbg(trf->dev, "read_cont(0x%x, %zd)\n", addr, len);
+
+ ret = spi_write_then_read(trf->spi, &addr, 1, buf, len);
+ if (ret)
+ dev_err(trf->dev, "%s - addr: 0x%x, ret: %d\n", __func__, addr,
+ ret);
+ return ret;
+}
+
+static int trf7970a_write(struct trf7970a *trf, u8 reg, u8 val)
+{
+ u8 buf[2] = { reg, val };
+ int ret;
+
+ dev_dbg(trf->dev, "write(0x%x): 0x%x\n", reg, val);
+
+ ret = spi_write(trf->spi, buf, 2);
+ if (ret)
+ dev_err(trf->dev, "%s - write: 0x%x 0x%x, ret: %d\n", __func__,
+ buf[0], buf[1], ret);
+
+ return ret;
+}
+
+static int trf7970a_read_irqstatus(struct trf7970a *trf, u8 *status)
+{
+ int ret;
+ u8 buf[2];
+ u8 addr;
+
+ addr = TRF7970A_IRQ_STATUS | TRF7970A_CMD_BIT_RW;
+
+ if (trf->quirks & TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA) {
+ addr |= TRF7970A_CMD_BIT_CONTINUOUS;
+ ret = spi_write_then_read(trf->spi, &addr, 1, buf, 2);
+ } else {
+ ret = spi_write_then_read(trf->spi, &addr, 1, buf, 1);
+ }
+
+ if (ret)
+ dev_err(trf->dev, "%s - irqstatus: Status read failed: %d\n",
+ __func__, ret);
+ else
+ *status = buf[0];
+
+ return ret;
+}
+
+static void trf7970a_send_upstream(struct trf7970a *trf)
+{
+ u8 rssi;
+
+ dev_kfree_skb_any(trf->tx_skb);
+ trf->tx_skb = NULL;
+
+ if (trf->rx_skb && !IS_ERR(trf->rx_skb) && !trf->aborting)
+ print_hex_dump_debug("trf7970a rx data: ", DUMP_PREFIX_NONE,
+ 16, 1, trf->rx_skb->data, trf->rx_skb->len,
+ false);
+
+ /* According to the manual it is "good form" to reset the fifo and
+ * read the RSSI levels & oscillator status register here. It doesn't
+ * explain why.
+ */
+ trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
+ trf7970a_read(trf, TRF7970A_RSSI_OSC_STATUS, &rssi);
+
+ trf->state = TRF7970A_ST_IDLE;
+
+ if (trf->aborting) {
+ dev_dbg(trf->dev, "Abort process complete\n");
+
+ if (!IS_ERR(trf->rx_skb)) {
+ kfree_skb(trf->rx_skb);
+ trf->rx_skb = ERR_PTR(-ECANCELED);
+ }
+
+ trf->aborting = false;
+ }
+
+ trf->cb(trf->ddev, trf->cb_arg, trf->rx_skb);
+
+ trf->rx_skb = NULL;
+}
+
+static void trf7970a_send_err_upstream(struct trf7970a *trf, int errno)
+{
+ dev_dbg(trf->dev, "Error - state: %d, errno: %d\n", trf->state, errno);
+
+ kfree_skb(trf->rx_skb);
+ trf->rx_skb = ERR_PTR(errno);
+
+ trf7970a_send_upstream(trf);
+}
+
+static int trf7970a_transmit(struct trf7970a *trf, struct sk_buff *skb,
+ unsigned int len)
+{
+ unsigned int timeout;
+ int ret;
+
+ print_hex_dump_debug("trf7970a tx data: ", DUMP_PREFIX_NONE,
+ 16, 1, skb->data, len, false);
+
+ ret = spi_write(trf->spi, skb->data, len);
+ if (ret) {
+ dev_err(trf->dev, "%s - Can't send tx data: %d\n", __func__,
+ ret);
+ return ret;
+ }
+
+ skb_pull(skb, len);
+
+ if (skb->len > 0) {
+ trf->state = TRF7970A_ST_WAIT_FOR_TX_FIFO;
+ timeout = TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT;
+ } else {
+ if (trf->issue_eof) {
+ trf->state = TRF7970A_ST_WAIT_TO_ISSUE_EOF;
+ timeout = TRF7970A_WAIT_TO_ISSUE_ISO15693_EOF;
+ } else {
+ trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA;
+ timeout = trf->timeout;
+ }
+ }
+
+ dev_dbg(trf->dev, "Setting timeout for %d ms, state: %d\n", timeout,
+ trf->state);
+
+ schedule_delayed_work(&trf->timeout_work, msecs_to_jiffies(timeout));
+
+ return 0;
+}
+
+static void trf7970a_fill_fifo(struct trf7970a *trf)
+{
+ struct sk_buff *skb = trf->tx_skb;
+ unsigned int len;
+ int ret;
+ u8 fifo_bytes;
+
+ ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, &fifo_bytes);
+ if (ret) {
+ trf7970a_send_err_upstream(trf, ret);
+ return;
+ }
+
+ dev_dbg(trf->dev, "Filling FIFO - fifo_bytes: 0x%x\n", fifo_bytes);
+
+ if (fifo_bytes & TRF7970A_FIFO_STATUS_OVERFLOW) {
+ dev_err(trf->dev, "%s - fifo overflow: 0x%x\n", __func__,
+ fifo_bytes);
+ trf7970a_send_err_upstream(trf, -EIO);
+ return;
+ }
+
+ /* Calculate how much more data can be written to the fifo */
+ len = TRF7970A_FIFO_SIZE - fifo_bytes;
+ len = min(skb->len, len);
+
+ ret = trf7970a_transmit(trf, skb, len);
+ if (ret)
+ trf7970a_send_err_upstream(trf, ret);
+}
+
+static void trf7970a_drain_fifo(struct trf7970a *trf, u8 status)
+{
+ struct sk_buff *skb = trf->rx_skb;
+ int ret;
+ u8 fifo_bytes;
+
+ if (status & TRF7970A_IRQ_STATUS_ERROR) {
+ trf7970a_send_err_upstream(trf, -EIO);
+ return;
+ }
+
+ ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, &fifo_bytes);
+ if (ret) {
+ trf7970a_send_err_upstream(trf, ret);
+ return;
+ }
+
+ dev_dbg(trf->dev, "Draining FIFO - fifo_bytes: 0x%x\n", fifo_bytes);
+
+ if (!fifo_bytes)
+ goto no_rx_data;
+
+ if (fifo_bytes & TRF7970A_FIFO_STATUS_OVERFLOW) {
+ dev_err(trf->dev, "%s - fifo overflow: 0x%x\n", __func__,
+ fifo_bytes);
+ trf7970a_send_err_upstream(trf, -EIO);
+ return;
+ }
+
+ if (fifo_bytes > skb_tailroom(skb)) {
+ skb = skb_copy_expand(skb, skb_headroom(skb),
+ max_t(int, fifo_bytes,
+ TRF7970A_RX_SKB_ALLOC_SIZE),
+ GFP_KERNEL);
+ if (!skb) {
+ trf7970a_send_err_upstream(trf, -ENOMEM);
+ return;
+ }
+
+ kfree_skb(trf->rx_skb);
+ trf->rx_skb = skb;
+ }
+
+ ret = trf7970a_read_cont(trf, TRF7970A_FIFO_IO_REGISTER,
+ skb_put(skb, fifo_bytes), fifo_bytes);
+ if (ret) {
+ trf7970a_send_err_upstream(trf, ret);
+ return;
+ }
+
+ /* If received Type 2 ACK/NACK, shift right 4 bits and pass up */
+ if ((trf->framing == NFC_DIGITAL_FRAMING_NFCA_T2T) && (skb->len == 1) &&
+ (trf->special_fcn_reg1 ==
+ TRF7970A_SPECIAL_FCN_REG1_4_BIT_RX)) {
+ skb->data[0] >>= 4;
+ status = TRF7970A_IRQ_STATUS_SRX;
+ } else {
+ trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA_CONT;
+ }
+
+no_rx_data:
+ if (status == TRF7970A_IRQ_STATUS_SRX) { /* Receive complete */
+ trf7970a_send_upstream(trf);
+ return;
+ }
+
+ dev_dbg(trf->dev, "Setting timeout for %d ms\n",
+ TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT);
+
+ schedule_delayed_work(&trf->timeout_work,
+ msecs_to_jiffies(TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT));
+}
+
+static irqreturn_t trf7970a_irq(int irq, void *dev_id)
+{
+ struct trf7970a *trf = dev_id;
+ int ret;
+ u8 status;
+
+ mutex_lock(&trf->lock);
+
+ if (trf->state == TRF7970A_ST_OFF) {
+ mutex_unlock(&trf->lock);
+ return IRQ_NONE;
+ }
+
+ ret = trf7970a_read_irqstatus(trf, &status);
+ if (ret) {
+ mutex_unlock(&trf->lock);
+ return IRQ_NONE;
+ }
+
+ dev_dbg(trf->dev, "IRQ - state: %d, status: 0x%x\n", trf->state,
+ status);
+
+ if (!status) {
+ mutex_unlock(&trf->lock);
+ return IRQ_NONE;
+ }
+
+ switch (trf->state) {
+ case TRF7970A_ST_IDLE:
+ case TRF7970A_ST_IDLE_RX_BLOCKED:
+ /* If getting interrupts caused by RF noise, turn off the
+ * receiver to avoid unnecessary interrupts. It will be
+ * turned back on in trf7970a_in_send_cmd() when the next
+ * command is issued.
+ */
+ if (status & TRF7970A_IRQ_STATUS_ERROR) {
+ trf7970a_cmd(trf, TRF7970A_CMD_BLOCK_RX);
+ trf->state = TRF7970A_ST_IDLE_RX_BLOCKED;
+ }
+
+ trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
+ break;
+ case TRF7970A_ST_WAIT_FOR_TX_FIFO:
+ if (status & TRF7970A_IRQ_STATUS_TX) {
+ trf->ignore_timeout =
+ !cancel_delayed_work(&trf->timeout_work);
+ trf7970a_fill_fifo(trf);
+ } else {
+ trf7970a_send_err_upstream(trf, -EIO);
+ }
+ break;
+ case TRF7970A_ST_WAIT_FOR_RX_DATA:
+ case TRF7970A_ST_WAIT_FOR_RX_DATA_CONT:
+ if (status & TRF7970A_IRQ_STATUS_SRX) {
+ trf->ignore_timeout =
+ !cancel_delayed_work(&trf->timeout_work);
+ trf7970a_drain_fifo(trf, status);
+ } else if (!(status & TRF7970A_IRQ_STATUS_TX)) {
+ trf7970a_send_err_upstream(trf, -EIO);
+ }
+ break;
+ case TRF7970A_ST_WAIT_TO_ISSUE_EOF:
+ if (status != TRF7970A_IRQ_STATUS_TX)
+ trf7970a_send_err_upstream(trf, -EIO);
+ break;
+ default:
+ dev_err(trf->dev, "%s - Driver in invalid state: %d\n",
+ __func__, trf->state);
+ }
+
+ mutex_unlock(&trf->lock);
+ return IRQ_HANDLED;
+}
+
+static void trf7970a_issue_eof(struct trf7970a *trf)
+{
+ int ret;
+
+ dev_dbg(trf->dev, "Issuing EOF\n");
+
+ ret = trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
+ if (ret)
+ trf7970a_send_err_upstream(trf, ret);
+
+ ret = trf7970a_cmd(trf, TRF7970A_CMD_EOF);
+ if (ret)
+ trf7970a_send_err_upstream(trf, ret);
+
+ trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA;
+
+ dev_dbg(trf->dev, "Setting timeout for %d ms, state: %d\n",
+ trf->timeout, trf->state);
+
+ schedule_delayed_work(&trf->timeout_work,
+ msecs_to_jiffies(trf->timeout));
+}
+
+static void trf7970a_timeout_work_handler(struct work_struct *work)
+{
+ struct trf7970a *trf = container_of(work, struct trf7970a,
+ timeout_work.work);
+
+ dev_dbg(trf->dev, "Timeout - state: %d, ignore_timeout: %d\n",
+ trf->state, trf->ignore_timeout);
+
+ mutex_lock(&trf->lock);
+
+ if (trf->ignore_timeout)
+ trf->ignore_timeout = false;
+ else if (trf->state == TRF7970A_ST_WAIT_FOR_RX_DATA_CONT)
+ trf7970a_send_upstream(trf); /* No more rx data so send up */
+ else if (trf->state == TRF7970A_ST_WAIT_TO_ISSUE_EOF)
+ trf7970a_issue_eof(trf);
+ else
+ trf7970a_send_err_upstream(trf, -ETIMEDOUT);
+
+ mutex_unlock(&trf->lock);
+}
+
+static int trf7970a_init(struct trf7970a *trf)
+{
+ int ret;
+
+ dev_dbg(trf->dev, "Initializing device - state: %d\n", trf->state);
+
+ ret = trf7970a_cmd(trf, TRF7970A_CMD_SOFT_INIT);
+ if (ret)
+ goto err_out;
+
+ ret = trf7970a_cmd(trf, TRF7970A_CMD_IDLE);
+ if (ret)
+ goto err_out;
+
+ ret = trf7970a_write(trf, TRF7970A_MODULATOR_SYS_CLK_CTRL,
+ TRF7970A_MODULATOR_DEPTH_OOK);
+ if (ret)
+ goto err_out;
+
+ ret = trf7970a_write(trf, TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS,
+ TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_96 |
+ TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_32);
+ if (ret)
+ goto err_out;
+
+ ret = trf7970a_write(trf, TRF7970A_SPECIAL_FCN_REG1, 0);
+ if (ret)
+ goto err_out;
+
+ trf->special_fcn_reg1 = 0;
+
+ ret = trf7970a_write(trf, TRF7970A_CHIP_STATUS_CTRL,
+ TRF7970A_CHIP_STATUS_RF_ON |
+ TRF7970A_CHIP_STATUS_VRS5_3);
+ if (ret)
+ goto err_out;
+
+ return 0;
+
+err_out:
+ dev_dbg(trf->dev, "Couldn't init device: %d\n", ret);
+ return ret;
+}
+
+static void trf7970a_switch_rf_off(struct trf7970a *trf)
+{
+ dev_dbg(trf->dev, "Switching rf off\n");
+
+ gpio_set_value(trf->en_gpio, 0);
+ gpio_set_value(trf->en2_gpio, 0);
+
+ trf->aborting = false;
+ trf->state = TRF7970A_ST_OFF;
+}
+
+static int trf7970a_switch_rf_on(struct trf7970a *trf)
+{
+ unsigned long delay;
+ int ret;
+
+ dev_dbg(trf->dev, "Switching rf on\n");
+
+ if (trf->powering_up)
+ usleep_range(5000, 6000);
+
+ gpio_set_value(trf->en2_gpio, 1);
+ usleep_range(1000, 2000);
+ gpio_set_value(trf->en_gpio, 1);
+
+ /* The delay between enabling the trf7970a and issuing the first
+ * command is significantly longer the very first time after powering
+ * up. Make sure the longer delay is only done the first time.
+ */
+ if (trf->powering_up) {
+ delay = 20000;
+ trf->powering_up = false;
+ } else {
+ delay = 5000;
+ }
+
+ usleep_range(delay, delay + 1000);
+
+ ret = trf7970a_init(trf);
+ if (ret)
+ trf7970a_switch_rf_off(trf);
+ else
+ trf->state = TRF7970A_ST_IDLE;
+
+ return ret;
+}
+
+static int trf7970a_switch_rf(struct nfc_digital_dev *ddev, bool on)
+{
+ struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+ int ret = 0;
+
+ dev_dbg(trf->dev, "Switching RF - state: %d, on: %d\n", trf->state, on);
+
+ mutex_lock(&trf->lock);
+
+ if (on) {
+ switch (trf->state) {
+ case TRF7970A_ST_OFF:
+ ret = trf7970a_switch_rf_on(trf);
+ break;
+ case TRF7970A_ST_IDLE:
+ case TRF7970A_ST_IDLE_RX_BLOCKED:
+ break;
+ default:
+ dev_err(trf->dev, "%s - Invalid request: %d %d\n",
+ __func__, trf->state, on);
+ trf7970a_switch_rf_off(trf);
+ }
+ } else {
+ switch (trf->state) {
+ case TRF7970A_ST_OFF:
+ break;
+ default:
+ dev_err(trf->dev, "%s - Invalid request: %d %d\n",
+ __func__, trf->state, on);
+ /* FALLTHROUGH */
+ case TRF7970A_ST_IDLE:
+ case TRF7970A_ST_IDLE_RX_BLOCKED:
+ trf7970a_switch_rf_off(trf);
+ }
+ }
+
+ mutex_unlock(&trf->lock);
+ return ret;
+}
+
+static int trf7970a_config_rf_tech(struct trf7970a *trf, int tech)
+{
+ int ret = 0;
+
+ dev_dbg(trf->dev, "rf technology: %d\n", tech);
+
+ switch (tech) {
+ case NFC_DIGITAL_RF_TECH_106A:
+ trf->iso_ctrl = TRF7970A_ISO_CTRL_14443A_106;
+ break;
+ case NFC_DIGITAL_RF_TECH_ISO15693:
+ trf->iso_ctrl = TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648;
+ break;
+ default:
+ dev_dbg(trf->dev, "Unsupported rf technology: %d\n", tech);
+ return -EINVAL;
+ }
+
+ trf->technology = tech;
+
+ return ret;
+}
+
+static int trf7970a_config_framing(struct trf7970a *trf, int framing)
+{
+ dev_dbg(trf->dev, "framing: %d\n", framing);
+
+ switch (framing) {
+ case NFC_DIGITAL_FRAMING_NFCA_SHORT:
+ case NFC_DIGITAL_FRAMING_NFCA_STANDARD:
+ trf->tx_cmd = TRF7970A_CMD_TRANSMIT_NO_CRC;
+ trf->iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N;
+ break;
+ case NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A:
+ case NFC_DIGITAL_FRAMING_NFCA_T4T:
+ case NFC_DIGITAL_FRAMING_ISO15693_INVENTORY:
+ case NFC_DIGITAL_FRAMING_ISO15693_T5T:
+ trf->tx_cmd = TRF7970A_CMD_TRANSMIT;
+ trf->iso_ctrl &= ~TRF7970A_ISO_CTRL_RX_CRC_N;
+ break;
+ case NFC_DIGITAL_FRAMING_NFCA_T2T:
+ trf->tx_cmd = TRF7970A_CMD_TRANSMIT;
+ trf->iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N;
+ break;
+ default:
+ dev_dbg(trf->dev, "Unsupported Framing: %d\n", framing);
+ return -EINVAL;
+ }
+
+ trf->framing = framing;
+
+ return trf7970a_write(trf, TRF7970A_ISO_CTRL, trf->iso_ctrl);
+}
+
+static int trf7970a_in_configure_hw(struct nfc_digital_dev *ddev, int type,
+ int param)
+{
+ struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+ int ret = 0;
+
+ dev_dbg(trf->dev, "Configure hw - type: %d, param: %d\n", type, param);
+
+ mutex_lock(&trf->lock);
+
+ if (trf->state == TRF7970A_ST_OFF) {
+ ret = trf7970a_switch_rf_on(trf);
+ if (ret)
+ goto err_out;
+ }
+
+ switch (type) {
+ case NFC_DIGITAL_CONFIG_RF_TECH:
+ ret = trf7970a_config_rf_tech(trf, param);
+ break;
+ case NFC_DIGITAL_CONFIG_FRAMING:
+ ret = trf7970a_config_framing(trf, param);
+ break;
+ default:
+ dev_dbg(trf->dev, "Unknown type: %d\n", type);
+ ret = -EINVAL;
+ }
+
+err_out:
+ mutex_unlock(&trf->lock);
+ return ret;
+}
+
+static int trf7970a_is_iso15693_write_or_lock(u8 cmd)
+{
+ switch (cmd) {
+ case ISO15693_CMD_WRITE_SINGLE_BLOCK:
+ case ISO15693_CMD_LOCK_BLOCK:
+ case ISO15693_CMD_WRITE_MULTIPLE_BLOCK:
+ case ISO15693_CMD_WRITE_AFI:
+ case ISO15693_CMD_LOCK_AFI:
+ case ISO15693_CMD_WRITE_DSFID:
+ case ISO15693_CMD_LOCK_DSFID:
+ return 1;
+ break;
+ default:
+ return 0;
+ }
+}
+
+static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb)
+{
+ u8 *req = skb->data;
+ u8 special_fcn_reg1, iso_ctrl;
+ int ret;
+
+ trf->issue_eof = false;
+
+ /* When issuing Type 2 read command, make sure the '4_bit_RX' bit in
+ * special functions register 1 is cleared; otherwise, its a write or
+ * sector select command and '4_bit_RX' must be set.
+ *
+ * When issuing an ISO 15693 command, inspect the flags byte to see
+ * what speed to use. Also, remember if the OPTION flag is set on
+ * a Type 5 write or lock command so the driver will know that it
+ * has to send an EOF in order to get a response.
+ */
+ if ((trf->technology == NFC_DIGITAL_RF_TECH_106A) &&
+ (trf->framing == NFC_DIGITAL_FRAMING_NFCA_T2T)) {
+ if (req[0] == NFC_T2T_CMD_READ)
+ special_fcn_reg1 = 0;
+ else
+ special_fcn_reg1 = TRF7970A_SPECIAL_FCN_REG1_4_BIT_RX;
+
+ if (special_fcn_reg1 != trf->special_fcn_reg1) {
+ ret = trf7970a_write(trf, TRF7970A_SPECIAL_FCN_REG1,
+ special_fcn_reg1);
+ if (ret)
+ return ret;
+
+ trf->special_fcn_reg1 = special_fcn_reg1;
+ }
+ } else if (trf->technology == NFC_DIGITAL_RF_TECH_ISO15693) {
+ iso_ctrl = trf->iso_ctrl & ~TRF7970A_ISO_CTRL_RFID_SPEED_MASK;
+
+ switch (req[0] & ISO15693_REQ_FLAG_SPEED_MASK) {
+ case 0x00:
+ iso_ctrl |= TRF7970A_ISO_CTRL_15693_SGL_1OF4_662;
+ break;
+ case ISO15693_REQ_FLAG_SUB_CARRIER:
+ iso_ctrl |= TRF7970A_ISO_CTRL_15693_DBL_1OF4_667a;
+ break;
+ case ISO15693_REQ_FLAG_DATA_RATE:
+ iso_ctrl |= TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648;
+ break;
+ case (ISO15693_REQ_FLAG_SUB_CARRIER |
+ ISO15693_REQ_FLAG_DATA_RATE):
+ iso_ctrl |= TRF7970A_ISO_CTRL_15693_DBL_1OF4_2669;
+ break;
+ }
+
+ if (iso_ctrl != trf->iso_ctrl) {
+ ret = trf7970a_write(trf, TRF7970A_ISO_CTRL, iso_ctrl);
+ if (ret)
+ return ret;
+
+ trf->iso_ctrl = iso_ctrl;
+ }
+
+ if ((trf->framing == NFC_DIGITAL_FRAMING_ISO15693_T5T) &&
+ trf7970a_is_iso15693_write_or_lock(req[1]) &&
+ (req[0] & ISO15693_REQ_FLAG_OPTION))
+ trf->issue_eof = true;
+ }
+
+ return 0;
+}
+
+static int trf7970a_in_send_cmd(struct nfc_digital_dev *ddev,
+ struct sk_buff *skb, u16 timeout,
+ nfc_digital_cmd_complete_t cb, void *arg)
+{
+ struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+ char *prefix;
+ unsigned int len;
+ int ret;
+
+ dev_dbg(trf->dev, "New request - state: %d, timeout: %d ms, len: %d\n",
+ trf->state, timeout, skb->len);
+
+ if (skb->len > TRF7970A_TX_MAX)
+ return -EINVAL;
+
+ mutex_lock(&trf->lock);
+
+ if ((trf->state != TRF7970A_ST_IDLE) &&
+ (trf->state != TRF7970A_ST_IDLE_RX_BLOCKED)) {
+ dev_err(trf->dev, "%s - Bogus state: %d\n", __func__,
+ trf->state);
+ ret = -EIO;
+ goto out_err;
+ }
+
+ if (trf->aborting) {
+ dev_dbg(trf->dev, "Abort process complete\n");
+ trf->aborting = false;
+ ret = -ECANCELED;
+ goto out_err;
+ }
+
+ trf->rx_skb = nfc_alloc_recv_skb(TRF7970A_RX_SKB_ALLOC_SIZE,
+ GFP_KERNEL);
+ if (!trf->rx_skb) {
+ dev_dbg(trf->dev, "Can't alloc rx_skb\n");
+ ret = -ENOMEM;
+ goto out_err;
+ }
+
+ if (trf->state == TRF7970A_ST_IDLE_RX_BLOCKED) {
+ ret = trf7970a_cmd(trf, TRF7970A_CMD_ENABLE_RX);
+ if (ret)
+ goto out_err;
+
+ trf->state = TRF7970A_ST_IDLE;
+ }
+
+ ret = trf7970a_per_cmd_config(trf, skb);
+ if (ret)
+ goto out_err;
+
+ trf->ddev = ddev;
+ trf->tx_skb = skb;
+ trf->cb = cb;
+ trf->cb_arg = arg;
+ trf->timeout = timeout;
+ trf->ignore_timeout = false;
+
+ len = skb->len;
+ prefix = skb_push(skb, TRF7970A_TX_SKB_HEADROOM);
+
+ /* TX data must be prefixed with a FIFO reset cmd, a cmd that depends
+ * on what the current framing is, the address of the TX length byte 1
+ * register (0x1d), and the 2 byte length of the data to be transmitted.
+ */
+ prefix[0] = TRF7970A_CMD_BIT_CTRL |
+ TRF7970A_CMD_BIT_OPCODE(TRF7970A_CMD_FIFO_RESET);
+ prefix[1] = TRF7970A_CMD_BIT_CTRL |
+ TRF7970A_CMD_BIT_OPCODE(trf->tx_cmd);
+ prefix[2] = TRF7970A_CMD_BIT_CONTINUOUS | TRF7970A_TX_LENGTH_BYTE1;
+
+ if (trf->framing == NFC_DIGITAL_FRAMING_NFCA_SHORT) {
+ prefix[3] = 0x00;
+ prefix[4] = 0x0f; /* 7 bits */
+ } else {
+ prefix[3] = (len & 0xf00) >> 4;
+ prefix[3] |= ((len & 0xf0) >> 4);
+ prefix[4] = ((len & 0x0f) << 4);
+ }
+
+ len = min_t(int, skb->len, TRF7970A_FIFO_SIZE);
+
+ usleep_range(1000, 2000);
+
+ ret = trf7970a_transmit(trf, skb, len);
+ if (ret) {
+ kfree_skb(trf->rx_skb);
+ trf->rx_skb = NULL;
+ }
+
+out_err:
+ mutex_unlock(&trf->lock);
+ return ret;
+}
+
+static int trf7970a_tg_configure_hw(struct nfc_digital_dev *ddev,
+ int type, int param)
+{
+ struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+
+ dev_dbg(trf->dev, "Unsupported interface\n");
+
+ return -EINVAL;
+}
+
+static int trf7970a_tg_send_cmd(struct nfc_digital_dev *ddev,
+ struct sk_buff *skb, u16 timeout,
+ nfc_digital_cmd_complete_t cb, void *arg)
+{
+ struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+
+ dev_dbg(trf->dev, "Unsupported interface\n");
+
+ return -EINVAL;
+}
+
+static int trf7970a_tg_listen(struct nfc_digital_dev *ddev,
+ u16 timeout, nfc_digital_cmd_complete_t cb, void *arg)
+{
+ struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+
+ dev_dbg(trf->dev, "Unsupported interface\n");
+
+ return -EINVAL;
+}
+
+static int trf7970a_tg_listen_mdaa(struct nfc_digital_dev *ddev,
+ struct digital_tg_mdaa_params *mdaa_params,
+ u16 timeout, nfc_digital_cmd_complete_t cb, void *arg)
+{
+ struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+
+ dev_dbg(trf->dev, "Unsupported interface\n");
+
+ return -EINVAL;
+}
+
+static void trf7970a_abort_cmd(struct nfc_digital_dev *ddev)
+{
+ struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+
+ dev_dbg(trf->dev, "Abort process initiated\n");
+
+ mutex_lock(&trf->lock);
+ trf->aborting = true;
+ mutex_unlock(&trf->lock);
+}
+
+static struct nfc_digital_ops trf7970a_nfc_ops = {
+ .in_configure_hw = trf7970a_in_configure_hw,
+ .in_send_cmd = trf7970a_in_send_cmd,
+ .tg_configure_hw = trf7970a_tg_configure_hw,
+ .tg_send_cmd = trf7970a_tg_send_cmd,
+ .tg_listen = trf7970a_tg_listen,
+ .tg_listen_mdaa = trf7970a_tg_listen_mdaa,
+ .switch_rf = trf7970a_switch_rf,
+ .abort_cmd = trf7970a_abort_cmd,
+};
+
+static int trf7970a_probe(struct spi_device *spi)
+{
+ struct device_node *np = spi->dev.of_node;
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ struct trf7970a *trf;
+ int ret;
+
+ if (!np) {
+ dev_err(&spi->dev, "No Device Tree entry\n");
+ return -EINVAL;
+ }
+
+ trf = devm_kzalloc(&spi->dev, sizeof(*trf), GFP_KERNEL);
+ if (!trf)
+ return -ENOMEM;
+
+ trf->state = TRF7970A_ST_OFF;
+ trf->dev = &spi->dev;
+ trf->spi = spi;
+ trf->quirks = id->driver_data;
+
+ spi->mode = SPI_MODE_1;
+ spi->bits_per_word = 8;
+
+ /* There are two enable pins - both must be present */
+ trf->en_gpio = of_get_named_gpio(np, "ti,enable-gpios", 0);
+ if (!gpio_is_valid(trf->en_gpio)) {
+ dev_err(trf->dev, "No EN GPIO property\n");
+ return trf->en_gpio;
+ }
+
+ ret = devm_gpio_request_one(trf->dev, trf->en_gpio,
+ GPIOF_DIR_OUT | GPIOF_INIT_LOW, "EN");
+ if (ret) {
+ dev_err(trf->dev, "Can't request EN GPIO: %d\n", ret);
+ return ret;
+ }
+
+ trf->en2_gpio = of_get_named_gpio(np, "ti,enable-gpios", 1);
+ if (!gpio_is_valid(trf->en2_gpio)) {
+ dev_err(trf->dev, "No EN2 GPIO property\n");
+ return trf->en2_gpio;
+ }
+
+ ret = devm_gpio_request_one(trf->dev, trf->en2_gpio,
+ GPIOF_DIR_OUT | GPIOF_INIT_LOW, "EN2");
+ if (ret) {
+ dev_err(trf->dev, "Can't request EN2 GPIO: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_request_threaded_irq(trf->dev, spi->irq, NULL,
+ trf7970a_irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "trf7970a", trf);
+ if (ret) {
+ dev_err(trf->dev, "Can't request IRQ#%d: %d\n", spi->irq, ret);
+ return ret;
+ }
+
+ mutex_init(&trf->lock);
+ INIT_DELAYED_WORK(&trf->timeout_work, trf7970a_timeout_work_handler);
+
+ trf->regulator = devm_regulator_get(&spi->dev, "vin");
+ if (IS_ERR(trf->regulator)) {
+ ret = PTR_ERR(trf->regulator);
+ dev_err(trf->dev, "Can't get VIN regulator: %d\n", ret);
+ goto err_destroy_lock;
+ }
+
+ ret = regulator_enable(trf->regulator);
+ if (ret) {
+ dev_err(trf->dev, "Can't enable VIN: %d\n", ret);
+ goto err_destroy_lock;
+ }
+
+ trf->powering_up = true;
+
+ trf->ddev = nfc_digital_allocate_device(&trf7970a_nfc_ops,
+ TRF7970A_SUPPORTED_PROTOCOLS,
+ NFC_DIGITAL_DRV_CAPS_IN_CRC, TRF7970A_TX_SKB_HEADROOM,
+ 0);
+ if (!trf->ddev) {
+ dev_err(trf->dev, "Can't allocate NFC digital device\n");
+ ret = -ENOMEM;
+ goto err_disable_regulator;
+ }
+
+ nfc_digital_set_parent_dev(trf->ddev, trf->dev);
+ nfc_digital_set_drvdata(trf->ddev, trf);
+ spi_set_drvdata(spi, trf);
+
+ ret = nfc_digital_register_device(trf->ddev);
+ if (ret) {
+ dev_err(trf->dev, "Can't register NFC digital device: %d\n",
+ ret);
+ goto err_free_ddev;
+ }
+
+ return 0;
+
+err_free_ddev:
+ nfc_digital_free_device(trf->ddev);
+err_disable_regulator:
+ regulator_disable(trf->regulator);
+err_destroy_lock:
+ mutex_destroy(&trf->lock);
+ return ret;
+}
+
+static int trf7970a_remove(struct spi_device *spi)
+{
+ struct trf7970a *trf = spi_get_drvdata(spi);
+
+ mutex_lock(&trf->lock);
+
+ trf7970a_switch_rf_off(trf);
+ trf7970a_init(trf);
+
+ switch (trf->state) {
+ case TRF7970A_ST_WAIT_FOR_TX_FIFO:
+ case TRF7970A_ST_WAIT_FOR_RX_DATA:
+ case TRF7970A_ST_WAIT_FOR_RX_DATA_CONT:
+ case TRF7970A_ST_WAIT_TO_ISSUE_EOF:
+ trf7970a_send_err_upstream(trf, -ECANCELED);
+ break;
+ default:
+ break;
+ }
+
+ mutex_unlock(&trf->lock);
+
+ nfc_digital_unregister_device(trf->ddev);
+ nfc_digital_free_device(trf->ddev);
+
+ regulator_disable(trf->regulator);
+
+ mutex_destroy(&trf->lock);
+
+ return 0;
+}
+
+static const struct spi_device_id trf7970a_id_table[] = {
+ { "trf7970a", TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, trf7970a_id_table);
+
+static struct spi_driver trf7970a_spi_driver = {
+ .probe = trf7970a_probe,
+ .remove = trf7970a_remove,
+ .id_table = trf7970a_id_table,
+ .driver = {
+ .name = "trf7970a",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_spi_driver(trf7970a_spi_driver);
+
+MODULE_AUTHOR("Mark A. Greer <mgreer@animalcreek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TI trf7970a RFID/NFC Transceiver Driver");
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index c6973f101a3e..889005fa4d04 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -7,14 +7,6 @@ config OF
menu "Device Tree and Open Firmware support"
depends on OF
-config PROC_DEVICETREE
- bool "Support for device tree in /proc"
- depends on PROC_FS && !SPARC
- help
- This option adds a device-tree directory under /proc which contains
- an image of the device tree that the kernel copies from Open
- Firmware or other boot firmware. If unsure, say Y here.
-
config OF_SELFTEST
bool "Device Tree Runtime self tests"
depends on OF_IRQ
@@ -44,6 +36,10 @@ config OF_DYNAMIC
config OF_ADDRESS
def_bool y
depends on !SPARC
+ select OF_ADDRESS_PCI if PCI
+
+config OF_ADDRESS_PCI
+ bool
config OF_IRQ
def_bool y
@@ -75,4 +71,10 @@ config OF_MTD
depends on MTD
def_bool y
+config OF_RESERVED_MEM
+ depends on OF_EARLY_FLATTREE
+ bool
+ help
+ Helpers to allow for reservation of memory regions
+
endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index efd05102c405..ed9660adad77 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o
obj-$(CONFIG_OF_PCI) += of_pci.o
obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
obj-$(CONFIG_OF_MTD) += of_mtd.o
+obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
diff --git a/drivers/of/address.c b/drivers/of/address.c
index d3dd41c840f1..cb4242a69cd5 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -91,7 +91,7 @@ static unsigned int of_bus_default_get_flags(const __be32 *addr)
return IORESOURCE_MEM;
}
-#ifdef CONFIG_PCI
+#ifdef CONFIG_OF_ADDRESS_PCI
/*
* PCI bus specific translator
*/
@@ -99,11 +99,12 @@ static unsigned int of_bus_default_get_flags(const __be32 *addr)
static int of_bus_pci_match(struct device_node *np)
{
/*
+ * "pciex" is PCI Express
* "vci" is for the /chaos bridge on 1st-gen PCI powermacs
* "ht" is hypertransport
*/
- return !strcmp(np->type, "pci") || !strcmp(np->type, "vci") ||
- !strcmp(np->type, "ht");
+ return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex") ||
+ !strcmp(np->type, "vci") || !strcmp(np->type, "ht");
}
static void of_bus_pci_count_cells(struct device_node *np,
@@ -165,7 +166,9 @@ static int of_bus_pci_translate(__be32 *addr, u64 offset, int na)
{
return of_bus_default_translate(addr + 1, offset, na - 1);
}
+#endif /* CONFIG_OF_ADDRESS_PCI */
+#ifdef CONFIG_PCI
const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
unsigned int *flags)
{
@@ -355,7 +358,7 @@ static unsigned int of_bus_isa_get_flags(const __be32 *addr)
*/
static struct of_bus of_busses[] = {
-#ifdef CONFIG_PCI
+#ifdef CONFIG_OF_ADDRESS_PCI
/* PCI */
{
.name = "pci",
@@ -366,7 +369,7 @@ static struct of_bus of_busses[] = {
.translate = of_bus_pci_translate,
.get_flags = of_bus_pci_get_flags,
},
-#endif /* CONFIG_PCI */
+#endif /* CONFIG_OF_ADDRESS_PCI */
/* ISA */
{
.name = "isa",
diff --git a/drivers/of/base.c b/drivers/of/base.c
index ff85450d5683..f72d19b7e5d2 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -21,8 +21,10 @@
#include <linux/cpu.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_graph.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/proc_fs.h>
#include "of_private.h"
@@ -35,6 +37,12 @@ struct device_node *of_chosen;
struct device_node *of_aliases;
static struct device_node *of_stdout;
+static struct kset *of_kset;
+
+/*
+ * Used to protect the of_aliases; but also overloaded to hold off addition of
+ * nodes to sysfs
+ */
DEFINE_MUTEX(of_aliases_mutex);
/* use when traversing tree through the allnext, child, sibling,
@@ -92,14 +100,14 @@ int __weak of_node_to_nid(struct device_node *np)
struct device_node *of_node_get(struct device_node *node)
{
if (node)
- kref_get(&node->kref);
+ kobject_get(&node->kobj);
return node;
}
EXPORT_SYMBOL(of_node_get);
-static inline struct device_node *kref_to_device_node(struct kref *kref)
+static inline struct device_node *kobj_to_device_node(struct kobject *kobj)
{
- return container_of(kref, struct device_node, kref);
+ return container_of(kobj, struct device_node, kobj);
}
/**
@@ -109,16 +117,15 @@ static inline struct device_node *kref_to_device_node(struct kref *kref)
* In of_node_put() this function is passed to kref_put()
* as the destructor.
*/
-static void of_node_release(struct kref *kref)
+static void of_node_release(struct kobject *kobj)
{
- struct device_node *node = kref_to_device_node(kref);
+ struct device_node *node = kobj_to_device_node(kobj);
struct property *prop = node->properties;
/* We should never be releasing nodes that haven't been detached. */
if (!of_node_check_flag(node, OF_DETACHED)) {
pr_err("ERROR: Bad of_node_put() on %s\n", node->full_name);
dump_stack();
- kref_init(&node->kref);
return;
}
@@ -151,11 +158,154 @@ static void of_node_release(struct kref *kref)
void of_node_put(struct device_node *node)
{
if (node)
- kref_put(&node->kref, of_node_release);
+ kobject_put(&node->kobj);
}
EXPORT_SYMBOL(of_node_put);
+#else
+static void of_node_release(struct kobject *kobj)
+{
+ /* Without CONFIG_OF_DYNAMIC, no nodes gets freed */
+}
#endif /* CONFIG_OF_DYNAMIC */
+struct kobj_type of_node_ktype = {
+ .release = of_node_release,
+};
+
+static ssize_t of_node_property_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t offset, size_t count)
+{
+ struct property *pp = container_of(bin_attr, struct property, attr);
+ return memory_read_from_buffer(buf, count, &offset, pp->value, pp->length);
+}
+
+static const char *safe_name(struct kobject *kobj, const char *orig_name)
+{
+ const char *name = orig_name;
+ struct kernfs_node *kn;
+ int i = 0;
+
+ /* don't be a hero. After 16 tries give up */
+ while (i < 16 && (kn = sysfs_get_dirent(kobj->sd, name))) {
+ sysfs_put(kn);
+ if (name != orig_name)
+ kfree(name);
+ name = kasprintf(GFP_KERNEL, "%s#%i", orig_name, ++i);
+ }
+
+ if (name != orig_name)
+ pr_warn("device-tree: Duplicate name in %s, renamed to \"%s\"\n",
+ kobject_name(kobj), name);
+ return name;
+}
+
+static int __of_add_property_sysfs(struct device_node *np, struct property *pp)
+{
+ int rc;
+
+ /* Important: Don't leak passwords */
+ bool secure = strncmp(pp->name, "security-", 9) == 0;
+
+ sysfs_bin_attr_init(&pp->attr);
+ pp->attr.attr.name = safe_name(&np->kobj, pp->name);
+ pp->attr.attr.mode = secure ? S_IRUSR : S_IRUGO;
+ pp->attr.size = secure ? 0 : pp->length;
+ pp->attr.read = of_node_property_read;
+
+ rc = sysfs_create_bin_file(&np->kobj, &pp->attr);
+ WARN(rc, "error adding attribute %s to node %s\n", pp->name, np->full_name);
+ return rc;
+}
+
+static int __of_node_add(struct device_node *np)
+{
+ const char *name;
+ struct property *pp;
+ int rc;
+
+ np->kobj.kset = of_kset;
+ if (!np->parent) {
+ /* Nodes without parents are new top level trees */
+ rc = kobject_add(&np->kobj, NULL, safe_name(&of_kset->kobj, "base"));
+ } else {
+ name = safe_name(&np->parent->kobj, kbasename(np->full_name));
+ if (!name || !name[0])
+ return -EINVAL;
+
+ rc = kobject_add(&np->kobj, &np->parent->kobj, "%s", name);
+ }
+ if (rc)
+ return rc;
+
+ for_each_property_of_node(np, pp)
+ __of_add_property_sysfs(np, pp);
+
+ return 0;
+}
+
+int of_node_add(struct device_node *np)
+{
+ int rc = 0;
+
+ BUG_ON(!of_node_is_initialized(np));
+
+ /*
+ * Grab the mutex here so that in a race condition between of_init() and
+ * of_node_add(), node addition will still be consistent.
+ */
+ mutex_lock(&of_aliases_mutex);
+ if (of_kset)
+ rc = __of_node_add(np);
+ else
+ /* This scenario may be perfectly valid, but report it anyway */
+ pr_info("of_node_add(%s) before of_init()\n", np->full_name);
+ mutex_unlock(&of_aliases_mutex);
+ return rc;
+}
+
+#if defined(CONFIG_OF_DYNAMIC)
+static void of_node_remove(struct device_node *np)
+{
+ struct property *pp;
+
+ BUG_ON(!of_node_is_initialized(np));
+
+ /* only remove properties if on sysfs */
+ if (of_node_is_attached(np)) {
+ for_each_property_of_node(np, pp)
+ sysfs_remove_bin_file(&np->kobj, &pp->attr);
+ kobject_del(&np->kobj);
+ }
+
+ /* finally remove the kobj_init ref */
+ of_node_put(np);
+}
+#endif
+
+static int __init of_init(void)
+{
+ struct device_node *np;
+
+ /* Create the kset, and register existing nodes */
+ mutex_lock(&of_aliases_mutex);
+ of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj);
+ if (!of_kset) {
+ mutex_unlock(&of_aliases_mutex);
+ return -ENOMEM;
+ }
+ for_each_of_allnodes(np)
+ __of_node_add(np);
+ mutex_unlock(&of_aliases_mutex);
+
+ /* Symlink in /proc as required by userspace ABI */
+ if (of_allnodes)
+ proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base");
+
+ return 0;
+}
+core_initcall(of_init);
+
static struct property *__of_find_property(const struct device_node *np,
const char *name, int *lenp)
{
@@ -342,27 +492,72 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
}
EXPORT_SYMBOL(of_get_cpu_node);
-/** Checks if the given "compat" string matches one of the strings in
- * the device's "compatible" property
+/**
+ * __of_device_is_compatible() - Check if the node matches given constraints
+ * @device: pointer to node
+ * @compat: required compatible string, NULL or "" for any match
+ * @type: required device_type value, NULL or "" for any match
+ * @name: required node name, NULL or "" for any match
+ *
+ * Checks if the given @compat, @type and @name strings match the
+ * properties of the given @device. A constraints can be skipped by
+ * passing NULL or an empty string as the constraint.
+ *
+ * Returns 0 for no match, and a positive integer on match. The return
+ * value is a relative score with larger values indicating better
+ * matches. The score is weighted for the most specific compatible value
+ * to get the highest score. Matching type is next, followed by matching
+ * name. Practically speaking, this results in the following priority
+ * order for matches:
+ *
+ * 1. specific compatible && type && name
+ * 2. specific compatible && type
+ * 3. specific compatible && name
+ * 4. specific compatible
+ * 5. general compatible && type && name
+ * 6. general compatible && type
+ * 7. general compatible && name
+ * 8. general compatible
+ * 9. type && name
+ * 10. type
+ * 11. name
*/
static int __of_device_is_compatible(const struct device_node *device,
- const char *compat)
+ const char *compat, const char *type, const char *name)
{
- const char* cp;
- int cplen, l;
+ struct property *prop;
+ const char *cp;
+ int index = 0, score = 0;
+
+ /* Compatible match has highest priority */
+ if (compat && compat[0]) {
+ prop = __of_find_property(device, "compatible", NULL);
+ for (cp = of_prop_next_string(prop, NULL); cp;
+ cp = of_prop_next_string(prop, cp), index++) {
+ if (of_compat_cmp(cp, compat, strlen(compat)) == 0) {
+ score = INT_MAX/2 - (index << 2);
+ break;
+ }
+ }
+ if (!score)
+ return 0;
+ }
- cp = __of_get_property(device, "compatible", &cplen);
- if (cp == NULL)
- return 0;
- while (cplen > 0) {
- if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
- return 1;
- l = strlen(cp) + 1;
- cp += l;
- cplen -= l;
+ /* Matching type is better than matching name */
+ if (type && type[0]) {
+ if (!device->type || of_node_cmp(type, device->type))
+ return 0;
+ score += 2;
}
- return 0;
+ /* Matching name is a bit better than not */
+ if (name && name[0]) {
+ if (!device->name || of_node_cmp(name, device->name))
+ return 0;
+ score++;
+ }
+
+ return score;
}
/** Checks if the given "compat" string matches one of the strings in
@@ -375,7 +570,7 @@ int of_device_is_compatible(const struct device_node *device,
int res;
raw_spin_lock_irqsave(&devtree_lock, flags);
- res = __of_device_is_compatible(device, compat);
+ res = __of_device_is_compatible(device, compat, NULL, NULL);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return res;
}
@@ -681,10 +876,7 @@ struct device_node *of_find_compatible_node(struct device_node *from,
raw_spin_lock_irqsave(&devtree_lock, flags);
np = from ? from->allnext : of_allnodes;
for (; np; np = np->allnext) {
- if (type
- && !(np->type && (of_node_cmp(np->type, type) == 0)))
- continue;
- if (__of_device_is_compatible(np, compatible) &&
+ if (__of_device_is_compatible(np, compatible, type, NULL) &&
of_node_get(np))
break;
}
@@ -734,43 +926,22 @@ static
const struct of_device_id *__of_match_node(const struct of_device_id *matches,
const struct device_node *node)
{
- const char *cp;
- int cplen, l;
+ const struct of_device_id *best_match = NULL;
+ int score, best_score = 0;
if (!matches)
return NULL;
- cp = __of_get_property(node, "compatible", &cplen);
- do {
- const struct of_device_id *m = matches;
-
- /* Check against matches with current compatible string */
- while (m->name[0] || m->type[0] || m->compatible[0]) {
- int match = 1;
- if (m->name[0])
- match &= node->name
- && !strcmp(m->name, node->name);
- if (m->type[0])
- match &= node->type
- && !strcmp(m->type, node->type);
- if (m->compatible[0])
- match &= cp
- && !of_compat_cmp(m->compatible, cp,
- strlen(m->compatible));
- if (match)
- return m;
- m++;
- }
-
- /* Get node's next compatible string */
- if (cp) {
- l = strlen(cp) + 1;
- cp += l;
- cplen -= l;
+ for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) {
+ score = __of_device_is_compatible(node, matches->compatible,
+ matches->type, matches->name);
+ if (score > best_score) {
+ best_match = matches;
+ best_score = score;
}
- } while (cp && (cplen > 0));
+ }
- return NULL;
+ return best_match;
}
/**
@@ -778,10 +949,7 @@ const struct of_device_id *__of_match_node(const struct of_device_id *matches,
* @matches: array of of device match structures to search in
* @node: the of device structure to match against
*
- * Low level utility function used by device matching. Matching order
- * is to compare each of the node's compatibles with all given matches
- * first. This implies node's compatible is sorted from specific to
- * generic while matches can be in any order.
+ * Low level utility function used by device matching.
*/
const struct of_device_id *of_match_node(const struct of_device_id *matches,
const struct device_node *node)
@@ -886,6 +1054,38 @@ struct device_node *of_find_node_by_phandle(phandle handle)
EXPORT_SYMBOL(of_find_node_by_phandle);
/**
+ * of_property_count_elems_of_size - Count the number of elements in a property
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @elem_size: size of the individual element
+ *
+ * Search for a property in a device node and count the number of elements of
+ * size elem_size in it. Returns number of elements on sucess, -EINVAL if the
+ * property does not exist or its length does not match a multiple of elem_size
+ * and -ENODATA if the property does not have a value.
+ */
+int of_property_count_elems_of_size(const struct device_node *np,
+ const char *propname, int elem_size)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+
+ if (prop->length % elem_size != 0) {
+ pr_err("size of %s in node %s is not a multiple of %d\n",
+ propname, np->full_name, elem_size);
+ return -EINVAL;
+ }
+
+ return prop->length / elem_size;
+}
+EXPORT_SYMBOL_GPL(of_property_count_elems_of_size);
+
+/**
* of_find_property_value_of_size
*
* @np: device node from which the property value is to be read.
@@ -1480,6 +1680,10 @@ static int of_property_notify(int action, struct device_node *np,
{
struct of_prop_reconfig pr;
+ /* only call notifiers if the node is attached */
+ if (!of_node_is_attached(np))
+ return 0;
+
pr.dn = np;
pr.prop = prop;
return of_reconfig_notify(action, &pr);
@@ -1493,11 +1697,31 @@ static int of_property_notify(int action, struct device_node *np,
#endif
/**
+ * __of_add_property - Add a property to a node without lock operations
+ */
+static int __of_add_property(struct device_node *np, struct property *prop)
+{
+ struct property **next;
+
+ prop->next = NULL;
+ next = &np->properties;
+ while (*next) {
+ if (strcmp(prop->name, (*next)->name) == 0)
+ /* duplicate ! don't insert it */
+ return -EEXIST;
+
+ next = &(*next)->next;
+ }
+ *next = prop;
+
+ return 0;
+}
+
+/**
* of_add_property - Add a property to a node
*/
int of_add_property(struct device_node *np, struct property *prop)
{
- struct property **next;
unsigned long flags;
int rc;
@@ -1505,27 +1729,16 @@ int of_add_property(struct device_node *np, struct property *prop)
if (rc)
return rc;
- prop->next = NULL;
raw_spin_lock_irqsave(&devtree_lock, flags);
- next = &np->properties;
- while (*next) {
- if (strcmp(prop->name, (*next)->name) == 0) {
- /* duplicate ! don't insert it */
- raw_spin_unlock_irqrestore(&devtree_lock, flags);
- return -1;
- }
- next = &(*next)->next;
- }
- *next = prop;
+ rc = __of_add_property(np, prop);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
+ if (rc)
+ return rc;
-#ifdef CONFIG_PROC_DEVICETREE
- /* try to add to proc as well if it was initialized */
- if (np->pde)
- proc_device_tree_add_prop(np->pde, prop);
-#endif /* CONFIG_PROC_DEVICETREE */
+ if (of_node_is_attached(np))
+ __of_add_property_sysfs(np, prop);
- return 0;
+ return rc;
}
/**
@@ -1565,11 +1778,11 @@ int of_remove_property(struct device_node *np, struct property *prop)
if (!found)
return -ENODEV;
-#ifdef CONFIG_PROC_DEVICETREE
- /* try to remove the proc node as well */
- if (np->pde)
- proc_device_tree_remove_prop(np->pde, prop);
-#endif /* CONFIG_PROC_DEVICETREE */
+ /* at early boot, bail hear and defer setup to of_init() */
+ if (!of_kset)
+ return 0;
+
+ sysfs_remove_bin_file(&np->kobj, &prop->attr);
return 0;
}
@@ -1615,16 +1828,17 @@ int of_update_property(struct device_node *np, struct property *newprop)
next = &(*next)->next;
}
raw_spin_unlock_irqrestore(&devtree_lock, flags);
+ if (rc)
+ return rc;
+
+ /* Update the sysfs attribute */
+ if (oldprop)
+ sysfs_remove_bin_file(&np->kobj, &oldprop->attr);
+ __of_add_property_sysfs(np, newprop);
if (!found)
return -ENODEV;
-#ifdef CONFIG_PROC_DEVICETREE
- /* try to add to proc as well if it was initialized */
- if (np->pde)
- proc_device_tree_update_prop(np->pde, newprop, oldprop);
-#endif /* CONFIG_PROC_DEVICETREE */
-
return 0;
}
@@ -1659,22 +1873,6 @@ int of_reconfig_notify(unsigned long action, void *p)
return notifier_to_errno(rc);
}
-#ifdef CONFIG_PROC_DEVICETREE
-static void of_add_proc_dt_entry(struct device_node *dn)
-{
- struct proc_dir_entry *ent;
-
- ent = proc_mkdir(strrchr(dn->full_name, '/') + 1, dn->parent->pde);
- if (ent)
- proc_device_tree_add_node(dn, ent);
-}
-#else
-static void of_add_proc_dt_entry(struct device_node *dn)
-{
- return;
-}
-#endif
-
/**
* of_attach_node - Plug a device node into the tree and global list.
*/
@@ -1692,24 +1890,13 @@ int of_attach_node(struct device_node *np)
np->allnext = of_allnodes;
np->parent->child = np;
of_allnodes = np;
+ of_node_clear_flag(np, OF_DETACHED);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
- of_add_proc_dt_entry(np);
+ of_node_add(np);
return 0;
}
-#ifdef CONFIG_PROC_DEVICETREE
-static void of_remove_proc_dt_entry(struct device_node *dn)
-{
- proc_remove(dn->pde);
-}
-#else
-static void of_remove_proc_dt_entry(struct device_node *dn)
-{
- return;
-}
-#endif
-
/**
* of_detach_node - "Unplug" a node from the device tree.
*
@@ -1765,7 +1952,7 @@ int of_detach_node(struct device_node *np)
of_node_set_flag(np, OF_DETACHED);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
- of_remove_proc_dt_entry(np);
+ of_node_remove(np);
return rc;
}
#endif /* defined(CONFIG_OF_DYNAMIC) */
@@ -1801,9 +1988,9 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
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);
+ const char *name = of_get_property(of_chosen, "stdout-path", NULL);
+ if (!name)
+ name = of_get_property(of_chosen, "linux,stdout-path", NULL);
if (name)
of_stdout = of_find_node_by_path(name);
}
@@ -1964,3 +2151,154 @@ struct device_node *of_find_next_cache_node(const struct device_node *np)
return NULL;
}
+
+/**
+ * of_graph_parse_endpoint() - parse common endpoint node properties
+ * @node: pointer to endpoint device_node
+ * @endpoint: pointer to the OF endpoint data structure
+ *
+ * The caller should hold a reference to @node.
+ */
+int of_graph_parse_endpoint(const struct device_node *node,
+ struct of_endpoint *endpoint)
+{
+ struct device_node *port_node = of_get_parent(node);
+
+ WARN_ONCE(!port_node, "%s(): endpoint %s has no parent node\n",
+ __func__, node->full_name);
+
+ memset(endpoint, 0, sizeof(*endpoint));
+
+ endpoint->local_node = node;
+ /*
+ * It doesn't matter whether the two calls below succeed.
+ * If they don't then the default value 0 is used.
+ */
+ of_property_read_u32(port_node, "reg", &endpoint->port);
+ of_property_read_u32(node, "reg", &endpoint->id);
+
+ of_node_put(port_node);
+
+ return 0;
+}
+EXPORT_SYMBOL(of_graph_parse_endpoint);
+
+/**
+ * of_graph_get_next_endpoint() - get next endpoint node
+ * @parent: pointer to the parent device node
+ * @prev: previous endpoint node, or NULL to get first
+ *
+ * Return: An 'endpoint' node pointer with refcount incremented. Refcount
+ * of the passed @prev node is not decremented, the caller have to use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
+ struct device_node *prev)
+{
+ struct device_node *endpoint;
+ struct device_node *port;
+
+ if (!parent)
+ return NULL;
+
+ /*
+ * Start by locating the port node. If no previous endpoint is specified
+ * search for the first port node, otherwise get the previous endpoint
+ * parent port node.
+ */
+ if (!prev) {
+ struct device_node *node;
+
+ node = of_get_child_by_name(parent, "ports");
+ if (node)
+ parent = node;
+
+ port = of_get_child_by_name(parent, "port");
+ of_node_put(node);
+
+ if (!port) {
+ pr_err("%s(): no port node found in %s\n",
+ __func__, parent->full_name);
+ return NULL;
+ }
+ } else {
+ port = of_get_parent(prev);
+ if (WARN_ONCE(!port, "%s(): endpoint %s has no parent node\n",
+ __func__, prev->full_name))
+ return NULL;
+
+ /*
+ * Avoid dropping prev node refcount to 0 when getting the next
+ * child below.
+ */
+ of_node_get(prev);
+ }
+
+ while (1) {
+ /*
+ * Now that we have a port node, get the next endpoint by
+ * getting the next child. If the previous endpoint is NULL this
+ * will return the first child.
+ */
+ endpoint = of_get_next_child(port, prev);
+ if (endpoint) {
+ of_node_put(port);
+ return endpoint;
+ }
+
+ /* No more endpoints under this port, try the next one. */
+ prev = NULL;
+
+ do {
+ port = of_get_next_child(parent, port);
+ if (!port)
+ return NULL;
+ } while (of_node_cmp(port->name, "port"));
+ }
+}
+EXPORT_SYMBOL(of_graph_get_next_endpoint);
+
+/**
+ * of_graph_get_remote_port_parent() - get remote port's parent node
+ * @node: pointer to a local endpoint device_node
+ *
+ * Return: Remote device node associated with remote endpoint node linked
+ * to @node. Use of_node_put() on it when done.
+ */
+struct device_node *of_graph_get_remote_port_parent(
+ const struct device_node *node)
+{
+ struct device_node *np;
+ unsigned int depth;
+
+ /* Get remote endpoint node. */
+ np = of_parse_phandle(node, "remote-endpoint", 0);
+
+ /* Walk 3 levels up only if there is 'ports' node. */
+ for (depth = 3; depth && np; depth--) {
+ np = of_get_next_parent(np);
+ if (depth == 2 && of_node_cmp(np->name, "ports"))
+ break;
+ }
+ return np;
+}
+EXPORT_SYMBOL(of_graph_get_remote_port_parent);
+
+/**
+ * of_graph_get_remote_port() - get remote port node
+ * @node: pointer to a local endpoint device_node
+ *
+ * Return: Remote port node associated with remote endpoint node linked
+ * to @node. Use of_node_put() on it when done.
+ */
+struct device_node *of_graph_get_remote_port(const struct device_node *node)
+{
+ struct device_node *np;
+
+ /* Get remote endpoint node. */
+ np = of_parse_phandle(node, "remote-endpoint", 0);
+ if (!np)
+ return NULL;
+ return of_get_next_parent(np);
+}
+EXPORT_SYMBOL(of_graph_get_remote_port);
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 758b4f8b30b7..fa16a912a927 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -15,6 +15,8 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/sizes.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/slab.h>
@@ -202,6 +204,7 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
__alignof__(struct device_node));
if (allnextpp) {
char *fn;
+ of_node_init(np);
np->full_name = fn = ((char *)np) + sizeof(*np);
if (new_format) {
/* rebuild full path for new format */
@@ -232,7 +235,6 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
dad->next->sibling = np;
dad->next = np;
}
- kref_init(&np->kref);
}
/* process properties */
while (1) {
@@ -440,6 +442,129 @@ struct boot_param_header *initial_boot_params;
#ifdef CONFIG_OF_EARLY_FLATTREE
/**
+ * res_mem_reserve_reg() - reserve all memory described in 'reg' property
+ */
+static int __init __reserved_mem_reserve_reg(unsigned long node,
+ const char *uname)
+{
+ int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
+ phys_addr_t base, size;
+ unsigned long len;
+ __be32 *prop;
+ int nomap, first = 1;
+
+ prop = of_get_flat_dt_prop(node, "reg", &len);
+ if (!prop)
+ return -ENOENT;
+
+ if (len && len % t_len != 0) {
+ pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n",
+ uname);
+ return -EINVAL;
+ }
+
+ nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
+
+ while (len >= t_len) {
+ base = dt_mem_next_cell(dt_root_addr_cells, &prop);
+ size = dt_mem_next_cell(dt_root_size_cells, &prop);
+
+ if (base && size &&
+ early_init_dt_reserve_memory_arch(base, size, nomap) == 0)
+ pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n",
+ uname, &base, (unsigned long)size / SZ_1M);
+ else
+ pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %ld MiB\n",
+ uname, &base, (unsigned long)size / SZ_1M);
+
+ len -= t_len;
+ if (first) {
+ fdt_reserved_mem_save_node(node, uname, base, size);
+ first = 0;
+ }
+ }
+ return 0;
+}
+
+/**
+ * __reserved_mem_check_root() - check if #size-cells, #address-cells provided
+ * in /reserved-memory matches the values supported by the current implementation,
+ * also check if ranges property has been provided
+ */
+static int __reserved_mem_check_root(unsigned long node)
+{
+ __be32 *prop;
+
+ prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
+ if (!prop || be32_to_cpup(prop) != dt_root_size_cells)
+ return -EINVAL;
+
+ prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
+ if (!prop || be32_to_cpup(prop) != dt_root_addr_cells)
+ return -EINVAL;
+
+ prop = of_get_flat_dt_prop(node, "ranges", NULL);
+ if (!prop)
+ return -EINVAL;
+ return 0;
+}
+
+/**
+ * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory
+ */
+static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ static int found;
+ const char *status;
+ int err;
+
+ if (!found && depth == 1 && strcmp(uname, "reserved-memory") == 0) {
+ if (__reserved_mem_check_root(node) != 0) {
+ pr_err("Reserved memory: unsupported node format, ignoring\n");
+ /* break scan */
+ return 1;
+ }
+ found = 1;
+ /* scan next node */
+ return 0;
+ } else if (!found) {
+ /* scan next node */
+ return 0;
+ } else if (found && depth < 2) {
+ /* scanning of /reserved-memory has been finished */
+ return 1;
+ }
+
+ status = of_get_flat_dt_prop(node, "status", NULL);
+ if (status && strcmp(status, "okay") != 0 && strcmp(status, "ok") != 0)
+ return 0;
+
+ err = __reserved_mem_reserve_reg(node, uname);
+ if (err == -ENOENT && of_get_flat_dt_prop(node, "size", NULL))
+ fdt_reserved_mem_save_node(node, uname, 0, 0);
+
+ /* scan next node */
+ return 0;
+}
+
+/**
+ * early_init_fdt_scan_reserved_mem() - create reserved memory regions
+ *
+ * This function grabs memory from early allocator for device exclusive use
+ * defined in device tree structures. It should be called by arch specific code
+ * once the early allocator (i.e. memblock) has been fully activated.
+ */
+void __init early_init_fdt_scan_reserved_mem(void)
+{
+ if (!initial_boot_params)
+ return;
+
+ of_scan_flat_dt(__fdt_scan_reserved_mem, NULL);
+ fdt_init_reserved_mem();
+}
+
+/**
* of_scan_flat_dt - scan flattened tree blob and call callback on each.
* @it: callback function
* @data: context data pointer
@@ -856,6 +981,16 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
memblock_add(base, size);
}
+int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
+ phys_addr_t size, bool nomap)
+{
+ if (memblock_is_region_reserved(base, size))
+ return -EBUSY;
+ if (nomap)
+ return memblock_remove(base, size);
+ return memblock_reserve(base, size);
+}
+
/*
* called from unflatten_device_tree() to bootstrap devicetree itself
* Architectures can override this definition if memblock isn't used
@@ -864,6 +999,14 @@ void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align)
{
return __va(memblock_alloc(size, align));
}
+#else
+int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
+ phys_addr_t size, bool nomap)
+{
+ pr_err("Reserved memory not supported, ignoring range 0x%llx - 0x%llx%s\n",
+ base, size, nomap ? " (nomap)" : "");
+ return -ENOSYS;
+}
#endif
bool __init early_init_dt_scan(void *params)
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index 875b7b6f0d2a..9a95831bd065 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -24,7 +24,11 @@ MODULE_LICENSE("GPL");
static void of_set_phy_supported(struct phy_device *phydev, u32 max_speed)
{
- phydev->supported |= PHY_DEFAULT_FEATURES;
+ /* The default values for phydev->supported are provided by the PHY
+ * driver "features" member, we want to reset to sane defaults fist
+ * before supporting higher speeds.
+ */
+ phydev->supported &= PHY_DEFAULT_FEATURES;
switch (max_speed) {
default:
@@ -39,27 +43,50 @@ static void of_set_phy_supported(struct phy_device *phydev, u32 max_speed)
}
}
+/* Extract the clause 22 phy ID from the compatible string of the form
+ * ethernet-phy-idAAAA.BBBB */
+static int of_get_phy_id(struct device_node *device, u32 *phy_id)
+{
+ struct property *prop;
+ const char *cp;
+ unsigned int upper, lower;
+
+ of_property_for_each_string(device, "compatible", prop, cp) {
+ if (sscanf(cp, "ethernet-phy-id%4x.%4x", &upper, &lower) == 2) {
+ *phy_id = ((upper & 0xFFFF) << 16) | (lower & 0xFFFF);
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *child,
u32 addr)
{
struct phy_device *phy;
bool is_c45;
- int rc, prev_irq;
+ int rc;
u32 max_speed = 0;
+ u32 phy_id;
is_c45 = of_device_is_compatible(child,
"ethernet-phy-ieee802.3-c45");
- phy = get_phy_device(mdio, addr, is_c45);
+ if (!is_c45 && !of_get_phy_id(child, &phy_id))
+ phy = phy_device_create(mdio, addr, phy_id, 0, NULL);
+ else
+ phy = get_phy_device(mdio, addr, is_c45);
if (!phy || IS_ERR(phy))
return 1;
- if (mdio->irq) {
- prev_irq = mdio->irq[addr];
- mdio->irq[addr] =
- irq_of_parse_and_map(child, 0);
- if (!mdio->irq[addr])
- mdio->irq[addr] = prev_irq;
+ rc = irq_of_parse_and_map(child, 0);
+ if (rc > 0) {
+ phy->irq = rc;
+ if (mdio->irq)
+ mdio->irq[addr] = rc;
+ } else {
+ if (mdio->irq)
+ phy->irq = mdio->irq[addr];
}
/* Associate the OF node with the device structure so it
diff --git a/drivers/of/of_net.c b/drivers/of/of_net.c
index a208a457558c..73e14184aafe 100644
--- a/drivers/of/of_net.c
+++ b/drivers/of/of_net.c
@@ -12,33 +12,12 @@
#include <linux/export.h>
/**
- * It maps 'enum phy_interface_t' found in include/linux/phy.h
- * into the device tree binding of 'phy-mode', so that Ethernet
- * device driver can get phy interface from device tree.
- */
-static const char *phy_modes[] = {
- [PHY_INTERFACE_MODE_NA] = "",
- [PHY_INTERFACE_MODE_MII] = "mii",
- [PHY_INTERFACE_MODE_GMII] = "gmii",
- [PHY_INTERFACE_MODE_SGMII] = "sgmii",
- [PHY_INTERFACE_MODE_TBI] = "tbi",
- [PHY_INTERFACE_MODE_REVMII] = "rev-mii",
- [PHY_INTERFACE_MODE_RMII] = "rmii",
- [PHY_INTERFACE_MODE_RGMII] = "rgmii",
- [PHY_INTERFACE_MODE_RGMII_ID] = "rgmii-id",
- [PHY_INTERFACE_MODE_RGMII_RXID] = "rgmii-rxid",
- [PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid",
- [PHY_INTERFACE_MODE_RTBI] = "rtbi",
- [PHY_INTERFACE_MODE_SMII] = "smii",
- [PHY_INTERFACE_MODE_XGMII] = "xgmii",
-};
-
-/**
* of_get_phy_mode - Get phy mode for given device_node
* @np: Pointer to the given device_node
*
- * The function gets phy interface string from property 'phy-mode',
- * and return its index in phy_modes table, or errno in error case.
+ * The function gets phy interface string from property 'phy-mode' or
+ * 'phy-connection-type', and return its index in phy_modes table, or errno in
+ * error case.
*/
int of_get_phy_mode(struct device_node *np)
{
@@ -47,10 +26,12 @@ int of_get_phy_mode(struct device_node *np)
err = of_property_read_string(np, "phy-mode", &pm);
if (err < 0)
+ err = of_property_read_string(np, "phy-connection-type", &pm);
+ if (err < 0)
return err;
- for (i = 0; i < ARRAY_SIZE(phy_modes); i++)
- if (!strcasecmp(pm, phy_modes[i]))
+ for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
+ if (!strcasecmp(pm, phy_modes(i)))
return i;
return -ENODEV;
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
new file mode 100644
index 000000000000..daaaf935911d
--- /dev/null
+++ b/drivers/of/of_reserved_mem.c
@@ -0,0 +1,217 @@
+/*
+ * Device tree based initialization code for reserved memory.
+ *
+ * Copyright (c) 2013, The Linux Foundation. All Rights Reserved.
+ * Copyright (c) 2013,2014 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ * Author: Marek Szyprowski <m.szyprowski@samsung.com>
+ * Author: Josh Cartwright <joshc@codeaurora.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 optional) any later version of the license.
+ */
+
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
+#include <linux/mm.h>
+#include <linux/sizes.h>
+#include <linux/of_reserved_mem.h>
+
+#define MAX_RESERVED_REGIONS 16
+static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
+static int reserved_mem_count;
+
+#if defined(CONFIG_HAVE_MEMBLOCK)
+#include <linux/memblock.h>
+int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
+ phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
+ phys_addr_t *res_base)
+{
+ /*
+ * We use __memblock_alloc_base() because memblock_alloc_base()
+ * panic()s on allocation failure.
+ */
+ phys_addr_t base = __memblock_alloc_base(size, align, end);
+ if (!base)
+ return -ENOMEM;
+
+ /*
+ * Check if the allocated region fits in to start..end window
+ */
+ if (base < start) {
+ memblock_free(base, size);
+ return -ENOMEM;
+ }
+
+ *res_base = base;
+ if (nomap)
+ return memblock_remove(base, size);
+ return 0;
+}
+#else
+int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
+ phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
+ phys_addr_t *res_base)
+{
+ pr_err("Reserved memory not supported, ignoring region 0x%llx%s\n",
+ size, nomap ? " (nomap)" : "");
+ return -ENOSYS;
+}
+#endif
+
+/**
+ * res_mem_save_node() - save fdt node for second pass initialization
+ */
+void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname,
+ phys_addr_t base, phys_addr_t size)
+{
+ struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];
+
+ if (reserved_mem_count == ARRAY_SIZE(reserved_mem)) {
+ pr_err("Reserved memory: not enough space all defined regions.\n");
+ return;
+ }
+
+ rmem->fdt_node = node;
+ rmem->name = uname;
+ rmem->base = base;
+ rmem->size = size;
+
+ reserved_mem_count++;
+ return;
+}
+
+/**
+ * res_mem_alloc_size() - allocate reserved memory described by 'size', 'align'
+ * and 'alloc-ranges' properties
+ */
+static int __init __reserved_mem_alloc_size(unsigned long node,
+ const char *uname, phys_addr_t *res_base, phys_addr_t *res_size)
+{
+ int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
+ phys_addr_t start = 0, end = 0;
+ phys_addr_t base = 0, align = 0, size;
+ unsigned long len;
+ __be32 *prop;
+ int nomap;
+ int ret;
+
+ prop = of_get_flat_dt_prop(node, "size", &len);
+ if (!prop)
+ return -EINVAL;
+
+ if (len != dt_root_size_cells * sizeof(__be32)) {
+ pr_err("Reserved memory: invalid size property in '%s' node.\n",
+ uname);
+ return -EINVAL;
+ }
+ size = dt_mem_next_cell(dt_root_size_cells, &prop);
+
+ nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
+
+ prop = of_get_flat_dt_prop(node, "alignment", &len);
+ if (prop) {
+ if (len != dt_root_addr_cells * sizeof(__be32)) {
+ pr_err("Reserved memory: invalid alignment property in '%s' node.\n",
+ uname);
+ return -EINVAL;
+ }
+ align = dt_mem_next_cell(dt_root_addr_cells, &prop);
+ }
+
+ prop = of_get_flat_dt_prop(node, "alloc-ranges", &len);
+ if (prop) {
+
+ if (len % t_len != 0) {
+ pr_err("Reserved memory: invalid alloc-ranges property in '%s', skipping node.\n",
+ uname);
+ return -EINVAL;
+ }
+
+ base = 0;
+
+ while (len > 0) {
+ start = dt_mem_next_cell(dt_root_addr_cells, &prop);
+ end = start + dt_mem_next_cell(dt_root_size_cells,
+ &prop);
+
+ ret = early_init_dt_alloc_reserved_memory_arch(size,
+ align, start, end, nomap, &base);
+ if (ret == 0) {
+ pr_debug("Reserved memory: allocated memory for '%s' node: base %pa, size %ld MiB\n",
+ uname, &base,
+ (unsigned long)size / SZ_1M);
+ break;
+ }
+ len -= t_len;
+ }
+
+ } else {
+ ret = early_init_dt_alloc_reserved_memory_arch(size, align,
+ 0, 0, nomap, &base);
+ if (ret == 0)
+ pr_debug("Reserved memory: allocated memory for '%s' node: base %pa, size %ld MiB\n",
+ uname, &base, (unsigned long)size / SZ_1M);
+ }
+
+ if (base == 0) {
+ pr_info("Reserved memory: failed to allocate memory for node '%s'\n",
+ uname);
+ return -ENOMEM;
+ }
+
+ *res_base = base;
+ *res_size = size;
+
+ return 0;
+}
+
+static const struct of_device_id __rmem_of_table_sentinel
+ __used __section(__reservedmem_of_table_end);
+
+/**
+ * res_mem_init_node() - call region specific reserved memory init code
+ */
+static int __init __reserved_mem_init_node(struct reserved_mem *rmem)
+{
+ extern const struct of_device_id __reservedmem_of_table[];
+ const struct of_device_id *i;
+
+ for (i = __reservedmem_of_table; i < &__rmem_of_table_sentinel; i++) {
+ reservedmem_of_init_fn initfn = i->data;
+ const char *compat = i->compatible;
+
+ if (!of_flat_dt_is_compatible(rmem->fdt_node, compat))
+ continue;
+
+ if (initfn(rmem, rmem->fdt_node, rmem->name) == 0) {
+ pr_info("Reserved memory: initialized node %s, compatible id %s\n",
+ rmem->name, compat);
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+/**
+ * fdt_init_reserved_mem - allocate and init all saved reserved memory regions
+ */
+void __init fdt_init_reserved_mem(void)
+{
+ int i;
+ for (i = 0; i < reserved_mem_count; i++) {
+ struct reserved_mem *rmem = &reserved_mem[i];
+ unsigned long node = rmem->fdt_node;
+ int err = 0;
+
+ if (rmem->size == 0)
+ err = __reserved_mem_alloc_size(node, rmem->name,
+ &rmem->base, &rmem->size);
+ if (err == 0)
+ __reserved_mem_init_node(rmem);
+ }
+}
diff --git a/drivers/of/pdt.c b/drivers/of/pdt.c
index 7b666736c168..36b4035881b0 100644
--- a/drivers/of/pdt.c
+++ b/drivers/of/pdt.c
@@ -176,11 +176,10 @@ static struct device_node * __init of_pdt_create_node(phandle node,
return NULL;
dp = prom_early_alloc(sizeof(*dp));
+ of_node_init(dp);
of_pdt_incr_unique_id(dp);
dp->parent = parent;
- kref_init(&dp->kref);
-
dp->name = of_pdt_get_one_property(node, "name");
dp->type = of_pdt_get_one_property(node, "device_type");
dp->phandle = node;
diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c
index e21012bde639..ae4450070503 100644
--- a/drivers/of/selftest.c
+++ b/drivers/of/selftest.c
@@ -30,6 +30,67 @@ static struct selftest_results {
} \
}
+static void __init of_selftest_dynamic(void)
+{
+ struct device_node *np;
+ struct property *prop;
+
+ np = of_find_node_by_path("/testcase-data");
+ if (!np) {
+ pr_err("missing testcase data\n");
+ return;
+ }
+
+ /* Array of 4 properties for the purpose of testing */
+ prop = kzalloc(sizeof(*prop) * 4, GFP_KERNEL);
+ if (!prop) {
+ selftest(0, "kzalloc() failed\n");
+ return;
+ }
+
+ /* Add a new property - should pass*/
+ prop->name = "new-property";
+ prop->value = "new-property-data";
+ prop->length = strlen(prop->value);
+ selftest(of_add_property(np, prop) == 0, "Adding a new property failed\n");
+
+ /* Try to add an existing property - should fail */
+ prop++;
+ prop->name = "new-property";
+ prop->value = "new-property-data-should-fail";
+ prop->length = strlen(prop->value);
+ selftest(of_add_property(np, prop) != 0,
+ "Adding an existing property should have failed\n");
+
+ /* Try to modify an existing property - should pass */
+ prop->value = "modify-property-data-should-pass";
+ prop->length = strlen(prop->value);
+ selftest(of_update_property(np, prop) == 0,
+ "Updating an existing property should have passed\n");
+
+ /* Try to modify non-existent property - should pass*/
+ prop++;
+ prop->name = "modify-property";
+ prop->value = "modify-missing-property-data-should-pass";
+ prop->length = strlen(prop->value);
+ selftest(of_update_property(np, prop) == 0,
+ "Updating a missing property should have passed\n");
+
+ /* Remove property - should pass */
+ selftest(of_remove_property(np, prop) == 0,
+ "Removing a property should have passed\n");
+
+ /* Adding very large property - should pass */
+ prop++;
+ prop->name = "large-property-PAGE_SIZEx8";
+ prop->length = PAGE_SIZE * 8;
+ prop->value = kzalloc(prop->length, GFP_KERNEL);
+ selftest(prop->value != NULL, "Unable to allocate large buffer\n");
+ if (prop->value)
+ selftest(of_add_property(np, prop) == 0,
+ "Adding a large property should have passed\n");
+}
+
static void __init of_selftest_parse_phandle_with_args(void)
{
struct device_node *np;
@@ -300,6 +361,72 @@ static void __init of_selftest_parse_interrupts_extended(void)
of_node_put(np);
}
+static struct of_device_id match_node_table[] = {
+ { .data = "A", .name = "name0", }, /* Name alone is lowest priority */
+ { .data = "B", .type = "type1", }, /* followed by type alone */
+
+ { .data = "Ca", .name = "name2", .type = "type1", }, /* followed by both together */
+ { .data = "Cb", .name = "name2", }, /* Only match when type doesn't match */
+ { .data = "Cc", .name = "name2", .type = "type2", },
+
+ { .data = "E", .compatible = "compat3" },
+ { .data = "G", .compatible = "compat2", },
+ { .data = "H", .compatible = "compat2", .name = "name5", },
+ { .data = "I", .compatible = "compat2", .type = "type1", },
+ { .data = "J", .compatible = "compat2", .type = "type1", .name = "name8", },
+ { .data = "K", .compatible = "compat2", .name = "name9", },
+ {}
+};
+
+static struct {
+ const char *path;
+ const char *data;
+} match_node_tests[] = {
+ { .path = "/testcase-data/match-node/name0", .data = "A", },
+ { .path = "/testcase-data/match-node/name1", .data = "B", },
+ { .path = "/testcase-data/match-node/a/name2", .data = "Ca", },
+ { .path = "/testcase-data/match-node/b/name2", .data = "Cb", },
+ { .path = "/testcase-data/match-node/c/name2", .data = "Cc", },
+ { .path = "/testcase-data/match-node/name3", .data = "E", },
+ { .path = "/testcase-data/match-node/name4", .data = "G", },
+ { .path = "/testcase-data/match-node/name5", .data = "H", },
+ { .path = "/testcase-data/match-node/name6", .data = "G", },
+ { .path = "/testcase-data/match-node/name7", .data = "I", },
+ { .path = "/testcase-data/match-node/name8", .data = "J", },
+ { .path = "/testcase-data/match-node/name9", .data = "K", },
+};
+
+static void __init of_selftest_match_node(void)
+{
+ struct device_node *np;
+ const struct of_device_id *match;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(match_node_tests); i++) {
+ np = of_find_node_by_path(match_node_tests[i].path);
+ if (!np) {
+ selftest(0, "missing testcase node %s\n",
+ match_node_tests[i].path);
+ continue;
+ }
+
+ match = of_match_node(match_node_table, np);
+ if (!match) {
+ selftest(0, "%s didn't match anything\n",
+ match_node_tests[i].path);
+ continue;
+ }
+
+ if (strcmp(match->data, match_node_tests[i].data) != 0) {
+ selftest(0, "%s got wrong match. expected %s, got %s\n",
+ match_node_tests[i].path, match_node_tests[i].data,
+ (const char *)match->data);
+ continue;
+ }
+ selftest(1, "passed");
+ }
+}
+
static int __init of_selftest(void)
{
struct device_node *np;
@@ -312,10 +439,12 @@ static int __init of_selftest(void)
of_node_put(np);
pr_info("start of selftest - you will see error messages\n");
+ of_selftest_dynamic();
of_selftest_parse_phandle_with_args();
of_selftest_property_match_string();
of_selftest_parse_interrupts();
of_selftest_parse_interrupts_extended();
+ of_selftest_match_node();
pr_info("end of selftest - %i passed, %i failed\n",
selftest_results.passed, selftest_results.failed);
return 0;
diff --git a/drivers/of/testcase-data/testcases.dtsi b/drivers/of/testcase-data/testcases.dtsi
new file mode 100644
index 000000000000..3a5b75a8e4d7
--- /dev/null
+++ b/drivers/of/testcase-data/testcases.dtsi
@@ -0,0 +1,3 @@
+#include "tests-phandle.dtsi"
+#include "tests-interrupts.dtsi"
+#include "tests-match.dtsi"
diff --git a/arch/arm/boot/dts/testcases/tests-interrupts.dtsi b/drivers/of/testcase-data/tests-interrupts.dtsi
index c843720bd3e5..c843720bd3e5 100644
--- a/arch/arm/boot/dts/testcases/tests-interrupts.dtsi
+++ b/drivers/of/testcase-data/tests-interrupts.dtsi
diff --git a/drivers/of/testcase-data/tests-match.dtsi b/drivers/of/testcase-data/tests-match.dtsi
new file mode 100644
index 000000000000..c9e541129534
--- /dev/null
+++ b/drivers/of/testcase-data/tests-match.dtsi
@@ -0,0 +1,19 @@
+
+/ {
+ testcase-data {
+ match-node {
+ name0 { };
+ name1 { device_type = "type1"; };
+ a { name2 { device_type = "type1"; }; };
+ b { name2 { }; };
+ c { name2 { device_type = "type2"; }; };
+ name3 { compatible = "compat3"; };
+ name4 { compatible = "compat2", "compat3"; };
+ name5 { compatible = "compat2", "compat3"; };
+ name6 { compatible = "compat1", "compat2", "compat3"; };
+ name7 { compatible = "compat2"; device_type = "type1"; };
+ name8 { compatible = "compat2"; device_type = "type1"; };
+ name9 { compatible = "compat2"; };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/testcases/tests-phandle.dtsi b/drivers/of/testcase-data/tests-phandle.dtsi
index 0007d3cd7dc2..788a4c24b8f5 100644
--- a/arch/arm/boot/dts/testcases/tests-phandle.dtsi
+++ b/drivers/of/testcase-data/tests-phandle.dtsi
@@ -1,6 +1,9 @@
/ {
testcase-data {
+ security-password = "password";
+ duplicate-name = "duplicate";
+ duplicate-name { };
phandle-tests {
provider0: provider0 {
#phandle-cells = <0>;
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index 6a83ee1e9178..3fa66244ce32 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -905,7 +905,8 @@ int parport_claim_or_block(struct pardevice *dev)
/* If dev->waiting is clear now, an interrupt
gave us the port and we would deadlock if we slept. */
if (dev->waiting) {
- interruptible_sleep_on (&dev->wait_q);
+ wait_event_interruptible(dev->wait_q,
+ !dev->waiting);
if (signal_pending (current)) {
return -EINTR;
}
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 17d2b07ee67c..e04fe2d9df3b 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -33,21 +33,14 @@ obj-$(CONFIG_PCI_IOV) += iov.o
#
# Some architectures use the generic PCI setup functions
#
-obj-$(CONFIG_X86) += setup-bus.o
-obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o
-obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o
-obj-$(CONFIG_UNICORE32) += setup-bus.o setup-irq.o
-obj-$(CONFIG_PARISC) += setup-bus.o
-obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o
-obj-$(CONFIG_PPC) += setup-bus.o
-obj-$(CONFIG_FRV) += setup-bus.o
-obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
-obj-$(CONFIG_X86_VISWS) += setup-irq.o
-obj-$(CONFIG_MN10300) += setup-bus.o
-obj-$(CONFIG_MICROBLAZE) += setup-bus.o
-obj-$(CONFIG_TILE) += setup-bus.o setup-irq.o
-obj-$(CONFIG_SPARC_LEON) += setup-bus.o setup-irq.o
-obj-$(CONFIG_M68K) += setup-bus.o setup-irq.o
+obj-$(CONFIG_ALPHA) += setup-irq.o
+obj-$(CONFIG_ARM) += setup-irq.o
+obj-$(CONFIG_UNICORE32) += setup-irq.o
+obj-$(CONFIG_SUPERH) += setup-irq.o
+obj-$(CONFIG_MIPS) += setup-irq.o
+obj-$(CONFIG_TILE) += setup-irq.o
+obj-$(CONFIG_SPARC_LEON) += setup-irq.o
+obj-$(CONFIG_M68K) += setup-irq.o
#
# ACPI Related PCI FW Functions
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 00660cc502c5..fb8aed307c28 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -132,7 +132,7 @@ static void pci_clip_resource_to_region(struct pci_bus *bus,
static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res,
resource_size_t size, resource_size_t align,
- resource_size_t min, unsigned int type_mask,
+ resource_size_t min, unsigned long type_mask,
resource_size_t (*alignf)(void *,
const struct resource *,
resource_size_t,
@@ -144,7 +144,7 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res,
struct resource *r, avail;
resource_size_t max;
- type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
+ type_mask |= IORESOURCE_TYPE_BITS;
pci_bus_for_each_resource(bus, r, i) {
if (!r)
@@ -162,8 +162,6 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res,
avail = *r;
pci_clip_resource_to_region(bus, &avail, region);
- if (!resource_size(&avail))
- continue;
/*
* "min" is typically PCIBIOS_MIN_IO or PCIBIOS_MIN_MEM to
@@ -202,7 +200,7 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res,
*/
int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
resource_size_t size, resource_size_t align,
- resource_size_t min, unsigned int type_mask,
+ resource_size_t min, unsigned long type_mask,
resource_size_t (*alignf)(void *,
const struct resource *,
resource_size_t,
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
index 06ace6248c61..47aaf22d814e 100644
--- a/drivers/pci/host-bridge.c
+++ b/drivers/pci/host-bridge.c
@@ -32,11 +32,6 @@ void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
bridge->release_data = release_data;
}
-static bool resource_contains(struct resource *res1, struct resource *res2)
-{
- return res1->start <= res2->start && res1->end >= res2->end;
-}
-
void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region,
struct resource *res)
{
@@ -45,9 +40,6 @@ void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region,
resource_size_t offset = 0;
list_for_each_entry(window, &bridge->windows, list) {
- if (resource_type(res) != resource_type(window->res))
- continue;
-
if (resource_contains(window->res, res)) {
offset = window->offset;
break;
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 47d46c6d8468..a6f67ec8882f 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -27,7 +27,7 @@ config PCI_TEGRA
config PCI_RCAR_GEN2
bool "Renesas R-Car Gen2 Internal PCI controller"
- depends on ARM && (ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST)
+ depends on ARCH_SHMOBILE || (ARM && COMPILE_TEST)
help
Say Y here if you want internal PCI support on R-Car Gen2 SoC.
There are 3 internal PCI controllers available with a single
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
index e8663a8c3406..ee082509b0ba 100644
--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/host/pci-imx6.c
@@ -424,20 +424,40 @@ static void imx6_pcie_reset_phy(struct pcie_port *pp)
static int imx6_pcie_link_up(struct pcie_port *pp)
{
- u32 rc, ltssm, rx_valid;
+ u32 rc, debug_r0, rx_valid;
+ int count = 5;
/*
- * Test if the PHY reports that the link is up and also that
- * the link training finished. It might happen that the PHY
- * reports the link is already up, but the link training bit
- * is still set, so make sure to check the training is done
- * as well here.
+ * Test if the PHY reports that the link is up and also that the LTSSM
+ * training finished. There are three possible states of the link when
+ * this code is called:
+ * 1) The link is DOWN (unlikely)
+ * The link didn't come up yet for some reason. This usually means
+ * we have a real problem somewhere. Reset the PHY and exit. This
+ * state calls for inspection of the DEBUG registers.
+ * 2) The link is UP, but still in LTSSM training
+ * Wait for the training to finish, which should take a very short
+ * time. If the training does not finish, we have a problem and we
+ * need to inspect the DEBUG registers. If the training does finish,
+ * the link is up and operating correctly.
+ * 3) The link is UP and no longer in LTSSM training
+ * The link is up and operating correctly.
*/
- rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1);
- if ((rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP) &&
- !(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING))
- return 1;
-
+ while (1) {
+ rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1);
+ if (!(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP))
+ break;
+ if (!(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING))
+ return 1;
+ if (!count--)
+ break;
+ dev_dbg(pp->dev, "Link is up, but still in training\n");
+ /*
+ * Wait a little bit, then re-check if the link finished
+ * the training.
+ */
+ usleep_range(1000, 2000);
+ }
/*
* From L0, initiate MAC entry to gen2 if EP/RC supports gen2.
* Wait 2ms (LTSSM timeout is 24ms, PHY lock is ~5us in gen2).
@@ -446,15 +466,16 @@ static int imx6_pcie_link_up(struct pcie_port *pp)
* to gen2 is stuck
*/
pcie_phy_read(pp->dbi_base, PCIE_PHY_RX_ASIC_OUT, &rx_valid);
- ltssm = readl(pp->dbi_base + PCIE_PHY_DEBUG_R0) & 0x3F;
+ debug_r0 = readl(pp->dbi_base + PCIE_PHY_DEBUG_R0);
if (rx_valid & 0x01)
return 0;
- if (ltssm != 0x0d)
+ if ((debug_r0 & 0x3f) != 0x0d)
return 0;
dev_err(pp->dev, "transition to gen2 is stuck, reset PHY!\n");
+ dev_dbg(pp->dev, "debug_r0=%08x debug_r1=%08x\n", debug_r0, rc);
imx6_pcie_reset_phy(pp);
diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c
index 13478ecd4113..d3d1cfd51e09 100644
--- a/drivers/pci/host/pci-mvebu.c
+++ b/drivers/pci/host/pci-mvebu.c
@@ -60,14 +60,6 @@
#define PCIE_DEBUG_CTRL 0x1a60
#define PCIE_DEBUG_SOFT_RESET BIT(20)
-/*
- * This product ID is registered by Marvell, and used when the Marvell
- * SoC is not the root complex, but an endpoint on the PCIe bus. It is
- * therefore safe to re-use this PCI ID for our emulated PCI-to-PCI
- * bridge.
- */
-#define MARVELL_EMULATED_PCI_PCI_BRIDGE_ID 0x7846
-
/* PCI configuration space of a PCI-to-PCI bridge */
struct mvebu_sw_pci_bridge {
u16 vendor;
@@ -109,7 +101,9 @@ struct mvebu_pcie {
struct mvebu_pcie_port *ports;
struct msi_chip *msi;
struct resource io;
+ char io_name[30];
struct resource realio;
+ char mem_name[30];
struct resource mem;
struct resource busn;
int nports;
@@ -388,7 +382,8 @@ static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port)
bridge->class = PCI_CLASS_BRIDGE_PCI;
bridge->vendor = PCI_VENDOR_ID_MARVELL;
- bridge->device = MARVELL_EMULATED_PCI_PCI_BRIDGE_ID;
+ bridge->device = mvebu_readl(port, PCIE_DEV_ID_OFF) >> 16;
+ bridge->revision = mvebu_readl(port, PCIE_DEV_REV_OFF) & 0xff;
bridge->header_type = PCI_HEADER_TYPE_BRIDGE;
bridge->cache_line_size = 0x10;
@@ -679,10 +674,30 @@ static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
{
struct mvebu_pcie *pcie = sys_to_pcie(sys);
int i;
+ int domain = 0;
+
+#ifdef CONFIG_PCI_DOMAINS
+ domain = sys->domain;
+#endif
+
+ snprintf(pcie->mem_name, sizeof(pcie->mem_name), "PCI MEM %04x",
+ domain);
+ pcie->mem.name = pcie->mem_name;
- if (resource_size(&pcie->realio) != 0)
+ snprintf(pcie->io_name, sizeof(pcie->io_name), "PCI I/O %04x", domain);
+ pcie->realio.name = pcie->io_name;
+
+ if (request_resource(&iomem_resource, &pcie->mem))
+ return 0;
+
+ if (resource_size(&pcie->realio) != 0) {
+ if (request_resource(&ioport_resource, &pcie->realio)) {
+ release_resource(&pcie->mem);
+ return 0;
+ }
pci_add_resource_offset(&sys->resources, &pcie->realio,
sys->io_offset);
+ }
pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
pci_add_resource(&sys->resources, &pcie->busn);
@@ -804,7 +819,7 @@ static int mvebu_get_tgt_attr(struct device_node *np, int devfn,
for (i = 0; i < nranges; i++) {
u32 flags = of_read_number(range, 1);
- u32 slot = of_read_number(range, 2);
+ u32 slot = of_read_number(range + 1, 1);
u64 cpuaddr = of_read_number(range + na, pna);
unsigned long rtype;
diff --git a/drivers/pci/host/pci-rcar-gen2.c b/drivers/pci/host/pci-rcar-gen2.c
index ceec147baec3..fd3e3ab56509 100644
--- a/drivers/pci/host/pci-rcar-gen2.c
+++ b/drivers/pci/host/pci-rcar-gen2.c
@@ -18,6 +18,7 @@
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/sizes.h>
#include <linux/slab.h>
/* AHB-PCI Bridge PCI communication registers */
@@ -39,9 +40,26 @@
#define RCAR_PCI_INT_ENABLE_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x20)
#define RCAR_PCI_INT_STATUS_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x24)
+#define RCAR_PCI_INT_SIGTABORT (1 << 0)
+#define RCAR_PCI_INT_SIGRETABORT (1 << 1)
+#define RCAR_PCI_INT_REMABORT (1 << 2)
+#define RCAR_PCI_INT_PERR (1 << 3)
+#define RCAR_PCI_INT_SIGSERR (1 << 4)
+#define RCAR_PCI_INT_RESERR (1 << 5)
+#define RCAR_PCI_INT_WIN1ERR (1 << 12)
+#define RCAR_PCI_INT_WIN2ERR (1 << 13)
#define RCAR_PCI_INT_A (1 << 16)
#define RCAR_PCI_INT_B (1 << 17)
#define RCAR_PCI_INT_PME (1 << 19)
+#define RCAR_PCI_INT_ALLERRORS (RCAR_PCI_INT_SIGTABORT | \
+ RCAR_PCI_INT_SIGRETABORT | \
+ RCAR_PCI_INT_SIGRETABORT | \
+ RCAR_PCI_INT_REMABORT | \
+ RCAR_PCI_INT_PERR | \
+ RCAR_PCI_INT_SIGSERR | \
+ RCAR_PCI_INT_RESERR | \
+ RCAR_PCI_INT_WIN1ERR | \
+ RCAR_PCI_INT_WIN2ERR)
#define RCAR_AHB_BUS_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x30)
#define RCAR_AHB_BUS_MMODE_HTRANS (1 << 0)
@@ -74,9 +92,6 @@
#define RCAR_PCI_UNIT_REV_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x48)
-/* Number of internal PCI controllers */
-#define RCAR_PCI_NR_CONTROLLERS 3
-
struct rcar_pci_priv {
struct device *dev;
void __iomem *reg;
@@ -84,6 +99,7 @@ struct rcar_pci_priv {
struct resource mem_res;
struct resource *cfg_res;
int irq;
+ unsigned long window_size;
};
/* PCI configuration space operations */
@@ -102,6 +118,10 @@ static void __iomem *rcar_pci_cfg_base(struct pci_bus *bus, unsigned int devfn,
if (slot > 2)
return NULL;
+ /* bridge logic only has registers to 0x40 */
+ if (slot == 0x0 && where >= 0x40)
+ return NULL;
+
val = slot ? RCAR_AHBPCI_WIN1_DEVICE | RCAR_AHBPCI_WIN_CTR_CFG :
RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG;
@@ -156,7 +176,7 @@ static int rcar_pci_write_config(struct pci_bus *bus, unsigned int devfn,
}
/* PCI interrupt mapping */
-static int __init rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+static int rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
struct pci_sys_data *sys = dev->bus->sysdata;
struct rcar_pci_priv *priv = sys->private_data;
@@ -164,8 +184,48 @@ static int __init rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
return priv->irq;
}
+#ifdef CONFIG_PCI_DEBUG
+/* if debug enabled, then attach an error handler irq to the bridge */
+
+static irqreturn_t rcar_pci_err_irq(int irq, void *pw)
+{
+ struct rcar_pci_priv *priv = pw;
+ u32 status = ioread32(priv->reg + RCAR_PCI_INT_STATUS_REG);
+
+ if (status & RCAR_PCI_INT_ALLERRORS) {
+ dev_err(priv->dev, "error irq: status %08x\n", status);
+
+ /* clear the error(s) */
+ iowrite32(status & RCAR_PCI_INT_ALLERRORS,
+ priv->reg + RCAR_PCI_INT_STATUS_REG);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static void rcar_pci_setup_errirq(struct rcar_pci_priv *priv)
+{
+ int ret;
+ u32 val;
+
+ ret = devm_request_irq(priv->dev, priv->irq, rcar_pci_err_irq,
+ IRQF_SHARED, "error irq", priv);
+ if (ret) {
+ dev_err(priv->dev, "cannot claim IRQ for error handling\n");
+ return;
+ }
+
+ val = ioread32(priv->reg + RCAR_PCI_INT_ENABLE_REG);
+ val |= RCAR_PCI_INT_ALLERRORS;
+ iowrite32(val, priv->reg + RCAR_PCI_INT_ENABLE_REG);
+}
+#else
+static inline void rcar_pci_setup_errirq(struct rcar_pci_priv *priv) { }
+#endif
+
/* PCI host controller setup */
-static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys)
+static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
{
struct rcar_pci_priv *priv = sys->private_data;
void __iomem *reg = priv->reg;
@@ -183,10 +243,31 @@ static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys)
iowrite32(val, reg + RCAR_USBCTR_REG);
udelay(4);
- /* De-assert reset and set PCIAHB window1 size to 1GB */
+ /* De-assert reset and reset PCIAHB window1 size */
val &= ~(RCAR_USBCTR_PCIAHB_WIN1_MASK | RCAR_USBCTR_PCICLK_MASK |
RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST);
- iowrite32(val | RCAR_USBCTR_PCIAHB_WIN1_1G, reg + RCAR_USBCTR_REG);
+
+ /* Setup PCIAHB window1 size */
+ switch (priv->window_size) {
+ case SZ_2G:
+ val |= RCAR_USBCTR_PCIAHB_WIN1_2G;
+ break;
+ case SZ_1G:
+ val |= RCAR_USBCTR_PCIAHB_WIN1_1G;
+ break;
+ case SZ_512M:
+ val |= RCAR_USBCTR_PCIAHB_WIN1_512M;
+ break;
+ default:
+ pr_warn("unknown window size %ld - defaulting to 256M\n",
+ priv->window_size);
+ priv->window_size = SZ_256M;
+ /* fall-through */
+ case SZ_256M:
+ val |= RCAR_USBCTR_PCIAHB_WIN1_256M;
+ break;
+ }
+ iowrite32(val, reg + RCAR_USBCTR_REG);
/* Configure AHB master and slave modes */
iowrite32(RCAR_AHB_BUS_MODE, reg + RCAR_AHB_BUS_CTR_REG);
@@ -197,7 +278,7 @@ static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys)
RCAR_PCI_ARBITER_PCIBP_MODE;
iowrite32(val, reg + RCAR_PCI_ARBITER_CTR_REG);
- /* PCI-AHB mapping: 0x40000000-0x80000000 */
+ /* PCI-AHB mapping: 0x40000000 base */
iowrite32(0x40000000 | RCAR_PCIAHB_PREFETCH16,
reg + RCAR_PCIAHB_WIN1_CTR_REG);
@@ -224,10 +305,15 @@ static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys)
iowrite32(RCAR_PCI_INT_A | RCAR_PCI_INT_B | RCAR_PCI_INT_PME,
reg + RCAR_PCI_INT_ENABLE_REG);
+ if (priv->irq > 0)
+ rcar_pci_setup_errirq(priv);
+
/* Add PCI resources */
pci_add_resource(&sys->resources, &priv->io_res);
pci_add_resource(&sys->resources, &priv->mem_res);
+ /* Setup bus number based on platform device id */
+ sys->busnr = to_platform_device(priv->dev)->id;
return 1;
}
@@ -236,48 +322,13 @@ static struct pci_ops rcar_pci_ops = {
.write = rcar_pci_write_config,
};
-static struct hw_pci rcar_hw_pci __initdata = {
- .map_irq = rcar_pci_map_irq,
- .ops = &rcar_pci_ops,
- .setup = rcar_pci_setup,
-};
-
-static int rcar_pci_count __initdata;
-
-static int __init rcar_pci_add_controller(struct rcar_pci_priv *priv)
-{
- void **private_data;
- int count;
-
- if (rcar_hw_pci.nr_controllers < rcar_pci_count)
- goto add_priv;
-
- /* (Re)allocate private data pointer array if needed */
- count = rcar_pci_count + RCAR_PCI_NR_CONTROLLERS;
- private_data = kzalloc(count * sizeof(void *), GFP_KERNEL);
- if (!private_data)
- return -ENOMEM;
-
- rcar_pci_count = count;
- if (rcar_hw_pci.private_data) {
- memcpy(private_data, rcar_hw_pci.private_data,
- rcar_hw_pci.nr_controllers * sizeof(void *));
- kfree(rcar_hw_pci.private_data);
- }
-
- rcar_hw_pci.private_data = private_data;
-
-add_priv:
- /* Add private data pointer to the array */
- rcar_hw_pci.private_data[rcar_hw_pci.nr_controllers++] = priv;
- return 0;
-}
-
-static int __init rcar_pci_probe(struct platform_device *pdev)
+static int rcar_pci_probe(struct platform_device *pdev)
{
struct resource *cfg_res, *mem_res;
struct rcar_pci_priv *priv;
void __iomem *reg;
+ struct hw_pci hw;
+ void *hw_private[1];
cfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg = devm_ioremap_resource(&pdev->dev, cfg_res);
@@ -308,31 +359,34 @@ static int __init rcar_pci_probe(struct platform_device *pdev)
priv->reg = reg;
priv->dev = &pdev->dev;
- return rcar_pci_add_controller(priv);
+ if (priv->irq < 0) {
+ dev_err(&pdev->dev, "no valid irq found\n");
+ return priv->irq;
+ }
+
+ priv->window_size = SZ_1G;
+
+ hw_private[0] = priv;
+ memset(&hw, 0, sizeof(hw));
+ hw.nr_controllers = ARRAY_SIZE(hw_private);
+ hw.private_data = hw_private;
+ hw.map_irq = rcar_pci_map_irq;
+ hw.ops = &rcar_pci_ops;
+ hw.setup = rcar_pci_setup;
+ pci_common_init_dev(&pdev->dev, &hw);
+ return 0;
}
static struct platform_driver rcar_pci_driver = {
.driver = {
.name = "pci-rcar-gen2",
+ .owner = THIS_MODULE,
+ .suppress_bind_attrs = true,
},
+ .probe = rcar_pci_probe,
};
-static int __init rcar_pci_init(void)
-{
- int retval;
-
- retval = platform_driver_probe(&rcar_pci_driver, rcar_pci_probe);
- if (!retval)
- pci_common_init(&rcar_hw_pci);
-
- /* Private data pointer array is not needed any more */
- kfree(rcar_hw_pci.private_data);
- rcar_hw_pci.private_data = NULL;
-
- return retval;
-}
-
-subsys_initcall(rcar_pci_init);
+module_platform_driver(rcar_pci_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Renesas R-Car Gen2 internal PCI");
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 17ce88f79d2b..509a29d84509 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -294,14 +294,12 @@ no_valid_irq:
static void clear_irq(unsigned int irq)
{
unsigned int pos, nvec;
- struct irq_desc *desc;
struct msi_desc *msi;
struct pcie_port *pp;
struct irq_data *data = irq_get_irq_data(irq);
/* get the port structure */
- desc = irq_to_desc(irq);
- msi = irq_desc_get_msi_desc(desc);
+ msi = irq_data_get_msi(data);
pp = sys_to_pcie(msi->dev->bus->sysdata);
if (!pp) {
BUG();
@@ -800,7 +798,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
/* setup RC BARs */
dw_pcie_writel_rc(pp, 0x00000004, PCI_BASE_ADDRESS_0);
- dw_pcie_writel_rc(pp, 0x00000004, PCI_BASE_ADDRESS_1);
+ dw_pcie_writel_rc(pp, 0x00000000, PCI_BASE_ADDRESS_1);
/* setup interrupt pins */
dw_pcie_readl_rc(pp, PCI_INTERRUPT_LINE, &val);
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index b6162be4df40..2b859249303b 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -93,7 +93,6 @@ struct acpiphp_slot {
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# */
u32 flags; /* see below */
@@ -117,20 +116,30 @@ struct acpiphp_func {
};
struct acpiphp_context {
- acpi_handle handle;
+ struct acpi_hotplug_context hp;
struct acpiphp_func func;
struct acpiphp_bridge *bridge;
unsigned int refcount;
};
+static inline struct acpiphp_context *to_acpiphp_context(struct acpi_hotplug_context *hp)
+{
+ return container_of(hp, struct acpiphp_context, hp);
+}
+
static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func)
{
return container_of(func, struct acpiphp_context, func);
}
+static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func)
+{
+ return func_to_context(func)->hp.self;
+}
+
static inline acpi_handle func_to_handle(struct acpiphp_func *func)
{
- return func_to_context(func)->handle;
+ return func_to_acpi_device(func)->handle;
}
/*
@@ -158,7 +167,6 @@ struct acpiphp_attention_info
#define FUNC_HAS_STA (0x00000001)
#define FUNC_HAS_EJ0 (0x00000002)
-#define FUNC_HAS_DCK (0x00000004)
/* function prototypes */
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index e2a783fdb98f..bccc27ee1030 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -58,71 +58,59 @@
static LIST_HEAD(bridge_list);
static DEFINE_MUTEX(bridge_mutex);
-static DEFINE_MUTEX(acpiphp_context_lock);
-static void handle_hotplug_event(acpi_handle handle, u32 type, void *data);
+static int acpiphp_hotplug_notify(struct acpi_device *adev, u32 type);
+static void acpiphp_post_dock_fixup(struct acpi_device *adev);
static void acpiphp_sanitize_bus(struct pci_bus *bus);
static void acpiphp_set_hpp_values(struct pci_bus *bus);
-static void hotplug_event(acpi_handle handle, u32 type, void *data);
+static void hotplug_event(u32 type, struct acpiphp_context *context);
static void free_bridge(struct kref *kref);
-static void acpiphp_context_handler(acpi_handle handle, void *context)
-{
- /* Intentionally empty. */
-}
-
/**
* acpiphp_init_context - Create hotplug context and grab a reference to it.
- * @handle: ACPI object handle to create the context for.
+ * @adev: ACPI device object to create the context for.
*
- * Call under acpiphp_context_lock.
+ * Call under acpi_hp_context_lock.
*/
-static struct acpiphp_context *acpiphp_init_context(acpi_handle handle)
+static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev)
{
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;
- }
+ acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_notify, NULL,
+ acpiphp_post_dock_fixup);
return context;
}
/**
* acpiphp_get_context - Get hotplug context and grab a reference to it.
- * @handle: ACPI object handle to get the context for.
+ * @adev: ACPI device object to get the context for.
*
- * Call under acpiphp_context_lock.
+ * Call under acpi_hp_context_lock.
*/
-static struct acpiphp_context *acpiphp_get_context(acpi_handle handle)
+static struct acpiphp_context *acpiphp_get_context(struct acpi_device *adev)
{
- struct acpiphp_context *context = NULL;
- acpi_status status;
- void *data;
+ struct acpiphp_context *context;
- status = acpi_get_data(handle, acpiphp_context_handler, &data);
- if (ACPI_SUCCESS(status)) {
- context = data;
- context->refcount++;
- }
+ if (!adev->hp)
+ return NULL;
+
+ context = to_acpiphp_context(adev->hp);
+ context->refcount++;
return context;
}
/**
* acpiphp_put_context - Drop a reference to ACPI hotplug context.
- * @handle: ACPI object handle to put the context for.
+ * @context: ACPI hotplug context to drop a reference to.
*
* The context object is removed if there are no more references to it.
*
- * Call under acpiphp_context_lock.
+ * Call under acpi_hp_context_lock.
*/
static void acpiphp_put_context(struct acpiphp_context *context)
{
@@ -130,7 +118,7 @@ static void acpiphp_put_context(struct acpiphp_context *context)
return;
WARN_ON(context->bridge);
- acpi_detach_data(context->handle, acpiphp_context_handler);
+ context->hp.self->hp = NULL;
kfree(context);
}
@@ -144,6 +132,27 @@ static inline void put_bridge(struct acpiphp_bridge *bridge)
kref_put(&bridge->ref, free_bridge);
}
+static struct acpiphp_context *acpiphp_grab_context(struct acpi_device *adev)
+{
+ struct acpiphp_context *context;
+
+ acpi_lock_hp_context();
+ context = acpiphp_get_context(adev);
+ if (!context || context->func.parent->is_going_away) {
+ acpi_unlock_hp_context();
+ return NULL;
+ }
+ get_bridge(context->func.parent);
+ acpiphp_put_context(context);
+ acpi_unlock_hp_context();
+ return context;
+}
+
+static void acpiphp_let_context_go(struct acpiphp_context *context)
+{
+ put_bridge(context->func.parent);
+}
+
static void free_bridge(struct kref *kref)
{
struct acpiphp_context *context;
@@ -151,7 +160,7 @@ static void free_bridge(struct kref *kref)
struct acpiphp_slot *slot, *next;
struct acpiphp_func *func, *tmp;
- mutex_lock(&acpiphp_context_lock);
+ acpi_lock_hp_context();
bridge = container_of(kref, struct acpiphp_bridge, ref);
@@ -175,31 +184,32 @@ static void free_bridge(struct kref *kref)
pci_dev_put(bridge->pci_dev);
kfree(bridge);
- mutex_unlock(&acpiphp_context_lock);
+ acpi_unlock_hp_context();
}
-/*
- * the _DCK method can do funny things... and sometimes not
- * hah-hah funny.
+/**
+ * acpiphp_post_dock_fixup - Post-dock fixups for PCI devices.
+ * @adev: ACPI device object corresponding to a PCI device.
*
- * TBD - figure out a way to only call fixups for
- * systems that require them.
+ * TBD - figure out a way to only call fixups for systems that require them.
*/
-static void post_dock_fixups(acpi_handle not_used, u32 event, void *data)
+static void acpiphp_post_dock_fixup(struct acpi_device *adev)
{
- struct acpiphp_context *context = data;
- struct pci_bus *bus = context->func.slot->bus;
+ struct acpiphp_context *context = acpiphp_grab_context(adev);
+ struct pci_bus *bus;
u32 buses;
- if (!bus->self)
+ if (!context)
return;
+ bus = context->func.slot->bus;
+ if (!bus->self)
+ goto out;
+
/* fixup bad _DCK function that rewrites
* secondary bridge on slot
*/
- pci_read_config_dword(bus->self,
- PCI_PRIMARY_BUS,
- &buses);
+ pci_read_config_dword(bus->self, PCI_PRIMARY_BUS, &buses);
if (((buses >> 8) & 0xff) != bus->busn_res.start) {
buses = (buses & 0xff000000)
@@ -208,33 +218,11 @@ static void post_dock_fixups(acpi_handle not_used, u32 event, void *data)
| ((unsigned int)(bus->busn_res.end) << 16);
pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses);
}
-}
-
-static void dock_event(acpi_handle handle, u32 type, void *data)
-{
- struct acpiphp_context *context;
-
- mutex_lock(&acpiphp_context_lock);
- context = acpiphp_get_context(handle);
- if (!context || WARN_ON(context->handle != handle)
- || context->func.parent->is_going_away) {
- mutex_unlock(&acpiphp_context_lock);
- return;
- }
- get_bridge(context->func.parent);
- acpiphp_put_context(context);
- mutex_unlock(&acpiphp_context_lock);
-
- hotplug_event(handle, type, data);
- put_bridge(context->func.parent);
+ out:
+ acpiphp_let_context_go(context);
}
-static const struct acpi_dock_ops acpiphp_dock_ops = {
- .fixup = post_dock_fixups,
- .handler = dock_event,
-};
-
/* Check whether the PCI device is managed by native PCIe hotplug driver */
static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev)
{
@@ -264,26 +252,19 @@ static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev)
return true;
}
-static void acpiphp_dock_init(void *data)
-{
- struct acpiphp_context *context = data;
-
- get_bridge(context->func.parent);
-}
-
-static void acpiphp_dock_release(void *data)
-{
- struct acpiphp_context *context = data;
-
- 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 *data,
- void **rv)
+/**
+ * acpiphp_add_context - Add ACPIPHP context to an ACPI device object.
+ * @handle: ACPI handle of the object to add a context to.
+ * @lvl: Not used.
+ * @data: The object's parent ACPIPHP bridge.
+ * @rv: Not used.
+ */
+static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data,
+ void **rv)
{
struct acpiphp_bridge *bridge = data;
struct acpiphp_context *context;
+ struct acpi_device *adev;
struct acpiphp_slot *slot;
struct acpiphp_func *newfunc;
acpi_status status = AE_OK;
@@ -293,9 +274,6 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
struct pci_dev *pdev = bridge->pci_dev;
u32 val;
- if (pdev && device_is_managed_by_native_pciehp(pdev))
- return AE_OK;
-
status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
if (ACPI_FAILURE(status)) {
if (status != AE_NOT_FOUND)
@@ -303,31 +281,34 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
"can't evaluate _ADR (%#x)\n", status);
return AE_OK;
}
+ if (acpi_bus_get_device(handle, &adev))
+ return AE_OK;
device = (adr >> 16) & 0xffff;
function = adr & 0xffff;
- mutex_lock(&acpiphp_context_lock);
- context = acpiphp_init_context(handle);
+ acpi_lock_hp_context();
+ context = acpiphp_init_context(adev);
if (!context) {
- mutex_unlock(&acpiphp_context_lock);
+ acpi_unlock_hp_context();
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);
+ acpi_unlock_hp_context();
- if (acpi_has_method(handle, "_EJ0"))
+ /*
+ * If this is a dock device, its _EJ0 should be executed by the dock
+ * notify handler after calling _DCK.
+ */
+ if (!is_dock_device(adev) && acpi_has_method(handle, "_EJ0"))
newfunc->flags = FUNC_HAS_EJ0;
if (acpi_has_method(handle, "_STA"))
newfunc->flags |= FUNC_HAS_STA;
- if (acpi_has_method(handle, "_DCK"))
- newfunc->flags |= FUNC_HAS_DCK;
-
/* search for objects that share the same slot */
list_for_each_entry(slot, &bridge->slots, node)
if (slot->device == device)
@@ -335,19 +316,26 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
if (!slot) {
- status = AE_NO_MEMORY;
- goto err;
+ acpi_lock_hp_context();
+ acpiphp_put_context(context);
+ acpi_unlock_hp_context();
+ return AE_NO_MEMORY;
}
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 functions only. */
- if (acpi_pci_check_ejectable(pbus, handle) || is_dock_device(handle)) {
+ /*
+ * Expose slots to user space for functions that have _EJ0 or _RMV or
+ * are located in dock stations. Do not expose them for devices handled
+ * by the native PCIe hotplug (PCIeHP), becuase that code is supposed to
+ * expose slots to user space in those cases.
+ */
+ if ((acpi_pci_check_ejectable(pbus, handle) || is_dock_device(adev))
+ && !(pdev && device_is_managed_by_native_pciehp(pdev))) {
unsigned long long sun;
int retval;
@@ -381,44 +369,16 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
&val, 60*1000))
slot->flags |= SLOT_ENABLED;
- if (is_dock_device(handle)) {
- /* we don't want to call this device's _EJ0
- * because we want the dock notify handler
- * to call it after it calls _DCK
- */
- newfunc->flags &= ~FUNC_HAS_EJ0;
- if (register_hotplug_dock_device(handle,
- &acpiphp_dock_ops, context,
- acpiphp_dock_init, acpiphp_dock_release))
- pr_debug("failed to register dock device\n");
- }
-
- /* install notify handler */
- if (!(newfunc->flags & FUNC_HAS_DCK)) {
- status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event,
- context);
- if (ACPI_FAILURE(status))
- acpi_handle_err(handle,
- "failed to install notify handler\n");
- }
-
return AE_OK;
-
- 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)
+static struct acpiphp_bridge *acpiphp_dev_to_bridge(struct acpi_device *adev)
{
struct acpiphp_context *context;
struct acpiphp_bridge *bridge = NULL;
- mutex_lock(&acpiphp_context_lock);
- context = acpiphp_get_context(handle);
+ acpi_lock_hp_context();
+ context = acpiphp_get_context(adev);
if (context) {
bridge = context->bridge;
if (bridge)
@@ -426,7 +386,7 @@ static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
acpiphp_put_context(context);
}
- mutex_unlock(&acpiphp_context_lock);
+ acpi_unlock_hp_context();
return bridge;
}
@@ -434,22 +394,15 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
{
struct acpiphp_slot *slot;
struct acpiphp_func *func;
- acpi_status status;
list_for_each_entry(slot, &bridge->slots, node) {
list_for_each_entry(func, &slot->funcs, sibling) {
- acpi_handle handle = func_to_handle(func);
-
- if (is_dock_device(handle))
- unregister_hotplug_dock_device(handle);
+ struct acpi_device *adev = func_to_acpi_device(func);
- if (!(func->flags & FUNC_HAS_DCK)) {
- status = acpi_remove_notify_handler(handle,
- ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event);
- if (ACPI_FAILURE(status))
- pr_err("failed to remove notify handler\n");
- }
+ acpi_lock_hp_context();
+ adev->hp->notify = NULL;
+ adev->hp->fixup = NULL;
+ acpi_unlock_hp_context();
}
slot->flags |= SLOT_IS_GOING_AWAY;
if (slot->slot)
@@ -460,9 +413,9 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
list_del(&bridge->list);
mutex_unlock(&bridge_mutex);
- mutex_lock(&acpiphp_context_lock);
+ acpi_lock_hp_context();
bridge->is_going_away = true;
- mutex_unlock(&acpiphp_context_lock);
+ acpi_unlock_hp_context();
}
/**
@@ -471,7 +424,7 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
*/
static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
{
- struct list_head *tmp;
+ struct pci_bus *tmp;
unsigned char max, n;
/*
@@ -484,41 +437,14 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
*/
max = bus->busn_res.start;
- list_for_each(tmp, &bus->children) {
- n = pci_bus_max_busnr(pci_bus_b(tmp));
+ list_for_each_entry(tmp, &bus->children, node) {
+ n = pci_bus_max_busnr(tmp);
if (n > max)
max = n;
}
return max;
}
-/**
- * acpiphp_bus_trim - Trim device objects in an ACPI namespace subtree.
- * @handle: ACPI device object handle to start from.
- */
-static void acpiphp_bus_trim(acpi_handle handle)
-{
- struct acpi_device *adev = NULL;
-
- acpi_bus_get_device(handle, &adev);
- if (adev)
- acpi_bus_trim(adev);
-}
-
-/**
- * acpiphp_bus_add - Scan ACPI namespace subtree.
- * @handle: ACPI object handle to start the scan from.
- */
-static void acpiphp_bus_add(acpi_handle handle)
-{
- struct acpi_device *adev = NULL;
-
- acpi_bus_scan(handle);
- acpi_bus_get_device(handle, &adev);
- if (acpi_device_enumerated(adev))
- acpi_device_set_power(adev, ACPI_STATE_D0);
-}
-
static void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
{
struct acpiphp_func *func;
@@ -558,9 +484,13 @@ static int acpiphp_rescan_slot(struct acpiphp_slot *slot)
{
struct acpiphp_func *func;
- list_for_each_entry(func, &slot->funcs, sibling)
- acpiphp_bus_add(func_to_handle(func));
+ list_for_each_entry(func, &slot->funcs, sibling) {
+ struct acpi_device *adev = func_to_acpi_device(func);
+ acpi_bus_scan(adev->handle);
+ if (acpi_device_enumerated(adev))
+ acpi_device_set_power(adev, ACPI_STATE_D0);
+ }
return pci_scan_slot(slot->bus, PCI_DEVFN(slot->device, 0));
}
@@ -625,32 +555,15 @@ static void __ref enable_slot(struct acpiphp_slot *slot)
}
}
-/* 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->bus;
- struct pci_dev *dev;
- struct pci_dev *ret = NULL;
-
- down_read(&pci_bus_sem);
- list_for_each_entry(dev, &bus->devices, bus_list)
- if (PCI_SLOT(dev->devfn) == slot->device) {
- ret = pci_dev_get(dev);
- break;
- }
- up_read(&pci_bus_sem);
-
- return ret;
-}
-
/**
* disable_slot - disable a slot
* @slot: ACPI PHP slot
*/
static void disable_slot(struct acpiphp_slot *slot)
{
+ struct pci_bus *bus = slot->bus;
+ struct pci_dev *dev, *prev;
struct acpiphp_func *func;
- struct pci_dev *pdev;
/*
* enable_slot() enumerates all functions in this device via
@@ -658,22 +571,18 @@ static void disable_slot(struct acpiphp_slot *slot)
* methods (_EJ0, etc.) or not. Therefore, we remove all functions
* here.
*/
- while ((pdev = dev_in_slot(slot))) {
- pci_stop_and_remove_bus_device(pdev);
- pci_dev_put(pdev);
- }
+ list_for_each_entry_safe_reverse(dev, prev, &bus->devices, bus_list)
+ if (PCI_SLOT(dev->devfn) == slot->device)
+ pci_stop_and_remove_bus_device(dev);
list_for_each_entry(func, &slot->funcs, sibling)
- acpiphp_bus_trim(func_to_handle(func));
+ acpi_bus_trim(func_to_acpi_device(func));
slot->flags &= (~SLOT_ENABLED);
}
-static bool acpiphp_no_hotplug(acpi_handle handle)
+static bool acpiphp_no_hotplug(struct acpi_device *adev)
{
- struct acpi_device *adev = NULL;
-
- acpi_bus_get_device(handle, &adev);
return adev && adev->flags.no_hotplug;
}
@@ -682,7 +591,7 @@ static bool slot_no_hotplug(struct acpiphp_slot *slot)
struct acpiphp_func *func;
list_for_each_entry(func, &slot->funcs, sibling)
- if (acpiphp_no_hotplug(func_to_handle(func)))
+ if (acpiphp_no_hotplug(func_to_acpi_device(func)))
return true;
return false;
@@ -730,34 +639,42 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot)
return (unsigned int)sta;
}
+static inline bool device_status_valid(unsigned int sta)
+{
+ /*
+ * ACPI spec says that _STA may return bit 0 clear with bit 3 set
+ * if the device is valid but does not require a device driver to be
+ * loaded (Section 6.3.7 of ACPI 5.0A).
+ */
+ unsigned int mask = ACPI_STA_DEVICE_ENABLED | ACPI_STA_DEVICE_FUNCTIONING;
+ return (sta & mask) == mask;
+}
+
/**
* trim_stale_devices - remove PCI devices that are not responding.
* @dev: PCI device to start walking the hierarchy from.
*/
static void trim_stale_devices(struct pci_dev *dev)
{
- acpi_handle handle = ACPI_HANDLE(&dev->dev);
+ struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
struct pci_bus *bus = dev->subordinate;
bool alive = false;
- if (handle) {
+ if (adev) {
acpi_status status;
unsigned long long sta;
- status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
- alive = (ACPI_SUCCESS(status) && sta == ACPI_STA_ALL)
- || acpiphp_no_hotplug(handle);
+ status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta);
+ alive = (ACPI_SUCCESS(status) && device_status_valid(sta))
+ || acpiphp_no_hotplug(adev);
}
- if (!alive) {
- u32 v;
+ if (!alive)
+ alive = pci_device_is_present(dev);
- /* 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);
+ if (adev)
+ acpi_bus_trim(adev);
} else if (bus) {
struct pci_dev *child, *tmp;
@@ -789,10 +706,9 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
struct pci_bus *bus = slot->bus;
struct pci_dev *dev, *tmp;
- mutex_lock(&slot->crit_sect);
if (slot_no_hotplug(slot)) {
; /* do nothing */
- } else if (get_slot_status(slot) == ACPI_STA_ALL) {
+ } else if (device_status_valid(get_slot_status(slot))) {
/* remove stale devices if any */
list_for_each_entry_safe_reverse(dev, tmp,
&bus->devices, bus_list)
@@ -804,7 +720,6 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
} else {
disable_slot(slot);
}
- mutex_unlock(&slot->crit_sect);
}
}
@@ -844,11 +759,11 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus)
* ACPI event handlers
*/
-void acpiphp_check_host_bridge(acpi_handle handle)
+void acpiphp_check_host_bridge(struct acpi_device *adev)
{
struct acpiphp_bridge *bridge;
- bridge = acpiphp_handle_to_bridge(handle);
+ bridge = acpiphp_dev_to_bridge(adev);
if (bridge) {
pci_lock_rescan_remove();
@@ -861,73 +776,52 @@ void acpiphp_check_host_bridge(acpi_handle handle)
static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot);
-static void hotplug_event(acpi_handle handle, u32 type, void *data)
+static void hotplug_event(u32 type, struct acpiphp_context *context)
{
- struct acpiphp_context *context = data;
+ acpi_handle handle = context->hp.self->handle;
struct acpiphp_func *func = &context->func;
+ struct acpiphp_slot *slot = func->slot;
struct acpiphp_bridge *bridge;
- char objname[64];
- struct acpi_buffer buffer = { .length = sizeof(objname),
- .pointer = objname };
- mutex_lock(&acpiphp_context_lock);
+ acpi_lock_hp_context();
bridge = context->bridge;
if (bridge)
get_bridge(bridge);
- mutex_unlock(&acpiphp_context_lock);
+ acpi_unlock_hp_context();
pci_lock_rescan_remove();
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
/* bus re-enumerate */
- pr_debug("%s: Bus check notify on %s\n", __func__, objname);
- pr_debug("%s: re-enumerating slots under %s\n",
- __func__, objname);
- if (bridge) {
+ acpi_handle_debug(handle, "Bus check in %s()\n", __func__);
+ if (bridge)
acpiphp_check_bridge(bridge);
- } else {
- struct acpiphp_slot *slot = func->slot;
-
- if (slot->flags & SLOT_IS_GOING_AWAY)
- break;
-
- mutex_lock(&slot->crit_sect);
+ else if (!(slot->flags & SLOT_IS_GOING_AWAY))
enable_slot(slot);
- mutex_unlock(&slot->crit_sect);
- }
+
break;
case ACPI_NOTIFY_DEVICE_CHECK:
/* device check */
- pr_debug("%s: Device check notify on %s\n", __func__, objname);
+ acpi_handle_debug(handle, "Device check in %s()\n", __func__);
if (bridge) {
acpiphp_check_bridge(bridge);
- } else {
- struct acpiphp_slot *slot = func->slot;
- int ret;
-
- if (slot->flags & SLOT_IS_GOING_AWAY)
- break;
-
+ } else if (!(slot->flags & SLOT_IS_GOING_AWAY)) {
/*
* Check if anything has changed in the slot and rescan
* from the parent if that's the case.
*/
- mutex_lock(&slot->crit_sect);
- ret = acpiphp_rescan_slot(slot);
- mutex_unlock(&slot->crit_sect);
- if (ret)
+ if (acpiphp_rescan_slot(slot))
acpiphp_check_bridge(func->parent);
}
break;
case ACPI_NOTIFY_EJECT_REQUEST:
/* request device eject */
- pr_debug("%s: Device eject notify on %s\n", __func__, objname);
- acpiphp_disable_and_eject_slot(func->slot);
+ acpi_handle_debug(handle, "Eject request in %s()\n", __func__);
+ acpiphp_disable_and_eject_slot(slot);
break;
}
@@ -936,106 +830,41 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data)
put_bridge(bridge);
}
-static void hotplug_event_work(void *data, u32 type)
+static int acpiphp_hotplug_notify(struct acpi_device *adev, u32 type)
{
- struct acpiphp_context *context = data;
- acpi_handle handle = context->handle;
-
- acpi_scan_lock_acquire();
+ struct acpiphp_context *context;
- hotplug_event(handle, type, context);
+ context = acpiphp_grab_context(adev);
+ if (!context)
+ return -ENODATA;
- acpi_scan_lock_release();
- acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL);
- put_bridge(context->func.parent);
+ hotplug_event(type, context);
+ acpiphp_let_context_go(context);
+ return 0;
}
/**
- * handle_hotplug_event - handle ACPI hotplug event
- * @handle: Notify()'ed acpi_handle
- * @type: Notify code
- * @data: pointer to acpiphp_context structure
+ * acpiphp_enumerate_slots - Enumerate PCI slots for a given bus.
+ * @bus: PCI bus to enumerate the slots for.
*
- * Handles ACPI event notification on slots.
- */
-static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
-{
- struct acpiphp_context *context;
- u32 ost_code = ACPI_OST_SC_SUCCESS;
- acpi_status status;
-
- switch (type) {
- case ACPI_NOTIFY_BUS_CHECK:
- case ACPI_NOTIFY_DEVICE_CHECK:
- break;
- case ACPI_NOTIFY_EJECT_REQUEST:
- ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS;
- acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
- break;
-
- case ACPI_NOTIFY_DEVICE_WAKE:
- return;
-
- case ACPI_NOTIFY_FREQUENCY_MISMATCH:
- acpi_handle_err(handle, "Device cannot be configured due "
- "to a frequency mismatch\n");
- goto out;
-
- case ACPI_NOTIFY_BUS_MODE_MISMATCH:
- acpi_handle_err(handle, "Device cannot be configured due "
- "to a bus mode mismatch\n");
- goto out;
-
- case ACPI_NOTIFY_POWER_FAULT:
- acpi_handle_err(handle, "Device has suffered a power fault\n");
- goto out;
-
- default:
- acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
- ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY;
- goto out;
- }
-
- mutex_lock(&acpiphp_context_lock);
- context = acpiphp_get_context(handle);
- if (!context || WARN_ON(context->handle != handle)
- || context->func.parent->is_going_away)
- goto err_out;
-
- get_bridge(context->func.parent);
- acpiphp_put_context(context);
- status = acpi_hotplug_execute(hotplug_event_work, context, type);
- if (ACPI_SUCCESS(status)) {
- mutex_unlock(&acpiphp_context_lock);
- return;
- }
- put_bridge(context->func.parent);
-
- err_out:
- mutex_unlock(&acpiphp_context_lock);
- ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
-
- out:
- acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
-}
-
-/*
- * Create hotplug slots for the PCI bus.
- * It should always return 0 to avoid skipping following notifiers.
+ * A "slot" is an object associated with a PCI device number. All functions
+ * (PCI devices) with the same bus and device number belong to the same slot.
*/
void acpiphp_enumerate_slots(struct pci_bus *bus)
{
struct acpiphp_bridge *bridge;
+ struct acpi_device *adev;
acpi_handle handle;
acpi_status status;
if (acpiphp_disabled)
return;
- handle = ACPI_HANDLE(bus->bridge);
- if (!handle)
+ adev = ACPI_COMPANION(bus->bridge);
+ if (!adev)
return;
+ handle = adev->handle;
bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
if (!bridge) {
acpi_handle_err(handle, "No memory for bridge object\n");
@@ -1063,10 +892,10 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
* parent is going to be handled by pciehp, in which case this
* bridge is not interesting to us either.
*/
- mutex_lock(&acpiphp_context_lock);
- context = acpiphp_get_context(handle);
+ acpi_lock_hp_context();
+ context = acpiphp_get_context(adev);
if (!context) {
- mutex_unlock(&acpiphp_context_lock);
+ acpi_unlock_hp_context();
put_device(&bus->dev);
pci_dev_put(bridge->pci_dev);
kfree(bridge);
@@ -1076,17 +905,17 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
context->bridge = bridge;
/* Get a reference to the parent bridge. */
get_bridge(context->func.parent);
- mutex_unlock(&acpiphp_context_lock);
+ acpi_unlock_hp_context();
}
- /* must be added to the list prior to calling register_slot */
+ /* Must be added to the list prior to calling acpiphp_add_context(). */
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);
+ acpiphp_add_context, NULL, bridge, NULL);
if (ACPI_FAILURE(status)) {
acpi_handle_err(handle, "failed to register slots\n");
cleanup_bridge(bridge);
@@ -1094,7 +923,10 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
}
}
-/* Destroy hotplug slots associated with the PCI bus */
+/**
+ * acpiphp_remove_slots - Remove slot objects associated with a given bus.
+ * @bus: PCI bus to remove the slot objects for.
+ */
void acpiphp_remove_slots(struct pci_bus *bus)
{
struct acpiphp_bridge *bridge;
@@ -1125,13 +957,10 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot)
if (slot->flags & SLOT_IS_GOING_AWAY)
return -ENODEV;
- mutex_lock(&slot->crit_sect);
/* configure all functions */
if (!(slot->flags & SLOT_ENABLED))
enable_slot(slot);
- mutex_unlock(&slot->crit_sect);
-
pci_unlock_rescan_remove();
return 0;
}
@@ -1147,8 +976,6 @@ static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot)
if (slot->flags & SLOT_IS_GOING_AWAY)
return -ENODEV;
- mutex_lock(&slot->crit_sect);
-
/* unconfigure all functions */
disable_slot(slot);
@@ -1162,7 +989,6 @@ static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot)
break;
}
- mutex_unlock(&slot->crit_sect);
return 0;
}
@@ -1170,9 +996,15 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot)
{
int ret;
+ /*
+ * Acquire acpi_scan_lock to ensure that the execution of _EJ0 in
+ * acpiphp_disable_and_eject_slot() will be synchronized properly.
+ */
+ acpi_scan_lock_acquire();
pci_lock_rescan_remove();
ret = acpiphp_disable_and_eject_slot(slot);
pci_unlock_rescan_remove();
+ acpi_scan_lock_release();
return ret;
}
diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
index 31273e155e6c..037e2612c5bd 100644
--- a/drivers/pci/hotplug/cpqphp_core.c
+++ b/drivers/pci/hotplug/cpqphp_core.c
@@ -920,12 +920,12 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
bus->max_bus_speed = PCI_SPEED_100MHz_PCIX;
break;
}
- if (bus_cap & 20) {
+ if (bus_cap & 0x20) {
dbg("bus max supports 66MHz PCI-X\n");
bus->max_bus_speed = PCI_SPEED_66MHz_PCIX;
break;
}
- if (bus_cap & 10) {
+ if (bus_cap & 0x10) {
dbg("bus max supports 66MHz PCI\n");
bus->max_bus_speed = PCI_SPEED_66MHz;
break;
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 88b37cad4b35..8a66866b8cf1 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -76,6 +76,7 @@ struct slot {
struct hotplug_slot *hotplug_slot;
struct delayed_work work; /* work for button event */
struct mutex lock;
+ struct mutex hotplug_lock;
struct workqueue_struct *wq;
};
@@ -109,6 +110,8 @@ struct controller {
#define INT_BUTTON_PRESS 7
#define INT_BUTTON_RELEASE 8
#define INT_BUTTON_CANCEL 9
+#define INT_LINK_UP 10
+#define INT_LINK_DOWN 11
#define STATIC_STATE 0
#define BLINKINGON_STATE 1
@@ -132,6 +135,7 @@ u8 pciehp_handle_attention_button(struct slot *p_slot);
u8 pciehp_handle_switch_change(struct slot *p_slot);
u8 pciehp_handle_presence_change(struct slot *p_slot);
u8 pciehp_handle_power_fault(struct slot *p_slot);
+void pciehp_handle_linkstate_change(struct slot *p_slot);
int pciehp_configure_device(struct slot *p_slot);
int pciehp_unconfigure_device(struct slot *p_slot);
void pciehp_queue_pushbutton_work(struct work_struct *work);
@@ -153,6 +157,7 @@ void pciehp_green_led_on(struct slot *slot);
void pciehp_green_led_off(struct slot *slot);
void pciehp_green_led_blink(struct slot *slot);
int pciehp_check_link_status(struct controller *ctrl);
+bool pciehp_check_link_active(struct controller *ctrl);
void pciehp_release_ctrl(struct controller *ctrl);
int pciehp_reset_slot(struct slot *slot, int probe);
diff --git a/drivers/pci/hotplug/pciehp_acpi.c b/drivers/pci/hotplug/pciehp_acpi.c
index eddddd447d0d..20fea57d2149 100644
--- a/drivers/pci/hotplug/pciehp_acpi.c
+++ b/drivers/pci/hotplug/pciehp_acpi.c
@@ -112,6 +112,7 @@ static struct pcie_port_service_driver __initdata dummy_driver = {
static int __init select_detection_mode(void)
{
struct dummy_slot *slot, *tmp;
+
if (pcie_port_service_register(&dummy_driver))
return PCIEHP_DETECT_ACPI;
pcie_port_service_unregister(&dummy_driver);
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index 53b58debc288..0e0a2fff20a3 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -108,6 +108,7 @@ static int init_slot(struct controller *ctrl)
ops = kzalloc(sizeof(*ops), GFP_KERNEL);
if (!ops)
goto out;
+
ops->enable_slot = enable_slot;
ops->disable_slot = disable_slot;
ops->get_power_status = get_power_status;
@@ -283,8 +284,11 @@ static int pciehp_probe(struct pcie_device *dev)
slot = ctrl->slot;
pciehp_get_adapter_status(slot, &occupied);
pciehp_get_power_status(slot, &poweron);
- if (occupied && pciehp_force)
+ if (occupied && pciehp_force) {
+ mutex_lock(&slot->hotplug_lock);
pciehp_enable_slot(slot);
+ mutex_unlock(&slot->hotplug_lock);
+ }
/* If empty slot's power status is on, turn power off */
if (!occupied && poweron && POWER_CTRL(ctrl))
pciehp_power_off_slot(slot);
@@ -328,10 +332,12 @@ static int pciehp_resume (struct pcie_device *dev)
/* Check if slot is occupied */
pciehp_get_adapter_status(slot, &status);
+ mutex_lock(&slot->hotplug_lock);
if (status)
pciehp_enable_slot(slot);
else
pciehp_disable_slot(slot);
+ mutex_unlock(&slot->hotplug_lock);
return 0;
}
#endif /* PM */
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 50628487597d..c75e6a678dcc 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -150,6 +150,27 @@ u8 pciehp_handle_power_fault(struct slot *p_slot)
return 1;
}
+void pciehp_handle_linkstate_change(struct slot *p_slot)
+{
+ u32 event_type;
+ struct controller *ctrl = p_slot->ctrl;
+
+ /* Link Status Change */
+ ctrl_dbg(ctrl, "Data Link Layer State change\n");
+
+ if (pciehp_check_link_active(ctrl)) {
+ ctrl_info(ctrl, "slot(%s): Link Up event\n",
+ slot_name(p_slot));
+ event_type = INT_LINK_UP;
+ } else {
+ ctrl_info(ctrl, "slot(%s): Link Down event\n",
+ slot_name(p_slot));
+ event_type = INT_LINK_DOWN;
+ }
+
+ queue_interrupt_event(p_slot, event_type);
+}
+
/* The following routines constitute the bulk of the
hotplug controller logic
*/
@@ -212,7 +233,8 @@ static int board_added(struct slot *p_slot)
if (retval) {
ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n",
pci_domain_nr(parent), parent->number);
- goto err_exit;
+ if (retval != -EEXIST)
+ goto err_exit;
}
pciehp_green_led_on(p_slot);
@@ -255,6 +277,9 @@ static int remove_board(struct slot *p_slot)
struct power_work_info {
struct slot *p_slot;
struct work_struct work;
+ unsigned int req;
+#define DISABLE_REQ 0
+#define ENABLE_REQ 1
};
/**
@@ -269,30 +294,38 @@ static void pciehp_power_thread(struct work_struct *work)
struct power_work_info *info =
container_of(work, struct power_work_info, work);
struct slot *p_slot = info->p_slot;
+ int ret;
- mutex_lock(&p_slot->lock);
- switch (p_slot->state) {
- case POWEROFF_STATE:
- mutex_unlock(&p_slot->lock);
+ switch (info->req) {
+ case DISABLE_REQ:
ctrl_dbg(p_slot->ctrl,
"Disabling domain:bus:device=%04x:%02x:00\n",
pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
p_slot->ctrl->pcie->port->subordinate->number);
+ mutex_lock(&p_slot->hotplug_lock);
pciehp_disable_slot(p_slot);
+ mutex_unlock(&p_slot->hotplug_lock);
mutex_lock(&p_slot->lock);
p_slot->state = STATIC_STATE;
- break;
- case POWERON_STATE:
mutex_unlock(&p_slot->lock);
- if (pciehp_enable_slot(p_slot))
+ break;
+ case ENABLE_REQ:
+ ctrl_dbg(p_slot->ctrl,
+ "Enabling domain:bus:device=%04x:%02x:00\n",
+ pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
+ p_slot->ctrl->pcie->port->subordinate->number);
+ mutex_lock(&p_slot->hotplug_lock);
+ ret = pciehp_enable_slot(p_slot);
+ mutex_unlock(&p_slot->hotplug_lock);
+ if (ret)
pciehp_green_led_off(p_slot);
mutex_lock(&p_slot->lock);
p_slot->state = STATIC_STATE;
+ mutex_unlock(&p_slot->lock);
break;
default:
break;
}
- mutex_unlock(&p_slot->lock);
kfree(info);
}
@@ -315,9 +348,11 @@ void pciehp_queue_pushbutton_work(struct work_struct *work)
switch (p_slot->state) {
case BLINKINGOFF_STATE:
p_slot->state = POWEROFF_STATE;
+ info->req = DISABLE_REQ;
break;
case BLINKINGON_STATE:
p_slot->state = POWERON_STATE;
+ info->req = ENABLE_REQ;
break;
default:
kfree(info);
@@ -364,11 +399,10 @@ static void handle_button_press_event(struct slot *p_slot)
*/
ctrl_info(ctrl, "Button cancel on Slot(%s)\n", slot_name(p_slot));
cancel_delayed_work(&p_slot->work);
- if (p_slot->state == BLINKINGOFF_STATE) {
+ if (p_slot->state == BLINKINGOFF_STATE)
pciehp_green_led_on(p_slot);
- } else {
+ else
pciehp_green_led_off(p_slot);
- }
pciehp_set_attention_status(p_slot, 0);
ctrl_info(ctrl, "PCI slot #%s - action canceled "
"due to button press\n", slot_name(p_slot));
@@ -407,14 +441,81 @@ static void handle_surprise_event(struct slot *p_slot)
INIT_WORK(&info->work, pciehp_power_thread);
pciehp_get_adapter_status(p_slot, &getstatus);
- if (!getstatus)
+ if (!getstatus) {
p_slot->state = POWEROFF_STATE;
- else
+ info->req = DISABLE_REQ;
+ } else {
p_slot->state = POWERON_STATE;
+ info->req = ENABLE_REQ;
+ }
queue_work(p_slot->wq, &info->work);
}
+/*
+ * Note: This function must be called with slot->lock held
+ */
+static void handle_link_event(struct slot *p_slot, u32 event)
+{
+ struct controller *ctrl = p_slot->ctrl;
+ struct power_work_info *info;
+
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n",
+ __func__);
+ return;
+ }
+ info->p_slot = p_slot;
+ info->req = event == INT_LINK_UP ? ENABLE_REQ : DISABLE_REQ;
+ INIT_WORK(&info->work, pciehp_power_thread);
+
+ switch (p_slot->state) {
+ case BLINKINGON_STATE:
+ case BLINKINGOFF_STATE:
+ cancel_delayed_work(&p_slot->work);
+ /* Fall through */
+ case STATIC_STATE:
+ p_slot->state = event == INT_LINK_UP ?
+ POWERON_STATE : POWEROFF_STATE;
+ queue_work(p_slot->wq, &info->work);
+ break;
+ case POWERON_STATE:
+ if (event == INT_LINK_UP) {
+ ctrl_info(ctrl,
+ "Link Up event ignored on slot(%s): already powering on\n",
+ slot_name(p_slot));
+ kfree(info);
+ } else {
+ ctrl_info(ctrl,
+ "Link Down event queued on slot(%s): currently getting powered on\n",
+ slot_name(p_slot));
+ p_slot->state = POWEROFF_STATE;
+ queue_work(p_slot->wq, &info->work);
+ }
+ break;
+ case POWEROFF_STATE:
+ if (event == INT_LINK_UP) {
+ ctrl_info(ctrl,
+ "Link Up event queued on slot(%s): currently getting powered off\n",
+ slot_name(p_slot));
+ p_slot->state = POWERON_STATE;
+ queue_work(p_slot->wq, &info->work);
+ } else {
+ ctrl_info(ctrl,
+ "Link Down event ignored on slot(%s): already powering off\n",
+ slot_name(p_slot));
+ kfree(info);
+ }
+ break;
+ default:
+ ctrl_err(ctrl, "Not a valid state on slot(%s)\n",
+ slot_name(p_slot));
+ kfree(info);
+ break;
+ }
+}
+
static void interrupt_event_handler(struct work_struct *work)
{
struct event_info *info = container_of(work, struct event_info, work);
@@ -433,12 +534,23 @@ static void interrupt_event_handler(struct work_struct *work)
pciehp_green_led_off(p_slot);
break;
case INT_PRESENCE_ON:
- case INT_PRESENCE_OFF:
if (!HP_SUPR_RM(ctrl))
break;
+ ctrl_dbg(ctrl, "Surprise Insertion\n");
+ handle_surprise_event(p_slot);
+ break;
+ case INT_PRESENCE_OFF:
+ /*
+ * Regardless of surprise capability, we need to
+ * definitely remove a card that has been pulled out!
+ */
ctrl_dbg(ctrl, "Surprise Removal\n");
handle_surprise_event(p_slot);
break;
+ case INT_LINK_UP:
+ case INT_LINK_DOWN:
+ handle_link_event(p_slot, info->event_type);
+ break;
default:
break;
}
@@ -447,6 +559,9 @@ static void interrupt_event_handler(struct work_struct *work)
kfree(info);
}
+/*
+ * Note: This function must be called with slot->hotplug_lock held
+ */
int pciehp_enable_slot(struct slot *p_slot)
{
u8 getstatus = 0;
@@ -479,13 +594,15 @@ int pciehp_enable_slot(struct slot *p_slot)
pciehp_get_latch_status(p_slot, &getstatus);
rc = board_added(p_slot);
- if (rc) {
+ if (rc)
pciehp_get_latch_status(p_slot, &getstatus);
- }
+
return rc;
}
-
+/*
+ * Note: This function must be called with slot->hotplug_lock held
+ */
int pciehp_disable_slot(struct slot *p_slot)
{
u8 getstatus = 0;
@@ -494,24 +611,6 @@ int pciehp_disable_slot(struct slot *p_slot)
if (!p_slot->ctrl)
return 1;
- if (!HP_SUPR_RM(p_slot->ctrl)) {
- pciehp_get_adapter_status(p_slot, &getstatus);
- if (!getstatus) {
- ctrl_info(ctrl, "No adapter on slot(%s)\n",
- slot_name(p_slot));
- return -ENODEV;
- }
- }
-
- if (MRL_SENS(p_slot->ctrl)) {
- pciehp_get_latch_status(p_slot, &getstatus);
- if (getstatus) {
- ctrl_info(ctrl, "Latch open on slot(%s)\n",
- slot_name(p_slot));
- return -ENODEV;
- }
- }
-
if (POWER_CTRL(p_slot->ctrl)) {
pciehp_get_power_status(p_slot, &getstatus);
if (!getstatus) {
@@ -536,7 +635,9 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot)
case STATIC_STATE:
p_slot->state = POWERON_STATE;
mutex_unlock(&p_slot->lock);
+ mutex_lock(&p_slot->hotplug_lock);
retval = pciehp_enable_slot(p_slot);
+ mutex_unlock(&p_slot->hotplug_lock);
mutex_lock(&p_slot->lock);
p_slot->state = STATIC_STATE;
break;
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 14acfccb7670..d7d058fa19a4 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -206,7 +206,7 @@ static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
mutex_unlock(&ctrl->ctrl_lock);
}
-static bool check_link_active(struct controller *ctrl)
+bool pciehp_check_link_active(struct controller *ctrl)
{
struct pci_dev *pdev = ctrl_dev(ctrl);
u16 lnk_status;
@@ -225,12 +225,12 @@ static void __pcie_wait_link_active(struct controller *ctrl, bool active)
{
int timeout = 1000;
- if (check_link_active(ctrl) == active)
+ if (pciehp_check_link_active(ctrl) == active)
return;
while (timeout > 0) {
msleep(10);
timeout -= 10;
- if (check_link_active(ctrl) == active)
+ if (pciehp_check_link_active(ctrl) == active)
return;
}
ctrl_dbg(ctrl, "Data Link Layer Link Active not %s in 1000 msec\n",
@@ -242,11 +242,6 @@ static void pcie_wait_link_active(struct controller *ctrl)
__pcie_wait_link_active(ctrl, true);
}
-static void pcie_wait_link_not_active(struct controller *ctrl)
-{
- __pcie_wait_link_active(ctrl, false);
-}
-
static bool pci_bus_check_dev(struct pci_bus *bus, int devfn)
{
u32 l;
@@ -332,11 +327,6 @@ static int pciehp_link_enable(struct controller *ctrl)
return __pciehp_link_set(ctrl, true);
}
-static int pciehp_link_disable(struct controller *ctrl)
-{
- return __pciehp_link_set(ctrl, false);
-}
-
void pciehp_get_attention_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
@@ -508,14 +498,6 @@ void pciehp_power_off_slot(struct slot * slot)
{
struct controller *ctrl = slot->ctrl;
- /* Disable the link at first */
- pciehp_link_disable(ctrl);
- /* wait the link is down */
- if (ctrl->link_active_reporting)
- pcie_wait_link_not_active(ctrl);
- else
- msleep(1000);
-
pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_OFF, PCI_EXP_SLTCTL_PCC);
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
@@ -540,7 +522,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC |
- PCI_EXP_SLTSTA_CC);
+ PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC);
detected &= ~intr_loc;
intr_loc |= detected;
if (!intr_loc)
@@ -579,6 +561,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
ctrl->power_fault_detected = 1;
pciehp_handle_power_fault(slot);
}
+
+ if (intr_loc & PCI_EXP_SLTSTA_DLLSC)
+ pciehp_handle_linkstate_change(slot);
+
return IRQ_HANDLED;
}
@@ -596,9 +582,17 @@ void pcie_enable_notification(struct controller *ctrl)
* when it is cleared in the interrupt service routine, and
* next power fault detected interrupt was notified again.
*/
- cmd = PCI_EXP_SLTCTL_PDCE;
+
+ /*
+ * Always enable link events: thus link-up and link-down shall
+ * always be treated as hotplug and unplug respectively. Enable
+ * presence detect only if Attention Button is not present.
+ */
+ cmd = PCI_EXP_SLTCTL_DLLSCE;
if (ATTN_BUTTN(ctrl))
cmd |= PCI_EXP_SLTCTL_ABPE;
+ else
+ cmd |= PCI_EXP_SLTCTL_PDCE;
if (MRL_SENS(ctrl))
cmd |= PCI_EXP_SLTCTL_MRLSCE;
if (!pciehp_poll_mode)
@@ -606,7 +600,8 @@ void pcie_enable_notification(struct controller *ctrl)
mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE |
PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE |
- PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE);
+ PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE |
+ PCI_EXP_SLTCTL_DLLSCE);
pcie_write_cmd(ctrl, cmd, mask);
}
@@ -624,33 +619,38 @@ static void pcie_disable_notification(struct controller *ctrl)
/*
* pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary
- * bus reset of the bridge, but if the slot supports surprise removal we need
- * to disable presence detection around the bus reset and clear any spurious
+ * bus reset of the bridge, but at the same time we want to ensure that it is
+ * not seen as a hot-unplug, followed by the hot-plug of the device. Thus,
+ * disable link state notification and presence detection change notification
+ * momentarily, if we see that they could interfere. Also, clear any spurious
* events after.
*/
int pciehp_reset_slot(struct slot *slot, int probe)
{
struct controller *ctrl = slot->ctrl;
struct pci_dev *pdev = ctrl_dev(ctrl);
+ u16 stat_mask = 0, ctrl_mask = 0;
if (probe)
return 0;
- if (HP_SUPR_RM(ctrl)) {
- pcie_write_cmd(ctrl, 0, PCI_EXP_SLTCTL_PDCE);
- if (pciehp_poll_mode)
- del_timer_sync(&ctrl->poll_timer);
+ if (!ATTN_BUTTN(ctrl)) {
+ ctrl_mask |= PCI_EXP_SLTCTL_PDCE;
+ stat_mask |= PCI_EXP_SLTSTA_PDC;
}
+ ctrl_mask |= PCI_EXP_SLTCTL_DLLSCE;
+ stat_mask |= PCI_EXP_SLTSTA_DLLSC;
+
+ pcie_write_cmd(ctrl, 0, ctrl_mask);
+ if (pciehp_poll_mode)
+ del_timer_sync(&ctrl->poll_timer);
pci_reset_bridge_secondary_bus(ctrl->pcie->port);
- if (HP_SUPR_RM(ctrl)) {
- pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
- PCI_EXP_SLTSTA_PDC);
- pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PDCE, PCI_EXP_SLTCTL_PDCE);
- if (pciehp_poll_mode)
- int_poll_timeout(ctrl->poll_timer.data);
- }
+ pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, stat_mask);
+ pcie_write_cmd(ctrl, ctrl_mask, ctrl_mask);
+ if (pciehp_poll_mode)
+ int_poll_timeout(ctrl->poll_timer.data);
return 0;
}
@@ -687,6 +687,7 @@ static int pcie_init_slot(struct controller *ctrl)
slot->ctrl = ctrl;
mutex_init(&slot->lock);
+ mutex_init(&slot->hotplug_lock);
INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
ctrl->slot = slot;
return 0;
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index b07d7cc2d697..1b533060ce65 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -50,7 +50,7 @@ int pciehp_configure_device(struct slot *p_slot)
"at %04x:%02x:00, cannot hot-add\n", pci_name(dev),
pci_domain_nr(parent), parent->number);
pci_dev_put(dev);
- ret = -EINVAL;
+ ret = -EEXIST;
goto out;
}
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 9dce7c5e2a77..de7a74782f92 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -170,97 +170,6 @@ static void virtfn_remove(struct pci_dev *dev, int id, int reset)
pci_dev_put(dev);
}
-static int sriov_migration(struct pci_dev *dev)
-{
- u16 status;
- struct pci_sriov *iov = dev->sriov;
-
- if (!iov->num_VFs)
- return 0;
-
- if (!(iov->cap & PCI_SRIOV_CAP_VFM))
- return 0;
-
- pci_read_config_word(dev, iov->pos + PCI_SRIOV_STATUS, &status);
- if (!(status & PCI_SRIOV_STATUS_VFM))
- return 0;
-
- schedule_work(&iov->mtask);
-
- return 1;
-}
-
-static void sriov_migration_task(struct work_struct *work)
-{
- int i;
- u8 state;
- u16 status;
- struct pci_sriov *iov = container_of(work, struct pci_sriov, mtask);
-
- for (i = iov->initial_VFs; i < iov->num_VFs; i++) {
- state = readb(iov->mstate + i);
- if (state == PCI_SRIOV_VFM_MI) {
- writeb(PCI_SRIOV_VFM_AV, iov->mstate + i);
- state = readb(iov->mstate + i);
- if (state == PCI_SRIOV_VFM_AV)
- virtfn_add(iov->self, i, 1);
- } else if (state == PCI_SRIOV_VFM_MO) {
- virtfn_remove(iov->self, i, 1);
- writeb(PCI_SRIOV_VFM_UA, iov->mstate + i);
- state = readb(iov->mstate + i);
- if (state == PCI_SRIOV_VFM_AV)
- virtfn_add(iov->self, i, 0);
- }
- }
-
- pci_read_config_word(iov->self, iov->pos + PCI_SRIOV_STATUS, &status);
- status &= ~PCI_SRIOV_STATUS_VFM;
- pci_write_config_word(iov->self, iov->pos + PCI_SRIOV_STATUS, status);
-}
-
-static int sriov_enable_migration(struct pci_dev *dev, int nr_virtfn)
-{
- int bir;
- u32 table;
- resource_size_t pa;
- struct pci_sriov *iov = dev->sriov;
-
- if (nr_virtfn <= iov->initial_VFs)
- return 0;
-
- pci_read_config_dword(dev, iov->pos + PCI_SRIOV_VFM, &table);
- bir = PCI_SRIOV_VFM_BIR(table);
- if (bir > PCI_STD_RESOURCE_END)
- return -EIO;
-
- table = PCI_SRIOV_VFM_OFFSET(table);
- if (table + nr_virtfn > pci_resource_len(dev, bir))
- return -EIO;
-
- pa = pci_resource_start(dev, bir) + table;
- iov->mstate = ioremap(pa, nr_virtfn);
- if (!iov->mstate)
- return -ENOMEM;
-
- INIT_WORK(&iov->mtask, sriov_migration_task);
-
- iov->ctrl |= PCI_SRIOV_CTRL_VFM | PCI_SRIOV_CTRL_INTR;
- pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
-
- return 0;
-}
-
-static void sriov_disable_migration(struct pci_dev *dev)
-{
- struct pci_sriov *iov = dev->sriov;
-
- iov->ctrl &= ~(PCI_SRIOV_CTRL_VFM | PCI_SRIOV_CTRL_INTR);
- pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
-
- cancel_work_sync(&iov->mtask);
- iounmap(iov->mstate);
-}
-
static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
{
int rc;
@@ -351,12 +260,6 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
goto failed;
}
- if (iov->cap & PCI_SRIOV_CAP_VFM) {
- rc = sriov_enable_migration(dev, nr_virtfn);
- if (rc)
- goto failed;
- }
-
kobject_uevent(&dev->dev.kobj, KOBJ_CHANGE);
iov->num_VFs = nr_virtfn;
@@ -387,9 +290,6 @@ static void sriov_disable(struct pci_dev *dev)
if (!iov->num_VFs)
return;
- if (iov->cap & PCI_SRIOV_CAP_VFM)
- sriov_disable_migration(dev);
-
for (i = 0; i < iov->num_VFs; i++)
virtfn_remove(dev, i, 0);
@@ -688,25 +588,6 @@ void pci_disable_sriov(struct pci_dev *dev)
EXPORT_SYMBOL_GPL(pci_disable_sriov);
/**
- * pci_sriov_migration - notify SR-IOV core of Virtual Function Migration
- * @dev: the PCI device
- *
- * Returns IRQ_HANDLED if the IRQ is handled, or IRQ_NONE if not.
- *
- * Physical Function driver is responsible to register IRQ handler using
- * VF Migration Interrupt Message Number, and call this function when the
- * interrupt is generated by the hardware.
- */
-irqreturn_t pci_sriov_migration(struct pci_dev *dev)
-{
- if (!dev->is_physfn)
- return IRQ_NONE;
-
- return sriov_migration(dev) ? IRQ_HANDLED : IRQ_NONE;
-}
-EXPORT_SYMBOL_GPL(pci_sriov_migration);
-
-/**
* pci_num_vf - return number of VFs associated with a PF device_release_driver
* @dev: the PCI device
*
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 7a0fec6ce571..955ab7990c5b 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -545,9 +545,15 @@ static int populate_msi_sysfs(struct pci_dev *pdev)
return -ENOMEM;
list_for_each_entry(entry, &pdev->msi_list, list) {
char *name = kmalloc(20, GFP_KERNEL);
+ if (!name)
+ goto error_attrs;
+
msi_dev_attr = kzalloc(sizeof(*msi_dev_attr), GFP_KERNEL);
- if (!msi_dev_attr)
+ if (!msi_dev_attr) {
+ kfree(name);
goto error_attrs;
+ }
+
sprintf(name, "%d", entry->irq);
sysfs_attr_init(&msi_dev_attr->attr);
msi_dev_attr->attr.name = name;
@@ -589,6 +595,7 @@ error_attrs:
++count;
msi_attr = msi_attrs[count];
}
+ kfree(msi_attrs);
return ret;
}
@@ -959,7 +966,6 @@ EXPORT_SYMBOL(pci_disable_msi);
/**
* pci_msix_vec_count - return the number of device's MSI-X table entries
* @dev: pointer to the pci_dev data structure of MSI-X device function
-
* This function returns the number of device's MSI-X table entries and
* therefore the number of MSI-X vectors device is capable of sending.
* It returns a negative errno if the device is not capable of sending MSI-X
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 25f0bc659164..d911e0c1f359 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -616,15 +616,11 @@ static int pci_pm_prepare(struct device *dev)
int error = 0;
/*
- * PCI devices suspended at run time need to be resumed at this
- * point, because in general it is necessary to reconfigure them for
- * system suspend. Namely, if the device is supposed to wake up the
- * system from the sleep state, we may need to reconfigure it for this
- * purpose. In turn, if the device is not supposed to wake up the
- * system from the sleep state, we'll have to prevent it from signaling
- * wake-up.
+ * Devices having power.ignore_children set may still be necessary for
+ * suspending their children in the next phase of device suspend.
*/
- pm_runtime_resume(dev);
+ if (dev->power.ignore_children)
+ pm_runtime_resume(dev);
if (drv && drv->pm && drv->pm->prepare)
error = drv->pm->prepare(dev);
@@ -654,6 +650,16 @@ static int pci_pm_suspend(struct device *dev)
goto Fixup;
}
+ /*
+ * PCI devices suspended at run time need to be resumed at this point,
+ * because in general it is necessary to reconfigure them for system
+ * suspend. Namely, if the device is supposed to wake up the system
+ * from the sleep state, we may need to reconfigure it for this purpose.
+ * In turn, if the device is not supposed to wake up the system from the
+ * sleep state, we'll have to prevent it from signaling wake-up.
+ */
+ pm_runtime_resume(dev);
+
pci_dev->state_saved = false;
if (pm->suspend) {
pci_power_t prev = pci_dev->current_state;
@@ -808,6 +814,14 @@ static int pci_pm_freeze(struct device *dev)
return 0;
}
+ /*
+ * This used to be done in pci_pm_prepare() for all devices and some
+ * drivers may depend on it, so do it here. Ideally, runtime-suspended
+ * devices should not be touched during freeze/thaw transitions,
+ * however.
+ */
+ pm_runtime_resume(dev);
+
pci_dev->state_saved = false;
if (pm->freeze) {
int error;
@@ -915,6 +929,9 @@ static int pci_pm_poweroff(struct device *dev)
goto Fixup;
}
+ /* The reason to do that is the same as in pci_pm_suspend(). */
+ pm_runtime_resume(dev);
+
pci_dev->state_saved = false;
if (pm->poweroff) {
int error;
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 276ef9c18802..4e0acefb7565 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -351,28 +351,17 @@ static struct device_attribute dev_rescan_attr = __ATTR(rescan,
(S_IWUSR|S_IWGRP),
NULL, dev_rescan_store);
-static void remove_callback(struct device *dev)
-{
- pci_stop_and_remove_bus_device_locked(to_pci_dev(dev));
-}
-
static ssize_t
-remove_store(struct device *dev, struct device_attribute *dummy,
+remove_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- int ret = 0;
unsigned long val;
if (kstrtoul(buf, 0, &val) < 0)
return -EINVAL;
- /* An attribute cannot be unregistered by one of its own methods,
- * so we have to use this roundabout approach.
- */
- if (val)
- ret = device_schedule_callback(dev, remove_callback);
- if (ret)
- count = ret;
+ if (val && device_remove_file_self(dev, attr))
+ pci_stop_and_remove_bus_device_locked(to_pci_dev(dev));
return count;
}
static struct device_attribute dev_remove_attr = __ATTR(remove,
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 1febe90831b4..7325d43bf030 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -108,12 +108,12 @@ static bool pcie_ari_disabled;
*/
unsigned char pci_bus_max_busnr(struct pci_bus* bus)
{
- struct list_head *tmp;
+ struct pci_bus *tmp;
unsigned char max, n;
max = bus->busn_res.end;
- list_for_each(tmp, &bus->children) {
- n = pci_bus_max_busnr(pci_bus_b(tmp));
+ list_for_each_entry(tmp, &bus->children, node) {
+ n = pci_bus_max_busnr(tmp);
if(n > max)
max = n;
}
@@ -401,33 +401,40 @@ EXPORT_SYMBOL_GPL(pci_find_ht_capability);
* @res: child resource record for which parent is sought
*
* For given resource region of given device, return the resource
- * region of parent bus the given region is contained in or where
- * it should be allocated from.
+ * region of parent bus the given region is contained in.
*/
struct resource *
pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
{
const struct pci_bus *bus = dev->bus;
+ struct resource *r;
int i;
- struct resource *best = NULL, *r;
pci_bus_for_each_resource(bus, r, i) {
if (!r)
continue;
- if (res->start && !(res->start >= r->start && res->end <= r->end))
- continue; /* Not contained */
- if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM))
- continue; /* Wrong type */
- if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH))
- return r; /* Exact match */
- /* We can't insert a non-prefetch resource inside a prefetchable parent .. */
- if (r->flags & IORESOURCE_PREFETCH)
- continue;
- /* .. but we can put a prefetchable resource inside a non-prefetchable one */
- if (!best)
- best = r;
+ if (res->start && resource_contains(r, res)) {
+
+ /*
+ * If the window is prefetchable but the BAR is
+ * not, the allocator made a mistake.
+ */
+ if (r->flags & IORESOURCE_PREFETCH &&
+ !(res->flags & IORESOURCE_PREFETCH))
+ return NULL;
+
+ /*
+ * If we're below a transparent bridge, there may
+ * be both a positively-decoded aperture and a
+ * subtractively-decoded region that contain the BAR.
+ * We want the positively-decoded one, so this depends
+ * on pci_bus_for_each_resource() giving us those
+ * first.
+ */
+ return r;
+ }
}
- return best;
+ return NULL;
}
/**
@@ -1178,9 +1185,16 @@ int pci_load_and_free_saved_state(struct pci_dev *dev,
}
EXPORT_SYMBOL_GPL(pci_load_and_free_saved_state);
+int __weak pcibios_enable_device(struct pci_dev *dev, int bars)
+{
+ return pci_enable_resources(dev, bars);
+}
+
static int do_pci_enable_device(struct pci_dev *dev, int bars)
{
int err;
+ u16 cmd;
+ u8 pin;
err = pci_set_power_state(dev, PCI_D0);
if (err < 0 && err != -EIO)
@@ -1190,6 +1204,17 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars)
return err;
pci_fixup_device(pci_fixup_enable, dev);
+ if (dev->msi_enabled || dev->msix_enabled)
+ return 0;
+
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ if (pin) {
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ if (cmd & PCI_COMMAND_INTX_DISABLE)
+ pci_write_config_word(dev, PCI_COMMAND,
+ cmd & ~PCI_COMMAND_INTX_DISABLE);
+ }
+
return 0;
}
@@ -1611,29 +1636,27 @@ static void pci_pme_list_scan(struct work_struct *work)
struct pci_pme_device *pme_dev, *n;
mutex_lock(&pci_pme_list_mutex);
- if (!list_empty(&pci_pme_list)) {
- list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) {
- if (pme_dev->dev->pme_poll) {
- struct pci_dev *bridge;
-
- bridge = pme_dev->dev->bus->self;
- /*
- * If bridge is in low power state, the
- * configuration space of subordinate devices
- * may be not accessible
- */
- if (bridge && bridge->current_state != PCI_D0)
- continue;
- pci_pme_wakeup(pme_dev->dev, NULL);
- } else {
- list_del(&pme_dev->list);
- kfree(pme_dev);
- }
+ list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) {
+ if (pme_dev->dev->pme_poll) {
+ struct pci_dev *bridge;
+
+ bridge = pme_dev->dev->bus->self;
+ /*
+ * If bridge is in low power state, the
+ * configuration space of subordinate devices
+ * may be not accessible
+ */
+ if (bridge && bridge->current_state != PCI_D0)
+ continue;
+ pci_pme_wakeup(pme_dev->dev, NULL);
+ } else {
+ list_del(&pme_dev->list);
+ kfree(pme_dev);
}
- if (!list_empty(&pci_pme_list))
- schedule_delayed_work(&pci_pme_work,
- msecs_to_jiffies(PME_TIMEOUT));
}
+ if (!list_empty(&pci_pme_list))
+ schedule_delayed_work(&pci_pme_work,
+ msecs_to_jiffies(PME_TIMEOUT));
mutex_unlock(&pci_pme_list_mutex);
}
@@ -2180,21 +2203,18 @@ void pci_request_acs(void)
}
/**
- * pci_enable_acs - enable ACS if hardware support it
+ * pci_std_enable_acs - enable ACS on devices using standard ACS capabilites
* @dev: the PCI device
*/
-void pci_enable_acs(struct pci_dev *dev)
+static int pci_std_enable_acs(struct pci_dev *dev)
{
int pos;
u16 cap;
u16 ctrl;
- if (!pci_acs_enable)
- return;
-
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
if (!pos)
- return;
+ return -ENODEV;
pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap);
pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
@@ -2212,6 +2232,23 @@ void pci_enable_acs(struct pci_dev *dev)
ctrl |= (cap & PCI_ACS_UF);
pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
+
+ return 0;
+}
+
+/**
+ * pci_enable_acs - enable ACS if hardware support it
+ * @dev: the PCI device
+ */
+void pci_enable_acs(struct pci_dev *dev)
+{
+ if (!pci_acs_enable)
+ return;
+
+ if (!pci_std_enable_acs(dev))
+ return;
+
+ pci_dev_specific_enable_acs(dev);
}
static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
@@ -4237,6 +4274,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
"Rounding up size of resource #%d to %#llx.\n",
i, (unsigned long long)size);
}
+ r->flags |= IORESOURCE_UNSET;
r->end = size - 1;
r->start = 0;
}
@@ -4250,6 +4288,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
r = &dev->resource[i];
if (!(r->flags & IORESOURCE_MEM))
continue;
+ r->flags |= IORESOURCE_UNSET;
r->end = resource_size(r) - 1;
r->start = 0;
}
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 4df38df224f4..6bd082299e31 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1,8 +1,6 @@
#ifndef DRIVERS_PCI_H
#define DRIVERS_PCI_H
-#include <linux/workqueue.h>
-
#define PCI_CFG_SPACE_SIZE 256
#define PCI_CFG_SPACE_EXP_SIZE 4096
@@ -240,8 +238,6 @@ struct pci_sriov {
struct pci_dev *dev; /* lowest numbered PF */
struct pci_dev *self; /* this PF */
struct mutex lock; /* lock for VF bus */
- struct work_struct mtask; /* VF Migration task */
- u8 __iomem *mstate; /* VF Migration State Array */
};
#ifdef CONFIG_PCI_ATS
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 6e34498ec9f0..ef09f5f2fe6c 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -252,6 +252,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
/* Address above 32-bit boundary; disable the BAR */
pci_write_config_dword(dev, pos, 0);
pci_write_config_dword(dev, pos + 4, 0);
+ res->flags |= IORESOURCE_UNSET;
region.start = 0;
region.end = sz64;
bar_disabled = true;
@@ -731,22 +732,6 @@ struct pci_bus *__ref pci_add_new_bus(struct pci_bus *parent, struct pci_dev *de
return child;
}
-static void pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max)
-{
- struct pci_bus *parent = child->parent;
-
- /* Attempts to fix that up are really dangerous unless
- we're going to re-assign all bus numbers. */
- if (!pcibios_assign_all_busses())
- return;
-
- while (parent->parent && parent->busn_res.end < max) {
- parent->busn_res.end = max;
- pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, max);
- parent = parent->parent;
- }
-}
-
/*
* If it's a bridge, configure it and scan the bus behind it.
* For CardBus bridges, we don't scan behind as the devices will
@@ -782,7 +767,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
/* Check if setup is sensible at all */
if (!pass &&
(primary != bus->number || secondary <= bus->number ||
- secondary > subordinate)) {
+ secondary > subordinate || subordinate > bus->busn_res.end)) {
dev_info(&dev->dev, "bridge configuration invalid ([bus %02x-%02x]), reconfiguring\n",
secondary, subordinate);
broken = 1;
@@ -805,11 +790,10 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
goto out;
/*
- * If we already got to this bus through a different bridge,
- * don't re-add it. This can happen with the i450NX chipset.
- *
- * However, we continue to descend down the hierarchy and
- * scan remaining child buses.
+ * The bus might already exist for two reasons: Either we are
+ * rescanning the bus or the bus is reachable through more than
+ * one bridge. The second case can happen with the i450NX
+ * chipset.
*/
child = pci_find_bus(pci_domain_nr(bus), secondary);
if (!child) {
@@ -822,17 +806,19 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
}
cmax = pci_scan_child_bus(child);
- if (cmax > max)
- max = cmax;
- if (child->busn_res.end > max)
- max = child->busn_res.end;
+ if (cmax > subordinate)
+ dev_warn(&dev->dev, "bridge has subordinate %02x but max busn %02x\n",
+ subordinate, cmax);
+ /* subordinate should equal child->busn_res.end */
+ if (subordinate > max)
+ max = subordinate;
} else {
/*
* We need to assign a number to this bus which we always
* do in the second pass.
*/
if (!pass) {
- if (pcibios_assign_all_busses() || broken)
+ if (pcibios_assign_all_busses() || broken || is_cardbus)
/* Temporarily disable forwarding of the
configuration cycles on all bridges in
this bus segment to avoid possible
@@ -844,19 +830,25 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
goto out;
}
+ if (max >= bus->busn_res.end) {
+ dev_warn(&dev->dev, "can't allocate child bus %02x from %pR\n",
+ max, &bus->busn_res);
+ goto out;
+ }
+
/* Clear errors */
pci_write_config_word(dev, PCI_STATUS, 0xffff);
- /* Prevent assigning a bus number that already exists.
- * This can happen when a bridge is hot-plugged, so in
- * this case we only re-scan this bus. */
+ /* The bus will already exist if we are rescanning */
child = pci_find_bus(pci_domain_nr(bus), max+1);
if (!child) {
- child = pci_add_new_bus(bus, dev, ++max);
+ child = pci_add_new_bus(bus, dev, max+1);
if (!child)
goto out;
- pci_bus_insert_busn_res(child, max, 0xff);
+ pci_bus_insert_busn_res(child, max+1,
+ bus->busn_res.end);
}
+ max++;
buses = (buses & 0xff000000)
| ((unsigned int)(child->primary) << 0)
| ((unsigned int)(child->busn_res.start) << 8)
@@ -878,20 +870,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
if (!is_cardbus) {
child->bridge_ctl = bctl;
- /*
- * Adjust subordinate busnr in parent buses.
- * We do this before scanning for children because
- * some devices may not be detected if the bios
- * was lazy.
- */
- pci_fixup_parent_subordinate_busnr(child, max);
- /* Now we can scan all subordinate buses... */
max = pci_scan_child_bus(child);
- /*
- * now fix it up again since we have found
- * the real value of max.
- */
- pci_fixup_parent_subordinate_busnr(child, max);
} else {
/*
* For CardBus bridges, we leave 4 bus numbers
@@ -922,11 +901,15 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
}
}
max += i;
- pci_fixup_parent_subordinate_busnr(child, max);
}
/*
* Set the subordinate bus number to its real value.
*/
+ if (max > bus->busn_res.end) {
+ dev_warn(&dev->dev, "max busn %02x is outside %pR\n",
+ max, &bus->busn_res);
+ max = bus->busn_res.end;
+ }
pci_bus_update_busn_res_end(child, max);
pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
}
@@ -1125,10 +1108,10 @@ int pci_setup_device(struct pci_dev *dev)
pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device);
/*
- * Do the ugly legacy mode stuff here rather than broken chip
- * quirk code. Legacy mode ATA controllers have fixed
- * addresses. These are not always echoed in BAR0-3, and
- * BAR0-3 in a few cases contain junk!
+ * Do the ugly legacy mode stuff here rather than broken chip
+ * quirk code. Legacy mode ATA controllers have fixed
+ * addresses. These are not always echoed in BAR0-3, and
+ * BAR0-3 in a few cases contain junk!
*/
if (class == PCI_CLASS_STORAGE_IDE) {
u8 progif;
@@ -1139,11 +1122,15 @@ int pci_setup_device(struct pci_dev *dev)
res = &dev->resource[0];
res->flags = LEGACY_IO_RESOURCE;
pcibios_bus_to_resource(dev->bus, res, &region);
+ dev_info(&dev->dev, "legacy IDE quirk: reg 0x10: %pR\n",
+ res);
region.start = 0x3F6;
region.end = 0x3F6;
res = &dev->resource[1];
res->flags = LEGACY_IO_RESOURCE;
pcibios_bus_to_resource(dev->bus, res, &region);
+ dev_info(&dev->dev, "legacy IDE quirk: reg 0x14: %pR\n",
+ res);
}
if ((progif & 4) == 0) {
region.start = 0x170;
@@ -1151,11 +1138,15 @@ int pci_setup_device(struct pci_dev *dev)
res = &dev->resource[2];
res->flags = LEGACY_IO_RESOURCE;
pcibios_bus_to_resource(dev->bus, res, &region);
+ dev_info(&dev->dev, "legacy IDE quirk: reg 0x18: %pR\n",
+ res);
region.start = 0x376;
region.end = 0x376;
res = &dev->resource[3];
res->flags = LEGACY_IO_RESOURCE;
pcibios_bus_to_resource(dev->bus, res, &region);
+ dev_info(&dev->dev, "legacy IDE quirk: reg 0x1c: %pR\n",
+ res);
}
}
break;
@@ -1835,7 +1826,7 @@ int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max)
res->flags |= IORESOURCE_PCI_FIXED;
}
- conflict = insert_resource_conflict(parent_res, res);
+ conflict = request_resource_conflict(parent_res, res);
if (conflict)
dev_printk(KERN_DEBUG, &b->dev,
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 5cb726c193de..e7292065a1b1 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -296,6 +296,7 @@ static void quirk_s3_64M(struct pci_dev *dev)
struct resource *r = &dev->resource[0];
if ((r->start & 0x3ffffff) || r->end != r->start + 0x3ffffff) {
+ r->flags |= IORESOURCE_UNSET;
r->start = 0;
r->end = 0x3ffffff;
}
@@ -937,6 +938,8 @@ DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C
static void quirk_dunord(struct pci_dev *dev)
{
struct resource *r = &dev->resource [1];
+
+ r->flags |= IORESOURCE_UNSET;
r->start = 0;
r->end = 0xffffff;
}
@@ -1740,6 +1743,7 @@ static void quirk_tc86c001_ide(struct pci_dev *dev)
struct resource *r = &dev->resource[0];
if (r->start & 0x8) {
+ r->flags |= IORESOURCE_UNSET;
r->start = 0;
r->end = 0xf;
}
@@ -1769,6 +1773,7 @@ static void quirk_plx_pci9050(struct pci_dev *dev)
dev_info(&dev->dev,
"Re-allocating PLX PCI 9050 BAR %u to length 256 to avoid bit 7 bug\n",
bar);
+ r->flags |= IORESOURCE_UNSET;
r->start = 0;
r->end = 0xff;
}
@@ -3423,6 +3428,61 @@ static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags)
#endif
}
+/*
+ * Many Intel PCH root ports do provide ACS-like features to disable peer
+ * transactions and validate bus numbers in requests, but do not provide an
+ * actual PCIe ACS capability. This is the list of device IDs known to fall
+ * into that category as provided by Intel in Red Hat bugzilla 1037684.
+ */
+static const u16 pci_quirk_intel_pch_acs_ids[] = {
+ /* Ibexpeak PCH */
+ 0x3b42, 0x3b43, 0x3b44, 0x3b45, 0x3b46, 0x3b47, 0x3b48, 0x3b49,
+ 0x3b4a, 0x3b4b, 0x3b4c, 0x3b4d, 0x3b4e, 0x3b4f, 0x3b50, 0x3b51,
+ /* Cougarpoint PCH */
+ 0x1c10, 0x1c11, 0x1c12, 0x1c13, 0x1c14, 0x1c15, 0x1c16, 0x1c17,
+ 0x1c18, 0x1c19, 0x1c1a, 0x1c1b, 0x1c1c, 0x1c1d, 0x1c1e, 0x1c1f,
+ /* Pantherpoint PCH */
+ 0x1e10, 0x1e11, 0x1e12, 0x1e13, 0x1e14, 0x1e15, 0x1e16, 0x1e17,
+ 0x1e18, 0x1e19, 0x1e1a, 0x1e1b, 0x1e1c, 0x1e1d, 0x1e1e, 0x1e1f,
+ /* Lynxpoint-H PCH */
+ 0x8c10, 0x8c11, 0x8c12, 0x8c13, 0x8c14, 0x8c15, 0x8c16, 0x8c17,
+ 0x8c18, 0x8c19, 0x8c1a, 0x8c1b, 0x8c1c, 0x8c1d, 0x8c1e, 0x8c1f,
+ /* Lynxpoint-LP PCH */
+ 0x9c10, 0x9c11, 0x9c12, 0x9c13, 0x9c14, 0x9c15, 0x9c16, 0x9c17,
+ 0x9c18, 0x9c19, 0x9c1a, 0x9c1b,
+ /* Wildcat PCH */
+ 0x9c90, 0x9c91, 0x9c92, 0x9c93, 0x9c94, 0x9c95, 0x9c96, 0x9c97,
+ 0x9c98, 0x9c99, 0x9c9a, 0x9c9b,
+};
+
+static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev)
+{
+ int i;
+
+ /* Filter out a few obvious non-matches first */
+ if (!pci_is_pcie(dev) || pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT)
+ return false;
+
+ for (i = 0; i < ARRAY_SIZE(pci_quirk_intel_pch_acs_ids); i++)
+ if (pci_quirk_intel_pch_acs_ids[i] == dev->device)
+ return true;
+
+ return false;
+}
+
+#define INTEL_PCH_ACS_FLAGS (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_SV)
+
+static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags)
+{
+ u16 flags = dev->dev_flags & PCI_DEV_FLAGS_ACS_ENABLED_QUIRK ?
+ INTEL_PCH_ACS_FLAGS : 0;
+
+ if (!pci_quirk_intel_pch_acs_match(dev))
+ return -ENOTTY;
+
+ return acs_flags & ~flags ? 0 : 1;
+}
+
static const struct pci_dev_acs_enabled {
u16 vendor;
u16 device;
@@ -3434,6 +3494,7 @@ static const struct pci_dev_acs_enabled {
{ PCI_VENDOR_ID_ATI, 0x439d, pci_quirk_amd_sb_acs },
{ PCI_VENDOR_ID_ATI, 0x4384, pci_quirk_amd_sb_acs },
{ PCI_VENDOR_ID_ATI, 0x4399, pci_quirk_amd_sb_acs },
+ { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs },
{ 0 }
};
@@ -3461,3 +3522,132 @@ int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags)
return -ENOTTY;
}
+
+/* Config space offset of Root Complex Base Address register */
+#define INTEL_LPC_RCBA_REG 0xf0
+/* 31:14 RCBA address */
+#define INTEL_LPC_RCBA_MASK 0xffffc000
+/* RCBA Enable */
+#define INTEL_LPC_RCBA_ENABLE (1 << 0)
+
+/* Backbone Scratch Pad Register */
+#define INTEL_BSPR_REG 0x1104
+/* Backbone Peer Non-Posted Disable */
+#define INTEL_BSPR_REG_BPNPD (1 << 8)
+/* Backbone Peer Posted Disable */
+#define INTEL_BSPR_REG_BPPD (1 << 9)
+
+/* Upstream Peer Decode Configuration Register */
+#define INTEL_UPDCR_REG 0x1114
+/* 5:0 Peer Decode Enable bits */
+#define INTEL_UPDCR_REG_MASK 0x3f
+
+static int pci_quirk_enable_intel_lpc_acs(struct pci_dev *dev)
+{
+ u32 rcba, bspr, updcr;
+ void __iomem *rcba_mem;
+
+ /*
+ * Read the RCBA register from the LPC (D31:F0). PCH root ports
+ * are D28:F* and therefore get probed before LPC, thus we can't
+ * use pci_get_slot/pci_read_config_dword here.
+ */
+ pci_bus_read_config_dword(dev->bus, PCI_DEVFN(31, 0),
+ INTEL_LPC_RCBA_REG, &rcba);
+ if (!(rcba & INTEL_LPC_RCBA_ENABLE))
+ return -EINVAL;
+
+ rcba_mem = ioremap_nocache(rcba & INTEL_LPC_RCBA_MASK,
+ PAGE_ALIGN(INTEL_UPDCR_REG));
+ if (!rcba_mem)
+ return -ENOMEM;
+
+ /*
+ * The BSPR can disallow peer cycles, but it's set by soft strap and
+ * therefore read-only. If both posted and non-posted peer cycles are
+ * disallowed, we're ok. If either are allowed, then we need to use
+ * the UPDCR to disable peer decodes for each port. This provides the
+ * PCIe ACS equivalent of PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF
+ */
+ bspr = readl(rcba_mem + INTEL_BSPR_REG);
+ bspr &= INTEL_BSPR_REG_BPNPD | INTEL_BSPR_REG_BPPD;
+ if (bspr != (INTEL_BSPR_REG_BPNPD | INTEL_BSPR_REG_BPPD)) {
+ updcr = readl(rcba_mem + INTEL_UPDCR_REG);
+ if (updcr & INTEL_UPDCR_REG_MASK) {
+ dev_info(&dev->dev, "Disabling UPDCR peer decodes\n");
+ updcr &= ~INTEL_UPDCR_REG_MASK;
+ writel(updcr, rcba_mem + INTEL_UPDCR_REG);
+ }
+ }
+
+ iounmap(rcba_mem);
+ return 0;
+}
+
+/* Miscellaneous Port Configuration register */
+#define INTEL_MPC_REG 0xd8
+/* MPC: Invalid Receive Bus Number Check Enable */
+#define INTEL_MPC_REG_IRBNCE (1 << 26)
+
+static void pci_quirk_enable_intel_rp_mpc_acs(struct pci_dev *dev)
+{
+ u32 mpc;
+
+ /*
+ * When enabled, the IRBNCE bit of the MPC register enables the
+ * equivalent of PCI ACS Source Validation (PCI_ACS_SV), which
+ * ensures that requester IDs fall within the bus number range
+ * of the bridge. Enable if not already.
+ */
+ pci_read_config_dword(dev, INTEL_MPC_REG, &mpc);
+ if (!(mpc & INTEL_MPC_REG_IRBNCE)) {
+ dev_info(&dev->dev, "Enabling MPC IRBNCE\n");
+ mpc |= INTEL_MPC_REG_IRBNCE;
+ pci_write_config_word(dev, INTEL_MPC_REG, mpc);
+ }
+}
+
+static int pci_quirk_enable_intel_pch_acs(struct pci_dev *dev)
+{
+ if (!pci_quirk_intel_pch_acs_match(dev))
+ return -ENOTTY;
+
+ if (pci_quirk_enable_intel_lpc_acs(dev)) {
+ dev_warn(&dev->dev, "Failed to enable Intel PCH ACS quirk\n");
+ return 0;
+ }
+
+ pci_quirk_enable_intel_rp_mpc_acs(dev);
+
+ dev->dev_flags |= PCI_DEV_FLAGS_ACS_ENABLED_QUIRK;
+
+ dev_info(&dev->dev, "Intel PCH root port ACS workaround enabled\n");
+
+ return 0;
+}
+
+static const struct pci_dev_enable_acs {
+ u16 vendor;
+ u16 device;
+ int (*enable_acs)(struct pci_dev *dev);
+} pci_dev_enable_acs[] = {
+ { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_enable_intel_pch_acs },
+ { 0 }
+};
+
+void pci_dev_specific_enable_acs(struct pci_dev *dev)
+{
+ const struct pci_dev_enable_acs *i;
+ int ret;
+
+ for (i = pci_dev_enable_acs; i->enable_acs; i++) {
+ if ((i->vendor == dev->vendor ||
+ i->vendor == (u16)PCI_ANY_ID) &&
+ (i->device == dev->device ||
+ i->device == (u16)PCI_ANY_ID)) {
+ ret = i->enable_acs(dev);
+ if (ret >= 0)
+ return;
+ }
+ }
+}
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
index 5d595724e5f4..c1839450d4d6 100644
--- a/drivers/pci/rom.c
+++ b/drivers/pci/rom.c
@@ -197,8 +197,10 @@ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom)
void pci_cleanup_rom(struct pci_dev *pdev)
{
struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
+
if (res->flags & IORESOURCE_ROM_COPY) {
kfree((void*)(unsigned long)res->start);
+ res->flags |= IORESOURCE_UNSET;
res->flags &= ~IORESOURCE_ROM_COPY;
res->start = 0;
res->end = 0;
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index 3ff2ac7c14e2..4a1b972efe7f 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -54,14 +54,14 @@ pci_find_upstream_pcie_bridge(struct pci_dev *pdev)
static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr)
{
- struct pci_bus* child;
- struct list_head *tmp;
+ struct pci_bus *child;
+ struct pci_bus *tmp;
if(bus->number == busnr)
return bus;
- list_for_each(tmp, &bus->children) {
- child = pci_do_find_bus(pci_bus_b(tmp), busnr);
+ list_for_each_entry(tmp, &bus->children, node) {
+ child = pci_do_find_bus(tmp, busnr);
if(child)
return child;
}
@@ -111,7 +111,7 @@ pci_find_next_bus(const struct pci_bus *from)
down_read(&pci_bus_sem);
n = from ? from->node.next : pci_root_buses.next;
if (n != &pci_root_buses)
- b = pci_bus_b(n);
+ b = list_entry(n, struct pci_bus, node);
up_read(&pci_bus_sem);
return b;
}
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 5c060b152ce6..7eed671d5586 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -44,6 +44,9 @@ void pci_update_resource(struct pci_dev *dev, int resno)
if (!res->flags)
return;
+ if (res->flags & IORESOURCE_UNSET)
+ return;
+
/*
* Ignore non-moveable resources. This might be legacy resources for
* which no functional BAR register exists or another important
@@ -101,11 +104,6 @@ void pci_update_resource(struct pci_dev *dev, int resno)
if (disable)
pci_write_config_word(dev, PCI_COMMAND, cmd);
-
- res->flags &= ~IORESOURCE_UNSET;
- dev_dbg(&dev->dev, "BAR %d: set to %pR (PCI address [%#llx-%#llx])\n",
- resno, res, (unsigned long long)region.start,
- (unsigned long long)region.end);
}
int pci_claim_resource(struct pci_dev *dev, int resource)
@@ -113,18 +111,23 @@ int pci_claim_resource(struct pci_dev *dev, int resource)
struct resource *res = &dev->resource[resource];
struct resource *root, *conflict;
+ if (res->flags & IORESOURCE_UNSET) {
+ dev_info(&dev->dev, "can't claim BAR %d %pR: no address assigned\n",
+ resource, res);
+ return -EINVAL;
+ }
+
root = pci_find_parent_resource(dev, res);
if (!root) {
- dev_info(&dev->dev, "no compatible bridge window for %pR\n",
- res);
+ dev_info(&dev->dev, "can't claim BAR %d %pR: no compatible bridge window\n",
+ resource, res);
return -EINVAL;
}
conflict = request_resource_conflict(root, res);
if (conflict) {
- dev_info(&dev->dev,
- "address space collision: %pR conflicts with %s %pR\n",
- res, conflict->name, conflict);
+ dev_info(&dev->dev, "can't claim BAR %d %pR: address conflict with %s %pR\n",
+ resource, res, conflict->name, conflict);
return -EBUSY;
}
@@ -263,6 +266,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
resource_size_t align, size;
int ret;
+ res->flags |= IORESOURCE_UNSET;
align = pci_resource_alignment(dev, res);
if (!align) {
dev_info(&dev->dev, "BAR %d: can't assign %pR "
@@ -282,6 +286,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
ret = pci_revert_fw_address(res, dev, resno, size);
if (!ret) {
+ res->flags &= ~IORESOURCE_UNSET;
res->flags &= ~IORESOURCE_STARTALIGN;
dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res);
if (resno < PCI_BRIDGE_RESOURCES)
@@ -297,6 +302,7 @@ int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsiz
resource_size_t new_size;
int ret;
+ res->flags |= IORESOURCE_UNSET;
if (!res->parent) {
dev_info(&dev->dev, "BAR %d: can't reassign an unassigned resource %pR "
"\n", resno, res);
@@ -307,6 +313,7 @@ int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsiz
new_size = resource_size(res) + addsize;
ret = _pci_assign_resource(dev, resno, new_size, min_align);
if (!ret) {
+ res->flags &= ~IORESOURCE_UNSET;
res->flags &= ~IORESOURCE_STARTALIGN;
dev_info(&dev->dev, "BAR %d: reassigned %pR\n", resno, res);
if (resno < PCI_BRIDGE_RESOURCES)
@@ -336,9 +343,15 @@ int pci_enable_resources(struct pci_dev *dev, int mask)
(!(r->flags & IORESOURCE_ROM_ENABLE)))
continue;
+ if (r->flags & IORESOURCE_UNSET) {
+ dev_err(&dev->dev, "can't enable device: BAR %d %pR not assigned\n",
+ i, r);
+ return -EINVAL;
+ }
+
if (!r->parent) {
- dev_err(&dev->dev, "device not available "
- "(can't reserve %pR)\n", r);
+ dev_err(&dev->dev, "can't enable device: BAR %d %pR not claimed\n",
+ i, r);
return -EINVAL;
}
diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c
index 6eecd7cddf57..54d3089d157b 100644
--- a/drivers/pcmcia/sa11xx_base.c
+++ b/drivers/pcmcia/sa11xx_base.c
@@ -125,9 +125,6 @@ sa1100_pcmcia_frequency_change(struct soc_pcmcia_socket *skt,
if (freqs->new < freqs->old)
sa1100_pcmcia_set_mecr(skt, freqs->new);
break;
- case CPUFREQ_RESUMECHANGE:
- sa1100_pcmcia_set_mecr(skt, freqs->new);
- break;
}
return 0;
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index 8485761e76af..946f90ef6020 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -1076,7 +1076,7 @@ static void yenta_config_init(struct yenta_socket *socket)
*/
static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge)
{
- struct list_head *tmp;
+ struct pci_bus *sibling;
unsigned char upper_limit;
/*
* We only check and fix the parent bridge: All systems which need
@@ -1095,18 +1095,18 @@ static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge)
/* stay within the limits of the bus range of the parent: */
upper_limit = bridge_to_fix->parent->busn_res.end;
- /* check the bus ranges of all silbling bridges to prevent overlap */
- list_for_each(tmp, &bridge_to_fix->parent->children) {
- struct pci_bus *silbling = pci_bus_b(tmp);
+ /* check the bus ranges of all sibling bridges to prevent overlap */
+ list_for_each_entry(sibling, &bridge_to_fix->parent->children,
+ node) {
/*
- * If the silbling has a higher secondary bus number
+ * If the sibling has a higher secondary bus number
* and it's secondary is equal or smaller than our
* current upper limit, set the new upper limit to
- * the bus number below the silbling's range:
+ * the bus number below the sibling's range:
*/
- if (silbling->busn_res.start > bridge_to_fix->busn_res.end
- && silbling->busn_res.start <= upper_limit)
- upper_limit = silbling->busn_res.start - 1;
+ if (sibling->busn_res.start > bridge_to_fix->busn_res.end
+ && sibling->busn_res.start <= upper_limit)
+ upper_limit = sibling->busn_res.start - 1;
}
/* Show that the wanted subordinate number is not possible: */
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index afa2354f6600..8d3c49cc500f 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -5,7 +5,7 @@
menu "PHY Subsystem"
config GENERIC_PHY
- tristate "PHY Core"
+ bool "PHY Core"
help
Generic PHY support.
@@ -16,30 +16,56 @@ config GENERIC_PHY
framework should select this config.
config PHY_EXYNOS_MIPI_VIDEO
- depends on HAS_IOMEM
tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver"
+ depends on HAS_IOMEM
+ depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
+ select GENERIC_PHY
+ default y if ARCH_S5PV210 || ARCH_EXYNOS
help
Support for MIPI CSI-2 and MIPI DSI DPHY found on Samsung S5P
and EXYNOS SoCs.
config PHY_MVEBU_SATA
def_bool y
- depends on ARCH_KIRKWOOD || ARCH_DOVE
+ depends on ARCH_KIRKWOOD || ARCH_DOVE || MACH_DOVE
depends on OF
select GENERIC_PHY
+config OMAP_CONTROL_PHY
+ tristate "OMAP CONTROL PHY Driver"
+ help
+ Enable this to add support for the PHY part present in the control
+ module. This driver has API to power on the USB2 PHY and to write to
+ the mailbox. The mailbox is present only in omap4 and the register to
+ power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an
+ additional register to power on USB3 PHY/SATA PHY/PCIE PHY
+ (PIPE3 PHY).
+
config OMAP_USB2
tristate "OMAP USB2 PHY Driver"
depends on ARCH_OMAP2PLUS
depends on USB_PHY
select GENERIC_PHY
- select OMAP_CONTROL_USB
+ select OMAP_CONTROL_PHY
+ depends on OMAP_OCP2SCP
help
Enable this to support the transceiver that is part of SOC. This
driver takes care of all the PHY functionality apart from comparator.
The USB OTG controller communicates with the comparator using this
driver.
+config TI_PIPE3
+ tristate "TI PIPE3 PHY Driver"
+ depends on ARCH_OMAP2PLUS || COMPILE_TEST
+ select GENERIC_PHY
+ select OMAP_CONTROL_PHY
+ depends on OMAP_OCP2SCP
+ help
+ Enable this to support the PIPE3 PHY that is part of TI SOCs. This
+ driver takes care of all the PHY functionality apart from comparator.
+ This driver interacts with the "OMAP Control PHY Driver" to power
+ on/off the PHY.
+
config TWL4030_USB
tristate "TWL4030 USB Transceiver Driver"
depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS
@@ -54,6 +80,8 @@ config TWL4030_USB
config PHY_EXYNOS_DP_VIDEO
tristate "EXYNOS SoC series Display Port PHY driver"
depends on OF
+ depends on ARCH_EXYNOS || COMPILE_TEST
+ default ARCH_EXYNOS
select GENERIC_PHY
help
Support for Display Port PHY found on Samsung EXYNOS SoCs.
@@ -61,7 +89,81 @@ config PHY_EXYNOS_DP_VIDEO
config BCM_KONA_USB2_PHY
tristate "Broadcom Kona USB2 PHY Driver"
depends on GENERIC_PHY
+ depends on HAS_IOMEM
help
Enable this to support the Broadcom Kona USB 2.0 PHY.
+config PHY_EXYNOS5250_SATA
+ tristate "Exynos5250 Sata SerDes/PHY driver"
+ depends on SOC_EXYNOS5250
+ depends on HAS_IOMEM
+ depends on OF
+ select GENERIC_PHY
+ select I2C
+ select I2C_S3C2410
+ select MFD_SYSCON
+ help
+ Enable this to support SATA SerDes/Phy found on Samsung's
+ Exynos5250 based SoCs.This SerDes/Phy supports SATA 1.5 Gb/s,
+ SATA 3.0 Gb/s, SATA 6.0 Gb/s speeds. It supports one SATA host
+ port to accept one SATA device.
+
+config PHY_SUN4I_USB
+ tristate "Allwinner sunxi SoC USB PHY driver"
+ depends on ARCH_SUNXI && HAS_IOMEM && OF
+ select GENERIC_PHY
+ help
+ Enable this to support the transceiver that is part of Allwinner
+ sunxi SoCs.
+
+ This driver controls the entire USB PHY block, both the USB OTG
+ parts, as well as the 2 regular USB 2 host PHYs.
+
+config PHY_SAMSUNG_USB2
+ tristate "Samsung USB 2.0 PHY driver"
+ select GENERIC_PHY
+ select MFD_SYSCON
+ help
+ Enable this to support the Samsung USB 2.0 PHY driver for Samsung
+ SoCs. This driver provides the interface for USB 2.0 PHY. Support for
+ particular SoCs has to be enabled in addition to this driver. Number
+ and type of supported phys depends on the SoC.
+
+config PHY_EXYNOS4210_USB2
+ bool "Support for Exynos 4210"
+ depends on PHY_SAMSUNG_USB2
+ depends on CPU_EXYNOS4210
+ help
+ Enable USB PHY support for Exynos 4210. This option requires that
+ Samsung USB 2.0 PHY driver is enabled and means that support for this
+ particular SoC is compiled in the driver. In case of Exynos 4210 four
+ phys are available - device, host, HSIC0 and HSIC1.
+
+config PHY_EXYNOS4X12_USB2
+ bool "Support for Exynos 4x12"
+ depends on PHY_SAMSUNG_USB2
+ depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)
+ help
+ Enable USB PHY support for Exynos 4x12. This option requires that
+ Samsung USB 2.0 PHY driver is enabled and means that support for this
+ particular SoC is compiled in the driver. In case of Exynos 4x12 four
+ phys are available - device, host, HSIC0 and HSIC1.
+
+config PHY_EXYNOS5250_USB2
+ bool "Support for Exynos 5250"
+ depends on PHY_SAMSUNG_USB2
+ depends on SOC_EXYNOS5250
+ help
+ Enable USB PHY support for Exynos 5250. This option requires that
+ Samsung USB 2.0 PHY driver is enabled and means that support for this
+ particular SoC is compiled in the driver. In case of Exynos 5250 four
+ phys are available - device, host, HSIC0 and HSIC.
+
+config PHY_XGENE
+ tristate "APM X-Gene 15Gbps PHY support"
+ depends on HAS_IOMEM && OF && (ARM64 || COMPILE_TEST)
+ select GENERIC_PHY
+ help
+ This option enables support for APM X-Gene SoC multi-purpose PHY.
+
endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index b57c25371cca..2faf78edc864 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -7,5 +7,14 @@ obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o
obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o
obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o
obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o
+obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o
obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o
+obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o
obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o
+obj-$(CONFIG_PHY_EXYNOS5250_SATA) += phy-exynos5250-sata.o
+obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o
+obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-samsung-usb2.o
+obj-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o
+obj-$(CONFIG_PHY_EXYNOS4X12_USB2) += phy-exynos4x12-usb2.o
+obj-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o
+obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
diff --git a/drivers/phy/phy-bcm-kona-usb2.c b/drivers/phy/phy-bcm-kona-usb2.c
index efc5c1a13a5d..e94f5a6a5645 100644
--- a/drivers/phy/phy-bcm-kona-usb2.c
+++ b/drivers/phy/phy-bcm-kona-usb2.c
@@ -128,10 +128,8 @@ static int bcm_kona_usb2_probe(struct platform_device *pdev)
phy_provider = devm_of_phy_provider_register(dev,
of_phy_simple_xlate);
- if (IS_ERR(phy_provider))
- return PTR_ERR(phy_provider);
- return 0;
+ return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id bcm_kona_usb2_dt_ids[] = {
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 645c867c1257..623b71c54b3e 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -162,6 +162,9 @@ int phy_init(struct phy *phy)
{
int ret;
+ if (!phy)
+ return 0;
+
ret = phy_pm_runtime_get_sync(phy);
if (ret < 0 && ret != -ENOTSUPP)
return ret;
@@ -173,6 +176,8 @@ int phy_init(struct phy *phy)
dev_err(&phy->dev, "phy init failed --> %d\n", ret);
goto out;
}
+ } else {
+ ret = 0; /* Override possible ret == -ENOTSUPP */
}
++phy->init_count;
@@ -187,6 +192,9 @@ int phy_exit(struct phy *phy)
{
int ret;
+ if (!phy)
+ return 0;
+
ret = phy_pm_runtime_get_sync(phy);
if (ret < 0 && ret != -ENOTSUPP)
return ret;
@@ -212,6 +220,9 @@ int phy_power_on(struct phy *phy)
{
int ret;
+ if (!phy)
+ return 0;
+
ret = phy_pm_runtime_get_sync(phy);
if (ret < 0 && ret != -ENOTSUPP)
return ret;
@@ -223,6 +234,8 @@ int phy_power_on(struct phy *phy)
dev_err(&phy->dev, "phy poweron failed --> %d\n", ret);
goto out;
}
+ } else {
+ ret = 0; /* Override possible ret == -ENOTSUPP */
}
++phy->power_count;
mutex_unlock(&phy->mutex);
@@ -240,6 +253,9 @@ int phy_power_off(struct phy *phy)
{
int ret;
+ if (!phy)
+ return 0;
+
mutex_lock(&phy->mutex);
if (phy->power_count == 1 && phy->ops->power_off) {
ret = phy->ops->power_off(phy);
@@ -258,8 +274,8 @@ int phy_power_off(struct phy *phy)
EXPORT_SYMBOL_GPL(phy_power_off);
/**
- * of_phy_get() - lookup and obtain a reference to a phy by phandle
- * @dev: device that requests this phy
+ * _of_phy_get() - lookup and obtain a reference to a phy by phandle
+ * @np: device_node for which to get the phy
* @index: the index of the phy
*
* Returns the phy associated with the given phandle value,
@@ -268,20 +284,17 @@ EXPORT_SYMBOL_GPL(phy_power_off);
* not yet loaded. This function uses of_xlate call back function provided
* while registering the phy_provider to find the phy instance.
*/
-static struct phy *of_phy_get(struct device *dev, int index)
+static struct phy *_of_phy_get(struct device_node *np, int index)
{
int ret;
struct phy_provider *phy_provider;
struct phy *phy = NULL;
struct of_phandle_args args;
- ret = of_parse_phandle_with_args(dev->of_node, "phys", "#phy-cells",
+ ret = of_parse_phandle_with_args(np, "phys", "#phy-cells",
index, &args);
- if (ret) {
- dev_dbg(dev, "failed to get phy in %s node\n",
- dev->of_node->full_name);
+ if (ret)
return ERR_PTR(-ENODEV);
- }
mutex_lock(&phy_provider_mutex);
phy_provider = of_phy_provider_lookup(args.np);
@@ -301,6 +314,36 @@ err0:
}
/**
+ * of_phy_get() - lookup and obtain a reference to a phy using a device_node.
+ * @np: device_node for which to get the phy
+ * @con_id: name of the phy from device's point of view
+ *
+ * Returns the phy driver, after getting a refcount to it; or
+ * -ENODEV if there is no such phy. The caller is responsible for
+ * calling phy_put() to release that count.
+ */
+struct phy *of_phy_get(struct device_node *np, const char *con_id)
+{
+ struct phy *phy = NULL;
+ int index = 0;
+
+ if (con_id)
+ index = of_property_match_string(np, "phy-names", con_id);
+
+ phy = _of_phy_get(np, index);
+ if (IS_ERR(phy))
+ return phy;
+
+ if (!try_module_get(phy->ops->owner))
+ return ERR_PTR(-EPROBE_DEFER);
+
+ get_device(&phy->dev);
+
+ return phy;
+}
+EXPORT_SYMBOL_GPL(of_phy_get);
+
+/**
* phy_put() - release the PHY
* @phy: the phy returned by phy_get()
*
@@ -308,7 +351,7 @@ err0:
*/
void phy_put(struct phy *phy)
{
- if (IS_ERR(phy))
+ if (!phy || IS_ERR(phy))
return;
module_put(phy->ops->owner);
@@ -328,6 +371,9 @@ void devm_phy_put(struct device *dev, struct phy *phy)
{
int r;
+ if (!phy)
+ return;
+
r = devres_destroy(dev, devm_phy_release, devm_phy_match, phy);
dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n");
}
@@ -388,18 +434,12 @@ struct phy *phy_get(struct device *dev, const char *string)
if (dev->of_node) {
index = of_property_match_string(dev->of_node, "phy-names",
string);
- phy = of_phy_get(dev, index);
- if (IS_ERR(phy)) {
- dev_err(dev, "unable to find phy\n");
- return phy;
- }
+ phy = _of_phy_get(dev->of_node, index);
} else {
phy = phy_lookup(dev, string);
- if (IS_ERR(phy)) {
- dev_err(dev, "unable to find phy\n");
- return phy;
- }
}
+ if (IS_ERR(phy))
+ return phy;
if (!try_module_get(phy->ops->owner))
return ERR_PTR(-EPROBE_DEFER);
@@ -411,6 +451,27 @@ struct phy *phy_get(struct device *dev, const char *string)
EXPORT_SYMBOL_GPL(phy_get);
/**
+ * phy_optional_get() - lookup and obtain a reference to an optional phy.
+ * @dev: device that requests this phy
+ * @string: the phy name as given in the dt data or the name of the controller
+ * port for non-dt case
+ *
+ * Returns the phy driver, after getting a refcount to it; or
+ * NULL if there is no such phy. The caller is responsible for
+ * calling phy_put() to release that count.
+ */
+struct phy *phy_optional_get(struct device *dev, const char *string)
+{
+ struct phy *phy = phy_get(dev, string);
+
+ if (PTR_ERR(phy) == -ENODEV)
+ phy = NULL;
+
+ return phy;
+}
+EXPORT_SYMBOL_GPL(phy_optional_get);
+
+/**
* devm_phy_get() - lookup and obtain a reference to a phy.
* @dev: device that requests this phy
* @string: the phy name as given in the dt data or phy device name
@@ -441,6 +502,61 @@ struct phy *devm_phy_get(struct device *dev, const char *string)
EXPORT_SYMBOL_GPL(devm_phy_get);
/**
+ * devm_phy_optional_get() - lookup and obtain a reference to an optional phy.
+ * @dev: device that requests this phy
+ * @string: the phy name as given in the dt data or phy device name
+ * for non-dt case
+ *
+ * Gets the phy using phy_get(), and associates a device with it using
+ * devres. On driver detach, release function is invoked on the devres
+ * data, then, devres data is freed. This differs to devm_phy_get() in
+ * that if the phy does not exist, it is not considered an error and
+ * -ENODEV will not be returned. Instead the NULL phy is returned,
+ * which can be passed to all other phy consumer calls.
+ */
+struct phy *devm_phy_optional_get(struct device *dev, const char *string)
+{
+ struct phy *phy = devm_phy_get(dev, string);
+
+ if (PTR_ERR(phy) == -ENODEV)
+ phy = NULL;
+
+ return phy;
+}
+EXPORT_SYMBOL_GPL(devm_phy_optional_get);
+
+/**
+ * devm_of_phy_get() - lookup and obtain a reference to a phy.
+ * @dev: device that requests this phy
+ * @np: node containing the phy
+ * @con_id: name of the phy from device's point of view
+ *
+ * Gets the phy using of_phy_get(), and associates a device with it using
+ * devres. On driver detach, release function is invoked on the devres data,
+ * then, devres data is freed.
+ */
+struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
+ const char *con_id)
+{
+ struct phy **ptr, *phy;
+
+ ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ phy = of_phy_get(np, con_id);
+ if (!IS_ERR(phy)) {
+ *ptr = phy;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return phy;
+}
+EXPORT_SYMBOL_GPL(devm_of_phy_get);
+
+/**
* phy_create() - create a new phy
* @dev: device that is creating the new phy
* @ops: function pointers for performing phy operations
diff --git a/drivers/phy/phy-exynos-dp-video.c b/drivers/phy/phy-exynos-dp-video.c
index 1dbe6ce7b2ce..0786fef842e7 100644
--- a/drivers/phy/phy-exynos-dp-video.c
+++ b/drivers/phy/phy-exynos-dp-video.c
@@ -76,10 +76,6 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev)
if (IS_ERR(state->regs))
return PTR_ERR(state->regs);
- phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
- if (IS_ERR(phy_provider))
- return PTR_ERR(phy_provider);
-
phy = devm_phy_create(dev, &exynos_dp_video_phy_ops, NULL);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create Display Port PHY\n");
@@ -87,6 +83,10 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev)
}
phy_set_drvdata(phy, state);
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ if (IS_ERR(phy_provider))
+ return PTR_ERR(phy_provider);
+
return 0;
}
diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/phy-exynos-mipi-video.c
index 0c5efab11af1..7f139326a642 100644
--- a/drivers/phy/phy-exynos-mipi-video.c
+++ b/drivers/phy/phy-exynos-mipi-video.c
@@ -134,11 +134,6 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
dev_set_drvdata(dev, state);
spin_lock_init(&state->slock);
- phy_provider = devm_of_phy_provider_register(dev,
- exynos_mipi_video_phy_xlate);
- if (IS_ERR(phy_provider))
- return PTR_ERR(phy_provider);
-
for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) {
struct phy *phy = devm_phy_create(dev,
&exynos_mipi_video_phy_ops, NULL);
@@ -152,6 +147,11 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
phy_set_drvdata(phy, &state->phys[i]);
}
+ phy_provider = devm_of_phy_provider_register(dev,
+ exynos_mipi_video_phy_xlate);
+ if (IS_ERR(phy_provider))
+ return PTR_ERR(phy_provider);
+
return 0;
}
diff --git a/drivers/phy/phy-exynos4210-usb2.c b/drivers/phy/phy-exynos4210-usb2.c
new file mode 100644
index 000000000000..236a52ad94eb
--- /dev/null
+++ b/drivers/phy/phy-exynos4210-usb2.c
@@ -0,0 +1,261 @@
+/*
+ * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4210 support
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Kamil Debski <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/phy/phy.h>
+#include <linux/regmap.h>
+#include "phy-samsung-usb2.h"
+
+/* Exynos USB PHY registers */
+
+/* PHY power control */
+#define EXYNOS_4210_UPHYPWR 0x0
+
+#define EXYNOS_4210_UPHYPWR_PHY0_SUSPEND BIT(0)
+#define EXYNOS_4210_UPHYPWR_PHY0_PWR BIT(3)
+#define EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR BIT(4)
+#define EXYNOS_4210_UPHYPWR_PHY0_SLEEP BIT(5)
+#define EXYNOS_4210_UPHYPWR_PHY0 ( \
+ EXYNOS_4210_UPHYPWR_PHY0_SUSPEND | \
+ EXYNOS_4210_UPHYPWR_PHY0_PWR | \
+ EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR | \
+ EXYNOS_4210_UPHYPWR_PHY0_SLEEP)
+
+#define EXYNOS_4210_UPHYPWR_PHY1_SUSPEND BIT(6)
+#define EXYNOS_4210_UPHYPWR_PHY1_PWR BIT(7)
+#define EXYNOS_4210_UPHYPWR_PHY1_SLEEP BIT(8)
+#define EXYNOS_4210_UPHYPWR_PHY1 ( \
+ EXYNOS_4210_UPHYPWR_PHY1_SUSPEND | \
+ EXYNOS_4210_UPHYPWR_PHY1_PWR | \
+ EXYNOS_4210_UPHYPWR_PHY1_SLEEP)
+
+#define EXYNOS_4210_UPHYPWR_HSIC0_SUSPEND BIT(9)
+#define EXYNOS_4210_UPHYPWR_HSIC0_SLEEP BIT(10)
+#define EXYNOS_4210_UPHYPWR_HSIC0 ( \
+ EXYNOS_4210_UPHYPWR_HSIC0_SUSPEND | \
+ EXYNOS_4210_UPHYPWR_HSIC0_SLEEP)
+
+#define EXYNOS_4210_UPHYPWR_HSIC1_SUSPEND BIT(11)
+#define EXYNOS_4210_UPHYPWR_HSIC1_SLEEP BIT(12)
+#define EXYNOS_4210_UPHYPWR_HSIC1 ( \
+ EXYNOS_4210_UPHYPWR_HSIC1_SUSPEND | \
+ EXYNOS_4210_UPHYPWR_HSIC1_SLEEP)
+
+/* PHY clock control */
+#define EXYNOS_4210_UPHYCLK 0x4
+
+#define EXYNOS_4210_UPHYCLK_PHYFSEL_MASK (0x3 << 0)
+#define EXYNOS_4210_UPHYCLK_PHYFSEL_OFFSET 0
+#define EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ (0x0 << 0)
+#define EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ (0x3 << 0)
+#define EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ (0x2 << 0)
+
+#define EXYNOS_4210_UPHYCLK_PHY0_ID_PULLUP BIT(2)
+#define EXYNOS_4210_UPHYCLK_PHY0_COMMON_ON BIT(4)
+#define EXYNOS_4210_UPHYCLK_PHY1_COMMON_ON BIT(7)
+
+/* PHY reset control */
+#define EXYNOS_4210_UPHYRST 0x8
+
+#define EXYNOS_4210_URSTCON_PHY0 BIT(0)
+#define EXYNOS_4210_URSTCON_OTG_HLINK BIT(1)
+#define EXYNOS_4210_URSTCON_OTG_PHYLINK BIT(2)
+#define EXYNOS_4210_URSTCON_PHY1_ALL BIT(3)
+#define EXYNOS_4210_URSTCON_PHY1_P0 BIT(4)
+#define EXYNOS_4210_URSTCON_PHY1_P1P2 BIT(5)
+#define EXYNOS_4210_URSTCON_HOST_LINK_ALL BIT(6)
+#define EXYNOS_4210_URSTCON_HOST_LINK_P0 BIT(7)
+#define EXYNOS_4210_URSTCON_HOST_LINK_P1 BIT(8)
+#define EXYNOS_4210_URSTCON_HOST_LINK_P2 BIT(9)
+
+/* Isolation, configured in the power management unit */
+#define EXYNOS_4210_USB_ISOL_DEVICE_OFFSET 0x704
+#define EXYNOS_4210_USB_ISOL_DEVICE BIT(0)
+#define EXYNOS_4210_USB_ISOL_HOST_OFFSET 0x708
+#define EXYNOS_4210_USB_ISOL_HOST BIT(0)
+
+/* USBYPHY1 Floating prevention */
+#define EXYNOS_4210_UPHY1CON 0x34
+#define EXYNOS_4210_UPHY1CON_FLOAT_PREVENTION 0x1
+
+/* Mode switching SUB Device <-> Host */
+#define EXYNOS_4210_MODE_SWITCH_OFFSET 0x21c
+#define EXYNOS_4210_MODE_SWITCH_MASK 1
+#define EXYNOS_4210_MODE_SWITCH_DEVICE 0
+#define EXYNOS_4210_MODE_SWITCH_HOST 1
+
+enum exynos4210_phy_id {
+ EXYNOS4210_DEVICE,
+ EXYNOS4210_HOST,
+ EXYNOS4210_HSIC0,
+ EXYNOS4210_HSIC1,
+ EXYNOS4210_NUM_PHYS,
+};
+
+/*
+ * exynos4210_rate_to_clk() converts the supplied clock rate to the value that
+ * can be written to the phy register.
+ */
+static int exynos4210_rate_to_clk(unsigned long rate, u32 *reg)
+{
+ switch (rate) {
+ case 12 * MHZ:
+ *reg = EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ;
+ break;
+ case 24 * MHZ:
+ *reg = EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ;
+ break;
+ case 48 * MHZ:
+ *reg = EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void exynos4210_isol(struct samsung_usb2_phy_instance *inst, bool on)
+{
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ u32 offset;
+ u32 mask;
+
+ switch (inst->cfg->id) {
+ case EXYNOS4210_DEVICE:
+ offset = EXYNOS_4210_USB_ISOL_DEVICE_OFFSET;
+ mask = EXYNOS_4210_USB_ISOL_DEVICE;
+ break;
+ case EXYNOS4210_HOST:
+ offset = EXYNOS_4210_USB_ISOL_HOST_OFFSET;
+ mask = EXYNOS_4210_USB_ISOL_HOST;
+ break;
+ default:
+ return;
+ };
+
+ regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
+}
+
+static void exynos4210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
+{
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ u32 rstbits = 0;
+ u32 phypwr = 0;
+ u32 rst;
+ u32 pwr;
+ u32 clk;
+
+ switch (inst->cfg->id) {
+ case EXYNOS4210_DEVICE:
+ phypwr = EXYNOS_4210_UPHYPWR_PHY0;
+ rstbits = EXYNOS_4210_URSTCON_PHY0;
+ break;
+ case EXYNOS4210_HOST:
+ phypwr = EXYNOS_4210_UPHYPWR_PHY1;
+ rstbits = EXYNOS_4210_URSTCON_PHY1_ALL |
+ EXYNOS_4210_URSTCON_PHY1_P0 |
+ EXYNOS_4210_URSTCON_PHY1_P1P2 |
+ EXYNOS_4210_URSTCON_HOST_LINK_ALL |
+ EXYNOS_4210_URSTCON_HOST_LINK_P0;
+ writel(on, drv->reg_phy + EXYNOS_4210_UPHY1CON);
+ break;
+ case EXYNOS4210_HSIC0:
+ phypwr = EXYNOS_4210_UPHYPWR_HSIC0;
+ rstbits = EXYNOS_4210_URSTCON_PHY1_P1P2 |
+ EXYNOS_4210_URSTCON_HOST_LINK_P1;
+ break;
+ case EXYNOS4210_HSIC1:
+ phypwr = EXYNOS_4210_UPHYPWR_HSIC1;
+ rstbits = EXYNOS_4210_URSTCON_PHY1_P1P2 |
+ EXYNOS_4210_URSTCON_HOST_LINK_P2;
+ break;
+ };
+
+ if (on) {
+ clk = readl(drv->reg_phy + EXYNOS_4210_UPHYCLK);
+ clk &= ~EXYNOS_4210_UPHYCLK_PHYFSEL_MASK;
+ clk |= drv->ref_reg_val << EXYNOS_4210_UPHYCLK_PHYFSEL_OFFSET;
+ writel(clk, drv->reg_phy + EXYNOS_4210_UPHYCLK);
+
+ pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
+ pwr &= ~phypwr;
+ writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
+
+ rst = readl(drv->reg_phy + EXYNOS_4210_UPHYRST);
+ rst |= rstbits;
+ writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
+ udelay(10);
+ rst &= ~rstbits;
+ writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
+ /* The following delay is necessary for the reset sequence to be
+ * completed */
+ udelay(80);
+ } else {
+ pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
+ pwr |= phypwr;
+ writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
+ }
+}
+
+static int exynos4210_power_on(struct samsung_usb2_phy_instance *inst)
+{
+ /* Order of initialisation is important - first power then isolation */
+ exynos4210_phy_pwr(inst, 1);
+ exynos4210_isol(inst, 0);
+
+ return 0;
+}
+
+static int exynos4210_power_off(struct samsung_usb2_phy_instance *inst)
+{
+ exynos4210_isol(inst, 1);
+ exynos4210_phy_pwr(inst, 0);
+
+ return 0;
+}
+
+
+static const struct samsung_usb2_common_phy exynos4210_phys[] = {
+ {
+ .label = "device",
+ .id = EXYNOS4210_DEVICE,
+ .power_on = exynos4210_power_on,
+ .power_off = exynos4210_power_off,
+ },
+ {
+ .label = "host",
+ .id = EXYNOS4210_HOST,
+ .power_on = exynos4210_power_on,
+ .power_off = exynos4210_power_off,
+ },
+ {
+ .label = "hsic0",
+ .id = EXYNOS4210_HSIC0,
+ .power_on = exynos4210_power_on,
+ .power_off = exynos4210_power_off,
+ },
+ {
+ .label = "hsic1",
+ .id = EXYNOS4210_HSIC1,
+ .power_on = exynos4210_power_on,
+ .power_off = exynos4210_power_off,
+ },
+ {},
+};
+
+const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
+ .has_mode_switch = 0,
+ .num_phys = EXYNOS4210_NUM_PHYS,
+ .phys = exynos4210_phys,
+ .rate_to_clk = exynos4210_rate_to_clk,
+};
diff --git a/drivers/phy/phy-exynos4x12-usb2.c b/drivers/phy/phy-exynos4x12-usb2.c
new file mode 100644
index 000000000000..d92a7cc5698a
--- /dev/null
+++ b/drivers/phy/phy-exynos4x12-usb2.c
@@ -0,0 +1,328 @@
+/*
+ * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4x12 support
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Kamil Debski <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/phy/phy.h>
+#include <linux/regmap.h>
+#include "phy-samsung-usb2.h"
+
+/* Exynos USB PHY registers */
+
+/* PHY power control */
+#define EXYNOS_4x12_UPHYPWR 0x0
+
+#define EXYNOS_4x12_UPHYPWR_PHY0_SUSPEND BIT(0)
+#define EXYNOS_4x12_UPHYPWR_PHY0_PWR BIT(3)
+#define EXYNOS_4x12_UPHYPWR_PHY0_OTG_PWR BIT(4)
+#define EXYNOS_4x12_UPHYPWR_PHY0_SLEEP BIT(5)
+#define EXYNOS_4x12_UPHYPWR_PHY0 ( \
+ EXYNOS_4x12_UPHYPWR_PHY0_SUSPEND | \
+ EXYNOS_4x12_UPHYPWR_PHY0_PWR | \
+ EXYNOS_4x12_UPHYPWR_PHY0_OTG_PWR | \
+ EXYNOS_4x12_UPHYPWR_PHY0_SLEEP)
+
+#define EXYNOS_4x12_UPHYPWR_PHY1_SUSPEND BIT(6)
+#define EXYNOS_4x12_UPHYPWR_PHY1_PWR BIT(7)
+#define EXYNOS_4x12_UPHYPWR_PHY1_SLEEP BIT(8)
+#define EXYNOS_4x12_UPHYPWR_PHY1 ( \
+ EXYNOS_4x12_UPHYPWR_PHY1_SUSPEND | \
+ EXYNOS_4x12_UPHYPWR_PHY1_PWR | \
+ EXYNOS_4x12_UPHYPWR_PHY1_SLEEP)
+
+#define EXYNOS_4x12_UPHYPWR_HSIC0_SUSPEND BIT(9)
+#define EXYNOS_4x12_UPHYPWR_HSIC0_PWR BIT(10)
+#define EXYNOS_4x12_UPHYPWR_HSIC0_SLEEP BIT(11)
+#define EXYNOS_4x12_UPHYPWR_HSIC0 ( \
+ EXYNOS_4x12_UPHYPWR_HSIC0_SUSPEND | \
+ EXYNOS_4x12_UPHYPWR_HSIC0_PWR | \
+ EXYNOS_4x12_UPHYPWR_HSIC0_SLEEP)
+
+#define EXYNOS_4x12_UPHYPWR_HSIC1_SUSPEND BIT(12)
+#define EXYNOS_4x12_UPHYPWR_HSIC1_PWR BIT(13)
+#define EXYNOS_4x12_UPHYPWR_HSIC1_SLEEP BIT(14)
+#define EXYNOS_4x12_UPHYPWR_HSIC1 ( \
+ EXYNOS_4x12_UPHYPWR_HSIC1_SUSPEND | \
+ EXYNOS_4x12_UPHYPWR_HSIC1_PWR | \
+ EXYNOS_4x12_UPHYPWR_HSIC1_SLEEP)
+
+/* PHY clock control */
+#define EXYNOS_4x12_UPHYCLK 0x4
+
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK (0x7 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_OFFSET 0
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_9MHZ6 (0x0 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_10MHZ (0x1 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_12MHZ (0x2 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_19MHZ2 (0x3 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_20MHZ (0x4 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_24MHZ (0x5 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_50MHZ (0x7 << 0)
+
+#define EXYNOS_4x12_UPHYCLK_PHY0_ID_PULLUP BIT(3)
+#define EXYNOS_4x12_UPHYCLK_PHY0_COMMON_ON BIT(4)
+#define EXYNOS_4x12_UPHYCLK_PHY1_COMMON_ON BIT(7)
+
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_MASK (0x7f << 10)
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_OFFSET 10
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_12MHZ (0x24 << 10)
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_15MHZ (0x1c << 10)
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_16MHZ (0x1a << 10)
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_19MHZ2 (0x15 << 10)
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_20MHZ (0x14 << 10)
+
+/* PHY reset control */
+#define EXYNOS_4x12_UPHYRST 0x8
+
+#define EXYNOS_4x12_URSTCON_PHY0 BIT(0)
+#define EXYNOS_4x12_URSTCON_OTG_HLINK BIT(1)
+#define EXYNOS_4x12_URSTCON_OTG_PHYLINK BIT(2)
+#define EXYNOS_4x12_URSTCON_HOST_PHY BIT(3)
+#define EXYNOS_4x12_URSTCON_PHY1 BIT(4)
+#define EXYNOS_4x12_URSTCON_HSIC0 BIT(5)
+#define EXYNOS_4x12_URSTCON_HSIC1 BIT(6)
+#define EXYNOS_4x12_URSTCON_HOST_LINK_ALL BIT(7)
+#define EXYNOS_4x12_URSTCON_HOST_LINK_P0 BIT(8)
+#define EXYNOS_4x12_URSTCON_HOST_LINK_P1 BIT(9)
+#define EXYNOS_4x12_URSTCON_HOST_LINK_P2 BIT(10)
+
+/* Isolation, configured in the power management unit */
+#define EXYNOS_4x12_USB_ISOL_OFFSET 0x704
+#define EXYNOS_4x12_USB_ISOL_OTG BIT(0)
+#define EXYNOS_4x12_USB_ISOL_HSIC0_OFFSET 0x708
+#define EXYNOS_4x12_USB_ISOL_HSIC0 BIT(0)
+#define EXYNOS_4x12_USB_ISOL_HSIC1_OFFSET 0x70c
+#define EXYNOS_4x12_USB_ISOL_HSIC1 BIT(0)
+
+/* Mode switching SUB Device <-> Host */
+#define EXYNOS_4x12_MODE_SWITCH_OFFSET 0x21c
+#define EXYNOS_4x12_MODE_SWITCH_MASK 1
+#define EXYNOS_4x12_MODE_SWITCH_DEVICE 0
+#define EXYNOS_4x12_MODE_SWITCH_HOST 1
+
+enum exynos4x12_phy_id {
+ EXYNOS4x12_DEVICE,
+ EXYNOS4x12_HOST,
+ EXYNOS4x12_HSIC0,
+ EXYNOS4x12_HSIC1,
+ EXYNOS4x12_NUM_PHYS,
+};
+
+/*
+ * exynos4x12_rate_to_clk() converts the supplied clock rate to the value that
+ * can be written to the phy register.
+ */
+static int exynos4x12_rate_to_clk(unsigned long rate, u32 *reg)
+{
+ /* EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK */
+
+ switch (rate) {
+ case 9600 * KHZ:
+ *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_9MHZ6;
+ break;
+ case 10 * MHZ:
+ *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_10MHZ;
+ break;
+ case 12 * MHZ:
+ *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_12MHZ;
+ break;
+ case 19200 * KHZ:
+ *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_19MHZ2;
+ break;
+ case 20 * MHZ:
+ *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_20MHZ;
+ break;
+ case 24 * MHZ:
+ *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_24MHZ;
+ break;
+ case 50 * MHZ:
+ *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_50MHZ;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void exynos4x12_isol(struct samsung_usb2_phy_instance *inst, bool on)
+{
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ u32 offset;
+ u32 mask;
+
+ switch (inst->cfg->id) {
+ case EXYNOS4x12_DEVICE:
+ case EXYNOS4x12_HOST:
+ offset = EXYNOS_4x12_USB_ISOL_OFFSET;
+ mask = EXYNOS_4x12_USB_ISOL_OTG;
+ break;
+ case EXYNOS4x12_HSIC0:
+ offset = EXYNOS_4x12_USB_ISOL_HSIC0_OFFSET;
+ mask = EXYNOS_4x12_USB_ISOL_HSIC0;
+ break;
+ case EXYNOS4x12_HSIC1:
+ offset = EXYNOS_4x12_USB_ISOL_HSIC1_OFFSET;
+ mask = EXYNOS_4x12_USB_ISOL_HSIC1;
+ break;
+ default:
+ return;
+ };
+
+ regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
+}
+
+static void exynos4x12_setup_clk(struct samsung_usb2_phy_instance *inst)
+{
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ u32 clk;
+
+ clk = readl(drv->reg_phy + EXYNOS_4x12_UPHYCLK);
+ clk &= ~EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK;
+ clk |= drv->ref_reg_val << EXYNOS_4x12_UPHYCLK_PHYFSEL_OFFSET;
+ writel(clk, drv->reg_phy + EXYNOS_4x12_UPHYCLK);
+}
+
+static void exynos4x12_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
+{
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ u32 rstbits = 0;
+ u32 phypwr = 0;
+ u32 rst;
+ u32 pwr;
+ u32 mode = 0;
+ u32 switch_mode = 0;
+
+ switch (inst->cfg->id) {
+ case EXYNOS4x12_DEVICE:
+ phypwr = EXYNOS_4x12_UPHYPWR_PHY0;
+ rstbits = EXYNOS_4x12_URSTCON_PHY0;
+ mode = EXYNOS_4x12_MODE_SWITCH_DEVICE;
+ switch_mode = 1;
+ break;
+ case EXYNOS4x12_HOST:
+ phypwr = EXYNOS_4x12_UPHYPWR_PHY1;
+ rstbits = EXYNOS_4x12_URSTCON_HOST_PHY;
+ mode = EXYNOS_4x12_MODE_SWITCH_HOST;
+ switch_mode = 1;
+ break;
+ case EXYNOS4x12_HSIC0:
+ phypwr = EXYNOS_4x12_UPHYPWR_HSIC0;
+ rstbits = EXYNOS_4x12_URSTCON_HSIC1 |
+ EXYNOS_4x12_URSTCON_HOST_LINK_P0 |
+ EXYNOS_4x12_URSTCON_HOST_PHY;
+ break;
+ case EXYNOS4x12_HSIC1:
+ phypwr = EXYNOS_4x12_UPHYPWR_HSIC1;
+ rstbits = EXYNOS_4x12_URSTCON_HSIC1 |
+ EXYNOS_4x12_URSTCON_HOST_LINK_P1;
+ break;
+ };
+
+ if (on) {
+ if (switch_mode)
+ regmap_update_bits(drv->reg_sys,
+ EXYNOS_4x12_MODE_SWITCH_OFFSET,
+ EXYNOS_4x12_MODE_SWITCH_MASK, mode);
+
+ pwr = readl(drv->reg_phy + EXYNOS_4x12_UPHYPWR);
+ pwr &= ~phypwr;
+ writel(pwr, drv->reg_phy + EXYNOS_4x12_UPHYPWR);
+
+ rst = readl(drv->reg_phy + EXYNOS_4x12_UPHYRST);
+ rst |= rstbits;
+ writel(rst, drv->reg_phy + EXYNOS_4x12_UPHYRST);
+ udelay(10);
+ rst &= ~rstbits;
+ writel(rst, drv->reg_phy + EXYNOS_4x12_UPHYRST);
+ /* The following delay is necessary for the reset sequence to be
+ * completed */
+ udelay(80);
+ } else {
+ pwr = readl(drv->reg_phy + EXYNOS_4x12_UPHYPWR);
+ pwr |= phypwr;
+ writel(pwr, drv->reg_phy + EXYNOS_4x12_UPHYPWR);
+ }
+}
+
+static int exynos4x12_power_on(struct samsung_usb2_phy_instance *inst)
+{
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+
+ inst->enabled = 1;
+ exynos4x12_setup_clk(inst);
+ exynos4x12_phy_pwr(inst, 1);
+ exynos4x12_isol(inst, 0);
+
+ /* Power on the device, as it is necessary for HSIC to work */
+ if (inst->cfg->id == EXYNOS4x12_HSIC0) {
+ struct samsung_usb2_phy_instance *device =
+ &drv->instances[EXYNOS4x12_DEVICE];
+ exynos4x12_phy_pwr(device, 1);
+ exynos4x12_isol(device, 0);
+ }
+
+ return 0;
+}
+
+static int exynos4x12_power_off(struct samsung_usb2_phy_instance *inst)
+{
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ struct samsung_usb2_phy_instance *device =
+ &drv->instances[EXYNOS4x12_DEVICE];
+
+ inst->enabled = 0;
+ exynos4x12_isol(inst, 1);
+ exynos4x12_phy_pwr(inst, 0);
+
+ if (inst->cfg->id == EXYNOS4x12_HSIC0 && !device->enabled) {
+ exynos4x12_isol(device, 1);
+ exynos4x12_phy_pwr(device, 0);
+ }
+
+ return 0;
+}
+
+
+static const struct samsung_usb2_common_phy exynos4x12_phys[] = {
+ {
+ .label = "device",
+ .id = EXYNOS4x12_DEVICE,
+ .power_on = exynos4x12_power_on,
+ .power_off = exynos4x12_power_off,
+ },
+ {
+ .label = "host",
+ .id = EXYNOS4x12_HOST,
+ .power_on = exynos4x12_power_on,
+ .power_off = exynos4x12_power_off,
+ },
+ {
+ .label = "hsic0",
+ .id = EXYNOS4x12_HSIC0,
+ .power_on = exynos4x12_power_on,
+ .power_off = exynos4x12_power_off,
+ },
+ {
+ .label = "hsic1",
+ .id = EXYNOS4x12_HSIC1,
+ .power_on = exynos4x12_power_on,
+ .power_off = exynos4x12_power_off,
+ },
+ {},
+};
+
+const struct samsung_usb2_phy_config exynos4x12_usb2_phy_config = {
+ .has_mode_switch = 1,
+ .num_phys = EXYNOS4x12_NUM_PHYS,
+ .phys = exynos4x12_phys,
+ .rate_to_clk = exynos4x12_rate_to_clk,
+};
diff --git a/drivers/phy/phy-exynos5250-sata.c b/drivers/phy/phy-exynos5250-sata.c
new file mode 100644
index 000000000000..c9361b731fa6
--- /dev/null
+++ b/drivers/phy/phy-exynos5250-sata.c
@@ -0,0 +1,251 @@
+/*
+ * Samsung SATA SerDes(PHY) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Authors: Girish K S <ks.giri@samsung.com>
+ * Yuvaraj Kumar C D <yuvaraj.cd@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/spinlock.h>
+#include <linux/mfd/syscon.h>
+
+#define SATAPHY_CONTROL_OFFSET 0x0724
+#define EXYNOS5_SATAPHY_PMU_ENABLE BIT(0)
+#define EXYNOS5_SATA_RESET 0x4
+#define RESET_GLOBAL_RST_N BIT(0)
+#define RESET_CMN_RST_N BIT(1)
+#define RESET_CMN_BLOCK_RST_N BIT(2)
+#define RESET_CMN_I2C_RST_N BIT(3)
+#define RESET_TX_RX_PIPE_RST_N BIT(4)
+#define RESET_TX_RX_BLOCK_RST_N BIT(5)
+#define RESET_TX_RX_I2C_RST_N (BIT(6) | BIT(7))
+#define LINK_RESET 0xf0000
+#define EXYNOS5_SATA_MODE0 0x10
+#define SATA_SPD_GEN3 BIT(1)
+#define EXYNOS5_SATA_CTRL0 0x14
+#define CTRL0_P0_PHY_CALIBRATED_SEL BIT(9)
+#define CTRL0_P0_PHY_CALIBRATED BIT(8)
+#define EXYNOS5_SATA_PHSATA_CTRLM 0xe0
+#define PHCTRLM_REF_RATE BIT(1)
+#define PHCTRLM_HIGH_SPEED BIT(0)
+#define EXYNOS5_SATA_PHSATA_STATM 0xf0
+#define PHSTATM_PLL_LOCKED BIT(0)
+
+#define PHY_PLL_TIMEOUT (usecs_to_jiffies(1000))
+
+struct exynos_sata_phy {
+ struct phy *phy;
+ struct clk *phyclk;
+ void __iomem *regs;
+ struct regmap *pmureg;
+ struct i2c_client *client;
+};
+
+static int wait_for_reg_status(void __iomem *base, u32 reg, u32 checkbit,
+ u32 status)
+{
+ unsigned long timeout = jiffies + PHY_PLL_TIMEOUT;
+
+ while (time_before(jiffies, timeout)) {
+ if ((readl(base + reg) & checkbit) == status)
+ return 0;
+ }
+
+ return -EFAULT;
+}
+
+static int exynos_sata_phy_power_on(struct phy *phy)
+{
+ struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy);
+
+ return regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET,
+ EXYNOS5_SATAPHY_PMU_ENABLE, true);
+
+}
+
+static int exynos_sata_phy_power_off(struct phy *phy)
+{
+ struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy);
+
+ return regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET,
+ EXYNOS5_SATAPHY_PMU_ENABLE, false);
+
+}
+
+static int exynos_sata_phy_init(struct phy *phy)
+{
+ u32 val = 0;
+ int ret = 0;
+ u8 buf[] = { 0x3a, 0x0b };
+ struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy);
+
+ ret = regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET,
+ EXYNOS5_SATAPHY_PMU_ENABLE, true);
+ if (ret != 0)
+ dev_err(&sata_phy->phy->dev, "phy init failed\n");
+
+ writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
+
+ val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
+ val |= RESET_GLOBAL_RST_N | RESET_CMN_RST_N | RESET_CMN_BLOCK_RST_N
+ | RESET_CMN_I2C_RST_N | RESET_TX_RX_PIPE_RST_N
+ | RESET_TX_RX_BLOCK_RST_N | RESET_TX_RX_I2C_RST_N;
+ writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
+
+ val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
+ val |= LINK_RESET;
+ writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
+
+ val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
+ val |= RESET_CMN_RST_N;
+ writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
+
+ val = readl(sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
+ val &= ~PHCTRLM_REF_RATE;
+ writel(val, sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
+
+ /* High speed enable for Gen3 */
+ val = readl(sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
+ val |= PHCTRLM_HIGH_SPEED;
+ writel(val, sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
+
+ val = readl(sata_phy->regs + EXYNOS5_SATA_CTRL0);
+ val |= CTRL0_P0_PHY_CALIBRATED_SEL | CTRL0_P0_PHY_CALIBRATED;
+ writel(val, sata_phy->regs + EXYNOS5_SATA_CTRL0);
+
+ val = readl(sata_phy->regs + EXYNOS5_SATA_MODE0);
+ val |= SATA_SPD_GEN3;
+ writel(val, sata_phy->regs + EXYNOS5_SATA_MODE0);
+
+ ret = i2c_master_send(sata_phy->client, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ /* release cmu reset */
+ val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
+ val &= ~RESET_CMN_RST_N;
+ writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
+
+ val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
+ val |= RESET_CMN_RST_N;
+ writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
+
+ ret = wait_for_reg_status(sata_phy->regs,
+ EXYNOS5_SATA_PHSATA_STATM,
+ PHSTATM_PLL_LOCKED, 1);
+ if (ret < 0)
+ dev_err(&sata_phy->phy->dev,
+ "PHY PLL locking failed\n");
+ return ret;
+}
+
+static struct phy_ops exynos_sata_phy_ops = {
+ .init = exynos_sata_phy_init,
+ .power_on = exynos_sata_phy_power_on,
+ .power_off = exynos_sata_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static int exynos_sata_phy_probe(struct platform_device *pdev)
+{
+ struct exynos_sata_phy *sata_phy;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct phy_provider *phy_provider;
+ struct device_node *node;
+ int ret = 0;
+
+ sata_phy = devm_kzalloc(dev, sizeof(*sata_phy), GFP_KERNEL);
+ if (!sata_phy)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ sata_phy->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(sata_phy->regs))
+ return PTR_ERR(sata_phy->regs);
+
+ sata_phy->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "samsung,syscon-phandle");
+ if (IS_ERR(sata_phy->pmureg)) {
+ dev_err(dev, "syscon regmap lookup failed.\n");
+ return PTR_ERR(sata_phy->pmureg);
+ }
+
+ node = of_parse_phandle(dev->of_node,
+ "samsung,exynos-sataphy-i2c-phandle", 0);
+ if (!node)
+ return -EINVAL;
+
+ sata_phy->client = of_find_i2c_device_by_node(node);
+ if (!sata_phy->client)
+ return -EPROBE_DEFER;
+
+ dev_set_drvdata(dev, sata_phy);
+
+ sata_phy->phyclk = devm_clk_get(dev, "sata_phyctrl");
+ if (IS_ERR(sata_phy->phyclk)) {
+ dev_err(dev, "failed to get clk for PHY\n");
+ return PTR_ERR(sata_phy->phyclk);
+ }
+
+ ret = clk_prepare_enable(sata_phy->phyclk);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable source clk\n");
+ return ret;
+ }
+
+ sata_phy->phy = devm_phy_create(dev, &exynos_sata_phy_ops, NULL);
+ if (IS_ERR(sata_phy->phy)) {
+ clk_disable_unprepare(sata_phy->phyclk);
+ dev_err(dev, "failed to create PHY\n");
+ return PTR_ERR(sata_phy->phy);
+ }
+
+ phy_set_drvdata(sata_phy->phy, sata_phy);
+
+ phy_provider = devm_of_phy_provider_register(dev,
+ of_phy_simple_xlate);
+ if (IS_ERR(phy_provider)) {
+ clk_disable_unprepare(sata_phy->phyclk);
+ return PTR_ERR(phy_provider);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id exynos_sata_phy_of_match[] = {
+ { .compatible = "samsung,exynos5250-sata-phy" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, exynos_sata_phy_of_match);
+
+static struct platform_driver exynos_sata_phy_driver = {
+ .probe = exynos_sata_phy_probe,
+ .driver = {
+ .of_match_table = exynos_sata_phy_of_match,
+ .name = "samsung,sata-phy",
+ .owner = THIS_MODULE,
+ }
+};
+module_platform_driver(exynos_sata_phy_driver);
+
+MODULE_DESCRIPTION("Samsung SerDes PHY driver");
+MODULE_LICENSE("GPL V2");
+MODULE_AUTHOR("Girish K S <ks.giri@samsung.com>");
+MODULE_AUTHOR("Yuvaraj C D <yuvaraj.cd@samsung.com>");
diff --git a/drivers/phy/phy-exynos5250-usb2.c b/drivers/phy/phy-exynos5250-usb2.c
new file mode 100644
index 000000000000..94179afda951
--- /dev/null
+++ b/drivers/phy/phy-exynos5250-usb2.c
@@ -0,0 +1,404 @@
+/*
+ * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 5250 support
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Kamil Debski <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/phy/phy.h>
+#include <linux/regmap.h>
+#include "phy-samsung-usb2.h"
+
+/* Exynos USB PHY registers */
+#define EXYNOS_5250_REFCLKSEL_CRYSTAL 0x0
+#define EXYNOS_5250_REFCLKSEL_XO 0x1
+#define EXYNOS_5250_REFCLKSEL_CLKCORE 0x2
+
+#define EXYNOS_5250_FSEL_9MHZ6 0x0
+#define EXYNOS_5250_FSEL_10MHZ 0x1
+#define EXYNOS_5250_FSEL_12MHZ 0x2
+#define EXYNOS_5250_FSEL_19MHZ2 0x3
+#define EXYNOS_5250_FSEL_20MHZ 0x4
+#define EXYNOS_5250_FSEL_24MHZ 0x5
+#define EXYNOS_5250_FSEL_50MHZ 0x7
+
+/* Normal host */
+#define EXYNOS_5250_HOSTPHYCTRL0 0x0
+
+#define EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL BIT(31)
+#define EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_SHIFT 19
+#define EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_MASK \
+ (0x3 << EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_SHIFT)
+#define EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT 16
+#define EXYNOS_5250_HOSTPHYCTRL0_FSEL_MASK \
+ (0x7 << EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT)
+#define EXYNOS_5250_HOSTPHYCTRL0_TESTBURNIN BIT(11)
+#define EXYNOS_5250_HOSTPHYCTRL0_RETENABLE BIT(10)
+#define EXYNOS_5250_HOSTPHYCTRL0_COMMON_ON_N BIT(9)
+#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_MASK (0x3 << 7)
+#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_DUAL (0x0 << 7)
+#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_ID0 (0x1 << 7)
+#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_ANALOGTEST (0x2 << 7)
+#define EXYNOS_5250_HOSTPHYCTRL0_SIDDQ BIT(6)
+#define EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP BIT(5)
+#define EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND BIT(4)
+#define EXYNOS_5250_HOSTPHYCTRL0_WORDINTERFACE BIT(3)
+#define EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST BIT(2)
+#define EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST BIT(1)
+#define EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST BIT(0)
+
+/* HSIC0 & HSIC1 */
+#define EXYNOS_5250_HSICPHYCTRL1 0x10
+#define EXYNOS_5250_HSICPHYCTRL2 0x20
+
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKSEL_MASK (0x3 << 23)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKSEL_DEFAULT (0x2 << 23)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_MASK (0x7f << 16)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_12 (0x24 << 16)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_15 (0x1c << 16)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_16 (0x1a << 16)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_19_2 (0x15 << 16)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_20 (0x14 << 16)
+#define EXYNOS_5250_HSICPHYCTRLX_SIDDQ BIT(6)
+#define EXYNOS_5250_HSICPHYCTRLX_FORCESLEEP BIT(5)
+#define EXYNOS_5250_HSICPHYCTRLX_FORCESUSPEND BIT(4)
+#define EXYNOS_5250_HSICPHYCTRLX_WORDINTERFACE BIT(3)
+#define EXYNOS_5250_HSICPHYCTRLX_UTMISWRST BIT(2)
+#define EXYNOS_5250_HSICPHYCTRLX_PHYSWRST BIT(0)
+
+/* EHCI control */
+#define EXYNOS_5250_HOSTEHCICTRL 0x30
+#define EXYNOS_5250_HOSTEHCICTRL_ENAINCRXALIGN BIT(29)
+#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR4 BIT(28)
+#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR8 BIT(27)
+#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR16 BIT(26)
+#define EXYNOS_5250_HOSTEHCICTRL_AUTOPPDONOVRCUREN BIT(25)
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT 19
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_MASK \
+ (0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT)
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_SHIFT 13
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_MASK \
+ (0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_SHIFT)
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL2_SHIFT 7
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_MASK \
+ (0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT)
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_SHIFT 1
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_MASK \
+ (0x1 << EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_SHIFT)
+#define EXYNOS_5250_HOSTEHCICTRL_SIMULATIONMODE BIT(0)
+
+/* OHCI control */
+#define EXYNOS_5250_HOSTOHCICTRL 0x34
+#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_SHIFT 1
+#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_MASK \
+ (0x3ff << EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_SHIFT)
+#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVALEN BIT(0)
+
+/* USBOTG */
+#define EXYNOS_5250_USBOTGSYS 0x38
+#define EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET BIT(14)
+#define EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG BIT(13)
+#define EXYNOS_5250_USBOTGSYS_PHY_SW_RST BIT(12)
+#define EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT 9
+#define EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK \
+ (0x3 << EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT)
+#define EXYNOS_5250_USBOTGSYS_ID_PULLUP BIT(8)
+#define EXYNOS_5250_USBOTGSYS_COMMON_ON BIT(7)
+#define EXYNOS_5250_USBOTGSYS_FSEL_SHIFT 4
+#define EXYNOS_5250_USBOTGSYS_FSEL_MASK \
+ (0x3 << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT)
+#define EXYNOS_5250_USBOTGSYS_FORCE_SLEEP BIT(3)
+#define EXYNOS_5250_USBOTGSYS_OTGDISABLE BIT(2)
+#define EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG BIT(1)
+#define EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND BIT(0)
+
+/* Isolation, configured in the power management unit */
+#define EXYNOS_5250_USB_ISOL_OTG_OFFSET 0x704
+#define EXYNOS_5250_USB_ISOL_OTG BIT(0)
+#define EXYNOS_5250_USB_ISOL_HOST_OFFSET 0x708
+#define EXYNOS_5250_USB_ISOL_HOST BIT(0)
+
+/* Mode swtich register */
+#define EXYNOS_5250_MODE_SWITCH_OFFSET 0x230
+#define EXYNOS_5250_MODE_SWITCH_MASK 1
+#define EXYNOS_5250_MODE_SWITCH_DEVICE 0
+#define EXYNOS_5250_MODE_SWITCH_HOST 1
+
+enum exynos4x12_phy_id {
+ EXYNOS5250_DEVICE,
+ EXYNOS5250_HOST,
+ EXYNOS5250_HSIC0,
+ EXYNOS5250_HSIC1,
+ EXYNOS5250_NUM_PHYS,
+};
+
+/*
+ * exynos5250_rate_to_clk() converts the supplied clock rate to the value that
+ * can be written to the phy register.
+ */
+static int exynos5250_rate_to_clk(unsigned long rate, u32 *reg)
+{
+ /* EXYNOS_5250_FSEL_MASK */
+
+ switch (rate) {
+ case 9600 * KHZ:
+ *reg = EXYNOS_5250_FSEL_9MHZ6;
+ break;
+ case 10 * MHZ:
+ *reg = EXYNOS_5250_FSEL_10MHZ;
+ break;
+ case 12 * MHZ:
+ *reg = EXYNOS_5250_FSEL_12MHZ;
+ break;
+ case 19200 * KHZ:
+ *reg = EXYNOS_5250_FSEL_19MHZ2;
+ break;
+ case 20 * MHZ:
+ *reg = EXYNOS_5250_FSEL_20MHZ;
+ break;
+ case 24 * MHZ:
+ *reg = EXYNOS_5250_FSEL_24MHZ;
+ break;
+ case 50 * MHZ:
+ *reg = EXYNOS_5250_FSEL_50MHZ;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void exynos5250_isol(struct samsung_usb2_phy_instance *inst, bool on)
+{
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ u32 offset;
+ u32 mask;
+
+ switch (inst->cfg->id) {
+ case EXYNOS5250_DEVICE:
+ offset = EXYNOS_5250_USB_ISOL_OTG_OFFSET;
+ mask = EXYNOS_5250_USB_ISOL_OTG;
+ break;
+ case EXYNOS5250_HOST:
+ offset = EXYNOS_5250_USB_ISOL_HOST_OFFSET;
+ mask = EXYNOS_5250_USB_ISOL_HOST;
+ break;
+ default:
+ return;
+ };
+
+ regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
+}
+
+static int exynos5250_power_on(struct samsung_usb2_phy_instance *inst)
+{
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ u32 ctrl0;
+ u32 otg;
+ u32 ehci;
+ u32 ohci;
+ u32 hsic;
+
+ switch (inst->cfg->id) {
+ case EXYNOS5250_DEVICE:
+ regmap_update_bits(drv->reg_sys,
+ EXYNOS_5250_MODE_SWITCH_OFFSET,
+ EXYNOS_5250_MODE_SWITCH_MASK,
+ EXYNOS_5250_MODE_SWITCH_DEVICE);
+
+ /* OTG configuration */
+ otg = readl(drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+ /* The clock */
+ otg &= ~EXYNOS_5250_USBOTGSYS_FSEL_MASK;
+ otg |= drv->ref_reg_val << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT;
+ /* Reset */
+ otg &= ~(EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND |
+ EXYNOS_5250_USBOTGSYS_FORCE_SLEEP |
+ EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG);
+ otg |= EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
+ EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
+ EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
+ EXYNOS_5250_USBOTGSYS_OTGDISABLE;
+ /* Ref clock */
+ otg &= ~EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK;
+ otg |= EXYNOS_5250_REFCLKSEL_CLKCORE <<
+ EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT;
+ writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+ udelay(100);
+ otg &= ~(EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
+ EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
+ EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
+ EXYNOS_5250_USBOTGSYS_OTGDISABLE);
+ writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+
+
+ break;
+ case EXYNOS5250_HOST:
+ case EXYNOS5250_HSIC0:
+ case EXYNOS5250_HSIC1:
+ /* Host registers configuration */
+ ctrl0 = readl(drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
+ /* The clock */
+ ctrl0 &= ~EXYNOS_5250_HOSTPHYCTRL0_FSEL_MASK;
+ ctrl0 |= drv->ref_reg_val <<
+ EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT;
+
+ /* Reset */
+ ctrl0 &= ~(EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST |
+ EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL |
+ EXYNOS_5250_HOSTPHYCTRL0_SIDDQ |
+ EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND |
+ EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP);
+ ctrl0 |= EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST |
+ EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST |
+ EXYNOS_5250_HOSTPHYCTRL0_COMMON_ON_N;
+ writel(ctrl0, drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
+ udelay(10);
+ ctrl0 &= ~(EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST |
+ EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST);
+ writel(ctrl0, drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
+
+ /* OTG configuration */
+ otg = readl(drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+ /* The clock */
+ otg &= ~EXYNOS_5250_USBOTGSYS_FSEL_MASK;
+ otg |= drv->ref_reg_val << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT;
+ /* Reset */
+ otg &= ~(EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND |
+ EXYNOS_5250_USBOTGSYS_FORCE_SLEEP |
+ EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG);
+ otg |= EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
+ EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
+ EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
+ EXYNOS_5250_USBOTGSYS_OTGDISABLE;
+ /* Ref clock */
+ otg &= ~EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK;
+ otg |= EXYNOS_5250_REFCLKSEL_CLKCORE <<
+ EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT;
+ writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+ udelay(10);
+ otg &= ~(EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
+ EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
+ EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET);
+
+ /* HSIC phy configuration */
+ hsic = (EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_12 |
+ EXYNOS_5250_HSICPHYCTRLX_REFCLKSEL_DEFAULT |
+ EXYNOS_5250_HSICPHYCTRLX_PHYSWRST);
+ writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL1);
+ writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL2);
+ udelay(10);
+ hsic &= ~EXYNOS_5250_HSICPHYCTRLX_PHYSWRST;
+ writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL1);
+ writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL2);
+ /* The following delay is necessary for the reset sequence to be
+ * completed */
+ udelay(80);
+
+ /* Enable EHCI DMA burst */
+ ehci = readl(drv->reg_phy + EXYNOS_5250_HOSTEHCICTRL);
+ ehci |= EXYNOS_5250_HOSTEHCICTRL_ENAINCRXALIGN |
+ EXYNOS_5250_HOSTEHCICTRL_ENAINCR4 |
+ EXYNOS_5250_HOSTEHCICTRL_ENAINCR8 |
+ EXYNOS_5250_HOSTEHCICTRL_ENAINCR16;
+ writel(ehci, drv->reg_phy + EXYNOS_5250_HOSTEHCICTRL);
+
+ /* OHCI settings */
+ ohci = readl(drv->reg_phy + EXYNOS_5250_HOSTOHCICTRL);
+ /* Following code is based on the old driver */
+ ohci |= 0x1 << 3;
+ writel(ohci, drv->reg_phy + EXYNOS_5250_HOSTOHCICTRL);
+
+ break;
+ }
+ inst->enabled = 1;
+ exynos5250_isol(inst, 0);
+
+ return 0;
+}
+
+static int exynos5250_power_off(struct samsung_usb2_phy_instance *inst)
+{
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ u32 ctrl0;
+ u32 otg;
+ u32 hsic;
+
+ inst->enabled = 0;
+ exynos5250_isol(inst, 1);
+
+ switch (inst->cfg->id) {
+ case EXYNOS5250_DEVICE:
+ otg = readl(drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+ otg |= (EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND |
+ EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG |
+ EXYNOS_5250_USBOTGSYS_FORCE_SLEEP);
+ writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+ break;
+ case EXYNOS5250_HOST:
+ ctrl0 = readl(drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
+ ctrl0 |= (EXYNOS_5250_HOSTPHYCTRL0_SIDDQ |
+ EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND |
+ EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP |
+ EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST |
+ EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL);
+ writel(ctrl0, drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
+ break;
+ case EXYNOS5250_HSIC0:
+ case EXYNOS5250_HSIC1:
+ hsic = (EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_12 |
+ EXYNOS_5250_HSICPHYCTRLX_REFCLKSEL_DEFAULT |
+ EXYNOS_5250_HSICPHYCTRLX_SIDDQ |
+ EXYNOS_5250_HSICPHYCTRLX_FORCESLEEP |
+ EXYNOS_5250_HSICPHYCTRLX_FORCESUSPEND
+ );
+ writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL1);
+ writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL2);
+ break;
+ }
+
+ return 0;
+}
+
+
+static const struct samsung_usb2_common_phy exynos5250_phys[] = {
+ {
+ .label = "device",
+ .id = EXYNOS5250_DEVICE,
+ .power_on = exynos5250_power_on,
+ .power_off = exynos5250_power_off,
+ },
+ {
+ .label = "host",
+ .id = EXYNOS5250_HOST,
+ .power_on = exynos5250_power_on,
+ .power_off = exynos5250_power_off,
+ },
+ {
+ .label = "hsic0",
+ .id = EXYNOS5250_HSIC0,
+ .power_on = exynos5250_power_on,
+ .power_off = exynos5250_power_off,
+ },
+ {
+ .label = "hsic1",
+ .id = EXYNOS5250_HSIC1,
+ .power_on = exynos5250_power_on,
+ .power_off = exynos5250_power_off,
+ },
+ {},
+};
+
+const struct samsung_usb2_phy_config exynos5250_usb2_phy_config = {
+ .has_mode_switch = 1,
+ .num_phys = EXYNOS5250_NUM_PHYS,
+ .phys = exynos5250_phys,
+ .rate_to_clk = exynos5250_rate_to_clk,
+};
diff --git a/drivers/phy/phy-mvebu-sata.c b/drivers/phy/phy-mvebu-sata.c
index d43786f62437..d70ecd6a1b3f 100644
--- a/drivers/phy/phy-mvebu-sata.c
+++ b/drivers/phy/phy-mvebu-sata.c
@@ -99,17 +99,17 @@ static int phy_mvebu_sata_probe(struct platform_device *pdev)
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);
- phy_provider = devm_of_phy_provider_register(&pdev->dev,
- of_phy_simple_xlate);
- if (IS_ERR(phy_provider))
- return PTR_ERR(phy_provider);
-
phy = devm_phy_create(&pdev->dev, &phy_mvebu_sata_ops, NULL);
if (IS_ERR(phy))
return PTR_ERR(phy);
phy_set_drvdata(phy, priv);
+ phy_provider = devm_of_phy_provider_register(&pdev->dev,
+ of_phy_simple_xlate);
+ if (IS_ERR(phy_provider))
+ return PTR_ERR(phy_provider);
+
/* The boot loader may of left it on. Turn it off. */
phy_mvebu_sata_power_off(phy);
diff --git a/drivers/usb/phy/phy-omap-control.c b/drivers/phy/phy-omap-control.c
index e7253182e47d..311b4f9a5132 100644
--- a/drivers/usb/phy/phy-omap-control.c
+++ b/drivers/phy/phy-omap-control.c
@@ -1,5 +1,5 @@
/*
- * omap-control-usb.c - The USB part of control module.
+ * omap-control-phy.c - The PHY part of control module.
*
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
* This program is free software; you can redistribute it and/or modify
@@ -24,36 +24,36 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/clk.h>
-#include <linux/usb/omap_control_usb.h>
+#include <linux/phy/omap_control_phy.h>
/**
- * omap_control_usb_phy_power - power on/off the phy using control module reg
+ * omap_control_phy_power - power on/off the phy using control module reg
* @dev: the control module device
* @on: 0 or 1, based on powering on or off the PHY
*/
-void omap_control_usb_phy_power(struct device *dev, int on)
+void omap_control_phy_power(struct device *dev, int on)
{
u32 val;
unsigned long rate;
- struct omap_control_usb *control_usb;
+ struct omap_control_phy *control_phy;
if (IS_ERR(dev) || !dev) {
pr_err("%s: invalid device\n", __func__);
return;
}
- control_usb = dev_get_drvdata(dev);
- if (!control_usb) {
- dev_err(dev, "%s: invalid control usb device\n", __func__);
+ control_phy = dev_get_drvdata(dev);
+ if (!control_phy) {
+ dev_err(dev, "%s: invalid control phy device\n", __func__);
return;
}
- if (control_usb->type == OMAP_CTRL_TYPE_OTGHS)
+ if (control_phy->type == OMAP_CTRL_TYPE_OTGHS)
return;
- val = readl(control_usb->power);
+ val = readl(control_phy->power);
- switch (control_usb->type) {
+ switch (control_phy->type) {
case OMAP_CTRL_TYPE_USB2:
if (on)
val &= ~OMAP_CTRL_DEV_PHY_PD;
@@ -62,19 +62,20 @@ void omap_control_usb_phy_power(struct device *dev, int on)
break;
case OMAP_CTRL_TYPE_PIPE3:
- rate = clk_get_rate(control_usb->sys_clk);
+ rate = clk_get_rate(control_phy->sys_clk);
rate = rate/1000000;
if (on) {
- val &= ~(OMAP_CTRL_USB_PWRCTL_CLK_CMD_MASK |
- OMAP_CTRL_USB_PWRCTL_CLK_FREQ_MASK);
- val |= OMAP_CTRL_USB3_PHY_TX_RX_POWERON <<
- OMAP_CTRL_USB_PWRCTL_CLK_CMD_SHIFT;
- val |= rate << OMAP_CTRL_USB_PWRCTL_CLK_FREQ_SHIFT;
+ val &= ~(OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK |
+ OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK);
+ val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWERON <<
+ OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
+ val |= rate <<
+ OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT;
} else {
- val &= ~OMAP_CTRL_USB_PWRCTL_CLK_CMD_MASK;
- val |= OMAP_CTRL_USB3_PHY_TX_RX_POWEROFF <<
- OMAP_CTRL_USB_PWRCTL_CLK_CMD_SHIFT;
+ val &= ~OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK;
+ val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF <<
+ OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
}
break;
@@ -100,66 +101,66 @@ void omap_control_usb_phy_power(struct device *dev, int on)
break;
default:
dev_err(dev, "%s: type %d not recognized\n",
- __func__, control_usb->type);
+ __func__, control_phy->type);
break;
}
- writel(val, control_usb->power);
+ writel(val, control_phy->power);
}
-EXPORT_SYMBOL_GPL(omap_control_usb_phy_power);
+EXPORT_SYMBOL_GPL(omap_control_phy_power);
/**
* omap_control_usb_host_mode - set AVALID, VBUSVALID and ID pin in grounded
- * @ctrl_usb: struct omap_control_usb *
+ * @ctrl_phy: struct omap_control_phy *
*
* Writes to the mailbox register to notify the usb core that a usb
* device has been connected.
*/
-static void omap_control_usb_host_mode(struct omap_control_usb *ctrl_usb)
+static void omap_control_usb_host_mode(struct omap_control_phy *ctrl_phy)
{
u32 val;
- val = readl(ctrl_usb->otghs_control);
+ val = readl(ctrl_phy->otghs_control);
val &= ~(OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_SESSEND);
val |= OMAP_CTRL_DEV_AVALID | OMAP_CTRL_DEV_VBUSVALID;
- writel(val, ctrl_usb->otghs_control);
+ writel(val, ctrl_phy->otghs_control);
}
/**
* omap_control_usb_device_mode - set AVALID, VBUSVALID and ID pin in high
* impedance
- * @ctrl_usb: struct omap_control_usb *
+ * @ctrl_phy: struct omap_control_phy *
*
* Writes to the mailbox register to notify the usb core that it has been
* connected to a usb host.
*/
-static void omap_control_usb_device_mode(struct omap_control_usb *ctrl_usb)
+static void omap_control_usb_device_mode(struct omap_control_phy *ctrl_phy)
{
u32 val;
- val = readl(ctrl_usb->otghs_control);
+ val = readl(ctrl_phy->otghs_control);
val &= ~OMAP_CTRL_DEV_SESSEND;
val |= OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_AVALID |
OMAP_CTRL_DEV_VBUSVALID;
- writel(val, ctrl_usb->otghs_control);
+ writel(val, ctrl_phy->otghs_control);
}
/**
* omap_control_usb_set_sessionend - Enable SESSIONEND and IDIG to high
* impedance
- * @ctrl_usb: struct omap_control_usb *
+ * @ctrl_phy: struct omap_control_phy *
*
* Writes to the mailbox register to notify the usb core it's now in
* disconnected state.
*/
-static void omap_control_usb_set_sessionend(struct omap_control_usb *ctrl_usb)
+static void omap_control_usb_set_sessionend(struct omap_control_phy *ctrl_phy)
{
u32 val;
- val = readl(ctrl_usb->otghs_control);
+ val = readl(ctrl_phy->otghs_control);
val &= ~(OMAP_CTRL_DEV_AVALID | OMAP_CTRL_DEV_VBUSVALID);
val |= OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_SESSEND;
- writel(val, ctrl_usb->otghs_control);
+ writel(val, ctrl_phy->otghs_control);
}
/**
@@ -174,30 +175,30 @@ static void omap_control_usb_set_sessionend(struct omap_control_usb *ctrl_usb)
void omap_control_usb_set_mode(struct device *dev,
enum omap_control_usb_mode mode)
{
- struct omap_control_usb *ctrl_usb;
+ struct omap_control_phy *ctrl_phy;
if (IS_ERR(dev) || !dev)
return;
- ctrl_usb = dev_get_drvdata(dev);
+ ctrl_phy = dev_get_drvdata(dev);
- if (!ctrl_usb) {
- dev_err(dev, "Invalid control usb device\n");
+ if (!ctrl_phy) {
+ dev_err(dev, "Invalid control phy device\n");
return;
}
- if (ctrl_usb->type != OMAP_CTRL_TYPE_OTGHS)
+ if (ctrl_phy->type != OMAP_CTRL_TYPE_OTGHS)
return;
switch (mode) {
case USB_MODE_HOST:
- omap_control_usb_host_mode(ctrl_usb);
+ omap_control_usb_host_mode(ctrl_phy);
break;
case USB_MODE_DEVICE:
- omap_control_usb_device_mode(ctrl_usb);
+ omap_control_usb_device_mode(ctrl_phy);
break;
case USB_MODE_DISCONNECT:
- omap_control_usb_set_sessionend(ctrl_usb);
+ omap_control_usb_set_sessionend(ctrl_phy);
break;
default:
dev_vdbg(dev, "invalid omap control usb mode\n");
@@ -207,13 +208,13 @@ EXPORT_SYMBOL_GPL(omap_control_usb_set_mode);
#ifdef CONFIG_OF
-static const enum omap_control_usb_type otghs_data = OMAP_CTRL_TYPE_OTGHS;
-static const enum omap_control_usb_type usb2_data = OMAP_CTRL_TYPE_USB2;
-static const enum omap_control_usb_type pipe3_data = OMAP_CTRL_TYPE_PIPE3;
-static const enum omap_control_usb_type dra7usb2_data = OMAP_CTRL_TYPE_DRA7USB2;
-static const enum omap_control_usb_type am437usb2_data = OMAP_CTRL_TYPE_AM437USB2;
+static const enum omap_control_phy_type otghs_data = OMAP_CTRL_TYPE_OTGHS;
+static const enum omap_control_phy_type usb2_data = OMAP_CTRL_TYPE_USB2;
+static const enum omap_control_phy_type pipe3_data = OMAP_CTRL_TYPE_PIPE3;
+static const enum omap_control_phy_type dra7usb2_data = OMAP_CTRL_TYPE_DRA7USB2;
+static const enum omap_control_phy_type am437usb2_data = OMAP_CTRL_TYPE_AM437USB2;
-static const struct of_device_id omap_control_usb_id_table[] = {
+static const struct of_device_id omap_control_phy_id_table[] = {
{
.compatible = "ti,control-phy-otghs",
.data = &otghs_data,
@@ -227,93 +228,93 @@ static const struct of_device_id omap_control_usb_id_table[] = {
.data = &pipe3_data,
},
{
- .compatible = "ti,control-phy-dra7usb2",
+ .compatible = "ti,control-phy-usb2-dra7",
.data = &dra7usb2_data,
},
{
- .compatible = "ti,control-phy-am437usb2",
+ .compatible = "ti,control-phy-usb2-am437",
.data = &am437usb2_data,
},
{},
};
-MODULE_DEVICE_TABLE(of, omap_control_usb_id_table);
+MODULE_DEVICE_TABLE(of, omap_control_phy_id_table);
#endif
-static int omap_control_usb_probe(struct platform_device *pdev)
+static int omap_control_phy_probe(struct platform_device *pdev)
{
struct resource *res;
const struct of_device_id *of_id;
- struct omap_control_usb *control_usb;
+ struct omap_control_phy *control_phy;
- of_id = of_match_device(of_match_ptr(omap_control_usb_id_table),
- &pdev->dev);
+ of_id = of_match_device(of_match_ptr(omap_control_phy_id_table),
+ &pdev->dev);
if (!of_id)
return -EINVAL;
- control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb),
+ control_phy = devm_kzalloc(&pdev->dev, sizeof(*control_phy),
GFP_KERNEL);
- if (!control_usb) {
- dev_err(&pdev->dev, "unable to alloc memory for control usb\n");
+ if (!control_phy) {
+ dev_err(&pdev->dev, "unable to alloc memory for control phy\n");
return -ENOMEM;
}
- control_usb->dev = &pdev->dev;
- control_usb->type = *(enum omap_control_usb_type *)of_id->data;
+ control_phy->dev = &pdev->dev;
+ control_phy->type = *(enum omap_control_phy_type *)of_id->data;
- if (control_usb->type == OMAP_CTRL_TYPE_OTGHS) {
+ if (control_phy->type == OMAP_CTRL_TYPE_OTGHS) {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"otghs_control");
- control_usb->otghs_control = devm_ioremap_resource(
+ control_phy->otghs_control = devm_ioremap_resource(
&pdev->dev, res);
- if (IS_ERR(control_usb->otghs_control))
- return PTR_ERR(control_usb->otghs_control);
+ if (IS_ERR(control_phy->otghs_control))
+ return PTR_ERR(control_phy->otghs_control);
} else {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"power");
- control_usb->power = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(control_usb->power)) {
+ control_phy->power = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(control_phy->power)) {
dev_err(&pdev->dev, "Couldn't get power register\n");
- return PTR_ERR(control_usb->power);
+ return PTR_ERR(control_phy->power);
}
}
- if (control_usb->type == OMAP_CTRL_TYPE_PIPE3) {
- control_usb->sys_clk = devm_clk_get(control_usb->dev,
+ if (control_phy->type == OMAP_CTRL_TYPE_PIPE3) {
+ control_phy->sys_clk = devm_clk_get(control_phy->dev,
"sys_clkin");
- if (IS_ERR(control_usb->sys_clk)) {
+ if (IS_ERR(control_phy->sys_clk)) {
pr_err("%s: unable to get sys_clkin\n", __func__);
return -EINVAL;
}
}
- dev_set_drvdata(control_usb->dev, control_usb);
+ dev_set_drvdata(control_phy->dev, control_phy);
return 0;
}
-static struct platform_driver omap_control_usb_driver = {
- .probe = omap_control_usb_probe,
+static struct platform_driver omap_control_phy_driver = {
+ .probe = omap_control_phy_probe,
.driver = {
- .name = "omap-control-usb",
+ .name = "omap-control-phy",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(omap_control_usb_id_table),
+ .of_match_table = of_match_ptr(omap_control_phy_id_table),
},
};
-static int __init omap_control_usb_init(void)
+static int __init omap_control_phy_init(void)
{
- return platform_driver_register(&omap_control_usb_driver);
+ return platform_driver_register(&omap_control_phy_driver);
}
-subsys_initcall(omap_control_usb_init);
+subsys_initcall(omap_control_phy_init);
-static void __exit omap_control_usb_exit(void)
+static void __exit omap_control_phy_exit(void)
{
- platform_driver_unregister(&omap_control_usb_driver);
+ platform_driver_unregister(&omap_control_phy_driver);
}
-module_exit(omap_control_usb_exit);
+module_exit(omap_control_phy_exit);
-MODULE_ALIAS("platform: omap_control_usb");
+MODULE_ALIAS("platform: omap_control_phy");
MODULE_AUTHOR("Texas Instruments Inc.");
-MODULE_DESCRIPTION("OMAP Control Module USB Driver");
+MODULE_DESCRIPTION("OMAP Control Module PHY Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c
index bfc5c337f99a..a2205a841e5e 100644
--- a/drivers/phy/phy-omap-usb2.c
+++ b/drivers/phy/phy-omap-usb2.c
@@ -21,16 +21,19 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/io.h>
-#include <linux/usb/omap_usb.h>
+#include <linux/phy/omap_usb.h>
#include <linux/usb/phy_companion.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/pm_runtime.h>
#include <linux/delay.h>
-#include <linux/usb/omap_control_usb.h>
+#include <linux/phy/omap_control_phy.h>
#include <linux/phy/phy.h>
#include <linux/of_platform.h>
+#define USB2PHY_DISCON_BYP_LATCH (1 << 31)
+#define USB2PHY_ANA_CONFIG1 0x4c
+
/**
* omap_usb2_set_comparator - links the comparator present in the sytem with
* this phy
@@ -98,65 +101,116 @@ static int omap_usb_set_peripheral(struct usb_otg *otg,
return 0;
}
-static int omap_usb2_suspend(struct usb_phy *x, int suspend)
+static int omap_usb_power_off(struct phy *x)
{
- struct omap_usb *phy = phy_to_omapusb(x);
- int ret;
+ struct omap_usb *phy = phy_get_drvdata(x);
- if (suspend && !phy->is_suspended) {
- omap_control_usb_phy_power(phy->control_dev, 0);
- pm_runtime_put_sync(phy->dev);
- phy->is_suspended = 1;
- } 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);
- return ret;
- }
- omap_control_usb_phy_power(phy->control_dev, 1);
- phy->is_suspended = 0;
- }
+ omap_control_phy_power(phy->control_dev, 0);
return 0;
}
-static int omap_usb_power_off(struct phy *x)
+static int omap_usb_power_on(struct phy *x)
{
struct omap_usb *phy = phy_get_drvdata(x);
- omap_control_usb_phy_power(phy->control_dev, 0);
+ omap_control_phy_power(phy->control_dev, 1);
return 0;
}
-static int omap_usb_power_on(struct phy *x)
+static int omap_usb_init(struct phy *x)
{
struct omap_usb *phy = phy_get_drvdata(x);
-
- omap_control_usb_phy_power(phy->control_dev, 1);
+ u32 val;
+
+ if (phy->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) {
+ /*
+ *
+ * Reduce the sensitivity of internal PHY by enabling the
+ * DISCON_BYP_LATCH of the USB2PHY_ANA_CONFIG1 register. This
+ * resolves issues with certain devices which can otherwise
+ * be prone to false disconnects.
+ *
+ */
+ val = omap_usb_readl(phy->phy_base, USB2PHY_ANA_CONFIG1);
+ val |= USB2PHY_DISCON_BYP_LATCH;
+ omap_usb_writel(phy->phy_base, USB2PHY_ANA_CONFIG1, val);
+ }
return 0;
}
static struct phy_ops ops = {
+ .init = omap_usb_init,
.power_on = omap_usb_power_on,
.power_off = omap_usb_power_off,
.owner = THIS_MODULE,
};
+#ifdef CONFIG_OF
+static const struct usb_phy_data omap_usb2_data = {
+ .label = "omap_usb2",
+ .flags = OMAP_USB2_HAS_START_SRP | OMAP_USB2_HAS_SET_VBUS,
+};
+
+static const struct usb_phy_data omap5_usb2_data = {
+ .label = "omap5_usb2",
+ .flags = 0,
+};
+
+static const struct usb_phy_data dra7x_usb2_data = {
+ .label = "dra7x_usb2",
+ .flags = OMAP_USB2_CALIBRATE_FALSE_DISCONNECT,
+};
+
+static const struct usb_phy_data am437x_usb2_data = {
+ .label = "am437x_usb2",
+ .flags = 0,
+};
+
+static const struct of_device_id omap_usb2_id_table[] = {
+ {
+ .compatible = "ti,omap-usb2",
+ .data = &omap_usb2_data,
+ },
+ {
+ .compatible = "ti,omap5-usb2",
+ .data = &omap5_usb2_data,
+ },
+ {
+ .compatible = "ti,dra7x-usb2",
+ .data = &dra7x_usb2_data,
+ },
+ {
+ .compatible = "ti,am437x-usb2",
+ .data = &am437x_usb2_data,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, omap_usb2_id_table);
+#endif
+
static int omap_usb2_probe(struct platform_device *pdev)
{
struct omap_usb *phy;
struct phy *generic_phy;
+ struct resource *res;
struct phy_provider *phy_provider;
struct usb_otg *otg;
struct device_node *node = pdev->dev.of_node;
struct device_node *control_node;
struct platform_device *control_pdev;
+ const struct of_device_id *of_id;
+ struct usb_phy_data *phy_data;
+
+ of_id = of_match_device(of_match_ptr(omap_usb2_id_table), &pdev->dev);
- if (!node)
+ if (!of_id)
return -EINVAL;
+ phy_data = (struct usb_phy_data *)of_id->data;
+
phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
if (!phy) {
dev_err(&pdev->dev, "unable to allocate memory for USB2 PHY\n");
@@ -172,15 +226,17 @@ static int omap_usb2_probe(struct platform_device *pdev)
phy->dev = &pdev->dev;
phy->phy.dev = phy->dev;
- phy->phy.label = "omap-usb2";
- phy->phy.set_suspend = omap_usb2_suspend;
+ phy->phy.label = phy_data->label;
phy->phy.otg = otg;
phy->phy.type = USB_PHY_TYPE_USB2;
- phy_provider = devm_of_phy_provider_register(phy->dev,
- of_phy_simple_xlate);
- if (IS_ERR(phy_provider))
- return PTR_ERR(phy_provider);
+ if (phy_data->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ phy->phy_base = devm_ioremap_resource(&pdev->dev, res);
+ if (!phy->phy_base)
+ return -ENOMEM;
+ phy->flags |= OMAP_USB2_CALIBRATE_FALSE_DISCONNECT;
+ }
control_node = of_parse_phandle(node, "ctrl-module", 0);
if (!control_node) {
@@ -195,14 +251,14 @@ static int omap_usb2_probe(struct platform_device *pdev)
}
phy->control_dev = &control_pdev->dev;
-
- phy->is_suspended = 1;
- omap_control_usb_phy_power(phy->control_dev, 0);
+ omap_control_phy_power(phy->control_dev, 0);
otg->set_host = omap_usb_set_host;
otg->set_peripheral = omap_usb_set_peripheral;
- otg->set_vbus = omap_usb_set_vbus;
- otg->start_srp = omap_usb_start_srp;
+ if (phy_data->flags & OMAP_USB2_HAS_SET_VBUS)
+ otg->set_vbus = omap_usb_set_vbus;
+ if (phy_data->flags & OMAP_USB2_HAS_START_SRP)
+ otg->start_srp = omap_usb_start_srp;
otg->phy = &phy->phy;
platform_set_drvdata(pdev, phy);
@@ -214,6 +270,11 @@ static int omap_usb2_probe(struct platform_device *pdev)
phy_set_drvdata(generic_phy, phy);
+ phy_provider = devm_of_phy_provider_register(phy->dev,
+ of_phy_simple_xlate);
+ if (IS_ERR(phy_provider))
+ return PTR_ERR(phy_provider);
+
phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k");
if (IS_ERR(phy->wkupclk)) {
dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n");
@@ -297,14 +358,6 @@ static const struct dev_pm_ops omap_usb2_pm_ops = {
#define DEV_PM_OPS NULL
#endif
-#ifdef CONFIG_OF
-static const struct of_device_id omap_usb2_id_table[] = {
- { .compatible = "ti,omap-usb2" },
- {}
-};
-MODULE_DEVICE_TABLE(of, omap_usb2_id_table);
-#endif
-
static struct platform_driver omap_usb2_driver = {
.probe = omap_usb2_probe,
.remove = omap_usb2_remove,
diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c
new file mode 100644
index 000000000000..8a8c6bc8709a
--- /dev/null
+++ b/drivers/phy/phy-samsung-usb2.c
@@ -0,0 +1,228 @@
+/*
+ * Samsung SoC USB 1.1/2.0 PHY driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Kamil Debski <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include "phy-samsung-usb2.h"
+
+static int samsung_usb2_phy_power_on(struct phy *phy)
+{
+ struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ int ret;
+
+ dev_dbg(drv->dev, "Request to power_on \"%s\" usb phy\n",
+ inst->cfg->label);
+ ret = clk_prepare_enable(drv->clk);
+ if (ret)
+ goto err_main_clk;
+ ret = clk_prepare_enable(drv->ref_clk);
+ if (ret)
+ goto err_instance_clk;
+ if (inst->cfg->power_on) {
+ spin_lock(&drv->lock);
+ ret = inst->cfg->power_on(inst);
+ spin_unlock(&drv->lock);
+ }
+
+ return 0;
+
+err_instance_clk:
+ clk_disable_unprepare(drv->clk);
+err_main_clk:
+ return ret;
+}
+
+static int samsung_usb2_phy_power_off(struct phy *phy)
+{
+ struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ int ret = 0;
+
+ dev_dbg(drv->dev, "Request to power_off \"%s\" usb phy\n",
+ inst->cfg->label);
+ if (inst->cfg->power_off) {
+ spin_lock(&drv->lock);
+ ret = inst->cfg->power_off(inst);
+ spin_unlock(&drv->lock);
+ }
+ clk_disable_unprepare(drv->ref_clk);
+ clk_disable_unprepare(drv->clk);
+ return ret;
+}
+
+static struct phy_ops samsung_usb2_phy_ops = {
+ .power_on = samsung_usb2_phy_power_on,
+ .power_off = samsung_usb2_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static struct phy *samsung_usb2_phy_xlate(struct device *dev,
+ struct of_phandle_args *args)
+{
+ struct samsung_usb2_phy_driver *drv;
+
+ drv = dev_get_drvdata(dev);
+ if (!drv)
+ return ERR_PTR(-EINVAL);
+
+ if (WARN_ON(args->args[0] >= drv->cfg->num_phys))
+ return ERR_PTR(-ENODEV);
+
+ return drv->instances[args->args[0]].phy;
+}
+
+static const struct of_device_id samsung_usb2_phy_of_match[] = {
+#ifdef CONFIG_PHY_EXYNOS4210_USB2
+ {
+ .compatible = "samsung,exynos4210-usb2-phy",
+ .data = &exynos4210_usb2_phy_config,
+ },
+#endif
+#ifdef CONFIG_PHY_EXYNOS4X12_USB2
+ {
+ .compatible = "samsung,exynos4x12-usb2-phy",
+ .data = &exynos4x12_usb2_phy_config,
+ },
+#endif
+#ifdef CONFIG_PHY_EXYNOS5250_USB2
+ {
+ .compatible = "samsung,exynos5250-usb2-phy",
+ .data = &exynos5250_usb2_phy_config,
+ },
+#endif
+ { },
+};
+
+static int samsung_usb2_phy_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ const struct samsung_usb2_phy_config *cfg;
+ struct device *dev = &pdev->dev;
+ struct phy_provider *phy_provider;
+ struct resource *mem;
+ struct samsung_usb2_phy_driver *drv;
+ int i, ret;
+
+ if (!pdev->dev.of_node) {
+ dev_err(dev, "This driver is required to be instantiated from device tree\n");
+ return -EINVAL;
+ }
+
+ match = of_match_node(samsung_usb2_phy_of_match, pdev->dev.of_node);
+ if (!match) {
+ dev_err(dev, "of_match_node() failed\n");
+ return -EINVAL;
+ }
+ cfg = match->data;
+
+ drv = devm_kzalloc(dev, sizeof(struct samsung_usb2_phy_driver) +
+ cfg->num_phys * sizeof(struct samsung_usb2_phy_instance),
+ GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, drv);
+ spin_lock_init(&drv->lock);
+
+ drv->cfg = cfg;
+ drv->dev = dev;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ drv->reg_phy = devm_ioremap_resource(dev, mem);
+ if (IS_ERR(drv->reg_phy)) {
+ dev_err(dev, "Failed to map register memory (phy)\n");
+ return PTR_ERR(drv->reg_phy);
+ }
+
+ drv->reg_pmu = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "samsung,pmureg-phandle");
+ if (IS_ERR(drv->reg_pmu)) {
+ dev_err(dev, "Failed to map PMU registers (via syscon)\n");
+ return PTR_ERR(drv->reg_pmu);
+ }
+
+ if (drv->cfg->has_mode_switch) {
+ drv->reg_sys = syscon_regmap_lookup_by_phandle(
+ pdev->dev.of_node, "samsung,sysreg-phandle");
+ if (IS_ERR(drv->reg_sys)) {
+ dev_err(dev, "Failed to map system registers (via syscon)\n");
+ return PTR_ERR(drv->reg_sys);
+ }
+ }
+
+ drv->clk = devm_clk_get(dev, "phy");
+ if (IS_ERR(drv->clk)) {
+ dev_err(dev, "Failed to get clock of phy controller\n");
+ return PTR_ERR(drv->clk);
+ }
+
+ drv->ref_clk = devm_clk_get(dev, "ref");
+ if (IS_ERR(drv->ref_clk)) {
+ dev_err(dev, "Failed to get reference clock for the phy controller\n");
+ return PTR_ERR(drv->ref_clk);
+ }
+
+ drv->ref_rate = clk_get_rate(drv->ref_clk);
+ if (drv->cfg->rate_to_clk) {
+ ret = drv->cfg->rate_to_clk(drv->ref_rate, &drv->ref_reg_val);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < drv->cfg->num_phys; i++) {
+ char *label = drv->cfg->phys[i].label;
+ struct samsung_usb2_phy_instance *p = &drv->instances[i];
+
+ dev_dbg(dev, "Creating phy \"%s\"\n", label);
+ p->phy = devm_phy_create(dev, &samsung_usb2_phy_ops, NULL);
+ if (IS_ERR(p->phy)) {
+ dev_err(drv->dev, "Failed to create usb2_phy \"%s\"\n",
+ label);
+ return PTR_ERR(p->phy);
+ }
+
+ p->cfg = &drv->cfg->phys[i];
+ p->drv = drv;
+ phy_set_bus_width(p->phy, 8);
+ phy_set_drvdata(p->phy, p);
+ }
+
+ phy_provider = devm_of_phy_provider_register(dev,
+ samsung_usb2_phy_xlate);
+ if (IS_ERR(phy_provider)) {
+ dev_err(drv->dev, "Failed to register phy provider\n");
+ return PTR_ERR(phy_provider);
+ }
+
+ return 0;
+}
+
+static struct platform_driver samsung_usb2_phy_driver = {
+ .probe = samsung_usb2_phy_probe,
+ .driver = {
+ .of_match_table = samsung_usb2_phy_of_match,
+ .name = "samsung-usb2-phy",
+ .owner = THIS_MODULE,
+ }
+};
+
+module_platform_driver(samsung_usb2_phy_driver);
+MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC USB PHY driver");
+MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:samsung-usb2-phy");
diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h
new file mode 100644
index 000000000000..45b3170652bd
--- /dev/null
+++ b/drivers/phy/phy-samsung-usb2.h
@@ -0,0 +1,67 @@
+/*
+ * Samsung SoC USB 1.1/2.0 PHY driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Kamil Debski <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _PHY_EXYNOS_USB2_H
+#define _PHY_EXYNOS_USB2_H
+
+#include <linux/clk.h>
+#include <linux/phy/phy.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/spinlock.h>
+
+#define KHZ 1000
+#define MHZ (KHZ * KHZ)
+
+struct samsung_usb2_phy_driver;
+struct samsung_usb2_phy_instance;
+struct samsung_usb2_phy_config;
+
+struct samsung_usb2_phy_instance {
+ const struct samsung_usb2_common_phy *cfg;
+ struct phy *phy;
+ struct samsung_usb2_phy_driver *drv;
+ bool enabled;
+};
+
+struct samsung_usb2_phy_driver {
+ const struct samsung_usb2_phy_config *cfg;
+ struct clk *clk;
+ struct clk *ref_clk;
+ unsigned long ref_rate;
+ u32 ref_reg_val;
+ struct device *dev;
+ void __iomem *reg_phy;
+ struct regmap *reg_pmu;
+ struct regmap *reg_sys;
+ spinlock_t lock;
+ struct samsung_usb2_phy_instance instances[0];
+};
+
+struct samsung_usb2_common_phy {
+ int (*power_on)(struct samsung_usb2_phy_instance *);
+ int (*power_off)(struct samsung_usb2_phy_instance *);
+ unsigned int id;
+ char *label;
+};
+
+
+struct samsung_usb2_phy_config {
+ const struct samsung_usb2_common_phy *phys;
+ int (*rate_to_clk)(unsigned long, u32 *);
+ unsigned int num_phys;
+ bool has_mode_switch;
+};
+
+extern const struct samsung_usb2_phy_config exynos4210_usb2_phy_config;
+extern const struct samsung_usb2_phy_config exynos4x12_usb2_phy_config;
+extern const struct samsung_usb2_phy_config exynos5250_usb2_phy_config;
+#endif
diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c
new file mode 100644
index 000000000000..e6e6c4ba7145
--- /dev/null
+++ b/drivers/phy/phy-sun4i-usb.c
@@ -0,0 +1,331 @@
+/*
+ * Allwinner sun4i USB phy driver
+ *
+ * Copyright (C) 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on code from
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ *
+ * Modelled after: Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY driver
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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/clk.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+
+#define REG_ISCR 0x00
+#define REG_PHYCTL 0x04
+#define REG_PHYBIST 0x08
+#define REG_PHYTUNE 0x0c
+
+#define PHYCTL_DATA BIT(7)
+
+#define SUNXI_AHB_ICHR8_EN BIT(10)
+#define SUNXI_AHB_INCR4_BURST_EN BIT(9)
+#define SUNXI_AHB_INCRX_ALIGN_EN BIT(8)
+#define SUNXI_ULPI_BYPASS_EN BIT(0)
+
+/* Common Control Bits for Both PHYs */
+#define PHY_PLL_BW 0x03
+#define PHY_RES45_CAL_EN 0x0c
+
+/* Private Control Bits for Each PHY */
+#define PHY_TX_AMPLITUDE_TUNE 0x20
+#define PHY_TX_SLEWRATE_TUNE 0x22
+#define PHY_VBUSVALID_TH_SEL 0x25
+#define PHY_PULLUP_RES_SEL 0x27
+#define PHY_OTG_FUNC_EN 0x28
+#define PHY_VBUS_DET_EN 0x29
+#define PHY_DISCON_TH_SEL 0x2a
+
+#define MAX_PHYS 3
+
+struct sun4i_usb_phy_data {
+ struct clk *clk;
+ void __iomem *base;
+ struct mutex mutex;
+ int num_phys;
+ u32 disc_thresh;
+ struct sun4i_usb_phy {
+ struct phy *phy;
+ void __iomem *pmu;
+ struct regulator *vbus;
+ struct reset_control *reset;
+ int index;
+ } phys[MAX_PHYS];
+};
+
+#define to_sun4i_usb_phy_data(phy) \
+ container_of((phy), struct sun4i_usb_phy_data, phys[(phy)->index])
+
+static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data,
+ int len)
+{
+ struct sun4i_usb_phy_data *phy_data = to_sun4i_usb_phy_data(phy);
+ u32 temp, usbc_bit = BIT(phy->index * 2);
+ int i;
+
+ mutex_lock(&phy_data->mutex);
+
+ for (i = 0; i < len; i++) {
+ temp = readl(phy_data->base + REG_PHYCTL);
+
+ /* clear the address portion */
+ temp &= ~(0xff << 8);
+
+ /* set the address */
+ temp |= ((addr + i) << 8);
+ writel(temp, phy_data->base + REG_PHYCTL);
+
+ /* set the data bit and clear usbc bit*/
+ temp = readb(phy_data->base + REG_PHYCTL);
+ if (data & 0x1)
+ temp |= PHYCTL_DATA;
+ else
+ temp &= ~PHYCTL_DATA;
+ temp &= ~usbc_bit;
+ writeb(temp, phy_data->base + REG_PHYCTL);
+
+ /* pulse usbc_bit */
+ temp = readb(phy_data->base + REG_PHYCTL);
+ temp |= usbc_bit;
+ writeb(temp, phy_data->base + REG_PHYCTL);
+
+ temp = readb(phy_data->base + REG_PHYCTL);
+ temp &= ~usbc_bit;
+ writeb(temp, phy_data->base + REG_PHYCTL);
+
+ data >>= 1;
+ }
+ mutex_unlock(&phy_data->mutex);
+}
+
+static void sun4i_usb_phy_passby(struct sun4i_usb_phy *phy, int enable)
+{
+ u32 bits, reg_value;
+
+ if (!phy->pmu)
+ return;
+
+ bits = SUNXI_AHB_ICHR8_EN | SUNXI_AHB_INCR4_BURST_EN |
+ SUNXI_AHB_INCRX_ALIGN_EN | SUNXI_ULPI_BYPASS_EN;
+
+ reg_value = readl(phy->pmu);
+
+ if (enable)
+ reg_value |= bits;
+ else
+ reg_value &= ~bits;
+
+ writel(reg_value, phy->pmu);
+}
+
+static int sun4i_usb_phy_init(struct phy *_phy)
+{
+ struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
+ struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
+ int ret;
+
+ ret = clk_prepare_enable(data->clk);
+ if (ret)
+ return ret;
+
+ ret = reset_control_deassert(phy->reset);
+ if (ret) {
+ clk_disable_unprepare(data->clk);
+ return ret;
+ }
+
+ /* Adjust PHY's magnitude and rate */
+ sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5);
+
+ /* Disconnect threshold adjustment */
+ sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL, data->disc_thresh, 2);
+
+ sun4i_usb_phy_passby(phy, 1);
+
+ return 0;
+}
+
+static int sun4i_usb_phy_exit(struct phy *_phy)
+{
+ struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
+ struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
+
+ sun4i_usb_phy_passby(phy, 0);
+ reset_control_assert(phy->reset);
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+}
+
+static int sun4i_usb_phy_power_on(struct phy *_phy)
+{
+ struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
+ int ret = 0;
+
+ if (phy->vbus)
+ ret = regulator_enable(phy->vbus);
+
+ return ret;
+}
+
+static int sun4i_usb_phy_power_off(struct phy *_phy)
+{
+ struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
+
+ if (phy->vbus)
+ regulator_disable(phy->vbus);
+
+ return 0;
+}
+
+static struct phy_ops sun4i_usb_phy_ops = {
+ .init = sun4i_usb_phy_init,
+ .exit = sun4i_usb_phy_exit,
+ .power_on = sun4i_usb_phy_power_on,
+ .power_off = sun4i_usb_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static struct phy *sun4i_usb_phy_xlate(struct device *dev,
+ struct of_phandle_args *args)
+{
+ struct sun4i_usb_phy_data *data = dev_get_drvdata(dev);
+
+ if (WARN_ON(args->args[0] == 0 || args->args[0] >= data->num_phys))
+ return ERR_PTR(-ENODEV);
+
+ return data->phys[args->args[0]].phy;
+}
+
+static int sun4i_usb_phy_probe(struct platform_device *pdev)
+{
+ struct sun4i_usb_phy_data *data;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ void __iomem *pmu = NULL;
+ struct phy_provider *phy_provider;
+ struct reset_control *reset;
+ struct regulator *vbus;
+ struct resource *res;
+ struct phy *phy;
+ char name[16];
+ int i;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ mutex_init(&data->mutex);
+
+ if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy"))
+ data->num_phys = 2;
+ else
+ data->num_phys = 3;
+
+ if (of_device_is_compatible(np, "allwinner,sun4i-a10-usb-phy"))
+ data->disc_thresh = 3;
+ else
+ data->disc_thresh = 2;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl");
+ data->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(data->base))
+ return PTR_ERR(data->base);
+
+ data->clk = devm_clk_get(dev, "usb_phy");
+ if (IS_ERR(data->clk)) {
+ dev_err(dev, "could not get usb_phy clock\n");
+ return PTR_ERR(data->clk);
+ }
+
+ /* Skip 0, 0 is the phy for otg which is not yet supported. */
+ for (i = 1; i < data->num_phys; i++) {
+ snprintf(name, sizeof(name), "usb%d_vbus", i);
+ vbus = devm_regulator_get_optional(dev, name);
+ if (IS_ERR(vbus)) {
+ if (PTR_ERR(vbus) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ vbus = NULL;
+ }
+
+ snprintf(name, sizeof(name), "usb%d_reset", i);
+ reset = devm_reset_control_get(dev, name);
+ if (IS_ERR(reset)) {
+ dev_err(dev, "failed to get reset %s\n", name);
+ return PTR_ERR(reset);
+ }
+
+ if (i) { /* No pmu for usbc0 */
+ snprintf(name, sizeof(name), "pmu%d", i);
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, name);
+ pmu = devm_ioremap_resource(dev, res);
+ if (IS_ERR(pmu))
+ return PTR_ERR(pmu);
+ }
+
+ phy = devm_phy_create(dev, &sun4i_usb_phy_ops, NULL);
+ if (IS_ERR(phy)) {
+ dev_err(dev, "failed to create PHY %d\n", i);
+ return PTR_ERR(phy);
+ }
+
+ data->phys[i].phy = phy;
+ data->phys[i].pmu = pmu;
+ data->phys[i].vbus = vbus;
+ data->phys[i].reset = reset;
+ data->phys[i].index = i;
+ phy_set_drvdata(phy, &data->phys[i]);
+ }
+
+ dev_set_drvdata(dev, data);
+ phy_provider = devm_of_phy_provider_register(dev, sun4i_usb_phy_xlate);
+ if (IS_ERR(phy_provider))
+ return PTR_ERR(phy_provider);
+
+ return 0;
+}
+
+static const struct of_device_id sun4i_usb_phy_of_match[] = {
+ { .compatible = "allwinner,sun4i-a10-usb-phy" },
+ { .compatible = "allwinner,sun5i-a13-usb-phy" },
+ { .compatible = "allwinner,sun7i-a20-usb-phy" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match);
+
+static struct platform_driver sun4i_usb_phy_driver = {
+ .probe = sun4i_usb_phy_probe,
+ .driver = {
+ .of_match_table = sun4i_usb_phy_of_match,
+ .name = "sun4i-usb-phy",
+ .owner = THIS_MODULE,
+ }
+};
+module_platform_driver(sun4i_usb_phy_driver);
+
+MODULE_DESCRIPTION("Allwinner sun4i USB phy driver");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c
new file mode 100644
index 000000000000..591367654613
--- /dev/null
+++ b/drivers/phy/phy-ti-pipe3.c
@@ -0,0 +1,470 @@
+/*
+ * phy-ti-pipe3 - PIPE3 PHY driver.
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.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.
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/platform_device.h>
+#include <linux/slab.h>
+#include <linux/phy/phy.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <linux/phy/omap_control_phy.h>
+#include <linux/of_platform.h>
+
+#define PLL_STATUS 0x00000004
+#define PLL_GO 0x00000008
+#define PLL_CONFIGURATION1 0x0000000C
+#define PLL_CONFIGURATION2 0x00000010
+#define PLL_CONFIGURATION3 0x00000014
+#define PLL_CONFIGURATION4 0x00000020
+
+#define PLL_REGM_MASK 0x001FFE00
+#define PLL_REGM_SHIFT 0x9
+#define PLL_REGM_F_MASK 0x0003FFFF
+#define PLL_REGM_F_SHIFT 0x0
+#define PLL_REGN_MASK 0x000001FE
+#define PLL_REGN_SHIFT 0x1
+#define PLL_SELFREQDCO_MASK 0x0000000E
+#define PLL_SELFREQDCO_SHIFT 0x1
+#define PLL_SD_MASK 0x0003FC00
+#define PLL_SD_SHIFT 10
+#define SET_PLL_GO 0x1
+#define PLL_LDOPWDN BIT(15)
+#define PLL_TICOPWDN BIT(16)
+#define PLL_LOCK 0x2
+#define PLL_IDLE 0x1
+
+/*
+ * This is an Empirical value that works, need to confirm the actual
+ * value required for the PIPE3PHY_PLL_CONFIGURATION2.PLL_IDLE status
+ * to be correctly reflected in the PIPE3PHY_PLL_STATUS register.
+ */
+#define PLL_IDLE_TIME 100 /* in milliseconds */
+#define PLL_LOCK_TIME 100 /* in milliseconds */
+
+struct pipe3_dpll_params {
+ u16 m;
+ u8 n;
+ u8 freq:3;
+ u8 sd;
+ u32 mf;
+};
+
+struct pipe3_dpll_map {
+ unsigned long rate;
+ struct pipe3_dpll_params params;
+};
+
+struct ti_pipe3 {
+ void __iomem *pll_ctrl_base;
+ struct device *dev;
+ struct device *control_dev;
+ struct clk *wkupclk;
+ struct clk *sys_clk;
+ struct clk *refclk;
+ struct pipe3_dpll_map *dpll_map;
+};
+
+static struct pipe3_dpll_map dpll_map_usb[] = {
+ {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 */
+ { }, /* Terminator */
+};
+
+static struct pipe3_dpll_map dpll_map_sata[] = {
+ {12000000, {1000, 7, 4, 6, 0} }, /* 12 MHz */
+ {16800000, {714, 7, 4, 6, 0} }, /* 16.8 MHz */
+ {19200000, {625, 7, 4, 6, 0} }, /* 19.2 MHz */
+ {20000000, {600, 7, 4, 6, 0} }, /* 20 MHz */
+ {26000000, {461, 7, 4, 6, 0} }, /* 26 MHz */
+ {38400000, {312, 7, 4, 6, 0} }, /* 38.4 MHz */
+ { }, /* Terminator */
+};
+
+static inline u32 ti_pipe3_readl(void __iomem *addr, unsigned offset)
+{
+ return __raw_readl(addr + offset);
+}
+
+static inline void ti_pipe3_writel(void __iomem *addr, unsigned offset,
+ u32 data)
+{
+ __raw_writel(data, addr + offset);
+}
+
+static struct pipe3_dpll_params *ti_pipe3_get_dpll_params(struct ti_pipe3 *phy)
+{
+ unsigned long rate;
+ struct pipe3_dpll_map *dpll_map = phy->dpll_map;
+
+ rate = clk_get_rate(phy->sys_clk);
+
+ for (; dpll_map->rate; dpll_map++) {
+ if (rate == dpll_map->rate)
+ return &dpll_map->params;
+ }
+
+ dev_err(phy->dev, "No DPLL configuration for %lu Hz SYS CLK\n", rate);
+
+ return NULL;
+}
+
+static int ti_pipe3_power_off(struct phy *x)
+{
+ struct ti_pipe3 *phy = phy_get_drvdata(x);
+
+ omap_control_phy_power(phy->control_dev, 0);
+
+ return 0;
+}
+
+static int ti_pipe3_power_on(struct phy *x)
+{
+ struct ti_pipe3 *phy = phy_get_drvdata(x);
+
+ omap_control_phy_power(phy->control_dev, 1);
+
+ return 0;
+}
+
+static int ti_pipe3_dpll_wait_lock(struct ti_pipe3 *phy)
+{
+ u32 val;
+ unsigned long timeout;
+
+ timeout = jiffies + msecs_to_jiffies(PLL_LOCK_TIME);
+ do {
+ cpu_relax();
+ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
+ if (val & PLL_LOCK)
+ break;
+ } while (!time_after(jiffies, timeout));
+
+ if (!(val & PLL_LOCK)) {
+ dev_err(phy->dev, "DPLL failed to lock\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int ti_pipe3_dpll_program(struct ti_pipe3 *phy)
+{
+ u32 val;
+ struct pipe3_dpll_params *dpll_params;
+
+ dpll_params = ti_pipe3_get_dpll_params(phy);
+ if (!dpll_params)
+ return -EINVAL;
+
+ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
+ val &= ~PLL_REGN_MASK;
+ val |= dpll_params->n << PLL_REGN_SHIFT;
+ ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
+
+ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
+ val &= ~PLL_SELFREQDCO_MASK;
+ val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT;
+ ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
+
+ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
+ val &= ~PLL_REGM_MASK;
+ val |= dpll_params->m << PLL_REGM_SHIFT;
+ ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
+
+ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4);
+ val &= ~PLL_REGM_F_MASK;
+ val |= dpll_params->mf << PLL_REGM_F_SHIFT;
+ ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val);
+
+ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3);
+ val &= ~PLL_SD_MASK;
+ val |= dpll_params->sd << PLL_SD_SHIFT;
+ ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val);
+
+ ti_pipe3_writel(phy->pll_ctrl_base, PLL_GO, SET_PLL_GO);
+
+ return ti_pipe3_dpll_wait_lock(phy);
+}
+
+static int ti_pipe3_init(struct phy *x)
+{
+ struct ti_pipe3 *phy = phy_get_drvdata(x);
+ u32 val;
+ int ret = 0;
+
+ /* Bring it out of IDLE if it is IDLE */
+ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
+ if (val & PLL_IDLE) {
+ val &= ~PLL_IDLE;
+ ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
+ ret = ti_pipe3_dpll_wait_lock(phy);
+ }
+
+ /* Program the DPLL only if not locked */
+ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
+ if (!(val & PLL_LOCK))
+ if (ti_pipe3_dpll_program(phy))
+ return -EINVAL;
+
+ return ret;
+}
+
+static int ti_pipe3_exit(struct phy *x)
+{
+ struct ti_pipe3 *phy = phy_get_drvdata(x);
+ u32 val;
+ unsigned long timeout;
+
+ /* SATA DPLL can't be powered down due to Errata i783 */
+ if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata"))
+ return 0;
+
+ /* Put DPLL in IDLE mode */
+ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
+ val |= PLL_IDLE;
+ ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
+
+ /* wait for LDO and Oscillator to power down */
+ timeout = jiffies + msecs_to_jiffies(PLL_IDLE_TIME);
+ do {
+ cpu_relax();
+ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
+ if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN))
+ break;
+ } while (!time_after(jiffies, timeout));
+
+ if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) {
+ dev_err(phy->dev, "Failed to power down: PLL_STATUS 0x%x\n",
+ val);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+static struct phy_ops ops = {
+ .init = ti_pipe3_init,
+ .exit = ti_pipe3_exit,
+ .power_on = ti_pipe3_power_on,
+ .power_off = ti_pipe3_power_off,
+ .owner = THIS_MODULE,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id ti_pipe3_id_table[];
+#endif
+
+static int ti_pipe3_probe(struct platform_device *pdev)
+{
+ struct ti_pipe3 *phy;
+ struct phy *generic_phy;
+ struct phy_provider *phy_provider;
+ struct resource *res;
+ struct device_node *node = pdev->dev.of_node;
+ struct device_node *control_node;
+ struct platform_device *control_pdev;
+ const struct of_device_id *match;
+
+ match = of_match_device(of_match_ptr(ti_pipe3_id_table), &pdev->dev);
+ if (!match)
+ return -EINVAL;
+
+ phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
+ if (!phy) {
+ dev_err(&pdev->dev, "unable to alloc mem for TI PIPE3 PHY\n");
+ return -ENOMEM;
+ }
+
+ phy->dpll_map = (struct pipe3_dpll_map *)match->data;
+ if (!phy->dpll_map) {
+ dev_err(&pdev->dev, "no DPLL data\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll_ctrl");
+ phy->pll_ctrl_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(phy->pll_ctrl_base))
+ return PTR_ERR(phy->pll_ctrl_base);
+
+ phy->dev = &pdev->dev;
+
+ if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) {
+
+ phy->wkupclk = devm_clk_get(phy->dev, "wkupclk");
+ if (IS_ERR(phy->wkupclk)) {
+ dev_err(&pdev->dev, "unable to get wkupclk\n");
+ return PTR_ERR(phy->wkupclk);
+ }
+
+ phy->refclk = devm_clk_get(phy->dev, "refclk");
+ if (IS_ERR(phy->refclk)) {
+ dev_err(&pdev->dev, "unable to get refclk\n");
+ return PTR_ERR(phy->refclk);
+ }
+ } else {
+ phy->wkupclk = ERR_PTR(-ENODEV);
+ phy->refclk = ERR_PTR(-ENODEV);
+ }
+
+ phy->sys_clk = devm_clk_get(phy->dev, "sysclk");
+ if (IS_ERR(phy->sys_clk)) {
+ dev_err(&pdev->dev, "unable to get sysclk\n");
+ return -EINVAL;
+ }
+
+ control_node = of_parse_phandle(node, "ctrl-module", 0);
+ if (!control_node) {
+ dev_err(&pdev->dev, "Failed to get control device phandle\n");
+ return -EINVAL;
+ }
+
+ control_pdev = of_find_device_by_node(control_node);
+ if (!control_pdev) {
+ dev_err(&pdev->dev, "Failed to get control device\n");
+ return -EINVAL;
+ }
+
+ phy->control_dev = &control_pdev->dev;
+
+ omap_control_phy_power(phy->control_dev, 0);
+
+ platform_set_drvdata(pdev, phy);
+ pm_runtime_enable(phy->dev);
+
+ generic_phy = devm_phy_create(phy->dev, &ops, NULL);
+ if (IS_ERR(generic_phy))
+ return PTR_ERR(generic_phy);
+
+ phy_set_drvdata(generic_phy, phy);
+ phy_provider = devm_of_phy_provider_register(phy->dev,
+ of_phy_simple_xlate);
+ if (IS_ERR(phy_provider))
+ return PTR_ERR(phy_provider);
+
+ pm_runtime_get(&pdev->dev);
+
+ return 0;
+}
+
+static int ti_pipe3_remove(struct platform_device *pdev)
+{
+ if (!pm_runtime_suspended(&pdev->dev))
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+
+static int ti_pipe3_runtime_suspend(struct device *dev)
+{
+ struct ti_pipe3 *phy = dev_get_drvdata(dev);
+
+ if (!IS_ERR(phy->wkupclk))
+ clk_disable_unprepare(phy->wkupclk);
+ if (!IS_ERR(phy->refclk))
+ clk_disable_unprepare(phy->refclk);
+
+ return 0;
+}
+
+static int ti_pipe3_runtime_resume(struct device *dev)
+{
+ u32 ret = 0;
+ struct ti_pipe3 *phy = dev_get_drvdata(dev);
+
+ if (!IS_ERR(phy->refclk)) {
+ ret = clk_prepare_enable(phy->refclk);
+ if (ret) {
+ dev_err(phy->dev, "Failed to enable refclk %d\n", ret);
+ goto err1;
+ }
+ }
+
+ if (!IS_ERR(phy->wkupclk)) {
+ ret = clk_prepare_enable(phy->wkupclk);
+ if (ret) {
+ dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret);
+ goto err2;
+ }
+ }
+
+ return 0;
+
+err2:
+ if (!IS_ERR(phy->refclk))
+ clk_disable_unprepare(phy->refclk);
+
+err1:
+ return ret;
+}
+
+static const struct dev_pm_ops ti_pipe3_pm_ops = {
+ SET_RUNTIME_PM_OPS(ti_pipe3_runtime_suspend,
+ ti_pipe3_runtime_resume, NULL)
+};
+
+#define DEV_PM_OPS (&ti_pipe3_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif
+
+#ifdef CONFIG_OF
+static const struct of_device_id ti_pipe3_id_table[] = {
+ {
+ .compatible = "ti,phy-usb3",
+ .data = dpll_map_usb,
+ },
+ {
+ .compatible = "ti,omap-usb3",
+ .data = dpll_map_usb,
+ },
+ {
+ .compatible = "ti,phy-pipe3-sata",
+ .data = dpll_map_sata,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, ti_pipe3_id_table);
+#endif
+
+static struct platform_driver ti_pipe3_driver = {
+ .probe = ti_pipe3_probe,
+ .remove = ti_pipe3_remove,
+ .driver = {
+ .name = "ti-pipe3",
+ .owner = THIS_MODULE,
+ .pm = DEV_PM_OPS,
+ .of_match_table = of_match_ptr(ti_pipe3_id_table),
+ },
+};
+
+module_platform_driver(ti_pipe3_driver);
+
+MODULE_ALIAS("platform: ti_pipe3");
+MODULE_AUTHOR("Texas Instruments Inc.");
+MODULE_DESCRIPTION("TI PIPE3 phy driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
index daf65e68aaab..2e0e9b3774c8 100644
--- a/drivers/phy/phy-twl4030-usb.c
+++ b/drivers/phy/phy-twl4030-usb.c
@@ -338,7 +338,7 @@ static void twl4030_usb_set_mode(struct twl4030_usb *twl, int mode)
dev_err(twl->dev, "unsupported T2 transceiver mode %d\n",
mode);
break;
- };
+ }
}
static void twl4030_i2c_access(struct twl4030_usb *twl, int on)
@@ -661,7 +661,7 @@ static int twl4030_usb_probe(struct platform_device *pdev)
struct phy_provider *phy_provider;
struct phy_init_data *init_data = NULL;
- twl = devm_kzalloc(&pdev->dev, sizeof *twl, GFP_KERNEL);
+ twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
if (!twl)
return -ENOMEM;
@@ -676,7 +676,7 @@ static int twl4030_usb_probe(struct platform_device *pdev)
return -EINVAL;
}
- otg = devm_kzalloc(&pdev->dev, sizeof *otg, GFP_KERNEL);
+ otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL);
if (!otg)
return -ENOMEM;
@@ -695,11 +695,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
otg->set_host = twl4030_set_host;
otg->set_peripheral = twl4030_set_peripheral;
- phy_provider = devm_of_phy_provider_register(twl->dev,
- of_phy_simple_xlate);
- if (IS_ERR(phy_provider))
- return PTR_ERR(phy_provider);
-
phy = devm_phy_create(twl->dev, &ops, init_data);
if (IS_ERR(phy)) {
dev_dbg(&pdev->dev, "Failed to create PHY\n");
@@ -708,6 +703,11 @@ static int twl4030_usb_probe(struct platform_device *pdev)
phy_set_drvdata(phy, twl);
+ phy_provider = devm_of_phy_provider_register(twl->dev,
+ of_phy_simple_xlate);
+ if (IS_ERR(phy_provider))
+ return PTR_ERR(phy_provider);
+
/* init spinlock for workqueue */
spin_lock_init(&twl->lock);
diff --git a/drivers/phy/phy-xgene.c b/drivers/phy/phy-xgene.c
new file mode 100644
index 000000000000..4aa1ccd1511f
--- /dev/null
+++ b/drivers/phy/phy-xgene.c
@@ -0,0 +1,1750 @@
+/*
+ * AppliedMicro X-Gene Multi-purpose PHY driver
+ *
+ * Copyright (c) 2014, Applied Micro Circuits Corporation
+ * Author: Loc Ho <lho@apm.com>
+ * Tuan Phan <tphan@apm.com>
+ * Suman Tripathi <stripathi@apm.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, see <http://www.gnu.org/licenses/>.
+ *
+ * The APM X-Gene PHY consists of two PLL clock macro's (CMU) and lanes.
+ * The first PLL clock macro is used for internal reference clock. The second
+ * PLL clock macro is used to generate the clock for the PHY. This driver
+ * configures the first PLL CMU, the second PLL CMU, and programs the PHY to
+ * operate according to the mode of operation. The first PLL CMU is only
+ * required if internal clock is enabled.
+ *
+ * Logical Layer Out Of HW module units:
+ *
+ * -----------------
+ * | Internal | |------|
+ * | Ref PLL CMU |----| | ------------- ---------
+ * ------------ ---- | MUX |-----|PHY PLL CMU|----| Serdes|
+ * | | | | ---------
+ * External Clock ------| | -------------
+ * |------|
+ *
+ * The Ref PLL CMU CSR (Configuration System Registers) is accessed
+ * indirectly from the SDS offset at 0x2000. It is only required for
+ * internal reference clock.
+ * The PHY PLL CMU CSR is accessed indirectly from the SDS offset at 0x0000.
+ * The Serdes CSR is accessed indirectly from the SDS offset at 0x0400.
+ *
+ * The Ref PLL CMU can be located within the same PHY IP or outside the PHY IP
+ * due to shared Ref PLL CMU. For PHY with Ref PLL CMU shared with another IP,
+ * it is located outside the PHY IP. This is the case for the PHY located
+ * at 0x1f23a000 (SATA Port 4/5). For such PHY, another resource is required
+ * to located the SDS/Ref PLL CMU module and its clock for that IP enabled.
+ *
+ * Currently, this driver only supports Gen3 SATA mode with external clock.
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/phy/phy.h>
+#include <linux/clk.h>
+
+/* Max 2 lanes per a PHY unit */
+#define MAX_LANE 2
+
+/* Register offset inside the PHY */
+#define SERDES_PLL_INDIRECT_OFFSET 0x0000
+#define SERDES_PLL_REF_INDIRECT_OFFSET 0x2000
+#define SERDES_INDIRECT_OFFSET 0x0400
+#define SERDES_LANE_STRIDE 0x0200
+
+/* Some default Serdes parameters */
+#define DEFAULT_SATA_TXBOOST_GAIN { 0x1e, 0x1e, 0x1e }
+#define DEFAULT_SATA_TXEYEDIRECTION { 0x0, 0x0, 0x0 }
+#define DEFAULT_SATA_TXEYETUNING { 0xa, 0xa, 0xa }
+#define DEFAULT_SATA_SPD_SEL { 0x1, 0x3, 0x7 }
+#define DEFAULT_SATA_TXAMP { 0x8, 0x8, 0x8 }
+#define DEFAULT_SATA_TXCN1 { 0x2, 0x2, 0x2 }
+#define DEFAULT_SATA_TXCN2 { 0x0, 0x0, 0x0 }
+#define DEFAULT_SATA_TXCP1 { 0xa, 0xa, 0xa }
+
+#define SATA_SPD_SEL_GEN3 0x7
+#define SATA_SPD_SEL_GEN2 0x3
+#define SATA_SPD_SEL_GEN1 0x1
+
+#define SSC_DISABLE 0
+#define SSC_ENABLE 1
+
+#define FBDIV_VAL_50M 0x77
+#define REFDIV_VAL_50M 0x1
+#define FBDIV_VAL_100M 0x3B
+#define REFDIV_VAL_100M 0x0
+
+/* SATA Clock/Reset CSR */
+#define SATACLKENREG 0x00000000
+#define SATA0_CORE_CLKEN 0x00000002
+#define SATA1_CORE_CLKEN 0x00000004
+#define SATASRESETREG 0x00000004
+#define SATA_MEM_RESET_MASK 0x00000020
+#define SATA_MEM_RESET_RD(src) (((src) & 0x00000020) >> 5)
+#define SATA_SDS_RESET_MASK 0x00000004
+#define SATA_CSR_RESET_MASK 0x00000001
+#define SATA_CORE_RESET_MASK 0x00000002
+#define SATA_PMCLK_RESET_MASK 0x00000010
+#define SATA_PCLK_RESET_MASK 0x00000008
+
+/* SDS CSR used for PHY Indirect access */
+#define SATA_ENET_SDS_PCS_CTL0 0x00000000
+#define REGSPEC_CFG_I_TX_WORDMODE0_SET(dst, src) \
+ (((dst) & ~0x00070000) | (((u32) (src) << 16) & 0x00070000))
+#define REGSPEC_CFG_I_RX_WORDMODE0_SET(dst, src) \
+ (((dst) & ~0x00e00000) | (((u32) (src) << 21) & 0x00e00000))
+#define SATA_ENET_SDS_CTL0 0x0000000c
+#define REGSPEC_CFG_I_CUSTOMER_PIN_MODE0_SET(dst, src) \
+ (((dst) & ~0x00007fff) | (((u32) (src)) & 0x00007fff))
+#define SATA_ENET_SDS_CTL1 0x00000010
+#define CFG_I_SPD_SEL_CDR_OVR1_SET(dst, src) \
+ (((dst) & ~0x0000000f) | (((u32) (src)) & 0x0000000f))
+#define SATA_ENET_SDS_RST_CTL 0x00000024
+#define SATA_ENET_SDS_IND_CMD_REG 0x0000003c
+#define CFG_IND_WR_CMD_MASK 0x00000001
+#define CFG_IND_RD_CMD_MASK 0x00000002
+#define CFG_IND_CMD_DONE_MASK 0x00000004
+#define CFG_IND_ADDR_SET(dst, src) \
+ (((dst) & ~0x003ffff0) | (((u32) (src) << 4) & 0x003ffff0))
+#define SATA_ENET_SDS_IND_RDATA_REG 0x00000040
+#define SATA_ENET_SDS_IND_WDATA_REG 0x00000044
+#define SATA_ENET_CLK_MACRO_REG 0x0000004c
+#define I_RESET_B_SET(dst, src) \
+ (((dst) & ~0x00000001) | (((u32) (src)) & 0x00000001))
+#define I_PLL_FBDIV_SET(dst, src) \
+ (((dst) & ~0x001ff000) | (((u32) (src) << 12) & 0x001ff000))
+#define I_CUSTOMEROV_SET(dst, src) \
+ (((dst) & ~0x00000f80) | (((u32) (src) << 7) & 0x00000f80))
+#define O_PLL_LOCK_RD(src) (((src) & 0x40000000) >> 30)
+#define O_PLL_READY_RD(src) (((src) & 0x80000000) >> 31)
+
+/* PLL Clock Macro Unit (CMU) CSR accessing from SDS indirectly */
+#define CMU_REG0 0x00000
+#define CMU_REG0_PLL_REF_SEL_MASK 0x00002000
+#define CMU_REG0_PLL_REF_SEL_SET(dst, src) \
+ (((dst) & ~0x00002000) | (((u32) (src) << 13) & 0x00002000))
+#define CMU_REG0_PDOWN_MASK 0x00004000
+#define CMU_REG0_CAL_COUNT_RESOL_SET(dst, src) \
+ (((dst) & ~0x000000e0) | (((u32) (src) << 5) & 0x000000e0))
+#define CMU_REG1 0x00002
+#define CMU_REG1_PLL_CP_SET(dst, src) \
+ (((dst) & ~0x00003c00) | (((u32) (src) << 10) & 0x00003c00))
+#define CMU_REG1_PLL_MANUALCAL_SET(dst, src) \
+ (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define CMU_REG1_PLL_CP_SEL_SET(dst, src) \
+ (((dst) & ~0x000003e0) | (((u32) (src) << 5) & 0x000003e0))
+#define CMU_REG1_REFCLK_CMOS_SEL_MASK 0x00000001
+#define CMU_REG1_REFCLK_CMOS_SEL_SET(dst, src) \
+ (((dst) & ~0x00000001) | (((u32) (src) << 0) & 0x00000001))
+#define CMU_REG2 0x00004
+#define CMU_REG2_PLL_REFDIV_SET(dst, src) \
+ (((dst) & ~0x0000c000) | (((u32) (src) << 14) & 0x0000c000))
+#define CMU_REG2_PLL_LFRES_SET(dst, src) \
+ (((dst) & ~0x0000001e) | (((u32) (src) << 1) & 0x0000001e))
+#define CMU_REG2_PLL_FBDIV_SET(dst, src) \
+ (((dst) & ~0x00003fe0) | (((u32) (src) << 5) & 0x00003fe0))
+#define CMU_REG3 0x00006
+#define CMU_REG3_VCOVARSEL_SET(dst, src) \
+ (((dst) & ~0x0000000f) | (((u32) (src) << 0) & 0x0000000f))
+#define CMU_REG3_VCO_MOMSEL_INIT_SET(dst, src) \
+ (((dst) & ~0x000003f0) | (((u32) (src) << 4) & 0x000003f0))
+#define CMU_REG3_VCO_MANMOMSEL_SET(dst, src) \
+ (((dst) & ~0x0000fc00) | (((u32) (src) << 10) & 0x0000fc00))
+#define CMU_REG4 0x00008
+#define CMU_REG5 0x0000a
+#define CMU_REG5_PLL_LFSMCAP_SET(dst, src) \
+ (((dst) & ~0x0000c000) | (((u32) (src) << 14) & 0x0000c000))
+#define CMU_REG5_PLL_LOCK_RESOLUTION_SET(dst, src) \
+ (((dst) & ~0x0000000e) | (((u32) (src) << 1) & 0x0000000e))
+#define CMU_REG5_PLL_LFCAP_SET(dst, src) \
+ (((dst) & ~0x00003000) | (((u32) (src) << 12) & 0x00003000))
+#define CMU_REG5_PLL_RESETB_MASK 0x00000001
+#define CMU_REG6 0x0000c
+#define CMU_REG6_PLL_VREGTRIM_SET(dst, src) \
+ (((dst) & ~0x00000600) | (((u32) (src) << 9) & 0x00000600))
+#define CMU_REG6_MAN_PVT_CAL_SET(dst, src) \
+ (((dst) & ~0x00000004) | (((u32) (src) << 2) & 0x00000004))
+#define CMU_REG7 0x0000e
+#define CMU_REG7_PLL_CALIB_DONE_RD(src) ((0x00004000 & (u32) (src)) >> 14)
+#define CMU_REG7_VCO_CAL_FAIL_RD(src) ((0x00000c00 & (u32) (src)) >> 10)
+#define CMU_REG8 0x00010
+#define CMU_REG9 0x00012
+#define CMU_REG9_WORD_LEN_8BIT 0x000
+#define CMU_REG9_WORD_LEN_10BIT 0x001
+#define CMU_REG9_WORD_LEN_16BIT 0x002
+#define CMU_REG9_WORD_LEN_20BIT 0x003
+#define CMU_REG9_WORD_LEN_32BIT 0x004
+#define CMU_REG9_WORD_LEN_40BIT 0x005
+#define CMU_REG9_WORD_LEN_64BIT 0x006
+#define CMU_REG9_WORD_LEN_66BIT 0x007
+#define CMU_REG9_TX_WORD_MODE_CH1_SET(dst, src) \
+ (((dst) & ~0x00000380) | (((u32) (src) << 7) & 0x00000380))
+#define CMU_REG9_TX_WORD_MODE_CH0_SET(dst, src) \
+ (((dst) & ~0x00000070) | (((u32) (src) << 4) & 0x00000070))
+#define CMU_REG9_PLL_POST_DIVBY2_SET(dst, src) \
+ (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define CMU_REG9_VBG_BYPASSB_SET(dst, src) \
+ (((dst) & ~0x00000004) | (((u32) (src) << 2) & 0x00000004))
+#define CMU_REG9_IGEN_BYPASS_SET(dst, src) \
+ (((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002))
+#define CMU_REG10 0x00014
+#define CMU_REG10_VREG_REFSEL_SET(dst, src) \
+ (((dst) & ~0x00000001) | (((u32) (src) << 0) & 0x00000001))
+#define CMU_REG11 0x00016
+#define CMU_REG12 0x00018
+#define CMU_REG12_STATE_DELAY9_SET(dst, src) \
+ (((dst) & ~0x000000f0) | (((u32) (src) << 4) & 0x000000f0))
+#define CMU_REG13 0x0001a
+#define CMU_REG14 0x0001c
+#define CMU_REG15 0x0001e
+#define CMU_REG16 0x00020
+#define CMU_REG16_PVT_DN_MAN_ENA_MASK 0x00000001
+#define CMU_REG16_PVT_UP_MAN_ENA_MASK 0x00000002
+#define CMU_REG16_VCOCAL_WAIT_BTW_CODE_SET(dst, src) \
+ (((dst) & ~0x0000001c) | (((u32) (src) << 2) & 0x0000001c))
+#define CMU_REG16_CALIBRATION_DONE_OVERRIDE_SET(dst, src) \
+ (((dst) & ~0x00000040) | (((u32) (src) << 6) & 0x00000040))
+#define CMU_REG16_BYPASS_PLL_LOCK_SET(dst, src) \
+ (((dst) & ~0x00000020) | (((u32) (src) << 5) & 0x00000020))
+#define CMU_REG17 0x00022
+#define CMU_REG17_PVT_CODE_R2A_SET(dst, src) \
+ (((dst) & ~0x00007f00) | (((u32) (src) << 8) & 0x00007f00))
+#define CMU_REG17_RESERVED_7_SET(dst, src) \
+ (((dst) & ~0x000000e0) | (((u32) (src) << 5) & 0x000000e0))
+#define CMU_REG17_PVT_TERM_MAN_ENA_MASK 0x00008000
+#define CMU_REG18 0x00024
+#define CMU_REG19 0x00026
+#define CMU_REG20 0x00028
+#define CMU_REG21 0x0002a
+#define CMU_REG22 0x0002c
+#define CMU_REG23 0x0002e
+#define CMU_REG24 0x00030
+#define CMU_REG25 0x00032
+#define CMU_REG26 0x00034
+#define CMU_REG26_FORCE_PLL_LOCK_SET(dst, src) \
+ (((dst) & ~0x00000001) | (((u32) (src) << 0) & 0x00000001))
+#define CMU_REG27 0x00036
+#define CMU_REG28 0x00038
+#define CMU_REG29 0x0003a
+#define CMU_REG30 0x0003c
+#define CMU_REG30_LOCK_COUNT_SET(dst, src) \
+ (((dst) & ~0x00000006) | (((u32) (src) << 1) & 0x00000006))
+#define CMU_REG30_PCIE_MODE_SET(dst, src) \
+ (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define CMU_REG31 0x0003e
+#define CMU_REG32 0x00040
+#define CMU_REG32_FORCE_VCOCAL_START_MASK 0x00004000
+#define CMU_REG32_PVT_CAL_WAIT_SEL_SET(dst, src) \
+ (((dst) & ~0x00000006) | (((u32) (src) << 1) & 0x00000006))
+#define CMU_REG32_IREF_ADJ_SET(dst, src) \
+ (((dst) & ~0x00000180) | (((u32) (src) << 7) & 0x00000180))
+#define CMU_REG33 0x00042
+#define CMU_REG34 0x00044
+#define CMU_REG34_VCO_CAL_VTH_LO_MAX_SET(dst, src) \
+ (((dst) & ~0x0000000f) | (((u32) (src) << 0) & 0x0000000f))
+#define CMU_REG34_VCO_CAL_VTH_HI_MAX_SET(dst, src) \
+ (((dst) & ~0x00000f00) | (((u32) (src) << 8) & 0x00000f00))
+#define CMU_REG34_VCO_CAL_VTH_LO_MIN_SET(dst, src) \
+ (((dst) & ~0x000000f0) | (((u32) (src) << 4) & 0x000000f0))
+#define CMU_REG34_VCO_CAL_VTH_HI_MIN_SET(dst, src) \
+ (((dst) & ~0x0000f000) | (((u32) (src) << 12) & 0x0000f000))
+#define CMU_REG35 0x00046
+#define CMU_REG35_PLL_SSC_MOD_SET(dst, src) \
+ (((dst) & ~0x0000fe00) | (((u32) (src) << 9) & 0x0000fe00))
+#define CMU_REG36 0x00048
+#define CMU_REG36_PLL_SSC_EN_SET(dst, src) \
+ (((dst) & ~0x00000010) | (((u32) (src) << 4) & 0x00000010))
+#define CMU_REG36_PLL_SSC_VSTEP_SET(dst, src) \
+ (((dst) & ~0x0000ffc0) | (((u32) (src) << 6) & 0x0000ffc0))
+#define CMU_REG36_PLL_SSC_DSMSEL_SET(dst, src) \
+ (((dst) & ~0x00000020) | (((u32) (src) << 5) & 0x00000020))
+#define CMU_REG37 0x0004a
+#define CMU_REG38 0x0004c
+#define CMU_REG39 0x0004e
+
+/* PHY lane CSR accessing from SDS indirectly */
+#define RXTX_REG0 0x000
+#define RXTX_REG0_CTLE_EQ_HR_SET(dst, src) \
+ (((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800))
+#define RXTX_REG0_CTLE_EQ_QR_SET(dst, src) \
+ (((dst) & ~0x000007c0) | (((u32) (src) << 6) & 0x000007c0))
+#define RXTX_REG0_CTLE_EQ_FR_SET(dst, src) \
+ (((dst) & ~0x0000003e) | (((u32) (src) << 1) & 0x0000003e))
+#define RXTX_REG1 0x002
+#define RXTX_REG1_RXACVCM_SET(dst, src) \
+ (((dst) & ~0x0000f000) | (((u32) (src) << 12) & 0x0000f000))
+#define RXTX_REG1_CTLE_EQ_SET(dst, src) \
+ (((dst) & ~0x00000f80) | (((u32) (src) << 7) & 0x00000f80))
+#define RXTX_REG1_RXVREG1_SET(dst, src) \
+ (((dst) & ~0x00000060) | (((u32) (src) << 5) & 0x00000060))
+#define RXTX_REG1_RXIREF_ADJ_SET(dst, src) \
+ (((dst) & ~0x00000006) | (((u32) (src) << 1) & 0x00000006))
+#define RXTX_REG2 0x004
+#define RXTX_REG2_VTT_ENA_SET(dst, src) \
+ (((dst) & ~0x00000100) | (((u32) (src) << 8) & 0x00000100))
+#define RXTX_REG2_TX_FIFO_ENA_SET(dst, src) \
+ (((dst) & ~0x00000020) | (((u32) (src) << 5) & 0x00000020))
+#define RXTX_REG2_VTT_SEL_SET(dst, src) \
+ (((dst) & ~0x000000c0) | (((u32) (src) << 6) & 0x000000c0))
+#define RXTX_REG4 0x008
+#define RXTX_REG4_TX_LOOPBACK_BUF_EN_MASK 0x00000040
+#define RXTX_REG4_TX_DATA_RATE_SET(dst, src) \
+ (((dst) & ~0x0000c000) | (((u32) (src) << 14) & 0x0000c000))
+#define RXTX_REG4_TX_WORD_MODE_SET(dst, src) \
+ (((dst) & ~0x00003800) | (((u32) (src) << 11) & 0x00003800))
+#define RXTX_REG5 0x00a
+#define RXTX_REG5_TX_CN1_SET(dst, src) \
+ (((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800))
+#define RXTX_REG5_TX_CP1_SET(dst, src) \
+ (((dst) & ~0x000007e0) | (((u32) (src) << 5) & 0x000007e0))
+#define RXTX_REG5_TX_CN2_SET(dst, src) \
+ (((dst) & ~0x0000001f) | (((u32) (src) << 0) & 0x0000001f))
+#define RXTX_REG6 0x00c
+#define RXTX_REG6_TXAMP_CNTL_SET(dst, src) \
+ (((dst) & ~0x00000780) | (((u32) (src) << 7) & 0x00000780))
+#define RXTX_REG6_TXAMP_ENA_SET(dst, src) \
+ (((dst) & ~0x00000040) | (((u32) (src) << 6) & 0x00000040))
+#define RXTX_REG6_RX_BIST_ERRCNT_RD_SET(dst, src) \
+ (((dst) & ~0x00000001) | (((u32) (src) << 0) & 0x00000001))
+#define RXTX_REG6_TX_IDLE_SET(dst, src) \
+ (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define RXTX_REG6_RX_BIST_RESYNC_SET(dst, src) \
+ (((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002))
+#define RXTX_REG7 0x00e
+#define RXTX_REG7_RESETB_RXD_MASK 0x00000100
+#define RXTX_REG7_RESETB_RXA_MASK 0x00000080
+#define RXTX_REG7_BIST_ENA_RX_SET(dst, src) \
+ (((dst) & ~0x00000040) | (((u32) (src) << 6) & 0x00000040))
+#define RXTX_REG7_RX_WORD_MODE_SET(dst, src) \
+ (((dst) & ~0x00003800) | (((u32) (src) << 11) & 0x00003800))
+#define RXTX_REG8 0x010
+#define RXTX_REG8_CDR_LOOP_ENA_SET(dst, src) \
+ (((dst) & ~0x00004000) | (((u32) (src) << 14) & 0x00004000))
+#define RXTX_REG8_CDR_BYPASS_RXLOS_SET(dst, src) \
+ (((dst) & ~0x00000800) | (((u32) (src) << 11) & 0x00000800))
+#define RXTX_REG8_SSC_ENABLE_SET(dst, src) \
+ (((dst) & ~0x00000200) | (((u32) (src) << 9) & 0x00000200))
+#define RXTX_REG8_SD_VREF_SET(dst, src) \
+ (((dst) & ~0x000000f0) | (((u32) (src) << 4) & 0x000000f0))
+#define RXTX_REG8_SD_DISABLE_SET(dst, src) \
+ (((dst) & ~0x00000100) | (((u32) (src) << 8) & 0x00000100))
+#define RXTX_REG7 0x00e
+#define RXTX_REG7_RESETB_RXD_SET(dst, src) \
+ (((dst) & ~0x00000100) | (((u32) (src) << 8) & 0x00000100))
+#define RXTX_REG7_RESETB_RXA_SET(dst, src) \
+ (((dst) & ~0x00000080) | (((u32) (src) << 7) & 0x00000080))
+#define RXTX_REG7_LOOP_BACK_ENA_CTLE_MASK 0x00004000
+#define RXTX_REG7_LOOP_BACK_ENA_CTLE_SET(dst, src) \
+ (((dst) & ~0x00004000) | (((u32) (src) << 14) & 0x00004000))
+#define RXTX_REG11 0x016
+#define RXTX_REG11_PHASE_ADJUST_LIMIT_SET(dst, src) \
+ (((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800))
+#define RXTX_REG12 0x018
+#define RXTX_REG12_LATCH_OFF_ENA_SET(dst, src) \
+ (((dst) & ~0x00002000) | (((u32) (src) << 13) & 0x00002000))
+#define RXTX_REG12_SUMOS_ENABLE_SET(dst, src) \
+ (((dst) & ~0x00000004) | (((u32) (src) << 2) & 0x00000004))
+#define RXTX_REG12_RX_DET_TERM_ENABLE_MASK 0x00000002
+#define RXTX_REG12_RX_DET_TERM_ENABLE_SET(dst, src) \
+ (((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002))
+#define RXTX_REG13 0x01a
+#define RXTX_REG14 0x01c
+#define RXTX_REG14_CLTE_LATCAL_MAN_PROG_SET(dst, src) \
+ (((dst) & ~0x0000003f) | (((u32) (src) << 0) & 0x0000003f))
+#define RXTX_REG14_CTLE_LATCAL_MAN_ENA_SET(dst, src) \
+ (((dst) & ~0x00000040) | (((u32) (src) << 6) & 0x00000040))
+#define RXTX_REG26 0x034
+#define RXTX_REG26_PERIOD_ERROR_LATCH_SET(dst, src) \
+ (((dst) & ~0x00003800) | (((u32) (src) << 11) & 0x00003800))
+#define RXTX_REG26_BLWC_ENA_SET(dst, src) \
+ (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define RXTX_REG21 0x02a
+#define RXTX_REG21_DO_LATCH_CALOUT_RD(src) ((0x0000fc00 & (u32) (src)) >> 10)
+#define RXTX_REG21_XO_LATCH_CALOUT_RD(src) ((0x000003f0 & (u32) (src)) >> 4)
+#define RXTX_REG21_LATCH_CAL_FAIL_ODD_RD(src) ((0x0000000f & (u32)(src)))
+#define RXTX_REG22 0x02c
+#define RXTX_REG22_SO_LATCH_CALOUT_RD(src) ((0x000003f0 & (u32) (src)) >> 4)
+#define RXTX_REG22_EO_LATCH_CALOUT_RD(src) ((0x0000fc00 & (u32) (src)) >> 10)
+#define RXTX_REG22_LATCH_CAL_FAIL_EVEN_RD(src) ((0x0000000f & (u32)(src)))
+#define RXTX_REG23 0x02e
+#define RXTX_REG23_DE_LATCH_CALOUT_RD(src) ((0x0000fc00 & (u32) (src)) >> 10)
+#define RXTX_REG23_XE_LATCH_CALOUT_RD(src) ((0x000003f0 & (u32) (src)) >> 4)
+#define RXTX_REG24 0x030
+#define RXTX_REG24_EE_LATCH_CALOUT_RD(src) ((0x0000fc00 & (u32) (src)) >> 10)
+#define RXTX_REG24_SE_LATCH_CALOUT_RD(src) ((0x000003f0 & (u32) (src)) >> 4)
+#define RXTX_REG27 0x036
+#define RXTX_REG28 0x038
+#define RXTX_REG31 0x03e
+#define RXTX_REG38 0x04c
+#define RXTX_REG38_CUSTOMER_PINMODE_INV_SET(dst, src) \
+ (((dst) & 0x0000fffe) | (((u32) (src) << 1) & 0x0000fffe))
+#define RXTX_REG39 0x04e
+#define RXTX_REG40 0x050
+#define RXTX_REG41 0x052
+#define RXTX_REG42 0x054
+#define RXTX_REG43 0x056
+#define RXTX_REG44 0x058
+#define RXTX_REG45 0x05a
+#define RXTX_REG46 0x05c
+#define RXTX_REG47 0x05e
+#define RXTX_REG48 0x060
+#define RXTX_REG49 0x062
+#define RXTX_REG50 0x064
+#define RXTX_REG51 0x066
+#define RXTX_REG52 0x068
+#define RXTX_REG53 0x06a
+#define RXTX_REG54 0x06c
+#define RXTX_REG55 0x06e
+#define RXTX_REG61 0x07a
+#define RXTX_REG61_ISCAN_INBERT_SET(dst, src) \
+ (((dst) & ~0x00000010) | (((u32) (src) << 4) & 0x00000010))
+#define RXTX_REG61_LOADFREQ_SHIFT_SET(dst, src) \
+ (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define RXTX_REG61_EYE_COUNT_WIDTH_SEL_SET(dst, src) \
+ (((dst) & ~0x000000c0) | (((u32) (src) << 6) & 0x000000c0))
+#define RXTX_REG61_SPD_SEL_CDR_SET(dst, src) \
+ (((dst) & ~0x00003c00) | (((u32) (src) << 10) & 0x00003c00))
+#define RXTX_REG62 0x07c
+#define RXTX_REG62_PERIOD_H1_QLATCH_SET(dst, src) \
+ (((dst) & ~0x00003800) | (((u32) (src) << 11) & 0x00003800))
+#define RXTX_REG81 0x0a2
+#define RXTX_REG89_MU_TH7_SET(dst, src) \
+ (((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800))
+#define RXTX_REG89_MU_TH8_SET(dst, src) \
+ (((dst) & ~0x000007c0) | (((u32) (src) << 6) & 0x000007c0))
+#define RXTX_REG89_MU_TH9_SET(dst, src) \
+ (((dst) & ~0x0000003e) | (((u32) (src) << 1) & 0x0000003e))
+#define RXTX_REG96 0x0c0
+#define RXTX_REG96_MU_FREQ1_SET(dst, src) \
+ (((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800))
+#define RXTX_REG96_MU_FREQ2_SET(dst, src) \
+ (((dst) & ~0x000007c0) | (((u32) (src) << 6) & 0x000007c0))
+#define RXTX_REG96_MU_FREQ3_SET(dst, src) \
+ (((dst) & ~0x0000003e) | (((u32) (src) << 1) & 0x0000003e))
+#define RXTX_REG99 0x0c6
+#define RXTX_REG99_MU_PHASE1_SET(dst, src) \
+ (((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800))
+#define RXTX_REG99_MU_PHASE2_SET(dst, src) \
+ (((dst) & ~0x000007c0) | (((u32) (src) << 6) & 0x000007c0))
+#define RXTX_REG99_MU_PHASE3_SET(dst, src) \
+ (((dst) & ~0x0000003e) | (((u32) (src) << 1) & 0x0000003e))
+#define RXTX_REG102 0x0cc
+#define RXTX_REG102_FREQLOOP_LIMIT_SET(dst, src) \
+ (((dst) & ~0x00000060) | (((u32) (src) << 5) & 0x00000060))
+#define RXTX_REG114 0x0e4
+#define RXTX_REG121 0x0f2
+#define RXTX_REG121_SUMOS_CAL_CODE_RD(src) ((0x0000003e & (u32)(src)) >> 0x1)
+#define RXTX_REG125 0x0fa
+#define RXTX_REG125_PQ_REG_SET(dst, src) \
+ (((dst) & ~0x0000fe00) | (((u32) (src) << 9) & 0x0000fe00))
+#define RXTX_REG125_SIGN_PQ_SET(dst, src) \
+ (((dst) & ~0x00000100) | (((u32) (src) << 8) & 0x00000100))
+#define RXTX_REG125_SIGN_PQ_2C_SET(dst, src) \
+ (((dst) & ~0x00000080) | (((u32) (src) << 7) & 0x00000080))
+#define RXTX_REG125_PHZ_MANUALCODE_SET(dst, src) \
+ (((dst) & ~0x0000007c) | (((u32) (src) << 2) & 0x0000007c))
+#define RXTX_REG125_PHZ_MANUAL_SET(dst, src) \
+ (((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002))
+#define RXTX_REG127 0x0fe
+#define RXTX_REG127_FORCE_SUM_CAL_START_MASK 0x00000002
+#define RXTX_REG127_FORCE_LAT_CAL_START_MASK 0x00000004
+#define RXTX_REG127_FORCE_SUM_CAL_START_SET(dst, src) \
+ (((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002))
+#define RXTX_REG127_FORCE_LAT_CAL_START_SET(dst, src) \
+ (((dst) & ~0x00000004) | (((u32) (src) << 2) & 0x00000004))
+#define RXTX_REG127_LATCH_MAN_CAL_ENA_SET(dst, src) \
+ (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define RXTX_REG127_DO_LATCH_MANCAL_SET(dst, src) \
+ (((dst) & ~0x0000fc00) | (((u32) (src) << 10) & 0x0000fc00))
+#define RXTX_REG127_XO_LATCH_MANCAL_SET(dst, src) \
+ (((dst) & ~0x000003f0) | (((u32) (src) << 4) & 0x000003f0))
+#define RXTX_REG128 0x100
+#define RXTX_REG128_LATCH_CAL_WAIT_SEL_SET(dst, src) \
+ (((dst) & ~0x0000000c) | (((u32) (src) << 2) & 0x0000000c))
+#define RXTX_REG128_EO_LATCH_MANCAL_SET(dst, src) \
+ (((dst) & ~0x0000fc00) | (((u32) (src) << 10) & 0x0000fc00))
+#define RXTX_REG128_SO_LATCH_MANCAL_SET(dst, src) \
+ (((dst) & ~0x000003f0) | (((u32) (src) << 4) & 0x000003f0))
+#define RXTX_REG129 0x102
+#define RXTX_REG129_DE_LATCH_MANCAL_SET(dst, src) \
+ (((dst) & ~0x0000fc00) | (((u32) (src) << 10) & 0x0000fc00))
+#define RXTX_REG129_XE_LATCH_MANCAL_SET(dst, src) \
+ (((dst) & ~0x000003f0) | (((u32) (src) << 4) & 0x000003f0))
+#define RXTX_REG130 0x104
+#define RXTX_REG130_EE_LATCH_MANCAL_SET(dst, src) \
+ (((dst) & ~0x0000fc00) | (((u32) (src) << 10) & 0x0000fc00))
+#define RXTX_REG130_SE_LATCH_MANCAL_SET(dst, src) \
+ (((dst) & ~0x000003f0) | (((u32) (src) << 4) & 0x000003f0))
+#define RXTX_REG145 0x122
+#define RXTX_REG145_TX_IDLE_SATA_SET(dst, src) \
+ (((dst) & ~0x00000001) | (((u32) (src) << 0) & 0x00000001))
+#define RXTX_REG145_RXES_ENA_SET(dst, src) \
+ (((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002))
+#define RXTX_REG145_RXDFE_CONFIG_SET(dst, src) \
+ (((dst) & ~0x0000c000) | (((u32) (src) << 14) & 0x0000c000))
+#define RXTX_REG145_RXVWES_LATENA_SET(dst, src) \
+ (((dst) & ~0x00000004) | (((u32) (src) << 2) & 0x00000004))
+#define RXTX_REG147 0x126
+#define RXTX_REG148 0x128
+
+/* Clock macro type */
+enum cmu_type_t {
+ REF_CMU = 0, /* Clock macro is the internal reference clock */
+ PHY_CMU = 1, /* Clock macro is the PLL for the Serdes */
+};
+
+enum mux_type_t {
+ MUX_SELECT_ATA = 0, /* Switch the MUX to ATA */
+ MUX_SELECT_SGMMII = 0, /* Switch the MUX to SGMII */
+};
+
+enum clk_type_t {
+ CLK_EXT_DIFF = 0, /* External differential */
+ CLK_INT_DIFF = 1, /* Internal differential */
+ CLK_INT_SING = 2, /* Internal single ended */
+};
+
+enum phy_mode {
+ MODE_SATA = 0, /* List them for simple reference */
+ MODE_SGMII = 1,
+ MODE_PCIE = 2,
+ MODE_USB = 3,
+ MODE_XFI = 4,
+ MODE_MAX
+};
+
+struct xgene_sata_override_param {
+ u32 speed[MAX_LANE]; /* Index for override parameter per lane */
+ u32 txspeed[3]; /* Tx speed */
+ u32 txboostgain[MAX_LANE*3]; /* Tx freq boost and gain control */
+ u32 txeyetuning[MAX_LANE*3]; /* Tx eye tuning */
+ u32 txeyedirection[MAX_LANE*3]; /* Tx eye tuning direction */
+ u32 txamplitude[MAX_LANE*3]; /* Tx amplitude control */
+ u32 txprecursor_cn1[MAX_LANE*3]; /* Tx emphasis taps 1st pre-cursor */
+ u32 txprecursor_cn2[MAX_LANE*3]; /* Tx emphasis taps 2nd pre-cursor */
+ u32 txpostcursor_cp1[MAX_LANE*3]; /* Tx emphasis taps post-cursor */
+};
+
+struct xgene_phy_ctx {
+ struct device *dev;
+ struct phy *phy;
+ enum phy_mode mode; /* Mode of operation */
+ enum clk_type_t clk_type; /* Input clock selection */
+ void __iomem *sds_base; /* PHY CSR base addr */
+ struct clk *clk; /* Optional clock */
+
+ /* Override Serdes parameters */
+ struct xgene_sata_override_param sata_param;
+};
+
+/*
+ * For chip earlier than A3 version, enable this flag.
+ * To enable, pass boot argument phy_xgene.preA3Chip=1
+ */
+static int preA3Chip;
+MODULE_PARM_DESC(preA3Chip, "Enable pre-A3 chip support (1=enable 0=disable)");
+module_param_named(preA3Chip, preA3Chip, int, 0444);
+
+static void sds_wr(void __iomem *csr_base, u32 indirect_cmd_reg,
+ u32 indirect_data_reg, u32 addr, u32 data)
+{
+ unsigned long deadline = jiffies + HZ;
+ u32 val;
+ u32 cmd;
+
+ cmd = CFG_IND_WR_CMD_MASK | CFG_IND_CMD_DONE_MASK;
+ cmd = CFG_IND_ADDR_SET(cmd, addr);
+ writel(data, csr_base + indirect_data_reg);
+ readl(csr_base + indirect_data_reg); /* Force a barrier */
+ writel(cmd, csr_base + indirect_cmd_reg);
+ readl(csr_base + indirect_cmd_reg); /* Force a barrier */
+ do {
+ val = readl(csr_base + indirect_cmd_reg);
+ } while (!(val & CFG_IND_CMD_DONE_MASK) &&
+ time_before(jiffies, deadline));
+ if (!(val & CFG_IND_CMD_DONE_MASK))
+ pr_err("SDS WR timeout at 0x%p offset 0x%08X value 0x%08X\n",
+ csr_base + indirect_cmd_reg, addr, data);
+}
+
+static void sds_rd(void __iomem *csr_base, u32 indirect_cmd_reg,
+ u32 indirect_data_reg, u32 addr, u32 *data)
+{
+ unsigned long deadline = jiffies + HZ;
+ u32 val;
+ u32 cmd;
+
+ cmd = CFG_IND_RD_CMD_MASK | CFG_IND_CMD_DONE_MASK;
+ cmd = CFG_IND_ADDR_SET(cmd, addr);
+ writel(cmd, csr_base + indirect_cmd_reg);
+ readl(csr_base + indirect_cmd_reg); /* Force a barrier */
+ do {
+ val = readl(csr_base + indirect_cmd_reg);
+ } while (!(val & CFG_IND_CMD_DONE_MASK) &&
+ time_before(jiffies, deadline));
+ *data = readl(csr_base + indirect_data_reg);
+ if (!(val & CFG_IND_CMD_DONE_MASK))
+ pr_err("SDS WR timeout at 0x%p offset 0x%08X value 0x%08X\n",
+ csr_base + indirect_cmd_reg, addr, *data);
+}
+
+static void cmu_wr(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type,
+ u32 reg, u32 data)
+{
+ void __iomem *sds_base = ctx->sds_base;
+ u32 val;
+
+ if (cmu_type == REF_CMU)
+ reg += SERDES_PLL_REF_INDIRECT_OFFSET;
+ else
+ reg += SERDES_PLL_INDIRECT_OFFSET;
+ sds_wr(sds_base, SATA_ENET_SDS_IND_CMD_REG,
+ SATA_ENET_SDS_IND_WDATA_REG, reg, data);
+ sds_rd(sds_base, SATA_ENET_SDS_IND_CMD_REG,
+ SATA_ENET_SDS_IND_RDATA_REG, reg, &val);
+ pr_debug("CMU WR addr 0x%X value 0x%08X <-> 0x%08X\n", reg, data, val);
+}
+
+static void cmu_rd(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type,
+ u32 reg, u32 *data)
+{
+ void __iomem *sds_base = ctx->sds_base;
+
+ if (cmu_type == REF_CMU)
+ reg += SERDES_PLL_REF_INDIRECT_OFFSET;
+ else
+ reg += SERDES_PLL_INDIRECT_OFFSET;
+ sds_rd(sds_base, SATA_ENET_SDS_IND_CMD_REG,
+ SATA_ENET_SDS_IND_RDATA_REG, reg, data);
+ pr_debug("CMU RD addr 0x%X value 0x%08X\n", reg, *data);
+}
+
+static void cmu_toggle1to0(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type,
+ u32 reg, u32 bits)
+{
+ u32 val;
+
+ cmu_rd(ctx, cmu_type, reg, &val);
+ val |= bits;
+ cmu_wr(ctx, cmu_type, reg, val);
+ cmu_rd(ctx, cmu_type, reg, &val);
+ val &= ~bits;
+ cmu_wr(ctx, cmu_type, reg, val);
+}
+
+static void cmu_clrbits(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type,
+ u32 reg, u32 bits)
+{
+ u32 val;
+
+ cmu_rd(ctx, cmu_type, reg, &val);
+ val &= ~bits;
+ cmu_wr(ctx, cmu_type, reg, val);
+}
+
+static void cmu_setbits(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type,
+ u32 reg, u32 bits)
+{
+ u32 val;
+
+ cmu_rd(ctx, cmu_type, reg, &val);
+ val |= bits;
+ cmu_wr(ctx, cmu_type, reg, val);
+}
+
+static void serdes_wr(struct xgene_phy_ctx *ctx, int lane, u32 reg, u32 data)
+{
+ void __iomem *sds_base = ctx->sds_base;
+ u32 val;
+
+ reg += SERDES_INDIRECT_OFFSET;
+ reg += lane * SERDES_LANE_STRIDE;
+ sds_wr(sds_base, SATA_ENET_SDS_IND_CMD_REG,
+ SATA_ENET_SDS_IND_WDATA_REG, reg, data);
+ sds_rd(sds_base, SATA_ENET_SDS_IND_CMD_REG,
+ SATA_ENET_SDS_IND_RDATA_REG, reg, &val);
+ pr_debug("SERDES WR addr 0x%X value 0x%08X <-> 0x%08X\n", reg, data,
+ val);
+}
+
+static void serdes_rd(struct xgene_phy_ctx *ctx, int lane, u32 reg, u32 *data)
+{
+ void __iomem *sds_base = ctx->sds_base;
+
+ reg += SERDES_INDIRECT_OFFSET;
+ reg += lane * SERDES_LANE_STRIDE;
+ sds_rd(sds_base, SATA_ENET_SDS_IND_CMD_REG,
+ SATA_ENET_SDS_IND_RDATA_REG, reg, data);
+ pr_debug("SERDES RD addr 0x%X value 0x%08X\n", reg, *data);
+}
+
+static void serdes_clrbits(struct xgene_phy_ctx *ctx, int lane, u32 reg,
+ u32 bits)
+{
+ u32 val;
+
+ serdes_rd(ctx, lane, reg, &val);
+ val &= ~bits;
+ serdes_wr(ctx, lane, reg, val);
+}
+
+static void serdes_setbits(struct xgene_phy_ctx *ctx, int lane, u32 reg,
+ u32 bits)
+{
+ u32 val;
+
+ serdes_rd(ctx, lane, reg, &val);
+ val |= bits;
+ serdes_wr(ctx, lane, reg, val);
+}
+
+static void xgene_phy_cfg_cmu_clk_type(struct xgene_phy_ctx *ctx,
+ enum cmu_type_t cmu_type,
+ enum clk_type_t clk_type)
+{
+ u32 val;
+
+ /* Set the reset sequence delay for TX ready assertion */
+ cmu_rd(ctx, cmu_type, CMU_REG12, &val);
+ val = CMU_REG12_STATE_DELAY9_SET(val, 0x1);
+ cmu_wr(ctx, cmu_type, CMU_REG12, val);
+ /* Set the programmable stage delays between various enable stages */
+ cmu_wr(ctx, cmu_type, CMU_REG13, 0x0222);
+ cmu_wr(ctx, cmu_type, CMU_REG14, 0x2225);
+
+ /* Configure clock type */
+ if (clk_type == CLK_EXT_DIFF) {
+ /* Select external clock mux */
+ cmu_rd(ctx, cmu_type, CMU_REG0, &val);
+ val = CMU_REG0_PLL_REF_SEL_SET(val, 0x0);
+ cmu_wr(ctx, cmu_type, CMU_REG0, val);
+ /* Select CMOS as reference clock */
+ cmu_rd(ctx, cmu_type, CMU_REG1, &val);
+ val = CMU_REG1_REFCLK_CMOS_SEL_SET(val, 0x0);
+ cmu_wr(ctx, cmu_type, CMU_REG1, val);
+ dev_dbg(ctx->dev, "Set external reference clock\n");
+ } else if (clk_type == CLK_INT_DIFF) {
+ /* Select internal clock mux */
+ cmu_rd(ctx, cmu_type, CMU_REG0, &val);
+ val = CMU_REG0_PLL_REF_SEL_SET(val, 0x1);
+ cmu_wr(ctx, cmu_type, CMU_REG0, val);
+ /* Select CMOS as reference clock */
+ cmu_rd(ctx, cmu_type, CMU_REG1, &val);
+ val = CMU_REG1_REFCLK_CMOS_SEL_SET(val, 0x1);
+ cmu_wr(ctx, cmu_type, CMU_REG1, val);
+ dev_dbg(ctx->dev, "Set internal reference clock\n");
+ } else if (clk_type == CLK_INT_SING) {
+ /*
+ * NOTE: This clock type is NOT support for controller
+ * whose internal clock shared in the PCIe controller
+ *
+ * Select internal clock mux
+ */
+ cmu_rd(ctx, cmu_type, CMU_REG1, &val);
+ val = CMU_REG1_REFCLK_CMOS_SEL_SET(val, 0x1);
+ cmu_wr(ctx, cmu_type, CMU_REG1, val);
+ /* Select CML as reference clock */
+ cmu_rd(ctx, cmu_type, CMU_REG1, &val);
+ val = CMU_REG1_REFCLK_CMOS_SEL_SET(val, 0x0);
+ cmu_wr(ctx, cmu_type, CMU_REG1, val);
+ dev_dbg(ctx->dev,
+ "Set internal single ended reference clock\n");
+ }
+}
+
+static void xgene_phy_sata_cfg_cmu_core(struct xgene_phy_ctx *ctx,
+ enum cmu_type_t cmu_type,
+ enum clk_type_t clk_type)
+{
+ u32 val;
+ int ref_100MHz;
+
+ if (cmu_type == REF_CMU) {
+ /* Set VCO calibration voltage threshold */
+ cmu_rd(ctx, cmu_type, CMU_REG34, &val);
+ val = CMU_REG34_VCO_CAL_VTH_LO_MAX_SET(val, 0x7);
+ val = CMU_REG34_VCO_CAL_VTH_HI_MAX_SET(val, 0xc);
+ val = CMU_REG34_VCO_CAL_VTH_LO_MIN_SET(val, 0x3);
+ val = CMU_REG34_VCO_CAL_VTH_HI_MIN_SET(val, 0x8);
+ cmu_wr(ctx, cmu_type, CMU_REG34, val);
+ }
+
+ /* Set the VCO calibration counter */
+ cmu_rd(ctx, cmu_type, CMU_REG0, &val);
+ if (cmu_type == REF_CMU || preA3Chip)
+ val = CMU_REG0_CAL_COUNT_RESOL_SET(val, 0x4);
+ else
+ val = CMU_REG0_CAL_COUNT_RESOL_SET(val, 0x7);
+ cmu_wr(ctx, cmu_type, CMU_REG0, val);
+
+ /* Configure PLL for calibration */
+ cmu_rd(ctx, cmu_type, CMU_REG1, &val);
+ val = CMU_REG1_PLL_CP_SET(val, 0x1);
+ if (cmu_type == REF_CMU || preA3Chip)
+ val = CMU_REG1_PLL_CP_SEL_SET(val, 0x5);
+ else
+ val = CMU_REG1_PLL_CP_SEL_SET(val, 0x3);
+ if (cmu_type == REF_CMU)
+ val = CMU_REG1_PLL_MANUALCAL_SET(val, 0x0);
+ else
+ val = CMU_REG1_PLL_MANUALCAL_SET(val, 0x1);
+ cmu_wr(ctx, cmu_type, CMU_REG1, val);
+
+ if (cmu_type != REF_CMU)
+ cmu_clrbits(ctx, cmu_type, CMU_REG5, CMU_REG5_PLL_RESETB_MASK);
+
+ /* Configure the PLL for either 100MHz or 50MHz */
+ cmu_rd(ctx, cmu_type, CMU_REG2, &val);
+ if (cmu_type == REF_CMU) {
+ val = CMU_REG2_PLL_LFRES_SET(val, 0xa);
+ ref_100MHz = 1;
+ } else {
+ val = CMU_REG2_PLL_LFRES_SET(val, 0x3);
+ if (clk_type == CLK_EXT_DIFF)
+ ref_100MHz = 0;
+ else
+ ref_100MHz = 1;
+ }
+ if (ref_100MHz) {
+ val = CMU_REG2_PLL_FBDIV_SET(val, FBDIV_VAL_100M);
+ val = CMU_REG2_PLL_REFDIV_SET(val, REFDIV_VAL_100M);
+ } else {
+ val = CMU_REG2_PLL_FBDIV_SET(val, FBDIV_VAL_50M);
+ val = CMU_REG2_PLL_REFDIV_SET(val, REFDIV_VAL_50M);
+ }
+ cmu_wr(ctx, cmu_type, CMU_REG2, val);
+
+ /* Configure the VCO */
+ cmu_rd(ctx, cmu_type, CMU_REG3, &val);
+ if (cmu_type == REF_CMU) {
+ val = CMU_REG3_VCOVARSEL_SET(val, 0x3);
+ val = CMU_REG3_VCO_MOMSEL_INIT_SET(val, 0x10);
+ } else {
+ val = CMU_REG3_VCOVARSEL_SET(val, 0xF);
+ if (preA3Chip)
+ val = CMU_REG3_VCO_MOMSEL_INIT_SET(val, 0x15);
+ else
+ val = CMU_REG3_VCO_MOMSEL_INIT_SET(val, 0x1a);
+ val = CMU_REG3_VCO_MANMOMSEL_SET(val, 0x15);
+ }
+ cmu_wr(ctx, cmu_type, CMU_REG3, val);
+
+ /* Disable force PLL lock */
+ cmu_rd(ctx, cmu_type, CMU_REG26, &val);
+ val = CMU_REG26_FORCE_PLL_LOCK_SET(val, 0x0);
+ cmu_wr(ctx, cmu_type, CMU_REG26, val);
+
+ /* Setup PLL loop filter */
+ cmu_rd(ctx, cmu_type, CMU_REG5, &val);
+ val = CMU_REG5_PLL_LFSMCAP_SET(val, 0x3);
+ val = CMU_REG5_PLL_LFCAP_SET(val, 0x3);
+ if (cmu_type == REF_CMU || !preA3Chip)
+ val = CMU_REG5_PLL_LOCK_RESOLUTION_SET(val, 0x7);
+ else
+ val = CMU_REG5_PLL_LOCK_RESOLUTION_SET(val, 0x4);
+ cmu_wr(ctx, cmu_type, CMU_REG5, val);
+
+ /* Enable or disable manual calibration */
+ cmu_rd(ctx, cmu_type, CMU_REG6, &val);
+ val = CMU_REG6_PLL_VREGTRIM_SET(val, preA3Chip ? 0x0 : 0x2);
+ val = CMU_REG6_MAN_PVT_CAL_SET(val, preA3Chip ? 0x1 : 0x0);
+ cmu_wr(ctx, cmu_type, CMU_REG6, val);
+
+ /* Configure lane for 20-bits */
+ if (cmu_type == PHY_CMU) {
+ cmu_rd(ctx, cmu_type, CMU_REG9, &val);
+ val = CMU_REG9_TX_WORD_MODE_CH1_SET(val,
+ CMU_REG9_WORD_LEN_20BIT);
+ val = CMU_REG9_TX_WORD_MODE_CH0_SET(val,
+ CMU_REG9_WORD_LEN_20BIT);
+ val = CMU_REG9_PLL_POST_DIVBY2_SET(val, 0x1);
+ if (!preA3Chip) {
+ val = CMU_REG9_VBG_BYPASSB_SET(val, 0x0);
+ val = CMU_REG9_IGEN_BYPASS_SET(val , 0x0);
+ }
+ cmu_wr(ctx, cmu_type, CMU_REG9, val);
+
+ if (!preA3Chip) {
+ cmu_rd(ctx, cmu_type, CMU_REG10, &val);
+ val = CMU_REG10_VREG_REFSEL_SET(val, 0x1);
+ cmu_wr(ctx, cmu_type, CMU_REG10, val);
+ }
+ }
+
+ cmu_rd(ctx, cmu_type, CMU_REG16, &val);
+ val = CMU_REG16_CALIBRATION_DONE_OVERRIDE_SET(val, 0x1);
+ val = CMU_REG16_BYPASS_PLL_LOCK_SET(val, 0x1);
+ if (cmu_type == REF_CMU || preA3Chip)
+ val = CMU_REG16_VCOCAL_WAIT_BTW_CODE_SET(val, 0x4);
+ else
+ val = CMU_REG16_VCOCAL_WAIT_BTW_CODE_SET(val, 0x7);
+ cmu_wr(ctx, cmu_type, CMU_REG16, val);
+
+ /* Configure for SATA */
+ cmu_rd(ctx, cmu_type, CMU_REG30, &val);
+ val = CMU_REG30_PCIE_MODE_SET(val, 0x0);
+ val = CMU_REG30_LOCK_COUNT_SET(val, 0x3);
+ cmu_wr(ctx, cmu_type, CMU_REG30, val);
+
+ /* Disable state machine bypass */
+ cmu_wr(ctx, cmu_type, CMU_REG31, 0xF);
+
+ cmu_rd(ctx, cmu_type, CMU_REG32, &val);
+ val = CMU_REG32_PVT_CAL_WAIT_SEL_SET(val, 0x3);
+ if (cmu_type == REF_CMU || preA3Chip)
+ val = CMU_REG32_IREF_ADJ_SET(val, 0x3);
+ else
+ val = CMU_REG32_IREF_ADJ_SET(val, 0x1);
+ cmu_wr(ctx, cmu_type, CMU_REG32, val);
+
+ /* Set VCO calibration threshold */
+ if (cmu_type != REF_CMU && preA3Chip)
+ cmu_wr(ctx, cmu_type, CMU_REG34, 0x8d27);
+ else
+ cmu_wr(ctx, cmu_type, CMU_REG34, 0x873c);
+
+ /* Set CTLE Override and override waiting from state machine */
+ cmu_wr(ctx, cmu_type, CMU_REG37, 0xF00F);
+}
+
+static void xgene_phy_ssc_enable(struct xgene_phy_ctx *ctx,
+ enum cmu_type_t cmu_type)
+{
+ u32 val;
+
+ /* Set SSC modulation value */
+ cmu_rd(ctx, cmu_type, CMU_REG35, &val);
+ val = CMU_REG35_PLL_SSC_MOD_SET(val, 98);
+ cmu_wr(ctx, cmu_type, CMU_REG35, val);
+
+ /* Enable SSC, set vertical step and DSM value */
+ cmu_rd(ctx, cmu_type, CMU_REG36, &val);
+ val = CMU_REG36_PLL_SSC_VSTEP_SET(val, 30);
+ val = CMU_REG36_PLL_SSC_EN_SET(val, 1);
+ val = CMU_REG36_PLL_SSC_DSMSEL_SET(val, 1);
+ cmu_wr(ctx, cmu_type, CMU_REG36, val);
+
+ /* Reset the PLL */
+ cmu_clrbits(ctx, cmu_type, CMU_REG5, CMU_REG5_PLL_RESETB_MASK);
+ cmu_setbits(ctx, cmu_type, CMU_REG5, CMU_REG5_PLL_RESETB_MASK);
+
+ /* Force VCO calibration to restart */
+ cmu_toggle1to0(ctx, cmu_type, CMU_REG32,
+ CMU_REG32_FORCE_VCOCAL_START_MASK);
+}
+
+static void xgene_phy_sata_cfg_lanes(struct xgene_phy_ctx *ctx)
+{
+ u32 val;
+ u32 reg;
+ int i;
+ int lane;
+
+ for (lane = 0; lane < MAX_LANE; lane++) {
+ serdes_wr(ctx, lane, RXTX_REG147, 0x6);
+
+ /* Set boost control for quarter, half, and full rate */
+ serdes_rd(ctx, lane, RXTX_REG0, &val);
+ val = RXTX_REG0_CTLE_EQ_HR_SET(val, 0x10);
+ val = RXTX_REG0_CTLE_EQ_QR_SET(val, 0x10);
+ val = RXTX_REG0_CTLE_EQ_FR_SET(val, 0x10);
+ serdes_wr(ctx, lane, RXTX_REG0, val);
+
+ /* Set boost control value */
+ serdes_rd(ctx, lane, RXTX_REG1, &val);
+ val = RXTX_REG1_RXACVCM_SET(val, 0x7);
+ val = RXTX_REG1_CTLE_EQ_SET(val,
+ ctx->sata_param.txboostgain[lane * 3 +
+ ctx->sata_param.speed[lane]]);
+ serdes_wr(ctx, lane, RXTX_REG1, val);
+
+ /* Latch VTT value based on the termination to ground and
+ enable TX FIFO */
+ serdes_rd(ctx, lane, RXTX_REG2, &val);
+ val = RXTX_REG2_VTT_ENA_SET(val, 0x1);
+ val = RXTX_REG2_VTT_SEL_SET(val, 0x1);
+ val = RXTX_REG2_TX_FIFO_ENA_SET(val, 0x1);
+ serdes_wr(ctx, lane, RXTX_REG2, val);
+
+ /* Configure Tx for 20-bits */
+ serdes_rd(ctx, lane, RXTX_REG4, &val);
+ val = RXTX_REG4_TX_WORD_MODE_SET(val, CMU_REG9_WORD_LEN_20BIT);
+ serdes_wr(ctx, lane, RXTX_REG4, val);
+
+ if (!preA3Chip) {
+ serdes_rd(ctx, lane, RXTX_REG1, &val);
+ val = RXTX_REG1_RXVREG1_SET(val, 0x2);
+ val = RXTX_REG1_RXIREF_ADJ_SET(val, 0x2);
+ serdes_wr(ctx, lane, RXTX_REG1, val);
+ }
+
+ /* Set pre-emphasis first 1 and 2, and post-emphasis values */
+ serdes_rd(ctx, lane, RXTX_REG5, &val);
+ val = RXTX_REG5_TX_CN1_SET(val,
+ ctx->sata_param.txprecursor_cn1[lane * 3 +
+ ctx->sata_param.speed[lane]]);
+ val = RXTX_REG5_TX_CP1_SET(val,
+ ctx->sata_param.txpostcursor_cp1[lane * 3 +
+ ctx->sata_param.speed[lane]]);
+ val = RXTX_REG5_TX_CN2_SET(val,
+ ctx->sata_param.txprecursor_cn2[lane * 3 +
+ ctx->sata_param.speed[lane]]);
+ serdes_wr(ctx, lane, RXTX_REG5, val);
+
+ /* Set TX amplitude value */
+ serdes_rd(ctx, lane, RXTX_REG6, &val);
+ val = RXTX_REG6_TXAMP_CNTL_SET(val,
+ ctx->sata_param.txamplitude[lane * 3 +
+ ctx->sata_param.speed[lane]]);
+ val = RXTX_REG6_TXAMP_ENA_SET(val, 0x1);
+ val = RXTX_REG6_TX_IDLE_SET(val, 0x0);
+ val = RXTX_REG6_RX_BIST_RESYNC_SET(val, 0x0);
+ val = RXTX_REG6_RX_BIST_ERRCNT_RD_SET(val, 0x0);
+ serdes_wr(ctx, lane, RXTX_REG6, val);
+
+ /* Configure Rx for 20-bits */
+ serdes_rd(ctx, lane, RXTX_REG7, &val);
+ val = RXTX_REG7_BIST_ENA_RX_SET(val, 0x0);
+ val = RXTX_REG7_RX_WORD_MODE_SET(val, CMU_REG9_WORD_LEN_20BIT);
+ serdes_wr(ctx, lane, RXTX_REG7, val);
+
+ /* Set CDR and LOS values and enable Rx SSC */
+ serdes_rd(ctx, lane, RXTX_REG8, &val);
+ val = RXTX_REG8_CDR_LOOP_ENA_SET(val, 0x1);
+ val = RXTX_REG8_CDR_BYPASS_RXLOS_SET(val, 0x0);
+ val = RXTX_REG8_SSC_ENABLE_SET(val, 0x1);
+ val = RXTX_REG8_SD_DISABLE_SET(val, 0x0);
+ val = RXTX_REG8_SD_VREF_SET(val, 0x4);
+ serdes_wr(ctx, lane, RXTX_REG8, val);
+
+ /* Set phase adjust upper/lower limits */
+ serdes_rd(ctx, lane, RXTX_REG11, &val);
+ val = RXTX_REG11_PHASE_ADJUST_LIMIT_SET(val, 0x0);
+ serdes_wr(ctx, lane, RXTX_REG11, val);
+
+ /* Enable Latch Off; disable SUMOS and Tx termination */
+ serdes_rd(ctx, lane, RXTX_REG12, &val);
+ val = RXTX_REG12_LATCH_OFF_ENA_SET(val, 0x1);
+ val = RXTX_REG12_SUMOS_ENABLE_SET(val, 0x0);
+ val = RXTX_REG12_RX_DET_TERM_ENABLE_SET(val, 0x0);
+ serdes_wr(ctx, lane, RXTX_REG12, val);
+
+ /* Set period error latch to 512T and enable BWL */
+ serdes_rd(ctx, lane, RXTX_REG26, &val);
+ val = RXTX_REG26_PERIOD_ERROR_LATCH_SET(val, 0x0);
+ val = RXTX_REG26_BLWC_ENA_SET(val, 0x1);
+ serdes_wr(ctx, lane, RXTX_REG26, val);
+
+ serdes_wr(ctx, lane, RXTX_REG28, 0x0);
+
+ /* Set DFE loop preset value */
+ serdes_wr(ctx, lane, RXTX_REG31, 0x0);
+
+ /* Set Eye Monitor counter width to 12-bit */
+ serdes_rd(ctx, lane, RXTX_REG61, &val);
+ val = RXTX_REG61_ISCAN_INBERT_SET(val, 0x1);
+ val = RXTX_REG61_LOADFREQ_SHIFT_SET(val, 0x0);
+ val = RXTX_REG61_EYE_COUNT_WIDTH_SEL_SET(val, 0x0);
+ serdes_wr(ctx, lane, RXTX_REG61, val);
+
+ serdes_rd(ctx, lane, RXTX_REG62, &val);
+ val = RXTX_REG62_PERIOD_H1_QLATCH_SET(val, 0x0);
+ serdes_wr(ctx, lane, RXTX_REG62, val);
+
+ /* Set BW select tap X for DFE loop */
+ for (i = 0; i < 9; i++) {
+ reg = RXTX_REG81 + i * 2;
+ serdes_rd(ctx, lane, reg, &val);
+ val = RXTX_REG89_MU_TH7_SET(val, 0xe);
+ val = RXTX_REG89_MU_TH8_SET(val, 0xe);
+ val = RXTX_REG89_MU_TH9_SET(val, 0xe);
+ serdes_wr(ctx, lane, reg, val);
+ }
+
+ /* Set BW select tap X for frequency adjust loop */
+ for (i = 0; i < 3; i++) {
+ reg = RXTX_REG96 + i * 2;
+ serdes_rd(ctx, lane, reg, &val);
+ val = RXTX_REG96_MU_FREQ1_SET(val, 0x10);
+ val = RXTX_REG96_MU_FREQ2_SET(val, 0x10);
+ val = RXTX_REG96_MU_FREQ3_SET(val, 0x10);
+ serdes_wr(ctx, lane, reg, val);
+ }
+
+ /* Set BW select tap X for phase adjust loop */
+ for (i = 0; i < 3; i++) {
+ reg = RXTX_REG99 + i * 2;
+ serdes_rd(ctx, lane, reg, &val);
+ val = RXTX_REG99_MU_PHASE1_SET(val, 0x7);
+ val = RXTX_REG99_MU_PHASE2_SET(val, 0x7);
+ val = RXTX_REG99_MU_PHASE3_SET(val, 0x7);
+ serdes_wr(ctx, lane, reg, val);
+ }
+
+ serdes_rd(ctx, lane, RXTX_REG102, &val);
+ val = RXTX_REG102_FREQLOOP_LIMIT_SET(val, 0x0);
+ serdes_wr(ctx, lane, RXTX_REG102, val);
+
+ serdes_wr(ctx, lane, RXTX_REG114, 0xffe0);
+
+ serdes_rd(ctx, lane, RXTX_REG125, &val);
+ val = RXTX_REG125_SIGN_PQ_SET(val,
+ ctx->sata_param.txeyedirection[lane * 3 +
+ ctx->sata_param.speed[lane]]);
+ val = RXTX_REG125_PQ_REG_SET(val,
+ ctx->sata_param.txeyetuning[lane * 3 +
+ ctx->sata_param.speed[lane]]);
+ val = RXTX_REG125_PHZ_MANUAL_SET(val, 0x1);
+ serdes_wr(ctx, lane, RXTX_REG125, val);
+
+ serdes_rd(ctx, lane, RXTX_REG127, &val);
+ val = RXTX_REG127_LATCH_MAN_CAL_ENA_SET(val, 0x0);
+ serdes_wr(ctx, lane, RXTX_REG127, val);
+
+ serdes_rd(ctx, lane, RXTX_REG128, &val);
+ val = RXTX_REG128_LATCH_CAL_WAIT_SEL_SET(val, 0x3);
+ serdes_wr(ctx, lane, RXTX_REG128, val);
+
+ serdes_rd(ctx, lane, RXTX_REG145, &val);
+ val = RXTX_REG145_RXDFE_CONFIG_SET(val, 0x3);
+ val = RXTX_REG145_TX_IDLE_SATA_SET(val, 0x0);
+ if (preA3Chip) {
+ val = RXTX_REG145_RXES_ENA_SET(val, 0x1);
+ val = RXTX_REG145_RXVWES_LATENA_SET(val, 0x1);
+ } else {
+ val = RXTX_REG145_RXES_ENA_SET(val, 0x0);
+ val = RXTX_REG145_RXVWES_LATENA_SET(val, 0x0);
+ }
+ serdes_wr(ctx, lane, RXTX_REG145, val);
+
+ /*
+ * Set Rx LOS filter clock rate, sample rate, and threshold
+ * windows
+ */
+ for (i = 0; i < 4; i++) {
+ reg = RXTX_REG148 + i * 2;
+ serdes_wr(ctx, lane, reg, 0xFFFF);
+ }
+ }
+}
+
+static int xgene_phy_cal_rdy_chk(struct xgene_phy_ctx *ctx,
+ enum cmu_type_t cmu_type,
+ enum clk_type_t clk_type)
+{
+ void __iomem *csr_serdes = ctx->sds_base;
+ int loop;
+ u32 val;
+
+ /* Release PHY main reset */
+ writel(0xdf, csr_serdes + SATA_ENET_SDS_RST_CTL);
+ readl(csr_serdes + SATA_ENET_SDS_RST_CTL); /* Force a barrier */
+
+ if (cmu_type != REF_CMU) {
+ cmu_setbits(ctx, cmu_type, CMU_REG5, CMU_REG5_PLL_RESETB_MASK);
+ /*
+ * As per PHY design spec, the PLL reset requires a minimum
+ * of 800us.
+ */
+ usleep_range(800, 1000);
+
+ cmu_rd(ctx, cmu_type, CMU_REG1, &val);
+ val = CMU_REG1_PLL_MANUALCAL_SET(val, 0x0);
+ cmu_wr(ctx, cmu_type, CMU_REG1, val);
+ /*
+ * As per PHY design spec, the PLL auto calibration requires
+ * a minimum of 800us.
+ */
+ usleep_range(800, 1000);
+
+ cmu_toggle1to0(ctx, cmu_type, CMU_REG32,
+ CMU_REG32_FORCE_VCOCAL_START_MASK);
+ /*
+ * As per PHY design spec, the PLL requires a minimum of
+ * 800us to settle.
+ */
+ usleep_range(800, 1000);
+ }
+
+ if (!preA3Chip)
+ goto skip_manual_cal;
+
+ /*
+ * Configure the termination resister calibration
+ * The serial receive pins, RXP/RXN, have TERMination resistor
+ * that is required to be calibrated.
+ */
+ cmu_rd(ctx, cmu_type, CMU_REG17, &val);
+ val = CMU_REG17_PVT_CODE_R2A_SET(val, 0x12);
+ val = CMU_REG17_RESERVED_7_SET(val, 0x0);
+ cmu_wr(ctx, cmu_type, CMU_REG17, val);
+ cmu_toggle1to0(ctx, cmu_type, CMU_REG17,
+ CMU_REG17_PVT_TERM_MAN_ENA_MASK);
+ /*
+ * The serial transmit pins, TXP/TXN, have Pull-UP and Pull-DOWN
+ * resistors that are required to the calibrated.
+ * Configure the pull DOWN calibration
+ */
+ cmu_rd(ctx, cmu_type, CMU_REG17, &val);
+ val = CMU_REG17_PVT_CODE_R2A_SET(val, 0x29);
+ val = CMU_REG17_RESERVED_7_SET(val, 0x0);
+ cmu_wr(ctx, cmu_type, CMU_REG17, val);
+ cmu_toggle1to0(ctx, cmu_type, CMU_REG16,
+ CMU_REG16_PVT_DN_MAN_ENA_MASK);
+ /* Configure the pull UP calibration */
+ cmu_rd(ctx, cmu_type, CMU_REG17, &val);
+ val = CMU_REG17_PVT_CODE_R2A_SET(val, 0x28);
+ val = CMU_REG17_RESERVED_7_SET(val, 0x0);
+ cmu_wr(ctx, cmu_type, CMU_REG17, val);
+ cmu_toggle1to0(ctx, cmu_type, CMU_REG16,
+ CMU_REG16_PVT_UP_MAN_ENA_MASK);
+
+skip_manual_cal:
+ /* Poll the PLL calibration completion status for at least 1 ms */
+ loop = 100;
+ do {
+ cmu_rd(ctx, cmu_type, CMU_REG7, &val);
+ if (CMU_REG7_PLL_CALIB_DONE_RD(val))
+ break;
+ /*
+ * As per PHY design spec, PLL calibration status requires
+ * a minimum of 10us to be updated.
+ */
+ usleep_range(10, 100);
+ } while (--loop > 0);
+
+ cmu_rd(ctx, cmu_type, CMU_REG7, &val);
+ dev_dbg(ctx->dev, "PLL calibration %s\n",
+ CMU_REG7_PLL_CALIB_DONE_RD(val) ? "done" : "failed");
+ if (CMU_REG7_VCO_CAL_FAIL_RD(val)) {
+ dev_err(ctx->dev,
+ "PLL calibration failed due to VCO failure\n");
+ return -1;
+ }
+ dev_dbg(ctx->dev, "PLL calibration successful\n");
+
+ cmu_rd(ctx, cmu_type, CMU_REG15, &val);
+ dev_dbg(ctx->dev, "PHY Tx is %sready\n", val & 0x300 ? "" : "not ");
+ return 0;
+}
+
+static void xgene_phy_pdwn_force_vco(struct xgene_phy_ctx *ctx,
+ enum cmu_type_t cmu_type,
+ enum clk_type_t clk_type)
+{
+ u32 val;
+
+ dev_dbg(ctx->dev, "Reset VCO and re-start again\n");
+ if (cmu_type == PHY_CMU) {
+ cmu_rd(ctx, cmu_type, CMU_REG16, &val);
+ val = CMU_REG16_VCOCAL_WAIT_BTW_CODE_SET(val, 0x7);
+ cmu_wr(ctx, cmu_type, CMU_REG16, val);
+ }
+
+ cmu_toggle1to0(ctx, cmu_type, CMU_REG0, CMU_REG0_PDOWN_MASK);
+ cmu_toggle1to0(ctx, cmu_type, CMU_REG32,
+ CMU_REG32_FORCE_VCOCAL_START_MASK);
+}
+
+static int xgene_phy_hw_init_sata(struct xgene_phy_ctx *ctx,
+ enum clk_type_t clk_type, int ssc_enable)
+{
+ void __iomem *sds_base = ctx->sds_base;
+ u32 val;
+ int i;
+
+ /* Configure the PHY for operation */
+ dev_dbg(ctx->dev, "Reset PHY\n");
+ /* Place PHY into reset */
+ writel(0x0, sds_base + SATA_ENET_SDS_RST_CTL);
+ val = readl(sds_base + SATA_ENET_SDS_RST_CTL); /* Force a barrier */
+ /* Release PHY lane from reset (active high) */
+ writel(0x20, sds_base + SATA_ENET_SDS_RST_CTL);
+ readl(sds_base + SATA_ENET_SDS_RST_CTL); /* Force a barrier */
+ /* Release all PHY module out of reset except PHY main reset */
+ writel(0xde, sds_base + SATA_ENET_SDS_RST_CTL);
+ readl(sds_base + SATA_ENET_SDS_RST_CTL); /* Force a barrier */
+
+ /* Set the operation speed */
+ val = readl(sds_base + SATA_ENET_SDS_CTL1);
+ val = CFG_I_SPD_SEL_CDR_OVR1_SET(val,
+ ctx->sata_param.txspeed[ctx->sata_param.speed[0]]);
+ writel(val, sds_base + SATA_ENET_SDS_CTL1);
+
+ dev_dbg(ctx->dev, "Set the customer pin mode to SATA\n");
+ val = readl(sds_base + SATA_ENET_SDS_CTL0);
+ val = REGSPEC_CFG_I_CUSTOMER_PIN_MODE0_SET(val, 0x4421);
+ writel(val, sds_base + SATA_ENET_SDS_CTL0);
+
+ /* Configure the clock macro unit (CMU) clock type */
+ xgene_phy_cfg_cmu_clk_type(ctx, PHY_CMU, clk_type);
+
+ /* Configure the clock macro */
+ xgene_phy_sata_cfg_cmu_core(ctx, PHY_CMU, clk_type);
+
+ /* Enable SSC if enabled */
+ if (ssc_enable)
+ xgene_phy_ssc_enable(ctx, PHY_CMU);
+
+ /* Configure PHY lanes */
+ xgene_phy_sata_cfg_lanes(ctx);
+
+ /* Set Rx/Tx 20-bit */
+ val = readl(sds_base + SATA_ENET_SDS_PCS_CTL0);
+ val = REGSPEC_CFG_I_RX_WORDMODE0_SET(val, 0x3);
+ val = REGSPEC_CFG_I_TX_WORDMODE0_SET(val, 0x3);
+ writel(val, sds_base + SATA_ENET_SDS_PCS_CTL0);
+
+ /* Start PLL calibration and try for three times */
+ i = 10;
+ do {
+ if (!xgene_phy_cal_rdy_chk(ctx, PHY_CMU, clk_type))
+ break;
+ /* If failed, toggle the VCO power signal and start again */
+ xgene_phy_pdwn_force_vco(ctx, PHY_CMU, clk_type);
+ } while (--i > 0);
+ /* Even on failure, allow to continue any way */
+ if (i <= 0)
+ dev_err(ctx->dev, "PLL calibration failed\n");
+
+ return 0;
+}
+
+static int xgene_phy_hw_initialize(struct xgene_phy_ctx *ctx,
+ enum clk_type_t clk_type,
+ int ssc_enable)
+{
+ int rc;
+
+ dev_dbg(ctx->dev, "PHY init clk type %d\n", clk_type);
+
+ if (ctx->mode == MODE_SATA) {
+ rc = xgene_phy_hw_init_sata(ctx, clk_type, ssc_enable);
+ if (rc)
+ return rc;
+ } else {
+ dev_err(ctx->dev, "Un-supported customer pin mode %d\n",
+ ctx->mode);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/*
+ * Receiver Offset Calibration:
+ *
+ * Calibrate the receiver signal path offset in two steps - summar and
+ * latch calibrations
+ */
+static void xgene_phy_force_lat_summer_cal(struct xgene_phy_ctx *ctx, int lane)
+{
+ int i;
+ struct {
+ u32 reg;
+ u32 val;
+ } serdes_reg[] = {
+ {RXTX_REG38, 0x0},
+ {RXTX_REG39, 0xff00},
+ {RXTX_REG40, 0xffff},
+ {RXTX_REG41, 0xffff},
+ {RXTX_REG42, 0xffff},
+ {RXTX_REG43, 0xffff},
+ {RXTX_REG44, 0xffff},
+ {RXTX_REG45, 0xffff},
+ {RXTX_REG46, 0xffff},
+ {RXTX_REG47, 0xfffc},
+ {RXTX_REG48, 0x0},
+ {RXTX_REG49, 0x0},
+ {RXTX_REG50, 0x0},
+ {RXTX_REG51, 0x0},
+ {RXTX_REG52, 0x0},
+ {RXTX_REG53, 0x0},
+ {RXTX_REG54, 0x0},
+ {RXTX_REG55, 0x0},
+ };
+
+ /* Start SUMMER calibration */
+ serdes_setbits(ctx, lane, RXTX_REG127,
+ RXTX_REG127_FORCE_SUM_CAL_START_MASK);
+ /*
+ * As per PHY design spec, the Summer calibration requires a minimum
+ * of 100us to complete.
+ */
+ usleep_range(100, 500);
+ serdes_clrbits(ctx, lane, RXTX_REG127,
+ RXTX_REG127_FORCE_SUM_CAL_START_MASK);
+ /*
+ * As per PHY design spec, the auto calibration requires a minimum
+ * of 100us to complete.
+ */
+ usleep_range(100, 500);
+
+ /* Start latch calibration */
+ serdes_setbits(ctx, lane, RXTX_REG127,
+ RXTX_REG127_FORCE_LAT_CAL_START_MASK);
+ /*
+ * As per PHY design spec, the latch calibration requires a minimum
+ * of 100us to complete.
+ */
+ usleep_range(100, 500);
+ serdes_clrbits(ctx, lane, RXTX_REG127,
+ RXTX_REG127_FORCE_LAT_CAL_START_MASK);
+
+ /* Configure the PHY lane for calibration */
+ serdes_wr(ctx, lane, RXTX_REG28, 0x7);
+ serdes_wr(ctx, lane, RXTX_REG31, 0x7e00);
+ serdes_clrbits(ctx, lane, RXTX_REG4,
+ RXTX_REG4_TX_LOOPBACK_BUF_EN_MASK);
+ serdes_clrbits(ctx, lane, RXTX_REG7,
+ RXTX_REG7_LOOP_BACK_ENA_CTLE_MASK);
+ for (i = 0; i < ARRAY_SIZE(serdes_reg); i++)
+ serdes_wr(ctx, lane, serdes_reg[i].reg,
+ serdes_reg[i].val);
+}
+
+static void xgene_phy_reset_rxd(struct xgene_phy_ctx *ctx, int lane)
+{
+ /* Reset digital Rx */
+ serdes_clrbits(ctx, lane, RXTX_REG7, RXTX_REG7_RESETB_RXD_MASK);
+ /* As per PHY design spec, the reset requires a minimum of 100us. */
+ usleep_range(100, 150);
+ serdes_setbits(ctx, lane, RXTX_REG7, RXTX_REG7_RESETB_RXD_MASK);
+}
+
+static int xgene_phy_get_avg(int accum, int samples)
+{
+ return (accum + (samples / 2)) / samples;
+}
+
+static void xgene_phy_gen_avg_val(struct xgene_phy_ctx *ctx, int lane)
+{
+ int max_loop = 10;
+ int avg_loop = 0;
+ int lat_do = 0, lat_xo = 0, lat_eo = 0, lat_so = 0;
+ int lat_de = 0, lat_xe = 0, lat_ee = 0, lat_se = 0;
+ int sum_cal = 0;
+ int lat_do_itr, lat_xo_itr, lat_eo_itr, lat_so_itr;
+ int lat_de_itr, lat_xe_itr, lat_ee_itr, lat_se_itr;
+ int sum_cal_itr;
+ int fail_even;
+ int fail_odd;
+ u32 val;
+
+ dev_dbg(ctx->dev, "Generating avg calibration value for lane %d\n",
+ lane);
+
+ /* Enable RX Hi-Z termination */
+ serdes_setbits(ctx, lane, RXTX_REG12,
+ RXTX_REG12_RX_DET_TERM_ENABLE_MASK);
+ /* Turn off DFE */
+ serdes_wr(ctx, lane, RXTX_REG28, 0x0000);
+ /* DFE Presets to zero */
+ serdes_wr(ctx, lane, RXTX_REG31, 0x0000);
+
+ /*
+ * Receiver Offset Calibration:
+ * Calibrate the receiver signal path offset in two steps - summar
+ * and latch calibration.
+ * Runs the "Receiver Offset Calibration multiple times to determine
+ * the average value to use.
+ */
+ while (avg_loop < max_loop) {
+ /* Start the calibration */
+ xgene_phy_force_lat_summer_cal(ctx, lane);
+
+ serdes_rd(ctx, lane, RXTX_REG21, &val);
+ lat_do_itr = RXTX_REG21_DO_LATCH_CALOUT_RD(val);
+ lat_xo_itr = RXTX_REG21_XO_LATCH_CALOUT_RD(val);
+ fail_odd = RXTX_REG21_LATCH_CAL_FAIL_ODD_RD(val);
+
+ serdes_rd(ctx, lane, RXTX_REG22, &val);
+ lat_eo_itr = RXTX_REG22_EO_LATCH_CALOUT_RD(val);
+ lat_so_itr = RXTX_REG22_SO_LATCH_CALOUT_RD(val);
+ fail_even = RXTX_REG22_LATCH_CAL_FAIL_EVEN_RD(val);
+
+ serdes_rd(ctx, lane, RXTX_REG23, &val);
+ lat_de_itr = RXTX_REG23_DE_LATCH_CALOUT_RD(val);
+ lat_xe_itr = RXTX_REG23_XE_LATCH_CALOUT_RD(val);
+
+ serdes_rd(ctx, lane, RXTX_REG24, &val);
+ lat_ee_itr = RXTX_REG24_EE_LATCH_CALOUT_RD(val);
+ lat_se_itr = RXTX_REG24_SE_LATCH_CALOUT_RD(val);
+
+ serdes_rd(ctx, lane, RXTX_REG121, &val);
+ sum_cal_itr = RXTX_REG121_SUMOS_CAL_CODE_RD(val);
+
+ /* Check for failure. If passed, sum them for averaging */
+ if ((fail_even == 0 || fail_even == 1) &&
+ (fail_odd == 0 || fail_odd == 1)) {
+ lat_do += lat_do_itr;
+ lat_xo += lat_xo_itr;
+ lat_eo += lat_eo_itr;
+ lat_so += lat_so_itr;
+ lat_de += lat_de_itr;
+ lat_xe += lat_xe_itr;
+ lat_ee += lat_ee_itr;
+ lat_se += lat_se_itr;
+ sum_cal += sum_cal_itr;
+
+ dev_dbg(ctx->dev, "Iteration %d:\n", avg_loop);
+ dev_dbg(ctx->dev, "DO 0x%x XO 0x%x EO 0x%x SO 0x%x\n",
+ lat_do_itr, lat_xo_itr, lat_eo_itr,
+ lat_so_itr);
+ dev_dbg(ctx->dev, "DE 0x%x XE 0x%x EE 0x%x SE 0x%x\n",
+ lat_de_itr, lat_xe_itr, lat_ee_itr,
+ lat_se_itr);
+ dev_dbg(ctx->dev, "SUM 0x%x\n", sum_cal_itr);
+ ++avg_loop;
+ } else {
+ dev_err(ctx->dev,
+ "Receiver calibration failed at %d loop\n",
+ avg_loop);
+ }
+ xgene_phy_reset_rxd(ctx, lane);
+ }
+
+ /* Update latch manual calibration with average value */
+ serdes_rd(ctx, lane, RXTX_REG127, &val);
+ val = RXTX_REG127_DO_LATCH_MANCAL_SET(val,
+ xgene_phy_get_avg(lat_do, max_loop));
+ val = RXTX_REG127_XO_LATCH_MANCAL_SET(val,
+ xgene_phy_get_avg(lat_xo, max_loop));
+ serdes_wr(ctx, lane, RXTX_REG127, val);
+
+ serdes_rd(ctx, lane, RXTX_REG128, &val);
+ val = RXTX_REG128_EO_LATCH_MANCAL_SET(val,
+ xgene_phy_get_avg(lat_eo, max_loop));
+ val = RXTX_REG128_SO_LATCH_MANCAL_SET(val,
+ xgene_phy_get_avg(lat_so, max_loop));
+ serdes_wr(ctx, lane, RXTX_REG128, val);
+
+ serdes_rd(ctx, lane, RXTX_REG129, &val);
+ val = RXTX_REG129_DE_LATCH_MANCAL_SET(val,
+ xgene_phy_get_avg(lat_de, max_loop));
+ val = RXTX_REG129_XE_LATCH_MANCAL_SET(val,
+ xgene_phy_get_avg(lat_xe, max_loop));
+ serdes_wr(ctx, lane, RXTX_REG129, val);
+
+ serdes_rd(ctx, lane, RXTX_REG130, &val);
+ val = RXTX_REG130_EE_LATCH_MANCAL_SET(val,
+ xgene_phy_get_avg(lat_ee, max_loop));
+ val = RXTX_REG130_SE_LATCH_MANCAL_SET(val,
+ xgene_phy_get_avg(lat_se, max_loop));
+ serdes_wr(ctx, lane, RXTX_REG130, val);
+
+ /* Update SUMMER calibration with average value */
+ serdes_rd(ctx, lane, RXTX_REG14, &val);
+ val = RXTX_REG14_CLTE_LATCAL_MAN_PROG_SET(val,
+ xgene_phy_get_avg(sum_cal, max_loop));
+ serdes_wr(ctx, lane, RXTX_REG14, val);
+
+ dev_dbg(ctx->dev, "Average Value:\n");
+ dev_dbg(ctx->dev, "DO 0x%x XO 0x%x EO 0x%x SO 0x%x\n",
+ xgene_phy_get_avg(lat_do, max_loop),
+ xgene_phy_get_avg(lat_xo, max_loop),
+ xgene_phy_get_avg(lat_eo, max_loop),
+ xgene_phy_get_avg(lat_so, max_loop));
+ dev_dbg(ctx->dev, "DE 0x%x XE 0x%x EE 0x%x SE 0x%x\n",
+ xgene_phy_get_avg(lat_de, max_loop),
+ xgene_phy_get_avg(lat_xe, max_loop),
+ xgene_phy_get_avg(lat_ee, max_loop),
+ xgene_phy_get_avg(lat_se, max_loop));
+ dev_dbg(ctx->dev, "SUM 0x%x\n",
+ xgene_phy_get_avg(sum_cal, max_loop));
+
+ serdes_rd(ctx, lane, RXTX_REG14, &val);
+ val = RXTX_REG14_CTLE_LATCAL_MAN_ENA_SET(val, 0x1);
+ serdes_wr(ctx, lane, RXTX_REG14, val);
+ dev_dbg(ctx->dev, "Enable Manual Summer calibration\n");
+
+ serdes_rd(ctx, lane, RXTX_REG127, &val);
+ val = RXTX_REG127_LATCH_MAN_CAL_ENA_SET(val, 0x1);
+ dev_dbg(ctx->dev, "Enable Manual Latch calibration\n");
+ serdes_wr(ctx, lane, RXTX_REG127, val);
+
+ /* Disable RX Hi-Z termination */
+ serdes_rd(ctx, lane, RXTX_REG12, &val);
+ val = RXTX_REG12_RX_DET_TERM_ENABLE_SET(val, 0);
+ serdes_wr(ctx, lane, RXTX_REG12, val);
+ /* Turn on DFE */
+ serdes_wr(ctx, lane, RXTX_REG28, 0x0007);
+ /* Set DFE preset */
+ serdes_wr(ctx, lane, RXTX_REG31, 0x7e00);
+}
+
+static int xgene_phy_hw_init(struct phy *phy)
+{
+ struct xgene_phy_ctx *ctx = phy_get_drvdata(phy);
+ int rc;
+ int i;
+
+ rc = xgene_phy_hw_initialize(ctx, CLK_EXT_DIFF, SSC_DISABLE);
+ if (rc) {
+ dev_err(ctx->dev, "PHY initialize failed %d\n", rc);
+ return rc;
+ }
+
+ /* Setup clock properly after PHY configuration */
+ if (!IS_ERR(ctx->clk)) {
+ /* HW requires an toggle of the clock */
+ clk_prepare_enable(ctx->clk);
+ clk_disable_unprepare(ctx->clk);
+ clk_prepare_enable(ctx->clk);
+ }
+
+ /* Compute average value */
+ for (i = 0; i < MAX_LANE; i++)
+ xgene_phy_gen_avg_val(ctx, i);
+
+ dev_dbg(ctx->dev, "PHY initialized\n");
+ return 0;
+}
+
+static const struct phy_ops xgene_phy_ops = {
+ .init = xgene_phy_hw_init,
+ .owner = THIS_MODULE,
+};
+
+static struct phy *xgene_phy_xlate(struct device *dev,
+ struct of_phandle_args *args)
+{
+ struct xgene_phy_ctx *ctx = dev_get_drvdata(dev);
+
+ if (args->args_count <= 0)
+ return ERR_PTR(-EINVAL);
+ if (args->args[0] < MODE_SATA || args->args[0] >= MODE_MAX)
+ return ERR_PTR(-EINVAL);
+
+ ctx->mode = args->args[0];
+ return ctx->phy;
+}
+
+static void xgene_phy_get_param(struct platform_device *pdev,
+ const char *name, u32 *buffer,
+ int count, u32 *default_val,
+ u32 conv_factor)
+{
+ int i;
+
+ if (!of_property_read_u32_array(pdev->dev.of_node, name, buffer,
+ count)) {
+ for (i = 0; i < count; i++)
+ buffer[i] /= conv_factor;
+ return;
+ }
+ /* Does not exist, load default */
+ for (i = 0; i < count; i++)
+ buffer[i] = default_val[i % 3];
+}
+
+static int xgene_phy_probe(struct platform_device *pdev)
+{
+ struct phy_provider *phy_provider;
+ struct xgene_phy_ctx *ctx;
+ struct resource *res;
+ int rc = 0;
+ u32 default_spd[] = DEFAULT_SATA_SPD_SEL;
+ u32 default_txboost_gain[] = DEFAULT_SATA_TXBOOST_GAIN;
+ u32 default_txeye_direction[] = DEFAULT_SATA_TXEYEDIRECTION;
+ u32 default_txeye_tuning[] = DEFAULT_SATA_TXEYETUNING;
+ u32 default_txamp[] = DEFAULT_SATA_TXAMP;
+ u32 default_txcn1[] = DEFAULT_SATA_TXCN1;
+ u32 default_txcn2[] = DEFAULT_SATA_TXCN2;
+ u32 default_txcp1[] = DEFAULT_SATA_TXCP1;
+ int i;
+
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ctx->sds_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ctx->sds_base)) {
+ rc = PTR_ERR(ctx->sds_base);
+ goto error;
+ }
+
+ /* Retrieve optional clock */
+ ctx->clk = clk_get(&pdev->dev, NULL);
+
+ /* Load override paramaters */
+ xgene_phy_get_param(pdev, "apm,tx-eye-tuning",
+ ctx->sata_param.txeyetuning, 6, default_txeye_tuning, 1);
+ xgene_phy_get_param(pdev, "apm,tx-eye-direction",
+ ctx->sata_param.txeyedirection, 6, default_txeye_direction, 1);
+ xgene_phy_get_param(pdev, "apm,tx-boost-gain",
+ ctx->sata_param.txboostgain, 6, default_txboost_gain, 1);
+ xgene_phy_get_param(pdev, "apm,tx-amplitude",
+ ctx->sata_param.txamplitude, 6, default_txamp, 13300);
+ xgene_phy_get_param(pdev, "apm,tx-pre-cursor1",
+ ctx->sata_param.txprecursor_cn1, 6, default_txcn1, 18200);
+ xgene_phy_get_param(pdev, "apm,tx-pre-cursor2",
+ ctx->sata_param.txprecursor_cn2, 6, default_txcn2, 18200);
+ xgene_phy_get_param(pdev, "apm,tx-post-cursor",
+ ctx->sata_param.txpostcursor_cp1, 6, default_txcp1, 18200);
+ xgene_phy_get_param(pdev, "apm,tx-speed",
+ ctx->sata_param.txspeed, 3, default_spd, 1);
+ for (i = 0; i < MAX_LANE; i++)
+ ctx->sata_param.speed[i] = 2; /* Default to Gen3 */
+
+ ctx->dev = &pdev->dev;
+ platform_set_drvdata(pdev, ctx);
+
+ ctx->phy = devm_phy_create(ctx->dev, &xgene_phy_ops, NULL);
+ if (IS_ERR(ctx->phy)) {
+ dev_dbg(&pdev->dev, "Failed to create PHY\n");
+ rc = PTR_ERR(ctx->phy);
+ goto error;
+ }
+ phy_set_drvdata(ctx->phy, ctx);
+
+ phy_provider = devm_of_phy_provider_register(ctx->dev,
+ xgene_phy_xlate);
+ if (IS_ERR(phy_provider)) {
+ rc = PTR_ERR(phy_provider);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ return rc;
+}
+
+static const struct of_device_id xgene_phy_of_match[] = {
+ {.compatible = "apm,xgene-phy",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, xgene_phy_of_match);
+
+static struct platform_driver xgene_phy_driver = {
+ .probe = xgene_phy_probe,
+ .driver = {
+ .name = "xgene-phy",
+ .owner = THIS_MODULE,
+ .of_match_table = xgene_phy_of_match,
+ },
+};
+module_platform_driver(xgene_phy_driver);
+
+MODULE_DESCRIPTION("APM X-Gene Multi-Purpose PHY driver");
+MODULE_AUTHOR("Loc Ho <lho@apm.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.1");
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index be361b7cd30f..e49324032611 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -217,14 +217,14 @@ config PINCTRL_IMX28
select PINCTRL_MXS
config PINCTRL_MSM
- tristate
+ bool
select PINMUX
select PINCONF
select GENERIC_PINCONF
config PINCTRL_MSM8X74
tristate "Qualcomm 8x74 pin controller driver"
- depends on GPIOLIB && OF && OF_IRQ
+ depends on GPIOLIB && OF
select PINCTRL_MSM
help
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
@@ -235,6 +235,9 @@ config PINCTRL_NOMADIK
depends on ARCH_U8500 || ARCH_NOMADIK
select PINMUX
select PINCONF
+ select GPIOLIB
+ select OF_GPIO
+ select GPIOLIB_IRQCHIP
config PINCTRL_STN8815
bool "STN8815 pin controller driver"
@@ -321,6 +324,7 @@ config PINCTRL_U300
config PINCTRL_COH901
bool "ST-Ericsson U300 COH 901 335/571 GPIO"
depends on GPIOLIB && ARCH_U300 && PINCTRL_U300
+ select GPIOLIB_IRQCHIP
help
Say yes here to support GPIO interface on ST-Ericsson U300.
The names of the two IP block variants supported are
diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
index 340fb4e6c600..eda13de2e7c0 100644
--- a/drivers/pinctrl/devicetree.c
+++ b/drivers/pinctrl/devicetree.c
@@ -186,7 +186,9 @@ int pinctrl_dt_to_map(struct pinctrl *p)
/* CONFIG_OF enabled, p->dev not instantiated from DT */
if (!np) {
- dev_dbg(p->dev, "no of_node; not parsing pinctrl DT\n");
+ if (of_have_populated_dt())
+ dev_dbg(p->dev,
+ "no of_node; not parsing pinctrl DT\n");
return 0;
}
diff --git a/drivers/pinctrl/mvebu/Kconfig b/drivers/pinctrl/mvebu/Kconfig
index 366fa541ee91..cc298fade93a 100644
--- a/drivers/pinctrl/mvebu/Kconfig
+++ b/drivers/pinctrl/mvebu/Kconfig
@@ -8,6 +8,7 @@ config PINCTRL_MVEBU
config PINCTRL_DOVE
bool
select PINCTRL_MVEBU
+ select MFD_SYSCON
config PINCTRL_KIRKWOOD
bool
@@ -17,6 +18,14 @@ config PINCTRL_ARMADA_370
bool
select PINCTRL_MVEBU
+config PINCTRL_ARMADA_375
+ bool
+ select PINCTRL_MVEBU
+
+config PINCTRL_ARMADA_38X
+ bool
+ select PINCTRL_MVEBU
+
config PINCTRL_ARMADA_XP
bool
select PINCTRL_MVEBU
diff --git a/drivers/pinctrl/mvebu/Makefile b/drivers/pinctrl/mvebu/Makefile
index 37c253297af0..bc1b9f14f539 100644
--- a/drivers/pinctrl/mvebu/Makefile
+++ b/drivers/pinctrl/mvebu/Makefile
@@ -2,4 +2,6 @@ obj-$(CONFIG_PINCTRL_MVEBU) += pinctrl-mvebu.o
obj-$(CONFIG_PINCTRL_DOVE) += pinctrl-dove.o
obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o
obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o
+obj-$(CONFIG_PINCTRL_ARMADA_375) += pinctrl-armada-375.o
+obj-$(CONFIG_PINCTRL_ARMADA_38X) += pinctrl-armada-38x.o
obj-$(CONFIG_PINCTRL_ARMADA_XP) += pinctrl-armada-xp.o
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-370.c b/drivers/pinctrl/mvebu/pinctrl-armada-370.c
index ae1f760cbdd2..670e5b01c678 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-370.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-370.c
@@ -23,6 +23,18 @@
#include "pinctrl-mvebu.h"
+static void __iomem *mpp_base;
+
+static int armada_370_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+ return default_mpp_ctrl_get(mpp_base, pid, config);
+}
+
+static int armada_370_mpp_ctrl_set(unsigned pid, unsigned long config)
+{
+ return default_mpp_ctrl_set(mpp_base, pid, config);
+}
+
static struct mvebu_mpp_mode mv88f6710_mpp_modes[] = {
MPP_MODE(0,
MPP_FUNCTION(0x0, "gpio", NULL),
@@ -373,7 +385,7 @@ static struct of_device_id armada_370_pinctrl_of_match[] = {
};
static struct mvebu_mpp_ctrl mv88f6710_mpp_controls[] = {
- MPP_REG_CTRL(0, 65),
+ MPP_FUNC_CTRL(0, 65, NULL, armada_370_mpp_ctrl),
};
static struct pinctrl_gpio_range mv88f6710_mpp_gpio_ranges[] = {
@@ -385,6 +397,12 @@ static struct pinctrl_gpio_range mv88f6710_mpp_gpio_ranges[] = {
static int armada_370_pinctrl_probe(struct platform_device *pdev)
{
struct mvebu_pinctrl_soc_info *soc = &armada_370_pinctrl_info;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mpp_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mpp_base))
+ return PTR_ERR(mpp_base);
soc->variant = 0; /* no variants for Armada 370 */
soc->controls = mv88f6710_mpp_controls;
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-375.c b/drivers/pinctrl/mvebu/pinctrl-armada-375.c
new file mode 100644
index 000000000000..db078fe7ace6
--- /dev/null
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-375.c
@@ -0,0 +1,459 @@
+/*
+ * Marvell Armada 375 pinctrl driver based on mvebu pinctrl core
+ *
+ * Copyright (C) 2012 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.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/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-mvebu.h"
+
+static void __iomem *mpp_base;
+
+static int armada_375_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+ return default_mpp_ctrl_get(mpp_base, pid, config);
+}
+
+static int armada_375_mpp_ctrl_set(unsigned pid, unsigned long config)
+{
+ return default_mpp_ctrl_set(mpp_base, pid, config);
+}
+
+static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = {
+ MPP_MODE(0,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad2"),
+ MPP_FUNCTION(0x2, "spi0", "cs1"),
+ MPP_FUNCTION(0x3, "spi1", "cs1"),
+ MPP_FUNCTION(0x5, "nand", "io2")),
+ MPP_MODE(1,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad3"),
+ MPP_FUNCTION(0x2, "spi0", "mosi"),
+ MPP_FUNCTION(0x3, "spi1", "mosi"),
+ MPP_FUNCTION(0x5, "nand", "io3")),
+ MPP_MODE(2,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad4"),
+ MPP_FUNCTION(0x2, "ptp", "eventreq"),
+ MPP_FUNCTION(0x3, "led", "c0"),
+ MPP_FUNCTION(0x4, "audio", "sdi"),
+ MPP_FUNCTION(0x5, "nand", "io4"),
+ MPP_FUNCTION(0x6, "spi1", "mosi")),
+ MPP_MODE(3,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad5"),
+ MPP_FUNCTION(0x2, "ptp", "triggen"),
+ MPP_FUNCTION(0x3, "led", "p3"),
+ MPP_FUNCTION(0x4, "audio", "mclk"),
+ MPP_FUNCTION(0x5, "nand", "io5"),
+ MPP_FUNCTION(0x6, "spi1", "miso")),
+ MPP_MODE(4,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad6"),
+ MPP_FUNCTION(0x2, "spi0", "miso"),
+ MPP_FUNCTION(0x3, "spi1", "miso"),
+ MPP_FUNCTION(0x5, "nand", "io6")),
+ MPP_MODE(5,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad7"),
+ MPP_FUNCTION(0x2, "spi0", "cs2"),
+ MPP_FUNCTION(0x3, "spi1", "cs2"),
+ MPP_FUNCTION(0x5, "nand", "io7"),
+ MPP_FUNCTION(0x6, "spi1", "miso")),
+ MPP_MODE(6,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad0"),
+ MPP_FUNCTION(0x3, "led", "p1"),
+ MPP_FUNCTION(0x4, "audio", "rclk"),
+ MPP_FUNCTION(0x5, "nand", "io0")),
+ MPP_MODE(7,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad1"),
+ MPP_FUNCTION(0x2, "ptp", "clk"),
+ MPP_FUNCTION(0x3, "led", "p2"),
+ MPP_FUNCTION(0x4, "audio", "extclk"),
+ MPP_FUNCTION(0x5, "nand", "io1")),
+ MPP_MODE(8,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev ", "bootcs"),
+ MPP_FUNCTION(0x2, "spi0", "cs0"),
+ MPP_FUNCTION(0x3, "spi1", "cs0"),
+ MPP_FUNCTION(0x5, "nand", "ce")),
+ MPP_MODE(9,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "nf", "wen"),
+ MPP_FUNCTION(0x2, "spi0", "sck"),
+ MPP_FUNCTION(0x3, "spi1", "sck"),
+ MPP_FUNCTION(0x5, "nand", "we")),
+ MPP_MODE(10,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "nf", "ren"),
+ MPP_FUNCTION(0x2, "dram", "vttctrl"),
+ MPP_FUNCTION(0x3, "led", "c1"),
+ MPP_FUNCTION(0x5, "nand", "re"),
+ MPP_FUNCTION(0x6, "spi1", "sck")),
+ MPP_MODE(11,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "a0"),
+ MPP_FUNCTION(0x3, "led", "c2"),
+ MPP_FUNCTION(0x4, "audio", "sdo"),
+ MPP_FUNCTION(0x5, "nand", "cle")),
+ MPP_MODE(12,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "a1"),
+ MPP_FUNCTION(0x4, "audio", "bclk"),
+ MPP_FUNCTION(0x5, "nand", "ale")),
+ MPP_MODE(13,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "readyn"),
+ MPP_FUNCTION(0x2, "pcie0", "rstoutn"),
+ MPP_FUNCTION(0x3, "pcie1", "rstoutn"),
+ MPP_FUNCTION(0x5, "nand", "rb"),
+ MPP_FUNCTION(0x6, "spi1", "mosi")),
+ MPP_MODE(14,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "i2c0", "sda"),
+ MPP_FUNCTION(0x3, "uart1", "txd")),
+ MPP_MODE(15,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "i2c0", "sck"),
+ MPP_FUNCTION(0x3, "uart1", "rxd")),
+ MPP_MODE(16,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "uart0", "txd")),
+ MPP_MODE(17,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "uart0", "rxd")),
+ MPP_MODE(18,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "tdm", "intn")),
+ MPP_MODE(19,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "tdm", "rstn")),
+ MPP_MODE(20,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "tdm", "pclk")),
+ MPP_MODE(21,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "tdm", "fsync")),
+ MPP_MODE(22,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "tdm", "drx")),
+ MPP_MODE(23,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "tdm", "dtx")),
+ MPP_MODE(24,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "led", "p0"),
+ MPP_FUNCTION(0x2, "ge1", "rxd0"),
+ MPP_FUNCTION(0x3, "sd", "cmd"),
+ MPP_FUNCTION(0x4, "uart0", "rts"),
+ MPP_FUNCTION(0x5, "spi0", "cs0"),
+ MPP_FUNCTION(0x6, "dev", "cs1")),
+ MPP_MODE(25,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "led", "p2"),
+ MPP_FUNCTION(0x2, "ge1", "rxd1"),
+ MPP_FUNCTION(0x3, "sd", "d0"),
+ MPP_FUNCTION(0x4, "uart0", "cts"),
+ MPP_FUNCTION(0x5, "spi0", "mosi"),
+ MPP_FUNCTION(0x6, "dev", "cs2")),
+ MPP_MODE(26,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "pcie0", "clkreq"),
+ MPP_FUNCTION(0x2, "ge1", "rxd2"),
+ MPP_FUNCTION(0x3, "sd", "d2"),
+ MPP_FUNCTION(0x4, "uart1", "rts"),
+ MPP_FUNCTION(0x5, "spi0", "cs1"),
+ MPP_FUNCTION(0x6, "led", "c1")),
+ MPP_MODE(27,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "pcie1", "clkreq"),
+ MPP_FUNCTION(0x2, "ge1", "rxd3"),
+ MPP_FUNCTION(0x3, "sd", "d1"),
+ MPP_FUNCTION(0x4, "uart1", "cts"),
+ MPP_FUNCTION(0x5, "spi0", "miso"),
+ MPP_FUNCTION(0x6, "led", "c2")),
+ MPP_MODE(28,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "led", "p3"),
+ MPP_FUNCTION(0x2, "ge1", "txctl"),
+ MPP_FUNCTION(0x3, "sd", "clk"),
+ MPP_FUNCTION(0x5, "dram", "vttctrl")),
+ MPP_MODE(29,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "pcie1", "clkreq"),
+ MPP_FUNCTION(0x2, "ge1", "rxclk"),
+ MPP_FUNCTION(0x3, "sd", "d3"),
+ MPP_FUNCTION(0x5, "spi0", "sck"),
+ MPP_FUNCTION(0x6, "pcie0", "rstoutn")),
+ MPP_MODE(30,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ge1", "txd0"),
+ MPP_FUNCTION(0x3, "spi1", "cs0"),
+ MPP_FUNCTION(0x5, "led", "p3"),
+ MPP_FUNCTION(0x6, "ptp", "eventreq")),
+ MPP_MODE(31,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ge1", "txd1"),
+ MPP_FUNCTION(0x3, "spi1", "mosi"),
+ MPP_FUNCTION(0x5, "led", "p0")),
+ MPP_MODE(32,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ge1", "txd2"),
+ MPP_FUNCTION(0x3, "spi1", "sck"),
+ MPP_FUNCTION(0x4, "ptp", "triggen"),
+ MPP_FUNCTION(0x5, "led", "c0")),
+ MPP_MODE(33,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ge1", "txd3"),
+ MPP_FUNCTION(0x3, "spi1", "miso"),
+ MPP_FUNCTION(0x5, "led", "p2")),
+ MPP_MODE(34,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ge1", "txclkout"),
+ MPP_FUNCTION(0x3, "spi1", "sck"),
+ MPP_FUNCTION(0x5, "led", "c1")),
+ MPP_MODE(35,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ge1", "rxctl"),
+ MPP_FUNCTION(0x3, "spi1", "cs1"),
+ MPP_FUNCTION(0x4, "spi0", "cs2"),
+ MPP_FUNCTION(0x5, "led", "p1")),
+ MPP_MODE(36,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "pcie0", "clkreq"),
+ MPP_FUNCTION(0x5, "led", "c2")),
+ MPP_MODE(37,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "pcie0", "clkreq"),
+ MPP_FUNCTION(0x2, "tdm", "intn"),
+ MPP_FUNCTION(0x4, "ge", "mdc")),
+ MPP_MODE(38,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "pcie1", "clkreq"),
+ MPP_FUNCTION(0x4, "ge", "mdio")),
+ MPP_MODE(39,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x4, "ref", "clkout"),
+ MPP_FUNCTION(0x5, "led", "p3")),
+ MPP_MODE(40,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x4, "uart1", "txd"),
+ MPP_FUNCTION(0x5, "led", "p0")),
+ MPP_MODE(41,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x4, "uart1", "rxd"),
+ MPP_FUNCTION(0x5, "led", "p1")),
+ MPP_MODE(42,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x3, "spi1", "cs2"),
+ MPP_FUNCTION(0x4, "led", "c0"),
+ MPP_FUNCTION(0x6, "ptp", "clk")),
+ MPP_MODE(43,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "sata0", "prsnt"),
+ MPP_FUNCTION(0x4, "dram", "vttctrl"),
+ MPP_FUNCTION(0x5, "led", "c1")),
+ MPP_MODE(44,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x4, "sata0", "prsnt")),
+ MPP_MODE(45,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "spi0", "cs2"),
+ MPP_FUNCTION(0x4, "pcie0", "rstoutn"),
+ MPP_FUNCTION(0x5, "led", "c2"),
+ MPP_FUNCTION(0x6, "spi1", "cs2")),
+ MPP_MODE(46,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "led", "p0"),
+ MPP_FUNCTION(0x2, "ge0", "txd0"),
+ MPP_FUNCTION(0x3, "ge1", "txd0"),
+ MPP_FUNCTION(0x6, "dev", "wen1")),
+ MPP_MODE(47,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "led", "p1"),
+ MPP_FUNCTION(0x2, "ge0", "txd1"),
+ MPP_FUNCTION(0x3, "ge1", "txd1"),
+ MPP_FUNCTION(0x5, "ptp", "triggen"),
+ MPP_FUNCTION(0x6, "dev", "ale0")),
+ MPP_MODE(48,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "led", "p2"),
+ MPP_FUNCTION(0x2, "ge0", "txd2"),
+ MPP_FUNCTION(0x3, "ge1", "txd2"),
+ MPP_FUNCTION(0x6, "dev", "ale1")),
+ MPP_MODE(49,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "led", "p3"),
+ MPP_FUNCTION(0x2, "ge0", "txd3"),
+ MPP_FUNCTION(0x3, "ge1", "txd3"),
+ MPP_FUNCTION(0x6, "dev", "a2")),
+ MPP_MODE(50,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "led", "c0"),
+ MPP_FUNCTION(0x2, "ge0", "rxd0"),
+ MPP_FUNCTION(0x3, "ge1", "rxd0"),
+ MPP_FUNCTION(0x5, "ptp", "eventreq"),
+ MPP_FUNCTION(0x6, "dev", "ad12")),
+ MPP_MODE(51,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "led", "c1"),
+ MPP_FUNCTION(0x2, "ge0", "rxd1"),
+ MPP_FUNCTION(0x3, "ge1", "rxd1"),
+ MPP_FUNCTION(0x6, "dev", "ad8")),
+ MPP_MODE(52,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "led", "c2"),
+ MPP_FUNCTION(0x2, "ge0", "rxd2"),
+ MPP_FUNCTION(0x3, "ge1", "rxd2"),
+ MPP_FUNCTION(0x5, "i2c0", "sda"),
+ MPP_FUNCTION(0x6, "dev", "ad9")),
+ MPP_MODE(53,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "pcie1", "rstoutn"),
+ MPP_FUNCTION(0x2, "ge0", "rxd3"),
+ MPP_FUNCTION(0x3, "ge1", "rxd3"),
+ MPP_FUNCTION(0x5, "i2c0", "sck"),
+ MPP_FUNCTION(0x6, "dev", "ad10")),
+ MPP_MODE(54,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "pcie0", "rstoutn"),
+ MPP_FUNCTION(0x2, "ge0", "rxctl"),
+ MPP_FUNCTION(0x3, "ge1", "rxctl"),
+ MPP_FUNCTION(0x6, "dev", "ad11")),
+ MPP_MODE(55,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ge0", "rxclk"),
+ MPP_FUNCTION(0x3, "ge1", "rxclk"),
+ MPP_FUNCTION(0x6, "dev", "cs0")),
+ MPP_MODE(56,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ge0", "txclkout"),
+ MPP_FUNCTION(0x3, "ge1", "txclkout"),
+ MPP_FUNCTION(0x6, "dev", "oe")),
+ MPP_MODE(57,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ge0", "txctl"),
+ MPP_FUNCTION(0x3, "ge1", "txctl"),
+ MPP_FUNCTION(0x6, "dev", "wen0")),
+ MPP_MODE(58,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x4, "led", "c0")),
+ MPP_MODE(59,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x4, "led", "c1")),
+ MPP_MODE(60,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "uart1", "txd"),
+ MPP_FUNCTION(0x4, "led", "c2"),
+ MPP_FUNCTION(0x6, "dev", "ad13")),
+ MPP_MODE(61,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "i2c1", "sda"),
+ MPP_FUNCTION(0x2, "uart1", "rxd"),
+ MPP_FUNCTION(0x3, "spi1", "cs2"),
+ MPP_FUNCTION(0x4, "led", "p0"),
+ MPP_FUNCTION(0x6, "dev", "ad14")),
+ MPP_MODE(62,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "i2c1", "sck"),
+ MPP_FUNCTION(0x4, "led", "p1"),
+ MPP_FUNCTION(0x6, "dev", "ad15")),
+ MPP_MODE(63,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ptp", "triggen"),
+ MPP_FUNCTION(0x4, "led", "p2"),
+ MPP_FUNCTION(0x6, "dev", "burst")),
+ MPP_MODE(64,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "dram", "vttctrl"),
+ MPP_FUNCTION(0x4, "led", "p3")),
+ MPP_MODE(65,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "sata1", "prsnt")),
+ MPP_MODE(66,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ptp", "eventreq"),
+ MPP_FUNCTION(0x4, "spi1", "cs3"),
+ MPP_FUNCTION(0x5, "pcie0", "rstoutn"),
+ MPP_FUNCTION(0x6, "dev", "cs3")),
+};
+
+static struct mvebu_pinctrl_soc_info armada_375_pinctrl_info;
+
+static struct of_device_id armada_375_pinctrl_of_match[] = {
+ { .compatible = "marvell,mv88f6720-pinctrl" },
+ { },
+};
+
+static struct mvebu_mpp_ctrl mv88f6720_mpp_controls[] = {
+ MPP_FUNC_CTRL(0, 69, NULL, armada_375_mpp_ctrl),
+};
+
+static struct pinctrl_gpio_range mv88f6720_mpp_gpio_ranges[] = {
+ MPP_GPIO_RANGE(0, 0, 0, 32),
+ MPP_GPIO_RANGE(1, 32, 32, 32),
+ MPP_GPIO_RANGE(2, 64, 64, 3),
+};
+
+static int armada_375_pinctrl_probe(struct platform_device *pdev)
+{
+ struct mvebu_pinctrl_soc_info *soc = &armada_375_pinctrl_info;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mpp_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mpp_base))
+ return PTR_ERR(mpp_base);
+
+ soc->variant = 0; /* no variants for Armada 375 */
+ soc->controls = mv88f6720_mpp_controls;
+ soc->ncontrols = ARRAY_SIZE(mv88f6720_mpp_controls);
+ soc->modes = mv88f6720_mpp_modes;
+ soc->nmodes = ARRAY_SIZE(mv88f6720_mpp_modes);
+ soc->gpioranges = mv88f6720_mpp_gpio_ranges;
+ soc->ngpioranges = ARRAY_SIZE(mv88f6720_mpp_gpio_ranges);
+
+ pdev->dev.platform_data = soc;
+
+ return mvebu_pinctrl_probe(pdev);
+}
+
+static int armada_375_pinctrl_remove(struct platform_device *pdev)
+{
+ return mvebu_pinctrl_remove(pdev);
+}
+
+static struct platform_driver armada_375_pinctrl_driver = {
+ .driver = {
+ .name = "armada-375-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(armada_375_pinctrl_of_match),
+ },
+ .probe = armada_375_pinctrl_probe,
+ .remove = armada_375_pinctrl_remove,
+};
+
+module_platform_driver(armada_375_pinctrl_driver);
+
+MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
+MODULE_DESCRIPTION("Marvell Armada 375 pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-38x.c b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c
new file mode 100644
index 000000000000..1049f82fb62f
--- /dev/null
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c
@@ -0,0 +1,462 @@
+/*
+ * Marvell Armada 380/385 pinctrl driver based on mvebu pinctrl core
+ *
+ * Copyright (C) 2013 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.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/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-mvebu.h"
+
+static void __iomem *mpp_base;
+
+static int armada_38x_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+ return default_mpp_ctrl_get(mpp_base, pid, config);
+}
+
+static int armada_38x_mpp_ctrl_set(unsigned pid, unsigned long config)
+{
+ return default_mpp_ctrl_set(mpp_base, pid, config);
+}
+
+enum {
+ V_88F6810 = BIT(0),
+ V_88F6820 = BIT(1),
+ V_88F6828 = BIT(2),
+ V_88F6810_PLUS = (V_88F6810 | V_88F6820 | V_88F6828),
+ V_88F6820_PLUS = (V_88F6820 | V_88F6828),
+};
+
+static struct mvebu_mpp_mode armada_38x_mpp_modes[] = {
+ MPP_MODE(0,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ua0", "rxd", V_88F6810_PLUS)),
+ MPP_MODE(1,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ua0", "txd", V_88F6810_PLUS)),
+ MPP_MODE(2,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "i2c0", "sck", V_88F6810_PLUS)),
+ MPP_MODE(3,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "i2c0", "sda", V_88F6810_PLUS)),
+ MPP_MODE(4,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge", "mdc", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ua1", "txd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua0", "rts", V_88F6810_PLUS)),
+ MPP_MODE(5,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge", "mdio", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ua1", "rxd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua0", "cts", V_88F6810_PLUS)),
+ MPP_MODE(6,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txclkout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge0", "crs", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "cs3", V_88F6810_PLUS)),
+ MPP_MODE(7,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txd0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad9", V_88F6810_PLUS)),
+ MPP_MODE(8,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txd1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad10", V_88F6810_PLUS)),
+ MPP_MODE(9,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txd2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad11", V_88F6810_PLUS)),
+ MPP_MODE(10,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txd3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad12", V_88F6810_PLUS)),
+ MPP_MODE(11,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txctl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad13", V_88F6810_PLUS)),
+ MPP_MODE(12,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxd0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie1", "rstout", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "cs1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad14", V_88F6810_PLUS)),
+ MPP_MODE(13,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxd1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "pcie0", "clkreq", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie1", "clkreq", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "cs2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad15", V_88F6810_PLUS)),
+ MPP_MODE(14,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxd2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ptp", "clk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "m", "vtt_ctrl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "cs3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "wen1", V_88F6810_PLUS)),
+ MPP_MODE(15,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxd3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge", "mdc slave", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "mosi", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "pcie1", "rstout", V_88F6820_PLUS)),
+ MPP_MODE(16,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxctl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge", "mdio slave", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "m", "decc_err", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "miso", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "pcie0", "clkreq", V_88F6810_PLUS)),
+ MPP_MODE(17,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ptp", "clk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua1", "rxd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "sck", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sata1", "prsnt", V_88F6810_PLUS)),
+ MPP_MODE(18,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxerr", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ptp", "trig_gen", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua1", "txd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "cs0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "pcie1", "rstout", V_88F6820_PLUS)),
+ MPP_MODE(19,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "col", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ptp", "event_req", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie0", "clkreq", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sata1", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "ua0", "cts", V_88F6810_PLUS)),
+ MPP_MODE(20,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ptp", "clk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie1", "rstout", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(4, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "ua0", "rts", V_88F6810_PLUS)),
+ MPP_MODE(21,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "cs1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "rxd0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "cmd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "bootcs", V_88F6810_PLUS)),
+ MPP_MODE(22,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "mosi", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad0", V_88F6810_PLUS)),
+ MPP_MODE(23,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "sck", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad2", V_88F6810_PLUS)),
+ MPP_MODE(24,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "miso", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ua0", "cts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua1", "rxd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d4", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ready", V_88F6810_PLUS)),
+ MPP_MODE(25,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "cs0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ua0", "rts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua1", "txd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d5", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "cs0", V_88F6810_PLUS)),
+ MPP_MODE(26,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "cs2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "i2c1", "sck", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d6", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "cs1", V_88F6810_PLUS)),
+ MPP_MODE(27,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "cs3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "txclkout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "i2c1", "sda", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d7", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "cs2", V_88F6810_PLUS)),
+ MPP_MODE(28,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "txd0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "clk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad5", V_88F6810_PLUS)),
+ MPP_MODE(29,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "txd1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ale0", V_88F6810_PLUS)),
+ MPP_MODE(30,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "txd2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "oen", V_88F6810_PLUS)),
+ MPP_MODE(31,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "txd3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ale1", V_88F6810_PLUS)),
+ MPP_MODE(32,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "txctl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "wen0", V_88F6810_PLUS)),
+ MPP_MODE(33,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "m", "decc_err", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad3", V_88F6810_PLUS)),
+ MPP_MODE(34,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad1", V_88F6810_PLUS)),
+ MPP_MODE(35,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ref", "clk_out1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "a1", V_88F6810_PLUS)),
+ MPP_MODE(36,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ptp", "trig_gen", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "a0", V_88F6810_PLUS)),
+ MPP_MODE(37,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ptp", "clk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "rxclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad8", V_88F6810_PLUS)),
+ MPP_MODE(38,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ptp", "event_req", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "rxd1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ref", "clk_out0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad4", V_88F6810_PLUS)),
+ MPP_MODE(39,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "i2c1", "sck", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "rxd2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua0", "cts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "a2", V_88F6810_PLUS)),
+ MPP_MODE(40,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "i2c1", "sda", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "rxd3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua0", "rts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad6", V_88F6810_PLUS)),
+ MPP_MODE(41,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ua1", "rxd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "rxctl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua0", "cts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "cs3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "burst/last", V_88F6810_PLUS)),
+ MPP_MODE(42,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ua1", "txd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua0", "rts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad7", V_88F6810_PLUS)),
+ MPP_MODE(43,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "pcie0", "clkreq", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "m", "vtt_ctrl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "m", "decc_err", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "clkout", V_88F6810_PLUS)),
+ MPP_MODE(44,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "sata1", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "sata2", "prsnt", V_88F6828),
+ MPP_VAR_FUNCTION(4, "sata3", "prsnt", V_88F6828),
+ MPP_VAR_FUNCTION(5, "pcie0", "rstout", V_88F6810_PLUS)),
+ MPP_MODE(45,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ref", "clk_out0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie1", "rstout", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(4, "pcie2", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "pcie3", "rstout", V_88F6810_PLUS)),
+ MPP_MODE(46,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ref", "clk_out1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie1", "rstout", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(4, "pcie2", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "pcie3", "rstout", V_88F6810_PLUS)),
+ MPP_MODE(47,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "sata1", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "sata2", "prsnt", V_88F6828),
+ MPP_VAR_FUNCTION(4, "spi1", "cs2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sata3", "prsnt", V_88F6828)),
+ MPP_MODE(48,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "m", "vtt_ctrl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm2c", "pclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "audio", "mclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d4", V_88F6810_PLUS)),
+ MPP_MODE(49,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "sata2", "prsnt", V_88F6828),
+ MPP_VAR_FUNCTION(2, "sata3", "prsnt", V_88F6828),
+ MPP_VAR_FUNCTION(3, "tdm2c", "fsync", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "audio", "lrclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d5", V_88F6810_PLUS)),
+ MPP_MODE(50,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "pcie1", "rstout", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm2c", "drx", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "audio", "extclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "cmd", V_88F6810_PLUS)),
+ MPP_MODE(51,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm2c", "dtx", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "audio", "sdo", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "m", "decc_err", V_88F6810_PLUS)),
+ MPP_MODE(52,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "pcie1", "rstout", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm2c", "intn", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "audio", "sdi", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d6", V_88F6810_PLUS)),
+ MPP_MODE(53,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "sata1", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm2c", "rstn", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "audio", "bclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d7", V_88F6810_PLUS)),
+ MPP_MODE(54,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "sata1", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "pcie1", "rstout", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d3", V_88F6810_PLUS)),
+ MPP_MODE(55,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ua1", "cts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge", "mdio", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie1", "clkreq", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "cs1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d0", V_88F6810_PLUS)),
+ MPP_MODE(56,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ua1", "rts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge", "mdc", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "m", "decc_err", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "mosi", V_88F6810_PLUS)),
+ MPP_MODE(57,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "sck", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "clk", V_88F6810_PLUS)),
+ MPP_MODE(58,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "pcie1", "clkreq", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(2, "i2c1", "sck", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie2", "clkreq", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "miso", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d1", V_88F6810_PLUS)),
+ MPP_MODE(59,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "i2c1", "sda", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie1", "rstout", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "cs0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d2", V_88F6810_PLUS)),
+};
+
+static struct mvebu_pinctrl_soc_info armada_38x_pinctrl_info;
+
+static struct of_device_id armada_38x_pinctrl_of_match[] = {
+ {
+ .compatible = "marvell,mv88f6810-pinctrl",
+ .data = (void *) V_88F6810,
+ },
+ {
+ .compatible = "marvell,mv88f6820-pinctrl",
+ .data = (void *) V_88F6820,
+ },
+ {
+ .compatible = "marvell,mv88f6828-pinctrl",
+ .data = (void *) V_88F6828,
+ },
+ { },
+};
+
+static struct mvebu_mpp_ctrl armada_38x_mpp_controls[] = {
+ MPP_FUNC_CTRL(0, 59, NULL, armada_38x_mpp_ctrl),
+};
+
+static struct pinctrl_gpio_range armada_38x_mpp_gpio_ranges[] = {
+ MPP_GPIO_RANGE(0, 0, 0, 32),
+ MPP_GPIO_RANGE(1, 32, 32, 27),
+};
+
+static int armada_38x_pinctrl_probe(struct platform_device *pdev)
+{
+ struct mvebu_pinctrl_soc_info *soc = &armada_38x_pinctrl_info;
+ const struct of_device_id *match =
+ of_match_device(armada_38x_pinctrl_of_match, &pdev->dev);
+ struct resource *res;
+
+ if (!match)
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mpp_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mpp_base))
+ return PTR_ERR(mpp_base);
+
+ soc->variant = (unsigned) match->data & 0xff;
+ soc->controls = armada_38x_mpp_controls;
+ soc->ncontrols = ARRAY_SIZE(armada_38x_mpp_controls);
+ soc->gpioranges = armada_38x_mpp_gpio_ranges;
+ soc->ngpioranges = ARRAY_SIZE(armada_38x_mpp_gpio_ranges);
+ soc->modes = armada_38x_mpp_modes;
+ soc->nmodes = armada_38x_mpp_controls[0].npins;
+
+ pdev->dev.platform_data = soc;
+
+ return mvebu_pinctrl_probe(pdev);
+}
+
+static int armada_38x_pinctrl_remove(struct platform_device *pdev)
+{
+ return mvebu_pinctrl_remove(pdev);
+}
+
+static struct platform_driver armada_38x_pinctrl_driver = {
+ .driver = {
+ .name = "armada-38x-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(armada_38x_pinctrl_of_match),
+ },
+ .probe = armada_38x_pinctrl_probe,
+ .remove = armada_38x_pinctrl_remove,
+};
+
+module_platform_driver(armada_38x_pinctrl_driver);
+
+MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
+MODULE_DESCRIPTION("Marvell Armada 38x pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-xp.c b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c
index 843a51f9d129..de311129f7a0 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-xp.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c
@@ -33,6 +33,18 @@
#include "pinctrl-mvebu.h"
+static void __iomem *mpp_base;
+
+static int armada_xp_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+ return default_mpp_ctrl_get(mpp_base, pid, config);
+}
+
+static int armada_xp_mpp_ctrl_set(unsigned pid, unsigned long config)
+{
+ return default_mpp_ctrl_set(mpp_base, pid, config);
+}
+
enum armada_xp_variant {
V_MV78230 = BIT(0),
V_MV78260 = BIT(1),
@@ -366,7 +378,7 @@ static struct of_device_id armada_xp_pinctrl_of_match[] = {
};
static struct mvebu_mpp_ctrl mv78230_mpp_controls[] = {
- MPP_REG_CTRL(0, 48),
+ MPP_FUNC_CTRL(0, 48, NULL, armada_xp_mpp_ctrl),
};
static struct pinctrl_gpio_range mv78230_mpp_gpio_ranges[] = {
@@ -375,7 +387,7 @@ static struct pinctrl_gpio_range mv78230_mpp_gpio_ranges[] = {
};
static struct mvebu_mpp_ctrl mv78260_mpp_controls[] = {
- MPP_REG_CTRL(0, 66),
+ MPP_FUNC_CTRL(0, 66, NULL, armada_xp_mpp_ctrl),
};
static struct pinctrl_gpio_range mv78260_mpp_gpio_ranges[] = {
@@ -385,7 +397,7 @@ static struct pinctrl_gpio_range mv78260_mpp_gpio_ranges[] = {
};
static struct mvebu_mpp_ctrl mv78460_mpp_controls[] = {
- MPP_REG_CTRL(0, 66),
+ MPP_FUNC_CTRL(0, 66, NULL, armada_xp_mpp_ctrl),
};
static struct pinctrl_gpio_range mv78460_mpp_gpio_ranges[] = {
@@ -399,10 +411,16 @@ static int armada_xp_pinctrl_probe(struct platform_device *pdev)
struct mvebu_pinctrl_soc_info *soc = &armada_xp_pinctrl_info;
const struct of_device_id *match =
of_match_device(armada_xp_pinctrl_of_match, &pdev->dev);
+ struct resource *res;
if (!match)
return -ENODEV;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mpp_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mpp_base))
+ return PTR_ERR(mpp_base);
+
soc->variant = (unsigned) match->data & 0xff;
switch (soc->variant) {
diff --git a/drivers/pinctrl/mvebu/pinctrl-dove.c b/drivers/pinctrl/mvebu/pinctrl-dove.c
index 47268393af34..3b022178a566 100644
--- a/drivers/pinctrl/mvebu/pinctrl-dove.c
+++ b/drivers/pinctrl/mvebu/pinctrl-dove.c
@@ -18,107 +18,122 @@
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/mfd/syscon.h>
#include <linux/pinctrl/pinctrl.h>
+#include <linux/regmap.h>
#include "pinctrl-mvebu.h"
-#define DOVE_SB_REGS_VIRT_BASE IOMEM(0xfde00000)
-#define DOVE_MPP_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE + 0xd0200)
-#define DOVE_PMU_MPP_GENERAL_CTRL (DOVE_MPP_VIRT_BASE + 0x10)
-#define DOVE_AU0_AC97_SEL BIT(16)
-#define DOVE_PMU_SIGNAL_SELECT_0 (DOVE_SB_REGS_VIRT_BASE + 0xd802C)
-#define DOVE_PMU_SIGNAL_SELECT_1 (DOVE_SB_REGS_VIRT_BASE + 0xd8030)
-#define DOVE_GLOBAL_CONFIG_1 (DOVE_SB_REGS_VIRT_BASE + 0xe802C)
-#define DOVE_GLOBAL_CONFIG_1 (DOVE_SB_REGS_VIRT_BASE + 0xe802C)
-#define DOVE_TWSI_ENABLE_OPTION1 BIT(7)
-#define DOVE_GLOBAL_CONFIG_2 (DOVE_SB_REGS_VIRT_BASE + 0xe8030)
-#define DOVE_TWSI_ENABLE_OPTION2 BIT(20)
-#define DOVE_TWSI_ENABLE_OPTION3 BIT(21)
-#define DOVE_TWSI_OPTION3_GPIO BIT(22)
-#define DOVE_SSP_CTRL_STATUS_1 (DOVE_SB_REGS_VIRT_BASE + 0xe8034)
-#define DOVE_SSP_ON_AU1 BIT(0)
-#define DOVE_MPP_GENERAL_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE + 0xe803c)
-#define DOVE_AU1_SPDIFO_GPIO_EN BIT(1)
-#define DOVE_NAND_GPIO_EN BIT(0)
-#define DOVE_GPIO_LO_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE + 0xd0400)
-#define DOVE_MPP_CTRL4_VIRT_BASE (DOVE_GPIO_LO_VIRT_BASE + 0x40)
-#define DOVE_SPI_GPIO_SEL BIT(5)
-#define DOVE_UART1_GPIO_SEL BIT(4)
-#define DOVE_AU1_GPIO_SEL BIT(3)
-#define DOVE_CAM_GPIO_SEL BIT(2)
-#define DOVE_SD1_GPIO_SEL BIT(1)
-#define DOVE_SD0_GPIO_SEL BIT(0)
-
-#define MPPS_PER_REG 8
-#define MPP_BITS 4
-#define MPP_MASK 0xf
+/* Internal registers can be configured at any 1 MiB aligned address */
+#define INT_REGS_MASK ~(SZ_1M - 1)
+#define MPP4_REGS_OFFS 0xd0440
+#define PMU_REGS_OFFS 0xd802c
+#define GC_REGS_OFFS 0xe802c
+
+/* MPP Base registers */
+#define PMU_MPP_GENERAL_CTRL 0x10
+#define AU0_AC97_SEL BIT(16)
+
+/* MPP Control 4 register */
+#define SPI_GPIO_SEL BIT(5)
+#define UART1_GPIO_SEL BIT(4)
+#define AU1_GPIO_SEL BIT(3)
+#define CAM_GPIO_SEL BIT(2)
+#define SD1_GPIO_SEL BIT(1)
+#define SD0_GPIO_SEL BIT(0)
+
+/* PMU Signal Select registers */
+#define PMU_SIGNAL_SELECT_0 0x00
+#define PMU_SIGNAL_SELECT_1 0x04
+
+/* Global Config regmap registers */
+#define GLOBAL_CONFIG_1 0x00
+#define TWSI_ENABLE_OPTION1 BIT(7)
+#define GLOBAL_CONFIG_2 0x04
+#define TWSI_ENABLE_OPTION2 BIT(20)
+#define TWSI_ENABLE_OPTION3 BIT(21)
+#define TWSI_OPTION3_GPIO BIT(22)
+#define SSP_CTRL_STATUS_1 0x08
+#define SSP_ON_AU1 BIT(0)
+#define MPP_GENERAL_CONFIG 0x10
+#define AU1_SPDIFO_GPIO_EN BIT(1)
+#define NAND_GPIO_EN BIT(0)
#define CONFIG_PMU BIT(4)
-static int dove_pmu_mpp_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
- unsigned long *config)
+static void __iomem *mpp_base;
+static void __iomem *mpp4_base;
+static void __iomem *pmu_base;
+static struct regmap *gconfmap;
+
+static int dove_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+ return default_mpp_ctrl_get(mpp_base, pid, config);
+}
+
+static int dove_mpp_ctrl_set(unsigned pid, unsigned long config)
{
- unsigned off = (ctrl->pid / MPPS_PER_REG) * MPP_BITS;
- unsigned shift = (ctrl->pid % MPPS_PER_REG) * MPP_BITS;
- unsigned long pmu = readl(DOVE_PMU_MPP_GENERAL_CTRL);
+ return default_mpp_ctrl_set(mpp_base, pid, config);
+}
+
+static int dove_pmu_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+ unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+ unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+ unsigned long pmu = readl(mpp_base + PMU_MPP_GENERAL_CTRL);
unsigned long func;
- if (pmu & (1 << ctrl->pid)) {
- func = readl(DOVE_PMU_SIGNAL_SELECT_0 + off);
- *config = (func >> shift) & MPP_MASK;
- *config |= CONFIG_PMU;
- } else {
- func = readl(DOVE_MPP_VIRT_BASE + off);
- *config = (func >> shift) & MPP_MASK;
- }
+ if ((pmu & BIT(pid)) == 0)
+ return default_mpp_ctrl_get(mpp_base, pid, config);
+
+ func = readl(pmu_base + PMU_SIGNAL_SELECT_0 + off);
+ *config = (func >> shift) & MVEBU_MPP_MASK;
+ *config |= CONFIG_PMU;
+
return 0;
}
-static int dove_pmu_mpp_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
- unsigned long config)
+static int dove_pmu_mpp_ctrl_set(unsigned pid, unsigned long config)
{
- unsigned off = (ctrl->pid / MPPS_PER_REG) * MPP_BITS;
- unsigned shift = (ctrl->pid % MPPS_PER_REG) * MPP_BITS;
- unsigned long pmu = readl(DOVE_PMU_MPP_GENERAL_CTRL);
+ unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+ unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+ unsigned long pmu = readl(mpp_base + PMU_MPP_GENERAL_CTRL);
unsigned long func;
- if (config & CONFIG_PMU) {
- writel(pmu | (1 << ctrl->pid), DOVE_PMU_MPP_GENERAL_CTRL);
- func = readl(DOVE_PMU_SIGNAL_SELECT_0 + off);
- func &= ~(MPP_MASK << shift);
- func |= (config & MPP_MASK) << shift;
- writel(func, DOVE_PMU_SIGNAL_SELECT_0 + off);
- } else {
- writel(pmu & ~(1 << ctrl->pid), DOVE_PMU_MPP_GENERAL_CTRL);
- func = readl(DOVE_MPP_VIRT_BASE + off);
- func &= ~(MPP_MASK << shift);
- func |= (config & MPP_MASK) << shift;
- writel(func, DOVE_MPP_VIRT_BASE + off);
+ if ((config & CONFIG_PMU) == 0) {
+ writel(pmu & ~BIT(pid), mpp_base + PMU_MPP_GENERAL_CTRL);
+ return default_mpp_ctrl_set(mpp_base, pid, config);
}
+
+ writel(pmu | BIT(pid), mpp_base + PMU_MPP_GENERAL_CTRL);
+ func = readl(pmu_base + PMU_SIGNAL_SELECT_0 + off);
+ func &= ~(MVEBU_MPP_MASK << shift);
+ func |= (config & MVEBU_MPP_MASK) << shift;
+ writel(func, pmu_base + PMU_SIGNAL_SELECT_0 + off);
+
return 0;
}
-static int dove_mpp4_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
- unsigned long *config)
+static int dove_mpp4_ctrl_get(unsigned pid, unsigned long *config)
{
- unsigned long mpp4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
+ unsigned long mpp4 = readl(mpp4_base);
unsigned long mask;
- switch (ctrl->pid) {
+ switch (pid) {
case 24: /* mpp_camera */
- mask = DOVE_CAM_GPIO_SEL;
+ mask = CAM_GPIO_SEL;
break;
case 40: /* mpp_sdio0 */
- mask = DOVE_SD0_GPIO_SEL;
+ mask = SD0_GPIO_SEL;
break;
case 46: /* mpp_sdio1 */
- mask = DOVE_SD1_GPIO_SEL;
+ mask = SD1_GPIO_SEL;
break;
case 58: /* mpp_spi0 */
- mask = DOVE_SPI_GPIO_SEL;
+ mask = SPI_GPIO_SEL;
break;
case 62: /* mpp_uart1 */
- mask = DOVE_UART1_GPIO_SEL;
+ mask = UART1_GPIO_SEL;
break;
default:
return -EINVAL;
@@ -129,27 +144,26 @@ static int dove_mpp4_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
return 0;
}
-static int dove_mpp4_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
- unsigned long config)
+static int dove_mpp4_ctrl_set(unsigned pid, unsigned long config)
{
- unsigned long mpp4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
+ unsigned long mpp4 = readl(mpp4_base);
unsigned long mask;
- switch (ctrl->pid) {
+ switch (pid) {
case 24: /* mpp_camera */
- mask = DOVE_CAM_GPIO_SEL;
+ mask = CAM_GPIO_SEL;
break;
case 40: /* mpp_sdio0 */
- mask = DOVE_SD0_GPIO_SEL;
+ mask = SD0_GPIO_SEL;
break;
case 46: /* mpp_sdio1 */
- mask = DOVE_SD1_GPIO_SEL;
+ mask = SD1_GPIO_SEL;
break;
case 58: /* mpp_spi0 */
- mask = DOVE_SPI_GPIO_SEL;
+ mask = SPI_GPIO_SEL;
break;
case 62: /* mpp_uart1 */
- mask = DOVE_UART1_GPIO_SEL;
+ mask = UART1_GPIO_SEL;
break;
default:
return -EINVAL;
@@ -159,74 +173,69 @@ static int dove_mpp4_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
if (config)
mpp4 |= mask;
- writel(mpp4, DOVE_MPP_CTRL4_VIRT_BASE);
+ writel(mpp4, mpp4_base);
return 0;
}
-static int dove_nand_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
- unsigned long *config)
+static int dove_nand_ctrl_get(unsigned pid, unsigned long *config)
{
- unsigned long gmpp = readl(DOVE_MPP_GENERAL_VIRT_BASE);
+ unsigned int gmpp;
- *config = ((gmpp & DOVE_NAND_GPIO_EN) != 0);
+ regmap_read(gconfmap, MPP_GENERAL_CONFIG, &gmpp);
+ *config = ((gmpp & NAND_GPIO_EN) != 0);
return 0;
}
-static int dove_nand_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
- unsigned long config)
+static int dove_nand_ctrl_set(unsigned pid, unsigned long config)
{
- unsigned long gmpp = readl(DOVE_MPP_GENERAL_VIRT_BASE);
-
- gmpp &= ~DOVE_NAND_GPIO_EN;
- if (config)
- gmpp |= DOVE_NAND_GPIO_EN;
-
- writel(gmpp, DOVE_MPP_GENERAL_VIRT_BASE);
-
+ regmap_update_bits(gconfmap, MPP_GENERAL_CONFIG,
+ NAND_GPIO_EN,
+ (config) ? NAND_GPIO_EN : 0);
return 0;
}
-static int dove_audio0_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
- unsigned long *config)
+static int dove_audio0_ctrl_get(unsigned pid, unsigned long *config)
{
- unsigned long pmu = readl(DOVE_PMU_MPP_GENERAL_CTRL);
+ unsigned long pmu = readl(mpp_base + PMU_MPP_GENERAL_CTRL);
- *config = ((pmu & DOVE_AU0_AC97_SEL) != 0);
+ *config = ((pmu & AU0_AC97_SEL) != 0);
return 0;
}
-static int dove_audio0_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
- unsigned long config)
+static int dove_audio0_ctrl_set(unsigned pid, unsigned long config)
{
- unsigned long pmu = readl(DOVE_PMU_MPP_GENERAL_CTRL);
+ unsigned long pmu = readl(mpp_base + PMU_MPP_GENERAL_CTRL);
- pmu &= ~DOVE_AU0_AC97_SEL;
+ pmu &= ~AU0_AC97_SEL;
if (config)
- pmu |= DOVE_AU0_AC97_SEL;
- writel(pmu, DOVE_PMU_MPP_GENERAL_CTRL);
+ pmu |= AU0_AC97_SEL;
+ writel(pmu, mpp_base + PMU_MPP_GENERAL_CTRL);
return 0;
}
-static int dove_audio1_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
- unsigned long *config)
+static int dove_audio1_ctrl_get(unsigned pid, unsigned long *config)
{
- unsigned long mpp4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
- unsigned long sspc1 = readl(DOVE_SSP_CTRL_STATUS_1);
- unsigned long gmpp = readl(DOVE_MPP_GENERAL_VIRT_BASE);
- unsigned long gcfg2 = readl(DOVE_GLOBAL_CONFIG_2);
+ unsigned int mpp4 = readl(mpp4_base);
+ unsigned int sspc1;
+ unsigned int gmpp;
+ unsigned int gcfg2;
+
+ regmap_read(gconfmap, SSP_CTRL_STATUS_1, &sspc1);
+ regmap_read(gconfmap, MPP_GENERAL_CONFIG, &gmpp);
+ regmap_read(gconfmap, GLOBAL_CONFIG_2, &gcfg2);
*config = 0;
- if (mpp4 & DOVE_AU1_GPIO_SEL)
+ if (mpp4 & AU1_GPIO_SEL)
*config |= BIT(3);
- if (sspc1 & DOVE_SSP_ON_AU1)
+ if (sspc1 & SSP_ON_AU1)
*config |= BIT(2);
- if (gmpp & DOVE_AU1_SPDIFO_GPIO_EN)
+ if (gmpp & AU1_SPDIFO_GPIO_EN)
*config |= BIT(1);
- if (gcfg2 & DOVE_TWSI_OPTION3_GPIO)
+ if (gcfg2 & TWSI_OPTION3_GPIO)
*config |= BIT(0);
/* SSP/TWSI only if I2S1 not set*/
@@ -238,35 +247,24 @@ static int dove_audio1_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
return 0;
}
-static int dove_audio1_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
- unsigned long config)
+static int dove_audio1_ctrl_set(unsigned pid, unsigned long config)
{
- unsigned long mpp4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
- unsigned long sspc1 = readl(DOVE_SSP_CTRL_STATUS_1);
- unsigned long gmpp = readl(DOVE_MPP_GENERAL_VIRT_BASE);
- unsigned long gcfg2 = readl(DOVE_GLOBAL_CONFIG_2);
+ unsigned int mpp4 = readl(mpp4_base);
- /*
- * clear all audio1 related bits before configure
- */
- gcfg2 &= ~DOVE_TWSI_OPTION3_GPIO;
- gmpp &= ~DOVE_AU1_SPDIFO_GPIO_EN;
- sspc1 &= ~DOVE_SSP_ON_AU1;
- mpp4 &= ~DOVE_AU1_GPIO_SEL;
-
- if (config & BIT(0))
- gcfg2 |= DOVE_TWSI_OPTION3_GPIO;
- if (config & BIT(1))
- gmpp |= DOVE_AU1_SPDIFO_GPIO_EN;
- if (config & BIT(2))
- sspc1 |= DOVE_SSP_ON_AU1;
+ mpp4 &= ~AU1_GPIO_SEL;
if (config & BIT(3))
- mpp4 |= DOVE_AU1_GPIO_SEL;
-
- writel(mpp4, DOVE_MPP_CTRL4_VIRT_BASE);
- writel(sspc1, DOVE_SSP_CTRL_STATUS_1);
- writel(gmpp, DOVE_MPP_GENERAL_VIRT_BASE);
- writel(gcfg2, DOVE_GLOBAL_CONFIG_2);
+ mpp4 |= AU1_GPIO_SEL;
+ writel(mpp4, mpp4_base);
+
+ regmap_update_bits(gconfmap, SSP_CTRL_STATUS_1,
+ SSP_ON_AU1,
+ (config & BIT(2)) ? SSP_ON_AU1 : 0);
+ regmap_update_bits(gconfmap, MPP_GENERAL_CONFIG,
+ AU1_SPDIFO_GPIO_EN,
+ (config & BIT(1)) ? AU1_SPDIFO_GPIO_EN : 0);
+ regmap_update_bits(gconfmap, GLOBAL_CONFIG_2,
+ TWSI_OPTION3_GPIO,
+ (config & BIT(0)) ? TWSI_OPTION3_GPIO : 0);
return 0;
}
@@ -276,11 +274,11 @@ static int dove_audio1_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
* break other functions. If you require all mpps as gpio
* enforce gpio setting by pinctrl mapping.
*/
-static int dove_audio1_ctrl_gpio_req(struct mvebu_mpp_ctrl *ctrl, u8 pid)
+static int dove_audio1_ctrl_gpio_req(unsigned pid)
{
unsigned long config;
- dove_audio1_ctrl_get(ctrl, &config);
+ dove_audio1_ctrl_get(pid, &config);
switch (config) {
case 0x02: /* i2s1 : gpio[56:57] */
@@ -303,76 +301,62 @@ static int dove_audio1_ctrl_gpio_req(struct mvebu_mpp_ctrl *ctrl, u8 pid)
}
/* mpp[52:57] has gpio pins capable of in and out */
-static int dove_audio1_ctrl_gpio_dir(struct mvebu_mpp_ctrl *ctrl, u8 pid,
- bool input)
+static int dove_audio1_ctrl_gpio_dir(unsigned pid, bool input)
{
if (pid < 52 || pid > 57)
return -ENOTSUPP;
return 0;
}
-static int dove_twsi_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
- unsigned long *config)
+static int dove_twsi_ctrl_get(unsigned pid, unsigned long *config)
{
- unsigned long gcfg1 = readl(DOVE_GLOBAL_CONFIG_1);
- unsigned long gcfg2 = readl(DOVE_GLOBAL_CONFIG_2);
+ unsigned int gcfg1;
+ unsigned int gcfg2;
+
+ regmap_read(gconfmap, GLOBAL_CONFIG_1, &gcfg1);
+ regmap_read(gconfmap, GLOBAL_CONFIG_2, &gcfg2);
*config = 0;
- if (gcfg1 & DOVE_TWSI_ENABLE_OPTION1)
+ if (gcfg1 & TWSI_ENABLE_OPTION1)
*config = 1;
- else if (gcfg2 & DOVE_TWSI_ENABLE_OPTION2)
+ else if (gcfg2 & TWSI_ENABLE_OPTION2)
*config = 2;
- else if (gcfg2 & DOVE_TWSI_ENABLE_OPTION3)
+ else if (gcfg2 & TWSI_ENABLE_OPTION3)
*config = 3;
return 0;
}
-static int dove_twsi_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
- unsigned long config)
+static int dove_twsi_ctrl_set(unsigned pid, unsigned long config)
{
- unsigned long gcfg1 = readl(DOVE_GLOBAL_CONFIG_1);
- unsigned long gcfg2 = readl(DOVE_GLOBAL_CONFIG_2);
-
- gcfg1 &= ~DOVE_TWSI_ENABLE_OPTION1;
- gcfg2 &= ~(DOVE_TWSI_ENABLE_OPTION2 | DOVE_TWSI_ENABLE_OPTION3);
+ unsigned int gcfg1 = 0;
+ unsigned int gcfg2 = 0;
switch (config) {
case 1:
- gcfg1 |= DOVE_TWSI_ENABLE_OPTION1;
+ gcfg1 = TWSI_ENABLE_OPTION1;
break;
case 2:
- gcfg2 |= DOVE_TWSI_ENABLE_OPTION2;
+ gcfg2 = TWSI_ENABLE_OPTION2;
break;
case 3:
- gcfg2 |= DOVE_TWSI_ENABLE_OPTION3;
+ gcfg2 = TWSI_ENABLE_OPTION3;
break;
}
- writel(gcfg1, DOVE_GLOBAL_CONFIG_1);
- writel(gcfg2, DOVE_GLOBAL_CONFIG_2);
+ regmap_update_bits(gconfmap, GLOBAL_CONFIG_1,
+ TWSI_ENABLE_OPTION1,
+ gcfg1);
+ regmap_update_bits(gconfmap, GLOBAL_CONFIG_2,
+ TWSI_ENABLE_OPTION2 | TWSI_ENABLE_OPTION3,
+ gcfg2);
return 0;
}
static struct mvebu_mpp_ctrl dove_mpp_controls[] = {
- MPP_FUNC_CTRL(0, 0, "mpp0", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(1, 1, "mpp1", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(2, 2, "mpp2", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(3, 3, "mpp3", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(4, 4, "mpp4", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(5, 5, "mpp5", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(6, 6, "mpp6", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(7, 7, "mpp7", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(8, 8, "mpp8", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(9, 9, "mpp9", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(10, 10, "mpp10", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(11, 11, "mpp11", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(12, 12, "mpp12", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(13, 13, "mpp13", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(14, 14, "mpp14", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(15, 15, "mpp15", dove_pmu_mpp_ctrl),
- MPP_REG_CTRL(16, 23),
+ MPP_FUNC_CTRL(0, 15, NULL, dove_pmu_mpp_ctrl),
+ MPP_FUNC_CTRL(16, 23, NULL, dove_mpp_ctrl),
MPP_FUNC_CTRL(24, 39, "mpp_camera", dove_mpp4_ctrl),
MPP_FUNC_CTRL(40, 45, "mpp_sdio0", dove_mpp4_ctrl),
MPP_FUNC_CTRL(46, 51, "mpp_sdio1", dove_mpp4_ctrl),
@@ -772,8 +756,17 @@ static struct of_device_id dove_pinctrl_of_match[] = {
{ }
};
+static struct regmap_config gc_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = 5,
+};
+
static int dove_pinctrl_probe(struct platform_device *pdev)
{
+ struct resource *res, *mpp_res;
+ struct resource fb_res;
const struct of_device_id *match =
of_match_device(dove_pinctrl_of_match, &pdev->dev);
pdev->dev.platform_data = (void *)match->data;
@@ -789,6 +782,59 @@ static int dove_pinctrl_probe(struct platform_device *pdev)
}
clk_prepare_enable(clk);
+ mpp_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mpp_base = devm_ioremap_resource(&pdev->dev, mpp_res);
+ if (IS_ERR(mpp_base))
+ return PTR_ERR(mpp_base);
+
+ /* prepare fallback resource */
+ memcpy(&fb_res, mpp_res, sizeof(struct resource));
+ fb_res.start = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ dev_warn(&pdev->dev, "falling back to hardcoded MPP4 resource\n");
+ adjust_resource(&fb_res,
+ (mpp_res->start & INT_REGS_MASK) + MPP4_REGS_OFFS, 0x4);
+ res = &fb_res;
+ }
+
+ mpp4_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mpp4_base))
+ return PTR_ERR(mpp4_base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (!res) {
+ dev_warn(&pdev->dev, "falling back to hardcoded PMU resource\n");
+ adjust_resource(&fb_res,
+ (mpp_res->start & INT_REGS_MASK) + PMU_REGS_OFFS, 0x8);
+ res = &fb_res;
+ }
+
+ pmu_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pmu_base))
+ return PTR_ERR(pmu_base);
+
+ gconfmap = syscon_regmap_lookup_by_compatible("marvell,dove-global-config");
+ if (IS_ERR(gconfmap)) {
+ void __iomem *gc_base;
+
+ dev_warn(&pdev->dev, "falling back to hardcoded global registers\n");
+ adjust_resource(&fb_res,
+ (mpp_res->start & INT_REGS_MASK) + GC_REGS_OFFS, 0x14);
+ gc_base = devm_ioremap_resource(&pdev->dev, &fb_res);
+ if (IS_ERR(gc_base))
+ return PTR_ERR(gc_base);
+ gconfmap = devm_regmap_init_mmio(&pdev->dev,
+ gc_base, &gc_regmap_config);
+ if (IS_ERR(gconfmap))
+ return PTR_ERR(gconfmap);
+ }
+
+ /* Warn on any missing DT resource */
+ if (fb_res.start)
+ dev_warn(&pdev->dev, FW_BUG "Missing pinctrl regs in DTB. Please update your firmware.\n");
+
return mvebu_pinctrl_probe(pdev);
}
diff --git a/drivers/pinctrl/mvebu/pinctrl-kirkwood.c b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c
index 6b504b5935a5..0d0211a1a0b0 100644
--- a/drivers/pinctrl/mvebu/pinctrl-kirkwood.c
+++ b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c
@@ -21,6 +21,18 @@
#include "pinctrl-mvebu.h"
+static void __iomem *mpp_base;
+
+static int kirkwood_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+ return default_mpp_ctrl_get(mpp_base, pid, config);
+}
+
+static int kirkwood_mpp_ctrl_set(unsigned pid, unsigned long config)
+{
+ return default_mpp_ctrl_set(mpp_base, pid, config);
+}
+
#define V(f6180, f6190, f6192, f6281, f6282, dx4122) \
((f6180 << 0) | (f6190 << 1) | (f6192 << 2) | \
(f6281 << 3) | (f6282 << 4) | (dx4122 << 5))
@@ -359,7 +371,7 @@ static struct mvebu_mpp_mode mv88f6xxx_mpp_modes[] = {
};
static struct mvebu_mpp_ctrl mv88f6180_mpp_controls[] = {
- MPP_REG_CTRL(0, 29),
+ MPP_FUNC_CTRL(0, 29, NULL, kirkwood_mpp_ctrl),
};
static struct pinctrl_gpio_range mv88f6180_gpio_ranges[] = {
@@ -367,7 +379,7 @@ static struct pinctrl_gpio_range mv88f6180_gpio_ranges[] = {
};
static struct mvebu_mpp_ctrl mv88f619x_mpp_controls[] = {
- MPP_REG_CTRL(0, 35),
+ MPP_FUNC_CTRL(0, 35, NULL, kirkwood_mpp_ctrl),
};
static struct pinctrl_gpio_range mv88f619x_gpio_ranges[] = {
@@ -376,7 +388,7 @@ static struct pinctrl_gpio_range mv88f619x_gpio_ranges[] = {
};
static struct mvebu_mpp_ctrl mv88f628x_mpp_controls[] = {
- MPP_REG_CTRL(0, 49),
+ MPP_FUNC_CTRL(0, 49, NULL, kirkwood_mpp_ctrl),
};
static struct pinctrl_gpio_range mv88f628x_gpio_ranges[] = {
@@ -456,9 +468,16 @@ static struct of_device_id kirkwood_pinctrl_of_match[] = {
static int kirkwood_pinctrl_probe(struct platform_device *pdev)
{
+ struct resource *res;
const struct of_device_id *match =
of_match_device(kirkwood_pinctrl_of_match, &pdev->dev);
pdev->dev.platform_data = (void *)match->data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mpp_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mpp_base))
+ return PTR_ERR(mpp_base);
+
return mvebu_pinctrl_probe(pdev);
}
diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
index 0fd1ad31fbf9..9908374f8f92 100644
--- a/drivers/pinctrl/mvebu/pinctrl-mvebu.c
+++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
@@ -50,7 +50,6 @@ struct mvebu_pinctrl {
struct device *dev;
struct pinctrl_dev *pctldev;
struct pinctrl_desc desc;
- void __iomem *base;
struct mvebu_pinctrl_group *groups;
unsigned num_groups;
struct mvebu_pinctrl_function *functions;
@@ -138,43 +137,6 @@ static struct mvebu_pinctrl_function *mvebu_pinctrl_find_function_by_name(
return NULL;
}
-/*
- * Common mpp pin configuration registers on MVEBU are
- * registers of eight 4-bit values for each mpp setting.
- * Register offset and bit mask are calculated accordingly below.
- */
-static int mvebu_common_mpp_get(struct mvebu_pinctrl *pctl,
- struct mvebu_pinctrl_group *grp,
- unsigned long *config)
-{
- unsigned pin = grp->gid;
- unsigned off = (pin / MPPS_PER_REG) * MPP_BITS;
- unsigned shift = (pin % MPPS_PER_REG) * MPP_BITS;
-
- *config = readl(pctl->base + off);
- *config >>= shift;
- *config &= MPP_MASK;
-
- return 0;
-}
-
-static int mvebu_common_mpp_set(struct mvebu_pinctrl *pctl,
- struct mvebu_pinctrl_group *grp,
- unsigned long config)
-{
- unsigned pin = grp->gid;
- unsigned off = (pin / MPPS_PER_REG) * MPP_BITS;
- unsigned shift = (pin % MPPS_PER_REG) * MPP_BITS;
- unsigned long reg;
-
- reg = readl(pctl->base + off);
- reg &= ~(MPP_MASK << shift);
- reg |= (config << shift);
- writel(reg, pctl->base + off);
-
- return 0;
-}
-
static int mvebu_pinconf_group_get(struct pinctrl_dev *pctldev,
unsigned gid, unsigned long *config)
{
@@ -184,10 +146,7 @@ static int mvebu_pinconf_group_get(struct pinctrl_dev *pctldev,
if (!grp->ctrl)
return -EINVAL;
- if (grp->ctrl->mpp_get)
- return grp->ctrl->mpp_get(grp->ctrl, config);
-
- return mvebu_common_mpp_get(pctl, grp, config);
+ return grp->ctrl->mpp_get(grp->pins[0], config);
}
static int mvebu_pinconf_group_set(struct pinctrl_dev *pctldev,
@@ -202,11 +161,7 @@ static int mvebu_pinconf_group_set(struct pinctrl_dev *pctldev,
return -EINVAL;
for (i = 0; i < num_configs; i++) {
- if (grp->ctrl->mpp_set)
- ret = grp->ctrl->mpp_set(grp->ctrl, configs[i]);
- else
- ret = mvebu_common_mpp_set(pctl, grp, configs[i]);
-
+ ret = grp->ctrl->mpp_set(grp->pins[0], configs[i]);
if (ret)
return ret;
} /* for each config */
@@ -347,7 +302,7 @@ static int mvebu_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev,
return -EINVAL;
if (grp->ctrl->mpp_gpio_req)
- return grp->ctrl->mpp_gpio_req(grp->ctrl, offset);
+ return grp->ctrl->mpp_gpio_req(offset);
setting = mvebu_pinctrl_find_gpio_setting(pctl, grp);
if (!setting)
@@ -370,7 +325,7 @@ static int mvebu_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
return -EINVAL;
if (grp->ctrl->mpp_gpio_dir)
- return grp->ctrl->mpp_gpio_dir(grp->ctrl, offset, input);
+ return grp->ctrl->mpp_gpio_dir(offset, input);
setting = mvebu_pinctrl_find_gpio_setting(pctl, grp);
if (!setting)
@@ -593,11 +548,12 @@ static int mvebu_pinctrl_build_functions(struct platform_device *pdev,
int mvebu_pinctrl_probe(struct platform_device *pdev)
{
struct mvebu_pinctrl_soc_info *soc = dev_get_platdata(&pdev->dev);
- struct resource *res;
struct mvebu_pinctrl *pctl;
- void __iomem *base;
struct pinctrl_pin_desc *pdesc;
unsigned gid, n, k;
+ unsigned size, noname = 0;
+ char *noname_buf;
+ void *p;
int ret;
if (!soc || !soc->controls || !soc->modes) {
@@ -605,11 +561,6 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
return -EINVAL;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
pctl = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pinctrl),
GFP_KERNEL);
if (!pctl) {
@@ -623,7 +574,6 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
pctl->desc.pmxops = &mvebu_pinmux_ops;
pctl->desc.confops = &mvebu_pinconf_ops;
pctl->variant = soc->variant;
- pctl->base = base;
pctl->dev = &pdev->dev;
platform_set_drvdata(pdev, pctl);
@@ -633,33 +583,23 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
pctl->desc.npins = 0;
for (n = 0; n < soc->ncontrols; n++) {
struct mvebu_mpp_ctrl *ctrl = &soc->controls[n];
- char *names;
pctl->desc.npins += ctrl->npins;
- /* initial control pins */
+ /* initialize control's pins[] array */
for (k = 0; k < ctrl->npins; k++)
ctrl->pins[k] = ctrl->pid + k;
- /* special soc specific control */
- if (ctrl->mpp_get || ctrl->mpp_set) {
- if (!ctrl->name || !ctrl->mpp_get || !ctrl->mpp_set) {
- dev_err(&pdev->dev, "wrong soc control info\n");
- return -EINVAL;
- }
+ /*
+ * We allow to pass controls with NULL name that we treat
+ * as a range of one-pin groups with generic mvebu register
+ * controls.
+ */
+ if (!ctrl->name) {
+ pctl->num_groups += ctrl->npins;
+ noname += ctrl->npins;
+ } else {
pctl->num_groups += 1;
- continue;
}
-
- /* generic mvebu register control */
- names = devm_kzalloc(&pdev->dev, ctrl->npins * 8, GFP_KERNEL);
- if (!names) {
- dev_err(&pdev->dev, "failed to alloc mpp names\n");
- return -ENOMEM;
- }
- for (k = 0; k < ctrl->npins; k++)
- sprintf(names + 8*k, "mpp%d", ctrl->pid+k);
- ctrl->name = names;
- pctl->num_groups += ctrl->npins;
}
pdesc = devm_kzalloc(&pdev->dev, pctl->desc.npins *
@@ -673,12 +613,17 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
pdesc[n].number = n;
pctl->desc.pins = pdesc;
- pctl->groups = devm_kzalloc(&pdev->dev, pctl->num_groups *
- sizeof(struct mvebu_pinctrl_group), GFP_KERNEL);
- if (!pctl->groups) {
- dev_err(&pdev->dev, "failed to alloc pinctrl groups\n");
+ /*
+ * allocate groups and name buffers for unnamed groups.
+ */
+ size = pctl->num_groups * sizeof(*pctl->groups) + noname * 8;
+ p = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+ if (!p) {
+ dev_err(&pdev->dev, "failed to alloc group data\n");
return -ENOMEM;
}
+ pctl->groups = p;
+ noname_buf = p + pctl->num_groups * sizeof(*pctl->groups);
/* assign mpp controls to groups */
gid = 0;
@@ -690,17 +635,26 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
pctl->groups[gid].pins = ctrl->pins;
pctl->groups[gid].npins = ctrl->npins;
- /* generic mvebu register control maps to a number of groups */
- if (!ctrl->mpp_get && !ctrl->mpp_set) {
+ /*
+ * We treat unnamed controls as a range of one-pin groups
+ * with generic mvebu register controls. Use one group for
+ * each in this range and assign a default group name.
+ */
+ if (!ctrl->name) {
+ pctl->groups[gid].name = noname_buf;
pctl->groups[gid].npins = 1;
+ sprintf(noname_buf, "mpp%d", ctrl->pid+0);
+ noname_buf += 8;
for (k = 1; k < ctrl->npins; k++) {
gid++;
pctl->groups[gid].gid = gid;
pctl->groups[gid].ctrl = ctrl;
- pctl->groups[gid].name = &ctrl->name[8*k];
+ pctl->groups[gid].name = noname_buf;
pctl->groups[gid].pins = &ctrl->pins[k];
pctl->groups[gid].npins = 1;
+ sprintf(noname_buf, "mpp%d", ctrl->pid+k);
+ noname_buf += 8;
}
}
gid++;
diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.h b/drivers/pinctrl/mvebu/pinctrl-mvebu.h
index 90bd3beee860..65a98e6f7265 100644
--- a/drivers/pinctrl/mvebu/pinctrl-mvebu.h
+++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.h
@@ -28,20 +28,19 @@
* between two or more different settings, e.g. assign mpp pin 13 to
* uart1 or sata.
*
- * If optional mpp_get/_set functions are set these are used to get/set
- * a specific mode. Otherwise it is assumed that the mpp control is based
- * on 4-bit groups in subsequent registers. The optional mpp_gpio_req/_dir
- * functions can be used to allow pin settings with varying gpio pins.
+ * The mpp_get/_set functions are mandatory and are used to get/set a
+ * specific mode. The optional mpp_gpio_req/_dir functions can be used
+ * to allow pin settings with varying gpio pins.
*/
struct mvebu_mpp_ctrl {
const char *name;
u8 pid;
u8 npins;
unsigned *pins;
- int (*mpp_get)(struct mvebu_mpp_ctrl *ctrl, unsigned long *config);
- int (*mpp_set)(struct mvebu_mpp_ctrl *ctrl, unsigned long config);
- int (*mpp_gpio_req)(struct mvebu_mpp_ctrl *ctrl, u8 pid);
- int (*mpp_gpio_dir)(struct mvebu_mpp_ctrl *ctrl, u8 pid, bool input);
+ int (*mpp_get)(unsigned pid, unsigned long *config);
+ int (*mpp_set)(unsigned pid, unsigned long config);
+ int (*mpp_gpio_req)(unsigned pid);
+ int (*mpp_gpio_dir)(unsigned pid, bool input);
};
/**
@@ -114,18 +113,6 @@ struct mvebu_pinctrl_soc_info {
int ngpioranges;
};
-#define MPP_REG_CTRL(_idl, _idh) \
- { \
- .name = NULL, \
- .pid = _idl, \
- .npins = _idh - _idl + 1, \
- .pins = (unsigned[_idh - _idl + 1]) { }, \
- .mpp_get = NULL, \
- .mpp_set = NULL, \
- .mpp_gpio_req = NULL, \
- .mpp_gpio_dir = NULL, \
- }
-
#define MPP_FUNC_CTRL(_idl, _idh, _name, _func) \
{ \
.name = _name, \
@@ -186,6 +173,34 @@ struct mvebu_pinctrl_soc_info {
.npins = _npins, \
}
+#define MVEBU_MPPS_PER_REG 8
+#define MVEBU_MPP_BITS 4
+#define MVEBU_MPP_MASK 0xf
+
+static inline int default_mpp_ctrl_get(void __iomem *base, unsigned int pid,
+ unsigned long *config)
+{
+ unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+ unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+
+ *config = (readl(base + off) >> shift) & MVEBU_MPP_MASK;
+
+ return 0;
+}
+
+static inline int default_mpp_ctrl_set(void __iomem *base, unsigned int pid,
+ unsigned long config)
+{
+ unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+ unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+ unsigned long reg;
+
+ reg = readl(base + off) & ~(MVEBU_MPP_MASK << shift);
+ writel(reg | (config << shift), base + off);
+
+ return 0;
+}
+
int mvebu_pinctrl_probe(struct platform_device *pdev);
int mvebu_pinctrl_remove(struct platform_device *pdev);
diff --git a/drivers/pinctrl/pinctrl-adi2-bf54x.c b/drivers/pinctrl/pinctrl-adi2-bf54x.c
index ea9d9ab9cda1..008a29e92e56 100644
--- a/drivers/pinctrl/pinctrl-adi2-bf54x.c
+++ b/drivers/pinctrl/pinctrl-adi2-bf54x.c
@@ -309,39 +309,6 @@ static const unsigned keys_8x8_pins[] = {
GPIO_PE4, GPIO_PE5, GPIO_PE6, GPIO_PE7,
};
-static const struct adi_pin_group adi_pin_groups[] = {
- ADI_PIN_GROUP("uart0grp", uart0_pins),
- ADI_PIN_GROUP("uart1grp", uart1_pins),
- ADI_PIN_GROUP("uart1ctsrtsgrp", uart1_ctsrts_pins),
- ADI_PIN_GROUP("uart2grp", uart2_pins),
- ADI_PIN_GROUP("uart3grp", uart3_pins),
- ADI_PIN_GROUP("uart3ctsrtsgrp", uart3_ctsrts_pins),
- ADI_PIN_GROUP("rsi0grp", rsi0_pins),
- ADI_PIN_GROUP("spi0grp", spi0_pins),
- ADI_PIN_GROUP("spi1grp", spi1_pins),
- ADI_PIN_GROUP("twi0grp", twi0_pins),
- ADI_PIN_GROUP("twi1grp", twi1_pins),
- ADI_PIN_GROUP("rotarygrp", rotary_pins),
- ADI_PIN_GROUP("can0grp", can0_pins),
- ADI_PIN_GROUP("can1grp", can1_pins),
- ADI_PIN_GROUP("smc0grp", smc0_pins),
- ADI_PIN_GROUP("sport0grp", sport0_pins),
- ADI_PIN_GROUP("sport1grp", sport1_pins),
- ADI_PIN_GROUP("sport2grp", sport2_pins),
- ADI_PIN_GROUP("sport3grp", sport3_pins),
- ADI_PIN_GROUP("ppi0_8bgrp", ppi0_8b_pins),
- ADI_PIN_GROUP("ppi0_16bgrp", ppi0_16b_pins),
- ADI_PIN_GROUP("ppi0_24bgrp", ppi0_24b_pins),
- ADI_PIN_GROUP("ppi1_8bgrp", ppi1_8b_pins),
- ADI_PIN_GROUP("ppi1_16bgrp", ppi1_16b_pins),
- ADI_PIN_GROUP("ppi2_8bgrp", ppi2_8b_pins),
- ADI_PIN_GROUP("atapigrp", atapi_pins),
- ADI_PIN_GROUP("atapialtergrp", atapi_alter_pins),
- ADI_PIN_GROUP("nfc0grp", nfc0_pins),
- ADI_PIN_GROUP("keys_4x4grp", keys_4x4_pins),
- ADI_PIN_GROUP("keys_8x8grp", keys_8x8_pins),
-};
-
static const unsigned short uart0_mux[] = {
P_UART0_TX, P_UART0_RX,
0
@@ -513,6 +480,39 @@ static const unsigned short keys_8x8_mux[] = {
0
};
+static const struct adi_pin_group adi_pin_groups[] = {
+ ADI_PIN_GROUP("uart0grp", uart0_pins, uart0_mux),
+ ADI_PIN_GROUP("uart1grp", uart1_pins, uart1_mux),
+ ADI_PIN_GROUP("uart1ctsrtsgrp", uart1_ctsrts_pins, uart1_ctsrts_mux),
+ ADI_PIN_GROUP("uart2grp", uart2_pins, uart2_mux),
+ ADI_PIN_GROUP("uart3grp", uart3_pins, uart3_mux),
+ ADI_PIN_GROUP("uart3ctsrtsgrp", uart3_ctsrts_pins, uart3_ctsrts_mux),
+ ADI_PIN_GROUP("rsi0grp", rsi0_pins, rsi0_mux),
+ ADI_PIN_GROUP("spi0grp", spi0_pins, spi0_mux),
+ ADI_PIN_GROUP("spi1grp", spi1_pins, spi1_mux),
+ ADI_PIN_GROUP("twi0grp", twi0_pins, twi0_mux),
+ ADI_PIN_GROUP("twi1grp", twi1_pins, twi1_mux),
+ ADI_PIN_GROUP("rotarygrp", rotary_pins, rotary_mux),
+ ADI_PIN_GROUP("can0grp", can0_pins, can0_mux),
+ ADI_PIN_GROUP("can1grp", can1_pins, can1_mux),
+ ADI_PIN_GROUP("smc0grp", smc0_pins, smc0_mux),
+ ADI_PIN_GROUP("sport0grp", sport0_pins, sport0_mux),
+ ADI_PIN_GROUP("sport1grp", sport1_pins, sport1_mux),
+ ADI_PIN_GROUP("sport2grp", sport2_pins, sport2_mux),
+ ADI_PIN_GROUP("sport3grp", sport3_pins, sport3_mux),
+ ADI_PIN_GROUP("ppi0_8bgrp", ppi0_8b_pins, ppi0_8b_mux),
+ ADI_PIN_GROUP("ppi0_16bgrp", ppi0_16b_pins, ppi0_16b_mux),
+ ADI_PIN_GROUP("ppi0_24bgrp", ppi0_24b_pins, ppi0_24b_mux),
+ ADI_PIN_GROUP("ppi1_8bgrp", ppi1_8b_pins, ppi1_8b_mux),
+ ADI_PIN_GROUP("ppi1_16bgrp", ppi1_16b_pins, ppi1_16b_mux),
+ ADI_PIN_GROUP("ppi2_8bgrp", ppi2_8b_pins, ppi2_8b_mux),
+ ADI_PIN_GROUP("atapigrp", atapi_pins, atapi_mux),
+ ADI_PIN_GROUP("atapialtergrp", atapi_alter_pins, atapi_alter_mux),
+ ADI_PIN_GROUP("nfc0grp", nfc0_pins, nfc0_mux),
+ ADI_PIN_GROUP("keys_4x4grp", keys_4x4_pins, keys_4x4_mux),
+ ADI_PIN_GROUP("keys_8x8grp", keys_8x8_pins, keys_8x8_mux),
+};
+
static const char * const uart0grp[] = { "uart0grp" };
static const char * const uart1grp[] = { "uart1grp" };
static const char * const uart1ctsrtsgrp[] = { "uart1ctsrtsgrp" };
@@ -532,49 +532,45 @@ static const char * const sport0grp[] = { "sport0grp" };
static const char * const sport1grp[] = { "sport1grp" };
static const char * const sport2grp[] = { "sport2grp" };
static const char * const sport3grp[] = { "sport3grp" };
-static const char * const ppi0_8bgrp[] = { "ppi0_8bgrp" };
-static const char * const ppi0_16bgrp[] = { "ppi0_16bgrp" };
-static const char * const ppi0_24bgrp[] = { "ppi0_24bgrp" };
-static const char * const ppi1_8bgrp[] = { "ppi1_8bgrp" };
-static const char * const ppi1_16bgrp[] = { "ppi1_16bgrp" };
-static const char * const ppi2_8bgrp[] = { "ppi2_8bgrp" };
+static const char * const ppi0grp[] = { "ppi0_8bgrp",
+ "ppi0_16bgrp",
+ "ppi0_24bgrp" };
+static const char * const ppi1grp[] = { "ppi1_8bgrp",
+ "ppi1_16bgrp" };
+static const char * const ppi2grp[] = { "ppi2_8bgrp" };
static const char * const atapigrp[] = { "atapigrp" };
static const char * const atapialtergrp[] = { "atapialtergrp" };
static const char * const nfc0grp[] = { "nfc0grp" };
-static const char * const keys_4x4grp[] = { "keys_4x4grp" };
-static const char * const keys_8x8grp[] = { "keys_8x8grp" };
+static const char * const keysgrp[] = { "keys_4x4grp",
+ "keys_8x8grp" };
static const struct adi_pmx_func adi_pmx_functions[] = {
- ADI_PMX_FUNCTION("uart0", uart0grp, uart0_mux),
- ADI_PMX_FUNCTION("uart1", uart1grp, uart1_mux),
- ADI_PMX_FUNCTION("uart1_ctsrts", uart1ctsrtsgrp, uart1_ctsrts_mux),
- ADI_PMX_FUNCTION("uart2", uart2grp, uart2_mux),
- ADI_PMX_FUNCTION("uart3", uart3grp, uart3_mux),
- ADI_PMX_FUNCTION("uart3_ctsrts", uart3ctsrtsgrp, uart3_ctsrts_mux),
- ADI_PMX_FUNCTION("rsi0", rsi0grp, rsi0_mux),
- ADI_PMX_FUNCTION("spi0", spi0grp, spi0_mux),
- ADI_PMX_FUNCTION("spi1", spi1grp, spi1_mux),
- ADI_PMX_FUNCTION("twi0", twi0grp, twi0_mux),
- ADI_PMX_FUNCTION("twi1", twi1grp, twi1_mux),
- ADI_PMX_FUNCTION("rotary", rotarygrp, rotary_mux),
- ADI_PMX_FUNCTION("can0", can0grp, can0_mux),
- ADI_PMX_FUNCTION("can1", can1grp, can1_mux),
- ADI_PMX_FUNCTION("smc0", smc0grp, smc0_mux),
- ADI_PMX_FUNCTION("sport0", sport0grp, sport0_mux),
- ADI_PMX_FUNCTION("sport1", sport1grp, sport1_mux),
- ADI_PMX_FUNCTION("sport2", sport2grp, sport2_mux),
- ADI_PMX_FUNCTION("sport3", sport3grp, sport3_mux),
- ADI_PMX_FUNCTION("ppi0_8b", ppi0_8bgrp, ppi0_8b_mux),
- ADI_PMX_FUNCTION("ppi0_16b", ppi0_16bgrp, ppi0_16b_mux),
- ADI_PMX_FUNCTION("ppi0_24b", ppi0_24bgrp, ppi0_24b_mux),
- ADI_PMX_FUNCTION("ppi1_8b", ppi1_8bgrp, ppi1_8b_mux),
- ADI_PMX_FUNCTION("ppi1_16b", ppi1_16bgrp, ppi1_16b_mux),
- ADI_PMX_FUNCTION("ppi2_8b", ppi2_8bgrp, ppi2_8b_mux),
- ADI_PMX_FUNCTION("atapi", atapigrp, atapi_mux),
- ADI_PMX_FUNCTION("atapi_alter", atapialtergrp, atapi_alter_mux),
- ADI_PMX_FUNCTION("nfc0", nfc0grp, nfc0_mux),
- ADI_PMX_FUNCTION("keys_4x4", keys_4x4grp, keys_4x4_mux),
- ADI_PMX_FUNCTION("keys_8x8", keys_8x8grp, keys_8x8_mux),
+ ADI_PMX_FUNCTION("uart0", uart0grp),
+ ADI_PMX_FUNCTION("uart1", uart1grp),
+ ADI_PMX_FUNCTION("uart1_ctsrts", uart1ctsrtsgrp),
+ ADI_PMX_FUNCTION("uart2", uart2grp),
+ ADI_PMX_FUNCTION("uart3", uart3grp),
+ ADI_PMX_FUNCTION("uart3_ctsrts", uart3ctsrtsgrp),
+ ADI_PMX_FUNCTION("rsi0", rsi0grp),
+ ADI_PMX_FUNCTION("spi0", spi0grp),
+ ADI_PMX_FUNCTION("spi1", spi1grp),
+ ADI_PMX_FUNCTION("twi0", twi0grp),
+ ADI_PMX_FUNCTION("twi1", twi1grp),
+ ADI_PMX_FUNCTION("rotary", rotarygrp),
+ ADI_PMX_FUNCTION("can0", can0grp),
+ ADI_PMX_FUNCTION("can1", can1grp),
+ ADI_PMX_FUNCTION("smc0", smc0grp),
+ ADI_PMX_FUNCTION("sport0", sport0grp),
+ ADI_PMX_FUNCTION("sport1", sport1grp),
+ ADI_PMX_FUNCTION("sport2", sport2grp),
+ ADI_PMX_FUNCTION("sport3", sport3grp),
+ ADI_PMX_FUNCTION("ppi0", ppi0grp),
+ ADI_PMX_FUNCTION("ppi1", ppi1grp),
+ ADI_PMX_FUNCTION("ppi2", ppi2grp),
+ ADI_PMX_FUNCTION("atapi", atapigrp),
+ ADI_PMX_FUNCTION("atapi_alter", atapialtergrp),
+ ADI_PMX_FUNCTION("nfc0", nfc0grp),
+ ADI_PMX_FUNCTION("keys", keysgrp),
};
static const struct adi_pinctrl_soc_data adi_bf54x_soc = {
diff --git a/drivers/pinctrl/pinctrl-adi2-bf60x.c b/drivers/pinctrl/pinctrl-adi2-bf60x.c
index bf57aea2826c..4cb59fe9be70 100644
--- a/drivers/pinctrl/pinctrl-adi2-bf60x.c
+++ b/drivers/pinctrl/pinctrl-adi2-bf60x.c
@@ -259,37 +259,6 @@ static const unsigned lp3_pins[] = {
GPIO_PF12, GPIO_PF13, GPIO_PF14, GPIO_PF15,
};
-static const struct adi_pin_group adi_pin_groups[] = {
- ADI_PIN_GROUP("uart0grp", uart0_pins),
- ADI_PIN_GROUP("uart0ctsrtsgrp", uart0_ctsrts_pins),
- ADI_PIN_GROUP("uart1grp", uart1_pins),
- ADI_PIN_GROUP("uart1ctsrtsgrp", uart1_ctsrts_pins),
- ADI_PIN_GROUP("rsi0grp", rsi0_pins),
- ADI_PIN_GROUP("eth0grp", eth0_pins),
- ADI_PIN_GROUP("eth1grp", eth1_pins),
- ADI_PIN_GROUP("spi0grp", spi0_pins),
- ADI_PIN_GROUP("spi1grp", spi1_pins),
- ADI_PIN_GROUP("twi0grp", twi0_pins),
- ADI_PIN_GROUP("twi1grp", twi1_pins),
- ADI_PIN_GROUP("rotarygrp", rotary_pins),
- ADI_PIN_GROUP("can0grp", can0_pins),
- ADI_PIN_GROUP("smc0grp", smc0_pins),
- ADI_PIN_GROUP("sport0grp", sport0_pins),
- ADI_PIN_GROUP("sport1grp", sport1_pins),
- ADI_PIN_GROUP("sport2grp", sport2_pins),
- ADI_PIN_GROUP("ppi0_8bgrp", ppi0_8b_pins),
- ADI_PIN_GROUP("ppi0_16bgrp", ppi0_16b_pins),
- ADI_PIN_GROUP("ppi0_24bgrp", ppi0_24b_pins),
- ADI_PIN_GROUP("ppi1_8bgrp", ppi1_8b_pins),
- ADI_PIN_GROUP("ppi1_16bgrp", ppi1_16b_pins),
- ADI_PIN_GROUP("ppi2_8bgrp", ppi2_8b_pins),
- ADI_PIN_GROUP("ppi2_16bgrp", ppi2_16b_pins),
- ADI_PIN_GROUP("lp0grp", lp0_pins),
- ADI_PIN_GROUP("lp1grp", lp1_pins),
- ADI_PIN_GROUP("lp2grp", lp2_pins),
- ADI_PIN_GROUP("lp3grp", lp3_pins),
-};
-
static const unsigned short uart0_mux[] = {
P_UART0_TX, P_UART0_RX,
0
@@ -446,6 +415,37 @@ static const unsigned short lp3_mux[] = {
0
};
+static const struct adi_pin_group adi_pin_groups[] = {
+ ADI_PIN_GROUP("uart0grp", uart0_pins, uart0_mux),
+ ADI_PIN_GROUP("uart0ctsrtsgrp", uart0_ctsrts_pins, uart0_ctsrts_mux),
+ ADI_PIN_GROUP("uart1grp", uart1_pins, uart1_mux),
+ ADI_PIN_GROUP("uart1ctsrtsgrp", uart1_ctsrts_pins, uart1_ctsrts_mux),
+ ADI_PIN_GROUP("rsi0grp", rsi0_pins, rsi0_mux),
+ ADI_PIN_GROUP("eth0grp", eth0_pins, eth0_mux),
+ ADI_PIN_GROUP("eth1grp", eth1_pins, eth1_mux),
+ ADI_PIN_GROUP("spi0grp", spi0_pins, spi0_mux),
+ ADI_PIN_GROUP("spi1grp", spi1_pins, spi1_mux),
+ ADI_PIN_GROUP("twi0grp", twi0_pins, twi0_mux),
+ ADI_PIN_GROUP("twi1grp", twi1_pins, twi1_mux),
+ ADI_PIN_GROUP("rotarygrp", rotary_pins, rotary_mux),
+ ADI_PIN_GROUP("can0grp", can0_pins, can0_mux),
+ ADI_PIN_GROUP("smc0grp", smc0_pins, smc0_mux),
+ ADI_PIN_GROUP("sport0grp", sport0_pins, sport0_mux),
+ ADI_PIN_GROUP("sport1grp", sport1_pins, sport1_mux),
+ ADI_PIN_GROUP("sport2grp", sport2_pins, sport2_mux),
+ ADI_PIN_GROUP("ppi0_8bgrp", ppi0_8b_pins, ppi0_8b_mux),
+ ADI_PIN_GROUP("ppi0_16bgrp", ppi0_16b_pins, ppi0_16b_mux),
+ ADI_PIN_GROUP("ppi0_24bgrp", ppi0_24b_pins, ppi0_24b_mux),
+ ADI_PIN_GROUP("ppi1_8bgrp", ppi1_8b_pins, ppi1_8b_mux),
+ ADI_PIN_GROUP("ppi1_16bgrp", ppi1_16b_pins, ppi1_16b_mux),
+ ADI_PIN_GROUP("ppi2_8bgrp", ppi2_8b_pins, ppi2_8b_mux),
+ ADI_PIN_GROUP("ppi2_16bgrp", ppi2_16b_pins, ppi2_16b_mux),
+ ADI_PIN_GROUP("lp0grp", lp0_pins, lp0_mux),
+ ADI_PIN_GROUP("lp1grp", lp1_pins, lp1_mux),
+ ADI_PIN_GROUP("lp2grp", lp2_pins, lp2_mux),
+ ADI_PIN_GROUP("lp3grp", lp3_pins, lp3_mux),
+};
+
static const char * const uart0grp[] = { "uart0grp" };
static const char * const uart0ctsrtsgrp[] = { "uart0ctsrtsgrp" };
static const char * const uart1grp[] = { "uart1grp" };
@@ -463,47 +463,43 @@ static const char * const smc0grp[] = { "smc0grp" };
static const char * const sport0grp[] = { "sport0grp" };
static const char * const sport1grp[] = { "sport1grp" };
static const char * const sport2grp[] = { "sport2grp" };
-static const char * const ppi0_8bgrp[] = { "ppi0_8bgrp" };
-static const char * const ppi0_16bgrp[] = { "ppi0_16bgrp" };
-static const char * const ppi0_24bgrp[] = { "ppi0_24bgrp" };
-static const char * const ppi1_8bgrp[] = { "ppi1_8bgrp" };
-static const char * const ppi1_16bgrp[] = { "ppi1_16bgrp" };
-static const char * const ppi2_8bgrp[] = { "ppi2_8bgrp" };
-static const char * const ppi2_16bgrp[] = { "ppi2_16bgrp" };
+static const char * const ppi0grp[] = { "ppi0_8bgrp",
+ "ppi0_16bgrp",
+ "ppi0_24bgrp" };
+static const char * const ppi1grp[] = { "ppi1_8bgrp",
+ "ppi1_16bgrp" };
+static const char * const ppi2grp[] = { "ppi2_8bgrp",
+ "ppi2_16bgrp" };
static const char * const lp0grp[] = { "lp0grp" };
static const char * const lp1grp[] = { "lp1grp" };
static const char * const lp2grp[] = { "lp2grp" };
static const char * const lp3grp[] = { "lp3grp" };
static const struct adi_pmx_func adi_pmx_functions[] = {
- ADI_PMX_FUNCTION("uart0", uart0grp, uart0_mux),
- ADI_PMX_FUNCTION("uart0_ctsrts", uart0ctsrtsgrp, uart0_ctsrts_mux),
- ADI_PMX_FUNCTION("uart1", uart1grp, uart1_mux),
- ADI_PMX_FUNCTION("uart1_ctsrts", uart1ctsrtsgrp, uart1_ctsrts_mux),
- ADI_PMX_FUNCTION("rsi0", rsi0grp, rsi0_mux),
- ADI_PMX_FUNCTION("eth0", eth0grp, eth0_mux),
- ADI_PMX_FUNCTION("eth1", eth1grp, eth1_mux),
- ADI_PMX_FUNCTION("spi0", spi0grp, spi0_mux),
- ADI_PMX_FUNCTION("spi1", spi1grp, spi1_mux),
- ADI_PMX_FUNCTION("twi0", twi0grp, twi0_mux),
- ADI_PMX_FUNCTION("twi1", twi1grp, twi1_mux),
- ADI_PMX_FUNCTION("rotary", rotarygrp, rotary_mux),
- ADI_PMX_FUNCTION("can0", can0grp, can0_mux),
- ADI_PMX_FUNCTION("smc0", smc0grp, smc0_mux),
- ADI_PMX_FUNCTION("sport0", sport0grp, sport0_mux),
- ADI_PMX_FUNCTION("sport1", sport1grp, sport1_mux),
- ADI_PMX_FUNCTION("sport2", sport2grp, sport2_mux),
- ADI_PMX_FUNCTION("ppi0_8b", ppi0_8bgrp, ppi0_8b_mux),
- ADI_PMX_FUNCTION("ppi0_16b", ppi0_16bgrp, ppi0_16b_mux),
- ADI_PMX_FUNCTION("ppi0_24b", ppi0_24bgrp, ppi0_24b_mux),
- ADI_PMX_FUNCTION("ppi1_8b", ppi1_8bgrp, ppi1_8b_mux),
- ADI_PMX_FUNCTION("ppi1_16b", ppi1_16bgrp, ppi1_16b_mux),
- ADI_PMX_FUNCTION("ppi2_8b", ppi2_8bgrp, ppi2_8b_mux),
- ADI_PMX_FUNCTION("ppi2_16b", ppi2_16bgrp, ppi2_16b_mux),
- ADI_PMX_FUNCTION("lp0", lp0grp, lp0_mux),
- ADI_PMX_FUNCTION("lp1", lp1grp, lp1_mux),
- ADI_PMX_FUNCTION("lp2", lp2grp, lp2_mux),
- ADI_PMX_FUNCTION("lp3", lp3grp, lp3_mux),
+ ADI_PMX_FUNCTION("uart0", uart0grp),
+ ADI_PMX_FUNCTION("uart0_ctsrts", uart0ctsrtsgrp),
+ ADI_PMX_FUNCTION("uart1", uart1grp),
+ ADI_PMX_FUNCTION("uart1_ctsrts", uart1ctsrtsgrp),
+ ADI_PMX_FUNCTION("rsi0", rsi0grp),
+ ADI_PMX_FUNCTION("eth0", eth0grp),
+ ADI_PMX_FUNCTION("eth1", eth1grp),
+ ADI_PMX_FUNCTION("spi0", spi0grp),
+ ADI_PMX_FUNCTION("spi1", spi1grp),
+ ADI_PMX_FUNCTION("twi0", twi0grp),
+ ADI_PMX_FUNCTION("twi1", twi1grp),
+ ADI_PMX_FUNCTION("rotary", rotarygrp),
+ ADI_PMX_FUNCTION("can0", can0grp),
+ ADI_PMX_FUNCTION("smc0", smc0grp),
+ ADI_PMX_FUNCTION("sport0", sport0grp),
+ ADI_PMX_FUNCTION("sport1", sport1grp),
+ ADI_PMX_FUNCTION("sport2", sport2grp),
+ ADI_PMX_FUNCTION("ppi0", ppi0grp),
+ ADI_PMX_FUNCTION("ppi1", ppi1grp),
+ ADI_PMX_FUNCTION("ppi2", ppi2grp),
+ ADI_PMX_FUNCTION("lp0", lp0grp),
+ ADI_PMX_FUNCTION("lp1", lp1grp),
+ ADI_PMX_FUNCTION("lp2", lp2grp),
+ ADI_PMX_FUNCTION("lp3", lp3grp),
};
static const struct adi_pinctrl_soc_data adi_bf60x_soc = {
diff --git a/drivers/pinctrl/pinctrl-adi2.c b/drivers/pinctrl/pinctrl-adi2.c
index 7a39562c3e42..0cc0eec83396 100644
--- a/drivers/pinctrl/pinctrl-adi2.c
+++ b/drivers/pinctrl/pinctrl-adi2.c
@@ -89,6 +89,19 @@ struct gpio_port_saved {
u32 mux;
};
+/*
+ * struct gpio_pint_saved - PINT registers saved in PM operations
+ *
+ * @assign: ASSIGN register
+ * @edge_set: EDGE_SET register
+ * @invert_set: INVERT_SET register
+ */
+struct gpio_pint_saved {
+ u32 assign;
+ u32 edge_set;
+ u32 invert_set;
+};
+
/**
* struct gpio_pint - Pin interrupt controller device. Multiple ADI GPIO
* banks can be mapped into one Pin interrupt controller.
@@ -114,7 +127,7 @@ struct gpio_pint {
int irq;
struct irq_domain *domain[2];
struct gpio_pint_regs *regs;
- struct adi_pm_pint_save saved_data;
+ struct gpio_pint_saved saved_data;
int map_count;
spinlock_t lock;
@@ -160,7 +173,7 @@ struct adi_pinctrl {
struct gpio_port {
struct list_head node;
void __iomem *base;
- unsigned int irq_base;
+ int irq_base;
unsigned int width;
struct gpio_port_t *regs;
struct gpio_port_saved saved_data;
@@ -324,6 +337,7 @@ static unsigned int adi_gpio_irq_startup(struct irq_data *d)
if (!port) {
pr_err("GPIO IRQ %d :Not exist\n", d->irq);
+ /* FIXME: negative return code will be ignored */
return -ENODEV;
}
@@ -605,8 +619,8 @@ static struct pinctrl_ops adi_pctrl_ops = {
.get_group_pins = adi_get_group_pins,
};
-static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
- unsigned group)
+static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned func_id,
+ unsigned group_id)
{
struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
struct gpio_port *port;
@@ -614,7 +628,7 @@ static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
unsigned long flags;
unsigned short *mux, pin;
- mux = (unsigned short *)pinctrl->soc->functions[selector].mux;
+ mux = (unsigned short *)pinctrl->soc->groups[group_id].mux;
while (*mux) {
pin = P_IDENT(*mux);
@@ -628,7 +642,7 @@ static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
spin_lock_irqsave(&port->lock, flags);
portmux_setup(port, pin_to_offset(range, pin),
- P_FUNCT2MUX(*mux));
+ P_FUNCT2MUX(*mux));
port_setup(port, pin_to_offset(range, pin), false);
mux++;
@@ -638,8 +652,8 @@ static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
return 0;
}
-static void adi_pinmux_disable(struct pinctrl_dev *pctldev, unsigned selector,
- unsigned group)
+static void adi_pinmux_disable(struct pinctrl_dev *pctldev, unsigned func_id,
+ unsigned group_id)
{
struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
struct gpio_port *port;
@@ -647,7 +661,7 @@ static void adi_pinmux_disable(struct pinctrl_dev *pctldev, unsigned selector,
unsigned long flags;
unsigned short *mux, pin;
- mux = (unsigned short *)pinctrl->soc->functions[selector].mux;
+ mux = (unsigned short *)pinctrl->soc->groups[group_id].mux;
while (*mux) {
pin = P_IDENT(*mux);
diff --git a/drivers/pinctrl/pinctrl-adi2.h b/drivers/pinctrl/pinctrl-adi2.h
index 1f06f8df1fa3..3ca29738213f 100644
--- a/drivers/pinctrl/pinctrl-adi2.h
+++ b/drivers/pinctrl/pinctrl-adi2.h
@@ -21,13 +21,15 @@ struct adi_pin_group {
const char *name;
const unsigned *pins;
const unsigned num;
+ const unsigned short *mux;
};
-#define ADI_PIN_GROUP(n, p) \
+#define ADI_PIN_GROUP(n, p, m) \
{ \
.name = n, \
.pins = p, \
.num = ARRAY_SIZE(p), \
+ .mux = m, \
}
/**
@@ -41,15 +43,13 @@ struct adi_pmx_func {
const char *name;
const char * const *groups;
const unsigned num_groups;
- const unsigned short *mux;
};
-#define ADI_PMX_FUNCTION(n, g, m) \
+#define ADI_PMX_FUNCTION(n, g) \
{ \
.name = n, \
.groups = g, \
.num_groups = ARRAY_SIZE(g), \
- .mux = m, \
}
/**
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index d990e33d8aa7..5d24aaec5dbc 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -1137,6 +1137,17 @@ static void at91_gpio_free(struct gpio_chip *chip, unsigned offset)
pinctrl_free_gpio(gpio);
}
+static int at91_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned mask = 1 << offset;
+ u32 osr;
+
+ osr = readl_relaxed(pio + PIO_OSR);
+ return !(osr & mask);
+}
+
static int at91_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
@@ -1325,6 +1336,31 @@ static int alt_gpio_irq_type(struct irq_data *d, unsigned type)
return 0;
}
+static unsigned int gpio_irq_startup(struct irq_data *d)
+{
+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+ unsigned pin = d->hwirq;
+ int ret;
+
+ ret = gpio_lock_as_irq(&at91_gpio->chip, pin);
+ if (ret) {
+ dev_err(at91_gpio->chip.dev, "unable to lock pind %lu IRQ\n",
+ d->hwirq);
+ return ret;
+ }
+ gpio_irq_unmask(d);
+ return 0;
+}
+
+static void gpio_irq_shutdown(struct irq_data *d)
+{
+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+ unsigned pin = d->hwirq;
+
+ gpio_irq_mask(d);
+ gpio_unlock_as_irq(&at91_gpio->chip, pin);
+}
+
#ifdef CONFIG_PM
static u32 wakeups[MAX_GPIO_BANKS];
@@ -1399,6 +1435,8 @@ void at91_pinctrl_gpio_resume(void)
static struct irq_chip gpio_irqchip = {
.name = "GPIO",
+ .irq_startup = gpio_irq_startup,
+ .irq_shutdown = gpio_irq_shutdown,
.irq_disable = gpio_irq_mask,
.irq_mask = gpio_irq_mask,
.irq_unmask = gpio_irq_unmask,
@@ -1543,6 +1581,7 @@ static int at91_gpio_of_irq_setup(struct device_node *node,
static struct gpio_chip at91_gpio_template = {
.request = at91_gpio_request,
.free = at91_gpio_free,
+ .get_direction = at91_gpio_get_direction,
.direction_input = at91_gpio_direction_input,
.get = at91_gpio_get,
.direction_output = at91_gpio_direction_output,
diff --git a/drivers/pinctrl/pinctrl-baytrail.c b/drivers/pinctrl/pinctrl-baytrail.c
index 665b96bc0c3a..6e8301f77187 100644
--- a/drivers/pinctrl/pinctrl-baytrail.c
+++ b/drivers/pinctrl/pinctrl-baytrail.c
@@ -60,6 +60,10 @@
#define BYT_NGPIO_NCORE 28
#define BYT_NGPIO_SUS 44
+#define BYT_SCORE_ACPI_UID "1"
+#define BYT_NCORE_ACPI_UID "2"
+#define BYT_SUS_ACPI_UID "3"
+
/*
* Baytrail gpio controller consist of three separate sub-controllers called
* SCORE, NCORE and SUS. The sub-controllers are identified by their acpi UID.
@@ -102,17 +106,17 @@ static unsigned const sus_pins[BYT_NGPIO_SUS] = {
static struct pinctrl_gpio_range byt_ranges[] = {
{
- .name = "1", /* match with acpi _UID in probe */
+ .name = BYT_SCORE_ACPI_UID, /* match with acpi _UID in probe */
.npins = BYT_NGPIO_SCORE,
.pins = score_pins,
},
{
- .name = "2",
+ .name = BYT_NCORE_ACPI_UID,
.npins = BYT_NGPIO_NCORE,
.pins = ncore_pins,
},
{
- .name = "3",
+ .name = BYT_SUS_ACPI_UID,
.npins = BYT_NGPIO_SUS,
.pins = sus_pins,
},
@@ -145,9 +149,41 @@ static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset,
return vg->reg_base + reg_offset + reg;
}
+static bool is_special_pin(struct byt_gpio *vg, unsigned offset)
+{
+ /* SCORE pin 92-93 */
+ if (!strcmp(vg->range->name, BYT_SCORE_ACPI_UID) &&
+ offset >= 92 && offset <= 93)
+ return true;
+
+ /* SUS pin 11-21 */
+ if (!strcmp(vg->range->name, BYT_SUS_ACPI_UID) &&
+ offset >= 11 && offset <= 21)
+ return true;
+
+ return false;
+}
+
static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
{
struct byt_gpio *vg = to_byt_gpio(chip);
+ void __iomem *reg = byt_gpio_reg(chip, offset, BYT_CONF0_REG);
+ u32 value;
+ bool special;
+
+ /*
+ * In most cases, func pin mux 000 means GPIO function.
+ * But, some pins may have func pin mux 001 represents
+ * GPIO function. Only allow user to export pin with
+ * func pin mux preset as GPIO function by BIOS/FW.
+ */
+ value = readl(reg) & BYT_PIN_MUX;
+ special = is_special_pin(vg, offset);
+ if ((special && value != 1) || (!special && value)) {
+ dev_err(&vg->pdev->dev,
+ "pin %u cannot be used as GPIO.\n", offset);
+ return -EINVAL;
+ }
pm_runtime_get(&vg->pdev->dev);
@@ -371,23 +407,23 @@ static void byt_irq_mask(struct irq_data *d)
{
}
-static unsigned int byt_irq_startup(struct irq_data *d)
+static int byt_irq_reqres(struct irq_data *d)
{
struct byt_gpio *vg = irq_data_get_irq_chip_data(d);
- if (gpio_lock_as_irq(&vg->chip, irqd_to_hwirq(d)))
+ if (gpio_lock_as_irq(&vg->chip, irqd_to_hwirq(d))) {
dev_err(vg->chip.dev,
"unable to lock HW IRQ %lu for IRQ\n",
irqd_to_hwirq(d));
- byt_irq_unmask(d);
+ return -EINVAL;
+ }
return 0;
}
-static void byt_irq_shutdown(struct irq_data *d)
+static void byt_irq_relres(struct irq_data *d)
{
struct byt_gpio *vg = irq_data_get_irq_chip_data(d);
- byt_irq_mask(d);
gpio_unlock_as_irq(&vg->chip, irqd_to_hwirq(d));
}
@@ -396,8 +432,8 @@ static struct irq_chip byt_irqchip = {
.irq_mask = byt_irq_mask,
.irq_unmask = byt_irq_unmask,
.irq_set_type = byt_irq_type,
- .irq_startup = byt_irq_startup,
- .irq_shutdown = byt_irq_shutdown,
+ .irq_request_resources = byt_irq_reqres,
+ .irq_release_resources = byt_irq_relres,
};
static void byt_gpio_irq_init_hw(struct byt_gpio *vg)
diff --git a/drivers/pinctrl/pinctrl-capri.c b/drivers/pinctrl/pinctrl-capri.c
index 4669c53f99b0..eb2500212147 100644
--- a/drivers/pinctrl/pinctrl-capri.c
+++ b/drivers/pinctrl/pinctrl-capri.c
@@ -1435,7 +1435,7 @@ int __init capri_pinctrl_probe(struct platform_device *pdev)
}
static struct of_device_id capri_pinctrl_of_match[] = {
- { .compatible = "brcm,capri-pinctrl", },
+ { .compatible = "brcm,bcm11351-pinctrl", },
{ },
};
diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c
index 162ac0d73739..d182fdd2e715 100644
--- a/drivers/pinctrl/pinctrl-coh901.c
+++ b/drivers/pinctrl/pinctrl-coh901.c
@@ -8,17 +8,14 @@
* Author: Jonas Aaberg <jonas.aberg@stericsson.com>
*/
#include <linux/module.h>
-#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/io.h>
-#include <linux/irqdomain.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
-#include <linux/list.h>
#include <linux/slab.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinconf-generic.h>
@@ -61,9 +58,17 @@
#define U300_GPIO_PINS_PER_PORT 8
#define U300_GPIO_MAX (U300_GPIO_PINS_PER_PORT * U300_GPIO_NUM_PORTS)
+struct u300_gpio_port {
+ struct u300_gpio *gpio;
+ char name[8];
+ int irq;
+ int number;
+ u8 toggle_edge_mode;
+};
+
struct u300_gpio {
struct gpio_chip chip;
- struct list_head port_list;
+ struct u300_gpio_port ports[U300_GPIO_NUM_PORTS];
struct clk *clk;
void __iomem *base;
struct device *dev;
@@ -78,16 +83,6 @@ struct u300_gpio {
u32 iev;
};
-struct u300_gpio_port {
- struct list_head node;
- struct u300_gpio *gpio;
- char name[8];
- struct irq_domain *domain;
- int irq;
- int number;
- u8 toggle_edge_mode;
-};
-
/*
* Macro to expand to read a specific register found in the "gpio"
* struct. It requires the struct u300_gpio *gpio variable to exist in
@@ -308,39 +303,6 @@ static int u300_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
return 0;
}
-static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- struct u300_gpio *gpio = to_u300_gpio(chip);
- int portno = offset >> 3;
- struct u300_gpio_port *port = NULL;
- struct list_head *p;
- int retirq;
- bool found = false;
-
- list_for_each(p, &gpio->port_list) {
- port = list_entry(p, struct u300_gpio_port, node);
- if (port->number == portno) {
- found = true;
- break;
- }
- }
- if (!found) {
- dev_err(gpio->dev, "could not locate port for GPIO %d IRQ\n",
- offset);
- return -EINVAL;
- }
-
- /*
- * The local hwirqs on the port are the lower three bits, there
- * are exactly 8 IRQs per port since they are 8-bit
- */
- retirq = irq_find_mapping(port->domain, (offset & 0x7));
-
- dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d from port %d\n",
- offset, retirq, port->number);
- return retirq;
-}
-
/* Returning -EINVAL means "supported but not available" */
int u300_gpio_config_get(struct gpio_chip *chip,
unsigned offset,
@@ -461,7 +423,6 @@ static struct gpio_chip u300_gpio_chip = {
.set = u300_gpio_set,
.direction_input = u300_gpio_direction_input,
.direction_output = u300_gpio_direction_output,
- .to_irq = u300_gpio_to_irq,
};
static void u300_toggle_trigger(struct u300_gpio *gpio, unsigned offset)
@@ -485,9 +446,10 @@ static void u300_toggle_trigger(struct u300_gpio *gpio, unsigned offset)
static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger)
{
- struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
- struct u300_gpio *gpio = port->gpio;
- int offset = (port->number << 3) + d->hwirq;
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+ struct u300_gpio *gpio = to_u300_gpio(chip);
+ struct u300_gpio_port *port = &gpio->ports[d->hwirq >> 3];
+ int offset = d->hwirq;
u32 val;
if ((trigger & IRQF_TRIGGER_RISING) &&
@@ -521,18 +483,15 @@ static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger)
static void u300_gpio_irq_enable(struct irq_data *d)
{
- struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
- struct u300_gpio *gpio = port->gpio;
- int offset = (port->number << 3) + d->hwirq;
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+ struct u300_gpio *gpio = to_u300_gpio(chip);
+ struct u300_gpio_port *port = &gpio->ports[d->hwirq >> 3];
+ int offset = d->hwirq;
u32 val;
unsigned long flags;
dev_dbg(gpio->dev, "enable IRQ for hwirq %lu on port %s, offset %d\n",
d->hwirq, port->name, offset);
- if (gpio_lock_as_irq(&gpio->chip, d->hwirq))
- dev_err(gpio->dev,
- "unable to lock HW IRQ %lu for IRQ\n",
- d->hwirq);
local_irq_save(flags);
val = readl(U300_PIN_REG(offset, ien));
writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien));
@@ -541,9 +500,9 @@ static void u300_gpio_irq_enable(struct irq_data *d)
static void u300_gpio_irq_disable(struct irq_data *d)
{
- struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
- struct u300_gpio *gpio = port->gpio;
- int offset = (port->number << 3) + d->hwirq;
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+ struct u300_gpio *gpio = to_u300_gpio(chip);
+ int offset = d->hwirq;
u32 val;
unsigned long flags;
@@ -551,7 +510,6 @@ static void u300_gpio_irq_disable(struct irq_data *d)
val = readl(U300_PIN_REG(offset, ien));
writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, ien));
local_irq_restore(flags);
- gpio_unlock_as_irq(&gpio->chip, d->hwirq);
}
static struct irq_chip u300_gpio_irqchip = {
@@ -559,17 +517,19 @@ static struct irq_chip u300_gpio_irqchip = {
.irq_enable = u300_gpio_irq_enable,
.irq_disable = u300_gpio_irq_disable,
.irq_set_type = u300_gpio_irq_type,
-
};
static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
{
- struct u300_gpio_port *port = irq_get_handler_data(irq);
- struct u300_gpio *gpio = port->gpio;
+ struct irq_chip *parent_chip = irq_get_chip(irq);
+ struct gpio_chip *chip = irq_get_handler_data(irq);
+ struct u300_gpio *gpio = to_u300_gpio(chip);
+ struct u300_gpio_port *port = &gpio->ports[irq - chip->base];
int pinoffset = port->number << 3; /* get the right stride */
unsigned long val;
- desc->irq_data.chip->irq_ack(&desc->irq_data);
+ chained_irq_enter(parent_chip, desc);
+
/* Read event register */
val = readl(U300_PIN_REG(pinoffset, iev));
/* Mask relevant bits */
@@ -582,8 +542,8 @@ static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
int irqoffset;
for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) {
- int pin_irq = irq_find_mapping(port->domain, irqoffset);
int offset = pinoffset + irqoffset;
+ int pin_irq = irq_find_mapping(chip->irqdomain, offset);
dev_dbg(gpio->dev, "GPIO IRQ %d on pin %d\n",
pin_irq, offset);
@@ -597,7 +557,7 @@ static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
}
}
- desc->irq_data.chip->irq_unmask(&desc->irq_data);
+ chained_irq_exit(parent_chip, desc);
}
static void __init u300_gpio_init_pin(struct u300_gpio *gpio,
@@ -648,20 +608,6 @@ static void __init u300_gpio_init_coh901571(struct u300_gpio *gpio)
}
}
-static inline void u300_gpio_free_ports(struct u300_gpio *gpio)
-{
- struct u300_gpio_port *port;
- struct list_head *p, *n;
-
- list_for_each_safe(p, n, &gpio->port_list) {
- port = list_entry(p, struct u300_gpio_port, node);
- list_del(&port->node);
- if (port->domain)
- irq_domain_remove(port->domain);
- kfree(port);
- }
-}
-
/*
* Here we map a GPIO in the local gpio_chip pin space to a pin in
* the local pinctrl pin space. The pin controller used is
@@ -752,17 +698,28 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
gpio->base + U300_GPIO_CR);
u300_gpio_init_coh901571(gpio);
+#ifdef CONFIG_OF_GPIO
+ gpio->chip.of_node = pdev->dev.of_node;
+#endif
+ err = gpiochip_add(&gpio->chip);
+ if (err) {
+ dev_err(gpio->dev, "unable to add gpiochip: %d\n", err);
+ goto err_no_chip;
+ }
+
+ err = gpiochip_irqchip_add(&gpio->chip,
+ &u300_gpio_irqchip,
+ 0,
+ handle_simple_irq,
+ IRQ_TYPE_EDGE_FALLING);
+ if (err) {
+ dev_err(gpio->dev, "no GPIO irqchip\n");
+ goto err_no_irqchip;
+ }
+
/* Add each port with its IRQ separately */
- INIT_LIST_HEAD(&gpio->port_list);
for (portno = 0 ; portno < U300_GPIO_NUM_PORTS; portno++) {
- struct u300_gpio_port *port =
- kmalloc(sizeof(struct u300_gpio_port), GFP_KERNEL);
-
- if (!port) {
- dev_err(gpio->dev, "out of memory\n");
- err = -ENOMEM;
- goto err_no_port;
- }
+ struct u300_gpio_port *port = &gpio->ports[portno];
snprintf(port->name, 8, "gpio%d", portno);
port->number = portno;
@@ -770,50 +727,16 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
port->irq = platform_get_irq(pdev, portno);
- dev_dbg(gpio->dev, "register IRQ %d for port %s\n", port->irq,
- port->name);
-
- port->domain = irq_domain_add_linear(pdev->dev.of_node,
- U300_GPIO_PINS_PER_PORT,
- &irq_domain_simple_ops,
- port);
- if (!port->domain) {
- err = -ENOMEM;
- goto err_no_domain;
- }
-
- irq_set_chained_handler(port->irq, u300_gpio_irq_handler);
- irq_set_handler_data(port->irq, port);
-
- /* For each GPIO pin set the unique IRQ handler */
- for (i = 0; i < U300_GPIO_PINS_PER_PORT; i++) {
- int irqno = irq_create_mapping(port->domain, i);
-
- dev_dbg(gpio->dev, "GPIO%d on port %s gets IRQ %d\n",
- gpio->chip.base + (port->number << 3) + i,
- port->name, irqno);
- irq_set_chip_and_handler(irqno, &u300_gpio_irqchip,
- handle_simple_irq);
- set_irq_flags(irqno, IRQF_VALID);
- irq_set_chip_data(irqno, port);
- }
+ gpiochip_set_chained_irqchip(&gpio->chip,
+ &u300_gpio_irqchip,
+ port->irq,
+ u300_gpio_irq_handler);
/* Turns off irq force (test register) for this port */
writel(0x0, gpio->base + portno * gpio->stride + ifr);
-
- list_add_tail(&port->node, &gpio->port_list);
}
dev_dbg(gpio->dev, "initialized %d GPIO ports\n", portno);
-#ifdef CONFIG_OF_GPIO
- gpio->chip.of_node = pdev->dev.of_node;
-#endif
- err = gpiochip_add(&gpio->chip);
- if (err) {
- dev_err(gpio->dev, "unable to add gpiochip: %d\n", err);
- goto err_no_chip;
- }
-
/*
* Add pinctrl pin ranges, the pin controller must be registered
* at this point
@@ -832,12 +755,10 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
return 0;
err_no_range:
+err_no_irqchip:
if (gpiochip_remove(&gpio->chip))
dev_err(&pdev->dev, "failed to remove gpio chip\n");
err_no_chip:
-err_no_domain:
-err_no_port:
- u300_gpio_free_ports(gpio);
clk_disable_unprepare(gpio->clk);
dev_err(&pdev->dev, "module ERROR:%d\n", err);
return err;
@@ -856,7 +777,6 @@ static int __exit u300_gpio_remove(struct platform_device *pdev)
dev_err(gpio->dev, "unable to remove gpiochip: %d\n", err);
return err;
}
- u300_gpio_free_ports(gpio);
clk_disable_unprepare(gpio->clk);
return 0;
}
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c
index 155b1b3a0e7a..07c81306f2f3 100644
--- a/drivers/pinctrl/pinctrl-exynos.c
+++ b/drivers/pinctrl/pinctrl-exynos.c
@@ -1042,6 +1042,88 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
},
};
+/* pin banks of exynos5260 pin-controller 0 */
+static struct samsung_pin_bank exynos5260_pin_banks0[] = {
+ EXYNOS_PIN_BANK_EINTG(4, 0x000, "gpa0", 0x00),
+ EXYNOS_PIN_BANK_EINTG(7, 0x020, "gpa1", 0x04),
+ EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08),
+ EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpb0", 0x0c),
+ EXYNOS_PIN_BANK_EINTG(4, 0x080, "gpb1", 0x10),
+ EXYNOS_PIN_BANK_EINTG(5, 0x0a0, "gpb2", 0x14),
+ EXYNOS_PIN_BANK_EINTG(8, 0x0c0, "gpb3", 0x18),
+ EXYNOS_PIN_BANK_EINTG(8, 0x0e0, "gpb4", 0x1c),
+ EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpb5", 0x20),
+ EXYNOS_PIN_BANK_EINTG(8, 0x120, "gpd0", 0x24),
+ EXYNOS_PIN_BANK_EINTG(7, 0x140, "gpd1", 0x28),
+ EXYNOS_PIN_BANK_EINTG(5, 0x160, "gpd2", 0x2c),
+ EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpe0", 0x30),
+ EXYNOS_PIN_BANK_EINTG(5, 0x1a0, "gpe1", 0x34),
+ EXYNOS_PIN_BANK_EINTG(4, 0x1c0, "gpf0", 0x38),
+ EXYNOS_PIN_BANK_EINTG(8, 0x1e0, "gpf1", 0x3c),
+ EXYNOS_PIN_BANK_EINTG(2, 0x200, "gpk0", 0x40),
+ EXYNOS_PIN_BANK_EINTW(8, 0xc00, "gpx0", 0x00),
+ EXYNOS_PIN_BANK_EINTW(8, 0xc20, "gpx1", 0x04),
+ EXYNOS_PIN_BANK_EINTW(8, 0xc40, "gpx2", 0x08),
+ EXYNOS_PIN_BANK_EINTW(8, 0xc60, "gpx3", 0x0c),
+};
+
+/* pin banks of exynos5260 pin-controller 1 */
+static struct samsung_pin_bank exynos5260_pin_banks1[] = {
+ EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpc0", 0x00),
+ EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpc1", 0x04),
+ EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpc2", 0x08),
+ EXYNOS_PIN_BANK_EINTG(4, 0x060, "gpc3", 0x0c),
+ EXYNOS_PIN_BANK_EINTG(4, 0x080, "gpc4", 0x10),
+};
+
+/* pin banks of exynos5260 pin-controller 2 */
+static struct samsung_pin_bank exynos5260_pin_banks2[] = {
+ EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz0", 0x00),
+ EXYNOS_PIN_BANK_EINTG(4, 0x020, "gpz1", 0x04),
+};
+
+/*
+ * Samsung pinctrl driver data for Exynos5260 SoC. Exynos5260 SoC includes
+ * three gpio/pin-mux/pinconfig controllers.
+ */
+struct samsung_pin_ctrl exynos5260_pin_ctrl[] = {
+ {
+ /* pin-controller instance 0 data */
+ .pin_banks = exynos5260_pin_banks0,
+ .nr_banks = ARRAY_SIZE(exynos5260_pin_banks0),
+ .geint_con = EXYNOS_GPIO_ECON_OFFSET,
+ .geint_mask = EXYNOS_GPIO_EMASK_OFFSET,
+ .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
+ .weint_con = EXYNOS_WKUP_ECON_OFFSET,
+ .weint_mask = EXYNOS_WKUP_EMASK_OFFSET,
+ .weint_pend = EXYNOS_WKUP_EPEND_OFFSET,
+ .svc = EXYNOS_SVC_OFFSET,
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .eint_wkup_init = exynos_eint_wkup_init,
+ .label = "exynos5260-gpio-ctrl0",
+ }, {
+ /* pin-controller instance 1 data */
+ .pin_banks = exynos5260_pin_banks1,
+ .nr_banks = ARRAY_SIZE(exynos5260_pin_banks1),
+ .geint_con = EXYNOS_GPIO_ECON_OFFSET,
+ .geint_mask = EXYNOS_GPIO_EMASK_OFFSET,
+ .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
+ .svc = EXYNOS_SVC_OFFSET,
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .label = "exynos5260-gpio-ctrl1",
+ }, {
+ /* pin-controller instance 2 data */
+ .pin_banks = exynos5260_pin_banks2,
+ .nr_banks = ARRAY_SIZE(exynos5260_pin_banks2),
+ .geint_con = EXYNOS_GPIO_ECON_OFFSET,
+ .geint_mask = EXYNOS_GPIO_EMASK_OFFSET,
+ .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
+ .svc = EXYNOS_SVC_OFFSET,
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .label = "exynos5260-gpio-ctrl2",
+ },
+};
+
/* pin banks of exynos5420 pin-controller 0 */
static struct samsung_pin_bank exynos5420_pin_banks0[] = {
EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpy7", 0x00),
diff --git a/drivers/pinctrl/pinctrl-imx.c b/drivers/pinctrl/pinctrl-imx.c
index 4779b8e0eee8..e118fb121e02 100644
--- a/drivers/pinctrl/pinctrl-imx.c
+++ b/drivers/pinctrl/pinctrl-imx.c
@@ -491,7 +491,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
pin->mux_mode |= IOMUXC_CONFIG_SION;
pin->config = config & ~IMX_PAD_SION;
- dev_dbg(info->dev, "%s: %d 0x%08lx", info->pins[i].name,
+ dev_dbg(info->dev, "%s: %d 0x%08lx", info->pins[pin_id].name,
pin->mux_mode, pin->config);
}
diff --git a/drivers/pinctrl/pinctrl-msm.c b/drivers/pinctrl/pinctrl-msm.c
index ef2bf3126da6..38d579b47f31 100644
--- a/drivers/pinctrl/pinctrl-msm.c
+++ b/drivers/pinctrl/pinctrl-msm.c
@@ -28,7 +28,6 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqchip/chained_irq.h>
-#include <linux/of_irq.h>
#include <linux/spinlock.h>
#include "core.h"
@@ -50,7 +49,6 @@
* @enabled_irqs: Bitmap of currently enabled irqs.
* @dual_edge_irqs: Bitmap of irqs that need sw emulated dual edge
* detection.
- * @wake_irqs: Bitmap of irqs with requested as wakeup source.
* @soc; Reference to soc_data of platform specific data.
* @regs: Base address for the TLMM register map.
*/
@@ -65,7 +63,6 @@ struct msm_pinctrl {
DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO);
DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO);
- DECLARE_BITMAP(wake_irqs, MAX_NR_GPIO);
const struct msm_pinctrl_soc_data *soc;
void __iomem *regs;
@@ -203,42 +200,29 @@ static const struct pinmux_ops msm_pinmux_ops = {
static int msm_config_reg(struct msm_pinctrl *pctrl,
const struct msm_pingroup *g,
unsigned param,
- s16 *reg,
unsigned *mask,
unsigned *bit)
{
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
- *reg = g->ctl_reg;
- *bit = g->pull_bit;
- *mask = 3;
- break;
case PIN_CONFIG_BIAS_PULL_DOWN:
- *reg = g->ctl_reg;
- *bit = g->pull_bit;
- *mask = 3;
- break;
case PIN_CONFIG_BIAS_PULL_UP:
- *reg = g->ctl_reg;
*bit = g->pull_bit;
*mask = 3;
break;
case PIN_CONFIG_DRIVE_STRENGTH:
- *reg = g->ctl_reg;
*bit = g->drv_bit;
*mask = 7;
break;
+ case PIN_CONFIG_OUTPUT:
+ *bit = g->oe_bit;
+ *mask = 1;
+ break;
default:
dev_err(pctrl->dev, "Invalid config param %04x\n", param);
return -ENOTSUPP;
}
- if (*reg < 0) {
- dev_err(pctrl->dev, "Config param %04x not supported on group %s\n",
- param, g->name);
- return -ENOTSUPP;
- }
-
return 0;
}
@@ -261,8 +245,10 @@ static int msm_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
#define MSM_PULL_DOWN 1
#define MSM_PULL_UP 3
-static const unsigned msm_regval_to_drive[] = { 2, 4, 6, 8, 10, 12, 14, 16 };
-static const unsigned msm_drive_to_regval[] = { -1, -1, 0, -1, 1, -1, 2, -1, 3, -1, 4, -1, 5, -1, 6, -1, 7 };
+static unsigned msm_regval_to_drive(u32 val)
+{
+ return (val + 1) * 2;
+}
static int msm_config_group_get(struct pinctrl_dev *pctldev,
unsigned int group,
@@ -274,17 +260,16 @@ static int msm_config_group_get(struct pinctrl_dev *pctldev,
unsigned mask;
unsigned arg;
unsigned bit;
- s16 reg;
int ret;
u32 val;
g = &pctrl->soc->groups[group];
- ret = msm_config_reg(pctrl, g, param, &reg, &mask, &bit);
+ ret = msm_config_reg(pctrl, g, param, &mask, &bit);
if (ret < 0)
return ret;
- val = readl(pctrl->regs + reg);
+ val = readl(pctrl->regs + g->ctl_reg);
arg = (val >> bit) & mask;
/* Convert register value to pinconf value */
@@ -299,7 +284,15 @@ static int msm_config_group_get(struct pinctrl_dev *pctldev,
arg = arg == MSM_PULL_UP;
break;
case PIN_CONFIG_DRIVE_STRENGTH:
- arg = msm_regval_to_drive[arg];
+ arg = msm_regval_to_drive(arg);
+ break;
+ case PIN_CONFIG_OUTPUT:
+ /* Pin is not output */
+ if (!arg)
+ return -EINVAL;
+
+ val = readl(pctrl->regs + g->io_reg);
+ arg = !!(val & BIT(g->in_bit));
break;
default:
dev_err(pctrl->dev, "Unsupported config parameter: %x\n",
@@ -324,7 +317,6 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
unsigned mask;
unsigned arg;
unsigned bit;
- s16 reg;
int ret;
u32 val;
int i;
@@ -335,7 +327,7 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
- ret = msm_config_reg(pctrl, g, param, &reg, &mask, &bit);
+ ret = msm_config_reg(pctrl, g, param, &mask, &bit);
if (ret < 0)
return ret;
@@ -352,10 +344,24 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
break;
case PIN_CONFIG_DRIVE_STRENGTH:
/* Check for invalid values */
- if (arg >= ARRAY_SIZE(msm_drive_to_regval))
+ if (arg > 16 || arg < 2 || (arg % 2) != 0)
arg = -1;
else
- arg = msm_drive_to_regval[arg];
+ arg = (arg / 2) - 1;
+ break;
+ case PIN_CONFIG_OUTPUT:
+ /* set output value */
+ spin_lock_irqsave(&pctrl->lock, flags);
+ val = readl(pctrl->regs + g->io_reg);
+ if (arg)
+ val |= BIT(g->out_bit);
+ else
+ val &= ~BIT(g->out_bit);
+ writel(val, pctrl->regs + g->io_reg);
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ /* enable output */
+ arg = 1;
break;
default:
dev_err(pctrl->dev, "Unsupported config parameter: %x\n",
@@ -370,10 +376,10 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
}
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + reg);
+ val = readl(pctrl->regs + g->ctl_reg);
val &= ~(mask << bit);
val |= arg << bit;
- writel(val, pctrl->regs + reg);
+ writel(val, pctrl->regs + g->ctl_reg);
spin_unlock_irqrestore(&pctrl->lock, flags);
}
@@ -402,8 +408,6 @@ static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
u32 val;
g = &pctrl->soc->groups[offset];
- if (WARN_ON(g->io_reg < 0))
- return -EINVAL;
spin_lock_irqsave(&pctrl->lock, flags);
@@ -424,8 +428,6 @@ static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, in
u32 val;
g = &pctrl->soc->groups[offset];
- if (WARN_ON(g->io_reg < 0))
- return -EINVAL;
spin_lock_irqsave(&pctrl->lock, flags);
@@ -452,8 +454,6 @@ static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
u32 val;
g = &pctrl->soc->groups[offset];
- if (WARN_ON(g->io_reg < 0))
- return -EINVAL;
val = readl(pctrl->regs + g->io_reg);
return !!(val & BIT(g->in_bit));
@@ -467,8 +467,6 @@ static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
u32 val;
g = &pctrl->soc->groups[offset];
- if (WARN_ON(g->io_reg < 0))
- return;
spin_lock_irqsave(&pctrl->lock, flags);
@@ -534,7 +532,7 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
pull = (ctl_reg >> g->pull_bit) & 3;
seq_printf(s, " %-8s: %-3s %d", g->name, is_out ? "out" : "in", func);
- seq_printf(s, " %dmA", msm_regval_to_drive[drive]);
+ seq_printf(s, " %dmA", msm_regval_to_drive(drive));
seq_printf(s, " %s", pulls[pull]);
}
@@ -617,8 +615,6 @@ static void msm_gpio_irq_mask(struct irq_data *d)
pctrl = irq_data_get_irq_chip_data(d);
g = &pctrl->soc->groups[d->hwirq];
- if (WARN_ON(g->intr_cfg_reg < 0))
- return;
spin_lock_irqsave(&pctrl->lock, flags);
@@ -640,8 +636,6 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
pctrl = irq_data_get_irq_chip_data(d);
g = &pctrl->soc->groups[d->hwirq];
- if (WARN_ON(g->intr_status_reg < 0))
- return;
spin_lock_irqsave(&pctrl->lock, flags);
@@ -667,8 +661,6 @@ static void msm_gpio_irq_ack(struct irq_data *d)
pctrl = irq_data_get_irq_chip_data(d);
g = &pctrl->soc->groups[d->hwirq];
- if (WARN_ON(g->intr_status_reg < 0))
- return;
spin_lock_irqsave(&pctrl->lock, flags);
@@ -693,8 +685,6 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
pctrl = irq_data_get_irq_chip_data(d);
g = &pctrl->soc->groups[d->hwirq];
- if (WARN_ON(g->intr_cfg_reg < 0))
- return -EINVAL;
spin_lock_irqsave(&pctrl->lock, flags);
@@ -783,45 +773,34 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
{
struct msm_pinctrl *pctrl;
unsigned long flags;
- unsigned ngpio;
pctrl = irq_data_get_irq_chip_data(d);
- ngpio = pctrl->chip.ngpio;
spin_lock_irqsave(&pctrl->lock, flags);
- if (on) {
- if (bitmap_empty(pctrl->wake_irqs, ngpio))
- enable_irq_wake(pctrl->irq);
- set_bit(d->hwirq, pctrl->wake_irqs);
- } else {
- clear_bit(d->hwirq, pctrl->wake_irqs);
- if (bitmap_empty(pctrl->wake_irqs, ngpio))
- disable_irq_wake(pctrl->irq);
- }
+ irq_set_irq_wake(pctrl->irq, on);
spin_unlock_irqrestore(&pctrl->lock, flags);
return 0;
}
-static unsigned int msm_gpio_irq_startup(struct irq_data *d)
+static int msm_gpio_irq_reqres(struct irq_data *d)
{
struct msm_pinctrl *pctrl = irq_data_get_irq_chip_data(d);
if (gpio_lock_as_irq(&pctrl->chip, d->hwirq)) {
dev_err(pctrl->dev, "unable to lock HW IRQ %lu for IRQ\n",
d->hwirq);
+ return -EINVAL;
}
- msm_gpio_irq_unmask(d);
return 0;
}
-static void msm_gpio_irq_shutdown(struct irq_data *d)
+static void msm_gpio_irq_relres(struct irq_data *d)
{
struct msm_pinctrl *pctrl = irq_data_get_irq_chip_data(d);
- msm_gpio_irq_mask(d);
gpio_unlock_as_irq(&pctrl->chip, d->hwirq);
}
@@ -832,8 +811,8 @@ static struct irq_chip msm_gpio_irq_chip = {
.irq_ack = msm_gpio_irq_ack,
.irq_set_type = msm_gpio_irq_set_type,
.irq_set_wake = msm_gpio_irq_set_wake,
- .irq_startup = msm_gpio_irq_startup,
- .irq_shutdown = msm_gpio_irq_shutdown,
+ .irq_request_resources = msm_gpio_irq_reqres,
+ .irq_release_resources = msm_gpio_irq_relres,
};
static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
@@ -869,6 +848,12 @@ static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
+/*
+ * This lock class tells lockdep that GPIO irqs are in a different
+ * category than their parents, so it won't report false recursion.
+ */
+static struct lock_class_key gpio_lock_class;
+
static int msm_gpio_init(struct msm_pinctrl *pctrl)
{
struct gpio_chip *chip;
@@ -876,10 +861,14 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
int ret;
int i;
int r;
+ unsigned ngpio = pctrl->soc->ngpios;
+
+ if (WARN_ON(ngpio > MAX_NR_GPIO))
+ return -EINVAL;
chip = &pctrl->chip;
chip->base = 0;
- chip->ngpio = pctrl->soc->ngpios;
+ chip->ngpio = ngpio;
chip->label = dev_name(pctrl->dev);
chip->dev = pctrl->dev;
chip->owner = THIS_MODULE;
@@ -907,6 +896,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
for (i = 0; i < chip->ngpio; i++) {
irq = irq_create_mapping(pctrl->domain, i);
+ irq_set_lockdep_class(irq, &gpio_lock_class);
irq_set_chip_and_handler(irq, &msm_gpio_irq_chip, handle_edge_irq);
irq_set_chip_data(irq, pctrl);
}
diff --git a/drivers/pinctrl/pinctrl-msm.h b/drivers/pinctrl/pinctrl-msm.h
index 206e782e2daa..8fbe9fb19f36 100644
--- a/drivers/pinctrl/pinctrl-msm.h
+++ b/drivers/pinctrl/pinctrl-msm.h
@@ -13,10 +13,7 @@
#ifndef __PINCTRL_MSM_H__
#define __PINCTRL_MSM_H__
-#include <linux/pinctrl/pinctrl.h>
-#include <linux/pinctrl/pinmux.h>
-#include <linux/pinctrl/pinconf.h>
-#include <linux/pinctrl/machine.h>
+struct pinctrl_pin_desc;
/**
* struct msm_function - a pinmux function
diff --git a/drivers/pinctrl/pinctrl-msm8x74.c b/drivers/pinctrl/pinctrl-msm8x74.c
index f944bf2172ef..dde5529807aa 100644
--- a/drivers/pinctrl/pinctrl-msm8x74.c
+++ b/drivers/pinctrl/pinctrl-msm8x74.c
@@ -15,7 +15,6 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/pinctrl.h>
-#include <linux/pinctrl/pinmux.h>
#include "pinctrl-msm.h"
@@ -406,6 +405,7 @@ enum msm8x74_functions {
MSM_MUX_blsp_i2c6,
MSM_MUX_blsp_i2c11,
MSM_MUX_blsp_spi1,
+ MSM_MUX_blsp_spi8,
MSM_MUX_blsp_uart2,
MSM_MUX_blsp_uart8,
MSM_MUX_slimbus,
@@ -416,6 +416,9 @@ static const char * const blsp_i2c2_groups[] = { "gpio6", "gpio7" };
static const char * const blsp_i2c6_groups[] = { "gpio29", "gpio30" };
static const char * const blsp_i2c11_groups[] = { "gpio83", "gpio84" };
static const char * const blsp_spi1_groups[] = { "gpio0", "gpio1", "gpio2", "gpio3" };
+static const char * const blsp_spi8_groups[] = {
+ "gpio45", "gpio46", "gpio47", "gpio48"
+};
static const char * const blsp_uart2_groups[] = { "gpio4", "gpio5" };
static const char * const blsp_uart8_groups[] = { "gpio45", "gpio46" };
static const char * const slimbus_groups[] = { "gpio70", "gpio71" };
@@ -425,6 +428,7 @@ static const struct msm_function msm8x74_functions[] = {
FUNCTION(blsp_i2c6),
FUNCTION(blsp_i2c11),
FUNCTION(blsp_spi1),
+ FUNCTION(blsp_spi8),
FUNCTION(blsp_uart2),
FUNCTION(blsp_uart8),
FUNCTION(slimbus),
@@ -476,10 +480,10 @@ static const struct msm_pingroup msm8x74_groups[] = {
PINGROUP(42, NA, NA, NA, NA, NA, NA, NA),
PINGROUP(43, NA, NA, NA, NA, NA, NA, NA),
PINGROUP(44, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(45, NA, blsp_uart8, NA, NA, NA, NA, NA),
- PINGROUP(46, NA, blsp_uart8, NA, NA, NA, NA, NA),
- PINGROUP(47, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(48, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(45, blsp_spi8, blsp_uart8, NA, NA, NA, NA, NA),
+ PINGROUP(46, blsp_spi8, blsp_uart8, NA, NA, NA, NA, NA),
+ PINGROUP(47, blsp_spi8, NA, NA, NA, NA, NA, NA),
+ PINGROUP(48, blsp_spi8, NA, NA, NA, NA, NA, NA),
PINGROUP(49, NA, NA, NA, NA, NA, NA, NA),
PINGROUP(50, NA, NA, NA, NA, NA, NA, NA),
PINGROUP(51, NA, NA, NA, NA, NA, NA, NA),
diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c
index 53a11114927f..208341fd57d2 100644
--- a/drivers/pinctrl/pinctrl-nomadik.c
+++ b/drivers/pinctrl/pinctrl-nomadik.c
@@ -21,9 +21,6 @@
#include <linux/gpio.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/irqdomain.h>
-#include <linux/irqchip/chained_irq.h>
#include <linux/slab.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
@@ -246,28 +243,14 @@ enum nmk_gpio_slpm {
NMK_GPIO_SLPM_WAKEUP_DISABLE = NMK_GPIO_SLPM_NOCHANGE,
};
-/*
- * Platform data to register a block: only the initial gpio/irq number.
- */
-struct nmk_gpio_platform_data {
- char *name;
- int first_gpio;
- int first_irq;
- int num_gpio;
- u32 (*get_secondary_status)(unsigned int bank);
- void (*set_ioforce)(bool enable);
- bool supports_sleepmode;
-};
-
struct nmk_gpio_chip {
struct gpio_chip chip;
- struct irq_domain *domain;
void __iomem *addr;
struct clk *clk;
unsigned int bank;
unsigned int parent_irq;
- int secondary_parent_irq;
- u32 (*get_secondary_status)(unsigned int bank);
+ int latent_parent_irq;
+ u32 (*get_latent_status)(unsigned int bank);
void (*set_ioforce)(bool enable);
spinlock_t lock;
bool sleepmode;
@@ -432,7 +415,7 @@ nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset)
u32 falling = nmk_chip->fimsc & BIT(offset);
u32 rising = nmk_chip->rimsc & BIT(offset);
int gpio = nmk_chip->chip.base + offset;
- int irq = irq_find_mapping(nmk_chip->domain, offset);
+ int irq = irq_find_mapping(nmk_chip->chip.irqdomain, offset);
struct irq_data *d = irq_get_irq_data(irq);
if (!rising && !falling)
@@ -660,11 +643,8 @@ static inline int nmk_gpio_get_bitmask(int gpio)
static void nmk_gpio_irq_ack(struct irq_data *d)
{
- struct nmk_gpio_chip *nmk_chip;
-
- nmk_chip = irq_data_get_irq_chip_data(d);
- if (!nmk_chip)
- return;
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+ struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
clk_enable(nmk_chip->clk);
writel(nmk_gpio_get_bitmask(d->hwirq), nmk_chip->addr + NMK_GPIO_IC);
@@ -848,10 +828,6 @@ static unsigned int nmk_gpio_irq_startup(struct irq_data *d)
{
struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d);
- if (gpio_lock_as_irq(&nmk_chip->chip, d->hwirq))
- dev_err(nmk_chip->chip.dev,
- "unable to lock HW IRQ %lu for IRQ\n",
- d->hwirq);
clk_enable(nmk_chip->clk);
nmk_gpio_irq_unmask(d);
return 0;
@@ -863,7 +839,6 @@ static void nmk_gpio_irq_shutdown(struct irq_data *d)
nmk_gpio_irq_mask(d);
clk_disable(nmk_chip->clk);
- gpio_unlock_as_irq(&nmk_chip->chip, d->hwirq);
}
static struct irq_chip nmk_gpio_irq_chip = {
@@ -881,16 +856,15 @@ static struct irq_chip nmk_gpio_irq_chip = {
static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
u32 status)
{
- struct nmk_gpio_chip *nmk_chip;
struct irq_chip *host_chip = irq_get_chip(irq);
+ struct gpio_chip *chip = irq_desc_get_handler_data(desc);
chained_irq_enter(host_chip, desc);
- nmk_chip = irq_get_handler_data(irq);
while (status) {
int bit = __ffs(status);
- generic_handle_irq(irq_find_mapping(nmk_chip->domain, bit));
+ generic_handle_irq(irq_find_mapping(chip->irqdomain, bit));
status &= ~BIT(bit);
}
@@ -899,9 +873,11 @@ static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
{
- struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq);
+ struct gpio_chip *chip = irq_desc_get_handler_data(desc);
+ struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
u32 status;
+ pr_err("PLONK IRQ %d\n", irq);
clk_enable(nmk_chip->clk);
status = readl(nmk_chip->addr + NMK_GPIO_IS);
clk_disable(nmk_chip->clk);
@@ -909,29 +885,16 @@ static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
__nmk_gpio_irq_handler(irq, desc, status);
}
-static void nmk_gpio_secondary_irq_handler(unsigned int irq,
+static void nmk_gpio_latent_irq_handler(unsigned int irq,
struct irq_desc *desc)
{
- struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq);
- u32 status = nmk_chip->get_secondary_status(nmk_chip->bank);
+ struct gpio_chip *chip = irq_desc_get_handler_data(desc);
+ struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
+ u32 status = nmk_chip->get_latent_status(nmk_chip->bank);
__nmk_gpio_irq_handler(irq, desc, status);
}
-static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip)
-{
- irq_set_chained_handler(nmk_chip->parent_irq, nmk_gpio_irq_handler);
- irq_set_handler_data(nmk_chip->parent_irq, nmk_chip);
-
- if (nmk_chip->secondary_parent_irq >= 0) {
- irq_set_chained_handler(nmk_chip->secondary_parent_irq,
- nmk_gpio_secondary_irq_handler);
- irq_set_handler_data(nmk_chip->secondary_parent_irq, nmk_chip);
- }
-
- return 0;
-}
-
/* I/O Functions */
static int nmk_gpio_request(struct gpio_chip *chip, unsigned offset)
@@ -1010,14 +973,6 @@ static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
return 0;
}
-static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- struct nmk_gpio_chip *nmk_chip =
- container_of(chip, struct nmk_gpio_chip, chip);
-
- return irq_create_mapping(nmk_chip->domain, offset);
-}
-
#ifdef CONFIG_DEBUG_FS
#include <linux/seq_file.h>
@@ -1116,7 +1071,6 @@ static struct gpio_chip nmk_gpio_template = {
.get = nmk_gpio_get_input,
.direction_output = nmk_gpio_make_output,
.set = nmk_gpio_set_output,
- .to_irq = nmk_gpio_to_irq,
.dbg_show = nmk_gpio_dbg_show,
.can_sleep = false,
};
@@ -1217,62 +1171,35 @@ void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up)
}
}
-static int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq,
- irq_hw_number_t hwirq)
-{
- struct nmk_gpio_chip *nmk_chip = d->host_data;
-
- if (!nmk_chip)
- return -EINVAL;
-
- irq_set_chip_and_handler(irq, &nmk_gpio_irq_chip, handle_edge_irq);
- set_irq_flags(irq, IRQF_VALID);
- irq_set_chip_data(irq, nmk_chip);
- irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
-
- return 0;
-}
-
-static const struct irq_domain_ops nmk_gpio_irq_simple_ops = {
- .map = nmk_gpio_irq_map,
- .xlate = irq_domain_xlate_twocell,
-};
-
static int nmk_gpio_probe(struct platform_device *dev)
{
- struct nmk_gpio_platform_data *pdata;
struct device_node *np = dev->dev.of_node;
struct nmk_gpio_chip *nmk_chip;
struct gpio_chip *chip;
struct resource *res;
struct clk *clk;
- int secondary_irq;
+ int latent_irq;
+ bool supports_sleepmode;
void __iomem *base;
int irq;
int ret;
- pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- return -ENOMEM;
-
if (of_get_property(np, "st,supports-sleepmode", NULL))
- pdata->supports_sleepmode = true;
+ supports_sleepmode = true;
+ else
+ supports_sleepmode = false;
if (of_property_read_u32(np, "gpio-bank", &dev->id)) {
dev_err(&dev->dev, "gpio-bank property not found\n");
return -EINVAL;
}
- pdata->first_gpio = dev->id * NMK_GPIO_PER_CHIP;
- pdata->num_gpio = NMK_GPIO_PER_CHIP;
-
irq = platform_get_irq(dev, 0);
if (irq < 0)
return irq;
- secondary_irq = platform_get_irq(dev, 1);
- if (secondary_irq >= 0 && !pdata->get_secondary_status)
- return -EINVAL;
+ /* It's OK for this IRQ not to be present */
+ latent_irq = platform_get_irq(dev, 1);
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&dev->dev, res);
@@ -1297,16 +1224,14 @@ static int nmk_gpio_probe(struct platform_device *dev)
nmk_chip->addr = base;
nmk_chip->chip = nmk_gpio_template;
nmk_chip->parent_irq = irq;
- nmk_chip->secondary_parent_irq = secondary_irq;
- nmk_chip->get_secondary_status = pdata->get_secondary_status;
- nmk_chip->set_ioforce = pdata->set_ioforce;
- nmk_chip->sleepmode = pdata->supports_sleepmode;
+ nmk_chip->latent_parent_irq = latent_irq;
+ nmk_chip->sleepmode = supports_sleepmode;
spin_lock_init(&nmk_chip->lock);
chip = &nmk_chip->chip;
- chip->base = pdata->first_gpio;
- chip->ngpio = pdata->num_gpio;
- chip->label = pdata->name ?: dev_name(&dev->dev);
+ chip->base = dev->id * NMK_GPIO_PER_CHIP;
+ chip->ngpio = NMK_GPIO_PER_CHIP;
+ chip->label = dev_name(&dev->dev);
chip->dev = &dev->dev;
chip->owner = THIS_MODULE;
@@ -1325,17 +1250,31 @@ static int nmk_gpio_probe(struct platform_device *dev)
platform_set_drvdata(dev, nmk_chip);
- nmk_chip->domain = irq_domain_add_simple(np,
- NMK_GPIO_PER_CHIP, 0,
- &nmk_gpio_irq_simple_ops, nmk_chip);
- if (!nmk_chip->domain) {
- dev_err(&dev->dev, "failed to create irqdomain\n");
- /* Just do this, no matter if it fails */
+ /*
+ * Let the generic code handle this edge IRQ, the the chained
+ * handler will perform the actual work of handling the parent
+ * interrupt.
+ */
+ ret = gpiochip_irqchip_add(&nmk_chip->chip,
+ &nmk_gpio_irq_chip,
+ 0,
+ handle_edge_irq,
+ IRQ_TYPE_EDGE_FALLING);
+ if (ret) {
+ dev_err(&dev->dev, "could not add irqchip\n");
ret = gpiochip_remove(&nmk_chip->chip);
- return -ENOSYS;
+ return -ENODEV;
}
-
- nmk_gpio_init_irq(nmk_chip);
+ /* Then register the chain on the parent IRQ */
+ gpiochip_set_chained_irqchip(&nmk_chip->chip,
+ &nmk_gpio_irq_chip,
+ nmk_chip->parent_irq,
+ nmk_gpio_irq_handler);
+ if (nmk_chip->latent_parent_irq > 0)
+ gpiochip_set_chained_irqchip(&nmk_chip->chip,
+ &nmk_gpio_irq_chip,
+ nmk_chip->latent_parent_irq,
+ nmk_gpio_latent_irq_handler);
dev_info(&dev->dev, "at address %p\n", nmk_chip->addr);
@@ -2035,27 +1974,29 @@ static const struct of_device_id nmk_pinctrl_match[] = {
{},
};
-static int nmk_pinctrl_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int nmk_pinctrl_suspend(struct device *dev)
{
struct nmk_pinctrl *npct;
- npct = platform_get_drvdata(pdev);
+ npct = dev_get_drvdata(dev);
if (!npct)
return -EINVAL;
return pinctrl_force_sleep(npct->pctl);
}
-static int nmk_pinctrl_resume(struct platform_device *pdev)
+static int nmk_pinctrl_resume(struct device *dev)
{
struct nmk_pinctrl *npct;
- npct = platform_get_drvdata(pdev);
+ npct = dev_get_drvdata(dev);
if (!npct)
return -EINVAL;
return pinctrl_force_default(npct->pctl);
}
+#endif
static int nmk_pinctrl_probe(struct platform_device *pdev)
{
@@ -2144,17 +2085,18 @@ static struct platform_driver nmk_gpio_driver = {
.probe = nmk_gpio_probe,
};
+static SIMPLE_DEV_PM_OPS(nmk_pinctrl_pm_ops,
+ nmk_pinctrl_suspend,
+ nmk_pinctrl_resume);
+
static struct platform_driver nmk_pinctrl_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "pinctrl-nomadik",
.of_match_table = nmk_pinctrl_match,
+ .pm = &nmk_pinctrl_pm_ops,
},
.probe = nmk_pinctrl_probe,
-#ifdef CONFIG_PM
- .suspend = nmk_pinctrl_suspend,
- .resume = nmk_pinctrl_resume,
-#endif
};
static int __init nmk_gpio_init(void)
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
index 47ec2e8741e4..0324d4cb19b2 100644
--- a/drivers/pinctrl/pinctrl-samsung.c
+++ b/drivers/pinctrl/pinctrl-samsung.c
@@ -1120,6 +1120,8 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = {
.data = (void *)exynos4x12_pin_ctrl },
{ .compatible = "samsung,exynos5250-pinctrl",
.data = (void *)exynos5250_pin_ctrl },
+ { .compatible = "samsung,exynos5260-pinctrl",
+ .data = (void *)exynos5260_pin_ctrl },
{ .compatible = "samsung,exynos5420-pinctrl",
.data = (void *)exynos5420_pin_ctrl },
{ .compatible = "samsung,s5pv210-pinctrl",
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h
index 30622d9afa2e..bab9c2122556 100644
--- a/drivers/pinctrl/pinctrl-samsung.h
+++ b/drivers/pinctrl/pinctrl-samsung.h
@@ -254,6 +254,7 @@ struct samsung_pmx_func {
extern struct samsung_pin_ctrl exynos4210_pin_ctrl[];
extern struct samsung_pin_ctrl exynos4x12_pin_ctrl[];
extern struct samsung_pin_ctrl exynos5250_pin_ctrl[];
+extern struct samsung_pin_ctrl exynos5260_pin_ctrl[];
extern struct samsung_pin_ctrl exynos5420_pin_ctrl[];
extern struct samsung_pin_ctrl s3c64xx_pin_ctrl[];
extern struct samsung_pin_ctrl s3c2412_pin_ctrl[];
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index de6459628b4f..81075f2a1d3f 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -662,6 +662,7 @@ static int pcs_pinconf_get(struct pinctrl_dev *pctldev,
break;
case PIN_CONFIG_DRIVE_STRENGTH:
case PIN_CONFIG_SLEW_RATE:
+ case PIN_CONFIG_LOW_POWER_MODE:
default:
*config = data;
break;
@@ -699,6 +700,7 @@ static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
case PIN_CONFIG_INPUT_SCHMITT:
case PIN_CONFIG_DRIVE_STRENGTH:
case PIN_CONFIG_SLEW_RATE:
+ case PIN_CONFIG_LOW_POWER_MODE:
shift = ffs(func->conf[i].mask) - 1;
data &= ~func->conf[i].mask;
data |= (arg << shift) & func->conf[i].mask;
@@ -1101,6 +1103,7 @@ static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np,
{ "pinctrl-single,drive-strength", PIN_CONFIG_DRIVE_STRENGTH, },
{ "pinctrl-single,slew-rate", PIN_CONFIG_SLEW_RATE, },
{ "pinctrl-single,input-schmitt", PIN_CONFIG_INPUT_SCHMITT, },
+ { "pinctrl-single,low-power-mode", PIN_CONFIG_LOW_POWER_MODE, },
};
struct pcs_conf_type prop4[] = {
{ "pinctrl-single,bias-pullup", PIN_CONFIG_BIAS_PULL_UP, },
diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c
index 320c27363cc8..bd725b0a4341 100644
--- a/drivers/pinctrl/pinctrl-st.c
+++ b/drivers/pinctrl/pinctrl-st.c
@@ -13,7 +13,12 @@
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/of.h>
+#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/of_address.h>
#include <linux/regmap.h>
@@ -266,11 +271,59 @@ struct st_pctl_group {
struct st_pinconf *pin_conf;
};
+/*
+ * Edge triggers are not supported at hardware level, it is supported by
+ * software by exploiting the level trigger support in hardware.
+ * Software uses a virtual register (EDGE_CONF) for edge trigger configuration
+ * of each gpio pin in a GPIO bank.
+ *
+ * Each bank has a 32 bit EDGE_CONF register which is divided in to 8 parts of
+ * 4-bits. Each 4-bit space is allocated for each pin in a gpio bank.
+ *
+ * bit allocation per pin is:
+ * Bits: [0 - 3] | [4 - 7] [8 - 11] ... ... ... ... [ 28 - 31]
+ * --------------------------------------------------------
+ * | pin-0 | pin-2 | pin-3 | ... ... ... ... | pin -7 |
+ * --------------------------------------------------------
+ *
+ * A pin can have one of following the values in its edge configuration field.
+ *
+ * ------- ----------------------------
+ * [0-3] - Description
+ * ------- ----------------------------
+ * 0000 - No edge IRQ.
+ * 0001 - Falling edge IRQ.
+ * 0010 - Rising edge IRQ.
+ * 0011 - Rising and Falling edge IRQ.
+ * ------- ----------------------------
+ */
+
+#define ST_IRQ_EDGE_CONF_BITS_PER_PIN 4
+#define ST_IRQ_EDGE_MASK 0xf
+#define ST_IRQ_EDGE_FALLING BIT(0)
+#define ST_IRQ_EDGE_RISING BIT(1)
+#define ST_IRQ_EDGE_BOTH (BIT(0) | BIT(1))
+
+#define ST_IRQ_RISING_EDGE_CONF(pin) \
+ (ST_IRQ_EDGE_RISING << (pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN))
+
+#define ST_IRQ_FALLING_EDGE_CONF(pin) \
+ (ST_IRQ_EDGE_FALLING << (pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN))
+
+#define ST_IRQ_BOTH_EDGE_CONF(pin) \
+ (ST_IRQ_EDGE_BOTH << (pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN))
+
+#define ST_IRQ_EDGE_CONF(conf, pin) \
+ (conf >> (pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN) & ST_IRQ_EDGE_MASK)
+
struct st_gpio_bank {
struct gpio_chip gpio_chip;
struct pinctrl_gpio_range range;
void __iomem *base;
struct st_pio_control pc;
+ struct irq_domain *domain;
+ unsigned long irq_edge_conf;
+ spinlock_t lock;
};
struct st_pinctrl {
@@ -284,6 +337,7 @@ struct st_pinctrl {
int ngroups;
struct regmap *regmap;
const struct st_pctl_data *data;
+ void __iomem *irqmux_base;
};
/* SOC specific data */
@@ -330,12 +384,25 @@ static unsigned int stih416_delays[] = {0, 300, 500, 750, 1000, 1250, 1500,
static const struct st_pctl_data stih416_data = {
.rt_style = st_retime_style_dedicated,
.input_delays = stih416_delays,
- .ninput_delays = 14,
+ .ninput_delays = ARRAY_SIZE(stih416_delays),
.output_delays = stih416_delays,
- .noutput_delays = 14,
+ .noutput_delays = ARRAY_SIZE(stih416_delays),
.alt = 0, .oe = 40, .pu = 50, .od = 60, .rt = 100,
};
+static const struct st_pctl_data stih407_flashdata = {
+ .rt_style = st_retime_style_none,
+ .input_delays = stih416_delays,
+ .ninput_delays = ARRAY_SIZE(stih416_delays),
+ .output_delays = stih416_delays,
+ .noutput_delays = ARRAY_SIZE(stih416_delays),
+ .alt = 0,
+ .oe = -1, /* Not Available */
+ .pu = -1, /* Not Available */
+ .od = 60,
+ .rt = 100,
+};
+
/* Low level functions.. */
static inline int st_gpio_bank(int gpio)
{
@@ -356,25 +423,29 @@ static void st_pinconf_set_config(struct st_pio_control *pc,
unsigned int oe_value, pu_value, od_value;
unsigned long mask = BIT(pin);
- regmap_field_read(output_enable, &oe_value);
- regmap_field_read(pull_up, &pu_value);
- regmap_field_read(open_drain, &od_value);
-
- /* Clear old values */
- oe_value &= ~mask;
- pu_value &= ~mask;
- od_value &= ~mask;
-
- if (config & ST_PINCONF_OE)
- oe_value |= mask;
- if (config & ST_PINCONF_PU)
- pu_value |= mask;
- if (config & ST_PINCONF_OD)
- od_value |= mask;
-
- regmap_field_write(output_enable, oe_value);
- regmap_field_write(pull_up, pu_value);
- regmap_field_write(open_drain, od_value);
+ if (output_enable) {
+ regmap_field_read(output_enable, &oe_value);
+ oe_value &= ~mask;
+ if (config & ST_PINCONF_OE)
+ oe_value |= mask;
+ regmap_field_write(output_enable, oe_value);
+ }
+
+ if (pull_up) {
+ regmap_field_read(pull_up, &pu_value);
+ pu_value &= ~mask;
+ if (config & ST_PINCONF_PU)
+ pu_value |= mask;
+ regmap_field_write(pull_up, pu_value);
+ }
+
+ if (open_drain) {
+ regmap_field_read(open_drain, &od_value);
+ od_value &= ~mask;
+ if (config & ST_PINCONF_OD)
+ od_value |= mask;
+ regmap_field_write(open_drain, od_value);
+ }
}
static void st_pctl_set_function(struct st_pio_control *pc,
@@ -385,6 +456,9 @@ static void st_pctl_set_function(struct st_pio_control *pc,
int pin = st_gpio_pin(pin_id);
int offset = pin * 4;
+ if (!alt)
+ return;
+
regmap_field_read(alt, &val);
val &= ~(0xf << offset);
val |= function << offset;
@@ -522,17 +596,23 @@ static void st_pinconf_get_direction(struct st_pio_control *pc,
{
unsigned int oe_value, pu_value, od_value;
- regmap_field_read(pc->oe, &oe_value);
- regmap_field_read(pc->pu, &pu_value);
- regmap_field_read(pc->od, &od_value);
+ if (pc->oe) {
+ regmap_field_read(pc->oe, &oe_value);
+ if (oe_value & BIT(pin))
+ ST_PINCONF_PACK_OE(*config);
+ }
- if (oe_value & BIT(pin))
- ST_PINCONF_PACK_OE(*config);
- if (pu_value & BIT(pin))
- ST_PINCONF_PACK_PU(*config);
- if (od_value & BIT(pin))
- ST_PINCONF_PACK_OD(*config);
+ if (pc->pu) {
+ regmap_field_read(pc->pu, &pu_value);
+ if (pu_value & BIT(pin))
+ ST_PINCONF_PACK_PU(*config);
+ }
+ if (pc->od) {
+ regmap_field_read(pc->od, &od_value);
+ if (od_value & BIT(pin))
+ ST_PINCONF_PACK_OD(*config);
+ }
}
static int st_pinconf_get_retime_packed(struct st_pinctrl *info,
@@ -1051,8 +1131,21 @@ static int st_pctl_dt_setup_retime(struct st_pinctrl *info,
return -EINVAL;
}
-static int st_parse_syscfgs(struct st_pinctrl *info,
- int bank, struct device_node *np)
+
+static struct regmap_field *st_pc_get_value(struct device *dev,
+ struct regmap *regmap, int bank,
+ int data, int lsb, int msb)
+{
+ struct reg_field reg = REG_FIELD((data + bank) * 4, lsb, msb);
+
+ if (data < 0)
+ return NULL;
+
+ return devm_regmap_field_alloc(dev, regmap, reg);
+}
+
+static void st_parse_syscfgs(struct st_pinctrl *info, int bank,
+ struct device_node *np)
{
const struct st_pctl_data *data = info->data;
/**
@@ -1062,29 +1155,21 @@ static int st_parse_syscfgs(struct st_pinctrl *info,
*/
int lsb = (bank%4) * ST_GPIO_PINS_PER_BANK;
int msb = lsb + ST_GPIO_PINS_PER_BANK - 1;
- struct reg_field alt_reg = REG_FIELD((data->alt + bank) * 4, 0, 31);
- struct reg_field oe_reg = REG_FIELD((data->oe + bank/4) * 4, lsb, msb);
- struct reg_field pu_reg = REG_FIELD((data->pu + bank/4) * 4, lsb, msb);
- struct reg_field od_reg = REG_FIELD((data->od + bank/4) * 4, lsb, msb);
struct st_pio_control *pc = &info->banks[bank].pc;
struct device *dev = info->dev;
struct regmap *regmap = info->regmap;
- pc->alt = devm_regmap_field_alloc(dev, regmap, alt_reg);
- pc->oe = devm_regmap_field_alloc(dev, regmap, oe_reg);
- pc->pu = devm_regmap_field_alloc(dev, regmap, pu_reg);
- pc->od = devm_regmap_field_alloc(dev, regmap, od_reg);
-
- if (IS_ERR(pc->alt) || IS_ERR(pc->oe) ||
- IS_ERR(pc->pu) || IS_ERR(pc->od))
- return -EINVAL;
+ pc->alt = st_pc_get_value(dev, regmap, bank, data->alt, 0, 31);
+ pc->oe = st_pc_get_value(dev, regmap, bank/4, data->oe, lsb, msb);
+ pc->pu = st_pc_get_value(dev, regmap, bank/4, data->pu, lsb, msb);
+ pc->od = st_pc_get_value(dev, regmap, bank/4, data->od, lsb, msb);
/* retime avaiable for all pins by default */
pc->rt_pin_mask = 0xff;
of_property_read_u32(np, "st,retime-pin-mask", &pc->rt_pin_mask);
st_pctl_dt_setup_retime(info, bank, pc);
- return 0;
+ return;
}
/*
@@ -1200,6 +1285,194 @@ static int st_pctl_parse_functions(struct device_node *np,
return 0;
}
+static int st_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct st_gpio_bank *bank = gpio_chip_to_bank(chip);
+ int irq = -ENXIO;
+
+ if (offset < chip->ngpio)
+ irq = irq_find_mapping(bank->domain, offset);
+
+ dev_info(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
+ chip->label, offset + chip->base, irq);
+ return irq;
+}
+
+static void st_gpio_irq_mask(struct irq_data *d)
+{
+ struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+
+ writel(BIT(d->hwirq), bank->base + REG_PIO_CLR_PMASK);
+}
+
+static void st_gpio_irq_unmask(struct irq_data *d)
+{
+ struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+
+ writel(BIT(d->hwirq), bank->base + REG_PIO_SET_PMASK);
+}
+
+static unsigned int st_gpio_irq_startup(struct irq_data *d)
+{
+ struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+
+ if (gpio_lock_as_irq(&bank->gpio_chip, d->hwirq))
+ dev_err(bank->gpio_chip.dev,
+ "unable to lock HW IRQ %lu for IRQ\n",
+ d->hwirq);
+
+ st_gpio_irq_unmask(d);
+
+ return 0;
+}
+
+static void st_gpio_irq_shutdown(struct irq_data *d)
+{
+ struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+
+ st_gpio_irq_mask(d);
+ gpio_unlock_as_irq(&bank->gpio_chip, d->hwirq);
+}
+
+static int st_gpio_irq_set_type(struct irq_data *d, unsigned type)
+{
+ struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+ unsigned long flags;
+ int comp, pin = d->hwirq;
+ u32 val;
+ u32 pin_edge_conf = 0;
+
+ switch (type) {
+ case IRQ_TYPE_LEVEL_HIGH:
+ comp = 0;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ comp = 0;
+ pin_edge_conf = ST_IRQ_FALLING_EDGE_CONF(pin);
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ comp = 1;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ comp = 1;
+ pin_edge_conf = ST_IRQ_RISING_EDGE_CONF(pin);
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ comp = st_gpio_get(&bank->gpio_chip, pin);
+ pin_edge_conf = ST_IRQ_BOTH_EDGE_CONF(pin);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&bank->lock, flags);
+ bank->irq_edge_conf &= ~(ST_IRQ_EDGE_MASK << (
+ pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN));
+ bank->irq_edge_conf |= pin_edge_conf;
+ spin_unlock_irqrestore(&bank->lock, flags);
+
+ val = readl(bank->base + REG_PIO_PCOMP);
+ val &= ~BIT(pin);
+ val |= (comp << pin);
+ writel(val, bank->base + REG_PIO_PCOMP);
+
+ return 0;
+}
+
+/*
+ * As edge triggers are not supported at hardware level, it is supported by
+ * software by exploiting the level trigger support in hardware.
+ *
+ * Steps for detection raising edge interrupt in software.
+ *
+ * Step 1: CONFIGURE pin to detect level LOW interrupts.
+ *
+ * Step 2: DETECT level LOW interrupt and in irqmux/gpio bank interrupt handler,
+ * if the value of pin is low, then CONFIGURE pin for level HIGH interrupt.
+ * IGNORE calling the actual interrupt handler for the pin at this stage.
+ *
+ * Step 3: DETECT level HIGH interrupt and in irqmux/gpio-bank interrupt handler
+ * if the value of pin is HIGH, CONFIGURE pin for level LOW interrupt and then
+ * DISPATCH the interrupt to the interrupt handler of the pin.
+ *
+ * step-1 ________ __________
+ * | | step - 3
+ * | |
+ * step -2 |_____|
+ *
+ * falling edge is also detected int the same way.
+ *
+ */
+static void __gpio_irq_handler(struct st_gpio_bank *bank)
+{
+ unsigned long port_in, port_mask, port_comp, active_irqs;
+ unsigned long bank_edge_mask, flags;
+ int n, val, ecfg;
+
+ spin_lock_irqsave(&bank->lock, flags);
+ bank_edge_mask = bank->irq_edge_conf;
+ spin_unlock_irqrestore(&bank->lock, flags);
+
+ for (;;) {
+ port_in = readl(bank->base + REG_PIO_PIN);
+ port_comp = readl(bank->base + REG_PIO_PCOMP);
+ port_mask = readl(bank->base + REG_PIO_PMASK);
+
+ active_irqs = (port_in ^ port_comp) & port_mask;
+
+ if (active_irqs == 0)
+ break;
+
+ for_each_set_bit(n, &active_irqs, BITS_PER_LONG) {
+ /* check if we are detecting fake edges ... */
+ ecfg = ST_IRQ_EDGE_CONF(bank_edge_mask, n);
+
+ if (ecfg) {
+ /* edge detection. */
+ val = st_gpio_get(&bank->gpio_chip, n);
+
+ writel(BIT(n),
+ val ? bank->base + REG_PIO_SET_PCOMP :
+ bank->base + REG_PIO_CLR_PCOMP);
+
+ if (ecfg != ST_IRQ_EDGE_BOTH &&
+ !((ecfg & ST_IRQ_EDGE_FALLING) ^ val))
+ continue;
+ }
+
+ generic_handle_irq(irq_find_mapping(bank->domain, n));
+ }
+ }
+}
+
+static void st_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+ /* interrupt dedicated per bank */
+ struct irq_chip *chip = irq_get_chip(irq);
+ struct st_gpio_bank *bank = irq_get_handler_data(irq);
+
+ chained_irq_enter(chip, desc);
+ __gpio_irq_handler(bank);
+ chained_irq_exit(chip, desc);
+}
+
+static void st_gpio_irqmux_handler(unsigned irq, struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_get_chip(irq);
+ struct st_pinctrl *info = irq_get_handler_data(irq);
+ unsigned long status;
+ int n;
+
+ chained_irq_enter(chip, desc);
+
+ status = readl(info->irqmux_base);
+
+ for_each_set_bit(n, &status, ST_GPIO_PINS_PER_BANK)
+ __gpio_irq_handler(&info->banks[n]);
+
+ chained_irq_exit(chip, desc);
+}
+
static struct gpio_chip st_gpio_template = {
.request = st_gpio_request,
.free = st_gpio_free,
@@ -1210,6 +1483,34 @@ static struct gpio_chip st_gpio_template = {
.ngpio = ST_GPIO_PINS_PER_BANK,
.of_gpio_n_cells = 1,
.of_xlate = st_gpio_xlate,
+ .to_irq = st_gpio_to_irq,
+};
+
+static struct irq_chip st_gpio_irqchip = {
+ .name = "GPIO",
+ .irq_mask = st_gpio_irq_mask,
+ .irq_unmask = st_gpio_irq_unmask,
+ .irq_set_type = st_gpio_irq_set_type,
+ .irq_startup = st_gpio_irq_startup,
+ .irq_shutdown = st_gpio_irq_shutdown,
+};
+
+static int st_gpio_irq_domain_map(struct irq_domain *h,
+ unsigned int virq, irq_hw_number_t hw)
+{
+ struct st_gpio_bank *bank = h->host_data;
+
+ irq_set_chip(virq, &st_gpio_irqchip);
+ irq_set_handler(virq, handle_simple_irq);
+ set_irq_flags(virq, IRQF_VALID);
+ irq_set_chip_data(virq, bank);
+
+ return 0;
+}
+
+static struct irq_domain_ops st_gpio_irq_ops = {
+ .map = st_gpio_irq_domain_map,
+ .xlate = irq_domain_xlate_twocell,
};
static int st_gpiolib_register_bank(struct st_pinctrl *info,
@@ -1219,8 +1520,8 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info,
struct pinctrl_gpio_range *range = &bank->range;
struct device *dev = info->dev;
int bank_num = of_alias_get_id(np, "gpio");
- struct resource res;
- int err;
+ struct resource res, irq_res;
+ int gpio_irq = 0, err, i;
if (of_address_to_resource(np, 0, &res))
return -ENODEV;
@@ -1233,6 +1534,7 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info,
bank->gpio_chip.base = bank_num * ST_GPIO_PINS_PER_BANK;
bank->gpio_chip.ngpio = ST_GPIO_PINS_PER_BANK;
bank->gpio_chip.of_node = np;
+ spin_lock_init(&bank->lock);
of_property_read_string(np, "st,bank-name", &range->name);
bank->gpio_chip.label = range->name;
@@ -1248,6 +1550,51 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info,
}
dev_info(dev, "%s bank added.\n", range->name);
+ /**
+ * GPIO bank can have one of the two possible types of
+ * interrupt-wirings.
+ *
+ * First type is via irqmux, single interrupt is used by multiple
+ * gpio banks. This reduces number of overall interrupts numbers
+ * required. All these banks belong to a single pincontroller.
+ * _________
+ * | |----> [gpio-bank (n) ]
+ * | |----> [gpio-bank (n + 1)]
+ * [irqN]-- | irq-mux |----> [gpio-bank (n + 2)]
+ * | |----> [gpio-bank (... )]
+ * |_________|----> [gpio-bank (n + 7)]
+ *
+ * Second type has a dedicated interrupt per each gpio bank.
+ *
+ * [irqN]----> [gpio-bank (n)]
+ */
+
+ if (of_irq_to_resource(np, 0, &irq_res)) {
+ gpio_irq = irq_res.start;
+ irq_set_chained_handler(gpio_irq, st_gpio_irq_handler);
+ irq_set_handler_data(gpio_irq, bank);
+ }
+
+ if (info->irqmux_base > 0 || gpio_irq > 0) {
+ /* Setup IRQ domain */
+ bank->domain = irq_domain_add_linear(np,
+ ST_GPIO_PINS_PER_BANK,
+ &st_gpio_irq_ops, bank);
+ if (!bank->domain) {
+ dev_err(dev, "Failed to add irq domain for %s\n",
+ np->full_name);
+ } else {
+ for (i = 0; i < ST_GPIO_PINS_PER_BANK; i++) {
+ if (irq_create_mapping(bank->domain, i) < 0)
+ dev_err(dev,
+ "Failed to map IRQ %i\n", i);
+ }
+ }
+
+ } else {
+ dev_info(dev, "No IRQ support for %s bank\n", np->full_name);
+ }
+
return 0;
}
@@ -1264,6 +1611,10 @@ static struct of_device_id st_pctl_of_match[] = {
{ .compatible = "st,stih416-rear-pinctrl", .data = &stih416_data},
{ .compatible = "st,stih416-fvdp-fe-pinctrl", .data = &stih416_data},
{ .compatible = "st,stih416-fvdp-lite-pinctrl", .data = &stih416_data},
+ { .compatible = "st,stih407-sbc-pinctrl", .data = &stih416_data},
+ { .compatible = "st,stih407-front-pinctrl", .data = &stih416_data},
+ { .compatible = "st,stih407-rear-pinctrl", .data = &stih416_data},
+ { .compatible = "st,stih407-flash-pinctrl", .data = &stih407_flashdata},
{ /* sentinel */ }
};
@@ -1276,6 +1627,8 @@ static int st_pctl_probe_dt(struct platform_device *pdev,
struct device_node *np = pdev->dev.of_node;
struct device_node *child;
int grp_index = 0;
+ int irq = 0;
+ struct resource *res;
st_pctl_dt_child_count(info, np);
if (!info->nbanks) {
@@ -1306,6 +1659,21 @@ static int st_pctl_probe_dt(struct platform_device *pdev,
}
info->data = of_match_node(st_pctl_of_match, np)->data;
+ irq = platform_get_irq(pdev, 0);
+
+ if (irq > 0) {
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "irqmux");
+ info->irqmux_base = devm_ioremap_resource(&pdev->dev, res);
+
+ if (IS_ERR(info->irqmux_base))
+ return PTR_ERR(info->irqmux_base);
+
+ irq_set_chained_handler(irq, st_gpio_irqmux_handler);
+ irq_set_handler_data(irq, info);
+
+ }
+
pctl_desc->npins = info->nbanks * ST_GPIO_PINS_PER_BANK;
pdesc = devm_kzalloc(&pdev->dev,
sizeof(*pdesc) * pctl_desc->npins, GFP_KERNEL);
diff --git a/drivers/pinctrl/pinctrl-sunxi-pins.h b/drivers/pinctrl/pinctrl-sunxi-pins.h
index 6fd8d4d95140..3d6066988a72 100644
--- a/drivers/pinctrl/pinctrl-sunxi-pins.h
+++ b/drivers/pinctrl/pinctrl-sunxi-pins.h
@@ -1932,27 +1932,27 @@ static const struct sunxi_desc_pin sun5i_a13_pins[] = {
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
- SUNXI_FUNCTION(0x4, "mmc0")), /* D1 */
+ SUNXI_FUNCTION(0x2, "mmc0")), /* D1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
- SUNXI_FUNCTION(0x4, "mmc0")), /* D0 */
+ SUNXI_FUNCTION(0x2, "mmc0")), /* D0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
- SUNXI_FUNCTION(0x4, "mmc0")), /* CLK */
+ SUNXI_FUNCTION(0x2, "mmc0")), /* CLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
- SUNXI_FUNCTION(0x4, "mmc0")), /* CMD */
+ SUNXI_FUNCTION(0x2, "mmc0")), /* CMD */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
- SUNXI_FUNCTION(0x4, "mmc0")), /* D3 */
+ SUNXI_FUNCTION(0x2, "mmc0")), /* D3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
- SUNXI_FUNCTION(0x4, "mmc0")), /* D2 */
+ SUNXI_FUNCTION(0x2, "mmc0")), /* D2 */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0,
SUNXI_FUNCTION(0x0, "gpio_in"),
diff --git a/drivers/pinctrl/pinctrl-sunxi.c b/drivers/pinctrl/pinctrl-sunxi.c
index 9ccf681dad2f..f9fabe9bf47d 100644
--- a/drivers/pinctrl/pinctrl-sunxi.c
+++ b/drivers/pinctrl/pinctrl-sunxi.c
@@ -14,6 +14,7 @@
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -584,7 +585,7 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d,
spin_lock_irqsave(&pctl->lock, flags);
regval = readl(pctl->membase + reg);
- regval &= ~IRQ_CFG_IRQ_MASK;
+ regval &= ~(IRQ_CFG_IRQ_MASK << index);
writel(regval | (mode << index), pctl->membase + reg);
spin_unlock_irqrestore(&pctl->lock, flags);
@@ -665,6 +666,7 @@ static struct irq_chip sunxi_pinctrl_irq_chip = {
static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = irq_get_chip(irq);
struct sunxi_pinctrl *pctl = irq_get_handler_data(irq);
const unsigned long reg = readl(pctl->membase + IRQ_STATUS_REG);
@@ -674,10 +676,12 @@ static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
if (reg) {
int irqoffset;
+ chained_irq_enter(chip, desc);
for_each_set_bit(irqoffset, &reg, SUNXI_IRQ_NUMBER) {
int pin_irq = irq_find_mapping(pctl->domain, irqoffset);
generic_handle_irq(pin_irq);
}
+ chained_irq_exit(chip, desc);
}
}
diff --git a/drivers/pinctrl/pinctrl-sunxi.h b/drivers/pinctrl/pinctrl-sunxi.h
index 01c494f8a14f..552b0e97077a 100644
--- a/drivers/pinctrl/pinctrl-sunxi.h
+++ b/drivers/pinctrl/pinctrl-sunxi.h
@@ -511,7 +511,7 @@ static inline u32 sunxi_pull_offset(u16 pin)
static inline u32 sunxi_irq_cfg_reg(u16 irq)
{
- u8 reg = irq / IRQ_CFG_IRQ_PER_REG;
+ u8 reg = irq / IRQ_CFG_IRQ_PER_REG * 0x04;
return reg + IRQ_CFG_REG;
}
@@ -523,7 +523,7 @@ static inline u32 sunxi_irq_cfg_offset(u16 irq)
static inline u32 sunxi_irq_ctrl_reg(u16 irq)
{
- u8 reg = irq / IRQ_CTRL_IRQ_PER_REG;
+ u8 reg = irq / IRQ_CTRL_IRQ_PER_REG * 0x04;
return reg + IRQ_CTRL_REG;
}
@@ -535,7 +535,7 @@ static inline u32 sunxi_irq_ctrl_offset(u16 irq)
static inline u32 sunxi_irq_status_reg(u16 irq)
{
- u8 reg = irq / IRQ_STATUS_IRQ_PER_REG;
+ u8 reg = irq / IRQ_STATUS_IRQ_PER_REG * 0x04;
return reg + IRQ_STATUS_REG;
}
diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
index e767355ab0ad..65458096f41e 100644
--- a/drivers/pinctrl/pinctrl-tegra.c
+++ b/drivers/pinctrl/pinctrl-tegra.c
@@ -39,6 +39,7 @@ struct tegra_pmx {
struct pinctrl_dev *pctl;
const struct tegra_pinctrl_soc_data *soc;
+ const char **group_pins;
int nbanks;
void __iomem **regs;
@@ -620,6 +621,8 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
struct tegra_pmx *pmx;
struct resource *res;
int i;
+ const char **group_pins;
+ int fn, gn, gfn;
pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
if (!pmx) {
@@ -629,6 +632,41 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
pmx->dev = &pdev->dev;
pmx->soc = soc_data;
+ /*
+ * Each mux group will appear in 4 functions' list of groups.
+ * This over-allocates slightly, since not all groups are mux groups.
+ */
+ pmx->group_pins = devm_kzalloc(&pdev->dev,
+ soc_data->ngroups * 4 * sizeof(*pmx->group_pins),
+ GFP_KERNEL);
+ if (!pmx->group_pins)
+ return -ENOMEM;
+
+ group_pins = pmx->group_pins;
+ for (fn = 0; fn < soc_data->nfunctions; fn++) {
+ struct tegra_function *func = &soc_data->functions[fn];
+
+ func->groups = group_pins;
+
+ for (gn = 0; gn < soc_data->ngroups; gn++) {
+ const struct tegra_pingroup *g = &soc_data->groups[gn];
+
+ if (g->mux_reg == -1)
+ continue;
+
+ for (gfn = 0; gfn < 4; gfn++)
+ if (g->funcs[gfn] == fn)
+ break;
+ if (gfn == 4)
+ continue;
+
+ BUG_ON(group_pins - pmx->group_pins >=
+ soc_data->ngroups * 4);
+ *group_pins++ = g->name;
+ func->ngroups++;
+ }
+ }
+
tegra_pinctrl_gpio_range.npins = pmx->soc->ngpios;
tegra_pinctrl_desc.name = dev_name(&pdev->dev);
tegra_pinctrl_desc.pins = pmx->soc->pins;
diff --git a/drivers/pinctrl/pinctrl-tegra.h b/drivers/pinctrl/pinctrl-tegra.h
index 817f7061dc4c..6053832d433e 100644
--- a/drivers/pinctrl/pinctrl-tegra.h
+++ b/drivers/pinctrl/pinctrl-tegra.h
@@ -72,7 +72,7 @@ enum tegra_pinconf_tristate {
*/
struct tegra_function {
const char *name;
- const char * const *groups;
+ const char **groups;
unsigned ngroups;
};
@@ -193,7 +193,7 @@ struct tegra_pinctrl_soc_data {
unsigned ngpios;
const struct pinctrl_pin_desc *pins;
unsigned npins;
- const struct tegra_function *functions;
+ struct tegra_function *functions;
unsigned nfunctions;
const struct tegra_pingroup *groups;
unsigned ngroups;
diff --git a/drivers/pinctrl/pinctrl-tegra114.c b/drivers/pinctrl/pinctrl-tegra114.c
index 93c9e3899d5e..63fe7619d3ff 100644
--- a/drivers/pinctrl/pinctrl-tegra114.c
+++ b/drivers/pinctrl/pinctrl-tegra114.c
@@ -1,10 +1,8 @@
/*
- * Pinctrl data and driver for the NVIDIA Tegra114 pinmux
+ * Pinctrl data for the NVIDIA Tegra114 pinmux
*
* Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved.
*
- * Author: Pritesh Raithatha <praithatha@nvidia.com>
- *
* 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.
@@ -13,9 +11,6 @@
* 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/module.h>
@@ -203,8 +198,8 @@
#define TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5 _GPIO(245)
/* All non-GPIO pins follow */
-#define NUM_GPIOS (TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5 + 1)
-#define _PIN(offset) (NUM_GPIOS + (offset))
+#define NUM_GPIOS (TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5 + 1)
+#define _PIN(offset) (NUM_GPIOS + (offset))
/* Non-GPIO pins */
#define TEGRA_PIN_CORE_PWR_REQ _PIN(0)
@@ -212,8 +207,11 @@
#define TEGRA_PIN_PWR_INT_N _PIN(2)
#define TEGRA_PIN_RESET_OUT_N _PIN(3)
#define TEGRA_PIN_OWR _PIN(4)
+#define TEGRA_PIN_JTAG_RTCK _PIN(5)
+#define TEGRA_PIN_CLK_32K_IN _PIN(6)
+#define TEGRA_PIN_GMI_CLK_LB _PIN(7)
-static const struct pinctrl_pin_desc tegra114_pins[] = {
+static const struct pinctrl_pin_desc tegra114_pins[] = {
PINCTRL_PIN(TEGRA_PIN_CLK_32K_OUT_PA0, "CLK_32K_OUT PA0"),
PINCTRL_PIN(TEGRA_PIN_UART3_CTS_N_PA1, "UART3_CTS_N PA1"),
PINCTRL_PIN(TEGRA_PIN_DAP2_FS_PA2, "DAP2_FS PA2"),
@@ -385,9 +383,12 @@ static const struct pinctrl_pin_desc tegra114_pins[] = {
PINCTRL_PIN(TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5, "SDMMC3_CLK_LB_IN PEE5"),
PINCTRL_PIN(TEGRA_PIN_CORE_PWR_REQ, "CORE_PWR_REQ"),
PINCTRL_PIN(TEGRA_PIN_CPU_PWR_REQ, "CPU_PWR_REQ"),
- PINCTRL_PIN(TEGRA_PIN_OWR, "OWR"),
PINCTRL_PIN(TEGRA_PIN_PWR_INT_N, "PWR_INT_N"),
PINCTRL_PIN(TEGRA_PIN_RESET_OUT_N, "RESET_OUT_N"),
+ PINCTRL_PIN(TEGRA_PIN_OWR, "OWR"),
+ PINCTRL_PIN(TEGRA_PIN_JTAG_RTCK, "JTAG_RTCK"),
+ PINCTRL_PIN(TEGRA_PIN_CLK_32K_IN, "CLK_32K_IN"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_CLK_LB, "GMI_CLK_LB"),
};
static const unsigned clk_32k_out_pa0_pins[] = {
@@ -1074,10 +1075,6 @@ static const unsigned cpu_pwr_req_pins[] = {
TEGRA_PIN_CPU_PWR_REQ,
};
-static const unsigned owr_pins[] = {
- TEGRA_PIN_OWR,
-};
-
static const unsigned pwr_int_n_pins[] = {
TEGRA_PIN_PWR_INT_N,
};
@@ -1086,6 +1083,22 @@ static const unsigned reset_out_n_pins[] = {
TEGRA_PIN_RESET_OUT_N,
};
+static const unsigned owr_pins[] = {
+ TEGRA_PIN_OWR,
+};
+
+static const unsigned jtag_rtck_pins[] = {
+ TEGRA_PIN_JTAG_RTCK,
+};
+
+static const unsigned clk_32k_in_pins[] = {
+ TEGRA_PIN_CLK_32K_IN,
+};
+
+static const unsigned gmi_clk_lb_pins[] = {
+ TEGRA_PIN_GMI_CLK_LB,
+};
+
static const unsigned drive_ao1_pins[] = {
TEGRA_PIN_KB_ROW0_PR0,
TEGRA_PIN_KB_ROW1_PR1,
@@ -1127,7 +1140,6 @@ static const unsigned drive_at1_pins[] = {
TEGRA_PIN_GMI_AD13_PH5,
TEGRA_PIN_GMI_AD14_PH6,
TEGRA_PIN_GMI_AD15_PH7,
-
TEGRA_PIN_GMI_IORDY_PI5,
TEGRA_PIN_GMI_CS7_N_PI6,
};
@@ -1141,15 +1153,12 @@ static const unsigned drive_at2_pins[] = {
TEGRA_PIN_GMI_AD5_PG5,
TEGRA_PIN_GMI_AD6_PG6,
TEGRA_PIN_GMI_AD7_PG7,
-
TEGRA_PIN_GMI_WR_N_PI0,
TEGRA_PIN_GMI_OE_N_PI1,
TEGRA_PIN_GMI_CS6_N_PI3,
TEGRA_PIN_GMI_RST_N_PI4,
TEGRA_PIN_GMI_WAIT_PI7,
-
TEGRA_PIN_GMI_DQS_P_PJ3,
-
TEGRA_PIN_GMI_ADV_N_PK0,
TEGRA_PIN_GMI_CLK_PK1,
TEGRA_PIN_GMI_CS4_N_PK2,
@@ -1342,14 +1351,37 @@ static const unsigned drive_uda_pins[] = {
};
static const unsigned drive_dev3_pins[] = {
- TEGRA_PIN_CLK3_OUT_PEE0,
- TEGRA_PIN_CLK3_REQ_PEE1,
+};
+
+static const unsigned drive_cec_pins[] = {
+};
+
+static const unsigned drive_at6_pins[] = {
+};
+
+static const unsigned drive_dap5_pins[] = {
+};
+
+static const unsigned drive_usb_vbus_en_pins[] = {
+};
+
+static const unsigned drive_ao3_pins[] = {
+};
+
+static const unsigned drive_hv0_pins[] = {
+};
+
+static const unsigned drive_sdio4_pins[] = {
+};
+
+static const unsigned drive_ao0_pins[] = {
};
enum tegra_mux {
TEGRA_MUX_BLINK,
TEGRA_MUX_CEC,
TEGRA_MUX_CLDVFS,
+ TEGRA_MUX_CLK,
TEGRA_MUX_CLK12,
TEGRA_MUX_CPU,
TEGRA_MUX_DAP,
@@ -1394,6 +1426,7 @@ enum tegra_mux {
TEGRA_MUX_RSVD2,
TEGRA_MUX_RSVD3,
TEGRA_MUX_RSVD4,
+ TEGRA_MUX_RTCK,
TEGRA_MUX_SDMMC1,
TEGRA_MUX_SDMMC2,
TEGRA_MUX_SDMMC3,
@@ -1425,944 +1458,16 @@ enum tegra_mux {
TEGRA_MUX_VI_ALT3,
};
-static const char * const blink_groups[] = {
- "clk_32k_out_pa0",
-};
-
-static const char * const cec_groups[] = {
- "hdmi_cec_pee3",
-};
-
-static const char * const cldvfs_groups[] = {
- "gmi_ad9_ph1",
- "gmi_ad10_ph2",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "dvfs_pwm_px0",
- "dvfs_clk_px2",
-};
-
-static const char * const clk12_groups[] = {
- "sdmmc1_wp_n_pv3",
- "sdmmc1_clk_pz0",
-};
-
-static const char * const cpu_groups[] = {
- "cpu_pwr_req",
-};
-
-static const char * const dap_groups[] = {
- "clk1_req_pee2",
- "clk2_req_pcc5",
-};
-
-static const char * const dap1_groups[] = {
- "clk1_req_pee2",
-};
-
-static const char * const dap2_groups[] = {
- "clk1_out_pw4",
- "gpio_x4_aud_px4",
-};
-
-static const char * const dev3_groups[] = {
- "clk3_req_pee1",
-};
-
-static const char * const displaya_groups[] = {
- "dap3_fs_pp0",
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "dap3_sclk_pp3",
- "uart3_rts_n_pc0",
- "pu3",
- "pu4",
- "pu5",
- "pbb3",
- "pbb4",
- "pbb5",
- "pbb6",
- "kb_row3_pr3",
- "kb_row4_pr4",
- "kb_row5_pr5",
- "kb_row6_pr6",
- "kb_col3_pq3",
- "sdmmc3_dat2_pb5",
-};
-
-static const char * const displaya_alt_groups[] = {
- "kb_row6_pr6",
-};
-
-static const char * const displayb_groups[] = {
- "dap3_fs_pp0",
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "dap3_sclk_pp3",
- "pu3",
- "pu4",
- "pu5",
- "pu6",
- "pbb3",
- "pbb4",
- "pbb5",
- "pbb6",
- "kb_row3_pr3",
- "kb_row4_pr4",
- "kb_row5_pr5",
- "kb_row6_pr6",
- "sdmmc3_dat3_pb4",
-};
-
-static const char * const dtv_groups[] = {
- "uart3_cts_n_pa1",
- "uart3_rts_n_pc0",
- "dap4_fs_pp4",
- "dap4_dout_pp6",
- "gmi_wait_pi7",
- "gmi_ad8_ph0",
- "gmi_ad14_ph6",
- "gmi_ad15_ph7",
-};
-
-static const char * const emc_dll_groups[] = {
- "kb_col0_pq0",
- "kb_col1_pq1",
-};
-
-static const char * const extperiph1_groups[] = {
- "clk1_out_pw4",
-};
-
-static const char * const extperiph2_groups[] = {
- "clk2_out_pw5",
-};
-
-static const char * const extperiph3_groups[] = {
- "clk3_out_pee0",
-};
-
-static const char * const gmi_groups[] = {
- "gmi_wp_n_pc7",
-
- "gmi_ad0_pg0",
- "gmi_ad1_pg1",
- "gmi_ad2_pg2",
- "gmi_ad3_pg3",
- "gmi_ad4_pg4",
- "gmi_ad5_pg5",
- "gmi_ad6_pg6",
- "gmi_ad7_pg7",
- "gmi_ad8_ph0",
- "gmi_ad9_ph1",
- "gmi_ad10_ph2",
- "gmi_ad11_ph3",
- "gmi_ad12_ph4",
- "gmi_ad13_ph5",
- "gmi_ad14_ph6",
- "gmi_ad15_ph7",
- "gmi_wr_n_pi0",
- "gmi_oe_n_pi1",
- "gmi_cs6_n_pi3",
- "gmi_rst_n_pi4",
- "gmi_iordy_pi5",
- "gmi_cs7_n_pi6",
- "gmi_wait_pi7",
- "gmi_cs0_n_pj0",
- "gmi_cs1_n_pj2",
- "gmi_dqs_p_pj3",
- "gmi_adv_n_pk0",
- "gmi_clk_pk1",
- "gmi_cs4_n_pk2",
- "gmi_cs2_n_pk3",
- "gmi_cs3_n_pk4",
- "gmi_a16_pj7",
- "gmi_a17_pb0",
- "gmi_a18_pb1",
- "gmi_a19_pk7",
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc4_dat7_paa7",
- "sdmmc4_clk_pcc4",
- "sdmmc4_cmd_pt7",
- "dap1_fs_pn0",
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_sclk_pn3",
-};
-
-static const char * const gmi_alt_groups[] = {
- "gmi_wp_n_pc7",
- "gmi_cs3_n_pk4",
- "gmi_a16_pj7",
-};
-
-static const char * const hda_groups[] = {
- "dap1_fs_pn0",
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_sclk_pn3",
- "dap2_fs_pa2",
- "dap2_sclk_pa3",
- "dap2_din_pa4",
- "dap2_dout_pa5",
-};
-
-static const char * const hsi_groups[] = {
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
-};
-
-static const char * const i2c1_groups[] = {
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
- "gpio_w2_aud_pw2",
- "gpio_w3_aud_pw3",
-};
-
-static const char * const i2c2_groups[] = {
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
-};
-
-static const char * const i2c3_groups[] = {
- "cam_i2c_scl_pbb1",
- "cam_i2c_sda_pbb2",
-};
-
-static const char * const i2c4_groups[] = {
- "ddc_scl_pv4",
- "ddc_sda_pv5",
-};
-
-static const char * const i2cpwr_groups[] = {
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
-};
-
-static const char * const i2s0_groups[] = {
- "dap1_fs_pn0",
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_sclk_pn3",
-};
-
-static const char * const i2s1_groups[] = {
- "dap2_fs_pa2",
- "dap2_sclk_pa3",
- "dap2_din_pa4",
- "dap2_dout_pa5",
-};
-
-static const char * const i2s2_groups[] = {
- "dap3_fs_pp0",
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "dap3_sclk_pp3",
-};
-
-static const char * const i2s3_groups[] = {
- "dap4_fs_pp4",
- "dap4_din_pp5",
- "dap4_dout_pp6",
- "dap4_sclk_pp7",
-};
-
-static const char * const i2s4_groups[] = {
- "pcc1",
- "pbb0",
- "pbb7",
- "pcc2",
-};
-
-static const char * const irda_groups[] = {
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
-};
-
-static const char * const kbc_groups[] = {
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row2_pr2",
- "kb_row3_pr3",
- "kb_row4_pr4",
- "kb_row5_pr5",
- "kb_row6_pr6",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "kb_row9_ps1",
- "kb_row10_ps2",
- "kb_col0_pq0",
- "kb_col1_pq1",
- "kb_col2_pq2",
- "kb_col3_pq3",
- "kb_col4_pq4",
- "kb_col5_pq5",
- "kb_col6_pq6",
- "kb_col7_pq7",
-};
-
-static const char * const nand_groups[] = {
- "gmi_wp_n_pc7",
- "gmi_wait_pi7",
- "gmi_adv_n_pk0",
- "gmi_clk_pk1",
- "gmi_cs0_n_pj0",
- "gmi_cs1_n_pj2",
- "gmi_cs2_n_pk3",
- "gmi_cs3_n_pk4",
- "gmi_cs4_n_pk2",
- "gmi_cs6_n_pi3",
- "gmi_cs7_n_pi6",
- "gmi_ad0_pg0",
- "gmi_ad1_pg1",
- "gmi_ad2_pg2",
- "gmi_ad3_pg3",
- "gmi_ad4_pg4",
- "gmi_ad5_pg5",
- "gmi_ad6_pg6",
- "gmi_ad7_pg7",
- "gmi_ad8_ph0",
- "gmi_ad9_ph1",
- "gmi_ad10_ph2",
- "gmi_ad11_ph3",
- "gmi_ad12_ph4",
- "gmi_ad13_ph5",
- "gmi_ad14_ph6",
- "gmi_ad15_ph7",
- "gmi_wr_n_pi0",
- "gmi_oe_n_pi1",
- "gmi_dqs_p_pj3",
- "gmi_rst_n_pi4",
-};
-
-static const char * const nand_alt_groups[] = {
- "gmi_cs6_n_pi3",
- "gmi_cs7_n_pi6",
- "gmi_rst_n_pi4",
-};
-
-static const char * const owr_groups[] = {
- "pu0",
- "kb_col4_pq4",
- "owr",
- "sdmmc3_cd_n_pv2",
-};
-
-static const char * const pmi_groups[] = {
- "pwr_int_n",
-};
-
-static const char * const pwm0_groups[] = {
- "sdmmc1_dat2_py5",
- "uart3_rts_n_pc0",
- "pu3",
- "gmi_ad8_ph0",
- "sdmmc3_dat3_pb4",
-};
-
-static const char * const pwm1_groups[] = {
- "sdmmc1_dat1_py6",
- "pu4",
- "gmi_ad9_ph1",
- "sdmmc3_dat2_pb5",
-};
-
-static const char * const pwm2_groups[] = {
- "pu5",
- "gmi_ad10_ph2",
- "kb_col3_pq3",
- "sdmmc3_dat1_pb6",
-};
-
-static const char * const pwm3_groups[] = {
- "pu6",
- "gmi_ad11_ph3",
- "sdmmc3_cmd_pa7",
-};
-
-static const char * const pwron_groups[] = {
- "core_pwr_req",
-};
-
-static const char * const reset_out_n_groups[] = {
- "reset_out_n",
-};
-
-static const char * const rsvd1_groups[] = {
- "pv1",
- "hdmi_int_pn7",
- "pu1",
- "pu2",
- "gmi_wp_n_pc7",
- "gmi_adv_n_pk0",
- "gmi_cs0_n_pj0",
- "gmi_cs1_n_pj2",
- "gmi_ad0_pg0",
- "gmi_ad1_pg1",
- "gmi_ad2_pg2",
- "gmi_ad3_pg3",
- "gmi_ad4_pg4",
- "gmi_ad5_pg5",
- "gmi_ad6_pg6",
- "gmi_ad7_pg7",
- "gmi_wr_n_pi0",
- "gmi_oe_n_pi1",
- "gpio_x4_aud_px4",
- "gpio_x5_aud_px5",
- "gpio_x7_aud_px7",
-
- "reset_out_n",
-};
-
-static const char * const rsvd2_groups[] = {
- "pv0",
- "pv1",
- "sdmmc1_dat0_py7",
- "clk2_out_pw5",
- "clk2_req_pcc5",
- "hdmi_int_pn7",
- "ddc_scl_pv4",
- "ddc_sda_pv5",
- "uart3_txd_pw6",
- "uart3_rxd_pw7",
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
- "dap4_fs_pp4",
- "dap4_din_pp5",
- "dap4_dout_pp6",
- "dap4_sclk_pp7",
- "clk3_out_pee0",
- "clk3_req_pee1",
- "gmi_iordy_pi5",
- "gmi_a17_pb0",
- "gmi_a18_pb1",
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
- "sdmmc4_clk_pcc4",
- "sdmmc4_cmd_pt7",
- "sdmmc4_dat7_paa7",
- "pcc1",
- "pbb7",
- "pcc2",
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row2_pr2",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "kb_row9_ps1",
- "kb_row10_ps2",
- "kb_col1_pq1",
- "kb_col2_pq2",
- "kb_col5_pq5",
- "kb_col6_pq6",
- "kb_col7_pq7",
- "sys_clk_req_pz5",
- "core_pwr_req",
- "cpu_pwr_req",
- "pwr_int_n",
- "owr",
- "spdif_out_pk5",
- "gpio_x1_aud_px1",
- "sdmmc3_clk_pa6",
- "sdmmc3_dat0_pb7",
- "gpio_w2_aud_pw2",
- "usb_vbus_en0_pn4",
- "usb_vbus_en1_pn5",
- "sdmmc3_clk_lb_out_pee4",
- "sdmmc3_clk_lb_in_pee5",
- "reset_out_n",
-};
-
-static const char * const rsvd3_groups[] = {
- "pv0",
- "pv1",
- "sdmmc1_clk_pz0",
- "clk2_out_pw5",
- "clk2_req_pcc5",
- "hdmi_int_pn7",
- "ddc_scl_pv4",
- "ddc_sda_pv5",
- "uart2_rts_n_pj6",
- "uart2_cts_n_pj5",
- "uart3_txd_pw6",
- "uart3_rxd_pw7",
- "pu0",
- "pu1",
- "pu2",
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
- "dap4_din_pp5",
- "dap4_sclk_pp7",
- "clk3_out_pee0",
- "clk3_req_pee1",
- "pcc1",
- "cam_i2c_scl_pbb1",
- "cam_i2c_sda_pbb2",
- "pbb7",
- "pcc2",
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row2_pr2",
- "kb_row3_pr3",
- "kb_row9_ps1",
- "kb_row10_ps2",
- "clk_32k_out_pa0",
- "sys_clk_req_pz5",
- "core_pwr_req",
- "cpu_pwr_req",
- "pwr_int_n",
- "owr",
- "clk1_req_pee2",
- "clk1_out_pw4",
- "spdif_out_pk5",
- "spdif_in_pk6",
- "dap2_fs_pa2",
- "dap2_sclk_pa3",
- "dap2_din_pa4",
- "dap2_dout_pa5",
- "dvfs_pwm_px0",
- "gpio_x1_aud_px1",
- "gpio_x3_aud_px3",
- "dvfs_clk_px2",
- "sdmmc3_clk_pa6",
- "sdmmc3_dat0_pb7",
- "hdmi_cec_pee3",
- "sdmmc3_cd_n_pv2",
- "usb_vbus_en0_pn4",
- "usb_vbus_en1_pn5",
- "sdmmc3_clk_lb_out_pee4",
- "sdmmc3_clk_lb_in_pee5",
- "reset_out_n",
-};
-
-static const char * const rsvd4_groups[] = {
- "pv0",
- "pv1",
- "sdmmc1_clk_pz0",
- "clk2_out_pw5",
- "clk2_req_pcc5",
- "hdmi_int_pn7",
- "ddc_scl_pv4",
- "ddc_sda_pv5",
- "pu0",
- "pu1",
- "pu2",
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
- "dap4_fs_pp4",
- "dap4_din_pp5",
- "dap4_dout_pp6",
- "dap4_sclk_pp7",
- "clk3_out_pee0",
- "clk3_req_pee1",
- "gmi_ad0_pg0",
- "gmi_ad1_pg1",
- "gmi_ad2_pg2",
- "gmi_ad3_pg3",
- "gmi_ad4_pg4",
- "gmi_ad12_ph4",
- "gmi_ad13_ph5",
- "gmi_rst_n_pi4",
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
- "sdmmc4_clk_pcc4",
- "sdmmc4_cmd_pt7",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc4_dat7_paa7",
- "cam_mclk_pcc0",
- "pcc1",
- "cam_i2c_scl_pbb1",
- "cam_i2c_sda_pbb2",
- "pbb3",
- "pbb4",
- "pbb5",
- "pbb6",
- "pbb7",
- "pcc2",
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row2_pr2",
- "kb_col2_pq2",
- "kb_col5_pq5",
- "kb_col6_pq6",
- "kb_col7_pq7",
- "clk_32k_out_pa0",
- "sys_clk_req_pz5",
- "core_pwr_req",
- "cpu_pwr_req",
- "pwr_int_n",
- "owr",
- "dap1_fs_pn0",
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_sclk_pn3",
- "clk1_req_pee2",
- "clk1_out_pw4",
- "spdif_in_pk6",
- "spdif_out_pk5",
- "dap2_fs_pa2",
- "dap2_sclk_pa3",
- "dap2_din_pa4",
- "dap2_dout_pa5",
- "dvfs_pwm_px0",
- "gpio_x1_aud_px1",
- "gpio_x3_aud_px3",
- "dvfs_clk_px2",
- "gpio_x5_aud_px5",
- "gpio_x6_aud_px6",
- "gpio_x7_aud_px7",
- "sdmmc3_cd_n_pv2",
- "usb_vbus_en0_pn4",
- "usb_vbus_en1_pn5",
- "sdmmc3_clk_lb_in_pee5",
- "sdmmc3_clk_lb_out_pee4",
-};
-
-static const char * const sdmmc1_groups[] = {
-
- "sdmmc1_clk_pz0",
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat3_py4",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat0_py7",
- "uart3_cts_n_pa1",
- "kb_col5_pq5",
- "sdmmc1_wp_n_pv3",
-};
-
-static const char * const sdmmc2_groups[] = {
- "gmi_iordy_pi5",
- "gmi_clk_pk1",
- "gmi_cs2_n_pk3",
- "gmi_cs3_n_pk4",
- "gmi_cs7_n_pi6",
- "gmi_ad12_ph4",
- "gmi_ad13_ph5",
- "gmi_ad14_ph6",
- "gmi_ad15_ph7",
- "gmi_dqs_p_pj3",
-};
-
-static const char * const sdmmc3_groups[] = {
- "kb_col4_pq4",
- "sdmmc3_clk_pa6",
- "sdmmc3_cmd_pa7",
- "sdmmc3_dat0_pb7",
- "sdmmc3_dat1_pb6",
- "sdmmc3_dat2_pb5",
- "sdmmc3_dat3_pb4",
- "hdmi_cec_pee3",
- "sdmmc3_cd_n_pv2",
- "sdmmc3_clk_lb_in_pee5",
- "sdmmc3_clk_lb_out_pee4",
-};
-
-static const char * const sdmmc4_groups[] = {
- "sdmmc4_clk_pcc4",
- "sdmmc4_cmd_pt7",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc4_dat7_paa7",
-};
-
-static const char * const soc_groups[] = {
- "gmi_cs1_n_pj2",
- "gmi_oe_n_pi1",
- "clk_32k_out_pa0",
- "hdmi_cec_pee3",
-};
-
-static const char * const spdif_groups[] = {
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat3_py4",
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
- "spdif_in_pk6",
- "spdif_out_pk5",
-};
-
-static const char * const spi1_groups[] = {
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
- "gpio_x3_aud_px3",
- "gpio_x4_aud_px4",
- "gpio_x5_aud_px5",
- "gpio_x6_aud_px6",
- "gpio_x7_aud_px7",
- "gpio_w3_aud_pw3",
-};
-
-static const char * const spi2_groups[] = {
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
- "kb_row4_pr4",
- "kb_row5_pr5",
- "kb_col0_pq0",
- "kb_col1_pq1",
- "kb_col2_pq2",
- "kb_col6_pq6",
- "kb_col7_pq7",
- "gpio_x4_aud_px4",
- "gpio_x5_aud_px5",
- "gpio_x6_aud_px6",
- "gpio_x7_aud_px7",
- "gpio_w2_aud_pw2",
- "gpio_w3_aud_pw3",
-};
-
-static const char * const spi3_groups[] = {
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc3_clk_pa6",
- "sdmmc3_cmd_pa7",
- "sdmmc3_dat0_pb7",
- "sdmmc3_dat1_pb6",
- "sdmmc3_dat2_pb5",
- "sdmmc3_dat3_pb4",
-};
-
-static const char * const spi4_groups[] = {
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat3_py4",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat0_py7",
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
- "uart2_rts_n_pj6",
- "uart2_cts_n_pj5",
- "uart3_txd_pw6",
- "uart3_rxd_pw7",
- "uart3_cts_n_pa1",
- "gmi_wait_pi7",
- "gmi_cs6_n_pi3",
- "gmi_ad5_pg5",
- "gmi_ad6_pg6",
- "gmi_ad7_pg7",
- "gmi_a19_pk7",
- "gmi_wr_n_pi0",
- "sdmmc1_wp_n_pv3",
-};
-
-static const char * const spi5_groups[] = {
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
- "dap3_fs_pp0",
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "dap3_sclk_pp3",
-};
-
-static const char * const spi6_groups[] = {
- "dvfs_pwm_px0",
- "gpio_x1_aud_px1",
- "gpio_x3_aud_px3",
- "dvfs_clk_px2",
- "gpio_x6_aud_px6",
- "gpio_w2_aud_pw2",
- "gpio_w3_aud_pw3",
-};
-
-static const char * const sysclk_groups[] = {
- "sys_clk_req_pz5",
-};
-
-static const char * const trace_groups[] = {
- "gmi_iordy_pi5",
- "gmi_adv_n_pk0",
- "gmi_clk_pk1",
- "gmi_cs2_n_pk3",
- "gmi_cs4_n_pk2",
- "gmi_a16_pj7",
- "gmi_a17_pb0",
- "gmi_a18_pb1",
- "gmi_a19_pk7",
- "gmi_dqs_p_pj3",
-};
-
-static const char * const uarta_groups[] = {
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat3_py4",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat0_py7",
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
- "uart2_rts_n_pj6",
- "uart2_cts_n_pj5",
- "pu0",
- "pu1",
- "pu2",
- "pu3",
- "pu4",
- "pu5",
- "pu6",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "kb_row9_ps1",
- "kb_row10_ps2",
- "kb_col3_pq3",
- "kb_col4_pq4",
- "sdmmc3_cmd_pa7",
- "sdmmc3_dat1_pb6",
- "sdmmc1_wp_n_pv3",
-};
-
-static const char * const uartb_groups[] = {
- "uart2_rts_n_pj6",
- "uart2_cts_n_pj5",
-};
-
-static const char * const uartc_groups[] = {
- "uart3_txd_pw6",
- "uart3_rxd_pw7",
- "uart3_cts_n_pa1",
- "uart3_rts_n_pc0",
-};
-
-static const char * const uartd_groups[] = {
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
- "gmi_a16_pj7",
- "gmi_a17_pb0",
- "gmi_a18_pb1",
- "gmi_a19_pk7",
-};
-
-static const char * const ulpi_groups[] = {
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
-};
-
-static const char * const usb_groups[] = {
- "pv0",
- "pu6",
- "gmi_cs0_n_pj0",
- "gmi_cs4_n_pk2",
- "gmi_ad11_ph3",
- "kb_col0_pq0",
- "spdif_in_pk6",
- "usb_vbus_en0_pn4",
- "usb_vbus_en1_pn5",
-};
-
-static const char * const vgp1_groups[] = {
- "cam_i2c_scl_pbb1",
-};
-
-static const char * const vgp2_groups[] = {
- "cam_i2c_sda_pbb2",
-};
-
-static const char * const vgp3_groups[] = {
- "pbb3",
-};
-
-static const char * const vgp4_groups[] = {
- "pbb4",
-};
-
-static const char * const vgp5_groups[] = {
- "pbb5",
-};
-
-static const char * const vgp6_groups[] = {
- "pbb6",
-};
-
-static const char * const vi_groups[] = {
- "cam_mclk_pcc0",
- "pbb0",
-};
-
-static const char * const vi_alt1_groups[] = {
- "cam_mclk_pcc0",
- "pbb0",
-};
-
-static const char * const vi_alt3_groups[] = {
- "cam_mclk_pcc0",
- "pbb0",
-};
-
#define FUNCTION(fname) \
{ \
.name = #fname, \
- .groups = fname##_groups, \
- .ngroups = ARRAY_SIZE(fname##_groups), \
}
-static const struct tegra_function tegra114_functions[] = {
+static struct tegra_function tegra114_functions[] = {
FUNCTION(blink),
FUNCTION(cec),
FUNCTION(cldvfs),
+ FUNCTION(clk),
FUNCTION(clk12),
FUNCTION(cpu),
FUNCTION(dap),
@@ -2407,6 +1512,7 @@ static const struct tegra_function tegra114_functions[] = {
FUNCTION(rsvd2),
FUNCTION(rsvd3),
FUNCTION(rsvd4),
+ FUNCTION(rtck),
FUNCTION(sdmmc1),
FUNCTION(sdmmc2),
FUNCTION(sdmmc3),
@@ -2438,11 +1544,11 @@ static const struct tegra_function tegra114_functions[] = {
FUNCTION(vi_alt3),
};
-#define DRV_PINGROUP_REG_START 0x868 /* bank 0 */
-#define PINGROUP_REG_START 0x3000 /* bank 1 */
+#define DRV_PINGROUP_REG_A 0x868 /* bank 0 */
+#define PINGROUP_REG_A 0x3000 /* bank 1 */
-#define PINGROUP_REG_Y(r) ((r) - PINGROUP_REG_START)
-#define PINGROUP_REG_N(r) -1
+#define PINGROUP_REG_Y(r) ((r) - PINGROUP_REG_A)
+#define PINGROUP_REG_N(r) -1
#define PINGROUP(pg_name, f0, f1, f2, f3, f_safe, r, od, ior, rcv_sel) \
{ \
@@ -2484,13 +1590,14 @@ static const struct tegra_function tegra114_functions[] = {
.drvtype_reg = -1, \
}
-#define DRV_PINGROUP_DVRTYPE_Y(r) ((r) - DRV_PINGROUP_REG_START)
-#define DRV_PINGROUP_DVRTYPE_N(r) -1
+#define DRV_PINGROUP_REG_Y(r) ((r) - DRV_PINGROUP_REG_A)
+#define DRV_PINGROUP_REG_N(r) -1
+
#define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b, \
- drvdn_b, drvdn_w, drvup_b, drvup_w, \
- slwr_b, slwr_w, slwf_b, slwf_w, \
- drvtype) \
+ drvdn_b, drvdn_w, drvup_b, drvup_w, \
+ slwr_b, slwr_w, slwf_b, slwf_w, \
+ drvtype) \
{ \
.name = "drive_" #pg_name, \
.pins = drive_##pg_name##_pins, \
@@ -2503,7 +1610,7 @@ static const struct tegra_function tegra114_functions[] = {
.lock_reg = -1, \
.ioreset_reg = -1, \
.rcv_sel_reg = -1, \
- .drv_reg = DRV_PINGROUP_DVRTYPE_Y(r), \
+ .drv_reg = DRV_PINGROUP_REG_Y(r), \
.drv_bank = 0, \
.hsm_bit = hsm_b, \
.schmitt_bit = schmitt_b, \
@@ -2516,14 +1623,13 @@ static const struct tegra_function tegra114_functions[] = {
.slwr_width = slwr_w, \
.slwf_bit = slwf_b, \
.slwf_width = slwf_w, \
- .drvtype_reg = DRV_PINGROUP_DVRTYPE_##drvtype(r), \
+ .drvtype_reg = DRV_PINGROUP_REG_##drvtype(r), \
.drvtype_bank = 0, \
.drvtype_bit = 6, \
}
static const struct tegra_pingroup tegra114_groups[] = {
/* pg_name, f0, f1, f2, f3, safe, r, od, ior, rcv_sel */
- /* FIXME: Fill in correct data in safe column */
PINGROUP(ulpi_data0_po1, SPI3, HSI, UARTA, ULPI, ULPI, 0x3000, N, N, N),
PINGROUP(ulpi_data1_po2, SPI3, HSI, UARTA, ULPI, ULPI, 0x3004, N, N, N),
PINGROUP(ulpi_data2_po3, SPI3, HSI, UARTA, ULPI, ULPI, 0x3008, N, N, N),
@@ -2635,6 +1741,7 @@ static const struct tegra_pingroup tegra114_groups[] = {
PINGROUP(pbb6, VGP6, DISPLAYA, DISPLAYB, RSVD4, RSVD4, 0x32a4, N, N, N),
PINGROUP(pbb7, I2S4, RSVD2, RSVD3, RSVD4, RSVD4, 0x32a8, N, N, N),
PINGROUP(pcc2, I2S4, RSVD2, RSVD3, RSVD4, RSVD4, 0x32ac, N, N, N),
+ PINGROUP(jtag_rtck, RTCK, RSVD2, RSVD3, RSVD4, RTCK, 0x32b0, N, N, N),
PINGROUP(pwr_i2c_scl_pz6, I2CPWR, RSVD2, RSVD3, RSVD4, RSVD4, 0x32b4, Y, N, N),
PINGROUP(pwr_i2c_sda_pz7, I2CPWR, RSVD2, RSVD3, RSVD4, RSVD4, 0x32b8, Y, N, N),
PINGROUP(kb_row0_pr0, KBC, RSVD2, RSVD3, RSVD4, RSVD4, 0x32bc, N, N, N),
@@ -2661,6 +1768,7 @@ static const struct tegra_pingroup tegra114_groups[] = {
PINGROUP(core_pwr_req, PWRON, RSVD2, RSVD3, RSVD4, RSVD4, 0x3324, N, N, N),
PINGROUP(cpu_pwr_req, CPU, RSVD2, RSVD3, RSVD4, RSVD4, 0x3328, N, N, N),
PINGROUP(pwr_int_n, PMI, RSVD2, RSVD3, RSVD4, RSVD4, 0x332c, N, N, N),
+ PINGROUP(clk_32k_in, CLK, RSVD2, RSVD3, RSVD4, CLK, 0x3330, N, N, N),
PINGROUP(owr, OWR, RSVD2, RSVD3, RSVD4, RSVD4, 0x3334, N, N, Y),
PINGROUP(dap1_fs_pn0, I2S0, HDA, GMI, RSVD4, RSVD4, 0x3338, N, N, N),
PINGROUP(dap1_din_pn1, I2S0, HDA, GMI, RSVD4, RSVD4, 0x333c, N, N, N),
@@ -2697,38 +1805,48 @@ static const struct tegra_pingroup tegra114_groups[] = {
PINGROUP(usb_vbus_en1_pn5, USB, RSVD2, RSVD3, RSVD4, RSVD4, 0x33f8, Y, N, N),
PINGROUP(sdmmc3_clk_lb_in_pee5, SDMMC3, RSVD2, RSVD3, RSVD4, RSVD4, 0x33fc, N, N, N),
PINGROUP(sdmmc3_clk_lb_out_pee4, SDMMC3, RSVD2, RSVD3, RSVD4, RSVD4, 0x3400, N, N, N),
+ PINGROUP(gmi_clk_lb, SDMMC2, NAND, GMI, RSVD4, GMI, 0x3404, N, N, N),
PINGROUP(reset_out_n, RSVD1, RSVD2, RSVD3, RESET_OUT_N, RSVD3, 0x3408, N, N, N),
/* pg_name, r, hsm_b, schmitt_b, lpmd_b, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w, drvtype */
- DRV_PINGROUP(ao1, 0x868, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(ao2, 0x86c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(at1, 0x870, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y),
- DRV_PINGROUP(at2, 0x874, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y),
- DRV_PINGROUP(at3, 0x878, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y),
- DRV_PINGROUP(at4, 0x87c, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y),
- DRV_PINGROUP(at5, 0x880, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(cdev1, 0x884, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(cdev2, 0x888, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(dap1, 0x890, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(dap2, 0x894, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(dap3, 0x898, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(dap4, 0x89c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(dbg, 0x8a0, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(sdio3, 0x8b0, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, N),
- DRV_PINGROUP(spi, 0x8b4, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(uaa, 0x8b8, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(uab, 0x8bc, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(uart2, 0x8c0, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(uart3, 0x8c4, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(sdio1, 0x8ec, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, N),
- DRV_PINGROUP(ddc, 0x8fc, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(gma, 0x900, 2, 3, 4, 14, 5, 20, 5, 28, 2, 30, 2, Y),
- DRV_PINGROUP(gme, 0x910, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(gmf, 0x914, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(gmg, 0x918, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(gmh, 0x91c, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(owr, 0x920, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(uda, 0x924, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(ao1, 0x868, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(ao2, 0x86c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(at1, 0x870, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, Y),
+ DRV_PINGROUP(at2, 0x874, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, Y),
+ DRV_PINGROUP(at3, 0x878, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, Y),
+ DRV_PINGROUP(at4, 0x87c, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, Y),
+ DRV_PINGROUP(at5, 0x880, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(cdev1, 0x884, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(cdev2, 0x888, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(dap1, 0x890, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(dap2, 0x894, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(dap3, 0x898, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(dap4, 0x89c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(dbg, 0x8a0, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(sdio3, 0x8b0, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, N),
+ DRV_PINGROUP(spi, 0x8b4, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(uaa, 0x8b8, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(uab, 0x8bc, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(uart2, 0x8c0, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(uart3, 0x8c4, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(sdio1, 0x8ec, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, N),
+ DRV_PINGROUP(ddc, 0x8fc, 2, 3, -1, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(gma, 0x900, 2, 3, -1, 14, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(gme, 0x910, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(gmf, 0x914, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(gmg, 0x918, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(gmh, 0x91c, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(owr, 0x920, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(uda, 0x924, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(dev3, 0x92c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(cec, 0x938, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(at6, 0x994, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, Y),
+ DRV_PINGROUP(dap5, 0x998, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(usb_vbus_en, 0x99c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(ao3, 0x9a0, 2, 3, 4, 12, 5, -1, -1, 28, 2, -1, -1, N),
+ DRV_PINGROUP(hv0, 0x9a4, 2, 3, 4, 12, 5, -1, -1, 28, 2, -1, -1, N),
+ DRV_PINGROUP(sdio4, 0x9a8, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(ao0, 0x9ac, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
};
static const struct tegra_pinctrl_soc_data tegra114_pinctrl = {
diff --git a/drivers/pinctrl/pinctrl-tegra124.c b/drivers/pinctrl/pinctrl-tegra124.c
index c20e0e1dda83..73773706755b 100644
--- a/drivers/pinctrl/pinctrl-tegra124.c
+++ b/drivers/pinctrl/pinctrl-tegra124.c
@@ -1,7 +1,7 @@
/*
* Pinctrl data for the NVIDIA Tegra124 pinmux
*
- * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -212,8 +212,8 @@
#define TEGRA_PIN_PFF2 _GPIO(250)
/* All non-GPIO pins follow */
-#define NUM_GPIOS (TEGRA_PIN_PFF2 + 1)
-#define _PIN(offset) (NUM_GPIOS + (offset))
+#define NUM_GPIOS (TEGRA_PIN_PFF2 + 1)
+#define _PIN(offset) (NUM_GPIOS + (offset))
/* Non-GPIO pins */
#define TEGRA_PIN_CORE_PWR_REQ _PIN(0)
@@ -325,13 +325,13 @@ static const struct pinctrl_pin_desc tegra124_pins[] = {
PINCTRL_PIN(TEGRA_PIN_KB_ROW8_PS0, "KB_ROW8 PS0"),
PINCTRL_PIN(TEGRA_PIN_KB_ROW9_PS1, "KB_ROW9 PS1"),
PINCTRL_PIN(TEGRA_PIN_KB_ROW10_PS2, "KB_ROW10 PS2"),
- PINCTRL_PIN(TEGRA_PIN_KB_ROW11_PS3, "KB_ROW10 PS3"),
- PINCTRL_PIN(TEGRA_PIN_KB_ROW12_PS4, "KB_ROW10 PS4"),
- PINCTRL_PIN(TEGRA_PIN_KB_ROW13_PS5, "KB_ROW10 PS5"),
- PINCTRL_PIN(TEGRA_PIN_KB_ROW14_PS6, "KB_ROW10 PS6"),
- PINCTRL_PIN(TEGRA_PIN_KB_ROW15_PS7, "KB_ROW10 PS7"),
- PINCTRL_PIN(TEGRA_PIN_KB_ROW16_PT0, "KB_ROW10 PT0"),
- PINCTRL_PIN(TEGRA_PIN_KB_ROW17_PT1, "KB_ROW10 PT1"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW11_PS3, "KB_ROW11 PS3"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW12_PS4, "KB_ROW12 PS4"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW13_PS5, "KB_ROW13 PS5"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW14_PS6, "KB_ROW14 PS6"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW15_PS7, "KB_ROW15 PS7"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW16_PT0, "KB_ROW16 PT0"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW17_PT1, "KB_ROW17 PT1"),
PINCTRL_PIN(TEGRA_PIN_GEN2_I2C_SCL_PT5, "GEN2_I2C_SCL PT5"),
PINCTRL_PIN(TEGRA_PIN_GEN2_I2C_SDA_PT6, "GEN2_I2C_SDA PT6"),
PINCTRL_PIN(TEGRA_PIN_SDMMC4_CMD_PT7, "SDMMC4_CMD PT7"),
@@ -406,16 +406,16 @@ static const struct pinctrl_pin_desc tegra124_pins[] = {
PINCTRL_PIN(TEGRA_PIN_HDMI_CEC_PEE3, "HDMI_CEC PEE3"),
PINCTRL_PIN(TEGRA_PIN_SDMMC3_CLK_LB_OUT_PEE4, "SDMMC3_CLK_LB_OUT PEE4"),
PINCTRL_PIN(TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5, "SDMMC3_CLK_LB_IN PEE5"),
+ PINCTRL_PIN(TEGRA_PIN_DP_HPD_PFF0, "DP_HPD PFF0"),
+ PINCTRL_PIN(TEGRA_PIN_USB_VBUS_EN2_PFF1, "USB_VBUS_EN2 PFF1"),
+ PINCTRL_PIN(TEGRA_PIN_PFF2, "PFF2"),
PINCTRL_PIN(TEGRA_PIN_CORE_PWR_REQ, "CORE_PWR_REQ"),
PINCTRL_PIN(TEGRA_PIN_CPU_PWR_REQ, "CPU_PWR_REQ"),
- PINCTRL_PIN(TEGRA_PIN_OWR, "OWR"),
PINCTRL_PIN(TEGRA_PIN_PWR_INT_N, "PWR_INT_N"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_CLK_LB, "GMI_CLK_LB"),
PINCTRL_PIN(TEGRA_PIN_RESET_OUT_N, "RESET_OUT_N"),
- PINCTRL_PIN(TEGRA_PIN_DP_HPD_PFF0, "DP_HPD PFF0"),
- PINCTRL_PIN(TEGRA_PIN_USB_VBUS_EN2_PFF1, "USB_VBUS_EN2 PFF1"),
- PINCTRL_PIN(TEGRA_PIN_PFF2, "PFF2"),
+ PINCTRL_PIN(TEGRA_PIN_OWR, "OWR"),
PINCTRL_PIN(TEGRA_PIN_CLK_32K_IN, "CLK_32K_IN"),
- PINCTRL_PIN(TEGRA_PIN_GMI_CLK_LB, "GMI_CLK_LB"),
PINCTRL_PIN(TEGRA_PIN_JTAG_RTCK, "JTAG_RTCK"),
};
@@ -1138,6 +1138,7 @@ static const unsigned sdmmc3_clk_lb_out_pee4_pins[] = {
static const unsigned sdmmc3_clk_lb_in_pee5_pins[] = {
TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5,
};
+
static const unsigned dp_hpd_pff0_pins[] = {
TEGRA_PIN_DP_HPD_PFF0,
};
@@ -1158,24 +1159,24 @@ static const unsigned cpu_pwr_req_pins[] = {
TEGRA_PIN_CPU_PWR_REQ,
};
-static const unsigned owr_pins[] = {
- TEGRA_PIN_OWR,
-};
-
static const unsigned pwr_int_n_pins[] = {
TEGRA_PIN_PWR_INT_N,
};
+static const unsigned gmi_clk_lb_pins[] = {
+ TEGRA_PIN_GMI_CLK_LB,
+};
+
static const unsigned reset_out_n_pins[] = {
TEGRA_PIN_RESET_OUT_N,
};
-static const unsigned clk_32k_in_pins[] = {
- TEGRA_PIN_CLK_32K_IN,
+static const unsigned owr_pins[] = {
+ TEGRA_PIN_OWR,
};
-static const unsigned gmi_clk_lb_pins[] = {
- TEGRA_PIN_GMI_CLK_LB,
+static const unsigned clk_32k_in_pins[] = {
+ TEGRA_PIN_CLK_32K_IN,
};
static const unsigned jtag_rtck_pins[] = {
@@ -1441,15 +1442,15 @@ static const unsigned drive_gpv_pins[] = {
TEGRA_PIN_PFF2,
};
-static const unsigned drive_cec_pins[] = {
- TEGRA_PIN_HDMI_CEC_PEE3,
-};
-
static const unsigned drive_dev3_pins[] = {
TEGRA_PIN_CLK3_OUT_PEE0,
TEGRA_PIN_CLK3_REQ_PEE1,
};
+static const unsigned drive_cec_pins[] = {
+ TEGRA_PIN_HDMI_CEC_PEE3,
+};
+
static const unsigned drive_at6_pins[] = {
TEGRA_PIN_PK1,
TEGRA_PIN_PK3,
@@ -1496,8 +1497,10 @@ static const unsigned drive_ao4_pins[] = {
enum tegra_mux {
TEGRA_MUX_BLINK,
+ TEGRA_MUX_CCLA,
TEGRA_MUX_CEC,
TEGRA_MUX_CLDVFS,
+ TEGRA_MUX_CLK,
TEGRA_MUX_CLK12,
TEGRA_MUX_CPU,
TEGRA_MUX_DAP,
@@ -1507,6 +1510,7 @@ enum tegra_mux {
TEGRA_MUX_DISPLAYA,
TEGRA_MUX_DISPLAYA_ALT,
TEGRA_MUX_DISPLAYB,
+ TEGRA_MUX_DP,
TEGRA_MUX_DTV,
TEGRA_MUX_EXTPERIPH1,
TEGRA_MUX_EXTPERIPH2,
@@ -1528,6 +1532,9 @@ enum tegra_mux {
TEGRA_MUX_IRDA,
TEGRA_MUX_KBC,
TEGRA_MUX_OWR,
+ TEGRA_MUX_PE,
+ TEGRA_MUX_PE0,
+ TEGRA_MUX_PE1,
TEGRA_MUX_PMI,
TEGRA_MUX_PWM0,
TEGRA_MUX_PWM1,
@@ -1539,6 +1546,8 @@ enum tegra_mux {
TEGRA_MUX_RSVD2,
TEGRA_MUX_RSVD3,
TEGRA_MUX_RSVD4,
+ TEGRA_MUX_RTCK,
+ TEGRA_MUX_SATA,
TEGRA_MUX_SDMMC1,
TEGRA_MUX_SDMMC2,
TEGRA_MUX_SDMMC3,
@@ -1551,6 +1560,8 @@ enum tegra_mux {
TEGRA_MUX_SPI4,
TEGRA_MUX_SPI5,
TEGRA_MUX_SPI6,
+ TEGRA_MUX_SYS,
+ TEGRA_MUX_TMDS,
TEGRA_MUX_TRACE,
TEGRA_MUX_UARTA,
TEGRA_MUX_UARTB,
@@ -1569,1134 +1580,19 @@ enum tegra_mux {
TEGRA_MUX_VI_ALT3,
TEGRA_MUX_VIMCLK2,
TEGRA_MUX_VIMCLK2_ALT,
- TEGRA_MUX_SATA,
- TEGRA_MUX_CCLA,
- TEGRA_MUX_PE0,
- TEGRA_MUX_PE,
- TEGRA_MUX_PE1,
- TEGRA_MUX_DP,
- TEGRA_MUX_RTCK,
- TEGRA_MUX_SYS,
- TEGRA_MUX_CLK,
- TEGRA_MUX_TMDS,
-};
-
-static const char * const blink_groups[] = {
- "clk_32k_out_pa0",
-};
-
-static const char * const cec_groups[] = {
- "hdmi_cec_pee3",
-};
-
-static const char * const cldvfs_groups[] = {
- "ph2",
- "ph3",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "dvfs_pwm_px0",
- "dvfs_clk_px2",
-};
-
-static const char * const clk12_groups[] = {
- "sdmmc1_wp_n_pv3",
- "sdmmc1_clk_pz0",
-};
-
-static const char * const cpu_groups[] = {
- "cpu_pwr_req",
-};
-
-static const char * const dap_groups[] = {
- "dap_mclk1_pee2",
- "clk2_req_pcc5",
-};
-
-static const char * const dap1_groups[] = {
- "dap_mclk1_pee2",
-};
-
-static const char * const dap2_groups[] = {
- "dap_mclk1_pw4",
- "gpio_x4_aud_px4",
-};
-
-static const char * const dev3_groups[] = {
- "clk3_req_pee1",
-};
-
-static const char * const displaya_groups[] = {
- "dap3_fs_pp0",
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "ph1",
- "pi4",
- "pbb3",
- "pbb4",
- "pbb5",
- "kb_row3_pr3",
- "kb_row4_pr4",
- "kb_row5_pr5",
- "kb_row6_pr6",
- "kb_col3_pq3",
- "sdmmc3_dat2_pb5",
-};
-
-static const char * const displaya_alt_groups[] = {
- "kb_row6_pr6",
-};
-
-static const char * const displayb_groups[] = {
- "dap3_fs_pp0",
- "dap3_din_pp1",
- "dap3_sclk_pp3",
-
- "pu3",
- "pu4",
- "pu5",
-
- "pbb3",
- "pbb4",
- "pbb6",
-
- "kb_row3_pr3",
- "kb_row4_pr4",
- "kb_row5_pr5",
- "kb_row6_pr6",
-
- "sdmmc3_dat3_pb4",
-};
-
-static const char * const dtv_groups[] = {
- "uart3_cts_n_pa1",
- "uart3_rts_n_pc0",
- "dap4_fs_pp4",
- "dap4_dout_pp6",
- "pi7",
- "ph0",
- "ph6",
- "ph7",
-};
-
-static const char * const extperiph1_groups[] = {
- "dap_mclk1_pw4",
-};
-
-static const char * const extperiph2_groups[] = {
- "clk2_out_pw5",
-};
-
-static const char * const extperiph3_groups[] = {
- "clk3_out_pee0",
-};
-
-static const char * const gmi_groups[] = {
- "uart2_cts_n_pj5",
- "uart2_rts_n_pj6",
- "uart3_txd_pw6",
- "uart3_rxd_pw7",
- "uart3_cts_n_pa1",
- "uart3_rts_n_pc0",
-
- "pu0",
- "pu1",
- "pu2",
- "pu3",
- "pu4",
- "pu5",
- "pu6",
-
- "dap4_fs_pp4",
- "dap4_din_pp5",
- "dap4_dout_pp6",
- "dap4_sclk_pp7",
-
- "pc7",
-
- "pg0",
- "pg1",
- "pg2",
- "pg3",
- "pg4",
- "pg5",
- "pg6",
- "pg7",
-
- "ph0",
- "ph1",
- "ph2",
- "ph3",
- "ph4",
- "ph5",
- "ph6",
- "ph7",
-
- "pi0",
- "pi1",
- "pi2",
- "pi3",
- "pi4",
- "pi5",
- "pi6",
- "pi7",
-
- "pj0",
- "pj2",
-
- "pk0",
- "pk1",
- "pk2",
- "pk3",
- "pk4",
-
- "pj7",
- "pb0",
- "pb1",
- "pk7",
-
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
-
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat6_paa6",
- "sdmmc4_dat7_paa7",
- "sdmmc4_clk_pcc4",
- "sdmmc4_cmd_pt7",
- "gmi_clk_lb",
-
- "dap1_fs_pn0",
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_sclk_pn3",
-
- "dap2_fs_pa2",
- "dap2_din_pa4",
- "dap2_dout_pa5",
- "dap2_sclk_pa3",
-
- "dvfs_pwm_px0",
- "dvfs_clk_px2",
- "gpio_x1_aud_px1",
- "gpio_x3_aud_px3",
- "gpio_x4_aud_px4",
- "gpio_x5_aud_px5",
- "gpio_x6_aud_px6",
-};
-
-static const char * const gmi_alt_groups[] = {
- "pc7",
- "pk4",
- "pj7",
-};
-
-static const char * const hda_groups[] = {
- "dap1_fs_pn0",
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_sclk_pn3",
- "dap2_fs_pa2",
- "dap2_sclk_pa3",
- "dap2_din_pa4",
- "dap2_dout_pa5",
-};
-
-static const char * const hsi_groups[] = {
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
-};
-
-static const char * const i2c1_groups[] = {
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
- "gpio_w2_aud_pw2",
- "gpio_w3_aud_pw3",
-};
-
-static const char * const i2c2_groups[] = {
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
-};
-
-static const char * const i2c3_groups[] = {
- "spdif_in_pk6",
- "spdif_out_pk5",
- "cam_i2c_scl_pbb1",
- "cam_i2c_sda_pbb2",
-};
-
-static const char * const i2c4_groups[] = {
- "ddc_scl_pv4",
- "ddc_sda_pv5",
-};
-
-static const char * const i2cpwr_groups[] = {
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
-};
-
-static const char * const i2s0_groups[] = {
- "dap1_fs_pn0",
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_sclk_pn3",
-};
-
-static const char * const i2s1_groups[] = {
- "dap2_fs_pa2",
- "dap2_sclk_pa3",
- "dap2_din_pa4",
- "dap2_dout_pa5",
-};
-
-static const char * const i2s2_groups[] = {
- "dap3_fs_pp0",
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "dap3_sclk_pp3",
-};
-
-static const char * const i2s3_groups[] = {
- "dap4_fs_pp4",
- "dap4_din_pp5",
- "dap4_dout_pp6",
- "dap4_sclk_pp7",
-};
-
-static const char * const i2s4_groups[] = {
- "pcc1",
- "pbb6",
- "pbb7",
- "pcc2",
-};
-
-static const char * const irda_groups[] = {
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
- "kb_row11_ps3",
- "kb_row12_ps4",
-};
-
-static const char * const kbc_groups[] = {
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row2_pr2",
- "kb_row3_pr3",
- "kb_row4_pr4",
- "kb_row5_pr5",
- "kb_row6_pr6",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "kb_row9_ps1",
- "kb_row10_ps2",
- "kb_row11_ps3",
- "kb_row12_ps4",
- "kb_row13_ps5",
- "kb_row14_ps6",
- "kb_row15_ps7",
- "kb_row16_pt0",
- "kb_row17_pt1",
-
- "kb_col0_pq0",
- "kb_col1_pq1",
- "kb_col2_pq2",
- "kb_col3_pq3",
- "kb_col4_pq4",
- "kb_col5_pq5",
- "kb_col6_pq6",
- "kb_col7_pq7",
-};
-
-static const char * const owr_groups[] = {
- "pu0",
- "kb_col4_pq4",
- "owr",
- "sdmmc3_cd_n_pv2",
-};
-
-static const char * const pmi_groups[] = {
- "pwr_int_n",
-};
-
-static const char * const pwm0_groups[] = {
- "sdmmc1_dat2_py5",
- "uart3_rts_n_pc0",
- "pu3",
- "ph0",
- "sdmmc3_dat3_pb4",
-};
-
-static const char * const pwm1_groups[] = {
- "sdmmc1_dat1_py6",
- "pu4",
- "ph1",
- "sdmmc3_dat2_pb5",
-};
-
-static const char * const pwm2_groups[] = {
- "pu5",
- "ph2",
- "kb_col3_pq3",
- "sdmmc3_dat1_pb6",
-};
-
-static const char * const pwm3_groups[] = {
- "pu6",
- "ph3",
- "sdmmc3_cmd_pa7",
-};
-
-static const char * const pwron_groups[] = {
- "core_pwr_req",
-};
-
-static const char * const reset_out_n_groups[] = {
- "reset_out_n",
-};
-
-static const char * const rsvd1_groups[] = {
- "pv0",
- "pv1",
-
- "hdmi_int_pn7",
- "pu1",
- "pu2",
- "pc7",
- "pi7",
- "pk0",
- "pj0",
- "pj2",
- "pk2",
- "pi3",
- "pi6",
-
- "pg0",
- "pg1",
- "pg2",
- "pg3",
- "pg4",
- "pg5",
- "pg6",
- "pg7",
-
- "pi0",
- "pi1",
-
- "gpio_x7_aud_px7",
-
- "reset_out_n",
-};
-
-static const char * const rsvd2_groups[] = {
- "pv0",
- "pv1",
-
- "sdmmc1_dat0_py7",
- "clk2_out_pw5",
- "clk2_req_pcc5",
- "hdmi_int_pn7",
- "ddc_scl_pv4",
- "ddc_sda_pv5",
-
- "uart3_txd_pw6",
- "uart3_rxd_pw7",
-
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
-
- "clk2_out_pee0",
- "clk2_req_pee1",
- "pc7",
- "pi5",
- "pj0",
- "pj2",
-
- "pk4",
- "pk2",
- "pi3",
- "pi6",
- "pg0",
- "pg1",
- "pg5",
- "pg6",
- "pg7",
-
- "ph4",
- "ph5",
- "pj7",
- "pb0",
- "pb1",
- "pk7",
- "pi0",
- "pi1",
-
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
- "sdmmc4_clk_pcc4",
- "sdmmc4_cmd_pt7",
- "sdmmc4_dat7_paa7",
- "pcc1",
- "pbb6",
- "pbb7",
- "pcc2",
- "jtag_rtck",
-
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
-
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row2_pr2",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "kb_row9_ps1",
- "kb_row10_ps2",
- "kb_row11_ps3",
- "kb_row12_ps4",
- "kb_row13_ps5",
- "kb_row14_ps6",
-
- "kb_col0_pq0",
- "kb_col1_pq1",
- "kb_col2_pq2",
- "kb_col5_pq5",
- "kb_col6_pq6",
- "kb_col7_pq7",
-
- "core_pwr_req",
- "cpu_pwr_req",
- "pwr_int_n",
- "clk_32k_in",
- "owr",
-
- "spdif_in_pk6",
- "spdif_out_pk5",
- "gpio_x1_aud_px1",
-
- "sdmmc3_clk_pa6",
- "sdmmc3_dat0_pb7",
-
- "pex_l0_rst_n_pdd1",
- "pex_l0_clkreq_n_pdd2",
- "pex_wake_n_pdd3",
- "pex_l1_rst_n_pdd5",
- "pex_l1_clkreq_n_pdd6",
- "hdmi_cec_pee3",
-
- "gpio_w2_aud_pw2",
- "usb_vbus_en0_pn4",
- "usb_vbus_en1_pn5",
- "sdmmc3_clk_lb_out_pee4",
- "sdmmc3_clk_lb_in_pee5",
- "gmi_clk_lb",
- "reset_out_n",
- "kb_row16_pt0",
- "kb_row17_pt1",
- "dp_hpd_pff0",
- "usb_vbus_en2_pff1",
- "pff2",
-};
-
-static const char * const rsvd3_groups[] = {
- "dap3_sclk_pp3",
- "pv0",
- "pv1",
- "sdmmc1_clk_pz0",
- "clk2_out_pw5",
- "clk2_req_pcc5",
- "hdmi_int_pn7",
-
- "ddc_scl_pv4",
- "ddc_sda_pv5",
-
- "pu6",
-
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
-
- "dap4_din_pp5",
- "dap4_sclk_pp7",
-
- "clk3_out_pee0",
- "clk3_req_pee1",
-
- "sdmmc4_dat5_paa5",
- "gpio_pcc1",
- "cam_i2c_scl_pbb1",
- "cam_i2c_sda_pbb2",
- "pbb5",
- "pbb7",
- "jtag_rtck",
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
-
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row2_pr2",
- "kb_row4_pr4",
- "kb_row5_pr5",
- "kb_row9_ps1",
- "kb_row10_ps2",
- "kb_row11_ps3",
- "kb_row12_ps4",
- "kb_row15_ps7",
-
- "clk_32k_out_pa0",
- "core_pwr_req",
- "cpu_pwr_req",
- "pwr_int_n",
- "clk_32k_in",
- "owr",
-
- "dap_mclk1_pw4",
- "spdif_in_pk6",
- "spdif_out_pk5",
- "sdmmc3_clk_pa6",
- "sdmmc3_dat0_pb7",
-
- "pex_l0_rst_n_pdd1",
- "pex_l0_clkreq_n_pdd2",
- "pex_wake_n_pdd3",
- "pex_l1_rst_n_pdd5",
- "pex_l1_clkreq_n_pdd6",
- "hdmi_cec_pee3",
-
- "sdmmc3_cd_n_pv2",
- "usb_vbus_en0_pn4",
- "usb_vbus_en1_pn5",
- "sdmmc3_clk_lb_out_pee4",
- "sdmmc3_clk_lb_in_pee5",
- "reset_out_n",
- "kb_row16_pt0",
- "kb_row17_pt1",
- "dp_hpd_pff0",
- "usb_vbus_en2_pff1",
- "pff2",
-};
-
-static const char * const rsvd4_groups[] = {
- "dap3_dout_pp2",
- "pv0",
- "pv1",
- "sdmmc1_clk_pz0",
-
- "clk2_out_pw5",
- "clk2_req_pcc5",
- "hdmi_int_pn7",
- "ddc_scl_pv4",
- "ddc_sda_pv5",
-
- "uart2_rts_n_pj6",
- "uart2_cts_n_pj5",
- "uart3_txd_pw6",
- "uart3_rxd_pw7",
-
- "pu0",
- "pu1",
- "pu2",
-
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
-
- "dap4_fs_pp4",
- "dap4_dout_pp6",
- "dap4_din_pp5",
- "dap4_sclk_pp7",
-
- "clk3_out_pee0",
- "clk3_req_pee1",
-
- "pi5",
- "pk1",
- "pk2",
- "pg0",
- "pg1",
- "pg2",
- "pg3",
- "ph4",
- "ph5",
- "pb0",
- "pb1",
- "pk7",
- "pi0",
- "pi1",
- "pi2",
-
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
-
- "sdmmc4_cmd_pt7",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc4_dat7_paa7",
-
- "jtag_rtck",
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
-
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row2_pr2",
- "kb_row13_ps5",
- "kb_row14_ps6",
- "kb_row15_ps7",
-
- "kb_col0_pq0",
- "kb_col1_pq1",
- "kb_col2_pq2",
- "kb_col5_pq5",
-
- "clk_32k_out_pa0",
- "core_pwr_req",
- "cpu_pwr_req",
- "pwr_int_n",
- "clk_32k_in",
- "owr",
-
- "dap1_fs_pn0",
- "dap1_din_pn1",
- "dap1_sclk_pn3",
- "dap_mclk1_req_pee2",
- "dap_mclk1_pw5",
-
- "dap2_fs_pa2",
- "dap2_din_pa4",
- "dap2_dout_pa5",
- "dap2_sclk_pa3",
-
- "dvfs_pwm_px0",
- "dvfs_clk_px2",
- "gpio_x1_aud_px1",
- "gpio_x3_aud_px3",
-
- "gpio_x5_aud_px5",
- "gpio_x7_aud_px7",
-
- "pex_l0_rst_n_pdd1",
- "pex_l0_clkreq_n_pdd2",
- "pex_wake_n_pdd3",
- "pex_l1_rst_n_pdd5",
- "pex_l1_clkreq_n_pdd6",
- "hdmi_cec_pee3",
-
- "sdmmc3_cd_n_pv2",
- "usb_vbus_en0_pn4",
- "usb_vbus_en1_pn5",
- "sdmmc3_clk_lb_out_pee4",
- "sdmmc3_clk_lb_in_pee5",
- "gmi_clk_lb",
-
- "dp_hpd_pff0",
- "usb_vbus_en2_pff1",
- "pff2",
-};
-
-static const char * const sdmmc1_groups[] = {
- "sdmmc1_clk_pz0",
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat3_py4",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat0_py7",
- "clk2_out_pw5",
- "clk2_req_pcc",
- "uart3_cts_n_pa1",
- "sdmmc1_wp_n_pv3",
-};
-
-static const char * const sdmmc2_groups[] = {
- "pi5",
- "pk1",
- "pk3",
- "pk4",
- "pi6",
- "ph4",
- "ph5",
- "ph6",
- "ph7",
- "pi2",
- "cam_mclk_pcc0",
- "pcc1",
- "pbb0",
- "cam_i2c_scl_pbb1",
- "cam_i2c_sda_pbb2",
- "pbb3",
- "pbb4",
- "pbb5",
- "pbb6",
- "pbb7",
- "pcc2",
- "gmi_clk_lb",
-};
-
-static const char * const sdmmc3_groups[] = {
- "pk0",
- "pcc2",
-
- "kb_col4_pq4",
- "kb_col5_pq5",
-
- "sdmmc3_clk_pa6",
- "sdmmc3_cmd_pa7",
- "sdmmc3_dat0_pb7",
- "sdmmc3_dat1_pb6",
- "sdmmc3_dat2_pb5",
- "sdmmc3_dat3_pb4",
-
- "sdmmc3_cd_n_pv2",
- "sdmmc3_clk_lb_in_pee5",
- "sdmmc3_clk_lb_out_pee4",
-};
-
-static const char * const sdmmc4_groups[] = {
- "sdmmc4_clk_pcc4",
- "sdmmc4_cmd_pt7",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc4_dat7_paa7",
-};
-
-static const char * const soc_groups[] = {
- "pk0",
- "pj2",
- "kb_row15_ps7",
- "clk_32k_out_pa0",
-};
-
-static const char * const spdif_groups[] = {
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat3_py4",
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
- "spdif_in_pk6",
- "spdif_out_pk5",
-};
-
-static const char * const spi1_groups[] = {
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
- "gpio_x3_aud_px3",
- "gpio_x4_aud_px4",
- "gpio_x5_aud_px5",
- "gpio_x6_aud_px6",
- "gpio_x7_aud_px7",
- "gpio_w3_aud_pw3",
-};
-
-static const char * const spi2_groups[] = {
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
-
- "kb_row13_ps5",
- "kb_row14_ps6",
- "kb_row15_ps7",
- "kb_col0_pq0",
- "kb_col1_pq1",
- "kb_col2_pq2",
- "kb_col6_pq6",
- "kb_col7_pq7",
- "gpio_x4_aud_px4",
- "gpio_x5_aud_px5",
- "gpio_x6_aud_px6",
- "gpio_x7_aud_px7",
- "gpio_w2_aud_pw2",
- "gpio_w3_aud_pw3",
-};
-
-static const char * const spi3_groups[] = {
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc3_clk_pa6",
- "sdmmc3_cmd_pa7",
- "sdmmc3_dat0_pb7",
- "sdmmc3_dat1_pb6",
- "sdmmc3_dat2_pb5",
- "sdmmc3_dat3_pb4",
-};
-
-static const char * const spi4_groups[] = {
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat3_py4",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat0_py7",
-
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
- "uart2_rts_n_pj6",
- "uart2_cts_n_pj5",
- "uart3_txd_pw6",
- "uart3_rxd_pw7",
-
- "pi3",
- "pg4",
- "pg5",
- "pg6",
- "pg7",
- "ph3",
- "pi4",
- "sdmmc1_wp_n_pv3",
-};
-
-static const char * const spi5_groups[] = {
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
- "dap3_fs_pp0",
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "dap3_sclk_pp3",
-};
-
-static const char * const spi6_groups[] = {
- "dvfs_pwm_px0",
- "gpio_x1_aud_px1",
- "gpio_x3_aud_px3",
- "dvfs_clk_px2",
- "gpio_x6_aud_px6",
- "gpio_w2_aud_pw2",
- "gpio_w3_aud_pw3",
-};
-
-static const char * const trace_groups[] = {
- "pi2",
- "pi4",
- "pi7",
- "ph0",
- "ph6",
- "ph7",
- "pg2",
- "pg3",
- "pk1",
- "pk3",
-};
-
-static const char * const uarta_groups[] = {
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
-
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat3_py4",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat0_py7",
-
-
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
- "uart2_rts_n_pj6",
- "uart2_cts_n_pj5",
-
- "pu0",
- "pu1",
- "pu2",
- "pu3",
- "pu4",
- "pu5",
- "pu6",
-
- "kb_row7_pr7",
- "kb_row8_ps0",
- "kb_row9_ps1",
- "kb_row10_ps2",
- "kb_col3_pq3",
- "kb_col4_pq4",
-
- "sdmmc3_cmd_pa7",
- "sdmmc3_dat1_pb6",
- "sdmmc1_wp_n_pv3",
-
-};
-
-static const char * const uartb_groups[] = {
- "uart2_rts_n_pj6",
- "uart2_cts_n_pj5",
-};
-
-static const char * const uartc_groups[] = {
- "uart3_txd_pw6",
- "uart3_rxd_pw7",
- "uart3_cts_n_pa1",
- "uart3_rts_n_pc0",
- "kb_row16_pt0",
- "kn_row17_pt1",
-};
-
-static const char * const uartd_groups[] = {
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
- "pj7",
- "pb0",
- "pb1",
- "pk7",
- "kb_col6_pq6",
- "kb_col7_pq7",
-};
-
-static const char * const ulpi_groups[] = {
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
-};
-
-static const char * const usb_groups[] = {
- "pj0",
- "usb_vbus_en0_pn4",
- "usb_vbus_en1_pn5",
- "usb_vbus_en2_pff1",
-};
-
-static const char * const vgp1_groups[] = {
- "cam_i2c_scl_pbb1",
-};
-
-static const char * const vgp2_groups[] = {
- "cam_i2c_sda_pbb2",
-};
-
-static const char * const vgp3_groups[] = {
- "pbb3",
-};
-
-static const char * const vgp4_groups[] = {
- "pbb4",
-};
-
-static const char * const vgp5_groups[] = {
- "pbb5",
-};
-
-static const char * const vgp6_groups[] = {
- "pbb0",
-};
-
-static const char * const vi_groups[] = {
- "cam_mclk_pcc0",
-};
-
-static const char * const vi_alt1_groups[] = {
- "cam_mclk_pcc0",
-};
-
-static const char * const vi_alt3_groups[] = {
- "cam_mclk_pcc0",
-};
-
-static const char * const vimclk2_groups[] = {
- "pbb0",
-};
-
-static const char * const vimclk2_alt_groups[] = {
- "pbb0",
-};
-
-static const char * const sata_groups[] = {
- "dap_mclk1_req_pee2",
- "dap1_dout_pn2",
- "pff2",
-};
-
-static const char * const ccla_groups[] = {
- "pk3",
-};
-
-static const char * const rtck_groups[] = {
- "jtag_rtck",
-};
-
-static const char * const sys_groups[] = {
- "kb_row3_pr3",
-};
-
-static const char * const pe0_groups[] = {
- "pex_l0_rst_n_pdd1",
- "pex_l0_clkreq_n_pdd2",
-};
-
-static const char * const pe_groups[] = {
- "pex_wake_n_pdd3",
-};
-
-static const char * const pe1_groups[] = {
- "pex_l1_rst_n_pdd5",
- "pex_l1_clkreq_n_pdd6",
-};
-
-static const char * const dp_groups[] = {
- "dp_hpd_pff0",
-};
-
-static const char * const clk_groups[] = {
- "clk_32k_in",
-};
-
-static const char * const tmds_groups[] = {
- "pg4",
- "ph1",
- "ph2",
};
#define FUNCTION(fname) \
{ \
.name = #fname, \
- .groups = fname##_groups, \
- .ngroups = ARRAY_SIZE(fname##_groups), \
}
-static const struct tegra_function tegra124_functions[] = {
+static struct tegra_function tegra124_functions[] = {
FUNCTION(blink),
+ FUNCTION(ccla),
FUNCTION(cec),
FUNCTION(cldvfs),
+ FUNCTION(clk),
FUNCTION(clk12),
FUNCTION(cpu),
FUNCTION(dap),
@@ -2706,6 +1602,7 @@ static const struct tegra_function tegra124_functions[] = {
FUNCTION(displaya),
FUNCTION(displaya_alt),
FUNCTION(displayb),
+ FUNCTION(dp),
FUNCTION(dtv),
FUNCTION(extperiph1),
FUNCTION(extperiph2),
@@ -2727,6 +1624,9 @@ static const struct tegra_function tegra124_functions[] = {
FUNCTION(irda),
FUNCTION(kbc),
FUNCTION(owr),
+ FUNCTION(pe),
+ FUNCTION(pe0),
+ FUNCTION(pe1),
FUNCTION(pmi),
FUNCTION(pwm0),
FUNCTION(pwm1),
@@ -2738,6 +1638,8 @@ static const struct tegra_function tegra124_functions[] = {
FUNCTION(rsvd2),
FUNCTION(rsvd3),
FUNCTION(rsvd4),
+ FUNCTION(rtck),
+ FUNCTION(sata),
FUNCTION(sdmmc1),
FUNCTION(sdmmc2),
FUNCTION(sdmmc3),
@@ -2750,6 +1652,8 @@ static const struct tegra_function tegra124_functions[] = {
FUNCTION(spi4),
FUNCTION(spi5),
FUNCTION(spi6),
+ FUNCTION(sys),
+ FUNCTION(tmds),
FUNCTION(trace),
FUNCTION(uarta),
FUNCTION(uartb),
@@ -2768,23 +1672,13 @@ static const struct tegra_function tegra124_functions[] = {
FUNCTION(vi_alt3),
FUNCTION(vimclk2),
FUNCTION(vimclk2_alt),
- FUNCTION(sata),
- FUNCTION(ccla),
- FUNCTION(pe0),
- FUNCTION(pe),
- FUNCTION(pe1),
- FUNCTION(dp),
- FUNCTION(rtck),
- FUNCTION(sys),
- FUNCTION(clk),
- FUNCTION(tmds),
};
-#define DRV_PINGROUP_REG_A 0x868 /* bank 0 */
-#define PINGROUP_REG_A 0x3000 /* bank 1 */
+#define DRV_PINGROUP_REG_A 0x868 /* bank 0 */
+#define PINGROUP_REG_A 0x3000 /* bank 1 */
-#define PINGROUP_REG_Y(r) ((r) - PINGROUP_REG_A)
-#define PINGROUP_REG_N(r) -1
+#define PINGROUP_REG_Y(r) ((r) - PINGROUP_REG_A)
+#define PINGROUP_REG_N(r) -1
#define PINGROUP(pg_name, f0, f1, f2, f3, f_safe, r, od, ior, rcv_sel) \
{ \
@@ -2792,12 +1686,12 @@ static const struct tegra_function tegra124_functions[] = {
.pins = pg_name##_pins, \
.npins = ARRAY_SIZE(pg_name##_pins), \
.funcs = { \
- TEGRA_MUX_ ## f0, \
- TEGRA_MUX_ ## f1, \
- TEGRA_MUX_ ## f2, \
- TEGRA_MUX_ ## f3, \
+ TEGRA_MUX_##f0, \
+ TEGRA_MUX_##f1, \
+ TEGRA_MUX_##f2, \
+ TEGRA_MUX_##f3, \
}, \
- .func_safe = TEGRA_MUX_ ## f_safe, \
+ .func_safe = TEGRA_MUX_##f_safe, \
.mux_reg = PINGROUP_REG_Y(r), \
.mux_bank = 1, \
.mux_bit = 0, \
@@ -2826,8 +1720,9 @@ static const struct tegra_function tegra124_functions[] = {
.drvtype_reg = -1, \
}
-#define DRV_PINGROUP_DVRTYPE_Y(r) ((r) - DRV_PINGROUP_REG_A)
-#define DRV_PINGROUP_DVRTYPE_N(r) -1
+#define DRV_PINGROUP_REG_Y(r) ((r) - DRV_PINGROUP_REG_A)
+#define DRV_PINGROUP_REG_N(r) -1
+
#define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b, \
drvdn_b, drvdn_w, drvup_b, drvup_w, \
@@ -2845,7 +1740,7 @@ static const struct tegra_function tegra124_functions[] = {
.lock_reg = -1, \
.ioreset_reg = -1, \
.rcv_sel_reg = -1, \
- .drv_reg = DRV_PINGROUP_DVRTYPE_Y(r), \
+ .drv_reg = DRV_PINGROUP_REG_Y(r), \
.drv_bank = 0, \
.hsm_bit = hsm_b, \
.schmitt_bit = schmitt_b, \
@@ -2858,7 +1753,7 @@ static const struct tegra_function tegra124_functions[] = {
.slwr_width = slwr_w, \
.slwf_bit = slwf_b, \
.slwf_width = slwf_w, \
- .drvtype_reg = DRV_PINGROUP_DVRTYPE_##drvtype(r), \
+ .drvtype_reg = DRV_PINGROUP_REG_##drvtype(r), \
.drvtype_bank = 0, \
.drvtype_bit = 6, \
}
@@ -2909,8 +1804,8 @@ static const struct tegra_pingroup tegra124_groups[] = {
PINGROUP(pu4, PWM1, UARTA, GMI, DISPLAYB, PWM1, 0x3194, N, N, N),
PINGROUP(pu5, PWM2, UARTA, GMI, DISPLAYB, PWM2, 0x3198, N, N, N),
PINGROUP(pu6, PWM3, UARTA, RSVD3, GMI, RSVD3, 0x319c, N, N, N),
- PINGROUP(gen1_i2c_scl_pc4, I2C1, RSVD2, RSVD3, RSVD4, I2C1, 0x31a0, Y, N, N),
- PINGROUP(gen1_i2c_sda_pc5, I2C1, RSVD2, RSVD3, RSVD4, I2C1, 0x31a4, Y, N, N),
+ PINGROUP(gen1_i2c_sda_pc5, I2C1, RSVD2, RSVD3, RSVD4, I2C1, 0x31a0, Y, N, N),
+ PINGROUP(gen1_i2c_scl_pc4, I2C1, RSVD2, RSVD3, RSVD4, I2C1, 0x31a4, Y, N, N),
PINGROUP(dap4_fs_pp4, I2S3, GMI, DTV, RSVD4, I2S3, 0x31a8, N, N, N),
PINGROUP(dap4_din_pp5, I2S3, GMI, RSVD3, RSVD4, I2S3, 0x31ac, N, N, N),
PINGROUP(dap4_dout_pp6, I2S3, GMI, DTV, RSVD4, I2S3, 0x31b0, N, N, N),
@@ -2964,9 +1859,9 @@ static const struct tegra_pingroup tegra124_groups[] = {
PINGROUP(sdmmc4_dat4_paa4, SDMMC4, SPI3, GMI, RSVD4, SDMMC4, 0x3270, N, Y, N),
PINGROUP(sdmmc4_dat5_paa5, SDMMC4, SPI3, RSVD3, RSVD4, SDMMC4, 0x3274, N, Y, N),
PINGROUP(sdmmc4_dat6_paa6, SDMMC4, SPI3, GMI, RSVD4, SDMMC4, 0x3278, N, Y, N),
- PINGROUP(sdmmc4_dat7_paa7, SDMMC4, RSVD1, GMI, RSVD4, SDMMC4, 0x327c, N, Y, N),
+ PINGROUP(sdmmc4_dat7_paa7, SDMMC4, RSVD2, GMI, RSVD4, SDMMC4, 0x327c, N, Y, N),
PINGROUP(cam_mclk_pcc0, VI, VI_ALT1, VI_ALT3, SDMMC2, VI, 0x3284, N, N, N),
- PINGROUP(pcc1, I2S4, RSVD1, RSVD3, SDMMC2, I2S4, 0x3288, N, N, N),
+ PINGROUP(pcc1, I2S4, RSVD2, RSVD3, SDMMC2, I2S4, 0x3288, N, N, N),
PINGROUP(pbb0, VGP6, VIMCLK2, SDMMC2, VIMCLK2_ALT, VGP6, 0x328c, N, N, N),
PINGROUP(cam_i2c_scl_pbb1, VGP1, I2C3, RSVD3, SDMMC2, VGP1, 0x3290, Y, N, N),
PINGROUP(cam_i2c_sda_pbb2, VGP2, I2C3, RSVD3, SDMMC2, VGP2, 0x3294, Y, N, N),
@@ -3047,8 +1942,8 @@ static const struct tegra_pingroup tegra124_groups[] = {
PINGROUP(gpio_w3_aud_pw3, SPI6, SPI1, SPI2, I2C1, SPI1, 0x33f0, N, N, N),
PINGROUP(usb_vbus_en0_pn4, USB, RSVD2, RSVD3, RSVD4, USB, 0x33f4, Y, N, N),
PINGROUP(usb_vbus_en1_pn5, USB, RSVD2, RSVD3, RSVD4, USB, 0x33f8, Y, N, N),
- PINGROUP(sdmmc3_clk_lb_out_pee4, SDMMC3, RSVD2, RSVD3, RSVD4, SDMMC3, 0x33fc, N, N, N),
- PINGROUP(sdmmc3_clk_lb_in_pee5, SDMMC3, RSVD2, RSVD3, RSVD4, SDMMC3, 0x3400, N, N, N),
+ PINGROUP(sdmmc3_clk_lb_in_pee5, SDMMC3, RSVD2, RSVD3, RSVD4, SDMMC3, 0x33fc, N, N, N),
+ PINGROUP(sdmmc3_clk_lb_out_pee4, SDMMC3, RSVD2, RSVD3, RSVD4, SDMMC3, 0x3400, N, N, N),
PINGROUP(gmi_clk_lb, SDMMC2, RSVD2, GMI, RSVD4, SDMMC2, 0x3404, N, N, N),
PINGROUP(reset_out_n, RSVD1, RSVD2, RSVD3, RESET_OUT_N, RSVD1, 0x3408, N, N, N),
PINGROUP(kb_row16_pt0, KBC, RSVD2, RSVD3, UARTC, KBC, 0x340c, N, N, N),
diff --git a/drivers/pinctrl/pinctrl-tegra20.c b/drivers/pinctrl/pinctrl-tegra20.c
index fcfb7d012c5b..e0b504088387 100644
--- a/drivers/pinctrl/pinctrl-tegra20.c
+++ b/drivers/pinctrl/pinctrl-tegra20.c
@@ -1894,637 +1894,12 @@ enum tegra_mux {
TEGRA_MUX_XIO,
};
-static const char * const ahb_clk_groups[] = {
- "cdev2",
-};
-
-static const char * const apb_clk_groups[] = {
- "cdev2",
-};
-
-static const char * const audio_sync_groups[] = {
- "cdev1",
-};
-
-static const char * const crt_groups[] = {
- "crtp",
- "lm1",
-};
-
-static const char * const dap1_groups[] = {
- "dap1",
-};
-
-static const char * const dap2_groups[] = {
- "dap2",
-};
-
-static const char * const dap3_groups[] = {
- "dap3",
-};
-
-static const char * const dap4_groups[] = {
- "dap4",
-};
-
-static const char * const dap5_groups[] = {
- "gme",
-};
-
-static const char * const displaya_groups[] = {
- "lcsn",
- "ld0",
- "ld1",
- "ld10",
- "ld11",
- "ld12",
- "ld13",
- "ld14",
- "ld15",
- "ld16",
- "ld17",
- "ld2",
- "ld3",
- "ld4",
- "ld5",
- "ld6",
- "ld7",
- "ld8",
- "ld9",
- "ldc",
- "ldi",
- "lhp0",
- "lhp1",
- "lhp2",
- "lhs",
- "lm0",
- "lm1",
- "lpp",
- "lpw0",
- "lpw1",
- "lpw2",
- "lsc0",
- "lsc1",
- "lsck",
- "lsda",
- "lsdi",
- "lspi",
- "lvp0",
- "lvp1",
- "lvs",
-};
-
-static const char * const displayb_groups[] = {
- "lcsn",
- "ld0",
- "ld1",
- "ld10",
- "ld11",
- "ld12",
- "ld13",
- "ld14",
- "ld15",
- "ld16",
- "ld17",
- "ld2",
- "ld3",
- "ld4",
- "ld5",
- "ld6",
- "ld7",
- "ld8",
- "ld9",
- "ldc",
- "ldi",
- "lhp0",
- "lhp1",
- "lhp2",
- "lhs",
- "lm0",
- "lm1",
- "lpp",
- "lpw0",
- "lpw1",
- "lpw2",
- "lsc0",
- "lsc1",
- "lsck",
- "lsda",
- "lsdi",
- "lspi",
- "lvp0",
- "lvp1",
- "lvs",
-};
-
-static const char * const emc_test0_dll_groups[] = {
- "kbca",
-};
-
-static const char * const emc_test1_dll_groups[] = {
- "kbcc",
-};
-
-static const char * const gmi_groups[] = {
- "ata",
- "atb",
- "atc",
- "atd",
- "ate",
- "dap1",
- "dap2",
- "dap4",
- "gma",
- "gmb",
- "gmc",
- "gmd",
- "gme",
- "gpu",
- "irrx",
- "irtx",
- "pta",
- "spia",
- "spib",
- "spic",
- "spid",
- "spie",
- "uca",
- "ucb",
-};
-
-static const char * const gmi_int_groups[] = {
- "gmb",
-};
-
-static const char * const hdmi_groups[] = {
- "hdint",
- "lpw0",
- "lpw2",
- "lsc1",
- "lsck",
- "lsda",
- "lspi",
- "pta",
-};
-
-static const char * const i2cp_groups[] = {
- "i2cp",
-};
-
-static const char * const i2c1_groups[] = {
- "rm",
- "spdi",
- "spdo",
- "spig",
- "spih",
-};
-
-static const char * const i2c2_groups[] = {
- "ddc",
- "pta",
-};
-
-static const char * const i2c3_groups[] = {
- "dtf",
-};
-
-static const char * const ide_groups[] = {
- "ata",
- "atb",
- "atc",
- "atd",
- "ate",
- "gmb",
-};
-
-static const char * const irda_groups[] = {
- "uad",
-};
-
-static const char * const kbc_groups[] = {
- "kbca",
- "kbcb",
- "kbcc",
- "kbcd",
- "kbce",
- "kbcf",
-};
-
-static const char * const mio_groups[] = {
- "kbcb",
- "kbcd",
- "kbcf",
-};
-
-static const char * const mipi_hs_groups[] = {
- "uaa",
- "uab",
-};
-
-static const char * const nand_groups[] = {
- "ata",
- "atb",
- "atc",
- "atd",
- "ate",
- "gmb",
- "gmd",
- "kbca",
- "kbcb",
- "kbcc",
- "kbcd",
- "kbce",
- "kbcf",
-};
-
-static const char * const osc_groups[] = {
- "cdev1",
- "cdev2",
-};
-
-static const char * const owr_groups[] = {
- "kbce",
- "owc",
- "uac",
-};
-
-static const char * const pcie_groups[] = {
- "gpv",
- "slxa",
- "slxk",
-};
-
-static const char * const plla_out_groups[] = {
- "cdev1",
-};
-
-static const char * const pllc_out1_groups[] = {
- "csus",
-};
-
-static const char * const pllm_out1_groups[] = {
- "cdev1",
-};
-
-static const char * const pllp_out2_groups[] = {
- "csus",
-};
-
-static const char * const pllp_out3_groups[] = {
- "csus",
-};
-
-static const char * const pllp_out4_groups[] = {
- "cdev2",
-};
-
-static const char * const pwm_groups[] = {
- "gpu",
- "sdb",
- "sdc",
- "sdd",
- "ucb",
-};
-
-static const char * const pwr_intr_groups[] = {
- "pmc",
-};
-
-static const char * const pwr_on_groups[] = {
- "pmc",
-};
-
-static const char * const rsvd1_groups[] = {
- "dta",
- "dtb",
- "dtc",
- "dtd",
- "dte",
- "gmd",
- "gme",
-};
-
-static const char * const rsvd2_groups[] = {
- "crtp",
- "dap1",
- "dap3",
- "dap4",
- "ddc",
- "dtb",
- "dtc",
- "dte",
- "dtf",
- "gpu7",
- "gpv",
- "hdint",
- "i2cp",
- "owc",
- "rm",
- "sdio1",
- "spdi",
- "spdo",
- "uac",
- "uca",
- "uda",
-};
-
-static const char * const rsvd3_groups[] = {
- "crtp",
- "dap2",
- "dap3",
- "ddc",
- "gpu7",
- "gpv",
- "hdint",
- "i2cp",
- "ld17",
- "ldc",
- "ldi",
- "lhp0",
- "lhp1",
- "lhp2",
- "lm1",
- "lpp",
- "lpw1",
- "lvp0",
- "lvp1",
- "owc",
- "pmc",
- "rm",
- "uac",
-};
-
-static const char * const rsvd4_groups[] = {
- "ata",
- "ate",
- "crtp",
- "dap3",
- "dap4",
- "ddc",
- "dta",
- "dtc",
- "dtd",
- "dtf",
- "gpu",
- "gpu7",
- "gpv",
- "hdint",
- "i2cp",
- "kbce",
- "lcsn",
- "ld0",
- "ld1",
- "ld2",
- "ld3",
- "ld4",
- "ld5",
- "ld6",
- "ld7",
- "ld8",
- "ld9",
- "ld10",
- "ld11",
- "ld12",
- "ld13",
- "ld14",
- "ld15",
- "ld16",
- "ld17",
- "ldc",
- "ldi",
- "lhp0",
- "lhp1",
- "lhp2",
- "lhs",
- "lm0",
- "lpp",
- "lpw1",
- "lsc0",
- "lsdi",
- "lvp0",
- "lvp1",
- "lvs",
- "owc",
- "pmc",
- "pta",
- "rm",
- "spif",
- "uac",
- "uca",
- "ucb",
-};
-
-static const char * const rtck_groups[] = {
- "gpu7",
-};
-
-static const char * const sdio1_groups[] = {
- "sdio1",
-};
-
-static const char * const sdio2_groups[] = {
- "dap1",
- "dta",
- "dtd",
- "kbca",
- "kbcb",
- "kbcd",
- "spdi",
- "spdo",
-};
-
-static const char * const sdio3_groups[] = {
- "sdb",
- "sdc",
- "sdd",
- "slxa",
- "slxc",
- "slxd",
- "slxk",
-};
-
-static const char * const sdio4_groups[] = {
- "atb",
- "atc",
- "atd",
- "gma",
- "gme",
-};
-
-static const char * const sflash_groups[] = {
- "gmc",
- "gmd",
-};
-
-static const char * const spdif_groups[] = {
- "slxc",
- "slxd",
- "spdi",
- "spdo",
- "uad",
-};
-
-static const char * const spi1_groups[] = {
- "dtb",
- "dte",
- "spia",
- "spib",
- "spic",
- "spid",
- "spie",
- "spif",
- "uda",
-};
-
-static const char * const spi2_groups[] = {
- "sdb",
- "slxa",
- "slxc",
- "slxd",
- "slxk",
- "spia",
- "spib",
- "spic",
- "spid",
- "spie",
- "spif",
- "spig",
- "spih",
- "uab",
-};
-
-static const char * const spi2_alt_groups[] = {
- "spid",
- "spie",
- "spig",
- "spih",
-};
-
-static const char * const spi3_groups[] = {
- "gma",
- "lcsn",
- "lm0",
- "lpw0",
- "lpw2",
- "lsc1",
- "lsck",
- "lsda",
- "lsdi",
- "sdc",
- "sdd",
- "spia",
- "spib",
- "spic",
- "spif",
- "spig",
- "spih",
- "uaa",
-};
-
-static const char * const spi4_groups[] = {
- "gmc",
- "irrx",
- "irtx",
- "slxa",
- "slxc",
- "slxd",
- "slxk",
- "uad",
-};
-
-static const char * const trace_groups[] = {
- "kbcc",
- "kbcf",
-};
-
-static const char * const twc_groups[] = {
- "dap2",
- "sdc",
-};
-
-static const char * const uarta_groups[] = {
- "gpu",
- "irrx",
- "irtx",
- "sdb",
- "sdd",
- "sdio1",
- "uaa",
- "uab",
- "uad",
-};
-
-static const char * const uartb_groups[] = {
- "irrx",
- "irtx",
-};
-
-static const char * const uartc_groups[] = {
- "uca",
- "ucb",
-};
-
-static const char * const uartd_groups[] = {
- "gmc",
- "uda",
-};
-
-static const char * const uarte_groups[] = {
- "gma",
- "sdio1",
-};
-
-static const char * const ulpi_groups[] = {
- "uaa",
- "uab",
- "uda",
-};
-
-static const char * const vi_groups[] = {
- "dta",
- "dtb",
- "dtc",
- "dtd",
- "dte",
- "dtf",
-};
-
-static const char * const vi_sensor_clk_groups[] = {
- "csus",
-};
-
-static const char * const xio_groups[] = {
- "ld0",
- "ld1",
- "ld10",
- "ld11",
- "ld12",
- "ld13",
- "ld14",
- "ld15",
- "ld16",
- "ld2",
- "ld3",
- "ld4",
- "ld5",
- "ld6",
- "ld7",
- "ld8",
- "ld9",
- "lhs",
- "lsc0",
- "lspi",
- "lvs",
-};
-
#define FUNCTION(fname) \
{ \
.name = #fname, \
- .groups = fname##_groups, \
- .ngroups = ARRAY_SIZE(fname##_groups), \
}
-static const struct tegra_function tegra20_functions[] = {
+static struct tegra_function tegra20_functions[] = {
FUNCTION(ahb_clk),
FUNCTION(apb_clk),
FUNCTION(audio_sync),
@@ -2881,18 +2256,7 @@ static struct platform_driver tegra20_pinctrl_driver = {
.probe = tegra20_pinctrl_probe,
.remove = tegra_pinctrl_remove,
};
-
-static int __init tegra20_pinctrl_init(void)
-{
- return platform_driver_register(&tegra20_pinctrl_driver);
-}
-arch_initcall(tegra20_pinctrl_init);
-
-static void __exit tegra20_pinctrl_exit(void)
-{
- platform_driver_unregister(&tegra20_pinctrl_driver);
-}
-module_exit(tegra20_pinctrl_exit);
+module_platform_driver(tegra20_pinctrl_driver);
MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
MODULE_DESCRIPTION("NVIDIA Tegra20 pinctrl driver");
diff --git a/drivers/pinctrl/pinctrl-tegra30.c b/drivers/pinctrl/pinctrl-tegra30.c
index 2300deba25bd..41d24f5c2854 100644
--- a/drivers/pinctrl/pinctrl-tegra30.c
+++ b/drivers/pinctrl/pinctrl-tegra30.c
@@ -25,7 +25,7 @@
* Most pins affected by the pinmux can also be GPIOs. Define these first.
* These must match how the GPIO driver names/numbers its pins.
*/
-#define _GPIO(offset) (offset)
+#define _GPIO(offset) (offset)
#define TEGRA_PIN_CLK_32K_OUT_PA0 _GPIO(0)
#define TEGRA_PIN_UART3_CTS_N_PA1 _GPIO(1)
@@ -277,8 +277,8 @@
#define TEGRA_PIN_PEE7 _GPIO(247)
/* All non-GPIO pins follow */
-#define NUM_GPIOS (TEGRA_PIN_PEE7 + 1)
-#define _PIN(offset) (NUM_GPIOS + (offset))
+#define NUM_GPIOS (TEGRA_PIN_PEE7 + 1)
+#define _PIN(offset) (NUM_GPIOS + (offset))
/* Non-GPIO pins */
#define TEGRA_PIN_CLK_32K_IN _PIN(0)
@@ -2015,1253 +2015,13 @@ enum tegra_mux {
TEGRA_MUX_VI_ALT2,
TEGRA_MUX_VI_ALT3,
};
-static const char * const blink_groups[] = {
- "clk_32k_out_pa0",
-};
-
-static const char * const cec_groups[] = {
- "hdmi_cec_pee3",
- "owr",
-};
-
-static const char * const clk_12m_out_groups[] = {
- "pv3",
-};
-
-static const char * const clk_32k_in_groups[] = {
- "clk_32k_in",
-};
-
-static const char * const core_pwr_req_groups[] = {
- "core_pwr_req",
-};
-
-static const char * const cpu_pwr_req_groups[] = {
- "cpu_pwr_req",
-};
-
-static const char * const crt_groups[] = {
- "crt_hsync_pv6",
- "crt_vsync_pv7",
-};
-
-static const char * const dap_groups[] = {
- "clk1_req_pee2",
- "clk2_req_pcc5",
-};
-
-static const char * const ddr_groups[] = {
- "vi_d0_pt4",
- "vi_d1_pd5",
- "vi_d10_pt2",
- "vi_d11_pt3",
- "vi_d2_pl0",
- "vi_d3_pl1",
- "vi_d4_pl2",
- "vi_d5_pl3",
- "vi_d6_pl4",
- "vi_d7_pl5",
- "vi_d8_pl6",
- "vi_d9_pl7",
- "vi_hsync_pd7",
- "vi_vsync_pd6",
-};
-
-static const char * const dev3_groups[] = {
- "clk3_req_pee1",
-};
-
-static const char * const displaya_groups[] = {
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "dap3_fs_pp0",
- "dap3_sclk_pp3",
- "pbb3",
- "pbb4",
- "pbb5",
- "pbb6",
- "lcd_cs0_n_pn4",
- "lcd_cs1_n_pw0",
- "lcd_d0_pe0",
- "lcd_d1_pe1",
- "lcd_d10_pf2",
- "lcd_d11_pf3",
- "lcd_d12_pf4",
- "lcd_d13_pf5",
- "lcd_d14_pf6",
- "lcd_d15_pf7",
- "lcd_d16_pm0",
- "lcd_d17_pm1",
- "lcd_d18_pm2",
- "lcd_d19_pm3",
- "lcd_d2_pe2",
- "lcd_d20_pm4",
- "lcd_d21_pm5",
- "lcd_d22_pm6",
- "lcd_d23_pm7",
- "lcd_d3_pe3",
- "lcd_d4_pe4",
- "lcd_d5_pe5",
- "lcd_d6_pe6",
- "lcd_d7_pe7",
- "lcd_d8_pf0",
- "lcd_d9_pf1",
- "lcd_dc0_pn6",
- "lcd_dc1_pd2",
- "lcd_de_pj1",
- "lcd_hsync_pj3",
- "lcd_m1_pw1",
- "lcd_pclk_pb3",
- "lcd_pwr0_pb2",
- "lcd_pwr1_pc1",
- "lcd_pwr2_pc6",
- "lcd_sck_pz4",
- "lcd_sdin_pz2",
- "lcd_sdout_pn5",
- "lcd_vsync_pj4",
- "lcd_wr_n_pz3",
-};
-
-static const char * const displayb_groups[] = {
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "dap3_fs_pp0",
- "dap3_sclk_pp3",
- "pbb3",
- "pbb4",
- "pbb5",
- "pbb6",
- "lcd_cs0_n_pn4",
- "lcd_cs1_n_pw0",
- "lcd_d0_pe0",
- "lcd_d1_pe1",
- "lcd_d10_pf2",
- "lcd_d11_pf3",
- "lcd_d12_pf4",
- "lcd_d13_pf5",
- "lcd_d14_pf6",
- "lcd_d15_pf7",
- "lcd_d16_pm0",
- "lcd_d17_pm1",
- "lcd_d18_pm2",
- "lcd_d19_pm3",
- "lcd_d2_pe2",
- "lcd_d20_pm4",
- "lcd_d21_pm5",
- "lcd_d22_pm6",
- "lcd_d23_pm7",
- "lcd_d3_pe3",
- "lcd_d4_pe4",
- "lcd_d5_pe5",
- "lcd_d6_pe6",
- "lcd_d7_pe7",
- "lcd_d8_pf0",
- "lcd_d9_pf1",
- "lcd_dc0_pn6",
- "lcd_dc1_pd2",
- "lcd_de_pj1",
- "lcd_hsync_pj3",
- "lcd_m1_pw1",
- "lcd_pclk_pb3",
- "lcd_pwr0_pb2",
- "lcd_pwr1_pc1",
- "lcd_pwr2_pc6",
- "lcd_sck_pz4",
- "lcd_sdin_pz2",
- "lcd_sdout_pn5",
- "lcd_vsync_pj4",
- "lcd_wr_n_pz3",
-};
-
-static const char * const dtv_groups[] = {
- "gmi_a17_pb0",
- "gmi_a18_pb1",
- "gmi_cs0_n_pj0",
- "gmi_cs1_n_pj2",
-};
-
-static const char * const extperiph1_groups[] = {
- "clk1_out_pw4",
-};
-
-static const char * const extperiph2_groups[] = {
- "clk2_out_pw5",
-};
-
-static const char * const extperiph3_groups[] = {
- "clk3_out_pee0",
-};
-
-static const char * const gmi_groups[] = {
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_fs_pn0",
- "dap1_sclk_pn3",
- "dap2_din_pa4",
- "dap2_dout_pa5",
- "dap2_fs_pa2",
- "dap2_sclk_pa3",
- "dap4_din_pp5",
- "dap4_dout_pp6",
- "dap4_fs_pp4",
- "dap4_sclk_pp7",
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
- "gmi_a16_pj7",
- "gmi_a17_pb0",
- "gmi_a18_pb1",
- "gmi_a19_pk7",
- "gmi_ad0_pg0",
- "gmi_ad1_pg1",
- "gmi_ad10_ph2",
- "gmi_ad11_ph3",
- "gmi_ad12_ph4",
- "gmi_ad13_ph5",
- "gmi_ad14_ph6",
- "gmi_ad15_ph7",
- "gmi_ad2_pg2",
- "gmi_ad3_pg3",
- "gmi_ad4_pg4",
- "gmi_ad5_pg5",
- "gmi_ad6_pg6",
- "gmi_ad7_pg7",
- "gmi_ad8_ph0",
- "gmi_ad9_ph1",
- "gmi_adv_n_pk0",
- "gmi_clk_pk1",
- "gmi_cs0_n_pj0",
- "gmi_cs1_n_pj2",
- "gmi_cs2_n_pk3",
- "gmi_cs3_n_pk4",
- "gmi_cs4_n_pk2",
- "gmi_cs6_n_pi3",
- "gmi_cs7_n_pi6",
- "gmi_dqs_pi2",
- "gmi_iordy_pi5",
- "gmi_oe_n_pi1",
- "gmi_rst_n_pi4",
- "gmi_wait_pi7",
- "gmi_wp_n_pc7",
- "gmi_wr_n_pi0",
- "pu0",
- "pu1",
- "pu2",
- "pu3",
- "pu4",
- "pu5",
- "pu6",
- "sdmmc4_clk_pcc4",
- "sdmmc4_cmd_pt7",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc4_dat7_paa7",
- "spi1_cs0_n_px6",
- "spi1_mosi_px4",
- "spi1_sck_px5",
- "spi2_cs0_n_px3",
- "spi2_miso_px1",
- "spi2_mosi_px0",
- "spi2_sck_px2",
- "uart2_cts_n_pj5",
- "uart2_rts_n_pj6",
- "uart3_cts_n_pa1",
- "uart3_rts_n_pc0",
- "uart3_rxd_pw7",
- "uart3_txd_pw6",
-};
-
-static const char * const gmi_alt_groups[] = {
- "gmi_a16_pj7",
- "gmi_cs3_n_pk4",
- "gmi_cs7_n_pi6",
- "gmi_wp_n_pc7",
-};
-
-static const char * const hda_groups[] = {
- "clk1_req_pee2",
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_fs_pn0",
- "dap1_sclk_pn3",
- "dap2_din_pa4",
- "dap2_dout_pa5",
- "dap2_fs_pa2",
- "dap2_sclk_pa3",
- "pex_l0_clkreq_n_pdd2",
- "pex_l0_prsnt_n_pdd0",
- "pex_l0_rst_n_pdd1",
- "pex_l1_clkreq_n_pdd6",
- "pex_l1_prsnt_n_pdd4",
- "pex_l1_rst_n_pdd5",
- "pex_l2_clkreq_n_pcc7",
- "pex_l2_prsnt_n_pdd7",
- "pex_l2_rst_n_pcc6",
- "pex_wake_n_pdd3",
- "spdif_in_pk6",
-};
-
-static const char * const hdcp_groups[] = {
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
- "lcd_pwr0_pb2",
- "lcd_pwr2_pc6",
- "lcd_sck_pz4",
- "lcd_sdout_pn5",
- "lcd_wr_n_pz3",
-};
-
-static const char * const hdmi_groups[] = {
- "hdmi_int_pn7",
-};
-
-static const char * const hsi_groups[] = {
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
-};
-
-static const char * const i2c1_groups[] = {
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
- "spdif_in_pk6",
- "spdif_out_pk5",
- "spi2_cs1_n_pw2",
- "spi2_cs2_n_pw3",
-};
-
-static const char * const i2c2_groups[] = {
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
-};
-
-static const char * const i2c3_groups[] = {
- "cam_i2c_scl_pbb1",
- "cam_i2c_sda_pbb2",
- "sdmmc4_cmd_pt7",
- "sdmmc4_dat4_paa4",
-};
-
-static const char * const i2c4_groups[] = {
- "ddc_scl_pv4",
- "ddc_sda_pv5",
-};
-
-static const char * const i2cpwr_groups[] = {
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
-};
-
-static const char * const i2s0_groups[] = {
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_fs_pn0",
- "dap1_sclk_pn3",
-};
-
-static const char * const i2s1_groups[] = {
- "dap2_din_pa4",
- "dap2_dout_pa5",
- "dap2_fs_pa2",
- "dap2_sclk_pa3",
-};
-
-static const char * const i2s2_groups[] = {
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "dap3_fs_pp0",
- "dap3_sclk_pp3",
-};
-
-static const char * const i2s3_groups[] = {
- "dap4_din_pp5",
- "dap4_dout_pp6",
- "dap4_fs_pp4",
- "dap4_sclk_pp7",
-};
-
-static const char * const i2s4_groups[] = {
- "pbb0",
- "pbb7",
- "pcc1",
- "pcc2",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc4_dat7_paa7",
-};
-
-static const char * const invalid_groups[] = {
- "kb_row3_pr3",
- "sdmmc4_clk_pcc4",
-};
-
-static const char * const kbc_groups[] = {
- "kb_col0_pq0",
- "kb_col1_pq1",
- "kb_col2_pq2",
- "kb_col3_pq3",
- "kb_col4_pq4",
- "kb_col5_pq5",
- "kb_col6_pq6",
- "kb_col7_pq7",
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row10_ps2",
- "kb_row11_ps3",
- "kb_row12_ps4",
- "kb_row13_ps5",
- "kb_row14_ps6",
- "kb_row15_ps7",
- "kb_row2_pr2",
- "kb_row3_pr3",
- "kb_row4_pr4",
- "kb_row5_pr5",
- "kb_row6_pr6",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "kb_row9_ps1",
-};
-
-static const char * const mio_groups[] = {
- "kb_col6_pq6",
- "kb_col7_pq7",
- "kb_row10_ps2",
- "kb_row11_ps3",
- "kb_row12_ps4",
- "kb_row13_ps5",
- "kb_row14_ps6",
- "kb_row15_ps7",
- "kb_row6_pr6",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "kb_row9_ps1",
-};
-
-static const char * const nand_groups[] = {
- "gmi_ad0_pg0",
- "gmi_ad1_pg1",
- "gmi_ad10_ph2",
- "gmi_ad11_ph3",
- "gmi_ad12_ph4",
- "gmi_ad13_ph5",
- "gmi_ad14_ph6",
- "gmi_ad15_ph7",
- "gmi_ad2_pg2",
- "gmi_ad3_pg3",
- "gmi_ad4_pg4",
- "gmi_ad5_pg5",
- "gmi_ad6_pg6",
- "gmi_ad7_pg7",
- "gmi_ad8_ph0",
- "gmi_ad9_ph1",
- "gmi_adv_n_pk0",
- "gmi_clk_pk1",
- "gmi_cs0_n_pj0",
- "gmi_cs1_n_pj2",
- "gmi_cs2_n_pk3",
- "gmi_cs3_n_pk4",
- "gmi_cs4_n_pk2",
- "gmi_cs6_n_pi3",
- "gmi_cs7_n_pi6",
- "gmi_dqs_pi2",
- "gmi_iordy_pi5",
- "gmi_oe_n_pi1",
- "gmi_rst_n_pi4",
- "gmi_wait_pi7",
- "gmi_wp_n_pc7",
- "gmi_wr_n_pi0",
- "kb_col0_pq0",
- "kb_col1_pq1",
- "kb_col2_pq2",
- "kb_col3_pq3",
- "kb_col4_pq4",
- "kb_col5_pq5",
- "kb_col6_pq6",
- "kb_col7_pq7",
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row10_ps2",
- "kb_row11_ps3",
- "kb_row12_ps4",
- "kb_row13_ps5",
- "kb_row14_ps6",
- "kb_row15_ps7",
- "kb_row2_pr2",
- "kb_row3_pr3",
- "kb_row4_pr4",
- "kb_row5_pr5",
- "kb_row6_pr6",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "kb_row9_ps1",
- "sdmmc4_clk_pcc4",
- "sdmmc4_cmd_pt7",
-};
-
-static const char * const nand_alt_groups[] = {
- "gmi_cs6_n_pi3",
- "gmi_cs7_n_pi6",
- "gmi_rst_n_pi4",
-};
-
-static const char * const owr_groups[] = {
- "pu0",
- "pv2",
- "kb_row5_pr5",
- "owr",
-};
-
-static const char * const pcie_groups[] = {
- "pex_l0_clkreq_n_pdd2",
- "pex_l0_prsnt_n_pdd0",
- "pex_l0_rst_n_pdd1",
- "pex_l1_clkreq_n_pdd6",
- "pex_l1_prsnt_n_pdd4",
- "pex_l1_rst_n_pdd5",
- "pex_l2_clkreq_n_pcc7",
- "pex_l2_prsnt_n_pdd7",
- "pex_l2_rst_n_pcc6",
- "pex_wake_n_pdd3",
-};
-
-static const char * const pwm0_groups[] = {
- "gmi_ad8_ph0",
- "pu3",
- "sdmmc3_dat3_pb4",
- "sdmmc3_dat5_pd0",
- "uart3_rts_n_pc0",
-};
-
-static const char * const pwm1_groups[] = {
- "gmi_ad9_ph1",
- "pu4",
- "sdmmc3_dat2_pb5",
- "sdmmc3_dat4_pd1",
-};
-
-static const char * const pwm2_groups[] = {
- "gmi_ad10_ph2",
- "pu5",
- "sdmmc3_clk_pa6",
-};
-
-static const char * const pwm3_groups[] = {
- "gmi_ad11_ph3",
- "pu6",
- "sdmmc3_cmd_pa7",
-};
-
-static const char * const pwr_int_n_groups[] = {
- "pwr_int_n",
-};
-
-static const char * const rsvd1_groups[] = {
- "gmi_ad0_pg0",
- "gmi_ad1_pg1",
- "gmi_ad12_ph4",
- "gmi_ad13_ph5",
- "gmi_ad14_ph6",
- "gmi_ad15_ph7",
- "gmi_ad2_pg2",
- "gmi_ad3_pg3",
- "gmi_ad4_pg4",
- "gmi_ad5_pg5",
- "gmi_ad6_pg6",
- "gmi_ad7_pg7",
- "gmi_adv_n_pk0",
- "gmi_clk_pk1",
- "gmi_cs0_n_pj0",
- "gmi_cs1_n_pj2",
- "gmi_cs2_n_pk3",
- "gmi_cs3_n_pk4",
- "gmi_cs4_n_pk2",
- "gmi_dqs_pi2",
- "gmi_iordy_pi5",
- "gmi_oe_n_pi1",
- "gmi_wait_pi7",
- "gmi_wp_n_pc7",
- "gmi_wr_n_pi0",
- "pu1",
- "pu2",
- "pv0",
- "pv1",
- "sdmmc3_dat0_pb7",
- "sdmmc3_dat1_pb6",
- "sdmmc3_dat2_pb5",
- "sdmmc3_dat3_pb4",
- "vi_pclk_pt0",
-};
-
-static const char * const rsvd2_groups[] = {
- "clk1_out_pw4",
- "clk2_out_pw5",
- "clk2_req_pcc5",
- "clk3_out_pee0",
- "clk3_req_pee1",
- "clk_32k_in",
- "clk_32k_out_pa0",
- "core_pwr_req",
- "cpu_pwr_req",
- "crt_hsync_pv6",
- "crt_vsync_pv7",
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "dap3_fs_pp0",
- "dap3_sclk_pp3",
- "dap4_din_pp5",
- "dap4_dout_pp6",
- "dap4_fs_pp4",
- "dap4_sclk_pp7",
- "ddc_scl_pv4",
- "ddc_sda_pv5",
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
- "pbb0",
- "pbb7",
- "pcc1",
- "pcc2",
- "pv0",
- "pv1",
- "pv2",
- "pv3",
- "hdmi_cec_pee3",
- "hdmi_int_pn7",
- "jtag_rtck_pu7",
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
- "pwr_int_n",
- "sdmmc1_clk_pz0",
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat0_py7",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat3_py4",
- "sdmmc3_dat0_pb7",
- "sdmmc3_dat1_pb6",
- "sdmmc4_rst_n_pcc3",
- "spdif_out_pk5",
- "sys_clk_req_pz5",
- "uart3_cts_n_pa1",
- "uart3_rxd_pw7",
- "uart3_txd_pw6",
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
- "vi_d0_pt4",
- "vi_d10_pt2",
- "vi_d11_pt3",
- "vi_hsync_pd7",
- "vi_vsync_pd6",
-};
-
-static const char * const rsvd3_groups[] = {
- "cam_i2c_scl_pbb1",
- "cam_i2c_sda_pbb2",
- "clk1_out_pw4",
- "clk1_req_pee2",
- "clk2_out_pw5",
- "clk2_req_pcc5",
- "clk3_out_pee0",
- "clk3_req_pee1",
- "clk_32k_in",
- "clk_32k_out_pa0",
- "core_pwr_req",
- "cpu_pwr_req",
- "crt_hsync_pv6",
- "crt_vsync_pv7",
- "dap2_din_pa4",
- "dap2_dout_pa5",
- "dap2_fs_pa2",
- "dap2_sclk_pa3",
- "ddc_scl_pv4",
- "ddc_sda_pv5",
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
- "pbb0",
- "pbb7",
- "pcc1",
- "pcc2",
- "pv0",
- "pv1",
- "pv2",
- "pv3",
- "hdmi_cec_pee3",
- "hdmi_int_pn7",
- "jtag_rtck_pu7",
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row2_pr2",
- "kb_row3_pr3",
- "lcd_d0_pe0",
- "lcd_d1_pe1",
- "lcd_d10_pf2",
- "lcd_d11_pf3",
- "lcd_d12_pf4",
- "lcd_d13_pf5",
- "lcd_d14_pf6",
- "lcd_d15_pf7",
- "lcd_d16_pm0",
- "lcd_d17_pm1",
- "lcd_d18_pm2",
- "lcd_d19_pm3",
- "lcd_d2_pe2",
- "lcd_d20_pm4",
- "lcd_d21_pm5",
- "lcd_d22_pm6",
- "lcd_d23_pm7",
- "lcd_d3_pe3",
- "lcd_d4_pe4",
- "lcd_d5_pe5",
- "lcd_d6_pe6",
- "lcd_d7_pe7",
- "lcd_d8_pf0",
- "lcd_d9_pf1",
- "lcd_dc0_pn6",
- "lcd_dc1_pd2",
- "lcd_de_pj1",
- "lcd_hsync_pj3",
- "lcd_m1_pw1",
- "lcd_pclk_pb3",
- "lcd_pwr1_pc1",
- "lcd_vsync_pj4",
- "owr",
- "pex_l0_clkreq_n_pdd2",
- "pex_l0_prsnt_n_pdd0",
- "pex_l0_rst_n_pdd1",
- "pex_l1_clkreq_n_pdd6",
- "pex_l1_prsnt_n_pdd4",
- "pex_l1_rst_n_pdd5",
- "pex_l2_clkreq_n_pcc7",
- "pex_l2_prsnt_n_pdd7",
- "pex_l2_rst_n_pcc6",
- "pex_wake_n_pdd3",
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
- "pwr_int_n",
- "sdmmc1_clk_pz0",
- "sdmmc1_cmd_pz1",
- "sdmmc4_rst_n_pcc3",
- "sys_clk_req_pz5",
-};
-
-static const char * const rsvd4_groups[] = {
- "clk1_out_pw4",
- "clk1_req_pee2",
- "clk2_out_pw5",
- "clk2_req_pcc5",
- "clk3_out_pee0",
- "clk3_req_pee1",
- "clk_32k_in",
- "clk_32k_out_pa0",
- "core_pwr_req",
- "cpu_pwr_req",
- "crt_hsync_pv6",
- "crt_vsync_pv7",
- "dap4_din_pp5",
- "dap4_dout_pp6",
- "dap4_fs_pp4",
- "dap4_sclk_pp7",
- "ddc_scl_pv4",
- "ddc_sda_pv5",
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
- "gmi_a19_pk7",
- "gmi_ad0_pg0",
- "gmi_ad1_pg1",
- "gmi_ad10_ph2",
- "gmi_ad11_ph3",
- "gmi_ad12_ph4",
- "gmi_ad13_ph5",
- "gmi_ad14_ph6",
- "gmi_ad15_ph7",
- "gmi_ad2_pg2",
- "gmi_ad3_pg3",
- "gmi_ad4_pg4",
- "gmi_ad5_pg5",
- "gmi_ad6_pg6",
- "gmi_ad7_pg7",
- "gmi_ad8_ph0",
- "gmi_ad9_ph1",
- "gmi_adv_n_pk0",
- "gmi_clk_pk1",
- "gmi_cs2_n_pk3",
- "gmi_cs4_n_pk2",
- "gmi_dqs_pi2",
- "gmi_iordy_pi5",
- "gmi_oe_n_pi1",
- "gmi_rst_n_pi4",
- "gmi_wait_pi7",
- "gmi_wr_n_pi0",
- "pcc2",
- "pu0",
- "pu1",
- "pu2",
- "pu3",
- "pu4",
- "pu5",
- "pu6",
- "pv0",
- "pv1",
- "pv2",
- "pv3",
- "hdmi_cec_pee3",
- "hdmi_int_pn7",
- "jtag_rtck_pu7",
- "kb_col2_pq2",
- "kb_col3_pq3",
- "kb_col4_pq4",
- "kb_col5_pq5",
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row2_pr2",
- "kb_row4_pr4",
- "lcd_cs0_n_pn4",
- "lcd_cs1_n_pw0",
- "lcd_d0_pe0",
- "lcd_d1_pe1",
- "lcd_d10_pf2",
- "lcd_d11_pf3",
- "lcd_d12_pf4",
- "lcd_d13_pf5",
- "lcd_d14_pf6",
- "lcd_d15_pf7",
- "lcd_d16_pm0",
- "lcd_d17_pm1",
- "lcd_d18_pm2",
- "lcd_d19_pm3",
- "lcd_d2_pe2",
- "lcd_d20_pm4",
- "lcd_d21_pm5",
- "lcd_d22_pm6",
- "lcd_d23_pm7",
- "lcd_d3_pe3",
- "lcd_d4_pe4",
- "lcd_d5_pe5",
- "lcd_d6_pe6",
- "lcd_d7_pe7",
- "lcd_d8_pf0",
- "lcd_d9_pf1",
- "lcd_dc0_pn6",
- "lcd_dc1_pd2",
- "lcd_de_pj1",
- "lcd_hsync_pj3",
- "lcd_m1_pw1",
- "lcd_pclk_pb3",
- "lcd_pwr1_pc1",
- "lcd_sdin_pz2",
- "lcd_vsync_pj4",
- "owr",
- "pex_l0_clkreq_n_pdd2",
- "pex_l0_prsnt_n_pdd0",
- "pex_l0_rst_n_pdd1",
- "pex_l1_clkreq_n_pdd6",
- "pex_l1_prsnt_n_pdd4",
- "pex_l1_rst_n_pdd5",
- "pex_l2_clkreq_n_pcc7",
- "pex_l2_prsnt_n_pdd7",
- "pex_l2_rst_n_pcc6",
- "pex_wake_n_pdd3",
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
- "pwr_int_n",
- "spi1_miso_px7",
- "sys_clk_req_pz5",
- "uart3_cts_n_pa1",
- "uart3_rts_n_pc0",
- "uart3_rxd_pw7",
- "uart3_txd_pw6",
- "vi_d0_pt4",
- "vi_d1_pd5",
- "vi_d10_pt2",
- "vi_d11_pt3",
- "vi_d2_pl0",
- "vi_d3_pl1",
- "vi_d4_pl2",
- "vi_d5_pl3",
- "vi_d6_pl4",
- "vi_d7_pl5",
- "vi_d8_pl6",
- "vi_d9_pl7",
- "vi_hsync_pd7",
- "vi_pclk_pt0",
- "vi_vsync_pd6",
-};
-
-static const char * const rtck_groups[] = {
- "jtag_rtck_pu7",
-};
-
-static const char * const sata_groups[] = {
- "gmi_cs6_n_pi3",
-};
-
-static const char * const sdmmc1_groups[] = {
- "sdmmc1_clk_pz0",
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat0_py7",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat3_py4",
-};
-
-static const char * const sdmmc2_groups[] = {
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_fs_pn0",
- "dap1_sclk_pn3",
- "kb_row10_ps2",
- "kb_row11_ps3",
- "kb_row12_ps4",
- "kb_row13_ps5",
- "kb_row14_ps6",
- "kb_row15_ps7",
- "kb_row6_pr6",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "kb_row9_ps1",
- "spdif_in_pk6",
- "spdif_out_pk5",
- "vi_d1_pd5",
- "vi_d2_pl0",
- "vi_d3_pl1",
- "vi_d4_pl2",
- "vi_d5_pl3",
- "vi_d6_pl4",
- "vi_d7_pl5",
- "vi_d8_pl6",
- "vi_d9_pl7",
- "vi_pclk_pt0",
-};
-
-static const char * const sdmmc3_groups[] = {
- "sdmmc3_clk_pa6",
- "sdmmc3_cmd_pa7",
- "sdmmc3_dat0_pb7",
- "sdmmc3_dat1_pb6",
- "sdmmc3_dat2_pb5",
- "sdmmc3_dat3_pb4",
- "sdmmc3_dat4_pd1",
- "sdmmc3_dat5_pd0",
- "sdmmc3_dat6_pd3",
- "sdmmc3_dat7_pd4",
-};
-
-static const char * const sdmmc4_groups[] = {
- "cam_i2c_scl_pbb1",
- "cam_i2c_sda_pbb2",
- "cam_mclk_pcc0",
- "pbb0",
- "pbb3",
- "pbb4",
- "pbb5",
- "pbb6",
- "pbb7",
- "pcc1",
- "sdmmc4_clk_pcc4",
- "sdmmc4_cmd_pt7",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc4_dat7_paa7",
- "sdmmc4_rst_n_pcc3",
-};
-
-static const char * const spdif_groups[] = {
- "sdmmc3_dat6_pd3",
- "sdmmc3_dat7_pd4",
- "spdif_in_pk6",
- "spdif_out_pk5",
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
-};
-
-static const char * const spi1_groups[] = {
- "spi1_cs0_n_px6",
- "spi1_miso_px7",
- "spi1_mosi_px4",
- "spi1_sck_px5",
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
-};
-
-static const char * const spi2_groups[] = {
- "sdmmc3_cmd_pa7",
- "sdmmc3_dat4_pd1",
- "sdmmc3_dat5_pd0",
- "sdmmc3_dat6_pd3",
- "sdmmc3_dat7_pd4",
- "spi1_cs0_n_px6",
- "spi1_mosi_px4",
- "spi1_sck_px5",
- "spi2_cs0_n_px3",
- "spi2_cs1_n_pw2",
- "spi2_cs2_n_pw3",
- "spi2_miso_px1",
- "spi2_mosi_px0",
- "spi2_sck_px2",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
-};
-
-static const char * const spi2_alt_groups[] = {
- "spi1_cs0_n_px6",
- "spi1_miso_px7",
- "spi1_mosi_px4",
- "spi1_sck_px5",
- "spi2_cs1_n_pw2",
- "spi2_cs2_n_pw3",
-};
-
-static const char * const spi3_groups[] = {
- "sdmmc3_clk_pa6",
- "sdmmc3_dat0_pb7",
- "sdmmc3_dat1_pb6",
- "sdmmc3_dat2_pb5",
- "sdmmc3_dat3_pb4",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "spi1_miso_px7",
- "spi2_cs0_n_px3",
- "spi2_cs1_n_pw2",
- "spi2_cs2_n_pw3",
- "spi2_miso_px1",
- "spi2_mosi_px0",
- "spi2_sck_px2",
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
-};
-
-static const char * const spi4_groups[] = {
- "gmi_a16_pj7",
- "gmi_a17_pb0",
- "gmi_a18_pb1",
- "gmi_a19_pk7",
- "sdmmc3_dat4_pd1",
- "sdmmc3_dat5_pd0",
- "sdmmc3_dat6_pd3",
- "sdmmc3_dat7_pd4",
- "uart2_cts_n_pj5",
- "uart2_rts_n_pj6",
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
-};
-
-static const char * const spi5_groups[] = {
- "lcd_cs0_n_pn4",
- "lcd_cs1_n_pw0",
- "lcd_pwr0_pb2",
- "lcd_pwr2_pc6",
- "lcd_sck_pz4",
- "lcd_sdin_pz2",
- "lcd_sdout_pn5",
- "lcd_wr_n_pz3",
-};
-
-static const char * const spi6_groups[] = {
- "spi2_cs0_n_px3",
- "spi2_miso_px1",
- "spi2_mosi_px0",
- "spi2_sck_px2",
-};
-
-static const char * const sysclk_groups[] = {
- "sys_clk_req_pz5",
-};
-
-static const char * const test_groups[] = {
- "kb_col0_pq0",
- "kb_col1_pq1",
-};
-
-static const char * const trace_groups[] = {
- "kb_col0_pq0",
- "kb_col1_pq1",
- "kb_col2_pq2",
- "kb_col3_pq3",
- "kb_col4_pq4",
- "kb_col5_pq5",
- "kb_col6_pq6",
- "kb_col7_pq7",
- "kb_row4_pr4",
- "kb_row5_pr5",
-};
-
-static const char * const uarta_groups[] = {
- "pu0",
- "pu1",
- "pu2",
- "pu3",
- "pu4",
- "pu5",
- "pu6",
- "sdmmc1_clk_pz0",
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat0_py7",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat3_py4",
- "sdmmc3_clk_pa6",
- "sdmmc3_cmd_pa7",
- "uart2_cts_n_pj5",
- "uart2_rts_n_pj6",
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
-};
-
-static const char * const uartb_groups[] = {
- "uart2_cts_n_pj5",
- "uart2_rts_n_pj6",
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
-};
-
-static const char * const uartc_groups[] = {
- "uart3_cts_n_pa1",
- "uart3_rts_n_pc0",
- "uart3_rxd_pw7",
- "uart3_txd_pw6",
-};
-
-static const char * const uartd_groups[] = {
- "gmi_a16_pj7",
- "gmi_a17_pb0",
- "gmi_a18_pb1",
- "gmi_a19_pk7",
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
-};
-
-static const char * const uarte_groups[] = {
- "sdmmc1_dat0_py7",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat3_py4",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
-};
-
-static const char * const ulpi_groups[] = {
- "ulpi_clk_py0",
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
-};
-
-static const char * const vgp1_groups[] = {
- "cam_i2c_scl_pbb1",
-};
-
-static const char * const vgp2_groups[] = {
- "cam_i2c_sda_pbb2",
-};
-
-static const char * const vgp3_groups[] = {
- "pbb3",
- "sdmmc4_dat5_paa5",
-};
-
-static const char * const vgp4_groups[] = {
- "pbb4",
- "sdmmc4_dat6_paa6",
-};
-
-static const char * const vgp5_groups[] = {
- "pbb5",
- "sdmmc4_dat7_paa7",
-};
-
-static const char * const vgp6_groups[] = {
- "pbb6",
- "sdmmc4_rst_n_pcc3",
-};
-
-static const char * const vi_groups[] = {
- "cam_mclk_pcc0",
- "vi_d0_pt4",
- "vi_d1_pd5",
- "vi_d10_pt2",
- "vi_d11_pt3",
- "vi_d2_pl0",
- "vi_d3_pl1",
- "vi_d4_pl2",
- "vi_d5_pl3",
- "vi_d6_pl4",
- "vi_d7_pl5",
- "vi_d8_pl6",
- "vi_d9_pl7",
- "vi_hsync_pd7",
- "vi_mclk_pt1",
- "vi_pclk_pt0",
- "vi_vsync_pd6",
-};
-
-static const char * const vi_alt1_groups[] = {
- "cam_mclk_pcc0",
- "vi_mclk_pt1",
-};
-
-static const char * const vi_alt2_groups[] = {
- "vi_mclk_pt1",
-};
-
-static const char * const vi_alt3_groups[] = {
- "cam_mclk_pcc0",
- "vi_mclk_pt1",
-};
#define FUNCTION(fname) \
{ \
.name = #fname, \
- .groups = fname##_groups, \
- .ngroups = ARRAY_SIZE(fname##_groups), \
}
-static const struct tegra_function tegra30_functions[] = {
+static struct tegra_function tegra30_functions[] = {
FUNCTION(blink),
FUNCTION(cec),
FUNCTION(clk_12m_out),
@@ -3345,11 +2105,11 @@ static const struct tegra_function tegra30_functions[] = {
FUNCTION(vi_alt3),
};
-#define DRV_PINGROUP_REG_A 0x868 /* bank 0 */
-#define PINGROUP_REG_A 0x3000 /* bank 1 */
+#define DRV_PINGROUP_REG_A 0x868 /* bank 0 */
+#define PINGROUP_REG_A 0x3000 /* bank 1 */
-#define PINGROUP_REG_Y(r) ((r) - PINGROUP_REG_A)
-#define PINGROUP_REG_N(r) -1
+#define PINGROUP_REG_Y(r) ((r) - PINGROUP_REG_A)
+#define PINGROUP_REG_N(r) -1
#define PINGROUP(pg_name, f0, f1, f2, f3, f_safe, r, od, ior) \
{ \
@@ -3357,12 +2117,12 @@ static const struct tegra_function tegra30_functions[] = {
.pins = pg_name##_pins, \
.npins = ARRAY_SIZE(pg_name##_pins), \
.funcs = { \
- TEGRA_MUX_ ## f0, \
- TEGRA_MUX_ ## f1, \
- TEGRA_MUX_ ## f2, \
- TEGRA_MUX_ ## f3, \
+ TEGRA_MUX_##f0, \
+ TEGRA_MUX_##f1, \
+ TEGRA_MUX_##f2, \
+ TEGRA_MUX_##f3, \
}, \
- .func_safe = TEGRA_MUX_ ## f_safe, \
+ .func_safe = TEGRA_MUX_##f_safe, \
.mux_reg = PINGROUP_REG_Y(r), \
.mux_bank = 1, \
.mux_bit = 0, \
@@ -3389,6 +2149,9 @@ static const struct tegra_function tegra30_functions[] = {
.drvtype_reg = -1, \
}
+#define DRV_PINGROUP_REG_Y(r) ((r) - DRV_PINGROUP_REG_A)
+#define DRV_PINGROUP_REG_N(r) -1
+
#define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b, \
drvdn_b, drvdn_w, drvup_b, drvup_w, \
slwr_b, slwr_w, slwf_b, slwf_w) \
@@ -3404,7 +2167,7 @@ static const struct tegra_function tegra30_functions[] = {
.lock_reg = -1, \
.ioreset_reg = -1, \
.rcv_sel_reg = -1, \
- .drv_reg = ((r) - DRV_PINGROUP_REG_A), \
+ .drv_reg = DRV_PINGROUP_REG_Y(r), \
.drv_bank = 0, \
.hsm_bit = hsm_b, \
.schmitt_bit = schmitt_b, \
@@ -3422,7 +2185,6 @@ static const struct tegra_function tegra30_functions[] = {
static const struct tegra_pingroup tegra30_groups[] = {
/* pg_name, f0, f1, f2, f3, safe, r, od, ior */
- /* FIXME: Fill in correct data in safe column */
PINGROUP(clk_32k_out_pa0, BLINK, RSVD2, RSVD3, RSVD4, RSVD4, 0x331c, N, N),
PINGROUP(uart3_cts_n_pa1, UARTC, RSVD2, GMI, RSVD4, RSVD4, 0x317c, N, N),
PINGROUP(dap2_fs_pa2, I2S1, HDA, RSVD3, GMI, RSVD3, 0x3358, N, N),
@@ -3735,6 +2497,7 @@ static struct of_device_id tegra30_pinctrl_of_match[] = {
{ .compatible = "nvidia,tegra30-pinmux", },
{ },
};
+MODULE_DEVICE_TABLE(of, tegra30_pinctrl_of_match);
static struct platform_driver tegra30_pinctrl_driver = {
.driver = {
@@ -3745,20 +2508,8 @@ static struct platform_driver tegra30_pinctrl_driver = {
.probe = tegra30_pinctrl_probe,
.remove = tegra_pinctrl_remove,
};
-
-static int __init tegra30_pinctrl_init(void)
-{
- return platform_driver_register(&tegra30_pinctrl_driver);
-}
-arch_initcall(tegra30_pinctrl_init);
-
-static void __exit tegra30_pinctrl_exit(void)
-{
- platform_driver_unregister(&tegra30_pinctrl_driver);
-}
-module_exit(tegra30_pinctrl_exit);
+module_platform_driver(tegra30_pinctrl_driver);
MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
MODULE_DESCRIPTION("NVIDIA Tegra30 pinctrl driver");
MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, tegra30_pinctrl_of_match);
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
index c381ae63c508..48093719167a 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
@@ -2260,6 +2260,42 @@ static const unsigned int msiof0_tx_pins[] = {
static const unsigned int msiof0_tx_mux[] = {
MSIOF0_TXD_MARK,
};
+
+static const unsigned int msiof0_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(1, 23),
+};
+static const unsigned int msiof0_clk_b_mux[] = {
+ MSIOF0_SCK_B_MARK,
+};
+static const unsigned int msiof0_ss1_b_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(1, 12),
+};
+static const unsigned int msiof0_ss1_b_mux[] = {
+ MSIOF0_SS1_B_MARK,
+};
+static const unsigned int msiof0_ss2_b_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(1, 10),
+};
+static const unsigned int msiof0_ss2_b_mux[] = {
+ MSIOF0_SS2_B_MARK,
+};
+static const unsigned int msiof0_rx_b_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(1, 29),
+};
+static const unsigned int msiof0_rx_b_mux[] = {
+ MSIOF0_RXD_B_MARK,
+};
+static const unsigned int msiof0_tx_b_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(1, 28),
+};
+static const unsigned int msiof0_tx_b_mux[] = {
+ MSIOF0_TXD_B_MARK,
+};
/* - MSIOF1 ----------------------------------------------------------------- */
static const unsigned int msiof1_clk_pins[] = {
/* SCK */
@@ -2303,6 +2339,42 @@ static const unsigned int msiof1_tx_pins[] = {
static const unsigned int msiof1_tx_mux[] = {
MSIOF1_TXD_MARK,
};
+
+static const unsigned int msiof1_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(1, 16),
+};
+static const unsigned int msiof1_clk_b_mux[] = {
+ MSIOF1_SCK_B_MARK,
+};
+static const unsigned int msiof1_ss1_b_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(0, 18),
+};
+static const unsigned int msiof1_ss1_b_mux[] = {
+ MSIOF1_SS1_B_MARK,
+};
+static const unsigned int msiof1_ss2_b_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(0, 19),
+};
+static const unsigned int msiof1_ss2_b_mux[] = {
+ MSIOF1_SS2_B_MARK,
+};
+static const unsigned int msiof1_rx_b_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(1, 17),
+};
+static const unsigned int msiof1_rx_b_mux[] = {
+ MSIOF1_RXD_B_MARK,
+};
+static const unsigned int msiof1_tx_b_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(0, 20),
+};
+static const unsigned int msiof1_tx_b_mux[] = {
+ MSIOF1_TXD_B_MARK,
+};
/* - MSIOF2 ----------------------------------------------------------------- */
static const unsigned int msiof2_clk_pins[] = {
/* SCK */
@@ -2389,6 +2461,58 @@ static const unsigned int msiof3_tx_pins[] = {
static const unsigned int msiof3_tx_mux[] = {
MSIOF3_TXD_MARK,
};
+
+static const unsigned int msiof3_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(0, 0),
+};
+static const unsigned int msiof3_clk_b_mux[] = {
+ MSIOF3_SCK_B_MARK,
+};
+static const unsigned int msiof3_sync_b_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(0, 1),
+};
+static const unsigned int msiof3_sync_b_mux[] = {
+ MSIOF3_SYNC_B_MARK,
+};
+static const unsigned int msiof3_rx_b_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(0, 2),
+};
+static const unsigned int msiof3_rx_b_mux[] = {
+ MSIOF3_RXD_B_MARK,
+};
+static const unsigned int msiof3_tx_b_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(0, 3),
+};
+static const unsigned int msiof3_tx_b_mux[] = {
+ MSIOF3_TXD_B_MARK,
+};
+/* - QSPI ------------------------------------------------------------------- */
+static const unsigned int qspi_ctrl_pins[] = {
+ /* SPCLK, SSL */
+ RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 9),
+};
+static const unsigned int qspi_ctrl_mux[] = {
+ SPCLK_MARK, SSL_MARK,
+};
+static const unsigned int qspi_data2_pins[] = {
+ /* MOSI_IO0, MISO_IO1 */
+ RCAR_GP_PIN(1, 5), RCAR_GP_PIN(1, 6),
+};
+static const unsigned int qspi_data2_mux[] = {
+ MOSI_IO0_MARK, MISO_IO1_MARK,
+};
+static const unsigned int qspi_data4_pins[] = {
+ /* MOSI_IO0, MISO_IO1, IO2, IO3 */
+ RCAR_GP_PIN(1, 5), RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 7),
+ RCAR_GP_PIN(1, 8),
+};
+static const unsigned int qspi_data4_mux[] = {
+ MOSI_IO0_MARK, MISO_IO1_MARK, IO2_MARK, IO3_MARK,
+};
/* - SCIF0 ------------------------------------------------------------------ */
static const unsigned int scif0_data_pins[] = {
/* RX, TX */
@@ -3231,6 +3355,13 @@ static const unsigned int usb0_pins[] = {
static const unsigned int usb0_mux[] = {
USB0_PWEN_MARK, USB0_OVC_VBUS_MARK,
};
+static const unsigned int usb0_ovc_vbus_pins[] = {
+ /* OVC/VBUS */
+ RCAR_GP_PIN(5, 19),
+};
+static const unsigned int usb0_ovc_vbus_mux[] = {
+ USB0_OVC_VBUS_MARK,
+};
/* - USB1 ------------------------------------------------------------------- */
static const unsigned int usb1_pins[] = {
/* PWEN, OVC */
@@ -3653,12 +3784,22 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(msiof0_ss2),
SH_PFC_PIN_GROUP(msiof0_rx),
SH_PFC_PIN_GROUP(msiof0_tx),
+ SH_PFC_PIN_GROUP(msiof0_clk_b),
+ SH_PFC_PIN_GROUP(msiof0_ss1_b),
+ SH_PFC_PIN_GROUP(msiof0_ss2_b),
+ SH_PFC_PIN_GROUP(msiof0_rx_b),
+ SH_PFC_PIN_GROUP(msiof0_tx_b),
SH_PFC_PIN_GROUP(msiof1_clk),
SH_PFC_PIN_GROUP(msiof1_sync),
SH_PFC_PIN_GROUP(msiof1_ss1),
SH_PFC_PIN_GROUP(msiof1_ss2),
SH_PFC_PIN_GROUP(msiof1_rx),
SH_PFC_PIN_GROUP(msiof1_tx),
+ SH_PFC_PIN_GROUP(msiof1_clk_b),
+ SH_PFC_PIN_GROUP(msiof1_ss1_b),
+ SH_PFC_PIN_GROUP(msiof1_ss2_b),
+ SH_PFC_PIN_GROUP(msiof1_rx_b),
+ SH_PFC_PIN_GROUP(msiof1_tx_b),
SH_PFC_PIN_GROUP(msiof2_clk),
SH_PFC_PIN_GROUP(msiof2_sync),
SH_PFC_PIN_GROUP(msiof2_ss1),
@@ -3671,6 +3812,13 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(msiof3_ss2),
SH_PFC_PIN_GROUP(msiof3_rx),
SH_PFC_PIN_GROUP(msiof3_tx),
+ SH_PFC_PIN_GROUP(msiof3_clk_b),
+ SH_PFC_PIN_GROUP(msiof3_sync_b),
+ SH_PFC_PIN_GROUP(msiof3_rx_b),
+ SH_PFC_PIN_GROUP(msiof3_tx_b),
+ SH_PFC_PIN_GROUP(qspi_ctrl),
+ SH_PFC_PIN_GROUP(qspi_data2),
+ SH_PFC_PIN_GROUP(qspi_data4),
SH_PFC_PIN_GROUP(scif0_data),
SH_PFC_PIN_GROUP(scif0_clk),
SH_PFC_PIN_GROUP(scif0_ctrl),
@@ -3789,6 +3937,7 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(tpu0_to2),
SH_PFC_PIN_GROUP(tpu0_to3),
SH_PFC_PIN_GROUP(usb0),
+ SH_PFC_PIN_GROUP(usb0_ovc_vbus),
SH_PFC_PIN_GROUP(usb1),
SH_PFC_PIN_GROUP(usb2),
VIN_DATA_PIN_GROUP(vin0_data, 24),
@@ -3941,6 +4090,11 @@ static const char * const msiof0_groups[] = {
"msiof0_ss2",
"msiof0_rx",
"msiof0_tx",
+ "msiof0_clk_b",
+ "msiof0_ss1_b",
+ "msiof0_ss2_b",
+ "msiof0_rx_b",
+ "msiof0_tx_b",
};
static const char * const msiof1_groups[] = {
@@ -3950,6 +4104,11 @@ static const char * const msiof1_groups[] = {
"msiof1_ss2",
"msiof1_rx",
"msiof1_tx",
+ "msiof1_clk_b",
+ "msiof1_ss1_b",
+ "msiof1_ss2_b",
+ "msiof1_rx_b",
+ "msiof1_tx_b",
};
static const char * const msiof2_groups[] = {
@@ -3968,6 +4127,16 @@ static const char * const msiof3_groups[] = {
"msiof3_ss2",
"msiof3_rx",
"msiof3_tx",
+ "msiof3_clk_b",
+ "msiof3_sync_b",
+ "msiof3_rx_b",
+ "msiof3_tx_b",
+};
+
+static const char * const qspi_groups[] = {
+ "qspi_ctrl",
+ "qspi_data2",
+ "qspi_data4",
};
static const char * const scif0_groups[] = {
@@ -4134,6 +4303,7 @@ static const char * const tpu0_groups[] = {
static const char * const usb0_groups[] = {
"usb0",
+ "usb0_ovc_vbus",
};
static const char * const usb1_groups[] = {
@@ -4213,6 +4383,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(msiof1),
SH_PFC_FUNCTION(msiof2),
SH_PFC_FUNCTION(msiof3),
+ SH_PFC_FUNCTION(qspi),
SH_PFC_FUNCTION(scif0),
SH_PFC_FUNCTION(scif1),
SH_PFC_FUNCTION(scif2),
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
index 77d103fe39d9..5186d70c49d4 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
@@ -89,7 +89,8 @@ enum {
/* GPSR6 */
FN_IP13_10, FN_IP13_11, FN_IP13_12, FN_IP13_13, FN_IP13_14,
- FN_IP13_15, FN_IP13_18_16, FN_IP13_21_19, FN_IP13_22, FN_IP13_24_23,
+ FN_IP13_15, FN_IP13_18_16, FN_IP13_21_19,
+ FN_IP13_22, FN_IP13_24_23, FN_SD1_CLK,
FN_IP13_25, FN_IP13_26, FN_IP13_27, FN_IP13_30_28, FN_IP14_1_0,
FN_IP14_2, FN_IP14_3, FN_IP14_4, FN_IP14_5, FN_IP14_6, FN_IP14_7,
FN_IP14_10_8, FN_IP14_13_11, FN_IP14_16_14, FN_IP14_19_17,
@@ -788,6 +789,7 @@ static const u16 pinmux_data[] = {
PINMUX_DATA(USB1_PWEN_MARK, FN_USB1_PWEN),
PINMUX_DATA(USB1_OVC_MARK, FN_USB1_OVC),
PINMUX_DATA(DU0_DOTCLKIN_MARK, FN_DU0_DOTCLKIN),
+ PINMUX_DATA(SD1_CLK_MARK, FN_SD1_CLK),
/* IPSR0 */
PINMUX_IPSR_DATA(IP0_0, D0),
@@ -1943,6 +1945,50 @@ static const unsigned int i2c4_c_pins[] = {
static const unsigned int i2c4_c_mux[] = {
SCL4_C_MARK, SDA4_C_MARK,
};
+/* - I2C7 ------------------------------------------------------------------- */
+static const unsigned int i2c7_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(5, 15), RCAR_GP_PIN(5, 16),
+};
+static const unsigned int i2c7_mux[] = {
+ SCL7_MARK, SDA7_MARK,
+};
+static const unsigned int i2c7_b_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(2, 2), RCAR_GP_PIN(2, 3),
+};
+static const unsigned int i2c7_b_mux[] = {
+ SCL7_B_MARK, SDA7_B_MARK,
+};
+static const unsigned int i2c7_c_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(6, 28), RCAR_GP_PIN(6, 29),
+};
+static const unsigned int i2c7_c_mux[] = {
+ SCL7_C_MARK, SDA7_C_MARK,
+};
+/* - I2C8 ------------------------------------------------------------------- */
+static const unsigned int i2c8_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(4, 13), RCAR_GP_PIN(4, 14),
+};
+static const unsigned int i2c8_mux[] = {
+ SCL8_MARK, SDA8_MARK,
+};
+static const unsigned int i2c8_b_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(2, 4), RCAR_GP_PIN(2, 5),
+};
+static const unsigned int i2c8_b_mux[] = {
+ SCL8_B_MARK, SDA8_B_MARK,
+};
+static const unsigned int i2c8_c_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(6, 22), RCAR_GP_PIN(6, 23),
+};
+static const unsigned int i2c8_c_mux[] = {
+ SCL8_C_MARK, SDA8_C_MARK,
+};
/* - INTC ------------------------------------------------------------------- */
static const unsigned int intc_irq0_pins[] = {
/* IRQ */
@@ -2049,6 +2095,92 @@ static const unsigned int msiof0_tx_pins[] = {
static const unsigned int msiof0_tx_mux[] = {
MSIOF0_TXD_MARK,
};
+
+static const unsigned int msiof0_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(0, 16),
+};
+static const unsigned int msiof0_clk_b_mux[] = {
+ MSIOF0_SCK_B_MARK,
+};
+static const unsigned int msiof0_sync_b_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(0, 17),
+};
+static const unsigned int msiof0_sync_b_mux[] = {
+ MSIOF0_SYNC_B_MARK,
+};
+static const unsigned int msiof0_ss1_b_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(0, 18),
+};
+static const unsigned int msiof0_ss1_b_mux[] = {
+ MSIOF0_SS1_B_MARK,
+};
+static const unsigned int msiof0_ss2_b_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(0, 19),
+};
+static const unsigned int msiof0_ss2_b_mux[] = {
+ MSIOF0_SS2_B_MARK,
+};
+static const unsigned int msiof0_rx_b_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(0, 21),
+};
+static const unsigned int msiof0_rx_b_mux[] = {
+ MSIOF0_RXD_B_MARK,
+};
+static const unsigned int msiof0_tx_b_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(0, 20),
+};
+static const unsigned int msiof0_tx_b_mux[] = {
+ MSIOF0_TXD_B_MARK,
+};
+
+static const unsigned int msiof0_clk_c_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(5, 26),
+};
+static const unsigned int msiof0_clk_c_mux[] = {
+ MSIOF0_SCK_C_MARK,
+};
+static const unsigned int msiof0_sync_c_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(5, 25),
+};
+static const unsigned int msiof0_sync_c_mux[] = {
+ MSIOF0_SYNC_C_MARK,
+};
+static const unsigned int msiof0_ss1_c_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(5, 27),
+};
+static const unsigned int msiof0_ss1_c_mux[] = {
+ MSIOF0_SS1_C_MARK,
+};
+static const unsigned int msiof0_ss2_c_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(5, 28),
+};
+static const unsigned int msiof0_ss2_c_mux[] = {
+ MSIOF0_SS2_C_MARK,
+};
+static const unsigned int msiof0_rx_c_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(5, 29),
+};
+static const unsigned int msiof0_rx_c_mux[] = {
+ MSIOF0_RXD_C_MARK,
+};
+static const unsigned int msiof0_tx_c_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(5, 30),
+};
+static const unsigned int msiof0_tx_c_mux[] = {
+ MSIOF0_TXD_C_MARK,
+};
/* - MSIOF1 ----------------------------------------------------------------- */
static const unsigned int msiof1_clk_pins[] = {
/* SCK */
@@ -2092,6 +2224,143 @@ static const unsigned int msiof1_tx_pins[] = {
static const unsigned int msiof1_tx_mux[] = {
MSIOF1_TXD_MARK,
};
+
+static const unsigned int msiof1_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(2, 29),
+};
+static const unsigned int msiof1_clk_b_mux[] = {
+ MSIOF1_SCK_B_MARK,
+};
+static const unsigned int msiof1_sync_b_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(2, 30),
+};
+static const unsigned int msiof1_sync_b_mux[] = {
+ MSIOF1_SYNC_B_MARK,
+};
+static const unsigned int msiof1_ss1_b_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(2, 31),
+};
+static const unsigned int msiof1_ss1_b_mux[] = {
+ MSIOF1_SS1_B_MARK,
+};
+static const unsigned int msiof1_ss2_b_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(7, 16),
+};
+static const unsigned int msiof1_ss2_b_mux[] = {
+ MSIOF1_SS2_B_MARK,
+};
+static const unsigned int msiof1_rx_b_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(7, 18),
+};
+static const unsigned int msiof1_rx_b_mux[] = {
+ MSIOF1_RXD_B_MARK,
+};
+static const unsigned int msiof1_tx_b_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(7, 17),
+};
+static const unsigned int msiof1_tx_b_mux[] = {
+ MSIOF1_TXD_B_MARK,
+};
+
+static const unsigned int msiof1_clk_c_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(2, 15),
+};
+static const unsigned int msiof1_clk_c_mux[] = {
+ MSIOF1_SCK_C_MARK,
+};
+static const unsigned int msiof1_sync_c_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(2, 16),
+};
+static const unsigned int msiof1_sync_c_mux[] = {
+ MSIOF1_SYNC_C_MARK,
+};
+static const unsigned int msiof1_rx_c_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(2, 18),
+};
+static const unsigned int msiof1_rx_c_mux[] = {
+ MSIOF1_RXD_C_MARK,
+};
+static const unsigned int msiof1_tx_c_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(2, 17),
+};
+static const unsigned int msiof1_tx_c_mux[] = {
+ MSIOF1_TXD_C_MARK,
+};
+
+static const unsigned int msiof1_clk_d_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(0, 28),
+};
+static const unsigned int msiof1_clk_d_mux[] = {
+ MSIOF1_SCK_D_MARK,
+};
+static const unsigned int msiof1_sync_d_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(0, 30),
+};
+static const unsigned int msiof1_sync_d_mux[] = {
+ MSIOF1_SYNC_D_MARK,
+};
+static const unsigned int msiof1_ss1_d_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(0, 29),
+};
+static const unsigned int msiof1_ss1_d_mux[] = {
+ MSIOF1_SS1_D_MARK,
+};
+static const unsigned int msiof1_rx_d_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(0, 27),
+};
+static const unsigned int msiof1_rx_d_mux[] = {
+ MSIOF1_RXD_D_MARK,
+};
+static const unsigned int msiof1_tx_d_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(0, 26),
+};
+static const unsigned int msiof1_tx_d_mux[] = {
+ MSIOF1_TXD_D_MARK,
+};
+
+static const unsigned int msiof1_clk_e_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(5, 18),
+};
+static const unsigned int msiof1_clk_e_mux[] = {
+ MSIOF1_SCK_E_MARK,
+};
+static const unsigned int msiof1_sync_e_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(5, 19),
+};
+static const unsigned int msiof1_sync_e_mux[] = {
+ MSIOF1_SYNC_E_MARK,
+};
+static const unsigned int msiof1_rx_e_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(5, 17),
+};
+static const unsigned int msiof1_rx_e_mux[] = {
+ MSIOF1_RXD_E_MARK,
+};
+static const unsigned int msiof1_tx_e_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(5, 20),
+};
+static const unsigned int msiof1_tx_e_mux[] = {
+ MSIOF1_TXD_E_MARK,
+};
/* - MSIOF2 ----------------------------------------------------------------- */
static const unsigned int msiof2_clk_pins[] = {
/* SCK */
@@ -2135,6 +2404,197 @@ static const unsigned int msiof2_tx_pins[] = {
static const unsigned int msiof2_tx_mux[] = {
MSIOF2_TXD_MARK,
};
+
+static const unsigned int msiof2_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(3, 0),
+};
+static const unsigned int msiof2_clk_b_mux[] = {
+ MSIOF2_SCK_B_MARK,
+};
+static const unsigned int msiof2_sync_b_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(3, 1),
+};
+static const unsigned int msiof2_sync_b_mux[] = {
+ MSIOF2_SYNC_B_MARK,
+};
+static const unsigned int msiof2_ss1_b_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(3, 8),
+};
+static const unsigned int msiof2_ss1_b_mux[] = {
+ MSIOF2_SS1_B_MARK,
+};
+static const unsigned int msiof2_ss2_b_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(3, 9),
+};
+static const unsigned int msiof2_ss2_b_mux[] = {
+ MSIOF2_SS2_B_MARK,
+};
+static const unsigned int msiof2_rx_b_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(3, 17),
+};
+static const unsigned int msiof2_rx_b_mux[] = {
+ MSIOF2_RXD_B_MARK,
+};
+static const unsigned int msiof2_tx_b_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(3, 16),
+};
+static const unsigned int msiof2_tx_b_mux[] = {
+ MSIOF2_TXD_B_MARK,
+};
+
+static const unsigned int msiof2_clk_c_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(2, 2),
+};
+static const unsigned int msiof2_clk_c_mux[] = {
+ MSIOF2_SCK_C_MARK,
+};
+static const unsigned int msiof2_sync_c_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(2, 3),
+};
+static const unsigned int msiof2_sync_c_mux[] = {
+ MSIOF2_SYNC_C_MARK,
+};
+static const unsigned int msiof2_rx_c_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(2, 5),
+};
+static const unsigned int msiof2_rx_c_mux[] = {
+ MSIOF2_RXD_C_MARK,
+};
+static const unsigned int msiof2_tx_c_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(2, 4),
+};
+static const unsigned int msiof2_tx_c_mux[] = {
+ MSIOF2_TXD_C_MARK,
+};
+
+static const unsigned int msiof2_clk_d_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(2, 14),
+};
+static const unsigned int msiof2_clk_d_mux[] = {
+ MSIOF2_SCK_D_MARK,
+};
+static const unsigned int msiof2_sync_d_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(2, 15),
+};
+static const unsigned int msiof2_sync_d_mux[] = {
+ MSIOF2_SYNC_D_MARK,
+};
+static const unsigned int msiof2_ss1_d_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(2, 17),
+};
+static const unsigned int msiof2_ss1_d_mux[] = {
+ MSIOF2_SS1_D_MARK,
+};
+static const unsigned int msiof2_ss2_d_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(2, 19),
+};
+static const unsigned int msiof2_ss2_d_mux[] = {
+ MSIOF2_SS2_D_MARK,
+};
+static const unsigned int msiof2_rx_d_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(2, 18),
+};
+static const unsigned int msiof2_rx_d_mux[] = {
+ MSIOF2_RXD_D_MARK,
+};
+static const unsigned int msiof2_tx_d_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(2, 16),
+};
+static const unsigned int msiof2_tx_d_mux[] = {
+ MSIOF2_TXD_D_MARK,
+};
+
+static const unsigned int msiof2_clk_e_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(7, 15),
+};
+static const unsigned int msiof2_clk_e_mux[] = {
+ MSIOF2_SCK_E_MARK,
+};
+static const unsigned int msiof2_sync_e_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(7, 16),
+};
+static const unsigned int msiof2_sync_e_mux[] = {
+ MSIOF2_SYNC_E_MARK,
+};
+static const unsigned int msiof2_rx_e_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(7, 14),
+};
+static const unsigned int msiof2_rx_e_mux[] = {
+ MSIOF2_RXD_E_MARK,
+};
+static const unsigned int msiof2_tx_e_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(7, 13),
+};
+static const unsigned int msiof2_tx_e_mux[] = {
+ MSIOF2_TXD_E_MARK,
+};
+/* - QSPI ------------------------------------------------------------------- */
+static const unsigned int qspi_ctrl_pins[] = {
+ /* SPCLK, SSL */
+ RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 9),
+};
+static const unsigned int qspi_ctrl_mux[] = {
+ SPCLK_MARK, SSL_MARK,
+};
+static const unsigned int qspi_data2_pins[] = {
+ /* MOSI_IO0, MISO_IO1 */
+ RCAR_GP_PIN(1, 5), RCAR_GP_PIN(1, 6),
+};
+static const unsigned int qspi_data2_mux[] = {
+ MOSI_IO0_MARK, MISO_IO1_MARK,
+};
+static const unsigned int qspi_data4_pins[] = {
+ /* MOSI_IO0, MISO_IO1, IO2, IO3 */
+ RCAR_GP_PIN(1, 5), RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 7),
+ RCAR_GP_PIN(1, 8),
+};
+static const unsigned int qspi_data4_mux[] = {
+ MOSI_IO0_MARK, MISO_IO1_MARK, IO2_MARK, IO3_MARK,
+};
+
+static const unsigned int qspi_ctrl_b_pins[] = {
+ /* SPCLK, SSL */
+ RCAR_GP_PIN(6, 0), RCAR_GP_PIN(6, 5),
+};
+static const unsigned int qspi_ctrl_b_mux[] = {
+ SPCLK_B_MARK, SSL_B_MARK,
+};
+static const unsigned int qspi_data2_b_pins[] = {
+ /* MOSI_IO0, MISO_IO1 */
+ RCAR_GP_PIN(6, 1), RCAR_GP_PIN(6, 2),
+};
+static const unsigned int qspi_data2_b_mux[] = {
+ MOSI_IO0_B_MARK, MISO_IO1_B_MARK,
+};
+static const unsigned int qspi_data4_b_pins[] = {
+ /* MOSI_IO0, MISO_IO1, IO2, IO3 */
+ RCAR_GP_PIN(6, 1), RCAR_GP_PIN(6, 2), RCAR_GP_PIN(6, 3),
+ RCAR_GP_PIN(6, 4),
+};
+static const unsigned int qspi_data4_b_mux[] = {
+ SPCLK_B_MARK, MOSI_IO0_B_MARK, MISO_IO1_B_MARK,
+ IO2_B_MARK, IO3_B_MARK, SSL_B_MARK,
+};
/* - SCIF0 ------------------------------------------------------------------ */
static const unsigned int scif0_data_pins[] = {
/* RX, TX */
@@ -3123,6 +3583,12 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(i2c4),
SH_PFC_PIN_GROUP(i2c4_b),
SH_PFC_PIN_GROUP(i2c4_c),
+ SH_PFC_PIN_GROUP(i2c7),
+ SH_PFC_PIN_GROUP(i2c7_b),
+ SH_PFC_PIN_GROUP(i2c7_c),
+ SH_PFC_PIN_GROUP(i2c8),
+ SH_PFC_PIN_GROUP(i2c8_b),
+ SH_PFC_PIN_GROUP(i2c8_c),
SH_PFC_PIN_GROUP(intc_irq0),
SH_PFC_PIN_GROUP(intc_irq1),
SH_PFC_PIN_GROUP(intc_irq2),
@@ -3137,18 +3603,75 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(msiof0_ss2),
SH_PFC_PIN_GROUP(msiof0_rx),
SH_PFC_PIN_GROUP(msiof0_tx),
+ SH_PFC_PIN_GROUP(msiof0_clk_b),
+ SH_PFC_PIN_GROUP(msiof0_sync_b),
+ SH_PFC_PIN_GROUP(msiof0_ss1_b),
+ SH_PFC_PIN_GROUP(msiof0_ss2_b),
+ SH_PFC_PIN_GROUP(msiof0_rx_b),
+ SH_PFC_PIN_GROUP(msiof0_tx_b),
+ SH_PFC_PIN_GROUP(msiof0_clk_c),
+ SH_PFC_PIN_GROUP(msiof0_sync_c),
+ SH_PFC_PIN_GROUP(msiof0_ss1_c),
+ SH_PFC_PIN_GROUP(msiof0_ss2_c),
+ SH_PFC_PIN_GROUP(msiof0_rx_c),
+ SH_PFC_PIN_GROUP(msiof0_tx_c),
SH_PFC_PIN_GROUP(msiof1_clk),
SH_PFC_PIN_GROUP(msiof1_sync),
SH_PFC_PIN_GROUP(msiof1_ss1),
SH_PFC_PIN_GROUP(msiof1_ss2),
SH_PFC_PIN_GROUP(msiof1_rx),
SH_PFC_PIN_GROUP(msiof1_tx),
+ SH_PFC_PIN_GROUP(msiof1_clk_b),
+ SH_PFC_PIN_GROUP(msiof1_sync_b),
+ SH_PFC_PIN_GROUP(msiof1_ss1_b),
+ SH_PFC_PIN_GROUP(msiof1_ss2_b),
+ SH_PFC_PIN_GROUP(msiof1_rx_b),
+ SH_PFC_PIN_GROUP(msiof1_tx_b),
+ SH_PFC_PIN_GROUP(msiof1_clk_c),
+ SH_PFC_PIN_GROUP(msiof1_sync_c),
+ SH_PFC_PIN_GROUP(msiof1_rx_c),
+ SH_PFC_PIN_GROUP(msiof1_tx_c),
+ SH_PFC_PIN_GROUP(msiof1_clk_d),
+ SH_PFC_PIN_GROUP(msiof1_sync_d),
+ SH_PFC_PIN_GROUP(msiof1_ss1_d),
+ SH_PFC_PIN_GROUP(msiof1_rx_d),
+ SH_PFC_PIN_GROUP(msiof1_tx_d),
+ SH_PFC_PIN_GROUP(msiof1_clk_e),
+ SH_PFC_PIN_GROUP(msiof1_sync_e),
+ SH_PFC_PIN_GROUP(msiof1_rx_e),
+ SH_PFC_PIN_GROUP(msiof1_tx_e),
SH_PFC_PIN_GROUP(msiof2_clk),
SH_PFC_PIN_GROUP(msiof2_sync),
SH_PFC_PIN_GROUP(msiof2_ss1),
SH_PFC_PIN_GROUP(msiof2_ss2),
SH_PFC_PIN_GROUP(msiof2_rx),
SH_PFC_PIN_GROUP(msiof2_tx),
+ SH_PFC_PIN_GROUP(msiof2_clk_b),
+ SH_PFC_PIN_GROUP(msiof2_sync_b),
+ SH_PFC_PIN_GROUP(msiof2_ss1_b),
+ SH_PFC_PIN_GROUP(msiof2_ss2_b),
+ SH_PFC_PIN_GROUP(msiof2_rx_b),
+ SH_PFC_PIN_GROUP(msiof2_tx_b),
+ SH_PFC_PIN_GROUP(msiof2_clk_c),
+ SH_PFC_PIN_GROUP(msiof2_sync_c),
+ SH_PFC_PIN_GROUP(msiof2_rx_c),
+ SH_PFC_PIN_GROUP(msiof2_tx_c),
+ SH_PFC_PIN_GROUP(msiof2_clk_d),
+ SH_PFC_PIN_GROUP(msiof2_sync_d),
+ SH_PFC_PIN_GROUP(msiof2_ss1_d),
+ SH_PFC_PIN_GROUP(msiof2_ss2_d),
+ SH_PFC_PIN_GROUP(msiof2_rx_d),
+ SH_PFC_PIN_GROUP(msiof2_tx_d),
+ SH_PFC_PIN_GROUP(msiof2_clk_e),
+ SH_PFC_PIN_GROUP(msiof2_sync_e),
+ SH_PFC_PIN_GROUP(msiof2_rx_e),
+ SH_PFC_PIN_GROUP(msiof2_tx_e),
+ SH_PFC_PIN_GROUP(qspi_ctrl),
+ SH_PFC_PIN_GROUP(qspi_data2),
+ SH_PFC_PIN_GROUP(qspi_data4),
+ SH_PFC_PIN_GROUP(qspi_ctrl_b),
+ SH_PFC_PIN_GROUP(qspi_data2_b),
+ SH_PFC_PIN_GROUP(qspi_data4_b),
SH_PFC_PIN_GROUP(scif0_data),
SH_PFC_PIN_GROUP(scif0_data_b),
SH_PFC_PIN_GROUP(scif0_data_c),
@@ -3335,6 +3858,18 @@ static const char * const i2c4_groups[] = {
"i2c4_c",
};
+static const char * const i2c7_groups[] = {
+ "i2c7",
+ "i2c7_b",
+ "i2c7_c",
+};
+
+static const char * const i2c8_groups[] = {
+ "i2c8",
+ "i2c8_b",
+ "i2c8_c",
+};
+
static const char * const intc_groups[] = {
"intc_irq0",
"intc_irq1",
@@ -3356,6 +3891,18 @@ static const char * const msiof0_groups[] = {
"msiof0_ss2",
"msiof0_rx",
"msiof0_tx",
+ "msiof0_clk_b",
+ "msiof0_sync_b",
+ "msiof0_ss1_b",
+ "msiof0_ss2_b",
+ "msiof0_rx_b",
+ "msiof0_tx_b",
+ "msiof0_clk_c",
+ "msiof0_sync_c",
+ "msiof0_ss1_c",
+ "msiof0_ss2_c",
+ "msiof0_rx_c",
+ "msiof0_tx_c",
};
static const char * const msiof1_groups[] = {
@@ -3365,6 +3912,25 @@ static const char * const msiof1_groups[] = {
"msiof1_ss2",
"msiof1_rx",
"msiof1_tx",
+ "msiof1_clk_b",
+ "msiof1_sync_b",
+ "msiof1_ss1_b",
+ "msiof1_ss2_b",
+ "msiof1_rx_b",
+ "msiof1_tx_b",
+ "msiof1_clk_c",
+ "msiof1_sync_c",
+ "msiof1_rx_c",
+ "msiof1_tx_c",
+ "msiof1_clk_d",
+ "msiof1_sync_d",
+ "msiof1_ss1_d",
+ "msiof1_rx_d",
+ "msiof1_tx_d",
+ "msiof1_clk_e",
+ "msiof1_sync_e",
+ "msiof1_rx_e",
+ "msiof1_tx_e",
};
static const char * const msiof2_groups[] = {
@@ -3374,6 +3940,35 @@ static const char * const msiof2_groups[] = {
"msiof2_ss2",
"msiof2_rx",
"msiof2_tx",
+ "msiof2_clk_b",
+ "msiof2_sync_b",
+ "msiof2_ss1_b",
+ "msiof2_ss2_b",
+ "msiof2_rx_b",
+ "msiof2_tx_b",
+ "msiof2_clk_c",
+ "msiof2_sync_c",
+ "msiof2_rx_c",
+ "msiof2_tx_c",
+ "msiof2_clk_d",
+ "msiof2_sync_d",
+ "msiof2_ss1_d",
+ "msiof2_ss2_d",
+ "msiof2_rx_d",
+ "msiof2_tx_d",
+ "msiof2_clk_e",
+ "msiof2_sync_e",
+ "msiof2_rx_e",
+ "msiof2_tx_e",
+};
+
+static const char * const qspi_groups[] = {
+ "qspi_ctrl",
+ "qspi_data2",
+ "qspi_data4",
+ "qspi_ctrl_b",
+ "qspi_data2_b",
+ "qspi_data4_b",
};
static const char * const scif0_groups[] = {
@@ -3566,11 +4161,14 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(i2c2),
SH_PFC_FUNCTION(i2c3),
SH_PFC_FUNCTION(i2c4),
+ SH_PFC_FUNCTION(i2c7),
+ SH_PFC_FUNCTION(i2c8),
SH_PFC_FUNCTION(intc),
SH_PFC_FUNCTION(mmc),
SH_PFC_FUNCTION(msiof0),
SH_PFC_FUNCTION(msiof1),
SH_PFC_FUNCTION(msiof2),
+ SH_PFC_FUNCTION(qspi),
SH_PFC_FUNCTION(scif0),
SH_PFC_FUNCTION(scif1),
SH_PFC_FUNCTION(scif2),
@@ -3825,7 +4423,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
GP_6_11_FN, FN_IP13_25,
GP_6_10_FN, FN_IP13_24_23,
GP_6_9_FN, FN_IP13_22,
- 0, 0,
+ GP_6_8_FN, FN_SD1_CLK,
GP_6_7_FN, FN_IP13_21_19,
GP_6_6_FN, FN_IP13_18_16,
GP_6_5_FN, FN_IP13_15,
diff --git a/drivers/pinctrl/sirf/pinctrl-atlas6.c b/drivers/pinctrl/sirf/pinctrl-atlas6.c
index 2b9f32065920..c4dd3d5cf9c3 100644
--- a/drivers/pinctrl/sirf/pinctrl-atlas6.c
+++ b/drivers/pinctrl/sirf/pinctrl-atlas6.c
@@ -1,7 +1,8 @@
/*
* pinctrl pads, groups, functions for CSR SiRFatlasVI
*
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ * Copyright (c) 2011 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
+ * company.
*
* Licensed under GPLv2 or later.
*/
@@ -529,6 +530,40 @@ static const struct sirfsoc_padmux usp0_padmux = {
static const unsigned usp0_pins[] = { 51, 52, 53, 54, 55 };
+static const struct sirfsoc_muxmask usp0_only_utfs_muxmask[] = {
+ {
+ .group = 1,
+ .mask = BIT(19) | BIT(20) | BIT(21) | BIT(22),
+ },
+};
+
+static const struct sirfsoc_padmux usp0_only_utfs_padmux = {
+ .muxmask_counts = ARRAY_SIZE(usp0_only_utfs_muxmask),
+ .muxmask = usp0_only_utfs_muxmask,
+ .ctrlreg = SIRFSOC_RSC_PIN_MUX,
+ .funcmask = BIT(1) | BIT(2) | BIT(6),
+ .funcval = 0,
+};
+
+static const unsigned usp0_only_utfs_pins[] = { 51, 52, 53, 54 };
+
+static const struct sirfsoc_muxmask usp0_only_urfs_muxmask[] = {
+ {
+ .group = 1,
+ .mask = BIT(19) | BIT(20) | BIT(21) | BIT(23),
+ },
+};
+
+static const struct sirfsoc_padmux usp0_only_urfs_padmux = {
+ .muxmask_counts = ARRAY_SIZE(usp0_only_urfs_muxmask),
+ .muxmask = usp0_only_urfs_muxmask,
+ .ctrlreg = SIRFSOC_RSC_PIN_MUX,
+ .funcmask = BIT(1) | BIT(2) | BIT(9),
+ .funcval = 0,
+};
+
+static const unsigned usp0_only_urfs_pins[] = { 51, 52, 53, 55 };
+
static const struct sirfsoc_muxmask usp0_uart_nostreamctrl_muxmask[] = {
{
.group = 1,
@@ -905,6 +940,8 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = {
SIRFSOC_PIN_GROUP("usp0grp", usp0_pins),
SIRFSOC_PIN_GROUP("usp0_uart_nostreamctrl_grp",
usp0_uart_nostreamctrl_pins),
+ SIRFSOC_PIN_GROUP("usp0_only_utfs_grp", usp0_only_utfs_pins),
+ SIRFSOC_PIN_GROUP("usp0_only_urfs_grp", usp0_only_urfs_pins),
SIRFSOC_PIN_GROUP("usp1grp", usp1_pins),
SIRFSOC_PIN_GROUP("usp1_uart_nostreamctrl_grp",
usp1_uart_nostreamctrl_pins),
@@ -953,6 +990,9 @@ 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 usp0_only_utfs_grp[] = { "usp0_only_utfs_grp" };
+static const char * const usp0_only_urfs_grp[] = { "usp0_only_urfs_grp" };
+
static const char * const usp1grp[] = { "usp1grp" };
static const char * const usp1_uart_nostreamctrl_grp[] = {
"usp1_uart_nostreamctrl_grp" };
@@ -1003,6 +1043,10 @@ static const struct sirfsoc_pmx_func sirfsoc_pmx_functions[] = {
SIRFSOC_PMX_FUNCTION("usp0_uart_nostreamctrl",
usp0_uart_nostreamctrl_grp,
usp0_uart_nostreamctrl_padmux),
+ SIRFSOC_PMX_FUNCTION("usp0_only_utfs", usp0_only_utfs_grp,
+ usp0_only_utfs_padmux),
+ SIRFSOC_PMX_FUNCTION("usp0_only_urfs", usp0_only_urfs_grp,
+ usp0_only_urfs_padmux),
SIRFSOC_PMX_FUNCTION("usp1", usp1grp, usp1_padmux),
SIRFSOC_PMX_FUNCTION("usp1_uart_nostreamctrl",
usp1_uart_nostreamctrl_grp,
diff --git a/drivers/pinctrl/sirf/pinctrl-prima2.c b/drivers/pinctrl/sirf/pinctrl-prima2.c
index dde0285544d6..8aa76f0776d7 100644
--- a/drivers/pinctrl/sirf/pinctrl-prima2.c
+++ b/drivers/pinctrl/sirf/pinctrl-prima2.c
@@ -1,7 +1,8 @@
/*
* pinctrl pads, groups, functions for CSR SiRFprimaII
*
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ * Copyright (c) 2011 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
+ * company.
*
* Licensed under GPLv2 or later.
*/
diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c
index a0d6152701cd..76502aab2cb1 100644
--- a/drivers/pinctrl/sirf/pinctrl-sirf.c
+++ b/drivers/pinctrl/sirf/pinctrl-sirf.c
@@ -1,7 +1,8 @@
/*
* pinmux driver for CSR SiRFprimaII
*
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ * Copyright (c) 2011 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
+ * company.
*
* Licensed under GPLv2 or later.
*/
@@ -594,24 +595,24 @@ static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type)
return 0;
}
-static unsigned int sirfsoc_gpio_irq_startup(struct irq_data *d)
+static int sirfsoc_gpio_irq_reqres(struct irq_data *d)
{
struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
- if (gpio_lock_as_irq(&bank->chip.gc, d->hwirq))
+ if (gpio_lock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE)) {
dev_err(bank->chip.gc.dev,
"unable to lock HW IRQ %lu for IRQ\n",
d->hwirq);
- sirfsoc_gpio_irq_unmask(d);
+ return -EINVAL;
+ }
return 0;
}
-static void sirfsoc_gpio_irq_shutdown(struct irq_data *d)
+static void sirfsoc_gpio_irq_relres(struct irq_data *d)
{
struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
- sirfsoc_gpio_irq_mask(d);
- gpio_unlock_as_irq(&bank->chip.gc, d->hwirq);
+ gpio_unlock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE);
}
static struct irq_chip sirfsoc_irq_chip = {
@@ -620,8 +621,8 @@ static struct irq_chip sirfsoc_irq_chip = {
.irq_mask = sirfsoc_gpio_irq_mask,
.irq_unmask = sirfsoc_gpio_irq_unmask,
.irq_set_type = sirfsoc_gpio_irq_type,
- .irq_startup = sirfsoc_gpio_irq_startup,
- .irq_shutdown = sirfsoc_gpio_irq_shutdown,
+ .irq_request_resources = sirfsoc_gpio_irq_reqres,
+ .irq_release_resources = sirfsoc_gpio_irq_relres,
};
static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc)
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 5ae65c11d544..5f67843c7fb7 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -27,8 +27,6 @@ config ACER_WMI
depends on ACPI_WMI
select INPUT_SPARSEKMAP
# Acer WMI depends on ACPI_VIDEO when ACPI is enabled
- # but for select to work, need to select ACPI_VIDEO's dependencies, ick
- select VIDEO_OUTPUT_CONTROL if ACPI
select ACPI_VIDEO if ACPI
---help---
This is a driver for newer Acer (and Wistron) laptops. It adds
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index be02bcc346d3..e6f336270c21 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -66,7 +66,6 @@
#include <linux/backlight.h>
#include <linux/input.h>
#include <linux/kfifo.h>
-#include <linux/video_output.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index defb6afc1409..94bb6157c957 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -6776,8 +6776,9 @@ static int __init volume_create_alsa_mixer(void)
struct snd_kcontrol *ctl_mute;
int rc;
- rc = snd_card_create(alsa_index, alsa_id, THIS_MODULE,
- sizeof(struct tpacpi_alsa_data), &card);
+ rc = snd_card_new(&tpacpi_pdev->dev,
+ alsa_index, alsa_id, THIS_MODULE,
+ sizeof(struct tpacpi_alsa_data), &card);
if (rc < 0 || !card) {
pr_err("Failed to create ALSA card structures: %d\n", rc);
return 1;
@@ -6828,7 +6829,6 @@ static int __init volume_create_alsa_mixer(void)
}
data->ctl_mute_id = &ctl_mute->id;
- snd_card_set_dev(card, &tpacpi_pdev->dev);
rc = snd_card_register(card);
if (rc < 0) {
pr_err("Failed to register ALSA card: %d\n", rc);
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 167f3d00c916..66977ebf13b3 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -183,9 +183,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
struct resource r = {0};
int i, flags;
- if (acpi_dev_resource_memory(res, &r)
- || acpi_dev_resource_io(res, &r)
- || acpi_dev_resource_address_space(res, &r)
+ if (acpi_dev_resource_address_space(res, &r)
|| acpi_dev_resource_ext_address_space(res, &r)) {
pnp_add_resource(dev, &r);
return AE_OK;
@@ -217,6 +215,17 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
}
switch (res->type) {
+ case ACPI_RESOURCE_TYPE_MEMORY24:
+ case ACPI_RESOURCE_TYPE_MEMORY32:
+ case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
+ if (acpi_dev_resource_memory(res, &r))
+ pnp_add_resource(dev, &r);
+ break;
+ case ACPI_RESOURCE_TYPE_IO:
+ case ACPI_RESOURCE_TYPE_FIXED_IO:
+ if (acpi_dev_resource_io(res, &r))
+ pnp_add_resource(dev, &r);
+ break;
case ACPI_RESOURCE_TYPE_DMA:
dma = &res->data.dma;
if (dma->channel_count > 0 && dma->channels[0] != (u8) -1)
diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c
index 769d265b221b..deb7f4bcdb7b 100644
--- a/drivers/pnp/pnpbios/bioscalls.c
+++ b/drivers/pnp/pnpbios/bioscalls.c
@@ -21,7 +21,7 @@
#include "pnpbios.h"
-static struct {
+__visible struct {
u16 offset;
u16 segment;
} pnp_bios_callpoint;
@@ -41,6 +41,7 @@ asmlinkage void pnp_bios_callfunc(void);
__asm__(".text \n"
__ALIGN_STR "\n"
+ ".globl pnp_bios_callfunc\n"
"pnp_bios_callfunc:\n"
" pushl %edx \n"
" pushl %ecx \n"
@@ -66,9 +67,9 @@ static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4092,
* after PnP BIOS oopses.
*/
-u32 pnp_bios_fault_esp;
-u32 pnp_bios_fault_eip;
-u32 pnp_bios_is_utter_crap = 0;
+__visible u32 pnp_bios_fault_esp;
+__visible u32 pnp_bios_fault_eip;
+__visible u32 pnp_bios_is_utter_crap = 0;
static spinlock_t pnp_bios_lock;
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index bacddd102ae9..01712cbfd92e 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -385,7 +385,7 @@ int pnp_check_irq(struct pnp_dev *dev, struct resource *res)
* device is active because it itself may be in use */
if (!dev->active) {
if (request_irq(*irq, pnp_test_handler,
- IRQF_DISABLED | IRQF_PROBE_SHARED, "pnp", NULL))
+ IRQF_PROBE_SHARED, "pnp", NULL))
return 0;
free_irq(*irq, NULL);
}
diff --git a/drivers/power/ds2782_battery.c b/drivers/power/ds2782_battery.c
index 563174891c90..041f9b638d28 100644
--- a/drivers/power/ds2782_battery.c
+++ b/drivers/power/ds2782_battery.c
@@ -192,7 +192,7 @@ static int ds2786_get_voltage(struct ds278x_info *info, int *voltage_uV)
/*
* Voltage is measured in units of 1.22mV. The voltage is stored as
- * a 10-bit number plus sign, in the upper bits of a 16-bit register
+ * a 12-bit number plus sign, in the upper bits of a 16-bit register
*/
err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw);
if (err)
diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c
index 80edb7d8cb54..0b4cf9d63291 100644
--- a/drivers/power/isp1704_charger.c
+++ b/drivers/power/isp1704_charger.c
@@ -444,8 +444,6 @@ static int isp1704_charger_probe(struct platform_device *pdev)
ret = PTR_ERR(isp->phy);
goto fail0;
}
- if (!isp->phy)
- goto fail0;
isp->dev = &pdev->dev;
platform_set_drvdata(pdev, isp);
diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c
index c7ff6d67f158..0fbac861080d 100644
--- a/drivers/power/max17040_battery.c
+++ b/drivers/power/max17040_battery.c
@@ -148,7 +148,7 @@ static void max17040_get_online(struct i2c_client *client)
{
struct max17040_chip *chip = i2c_get_clientdata(client);
- if (chip->pdata->battery_online)
+ if (chip->pdata && chip->pdata->battery_online)
chip->online = chip->pdata->battery_online();
else
chip->online = 1;
@@ -158,7 +158,8 @@ static void max17040_get_status(struct i2c_client *client)
{
struct max17040_chip *chip = i2c_get_clientdata(client);
- if (!chip->pdata->charger_online || !chip->pdata->charger_enable) {
+ if (!chip->pdata || !chip->pdata->charger_online
+ || !chip->pdata->charger_enable) {
chip->status = POWER_SUPPLY_STATUS_UNKNOWN;
return;
}
diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c
index 3c6768378a94..61b51e17d932 100644
--- a/drivers/powercap/intel_rapl.c
+++ b/drivers/powercap/intel_rapl.c
@@ -834,7 +834,7 @@ static int rapl_write_data_raw(struct rapl_domain *rd,
}
static const struct x86_cpu_id energy_unit_quirk_ids[] = {
- { X86_VENDOR_INTEL, 6, 0x37},/* VLV */
+ { X86_VENDOR_INTEL, 6, 0x37},/* Valleyview */
{}
};
@@ -947,11 +947,11 @@ static void package_power_limit_irq_restore(int package_id)
}
static const struct x86_cpu_id rapl_ids[] = {
- { X86_VENDOR_INTEL, 6, 0x2a},/* SNB */
- { X86_VENDOR_INTEL, 6, 0x2d},/* SNB EP */
- { X86_VENDOR_INTEL, 6, 0x37},/* VLV */
- { X86_VENDOR_INTEL, 6, 0x3a},/* IVB */
- { X86_VENDOR_INTEL, 6, 0x45},/* HSW */
+ { X86_VENDOR_INTEL, 6, 0x2a},/* Sandy Bridge */
+ { X86_VENDOR_INTEL, 6, 0x2d},/* Sandy Bridge EP */
+ { X86_VENDOR_INTEL, 6, 0x37},/* Valleyview */
+ { X86_VENDOR_INTEL, 6, 0x3a},/* Ivy Bridge */
+ { X86_VENDOR_INTEL, 6, 0x45},/* Haswell */
/* TODO: Add more CPU IDs after testing */
{}
};
@@ -1147,6 +1147,11 @@ static int rapl_check_domain(int cpu, int domain)
if (rdmsrl_safe_on_cpu(cpu, msr, &val1))
return -ENODEV;
+ /* PP1/uncore/graphics domain may not be active at the time of
+ * driver loading. So skip further checks.
+ */
+ if (domain == RAPL_DOMAIN_PP1)
+ return 0;
/* energy counters roll slowly on some domains */
while (++retry < 10) {
usleep_range(10000, 15000);
diff --git a/drivers/ps3/ps3-vuart.c b/drivers/ps3/ps3-vuart.c
index fb7300837fee..bc1e5139ba29 100644
--- a/drivers/ps3/ps3-vuart.c
+++ b/drivers/ps3/ps3-vuart.c
@@ -699,8 +699,6 @@ int ps3_vuart_read_async(struct ps3_system_bus_device *dev, unsigned int bytes)
BUG_ON(!bytes);
- PREPARE_WORK(&priv->rx_list.work.work, ps3_vuart_work);
-
spin_lock_irqsave(&priv->rx_list.lock, flags);
if (priv->rx_list.bytes_held >= bytes) {
dev_dbg(&dev->core, "%s:%d: schedule_work %xh bytes\n",
@@ -1052,7 +1050,7 @@ static int ps3_vuart_probe(struct ps3_system_bus_device *dev)
INIT_LIST_HEAD(&priv->rx_list.head);
spin_lock_init(&priv->rx_list.lock);
- INIT_WORK(&priv->rx_list.work.work, NULL);
+ INIT_WORK(&priv->rx_list.work.work, ps3_vuart_work);
priv->rx_list.work.trigger = 0;
priv->rx_list.work.dev = dev;
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
index 5a7910e61e17..6963bdf54175 100644
--- a/drivers/ptp/Kconfig
+++ b/drivers/ptp/Kconfig
@@ -7,6 +7,7 @@ menu "PTP clock support"
config PTP_1588_CLOCK
tristate "PTP clock support"
select PPS
+ select NET_PTP_CLASSIFY
help
The IEEE 1588 standard defines a method to precisely
synchronize distributed clocks over Ethernet networks. The
diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c
index 34a0c607318e..419056d7887e 100644
--- a/drivers/ptp/ptp_chardev.c
+++ b/drivers/ptp/ptp_chardev.c
@@ -25,6 +25,96 @@
#include "ptp_private.h"
+static int ptp_disable_pinfunc(struct ptp_clock_info *ops,
+ enum ptp_pin_function func, unsigned int chan)
+{
+ struct ptp_clock_request rq;
+ int err = 0;
+
+ memset(&rq, 0, sizeof(rq));
+
+ switch (func) {
+ case PTP_PF_NONE:
+ break;
+ case PTP_PF_EXTTS:
+ rq.type = PTP_CLK_REQ_EXTTS;
+ rq.extts.index = chan;
+ err = ops->enable(ops, &rq, 0);
+ break;
+ case PTP_PF_PEROUT:
+ rq.type = PTP_CLK_REQ_PEROUT;
+ rq.perout.index = chan;
+ err = ops->enable(ops, &rq, 0);
+ break;
+ case PTP_PF_PHYSYNC:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return err;
+}
+
+int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin,
+ enum ptp_pin_function func, unsigned int chan)
+{
+ struct ptp_clock_info *info = ptp->info;
+ struct ptp_pin_desc *pin1 = NULL, *pin2 = &info->pin_config[pin];
+ unsigned int i;
+
+ /* Check to see if any other pin previously had this function. */
+ for (i = 0; i < info->n_pins; i++) {
+ if (info->pin_config[i].func == func &&
+ info->pin_config[i].chan == chan) {
+ pin1 = &info->pin_config[i];
+ break;
+ }
+ }
+ if (pin1 && i == pin)
+ return 0;
+
+ /* Check the desired function and channel. */
+ switch (func) {
+ case PTP_PF_NONE:
+ break;
+ case PTP_PF_EXTTS:
+ if (chan >= info->n_ext_ts)
+ return -EINVAL;
+ break;
+ case PTP_PF_PEROUT:
+ if (chan >= info->n_per_out)
+ return -EINVAL;
+ break;
+ case PTP_PF_PHYSYNC:
+ pr_err("sorry, cannot reassign the calibration pin\n");
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+
+ if (pin2->func == PTP_PF_PHYSYNC) {
+ pr_err("sorry, cannot reprogram the calibration pin\n");
+ return -EINVAL;
+ }
+
+ if (info->verify(info, pin, func, chan)) {
+ pr_err("driver cannot use function %u on pin %u\n", func, chan);
+ return -EOPNOTSUPP;
+ }
+
+ /* Disable whatever function was previously assigned. */
+ if (pin1) {
+ ptp_disable_pinfunc(info, func, chan);
+ pin1->func = PTP_PF_NONE;
+ pin1->chan = 0;
+ }
+ ptp_disable_pinfunc(info, pin2->func, pin2->chan);
+ pin2->func = func;
+ pin2->chan = chan;
+
+ return 0;
+}
+
int ptp_open(struct posix_clock *pc, fmode_t fmode)
{
return 0;
@@ -35,12 +125,13 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
struct ptp_clock_caps caps;
struct ptp_clock_request req;
struct ptp_sys_offset *sysoff = NULL;
+ struct ptp_pin_desc pd;
struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
struct ptp_clock_info *ops = ptp->info;
struct ptp_clock_time *pct;
struct timespec ts;
int enable, err = 0;
- unsigned int i;
+ unsigned int i, pin_index;
switch (cmd) {
@@ -51,6 +142,7 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
caps.n_ext_ts = ptp->info->n_ext_ts;
caps.n_per_out = ptp->info->n_per_out;
caps.pps = ptp->info->pps;
+ caps.n_pins = ptp->info->n_pins;
if (copy_to_user((void __user *)arg, &caps, sizeof(caps)))
err = -EFAULT;
break;
@@ -126,6 +218,40 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
err = -EFAULT;
break;
+ case PTP_PIN_GETFUNC:
+ if (copy_from_user(&pd, (void __user *)arg, sizeof(pd))) {
+ err = -EFAULT;
+ break;
+ }
+ pin_index = pd.index;
+ if (pin_index >= ops->n_pins) {
+ err = -EINVAL;
+ break;
+ }
+ if (mutex_lock_interruptible(&ptp->pincfg_mux))
+ return -ERESTARTSYS;
+ pd = ops->pin_config[pin_index];
+ mutex_unlock(&ptp->pincfg_mux);
+ if (!err && copy_to_user((void __user *)arg, &pd, sizeof(pd)))
+ err = -EFAULT;
+ break;
+
+ case PTP_PIN_SETFUNC:
+ if (copy_from_user(&pd, (void __user *)arg, sizeof(pd))) {
+ err = -EFAULT;
+ break;
+ }
+ pin_index = pd.index;
+ if (pin_index >= ops->n_pins) {
+ err = -EINVAL;
+ break;
+ }
+ if (mutex_lock_interruptible(&ptp->pincfg_mux))
+ return -ERESTARTSYS;
+ err = ptp_set_pinfunc(ptp, pin_index, pd.func, pd.chan);
+ mutex_unlock(&ptp->pincfg_mux);
+ break;
+
default:
err = -ENOTTY;
break;
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index a8319b266643..e25d2bc898e5 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -169,6 +169,7 @@ static void delete_ptp_clock(struct posix_clock *pc)
struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
mutex_destroy(&ptp->tsevq_mux);
+ mutex_destroy(&ptp->pincfg_mux);
ida_simple_remove(&ptp_clocks_map, ptp->index);
kfree(ptp);
}
@@ -203,6 +204,7 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
ptp->index = index;
spin_lock_init(&ptp->tsevq.lock);
mutex_init(&ptp->tsevq_mux);
+ mutex_init(&ptp->pincfg_mux);
init_waitqueue_head(&ptp->tsev_wq);
/* Create a new device in our class. */
@@ -249,6 +251,7 @@ no_sysfs:
device_destroy(ptp_class, ptp->devid);
no_device:
mutex_destroy(&ptp->tsevq_mux);
+ mutex_destroy(&ptp->pincfg_mux);
no_slot:
kfree(ptp);
no_memory:
@@ -305,6 +308,26 @@ int ptp_clock_index(struct ptp_clock *ptp)
}
EXPORT_SYMBOL(ptp_clock_index);
+int ptp_find_pin(struct ptp_clock *ptp,
+ enum ptp_pin_function func, unsigned int chan)
+{
+ struct ptp_pin_desc *pin = NULL;
+ int i;
+
+ mutex_lock(&ptp->pincfg_mux);
+ for (i = 0; i < ptp->info->n_pins; i++) {
+ if (ptp->info->pin_config[i].func == func &&
+ ptp->info->pin_config[i].chan == chan) {
+ pin = &ptp->info->pin_config[i];
+ break;
+ }
+ }
+ mutex_unlock(&ptp->pincfg_mux);
+
+ return pin ? i : -1;
+}
+EXPORT_SYMBOL(ptp_find_pin);
+
/* module operations */
static void __exit ptp_exit(void)
diff --git a/drivers/ptp/ptp_ixp46x.c b/drivers/ptp/ptp_ixp46x.c
index 4a08727fcaf3..604d340f2095 100644
--- a/drivers/ptp/ptp_ixp46x.c
+++ b/drivers/ptp/ptp_ixp46x.c
@@ -244,6 +244,7 @@ static struct ptp_clock_info ptp_ixp_caps = {
.name = "IXP46X timer",
.max_adj = 66666655,
.n_ext_ts = N_EXT_TS,
+ .n_pins = 0,
.pps = 0,
.adjfreq = ptp_ixp_adjfreq,
.adjtime = ptp_ixp_adjtime,
diff --git a/drivers/ptp/ptp_pch.c b/drivers/ptp/ptp_pch.c
index 71a2559278d7..90a106308c4f 100644
--- a/drivers/ptp/ptp_pch.c
+++ b/drivers/ptp/ptp_pch.c
@@ -514,6 +514,7 @@ static struct ptp_clock_info ptp_pch_caps = {
.name = "PCH timer",
.max_adj = 50000000,
.n_ext_ts = N_EXT_TS,
+ .n_pins = 0,
.pps = 0,
.adjfreq = ptp_pch_adjfreq,
.adjtime = ptp_pch_adjtime,
diff --git a/drivers/ptp/ptp_private.h b/drivers/ptp/ptp_private.h
index df03f2e30ad9..9c5d41421b65 100644
--- a/drivers/ptp/ptp_private.h
+++ b/drivers/ptp/ptp_private.h
@@ -48,8 +48,12 @@ struct ptp_clock {
long dialed_frequency; /* remembers the frequency adjustment */
struct timestamp_event_queue tsevq; /* simple fifo for time stamps */
struct mutex tsevq_mux; /* one process at a time reading the fifo */
+ struct mutex pincfg_mux; /* protect concurrent info->pin_config access */
wait_queue_head_t tsev_wq;
int defunct; /* tells readers to go away when clock is being removed */
+ struct device_attribute *pin_dev_attr;
+ struct attribute **pin_attr;
+ struct attribute_group pin_attr_group;
};
/*
@@ -69,6 +73,10 @@ static inline int queue_cnt(struct timestamp_event_queue *q)
* see ptp_chardev.c
*/
+/* caller must hold pincfg_mux */
+int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin,
+ enum ptp_pin_function func, unsigned int chan);
+
long ptp_ioctl(struct posix_clock *pc,
unsigned int cmd, unsigned long arg);
diff --git a/drivers/ptp/ptp_sysfs.c b/drivers/ptp/ptp_sysfs.c
index 13ec5311746a..302e626fe6b0 100644
--- a/drivers/ptp/ptp_sysfs.c
+++ b/drivers/ptp/ptp_sysfs.c
@@ -18,6 +18,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/capability.h>
+#include <linux/slab.h>
#include "ptp_private.h"
@@ -42,6 +43,7 @@ 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(n_programmable_pins, n_pins);
PTP_SHOW_INT(pps_available, pps);
static struct attribute *ptp_attrs[] = {
@@ -50,6 +52,7 @@ static struct attribute *ptp_attrs[] = {
&dev_attr_n_alarms.attr,
&dev_attr_n_external_timestamps.attr,
&dev_attr_n_periodic_outputs.attr,
+ &dev_attr_n_programmable_pins.attr,
&dev_attr_pps_available.attr,
NULL,
};
@@ -175,6 +178,63 @@ out:
return err;
}
+static int ptp_pin_name2index(struct ptp_clock *ptp, const char *name)
+{
+ int i;
+ for (i = 0; i < ptp->info->n_pins; i++) {
+ if (!strcmp(ptp->info->pin_config[i].name, name))
+ return i;
+ }
+ return -1;
+}
+
+static ssize_t ptp_pin_show(struct device *dev, struct device_attribute *attr,
+ char *page)
+{
+ struct ptp_clock *ptp = dev_get_drvdata(dev);
+ unsigned int func, chan;
+ int index;
+
+ index = ptp_pin_name2index(ptp, attr->attr.name);
+ if (index < 0)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&ptp->pincfg_mux))
+ return -ERESTARTSYS;
+
+ func = ptp->info->pin_config[index].func;
+ chan = ptp->info->pin_config[index].chan;
+
+ mutex_unlock(&ptp->pincfg_mux);
+
+ return snprintf(page, PAGE_SIZE, "%u %u\n", func, chan);
+}
+
+static ssize_t ptp_pin_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ptp_clock *ptp = dev_get_drvdata(dev);
+ unsigned int func, chan;
+ int cnt, err, index;
+
+ cnt = sscanf(buf, "%u %u", &func, &chan);
+ if (cnt != 2)
+ return -EINVAL;
+
+ index = ptp_pin_name2index(ptp, attr->attr.name);
+ if (index < 0)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&ptp->pincfg_mux))
+ return -ERESTARTSYS;
+ err = ptp_set_pinfunc(ptp, index, func, chan);
+ mutex_unlock(&ptp->pincfg_mux);
+ if (err)
+ return err;
+
+ return count;
+}
+
static DEVICE_ATTR(extts_enable, 0220, NULL, extts_enable_store);
static DEVICE_ATTR(fifo, 0444, extts_fifo_show, NULL);
static DEVICE_ATTR(period, 0220, NULL, period_store);
@@ -195,9 +255,56 @@ int ptp_cleanup_sysfs(struct ptp_clock *ptp)
if (info->pps)
device_remove_file(dev, &dev_attr_pps_enable);
+ if (info->n_pins) {
+ sysfs_remove_group(&dev->kobj, &ptp->pin_attr_group);
+ kfree(ptp->pin_attr);
+ kfree(ptp->pin_dev_attr);
+ }
return 0;
}
+static int ptp_populate_pins(struct ptp_clock *ptp)
+{
+ struct device *dev = ptp->dev;
+ struct ptp_clock_info *info = ptp->info;
+ int err = -ENOMEM, i, n_pins = info->n_pins;
+
+ ptp->pin_dev_attr = kzalloc(n_pins * sizeof(*ptp->pin_dev_attr),
+ GFP_KERNEL);
+ if (!ptp->pin_dev_attr)
+ goto no_dev_attr;
+
+ ptp->pin_attr = kzalloc((1 + n_pins) * sizeof(struct attribute *),
+ GFP_KERNEL);
+ if (!ptp->pin_attr)
+ goto no_pin_attr;
+
+ for (i = 0; i < n_pins; i++) {
+ struct device_attribute *da = &ptp->pin_dev_attr[i];
+ sysfs_attr_init(&da->attr);
+ da->attr.name = info->pin_config[i].name;
+ da->attr.mode = 0644;
+ da->show = ptp_pin_show;
+ da->store = ptp_pin_store;
+ ptp->pin_attr[i] = &da->attr;
+ }
+
+ ptp->pin_attr_group.name = "pins";
+ ptp->pin_attr_group.attrs = ptp->pin_attr;
+
+ err = sysfs_create_group(&dev->kobj, &ptp->pin_attr_group);
+ if (err)
+ goto no_group;
+ return 0;
+
+no_group:
+ kfree(ptp->pin_attr);
+no_pin_attr:
+ kfree(ptp->pin_dev_attr);
+no_dev_attr:
+ return err;
+}
+
int ptp_populate_sysfs(struct ptp_clock *ptp)
{
struct device *dev = ptp->dev;
@@ -222,7 +329,15 @@ int ptp_populate_sysfs(struct ptp_clock *ptp)
if (err)
goto out4;
}
+ if (info->n_pins) {
+ err = ptp_populate_pins(ptp);
+ if (err)
+ goto out5;
+ }
return 0;
+out5:
+ if (info->pps)
+ device_remove_file(dev, &dev_attr_pps_enable);
out4:
if (info->n_per_out)
device_remove_file(dev, &dev_attr_period);
diff --git a/drivers/pwm/pwm-lp3943.c b/drivers/pwm/pwm-lp3943.c
index 8a843a04c224..a40b9c34e9ff 100644
--- a/drivers/pwm/pwm-lp3943.c
+++ b/drivers/pwm/pwm-lp3943.c
@@ -52,8 +52,10 @@ lp3943_pwm_request_map(struct lp3943_pwm *lp3943_pwm, int hwpwm)
offset = pwm_map->output[i];
/* Return an error if the pin is already assigned */
- if (test_and_set_bit(offset, &lp3943->pin_used))
+ if (test_and_set_bit(offset, &lp3943->pin_used)) {
+ kfree(pwm_map);
return ERR_PTR(-EBUSY);
+ }
}
return pwm_map;
diff --git a/drivers/rapidio/devices/tsi721.h b/drivers/rapidio/devices/tsi721.h
index b4b0d83f9ef6..7061ac0ad428 100644
--- a/drivers/rapidio/devices/tsi721.h
+++ b/drivers/rapidio/devices/tsi721.h
@@ -678,6 +678,7 @@ struct tsi721_bdma_chan {
struct list_head free_list;
dma_cookie_t completed_cookie;
struct tasklet_struct tasklet;
+ bool active;
};
#endif /* CONFIG_RAPIDIO_DMA_ENGINE */
diff --git a/drivers/rapidio/devices/tsi721_dma.c b/drivers/rapidio/devices/tsi721_dma.c
index 502663f5f7c6..91245f5dbe81 100644
--- a/drivers/rapidio/devices/tsi721_dma.c
+++ b/drivers/rapidio/devices/tsi721_dma.c
@@ -206,8 +206,8 @@ void tsi721_bdma_handler(struct tsi721_bdma_chan *bdma_chan)
{
/* Disable BDMA channel interrupts */
iowrite32(0, bdma_chan->regs + TSI721_DMAC_INTE);
-
- tasklet_schedule(&bdma_chan->tasklet);
+ if (bdma_chan->active)
+ tasklet_schedule(&bdma_chan->tasklet);
}
#ifdef CONFIG_PCI_MSI
@@ -562,7 +562,7 @@ static int tsi721_alloc_chan_resources(struct dma_chan *dchan)
}
#endif /* CONFIG_PCI_MSI */
- tasklet_enable(&bdma_chan->tasklet);
+ bdma_chan->active = true;
tsi721_bdma_interrupt_enable(bdma_chan, 1);
return bdma_chan->bd_num - 1;
@@ -576,9 +576,7 @@ err_out:
static void tsi721_free_chan_resources(struct dma_chan *dchan)
{
struct tsi721_bdma_chan *bdma_chan = to_tsi721_chan(dchan);
-#ifdef CONFIG_PCI_MSI
struct tsi721_device *priv = to_tsi721(dchan->device);
-#endif
LIST_HEAD(list);
dev_dbg(dchan->device->dev, "%s: Entry\n", __func__);
@@ -589,14 +587,25 @@ static void tsi721_free_chan_resources(struct dma_chan *dchan)
BUG_ON(!list_empty(&bdma_chan->active_list));
BUG_ON(!list_empty(&bdma_chan->queue));
- tasklet_disable(&bdma_chan->tasklet);
+ tsi721_bdma_interrupt_enable(bdma_chan, 0);
+ bdma_chan->active = false;
+
+#ifdef CONFIG_PCI_MSI
+ if (priv->flags & TSI721_USING_MSIX) {
+ synchronize_irq(priv->msix[TSI721_VECT_DMA0_DONE +
+ bdma_chan->id].vector);
+ synchronize_irq(priv->msix[TSI721_VECT_DMA0_INT +
+ bdma_chan->id].vector);
+ } else
+#endif
+ synchronize_irq(priv->pdev->irq);
+
+ tasklet_kill(&bdma_chan->tasklet);
spin_lock_bh(&bdma_chan->lock);
list_splice_init(&bdma_chan->free_list, &list);
spin_unlock_bh(&bdma_chan->lock);
- tsi721_bdma_interrupt_enable(bdma_chan, 0);
-
#ifdef CONFIG_PCI_MSI
if (priv->flags & TSI721_USING_MSIX) {
free_irq(priv->msix[TSI721_VECT_DMA0_DONE +
@@ -790,6 +799,7 @@ int tsi721_register_dma(struct tsi721_device *priv)
bdma_chan->dchan.cookie = 1;
bdma_chan->dchan.chan_id = i;
bdma_chan->id = i;
+ bdma_chan->active = false;
spin_lock_init(&bdma_chan->lock);
@@ -799,7 +809,6 @@ int tsi721_register_dma(struct tsi721_device *priv)
tasklet_init(&bdma_chan->tasklet, tsi721_dma_tasklet,
(unsigned long)bdma_chan);
- tasklet_disable(&bdma_chan->tasklet);
list_add_tail(&bdma_chan->dchan.device_node,
&mport->dma.channels);
}
diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c
index d333f7eac106..7a721d67e6ac 100644
--- a/drivers/regulator/88pm800.c
+++ b/drivers/regulator/88pm800.c
@@ -310,10 +310,8 @@ static int pm800_regulator_probe(struct platform_device *pdev)
pm800_data = devm_kzalloc(&pdev->dev, sizeof(*pm800_data),
GFP_KERNEL);
- if (!pm800_data) {
- dev_err(&pdev->dev, "Failed to allocate pm800_regualtors");
+ if (!pm800_data)
return -ENOMEM;
- }
pm800_data->map = chip->subchip->regmap_power;
pm800_data->chip = chip;
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c
index f704d83c93c4..337634ad0562 100644
--- a/drivers/regulator/88pm8607.c
+++ b/drivers/regulator/88pm8607.c
@@ -2,7 +2,7 @@
* Regulators driver for Marvell 88PM8607
*
* Copyright (C) 2009 Marvell International Ltd.
- * Haojian Zhuang <haojian.zhuang@marvell.com>
+ * Haojian Zhuang <haojian.zhuang@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
@@ -78,7 +78,7 @@ static const unsigned int BUCK2_suspend_table[] = {
};
static const unsigned int BUCK3_table[] = {
- 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000,
+ 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000,
200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000,
400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000,
600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000,
@@ -89,7 +89,7 @@ static const unsigned int BUCK3_table[] = {
};
static const unsigned int BUCK3_suspend_table[] = {
- 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000,
+ 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000,
200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000,
400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000,
600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000,
@@ -322,7 +322,7 @@ static int pm8607_regulator_dt_init(struct platform_device *pdev,
nproot = of_node_get(pdev->dev.parent->of_node);
if (!nproot)
return -ENODEV;
- nproot = of_find_node_by_name(nproot, "regulators");
+ nproot = of_get_child_by_name(nproot, "regulators");
if (!nproot) {
dev_err(&pdev->dev, "failed to find regulators node\n");
return -ENODEV;
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 6a7932822e37..1cd8584a7b88 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -139,6 +139,14 @@ config REGULATOR_AS3722
AS3722 PMIC. This will enable support for all the software
controllable DCDC/LDO regulators.
+config REGULATOR_BCM590XX
+ tristate "Broadcom BCM590xx PMU Regulators"
+ depends on MFD_BCM590XX
+ help
+ This driver provides support for the voltage regulators on the
+ BCM590xx PMUs. This will enable support for the software
+ controllable LDO/Switching regulators.
+
config REGULATOR_DA903X
tristate "Dialog Semiconductor DA9030/DA9034 regulators"
depends on PMIC_DA903X
@@ -399,12 +407,12 @@ config REGULATOR_PCF50633
on PCF50633
config REGULATOR_PFUZE100
- tristate "Freescale PFUZE100 regulator driver"
+ tristate "Freescale PFUZE100/PFUZE200 regulator driver"
depends on I2C
select REGMAP_I2C
help
- Say y here to support the regulators found on the Freescale PFUZE100
- PMIC.
+ Say y here to support the regulators found on the Freescale
+ PFUZE100/PFUZE200 PMIC.
config REGULATOR_RC5T583
tristate "RICOH RC5T583 Power regulators"
@@ -416,13 +424,21 @@ config REGULATOR_RC5T583
through regulator interface. The device supports multiple DCDC/LDO
outputs which can be controlled by i2c communication.
+config REGULATOR_S2MPA01
+ tristate "Samsung S2MPA01 voltage regulator"
+ depends on MFD_SEC_CORE
+ help
+ This driver controls Samsung S2MPA01 voltage output regulator
+ via I2C bus. S2MPA01 has 10 Bucks and 26 LDO outputs.
+
config REGULATOR_S2MPS11
- tristate "Samsung S2MPS11 voltage regulator"
+ tristate "Samsung S2MPS11/S2MPS14 voltage regulator"
depends on MFD_SEC_CORE
help
- This driver supports a Samsung S2MPS11 voltage output regulator
- via I2C bus. S2MPS11 is comprised of high efficient Buck converters
- including Dual-Phase Buck converter, Buck-Boost converter, various LDOs.
+ This driver supports a Samsung S2MPS11/S2MPS14 voltage output
+ regulator via I2C bus. The chip is comprised of high efficient Buck
+ converters including Dual-Phase Buck converter, Buck-Boost converter,
+ various LDOs.
config REGULATOR_S5M8767
tristate "Samsung S5M8767A voltage regulator"
@@ -432,6 +448,12 @@ 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_ST_PWM
+ tristate "STMicroelectronics PWM voltage regulator"
+ depends on ARCH_STI
+ help
+ This driver supports ST's PWM controlled voltage regulators.
+
config REGULATOR_TI_ABB
tristate "TI Adaptive Body Bias on-chip LDO"
depends on ARCH_OMAP
@@ -513,6 +535,15 @@ config REGULATOR_TPS65217
voltage regulators. It supports software based voltage control
for different voltage domains
+config REGULATOR_TPS65218
+ tristate "TI TPS65218 Power regulators"
+ depends on MFD_TPS65218 && OF
+ help
+ This driver supports TPS65218 voltage regulator chips. TPS65218
+ provides six step-down converters and one general-purpose LDO
+ voltage regulators. It supports software based voltage control
+ for different voltage domains
+
config REGULATOR_TPS6524X
tristate "TI TPS6524X Power regulators"
depends on SPI
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 979f9ddcf259..f0fe0c50b59c 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o
obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o
obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
+obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
obj-$(CONFIG_REGULATOR_DA9055) += da9055-regulator.o
@@ -57,8 +58,10 @@ 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_S2MPA01) += s2mpa01.o
obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
+obj-$(CONFIG_REGULATOR_ST_PWM) += st-pwm.o
obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
@@ -67,6 +70,7 @@ obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
obj-$(CONFIG_REGULATOR_TPS65090) += tps65090-regulator.o
obj-$(CONFIG_REGULATOR_TPS65217) += tps65217-regulator.o
+obj-$(CONFIG_REGULATOR_TPS65218) += tps65218-regulator.o
obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o
obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o
obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c
index f70a9bfa5ff2..c873ee0082cf 100644
--- a/drivers/regulator/aat2870-regulator.c
+++ b/drivers/regulator/aat2870-regulator.c
@@ -99,6 +99,7 @@ static int aat2870_ldo_is_enabled(struct regulator_dev *rdev)
static struct regulator_ops aat2870_ldo_ops = {
.list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
.set_voltage_sel = aat2870_ldo_set_voltage_sel,
.get_voltage_sel = aat2870_ldo_get_voltage_sel,
.enable = aat2870_ldo_enable,
diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c
index 084cc0819a52..b92d7dd01a18 100644
--- a/drivers/regulator/act8865-regulator.c
+++ b/drivers/regulator/act8865-regulator.c
@@ -62,7 +62,6 @@
#define ACT8865_VOLTAGE_NUM 64
struct act8865 {
- struct regulator_dev *rdev[ACT8865_REG_NUM];
struct regmap *regmap;
};
@@ -213,7 +212,7 @@ static int act8865_pdata_from_dt(struct device *dev,
struct device_node *np;
struct act8865_regulator_data *regulator;
- np = of_find_node_by_name(dev->of_node, "regulators");
+ np = of_get_child_by_name(dev->of_node, "regulators");
if (!np) {
dev_err(dev, "missing 'regulators' subnode in DT\n");
return -EINVAL;
@@ -221,17 +220,15 @@ static int act8865_pdata_from_dt(struct device *dev,
matched = of_regulator_match(dev, np,
act8865_matches, ARRAY_SIZE(act8865_matches));
+ of_node_put(np);
if (matched <= 0)
return matched;
pdata->regulators = devm_kzalloc(dev,
sizeof(struct act8865_regulator_data) *
ARRAY_SIZE(act8865_matches), GFP_KERNEL);
- if (!pdata->regulators) {
- dev_err(dev, "%s: failed to allocate act8865 registor\n",
- __func__);
+ if (!pdata->regulators)
return -ENOMEM;
- }
pdata->num_regulators = matched;
regulator = pdata->regulators;
@@ -258,7 +255,7 @@ static inline int act8865_pdata_from_dt(struct device *dev,
static int act8865_pmic_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
- struct regulator_dev **rdev;
+ struct regulator_dev *rdev;
struct device *dev = &client->dev;
struct act8865_platform_data *pdata = dev_get_platdata(dev);
struct regulator_config config = { };
@@ -292,8 +289,6 @@ static int act8865_pmic_probe(struct i2c_client *client,
if (!act8865)
return -ENOMEM;
- rdev = act8865->rdev;
-
act8865->regmap = devm_regmap_init_i2c(client, &act8865_regmap_config);
if (IS_ERR(act8865->regmap)) {
error = PTR_ERR(act8865->regmap);
@@ -313,12 +308,12 @@ static int act8865_pmic_probe(struct i2c_client *client,
config.driver_data = act8865;
config.regmap = act8865->regmap;
- rdev[i] = devm_regulator_register(&client->dev,
- &act8865_reg[i], &config);
- if (IS_ERR(rdev[i])) {
+ rdev = devm_regulator_register(&client->dev, &act8865_reg[i],
+ &config);
+ if (IS_ERR(rdev)) {
dev_err(dev, "failed to register %s\n",
act8865_reg[id].name);
- return PTR_ERR(rdev[i]);
+ return PTR_ERR(rdev);
}
}
diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
index 862e63e451d0..7c397bb81e01 100644
--- a/drivers/regulator/anatop-regulator.c
+++ b/drivers/regulator/anatop-regulator.c
@@ -34,6 +34,9 @@
#define LDO_RAMP_UP_UNIT_IN_CYCLES 64 /* 64 cycles per step */
#define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* cycle based on 24M OSC */
+#define LDO_POWER_GATE 0x00
+#define LDO_FET_FULL_ON 0x1f
+
struct anatop_regulator {
const char *name;
u32 control_reg;
@@ -48,19 +51,10 @@ struct anatop_regulator {
int max_voltage;
struct regulator_desc rdesc;
struct regulator_init_data *initdata;
+ bool bypass;
+ int sel;
};
-static int anatop_regmap_set_voltage_sel(struct regulator_dev *reg,
- unsigned selector)
-{
- struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
-
- if (!anatop_reg->control_reg)
- return -ENOTSUPP;
-
- return regulator_set_voltage_sel_regmap(reg, selector);
-}
-
static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg,
unsigned int old_sel,
unsigned int new_sel)
@@ -87,22 +81,99 @@ static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg,
return ret;
}
-static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg)
+static int anatop_regmap_enable(struct regulator_dev *reg)
{
struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+ int sel;
- if (!anatop_reg->control_reg)
- return -ENOTSUPP;
+ sel = anatop_reg->bypass ? LDO_FET_FULL_ON : anatop_reg->sel;
+ return regulator_set_voltage_sel_regmap(reg, sel);
+}
+
+static int anatop_regmap_disable(struct regulator_dev *reg)
+{
+ return regulator_set_voltage_sel_regmap(reg, LDO_POWER_GATE);
+}
+
+static int anatop_regmap_is_enabled(struct regulator_dev *reg)
+{
+ return regulator_get_voltage_sel_regmap(reg) != LDO_POWER_GATE;
+}
+
+static int anatop_regmap_core_set_voltage_sel(struct regulator_dev *reg,
+ unsigned selector)
+{
+ struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+ int ret;
+
+ if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg)) {
+ anatop_reg->sel = selector;
+ return 0;
+ }
+
+ ret = regulator_set_voltage_sel_regmap(reg, selector);
+ if (!ret)
+ anatop_reg->sel = selector;
+ return ret;
+}
+
+static int anatop_regmap_core_get_voltage_sel(struct regulator_dev *reg)
+{
+ struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+
+ if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg))
+ return anatop_reg->sel;
return regulator_get_voltage_sel_regmap(reg);
}
+static int anatop_regmap_get_bypass(struct regulator_dev *reg, bool *enable)
+{
+ struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+ int sel;
+
+ sel = regulator_get_voltage_sel_regmap(reg);
+ if (sel == LDO_FET_FULL_ON)
+ WARN_ON(!anatop_reg->bypass);
+ else if (sel != LDO_POWER_GATE)
+ WARN_ON(anatop_reg->bypass);
+
+ *enable = anatop_reg->bypass;
+ return 0;
+}
+
+static int anatop_regmap_set_bypass(struct regulator_dev *reg, bool enable)
+{
+ struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+ int sel;
+
+ if (enable == anatop_reg->bypass)
+ return 0;
+
+ sel = enable ? LDO_FET_FULL_ON : anatop_reg->sel;
+ anatop_reg->bypass = enable;
+
+ return regulator_set_voltage_sel_regmap(reg, sel);
+}
+
static struct regulator_ops anatop_rops = {
- .set_voltage_sel = anatop_regmap_set_voltage_sel,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+};
+
+static struct regulator_ops anatop_core_rops = {
+ .enable = anatop_regmap_enable,
+ .disable = anatop_regmap_disable,
+ .is_enabled = anatop_regmap_is_enabled,
+ .set_voltage_sel = anatop_regmap_core_set_voltage_sel,
.set_voltage_time_sel = anatop_regmap_set_voltage_time_sel,
- .get_voltage_sel = anatop_regmap_get_voltage_sel,
+ .get_voltage_sel = anatop_regmap_core_get_voltage_sel,
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
+ .get_bypass = anatop_regmap_get_bypass,
+ .set_bypass = anatop_regmap_set_bypass,
};
static int anatop_regulator_probe(struct platform_device *pdev)
@@ -116,6 +187,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
struct regulator_init_data *initdata;
struct regulator_config config = { };
int ret = 0;
+ u32 val;
initdata = of_get_regulator_init_data(dev, np);
sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL);
@@ -125,7 +197,6 @@ static int anatop_regulator_probe(struct platform_device *pdev)
sreg->name = of_get_property(np, "regulator-name", NULL);
rdesc = &sreg->rdesc;
rdesc->name = sreg->name;
- rdesc->ops = &anatop_rops;
rdesc->type = REGULATOR_VOLTAGE;
rdesc->owner = THIS_MODULE;
@@ -197,6 +268,25 @@ static int anatop_regulator_probe(struct platform_device *pdev)
config.of_node = pdev->dev.of_node;
config.regmap = sreg->anatop;
+ /* Only core regulators have the ramp up delay configuration. */
+ if (sreg->control_reg && sreg->delay_bit_width) {
+ rdesc->ops = &anatop_core_rops;
+
+ ret = regmap_read(config.regmap, rdesc->vsel_reg, &val);
+ if (ret) {
+ dev_err(dev, "failed to read initial state\n");
+ return ret;
+ }
+
+ sreg->sel = (val & rdesc->vsel_mask) >> sreg->vol_bit_shift;
+ if (sreg->sel == LDO_FET_FULL_ON) {
+ sreg->sel = 0;
+ sreg->bypass = true;
+ }
+ } else {
+ rdesc->ops = &anatop_rops;
+ }
+
/* register regulator */
rdev = devm_regulator_register(dev, rdesc, &config);
if (IS_ERR(rdev)) {
diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c
index 4f6c2055f6b2..b1033d30b504 100644
--- a/drivers/regulator/arizona-ldo1.c
+++ b/drivers/regulator/arizona-ldo1.c
@@ -153,11 +153,9 @@ static const struct regulator_desc arizona_ldo1 = {
.vsel_reg = ARIZONA_LDO1_CONTROL_1,
.vsel_mask = ARIZONA_LDO1_VSEL_MASK,
- .bypass_reg = ARIZONA_LDO1_CONTROL_1,
- .bypass_mask = ARIZONA_LDO1_BYPASS,
.min_uV = 900000,
- .uV_step = 50000,
- .n_voltages = 7,
+ .uV_step = 25000,
+ .n_voltages = 13,
.enable_time = 500,
.owner = THIS_MODULE,
@@ -189,10 +187,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
int ret;
ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
- if (ldo1 == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!ldo1)
return -ENOMEM;
- }
ldo1->arizona = arizona;
@@ -203,6 +199,7 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
*/
switch (arizona->type) {
case WM5102:
+ case WM8997:
desc = &arizona_ldo1_hc;
ldo1->init_data = arizona_ldo1_dvfs;
break;
diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c
index 034ece707083..6fdd9bf6927f 100644
--- a/drivers/regulator/arizona-micsupp.c
+++ b/drivers/regulator/arizona-micsupp.c
@@ -204,10 +204,8 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
int ret;
micsupp = devm_kzalloc(&pdev->dev, sizeof(*micsupp), GFP_KERNEL);
- if (micsupp == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!micsupp)
return -ENOMEM;
- }
micsupp->arizona = arizona;
INIT_WORK(&micsupp->check_cp_work, arizona_micsupp_check_cp);
diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c
index c77a58478cca..b47283f91e2d 100644
--- a/drivers/regulator/as3711-regulator.c
+++ b/drivers/regulator/as3711-regulator.c
@@ -191,7 +191,7 @@ static int as3711_regulator_parse_dt(struct device *dev,
{
struct as3711_regulator_pdata *pdata = dev_get_platdata(dev);
struct device_node *regulators =
- of_find_node_by_name(dev->parent->of_node, "regulators");
+ of_get_child_by_name(dev->parent->of_node, "regulators");
struct of_regulator_match *match;
int ret, i;
@@ -221,7 +221,6 @@ static int as3711_regulator_probe(struct platform_device *pdev)
{
struct as3711_regulator_pdata *pdata = dev_get_platdata(&pdev->dev);
struct as3711 *as3711 = dev_get_drvdata(pdev->dev.parent);
- struct regulator_init_data *reg_data;
struct regulator_config config = {.dev = &pdev->dev,};
struct as3711_regulator *reg = NULL;
struct as3711_regulator *regs;
@@ -246,22 +245,14 @@ static int as3711_regulator_probe(struct platform_device *pdev)
regs = devm_kzalloc(&pdev->dev, AS3711_REGULATOR_NUM *
sizeof(struct as3711_regulator), GFP_KERNEL);
- if (!regs) {
- dev_err(&pdev->dev, "Memory allocation failed exiting..\n");
+ if (!regs)
return -ENOMEM;
- }
for (id = 0, ri = as3711_reg_info; id < AS3711_REGULATOR_NUM; ++id, ri++) {
- reg_data = pdata->init_data[id];
-
- /* No need to register if there is no regulator data */
- if (!reg_data)
- continue;
-
reg = &regs[id];
reg->reg_info = ri;
- config.init_data = reg_data;
+ config.init_data = pdata->init_data[id];
config.driver_data = reg;
config.regmap = as3711->regmap;
config.of_node = of_node[id];
diff --git a/drivers/regulator/as3722-regulator.c b/drivers/regulator/as3722-regulator.c
index 8b17d786cb71..85585219ce82 100644
--- a/drivers/regulator/as3722-regulator.c
+++ b/drivers/regulator/as3722-regulator.c
@@ -719,6 +719,7 @@ static int as3722_get_regulator_dt_data(struct platform_device *pdev,
ret = of_regulator_match(&pdev->dev, np, as3722_regulator_matches,
ARRAY_SIZE(as3722_regulator_matches));
+ of_node_put(np);
if (ret < 0) {
dev_err(&pdev->dev, "Parsing of regulator node failed: %d\n",
ret);
diff --git a/drivers/regulator/bcm590xx-regulator.c b/drivers/regulator/bcm590xx-regulator.c
new file mode 100644
index 000000000000..ab08ca7cfb08
--- /dev/null
+++ b/drivers/regulator/bcm590xx-regulator.c
@@ -0,0 +1,403 @@
+/*
+ * Broadcom BCM590xx regulator driver
+ *
+ * Copyright 2014 Linaro Limited
+ * Author: Matt Porter <mporter@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mfd/bcm590xx.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/slab.h>
+
+/* Register defs */
+#define BCM590XX_RFLDOPMCTRL1 0x60
+#define BCM590XX_IOSR1PMCTRL1 0x7a
+#define BCM590XX_IOSR2PMCTRL1 0x7c
+#define BCM590XX_CSRPMCTRL1 0x7e
+#define BCM590XX_SDSR1PMCTRL1 0x82
+#define BCM590XX_SDSR2PMCTRL1 0x86
+#define BCM590XX_MSRPMCTRL1 0x8a
+#define BCM590XX_VSRPMCTRL1 0x8e
+#define BCM590XX_REG_ENABLE BIT(7)
+
+#define BCM590XX_RFLDOCTRL 0x96
+#define BCM590XX_CSRVOUT1 0xc0
+#define BCM590XX_LDO_VSEL_MASK GENMASK(5, 3)
+#define BCM590XX_SR_VSEL_MASK GENMASK(5, 0)
+
+/* LDO regulator IDs */
+#define BCM590XX_REG_RFLDO 0
+#define BCM590XX_REG_CAMLDO1 1
+#define BCM590XX_REG_CAMLDO2 2
+#define BCM590XX_REG_SIMLDO1 3
+#define BCM590XX_REG_SIMLDO2 4
+#define BCM590XX_REG_SDLDO 5
+#define BCM590XX_REG_SDXLDO 6
+#define BCM590XX_REG_MMCLDO1 7
+#define BCM590XX_REG_MMCLDO2 8
+#define BCM590XX_REG_AUDLDO 9
+#define BCM590XX_REG_MICLDO 10
+#define BCM590XX_REG_USBLDO 11
+#define BCM590XX_REG_VIBLDO 12
+
+/* DCDC regulator IDs */
+#define BCM590XX_REG_CSR 13
+#define BCM590XX_REG_IOSR1 14
+#define BCM590XX_REG_IOSR2 15
+#define BCM590XX_REG_MSR 16
+#define BCM590XX_REG_SDSR1 17
+#define BCM590XX_REG_SDSR2 18
+#define BCM590XX_REG_VSR 19
+
+#define BCM590XX_NUM_REGS 20
+
+#define BCM590XX_REG_IS_LDO(n) (n < BCM590XX_REG_CSR)
+
+struct bcm590xx_board {
+ struct regulator_init_data *bcm590xx_pmu_init_data[BCM590XX_NUM_REGS];
+};
+
+/* LDO group A: supported voltages in microvolts */
+static const unsigned int ldo_a_table[] = {
+ 1200000, 1800000, 2500000, 2700000, 2800000,
+ 2900000, 3000000, 3300000,
+};
+
+/* LDO group C: supported voltages in microvolts */
+static const unsigned int ldo_c_table[] = {
+ 3100000, 1800000, 2500000, 2700000, 2800000,
+ 2900000, 3000000, 3300000,
+};
+
+/* DCDC group CSR: supported voltages in microvolts */
+static const struct regulator_linear_range dcdc_csr_ranges[] = {
+ REGULATOR_LINEAR_RANGE(860000, 2, 50, 10000),
+ REGULATOR_LINEAR_RANGE(1360000, 51, 55, 20000),
+ REGULATOR_LINEAR_RANGE(900000, 56, 63, 0),
+};
+
+/* DCDC group IOSR1: supported voltages in microvolts */
+static const struct regulator_linear_range dcdc_iosr1_ranges[] = {
+ REGULATOR_LINEAR_RANGE(860000, 2, 51, 10000),
+ REGULATOR_LINEAR_RANGE(1500000, 52, 52, 0),
+ REGULATOR_LINEAR_RANGE(1800000, 53, 53, 0),
+ REGULATOR_LINEAR_RANGE(900000, 54, 63, 0),
+};
+
+/* DCDC group SDSR1: supported voltages in microvolts */
+static const struct regulator_linear_range dcdc_sdsr1_ranges[] = {
+ REGULATOR_LINEAR_RANGE(860000, 2, 50, 10000),
+ REGULATOR_LINEAR_RANGE(1340000, 51, 51, 0),
+ REGULATOR_LINEAR_RANGE(900000, 52, 63, 0),
+};
+
+struct bcm590xx_info {
+ const char *name;
+ const char *vin_name;
+ u8 n_voltages;
+ const unsigned int *volt_table;
+ u8 n_linear_ranges;
+ const struct regulator_linear_range *linear_ranges;
+};
+
+#define BCM590XX_REG_TABLE(_name, _table) \
+ { \
+ .name = #_name, \
+ .n_voltages = ARRAY_SIZE(_table), \
+ .volt_table = _table, \
+ }
+
+#define BCM590XX_REG_RANGES(_name, _ranges) \
+ { \
+ .name = #_name, \
+ .n_linear_ranges = ARRAY_SIZE(_ranges), \
+ .linear_ranges = _ranges, \
+ }
+
+static struct bcm590xx_info bcm590xx_regs[] = {
+ BCM590XX_REG_TABLE(rfldo, ldo_a_table),
+ BCM590XX_REG_TABLE(camldo1, ldo_c_table),
+ BCM590XX_REG_TABLE(camldo2, ldo_c_table),
+ BCM590XX_REG_TABLE(simldo1, ldo_a_table),
+ BCM590XX_REG_TABLE(simldo2, ldo_a_table),
+ BCM590XX_REG_TABLE(sdldo, ldo_c_table),
+ BCM590XX_REG_TABLE(sdxldo, ldo_a_table),
+ BCM590XX_REG_TABLE(mmcldo1, ldo_a_table),
+ BCM590XX_REG_TABLE(mmcldo2, ldo_a_table),
+ BCM590XX_REG_TABLE(audldo, ldo_a_table),
+ BCM590XX_REG_TABLE(micldo, ldo_a_table),
+ BCM590XX_REG_TABLE(usbldo, ldo_a_table),
+ BCM590XX_REG_TABLE(vibldo, ldo_c_table),
+ BCM590XX_REG_RANGES(csr, dcdc_csr_ranges),
+ BCM590XX_REG_RANGES(iosr1, dcdc_iosr1_ranges),
+ BCM590XX_REG_RANGES(iosr2, dcdc_iosr1_ranges),
+ BCM590XX_REG_RANGES(msr, dcdc_iosr1_ranges),
+ BCM590XX_REG_RANGES(sdsr1, dcdc_sdsr1_ranges),
+ BCM590XX_REG_RANGES(sdsr2, dcdc_iosr1_ranges),
+ BCM590XX_REG_RANGES(vsr, dcdc_iosr1_ranges),
+};
+
+struct bcm590xx_reg {
+ struct regulator_desc *desc;
+ struct bcm590xx *mfd;
+ struct bcm590xx_info **info;
+};
+
+static int bcm590xx_get_vsel_register(int id)
+{
+ if (BCM590XX_REG_IS_LDO(id))
+ return BCM590XX_RFLDOCTRL + id;
+ else
+ return BCM590XX_CSRVOUT1 + (id - BCM590XX_REG_CSR) * 3;
+}
+
+static int bcm590xx_get_enable_register(int id)
+{
+ int reg = 0;
+
+ if (BCM590XX_REG_IS_LDO(id))
+ reg = BCM590XX_RFLDOPMCTRL1 + id * 2;
+ else
+ switch (id) {
+ case BCM590XX_REG_CSR:
+ reg = BCM590XX_CSRPMCTRL1;
+ break;
+ case BCM590XX_REG_IOSR1:
+ reg = BCM590XX_IOSR1PMCTRL1;
+ break;
+ case BCM590XX_REG_IOSR2:
+ reg = BCM590XX_IOSR2PMCTRL1;
+ break;
+ case BCM590XX_REG_MSR:
+ reg = BCM590XX_MSRPMCTRL1;
+ break;
+ case BCM590XX_REG_SDSR1:
+ reg = BCM590XX_SDSR1PMCTRL1;
+ break;
+ case BCM590XX_REG_SDSR2:
+ reg = BCM590XX_SDSR2PMCTRL1;
+ break;
+ };
+
+ return reg;
+}
+
+static struct regulator_ops bcm590xx_ops_ldo = {
+ .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 = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_iterate,
+};
+
+static struct regulator_ops bcm590xx_ops_dcdc = {
+ .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 = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+};
+
+#define BCM590XX_MATCH(_name, _id) \
+ { \
+ .name = #_name, \
+ .driver_data = (void *)&bcm590xx_regs[BCM590XX_REG_##_id], \
+ }
+
+static struct of_regulator_match bcm590xx_matches[] = {
+ BCM590XX_MATCH(rfldo, RFLDO),
+ BCM590XX_MATCH(camldo1, CAMLDO1),
+ BCM590XX_MATCH(camldo2, CAMLDO2),
+ BCM590XX_MATCH(simldo1, SIMLDO1),
+ BCM590XX_MATCH(simldo2, SIMLDO2),
+ BCM590XX_MATCH(sdldo, SDLDO),
+ BCM590XX_MATCH(sdxldo, SDXLDO),
+ BCM590XX_MATCH(mmcldo1, MMCLDO1),
+ BCM590XX_MATCH(mmcldo2, MMCLDO2),
+ BCM590XX_MATCH(audldo, AUDLDO),
+ BCM590XX_MATCH(micldo, MICLDO),
+ BCM590XX_MATCH(usbldo, USBLDO),
+ BCM590XX_MATCH(vibldo, VIBLDO),
+ BCM590XX_MATCH(csr, CSR),
+ BCM590XX_MATCH(iosr1, IOSR1),
+ BCM590XX_MATCH(iosr2, IOSR2),
+ BCM590XX_MATCH(msr, MSR),
+ BCM590XX_MATCH(sdsr1, SDSR1),
+ BCM590XX_MATCH(sdsr2, SDSR2),
+ BCM590XX_MATCH(vsr, VSR),
+};
+
+static struct bcm590xx_board *bcm590xx_parse_dt_reg_data(
+ struct platform_device *pdev,
+ struct of_regulator_match **bcm590xx_reg_matches)
+{
+ struct bcm590xx_board *data;
+ struct device_node *np = pdev->dev.parent->of_node;
+ struct device_node *regulators;
+ struct of_regulator_match *matches = bcm590xx_matches;
+ int count = ARRAY_SIZE(bcm590xx_matches);
+ int idx = 0;
+ int ret;
+
+ if (!np) {
+ dev_err(&pdev->dev, "of node not found\n");
+ return NULL;
+ }
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&pdev->dev, "failed to allocate regulator board data\n");
+ return NULL;
+ }
+
+ np = of_node_get(np);
+ regulators = of_get_child_by_name(np, "regulators");
+ if (!regulators) {
+ dev_warn(&pdev->dev, "regulator node not found\n");
+ return NULL;
+ }
+
+ ret = of_regulator_match(&pdev->dev, regulators, matches, count);
+ of_node_put(regulators);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
+ ret);
+ return NULL;
+ }
+
+ *bcm590xx_reg_matches = matches;
+
+ for (idx = 0; idx < count; idx++) {
+ if (!matches[idx].init_data || !matches[idx].of_node)
+ continue;
+
+ data->bcm590xx_pmu_init_data[idx] = matches[idx].init_data;
+ }
+
+ return data;
+}
+
+static int bcm590xx_probe(struct platform_device *pdev)
+{
+ struct bcm590xx *bcm590xx = dev_get_drvdata(pdev->dev.parent);
+ struct bcm590xx_board *pmu_data = NULL;
+ struct bcm590xx_reg *pmu;
+ struct regulator_config config = { };
+ struct bcm590xx_info *info;
+ struct regulator_init_data *reg_data;
+ struct regulator_dev *rdev;
+ struct of_regulator_match *bcm590xx_reg_matches = NULL;
+ int i;
+
+ pmu_data = bcm590xx_parse_dt_reg_data(pdev,
+ &bcm590xx_reg_matches);
+
+ pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL);
+ if (!pmu) {
+ dev_err(&pdev->dev, "Memory allocation failed for pmu\n");
+ return -ENOMEM;
+ }
+
+ pmu->mfd = bcm590xx;
+
+ platform_set_drvdata(pdev, pmu);
+
+ pmu->desc = devm_kzalloc(&pdev->dev, BCM590XX_NUM_REGS *
+ sizeof(struct regulator_desc), GFP_KERNEL);
+ if (!pmu->desc) {
+ dev_err(&pdev->dev, "Memory alloc fails for desc\n");
+ return -ENOMEM;
+ }
+
+ pmu->info = devm_kzalloc(&pdev->dev, BCM590XX_NUM_REGS *
+ sizeof(struct bcm590xx_info *), GFP_KERNEL);
+ if (!pmu->info) {
+ dev_err(&pdev->dev, "Memory alloc fails for info\n");
+ return -ENOMEM;
+ }
+
+ info = bcm590xx_regs;
+
+ for (i = 0; i < BCM590XX_NUM_REGS; i++, info++) {
+ if (pmu_data)
+ reg_data = pmu_data->bcm590xx_pmu_init_data[i];
+ else
+ reg_data = NULL;
+
+ /* Register the regulators */
+ pmu->info[i] = info;
+
+ pmu->desc[i].name = info->name;
+ pmu->desc[i].supply_name = info->vin_name;
+ pmu->desc[i].id = i;
+ pmu->desc[i].volt_table = info->volt_table;
+ pmu->desc[i].n_voltages = info->n_voltages;
+ pmu->desc[i].linear_ranges = info->linear_ranges;
+ pmu->desc[i].n_linear_ranges = info->n_linear_ranges;
+
+ if (BCM590XX_REG_IS_LDO(i)) {
+ pmu->desc[i].ops = &bcm590xx_ops_ldo;
+ pmu->desc[i].vsel_mask = BCM590XX_LDO_VSEL_MASK;
+ } else {
+ pmu->desc[i].ops = &bcm590xx_ops_dcdc;
+ pmu->desc[i].vsel_mask = BCM590XX_SR_VSEL_MASK;
+ }
+
+ pmu->desc[i].vsel_reg = bcm590xx_get_vsel_register(i);
+ pmu->desc[i].enable_is_inverted = true;
+ pmu->desc[i].enable_mask = BCM590XX_REG_ENABLE;
+ pmu->desc[i].enable_reg = bcm590xx_get_enable_register(i);
+ pmu->desc[i].type = REGULATOR_VOLTAGE;
+ pmu->desc[i].owner = THIS_MODULE;
+
+ config.dev = bcm590xx->dev;
+ config.init_data = reg_data;
+ config.driver_data = pmu;
+ config.regmap = bcm590xx->regmap;
+
+ if (bcm590xx_reg_matches)
+ config.of_node = bcm590xx_reg_matches[i].of_node;
+
+ rdev = devm_regulator_register(&pdev->dev, &pmu->desc[i],
+ &config);
+ if (IS_ERR(rdev)) {
+ dev_err(bcm590xx->dev,
+ "failed to register %s regulator\n",
+ pdev->name);
+ return PTR_ERR(rdev);
+ }
+ }
+
+ return 0;
+}
+
+static struct platform_driver bcm590xx_regulator_driver = {
+ .driver = {
+ .name = "bcm590xx-vregs",
+ .owner = THIS_MODULE,
+ },
+ .probe = bcm590xx_probe,
+};
+module_platform_driver(bcm590xx_regulator_driver);
+
+MODULE_AUTHOR("Matt Porter <mporter@linaro.org>");
+MODULE_DESCRIPTION("BCM590xx voltage regulator driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:bcm590xx-vregs");
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 16a309e5c024..9a09f3cdbabb 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -953,6 +953,8 @@ static int machine_constraints_current(struct regulator_dev *rdev,
return 0;
}
+static int _regulator_do_enable(struct regulator_dev *rdev);
+
/**
* set_machine_constraints - sets regulator constraints
* @rdev: regulator source
@@ -1013,10 +1015,9 @@ static int set_machine_constraints(struct regulator_dev *rdev,
/* If the constraints say the regulator should be on at this point
* and we have control then make sure it is enabled.
*/
- if ((rdev->constraints->always_on || rdev->constraints->boot_on) &&
- ops->enable) {
- ret = ops->enable(rdev);
- if (ret < 0) {
+ if (rdev->constraints->always_on || rdev->constraints->boot_on) {
+ ret = _regulator_do_enable(rdev);
+ if (ret < 0 && ret != -EINVAL) {
rdev_err(rdev, "failed to enable\n");
goto out;
}
@@ -1359,7 +1360,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
goto found;
/* Don't log an error when called from regulator_get_optional() */
} else if (!have_full_constraints() || exclusive) {
- dev_err(dev, "dummy supplies not allowed\n");
+ dev_warn(dev, "dummy supplies not allowed\n");
}
mutex_unlock(&regulator_list_mutex);
@@ -1907,8 +1908,6 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
trace_regulator_disable_complete(rdev_get_name(rdev));
- _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
- NULL);
return 0;
}
@@ -1932,6 +1931,8 @@ static int _regulator_disable(struct regulator_dev *rdev)
rdev_err(rdev, "failed to disable\n");
return ret;
}
+ _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
+ NULL);
}
rdev->use_count = 0;
@@ -1984,20 +1985,16 @@ static int _regulator_force_disable(struct regulator_dev *rdev)
{
int ret = 0;
- /* force disable */
- if (rdev->desc->ops->disable) {
- /* ah well, who wants to live forever... */
- ret = rdev->desc->ops->disable(rdev);
- if (ret < 0) {
- rdev_err(rdev, "failed to force disable\n");
- return ret;
- }
- /* notify other consumers that power has been forced off */
- _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
- REGULATOR_EVENT_DISABLE, NULL);
+ ret = _regulator_do_disable(rdev);
+ if (ret < 0) {
+ rdev_err(rdev, "failed to force disable\n");
+ return ret;
}
- return ret;
+ _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
+ REGULATOR_EVENT_DISABLE, NULL);
+
+ return 0;
}
/**
@@ -2141,7 +2138,7 @@ EXPORT_SYMBOL_GPL(regulator_is_enabled);
* @regulator: regulator source
*
* Returns positive if the regulator driver backing the source/client
- * can change its voltage, false otherwise. Usefull for detecting fixed
+ * can change its voltage, false otherwise. Useful for detecting fixed
* or dummy regulators and disabling voltage change logic in the client
* driver.
*/
@@ -2402,6 +2399,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
struct regulator_dev *rdev = regulator->rdev;
int ret = 0;
int old_min_uV, old_max_uV;
+ int current_uV;
mutex_lock(&rdev->mutex);
@@ -2412,6 +2410,19 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
if (regulator->min_uV == min_uV && regulator->max_uV == max_uV)
goto out;
+ /* If we're trying to set a range that overlaps the current voltage,
+ * return succesfully even though the regulator does not support
+ * changing the voltage.
+ */
+ if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
+ current_uV = _regulator_get_voltage(rdev);
+ if (min_uV <= current_uV && current_uV <= max_uV) {
+ regulator->min_uV = min_uV;
+ regulator->max_uV = max_uV;
+ goto out;
+ }
+ }
+
/* sanity check */
if (!rdev->desc->ops->set_voltage &&
!rdev->desc->ops->set_voltage_sel) {
@@ -3630,23 +3641,18 @@ int regulator_suspend_finish(void)
mutex_lock(&regulator_list_mutex);
list_for_each_entry(rdev, &regulator_list, list) {
- struct regulator_ops *ops = rdev->desc->ops;
-
mutex_lock(&rdev->mutex);
- if ((rdev->use_count > 0 || rdev->constraints->always_on) &&
- ops->enable) {
- error = ops->enable(rdev);
+ if (rdev->use_count > 0 || rdev->constraints->always_on) {
+ error = _regulator_do_enable(rdev);
if (error)
ret = error;
} else {
if (!have_full_constraints())
goto unlock;
- if (!ops->disable)
- goto unlock;
if (!_regulator_is_enabled(rdev))
goto unlock;
- error = ops->disable(rdev);
+ error = _regulator_do_disable(rdev);
if (error)
ret = error;
}
@@ -3820,7 +3826,7 @@ static int __init regulator_init_complete(void)
ops = rdev->desc->ops;
c = rdev->constraints;
- if (!ops->disable || (c && c->always_on))
+ if (c && c->always_on)
continue;
mutex_lock(&rdev->mutex);
@@ -3841,7 +3847,7 @@ static int __init regulator_init_complete(void)
/* We log since this may kill the system if it
* goes wrong. */
rdev_info(rdev, "disabling\n");
- ret = ops->disable(rdev);
+ ret = _regulator_do_disable(rdev);
if (ret != 0)
rdev_err(rdev, "couldn't disable: %d\n", ret);
} else {
diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c
index 3adeaeffc485..fdb6ea8ae7e6 100644
--- a/drivers/regulator/da9052-regulator.c
+++ b/drivers/regulator/da9052-regulator.c
@@ -240,6 +240,31 @@ static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev,
return ret;
}
+static int da9052_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
+ unsigned int old_sel,
+ unsigned int new_sel)
+{
+ struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
+ struct da9052_regulator_info *info = regulator->info;
+ int id = rdev_get_id(rdev);
+ int ret = 0;
+
+ /* The DVC controlled LDOs and DCDCs ramp with 6.25mV/µs after enabling
+ * the activate bit.
+ */
+ switch (id) {
+ case DA9052_ID_BUCK1:
+ case DA9052_ID_BUCK2:
+ case DA9052_ID_BUCK3:
+ case DA9052_ID_LDO2:
+ case DA9052_ID_LDO3:
+ ret = (new_sel - old_sel) * info->step_uV / 6250;
+ break;
+ }
+
+ return ret;
+}
+
static struct regulator_ops da9052_dcdc_ops = {
.get_current_limit = da9052_dcdc_get_current_limit,
.set_current_limit = da9052_dcdc_set_current_limit,
@@ -248,6 +273,7 @@ static struct regulator_ops da9052_dcdc_ops = {
.map_voltage = da9052_map_voltage,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = da9052_regulator_set_voltage_sel,
+ .set_voltage_time_sel = da9052_regulator_set_voltage_time_sel,
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@@ -258,6 +284,7 @@ static struct regulator_ops da9052_ldo_ops = {
.map_voltage = da9052_map_voltage,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = da9052_regulator_set_voltage_sel,
+ .set_voltage_time_sel = da9052_regulator_set_voltage_time_sel,
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@@ -401,7 +428,7 @@ static int da9052_regulator_probe(struct platform_device *pdev)
if (!nproot)
return -ENODEV;
- nproot = of_find_node_by_name(nproot, "regulators");
+ nproot = of_get_child_by_name(nproot, "regulators");
if (!nproot)
return -ENODEV;
diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c
index 7f340206d329..9516317e1a9f 100644
--- a/drivers/regulator/da9055-regulator.c
+++ b/drivers/regulator/da9055-regulator.c
@@ -19,6 +19,8 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
+#include <linux/of.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/mfd/da9055/core.h>
#include <linux/mfd/da9055/reg.h>
@@ -446,6 +448,9 @@ static int da9055_gpio_init(struct da9055_regulator *regulator,
struct da9055_regulator_info *info = regulator->info;
int ret = 0;
+ if (!pdata)
+ return 0;
+
if (pdata->gpio_ren && pdata->gpio_ren[id]) {
char name[18];
int gpio_mux = pdata->gpio_ren[id];
@@ -530,6 +535,59 @@ static inline struct da9055_regulator_info *find_regulator_info(int id)
return NULL;
}
+#ifdef CONFIG_OF
+static struct of_regulator_match da9055_reg_matches[] = {
+ { .name = "BUCK1", },
+ { .name = "BUCK2", },
+ { .name = "LDO1", },
+ { .name = "LDO2", },
+ { .name = "LDO3", },
+ { .name = "LDO4", },
+ { .name = "LDO5", },
+ { .name = "LDO6", },
+};
+
+static int da9055_regulator_dt_init(struct platform_device *pdev,
+ struct da9055_regulator *regulator,
+ struct regulator_config *config,
+ int regid)
+{
+ struct device_node *nproot, *np;
+ int ret;
+
+ nproot = of_node_get(pdev->dev.parent->of_node);
+ if (!nproot)
+ return -ENODEV;
+
+ np = of_get_child_by_name(nproot, "regulators");
+ if (!np)
+ return -ENODEV;
+
+ ret = of_regulator_match(&pdev->dev, np, &da9055_reg_matches[regid], 1);
+ of_node_put(nproot);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error matching regulator: %d\n", ret);
+ return ret;
+ }
+
+ config->init_data = da9055_reg_matches[regid].init_data;
+ config->of_node = da9055_reg_matches[regid].of_node;
+
+ if (!config->of_node)
+ return -ENODEV;
+
+ return 0;
+}
+#else
+static inline int da9055_regulator_dt_init(struct platform_device *pdev,
+ struct da9055_regulator *regulator,
+ struct regulator_config *config,
+ int regid)
+{
+ return -ENODEV;
+}
+#endif /* CONFIG_OF */
+
static int da9055_regulator_probe(struct platform_device *pdev)
{
struct regulator_config config = { };
@@ -538,9 +596,6 @@ static int da9055_regulator_probe(struct platform_device *pdev)
struct da9055_pdata *pdata = dev_get_platdata(da9055->dev);
int ret, irq;
- if (pdata == NULL || pdata->regulators[pdev->id] == NULL)
- return -ENODEV;
-
regulator = devm_kzalloc(&pdev->dev, sizeof(struct da9055_regulator),
GFP_KERNEL);
if (!regulator)
@@ -557,8 +612,14 @@ static int da9055_regulator_probe(struct platform_device *pdev)
config.driver_data = regulator;
config.regmap = da9055->regmap;
- if (pdata && pdata->regulators)
+ if (pdata && pdata->regulators) {
config.init_data = pdata->regulators[pdev->id];
+ } else {
+ ret = da9055_regulator_dt_init(pdev, regulator, &config,
+ pdev->id);
+ if (ret < 0)
+ return ret;
+ }
ret = da9055_gpio_init(regulator, &config, pdata, pdev->id);
if (ret < 0)
@@ -576,7 +637,9 @@ static int da9055_regulator_probe(struct platform_device *pdev)
/* Only LDO 5 and 6 has got the over current interrupt */
if (pdev->id == DA9055_ID_LDO5 || pdev->id == DA9055_ID_LDO6) {
irq = platform_get_irq_byname(pdev, "REGULATOR");
- irq = regmap_irq_get_virq(da9055->irq_data, irq);
+ if (irq < 0)
+ return irq;
+
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
da9055_ldo5_6_oc_irq,
IRQF_TRIGGER_HIGH |
diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c
index 56727eb745df..7c9461d13313 100644
--- a/drivers/regulator/da9063-regulator.c
+++ b/drivers/regulator/da9063-regulator.c
@@ -1,3 +1,4 @@
+
/*
* Regulator driver for DA9063 PMIC series
*
@@ -60,7 +61,8 @@ struct da9063_regulator_info {
.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.n_voltages = (((max_mV) - (min_mV))/(step_mV) + 1 \
+ + (DA9063_V##regl_name##_BIAS)), \
.desc.enable_reg = DA9063_REG_##regl_name##_CONT, \
.desc.enable_mask = DA9063_LDO_EN, \
.desc.vsel_reg = DA9063_REG_V##regl_name##_A, \
@@ -363,7 +365,7 @@ static int da9063_set_suspend_voltage(struct regulator_dev *rdev, int uV)
sel = regulator_map_voltage_linear(rdev, uV, uV);
if (sel < 0)
- return -EINVAL;
+ return sel;
sel <<= ffs(rdev->desc->vsel_mask) - 1;
@@ -664,7 +666,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt(
struct device_node *node;
int i, n, num;
- node = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
+ node = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
if (!node) {
dev_err(&pdev->dev, "Regulators device node not found\n");
return ERR_PTR(-ENODEV);
@@ -672,6 +674,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt(
num = of_regulator_match(&pdev->dev, node, da9063_matches,
ARRAY_SIZE(da9063_matches));
+ of_node_put(node);
if (num < 0) {
dev_err(&pdev->dev, "Failed to match regulators\n");
return ERR_PTR(-EINVAL);
@@ -708,7 +711,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt(
struct platform_device *pdev,
struct of_regulator_match **da9063_reg_matches)
{
- da9063_reg_matches = NULL;
+ *da9063_reg_matches = NULL;
return ERR_PTR(-ENODEV);
}
#endif
@@ -754,7 +757,7 @@ static int da9063_regulator_probe(struct platform_device *pdev)
if (ret < 0) {
dev_err(&pdev->dev,
"Error while reading BUCKs configuration\n");
- return -EIO;
+ return ret;
}
bcores_merged = val & DA9063_BCORE_MERGE;
bmem_bio_merged = val & DA9063_BUCK_MERGE;
@@ -773,10 +776,8 @@ static int da9063_regulator_probe(struct platform_device *pdev)
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");
+ if (!regulators)
return -ENOMEM;
- }
regulators->n_regulators = n_regulators;
platform_set_drvdata(pdev, regulators);
diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c
index 6f5ecbe1132e..7a320dd11c46 100644
--- a/drivers/regulator/da9210-regulator.c
+++ b/drivers/regulator/da9210-regulator.c
@@ -134,11 +134,8 @@ static int da9210_i2c_probe(struct i2c_client *i2c,
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");
+ if (!chip)
return -ENOMEM;
- }
chip->regmap = devm_regmap_init_i2c(i2c, &da9210_regmap_config);
if (IS_ERR(chip->regmap)) {
diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c
index 846acf240e48..617c1adca816 100644
--- a/drivers/regulator/db8500-prcmu.c
+++ b/drivers/regulator/db8500-prcmu.c
@@ -263,6 +263,8 @@ dbx500_regulator_info[DB8500_NUM_REGULATORS] = {
.ops = &db8500_regulator_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
+ .fixed_uV = 1800000,
+ .n_voltages = 1,
},
.exclude_from_power_state = true,
},
diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c
index ce89f7848a57..2d16b9f16de7 100644
--- a/drivers/regulator/dbx500-prcmu.c
+++ b/drivers/regulator/dbx500-prcmu.c
@@ -78,6 +78,7 @@ static struct ux500_regulator_debug {
void ux500_regulator_suspend_debug(void)
{
int i;
+
for (i = 0; i < rdebug.num_regulators; i++)
rdebug.state_before_suspend[i] =
rdebug.regulator_array[i].is_enabled;
@@ -86,6 +87,7 @@ void ux500_regulator_suspend_debug(void)
void ux500_regulator_resume_debug(void)
{
int i;
+
for (i = 0; i < rdebug.num_regulators; i++)
rdebug.state_after_suspend[i] =
rdebug.regulator_array[i].is_enabled;
@@ -127,9 +129,9 @@ static int ux500_regulator_status_print(struct seq_file *s, void *p)
int i;
/* print dump header */
- err = seq_printf(s, "ux500-regulator status:\n");
+ err = seq_puts(s, "ux500-regulator status:\n");
if (err < 0)
- dev_err(dev, "seq_printf overflow\n");
+ dev_err(dev, "seq_puts overflow\n");
err = seq_printf(s, "%31s : %8s : %8s\n", "current",
"before", "after");
@@ -202,18 +204,12 @@ ux500_regulator_debug_init(struct platform_device *pdev,
rdebug.num_regulators = num_regulators;
rdebug.state_before_suspend = kzalloc(num_regulators, GFP_KERNEL);
- if (!rdebug.state_before_suspend) {
- dev_err(&pdev->dev,
- "could not allocate memory for saving state\n");
+ if (!rdebug.state_before_suspend)
goto exit_destroy_power_state;
- }
rdebug.state_after_suspend = kzalloc(num_regulators, GFP_KERNEL);
- if (!rdebug.state_after_suspend) {
- dev_err(&pdev->dev,
- "could not allocate memory for saving state\n");
+ if (!rdebug.state_after_suspend)
goto exit_free;
- }
dbx500_regulator_testcase(regulator_info, num_regulators);
return 0;
diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c
index df9f42524abb..2436db9e2ca3 100644
--- a/drivers/regulator/dummy.c
+++ b/drivers/regulator/dummy.c
@@ -25,7 +25,11 @@
struct regulator_dev *dummy_regulator_rdev;
-static struct regulator_init_data dummy_initdata;
+static struct regulator_init_data dummy_initdata = {
+ .constraints = {
+ .always_on = 1,
+ },
+};
static struct regulator_ops dummy_ops;
diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c
index 7ca3d9e3b0fe..714fd9a89aa1 100644
--- a/drivers/regulator/fan53555.c
+++ b/drivers/regulator/fan53555.c
@@ -90,11 +90,11 @@ static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV)
return 0;
ret = regulator_map_voltage_linear(rdev, uV, uV);
if (ret < 0)
- return -EINVAL;
+ return ret;
ret = regmap_update_bits(di->regmap, di->sleep_reg,
VSEL_NSEL_MASK, ret);
if (ret < 0)
- return -EINVAL;
+ return ret;
/* Cache the sleep voltage setting.
* Might not be the real voltage which is rounded */
di->sleep_vol_cache = uV;
@@ -244,10 +244,9 @@ static int fan53555_regulator_probe(struct i2c_client *client,
di = devm_kzalloc(&client->dev, sizeof(struct fan53555_device_info),
GFP_KERNEL);
- if (!di) {
- dev_err(&client->dev, "Failed to allocate device info data!\n");
+ if (!di)
return -ENOMEM;
- }
+
di->regmap = devm_regmap_init_i2c(client, &fan53555_regmap_config);
if (IS_ERR(di->regmap)) {
dev_err(&client->dev, "Failed to allocate regmap!\n");
@@ -260,14 +259,14 @@ static int fan53555_regulator_probe(struct i2c_client *client,
ret = regmap_read(di->regmap, FAN53555_ID1, &val);
if (ret < 0) {
dev_err(&client->dev, "Failed to get chip ID!\n");
- return -ENODEV;
+ return ret;
}
di->chip_id = val & DIE_ID;
/* Get chip revision */
ret = regmap_read(di->regmap, FAN53555_ID2, &val);
if (ret < 0) {
dev_err(&client->dev, "Failed to get chip Rev!\n");
- return -ENODEV;
+ return ret;
}
di->chip_rev = val & DIE_REV;
dev_info(&client->dev, "FAN53555 Option[%d] Rev[%d] Detected!\n",
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 5ea64b94341c..c61f7e97e4f8 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -130,17 +130,15 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data),
GFP_KERNEL);
- if (drvdata == NULL) {
- dev_err(&pdev->dev, "Failed to allocate device data\n");
- ret = -ENOMEM;
- goto err;
- }
+ if (!drvdata)
+ return -ENOMEM;
- drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL);
+ drvdata->desc.name = devm_kstrdup(&pdev->dev,
+ config->supply_name,
+ GFP_KERNEL);
if (drvdata->desc.name == NULL) {
dev_err(&pdev->dev, "Failed to allocate supply name\n");
- ret = -ENOMEM;
- goto err;
+ return -ENOMEM;
}
drvdata->desc.type = REGULATOR_VOLTAGE;
drvdata->desc.owner = THIS_MODULE;
@@ -149,13 +147,13 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
drvdata->desc.enable_time = config->startup_delay;
if (config->input_supply) {
- drvdata->desc.supply_name = kstrdup(config->input_supply,
- GFP_KERNEL);
+ drvdata->desc.supply_name = devm_kstrdup(&pdev->dev,
+ config->input_supply,
+ GFP_KERNEL);
if (!drvdata->desc.supply_name) {
dev_err(&pdev->dev,
"Failed to allocate input supply\n");
- ret = -ENOMEM;
- goto err_name;
+ return -ENOMEM;
}
}
@@ -186,11 +184,12 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
cfg.driver_data = drvdata;
cfg.of_node = pdev->dev.of_node;
- drvdata->dev = regulator_register(&drvdata->desc, &cfg);
+ drvdata->dev = devm_regulator_register(&pdev->dev, &drvdata->desc,
+ &cfg);
if (IS_ERR(drvdata->dev)) {
ret = PTR_ERR(drvdata->dev);
dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret);
- goto err_input;
+ return ret;
}
platform_set_drvdata(pdev, drvdata);
@@ -199,24 +198,6 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
drvdata->desc.fixed_uV);
return 0;
-
-err_input:
- kfree(drvdata->desc.supply_name);
-err_name:
- kfree(drvdata->desc.name);
-err:
- return ret;
-}
-
-static int reg_fixed_voltage_remove(struct platform_device *pdev)
-{
- struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev);
-
- regulator_unregister(drvdata->dev);
- kfree(drvdata->desc.supply_name);
- kfree(drvdata->desc.name);
-
- return 0;
}
#if defined(CONFIG_OF)
@@ -229,7 +210,6 @@ MODULE_DEVICE_TABLE(of, fixed_of_match);
static struct platform_driver regulator_fixed_voltage_driver = {
.probe = reg_fixed_voltage_probe,
- .remove = reg_fixed_voltage_remove,
.driver = {
.name = "reg-fixed-voltage",
.owner = THIS_MODULE,
diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c
index c0a1d00b78c9..989b23b377c0 100644
--- a/drivers/regulator/gpio-regulator.c
+++ b/drivers/regulator/gpio-regulator.c
@@ -136,7 +136,6 @@ static struct gpio_regulator_config *
of_get_gpio_regulator_config(struct device *dev, struct device_node *np)
{
struct gpio_regulator_config *config;
- struct property *prop;
const char *regtype;
int proplen, gpio, i;
int ret;
@@ -172,22 +171,35 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np)
if (!config->gpios)
return ERR_PTR(-ENOMEM);
+ proplen = of_property_count_u32_elems(np, "gpios-states");
+ /* optional property */
+ if (proplen < 0)
+ proplen = 0;
+
+ if (proplen > 0 && proplen != config->nr_gpios) {
+ dev_warn(dev, "gpios <-> gpios-states mismatch\n");
+ proplen = 0;
+ }
+
for (i = 0; i < config->nr_gpios; i++) {
gpio = of_get_named_gpio(np, "gpios", i);
if (gpio < 0)
break;
config->gpios[i].gpio = gpio;
+ if (proplen > 0) {
+ of_property_read_u32_index(np, "gpios-states", i, &ret);
+ if (ret)
+ config->gpios[i].flags = GPIOF_OUT_INIT_HIGH;
+ }
}
/* Fetch states. */
- prop = of_find_property(np, "states", NULL);
- if (!prop) {
+ proplen = of_property_count_u32_elems(np, "states");
+ if (proplen < 0) {
dev_err(dev, "No 'states' property found\n");
return ERR_PTR(-EINVAL);
}
- proplen = prop->length / sizeof(int);
-
config->states = devm_kzalloc(dev,
sizeof(struct gpio_regulator_state)
* (proplen / 2),
@@ -196,10 +208,10 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np)
return ERR_PTR(-ENOMEM);
for (i = 0; i < proplen / 2; i++) {
- config->states[i].value =
- be32_to_cpup((int *)prop->value + (i * 2));
- config->states[i].gpios =
- be32_to_cpup((int *)prop->value + (i * 2 + 1));
+ of_property_read_u32_index(np, "states", i * 2,
+ &config->states[i].value);
+ of_property_read_u32_index(np, "states", i * 2 + 1,
+ &config->states[i].gpios);
}
config->nr_states = i;
@@ -239,10 +251,8 @@ static int gpio_regulator_probe(struct platform_device *pdev)
drvdata = devm_kzalloc(&pdev->dev, sizeof(struct gpio_regulator_data),
GFP_KERNEL);
- if (drvdata == NULL) {
- dev_err(&pdev->dev, "Failed to allocate device data\n");
+ if (drvdata == NULL)
return -ENOMEM;
- }
drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL);
if (drvdata->desc.name == NULL) {
diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c
index e221a271ba56..cbc39096c78d 100644
--- a/drivers/regulator/helpers.c
+++ b/drivers/regulator/helpers.c
@@ -37,10 +37,17 @@ int regulator_is_enabled_regmap(struct regulator_dev *rdev)
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;
+ val &= rdev->desc->enable_mask;
+
+ if (rdev->desc->enable_is_inverted) {
+ if (rdev->desc->enable_val)
+ return val != rdev->desc->enable_val;
+ return val == 0;
+ } else {
+ if (rdev->desc->enable_val)
+ return val == rdev->desc->enable_val;
+ return val != 0;
+ }
}
EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap);
@@ -57,10 +64,13 @@ 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;
+ if (rdev->desc->enable_is_inverted) {
+ val = rdev->desc->disable_val;
+ } else {
+ val = rdev->desc->enable_val;
+ if (!val)
+ val = rdev->desc->enable_mask;
+ }
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
rdev->desc->enable_mask, val);
@@ -80,10 +90,13 @@ 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;
+ if (rdev->desc->enable_is_inverted) {
+ val = rdev->desc->enable_val;
+ if (!val)
+ val = rdev->desc->enable_mask;
+ } else {
+ val = rdev->desc->disable_val;
+ }
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
rdev->desc->enable_mask, val);
@@ -419,10 +432,13 @@ int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable)
{
unsigned int val;
- if (enable)
- val = rdev->desc->bypass_mask;
- else
- val = 0;
+ if (enable) {
+ val = rdev->desc->bypass_val_on;
+ if (!val)
+ val = rdev->desc->bypass_mask;
+ } else {
+ val = rdev->desc->bypass_val_off;
+ }
return regmap_update_bits(rdev->regmap, rdev->desc->bypass_reg,
rdev->desc->bypass_mask, val);
diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c
index 3b1102b75071..66fd2330dca0 100644
--- a/drivers/regulator/lp3971.c
+++ b/drivers/regulator/lp3971.c
@@ -327,7 +327,7 @@ static int lp3971_i2c_read(struct i2c_client *i2c, char reg, int count,
return -EIO;
ret = i2c_smbus_read_byte_data(i2c, reg);
if (ret < 0)
- return -EIO;
+ return ret;
*dest = ret;
return 0;
diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c
index 2e4734ff79fc..2e022aabd951 100644
--- a/drivers/regulator/lp872x.c
+++ b/drivers/regulator/lp872x.c
@@ -211,7 +211,7 @@ static int lp872x_get_timestep_usec(struct lp872x *lp)
ret = lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val);
if (ret)
- return -EINVAL;
+ return ret;
val = (val & mask) >> shift;
if (val >= size)
@@ -229,7 +229,7 @@ static int lp872x_regulator_enable_time(struct regulator_dev *rdev)
u8 addr, val;
if (time_step_us < 0)
- return -EINVAL;
+ return time_step_us;
switch (rid) {
case LP8720_ID_LDO1 ... LP8720_ID_BUCK:
diff --git a/drivers/regulator/max14577.c b/drivers/regulator/max14577.c
index b1078ba3f393..ed60baaeceec 100644
--- a/drivers/regulator/max14577.c
+++ b/drivers/regulator/max14577.c
@@ -1,7 +1,7 @@
/*
* max14577.c - Regulator driver for the Maxim 14577
*
- * Copyright (C) 2013 Samsung Electronics
+ * Copyright (C) 2013,2014 Samsung Electronics
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -22,12 +22,6 @@
#include <linux/mfd/max14577-private.h>
#include <linux/regulator/of_regulator.h>
-struct max14577_regulator {
- struct device *dev;
- struct max14577 *max14577;
- struct regulator_dev **regulators;
-};
-
static int max14577_reg_is_enabled(struct regulator_dev *rdev)
{
int rid = rdev_get_id(rdev);
@@ -166,12 +160,14 @@ static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
ret = of_regulator_match(&pdev->dev, np, max14577_regulator_matches,
MAX14577_REG_MAX);
- if (ret < 0) {
+ if (ret < 0)
dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret);
- return ret;
- }
+ else
+ ret = 0;
- return 0;
+ of_node_put(np);
+
+ return ret;
}
static inline struct regulator_init_data *match_init_data(int index)
diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c
index e242dd316d36..d23d0577754b 100644
--- a/drivers/regulator/max1586.c
+++ b/drivers/regulator/max1586.c
@@ -46,8 +46,6 @@ struct max1586_data {
unsigned int v3_curr_sel;
unsigned int v6_curr_sel;
-
- struct regulator_dev *rdev[0];
};
/*
@@ -162,14 +160,12 @@ static struct regulator_desc max1586_reg[] = {
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 = dev_get_platdata(&client->dev);
struct regulator_config config = { };
struct max1586_data *max1586;
int i, id;
- max1586 = devm_kzalloc(&client->dev, sizeof(struct max1586_data) +
- sizeof(struct regulator_dev *) * (MAX1586_V6 + 1),
+ max1586 = devm_kzalloc(&client->dev, sizeof(struct max1586_data),
GFP_KERNEL);
if (!max1586)
return -ENOMEM;
@@ -186,8 +182,9 @@ static int max1586_pmic_probe(struct i2c_client *client,
max1586->v3_curr_sel = 24; /* 1.3V */
max1586->v6_curr_sel = 0;
- rdev = max1586->rdev;
for (i = 0; i < pdata->num_subdevs && i <= MAX1586_V6; i++) {
+ struct regulator_dev *rdev;
+
id = pdata->subdevs[i].id;
if (!pdata->subdevs[i].platform_data)
continue;
@@ -207,12 +204,12 @@ static int max1586_pmic_probe(struct i2c_client *client,
config.init_data = pdata->subdevs[i].platform_data;
config.driver_data = max1586;
- rdev[i] = devm_regulator_register(&client->dev,
+ rdev = devm_regulator_register(&client->dev,
&max1586_reg[id], &config);
- if (IS_ERR(rdev[i])) {
+ if (IS_ERR(rdev)) {
dev_err(&client->dev, "failed to register %s\n",
max1586_reg[id].name);
- return PTR_ERR(rdev[i]);
+ return PTR_ERR(rdev);
}
}
diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c
index ae001ccf26f4..ef1af2debbd2 100644
--- a/drivers/regulator/max77686.c
+++ b/drivers/regulator/max77686.c
@@ -65,7 +65,6 @@ enum max77686_ramp_rate {
};
struct max77686_data {
- struct regulator_dev *rdev[MAX77686_REGULATORS];
unsigned int opmode[MAX77686_REGULATORS];
};
@@ -400,7 +399,7 @@ static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev,
unsigned int i;
pmic_np = iodev->dev->of_node;
- regulators_np = of_find_node_by_name(pmic_np, "voltage-regulators");
+ regulators_np = of_get_child_by_name(pmic_np, "voltage-regulators");
if (!regulators_np) {
dev_err(&pdev->dev, "could not find regulators sub-node\n");
return -EINVAL;
@@ -410,8 +409,7 @@ static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev,
rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
pdata->num_regulators, GFP_KERNEL);
if (!rdata) {
- dev_err(&pdev->dev,
- "could not allocate memory for regulator data\n");
+ of_node_put(regulators_np);
return -ENOMEM;
}
@@ -425,6 +423,7 @@ static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev,
}
pdata->regulators = rdata;
+ of_node_put(regulators_np);
return 0;
}
@@ -474,16 +473,18 @@ static int max77686_pmic_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, max77686);
for (i = 0; i < MAX77686_REGULATORS; i++) {
+ struct regulator_dev *rdev;
+
config.init_data = pdata->regulators[i].initdata;
config.of_node = pdata->regulators[i].of_node;
max77686->opmode[i] = regulators[i].enable_mask;
- max77686->rdev[i] = devm_regulator_register(&pdev->dev,
+ rdev = devm_regulator_register(&pdev->dev,
&regulators[i], &config);
- if (IS_ERR(max77686->rdev[i])) {
+ if (IS_ERR(rdev)) {
dev_err(&pdev->dev,
"regulator init failed for %d\n", i);
- return PTR_ERR(max77686->rdev[i]);
+ return PTR_ERR(rdev);
}
}
diff --git a/drivers/regulator/max77693.c b/drivers/regulator/max77693.c
index 5fb899f461d0..653a58b49cdf 100644
--- a/drivers/regulator/max77693.c
+++ b/drivers/regulator/max77693.c
@@ -34,13 +34,6 @@
#define CHGIN_ILIM_STEP_20mA 20000
-struct max77693_pmic_dev {
- struct device *dev;
- struct max77693_dev *iodev;
- int num_regulators;
- struct regulator_dev **rdev;
-};
-
/* CHARGER regulator ops */
/* CHARGER regulator uses two bits for enabling */
static int max77693_chg_is_enabled(struct regulator_dev *rdev)
@@ -170,19 +163,22 @@ static int max77693_pmic_dt_parse_rdata(struct device *dev,
struct max77693_regulator_data *tmp;
int i, matched = 0;
- np = of_find_node_by_name(dev->parent->of_node, "regulators");
+ np = of_get_child_by_name(dev->parent->of_node, "regulators");
if (!np)
return -EINVAL;
rmatch = devm_kzalloc(dev,
sizeof(*rmatch) * ARRAY_SIZE(regulators), GFP_KERNEL);
- if (!rmatch)
+ if (!rmatch) {
+ of_node_put(np);
return -ENOMEM;
+ }
for (i = 0; i < ARRAY_SIZE(regulators); i++)
rmatch[i].name = regulators[i].name;
matched = of_regulator_match(dev, np, rmatch, ARRAY_SIZE(regulators));
+ of_node_put(np);
if (matched <= 0)
return matched;
*rdata = devm_kzalloc(dev, sizeof(**rdata) * matched, GFP_KERNEL);
@@ -229,7 +225,6 @@ static int max77693_pmic_init_rdata(struct device *dev,
static int max77693_pmic_probe(struct platform_device *pdev)
{
struct max77693_dev *iodev = dev_get_drvdata(pdev->dev.parent);
- struct max77693_pmic_dev *max77693_pmic;
struct max77693_regulator_data *rdata = NULL;
int num_rdata, i;
struct regulator_config config;
@@ -240,39 +235,22 @@ static int max77693_pmic_probe(struct platform_device *pdev)
return -ENODEV;
}
- max77693_pmic = devm_kzalloc(&pdev->dev,
- sizeof(struct max77693_pmic_dev),
- GFP_KERNEL);
- if (!max77693_pmic)
- return -ENOMEM;
-
- max77693_pmic->rdev = devm_kzalloc(&pdev->dev,
- sizeof(struct regulator_dev *) * num_rdata,
- GFP_KERNEL);
- if (!max77693_pmic->rdev)
- return -ENOMEM;
-
- max77693_pmic->dev = &pdev->dev;
- max77693_pmic->iodev = iodev;
- max77693_pmic->num_regulators = num_rdata;
-
config.dev = &pdev->dev;
config.regmap = iodev->regmap;
- config.driver_data = max77693_pmic;
- platform_set_drvdata(pdev, max77693_pmic);
- for (i = 0; i < max77693_pmic->num_regulators; i++) {
+ for (i = 0; i < num_rdata; i++) {
int id = rdata[i].id;
+ struct regulator_dev *rdev;
config.init_data = rdata[i].initdata;
config.of_node = rdata[i].of_node;
- max77693_pmic->rdev[i] = devm_regulator_register(&pdev->dev,
+ rdev = devm_regulator_register(&pdev->dev,
&regulators[id], &config);
- if (IS_ERR(max77693_pmic->rdev[i])) {
- dev_err(max77693_pmic->dev,
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev,
"Failed to initialize regulator-%d\n", id);
- return PTR_ERR(max77693_pmic->rdev[i]);
+ return PTR_ERR(rdev);
}
}
diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c
index 7f049c92ee52..3172da847d24 100644
--- a/drivers/regulator/max8649.c
+++ b/drivers/regulator/max8649.c
@@ -49,7 +49,6 @@
#define MAX8649_RAMP_DOWN (1 << 1)
struct max8649_regulator_info {
- struct regulator_dev *regulator;
struct device *dev;
struct regmap *regmap;
@@ -154,6 +153,7 @@ static int max8649_regulator_probe(struct i2c_client *client,
{
struct max8649_platform_data *pdata = dev_get_platdata(&client->dev);
struct max8649_regulator_info *info = NULL;
+ struct regulator_dev *regulator;
struct regulator_config config = { };
unsigned int val;
unsigned char data;
@@ -234,12 +234,12 @@ static int max8649_regulator_probe(struct i2c_client *client,
config.driver_data = info;
config.regmap = info->regmap;
- info->regulator = devm_regulator_register(&client->dev, &dcdc_desc,
+ regulator = devm_regulator_register(&client->dev, &dcdc_desc,
&config);
- if (IS_ERR(info->regulator)) {
+ if (IS_ERR(regulator)) {
dev_err(info->dev, "failed to register regulator %s\n",
dcdc_desc.name);
- return PTR_ERR(info->regulator);
+ return PTR_ERR(regulator);
}
return 0;
diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c
index 8d94d3d7f97f..2fc411188794 100644
--- a/drivers/regulator/max8660.c
+++ b/drivers/regulator/max8660.c
@@ -81,16 +81,17 @@ enum {
struct max8660 {
struct i2c_client *client;
u8 shadow_regs[MAX8660_N_REGS]; /* as chip is write only */
- struct regulator_dev *rdev[];
};
static int max8660_write(struct max8660 *max8660, u8 reg, u8 mask, u8 val)
{
- static const u8 max8660_addresses[MAX8660_N_REGS] =
- { 0x10, 0x12, 0x20, 0x23, 0x24, 0x29, 0x2a, 0x32, 0x33, 0x39, 0x80 };
+ static const u8 max8660_addresses[MAX8660_N_REGS] = {
+ 0x10, 0x12, 0x20, 0x23, 0x24, 0x29, 0x2a, 0x32, 0x33, 0x39, 0x80
+ };
int ret;
u8 reg_val = (max8660->shadow_regs[reg] & mask) | val;
+
dev_vdbg(&max8660->client->dev, "Writing reg %02x with %02x\n",
max8660_addresses[reg], reg_val);
@@ -112,6 +113,7 @@ static int max8660_dcdc_is_enabled(struct regulator_dev *rdev)
struct max8660 *max8660 = rdev_get_drvdata(rdev);
u8 val = max8660->shadow_regs[MAX8660_OVER1];
u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4;
+
return !!(val & mask);
}
@@ -119,6 +121,7 @@ static int max8660_dcdc_enable(struct regulator_dev *rdev)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
u8 bit = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4;
+
return max8660_write(max8660, MAX8660_OVER1, 0xff, bit);
}
@@ -126,15 +129,16 @@ static int max8660_dcdc_disable(struct regulator_dev *rdev)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? ~1 : ~4;
+
return max8660_write(max8660, MAX8660_OVER1, mask, 0);
}
static int max8660_dcdc_get_voltage_sel(struct regulator_dev *rdev)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
-
u8 reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2;
u8 selector = max8660->shadow_regs[reg];
+
return selector;
}
@@ -207,6 +211,7 @@ static int max8660_ldo67_is_enabled(struct regulator_dev *rdev)
struct max8660 *max8660 = rdev_get_drvdata(rdev);
u8 val = max8660->shadow_regs[MAX8660_OVER2];
u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4;
+
return !!(val & mask);
}
@@ -214,6 +219,7 @@ static int max8660_ldo67_enable(struct regulator_dev *rdev)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
u8 bit = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4;
+
return max8660_write(max8660, MAX8660_OVER2, 0xff, bit);
}
@@ -221,15 +227,16 @@ static int max8660_ldo67_disable(struct regulator_dev *rdev)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? ~2 : ~4;
+
return max8660_write(max8660, MAX8660_OVER2, mask, 0);
}
static int max8660_ldo67_get_voltage_sel(struct regulator_dev *rdev)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
-
u8 shift = (rdev_get_id(rdev) == MAX8660_V6) ? 0 : 4;
u8 selector = (max8660->shadow_regs[MAX8660_L12VCR] >> shift) & 0xf;
+
return selector;
}
@@ -330,7 +337,7 @@ static int max8660_pdata_from_dt(struct device *dev,
struct max8660_subdev_data *sub;
struct of_regulator_match rmatch[ARRAY_SIZE(max8660_reg)];
- np = of_find_node_by_name(dev->of_node, "regulators");
+ np = of_get_child_by_name(dev->of_node, "regulators");
if (!np) {
dev_err(dev, "missing 'regulators' subnode in DT\n");
return -EINVAL;
@@ -340,6 +347,7 @@ static int max8660_pdata_from_dt(struct device *dev,
rmatch[i].name = max8660_reg[i].name;
matched = of_regulator_match(dev, np, rmatch, ARRAY_SIZE(rmatch));
+ of_node_put(np);
if (matched <= 0)
return matched;
@@ -373,7 +381,6 @@ static inline int max8660_pdata_from_dt(struct device *dev,
static int max8660_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
- struct regulator_dev **rdev;
struct device *dev = &client->dev;
struct max8660_platform_data *pdata = dev_get_platdata(dev);
struct regulator_config config = { };
@@ -406,14 +413,11 @@ static int max8660_probe(struct i2c_client *client,
return -EINVAL;
}
- max8660 = devm_kzalloc(dev, sizeof(struct max8660) +
- sizeof(struct regulator_dev *) * MAX8660_V_END,
- GFP_KERNEL);
+ max8660 = devm_kzalloc(dev, sizeof(struct max8660), GFP_KERNEL);
if (!max8660)
return -ENOMEM;
max8660->client = client;
- rdev = max8660->rdev;
if (pdata->en34_is_high) {
/* Simulate always on */
@@ -481,6 +485,7 @@ static int max8660_probe(struct i2c_client *client,
/* Finally register devices */
for (i = 0; i < pdata->num_subdevs; i++) {
+ struct regulator_dev *rdev;
id = pdata->subdevs[i].id;
@@ -489,13 +494,13 @@ static int max8660_probe(struct i2c_client *client,
config.of_node = of_node[i];
config.driver_data = max8660;
- rdev[i] = devm_regulator_register(&client->dev,
+ rdev = devm_regulator_register(&client->dev,
&max8660_reg[id], &config);
- if (IS_ERR(rdev[i])) {
- ret = PTR_ERR(rdev[i]);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
dev_err(&client->dev, "failed to register %s\n",
max8660_reg[id].name);
- return PTR_ERR(rdev[i]);
+ return PTR_ERR(rdev);
}
}
diff --git a/drivers/regulator/max8907-regulator.c b/drivers/regulator/max8907-regulator.c
index 0c5fe6c6ac26..9623e9e290bf 100644
--- a/drivers/regulator/max8907-regulator.c
+++ b/drivers/regulator/max8907-regulator.c
@@ -34,7 +34,6 @@
struct max8907_regulator {
struct regulator_desc desc[MAX8907_NUM_REGULATORS];
- struct regulator_dev *rdev[MAX8907_NUM_REGULATORS];
};
#define REG_MBATT() \
@@ -231,7 +230,7 @@ static int max8907_regulator_parse_dt(struct platform_device *pdev)
if (!np)
return 0;
- regulators = of_find_node_by_name(np, "regulators");
+ regulators = of_get_child_by_name(np, "regulators");
if (!regulators) {
dev_err(&pdev->dev, "regulators node not found\n");
return -EINVAL;
@@ -292,10 +291,9 @@ static int max8907_regulator_probe(struct platform_device *pdev)
return ret;
pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
- if (!pmic) {
- dev_err(&pdev->dev, "Failed to alloc pmic\n");
+ if (!pmic)
return -ENOMEM;
- }
+
platform_set_drvdata(pdev, pmic);
memcpy(pmic->desc, max8907_regulators, sizeof(pmic->desc));
@@ -311,6 +309,8 @@ static int max8907_regulator_probe(struct platform_device *pdev)
}
for (i = 0; i < MAX8907_NUM_REGULATORS; i++) {
+ struct regulator_dev *rdev;
+
config.dev = pdev->dev.parent;
if (pdata)
idata = pdata->init_data[i];
@@ -350,13 +350,13 @@ static int max8907_regulator_probe(struct platform_device *pdev)
pmic->desc[i].ops = &max8907_out5v_hwctl_ops;
}
- pmic->rdev[i] = devm_regulator_register(&pdev->dev,
+ rdev = devm_regulator_register(&pdev->dev,
&pmic->desc[i], &config);
- if (IS_ERR(pmic->rdev[i])) {
+ if (IS_ERR(rdev)) {
dev_err(&pdev->dev,
"failed to register %s regulator\n",
pmic->desc[i].name);
- return PTR_ERR(pmic->rdev[i]);
+ return PTR_ERR(rdev);
}
}
diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c
index 759510789e71..dad2bcd14e96 100644
--- a/drivers/regulator/max8925-regulator.c
+++ b/drivers/regulator/max8925-regulator.c
@@ -36,9 +36,7 @@
struct max8925_regulator_info {
struct regulator_desc desc;
- struct regulator_dev *regulator;
struct i2c_client *i2c;
- struct max8925_chip *chip;
int vol_reg;
int enable_reg;
@@ -251,10 +249,11 @@ static int max8925_regulator_dt_init(struct platform_device *pdev,
{
struct device_node *nproot, *np;
int rcount;
+
nproot = of_node_get(pdev->dev.parent->of_node);
if (!nproot)
return -ENODEV;
- np = of_find_node_by_name(nproot, "regulators");
+ np = of_get_child_by_name(nproot, "regulators");
if (!np) {
dev_err(&pdev->dev, "failed to find regulators node\n");
return -ENODEV;
@@ -264,7 +263,7 @@ static int max8925_regulator_dt_init(struct platform_device *pdev,
&max8925_regulator_matches[ridx], 1);
of_node_put(np);
if (rcount < 0)
- return -ENODEV;
+ return rcount;
config->init_data = max8925_regulator_matches[ridx].init_data;
config->of_node = max8925_regulator_matches[ridx].of_node;
@@ -303,7 +302,6 @@ static int max8925_regulator_probe(struct platform_device *pdev)
return -EINVAL;
}
ri->i2c = chip->i2c;
- ri->chip = chip;
config.dev = &pdev->dev;
config.driver_data = ri;
diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c
index 788e5ae2af1b..d920f5a32ec8 100644
--- a/drivers/regulator/max8952.c
+++ b/drivers/regulator/max8952.c
@@ -48,9 +48,7 @@ enum {
struct max8952_data {
struct i2c_client *client;
- struct device *dev;
struct max8952_platform_data *pdata;
- struct regulator_dev *rdev;
bool vid0;
bool vid1;
@@ -59,6 +57,7 @@ struct max8952_data {
static int max8952_read_reg(struct max8952_data *max8952, u8 reg)
{
int ret = i2c_smbus_read_byte_data(max8952->client, reg);
+
if (ret > 0)
ret &= 0xff;
@@ -144,10 +143,8 @@ static struct max8952_platform_data *max8952_parse_dt(struct device *dev)
int i;
pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
- if (!pd) {
- dev_err(dev, "Failed to allocate platform data\n");
+ if (!pd)
return NULL;
- }
pd->gpio_vid0 = of_get_named_gpio(np, "max8952,vid-gpios", 0);
pd->gpio_vid1 = of_get_named_gpio(np, "max8952,vid-gpios", 1);
@@ -199,6 +196,7 @@ static int max8952_pmic_probe(struct i2c_client *client,
struct max8952_platform_data *pdata = dev_get_platdata(&client->dev);
struct regulator_config config = { };
struct max8952_data *max8952;
+ struct regulator_dev *rdev;
int ret = 0, err = 0;
@@ -219,10 +217,9 @@ static int max8952_pmic_probe(struct i2c_client *client,
return -ENOMEM;
max8952->client = client;
- max8952->dev = &client->dev;
max8952->pdata = pdata;
- config.dev = max8952->dev;
+ config.dev = &client->dev;
config.init_data = pdata->reg_data;
config.driver_data = max8952;
config.of_node = client->dev.of_node;
@@ -231,11 +228,11 @@ static int max8952_pmic_probe(struct i2c_client *client,
if (pdata->reg_data->constraints.boot_on)
config.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
- max8952->rdev = regulator_register(&regulator, &config);
+ rdev = devm_regulator_register(&client->dev, &regulator, &config);
- if (IS_ERR(max8952->rdev)) {
- ret = PTR_ERR(max8952->rdev);
- dev_err(max8952->dev, "regulator init failed (%d)\n", ret);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
+ dev_err(&client->dev, "regulator init failed (%d)\n", ret);
return ret;
}
@@ -263,7 +260,7 @@ static int max8952_pmic_probe(struct i2c_client *client,
err = 3;
if (err) {
- dev_warn(max8952->dev, "VID0/1 gpio invalid: "
+ dev_warn(&client->dev, "VID0/1 gpio invalid: "
"DVS not available.\n");
max8952->vid0 = 0;
max8952->vid1 = 0;
@@ -274,7 +271,7 @@ static int max8952_pmic_probe(struct i2c_client *client,
/* Disable Pulldown of EN only */
max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x60);
- dev_err(max8952->dev, "DVS modes disabled because VID0 and VID1"
+ dev_err(&client->dev, "DVS modes disabled because VID0 and VID1"
" do not have proper controls.\n");
} else {
/*
@@ -321,9 +318,6 @@ static int max8952_pmic_remove(struct i2c_client *client)
{
struct max8952_data *max8952 = i2c_get_clientdata(client);
struct max8952_platform_data *pdata = max8952->pdata;
- struct regulator_dev *rdev = max8952->rdev;
-
- regulator_unregister(rdev);
gpio_free(pdata->gpio_vid0);
gpio_free(pdata->gpio_vid1);
diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c
index 892aa1e5b96c..dbedf1768db0 100644
--- a/drivers/regulator/max8973-regulator.c
+++ b/drivers/regulator/max8973-regulator.c
@@ -93,7 +93,6 @@
struct max8973_chip {
struct device *dev;
struct regulator_desc desc;
- struct regulator_dev *rdev;
struct regmap *regmap;
bool enable_external_control;
int dvs_gpio;
@@ -379,10 +378,8 @@ static int max8973_probe(struct i2c_client *client,
}
max = devm_kzalloc(&client->dev, sizeof(*max), GFP_KERNEL);
- if (!max) {
- dev_err(&client->dev, "Memory allocation for max failed\n");
+ if (!max)
return -ENOMEM;
- }
max->regmap = devm_regmap_init_i2c(client, &max8973_regmap_config);
if (IS_ERR(max->regmap)) {
@@ -474,7 +471,6 @@ static int max8973_probe(struct i2c_client *client,
return ret;
}
- max->rdev = rdev;
return 0;
}
diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c
index 2d618fc9c1af..90b4c530dee5 100644
--- a/drivers/regulator/max8997.c
+++ b/drivers/regulator/max8997.c
@@ -38,7 +38,6 @@ struct max8997_data {
struct device *dev;
struct max8997_dev *iodev;
int num_regulators;
- struct regulator_dev **rdev;
int ramp_delay; /* in mV/us */
bool buck1_gpiodvs;
@@ -924,7 +923,7 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
return -ENODEV;
}
- regulators_np = of_find_node_by_name(pmic_np, "regulators");
+ regulators_np = of_get_child_by_name(pmic_np, "regulators");
if (!regulators_np) {
dev_err(&pdev->dev, "could not find regulators sub-node\n");
return -EINVAL;
@@ -937,7 +936,6 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
pdata->num_regulators, GFP_KERNEL);
if (!rdata) {
of_node_put(regulators_np);
- dev_err(&pdev->dev, "could not allocate memory for regulator data\n");
return -ENOMEM;
}
@@ -1030,10 +1028,10 @@ static int max8997_pmic_probe(struct platform_device *pdev)
struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct max8997_platform_data *pdata = iodev->pdata;
struct regulator_config config = { };
- struct regulator_dev **rdev;
+ struct regulator_dev *rdev;
struct max8997_data *max8997;
struct i2c_client *i2c;
- int i, ret, size, nr_dvs;
+ int i, ret, nr_dvs;
u8 max_buck1 = 0, max_buck2 = 0, max_buck5 = 0;
if (!pdata) {
@@ -1052,12 +1050,6 @@ static int max8997_pmic_probe(struct platform_device *pdev)
if (!max8997)
return -ENOMEM;
- size = sizeof(struct regulator_dev *) * pdata->num_regulators;
- max8997->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
- if (!max8997->rdev)
- return -ENOMEM;
-
- rdev = max8997->rdev;
max8997->dev = &pdev->dev;
max8997->iodev = iodev;
max8997->num_regulators = pdata->num_regulators;
@@ -1205,12 +1197,12 @@ static int max8997_pmic_probe(struct platform_device *pdev)
config.driver_data = max8997;
config.of_node = pdata->regulators[i].reg_node;
- rdev[i] = devm_regulator_register(&pdev->dev, &regulators[id],
- &config);
- if (IS_ERR(rdev[i])) {
+ rdev = devm_regulator_register(&pdev->dev, &regulators[id],
+ &config);
+ if (IS_ERR(rdev)) {
dev_err(max8997->dev, "regulator init failed for %d\n",
id);
- return PTR_ERR(rdev[i]);
+ return PTR_ERR(rdev);
}
}
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c
index ae3f0656feb0..961091b46557 100644
--- a/drivers/regulator/max8998.c
+++ b/drivers/regulator/max8998.c
@@ -40,7 +40,6 @@ struct max8998_data {
struct device *dev;
struct max8998_dev *iodev;
int num_regulators;
- struct regulator_dev **rdev;
u8 buck1_vol[4]; /* voltages for selection */
u8 buck2_vol[2];
unsigned int buck1_idx; /* index to last changed voltage */
@@ -674,8 +673,10 @@ static int max8998_pmic_dt_parse_pdata(struct max8998_dev *iodev,
rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) *
pdata->num_regulators, GFP_KERNEL);
- if (!rdata)
+ if (!rdata) {
+ of_node_put(regulators_np);
return -ENOMEM;
+ }
pdata->regulators = rdata;
for (i = 0; i < ARRAY_SIZE(regulators); ++i) {
@@ -692,6 +693,9 @@ static int max8998_pmic_dt_parse_pdata(struct max8998_dev *iodev,
}
pdata->num_regulators = rdata - pdata->regulators;
+ of_node_put(reg_np);
+ of_node_put(regulators_np);
+
ret = max8998_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np);
if (ret)
return -EINVAL;
@@ -741,10 +745,10 @@ static int max8998_pmic_probe(struct platform_device *pdev)
struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct max8998_platform_data *pdata = iodev->pdata;
struct regulator_config config = { };
- struct regulator_dev **rdev;
+ struct regulator_dev *rdev;
struct max8998_data *max8998;
struct i2c_client *i2c;
- int i, ret, size;
+ int i, ret;
unsigned int v;
if (!pdata) {
@@ -763,12 +767,6 @@ static int max8998_pmic_probe(struct platform_device *pdev)
if (!max8998)
return -ENOMEM;
- size = sizeof(struct regulator_dev *) * pdata->num_regulators;
- max8998->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
- if (!max8998->rdev)
- return -ENOMEM;
-
- rdev = max8998->rdev;
max8998->dev = &pdev->dev;
max8998->iodev = iodev;
max8998->num_regulators = pdata->num_regulators;
@@ -872,13 +870,12 @@ static int max8998_pmic_probe(struct platform_device *pdev)
config.init_data = pdata->regulators[i].initdata;
config.driver_data = max8998;
- rdev[i] = devm_regulator_register(&pdev->dev,
- &regulators[index], &config);
- if (IS_ERR(rdev[i])) {
- ret = PTR_ERR(rdev[i]);
+ rdev = devm_regulator_register(&pdev->dev, &regulators[index],
+ &config);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
dev_err(max8998->dev, "regulator %s init failed (%d)\n",
regulators[index].name, ret);
- rdev[i] = NULL;
return ret;
}
}
diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c
index da4859282302..05b971726ffa 100644
--- a/drivers/regulator/mc13xxx-regulator-core.c
+++ b/drivers/regulator/mc13xxx-regulator-core.c
@@ -167,8 +167,10 @@ int mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
struct device_node *parent;
int num;
- of_node_get(pdev->dev.parent->of_node);
- parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
+ if (!pdev->dev.parent->of_node)
+ return -ENODEV;
+
+ parent = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
if (!parent)
return -ENODEV;
@@ -187,8 +189,10 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
struct device_node *parent, *child;
int i, parsed = 0;
- of_node_get(pdev->dev.parent->of_node);
- parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
+ if (!pdev->dev.parent->of_node)
+ return NULL;
+
+ parent = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
if (!parent)
return NULL;
diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c
index ab174f20ca11..67e678c4301c 100644
--- a/drivers/regulator/pfuze100-regulator.c
+++ b/drivers/regulator/pfuze100-regulator.c
@@ -56,6 +56,8 @@
#define PFUZE100_VGEN5VOL 0x70
#define PFUZE100_VGEN6VOL 0x71
+enum chips { PFUZE100, PFUZE200 };
+
struct pfuze_regulator {
struct regulator_desc desc;
unsigned char stby_reg;
@@ -63,6 +65,7 @@ struct pfuze_regulator {
};
struct pfuze_chip {
+ int chip_id;
struct regmap *regmap;
struct device *dev;
struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR];
@@ -78,21 +81,23 @@ static const int pfuze100_vsnvs[] = {
};
static const struct i2c_device_id pfuze_device_id[] = {
- {.name = "pfuze100"},
- {},
+ {.name = "pfuze100", .driver_data = PFUZE100},
+ {.name = "pfuze200", .driver_data = PFUZE200},
+ { }
};
MODULE_DEVICE_TABLE(i2c, pfuze_device_id);
static const struct of_device_id pfuze_dt_ids[] = {
- { .compatible = "fsl,pfuze100" },
- {},
+ { .compatible = "fsl,pfuze100", .data = (void *)PFUZE100},
+ { .compatible = "fsl,pfuze200", .data = (void *)PFUZE200},
+ { }
};
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;
+ int id = rdev_get_id(rdev);
unsigned int ramp_bits;
int ret;
@@ -139,14 +144,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {
};
-#define PFUZE100_FIXED_REG(_name, base, voltage) \
- [PFUZE100_ ## _name] = { \
+#define PFUZE100_FIXED_REG(_chip, _name, base, voltage) \
+ [_chip ## _ ## _name] = { \
.desc = { \
.name = #_name, \
.n_voltages = 1, \
.ops = &pfuze100_fixed_regulator_ops, \
.type = REGULATOR_VOLTAGE, \
- .id = PFUZE100_ ## _name, \
+ .id = _chip ## _ ## _name, \
.owner = THIS_MODULE, \
.min_uV = (voltage), \
.enable_reg = (base), \
@@ -154,14 +159,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {
}, \
}
-#define PFUZE100_SW_REG(_name, base, min, max, step) \
- [PFUZE100_ ## _name] = { \
+#define PFUZE100_SW_REG(_chip, _name, base, min, max, step) \
+ [_chip ## _ ## _name] = { \
.desc = { \
.name = #_name,\
.n_voltages = ((max) - (min)) / (step) + 1, \
.ops = &pfuze100_sw_regulator_ops, \
.type = REGULATOR_VOLTAGE, \
- .id = PFUZE100_ ## _name, \
+ .id = _chip ## _ ## _name, \
.owner = THIS_MODULE, \
.min_uV = (min), \
.uV_step = (step), \
@@ -172,14 +177,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {
.stby_mask = 0x3f, \
}
-#define PFUZE100_SWB_REG(_name, base, mask, voltages) \
- [PFUZE100_ ## _name] = { \
+#define PFUZE100_SWB_REG(_chip, _name, base, mask, voltages) \
+ [_chip ## _ ## _name] = { \
.desc = { \
.name = #_name, \
.n_voltages = ARRAY_SIZE(voltages), \
.ops = &pfuze100_swb_regulator_ops, \
.type = REGULATOR_VOLTAGE, \
- .id = PFUZE100_ ## _name, \
+ .id = _chip ## _ ## _name, \
.owner = THIS_MODULE, \
.volt_table = voltages, \
.vsel_reg = (base), \
@@ -187,14 +192,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {
}, \
}
-#define PFUZE100_VGEN_REG(_name, base, min, max, step) \
- [PFUZE100_ ## _name] = { \
+#define PFUZE100_VGEN_REG(_chip, _name, base, min, max, step) \
+ [_chip ## _ ## _name] = { \
.desc = { \
.name = #_name, \
.n_voltages = ((max) - (min)) / (step) + 1, \
.ops = &pfuze100_ldo_regulator_ops, \
.type = REGULATOR_VOLTAGE, \
- .id = PFUZE100_ ## _name, \
+ .id = _chip ## _ ## _name, \
.owner = THIS_MODULE, \
.min_uV = (min), \
.uV_step = (step), \
@@ -207,25 +212,45 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {
.stby_mask = 0x20, \
}
+/* PFUZE100 */
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),
+ PFUZE100_SW_REG(PFUZE100, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000),
+ PFUZE100_SW_REG(PFUZE100, SW1C, PFUZE100_SW1CVOL, 300000, 1875000, 25000),
+ PFUZE100_SW_REG(PFUZE100, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000),
+ PFUZE100_SW_REG(PFUZE100, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000),
+ PFUZE100_SW_REG(PFUZE100, SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000),
+ PFUZE100_SW_REG(PFUZE100, SW4, PFUZE100_SW4VOL, 400000, 1975000, 25000),
+ PFUZE100_SWB_REG(PFUZE100, SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst),
+ PFUZE100_SWB_REG(PFUZE100, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
+ PFUZE100_FIXED_REG(PFUZE100, VREFDDR, PFUZE100_VREFDDRCON, 750000),
+ PFUZE100_VGEN_REG(PFUZE100, VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000),
+ PFUZE100_VGEN_REG(PFUZE100, VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
+ PFUZE100_VGEN_REG(PFUZE100, VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000),
+ PFUZE100_VGEN_REG(PFUZE100, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000),
+ PFUZE100_VGEN_REG(PFUZE100, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
+ PFUZE100_VGEN_REG(PFUZE100, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
+};
+
+static struct pfuze_regulator pfuze200_regulators[] = {
+ PFUZE100_SW_REG(PFUZE200, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000),
+ PFUZE100_SW_REG(PFUZE200, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000),
+ PFUZE100_SW_REG(PFUZE200, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000),
+ PFUZE100_SW_REG(PFUZE200, SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000),
+ PFUZE100_SWB_REG(PFUZE200, SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst),
+ PFUZE100_SWB_REG(PFUZE200, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
+ PFUZE100_FIXED_REG(PFUZE200, VREFDDR, PFUZE100_VREFDDRCON, 750000),
+ PFUZE100_VGEN_REG(PFUZE200, VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000),
+ PFUZE100_VGEN_REG(PFUZE200, VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
+ PFUZE100_VGEN_REG(PFUZE200, VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000),
+ PFUZE100_VGEN_REG(PFUZE200, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000),
+ PFUZE100_VGEN_REG(PFUZE200, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
+ PFUZE100_VGEN_REG(PFUZE200, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
};
+static struct pfuze_regulator *pfuze_regulators;
+
#ifdef CONFIG_OF
+/* PFUZE100 */
static struct of_regulator_match pfuze100_matches[] = {
{ .name = "sw1ab", },
{ .name = "sw1c", },
@@ -244,24 +269,56 @@ static struct of_regulator_match pfuze100_matches[] = {
{ .name = "vgen6", },
};
+/* PFUZE200 */
+static struct of_regulator_match pfuze200_matches[] = {
+
+ { .name = "sw1ab", },
+ { .name = "sw2", },
+ { .name = "sw3a", },
+ { .name = "sw3b", },
+ { .name = "swbst", },
+ { .name = "vsnvs", },
+ { .name = "vrefddr", },
+ { .name = "vgen1", },
+ { .name = "vgen2", },
+ { .name = "vgen3", },
+ { .name = "vgen4", },
+ { .name = "vgen5", },
+ { .name = "vgen6", },
+};
+
+static struct of_regulator_match *pfuze_matches;
+
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);
+ np = of_node_get(dev->of_node);
if (!np)
- return 0;
+ return -EINVAL;
- parent = of_find_node_by_name(np, "regulators");
+ parent = of_get_child_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));
+ switch (chip->chip_id) {
+ case PFUZE200:
+ pfuze_matches = pfuze200_matches;
+ ret = of_regulator_match(dev, parent, pfuze200_matches,
+ ARRAY_SIZE(pfuze200_matches));
+ break;
+
+ case PFUZE100:
+ default:
+ pfuze_matches = pfuze100_matches;
+ ret = of_regulator_match(dev, parent, pfuze100_matches,
+ ARRAY_SIZE(pfuze100_matches));
+ break;
+ }
of_node_put(parent);
if (ret < 0) {
@@ -275,12 +332,12 @@ static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
static inline struct regulator_init_data *match_init_data(int index)
{
- return pfuze100_matches[index].init_data;
+ return pfuze_matches[index].init_data;
}
static inline struct device_node *match_of_node(int index)
{
- return pfuze100_matches[index].of_node;
+ return pfuze_matches[index].of_node;
}
#else
static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
@@ -308,16 +365,14 @@ static int pfuze_identify(struct pfuze_chip *pfuze_chip)
if (ret)
return ret;
- switch (value & 0x0f) {
- /*
- * Freescale misprogrammed 1-3% of parts prior to week 8 of 2013
- * as ID=8
- */
- case 0x8:
+ if (((value & 0x0f) == 0x8) && (pfuze_chip->chip_id == PFUZE100)) {
+ /*
+ * Freescale misprogrammed 1-3% of parts prior to week 8 of 2013
+ * as ID=8 in PFUZE100
+ */
dev_info(pfuze_chip->dev, "Assuming misprogrammed ID=0x8");
- case 0x0:
- break;
- default:
+ } else if ((value & 0x0f) != pfuze_chip->chip_id) {
+ /* device id NOT match with your setting */
dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value);
return -ENODEV;
}
@@ -353,17 +408,31 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
dev_get_platdata(&client->dev);
struct regulator_config config = { };
int i, ret;
+ const struct of_device_id *match;
+ u32 regulator_num;
+ u32 sw_check_start, sw_check_end;
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));
+ if (client->dev.of_node) {
+ match = of_match_device(of_match_ptr(pfuze_dt_ids),
+ &client->dev);
+ if (!match) {
+ dev_err(&client->dev, "Error: No device match found\n");
+ return -ENODEV;
+ }
+ pfuze_chip->chip_id = (int)(long)match->data;
+ } else if (id) {
+ pfuze_chip->chip_id = id->driver_data;
+ } else {
+ dev_err(&client->dev, "No dts match or id table match found\n");
+ return -ENODEV;
+ }
+ i2c_set_clientdata(client, pfuze_chip);
pfuze_chip->dev = &client->dev;
pfuze_chip->regmap = devm_regmap_init_i2c(client, &pfuze_regmap_config);
@@ -380,11 +449,34 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
return ret;
}
+ /* use the right regulators after identify the right device */
+ switch (pfuze_chip->chip_id) {
+ case PFUZE200:
+ pfuze_regulators = pfuze200_regulators;
+ regulator_num = ARRAY_SIZE(pfuze200_regulators);
+ sw_check_start = PFUZE200_SW2;
+ sw_check_end = PFUZE200_SW3B;
+ break;
+
+ case PFUZE100:
+ default:
+ pfuze_regulators = pfuze100_regulators;
+ regulator_num = ARRAY_SIZE(pfuze100_regulators);
+ sw_check_start = PFUZE100_SW2;
+ sw_check_end = PFUZE100_SW4;
+ break;
+ }
+ dev_info(&client->dev, "pfuze%s found.\n",
+ (pfuze_chip->chip_id == PFUZE100) ? "100" : "200");
+
+ memcpy(pfuze_chip->regulator_descs, pfuze_regulators,
+ sizeof(pfuze_chip->regulator_descs));
+
ret = pfuze_parse_regulators_dt(pfuze_chip);
if (ret)
return ret;
- for (i = 0; i < PFUZE100_MAX_REGULATOR; i++) {
+ for (i = 0; i < regulator_num; i++) {
struct regulator_init_data *init_data;
struct regulator_desc *desc;
int val;
@@ -397,7 +489,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
init_data = match_init_data(i);
/* SW2~SW4 high bit check and modify the voltage value table */
- if (i > PFUZE100_SW1C && i < PFUZE100_SWBST) {
+ if (i >= sw_check_start && i <= sw_check_end) {
regmap_read(pfuze_chip->regmap, desc->vsel_reg, &val);
if (val & 0x40) {
desc->min_uV = 800000;
@@ -415,7 +507,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
devm_regulator_register(&client->dev, desc, &config);
if (IS_ERR(pfuze_chip->regulators[i])) {
dev_err(&client->dev, "register regulator%s failed\n",
- pfuze100_regulators[i].desc.name);
+ pfuze_regulators[i].desc.name);
return PTR_ERR(pfuze_chip->regulators[i]);
}
}
@@ -435,6 +527,6 @@ static struct i2c_driver pfuze_driver = {
module_i2c_driver(pfuze_driver);
MODULE_AUTHOR("Robin Gong <b38343@freescale.com>");
-MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100 PMIC");
+MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/PFUZE200 PMIC");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("i2c:pfuze100-regulator");
diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c
index b58affb33143..4c414ae109ae 100644
--- a/drivers/regulator/rc5t583-regulator.c
+++ b/drivers/regulator/rc5t583-regulator.c
@@ -119,7 +119,6 @@ static int rc5t583_regulator_probe(struct platform_device *pdev)
{
struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent);
struct rc5t583_platform_data *pdata = dev_get_platdata(rc5t583->dev);
- struct regulator_init_data *reg_data;
struct regulator_config config = { };
struct rc5t583_regulator *reg = NULL;
struct rc5t583_regulator *regs;
@@ -135,19 +134,11 @@ static int rc5t583_regulator_probe(struct platform_device *pdev)
regs = devm_kzalloc(&pdev->dev, RC5T583_REGULATOR_MAX *
sizeof(struct rc5t583_regulator), GFP_KERNEL);
- if (!regs) {
- dev_err(&pdev->dev, "Memory allocation failed exiting..\n");
+ if (!regs)
return -ENOMEM;
- }
for (id = 0; id < RC5T583_REGULATOR_MAX; ++id) {
- reg_data = pdata->reg_init_data[id];
-
- /* No need to register if there is no regulator data */
- if (!reg_data)
- continue;
-
reg = &regs[id];
ri = &rc5t583_reg_info[id];
reg->reg_info = ri;
@@ -169,7 +160,7 @@ static int rc5t583_regulator_probe(struct platform_device *pdev)
skip_ext_pwr_config:
config.dev = &pdev->dev;
- config.init_data = reg_data;
+ config.init_data = pdata->reg_init_data[id];
config.driver_data = reg;
config.regmap = rc5t583->regmap;
diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c
new file mode 100644
index 000000000000..808b3aa7a42c
--- /dev/null
+++ b/drivers/regulator/s2mpa01.c
@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd
+ * http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/bug.h>
+#include <linux/err.h>
+#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/s2mpa01.h>
+
+#define S2MPA01_REGULATOR_CNT ARRAY_SIZE(regulators)
+
+struct s2mpa01_info {
+ int ramp_delay24;
+ int ramp_delay3;
+ int ramp_delay5;
+ int ramp_delay16;
+ int ramp_delay7;
+ int ramp_delay8910;
+};
+
+static int get_ramp_delay(int ramp_delay)
+{
+ unsigned char cnt = 0;
+
+ ramp_delay /= 6250;
+
+ while (true) {
+ ramp_delay = ramp_delay >> 1;
+ if (ramp_delay == 0)
+ break;
+ cnt++;
+ }
+
+ if (cnt > 3)
+ cnt = 3;
+
+ return cnt;
+}
+
+static int s2mpa01_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
+ unsigned int old_selector,
+ unsigned int new_selector)
+{
+ struct s2mpa01_info *s2mpa01 = rdev_get_drvdata(rdev);
+ unsigned int ramp_delay = 0;
+ int old_volt, new_volt;
+
+ switch (rdev->desc->id) {
+ case S2MPA01_BUCK2:
+ case S2MPA01_BUCK4:
+ ramp_delay = s2mpa01->ramp_delay24;
+ break;
+ case S2MPA01_BUCK3:
+ ramp_delay = s2mpa01->ramp_delay3;
+ break;
+ case S2MPA01_BUCK5:
+ ramp_delay = s2mpa01->ramp_delay5;
+ break;
+ case S2MPA01_BUCK1:
+ case S2MPA01_BUCK6:
+ ramp_delay = s2mpa01->ramp_delay16;
+ break;
+ case S2MPA01_BUCK7:
+ ramp_delay = s2mpa01->ramp_delay7;
+ break;
+ case S2MPA01_BUCK8:
+ case S2MPA01_BUCK9:
+ case S2MPA01_BUCK10:
+ ramp_delay = s2mpa01->ramp_delay8910;
+ break;
+ }
+
+ 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 s2mpa01_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+ struct s2mpa01_info *s2mpa01 = rdev_get_drvdata(rdev);
+ unsigned int ramp_val, ramp_shift, ramp_reg = S2MPA01_REG_RAMP2;
+ unsigned int ramp_enable = 1, enable_shift = 0;
+ int ret;
+
+ switch (rdev->desc->id) {
+ case S2MPA01_BUCK1:
+ enable_shift = S2MPA01_BUCK1_RAMP_EN_SHIFT;
+ if (!ramp_delay) {
+ ramp_enable = 0;
+ break;
+ }
+
+ if (ramp_delay > s2mpa01->ramp_delay16)
+ s2mpa01->ramp_delay16 = ramp_delay;
+ else
+ ramp_delay = s2mpa01->ramp_delay16;
+
+ ramp_shift = S2MPA01_BUCK16_RAMP_SHIFT;
+ ramp_reg = S2MPA01_REG_RAMP1;
+ break;
+ case S2MPA01_BUCK2:
+ enable_shift = S2MPA01_BUCK2_RAMP_EN_SHIFT;
+ if (!ramp_delay) {
+ ramp_enable = 0;
+ break;
+ }
+
+ if (ramp_delay > s2mpa01->ramp_delay24)
+ s2mpa01->ramp_delay24 = ramp_delay;
+ else
+ ramp_delay = s2mpa01->ramp_delay24;
+
+ ramp_shift = S2MPA01_BUCK24_RAMP_SHIFT;
+ ramp_reg = S2MPA01_REG_RAMP1;
+ break;
+ case S2MPA01_BUCK3:
+ enable_shift = S2MPA01_BUCK3_RAMP_EN_SHIFT;
+ if (!ramp_delay) {
+ ramp_enable = 0;
+ break;
+ }
+
+ s2mpa01->ramp_delay3 = ramp_delay;
+ ramp_shift = S2MPA01_BUCK3_RAMP_SHIFT;
+ ramp_reg = S2MPA01_REG_RAMP1;
+ break;
+ case S2MPA01_BUCK4:
+ enable_shift = S2MPA01_BUCK4_RAMP_EN_SHIFT;
+ if (!ramp_delay) {
+ ramp_enable = 0;
+ break;
+ }
+
+ if (ramp_delay > s2mpa01->ramp_delay24)
+ s2mpa01->ramp_delay24 = ramp_delay;
+ else
+ ramp_delay = s2mpa01->ramp_delay24;
+
+ ramp_shift = S2MPA01_BUCK24_RAMP_SHIFT;
+ ramp_reg = S2MPA01_REG_RAMP1;
+ break;
+ case S2MPA01_BUCK5:
+ s2mpa01->ramp_delay5 = ramp_delay;
+ ramp_shift = S2MPA01_BUCK5_RAMP_SHIFT;
+ break;
+ case S2MPA01_BUCK6:
+ if (ramp_delay > s2mpa01->ramp_delay16)
+ s2mpa01->ramp_delay16 = ramp_delay;
+ else
+ ramp_delay = s2mpa01->ramp_delay16;
+
+ ramp_shift = S2MPA01_BUCK16_RAMP_SHIFT;
+ break;
+ case S2MPA01_BUCK7:
+ s2mpa01->ramp_delay7 = ramp_delay;
+ ramp_shift = S2MPA01_BUCK7_RAMP_SHIFT;
+ break;
+ case S2MPA01_BUCK8:
+ case S2MPA01_BUCK9:
+ case S2MPA01_BUCK10:
+ if (ramp_delay > s2mpa01->ramp_delay8910)
+ s2mpa01->ramp_delay8910 = ramp_delay;
+ else
+ ramp_delay = s2mpa01->ramp_delay8910;
+
+ ramp_shift = S2MPA01_BUCK8910_RAMP_SHIFT;
+ break;
+ default:
+ return 0;
+ }
+
+ if (!ramp_enable)
+ goto ramp_disable;
+
+ if (enable_shift) {
+ ret = regmap_update_bits(rdev->regmap, S2MPA01_REG_RAMP1,
+ 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, S2MPA01_REG_RAMP1,
+ 1 << enable_shift, 0);
+}
+
+static struct regulator_ops s2mpa01_ldo_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .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,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops s2mpa01_buck_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .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,
+ .set_voltage_time_sel = s2mpa01_regulator_set_voltage_time_sel,
+ .set_ramp_delay = s2mpa01_set_ramp_delay,
+};
+
+#define regulator_desc_ldo1(num) { \
+ .name = "LDO"#num, \
+ .id = S2MPA01_LDO##num, \
+ .ops = &s2mpa01_ldo_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPA01_LDO_MIN, \
+ .uV_step = S2MPA01_LDO_STEP1, \
+ .n_voltages = S2MPA01_LDO_N_VOLTAGES, \
+ .vsel_reg = S2MPA01_REG_L1CTRL + num - 1, \
+ .vsel_mask = S2MPA01_LDO_VSEL_MASK, \
+ .enable_reg = S2MPA01_REG_L1CTRL + num - 1, \
+ .enable_mask = S2MPA01_ENABLE_MASK \
+}
+#define regulator_desc_ldo2(num) { \
+ .name = "LDO"#num, \
+ .id = S2MPA01_LDO##num, \
+ .ops = &s2mpa01_ldo_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPA01_LDO_MIN, \
+ .uV_step = S2MPA01_LDO_STEP2, \
+ .n_voltages = S2MPA01_LDO_N_VOLTAGES, \
+ .vsel_reg = S2MPA01_REG_L1CTRL + num - 1, \
+ .vsel_mask = S2MPA01_LDO_VSEL_MASK, \
+ .enable_reg = S2MPA01_REG_L1CTRL + num - 1, \
+ .enable_mask = S2MPA01_ENABLE_MASK \
+}
+
+#define regulator_desc_buck1_4(num) { \
+ .name = "BUCK"#num, \
+ .id = S2MPA01_BUCK##num, \
+ .ops = &s2mpa01_buck_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPA01_BUCK_MIN1, \
+ .uV_step = S2MPA01_BUCK_STEP1, \
+ .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \
+ .ramp_delay = S2MPA01_RAMP_DELAY, \
+ .vsel_reg = S2MPA01_REG_B1CTRL2 + (num - 1) * 2, \
+ .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPA01_REG_B1CTRL1 + (num - 1) * 2, \
+ .enable_mask = S2MPA01_ENABLE_MASK \
+}
+
+#define regulator_desc_buck5 { \
+ .name = "BUCK5", \
+ .id = S2MPA01_BUCK5, \
+ .ops = &s2mpa01_buck_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPA01_BUCK_MIN2, \
+ .uV_step = S2MPA01_BUCK_STEP1, \
+ .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \
+ .ramp_delay = S2MPA01_RAMP_DELAY, \
+ .vsel_reg = S2MPA01_REG_B5CTRL2, \
+ .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPA01_REG_B5CTRL1, \
+ .enable_mask = S2MPA01_ENABLE_MASK \
+}
+
+#define regulator_desc_buck6_7(num) { \
+ .name = "BUCK"#num, \
+ .id = S2MPA01_BUCK##num, \
+ .ops = &s2mpa01_buck_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPA01_BUCK_MIN1, \
+ .uV_step = S2MPA01_BUCK_STEP1, \
+ .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \
+ .ramp_delay = S2MPA01_RAMP_DELAY, \
+ .vsel_reg = S2MPA01_REG_B6CTRL2 + (num - 6) * 2, \
+ .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPA01_REG_B6CTRL1 + (num - 6) * 2, \
+ .enable_mask = S2MPA01_ENABLE_MASK \
+}
+
+#define regulator_desc_buck8 { \
+ .name = "BUCK8", \
+ .id = S2MPA01_BUCK8, \
+ .ops = &s2mpa01_buck_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPA01_BUCK_MIN2, \
+ .uV_step = S2MPA01_BUCK_STEP2, \
+ .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \
+ .ramp_delay = S2MPA01_RAMP_DELAY, \
+ .vsel_reg = S2MPA01_REG_B8CTRL2, \
+ .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPA01_REG_B8CTRL1, \
+ .enable_mask = S2MPA01_ENABLE_MASK \
+}
+
+#define regulator_desc_buck9 { \
+ .name = "BUCK9", \
+ .id = S2MPA01_BUCK9, \
+ .ops = &s2mpa01_buck_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPA01_BUCK_MIN4, \
+ .uV_step = S2MPA01_BUCK_STEP2, \
+ .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \
+ .ramp_delay = S2MPA01_RAMP_DELAY, \
+ .vsel_reg = S2MPA01_REG_B9CTRL2, \
+ .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPA01_REG_B9CTRL1, \
+ .enable_mask = S2MPA01_ENABLE_MASK \
+}
+
+#define regulator_desc_buck10 { \
+ .name = "BUCK10", \
+ .id = S2MPA01_BUCK10, \
+ .ops = &s2mpa01_buck_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPA01_BUCK_MIN3, \
+ .uV_step = S2MPA01_BUCK_STEP2, \
+ .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \
+ .ramp_delay = S2MPA01_RAMP_DELAY, \
+ .vsel_reg = S2MPA01_REG_B10CTRL2, \
+ .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPA01_REG_B10CTRL1, \
+ .enable_mask = S2MPA01_ENABLE_MASK \
+}
+
+static struct regulator_desc regulators[] = {
+ regulator_desc_ldo2(1),
+ regulator_desc_ldo1(2),
+ regulator_desc_ldo1(3),
+ regulator_desc_ldo1(4),
+ regulator_desc_ldo1(5),
+ regulator_desc_ldo2(6),
+ regulator_desc_ldo1(7),
+ regulator_desc_ldo1(8),
+ regulator_desc_ldo1(9),
+ regulator_desc_ldo1(10),
+ regulator_desc_ldo2(11),
+ regulator_desc_ldo1(12),
+ regulator_desc_ldo1(13),
+ regulator_desc_ldo1(14),
+ regulator_desc_ldo1(15),
+ regulator_desc_ldo1(16),
+ regulator_desc_ldo1(17),
+ regulator_desc_ldo1(18),
+ regulator_desc_ldo1(19),
+ regulator_desc_ldo1(20),
+ regulator_desc_ldo1(21),
+ regulator_desc_ldo2(22),
+ regulator_desc_ldo2(23),
+ regulator_desc_ldo1(24),
+ regulator_desc_ldo1(25),
+ regulator_desc_ldo1(26),
+ regulator_desc_buck1_4(1),
+ regulator_desc_buck1_4(2),
+ regulator_desc_buck1_4(3),
+ regulator_desc_buck1_4(4),
+ regulator_desc_buck5,
+ regulator_desc_buck6_7(6),
+ regulator_desc_buck6_7(7),
+ regulator_desc_buck8,
+ regulator_desc_buck9,
+ regulator_desc_buck10,
+};
+
+static int s2mpa01_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[S2MPA01_REGULATOR_MAX];
+ struct device_node *reg_np = NULL;
+ struct regulator_config config = { };
+ struct s2mpa01_info *s2mpa01;
+ int i;
+
+ s2mpa01 = devm_kzalloc(&pdev->dev, sizeof(*s2mpa01), GFP_KERNEL);
+ if (!s2mpa01)
+ return -ENOMEM;
+
+ for (i = 0; i < S2MPA01_REGULATOR_CNT; i++)
+ rdata[i].name = regulators[i].name;
+
+ if (iodev->dev->of_node) {
+ reg_np = of_get_child_by_name(iodev->dev->of_node,
+ "regulators");
+ if (!reg_np) {
+ dev_err(&pdev->dev,
+ "could not find regulators sub-node\n");
+ return -EINVAL;
+ }
+
+ of_regulator_match(&pdev->dev, reg_np, rdata,
+ S2MPA01_REGULATOR_MAX);
+ of_node_put(reg_np);
+ }
+
+ platform_set_drvdata(pdev, s2mpa01);
+
+ config.dev = &pdev->dev;
+ config.regmap = iodev->regmap_pmic;
+ config.driver_data = s2mpa01;
+
+ for (i = 0; i < S2MPA01_REGULATOR_MAX; i++) {
+ struct regulator_dev *rdev;
+ if (pdata)
+ config.init_data = pdata->regulators[i].initdata;
+ else
+ config.init_data = rdata[i].init_data;
+
+ if (reg_np)
+ config.of_node = rdata[i].of_node;
+
+ rdev = devm_regulator_register(&pdev->dev,
+ &regulators[i], &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "regulator init failed for %d\n",
+ i);
+ return PTR_ERR(rdev);
+ }
+ }
+
+ return 0;
+}
+
+static const struct platform_device_id s2mpa01_pmic_id[] = {
+ { "s2mpa01-pmic", 0},
+ { },
+};
+MODULE_DEVICE_TABLE(platform, s2mpa01_pmic_id);
+
+static struct platform_driver s2mpa01_pmic_driver = {
+ .driver = {
+ .name = "s2mpa01-pmic",
+ .owner = THIS_MODULE,
+ },
+ .probe = s2mpa01_pmic_probe,
+ .id_table = s2mpa01_pmic_id,
+};
+
+module_platform_driver(s2mpa01_pmic_driver);
+
+/* Module information */
+MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
+MODULE_AUTHOR("Sachin Kamat <sachin.kamat@samsung.com>");
+MODULE_DESCRIPTION("SAMSUNG S2MPA01 Regulator Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
index cd0b9e35a56d..68fd54702edb 100644
--- a/drivers/regulator/s2mps11.c
+++ b/drivers/regulator/s2mps11.c
@@ -1,13 +1,18 @@
/*
* s2mps11.c
*
- * Copyright (c) 2012 Samsung Electronics Co., Ltd
+ * Copyright (c) 2012-2014 Samsung Electronics Co., Ltd
* http://www.samsung.com
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License 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 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.
*
*/
@@ -24,18 +29,21 @@
#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)
+#include <linux/mfd/samsung/s2mps14.h>
struct s2mps11_info {
- struct regulator_dev *rdev[S2MPS11_REGULATOR_MAX];
-
+ unsigned int rdev_num;
int ramp_delay2;
int ramp_delay34;
int ramp_delay5;
int ramp_delay16;
int ramp_delay7810;
int ramp_delay9;
+ /*
+ * One bit for each S2MPS14 regulator whether the suspend mode
+ * was enabled.
+ */
+ unsigned int s2mps14_suspend_state:30;
};
static int get_ramp_delay(int ramp_delay)
@@ -65,7 +73,7 @@ static int s2mps11_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
unsigned int ramp_delay = 0;
int old_volt, new_volt;
- switch (rdev->desc->id) {
+ switch (rdev_get_id(rdev)) {
case S2MPS11_BUCK2:
ramp_delay = s2mps11->ramp_delay2;
break;
@@ -105,7 +113,7 @@ static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
unsigned int ramp_enable = 1, enable_shift = 0;
int ret;
- switch (rdev->desc->id) {
+ switch (rdev_get_id(rdev)) {
case S2MPS11_BUCK1:
if (ramp_delay > s2mps11->ramp_delay16)
s2mps11->ramp_delay16 = ramp_delay;
@@ -236,7 +244,7 @@ static struct regulator_ops s2mps11_buck_ops = {
.set_ramp_delay = s2mps11_set_ramp_delay,
};
-#define regulator_desc_ldo1(num) { \
+#define regulator_desc_s2mps11_ldo1(num) { \
.name = "LDO"#num, \
.id = S2MPS11_LDO##num, \
.ops = &s2mps11_ldo_ops, \
@@ -250,7 +258,7 @@ static struct regulator_ops s2mps11_buck_ops = {
.enable_reg = S2MPS11_REG_L1CTRL + num - 1, \
.enable_mask = S2MPS11_ENABLE_MASK \
}
-#define regulator_desc_ldo2(num) { \
+#define regulator_desc_s2mps11_ldo2(num) { \
.name = "LDO"#num, \
.id = S2MPS11_LDO##num, \
.ops = &s2mps11_ldo_ops, \
@@ -265,7 +273,7 @@ static struct regulator_ops s2mps11_buck_ops = {
.enable_mask = S2MPS11_ENABLE_MASK \
}
-#define regulator_desc_buck1_4(num) { \
+#define regulator_desc_s2mps11_buck1_4(num) { \
.name = "BUCK"#num, \
.id = S2MPS11_BUCK##num, \
.ops = &s2mps11_buck_ops, \
@@ -281,7 +289,7 @@ static struct regulator_ops s2mps11_buck_ops = {
.enable_mask = S2MPS11_ENABLE_MASK \
}
-#define regulator_desc_buck5 { \
+#define regulator_desc_s2mps11_buck5 { \
.name = "BUCK5", \
.id = S2MPS11_BUCK5, \
.ops = &s2mps11_buck_ops, \
@@ -297,7 +305,7 @@ static struct regulator_ops s2mps11_buck_ops = {
.enable_mask = S2MPS11_ENABLE_MASK \
}
-#define regulator_desc_buck6_8(num) { \
+#define regulator_desc_s2mps11_buck6_8(num) { \
.name = "BUCK"#num, \
.id = S2MPS11_BUCK##num, \
.ops = &s2mps11_buck_ops, \
@@ -313,7 +321,7 @@ static struct regulator_ops s2mps11_buck_ops = {
.enable_mask = S2MPS11_ENABLE_MASK \
}
-#define regulator_desc_buck9 { \
+#define regulator_desc_s2mps11_buck9 { \
.name = "BUCK9", \
.id = S2MPS11_BUCK9, \
.ops = &s2mps11_buck_ops, \
@@ -329,7 +337,7 @@ static struct regulator_ops s2mps11_buck_ops = {
.enable_mask = S2MPS11_ENABLE_MASK \
}
-#define regulator_desc_buck10 { \
+#define regulator_desc_s2mps11_buck10 { \
.name = "BUCK10", \
.id = S2MPS11_BUCK10, \
.ops = &s2mps11_buck_ops, \
@@ -345,72 +353,252 @@ static struct regulator_ops s2mps11_buck_ops = {
.enable_mask = S2MPS11_ENABLE_MASK \
}
-static struct regulator_desc regulators[] = {
- regulator_desc_ldo2(1),
- regulator_desc_ldo1(2),
- regulator_desc_ldo1(3),
- regulator_desc_ldo1(4),
- regulator_desc_ldo1(5),
- regulator_desc_ldo2(6),
- regulator_desc_ldo1(7),
- regulator_desc_ldo1(8),
- regulator_desc_ldo1(9),
- regulator_desc_ldo1(10),
- regulator_desc_ldo2(11),
- regulator_desc_ldo1(12),
- regulator_desc_ldo1(13),
- regulator_desc_ldo1(14),
- regulator_desc_ldo1(15),
- regulator_desc_ldo1(16),
- regulator_desc_ldo1(17),
- regulator_desc_ldo1(18),
- regulator_desc_ldo1(19),
- regulator_desc_ldo1(20),
- regulator_desc_ldo1(21),
- regulator_desc_ldo2(22),
- regulator_desc_ldo2(23),
- regulator_desc_ldo1(24),
- regulator_desc_ldo1(25),
- regulator_desc_ldo1(26),
- regulator_desc_ldo2(27),
- regulator_desc_ldo1(28),
- regulator_desc_ldo1(29),
- regulator_desc_ldo1(30),
- regulator_desc_ldo1(31),
- regulator_desc_ldo1(32),
- regulator_desc_ldo1(33),
- regulator_desc_ldo1(34),
- regulator_desc_ldo1(35),
- regulator_desc_ldo1(36),
- regulator_desc_ldo1(37),
- regulator_desc_ldo1(38),
- regulator_desc_buck1_4(1),
- regulator_desc_buck1_4(2),
- regulator_desc_buck1_4(3),
- regulator_desc_buck1_4(4),
- regulator_desc_buck5,
- regulator_desc_buck6_8(6),
- regulator_desc_buck6_8(7),
- regulator_desc_buck6_8(8),
- regulator_desc_buck9,
- regulator_desc_buck10,
+static const struct regulator_desc s2mps11_regulators[] = {
+ regulator_desc_s2mps11_ldo2(1),
+ regulator_desc_s2mps11_ldo1(2),
+ regulator_desc_s2mps11_ldo1(3),
+ regulator_desc_s2mps11_ldo1(4),
+ regulator_desc_s2mps11_ldo1(5),
+ regulator_desc_s2mps11_ldo2(6),
+ regulator_desc_s2mps11_ldo1(7),
+ regulator_desc_s2mps11_ldo1(8),
+ regulator_desc_s2mps11_ldo1(9),
+ regulator_desc_s2mps11_ldo1(10),
+ regulator_desc_s2mps11_ldo2(11),
+ regulator_desc_s2mps11_ldo1(12),
+ regulator_desc_s2mps11_ldo1(13),
+ regulator_desc_s2mps11_ldo1(14),
+ regulator_desc_s2mps11_ldo1(15),
+ regulator_desc_s2mps11_ldo1(16),
+ regulator_desc_s2mps11_ldo1(17),
+ regulator_desc_s2mps11_ldo1(18),
+ regulator_desc_s2mps11_ldo1(19),
+ regulator_desc_s2mps11_ldo1(20),
+ regulator_desc_s2mps11_ldo1(21),
+ regulator_desc_s2mps11_ldo2(22),
+ regulator_desc_s2mps11_ldo2(23),
+ regulator_desc_s2mps11_ldo1(24),
+ regulator_desc_s2mps11_ldo1(25),
+ regulator_desc_s2mps11_ldo1(26),
+ regulator_desc_s2mps11_ldo2(27),
+ regulator_desc_s2mps11_ldo1(28),
+ regulator_desc_s2mps11_ldo1(29),
+ regulator_desc_s2mps11_ldo1(30),
+ regulator_desc_s2mps11_ldo1(31),
+ regulator_desc_s2mps11_ldo1(32),
+ regulator_desc_s2mps11_ldo1(33),
+ regulator_desc_s2mps11_ldo1(34),
+ regulator_desc_s2mps11_ldo1(35),
+ regulator_desc_s2mps11_ldo1(36),
+ regulator_desc_s2mps11_ldo1(37),
+ regulator_desc_s2mps11_ldo1(38),
+ regulator_desc_s2mps11_buck1_4(1),
+ regulator_desc_s2mps11_buck1_4(2),
+ regulator_desc_s2mps11_buck1_4(3),
+ regulator_desc_s2mps11_buck1_4(4),
+ regulator_desc_s2mps11_buck5,
+ regulator_desc_s2mps11_buck6_8(6),
+ regulator_desc_s2mps11_buck6_8(7),
+ regulator_desc_s2mps11_buck6_8(8),
+ regulator_desc_s2mps11_buck9,
+ regulator_desc_s2mps11_buck10,
+};
+
+static int s2mps14_regulator_enable(struct regulator_dev *rdev)
+{
+ struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+ unsigned int val;
+
+ if (s2mps11->s2mps14_suspend_state & (1 << rdev_get_id(rdev)))
+ val = S2MPS14_ENABLE_SUSPEND;
+ else
+ val = rdev->desc->enable_mask;
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, val);
+}
+
+static int s2mps14_regulator_set_suspend_disable(struct regulator_dev *rdev)
+{
+ int ret;
+ unsigned int val;
+ struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+
+ /* LDO3 should be always on and does not support suspend mode */
+ if (rdev_get_id(rdev) == S2MPS14_LDO3)
+ return 0;
+
+ ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val);
+ if (ret < 0)
+ return ret;
+
+ s2mps11->s2mps14_suspend_state |= (1 << rdev_get_id(rdev));
+ /*
+ * Don't enable suspend mode if regulator is already disabled because
+ * this would effectively for a short time turn on the regulator after
+ * resuming.
+ * However we still want to toggle the suspend_state bit for regulator
+ * in case if it got enabled before suspending the system.
+ */
+ if (!(val & rdev->desc->enable_mask))
+ return 0;
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, S2MPS14_ENABLE_SUSPEND);
+}
+
+static struct regulator_ops s2mps14_reg_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = s2mps14_regulator_enable,
+ .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_suspend_disable = s2mps14_regulator_set_suspend_disable,
+};
+
+#define regulator_desc_s2mps14_ldo1(num) { \
+ .name = "LDO"#num, \
+ .id = S2MPS14_LDO##num, \
+ .ops = &s2mps14_reg_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPS14_LDO_MIN_800MV, \
+ .uV_step = S2MPS14_LDO_STEP_25MV, \
+ .n_voltages = S2MPS14_LDO_N_VOLTAGES, \
+ .vsel_reg = S2MPS14_REG_L1CTRL + num - 1, \
+ .vsel_mask = S2MPS14_LDO_VSEL_MASK, \
+ .enable_reg = S2MPS14_REG_L1CTRL + num - 1, \
+ .enable_mask = S2MPS14_ENABLE_MASK \
+}
+#define regulator_desc_s2mps14_ldo2(num) { \
+ .name = "LDO"#num, \
+ .id = S2MPS14_LDO##num, \
+ .ops = &s2mps14_reg_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPS14_LDO_MIN_1800MV, \
+ .uV_step = S2MPS14_LDO_STEP_25MV, \
+ .n_voltages = S2MPS14_LDO_N_VOLTAGES, \
+ .vsel_reg = S2MPS14_REG_L1CTRL + num - 1, \
+ .vsel_mask = S2MPS14_LDO_VSEL_MASK, \
+ .enable_reg = S2MPS14_REG_L1CTRL + num - 1, \
+ .enable_mask = S2MPS14_ENABLE_MASK \
+}
+#define regulator_desc_s2mps14_ldo3(num) { \
+ .name = "LDO"#num, \
+ .id = S2MPS14_LDO##num, \
+ .ops = &s2mps14_reg_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPS14_LDO_MIN_800MV, \
+ .uV_step = S2MPS14_LDO_STEP_12_5MV, \
+ .n_voltages = S2MPS14_LDO_N_VOLTAGES, \
+ .vsel_reg = S2MPS14_REG_L1CTRL + num - 1, \
+ .vsel_mask = S2MPS14_LDO_VSEL_MASK, \
+ .enable_reg = S2MPS14_REG_L1CTRL + num - 1, \
+ .enable_mask = S2MPS14_ENABLE_MASK \
+}
+#define regulator_desc_s2mps14_buck1235(num) { \
+ .name = "BUCK"#num, \
+ .id = S2MPS14_BUCK##num, \
+ .ops = &s2mps14_reg_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPS14_BUCK1235_MIN_600MV, \
+ .uV_step = S2MPS14_BUCK1235_STEP_6_25MV, \
+ .n_voltages = S2MPS14_BUCK_N_VOLTAGES, \
+ .linear_min_sel = S2MPS14_BUCK1235_START_SEL, \
+ .ramp_delay = S2MPS14_BUCK_RAMP_DELAY, \
+ .vsel_reg = S2MPS14_REG_B1CTRL2 + (num - 1) * 2, \
+ .vsel_mask = S2MPS14_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPS14_REG_B1CTRL1 + (num - 1) * 2, \
+ .enable_mask = S2MPS14_ENABLE_MASK \
+}
+#define regulator_desc_s2mps14_buck4(num) { \
+ .name = "BUCK"#num, \
+ .id = S2MPS14_BUCK##num, \
+ .ops = &s2mps14_reg_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPS14_BUCK4_MIN_1400MV, \
+ .uV_step = S2MPS14_BUCK4_STEP_12_5MV, \
+ .n_voltages = S2MPS14_BUCK_N_VOLTAGES, \
+ .linear_min_sel = S2MPS14_BUCK4_START_SEL, \
+ .ramp_delay = S2MPS14_BUCK_RAMP_DELAY, \
+ .vsel_reg = S2MPS14_REG_B1CTRL2 + (num - 1) * 2, \
+ .vsel_mask = S2MPS14_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPS14_REG_B1CTRL1 + (num - 1) * 2, \
+ .enable_mask = S2MPS14_ENABLE_MASK \
+}
+
+static const struct regulator_desc s2mps14_regulators[] = {
+ regulator_desc_s2mps14_ldo3(1),
+ regulator_desc_s2mps14_ldo3(2),
+ regulator_desc_s2mps14_ldo1(3),
+ regulator_desc_s2mps14_ldo1(4),
+ regulator_desc_s2mps14_ldo3(5),
+ regulator_desc_s2mps14_ldo3(6),
+ regulator_desc_s2mps14_ldo1(7),
+ regulator_desc_s2mps14_ldo2(8),
+ regulator_desc_s2mps14_ldo3(9),
+ regulator_desc_s2mps14_ldo3(10),
+ regulator_desc_s2mps14_ldo1(11),
+ regulator_desc_s2mps14_ldo2(12),
+ regulator_desc_s2mps14_ldo2(13),
+ regulator_desc_s2mps14_ldo2(14),
+ regulator_desc_s2mps14_ldo2(15),
+ regulator_desc_s2mps14_ldo2(16),
+ regulator_desc_s2mps14_ldo2(17),
+ regulator_desc_s2mps14_ldo2(18),
+ regulator_desc_s2mps14_ldo1(19),
+ regulator_desc_s2mps14_ldo1(20),
+ regulator_desc_s2mps14_ldo1(21),
+ regulator_desc_s2mps14_ldo3(22),
+ regulator_desc_s2mps14_ldo1(23),
+ regulator_desc_s2mps14_ldo2(24),
+ regulator_desc_s2mps14_ldo2(25),
+ regulator_desc_s2mps14_buck1235(1),
+ regulator_desc_s2mps14_buck1235(2),
+ regulator_desc_s2mps14_buck1235(3),
+ regulator_desc_s2mps14_buck4(4),
+ regulator_desc_s2mps14_buck1235(5),
};
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 sec_platform_data *pdata = iodev->pdata;
+ struct of_regulator_match *rdata = NULL;
struct device_node *reg_np = NULL;
struct regulator_config config = { };
struct s2mps11_info *s2mps11;
- int i, ret;
+ int i, ret = 0;
+ const struct regulator_desc *regulators;
+ enum sec_device_type dev_type;
s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info),
GFP_KERNEL);
if (!s2mps11)
return -ENOMEM;
+ dev_type = platform_get_device_id(pdev)->driver_data;
+ switch (dev_type) {
+ case S2MPS11X:
+ s2mps11->rdev_num = ARRAY_SIZE(s2mps11_regulators);
+ regulators = s2mps11_regulators;
+ break;
+ case S2MPS14X:
+ s2mps11->rdev_num = ARRAY_SIZE(s2mps14_regulators);
+ regulators = s2mps14_regulators;
+ break;
+ default:
+ dev_err(&pdev->dev, "Invalid device type: %u\n", dev_type);
+ return -EINVAL;
+ };
+
if (!iodev->dev->of_node) {
if (pdata) {
goto common_reg;
@@ -421,16 +609,22 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
}
}
- for (i = 0; i < S2MPS11_REGULATOR_CNT; i++)
+ rdata = kzalloc(sizeof(*rdata) * s2mps11->rdev_num, GFP_KERNEL);
+ if (!rdata)
+ return -ENOMEM;
+
+ for (i = 0; i < s2mps11->rdev_num; i++)
rdata[i].name = regulators[i].name;
- reg_np = of_find_node_by_name(iodev->dev->of_node, "regulators");
+ reg_np = of_get_child_by_name(iodev->dev->of_node, "regulators");
if (!reg_np) {
dev_err(&pdev->dev, "could not find regulators sub-node\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
- of_regulator_match(&pdev->dev, reg_np, rdata, S2MPS11_REGULATOR_MAX);
+ of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num);
+ of_node_put(reg_np);
common_reg:
platform_set_drvdata(pdev, s2mps11);
@@ -438,7 +632,9 @@ common_reg:
config.dev = &pdev->dev;
config.regmap = iodev->regmap_pmic;
config.driver_data = s2mps11;
- for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) {
+ for (i = 0; i < s2mps11->rdev_num; i++) {
+ struct regulator_dev *regulator;
+
if (!reg_np) {
config.init_data = pdata->regulators[i].initdata;
config.of_node = pdata->regulators[i].reg_node;
@@ -447,21 +643,25 @@ common_reg:
config.of_node = rdata[i].of_node;
}
- s2mps11->rdev[i] = devm_regulator_register(&pdev->dev,
+ regulator = devm_regulator_register(&pdev->dev,
&regulators[i], &config);
- if (IS_ERR(s2mps11->rdev[i])) {
- ret = PTR_ERR(s2mps11->rdev[i]);
+ if (IS_ERR(regulator)) {
+ ret = PTR_ERR(regulator);
dev_err(&pdev->dev, "regulator init failed for %d\n",
i);
- return ret;
+ goto out;
}
}
- return 0;
+out:
+ kfree(rdata);
+
+ return ret;
}
static const struct platform_device_id s2mps11_pmic_id[] = {
- { "s2mps11-pmic", 0},
+ { "s2mps11-pmic", S2MPS11X},
+ { "s2mps14-pmic", S2MPS14X},
{ },
};
MODULE_DEVICE_TABLE(platform, s2mps11_pmic_id);
@@ -489,5 +689,5 @@ module_exit(s2mps11_pmic_exit);
/* Module information */
MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
-MODULE_DESCRIPTION("SAMSUNG S2MPS11 Regulator Driver");
+MODULE_DESCRIPTION("SAMSUNG S2MPS11/S2MPS14 Regulator Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
index d7164bb75d3e..f05badabd69e 100644
--- a/drivers/regulator/s5m8767.c
+++ b/drivers/regulator/s5m8767.c
@@ -11,11 +11,8 @@
*
*/
-#include <linux/bug.h>
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/of_gpio.h>
-#include <linux/slab.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
@@ -170,12 +167,11 @@ static unsigned int s5m8767_opmode_reg[][4] = {
{0x0, 0x3, 0x1, 0x1}, /* BUCK9 */
};
-static int s5m8767_get_register(struct regulator_dev *rdev, int *reg,
- int *enable_ctrl)
+static int s5m8767_get_register(struct s5m8767_info *s5m8767, int reg_id,
+ int *reg, int *enable_ctrl)
{
- int i, reg_id = rdev_get_id(rdev);
+ int i;
unsigned int mode;
- struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
switch (reg_id) {
case S5M8767_LDO1 ... S5M8767_LDO2:
@@ -214,53 +210,6 @@ static int s5m8767_get_register(struct regulator_dev *rdev, int *reg,
return 0;
}
-static int s5m8767_reg_is_enabled(struct regulator_dev *rdev)
-{
- struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
- int ret, reg;
- int enable_ctrl;
- unsigned int val;
-
- ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
- if (ret == -EINVAL)
- return 1;
- else if (ret)
- return ret;
-
- ret = regmap_read(s5m8767->iodev->regmap_pmic, reg, &val);
- if (ret)
- return ret;
-
- return (val & S5M8767_ENCTRL_MASK) == enable_ctrl;
-}
-
-static int s5m8767_reg_enable(struct regulator_dev *rdev)
-{
- struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
- int ret, reg;
- int enable_ctrl;
-
- ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
- if (ret)
- return ret;
-
- return regmap_update_bits(s5m8767->iodev->regmap_pmic, reg,
- S5M8767_ENCTRL_MASK, enable_ctrl);
-}
-
-static int s5m8767_reg_disable(struct regulator_dev *rdev)
-{
- struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
- int ret, reg, enable_ctrl;
-
- ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
- if (ret)
- return ret;
-
- return regmap_update_bits(s5m8767->iodev->regmap_pmic, reg,
- S5M8767_ENCTRL_MASK, ~S5M8767_ENCTRL_MASK);
-}
-
static int s5m8767_get_vsel_reg(int reg_id, struct s5m8767_info *s5m8767)
{
int reg;
@@ -410,9 +359,9 @@ static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,
static struct regulator_ops s5m8767_ops = {
.list_voltage = regulator_list_voltage_linear,
- .is_enabled = s5m8767_reg_is_enabled,
- .enable = s5m8767_reg_enable,
- .disable = s5m8767_reg_disable,
+ .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 = s5m8767_set_voltage_sel,
.set_voltage_time_sel = s5m8767_set_voltage_time_sel,
@@ -420,9 +369,9 @@ static struct regulator_ops s5m8767_ops = {
static struct regulator_ops s5m8767_buck78_ops = {
.list_voltage = regulator_list_voltage_linear,
- .is_enabled = s5m8767_reg_is_enabled,
- .enable = s5m8767_reg_enable,
- .disable = s5m8767_reg_disable,
+ .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,
};
@@ -483,6 +432,66 @@ static struct regulator_desc regulators[] = {
s5m8767_regulator_desc(BUCK9),
};
+/*
+ * Enable GPIO control over BUCK9 in regulator_config for that regulator.
+ */
+static void s5m8767_regulator_config_ext_control(struct s5m8767_info *s5m8767,
+ struct sec_regulator_data *rdata,
+ struct regulator_config *config)
+{
+ int i, mode = 0;
+
+ if (rdata->id != S5M8767_BUCK9)
+ return;
+
+ /* Check if opmode for regulator matches S5M8767_ENCTRL_USE_GPIO */
+ for (i = 0; i < s5m8767->num_regulators; i++) {
+ const struct sec_opmode_data *opmode = &s5m8767->opmode[i];
+ if (opmode->id == rdata->id) {
+ mode = s5m8767_opmode_reg[rdata->id][opmode->mode];
+ break;
+ }
+ }
+ if (mode != S5M8767_ENCTRL_USE_GPIO) {
+ dev_warn(s5m8767->dev,
+ "ext-control for %s: mismatched op_mode (%x), ignoring\n",
+ rdata->reg_node->name, mode);
+ return;
+ }
+
+ if (!gpio_is_valid(rdata->ext_control_gpio)) {
+ dev_warn(s5m8767->dev,
+ "ext-control for %s: GPIO not valid, ignoring\n",
+ rdata->reg_node->name);
+ return;
+ }
+
+ config->ena_gpio = rdata->ext_control_gpio;
+ config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
+}
+
+/*
+ * Turn on GPIO control over BUCK9.
+ */
+static int s5m8767_enable_ext_control(struct s5m8767_info *s5m8767,
+ struct regulator_dev *rdev)
+{
+ int id = rdev_get_id(rdev);
+ int ret, reg, enable_ctrl;
+
+ if (id != S5M8767_BUCK9)
+ return -EINVAL;
+
+ ret = s5m8767_get_register(s5m8767, id, &reg, &enable_ctrl);
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(s5m8767->iodev->regmap_pmic,
+ reg, S5M8767_ENCTRL_MASK,
+ S5M8767_ENCTRL_USE_GPIO << S5M8767_ENCTRL_SHIFT);
+}
+
+
#ifdef CONFIG_OF
static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev,
struct sec_platform_data *pdata,
@@ -520,6 +529,16 @@ static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev,
return 0;
}
+static void s5m8767_pmic_dt_parse_ext_control_gpio(struct sec_pmic_dev *iodev,
+ struct sec_regulator_data *rdata,
+ struct device_node *reg_np)
+{
+ rdata->ext_control_gpio = of_get_named_gpio(reg_np,
+ "s5m8767,pmic-ext-control-gpios", 0);
+ if (!gpio_is_valid(rdata->ext_control_gpio))
+ rdata->ext_control_gpio = 0;
+}
+
static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
struct sec_platform_data *pdata)
{
@@ -535,7 +554,7 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
return -ENODEV;
}
- regulators_np = of_find_node_by_name(pmic_np, "regulators");
+ regulators_np = of_get_child_by_name(pmic_np, "regulators");
if (!regulators_np) {
dev_err(iodev->dev, "could not find regulators sub-node\n");
return -EINVAL;
@@ -546,19 +565,13 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
pdata->num_regulators, GFP_KERNEL);
- if (!rdata) {
- dev_err(iodev->dev,
- "could not allocate memory for regulator data\n");
+ if (!rdata)
return -ENOMEM;
- }
rmode = devm_kzalloc(&pdev->dev, sizeof(*rmode) *
pdata->num_regulators, GFP_KERNEL);
- if (!rmode) {
- dev_err(iodev->dev,
- "could not allocate memory for regulator mode\n");
+ if (!rmode)
return -ENOMEM;
- }
pdata->regulators = rdata;
pdata->opmode = rmode;
@@ -574,6 +587,8 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
continue;
}
+ s5m8767_pmic_dt_parse_ext_control_gpio(iodev, rdata, reg_np);
+
rdata->id = i;
rdata->initdata = of_get_regulator_init_data(
&pdev->dev, reg_np);
@@ -591,6 +606,8 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
rmode++;
}
+ of_node_put(regulators_np);
+
if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL)) {
pdata->buck2_gpiodvs = true;
@@ -920,6 +937,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
for (i = 0; i < pdata->num_regulators; i++) {
const struct sec_voltage_desc *desc;
int id = pdata->regulators[i].id;
+ int enable_reg, enable_val;
desc = reg_voltage_map[id];
if (desc) {
@@ -933,6 +951,12 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
regulators[id].vsel_mask = 0x3f;
else
regulators[id].vsel_mask = 0xff;
+
+ s5m8767_get_register(s5m8767, id, &enable_reg,
+ &enable_val);
+ regulators[id].enable_reg = enable_reg;
+ regulators[id].enable_mask = S5M8767_ENCTRL_MASK;
+ regulators[id].enable_val = enable_val;
}
config.dev = s5m8767->dev;
@@ -940,6 +964,9 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
config.driver_data = s5m8767;
config.regmap = iodev->regmap_pmic;
config.of_node = pdata->regulators[i].reg_node;
+ if (pdata->regulators[i].ext_control_gpio)
+ s5m8767_regulator_config_ext_control(s5m8767,
+ &pdata->regulators[i], &config);
rdev[i] = devm_regulator_register(&pdev->dev, &regulators[id],
&config);
@@ -949,6 +976,16 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
id);
return ret;
}
+
+ if (pdata->regulators[i].ext_control_gpio) {
+ ret = s5m8767_enable_ext_control(s5m8767, rdev[i]);
+ if (ret < 0) {
+ dev_err(s5m8767->dev,
+ "failed to enable gpio control over %s: %d\n",
+ rdev[i]->desc->name, ret);
+ return ret;
+ }
+ }
}
return 0;
diff --git a/drivers/regulator/st-pwm.c b/drivers/regulator/st-pwm.c
new file mode 100644
index 000000000000..e367af1c5f9d
--- /dev/null
+++ b/drivers/regulator/st-pwm.c
@@ -0,0 +1,190 @@
+/*
+ * Regulator driver for ST's PWM Regulators
+ *
+ * Copyright (C) 2014 - STMicroelectronics Inc.
+ *
+ * Author: Lee Jones <lee.jones@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pwm.h>
+
+#define ST_PWM_REG_PERIOD 8448
+
+struct st_pwm_regulator_pdata {
+ const struct regulator_desc *desc;
+ struct st_pwm_voltages *duty_cycle_table;
+};
+
+struct st_pwm_regulator_data {
+ const struct st_pwm_regulator_pdata *pdata;
+ struct pwm_device *pwm;
+ bool enabled;
+ int state;
+};
+
+struct st_pwm_voltages {
+ unsigned int uV;
+ unsigned int dutycycle;
+};
+
+static int st_pwm_regulator_get_voltage_sel(struct regulator_dev *dev)
+{
+ struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
+
+ return drvdata->state;
+}
+
+static int st_pwm_regulator_set_voltage_sel(struct regulator_dev *dev,
+ unsigned selector)
+{
+ struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
+ int dutycycle;
+ int ret;
+
+ dutycycle = (ST_PWM_REG_PERIOD / 100) *
+ drvdata->pdata->duty_cycle_table[selector].dutycycle;
+
+ ret = pwm_config(drvdata->pwm, dutycycle, ST_PWM_REG_PERIOD);
+ if (ret) {
+ dev_err(&dev->dev, "Failed to configure PWM\n");
+ return ret;
+ }
+
+ drvdata->state = selector;
+
+ if (!drvdata->enabled) {
+ ret = pwm_enable(drvdata->pwm);
+ if (ret) {
+ dev_err(&dev->dev, "Failed to enable PWM\n");
+ return ret;
+ }
+ drvdata->enabled = true;
+ }
+
+ return 0;
+}
+
+static int st_pwm_regulator_list_voltage(struct regulator_dev *dev,
+ unsigned selector)
+{
+ struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
+
+ if (selector >= dev->desc->n_voltages)
+ return -EINVAL;
+
+ return drvdata->pdata->duty_cycle_table[selector].uV;
+}
+
+static struct regulator_ops st_pwm_regulator_voltage_ops = {
+ .set_voltage_sel = st_pwm_regulator_set_voltage_sel,
+ .get_voltage_sel = st_pwm_regulator_get_voltage_sel,
+ .list_voltage = st_pwm_regulator_list_voltage,
+ .map_voltage = regulator_map_voltage_iterate,
+};
+
+static struct st_pwm_voltages b2105_duty_cycle_table[] = {
+ { .uV = 1114000, .dutycycle = 0, },
+ { .uV = 1095000, .dutycycle = 10, },
+ { .uV = 1076000, .dutycycle = 20, },
+ { .uV = 1056000, .dutycycle = 30, },
+ { .uV = 1036000, .dutycycle = 40, },
+ { .uV = 1016000, .dutycycle = 50, },
+ /* WARNING: Values above 50% duty-cycle cause boot failures. */
+};
+
+static const struct regulator_desc b2105_desc = {
+ .name = "b2105-pwm-regulator",
+ .ops = &st_pwm_regulator_voltage_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(b2105_duty_cycle_table),
+ .supply_name = "pwm",
+};
+
+static const struct st_pwm_regulator_pdata b2105_info = {
+ .desc = &b2105_desc,
+ .duty_cycle_table = b2105_duty_cycle_table,
+};
+
+static struct of_device_id st_pwm_of_match[] = {
+ { .compatible = "st,b2105-pwm-regulator", .data = &b2105_info, },
+ { },
+};
+MODULE_DEVICE_TABLE(of, st_pwm_of_match);
+
+static int st_pwm_regulator_probe(struct platform_device *pdev)
+{
+ struct st_pwm_regulator_data *drvdata;
+ struct regulator_dev *regulator;
+ struct regulator_config config = { };
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *of_match;
+
+ if (!np) {
+ dev_err(&pdev->dev, "Device Tree node missing\n");
+ return -EINVAL;
+ }
+
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ of_match = of_match_device(st_pwm_of_match, &pdev->dev);
+ if (!of_match) {
+ dev_err(&pdev->dev, "failed to match of device\n");
+ return -ENODEV;
+ }
+ drvdata->pdata = of_match->data;
+
+ config.init_data = of_get_regulator_init_data(&pdev->dev, np);
+ if (!config.init_data)
+ return -ENOMEM;
+
+ config.of_node = np;
+ config.dev = &pdev->dev;
+ config.driver_data = drvdata;
+
+ drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);
+ if (IS_ERR(drvdata->pwm)) {
+ dev_err(&pdev->dev, "Failed to get PWM\n");
+ return PTR_ERR(drvdata->pwm);
+ }
+
+ regulator = devm_regulator_register(&pdev->dev,
+ drvdata->pdata->desc, &config);
+ if (IS_ERR(regulator)) {
+ dev_err(&pdev->dev, "Failed to register regulator %s\n",
+ drvdata->pdata->desc->name);
+ return PTR_ERR(regulator);
+ }
+
+ return 0;
+}
+
+static struct platform_driver st_pwm_regulator_driver = {
+ .driver = {
+ .name = "st-pwm-regulator",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(st_pwm_of_match),
+ },
+ .probe = st_pwm_regulator_probe,
+};
+
+module_platform_driver(st_pwm_regulator_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>");
+MODULE_DESCRIPTION("ST PWM Regulator Driver");
+MODULE_ALIAS("platform:st_pwm-regulator");
diff --git a/drivers/regulator/ti-abb-regulator.c b/drivers/regulator/ti-abb-regulator.c
index b187b6bba7ad..a2dabb575b97 100644
--- a/drivers/regulator/ti-abb-regulator.c
+++ b/drivers/regulator/ti-abb-regulator.c
@@ -54,8 +54,8 @@ struct ti_abb_info {
/**
* struct ti_abb_reg - Register description for ABB block
- * @setup_reg: setup register offset from base
- * @control_reg: control register offset from base
+ * @setup_off: setup register offset from base
+ * @control_off: control register offset from base
* @sr2_wtcnt_value_mask: setup register- sr2_wtcnt_value mask
* @fbb_sel_mask: setup register- FBB sel mask
* @rbb_sel_mask: setup register- RBB sel mask
@@ -64,8 +64,8 @@ struct ti_abb_info {
* @opp_sel_mask: control register - mask for mode to operate
*/
struct ti_abb_reg {
- u32 setup_reg;
- u32 control_reg;
+ u32 setup_off;
+ u32 control_off;
/* Setup register fields */
u32 sr2_wtcnt_value_mask;
@@ -83,6 +83,8 @@ struct ti_abb_reg {
* @rdesc: regulator descriptor
* @clk: clock(usually sysclk) supplying ABB block
* @base: base address of ABB block
+ * @setup_reg: setup register of ABB block
+ * @control_reg: control register of ABB block
* @int_base: interrupt register base address
* @efuse_base: (optional) efuse base address for ABB modes
* @ldo_base: (optional) LDOVBB vset override base address
@@ -99,6 +101,8 @@ struct ti_abb {
struct regulator_desc rdesc;
struct clk *clk;
void __iomem *base;
+ void __iomem *setup_reg;
+ void __iomem *control_reg;
void __iomem *int_base;
void __iomem *efuse_base;
void __iomem *ldo_base;
@@ -118,20 +122,18 @@ struct ti_abb {
* ti_abb_rmw() - handy wrapper to set specific register bits
* @mask: mask for register field
* @value: value shifted to mask location and written
- * @offset: offset of register
- * @base: base address
+ * @reg: register address
*
* Return: final register value (may be unused)
*/
-static inline u32 ti_abb_rmw(u32 mask, u32 value, u32 offset,
- void __iomem *base)
+static inline u32 ti_abb_rmw(u32 mask, u32 value, void __iomem *reg)
{
u32 val;
- val = readl(base + offset);
+ val = readl(reg);
val &= ~mask;
val |= (value << __ffs(mask)) & mask;
- writel(val, base + offset);
+ writel(val, reg);
return val;
}
@@ -263,21 +265,19 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb,
if (ret)
goto out;
- ti_abb_rmw(regs->fbb_sel_mask | regs->rbb_sel_mask, 0, regs->setup_reg,
- abb->base);
+ ti_abb_rmw(regs->fbb_sel_mask | regs->rbb_sel_mask, 0, abb->setup_reg);
switch (info->opp_sel) {
case TI_ABB_SLOW_OPP:
- ti_abb_rmw(regs->rbb_sel_mask, 1, regs->setup_reg, abb->base);
+ ti_abb_rmw(regs->rbb_sel_mask, 1, abb->setup_reg);
break;
case TI_ABB_FAST_OPP:
- ti_abb_rmw(regs->fbb_sel_mask, 1, regs->setup_reg, abb->base);
+ ti_abb_rmw(regs->fbb_sel_mask, 1, abb->setup_reg);
break;
}
/* program next state of ABB ldo */
- ti_abb_rmw(regs->opp_sel_mask, info->opp_sel, regs->control_reg,
- abb->base);
+ ti_abb_rmw(regs->opp_sel_mask, info->opp_sel, abb->control_reg);
/*
* program LDO VBB vset override if needed for !bypass mode
@@ -288,7 +288,7 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb,
ti_abb_program_ldovbb(dev, abb, info);
/* Initiate ABB ldo change */
- ti_abb_rmw(regs->opp_change_mask, 1, regs->control_reg, abb->base);
+ ti_abb_rmw(regs->opp_change_mask, 1, abb->control_reg);
/* Wait for ABB LDO to complete transition to new Bias setting */
ret = ti_abb_wait_txdone(dev, abb);
@@ -490,8 +490,7 @@ static int ti_abb_init_timings(struct device *dev, struct ti_abb *abb)
dev_dbg(dev, "%s: Clk_rate=%ld, sr2_cnt=0x%08x\n", __func__,
clk_get_rate(abb->clk), sr2_wt_cnt_val);
- ti_abb_rmw(regs->sr2_wtcnt_value_mask, sr2_wt_cnt_val, regs->setup_reg,
- abb->base);
+ ti_abb_rmw(regs->sr2_wtcnt_value_mask, sr2_wt_cnt_val, abb->setup_reg);
return 0;
}
@@ -508,32 +507,24 @@ static int ti_abb_init_table(struct device *dev, struct ti_abb *abb,
struct regulator_init_data *rinit_data)
{
struct ti_abb_info *info;
- const struct property *prop;
- const __be32 *abb_info;
const u32 num_values = 6;
char *pname = "ti,abb_info";
- u32 num_entries, i;
+ u32 i;
unsigned int *volt_table;
- int min_uV = INT_MAX, max_uV = 0;
+ int num_entries, min_uV = INT_MAX, max_uV = 0;
struct regulation_constraints *c = &rinit_data->constraints;
- prop = of_find_property(dev->of_node, pname, NULL);
- if (!prop) {
- dev_err(dev, "No '%s' property?\n", pname);
- return -ENODEV;
- }
-
- if (!prop->value) {
- dev_err(dev, "Empty '%s' property?\n", pname);
- return -ENODATA;
- }
-
/*
* Each abb_info is a set of n-tuple, where n is num_values, consisting
* of voltage and a set of detection logic for ABB information for that
* voltage to apply.
*/
- num_entries = prop->length / sizeof(u32);
+ num_entries = of_property_count_u32_elems(dev->of_node, pname);
+ if (num_entries < 0) {
+ dev_err(dev, "No '%s' property?\n", pname);
+ return num_entries;
+ }
+
if (!num_entries || (num_entries % num_values)) {
dev_err(dev, "All '%s' list entries need %d vals\n", pname,
num_values);
@@ -542,38 +533,38 @@ static int ti_abb_init_table(struct device *dev, struct ti_abb *abb,
num_entries /= num_values;
info = devm_kzalloc(dev, sizeof(*info) * num_entries, GFP_KERNEL);
- if (!info) {
- dev_err(dev, "Can't allocate info table for '%s' property\n",
- pname);
+ if (!info)
return -ENOMEM;
- }
+
abb->info = info;
volt_table = devm_kzalloc(dev, sizeof(unsigned int) * num_entries,
GFP_KERNEL);
- if (!volt_table) {
- dev_err(dev, "Can't allocate voltage table for '%s' property\n",
- pname);
+ if (!volt_table)
return -ENOMEM;
- }
abb->rdesc.n_voltages = num_entries;
abb->rdesc.volt_table = volt_table;
/* We do not know where the OPP voltage is at the moment */
abb->current_info_idx = -EINVAL;
- abb_info = prop->value;
for (i = 0; i < num_entries; i++, info++, volt_table++) {
u32 efuse_offset, rbb_mask, fbb_mask, vset_mask;
u32 efuse_val;
/* NOTE: num_values should equal to entries picked up here */
- *volt_table = be32_to_cpup(abb_info++);
- info->opp_sel = be32_to_cpup(abb_info++);
- efuse_offset = be32_to_cpup(abb_info++);
- rbb_mask = be32_to_cpup(abb_info++);
- fbb_mask = be32_to_cpup(abb_info++);
- vset_mask = be32_to_cpup(abb_info++);
+ of_property_read_u32_index(dev->of_node, pname, i * num_values,
+ volt_table);
+ of_property_read_u32_index(dev->of_node, pname,
+ i * num_values + 1, &info->opp_sel);
+ of_property_read_u32_index(dev->of_node, pname,
+ i * num_values + 2, &efuse_offset);
+ of_property_read_u32_index(dev->of_node, pname,
+ i * num_values + 3, &rbb_mask);
+ of_property_read_u32_index(dev->of_node, pname,
+ i * num_values + 4, &fbb_mask);
+ of_property_read_u32_index(dev->of_node, pname,
+ i * num_values + 5, &vset_mask);
dev_dbg(dev,
"[%d]v=%d ABB=%d ef=0x%x rbb=0x%x fbb=0x%x vset=0x%x\n",
@@ -648,8 +639,8 @@ static struct regulator_ops ti_abb_reg_ops = {
/* Default ABB block offsets, IF this changes in future, create new one */
static const struct ti_abb_reg abb_regs_v1 = {
/* WARNING: registers are wrongly documented in TRM */
- .setup_reg = 0x04,
- .control_reg = 0x00,
+ .setup_off = 0x04,
+ .control_off = 0x00,
.sr2_wtcnt_value_mask = (0xff << 8),
.fbb_sel_mask = (0x01 << 2),
@@ -661,8 +652,8 @@ static const struct ti_abb_reg abb_regs_v1 = {
};
static const struct ti_abb_reg abb_regs_v2 = {
- .setup_reg = 0x00,
- .control_reg = 0x04,
+ .setup_off = 0x00,
+ .control_off = 0x04,
.sr2_wtcnt_value_mask = (0xff << 8),
.fbb_sel_mask = (0x01 << 2),
@@ -673,9 +664,20 @@ static const struct ti_abb_reg abb_regs_v2 = {
.opp_sel_mask = (0x03 << 0),
};
+static const struct ti_abb_reg abb_regs_generic = {
+ .sr2_wtcnt_value_mask = (0xff << 8),
+ .fbb_sel_mask = (0x01 << 2),
+ .rbb_sel_mask = (0x01 << 1),
+ .sr2_en_mask = (0x01 << 0),
+
+ .opp_change_mask = (0x01 << 2),
+ .opp_sel_mask = (0x03 << 0),
+};
+
static const struct of_device_id ti_abb_of_match[] = {
{.compatible = "ti,abb-v1", .data = &abb_regs_v1},
{.compatible = "ti,abb-v2", .data = &abb_regs_v2},
+ {.compatible = "ti,abb-v3", .data = &abb_regs_generic},
{ },
};
@@ -722,11 +724,29 @@ static int ti_abb_probe(struct platform_device *pdev)
abb->regs = match->data;
/* Map ABB resources */
- pname = "base-address";
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
- abb->base = devm_ioremap_resource(dev, res);
- if (IS_ERR(abb->base))
- return PTR_ERR(abb->base);
+ if (abb->regs->setup_off || abb->regs->control_off) {
+ pname = "base-address";
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
+ abb->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(abb->base))
+ return PTR_ERR(abb->base);
+
+ abb->setup_reg = abb->base + abb->regs->setup_off;
+ abb->control_reg = abb->base + abb->regs->control_off;
+
+ } else {
+ pname = "control-address";
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
+ abb->control_reg = devm_ioremap_resource(dev, res);
+ if (IS_ERR(abb->control_reg))
+ return PTR_ERR(abb->control_reg);
+
+ pname = "setup-address";
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
+ abb->setup_reg = devm_ioremap_resource(dev, res);
+ if (IS_ERR(abb->setup_reg))
+ return PTR_ERR(abb->setup_reg);
+ }
pname = "int-address";
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
@@ -860,7 +880,7 @@ skip_opt:
platform_set_drvdata(pdev, rdev);
/* Enable the ldo if not already done by bootloader */
- ti_abb_rmw(abb->regs->sr2_en_mask, 1, abb->regs->setup_reg, abb->base);
+ ti_abb_rmw(abb->regs->sr2_en_mask, 1, abb->setup_reg);
return 0;
}
diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c
index b3764f594ee9..f31f22e3e1bd 100644
--- a/drivers/regulator/tps51632-regulator.c
+++ b/drivers/regulator/tps51632-regulator.c
@@ -227,10 +227,8 @@ static struct tps51632_regulator_platform_data *
struct device_node *np = dev->of_node;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(dev, "Memory alloc failed for platform data\n");
+ if (!pdata)
return NULL;
- }
pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node);
if (!pdata->reg_init_data) {
@@ -299,10 +297,8 @@ static int tps51632_probe(struct i2c_client *client,
}
tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
- if (!tps) {
- dev_err(&client->dev, "Memory allocation failed\n");
+ if (!tps)
return -ENOMEM;
- }
tps->dev = &client->dev;
tps->desc.name = client->name;
diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c
index c3fa15a299b1..a1672044e519 100644
--- a/drivers/regulator/tps62360-regulator.c
+++ b/drivers/regulator/tps62360-regulator.c
@@ -299,10 +299,8 @@ static struct tps62360_regulator_platform_data *
struct device_node *np = dev->of_node;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(dev, "Memory alloc failed for platform data\n");
+ if (!pdata)
return NULL;
- }
pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node);
if (!pdata->reg_init_data) {
@@ -377,11 +375,8 @@ static int tps62360_probe(struct i2c_client *client,
}
tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
- if (!tps) {
- dev_err(&client->dev, "%s(): Memory allocation failed\n",
- __func__);
+ if (!tps)
return -ENOMEM;
- }
tps->en_discharge = pdata->en_discharge;
tps->en_internal_pulldn = pdata->en_internal_pulldn;
diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c
index 162a0fae20b3..98e66ce26723 100644
--- a/drivers/regulator/tps6507x-regulator.c
+++ b/drivers/regulator/tps6507x-regulator.c
@@ -359,7 +359,6 @@ static struct regulator_ops tps6507x_pmic_ops = {
.map_voltage = regulator_map_voltage_ascend,
};
-#ifdef CONFIG_OF
static struct of_regulator_match tps6507x_matches[] = {
{ .name = "VDCDC1"},
{ .name = "VDCDC2"},
@@ -381,12 +380,10 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data(
tps_board = devm_kzalloc(&pdev->dev, sizeof(*tps_board),
GFP_KERNEL);
- if (!tps_board) {
- dev_err(&pdev->dev, "Failure to alloc pdata for regulators.\n");
+ if (!tps_board)
return NULL;
- }
- regulators = of_find_node_by_name(np, "regulators");
+ regulators = of_get_child_by_name(np, "regulators");
if (!regulators) {
dev_err(&pdev->dev, "regulator node not found\n");
return NULL;
@@ -396,6 +393,7 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data(
matches = tps6507x_matches;
ret = of_regulator_match(&pdev->dev, regulators, matches, count);
+ of_node_put(regulators);
if (ret < 0) {
dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
ret);
@@ -406,10 +404,8 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data(
reg_data = devm_kzalloc(&pdev->dev, (sizeof(struct regulator_init_data)
* TPS6507X_NUM_REGULATOR), GFP_KERNEL);
- if (!reg_data) {
- dev_err(&pdev->dev, "Failure to alloc init data for regulators.\n");
+ if (!reg_data)
return NULL;
- }
tps_board->tps6507x_pmic_init_data = reg_data;
@@ -424,15 +420,7 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data(
return tps_board;
}
-#else
-static inline struct tps6507x_board *tps6507x_parse_dt_reg_data(
- struct platform_device *pdev,
- struct of_regulator_match **tps6507x_reg_matches)
-{
- *tps6507x_reg_matches = NULL;
- return NULL;
-}
-#endif
+
static int tps6507x_pmic_probe(struct platform_device *pdev)
{
struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
@@ -453,9 +441,10 @@ static int tps6507x_pmic_probe(struct platform_device *pdev)
*/
tps_board = dev_get_platdata(tps6507x_dev->dev);
- if (!tps_board && tps6507x_dev->dev->of_node)
+ if (IS_ENABLED(CONFIG_OF) && !tps_board &&
+ tps6507x_dev->dev->of_node)
tps_board = tps6507x_parse_dt_reg_data(pdev,
- &tps6507x_reg_matches);
+ &tps6507x_reg_matches);
if (!tps_board)
return -EINVAL;
@@ -481,7 +470,7 @@ static int tps6507x_pmic_probe(struct platform_device *pdev)
tps->info[i] = info;
if (init_data->driver_data) {
struct tps6507x_reg_platform_data *data =
- init_data->driver_data;
+ init_data->driver_data;
tps->info[i]->defdcdc_default = data->defdcdc_default;
}
diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c
index 676f75548f00..2e92ef68574d 100644
--- a/drivers/regulator/tps65090-regulator.c
+++ b/drivers/regulator/tps65090-regulator.c
@@ -168,17 +168,13 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data(
tps65090_pdata = devm_kzalloc(&pdev->dev, sizeof(*tps65090_pdata),
GFP_KERNEL);
- if (!tps65090_pdata) {
- dev_err(&pdev->dev, "Memory alloc for tps65090_pdata failed\n");
+ if (!tps65090_pdata)
return ERR_PTR(-ENOMEM);
- }
reg_pdata = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX *
sizeof(*reg_pdata), GFP_KERNEL);
- if (!reg_pdata) {
- dev_err(&pdev->dev, "Memory alloc for reg_pdata failed\n");
+ if (!reg_pdata)
return ERR_PTR(-ENOMEM);
- }
regulators = of_get_child_by_name(np, "regulators");
if (!regulators) {
@@ -188,6 +184,7 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data(
ret = of_regulator_match(&pdev->dev, regulators, tps65090_matches,
ARRAY_SIZE(tps65090_matches));
+ of_node_put(regulators);
if (ret < 0) {
dev_err(&pdev->dev,
"Error parsing regulator init data: %d\n", ret);
@@ -252,10 +249,8 @@ static int tps65090_regulator_probe(struct platform_device *pdev)
pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic),
GFP_KERNEL);
- if (!pmic) {
- dev_err(&pdev->dev, "mem alloc for pmic failed\n");
+ if (!pmic)
return -ENOMEM;
- }
for (num = 0; num < TPS65090_REGULATOR_MAX; num++) {
tps_pdata = tps65090_pdata->reg_pdata[num];
diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c
index 9ea1bf26bd13..10b78d2b766a 100644
--- a/drivers/regulator/tps65217-regulator.c
+++ b/drivers/regulator/tps65217-regulator.c
@@ -187,7 +187,7 @@ static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev)
struct device_node *regs;
int i, count;
- regs = of_find_node_by_name(node, "regulators");
+ regs = of_get_child_by_name(node, "regulators");
if (!regs)
return NULL;
@@ -202,7 +202,7 @@ static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev)
return NULL;
for (i = 0; i < count; i++) {
- if (!reg_matches[i].init_data || !reg_matches[i].of_node)
+ if (!reg_matches[i].of_node)
continue;
pdata->tps65217_init_data[i] = reg_matches[i].init_data;
@@ -222,7 +222,6 @@ static int tps65217_regulator_probe(struct platform_device *pdev)
{
struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
struct tps65217_board *pdata = dev_get_platdata(tps->dev);
- struct regulator_init_data *reg_data;
struct regulator_dev *rdev;
struct regulator_config config = { };
int i;
@@ -243,19 +242,9 @@ static int tps65217_regulator_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, tps);
for (i = 0; i < TPS65217_NUM_REGULATOR; i++) {
-
- reg_data = pdata->tps65217_init_data[i];
-
- /*
- * Regulator API handles empty constraints but not NULL
- * constraints
- */
- if (!reg_data)
- continue;
-
/* Register the regulators */
config.dev = tps->dev;
- config.init_data = reg_data;
+ config.init_data = pdata->tps65217_init_data[i];
config.driver_data = tps;
config.regmap = tps->regmap;
if (tps->dev->of_node)
diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c
new file mode 100644
index 000000000000..cec72fa71d1d
--- /dev/null
+++ b/drivers/regulator/tps65218-regulator.c
@@ -0,0 +1,285 @@
+/*
+ * tps65218-regulator.c
+ *
+ * Regulator driver for TPS65218 PMIC
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.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 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether expressed or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License version 2 for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/tps65218.h>
+
+static unsigned int tps65218_ramp_delay = 4000;
+
+enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4, DCDC5, DCDC6, LDO1 };
+
+#define TPS65218_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _er, _em, _t, \
+ _lr, _nlr) \
+ { \
+ .name = _name, \
+ .id = _id, \
+ .ops = &_ops, \
+ .n_voltages = _n, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .vsel_reg = _vr, \
+ .vsel_mask = _vm, \
+ .enable_reg = _er, \
+ .enable_mask = _em, \
+ .volt_table = _t, \
+ .linear_ranges = _lr, \
+ .n_linear_ranges = _nlr, \
+ } \
+
+#define TPS65218_INFO(_id, _nm, _min, _max) \
+ { \
+ .id = _id, \
+ .name = _nm, \
+ .min_uV = _min, \
+ .max_uV = _max, \
+ }
+
+static const struct regulator_linear_range dcdc1_dcdc2_ranges[] = {
+ REGULATOR_LINEAR_RANGE(850000, 0x0, 0x32, 10000),
+ REGULATOR_LINEAR_RANGE(1375000, 0x33, 0x3f, 25000),
+};
+
+static const struct regulator_linear_range ldo1_dcdc3_ranges[] = {
+ REGULATOR_LINEAR_RANGE(900000, 0x0, 0x1a, 25000),
+ REGULATOR_LINEAR_RANGE(1600000, 0x1b, 0x3f, 50000),
+};
+
+static const struct regulator_linear_range dcdc4_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1175000, 0x0, 0xf, 25000),
+ REGULATOR_LINEAR_RANGE(1550000, 0x10, 0x34, 50000),
+};
+
+static struct tps_info tps65218_pmic_regs[] = {
+ TPS65218_INFO(0, "DCDC1", 850000, 167500),
+ TPS65218_INFO(1, "DCDC2", 850000, 1675000),
+ TPS65218_INFO(2, "DCDC3", 900000, 3400000),
+ TPS65218_INFO(3, "DCDC4", 1175000, 3400000),
+ TPS65218_INFO(4, "DCDC5", 1000000, 1000000),
+ TPS65218_INFO(5, "DCDC6", 1800000, 1800000),
+ TPS65218_INFO(6, "LDO1", 900000, 3400000),
+};
+
+#define TPS65218_OF_MATCH(comp, label) \
+ { \
+ .compatible = comp, \
+ .data = &label, \
+ }
+
+static const struct of_device_id tps65218_of_match[] = {
+ TPS65218_OF_MATCH("ti,tps65218-dcdc1", tps65218_pmic_regs[DCDC1]),
+ TPS65218_OF_MATCH("ti,tps65218-dcdc2", tps65218_pmic_regs[DCDC2]),
+ TPS65218_OF_MATCH("ti,tps65218-dcdc3", tps65218_pmic_regs[DCDC3]),
+ TPS65218_OF_MATCH("ti,tps65218-dcdc4", tps65218_pmic_regs[DCDC4]),
+ TPS65218_OF_MATCH("ti,tps65218-dcdc5", tps65218_pmic_regs[DCDC5]),
+ TPS65218_OF_MATCH("ti,tps65218-dcdc6", tps65218_pmic_regs[DCDC6]),
+ TPS65218_OF_MATCH("ti,tps65218-ldo1", tps65218_pmic_regs[LDO1]),
+ { }
+};
+MODULE_DEVICE_TABLE(of, tps65218_of_match);
+
+static int tps65218_pmic_set_voltage_sel(struct regulator_dev *dev,
+ unsigned selector)
+{
+ int ret;
+ struct tps65218 *tps = rdev_get_drvdata(dev);
+ unsigned int rid = rdev_get_id(dev);
+
+ /* Set the voltage based on vsel value and write protect level is 2 */
+ ret = tps65218_set_bits(tps, dev->desc->vsel_reg, dev->desc->vsel_mask,
+ selector, TPS65218_PROTECT_L1);
+
+ /* Set GO bit for DCDC1/2 to initiate voltage transistion */
+ switch (rid) {
+ case TPS65218_DCDC_1:
+ case TPS65218_DCDC_2:
+ ret = tps65218_set_bits(tps, TPS65218_REG_CONTRL_SLEW_RATE,
+ TPS65218_SLEW_RATE_GO,
+ TPS65218_SLEW_RATE_GO,
+ TPS65218_PROTECT_L1);
+ break;
+ }
+
+ return ret;
+}
+
+static int tps65218_pmic_enable(struct regulator_dev *dev)
+{
+ struct tps65218 *tps = rdev_get_drvdata(dev);
+ unsigned int rid = rdev_get_id(dev);
+
+ if (rid < TPS65218_DCDC_1 || rid > TPS65218_LDO_1)
+ return -EINVAL;
+
+ /* Enable the regulator and password protection is level 1 */
+ return tps65218_set_bits(tps, dev->desc->enable_reg,
+ dev->desc->enable_mask, dev->desc->enable_mask,
+ TPS65218_PROTECT_L1);
+}
+
+static int tps65218_pmic_disable(struct regulator_dev *dev)
+{
+ struct tps65218 *tps = rdev_get_drvdata(dev);
+ unsigned int rid = rdev_get_id(dev);
+
+ if (rid < TPS65218_DCDC_1 || rid > TPS65218_LDO_1)
+ return -EINVAL;
+
+ /* Disable the regulator and password protection is level 1 */
+ return tps65218_clear_bits(tps, dev->desc->enable_reg,
+ dev->desc->enable_mask, TPS65218_PROTECT_L1);
+}
+
+static int tps65218_set_voltage_time_sel(struct regulator_dev *rdev,
+ unsigned int old_selector, unsigned int new_selector)
+{
+ int old_uv, new_uv;
+
+ old_uv = regulator_list_voltage_linear_range(rdev, old_selector);
+ if (old_uv < 0)
+ return old_uv;
+
+ new_uv = regulator_list_voltage_linear_range(rdev, new_selector);
+ if (new_uv < 0)
+ return new_uv;
+
+ return DIV_ROUND_UP(abs(old_uv - new_uv), tps65218_ramp_delay);
+}
+
+/* Operations permitted on DCDC1, DCDC2 */
+static struct regulator_ops tps65218_dcdc12_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = tps65218_pmic_enable,
+ .disable = tps65218_pmic_disable,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = tps65218_pmic_set_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .set_voltage_time_sel = tps65218_set_voltage_time_sel,
+};
+
+/* Operations permitted on DCDC3, DCDC4 and LDO1 */
+static struct regulator_ops tps65218_ldo1_dcdc34_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = tps65218_pmic_enable,
+ .disable = tps65218_pmic_disable,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = tps65218_pmic_set_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+};
+
+/* Operations permitted on DCDC5, DCDC6 */
+static struct regulator_ops tps65218_dcdc56_pmic_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = tps65218_pmic_enable,
+ .disable = tps65218_pmic_disable,
+};
+
+static const struct regulator_desc regulators[] = {
+ TPS65218_REGULATOR("DCDC1", TPS65218_DCDC_1, tps65218_dcdc12_ops, 64,
+ TPS65218_REG_CONTROL_DCDC1,
+ TPS65218_CONTROL_DCDC1_MASK,
+ TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC1_EN, NULL,
+ dcdc1_dcdc2_ranges, 2),
+ TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, tps65218_dcdc12_ops, 64,
+ TPS65218_REG_CONTROL_DCDC2,
+ TPS65218_CONTROL_DCDC2_MASK,
+ TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC2_EN, NULL,
+ dcdc1_dcdc2_ranges, 2),
+ TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, tps65218_ldo1_dcdc34_ops,
+ 64, TPS65218_REG_CONTROL_DCDC3,
+ TPS65218_CONTROL_DCDC3_MASK, TPS65218_REG_ENABLE1,
+ TPS65218_ENABLE1_DC3_EN, NULL,
+ ldo1_dcdc3_ranges, 2),
+ TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, tps65218_ldo1_dcdc34_ops,
+ 53, TPS65218_REG_CONTROL_DCDC4,
+ TPS65218_CONTROL_DCDC4_MASK,
+ TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC4_EN, NULL,
+ dcdc4_ranges, 2),
+ TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, tps65218_dcdc56_pmic_ops,
+ 1, -1, -1, TPS65218_REG_ENABLE1,
+ TPS65218_ENABLE1_DC5_EN, NULL, NULL, 0),
+ TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, tps65218_dcdc56_pmic_ops,
+ 1, -1, -1, TPS65218_REG_ENABLE1,
+ TPS65218_ENABLE1_DC6_EN, NULL, NULL, 0),
+ TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, tps65218_ldo1_dcdc34_ops, 64,
+ TPS65218_REG_CONTROL_DCDC4,
+ TPS65218_CONTROL_LDO1_MASK, TPS65218_REG_ENABLE2,
+ TPS65218_ENABLE2_LDO1_EN, NULL, ldo1_dcdc3_ranges,
+ 2),
+};
+
+static int tps65218_regulator_probe(struct platform_device *pdev)
+{
+ struct tps65218 *tps = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_init_data *init_data;
+ const struct tps_info *template;
+ struct regulator_dev *rdev;
+ const struct of_device_id *match;
+ struct regulator_config config = { };
+ int id;
+
+ match = of_match_device(tps65218_of_match, &pdev->dev);
+ if (!match)
+ return -ENODEV;
+
+ template = match->data;
+ id = template->id;
+ init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node);
+
+ platform_set_drvdata(pdev, tps);
+
+ tps->info[id] = &tps65218_pmic_regs[id];
+ config.dev = &pdev->dev;
+ config.init_data = init_data;
+ config.driver_data = tps;
+ config.regmap = tps->regmap;
+
+ rdev = devm_regulator_register(&pdev->dev, &regulators[id], &config);
+ if (IS_ERR(rdev)) {
+ dev_err(tps->dev, "failed to register %s regulator\n",
+ pdev->name);
+ return PTR_ERR(rdev);
+ }
+
+ return 0;
+}
+
+static struct platform_driver tps65218_regulator_driver = {
+ .driver = {
+ .name = "tps65218-pmic",
+ .owner = THIS_MODULE,
+ .of_match_table = tps65218_of_match,
+ },
+ .probe = tps65218_regulator_probe,
+};
+
+module_platform_driver(tps65218_regulator_driver);
+
+MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>");
+MODULE_DESCRIPTION("TPS65218 voltage regulator driver");
+MODULE_ALIAS("platform:tps65218-pmic");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c
index 9f6bfda711b7..5b494db9f95c 100644
--- a/drivers/regulator/tps6524x-regulator.c
+++ b/drivers/regulator/tps6524x-regulator.c
@@ -593,10 +593,9 @@ static int pmic_probe(struct spi_device *spi)
}
hw = devm_kzalloc(&spi->dev, sizeof(struct tps6524x), GFP_KERNEL);
- if (!hw) {
- dev_err(dev, "cannot allocate regulator private data\n");
+ if (!hw)
return -ENOMEM;
- }
+
spi_set_drvdata(spi, hw);
memset(hw, 0, sizeof(struct tps6524x));
diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c
index 0485d47f0d8a..32f38a63d944 100644
--- a/drivers/regulator/tps6586x-regulator.c
+++ b/drivers/regulator/tps6586x-regulator.c
@@ -363,10 +363,8 @@ static struct tps6586x_platform_data *tps6586x_parse_regulator_dt(
}
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(&pdev->dev, "Memory alloction failed\n");
+ if (!pdata)
return NULL;
- }
for (i = 0; i < num; i++) {
int id;
@@ -398,7 +396,7 @@ static int tps6586x_regulator_probe(struct platform_device *pdev)
{
struct tps6586x_regulator *ri = NULL;
struct regulator_config config = { };
- struct regulator_dev **rdev;
+ struct regulator_dev *rdev;
struct regulator_init_data *reg_data;
struct tps6586x_platform_data *pdata;
struct of_regulator_match *tps6586x_reg_matches = NULL;
@@ -418,13 +416,6 @@ static int tps6586x_regulator_probe(struct platform_device *pdev)
return -ENODEV;
}
- rdev = devm_kzalloc(&pdev->dev, TPS6586X_ID_MAX_REGULATOR *
- sizeof(*rdev), GFP_KERNEL);
- if (!rdev) {
- dev_err(&pdev->dev, "Mmemory alloc failed\n");
- return -ENOMEM;
- }
-
version = tps6586x_get_version(pdev->dev.parent);
for (id = 0; id < TPS6586X_ID_MAX_REGULATOR; ++id) {
@@ -451,12 +442,11 @@ static int tps6586x_regulator_probe(struct platform_device *pdev)
if (tps6586x_reg_matches)
config.of_node = tps6586x_reg_matches[id].of_node;
- rdev[id] = devm_regulator_register(&pdev->dev, &ri->desc,
- &config);
- if (IS_ERR(rdev[id])) {
+ rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config);
+ if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
ri->desc.name);
- return PTR_ERR(rdev[id]);
+ return PTR_ERR(rdev);
}
if (reg_data) {
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
index f50dd847eebc..fa7db8847578 100644
--- a/drivers/regulator/tps65910-regulator.c
+++ b/drivers/regulator/tps65910-regulator.c
@@ -1011,11 +1011,8 @@ static struct tps65910_board *tps65910_parse_dt_reg_data(
pmic_plat_data = devm_kzalloc(&pdev->dev, sizeof(*pmic_plat_data),
GFP_KERNEL);
-
- if (!pmic_plat_data) {
- dev_err(&pdev->dev, "Failure to alloc pdata for regulators.\n");
+ if (!pmic_plat_data)
return NULL;
- }
np = of_node_get(pdev->dev.parent->of_node);
regulators = of_get_child_by_name(np, "regulators");
@@ -1098,10 +1095,8 @@ static int tps65910_probe(struct platform_device *pdev)
}
pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
- if (!pmic) {
- dev_err(&pdev->dev, "Memory allocation failed for pmic\n");
+ if (!pmic)
return -ENOMEM;
- }
pmic->mfd = tps65910;
platform_set_drvdata(pdev, pmic);
@@ -1130,24 +1125,18 @@ static int tps65910_probe(struct platform_device *pdev)
pmic->desc = devm_kzalloc(&pdev->dev, pmic->num_regulators *
sizeof(struct regulator_desc), GFP_KERNEL);
- if (!pmic->desc) {
- dev_err(&pdev->dev, "Memory alloc fails for desc\n");
+ if (!pmic->desc)
return -ENOMEM;
- }
pmic->info = devm_kzalloc(&pdev->dev, pmic->num_regulators *
sizeof(struct tps_info *), GFP_KERNEL);
- if (!pmic->info) {
- dev_err(&pdev->dev, "Memory alloc fails for info\n");
+ if (!pmic->info)
return -ENOMEM;
- }
pmic->rdev = devm_kzalloc(&pdev->dev, pmic->num_regulators *
sizeof(struct regulator_dev *), GFP_KERNEL);
- if (!pmic->rdev) {
- dev_err(&pdev->dev, "Memory alloc fails for rdev\n");
+ if (!pmic->rdev)
return -ENOMEM;
- }
for (i = 0; i < pmic->num_regulators && i < TPS65910_NUM_REGS;
i++, info++) {
diff --git a/drivers/regulator/tps80031-regulator.c b/drivers/regulator/tps80031-regulator.c
index 71f457a42623..26aa6d9c308f 100644
--- a/drivers/regulator/tps80031-regulator.c
+++ b/drivers/regulator/tps80031-regulator.c
@@ -115,7 +115,7 @@ static int tps80031_reg_is_enabled(struct regulator_dev *rdev)
ri->rinfo->state_reg, ret);
return ret;
}
- return ((reg_val & TPS80031_STATE_MASK) == TPS80031_STATE_ON);
+ return (reg_val & TPS80031_STATE_MASK) == TPS80031_STATE_ON;
}
static int tps80031_reg_enable(struct regulator_dev *rdev)
@@ -693,10 +693,8 @@ static int tps80031_regulator_probe(struct platform_device *pdev)
pmic = devm_kzalloc(&pdev->dev,
TPS80031_REGULATOR_MAX * sizeof(*pmic), GFP_KERNEL);
- if (!pmic) {
- dev_err(&pdev->dev, "mem alloc for pmic failed\n");
+ if (!pmic)
return -ENOMEM;
- }
for (num = 0; num < TPS80031_REGULATOR_MAX; ++num) {
tps_pdata = pdata->regulator_pdata[num];
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c
index 04cf9c16ef23..0d88a82ab2a2 100644
--- a/drivers/regulator/wm831x-dcdc.c
+++ b/drivers/regulator/wm831x-dcdc.c
@@ -469,10 +469,8 @@ static int wm831x_buckv_probe(struct platform_device *pdev)
dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc),
GFP_KERNEL);
- if (dcdc == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!dcdc)
return -ENOMEM;
- }
dcdc->wm831x = wm831x;
@@ -622,10 +620,8 @@ static int wm831x_buckp_probe(struct platform_device *pdev)
dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc),
GFP_KERNEL);
- if (dcdc == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!dcdc)
return -ENOMEM;
- }
dcdc->wm831x = wm831x;
@@ -752,10 +748,8 @@ static int wm831x_boostp_probe(struct platform_device *pdev)
return -ENODEV;
dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL);
- if (dcdc == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!dcdc)
return -ENOMEM;
- }
dcdc->wm831x = wm831x;
@@ -842,10 +836,8 @@ static int wm831x_epe_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Probing EPE%d\n", id + 1);
dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL);
- if (dcdc == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!dcdc)
return -ENOMEM;
- }
dcdc->wm831x = wm831x;
diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c
index 0339b886df5d..72e385e76a9d 100644
--- a/drivers/regulator/wm831x-isink.c
+++ b/drivers/regulator/wm831x-isink.c
@@ -165,10 +165,8 @@ static int wm831x_isink_probe(struct platform_device *pdev)
isink = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_isink),
GFP_KERNEL);
- if (isink == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!isink)
return -ENOMEM;
- }
isink->wm831x = wm831x;
diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c
index 46d6700467b5..eca0eeb78acd 100644
--- a/drivers/regulator/wm831x-ldo.c
+++ b/drivers/regulator/wm831x-ldo.c
@@ -235,10 +235,8 @@ static int wm831x_gp_ldo_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
- if (ldo == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!ldo)
return -ENOMEM;
- }
ldo->wm831x = wm831x;
@@ -447,10 +445,8 @@ static int wm831x_aldo_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
- if (ldo == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!ldo)
return -ENOMEM;
- }
ldo->wm831x = wm831x;
@@ -594,10 +590,8 @@ static int wm831x_alive_ldo_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
- if (ldo == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!ldo)
return -ENOMEM;
- }
ldo->wm831x = wm831x;
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
index de7b9c73e3fa..7ec7c390eeda 100644
--- a/drivers/regulator/wm8350-regulator.c
+++ b/drivers/regulator/wm8350-regulator.c
@@ -361,7 +361,7 @@ static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV)
sel = regulator_map_voltage_linear(rdev, uV, uV);
if (sel < 0)
- return -EINVAL;
+ return sel;
/* all DCDCs have same mV bits */
val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
@@ -574,7 +574,7 @@ static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
sel = regulator_map_voltage_linear_range(rdev, uV, uV);
if (sel < 0)
- return -EINVAL;
+ return sel;
/* all LDOs have same mV bits */
val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c
index 71c5911f2e71..c24346db8a71 100644
--- a/drivers/regulator/wm8994-regulator.c
+++ b/drivers/regulator/wm8994-regulator.c
@@ -134,10 +134,8 @@ static int wm8994_ldo_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm8994_ldo), GFP_KERNEL);
- if (ldo == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!ldo)
return -ENOMEM;
- }
ldo->wm8994 = wm8994;
ldo->supply = wm8994_ldo_consumer[id];
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index db933decc39c..2e565f8e5165 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -573,6 +573,18 @@ config RTC_DRV_DS1305
This driver can also be built as a module. If so, the module
will be called rtc-ds1305.
+config RTC_DRV_DS1347
+ tristate "Dallas/Maxim DS1347"
+ help
+ If you say yes here you get support for the
+ Dallas/Maxim DS1347 chips.
+
+ This driver only supports the RTC feature, and not other chip
+ features such as alarms.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ds1347.
+
config RTC_DRV_DS1390
tristate "Dallas/Maxim DS1390/93/94"
help
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index b427bf7dd20d..40a09915c8f6 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o
obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o
obj-$(CONFIG_RTC_DRV_DS1305) += rtc-ds1305.o
obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o
+obj-$(CONFIG_RTC_DRV_DS1347) += rtc-ds1347.o
obj-$(CONFIG_RTC_DRV_DS1374) += rtc-ds1374.o
obj-$(CONFIG_RTC_DRV_DS1390) += rtc-ds1390.o
obj-$(CONFIG_RTC_DRV_DS1511) += rtc-ds1511.o
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 544be722937c..c2eff6082363 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -584,6 +584,9 @@ enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer)
void rtc_update_irq(struct rtc_device *rtc,
unsigned long num, unsigned long events)
{
+ if (unlikely(IS_ERR_OR_NULL(rtc)))
+ return;
+
pm_stay_awake(rtc->dev.parent);
schedule_work(&rtc->irqwork);
}
diff --git a/drivers/rtc/rtc-as3722.c b/drivers/rtc/rtc-as3722.c
index 4af016985890..9f38eda69154 100644
--- a/drivers/rtc/rtc-as3722.c
+++ b/drivers/rtc/rtc-as3722.c
@@ -242,9 +242,8 @@ static int as3722_rtc_resume(struct device *dev)
}
#endif
-static const struct dev_pm_ops as3722_rtc_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(as3722_rtc_suspend, as3722_rtc_resume)
-};
+static SIMPLE_DEV_PM_OPS(as3722_rtc_pm_ops, as3722_rtc_suspend,
+ as3722_rtc_resume);
static struct platform_driver as3722_rtc_driver = {
.probe = as3722_rtc_probe,
diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c
index 3161ab5263ed..aee3387fb099 100644
--- a/drivers/rtc/rtc-at32ap700x.c
+++ b/drivers/rtc/rtc-at32ap700x.c
@@ -204,10 +204,8 @@ static int __init at32_rtc_probe(struct platform_device *pdev)
rtc = devm_kzalloc(&pdev->dev, sizeof(struct rtc_at32ap700x),
GFP_KERNEL);
- if (!rtc) {
- dev_dbg(&pdev->dev, "out of memory\n");
+ if (!rtc)
return -ENOMEM;
- }
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index cae212f30d65..0963c9309c74 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -837,7 +837,7 @@ static void __exit cmos_do_remove(struct device *dev)
cmos->dev = NULL;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int cmos_suspend(struct device *dev)
{
@@ -935,8 +935,6 @@ static int cmos_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(cmos_pm_ops, cmos_suspend, cmos_resume);
-
#else
static inline int cmos_poweroff(struct device *dev)
@@ -946,6 +944,8 @@ static inline int cmos_poweroff(struct device *dev)
#endif
+static SIMPLE_DEV_PM_OPS(cmos_pm_ops, cmos_suspend, cmos_resume);
+
/*----------------------------------------------------------------*/
/* On non-x86 systems, a "CMOS" RTC lives most naturally on platform_bus.
@@ -1088,11 +1088,9 @@ static struct pnp_driver cmos_pnp_driver = {
/* flag ensures resume() gets called, and stops syslog spam */
.flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
-#ifdef CONFIG_PM_SLEEP
.driver = {
.pm = &cmos_pm_ops,
},
-#endif
};
#endif /* CONFIG_PNP */
diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c
index 73f157519dff..869cae273799 100644
--- a/drivers/rtc/rtc-coh901331.c
+++ b/drivers/rtc/rtc-coh901331.c
@@ -43,8 +43,6 @@
struct coh901331_port {
struct rtc_device *rtc;
struct clk *clk;
- u32 phybase;
- u32 physize;
void __iomem *virtbase;
int irq;
#ifdef CONFIG_PM_SLEEP
@@ -173,19 +171,9 @@ static int __init coh901331_probe(struct platform_device *pdev)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENOENT;
-
- rtap->phybase = res->start;
- rtap->physize = resource_size(res);
-
- if (devm_request_mem_region(&pdev->dev, rtap->phybase, rtap->physize,
- "rtc-coh901331") == NULL)
- return -EBUSY;
-
- rtap->virtbase = devm_ioremap(&pdev->dev, rtap->phybase, rtap->physize);
- if (!rtap->virtbase)
- return -ENOMEM;
+ rtap->virtbase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(rtap->virtbase))
+ return PTR_ERR(rtap->virtbase);
rtap->irq = platform_get_irq(pdev, 0);
if (devm_request_irq(&pdev->dev, rtap->irq, coh901331_interrupt, 0,
diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c
index 4385ca4503da..a1cbf64242a5 100644
--- a/drivers/rtc/rtc-da9052.c
+++ b/drivers/rtc/rtc-da9052.c
@@ -26,7 +26,6 @@
struct da9052_rtc {
struct rtc_device *rtc;
struct da9052 *da9052;
- int irq;
};
static int da9052_rtc_enable_alarm(struct da9052 *da9052, bool enable)
@@ -240,8 +239,7 @@ static int da9052_rtc_probe(struct platform_device *pdev)
rtc->da9052 = dev_get_drvdata(pdev->dev.parent);
platform_set_drvdata(pdev, rtc);
- rtc->irq = DA9052_IRQ_ALARM;
- ret = da9052_request_irq(rtc->da9052, rtc->irq, "ALM",
+ ret = da9052_request_irq(rtc->da9052, DA9052_IRQ_ALARM, "ALM",
da9052_rtc_irq, rtc);
if (ret != 0) {
rtc_err(rtc->da9052, "irq registration failed: %d\n", ret);
diff --git a/drivers/rtc/rtc-da9055.c b/drivers/rtc/rtc-da9055.c
index 48cb2ac3bd3e..a825491331c8 100644
--- a/drivers/rtc/rtc-da9055.c
+++ b/drivers/rtc/rtc-da9055.c
@@ -302,7 +302,9 @@ static int da9055_rtc_probe(struct platform_device *pdev)
}
alm_irq = platform_get_irq_byname(pdev, "ALM");
- alm_irq = regmap_irq_get_virq(rtc->da9055->irq_data, alm_irq);
+ if (alm_irq < 0)
+ return alm_irq;
+
ret = devm_request_threaded_irq(&pdev->dev, alm_irq, NULL,
da9055_rtc_alm_irq,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c
index 24677ef8c39a..c0a3b59f65a2 100644
--- a/drivers/rtc/rtc-davinci.c
+++ b/drivers/rtc/rtc-davinci.c
@@ -119,8 +119,6 @@ static DEFINE_SPINLOCK(davinci_rtc_lock);
struct davinci_rtc {
struct rtc_device *rtc;
void __iomem *base;
- resource_size_t pbase;
- size_t base_size;
int irq;
};
@@ -482,14 +480,12 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct davinci_rtc *davinci_rtc;
- struct resource *res, *mem;
+ struct resource *res;
int ret = 0;
davinci_rtc = devm_kzalloc(&pdev->dev, sizeof(struct davinci_rtc), GFP_KERNEL);
- if (!davinci_rtc) {
- dev_dbg(dev, "could not allocate memory for private data\n");
+ if (!davinci_rtc)
return -ENOMEM;
- }
davinci_rtc->irq = platform_get_irq(pdev, 0);
if (davinci_rtc->irq < 0) {
@@ -498,28 +494,9 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "no mem resource\n");
- return -EINVAL;
- }
-
- davinci_rtc->pbase = res->start;
- davinci_rtc->base_size = resource_size(res);
-
- mem = devm_request_mem_region(dev, davinci_rtc->pbase,
- davinci_rtc->base_size, pdev->name);
- if (!mem) {
- dev_err(dev, "RTC registers at %08x are not free\n",
- davinci_rtc->pbase);
- return -EBUSY;
- }
-
- davinci_rtc->base = devm_ioremap(dev, davinci_rtc->pbase,
- davinci_rtc->base_size);
- if (!davinci_rtc->base) {
- dev_err(dev, "unable to ioremap MEM resource\n");
- return -ENOMEM;
- }
+ davinci_rtc->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(davinci_rtc->base))
+ return PTR_ERR(davinci_rtc->base);
platform_set_drvdata(pdev, davinci_rtc);
diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c
index 2dd586a19b59..129add77065d 100644
--- a/drivers/rtc/rtc-ds1305.c
+++ b/drivers/rtc/rtc-ds1305.c
@@ -756,19 +756,17 @@ static int ds1305_probe(struct spi_device *spi)
status = devm_request_irq(&spi->dev, spi->irq, ds1305_irq,
0, dev_name(&ds1305->rtc->dev), ds1305);
if (status < 0) {
- dev_dbg(&spi->dev, "request_irq %d --> %d\n",
+ dev_err(&spi->dev, "request_irq %d --> %d\n",
spi->irq, status);
- return status;
+ } else {
+ device_set_wakeup_capable(&spi->dev, 1);
}
-
- device_set_wakeup_capable(&spi->dev, 1);
}
/* export NVRAM */
status = sysfs_create_bin_file(&spi->dev.kobj, &nvram);
if (status < 0) {
- dev_dbg(&spi->dev, "register nvram --> %d\n", status);
- return status;
+ dev_err(&spi->dev, "register nvram --> %d\n", status);
}
return 0;
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 4e75345a559a..f03d5ba96db1 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -154,6 +154,7 @@ static const struct chip_desc chips[last_ds_type] = {
.alarm = 1,
},
[mcp7941x] = {
+ .alarm = 1,
/* this is battery backed SRAM */
.nvram_offset = 0x20,
.nvram_size = 0x40,
@@ -606,6 +607,178 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {
/*----------------------------------------------------------------------*/
+/*
+ * Alarm support for mcp7941x devices.
+ */
+
+#define MCP7941X_REG_CONTROL 0x07
+# define MCP7941X_BIT_ALM0_EN 0x10
+# define MCP7941X_BIT_ALM1_EN 0x20
+#define MCP7941X_REG_ALARM0_BASE 0x0a
+#define MCP7941X_REG_ALARM0_CTRL 0x0d
+#define MCP7941X_REG_ALARM1_BASE 0x11
+#define MCP7941X_REG_ALARM1_CTRL 0x14
+# define MCP7941X_BIT_ALMX_IF (1 << 3)
+# define MCP7941X_BIT_ALMX_C0 (1 << 4)
+# define MCP7941X_BIT_ALMX_C1 (1 << 5)
+# define MCP7941X_BIT_ALMX_C2 (1 << 6)
+# define MCP7941X_BIT_ALMX_POL (1 << 7)
+# define MCP7941X_MSK_ALMX_MATCH (MCP7941X_BIT_ALMX_C0 | \
+ MCP7941X_BIT_ALMX_C1 | \
+ MCP7941X_BIT_ALMX_C2)
+
+static void mcp7941x_work(struct work_struct *work)
+{
+ struct ds1307 *ds1307 = container_of(work, struct ds1307, work);
+ struct i2c_client *client = ds1307->client;
+ int reg, ret;
+
+ mutex_lock(&ds1307->rtc->ops_lock);
+
+ /* Check and clear alarm 0 interrupt flag. */
+ reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_ALARM0_CTRL);
+ if (reg < 0)
+ goto out;
+ if (!(reg & MCP7941X_BIT_ALMX_IF))
+ goto out;
+ reg &= ~MCP7941X_BIT_ALMX_IF;
+ ret = i2c_smbus_write_byte_data(client, MCP7941X_REG_ALARM0_CTRL, reg);
+ if (ret < 0)
+ goto out;
+
+ /* Disable alarm 0. */
+ reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_CONTROL);
+ if (reg < 0)
+ goto out;
+ reg &= ~MCP7941X_BIT_ALM0_EN;
+ ret = i2c_smbus_write_byte_data(client, MCP7941X_REG_CONTROL, reg);
+ if (ret < 0)
+ goto out;
+
+ rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF);
+
+out:
+ if (test_bit(HAS_ALARM, &ds1307->flags))
+ enable_irq(client->irq);
+ mutex_unlock(&ds1307->rtc->ops_lock);
+}
+
+static int mcp7941x_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1307 *ds1307 = i2c_get_clientdata(client);
+ u8 *regs = ds1307->regs;
+ int ret;
+
+ if (!test_bit(HAS_ALARM, &ds1307->flags))
+ return -EINVAL;
+
+ /* Read control and alarm 0 registers. */
+ ret = ds1307->read_block_data(client, MCP7941X_REG_CONTROL, 10, regs);
+ if (ret < 0)
+ return ret;
+
+ t->enabled = !!(regs[0] & MCP7941X_BIT_ALM0_EN);
+
+ /* Report alarm 0 time assuming 24-hour and day-of-month modes. */
+ t->time.tm_sec = bcd2bin(ds1307->regs[3] & 0x7f);
+ t->time.tm_min = bcd2bin(ds1307->regs[4] & 0x7f);
+ t->time.tm_hour = bcd2bin(ds1307->regs[5] & 0x3f);
+ t->time.tm_wday = bcd2bin(ds1307->regs[6] & 0x7) - 1;
+ t->time.tm_mday = bcd2bin(ds1307->regs[7] & 0x3f);
+ t->time.tm_mon = bcd2bin(ds1307->regs[8] & 0x1f) - 1;
+ t->time.tm_year = -1;
+ t->time.tm_yday = -1;
+ t->time.tm_isdst = -1;
+
+ dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d "
+ "enabled=%d polarity=%d irq=%d match=%d\n", __func__,
+ t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
+ t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, t->enabled,
+ !!(ds1307->regs[6] & MCP7941X_BIT_ALMX_POL),
+ !!(ds1307->regs[6] & MCP7941X_BIT_ALMX_IF),
+ (ds1307->regs[6] & MCP7941X_MSK_ALMX_MATCH) >> 4);
+
+ return 0;
+}
+
+static int mcp7941x_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1307 *ds1307 = i2c_get_clientdata(client);
+ unsigned char *regs = ds1307->regs;
+ int ret;
+
+ if (!test_bit(HAS_ALARM, &ds1307->flags))
+ return -EINVAL;
+
+ dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d "
+ "enabled=%d pending=%d\n", __func__,
+ t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
+ t->time.tm_wday, t->time.tm_mday, t->time.tm_mon,
+ t->enabled, t->pending);
+
+ /* Read control and alarm 0 registers. */
+ ret = ds1307->read_block_data(client, MCP7941X_REG_CONTROL, 10, regs);
+ if (ret < 0)
+ return ret;
+
+ /* Set alarm 0, using 24-hour and day-of-month modes. */
+ regs[3] = bin2bcd(t->time.tm_sec);
+ regs[4] = bin2bcd(t->time.tm_min);
+ regs[5] = bin2bcd(t->time.tm_hour);
+ regs[6] = bin2bcd(t->time.tm_wday) + 1;
+ regs[7] = bin2bcd(t->time.tm_mday);
+ regs[8] = bin2bcd(t->time.tm_mon) + 1;
+
+ /* Clear the alarm 0 interrupt flag. */
+ regs[6] &= ~MCP7941X_BIT_ALMX_IF;
+ /* Set alarm match: second, minute, hour, day, date, month. */
+ regs[6] |= MCP7941X_MSK_ALMX_MATCH;
+
+ if (t->enabled)
+ regs[0] |= MCP7941X_BIT_ALM0_EN;
+ else
+ regs[0] &= ~MCP7941X_BIT_ALM0_EN;
+
+ ret = ds1307->write_block_data(client, MCP7941X_REG_CONTROL, 10, regs);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int mcp7941x_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1307 *ds1307 = i2c_get_clientdata(client);
+ int reg;
+
+ if (!test_bit(HAS_ALARM, &ds1307->flags))
+ return -EINVAL;
+
+ reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_CONTROL);
+ if (reg < 0)
+ return reg;
+
+ if (enabled)
+ reg |= MCP7941X_BIT_ALM0_EN;
+ else
+ reg &= ~MCP7941X_BIT_ALM0_EN;
+
+ return i2c_smbus_write_byte_data(client, MCP7941X_REG_CONTROL, reg);
+}
+
+static const struct rtc_class_ops mcp7941x_rtc_ops = {
+ .read_time = ds1307_get_time,
+ .set_time = ds1307_set_time,
+ .read_alarm = mcp7941x_read_alarm,
+ .set_alarm = mcp7941x_set_alarm,
+ .alarm_irq_enable = mcp7941x_alarm_irq_enable,
+};
+
+/*----------------------------------------------------------------------*/
+
static ssize_t
ds1307_nvram_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
@@ -678,6 +851,7 @@ static int ds1307_probe(struct i2c_client *client,
[ds_1339] = DS1339_BIT_BBSQI,
[ds_3231] = DS3231_BIT_BBSQW,
};
+ const struct rtc_class_ops *rtc_ops = &ds13xx_rtc_ops;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)
&& !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
@@ -816,6 +990,13 @@ static int ds1307_probe(struct i2c_client *client,
case ds_1388:
ds1307->offset = 1; /* Seconds starts at 1 */
break;
+ case mcp7941x:
+ rtc_ops = &mcp7941x_rtc_ops;
+ if (ds1307->client->irq > 0 && chip->alarm) {
+ INIT_WORK(&ds1307->work, mcp7941x_work);
+ want_irq = true;
+ }
+ break;
default:
break;
}
@@ -927,55 +1108,61 @@ read_rtc:
bin2bcd(tmp));
}
+ device_set_wakeup_capable(&client->dev, want_irq);
ds1307->rtc = devm_rtc_device_register(&client->dev, client->name,
- &ds13xx_rtc_ops, THIS_MODULE);
+ rtc_ops, THIS_MODULE);
if (IS_ERR(ds1307->rtc)) {
- err = PTR_ERR(ds1307->rtc);
- dev_err(&client->dev,
- "unable to register the class device\n");
- goto exit;
+ return PTR_ERR(ds1307->rtc);
}
if (want_irq) {
err = request_irq(client->irq, ds1307_irq, IRQF_SHARED,
ds1307->rtc->name, client);
if (err) {
- dev_err(&client->dev,
- "unable to request IRQ!\n");
- goto exit;
- }
+ client->irq = 0;
+ dev_err(&client->dev, "unable to request IRQ!\n");
+ } else {
- device_set_wakeup_capable(&client->dev, 1);
- set_bit(HAS_ALARM, &ds1307->flags);
- dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
+ set_bit(HAS_ALARM, &ds1307->flags);
+ dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
+ }
}
if (chip->nvram_size) {
+
ds1307->nvram = devm_kzalloc(&client->dev,
sizeof(struct bin_attribute),
GFP_KERNEL);
if (!ds1307->nvram) {
- err = -ENOMEM;
- goto err_irq;
+ dev_err(&client->dev, "cannot allocate memory for nvram sysfs\n");
+ } else {
+
+ ds1307->nvram->attr.name = "nvram";
+ ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR;
+
+ sysfs_bin_attr_init(ds1307->nvram);
+
+ ds1307->nvram->read = ds1307_nvram_read;
+ ds1307->nvram->write = ds1307_nvram_write;
+ ds1307->nvram->size = chip->nvram_size;
+ ds1307->nvram_offset = chip->nvram_offset;
+
+ err = sysfs_create_bin_file(&client->dev.kobj,
+ ds1307->nvram);
+ if (err) {
+ dev_err(&client->dev,
+ "unable to create sysfs file: %s\n",
+ ds1307->nvram->attr.name);
+ } else {
+ set_bit(HAS_NVRAM, &ds1307->flags);
+ dev_info(&client->dev, "%zu bytes nvram\n",
+ ds1307->nvram->size);
+ }
}
- ds1307->nvram->attr.name = "nvram";
- ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR;
- sysfs_bin_attr_init(ds1307->nvram);
- ds1307->nvram->read = ds1307_nvram_read;
- ds1307->nvram->write = ds1307_nvram_write;
- ds1307->nvram->size = chip->nvram_size;
- ds1307->nvram_offset = chip->nvram_offset;
- err = sysfs_create_bin_file(&client->dev.kobj, ds1307->nvram);
- if (err)
- goto err_irq;
- set_bit(HAS_NVRAM, &ds1307->flags);
- dev_info(&client->dev, "%zu bytes nvram\n", ds1307->nvram->size);
}
return 0;
-err_irq:
- free_irq(client->irq, client);
exit:
return err;
}
diff --git a/drivers/rtc/rtc-ds1347.c b/drivers/rtc/rtc-ds1347.c
new file mode 100644
index 000000000000..c82b4c050326
--- /dev/null
+++ b/drivers/rtc/rtc-ds1347.c
@@ -0,0 +1,166 @@
+/* rtc-ds1347.c
+ *
+ * Driver for Dallas Semiconductor DS1347 Low Current, SPI Compatible
+ * Real Time Clock
+ *
+ * Author : Raghavendra Chandra Ganiga <ravi23ganiga@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/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+#include <linux/bcd.h>
+
+/* Registers in ds1347 rtc */
+
+#define DS1347_SECONDS_REG 0x01
+#define DS1347_MINUTES_REG 0x03
+#define DS1347_HOURS_REG 0x05
+#define DS1347_DATE_REG 0x07
+#define DS1347_MONTH_REG 0x09
+#define DS1347_DAY_REG 0x0B
+#define DS1347_YEAR_REG 0x0D
+#define DS1347_CONTROL_REG 0x0F
+#define DS1347_STATUS_REG 0x17
+#define DS1347_CLOCK_BURST 0x3F
+
+static int ds1347_read_reg(struct device *dev, unsigned char address,
+ unsigned char *data)
+{
+ struct spi_device *spi = to_spi_device(dev);
+
+ *data = address | 0x80;
+
+ return spi_write_then_read(spi, data, 1, data, 1);
+}
+
+static int ds1347_write_reg(struct device *dev, unsigned char address,
+ unsigned char data)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ unsigned char buf[2];
+
+ buf[0] = address & 0x7F;
+ buf[1] = data;
+
+ return spi_write_then_read(spi, buf, 2, NULL, 0);
+}
+
+static int ds1347_read_time(struct device *dev, struct rtc_time *dt)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ int err;
+ unsigned char buf[8];
+
+ buf[0] = DS1347_CLOCK_BURST | 0x80;
+
+ err = spi_write_then_read(spi, buf, 1, buf, 8);
+ if (err)
+ return err;
+
+ dt->tm_sec = bcd2bin(buf[0]);
+ dt->tm_min = bcd2bin(buf[1]);
+ dt->tm_hour = bcd2bin(buf[2] & 0x3F);
+ dt->tm_mday = bcd2bin(buf[3]);
+ dt->tm_mon = bcd2bin(buf[4]) - 1;
+ dt->tm_wday = bcd2bin(buf[5]) - 1;
+ dt->tm_year = bcd2bin(buf[6]) + 100;
+
+ return rtc_valid_tm(dt);
+}
+
+static int ds1347_set_time(struct device *dev, struct rtc_time *dt)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ unsigned char buf[9];
+
+ buf[0] = DS1347_CLOCK_BURST & 0x7F;
+ buf[1] = bin2bcd(dt->tm_sec);
+ buf[2] = bin2bcd(dt->tm_min);
+ buf[3] = (bin2bcd(dt->tm_hour) & 0x3F);
+ buf[4] = bin2bcd(dt->tm_mday);
+ buf[5] = bin2bcd(dt->tm_mon + 1);
+ buf[6] = bin2bcd(dt->tm_wday + 1);
+
+ /* year in linux is from 1900 i.e in range of 100
+ in rtc it is from 00 to 99 */
+ dt->tm_year = dt->tm_year % 100;
+
+ buf[7] = bin2bcd(dt->tm_year);
+ buf[8] = bin2bcd(0x00);
+
+ /* write the rtc settings */
+ return spi_write_then_read(spi, buf, 9, NULL, 0);
+}
+
+static const struct rtc_class_ops ds1347_rtc_ops = {
+ .read_time = ds1347_read_time,
+ .set_time = ds1347_set_time,
+};
+
+static int ds1347_probe(struct spi_device *spi)
+{
+ struct rtc_device *rtc;
+ unsigned char data;
+ int res;
+
+ /* spi setup with ds1347 in mode 3 and bits per word as 8 */
+ spi->mode = SPI_MODE_3;
+ spi->bits_per_word = 8;
+ spi_setup(spi);
+
+ /* RTC Settings */
+ res = ds1347_read_reg(&spi->dev, DS1347_SECONDS_REG, &data);
+ if (res)
+ return res;
+
+ /* Disable the write protect of rtc */
+ ds1347_read_reg(&spi->dev, DS1347_CONTROL_REG, &data);
+ data = data & ~(1<<7);
+ ds1347_write_reg(&spi->dev, DS1347_CONTROL_REG, data);
+
+ /* Enable the oscillator , disable the oscillator stop flag,
+ and glitch filter to reduce current consumption */
+ ds1347_read_reg(&spi->dev, DS1347_STATUS_REG, &data);
+ data = data & 0x1B;
+ ds1347_write_reg(&spi->dev, DS1347_STATUS_REG, data);
+
+ /* display the settings */
+ ds1347_read_reg(&spi->dev, DS1347_CONTROL_REG, &data);
+ dev_info(&spi->dev, "DS1347 RTC CTRL Reg = 0x%02x\n", data);
+
+ ds1347_read_reg(&spi->dev, DS1347_STATUS_REG, &data);
+ dev_info(&spi->dev, "DS1347 RTC Status Reg = 0x%02x\n", data);
+
+ rtc = devm_rtc_device_register(&spi->dev, "ds1347",
+ &ds1347_rtc_ops, THIS_MODULE);
+
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+
+ spi_set_drvdata(spi, rtc);
+
+ return 0;
+}
+
+static struct spi_driver ds1347_driver = {
+ .driver = {
+ .name = "ds1347",
+ .owner = THIS_MODULE,
+ },
+ .probe = ds1347_probe,
+};
+
+module_spi_driver(ds1347_driver);
+
+MODULE_DESCRIPTION("DS1347 SPI RTC DRIVER");
+MODULE_AUTHOR("Raghavendra C Ganiga <ravi23ganiga@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c
index be9d8c0a7e3a..e67bfcb3a1aa 100644
--- a/drivers/rtc/rtc-ds1390.c
+++ b/drivers/rtc/rtc-ds1390.c
@@ -132,10 +132,9 @@ static int ds1390_probe(struct spi_device *spi)
spi_setup(spi);
chip = devm_kzalloc(&spi->dev, sizeof(*chip), GFP_KERNEL);
- if (!chip) {
- dev_err(&spi->dev, "unable to allocate device memory\n");
+ if (!chip)
return -ENOMEM;
- }
+
spi_set_drvdata(spi, chip);
res = ds1390_get_reg(&spi->dev, DS1390_REG_SECONDS, &tmp);
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
index bc7b4fcf603c..b13d1399b81a 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -371,8 +371,7 @@ ds1511_interrupt(int irq, void *dev_id)
events |= RTC_UF;
else
events |= RTC_AF;
- if (likely(pdata->rtc))
- rtc_update_irq(pdata->rtc, 1, events);
+ rtc_update_irq(pdata->rtc, 1, events);
}
spin_unlock(&pdata->lock);
return events ? IRQ_HANDLED : IRQ_NONE;
@@ -473,7 +472,6 @@ static struct bin_attribute ds1511_nvram_attr = {
static int ds1511_rtc_probe(struct platform_device *pdev)
{
- struct rtc_device *rtc;
struct resource *res;
struct rtc_plat_data *pdata;
int ret = 0;
@@ -512,6 +510,12 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
spin_lock_init(&pdata->lock);
platform_set_drvdata(pdev, pdata);
+
+ pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &ds1511_rtc_ops, THIS_MODULE);
+ if (IS_ERR(pdata->rtc))
+ return PTR_ERR(pdata->rtc);
+
/*
* if the platform has an interrupt in mind for this device,
* then by all means, set it
@@ -526,15 +530,12 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
}
}
- rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &ds1511_rtc_ops,
- THIS_MODULE);
- if (IS_ERR(rtc))
- return PTR_ERR(rtc);
- pdata->rtc = rtc;
-
ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
+ if (ret)
+ dev_err(&pdev->dev, "Unable to create sysfs entry: %s\n",
+ ds1511_nvram_attr.attr.name);
- return ret;
+ return 0;
}
static int ds1511_rtc_remove(struct platform_device *pdev)
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index fd31571941f5..ab56893aac73 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -206,8 +206,7 @@ static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id)
events |= RTC_UF;
else
events |= RTC_AF;
- if (likely(pdata->rtc))
- rtc_update_irq(pdata->rtc, 1, events);
+ rtc_update_irq(pdata->rtc, 1, events);
}
spin_unlock(&pdata->lock);
return events ? IRQ_HANDLED : IRQ_NONE;
@@ -278,7 +277,6 @@ static struct bin_attribute ds1553_nvram_attr = {
static int ds1553_rtc_probe(struct platform_device *pdev)
{
- struct rtc_device *rtc;
struct resource *res;
unsigned int cen, sec;
struct rtc_plat_data *pdata;
@@ -311,6 +309,12 @@ static int ds1553_rtc_probe(struct platform_device *pdev)
spin_lock_init(&pdata->lock);
pdata->last_jiffies = jiffies;
platform_set_drvdata(pdev, pdata);
+
+ pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &ds1553_rtc_ops, THIS_MODULE);
+ if (IS_ERR(pdata->rtc))
+ return PTR_ERR(pdata->rtc);
+
if (pdata->irq > 0) {
writeb(0, ioaddr + RTC_INTERRUPTS);
if (devm_request_irq(&pdev->dev, pdata->irq,
@@ -321,15 +325,12 @@ static int ds1553_rtc_probe(struct platform_device *pdev)
}
}
- rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
- &ds1553_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc))
- return PTR_ERR(rtc);
- pdata->rtc = rtc;
-
ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
+ if (ret)
+ dev_err(&pdev->dev, "unable to create sysfs file: %s\n",
+ ds1553_nvram_attr.attr.name);
- return ret;
+ return 0;
}
static int ds1553_rtc_remove(struct platform_device *pdev)
diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c
index 18e2d8471472..a4888dbca2e1 100644
--- a/drivers/rtc/rtc-ds1672.c
+++ b/drivers/rtc/rtc-ds1672.c
@@ -177,8 +177,9 @@ static int ds1672_probe(struct i2c_client *client,
/* read control register */
err = ds1672_get_control(client, &control);
- if (err)
- goto exit_devreg;
+ if (err) {
+ dev_warn(&client->dev, "Unable to read the control register\n");
+ }
if (control & DS1672_REG_CONTROL_EOSC)
dev_warn(&client->dev, "Oscillator not enabled. "
@@ -187,12 +188,10 @@ static int ds1672_probe(struct i2c_client *client,
/* Register sysfs hooks */
err = device_create_file(&client->dev, &dev_attr_control);
if (err)
- goto exit_devreg;
+ dev_err(&client->dev, "Unable to create sysfs entry: %s\n",
+ dev_attr_control.attr.name);
return 0;
-
- exit_devreg:
- return err;
}
static struct i2c_device_id ds1672_id[] = {
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
index 5a1f3b2a8f1e..942103dac30f 100644
--- a/drivers/rtc/rtc-ds1742.c
+++ b/drivers/rtc/rtc-ds1742.c
@@ -204,8 +204,11 @@ static int ds1742_rtc_probe(struct platform_device *pdev)
return PTR_ERR(rtc);
ret = sysfs_create_bin_file(&pdev->dev.kobj, &pdata->nvram_attr);
+ if (ret)
+ dev_err(&pdev->dev, "Unable to create sysfs entry: %s\n",
+ pdata->nvram_attr.attr.name);
- return ret;
+ return 0;
}
static int ds1742_rtc_remove(struct platform_device *pdev)
diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c
index b83bb5a527f8..adaf06c41479 100644
--- a/drivers/rtc/rtc-ds3232.c
+++ b/drivers/rtc/rtc-ds3232.c
@@ -57,6 +57,7 @@ struct ds3232 {
* in the remove function.
*/
struct mutex mutex;
+ bool suspended;
int exiting;
};
@@ -345,7 +346,15 @@ static irqreturn_t ds3232_irq(int irq, void *dev_id)
struct ds3232 *ds3232 = i2c_get_clientdata(client);
disable_irq_nosync(irq);
- schedule_work(&ds3232->work);
+
+ /*
+ * If rtc as a wakeup source, can't schedule the work
+ * at system resume flow, because at this time the i2c bus
+ * has not been resumed.
+ */
+ if (!ds3232->suspended)
+ schedule_work(&ds3232->work);
+
return IRQ_HANDLED;
}
@@ -363,22 +372,26 @@ static void ds3232_work(struct work_struct *work)
if (stat & DS3232_REG_SR_A1F) {
control = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
- if (control < 0)
- goto out;
- /* disable alarm1 interrupt */
- control &= ~(DS3232_REG_CR_A1IE);
- i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
-
- /* clear the alarm pend flag */
- stat &= ~DS3232_REG_SR_A1F;
- i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat);
-
- rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF);
+ if (control < 0) {
+ pr_warn("Read DS3232 Control Register error."
+ "Disable IRQ%d.\n", client->irq);
+ } else {
+ /* disable alarm1 interrupt */
+ control &= ~(DS3232_REG_CR_A1IE);
+ i2c_smbus_write_byte_data(client, DS3232_REG_CR,
+ control);
+
+ /* clear the alarm pend flag */
+ stat &= ~DS3232_REG_SR_A1F;
+ i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat);
+
+ rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF);
+
+ if (!ds3232->exiting)
+ enable_irq(client->irq);
+ }
}
-out:
- if (!ds3232->exiting)
- enable_irq(client->irq);
unlock:
mutex_unlock(&ds3232->mutex);
}
@@ -411,23 +424,17 @@ static int ds3232_probe(struct i2c_client *client,
if (ret)
return ret;
- ds3232->rtc = devm_rtc_device_register(&client->dev, client->name,
- &ds3232_rtc_ops, THIS_MODULE);
- if (IS_ERR(ds3232->rtc)) {
- dev_err(&client->dev, "unable to register the class device\n");
- return PTR_ERR(ds3232->rtc);
- }
-
- if (client->irq >= 0) {
- ret = devm_request_irq(&client->dev, client->irq, ds3232_irq, 0,
- "ds3232", client);
+ if (client->irq > 0) {
+ ret = devm_request_irq(&client->dev, client->irq, ds3232_irq,
+ IRQF_SHARED, "ds3232", client);
if (ret) {
dev_err(&client->dev, "unable to request IRQ\n");
- return ret;
}
+ device_init_wakeup(&client->dev, 1);
}
-
- return 0;
+ ds3232->rtc = devm_rtc_device_register(&client->dev, client->name,
+ &ds3232_rtc_ops, THIS_MODULE);
+ return PTR_ERR_OR_ZERO(ds3232->rtc);
}
static int ds3232_remove(struct i2c_client *client)
@@ -446,6 +453,42 @@ static int ds3232_remove(struct i2c_client *client)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int ds3232_suspend(struct device *dev)
+{
+ struct ds3232 *ds3232 = dev_get_drvdata(dev);
+ struct i2c_client *client = to_i2c_client(dev);
+
+ if (device_can_wakeup(dev)) {
+ ds3232->suspended = true;
+ irq_set_irq_wake(client->irq, 1);
+ }
+
+ return 0;
+}
+
+static int ds3232_resume(struct device *dev)
+{
+ struct ds3232 *ds3232 = dev_get_drvdata(dev);
+ struct i2c_client *client = to_i2c_client(dev);
+
+ if (ds3232->suspended) {
+ ds3232->suspended = false;
+
+ /* Clear the hardware alarm pend flag */
+ schedule_work(&ds3232->work);
+
+ irq_set_irq_wake(client->irq, 0);
+ }
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops ds3232_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(ds3232_suspend, ds3232_resume)
+};
+
static const struct i2c_device_id ds3232_id[] = {
{ "ds3232", 0 },
{ }
@@ -456,6 +499,7 @@ static struct i2c_driver ds3232_driver = {
.driver = {
.name = "rtc-ds3232",
.owner = THIS_MODULE,
+ .pm = &ds3232_pm_ops,
},
.probe = ds3232_probe,
.remove = ds3232_remove,
diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c
index abd7f9091f34..cd741c77e085 100644
--- a/drivers/rtc/rtc-imxdi.c
+++ b/drivers/rtc/rtc-imxdi.c
@@ -401,7 +401,9 @@ static int __init dryice_rtc_probe(struct platform_device *pdev)
imxdi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(imxdi->clk))
return PTR_ERR(imxdi->clk);
- clk_prepare_enable(imxdi->clk);
+ rc = clk_prepare_enable(imxdi->clk);
+ if (rc)
+ return rc;
/*
* Initialize dryice hardware
diff --git a/drivers/rtc/rtc-isl12057.c b/drivers/rtc/rtc-isl12057.c
index 7854a656628f..7e5ead936a04 100644
--- a/drivers/rtc/rtc-isl12057.c
+++ b/drivers/rtc/rtc-isl12057.c
@@ -26,7 +26,6 @@
#include <linux/rtc.h>
#include <linux/i2c.h>
#include <linux/bcd.h>
-#include <linux/rtc.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c
index 1b126d2513de..08f5160fb6d4 100644
--- a/drivers/rtc/rtc-jz4740.c
+++ b/drivers/rtc/rtc-jz4740.c
@@ -38,7 +38,6 @@
#define JZ_RTC_CTRL_ENABLE BIT(0)
struct jz4740_rtc {
- struct resource *mem;
void __iomem *base;
struct rtc_device *rtc;
@@ -216,6 +215,7 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
int ret;
struct jz4740_rtc *rtc;
uint32_t scratchpad;
+ struct resource *mem;
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
@@ -227,25 +227,10 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
return -ENOENT;
}
- rtc->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!rtc->mem) {
- dev_err(&pdev->dev, "Failed to get platform mmio memory\n");
- return -ENOENT;
- }
-
- rtc->mem = devm_request_mem_region(&pdev->dev, rtc->mem->start,
- resource_size(rtc->mem), pdev->name);
- if (!rtc->mem) {
- dev_err(&pdev->dev, "Failed to request mmio memory region\n");
- return -EBUSY;
- }
-
- rtc->base = devm_ioremap_nocache(&pdev->dev, rtc->mem->start,
- resource_size(rtc->mem));
- if (!rtc->base) {
- dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
- return -EBUSY;
- }
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ rtc->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(rtc->base))
+ return PTR_ERR(rtc->base);
spin_lock_init(&rtc->lock);
diff --git a/drivers/rtc/rtc-lpc32xx.c b/drivers/rtc/rtc-lpc32xx.c
index bfdbcb82d069..f130c08c98f8 100644
--- a/drivers/rtc/rtc-lpc32xx.c
+++ b/drivers/rtc/rtc-lpc32xx.c
@@ -211,10 +211,9 @@ static int lpc32xx_rtc_probe(struct platform_device *pdev)
}
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
- if (unlikely(!rtc)) {
- dev_err(&pdev->dev, "Can't allocate memory\n");
+ if (unlikely(!rtc))
return -ENOMEM;
- }
+
rtc->irq = rtcirq;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/rtc/rtc-mc13xxx.c b/drivers/rtc/rtc-mc13xxx.c
index 77ea9896b5ba..0765606a2d14 100644
--- a/drivers/rtc/rtc-mc13xxx.c
+++ b/drivers/rtc/rtc-mc13xxx.c
@@ -23,6 +23,8 @@
#define MC13XXX_RTCDAY 22
#define MC13XXX_RTCDAYA 23
+#define SEC_PER_DAY (24 * 60 * 60)
+
struct mc13xxx_rtc {
struct rtc_device *rtc;
struct mc13xxx *mc13xxx;
@@ -42,15 +44,15 @@ static int mc13xxx_rtc_irq_enable_unlocked(struct device *dev,
return func(priv->mc13xxx, irq);
}
-static int mc13xxx_rtc_irq_enable(struct device *dev,
- unsigned int enabled, int irq)
+static int mc13xxx_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
{
struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
int ret;
mc13xxx_lock(priv->mc13xxx);
- ret = mc13xxx_rtc_irq_enable_unlocked(dev, enabled, irq);
+ ret = mc13xxx_rtc_irq_enable_unlocked(dev, enabled, MC13XXX_IRQ_TODA);
mc13xxx_unlock(priv->mc13xxx);
@@ -61,44 +63,27 @@ static int mc13xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
unsigned int seconds, days1, days2;
- unsigned long s1970;
- int ret;
-
- mc13xxx_lock(priv->mc13xxx);
-
- if (!priv->valid) {
- ret = -ENODATA;
- goto out;
- }
- ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days1);
- if (unlikely(ret))
- goto out;
-
- ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTOD, &seconds);
- if (unlikely(ret))
- goto out;
-
- ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days2);
-out:
- mc13xxx_unlock(priv->mc13xxx);
+ if (!priv->valid)
+ return -ENODATA;
- if (ret)
- return ret;
+ do {
+ int ret;
- if (days2 == days1 + 1) {
- if (seconds >= 86400 / 2)
- days2 = days1;
- else
- days1 = days2;
- }
+ ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days1);
+ if (ret)
+ return ret;
- if (days1 != days2)
- return -EIO;
+ ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTOD, &seconds);
+ if (ret)
+ return ret;
- s1970 = days1 * 86400 + seconds;
+ ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days2);
+ if (ret)
+ return ret;
+ } while (days1 != days2);
- rtc_time_to_tm(s1970, tm);
+ rtc_time_to_tm(days1 * SEC_PER_DAY + seconds, tm);
return rtc_valid_tm(tm);
}
@@ -110,8 +95,8 @@ static int mc13xxx_rtc_set_mmss(struct device *dev, unsigned long secs)
unsigned int alarmseconds;
int ret;
- seconds = secs % 86400;
- days = secs / 86400;
+ seconds = secs % SEC_PER_DAY;
+ days = secs / SEC_PER_DAY;
mc13xxx_lock(priv->mc13xxx);
@@ -123,7 +108,7 @@ static int mc13xxx_rtc_set_mmss(struct device *dev, unsigned long secs)
if (unlikely(ret))
goto out;
- if (alarmseconds < 86400) {
+ if (alarmseconds < SEC_PER_DAY) {
ret = mc13xxx_reg_write(priv->mc13xxx,
MC13XXX_RTCTODA, 0x1ffff);
if (unlikely(ret))
@@ -147,18 +132,21 @@ static int mc13xxx_rtc_set_mmss(struct device *dev, unsigned long secs)
goto out;
/* restore alarm */
- if (alarmseconds < 86400) {
+ if (alarmseconds < SEC_PER_DAY) {
ret = mc13xxx_reg_write(priv->mc13xxx,
MC13XXX_RTCTODA, alarmseconds);
if (unlikely(ret))
goto out;
}
- ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_RTCRST);
- if (unlikely(ret))
- goto out;
+ if (!priv->valid) {
+ ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_RTCRST);
+ if (unlikely(ret))
+ goto out;
+
+ ret = mc13xxx_irq_unmask(priv->mc13xxx, MC13XXX_IRQ_RTCRST);
+ }
- ret = mc13xxx_irq_unmask(priv->mc13xxx, MC13XXX_IRQ_RTCRST);
out:
priv->valid = !ret;
@@ -180,7 +168,7 @@ static int mc13xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTODA, &seconds);
if (unlikely(ret))
goto out;
- if (seconds >= 86400) {
+ if (seconds >= SEC_PER_DAY) {
ret = -ENODATA;
goto out;
}
@@ -201,7 +189,7 @@ out:
alarm->enabled = enabled;
alarm->pending = pending;
- s1970 = days * 86400 + seconds;
+ s1970 = days * SEC_PER_DAY + seconds;
rtc_time_to_tm(s1970, &alarm->time);
dev_dbg(dev, "%s: %lu\n", __func__, s1970);
@@ -239,8 +227,8 @@ static int mc13xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
if (unlikely(ret))
goto out;
- seconds = s1970 % 86400;
- days = s1970 / 86400;
+ seconds = s1970 % SEC_PER_DAY;
+ days = s1970 / SEC_PER_DAY;
ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCDAYA, days);
if (unlikely(ret))
@@ -259,8 +247,6 @@ static irqreturn_t mc13xxx_rtc_alarm_handler(int irq, void *dev)
struct mc13xxx_rtc *priv = dev;
struct mc13xxx *mc13xxx = priv->mc13xxx;
- dev_dbg(&priv->rtc->dev, "Alarm\n");
-
rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF);
mc13xxx_irq_ack(mc13xxx, irq);
@@ -273,8 +259,6 @@ static irqreturn_t mc13xxx_rtc_update_handler(int irq, void *dev)
struct mc13xxx_rtc *priv = dev;
struct mc13xxx *mc13xxx = priv->mc13xxx;
- dev_dbg(&priv->rtc->dev, "1HZ\n");
-
rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF);
mc13xxx_irq_ack(mc13xxx, irq);
@@ -282,12 +266,6 @@ static irqreturn_t mc13xxx_rtc_update_handler(int irq, void *dev)
return IRQ_HANDLED;
}
-static int mc13xxx_rtc_alarm_irq_enable(struct device *dev,
- unsigned int enabled)
-{
- return mc13xxx_rtc_irq_enable(dev, enabled, MC13XXX_IRQ_TODA);
-}
-
static const struct rtc_class_ops mc13xxx_rtc_ops = {
.read_time = mc13xxx_rtc_read_time,
.set_mmss = mc13xxx_rtc_set_mmss,
@@ -301,7 +279,6 @@ static irqreturn_t mc13xxx_rtc_reset_handler(int irq, void *dev)
struct mc13xxx_rtc *priv = dev;
struct mc13xxx *mc13xxx = priv->mc13xxx;
- dev_dbg(&priv->rtc->dev, "RTCRST\n");
priv->valid = 0;
mc13xxx_irq_mask(mc13xxx, irq);
@@ -314,7 +291,6 @@ static int __init mc13xxx_rtc_probe(struct platform_device *pdev)
int ret;
struct mc13xxx_rtc *priv;
struct mc13xxx *mc13xxx;
- int rtcrst_pending;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -322,60 +298,47 @@ static int __init mc13xxx_rtc_probe(struct platform_device *pdev)
mc13xxx = dev_get_drvdata(pdev->dev.parent);
priv->mc13xxx = mc13xxx;
+ priv->valid = 1;
platform_set_drvdata(pdev, priv);
mc13xxx_lock(mc13xxx);
+ mc13xxx_irq_ack(mc13xxx, MC13XXX_IRQ_RTCRST);
+
ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_RTCRST,
mc13xxx_rtc_reset_handler, DRIVER_NAME, priv);
if (ret)
- goto err_reset_irq_request;
-
- ret = mc13xxx_irq_status(mc13xxx, MC13XXX_IRQ_RTCRST,
- NULL, &rtcrst_pending);
- if (ret)
- goto err_reset_irq_status;
-
- priv->valid = !rtcrst_pending;
+ goto err_irq_request;
- ret = mc13xxx_irq_request_nounmask(mc13xxx, MC13XXX_IRQ_1HZ,
+ ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_1HZ,
mc13xxx_rtc_update_handler, DRIVER_NAME, priv);
if (ret)
- goto err_update_irq_request;
+ goto err_irq_request;
ret = mc13xxx_irq_request_nounmask(mc13xxx, MC13XXX_IRQ_TODA,
mc13xxx_rtc_alarm_handler, DRIVER_NAME, priv);
if (ret)
- goto err_alarm_irq_request;
+ goto err_irq_request;
mc13xxx_unlock(mc13xxx);
priv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
- &mc13xxx_rtc_ops, THIS_MODULE);
- if (IS_ERR(priv->rtc)) {
- ret = PTR_ERR(priv->rtc);
+ &mc13xxx_rtc_ops, THIS_MODULE);
- mc13xxx_lock(mc13xxx);
-
- mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv);
-err_alarm_irq_request:
-
- mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_1HZ, priv);
-err_update_irq_request:
-
-err_reset_irq_status:
+ return 0;
- mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv);
-err_reset_irq_request:
+err_irq_request:
+ mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv);
+ mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_1HZ, priv);
+ mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv);
- mc13xxx_unlock(mc13xxx);
- }
+ mc13xxx_unlock(mc13xxx);
return ret;
}
-static int __exit mc13xxx_rtc_remove(struct platform_device *pdev)
+static int mc13xxx_rtc_remove(struct platform_device *pdev)
{
struct mc13xxx_rtc *priv = platform_get_drvdata(pdev);
@@ -404,7 +367,7 @@ MODULE_DEVICE_TABLE(platform, mc13xxx_rtc_idtable);
static struct platform_driver mc13xxx_rtc_driver = {
.id_table = mc13xxx_rtc_idtable,
- .remove = __exit_p(mc13xxx_rtc_remove),
+ .remove = mc13xxx_rtc_remove,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
diff --git a/drivers/rtc/rtc-moxart.c b/drivers/rtc/rtc-moxart.c
index c29dee0946e6..c31846238871 100644
--- a/drivers/rtc/rtc-moxart.c
+++ b/drivers/rtc/rtc-moxart.c
@@ -247,10 +247,8 @@ static int moxart_rtc_probe(struct platform_device *pdev)
int ret = 0;
moxart_rtc = devm_kzalloc(&pdev->dev, sizeof(*moxart_rtc), GFP_KERNEL);
- if (!moxart_rtc) {
- dev_err(&pdev->dev, "devm_kzalloc failed\n");
+ if (!moxart_rtc)
return -ENOMEM;
- }
moxart_rtc->gpio_data = of_get_named_gpio(pdev->dev.of_node,
"gpio-rtc-data", 0);
diff --git a/drivers/rtc/rtc-nuc900.c b/drivers/rtc/rtc-nuc900.c
index 248653c74b80..a53da0958e95 100644
--- a/drivers/rtc/rtc-nuc900.c
+++ b/drivers/rtc/rtc-nuc900.c
@@ -229,10 +229,9 @@ static int __init nuc900_rtc_probe(struct platform_device *pdev)
nuc900_rtc = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_rtc),
GFP_KERNEL);
- if (!nuc900_rtc) {
- dev_err(&pdev->dev, "kzalloc nuc900_rtc failed\n");
+ if (!nuc900_rtc)
return -ENOMEM;
- }
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nuc900_rtc->rtc_reg = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(nuc900_rtc->rtc_reg))
diff --git a/drivers/rtc/rtc-palmas.c b/drivers/rtc/rtc-palmas.c
index fffb7d3449d7..c360d62fb3f6 100644
--- a/drivers/rtc/rtc-palmas.c
+++ b/drivers/rtc/rtc-palmas.c
@@ -348,9 +348,8 @@ static int palmas_rtc_resume(struct device *dev)
}
#endif
-static const struct dev_pm_ops palmas_rtc_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(palmas_rtc_suspend, palmas_rtc_resume)
-};
+static SIMPLE_DEV_PM_OPS(palmas_rtc_pm_ops, palmas_rtc_suspend,
+ palmas_rtc_resume);
#ifdef CONFIG_OF
static struct of_device_id of_palmas_rtc_match[] = {
diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c
index 03f8f75d5af2..197699f358c7 100644
--- a/drivers/rtc/rtc-pm8xxx.c
+++ b/drivers/rtc/rtc-pm8xxx.c
@@ -9,18 +9,16 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-
+#include <linux/of.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/rtc.h>
+#include <linux/platform_device.h>
#include <linux/pm.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include <linux/mfd/pm8xxx/core.h>
-#include <linux/mfd/pm8xxx/rtc.h>
-
-
/* RTC Register offsets from RTC CTRL REG */
#define PM8XXX_ALARM_CTRL_OFFSET 0x01
#define PM8XXX_RTC_WRITE_OFFSET 0x02
@@ -37,6 +35,8 @@
/**
* struct pm8xxx_rtc - rtc driver internal structure
* @rtc: rtc device for this driver.
+ * @regmap: regmap used to access RTC registers
+ * @allow_set_time: indicates whether writing to the RTC is allowed
* @rtc_alarm_irq: rtc alarm irq number.
* @rtc_base: address of rtc control register.
* @rtc_read_base: base address of read registers.
@@ -48,55 +48,19 @@
*/
struct pm8xxx_rtc {
struct rtc_device *rtc;
+ struct regmap *regmap;
+ bool allow_set_time;
int rtc_alarm_irq;
int rtc_base;
int rtc_read_base;
int rtc_write_base;
int alarm_rw_base;
- u8 ctrl_reg;
+ u8 ctrl_reg;
struct device *rtc_dev;
spinlock_t ctrl_reg_lock;
};
/*
- * The RTC registers need to be read/written one byte at a time. This is a
- * hardware limitation.
- */
-static int pm8xxx_read_wrapper(struct pm8xxx_rtc *rtc_dd, u8 *rtc_val,
- int base, int count)
-{
- int i, rc;
- struct device *parent = rtc_dd->rtc_dev->parent;
-
- for (i = 0; i < count; i++) {
- rc = pm8xxx_readb(parent, base + i, &rtc_val[i]);
- if (rc < 0) {
- dev_err(rtc_dd->rtc_dev, "PMIC read failed\n");
- return rc;
- }
- }
-
- return 0;
-}
-
-static int pm8xxx_write_wrapper(struct pm8xxx_rtc *rtc_dd, u8 *rtc_val,
- int base, int count)
-{
- int i, rc;
- struct device *parent = rtc_dd->rtc_dev->parent;
-
- for (i = 0; i < count; i++) {
- rc = pm8xxx_writeb(parent, base + i, rtc_val[i]);
- if (rc < 0) {
- dev_err(rtc_dd->rtc_dev, "PMIC write failed\n");
- return rc;
- }
- }
-
- return 0;
-}
-
-/*
* Steps to write the RTC registers.
* 1. Disable alarm if enabled.
* 2. Write 0x00 to LSB.
@@ -107,9 +71,12 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
int rc, i;
unsigned long secs, irq_flags;
- u8 value[NUM_8_BIT_RTC_REGS], reg = 0, alarm_enabled = 0, ctrl_reg;
+ u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0, ctrl_reg;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
+ if (!rtc_dd->allow_set_time)
+ return -EACCES;
+
rtc_tm_to_time(tm, &secs);
for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) {
@@ -125,47 +92,43 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
if (ctrl_reg & PM8xxx_RTC_ALARM_ENABLE) {
alarm_enabled = 1;
ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE;
- rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base,
- 1);
- if (rc < 0) {
- dev_err(dev, "Write to RTC control register "
- "failed\n");
+ rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg);
+ if (rc) {
+ dev_err(dev, "Write to RTC control register failed\n");
goto rtc_rw_fail;
}
rtc_dd->ctrl_reg = ctrl_reg;
- } else
+ } else {
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
+ }
/* Write 0 to Byte[0] */
- reg = 0;
- rc = pm8xxx_write_wrapper(rtc_dd, &reg, rtc_dd->rtc_write_base, 1);
- if (rc < 0) {
+ rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_write_base, 0);
+ if (rc) {
dev_err(dev, "Write to RTC write data register failed\n");
goto rtc_rw_fail;
}
/* Write Byte[1], Byte[2], Byte[3] */
- rc = pm8xxx_write_wrapper(rtc_dd, value + 1,
- rtc_dd->rtc_write_base + 1, 3);
- if (rc < 0) {
+ rc = regmap_bulk_write(rtc_dd->regmap, rtc_dd->rtc_write_base + 1,
+ &value[1], sizeof(value) - 1);
+ if (rc) {
dev_err(dev, "Write to RTC write data register failed\n");
goto rtc_rw_fail;
}
/* Write Byte[0] */
- rc = pm8xxx_write_wrapper(rtc_dd, value, rtc_dd->rtc_write_base, 1);
- if (rc < 0) {
+ rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_write_base, value[0]);
+ if (rc) {
dev_err(dev, "Write to RTC write data register failed\n");
goto rtc_rw_fail;
}
if (alarm_enabled) {
ctrl_reg |= PM8xxx_RTC_ALARM_ENABLE;
- rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base,
- 1);
- if (rc < 0) {
- dev_err(dev, "Write to RTC control register "
- "failed\n");
+ rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg);
+ if (rc) {
+ dev_err(dev, "Write to RTC control register failed\n");
goto rtc_rw_fail;
}
rtc_dd->ctrl_reg = ctrl_reg;
@@ -181,13 +144,14 @@ rtc_rw_fail:
static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
int rc;
- u8 value[NUM_8_BIT_RTC_REGS], reg;
+ u8 value[NUM_8_BIT_RTC_REGS];
unsigned long secs;
+ unsigned int reg;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
- rc = pm8xxx_read_wrapper(rtc_dd, value, rtc_dd->rtc_read_base,
- NUM_8_BIT_RTC_REGS);
- if (rc < 0) {
+ rc = regmap_bulk_read(rtc_dd->regmap, rtc_dd->rtc_read_base,
+ value, sizeof(value));
+ if (rc) {
dev_err(dev, "RTC read data register failed\n");
return rc;
}
@@ -196,16 +160,16 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
* Read the LSB again and check if there has been a carry over.
* If there is, redo the read operation.
*/
- rc = pm8xxx_read_wrapper(rtc_dd, &reg, rtc_dd->rtc_read_base, 1);
+ rc = regmap_read(rtc_dd->regmap, rtc_dd->rtc_read_base, &reg);
if (rc < 0) {
dev_err(dev, "RTC read data register failed\n");
return rc;
}
if (unlikely(reg < value[0])) {
- rc = pm8xxx_read_wrapper(rtc_dd, value,
- rtc_dd->rtc_read_base, NUM_8_BIT_RTC_REGS);
- if (rc < 0) {
+ rc = regmap_bulk_read(rtc_dd->regmap, rtc_dd->rtc_read_base,
+ value, sizeof(value));
+ if (rc) {
dev_err(dev, "RTC read data register failed\n");
return rc;
}
@@ -222,8 +186,8 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
}
dev_dbg(dev, "secs = %lu, h:m:s == %d:%d:%d, d/m/y = %d/%d/%d\n",
- secs, tm->tm_hour, tm->tm_min, tm->tm_sec,
- tm->tm_mday, tm->tm_mon, tm->tm_year);
+ secs, tm->tm_hour, tm->tm_min, tm->tm_sec,
+ tm->tm_mday, tm->tm_mon, tm->tm_year);
return 0;
}
@@ -244,19 +208,22 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
- rc = pm8xxx_write_wrapper(rtc_dd, value, rtc_dd->alarm_rw_base,
- NUM_8_BIT_RTC_REGS);
- if (rc < 0) {
+ rc = regmap_bulk_write(rtc_dd->regmap, rtc_dd->alarm_rw_base, value,
+ sizeof(value));
+ if (rc) {
dev_err(dev, "Write to RTC ALARM register failed\n");
goto rtc_rw_fail;
}
ctrl_reg = rtc_dd->ctrl_reg;
- ctrl_reg = alarm->enabled ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) :
- (ctrl_reg & ~PM8xxx_RTC_ALARM_ENABLE);
- rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
- if (rc < 0) {
+ if (alarm->enabled)
+ ctrl_reg |= PM8xxx_RTC_ALARM_ENABLE;
+ else
+ ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE;
+
+ rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg);
+ if (rc) {
dev_err(dev, "Write to RTC control register failed\n");
goto rtc_rw_fail;
}
@@ -264,9 +231,9 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
rtc_dd->ctrl_reg = ctrl_reg;
dev_dbg(dev, "Alarm Set for h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
- alarm->time.tm_hour, alarm->time.tm_min,
- alarm->time.tm_sec, alarm->time.tm_mday,
- alarm->time.tm_mon, alarm->time.tm_year);
+ alarm->time.tm_hour, alarm->time.tm_min,
+ alarm->time.tm_sec, alarm->time.tm_mday,
+ alarm->time.tm_mon, alarm->time.tm_year);
rtc_rw_fail:
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
return rc;
@@ -279,9 +246,9 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
unsigned long secs;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
- rc = pm8xxx_read_wrapper(rtc_dd, value, rtc_dd->alarm_rw_base,
- NUM_8_BIT_RTC_REGS);
- if (rc < 0) {
+ rc = regmap_bulk_read(rtc_dd->regmap, rtc_dd->alarm_rw_base, value,
+ sizeof(value));
+ if (rc) {
dev_err(dev, "RTC alarm time read failed\n");
return rc;
}
@@ -297,9 +264,9 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
}
dev_dbg(dev, "Alarm set for - h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
- alarm->time.tm_hour, alarm->time.tm_min,
- alarm->time.tm_sec, alarm->time.tm_mday,
- alarm->time.tm_mon, alarm->time.tm_year);
+ alarm->time.tm_hour, alarm->time.tm_min,
+ alarm->time.tm_sec, alarm->time.tm_mday,
+ alarm->time.tm_mon, alarm->time.tm_year);
return 0;
}
@@ -312,12 +279,16 @@ static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
u8 ctrl_reg;
spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
+
ctrl_reg = rtc_dd->ctrl_reg;
- ctrl_reg = (enable) ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) :
- (ctrl_reg & ~PM8xxx_RTC_ALARM_ENABLE);
- rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
- if (rc < 0) {
+ if (enable)
+ ctrl_reg |= PM8xxx_RTC_ALARM_ENABLE;
+ else
+ ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE;
+
+ rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg);
+ if (rc) {
dev_err(dev, "Write to RTC control register failed\n");
goto rtc_rw_fail;
}
@@ -329,8 +300,9 @@ rtc_rw_fail:
return rc;
}
-static struct rtc_class_ops pm8xxx_rtc_ops = {
+static const struct rtc_class_ops pm8xxx_rtc_ops = {
.read_time = pm8xxx_rtc_read_time,
+ .set_time = pm8xxx_rtc_set_time,
.set_alarm = pm8xxx_rtc_set_alarm,
.read_alarm = pm8xxx_rtc_read_alarm,
.alarm_irq_enable = pm8xxx_rtc_alarm_irq_enable,
@@ -339,7 +311,7 @@ static struct rtc_class_ops pm8xxx_rtc_ops = {
static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id)
{
struct pm8xxx_rtc *rtc_dd = dev_id;
- u8 ctrl_reg;
+ unsigned int ctrl_reg;
int rc;
unsigned long irq_flags;
@@ -351,11 +323,11 @@ static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id)
ctrl_reg = rtc_dd->ctrl_reg;
ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE;
- rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
- if (rc < 0) {
+ rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg);
+ if (rc) {
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
- dev_err(rtc_dd->rtc_dev, "Write to RTC control register "
- "failed\n");
+ dev_err(rtc_dd->rtc_dev,
+ "Write to RTC control register failed\n");
goto rtc_alarm_handled;
}
@@ -363,61 +335,71 @@ static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id)
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
/* Clear RTC alarm register */
- rc = pm8xxx_read_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base +
- PM8XXX_ALARM_CTRL_OFFSET, 1);
- if (rc < 0) {
- dev_err(rtc_dd->rtc_dev, "RTC Alarm control register read "
- "failed\n");
+ rc = regmap_read(rtc_dd->regmap,
+ rtc_dd->rtc_base + PM8XXX_ALARM_CTRL_OFFSET,
+ &ctrl_reg);
+ if (rc) {
+ dev_err(rtc_dd->rtc_dev,
+ "RTC Alarm control register read failed\n");
goto rtc_alarm_handled;
}
ctrl_reg &= ~PM8xxx_RTC_ALARM_CLEAR;
- rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base +
- PM8XXX_ALARM_CTRL_OFFSET, 1);
- if (rc < 0)
- dev_err(rtc_dd->rtc_dev, "Write to RTC Alarm control register"
- " failed\n");
+ rc = regmap_write(rtc_dd->regmap,
+ rtc_dd->rtc_base + PM8XXX_ALARM_CTRL_OFFSET,
+ ctrl_reg);
+ if (rc)
+ dev_err(rtc_dd->rtc_dev,
+ "Write to RTC Alarm control register failed\n");
rtc_alarm_handled:
return IRQ_HANDLED;
}
+/*
+ * Hardcoded RTC bases until IORESOURCE_REG mapping is figured out
+ */
+static const struct of_device_id pm8xxx_id_table[] = {
+ { .compatible = "qcom,pm8921-rtc", .data = (void *) 0x11D },
+ { .compatible = "qcom,pm8058-rtc", .data = (void *) 0x1E8 },
+ { },
+};
+MODULE_DEVICE_TABLE(of, pm8xxx_id_table);
+
static int pm8xxx_rtc_probe(struct platform_device *pdev)
{
int rc;
- u8 ctrl_reg;
- bool rtc_write_enable = false;
+ unsigned int ctrl_reg;
struct pm8xxx_rtc *rtc_dd;
- struct resource *rtc_resource;
- const struct pm8xxx_rtc_platform_data *pdata =
- dev_get_platdata(&pdev->dev);
+ const struct of_device_id *match;
- if (pdata != NULL)
- rtc_write_enable = pdata->rtc_write_enable;
+ match = of_match_node(pm8xxx_id_table, pdev->dev.of_node);
+ if (!match)
+ return -ENXIO;
rtc_dd = devm_kzalloc(&pdev->dev, sizeof(*rtc_dd), GFP_KERNEL);
- if (rtc_dd == NULL) {
- dev_err(&pdev->dev, "Unable to allocate memory!\n");
+ if (rtc_dd == NULL)
return -ENOMEM;
- }
/* Initialise spinlock to protect RTC control register */
spin_lock_init(&rtc_dd->ctrl_reg_lock);
+ rtc_dd->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!rtc_dd->regmap) {
+ dev_err(&pdev->dev, "Parent regmap unavailable.\n");
+ return -ENXIO;
+ }
+
rtc_dd->rtc_alarm_irq = platform_get_irq(pdev, 0);
if (rtc_dd->rtc_alarm_irq < 0) {
dev_err(&pdev->dev, "Alarm IRQ resource absent!\n");
return -ENXIO;
}
- rtc_resource = platform_get_resource_byname(pdev, IORESOURCE_IO,
- "pmic_rtc_base");
- if (!(rtc_resource && rtc_resource->start)) {
- dev_err(&pdev->dev, "RTC IO resource absent!\n");
- return -ENXIO;
- }
+ rtc_dd->allow_set_time = of_property_read_bool(pdev->dev.of_node,
+ "allow-set-time");
- rtc_dd->rtc_base = rtc_resource->start;
+ rtc_dd->rtc_base = (long) match->data;
/* Setup RTC register addresses */
rtc_dd->rtc_write_base = rtc_dd->rtc_base + PM8XXX_RTC_WRITE_OFFSET;
@@ -427,64 +409,52 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
rtc_dd->rtc_dev = &pdev->dev;
/* Check if the RTC is on, else turn it on */
- rc = pm8xxx_read_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
- if (rc < 0) {
+ rc = regmap_read(rtc_dd->regmap, rtc_dd->rtc_base, &ctrl_reg);
+ if (rc) {
dev_err(&pdev->dev, "RTC control register read failed!\n");
return rc;
}
if (!(ctrl_reg & PM8xxx_RTC_ENABLE)) {
ctrl_reg |= PM8xxx_RTC_ENABLE;
- rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base,
- 1);
- if (rc < 0) {
- dev_err(&pdev->dev, "Write to RTC control register "
- "failed\n");
+ rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "Write to RTC control register failed\n");
return rc;
}
}
rtc_dd->ctrl_reg = ctrl_reg;
- if (rtc_write_enable == true)
- pm8xxx_rtc_ops.set_time = pm8xxx_rtc_set_time;
platform_set_drvdata(pdev, rtc_dd);
+ device_init_wakeup(&pdev->dev, 1);
+
/* Register the RTC device */
rtc_dd->rtc = devm_rtc_device_register(&pdev->dev, "pm8xxx_rtc",
- &pm8xxx_rtc_ops, THIS_MODULE);
+ &pm8xxx_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc_dd->rtc)) {
dev_err(&pdev->dev, "%s: RTC registration failed (%ld)\n",
- __func__, PTR_ERR(rtc_dd->rtc));
+ __func__, PTR_ERR(rtc_dd->rtc));
return PTR_ERR(rtc_dd->rtc);
}
/* Request the alarm IRQ */
- rc = request_any_context_irq(rtc_dd->rtc_alarm_irq,
- pm8xxx_alarm_trigger, IRQF_TRIGGER_RISING,
- "pm8xxx_rtc_alarm", rtc_dd);
+ rc = devm_request_any_context_irq(&pdev->dev, rtc_dd->rtc_alarm_irq,
+ pm8xxx_alarm_trigger,
+ IRQF_TRIGGER_RISING,
+ "pm8xxx_rtc_alarm", rtc_dd);
if (rc < 0) {
dev_err(&pdev->dev, "Request IRQ failed (%d)\n", rc);
return rc;
}
- device_init_wakeup(&pdev->dev, 1);
-
dev_dbg(&pdev->dev, "Probe success !!\n");
return 0;
}
-static int pm8xxx_rtc_remove(struct platform_device *pdev)
-{
- struct pm8xxx_rtc *rtc_dd = platform_get_drvdata(pdev);
-
- device_init_wakeup(&pdev->dev, 0);
- free_irq(rtc_dd->rtc_alarm_irq, rtc_dd);
-
- return 0;
-}
-
#ifdef CONFIG_PM_SLEEP
static int pm8xxx_rtc_resume(struct device *dev)
{
@@ -507,15 +477,17 @@ static int pm8xxx_rtc_suspend(struct device *dev)
}
#endif
-static SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops, pm8xxx_rtc_suspend, pm8xxx_rtc_resume);
+static SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops,
+ pm8xxx_rtc_suspend,
+ pm8xxx_rtc_resume);
static struct platform_driver pm8xxx_rtc_driver = {
.probe = pm8xxx_rtc_probe,
- .remove = pm8xxx_rtc_remove,
.driver = {
- .name = PM8XXX_RTC_DEV_NAME,
- .owner = THIS_MODULE,
- .pm = &pm8xxx_rtc_pm_ops,
+ .name = "rtc-pm8xxx",
+ .owner = THIS_MODULE,
+ .pm = &pm8xxx_rtc_pm_ops,
+ .of_match_table = pm8xxx_id_table,
},
};
diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c
index 1a779a67ff66..e9ac5a43be1a 100644
--- a/drivers/rtc/rtc-rv3029c2.c
+++ b/drivers/rtc/rtc-rv3029c2.c
@@ -395,6 +395,12 @@ static int rv3029c2_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_EMUL))
return -ENODEV;
+ rc = rv3029c2_i2c_get_sr(client, buf);
+ if (rc < 0) {
+ dev_err(&client->dev, "reading status failed\n");
+ return rc;
+ }
+
rtc = devm_rtc_device_register(&client->dev, client->name,
&rv3029c2_rtc_ops, THIS_MODULE);
@@ -403,12 +409,6 @@ static int rv3029c2_probe(struct i2c_client *client,
i2c_set_clientdata(client, rtc);
- rc = rv3029c2_i2c_get_sr(client, buf);
- if (rc < 0) {
- dev_err(&client->dev, "reading status failed\n");
- return rc;
- }
-
return 0;
}
diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c
index 8fa23eabcb68..e6298e02b400 100644
--- a/drivers/rtc/rtc-rx8025.c
+++ b/drivers/rtc/rtc-rx8025.c
@@ -551,7 +551,6 @@ static int rx8025_probe(struct i2c_client *client,
rx8025 = devm_kzalloc(&client->dev, sizeof(*rx8025), GFP_KERNEL);
if (!rx8025) {
- dev_err(&adapter->dev, "failed to alloc memory\n");
err = -ENOMEM;
goto errout;
}
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 7afd373b9595..4958a363b2c7 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -48,8 +48,8 @@ struct s3c_rtc_drv_data {
static struct clk *rtc_clk;
static void __iomem *s3c_rtc_base;
-static int s3c_rtc_alarmno = NO_IRQ;
-static int s3c_rtc_tickno = NO_IRQ;
+static int s3c_rtc_alarmno;
+static int s3c_rtc_tickno;
static enum s3c_cpu_type s3c_rtc_cpu_type;
static DEFINE_SPINLOCK(s3c_rtc_pie_lock);
@@ -580,10 +580,12 @@ static int s3c_rtc_suspend(struct device *dev)
clk_enable(rtc_clk);
/* save TICNT for anyone using periodic interrupts */
- ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
ticnt_en_save = readw(s3c_rtc_base + S3C2410_RTCCON);
ticnt_en_save &= S3C64XX_RTCCON_TICEN;
+ ticnt_save = readl(s3c_rtc_base + S3C2410_TICNT);
+ } else {
+ ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
}
s3c_rtc_enable(pdev, 0);
@@ -605,10 +607,15 @@ static int s3c_rtc_resume(struct device *dev)
clk_enable(rtc_clk);
s3c_rtc_enable(pdev, 1);
- writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
- if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) {
- tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
- writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON);
+ if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
+ writel(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
+ if (ticnt_en_save) {
+ tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
+ writew(tmp | ticnt_en_save,
+ s3c_rtc_base + S3C2410_RTCCON);
+ }
+ } else {
+ writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
}
if (device_may_wakeup(dev) && wake_en) {
diff --git a/drivers/rtc/rtc-sirfsoc.c b/drivers/rtc/rtc-sirfsoc.c
index 3eb3642ae299..76e38007ba90 100644
--- a/drivers/rtc/rtc-sirfsoc.c
+++ b/drivers/rtc/rtc-sirfsoc.c
@@ -264,12 +264,8 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev)
rtcdrv = devm_kzalloc(&pdev->dev,
sizeof(struct sirfsoc_rtc_drv), GFP_KERNEL);
- if (rtcdrv == NULL) {
- dev_err(&pdev->dev,
- "%s: can't alloc mem for drv struct\n",
- pdev->name);
+ if (rtcdrv == NULL)
return -ENOMEM;
- }
err = of_property_read_u32(np, "reg", &rtcdrv->rtc_base);
if (err) {
@@ -335,39 +331,29 @@ static int sirfsoc_rtc_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-
+#ifdef CONFIG_PM_SLEEP
static int sirfsoc_rtc_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
+ struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev);
rtcdrv->overflow_rtc =
sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE);
rtcdrv->saved_counter =
sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN);
rtcdrv->saved_overflow_rtc = rtcdrv->overflow_rtc;
- if (device_may_wakeup(&pdev->dev) && !enable_irq_wake(rtcdrv->irq))
+ if (device_may_wakeup(dev) && !enable_irq_wake(rtcdrv->irq))
rtcdrv->irq_wake = 1;
return 0;
}
-static int sirfsoc_rtc_freeze(struct device *dev)
-{
- sirfsoc_rtc_suspend(dev);
-
- return 0;
-}
-
-static int sirfsoc_rtc_thaw(struct device *dev)
+static int sirfsoc_rtc_resume(struct device *dev)
{
u32 tmp;
- struct sirfsoc_rtc_drv *rtcdrv;
- rtcdrv = dev_get_drvdata(dev);
+ struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev);
/*
- * if resume from snapshot and the rtc power is losed,
+ * if resume from snapshot and the rtc power is lost,
* restroe the rtc settings
*/
if (SIRFSOC_RTC_CLK != sirfsoc_rtc_iobrg_readl(
@@ -407,57 +393,23 @@ static int sirfsoc_rtc_thaw(struct device *dev)
sirfsoc_rtc_iobrg_writel(rtcdrv->overflow_rtc,
rtcdrv->rtc_base + RTC_SW_VALUE);
- return 0;
-}
-
-static int sirfsoc_rtc_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
- sirfsoc_rtc_thaw(dev);
- if (device_may_wakeup(&pdev->dev) && rtcdrv->irq_wake) {
+ if (device_may_wakeup(dev) && rtcdrv->irq_wake) {
disable_irq_wake(rtcdrv->irq);
rtcdrv->irq_wake = 0;
}
return 0;
}
-
-static int sirfsoc_rtc_restore(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
-
- if (device_may_wakeup(&pdev->dev) && rtcdrv->irq_wake) {
- disable_irq_wake(rtcdrv->irq);
- rtcdrv->irq_wake = 0;
- }
- return 0;
-}
-
-#else
-#define sirfsoc_rtc_suspend NULL
-#define sirfsoc_rtc_resume NULL
-#define sirfsoc_rtc_freeze NULL
-#define sirfsoc_rtc_thaw NULL
-#define sirfsoc_rtc_restore NULL
#endif
-static const struct dev_pm_ops sirfsoc_rtc_pm_ops = {
- .suspend = sirfsoc_rtc_suspend,
- .resume = sirfsoc_rtc_resume,
- .freeze = sirfsoc_rtc_freeze,
- .thaw = sirfsoc_rtc_thaw,
- .restore = sirfsoc_rtc_restore,
-};
+static SIMPLE_DEV_PM_OPS(sirfsoc_rtc_pm_ops,
+ sirfsoc_rtc_suspend, sirfsoc_rtc_resume);
static struct platform_driver sirfsoc_rtc_driver = {
.driver = {
.name = "sirfsoc-rtc",
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
.pm = &sirfsoc_rtc_pm_ops,
-#endif
.of_match_table = sirfsoc_rtc_of_match,
},
.probe = sirfsoc_rtc_probe,
diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c
index c492cf0ab8cd..d2cdb9823a15 100644
--- a/drivers/rtc/rtc-spear.c
+++ b/drivers/rtc/rtc-spear.c
@@ -365,10 +365,8 @@ static int spear_rtc_probe(struct platform_device *pdev)
}
config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
- if (!config) {
- dev_err(&pdev->dev, "out of memory\n");
+ if (!config)
return -ENOMEM;
- }
/* alarm irqs */
irq = platform_get_irq(pdev, 0);
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c
index a176ba614683..35ed49ea1f81 100644
--- a/drivers/rtc/rtc-stk17ta8.c
+++ b/drivers/rtc/rtc-stk17ta8.c
@@ -214,8 +214,7 @@ static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id)
events |= RTC_UF;
else
events |= RTC_AF;
- if (likely(pdata->rtc))
- rtc_update_irq(pdata->rtc, 1, events);
+ rtc_update_irq(pdata->rtc, 1, events);
}
spin_unlock(&pdata->lock);
return events ? IRQ_HANDLED : IRQ_NONE;
diff --git a/drivers/rtc/rtc-sunxi.c b/drivers/rtc/rtc-sunxi.c
index 68a35284e5ad..b6f21f73d508 100644
--- a/drivers/rtc/rtc-sunxi.c
+++ b/drivers/rtc/rtc-sunxi.c
@@ -428,7 +428,7 @@ static const struct rtc_class_ops sunxi_rtc_ops = {
};
static const struct of_device_id sunxi_rtc_dt_ids[] = {
- { .compatible = "allwinner,sun4i-rtc", .data = &data_year_param[0] },
+ { .compatible = "allwinner,sun4i-a10-rtc", .data = &data_year_param[0] },
{ .compatible = "allwinner,sun7i-a20-rtc", .data = &data_year_param[1] },
{ /* sentinel */ },
};
diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c
index 7746e65b93f2..6599c20bc454 100644
--- a/drivers/rtc/rtc-test.c
+++ b/drivers/rtc/rtc-test.c
@@ -104,20 +104,17 @@ static int test_probe(struct platform_device *plat_dev)
rtc = devm_rtc_device_register(&plat_dev->dev, "test",
&test_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
- err = PTR_ERR(rtc);
- return err;
+ return PTR_ERR(rtc);
}
err = device_create_file(&plat_dev->dev, &dev_attr_irq);
if (err)
- goto err;
+ dev_err(&plat_dev->dev, "Unable to create sysfs entry: %s\n",
+ dev_attr_irq.attr.name);
platform_set_drvdata(plat_dev, rtc);
return 0;
-
-err:
- return err;
}
static int test_remove(struct platform_device *plat_dev)
diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c
index 4f87234e0dee..2e678c681b13 100644
--- a/drivers/rtc/rtc-tx4939.c
+++ b/drivers/rtc/rtc-tx4939.c
@@ -176,8 +176,8 @@ static irqreturn_t tx4939_rtc_interrupt(int irq, void *dev_id)
tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_NOP);
}
spin_unlock(&pdata->lock);
- if (likely(pdata->rtc))
- rtc_update_irq(pdata->rtc, 1, events);
+ rtc_update_irq(pdata->rtc, 1, events);
+
return IRQ_HANDLED;
}
diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c
index df2ef3eba7cd..051da968da6d 100644
--- a/drivers/rtc/rtc-vt8500.c
+++ b/drivers/rtc/rtc-vt8500.c
@@ -79,7 +79,6 @@
struct vt8500_rtc {
void __iomem *regbase;
- struct resource *res;
int irq_alarm;
struct rtc_device *rtc;
spinlock_t lock; /* Protects this structure */
@@ -209,6 +208,7 @@ static const struct rtc_class_ops vt8500_rtc_ops = {
static int vt8500_rtc_probe(struct platform_device *pdev)
{
struct vt8500_rtc *vt8500_rtc;
+ struct resource *res;
int ret;
vt8500_rtc = devm_kzalloc(&pdev->dev,
@@ -219,34 +219,16 @@ static int vt8500_rtc_probe(struct platform_device *pdev)
spin_lock_init(&vt8500_rtc->lock);
platform_set_drvdata(pdev, vt8500_rtc);
- vt8500_rtc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!vt8500_rtc->res) {
- dev_err(&pdev->dev, "No I/O memory resource defined\n");
- return -ENXIO;
- }
-
vt8500_rtc->irq_alarm = platform_get_irq(pdev, 0);
if (vt8500_rtc->irq_alarm < 0) {
dev_err(&pdev->dev, "No alarm IRQ resource defined\n");
return vt8500_rtc->irq_alarm;
}
- vt8500_rtc->res = devm_request_mem_region(&pdev->dev,
- vt8500_rtc->res->start,
- resource_size(vt8500_rtc->res),
- "vt8500-rtc");
- if (vt8500_rtc->res == NULL) {
- dev_err(&pdev->dev, "failed to request I/O memory\n");
- return -EBUSY;
- }
-
- vt8500_rtc->regbase = devm_ioremap(&pdev->dev, vt8500_rtc->res->start,
- resource_size(vt8500_rtc->res));
- if (!vt8500_rtc->regbase) {
- dev_err(&pdev->dev, "Unable to map RTC I/O memory\n");
- ret = -EBUSY;
- goto err_return;
- }
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ vt8500_rtc->regbase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(vt8500_rtc->regbase))
+ return PTR_ERR(vt8500_rtc->regbase);
/* Enable RTC and set it to 24-hour mode */
writel(VT8500_RTC_CR_ENABLE,
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index 365dc6505148..b1de58e0b3d0 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -660,7 +660,7 @@ static int x1205_probe(struct i2c_client *client,
err = x1205_sysfs_register(&client->dev);
if (err)
- return err;
+ dev_err(&client->dev, "Unable to create sysfs entries\n");
return 0;
}
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index ebf41e228e55..ee0e85abe1fd 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -304,12 +304,6 @@ dcssblk_load_segment(char *name, struct segment_info **seg_info)
return rc;
}
-static void dcssblk_unregister_callback(struct device *dev)
-{
- device_unregister(dev);
- put_device(dev);
-}
-
/*
* device attribute for switching shared/nonshared (exclusive)
* operation (show + store)
@@ -397,7 +391,13 @@ removeseg:
blk_cleanup_queue(dev_info->dcssblk_queue);
dev_info->gd->queue = NULL;
put_disk(dev_info->gd);
- rc = device_schedule_callback(dev, dcssblk_unregister_callback);
+ up_write(&dcssblk_devices_sem);
+
+ if (device_remove_file_self(dev, attr)) {
+ device_unregister(dev);
+ put_device(dev);
+ }
+ return rc;
out:
up_write(&dcssblk_devices_sem);
return rc;
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index eb5d22795c47..5af7f0bd6125 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -922,7 +922,7 @@ static int __init con3215_init(void)
raw3215_freelist = req;
}
- cdev = ccw_device_probe_console();
+ cdev = ccw_device_create_console(&raw3215_ccw_driver);
if (IS_ERR(cdev))
return -ENODEV;
@@ -932,6 +932,12 @@ static int __init con3215_init(void)
cdev->handler = raw3215_irq;
raw->flags |= RAW3215_FIXED;
+ if (ccw_device_enable_console(cdev)) {
+ ccw_device_destroy_console(cdev);
+ raw3215_free_info(raw);
+ raw3215[0] = NULL;
+ return -ENODEV;
+ }
/* Request the console irq */
if (raw3215_startup(raw) != 0) {
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index 699fd3e363df..75ffe9980c3e 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -7,6 +7,7 @@
* Copyright IBM Corp. 2003, 2009
*/
+#include <linux/module.h>
#include <linux/console.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -30,6 +31,9 @@
static struct raw3270_fn con3270_fn;
+static bool auto_update = 1;
+module_param(auto_update, bool, 0);
+
/*
* Main 3270 console view data structure.
*/
@@ -204,6 +208,8 @@ con3270_update(struct con3270 *cp)
struct string *s, *n;
int rc;
+ if (!auto_update && !raw3270_view_active(&cp->view))
+ return;
if (cp->view.dev)
raw3270_activate_view(&cp->view);
@@ -529,6 +535,7 @@ con3270_flush(void)
if (!cp->view.dev)
return;
raw3270_pm_unfreeze(&cp->view);
+ raw3270_activate_view(&cp->view);
spin_lock_irqsave(&cp->view.lock, flags);
con3270_wait_write(cp);
cp->nr_up = 0;
@@ -576,7 +583,6 @@ static struct console con3270 = {
static int __init
con3270_init(void)
{
- struct ccw_device *cdev;
struct raw3270 *rp;
void *cbuf;
int i;
@@ -591,10 +597,7 @@ con3270_init(void)
cpcmd("TERM AUTOCR OFF", NULL, 0, NULL);
}
- cdev = ccw_device_probe_console();
- if (IS_ERR(cdev))
- return -ENODEV;
- rp = raw3270_setup_console(cdev);
+ rp = raw3270_setup_console();
if (IS_ERR(rp))
return PTR_ERR(rp);
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 2cdec21e8924..9f849df4381e 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -276,6 +276,15 @@ __raw3270_start(struct raw3270 *rp, struct raw3270_view *view,
}
int
+raw3270_view_active(struct raw3270_view *view)
+{
+ struct raw3270 *rp = view->dev;
+
+ return rp && rp->view == view &&
+ !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
+}
+
+int
raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
{
unsigned long flags;
@@ -776,22 +785,37 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
}
#ifdef CONFIG_TN3270_CONSOLE
+/* Tentative definition - see below for actual definition. */
+static struct ccw_driver raw3270_ccw_driver;
+
/*
* Setup 3270 device configured as console.
*/
-struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev)
+struct raw3270 __init *raw3270_setup_console(void)
{
+ struct ccw_device *cdev;
unsigned long flags;
struct raw3270 *rp;
char *ascebc;
int rc;
+ cdev = ccw_device_create_console(&raw3270_ccw_driver);
+ if (IS_ERR(cdev))
+ return ERR_CAST(cdev);
+
rp = kzalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA);
ascebc = kzalloc(256, GFP_KERNEL);
rc = raw3270_setup_device(cdev, rp, ascebc);
if (rc)
return ERR_PTR(rc);
set_bit(RAW3270_FLAGS_CONSOLE, &rp->flags);
+
+ rc = ccw_device_enable_console(cdev);
+ if (rc) {
+ ccw_device_destroy_console(cdev);
+ return ERR_PTR(rc);
+ }
+
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
do {
__raw3270_reset_device(rp);
diff --git a/drivers/s390/char/raw3270.h b/drivers/s390/char/raw3270.h
index 7b73ff8c1bd7..e1e41c2861fb 100644
--- a/drivers/s390/char/raw3270.h
+++ b/drivers/s390/char/raw3270.h
@@ -173,6 +173,7 @@ int raw3270_start_locked(struct raw3270_view *, struct raw3270_request *);
int raw3270_start_irq(struct raw3270_view *, struct raw3270_request *);
int raw3270_reset(struct raw3270_view *);
struct raw3270_view *raw3270_view(struct raw3270_view *);
+int raw3270_view_active(struct raw3270_view *);
/* Reference count inliner for view structures. */
static inline void
@@ -190,7 +191,7 @@ raw3270_put_view(struct raw3270_view *view)
wake_up(&raw3270_wait_queue);
}
-struct raw3270 *raw3270_setup_console(struct ccw_device *cdev);
+struct raw3270 *raw3270_setup_console(void);
void raw3270_wait_cons_dev(struct raw3270 *);
/* Notifier for device addition/removal */
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c
index 82f2c389b4d1..14196ea0fdf3 100644
--- a/drivers/s390/char/sclp_early.c
+++ b/drivers/s390/char/sclp_early.c
@@ -20,7 +20,9 @@ struct read_info_sccb {
struct sccb_header header; /* 0-7 */
u16 rnmax; /* 8-9 */
u8 rnsize; /* 10 */
- u8 _reserved0[24 - 11]; /* 11-15 */
+ u8 _reserved0[16 - 11]; /* 11-15 */
+ u16 ncpurl; /* 16-17 */
+ u8 _reserved7[24 - 18]; /* 18-23 */
u8 loadparm[8]; /* 24-31 */
u8 _reserved1[48 - 32]; /* 32-47 */
u64 facilities; /* 48-55 */
@@ -32,13 +34,16 @@ struct read_info_sccb {
u8 _reserved4[100 - 92]; /* 92-99 */
u32 rnsize2; /* 100-103 */
u64 rnmax2; /* 104-111 */
- u8 _reserved5[4096 - 112]; /* 112-4095 */
+ u8 _reserved5[120 - 112]; /* 112-119 */
+ u16 hcpua; /* 120-121 */
+ u8 _reserved6[4096 - 122]; /* 122-4095 */
} __packed __aligned(PAGE_SIZE);
static char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE) __initdata;
static unsigned int sclp_con_has_vt220 __initdata;
static unsigned int sclp_con_has_linemode __initdata;
static unsigned long sclp_hsa_size;
+static unsigned int sclp_max_cpu;
static struct sclp_ipl_info sclp_ipl_info;
u64 sclp_facilities;
@@ -102,6 +107,15 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
sclp_rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
sclp_rzm <<= 20;
+ if (!sccb->hcpua) {
+ if (MACHINE_IS_VM)
+ sclp_max_cpu = 64;
+ else
+ sclp_max_cpu = sccb->ncpurl;
+ } else {
+ sclp_max_cpu = sccb->hcpua + 1;
+ }
+
/* Save IPL information */
sclp_ipl_info.is_valid = 1;
if (sccb->flags & 0x2)
@@ -129,6 +143,11 @@ unsigned long long sclp_get_rzm(void)
return sclp_rzm;
}
+unsigned int sclp_get_max_cpu(void)
+{
+ return sclp_max_cpu;
+}
+
/*
* This function will be called after sclp_facilities_detect(), which gets
* called from early.c code. The sclp_facilities_detect() function retrieves
@@ -184,9 +203,9 @@ static long __init sclp_hsa_size_init(struct sdias_sccb *sccb)
sccb_init_eq_size(sccb);
if (sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_DATA, sccb))
return -EIO;
- if (sccb->evbuf.blk_cnt != 0)
- return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
- return 0;
+ if (sccb->evbuf.blk_cnt == 0)
+ return 0;
+ return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
}
static long __init sclp_hsa_copy_wait(struct sccb_header *sccb)
@@ -195,6 +214,8 @@ static long __init sclp_hsa_copy_wait(struct sccb_header *sccb)
sccb->length = PAGE_SIZE;
if (sclp_cmd_early(SCLP_CMDW_READ_EVENT_DATA, sccb))
return -EIO;
+ if (((struct sdias_sccb *) sccb)->evbuf.blk_cnt == 0)
+ return 0;
return (((struct sdias_sccb *) sccb)->evbuf.blk_cnt - 1) * PAGE_SIZE;
}
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c
index f055df0b167f..445564c790f6 100644
--- a/drivers/s390/cio/airq.c
+++ b/drivers/s390/cio/airq.c
@@ -186,55 +186,71 @@ void airq_iv_release(struct airq_iv *iv)
EXPORT_SYMBOL(airq_iv_release);
/**
- * airq_iv_alloc_bit - allocate an irq bit from an interrupt vector
+ * airq_iv_alloc - allocate irq bits from an interrupt vector
* @iv: pointer to an interrupt vector structure
+ * @num: number of consecutive irq bits to allocate
*
- * 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
+ * Returns the bit number of the first irq in the allocated block of irqs,
+ * 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)
+unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num)
{
- unsigned long bit;
+ unsigned long bit, i;
- if (!iv->avail)
+ if (!iv->avail || num == 0)
return -1UL;
spin_lock(&iv->lock);
bit = find_first_bit_inv(iv->avail, iv->bits);
- if (bit < iv->bits) {
- clear_bit_inv(bit, iv->avail);
- if (bit >= iv->end)
- iv->end = bit + 1;
- } else
+ while (bit + num <= iv->bits) {
+ for (i = 1; i < num; i++)
+ if (!test_bit_inv(bit + i, iv->avail))
+ break;
+ if (i >= num) {
+ /* Found a suitable block of irqs */
+ for (i = 0; i < num; i++)
+ clear_bit_inv(bit + i, iv->avail);
+ if (bit + num >= iv->end)
+ iv->end = bit + num + 1;
+ break;
+ }
+ bit = find_next_bit_inv(iv->avail, iv->bits, bit + i + 1);
+ }
+ if (bit + num > iv->bits)
bit = -1UL;
spin_unlock(&iv->lock);
return bit;
}
-EXPORT_SYMBOL(airq_iv_alloc_bit);
+EXPORT_SYMBOL(airq_iv_alloc);
/**
- * airq_iv_free_bit - free an irq bit of an interrupt vector
+ * airq_iv_free - free irq bits of an interrupt vector
* @iv: pointer to interrupt vector structure
- * @bit: number of the irq bit to free
+ * @bit: number of the first irq bit to free
+ * @num: number of consecutive irq bits to free
*/
-void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit)
+void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num)
{
- if (!iv->avail)
+ unsigned long i;
+
+ if (!iv->avail || num == 0)
return;
spin_lock(&iv->lock);
- /* Clear (possibly left over) interrupt bit */
- clear_bit_inv(bit, iv->vector);
- /* Make the bit position available again */
- set_bit_inv(bit, iv->avail);
- if (bit == iv->end - 1) {
+ for (i = 0; i < num; i++) {
+ /* Clear (possibly left over) interrupt bit */
+ clear_bit_inv(bit + i, iv->vector);
+ /* Make the bit positions available again */
+ set_bit_inv(bit + i, iv->avail);
+ }
+ if (bit + num >= iv->end) {
/* Find new end of bit-field */
- while (--iv->end > 0)
- if (!test_bit_inv(iv->end - 1, iv->avail))
- break;
+ while (iv->end > 0 && !test_bit_inv(iv->end - 1, iv->avail))
+ iv->end--;
}
spin_unlock(&iv->lock);
}
-EXPORT_SYMBOL(airq_iv_free_bit);
+EXPORT_SYMBOL(airq_iv_free);
/**
* airq_iv_scan - scan interrupt vector for non-zero bits
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index fd3367a1dc7a..dfd7bc681c25 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -168,14 +168,12 @@ static ssize_t ccwgroup_online_show(struct device *dev,
* Provide an 'ungroup' attribute so the user can remove group devices no
* longer needed or accidentially created. Saves memory :)
*/
-static void ccwgroup_ungroup_callback(struct device *dev)
+static void ccwgroup_ungroup(struct ccwgroup_device *gdev)
{
- struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
-
mutex_lock(&gdev->reg_mutex);
if (device_is_registered(&gdev->dev)) {
__ccwgroup_remove_symlinks(gdev);
- device_unregister(dev);
+ device_unregister(&gdev->dev);
__ccwgroup_remove_cdev_refs(gdev);
}
mutex_unlock(&gdev->reg_mutex);
@@ -195,10 +193,9 @@ static ssize_t ccwgroup_ungroup_store(struct device *dev,
rc = -EINVAL;
goto out;
}
- /* Note that we cannot unregister the device from one of its
- * attribute methods, so we have to use this roundabout approach.
- */
- rc = device_schedule_callback(dev, ccwgroup_ungroup_callback);
+
+ if (device_remove_file_self(dev, attr))
+ ccwgroup_ungroup(gdev);
out:
if (rc) {
if (rc != -EAGAIN)
@@ -224,6 +221,14 @@ static const struct attribute_group *ccwgroup_attr_groups[] = {
NULL,
};
+static void ccwgroup_ungroup_workfn(struct work_struct *work)
+{
+ struct ccwgroup_device *gdev =
+ container_of(work, struct ccwgroup_device, ungroup_work);
+
+ ccwgroup_ungroup(gdev);
+}
+
static void ccwgroup_release(struct device *dev)
{
kfree(to_ccwgroupdev(dev));
@@ -323,6 +328,7 @@ int ccwgroup_create_dev(struct device *parent, struct ccwgroup_driver *gdrv,
atomic_set(&gdev->onoff, 0);
mutex_init(&gdev->reg_mutex);
mutex_lock(&gdev->reg_mutex);
+ INIT_WORK(&gdev->ungroup_work, ccwgroup_ungroup_workfn);
gdev->count = num_devices;
gdev->dev.bus = &ccwgroup_bus_type;
gdev->dev.parent = parent;
@@ -404,10 +410,10 @@ EXPORT_SYMBOL(ccwgroup_create_dev);
static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action,
void *data)
{
- struct device *dev = data;
+ struct ccwgroup_device *gdev = to_ccwgroupdev(data);
if (action == BUS_NOTIFY_UNBIND_DRIVER)
- device_schedule_callback(dev, ccwgroup_ungroup_callback);
+ schedule_work(&gdev->ungroup_work);
return NOTIFY_OK;
}
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index f6b9188c5af5..9f0ea6cb6922 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -610,6 +610,7 @@ void chsc_chp_online(struct chp_id chpid)
css_wait_for_slow_path();
for_each_subchannel_staged(__s390_process_res_acc, NULL,
&link);
+ css_schedule_reprobe();
}
}
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c
index 7b29d0be0ca3..1d3661af7bd8 100644
--- a/drivers/s390/cio/chsc_sch.c
+++ b/drivers/s390/cio/chsc_sch.c
@@ -173,8 +173,7 @@ static struct css_driver chsc_subchannel_driver = {
static int __init chsc_init_dbfs(void)
{
- chsc_debug_msg_id = debug_register("chsc_msg", 16, 1,
- 16 * sizeof(long));
+ chsc_debug_msg_id = debug_register("chsc_msg", 8, 1, 4 * sizeof(long));
if (!chsc_debug_msg_id)
goto out;
debug_register_view(chsc_debug_msg_id, &debug_sprintf_view);
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 88e35d85d205..9e058c4657a3 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -18,6 +18,7 @@
#include <linux/device.h>
#include <linux/kernel_stat.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <asm/cio.h>
#include <asm/delay.h>
#include <asm/irq.h>
@@ -28,7 +29,7 @@
#include <asm/chpid.h>
#include <asm/airq.h>
#include <asm/isc.h>
-#include <asm/cputime.h>
+#include <linux/cputime.h>
#include <asm/fcx.h>
#include <asm/nmi.h>
#include <asm/crw.h>
@@ -54,7 +55,7 @@ debug_info_t *cio_debug_crw_id;
*/
static int __init cio_debug_init(void)
{
- cio_debug_msg_id = debug_register("cio_msg", 16, 1, 16 * sizeof(long));
+ cio_debug_msg_id = debug_register("cio_msg", 16, 1, 11 * sizeof(long));
if (!cio_debug_msg_id)
goto out_unregister;
debug_register_view(cio_debug_msg_id, &debug_sprintf_view);
@@ -64,7 +65,7 @@ static int __init cio_debug_init(void)
goto out_unregister;
debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view);
debug_set_level(cio_debug_trace_id, 2);
- cio_debug_crw_id = debug_register("cio_crw", 16, 1, 16 * sizeof(long));
+ cio_debug_crw_id = debug_register("cio_crw", 8, 1, 8 * sizeof(long));
if (!cio_debug_crw_id)
goto out_unregister;
debug_register_view(cio_debug_crw_id, &debug_sprintf_view);
@@ -342,8 +343,9 @@ static int cio_check_config(struct subchannel *sch, struct schib *schib)
*/
int cio_commit_config(struct subchannel *sch)
{
- struct schib schib;
int ccode, retry, ret = 0;
+ struct schib schib;
+ struct irb irb;
if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib))
return -ENODEV;
@@ -367,7 +369,10 @@ int cio_commit_config(struct subchannel *sch)
ret = -EAGAIN;
break;
case 1: /* status pending */
- return -EBUSY;
+ ret = -EBUSY;
+ if (tsch(sch->schid, &irb))
+ return ret;
+ break;
case 2: /* busy */
udelay(100); /* allow for recovery */
ret = -EBUSY;
@@ -403,7 +408,6 @@ EXPORT_SYMBOL_GPL(cio_update_schib);
*/
int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
{
- int retry;
int ret;
CIO_TRACE_EVENT(2, "ensch");
@@ -418,20 +422,14 @@ int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
sch->config.isc = sch->isc;
sch->config.intparm = intparm;
- for (retry = 0; retry < 3; retry++) {
+ ret = cio_commit_config(sch);
+ if (ret == -EIO) {
+ /*
+ * Got a program check in msch. Try without
+ * the concurrent sense bit the next time.
+ */
+ sch->config.csense = 0;
ret = cio_commit_config(sch);
- if (ret == -EIO) {
- /*
- * Got a program check in msch. Try without
- * the concurrent sense bit the next time.
- */
- sch->config.csense = 0;
- } else if (ret == -EBUSY) {
- struct irb irb;
- if (tsch(sch->schid, &irb) != 0)
- break;
- } else
- break;
}
CIO_HEX_EVENT(2, &ret, sizeof(ret));
return ret;
@@ -444,7 +442,6 @@ EXPORT_SYMBOL_GPL(cio_enable_subchannel);
*/
int cio_disable_subchannel(struct subchannel *sch)
{
- int retry;
int ret;
CIO_TRACE_EVENT(2, "dissch");
@@ -456,16 +453,8 @@ int cio_disable_subchannel(struct subchannel *sch)
return -ENODEV;
sch->config.ena = 0;
+ ret = cio_commit_config(sch);
- for (retry = 0; retry < 3; retry++) {
- ret = cio_commit_config(sch);
- if (ret == -EBUSY) {
- struct irb irb;
- if (tsch(sch->schid, &irb) != 0)
- break;
- } else
- break;
- }
CIO_HEX_EVENT(2, &ret, sizeof(ret));
return ret;
}
@@ -596,8 +585,6 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy)
return IRQ_HANDLED;
}
-static struct irq_desc *irq_desc_io;
-
static struct irqaction io_interrupt = {
.name = "IO",
.handler = do_cio_interrupt,
@@ -608,7 +595,6 @@ 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 +621,7 @@ void cio_tsch(struct subchannel *sch)
local_bh_disable();
irq_enter();
}
- kstat_incr_irqs_this_cpu(IO_INTERRUPT, irq_desc_io);
+ kstat_incr_irq_this_cpu(IO_INTERRUPT);
if (sch->driver && sch->driver->irq)
sch->driver->irq(sch);
else
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index e9d783563cbb..d8d9b5b5cc56 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1571,12 +1571,27 @@ out:
return rc;
}
+static void ccw_device_set_int_class(struct ccw_device *cdev)
+{
+ struct ccw_driver *cdrv = cdev->drv;
+
+ /* Note: we interpret class 0 in this context as an uninitialized
+ * field since it translates to a non-I/O interrupt class. */
+ if (cdrv->int_class != 0)
+ cdev->private->int_class = cdrv->int_class;
+ else
+ cdev->private->int_class = IRQIO_CIO;
+}
+
#ifdef CONFIG_CCW_CONSOLE
-static int ccw_device_console_enable(struct ccw_device *cdev,
- struct subchannel *sch)
+int __init ccw_device_enable_console(struct ccw_device *cdev)
{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
int rc;
+ if (!cdev->drv || !cdev->handler)
+ return -EINVAL;
+
io_subchannel_init_fields(sch);
rc = cio_commit_config(sch);
if (rc)
@@ -1609,12 +1624,11 @@ out_unlock:
return rc;
}
-struct ccw_device *ccw_device_probe_console(void)
+struct ccw_device * __init ccw_device_create_console(struct ccw_driver *drv)
{
struct io_subchannel_private *io_priv;
struct ccw_device *cdev;
struct subchannel *sch;
- int ret;
sch = cio_probe_console();
if (IS_ERR(sch))
@@ -1631,18 +1645,23 @@ struct ccw_device *ccw_device_probe_console(void)
kfree(io_priv);
return cdev;
}
+ cdev->drv = drv;
set_io_private(sch, io_priv);
- ret = ccw_device_console_enable(cdev, sch);
- if (ret) {
- set_io_private(sch, NULL);
- put_device(&sch->dev);
- put_device(&cdev->dev);
- kfree(io_priv);
- return ERR_PTR(ret);
- }
+ ccw_device_set_int_class(cdev);
return cdev;
}
+void __init ccw_device_destroy_console(struct ccw_device *cdev)
+{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct io_subchannel_private *io_priv = to_io_private(sch);
+
+ set_io_private(sch, NULL);
+ put_device(&sch->dev);
+ put_device(&cdev->dev);
+ kfree(io_priv);
+}
+
/**
* ccw_device_wait_idle() - busy wait for device to become idle
* @cdev: ccw device
@@ -1726,15 +1745,8 @@ ccw_device_probe (struct device *dev)
int ret;
cdev->drv = cdrv; /* to let the driver call _set_online */
- /* Note: we interpret class 0 in this context as an uninitialized
- * field since it translates to a non-I/O interrupt class. */
- if (cdrv->int_class != 0)
- cdev->private->int_class = cdrv->int_class;
- else
- cdev->private->int_class = IRQIO_CIO;
-
+ ccw_device_set_int_class(cdev);
ret = cdrv->probe ? cdrv->probe(cdev) : -ENODEV;
-
if (ret) {
cdev->drv = NULL;
cdev->private->int_class = IRQIO_CIO;
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index 8acaae18bd11..a563e4c00590 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -359,14 +359,12 @@ static inline int multicast_outbound(struct qdio_q *q)
#define need_siga_sync_out_after_pci(q) \
(unlikely(q->irq_ptr->siga_flag.sync_out_after_pci))
-#define for_each_input_queue(irq_ptr, q, i) \
- for (i = 0, q = irq_ptr->input_qs[0]; \
- i < irq_ptr->nr_input_qs; \
- q = irq_ptr->input_qs[++i])
-#define for_each_output_queue(irq_ptr, q, i) \
- for (i = 0, q = irq_ptr->output_qs[0]; \
- i < irq_ptr->nr_output_qs; \
- q = irq_ptr->output_qs[++i])
+#define for_each_input_queue(irq_ptr, q, i) \
+ for (i = 0; i < irq_ptr->nr_input_qs && \
+ ({ q = irq_ptr->input_qs[i]; 1; }); i++)
+#define for_each_output_queue(irq_ptr, q, i) \
+ for (i = 0; i < irq_ptr->nr_output_qs && \
+ ({ q = irq_ptr->output_qs[i]; 1; }); i++)
#define prev_buf(bufnr) \
((bufnr + QDIO_MAX_BUFFERS_MASK) & QDIO_MAX_BUFFERS_MASK)
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index c883a085c059..77466c4faabb 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -996,7 +996,7 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr)
}
}
- if (!pci_out_supported(q))
+ if (!(irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED))
return;
for_each_output_queue(irq_ptr, q, i) {
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c
index dc542e0a3055..0bc91e46395a 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.c
+++ b/drivers/s390/crypto/zcrypt_msgtype6.c
@@ -311,7 +311,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
} __packed * msg = ap_msg->message;
int rcblen = CEIL4(xcRB->request_control_blk_length);
- int replylen;
+ int replylen, req_sumlen, resp_sumlen;
char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen;
char *function_code;
@@ -321,12 +321,34 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
xcRB->request_data_length;
if (ap_msg->length > MSGTYPE06_MAX_MSG_SIZE)
return -EINVAL;
+
+ /* Overflow check
+ sum must be greater (or equal) than the largest operand */
+ req_sumlen = CEIL4(xcRB->request_control_blk_length) +
+ xcRB->request_data_length;
+ if ((CEIL4(xcRB->request_control_blk_length) <=
+ xcRB->request_data_length) ?
+ (req_sumlen < xcRB->request_data_length) :
+ (req_sumlen < CEIL4(xcRB->request_control_blk_length))) {
+ return -EINVAL;
+ }
+
replylen = sizeof(struct type86_fmt2_msg) +
CEIL4(xcRB->reply_control_blk_length) +
xcRB->reply_data_length;
if (replylen > MSGTYPE06_MAX_MSG_SIZE)
return -EINVAL;
+ /* Overflow check
+ sum must be greater (or equal) than the largest operand */
+ resp_sumlen = CEIL4(xcRB->reply_control_blk_length) +
+ xcRB->reply_data_length;
+ if ((CEIL4(xcRB->reply_control_blk_length) <= xcRB->reply_data_length) ?
+ (resp_sumlen < xcRB->reply_data_length) :
+ (resp_sumlen < CEIL4(xcRB->reply_control_blk_length))) {
+ return -EINVAL;
+ }
+
/* prepare type6 header */
msg->hdr = static_type6_hdrX;
memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID));
diff --git a/drivers/s390/kvm/virtio_ccw.c b/drivers/s390/kvm/virtio_ccw.c
index 0fc584832001..1e1fc671f89a 100644
--- a/drivers/s390/kvm/virtio_ccw.c
+++ b/drivers/s390/kvm/virtio_ccw.c
@@ -1,7 +1,7 @@
/*
* ccw based virtio transport
*
- * Copyright IBM Corp. 2012
+ * Copyright IBM Corp. 2012, 2014
*
* 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)
@@ -32,6 +32,8 @@
#include <asm/cio.h>
#include <asm/ccwdev.h>
#include <asm/virtio-ccw.h>
+#include <asm/isc.h>
+#include <asm/airq.h>
/*
* virtio related functions
@@ -58,6 +60,9 @@ struct virtio_ccw_device {
unsigned long indicators;
unsigned long indicators2;
struct vq_config_block *config_block;
+ bool is_thinint;
+ bool going_away;
+ void *airq_info;
};
struct vq_info_block {
@@ -72,15 +77,38 @@ struct virtio_feature_desc {
__u8 index;
} __packed;
+struct virtio_thinint_area {
+ unsigned long summary_indicator;
+ unsigned long indicator;
+ u64 bit_nr;
+ u8 isc;
+} __packed;
+
struct virtio_ccw_vq_info {
struct virtqueue *vq;
int num;
void *queue;
struct vq_info_block *info_block;
+ int bit_nr;
struct list_head node;
long cookie;
};
+#define VIRTIO_AIRQ_ISC IO_SCH_ISC /* inherit from subchannel */
+
+#define VIRTIO_IV_BITS (L1_CACHE_BYTES * 8)
+#define MAX_AIRQ_AREAS 20
+
+static int virtio_ccw_use_airq = 1;
+
+struct airq_info {
+ rwlock_t lock;
+ u8 summary_indicator;
+ struct airq_struct airq;
+ struct airq_iv *aiv;
+};
+static struct airq_info *airq_areas[MAX_AIRQ_AREAS];
+
#define CCW_CMD_SET_VQ 0x13
#define CCW_CMD_VDEV_RESET 0x33
#define CCW_CMD_SET_IND 0x43
@@ -91,6 +119,7 @@ struct virtio_ccw_vq_info {
#define CCW_CMD_WRITE_CONF 0x21
#define CCW_CMD_WRITE_STATUS 0x31
#define CCW_CMD_READ_VQ_CONF 0x32
+#define CCW_CMD_SET_IND_ADAPTER 0x73
#define VIRTIO_CCW_DOING_SET_VQ 0x00010000
#define VIRTIO_CCW_DOING_RESET 0x00040000
@@ -102,6 +131,7 @@ struct virtio_ccw_vq_info {
#define VIRTIO_CCW_DOING_SET_IND 0x01000000
#define VIRTIO_CCW_DOING_READ_VQ_CONF 0x02000000
#define VIRTIO_CCW_DOING_SET_CONF_IND 0x04000000
+#define VIRTIO_CCW_DOING_SET_IND_ADAPTER 0x08000000
#define VIRTIO_CCW_INTPARM_MASK 0xffff0000
static struct virtio_ccw_device *to_vc_device(struct virtio_device *vdev)
@@ -109,6 +139,125 @@ static struct virtio_ccw_device *to_vc_device(struct virtio_device *vdev)
return container_of(vdev, struct virtio_ccw_device, vdev);
}
+static void drop_airq_indicator(struct virtqueue *vq, struct airq_info *info)
+{
+ unsigned long i, flags;
+
+ write_lock_irqsave(&info->lock, flags);
+ for (i = 0; i < airq_iv_end(info->aiv); i++) {
+ if (vq == (void *)airq_iv_get_ptr(info->aiv, i)) {
+ airq_iv_free_bit(info->aiv, i);
+ airq_iv_set_ptr(info->aiv, i, 0);
+ break;
+ }
+ }
+ write_unlock_irqrestore(&info->lock, flags);
+}
+
+static void virtio_airq_handler(struct airq_struct *airq)
+{
+ struct airq_info *info = container_of(airq, struct airq_info, airq);
+ unsigned long ai;
+
+ inc_irq_stat(IRQIO_VAI);
+ read_lock(&info->lock);
+ /* Walk through indicators field, summary indicator active. */
+ for (ai = 0;;) {
+ ai = airq_iv_scan(info->aiv, ai, airq_iv_end(info->aiv));
+ if (ai == -1UL)
+ break;
+ vring_interrupt(0, (void *)airq_iv_get_ptr(info->aiv, ai));
+ }
+ info->summary_indicator = 0;
+ smp_wmb();
+ /* Walk through indicators field, summary indicator not active. */
+ for (ai = 0;;) {
+ ai = airq_iv_scan(info->aiv, ai, airq_iv_end(info->aiv));
+ if (ai == -1UL)
+ break;
+ vring_interrupt(0, (void *)airq_iv_get_ptr(info->aiv, ai));
+ }
+ read_unlock(&info->lock);
+}
+
+static struct airq_info *new_airq_info(void)
+{
+ struct airq_info *info;
+ int rc;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return NULL;
+ rwlock_init(&info->lock);
+ info->aiv = airq_iv_create(VIRTIO_IV_BITS, AIRQ_IV_ALLOC | AIRQ_IV_PTR);
+ if (!info->aiv) {
+ kfree(info);
+ return NULL;
+ }
+ info->airq.handler = virtio_airq_handler;
+ info->airq.lsi_ptr = &info->summary_indicator;
+ info->airq.lsi_mask = 0xff;
+ info->airq.isc = VIRTIO_AIRQ_ISC;
+ rc = register_adapter_interrupt(&info->airq);
+ if (rc) {
+ airq_iv_release(info->aiv);
+ kfree(info);
+ return NULL;
+ }
+ return info;
+}
+
+static void destroy_airq_info(struct airq_info *info)
+{
+ if (!info)
+ return;
+
+ unregister_adapter_interrupt(&info->airq);
+ airq_iv_release(info->aiv);
+ kfree(info);
+}
+
+static unsigned long get_airq_indicator(struct virtqueue *vqs[], int nvqs,
+ u64 *first, void **airq_info)
+{
+ int i, j;
+ struct airq_info *info;
+ unsigned long indicator_addr = 0;
+ unsigned long bit, flags;
+
+ for (i = 0; i < MAX_AIRQ_AREAS && !indicator_addr; i++) {
+ if (!airq_areas[i])
+ airq_areas[i] = new_airq_info();
+ info = airq_areas[i];
+ if (!info)
+ return 0;
+ write_lock_irqsave(&info->lock, flags);
+ bit = airq_iv_alloc(info->aiv, nvqs);
+ if (bit == -1UL) {
+ /* Not enough vacancies. */
+ write_unlock_irqrestore(&info->lock, flags);
+ continue;
+ }
+ *first = bit;
+ *airq_info = info;
+ indicator_addr = (unsigned long)info->aiv->vector;
+ for (j = 0; j < nvqs; j++) {
+ airq_iv_set_ptr(info->aiv, bit + j,
+ (unsigned long)vqs[j]);
+ }
+ write_unlock_irqrestore(&info->lock, flags);
+ }
+ return indicator_addr;
+}
+
+static void virtio_ccw_drop_indicators(struct virtio_ccw_device *vcdev)
+{
+ struct virtio_ccw_vq_info *info;
+
+ list_for_each_entry(info, &vcdev->virtqueues, node)
+ drop_airq_indicator(info->vq, vcdev->airq_info);
+}
+
static int doing_io(struct virtio_ccw_device *vcdev, __u32 flag)
{
unsigned long flags;
@@ -145,6 +294,51 @@ static int ccw_io_helper(struct virtio_ccw_device *vcdev,
return ret ? ret : vcdev->err;
}
+static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev,
+ struct ccw1 *ccw)
+{
+ int ret;
+ unsigned long *indicatorp = NULL;
+ struct virtio_thinint_area *thinint_area = NULL;
+ struct airq_info *airq_info = vcdev->airq_info;
+
+ if (vcdev->is_thinint) {
+ thinint_area = kzalloc(sizeof(*thinint_area),
+ GFP_DMA | GFP_KERNEL);
+ if (!thinint_area)
+ return;
+ thinint_area->summary_indicator =
+ (unsigned long) &airq_info->summary_indicator;
+ thinint_area->isc = VIRTIO_AIRQ_ISC;
+ ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER;
+ ccw->count = sizeof(*thinint_area);
+ ccw->cda = (__u32)(unsigned long) thinint_area;
+ } else {
+ indicatorp = kmalloc(sizeof(&vcdev->indicators),
+ GFP_DMA | GFP_KERNEL);
+ if (!indicatorp)
+ return;
+ *indicatorp = 0;
+ ccw->cmd_code = CCW_CMD_SET_IND;
+ ccw->count = sizeof(vcdev->indicators);
+ ccw->cda = (__u32)(unsigned long) indicatorp;
+ }
+ /* Deregister indicators from host. */
+ vcdev->indicators = 0;
+ ccw->flags = 0;
+ ret = ccw_io_helper(vcdev, ccw,
+ vcdev->is_thinint ?
+ VIRTIO_CCW_DOING_SET_IND_ADAPTER :
+ VIRTIO_CCW_DOING_SET_IND);
+ if (ret && (ret != -ENODEV))
+ dev_info(&vcdev->cdev->dev,
+ "Failed to deregister indicators (%d)\n", ret);
+ else if (vcdev->is_thinint)
+ virtio_ccw_drop_indicators(vcdev);
+ kfree(indicatorp);
+ kfree(thinint_area);
+}
+
static inline long do_kvm_notify(struct subchannel_id schid,
unsigned long queue_index,
long cookie)
@@ -232,11 +426,13 @@ static void virtio_ccw_del_vqs(struct virtio_device *vdev)
{
struct virtqueue *vq, *n;
struct ccw1 *ccw;
+ struct virtio_ccw_device *vcdev = to_vc_device(vdev);
ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
if (!ccw)
return;
+ virtio_ccw_drop_indicator(vcdev, ccw);
list_for_each_entry_safe(vq, n, &vdev->vqs, list)
virtio_ccw_del_vq(vq, ccw);
@@ -326,6 +522,54 @@ out_err:
return ERR_PTR(err);
}
+static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev,
+ struct virtqueue *vqs[], int nvqs,
+ struct ccw1 *ccw)
+{
+ int ret;
+ struct virtio_thinint_area *thinint_area = NULL;
+ struct airq_info *info;
+
+ thinint_area = kzalloc(sizeof(*thinint_area), GFP_DMA | GFP_KERNEL);
+ if (!thinint_area) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ /* Try to get an indicator. */
+ thinint_area->indicator = get_airq_indicator(vqs, nvqs,
+ &thinint_area->bit_nr,
+ &vcdev->airq_info);
+ if (!thinint_area->indicator) {
+ ret = -ENOSPC;
+ goto out;
+ }
+ info = vcdev->airq_info;
+ thinint_area->summary_indicator =
+ (unsigned long) &info->summary_indicator;
+ thinint_area->isc = VIRTIO_AIRQ_ISC;
+ ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER;
+ ccw->flags = CCW_FLAG_SLI;
+ ccw->count = sizeof(*thinint_area);
+ ccw->cda = (__u32)(unsigned long)thinint_area;
+ ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND_ADAPTER);
+ if (ret) {
+ if (ret == -EOPNOTSUPP) {
+ /*
+ * The host does not support adapter interrupts
+ * for virtio-ccw, stop trying.
+ */
+ virtio_ccw_use_airq = 0;
+ pr_info("Adapter interrupts unsupported on host\n");
+ } else
+ dev_warn(&vcdev->cdev->dev,
+ "enabling adapter interrupts = %d\n", ret);
+ virtio_ccw_drop_indicators(vcdev);
+ }
+out:
+ kfree(thinint_area);
+ return ret;
+}
+
static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[],
vq_callback_t *callbacks[],
@@ -355,15 +599,23 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
if (!indicatorp)
goto out;
*indicatorp = (unsigned long) &vcdev->indicators;
- /* Register queue indicators with host. */
- vcdev->indicators = 0;
- ccw->cmd_code = CCW_CMD_SET_IND;
- ccw->flags = 0;
- ccw->count = sizeof(vcdev->indicators);
- ccw->cda = (__u32)(unsigned long) indicatorp;
- ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND);
- if (ret)
- goto out;
+ if (vcdev->is_thinint) {
+ ret = virtio_ccw_register_adapter_ind(vcdev, vqs, nvqs, ccw);
+ if (ret)
+ /* no error, just fall back to legacy interrupts */
+ vcdev->is_thinint = 0;
+ }
+ if (!vcdev->is_thinint) {
+ /* Register queue indicators with host. */
+ vcdev->indicators = 0;
+ ccw->cmd_code = CCW_CMD_SET_IND;
+ ccw->flags = 0;
+ ccw->count = sizeof(vcdev->indicators);
+ ccw->cda = (__u32)(unsigned long) indicatorp;
+ ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND);
+ if (ret)
+ goto out;
+ }
/* Register indicators2 with host for config changes */
*indicatorp = (unsigned long) &vcdev->indicators2;
vcdev->indicators2 = 0;
@@ -636,6 +888,8 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev,
struct virtqueue *vq;
struct virtio_driver *drv;
+ if (!vcdev)
+ return;
/* Check if it's a notification from the host. */
if ((intparm == 0) &&
(scsw_stctl(&irb->scsw) ==
@@ -663,6 +917,7 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev,
case VIRTIO_CCW_DOING_SET_CONF_IND:
case VIRTIO_CCW_DOING_RESET:
case VIRTIO_CCW_DOING_READ_VQ_CONF:
+ case VIRTIO_CCW_DOING_SET_IND_ADAPTER:
vcdev->curr_io &= ~activity;
wake_up(&vcdev->wait_q);
break;
@@ -734,23 +989,46 @@ static int virtio_ccw_probe(struct ccw_device *cdev)
return 0;
}
+static struct virtio_ccw_device *virtio_grab_drvdata(struct ccw_device *cdev)
+{
+ unsigned long flags;
+ struct virtio_ccw_device *vcdev;
+
+ spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+ vcdev = dev_get_drvdata(&cdev->dev);
+ if (!vcdev || vcdev->going_away) {
+ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+ return NULL;
+ }
+ vcdev->going_away = true;
+ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+ return vcdev;
+}
+
static void virtio_ccw_remove(struct ccw_device *cdev)
{
- struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev);
+ unsigned long flags;
+ struct virtio_ccw_device *vcdev = virtio_grab_drvdata(cdev);
- if (cdev->online) {
+ if (vcdev && cdev->online)
unregister_virtio_device(&vcdev->vdev);
- dev_set_drvdata(&cdev->dev, NULL);
- }
+ spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+ dev_set_drvdata(&cdev->dev, NULL);
+ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
cdev->handler = NULL;
}
static int virtio_ccw_offline(struct ccw_device *cdev)
{
- struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev);
+ unsigned long flags;
+ struct virtio_ccw_device *vcdev = virtio_grab_drvdata(cdev);
- unregister_virtio_device(&vcdev->vdev);
- dev_set_drvdata(&cdev->dev, NULL);
+ if (vcdev) {
+ unregister_virtio_device(&vcdev->vdev);
+ spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+ dev_set_drvdata(&cdev->dev, NULL);
+ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+ }
return 0;
}
@@ -759,6 +1037,7 @@ static int virtio_ccw_online(struct ccw_device *cdev)
{
int ret;
struct virtio_ccw_device *vcdev;
+ unsigned long flags;
vcdev = kzalloc(sizeof(*vcdev), GFP_KERNEL);
if (!vcdev) {
@@ -778,6 +1057,8 @@ static int virtio_ccw_online(struct ccw_device *cdev)
goto out_free;
}
+ vcdev->is_thinint = virtio_ccw_use_airq; /* at least try */
+
vcdev->vdev.dev.parent = &cdev->dev;
vcdev->vdev.dev.release = virtio_ccw_release_dev;
vcdev->vdev.config = &virtio_ccw_config_ops;
@@ -786,7 +1067,9 @@ static int virtio_ccw_online(struct ccw_device *cdev)
INIT_LIST_HEAD(&vcdev->virtqueues);
spin_lock_init(&vcdev->lock);
+ spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
dev_set_drvdata(&cdev->dev, vcdev);
+ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
vcdev->vdev.id.vendor = cdev->id.cu_type;
vcdev->vdev.id.device = cdev->id.cu_model;
ret = register_virtio_device(&vcdev->vdev);
@@ -797,7 +1080,9 @@ static int virtio_ccw_online(struct ccw_device *cdev)
}
return 0;
out_put:
+ spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
dev_set_drvdata(&cdev->dev, NULL);
+ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
put_device(&vcdev->vdev.dev);
return ret;
out_free:
@@ -935,6 +1220,10 @@ module_init(virtio_ccw_init);
static void __exit virtio_ccw_exit(void)
{
+ int i;
+
ccw_driver_unregister(&virtio_ccw_driver);
+ for (i = 0; i < MAX_AIRQ_AREAS; i++)
+ destroy_airq_info(airq_areas[i]);
}
module_exit(virtio_ccw_exit);
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index a0de045eb227..5333b2c018e7 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -854,8 +854,11 @@ static inline int qeth_get_micros(void)
static inline int qeth_get_ip_version(struct sk_buff *skb)
{
- struct ethhdr *ehdr = (struct ethhdr *)skb->data;
- switch (ehdr->h_proto) {
+ __be16 *p = &((struct ethhdr *)skb->data)->h_proto;
+
+ if (*p == ETH_P_8021Q)
+ p += 2;
+ switch (*p) {
case ETH_P_IPV6:
return 6;
case ETH_P_IP:
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index c3a83df07894..22470a3b182f 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -33,8 +33,8 @@ struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS] = {
/* N P A M L V H */
[QETH_DBF_SETUP] = {"qeth_setup",
8, 1, 8, 5, &debug_hex_ascii_view, NULL},
- [QETH_DBF_MSG] = {"qeth_msg",
- 8, 1, 128, 3, &debug_sprintf_view, NULL},
+ [QETH_DBF_MSG] = {"qeth_msg", 8, 1, 11 * sizeof(long), 3,
+ &debug_sprintf_view, NULL},
[QETH_DBF_CTRL] = {"qeth_control",
8, 1, QETH_DBF_CTRL_LEN, 5, &debug_hex_ascii_view, NULL},
};
@@ -1660,7 +1660,6 @@ int qeth_qdio_clear_card(struct qeth_card *card, int use_halt)
QDIO_FLAG_CLEANUP_USING_CLEAR);
if (rc)
QETH_CARD_TEXT_(card, 3, "1err%d", rc);
- qdio_free(CARD_DDEV(card));
atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED);
break;
case QETH_QDIO_CLEANING:
@@ -2605,6 +2604,7 @@ static int qeth_mpc_initialize(struct qeth_card *card)
return 0;
out_qdio:
qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD);
+ qdio_free(CARD_DDEV(card));
return rc;
}
@@ -4610,8 +4610,8 @@ out:
}
EXPORT_SYMBOL_GPL(qeth_query_oat_command);
-int qeth_query_card_info_cb(struct qeth_card *card,
- struct qeth_reply *reply, unsigned long data)
+static int qeth_query_card_info_cb(struct qeth_card *card,
+ struct qeth_reply *reply, unsigned long data)
{
struct qeth_ipa_cmd *cmd;
struct qeth_query_card_info *card_info;
@@ -4906,9 +4906,11 @@ retry:
if (retries < 3)
QETH_DBF_MESSAGE(2, "%s Retrying to do IDX activates.\n",
dev_name(&card->gdev->dev));
+ rc = qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD);
ccw_device_set_offline(CARD_DDEV(card));
ccw_device_set_offline(CARD_WDEV(card));
ccw_device_set_offline(CARD_RDEV(card));
+ qdio_free(CARD_DDEV(card));
rc = ccw_device_set_online(CARD_RDEV(card));
if (rc)
goto retriable;
@@ -4918,7 +4920,6 @@ retry:
rc = ccw_device_set_online(CARD_DDEV(card));
if (rc)
goto retriable;
- rc = qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD);
retriable:
if (rc == -ERESTARTSYS) {
QETH_DBF_TEXT(SETUP, 2, "break1");
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 0710550093ce..8dea3f12ccc1 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -241,7 +241,7 @@ static inline int qeth_l2_get_cast_type(struct qeth_card *card,
}
static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
- struct sk_buff *skb, int ipv, int cast_type)
+ struct sk_buff *skb, int cast_type)
{
struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb);
@@ -762,7 +762,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
goto tx_drop;
elements_needed++;
skb_reset_mac_header(new_skb);
- qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type);
+ qeth_l2_fill_header(card, hdr, new_skb, cast_type);
hdr->hdr.l2.pkt_length = new_skb->len;
memcpy(((char *)hdr) + sizeof(struct qeth_hdr),
skb_mac_header(new_skb), ETH_HLEN);
@@ -775,7 +775,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
hdr = (struct qeth_hdr *)skb_push(new_skb,
sizeof(struct qeth_hdr));
skb_set_mac_header(new_skb, sizeof(struct qeth_hdr));
- qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type);
+ qeth_l2_fill_header(card, hdr, new_skb, cast_type);
}
}
@@ -1091,6 +1091,7 @@ out_remove:
ccw_device_set_offline(CARD_DDEV(card));
ccw_device_set_offline(CARD_WDEV(card));
ccw_device_set_offline(CARD_RDEV(card));
+ qdio_free(CARD_DDEV(card));
if (recover_flag == CARD_STATE_RECOVER)
card->state = CARD_STATE_RECOVER;
else
@@ -1132,6 +1133,7 @@ static int __qeth_l2_set_offline(struct ccwgroup_device *cgdev,
rc = (rc2) ? rc2 : rc3;
if (rc)
QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
+ qdio_free(CARD_DDEV(card));
if (recover_flag == CARD_STATE_UP)
card->state = CARD_STATE_RECOVER;
/* let user_space know that device is offline */
@@ -1194,6 +1196,7 @@ static void qeth_l2_shutdown(struct ccwgroup_device *gdev)
qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
qeth_qdio_clear_card(card, 0);
qeth_clear_qdio_buffers(card);
+ qdio_free(CARD_DDEV(card));
}
static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev)
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 0f430424c3b8..3524d34ff694 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -3447,6 +3447,7 @@ out_remove:
ccw_device_set_offline(CARD_DDEV(card));
ccw_device_set_offline(CARD_WDEV(card));
ccw_device_set_offline(CARD_RDEV(card));
+ qdio_free(CARD_DDEV(card));
if (recover_flag == CARD_STATE_RECOVER)
card->state = CARD_STATE_RECOVER;
else
@@ -3493,6 +3494,7 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev,
rc = (rc2) ? rc2 : rc3;
if (rc)
QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
+ qdio_free(CARD_DDEV(card));
if (recover_flag == CARD_STATE_UP)
card->state = CARD_STATE_RECOVER;
/* let user_space know that device is offline */
@@ -3545,6 +3547,7 @@ static void qeth_l3_shutdown(struct ccwgroup_device *gdev)
qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
qeth_qdio_clear_card(card, 0);
qeth_clear_qdio_buffers(card);
+ qdio_free(CARD_DDEV(card));
}
static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev)
diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c
index 6b4678a7900a..4ccb5d869389 100644
--- a/drivers/sbus/char/jsflash.c
+++ b/drivers/sbus/char/jsflash.c
@@ -507,7 +507,6 @@ static int jsflash_init(void)
}
/* Let us be really paranoid for modifications to probing code. */
- /* extern enum sparc_cpu sparc_cpu_model; */ /* in <asm/system.h> */
if (sparc_cpu_model != sun4m) {
/* We must be on sun4m because we use MMU Bypass ASI. */
return -ENXIO;
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 1e9d6ad9302b..bcd223868227 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -584,7 +584,7 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
NCR5380_setup(instance);
for (trying_irqs = i = 0, mask = 1; i < 16; ++i, mask <<= 1)
- if ((mask & possible) && (request_irq(i, &probe_intr, IRQF_DISABLED, "NCR-probe", NULL) == 0))
+ if ((mask & possible) && (request_irq(i, &probe_intr, 0, "NCR-probe", NULL) == 0))
trying_irqs |= mask;
timeout = jiffies + (250 * HZ / 1000);
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 9323d058706b..eaaf8705a5f4 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -12,7 +12,7 @@
*----------------------------------------------------------------------------*/
#ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 30200
+# define AAC_DRIVER_BUILD 30300
# define AAC_DRIVER_BRANCH "-ms"
#endif
#define MAXIMUM_NUM_CONTAINERS 32
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index dada38aeacc0..5c6a8703f535 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -480,7 +480,7 @@ static int aac_rx_ioremap(struct aac_dev * dev, u32 size)
static int aac_rx_restart_adapter(struct aac_dev *dev, int bled)
{
- u32 var;
+ u32 var = 0;
if (!(dev->supplement_adapter_info.SupportedOptions2 &
AAC_OPTION_MU_RESET) || (bled >= 0) || (bled == -2)) {
@@ -500,13 +500,14 @@ static int aac_rx_restart_adapter(struct aac_dev *dev, int bled)
if (bled && (bled != -ETIMEDOUT))
return -EINVAL;
}
- if (bled || (var == 0x3803000F)) { /* USE_OTHER_METHOD */
+ if (bled && (var == 0x3803000F)) { /* USE_OTHER_METHOD */
rx_writel(dev, MUnit.reserved2, 3);
msleep(5000); /* Delay 5 seconds */
var = 0x00000001;
}
- if (var != 0x00000001)
+ if (bled && (var != 0x00000001))
return -EINVAL;
+ ssleep(5);
if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC)
return -ENODEV;
if (startup_timeout < 300)
@@ -646,7 +647,7 @@ int _aac_rx_init(struct aac_dev *dev)
dev->sync_mode = 0; /* sync. mode not supported */
dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
- IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) {
+ IRQF_SHARED, "aacraid", dev) < 0) {
if (dev->msi)
pci_disable_msi(dev->pdev);
printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c
index 2244f315f33b..e66477c98240 100644
--- a/drivers/scsi/aacraid/sa.c
+++ b/drivers/scsi/aacraid/sa.c
@@ -387,8 +387,7 @@ int aac_sa_init(struct aac_dev *dev)
goto error_irq;
dev->sync_mode = 0; /* sync. mode not supported */
if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
- IRQF_SHARED|IRQF_DISABLED,
- "aacraid", (void *)dev ) < 0) {
+ IRQF_SHARED, "aacraid", (void *)dev) < 0) {
printk(KERN_WARNING "%s%d: Interrupt unavailable.\n",
name, instance);
goto error_iounmap;
diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c
index 7e17107643d4..9c65aed26212 100644
--- a/drivers/scsi/aacraid/src.c
+++ b/drivers/scsi/aacraid/src.c
@@ -647,7 +647,7 @@ int aac_src_init(struct aac_dev *dev)
dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
- IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) {
+ IRQF_SHARED, "aacraid", dev) < 0) {
if (dev->msi)
pci_disable_msi(dev->pdev);
@@ -804,7 +804,7 @@ int aac_srcv_init(struct aac_dev *dev)
goto error_iounmap;
dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
- IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) {
+ IRQF_SHARED, "aacraid", dev) < 0) {
if (dev->msi)
pci_disable_msi(dev->pdev);
printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 3f7b6fee0a74..e86eb6a921fc 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -857,7 +857,7 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
SETPORT(SIMODE0, 0);
SETPORT(SIMODE1, 0);
- if( request_irq(shpnt->irq, swintr, IRQF_DISABLED|IRQF_SHARED, "aha152x", shpnt) ) {
+ if (request_irq(shpnt->irq, swintr, IRQF_SHARED, "aha152x", shpnt)) {
printk(KERN_ERR "aha152x%d: irq %d busy.\n", shpnt->host_no, shpnt->irq);
goto out_host_put;
}
@@ -891,7 +891,7 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
SETPORT(SSTAT0, 0x7f);
SETPORT(SSTAT1, 0xef);
- if ( request_irq(shpnt->irq, intr, IRQF_DISABLED|IRQF_SHARED, "aha152x", shpnt) ) {
+ if (request_irq(shpnt->irq, intr, IRQF_SHARED, "aha152x", shpnt)) {
printk(KERN_ERR "aha152x%d: failed to reassign irq %d.\n", shpnt->host_no, shpnt->irq);
goto out_host_put;
}
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h b/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h
index 9df9e2ce3538..8373447bd7d3 100644
--- a/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h
@@ -209,7 +209,6 @@ struct instruction {
#define AIC_OP_JC16 0x9105
#define AIC_OP_JNC16 0x9205
#define AIC_OP_CALL16 0x9305
-#define AIC_OP_CALL16 0x9305
/* Page extension is low three bits of second opcode byte. */
#define AIC_OP_JMPF 0xA005
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 4f6a30b8e5f9..652b41b4ddbd 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -2500,16 +2500,15 @@ static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
{
uint32_t cdb_phyaddr, cdb_phyaddr_hi32;
- dma_addr_t dma_coherent_handle;
+
/*
********************************************************************
** here we need to tell iop 331 our freeccb.HighPart
** if freeccb.HighPart is not zero
********************************************************************
*/
- dma_coherent_handle = acb->dma_coherent_handle;
- cdb_phyaddr = (uint32_t)(dma_coherent_handle);
- cdb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16);
+ cdb_phyaddr = lower_32_bits(acb->dma_coherent_handle);
+ cdb_phyaddr_hi32 = upper_32_bits(acb->dma_coherent_handle);
acb->cdb_phyaddr_hi32 = cdb_phyaddr_hi32;
/*
***********************************************************************
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
index 09ba1869d366..059ff477a398 100644
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -2971,7 +2971,7 @@ static int acornscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
ec->irqaddr = ashost->fast + INT_REG;
ec->irqmask = 0x0a;
- ret = request_irq(host->irq, acornscsi_intr, IRQF_DISABLED, "acornscsi", ashost);
+ ret = request_irq(host->irq, acornscsi_intr, 0, "acornscsi", ashost);
if (ret) {
printk(KERN_CRIT "scsi%d: IRQ%d not free: %d\n",
host->host_no, ashost->scsi.irq, ret);
diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
index b679778376c5..f8e060900052 100644
--- a/drivers/scsi/arm/cumana_1.c
+++ b/drivers/scsi/arm/cumana_1.c
@@ -262,7 +262,7 @@ static int cumanascsi1_probe(struct expansion_card *ec,
goto out_unmap;
}
- ret = request_irq(host->irq, cumanascsi_intr, IRQF_DISABLED,
+ ret = request_irq(host->irq, cumanascsi_intr, 0,
"CumanaSCSI-1", host);
if (ret) {
printk("scsi%d: IRQ%d not free: %d\n",
diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c
index 58915f29055b..abc66f5263ec 100644
--- a/drivers/scsi/arm/cumana_2.c
+++ b/drivers/scsi/arm/cumana_2.c
@@ -431,7 +431,7 @@ static int cumanascsi2_probe(struct expansion_card *ec,
goto out_free;
ret = request_irq(ec->irq, cumanascsi_2_intr,
- IRQF_DISABLED, "cumanascsi2", info);
+ 0, "cumanascsi2", info);
if (ret) {
printk("scsi%d: IRQ%d not free: %d\n",
host->host_no, ec->irq, ret);
diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c
index abc9593615e9..5e1b73e1b743 100644
--- a/drivers/scsi/arm/powertec.c
+++ b/drivers/scsi/arm/powertec.c
@@ -358,7 +358,7 @@ static int powertecscsi_probe(struct expansion_card *ec,
goto out_free;
ret = request_irq(ec->irq, powertecscsi_intr,
- IRQF_DISABLED, "powertec", info);
+ 0, "powertec", info);
if (ret) {
printk("scsi%d: IRQ%d not free: %d\n",
host->host_no, ec->irq, ret);
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index a3e6c8a3ff0f..296c936cc03c 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -90,6 +90,7 @@
#include <linux/init.h>
#include <linux/nvram.h>
#include <linux/bitops.h>
+#include <linux/wait.h>
#include <asm/setup.h>
#include <asm/atarihw.h>
@@ -549,8 +550,10 @@ static void falcon_get_lock(void)
local_irq_save(flags);
- while (!in_irq() && falcon_got_lock && stdma_others_waiting())
- sleep_on(&falcon_fairness_wait);
+ wait_event_cmd(falcon_fairness_wait,
+ in_interrupt() || !falcon_got_lock || !stdma_others_waiting(),
+ local_irq_restore(flags),
+ local_irq_save(flags));
while (!falcon_got_lock) {
if (in_irq())
@@ -562,7 +565,10 @@ static void falcon_get_lock(void)
falcon_trying_lock = 0;
wake_up(&falcon_try_wait);
} else {
- sleep_on(&falcon_try_wait);
+ wait_event_cmd(falcon_try_wait,
+ falcon_got_lock && !falcon_trying_lock,
+ local_irq_restore(flags),
+ local_irq_save(flags));
}
}
diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h
index 2e28f6c419fe..1bfb0bd01198 100644
--- a/drivers/scsi/be2iscsi/be.h
+++ b/drivers/scsi/be2iscsi/be.h
@@ -98,6 +98,14 @@ struct be_mcc_obj {
struct be_queue_info cq;
};
+struct beiscsi_mcc_tag_state {
+#define MCC_TAG_STATE_COMPLETED 0x00
+#define MCC_TAG_STATE_RUNNING 0x01
+#define MCC_TAG_STATE_TIMEOUT 0x02
+ uint8_t tag_state;
+ struct be_dma_mem tag_mem_state;
+};
+
struct be_ctrl_info {
u8 __iomem *csr;
u8 __iomem *db; /* Door Bell */
@@ -122,6 +130,8 @@ struct be_ctrl_info {
unsigned short mcc_alloc_index;
unsigned short mcc_free_index;
unsigned int mcc_tag_available;
+
+ struct beiscsi_mcc_tag_state ptag_state[MAX_MCC_CMD + 1];
};
#include "be_cmds.h"
@@ -129,6 +139,7 @@ struct be_ctrl_info {
#define PAGE_SHIFT_4K 12
#define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K)
#define mcc_timeout 120000 /* 12s timeout */
+#define BEISCSI_LOGOUT_SYNC_DELAY 250
/* Returns number of pages spanned by the data starting at the given addr */
#define PAGES_4K_SPANNED(_address, size) \
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c
index 3338391b64de..1432ed5e9fc6 100644
--- a/drivers/scsi/be2iscsi/be_cmds.c
+++ b/drivers/scsi/be2iscsi/be_cmds.c
@@ -138,7 +138,7 @@ unsigned int alloc_mcc_tag(struct beiscsi_hba *phba)
* @phba: Driver private structure
* @tag: Tag for the MBX Command
* @wrb: the WRB used for the MBX Command
- * @cmd_hdr: IOCTL Hdr for the MBX Cmd
+ * @mbx_cmd_mem: ptr to memory allocated for MBX Cmd
*
* Waits for MBX completion with the passed TAG.
*
@@ -148,21 +148,26 @@ unsigned int alloc_mcc_tag(struct beiscsi_hba *phba)
**/
int beiscsi_mccq_compl(struct beiscsi_hba *phba,
uint32_t tag, struct be_mcc_wrb **wrb,
- void *cmd_hdr)
+ struct be_dma_mem *mbx_cmd_mem)
{
int rc = 0;
uint32_t mcc_tag_response;
uint16_t status = 0, addl_status = 0, wrb_num = 0;
struct be_mcc_wrb *temp_wrb;
- struct be_cmd_req_hdr *ioctl_hdr;
- struct be_cmd_resp_hdr *ioctl_resp_hdr;
+ struct be_cmd_req_hdr *mbx_hdr;
+ struct be_cmd_resp_hdr *mbx_resp_hdr;
struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
if (beiscsi_error(phba)) {
free_mcc_tag(&phba->ctrl, tag);
- return -EIO;
+ return -EPERM;
}
+ /* Set MBX Tag state to Active */
+ spin_lock(&phba->ctrl.mbox_lock);
+ phba->ctrl.ptag_state[tag].tag_state = MCC_TAG_STATE_RUNNING;
+ spin_unlock(&phba->ctrl.mbox_lock);
+
/* wait for the mccq completion */
rc = wait_event_interruptible_timeout(
phba->ctrl.mcc_wait[tag],
@@ -171,56 +176,71 @@ int beiscsi_mccq_compl(struct beiscsi_hba *phba,
BEISCSI_HOST_MBX_TIMEOUT));
if (rc <= 0) {
+ struct be_dma_mem *tag_mem;
+ /* Set MBX Tag state to timeout */
+ spin_lock(&phba->ctrl.mbox_lock);
+ phba->ctrl.ptag_state[tag].tag_state = MCC_TAG_STATE_TIMEOUT;
+ spin_unlock(&phba->ctrl.mbox_lock);
+
+ /* Store resource addr to be freed later */
+ tag_mem = &phba->ctrl.ptag_state[tag].tag_mem_state;
+ if (mbx_cmd_mem) {
+ tag_mem->size = mbx_cmd_mem->size;
+ tag_mem->va = mbx_cmd_mem->va;
+ tag_mem->dma = mbx_cmd_mem->dma;
+ } else
+ tag_mem->size = 0;
+
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_INIT | BEISCSI_LOG_EH |
BEISCSI_LOG_CONFIG,
"BC_%d : MBX Cmd Completion timed out\n");
- rc = -EBUSY;
-
- /* decrement the mccq used count */
- atomic_dec(&phba->ctrl.mcc_obj.q.used);
-
- goto release_mcc_tag;
- } else
+ return -EBUSY;
+ } else {
rc = 0;
+ /* Set MBX Tag state to completed */
+ spin_lock(&phba->ctrl.mbox_lock);
+ phba->ctrl.ptag_state[tag].tag_state = MCC_TAG_STATE_COMPLETED;
+ spin_unlock(&phba->ctrl.mbox_lock);
+ }
mcc_tag_response = phba->ctrl.mcc_numtag[tag];
status = (mcc_tag_response & CQE_STATUS_MASK);
addl_status = ((mcc_tag_response & CQE_STATUS_ADDL_MASK) >>
CQE_STATUS_ADDL_SHIFT);
- if (cmd_hdr) {
- ioctl_hdr = (struct be_cmd_req_hdr *)cmd_hdr;
+ if (mbx_cmd_mem) {
+ mbx_hdr = (struct be_cmd_req_hdr *)mbx_cmd_mem->va;
} else {
wrb_num = (mcc_tag_response & CQE_STATUS_WRB_MASK) >>
CQE_STATUS_WRB_SHIFT;
temp_wrb = (struct be_mcc_wrb *)queue_get_wrb(mccq, wrb_num);
- ioctl_hdr = embedded_payload(temp_wrb);
+ mbx_hdr = embedded_payload(temp_wrb);
if (wrb)
*wrb = temp_wrb;
}
if (status || addl_status) {
- beiscsi_log(phba, KERN_ERR,
+ beiscsi_log(phba, KERN_WARNING,
BEISCSI_LOG_INIT | BEISCSI_LOG_EH |
BEISCSI_LOG_CONFIG,
"BC_%d : MBX Cmd Failed for "
"Subsys : %d Opcode : %d with "
"Status : %d and Extd_Status : %d\n",
- ioctl_hdr->subsystem,
- ioctl_hdr->opcode,
+ mbx_hdr->subsystem,
+ mbx_hdr->opcode,
status, addl_status);
if (status == MCC_STATUS_INSUFFICIENT_BUFFER) {
- ioctl_resp_hdr = (struct be_cmd_resp_hdr *) ioctl_hdr;
+ mbx_resp_hdr = (struct be_cmd_resp_hdr *) mbx_hdr;
beiscsi_log(phba, KERN_WARNING,
BEISCSI_LOG_INIT | BEISCSI_LOG_EH |
BEISCSI_LOG_CONFIG,
"BC_%d : Insufficent Buffer Error "
"Resp_Len : %d Actual_Resp_Len : %d\n",
- ioctl_resp_hdr->response_length,
- ioctl_resp_hdr->actual_resp_len);
+ mbx_resp_hdr->response_length,
+ mbx_resp_hdr->actual_resp_len);
rc = -EAGAIN;
goto release_mcc_tag;
@@ -319,6 +339,7 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl,
int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl,
struct be_mcc_compl *compl)
{
+ struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
u16 compl_status, extd_status;
unsigned short tag;
@@ -338,7 +359,32 @@ int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl,
ctrl->mcc_numtag[tag] |= (compl->tag0 & 0x00FF0000);
ctrl->mcc_numtag[tag] |= (extd_status & 0x000000FF) << 8;
ctrl->mcc_numtag[tag] |= (compl_status & 0x000000FF);
- wake_up_interruptible(&ctrl->mcc_wait[tag]);
+
+ if (ctrl->ptag_state[tag].tag_state == MCC_TAG_STATE_RUNNING) {
+ wake_up_interruptible(&ctrl->mcc_wait[tag]);
+ } else if (ctrl->ptag_state[tag].tag_state == MCC_TAG_STATE_TIMEOUT) {
+ struct be_dma_mem *tag_mem;
+ tag_mem = &ctrl->ptag_state[tag].tag_mem_state;
+
+ beiscsi_log(phba, KERN_WARNING,
+ BEISCSI_LOG_MBOX | BEISCSI_LOG_INIT |
+ BEISCSI_LOG_CONFIG,
+ "BC_%d : MBX Completion for timeout Command "
+ "from FW\n");
+ /* Check if memory needs to be freed */
+ if (tag_mem->size)
+ pci_free_consistent(ctrl->pdev, tag_mem->size,
+ tag_mem->va, tag_mem->dma);
+
+ /* Change tag state */
+ spin_lock(&phba->ctrl.mbox_lock);
+ ctrl->ptag_state[tag].tag_state = MCC_TAG_STATE_COMPLETED;
+ spin_unlock(&phba->ctrl.mbox_lock);
+
+ /* Free MCC Tag */
+ free_mcc_tag(ctrl, tag);
+ }
+
return 0;
}
@@ -354,8 +400,23 @@ static struct be_mcc_compl *be_mcc_compl_get(struct beiscsi_hba *phba)
return NULL;
}
-static void be2iscsi_fail_session(struct iscsi_cls_session *cls_session)
+/**
+ * be2iscsi_fail_session(): Closing session with appropriate error
+ * @cls_session: ptr to session
+ *
+ * Depending on adapter state appropriate error flag is passed.
+ **/
+void be2iscsi_fail_session(struct iscsi_cls_session *cls_session)
{
+ struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
+ struct beiscsi_hba *phba = iscsi_host_priv(shost);
+ uint32_t iscsi_err_flag;
+
+ if (phba->state & BE_ADAPTER_STATE_SHUTDOWN)
+ iscsi_err_flag = ISCSI_ERR_INVALID_HOST;
+ else
+ iscsi_err_flag = ISCSI_ERR_CONN_FAILED;
+
iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED);
}
@@ -386,18 +447,6 @@ void beiscsi_async_link_state_process(struct beiscsi_hba *phba,
}
}
-static void beiscsi_cq_notify(struct beiscsi_hba *phba, u16 qid, bool arm,
- u16 num_popped)
-{
- u32 val = 0;
- val |= qid & DB_CQ_RING_ID_MASK;
- if (arm)
- val |= 1 << DB_CQ_REARM_SHIFT;
- val |= num_popped << DB_CQ_NUM_POPPED_SHIFT;
- iowrite32(val, phba->db_va + DB_CQ_OFFSET);
-}
-
-
int beiscsi_process_mcc(struct beiscsi_hba *phba)
{
struct be_mcc_compl *compl;
@@ -428,7 +477,7 @@ int beiscsi_process_mcc(struct beiscsi_hba *phba)
}
if (num)
- beiscsi_cq_notify(phba, phba->ctrl.mcc_obj.cq.id, true, num);
+ hwi_ring_cq_db(phba, phba->ctrl.mcc_obj.cq.id, num, 1, 0);
spin_unlock_bh(&phba->ctrl.mcc_cq_lock);
return status;
diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h
index 627ebbe0172c..7cf7f99ee442 100644
--- a/drivers/scsi/be2iscsi/be_cmds.h
+++ b/drivers/scsi/be2iscsi/be_cmds.h
@@ -103,7 +103,7 @@ struct be_mcc_compl {
/********** MCC door bell ************/
#define DB_MCCQ_OFFSET 0x140
-#define DB_MCCQ_RING_ID_MASK 0x7FF /* bits 0 - 10 */
+#define DB_MCCQ_RING_ID_MASK 0xFFFF /* bits 0 - 15 */
/* Number of entries posted */
#define DB_MCCQ_NUM_POSTED_SHIFT 16 /* bits 16 - 29 */
@@ -709,7 +709,8 @@ unsigned int be_cmd_get_port_speed(struct beiscsi_hba *phba);
void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag);
int beiscsi_mccq_compl(struct beiscsi_hba *phba,
- uint32_t tag, struct be_mcc_wrb **wrb, void *cmd_va);
+ uint32_t tag, struct be_mcc_wrb **wrb,
+ struct be_dma_mem *mbx_cmd_mem);
/*ISCSI Functuions */
int be_cmd_fw_initialize(struct be_ctrl_info *ctrl);
int be_cmd_fw_uninit(struct be_ctrl_info *ctrl);
@@ -1017,8 +1018,8 @@ struct be_mcc_wrb_context {
int *users_final_status;
} __packed;
-#define DB_DEF_PDU_RING_ID_MASK 0x3FF /* bits 0 - 9 */
-#define DB_DEF_PDU_CQPROC_MASK 0x3FFF /* bits 0 - 9 */
+#define DB_DEF_PDU_RING_ID_MASK 0x3FFF /* bits 0 - 13 */
+#define DB_DEF_PDU_CQPROC_MASK 0x3FFF /* bits 16 - 29 */
#define DB_DEF_PDU_REARM_SHIFT 14
#define DB_DEF_PDU_EVENT_SHIFT 15
#define DB_DEF_PDU_CQPROC_SHIFT 16
@@ -1317,4 +1318,5 @@ void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr,
u8 subsystem, u8 opcode, int cmd_len);
+void be2iscsi_fail_session(struct iscsi_cls_session *cls_session);
#endif /* !BEISCSI_CMDS_H */
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index 889066d9d6fb..a3df43324c98 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -793,7 +793,7 @@ static int beiscsi_get_port_speed(struct Scsi_Host *shost)
ihost->port_speed = ISCSI_PORT_SPEED_10MBPS;
break;
case BE2ISCSI_LINK_SPEED_100MBPS:
- ihost->port_speed = BE2ISCSI_LINK_SPEED_100MBPS;
+ ihost->port_speed = ISCSI_PORT_SPEED_100MBPS;
break;
case BE2ISCSI_LINK_SPEED_1GBPS:
ihost->port_speed = ISCSI_PORT_SPEED_1GBPS;
@@ -1153,16 +1153,18 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
return -EAGAIN;
}
- ret = beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd.va);
+ ret = beiscsi_mccq_compl(phba, tag, NULL, &nonemb_cmd);
if (ret) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
"BS_%d : mgmt_open_connection Failed");
- pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
- nonemb_cmd.va, nonemb_cmd.dma);
+ if (ret != -EBUSY)
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
+
beiscsi_free_ep(beiscsi_ep);
- return -EBUSY;
+ return ret;
}
ptcpcnct_out = (struct tcp_connect_and_offload_out *)nonemb_cmd.va;
@@ -1359,6 +1361,7 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
beiscsi_mccq_compl(phba, tag, NULL, NULL);
beiscsi_close_conn(beiscsi_ep, tcp_upload_flag);
free_ep:
+ msleep(BEISCSI_LOGOUT_SYNC_DELAY);
beiscsi_free_ep(beiscsi_ep);
beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid);
iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep);
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 1f375051483a..0d822297aa80 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -228,24 +228,25 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc)
struct invalidate_command_table *inv_tbl;
struct be_dma_mem nonemb_cmd;
unsigned int cid, tag, num_invalidate;
+ int rc;
cls_session = starget_to_session(scsi_target(sc->device));
session = cls_session->dd_data;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (!aborted_task || !aborted_task->sc) {
/* we raced */
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
return SUCCESS;
}
aborted_io_task = aborted_task->dd_data;
if (!aborted_io_task->scsi_cmnd) {
/* raced or invalid command */
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
return SUCCESS;
}
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
/* Invalidate WRB Posted for this Task */
AMAP_SET_BITS(struct amap_iscsi_wrb, invld,
aborted_io_task->pwrb_handle->pwrb,
@@ -285,9 +286,11 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc)
return FAILED;
}
- beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd.va);
- pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
- nonemb_cmd.va, nonemb_cmd.dma);
+ rc = beiscsi_mccq_compl(phba, tag, NULL, &nonemb_cmd);
+ if (rc != -EBUSY)
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
+
return iscsi_eh_abort(sc);
}
@@ -303,13 +306,14 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
struct invalidate_command_table *inv_tbl;
struct be_dma_mem nonemb_cmd;
unsigned int cid, tag, i, num_invalidate;
+ int rc;
/* invalidate iocbs */
cls_session = starget_to_session(scsi_target(sc->device));
session = cls_session->dd_data;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) {
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
return FAILED;
}
conn = session->leadconn;
@@ -325,7 +329,7 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
if (!abrt_task->sc || abrt_task->state == ISCSI_TASK_FREE)
continue;
- if (abrt_task->sc->device->lun != abrt_task->sc->device->lun)
+ if (sc->device->lun != abrt_task->sc->device->lun)
continue;
/* Invalidate WRB Posted for this Task */
@@ -338,7 +342,7 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
num_invalidate++;
inv_tbl++;
}
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
inv_tbl = phba->inv_tbl;
nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
@@ -363,9 +367,10 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
return FAILED;
}
- beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd.va);
- pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
- nonemb_cmd.va, nonemb_cmd.dma);
+ rc = beiscsi_mccq_compl(phba, tag, NULL, &nonemb_cmd);
+ if (rc != -EBUSY)
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
return iscsi_eh_device_reset(sc);
}
@@ -674,8 +679,19 @@ static int beiscsi_enable_pci(struct pci_dev *pcidev)
}
pci_set_master(pcidev);
- if (pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(64))) {
- ret = pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(32));
+ ret = pci_set_dma_mask(pcidev, DMA_BIT_MASK(64));
+ if (ret) {
+ ret = pci_set_dma_mask(pcidev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(&pcidev->dev, "Could not set PCI DMA Mask\n");
+ pci_disable_device(pcidev);
+ return ret;
+ } else {
+ ret = pci_set_consistent_dma_mask(pcidev,
+ DMA_BIT_MASK(32));
+ }
+ } else {
+ ret = pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(64));
if (ret) {
dev_err(&pcidev->dev, "Could not set PCI DMA Mask\n");
pci_disable_device(pcidev);
@@ -804,14 +820,23 @@ static void hwi_ring_eq_db(struct beiscsi_hba *phba,
unsigned char rearm, unsigned char event)
{
u32 val = 0;
- val |= id & DB_EQ_RING_ID_MASK;
+
if (rearm)
val |= 1 << DB_EQ_REARM_SHIFT;
if (clr_interrupt)
val |= 1 << DB_EQ_CLR_SHIFT;
if (event)
val |= 1 << DB_EQ_EVNT_SHIFT;
+
val |= num_processed << DB_EQ_NUM_POPPED_SHIFT;
+ /* Setting lower order EQ_ID Bits */
+ val |= (id & DB_EQ_RING_ID_LOW_MASK);
+
+ /* Setting Higher order EQ_ID Bits */
+ val |= (((id >> DB_EQ_HIGH_FEILD_SHIFT) &
+ DB_EQ_RING_ID_HIGH_MASK)
+ << DB_EQ_HIGH_SET_SHIFT);
+
iowrite32(val, phba->db_va + DB_EQ_OFFSET);
}
@@ -873,7 +898,6 @@ static irqreturn_t be_isr_msix(int irq, void *dev_id)
struct be_queue_info *cq;
unsigned int num_eq_processed;
struct be_eq_obj *pbe_eq;
- unsigned long flags;
pbe_eq = dev_id;
eq = &pbe_eq->q;
@@ -882,31 +906,15 @@ static irqreturn_t be_isr_msix(int irq, void *dev_id)
phba = pbe_eq->phba;
num_eq_processed = 0;
- if (blk_iopoll_enabled) {
- while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
- & EQE_VALID_MASK) {
- if (!blk_iopoll_sched_prep(&pbe_eq->iopoll))
- blk_iopoll_sched(&pbe_eq->iopoll);
-
- AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
- queue_tail_inc(eq);
- eqe = queue_tail_node(eq);
- num_eq_processed++;
- }
- } else {
- while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
- & EQE_VALID_MASK) {
- spin_lock_irqsave(&phba->isr_lock, flags);
- pbe_eq->todo_cq = true;
- spin_unlock_irqrestore(&phba->isr_lock, flags);
- AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
- queue_tail_inc(eq);
- eqe = queue_tail_node(eq);
- num_eq_processed++;
- }
+ while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
+ & EQE_VALID_MASK) {
+ if (!blk_iopoll_sched_prep(&pbe_eq->iopoll))
+ blk_iopoll_sched(&pbe_eq->iopoll);
- if (pbe_eq->todo_cq)
- queue_work(phba->wq, &pbe_eq->work_cqs);
+ AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
+ queue_tail_inc(eq);
+ eqe = queue_tail_node(eq);
+ num_eq_processed++;
}
if (num_eq_processed)
@@ -927,7 +935,6 @@ static irqreturn_t be_isr(int irq, void *dev_id)
struct hwi_context_memory *phwi_context;
struct be_eq_entry *eqe = NULL;
struct be_queue_info *eq;
- struct be_queue_info *cq;
struct be_queue_info *mcc;
unsigned long flags, index;
unsigned int num_mcceq_processed, num_ioeq_processed;
@@ -953,72 +960,40 @@ static irqreturn_t be_isr(int irq, void *dev_id)
num_ioeq_processed = 0;
num_mcceq_processed = 0;
- if (blk_iopoll_enabled) {
- while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
- & EQE_VALID_MASK) {
- if (((eqe->dw[offsetof(struct amap_eq_entry,
- resource_id) / 32] &
- EQE_RESID_MASK) >> 16) == mcc->id) {
- spin_lock_irqsave(&phba->isr_lock, flags);
- pbe_eq->todo_mcc_cq = true;
- spin_unlock_irqrestore(&phba->isr_lock, flags);
- num_mcceq_processed++;
- } else {
- if (!blk_iopoll_sched_prep(&pbe_eq->iopoll))
- blk_iopoll_sched(&pbe_eq->iopoll);
- num_ioeq_processed++;
- }
- AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
- queue_tail_inc(eq);
- eqe = queue_tail_node(eq);
- }
- if (num_ioeq_processed || num_mcceq_processed) {
- if (pbe_eq->todo_mcc_cq)
- queue_work(phba->wq, &pbe_eq->work_cqs);
-
- if ((num_mcceq_processed) && (!num_ioeq_processed))
- hwi_ring_eq_db(phba, eq->id, 0,
- (num_ioeq_processed +
- num_mcceq_processed) , 1, 1);
- else
- hwi_ring_eq_db(phba, eq->id, 0,
- (num_ioeq_processed +
- num_mcceq_processed), 0, 1);
-
- return IRQ_HANDLED;
- } else
- return IRQ_NONE;
- } else {
- cq = &phwi_context->be_cq[0];
- while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
- & EQE_VALID_MASK) {
-
- if (((eqe->dw[offsetof(struct amap_eq_entry,
- resource_id) / 32] &
- EQE_RESID_MASK) >> 16) != cq->id) {
- spin_lock_irqsave(&phba->isr_lock, flags);
- pbe_eq->todo_mcc_cq = true;
- spin_unlock_irqrestore(&phba->isr_lock, flags);
- } else {
- spin_lock_irqsave(&phba->isr_lock, flags);
- pbe_eq->todo_cq = true;
- spin_unlock_irqrestore(&phba->isr_lock, flags);
- }
- AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
- queue_tail_inc(eq);
- eqe = queue_tail_node(eq);
+ while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
+ & EQE_VALID_MASK) {
+ if (((eqe->dw[offsetof(struct amap_eq_entry,
+ resource_id) / 32] &
+ EQE_RESID_MASK) >> 16) == mcc->id) {
+ spin_lock_irqsave(&phba->isr_lock, flags);
+ pbe_eq->todo_mcc_cq = true;
+ spin_unlock_irqrestore(&phba->isr_lock, flags);
+ num_mcceq_processed++;
+ } else {
+ if (!blk_iopoll_sched_prep(&pbe_eq->iopoll))
+ blk_iopoll_sched(&pbe_eq->iopoll);
num_ioeq_processed++;
}
- if (pbe_eq->todo_cq || pbe_eq->todo_mcc_cq)
+ AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
+ queue_tail_inc(eq);
+ eqe = queue_tail_node(eq);
+ }
+ if (num_ioeq_processed || num_mcceq_processed) {
+ if (pbe_eq->todo_mcc_cq)
queue_work(phba->wq, &pbe_eq->work_cqs);
- if (num_ioeq_processed) {
+ if ((num_mcceq_processed) && (!num_ioeq_processed))
hwi_ring_eq_db(phba, eq->id, 0,
- num_ioeq_processed, 1, 1);
- return IRQ_HANDLED;
- } else
- return IRQ_NONE;
- }
+ (num_ioeq_processed +
+ num_mcceq_processed) , 1, 1);
+ else
+ hwi_ring_eq_db(phba, eq->id, 0,
+ (num_ioeq_processed +
+ num_mcceq_processed), 0, 1);
+
+ return IRQ_HANDLED;
+ } else
+ return IRQ_NONE;
}
static int beiscsi_init_irqs(struct beiscsi_hba *phba)
@@ -1093,15 +1068,25 @@ free_msix_irqs:
return ret;
}
-static void hwi_ring_cq_db(struct beiscsi_hba *phba,
+void hwi_ring_cq_db(struct beiscsi_hba *phba,
unsigned int id, unsigned int num_processed,
unsigned char rearm, unsigned char event)
{
u32 val = 0;
- val |= id & DB_CQ_RING_ID_MASK;
+
if (rearm)
val |= 1 << DB_CQ_REARM_SHIFT;
+
val |= num_processed << DB_CQ_NUM_POPPED_SHIFT;
+
+ /* Setting lower order CQ_ID Bits */
+ val |= (id & DB_CQ_RING_ID_LOW_MASK);
+
+ /* Setting Higher order CQ_ID Bits */
+ val |= (((id >> DB_CQ_HIGH_FEILD_SHIFT) &
+ DB_CQ_RING_ID_HIGH_MASK)
+ << DB_CQ_HIGH_SET_SHIFT);
+
iowrite32(val, phba->db_va + DB_CQ_OFFSET);
}
@@ -1150,9 +1135,9 @@ beiscsi_process_async_pdu(struct beiscsi_conn *beiscsi_conn,
return 1;
}
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->back_lock);
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)ppdu, pbuffer, buf_len);
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->back_lock);
return 0;
}
@@ -1342,8 +1327,10 @@ be_complete_io(struct beiscsi_conn *beiscsi_conn,
resid = csol_cqe->res_cnt;
if (!task->sc) {
- if (io_task->scsi_cmnd)
+ if (io_task->scsi_cmnd) {
scsi_dma_unmap(io_task->scsi_cmnd);
+ io_task->scsi_cmnd = NULL;
+ }
return;
}
@@ -1380,6 +1367,7 @@ be_complete_io(struct beiscsi_conn *beiscsi_conn,
conn->rxdata_octets += resid;
unmap:
scsi_dma_unmap(io_task->scsi_cmnd);
+ io_task->scsi_cmnd = NULL;
iscsi_complete_scsi_task(task, exp_cmdsn, max_cmdsn);
}
@@ -1568,7 +1556,7 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
pwrb = pwrb_handle->pwrb;
type = ((struct beiscsi_io_task *)task->dd_data)->wrb_type;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->back_lock);
switch (type) {
case HWH_TYPE_IO:
case HWH_TYPE_IO_RD:
@@ -1607,7 +1595,7 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
break;
}
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->back_lock);
}
static struct list_head *hwi_get_async_busy_list(struct hwi_async_pdu_context
@@ -4360,12 +4348,16 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba)
goto boot_freemem;
}
- ret = beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd.va);
+ ret = beiscsi_mccq_compl(phba, tag, NULL, &nonemb_cmd);
if (ret) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
"BM_%d : beiscsi_get_session_info Failed");
- goto boot_freemem;
+
+ if (ret != -EBUSY)
+ goto boot_freemem;
+ else
+ return ret;
}
session_resp = nonemb_cmd.va ;
@@ -4625,6 +4617,11 @@ static void beiscsi_cleanup_task(struct iscsi_task *task)
spin_unlock(&phba->io_sgl_lock);
io_task->psgl_handle = NULL;
}
+
+ if (io_task->scsi_cmnd) {
+ scsi_dma_unmap(io_task->scsi_cmnd);
+ io_task->scsi_cmnd = NULL;
+ }
} else {
if (!beiscsi_conn->login_in_progress)
beiscsi_free_mgmt_task_handles(beiscsi_conn, task);
@@ -4646,9 +4643,9 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
* login/startup related tasks.
*/
beiscsi_conn->login_in_progress = 0;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->back_lock);
beiscsi_cleanup_task(task);
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->back_lock);
pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid);
@@ -5216,11 +5213,10 @@ static void beiscsi_quiesce(struct beiscsi_hba *phba,
}
pci_disable_msix(phba->pcidev);
- if (blk_iopoll_enabled)
- for (i = 0; i < phba->num_cpus; i++) {
- pbe_eq = &phwi_context->be_eq[i];
- blk_iopoll_disable(&pbe_eq->iopoll);
- }
+ for (i = 0; i < phba->num_cpus; i++) {
+ pbe_eq = &phwi_context->be_eq[i];
+ blk_iopoll_disable(&pbe_eq->iopoll);
+ }
if (unload_state == BEISCSI_CLEAN_UNLOAD) {
destroy_workqueue(phba->wq);
@@ -5273,6 +5269,8 @@ static void beiscsi_shutdown(struct pci_dev *pcidev)
return;
}
+ phba->state = BE_ADAPTER_STATE_SHUTDOWN;
+ iscsi_host_for_each_session(phba->shost, be2iscsi_fail_session);
beiscsi_quiesce(phba, BEISCSI_CLEAN_UNLOAD);
pci_disable_device(pcidev);
}
@@ -5429,32 +5427,18 @@ static void beiscsi_eeh_resume(struct pci_dev *pdev)
phwi_ctrlr = phba->phwi_ctrlr;
phwi_context = phwi_ctrlr->phwi_ctxt;
- if (blk_iopoll_enabled) {
- for (i = 0; i < phba->num_cpus; i++) {
- pbe_eq = &phwi_context->be_eq[i];
- blk_iopoll_init(&pbe_eq->iopoll, be_iopoll_budget,
- be_iopoll);
- blk_iopoll_enable(&pbe_eq->iopoll);
- }
-
- i = (phba->msix_enabled) ? i : 0;
- /* Work item for MCC handling */
+ for (i = 0; i < phba->num_cpus; i++) {
pbe_eq = &phwi_context->be_eq[i];
- INIT_WORK(&pbe_eq->work_cqs, beiscsi_process_all_cqs);
- } else {
- if (phba->msix_enabled) {
- for (i = 0; i <= phba->num_cpus; i++) {
- pbe_eq = &phwi_context->be_eq[i];
- INIT_WORK(&pbe_eq->work_cqs,
- beiscsi_process_all_cqs);
- }
- } else {
- pbe_eq = &phwi_context->be_eq[0];
- INIT_WORK(&pbe_eq->work_cqs,
- beiscsi_process_all_cqs);
- }
+ blk_iopoll_init(&pbe_eq->iopoll, be_iopoll_budget,
+ be_iopoll);
+ blk_iopoll_enable(&pbe_eq->iopoll);
}
+ i = (phba->msix_enabled) ? i : 0;
+ /* Work item for MCC handling */
+ pbe_eq = &phwi_context->be_eq[i];
+ INIT_WORK(&pbe_eq->work_cqs, beiscsi_process_all_cqs);
+
ret = beiscsi_init_irqs(phba);
if (ret < 0) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
@@ -5594,6 +5578,8 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
phba->ctrl.mcc_tag[i] = i + 1;
phba->ctrl.mcc_numtag[i + 1] = 0;
phba->ctrl.mcc_tag_available++;
+ memset(&phba->ctrl.ptag_state[i].tag_mem_state, 0,
+ sizeof(struct beiscsi_mcc_tag_state));
}
phba->ctrl.mcc_alloc_index = phba->ctrl.mcc_free_index = 0;
@@ -5614,32 +5600,18 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
phwi_ctrlr = phba->phwi_ctrlr;
phwi_context = phwi_ctrlr->phwi_ctxt;
- if (blk_iopoll_enabled) {
- for (i = 0; i < phba->num_cpus; i++) {
- pbe_eq = &phwi_context->be_eq[i];
- blk_iopoll_init(&pbe_eq->iopoll, be_iopoll_budget,
- be_iopoll);
- blk_iopoll_enable(&pbe_eq->iopoll);
- }
-
- i = (phba->msix_enabled) ? i : 0;
- /* Work item for MCC handling */
+ for (i = 0; i < phba->num_cpus; i++) {
pbe_eq = &phwi_context->be_eq[i];
- INIT_WORK(&pbe_eq->work_cqs, beiscsi_process_all_cqs);
- } else {
- if (phba->msix_enabled) {
- for (i = 0; i <= phba->num_cpus; i++) {
- pbe_eq = &phwi_context->be_eq[i];
- INIT_WORK(&pbe_eq->work_cqs,
- beiscsi_process_all_cqs);
- }
- } else {
- pbe_eq = &phwi_context->be_eq[0];
- INIT_WORK(&pbe_eq->work_cqs,
- beiscsi_process_all_cqs);
- }
+ blk_iopoll_init(&pbe_eq->iopoll, be_iopoll_budget,
+ be_iopoll);
+ blk_iopoll_enable(&pbe_eq->iopoll);
}
+ i = (phba->msix_enabled) ? i : 0;
+ /* Work item for MCC handling */
+ pbe_eq = &phwi_context->be_eq[i];
+ INIT_WORK(&pbe_eq->work_cqs, beiscsi_process_all_cqs);
+
ret = beiscsi_init_irqs(phba);
if (ret < 0) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
@@ -5668,11 +5640,10 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
free_blkenbld:
destroy_workqueue(phba->wq);
- if (blk_iopoll_enabled)
- for (i = 0; i < phba->num_cpus; i++) {
- pbe_eq = &phwi_context->be_eq[i];
- blk_iopoll_disable(&pbe_eq->iopoll);
- }
+ for (i = 0; i < phba->num_cpus; i++) {
+ pbe_eq = &phwi_context->be_eq[i];
+ blk_iopoll_disable(&pbe_eq->iopoll);
+ }
free_twq:
beiscsi_clean_port(phba);
beiscsi_free_mem(phba);
diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h
index 31fa27b4a9b2..9380b55bdeaf 100644
--- a/drivers/scsi/be2iscsi/be_main.h
+++ b/drivers/scsi/be2iscsi/be_main.h
@@ -36,7 +36,7 @@
#include <scsi/scsi_transport_iscsi.h>
#define DRV_NAME "be2iscsi"
-#define BUILD_STR "10.0.659.0"
+#define BUILD_STR "10.2.125.0"
#define BE_NAME "Emulex OneConnect" \
"Open-iSCSI Driver version" BUILD_STR
#define DRV_DESC BE_NAME " " "Driver"
@@ -97,9 +97,14 @@
#define INVALID_SESS_HANDLE 0xFFFFFFFF
+/**
+ * Adapter States
+ **/
#define BE_ADAPTER_LINK_UP 0x001
#define BE_ADAPTER_LINK_DOWN 0x002
#define BE_ADAPTER_PCI_ERR 0x004
+#define BE_ADAPTER_STATE_SHUTDOWN 0x008
+
#define BEISCSI_CLEAN_UNLOAD 0x01
#define BEISCSI_EEH_UNLOAD 0x02
@@ -135,11 +140,15 @@
#define DB_RXULP0_OFFSET 0xA0
/********* Event Q door bell *************/
#define DB_EQ_OFFSET DB_CQ_OFFSET
-#define DB_EQ_RING_ID_MASK 0x1FF /* bits 0 - 8 */
+#define DB_EQ_RING_ID_LOW_MASK 0x1FF /* bits 0 - 8 */
/* Clear the interrupt for this eq */
#define DB_EQ_CLR_SHIFT (9) /* bit 9 */
/* Must be 1 */
#define DB_EQ_EVNT_SHIFT (10) /* bit 10 */
+/* Higher Order EQ_ID bit */
+#define DB_EQ_RING_ID_HIGH_MASK 0x1F /* bits 11 - 15 */
+#define DB_EQ_HIGH_SET_SHIFT 11
+#define DB_EQ_HIGH_FEILD_SHIFT 9
/* Number of event entries processed */
#define DB_EQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */
/* Rearm bit */
@@ -147,7 +156,12 @@
/********* Compl Q door bell *************/
#define DB_CQ_OFFSET 0x120
-#define DB_CQ_RING_ID_MASK 0x3FF /* bits 0 - 9 */
+#define DB_CQ_RING_ID_LOW_MASK 0x3FF /* bits 0 - 9 */
+/* Higher Order CQ_ID bit */
+#define DB_CQ_RING_ID_HIGH_MASK 0x1F /* bits 11 - 15 */
+#define DB_CQ_HIGH_SET_SHIFT 11
+#define DB_CQ_HIGH_FEILD_SHIFT 10
+
/* Number of event entries processed */
#define DB_CQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */
/* Rearm bit */
@@ -821,6 +835,9 @@ void beiscsi_process_all_cqs(struct work_struct *work);
void beiscsi_free_mgmt_task_handles(struct beiscsi_conn *beiscsi_conn,
struct iscsi_task *task);
+void hwi_ring_cq_db(struct beiscsi_hba *phba,
+ unsigned int id, unsigned int num_processed,
+ unsigned char rearm, unsigned char event);
static inline bool beiscsi_error(struct beiscsi_hba *phba)
{
return phba->ue_detected || phba->fw_timeout;
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c
index b2fcac78feaa..088bdf752cfa 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.c
+++ b/drivers/scsi/be2iscsi/be_mgmt.c
@@ -828,22 +828,25 @@ static int mgmt_exec_nonemb_cmd(struct beiscsi_hba *phba,
be_mcc_notify(phba);
spin_unlock(&ctrl->mbox_lock);
- rc = beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd->va);
+ rc = beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd);
+
+ if (resp_buf)
+ memcpy(resp_buf, nonemb_cmd->va, resp_buf_len);
+
if (rc) {
- /* Check if the IOCTL needs to be re-issued */
+ /* Check if the MBX Cmd needs to be re-issued */
if (rc == -EAGAIN)
return rc;
- beiscsi_log(phba, KERN_ERR,
+ beiscsi_log(phba, KERN_WARNING,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
"BG_%d : mgmt_exec_nonemb_cmd Failed status\n");
- goto free_cmd;
+ if (rc != -EBUSY)
+ goto free_cmd;
+ else
+ return rc;
}
-
- if (resp_buf)
- memcpy(resp_buf, nonemb_cmd->va, resp_buf_len);
-
free_cmd:
pci_free_consistent(ctrl->pdev, nonemb_cmd->size,
nonemb_cmd->va, nonemb_cmd->dma);
@@ -1348,7 +1351,6 @@ int mgmt_set_vlan(struct beiscsi_hba *phba,
{
int rc;
unsigned int tag;
- struct be_mcc_wrb *wrb = NULL;
tag = be_cmd_set_vlan(phba, vlan_tag);
if (!tag) {
@@ -1358,7 +1360,7 @@ int mgmt_set_vlan(struct beiscsi_hba *phba,
return -EBUSY;
}
- rc = beiscsi_mccq_compl(phba, tag, &wrb, NULL);
+ rc = beiscsi_mccq_compl(phba, tag, NULL, NULL);
if (rc) {
beiscsi_log(phba, KERN_ERR,
(BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX),
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c
index 65180e15de6e..315d6d6dcfc8 100644
--- a/drivers/scsi/bfa/bfa_ioc.c
+++ b/drivers/scsi/bfa/bfa_ioc.c
@@ -3878,7 +3878,7 @@ bfa_sfp_show_comp(struct bfa_sfp_s *sfp, struct bfi_mbmsg_s *msg)
bfa_trc(sfp, sfp->data_valid);
if (sfp->data_valid) {
u32 size = sizeof(struct sfp_mem_s);
- u8 *des = (u8 *) &(sfp->sfpmem->srlid_base);
+ u8 *des = (u8 *) &(sfp->sfpmem);
memcpy(des, sfp->dbuf_kva, size);
}
/*
@@ -6851,7 +6851,7 @@ static u32
bfa_flash_status_read(void __iomem *pci_bar)
{
union bfa_flash_dev_status_reg_u dev_status;
- u32 status;
+ int status;
u32 ret_status;
int i;
@@ -6899,7 +6899,7 @@ static u32
bfa_flash_read_start(void __iomem *pci_bar, u32 offset, u32 len,
char *buf)
{
- u32 status;
+ int status;
/*
* len must be mutiple of 4 and not exceeding fifo size
@@ -7006,7 +7006,7 @@ bfa_flash_sem_get(void __iomem *bar)
while (!bfa_raw_sem_get(bar)) {
if (--n <= 0)
return BFA_STATUS_BADFLASH;
- udelay(10000);
+ mdelay(10);
}
return BFA_STATUS_OK;
}
@@ -7021,7 +7021,8 @@ bfa_status_t
bfa_flash_raw_read(void __iomem *pci_bar, u32 offset, char *buf,
u32 len)
{
- u32 n, status;
+ u32 n;
+ int status;
u32 off, l, s, residue, fifo_sz;
residue = len;
diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c
index 157f6044a9bb..8994fb857ee9 100644
--- a/drivers/scsi/bfa/bfad_bsg.c
+++ b/drivers/scsi/bfa/bfad_bsg.c
@@ -2304,8 +2304,10 @@ bfad_iocmd_cfg_trunk(struct bfad_s *bfad, void *cmd, unsigned int v_cmd)
spin_lock_irqsave(&bfad->bfad_lock, flags);
- if (bfa_fcport_is_dport(&bfad->bfa))
+ if (bfa_fcport_is_dport(&bfad->bfa)) {
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
return BFA_STATUS_DPORT_ERR;
+ }
if ((fcport->cfg.topology == BFA_PORT_TOPOLOGY_LOOP) ||
(fcport->topology == BFA_PORT_TOPOLOGY_LOOP))
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c
index 9967f9c14851..f067332bf763 100644
--- a/drivers/scsi/bfa/bfad_im.c
+++ b/drivers/scsi/bfa/bfad_im.c
@@ -73,9 +73,14 @@ bfa_cb_ioim_done(void *drv, struct bfad_ioim_s *dio,
break;
- case BFI_IOIM_STS_ABORTED:
case BFI_IOIM_STS_TIMEDOUT:
+ host_status = DID_TIME_OUT;
+ cmnd->result = ScsiResult(host_status, 0);
+ break;
case BFI_IOIM_STS_PATHTOV:
+ host_status = DID_TRANSPORT_DISRUPTED;
+ cmnd->result = ScsiResult(host_status, 0);
+ break;
default:
host_status = DID_ERROR;
cmnd->result = ScsiResult(host_status, 0);
diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h
index 1ebf3fb683e6..6a976657b475 100644
--- a/drivers/scsi/bnx2fc/bnx2fc.h
+++ b/drivers/scsi/bnx2fc/bnx2fc.h
@@ -64,7 +64,7 @@
#include "bnx2fc_constants.h"
#define BNX2FC_NAME "bnx2fc"
-#define BNX2FC_VERSION "2.4.1"
+#define BNX2FC_VERSION "2.4.2"
#define PFX "bnx2fc: "
@@ -367,6 +367,7 @@ struct bnx2fc_rport {
atomic_t num_active_ios;
u32 flush_in_prog;
unsigned long timestamp;
+ unsigned long retry_delay_timestamp;
struct list_head free_task_list;
struct bnx2fc_cmd *pending_queue[BNX2FC_SQ_WQES_MAX+1];
struct list_head active_cmd_queue;
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index 9b948505d118..6287f6a8b79d 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -22,7 +22,7 @@ DEFINE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu);
#define DRV_MODULE_NAME "bnx2fc"
#define DRV_MODULE_VERSION BNX2FC_VERSION
-#define DRV_MODULE_RELDATE "Sep 17, 2013"
+#define DRV_MODULE_RELDATE "Dec 11, 2013"
static char version[] =
@@ -850,6 +850,9 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event,
__bnx2fc_destroy(interface);
}
mutex_unlock(&bnx2fc_dev_lock);
+
+ /* Ensure ALL destroy work has been completed before return */
+ flush_workqueue(bnx2fc_wq);
return;
default:
@@ -2389,6 +2392,9 @@ static void bnx2fc_ulp_exit(struct cnic_dev *dev)
__bnx2fc_destroy(interface);
mutex_unlock(&bnx2fc_dev_lock);
+ /* Ensure ALL destroy work has been completed before return */
+ flush_workqueue(bnx2fc_wq);
+
bnx2fc_ulp_stop(hba);
/* unregister cnic device */
if (test_and_clear_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic))
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c
index ed880891cb7c..32a5e0a2a669 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_io.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -594,13 +594,13 @@ static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req)
mp_req->mp_resp_bd = NULL;
}
if (mp_req->req_buf) {
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
mp_req->req_buf,
mp_req->req_buf_dma);
mp_req->req_buf = NULL;
}
if (mp_req->resp_buf) {
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
mp_req->resp_buf,
mp_req->resp_buf_dma);
mp_req->resp_buf = NULL;
@@ -622,7 +622,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
mp_req->req_len = sizeof(struct fcp_cmnd);
io_req->data_xfer_len = mp_req->req_len;
- mp_req->req_buf = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ mp_req->req_buf = dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
&mp_req->req_buf_dma,
GFP_ATOMIC);
if (!mp_req->req_buf) {
@@ -631,7 +631,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
return FAILED;
}
- mp_req->resp_buf = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ mp_req->resp_buf = dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
&mp_req->resp_buf_dma,
GFP_ATOMIC);
if (!mp_req->resp_buf) {
@@ -639,8 +639,8 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
bnx2fc_free_mp_resc(io_req);
return FAILED;
}
- memset(mp_req->req_buf, 0, PAGE_SIZE);
- memset(mp_req->resp_buf, 0, PAGE_SIZE);
+ memset(mp_req->req_buf, 0, CNIC_PAGE_SIZE);
+ memset(mp_req->resp_buf, 0, CNIC_PAGE_SIZE);
/* Allocate and map mp_req_bd and mp_resp_bd */
sz = sizeof(struct fcoe_bd_ctx);
@@ -665,7 +665,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
mp_req_bd = mp_req->mp_req_bd;
mp_req_bd->buf_addr_lo = (u32)addr & 0xffffffff;
mp_req_bd->buf_addr_hi = (u32)((u64)addr >> 32);
- mp_req_bd->buf_len = PAGE_SIZE;
+ mp_req_bd->buf_len = CNIC_PAGE_SIZE;
mp_req_bd->flags = 0;
/*
@@ -677,7 +677,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
addr = mp_req->resp_buf_dma;
mp_resp_bd->buf_addr_lo = (u32)addr & 0xffffffff;
mp_resp_bd->buf_addr_hi = (u32)((u64)addr >> 32);
- mp_resp_bd->buf_len = PAGE_SIZE;
+ mp_resp_bd->buf_len = CNIC_PAGE_SIZE;
mp_resp_bd->flags = 0;
return SUCCESS;
@@ -1871,7 +1871,15 @@ int bnx2fc_queuecommand(struct Scsi_Host *host,
rc = SCSI_MLQUEUE_TARGET_BUSY;
goto exit_qcmd;
}
-
+ if (tgt->retry_delay_timestamp) {
+ if (time_after(jiffies, tgt->retry_delay_timestamp)) {
+ tgt->retry_delay_timestamp = 0;
+ } else {
+ /* If retry_delay timer is active, flow off the ML */
+ rc = SCSI_MLQUEUE_TARGET_BUSY;
+ goto exit_qcmd;
+ }
+ }
io_req = bnx2fc_cmd_alloc(tgt);
if (!io_req) {
rc = SCSI_MLQUEUE_HOST_BUSY;
@@ -1961,6 +1969,15 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
" fcp_resid = 0x%x\n",
io_req->cdb_status, io_req->fcp_resid);
sc_cmd->result = (DID_OK << 16) | io_req->cdb_status;
+
+ if (io_req->cdb_status == SAM_STAT_TASK_SET_FULL ||
+ io_req->cdb_status == SAM_STAT_BUSY) {
+ /* Set the jiffies + retry_delay_timer * 100ms
+ for the rport/tgt */
+ tgt->retry_delay_timestamp = jiffies +
+ fcp_rsp->retry_delay_timer * HZ / 10;
+ }
+
}
if (io_req->fcp_resid)
scsi_set_resid(sc_cmd, io_req->fcp_resid);
diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
index 4d93177dfb53..6870cf6781d9 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
@@ -386,6 +386,7 @@ static int bnx2fc_init_tgt(struct bnx2fc_rport *tgt,
tgt->rq_prod_idx = 0x8000;
tgt->rq_cons_idx = 0;
atomic_set(&tgt->num_active_ios, 0);
+ tgt->retry_delay_timestamp = 0;
if (rdata->flags & FC_RP_FLAGS_RETRY &&
rdata->ids.roles & FC_RPORT_ROLE_FCP_TARGET &&
@@ -673,7 +674,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
/* Allocate and map SQ */
tgt->sq_mem_size = tgt->max_sqes * BNX2FC_SQ_WQE_SIZE;
- tgt->sq_mem_size = (tgt->sq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ tgt->sq_mem_size = (tgt->sq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+ CNIC_PAGE_MASK;
tgt->sq = dma_alloc_coherent(&hba->pcidev->dev, tgt->sq_mem_size,
&tgt->sq_dma, GFP_KERNEL);
@@ -686,7 +688,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
/* Allocate and map CQ */
tgt->cq_mem_size = tgt->max_cqes * BNX2FC_CQ_WQE_SIZE;
- tgt->cq_mem_size = (tgt->cq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ tgt->cq_mem_size = (tgt->cq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+ CNIC_PAGE_MASK;
tgt->cq = dma_alloc_coherent(&hba->pcidev->dev, tgt->cq_mem_size,
&tgt->cq_dma, GFP_KERNEL);
@@ -699,7 +702,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
/* Allocate and map RQ and RQ PBL */
tgt->rq_mem_size = tgt->max_rqes * BNX2FC_RQ_WQE_SIZE;
- tgt->rq_mem_size = (tgt->rq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ tgt->rq_mem_size = (tgt->rq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+ CNIC_PAGE_MASK;
tgt->rq = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_mem_size,
&tgt->rq_dma, GFP_KERNEL);
@@ -710,8 +714,9 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
}
memset(tgt->rq, 0, tgt->rq_mem_size);
- tgt->rq_pbl_size = (tgt->rq_mem_size / PAGE_SIZE) * sizeof(void *);
- tgt->rq_pbl_size = (tgt->rq_pbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ tgt->rq_pbl_size = (tgt->rq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
+ tgt->rq_pbl_size = (tgt->rq_pbl_size + (CNIC_PAGE_SIZE - 1)) &
+ CNIC_PAGE_MASK;
tgt->rq_pbl = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_pbl_size,
&tgt->rq_pbl_dma, GFP_KERNEL);
@@ -722,7 +727,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
}
memset(tgt->rq_pbl, 0, tgt->rq_pbl_size);
- num_pages = tgt->rq_mem_size / PAGE_SIZE;
+ num_pages = tgt->rq_mem_size / CNIC_PAGE_SIZE;
page = tgt->rq_dma;
pbl = (u32 *)tgt->rq_pbl;
@@ -731,13 +736,13 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
pbl++;
*pbl = (u32)((u64)page >> 32);
pbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
}
/* Allocate and map XFERQ */
tgt->xferq_mem_size = tgt->max_sqes * BNX2FC_XFERQ_WQE_SIZE;
- tgt->xferq_mem_size = (tgt->xferq_mem_size + (PAGE_SIZE - 1)) &
- PAGE_MASK;
+ tgt->xferq_mem_size = (tgt->xferq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+ CNIC_PAGE_MASK;
tgt->xferq = dma_alloc_coherent(&hba->pcidev->dev, tgt->xferq_mem_size,
&tgt->xferq_dma, GFP_KERNEL);
@@ -750,8 +755,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
/* Allocate and map CONFQ & CONFQ PBL */
tgt->confq_mem_size = tgt->max_sqes * BNX2FC_CONFQ_WQE_SIZE;
- tgt->confq_mem_size = (tgt->confq_mem_size + (PAGE_SIZE - 1)) &
- PAGE_MASK;
+ tgt->confq_mem_size = (tgt->confq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+ CNIC_PAGE_MASK;
tgt->confq = dma_alloc_coherent(&hba->pcidev->dev, tgt->confq_mem_size,
&tgt->confq_dma, GFP_KERNEL);
@@ -763,9 +768,9 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
memset(tgt->confq, 0, tgt->confq_mem_size);
tgt->confq_pbl_size =
- (tgt->confq_mem_size / PAGE_SIZE) * sizeof(void *);
+ (tgt->confq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
tgt->confq_pbl_size =
- (tgt->confq_pbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ (tgt->confq_pbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
tgt->confq_pbl = dma_alloc_coherent(&hba->pcidev->dev,
tgt->confq_pbl_size,
@@ -777,7 +782,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
}
memset(tgt->confq_pbl, 0, tgt->confq_pbl_size);
- num_pages = tgt->confq_mem_size / PAGE_SIZE;
+ num_pages = tgt->confq_mem_size / CNIC_PAGE_SIZE;
page = tgt->confq_dma;
pbl = (u32 *)tgt->confq_pbl;
@@ -786,7 +791,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
pbl++;
*pbl = (u32)((u64)page >> 32);
pbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
}
/* Allocate and map ConnDB */
@@ -805,8 +810,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
/* Allocate and map LCQ */
tgt->lcq_mem_size = (tgt->max_sqes + 8) * BNX2FC_SQ_WQE_SIZE;
- tgt->lcq_mem_size = (tgt->lcq_mem_size + (PAGE_SIZE - 1)) &
- PAGE_MASK;
+ tgt->lcq_mem_size = (tgt->lcq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+ CNIC_PAGE_MASK;
tgt->lcq = dma_alloc_coherent(&hba->pcidev->dev, tgt->lcq_mem_size,
&tgt->lcq_dma, GFP_KERNEL);
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index e4cf23df4b4f..b5ffd280a1ae 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -61,7 +61,7 @@ static void bnx2i_adjust_qp_size(struct bnx2i_hba *hba)
* yield integral num of page buffers
*/
/* adjust SQ */
- num_elements_per_pg = PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
+ num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
if (hba->max_sqes < num_elements_per_pg)
hba->max_sqes = num_elements_per_pg;
else if (hba->max_sqes % num_elements_per_pg)
@@ -69,7 +69,7 @@ static void bnx2i_adjust_qp_size(struct bnx2i_hba *hba)
~(num_elements_per_pg - 1);
/* adjust CQ */
- num_elements_per_pg = PAGE_SIZE / BNX2I_CQE_SIZE;
+ num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_CQE_SIZE;
if (hba->max_cqes < num_elements_per_pg)
hba->max_cqes = num_elements_per_pg;
else if (hba->max_cqes % num_elements_per_pg)
@@ -77,7 +77,7 @@ static void bnx2i_adjust_qp_size(struct bnx2i_hba *hba)
~(num_elements_per_pg - 1);
/* adjust RQ */
- num_elements_per_pg = PAGE_SIZE / BNX2I_RQ_WQE_SIZE;
+ num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_RQ_WQE_SIZE;
if (hba->max_rqes < num_elements_per_pg)
hba->max_rqes = num_elements_per_pg;
else if (hba->max_rqes % num_elements_per_pg)
@@ -959,7 +959,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
/* SQ page table */
memset(ep->qp.sq_pgtbl_virt, 0, ep->qp.sq_pgtbl_size);
- num_pages = ep->qp.sq_mem_size / PAGE_SIZE;
+ num_pages = ep->qp.sq_mem_size / CNIC_PAGE_SIZE;
page = ep->qp.sq_phys;
if (cnic_dev_10g)
@@ -973,7 +973,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
ptbl++;
*ptbl = (u32) ((u64) page >> 32);
ptbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
} else {
/* PTE is written in big endian format for
* 5706/5708/5709 devices */
@@ -981,13 +981,13 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
ptbl++;
*ptbl = (u32) page;
ptbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
}
}
/* RQ page table */
memset(ep->qp.rq_pgtbl_virt, 0, ep->qp.rq_pgtbl_size);
- num_pages = ep->qp.rq_mem_size / PAGE_SIZE;
+ num_pages = ep->qp.rq_mem_size / CNIC_PAGE_SIZE;
page = ep->qp.rq_phys;
if (cnic_dev_10g)
@@ -1001,7 +1001,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
ptbl++;
*ptbl = (u32) ((u64) page >> 32);
ptbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
} else {
/* PTE is written in big endian format for
* 5706/5708/5709 devices */
@@ -1009,13 +1009,13 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
ptbl++;
*ptbl = (u32) page;
ptbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
}
}
/* CQ page table */
memset(ep->qp.cq_pgtbl_virt, 0, ep->qp.cq_pgtbl_size);
- num_pages = ep->qp.cq_mem_size / PAGE_SIZE;
+ num_pages = ep->qp.cq_mem_size / CNIC_PAGE_SIZE;
page = ep->qp.cq_phys;
if (cnic_dev_10g)
@@ -1029,7 +1029,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
ptbl++;
*ptbl = (u32) ((u64) page >> 32);
ptbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
} else {
/* PTE is written in big endian format for
* 5706/5708/5709 devices */
@@ -1037,7 +1037,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
ptbl++;
*ptbl = (u32) page;
ptbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
}
}
}
@@ -1064,11 +1064,11 @@ int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
/* Allocate page table memory for SQ which is page aligned */
ep->qp.sq_mem_size = hba->max_sqes * BNX2I_SQ_WQE_SIZE;
ep->qp.sq_mem_size =
- (ep->qp.sq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ (ep->qp.sq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
ep->qp.sq_pgtbl_size =
- (ep->qp.sq_mem_size / PAGE_SIZE) * sizeof(void *);
+ (ep->qp.sq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
ep->qp.sq_pgtbl_size =
- (ep->qp.sq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ (ep->qp.sq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
ep->qp.sq_pgtbl_virt =
dma_alloc_coherent(&hba->pcidev->dev, ep->qp.sq_pgtbl_size,
@@ -1101,11 +1101,11 @@ int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
/* Allocate page table memory for CQ which is page aligned */
ep->qp.cq_mem_size = hba->max_cqes * BNX2I_CQE_SIZE;
ep->qp.cq_mem_size =
- (ep->qp.cq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ (ep->qp.cq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
ep->qp.cq_pgtbl_size =
- (ep->qp.cq_mem_size / PAGE_SIZE) * sizeof(void *);
+ (ep->qp.cq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
ep->qp.cq_pgtbl_size =
- (ep->qp.cq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ (ep->qp.cq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
ep->qp.cq_pgtbl_virt =
dma_alloc_coherent(&hba->pcidev->dev, ep->qp.cq_pgtbl_size,
@@ -1144,11 +1144,11 @@ int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
/* Allocate page table memory for RQ which is page aligned */
ep->qp.rq_mem_size = hba->max_rqes * BNX2I_RQ_WQE_SIZE;
ep->qp.rq_mem_size =
- (ep->qp.rq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ (ep->qp.rq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
ep->qp.rq_pgtbl_size =
- (ep->qp.rq_mem_size / PAGE_SIZE) * sizeof(void *);
+ (ep->qp.rq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
ep->qp.rq_pgtbl_size =
- (ep->qp.rq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ (ep->qp.rq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
ep->qp.rq_pgtbl_virt =
dma_alloc_coherent(&hba->pcidev->dev, ep->qp.rq_pgtbl_size,
@@ -1270,7 +1270,7 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)
bnx2i_adjust_qp_size(hba);
iscsi_init.flags =
- ISCSI_PAGE_SIZE_4K << ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT;
+ (CNIC_PAGE_BITS - 8) << ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT;
if (en_tcp_dack)
iscsi_init.flags |= ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE;
iscsi_init.reserved0 = 0;
@@ -1288,15 +1288,15 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)
((hba->num_ccell & 0xFFFF) | (hba->max_sqes << 16));
iscsi_init.num_ccells_per_conn = hba->num_ccell;
iscsi_init.num_tasks_per_conn = hba->max_sqes;
- iscsi_init.sq_wqes_per_page = PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
+ iscsi_init.sq_wqes_per_page = CNIC_PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
iscsi_init.sq_num_wqes = hba->max_sqes;
iscsi_init.cq_log_wqes_per_page =
- (u8) bnx2i_power_of2(PAGE_SIZE / BNX2I_CQE_SIZE);
+ (u8) bnx2i_power_of2(CNIC_PAGE_SIZE / BNX2I_CQE_SIZE);
iscsi_init.cq_num_wqes = hba->max_cqes;
iscsi_init.cq_num_pages = (hba->max_cqes * BNX2I_CQE_SIZE +
- (PAGE_SIZE - 1)) / PAGE_SIZE;
+ (CNIC_PAGE_SIZE - 1)) / CNIC_PAGE_SIZE;
iscsi_init.sq_num_pages = (hba->max_sqes * BNX2I_SQ_WQE_SIZE +
- (PAGE_SIZE - 1)) / PAGE_SIZE;
+ (CNIC_PAGE_SIZE - 1)) / CNIC_PAGE_SIZE;
iscsi_init.rq_buffer_size = BNX2I_RQ_WQE_SIZE;
iscsi_init.rq_num_wqes = hba->max_rqes;
@@ -1361,7 +1361,7 @@ int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session,
u32 datalen = 0;
resp_cqe = (struct bnx2i_cmd_response *)cqe;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->back_lock);
task = iscsi_itt_to_task(conn,
resp_cqe->itt & ISCSI_CMD_RESPONSE_INDEX);
if (!task)
@@ -1432,7 +1432,7 @@ done:
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr,
conn->data, datalen);
fail:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->back_lock);
return 0;
}
@@ -1457,7 +1457,7 @@ static int bnx2i_process_login_resp(struct iscsi_session *session,
int pad_len;
login = (struct bnx2i_login_response *) cqe;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
task = iscsi_itt_to_task(conn,
login->itt & ISCSI_LOGIN_RESPONSE_INDEX);
if (!task)
@@ -1500,7 +1500,7 @@ static int bnx2i_process_login_resp(struct iscsi_session *session,
bnx2i_conn->gen_pdu.resp_buf,
bnx2i_conn->gen_pdu.resp_wr_ptr - bnx2i_conn->gen_pdu.resp_buf);
done:
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
return 0;
}
@@ -1525,7 +1525,7 @@ static int bnx2i_process_text_resp(struct iscsi_session *session,
int pad_len;
text = (struct bnx2i_text_response *) cqe;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
task = iscsi_itt_to_task(conn, text->itt & ISCSI_LOGIN_RESPONSE_INDEX);
if (!task)
goto done;
@@ -1561,7 +1561,7 @@ static int bnx2i_process_text_resp(struct iscsi_session *session,
bnx2i_conn->gen_pdu.resp_wr_ptr -
bnx2i_conn->gen_pdu.resp_buf);
done:
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
return 0;
}
@@ -1584,7 +1584,7 @@ static int bnx2i_process_tmf_resp(struct iscsi_session *session,
struct iscsi_tm_rsp *resp_hdr;
tmf_cqe = (struct bnx2i_tmf_response *)cqe;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
task = iscsi_itt_to_task(conn,
tmf_cqe->itt & ISCSI_TMF_RESPONSE_INDEX);
if (!task)
@@ -1600,7 +1600,7 @@ static int bnx2i_process_tmf_resp(struct iscsi_session *session,
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
done:
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
return 0;
}
@@ -1623,7 +1623,7 @@ static int bnx2i_process_logout_resp(struct iscsi_session *session,
struct iscsi_logout_rsp *resp_hdr;
logout = (struct bnx2i_logout_response *) cqe;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
task = iscsi_itt_to_task(conn,
logout->itt & ISCSI_LOGOUT_RESPONSE_INDEX);
if (!task)
@@ -1647,7 +1647,7 @@ static int bnx2i_process_logout_resp(struct iscsi_session *session,
bnx2i_conn->ep->state = EP_STATE_LOGOUT_RESP_RCVD;
done:
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
return 0;
}
@@ -1668,12 +1668,12 @@ static void bnx2i_process_nopin_local_cmpl(struct iscsi_session *session,
struct iscsi_task *task;
nop_in = (struct bnx2i_nop_in_msg *)cqe;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
task = iscsi_itt_to_task(conn,
nop_in->itt & ISCSI_NOP_IN_MSG_INDEX);
if (task)
__iscsi_put_task(task);
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
}
/**
@@ -1712,7 +1712,7 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session,
nop_in = (struct bnx2i_nop_in_msg *)cqe;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
hdr = (struct iscsi_nopin *)&bnx2i_conn->gen_pdu.resp_hdr;
memset(hdr, 0, sizeof(struct iscsi_hdr));
hdr->opcode = nop_in->op_code;
@@ -1738,7 +1738,7 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session,
}
done:
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
return tgt_async_nop;
}
@@ -1771,7 +1771,7 @@ static void bnx2i_process_async_mesg(struct iscsi_session *session,
return;
}
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
resp_hdr = (struct iscsi_async *) &bnx2i_conn->gen_pdu.resp_hdr;
memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
resp_hdr->opcode = async_cqe->op_code;
@@ -1790,7 +1790,7 @@ static void bnx2i_process_async_mesg(struct iscsi_session *session,
__iscsi_complete_pdu(bnx2i_conn->cls_conn->dd_data,
(struct iscsi_hdr *)resp_hdr, NULL, 0);
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
}
@@ -1817,7 +1817,7 @@ static void bnx2i_process_reject_mesg(struct iscsi_session *session,
} else
bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
hdr = (struct iscsi_reject *) &bnx2i_conn->gen_pdu.resp_hdr;
memset(hdr, 0, sizeof(struct iscsi_hdr));
hdr->opcode = reject->op_code;
@@ -1828,7 +1828,7 @@ static void bnx2i_process_reject_mesg(struct iscsi_session *session,
hdr->ffffffff = cpu_to_be32(RESERVED_ITT);
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, conn->data,
reject->data_length);
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
}
/**
@@ -1848,13 +1848,13 @@ static void bnx2i_process_cmd_cleanup_resp(struct iscsi_session *session,
struct iscsi_task *task;
cmd_clean_rsp = (struct bnx2i_cleanup_response *)cqe;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
task = iscsi_itt_to_task(conn,
cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX);
if (!task)
printk(KERN_ALERT "bnx2i: cmd clean ITT %x not active\n",
cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX);
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
complete(&bnx2i_conn->cmd_cleanup_cmpl);
}
@@ -1921,11 +1921,11 @@ static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session,
int rc = 0;
int cpu;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data,
cqe->itt & ISCSI_CMD_RESPONSE_INDEX);
if (!task || !task->sc) {
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
return -EINVAL;
}
sc = task->sc;
@@ -1935,7 +1935,7 @@ static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session,
else
cpu = sc->request->cpu;
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
p = &per_cpu(bnx2i_percpu, cpu);
spin_lock(&p->p_work_lock);
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index 854dad7d5b03..166543f7ef55 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -525,7 +525,7 @@ static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba)
struct iscsi_bd *mp_bdt;
u64 addr;
- hba->mp_bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ hba->mp_bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
&hba->mp_bd_dma, GFP_KERNEL);
if (!hba->mp_bd_tbl) {
printk(KERN_ERR "unable to allocate Middle Path BDT\n");
@@ -533,11 +533,12 @@ static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba)
goto out;
}
- hba->dummy_buffer = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ hba->dummy_buffer = dma_alloc_coherent(&hba->pcidev->dev,
+ CNIC_PAGE_SIZE,
&hba->dummy_buf_dma, GFP_KERNEL);
if (!hba->dummy_buffer) {
printk(KERN_ERR "unable to alloc Middle Path Dummy Buffer\n");
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
hba->mp_bd_tbl, hba->mp_bd_dma);
hba->mp_bd_tbl = NULL;
rc = -1;
@@ -548,7 +549,7 @@ static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba)
addr = (unsigned long) hba->dummy_buf_dma;
mp_bdt->buffer_addr_lo = addr & 0xffffffff;
mp_bdt->buffer_addr_hi = addr >> 32;
- mp_bdt->buffer_length = PAGE_SIZE;
+ mp_bdt->buffer_length = CNIC_PAGE_SIZE;
mp_bdt->flags = ISCSI_BD_LAST_IN_BD_CHAIN |
ISCSI_BD_FIRST_IN_BD_CHAIN;
out:
@@ -565,12 +566,12 @@ out:
static void bnx2i_free_mp_bdt(struct bnx2i_hba *hba)
{
if (hba->mp_bd_tbl) {
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
hba->mp_bd_tbl, hba->mp_bd_dma);
hba->mp_bd_tbl = NULL;
}
if (hba->dummy_buffer) {
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
hba->dummy_buffer, hba->dummy_buf_dma);
hba->dummy_buffer = NULL;
}
@@ -934,14 +935,14 @@ static void bnx2i_conn_free_login_resources(struct bnx2i_hba *hba,
struct bnx2i_conn *bnx2i_conn)
{
if (bnx2i_conn->gen_pdu.resp_bd_tbl) {
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
bnx2i_conn->gen_pdu.resp_bd_tbl,
bnx2i_conn->gen_pdu.resp_bd_dma);
bnx2i_conn->gen_pdu.resp_bd_tbl = NULL;
}
if (bnx2i_conn->gen_pdu.req_bd_tbl) {
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
bnx2i_conn->gen_pdu.req_bd_tbl,
bnx2i_conn->gen_pdu.req_bd_dma);
bnx2i_conn->gen_pdu.req_bd_tbl = NULL;
@@ -998,13 +999,13 @@ static int bnx2i_conn_alloc_login_resources(struct bnx2i_hba *hba,
bnx2i_conn->gen_pdu.resp_wr_ptr = bnx2i_conn->gen_pdu.resp_buf;
bnx2i_conn->gen_pdu.req_bd_tbl =
- dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
&bnx2i_conn->gen_pdu.req_bd_dma, GFP_KERNEL);
if (bnx2i_conn->gen_pdu.req_bd_tbl == NULL)
goto login_req_bd_tbl_failure;
bnx2i_conn->gen_pdu.resp_bd_tbl =
- dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
&bnx2i_conn->gen_pdu.resp_bd_dma,
GFP_KERNEL);
if (bnx2i_conn->gen_pdu.resp_bd_tbl == NULL)
@@ -1013,7 +1014,7 @@ static int bnx2i_conn_alloc_login_resources(struct bnx2i_hba *hba,
return 0;
login_resp_bd_tbl_failure:
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
bnx2i_conn->gen_pdu.req_bd_tbl,
bnx2i_conn->gen_pdu.req_bd_dma);
bnx2i_conn->gen_pdu.req_bd_tbl = NULL;
@@ -1169,10 +1170,10 @@ static void bnx2i_cleanup_task(struct iscsi_task *task)
if (task->state == ISCSI_TASK_ABRT_TMF) {
bnx2i_send_cmd_cleanup_req(hba, task->dd_data);
- spin_unlock_bh(&conn->session->lock);
+ spin_unlock_bh(&conn->session->back_lock);
wait_for_completion_timeout(&bnx2i_conn->cmd_cleanup_cmpl,
msecs_to_jiffies(ISCSI_CMD_CLEANUP_TIMEOUT));
- spin_lock_bh(&conn->session->lock);
+ spin_lock_bh(&conn->session->back_lock);
}
bnx2i_iscsi_unmap_sg_list(task->dd_data);
}
@@ -2059,7 +2060,7 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep)
goto out;
if (session) {
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (bnx2i_ep->state != EP_STATE_TCP_FIN_RCVD) {
if (session->state == ISCSI_STATE_LOGGING_OUT) {
if (bnx2i_ep->state == EP_STATE_LOGOUT_SENT) {
@@ -2075,7 +2076,7 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep)
} else
close = 1;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
}
bnx2i_ep->state = EP_STATE_DISCONN_START;
diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
index 5a9f84238a53..e8ee5e5fe0ef 100644
--- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
+++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
@@ -175,52 +175,6 @@ static inline int is_ofld_imm(const struct sk_buff *skb)
sizeof(struct fw_ofld_tx_data_wr));
}
-
-#define VLAN_NONE 0xfff
-#define FILTER_SEL_VLAN_NONE 0xffff
-#define FILTER_SEL_WIDTH_P_FC (3+1) /* port uses 3 bits, FCoE one bit */
-#define FILTER_SEL_WIDTH_VIN_P_FC \
- (6 + 7 + FILTER_SEL_WIDTH_P_FC) /* 6 bits are unused, VF uses 7 bits*/
-#define FILTER_SEL_WIDTH_TAG_P_FC \
- (3 + FILTER_SEL_WIDTH_VIN_P_FC) /* PF uses 3 bits */
-#define FILTER_SEL_WIDTH_VLD_TAG_P_FC (1 + FILTER_SEL_WIDTH_TAG_P_FC)
-
-static unsigned int select_ntuple(struct cxgbi_device *cdev,
- struct l2t_entry *l2t)
-{
- struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev);
- unsigned int ntuple = 0;
- u32 viid;
-
- switch (lldi->filt_mode) {
-
- /* default filter mode */
- case HW_TPL_FR_MT_PR_IV_P_FC:
- if (l2t->vlan == VLAN_NONE)
- ntuple |= FILTER_SEL_VLAN_NONE << FILTER_SEL_WIDTH_P_FC;
- else {
- ntuple |= l2t->vlan << FILTER_SEL_WIDTH_P_FC;
- ntuple |= 1 << FILTER_SEL_WIDTH_VLD_TAG_P_FC;
- }
- ntuple |= l2t->lport << S_PORT | IPPROTO_TCP <<
- FILTER_SEL_WIDTH_VLD_TAG_P_FC;
- break;
- case HW_TPL_FR_MT_PR_OV_P_FC: {
- viid = cxgb4_port_viid(l2t->neigh->dev);
-
- ntuple |= FW_VIID_VIN_GET(viid) << FILTER_SEL_WIDTH_P_FC;
- ntuple |= FW_VIID_PFN_GET(viid) << FILTER_SEL_WIDTH_VIN_P_FC;
- ntuple |= FW_VIID_VIVLD_GET(viid) << FILTER_SEL_WIDTH_TAG_P_FC;
- ntuple |= l2t->lport << S_PORT | IPPROTO_TCP <<
- FILTER_SEL_WIDTH_VLD_TAG_P_FC;
- break;
- }
- default:
- break;
- }
- return ntuple;
-}
-
static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb,
struct l2t_entry *e)
{
@@ -248,8 +202,6 @@ static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb,
struct cpl_act_open_req *req =
(struct cpl_act_open_req *)skb->head;
- req = (struct cpl_act_open_req *)skb->head;
-
INIT_TP_WR(req, 0);
OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ,
qid_atid));
@@ -258,7 +210,9 @@ static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb,
req->local_ip = csk->saddr.sin_addr.s_addr;
req->peer_ip = csk->daddr.sin_addr.s_addr;
req->opt0 = cpu_to_be64(opt0);
- req->params = cpu_to_be32(select_ntuple(csk->cdev, csk->l2t));
+ req->params = cpu_to_be32(cxgb4_select_ntuple(
+ csk->cdev->ports[csk->port_id],
+ csk->l2t));
opt2 |= 1 << 22;
req->opt2 = cpu_to_be32(opt2);
@@ -271,8 +225,6 @@ static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb,
struct cpl_t5_act_open_req *req =
(struct cpl_t5_act_open_req *)skb->head;
- req = (struct cpl_t5_act_open_req *)skb->head;
-
INIT_TP_WR(req, 0);
OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ,
qid_atid));
@@ -281,7 +233,10 @@ static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb,
req->local_ip = csk->saddr.sin_addr.s_addr;
req->peer_ip = csk->daddr.sin_addr.s_addr;
req->opt0 = cpu_to_be64(opt0);
- req->params = cpu_to_be32(select_ntuple(csk->cdev, csk->l2t));
+ req->params = cpu_to_be64(V_FILTER_TUPLE(
+ cxgb4_select_ntuple(
+ csk->cdev->ports[csk->port_id],
+ csk->l2t)));
opt2 |= 1 << 31;
req->opt2 = cpu_to_be32(opt2);
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
index d01f01604140..eb29fe7eaf49 100644
--- a/drivers/scsi/dtc.c
+++ b/drivers/scsi/dtc.c
@@ -277,7 +277,7 @@ found:
/* With interrupts enabled, it will sometimes hang when doing heavy
* reads. So better not enable them until I finger it out. */
if (instance->irq != SCSI_IRQ_NONE)
- if (request_irq(instance->irq, dtc_intr, IRQF_DISABLED,
+ if (request_irq(instance->irq, dtc_intr, 0,
"dtc", instance)) {
printk(KERN_ERR "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
instance->irq = SCSI_IRQ_NONE;
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index 94de88955a99..ebf57364df91 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -1221,7 +1221,7 @@ static int port_detect(unsigned long port_base, unsigned int j,
/* Board detected, allocate its IRQ */
if (request_irq(irq, do_interrupt_handler,
- IRQF_DISABLED | ((subversion == ESA) ? IRQF_SHARED : 0),
+ (subversion == ESA) ? IRQF_SHARED : 0,
driver_name, (void *)&sha[j])) {
printk("%s: unable to allocate IRQ %u, detaching.\n", name,
irq);
diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
index 1663173cdb91..8319d2b417b8 100644
--- a/drivers/scsi/eata_pio.c
+++ b/drivers/scsi/eata_pio.c
@@ -687,7 +687,7 @@ static int register_pio_HBA(long base, struct get_conf *gc, struct pci_dev *pdev
return 0;
if (!reg_IRQ[gc->IRQ]) { /* Interrupt already registered ? */
- if (!request_irq(gc->IRQ, do_eata_pio_int_handler, IRQF_DISABLED, "EATA-PIO", sh)) {
+ if (!request_irq(gc->IRQ, do_eata_pio_int_handler, 0, "EATA-PIO", sh)) {
reg_IRQ[gc->IRQ]++;
if (!gc->IRQ_TR)
reg_IRQL[gc->IRQ] = 1; /* IRQ is edge triggered */
@@ -921,7 +921,7 @@ static int eata_pio_detect(struct scsi_host_template *tpnt)
for (i = 0; i < MAXIRQ; i++)
if (reg_IRQ[i])
- request_irq(i, do_eata_pio_int_handler, IRQF_DISABLED, "EATA-PIO", NULL);
+ request_irq(i, do_eata_pio_int_handler, 0, "EATA-PIO", NULL);
HBA_ptr = first_HBA;
diff --git a/drivers/scsi/esas2r/esas2r_init.c b/drivers/scsi/esas2r/esas2r_init.c
index b9750e296d71..6776931e25d4 100644
--- a/drivers/scsi/esas2r/esas2r_init.c
+++ b/drivers/scsi/esas2r/esas2r_init.c
@@ -231,7 +231,7 @@ use_legacy_interrupts:
static void esas2r_claim_interrupts(struct esas2r_adapter *a)
{
- unsigned long flags = IRQF_DISABLED;
+ unsigned long flags = 0;
if (a->intr_mode == INTR_MODE_LEGACY)
flags |= IRQF_SHARED;
diff --git a/drivers/scsi/esas2r/esas2r_log.c b/drivers/scsi/esas2r/esas2r_log.c
index 9bf285df58dd..a82030aa8577 100644
--- a/drivers/scsi/esas2r/esas2r_log.c
+++ b/drivers/scsi/esas2r/esas2r_log.c
@@ -165,13 +165,9 @@ static int esas2r_log_master(const long level,
/*
* 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.
+ * we don't wind up with run-on messages.
*/
- if (strlen(event_buffer) < buflen)
- strcat(buffer, "\n");
-
- printk(event_buffer);
+ printk("%s\n", event_buffer);
spin_unlock_irqrestore(&event_buffer_lock, flags);
}
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 5cec6c60ca22..7176365e916b 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -461,7 +461,7 @@ int __init generic_NCR5380_detect(struct scsi_host_template * tpnt)
if (instance->irq != SCSI_IRQ_NONE)
if (request_irq(instance->irq, generic_NCR5380_intr,
- IRQF_DISABLED, "NCR5380", instance)) {
+ 0, "NCR5380", instance)) {
printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
instance->irq = SCSI_IRQ_NONE;
}
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index ce5ef0190bad..0f1ae13ce7c7 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -4711,7 +4711,7 @@ static int __init gdth_isa_probe_one(u32 isa_bios)
printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n",
isa_bios, ha->irq, ha->drq);
- error = request_irq(ha->irq, gdth_interrupt, IRQF_DISABLED, "gdth", ha);
+ error = request_irq(ha->irq, gdth_interrupt, 0, "gdth", ha);
if (error) {
printk("GDT-ISA: Unable to allocate IRQ\n");
goto out_host_put;
@@ -4843,7 +4843,7 @@ static int __init gdth_eisa_probe_one(u16 eisa_slot)
printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n",
eisa_slot >> 12, ha->irq);
- error = request_irq(ha->irq, gdth_interrupt, IRQF_DISABLED, "gdth", ha);
+ error = request_irq(ha->irq, gdth_interrupt, 0, "gdth", ha);
if (error) {
printk("GDT-EISA: Unable to allocate IRQ\n");
goto out_host_put;
@@ -4979,7 +4979,7 @@ static int gdth_pci_probe_one(gdth_pci_str *pcistr, gdth_ha_str **ha_out)
ha->irq);
error = request_irq(ha->irq, gdth_interrupt,
- IRQF_DISABLED|IRQF_SHARED, "gdth", ha);
+ IRQF_SHARED, "gdth", ha);
if (error) {
printk("GDT-PCI: Unable to allocate IRQ\n");
goto out_host_put;
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index f28ea070d3df..3cbb57a8b846 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -398,7 +398,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
shost->ordered_tag = sht->ordered_tag;
shost->no_write_same = sht->no_write_same;
- if (shost_eh_deadline == -1)
+ if (shost_eh_deadline == -1 || !sht->eh_host_reset_handler)
shost->eh_deadline = -1;
else if ((ulong) shost_eh_deadline * HZ > INT_MAX) {
shost_printk(KERN_WARNING, shost,
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 868318a7067c..8cf4a0c69baf 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -1,6 +1,6 @@
/*
* Disk Array driver for HP Smart Array SAS controllers
- * Copyright 2000, 2009 Hewlett-Packard Development Company, L.P.
+ * Copyright 2000, 2014 Hewlett-Packard Development Company, L.P.
*
* 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
@@ -47,13 +47,13 @@
#include <linux/string.h>
#include <linux/bitmap.h>
#include <linux/atomic.h>
-#include <linux/kthread.h>
#include <linux/jiffies.h>
+#include <asm/div64.h>
#include "hpsa_cmd.h"
#include "hpsa.h"
/* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */
-#define HPSA_DRIVER_VERSION "3.4.0-1"
+#define HPSA_DRIVER_VERSION "3.4.4-1"
#define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")"
#define HPSA "hpsa"
@@ -118,6 +118,11 @@ static const struct pci_device_id hpsa_pci_device_id[] = {
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21C7},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21C8},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21C9},
+ {PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x0076},
+ {PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x0087},
+ {PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x007D},
+ {PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x0088},
+ {PCI_VENDOR_ID_HP, 0x333f, 0x103c, 0x333f},
{PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
{0,}
@@ -163,6 +168,11 @@ static struct board_type products[] = {
{0x21C7103C, "Smart Array", &SA5_access},
{0x21C8103C, "Smart Array", &SA5_access},
{0x21C9103C, "Smart Array", &SA5_access},
+ {0x00761590, "HP Storage P1224 Array Controller", &SA5_access},
+ {0x00871590, "HP Storage P1224e Array Controller", &SA5_access},
+ {0x007D1590, "HP Storage P1228 Array Controller", &SA5_access},
+ {0x00881590, "HP Storage P1228e Array Controller", &SA5_access},
+ {0x333f103c, "HP StorageWorks 1210m Array Controller", &SA5_access},
{0xFFFF103C, "Unknown Smart Array", &SA5_access},
};
@@ -182,8 +192,9 @@ static void cmd_special_free(struct ctlr_info *h, struct CommandList *c);
static struct CommandList *cmd_alloc(struct ctlr_info *h);
static struct CommandList *cmd_special_alloc(struct ctlr_info *h);
static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
- void *buff, size_t size, u8 page_code, unsigned char *scsi3addr,
+ void *buff, size_t size, u16 page_code, unsigned char *scsi3addr,
int cmd_type);
+#define VPD_PAGE (1 << 8)
static int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd);
static void hpsa_scan_start(struct Scsi_Host *);
@@ -204,7 +215,7 @@ static void check_ioctl_unit_attention(struct ctlr_info *h,
struct CommandList *c);
/* performant mode helper functions */
static void calc_bucket_map(int *bucket, int num_buckets,
- int nsgs, int *bucket_map);
+ int nsgs, int min_blocks, int *bucket_map);
static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h);
static inline u32 next_command(struct ctlr_info *h, u8 q);
static int hpsa_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr,
@@ -216,8 +227,14 @@ static int hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id);
static int hpsa_wait_for_board_state(struct pci_dev *pdev, void __iomem *vaddr,
int wait_for_ready);
static inline void finish_cmd(struct CommandList *c);
+static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h);
#define BOARD_NOT_READY 0
#define BOARD_READY 1
+static void hpsa_drain_accel_commands(struct ctlr_info *h);
+static void hpsa_flush_cache(struct ctlr_info *h);
+static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
+ struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
+ u8 *scsi3addr);
static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev)
{
@@ -280,6 +297,55 @@ static int check_for_busy(struct ctlr_info *h, struct CommandList *c)
return 1;
}
+static ssize_t host_store_hp_ssd_smart_path_status(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int status, len;
+ struct ctlr_info *h;
+ struct Scsi_Host *shost = class_to_shost(dev);
+ char tmpbuf[10];
+
+ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+ return -EACCES;
+ len = count > sizeof(tmpbuf) - 1 ? sizeof(tmpbuf) - 1 : count;
+ strncpy(tmpbuf, buf, len);
+ tmpbuf[len] = '\0';
+ if (sscanf(tmpbuf, "%d", &status) != 1)
+ return -EINVAL;
+ h = shost_to_hba(shost);
+ h->acciopath_status = !!status;
+ dev_warn(&h->pdev->dev,
+ "hpsa: HP SSD Smart Path %s via sysfs update.\n",
+ h->acciopath_status ? "enabled" : "disabled");
+ return count;
+}
+
+static ssize_t host_store_raid_offload_debug(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int debug_level, len;
+ struct ctlr_info *h;
+ struct Scsi_Host *shost = class_to_shost(dev);
+ char tmpbuf[10];
+
+ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+ return -EACCES;
+ len = count > sizeof(tmpbuf) - 1 ? sizeof(tmpbuf) - 1 : count;
+ strncpy(tmpbuf, buf, len);
+ tmpbuf[len] = '\0';
+ if (sscanf(tmpbuf, "%d", &debug_level) != 1)
+ return -EINVAL;
+ if (debug_level < 0)
+ debug_level = 0;
+ h = shost_to_hba(shost);
+ h->raid_offload_debug = debug_level;
+ dev_warn(&h->pdev->dev, "hpsa: Set raid_offload_debug level = %d\n",
+ h->raid_offload_debug);
+ return count;
+}
+
static ssize_t host_store_rescan(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -327,6 +393,17 @@ static ssize_t host_show_transport_mode(struct device *dev,
"performant" : "simple");
}
+static ssize_t host_show_hp_ssd_smart_path_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ctlr_info *h;
+ struct Scsi_Host *shost = class_to_shost(dev);
+
+ h = shost_to_hba(shost);
+ return snprintf(buf, 30, "HP SSD Smart Path %s\n",
+ (h->acciopath_status == 1) ? "enabled" : "disabled");
+}
+
/* List of controllers which cannot be hard reset on kexec with reset_devices */
static u32 unresettable_controller[] = {
0x324a103C, /* Smart Array P712m */
@@ -416,6 +493,13 @@ static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[])
static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
"1(ADM)", "UNKNOWN"
};
+#define HPSA_RAID_0 0
+#define HPSA_RAID_4 1
+#define HPSA_RAID_1 2 /* also used for RAID 10 */
+#define HPSA_RAID_5 3 /* also used for RAID 50 */
+#define HPSA_RAID_51 4
+#define HPSA_RAID_6 5 /* also used for RAID 60 */
+#define HPSA_RAID_ADM 6 /* also used for RAID 1+0 ADM */
#define RAID_UNKNOWN (ARRAY_SIZE(raid_label) - 1)
static ssize_t raid_level_show(struct device *dev,
@@ -504,10 +588,39 @@ static ssize_t unique_id_show(struct device *dev,
sn[12], sn[13], sn[14], sn[15]);
}
+static ssize_t host_show_hp_ssd_smart_path_enabled(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ctlr_info *h;
+ struct scsi_device *sdev;
+ struct hpsa_scsi_dev_t *hdev;
+ unsigned long flags;
+ int offload_enabled;
+
+ sdev = to_scsi_device(dev);
+ h = sdev_to_hba(sdev);
+ spin_lock_irqsave(&h->lock, flags);
+ hdev = sdev->hostdata;
+ if (!hdev) {
+ spin_unlock_irqrestore(&h->lock, flags);
+ return -ENODEV;
+ }
+ offload_enabled = hdev->offload_enabled;
+ spin_unlock_irqrestore(&h->lock, flags);
+ return snprintf(buf, 20, "%d\n", offload_enabled);
+}
+
static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL);
static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL);
static DEVICE_ATTR(unique_id, S_IRUGO, unique_id_show, NULL);
static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan);
+static DEVICE_ATTR(hp_ssd_smart_path_enabled, S_IRUGO,
+ host_show_hp_ssd_smart_path_enabled, NULL);
+static DEVICE_ATTR(hp_ssd_smart_path_status, S_IWUSR|S_IRUGO|S_IROTH,
+ host_show_hp_ssd_smart_path_status,
+ host_store_hp_ssd_smart_path_status);
+static DEVICE_ATTR(raid_offload_debug, S_IWUSR, NULL,
+ host_store_raid_offload_debug);
static DEVICE_ATTR(firmware_revision, S_IRUGO,
host_show_firmware_revision, NULL);
static DEVICE_ATTR(commands_outstanding, S_IRUGO,
@@ -521,6 +634,7 @@ static struct device_attribute *hpsa_sdev_attrs[] = {
&dev_attr_raid_level,
&dev_attr_lunid,
&dev_attr_unique_id,
+ &dev_attr_hp_ssd_smart_path_enabled,
NULL,
};
@@ -530,6 +644,8 @@ static struct device_attribute *hpsa_shost_attrs[] = {
&dev_attr_commands_outstanding,
&dev_attr_transport_mode,
&dev_attr_resettable,
+ &dev_attr_hp_ssd_smart_path_status,
+ &dev_attr_raid_offload_debug,
NULL,
};
@@ -570,6 +686,9 @@ static inline u32 next_command(struct ctlr_info *h, u8 q)
struct reply_pool *rq = &h->reply_queue[q];
unsigned long flags;
+ if (h->transMethod & CFGTBL_Trans_io_accel1)
+ return h->access.command_completed(h, q);
+
if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant)))
return h->access.command_completed(h, q);
@@ -590,6 +709,32 @@ static inline u32 next_command(struct ctlr_info *h, u8 q)
return a;
}
+/*
+ * There are some special bits in the bus address of the
+ * command that we have to set for the controller to know
+ * how to process the command:
+ *
+ * Normal performant mode:
+ * bit 0: 1 means performant mode, 0 means simple mode.
+ * bits 1-3 = block fetch table entry
+ * bits 4-6 = command type (== 0)
+ *
+ * ioaccel1 mode:
+ * bit 0 = "performant mode" bit.
+ * bits 1-3 = block fetch table entry
+ * bits 4-6 = command type (== 110)
+ * (command type is needed because ioaccel1 mode
+ * commands are submitted through the same register as normal
+ * mode commands, so this is how the controller knows whether
+ * the command is normal mode or ioaccel1 mode.)
+ *
+ * ioaccel2 mode:
+ * bit 0 = "performant mode" bit.
+ * bits 1-4 = block fetch table entry (note extra bit)
+ * bits 4-6 = not needed, because ioaccel2 mode has
+ * a separate special register for submitting commands.
+ */
+
/* set_performant_mode: Modify the tag for cciss performant
* set bit 0 for pull model, bits 3-1 for block fetch
* register number
@@ -598,12 +743,47 @@ static void set_performant_mode(struct ctlr_info *h, struct CommandList *c)
{
if (likely(h->transMethod & CFGTBL_Trans_Performant)) {
c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1);
- if (likely(h->msix_vector))
+ if (likely(h->msix_vector > 0))
c->Header.ReplyQueue =
raw_smp_processor_id() % h->nreply_queues;
}
}
+static void set_ioaccel1_performant_mode(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[c->cmdindex];
+
+ /* Tell the controller to post the reply to the queue for this
+ * processor. This seems to give the best I/O throughput.
+ */
+ cp->ReplyQueue = smp_processor_id() % h->nreply_queues;
+ /* Set the bits in the address sent down to include:
+ * - performant mode bit (bit 0)
+ * - pull count (bits 1-3)
+ * - command type (bits 4-6)
+ */
+ c->busaddr |= 1 | (h->ioaccel1_blockFetchTable[c->Header.SGList] << 1) |
+ IOACCEL1_BUSADDR_CMDTYPE;
+}
+
+static void set_ioaccel2_performant_mode(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ struct io_accel2_cmd *cp = &h->ioaccel2_cmd_pool[c->cmdindex];
+
+ /* Tell the controller to post the reply to the queue for this
+ * processor. This seems to give the best I/O throughput.
+ */
+ cp->reply_queue = smp_processor_id() % h->nreply_queues;
+ /* Set the bits in the address sent down to include:
+ * - performant mode bit not used in ioaccel mode 2
+ * - pull count (bits 0-3)
+ * - command type isn't needed for ioaccel2
+ */
+ c->busaddr |= (h->ioaccel2_blockFetchTable[cp->sg_count]);
+}
+
static int is_firmware_flash_cmd(u8 *cdb)
{
return cdb[0] == BMIC_WRITE && cdb[6] == BMIC_FLASH_FIRMWARE;
@@ -638,7 +818,16 @@ static void enqueue_cmd_and_start_io(struct ctlr_info *h,
{
unsigned long flags;
- set_performant_mode(h, c);
+ switch (c->cmd_type) {
+ case CMD_IOACCEL1:
+ set_ioaccel1_performant_mode(h, c);
+ break;
+ case CMD_IOACCEL2:
+ set_ioaccel2_performant_mode(h, c);
+ break;
+ default:
+ set_performant_mode(h, c);
+ }
dial_down_lockup_detection_during_fw_flash(h, c);
spin_lock_irqsave(&h->lock, flags);
addQ(&h->reqQ, c);
@@ -782,6 +971,14 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno,
/* Raid level changed. */
h->dev[entry]->raid_level = new_entry->raid_level;
+
+ /* Raid offload parameters changed. */
+ h->dev[entry]->offload_config = new_entry->offload_config;
+ h->dev[entry]->offload_enabled = new_entry->offload_enabled;
+ h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle;
+ h->dev[entry]->offload_to_mirror = new_entry->offload_to_mirror;
+ h->dev[entry]->raid_map = new_entry->raid_map;
+
dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d updated.\n",
scsi_device_type(new_entry->devtype), hostno, new_entry->bus,
new_entry->target, new_entry->lun);
@@ -902,6 +1099,10 @@ static inline int device_updated(struct hpsa_scsi_dev_t *dev1,
*/
if (dev1->raid_level != dev2->raid_level)
return 1;
+ if (dev1->offload_config != dev2->offload_config)
+ return 1;
+ if (dev1->offload_enabled != dev2->offload_enabled)
+ return 1;
return 0;
}
@@ -932,6 +1133,9 @@ static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle,
return DEVICE_UPDATED;
return DEVICE_SAME;
} else {
+ /* Keep offline devices offline */
+ if (needle->volume_offline)
+ return DEVICE_NOT_FOUND;
return DEVICE_CHANGED;
}
}
@@ -940,6 +1144,110 @@ static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle,
return DEVICE_NOT_FOUND;
}
+static void hpsa_monitor_offline_device(struct ctlr_info *h,
+ unsigned char scsi3addr[])
+{
+ struct offline_device_entry *device;
+ unsigned long flags;
+
+ /* Check to see if device is already on the list */
+ spin_lock_irqsave(&h->offline_device_lock, flags);
+ list_for_each_entry(device, &h->offline_device_list, offline_list) {
+ if (memcmp(device->scsi3addr, scsi3addr,
+ sizeof(device->scsi3addr)) == 0) {
+ spin_unlock_irqrestore(&h->offline_device_lock, flags);
+ return;
+ }
+ }
+ spin_unlock_irqrestore(&h->offline_device_lock, flags);
+
+ /* Device is not on the list, add it. */
+ device = kmalloc(sizeof(*device), GFP_KERNEL);
+ if (!device) {
+ dev_warn(&h->pdev->dev, "out of memory in %s\n", __func__);
+ return;
+ }
+ memcpy(device->scsi3addr, scsi3addr, sizeof(device->scsi3addr));
+ spin_lock_irqsave(&h->offline_device_lock, flags);
+ list_add_tail(&device->offline_list, &h->offline_device_list);
+ spin_unlock_irqrestore(&h->offline_device_lock, flags);
+}
+
+/* Print a message explaining various offline volume states */
+static void hpsa_show_volume_status(struct ctlr_info *h,
+ struct hpsa_scsi_dev_t *sd)
+{
+ if (sd->volume_offline == HPSA_VPD_LV_STATUS_UNSUPPORTED)
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume status is not available through vital product data pages.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ switch (sd->volume_offline) {
+ case HPSA_LV_OK:
+ break;
+ case HPSA_LV_UNDERGOING_ERASE:
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume is undergoing background erase process.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ break;
+ case HPSA_LV_UNDERGOING_RPI:
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume is undergoing rapid parity initialization process.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ break;
+ case HPSA_LV_PENDING_RPI:
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume is queued for rapid parity initialization process.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ break;
+ case HPSA_LV_ENCRYPTED_NO_KEY:
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume is encrypted and cannot be accessed because key is not present.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ break;
+ case HPSA_LV_PLAINTEXT_IN_ENCRYPT_ONLY_CONTROLLER:
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume is not encrypted and cannot be accessed because controller is in encryption-only mode.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ break;
+ case HPSA_LV_UNDERGOING_ENCRYPTION:
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume is undergoing encryption process.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ break;
+ case HPSA_LV_UNDERGOING_ENCRYPTION_REKEYING:
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume is undergoing encryption re-keying process.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ break;
+ case HPSA_LV_ENCRYPTED_IN_NON_ENCRYPTED_CONTROLLER:
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume is encrypted and cannot be accessed because controller does not have encryption enabled.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ break;
+ case HPSA_LV_PENDING_ENCRYPTION:
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume is pending migration to encrypted state, but process has not started.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ break;
+ case HPSA_LV_PENDING_ENCRYPTION_REKEYING:
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume is encrypted and is pending encryption rekeying.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ break;
+ }
+}
+
static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
struct hpsa_scsi_dev_t *sd[], int nsds)
{
@@ -1004,6 +1312,20 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
for (i = 0; i < nsds; i++) {
if (!sd[i]) /* if already added above. */
continue;
+
+ /* Don't add devices which are NOT READY, FORMAT IN PROGRESS
+ * as the SCSI mid-layer does not handle such devices well.
+ * It relentlessly loops sending TUR at 3Hz, then READ(10)
+ * at 160Hz, and prevents the system from coming up.
+ */
+ if (sd[i]->volume_offline) {
+ hpsa_show_volume_status(h, sd[i]);
+ dev_info(&h->pdev->dev, "c%db%dt%dl%d: temporarily offline\n",
+ h->scsi_host->host_no,
+ sd[i]->bus, sd[i]->target, sd[i]->lun);
+ continue;
+ }
+
device_change = hpsa_scsi_find_entry(sd[i], h->dev,
h->ndevices, &entry);
if (device_change == DEVICE_NOT_FOUND) {
@@ -1022,6 +1344,17 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
}
spin_unlock_irqrestore(&h->devlock, flags);
+ /* Monitor devices which are in one of several NOT READY states to be
+ * brought online later. This must be done without holding h->devlock,
+ * so don't touch h->dev[]
+ */
+ for (i = 0; i < nsds; i++) {
+ if (!sd[i]) /* if already added above. */
+ continue;
+ if (sd[i]->volume_offline)
+ hpsa_monitor_offline_device(h, sd[i]->scsi3addr);
+ }
+
/* Don't notify scsi mid layer of any changes the first time through
* (or if there are no changes) scsi_scan_host will do it later the
* first time through.
@@ -1187,11 +1520,163 @@ static void hpsa_unmap_sg_chain_block(struct ctlr_info *h,
pci_unmap_single(h->pdev, temp64.val, chain_sg->Len, PCI_DMA_TODEVICE);
}
+
+/* Decode the various types of errors on ioaccel2 path.
+ * Return 1 for any error that should generate a RAID path retry.
+ * Return 0 for errors that don't require a RAID path retry.
+ */
+static int handle_ioaccel_mode2_error(struct ctlr_info *h,
+ struct CommandList *c,
+ struct scsi_cmnd *cmd,
+ struct io_accel2_cmd *c2)
+{
+ int data_len;
+ int retry = 0;
+
+ switch (c2->error_data.serv_response) {
+ case IOACCEL2_SERV_RESPONSE_COMPLETE:
+ switch (c2->error_data.status) {
+ case IOACCEL2_STATUS_SR_TASK_COMP_GOOD:
+ break;
+ case IOACCEL2_STATUS_SR_TASK_COMP_CHK_COND:
+ dev_warn(&h->pdev->dev,
+ "%s: task complete with check condition.\n",
+ "HP SSD Smart Path");
+ if (c2->error_data.data_present !=
+ IOACCEL2_SENSE_DATA_PRESENT)
+ break;
+ /* copy the sense data */
+ data_len = c2->error_data.sense_data_len;
+ if (data_len > SCSI_SENSE_BUFFERSIZE)
+ data_len = SCSI_SENSE_BUFFERSIZE;
+ if (data_len > sizeof(c2->error_data.sense_data_buff))
+ data_len =
+ sizeof(c2->error_data.sense_data_buff);
+ memcpy(cmd->sense_buffer,
+ c2->error_data.sense_data_buff, data_len);
+ cmd->result |= SAM_STAT_CHECK_CONDITION;
+ retry = 1;
+ break;
+ case IOACCEL2_STATUS_SR_TASK_COMP_BUSY:
+ dev_warn(&h->pdev->dev,
+ "%s: task complete with BUSY status.\n",
+ "HP SSD Smart Path");
+ retry = 1;
+ break;
+ case IOACCEL2_STATUS_SR_TASK_COMP_RES_CON:
+ dev_warn(&h->pdev->dev,
+ "%s: task complete with reservation conflict.\n",
+ "HP SSD Smart Path");
+ retry = 1;
+ break;
+ case IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL:
+ /* Make scsi midlayer do unlimited retries */
+ cmd->result = DID_IMM_RETRY << 16;
+ break;
+ case IOACCEL2_STATUS_SR_TASK_COMP_ABORTED:
+ dev_warn(&h->pdev->dev,
+ "%s: task complete with aborted status.\n",
+ "HP SSD Smart Path");
+ retry = 1;
+ break;
+ default:
+ dev_warn(&h->pdev->dev,
+ "%s: task complete with unrecognized status: 0x%02x\n",
+ "HP SSD Smart Path", c2->error_data.status);
+ retry = 1;
+ break;
+ }
+ break;
+ case IOACCEL2_SERV_RESPONSE_FAILURE:
+ /* don't expect to get here. */
+ dev_warn(&h->pdev->dev,
+ "unexpected delivery or target failure, status = 0x%02x\n",
+ c2->error_data.status);
+ retry = 1;
+ break;
+ case IOACCEL2_SERV_RESPONSE_TMF_COMPLETE:
+ break;
+ case IOACCEL2_SERV_RESPONSE_TMF_SUCCESS:
+ break;
+ case IOACCEL2_SERV_RESPONSE_TMF_REJECTED:
+ dev_warn(&h->pdev->dev, "task management function rejected.\n");
+ retry = 1;
+ break;
+ case IOACCEL2_SERV_RESPONSE_TMF_WRONG_LUN:
+ dev_warn(&h->pdev->dev, "task management function invalid LUN\n");
+ break;
+ default:
+ dev_warn(&h->pdev->dev,
+ "%s: Unrecognized server response: 0x%02x\n",
+ "HP SSD Smart Path",
+ c2->error_data.serv_response);
+ retry = 1;
+ break;
+ }
+
+ return retry; /* retry on raid path? */
+}
+
+static void process_ioaccel2_completion(struct ctlr_info *h,
+ struct CommandList *c, struct scsi_cmnd *cmd,
+ struct hpsa_scsi_dev_t *dev)
+{
+ struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex];
+ int raid_retry = 0;
+
+ /* check for good status */
+ if (likely(c2->error_data.serv_response == 0 &&
+ c2->error_data.status == 0)) {
+ cmd_free(h, c);
+ cmd->scsi_done(cmd);
+ return;
+ }
+
+ /* Any RAID offload error results in retry which will use
+ * the normal I/O path so the controller can handle whatever's
+ * wrong.
+ */
+ if (is_logical_dev_addr_mode(dev->scsi3addr) &&
+ c2->error_data.serv_response ==
+ IOACCEL2_SERV_RESPONSE_FAILURE) {
+ if (c2->error_data.status ==
+ IOACCEL2_STATUS_SR_IOACCEL_DISABLED)
+ dev_warn(&h->pdev->dev,
+ "%s: Path is unavailable, retrying on standard path.\n",
+ "HP SSD Smart Path");
+ else
+ dev_warn(&h->pdev->dev,
+ "%s: Error 0x%02x, retrying on standard path.\n",
+ "HP SSD Smart Path", c2->error_data.status);
+
+ dev->offload_enabled = 0;
+ h->drv_req_rescan = 1; /* schedule controller for a rescan */
+ cmd->result = DID_SOFT_ERROR << 16;
+ cmd_free(h, c);
+ cmd->scsi_done(cmd);
+ return;
+ }
+ raid_retry = handle_ioaccel_mode2_error(h, c, cmd, c2);
+ /* If error found, disable Smart Path, schedule a rescan,
+ * and force a retry on the standard path.
+ */
+ if (raid_retry) {
+ dev_warn(&h->pdev->dev, "%s: Retrying on standard path.\n",
+ "HP SSD Smart Path");
+ dev->offload_enabled = 0; /* Disable Smart Path */
+ h->drv_req_rescan = 1; /* schedule controller rescan */
+ cmd->result = DID_SOFT_ERROR << 16;
+ }
+ cmd_free(h, c);
+ cmd->scsi_done(cmd);
+}
+
static void complete_scsi_command(struct CommandList *cp)
{
struct scsi_cmnd *cmd;
struct ctlr_info *h;
struct ErrorInfo *ei;
+ struct hpsa_scsi_dev_t *dev;
unsigned char sense_key;
unsigned char asc; /* additional sense code */
@@ -1201,13 +1686,19 @@ static void complete_scsi_command(struct CommandList *cp)
ei = cp->err_info;
cmd = (struct scsi_cmnd *) cp->scsi_cmd;
h = cp->h;
+ dev = cmd->device->hostdata;
scsi_dma_unmap(cmd); /* undo the DMA mappings */
- if (cp->Header.SGTotal > h->max_cmd_sg_entries)
+ if ((cp->cmd_type == CMD_SCSI) &&
+ (cp->Header.SGTotal > h->max_cmd_sg_entries))
hpsa_unmap_sg_chain_block(h, cp);
cmd->result = (DID_OK << 16); /* host byte */
cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
+
+ if (cp->cmd_type == CMD_IOACCEL2)
+ return process_ioaccel2_completion(h, cp, cmd, dev);
+
cmd->result |= ei->ScsiStatus;
/* copy the sense data whether we need to or not. */
@@ -1227,6 +1718,32 @@ static void complete_scsi_command(struct CommandList *cp)
return;
}
+ /* For I/O accelerator commands, copy over some fields to the normal
+ * CISS header used below for error handling.
+ */
+ if (cp->cmd_type == CMD_IOACCEL1) {
+ struct io_accel1_cmd *c = &h->ioaccel_cmd_pool[cp->cmdindex];
+ cp->Header.SGList = cp->Header.SGTotal = scsi_sg_count(cmd);
+ cp->Request.CDBLen = c->io_flags & IOACCEL1_IOFLAGS_CDBLEN_MASK;
+ cp->Header.Tag.lower = c->Tag.lower;
+ cp->Header.Tag.upper = c->Tag.upper;
+ memcpy(cp->Header.LUN.LunAddrBytes, c->CISS_LUN, 8);
+ memcpy(cp->Request.CDB, c->CDB, cp->Request.CDBLen);
+
+ /* Any RAID offload error results in retry which will use
+ * the normal I/O path so the controller can handle whatever's
+ * wrong.
+ */
+ if (is_logical_dev_addr_mode(dev->scsi3addr)) {
+ if (ei->CommandStatus == CMD_IOACCEL_DISABLED)
+ dev->offload_enabled = 0;
+ cmd->result = DID_SOFT_ERROR << 16;
+ cmd_free(h, cp);
+ cmd->scsi_done(cmd);
+ return;
+ }
+ }
+
/* an error has occurred */
switch (ei->CommandStatus) {
@@ -1389,6 +1906,14 @@ static void complete_scsi_command(struct CommandList *cp)
cmd->result = DID_ERROR << 16;
dev_warn(&h->pdev->dev, "Command unabortable\n");
break;
+ case CMD_IOACCEL_DISABLED:
+ /* This only handles the direct pass-through case since RAID
+ * offload is handled above. Just attempt a retry.
+ */
+ cmd->result = DID_SOFT_ERROR << 16;
+ dev_warn(&h->pdev->dev,
+ "cp %p had HP SSD Smart Path error\n", cp);
+ break;
default:
cmd->result = DID_ERROR << 16;
dev_warn(&h->pdev->dev, "cp %p returned unknown status %x\n",
@@ -1438,6 +1963,7 @@ static int hpsa_map_one(struct pci_dev *pdev,
cp->SG[0].Addr.upper =
(u32) ((addr64 >> 32) & (u64) 0x00000000FFFFFFFF);
cp->SG[0].Len = buflen;
+ cp->SG[0].Ext = HPSA_SG_LAST; /* we are not chaining */
cp->Header.SGList = (u8) 1; /* no. SGs contig in this cmd */
cp->Header.SGTotal = (u16) 1; /* total sgs in this cmd list */
return 0;
@@ -1490,17 +2016,37 @@ static void hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h,
hpsa_pci_unmap(h->pdev, c, 1, data_direction);
}
-static void hpsa_scsi_interpret_error(struct CommandList *cp)
+static void hpsa_print_cmd(struct ctlr_info *h, char *txt,
+ struct CommandList *c)
{
- struct ErrorInfo *ei;
+ const u8 *cdb = c->Request.CDB;
+ const u8 *lun = c->Header.LUN.LunAddrBytes;
+
+ dev_warn(&h->pdev->dev, "%s: LUN:%02x%02x%02x%02x%02x%02x%02x%02x"
+ " CDB:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ txt, lun[0], lun[1], lun[2], lun[3],
+ lun[4], lun[5], lun[6], lun[7],
+ cdb[0], cdb[1], cdb[2], cdb[3],
+ cdb[4], cdb[5], cdb[6], cdb[7],
+ cdb[8], cdb[9], cdb[10], cdb[11],
+ cdb[12], cdb[13], cdb[14], cdb[15]);
+}
+
+static void hpsa_scsi_interpret_error(struct ctlr_info *h,
+ struct CommandList *cp)
+{
+ const struct ErrorInfo *ei = cp->err_info;
struct device *d = &cp->h->pdev->dev;
+ const u8 *sd = ei->SenseInfo;
- ei = cp->err_info;
switch (ei->CommandStatus) {
case CMD_TARGET_STATUS:
- dev_warn(d, "cmd %p has completed with errors\n", cp);
- dev_warn(d, "cmd %p has SCSI Status = %x\n", cp,
- ei->ScsiStatus);
+ hpsa_print_cmd(h, "SCSI status", cp);
+ if (ei->ScsiStatus == SAM_STAT_CHECK_CONDITION)
+ dev_warn(d, "SCSI Status = 02, Sense key = %02x, ASC = %02x, ASCQ = %02x\n",
+ sd[2] & 0x0f, sd[12], sd[13]);
+ else
+ dev_warn(d, "SCSI Status = %02x\n", ei->ScsiStatus);
if (ei->ScsiStatus == 0)
dev_warn(d, "SCSI status is abnormally zero. "
"(probably indicates selection timeout "
@@ -1508,54 +2054,51 @@ static void hpsa_scsi_interpret_error(struct CommandList *cp)
"firmware bug, circa July, 2001.)\n");
break;
case CMD_DATA_UNDERRUN: /* let mid layer handle it. */
- dev_info(d, "UNDERRUN\n");
break;
case CMD_DATA_OVERRUN:
- dev_warn(d, "cp %p has completed with data overrun\n", cp);
+ hpsa_print_cmd(h, "overrun condition", cp);
break;
case CMD_INVALID: {
/* controller unfortunately reports SCSI passthru's
* to non-existent targets as invalid commands.
*/
- dev_warn(d, "cp %p is reported invalid (probably means "
- "target device no longer present)\n", cp);
- /* print_bytes((unsigned char *) cp, sizeof(*cp), 1, 0);
- print_cmd(cp); */
+ hpsa_print_cmd(h, "invalid command", cp);
+ dev_warn(d, "probably means device no longer present\n");
}
break;
case CMD_PROTOCOL_ERR:
- dev_warn(d, "cp %p has protocol error \n", cp);
+ hpsa_print_cmd(h, "protocol error", cp);
break;
case CMD_HARDWARE_ERR:
- /* cmd->result = DID_ERROR << 16; */
- dev_warn(d, "cp %p had hardware error\n", cp);
+ hpsa_print_cmd(h, "hardware error", cp);
break;
case CMD_CONNECTION_LOST:
- dev_warn(d, "cp %p had connection lost\n", cp);
+ hpsa_print_cmd(h, "connection lost", cp);
break;
case CMD_ABORTED:
- dev_warn(d, "cp %p was aborted\n", cp);
+ hpsa_print_cmd(h, "aborted", cp);
break;
case CMD_ABORT_FAILED:
- dev_warn(d, "cp %p reports abort failed\n", cp);
+ hpsa_print_cmd(h, "abort failed", cp);
break;
case CMD_UNSOLICITED_ABORT:
- dev_warn(d, "cp %p aborted due to an unsolicited abort\n", cp);
+ hpsa_print_cmd(h, "unsolicited abort", cp);
break;
case CMD_TIMEOUT:
- dev_warn(d, "cp %p timed out\n", cp);
+ hpsa_print_cmd(h, "timed out", cp);
break;
case CMD_UNABORTABLE:
- dev_warn(d, "Command unabortable\n");
+ hpsa_print_cmd(h, "unabortable", cp);
break;
default:
- dev_warn(d, "cp %p returned unknown status %x\n", cp,
+ hpsa_print_cmd(h, "unknown status", cp);
+ dev_warn(d, "Unknown command status %x\n",
ei->CommandStatus);
}
}
static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr,
- unsigned char page, unsigned char *buf,
+ u16 page, unsigned char *buf,
unsigned char bufsize)
{
int rc = IO_OK;
@@ -1577,7 +2120,7 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr,
hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE);
ei = c->err_info;
if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
- hpsa_scsi_interpret_error(c);
+ hpsa_scsi_interpret_error(h, c);
rc = -1;
}
out:
@@ -1585,7 +2128,39 @@ out:
return rc;
}
-static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr)
+static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h,
+ unsigned char *scsi3addr, unsigned char page,
+ struct bmic_controller_parameters *buf, size_t bufsize)
+{
+ int rc = IO_OK;
+ struct CommandList *c;
+ struct ErrorInfo *ei;
+
+ c = cmd_special_alloc(h);
+
+ if (c == NULL) { /* trouble... */
+ dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ return -ENOMEM;
+ }
+
+ if (fill_cmd(c, BMIC_SENSE_CONTROLLER_PARAMETERS, h, buf, bufsize,
+ page, scsi3addr, TYPE_CMD)) {
+ rc = -1;
+ goto out;
+ }
+ hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE);
+ ei = c->err_info;
+ if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
+ hpsa_scsi_interpret_error(h, c);
+ rc = -1;
+ }
+out:
+ cmd_special_free(h, c);
+ return rc;
+ }
+
+static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr,
+ u8 reset_type)
{
int rc = IO_OK;
struct CommandList *c;
@@ -1599,14 +2174,15 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr)
}
/* fill_cmd can't fail here, no data buffer to map. */
- (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h,
- NULL, 0, 0, scsi3addr, TYPE_MSG);
+ (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0,
+ scsi3addr, TYPE_MSG);
+ c->Request.CDB[1] = reset_type; /* fill_cmd defaults to LUN reset */
hpsa_scsi_do_simple_cmd_core(h, c);
/* no unmap needed here because no data xfer. */
ei = c->err_info;
if (ei->CommandStatus != 0) {
- hpsa_scsi_interpret_error(c);
+ hpsa_scsi_interpret_error(h, c);
rc = -1;
}
cmd_special_free(h, c);
@@ -1623,7 +2199,7 @@ static void hpsa_get_raid_level(struct ctlr_info *h,
buf = kzalloc(64, GFP_KERNEL);
if (!buf)
return;
- rc = hpsa_scsi_do_inquiry(h, scsi3addr, 0xC1, buf, 64);
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | 0xC1, buf, 64);
if (rc == 0)
*raid_level = buf[8];
if (*raid_level > RAID_UNKNOWN)
@@ -1632,6 +2208,204 @@ static void hpsa_get_raid_level(struct ctlr_info *h,
return;
}
+#define HPSA_MAP_DEBUG
+#ifdef HPSA_MAP_DEBUG
+static void hpsa_debug_map_buff(struct ctlr_info *h, int rc,
+ struct raid_map_data *map_buff)
+{
+ struct raid_map_disk_data *dd = &map_buff->data[0];
+ int map, row, col;
+ u16 map_cnt, row_cnt, disks_per_row;
+
+ if (rc != 0)
+ return;
+
+ /* Show details only if debugging has been activated. */
+ if (h->raid_offload_debug < 2)
+ return;
+
+ dev_info(&h->pdev->dev, "structure_size = %u\n",
+ le32_to_cpu(map_buff->structure_size));
+ dev_info(&h->pdev->dev, "volume_blk_size = %u\n",
+ le32_to_cpu(map_buff->volume_blk_size));
+ dev_info(&h->pdev->dev, "volume_blk_cnt = 0x%llx\n",
+ le64_to_cpu(map_buff->volume_blk_cnt));
+ dev_info(&h->pdev->dev, "physicalBlockShift = %u\n",
+ map_buff->phys_blk_shift);
+ dev_info(&h->pdev->dev, "parity_rotation_shift = %u\n",
+ map_buff->parity_rotation_shift);
+ dev_info(&h->pdev->dev, "strip_size = %u\n",
+ le16_to_cpu(map_buff->strip_size));
+ dev_info(&h->pdev->dev, "disk_starting_blk = 0x%llx\n",
+ le64_to_cpu(map_buff->disk_starting_blk));
+ dev_info(&h->pdev->dev, "disk_blk_cnt = 0x%llx\n",
+ le64_to_cpu(map_buff->disk_blk_cnt));
+ dev_info(&h->pdev->dev, "data_disks_per_row = %u\n",
+ le16_to_cpu(map_buff->data_disks_per_row));
+ dev_info(&h->pdev->dev, "metadata_disks_per_row = %u\n",
+ le16_to_cpu(map_buff->metadata_disks_per_row));
+ dev_info(&h->pdev->dev, "row_cnt = %u\n",
+ le16_to_cpu(map_buff->row_cnt));
+ dev_info(&h->pdev->dev, "layout_map_count = %u\n",
+ le16_to_cpu(map_buff->layout_map_count));
+ dev_info(&h->pdev->dev, "flags = %u\n",
+ le16_to_cpu(map_buff->flags));
+ if (map_buff->flags & RAID_MAP_FLAG_ENCRYPT_ON)
+ dev_info(&h->pdev->dev, "encrypytion = ON\n");
+ else
+ dev_info(&h->pdev->dev, "encrypytion = OFF\n");
+ dev_info(&h->pdev->dev, "dekindex = %u\n",
+ le16_to_cpu(map_buff->dekindex));
+
+ map_cnt = le16_to_cpu(map_buff->layout_map_count);
+ for (map = 0; map < map_cnt; map++) {
+ dev_info(&h->pdev->dev, "Map%u:\n", map);
+ row_cnt = le16_to_cpu(map_buff->row_cnt);
+ for (row = 0; row < row_cnt; row++) {
+ dev_info(&h->pdev->dev, " Row%u:\n", row);
+ disks_per_row =
+ le16_to_cpu(map_buff->data_disks_per_row);
+ for (col = 0; col < disks_per_row; col++, dd++)
+ dev_info(&h->pdev->dev,
+ " D%02u: h=0x%04x xor=%u,%u\n",
+ col, dd->ioaccel_handle,
+ dd->xor_mult[0], dd->xor_mult[1]);
+ disks_per_row =
+ le16_to_cpu(map_buff->metadata_disks_per_row);
+ for (col = 0; col < disks_per_row; col++, dd++)
+ dev_info(&h->pdev->dev,
+ " M%02u: h=0x%04x xor=%u,%u\n",
+ col, dd->ioaccel_handle,
+ dd->xor_mult[0], dd->xor_mult[1]);
+ }
+ }
+}
+#else
+static void hpsa_debug_map_buff(__attribute__((unused)) struct ctlr_info *h,
+ __attribute__((unused)) int rc,
+ __attribute__((unused)) struct raid_map_data *map_buff)
+{
+}
+#endif
+
+static int hpsa_get_raid_map(struct ctlr_info *h,
+ unsigned char *scsi3addr, struct hpsa_scsi_dev_t *this_device)
+{
+ int rc = 0;
+ struct CommandList *c;
+ struct ErrorInfo *ei;
+
+ c = cmd_special_alloc(h);
+ if (c == NULL) {
+ dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ return -ENOMEM;
+ }
+ if (fill_cmd(c, HPSA_GET_RAID_MAP, h, &this_device->raid_map,
+ sizeof(this_device->raid_map), 0,
+ scsi3addr, TYPE_CMD)) {
+ dev_warn(&h->pdev->dev, "Out of memory in hpsa_get_raid_map()\n");
+ cmd_special_free(h, c);
+ return -ENOMEM;
+ }
+ hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE);
+ ei = c->err_info;
+ if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
+ hpsa_scsi_interpret_error(h, c);
+ cmd_special_free(h, c);
+ return -1;
+ }
+ cmd_special_free(h, c);
+
+ /* @todo in the future, dynamically allocate RAID map memory */
+ if (le32_to_cpu(this_device->raid_map.structure_size) >
+ sizeof(this_device->raid_map)) {
+ dev_warn(&h->pdev->dev, "RAID map size is too large!\n");
+ rc = -1;
+ }
+ hpsa_debug_map_buff(h, rc, &this_device->raid_map);
+ return rc;
+}
+
+static int hpsa_vpd_page_supported(struct ctlr_info *h,
+ unsigned char scsi3addr[], u8 page)
+{
+ int rc;
+ int i;
+ int pages;
+ unsigned char *buf, bufsize;
+
+ buf = kzalloc(256, GFP_KERNEL);
+ if (!buf)
+ return 0;
+
+ /* Get the size of the page list first */
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr,
+ VPD_PAGE | HPSA_VPD_SUPPORTED_PAGES,
+ buf, HPSA_VPD_HEADER_SZ);
+ if (rc != 0)
+ goto exit_unsupported;
+ pages = buf[3];
+ if ((pages + HPSA_VPD_HEADER_SZ) <= 255)
+ bufsize = pages + HPSA_VPD_HEADER_SZ;
+ else
+ bufsize = 255;
+
+ /* Get the whole VPD page list */
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr,
+ VPD_PAGE | HPSA_VPD_SUPPORTED_PAGES,
+ buf, bufsize);
+ if (rc != 0)
+ goto exit_unsupported;
+
+ pages = buf[3];
+ for (i = 1; i <= pages; i++)
+ if (buf[3 + i] == page)
+ goto exit_supported;
+exit_unsupported:
+ kfree(buf);
+ return 0;
+exit_supported:
+ kfree(buf);
+ return 1;
+}
+
+static void hpsa_get_ioaccel_status(struct ctlr_info *h,
+ unsigned char *scsi3addr, struct hpsa_scsi_dev_t *this_device)
+{
+ int rc;
+ unsigned char *buf;
+ u8 ioaccel_status;
+
+ this_device->offload_config = 0;
+ this_device->offload_enabled = 0;
+
+ buf = kzalloc(64, GFP_KERNEL);
+ if (!buf)
+ return;
+ if (!hpsa_vpd_page_supported(h, scsi3addr, HPSA_VPD_LV_IOACCEL_STATUS))
+ goto out;
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr,
+ VPD_PAGE | HPSA_VPD_LV_IOACCEL_STATUS, buf, 64);
+ if (rc != 0)
+ goto out;
+
+#define IOACCEL_STATUS_BYTE 4
+#define OFFLOAD_CONFIGURED_BIT 0x01
+#define OFFLOAD_ENABLED_BIT 0x02
+ ioaccel_status = buf[IOACCEL_STATUS_BYTE];
+ this_device->offload_config =
+ !!(ioaccel_status & OFFLOAD_CONFIGURED_BIT);
+ if (this_device->offload_config) {
+ this_device->offload_enabled =
+ !!(ioaccel_status & OFFLOAD_ENABLED_BIT);
+ if (hpsa_get_raid_map(h, scsi3addr, this_device))
+ this_device->offload_enabled = 0;
+ }
+out:
+ kfree(buf);
+ return;
+}
+
/* Get the device id from inquiry page 0x83 */
static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr,
unsigned char *device_id, int buflen)
@@ -1644,7 +2418,7 @@ static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr,
buf = kzalloc(64, GFP_KERNEL);
if (!buf)
return -1;
- rc = hpsa_scsi_do_inquiry(h, scsi3addr, 0x83, buf, 64);
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | 0x83, buf, 64);
if (rc == 0)
memcpy(device_id, &buf[8], buflen);
kfree(buf);
@@ -1678,8 +2452,16 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical,
ei = c->err_info;
if (ei->CommandStatus != 0 &&
ei->CommandStatus != CMD_DATA_UNDERRUN) {
- hpsa_scsi_interpret_error(c);
+ hpsa_scsi_interpret_error(h, c);
rc = -1;
+ } else {
+ if (buf->extended_response_flag != extended_response) {
+ dev_err(&h->pdev->dev,
+ "report luns requested format %u, got %u\n",
+ extended_response,
+ buf->extended_response_flag);
+ rc = -1;
+ }
}
out:
cmd_special_free(h, c);
@@ -1707,6 +2489,117 @@ static inline void hpsa_set_bus_target_lun(struct hpsa_scsi_dev_t *device,
device->lun = lun;
}
+/* Use VPD inquiry to get details of volume status */
+static int hpsa_get_volume_status(struct ctlr_info *h,
+ unsigned char scsi3addr[])
+{
+ int rc;
+ int status;
+ int size;
+ unsigned char *buf;
+
+ buf = kzalloc(64, GFP_KERNEL);
+ if (!buf)
+ return HPSA_VPD_LV_STATUS_UNSUPPORTED;
+
+ /* Does controller have VPD for logical volume status? */
+ if (!hpsa_vpd_page_supported(h, scsi3addr, HPSA_VPD_LV_STATUS)) {
+ dev_warn(&h->pdev->dev, "Logical volume status VPD page is unsupported.\n");
+ goto exit_failed;
+ }
+
+ /* Get the size of the VPD return buffer */
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | HPSA_VPD_LV_STATUS,
+ buf, HPSA_VPD_HEADER_SZ);
+ if (rc != 0) {
+ dev_warn(&h->pdev->dev, "Logical volume status VPD inquiry failed.\n");
+ goto exit_failed;
+ }
+ size = buf[3];
+
+ /* Now get the whole VPD buffer */
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | HPSA_VPD_LV_STATUS,
+ buf, size + HPSA_VPD_HEADER_SZ);
+ if (rc != 0) {
+ dev_warn(&h->pdev->dev, "Logical volume status VPD inquiry failed.\n");
+ goto exit_failed;
+ }
+ status = buf[4]; /* status byte */
+
+ kfree(buf);
+ return status;
+exit_failed:
+ kfree(buf);
+ return HPSA_VPD_LV_STATUS_UNSUPPORTED;
+}
+
+/* Determine offline status of a volume.
+ * Return either:
+ * 0 (not offline)
+ * -1 (offline for unknown reasons)
+ * # (integer code indicating one of several NOT READY states
+ * describing why a volume is to be kept offline)
+ */
+static unsigned char hpsa_volume_offline(struct ctlr_info *h,
+ unsigned char scsi3addr[])
+{
+ struct CommandList *c;
+ unsigned char *sense, sense_key, asc, ascq;
+ int ldstat = 0;
+ u16 cmd_status;
+ u8 scsi_status;
+#define ASC_LUN_NOT_READY 0x04
+#define ASCQ_LUN_NOT_READY_FORMAT_IN_PROGRESS 0x04
+#define ASCQ_LUN_NOT_READY_INITIALIZING_CMD_REQ 0x02
+
+ c = cmd_alloc(h);
+ if (!c)
+ return 0;
+ (void) fill_cmd(c, TEST_UNIT_READY, h, NULL, 0, 0, scsi3addr, TYPE_CMD);
+ hpsa_scsi_do_simple_cmd_core(h, c);
+ sense = c->err_info->SenseInfo;
+ sense_key = sense[2];
+ asc = sense[12];
+ ascq = sense[13];
+ cmd_status = c->err_info->CommandStatus;
+ scsi_status = c->err_info->ScsiStatus;
+ cmd_free(h, c);
+ /* Is the volume 'not ready'? */
+ if (cmd_status != CMD_TARGET_STATUS ||
+ scsi_status != SAM_STAT_CHECK_CONDITION ||
+ sense_key != NOT_READY ||
+ asc != ASC_LUN_NOT_READY) {
+ return 0;
+ }
+
+ /* Determine the reason for not ready state */
+ ldstat = hpsa_get_volume_status(h, scsi3addr);
+
+ /* Keep volume offline in certain cases: */
+ switch (ldstat) {
+ case HPSA_LV_UNDERGOING_ERASE:
+ case HPSA_LV_UNDERGOING_RPI:
+ case HPSA_LV_PENDING_RPI:
+ case HPSA_LV_ENCRYPTED_NO_KEY:
+ case HPSA_LV_PLAINTEXT_IN_ENCRYPT_ONLY_CONTROLLER:
+ case HPSA_LV_UNDERGOING_ENCRYPTION:
+ case HPSA_LV_UNDERGOING_ENCRYPTION_REKEYING:
+ case HPSA_LV_ENCRYPTED_IN_NON_ENCRYPTED_CONTROLLER:
+ return ldstat;
+ case HPSA_VPD_LV_STATUS_UNSUPPORTED:
+ /* If VPD status page isn't available,
+ * use ASC/ASCQ to determine state
+ */
+ if ((ascq == ASCQ_LUN_NOT_READY_FORMAT_IN_PROGRESS) ||
+ (ascq == ASCQ_LUN_NOT_READY_INITIALIZING_CMD_REQ))
+ return ldstat;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
static int hpsa_update_device_info(struct ctlr_info *h,
unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device,
unsigned char *is_OBDR_device)
@@ -1745,10 +2638,18 @@ static int hpsa_update_device_info(struct ctlr_info *h,
sizeof(this_device->device_id));
if (this_device->devtype == TYPE_DISK &&
- is_logical_dev_addr_mode(scsi3addr))
+ is_logical_dev_addr_mode(scsi3addr)) {
hpsa_get_raid_level(h, scsi3addr, &this_device->raid_level);
- else
+ if (h->fw_support & MISC_FW_RAID_OFFLOAD_BASIC)
+ hpsa_get_ioaccel_status(h, scsi3addr, this_device);
+ this_device->volume_offline =
+ hpsa_volume_offline(h, scsi3addr);
+ } else {
this_device->raid_level = RAID_UNKNOWN;
+ this_device->offload_config = 0;
+ this_device->offload_enabled = 0;
+ this_device->volume_offline = 0;
+ }
if (is_OBDR_device) {
/* See if this is a One-Button-Disaster-Recovery device
@@ -1878,6 +2779,105 @@ static int add_ext_target_dev(struct ctlr_info *h,
}
/*
+ * Get address of physical disk used for an ioaccel2 mode command:
+ * 1. Extract ioaccel2 handle from the command.
+ * 2. Find a matching ioaccel2 handle from list of physical disks.
+ * 3. Return:
+ * 1 and set scsi3addr to address of matching physical
+ * 0 if no matching physical disk was found.
+ */
+static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h,
+ struct CommandList *ioaccel2_cmd_to_abort, unsigned char *scsi3addr)
+{
+ struct ReportExtendedLUNdata *physicals = NULL;
+ int responsesize = 24; /* size of physical extended response */
+ int extended = 2; /* flag forces reporting 'other dev info'. */
+ int reportsize = sizeof(*physicals) + HPSA_MAX_PHYS_LUN * responsesize;
+ u32 nphysicals = 0; /* number of reported physical devs */
+ int found = 0; /* found match (1) or not (0) */
+ u32 find; /* handle we need to match */
+ int i;
+ struct scsi_cmnd *scmd; /* scsi command within request being aborted */
+ struct hpsa_scsi_dev_t *d; /* device of request being aborted */
+ struct io_accel2_cmd *c2a; /* ioaccel2 command to abort */
+ u32 it_nexus; /* 4 byte device handle for the ioaccel2 cmd */
+ u32 scsi_nexus; /* 4 byte device handle for the ioaccel2 cmd */
+
+ if (ioaccel2_cmd_to_abort->cmd_type != CMD_IOACCEL2)
+ return 0; /* no match */
+
+ /* point to the ioaccel2 device handle */
+ c2a = &h->ioaccel2_cmd_pool[ioaccel2_cmd_to_abort->cmdindex];
+ if (c2a == NULL)
+ return 0; /* no match */
+
+ scmd = (struct scsi_cmnd *) ioaccel2_cmd_to_abort->scsi_cmd;
+ if (scmd == NULL)
+ return 0; /* no match */
+
+ d = scmd->device->hostdata;
+ if (d == NULL)
+ return 0; /* no match */
+
+ it_nexus = cpu_to_le32((u32) d->ioaccel_handle);
+ scsi_nexus = cpu_to_le32((u32) c2a->scsi_nexus);
+ find = c2a->scsi_nexus;
+
+ if (h->raid_offload_debug > 0)
+ dev_info(&h->pdev->dev,
+ "%s: scsi_nexus:0x%08x device id: 0x%02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x\n",
+ __func__, scsi_nexus,
+ d->device_id[0], d->device_id[1], d->device_id[2],
+ d->device_id[3], d->device_id[4], d->device_id[5],
+ d->device_id[6], d->device_id[7], d->device_id[8],
+ d->device_id[9], d->device_id[10], d->device_id[11],
+ d->device_id[12], d->device_id[13], d->device_id[14],
+ d->device_id[15]);
+
+ /* Get the list of physical devices */
+ physicals = kzalloc(reportsize, GFP_KERNEL);
+ if (hpsa_scsi_do_report_phys_luns(h, (struct ReportLUNdata *) physicals,
+ reportsize, extended)) {
+ dev_err(&h->pdev->dev,
+ "Can't lookup %s device handle: report physical LUNs failed.\n",
+ "HP SSD Smart Path");
+ kfree(physicals);
+ return 0;
+ }
+ nphysicals = be32_to_cpu(*((__be32 *)physicals->LUNListLength)) /
+ responsesize;
+
+
+ /* find ioaccel2 handle in list of physicals: */
+ for (i = 0; i < nphysicals; i++) {
+ /* handle is in bytes 28-31 of each lun */
+ if (memcmp(&((struct ReportExtendedLUNdata *)
+ physicals)->LUN[i][20], &find, 4) != 0) {
+ continue; /* didn't match */
+ }
+ found = 1;
+ memcpy(scsi3addr, &((struct ReportExtendedLUNdata *)
+ physicals)->LUN[i][0], 8);
+ if (h->raid_offload_debug > 0)
+ dev_info(&h->pdev->dev,
+ "%s: Searched h=0x%08x, Found h=0x%08x, scsiaddr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ __func__, find,
+ ((struct ReportExtendedLUNdata *)
+ physicals)->LUN[i][20],
+ scsi3addr[0], scsi3addr[1], scsi3addr[2],
+ scsi3addr[3], scsi3addr[4], scsi3addr[5],
+ scsi3addr[6], scsi3addr[7]);
+ break; /* found it */
+ }
+
+ kfree(physicals);
+ if (found)
+ return 1;
+ else
+ return 0;
+
+}
+/*
* Do CISS_REPORT_PHYS and CISS_REPORT_LOG. Data is returned in physdev,
* logdev. The number of luns in physdev and logdev are returned in
* *nphysicals and *nlogicals, respectively.
@@ -1885,14 +2885,26 @@ static int add_ext_target_dev(struct ctlr_info *h,
*/
static int hpsa_gather_lun_info(struct ctlr_info *h,
int reportlunsize,
- struct ReportLUNdata *physdev, u32 *nphysicals,
+ struct ReportLUNdata *physdev, u32 *nphysicals, int *physical_mode,
struct ReportLUNdata *logdev, u32 *nlogicals)
{
- if (hpsa_scsi_do_report_phys_luns(h, physdev, reportlunsize, 0)) {
+ int physical_entry_size = 8;
+
+ *physical_mode = 0;
+
+ /* For I/O accelerator mode we need to read physical device handles */
+ if (h->transMethod & CFGTBL_Trans_io_accel1 ||
+ h->transMethod & CFGTBL_Trans_io_accel2) {
+ *physical_mode = HPSA_REPORT_PHYS_EXTENDED;
+ physical_entry_size = 24;
+ }
+ if (hpsa_scsi_do_report_phys_luns(h, physdev, reportlunsize,
+ *physical_mode)) {
dev_err(&h->pdev->dev, "report physical LUNs failed.\n");
return -1;
}
- *nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) / 8;
+ *nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) /
+ physical_entry_size;
if (*nphysicals > HPSA_MAX_PHYS_LUN) {
dev_warn(&h->pdev->dev, "maximum physical LUNs (%d) exceeded."
" %d LUNs ignored.\n", HPSA_MAX_PHYS_LUN,
@@ -1923,7 +2935,8 @@ static int hpsa_gather_lun_info(struct ctlr_info *h,
}
u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position, int i,
- int nphysicals, int nlogicals, struct ReportLUNdata *physdev_list,
+ int nphysicals, int nlogicals,
+ struct ReportExtendedLUNdata *physdev_list,
struct ReportLUNdata *logdev_list)
{
/* Helper function, figure out where the LUN ID info is coming from
@@ -1947,6 +2960,24 @@ u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position, int i,
return NULL;
}
+static int hpsa_hba_mode_enabled(struct ctlr_info *h)
+{
+ int rc;
+ struct bmic_controller_parameters *ctlr_params;
+ ctlr_params = kzalloc(sizeof(struct bmic_controller_parameters),
+ GFP_KERNEL);
+
+ if (!ctlr_params)
+ return 0;
+ rc = hpsa_bmic_ctrl_mode_sense(h, RAID_CTLR_LUNID, 0, ctlr_params,
+ sizeof(struct bmic_controller_parameters));
+ if (rc != 0) {
+ kfree(ctlr_params);
+ return 0;
+ }
+ return ctlr_params->nvram_flags & (1 << 3) ? 1 : 0;
+}
+
static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
{
/* the idea here is we could get notified
@@ -1959,16 +2990,18 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
* tell which devices we already know about, vs. new
* devices, vs. disappearing devices.
*/
- struct ReportLUNdata *physdev_list = NULL;
+ struct ReportExtendedLUNdata *physdev_list = NULL;
struct ReportLUNdata *logdev_list = NULL;
u32 nphysicals = 0;
u32 nlogicals = 0;
+ int physical_mode = 0;
u32 ndev_allocated = 0;
struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice;
int ncurrent = 0;
- int reportlunsize = sizeof(*physdev_list) + HPSA_MAX_PHYS_LUN * 8;
+ int reportlunsize = sizeof(*physdev_list) + HPSA_MAX_PHYS_LUN * 24;
int i, n_ext_target_devs, ndevs_to_allocate;
int raid_ctlr_position;
+ u8 rescan_hba_mode;
DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS);
currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_DEVICES, GFP_KERNEL);
@@ -1982,8 +3015,18 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
}
memset(lunzerobits, 0, sizeof(lunzerobits));
- if (hpsa_gather_lun_info(h, reportlunsize, physdev_list, &nphysicals,
- logdev_list, &nlogicals))
+ rescan_hba_mode = hpsa_hba_mode_enabled(h);
+
+ if (!h->hba_mode_enabled && rescan_hba_mode)
+ dev_warn(&h->pdev->dev, "HBA mode enabled\n");
+ else if (h->hba_mode_enabled && !rescan_hba_mode)
+ dev_warn(&h->pdev->dev, "HBA mode disabled\n");
+
+ h->hba_mode_enabled = rescan_hba_mode;
+
+ if (hpsa_gather_lun_info(h, reportlunsize,
+ (struct ReportLUNdata *) physdev_list, &nphysicals,
+ &physical_mode, logdev_list, &nlogicals))
goto out;
/* We might see up to the maximum number of logical and physical disks
@@ -2064,9 +3107,28 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
ncurrent++;
break;
case TYPE_DISK:
- if (i < nphysicals)
+ if (h->hba_mode_enabled) {
+ /* never use raid mapper in HBA mode */
+ this_device->offload_enabled = 0;
+ ncurrent++;
break;
- ncurrent++;
+ } else if (h->acciopath_status) {
+ if (i >= nphysicals) {
+ ncurrent++;
+ break;
+ }
+ } else {
+ if (i < nphysicals)
+ break;
+ ncurrent++;
+ break;
+ }
+ if (physical_mode == HPSA_REPORT_PHYS_EXTENDED) {
+ memcpy(&this_device->ioaccel_handle,
+ &lunaddrbytes[20],
+ sizeof(this_device->ioaccel_handle));
+ ncurrent++;
+ }
break;
case TYPE_TAPE:
case TYPE_MEDIUM_CHANGER:
@@ -2136,7 +3198,7 @@ static int hpsa_scatter_gather(struct ctlr_info *h,
curr_sg->Addr.lower = (u32) (addr64 & 0x0FFFFFFFFULL);
curr_sg->Addr.upper = (u32) ((addr64 >> 32) & 0x0FFFFFFFFULL);
curr_sg->Len = len;
- curr_sg->Ext = 0; /* we are not chaining */
+ curr_sg->Ext = (i < scsi_sg_count(cmd) - 1) ? 0 : HPSA_SG_LAST;
curr_sg++;
}
@@ -2160,6 +3222,726 @@ sglist_finished:
return 0;
}
+#define IO_ACCEL_INELIGIBLE (1)
+static int fixup_ioaccel_cdb(u8 *cdb, int *cdb_len)
+{
+ int is_write = 0;
+ u32 block;
+ u32 block_cnt;
+
+ /* Perform some CDB fixups if needed using 10 byte reads/writes only */
+ switch (cdb[0]) {
+ case WRITE_6:
+ case WRITE_12:
+ is_write = 1;
+ case READ_6:
+ case READ_12:
+ if (*cdb_len == 6) {
+ block = (((u32) cdb[2]) << 8) | cdb[3];
+ block_cnt = cdb[4];
+ } else {
+ BUG_ON(*cdb_len != 12);
+ block = (((u32) cdb[2]) << 24) |
+ (((u32) cdb[3]) << 16) |
+ (((u32) cdb[4]) << 8) |
+ cdb[5];
+ block_cnt =
+ (((u32) cdb[6]) << 24) |
+ (((u32) cdb[7]) << 16) |
+ (((u32) cdb[8]) << 8) |
+ cdb[9];
+ }
+ if (block_cnt > 0xffff)
+ return IO_ACCEL_INELIGIBLE;
+
+ cdb[0] = is_write ? WRITE_10 : READ_10;
+ cdb[1] = 0;
+ cdb[2] = (u8) (block >> 24);
+ cdb[3] = (u8) (block >> 16);
+ cdb[4] = (u8) (block >> 8);
+ cdb[5] = (u8) (block);
+ cdb[6] = 0;
+ cdb[7] = (u8) (block_cnt >> 8);
+ cdb[8] = (u8) (block_cnt);
+ cdb[9] = 0;
+ *cdb_len = 10;
+ break;
+ }
+ return 0;
+}
+
+static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h,
+ struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
+ u8 *scsi3addr)
+{
+ struct scsi_cmnd *cmd = c->scsi_cmd;
+ struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[c->cmdindex];
+ unsigned int len;
+ unsigned int total_len = 0;
+ struct scatterlist *sg;
+ u64 addr64;
+ int use_sg, i;
+ struct SGDescriptor *curr_sg;
+ u32 control = IOACCEL1_CONTROL_SIMPLEQUEUE;
+
+ /* TODO: implement chaining support */
+ if (scsi_sg_count(cmd) > h->ioaccel_maxsg)
+ return IO_ACCEL_INELIGIBLE;
+
+ BUG_ON(cmd->cmd_len > IOACCEL1_IOFLAGS_CDBLEN_MAX);
+
+ if (fixup_ioaccel_cdb(cdb, &cdb_len))
+ return IO_ACCEL_INELIGIBLE;
+
+ c->cmd_type = CMD_IOACCEL1;
+
+ /* Adjust the DMA address to point to the accelerated command buffer */
+ c->busaddr = (u32) h->ioaccel_cmd_pool_dhandle +
+ (c->cmdindex * sizeof(*cp));
+ BUG_ON(c->busaddr & 0x0000007F);
+
+ use_sg = scsi_dma_map(cmd);
+ if (use_sg < 0)
+ return use_sg;
+
+ if (use_sg) {
+ curr_sg = cp->SG;
+ scsi_for_each_sg(cmd, sg, use_sg, i) {
+ addr64 = (u64) sg_dma_address(sg);
+ len = sg_dma_len(sg);
+ total_len += len;
+ curr_sg->Addr.lower = (u32) (addr64 & 0x0FFFFFFFFULL);
+ curr_sg->Addr.upper =
+ (u32) ((addr64 >> 32) & 0x0FFFFFFFFULL);
+ curr_sg->Len = len;
+
+ if (i == (scsi_sg_count(cmd) - 1))
+ curr_sg->Ext = HPSA_SG_LAST;
+ else
+ curr_sg->Ext = 0; /* we are not chaining */
+ curr_sg++;
+ }
+
+ switch (cmd->sc_data_direction) {
+ case DMA_TO_DEVICE:
+ control |= IOACCEL1_CONTROL_DATA_OUT;
+ break;
+ case DMA_FROM_DEVICE:
+ control |= IOACCEL1_CONTROL_DATA_IN;
+ break;
+ case DMA_NONE:
+ control |= IOACCEL1_CONTROL_NODATAXFER;
+ break;
+ default:
+ dev_err(&h->pdev->dev, "unknown data direction: %d\n",
+ cmd->sc_data_direction);
+ BUG();
+ break;
+ }
+ } else {
+ control |= IOACCEL1_CONTROL_NODATAXFER;
+ }
+
+ c->Header.SGList = use_sg;
+ /* Fill out the command structure to submit */
+ cp->dev_handle = ioaccel_handle & 0xFFFF;
+ cp->transfer_len = total_len;
+ cp->io_flags = IOACCEL1_IOFLAGS_IO_REQ |
+ (cdb_len & IOACCEL1_IOFLAGS_CDBLEN_MASK);
+ cp->control = control;
+ memcpy(cp->CDB, cdb, cdb_len);
+ memcpy(cp->CISS_LUN, scsi3addr, 8);
+ /* Tag was already set at init time. */
+ enqueue_cmd_and_start_io(h, c);
+ return 0;
+}
+
+/*
+ * Queue a command directly to a device behind the controller using the
+ * I/O accelerator path.
+ */
+static int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ struct scsi_cmnd *cmd = c->scsi_cmd;
+ struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
+
+ return hpsa_scsi_ioaccel_queue_command(h, c, dev->ioaccel_handle,
+ cmd->cmnd, cmd->cmd_len, dev->scsi3addr);
+}
+
+/*
+ * Set encryption parameters for the ioaccel2 request
+ */
+static void set_encrypt_ioaccel2(struct ctlr_info *h,
+ struct CommandList *c, struct io_accel2_cmd *cp)
+{
+ struct scsi_cmnd *cmd = c->scsi_cmd;
+ struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
+ struct raid_map_data *map = &dev->raid_map;
+ u64 first_block;
+
+ BUG_ON(!(dev->offload_config && dev->offload_enabled));
+
+ /* Are we doing encryption on this device */
+ if (!(map->flags & RAID_MAP_FLAG_ENCRYPT_ON))
+ return;
+ /* Set the data encryption key index. */
+ cp->dekindex = map->dekindex;
+
+ /* Set the encryption enable flag, encoded into direction field. */
+ cp->direction |= IOACCEL2_DIRECTION_ENCRYPT_MASK;
+
+ /* Set encryption tweak values based on logical block address
+ * If block size is 512, tweak value is LBA.
+ * For other block sizes, tweak is (LBA * block size)/ 512)
+ */
+ switch (cmd->cmnd[0]) {
+ /* Required? 6-byte cdbs eliminated by fixup_ioaccel_cdb */
+ case WRITE_6:
+ case READ_6:
+ if (map->volume_blk_size == 512) {
+ cp->tweak_lower =
+ (((u32) cmd->cmnd[2]) << 8) |
+ cmd->cmnd[3];
+ cp->tweak_upper = 0;
+ } else {
+ first_block =
+ (((u64) cmd->cmnd[2]) << 8) |
+ cmd->cmnd[3];
+ first_block = (first_block * map->volume_blk_size)/512;
+ cp->tweak_lower = (u32)first_block;
+ cp->tweak_upper = (u32)(first_block >> 32);
+ }
+ break;
+ case WRITE_10:
+ case READ_10:
+ if (map->volume_blk_size == 512) {
+ cp->tweak_lower =
+ (((u32) cmd->cmnd[2]) << 24) |
+ (((u32) cmd->cmnd[3]) << 16) |
+ (((u32) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ cp->tweak_upper = 0;
+ } else {
+ first_block =
+ (((u64) cmd->cmnd[2]) << 24) |
+ (((u64) cmd->cmnd[3]) << 16) |
+ (((u64) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ first_block = (first_block * map->volume_blk_size)/512;
+ cp->tweak_lower = (u32)first_block;
+ cp->tweak_upper = (u32)(first_block >> 32);
+ }
+ break;
+ /* Required? 12-byte cdbs eliminated by fixup_ioaccel_cdb */
+ case WRITE_12:
+ case READ_12:
+ if (map->volume_blk_size == 512) {
+ cp->tweak_lower =
+ (((u32) cmd->cmnd[2]) << 24) |
+ (((u32) cmd->cmnd[3]) << 16) |
+ (((u32) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ cp->tweak_upper = 0;
+ } else {
+ first_block =
+ (((u64) cmd->cmnd[2]) << 24) |
+ (((u64) cmd->cmnd[3]) << 16) |
+ (((u64) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ first_block = (first_block * map->volume_blk_size)/512;
+ cp->tweak_lower = (u32)first_block;
+ cp->tweak_upper = (u32)(first_block >> 32);
+ }
+ break;
+ case WRITE_16:
+ case READ_16:
+ if (map->volume_blk_size == 512) {
+ cp->tweak_lower =
+ (((u32) cmd->cmnd[6]) << 24) |
+ (((u32) cmd->cmnd[7]) << 16) |
+ (((u32) cmd->cmnd[8]) << 8) |
+ cmd->cmnd[9];
+ cp->tweak_upper =
+ (((u32) cmd->cmnd[2]) << 24) |
+ (((u32) cmd->cmnd[3]) << 16) |
+ (((u32) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ } else {
+ first_block =
+ (((u64) cmd->cmnd[2]) << 56) |
+ (((u64) cmd->cmnd[3]) << 48) |
+ (((u64) cmd->cmnd[4]) << 40) |
+ (((u64) cmd->cmnd[5]) << 32) |
+ (((u64) cmd->cmnd[6]) << 24) |
+ (((u64) cmd->cmnd[7]) << 16) |
+ (((u64) cmd->cmnd[8]) << 8) |
+ cmd->cmnd[9];
+ first_block = (first_block * map->volume_blk_size)/512;
+ cp->tweak_lower = (u32)first_block;
+ cp->tweak_upper = (u32)(first_block >> 32);
+ }
+ break;
+ default:
+ dev_err(&h->pdev->dev,
+ "ERROR: %s: IOACCEL request CDB size not supported for encryption\n",
+ __func__);
+ BUG();
+ break;
+ }
+}
+
+static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
+ struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
+ u8 *scsi3addr)
+{
+ struct scsi_cmnd *cmd = c->scsi_cmd;
+ struct io_accel2_cmd *cp = &h->ioaccel2_cmd_pool[c->cmdindex];
+ struct ioaccel2_sg_element *curr_sg;
+ int use_sg, i;
+ struct scatterlist *sg;
+ u64 addr64;
+ u32 len;
+ u32 total_len = 0;
+
+ if (scsi_sg_count(cmd) > h->ioaccel_maxsg)
+ return IO_ACCEL_INELIGIBLE;
+
+ if (fixup_ioaccel_cdb(cdb, &cdb_len))
+ return IO_ACCEL_INELIGIBLE;
+ c->cmd_type = CMD_IOACCEL2;
+ /* Adjust the DMA address to point to the accelerated command buffer */
+ c->busaddr = (u32) h->ioaccel2_cmd_pool_dhandle +
+ (c->cmdindex * sizeof(*cp));
+ BUG_ON(c->busaddr & 0x0000007F);
+
+ memset(cp, 0, sizeof(*cp));
+ cp->IU_type = IOACCEL2_IU_TYPE;
+
+ use_sg = scsi_dma_map(cmd);
+ if (use_sg < 0)
+ return use_sg;
+
+ if (use_sg) {
+ BUG_ON(use_sg > IOACCEL2_MAXSGENTRIES);
+ curr_sg = cp->sg;
+ scsi_for_each_sg(cmd, sg, use_sg, i) {
+ addr64 = (u64) sg_dma_address(sg);
+ len = sg_dma_len(sg);
+ total_len += len;
+ curr_sg->address = cpu_to_le64(addr64);
+ curr_sg->length = cpu_to_le32(len);
+ curr_sg->reserved[0] = 0;
+ curr_sg->reserved[1] = 0;
+ curr_sg->reserved[2] = 0;
+ curr_sg->chain_indicator = 0;
+ curr_sg++;
+ }
+
+ switch (cmd->sc_data_direction) {
+ case DMA_TO_DEVICE:
+ cp->direction &= ~IOACCEL2_DIRECTION_MASK;
+ cp->direction |= IOACCEL2_DIR_DATA_OUT;
+ break;
+ case DMA_FROM_DEVICE:
+ cp->direction &= ~IOACCEL2_DIRECTION_MASK;
+ cp->direction |= IOACCEL2_DIR_DATA_IN;
+ break;
+ case DMA_NONE:
+ cp->direction &= ~IOACCEL2_DIRECTION_MASK;
+ cp->direction |= IOACCEL2_DIR_NO_DATA;
+ break;
+ default:
+ dev_err(&h->pdev->dev, "unknown data direction: %d\n",
+ cmd->sc_data_direction);
+ BUG();
+ break;
+ }
+ } else {
+ cp->direction &= ~IOACCEL2_DIRECTION_MASK;
+ cp->direction |= IOACCEL2_DIR_NO_DATA;
+ }
+
+ /* Set encryption parameters, if necessary */
+ set_encrypt_ioaccel2(h, c, cp);
+
+ cp->scsi_nexus = ioaccel_handle;
+ cp->Tag = (c->cmdindex << DIRECT_LOOKUP_SHIFT) |
+ DIRECT_LOOKUP_BIT;
+ memcpy(cp->cdb, cdb, sizeof(cp->cdb));
+
+ /* fill in sg elements */
+ cp->sg_count = (u8) use_sg;
+
+ cp->data_len = cpu_to_le32(total_len);
+ cp->err_ptr = cpu_to_le64(c->busaddr +
+ offsetof(struct io_accel2_cmd, error_data));
+ cp->err_len = cpu_to_le32((u32) sizeof(cp->error_data));
+
+ enqueue_cmd_and_start_io(h, c);
+ return 0;
+}
+
+/*
+ * Queue a command to the correct I/O accelerator path.
+ */
+static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
+ struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
+ u8 *scsi3addr)
+{
+ if (h->transMethod & CFGTBL_Trans_io_accel1)
+ return hpsa_scsi_ioaccel1_queue_command(h, c, ioaccel_handle,
+ cdb, cdb_len, scsi3addr);
+ else
+ return hpsa_scsi_ioaccel2_queue_command(h, c, ioaccel_handle,
+ cdb, cdb_len, scsi3addr);
+}
+
+static void raid_map_helper(struct raid_map_data *map,
+ int offload_to_mirror, u32 *map_index, u32 *current_group)
+{
+ if (offload_to_mirror == 0) {
+ /* use physical disk in the first mirrored group. */
+ *map_index %= map->data_disks_per_row;
+ return;
+ }
+ do {
+ /* determine mirror group that *map_index indicates */
+ *current_group = *map_index / map->data_disks_per_row;
+ if (offload_to_mirror == *current_group)
+ continue;
+ if (*current_group < (map->layout_map_count - 1)) {
+ /* select map index from next group */
+ *map_index += map->data_disks_per_row;
+ (*current_group)++;
+ } else {
+ /* select map index from first group */
+ *map_index %= map->data_disks_per_row;
+ *current_group = 0;
+ }
+ } while (offload_to_mirror != *current_group);
+}
+
+/*
+ * Attempt to perform offload RAID mapping for a logical volume I/O.
+ */
+static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ struct scsi_cmnd *cmd = c->scsi_cmd;
+ struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
+ struct raid_map_data *map = &dev->raid_map;
+ struct raid_map_disk_data *dd = &map->data[0];
+ int is_write = 0;
+ u32 map_index;
+ u64 first_block, last_block;
+ u32 block_cnt;
+ u32 blocks_per_row;
+ u64 first_row, last_row;
+ u32 first_row_offset, last_row_offset;
+ u32 first_column, last_column;
+ u64 r0_first_row, r0_last_row;
+ u32 r5or6_blocks_per_row;
+ u64 r5or6_first_row, r5or6_last_row;
+ u32 r5or6_first_row_offset, r5or6_last_row_offset;
+ u32 r5or6_first_column, r5or6_last_column;
+ u32 total_disks_per_row;
+ u32 stripesize;
+ u32 first_group, last_group, current_group;
+ u32 map_row;
+ u32 disk_handle;
+ u64 disk_block;
+ u32 disk_block_cnt;
+ u8 cdb[16];
+ u8 cdb_len;
+#if BITS_PER_LONG == 32
+ u64 tmpdiv;
+#endif
+ int offload_to_mirror;
+
+ BUG_ON(!(dev->offload_config && dev->offload_enabled));
+
+ /* check for valid opcode, get LBA and block count */
+ switch (cmd->cmnd[0]) {
+ case WRITE_6:
+ is_write = 1;
+ case READ_6:
+ first_block =
+ (((u64) cmd->cmnd[2]) << 8) |
+ cmd->cmnd[3];
+ block_cnt = cmd->cmnd[4];
+ break;
+ case WRITE_10:
+ is_write = 1;
+ case READ_10:
+ first_block =
+ (((u64) cmd->cmnd[2]) << 24) |
+ (((u64) cmd->cmnd[3]) << 16) |
+ (((u64) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ block_cnt =
+ (((u32) cmd->cmnd[7]) << 8) |
+ cmd->cmnd[8];
+ break;
+ case WRITE_12:
+ is_write = 1;
+ case READ_12:
+ first_block =
+ (((u64) cmd->cmnd[2]) << 24) |
+ (((u64) cmd->cmnd[3]) << 16) |
+ (((u64) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ block_cnt =
+ (((u32) cmd->cmnd[6]) << 24) |
+ (((u32) cmd->cmnd[7]) << 16) |
+ (((u32) cmd->cmnd[8]) << 8) |
+ cmd->cmnd[9];
+ break;
+ case WRITE_16:
+ is_write = 1;
+ case READ_16:
+ first_block =
+ (((u64) cmd->cmnd[2]) << 56) |
+ (((u64) cmd->cmnd[3]) << 48) |
+ (((u64) cmd->cmnd[4]) << 40) |
+ (((u64) cmd->cmnd[5]) << 32) |
+ (((u64) cmd->cmnd[6]) << 24) |
+ (((u64) cmd->cmnd[7]) << 16) |
+ (((u64) cmd->cmnd[8]) << 8) |
+ cmd->cmnd[9];
+ block_cnt =
+ (((u32) cmd->cmnd[10]) << 24) |
+ (((u32) cmd->cmnd[11]) << 16) |
+ (((u32) cmd->cmnd[12]) << 8) |
+ cmd->cmnd[13];
+ break;
+ default:
+ return IO_ACCEL_INELIGIBLE; /* process via normal I/O path */
+ }
+ BUG_ON(block_cnt == 0);
+ last_block = first_block + block_cnt - 1;
+
+ /* check for write to non-RAID-0 */
+ if (is_write && dev->raid_level != 0)
+ return IO_ACCEL_INELIGIBLE;
+
+ /* check for invalid block or wraparound */
+ if (last_block >= map->volume_blk_cnt || last_block < first_block)
+ return IO_ACCEL_INELIGIBLE;
+
+ /* calculate stripe information for the request */
+ blocks_per_row = map->data_disks_per_row * map->strip_size;
+#if BITS_PER_LONG == 32
+ tmpdiv = first_block;
+ (void) do_div(tmpdiv, blocks_per_row);
+ first_row = tmpdiv;
+ tmpdiv = last_block;
+ (void) do_div(tmpdiv, blocks_per_row);
+ last_row = tmpdiv;
+ first_row_offset = (u32) (first_block - (first_row * blocks_per_row));
+ last_row_offset = (u32) (last_block - (last_row * blocks_per_row));
+ tmpdiv = first_row_offset;
+ (void) do_div(tmpdiv, map->strip_size);
+ first_column = tmpdiv;
+ tmpdiv = last_row_offset;
+ (void) do_div(tmpdiv, map->strip_size);
+ last_column = tmpdiv;
+#else
+ first_row = first_block / blocks_per_row;
+ last_row = last_block / blocks_per_row;
+ first_row_offset = (u32) (first_block - (first_row * blocks_per_row));
+ last_row_offset = (u32) (last_block - (last_row * blocks_per_row));
+ first_column = first_row_offset / map->strip_size;
+ last_column = last_row_offset / map->strip_size;
+#endif
+
+ /* if this isn't a single row/column then give to the controller */
+ if ((first_row != last_row) || (first_column != last_column))
+ return IO_ACCEL_INELIGIBLE;
+
+ /* proceeding with driver mapping */
+ total_disks_per_row = map->data_disks_per_row +
+ map->metadata_disks_per_row;
+ map_row = ((u32)(first_row >> map->parity_rotation_shift)) %
+ map->row_cnt;
+ map_index = (map_row * total_disks_per_row) + first_column;
+
+ switch (dev->raid_level) {
+ case HPSA_RAID_0:
+ break; /* nothing special to do */
+ case HPSA_RAID_1:
+ /* Handles load balance across RAID 1 members.
+ * (2-drive R1 and R10 with even # of drives.)
+ * Appropriate for SSDs, not optimal for HDDs
+ */
+ BUG_ON(map->layout_map_count != 2);
+ if (dev->offload_to_mirror)
+ map_index += map->data_disks_per_row;
+ dev->offload_to_mirror = !dev->offload_to_mirror;
+ break;
+ case HPSA_RAID_ADM:
+ /* Handles N-way mirrors (R1-ADM)
+ * and R10 with # of drives divisible by 3.)
+ */
+ BUG_ON(map->layout_map_count != 3);
+
+ offload_to_mirror = dev->offload_to_mirror;
+ raid_map_helper(map, offload_to_mirror,
+ &map_index, &current_group);
+ /* set mirror group to use next time */
+ offload_to_mirror =
+ (offload_to_mirror >= map->layout_map_count - 1)
+ ? 0 : offload_to_mirror + 1;
+ /* FIXME: remove after debug/dev */
+ BUG_ON(offload_to_mirror >= map->layout_map_count);
+ dev_warn(&h->pdev->dev,
+ "DEBUG: Using physical disk map index %d from mirror group %d\n",
+ map_index, offload_to_mirror);
+ dev->offload_to_mirror = offload_to_mirror;
+ /* Avoid direct use of dev->offload_to_mirror within this
+ * function since multiple threads might simultaneously
+ * increment it beyond the range of dev->layout_map_count -1.
+ */
+ break;
+ case HPSA_RAID_5:
+ case HPSA_RAID_6:
+ if (map->layout_map_count <= 1)
+ break;
+
+ /* Verify first and last block are in same RAID group */
+ r5or6_blocks_per_row =
+ map->strip_size * map->data_disks_per_row;
+ BUG_ON(r5or6_blocks_per_row == 0);
+ stripesize = r5or6_blocks_per_row * map->layout_map_count;
+#if BITS_PER_LONG == 32
+ tmpdiv = first_block;
+ first_group = do_div(tmpdiv, stripesize);
+ tmpdiv = first_group;
+ (void) do_div(tmpdiv, r5or6_blocks_per_row);
+ first_group = tmpdiv;
+ tmpdiv = last_block;
+ last_group = do_div(tmpdiv, stripesize);
+ tmpdiv = last_group;
+ (void) do_div(tmpdiv, r5or6_blocks_per_row);
+ last_group = tmpdiv;
+#else
+ first_group = (first_block % stripesize) / r5or6_blocks_per_row;
+ last_group = (last_block % stripesize) / r5or6_blocks_per_row;
+#endif
+ if (first_group != last_group)
+ return IO_ACCEL_INELIGIBLE;
+
+ /* Verify request is in a single row of RAID 5/6 */
+#if BITS_PER_LONG == 32
+ tmpdiv = first_block;
+ (void) do_div(tmpdiv, stripesize);
+ first_row = r5or6_first_row = r0_first_row = tmpdiv;
+ tmpdiv = last_block;
+ (void) do_div(tmpdiv, stripesize);
+ r5or6_last_row = r0_last_row = tmpdiv;
+#else
+ first_row = r5or6_first_row = r0_first_row =
+ first_block / stripesize;
+ r5or6_last_row = r0_last_row = last_block / stripesize;
+#endif
+ if (r5or6_first_row != r5or6_last_row)
+ return IO_ACCEL_INELIGIBLE;
+
+
+ /* Verify request is in a single column */
+#if BITS_PER_LONG == 32
+ tmpdiv = first_block;
+ first_row_offset = do_div(tmpdiv, stripesize);
+ tmpdiv = first_row_offset;
+ first_row_offset = (u32) do_div(tmpdiv, r5or6_blocks_per_row);
+ r5or6_first_row_offset = first_row_offset;
+ tmpdiv = last_block;
+ r5or6_last_row_offset = do_div(tmpdiv, stripesize);
+ tmpdiv = r5or6_last_row_offset;
+ r5or6_last_row_offset = do_div(tmpdiv, r5or6_blocks_per_row);
+ tmpdiv = r5or6_first_row_offset;
+ (void) do_div(tmpdiv, map->strip_size);
+ first_column = r5or6_first_column = tmpdiv;
+ tmpdiv = r5or6_last_row_offset;
+ (void) do_div(tmpdiv, map->strip_size);
+ r5or6_last_column = tmpdiv;
+#else
+ first_row_offset = r5or6_first_row_offset =
+ (u32)((first_block % stripesize) %
+ r5or6_blocks_per_row);
+
+ r5or6_last_row_offset =
+ (u32)((last_block % stripesize) %
+ r5or6_blocks_per_row);
+
+ first_column = r5or6_first_column =
+ r5or6_first_row_offset / map->strip_size;
+ r5or6_last_column =
+ r5or6_last_row_offset / map->strip_size;
+#endif
+ if (r5or6_first_column != r5or6_last_column)
+ return IO_ACCEL_INELIGIBLE;
+
+ /* Request is eligible */
+ map_row = ((u32)(first_row >> map->parity_rotation_shift)) %
+ map->row_cnt;
+
+ map_index = (first_group *
+ (map->row_cnt * total_disks_per_row)) +
+ (map_row * total_disks_per_row) + first_column;
+ break;
+ default:
+ return IO_ACCEL_INELIGIBLE;
+ }
+
+ disk_handle = dd[map_index].ioaccel_handle;
+ disk_block = map->disk_starting_blk + (first_row * map->strip_size) +
+ (first_row_offset - (first_column * map->strip_size));
+ disk_block_cnt = block_cnt;
+
+ /* handle differing logical/physical block sizes */
+ if (map->phys_blk_shift) {
+ disk_block <<= map->phys_blk_shift;
+ disk_block_cnt <<= map->phys_blk_shift;
+ }
+ BUG_ON(disk_block_cnt > 0xffff);
+
+ /* build the new CDB for the physical disk I/O */
+ if (disk_block > 0xffffffff) {
+ cdb[0] = is_write ? WRITE_16 : READ_16;
+ cdb[1] = 0;
+ cdb[2] = (u8) (disk_block >> 56);
+ cdb[3] = (u8) (disk_block >> 48);
+ cdb[4] = (u8) (disk_block >> 40);
+ cdb[5] = (u8) (disk_block >> 32);
+ cdb[6] = (u8) (disk_block >> 24);
+ cdb[7] = (u8) (disk_block >> 16);
+ cdb[8] = (u8) (disk_block >> 8);
+ cdb[9] = (u8) (disk_block);
+ cdb[10] = (u8) (disk_block_cnt >> 24);
+ cdb[11] = (u8) (disk_block_cnt >> 16);
+ cdb[12] = (u8) (disk_block_cnt >> 8);
+ cdb[13] = (u8) (disk_block_cnt);
+ cdb[14] = 0;
+ cdb[15] = 0;
+ cdb_len = 16;
+ } else {
+ cdb[0] = is_write ? WRITE_10 : READ_10;
+ cdb[1] = 0;
+ cdb[2] = (u8) (disk_block >> 24);
+ cdb[3] = (u8) (disk_block >> 16);
+ cdb[4] = (u8) (disk_block >> 8);
+ cdb[5] = (u8) (disk_block);
+ cdb[6] = 0;
+ cdb[7] = (u8) (disk_block_cnt >> 8);
+ cdb[8] = (u8) (disk_block_cnt);
+ cdb[9] = 0;
+ cdb_len = 10;
+ }
+ return hpsa_scsi_ioaccel_queue_command(h, c, disk_handle, cdb, cdb_len,
+ dev->scsi3addr);
+}
static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
@@ -2169,6 +3951,7 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
unsigned char scsi3addr[8];
struct CommandList *c;
unsigned long flags;
+ int rc = 0;
/* Get the ptr to our adapter structure out of cmd->host. */
h = sdev_to_hba(cmd->device);
@@ -2203,6 +3986,32 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
c->cmd_type = CMD_SCSI;
c->scsi_cmd = cmd;
+
+ /* Call alternate submit routine for I/O accelerated commands.
+ * Retries always go down the normal I/O path.
+ */
+ if (likely(cmd->retries == 0 &&
+ cmd->request->cmd_type == REQ_TYPE_FS &&
+ h->acciopath_status)) {
+ if (dev->offload_enabled) {
+ rc = hpsa_scsi_ioaccel_raid_map(h, c);
+ if (rc == 0)
+ return 0; /* Sent on ioaccel path */
+ if (rc < 0) { /* scsi_dma_map failed. */
+ cmd_free(h, c);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+ } else if (dev->ioaccel_handle) {
+ rc = hpsa_scsi_ioaccel_direct_map(h, c);
+ if (rc == 0)
+ return 0; /* Sent on direct map path */
+ if (rc < 0) { /* scsi_dma_map failed. */
+ cmd_free(h, c);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+ }
+ }
+
c->Header.ReplyQueue = 0; /* unused in simple mode */
memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8);
c->Header.Tag.lower = (c->cmdindex << DIRECT_LOOKUP_SHIFT);
@@ -2262,11 +4071,38 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
static DEF_SCSI_QCMD(hpsa_scsi_queue_command)
+static int do_not_scan_if_controller_locked_up(struct ctlr_info *h)
+{
+ unsigned long flags;
+
+ /*
+ * Don't let rescans be initiated on a controller known
+ * to be locked up. If the controller locks up *during*
+ * a rescan, that thread is probably hosed, but at least
+ * we can prevent new rescan threads from piling up on a
+ * locked up controller.
+ */
+ spin_lock_irqsave(&h->lock, flags);
+ if (unlikely(h->lockup_detected)) {
+ spin_unlock_irqrestore(&h->lock, flags);
+ spin_lock_irqsave(&h->scan_lock, flags);
+ h->scan_finished = 1;
+ wake_up_all(&h->scan_wait_queue);
+ spin_unlock_irqrestore(&h->scan_lock, flags);
+ return 1;
+ }
+ spin_unlock_irqrestore(&h->lock, flags);
+ return 0;
+}
+
static void hpsa_scan_start(struct Scsi_Host *sh)
{
struct ctlr_info *h = shost_to_hba(sh);
unsigned long flags;
+ if (do_not_scan_if_controller_locked_up(h))
+ return;
+
/* wait until any scan already in progress is finished. */
while (1) {
spin_lock_irqsave(&h->scan_lock, flags);
@@ -2283,6 +4119,9 @@ static void hpsa_scan_start(struct Scsi_Host *sh)
h->scan_finished = 0; /* mark scan as in progress */
spin_unlock_irqrestore(&h->scan_lock, flags);
+ if (do_not_scan_if_controller_locked_up(h))
+ return;
+
hpsa_update_scsi_devices(h, h->scsi_host->host_no);
spin_lock_irqsave(&h->scan_lock, flags);
@@ -2346,7 +4185,10 @@ static int hpsa_register_scsi(struct ctlr_info *h)
sh->max_lun = HPSA_MAX_LUN;
sh->max_id = HPSA_MAX_LUN;
sh->can_queue = h->nr_cmds;
- sh->cmd_per_lun = h->nr_cmds;
+ if (h->hba_mode_enabled)
+ sh->cmd_per_lun = 7;
+ else
+ sh->cmd_per_lun = h->nr_cmds;
sh->sg_tablesize = h->maxsgentries;
h->scsi_host = sh;
sh->hostdata[0] = (unsigned long) h;
@@ -2372,7 +4214,7 @@ static int hpsa_register_scsi(struct ctlr_info *h)
static int wait_for_device_to_become_ready(struct ctlr_info *h,
unsigned char lunaddr[])
{
- int rc = 0;
+ int rc;
int count = 0;
int waittime = 1; /* seconds */
struct CommandList *c;
@@ -2392,6 +4234,7 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h,
*/
msleep(1000 * waittime);
count++;
+ rc = 0; /* Device ready. */
/* Increase wait time with each try, up to a point. */
if (waittime < HPSA_MAX_WAIT_INTERVAL_SECS)
@@ -2448,7 +4291,7 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
dev_warn(&h->pdev->dev, "resetting device %d:%d:%d:%d\n",
h->scsi_host->host_no, dev->bus, dev->target, dev->lun);
/* send a reset to the SCSI LUN which the command was sent to */
- rc = hpsa_send_reset(h, dev->scsi3addr);
+ rc = hpsa_send_reset(h, dev->scsi3addr, HPSA_RESET_TYPE_LUN);
if (rc == 0 && wait_for_device_to_become_ready(h, dev->scsi3addr) == 0)
return SUCCESS;
@@ -2471,12 +4314,36 @@ static void swizzle_abort_tag(u8 *tag)
tag[7] = original_tag[4];
}
+static void hpsa_get_tag(struct ctlr_info *h,
+ struct CommandList *c, u32 *taglower, u32 *tagupper)
+{
+ if (c->cmd_type == CMD_IOACCEL1) {
+ struct io_accel1_cmd *cm1 = (struct io_accel1_cmd *)
+ &h->ioaccel_cmd_pool[c->cmdindex];
+ *tagupper = cm1->Tag.upper;
+ *taglower = cm1->Tag.lower;
+ return;
+ }
+ if (c->cmd_type == CMD_IOACCEL2) {
+ struct io_accel2_cmd *cm2 = (struct io_accel2_cmd *)
+ &h->ioaccel2_cmd_pool[c->cmdindex];
+ /* upper tag not used in ioaccel2 mode */
+ memset(tagupper, 0, sizeof(*tagupper));
+ *taglower = cm2->Tag;
+ return;
+ }
+ *tagupper = c->Header.Tag.upper;
+ *taglower = c->Header.Tag.lower;
+}
+
+
static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
struct CommandList *abort, int swizzle)
{
int rc = IO_OK;
struct CommandList *c;
struct ErrorInfo *ei;
+ u32 tagupper, taglower;
c = cmd_special_alloc(h);
if (c == NULL) { /* trouble... */
@@ -2490,8 +4357,9 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
if (swizzle)
swizzle_abort_tag(&c->Request.CDB[4]);
hpsa_scsi_do_simple_cmd_core(h, c);
+ hpsa_get_tag(h, abort, &taglower, &tagupper);
dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: do_simple_cmd_core completed.\n",
- __func__, abort->Header.Tag.upper, abort->Header.Tag.lower);
+ __func__, tagupper, taglower);
/* no unmap needed here because no data xfer. */
ei = c->err_info;
@@ -2503,15 +4371,14 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
break;
default:
dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: interpreting error.\n",
- __func__, abort->Header.Tag.upper,
- abort->Header.Tag.lower);
- hpsa_scsi_interpret_error(c);
+ __func__, tagupper, taglower);
+ hpsa_scsi_interpret_error(h, c);
rc = -1;
break;
}
cmd_special_free(h, c);
- dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: Finished.\n", __func__,
- abort->Header.Tag.upper, abort->Header.Tag.lower);
+ dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: Finished.\n",
+ __func__, tagupper, taglower);
return rc;
}
@@ -2565,6 +4432,83 @@ static struct CommandList *hpsa_find_cmd_in_queue_by_tag(struct ctlr_info *h,
return NULL;
}
+/* ioaccel2 path firmware cannot handle abort task requests.
+ * Change abort requests to physical target reset, and send to the
+ * address of the physical disk used for the ioaccel 2 command.
+ * Return 0 on success (IO_OK)
+ * -1 on failure
+ */
+
+static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h,
+ unsigned char *scsi3addr, struct CommandList *abort)
+{
+ int rc = IO_OK;
+ struct scsi_cmnd *scmd; /* scsi command within request being aborted */
+ struct hpsa_scsi_dev_t *dev; /* device to which scsi cmd was sent */
+ unsigned char phys_scsi3addr[8]; /* addr of phys disk with volume */
+ unsigned char *psa = &phys_scsi3addr[0];
+
+ /* Get a pointer to the hpsa logical device. */
+ scmd = (struct scsi_cmnd *) abort->scsi_cmd;
+ dev = (struct hpsa_scsi_dev_t *)(scmd->device->hostdata);
+ if (dev == NULL) {
+ dev_warn(&h->pdev->dev,
+ "Cannot abort: no device pointer for command.\n");
+ return -1; /* not abortable */
+ }
+
+ if (h->raid_offload_debug > 0)
+ dev_info(&h->pdev->dev,
+ "Reset as abort: Abort requested on C%d:B%d:T%d:L%d scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ h->scsi_host->host_no, dev->bus, dev->target, dev->lun,
+ scsi3addr[0], scsi3addr[1], scsi3addr[2], scsi3addr[3],
+ scsi3addr[4], scsi3addr[5], scsi3addr[6], scsi3addr[7]);
+
+ if (!dev->offload_enabled) {
+ dev_warn(&h->pdev->dev,
+ "Can't abort: device is not operating in HP SSD Smart Path mode.\n");
+ return -1; /* not abortable */
+ }
+
+ /* Incoming scsi3addr is logical addr. We need physical disk addr. */
+ if (!hpsa_get_pdisk_of_ioaccel2(h, abort, psa)) {
+ dev_warn(&h->pdev->dev, "Can't abort: Failed lookup of physical address.\n");
+ return -1; /* not abortable */
+ }
+
+ /* send the reset */
+ if (h->raid_offload_debug > 0)
+ dev_info(&h->pdev->dev,
+ "Reset as abort: Resetting physical device at scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ psa[0], psa[1], psa[2], psa[3],
+ psa[4], psa[5], psa[6], psa[7]);
+ rc = hpsa_send_reset(h, psa, HPSA_RESET_TYPE_TARGET);
+ if (rc != 0) {
+ dev_warn(&h->pdev->dev,
+ "Reset as abort: Failed on physical device at scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ psa[0], psa[1], psa[2], psa[3],
+ psa[4], psa[5], psa[6], psa[7]);
+ return rc; /* failed to reset */
+ }
+
+ /* wait for device to recover */
+ if (wait_for_device_to_become_ready(h, psa) != 0) {
+ dev_warn(&h->pdev->dev,
+ "Reset as abort: Failed: Device never recovered from reset: 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ psa[0], psa[1], psa[2], psa[3],
+ psa[4], psa[5], psa[6], psa[7]);
+ return -1; /* failed to recover */
+ }
+
+ /* device recovered */
+ dev_info(&h->pdev->dev,
+ "Reset as abort: Device recovered from reset: scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ psa[0], psa[1], psa[2], psa[3],
+ psa[4], psa[5], psa[6], psa[7]);
+
+ return rc; /* success */
+}
+
/* Some Smart Arrays need the abort tag swizzled, and some don't. It's hard to
* tell which kind we're dealing with, so we send the abort both ways. There
* shouldn't be any collisions between swizzled and unswizzled tags due to the
@@ -2578,6 +4522,14 @@ static int hpsa_send_abort_both_ways(struct ctlr_info *h,
struct CommandList *c;
int rc = 0, rc2 = 0;
+ /* ioccelerator mode 2 commands should be aborted via the
+ * accelerated path, since RAID path is unaware of these commands,
+ * but underlying firmware can't handle abort TMF.
+ * Change abort to physical device reset.
+ */
+ if (abort->cmd_type == CMD_IOACCEL2)
+ return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr, abort);
+
/* we do not expect to find the swizzled tag in our queue, but
* check anyway just to be sure the assumptions which make this
* the case haven't become wrong.
@@ -2616,6 +4568,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
struct scsi_cmnd *as; /* ptr to scsi cmd inside aborted command. */
char msg[256]; /* For debug messaging. */
int ml = 0;
+ u32 tagupper, taglower;
/* Find the controller of the command to be aborted */
h = sdev_to_hba(sc->device);
@@ -2648,9 +4601,8 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
msg);
return FAILED;
}
-
- ml += sprintf(msg+ml, "Tag:0x%08x:%08x ",
- abort->Header.Tag.upper, abort->Header.Tag.lower);
+ hpsa_get_tag(h, abort, &taglower, &tagupper);
+ ml += sprintf(msg+ml, "Tag:0x%08x:%08x ", tagupper, taglower);
as = (struct scsi_cmnd *) abort->scsi_cmd;
if (as != NULL)
ml += sprintf(msg+ml, "Command:0x%x SN:0x%lx ",
@@ -2776,6 +4728,7 @@ static struct CommandList *cmd_special_alloc(struct ctlr_info *h)
return NULL;
memset(c, 0, sizeof(*c));
+ c->cmd_type = CMD_SCSI;
c->cmdindex = -1;
c->err_info = pci_alloc_consistent(h->pdev, sizeof(*c->err_info),
@@ -3038,7 +4991,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
c->SG[0].Addr.lower = temp64.val32.lower;
c->SG[0].Addr.upper = temp64.val32.upper;
c->SG[0].Len = iocommand.buf_size;
- c->SG[0].Ext = 0; /* we are not chaining*/
+ c->SG[0].Ext = HPSA_SG_LAST; /* we are not chaining*/
}
hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c);
if (iocommand.buf_size > 0)
@@ -3168,8 +5121,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
c->SG[i].Addr.lower = temp64.val32.lower;
c->SG[i].Addr.upper = temp64.val32.upper;
c->SG[i].Len = buff_size[i];
- /* we are not chaining */
- c->SG[i].Ext = 0;
+ c->SG[i].Ext = i < sg_used - 1 ? 0 : HPSA_SG_LAST;
}
}
hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c);
@@ -3304,7 +5256,7 @@ static int hpsa_send_host_reset(struct ctlr_info *h, unsigned char *scsi3addr,
}
static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
- void *buff, size_t size, u8 page_code, unsigned char *scsi3addr,
+ void *buff, size_t size, u16 page_code, unsigned char *scsi3addr,
int cmd_type)
{
int pci_dir = XFER_NONE;
@@ -3327,9 +5279,9 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
switch (cmd) {
case HPSA_INQUIRY:
/* are we trying to read a vital product page */
- if (page_code != 0) {
+ if (page_code & VPD_PAGE) {
c->Request.CDB[1] = 0x01;
- c->Request.CDB[2] = page_code;
+ c->Request.CDB[2] = (page_code & 0xff);
}
c->Request.CDBLen = 6;
c->Request.Type.Attribute = ATTR_SIMPLE;
@@ -3369,6 +5321,28 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
c->Request.Type.Direction = XFER_NONE;
c->Request.Timeout = 0;
break;
+ case HPSA_GET_RAID_MAP:
+ c->Request.CDBLen = 12;
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Direction = XFER_READ;
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = HPSA_CISS_READ;
+ c->Request.CDB[1] = cmd;
+ c->Request.CDB[6] = (size >> 24) & 0xFF; /* MSB */
+ c->Request.CDB[7] = (size >> 16) & 0xFF;
+ c->Request.CDB[8] = (size >> 8) & 0xFF;
+ c->Request.CDB[9] = size & 0xFF;
+ break;
+ case BMIC_SENSE_CONTROLLER_PARAMETERS:
+ c->Request.CDBLen = 10;
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Direction = XFER_READ;
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = BMIC_READ;
+ c->Request.CDB[6] = BMIC_SENSE_CONTROLLER_PARAMETERS;
+ c->Request.CDB[7] = (size >> 16) & 0xFF;
+ c->Request.CDB[8] = (size >> 8) & 0xFF;
+ break;
default:
dev_warn(&h->pdev->dev, "unknown command 0x%c\n", cmd);
BUG();
@@ -3562,7 +5536,8 @@ static inline void finish_cmd(struct CommandList *c)
spin_unlock_irqrestore(&h->lock, flags);
dial_up_lockup_detection_on_fw_flash_complete(c->h, c);
- if (likely(c->cmd_type == CMD_SCSI))
+ if (likely(c->cmd_type == CMD_IOACCEL1 || c->cmd_type == CMD_SCSI
+ || c->cmd_type == CMD_IOACCEL2))
complete_scsi_command(c);
else if (c->cmd_type == CMD_IOCTL_PEND)
complete(c->waiting);
@@ -4169,21 +6144,24 @@ static void hpsa_interrupt_mode(struct ctlr_info *h)
goto default_int_mode;
if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) {
dev_info(&h->pdev->dev, "MSIX\n");
+ h->msix_vector = MAX_REPLY_QUEUES;
err = pci_enable_msix(h->pdev, hpsa_msix_entries,
- MAX_REPLY_QUEUES);
- if (!err) {
- for (i = 0; i < MAX_REPLY_QUEUES; i++)
- h->intr[i] = hpsa_msix_entries[i].vector;
- h->msix_vector = 1;
- return;
- }
+ h->msix_vector);
if (err > 0) {
dev_warn(&h->pdev->dev, "only %d MSI-X vectors "
"available\n", err);
- goto default_int_mode;
+ h->msix_vector = err;
+ err = pci_enable_msix(h->pdev, hpsa_msix_entries,
+ h->msix_vector);
+ }
+ if (!err) {
+ for (i = 0; i < h->msix_vector; i++)
+ h->intr[i] = hpsa_msix_entries[i].vector;
+ return;
} else {
dev_warn(&h->pdev->dev, "MSI-X init failed %d\n",
err);
+ h->msix_vector = 0;
goto default_int_mode;
}
}
@@ -4336,6 +6314,7 @@ static void hpsa_find_board_params(struct ctlr_info *h)
hpsa_get_max_perf_mode_cmds(h);
h->nr_cmds = h->max_commands - 4; /* Allow room for some ioctls */
h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements));
+ h->fw_support = readl(&(h->cfgtable->misc_fw_support));
/*
* Limit in-command s/g elements to 32 save dma'able memory.
* Howvever spec says if 0, use 31
@@ -4352,6 +6331,10 @@ static void hpsa_find_board_params(struct ctlr_info *h)
/* Find out what task management functions are supported and cache */
h->TMFSupportFlags = readl(&(h->cfgtable->TMFSupportFlags));
+ if (!(HPSATMF_PHYS_TASK_ABORT & h->TMFSupportFlags))
+ dev_warn(&h->pdev->dev, "Physical aborts not supported\n");
+ if (!(HPSATMF_LOG_TASK_ABORT & h->TMFSupportFlags))
+ dev_warn(&h->pdev->dev, "Logical aborts not supported\n");
}
static inline bool hpsa_CISS_signature_present(struct ctlr_info *h)
@@ -4390,6 +6373,23 @@ static inline void hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h)
writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG);
}
+static void hpsa_wait_for_clear_event_notify_ack(struct ctlr_info *h)
+{
+ int i;
+ u32 doorbell_value;
+ unsigned long flags;
+ /* wait until the clear_event_notify bit 6 is cleared by controller. */
+ for (i = 0; i < MAX_CONFIG_WAIT; i++) {
+ spin_lock_irqsave(&h->lock, flags);
+ doorbell_value = readl(h->vaddr + SA5_DOORBELL);
+ spin_unlock_irqrestore(&h->lock, flags);
+ if (!(doorbell_value & DOORBELL_CLEAR_EVENTS))
+ break;
+ /* delay and try again */
+ msleep(20);
+ }
+}
+
static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h)
{
int i;
@@ -4420,18 +6420,20 @@ static int hpsa_enter_simple_mode(struct ctlr_info *h)
return -ENOTSUPP;
h->max_commands = readl(&(h->cfgtable->CmdsOutMax));
+
/* Update the field, and then ring the doorbell */
writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest));
+ writel(0, &h->cfgtable->HostWrite.command_pool_addr_hi);
writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
hpsa_wait_for_mode_change_ack(h);
print_cfg_table(&h->pdev->dev, h->cfgtable);
- if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) {
- dev_warn(&h->pdev->dev,
- "unable to get board into simple mode\n");
- return -ENODEV;
- }
+ if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple))
+ goto error;
h->transMethod = CFGTBL_Trans_Simple;
return 0;
+error:
+ dev_warn(&h->pdev->dev, "unable to get board into simple mode\n");
+ return -ENODEV;
}
static int hpsa_pci_init(struct ctlr_info *h)
@@ -4577,11 +6579,19 @@ static void hpsa_free_cmd_pool(struct ctlr_info *h)
pci_free_consistent(h->pdev,
h->nr_cmds * sizeof(struct CommandList),
h->cmd_pool, h->cmd_pool_dhandle);
+ if (h->ioaccel2_cmd_pool)
+ pci_free_consistent(h->pdev,
+ h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool),
+ h->ioaccel2_cmd_pool, h->ioaccel2_cmd_pool_dhandle);
if (h->errinfo_pool)
pci_free_consistent(h->pdev,
h->nr_cmds * sizeof(struct ErrorInfo),
h->errinfo_pool,
h->errinfo_pool_dhandle);
+ if (h->ioaccel_cmd_pool)
+ pci_free_consistent(h->pdev,
+ h->nr_cmds * sizeof(struct io_accel1_cmd),
+ h->ioaccel_cmd_pool, h->ioaccel_cmd_pool_dhandle);
}
static int hpsa_request_irq(struct ctlr_info *h,
@@ -4597,15 +6607,15 @@ static int hpsa_request_irq(struct ctlr_info *h,
for (i = 0; i < MAX_REPLY_QUEUES; i++)
h->q[i] = (u8) i;
- if (h->intr_mode == PERF_MODE_INT && h->msix_vector) {
+ if (h->intr_mode == PERF_MODE_INT && h->msix_vector > 0) {
/* If performant mode and MSI-X, use multiple reply queues */
- for (i = 0; i < MAX_REPLY_QUEUES; i++)
+ for (i = 0; i < h->msix_vector; i++)
rc = request_irq(h->intr[i], msixhandler,
0, h->devname,
&h->q[i]);
} else {
/* Use single reply pool */
- if (h->msix_vector || h->msi_vector) {
+ if (h->msix_vector > 0 || h->msi_vector) {
rc = request_irq(h->intr[h->intr_mode],
msixhandler, 0, h->devname,
&h->q[h->intr_mode]);
@@ -4658,7 +6668,7 @@ static void free_irqs(struct ctlr_info *h)
return;
}
- for (i = 0; i < MAX_REPLY_QUEUES; i++)
+ for (i = 0; i < h->msix_vector; i++)
free_irq(h->intr[i], &h->q[i]);
}
@@ -4681,6 +6691,7 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h)
hpsa_free_irqs_and_disable_msix(h);
hpsa_free_sg_chain_blocks(h);
hpsa_free_cmd_pool(h);
+ kfree(h->ioaccel1_blockFetchTable);
kfree(h->blockFetchTable);
pci_free_consistent(h->pdev, h->reply_pool_size,
h->reply_pool, h->reply_pool_dhandle);
@@ -4760,6 +6771,92 @@ static void detect_controller_lockup(struct ctlr_info *h)
h->last_heartbeat_timestamp = now;
}
+static void hpsa_ack_ctlr_events(struct ctlr_info *h)
+{
+ int i;
+ char *event_type;
+
+ /* Clear the driver-requested rescan flag */
+ h->drv_req_rescan = 0;
+
+ /* Ask the controller to clear the events we're handling. */
+ if ((h->transMethod & (CFGTBL_Trans_io_accel1
+ | CFGTBL_Trans_io_accel2)) &&
+ (h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_STATE_CHANGE ||
+ h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_CONFIG_CHANGE)) {
+
+ if (h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_STATE_CHANGE)
+ event_type = "state change";
+ if (h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_CONFIG_CHANGE)
+ event_type = "configuration change";
+ /* Stop sending new RAID offload reqs via the IO accelerator */
+ scsi_block_requests(h->scsi_host);
+ for (i = 0; i < h->ndevices; i++)
+ h->dev[i]->offload_enabled = 0;
+ hpsa_drain_accel_commands(h);
+ /* Set 'accelerator path config change' bit */
+ dev_warn(&h->pdev->dev,
+ "Acknowledging event: 0x%08x (HP SSD Smart Path %s)\n",
+ h->events, event_type);
+ writel(h->events, &(h->cfgtable->clear_event_notify));
+ /* Set the "clear event notify field update" bit 6 */
+ writel(DOORBELL_CLEAR_EVENTS, h->vaddr + SA5_DOORBELL);
+ /* Wait until ctlr clears 'clear event notify field', bit 6 */
+ hpsa_wait_for_clear_event_notify_ack(h);
+ scsi_unblock_requests(h->scsi_host);
+ } else {
+ /* Acknowledge controller notification events. */
+ writel(h->events, &(h->cfgtable->clear_event_notify));
+ writel(DOORBELL_CLEAR_EVENTS, h->vaddr + SA5_DOORBELL);
+ hpsa_wait_for_clear_event_notify_ack(h);
+#if 0
+ writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+ hpsa_wait_for_mode_change_ack(h);
+#endif
+ }
+ return;
+}
+
+/* Check a register on the controller to see if there are configuration
+ * changes (added/changed/removed logical drives, etc.) which mean that
+ * we should rescan the controller for devices.
+ * Also check flag for driver-initiated rescan.
+ */
+static int hpsa_ctlr_needs_rescan(struct ctlr_info *h)
+{
+ if (h->drv_req_rescan)
+ return 1;
+
+ if (!(h->fw_support & MISC_FW_EVENT_NOTIFY))
+ return 0;
+
+ h->events = readl(&(h->cfgtable->event_notify));
+ return h->events & RESCAN_REQUIRED_EVENT_BITS;
+}
+
+/*
+ * Check if any of the offline devices have become ready
+ */
+static int hpsa_offline_devices_ready(struct ctlr_info *h)
+{
+ unsigned long flags;
+ struct offline_device_entry *d;
+ struct list_head *this, *tmp;
+
+ spin_lock_irqsave(&h->offline_device_lock, flags);
+ list_for_each_safe(this, tmp, &h->offline_device_list) {
+ d = list_entry(this, struct offline_device_entry,
+ offline_list);
+ spin_unlock_irqrestore(&h->offline_device_lock, flags);
+ if (!hpsa_volume_offline(h, d->scsi3addr))
+ return 1;
+ spin_lock_irqsave(&h->offline_device_lock, flags);
+ }
+ spin_unlock_irqrestore(&h->offline_device_lock, flags);
+ return 0;
+}
+
+
static void hpsa_monitor_ctlr_worker(struct work_struct *work)
{
unsigned long flags;
@@ -4768,6 +6865,15 @@ static void hpsa_monitor_ctlr_worker(struct work_struct *work)
detect_controller_lockup(h);
if (h->lockup_detected)
return;
+
+ if (hpsa_ctlr_needs_rescan(h) || hpsa_offline_devices_ready(h)) {
+ scsi_host_get(h->scsi_host);
+ h->drv_req_rescan = 0;
+ hpsa_ack_ctlr_events(h);
+ hpsa_scan_start(h->scsi_host);
+ scsi_host_put(h->scsi_host);
+ }
+
spin_lock_irqsave(&h->lock, flags);
if (h->remove_in_progress) {
spin_unlock_irqrestore(&h->lock, flags);
@@ -4807,7 +6913,7 @@ reinit_after_soft_reset:
* the 5 lower bits of the address are used by the hardware. and by
* the driver. See comments in hpsa.h for more info.
*/
-#define COMMANDLIST_ALIGNMENT 32
+#define COMMANDLIST_ALIGNMENT 128
BUILD_BUG_ON(sizeof(struct CommandList) % COMMANDLIST_ALIGNMENT);
h = kzalloc(sizeof(*h), GFP_KERNEL);
if (!h)
@@ -4817,7 +6923,9 @@ reinit_after_soft_reset:
h->intr_mode = hpsa_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT;
INIT_LIST_HEAD(&h->cmpQ);
INIT_LIST_HEAD(&h->reqQ);
+ INIT_LIST_HEAD(&h->offline_device_list);
spin_lock_init(&h->lock);
+ spin_lock_init(&h->offline_device_lock);
spin_lock_init(&h->scan_lock);
spin_lock_init(&h->passthru_count_lock);
rc = hpsa_pci_init(h);
@@ -4859,6 +6967,7 @@ reinit_after_soft_reset:
pci_set_drvdata(pdev, h);
h->ndevices = 0;
+ h->hba_mode_enabled = 0;
h->scsi_host = NULL;
spin_lock_init(&h->devlock);
hpsa_put_ctlr_into_performant_mode(h);
@@ -4918,6 +7027,11 @@ reinit_after_soft_reset:
goto reinit_after_soft_reset;
}
+ /* Enable Accelerated IO path at driver layer */
+ h->acciopath_status = 1;
+
+ h->drv_req_rescan = 0;
+
/* Turn the interrupts on so we can service requests */
h->access.set_intr_mask(h, HPSA_INTR_ON);
@@ -5034,6 +7148,8 @@ static void hpsa_remove_one(struct pci_dev *pdev)
h->reply_pool, h->reply_pool_dhandle);
kfree(h->cmd_pool_bits);
kfree(h->blockFetchTable);
+ kfree(h->ioaccel1_blockFetchTable);
+ kfree(h->ioaccel2_blockFetchTable);
kfree(h->hba_inquiry_data);
pci_disable_device(pdev);
pci_release_regions(pdev);
@@ -5074,20 +7190,17 @@ static struct pci_driver hpsa_pci_driver = {
* bits of the command address.
*/
static void calc_bucket_map(int bucket[], int num_buckets,
- int nsgs, int *bucket_map)
+ int nsgs, int min_blocks, int *bucket_map)
{
int i, j, b, size;
- /* even a command with 0 SGs requires 4 blocks */
-#define MINIMUM_TRANSFER_BLOCKS 4
-#define NUM_BUCKETS 8
/* Note, bucket_map must have nsgs+1 entries. */
for (i = 0; i <= nsgs; i++) {
/* Compute size of a command with i SG entries */
- size = i + MINIMUM_TRANSFER_BLOCKS;
+ size = i + min_blocks;
b = num_buckets; /* Assume the biggest bucket */
/* Find the bucket that is just big enough */
- for (j = 0; j < 8; j++) {
+ for (j = 0; j < num_buckets; j++) {
if (bucket[j] >= size) {
b = j;
break;
@@ -5098,10 +7211,16 @@ static void calc_bucket_map(int bucket[], int num_buckets,
}
}
-static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 use_short_tags)
+static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)
{
int i;
unsigned long register_value;
+ unsigned long transMethod = CFGTBL_Trans_Performant |
+ (trans_support & CFGTBL_Trans_use_short_tags) |
+ CFGTBL_Trans_enable_directed_msix |
+ (trans_support & (CFGTBL_Trans_io_accel1 |
+ CFGTBL_Trans_io_accel2));
+ struct access_method access = SA5_performant_access;
/* This is a bit complicated. There are 8 registers on
* the controller which we write to to tell it 8 different
@@ -5121,6 +7240,16 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 use_short_tags)
* sizes for small commands, and fewer sizes for larger commands.
*/
int bft[8] = {5, 6, 8, 10, 12, 20, 28, SG_ENTRIES_IN_CMD + 4};
+#define MIN_IOACCEL2_BFT_ENTRY 5
+#define HPSA_IOACCEL2_HEADER_SZ 4
+ int bft2[16] = {MIN_IOACCEL2_BFT_ENTRY, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19,
+ HPSA_IOACCEL2_HEADER_SZ + IOACCEL2_MAXSGENTRIES};
+ BUILD_BUG_ON(ARRAY_SIZE(bft2) != 16);
+ BUILD_BUG_ON(ARRAY_SIZE(bft) != 8);
+ BUILD_BUG_ON(offsetof(struct io_accel2_cmd, sg) >
+ 16 * MIN_IOACCEL2_BFT_ENTRY);
+ BUILD_BUG_ON(sizeof(struct ioaccel2_sg_element) != 16);
BUILD_BUG_ON(28 > SG_ENTRIES_IN_CMD + 4);
/* 5 = 1 s/g entry or 4k
* 6 = 2 s/g entry or 8k
@@ -5133,7 +7262,7 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 use_short_tags)
bft[7] = SG_ENTRIES_IN_CMD + 4;
calc_bucket_map(bft, ARRAY_SIZE(bft),
- SG_ENTRIES_IN_CMD, h->blockFetchTable);
+ SG_ENTRIES_IN_CMD, 4, h->blockFetchTable);
for (i = 0; i < 8; i++)
writel(bft[i], &h->transtable->BlockFetch[i]);
@@ -5150,9 +7279,22 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 use_short_tags)
&h->transtable->RepQAddr[i].lower);
}
- writel(CFGTBL_Trans_Performant | use_short_tags |
- CFGTBL_Trans_enable_directed_msix,
- &(h->cfgtable->HostWrite.TransportRequest));
+ writel(0, &h->cfgtable->HostWrite.command_pool_addr_hi);
+ writel(transMethod, &(h->cfgtable->HostWrite.TransportRequest));
+ /*
+ * enable outbound interrupt coalescing in accelerator mode;
+ */
+ if (trans_support & CFGTBL_Trans_io_accel1) {
+ access = SA5_ioaccel_mode1_access;
+ writel(10, &h->cfgtable->HostWrite.CoalIntDelay);
+ writel(4, &h->cfgtable->HostWrite.CoalIntCount);
+ } else {
+ if (trans_support & CFGTBL_Trans_io_accel2) {
+ access = SA5_ioaccel_mode2_access;
+ writel(10, &h->cfgtable->HostWrite.CoalIntDelay);
+ writel(4, &h->cfgtable->HostWrite.CoalIntCount);
+ }
+ }
writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
hpsa_wait_for_mode_change_ack(h);
register_value = readl(&(h->cfgtable->TransportActive));
@@ -5162,23 +7304,186 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 use_short_tags)
return;
}
/* Change the access methods to the performant access methods */
- h->access = SA5_performant_access;
- h->transMethod = CFGTBL_Trans_Performant;
+ h->access = access;
+ h->transMethod = transMethod;
+
+ if (!((trans_support & CFGTBL_Trans_io_accel1) ||
+ (trans_support & CFGTBL_Trans_io_accel2)))
+ return;
+
+ if (trans_support & CFGTBL_Trans_io_accel1) {
+ /* Set up I/O accelerator mode */
+ for (i = 0; i < h->nreply_queues; i++) {
+ writel(i, h->vaddr + IOACCEL_MODE1_REPLY_QUEUE_INDEX);
+ h->reply_queue[i].current_entry =
+ readl(h->vaddr + IOACCEL_MODE1_PRODUCER_INDEX);
+ }
+ bft[7] = h->ioaccel_maxsg + 8;
+ calc_bucket_map(bft, ARRAY_SIZE(bft), h->ioaccel_maxsg, 8,
+ h->ioaccel1_blockFetchTable);
+
+ /* initialize all reply queue entries to unused */
+ memset(h->reply_pool, (u8) IOACCEL_MODE1_REPLY_UNUSED,
+ h->reply_pool_size);
+
+ /* set all the constant fields in the accelerator command
+ * frames once at init time to save CPU cycles later.
+ */
+ for (i = 0; i < h->nr_cmds; i++) {
+ struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[i];
+
+ cp->function = IOACCEL1_FUNCTION_SCSIIO;
+ cp->err_info = (u32) (h->errinfo_pool_dhandle +
+ (i * sizeof(struct ErrorInfo)));
+ cp->err_info_len = sizeof(struct ErrorInfo);
+ cp->sgl_offset = IOACCEL1_SGLOFFSET;
+ cp->host_context_flags = IOACCEL1_HCFLAGS_CISS_FORMAT;
+ cp->timeout_sec = 0;
+ cp->ReplyQueue = 0;
+ cp->Tag.lower = (i << DIRECT_LOOKUP_SHIFT) |
+ DIRECT_LOOKUP_BIT;
+ cp->Tag.upper = 0;
+ cp->host_addr.lower =
+ (u32) (h->ioaccel_cmd_pool_dhandle +
+ (i * sizeof(struct io_accel1_cmd)));
+ cp->host_addr.upper = 0;
+ }
+ } else if (trans_support & CFGTBL_Trans_io_accel2) {
+ u64 cfg_offset, cfg_base_addr_index;
+ u32 bft2_offset, cfg_base_addr;
+ int rc;
+
+ rc = hpsa_find_cfg_addrs(h->pdev, h->vaddr, &cfg_base_addr,
+ &cfg_base_addr_index, &cfg_offset);
+ BUILD_BUG_ON(offsetof(struct io_accel2_cmd, sg) != 64);
+ bft2[15] = h->ioaccel_maxsg + HPSA_IOACCEL2_HEADER_SZ;
+ calc_bucket_map(bft2, ARRAY_SIZE(bft2), h->ioaccel_maxsg,
+ 4, h->ioaccel2_blockFetchTable);
+ bft2_offset = readl(&h->cfgtable->io_accel_request_size_offset);
+ BUILD_BUG_ON(offsetof(struct CfgTable,
+ io_accel_request_size_offset) != 0xb8);
+ h->ioaccel2_bft2_regs =
+ remap_pci_mem(pci_resource_start(h->pdev,
+ cfg_base_addr_index) +
+ cfg_offset + bft2_offset,
+ ARRAY_SIZE(bft2) *
+ sizeof(*h->ioaccel2_bft2_regs));
+ for (i = 0; i < ARRAY_SIZE(bft2); i++)
+ writel(bft2[i], &h->ioaccel2_bft2_regs[i]);
+ }
+ writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+ hpsa_wait_for_mode_change_ack(h);
+}
+
+static int hpsa_alloc_ioaccel_cmd_and_bft(struct ctlr_info *h)
+{
+ h->ioaccel_maxsg =
+ readl(&(h->cfgtable->io_accel_max_embedded_sg_count));
+ if (h->ioaccel_maxsg > IOACCEL1_MAXSGENTRIES)
+ h->ioaccel_maxsg = IOACCEL1_MAXSGENTRIES;
+
+ /* Command structures must be aligned on a 128-byte boundary
+ * because the 7 lower bits of the address are used by the
+ * hardware.
+ */
+#define IOACCEL1_COMMANDLIST_ALIGNMENT 128
+ BUILD_BUG_ON(sizeof(struct io_accel1_cmd) %
+ IOACCEL1_COMMANDLIST_ALIGNMENT);
+ h->ioaccel_cmd_pool =
+ pci_alloc_consistent(h->pdev,
+ h->nr_cmds * sizeof(*h->ioaccel_cmd_pool),
+ &(h->ioaccel_cmd_pool_dhandle));
+
+ h->ioaccel1_blockFetchTable =
+ kmalloc(((h->ioaccel_maxsg + 1) *
+ sizeof(u32)), GFP_KERNEL);
+
+ if ((h->ioaccel_cmd_pool == NULL) ||
+ (h->ioaccel1_blockFetchTable == NULL))
+ goto clean_up;
+
+ memset(h->ioaccel_cmd_pool, 0,
+ h->nr_cmds * sizeof(*h->ioaccel_cmd_pool));
+ return 0;
+
+clean_up:
+ if (h->ioaccel_cmd_pool)
+ pci_free_consistent(h->pdev,
+ h->nr_cmds * sizeof(*h->ioaccel_cmd_pool),
+ h->ioaccel_cmd_pool, h->ioaccel_cmd_pool_dhandle);
+ kfree(h->ioaccel1_blockFetchTable);
+ return 1;
+}
+
+static int ioaccel2_alloc_cmds_and_bft(struct ctlr_info *h)
+{
+ /* Allocate ioaccel2 mode command blocks and block fetch table */
+
+ h->ioaccel_maxsg =
+ readl(&(h->cfgtable->io_accel_max_embedded_sg_count));
+ if (h->ioaccel_maxsg > IOACCEL2_MAXSGENTRIES)
+ h->ioaccel_maxsg = IOACCEL2_MAXSGENTRIES;
+
+#define IOACCEL2_COMMANDLIST_ALIGNMENT 128
+ BUILD_BUG_ON(sizeof(struct io_accel2_cmd) %
+ IOACCEL2_COMMANDLIST_ALIGNMENT);
+ h->ioaccel2_cmd_pool =
+ pci_alloc_consistent(h->pdev,
+ h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool),
+ &(h->ioaccel2_cmd_pool_dhandle));
+
+ h->ioaccel2_blockFetchTable =
+ kmalloc(((h->ioaccel_maxsg + 1) *
+ sizeof(u32)), GFP_KERNEL);
+
+ if ((h->ioaccel2_cmd_pool == NULL) ||
+ (h->ioaccel2_blockFetchTable == NULL))
+ goto clean_up;
+
+ memset(h->ioaccel2_cmd_pool, 0,
+ h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool));
+ return 0;
+
+clean_up:
+ if (h->ioaccel2_cmd_pool)
+ pci_free_consistent(h->pdev,
+ h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool),
+ h->ioaccel2_cmd_pool, h->ioaccel2_cmd_pool_dhandle);
+ kfree(h->ioaccel2_blockFetchTable);
+ return 1;
}
static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
{
u32 trans_support;
+ unsigned long transMethod = CFGTBL_Trans_Performant |
+ CFGTBL_Trans_use_short_tags;
int i;
if (hpsa_simple_mode)
return;
+ /* Check for I/O accelerator mode support */
+ if (trans_support & CFGTBL_Trans_io_accel1) {
+ transMethod |= CFGTBL_Trans_io_accel1 |
+ CFGTBL_Trans_enable_directed_msix;
+ if (hpsa_alloc_ioaccel_cmd_and_bft(h))
+ goto clean_up;
+ } else {
+ if (trans_support & CFGTBL_Trans_io_accel2) {
+ transMethod |= CFGTBL_Trans_io_accel2 |
+ CFGTBL_Trans_enable_directed_msix;
+ if (ioaccel2_alloc_cmds_and_bft(h))
+ goto clean_up;
+ }
+ }
+
+ /* TODO, check that this next line h->nreply_queues is correct */
trans_support = readl(&(h->cfgtable->TransportSupport));
if (!(trans_support & PERFORMANT_MODE))
return;
- h->nreply_queues = h->msix_vector ? MAX_REPLY_QUEUES : 1;
+ h->nreply_queues = h->msix_vector > 0 ? h->msix_vector : 1;
hpsa_get_max_perf_mode_cmds(h);
/* Performant mode ring buffer and supporting data structures */
h->reply_pool_size = h->max_commands * sizeof(u64) * h->nreply_queues;
@@ -5200,9 +7505,7 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
|| (h->blockFetchTable == NULL))
goto clean_up;
- hpsa_enter_performant_mode(h,
- trans_support & CFGTBL_Trans_use_short_tags);
-
+ hpsa_enter_performant_mode(h, trans_support);
return;
clean_up:
@@ -5212,6 +7515,31 @@ clean_up:
kfree(h->blockFetchTable);
}
+static int is_accelerated_cmd(struct CommandList *c)
+{
+ return c->cmd_type == CMD_IOACCEL1 || c->cmd_type == CMD_IOACCEL2;
+}
+
+static void hpsa_drain_accel_commands(struct ctlr_info *h)
+{
+ struct CommandList *c = NULL;
+ unsigned long flags;
+ int accel_cmds_out;
+
+ do { /* wait for all outstanding commands to drain out */
+ accel_cmds_out = 0;
+ spin_lock_irqsave(&h->lock, flags);
+ list_for_each_entry(c, &h->cmpQ, list)
+ accel_cmds_out += is_accelerated_cmd(c);
+ list_for_each_entry(c, &h->reqQ, list)
+ accel_cmds_out += is_accelerated_cmd(c);
+ spin_unlock_irqrestore(&h->lock, flags);
+ if (accel_cmds_out <= 0)
+ break;
+ msleep(100);
+ } while (1);
+}
+
/*
* This is it. Register the PCI driver information for the cards we control
* the OS will call our registered routines when it finds one of our cards.
@@ -5226,5 +7554,83 @@ static void __exit hpsa_cleanup(void)
pci_unregister_driver(&hpsa_pci_driver);
}
+static void __attribute__((unused)) verify_offsets(void)
+{
+#define VERIFY_OFFSET(member, offset) \
+ BUILD_BUG_ON(offsetof(struct raid_map_data, member) != offset)
+
+ VERIFY_OFFSET(structure_size, 0);
+ VERIFY_OFFSET(volume_blk_size, 4);
+ VERIFY_OFFSET(volume_blk_cnt, 8);
+ VERIFY_OFFSET(phys_blk_shift, 16);
+ VERIFY_OFFSET(parity_rotation_shift, 17);
+ VERIFY_OFFSET(strip_size, 18);
+ VERIFY_OFFSET(disk_starting_blk, 20);
+ VERIFY_OFFSET(disk_blk_cnt, 28);
+ VERIFY_OFFSET(data_disks_per_row, 36);
+ VERIFY_OFFSET(metadata_disks_per_row, 38);
+ VERIFY_OFFSET(row_cnt, 40);
+ VERIFY_OFFSET(layout_map_count, 42);
+ VERIFY_OFFSET(flags, 44);
+ VERIFY_OFFSET(dekindex, 46);
+ /* VERIFY_OFFSET(reserved, 48 */
+ VERIFY_OFFSET(data, 64);
+
+#undef VERIFY_OFFSET
+
+#define VERIFY_OFFSET(member, offset) \
+ BUILD_BUG_ON(offsetof(struct io_accel2_cmd, member) != offset)
+
+ VERIFY_OFFSET(IU_type, 0);
+ VERIFY_OFFSET(direction, 1);
+ VERIFY_OFFSET(reply_queue, 2);
+ /* VERIFY_OFFSET(reserved1, 3); */
+ VERIFY_OFFSET(scsi_nexus, 4);
+ VERIFY_OFFSET(Tag, 8);
+ VERIFY_OFFSET(cdb, 16);
+ VERIFY_OFFSET(cciss_lun, 32);
+ VERIFY_OFFSET(data_len, 40);
+ VERIFY_OFFSET(cmd_priority_task_attr, 44);
+ VERIFY_OFFSET(sg_count, 45);
+ /* VERIFY_OFFSET(reserved3 */
+ VERIFY_OFFSET(err_ptr, 48);
+ VERIFY_OFFSET(err_len, 56);
+ /* VERIFY_OFFSET(reserved4 */
+ VERIFY_OFFSET(sg, 64);
+
+#undef VERIFY_OFFSET
+
+#define VERIFY_OFFSET(member, offset) \
+ BUILD_BUG_ON(offsetof(struct io_accel1_cmd, member) != offset)
+
+ VERIFY_OFFSET(dev_handle, 0x00);
+ VERIFY_OFFSET(reserved1, 0x02);
+ VERIFY_OFFSET(function, 0x03);
+ VERIFY_OFFSET(reserved2, 0x04);
+ VERIFY_OFFSET(err_info, 0x0C);
+ VERIFY_OFFSET(reserved3, 0x10);
+ VERIFY_OFFSET(err_info_len, 0x12);
+ VERIFY_OFFSET(reserved4, 0x13);
+ VERIFY_OFFSET(sgl_offset, 0x14);
+ VERIFY_OFFSET(reserved5, 0x15);
+ VERIFY_OFFSET(transfer_len, 0x1C);
+ VERIFY_OFFSET(reserved6, 0x20);
+ VERIFY_OFFSET(io_flags, 0x24);
+ VERIFY_OFFSET(reserved7, 0x26);
+ VERIFY_OFFSET(LUN, 0x34);
+ VERIFY_OFFSET(control, 0x3C);
+ VERIFY_OFFSET(CDB, 0x40);
+ VERIFY_OFFSET(reserved8, 0x50);
+ VERIFY_OFFSET(host_context_flags, 0x60);
+ VERIFY_OFFSET(timeout_sec, 0x62);
+ VERIFY_OFFSET(ReplyQueue, 0x64);
+ VERIFY_OFFSET(reserved9, 0x65);
+ VERIFY_OFFSET(Tag, 0x68);
+ VERIFY_OFFSET(host_addr, 0x70);
+ VERIFY_OFFSET(CISS_LUN, 0x78);
+ VERIFY_OFFSET(SG, 0x78 + 8);
+#undef VERIFY_OFFSET
+}
+
module_init(hpsa_init);
module_exit(hpsa_cleanup);
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 01c328349c83..44235a27e1b6 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -1,6 +1,6 @@
/*
* Disk Array driver for HP Smart Array SAS controllers
- * Copyright 2000, 2009 Hewlett-Packard Development Company, L.P.
+ * Copyright 2000, 2014 Hewlett-Packard Development Company, L.P.
*
* 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
@@ -46,6 +46,15 @@ struct hpsa_scsi_dev_t {
unsigned char vendor[8]; /* bytes 8-15 of inquiry data */
unsigned char model[16]; /* bytes 16-31 of inquiry data */
unsigned char raid_level; /* from inquiry page 0xC1 */
+ unsigned char volume_offline; /* discovered via TUR or VPD */
+ u32 ioaccel_handle;
+ int offload_config; /* I/O accel RAID offload configured */
+ int offload_enabled; /* I/O accel RAID offload enabled */
+ int offload_to_mirror; /* Send next I/O accelerator RAID
+ * offload request to mirror drive
+ */
+ struct raid_map_data raid_map; /* I/O accelerator RAID map */
+
};
struct reply_pool {
@@ -55,6 +64,46 @@ struct reply_pool {
u32 current_entry;
};
+#pragma pack(1)
+struct bmic_controller_parameters {
+ u8 led_flags;
+ u8 enable_command_list_verification;
+ u8 backed_out_write_drives;
+ u16 stripes_for_parity;
+ u8 parity_distribution_mode_flags;
+ u16 max_driver_requests;
+ u16 elevator_trend_count;
+ u8 disable_elevator;
+ u8 force_scan_complete;
+ u8 scsi_transfer_mode;
+ u8 force_narrow;
+ u8 rebuild_priority;
+ u8 expand_priority;
+ u8 host_sdb_asic_fix;
+ u8 pdpi_burst_from_host_disabled;
+ char software_name[64];
+ char hardware_name[32];
+ u8 bridge_revision;
+ u8 snapshot_priority;
+ u32 os_specific;
+ u8 post_prompt_timeout;
+ u8 automatic_drive_slamming;
+ u8 reserved1;
+ u8 nvram_flags;
+ u8 cache_nvram_flags;
+ u8 drive_config_flags;
+ u16 reserved2;
+ u8 temp_warning_level;
+ u8 temp_shutdown_level;
+ u8 temp_condition_reset;
+ u8 max_coalesce_commands;
+ u32 max_coalesce_delay;
+ u8 orca_password[4];
+ u8 access_id[16];
+ u8 reserved[356];
+};
+#pragma pack()
+
struct ctlr_info {
int ctlr;
char devname[8];
@@ -80,6 +129,7 @@ struct ctlr_info {
unsigned int msi_vector;
int intr_mode; /* either PERF_MODE_INT or SIMPLE_MODE_INT */
struct access_method access;
+ char hba_mode_enabled;
/* queue and queue Info */
struct list_head reqQ;
@@ -95,6 +145,10 @@ struct ctlr_info {
/* pointers to command and error info pool */
struct CommandList *cmd_pool;
dma_addr_t cmd_pool_dhandle;
+ struct io_accel1_cmd *ioaccel_cmd_pool;
+ dma_addr_t ioaccel_cmd_pool_dhandle;
+ struct io_accel2_cmd *ioaccel2_cmd_pool;
+ dma_addr_t ioaccel2_cmd_pool_dhandle;
struct ErrorInfo *errinfo_pool;
dma_addr_t errinfo_pool_dhandle;
unsigned long *cmd_pool_bits;
@@ -128,7 +182,14 @@ struct ctlr_info {
u8 nreply_queues;
dma_addr_t reply_pool_dhandle;
u32 *blockFetchTable;
+ u32 *ioaccel1_blockFetchTable;
+ u32 *ioaccel2_blockFetchTable;
+ u32 *ioaccel2_bft2_regs;
unsigned char *hba_inquiry_data;
+ u32 driver_support;
+ u32 fw_support;
+ int ioaccel_support;
+ int ioaccel_maxsg;
u64 last_intr_timestamp;
u32 last_heartbeat;
u64 last_heartbeat_timestamp;
@@ -161,7 +222,35 @@ struct ctlr_info {
#define HPSATMF_LOG_QRY_TASK (1 << 23)
#define HPSATMF_LOG_QRY_TSET (1 << 24)
#define HPSATMF_LOG_QRY_ASYNC (1 << 25)
+ u32 events;
+#define CTLR_STATE_CHANGE_EVENT (1 << 0)
+#define CTLR_ENCLOSURE_HOT_PLUG_EVENT (1 << 1)
+#define CTLR_STATE_CHANGE_EVENT_PHYSICAL_DRV (1 << 4)
+#define CTLR_STATE_CHANGE_EVENT_LOGICAL_DRV (1 << 5)
+#define CTLR_STATE_CHANGE_EVENT_REDUNDANT_CNTRL (1 << 6)
+#define CTLR_STATE_CHANGE_EVENT_AIO_ENABLED_DISABLED (1 << 30)
+#define CTLR_STATE_CHANGE_EVENT_AIO_CONFIG_CHANGE (1 << 31)
+
+#define RESCAN_REQUIRED_EVENT_BITS \
+ (CTLR_STATE_CHANGE_EVENT | \
+ CTLR_ENCLOSURE_HOT_PLUG_EVENT | \
+ CTLR_STATE_CHANGE_EVENT_PHYSICAL_DRV | \
+ CTLR_STATE_CHANGE_EVENT_LOGICAL_DRV | \
+ CTLR_STATE_CHANGE_EVENT_REDUNDANT_CNTRL | \
+ CTLR_STATE_CHANGE_EVENT_AIO_ENABLED_DISABLED | \
+ CTLR_STATE_CHANGE_EVENT_AIO_CONFIG_CHANGE)
+ spinlock_t offline_device_lock;
+ struct list_head offline_device_list;
+ int acciopath_status;
+ int drv_req_rescan; /* flag for driver to request rescan event */
+ int raid_offload_debug;
};
+
+struct offline_device_entry {
+ unsigned char scsi3addr[8];
+ struct list_head offline_list;
+};
+
#define HPSA_ABORT_MSG 0
#define HPSA_DEVICE_RESET_MSG 1
#define HPSA_RESET_TYPE_CONTROLLER 0x00
@@ -242,6 +331,14 @@ struct ctlr_info {
#define HPSA_INTR_ON 1
#define HPSA_INTR_OFF 0
+
+/*
+ * Inbound Post Queue offsets for IO Accelerator Mode 2
+ */
+#define IOACCEL2_INBOUND_POSTQ_32 0x48
+#define IOACCEL2_INBOUND_POSTQ_64_LOW 0xd0
+#define IOACCEL2_INBOUND_POSTQ_64_HI 0xd4
+
/*
Send the command to the hardware
*/
@@ -254,6 +351,18 @@ static void SA5_submit_command(struct ctlr_info *h,
(void) readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
}
+static void SA5_submit_command_ioaccel2(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ dev_dbg(&h->pdev->dev, "Sending %x, tag = %x\n", c->busaddr,
+ c->Header.Tag.lower);
+ if (c->cmd_type == CMD_IOACCEL2)
+ writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32);
+ else
+ writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET);
+ (void) readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
+}
+
/*
* This card is the opposite of the other cards.
* 0 turns interrupts on...
@@ -387,6 +496,50 @@ static bool SA5_performant_intr_pending(struct ctlr_info *h)
return register_value & SA5_OUTDB_STATUS_PERF_BIT;
}
+#define SA5_IOACCEL_MODE1_INTR_STATUS_CMP_BIT 0x100
+
+static bool SA5_ioaccel_mode1_intr_pending(struct ctlr_info *h)
+{
+ unsigned long register_value = readl(h->vaddr + SA5_INTR_STATUS);
+
+ return (register_value & SA5_IOACCEL_MODE1_INTR_STATUS_CMP_BIT) ?
+ true : false;
+}
+
+#define IOACCEL_MODE1_REPLY_QUEUE_INDEX 0x1A0
+#define IOACCEL_MODE1_PRODUCER_INDEX 0x1B8
+#define IOACCEL_MODE1_CONSUMER_INDEX 0x1BC
+#define IOACCEL_MODE1_REPLY_UNUSED 0xFFFFFFFFFFFFFFFFULL
+
+static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q)
+{
+ u64 register_value;
+ struct reply_pool *rq = &h->reply_queue[q];
+ unsigned long flags;
+
+ BUG_ON(q >= h->nreply_queues);
+
+ register_value = rq->head[rq->current_entry];
+ if (register_value != IOACCEL_MODE1_REPLY_UNUSED) {
+ rq->head[rq->current_entry] = IOACCEL_MODE1_REPLY_UNUSED;
+ if (++rq->current_entry == rq->size)
+ rq->current_entry = 0;
+ /*
+ * @todo
+ *
+ * Don't really need to write the new index after each command,
+ * but with current driver design this is easiest.
+ */
+ wmb();
+ writel((q << 24) | rq->current_entry, h->vaddr +
+ IOACCEL_MODE1_CONSUMER_INDEX);
+ spin_lock_irqsave(&h->lock, flags);
+ h->commands_outstanding--;
+ spin_unlock_irqrestore(&h->lock, flags);
+ }
+ return (unsigned long) register_value;
+}
+
static struct access_method SA5_access = {
SA5_submit_command,
SA5_intr_mask,
@@ -395,6 +548,22 @@ static struct access_method SA5_access = {
SA5_completed,
};
+static struct access_method SA5_ioaccel_mode1_access = {
+ SA5_submit_command,
+ SA5_performant_intr_mask,
+ SA5_fifo_full,
+ SA5_ioaccel_mode1_intr_pending,
+ SA5_ioaccel_mode1_completed,
+};
+
+static struct access_method SA5_ioaccel_mode2_access = {
+ SA5_submit_command_ioaccel2,
+ SA5_performant_intr_mask,
+ SA5_fifo_full,
+ SA5_performant_intr_pending,
+ SA5_performant_completed,
+};
+
static struct access_method SA5_performant_access = {
SA5_submit_command,
SA5_performant_intr_mask,
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index bfc8c4ea66f8..b5cc7052339f 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -1,6 +1,6 @@
/*
* Disk Array driver for HP Smart Array SAS controllers
- * Copyright 2000, 2009 Hewlett-Packard Development Company, L.P.
+ * Copyright 2000, 2014 Hewlett-Packard Development Company, L.P.
*
* 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
@@ -25,6 +25,7 @@
#define SENSEINFOBYTES 32 /* may vary between hbas */
#define SG_ENTRIES_IN_CMD 32 /* Max SG entries excluding chain blocks */
#define HPSA_SG_CHAIN 0x80000000
+#define HPSA_SG_LAST 0x40000000
#define MAXREPLYQS 256
/* Command Status value */
@@ -41,6 +42,8 @@
#define CMD_UNSOLICITED_ABORT 0x000A
#define CMD_TIMEOUT 0x000B
#define CMD_UNABORTABLE 0x000C
+#define CMD_IOACCEL_DISABLED 0x000E
+
/* Unit Attentions ASC's as defined for the MSA2012sa */
#define POWER_OR_RESET 0x29
@@ -79,8 +82,9 @@
#define ATTR_ACA 0x07
/* cdb type */
-#define TYPE_CMD 0x00
-#define TYPE_MSG 0x01
+#define TYPE_CMD 0x00
+#define TYPE_MSG 0x01
+#define TYPE_IOACCEL2_CMD 0x81 /* 0x81 is not used by hardware */
/* Message Types */
#define HPSA_TASK_MANAGEMENT 0x00
@@ -125,9 +129,12 @@
#define CFGTBL_AccCmds 0x00000001l
#define DOORBELL_CTLR_RESET 0x00000004l
#define DOORBELL_CTLR_RESET2 0x00000020l
+#define DOORBELL_CLEAR_EVENTS 0x00000040l
#define CFGTBL_Trans_Simple 0x00000002l
#define CFGTBL_Trans_Performant 0x00000004l
+#define CFGTBL_Trans_io_accel1 0x00000080l
+#define CFGTBL_Trans_io_accel2 0x00000100l
#define CFGTBL_Trans_use_short_tags 0x20000000l
#define CFGTBL_Trans_enable_directed_msix (1 << 30)
@@ -135,6 +142,28 @@
#define CFGTBL_BusType_Ultra3 0x00000002l
#define CFGTBL_BusType_Fibre1G 0x00000100l
#define CFGTBL_BusType_Fibre2G 0x00000200l
+
+/* VPD Inquiry types */
+#define HPSA_VPD_SUPPORTED_PAGES 0x00
+#define HPSA_VPD_LV_DEVICE_GEOMETRY 0xC1
+#define HPSA_VPD_LV_IOACCEL_STATUS 0xC2
+#define HPSA_VPD_LV_STATUS 0xC3
+#define HPSA_VPD_HEADER_SZ 4
+
+/* Logical volume states */
+#define HPSA_VPD_LV_STATUS_UNSUPPORTED -1
+#define HPSA_LV_OK 0x0
+#define HPSA_LV_UNDERGOING_ERASE 0x0F
+#define HPSA_LV_UNDERGOING_RPI 0x12
+#define HPSA_LV_PENDING_RPI 0x13
+#define HPSA_LV_ENCRYPTED_NO_KEY 0x14
+#define HPSA_LV_PLAINTEXT_IN_ENCRYPT_ONLY_CONTROLLER 0x15
+#define HPSA_LV_UNDERGOING_ENCRYPTION 0x16
+#define HPSA_LV_UNDERGOING_ENCRYPTION_REKEYING 0x17
+#define HPSA_LV_ENCRYPTED_IN_NON_ENCRYPTED_CONTROLLER 0x18
+#define HPSA_LV_PENDING_ENCRYPTION 0x19
+#define HPSA_LV_PENDING_ENCRYPTION_REKEYING 0x1A
+
struct vals32 {
u32 lower;
u32 upper;
@@ -162,9 +191,50 @@ struct InquiryData {
#define HPSA_REPORT_LOG 0xc2 /* Report Logical LUNs */
#define HPSA_REPORT_PHYS 0xc3 /* Report Physical LUNs */
+#define HPSA_REPORT_PHYS_EXTENDED 0x02
+#define HPSA_CISS_READ 0xc0 /* CISS Read */
+#define HPSA_GET_RAID_MAP 0xc8 /* CISS Get RAID Layout Map */
+
+#define RAID_MAP_MAX_ENTRIES 256
+
+struct raid_map_disk_data {
+ u32 ioaccel_handle; /**< Handle to access this disk via the
+ * I/O accelerator */
+ u8 xor_mult[2]; /**< XOR multipliers for this position,
+ * valid for data disks only */
+ u8 reserved[2];
+};
+
+struct raid_map_data {
+ u32 structure_size; /* Size of entire structure in bytes */
+ u32 volume_blk_size; /* bytes / block in the volume */
+ u64 volume_blk_cnt; /* logical blocks on the volume */
+ u8 phys_blk_shift; /* Shift factor to convert between
+ * units of logical blocks and physical
+ * disk blocks */
+ u8 parity_rotation_shift; /* Shift factor to convert between units
+ * of logical stripes and physical
+ * stripes */
+ u16 strip_size; /* blocks used on each disk / stripe */
+ u64 disk_starting_blk; /* First disk block used in volume */
+ u64 disk_blk_cnt; /* disk blocks used by volume / disk */
+ u16 data_disks_per_row; /* data disk entries / row in the map */
+ u16 metadata_disks_per_row; /* mirror/parity disk entries / row
+ * in the map */
+ u16 row_cnt; /* rows in each layout map */
+ u16 layout_map_count; /* layout maps (1 map per mirror/parity
+ * group) */
+ u16 flags; /* Bit 0 set if encryption enabled */
+#define RAID_MAP_FLAG_ENCRYPT_ON 0x01
+ u16 dekindex; /* Data encryption key index. */
+ u8 reserved[16];
+ struct raid_map_disk_data data[RAID_MAP_MAX_ENTRIES];
+};
+
struct ReportLUNdata {
u8 LUNListLength[4];
- u32 reserved;
+ u8 extended_response_flag;
+ u8 reserved[3];
u8 LUN[HPSA_MAX_LUN][8];
};
@@ -187,6 +257,7 @@ struct SenseSubsystem_info {
#define BMIC_CACHE_FLUSH 0xc2
#define HPSA_CACHE_FLUSH 0x01 /* C2 was already being used by HPSA */
#define BMIC_FLASH_FIRMWARE 0xF7
+#define BMIC_SENSE_CONTROLLER_PARAMETERS 0x64
/* Command List Structure */
union SCSI3Addr {
@@ -283,6 +354,8 @@ struct ErrorInfo {
/* Command types */
#define CMD_IOCTL_PEND 0x01
#define CMD_SCSI 0x03
+#define CMD_IOACCEL1 0x04
+#define CMD_IOACCEL2 0x05
#define DIRECT_LOOKUP_SHIFT 5
#define DIRECT_LOOKUP_BIT 0x10
@@ -314,7 +387,6 @@ struct CommandList {
int cmd_type;
long cmdindex;
struct list_head list;
- struct request *rq;
struct completion *waiting;
void *scsi_cmd;
@@ -327,16 +399,183 @@ struct CommandList {
*/
#define IS_32_BIT ((8 - sizeof(long))/4)
#define IS_64_BIT (!IS_32_BIT)
-#define PAD_32 (4)
-#define PAD_64 (4)
+#define PAD_32 (40)
+#define PAD_64 (12)
#define COMMANDLIST_PAD (IS_32_BIT * PAD_32 + IS_64_BIT * PAD_64)
u8 pad[COMMANDLIST_PAD];
};
+/* Max S/G elements in I/O accelerator command */
+#define IOACCEL1_MAXSGENTRIES 24
+#define IOACCEL2_MAXSGENTRIES 28
+
+/*
+ * Structure for I/O accelerator (mode 1) commands.
+ * Note that this structure must be 128-byte aligned in size.
+ */
+struct io_accel1_cmd {
+ u16 dev_handle; /* 0x00 - 0x01 */
+ u8 reserved1; /* 0x02 */
+ u8 function; /* 0x03 */
+ u8 reserved2[8]; /* 0x04 - 0x0B */
+ u32 err_info; /* 0x0C - 0x0F */
+ u8 reserved3[2]; /* 0x10 - 0x11 */
+ u8 err_info_len; /* 0x12 */
+ u8 reserved4; /* 0x13 */
+ u8 sgl_offset; /* 0x14 */
+ u8 reserved5[7]; /* 0x15 - 0x1B */
+ u32 transfer_len; /* 0x1C - 0x1F */
+ u8 reserved6[4]; /* 0x20 - 0x23 */
+ u16 io_flags; /* 0x24 - 0x25 */
+ u8 reserved7[14]; /* 0x26 - 0x33 */
+ u8 LUN[8]; /* 0x34 - 0x3B */
+ u32 control; /* 0x3C - 0x3F */
+ u8 CDB[16]; /* 0x40 - 0x4F */
+ u8 reserved8[16]; /* 0x50 - 0x5F */
+ u16 host_context_flags; /* 0x60 - 0x61 */
+ u16 timeout_sec; /* 0x62 - 0x63 */
+ u8 ReplyQueue; /* 0x64 */
+ u8 reserved9[3]; /* 0x65 - 0x67 */
+ struct vals32 Tag; /* 0x68 - 0x6F */
+ struct vals32 host_addr; /* 0x70 - 0x77 */
+ u8 CISS_LUN[8]; /* 0x78 - 0x7F */
+ struct SGDescriptor SG[IOACCEL1_MAXSGENTRIES];
+#define IOACCEL1_PAD_64 0
+#define IOACCEL1_PAD_32 0
+#define IOACCEL1_PAD (IS_32_BIT * IOACCEL1_PAD_32 + \
+ IS_64_BIT * IOACCEL1_PAD_64)
+ u8 pad[IOACCEL1_PAD];
+};
+
+#define IOACCEL1_FUNCTION_SCSIIO 0x00
+#define IOACCEL1_SGLOFFSET 32
+
+#define IOACCEL1_IOFLAGS_IO_REQ 0x4000
+#define IOACCEL1_IOFLAGS_CDBLEN_MASK 0x001F
+#define IOACCEL1_IOFLAGS_CDBLEN_MAX 16
+
+#define IOACCEL1_CONTROL_NODATAXFER 0x00000000
+#define IOACCEL1_CONTROL_DATA_OUT 0x01000000
+#define IOACCEL1_CONTROL_DATA_IN 0x02000000
+#define IOACCEL1_CONTROL_TASKPRIO_MASK 0x00007800
+#define IOACCEL1_CONTROL_TASKPRIO_SHIFT 11
+#define IOACCEL1_CONTROL_SIMPLEQUEUE 0x00000000
+#define IOACCEL1_CONTROL_HEADOFQUEUE 0x00000100
+#define IOACCEL1_CONTROL_ORDEREDQUEUE 0x00000200
+#define IOACCEL1_CONTROL_ACA 0x00000400
+
+#define IOACCEL1_HCFLAGS_CISS_FORMAT 0x0013
+
+#define IOACCEL1_BUSADDR_CMDTYPE 0x00000060
+
+struct ioaccel2_sg_element {
+ u64 address;
+ u32 length;
+ u8 reserved[3];
+ u8 chain_indicator;
+#define IOACCEL2_CHAIN 0x80
+};
+
+/*
+ * SCSI Response Format structure for IO Accelerator Mode 2
+ */
+struct io_accel2_scsi_response {
+ u8 IU_type;
+#define IOACCEL2_IU_TYPE_SRF 0x60
+ u8 reserved1[3];
+ u8 req_id[4]; /* request identifier */
+ u8 reserved2[4];
+ u8 serv_response; /* service response */
+#define IOACCEL2_SERV_RESPONSE_COMPLETE 0x000
+#define IOACCEL2_SERV_RESPONSE_FAILURE 0x001
+#define IOACCEL2_SERV_RESPONSE_TMF_COMPLETE 0x002
+#define IOACCEL2_SERV_RESPONSE_TMF_SUCCESS 0x003
+#define IOACCEL2_SERV_RESPONSE_TMF_REJECTED 0x004
+#define IOACCEL2_SERV_RESPONSE_TMF_WRONG_LUN 0x005
+ u8 status; /* status */
+#define IOACCEL2_STATUS_SR_TASK_COMP_GOOD 0x00
+#define IOACCEL2_STATUS_SR_TASK_COMP_CHK_COND 0x02
+#define IOACCEL2_STATUS_SR_TASK_COMP_BUSY 0x08
+#define IOACCEL2_STATUS_SR_TASK_COMP_RES_CON 0x18
+#define IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL 0x28
+#define IOACCEL2_STATUS_SR_TASK_COMP_ABORTED 0x40
+#define IOACCEL2_STATUS_SR_IOACCEL_DISABLED 0x0E
+ u8 data_present; /* low 2 bits */
+#define IOACCEL2_NO_DATAPRESENT 0x000
+#define IOACCEL2_RESPONSE_DATAPRESENT 0x001
+#define IOACCEL2_SENSE_DATA_PRESENT 0x002
+#define IOACCEL2_RESERVED 0x003
+ u8 sense_data_len; /* sense/response data length */
+ u8 resid_cnt[4]; /* residual count */
+ u8 sense_data_buff[32]; /* sense/response data buffer */
+};
+
+#define IOACCEL2_64_PAD 76
+#define IOACCEL2_32_PAD 76
+#define IOACCEL2_PAD (IS_32_BIT * IOACCEL2_32_PAD + \
+ IS_64_BIT * IOACCEL2_64_PAD)
+/*
+ * Structure for I/O accelerator (mode 2 or m2) commands.
+ * Note that this structure must be 128-byte aligned in size.
+ */
+struct io_accel2_cmd {
+ u8 IU_type; /* IU Type */
+ u8 direction; /* direction, memtype, and encryption */
+#define IOACCEL2_DIRECTION_MASK 0x03 /* bits 0,1: direction */
+#define IOACCEL2_DIRECTION_MEMTYPE_MASK 0x04 /* bit 2: memtype source/dest */
+ /* 0b=PCIe, 1b=DDR */
+#define IOACCEL2_DIRECTION_ENCRYPT_MASK 0x08 /* bit 3: encryption flag */
+ /* 0=off, 1=on */
+ u8 reply_queue; /* Reply Queue ID */
+ u8 reserved1; /* Reserved */
+ u32 scsi_nexus; /* Device Handle */
+ u32 Tag; /* cciss tag, lower 4 bytes only */
+ u32 tweak_lower; /* Encryption tweak, lower 4 bytes */
+ u8 cdb[16]; /* SCSI Command Descriptor Block */
+ u8 cciss_lun[8]; /* 8 byte SCSI address */
+ u32 data_len; /* Total bytes to transfer */
+ u8 cmd_priority_task_attr; /* priority and task attrs */
+#define IOACCEL2_PRIORITY_MASK 0x78
+#define IOACCEL2_ATTR_MASK 0x07
+ u8 sg_count; /* Number of sg elements */
+ u16 dekindex; /* Data encryption key index */
+ u64 err_ptr; /* Error Pointer */
+ u32 err_len; /* Error Length*/
+ u32 tweak_upper; /* Encryption tweak, upper 4 bytes */
+ struct ioaccel2_sg_element sg[IOACCEL2_MAXSGENTRIES];
+ struct io_accel2_scsi_response error_data;
+ u8 pad[IOACCEL2_PAD];
+};
+
+/*
+ * defines for Mode 2 command struct
+ * FIXME: this can't be all I need mfm
+ */
+#define IOACCEL2_IU_TYPE 0x40
+#define IOACCEL2_IU_TMF_TYPE 0x41
+#define IOACCEL2_DIR_NO_DATA 0x00
+#define IOACCEL2_DIR_DATA_IN 0x01
+#define IOACCEL2_DIR_DATA_OUT 0x02
+/*
+ * SCSI Task Management Request format for Accelerator Mode 2
+ */
+struct hpsa_tmf_struct {
+ u8 iu_type; /* Information Unit Type */
+ u8 reply_queue; /* Reply Queue ID */
+ u8 tmf; /* Task Management Function */
+ u8 reserved1; /* byte 3 Reserved */
+ u32 it_nexus; /* SCSI I-T Nexus */
+ u8 lun_id[8]; /* LUN ID for TMF request */
+ struct vals32 Tag; /* cciss tag associated w/ request */
+ struct vals32 abort_tag;/* cciss tag of SCSI cmd or task to abort */
+ u64 error_ptr; /* Error Pointer */
+ u32 error_len; /* Error Length */
+};
+
/* Configuration Table Structure */
struct HostWrite {
u32 TransportRequest;
- u32 Reserved;
+ u32 command_pool_addr_hi;
u32 CoalIntDelay;
u32 CoalIntCount;
};
@@ -344,6 +583,9 @@ struct HostWrite {
#define SIMPLE_MODE 0x02
#define PERFORMANT_MODE 0x04
#define MEMQ_MODE 0x08
+#define IOACCEL_MODE_1 0x80
+
+#define DRIVER_SUPPORT_UA_ENABLE 0x00000001
struct CfgTable {
u8 Signature[4];
@@ -373,8 +615,18 @@ struct CfgTable {
u32 misc_fw_support; /* offset 0x78 */
#define MISC_FW_DOORBELL_RESET (0x02)
#define MISC_FW_DOORBELL_RESET2 (0x010)
+#define MISC_FW_RAID_OFFLOAD_BASIC (0x020)
+#define MISC_FW_EVENT_NOTIFY (0x080)
u8 driver_version[32];
-
+ u32 max_cached_write_size;
+ u8 driver_scratchpad[16];
+ u32 max_error_info_length;
+ u32 io_accel_max_embedded_sg_count;
+ u32 io_accel_request_size_offset;
+ u32 event_notify;
+#define HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_STATE_CHANGE (1 << 30)
+#define HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_CONFIG_CHANGE (1 << 31)
+ u32 clear_event_notify;
};
#define NUM_BLOCKFETCH_ENTRIES 8
diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
index bf9eca845166..56f8a861ed72 100644
--- a/drivers/scsi/ibmvscsi/ibmvstgt.c
+++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
@@ -589,7 +589,7 @@ static int crq_queue_create(struct crq_queue *queue, struct srp_target *target)
}
err = request_irq(vport->dma_dev->irq, &ibmvstgt_interrupt,
- IRQF_DISABLED, "ibmvstgt", target);
+ 0, "ibmvstgt", target);
if (err)
goto req_irq_failed;
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
index bf028218ac36..b1c4d831137d 100644
--- a/drivers/scsi/in2000.c
+++ b/drivers/scsi/in2000.c
@@ -2015,7 +2015,7 @@ static int __init in2000_detect(struct scsi_host_template * tpnt)
write1_io(0, IO_FIFO_READ); /* start fifo out in read mode */
write1_io(0, IO_INTR_MASK); /* allow all ints */
x = int_tab[(switches & (SW_INT0 | SW_INT1)) >> SW_INT_SHIFT];
- if (request_irq(x, in2000_intr, IRQF_DISABLED, "in2000", instance)) {
+ if (request_irq(x, in2000_intr, 0, "in2000", instance)) {
printk("in2000_detect: Unable to allocate IRQ.\n");
detect_count--;
continue;
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index 280d5af113d1..e5dae7b54d9a 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -2931,7 +2931,7 @@ static int initio_probe_one(struct pci_dev *pdev,
shost->base = host->addr;
shost->sg_tablesize = TOTAL_SG_ENTRY;
- error = request_irq(pdev->irq, i91u_intr, IRQF_DISABLED|IRQF_SHARED, "i91u", shost);
+ error = request_irq(pdev->irq, i91u_intr, IRQF_SHARED, "i91u", shost);
if (error < 0) {
printk(KERN_WARNING "initio: Unable to request IRQ %d\n", pdev->irq);
goto out_free_scbs;
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 3f5b56a99892..924b0ba74dfe 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -1143,6 +1143,7 @@ static void ipr_init_res_entry(struct ipr_resource_entry *res,
res->add_to_ml = 0;
res->del_from_ml = 0;
res->resetting_device = 0;
+ res->reset_occurred = 0;
res->sdev = NULL;
res->sata_port = NULL;
@@ -2367,6 +2368,42 @@ static void ipr_log_generic_error(struct ipr_ioa_cfg *ioa_cfg,
}
/**
+ * ipr_log_sis64_device_error - Log a cache error.
+ * @ioa_cfg: ioa config struct
+ * @hostrcb: hostrcb struct
+ *
+ * Return value:
+ * none
+ **/
+static void ipr_log_sis64_device_error(struct ipr_ioa_cfg *ioa_cfg,
+ struct ipr_hostrcb *hostrcb)
+{
+ struct ipr_hostrcb_type_21_error *error;
+ char buffer[IPR_MAX_RES_PATH_LENGTH];
+
+ error = &hostrcb->hcam.u.error64.u.type_21_error;
+
+ ipr_err("-----Failing Device Information-----\n");
+ ipr_err("World Wide Unique ID: %08X%08X%08X%08X\n",
+ be32_to_cpu(error->wwn[0]), be32_to_cpu(error->wwn[1]),
+ be32_to_cpu(error->wwn[2]), be32_to_cpu(error->wwn[3]));
+ ipr_err("Device Resource Path: %s\n",
+ __ipr_format_res_path(error->res_path,
+ buffer, sizeof(buffer)));
+ error->primary_problem_desc[sizeof(error->primary_problem_desc) - 1] = '\0';
+ error->second_problem_desc[sizeof(error->second_problem_desc) - 1] = '\0';
+ ipr_err("Primary Problem Description: %s\n", error->primary_problem_desc);
+ ipr_err("Secondary Problem Description: %s\n", error->second_problem_desc);
+ ipr_err("SCSI Sense Data:\n");
+ ipr_log_hex_data(ioa_cfg, error->sense_data, sizeof(error->sense_data));
+ ipr_err("SCSI Command Descriptor Block: \n");
+ ipr_log_hex_data(ioa_cfg, error->cdb, sizeof(error->cdb));
+
+ ipr_err("Additional IOA Data:\n");
+ ipr_log_hex_data(ioa_cfg, error->ioa_data, be32_to_cpu(error->length_of_error));
+}
+
+/**
* ipr_get_error - Find the specfied IOASC in the ipr_error_table.
* @ioasc: IOASC
*
@@ -2467,6 +2504,9 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,
case IPR_HOST_RCB_OVERLAY_ID_20:
ipr_log_fabric_error(ioa_cfg, hostrcb);
break;
+ case IPR_HOST_RCB_OVERLAY_ID_21:
+ ipr_log_sis64_device_error(ioa_cfg, hostrcb);
+ break;
case IPR_HOST_RCB_OVERLAY_ID_23:
ipr_log_sis64_config_error(ioa_cfg, hostrcb);
break;
@@ -3630,16 +3670,14 @@ static ssize_t ipr_store_iopoll_weight(struct device *dev,
return strlen(buf);
}
- if (blk_iopoll_enabled && ioa_cfg->iopoll_weight &&
- ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
+ if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
for (i = 1; i < ioa_cfg->hrrq_num; i++)
blk_iopoll_disable(&ioa_cfg->hrrq[i].iopoll);
}
spin_lock_irqsave(shost->host_lock, lock_flags);
ioa_cfg->iopoll_weight = user_iopoll_weight;
- if (blk_iopoll_enabled && ioa_cfg->iopoll_weight &&
- ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
+ if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
for (i = 1; i < ioa_cfg->hrrq_num; i++) {
blk_iopoll_init(&ioa_cfg->hrrq[i].iopoll,
ioa_cfg->iopoll_weight, ipr_iopoll);
@@ -5015,6 +5053,7 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd)
} else
rc = ipr_device_reset(ioa_cfg, res);
res->resetting_device = 0;
+ res->reset_occurred = 1;
LEAVE;
return rc ? FAILED : SUCCESS;
@@ -5484,8 +5523,7 @@ static irqreturn_t ipr_isr_mhrrq(int irq, void *devp)
return IRQ_NONE;
}
- if (blk_iopoll_enabled && ioa_cfg->iopoll_weight &&
- ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
+ if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
if ((be32_to_cpu(*hrrq->hrrq_curr) & IPR_HRRQ_TOGGLE_BIT) ==
hrrq->toggle_bit) {
if (!blk_iopoll_sched_prep(&hrrq->iopoll))
@@ -6183,8 +6221,10 @@ static int ipr_queuecommand(struct Scsi_Host *shost,
ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK;
ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC;
- if (ipr_is_gscsi(res))
+ if (ipr_is_gscsi(res) && res->reset_occurred) {
+ res->reset_occurred = 0;
ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_DELAY_AFTER_RST;
+ }
ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_ALIGNED_BFR;
ioarcb->cmd_pkt.flags_lo |= ipr_get_task_attributes(scsi_cmd);
}
@@ -8641,6 +8681,25 @@ static int ipr_reset_freeze(struct ipr_cmnd *ipr_cmd)
}
/**
+ * ipr_pci_mmio_enabled - Called when MMIO has been re-enabled
+ * @pdev: PCI device struct
+ *
+ * Description: This routine is called to tell us that the MMIO
+ * access to the IOA has been restored
+ */
+static pci_ers_result_t ipr_pci_mmio_enabled(struct pci_dev *pdev)
+{
+ unsigned long flags = 0;
+ struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
+
+ spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+ if (!ioa_cfg->probe_done)
+ pci_save_state(pdev);
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
* ipr_pci_frozen - Called when slot has experienced a PCI bus error.
* @pdev: PCI device struct
*
@@ -8654,7 +8713,8 @@ static void ipr_pci_frozen(struct pci_dev *pdev)
struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
- _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_freeze, IPR_SHUTDOWN_NONE);
+ if (ioa_cfg->probe_done)
+ _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_freeze, IPR_SHUTDOWN_NONE);
spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
}
@@ -8672,11 +8732,14 @@ static pci_ers_result_t ipr_pci_slot_reset(struct pci_dev *pdev)
struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
- if (ioa_cfg->needs_warm_reset)
- ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
- else
- _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space,
- IPR_SHUTDOWN_NONE);
+ if (ioa_cfg->probe_done) {
+ if (ioa_cfg->needs_warm_reset)
+ ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+ else
+ _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space,
+ IPR_SHUTDOWN_NONE);
+ } else
+ wake_up_all(&ioa_cfg->eeh_wait_q);
spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
return PCI_ERS_RESULT_RECOVERED;
}
@@ -8695,17 +8758,20 @@ static void ipr_pci_perm_failure(struct pci_dev *pdev)
int i;
spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
- if (ioa_cfg->sdt_state == WAIT_FOR_DUMP)
- ioa_cfg->sdt_state = ABORT_DUMP;
- ioa_cfg->reset_retries = IPR_NUM_RESET_RELOAD_RETRIES - 1;
- ioa_cfg->in_ioa_bringdown = 1;
- for (i = 0; i < ioa_cfg->hrrq_num; i++) {
- spin_lock(&ioa_cfg->hrrq[i]._lock);
- ioa_cfg->hrrq[i].allow_cmds = 0;
- spin_unlock(&ioa_cfg->hrrq[i]._lock);
- }
- wmb();
- ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+ if (ioa_cfg->probe_done) {
+ if (ioa_cfg->sdt_state == WAIT_FOR_DUMP)
+ ioa_cfg->sdt_state = ABORT_DUMP;
+ ioa_cfg->reset_retries = IPR_NUM_RESET_RELOAD_RETRIES - 1;
+ ioa_cfg->in_ioa_bringdown = 1;
+ for (i = 0; i < ioa_cfg->hrrq_num; i++) {
+ spin_lock(&ioa_cfg->hrrq[i]._lock);
+ ioa_cfg->hrrq[i].allow_cmds = 0;
+ spin_unlock(&ioa_cfg->hrrq[i]._lock);
+ }
+ wmb();
+ ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+ } else
+ wake_up_all(&ioa_cfg->eeh_wait_q);
spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
}
@@ -8725,7 +8791,7 @@ static pci_ers_result_t ipr_pci_error_detected(struct pci_dev *pdev,
switch (state) {
case pci_channel_io_frozen:
ipr_pci_frozen(pdev);
- return PCI_ERS_RESULT_NEED_RESET;
+ return PCI_ERS_RESULT_CAN_RECOVER;
case pci_channel_io_perm_failure:
ipr_pci_perm_failure(pdev);
return PCI_ERS_RESULT_DISCONNECT;
@@ -8755,6 +8821,7 @@ static int ipr_probe_ioa_part2(struct ipr_ioa_cfg *ioa_cfg)
ENTER;
spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
dev_dbg(&ioa_cfg->pdev->dev, "ioa_cfg adx: 0x%p\n", ioa_cfg);
+ ioa_cfg->probe_done = 1;
if (ioa_cfg->needs_hard_reset) {
ioa_cfg->needs_hard_reset = 0;
ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
@@ -9030,16 +9097,6 @@ static int ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg)
if (!ioa_cfg->vpd_cbs)
goto out_free_res_entries;
- for (i = 0; i < ioa_cfg->hrrq_num; i++) {
- INIT_LIST_HEAD(&ioa_cfg->hrrq[i].hrrq_free_q);
- INIT_LIST_HEAD(&ioa_cfg->hrrq[i].hrrq_pending_q);
- spin_lock_init(&ioa_cfg->hrrq[i]._lock);
- if (i == 0)
- ioa_cfg->hrrq[i].lock = ioa_cfg->host->host_lock;
- else
- ioa_cfg->hrrq[i].lock = &ioa_cfg->hrrq[i]._lock;
- }
-
if (ipr_alloc_cmd_blks(ioa_cfg))
goto out_free_vpd_cbs;
@@ -9140,6 +9197,48 @@ static void ipr_initialize_bus_attr(struct ipr_ioa_cfg *ioa_cfg)
}
/**
+ * ipr_init_regs - Initialize IOA registers
+ * @ioa_cfg: ioa config struct
+ *
+ * Return value:
+ * none
+ **/
+static void ipr_init_regs(struct ipr_ioa_cfg *ioa_cfg)
+{
+ const struct ipr_interrupt_offsets *p;
+ struct ipr_interrupts *t;
+ void __iomem *base;
+
+ p = &ioa_cfg->chip_cfg->regs;
+ t = &ioa_cfg->regs;
+ base = ioa_cfg->hdw_dma_regs;
+
+ t->set_interrupt_mask_reg = base + p->set_interrupt_mask_reg;
+ t->clr_interrupt_mask_reg = base + p->clr_interrupt_mask_reg;
+ t->clr_interrupt_mask_reg32 = base + p->clr_interrupt_mask_reg32;
+ t->sense_interrupt_mask_reg = base + p->sense_interrupt_mask_reg;
+ t->sense_interrupt_mask_reg32 = base + p->sense_interrupt_mask_reg32;
+ t->clr_interrupt_reg = base + p->clr_interrupt_reg;
+ t->clr_interrupt_reg32 = base + p->clr_interrupt_reg32;
+ t->sense_interrupt_reg = base + p->sense_interrupt_reg;
+ t->sense_interrupt_reg32 = base + p->sense_interrupt_reg32;
+ t->ioarrin_reg = base + p->ioarrin_reg;
+ t->sense_uproc_interrupt_reg = base + p->sense_uproc_interrupt_reg;
+ t->sense_uproc_interrupt_reg32 = base + p->sense_uproc_interrupt_reg32;
+ t->set_uproc_interrupt_reg = base + p->set_uproc_interrupt_reg;
+ t->set_uproc_interrupt_reg32 = base + p->set_uproc_interrupt_reg32;
+ t->clr_uproc_interrupt_reg = base + p->clr_uproc_interrupt_reg;
+ t->clr_uproc_interrupt_reg32 = base + p->clr_uproc_interrupt_reg32;
+
+ if (ioa_cfg->sis64) {
+ t->init_feedback_reg = base + p->init_feedback_reg;
+ t->dump_addr_reg = base + p->dump_addr_reg;
+ t->dump_data_reg = base + p->dump_data_reg;
+ t->endian_swap_reg = base + p->endian_swap_reg;
+ }
+}
+
+/**
* ipr_init_ioa_cfg - Initialize IOA config struct
* @ioa_cfg: ioa config struct
* @host: scsi host struct
@@ -9151,9 +9250,7 @@ static void ipr_initialize_bus_attr(struct ipr_ioa_cfg *ioa_cfg)
static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
struct Scsi_Host *host, struct pci_dev *pdev)
{
- const struct ipr_interrupt_offsets *p;
- struct ipr_interrupts *t;
- void __iomem *base;
+ int i;
ioa_cfg->host = host;
ioa_cfg->pdev = pdev;
@@ -9173,6 +9270,7 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread);
init_waitqueue_head(&ioa_cfg->reset_wait_q);
init_waitqueue_head(&ioa_cfg->msi_wait_q);
+ init_waitqueue_head(&ioa_cfg->eeh_wait_q);
ioa_cfg->sdt_state = INACTIVE;
ipr_initialize_bus_attr(ioa_cfg);
@@ -9183,44 +9281,33 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
host->max_lun = IPR_MAX_SIS64_LUNS_PER_TARGET;
if (ipr_max_devs > IPR_MAX_SIS64_DEVS)
ioa_cfg->max_devs_supported = IPR_MAX_SIS64_DEVS;
+ ioa_cfg->cfg_table_size = (sizeof(struct ipr_config_table_hdr64)
+ + ((sizeof(struct ipr_config_table_entry64)
+ * ioa_cfg->max_devs_supported)));
} else {
host->max_id = IPR_MAX_NUM_TARGETS_PER_BUS;
host->max_lun = IPR_MAX_NUM_LUNS_PER_TARGET;
if (ipr_max_devs > IPR_MAX_PHYSICAL_DEVS)
ioa_cfg->max_devs_supported = IPR_MAX_PHYSICAL_DEVS;
+ ioa_cfg->cfg_table_size = (sizeof(struct ipr_config_table_hdr)
+ + ((sizeof(struct ipr_config_table_entry)
+ * ioa_cfg->max_devs_supported)));
}
+
host->max_channel = IPR_MAX_BUS_TO_SCAN;
host->unique_id = host->host_no;
host->max_cmd_len = IPR_MAX_CDB_LEN;
host->can_queue = ioa_cfg->max_cmds;
pci_set_drvdata(pdev, ioa_cfg);
- p = &ioa_cfg->chip_cfg->regs;
- t = &ioa_cfg->regs;
- base = ioa_cfg->hdw_dma_regs;
-
- t->set_interrupt_mask_reg = base + p->set_interrupt_mask_reg;
- t->clr_interrupt_mask_reg = base + p->clr_interrupt_mask_reg;
- t->clr_interrupt_mask_reg32 = base + p->clr_interrupt_mask_reg32;
- t->sense_interrupt_mask_reg = base + p->sense_interrupt_mask_reg;
- t->sense_interrupt_mask_reg32 = base + p->sense_interrupt_mask_reg32;
- t->clr_interrupt_reg = base + p->clr_interrupt_reg;
- t->clr_interrupt_reg32 = base + p->clr_interrupt_reg32;
- t->sense_interrupt_reg = base + p->sense_interrupt_reg;
- t->sense_interrupt_reg32 = base + p->sense_interrupt_reg32;
- t->ioarrin_reg = base + p->ioarrin_reg;
- t->sense_uproc_interrupt_reg = base + p->sense_uproc_interrupt_reg;
- t->sense_uproc_interrupt_reg32 = base + p->sense_uproc_interrupt_reg32;
- t->set_uproc_interrupt_reg = base + p->set_uproc_interrupt_reg;
- t->set_uproc_interrupt_reg32 = base + p->set_uproc_interrupt_reg32;
- t->clr_uproc_interrupt_reg = base + p->clr_uproc_interrupt_reg;
- t->clr_uproc_interrupt_reg32 = base + p->clr_uproc_interrupt_reg32;
-
- if (ioa_cfg->sis64) {
- t->init_feedback_reg = base + p->init_feedback_reg;
- t->dump_addr_reg = base + p->dump_addr_reg;
- t->dump_data_reg = base + p->dump_data_reg;
- t->endian_swap_reg = base + p->endian_swap_reg;
+ for (i = 0; i < ARRAY_SIZE(ioa_cfg->hrrq); i++) {
+ INIT_LIST_HEAD(&ioa_cfg->hrrq[i].hrrq_free_q);
+ INIT_LIST_HEAD(&ioa_cfg->hrrq[i].hrrq_pending_q);
+ spin_lock_init(&ioa_cfg->hrrq[i]._lock);
+ if (i == 0)
+ ioa_cfg->hrrq[i].lock = ioa_cfg->host->host_lock;
+ else
+ ioa_cfg->hrrq[i].lock = &ioa_cfg->hrrq[i]._lock;
}
}
@@ -9243,54 +9330,63 @@ ipr_get_chip_info(const struct pci_device_id *dev_id)
return NULL;
}
+/**
+ * ipr_wait_for_pci_err_recovery - Wait for any PCI error recovery to complete
+ * during probe time
+ * @ioa_cfg: ioa config struct
+ *
+ * Return value:
+ * None
+ **/
+static void ipr_wait_for_pci_err_recovery(struct ipr_ioa_cfg *ioa_cfg)
+{
+ struct pci_dev *pdev = ioa_cfg->pdev;
+
+ if (pci_channel_offline(pdev)) {
+ wait_event_timeout(ioa_cfg->eeh_wait_q,
+ !pci_channel_offline(pdev),
+ IPR_PCI_ERROR_RECOVERY_TIMEOUT);
+ pci_restore_state(pdev);
+ }
+}
+
static int ipr_enable_msix(struct ipr_ioa_cfg *ioa_cfg)
{
struct msix_entry entries[IPR_MAX_MSIX_VECTORS];
- int i, err, vectors;
+ int i, vectors;
for (i = 0; i < ARRAY_SIZE(entries); ++i)
entries[i].entry = i;
- vectors = ipr_number_of_msix;
-
- while ((err = pci_enable_msix(ioa_cfg->pdev, entries, vectors)) > 0)
- vectors = err;
-
- if (err < 0) {
- pci_disable_msix(ioa_cfg->pdev);
- return err;
+ vectors = pci_enable_msix_range(ioa_cfg->pdev,
+ entries, 1, ipr_number_of_msix);
+ if (vectors < 0) {
+ ipr_wait_for_pci_err_recovery(ioa_cfg);
+ return vectors;
}
- if (!err) {
- for (i = 0; i < vectors; i++)
- ioa_cfg->vectors_info[i].vec = entries[i].vector;
- ioa_cfg->nvectors = vectors;
- }
+ for (i = 0; i < vectors; i++)
+ ioa_cfg->vectors_info[i].vec = entries[i].vector;
+ ioa_cfg->nvectors = vectors;
- return err;
+ return 0;
}
static int ipr_enable_msi(struct ipr_ioa_cfg *ioa_cfg)
{
- int i, err, vectors;
-
- vectors = ipr_number_of_msix;
+ int i, vectors;
- while ((err = pci_enable_msi_block(ioa_cfg->pdev, vectors)) > 0)
- vectors = err;
-
- if (err < 0) {
- pci_disable_msi(ioa_cfg->pdev);
- return err;
+ vectors = pci_enable_msi_range(ioa_cfg->pdev, 1, ipr_number_of_msix);
+ if (vectors < 0) {
+ ipr_wait_for_pci_err_recovery(ioa_cfg);
+ return vectors;
}
- if (!err) {
- for (i = 0; i < vectors; i++)
- ioa_cfg->vectors_info[i].vec = ioa_cfg->pdev->irq + i;
- ioa_cfg->nvectors = vectors;
- }
+ for (i = 0; i < vectors; i++)
+ ioa_cfg->vectors_info[i].vec = ioa_cfg->pdev->irq + i;
+ ioa_cfg->nvectors = vectors;
- return err;
+ return 0;
}
static void name_msi_vectors(struct ipr_ioa_cfg *ioa_cfg)
@@ -9355,7 +9451,7 @@ static irqreturn_t ipr_test_intr(int irq, void *devp)
* ipr_test_msi - Test for Message Signaled Interrupt (MSI) support.
* @pdev: PCI device struct
*
- * Description: The return value from pci_enable_msi() can not always be
+ * Description: The return value from pci_enable_msi_range() can not always be
* trusted. This routine sets up and initiates a test interrupt to determine
* if the interrupt is received via the ipr_test_intr() service routine.
* If the tests fails, the driver will fall back to LSI.
@@ -9434,19 +9530,13 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
ENTER;
- if ((rc = pci_enable_device(pdev))) {
- dev_err(&pdev->dev, "Cannot enable adapter\n");
- goto out;
- }
-
dev_info(&pdev->dev, "Found IOA with IRQ: %d\n", pdev->irq);
-
host = scsi_host_alloc(&driver_template, sizeof(*ioa_cfg));
if (!host) {
dev_err(&pdev->dev, "call to scsi_host_alloc failed!\n");
rc = -ENOMEM;
- goto out_disable;
+ goto out;
}
ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata;
@@ -9476,6 +9566,8 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
ioa_cfg->revid = pdev->revision;
+ ipr_init_ioa_cfg(ioa_cfg, host, pdev);
+
ipr_regs_pci = pci_resource_start(pdev, 0);
rc = pci_request_regions(pdev, IPR_NAME);
@@ -9485,22 +9577,35 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
goto out_scsi_host_put;
}
+ rc = pci_enable_device(pdev);
+
+ if (rc || pci_channel_offline(pdev)) {
+ if (pci_channel_offline(pdev)) {
+ ipr_wait_for_pci_err_recovery(ioa_cfg);
+ rc = pci_enable_device(pdev);
+ }
+
+ if (rc) {
+ dev_err(&pdev->dev, "Cannot enable adapter\n");
+ ipr_wait_for_pci_err_recovery(ioa_cfg);
+ goto out_release_regions;
+ }
+ }
+
ipr_regs = pci_ioremap_bar(pdev, 0);
if (!ipr_regs) {
dev_err(&pdev->dev,
"Couldn't map memory range of registers\n");
rc = -ENOMEM;
- goto out_release_regions;
+ goto out_disable;
}
ioa_cfg->hdw_dma_regs = ipr_regs;
ioa_cfg->hdw_dma_regs_pci = ipr_regs_pci;
ioa_cfg->ioa_mailbox = ioa_cfg->chip_cfg->mailbox + ipr_regs;
- ipr_init_ioa_cfg(ioa_cfg, host, pdev);
-
- pci_set_master(pdev);
+ ipr_init_regs(ioa_cfg);
if (ioa_cfg->sis64) {
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
@@ -9508,7 +9613,6 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
dev_dbg(&pdev->dev, "Failed to set 64 bit PCI DMA mask\n");
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
}
-
} else
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
@@ -9522,10 +9626,15 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
if (rc != PCIBIOS_SUCCESSFUL) {
dev_err(&pdev->dev, "Write of cache line size failed\n");
+ ipr_wait_for_pci_err_recovery(ioa_cfg);
rc = -EIO;
goto cleanup_nomem;
}
+ /* Issue MMIO read to ensure card is not in EEH */
+ interrupts = readl(ioa_cfg->regs.sense_interrupt_reg);
+ ipr_wait_for_pci_err_recovery(ioa_cfg);
+
if (ipr_number_of_msix > IPR_MAX_MSIX_VECTORS) {
dev_err(&pdev->dev, "The max number of MSIX is %d\n",
IPR_MAX_MSIX_VECTORS);
@@ -9544,10 +9653,22 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
dev_info(&pdev->dev, "Cannot enable MSI.\n");
}
+ pci_set_master(pdev);
+
+ if (pci_channel_offline(pdev)) {
+ ipr_wait_for_pci_err_recovery(ioa_cfg);
+ pci_set_master(pdev);
+ if (pci_channel_offline(pdev)) {
+ rc = -EIO;
+ goto out_msi_disable;
+ }
+ }
+
if (ioa_cfg->intr_flag == IPR_USE_MSI ||
ioa_cfg->intr_flag == IPR_USE_MSIX) {
rc = ipr_test_msi(ioa_cfg, pdev);
if (rc == -EOPNOTSUPP) {
+ ipr_wait_for_pci_err_recovery(ioa_cfg);
if (ioa_cfg->intr_flag == IPR_USE_MSI) {
ioa_cfg->intr_flag &= ~IPR_USE_MSI;
pci_disable_msi(pdev);
@@ -9577,30 +9698,12 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
(unsigned int)num_online_cpus(),
(unsigned int)IPR_MAX_HRRQ_NUM);
- /* Save away PCI config space for use following IOA reset */
- rc = pci_save_state(pdev);
-
- if (rc != PCIBIOS_SUCCESSFUL) {
- dev_err(&pdev->dev, "Failed to save PCI config space\n");
- rc = -EIO;
- goto out_msi_disable;
- }
-
if ((rc = ipr_save_pcix_cmd_reg(ioa_cfg)))
goto out_msi_disable;
if ((rc = ipr_set_pcix_cmd_reg(ioa_cfg)))
goto out_msi_disable;
- if (ioa_cfg->sis64)
- ioa_cfg->cfg_table_size = (sizeof(struct ipr_config_table_hdr64)
- + ((sizeof(struct ipr_config_table_entry64)
- * ioa_cfg->max_devs_supported)));
- else
- ioa_cfg->cfg_table_size = (sizeof(struct ipr_config_table_hdr)
- + ((sizeof(struct ipr_config_table_entry)
- * ioa_cfg->max_devs_supported)));
-
rc = ipr_alloc_mem(ioa_cfg);
if (rc < 0) {
dev_err(&pdev->dev,
@@ -9608,6 +9711,15 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
goto out_msi_disable;
}
+ /* Save away PCI config space for use following IOA reset */
+ rc = pci_save_state(pdev);
+
+ if (rc != PCIBIOS_SUCCESSFUL) {
+ dev_err(&pdev->dev, "Failed to save PCI config space\n");
+ rc = -EIO;
+ goto cleanup_nolog;
+ }
+
/*
* If HRRQ updated interrupt is not masked, or reset alert is set,
* the card is in an unknown state and needs a hard reset
@@ -9664,18 +9776,19 @@ out:
cleanup_nolog:
ipr_free_mem(ioa_cfg);
out_msi_disable:
+ ipr_wait_for_pci_err_recovery(ioa_cfg);
if (ioa_cfg->intr_flag == IPR_USE_MSI)
pci_disable_msi(pdev);
else if (ioa_cfg->intr_flag == IPR_USE_MSIX)
pci_disable_msix(pdev);
cleanup_nomem:
iounmap(ipr_regs);
+out_disable:
+ pci_disable_device(pdev);
out_release_regions:
pci_release_regions(pdev);
out_scsi_host_put:
scsi_host_put(host);
-out_disable:
- pci_disable_device(pdev);
goto out;
}
@@ -9859,8 +9972,7 @@ static int ipr_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
ioa_cfg->host->max_channel = IPR_VSET_BUS;
ioa_cfg->iopoll_weight = ioa_cfg->chip_cfg->iopoll_weight;
- if (blk_iopoll_enabled && ioa_cfg->iopoll_weight &&
- ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
+ if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
for (i = 1; i < ioa_cfg->hrrq_num; i++) {
blk_iopoll_init(&ioa_cfg->hrrq[i].iopoll,
ioa_cfg->iopoll_weight, ipr_iopoll);
@@ -9889,8 +10001,7 @@ static void ipr_shutdown(struct pci_dev *pdev)
int i;
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
- if (blk_iopoll_enabled && ioa_cfg->iopoll_weight &&
- ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
+ if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
ioa_cfg->iopoll_weight = 0;
for (i = 1; i < ioa_cfg->hrrq_num; i++)
blk_iopoll_disable(&ioa_cfg->hrrq[i].iopoll);
@@ -9994,6 +10105,8 @@ static struct pci_device_id ipr_pci_table[] = {
{ 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_57DA, 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 },
@@ -10005,12 +10118,19 @@ static struct pci_device_id ipr_pci_table[] = {
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 },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2CCA, 0, 0, 0 },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2CD2, 0, 0, 0 },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2CCD, 0, 0, 0 },
{ }
};
MODULE_DEVICE_TABLE(pci, ipr_pci_table);
static const struct pci_error_handlers ipr_err_handler = {
.error_detected = ipr_pci_error_detected,
+ .mmio_enabled = ipr_pci_mmio_enabled,
.slot_reset = ipr_pci_slot_reset,
};
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index 9ce38a22647e..31ed126f7143 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -101,12 +101,16 @@
#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_57DA 0x04CA
#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_SUBS_DEV_ID_2CCA 0x04C7
+#define IPR_SUBS_DEV_ID_2CD2 0x04C8
+#define IPR_SUBS_DEV_ID_2CCD 0x04C9
#define IPR_NAME "ipr"
/*
@@ -230,6 +234,7 @@
#define IPR_WAIT_FOR_RESET_TIMEOUT (2 * HZ)
#define IPR_CHECK_FOR_RESET_TIMEOUT (HZ / 10)
#define IPR_WAIT_FOR_BIST_TIMEOUT (2 * HZ)
+#define IPR_PCI_ERROR_RECOVERY_TIMEOUT (120 * HZ)
#define IPR_PCI_RESET_TIMEOUT (HZ / 2)
#define IPR_SIS32_DUMP_TIMEOUT (15 * HZ)
#define IPR_SIS64_DUMP_TIMEOUT (40 * HZ)
@@ -897,6 +902,18 @@ struct ipr_hostrcb_type_01_error {
__be32 ioa_data[236];
}__attribute__((packed, aligned (4)));
+struct ipr_hostrcb_type_21_error {
+ __be32 wwn[4];
+ u8 res_path[8];
+ u8 primary_problem_desc[32];
+ u8 second_problem_desc[32];
+ __be32 sense_data[8];
+ __be32 cdb[4];
+ __be32 residual_trans_length;
+ __be32 length_of_error;
+ __be32 ioa_data[236];
+}__attribute__((packed, aligned (4)));
+
struct ipr_hostrcb_type_02_error {
struct ipr_vpd ioa_vpd;
struct ipr_vpd cfc_vpd;
@@ -1126,6 +1143,7 @@ struct ipr_hostrcb64_error {
struct ipr_hostrcb_type_ff_error type_ff_error;
struct ipr_hostrcb_type_12_error type_12_error;
struct ipr_hostrcb_type_17_error type_17_error;
+ struct ipr_hostrcb_type_21_error type_21_error;
struct ipr_hostrcb_type_23_error type_23_error;
struct ipr_hostrcb_type_24_error type_24_error;
struct ipr_hostrcb_type_30_error type_30_error;
@@ -1169,6 +1187,7 @@ struct ipr_hcam {
#define IPR_HOST_RCB_OVERLAY_ID_16 0x16
#define IPR_HOST_RCB_OVERLAY_ID_17 0x17
#define IPR_HOST_RCB_OVERLAY_ID_20 0x20
+#define IPR_HOST_RCB_OVERLAY_ID_21 0x21
#define IPR_HOST_RCB_OVERLAY_ID_23 0x23
#define IPR_HOST_RCB_OVERLAY_ID_24 0x24
#define IPR_HOST_RCB_OVERLAY_ID_26 0x26
@@ -1252,6 +1271,7 @@ struct ipr_resource_entry {
u8 add_to_ml:1;
u8 del_from_ml:1;
u8 resetting_device:1;
+ u8 reset_occurred:1;
u32 bus; /* AKA channel */
u32 target; /* AKA id */
@@ -1441,6 +1461,7 @@ struct ipr_ioa_cfg {
u8 dump_timeout:1;
u8 cfg_locked:1;
u8 clear_isr:1;
+ u8 probe_done:1;
u8 revid;
@@ -1519,6 +1540,7 @@ struct ipr_ioa_cfg {
wait_queue_head_t reset_wait_q;
wait_queue_head_t msi_wait_q;
+ wait_queue_head_t eeh_wait_q;
struct ipr_dump *dump;
enum ipr_sdt_state sdt_state;
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index 4911310a38f5..22a9bb1abae1 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -311,9 +311,8 @@ static inline struct Scsi_Host *to_shost(struct isci_host *ihost)
}
#define for_each_isci_host(id, ihost, pdev) \
- for (id = 0, ihost = to_pci_info(pdev)->hosts[id]; \
- id < ARRAY_SIZE(to_pci_info(pdev)->hosts) && ihost; \
- ihost = to_pci_info(pdev)->hosts[++id])
+ for (id = 0; id < SCI_MAX_CONTROLLERS && \
+ (ihost = to_pci_info(pdev)->hosts[id]); id++)
static inline void wait_for_start(struct isci_host *ihost)
{
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index d25d0d859f05..695b34e9154e 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -66,7 +66,7 @@
#include "probe_roms.h"
#define MAJ 1
-#define MIN 1
+#define MIN 2
#define BUILD 0
#define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \
__stringify(BUILD)
diff --git a/drivers/scsi/isci/port_config.c b/drivers/scsi/isci/port_config.c
index 85c77f6b802b..ac879745ef80 100644
--- a/drivers/scsi/isci/port_config.c
+++ b/drivers/scsi/isci/port_config.c
@@ -615,13 +615,6 @@ static void sci_apc_agent_link_up(struct isci_host *ihost,
SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION);
} else {
/* the phy is already the part of the port */
- u32 port_state = iport->sm.current_state_id;
-
- /* if the PORT'S state is resetting then the link up is from
- * port hard reset in this case, we need to tell the port
- * that link up is recieved
- */
- BUG_ON(port_state != SCI_PORT_RESETTING);
port_agent->phy_ready_mask |= 1 << phy_index;
sci_port_link_up(iport, iphy);
}
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 99d2930b18c8..56e38096f0c4 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -2723,13 +2723,9 @@ static void isci_process_stp_response(struct sas_task *task, struct dev_to_host_
memcpy(resp->ending_fis, fis, sizeof(*fis));
ts->buf_valid_size = sizeof(*resp);
- /* If the device fault bit is set in the status register, then
- * set the sense data and return.
- */
- if (fis->status & ATA_DF)
+ /* If an error is flagged let libata decode the fis */
+ if (ac_err_mask(fis->status))
ts->stat = SAS_PROTO_RESPONSE;
- else if (fis->status & ATA_ERR)
- ts->stat = SAM_STAT_CHECK_CONDITION;
else
ts->stat = SAM_STAT_GOOD;
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 0d30ca849e8f..5d6fda72d659 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -801,7 +801,7 @@ int isci_task_I_T_nexus_reset(struct domain_device *dev)
/* XXX: need to cleanup any ireqs targeting this
* domain_device
*/
- ret = TMF_RESP_FUNC_COMPLETE;
+ ret = -ENODEV;
goto out;
}
diff --git a/drivers/scsi/iscsi_boot_sysfs.c b/drivers/scsi/iscsi_boot_sysfs.c
index 14c1c8f6a95e..680bf6f0ce76 100644
--- a/drivers/scsi/iscsi_boot_sysfs.c
+++ b/drivers/scsi/iscsi_boot_sysfs.c
@@ -490,5 +490,6 @@ void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset)
iscsi_boot_remove_kobj(boot_kobj);
kset_unregister(boot_kset->kset);
+ kfree(boot_kset);
}
EXPORT_SYMBOL_GPL(iscsi_boot_destroy_kset);
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index add6d1566ec8..bfb6d07d87f0 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -593,9 +593,9 @@ static void iscsi_sw_tcp_release_conn(struct iscsi_conn *conn)
iscsi_sw_tcp_conn_restore_callbacks(conn);
sock_put(sock->sk);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
tcp_sw_conn->sock = NULL;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
sockfd_put(sock);
}
@@ -663,10 +663,10 @@ iscsi_sw_tcp_conn_bind(struct iscsi_cls_session *cls_session,
if (err)
goto free_socket;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
/* bind iSCSI connection and socket */
tcp_sw_conn->sock = sock;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
/* setup Socket parameters */
sk = sock->sk;
@@ -726,14 +726,14 @@ static int iscsi_sw_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn,
switch(param) {
case ISCSI_PARAM_CONN_PORT:
case ISCSI_PARAM_CONN_ADDRESS:
- spin_lock_bh(&conn->session->lock);
+ spin_lock_bh(&conn->session->frwd_lock);
if (!tcp_sw_conn || !tcp_sw_conn->sock) {
- spin_unlock_bh(&conn->session->lock);
+ spin_unlock_bh(&conn->session->frwd_lock);
return -ENOTCONN;
}
rc = kernel_getpeername(tcp_sw_conn->sock,
(struct sockaddr *)&addr, &len);
- spin_unlock_bh(&conn->session->lock);
+ spin_unlock_bh(&conn->session->frwd_lock);
if (rc)
return rc;
@@ -759,23 +759,26 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost,
switch (param) {
case ISCSI_HOST_PARAM_IPADDRESS:
- spin_lock_bh(&session->lock);
+ if (!session)
+ return -ENOTCONN;
+
+ spin_lock_bh(&session->frwd_lock);
conn = session->leadconn;
if (!conn) {
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
return -ENOTCONN;
}
tcp_conn = conn->dd_data;
tcp_sw_conn = tcp_conn->dd_data;
if (!tcp_sw_conn->sock) {
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
return -ENOTCONN;
}
rc = kernel_getsockname(tcp_sw_conn->sock,
(struct sockaddr *)&addr, &len);
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
if (rc)
return rc;
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 40462415291e..26dc005bb0f0 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -110,16 +110,8 @@ static void __iscsi_update_cmdsn(struct iscsi_session *session,
session->exp_cmdsn = exp_cmdsn;
if (max_cmdsn != session->max_cmdsn &&
- !iscsi_sna_lt(max_cmdsn, session->max_cmdsn)) {
+ !iscsi_sna_lt(max_cmdsn, session->max_cmdsn))
session->max_cmdsn = max_cmdsn;
- /*
- * if the window closed with IO queued, then kick the
- * xmit thread
- */
- if (!list_empty(&session->leadconn->cmdqueue) ||
- !list_empty(&session->leadconn->mgmtqueue))
- iscsi_conn_queue_work(session->leadconn);
- }
}
void iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
@@ -395,6 +387,10 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
if (rc)
return rc;
}
+
+ if (scsi_get_prot_op(sc) != SCSI_PROT_NORMAL)
+ task->protected = true;
+
if (sc->sc_data_direction == DMA_TO_DEVICE) {
unsigned out_len = scsi_out(sc)->length;
struct iscsi_r2t_info *r2t = &task->unsol_r2t;
@@ -481,7 +477,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
* iscsi_free_task - free a task
* @task: iscsi cmd task
*
- * Must be called with session lock.
+ * Must be called with session back_lock.
* This function returns the scsi command to scsi-ml or cleans
* up mgmt tasks then returns the task to the pool.
*/
@@ -535,9 +531,10 @@ void iscsi_put_task(struct iscsi_task *task)
{
struct iscsi_session *session = task->conn->session;
- spin_lock_bh(&session->lock);
+ /* regular RX path uses back_lock */
+ spin_lock_bh(&session->back_lock);
__iscsi_put_task(task);
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->back_lock);
}
EXPORT_SYMBOL_GPL(iscsi_put_task);
@@ -546,7 +543,7 @@ EXPORT_SYMBOL_GPL(iscsi_put_task);
* @task: iscsi cmd task
* @state: state to complete task with
*
- * Must be called with session lock.
+ * Must be called with session back_lock.
*/
static void iscsi_complete_task(struct iscsi_task *task, int state)
{
@@ -585,7 +582,7 @@ static void iscsi_complete_task(struct iscsi_task *task, int state)
* This is used when drivers do not need or cannot perform
* lower level pdu processing.
*
- * Called with session lock
+ * Called with session back_lock
*/
void iscsi_complete_scsi_task(struct iscsi_task *task,
uint32_t exp_cmdsn, uint32_t max_cmdsn)
@@ -602,7 +599,7 @@ EXPORT_SYMBOL_GPL(iscsi_complete_scsi_task);
/*
- * session lock must be held and if not called for a task that is
+ * session back_lock must be held and if not called for a task that is
* still pending or from the xmit thread, then xmit thread must
* be suspended.
*/
@@ -642,7 +639,10 @@ static void fail_scsi_task(struct iscsi_task *task, int err)
scsi_in(sc)->resid = scsi_in(sc)->length;
}
+ /* regular RX path uses back_lock */
+ spin_lock_bh(&conn->session->back_lock);
iscsi_complete_task(task, state);
+ spin_unlock_bh(&conn->session->back_lock);
}
static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
@@ -780,7 +780,10 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
return task;
free_task:
+ /* regular RX path uses back_lock */
+ spin_lock_bh(&session->back_lock);
__iscsi_put_task(task);
+ spin_unlock_bh(&session->back_lock);
return NULL;
}
@@ -791,10 +794,10 @@ int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
struct iscsi_session *session = conn->session;
int err = 0;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
err = -EPERM;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
return err;
}
EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
@@ -823,6 +826,33 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
sc->result = (DID_OK << 16) | rhdr->cmd_status;
+ if (task->protected) {
+ sector_t sector;
+ u8 ascq;
+
+ /**
+ * Transports that didn't implement check_protection
+ * callback but still published T10-PI support to scsi-mid
+ * deserve this BUG_ON.
+ **/
+ BUG_ON(!session->tt->check_protection);
+
+ ascq = session->tt->check_protection(task, &sector);
+ if (ascq) {
+ sc->result = DRIVER_SENSE << 24 |
+ SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense_buffer(1, sc->sense_buffer,
+ ILLEGAL_REQUEST, 0x10, ascq);
+ sc->sense_buffer[7] = 0xc; /* Additional sense length */
+ sc->sense_buffer[8] = 0; /* Information desc type */
+ sc->sense_buffer[9] = 0xa; /* Additional desc length */
+ sc->sense_buffer[10] = 0x80; /* Validity bit */
+
+ put_unaligned_be64(sector, &sc->sense_buffer[12]);
+ goto out;
+ }
+ }
+
if (rhdr->response != ISCSI_STATUS_CMD_COMPLETED) {
sc->result = DID_ERROR << 16;
goto out;
@@ -1013,13 +1043,13 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
iscsi_conn_printk(KERN_ERR, conn,
"pdu (op 0x%x itt 0x%x) rejected "
"due to DataDigest error.\n",
- rejected_pdu.itt, opcode);
+ opcode, rejected_pdu.itt);
break;
case ISCSI_REASON_IMM_CMD_REJECT:
iscsi_conn_printk(KERN_ERR, conn,
"pdu (op 0x%x itt 0x%x) rejected. Too many "
"immediate commands.\n",
- rejected_pdu.itt, opcode);
+ opcode, rejected_pdu.itt);
/*
* We only send one TMF at a time so if the target could not
* handle it, then it should get fixed (RFC mandates that
@@ -1031,14 +1061,19 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
if (opcode != ISCSI_OP_NOOP_OUT)
return 0;
- if (rejected_pdu.itt == cpu_to_be32(ISCSI_RESERVED_TAG))
+ if (rejected_pdu.itt == cpu_to_be32(ISCSI_RESERVED_TAG)) {
/*
* nop-out in response to target's nop-out rejected.
* Just resend.
*/
+ /* In RX path we are under back lock */
+ spin_unlock(&conn->session->back_lock);
+ spin_lock(&conn->session->frwd_lock);
iscsi_send_nopout(conn,
(struct iscsi_nopin*)&rejected_pdu);
- else {
+ spin_unlock(&conn->session->frwd_lock);
+ spin_lock(&conn->session->back_lock);
+ } else {
struct iscsi_task *task;
/*
* Our nop as ping got dropped. We know the target
@@ -1059,8 +1094,8 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
default:
iscsi_conn_printk(KERN_ERR, conn,
"pdu (op 0x%x itt 0x%x) rejected. Reason "
- "code 0x%x\n", rejected_pdu.itt,
- rejected_pdu.opcode, reject->reason);
+ "code 0x%x\n", rejected_pdu.opcode,
+ rejected_pdu.itt, reject->reason);
break;
}
return rc;
@@ -1074,7 +1109,7 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
* This should be used for mgmt tasks like login and nops, or if
* the LDD's itt space does not include the session age.
*
- * The session lock must be held.
+ * The session back_lock must be held.
*/
struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
{
@@ -1103,7 +1138,7 @@ EXPORT_SYMBOL_GPL(iscsi_itt_to_task);
* @datalen: len of data buffer
*
* Completes pdu processing by freeing any resources allocated at
- * queuecommand or send generic. session lock must be held and verify
+ * queuecommand or send generic. session back_lock must be held and verify
* itt must have been called.
*/
int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
@@ -1140,7 +1175,12 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG))
break;
+ /* In RX path we are under back lock */
+ spin_unlock(&session->back_lock);
+ spin_lock(&session->frwd_lock);
iscsi_send_nopout(conn, (struct iscsi_nopin*)hdr);
+ spin_unlock(&session->frwd_lock);
+ spin_lock(&session->back_lock);
break;
case ISCSI_OP_REJECT:
rc = iscsi_handle_reject(conn, hdr, data, datalen);
@@ -1247,9 +1287,9 @@ int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
{
int rc;
- spin_lock(&conn->session->lock);
+ spin_lock(&conn->session->back_lock);
rc = __iscsi_complete_pdu(conn, hdr, data, datalen);
- spin_unlock(&conn->session->lock);
+ spin_unlock(&conn->session->back_lock);
return rc;
}
EXPORT_SYMBOL_GPL(iscsi_complete_pdu);
@@ -1293,7 +1333,7 @@ EXPORT_SYMBOL_GPL(iscsi_verify_itt);
*
* This should be used for cmd tasks.
*
- * The session lock must be held.
+ * The session back_lock must be held.
*/
struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt)
{
@@ -1323,15 +1363,15 @@ void iscsi_session_failure(struct iscsi_session *session,
struct iscsi_conn *conn;
struct device *dev;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
conn = session->leadconn;
if (session->state == ISCSI_STATE_TERMINATE || !conn) {
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
return;
}
dev = get_device(&conn->cls_conn->dev);
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
if (!dev)
return;
/*
@@ -1351,15 +1391,15 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
{
struct iscsi_session *session = conn->session;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (session->state == ISCSI_STATE_FAILED) {
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
return;
}
if (conn->stop_stage == 0)
session->state = ISCSI_STATE_FAILED;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
@@ -1393,15 +1433,18 @@ static int iscsi_xmit_task(struct iscsi_conn *conn)
return -ENODATA;
__iscsi_get_task(task);
- spin_unlock_bh(&conn->session->lock);
+ spin_unlock_bh(&conn->session->frwd_lock);
rc = conn->session->tt->xmit_task(task);
- spin_lock_bh(&conn->session->lock);
+ spin_lock_bh(&conn->session->frwd_lock);
if (!rc) {
/* done with this task */
task->last_xfer = jiffies;
conn->task = NULL;
}
+ /* regular RX path uses back_lock */
+ spin_lock_bh(&conn->session->back_lock);
__iscsi_put_task(task);
+ spin_unlock_bh(&conn->session->back_lock);
return rc;
}
@@ -1410,7 +1453,7 @@ static int iscsi_xmit_task(struct iscsi_conn *conn)
* @task: task to requeue
*
* LLDs that need to run a task from the session workqueue should call
- * this. The session lock must be held. This should only be called
+ * this. The session frwd_lock must be held. This should only be called
* by software drivers.
*/
void iscsi_requeue_task(struct iscsi_task *task)
@@ -1441,10 +1484,10 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
struct iscsi_task *task;
int rc = 0;
- spin_lock_bh(&conn->session->lock);
+ spin_lock_bh(&conn->session->frwd_lock);
if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
ISCSI_DBG_SESSION(conn->session, "Tx suspended!\n");
- spin_unlock_bh(&conn->session->lock);
+ spin_unlock_bh(&conn->session->frwd_lock);
return -ENODATA;
}
@@ -1465,7 +1508,10 @@ check_mgmt:
struct iscsi_task, running);
list_del_init(&conn->task->running);
if (iscsi_prep_mgmt_task(conn, conn->task)) {
+ /* regular RX path uses back_lock */
+ spin_lock_bh(&conn->session->back_lock);
__iscsi_put_task(conn->task);
+ spin_unlock_bh(&conn->session->back_lock);
conn->task = NULL;
continue;
}
@@ -1527,11 +1573,11 @@ check_mgmt:
if (!list_empty(&conn->mgmtqueue))
goto check_mgmt;
}
- spin_unlock_bh(&conn->session->lock);
+ spin_unlock_bh(&conn->session->frwd_lock);
return -ENODATA;
done:
- spin_unlock_bh(&conn->session->lock);
+ spin_unlock_bh(&conn->session->frwd_lock);
return rc;
}
@@ -1567,6 +1613,7 @@ static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn,
task->have_checked_conn = false;
task->last_timeout = jiffies;
task->last_xfer = jiffies;
+ task->protected = false;
INIT_LIST_HEAD(&task->running);
return task;
}
@@ -1600,7 +1647,7 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
cls_session = starget_to_session(scsi_target(sc->device));
session = cls_session->dd_data;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
reason = iscsi_session_chkready(cls_session);
if (reason) {
@@ -1686,13 +1733,13 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
}
session->queued_cmdsn++;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
return 0;
prepd_reject:
iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ);
reject:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n",
sc->cmnd[0], reason);
return SCSI_MLQUEUE_TARGET_BUSY;
@@ -1700,7 +1747,7 @@ reject:
prepd_fault:
iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ);
fault:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n",
sc->cmnd[0], reason);
if (!scsi_bidi_cmnd(sc))
@@ -1748,14 +1795,14 @@ static void iscsi_tmf_timedout(unsigned long data)
struct iscsi_conn *conn = (struct iscsi_conn *)data;
struct iscsi_session *session = conn->session;
- spin_lock(&session->lock);
+ spin_lock(&session->frwd_lock);
if (conn->tmf_state == TMF_QUEUED) {
conn->tmf_state = TMF_TIMEDOUT;
ISCSI_DBG_EH(session, "tmf timedout\n");
/* unblock eh_abort() */
wake_up(&conn->ehwait);
}
- spin_unlock(&session->lock);
+ spin_unlock(&session->frwd_lock);
}
static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
@@ -1768,10 +1815,10 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
NULL, 0);
if (!task) {
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_conn_printk(KERN_ERR, conn, "Could not send TMF.\n");
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
return -EPERM;
}
conn->tmfcmd_pdus_cnt++;
@@ -1781,7 +1828,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
add_timer(&conn->tmf_timer);
ISCSI_DBG_EH(session, "tmf set timeout\n");
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
mutex_unlock(&session->eh_mutex);
/*
@@ -1800,7 +1847,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
del_timer_sync(&conn->tmf_timer);
mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
/* if the session drops it will clean up the task */
if (age != session->age ||
session->state != ISCSI_STATE_LOGGED_IN)
@@ -1837,7 +1884,7 @@ static void fail_scsi_tasks(struct iscsi_conn *conn, unsigned lun,
* iscsi_suspend_queue - suspend iscsi_queuecommand
* @conn: iscsi conn to stop queueing IO on
*
- * This grabs the session lock to make sure no one is in
+ * This grabs the session frwd_lock to make sure no one is in
* xmit_task/queuecommand, and then sets suspend to prevent
* new commands from being queued. This only needs to be called
* by offload drivers that need to sync a path like ep disconnect
@@ -1846,9 +1893,9 @@ static void fail_scsi_tasks(struct iscsi_conn *conn, unsigned lun,
*/
void iscsi_suspend_queue(struct iscsi_conn *conn)
{
- spin_lock_bh(&conn->session->lock);
+ spin_lock_bh(&conn->session->frwd_lock);
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
- spin_unlock_bh(&conn->session->lock);
+ spin_unlock_bh(&conn->session->frwd_lock);
}
EXPORT_SYMBOL_GPL(iscsi_suspend_queue);
@@ -1907,7 +1954,7 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
ISCSI_DBG_EH(session, "scsi cmd %p timedout\n", sc);
- spin_lock(&session->lock);
+ spin_lock(&session->frwd_lock);
task = (struct iscsi_task *)sc->SCp.ptr;
if (!task) {
/*
@@ -2021,7 +2068,7 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
done:
if (task)
task->last_timeout = jiffies;
- spin_unlock(&session->lock);
+ spin_unlock(&session->frwd_lock);
ISCSI_DBG_EH(session, "return %s\n", rc == BLK_EH_RESET_TIMER ?
"timer reset" : "nh");
return rc;
@@ -2033,7 +2080,7 @@ static void iscsi_check_transport_timeouts(unsigned long data)
struct iscsi_session *session = conn->session;
unsigned long recv_timeout, next_timeout = 0, last_recv;
- spin_lock(&session->lock);
+ spin_lock(&session->frwd_lock);
if (session->state != ISCSI_STATE_LOGGED_IN)
goto done;
@@ -2050,7 +2097,7 @@ static void iscsi_check_transport_timeouts(unsigned long data)
"last ping %lu, now %lu\n",
conn->ping_timeout, conn->recv_timeout,
last_recv, conn->last_ping, jiffies);
- spin_unlock(&session->lock);
+ spin_unlock(&session->frwd_lock);
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
return;
}
@@ -2066,7 +2113,7 @@ static void iscsi_check_transport_timeouts(unsigned long data)
ISCSI_DBG_CONN(conn, "Setting next tmo %lu\n", next_timeout);
mod_timer(&conn->transport_timer, next_timeout);
done:
- spin_unlock(&session->lock);
+ spin_unlock(&session->frwd_lock);
}
static void iscsi_prep_abort_task_pdu(struct iscsi_task *task,
@@ -2096,7 +2143,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
ISCSI_DBG_EH(session, "aborting sc %p\n", sc);
mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
/*
* if session was ISCSI_STATE_IN_RECOVERY then we may not have
* got the command.
@@ -2104,7 +2151,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
if (!sc->SCp.ptr) {
ISCSI_DBG_EH(session, "sc never reached iscsi layer or "
"it completed.\n");
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
mutex_unlock(&session->eh_mutex);
return SUCCESS;
}
@@ -2115,7 +2162,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
*/
if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN ||
sc->SCp.phase != session->age) {
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
mutex_unlock(&session->eh_mutex);
ISCSI_DBG_EH(session, "failing abort due to dropped "
"session.\n");
@@ -2156,7 +2203,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
switch (conn->tmf_state) {
case TMF_SUCCESS:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
/*
* stop tx side incase the target had sent a abort rsp but
* the initiator was still writing out data.
@@ -2167,15 +2214,15 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
* good and have never sent us a successful tmf response
* then sent more data for the cmd.
*/
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
fail_scsi_task(task, DID_ABORT);
conn->tmf_state = TMF_INITIAL;
memset(hdr, 0, sizeof(*hdr));
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_start_tx(conn);
goto success_unlocked;
case TMF_TIMEDOUT:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
goto failed_unlocked;
case TMF_NOT_FOUND:
@@ -2194,7 +2241,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
}
success:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
success_unlocked:
ISCSI_DBG_EH(session, "abort success [sc %p itt 0x%x]\n",
sc, task->itt);
@@ -2202,7 +2249,7 @@ success_unlocked:
return SUCCESS;
failed:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
failed_unlocked:
ISCSI_DBG_EH(session, "abort failed [sc %p itt 0x%x]\n", sc,
task ? task->itt : 0);
@@ -2235,7 +2282,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
ISCSI_DBG_EH(session, "LU Reset [sc %p lun %u]\n", sc, sc->device->lun);
mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
/*
* Just check if we are not logged in. We cannot check for
* the phase because the reset could come from a ioctl.
@@ -2262,7 +2309,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
case TMF_SUCCESS:
break;
case TMF_TIMEDOUT:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
goto done;
default:
@@ -2271,21 +2318,21 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
}
rc = SUCCESS;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_suspend_tx(conn);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
memset(hdr, 0, sizeof(*hdr));
fail_scsi_tasks(conn, sc->device->lun, DID_ERROR);
conn->tmf_state = TMF_INITIAL;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_start_tx(conn);
goto done;
unlock:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
done:
ISCSI_DBG_EH(session, "dev reset result = %s\n",
rc == SUCCESS ? "SUCCESS" : "FAILED");
@@ -2298,13 +2345,13 @@ void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
{
struct iscsi_session *session = cls_session->dd_data;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (session->state != ISCSI_STATE_LOGGED_IN) {
session->state = ISCSI_STATE_RECOVERY_FAILED;
if (session->leadconn)
wake_up(&session->leadconn->ehwait);
}
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
}
EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout);
@@ -2326,19 +2373,19 @@ int iscsi_eh_session_reset(struct scsi_cmnd *sc)
conn = session->leadconn;
mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (session->state == ISCSI_STATE_TERMINATE) {
failed:
ISCSI_DBG_EH(session,
"failing session reset: Could not log back into "
"%s, %s [age %d]\n", session->targetname,
conn->persistent_address, session->age);
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
mutex_unlock(&session->eh_mutex);
return FAILED;
}
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
mutex_unlock(&session->eh_mutex);
/*
* we drop the lock here but the leadconn cannot be destoyed while
@@ -2355,14 +2402,14 @@ failed:
flush_signals(current);
mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (session->state == ISCSI_STATE_LOGGED_IN) {
ISCSI_DBG_EH(session,
"session reset succeeded for %s,%s\n",
session->targetname, conn->persistent_address);
} else
goto failed;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
mutex_unlock(&session->eh_mutex);
return SUCCESS;
}
@@ -2398,7 +2445,7 @@ int iscsi_eh_target_reset(struct scsi_cmnd *sc)
session->targetname);
mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
/*
* Just check if we are not logged in. We cannot check for
* the phase because the reset could come from a ioctl.
@@ -2425,7 +2472,7 @@ int iscsi_eh_target_reset(struct scsi_cmnd *sc)
case TMF_SUCCESS:
break;
case TMF_TIMEDOUT:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
goto done;
default:
@@ -2434,21 +2481,21 @@ int iscsi_eh_target_reset(struct scsi_cmnd *sc)
}
rc = SUCCESS;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_suspend_tx(conn);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
memset(hdr, 0, sizeof(*hdr));
fail_scsi_tasks(conn, -1, DID_ERROR);
conn->tmf_state = TMF_INITIAL;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_start_tx(conn);
goto done;
unlock:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
done:
ISCSI_DBG_EH(session, "tgt %s reset result = %s\n", session->targetname,
rc == SUCCESS ? "SUCCESS" : "FAILED");
@@ -2746,8 +2793,10 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
session->max_r2t = 1;
session->tt = iscsit;
session->dd_data = cls_session->dd_data + sizeof(*session);
+
mutex_init(&session->eh_mutex);
- spin_lock_init(&session->lock);
+ spin_lock_init(&session->frwd_lock);
+ spin_lock_init(&session->back_lock);
/* initialize SCSI PDU commands pool */
if (iscsi_pool_init(&session->cmdpool, session->cmds_max,
@@ -2861,14 +2910,14 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
/* allocate login_task used for the login/text sequences */
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (!kfifo_out(&session->cmdpool.queue,
(void*)&conn->login_task,
sizeof(void*))) {
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
goto login_task_alloc_fail;
}
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
data = (char *) __get_free_pages(GFP_KERNEL,
get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
@@ -2905,7 +2954,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
del_timer_sync(&conn->transport_timer);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
if (session->leadconn == conn) {
/*
@@ -2914,7 +2963,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
session->state = ISCSI_STATE_TERMINATE;
wake_up(&conn->ehwait);
}
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
/*
* Block until all in-progress commands for this connection
@@ -2941,16 +2990,19 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
/* flush queued up work because we free the connection below */
iscsi_suspend_tx(conn);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
free_pages((unsigned long) conn->data,
get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
kfree(conn->persistent_address);
kfree(conn->local_ipaddr);
+ /* regular RX path uses back_lock */
+ spin_lock_bh(&session->back_lock);
kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
sizeof(void*));
+ spin_unlock_bh(&session->back_lock);
if (session->leadconn == conn)
session->leadconn = NULL;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_destroy_conn(cls_conn);
}
@@ -2987,7 +3039,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
conn->ping_timeout = 5;
}
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
conn->c_stage = ISCSI_CONN_STARTED;
session->state = ISCSI_STATE_LOGGED_IN;
session->queued_cmdsn = session->cmdsn;
@@ -3016,7 +3068,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
default:
break;
}
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_unblock_session(session->cls_session);
wake_up(&conn->ehwait);
@@ -3055,9 +3107,9 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
int old_stop_stage;
mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (conn->stop_stage == STOP_CONN_TERM) {
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
mutex_unlock(&session->eh_mutex);
return;
}
@@ -3074,14 +3126,14 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
old_stop_stage = conn->stop_stage;
conn->stop_stage = flag;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
del_timer_sync(&conn->transport_timer);
iscsi_suspend_tx(conn);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
conn->c_stage = ISCSI_CONN_STOPPED;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
/*
* for connection level recovery we should not calculate
@@ -3102,11 +3154,11 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
/*
* flush queues.
*/
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
fail_scsi_tasks(conn, -1, DID_TRANSPORT_DISRUPTED);
fail_mgmt_tasks(session, conn);
memset(&conn->tmhdr, 0, sizeof(conn->tmhdr));
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
mutex_unlock(&session->eh_mutex);
}
@@ -3133,10 +3185,10 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session,
struct iscsi_session *session = cls_session->dd_data;
struct iscsi_conn *conn = cls_conn->dd_data;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (is_leading)
session->leadconn = conn;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
/*
* Unblock xmitworker(), Login Phase will pass through.
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index 1d58d5336018..60cb6dc3c6f0 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -446,7 +446,7 @@ iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn)
* iscsi_tcp_cleanup_task - free tcp_task resources
* @task: iscsi task
*
- * must be called with session lock
+ * must be called with session back_lock
*/
void iscsi_tcp_cleanup_task(struct iscsi_task *task)
{
@@ -457,6 +457,7 @@ void iscsi_tcp_cleanup_task(struct iscsi_task *task)
if (!task->sc)
return;
+ spin_lock_bh(&tcp_task->queue2pool);
/* flush task's r2t queues */
while (kfifo_out(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
@@ -470,6 +471,7 @@ void iscsi_tcp_cleanup_task(struct iscsi_task *task)
sizeof(void*));
tcp_task->r2t = NULL;
}
+ spin_unlock_bh(&tcp_task->queue2pool);
}
EXPORT_SYMBOL_GPL(iscsi_tcp_cleanup_task);
@@ -529,6 +531,8 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
struct iscsi_r2t_rsp *rhdr = (struct iscsi_r2t_rsp *)tcp_conn->in.hdr;
struct iscsi_r2t_info *r2t;
int r2tsn = be32_to_cpu(rhdr->r2tsn);
+ u32 data_length;
+ u32 data_offset;
int rc;
if (tcp_conn->in.datalen) {
@@ -554,40 +558,41 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
return 0;
}
- rc = kfifo_out(&tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*));
- if (!rc) {
- iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. "
- "Target has sent more R2Ts than it "
- "negotiated for or driver has leaked.\n");
- return ISCSI_ERR_PROTO;
- }
-
- r2t->exp_statsn = rhdr->statsn;
- r2t->data_length = be32_to_cpu(rhdr->data_length);
- if (r2t->data_length == 0) {
+ data_length = be32_to_cpu(rhdr->data_length);
+ if (data_length == 0) {
iscsi_conn_printk(KERN_ERR, conn,
"invalid R2T with zero data len\n");
- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
return ISCSI_ERR_DATALEN;
}
- if (r2t->data_length > session->max_burst)
+ if (data_length > session->max_burst)
ISCSI_DBG_TCP(conn, "invalid R2T with data len %u and max "
"burst %u. Attempting to execute request.\n",
- r2t->data_length, session->max_burst);
+ data_length, session->max_burst);
- r2t->data_offset = be32_to_cpu(rhdr->data_offset);
- if (r2t->data_offset + r2t->data_length > scsi_out(task->sc)->length) {
+ data_offset = be32_to_cpu(rhdr->data_offset);
+ if (data_offset + data_length > scsi_out(task->sc)->length) {
iscsi_conn_printk(KERN_ERR, conn,
"invalid R2T with data len %u at offset %u "
- "and total length %d\n", r2t->data_length,
- r2t->data_offset, scsi_out(task->sc)->length);
- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
+ "and total length %d\n", data_length,
+ data_offset, scsi_out(task->sc)->length);
return ISCSI_ERR_DATALEN;
}
+ spin_lock(&tcp_task->pool2queue);
+ rc = kfifo_out(&tcp_task->r2tpool.queue, (void *)&r2t, sizeof(void *));
+ if (!rc) {
+ iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. "
+ "Target has sent more R2Ts than it "
+ "negotiated for or driver has leaked.\n");
+ spin_unlock(&tcp_task->pool2queue);
+ return ISCSI_ERR_PROTO;
+ }
+
+ r2t->exp_statsn = rhdr->statsn;
+ r2t->data_length = data_length;
+ r2t->data_offset = data_offset;
+
r2t->ttt = rhdr->ttt; /* no flip */
r2t->datasn = 0;
r2t->sent = 0;
@@ -595,6 +600,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
tcp_task->exp_datasn = r2tsn + 1;
kfifo_in(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
conn->r2t_pdus_cnt++;
+ spin_unlock(&tcp_task->pool2queue);
iscsi_requeue_task(task);
return 0;
@@ -667,14 +673,14 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
switch(opcode) {
case ISCSI_OP_SCSI_DATA_IN:
- spin_lock(&conn->session->lock);
+ spin_lock(&conn->session->back_lock);
task = iscsi_itt_to_ctask(conn, hdr->itt);
if (!task)
rc = ISCSI_ERR_BAD_ITT;
else
rc = iscsi_tcp_data_in(conn, task);
if (rc) {
- spin_unlock(&conn->session->lock);
+ spin_unlock(&conn->session->back_lock);
break;
}
@@ -707,11 +713,11 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
tcp_conn->in.datalen,
iscsi_tcp_process_data_in,
rx_hash);
- spin_unlock(&conn->session->lock);
+ spin_unlock(&conn->session->back_lock);
return rc;
}
rc = __iscsi_complete_pdu(conn, hdr, NULL, 0);
- spin_unlock(&conn->session->lock);
+ spin_unlock(&conn->session->back_lock);
break;
case ISCSI_OP_SCSI_CMD_RSP:
if (tcp_conn->in.datalen) {
@@ -721,18 +727,20 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
rc = iscsi_complete_pdu(conn, hdr, NULL, 0);
break;
case ISCSI_OP_R2T:
- spin_lock(&conn->session->lock);
+ spin_lock(&conn->session->back_lock);
task = iscsi_itt_to_ctask(conn, hdr->itt);
+ spin_unlock(&conn->session->back_lock);
if (!task)
rc = ISCSI_ERR_BAD_ITT;
else if (ahslen)
rc = ISCSI_ERR_AHSLEN;
else if (task->sc->sc_data_direction == DMA_TO_DEVICE) {
task->last_xfer = jiffies;
+ spin_lock(&conn->session->frwd_lock);
rc = iscsi_tcp_r2t_rsp(conn, task);
+ spin_unlock(&conn->session->frwd_lock);
} else
rc = ISCSI_ERR_PROTO;
- spin_unlock(&conn->session->lock);
break;
case ISCSI_OP_LOGIN_RSP:
case ISCSI_OP_TEXT_RSP:
@@ -980,14 +988,13 @@ EXPORT_SYMBOL_GPL(iscsi_tcp_task_init);
static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
{
- struct iscsi_session *session = task->conn->session;
struct iscsi_tcp_task *tcp_task = task->dd_data;
struct iscsi_r2t_info *r2t = NULL;
if (iscsi_task_has_unsol_data(task))
r2t = &task->unsol_r2t;
else {
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&tcp_task->queue2pool);
if (tcp_task->r2t) {
r2t = tcp_task->r2t;
/* Continue with this R2T? */
@@ -1009,7 +1016,7 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
else
r2t = tcp_task->r2t;
}
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&tcp_task->queue2pool);
}
return r2t;
@@ -1139,6 +1146,8 @@ int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session)
iscsi_pool_free(&tcp_task->r2tpool);
goto r2t_alloc_fail;
}
+ spin_lock_init(&tcp_task->pool2queue);
+ spin_lock_init(&tcp_task->queue2pool);
}
return 0;
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index d2895836f9fa..766098af4eb7 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -700,46 +700,26 @@ void sas_probe_sata(struct asd_sas_port *port)
}
-static bool sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func)
+static void sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func)
{
struct domain_device *dev, *n;
- bool retry = false;
list_for_each_entry_safe(dev, n, &port->dev_list, dev_list_node) {
- int rc;
-
if (!dev_is_sata(dev))
continue;
sas_ata_wait_eh(dev);
- rc = dev->sata_dev.pm_result;
- if (rc == -EAGAIN)
- retry = true;
- else if (rc) {
- /* since we don't have a
- * ->port_{suspend|resume} routine in our
- * ata_port ops, and no entanglements with
- * acpi, suspend should just be mechanical trip
- * through eh, catch cases where these
- * assumptions are invalidated
- */
- WARN_ONCE(1, "failed %s %s error: %d\n", func,
- dev_name(&dev->rphy->dev), rc);
- }
/* if libata failed to power manage the device, tear it down */
if (ata_dev_disabled(sas_to_ata_dev(dev)))
sas_fail_probe(dev, func, -ENODEV);
}
-
- return retry;
}
void sas_suspend_sata(struct asd_sas_port *port)
{
struct domain_device *dev;
- retry:
mutex_lock(&port->ha->disco_mutex);
list_for_each_entry(dev, &port->dev_list, dev_list_node) {
struct sata_device *sata;
@@ -751,20 +731,17 @@ void sas_suspend_sata(struct asd_sas_port *port)
if (sata->ap->pm_mesg.event == PM_EVENT_SUSPEND)
continue;
- sata->pm_result = -EIO;
- ata_sas_port_async_suspend(sata->ap, &sata->pm_result);
+ ata_sas_port_suspend(sata->ap);
}
mutex_unlock(&port->ha->disco_mutex);
- if (sas_ata_flush_pm_eh(port, __func__))
- goto retry;
+ sas_ata_flush_pm_eh(port, __func__);
}
void sas_resume_sata(struct asd_sas_port *port)
{
struct domain_device *dev;
- retry:
mutex_lock(&port->ha->disco_mutex);
list_for_each_entry(dev, &port->dev_list, dev_list_node) {
struct sata_device *sata;
@@ -776,13 +753,11 @@ void sas_resume_sata(struct asd_sas_port *port)
if (sata->ap->pm_mesg.event == PM_EVENT_ON)
continue;
- sata->pm_result = -EIO;
- ata_sas_port_async_resume(sata->ap, &sata->pm_result);
+ ata_sas_port_resume(sata->ap);
}
mutex_unlock(&port->ha->disco_mutex);
- if (sas_ata_flush_pm_eh(port, __func__))
- goto retry;
+ sas_ata_flush_pm_eh(port, __func__);
}
/**
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index da3aee17faa5..25d0f127424d 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -862,7 +862,7 @@ out:
enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
{
- scmd_printk(KERN_DEBUG, cmd, "command %p timed out\n", cmd);
+ scmd_dbg(cmd, "command %p timed out\n", cmd);
return BLK_EH_NOT_HANDLED;
}
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 4e1b75ca7451..94a3cafe7197 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -73,8 +73,6 @@ struct lpfc_sli2_slim;
*/
/* 1 Second */
#define QUEUE_RAMP_DOWN_INTERVAL (msecs_to_jiffies(1000 * 1))
-/* 5 minutes */
-#define QUEUE_RAMP_UP_INTERVAL (msecs_to_jiffies(1000 * 300))
/* Number of exchanges reserved for discovery to complete */
#define LPFC_DISC_IOCB_BUFF_COUNT 20
@@ -722,6 +720,20 @@ struct lpfc_hba {
uint32_t cfg_hba_queue_depth;
uint32_t cfg_enable_hba_reset;
uint32_t cfg_enable_hba_heartbeat;
+ uint32_t cfg_fof;
+ uint32_t cfg_EnableXLane;
+ uint8_t cfg_oas_tgt_wwpn[8];
+ uint8_t cfg_oas_vpt_wwpn[8];
+ uint32_t cfg_oas_lun_state;
+#define OAS_LUN_ENABLE 1
+#define OAS_LUN_DISABLE 0
+ uint32_t cfg_oas_lun_status;
+#define OAS_LUN_STATUS_EXISTS 0x01
+ uint32_t cfg_oas_flags;
+#define OAS_FIND_ANY_VPORT 0x01
+#define OAS_FIND_ANY_TARGET 0x02
+#define OAS_LUN_VALID 0x04
+ uint32_t cfg_XLanePriority;
uint32_t cfg_enable_bg;
uint32_t cfg_hostmem_hgp;
uint32_t cfg_log_verbose;
@@ -730,6 +742,7 @@ struct lpfc_hba {
uint32_t cfg_request_firmware_upgrade;
uint32_t cfg_iocb_cnt;
uint32_t cfg_suppress_link_up;
+ uint32_t cfg_rrq_xri_bitmap_sz;
#define LPFC_INITIALIZE_LINK 0 /* do normal init_link mbox */
#define LPFC_DELAY_INIT_LINK 1 /* layered driver hold off */
#define LPFC_DELAY_INIT_LINK_INDEFINITELY 2 /* wait, manual intervention */
@@ -835,6 +848,7 @@ struct lpfc_hba {
mempool_t *mbox_mem_pool;
mempool_t *nlp_mem_pool;
mempool_t *rrq_pool;
+ mempool_t *active_rrq_pool;
struct fc_host_statistics link_stats;
enum intr_type_t intr_type;
@@ -869,7 +883,6 @@ struct lpfc_hba {
atomic_t num_cmd_success;
unsigned long last_rsrc_error_time;
unsigned long last_ramp_down_time;
- unsigned long last_ramp_up_time;
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
struct dentry *hba_debugfs_root;
atomic_t debugfs_vport_count;
@@ -971,6 +984,9 @@ struct lpfc_hba {
atomic_t sdev_cnt;
uint8_t fips_spec_rev;
uint8_t fips_level;
+ spinlock_t devicelock; /* lock for luns list */
+ mempool_t *device_data_mem_pool;
+ struct list_head luns;
};
static inline struct Scsi_Host *
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 00656fc92b93..8d5b6ceec9c9 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -529,6 +529,27 @@ lpfc_sli4_protocol_show(struct device *dev, struct device_attribute *attr,
}
/**
+ * lpfc_oas_supported_show - Return whether or not Optimized Access Storage
+ * (OAS) is supported.
+ * @dev: class unused variable.
+ * @attr: device attribute, not used.
+ * @buf: on return contains the module description text.
+ *
+ * Returns: size of formatted string.
+ **/
+static ssize_t
+lpfc_oas_supported_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ phba->sli4_hba.pc_sli4_params.oas_supported);
+}
+
+/**
* lpfc_link_state_store - Transition the link_state on an HBA port
* @dev: class device that is converted into a Scsi_host.
* @attr: device attribute, not used.
@@ -2041,9 +2062,53 @@ static DEVICE_ATTR(lpfc_dss, S_IRUGO, lpfc_dss_show, NULL);
static DEVICE_ATTR(lpfc_sriov_hw_max_virtfn, S_IRUGO,
lpfc_sriov_hw_max_virtfn_show, NULL);
static DEVICE_ATTR(protocol, S_IRUGO, lpfc_sli4_protocol_show, NULL);
+static DEVICE_ATTR(lpfc_xlane_supported, S_IRUGO, lpfc_oas_supported_show,
+ NULL);
static char *lpfc_soft_wwn_key = "C99G71SL8032A";
+#define WWN_SZ 8
+/**
+ * lpfc_wwn_set - Convert string to the 8 byte WWN value.
+ * @buf: WWN string.
+ * @cnt: Length of string.
+ * @wwn: Array to receive converted wwn value.
+ *
+ * Returns:
+ * -EINVAL if the buffer does not contain a valid wwn
+ * 0 success
+ **/
+static size_t
+lpfc_wwn_set(const char *buf, size_t cnt, char wwn[])
+{
+ unsigned int i, j;
+
+ /* Count may include a LF at end of string */
+ if (buf[cnt-1] == '\n')
+ cnt--;
+ if ((cnt < 16) || (cnt > 18) || ((cnt == 17) && (*buf++ != 'x')) ||
+ ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x'))))
+ return -EINVAL;
+
+ memset(wwn, 0, WWN_SZ);
+
+ /* Validate and store the new name */
+ for (i = 0, j = 0; i < 16; i++) {
+ if ((*buf >= 'a') && (*buf <= 'f'))
+ j = ((j << 4) | ((*buf++ - 'a') + 10));
+ else if ((*buf >= 'A') && (*buf <= 'F'))
+ j = ((j << 4) | ((*buf++ - 'A') + 10));
+ else if ((*buf >= '0') && (*buf <= '9'))
+ j = ((j << 4) | (*buf++ - '0'));
+ else
+ return -EINVAL;
+ if (i % 2) {
+ wwn[i/2] = j & 0xff;
+ j = 0;
+ }
+ }
+ return 0;
+}
/**
* lpfc_soft_wwn_enable_store - Allows setting of the wwn if the key is valid
* @dev: class device that is converted into a Scsi_host.
@@ -2132,9 +2197,9 @@ lpfc_soft_wwpn_store(struct device *dev, struct device_attribute *attr,
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
struct completion online_compl;
- int stat1=0, stat2=0;
- unsigned int i, j, cnt=count;
- u8 wwpn[8];
+ int stat1 = 0, stat2 = 0;
+ unsigned int cnt = count;
+ u8 wwpn[WWN_SZ];
int rc;
if (!phba->cfg_enable_hba_reset)
@@ -2149,29 +2214,19 @@ lpfc_soft_wwpn_store(struct device *dev, struct device_attribute *attr,
if (buf[cnt-1] == '\n')
cnt--;
- if (!phba->soft_wwn_enable || (cnt < 16) || (cnt > 18) ||
- ((cnt == 17) && (*buf++ != 'x')) ||
- ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x'))))
+ if (!phba->soft_wwn_enable)
return -EINVAL;
+ /* lock setting wwpn, wwnn down */
phba->soft_wwn_enable = 0;
- memset(wwpn, 0, sizeof(wwpn));
-
- /* Validate and store the new name */
- for (i=0, j=0; i < 16; i++) {
- int value;
-
- value = hex_to_bin(*buf++);
- if (value >= 0)
- j = (j << 4) | value;
- else
- return -EINVAL;
- if (i % 2) {
- wwpn[i/2] = j & 0xff;
- j = 0;
- }
+ rc = lpfc_wwn_set(buf, cnt, wwpn);
+ if (!rc) {
+ /* not able to set wwpn, unlock it */
+ phba->soft_wwn_enable = 1;
+ return rc;
}
+
phba->cfg_soft_wwpn = wwn_to_u64(wwpn);
fc_host_port_name(shost) = phba->cfg_soft_wwpn;
if (phba->cfg_soft_wwnn)
@@ -2198,7 +2253,7 @@ lpfc_soft_wwpn_store(struct device *dev, struct device_attribute *attr,
"reinit adapter - %d\n", stat2);
return (stat1 || stat2) ? -EIO : count;
}
-static DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR,\
+static DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR,
lpfc_soft_wwpn_show, lpfc_soft_wwpn_store);
/**
@@ -2235,39 +2290,25 @@ lpfc_soft_wwnn_store(struct device *dev, struct device_attribute *attr,
{
struct Scsi_Host *shost = class_to_shost(dev);
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
- unsigned int i, j, cnt=count;
- u8 wwnn[8];
+ unsigned int cnt = count;
+ u8 wwnn[WWN_SZ];
+ int rc;
/* count may include a LF at end of string */
if (buf[cnt-1] == '\n')
cnt--;
- if (!phba->soft_wwn_enable || (cnt < 16) || (cnt > 18) ||
- ((cnt == 17) && (*buf++ != 'x')) ||
- ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x'))))
+ if (!phba->soft_wwn_enable)
return -EINVAL;
- /*
- * Allow wwnn to be set many times, as long as the enable is set.
- * However, once the wwpn is set, everything locks.
- */
-
- memset(wwnn, 0, sizeof(wwnn));
-
- /* Validate and store the new name */
- for (i=0, j=0; i < 16; i++) {
- int value;
-
- value = hex_to_bin(*buf++);
- if (value >= 0)
- j = (j << 4) | value;
- else
- return -EINVAL;
- if (i % 2) {
- wwnn[i/2] = j & 0xff;
- j = 0;
- }
+ rc = lpfc_wwn_set(buf, cnt, wwnn);
+ if (!rc) {
+ /* Allow wwnn to be set many times, as long as the enable
+ * is set. However, once the wwpn is set, everything locks.
+ */
+ return rc;
}
+
phba->cfg_soft_wwnn = wwn_to_u64(wwnn);
dev_printk(KERN_NOTICE, &phba->pcidev->dev,
@@ -2276,9 +2317,438 @@ lpfc_soft_wwnn_store(struct device *dev, struct device_attribute *attr,
return count;
}
-static DEVICE_ATTR(lpfc_soft_wwnn, S_IRUGO | S_IWUSR,\
+static DEVICE_ATTR(lpfc_soft_wwnn, S_IRUGO | S_IWUSR,
lpfc_soft_wwnn_show, lpfc_soft_wwnn_store);
+/**
+ * lpfc_oas_tgt_show - Return wwpn of target whose luns maybe enabled for
+ * Optimized Access Storage (OAS) operations.
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: buffer for passing information.
+ *
+ * Returns:
+ * value of count
+ **/
+static ssize_t
+lpfc_oas_tgt_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+ return snprintf(buf, PAGE_SIZE, "0x%llx\n",
+ wwn_to_u64(phba->cfg_oas_tgt_wwpn));
+}
+
+/**
+ * lpfc_oas_tgt_store - Store wwpn of target whose luns maybe enabled for
+ * Optimized Access Storage (OAS) operations.
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: buffer for passing information.
+ * @count: Size of the data buffer.
+ *
+ * Returns:
+ * -EINVAL count is invalid, invalid wwpn byte invalid
+ * -EPERM oas is not supported by hba
+ * value of count on success
+ **/
+static ssize_t
+lpfc_oas_tgt_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+ unsigned int cnt = count;
+ uint8_t wwpn[WWN_SZ];
+ int rc;
+
+ if (!phba->cfg_EnableXLane)
+ return -EPERM;
+
+ /* count may include a LF at end of string */
+ if (buf[cnt-1] == '\n')
+ cnt--;
+
+ rc = lpfc_wwn_set(buf, cnt, wwpn);
+ if (rc)
+ return rc;
+
+ memcpy(phba->cfg_oas_tgt_wwpn, wwpn, (8 * sizeof(uint8_t)));
+ memcpy(phba->sli4_hba.oas_next_tgt_wwpn, wwpn, (8 * sizeof(uint8_t)));
+ if (wwn_to_u64(wwpn) == 0)
+ phba->cfg_oas_flags |= OAS_FIND_ANY_TARGET;
+ else
+ phba->cfg_oas_flags &= ~OAS_FIND_ANY_TARGET;
+ phba->cfg_oas_flags &= ~OAS_LUN_VALID;
+ phba->sli4_hba.oas_next_lun = FIND_FIRST_OAS_LUN;
+ return count;
+}
+static DEVICE_ATTR(lpfc_xlane_tgt, S_IRUGO | S_IWUSR,
+ lpfc_oas_tgt_show, lpfc_oas_tgt_store);
+
+/**
+ * lpfc_oas_vpt_show - Return wwpn of vport whose targets maybe enabled
+ * for Optimized Access Storage (OAS) operations.
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: buffer for passing information.
+ *
+ * Returns:
+ * value of count on success
+ **/
+static ssize_t
+lpfc_oas_vpt_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+ return snprintf(buf, PAGE_SIZE, "0x%llx\n",
+ wwn_to_u64(phba->cfg_oas_vpt_wwpn));
+}
+
+/**
+ * lpfc_oas_vpt_store - Store wwpn of vport whose targets maybe enabled
+ * for Optimized Access Storage (OAS) operations.
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: buffer for passing information.
+ * @count: Size of the data buffer.
+ *
+ * Returns:
+ * -EINVAL count is invalid, invalid wwpn byte invalid
+ * -EPERM oas is not supported by hba
+ * value of count on success
+ **/
+static ssize_t
+lpfc_oas_vpt_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+ unsigned int cnt = count;
+ uint8_t wwpn[WWN_SZ];
+ int rc;
+
+ if (!phba->cfg_EnableXLane)
+ return -EPERM;
+
+ /* count may include a LF at end of string */
+ if (buf[cnt-1] == '\n')
+ cnt--;
+
+ rc = lpfc_wwn_set(buf, cnt, wwpn);
+ if (rc)
+ return rc;
+
+ memcpy(phba->cfg_oas_vpt_wwpn, wwpn, (8 * sizeof(uint8_t)));
+ memcpy(phba->sli4_hba.oas_next_vpt_wwpn, wwpn, (8 * sizeof(uint8_t)));
+ if (wwn_to_u64(wwpn) == 0)
+ phba->cfg_oas_flags |= OAS_FIND_ANY_VPORT;
+ else
+ phba->cfg_oas_flags &= ~OAS_FIND_ANY_VPORT;
+ phba->cfg_oas_flags &= ~OAS_LUN_VALID;
+ phba->sli4_hba.oas_next_lun = FIND_FIRST_OAS_LUN;
+ return count;
+}
+static DEVICE_ATTR(lpfc_xlane_vpt, S_IRUGO | S_IWUSR,
+ lpfc_oas_vpt_show, lpfc_oas_vpt_store);
+
+/**
+ * lpfc_oas_lun_state_show - Return the current state (enabled or disabled)
+ * of whether luns will be enabled or disabled
+ * for Optimized Access Storage (OAS) operations.
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: buffer for passing information.
+ *
+ * Returns:
+ * size of formatted string.
+ **/
+static ssize_t
+lpfc_oas_lun_state_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", phba->cfg_oas_lun_state);
+}
+
+/**
+ * lpfc_oas_lun_state_store - Store the state (enabled or disabled)
+ * of whether luns will be enabled or disabled
+ * for Optimized Access Storage (OAS) operations.
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: buffer for passing information.
+ * @count: Size of the data buffer.
+ *
+ * Returns:
+ * -EINVAL count is invalid, invalid wwpn byte invalid
+ * -EPERM oas is not supported by hba
+ * value of count on success
+ **/
+static ssize_t
+lpfc_oas_lun_state_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+ int val = 0;
+
+ if (!phba->cfg_EnableXLane)
+ return -EPERM;
+
+ if (!isdigit(buf[0]))
+ return -EINVAL;
+
+ if (sscanf(buf, "%i", &val) != 1)
+ return -EINVAL;
+
+ if ((val != 0) && (val != 1))
+ return -EINVAL;
+
+ phba->cfg_oas_lun_state = val;
+
+ return strlen(buf);
+}
+static DEVICE_ATTR(lpfc_xlane_lun_state, S_IRUGO | S_IWUSR,
+ lpfc_oas_lun_state_show, lpfc_oas_lun_state_store);
+
+/**
+ * lpfc_oas_lun_status_show - Return the status of the Optimized Access
+ * Storage (OAS) lun returned by the
+ * lpfc_oas_lun_show function.
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: buffer for passing information.
+ *
+ * Returns:
+ * size of formatted string.
+ **/
+static ssize_t
+lpfc_oas_lun_status_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+ if (!(phba->cfg_oas_flags & OAS_LUN_VALID))
+ return -EFAULT;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", phba->cfg_oas_lun_status);
+}
+static DEVICE_ATTR(lpfc_xlane_lun_status, S_IRUGO,
+ lpfc_oas_lun_status_show, NULL);
+
+
+/**
+ * lpfc_oas_lun_state_set - enable or disable a lun for Optimized Access Storage
+ * (OAS) operations.
+ * @phba: lpfc_hba pointer.
+ * @ndlp: pointer to fcp target node.
+ * @lun: the fc lun for setting oas state.
+ * @oas_state: the oas state to be set to the lun.
+ *
+ * Returns:
+ * SUCCESS : 0
+ * -EPERM OAS is not enabled or not supported by this port.
+ *
+ */
+static size_t
+lpfc_oas_lun_state_set(struct lpfc_hba *phba, uint8_t vpt_wwpn[],
+ uint8_t tgt_wwpn[], uint64_t lun, uint32_t oas_state)
+{
+
+ int rc = 0;
+
+ if (!phba->cfg_EnableXLane)
+ return -EPERM;
+
+ if (oas_state) {
+ if (!lpfc_enable_oas_lun(phba, (struct lpfc_name *)vpt_wwpn,
+ (struct lpfc_name *)tgt_wwpn, lun))
+ rc = -ENOMEM;
+ } else {
+ lpfc_disable_oas_lun(phba, (struct lpfc_name *)vpt_wwpn,
+ (struct lpfc_name *)tgt_wwpn, lun);
+ }
+ return rc;
+
+}
+
+/**
+ * lpfc_oas_lun_get_next - get the next lun that has been enabled for Optimized
+ * Access Storage (OAS) operations.
+ * @phba: lpfc_hba pointer.
+ * @vpt_wwpn: wwpn of the vport associated with the returned lun
+ * @tgt_wwpn: wwpn of the target associated with the returned lun
+ * @lun_status: status of the lun returned lun
+ *
+ * Returns the first or next lun enabled for OAS operations for the vport/target
+ * specified. If a lun is found, its vport wwpn, target wwpn and status is
+ * returned. If the lun is not found, NOT_OAS_ENABLED_LUN is returned.
+ *
+ * Return:
+ * lun that is OAS enabled for the vport/target
+ * NOT_OAS_ENABLED_LUN when no oas enabled lun found.
+ */
+static uint64_t
+lpfc_oas_lun_get_next(struct lpfc_hba *phba, uint8_t vpt_wwpn[],
+ uint8_t tgt_wwpn[], uint32_t *lun_status)
+{
+ uint64_t found_lun;
+
+ if (unlikely(!phba) || !vpt_wwpn || !tgt_wwpn)
+ return NOT_OAS_ENABLED_LUN;
+ if (lpfc_find_next_oas_lun(phba, (struct lpfc_name *)
+ phba->sli4_hba.oas_next_vpt_wwpn,
+ (struct lpfc_name *)
+ phba->sli4_hba.oas_next_tgt_wwpn,
+ &phba->sli4_hba.oas_next_lun,
+ (struct lpfc_name *)vpt_wwpn,
+ (struct lpfc_name *)tgt_wwpn,
+ &found_lun, lun_status))
+ return found_lun;
+ else
+ return NOT_OAS_ENABLED_LUN;
+}
+
+/**
+ * lpfc_oas_lun_state_change - enable/disable a lun for OAS operations
+ * @phba: lpfc_hba pointer.
+ * @vpt_wwpn: vport wwpn by reference.
+ * @tgt_wwpn: target wwpn by reference.
+ * @lun: the fc lun for setting oas state.
+ * @oas_state: the oas state to be set to the oas_lun.
+ *
+ * This routine enables (OAS_LUN_ENABLE) or disables (OAS_LUN_DISABLE)
+ * a lun for OAS operations.
+ *
+ * Return:
+ * SUCCESS: 0
+ * -ENOMEM: failed to enable an lun for OAS operations
+ * -EPERM: OAS is not enabled
+ */
+static ssize_t
+lpfc_oas_lun_state_change(struct lpfc_hba *phba, uint8_t vpt_wwpn[],
+ uint8_t tgt_wwpn[], uint64_t lun,
+ uint32_t oas_state)
+{
+
+ int rc;
+
+ rc = lpfc_oas_lun_state_set(phba, vpt_wwpn, tgt_wwpn, lun,
+ oas_state);
+ return rc;
+}
+
+/**
+ * lpfc_oas_lun_show - Return oas enabled luns from a chosen target
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: buffer for passing information.
+ *
+ * This routine returns a lun enabled for OAS each time the function
+ * is called.
+ *
+ * Returns:
+ * SUCCESS: size of formatted string.
+ * -EFAULT: target or vport wwpn was not set properly.
+ * -EPERM: oas is not enabled.
+ **/
+static ssize_t
+lpfc_oas_lun_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+ uint64_t oas_lun;
+ int len = 0;
+
+ if (!phba->cfg_EnableXLane)
+ return -EPERM;
+
+ if (wwn_to_u64(phba->cfg_oas_vpt_wwpn) == 0)
+ if (!(phba->cfg_oas_flags & OAS_FIND_ANY_VPORT))
+ return -EFAULT;
+
+ if (wwn_to_u64(phba->cfg_oas_tgt_wwpn) == 0)
+ if (!(phba->cfg_oas_flags & OAS_FIND_ANY_TARGET))
+ return -EFAULT;
+
+ oas_lun = lpfc_oas_lun_get_next(phba, phba->cfg_oas_vpt_wwpn,
+ phba->cfg_oas_tgt_wwpn,
+ &phba->cfg_oas_lun_status);
+ if (oas_lun != NOT_OAS_ENABLED_LUN)
+ phba->cfg_oas_flags |= OAS_LUN_VALID;
+
+ len += snprintf(buf + len, PAGE_SIZE-len, "0x%llx", oas_lun);
+
+ return len;
+}
+
+/**
+ * lpfc_oas_lun_store - Sets the OAS state for lun
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: buffer for passing information.
+ *
+ * This function sets the OAS state for lun. Before this function is called,
+ * the vport wwpn, target wwpn, and oas state need to be set.
+ *
+ * Returns:
+ * SUCCESS: size of formatted string.
+ * -EFAULT: target or vport wwpn was not set properly.
+ * -EPERM: oas is not enabled.
+ * size of formatted string.
+ **/
+static ssize_t
+lpfc_oas_lun_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+ uint64_t scsi_lun;
+ ssize_t rc;
+
+ if (!phba->cfg_EnableXLane)
+ return -EPERM;
+
+ if (wwn_to_u64(phba->cfg_oas_vpt_wwpn) == 0)
+ return -EFAULT;
+
+ if (wwn_to_u64(phba->cfg_oas_tgt_wwpn) == 0)
+ return -EFAULT;
+
+ if (!isdigit(buf[0]))
+ return -EINVAL;
+
+ if (sscanf(buf, "0x%llx", &scsi_lun) != 1)
+ return -EINVAL;
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "3372 Try to set vport 0x%llx target 0x%llx lun:%lld "
+ "with oas set to %d\n",
+ wwn_to_u64(phba->cfg_oas_vpt_wwpn),
+ wwn_to_u64(phba->cfg_oas_tgt_wwpn), scsi_lun,
+ phba->cfg_oas_lun_state);
+
+ rc = lpfc_oas_lun_state_change(phba, phba->cfg_oas_vpt_wwpn,
+ phba->cfg_oas_tgt_wwpn, scsi_lun,
+ phba->cfg_oas_lun_state);
+
+ if (rc)
+ return rc;
+
+ return count;
+}
+static DEVICE_ATTR(lpfc_xlane_lun, S_IRUGO | S_IWUSR,
+ lpfc_oas_lun_show, lpfc_oas_lun_store);
static int lpfc_poll = 0;
module_param(lpfc_poll, int, S_IRUGO);
@@ -3818,7 +4288,7 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr,
struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
struct lpfc_hba *phba = vport->phba;
struct lpfc_vector_map_info *cpup;
- int idx, len = 0;
+ int len = 0;
if ((phba->sli_rev != LPFC_SLI_REV4) ||
(phba->intr_type != MSIX))
@@ -3846,23 +4316,39 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr,
break;
}
- cpup = phba->sli4_hba.cpu_map;
- for (idx = 0; idx < phba->sli4_hba.num_present_cpu; idx++) {
+ while (phba->sli4_hba.curr_disp_cpu < phba->sli4_hba.num_present_cpu) {
+ cpup = &phba->sli4_hba.cpu_map[phba->sli4_hba.curr_disp_cpu];
+
+ /* margin should fit in this and the truncated message */
if (cpup->irq == LPFC_VECTOR_MAP_EMPTY)
len += snprintf(buf + len, PAGE_SIZE-len,
"CPU %02d io_chan %02d "
"physid %d coreid %d\n",
- idx, cpup->channel_id, cpup->phys_id,
+ phba->sli4_hba.curr_disp_cpu,
+ cpup->channel_id, cpup->phys_id,
cpup->core_id);
else
len += snprintf(buf + len, PAGE_SIZE-len,
"CPU %02d io_chan %02d "
"physid %d coreid %d IRQ %d\n",
- idx, cpup->channel_id, cpup->phys_id,
+ phba->sli4_hba.curr_disp_cpu,
+ cpup->channel_id, cpup->phys_id,
cpup->core_id, cpup->irq);
- cpup++;
+ phba->sli4_hba.curr_disp_cpu++;
+
+ /* display max number of CPUs keeping some margin */
+ if (phba->sli4_hba.curr_disp_cpu <
+ phba->sli4_hba.num_present_cpu &&
+ (len >= (PAGE_SIZE - 64))) {
+ len += snprintf(buf + len, PAGE_SIZE-len, "more...\n");
+ break;
+ }
}
+
+ if (phba->sli4_hba.curr_disp_cpu == phba->sli4_hba.num_present_cpu)
+ phba->sli4_hba.curr_disp_cpu = 0;
+
return len;
}
@@ -4157,6 +4643,21 @@ LPFC_ATTR_R(enable_hba_reset, 1, 0, 1, "Enable HBA resets from the driver.");
LPFC_ATTR_R(enable_hba_heartbeat, 0, 0, 1, "Enable HBA Heartbeat.");
/*
+# lpfc_EnableXLane: Enable Express Lane Feature
+# 0x0 Express Lane Feature disabled
+# 0x1 Express Lane Feature enabled
+# Value range is [0,1]. Default value is 0.
+*/
+LPFC_ATTR_R(EnableXLane, 0, 0, 1, "Enable Express Lane Feature.");
+
+/*
+# lpfc_XLanePriority: Define CS_CTL priority for Express Lane Feature
+# 0x0 - 0x7f = CS_CTL field in FC header (high 7 bits)
+# Value range is [0x0,0x7f]. Default value is 0
+*/
+LPFC_ATTR_R(XLanePriority, 0, 0x0, 0x7f, "CS_CTL for Express Lane Feature.");
+
+/*
# lpfc_enable_bg: Enable BlockGuard (Emulex's Implementation of T10-DIF)
# 0 = BlockGuard disabled (default)
# 1 = BlockGuard enabled
@@ -4317,6 +4818,13 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_soft_wwn_enable,
&dev_attr_lpfc_enable_hba_reset,
&dev_attr_lpfc_enable_hba_heartbeat,
+ &dev_attr_lpfc_EnableXLane,
+ &dev_attr_lpfc_XLanePriority,
+ &dev_attr_lpfc_xlane_lun,
+ &dev_attr_lpfc_xlane_tgt,
+ &dev_attr_lpfc_xlane_vpt,
+ &dev_attr_lpfc_xlane_lun_state,
+ &dev_attr_lpfc_xlane_lun_status,
&dev_attr_lpfc_sg_seg_cnt,
&dev_attr_lpfc_max_scsicmpl_time,
&dev_attr_lpfc_stat_data_ctrl,
@@ -4335,6 +4843,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_dss,
&dev_attr_lpfc_sriov_hw_max_virtfn,
&dev_attr_protocol,
+ &dev_attr_lpfc_xlane_supported,
NULL,
};
@@ -5296,11 +5805,20 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
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);
+ lpfc_EnableXLane_init(phba, lpfc_EnableXLane);
+ if (phba->sli_rev != LPFC_SLI_REV4)
+ phba->cfg_EnableXLane = 0;
+ lpfc_XLanePriority_init(phba, lpfc_XLanePriority);
+ memset(phba->cfg_oas_tgt_wwpn, 0, (8 * sizeof(uint8_t)));
+ memset(phba->cfg_oas_vpt_wwpn, 0, (8 * sizeof(uint8_t)));
+ phba->cfg_oas_lun_state = 0;
+ phba->cfg_oas_lun_status = 0;
+ phba->cfg_oas_flags = 0;
lpfc_enable_bg_init(phba, lpfc_enable_bg);
if (phba->sli_rev == LPFC_SLI_REV4)
phba->cfg_poll = 0;
else
- phba->cfg_poll = lpfc_poll;
+ phba->cfg_poll = lpfc_poll;
phba->cfg_soft_wwnn = 0L;
phba->cfg_soft_wwpn = 0L;
lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt);
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index 82134d20e2d8..ca2f4ea7cdef 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -4153,6 +4153,7 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
if (subsys == SLI_CONFIG_SUBSYS_FCOE) {
switch (opcode) {
case FCOE_OPCODE_READ_FCF:
+ case FCOE_OPCODE_GET_DPORT_RESULTS:
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
"2957 Handled SLI_CONFIG "
"subsys_fcoe, opcode:x%x\n",
@@ -4161,6 +4162,8 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
nemb_mse, dmabuf);
break;
case FCOE_OPCODE_ADD_FCF:
+ case FCOE_OPCODE_SET_DPORT_MODE:
+ case LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE:
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
"2958 Handled SLI_CONFIG "
"subsys_fcoe, opcode:x%x\n",
diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h
index 67f7d0a160d1..a94d4c9dfaa5 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.h
+++ b/drivers/scsi/lpfc/lpfc_bsg.h
@@ -231,6 +231,8 @@ struct lpfc_sli_config_emb0_subsys {
#define SLI_CONFIG_SUBSYS_FCOE 0x0C
#define FCOE_OPCODE_READ_FCF 0x08
#define FCOE_OPCODE_ADD_FCF 0x09
+#define FCOE_OPCODE_SET_DPORT_MODE 0x27
+#define FCOE_OPCODE_GET_DPORT_RESULTS 0x28
};
struct lpfc_sli_config_emb1_subsys {
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index cda076a84239..adda0bf7a244 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -187,6 +187,11 @@ void lpfc_offline_prep(struct lpfc_hba *, int);
void lpfc_offline(struct lpfc_hba *);
void lpfc_reset_hba(struct lpfc_hba *);
+int lpfc_fof_queue_create(struct lpfc_hba *);
+int lpfc_fof_queue_setup(struct lpfc_hba *);
+int lpfc_fof_queue_destroy(struct lpfc_hba *);
+irqreturn_t lpfc_sli4_fof_intr_handler(int, void *);
+
int lpfc_sli_setup(struct lpfc_hba *);
int lpfc_sli_queue_setup(struct lpfc_hba *);
@@ -242,6 +247,7 @@ int lpfc_sli4_fcf_rr_next_proc(struct lpfc_vport *, uint16_t);
void lpfc_sli4_clear_fcf_rr_bmask(struct lpfc_hba *);
int lpfc_mem_alloc(struct lpfc_hba *, int align);
+int lpfc_mem_alloc_active_rrq_pool_s4(struct lpfc_hba *);
void lpfc_mem_free(struct lpfc_hba *);
void lpfc_mem_free_all(struct lpfc_hba *);
void lpfc_stop_vport_timers(struct lpfc_vport *);
@@ -399,7 +405,6 @@ void lpfc_fabric_block_timeout(unsigned long);
void lpfc_unblock_fabric_iocbs(struct lpfc_hba *);
void lpfc_rampdown_queue_depth(struct lpfc_hba *);
void lpfc_ramp_down_queue_handler(struct lpfc_hba *);
-void lpfc_ramp_up_queue_handler(struct lpfc_hba *);
void lpfc_scsi_dev_block(struct lpfc_hba *);
void
@@ -471,3 +476,20 @@ void lpfc_free_sgl_list(struct lpfc_hba *, struct list_head *);
uint32_t lpfc_sli_port_speed_get(struct lpfc_hba *);
int lpfc_sli4_request_firmware_update(struct lpfc_hba *, uint8_t);
void lpfc_sli4_offline_eratt(struct lpfc_hba *);
+
+struct lpfc_device_data *lpfc_create_device_data(struct lpfc_hba *,
+ struct lpfc_name *,
+ struct lpfc_name *,
+ uint64_t, bool);
+void lpfc_delete_device_data(struct lpfc_hba *, struct lpfc_device_data*);
+struct lpfc_device_data *__lpfc_get_device_data(struct lpfc_hba *,
+ struct list_head *list,
+ struct lpfc_name *,
+ struct lpfc_name *, uint64_t);
+bool lpfc_enable_oas_lun(struct lpfc_hba *, struct lpfc_name *,
+ struct lpfc_name *, uint64_t);
+bool lpfc_disable_oas_lun(struct lpfc_hba *, struct lpfc_name *,
+ struct lpfc_name *, uint64_t);
+bool lpfc_find_next_oas_lun(struct lpfc_hba *, struct lpfc_name *,
+ struct lpfc_name *, uint64_t *, struct lpfc_name *,
+ struct lpfc_name *, uint64_t *, uint32_t *);
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index b800cc952ca6..828c08e9389e 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -2280,6 +2280,104 @@ proc_cq:
}
}
+ if (phba->cfg_fof) {
+ /* FOF EQ */
+ qp = phba->sli4_hba.fof_eq;
+ if (!qp)
+ goto out;
+
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\nFOF EQ info: "
+ "EQ-STAT[max:x%x noE:x%x "
+ "bs:x%x proc:x%llx]\n",
+ qp->q_cnt_1, qp->q_cnt_2,
+ qp->q_cnt_3, (unsigned long long)qp->q_cnt_4);
+
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "EQID[%02d], "
+ "QE-CNT[%04d], QE-SIZE[%04d], "
+ "HOST-IDX[%04d], PORT-IDX[%04d]",
+ qp->queue_id,
+ qp->entry_count,
+ qp->entry_size,
+ qp->host_index,
+ qp->hba_index);
+
+ /* Reset max counter */
+ qp->EQ_max_eqe = 0;
+
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n");
+ if (len >= max_cnt)
+ goto too_big;
+ }
+
+ if (phba->cfg_EnableXLane) {
+
+ /* OAS CQ */
+ qp = phba->sli4_hba.oas_cq;
+ if (qp) {
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\tOAS CQ info: ");
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "AssocEQID[%02d]: "
+ "CQ STAT[max:x%x relw:x%x "
+ "xabt:x%x wq:x%llx]\n",
+ qp->assoc_qid,
+ qp->q_cnt_1, qp->q_cnt_2,
+ qp->q_cnt_3, (unsigned long long)qp->q_cnt_4);
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\tCQID[%02d], "
+ "QE-CNT[%04d], QE-SIZE[%04d], "
+ "HOST-IDX[%04d], PORT-IDX[%04d]",
+ qp->queue_id, qp->entry_count,
+ qp->entry_size, qp->host_index,
+ qp->hba_index);
+
+ /* Reset max counter */
+ qp->CQ_max_cqe = 0;
+
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n");
+ if (len >= max_cnt)
+ goto too_big;
+ }
+
+ /* OAS WQ */
+ qp = phba->sli4_hba.oas_wq;
+ if (qp) {
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\t\tOAS WQ info: ");
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "AssocCQID[%02d]: "
+ "WQ-STAT[oflow:x%x posted:x%llx]\n",
+ qp->assoc_qid,
+ qp->q_cnt_1, (unsigned long long)qp->q_cnt_4);
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\t\tWQID[%02d], "
+ "QE-CNT[%04d], QE-SIZE[%04d], "
+ "HOST-IDX[%04d], PORT-IDX[%04d]",
+ qp->queue_id,
+ qp->entry_count,
+ qp->entry_size,
+ qp->host_index,
+ qp->hba_index);
+
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n");
+ if (len >= max_cnt)
+ goto too_big;
+ }
+ }
+out:
spin_unlock_irq(&phba->hbalock);
return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
@@ -3927,6 +4025,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
struct lpfc_hba *phba = vport->phba;
char name[64];
uint32_t num, i;
+ bool pport_setup = false;
if (!lpfc_debugfs_enable)
return;
@@ -3947,6 +4046,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
/* Setup funcX directory for specific HBA PCI function */
snprintf(name, sizeof(name), "fn%d", phba->brd_no);
if (!phba->hba_debugfs_root) {
+ pport_setup = true;
phba->hba_debugfs_root =
debugfs_create_dir(name, lpfc_debugfs_root);
if (!phba->hba_debugfs_root) {
@@ -4239,6 +4339,14 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
}
/*
+ * The following section is for additional directories/files for the
+ * physical port.
+ */
+
+ if (!pport_setup)
+ goto debug_failed;
+
+ /*
* iDiag debugfs root entry points for SLI4 device only
*/
if (phba->sli_rev < LPFC_SLI_REV4)
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index e409ba5f728c..1a6fe524940d 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -116,7 +116,7 @@ struct lpfc_nodelist {
atomic_t cmd_pending;
uint32_t cmd_qdepth;
unsigned long last_change_time;
- struct lpfc_node_rrqs active_rrqs;
+ unsigned long *active_rrqs_xri_bitmap;
struct lpfc_scsicmd_bkt *lat_data; /* Latency data */
};
struct lpfc_node_rrq {
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 110445f0c58d..624fe0b3cc0b 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -1516,7 +1516,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
uint32_t rc, keepDID = 0;
int put_node;
int put_rport;
- struct lpfc_node_rrqs rrq;
+ unsigned long *active_rrqs_xri_bitmap = NULL;
/* Fabric nodes can have the same WWPN so we don't bother searching
* by WWPN. Just return the ndlp that was given to us.
@@ -1534,7 +1534,13 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
if (new_ndlp == ndlp && NLP_CHK_NODE_ACT(new_ndlp))
return ndlp;
- memset(&rrq.xri_bitmap, 0, sizeof(new_ndlp->active_rrqs.xri_bitmap));
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ active_rrqs_xri_bitmap = mempool_alloc(phba->active_rrq_pool,
+ GFP_KERNEL);
+ if (active_rrqs_xri_bitmap)
+ memset(active_rrqs_xri_bitmap, 0,
+ phba->cfg_rrq_xri_bitmap_sz);
+ }
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"3178 PLOGI confirm: ndlp %p x%x: new_ndlp %p\n",
@@ -1543,41 +1549,58 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
if (!new_ndlp) {
rc = memcmp(&ndlp->nlp_portname, name,
sizeof(struct lpfc_name));
- if (!rc)
+ if (!rc) {
+ if (active_rrqs_xri_bitmap)
+ mempool_free(active_rrqs_xri_bitmap,
+ phba->active_rrq_pool);
return ndlp;
+ }
new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC);
- if (!new_ndlp)
+ if (!new_ndlp) {
+ if (active_rrqs_xri_bitmap)
+ mempool_free(active_rrqs_xri_bitmap,
+ phba->active_rrq_pool);
return ndlp;
+ }
lpfc_nlp_init(vport, new_ndlp, ndlp->nlp_DID);
} else if (!NLP_CHK_NODE_ACT(new_ndlp)) {
rc = memcmp(&ndlp->nlp_portname, name,
sizeof(struct lpfc_name));
- if (!rc)
+ if (!rc) {
+ if (active_rrqs_xri_bitmap)
+ mempool_free(active_rrqs_xri_bitmap,
+ phba->active_rrq_pool);
return ndlp;
+ }
new_ndlp = lpfc_enable_node(vport, new_ndlp,
NLP_STE_UNUSED_NODE);
- if (!new_ndlp)
+ if (!new_ndlp) {
+ if (active_rrqs_xri_bitmap)
+ mempool_free(active_rrqs_xri_bitmap,
+ phba->active_rrq_pool);
return ndlp;
+ }
keepDID = new_ndlp->nlp_DID;
- if (phba->sli_rev == LPFC_SLI_REV4)
- memcpy(&rrq.xri_bitmap,
- &new_ndlp->active_rrqs.xri_bitmap,
- sizeof(new_ndlp->active_rrqs.xri_bitmap));
+ if ((phba->sli_rev == LPFC_SLI_REV4) && active_rrqs_xri_bitmap)
+ memcpy(active_rrqs_xri_bitmap,
+ new_ndlp->active_rrqs_xri_bitmap,
+ phba->cfg_rrq_xri_bitmap_sz);
} else {
keepDID = new_ndlp->nlp_DID;
- if (phba->sli_rev == LPFC_SLI_REV4)
- memcpy(&rrq.xri_bitmap,
- &new_ndlp->active_rrqs.xri_bitmap,
- sizeof(new_ndlp->active_rrqs.xri_bitmap));
+ if (phba->sli_rev == LPFC_SLI_REV4 &&
+ active_rrqs_xri_bitmap)
+ memcpy(active_rrqs_xri_bitmap,
+ new_ndlp->active_rrqs_xri_bitmap,
+ phba->cfg_rrq_xri_bitmap_sz);
}
lpfc_unreg_rpi(vport, new_ndlp);
new_ndlp->nlp_DID = ndlp->nlp_DID;
new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
if (phba->sli_rev == LPFC_SLI_REV4)
- memcpy(new_ndlp->active_rrqs.xri_bitmap,
- &ndlp->active_rrqs.xri_bitmap,
- sizeof(ndlp->active_rrqs.xri_bitmap));
+ memcpy(new_ndlp->active_rrqs_xri_bitmap,
+ ndlp->active_rrqs_xri_bitmap,
+ phba->cfg_rrq_xri_bitmap_sz);
if (ndlp->nlp_flag & NLP_NPR_2B_DISC)
new_ndlp->nlp_flag |= NLP_NPR_2B_DISC;
@@ -1619,10 +1642,11 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
/* Two ndlps cannot have the same did on the nodelist */
ndlp->nlp_DID = keepDID;
- if (phba->sli_rev == LPFC_SLI_REV4)
- memcpy(&ndlp->active_rrqs.xri_bitmap,
- &rrq.xri_bitmap,
- sizeof(ndlp->active_rrqs.xri_bitmap));
+ if (phba->sli_rev == LPFC_SLI_REV4 &&
+ active_rrqs_xri_bitmap)
+ memcpy(ndlp->active_rrqs_xri_bitmap,
+ active_rrqs_xri_bitmap,
+ phba->cfg_rrq_xri_bitmap_sz);
lpfc_drop_node(vport, ndlp);
}
else {
@@ -1634,10 +1658,11 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
/* Two ndlps cannot have the same did */
ndlp->nlp_DID = keepDID;
- if (phba->sli_rev == LPFC_SLI_REV4)
- memcpy(&ndlp->active_rrqs.xri_bitmap,
- &rrq.xri_bitmap,
- sizeof(ndlp->active_rrqs.xri_bitmap));
+ if (phba->sli_rev == LPFC_SLI_REV4 &&
+ active_rrqs_xri_bitmap)
+ memcpy(ndlp->active_rrqs_xri_bitmap,
+ active_rrqs_xri_bitmap,
+ phba->cfg_rrq_xri_bitmap_sz);
/* Since we are swapping the ndlp passed in with the new one
* and the did has already been swapped, copy over state.
@@ -1668,6 +1693,10 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
put_device(&rport->dev);
}
}
+ if (phba->sli_rev == LPFC_SLI_REV4 &&
+ active_rrqs_xri_bitmap)
+ mempool_free(active_rrqs_xri_bitmap,
+ phba->active_rrq_pool);
return new_ndlp;
}
@@ -2772,6 +2801,7 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
/* This will cause the callback-function lpfc_cmpl_els_cmd to
* trigger the release of node.
*/
+
lpfc_nlp_put(ndlp);
return 0;
}
@@ -6193,11 +6223,11 @@ lpfc_els_timeout(unsigned long ptr)
spin_lock_irqsave(&vport->work_port_lock, iflag);
tmo_posted = vport->work_port_events & WORKER_ELS_TMO;
- if (!tmo_posted)
+ if ((!tmo_posted) && (!(vport->load_flag & FC_UNLOADING)))
vport->work_port_events |= WORKER_ELS_TMO;
spin_unlock_irqrestore(&vport->work_port_lock, iflag);
- if (!tmo_posted)
+ if ((!tmo_posted) && (!(vport->load_flag & FC_UNLOADING)))
lpfc_worker_wake_up(phba);
return;
}
@@ -6223,19 +6253,26 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
uint32_t els_command = 0;
uint32_t timeout;
uint32_t remote_ID = 0xffffffff;
- LIST_HEAD(txcmplq_completions);
LIST_HEAD(abort_list);
timeout = (uint32_t)(phba->fc_ratov << 1);
pring = &phba->sli.ring[LPFC_ELS_RING];
-
+ if ((phba->pport->load_flag & FC_UNLOADING))
+ return;
spin_lock_irq(&phba->hbalock);
- list_splice_init(&pring->txcmplq, &txcmplq_completions);
- spin_unlock_irq(&phba->hbalock);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_lock(&pring->ring_lock);
+
+ if ((phba->pport->load_flag & FC_UNLOADING)) {
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_unlock(&pring->ring_lock);
+ spin_unlock_irq(&phba->hbalock);
+ return;
+ }
- list_for_each_entry_safe(piocb, tmp_iocb, &txcmplq_completions, list) {
+ list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
cmd = &piocb->iocb;
if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 ||
@@ -6274,11 +6311,12 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
}
list_add_tail(&piocb->dlist, &abort_list);
}
- spin_lock_irq(&phba->hbalock);
- list_splice(&txcmplq_completions, &pring->txcmplq);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_unlock(&pring->ring_lock);
spin_unlock_irq(&phba->hbalock);
list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) {
+ cmd = &piocb->iocb;
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
"0127 ELS timeout Data: x%x x%x x%x "
"x%x\n", els_command,
@@ -6290,8 +6328,9 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
}
if (!list_empty(&phba->sli.ring[LPFC_ELS_RING].txcmplq))
- mod_timer(&vport->els_tmofunc,
- jiffies + msecs_to_jiffies(1000 * timeout));
+ if (!(phba->pport->load_flag & FC_UNLOADING))
+ mod_timer(&vport->els_tmofunc,
+ jiffies + msecs_to_jiffies(1000 * timeout));
}
/**
@@ -6317,15 +6356,50 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
void
lpfc_els_flush_cmd(struct lpfc_vport *vport)
{
- LIST_HEAD(completions);
+ LIST_HEAD(abort_list);
struct lpfc_hba *phba = vport->phba;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
struct lpfc_iocbq *tmp_iocb, *piocb;
IOCB_t *cmd = NULL;
lpfc_fabric_abort_vport(vport);
+ /*
+ * For SLI3, only the hbalock is required. But SLI4 needs to coordinate
+ * with the ring insert operation. Because lpfc_sli_issue_abort_iotag
+ * ultimately grabs the ring_lock, the driver must splice the list into
+ * a working list and release the locks before calling the abort.
+ */
+ spin_lock_irq(&phba->hbalock);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_lock(&pring->ring_lock);
+
+ list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
+ if (piocb->iocb_flag & LPFC_IO_LIBDFC)
+ continue;
+
+ if (piocb->vport != vport)
+ continue;
+ list_add_tail(&piocb->dlist, &abort_list);
+ }
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_unlock(&pring->ring_lock);
+ spin_unlock_irq(&phba->hbalock);
+ /* Abort each iocb on the aborted list and remove the dlist links. */
+ list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) {
+ spin_lock_irq(&phba->hbalock);
+ list_del_init(&piocb->dlist);
+ lpfc_sli_issue_abort_iotag(phba, pring, piocb);
+ spin_unlock_irq(&phba->hbalock);
+ }
+ if (!list_empty(&abort_list))
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "3387 abort list for txq not empty\n");
+ INIT_LIST_HEAD(&abort_list);
spin_lock_irq(&phba->hbalock);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_lock(&pring->ring_lock);
+
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
cmd = &piocb->iocb;
@@ -6343,24 +6417,16 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
if (piocb->vport != vport)
continue;
- list_move_tail(&piocb->list, &completions);
- }
-
- list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
- if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
- continue;
- }
-
- if (piocb->vport != vport)
- continue;
-
- lpfc_sli_issue_abort_iotag(phba, pring, piocb);
+ list_del_init(&piocb->list);
+ list_add_tail(&piocb->list, &abort_list);
}
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_unlock(&pring->ring_lock);
spin_unlock_irq(&phba->hbalock);
/* Cancell all the IOCBs from the completions list */
- lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
- IOERR_SLI_ABORTED);
+ lpfc_sli_cancel_iocbs(phba, &abort_list,
+ IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED);
return;
}
@@ -6385,35 +6451,9 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
void
lpfc_els_flush_all_cmd(struct lpfc_hba *phba)
{
- LIST_HEAD(completions);
- struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
- struct lpfc_iocbq *tmp_iocb, *piocb;
- IOCB_t *cmd = NULL;
-
- lpfc_fabric_abort_hba(phba);
- spin_lock_irq(&phba->hbalock);
- list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
- cmd = &piocb->iocb;
- if (piocb->iocb_flag & LPFC_IO_LIBDFC)
- continue;
- /* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */
- if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
- cmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
- cmd->ulpCommand == CMD_CLOSE_XRI_CN ||
- cmd->ulpCommand == CMD_ABORT_XRI_CN)
- continue;
- list_move_tail(&piocb->list, &completions);
- }
- list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
- if (piocb->iocb_flag & LPFC_IO_LIBDFC)
- continue;
- lpfc_sli_issue_abort_iotag(phba, pring, piocb);
- }
- spin_unlock_irq(&phba->hbalock);
-
- /* Cancel all the IOCBs from the completions list */
- lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
- IOERR_SLI_ABORTED);
+ struct lpfc_vport *vport;
+ list_for_each_entry(vport, &phba->port_list, listentry)
+ lpfc_els_flush_cmd(vport);
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 883ea2d9f237..59b51c529ba0 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -674,8 +674,6 @@ lpfc_work_done(struct lpfc_hba *phba)
lpfc_fdmi_timeout_handler(vport);
if (work_port_events & WORKER_RAMP_DOWN_QUEUE)
lpfc_ramp_down_queue_handler(phba);
- if (work_port_events & WORKER_RAMP_UP_QUEUE)
- lpfc_ramp_up_queue_handler(phba);
if (work_port_events & WORKER_DELAYED_DISC_TMO)
lpfc_delayed_disc_timeout_handler(vport);
}
@@ -2545,8 +2543,11 @@ lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
if (!new_fcf_record) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
"2766 Mailbox command READ_FCF_RECORD "
- "failed to retrieve a FCF record.\n");
- goto error_out;
+ "failed to retrieve a FCF record. "
+ "hba_flg x%x fcf_flg x%x\n", phba->hba_flag,
+ phba->fcf.fcf_flag);
+ lpfc_unregister_fcf_rescan(phba);
+ goto out;
}
/* Get the needed parameters from FCF record */
@@ -3973,7 +3974,10 @@ lpfc_nlp_counters(struct lpfc_vport *vport, int state, int count)
vport->fc_map_cnt += count;
break;
case NLP_STE_NPR_NODE:
- vport->fc_npr_cnt += count;
+ if (vport->fc_npr_cnt == 0 && count == -1)
+ vport->fc_npr_cnt = 0;
+ else
+ vport->fc_npr_cnt += count;
break;
}
spin_unlock_irq(shost->host_lock);
@@ -4180,6 +4184,7 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
struct lpfc_hba *phba = vport->phba;
uint32_t did;
unsigned long flags;
+ unsigned long *active_rrqs_xri_bitmap = NULL;
if (!ndlp)
return NULL;
@@ -4208,12 +4213,17 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
/* Keep the original DID */
did = ndlp->nlp_DID;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ active_rrqs_xri_bitmap = ndlp->active_rrqs_xri_bitmap;
/* re-initialize ndlp except of ndlp linked list pointer */
memset((((char *)ndlp) + sizeof (struct list_head)), 0,
sizeof (struct lpfc_nodelist) - sizeof (struct list_head));
lpfc_initialize_node(vport, ndlp, did);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ ndlp->active_rrqs_xri_bitmap = active_rrqs_xri_bitmap;
+
spin_unlock_irqrestore(&phba->ndlp_lock, flags);
if (vport->phba->sli_rev == LPFC_SLI_REV4)
ndlp->nlp_rpi = lpfc_sli4_alloc_rpi(vport->phba);
@@ -4799,9 +4809,10 @@ __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did)
((uint32_t) ndlp->nlp_rpi & 0xff));
lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
"0929 FIND node DID "
- "Data: x%p x%x x%x x%x\n",
+ "Data: x%p x%x x%x x%x %p\n",
ndlp, ndlp->nlp_DID,
- ndlp->nlp_flag, data1);
+ ndlp->nlp_flag, data1,
+ ndlp->active_rrqs_xri_bitmap);
return ndlp;
}
}
@@ -5618,8 +5629,13 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
lpfc_initialize_node(vport, ndlp, did);
INIT_LIST_HEAD(&ndlp->nlp_listp);
- if (vport->phba->sli_rev == LPFC_SLI_REV4)
+ if (vport->phba->sli_rev == LPFC_SLI_REV4) {
ndlp->nlp_rpi = lpfc_sli4_alloc_rpi(vport->phba);
+ ndlp->active_rrqs_xri_bitmap =
+ mempool_alloc(vport->phba->active_rrq_pool,
+ GFP_KERNEL);
+ }
+
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE,
@@ -5664,6 +5680,9 @@ lpfc_nlp_release(struct kref *kref)
/* free ndlp memory for final ndlp release */
if (NLP_CHK_FREE_REQ(ndlp)) {
kfree(ndlp->lat_data);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ mempool_free(ndlp->active_rrqs_xri_bitmap,
+ ndlp->phba->active_rrq_pool);
mempool_free(ndlp, ndlp->phba->nlp_mem_pool);
}
}
@@ -6170,10 +6189,6 @@ lpfc_read_fcf_conn_tbl(struct lpfc_hba *phba,
memcpy(&conn_entry->conn_rec, &conn_rec[i],
sizeof(struct lpfc_fcf_conn_rec));
- conn_entry->conn_rec.vlan_tag =
- conn_entry->conn_rec.vlan_tag;
- conn_entry->conn_rec.flags =
- conn_entry->conn_rec.flags;
list_add_tail(&conn_entry->list,
&phba->fcf_conn_rec_list);
}
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 6f927d30ca69..3d9438ce59ab 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -45,6 +45,7 @@
#define LPFC_EXTRA_RING 1 /* ring 1 for other protocols */
#define LPFC_ELS_RING 2 /* ring 2 for ELS commands */
#define LPFC_FCP_NEXT_RING 3
+#define LPFC_FCP_OAS_RING 3
#define SLI2_IOCB_CMD_R0_ENTRIES 172 /* SLI-2 FCP command ring entries */
#define SLI2_IOCB_RSP_R0_ENTRIES 134 /* SLI-2 FCP response ring entries */
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 5464b116d328..fd79f7de7666 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -2616,6 +2616,9 @@ struct lpfc_sli4_parameters {
#define cfg_phwq_SHIFT 15
#define cfg_phwq_MASK 0x00000001
#define cfg_phwq_WORD word12
+#define cfg_oas_SHIFT 25
+#define cfg_oas_MASK 0x00000001
+#define cfg_oas_WORD word12
#define cfg_loopbk_scope_SHIFT 28
#define cfg_loopbk_scope_MASK 0x0000000f
#define cfg_loopbk_scope_WORD word12
@@ -3322,6 +3325,9 @@ struct wqe_common {
#define wqe_ebde_cnt_SHIFT 0
#define wqe_ebde_cnt_MASK 0x0000000f
#define wqe_ebde_cnt_WORD word10
+#define wqe_oas_SHIFT 6
+#define wqe_oas_MASK 0x00000001
+#define wqe_oas_WORD word10
#define wqe_lenloc_SHIFT 7
#define wqe_lenloc_MASK 0x00000003
#define wqe_lenloc_WORD word10
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 68c94cc85c35..635eeb3d6987 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -80,6 +80,7 @@ static void lpfc_sli4_cq_event_pool_destroy(struct lpfc_hba *);
static void lpfc_sli4_cq_event_release_all(struct lpfc_hba *);
static void lpfc_sli4_disable_intr(struct lpfc_hba *);
static uint32_t lpfc_sli4_enable_intr(struct lpfc_hba *, uint32_t);
+static void lpfc_sli4_oas_verify(struct lpfc_hba *phba);
static struct scsi_transport_template *lpfc_transport_template = NULL;
static struct scsi_transport_template *lpfc_vport_transport_template = NULL;
@@ -1005,9 +1006,14 @@ lpfc_rrq_timeout(unsigned long ptr)
phba = (struct lpfc_hba *)ptr;
spin_lock_irqsave(&phba->pport->work_port_lock, iflag);
- phba->hba_flag |= HBA_RRQ_ACTIVE;
+ if (!(phba->pport->load_flag & FC_UNLOADING))
+ phba->hba_flag |= HBA_RRQ_ACTIVE;
+ else
+ phba->hba_flag &= ~HBA_RRQ_ACTIVE;
spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag);
- lpfc_worker_wake_up(phba);
+
+ if (!(phba->pport->load_flag & FC_UNLOADING))
+ lpfc_worker_wake_up(phba);
}
/**
@@ -1468,7 +1474,8 @@ lpfc_handle_eratt_s3(struct lpfc_hba *phba)
* for handling possible port resource change.
**/
static int
-lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action)
+lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action,
+ bool en_rn_msg)
{
int rc;
uint32_t intr_mode;
@@ -1480,9 +1487,10 @@ lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action)
rc = lpfc_sli4_pdev_status_reg_wait(phba);
if (!rc) {
/* need reset: attempt for port recovery */
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "2887 Reset Needed: Attempting Port "
- "Recovery...\n");
+ if (en_rn_msg)
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2887 Reset Needed: Attempting Port "
+ "Recovery...\n");
lpfc_offline_prep(phba, mbx_action);
lpfc_offline(phba);
/* release interrupt for possible resource change */
@@ -1522,6 +1530,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
uint32_t reg_err1, reg_err2;
uint32_t uerrlo_reg, uemasklo_reg;
uint32_t pci_rd_rc1, pci_rd_rc2;
+ bool en_rn_msg = true;
int rc;
/* If the pci channel is offline, ignore possible errors, since
@@ -1572,10 +1581,12 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
break;
}
if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 &&
- reg_err2 == SLIPORT_ERR2_REG_FW_RESTART)
+ reg_err2 == SLIPORT_ERR2_REG_FW_RESTART) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "3143 Port Down: Firmware Restarted\n");
- else if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 &&
+ "3143 Port Down: Firmware Update "
+ "Detected\n");
+ en_rn_msg = false;
+ } else if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 &&
reg_err2 == SLIPORT_ERR2_REG_FORCED_DUMP)
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"3144 Port Down: Debug Dump\n");
@@ -1585,7 +1596,8 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
"3145 Port Down: Provisioning\n");
/* Check port status register for function reset */
- rc = lpfc_sli4_port_sta_fn_reset(phba, LPFC_MBX_NO_WAIT);
+ rc = lpfc_sli4_port_sta_fn_reset(phba, LPFC_MBX_NO_WAIT,
+ en_rn_msg);
if (rc == 0) {
/* don't report event on forced debug dump */
if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 &&
@@ -4856,6 +4868,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
uint8_t pn_page[LPFC_MAX_SUPPORTED_PAGES] = {0};
struct lpfc_mqe *mqe;
int longs;
+ int fof_vectors = 0;
/* Get all the module params for configuring this host */
lpfc_get_cfgparam(phba);
@@ -5061,6 +5074,9 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
rc = lpfc_sli4_read_config(phba);
if (unlikely(rc))
goto out_free_bsmbx;
+ rc = lpfc_mem_alloc_active_rrq_pool_s4(phba);
+ if (unlikely(rc))
+ goto out_free_bsmbx;
/* IF Type 0 ports get initialized now. */
if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
@@ -5118,6 +5134,12 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
}
}
mempool_free(mboxq, phba->mbox_mem_pool);
+
+ /* Verify OAS is supported */
+ lpfc_sli4_oas_verify(phba);
+ if (phba->cfg_fof)
+ fof_vectors = 1;
+
/* Verify all the SLI4 queues */
rc = lpfc_sli4_queue_verify(phba);
if (rc)
@@ -5159,7 +5181,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
phba->sli4_hba.fcp_eq_hdl =
kzalloc((sizeof(struct lpfc_fcp_eq_hdl) *
- phba->cfg_fcp_io_channel), GFP_KERNEL);
+ (fof_vectors + phba->cfg_fcp_io_channel)),
+ GFP_KERNEL);
if (!phba->sli4_hba.fcp_eq_hdl) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"2572 Failed allocate memory for "
@@ -5169,7 +5192,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
}
phba->sli4_hba.msix_entries = kzalloc((sizeof(struct msix_entry) *
- phba->cfg_fcp_io_channel), GFP_KERNEL);
+ (fof_vectors +
+ phba->cfg_fcp_io_channel)), GFP_KERNEL);
if (!phba->sli4_hba.msix_entries) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"2573 Failed allocate memory for msi-x "
@@ -5267,6 +5291,7 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba)
kfree(phba->sli4_hba.cpu_map);
phba->sli4_hba.num_present_cpu = 0;
phba->sli4_hba.num_online_cpu = 0;
+ phba->sli4_hba.curr_disp_cpu = 0;
/* Free memory allocated for msi-x interrupt vector entries */
kfree(phba->sli4_hba.msix_entries);
@@ -5390,6 +5415,10 @@ lpfc_setup_driver_resource_phase1(struct lpfc_hba *phba)
/* Initialize FCF connection rec list */
INIT_LIST_HEAD(&phba->fcf_conn_rec_list);
+ /* Initialize OAS configuration list */
+ spin_lock_init(&phba->devicelock);
+ INIT_LIST_HEAD(&phba->luns);
+
return 0;
}
@@ -6816,6 +6845,7 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba)
int cfg_fcp_io_channel;
uint32_t cpu;
uint32_t i = 0;
+ int fof_vectors = phba->cfg_fof ? 1 : 0;
/*
* Sanity check for configured queue parameters against the run-time
@@ -6832,6 +6862,7 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba)
}
phba->sli4_hba.num_online_cpu = i;
phba->sli4_hba.num_present_cpu = lpfc_present_cpu;
+ phba->sli4_hba.curr_disp_cpu = 0;
if (i < cfg_fcp_io_channel) {
lpfc_printf_log(phba,
@@ -6842,7 +6873,7 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba)
cfg_fcp_io_channel = i;
}
- if (cfg_fcp_io_channel >
+ if (cfg_fcp_io_channel + fof_vectors >
phba->sli4_hba.max_cfg_param.max_eq) {
if (phba->sli4_hba.max_cfg_param.max_eq <
LPFC_FCP_IO_CHAN_MIN) {
@@ -6859,7 +6890,8 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba)
"available EQs: from %d to %d\n",
cfg_fcp_io_channel,
phba->sli4_hba.max_cfg_param.max_eq);
- cfg_fcp_io_channel = phba->sli4_hba.max_cfg_param.max_eq;
+ cfg_fcp_io_channel = phba->sli4_hba.max_cfg_param.max_eq -
+ fof_vectors;
}
/* The actual number of FCP event queues adopted */
@@ -7070,6 +7102,9 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
}
phba->sli4_hba.dat_rq = qdesc;
+ /* Create the Queues needed for Flash Optimized Fabric operations */
+ if (phba->cfg_fof)
+ lpfc_fof_queue_create(phba);
return 0;
out_error:
@@ -7094,6 +7129,9 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba)
{
int idx;
+ if (phba->cfg_fof)
+ lpfc_fof_queue_destroy(phba);
+
if (phba->sli4_hba.hba_eq != NULL) {
/* Release HBA event queue */
for (idx = 0; idx < phba->cfg_fcp_io_channel; idx++) {
@@ -7478,8 +7516,20 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
phba->sli4_hba.hdr_rq->queue_id,
phba->sli4_hba.dat_rq->queue_id,
phba->sli4_hba.els_cq->queue_id);
+
+ if (phba->cfg_fof) {
+ rc = lpfc_fof_queue_setup(phba);
+ if (rc) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "0549 Failed setup of FOF Queues: "
+ "rc = 0x%x\n", rc);
+ goto out_destroy_els_rq;
+ }
+ }
return 0;
+out_destroy_els_rq:
+ lpfc_rq_destroy(phba, phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq);
out_destroy_els_wq:
lpfc_wq_destroy(phba, phba->sli4_hba.els_wq);
out_destroy_mbx_wq:
@@ -7518,6 +7568,9 @@ lpfc_sli4_queue_unset(struct lpfc_hba *phba)
{
int fcp_qidx;
+ /* Unset the queues created for Flash Optimized Fabric operations */
+ if (phba->cfg_fof)
+ lpfc_fof_queue_destroy(phba);
/* Unset mailbox command work queue */
lpfc_mq_destroy(phba, phba->sli4_hba.mbx_wq);
/* Unset ELS work queue */
@@ -8635,6 +8688,10 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba)
/* Configure MSI-X capability structure */
vectors = phba->cfg_fcp_io_channel;
+ if (phba->cfg_fof) {
+ phba->sli4_hba.msix_entries[index].entry = index;
+ vectors++;
+ }
enable_msix_vectors:
rc = pci_enable_msix(phba->pcidev, phba->sli4_hba.msix_entries,
vectors);
@@ -8664,7 +8721,15 @@ enable_msix_vectors:
phba->sli4_hba.fcp_eq_hdl[index].idx = index;
phba->sli4_hba.fcp_eq_hdl[index].phba = phba;
atomic_set(&phba->sli4_hba.fcp_eq_hdl[index].fcp_eq_in_use, 1);
- rc = request_irq(phba->sli4_hba.msix_entries[index].vector,
+ if (phba->cfg_fof && (index == (vectors - 1)))
+ rc = request_irq(
+ phba->sli4_hba.msix_entries[index].vector,
+ &lpfc_sli4_fof_intr_handler, IRQF_SHARED,
+ (char *)&phba->sli4_hba.handler_name[index],
+ &phba->sli4_hba.fcp_eq_hdl[index]);
+ else
+ rc = request_irq(
+ phba->sli4_hba.msix_entries[index].vector,
&lpfc_sli4_hba_intr_handler, IRQF_SHARED,
(char *)&phba->sli4_hba.handler_name[index],
&phba->sli4_hba.fcp_eq_hdl[index]);
@@ -8676,6 +8741,9 @@ enable_msix_vectors:
}
}
+ if (phba->cfg_fof)
+ vectors--;
+
if (vectors != phba->cfg_fcp_io_channel) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"3238 Reducing IO channels to match number of "
@@ -8721,7 +8789,10 @@ lpfc_sli4_disable_msix(struct lpfc_hba *phba)
free_irq(phba->sli4_hba.msix_entries[index].vector,
&phba->sli4_hba.fcp_eq_hdl[index]);
}
-
+ if (phba->cfg_fof) {
+ free_irq(phba->sli4_hba.msix_entries[index].vector,
+ &phba->sli4_hba.fcp_eq_hdl[index]);
+ }
/* Disable MSI-X */
pci_disable_msix(phba->pcidev);
@@ -8771,6 +8842,10 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba)
phba->sli4_hba.fcp_eq_hdl[index].phba = phba;
}
+ if (phba->cfg_fof) {
+ phba->sli4_hba.fcp_eq_hdl[index].idx = index;
+ phba->sli4_hba.fcp_eq_hdl[index].phba = phba;
+ }
return 0;
}
@@ -8853,6 +8928,12 @@ lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)
atomic_set(&phba->sli4_hba.fcp_eq_hdl[index].
fcp_eq_in_use, 1);
}
+ if (phba->cfg_fof) {
+ phba->sli4_hba.fcp_eq_hdl[index].idx = index;
+ phba->sli4_hba.fcp_eq_hdl[index].phba = phba;
+ atomic_set(&phba->sli4_hba.fcp_eq_hdl[index].
+ fcp_eq_in_use, 1);
+ }
}
}
return intr_mode;
@@ -9163,6 +9244,7 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
phba->sli3_options &= ~LPFC_SLI4_PHWQ_ENABLED;
sli4_params->sge_supp_len = mbx_sli4_parameters->sge_supp_len;
sli4_params->loopbk_scope = bf_get(loopbk_scope, mbx_sli4_parameters);
+ sli4_params->oas_supported = bf_get(cfg_oas, mbx_sli4_parameters);
sli4_params->cqv = bf_get(cfg_cqv, mbx_sli4_parameters);
sli4_params->mqv = bf_get(cfg_mqv, mbx_sli4_parameters);
sli4_params->wqv = bf_get(cfg_wqv, mbx_sli4_parameters);
@@ -10796,6 +10878,169 @@ lpfc_io_resume(struct pci_dev *pdev)
return;
}
+/**
+ * lpfc_sli4_oas_verify - Verify OAS is supported by this adapter
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine checks to see if OAS is supported for this adapter. If
+ * supported, the configure Flash Optimized Fabric flag is set. Otherwise,
+ * the enable oas flag is cleared and the pool created for OAS device data
+ * is destroyed.
+ *
+ **/
+void
+lpfc_sli4_oas_verify(struct lpfc_hba *phba)
+{
+
+ if (!phba->cfg_EnableXLane)
+ return;
+
+ if (phba->sli4_hba.pc_sli4_params.oas_supported) {
+ phba->cfg_fof = 1;
+ } else {
+ phba->cfg_EnableXLane = 0;
+ if (phba->device_data_mem_pool)
+ mempool_destroy(phba->device_data_mem_pool);
+ phba->device_data_mem_pool = NULL;
+ }
+
+ return;
+}
+
+/**
+ * lpfc_fof_queue_setup - Set up all the fof queues
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to set up all the fof queues for the FC HBA
+ * operation.
+ *
+ * Return codes
+ * 0 - successful
+ * -ENOMEM - No available memory
+ **/
+int
+lpfc_fof_queue_setup(struct lpfc_hba *phba)
+{
+ struct lpfc_sli *psli = &phba->sli;
+ int rc;
+
+ rc = lpfc_eq_create(phba, phba->sli4_hba.fof_eq, LPFC_MAX_IMAX);
+ if (rc)
+ return -ENOMEM;
+
+ if (phba->cfg_EnableXLane) {
+
+ rc = lpfc_cq_create(phba, phba->sli4_hba.oas_cq,
+ phba->sli4_hba.fof_eq, LPFC_WCQ, LPFC_FCP);
+ if (rc)
+ goto out_oas_cq;
+
+ rc = lpfc_wq_create(phba, phba->sli4_hba.oas_wq,
+ phba->sli4_hba.oas_cq, LPFC_FCP);
+ if (rc)
+ goto out_oas_wq;
+
+ phba->sli4_hba.oas_cq->pring = &psli->ring[LPFC_FCP_OAS_RING];
+ phba->sli4_hba.oas_ring = &psli->ring[LPFC_FCP_OAS_RING];
+ }
+
+ return 0;
+
+out_oas_wq:
+ if (phba->cfg_EnableXLane)
+ lpfc_cq_destroy(phba, phba->sli4_hba.oas_cq);
+out_oas_cq:
+ lpfc_eq_destroy(phba, phba->sli4_hba.fof_eq);
+ return rc;
+
+}
+
+/**
+ * lpfc_fof_queue_create - Create all the fof queues
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to allocate all the fof queues for the FC HBA
+ * operation. For each SLI4 queue type, the parameters such as queue entry
+ * count (queue depth) shall be taken from the module parameter. For now,
+ * we just use some constant number as place holder.
+ *
+ * Return codes
+ * 0 - successful
+ * -ENOMEM - No availble memory
+ * -EIO - The mailbox failed to complete successfully.
+ **/
+int
+lpfc_fof_queue_create(struct lpfc_hba *phba)
+{
+ struct lpfc_queue *qdesc;
+
+ /* Create FOF EQ */
+ qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.eq_esize,
+ phba->sli4_hba.eq_ecount);
+ if (!qdesc)
+ goto out_error;
+
+ phba->sli4_hba.fof_eq = qdesc;
+
+ if (phba->cfg_EnableXLane) {
+
+ /* Create OAS CQ */
+ qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize,
+ phba->sli4_hba.cq_ecount);
+ if (!qdesc)
+ goto out_error;
+
+ phba->sli4_hba.oas_cq = qdesc;
+
+ /* Create OAS WQ */
+ qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.wq_esize,
+ phba->sli4_hba.wq_ecount);
+ if (!qdesc)
+ goto out_error;
+
+ phba->sli4_hba.oas_wq = qdesc;
+
+ }
+ return 0;
+
+out_error:
+ lpfc_fof_queue_destroy(phba);
+ return -ENOMEM;
+}
+
+/**
+ * lpfc_fof_queue_destroy - Destroy all the fof queues
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to release all the SLI4 queues with the FC HBA
+ * operation.
+ *
+ * Return codes
+ * 0 - successful
+ **/
+int
+lpfc_fof_queue_destroy(struct lpfc_hba *phba)
+{
+ /* Release FOF Event queue */
+ if (phba->sli4_hba.fof_eq != NULL) {
+ lpfc_sli4_queue_free(phba->sli4_hba.fof_eq);
+ phba->sli4_hba.fof_eq = NULL;
+ }
+
+ /* Release OAS Completion queue */
+ if (phba->sli4_hba.oas_cq != NULL) {
+ lpfc_sli4_queue_free(phba->sli4_hba.oas_cq);
+ phba->sli4_hba.oas_cq = NULL;
+ }
+
+ /* Release OAS Work queue */
+ if (phba->sli4_hba.oas_wq != NULL) {
+ lpfc_sli4_queue_free(phba->sli4_hba.oas_wq);
+ phba->sli4_hba.oas_wq = NULL;
+ }
+ return 0;
+}
+
static struct pci_device_id lpfc_id_table[] = {
{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER,
PCI_ANY_ID, PCI_ANY_ID, },
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index 812d0cd7c86d..ed419aad2b1f 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -38,10 +38,29 @@
#include "lpfc_scsi.h"
#include "lpfc.h"
#include "lpfc_crtn.h"
+#include "lpfc_logmsg.h"
#define LPFC_MBUF_POOL_SIZE 64 /* max elements in MBUF safety pool */
#define LPFC_MEM_POOL_SIZE 64 /* max elem in non-DMA safety pool */
+#define LPFC_DEVICE_DATA_POOL_SIZE 64 /* max elements in device data pool */
+int
+lpfc_mem_alloc_active_rrq_pool_s4(struct lpfc_hba *phba) {
+ size_t bytes;
+ int max_xri = phba->sli4_hba.max_cfg_param.max_xri;
+
+ if (max_xri <= 0)
+ return -ENOMEM;
+ bytes = ((BITS_PER_LONG - 1 + max_xri) / BITS_PER_LONG) *
+ sizeof(unsigned long);
+ phba->cfg_rrq_xri_bitmap_sz = bytes;
+ phba->active_rrq_pool = mempool_create_kmalloc_pool(LPFC_MEM_POOL_SIZE,
+ bytes);
+ if (!phba->active_rrq_pool)
+ return -ENOMEM;
+ else
+ return 0;
+}
/**
* lpfc_mem_alloc - create and allocate all PCI and memory pools
@@ -146,6 +165,16 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align)
phba->lpfc_drb_pool = NULL;
}
+ if (phba->cfg_EnableXLane) {
+ phba->device_data_mem_pool = mempool_create_kmalloc_pool(
+ LPFC_DEVICE_DATA_POOL_SIZE,
+ sizeof(struct lpfc_device_data));
+ if (!phba->device_data_mem_pool)
+ goto fail_free_hrb_pool;
+ } else {
+ phba->device_data_mem_pool = NULL;
+ }
+
return 0;
fail_free_hrb_pool:
pci_pool_destroy(phba->lpfc_hrb_pool);
@@ -188,6 +217,7 @@ lpfc_mem_free(struct lpfc_hba *phba)
{
int i;
struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
+ struct lpfc_device_data *device_data;
/* Free HBQ pools */
lpfc_sli_hbqbuf_free_all(phba);
@@ -209,6 +239,10 @@ lpfc_mem_free(struct lpfc_hba *phba)
/* Free NLP memory pool */
mempool_destroy(phba->nlp_mem_pool);
phba->nlp_mem_pool = NULL;
+ if (phba->sli_rev == LPFC_SLI_REV4 && phba->active_rrq_pool) {
+ mempool_destroy(phba->active_rrq_pool);
+ phba->active_rrq_pool = NULL;
+ }
/* Free mbox memory pool */
mempool_destroy(phba->mbox_mem_pool);
@@ -227,6 +261,19 @@ lpfc_mem_free(struct lpfc_hba *phba)
pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
phba->lpfc_scsi_dma_buf_pool = NULL;
+ /* Free Device Data memory pool */
+ if (phba->device_data_mem_pool) {
+ /* Ensure all objects have been returned to the pool */
+ while (!list_empty(&phba->luns)) {
+ device_data = list_first_entry(&phba->luns,
+ struct lpfc_device_data,
+ listentry);
+ list_del(&device_data->listentry);
+ mempool_free(device_data, phba->device_data_mem_pool);
+ }
+ mempool_destroy(phba->device_data_mem_pool);
+ }
+ phba->device_data_mem_pool = NULL;
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index abc361259d6d..c342f6afd747 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -203,8 +203,6 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
int
lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
- LIST_HEAD(completions);
- LIST_HEAD(txcmplq_completions);
LIST_HEAD(abort_list);
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
@@ -216,32 +214,27 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
"Data: x%x x%x x%x\n",
ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
ndlp->nlp_rpi);
-
+ /* Clean up all fabric IOs first.*/
lpfc_fabric_abort_nport(ndlp);
- /* First check the txq */
+ /*
+ * Lock the ELS ring txcmplq for SLI3/SLI4 and build a local list
+ * of all ELS IOs that need an ABTS. The IOs need to stay on the
+ * txcmplq so that the abort operation completes them successfully.
+ */
spin_lock_irq(&phba->hbalock);
- list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
- /* Check to see if iocb matches the nport we are looking for */
- if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
- /* It matches, so deque and call compl with anp error */
- list_move_tail(&iocb->list, &completions);
- }
- }
-
- /* Next check the txcmplq */
- list_splice_init(&pring->txcmplq, &txcmplq_completions);
- spin_unlock_irq(&phba->hbalock);
-
- list_for_each_entry_safe(iocb, next_iocb, &txcmplq_completions, list) {
- /* Check to see if iocb matches the nport we are looking for */
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_lock(&pring->ring_lock);
+ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
+ /* Add to abort_list on on NDLP match. */
if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))
list_add_tail(&iocb->dlist, &abort_list);
}
- spin_lock_irq(&phba->hbalock);
- list_splice(&txcmplq_completions, &pring->txcmplq);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_unlock(&pring->ring_lock);
spin_unlock_irq(&phba->hbalock);
+ /* Abort the targeted IOs and remove them from the abort list. */
list_for_each_entry_safe(iocb, next_iocb, &abort_list, dlist) {
spin_lock_irq(&phba->hbalock);
list_del_init(&iocb->dlist);
@@ -249,9 +242,28 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
spin_unlock_irq(&phba->hbalock);
}
+ INIT_LIST_HEAD(&abort_list);
+
+ /* Now process the txq */
+ spin_lock_irq(&phba->hbalock);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_lock(&pring->ring_lock);
+
+ list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
+ /* Check to see if iocb matches the nport we are looking for */
+ if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
+ list_del_init(&iocb->list);
+ list_add_tail(&iocb->list, &abort_list);
+ }
+ }
+
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_unlock(&pring->ring_lock);
+ spin_unlock_irq(&phba->hbalock);
+
/* Cancel all the IOCBs from the completions list */
- lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
- IOERR_SLI_ABORTED);
+ lpfc_sli_cancel_iocbs(phba, &abort_list,
+ IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED);
lpfc_cancel_retry_delay_tmo(phba->pport, ndlp);
return 0;
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index b2ede05a5f0a..462453ee0bda 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -68,6 +68,17 @@ struct scsi_dif_tuple {
__be32 ref_tag; /* Target LBA or indirect LBA */
};
+static struct lpfc_rport_data *
+lpfc_rport_data_from_scsi_device(struct scsi_device *sdev)
+{
+ struct lpfc_vport *vport = (struct lpfc_vport *)sdev->host->hostdata;
+
+ if (vport->phba->cfg_EnableXLane)
+ return ((struct lpfc_device_data *)sdev->hostdata)->rport_data;
+ else
+ return (struct lpfc_rport_data *)sdev->hostdata;
+}
+
static void
lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb);
static void
@@ -304,9 +315,27 @@ lpfc_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
unsigned long new_queue_depth, old_queue_depth;
old_queue_depth = sdev->queue_depth;
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+
+ switch (reason) {
+ case SCSI_QDEPTH_DEFAULT:
+ /* change request from sysfs, fall through */
+ case SCSI_QDEPTH_RAMP_UP:
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+ break;
+ case SCSI_QDEPTH_QFULL:
+ if (scsi_track_queue_full(sdev, qdepth) == 0)
+ return sdev->queue_depth;
+
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+ "0711 detected queue full - lun queue "
+ "depth adjusted to %d.\n", sdev->queue_depth);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
new_queue_depth = sdev->queue_depth;
- rdata = sdev->hostdata;
+ rdata = lpfc_rport_data_from_scsi_device(sdev);
if (rdata)
lpfc_send_sdev_queuedepth_change_event(phba, vport,
rdata->pnode, sdev->lun,
@@ -377,50 +406,6 @@ lpfc_rampdown_queue_depth(struct lpfc_hba *phba)
}
/**
- * lpfc_rampup_queue_depth - Post RAMP_UP_QUEUE event for worker thread
- * @phba: The Hba for which this call is being executed.
- *
- * This routine post WORKER_RAMP_UP_QUEUE event for @phba vport. This routine
- * post at most 1 event every 5 minute after last_ramp_up_time or
- * last_rsrc_error_time. This routine wakes up worker thread of @phba
- * to process WORKER_RAM_DOWN_EVENT event.
- *
- * This routine should be called with no lock held.
- **/
-static inline void
-lpfc_rampup_queue_depth(struct lpfc_vport *vport,
- uint32_t queue_depth)
-{
- unsigned long flags;
- struct lpfc_hba *phba = vport->phba;
- uint32_t evt_posted;
- atomic_inc(&phba->num_cmd_success);
-
- if (vport->cfg_lun_queue_depth <= queue_depth)
- return;
- spin_lock_irqsave(&phba->hbalock, flags);
- if (time_before(jiffies,
- phba->last_ramp_up_time + QUEUE_RAMP_UP_INTERVAL) ||
- time_before(jiffies,
- phba->last_rsrc_error_time + QUEUE_RAMP_UP_INTERVAL)) {
- spin_unlock_irqrestore(&phba->hbalock, flags);
- return;
- }
- phba->last_ramp_up_time = jiffies;
- spin_unlock_irqrestore(&phba->hbalock, flags);
-
- spin_lock_irqsave(&phba->pport->work_port_lock, flags);
- evt_posted = phba->pport->work_port_events & WORKER_RAMP_UP_QUEUE;
- if (!evt_posted)
- phba->pport->work_port_events |= WORKER_RAMP_UP_QUEUE;
- spin_unlock_irqrestore(&phba->pport->work_port_lock, flags);
-
- if (!evt_posted)
- lpfc_worker_wake_up(phba);
- return;
-}
-
-/**
* lpfc_ramp_down_queue_handler - WORKER_RAMP_DOWN_QUEUE event handler
* @phba: The Hba for which this call is being executed.
*
@@ -472,41 +457,6 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
}
/**
- * lpfc_ramp_up_queue_handler - WORKER_RAMP_UP_QUEUE event handler
- * @phba: The Hba for which this call is being executed.
- *
- * This routine is called to process WORKER_RAMP_UP_QUEUE event for worker
- * thread.This routine increases queue depth for all scsi device on each vport
- * associated with @phba by 1. This routine also sets @phba num_rsrc_err and
- * num_cmd_success to zero.
- **/
-void
-lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
-{
- struct lpfc_vport **vports;
- struct Scsi_Host *shost;
- struct scsi_device *sdev;
- int i;
-
- vports = lpfc_create_vport_work_array(phba);
- if (vports != NULL)
- for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
- shost = lpfc_shost_from_vport(vports[i]);
- shost_for_each_device(sdev, shost) {
- if (vports[i]->cfg_lun_queue_depth <=
- sdev->queue_depth)
- continue;
- lpfc_change_queue_depth(sdev,
- sdev->queue_depth+1,
- SCSI_QDEPTH_RAMP_UP);
- }
- }
- lpfc_destroy_vport_work_array(phba, vports);
- atomic_set(&phba->num_rsrc_err, 0);
- atomic_set(&phba->num_cmd_success, 0);
-}
-
-/**
* lpfc_scsi_dev_block - set all scsi hosts to block state
* @phba: Pointer to HBA context object.
*
@@ -1502,7 +1452,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc,
}
/* Next check if we need to match the remote NPortID or WWPN */
- rdata = sc->device->hostdata;
+ rdata = lpfc_rport_data_from_scsi_device(sc->device);
if (rdata && rdata->pnode) {
ndlp = rdata->pnode;
@@ -3507,6 +3457,14 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
* we need to set word 4 of IOCB here
*/
iocb_cmd->un.fcpi.fcpi_parm = scsi_bufflen(scsi_cmnd);
+
+ /*
+ * If the OAS driver feature is enabled and the lun is enabled for
+ * OAS, set the oas iocb related flags.
+ */
+ if ((phba->cfg_EnableXLane) && ((struct lpfc_device_data *)
+ scsi_cmnd->device->hostdata)->oas_enabled)
+ lpfc_cmd->cur_iocbq.iocb_flag |= LPFC_IO_OAS;
return 0;
}
@@ -4021,7 +3979,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
struct lpfc_nodelist *pnode = rdata->pnode;
struct scsi_cmnd *cmd;
int result;
- struct scsi_device *tmp_sdev;
int depth;
unsigned long flags;
struct lpfc_fast_path_event *fast_path_evt;
@@ -4266,32 +4223,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
return;
}
- if (!result)
- lpfc_rampup_queue_depth(vport, queue_depth);
-
- /*
- * Check for queue full. If the lun is reporting queue full, then
- * back off the lun queue depth to prevent target overloads.
- */
- if (result == SAM_STAT_TASK_SET_FULL && pnode &&
- NLP_CHK_NODE_ACT(pnode)) {
- shost_for_each_device(tmp_sdev, shost) {
- if (tmp_sdev->id != scsi_id)
- continue;
- depth = scsi_track_queue_full(tmp_sdev,
- tmp_sdev->queue_depth-1);
- if (depth <= 0)
- continue;
- lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
- "0711 detected queue full - lun queue "
- "depth adjusted to %d.\n", depth);
- lpfc_send_sdev_queuedepth_change_event(phba, vport,
- pnode,
- tmp_sdev->lun,
- depth+1, depth);
- }
- }
-
spin_lock_irqsave(&phba->hbalock, flags);
lpfc_cmd->pCmd = NULL;
spin_unlock_irqrestore(&phba->hbalock, flags);
@@ -4492,6 +4423,8 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport,
}
piocb->ulpFCP2Rcvy = (ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) ? 1 : 0;
piocb->ulpClass = (ndlp->nlp_fcp_info & 0x0f);
+ piocb->ulpPU = 0;
+ piocb->un.fcpi.fcpi_parm = 0;
/* ulpTimeout is only one byte */
if (lpfc_cmd->timeout > 0xff) {
@@ -4691,12 +4624,13 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
{
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- struct lpfc_rport_data *rdata = cmnd->device->hostdata;
+ struct lpfc_rport_data *rdata;
struct lpfc_nodelist *ndlp;
struct lpfc_scsi_buf *lpfc_cmd;
struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
int err;
+ rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
err = fc_remote_port_chkready(rport);
if (err) {
cmnd->result = err;
@@ -4782,6 +4716,24 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
&lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB);
if (err) {
atomic_dec(&ndlp->cmd_pending);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
+ "3376 FCP could not issue IOCB err %x"
+ "FCP cmd x%x <%d/%d> "
+ "sid: x%x did: x%x oxid: x%x "
+ "Data: x%x x%x x%x x%x\n",
+ err, cmnd->cmnd[0],
+ cmnd->device ? cmnd->device->id : 0xffff,
+ cmnd->device ? cmnd->device->lun : 0xffff,
+ vport->fc_myDID, ndlp->nlp_DID,
+ phba->sli_rev == LPFC_SLI_REV4 ?
+ lpfc_cmd->cur_iocbq.sli4_xritag : 0xffff,
+ lpfc_cmd->cur_iocbq.iocb.ulpContext,
+ lpfc_cmd->cur_iocbq.iocb.ulpIoTag,
+ lpfc_cmd->cur_iocbq.iocb.ulpTimeout,
+ (uint32_t)
+ (cmnd->request->timeout / 1000));
+
+
goto out_host_busy_free_buf;
}
if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
@@ -5161,10 +5113,11 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
static int
lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd)
{
- struct lpfc_rport_data *rdata = cmnd->device->hostdata;
+ struct lpfc_rport_data *rdata;
struct lpfc_nodelist *pnode;
unsigned long later;
+ rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
if (!rdata) {
lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
"0797 Tgt Map rport failure: rdata x%p\n", rdata);
@@ -5182,7 +5135,7 @@ lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd)
if (pnode->nlp_state == NLP_STE_MAPPED_NODE)
return SUCCESS;
schedule_timeout_uninterruptible(msecs_to_jiffies(500));
- rdata = cmnd->device->hostdata;
+ rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
if (!rdata)
return FAILED;
pnode = rdata->pnode;
@@ -5254,13 +5207,14 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
{
struct Scsi_Host *shost = cmnd->device->host;
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
- struct lpfc_rport_data *rdata = cmnd->device->hostdata;
+ struct lpfc_rport_data *rdata;
struct lpfc_nodelist *pnode;
unsigned tgt_id = cmnd->device->id;
unsigned int lun_id = cmnd->device->lun;
struct lpfc_scsi_event_header scsi_event;
int status;
+ rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
if (!rdata) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
"0798 Device Reset rport failure: rdata x%p\n", rdata);
@@ -5323,13 +5277,14 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd)
{
struct Scsi_Host *shost = cmnd->device->host;
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
- struct lpfc_rport_data *rdata = cmnd->device->hostdata;
+ struct lpfc_rport_data *rdata;
struct lpfc_nodelist *pnode;
unsigned tgt_id = cmnd->device->id;
unsigned int lun_id = cmnd->device->lun;
struct lpfc_scsi_event_header scsi_event;
int status;
+ rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
if (!rdata) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
"0799 Target Reset rport failure: rdata x%p\n", rdata);
@@ -5529,11 +5484,45 @@ lpfc_slave_alloc(struct scsi_device *sdev)
uint32_t num_to_alloc = 0;
int num_allocated = 0;
uint32_t sdev_cnt;
+ struct lpfc_device_data *device_data;
+ unsigned long flags;
+ struct lpfc_name target_wwpn;
if (!rport || fc_remote_port_chkready(rport))
return -ENXIO;
- sdev->hostdata = rport->dd_data;
+ if (phba->cfg_EnableXLane) {
+
+ /*
+ * Check to see if the device data structure for the lun
+ * exists. If not, create one.
+ */
+
+ u64_to_wwn(rport->port_name, target_wwpn.u.wwn);
+ spin_lock_irqsave(&phba->devicelock, flags);
+ device_data = __lpfc_get_device_data(phba,
+ &phba->luns,
+ &vport->fc_portname,
+ &target_wwpn,
+ sdev->lun);
+ if (!device_data) {
+ spin_unlock_irqrestore(&phba->devicelock, flags);
+ device_data = lpfc_create_device_data(phba,
+ &vport->fc_portname,
+ &target_wwpn,
+ sdev->lun, true);
+ if (!device_data)
+ return -ENOMEM;
+ spin_lock_irqsave(&phba->devicelock, flags);
+ list_add_tail(&device_data->listentry, &phba->luns);
+ }
+ device_data->rport_data = rport->dd_data;
+ device_data->available = true;
+ spin_unlock_irqrestore(&phba->devicelock, flags);
+ sdev->hostdata = device_data;
+ } else {
+ sdev->hostdata = rport->dd_data;
+ }
sdev_cnt = atomic_inc_return(&phba->sdev_cnt);
/*
@@ -5623,11 +5612,344 @@ lpfc_slave_destroy(struct scsi_device *sdev)
{
struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata;
struct lpfc_hba *phba = vport->phba;
+ unsigned long flags;
+ struct lpfc_device_data *device_data = sdev->hostdata;
+
atomic_dec(&phba->sdev_cnt);
+ if ((phba->cfg_EnableXLane) && (device_data)) {
+ spin_lock_irqsave(&phba->devicelock, flags);
+ device_data->available = false;
+ if (!device_data->oas_enabled)
+ lpfc_delete_device_data(phba, device_data);
+ spin_unlock_irqrestore(&phba->devicelock, flags);
+ }
sdev->hostdata = NULL;
return;
}
+/**
+ * lpfc_create_device_data - creates and initializes device data structure for OAS
+ * @pha: Pointer to host bus adapter structure.
+ * @vport_wwpn: Pointer to vport's wwpn information
+ * @target_wwpn: Pointer to target's wwpn information
+ * @lun: Lun on target
+ * @atomic_create: Flag to indicate if memory should be allocated using the
+ * GFP_ATOMIC flag or not.
+ *
+ * This routine creates a device data structure which will contain identifying
+ * information for the device (host wwpn, target wwpn, lun), state of OAS,
+ * whether or not the corresponding lun is available by the system,
+ * and pointer to the rport data.
+ *
+ * Return codes:
+ * NULL - Error
+ * Pointer to lpfc_device_data - Success
+ **/
+struct lpfc_device_data*
+lpfc_create_device_data(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
+ struct lpfc_name *target_wwpn, uint64_t lun,
+ bool atomic_create)
+{
+
+ struct lpfc_device_data *lun_info;
+ int memory_flags;
+
+ if (unlikely(!phba) || !vport_wwpn || !target_wwpn ||
+ !(phba->cfg_EnableXLane))
+ return NULL;
+
+ /* Attempt to create the device data to contain lun info */
+
+ if (atomic_create)
+ memory_flags = GFP_ATOMIC;
+ else
+ memory_flags = GFP_KERNEL;
+ lun_info = mempool_alloc(phba->device_data_mem_pool, memory_flags);
+ if (!lun_info)
+ return NULL;
+ INIT_LIST_HEAD(&lun_info->listentry);
+ lun_info->rport_data = NULL;
+ memcpy(&lun_info->device_id.vport_wwpn, vport_wwpn,
+ sizeof(struct lpfc_name));
+ memcpy(&lun_info->device_id.target_wwpn, target_wwpn,
+ sizeof(struct lpfc_name));
+ lun_info->device_id.lun = lun;
+ lun_info->oas_enabled = false;
+ lun_info->available = false;
+ return lun_info;
+}
+
+/**
+ * lpfc_delete_device_data - frees a device data structure for OAS
+ * @pha: Pointer to host bus adapter structure.
+ * @lun_info: Pointer to device data structure to free.
+ *
+ * This routine frees the previously allocated device data structure passed.
+ *
+ **/
+void
+lpfc_delete_device_data(struct lpfc_hba *phba,
+ struct lpfc_device_data *lun_info)
+{
+
+ if (unlikely(!phba) || !lun_info ||
+ !(phba->cfg_EnableXLane))
+ return;
+
+ if (!list_empty(&lun_info->listentry))
+ list_del(&lun_info->listentry);
+ mempool_free(lun_info, phba->device_data_mem_pool);
+ return;
+}
+
+/**
+ * __lpfc_get_device_data - returns the device data for the specified lun
+ * @pha: Pointer to host bus adapter structure.
+ * @list: Point to list to search.
+ * @vport_wwpn: Pointer to vport's wwpn information
+ * @target_wwpn: Pointer to target's wwpn information
+ * @lun: Lun on target
+ *
+ * This routine searches the list passed for the specified lun's device data.
+ * This function does not hold locks, it is the responsibility of the caller
+ * to ensure the proper lock is held before calling the function.
+ *
+ * Return codes:
+ * NULL - Error
+ * Pointer to lpfc_device_data - Success
+ **/
+struct lpfc_device_data*
+__lpfc_get_device_data(struct lpfc_hba *phba, struct list_head *list,
+ struct lpfc_name *vport_wwpn,
+ struct lpfc_name *target_wwpn, uint64_t lun)
+{
+
+ struct lpfc_device_data *lun_info;
+
+ if (unlikely(!phba) || !list || !vport_wwpn || !target_wwpn ||
+ !phba->cfg_EnableXLane)
+ return NULL;
+
+ /* Check to see if the lun is already enabled for OAS. */
+
+ list_for_each_entry(lun_info, list, listentry) {
+ if ((memcmp(&lun_info->device_id.vport_wwpn, vport_wwpn,
+ sizeof(struct lpfc_name)) == 0) &&
+ (memcmp(&lun_info->device_id.target_wwpn, target_wwpn,
+ sizeof(struct lpfc_name)) == 0) &&
+ (lun_info->device_id.lun == lun))
+ return lun_info;
+ }
+
+ return NULL;
+}
+
+/**
+ * lpfc_find_next_oas_lun - searches for the next oas lun
+ * @pha: Pointer to host bus adapter structure.
+ * @vport_wwpn: Pointer to vport's wwpn information
+ * @target_wwpn: Pointer to target's wwpn information
+ * @starting_lun: Pointer to the lun to start searching for
+ * @found_vport_wwpn: Pointer to the found lun's vport wwpn information
+ * @found_target_wwpn: Pointer to the found lun's target wwpn information
+ * @found_lun: Pointer to the found lun.
+ * @found_lun_status: Pointer to status of the found lun.
+ *
+ * This routine searches the luns list for the specified lun
+ * or the first lun for the vport/target. If the vport wwpn contains
+ * a zero value then a specific vport is not specified. In this case
+ * any vport which contains the lun will be considered a match. If the
+ * target wwpn contains a zero value then a specific target is not specified.
+ * In this case any target which contains the lun will be considered a
+ * match. If the lun is found, the lun, vport wwpn, target wwpn and lun status
+ * are returned. The function will also return the next lun if available.
+ * If the next lun is not found, starting_lun parameter will be set to
+ * NO_MORE_OAS_LUN.
+ *
+ * Return codes:
+ * non-0 - Error
+ * 0 - Success
+ **/
+bool
+lpfc_find_next_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
+ struct lpfc_name *target_wwpn, uint64_t *starting_lun,
+ struct lpfc_name *found_vport_wwpn,
+ struct lpfc_name *found_target_wwpn,
+ uint64_t *found_lun,
+ uint32_t *found_lun_status)
+{
+
+ unsigned long flags;
+ struct lpfc_device_data *lun_info;
+ struct lpfc_device_id *device_id;
+ uint64_t lun;
+ bool found = false;
+
+ if (unlikely(!phba) || !vport_wwpn || !target_wwpn ||
+ !starting_lun || !found_vport_wwpn ||
+ !found_target_wwpn || !found_lun || !found_lun_status ||
+ (*starting_lun == NO_MORE_OAS_LUN) ||
+ !phba->cfg_EnableXLane)
+ return false;
+
+ lun = *starting_lun;
+ *found_lun = NO_MORE_OAS_LUN;
+ *starting_lun = NO_MORE_OAS_LUN;
+
+ /* Search for lun or the lun closet in value */
+
+ spin_lock_irqsave(&phba->devicelock, flags);
+ list_for_each_entry(lun_info, &phba->luns, listentry) {
+ if (((wwn_to_u64(vport_wwpn->u.wwn) == 0) ||
+ (memcmp(&lun_info->device_id.vport_wwpn, vport_wwpn,
+ sizeof(struct lpfc_name)) == 0)) &&
+ ((wwn_to_u64(target_wwpn->u.wwn) == 0) ||
+ (memcmp(&lun_info->device_id.target_wwpn, target_wwpn,
+ sizeof(struct lpfc_name)) == 0)) &&
+ (lun_info->oas_enabled)) {
+ device_id = &lun_info->device_id;
+ if ((!found) &&
+ ((lun == FIND_FIRST_OAS_LUN) ||
+ (device_id->lun == lun))) {
+ *found_lun = device_id->lun;
+ memcpy(found_vport_wwpn,
+ &device_id->vport_wwpn,
+ sizeof(struct lpfc_name));
+ memcpy(found_target_wwpn,
+ &device_id->target_wwpn,
+ sizeof(struct lpfc_name));
+ if (lun_info->available)
+ *found_lun_status =
+ OAS_LUN_STATUS_EXISTS;
+ else
+ *found_lun_status = 0;
+ if (phba->cfg_oas_flags & OAS_FIND_ANY_VPORT)
+ memset(vport_wwpn, 0x0,
+ sizeof(struct lpfc_name));
+ if (phba->cfg_oas_flags & OAS_FIND_ANY_TARGET)
+ memset(target_wwpn, 0x0,
+ sizeof(struct lpfc_name));
+ found = true;
+ } else if (found) {
+ *starting_lun = device_id->lun;
+ memcpy(vport_wwpn, &device_id->vport_wwpn,
+ sizeof(struct lpfc_name));
+ memcpy(target_wwpn, &device_id->target_wwpn,
+ sizeof(struct lpfc_name));
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&phba->devicelock, flags);
+ return found;
+}
+
+/**
+ * lpfc_enable_oas_lun - enables a lun for OAS operations
+ * @pha: Pointer to host bus adapter structure.
+ * @vport_wwpn: Pointer to vport's wwpn information
+ * @target_wwpn: Pointer to target's wwpn information
+ * @lun: Lun
+ *
+ * This routine enables a lun for oas operations. The routines does so by
+ * doing the following :
+ *
+ * 1) Checks to see if the device data for the lun has been created.
+ * 2) If found, sets the OAS enabled flag if not set and returns.
+ * 3) Otherwise, creates a device data structure.
+ * 4) If successfully created, indicates the device data is for an OAS lun,
+ * indicates the lun is not available and add to the list of luns.
+ *
+ * Return codes:
+ * false - Error
+ * true - Success
+ **/
+bool
+lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
+ struct lpfc_name *target_wwpn, uint64_t lun)
+{
+
+ struct lpfc_device_data *lun_info;
+ unsigned long flags;
+
+ if (unlikely(!phba) || !vport_wwpn || !target_wwpn ||
+ !phba->cfg_EnableXLane)
+ return false;
+
+ spin_lock_irqsave(&phba->devicelock, flags);
+
+ /* Check to see if the device data for the lun has been created */
+ lun_info = __lpfc_get_device_data(phba, &phba->luns, vport_wwpn,
+ target_wwpn, lun);
+ if (lun_info) {
+ if (!lun_info->oas_enabled)
+ lun_info->oas_enabled = true;
+ spin_unlock_irqrestore(&phba->devicelock, flags);
+ return true;
+ }
+
+ /* Create an lun info structure and add to list of luns */
+ lun_info = lpfc_create_device_data(phba, vport_wwpn, target_wwpn, lun,
+ false);
+ if (lun_info) {
+ lun_info->oas_enabled = true;
+ lun_info->available = false;
+ list_add_tail(&lun_info->listentry, &phba->luns);
+ spin_unlock_irqrestore(&phba->devicelock, flags);
+ return true;
+ }
+ spin_unlock_irqrestore(&phba->devicelock, flags);
+ return false;
+}
+
+/**
+ * lpfc_disable_oas_lun - disables a lun for OAS operations
+ * @pha: Pointer to host bus adapter structure.
+ * @vport_wwpn: Pointer to vport's wwpn information
+ * @target_wwpn: Pointer to target's wwpn information
+ * @lun: Lun
+ *
+ * This routine disables a lun for oas operations. The routines does so by
+ * doing the following :
+ *
+ * 1) Checks to see if the device data for the lun is created.
+ * 2) If present, clears the flag indicating this lun is for OAS.
+ * 3) If the lun is not available by the system, the device data is
+ * freed.
+ *
+ * Return codes:
+ * false - Error
+ * true - Success
+ **/
+bool
+lpfc_disable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
+ struct lpfc_name *target_wwpn, uint64_t lun)
+{
+
+ struct lpfc_device_data *lun_info;
+ unsigned long flags;
+
+ if (unlikely(!phba) || !vport_wwpn || !target_wwpn ||
+ !phba->cfg_EnableXLane)
+ return false;
+
+ spin_lock_irqsave(&phba->devicelock, flags);
+
+ /* Check to see if the lun is available. */
+ lun_info = __lpfc_get_device_data(phba,
+ &phba->luns, vport_wwpn,
+ target_wwpn, lun);
+ if (lun_info) {
+ lun_info->oas_enabled = false;
+ if (!lun_info->available)
+ lpfc_delete_device_data(phba, lun_info);
+ spin_unlock_irqrestore(&phba->devicelock, flags);
+ return true;
+ }
+
+ spin_unlock_irqrestore(&phba->devicelock, flags);
+ return false;
+}
struct scsi_host_template lpfc_template = {
.module = THIS_MODULE,
diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h
index 852ff7def493..0120bfccf50b 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.h
+++ b/drivers/scsi/lpfc/lpfc_scsi.h
@@ -41,6 +41,20 @@ struct lpfc_rport_data {
struct lpfc_nodelist *pnode; /* Pointer to the node structure. */
};
+struct lpfc_device_id {
+ struct lpfc_name vport_wwpn;
+ struct lpfc_name target_wwpn;
+ uint64_t lun;
+};
+
+struct lpfc_device_data {
+ struct list_head listentry;
+ struct lpfc_rport_data *rport_data;
+ struct lpfc_device_id device_id;
+ bool oas_enabled;
+ bool available;
+};
+
struct fcp_rsp {
uint32_t rspRsvd1; /* FC Word 0, byte 0:3 */
uint32_t rspRsvd2; /* FC Word 1, byte 0:3 */
@@ -166,3 +180,7 @@ struct lpfc_scsi_buf {
#define LPFC_SCSI_DMA_EXT_SIZE 264
#define LPFC_BPL_SIZE 1024
#define MDAC_DIRECT_CMD 0x22
+
+#define FIND_FIRST_OAS_LUN 0
+#define NO_MORE_OAS_LUN -1
+#define NOT_OAS_ENABLED_LUN NO_MORE_OAS_LUN
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 8f580fda443f..6bb51f8e3c1b 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -635,7 +635,7 @@ lpfc_clr_rrq_active(struct lpfc_hba *phba,
if (!ndlp)
goto out;
- if (test_and_clear_bit(xritag, ndlp->active_rrqs.xri_bitmap)) {
+ if (test_and_clear_bit(xritag, ndlp->active_rrqs_xri_bitmap)) {
rrq->send_rrq = 0;
rrq->xritag = 0;
rrq->rrq_stop_time = 0;
@@ -678,7 +678,8 @@ lpfc_handle_rrq_active(struct lpfc_hba *phba)
next_time = rrq->rrq_stop_time;
}
spin_unlock_irqrestore(&phba->hbalock, iflags);
- if (!list_empty(&phba->active_rrq_list))
+ if ((!list_empty(&phba->active_rrq_list)) &&
+ (!(phba->pport->load_flag & FC_UNLOADING)))
mod_timer(&phba->rrq_tmr, next_time);
list_for_each_entry_safe(rrq, nextrrq, &send_rrq, list) {
list_del(&rrq->list);
@@ -792,7 +793,9 @@ lpfc_cleanup_wt_rrqs(struct lpfc_hba *phba)
list_del(&rrq->list);
lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
}
- if (!list_empty(&phba->active_rrq_list))
+ if ((!list_empty(&phba->active_rrq_list)) &&
+ (!(phba->pport->load_flag & FC_UNLOADING)))
+
mod_timer(&phba->rrq_tmr, next_time);
}
@@ -813,7 +816,9 @@ lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
{
if (!ndlp)
return 0;
- if (test_bit(xritag, ndlp->active_rrqs.xri_bitmap))
+ if (!ndlp->active_rrqs_xri_bitmap)
+ return 0;
+ if (test_bit(xritag, ndlp->active_rrqs_xri_bitmap))
return 1;
else
return 0;
@@ -863,7 +868,10 @@ lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
if (ndlp->vport && (ndlp->vport->load_flag & FC_UNLOADING))
goto out;
- if (test_and_set_bit(xritag, ndlp->active_rrqs.xri_bitmap))
+ if (!ndlp->active_rrqs_xri_bitmap)
+ goto out;
+
+ if (test_and_set_bit(xritag, ndlp->active_rrqs_xri_bitmap))
goto out;
spin_unlock_irqrestore(&phba->hbalock, iflags);
@@ -1318,7 +1326,8 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if ((unlikely(pring->ringno == LPFC_ELS_RING)) &&
(piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
- (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) {
+ (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN) &&
+ (!(piocb->vport->load_flag & FC_UNLOADING))) {
if (!piocb->vport)
BUG();
else
@@ -4971,12 +4980,19 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)
LPFC_QUEUE_REARM);
} while (++fcp_eqidx < phba->cfg_fcp_io_channel);
}
+
+ if (phba->cfg_EnableXLane)
+ lpfc_sli4_cq_release(phba->sli4_hba.oas_cq, LPFC_QUEUE_REARM);
+
if (phba->sli4_hba.hba_eq) {
for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_io_channel;
fcp_eqidx++)
lpfc_sli4_eq_release(phba->sli4_hba.hba_eq[fcp_eqidx],
LPFC_QUEUE_REARM);
}
+
+ if (phba->cfg_fof)
+ lpfc_sli4_eq_release(phba->sli4_hba.fof_eq, LPFC_QUEUE_REARM);
}
/**
@@ -8032,7 +8048,8 @@ lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba)
struct lpfc_vector_map_info *cpup;
int chann, cpu;
- if (phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_CPU) {
+ if (phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_CPU
+ && phba->cfg_fcp_io_channel > 1) {
cpu = smp_processor_id();
if (cpu < phba->sli4_hba.num_present_cpu) {
cpup = phba->sli4_hba.cpu_map;
@@ -8250,6 +8267,14 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
bf_set(wqe_ebde_cnt, &wqe->fcp_iwrite.wqe_com, 0);
bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpPU);
bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 1);
+ if (iocbq->iocb_flag & LPFC_IO_OAS) {
+ bf_set(wqe_oas, &wqe->fcp_iwrite.wqe_com, 1);
+ if (phba->cfg_XLanePriority) {
+ bf_set(wqe_ccpe, &wqe->fcp_iwrite.wqe_com, 1);
+ bf_set(wqe_ccp, &wqe->fcp_iwrite.wqe_com,
+ (phba->cfg_XLanePriority << 1));
+ }
+ }
break;
case CMD_FCP_IREAD64_CR:
/* word3 iocb=iotag wqe=payload_offset_len */
@@ -8271,6 +8296,14 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
bf_set(wqe_ebde_cnt, &wqe->fcp_iread.wqe_com, 0);
bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpPU);
bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 1);
+ if (iocbq->iocb_flag & LPFC_IO_OAS) {
+ bf_set(wqe_oas, &wqe->fcp_iread.wqe_com, 1);
+ if (phba->cfg_XLanePriority) {
+ bf_set(wqe_ccpe, &wqe->fcp_iread.wqe_com, 1);
+ bf_set(wqe_ccp, &wqe->fcp_iread.wqe_com,
+ (phba->cfg_XLanePriority << 1));
+ }
+ }
break;
case CMD_FCP_ICMND64_CR:
/* word3 iocb=iotag wqe=payload_offset_len */
@@ -8291,6 +8324,14 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
bf_set(wqe_ebde_cnt, &wqe->fcp_icmd.wqe_com, 0);
bf_set(wqe_erp, &wqe->fcp_icmd.wqe_com,
iocbq->iocb.ulpFCP2Rcvy);
+ if (iocbq->iocb_flag & LPFC_IO_OAS) {
+ bf_set(wqe_oas, &wqe->fcp_icmd.wqe_com, 1);
+ if (phba->cfg_XLanePriority) {
+ bf_set(wqe_ccpe, &wqe->fcp_icmd.wqe_com, 1);
+ bf_set(wqe_ccp, &wqe->fcp_icmd.wqe_com,
+ (phba->cfg_XLanePriority << 1));
+ }
+ }
break;
case CMD_GEN_REQUEST64_CR:
/* For this command calculate the xmit length of the
@@ -8523,6 +8564,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
{
struct lpfc_sglq *sglq;
union lpfc_wqe wqe;
+ struct lpfc_queue *wq;
struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number];
if (piocb->sli4_xritag == NO_XRI) {
@@ -8575,11 +8617,14 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
return IOCB_ERROR;
if ((piocb->iocb_flag & LPFC_IO_FCP) ||
- (piocb->iocb_flag & LPFC_USE_FCPWQIDX)) {
- if (unlikely(!phba->sli4_hba.fcp_wq))
- return IOCB_ERROR;
- if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[piocb->fcp_wqidx],
- &wqe))
+ (piocb->iocb_flag & LPFC_USE_FCPWQIDX)) {
+ if (!phba->cfg_EnableXLane || (!(piocb->iocb_flag &
+ LPFC_IO_OAS))) {
+ wq = phba->sli4_hba.fcp_wq[piocb->fcp_wqidx];
+ } else {
+ wq = phba->sli4_hba.oas_wq;
+ }
+ if (lpfc_sli4_wq_put(wq, &wqe))
return IOCB_ERROR;
} else {
if (unlikely(!phba->sli4_hba.els_wq))
@@ -8669,12 +8714,20 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
if (phba->sli_rev == LPFC_SLI_REV4) {
if (piocb->iocb_flag & LPFC_IO_FCP) {
- if (unlikely(!phba->sli4_hba.fcp_wq))
- return IOCB_ERROR;
- idx = lpfc_sli4_scmd_to_wqidx_distr(phba);
- piocb->fcp_wqidx = idx;
- ring_number = MAX_SLI3_CONFIGURED_RINGS + idx;
-
+ if (!phba->cfg_EnableXLane || (!(piocb->iocb_flag &
+ LPFC_IO_OAS))) {
+ if (unlikely(!phba->sli4_hba.fcp_wq))
+ return IOCB_ERROR;
+ idx = lpfc_sli4_scmd_to_wqidx_distr(phba);
+ piocb->fcp_wqidx = idx;
+ ring_number = MAX_SLI3_CONFIGURED_RINGS + idx;
+ } else {
+ if (unlikely(!phba->sli4_hba.oas_wq))
+ return IOCB_ERROR;
+ idx = 0;
+ piocb->fcp_wqidx = 0;
+ ring_number = LPFC_FCP_OAS_RING;
+ }
pring = &phba->sli.ring[ring_number];
spin_lock_irqsave(&pring->ring_lock, iflags);
rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb,
@@ -12132,6 +12185,175 @@ lpfc_sli4_eq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq)
lpfc_sli4_eq_release(eq, LPFC_QUEUE_REARM);
}
+
+/**
+ * lpfc_sli4_fof_handle_eqe - Process a Flash Optimized Fabric event queue
+ * entry
+ * @phba: Pointer to HBA context object.
+ * @eqe: Pointer to fast-path event queue entry.
+ *
+ * This routine process a event queue entry from the Flash Optimized Fabric
+ * event queue. It will check the MajorCode and MinorCode to determine this
+ * is for a completion event on a completion queue, if not, an error shall be
+ * logged and just return. Otherwise, it will get to the corresponding
+ * completion queue and process all the entries on the completion queue, rearm
+ * the completion queue, and then return.
+ **/
+static void
+lpfc_sli4_fof_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe)
+{
+ struct lpfc_queue *cq;
+ struct lpfc_cqe *cqe;
+ bool workposted = false;
+ uint16_t cqid;
+ int ecount = 0;
+
+ if (unlikely(bf_get_le32(lpfc_eqe_major_code, eqe) != 0)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "9147 Not a valid completion "
+ "event: majorcode=x%x, minorcode=x%x\n",
+ bf_get_le32(lpfc_eqe_major_code, eqe),
+ bf_get_le32(lpfc_eqe_minor_code, eqe));
+ return;
+ }
+
+ /* Get the reference to the corresponding CQ */
+ cqid = bf_get_le32(lpfc_eqe_resource_id, eqe);
+
+ /* Next check for OAS */
+ cq = phba->sli4_hba.oas_cq;
+ if (unlikely(!cq)) {
+ if (phba->sli.sli_flag & LPFC_SLI_ACTIVE)
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "9148 OAS completion queue "
+ "does not exist\n");
+ return;
+ }
+
+ if (unlikely(cqid != cq->queue_id)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "9149 Miss-matched fast-path compl "
+ "queue id: eqcqid=%d, fcpcqid=%d\n",
+ cqid, cq->queue_id);
+ return;
+ }
+
+ /* Process all the entries to the OAS CQ */
+ while ((cqe = lpfc_sli4_cq_get(cq))) {
+ workposted |= lpfc_sli4_fp_handle_wcqe(phba, cq, cqe);
+ if (!(++ecount % cq->entry_repost))
+ lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM);
+ }
+
+ /* Track the max number of CQEs processed in 1 EQ */
+ if (ecount > cq->CQ_max_cqe)
+ cq->CQ_max_cqe = ecount;
+
+ /* Catch the no cq entry condition */
+ if (unlikely(ecount == 0))
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "9153 No entry from fast-path completion "
+ "queue fcpcqid=%d\n", cq->queue_id);
+
+ /* In any case, flash and re-arm the CQ */
+ lpfc_sli4_cq_release(cq, LPFC_QUEUE_REARM);
+
+ /* wake up worker thread if there are works to be done */
+ if (workposted)
+ lpfc_worker_wake_up(phba);
+}
+
+/**
+ * lpfc_sli4_fof_intr_handler - HBA interrupt handler to SLI-4 device
+ * @irq: Interrupt number.
+ * @dev_id: The device context pointer.
+ *
+ * This function is directly called from the PCI layer as an interrupt
+ * service routine when device with SLI-4 interface spec is enabled with
+ * MSI-X multi-message interrupt mode and there is a Flash Optimized Fabric
+ * IOCB ring event in the HBA. However, when the device is enabled with either
+ * MSI or Pin-IRQ interrupt mode, this function is called as part of the
+ * device-level interrupt handler. When the PCI slot is in error recovery
+ * or the HBA is undergoing initialization, the interrupt handler will not
+ * process the interrupt. The Flash Optimized Fabric ring event are handled in
+ * the intrrupt context. This function is called without any lock held.
+ * It gets the hbalock to access and update SLI data structures. Note that,
+ * the EQ to CQ are one-to-one map such that the EQ index is
+ * equal to that of CQ index.
+ *
+ * This function returns IRQ_HANDLED when interrupt is handled else it
+ * returns IRQ_NONE.
+ **/
+irqreturn_t
+lpfc_sli4_fof_intr_handler(int irq, void *dev_id)
+{
+ struct lpfc_hba *phba;
+ struct lpfc_fcp_eq_hdl *fcp_eq_hdl;
+ struct lpfc_queue *eq;
+ struct lpfc_eqe *eqe;
+ unsigned long iflag;
+ int ecount = 0;
+ uint32_t eqidx;
+
+ /* Get the driver's phba structure from the dev_id */
+ fcp_eq_hdl = (struct lpfc_fcp_eq_hdl *)dev_id;
+ phba = fcp_eq_hdl->phba;
+ eqidx = fcp_eq_hdl->idx;
+
+ if (unlikely(!phba))
+ return IRQ_NONE;
+
+ /* Get to the EQ struct associated with this vector */
+ eq = phba->sli4_hba.fof_eq;
+ if (unlikely(!eq))
+ return IRQ_NONE;
+
+ /* Check device state for handling interrupt */
+ if (unlikely(lpfc_intr_state_check(phba))) {
+ eq->EQ_badstate++;
+ /* Check again for link_state with lock held */
+ spin_lock_irqsave(&phba->hbalock, iflag);
+ if (phba->link_state < LPFC_LINK_DOWN)
+ /* Flush, clear interrupt, and rearm the EQ */
+ lpfc_sli4_eq_flush(phba, eq);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
+ return IRQ_NONE;
+ }
+
+ /*
+ * Process all the event on FCP fast-path EQ
+ */
+ while ((eqe = lpfc_sli4_eq_get(eq))) {
+ lpfc_sli4_fof_handle_eqe(phba, eqe);
+ if (!(++ecount % eq->entry_repost))
+ lpfc_sli4_eq_release(eq, LPFC_QUEUE_NOARM);
+ eq->EQ_processed++;
+ }
+
+ /* Track the max number of EQEs processed in 1 intr */
+ if (ecount > eq->EQ_max_eqe)
+ eq->EQ_max_eqe = ecount;
+
+
+ if (unlikely(ecount == 0)) {
+ eq->EQ_no_entry++;
+
+ if (phba->intr_type == MSIX)
+ /* MSI-X treated interrupt served as no EQ share INT */
+ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+ "9145 MSI-X interrupt with no EQE\n");
+ else {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "9146 ISR interrupt with no EQE\n");
+ /* Non MSI-X treated on interrupt as EQ share INT */
+ return IRQ_NONE;
+ }
+ }
+ /* Always clear and re-arm the fast-path EQ */
+ lpfc_sli4_eq_release(eq, LPFC_QUEUE_REARM);
+ return IRQ_HANDLED;
+}
+
/**
* lpfc_sli4_hba_intr_handler - HBA interrupt handler to SLI-4 device
* @irq: Interrupt number.
@@ -12287,6 +12509,13 @@ lpfc_sli4_intr_handler(int irq, void *dev_id)
hba_handled |= true;
}
+ if (phba->cfg_fof) {
+ hba_irq_rc = lpfc_sli4_fof_intr_handler(irq,
+ &phba->sli4_hba.fcp_eq_hdl[0]);
+ if (hba_irq_rc == IRQ_HANDLED)
+ hba_handled |= true;
+ }
+
return (hba_handled == true) ? IRQ_HANDLED : IRQ_NONE;
} /* lpfc_sli4_intr_handler */
@@ -16544,7 +16773,7 @@ lpfc_drain_txq(struct lpfc_hba *phba)
{
LIST_HEAD(completions);
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
- struct lpfc_iocbq *piocbq = 0;
+ struct lpfc_iocbq *piocbq = NULL;
unsigned long iflags = 0;
char *fail_msg = NULL;
struct lpfc_sglq *sglq;
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 6b0f2478706e..6f04080f4ea8 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -78,6 +78,8 @@ struct lpfc_iocbq {
#define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */
#define LPFC_FIP_ELS_ID_SHIFT 14
+#define LPFC_IO_OAS 0x10000 /* OAS FCP IO */
+
uint32_t drvrTimeout; /* driver timeout in seconds */
uint32_t fcp_wqidx; /* index to FCP work queue */
struct lpfc_vport *vport;/* virtual port pointer */
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index 298c8cd1a89d..9b8cda866176 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -39,6 +39,10 @@
#define LPFC_FCP_IO_CHAN_MIN 1
#define LPFC_FCP_IO_CHAN_MAX 16
+/* Number of channels used for Flash Optimized Fabric (FOF) operations */
+
+#define LPFC_FOF_IO_CHAN_NUM 1
+
/*
* Provide the default FCF Record attributes used by the driver
* when nonFIP mode is configured and there is no other default
@@ -399,6 +403,7 @@ struct lpfc_pc_sli4_params {
uint32_t if_page_sz;
uint32_t rq_db_window;
uint32_t loopbk_scope;
+ uint32_t oas_supported;
uint32_t eq_pages_max;
uint32_t eqe_size;
uint32_t cq_pages_max;
@@ -439,6 +444,8 @@ struct lpfc_sli4_lnk_info {
uint8_t lnk_no;
};
+#define LPFC_SLI4_HANDLER_CNT (LPFC_FCP_IO_CHAN_MAX+ \
+ LPFC_FOF_IO_CHAN_NUM)
#define LPFC_SLI4_HANDLER_NAME_SZ 16
/* Used for IRQ vector to CPU mapping */
@@ -507,7 +514,7 @@ struct lpfc_sli4_hba {
struct lpfc_register sli_intf;
struct lpfc_pc_sli4_params pc_sli4_params;
struct msix_entry *msix_entries;
- uint8_t handler_name[LPFC_FCP_IO_CHAN_MAX][LPFC_SLI4_HANDLER_NAME_SZ];
+ uint8_t handler_name[LPFC_SLI4_HANDLER_CNT][LPFC_SLI4_HANDLER_NAME_SZ];
struct lpfc_fcp_eq_hdl *fcp_eq_hdl; /* FCP per-WQ handle */
/* Pointers to the constructed SLI4 queues */
@@ -527,6 +534,17 @@ struct lpfc_sli4_hba {
uint32_t ulp0_mode; /* ULP0 protocol mode */
uint32_t ulp1_mode; /* ULP1 protocol mode */
+ struct lpfc_queue *fof_eq; /* Flash Optimized Fabric Event queue */
+
+ /* Optimized Access Storage specific queues/structures */
+
+ struct lpfc_queue *oas_cq; /* OAS completion queue */
+ struct lpfc_queue *oas_wq; /* OAS Work queue */
+ struct lpfc_sli_ring *oas_ring;
+ uint64_t oas_next_lun;
+ uint8_t oas_next_tgt_wwpn[8];
+ uint8_t oas_next_vpt_wwpn[8];
+
/* Setup information for various queue parameters */
int eq_esize;
int eq_ecount;
@@ -589,6 +607,7 @@ struct lpfc_sli4_hba {
struct lpfc_vector_map_info *cpu_map;
uint16_t num_online_cpu;
uint16_t num_present_cpu;
+ uint16_t curr_disp_cpu;
};
enum lpfc_sge_type {
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index e3094c4e143b..e32cbec70324 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.43"
+#define LPFC_DRIVER_VERSION "8.3.45"
#define LPFC_DRIVER_NAME "lpfc"
/* Used for SLI 2/3 */
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 816db12ef5d5..b7770516f4c2 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -531,13 +531,6 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy)
int target = 0;
int ldrv_num = 0; /* logical drive number */
-
- /*
- * filter the internal and ioctl commands
- */
- if((cmd->cmnd[0] == MEGA_INTERNAL_CMD))
- return (scb_t *)cmd->host_scribble;
-
/*
* We know what channels our logical drives are on - mega_find_card()
*/
@@ -1439,19 +1432,22 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status)
cmdid = completed[i];
- if( cmdid == CMDID_INT_CMDS ) { /* internal command */
+ /*
+ * Only free SCBs for the commands coming down from the
+ * mid-layer, not for which were issued internally
+ *
+ * For internal command, restore the status returned by the
+ * firmware so that user can interpret it.
+ */
+ if (cmdid == CMDID_INT_CMDS) {
scb = &adapter->int_scb;
- cmd = scb->cmd;
- mbox = (mbox_t *)scb->raw_mbox;
- /*
- * Internal command interface do not fire the extended
- * passthru or 64-bit passthru
- */
- pthru = scb->pthru;
+ list_del_init(&scb->list);
+ scb->state = SCB_FREE;
- }
- else {
+ adapter->int_status = status;
+ complete(&adapter->int_waitq);
+ } else {
scb = &adapter->scb_list[cmdid];
/*
@@ -1640,25 +1636,7 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status)
cmd->result |= (DID_BAD_TARGET << 16)|status;
}
- /*
- * Only free SCBs for the commands coming down from the
- * mid-layer, not for which were issued internally
- *
- * For internal command, restore the status returned by the
- * firmware so that user can interpret it.
- */
- if( cmdid == CMDID_INT_CMDS ) { /* internal command */
- cmd->result = status;
-
- /*
- * Remove the internal command from the pending list
- */
- list_del_init(&scb->list);
- scb->state = SCB_FREE;
- }
- else {
- mega_free_scb(adapter, scb);
- }
+ mega_free_scb(adapter, scb);
/* Add Scsi_Command to end of completed queue */
list_add_tail(SCSI_LIST(cmd), &adapter->completed_list);
@@ -4133,23 +4111,15 @@ mega_internal_dev_inquiry(adapter_t *adapter, u8 ch, u8 tgt,
* The last argument is the address of the passthru structure if the command
* to be fired is a passthru command
*
- * lockscope specifies whether the caller has already acquired the lock. Of
- * course, the caller must know which lock we are talking about.
- *
* Note: parameter 'pthru' is null for non-passthru commands.
*/
static int
mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru)
{
- Scsi_Cmnd *scmd;
- struct scsi_device *sdev;
+ unsigned long flags;
scb_t *scb;
int rval;
- scmd = scsi_allocate_command(GFP_KERNEL);
- if (!scmd)
- return -ENOMEM;
-
/*
* The internal commands share one command id and hence are
* serialized. This is so because we want to reserve maximum number of
@@ -4160,73 +4130,45 @@ mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru)
scb = &adapter->int_scb;
memset(scb, 0, sizeof(scb_t));
- sdev = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
- scmd->device = sdev;
-
- memset(adapter->int_cdb, 0, sizeof(adapter->int_cdb));
- scmd->cmnd = adapter->int_cdb;
- scmd->device->host = adapter->host;
- scmd->host_scribble = (void *)scb;
- scmd->cmnd[0] = MEGA_INTERNAL_CMD;
-
- scb->state |= SCB_ACTIVE;
- scb->cmd = scmd;
+ scb->idx = CMDID_INT_CMDS;
+ scb->state |= SCB_ACTIVE | SCB_PENDQ;
memcpy(scb->raw_mbox, mc, sizeof(megacmd_t));
/*
* Is it a passthru command
*/
- if( mc->cmd == MEGA_MBOXCMD_PASSTHRU ) {
-
+ if (mc->cmd == MEGA_MBOXCMD_PASSTHRU)
scb->pthru = pthru;
- }
-
- scb->idx = CMDID_INT_CMDS;
- megaraid_queue_lck(scmd, mega_internal_done);
+ spin_lock_irqsave(&adapter->lock, flags);
+ list_add_tail(&scb->list, &adapter->pending_list);
+ /*
+ * Check if the HBA is in quiescent state, e.g., during a
+ * delete logical drive opertion. If it is, don't run
+ * the pending_list.
+ */
+ if (atomic_read(&adapter->quiescent) == 0)
+ mega_runpendq(adapter);
+ spin_unlock_irqrestore(&adapter->lock, flags);
wait_for_completion(&adapter->int_waitq);
- rval = scmd->result;
- mc->status = scmd->result;
- kfree(sdev);
+ mc->status = rval = adapter->int_status;
/*
* Print a debug message for all failed commands. Applications can use
* this information.
*/
- if( scmd->result && trace_level ) {
+ if (rval && trace_level) {
printk("megaraid: cmd [%x, %x, %x] status:[%x]\n",
- mc->cmd, mc->opcode, mc->subopcode, scmd->result);
+ mc->cmd, mc->opcode, mc->subopcode, rval);
}
mutex_unlock(&adapter->int_mtx);
-
- scsi_free_command(GFP_KERNEL, scmd);
-
return rval;
}
-
-/**
- * mega_internal_done()
- * @scmd - internal scsi command
- *
- * Callback routine for internal commands.
- */
-static void
-mega_internal_done(Scsi_Cmnd *scmd)
-{
- adapter_t *adapter;
-
- adapter = (adapter_t *)scmd->device->host->hostdata;
-
- complete(&adapter->int_waitq);
-
-}
-
-
static struct scsi_host_template megaraid_template = {
.module = THIS_MODULE,
.name = "MegaRAID",
diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
index 4d0ce4e78dfd..508d65e5a518 100644
--- a/drivers/scsi/megaraid.h
+++ b/drivers/scsi/megaraid.h
@@ -853,10 +853,10 @@ typedef struct {
u8 sglen; /* f/w supported scatter-gather list length */
- unsigned char int_cdb[MAX_COMMAND_SIZE];
scb_t int_scb;
struct mutex int_mtx; /* To synchronize the internal
commands */
+ int int_status; /* status of internal cmd */
struct completion int_waitq; /* wait queue for internal
cmds */
@@ -1004,7 +1004,6 @@ static int mega_del_logdrv(adapter_t *, int);
static int mega_do_del_logdrv(adapter_t *, int);
static void mega_get_max_sgl(adapter_t *);
static int mega_internal_command(adapter_t *, megacmd_t *, mega_passthru *);
-static void mega_internal_done(Scsi_Cmnd *);
static int mega_support_cluster(adapter_t *);
#endif
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c
index dfffd0f37916..a70692779a16 100644
--- a/drivers/scsi/megaraid/megaraid_mm.c
+++ b/drivers/scsi/megaraid/megaraid_mm.c
@@ -486,6 +486,8 @@ mimd_to_kioc(mimd_t __user *umimd, mraid_mmadp_t *adp, uioc_t *kioc)
pthru32->dataxferaddr = kioc->buf_paddr;
if (kioc->data_dir & UIOC_WR) {
+ if (pthru32->dataxferlen > kioc->xferlen)
+ return -EINVAL;
if (copy_from_user(kioc->buf_vaddr, kioc->user_data,
pthru32->dataxferlen)) {
return (-EFAULT);
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 34452ea386ac..32166c2c7854 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -33,9 +33,9 @@
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "06.700.06.00-rc1"
-#define MEGASAS_RELDATE "Aug. 31, 2013"
-#define MEGASAS_EXT_VERSION "Sat. Aug. 31 17:00:00 PDT 2013"
+#define MEGASAS_VERSION "06.803.01.00-rc1"
+#define MEGASAS_RELDATE "Mar. 10, 2014"
+#define MEGASAS_EXT_VERSION "Mon. Mar. 10 17:00:00 PDT 2014"
/*
* Device IDs
@@ -48,6 +48,7 @@
#define PCI_DEVICE_ID_LSI_SAS0073SKINNY 0x0073
#define PCI_DEVICE_ID_LSI_SAS0071SKINNY 0x0071
#define PCI_DEVICE_ID_LSI_FUSION 0x005b
+#define PCI_DEVICE_ID_LSI_PLASMA 0x002f
#define PCI_DEVICE_ID_LSI_INVADER 0x005d
#define PCI_DEVICE_ID_LSI_FURY 0x005f
@@ -559,7 +560,8 @@ struct megasas_ctrl_info {
u8 PCIE:1;
u8 iSCSI:1;
u8 SAS_3G:1;
- u8 reserved_0:4;
+ u8 SRIOV:1;
+ u8 reserved_0:3;
u8 reserved_1[6];
u8 port_count;
u64 port_addr[8];
@@ -839,7 +841,12 @@ struct megasas_ctrl_info {
struct { /*7A4h */
#if defined(__BIG_ENDIAN_BITFIELD)
- u32 reserved:11;
+ u32 reserved:5;
+ u32 activePassive:2;
+ u32 supportConfigAutoBalance:1;
+ u32 mpio:1;
+ u32 supportDataLDonSSCArray:1;
+ u32 supportPointInTimeProgress:1;
u32 supportUnevenSpans:1;
u32 dedicatedHotSparesLimited:1;
u32 headlessMode:1;
@@ -886,7 +893,12 @@ struct megasas_ctrl_info {
u32 supportUnevenSpans:1;
- u32 reserved:11;
+ u32 supportPointInTimeProgress:1;
+ u32 supportDataLDonSSCArray:1;
+ u32 mpio:1;
+ u32 supportConfigAutoBalance:1;
+ u32 activePassive:2;
+ u32 reserved:5;
#endif
} adapterOperations2;
@@ -914,8 +926,14 @@ struct megasas_ctrl_info {
} cluster;
char clusterId[16]; /*7D4h */
+ struct {
+ u8 maxVFsSupported; /*0x7E4*/
+ u8 numVFsEnabled; /*0x7E5*/
+ u8 requestorId; /*0x7E6 0:PF, 1:VF1, 2:VF2*/
+ u8 reserved; /*0x7E7*/
+ } iov;
- u8 pad[0x800-0x7E4]; /*7E4 */
+ u8 pad[0x800-0x7E8]; /*0x7E8 pad to 2k */
} __packed;
/*
@@ -986,7 +1004,9 @@ struct megasas_ctrl_info {
#define MFI_OB_INTR_STATUS_MASK 0x00000002
#define MFI_POLL_TIMEOUT_SECS 60
-
+#define MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF (5 * HZ)
+#define MEGASAS_OCR_SETTLE_TIME_VF (1000 * 30)
+#define MEGASAS_ROUTINE_WAIT_TIME_VF 300
#define MFI_REPLY_1078_MESSAGE_INTERRUPT 0x80000000
#define MFI_REPLY_GEN2_MESSAGE_INTERRUPT 0x00000001
#define MFI_GEN2_ENABLE_INTERRUPT_MASK (0x00000001 | 0x00000004)
@@ -1347,9 +1367,15 @@ struct megasas_cmd;
union megasas_evt_class_locale {
struct {
+#ifndef __BIG_ENDIAN_BITFIELD
u16 locale;
u8 reserved;
s8 class;
+#else
+ s8 class;
+ u8 reserved;
+ u16 locale;
+#endif
} __attribute__ ((packed)) members;
u32 word;
@@ -1523,6 +1549,12 @@ struct megasas_instance {
dma_addr_t producer_h;
u32 *consumer;
dma_addr_t consumer_h;
+ struct MR_LD_VF_AFFILIATION *vf_affiliation;
+ dma_addr_t vf_affiliation_h;
+ struct MR_LD_VF_AFFILIATION_111 *vf_affiliation_111;
+ dma_addr_t vf_affiliation_111_h;
+ struct MR_CTRL_HB_HOST_MEM *hb_host_mem;
+ dma_addr_t hb_host_mem_h;
u32 *reply_queue;
dma_addr_t reply_queue_h;
@@ -1598,10 +1630,73 @@ struct megasas_instance {
unsigned long bar;
long reset_flags;
struct mutex reset_mutex;
+ struct timer_list sriov_heartbeat_timer;
+ char skip_heartbeat_timer_del;
+ u8 requestorId;
+ u64 initiator_sas_address;
+ u64 ld_sas_address[64];
+ char PlasmaFW111;
+ char mpio;
int throttlequeuedepth;
u8 mask_interrupts;
u8 is_imr;
};
+struct MR_LD_VF_MAP {
+ u32 size;
+ union MR_LD_REF ref;
+ u8 ldVfCount;
+ u8 reserved[6];
+ u8 policy[1];
+};
+
+struct MR_LD_VF_AFFILIATION {
+ u32 size;
+ u8 ldCount;
+ u8 vfCount;
+ u8 thisVf;
+ u8 reserved[9];
+ struct MR_LD_VF_MAP map[1];
+};
+
+/* Plasma 1.11 FW backward compatibility structures */
+#define IOV_111_OFFSET 0x7CE
+#define MAX_VIRTUAL_FUNCTIONS 8
+
+struct IOV_111 {
+ u8 maxVFsSupported;
+ u8 numVFsEnabled;
+ u8 requestorId;
+ u8 reserved[5];
+};
+
+struct MR_LD_VF_MAP_111 {
+ u8 targetId;
+ u8 reserved[3];
+ u8 policy[MAX_VIRTUAL_FUNCTIONS];
+};
+
+struct MR_LD_VF_AFFILIATION_111 {
+ u8 vdCount;
+ u8 vfCount;
+ u8 thisVf;
+ u8 reserved[5];
+ struct MR_LD_VF_MAP_111 map[MAX_LOGICAL_DRIVES];
+};
+
+struct MR_CTRL_HB_HOST_MEM {
+ struct {
+ u32 fwCounter; /* Firmware heart beat counter */
+ struct {
+ u32 debugmode:1; /* 1=Firmware is in debug mode.
+ Heart beat will not be updated. */
+ u32 reserved:31;
+ } debug;
+ u32 reserved_fw[6];
+ u32 driverCounter; /* Driver heart beat counter. 0x20 */
+ u32 reserved_driver[7];
+ } HB;
+ u8 pad[0x400-0x40];
+};
enum {
MEGASAS_HBA_OPERATIONAL = 0,
@@ -1609,6 +1704,7 @@ enum {
MEGASAS_ADPRESET_SM_FW_RESET_SUCCESS = 2,
MEGASAS_ADPRESET_SM_OPERATIONAL = 3,
MEGASAS_HW_CRITICAL_ERROR = 4,
+ MEGASAS_ADPRESET_SM_POLLING = 5,
MEGASAS_ADPRESET_INPROG_SIGN = 0xDEADDEAD,
};
@@ -1728,7 +1824,7 @@ MR_BuildRaidContext(struct megasas_instance *instance,
struct IO_REQUEST_INFO *io_info,
struct RAID_CONTEXT *pRAID_Context,
struct MR_FW_RAID_MAP_ALL *map, u8 **raidLUN);
-u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map);
+u8 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map);
struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_FW_RAID_MAP_ALL *map);
u16 MR_ArPdGet(u32 ar, u32 arm, struct MR_FW_RAID_MAP_ALL *map);
u16 MR_LdSpanArrayGet(u32 ld, u32 span, struct MR_FW_RAID_MAP_ALL *map);
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 3b7ad10497fe..d84d02c2aad9 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -18,7 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* FILE: megaraid_sas_base.c
- * Version : 06.700.06.00-rc1
+ * Version : 06.803.01.00-rc1
*
* Authors: LSI Corporation
* Sreenivas Bagalkote
@@ -75,6 +75,10 @@ static unsigned int msix_vectors;
module_param(msix_vectors, int, S_IRUGO);
MODULE_PARM_DESC(msix_vectors, "MSI-X max vector count. Default: Set by FW");
+static int allow_vf_ioctls;
+module_param(allow_vf_ioctls, int, S_IRUGO);
+MODULE_PARM_DESC(allow_vf_ioctls, "Allow ioctls in SR-IOV VF mode. Default: 0");
+
static int throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH;
module_param(throttlequeuedepth, int, S_IRUGO);
MODULE_PARM_DESC(throttlequeuedepth,
@@ -122,6 +126,8 @@ static struct pci_device_id megasas_pci_table[] = {
/* xscale IOP */
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FUSION)},
/* Fusion */
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_PLASMA)},
+ /* Plasma */
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INVADER)},
/* Invader */
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FURY)},
@@ -132,7 +138,7 @@ static struct pci_device_id megasas_pci_table[] = {
MODULE_DEVICE_TABLE(pci, megasas_pci_table);
static int megasas_mgmt_majorno;
-static struct megasas_mgmt_info megasas_mgmt_info;
+struct megasas_mgmt_info megasas_mgmt_info;
static struct fasync_struct *megasas_async_queue;
static DEFINE_MUTEX(megasas_async_queue_mutex);
@@ -171,10 +177,15 @@ megasas_get_map_info(struct megasas_instance *instance);
int
megasas_sync_map_info(struct megasas_instance *instance);
int
-wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd);
+wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
+ int seconds);
void megasas_reset_reply_desc(struct megasas_instance *instance);
-int megasas_reset_fusion(struct Scsi_Host *shost);
+int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout);
void megasas_fusion_ocr_wq(struct work_struct *work);
+static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
+ int initial);
+int megasas_check_mpio_paths(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd);
void
megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
@@ -224,6 +235,7 @@ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
cmd->scmd = NULL;
cmd->frame_count = 0;
if ((instance->pdev->device != PCI_DEVICE_ID_LSI_FUSION) &&
+ (instance->pdev->device != PCI_DEVICE_ID_LSI_PLASMA) &&
(instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER) &&
(instance->pdev->device != PCI_DEVICE_ID_LSI_FURY) &&
(reset_devices))
@@ -877,6 +889,7 @@ extern struct megasas_instance_template megasas_instance_template_fusion;
int
megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
{
+ int seconds;
struct megasas_header *frame_hdr = &cmd->frame->hdr;
@@ -891,13 +904,18 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
/*
* Wait for cmd_status to change
*/
- return wait_and_poll(instance, cmd);
+ if (instance->requestorId)
+ seconds = MEGASAS_ROUTINE_WAIT_TIME_VF;
+ else
+ seconds = MFI_POLL_TIMEOUT_SECS;
+ return wait_and_poll(instance, cmd, seconds);
}
/**
* megasas_issue_blocked_cmd - Synchronous wrapper around regular FW cmds
* @instance: Adapter soft state
* @cmd: Command to be issued
+ * @timeout: Timeout in seconds
*
* This function waits on an event for the command to be returned from ISR.
* Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
@@ -905,13 +923,20 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
*/
static int
megasas_issue_blocked_cmd(struct megasas_instance *instance,
- struct megasas_cmd *cmd)
+ struct megasas_cmd *cmd, int timeout)
{
+ int ret = 0;
cmd->cmd_status = ENODATA;
instance->instancet->issue_dcmd(instance, cmd);
-
- wait_event(instance->int_cmd_wait_q, cmd->cmd_status != ENODATA);
+ if (timeout) {
+ ret = wait_event_timeout(instance->int_cmd_wait_q,
+ cmd->cmd_status != ENODATA, timeout * HZ);
+ if (!ret)
+ return 1;
+ } else
+ wait_event(instance->int_cmd_wait_q,
+ cmd->cmd_status != ENODATA);
return 0;
}
@@ -920,18 +945,20 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
* megasas_issue_blocked_abort_cmd - Aborts previously issued cmd
* @instance: Adapter soft state
* @cmd_to_abort: Previously issued cmd to be aborted
+ * @timeout: Timeout in seconds
*
- * MFI firmware can abort previously issued AEN command (automatic event
+ * MFI firmware can abort previously issued AEN comamnd (automatic event
* notification). The megasas_issue_blocked_abort_cmd() issues such abort
* cmd and waits for return status.
* Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
*/
static int
megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
- struct megasas_cmd *cmd_to_abort)
+ struct megasas_cmd *cmd_to_abort, int timeout)
{
struct megasas_cmd *cmd;
struct megasas_abort_frame *abort_fr;
+ int ret = 0;
cmd = megasas_get_cmd(instance);
@@ -957,10 +984,18 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
instance->instancet->issue_dcmd(instance, cmd);
- /*
- * Wait for this cmd to complete
- */
- wait_event(instance->abort_cmd_wait_q, cmd->cmd_status != 0xFF);
+ if (timeout) {
+ ret = wait_event_timeout(instance->abort_cmd_wait_q,
+ cmd->cmd_status != ENODATA, timeout * HZ);
+ if (!ret) {
+ dev_err(&instance->pdev->dev, "Command timedout"
+ "from %s\n", __func__);
+ return 1;
+ }
+ } else
+ wait_event(instance->abort_cmd_wait_q,
+ cmd->cmd_status != ENODATA);
+
cmd->sync_cmd = 0;
megasas_return_cmd(instance, cmd);
@@ -1514,9 +1549,23 @@ megasas_queue_command_lck(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd
spin_lock_irqsave(&instance->hba_lock, flags);
+ /* Check for an mpio path and adjust behavior */
+ if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
+ if (megasas_check_mpio_paths(instance, scmd) ==
+ (DID_RESET << 16)) {
+ spin_unlock_irqrestore(&instance->hba_lock, flags);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ } else {
+ spin_unlock_irqrestore(&instance->hba_lock, flags);
+ scmd->result = DID_NO_CONNECT << 16;
+ done(scmd);
+ return 0;
+ }
+ }
+
if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
spin_unlock_irqrestore(&instance->hba_lock, flags);
- scmd->result = DID_ERROR << 16;
+ scmd->result = DID_NO_CONNECT << 16;
done(scmd);
return 0;
}
@@ -1641,9 +1690,14 @@ void megaraid_sas_kill_hba(struct megasas_instance *instance)
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
writel(MFI_STOP_ADP, &instance->reg_set->doorbell);
+ /* Flush */
+ readl(&instance->reg_set->doorbell);
+ if (instance->mpio && instance->requestorId)
+ memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
} else {
writel(MFI_STOP_ADP, &instance->reg_set->inbound_doorbell);
}
@@ -1730,6 +1784,25 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
megasas_check_and_restore_queue_depth(instance);
}
+/**
+ * megasas_start_timer - Initializes a timer object
+ * @instance: Adapter soft state
+ * @timer: timer object to be initialized
+ * @fn: timer function
+ * @interval: time interval between timer function call
+ *
+ */
+void megasas_start_timer(struct megasas_instance *instance,
+ struct timer_list *timer,
+ void *fn, unsigned long interval)
+{
+ init_timer(timer);
+ timer->expires = jiffies + interval;
+ timer->data = (unsigned long)instance;
+ timer->function = fn;
+ add_timer(timer);
+}
+
static void
megasas_internal_reset_defer_cmds(struct megasas_instance *instance);
@@ -1752,6 +1825,295 @@ void megasas_do_ocr(struct megasas_instance *instance)
process_fw_state_change_wq(&instance->work_init);
}
+/* This function will get the current SR-IOV LD/VF affiliation */
+static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
+ int initial)
+{
+ struct megasas_cmd *cmd;
+ struct megasas_dcmd_frame *dcmd;
+ struct MR_LD_VF_AFFILIATION *new_affiliation = NULL;
+ struct MR_LD_VF_AFFILIATION_111 *new_affiliation_111 = NULL;
+ struct MR_LD_VF_MAP *newmap = NULL, *savedmap = NULL;
+ dma_addr_t new_affiliation_h;
+ dma_addr_t new_affiliation_111_h;
+ int ld, retval = 0;
+ u8 thisVf;
+
+ cmd = megasas_get_cmd(instance);
+
+ if (!cmd) {
+ printk(KERN_DEBUG "megasas: megasas_get_ld_vf_"
+ "affiliation: Failed to get cmd for scsi%d.\n",
+ instance->host->host_no);
+ return -ENOMEM;
+ }
+
+ dcmd = &cmd->frame->dcmd;
+
+ if (!instance->vf_affiliation && !instance->vf_affiliation_111) {
+ printk(KERN_WARNING "megasas: SR-IOV: Couldn't get LD/VF "
+ "affiliation for scsi%d.\n", instance->host->host_no);
+ megasas_return_cmd(instance, cmd);
+ return -ENOMEM;
+ }
+
+ if (initial)
+ if (instance->PlasmaFW111)
+ memset(instance->vf_affiliation_111, 0,
+ sizeof(struct MR_LD_VF_AFFILIATION_111));
+ else
+ memset(instance->vf_affiliation, 0,
+ (MAX_LOGICAL_DRIVES + 1) *
+ sizeof(struct MR_LD_VF_AFFILIATION));
+ else {
+ if (instance->PlasmaFW111)
+ new_affiliation_111 =
+ pci_alloc_consistent(instance->pdev,
+ sizeof(struct MR_LD_VF_AFFILIATION_111),
+ &new_affiliation_111_h);
+ else
+ new_affiliation =
+ pci_alloc_consistent(instance->pdev,
+ (MAX_LOGICAL_DRIVES + 1) *
+ sizeof(struct MR_LD_VF_AFFILIATION),
+ &new_affiliation_h);
+ if (!new_affiliation && !new_affiliation_111) {
+ printk(KERN_DEBUG "megasas: SR-IOV: Couldn't allocate "
+ "memory for new affiliation for scsi%d.\n",
+ instance->host->host_no);
+ megasas_return_cmd(instance, cmd);
+ return -ENOMEM;
+ }
+ if (instance->PlasmaFW111)
+ memset(new_affiliation_111, 0,
+ sizeof(struct MR_LD_VF_AFFILIATION_111));
+ else
+ memset(new_affiliation, 0, (MAX_LOGICAL_DRIVES + 1) *
+ sizeof(struct MR_LD_VF_AFFILIATION));
+ }
+
+ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+ dcmd->cmd = MFI_CMD_DCMD;
+ dcmd->cmd_status = 0xFF;
+ dcmd->sge_count = 1;
+ dcmd->flags = MFI_FRAME_DIR_BOTH;
+ dcmd->timeout = 0;
+ dcmd->pad_0 = 0;
+ if (instance->PlasmaFW111) {
+ dcmd->data_xfer_len = sizeof(struct MR_LD_VF_AFFILIATION_111);
+ dcmd->opcode = MR_DCMD_LD_VF_MAP_GET_ALL_LDS_111;
+ } else {
+ dcmd->data_xfer_len = (MAX_LOGICAL_DRIVES + 1) *
+ sizeof(struct MR_LD_VF_AFFILIATION);
+ dcmd->opcode = MR_DCMD_LD_VF_MAP_GET_ALL_LDS;
+ }
+
+ if (initial) {
+ if (instance->PlasmaFW111)
+ dcmd->sgl.sge32[0].phys_addr =
+ instance->vf_affiliation_111_h;
+ else
+ dcmd->sgl.sge32[0].phys_addr =
+ instance->vf_affiliation_h;
+ } else {
+ if (instance->PlasmaFW111)
+ dcmd->sgl.sge32[0].phys_addr = new_affiliation_111_h;
+ else
+ dcmd->sgl.sge32[0].phys_addr = new_affiliation_h;
+ }
+ if (instance->PlasmaFW111)
+ dcmd->sgl.sge32[0].length =
+ sizeof(struct MR_LD_VF_AFFILIATION_111);
+ else
+ dcmd->sgl.sge32[0].length = (MAX_LOGICAL_DRIVES + 1) *
+ sizeof(struct MR_LD_VF_AFFILIATION);
+
+ printk(KERN_WARNING "megasas: SR-IOV: Getting LD/VF affiliation for "
+ "scsi%d\n", instance->host->host_no);
+
+ megasas_issue_blocked_cmd(instance, cmd, 0);
+
+ if (dcmd->cmd_status) {
+ printk(KERN_WARNING "megasas: SR-IOV: LD/VF affiliation DCMD"
+ " failed with status 0x%x for scsi%d.\n",
+ dcmd->cmd_status, instance->host->host_no);
+ retval = 1; /* Do a scan if we couldn't get affiliation */
+ goto out;
+ }
+
+ if (!initial) {
+ if (instance->PlasmaFW111) {
+ if (!new_affiliation_111->vdCount) {
+ printk(KERN_WARNING "megasas: SR-IOV: Got new "
+ "LD/VF affiliation for passive path "
+ "for scsi%d.\n",
+ instance->host->host_no);
+ retval = 1;
+ goto out;
+ }
+ thisVf = new_affiliation_111->thisVf;
+ for (ld = 0 ; ld < new_affiliation_111->vdCount; ld++)
+ if (instance->vf_affiliation_111->map[ld].policy[thisVf] != new_affiliation_111->map[ld].policy[thisVf]) {
+ printk(KERN_WARNING "megasas: SR-IOV: "
+ "Got new LD/VF affiliation "
+ "for scsi%d.\n",
+ instance->host->host_no);
+ memcpy(instance->vf_affiliation_111,
+ new_affiliation_111,
+ sizeof(struct MR_LD_VF_AFFILIATION_111));
+ retval = 1;
+ goto out;
+ }
+ } else {
+ if (!new_affiliation->ldCount) {
+ printk(KERN_WARNING "megasas: SR-IOV: Got new "
+ "LD/VF affiliation for passive "
+ "path for scsi%d.\n",
+ instance->host->host_no);
+ retval = 1;
+ goto out;
+ }
+ newmap = new_affiliation->map;
+ savedmap = instance->vf_affiliation->map;
+ thisVf = new_affiliation->thisVf;
+ for (ld = 0 ; ld < new_affiliation->ldCount; ld++) {
+ if (savedmap->policy[thisVf] !=
+ newmap->policy[thisVf]) {
+ printk(KERN_WARNING "megasas: SR-IOV: "
+ "Got new LD/VF affiliation "
+ "for scsi%d.\n",
+ instance->host->host_no);
+ memcpy(instance->vf_affiliation,
+ new_affiliation,
+ new_affiliation->size);
+ retval = 1;
+ goto out;
+ }
+ savedmap = (struct MR_LD_VF_MAP *)
+ ((unsigned char *)savedmap +
+ savedmap->size);
+ newmap = (struct MR_LD_VF_MAP *)
+ ((unsigned char *)newmap +
+ newmap->size);
+ }
+ }
+ }
+out:
+ if (new_affiliation) {
+ if (instance->PlasmaFW111)
+ pci_free_consistent(instance->pdev,
+ sizeof(struct MR_LD_VF_AFFILIATION_111),
+ new_affiliation_111,
+ new_affiliation_111_h);
+ else
+ pci_free_consistent(instance->pdev,
+ (MAX_LOGICAL_DRIVES + 1) *
+ sizeof(struct MR_LD_VF_AFFILIATION),
+ new_affiliation, new_affiliation_h);
+ }
+ megasas_return_cmd(instance, cmd);
+
+ return retval;
+}
+
+/* This function will tell FW to start the SR-IOV heartbeat */
+int megasas_sriov_start_heartbeat(struct megasas_instance *instance,
+ int initial)
+{
+ struct megasas_cmd *cmd;
+ struct megasas_dcmd_frame *dcmd;
+ int retval = 0;
+
+ cmd = megasas_get_cmd(instance);
+
+ if (!cmd) {
+ printk(KERN_DEBUG "megasas: megasas_sriov_start_heartbeat: "
+ "Failed to get cmd for scsi%d.\n",
+ instance->host->host_no);
+ return -ENOMEM;
+ }
+
+ dcmd = &cmd->frame->dcmd;
+
+ if (initial) {
+ instance->hb_host_mem =
+ pci_alloc_consistent(instance->pdev,
+ sizeof(struct MR_CTRL_HB_HOST_MEM),
+ &instance->hb_host_mem_h);
+ if (!instance->hb_host_mem) {
+ printk(KERN_DEBUG "megasas: SR-IOV: Couldn't allocate"
+ " memory for heartbeat host memory for "
+ "scsi%d.\n", instance->host->host_no);
+ retval = -ENOMEM;
+ goto out;
+ }
+ memset(instance->hb_host_mem, 0,
+ sizeof(struct MR_CTRL_HB_HOST_MEM));
+ }
+
+ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+ dcmd->mbox.s[0] = sizeof(struct MR_CTRL_HB_HOST_MEM);
+ dcmd->cmd = MFI_CMD_DCMD;
+ dcmd->cmd_status = 0xFF;
+ dcmd->sge_count = 1;
+ dcmd->flags = MFI_FRAME_DIR_BOTH;
+ dcmd->timeout = 0;
+ dcmd->pad_0 = 0;
+ dcmd->data_xfer_len = sizeof(struct MR_CTRL_HB_HOST_MEM);
+ dcmd->opcode = MR_DCMD_CTRL_SHARED_HOST_MEM_ALLOC;
+ dcmd->sgl.sge32[0].phys_addr = instance->hb_host_mem_h;
+ dcmd->sgl.sge32[0].length = sizeof(struct MR_CTRL_HB_HOST_MEM);
+
+ printk(KERN_WARNING "megasas: SR-IOV: Starting heartbeat for scsi%d\n",
+ instance->host->host_no);
+
+ if (!megasas_issue_polled(instance, cmd)) {
+ retval = 0;
+ } else {
+ printk(KERN_WARNING "megasas: SR-IOV: MR_DCMD_CTRL_SHARED_HOST"
+ "_MEM_ALLOC DCMD timed out for scsi%d\n",
+ instance->host->host_no);
+ retval = 1;
+ goto out;
+ }
+
+
+ if (dcmd->cmd_status) {
+ printk(KERN_WARNING "megasas: SR-IOV: MR_DCMD_CTRL_SHARED_HOST"
+ "_MEM_ALLOC DCMD failed with status 0x%x for scsi%d\n",
+ dcmd->cmd_status,
+ instance->host->host_no);
+ retval = 1;
+ goto out;
+ }
+
+out:
+ megasas_return_cmd(instance, cmd);
+
+ return retval;
+}
+
+/* Handler for SR-IOV heartbeat */
+void megasas_sriov_heartbeat_handler(unsigned long instance_addr)
+{
+ struct megasas_instance *instance =
+ (struct megasas_instance *)instance_addr;
+
+ if (instance->hb_host_mem->HB.fwCounter !=
+ instance->hb_host_mem->HB.driverCounter) {
+ instance->hb_host_mem->HB.driverCounter =
+ instance->hb_host_mem->HB.fwCounter;
+ mod_timer(&instance->sriov_heartbeat_timer,
+ jiffies + MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
+ } else {
+ printk(KERN_WARNING "megasas: SR-IOV: Heartbeat never "
+ "completed for scsi%d\n", instance->host->host_no);
+ schedule_work(&instance->work_init);
+ }
+}
+
/**
* megasas_wait_for_outstanding - Wait for all outstanding cmds
* @instance: Adapter soft state
@@ -2014,9 +2376,10 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
* First wait for all commands to complete
*/
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
- ret = megasas_reset_fusion(scmd->device->host);
+ ret = megasas_reset_fusion(scmd->device->host, 1);
else
ret = megasas_generic_reset(scmd);
@@ -2731,6 +3094,8 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_FUSION) ||
(instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_PLASMA) ||
+ (instance->pdev->device ==
PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_FURY)) {
@@ -2755,6 +3120,8 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_FUSION) ||
(instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_PLASMA) ||
+ (instance->pdev->device ==
PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_FURY)) {
@@ -2780,6 +3147,8 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
(instance->pdev->device
== PCI_DEVICE_ID_LSI_FUSION) ||
(instance->pdev->device
+ == PCI_DEVICE_ID_LSI_PLASMA) ||
+ (instance->pdev->device
== PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device
== PCI_DEVICE_ID_LSI_FURY)) {
@@ -2788,6 +3157,8 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
if ((instance->pdev->device ==
PCI_DEVICE_ID_LSI_FUSION) ||
(instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_PLASMA) ||
+ (instance->pdev->device ==
PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_FURY)) {
@@ -3014,6 +3385,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
cmd->frame->io.context = cpu_to_le32(cmd->index);
cmd->frame->io.pad_0 = 0;
if ((instance->pdev->device != PCI_DEVICE_ID_LSI_FUSION) &&
+ (instance->pdev->device != PCI_DEVICE_ID_LSI_PLASMA) &&
(instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER) &&
(instance->pdev->device != PCI_DEVICE_ID_LSI_FURY) &&
(reset_devices))
@@ -3620,6 +3992,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
struct megasas_ctrl_info *ctrl_info;
unsigned long bar_list;
int i, loop, fw_msix_count = 0;
+ struct IOV_111 *iovPtr;
/* Find first memory bar */
bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM);
@@ -3642,6 +4015,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
switch (instance->pdev->device) {
case PCI_DEVICE_ID_LSI_FUSION:
+ case PCI_DEVICE_ID_LSI_PLASMA:
case PCI_DEVICE_ID_LSI_INVADER:
case PCI_DEVICE_ID_LSI_FURY:
instance->instancet = &megasas_instance_template_fusion;
@@ -3696,7 +4070,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
scratch_pad_2 = readl
(&instance->reg_set->outbound_scratch_pad_2);
/* Check max MSI-X vectors */
- if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) {
+ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA)) {
instance->msix_vectors = (scratch_pad_2
& MR_MAX_REPLY_QUEUES_OFFSET) + 1;
fw_msix_count = instance->msix_vectors;
@@ -3763,7 +4138,10 @@ static int megasas_init_fw(struct megasas_instance *instance)
memset(instance->pd_list, 0 ,
(MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)));
- megasas_get_pd_list(instance);
+ if (megasas_get_pd_list(instance) < 0) {
+ printk(KERN_ERR "megasas: failed to get PD list\n");
+ goto fail_init_adapter;
+ }
memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
if (megasas_ld_list_query(instance,
@@ -3807,6 +4185,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
/* adapterOperations2 are converted into CPU arch*/
le32_to_cpus((u32 *)&ctrl_info->adapterOperations2);
+ instance->mpio = ctrl_info->adapterOperations2.mpio;
instance->UnevenSpanSupport =
ctrl_info->adapterOperations2.supportUnevenSpans;
if (instance->UnevenSpanSupport) {
@@ -3819,6 +4198,20 @@ static int megasas_init_fw(struct megasas_instance *instance)
fusion->fast_path_io = 0;
}
+ if (ctrl_info->host_interface.SRIOV) {
+ if (!ctrl_info->adapterOperations2.activePassive)
+ instance->PlasmaFW111 = 1;
+
+ if (!instance->PlasmaFW111)
+ instance->requestorId =
+ ctrl_info->iov.requestorId;
+ else {
+ iovPtr = (struct IOV_111 *)((unsigned char *)ctrl_info + IOV_111_OFFSET);
+ instance->requestorId = iovPtr->requestorId;
+ }
+ printk(KERN_WARNING "megaraid_sas: I am VF "
+ "requestorId %d\n", instance->requestorId);
+ }
}
instance->max_sectors_per_req = instance->max_num_sge *
PAGE_SIZE / 512;
@@ -3851,6 +4244,17 @@ static int megasas_init_fw(struct megasas_instance *instance)
tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
(unsigned long)instance);
+ /* Launch SR-IOV heartbeat timer */
+ if (instance->requestorId) {
+ if (!megasas_sriov_start_heartbeat(instance, 1))
+ megasas_start_timer(instance,
+ &instance->sriov_heartbeat_timer,
+ megasas_sriov_heartbeat_handler,
+ MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
+ else
+ instance->skip_heartbeat_timer_del = 1;
+ }
+
return 0;
fail_init_adapter:
@@ -3933,16 +4337,19 @@ megasas_get_seq_num(struct megasas_instance *instance,
dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(el_info_h);
dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct megasas_evt_log_info));
- megasas_issue_blocked_cmd(instance, cmd);
-
- /*
- * Copy the data back into callers buffer
- */
- eli->newest_seq_num = le32_to_cpu(el_info->newest_seq_num);
- eli->oldest_seq_num = le32_to_cpu(el_info->oldest_seq_num);
- eli->clear_seq_num = le32_to_cpu(el_info->clear_seq_num);
- eli->shutdown_seq_num = le32_to_cpu(el_info->shutdown_seq_num);
- eli->boot_seq_num = le32_to_cpu(el_info->boot_seq_num);
+ if (megasas_issue_blocked_cmd(instance, cmd, 30))
+ dev_err(&instance->pdev->dev, "Command timedout"
+ "from %s\n", __func__);
+ else {
+ /*
+ * Copy the data back into callers buffer
+ */
+ eli->newest_seq_num = le32_to_cpu(el_info->newest_seq_num);
+ eli->oldest_seq_num = le32_to_cpu(el_info->oldest_seq_num);
+ eli->clear_seq_num = le32_to_cpu(el_info->clear_seq_num);
+ eli->shutdown_seq_num = le32_to_cpu(el_info->shutdown_seq_num);
+ eli->boot_seq_num = le32_to_cpu(el_info->boot_seq_num);
+ }
pci_free_consistent(instance->pdev, sizeof(struct megasas_evt_log_info),
el_info, el_info_h);
@@ -4018,7 +4425,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
instance->aen_cmd->abort_aen = 1;
ret_val = megasas_issue_blocked_abort_cmd(instance,
instance->
- aen_cmd);
+ aen_cmd, 30);
if (ret_val) {
printk(KERN_DEBUG "megasas: Failed to abort "
@@ -4160,6 +4567,7 @@ static int megasas_io_attach(struct megasas_instance *instance)
/* Fusion only supports host reset */
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
host->hostt->eh_device_reset_handler = NULL;
@@ -4197,6 +4605,19 @@ megasas_set_dma_mask(struct pci_dev *pdev)
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)
goto fail_set_dma_mask;
}
+ /*
+ * Ensure that all data structures are allocated in 32-bit
+ * memory.
+ */
+ if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) {
+ /* Try 32bit DMA mask and 32 bit Consistent dma mask */
+ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
+ && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
+ dev_info(&pdev->dev, "set 32bit DMA mask"
+ "and 32 bit consistent mask\n");
+ else
+ goto fail_set_dma_mask;
+ }
return 0;
@@ -4212,7 +4633,7 @@ fail_set_dma_mask:
static int megasas_probe_one(struct pci_dev *pdev,
const struct pci_device_id *id)
{
- int rval, pos, i, j;
+ int rval, pos, i, j, cpu;
struct Scsi_Host *host;
struct megasas_instance *instance;
u16 control = 0;
@@ -4272,6 +4693,7 @@ static int megasas_probe_one(struct pci_dev *pdev,
switch (instance->pdev->device) {
case PCI_DEVICE_ID_LSI_FUSION:
+ case PCI_DEVICE_ID_LSI_PLASMA:
case PCI_DEVICE_ID_LSI_INVADER:
case PCI_DEVICE_ID_LSI_FURY:
{
@@ -4368,6 +4790,7 @@ static int megasas_probe_one(struct pci_dev *pdev,
instance->UnevenSpanSupport = 0;
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq);
@@ -4380,12 +4803,33 @@ static int megasas_probe_one(struct pci_dev *pdev,
if (megasas_init_fw(instance))
goto fail_init_mfi;
+ if (instance->requestorId) {
+ if (instance->PlasmaFW111) {
+ instance->vf_affiliation_111 =
+ pci_alloc_consistent(pdev, sizeof(struct MR_LD_VF_AFFILIATION_111),
+ &instance->vf_affiliation_111_h);
+ if (!instance->vf_affiliation_111)
+ printk(KERN_WARNING "megasas: Can't allocate "
+ "memory for VF affiliation buffer\n");
+ } else {
+ instance->vf_affiliation =
+ pci_alloc_consistent(pdev,
+ (MAX_LOGICAL_DRIVES + 1) *
+ sizeof(struct MR_LD_VF_AFFILIATION),
+ &instance->vf_affiliation_h);
+ if (!instance->vf_affiliation)
+ printk(KERN_WARNING "megasas: Can't allocate "
+ "memory for VF affiliation buffer\n");
+ }
+ }
+
retry_irq_register:
/*
* Register IRQ
*/
if (instance->msix_vectors) {
- for (i = 0 ; i < instance->msix_vectors; i++) {
+ cpu = cpumask_first(cpu_online_mask);
+ for (i = 0; i < instance->msix_vectors; i++) {
instance->irq_context[i].instance = instance;
instance->irq_context[i].MSIxIndex = i;
if (request_irq(instance->msixentry[i].vector,
@@ -4394,14 +4838,22 @@ retry_irq_register:
&instance->irq_context[i])) {
printk(KERN_DEBUG "megasas: Failed to "
"register IRQ for vector %d.\n", i);
- for (j = 0 ; j < i ; j++)
+ for (j = 0; j < i; j++) {
+ irq_set_affinity_hint(
+ instance->msixentry[j].vector, NULL);
free_irq(
instance->msixentry[j].vector,
&instance->irq_context[j]);
+ }
/* Retry irq register for IO_APIC */
instance->msix_vectors = 0;
goto retry_irq_register;
}
+ if (irq_set_affinity_hint(instance->msixentry[i].vector,
+ get_cpu_mask(cpu)))
+ dev_err(&instance->pdev->dev, "Error setting"
+ "affinity hint for cpu %d\n", cpu);
+ cpu = cpumask_next(cpu, cpu_online_mask);
}
} else {
instance->irq_context[0].instance = instance;
@@ -4455,13 +4907,17 @@ retry_irq_register:
instance->instancet->disable_intr(instance);
if (instance->msix_vectors)
- for (i = 0 ; i < instance->msix_vectors; i++)
+ for (i = 0; i < instance->msix_vectors; i++) {
+ irq_set_affinity_hint(
+ instance->msixentry[i].vector, NULL);
free_irq(instance->msixentry[i].vector,
&instance->irq_context[i]);
+ }
else
free_irq(instance->pdev->irq, &instance->irq_context[0]);
fail_irq:
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
megasas_release_fusion(instance);
@@ -4522,7 +4978,9 @@ static void megasas_flush_cache(struct megasas_instance *instance)
dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_CACHE_FLUSH);
dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
- megasas_issue_blocked_cmd(instance, cmd);
+ if (megasas_issue_blocked_cmd(instance, cmd, 30))
+ dev_err(&instance->pdev->dev, "Command timedout"
+ " from %s\n", __func__);
megasas_return_cmd(instance, cmd);
@@ -4549,10 +5007,11 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
return;
if (instance->aen_cmd)
- megasas_issue_blocked_abort_cmd(instance, instance->aen_cmd);
+ megasas_issue_blocked_abort_cmd(instance,
+ instance->aen_cmd, 30);
if (instance->map_update_cmd)
megasas_issue_blocked_abort_cmd(instance,
- instance->map_update_cmd);
+ instance->map_update_cmd, 30);
dcmd = &cmd->frame->dcmd;
memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
@@ -4566,7 +5025,9 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
dcmd->data_xfer_len = 0;
dcmd->opcode = cpu_to_le32(opcode);
- megasas_issue_blocked_cmd(instance, cmd);
+ if (megasas_issue_blocked_cmd(instance, cmd, 30))
+ dev_err(&instance->pdev->dev, "Command timedout"
+ "from %s\n", __func__);
megasas_return_cmd(instance, cmd);
@@ -4590,6 +5051,10 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
host = instance->host;
instance->unload = 1;
+ /* Shutdown SR-IOV heartbeat timer */
+ if (instance->requestorId && !instance->skip_heartbeat_timer_del)
+ del_timer_sync(&instance->sriov_heartbeat_timer);
+
megasas_flush_cache(instance);
megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN);
@@ -4606,9 +5071,12 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
instance->instancet->disable_intr(instance);
if (instance->msix_vectors)
- for (i = 0 ; i < instance->msix_vectors; i++)
+ for (i = 0; i < instance->msix_vectors; i++) {
+ irq_set_affinity_hint(
+ instance->msixentry[i].vector, NULL);
free_irq(instance->msixentry[i].vector,
&instance->irq_context[i]);
+ }
else
free_irq(instance->pdev->irq, &instance->irq_context[0]);
if (instance->msix_vectors)
@@ -4629,7 +5097,7 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
static int
megasas_resume(struct pci_dev *pdev)
{
- int rval, i, j;
+ int rval, i, j, cpu;
struct Scsi_Host *host;
struct megasas_instance *instance;
@@ -4673,6 +5141,7 @@ megasas_resume(struct pci_dev *pdev)
switch (instance->pdev->device) {
case PCI_DEVICE_ID_LSI_FUSION:
+ case PCI_DEVICE_ID_LSI_PLASMA:
case PCI_DEVICE_ID_LSI_INVADER:
case PCI_DEVICE_ID_LSI_FURY:
{
@@ -4701,6 +5170,7 @@ megasas_resume(struct pci_dev *pdev)
* Register IRQ
*/
if (instance->msix_vectors) {
+ cpu = cpumask_first(cpu_online_mask);
for (i = 0 ; i < instance->msix_vectors; i++) {
instance->irq_context[i].instance = instance;
instance->irq_context[i].MSIxIndex = i;
@@ -4710,12 +5180,21 @@ megasas_resume(struct pci_dev *pdev)
&instance->irq_context[i])) {
printk(KERN_DEBUG "megasas: Failed to "
"register IRQ for vector %d.\n", i);
- for (j = 0 ; j < i ; j++)
+ for (j = 0; j < i; j++) {
+ irq_set_affinity_hint(
+ instance->msixentry[j].vector, NULL);
free_irq(
instance->msixentry[j].vector,
&instance->irq_context[j]);
+ }
goto fail_irq;
}
+
+ if (irq_set_affinity_hint(instance->msixentry[i].vector,
+ get_cpu_mask(cpu)))
+ dev_err(&instance->pdev->dev, "Error setting"
+ "affinity hint for cpu %d\n", cpu);
+ cpu = cpumask_next(cpu, cpu_online_mask);
}
} else {
instance->irq_context[0].instance = instance;
@@ -4728,6 +5207,17 @@ megasas_resume(struct pci_dev *pdev)
}
}
+ /* Re-launch SR-IOV heartbeat timer */
+ if (instance->requestorId) {
+ if (!megasas_sriov_start_heartbeat(instance, 0))
+ megasas_start_timer(instance,
+ &instance->sriov_heartbeat_timer,
+ megasas_sriov_heartbeat_handler,
+ MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
+ else
+ instance->skip_heartbeat_timer_del = 1;
+ }
+
instance->instancet->enable_intr(instance);
instance->unload = 0;
@@ -4782,6 +5272,10 @@ static void megasas_detach_one(struct pci_dev *pdev)
host = instance->host;
fusion = instance->ctrl_context;
+ /* Shutdown SR-IOV heartbeat timer */
+ if (instance->requestorId && !instance->skip_heartbeat_timer_del)
+ del_timer_sync(&instance->sriov_heartbeat_timer);
+
scsi_remove_host(instance->host);
megasas_flush_cache(instance);
megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
@@ -4793,6 +5287,9 @@ static void megasas_detach_one(struct pci_dev *pdev)
instance->ev = NULL;
}
+ /* cancel all wait events */
+ wake_up_all(&instance->int_cmd_wait_q);
+
tasklet_kill(&instance->isr_tasklet);
/*
@@ -4811,9 +5308,12 @@ static void megasas_detach_one(struct pci_dev *pdev)
instance->instancet->disable_intr(instance);
if (instance->msix_vectors)
- for (i = 0 ; i < instance->msix_vectors; i++)
+ for (i = 0; i < instance->msix_vectors; i++) {
+ irq_set_affinity_hint(
+ instance->msixentry[i].vector, NULL);
free_irq(instance->msixentry[i].vector,
&instance->irq_context[i]);
+ }
else
free_irq(instance->pdev->irq, &instance->irq_context[0]);
if (instance->msix_vectors)
@@ -4821,6 +5321,7 @@ static void megasas_detach_one(struct pci_dev *pdev)
switch (instance->pdev->device) {
case PCI_DEVICE_ID_LSI_FUSION:
+ case PCI_DEVICE_ID_LSI_PLASMA:
case PCI_DEVICE_ID_LSI_INVADER:
case PCI_DEVICE_ID_LSI_FURY:
megasas_release_fusion(instance);
@@ -4847,6 +5348,24 @@ static void megasas_detach_one(struct pci_dev *pdev)
if (instance->evt_detail)
pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
instance->evt_detail, instance->evt_detail_h);
+
+ if (instance->vf_affiliation)
+ pci_free_consistent(pdev, (MAX_LOGICAL_DRIVES + 1) *
+ sizeof(struct MR_LD_VF_AFFILIATION),
+ instance->vf_affiliation,
+ instance->vf_affiliation_h);
+
+ if (instance->vf_affiliation_111)
+ pci_free_consistent(pdev,
+ sizeof(struct MR_LD_VF_AFFILIATION_111),
+ instance->vf_affiliation_111,
+ instance->vf_affiliation_111_h);
+
+ if (instance->hb_host_mem)
+ pci_free_consistent(pdev, sizeof(struct MR_CTRL_HB_HOST_MEM),
+ instance->hb_host_mem,
+ instance->hb_host_mem_h);
+
scsi_host_put(host);
pci_disable_device(pdev);
@@ -4868,9 +5387,12 @@ static void megasas_shutdown(struct pci_dev *pdev)
megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
instance->instancet->disable_intr(instance);
if (instance->msix_vectors)
- for (i = 0 ; i < instance->msix_vectors; i++)
+ for (i = 0; i < instance->msix_vectors; i++) {
+ irq_set_affinity_hint(
+ instance->msixentry[i].vector, NULL);
free_irq(instance->msixentry[i].vector,
&instance->irq_context[i]);
+ }
else
free_irq(instance->pdev->irq, &instance->irq_context[0]);
if (instance->msix_vectors)
@@ -5045,7 +5567,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
* cmd to the SCSI mid-layer
*/
cmd->sync_cmd = 1;
- megasas_issue_blocked_cmd(instance, cmd);
+ megasas_issue_blocked_cmd(instance, cmd, 0);
cmd->sync_cmd = 0;
/*
@@ -5132,6 +5654,16 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
goto out_kfree_ioc;
}
+ /* Adjust ioctl wait time for VF mode */
+ if (instance->requestorId)
+ wait_time = MEGASAS_ROUTINE_WAIT_TIME_VF;
+
+ /* Block ioctls in VF mode */
+ if (instance->requestorId && !allow_vf_ioctls) {
+ error = -ENODEV;
+ goto out_kfree_ioc;
+ }
+
if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
printk(KERN_ERR "Controller in crit error\n");
error = -ENODEV;
@@ -5441,7 +5973,7 @@ megasas_aen_polling(struct work_struct *work)
u16 pd_index = 0;
u16 ld_index = 0;
int i, j, doscan = 0;
- u32 seq_num;
+ u32 seq_num, wait_time = MEGASAS_RESET_WAIT_TIME;
int error;
if (!instance) {
@@ -5449,6 +5981,23 @@ megasas_aen_polling(struct work_struct *work)
kfree(ev);
return;
}
+
+ /* Adjust event workqueue thread wait time for VF mode */
+ if (instance->requestorId)
+ wait_time = MEGASAS_ROUTINE_WAIT_TIME_VF;
+
+ /* Don't run the event workqueue thread if OCR is running */
+ for (i = 0; i < wait_time; i++) {
+ if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL)
+ break;
+ if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
+ printk(KERN_NOTICE "megasas: %s waiting for "
+ "controller reset to finish for scsi%d\n",
+ __func__, instance->host->host_no);
+ }
+ msleep(1000);
+ }
+
instance->ev = NULL;
host = instance->host;
if (instance->evt_detail) {
@@ -5515,65 +6064,64 @@ megasas_aen_polling(struct work_struct *work)
case MR_EVT_LD_OFFLINE:
case MR_EVT_CFG_CLEARED:
case MR_EVT_LD_DELETED:
- if (megasas_ld_list_query(instance,
- MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
- megasas_get_ld_list(instance);
- for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
- for (j = 0;
- j < MEGASAS_MAX_DEV_PER_CHANNEL;
- j++) {
-
- ld_index =
- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
- sdev1 = scsi_device_lookup(host,
- MEGASAS_MAX_PD_CHANNELS + i,
- j,
- 0);
-
- if (instance->ld_ids[ld_index] != 0xff) {
- if (sdev1) {
- scsi_device_put(sdev1);
- }
- } else {
- if (sdev1) {
- scsi_remove_device(sdev1);
- scsi_device_put(sdev1);
+ if (!instance->requestorId ||
+ (instance->requestorId &&
+ megasas_get_ld_vf_affiliation(instance, 0))) {
+ if (megasas_ld_list_query(instance,
+ MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
+ megasas_get_ld_list(instance);
+ for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+ for (j = 0;
+ j < MEGASAS_MAX_DEV_PER_CHANNEL;
+ j++) {
+
+ ld_index =
+ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+
+ sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+
+ if (instance->ld_ids[ld_index]
+ != 0xff) {
+ if (sdev1)
+ scsi_device_put(sdev1);
+ } else {
+ if (sdev1) {
+ scsi_remove_device(sdev1);
+ scsi_device_put(sdev1);
+ }
+ }
}
}
- }
+ doscan = 0;
}
- doscan = 0;
break;
case MR_EVT_LD_CREATED:
- if (megasas_ld_list_query(instance,
- MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
- megasas_get_ld_list(instance);
- for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
- for (j = 0;
- j < MEGASAS_MAX_DEV_PER_CHANNEL;
- j++) {
- ld_index =
- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
- sdev1 = scsi_device_lookup(host,
- MEGASAS_MAX_PD_CHANNELS + i,
- j, 0);
-
- if (instance->ld_ids[ld_index] !=
- 0xff) {
- if (!sdev1) {
- scsi_add_device(host,
- MEGASAS_MAX_PD_CHANNELS + i,
- j, 0);
+ if (!instance->requestorId ||
+ (instance->requestorId &&
+ megasas_get_ld_vf_affiliation(instance, 0))) {
+ if (megasas_ld_list_query(instance,
+ MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
+ megasas_get_ld_list(instance);
+ for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+ for (j = 0;
+ j < MEGASAS_MAX_DEV_PER_CHANNEL;
+ j++) {
+ ld_index =
+ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+
+ sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+
+ if (instance->ld_ids[ld_index]
+ != 0xff) {
+ if (!sdev1)
+ scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
}
- }
- if (sdev1) {
- scsi_device_put(sdev1);
+ if (sdev1)
+ scsi_device_put(sdev1);
}
}
+ doscan = 0;
}
- doscan = 0;
break;
case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
case MR_EVT_FOREIGN_CFG_IMPORTED:
@@ -5591,50 +6139,55 @@ megasas_aen_polling(struct work_struct *work)
}
if (doscan) {
- printk(KERN_INFO "scanning ...\n");
- megasas_get_pd_list(instance);
- for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
- for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
- pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
- sdev1 = scsi_device_lookup(host, i, j, 0);
- if (instance->pd_list[pd_index].driveState ==
- MR_PD_STATE_SYSTEM) {
- if (!sdev1) {
- scsi_add_device(host, i, j, 0);
- }
- if (sdev1)
- scsi_device_put(sdev1);
- } else {
- if (sdev1) {
- scsi_remove_device(sdev1);
- scsi_device_put(sdev1);
+ printk(KERN_INFO "megaraid_sas: scanning for scsi%d...\n",
+ instance->host->host_no);
+ if (megasas_get_pd_list(instance) == 0) {
+ for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
+ for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+ pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
+ sdev1 = scsi_device_lookup(host, i, j, 0);
+ if (instance->pd_list[pd_index].driveState ==
+ MR_PD_STATE_SYSTEM) {
+ if (!sdev1) {
+ scsi_add_device(host, i, j, 0);
+ }
+ if (sdev1)
+ scsi_device_put(sdev1);
+ } else {
+ if (sdev1) {
+ scsi_remove_device(sdev1);
+ scsi_device_put(sdev1);
+ }
}
}
}
}
- if (megasas_ld_list_query(instance,
- MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
- megasas_get_ld_list(instance);
- for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
- for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
- ld_index =
- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+ if (!instance->requestorId ||
+ (instance->requestorId &&
+ megasas_get_ld_vf_affiliation(instance, 0))) {
+ if (megasas_ld_list_query(instance,
+ MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
+ megasas_get_ld_list(instance);
+ for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+ for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL;
+ j++) {
+ ld_index =
+ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
- sdev1 = scsi_device_lookup(host,
- MEGASAS_MAX_PD_CHANNELS + i, j, 0);
- if (instance->ld_ids[ld_index] != 0xff) {
- if (!sdev1) {
- scsi_add_device(host,
- MEGASAS_MAX_PD_CHANNELS + i,
- j, 0);
+ sdev1 = scsi_device_lookup(host,
+ MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+ if (instance->ld_ids[ld_index]
+ != 0xff) {
+ if (!sdev1)
+ scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+ else
+ scsi_device_put(sdev1);
} else {
- scsi_device_put(sdev1);
- }
- } else {
- if (sdev1) {
- scsi_remove_device(sdev1);
- scsi_device_put(sdev1);
+ if (sdev1) {
+ scsi_remove_device(sdev1);
+ scsi_device_put(sdev1);
+ }
}
}
}
diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c
index e24b6eb645b5..081bfff12d00 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fp.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fp.c
@@ -143,12 +143,12 @@ u16 MR_PdDevHandleGet(u32 pd, struct MR_FW_RAID_MAP_ALL *map)
u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map)
{
- return map->raidMap.ldSpanMap[ld].ldRaid.targetId;
+ return le16_to_cpu(map->raidMap.ldSpanMap[ld].ldRaid.targetId);
}
-u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map)
+u8 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map)
{
- return le16_to_cpu(map->raidMap.ldTgtIdToLd[ldTgtId]);
+ return map->raidMap.ldTgtIdToLd[ldTgtId];
}
static struct MR_LD_SPAN *MR_LdSpanPtrGet(u32 ld, u32 span,
@@ -975,7 +975,10 @@ MR_BuildRaidContext(struct megasas_instance *instance,
regSize += stripSize;
}
- pRAID_Context->timeoutValue = cpu_to_le16(map->raidMap.fpPdIoTimeoutSec);
+ pRAID_Context->timeoutValue =
+ cpu_to_le16(raid->fpIoTimeoutForLd ?
+ raid->fpIoTimeoutForLd :
+ map->raidMap.fpPdIoTimeoutSec);
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
pRAID_Context->regLockFlags = (isRead) ?
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index f6555921fd7a..22600419ae9f 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -62,7 +62,8 @@ megasas_complete_cmd(struct megasas_instance *instance,
struct megasas_cmd *cmd, u8 alt_status);
int megasas_is_ldio(struct scsi_cmnd *cmd);
int
-wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd);
+wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
+ int seconds);
void
megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd);
@@ -81,6 +82,13 @@ int megasas_transition_to_ready(struct megasas_instance *instance, int ocr);
void megaraid_sas_kill_hba(struct megasas_instance *instance);
extern u32 megasas_dbg_lvl;
+void megasas_sriov_heartbeat_handler(unsigned long instance_addr);
+int megasas_sriov_start_heartbeat(struct megasas_instance *instance,
+ int initial);
+void megasas_start_timer(struct megasas_instance *instance,
+ struct timer_list *timer,
+ void *fn, unsigned long interval);
+extern struct megasas_mgmt_info megasas_mgmt_info;
extern int resetwaittime;
/**
@@ -549,12 +557,13 @@ fail_req_desc:
* For polling, MFI requires the cmd_status to be set to 0xFF before posting.
*/
int
-wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd)
+wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
+ int seconds)
{
int i;
struct megasas_header *frame_hdr = &cmd->frame->hdr;
- u32 msecs = MFI_POLL_TIMEOUT_SECS * 1000;
+ u32 msecs = seconds * 1000;
/*
* Wait for cmd_status to change
@@ -585,7 +594,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
struct megasas_cmd *cmd;
u8 ret;
struct fusion_context *fusion;
- union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION req_desc;
int i;
struct megasas_header *frame_hdr;
@@ -644,18 +653,18 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
/* Convert capability to LE32 */
cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities);
- init_frame->queue_info_new_phys_addr_lo = cpu_to_le32((u32)ioc_init_handle);
+ init_frame->queue_info_new_phys_addr_hi =
+ cpu_to_le32(upper_32_bits(ioc_init_handle));
+ init_frame->queue_info_new_phys_addr_lo =
+ cpu_to_le32(lower_32_bits(ioc_init_handle));
init_frame->data_xfer_len = cpu_to_le32(sizeof(struct MPI2_IOC_INIT_REQUEST));
- req_desc =
- (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)fusion->req_frames_desc;
-
- req_desc->Words = 0;
- req_desc->MFAIo.RequestFlags =
+ req_desc.Words = 0;
+ req_desc.MFAIo.RequestFlags =
(MEGASAS_REQ_DESCRIPT_FLAGS_MFA <<
MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
- cpu_to_le32s((u32 *)&req_desc->MFAIo);
- req_desc->Words |= cpu_to_le64(cmd->frame_phys_addr);
+ cpu_to_le32s((u32 *)&req_desc.MFAIo);
+ req_desc.Words |= cpu_to_le64(cmd->frame_phys_addr);
/*
* disable the intr before firing the init frame
@@ -669,10 +678,10 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
break;
}
- instance->instancet->fire_cmd(instance, req_desc->u.low,
- req_desc->u.high, instance->reg_set);
+ instance->instancet->fire_cmd(instance, req_desc.u.low,
+ req_desc.u.high, instance->reg_set);
- wait_and_poll(instance, cmd);
+ wait_and_poll(instance, cmd, MFI_POLL_TIMEOUT_SECS);
frame_hdr = &cmd->frame->hdr;
if (frame_hdr->cmd_status != 0) {
@@ -723,7 +732,7 @@ megasas_get_ld_map_info(struct megasas_instance *instance)
if (!fusion) {
megasas_return_cmd(instance, cmd);
- return 1;
+ return -ENXIO;
}
dcmd = &cmd->frame->dcmd;
@@ -1604,13 +1613,15 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance,
MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT;
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
- io_request->IoFlags |=
- MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH;
+ io_request->IoFlags |= cpu_to_le16(
+ MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
cmd->request_desc->SCSIIO.RequestFlags =
(MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
cmd->request_desc->SCSIIO.DevHandle =
local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
+ cmd->request_desc->SCSIIO.MSIxIndex =
+ instance->msix_vectors ? smp_processor_id() % instance->msix_vectors : 0;
/*
* If the command is for the tape device, set the
* FP timeout to the os layer timeout value.
@@ -1770,7 +1781,8 @@ megasas_get_request_descriptor(struct megasas_instance *instance, u16 index)
if (index >= instance->max_fw_cmds) {
printk(KERN_ERR "megasas: Invalid SMID (0x%x)request for "
- "descriptor\n", index);
+ "descriptor for scsi%d\n", index,
+ instance->host->host_no);
return NULL;
}
fusion = instance->ctrl_context;
@@ -2038,8 +2050,11 @@ irqreturn_t megasas_isr_fusion(int irq, void *devp)
/* If we didn't complete any commands, check for FW fault */
fw_state = instance->instancet->read_fw_status_reg(
instance->reg_set) & MFI_STATE_MASK;
- if (fw_state == MFI_STATE_FAULT)
+ if (fw_state == MFI_STATE_FAULT) {
+ printk(KERN_WARNING "megaraid_sas: Iop2SysDoorbellInt"
+ "for scsi%d\n", instance->host->host_no);
schedule_work(&instance->work_init);
+ }
}
return IRQ_HANDLED;
@@ -2210,9 +2225,10 @@ megasas_check_reset_fusion(struct megasas_instance *instance,
}
/* This function waits for outstanding commands on fusion to complete */
-int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance)
+int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
+ int iotimeout, int *convert)
{
- int i, outstanding, retval = 0;
+ int i, outstanding, retval = 0, hb_seconds_missed = 0;
u32 fw_state;
for (i = 0; i < resetwaittime; i++) {
@@ -2221,18 +2237,49 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance)
instance->reg_set) & MFI_STATE_MASK;
if (fw_state == MFI_STATE_FAULT) {
printk(KERN_WARNING "megasas: Found FW in FAULT state,"
- " will reset adapter.\n");
+ " will reset adapter scsi%d.\n",
+ instance->host->host_no);
+ retval = 1;
+ goto out;
+ }
+ /* If SR-IOV VF mode & heartbeat timeout, don't wait */
+ if (instance->requestorId && !iotimeout) {
retval = 1;
goto out;
}
+ /* If SR-IOV VF mode & I/O timeout, check for HB timeout */
+ if (instance->requestorId && iotimeout) {
+ if (instance->hb_host_mem->HB.fwCounter !=
+ instance->hb_host_mem->HB.driverCounter) {
+ instance->hb_host_mem->HB.driverCounter =
+ instance->hb_host_mem->HB.fwCounter;
+ hb_seconds_missed = 0;
+ } else {
+ hb_seconds_missed++;
+ if (hb_seconds_missed ==
+ (MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF/HZ)) {
+ printk(KERN_WARNING "megasas: SR-IOV:"
+ " Heartbeat never completed "
+ " while polling during I/O "
+ " timeout handling for "
+ "scsi%d.\n",
+ instance->host->host_no);
+ *convert = 1;
+ retval = 1;
+ goto out;
+ }
+ }
+ }
+
outstanding = atomic_read(&instance->fw_outstanding);
if (!outstanding)
goto out;
if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
printk(KERN_NOTICE "megasas: [%2d]waiting for %d "
- "commands to complete\n", i, outstanding);
+ "commands to complete for scsi%d\n", i,
+ outstanding, instance->host->host_no);
megasas_complete_cmd_dpc_fusion(
(unsigned long)instance);
}
@@ -2241,7 +2288,8 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance)
if (atomic_read(&instance->fw_outstanding)) {
printk("megaraid_sas: pending commands remain after waiting, "
- "will reset adapter.\n");
+ "will reset adapter scsi%d.\n",
+ instance->host->host_no);
retval = 1;
}
out:
@@ -2263,10 +2311,34 @@ void megasas_reset_reply_desc(struct megasas_instance *instance)
reply_desc->Words = ULLONG_MAX;
}
+/* Check for a second path that is currently UP */
+int megasas_check_mpio_paths(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd)
+{
+ int i, j, retval = (DID_RESET << 16);
+
+ if (instance->mpio && instance->requestorId) {
+ for (i = 0 ; i < MAX_MGMT_ADAPTERS ; i++)
+ for (j = 0 ; j < MAX_LOGICAL_DRIVES; j++)
+ if (megasas_mgmt_info.instance[i] &&
+ (megasas_mgmt_info.instance[i] != instance) &&
+ megasas_mgmt_info.instance[i]->mpio &&
+ megasas_mgmt_info.instance[i]->requestorId
+ &&
+ (megasas_mgmt_info.instance[i]->ld_ids[j]
+ == scmd->device->id)) {
+ retval = (DID_NO_CONNECT << 16);
+ goto out;
+ }
+ }
+out:
+ return retval;
+}
+
/* Core fusion reset function */
-int megasas_reset_fusion(struct Scsi_Host *shost)
+int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
{
- int retval = SUCCESS, i, j, retry = 0;
+ int retval = SUCCESS, i, j, retry = 0, convert = 0;
struct megasas_instance *instance;
struct megasas_cmd_fusion *cmd_fusion;
struct fusion_context *fusion;
@@ -2277,28 +2349,39 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
instance = (struct megasas_instance *)shost->hostdata;
fusion = instance->ctrl_context;
+ mutex_lock(&instance->reset_mutex);
+
if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
printk(KERN_WARNING "megaraid_sas: Hardware critical error, "
- "returning FAILED.\n");
+ "returning FAILED for scsi%d.\n",
+ instance->host->host_no);
return FAILED;
}
- mutex_lock(&instance->reset_mutex);
+ if (instance->requestorId && !instance->skip_heartbeat_timer_del)
+ del_timer_sync(&instance->sriov_heartbeat_timer);
set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
- instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+ instance->adprecovery = MEGASAS_ADPRESET_SM_POLLING;
instance->instancet->disable_intr(instance);
msleep(1000);
/* First try waiting for commands to complete */
- if (megasas_wait_for_outstanding_fusion(instance)) {
+ if (megasas_wait_for_outstanding_fusion(instance, iotimeout,
+ &convert)) {
+ instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
printk(KERN_WARNING "megaraid_sas: resetting fusion "
- "adapter.\n");
+ "adapter scsi%d.\n", instance->host->host_no);
+ if (convert)
+ iotimeout = 0;
+
/* Now return commands back to the OS */
for (i = 0 ; i < instance->max_fw_cmds; i++) {
cmd_fusion = fusion->cmd_list[i];
if (cmd_fusion->scmd) {
scsi_dma_unmap(cmd_fusion->scmd);
- cmd_fusion->scmd->result = (DID_RESET << 16);
+ cmd_fusion->scmd->result =
+ megasas_check_mpio_paths(instance,
+ cmd_fusion->scmd);
cmd_fusion->scmd->scsi_done(cmd_fusion->scmd);
megasas_return_cmd_fusion(instance, cmd_fusion);
atomic_dec(&instance->fw_outstanding);
@@ -2313,13 +2396,67 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
(abs_state == MFI_STATE_FAULT && !reset_adapter)) {
/* Reset not supported, kill adapter */
printk(KERN_WARNING "megaraid_sas: Reset not supported"
- ", killing adapter.\n");
+ ", killing adapter scsi%d.\n",
+ instance->host->host_no);
megaraid_sas_kill_hba(instance);
+ instance->skip_heartbeat_timer_del = 1;
instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
retval = FAILED;
goto out;
}
+ /* Let SR-IOV VF & PF sync up if there was a HB failure */
+ if (instance->requestorId && !iotimeout) {
+ msleep(MEGASAS_OCR_SETTLE_TIME_VF);
+ /* Look for a late HB update after VF settle time */
+ if (abs_state == MFI_STATE_OPERATIONAL &&
+ (instance->hb_host_mem->HB.fwCounter !=
+ instance->hb_host_mem->HB.driverCounter)) {
+ instance->hb_host_mem->HB.driverCounter =
+ instance->hb_host_mem->HB.fwCounter;
+ printk(KERN_WARNING "megasas: SR-IOV:"
+ "Late FW heartbeat update for "
+ "scsi%d.\n",
+ instance->host->host_no);
+ } else {
+ /* In VF mode, first poll for FW ready */
+ for (i = 0;
+ i < (MEGASAS_RESET_WAIT_TIME * 1000);
+ i += 20) {
+ status_reg =
+ instance->instancet->
+ read_fw_status_reg(
+ instance->reg_set);
+ abs_state = status_reg &
+ MFI_STATE_MASK;
+ if (abs_state == MFI_STATE_READY) {
+ printk(KERN_WARNING "megasas"
+ ": SR-IOV: FW was found"
+ "to be in ready state "
+ "for scsi%d.\n",
+ instance->host->host_no);
+ break;
+ }
+ msleep(20);
+ }
+ if (abs_state != MFI_STATE_READY) {
+ printk(KERN_WARNING "megasas: SR-IOV: "
+ "FW not in ready state after %d"
+ " seconds for scsi%d, status_reg = "
+ "0x%x.\n",
+ MEGASAS_RESET_WAIT_TIME,
+ instance->host->host_no,
+ status_reg);
+ megaraid_sas_kill_hba(instance);
+ instance->skip_heartbeat_timer_del = 1;
+ instance->adprecovery =
+ MEGASAS_HW_CRITICAL_ERROR;
+ retval = FAILED;
+ goto out;
+ }
+ }
+ }
+
/* Now try to reset the chip */
for (i = 0; i < MEGASAS_FUSION_MAX_RESET_TRIES; i++) {
writel(MPI2_WRSEQ_FLUSH_KEY_VALUE,
@@ -2346,7 +2483,9 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
readl(&instance->reg_set->fusion_host_diag);
if (retry++ == 100) {
printk(KERN_WARNING "megaraid_sas: "
- "Host diag unlock failed!\n");
+ "Host diag unlock failed! "
+ "for scsi%d\n",
+ instance->host->host_no);
break;
}
}
@@ -2368,7 +2507,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
if (retry++ == 1000) {
printk(KERN_WARNING "megaraid_sas: "
"Diag reset adapter never "
- "cleared!\n");
+ "cleared for scsi%d!\n",
+ instance->host->host_no);
break;
}
}
@@ -2390,29 +2530,29 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
if (abs_state <= MFI_STATE_FW_INIT) {
printk(KERN_WARNING "megaraid_sas: firmware "
"state < MFI_STATE_FW_INIT, state = "
- "0x%x\n", abs_state);
+ "0x%x for scsi%d\n", abs_state,
+ instance->host->host_no);
continue;
}
/* Wait for FW to become ready */
if (megasas_transition_to_ready(instance, 1)) {
printk(KERN_WARNING "megaraid_sas: Failed to "
- "transition controller to ready.\n");
+ "transition controller to ready "
+ "for scsi%d.\n",
+ instance->host->host_no);
continue;
}
megasas_reset_reply_desc(instance);
if (megasas_ioc_init_fusion(instance)) {
printk(KERN_WARNING "megaraid_sas: "
- "megasas_ioc_init_fusion() failed!\n");
+ "megasas_ioc_init_fusion() failed!"
+ " for scsi%d\n",
+ instance->host->host_no);
continue;
}
- clear_bit(MEGASAS_FUSION_IN_RESET,
- &instance->reset_flags);
- instance->instancet->enable_intr(instance);
- instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
-
/* Re-fire management commands */
for (j = 0 ; j < instance->max_fw_cmds; j++) {
cmd_fusion = fusion->cmd_list[j];
@@ -2422,7 +2562,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
instance->
cmd_list[cmd_fusion->sync_cmd_idx];
if (cmd_mfi->frame->dcmd.opcode ==
- MR_DCMD_LD_MAP_GET_INFO) {
+ cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO)) {
megasas_return_cmd(instance,
cmd_mfi);
megasas_return_cmd_fusion(
@@ -2433,11 +2573,15 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
instance,
cmd_mfi->context.smid
-1);
- if (!req_desc)
+ if (!req_desc) {
printk(KERN_WARNING
"req_desc NULL"
- "\n");
- else {
+ " for scsi%d\n",
+ instance->host->host_no);
+ /* Return leaked MPT
+ frame */
+ megasas_return_cmd_fusion(instance, cmd_fusion);
+ } else {
instance->instancet->
fire_cmd(instance,
req_desc->
@@ -2451,6 +2595,11 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
}
}
+ clear_bit(MEGASAS_FUSION_IN_RESET,
+ &instance->reset_flags);
+ instance->instancet->enable_intr(instance);
+ instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+
/* Reset load balance info */
memset(fusion->load_balance_info, 0,
sizeof(struct LD_LOAD_BALANCE_INFO)
@@ -2459,18 +2608,39 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
if (!megasas_get_map_info(instance))
megasas_sync_map_info(instance);
+ /* Restart SR-IOV heartbeat */
+ if (instance->requestorId) {
+ if (!megasas_sriov_start_heartbeat(instance, 0))
+ megasas_start_timer(instance,
+ &instance->sriov_heartbeat_timer,
+ megasas_sriov_heartbeat_handler,
+ MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
+ else
+ instance->skip_heartbeat_timer_del = 1;
+ }
+
/* Adapter reset completed successfully */
printk(KERN_WARNING "megaraid_sas: Reset "
- "successful.\n");
+ "successful for scsi%d.\n",
+ instance->host->host_no);
retval = SUCCESS;
goto out;
}
/* Reset failed, kill the adapter */
printk(KERN_WARNING "megaraid_sas: Reset failed, killing "
- "adapter.\n");
+ "adapter scsi%d.\n", instance->host->host_no);
megaraid_sas_kill_hba(instance);
+ instance->skip_heartbeat_timer_del = 1;
+ instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
retval = FAILED;
} else {
+ /* For VF: Restart HB timer if we didn't OCR */
+ if (instance->requestorId) {
+ megasas_start_timer(instance,
+ &instance->sriov_heartbeat_timer,
+ megasas_sriov_heartbeat_handler,
+ MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
+ }
clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
instance->instancet->enable_intr(instance);
instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
@@ -2487,7 +2657,7 @@ void megasas_fusion_ocr_wq(struct work_struct *work)
struct megasas_instance *instance =
container_of(work, struct megasas_instance, work_init);
- megasas_reset_fusion(instance->host);
+ megasas_reset_fusion(instance->host, 0);
}
struct megasas_instance_template megasas_instance_template_fusion = {
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
index 35a51397b364..e76af5459a09 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -485,6 +485,9 @@ struct MPI2_IOC_INIT_REQUEST {
#define MAX_PHYSICAL_DEVICES 256
#define MAX_RAIDMAP_PHYSICAL_DEVICES (MAX_PHYSICAL_DEVICES)
#define MR_DCMD_LD_MAP_GET_INFO 0x0300e101
+#define MR_DCMD_CTRL_SHARED_HOST_MEM_ALLOC 0x010e8485 /* SR-IOV HB alloc*/
+#define MR_DCMD_LD_VF_MAP_GET_ALL_LDS_111 0x03200200
+#define MR_DCMD_LD_VF_MAP_GET_ALL_LDS 0x03150200
struct MR_DEV_HANDLE_INFO {
u16 curDevHdl;
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
index 62f1a6031765..0d78a4d5576c 100644
--- a/drivers/scsi/pas16.c
+++ b/drivers/scsi/pas16.c
@@ -453,7 +453,7 @@ int __init pas16_detect(struct scsi_host_template * tpnt)
instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS);
if (instance->irq != SCSI_IRQ_NONE)
- if (request_irq(instance->irq, pas16_intr, IRQF_DISABLED,
+ if (request_irq(instance->irq, pas16_intr, 0,
"pas16", instance)) {
printk("scsi%d : IRQ%d not free, interrupts disabled\n",
instance->host_no, instance->irq);
diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c
index a04b4ff8c7f6..28b4e8139153 100644
--- a/drivers/scsi/pm8001/pm8001_ctl.c
+++ b/drivers/scsi/pm8001/pm8001_ctl.c
@@ -323,24 +323,17 @@ static ssize_t pm8001_ctl_ib_queue_log_show(struct device *cdev,
int offset;
char *str = buf;
int start = 0;
-#define IB_MEMMAP(c) \
- (*(u32 *)((u8 *)pm8001_ha-> \
- memoryMap.region[IB].virt_ptr + \
+#define IB_MEMMAP(c) \
+ (*(u32 *)((u8 *)pm8001_ha-> \
+ memoryMap.region[IB].virt_ptr + \
pm8001_ha->evtlog_ib_offset + (c)))
for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {
- if (pm8001_ha->chip_id != chip_8001)
- str += sprintf(str, "0x%08x\n", IB_MEMMAP(start));
- else
- str += sprintf(str, "0x%08x\n", IB_MEMMAP(start));
+ str += sprintf(str, "0x%08x\n", IB_MEMMAP(start));
start = start + 4;
}
pm8001_ha->evtlog_ib_offset += SYSFS_OFFSET;
- if ((((pm8001_ha->evtlog_ib_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0)
- && (pm8001_ha->chip_id != chip_8001))
- pm8001_ha->evtlog_ib_offset = 0;
- if ((((pm8001_ha->evtlog_ib_offset) % (PM8001_IB_OB_QUEUE_SIZE)) == 0)
- && (pm8001_ha->chip_id == chip_8001))
+ if (((pm8001_ha->evtlog_ib_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0)
pm8001_ha->evtlog_ib_offset = 0;
return str - buf;
@@ -363,24 +356,17 @@ static ssize_t pm8001_ctl_ob_queue_log_show(struct device *cdev,
int offset;
char *str = buf;
int start = 0;
-#define OB_MEMMAP(c) \
- (*(u32 *)((u8 *)pm8001_ha-> \
- memoryMap.region[OB].virt_ptr + \
+#define OB_MEMMAP(c) \
+ (*(u32 *)((u8 *)pm8001_ha-> \
+ memoryMap.region[OB].virt_ptr + \
pm8001_ha->evtlog_ob_offset + (c)))
for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {
- if (pm8001_ha->chip_id != chip_8001)
- str += sprintf(str, "0x%08x\n", OB_MEMMAP(start));
- else
- str += sprintf(str, "0x%08x\n", OB_MEMMAP(start));
+ str += sprintf(str, "0x%08x\n", OB_MEMMAP(start));
start = start + 4;
}
pm8001_ha->evtlog_ob_offset += SYSFS_OFFSET;
- if ((((pm8001_ha->evtlog_ob_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0)
- && (pm8001_ha->chip_id != chip_8001))
- pm8001_ha->evtlog_ob_offset = 0;
- if ((((pm8001_ha->evtlog_ob_offset) % (PM8001_IB_OB_QUEUE_SIZE)) == 0)
- && (pm8001_ha->chip_id == chip_8001))
+ if (((pm8001_ha->evtlog_ob_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0)
pm8001_ha->evtlog_ob_offset = 0;
return str - buf;
@@ -466,7 +452,7 @@ static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL);
static ssize_t pm8001_ctl_fatal_log_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
- u32 count;
+ ssize_t count;
count = pm80xx_get_fatal_dump(cdev, attr, buf);
return count;
@@ -484,7 +470,7 @@ static DEVICE_ATTR(fatal_log, S_IRUGO, pm8001_ctl_fatal_log_show, NULL);
static ssize_t pm8001_ctl_gsm_log_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
- u32 count;
+ ssize_t count;
count = pm8001_get_gsm_dump(cdev, SYSFS_OFFSET, buf);
return count;
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index 0a1296a87d66..a97be015e52e 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -644,7 +644,7 @@ static int pm8001_chip_init(struct pm8001_hba_info *pm8001_ha)
pci_read_config_word(pm8001_ha->pdev, PCI_DEVICE_ID, &deviceid);
/* 8081 controllers need BAR shift to access MPI space
* as this is shared with BIOS data */
- if (deviceid == 0x8081) {
+ if (deviceid == 0x8081 || deviceid == 0x0042) {
if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_SM_BASE)) {
PM8001_FAIL_DBG(pm8001_ha,
pm8001_printk("Shift Bar4 to 0x%x failed\n",
@@ -673,7 +673,7 @@ static int pm8001_chip_init(struct pm8001_hba_info *pm8001_ha)
for (i = 0; i < PM8001_MAX_OUTB_NUM; i++)
update_outbnd_queue_table(pm8001_ha, i);
/* 8081 controller donot require these operations */
- if (deviceid != 0x8081) {
+ if (deviceid != 0x8081 && deviceid != 0x0042) {
mpi_set_phys_g3_with_ssc(pm8001_ha, 0);
/* 7->130ms, 34->500ms, 119->1.5s */
mpi_set_open_retry_interval_reg(pm8001_ha, 119);
@@ -701,7 +701,7 @@ static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha)
u32 gst_len_mpistate;
u16 deviceid;
pci_read_config_word(pm8001_ha->pdev, PCI_DEVICE_ID, &deviceid);
- if (deviceid == 0x8081) {
+ if (deviceid == 0x8081 || deviceid == 0x0042) {
if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_SM_BASE)) {
PM8001_FAIL_DBG(pm8001_ha,
pm8001_printk("Shift Bar4 to 0x%x failed\n",
@@ -2502,11 +2502,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*in order to force CPU ordering*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2522,11 +2518,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2550,11 +2542,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY);
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/* ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2617,11 +2605,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
IO_DS_NON_OPERATIONAL);
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2641,11 +2625,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
IO_DS_IN_ERROR);
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2674,20 +2654,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
" resp 0x%x stat 0x%x but aborted by upper layer!\n",
t, status, ts->resp, ts->stat));
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- } else if (t->uldd_task) {
- spin_unlock_irqrestore(&t->task_state_lock, flags);
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/* ditto */
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
- } else if (!t->uldd_task) {
+ } else {
spin_unlock_irqrestore(&t->task_state_lock, flags);
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
}
}
@@ -2796,11 +2765,7 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2909,20 +2874,9 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
" resp 0x%x stat 0x%x but aborted by upper layer!\n",
t, event, ts->resp, ts->stat));
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- } else if (t->uldd_task) {
- spin_unlock_irqrestore(&t->task_state_lock, flags);
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/* ditto */
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
- } else if (!t->uldd_task) {
+ } else {
spin_unlock_irqrestore(&t->task_state_lock, flags);
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
}
}
@@ -4467,23 +4421,11 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
" stat 0x%x but aborted by upper layer "
"\n", task, ts->resp, ts->stat));
pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
- } else if (task->uldd_task) {
- spin_unlock_irqrestore(&task->task_state_lock,
- flags);
- pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
- mb();/* ditto */
- spin_unlock_irq(&pm8001_ha->lock);
- task->task_done(task);
- spin_lock_irq(&pm8001_ha->lock);
- return 0;
- } else if (!task->uldd_task) {
+ } else {
spin_unlock_irqrestore(&task->task_state_lock,
flags);
- pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- task->task_done(task);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, task,
+ ccb, tag);
return 0;
}
}
@@ -5020,7 +4962,7 @@ pm8001_get_gsm_dump(struct device *cdev, u32 length, char *buf)
/* check max is 1 Mbytes */
if ((length > 0x100000) || (gsm_dump_offset & 3) ||
((gsm_dump_offset + length) > 0x1000000))
- return 1;
+ return -EINVAL;
if (pm8001_ha->chip_id == chip_8001)
bar = 2;
@@ -5048,12 +4990,12 @@ pm8001_get_gsm_dump(struct device *cdev, u32 length, char *buf)
gsm_base = GSM_BASE;
if (-1 == pm8001_bar4_shift(pm8001_ha,
(gsm_base + shift_value)))
- return 1;
+ return -EIO;
} else {
gsm_base = 0;
if (-1 == pm80xx_bar4_shift(pm8001_ha,
(gsm_base + shift_value)))
- return 1;
+ return -EIO;
}
gsm_dump_offset = (gsm_dump_offset + offset) &
0xFFFF0000;
@@ -5072,13 +5014,8 @@ pm8001_get_gsm_dump(struct device *cdev, u32 length, char *buf)
direct_data += sprintf(direct_data, "%08x ", value);
}
/* Shift back to BAR4 original address */
- if (pm8001_ha->chip_id == chip_8001) {
- if (-1 == pm8001_bar4_shift(pm8001_ha, 0))
- return 1;
- } else {
- if (-1 == pm80xx_bar4_shift(pm8001_ha, 0))
- return 1;
- }
+ if (-1 == pm8001_bar4_shift(pm8001_ha, 0))
+ return -EIO;
pm8001_ha->fatal_forensic_shift_offset += 1024;
if (pm8001_ha->fatal_forensic_shift_offset >= 0x100000)
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index 73a120d81b4d..c4f31b21feb8 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -625,7 +625,7 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
pm8001_ha->nvmd_completion = &completion;
if (pm8001_ha->chip_id == chip_8001) {
- if (deviceid == 0x8081) {
+ if (deviceid == 0x8081 || deviceid == 0x0042) {
payload.minor_function = 4;
payload.length = 4096;
} else {
@@ -646,6 +646,9 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
if (deviceid == 0x8081)
pm8001_ha->sas_addr[j] =
payload.func_specific[0x704 + i];
+ else if (deviceid == 0x0042)
+ pm8001_ha->sas_addr[j] =
+ payload.func_specific[0x010 + i];
} else
pm8001_ha->sas_addr[j] =
payload.func_specific[0x804 + i];
@@ -713,11 +716,9 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha)
/* SPCv controllers supports 64 msi-x */
if (pm8001_ha->chip_id == chip_8001) {
number_of_intr = 1;
- flag |= IRQF_DISABLED;
} else {
number_of_intr = PM8001_MAX_MSIX_VEC;
flag &= ~IRQF_SHARED;
- flag |= IRQF_DISABLED;
}
max_entry = sizeof(pm8001_ha->msix_entries) /
@@ -1072,10 +1073,7 @@ err_out_enable:
*/
static struct pci_device_id pm8001_pci_table[] = {
{ PCI_VDEVICE(PMC_Sierra, 0x8001), chip_8001 },
- {
- PCI_DEVICE(0x117c, 0x0042),
- .driver_data = chip_8001
- },
+ { PCI_VDEVICE(ATTO, 0x0042), chip_8001 },
/* Support for SPC/SPCv/SPCve controllers */
{ PCI_VDEVICE(ADAPTEC2, 0x8001), chip_8001 },
{ PCI_VDEVICE(PMC_Sierra, 0x8008), chip_8008 },
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index f50ac44b950e..8a44bc92bc78 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -434,6 +434,7 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
ccb->n_elem = n_elem;
ccb->ccb_tag = tag;
ccb->task = t;
+ ccb->device = pm8001_dev;
switch (t->task_proto) {
case SAS_PROTOCOL_SMP:
rc = pm8001_task_prep_smp(pm8001_ha, ccb);
@@ -865,13 +866,11 @@ ex_err:
static void pm8001_dev_gone_notify(struct domain_device *dev)
{
unsigned long flags = 0;
- u32 tag;
struct pm8001_hba_info *pm8001_ha;
struct pm8001_device *pm8001_dev = dev->lldd_dev;
pm8001_ha = pm8001_find_ha_by_dev(dev);
spin_lock_irqsave(&pm8001_ha->lock, flags);
- pm8001_tag_alloc(pm8001_ha, &tag);
if (pm8001_dev) {
u32 device_id = pm8001_dev->device_id;
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index 6c5fd5ee22d3..1ee06f21803b 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -708,5 +708,17 @@ ssize_t pm8001_get_gsm_dump(struct device *cdev, u32, char *buf);
/* ctl shared API */
extern struct device_attribute *pm8001_host_attrs[];
+static inline void
+pm8001_ccb_task_free_done(struct pm8001_hba_info *pm8001_ha,
+ struct sas_task *task, struct pm8001_ccb_info *ccb,
+ u32 ccb_idx)
+{
+ pm8001_ccb_task_free(pm8001_ha, task, ccb, ccb_idx);
+ smp_mb(); /*in order to force CPU ordering*/
+ spin_unlock(&pm8001_ha->lock);
+ task->task_done(task);
+ spin_lock(&pm8001_ha->lock);
+}
+
#endif
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index c950dc5c9943..d70587f96184 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -91,7 +91,6 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev,
struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
void __iomem *fatal_table_address = pm8001_ha->fatal_tbl_addr;
- u32 status = 1;
u32 accum_len , reg_val, index, *temp;
unsigned long start;
u8 *direct_data;
@@ -111,13 +110,10 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev,
direct_data = (u8 *)fatal_error_data;
pm8001_ha->forensic_info.data_type = TYPE_NON_FATAL;
pm8001_ha->forensic_info.data_buf.direct_len = SYSFS_OFFSET;
- pm8001_ha->forensic_info.data_buf.direct_offset = 0;
pm8001_ha->forensic_info.data_buf.read_len = 0;
pm8001_ha->forensic_info.data_buf.direct_data = direct_data;
- }
- if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) {
/* start to get data */
/* Program the MEMBASE II Shifting Register with 0x00.*/
pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER,
@@ -126,6 +122,7 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev,
pm8001_ha->forensic_fatal_step = 0;
pm8001_ha->fatal_bar_loc = 0;
}
+
/* Read until accum_len is retrived */
accum_len = pm8001_mr32(fatal_table_address,
MPI_FATAL_EDUMP_TABLE_ACCUM_LEN);
@@ -135,7 +132,7 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev,
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("Possible PCI issue 0x%x not expected\n",
accum_len));
- return status;
+ return -EIO;
}
if (accum_len == 0 || accum_len >= 0x100000) {
pm8001_ha->forensic_info.data_buf.direct_data +=
@@ -178,7 +175,6 @@ moreData:
pm8001_ha->forensic_fatal_step = 1;
pm8001_ha->fatal_forensic_shift_offset = 0;
pm8001_ha->forensic_last_offset = 0;
- status = 0;
return (char *)pm8001_ha->
forensic_info.data_buf.direct_data -
(char *)buf;
@@ -194,7 +190,6 @@ moreData:
forensic_info.data_buf.direct_data,
"%08x ", *(temp + index));
}
- status = 0;
return (char *)pm8001_ha->
forensic_info.data_buf.direct_data -
(char *)buf;
@@ -214,7 +209,6 @@ moreData:
pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER,
pm8001_ha->fatal_forensic_shift_offset);
pm8001_ha->fatal_bar_loc = 0;
- status = 0;
return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
(char *)buf;
}
@@ -239,7 +233,7 @@ moreData:
PM8001_FAIL_DBG(pm8001_ha,
pm8001_printk("TIMEOUT:MEMBASE_II_SHIFT_REGISTER"
" = 0x%x\n", reg_val));
- return -1;
+ return -EIO;
}
/* Read the next 64K of the debug data. */
@@ -259,7 +253,6 @@ moreData:
pm8001_ha->forensic_info.data_buf.direct_len = 0;
pm8001_ha->forensic_info.data_buf.direct_offset = 0;
pm8001_ha->forensic_info.data_buf.read_len = 0;
- status = 0;
}
}
@@ -2175,11 +2168,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*in order to force CPU ordering*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2195,11 +2184,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2221,11 +2206,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY);
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/* ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2288,11 +2269,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
IO_DS_NON_OPERATIONAL);
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2312,11 +2289,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
IO_DS_IN_ERROR);
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2345,20 +2318,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
" resp 0x%x stat 0x%x but aborted by upper layer!\n",
t, status, ts->resp, ts->stat));
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- } else if (t->uldd_task) {
- spin_unlock_irqrestore(&t->task_state_lock, flags);
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/* ditto */
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
- } else if (!t->uldd_task) {
+ } else {
spin_unlock_irqrestore(&t->task_state_lock, flags);
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
}
}
@@ -2470,11 +2432,7 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2596,20 +2554,9 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
" resp 0x%x stat 0x%x but aborted by upper layer!\n",
t, event, ts->resp, ts->stat));
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- } else if (t->uldd_task) {
- spin_unlock_irqrestore(&t->task_state_lock, flags);
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/* ditto */
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
- } else if (!t->uldd_task) {
+ } else {
spin_unlock_irqrestore(&t->task_state_lock, flags);
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
}
}
@@ -4304,23 +4251,11 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
"\n", task, ts->resp, ts->stat));
pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
return 0;
- } else if (task->uldd_task) {
- spin_unlock_irqrestore(&task->task_state_lock,
- flags);
- pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
- mb();/* ditto */
- spin_unlock_irq(&pm8001_ha->lock);
- task->task_done(task);
- spin_lock_irq(&pm8001_ha->lock);
- return 0;
- } else if (!task->uldd_task) {
+ } else {
spin_unlock_irqrestore(&task->task_state_lock,
flags);
- pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- task->task_done(task);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, task,
+ ccb, tag);
return 0;
}
}
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 97dabd39b092..158020522dfb 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -379,14 +379,7 @@
#define DEBUG_PRINT_NVRAM 0
#define DEBUG_QLA1280 0
-/*
- * The SGI VISWS is broken and doesn't support MMIO ;-(
- */
-#ifdef CONFIG_X86_VISWS
-#define MEMORY_MAPPED_IO 0
-#else
#define MEMORY_MAPPED_IO 1
-#endif
#include "qla1280.h"
diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile
index ff0fc7c7812f..44def6bb4bb0 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_nx2.o qla_target.o
+ qla_nx.o qla_mr.o qla_nx2.o qla_target.o qla_tmpl.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 4a0d7c92181f..07befcf365b8 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -147,6 +147,92 @@ static struct bin_attribute sysfs_fw_dump_attr = {
};
static ssize_t
+qla2x00_sysfs_read_fw_dump_template(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
+ struct device, kobj)));
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!ha->fw_dump_template || !ha->fw_dump_template_len)
+ return 0;
+
+ ql_dbg(ql_dbg_user, vha, 0x70e2,
+ "chunk <- off=%llx count=%zx\n", off, count);
+ return memory_read_from_buffer(buf, count, &off,
+ ha->fw_dump_template, ha->fw_dump_template_len);
+}
+
+static ssize_t
+qla2x00_sysfs_write_fw_dump_template(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
+ struct device, kobj)));
+ struct qla_hw_data *ha = vha->hw;
+ uint32_t size;
+
+ if (off == 0) {
+ if (ha->fw_dump)
+ vfree(ha->fw_dump);
+ if (ha->fw_dump_template)
+ vfree(ha->fw_dump_template);
+
+ ha->fw_dump = NULL;
+ ha->fw_dump_len = 0;
+ ha->fw_dump_template = NULL;
+ ha->fw_dump_template_len = 0;
+
+ size = qla27xx_fwdt_template_size(buf);
+ ql_dbg(ql_dbg_user, vha, 0x70d1,
+ "-> allocating fwdt (%x bytes)...\n", size);
+ ha->fw_dump_template = vmalloc(size);
+ if (!ha->fw_dump_template) {
+ ql_log(ql_log_warn, vha, 0x70d2,
+ "Failed allocate fwdt (%x bytes).\n", size);
+ return -ENOMEM;
+ }
+ ha->fw_dump_template_len = size;
+ }
+
+ if (off + count > ha->fw_dump_template_len) {
+ count = ha->fw_dump_template_len - off;
+ ql_dbg(ql_dbg_user, vha, 0x70d3,
+ "chunk -> truncating to %zx bytes.\n", count);
+ }
+
+ ql_dbg(ql_dbg_user, vha, 0x70d4,
+ "chunk -> off=%llx count=%zx\n", off, count);
+ memcpy(ha->fw_dump_template + off, buf, count);
+
+ if (off + count == ha->fw_dump_template_len) {
+ size = qla27xx_fwdt_calculate_dump_size(vha);
+ ql_dbg(ql_dbg_user, vha, 0x70d5,
+ "-> allocating fwdump (%x bytes)...\n", size);
+ ha->fw_dump = vmalloc(size);
+ if (!ha->fw_dump) {
+ ql_log(ql_log_warn, vha, 0x70d6,
+ "Failed allocate fwdump (%x bytes).\n", size);
+ return -ENOMEM;
+ }
+ ha->fw_dump_len = size;
+ }
+
+ return count;
+}
+static struct bin_attribute sysfs_fw_dump_template_attr = {
+ .attr = {
+ .name = "fw_dump_template",
+ .mode = S_IRUSR | S_IWUSR,
+ },
+ .size = 0,
+ .read = qla2x00_sysfs_read_fw_dump_template,
+ .write = qla2x00_sysfs_write_fw_dump_template,
+};
+
+static ssize_t
qla2x00_sysfs_read_nvram(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
@@ -241,12 +327,17 @@ qla2x00_sysfs_read_optrom(struct file *filp, struct kobject *kobj,
struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
struct qla_hw_data *ha = vha->hw;
+ ssize_t rval = 0;
if (ha->optrom_state != QLA_SREADING)
return 0;
- return memory_read_from_buffer(buf, count, &off, ha->optrom_buffer,
- ha->optrom_region_size);
+ mutex_lock(&ha->optrom_mutex);
+ rval = memory_read_from_buffer(buf, count, &off, ha->optrom_buffer,
+ ha->optrom_region_size);
+ mutex_unlock(&ha->optrom_mutex);
+
+ return rval;
}
static ssize_t
@@ -265,7 +356,9 @@ qla2x00_sysfs_write_optrom(struct file *filp, struct kobject *kobj,
if (off + count > ha->optrom_region_size)
count = ha->optrom_region_size - off;
+ mutex_lock(&ha->optrom_mutex);
memcpy(&ha->optrom_buffer[off], buf, count);
+ mutex_unlock(&ha->optrom_mutex);
return count;
}
@@ -288,10 +381,10 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
struct qla_hw_data *ha = vha->hw;
-
uint32_t start = 0;
uint32_t size = ha->optrom_size;
int val, valid;
+ ssize_t rval = count;
if (off)
return -EINVAL;
@@ -304,12 +397,14 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
if (start > ha->optrom_size)
return -EINVAL;
+ mutex_lock(&ha->optrom_mutex);
switch (val) {
case 0:
if (ha->optrom_state != QLA_SREADING &&
- ha->optrom_state != QLA_SWRITING)
- return -EINVAL;
-
+ ha->optrom_state != QLA_SWRITING) {
+ rval = -EINVAL;
+ goto out;
+ }
ha->optrom_state = QLA_SWAITING;
ql_dbg(ql_dbg_user, vha, 0x7061,
@@ -320,8 +415,10 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
ha->optrom_buffer = NULL;
break;
case 1:
- if (ha->optrom_state != QLA_SWAITING)
- return -EINVAL;
+ if (ha->optrom_state != QLA_SWAITING) {
+ rval = -EINVAL;
+ goto out;
+ }
ha->optrom_region_start = start;
ha->optrom_region_size = start + size > ha->optrom_size ?
@@ -335,13 +432,15 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
"(%x).\n", ha->optrom_region_size);
ha->optrom_state = QLA_SWAITING;
- return -ENOMEM;
+ rval = -ENOMEM;
+ goto out;
}
if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x7063,
"HBA not online, failing NVRAM update.\n");
- return -EAGAIN;
+ rval = -EAGAIN;
+ goto out;
}
ql_dbg(ql_dbg_user, vha, 0x7064,
@@ -353,8 +452,10 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
ha->optrom_region_start, ha->optrom_region_size);
break;
case 2:
- if (ha->optrom_state != QLA_SWAITING)
- return -EINVAL;
+ if (ha->optrom_state != QLA_SWAITING) {
+ rval = -EINVAL;
+ goto out;
+ }
/*
* We need to be more restrictive on which FLASH regions are
@@ -388,7 +489,8 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
if (!valid) {
ql_log(ql_log_warn, vha, 0x7065,
"Invalid start region 0x%x/0x%x.\n", start, size);
- return -EINVAL;
+ rval = -EINVAL;
+ goto out;
}
ha->optrom_region_start = start;
@@ -403,7 +505,8 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
"(%x)\n", ha->optrom_region_size);
ha->optrom_state = QLA_SWAITING;
- return -ENOMEM;
+ rval = -ENOMEM;
+ goto out;
}
ql_dbg(ql_dbg_user, vha, 0x7067,
@@ -413,13 +516,16 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
memset(ha->optrom_buffer, 0, ha->optrom_region_size);
break;
case 3:
- if (ha->optrom_state != QLA_SWRITING)
- return -EINVAL;
+ if (ha->optrom_state != QLA_SWRITING) {
+ rval = -EINVAL;
+ goto out;
+ }
if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x7068,
"HBA not online, failing flash update.\n");
- return -EAGAIN;
+ rval = -EAGAIN;
+ goto out;
}
ql_dbg(ql_dbg_user, vha, 0x7069,
@@ -430,9 +536,12 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
ha->optrom_region_start, ha->optrom_region_size);
break;
default:
- return -EINVAL;
+ rval = -EINVAL;
}
- return count;
+
+out:
+ mutex_unlock(&ha->optrom_mutex);
+ return rval;
}
static struct bin_attribute sysfs_optrom_ctl_attr = {
@@ -822,6 +931,7 @@ static struct sysfs_entry {
int is4GBp_only;
} bin_file_entries[] = {
{ "fw_dump", &sysfs_fw_dump_attr, },
+ { "fw_dump_template", &sysfs_fw_dump_template_attr, 0x27 },
{ "nvram", &sysfs_nvram_attr, },
{ "optrom", &sysfs_optrom_attr, },
{ "optrom_ctl", &sysfs_optrom_ctl_attr, },
@@ -847,6 +957,8 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha)
continue;
if (iter->is4GBp_only == 3 && !(IS_CNA_CAPABLE(vha->hw)))
continue;
+ if (iter->is4GBp_only == 0x27 && !IS_QLA27XX(vha->hw))
+ continue;
ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
iter->attr);
@@ -1187,7 +1299,7 @@ qla2x00_optrom_gold_fw_version_show(struct device *dev,
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
struct qla_hw_data *ha = vha->hw;
- if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha))
+ if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) && !IS_QLA27XX(ha))
return scnprintf(buf, PAGE_SIZE, "\n");
return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%d)\n",
@@ -1391,6 +1503,37 @@ qla2x00_fw_dump_size_show(struct device *dev, struct device_attribute *attr,
return scnprintf(buf, PAGE_SIZE, "%d\n", size);
}
+static ssize_t
+qla2x00_allow_cna_fw_dump_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+
+ if (!IS_P3P_TYPE(vha->hw))
+ return scnprintf(buf, PAGE_SIZE, "\n");
+ else
+ return scnprintf(buf, PAGE_SIZE, "%s\n",
+ vha->hw->allow_cna_fw_dump ? "true" : "false");
+}
+
+static ssize_t
+qla2x00_allow_cna_fw_dump_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ int val = 0;
+
+ if (!IS_P3P_TYPE(vha->hw))
+ return -EINVAL;
+
+ if (sscanf(buf, "%d", &val) != 1)
+ return -EINVAL;
+
+ vha->hw->allow_cna_fw_dump = val != 0;
+
+ return strlen(buf);
+}
+
static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL);
static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
@@ -1432,6 +1575,9 @@ static DEVICE_ATTR(thermal_temp, S_IRUGO, qla2x00_thermal_temp_show, NULL);
static DEVICE_ATTR(diag_requests, S_IRUGO, qla2x00_diag_requests_show, NULL);
static DEVICE_ATTR(diag_megabytes, S_IRUGO, qla2x00_diag_megabytes_show, NULL);
static DEVICE_ATTR(fw_dump_size, S_IRUGO, qla2x00_fw_dump_size_show, NULL);
+static DEVICE_ATTR(allow_cna_fw_dump, S_IRUGO | S_IWUSR,
+ qla2x00_allow_cna_fw_dump_show,
+ qla2x00_allow_cna_fw_dump_store);
struct device_attribute *qla2x00_host_attrs[] = {
&dev_attr_driver_version,
@@ -1464,6 +1610,7 @@ struct device_attribute *qla2x00_host_attrs[] = {
&dev_attr_diag_requests,
&dev_attr_diag_megabytes,
&dev_attr_fw_dump_size,
+ &dev_attr_allow_cna_fw_dump,
NULL,
};
@@ -1509,6 +1656,9 @@ qla2x00_get_host_speed(struct Scsi_Host *shost)
case PORT_SPEED_16GB:
speed = FC_PORTSPEED_16GBIT;
break;
+ case PORT_SPEED_32GB:
+ speed = FC_PORTSPEED_32GBIT;
+ break;
}
fc_host_speed(shost) = speed;
}
@@ -2160,6 +2310,9 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha)
else if (IS_QLAFX00(ha))
speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT |
FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT;
+ else if (IS_QLA27XX(ha))
+ speed = FC_PORTSPEED_32GBIT | FC_PORTSPEED_16GBIT |
+ FC_PORTSPEED_8GBIT;
else
speed = FC_PORTSPEED_1GBIT;
fc_host_supported_speeds(vha->host) = speed;
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index f15d03e6b7ee..71ff340f6de4 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -1437,9 +1437,12 @@ qla2x00_read_optrom(struct fc_bsg_job *bsg_job)
if (ha->flags.nic_core_reset_hdlr_active)
return -EBUSY;
+ mutex_lock(&ha->optrom_mutex);
rval = qla2x00_optrom_setup(bsg_job, vha, 0);
- if (rval)
+ if (rval) {
+ mutex_unlock(&ha->optrom_mutex);
return rval;
+ }
ha->isp_ops->read_optrom(vha, ha->optrom_buffer,
ha->optrom_region_start, ha->optrom_region_size);
@@ -1453,6 +1456,7 @@ qla2x00_read_optrom(struct fc_bsg_job *bsg_job)
vfree(ha->optrom_buffer);
ha->optrom_buffer = NULL;
ha->optrom_state = QLA_SWAITING;
+ mutex_unlock(&ha->optrom_mutex);
bsg_job->job_done(bsg_job);
return rval;
}
@@ -1465,9 +1469,12 @@ qla2x00_update_optrom(struct fc_bsg_job *bsg_job)
struct qla_hw_data *ha = vha->hw;
int rval = 0;
+ mutex_lock(&ha->optrom_mutex);
rval = qla2x00_optrom_setup(bsg_job, vha, 1);
- if (rval)
+ if (rval) {
+ mutex_unlock(&ha->optrom_mutex);
return rval;
+ }
/* Set the isp82xx_no_md_cap not to capture minidump */
ha->flags.isp82xx_no_md_cap = 1;
@@ -1483,6 +1490,7 @@ qla2x00_update_optrom(struct fc_bsg_job *bsg_job)
vfree(ha->optrom_buffer);
ha->optrom_buffer = NULL;
ha->optrom_state = QLA_SWAITING;
+ mutex_unlock(&ha->optrom_mutex);
bsg_job->job_done(bsg_job);
return rval;
}
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index f6103f553bb1..97255f7c3975 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -11,13 +11,15 @@
* ----------------------------------------------------------------------
* | Level | Last Value Used | Holes |
* ----------------------------------------------------------------------
- * | Module Init and Probe | 0x015b | 0x4b,0xba,0xfa |
- * | | | 0x0x015a |
- * | Mailbox commands | 0x1187 | 0x111a-0x111b |
- * | | | 0x1155-0x1158 |
- * | | | 0x1018-0x1019 |
+ * | Module Init and Probe | 0x017d | 0x004b,0x0141 |
+ * | | | 0x0144,0x0146 |
+ * | | | 0x015b-0x0160 |
+ * | | | 0x016e-0x0170 |
+ * | Mailbox commands | 0x1187 | 0x1018-0x1019 |
+ * | | | 0x10ca |
* | | | 0x1115-0x1116 |
- * | | | 0x10ca |
+ * | | | 0x111a-0x111b |
+ * | | | 0x1155-0x1158 |
* | Device Discovery | 0x2095 | 0x2020-0x2022, |
* | | | 0x2011-0x2012, |
* | | | 0x2016 |
@@ -32,18 +34,17 @@
* | | | 0x5047,0x5052 |
* | | | 0x5084,0x5075 |
* | | | 0x503d,0x5044 |
+ * | | | 0x507b |
* | Timer Routines | 0x6012 | |
- * | User Space Interactions | 0x70e1 | 0x7018,0x702e, |
- * | | | 0x7020,0x7024, |
- * | | | 0x7039,0x7045, |
- * | | | 0x7073-0x7075, |
- * | | | 0x707b,0x708c, |
- * | | | 0x70a5,0x70a6, |
- * | | | 0x70a8,0x70ab, |
- * | | | 0x70ad-0x70ae, |
- * | | | 0x70d1-0x70db, |
- * | | | 0x7047,0x703b |
- * | | | 0x70de-0x70df, |
+ * | User Space Interactions | 0x70e2 | 0x7018,0x702e |
+ * | | | 0x7020,0x7024 |
+ * | | | 0x7039,0x7045 |
+ * | | | 0x7073-0x7075 |
+ * | | | 0x70a5-0x70a6 |
+ * | | | 0x70a8,0x70ab |
+ * | | | 0x70ad-0x70ae |
+ * | | | 0x70d7-0x70db |
+ * | | | 0x70de-0x70df |
* | Task Management | 0x803d | 0x8025-0x8026 |
* | | | 0x800b,0x8039 |
* | AER/EEH | 0x9011 | |
@@ -59,7 +60,11 @@
* | | | 0xb13c-0xb140 |
* | | | 0xb149 |
* | MultiQ | 0xc00c | |
- * | Misc | 0xd010 | |
+ * | Misc | 0xd2ff | 0xd017-0xd019 |
+ * | | | 0xd020 |
+ * | | | 0xd02e-0xd0ff |
+ * | | | 0xd101-0xd1fe |
+ * | | | 0xd212-0xd2fe |
* | Target Mode | 0xe070 | 0xe021 |
* | Target Mode Management | 0xf072 | 0xf002-0xf003 |
* | | | 0xf046-0xf049 |
@@ -104,7 +109,87 @@ qla2xxx_copy_queues(struct qla_hw_data *ha, void *ptr)
return ptr + (rsp->length * sizeof(response_t));
}
-static int
+int
+qla27xx_dump_mpi_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram,
+ uint32_t ram_dwords, void **nxt)
+{
+ int rval;
+ uint32_t cnt, stat, timer, dwords, idx;
+ uint16_t mb0, mb1;
+ struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+ dma_addr_t dump_dma = ha->gid_list_dma;
+ uint32_t *dump = (uint32_t *)ha->gid_list;
+
+ rval = QLA_SUCCESS;
+ mb0 = 0;
+
+ WRT_REG_WORD(&reg->mailbox0, MBC_LOAD_DUMP_MPI_RAM);
+ clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+
+ dwords = qla2x00_gid_list_size(ha) / 4;
+ for (cnt = 0; cnt < ram_dwords && rval == QLA_SUCCESS;
+ cnt += dwords, addr += dwords) {
+ if (cnt + dwords > ram_dwords)
+ dwords = ram_dwords - cnt;
+
+ WRT_REG_WORD(&reg->mailbox1, LSW(addr));
+ WRT_REG_WORD(&reg->mailbox8, MSW(addr));
+
+ WRT_REG_WORD(&reg->mailbox2, MSW(dump_dma));
+ WRT_REG_WORD(&reg->mailbox3, LSW(dump_dma));
+ WRT_REG_WORD(&reg->mailbox6, MSW(MSD(dump_dma)));
+ WRT_REG_WORD(&reg->mailbox7, LSW(MSD(dump_dma)));
+
+ WRT_REG_WORD(&reg->mailbox4, MSW(dwords));
+ WRT_REG_WORD(&reg->mailbox5, LSW(dwords));
+
+ WRT_REG_WORD(&reg->mailbox9, 0);
+ WRT_REG_DWORD(&reg->hccr, HCCRX_SET_HOST_INT);
+
+ ha->flags.mbox_int = 0;
+ for (timer = 6000000; timer; timer--) {
+ /* Check for pending interrupts. */
+ stat = RD_REG_DWORD(&reg->host_status);
+ if (stat & HSRX_RISC_INT) {
+ stat &= 0xff;
+
+ if (stat == 0x1 || stat == 0x2 ||
+ stat == 0x10 || stat == 0x11) {
+ set_bit(MBX_INTERRUPT,
+ &ha->mbx_cmd_flags);
+
+ mb0 = RD_REG_WORD(&reg->mailbox0);
+ mb1 = RD_REG_WORD(&reg->mailbox1);
+
+ WRT_REG_DWORD(&reg->hccr,
+ HCCRX_CLR_RISC_INT);
+ RD_REG_DWORD(&reg->hccr);
+ break;
+ }
+
+ /* Clear this intr; it wasn't a mailbox intr */
+ WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
+ RD_REG_DWORD(&reg->hccr);
+ }
+ udelay(5);
+ }
+ ha->flags.mbox_int = 1;
+
+ if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
+ rval = mb0 & MBS_MASK;
+ for (idx = 0; idx < dwords; idx++)
+ ram[cnt + idx] = IS_QLA27XX(ha) ?
+ le32_to_cpu(dump[idx]) : swab32(dump[idx]);
+ } else {
+ rval = QLA_FUNCTION_FAILED;
+ }
+ }
+
+ *nxt = rval == QLA_SUCCESS ? &ram[cnt] : NULL;
+ return rval;
+}
+
+int
qla24xx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram,
uint32_t ram_dwords, void **nxt)
{
@@ -139,6 +224,7 @@ qla24xx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram,
WRT_REG_WORD(&reg->mailbox5, LSW(dwords));
WRT_REG_DWORD(&reg->hccr, HCCRX_SET_HOST_INT);
+ ha->flags.mbox_int = 0;
for (timer = 6000000; timer; timer--) {
/* Check for pending interrupts. */
stat = RD_REG_DWORD(&reg->host_status);
@@ -164,11 +250,13 @@ qla24xx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram,
}
udelay(5);
}
+ ha->flags.mbox_int = 1;
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
rval = mb0 & MBS_MASK;
for (idx = 0; idx < dwords; idx++)
- ram[cnt + idx] = swab32(dump[idx]);
+ ram[cnt + idx] = IS_QLA27XX(ha) ?
+ le32_to_cpu(dump[idx]) : swab32(dump[idx]);
} else {
rval = QLA_FUNCTION_FAILED;
}
@@ -208,7 +296,7 @@ qla24xx_read_window(struct device_reg_24xx __iomem *reg, uint32_t iobase,
return buf;
}
-static inline int
+int
qla24xx_pause_risc(struct device_reg_24xx __iomem *reg)
{
int rval = QLA_SUCCESS;
@@ -227,7 +315,7 @@ qla24xx_pause_risc(struct device_reg_24xx __iomem *reg)
return rval;
}
-static int
+int
qla24xx_soft_reset(struct qla_hw_data *ha)
{
int rval = QLA_SUCCESS;
@@ -537,7 +625,7 @@ qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
struct qla2xxx_mq_chain *mq = ptr;
device_reg_t __iomem *reg;
- if (!ha->mqenable || IS_QLA83XX(ha))
+ if (!ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha))
return ptr;
mq = ptr;
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index 35e20b4f8b6c..cc961040f8b1 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -348,3 +348,10 @@ ql_log_pci(uint32_t, struct pci_dev *pdev, int32_t, const char *fmt, ...);
#define ql_dbg_tgt 0x00004000 /* Target mode */
#define ql_dbg_tgt_mgt 0x00002000 /* Target mode management */
#define ql_dbg_tgt_tmr 0x00001000 /* Target mode task management */
+
+extern int qla27xx_dump_mpi_ram(struct qla_hw_data *, uint32_t, uint32_t *,
+ uint32_t, void **);
+extern int qla24xx_dump_ram(struct qla_hw_data *, uint32_t, uint32_t *,
+ uint32_t, void **);
+extern int qla24xx_pause_risc(struct device_reg_24xx __iomem *);
+extern int qla24xx_soft_reset(struct qla_hw_data *);
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index e1fe95ef23e1..6a106136716c 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -654,7 +654,7 @@ typedef union {
struct device_reg_25xxmq isp25mq;
struct device_reg_82xx isp82;
struct device_reg_fx00 ispfx00;
-} device_reg_t;
+} __iomem device_reg_t;
#define ISP_REQ_Q_IN(ha, reg) \
(IS_QLA2100(ha) || IS_QLA2200(ha) ? \
@@ -808,7 +808,7 @@ struct mbx_cmd_32 {
Notification */
#define MBA_FW_POLL_STATE 0x8600 /* Firmware in poll diagnostic state */
#define MBA_FW_RESET_FCT 0x8502 /* Firmware reset factory defaults */
-
+#define MBA_FW_INIT_INPROGRESS 0x8500 /* Firmware boot in progress */
/* 83XX FCoE specific */
#define MBA_IDC_AEN 0x8200 /* FCoE: NIC Core state change AEN */
@@ -938,6 +938,7 @@ struct mbx_cmd_32 {
*/
#define MBC_WRITE_SERDES 0x3 /* Write serdes word. */
#define MBC_READ_SERDES 0x4 /* Read serdes word. */
+#define MBC_LOAD_DUMP_MPI_RAM 0x5 /* Load/Dump MPI RAM. */
#define MBC_SERDES_PARAMS 0x10 /* Serdes Tx Parameters. */
#define MBC_GET_IOCB_STATUS 0x12 /* Get IOCB status command. */
#define MBC_PORT_PARAMS 0x1A /* Port iDMA Parameters. */
@@ -1197,30 +1198,6 @@ typedef struct {
uint8_t reserved_3[26];
} init_cb_t;
-
-struct init_cb_fx {
- uint16_t version;
- uint16_t reserved_1[13];
- __le16 request_q_outpointer;
- __le16 response_q_inpointer;
- uint16_t reserved_2[2];
- __le16 response_q_length;
- __le16 request_q_length;
- uint16_t reserved_3[2];
- __le32 request_q_address[2];
- __le32 response_q_address[2];
- uint16_t reserved_4[4];
- uint8_t response_q_msivec;
- uint8_t reserved_5[19];
- uint16_t interrupt_delay_timer;
- uint16_t reserved_6;
- uint32_t fwoptions1;
- uint32_t fwoptions2;
- uint32_t fwoptions3;
- uint8_t reserved_7[24];
-};
-
-
/*
* Get Link Status mailbox command return buffer.
*/
@@ -2172,6 +2149,7 @@ struct ct_fdmi_hba_attributes {
#define FDMI_PORT_SPEED_4GB 0x8
#define FDMI_PORT_SPEED_8GB 0x10
#define FDMI_PORT_SPEED_16GB 0x20
+#define FDMI_PORT_SPEED_32GB 0x40
#define FDMI_PORT_SPEED_UNKNOWN 0x8000
struct ct_fdmi_port_attr {
@@ -2680,7 +2658,7 @@ struct bidi_statistics {
#define QLA_MQ_SIZE 32
#define QLA_MAX_QUEUES 256
#define ISP_QUE_REG(ha, id) \
- ((ha->mqenable || IS_QLA83XX(ha)) ? \
+ ((ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) ? \
((void __iomem *)ha->mqiobase + (QLA_QUE_PAGE * id)) :\
((void __iomem *)ha->iobase))
#define QLA_REQ_QUE_ID(tag) \
@@ -2818,7 +2796,6 @@ struct qla_hw_data {
uint32_t fac_supported :1;
uint32_t chip_reset_done :1;
- uint32_t port0 :1;
uint32_t running_gold_fw :1;
uint32_t eeh_busy :1;
uint32_t cpu_affinity_enabled :1;
@@ -2849,7 +2826,7 @@ struct qla_hw_data {
spinlock_t hardware_lock ____cacheline_aligned;
int bars;
int mem_only;
- device_reg_t __iomem *iobase; /* Base I/O address */
+ device_reg_t *iobase; /* Base I/O address */
resource_size_t pio_address;
#define MIN_IOBASE_LEN 0x100
@@ -2868,8 +2845,8 @@ struct qla_hw_data {
uint32_t rsp_que_off;
/* Multi queue data structs */
- device_reg_t __iomem *mqiobase;
- device_reg_t __iomem *msixbase;
+ device_reg_t *mqiobase;
+ device_reg_t *msixbase;
uint16_t msix_count;
uint8_t mqenable;
struct req_que **req_q_map;
@@ -2905,6 +2882,7 @@ struct qla_hw_data {
#define PORT_SPEED_4GB 0x03
#define PORT_SPEED_8GB 0x04
#define PORT_SPEED_16GB 0x05
+#define PORT_SPEED_32GB 0x06
#define PORT_SPEED_10GB 0x13
uint16_t link_data_rate; /* F/W operating speed */
@@ -2928,6 +2906,7 @@ struct qla_hw_data {
#define PCI_DEVICE_ID_QLOGIC_ISP8001 0x8001
#define PCI_DEVICE_ID_QLOGIC_ISP8031 0x8031
#define PCI_DEVICE_ID_QLOGIC_ISP2031 0x2031
+#define PCI_DEVICE_ID_QLOGIC_ISP2071 0x2071
uint32_t device_type;
#define DT_ISP2100 BIT_0
#define DT_ISP2200 BIT_1
@@ -2948,7 +2927,8 @@ struct qla_hw_data {
#define DT_ISP8031 BIT_16
#define DT_ISPFX00 BIT_17
#define DT_ISP8044 BIT_18
-#define DT_ISP_LAST (DT_ISP8044 << 1)
+#define DT_ISP2071 BIT_19
+#define DT_ISP_LAST (DT_ISP2071 << 1)
#define DT_T10_PI BIT_25
#define DT_IIDMA BIT_26
@@ -2978,6 +2958,7 @@ struct qla_hw_data {
#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)
+#define IS_QLA2071(ha) (DT_MASK(ha) & DT_ISP2071)
#define IS_QLA23XX(ha) (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \
IS_QLA6312(ha) || IS_QLA6322(ha))
@@ -2986,6 +2967,7 @@ struct qla_hw_data {
#define IS_QLA25XX(ha) (IS_QLA2532(ha))
#define IS_QLA83XX(ha) (IS_QLA2031(ha) || IS_QLA8031(ha))
#define IS_QLA84XX(ha) (IS_QLA8432(ha))
+#define IS_QLA27XX(ha) (IS_QLA2071(ha))
#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) || \
@@ -2994,12 +2976,13 @@ struct qla_hw_data {
#define IS_QLA2XXX_MIDTYPE(ha) (IS_QLA24XX(ha) || IS_QLA84XX(ha) || \
IS_QLA25XX(ha) || IS_QLA81XX(ha) || \
IS_QLA82XX(ha) || IS_QLA83XX(ha) || \
- IS_QLA8044(ha))
+ IS_QLA8044(ha) || IS_QLA27XX(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)
-#define IS_FAC_REQUIRED(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha))
-#define IS_NOCACHE_VPD_TYPE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha))
+#define IS_NOPOLLING_TYPE(ha) (IS_QLA81XX(ha) && (ha)->flags.msix_enabled)
+#define IS_FAC_REQUIRED(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha) || \
+ IS_QLA27XX(ha))
+#define IS_NOCACHE_VPD_TYPE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha) || \
+ IS_QLA27XX(ha))
#define IS_ALOGIO_CAPABLE(ha) (IS_QLA23XX(ha) || IS_FWI2_CAPABLE(ha))
#define IS_T10_PI_CAPABLE(ha) ((ha)->device_type & DT_T10_PI)
@@ -3009,7 +2992,8 @@ struct qla_hw_data {
#define IS_OEM_001(ha) ((ha)->device_type & DT_OEM_001)
#define HAS_EXTENDED_IDS(ha) ((ha)->device_type & DT_EXTENDED_IDS)
#define IS_CT6_SUPPORTED(ha) ((ha)->device_type & DT_CT6_SUPPORTED)
-#define IS_MQUE_CAPABLE(ha) ((ha)->mqenable || IS_QLA83XX(ha))
+#define IS_MQUE_CAPABLE(ha) ((ha)->mqenable || IS_QLA83XX(ha) || \
+ IS_QLA27XX(ha))
#define IS_BIDI_CAPABLE(ha) ((IS_QLA25XX(ha) || IS_QLA2031(ha)))
/* Bit 21 of fw_attributes decides the MCTP capabilities */
#define IS_MCTP_CAPABLE(ha) (IS_QLA2031(ha) && \
@@ -3134,6 +3118,9 @@ struct qla_hw_data {
uint16_t fw_xcb_count;
uint16_t fw_iocb_count;
+ uint32_t fw_shared_ram_start;
+ uint32_t fw_shared_ram_end;
+
uint16_t fw_options[16]; /* slots: 1,2,3,10,11 */
uint8_t fw_seriallink_options[4];
uint16_t fw_seriallink_options24[4];
@@ -3142,6 +3129,9 @@ struct qla_hw_data {
uint32_t mpi_capabilities;
uint8_t phy_version[3];
+ /* Firmware dump template */
+ void *fw_dump_template;
+ uint32_t fw_dump_template_len;
/* Firmware dump information. */
struct qla2xxx_fw_dump *fw_dump;
uint32_t fw_dump_len;
@@ -3184,6 +3174,7 @@ struct qla_hw_data {
#define QLA_SWRITING 2
uint32_t optrom_region_start;
uint32_t optrom_region_size;
+ struct mutex optrom_mutex;
/* PCI expansion ROM image information. */
#define ROM_CODE_TYPE_BIOS 0
@@ -3310,6 +3301,7 @@ struct qla_hw_data {
struct mr_data_fx00 mr;
struct qlt_hw_data tgt;
+ int allow_cna_fw_dump;
};
/*
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 792a29294b62..32ab80957688 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -114,7 +114,8 @@ qla2x00_dfs_setup(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
- if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha))
+ if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
+ !IS_QLA27XX(ha))
goto out;
if (!ha->fce)
goto out;
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 610d3aa905a0..3a7353eaccbd 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -1378,6 +1378,10 @@ struct qla_flt_header {
#define FLT_REG_NVRAM_0 0x15
#define FLT_REG_VPD_1 0x16
#define FLT_REG_NVRAM_1 0x17
+#define FLT_REG_VPD_2 0xD4
+#define FLT_REG_NVRAM_2 0xD5
+#define FLT_REG_VPD_3 0xD6
+#define FLT_REG_NVRAM_3 0xD7
#define FLT_REG_FDT 0x1a
#define FLT_REG_FLT 0x1c
#define FLT_REG_HW_EVENT_0 0x1d
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 1f426628a0a5..e665e8109933 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -330,6 +330,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *, struct link_statistics *,
dma_addr_t);
extern int qla24xx_abort_command(srb_t *);
+extern int qla24xx_async_abort_command(srb_t *);
extern int
qla24xx_abort_target(struct fc_port *, unsigned int, int);
extern int
@@ -511,6 +512,16 @@ extern void qla2300_fw_dump(scsi_qla_host_t *, int);
extern void qla24xx_fw_dump(scsi_qla_host_t *, int);
extern void qla25xx_fw_dump(scsi_qla_host_t *, int);
extern void qla81xx_fw_dump(scsi_qla_host_t *, int);
+extern void qla82xx_fw_dump(scsi_qla_host_t *, int);
+extern void qla8044_fw_dump(scsi_qla_host_t *, int);
+
+extern void qla27xx_fwdump(scsi_qla_host_t *, int);
+extern ulong qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host *);
+extern int qla27xx_fwdt_template_valid(void *);
+extern ulong qla27xx_fwdt_template_size(void *);
+extern const void *qla27xx_fwdt_template_default(void);
+extern ulong qla27xx_fwdt_template_default_size(void);
+
extern void qla2x00_dump_regs(scsi_qla_host_t *);
extern void qla2x00_dump_buffer(uint8_t *, uint32_t);
extern void qla2x00_dump_buffer_zipped(uint8_t *, uint32_t);
@@ -594,7 +605,6 @@ extern char *qlafx00_fw_version_str(struct scsi_qla_host *, char *);
extern irqreturn_t qlafx00_intr_handler(int, void *);
extern void qlafx00_enable_intrs(struct qla_hw_data *);
extern void qlafx00_disable_intrs(struct qla_hw_data *);
-extern int qlafx00_abort_command(srb_t *);
extern int qlafx00_abort_target(fc_port_t *, unsigned int, int);
extern int qlafx00_lun_reset(fc_port_t *, unsigned int, int);
extern int qlafx00_start_scsi(srb_t *);
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index cd47f1b32d9a..e377f9d2f92a 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -1532,6 +1532,10 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
if (IS_CNA_CAPABLE(ha))
eiter->a.sup_speed = __constant_cpu_to_be32(
FDMI_PORT_SPEED_10GB);
+ else if (IS_QLA27XX(ha))
+ eiter->a.sup_speed = __constant_cpu_to_be32(
+ FDMI_PORT_SPEED_32GB|FDMI_PORT_SPEED_16GB|
+ FDMI_PORT_SPEED_8GB);
else if (IS_QLA25XX(ha))
eiter->a.sup_speed = __constant_cpu_to_be32(
FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB|
@@ -1580,6 +1584,10 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
eiter->a.cur_speed =
__constant_cpu_to_be32(FDMI_PORT_SPEED_16GB);
break;
+ case PORT_SPEED_32GB:
+ eiter->a.cur_speed =
+ __constant_cpu_to_be32(FDMI_PORT_SPEED_32GB);
+ break;
default:
eiter->a.cur_speed =
__constant_cpu_to_be32(FDMI_PORT_SPEED_UNKNOWN);
@@ -1889,6 +1897,9 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list)
case BIT_10:
list[i].fp_speed = PORT_SPEED_16GB;
break;
+ case BIT_8:
+ list[i].fp_speed = PORT_SPEED_32GB;
+ break;
}
ql_dbg(ql_dbg_disc, vha, 0x205b,
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index e7e5f4facf7f..38aeb54cd9d8 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -271,56 +271,46 @@ done:
}
static void
-qla2x00_async_tm_cmd_done(void *data, void *ptr, int res)
+qla2x00_tmf_iocb_timeout(void *data)
{
- srb_t *sp = (srb_t *)ptr;
- struct srb_iocb *iocb = &sp->u.iocb_cmd;
- struct scsi_qla_host *vha = (scsi_qla_host_t *)data;
- uint32_t flags;
- uint16_t lun;
- int rval;
-
- if (!test_bit(UNLOADING, &vha->dpc_flags)) {
- flags = iocb->u.tmf.flags;
- lun = (uint16_t)iocb->u.tmf.lun;
+ srb_t *sp = (srb_t *)data;
+ struct srb_iocb *tmf = &sp->u.iocb_cmd;
- /* Issue Marker IOCB */
- rval = qla2x00_marker(vha, vha->hw->req_q_map[0],
- vha->hw->rsp_q_map[0], sp->fcport->loop_id, lun,
- flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);
+ tmf->u.tmf.comp_status = CS_TIMEOUT;
+ complete(&tmf->u.tmf.comp);
+}
- if ((rval != QLA_SUCCESS) || iocb->u.tmf.data) {
- ql_dbg(ql_dbg_taskm, vha, 0x8030,
- "TM IOCB failed (%x).\n", rval);
- }
- }
- sp->free(sp->fcport->vha, sp);
+static void
+qla2x00_tmf_sp_done(void *data, void *ptr, int res)
+{
+ srb_t *sp = (srb_t *)ptr;
+ struct srb_iocb *tmf = &sp->u.iocb_cmd;
+ complete(&tmf->u.tmf.comp);
}
int
-qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t tm_flags, uint32_t lun,
+qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
uint32_t tag)
{
struct scsi_qla_host *vha = fcport->vha;
+ struct srb_iocb *tm_iocb;
srb_t *sp;
- struct srb_iocb *tcf;
- int rval;
+ int rval = QLA_FUNCTION_FAILED;
- rval = QLA_FUNCTION_FAILED;
sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
if (!sp)
goto done;
+ tm_iocb = &sp->u.iocb_cmd;
sp->type = SRB_TM_CMD;
sp->name = "tmf";
- qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
-
- tcf = &sp->u.iocb_cmd;
- tcf->u.tmf.flags = tm_flags;
- tcf->u.tmf.lun = lun;
- tcf->u.tmf.data = tag;
- tcf->timeout = qla2x00_async_iocb_timeout;
- sp->done = qla2x00_async_tm_cmd_done;
+ qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha));
+ tm_iocb->u.tmf.flags = flags;
+ tm_iocb->u.tmf.lun = lun;
+ tm_iocb->u.tmf.data = tag;
+ sp->done = qla2x00_tmf_sp_done;
+ tm_iocb->timeout = qla2x00_tmf_iocb_timeout;
+ init_completion(&tm_iocb->u.tmf.comp);
rval = qla2x00_start_sp(sp);
if (rval != QLA_SUCCESS)
@@ -330,14 +320,121 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t tm_flags, uint32_t lun,
"Async-tmf hdl=%x loop-id=%x portid=%02x%02x%02x.\n",
sp->handle, fcport->loop_id, fcport->d_id.b.domain,
fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+ wait_for_completion(&tm_iocb->u.tmf.comp);
+
+ rval = tm_iocb->u.tmf.comp_status == CS_COMPLETE ?
+ QLA_SUCCESS : QLA_FUNCTION_FAILED;
+
+ if ((rval != QLA_SUCCESS) || tm_iocb->u.tmf.data) {
+ ql_dbg(ql_dbg_taskm, vha, 0x8030,
+ "TM IOCB failed (%x).\n", rval);
+ }
+
+ if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw)) {
+ flags = tm_iocb->u.tmf.flags;
+ lun = (uint16_t)tm_iocb->u.tmf.lun;
+
+ /* Issue Marker IOCB */
+ qla2x00_marker(vha, vha->hw->req_q_map[0],
+ vha->hw->rsp_q_map[0], sp->fcport->loop_id, lun,
+ flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);
+ }
+
+done_free_sp:
+ sp->free(vha, sp);
+done:
return rval;
+}
+
+static void
+qla24xx_abort_iocb_timeout(void *data)
+{
+ srb_t *sp = (srb_t *)data;
+ struct srb_iocb *abt = &sp->u.iocb_cmd;
+
+ abt->u.abt.comp_status = CS_TIMEOUT;
+ complete(&abt->u.abt.comp);
+}
+
+static void
+qla24xx_abort_sp_done(void *data, void *ptr, int res)
+{
+ srb_t *sp = (srb_t *)ptr;
+ struct srb_iocb *abt = &sp->u.iocb_cmd;
+
+ complete(&abt->u.abt.comp);
+}
+
+static int
+qla24xx_async_abort_cmd(srb_t *cmd_sp)
+{
+ scsi_qla_host_t *vha = cmd_sp->fcport->vha;
+ fc_port_t *fcport = cmd_sp->fcport;
+ struct srb_iocb *abt_iocb;
+ srb_t *sp;
+ int rval = QLA_FUNCTION_FAILED;
+
+ sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+ if (!sp)
+ goto done;
+
+ abt_iocb = &sp->u.iocb_cmd;
+ sp->type = SRB_ABT_CMD;
+ sp->name = "abort";
+ qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha));
+ abt_iocb->u.abt.cmd_hndl = cmd_sp->handle;
+ sp->done = qla24xx_abort_sp_done;
+ abt_iocb->timeout = qla24xx_abort_iocb_timeout;
+ init_completion(&abt_iocb->u.abt.comp);
+
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS)
+ goto done_free_sp;
+
+ ql_dbg(ql_dbg_async, vha, 0x507c,
+ "Abort command issued - hdl=%x, target_id=%x\n",
+ cmd_sp->handle, fcport->tgt_id);
+
+ wait_for_completion(&abt_iocb->u.abt.comp);
+
+ rval = abt_iocb->u.abt.comp_status == CS_COMPLETE ?
+ QLA_SUCCESS : QLA_FUNCTION_FAILED;
done_free_sp:
- sp->free(fcport->vha, sp);
+ sp->free(vha, sp);
done:
return rval;
}
+int
+qla24xx_async_abort_command(srb_t *sp)
+{
+ unsigned long flags = 0;
+
+ uint32_t handle;
+ fc_port_t *fcport = sp->fcport;
+ struct scsi_qla_host *vha = fcport->vha;
+ struct qla_hw_data *ha = vha->hw;
+ struct req_que *req = vha->req;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ for (handle = 1; handle < req->num_outstanding_cmds; handle++) {
+ if (req->outstanding_cmds[handle] == sp)
+ break;
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ if (handle == req->num_outstanding_cmds) {
+ /* Command not found. */
+ return QLA_FUNCTION_FAILED;
+ }
+ if (sp->type == SRB_FXIOCB_DCMD)
+ return qlafx00_fx_disc(vha, &vha->hw->mr.fcport,
+ FXDISC_ABORT_IOCTL);
+
+ return qla24xx_async_abort_cmd(sp);
+}
+
void
qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
uint16_t *data)
@@ -1379,7 +1476,12 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
}
ha->fw_dumped = 0;
- fixed_size = mem_size = eft_size = fce_size = mq_size = 0;
+ dump_size = fixed_size = mem_size = eft_size = fce_size = mq_size = 0;
+ req_q_size = rsp_q_size = 0;
+
+ if (IS_QLA27XX(ha))
+ goto try_fce;
+
if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
fixed_size = sizeof(struct qla2100_fw_dump);
} else if (IS_QLA23XX(ha)) {
@@ -1395,6 +1497,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
fixed_size = offsetof(struct qla25xx_fw_dump, ext_mem);
else
fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem);
+
mem_size = (ha->fw_memory_size - 0x100000 + 1) *
sizeof(uint32_t);
if (ha->mqenable) {
@@ -1412,9 +1515,16 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
if (ha->tgt.atio_ring)
mq_size += ha->tgt.atio_q_length * sizeof(request_t);
/* Allocate memory for Fibre Channel Event Buffer. */
- if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha))
+ if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
+ !IS_QLA27XX(ha))
goto try_eft;
+try_fce:
+ if (ha->fce)
+ dma_free_coherent(&ha->pdev->dev,
+ FCE_SIZE, ha->fce, ha->fce_dma);
+
+ /* Allocate memory for Fibre Channel Event Buffer. */
tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
GFP_KERNEL);
if (!tc) {
@@ -1442,7 +1552,12 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
ha->flags.fce_enabled = 1;
ha->fce_dma = tc_dma;
ha->fce = tc;
+
try_eft:
+ if (ha->eft)
+ dma_free_coherent(&ha->pdev->dev,
+ EFT_SIZE, ha->eft, ha->eft_dma);
+
/* Allocate memory for Extended Trace Buffer. */
tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
GFP_KERNEL);
@@ -1469,15 +1584,28 @@ try_eft:
ha->eft_dma = tc_dma;
ha->eft = tc;
}
+
cont_alloc:
+ if (IS_QLA27XX(ha)) {
+ if (!ha->fw_dump_template) {
+ ql_log(ql_log_warn, vha, 0x00ba,
+ "Failed missing fwdump template\n");
+ return;
+ }
+ dump_size = qla27xx_fwdt_calculate_dump_size(vha);
+ ql_dbg(ql_dbg_init, vha, 0x00fa,
+ "-> allocating fwdump (%x bytes)...\n", dump_size);
+ goto allocate;
+ }
+
req_q_size = req->length * sizeof(request_t);
rsp_q_size = rsp->length * sizeof(response_t);
-
dump_size = offsetof(struct qla2xxx_fw_dump, isp);
dump_size += fixed_size + mem_size + req_q_size + rsp_q_size + eft_size;
ha->chain_offset = dump_size;
dump_size += mq_size + fce_size;
+allocate:
ha->fw_dump = vmalloc(dump_size);
if (!ha->fw_dump) {
ql_log(ql_log_warn, vha, 0x00c4,
@@ -1499,10 +1627,13 @@ cont_alloc:
}
return;
}
+ ha->fw_dump_len = dump_size;
ql_dbg(ql_dbg_init, vha, 0x00c5,
"Allocated (%d KB) for firmware dump.\n", dump_size / 1024);
- ha->fw_dump_len = dump_size;
+ if (IS_QLA27XX(ha))
+ return;
+
ha->fw_dump->signature[0] = 'Q';
ha->fw_dump->signature[1] = 'L';
ha->fw_dump->signature[2] = 'G';
@@ -1718,9 +1849,6 @@ enable_82xx_npiv:
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
- if (IS_QLA83XX(ha))
- goto skip_fac_check;
-
if (rval == QLA_SUCCESS && IS_FAC_REQUIRED(ha)) {
uint32_t size;
@@ -1733,8 +1861,8 @@ enable_82xx_npiv:
"Unsupported FAC firmware (%d.%02d.%02d).\n",
ha->fw_major_version, ha->fw_minor_version,
ha->fw_subminor_version);
-skip_fac_check:
- if (IS_QLA83XX(ha)) {
+
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
ha->flags.fac_supported = 0;
rval = QLA_SUCCESS;
}
@@ -1933,7 +2061,7 @@ qla24xx_config_rings(struct scsi_qla_host *vha)
icb->atio_q_address[0] = cpu_to_le32(LSD(ha->tgt.atio_dma));
icb->atio_q_address[1] = cpu_to_le32(MSD(ha->tgt.atio_dma));
- if (ha->mqenable || IS_QLA83XX(ha)) {
+ if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
icb->qos = __constant_cpu_to_le16(QLA_DEFAULT_QUE_QOS);
icb->rid = __constant_cpu_to_le16(rid);
if (ha->flags.msix_enabled) {
@@ -4792,13 +4920,14 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
nv = ha->nvram;
/* Determine NVRAM starting address. */
- if (ha->flags.port0) {
+ if (ha->port_no == 0) {
ha->nvram_base = FA_NVRAM_FUNC0_ADDR;
ha->vpd_base = FA_NVRAM_VPD0_ADDR;
} else {
ha->nvram_base = FA_NVRAM_FUNC1_ADDR;
ha->vpd_base = FA_NVRAM_VPD1_ADDR;
}
+
ha->nvram_size = sizeof(struct nvram_24xx);
ha->vpd_size = FA_NVRAM_VPD_SIZE;
@@ -4842,7 +4971,7 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
nv->exchange_count = __constant_cpu_to_le16(0);
nv->hard_address = __constant_cpu_to_le16(124);
nv->port_name[0] = 0x21;
- nv->port_name[1] = 0x00 + ha->port_no;
+ nv->port_name[1] = 0x00 + ha->port_no + 1;
nv->port_name[2] = 0x00;
nv->port_name[3] = 0xe0;
nv->port_name[4] = 0x8b;
@@ -5117,6 +5246,99 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
segments--;
}
+ if (!IS_QLA27XX(ha))
+ return rval;
+
+ if (ha->fw_dump_template)
+ vfree(ha->fw_dump_template);
+ ha->fw_dump_template = NULL;
+ ha->fw_dump_template_len = 0;
+
+ ql_dbg(ql_dbg_init, vha, 0x0161,
+ "Loading fwdump template from %x\n", faddr);
+ qla24xx_read_flash_data(vha, dcode, faddr, 7);
+ risc_size = be32_to_cpu(dcode[2]);
+ ql_dbg(ql_dbg_init, vha, 0x0162,
+ "-> array size %x dwords\n", risc_size);
+ if (risc_size == 0 || risc_size == ~0)
+ goto default_template;
+
+ dlen = (risc_size - 8) * sizeof(*dcode);
+ ql_dbg(ql_dbg_init, vha, 0x0163,
+ "-> template allocating %x bytes...\n", dlen);
+ ha->fw_dump_template = vmalloc(dlen);
+ if (!ha->fw_dump_template) {
+ ql_log(ql_log_warn, vha, 0x0164,
+ "Failed fwdump template allocate %x bytes.\n", risc_size);
+ goto default_template;
+ }
+
+ faddr += 7;
+ risc_size -= 8;
+ dcode = ha->fw_dump_template;
+ qla24xx_read_flash_data(vha, dcode, faddr, risc_size);
+ for (i = 0; i < risc_size; i++)
+ dcode[i] = le32_to_cpu(dcode[i]);
+
+ if (!qla27xx_fwdt_template_valid(dcode)) {
+ ql_log(ql_log_warn, vha, 0x0165,
+ "Failed fwdump template validate\n");
+ goto default_template;
+ }
+
+ dlen = qla27xx_fwdt_template_size(dcode);
+ ql_dbg(ql_dbg_init, vha, 0x0166,
+ "-> template size %x bytes\n", dlen);
+ if (dlen > risc_size * sizeof(*dcode)) {
+ ql_log(ql_log_warn, vha, 0x0167,
+ "Failed fwdump template exceeds array by %x bytes\n",
+ (uint32_t)(dlen - risc_size * sizeof(*dcode)));
+ goto default_template;
+ }
+ ha->fw_dump_template_len = dlen;
+ return rval;
+
+default_template:
+ ql_log(ql_log_warn, vha, 0x0168, "Using default fwdump template\n");
+ if (ha->fw_dump_template)
+ vfree(ha->fw_dump_template);
+ ha->fw_dump_template = NULL;
+ ha->fw_dump_template_len = 0;
+
+ dlen = qla27xx_fwdt_template_default_size();
+ ql_dbg(ql_dbg_init, vha, 0x0169,
+ "-> template allocating %x bytes...\n", dlen);
+ ha->fw_dump_template = vmalloc(dlen);
+ if (!ha->fw_dump_template) {
+ ql_log(ql_log_warn, vha, 0x016a,
+ "Failed fwdump template allocate %x bytes.\n", risc_size);
+ goto failed_template;
+ }
+
+ dcode = ha->fw_dump_template;
+ risc_size = dlen / sizeof(*dcode);
+ memcpy(dcode, qla27xx_fwdt_template_default(), dlen);
+ for (i = 0; i < risc_size; i++)
+ dcode[i] = be32_to_cpu(dcode[i]);
+
+ if (!qla27xx_fwdt_template_valid(ha->fw_dump_template)) {
+ ql_log(ql_log_warn, vha, 0x016b,
+ "Failed fwdump template validate\n");
+ goto failed_template;
+ }
+
+ dlen = qla27xx_fwdt_template_size(ha->fw_dump_template);
+ ql_dbg(ql_dbg_init, vha, 0x016c,
+ "-> template size %x bytes\n", dlen);
+ ha->fw_dump_template_len = dlen;
+ return rval;
+
+failed_template:
+ ql_log(ql_log_warn, vha, 0x016d, "Failed default fwdump template\n");
+ if (ha->fw_dump_template)
+ vfree(ha->fw_dump_template);
+ ha->fw_dump_template = NULL;
+ ha->fw_dump_template_len = 0;
return rval;
}
@@ -5231,7 +5453,8 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
uint32_t risc_size;
uint32_t i;
struct fw_blob *blob;
- uint32_t *fwcode, fwclen;
+ const uint32_t *fwcode;
+ uint32_t fwclen;
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
@@ -5263,7 +5486,7 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
ql_log(ql_log_fatal, vha, 0x0093,
"Unable to verify integrity of firmware image (%Zd).\n",
blob->fw->size);
- goto fail_fw_integrity;
+ return QLA_FUNCTION_FAILED;
}
for (i = 0; i < 4; i++)
dcode[i] = be32_to_cpu(fwcode[i + 4]);
@@ -5277,7 +5500,7 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
ql_log(ql_log_fatal, vha, 0x0095,
"Firmware data: %08x %08x %08x %08x.\n",
dcode[0], dcode[1], dcode[2], dcode[3]);
- goto fail_fw_integrity;
+ return QLA_FUNCTION_FAILED;
}
while (segments && rval == QLA_SUCCESS) {
@@ -5291,8 +5514,7 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
ql_log(ql_log_fatal, vha, 0x0096,
"Unable to verify integrity of firmware image "
"(%Zd).\n", blob->fw->size);
-
- goto fail_fw_integrity;
+ return QLA_FUNCTION_FAILED;
}
fragment = 0;
@@ -5326,10 +5548,100 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
/* Next segment. */
segments--;
}
+
+ if (!IS_QLA27XX(ha))
+ return rval;
+
+ if (ha->fw_dump_template)
+ vfree(ha->fw_dump_template);
+ ha->fw_dump_template = NULL;
+ ha->fw_dump_template_len = 0;
+
+ ql_dbg(ql_dbg_init, vha, 0x171,
+ "Loading fwdump template from %x\n",
+ (uint32_t)((void *)fwcode - (void *)blob->fw->data));
+ risc_size = be32_to_cpu(fwcode[2]);
+ ql_dbg(ql_dbg_init, vha, 0x172,
+ "-> array size %x dwords\n", risc_size);
+ if (risc_size == 0 || risc_size == ~0)
+ goto default_template;
+
+ dlen = (risc_size - 8) * sizeof(*fwcode);
+ ql_dbg(ql_dbg_init, vha, 0x0173,
+ "-> template allocating %x bytes...\n", dlen);
+ ha->fw_dump_template = vmalloc(dlen);
+ if (!ha->fw_dump_template) {
+ ql_log(ql_log_warn, vha, 0x0174,
+ "Failed fwdump template allocate %x bytes.\n", risc_size);
+ goto default_template;
+ }
+
+ fwcode += 7;
+ risc_size -= 8;
+ dcode = ha->fw_dump_template;
+ for (i = 0; i < risc_size; i++)
+ dcode[i] = le32_to_cpu(fwcode[i]);
+
+ if (!qla27xx_fwdt_template_valid(dcode)) {
+ ql_log(ql_log_warn, vha, 0x0175,
+ "Failed fwdump template validate\n");
+ goto default_template;
+ }
+
+ dlen = qla27xx_fwdt_template_size(dcode);
+ ql_dbg(ql_dbg_init, vha, 0x0176,
+ "-> template size %x bytes\n", dlen);
+ if (dlen > risc_size * sizeof(*fwcode)) {
+ ql_log(ql_log_warn, vha, 0x0177,
+ "Failed fwdump template exceeds array by %x bytes\n",
+ (uint32_t)(dlen - risc_size * sizeof(*fwcode)));
+ goto default_template;
+ }
+ ha->fw_dump_template_len = dlen;
return rval;
-fail_fw_integrity:
- return QLA_FUNCTION_FAILED;
+default_template:
+ ql_log(ql_log_warn, vha, 0x0178, "Using default fwdump template\n");
+ if (ha->fw_dump_template)
+ vfree(ha->fw_dump_template);
+ ha->fw_dump_template = NULL;
+ ha->fw_dump_template_len = 0;
+
+ dlen = qla27xx_fwdt_template_default_size();
+ ql_dbg(ql_dbg_init, vha, 0x0179,
+ "-> template allocating %x bytes...\n", dlen);
+ ha->fw_dump_template = vmalloc(dlen);
+ if (!ha->fw_dump_template) {
+ ql_log(ql_log_warn, vha, 0x017a,
+ "Failed fwdump template allocate %x bytes.\n", risc_size);
+ goto failed_template;
+ }
+
+ dcode = ha->fw_dump_template;
+ risc_size = dlen / sizeof(*fwcode);
+ fwcode = qla27xx_fwdt_template_default();
+ for (i = 0; i < risc_size; i++)
+ dcode[i] = be32_to_cpu(fwcode[i]);
+
+ if (!qla27xx_fwdt_template_valid(ha->fw_dump_template)) {
+ ql_log(ql_log_warn, vha, 0x017b,
+ "Failed fwdump template validate\n");
+ goto failed_template;
+ }
+
+ dlen = qla27xx_fwdt_template_size(ha->fw_dump_template);
+ ql_dbg(ql_dbg_init, vha, 0x017c,
+ "-> template size %x bytes\n", dlen);
+ ha->fw_dump_template_len = dlen;
+ return rval;
+
+failed_template:
+ ql_log(ql_log_warn, vha, 0x017d, "Failed default fwdump template\n");
+ if (ha->fw_dump_template)
+ vfree(ha->fw_dump_template);
+ ha->fw_dump_template = NULL;
+ ha->fw_dump_template_len = 0;
+ return rval;
}
int
@@ -5605,7 +5917,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
nv->execution_throttle = __constant_cpu_to_le16(0xFFFF);
nv->exchange_count = __constant_cpu_to_le16(0);
nv->port_name[0] = 0x21;
- nv->port_name[1] = 0x00 + ha->port_no;
+ nv->port_name[1] = 0x00 + ha->port_no + 1;
nv->port_name[2] = 0x00;
nv->port_name[3] = 0xe0;
nv->port_name[4] = 0x8b;
@@ -5639,7 +5951,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
nv->enode_mac[2] = 0xDD;
nv->enode_mac[3] = 0x04;
nv->enode_mac[4] = 0x05;
- nv->enode_mac[5] = 0x06 + ha->port_no;
+ nv->enode_mac[5] = 0x06 + ha->port_no + 1;
rval = 1;
}
@@ -5677,7 +5989,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
icb->enode_mac[2] = 0xDD;
icb->enode_mac[3] = 0x04;
icb->enode_mac[4] = 0x05;
- icb->enode_mac[5] = 0x06 + ha->port_no;
+ icb->enode_mac[5] = 0x06 + ha->port_no + 1;
}
/* Use extended-initialization control block. */
@@ -5780,7 +6092,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
ha->login_retry_count = ql2xloginretrycount;
/* if not running MSI-X we need handshaking on interrupts */
- if (!vha->hw->flags.msix_enabled && IS_QLA83XX(ha))
+ if (!vha->hw->flags.msix_enabled && (IS_QLA83XX(ha) || IS_QLA27XX(ha)))
icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_22);
/* Enable ZIO. */
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 46b9307e8be4..e607568bce49 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -488,7 +488,7 @@ qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req)
req->ring_ptr++;
/* Set chip new ring index. */
- if (ha->mqenable || IS_QLA83XX(ha)) {
+ if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
WRT_REG_DWORD(req->req_q_in, req->ring_index);
RD_REG_DWORD_RELAXED(&ha->iobase->isp24.hccr);
} else if (IS_QLAFX00(ha)) {
@@ -524,7 +524,6 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req,
{
mrk_entry_t *mrk;
struct mrk_entry_24xx *mrk24 = NULL;
- struct mrk_entry_fx00 *mrkfx = NULL;
struct qla_hw_data *ha = vha->hw;
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
@@ -541,15 +540,7 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req,
mrk->entry_type = MARKER_TYPE;
mrk->modifier = type;
if (type != MK_SYNC_ALL) {
- if (IS_QLAFX00(ha)) {
- mrkfx = (struct mrk_entry_fx00 *) mrk;
- mrkfx->handle = MAKE_HANDLE(req->id, mrkfx->handle);
- mrkfx->handle_hi = 0;
- mrkfx->tgt_id = cpu_to_le16(loop_id);
- mrkfx->lun[1] = LSB(lun);
- mrkfx->lun[2] = MSB(lun);
- host_to_fcp_swap(mrkfx->lun, sizeof(mrkfx->lun));
- } else if (IS_FWI2_CAPABLE(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mrk24 = (struct mrk_entry_24xx *) mrk;
mrk24->nport_handle = cpu_to_le16(loop_id);
mrk24->lun[1] = LSB(lun);
@@ -1823,7 +1814,7 @@ qla2x00_alloc_iocbs(scsi_qla_host_t *vha, srb_t *sp)
/* Check for room in outstanding command list. */
handle = req->current_outstanding_cmd;
- for (index = 1; req->num_outstanding_cmds; index++) {
+ for (index = 1; index < req->num_outstanding_cmds; index++) {
handle++;
if (handle == req->num_outstanding_cmds)
handle = 1;
@@ -1848,7 +1839,7 @@ qla2x00_alloc_iocbs(scsi_qla_host_t *vha, srb_t *sp)
skip_cmd_array:
/* Check for room on request queue. */
if (req->cnt < req_cnt) {
- if (ha->mqenable || IS_QLA83XX(ha))
+ if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha))
cnt = RD_REG_DWORD(&reg->isp25mq.req_q_out);
else if (IS_P3P_TYPE(ha))
cnt = RD_REG_DWORD(&reg->isp82.req_q_out);
@@ -2594,6 +2585,29 @@ queuing_error:
return QLA_FUNCTION_FAILED;
}
+void
+qla24xx_abort_iocb(srb_t *sp, struct abort_entry_24xx *abt_iocb)
+{
+ struct srb_iocb *aio = &sp->u.iocb_cmd;
+ scsi_qla_host_t *vha = sp->fcport->vha;
+ struct req_que *req = vha->req;
+
+ memset(abt_iocb, 0, sizeof(struct abort_entry_24xx));
+ abt_iocb->entry_type = ABORT_IOCB_TYPE;
+ abt_iocb->entry_count = 1;
+ abt_iocb->handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle));
+ abt_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
+ abt_iocb->handle_to_abort =
+ cpu_to_le32(MAKE_HANDLE(req->id, aio->u.abt.cmd_hndl));
+ abt_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
+ abt_iocb->port_id[1] = sp->fcport->d_id.b.area;
+ abt_iocb->port_id[2] = sp->fcport->d_id.b.domain;
+ abt_iocb->vp_index = vha->vp_idx;
+ abt_iocb->req_que_no = cpu_to_le16(req->id);
+ /* Send the command to the firmware */
+ wmb();
+}
+
int
qla2x00_start_sp(srb_t *sp)
{
@@ -2647,7 +2661,9 @@ qla2x00_start_sp(srb_t *sp)
qlafx00_fxdisc_iocb(sp, pkt);
break;
case SRB_ABT_CMD:
- qlafx00_abort_iocb(sp, pkt);
+ IS_QLAFX00(ha) ?
+ qlafx00_abort_iocb(sp, pkt) :
+ qla24xx_abort_iocb(sp, pkt);
break;
default:
break;
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 9bc86b9e86b1..95314ef2e505 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -356,15 +356,16 @@ qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr)
const char *
qla2x00_get_link_speed_str(struct qla_hw_data *ha, uint16_t speed)
{
- static const char * const link_speeds[] = {
- "1", "2", "?", "4", "8", "16", "10"
+ static const char *const link_speeds[] = {
+ "1", "2", "?", "4", "8", "16", "32", "10"
};
+#define QLA_LAST_SPEED 7
if (IS_QLA2100(ha) || IS_QLA2200(ha))
return link_speeds[0];
else if (speed == 0x13)
- return link_speeds[6];
- else if (speed < 6)
+ return link_speeds[QLA_LAST_SPEED];
+ else if (speed < QLA_LAST_SPEED)
return link_speeds[speed];
else
return link_speeds[LS_UNKNOWN];
@@ -649,7 +650,7 @@ skip_rio:
break;
case MBA_SYSTEM_ERR: /* System Error */
- mbx = (IS_QLA81XX(ha) || IS_QLA83XX(ha)) ?
+ mbx = (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha)) ?
RD_REG_WORD(&reg24->mailbox7) : 0;
ql_log(ql_log_warn, vha, 0x5003,
"ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh "
@@ -666,7 +667,7 @@ skip_rio:
vha->device_flags |= DFLG_DEV_FAILED;
} else {
/* Check to see if MPI timeout occurred */
- if ((mbx & MBX_3) && (ha->flags.port0))
+ if ((mbx & MBX_3) && (ha->port_no == 0))
set_bit(MPI_RESET_NEEDED,
&vha->dpc_flags);
@@ -1497,8 +1498,7 @@ logio_done:
}
static void
-qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
- struct tsk_mgmt_entry *tsk)
+qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk)
{
const char func[] = "TMF-IOCB";
const char *type;
@@ -1506,7 +1506,6 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
srb_t *sp;
struct srb_iocb *iocb;
struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk;
- int error = 1;
sp = qla2x00_get_sp_from_handle(vha, func, req, tsk);
if (!sp)
@@ -1515,37 +1514,35 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
iocb = &sp->u.iocb_cmd;
type = sp->name;
fcport = sp->fcport;
+ iocb->u.tmf.data = QLA_SUCCESS;
if (sts->entry_status) {
ql_log(ql_log_warn, fcport->vha, 0x5038,
"Async-%s error - hdl=%x entry-status(%x).\n",
type, sp->handle, sts->entry_status);
+ iocb->u.tmf.data = QLA_FUNCTION_FAILED;
} else if (sts->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
ql_log(ql_log_warn, fcport->vha, 0x5039,
"Async-%s error - hdl=%x completion status(%x).\n",
type, sp->handle, sts->comp_status);
- } else if (!(le16_to_cpu(sts->scsi_status) &
+ iocb->u.tmf.data = QLA_FUNCTION_FAILED;
+ } else if ((le16_to_cpu(sts->scsi_status) &
SS_RESPONSE_INFO_LEN_VALID)) {
- ql_log(ql_log_warn, fcport->vha, 0x503a,
- "Async-%s error - hdl=%x no response info(%x).\n",
- type, sp->handle, sts->scsi_status);
- } else if (le32_to_cpu(sts->rsp_data_len) < 4) {
- ql_log(ql_log_warn, fcport->vha, 0x503b,
- "Async-%s error - hdl=%x not enough response(%d).\n",
- type, sp->handle, sts->rsp_data_len);
- } else if (sts->data[3]) {
- ql_log(ql_log_warn, fcport->vha, 0x503c,
- "Async-%s error - hdl=%x response(%x).\n",
- type, sp->handle, sts->data[3]);
- } else {
- error = 0;
+ if (le32_to_cpu(sts->rsp_data_len) < 4) {
+ ql_log(ql_log_warn, fcport->vha, 0x503b,
+ "Async-%s error - hdl=%x not enough response(%d).\n",
+ type, sp->handle, sts->rsp_data_len);
+ } else if (sts->data[3]) {
+ ql_log(ql_log_warn, fcport->vha, 0x503c,
+ "Async-%s error - hdl=%x response(%x).\n",
+ type, sp->handle, sts->data[3]);
+ iocb->u.tmf.data = QLA_FUNCTION_FAILED;
+ }
}
- if (error) {
- iocb->u.tmf.data = error;
+ if (iocb->u.tmf.data != QLA_SUCCESS)
ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5055,
(uint8_t *)sts, sizeof(*sts));
- }
sp->done(vha, sp, 0);
}
@@ -2025,6 +2022,12 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
return;
}
+ /* Task Management completion. */
+ if (sp->type == SRB_TM_CMD) {
+ qla24xx_tm_iocb_entry(vha, req, pkt);
+ return;
+ }
+
/* Fast path completion. */
if (comp_status == CS_COMPLETE && scsi_status == 0) {
qla2x00_process_completed_request(vha, req, handle);
@@ -2425,6 +2428,23 @@ qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
}
}
+static void
+qla24xx_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
+ struct abort_entry_24xx *pkt)
+{
+ const char func[] = "ABT_IOCB";
+ srb_t *sp;
+ struct srb_iocb *abt;
+
+ sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
+ if (!sp)
+ return;
+
+ abt = &sp->u.iocb_cmd;
+ abt->u.abt.comp_status = le32_to_cpu(pkt->nport_handle);
+ sp->done(vha, sp, 0);
+}
+
/**
* qla24xx_process_response_queue() - Process response queue entries.
* @ha: SCSI driver HA context
@@ -2474,10 +2494,6 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
qla24xx_logio_entry(vha, rsp->req,
(struct logio_entry_24xx *)pkt);
break;
- case TSK_MGMT_IOCB_TYPE:
- qla24xx_tm_iocb_entry(vha, rsp->req,
- (struct tsk_mgmt_entry *)pkt);
- break;
case CT_IOCB_TYPE:
qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
break;
@@ -2497,6 +2513,10 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
* from falling into default case
*/
break;
+ case ABORT_IOCB_TYPE:
+ qla24xx_abort_iocb_entry(vha, rsp->req,
+ (struct abort_entry_24xx *)pkt);
+ break;
default:
/* Type Not Supported. */
ql_dbg(ql_dbg_async, vha, 0x5042,
@@ -2525,7 +2545,8 @@ qla2xxx_check_risc_status(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
- if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha))
+ if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
+ !IS_QLA27XX(ha))
return;
rval = QLA_SUCCESS;
@@ -2880,6 +2901,7 @@ static int
qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
{
#define MIN_MSIX_COUNT 2
+#define ATIO_VECTOR 2
int i, ret;
struct msix_entry *entries;
struct qla_msix_entry *qentry;
@@ -2936,36 +2958,49 @@ msix_failed:
}
/* Enable MSI-X vectors for the base queue */
- for (i = 0; i < ha->msix_count; i++) {
+ for (i = 0; i < 2; i++) {
qentry = &ha->msix_entries[i];
- if (QLA_TGT_MODE_ENABLED() && IS_ATIO_MSIX_CAPABLE(ha)) {
- ret = request_irq(qentry->vector,
- qla83xx_msix_entries[i].handler,
- 0, qla83xx_msix_entries[i].name, rsp);
- } else if (IS_P3P_TYPE(ha)) {
+ if (IS_P3P_TYPE(ha))
ret = request_irq(qentry->vector,
qla82xx_msix_entries[i].handler,
0, qla82xx_msix_entries[i].name, rsp);
- } else {
+ else
ret = request_irq(qentry->vector,
msix_entries[i].handler,
0, msix_entries[i].name, rsp);
- }
- if (ret) {
- ql_log(ql_log_fatal, vha, 0x00cb,
- "MSI-X: unable to register handler -- %x/%d.\n",
- qentry->vector, ret);
- qla24xx_disable_msix(ha);
- ha->mqenable = 0;
- goto msix_out;
- }
+ if (ret)
+ goto msix_register_fail;
+ qentry->have_irq = 1;
+ qentry->rsp = rsp;
+ rsp->msix = qentry;
+ }
+
+ /*
+ * If target mode is enable, also request the vector for the ATIO
+ * queue.
+ */
+ if (QLA_TGT_MODE_ENABLED() && IS_ATIO_MSIX_CAPABLE(ha)) {
+ qentry = &ha->msix_entries[ATIO_VECTOR];
+ ret = request_irq(qentry->vector,
+ qla83xx_msix_entries[ATIO_VECTOR].handler,
+ 0, qla83xx_msix_entries[ATIO_VECTOR].name, rsp);
qentry->have_irq = 1;
qentry->rsp = rsp;
rsp->msix = qentry;
}
+msix_register_fail:
+ if (ret) {
+ ql_log(ql_log_fatal, vha, 0x00cb,
+ "MSI-X: unable to register handler -- %x/%d.\n",
+ qentry->vector, ret);
+ qla24xx_disable_msix(ha);
+ ha->mqenable = 0;
+ goto msix_out;
+ }
+
/* Enable MSI-X vector for response queue update for queue 0 */
- if (IS_QLA83XX(ha)) {
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
if (ha->msixbase && ha->mqiobase &&
(ha->max_rsp_queues > 1 || ha->max_req_queues > 1))
ha->mqenable = 1;
@@ -2989,12 +3024,13 @@ int
qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
{
int ret = QLA_FUNCTION_FAILED;
- device_reg_t __iomem *reg = ha->iobase;
+ device_reg_t *reg = ha->iobase;
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
/* If possible, enable MSI-X. */
if (!IS_QLA2432(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
- !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) && !IS_QLAFX00(ha))
+ !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) && !IS_QLAFX00(ha) &&
+ !IS_QLA27XX(ha))
goto skip_msi;
if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
@@ -3029,7 +3065,8 @@ skip_msix:
"Falling back-to MSI mode -%d.\n", ret);
if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
- !IS_QLA8001(ha) && !IS_P3P_TYPE(ha) && !IS_QLAFX00(ha))
+ !IS_QLA8001(ha) && !IS_P3P_TYPE(ha) && !IS_QLAFX00(ha) &&
+ !IS_QLA27XX(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 b94511ae0051..2528709c4add 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -35,7 +35,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
{
int rval;
unsigned long flags = 0;
- device_reg_t __iomem *reg;
+ device_reg_t *reg;
uint8_t abort_active;
uint8_t io_lock_on;
uint16_t command = 0;
@@ -468,7 +468,8 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
mcp->mb[1] = MSW(risc_addr);
mcp->mb[2] = LSW(risc_addr);
mcp->mb[3] = 0;
- if (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha)) {
+ if (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) ||
+ IS_QLA27XX(ha)) {
struct nvram_81xx *nv = ha->nvram;
mcp->mb[4] = (nv->enhanced_features &
EXTENDED_BB_CREDITS);
@@ -539,6 +540,8 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
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;
+ if (IS_QLA27XX(ha))
+ mcp->in_mb |= MBX_21|MBX_20|MBX_19|MBX_18;
mcp->flags = 0;
mcp->tov = MBX_TOV_SECONDS;
rval = qla2x00_mailbox_command(vha, mcp);
@@ -574,6 +577,10 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
"%s: Ext_FwAttributes Upper: 0x%x, Lower: 0x%x.\n",
__func__, mcp->mb[17], mcp->mb[16]);
}
+ if (IS_QLA27XX(ha)) {
+ ha->fw_shared_ram_start = (mcp->mb[19] << 16) | mcp->mb[18];
+ ha->fw_shared_ram_end = (mcp->mb[21] << 16) | mcp->mb[20];
+ }
failed:
if (rval != QLA_SUCCESS) {
@@ -1225,7 +1232,7 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
}
/* 1 and 2 should normally be captured. */
mcp->in_mb = MBX_2|MBX_1|MBX_0;
- if (IS_QLA83XX(ha))
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
/* mb3 is additional info about the installed SFP. */
mcp->in_mb |= MBX_3;
mcp->buf_size = size;
@@ -2349,7 +2356,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
mcp->mb[0] = MBC_GET_RESOURCE_COUNTS;
mcp->out_mb = MBX_0;
mcp->in_mb = MBX_11|MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
- if (IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw))
+ if (IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw) || IS_QLA27XX(vha->hw))
mcp->in_mb |= MBX_12;
mcp->tov = MBX_TOV_SECONDS;
mcp->flags = 0;
@@ -2590,6 +2597,9 @@ qla24xx_abort_command(srb_t *sp)
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x108c,
"Entered %s.\n", __func__);
+ if (ql2xasynctmfenable)
+ return qla24xx_async_abort_command(sp);
+
spin_lock_irqsave(&ha->hardware_lock, flags);
for (handle = 1; handle < req->num_outstanding_cmds; handle++) {
if (req->outstanding_cmds[handle] == sp)
@@ -3032,7 +3042,7 @@ qla2x00_enable_fce_trace(scsi_qla_host_t *vha, dma_addr_t fce_dma,
"Entered %s.\n", __func__);
if (!IS_QLA25XX(vha->hw) && !IS_QLA81XX(vha->hw) &&
- !IS_QLA83XX(vha->hw))
+ !IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw))
return QLA_FUNCTION_FAILED;
if (unlikely(pci_channel_offline(vha->hw->pdev)))
@@ -3662,7 +3672,7 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
mcp->mb[12] = req->qos;
mcp->mb[11] = req->vp_idx;
mcp->mb[13] = req->rid;
- if (IS_QLA83XX(ha))
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
mcp->mb[15] = 0;
mcp->mb[4] = req->id;
@@ -3676,9 +3686,9 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
mcp->flags = MBX_DMA_OUT;
mcp->tov = MBX_TOV_SECONDS * 2;
- if (IS_QLA81XX(ha) || IS_QLA83XX(ha))
+ if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha))
mcp->in_mb |= MBX_1;
- if (IS_QLA83XX(ha)) {
+ if (IS_QLA83XX(ha) || !IS_QLA27XX(ha)) {
mcp->out_mb |= MBX_15;
/* debug q create issue in SR-IOV */
mcp->in_mb |= MBX_9 | MBX_8 | MBX_7;
@@ -3687,7 +3697,7 @@ 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(req->req_q_in, 0);
- if (!IS_QLA83XX(ha))
+ if (!IS_QLA83XX(ha) || !IS_QLA27XX(ha))
WRT_REG_DWORD(req->req_q_out, 0);
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -3725,7 +3735,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
mcp->mb[5] = rsp->length;
mcp->mb[14] = rsp->msix->entry;
mcp->mb[13] = rsp->rid;
- if (IS_QLA83XX(ha))
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
mcp->mb[15] = 0;
mcp->mb[4] = rsp->id;
@@ -3742,7 +3752,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
if (IS_QLA81XX(ha)) {
mcp->out_mb |= MBX_12|MBX_11|MBX_10;
mcp->in_mb |= MBX_1;
- } else if (IS_QLA83XX(ha)) {
+ } else if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
mcp->out_mb |= MBX_15|MBX_12|MBX_11|MBX_10;
mcp->in_mb |= MBX_1;
/* debug q create issue in SR-IOV */
@@ -3809,7 +3819,8 @@ qla81xx_fac_get_sector_size(scsi_qla_host_t *vha, uint32_t *sector_size)
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10dc,
"Entered %s.\n", __func__);
- if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw))
+ if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw) &&
+ !IS_QLA27XX(vha->hw))
return QLA_FUNCTION_FAILED;
mcp->mb[0] = MBC_FLASH_ACCESS_CTRL;
@@ -3840,7 +3851,8 @@ qla81xx_fac_do_write_enable(scsi_qla_host_t *vha, int enable)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw))
+ if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw) &&
+ !IS_QLA27XX(vha->hw))
return QLA_FUNCTION_FAILED;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10df,
@@ -3874,7 +3886,8 @@ qla81xx_fac_erase_sector(scsi_qla_host_t *vha, uint32_t start, uint32_t finish)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw))
+ if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw) &&
+ !IS_QLA27XX(vha->hw))
return QLA_FUNCTION_FAILED;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e2,
@@ -4545,7 +4558,7 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
mcp->mb[1] = 0;
mcp->out_mb = MBX_1|MBX_0;
mcp->in_mb = MBX_2|MBX_1|MBX_0;
- if (IS_QLA83XX(ha))
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
mcp->in_mb |= MBX_3;
mcp->tov = MBX_TOV_SECONDS;
mcp->flags = 0;
@@ -4574,7 +4587,8 @@ 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) && !IS_QLA8044(ha))
+ if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) && !IS_QLA8044(ha) &&
+ !IS_QLA27XX(ha))
return QLA_FUNCTION_FAILED;
mcp->mb[0] = MBC_GET_PORT_CONFIG;
mcp->out_mb = MBX_0;
@@ -5070,7 +5084,7 @@ qla83xx_wr_reg(scsi_qla_host_t *vha, uint32_t reg, uint32_t data)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA83XX(ha))
+ if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
return QLA_FUNCTION_FAILED;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1130,
@@ -5145,7 +5159,7 @@ qla83xx_rd_reg(scsi_qla_host_t *vha, uint32_t reg, uint32_t *data)
struct qla_hw_data *ha = vha->hw;
unsigned long retry_max_time = jiffies + (2 * HZ);
- if (!IS_QLA83XX(ha))
+ if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
return QLA_FUNCTION_FAILED;
ql_dbg(ql_dbg_mbx, vha, 0x114b, "Entered %s.\n", __func__);
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index a72df701fb38..f0a852257f99 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -630,7 +630,7 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
struct req_que *req = NULL;
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
uint16_t que_id = 0;
- device_reg_t __iomem *reg;
+ device_reg_t *reg;
uint32_t cnt;
req = kzalloc(sizeof(struct req_que), GFP_KERNEL);
@@ -754,7 +754,7 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
struct rsp_que *rsp = NULL;
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
uint16_t que_id = 0;
- device_reg_t __iomem *reg;
+ device_reg_t *reg;
rsp = kzalloc(sizeof(struct rsp_que), GFP_KERNEL);
if (rsp == NULL) {
diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c
index ba6f8b139c98..0aaf6a9c87d3 100644
--- a/drivers/scsi/qla2xxx/qla_mr.c
+++ b/drivers/scsi/qla2xxx/qla_mr.c
@@ -40,7 +40,7 @@ qlafx00_mailbox_command(scsi_qla_host_t *vha, struct mbx_cmd_32 *mcp)
{
int rval;
unsigned long flags = 0;
- device_reg_t __iomem *reg;
+ device_reg_t *reg;
uint8_t abort_active;
uint8_t io_lock_on;
uint16_t command = 0;
@@ -631,20 +631,6 @@ qlafx00_config_rings(struct scsi_qla_host *vha)
{
struct qla_hw_data *ha = vha->hw;
struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
- struct init_cb_fx *icb;
- struct req_que *req = ha->req_q_map[0];
- struct rsp_que *rsp = ha->rsp_q_map[0];
-
- /* Setup ring parameters in initialization control block. */
- icb = (struct init_cb_fx *)ha->init_cb;
- icb->request_q_outpointer = __constant_cpu_to_le16(0);
- icb->response_q_inpointer = __constant_cpu_to_le16(0);
- icb->request_q_length = cpu_to_le16(req->length);
- icb->response_q_length = cpu_to_le16(rsp->length);
- icb->request_q_address[0] = cpu_to_le32(LSD(req->dma));
- icb->request_q_address[1] = cpu_to_le32(MSD(req->dma));
- icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma));
- icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma));
WRT_REG_DWORD(&reg->req_q_in, 0);
WRT_REG_DWORD(&reg->req_q_out, 0);
@@ -699,78 +685,16 @@ qlafx00_disable_intrs(struct qla_hw_data *ha)
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
-static void
-qlafx00_tmf_iocb_timeout(void *data)
-{
- srb_t *sp = (srb_t *)data;
- struct srb_iocb *tmf = &sp->u.iocb_cmd;
-
- tmf->u.tmf.comp_status = cpu_to_le16((uint16_t)CS_TIMEOUT);
- complete(&tmf->u.tmf.comp);
-}
-
-static void
-qlafx00_tmf_sp_done(void *data, void *ptr, int res)
-{
- srb_t *sp = (srb_t *)ptr;
- struct srb_iocb *tmf = &sp->u.iocb_cmd;
-
- complete(&tmf->u.tmf.comp);
-}
-
-static int
-qlafx00_async_tm_cmd(fc_port_t *fcport, uint32_t flags,
- uint32_t lun, uint32_t tag)
-{
- scsi_qla_host_t *vha = fcport->vha;
- struct srb_iocb *tm_iocb;
- srb_t *sp;
- int rval = QLA_FUNCTION_FAILED;
-
- sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
- if (!sp)
- goto done;
-
- tm_iocb = &sp->u.iocb_cmd;
- sp->type = SRB_TM_CMD;
- sp->name = "tmf";
- qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha));
- tm_iocb->u.tmf.flags = flags;
- tm_iocb->u.tmf.lun = lun;
- tm_iocb->u.tmf.data = tag;
- sp->done = qlafx00_tmf_sp_done;
- tm_iocb->timeout = qlafx00_tmf_iocb_timeout;
- init_completion(&tm_iocb->u.tmf.comp);
-
- rval = qla2x00_start_sp(sp);
- if (rval != QLA_SUCCESS)
- goto done_free_sp;
-
- ql_dbg(ql_dbg_async, vha, 0x507b,
- "Task management command issued target_id=%x\n",
- fcport->tgt_id);
-
- wait_for_completion(&tm_iocb->u.tmf.comp);
-
- rval = tm_iocb->u.tmf.comp_status == CS_COMPLETE ?
- QLA_SUCCESS : QLA_FUNCTION_FAILED;
-
-done_free_sp:
- sp->free(vha, sp);
-done:
- return rval;
-}
-
int
qlafx00_abort_target(fc_port_t *fcport, unsigned int l, int tag)
{
- return qlafx00_async_tm_cmd(fcport, TCF_TARGET_RESET, l, tag);
+ return qla2x00_async_tm_cmd(fcport, TCF_TARGET_RESET, l, tag);
}
int
qlafx00_lun_reset(fc_port_t *fcport, unsigned int l, int tag)
{
- return qlafx00_async_tm_cmd(fcport, TCF_LUN_RESET, l, tag);
+ return qla2x00_async_tm_cmd(fcport, TCF_LUN_RESET, l, tag);
}
int
@@ -997,6 +921,9 @@ qlafx00_init_fw_ready(scsi_qla_host_t *vha)
break;
default:
+ if ((aenmbx & 0xFF00) == MBA_FW_INIT_INPROGRESS)
+ break;
+
/* If fw is apparently not ready. In order to continue,
* we might need to issue Mbox cmd, but the problem is
* that the DoorBell vector values that come with the
@@ -2014,7 +1941,8 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
memcpy(vha->hw->gid_list, pinfo, QLAFX00_TGT_NODE_LIST_SIZE);
} else if (fx_type == FXDISC_ABORT_IOCTL)
fdisc->u.fxiocb.result =
- (fdisc->u.fxiocb.result == cpu_to_le32(0x68)) ?
+ (fdisc->u.fxiocb.result ==
+ cpu_to_le32(QLAFX00_IOCTL_ICOB_ABORT_SUCCESS)) ?
cpu_to_le32(QLA_SUCCESS) : cpu_to_le32(QLA_FUNCTION_FAILED);
rval = le32_to_cpu(fdisc->u.fxiocb.result);
@@ -2034,94 +1962,6 @@ done:
return rval;
}
-static void
-qlafx00_abort_iocb_timeout(void *data)
-{
- srb_t *sp = (srb_t *)data;
- struct srb_iocb *abt = &sp->u.iocb_cmd;
-
- abt->u.abt.comp_status = cpu_to_le16((uint16_t)CS_TIMEOUT);
- complete(&abt->u.abt.comp);
-}
-
-static void
-qlafx00_abort_sp_done(void *data, void *ptr, int res)
-{
- srb_t *sp = (srb_t *)ptr;
- struct srb_iocb *abt = &sp->u.iocb_cmd;
-
- complete(&abt->u.abt.comp);
-}
-
-static int
-qlafx00_async_abt_cmd(srb_t *cmd_sp)
-{
- scsi_qla_host_t *vha = cmd_sp->fcport->vha;
- fc_port_t *fcport = cmd_sp->fcport;
- struct srb_iocb *abt_iocb;
- srb_t *sp;
- int rval = QLA_FUNCTION_FAILED;
-
- sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
- if (!sp)
- goto done;
-
- abt_iocb = &sp->u.iocb_cmd;
- sp->type = SRB_ABT_CMD;
- sp->name = "abort";
- qla2x00_init_timer(sp, FXDISC_TIMEOUT);
- abt_iocb->u.abt.cmd_hndl = cmd_sp->handle;
- sp->done = qlafx00_abort_sp_done;
- abt_iocb->timeout = qlafx00_abort_iocb_timeout;
- init_completion(&abt_iocb->u.abt.comp);
-
- rval = qla2x00_start_sp(sp);
- if (rval != QLA_SUCCESS)
- goto done_free_sp;
-
- ql_dbg(ql_dbg_async, vha, 0x507c,
- "Abort command issued - hdl=%x, target_id=%x\n",
- cmd_sp->handle, fcport->tgt_id);
-
- wait_for_completion(&abt_iocb->u.abt.comp);
-
- rval = abt_iocb->u.abt.comp_status == CS_COMPLETE ?
- QLA_SUCCESS : QLA_FUNCTION_FAILED;
-
-done_free_sp:
- sp->free(vha, sp);
-done:
- return rval;
-}
-
-int
-qlafx00_abort_command(srb_t *sp)
-{
- unsigned long flags = 0;
-
- uint32_t handle;
- fc_port_t *fcport = sp->fcport;
- struct scsi_qla_host *vha = fcport->vha;
- struct qla_hw_data *ha = vha->hw;
- struct req_que *req = vha->req;
-
- spin_lock_irqsave(&ha->hardware_lock, flags);
- for (handle = 1; handle < DEFAULT_OUTSTANDING_COMMANDS; handle++) {
- if (req->outstanding_cmds[handle] == sp)
- break;
- }
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- if (handle == DEFAULT_OUTSTANDING_COMMANDS) {
- /* Command not found. */
- return QLA_FUNCTION_FAILED;
- }
- if (sp->type == SRB_FXIOCB_DCMD)
- return qlafx00_fx_disc(vha, &vha->hw->mr.fcport,
- FXDISC_ABORT_IOCTL);
-
- return qlafx00_async_abt_cmd(sp);
-}
-
/*
* qlafx00_initialize_adapter
* Initialize board.
@@ -2150,7 +1990,6 @@ qlafx00_initialize_adapter(scsi_qla_host_t *vha)
vha->device_flags = DFLG_NO_CABLE;
vha->dpc_flags = 0;
vha->flags.management_server_logged_in = 0;
- vha->marker_needed = 0;
ha->isp_abort_cnt = 0;
ha->beacon_blink_led = 0;
@@ -2354,8 +2193,7 @@ qlafx00_ioctl_iosb_entry(scsi_qla_host_t *vha, struct req_que *req,
fstatus.ioctl_flags = pkt->fw_iotcl_flags;
fstatus.ioctl_data = pkt->dataword_r;
fstatus.adapid = pkt->adapid;
- fstatus.adapid_hi = pkt->adapid_hi;
- fstatus.reserved_2 = pkt->reserved_1;
+ fstatus.reserved_2 = pkt->dataword_r_extra;
fstatus.res_count = pkt->residuallen;
fstatus.status = pkt->status;
fstatus.seq_number = pkt->seq_no;
@@ -2804,7 +2642,7 @@ qlafx00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp,
srb_t *sp;
struct qla_hw_data *ha = vha->hw;
const char func[] = "ERROR-IOCB";
- uint16_t que = MSW(pkt->handle);
+ uint16_t que = 0;
struct req_que *req = NULL;
int res = DID_ERROR << 16;
@@ -2833,16 +2671,22 @@ qlafx00_process_response_queue(struct scsi_qla_host *vha,
{
struct sts_entry_fx00 *pkt;
response_t *lptr;
+ uint16_t lreq_q_in = 0;
+ uint16_t lreq_q_out = 0;
- while (RD_REG_DWORD((void __iomem *)&(rsp->ring_ptr->signature)) !=
- RESPONSE_PROCESSED) {
+ lreq_q_in = RD_REG_DWORD(rsp->rsp_q_in);
+ lreq_q_out = RD_REG_DWORD(rsp->rsp_q_out);
+
+ while (lreq_q_in != lreq_q_out) {
lptr = rsp->ring_ptr;
memcpy_fromio(rsp->rsp_pkt, (void __iomem *)lptr,
sizeof(rsp->rsp_pkt));
pkt = (struct sts_entry_fx00 *)rsp->rsp_pkt;
rsp->ring_index++;
+ lreq_q_out++;
if (rsp->ring_index == rsp->length) {
+ lreq_q_out = 0;
rsp->ring_index = 0;
rsp->ring_ptr = rsp->ring;
} else {
@@ -2854,7 +2698,6 @@ qlafx00_process_response_queue(struct scsi_qla_host *vha,
qlafx00_error_entry(vha, rsp,
(struct sts_entry_fx00 *)pkt, pkt->entry_status,
pkt->entry_type);
- goto next_iter;
continue;
}
@@ -2888,10 +2731,6 @@ qlafx00_process_response_queue(struct scsi_qla_host *vha,
pkt->entry_type, pkt->entry_status);
break;
}
-next_iter:
- WRT_REG_DWORD((void __iomem *)&lptr->signature,
- RESPONSE_PROCESSED);
- wmb();
}
/* Adjust ring index */
@@ -2926,9 +2765,9 @@ qlafx00_async_event(scsi_qla_host_t *vha)
break;
case QLAFX00_MBA_PORT_UPDATE: /* Port database update */
- ha->aenmb[1] = RD_REG_WORD(&reg->aenmailbox1);
- ha->aenmb[2] = RD_REG_WORD(&reg->aenmailbox2);
- ha->aenmb[3] = RD_REG_WORD(&reg->aenmailbox3);
+ ha->aenmb[1] = RD_REG_DWORD(&reg->aenmailbox1);
+ ha->aenmb[2] = RD_REG_DWORD(&reg->aenmailbox2);
+ ha->aenmb[3] = RD_REG_DWORD(&reg->aenmailbox3);
ql_dbg(ql_dbg_async, vha, 0x5077,
"Asynchronous port Update received "
"aenmb[0]: %x, aenmb[1]: %x, aenmb[2]: %x, aenmb[3]: %x\n",
@@ -2985,7 +2824,7 @@ static void
qlafx00_mbx_completion(scsi_qla_host_t *vha, uint32_t mb0)
{
uint16_t cnt;
- uint16_t __iomem *wptr;
+ uint32_t __iomem *wptr;
struct qla_hw_data *ha = vha->hw;
struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
@@ -2995,10 +2834,10 @@ qlafx00_mbx_completion(scsi_qla_host_t *vha, uint32_t mb0)
/* Load return mailbox registers. */
ha->flags.mbox_int = 1;
ha->mailbox_out32[0] = mb0;
- wptr = (uint16_t __iomem *)&reg->mailbox17;
+ wptr = (uint32_t __iomem *)&reg->mailbox17;
for (cnt = 1; cnt < ha->mbx_count; cnt++) {
- ha->mailbox_out32[cnt] = RD_REG_WORD(wptr);
+ ha->mailbox_out32[cnt] = RD_REG_DWORD(wptr);
wptr++;
}
}
@@ -3025,6 +2864,7 @@ qlafx00_intr_handler(int irq, void *dev_id)
struct rsp_que *rsp;
unsigned long flags;
uint32_t clr_intr = 0;
+ uint32_t intr_stat = 0;
rsp = (struct rsp_que *) dev_id;
if (!rsp) {
@@ -3046,34 +2886,26 @@ qlafx00_intr_handler(int irq, void *dev_id)
stat = QLAFX00_RD_INTR_REG(ha);
if (qla2x00_check_reg_for_disconnect(vha, stat))
break;
- if ((stat & QLAFX00_HST_INT_STS_BITS) == 0)
+ intr_stat = stat & QLAFX00_HST_INT_STS_BITS;
+ if (!intr_stat)
break;
- switch (stat & QLAFX00_HST_INT_STS_BITS) {
- case QLAFX00_INTR_MB_CMPLT:
- case QLAFX00_INTR_MB_RSP_CMPLT:
- case QLAFX00_INTR_MB_ASYNC_CMPLT:
- case QLAFX00_INTR_ALL_CMPLT:
+ if (stat & QLAFX00_INTR_MB_CMPLT) {
mb[0] = RD_REG_WORD(&reg->mailbox16);
qlafx00_mbx_completion(vha, mb[0]);
status |= MBX_INTERRUPT;
clr_intr |= QLAFX00_INTR_MB_CMPLT;
- break;
- case QLAFX00_INTR_ASYNC_CMPLT:
- case QLAFX00_INTR_RSP_ASYNC_CMPLT:
+ }
+ if (intr_stat & QLAFX00_INTR_ASYNC_CMPLT) {
ha->aenmb[0] = RD_REG_WORD(&reg->aenmailbox0);
qlafx00_async_event(vha);
clr_intr |= QLAFX00_INTR_ASYNC_CMPLT;
- break;
- case QLAFX00_INTR_RSP_CMPLT:
+ }
+ if (intr_stat & QLAFX00_INTR_RSP_CMPLT) {
qlafx00_process_response_queue(vha, rsp);
clr_intr |= QLAFX00_INTR_RSP_CMPLT;
- break;
- default:
- ql_dbg(ql_dbg_async, vha, 0x507a,
- "Unrecognized interrupt type (%d).\n", stat);
- break;
}
+
QLAFX00_CLR_INTR_REG(ha, clr_intr);
QLAFX00_RD_INTR_REG(ha);
}
@@ -3223,17 +3055,6 @@ qlafx00_start_scsi(srb_t *sp)
/* So we know we haven't pci_map'ed anything yet */
tot_dsds = 0;
- /* Forcing marker needed for now */
- vha->marker_needed = 0;
-
- /* Send marker if required */
- if (vha->marker_needed != 0) {
- if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) !=
- QLA_SUCCESS)
- return QLA_FUNCTION_FAILED;
- vha->marker_needed = 0;
- }
-
/* Acquire ring specific lock */
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -3284,7 +3105,9 @@ qlafx00_start_scsi(srb_t *sp)
memset(&lcmd_pkt, 0, REQUEST_ENTRY_SIZE);
lcmd_pkt.handle = MAKE_HANDLE(req->id, sp->handle);
- lcmd_pkt.handle_hi = 0;
+ lcmd_pkt.reserved_0 = 0;
+ lcmd_pkt.port_path_ctrl = 0;
+ lcmd_pkt.reserved_1 = 0;
lcmd_pkt.dseg_count = cpu_to_le16(tot_dsds);
lcmd_pkt.tgt_idx = cpu_to_le16(sp->fcport->tgt_id);
@@ -3364,8 +3187,7 @@ qlafx00_tm_iocb(srb_t *sp, struct tsk_mgmt_entry_fx00 *ptm_iocb)
tm_iocb.entry_type = TSK_MGMT_IOCB_TYPE_FX00;
tm_iocb.entry_count = 1;
tm_iocb.handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle));
- tm_iocb.handle_hi = 0;
- tm_iocb.timeout = cpu_to_le16(qla2x00_get_async_timeout(vha) + 2);
+ tm_iocb.reserved_0 = 0;
tm_iocb.tgt_id = cpu_to_le16(sp->fcport->tgt_id);
tm_iocb.control_flags = cpu_to_le32(fxio->u.tmf.flags);
if (tm_iocb.control_flags == cpu_to_le32((uint32_t)TCF_LUN_RESET)) {
diff --git a/drivers/scsi/qla2xxx/qla_mr.h b/drivers/scsi/qla2xxx/qla_mr.h
index 6cd7072cc0ff..e529dfaeb854 100644
--- a/drivers/scsi/qla2xxx/qla_mr.h
+++ b/drivers/scsi/qla2xxx/qla_mr.h
@@ -22,13 +22,16 @@ struct cmd_type_7_fx00 {
uint8_t entry_status; /* Entry Status. */
uint32_t handle; /* System handle. */
- uint32_t handle_hi;
+ uint8_t reserved_0;
+ uint8_t port_path_ctrl;
+ uint16_t reserved_1;
__le16 tgt_idx; /* Target Idx. */
uint16_t timeout; /* Command timeout. */
__le16 dseg_count; /* Data segment count. */
- uint16_t scsi_rsp_dsd_len;
+ uint8_t scsi_rsp_dsd_len;
+ uint8_t reserved_2;
struct scsi_lun lun; /* LUN (LE). */
@@ -47,30 +50,6 @@ struct cmd_type_7_fx00 {
uint32_t dseg_0_len; /* Data segment 0 length. */
};
-/*
- * ISP queue - marker entry structure definition.
- */
-struct mrk_entry_fx00 {
- uint8_t entry_type; /* Entry type. */
- uint8_t entry_count; /* Entry count. */
- uint8_t handle_count; /* Handle count. */
- uint8_t entry_status; /* Entry Status. */
-
- uint32_t handle; /* System handle. */
- uint32_t handle_hi; /* System handle. */
-
- uint16_t tgt_id; /* Target ID. */
-
- uint8_t modifier; /* Modifier (7-0). */
- uint8_t reserved_1;
-
- uint8_t reserved_2[5];
-
- uint8_t lun[8]; /* FCP LUN (BE). */
- uint8_t reserved_3[36];
-};
-
-
#define STATUS_TYPE_FX00 0x01 /* Status entry. */
struct sts_entry_fx00 {
uint8_t entry_type; /* Entry type. */
@@ -79,7 +58,7 @@ struct sts_entry_fx00 {
uint8_t entry_status; /* Entry Status. */
uint32_t handle; /* System handle. */
- uint32_t handle_hi; /* System handle. */
+ uint32_t reserved_3; /* System handle. */
__le16 comp_status; /* Completion status. */
uint16_t reserved_0; /* OX_ID used by the firmware. */
@@ -102,7 +81,7 @@ struct sts_entry_fx00 {
struct multi_sts_entry_fx00 {
uint8_t entry_type; /* Entry type. */
- uint8_t sys_define; /* System defined. */
+ uint8_t entry_count; /* Entry count. */
uint8_t handle_count;
uint8_t entry_status;
@@ -118,15 +97,13 @@ struct tsk_mgmt_entry_fx00 {
__le32 handle; /* System handle. */
- uint32_t handle_hi; /* System handle. */
+ uint32_t reserved_0;
__le16 tgt_id; /* Target Idx. */
uint16_t reserved_1;
-
- uint16_t delay; /* Activity delay in seconds. */
-
- __le16 timeout; /* Command timeout. */
+ uint16_t reserved_3;
+ uint16_t reserved_4;
struct scsi_lun lun; /* LUN (LE). */
@@ -144,13 +121,13 @@ struct abort_iocb_entry_fx00 {
uint8_t entry_status; /* Entry Status. */
__le32 handle; /* System handle. */
- __le32 handle_hi; /* System handle. */
+ __le32 reserved_0;
__le16 tgt_id_sts; /* Completion status. */
__le16 options;
__le32 abort_handle; /* System handle. */
- __le32 abort_handle_hi; /* System handle. */
+ __le32 reserved_2;
__le16 req_que_no;
uint8_t reserved_1[38];
@@ -171,8 +148,7 @@ struct ioctl_iocb_entry_fx00 {
__le32 dataword_r; /* Data word returned */
uint32_t adapid; /* Adapter ID */
- uint32_t adapid_hi; /* Adapter ID high */
- uint32_t reserved_1;
+ uint32_t dataword_r_extra;
__le32 seq_no;
uint8_t reserved_2[20];
@@ -360,11 +336,7 @@ struct config_info_data {
#define QLAFX00_INTR_MB_CMPLT 0x1
#define QLAFX00_INTR_RSP_CMPLT 0x2
-#define QLAFX00_INTR_MB_RSP_CMPLT 0x3
#define QLAFX00_INTR_ASYNC_CMPLT 0x4
-#define QLAFX00_INTR_MB_ASYNC_CMPLT 0x5
-#define QLAFX00_INTR_RSP_ASYNC_CMPLT 0x6
-#define QLAFX00_INTR_ALL_CMPLT 0x7
#define QLAFX00_MBA_SYSTEM_ERR 0x8002
#define QLAFX00_MBA_TEMP_OVER 0x8005
@@ -548,4 +520,7 @@ struct mr_data_fx00 {
/* Max conncurrent IOs that can be queued */
#define QLAFX00_MAX_CANQUEUE 1024
+/* IOCTL IOCB abort success */
+#define QLAFX00_IOCTL_ICOB_ABORT_SUCCESS 0x68
+
#endif
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index 1e6ba4a369e2..5511e24b1f11 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -1664,10 +1664,10 @@ qla82xx_iospace_config(struct qla_hw_data *ha)
/* Mapping of IO base pointer */
if (IS_QLA8044(ha)) {
ha->iobase =
- (device_reg_t __iomem *)((uint8_t *)ha->nx_pcibase);
+ (device_reg_t *)((uint8_t *)ha->nx_pcibase);
} else if (IS_QLA82XX(ha)) {
ha->iobase =
- (device_reg_t __iomem *)((uint8_t *)ha->nx_pcibase +
+ (device_reg_t *)((uint8_t *)ha->nx_pcibase +
0xbc000 + (ha->pdev->devfn << 11));
}
@@ -4502,3 +4502,20 @@ exit:
qla82xx_idc_unlock(ha);
return rval;
}
+
+void
+qla82xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
+{
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!ha->allow_cna_fw_dump)
+ return;
+
+ scsi_block_requests(vha->host);
+ ha->flags.isp82xx_no_md_cap = 1;
+ qla82xx_idc_lock(ha);
+ qla82xx_set_reset_owner(vha);
+ qla82xx_idc_unlock(ha);
+ qla2x00_wait_for_chip_reset(vha);
+ scsi_unblock_requests(vha->host);
+}
diff --git a/drivers/scsi/qla2xxx/qla_nx2.c b/drivers/scsi/qla2xxx/qla_nx2.c
index f60989d729a8..86cf10815db0 100644
--- a/drivers/scsi/qla2xxx/qla_nx2.c
+++ b/drivers/scsi/qla2xxx/qla_nx2.c
@@ -1578,8 +1578,8 @@ qla8044_need_reset_handler(struct scsi_qla_host *vha)
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__);
+ "%s: Non Reset owner: Reset Ack Timeout!\n",
+ __func__);
break;
}
@@ -2014,8 +2014,6 @@ qla8044_watchdog(struct scsi_qla_host *vha)
/* 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);
@@ -3715,3 +3713,19 @@ exit_isp_reset:
return rval;
}
+void
+qla8044_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
+{
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!ha->allow_cna_fw_dump)
+ return;
+
+ scsi_block_requests(vha->host);
+ ha->flags.isp82xx_no_md_cap = 1;
+ qla8044_idc_lock(ha);
+ qla82xx_set_reset_owner(vha);
+ qla8044_idc_unlock(ha);
+ qla2x00_wait_for_chip_reset(vha);
+ scsi_unblock_requests(vha->host);
+}
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 89a53002b585..19e99cc33724 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -120,15 +120,17 @@ MODULE_PARM_DESC(ql2xmaxqdepth,
int ql2xenabledif = 2;
module_param(ql2xenabledif, int, S_IRUGO);
MODULE_PARM_DESC(ql2xenabledif,
- " Enable T10-CRC-DIF "
- " Default is 0 - No DIF Support. 1 - Enable it"
- ", 2 - Enable DIF for all types, except Type 0.");
+ " Enable T10-CRC-DIF:\n"
+ " Default is 2.\n"
+ " 0 -- No DIF Support\n"
+ " 1 -- Enable DIF for all types\n"
+ " 2 -- Enable DIF for all types, except Type 0.\n");
int ql2xenablehba_err_chk = 2;
module_param(ql2xenablehba_err_chk, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xenablehba_err_chk,
" Enable T10-CRC-DIF Error isolation by HBA:\n"
- " Default is 1.\n"
+ " Default is 2.\n"
" 0 -- Error isolation disabled\n"
" 1 -- Error isolation enabled only for DIX Type 0\n"
" 2 -- Error isolation enabled for all Types\n");
@@ -1975,7 +1977,7 @@ static struct isp_operations qla82xx_isp_ops = {
.prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb,
.read_nvram = qla24xx_read_nvram_data,
.write_nvram = qla24xx_write_nvram_data,
- .fw_dump = qla24xx_fw_dump,
+ .fw_dump = qla82xx_fw_dump,
.beacon_on = qla82xx_beacon_on,
.beacon_off = qla82xx_beacon_off,
.beacon_blink = NULL,
@@ -2013,11 +2015,11 @@ static struct isp_operations qla8044_isp_ops = {
.prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb,
.read_nvram = NULL,
.write_nvram = NULL,
- .fw_dump = qla24xx_fw_dump,
+ .fw_dump = qla8044_fw_dump,
.beacon_on = qla82xx_beacon_on,
.beacon_off = qla82xx_beacon_off,
.beacon_blink = NULL,
- .read_optrom = qla82xx_read_optrom_data,
+ .read_optrom = qla8044_read_optrom_data,
.write_optrom = qla8044_write_optrom_data,
.get_flash_version = qla82xx_get_flash_version,
.start_scsi = qla82xx_start_scsi,
@@ -2078,7 +2080,7 @@ static struct isp_operations qlafx00_isp_ops = {
.intr_handler = qlafx00_intr_handler,
.enable_intrs = qlafx00_enable_intrs,
.disable_intrs = qlafx00_disable_intrs,
- .abort_command = qlafx00_abort_command,
+ .abort_command = qla24xx_async_abort_command,
.target_reset = qlafx00_abort_target,
.lun_reset = qlafx00_lun_reset,
.fabric_login = NULL,
@@ -2102,6 +2104,44 @@ static struct isp_operations qlafx00_isp_ops = {
.initialize_adapter = qlafx00_initialize_adapter,
};
+static struct isp_operations qla27xx_isp_ops = {
+ .pci_config = qla25xx_pci_config,
+ .reset_chip = qla24xx_reset_chip,
+ .chip_diag = qla24xx_chip_diag,
+ .config_rings = qla24xx_config_rings,
+ .reset_adapter = qla24xx_reset_adapter,
+ .nvram_config = qla81xx_nvram_config,
+ .update_fw_options = qla81xx_update_fw_options,
+ .load_risc = qla81xx_load_risc,
+ .pci_info_str = qla24xx_pci_info_str,
+ .fw_version_str = qla24xx_fw_version_str,
+ .intr_handler = qla24xx_intr_handler,
+ .enable_intrs = qla24xx_enable_intrs,
+ .disable_intrs = qla24xx_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 = qla27xx_fwdump,
+ .beacon_on = qla24xx_beacon_on,
+ .beacon_off = qla24xx_beacon_off,
+ .beacon_blink = qla83xx_beacon_blink,
+ .read_optrom = qla25xx_read_optrom_data,
+ .write_optrom = qla24xx_write_optrom_data,
+ .get_flash_version = qla24xx_get_flash_version,
+ .start_scsi = qla24xx_dif_start_scsi,
+ .abort_isp = qla2x00_abort_isp,
+ .iospace_config = qla83xx_iospace_config,
+ .initialize_adapter = qla2x00_initialize_adapter,
+};
+
static inline void
qla2x00_set_isp_flags(struct qla_hw_data *ha)
{
@@ -2223,21 +2263,29 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
case PCI_DEVICE_ID_QLOGIC_ISPF001:
ha->device_type |= DT_ISPFX00;
break;
+ case PCI_DEVICE_ID_QLOGIC_ISP2071:
+ ha->device_type |= DT_ISP2071;
+ ha->device_type |= DT_ZIO_SUPPORTED;
+ ha->device_type |= DT_FWI2;
+ ha->device_type |= DT_IIDMA;
+ ha->fw_srisc_address = RISC_START_ADDRESS_2400;
+ break;
}
if (IS_QLA82XX(ha))
- ha->port_no = !(ha->portnum & 1);
- else
+ ha->port_no = ha->portnum & 1;
+ else {
/* Get adapter physical port no from interrupt pin register. */
pci_read_config_byte(ha->pdev, PCI_INTERRUPT_PIN, &ha->port_no);
+ if (IS_QLA27XX(ha))
+ ha->port_no--;
+ else
+ ha->port_no = !(ha->port_no & 1);
+ }
- if (ha->port_no & 1)
- ha->flags.port0 = 1;
- else
- ha->flags.port0 = 0;
ql_dbg_pci(ql_dbg_init, ha->pdev, 0x000b,
"device_type=0x%x port=%d fw_srisc_address=0x%x.\n",
- ha->device_type, ha->flags.port0, ha->fw_srisc_address);
+ ha->device_type, ha->port_no, ha->fw_srisc_address);
}
static void
@@ -2297,7 +2345,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
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_ISP8044) {
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8044 ||
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2071) {
bars = pci_select_bars(pdev, IORESOURCE_MEM);
mem_only = 1;
ql_dbg_pci(ql_dbg_init, pdev, 0x0007,
@@ -2334,13 +2383,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
spin_lock_init(&ha->hardware_lock);
spin_lock_init(&ha->vport_slock);
mutex_init(&ha->selflogin_lock);
+ mutex_init(&ha->optrom_mutex);
/* Set ISP-type information. */
qla2x00_set_isp_flags(ha);
/* Set EEH reset type to fundamental if required by hba */
if (IS_QLA24XX(ha) || IS_QLA25XX(ha) || IS_QLA81XX(ha) ||
- IS_QLA83XX(ha))
+ IS_QLA83XX(ha) || IS_QLA27XX(ha))
pdev->needs_freset = 1;
ha->prev_topology = 0;
@@ -2488,7 +2538,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->aen_mbx_count = AEN_MAILBOX_REGISTER_COUNT_FX00;
req_length = REQUEST_ENTRY_CNT_FX00;
rsp_length = RESPONSE_ENTRY_CNT_FX00;
- ha->init_cb_size = sizeof(struct init_cb_fx);
ha->isp_ops = &qlafx00_isp_ops;
ha->port_down_retry_count = 30; /* default value */
ha->mr.fw_hbt_cnt = QLAFX00_HEARTBEAT_INTERVAL;
@@ -2497,6 +2546,22 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->mr.fw_hbt_en = 1;
ha->mr.host_info_resend = false;
ha->mr.hinfo_resend_timer_tick = QLAFX00_HINFO_RESEND_INTERVAL;
+ } else if (IS_QLA27XX(ha)) {
+ ha->portnum = PCI_FUNC(ha->pdev->devfn);
+ ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
+ ha->mbx_count = MAILBOX_REGISTER_COUNT;
+ req_length = REQUEST_ENTRY_CNT_24XX;
+ rsp_length = RESPONSE_ENTRY_CNT_2300;
+ 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 = &qla27xx_isp_ops;
+ ha->flash_conf_off = FARX_ACCESS_FLASH_CONF_81XX;
+ ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX;
+ ha->nvram_conf_off = ~0;
+ ha->nvram_data_off = ~0;
}
ql_dbg_pci(ql_dbg_init, pdev, 0x001e,
@@ -2536,7 +2601,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->flags.enable_64bit_addressing ? "enable" :
"disable");
ret = qla2x00_mem_alloc(ha, req_length, rsp_length, &req, &rsp);
- if (!ret) {
+ if (ret) {
ql_log_pci(ql_log_fatal, pdev, 0x0031,
"Failed to allocate memory for adapter, aborting.\n");
@@ -2561,10 +2626,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
host = base_vha->host;
base_vha->req = req;
- if (IS_QLAFX00(ha))
- host->can_queue = QLAFX00_MAX_CANQUEUE;
- else
- host->can_queue = req->length + 128;
if (IS_QLA2XXX_MIDTYPE(ha))
base_vha->mgmt_svr_loop_id = 10 + base_vha->vp_idx;
else
@@ -2587,11 +2648,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (!IS_QLA82XX(ha))
host->sg_tablesize = QLA_SG_ALL;
}
- ql_dbg(ql_dbg_init, base_vha, 0x0032,
- "can_queue=%d, req=%p, "
- "mgmt_svr_loop_id=%d, sg_tablesize=%d.\n",
- host->can_queue, base_vha->req,
- base_vha->mgmt_svr_loop_id, host->sg_tablesize);
host->max_id = ha->max_fibre_devices;
host->cmd_per_lun = 3;
host->unique_id = host->host_no;
@@ -2646,7 +2702,7 @@ que_init:
req->req_q_out = &ha->iobase->isp24.req_q_out;
rsp->rsp_q_in = &ha->iobase->isp24.rsp_q_in;
rsp->rsp_q_out = &ha->iobase->isp24.rsp_q_out;
- if (ha->mqenable || IS_QLA83XX(ha)) {
+ if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
req->req_q_in = &ha->mqiobase->isp25mq.req_q_in;
req->req_q_out = &ha->mqiobase->isp25mq.req_q_out;
rsp->rsp_q_in = &ha->mqiobase->isp25mq.rsp_q_in;
@@ -2707,6 +2763,16 @@ que_init:
goto probe_failed;
}
+ if (IS_QLAFX00(ha))
+ host->can_queue = QLAFX00_MAX_CANQUEUE;
+ else
+ host->can_queue = req->num_outstanding_cmds - 10;
+
+ ql_dbg(ql_dbg_init, base_vha, 0x0032,
+ "can_queue=%d, req=%p, mgmt_svr_loop_id=%d, sg_tablesize=%d.\n",
+ host->can_queue, base_vha->req,
+ base_vha->mgmt_svr_loop_id, host->sg_tablesize);
+
if (ha->mqenable) {
if (qla25xx_setup_mode(base_vha)) {
ql_log(ql_log_warn, base_vha, 0x00ec,
@@ -2887,9 +2953,9 @@ probe_hw_failed:
iospace_config_failed:
if (IS_P3P_TYPE(ha)) {
if (!ha->nx_pcibase)
- iounmap((device_reg_t __iomem *)ha->nx_pcibase);
+ iounmap((device_reg_t *)ha->nx_pcibase);
if (!ql2xdbwr)
- iounmap((device_reg_t __iomem *)ha->nxdb_wr_ptr);
+ iounmap((device_reg_t *)ha->nxdb_wr_ptr);
} else {
if (ha->iobase)
iounmap(ha->iobase);
@@ -3020,9 +3086,9 @@ qla2x00_unmap_iobases(struct qla_hw_data *ha)
{
if (IS_QLA82XX(ha)) {
- iounmap((device_reg_t __iomem *)ha->nx_pcibase);
+ iounmap((device_reg_t *)ha->nx_pcibase);
if (!ql2xdbwr)
- iounmap((device_reg_t __iomem *)ha->nxdb_wr_ptr);
+ iounmap((device_reg_t *)ha->nxdb_wr_ptr);
} else {
if (ha->iobase)
iounmap(ha->iobase);
@@ -3033,7 +3099,7 @@ qla2x00_unmap_iobases(struct qla_hw_data *ha)
if (ha->mqiobase)
iounmap(ha->mqiobase);
- if (IS_QLA83XX(ha) && ha->msixbase)
+ if ((IS_QLA83XX(ha) || IS_QLA27XX(ha)) && ha->msixbase)
iounmap(ha->msixbase);
}
}
@@ -3447,7 +3513,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
ha->npiv_info = NULL;
/* Get consistent memory allocated for EX-INIT-CB. */
- if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha)) {
+ if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha)) {
ha->ex_init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
&ha->ex_init_cb_dma);
if (!ha->ex_init_cb)
@@ -3478,10 +3544,10 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
else {
qla2x00_set_reserved_loop_ids(ha);
ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0123,
- "loop_id_map=%p. \n", ha->loop_id_map);
+ "loop_id_map=%p.\n", ha->loop_id_map);
}
- return 1;
+ return 0;
fail_async_pd:
dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma);
@@ -3562,22 +3628,28 @@ static void
qla2x00_free_fw_dump(struct qla_hw_data *ha)
{
if (ha->fce)
- dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce,
- ha->fce_dma);
+ dma_free_coherent(&ha->pdev->dev,
+ FCE_SIZE, ha->fce, ha->fce_dma);
- if (ha->fw_dump) {
- if (ha->eft)
- dma_free_coherent(&ha->pdev->dev,
- ntohl(ha->fw_dump->eft_size), ha->eft, ha->eft_dma);
+ if (ha->eft)
+ dma_free_coherent(&ha->pdev->dev,
+ EFT_SIZE, ha->eft, ha->eft_dma);
+
+ if (ha->fw_dump)
vfree(ha->fw_dump);
- }
+ if (ha->fw_dump_template)
+ vfree(ha->fw_dump_template);
+
ha->fce = NULL;
ha->fce_dma = 0;
ha->eft = NULL;
ha->eft_dma = 0;
- ha->fw_dump = NULL;
ha->fw_dumped = 0;
ha->fw_dump_reading = 0;
+ ha->fw_dump = NULL;
+ ha->fw_dump_len = 0;
+ ha->fw_dump_template = NULL;
+ ha->fw_dump_template_len = 0;
}
/*
@@ -5242,7 +5314,7 @@ qla2x00_timer(scsi_qla_host_t *vha)
/* Firmware interface routines. */
-#define FW_BLOBS 10
+#define FW_BLOBS 11
#define FW_ISP21XX 0
#define FW_ISP22XX 1
#define FW_ISP2300 2
@@ -5253,6 +5325,7 @@ qla2x00_timer(scsi_qla_host_t *vha)
#define FW_ISP82XX 7
#define FW_ISP2031 8
#define FW_ISP8031 9
+#define FW_ISP2071 10
#define FW_FILE_ISP21XX "ql2100_fw.bin"
#define FW_FILE_ISP22XX "ql2200_fw.bin"
@@ -5264,6 +5337,8 @@ qla2x00_timer(scsi_qla_host_t *vha)
#define FW_FILE_ISP82XX "ql8200_fw.bin"
#define FW_FILE_ISP2031 "ql2600_fw.bin"
#define FW_FILE_ISP8031 "ql8300_fw.bin"
+#define FW_FILE_ISP2071 "ql2700_fw.bin"
+
static DEFINE_MUTEX(qla_fw_lock);
@@ -5278,6 +5353,7 @@ static struct fw_blob qla_fw_blobs[FW_BLOBS] = {
{ .name = FW_FILE_ISP82XX, },
{ .name = FW_FILE_ISP2031, },
{ .name = FW_FILE_ISP8031, },
+ { .name = FW_FILE_ISP2071, },
};
struct fw_blob *
@@ -5306,6 +5382,8 @@ qla2x00_request_firmware(scsi_qla_host_t *vha)
blob = &qla_fw_blobs[FW_ISP2031];
} else if (IS_QLA8031(ha)) {
blob = &qla_fw_blobs[FW_ISP8031];
+ } else if (IS_QLA2071(ha)) {
+ blob = &qla_fw_blobs[FW_ISP2071];
} else {
return NULL;
}
@@ -5635,6 +5713,7 @@ static struct pci_device_id qla2xxx_pci_tbl[] = {
{ 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) },
+ { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2071) },
{ 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 bd56cde795fc..f28123e8ed65 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -568,7 +568,7 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
else if (IS_P3P_TYPE(ha)) {
*start = FA_FLASH_LAYOUT_ADDR_82;
goto end;
- } else if (IS_QLA83XX(ha)) {
+ } else if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
*start = FA_FLASH_LAYOUT_ADDR_83;
goto end;
}
@@ -682,7 +682,7 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
/* Assign FCP prio region since older adapters may not have FLT, or
FCP prio region in it's FLT.
*/
- ha->flt_region_fcp_prio = ha->flags.port0 ?
+ ha->flt_region_fcp_prio = (ha->port_no == 0) ?
fcp_prio_cfg0[def] : fcp_prio_cfg1[def];
ha->flt_region_flt = flt_addr;
@@ -743,47 +743,71 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
ha->flt_region_vpd_nvram = start;
if (IS_P3P_TYPE(ha))
break;
- if (ha->flags.port0)
+ if (ha->port_no == 0)
ha->flt_region_vpd = start;
break;
case FLT_REG_VPD_1:
if (IS_P3P_TYPE(ha) || IS_QLA8031(ha))
break;
- if (!ha->flags.port0)
+ if (ha->port_no == 1)
+ ha->flt_region_vpd = start;
+ break;
+ case FLT_REG_VPD_2:
+ if (!IS_QLA27XX(ha))
+ break;
+ if (ha->port_no == 2)
+ ha->flt_region_vpd = start;
+ break;
+ case FLT_REG_VPD_3:
+ if (!IS_QLA27XX(ha))
+ break;
+ if (ha->port_no == 3)
ha->flt_region_vpd = start;
break;
case FLT_REG_NVRAM_0:
if (IS_QLA8031(ha))
break;
- if (ha->flags.port0)
+ if (ha->port_no == 0)
ha->flt_region_nvram = start;
break;
case FLT_REG_NVRAM_1:
if (IS_QLA8031(ha))
break;
- if (!ha->flags.port0)
+ if (ha->port_no == 1)
+ ha->flt_region_nvram = start;
+ break;
+ case FLT_REG_NVRAM_2:
+ if (!IS_QLA27XX(ha))
+ break;
+ if (ha->port_no == 2)
+ ha->flt_region_nvram = start;
+ break;
+ case FLT_REG_NVRAM_3:
+ if (!IS_QLA27XX(ha))
+ break;
+ if (ha->port_no == 3)
ha->flt_region_nvram = start;
break;
case FLT_REG_FDT:
ha->flt_region_fdt = start;
break;
case FLT_REG_NPIV_CONF_0:
- if (ha->flags.port0)
+ if (ha->port_no == 0)
ha->flt_region_npiv_conf = start;
break;
case FLT_REG_NPIV_CONF_1:
- if (!ha->flags.port0)
+ if (ha->port_no == 1)
ha->flt_region_npiv_conf = start;
break;
case FLT_REG_GOLD_FW:
ha->flt_region_gold_fw = start;
break;
case FLT_REG_FCP_PRIO_0:
- if (ha->flags.port0)
+ if (ha->port_no == 0)
ha->flt_region_fcp_prio = start;
break;
case FLT_REG_FCP_PRIO_1:
- if (!ha->flags.port0)
+ if (ha->port_no == 1)
ha->flt_region_fcp_prio = start;
break;
case FLT_REG_BOOT_CODE_82XX:
@@ -813,13 +837,13 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
case FLT_REG_FCOE_NVRAM_0:
if (!(IS_QLA8031(ha) || IS_QLA8044(ha)))
break;
- if (ha->flags.port0)
+ if (ha->port_no == 0)
ha->flt_region_nvram = start;
break;
case FLT_REG_FCOE_NVRAM_1:
if (!(IS_QLA8031(ha) || IS_QLA8044(ha)))
break;
- if (!ha->flags.port0)
+ if (ha->port_no == 1)
ha->flt_region_nvram = start;
break;
}
@@ -832,12 +856,12 @@ no_flash_data:
ha->flt_region_fw = def_fw[def];
ha->flt_region_boot = def_boot[def];
ha->flt_region_vpd_nvram = def_vpd_nvram[def];
- ha->flt_region_vpd = ha->flags.port0 ?
+ ha->flt_region_vpd = (ha->port_no == 0) ?
def_vpd0[def] : def_vpd1[def];
- ha->flt_region_nvram = ha->flags.port0 ?
+ ha->flt_region_nvram = (ha->port_no == 0) ?
def_nvram0[def] : def_nvram1[def];
ha->flt_region_fdt = def_fdt[def];
- ha->flt_region_npiv_conf = ha->flags.port0 ?
+ ha->flt_region_npiv_conf = (ha->port_no == 0) ?
def_npiv_conf0[def] : def_npiv_conf1[def];
done:
ql_dbg(ql_dbg_init, vha, 0x004a,
@@ -989,7 +1013,7 @@ qla2xxx_get_flash_info(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) &&
- !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha))
+ !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) && !IS_QLA27XX(ha))
return QLA_SUCCESS;
ret = qla2xxx_find_flt_start(vha, &flt_addr);
@@ -1192,7 +1216,8 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
struct qla_hw_data *ha = vha->hw;
/* Prepare burst-capable write on supported ISPs. */
- if ((IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha)) &&
+ if ((IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) ||
+ IS_QLA27XX(ha)) &&
!(faddr & 0xfff) && dwords > OPTROM_BURST_DWORDS) {
optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
&optrom_dma, GFP_KERNEL);
@@ -1675,7 +1700,7 @@ qla83xx_select_led_port(struct qla_hw_data *ha)
if (!IS_QLA83XX(ha))
goto out;
- if (ha->flags.port0)
+ if (ha->port_no == 0)
led_select_value = QLA83XX_LED_PORT0;
else
led_select_value = QLA83XX_LED_PORT1;
@@ -2332,7 +2357,7 @@ qla2x00_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
*/
rest_addr = 0xffff;
sec_mask = 0x10000;
- break;
+ break;
}
/*
* ST m29w010b part - 16kb sector size
@@ -2558,7 +2583,7 @@ qla25xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
uint32_t faddr, left, burst;
struct qla_hw_data *ha = vha->hw;
- if (IS_QLA25XX(ha) || IS_QLA81XX(ha))
+ if (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA27XX(ha))
goto try_fast;
if (offset & 0xfff)
goto slow_read;
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 9e80d61e5a3a..0cb73074c199 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -790,17 +790,32 @@ static inline int test_tgt_sess_count(struct qla_tgt *tgt)
}
/* Called by tcm_qla2xxx configfs code */
-void qlt_stop_phase1(struct qla_tgt *tgt)
+int qlt_stop_phase1(struct qla_tgt *tgt)
{
struct scsi_qla_host *vha = tgt->vha;
struct qla_hw_data *ha = tgt->ha;
unsigned long flags;
+ mutex_lock(&qla_tgt_mutex);
+ if (!vha->fc_vport) {
+ struct Scsi_Host *sh = vha->host;
+ struct fc_host_attrs *fc_host = shost_to_fc_host(sh);
+ bool npiv_vports;
+
+ spin_lock_irqsave(sh->host_lock, flags);
+ npiv_vports = (fc_host->npiv_vports_inuse);
+ spin_unlock_irqrestore(sh->host_lock, flags);
+
+ if (npiv_vports) {
+ mutex_unlock(&qla_tgt_mutex);
+ return -EPERM;
+ }
+ }
if (tgt->tgt_stop || tgt->tgt_stopped) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04e,
"Already in tgt->tgt_stop or tgt_stopped state\n");
- dump_stack();
- return;
+ mutex_unlock(&qla_tgt_mutex);
+ return -EPERM;
}
ql_dbg(ql_dbg_tgt, vha, 0xe003, "Stopping target for host %ld(%p)\n",
@@ -815,6 +830,7 @@ void qlt_stop_phase1(struct qla_tgt *tgt)
qlt_clear_tgt_db(tgt, true);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
mutex_unlock(&vha->vha_tgt.tgt_mutex);
+ mutex_unlock(&qla_tgt_mutex);
flush_delayed_work(&tgt->sess_del_work);
@@ -841,6 +857,7 @@ void qlt_stop_phase1(struct qla_tgt *tgt)
/* Wait for sessions to clear out (just in case) */
wait_event(tgt->waitQ, test_tgt_sess_count(tgt));
+ return 0;
}
EXPORT_SYMBOL(qlt_stop_phase1);
@@ -2595,8 +2612,6 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
return -ENOMEM;
}
- INIT_LIST_HEAD(&cmd->cmd_list);
-
memcpy(&cmd->atio, atio, sizeof(*atio));
cmd->state = QLA_TGT_STATE_NEW;
cmd->tgt = vha->vha_tgt.qla_tgt;
@@ -3187,7 +3202,8 @@ restart:
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf02c,
"SRR cmd %p (se_cmd %p, tag %d, op %x), "
"sg_cnt=%d, offset=%d", cmd, &cmd->se_cmd, cmd->tag,
- se_cmd->t_task_cdb[0], cmd->sg_cnt, cmd->offset);
+ se_cmd->t_task_cdb ? se_cmd->t_task_cdb[0] : 0,
+ cmd->sg_cnt, cmd->offset);
qlt_handle_srr(vha, sctio, imm);
@@ -4183,6 +4199,9 @@ int qlt_add_target(struct qla_hw_data *ha, struct scsi_qla_host *base_vha)
tgt->datasegs_per_cmd = QLA_TGT_DATASEGS_PER_CMD_24XX;
tgt->datasegs_per_cont = QLA_TGT_DATASEGS_PER_CONT_24XX;
+ if (base_vha->fc_vport)
+ return 0;
+
mutex_lock(&qla_tgt_mutex);
list_add_tail(&tgt->tgt_list_entry, &qla_tgt_glist);
mutex_unlock(&qla_tgt_mutex);
@@ -4196,6 +4215,10 @@ int qlt_remove_target(struct qla_hw_data *ha, struct scsi_qla_host *vha)
if (!vha->vha_tgt.qla_tgt)
return 0;
+ if (vha->fc_vport) {
+ qlt_release(vha->vha_tgt.qla_tgt);
+ return 0;
+ }
mutex_lock(&qla_tgt_mutex);
list_del(&vha->vha_tgt.qla_tgt->tgt_list_entry);
mutex_unlock(&qla_tgt_mutex);
@@ -4267,6 +4290,12 @@ int qlt_lport_register(void *target_lport_ptr, u64 phys_wwpn,
spin_unlock_irqrestore(&ha->hardware_lock, flags);
continue;
}
+ if (tgt->tgt_stop) {
+ pr_debug("MODE_TARGET in shutdown on qla2xxx(%d)\n",
+ host->host_no);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ continue;
+ }
spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (!scsi_host_get(host)) {
@@ -4281,12 +4310,11 @@ int qlt_lport_register(void *target_lport_ptr, u64 phys_wwpn,
scsi_host_put(host);
continue;
}
- mutex_unlock(&qla_tgt_mutex);
-
rc = (*callback)(vha, target_lport_ptr, npiv_wwpn, npiv_wwnn);
if (rc != 0)
scsi_host_put(host);
+ mutex_unlock(&qla_tgt_mutex);
return rc;
}
mutex_unlock(&qla_tgt_mutex);
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index 1d10eecad499..ce33d8c26406 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -855,7 +855,6 @@ struct qla_tgt_cmd {
uint16_t loop_id; /* to save extra sess dereferences */
struct qla_tgt *tgt; /* to save extra sess dereferences */
struct scsi_qla_host *vha;
- struct list_head cmd_list;
struct atio_from_isp atio;
};
@@ -1002,7 +1001,7 @@ extern void qlt_modify_vp_config(struct scsi_qla_host *,
extern void qlt_probe_one_stage1(struct scsi_qla_host *, struct qla_hw_data *);
extern int qlt_mem_alloc(struct qla_hw_data *);
extern void qlt_mem_free(struct qla_hw_data *);
-extern void qlt_stop_phase1(struct qla_tgt *);
+extern int qlt_stop_phase1(struct qla_tgt *);
extern void qlt_stop_phase2(struct qla_tgt *);
extern irqreturn_t qla83xx_msix_atio_q(int, void *);
extern void qlt_83xx_iospace_config(struct qla_hw_data *);
diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c
new file mode 100644
index 000000000000..a804e9b744bb
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_tmpl.c
@@ -0,0 +1,909 @@
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c) 2003-2013 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+#include "qla_def.h"
+#include "qla_tmpl.h"
+
+/* note default template is in big endian */
+static const uint32_t ql27xx_fwdt_default_template[] = {
+ 0x63000000, 0xa4000000, 0x7c050000, 0x00000000,
+ 0x30000000, 0x01000000, 0x00000000, 0xc0406eb4,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x04010000, 0x14000000, 0x00000000,
+ 0x02000000, 0x44000000, 0x09010000, 0x10000000,
+ 0x00000000, 0x02000000, 0x01010000, 0x1c000000,
+ 0x00000000, 0x02000000, 0x00600000, 0x00000000,
+ 0xc0000000, 0x01010000, 0x1c000000, 0x00000000,
+ 0x02000000, 0x00600000, 0x00000000, 0xcc000000,
+ 0x01010000, 0x1c000000, 0x00000000, 0x02000000,
+ 0x10600000, 0x00000000, 0xd4000000, 0x01010000,
+ 0x1c000000, 0x00000000, 0x02000000, 0x700f0000,
+ 0x00000060, 0xf0000000, 0x00010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x00700000, 0x041000c0,
+ 0x00010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x10700000, 0x041000c0, 0x00010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x40700000, 0x041000c0,
+ 0x01010000, 0x1c000000, 0x00000000, 0x02000000,
+ 0x007c0000, 0x01000000, 0xc0000000, 0x00010000,
+ 0x18000000, 0x00000000, 0x02000000, 0x007c0000,
+ 0x040300c4, 0x00010000, 0x18000000, 0x00000000,
+ 0x02000000, 0x007c0000, 0x040100c0, 0x01010000,
+ 0x1c000000, 0x00000000, 0x02000000, 0x007c0000,
+ 0x00000000, 0xc0000000, 0x00010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x007c0000, 0x04200000,
+ 0x0b010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x0c000000, 0x00000000, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x000000b0, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x000010b0, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x000020b0, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x000030b0, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x000040b0, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x000050b0, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x000060b0, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x000070b0, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x000080b0, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x000090b0, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x0000a0b0, 0x00010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x0a000000, 0x040100c0,
+ 0x00010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x0a000000, 0x04200080, 0x00010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x00be0000, 0x041000c0,
+ 0x00010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x10be0000, 0x041000c0, 0x00010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x20be0000, 0x041000c0,
+ 0x00010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x30be0000, 0x041000c0, 0x00010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x00b00000, 0x041000c0,
+ 0x00010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x10b00000, 0x041000c0, 0x00010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x20b00000, 0x041000c0,
+ 0x00010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x30b00000, 0x041000c0, 0x00010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x00300000, 0x041000c0,
+ 0x00010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x10300000, 0x041000c0, 0x00010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x20300000, 0x041000c0,
+ 0x00010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x30300000, 0x041000c0, 0x0a010000, 0x10000000,
+ 0x00000000, 0x02000000, 0x06010000, 0x1c000000,
+ 0x00000000, 0x02000000, 0x01000000, 0x00000200,
+ 0xff230200, 0x06010000, 0x1c000000, 0x00000000,
+ 0x02000000, 0x02000000, 0x00001000, 0x00000000,
+ 0x07010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x00000000, 0x01000000, 0x07010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x00000000, 0x02000000,
+ 0x07010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x00000000, 0x03000000, 0x0d010000, 0x14000000,
+ 0x00000000, 0x02000000, 0x00000000, 0xff000000,
+ 0x10000000, 0x00000000, 0x00000080,
+};
+
+static inline void __iomem *
+qla27xx_isp_reg(struct scsi_qla_host *vha)
+{
+ return &vha->hw->iobase->isp24;
+}
+
+static inline void
+qla27xx_insert16(uint16_t value, void *buf, ulong *len)
+{
+ if (buf) {
+ buf += *len;
+ *(__le16 *)buf = cpu_to_le16(value);
+ }
+ *len += sizeof(value);
+}
+
+static inline void
+qla27xx_insert32(uint32_t value, void *buf, ulong *len)
+{
+ if (buf) {
+ buf += *len;
+ *(__le32 *)buf = cpu_to_le32(value);
+ }
+ *len += sizeof(value);
+}
+
+static inline void
+qla27xx_insertbuf(void *mem, ulong size, void *buf, ulong *len)
+{
+ ulong cnt = size;
+
+ if (buf && mem) {
+ buf += *len;
+ while (cnt >= sizeof(uint32_t)) {
+ *(__le32 *)buf = cpu_to_le32p(mem);
+ buf += sizeof(uint32_t);
+ mem += sizeof(uint32_t);
+ cnt -= sizeof(uint32_t);
+ }
+ if (cnt)
+ memcpy(buf, mem, cnt);
+ }
+ *len += size;
+}
+
+static inline void
+qla27xx_read8(void *window, void *buf, ulong *len)
+{
+ uint8_t value = ~0;
+
+ if (buf) {
+ value = RD_REG_BYTE((__iomem void *)window);
+ ql_dbg(ql_dbg_misc, NULL, 0xd011,
+ "%s: -> %x\n", __func__, value);
+ }
+ qla27xx_insert32(value, buf, len);
+}
+
+static inline void
+qla27xx_read16(void *window, void *buf, ulong *len)
+{
+ uint16_t value = ~0;
+
+ if (buf) {
+ value = RD_REG_WORD((__iomem void *)window);
+ ql_dbg(ql_dbg_misc, NULL, 0xd012,
+ "%s: -> %x\n", __func__, value);
+ }
+ qla27xx_insert32(value, buf, len);
+}
+
+static inline void
+qla27xx_read32(void *window, void *buf, ulong *len)
+{
+ uint32_t value = ~0;
+
+ if (buf) {
+ value = RD_REG_DWORD((__iomem void *)window);
+ ql_dbg(ql_dbg_misc, NULL, 0xd013,
+ "%s: -> %x\n", __func__, value);
+ }
+ qla27xx_insert32(value, buf, len);
+}
+
+static inline void (*qla27xx_read_vector(uint width))(void *, void *, ulong *)
+{
+ return
+ (width == 1) ? qla27xx_read8 :
+ (width == 2) ? qla27xx_read16 :
+ qla27xx_read32;
+}
+
+static inline void
+qla27xx_read_reg(__iomem struct device_reg_24xx *reg,
+ uint offset, void *buf, ulong *len)
+{
+ void *window = (void *)reg + offset;
+
+ if (buf) {
+ ql_dbg(ql_dbg_misc, NULL, 0xd014,
+ "%s: @%x\n", __func__, offset);
+ }
+ qla27xx_insert32(offset, buf, len);
+ qla27xx_read32(window, buf, len);
+}
+
+static inline void
+qla27xx_write_reg(__iomem struct device_reg_24xx *reg,
+ uint offset, uint32_t data, void *buf)
+{
+ __iomem void *window = reg + offset;
+
+ if (buf) {
+ ql_dbg(ql_dbg_misc, NULL, 0xd015,
+ "%s: @%x <- %x\n", __func__, offset, data);
+ WRT_REG_DWORD(window, data);
+ }
+}
+
+static inline void
+qla27xx_read_window(__iomem struct device_reg_24xx *reg,
+ uint32_t base, uint offset, uint count, uint width, void *buf,
+ ulong *len)
+{
+ void *window = (void *)reg + offset;
+ void (*readn)(void *, void *, ulong *) = qla27xx_read_vector(width);
+
+ if (buf) {
+ ql_dbg(ql_dbg_misc, NULL, 0xd016,
+ "%s: base=%x offset=%x count=%x width=%x\n",
+ __func__, base, offset, count, width);
+ }
+ qla27xx_write_reg(reg, IOBASE_ADDR, base, buf);
+ while (count--) {
+ qla27xx_insert32(base, buf, len);
+ readn(window, buf, len);
+ window += width;
+ base += width;
+ }
+}
+
+static inline void
+qla27xx_skip_entry(struct qla27xx_fwdt_entry *ent, void *buf)
+{
+ if (buf)
+ ent->hdr.driver_flags |= DRIVER_FLAG_SKIP_ENTRY;
+}
+
+static int
+qla27xx_fwdt_entry_t0(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ ql_dbg(ql_dbg_misc, vha, 0xd100,
+ "%s: nop [%lx]\n", __func__, *len);
+ qla27xx_skip_entry(ent, buf);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t255(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ ql_dbg(ql_dbg_misc, vha, 0xd1ff,
+ "%s: end [%lx]\n", __func__, *len);
+ qla27xx_skip_entry(ent, buf);
+
+ /* terminate */
+ return true;
+}
+
+static int
+qla27xx_fwdt_entry_t256(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+
+ ql_dbg(ql_dbg_misc, vha, 0xd200,
+ "%s: rdio t1 [%lx]\n", __func__, *len);
+ qla27xx_read_window(reg, ent->t256.base_addr, ent->t256.pci_offset,
+ ent->t256.reg_count, ent->t256.reg_width, buf, len);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t257(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+
+ ql_dbg(ql_dbg_misc, vha, 0xd201,
+ "%s: wrio t1 [%lx]\n", __func__, *len);
+ qla27xx_write_reg(reg, IOBASE_ADDR, ent->t257.base_addr, buf);
+ qla27xx_write_reg(reg, ent->t257.pci_offset, ent->t257.write_data, buf);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t258(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+
+ ql_dbg(ql_dbg_misc, vha, 0xd202,
+ "%s: rdio t2 [%lx]\n", __func__, *len);
+ qla27xx_write_reg(reg, ent->t258.banksel_offset, ent->t258.bank, buf);
+ qla27xx_read_window(reg, ent->t258.base_addr, ent->t258.pci_offset,
+ ent->t258.reg_count, ent->t258.reg_width, buf, len);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t259(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+
+ ql_dbg(ql_dbg_misc, vha, 0xd203,
+ "%s: wrio t2 [%lx]\n", __func__, *len);
+ qla27xx_write_reg(reg, IOBASE_ADDR, ent->t259.base_addr, buf);
+ qla27xx_write_reg(reg, ent->t259.banksel_offset, ent->t259.bank, buf);
+ qla27xx_write_reg(reg, ent->t259.pci_offset, ent->t259.write_data, buf);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t260(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+
+ ql_dbg(ql_dbg_misc, vha, 0xd204,
+ "%s: rdpci [%lx]\n", __func__, *len);
+ qla27xx_read_reg(reg, ent->t260.pci_addr, buf, len);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t261(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+
+ ql_dbg(ql_dbg_misc, vha, 0xd205,
+ "%s: wrpci [%lx]\n", __func__, *len);
+ qla27xx_write_reg(reg, ent->t261.pci_addr, ent->t261.write_data, buf);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ ulong dwords;
+ ulong start;
+ ulong end;
+
+ ql_dbg(ql_dbg_misc, vha, 0xd206,
+ "%s: rdram(%x) [%lx]\n", __func__, ent->t262.ram_area, *len);
+ start = ent->t262.start_addr;
+ end = ent->t262.end_addr;
+
+ if (ent->t262.ram_area == T262_RAM_AREA_CRITICAL_RAM) {
+ ;
+ } else if (ent->t262.ram_area == T262_RAM_AREA_EXTERNAL_RAM) {
+ end = vha->hw->fw_memory_size;
+ if (buf)
+ ent->t262.end_addr = end;
+ } else if (ent->t262.ram_area == T262_RAM_AREA_SHARED_RAM) {
+ start = vha->hw->fw_shared_ram_start;
+ end = vha->hw->fw_shared_ram_end;
+ if (buf) {
+ ent->t262.start_addr = start;
+ ent->t262.end_addr = end;
+ }
+ } else if (ent->t262.ram_area == T262_RAM_AREA_DDR_RAM) {
+ ql_dbg(ql_dbg_misc, vha, 0xd021,
+ "%s: unsupported ddr ram\n", __func__);
+ qla27xx_skip_entry(ent, buf);
+ goto done;
+ } else {
+ ql_dbg(ql_dbg_misc, vha, 0xd022,
+ "%s: unknown area %u\n", __func__, ent->t262.ram_area);
+ qla27xx_skip_entry(ent, buf);
+ goto done;
+ }
+
+ if (end < start) {
+ ql_dbg(ql_dbg_misc, vha, 0xd023,
+ "%s: bad range (start=%x end=%x)\n", __func__,
+ ent->t262.end_addr, ent->t262.start_addr);
+ qla27xx_skip_entry(ent, buf);
+ goto done;
+ }
+
+ dwords = end - start + 1;
+ if (buf) {
+ ql_dbg(ql_dbg_misc, vha, 0xd024,
+ "%s: @%lx -> (%lx dwords)\n", __func__, start, dwords);
+ buf += *len;
+ qla24xx_dump_ram(vha->hw, start, buf, dwords, &buf);
+ }
+ *len += dwords * sizeof(uint32_t);
+done:
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ uint count = 0;
+ uint i;
+ uint length;
+
+ ql_dbg(ql_dbg_misc, vha, 0xd207,
+ "%s: getq(%x) [%lx]\n", __func__, ent->t263.queue_type, *len);
+ if (ent->t263.queue_type == T263_QUEUE_TYPE_REQ) {
+ for (i = 0; i < vha->hw->max_req_queues; i++) {
+ struct req_que *req = vha->hw->req_q_map[i];
+ if (req || !buf) {
+ length = req ?
+ req->length : REQUEST_ENTRY_CNT_24XX;
+ qla27xx_insert16(i, buf, len);
+ qla27xx_insert16(length, buf, len);
+ qla27xx_insertbuf(req ? req->ring : NULL,
+ length * sizeof(*req->ring), buf, len);
+ count++;
+ }
+ }
+ } else if (ent->t263.queue_type == T263_QUEUE_TYPE_RSP) {
+ for (i = 0; i < vha->hw->max_rsp_queues; i++) {
+ struct rsp_que *rsp = vha->hw->rsp_q_map[i];
+ if (rsp || !buf) {
+ length = rsp ?
+ rsp->length : RESPONSE_ENTRY_CNT_MQ;
+ qla27xx_insert16(i, buf, len);
+ qla27xx_insert16(length, buf, len);
+ qla27xx_insertbuf(rsp ? rsp->ring : NULL,
+ length * sizeof(*rsp->ring), buf, len);
+ count++;
+ }
+ }
+ } else if (ent->t263.queue_type == T263_QUEUE_TYPE_ATIO) {
+ ql_dbg(ql_dbg_misc, vha, 0xd025,
+ "%s: unsupported atio queue\n", __func__);
+ qla27xx_skip_entry(ent, buf);
+ goto done;
+ } else {
+ ql_dbg(ql_dbg_misc, vha, 0xd026,
+ "%s: unknown queue %u\n", __func__, ent->t263.queue_type);
+ qla27xx_skip_entry(ent, buf);
+ goto done;
+ }
+
+ if (buf)
+ ent->t263.num_queues = count;
+done:
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t264(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ ql_dbg(ql_dbg_misc, vha, 0xd208,
+ "%s: getfce [%lx]\n", __func__, *len);
+ if (vha->hw->fce) {
+ if (buf) {
+ ent->t264.fce_trace_size = FCE_SIZE;
+ ent->t264.write_pointer = vha->hw->fce_wr;
+ ent->t264.base_pointer = vha->hw->fce_dma;
+ ent->t264.fce_enable_mb0 = vha->hw->fce_mb[0];
+ ent->t264.fce_enable_mb2 = vha->hw->fce_mb[2];
+ ent->t264.fce_enable_mb3 = vha->hw->fce_mb[3];
+ ent->t264.fce_enable_mb4 = vha->hw->fce_mb[4];
+ ent->t264.fce_enable_mb5 = vha->hw->fce_mb[5];
+ ent->t264.fce_enable_mb6 = vha->hw->fce_mb[6];
+ }
+ qla27xx_insertbuf(vha->hw->fce, FCE_SIZE, buf, len);
+ } else {
+ ql_dbg(ql_dbg_misc, vha, 0xd027,
+ "%s: missing fce\n", __func__);
+ qla27xx_skip_entry(ent, buf);
+ }
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t265(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+
+ ql_dbg(ql_dbg_misc, vha, 0xd209,
+ "%s: pause risc [%lx]\n", __func__, *len);
+ if (buf)
+ qla24xx_pause_risc(reg);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t266(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ ql_dbg(ql_dbg_misc, vha, 0xd20a,
+ "%s: reset risc [%lx]\n", __func__, *len);
+ if (buf)
+ qla24xx_soft_reset(vha->hw);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t267(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+
+ ql_dbg(ql_dbg_misc, vha, 0xd20b,
+ "%s: dis intr [%lx]\n", __func__, *len);
+ qla27xx_write_reg(reg, ent->t267.pci_offset, ent->t267.data, buf);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t268(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ ql_dbg(ql_dbg_misc, vha, 0xd20c,
+ "%s: gethb(%x) [%lx]\n", __func__, ent->t268.buf_type, *len);
+ if (ent->t268.buf_type == T268_BUF_TYPE_EXTD_TRACE) {
+ if (vha->hw->eft) {
+ if (buf) {
+ ent->t268.buf_size = EFT_SIZE;
+ ent->t268.start_addr = vha->hw->eft_dma;
+ }
+ qla27xx_insertbuf(vha->hw->eft, EFT_SIZE, buf, len);
+ } else {
+ ql_dbg(ql_dbg_misc, vha, 0xd028,
+ "%s: missing eft\n", __func__);
+ qla27xx_skip_entry(ent, buf);
+ }
+ } else if (ent->t268.buf_type == T268_BUF_TYPE_EXCH_BUFOFF) {
+ ql_dbg(ql_dbg_misc, vha, 0xd029,
+ "%s: unsupported exchange offload buffer\n", __func__);
+ qla27xx_skip_entry(ent, buf);
+ } else if (ent->t268.buf_type == T268_BUF_TYPE_EXTD_LOGIN) {
+ ql_dbg(ql_dbg_misc, vha, 0xd02a,
+ "%s: unsupported extended login buffer\n", __func__);
+ qla27xx_skip_entry(ent, buf);
+ } else {
+ ql_dbg(ql_dbg_misc, vha, 0xd02b,
+ "%s: unknown buf %x\n", __func__, ent->t268.buf_type);
+ qla27xx_skip_entry(ent, buf);
+ }
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t269(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ ql_dbg(ql_dbg_misc, vha, 0xd20d,
+ "%s: scratch [%lx]\n", __func__, *len);
+ qla27xx_insert32(0xaaaaaaaa, buf, len);
+ qla27xx_insert32(0xbbbbbbbb, buf, len);
+ qla27xx_insert32(0xcccccccc, buf, len);
+ qla27xx_insert32(0xdddddddd, buf, len);
+ qla27xx_insert32(*len + sizeof(uint32_t), buf, len);
+ if (buf)
+ ent->t269.scratch_size = 5 * sizeof(uint32_t);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t270(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+ void *window = (void *)reg + 0xc4;
+ ulong dwords = ent->t270.count;
+ ulong addr = ent->t270.addr;
+
+ ql_dbg(ql_dbg_misc, vha, 0xd20e,
+ "%s: rdremreg [%lx]\n", __func__, *len);
+ qla27xx_write_reg(reg, IOBASE_ADDR, 0x40, buf);
+ while (dwords--) {
+ qla27xx_write_reg(reg, 0xc0, addr|0x80000000, buf);
+ qla27xx_read_reg(reg, 0xc4, buf, len);
+ qla27xx_insert32(addr, buf, len);
+ qla27xx_read32(window, buf, len);
+ addr++;
+ }
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t271(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+ ulong addr = ent->t271.addr;
+
+ ql_dbg(ql_dbg_misc, vha, 0xd20f,
+ "%s: wrremreg [%lx]\n", __func__, *len);
+ qla27xx_write_reg(reg, IOBASE_ADDR, 0x40, buf);
+ qla27xx_read_reg(reg, 0xc4, buf, len);
+ qla27xx_insert32(addr, buf, len);
+ qla27xx_write_reg(reg, 0xc0, addr, buf);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t272(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ ulong dwords = ent->t272.count;
+ ulong start = ent->t272.addr;
+
+ ql_dbg(ql_dbg_misc, vha, 0xd210,
+ "%s: rdremram [%lx]\n", __func__, *len);
+ if (buf) {
+ ql_dbg(ql_dbg_misc, vha, 0xd02c,
+ "%s: @%lx -> (%lx dwords)\n", __func__, start, dwords);
+ buf += *len;
+ qla27xx_dump_mpi_ram(vha->hw, start, buf, dwords, &buf);
+ }
+ *len += dwords * sizeof(uint32_t);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t273(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ ulong dwords = ent->t273.count;
+ ulong addr = ent->t273.addr;
+ uint32_t value;
+
+ ql_dbg(ql_dbg_misc, vha, 0xd211,
+ "%s: pcicfg [%lx]\n", __func__, *len);
+ while (dwords--) {
+ value = ~0;
+ if (pci_read_config_dword(vha->hw->pdev, addr, &value))
+ ql_dbg(ql_dbg_misc, vha, 0xd02d,
+ "%s: failed pcicfg read at %lx\n", __func__, addr);
+ qla27xx_insert32(addr, buf, len);
+ qla27xx_insert32(value, buf, len);
+ addr += 4;
+ }
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_other(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ ql_dbg(ql_dbg_misc, vha, 0xd2ff,
+ "%s: type %x [%lx]\n", __func__, ent->hdr.entry_type, *len);
+ qla27xx_skip_entry(ent, buf);
+
+ return false;
+}
+
+struct qla27xx_fwdt_entry_call {
+ int type;
+ int (*call)(
+ struct scsi_qla_host *,
+ struct qla27xx_fwdt_entry *,
+ void *,
+ ulong *);
+};
+
+static struct qla27xx_fwdt_entry_call ql27xx_fwdt_entry_call_list[] = {
+ { ENTRY_TYPE_NOP , qla27xx_fwdt_entry_t0 } ,
+ { ENTRY_TYPE_TMP_END , qla27xx_fwdt_entry_t255 } ,
+ { ENTRY_TYPE_RD_IOB_T1 , qla27xx_fwdt_entry_t256 } ,
+ { ENTRY_TYPE_WR_IOB_T1 , qla27xx_fwdt_entry_t257 } ,
+ { ENTRY_TYPE_RD_IOB_T2 , qla27xx_fwdt_entry_t258 } ,
+ { ENTRY_TYPE_WR_IOB_T2 , qla27xx_fwdt_entry_t259 } ,
+ { ENTRY_TYPE_RD_PCI , qla27xx_fwdt_entry_t260 } ,
+ { ENTRY_TYPE_WR_PCI , qla27xx_fwdt_entry_t261 } ,
+ { ENTRY_TYPE_RD_RAM , qla27xx_fwdt_entry_t262 } ,
+ { ENTRY_TYPE_GET_QUEUE , qla27xx_fwdt_entry_t263 } ,
+ { ENTRY_TYPE_GET_FCE , qla27xx_fwdt_entry_t264 } ,
+ { ENTRY_TYPE_PSE_RISC , qla27xx_fwdt_entry_t265 } ,
+ { ENTRY_TYPE_RST_RISC , qla27xx_fwdt_entry_t266 } ,
+ { ENTRY_TYPE_DIS_INTR , qla27xx_fwdt_entry_t267 } ,
+ { ENTRY_TYPE_GET_HBUF , qla27xx_fwdt_entry_t268 } ,
+ { ENTRY_TYPE_SCRATCH , qla27xx_fwdt_entry_t269 } ,
+ { ENTRY_TYPE_RDREMREG , qla27xx_fwdt_entry_t270 } ,
+ { ENTRY_TYPE_WRREMREG , qla27xx_fwdt_entry_t271 } ,
+ { ENTRY_TYPE_RDREMRAM , qla27xx_fwdt_entry_t272 } ,
+ { ENTRY_TYPE_PCICFG , qla27xx_fwdt_entry_t273 } ,
+ { -1 , qla27xx_fwdt_entry_other }
+};
+
+static inline int (*qla27xx_find_entry(int type))
+ (struct scsi_qla_host *, struct qla27xx_fwdt_entry *, void *, ulong *)
+{
+ struct qla27xx_fwdt_entry_call *list = ql27xx_fwdt_entry_call_list;
+
+ while (list->type != -1 && list->type != type)
+ list++;
+
+ return list->call;
+}
+
+static inline void *
+qla27xx_next_entry(void *p)
+{
+ struct qla27xx_fwdt_entry *ent = p;
+
+ return p + ent->hdr.entry_size;
+}
+
+static void
+qla27xx_walk_template(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_template *tmp, void *buf, ulong *len)
+{
+ struct qla27xx_fwdt_entry *ent = (void *)tmp + tmp->entry_offset;
+ ulong count = tmp->entry_count;
+
+ ql_dbg(ql_dbg_misc, vha, 0xd01a,
+ "%s: entry count %lx\n", __func__, count);
+ while (count--) {
+ if (qla27xx_find_entry(ent->hdr.entry_type)(vha, ent, buf, len))
+ break;
+ ent = qla27xx_next_entry(ent);
+ }
+ ql_dbg(ql_dbg_misc, vha, 0xd01b,
+ "%s: len=%lx\n", __func__, *len);
+}
+
+static void
+qla27xx_time_stamp(struct qla27xx_fwdt_template *tmp)
+{
+ tmp->capture_timestamp = jiffies;
+}
+
+static void
+qla27xx_driver_info(struct qla27xx_fwdt_template *tmp)
+{
+ uint8_t v[] = { 0, 0, 0, 0, 0, 0 };
+ int rval = 0;
+
+ rval = sscanf(qla2x00_version_str, "%hhu.%hhu.%hhu.%hhu.%hhu.%hhu",
+ v+0, v+1, v+2, v+3, v+4, v+5);
+
+ tmp->driver_info[0] = v[3] << 24 | v[2] << 16 | v[1] << 8 | v[0];
+ tmp->driver_info[1] = v[5] << 8 | v[4];
+ tmp->driver_info[2] = 0x12345678;
+}
+
+static void
+qla27xx_firmware_info(struct qla27xx_fwdt_template *tmp,
+ struct scsi_qla_host *vha)
+{
+ tmp->firmware_version[0] = vha->hw->fw_major_version;
+ tmp->firmware_version[1] = vha->hw->fw_minor_version;
+ tmp->firmware_version[2] = vha->hw->fw_subminor_version;
+ tmp->firmware_version[3] =
+ vha->hw->fw_attributes_h << 16 | vha->hw->fw_attributes;
+ tmp->firmware_version[4] =
+ vha->hw->fw_attributes_ext[1] << 16 | vha->hw->fw_attributes_ext[0];
+}
+
+static void
+ql27xx_edit_template(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_template *tmp)
+{
+ qla27xx_time_stamp(tmp);
+ qla27xx_driver_info(tmp);
+ qla27xx_firmware_info(tmp, vha);
+}
+
+static inline uint32_t
+qla27xx_template_checksum(void *p, ulong size)
+{
+ uint32_t *buf = p;
+ uint64_t sum = 0;
+
+ size /= sizeof(*buf);
+
+ while (size--)
+ sum += *buf++;
+
+ sum = (sum & 0xffffffff) + (sum >> 32);
+
+ return ~sum;
+}
+
+static inline int
+qla27xx_verify_template_checksum(struct qla27xx_fwdt_template *tmp)
+{
+ return qla27xx_template_checksum(tmp, tmp->template_size) == 0;
+}
+
+static inline int
+qla27xx_verify_template_header(struct qla27xx_fwdt_template *tmp)
+{
+ return tmp->template_type == TEMPLATE_TYPE_FWDUMP;
+}
+
+static void
+qla27xx_execute_fwdt_template(struct scsi_qla_host *vha)
+{
+ struct qla27xx_fwdt_template *tmp = vha->hw->fw_dump_template;
+ ulong len;
+
+ if (qla27xx_fwdt_template_valid(tmp)) {
+ len = tmp->template_size;
+ tmp = memcpy(vha->hw->fw_dump, tmp, len);
+ ql27xx_edit_template(vha, tmp);
+ qla27xx_walk_template(vha, tmp, tmp, &len);
+ vha->hw->fw_dump_len = len;
+ vha->hw->fw_dumped = 1;
+ }
+}
+
+ulong
+qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host *vha)
+{
+ struct qla27xx_fwdt_template *tmp = vha->hw->fw_dump_template;
+ ulong len = 0;
+
+ if (qla27xx_fwdt_template_valid(tmp)) {
+ len = tmp->template_size;
+ qla27xx_walk_template(vha, tmp, NULL, &len);
+ }
+
+ return len;
+}
+
+ulong
+qla27xx_fwdt_template_size(void *p)
+{
+ struct qla27xx_fwdt_template *tmp = p;
+
+ return tmp->template_size;
+}
+
+ulong
+qla27xx_fwdt_template_default_size(void)
+{
+ return sizeof(ql27xx_fwdt_default_template);
+}
+
+const void *
+qla27xx_fwdt_template_default(void)
+{
+ return ql27xx_fwdt_default_template;
+}
+
+int
+qla27xx_fwdt_template_valid(void *p)
+{
+ struct qla27xx_fwdt_template *tmp = p;
+
+ if (!qla27xx_verify_template_header(tmp)) {
+ ql_log(ql_log_warn, NULL, 0xd01c,
+ "%s: template type %x\n", __func__, tmp->template_type);
+ return false;
+ }
+
+ if (!qla27xx_verify_template_checksum(tmp)) {
+ ql_log(ql_log_warn, NULL, 0xd01d,
+ "%s: failed template checksum\n", __func__);
+ return false;
+ }
+
+ return true;
+}
+
+void
+qla27xx_fwdump(scsi_qla_host_t *vha, int hardware_locked)
+{
+ ulong flags = 0;
+
+ if (!hardware_locked)
+ spin_lock_irqsave(&vha->hw->hardware_lock, flags);
+
+ if (!vha->hw->fw_dump)
+ ql_log(ql_log_warn, vha, 0xd01e, "fwdump buffer missing.\n");
+ else if (!vha->hw->fw_dump_template)
+ ql_log(ql_log_warn, vha, 0xd01f, "fwdump template missing.\n");
+ else
+ qla27xx_execute_fwdt_template(vha);
+
+ if (!hardware_locked)
+ spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
+}
diff --git a/drivers/scsi/qla2xxx/qla_tmpl.h b/drivers/scsi/qla2xxx/qla_tmpl.h
new file mode 100644
index 000000000000..c9d2fff4d964
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_tmpl.h
@@ -0,0 +1,205 @@
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c) 2003-2013 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+
+#ifndef __QLA_DMP27_H__
+#define __QLA_DMP27_H__
+
+#define IOBASE_ADDR offsetof(struct device_reg_24xx, iobase_addr)
+
+struct __packed qla27xx_fwdt_template {
+ uint32_t template_type;
+ uint32_t entry_offset;
+ uint32_t template_size;
+ uint32_t reserved_1;
+
+ uint32_t entry_count;
+ uint32_t template_version;
+ uint32_t capture_timestamp;
+ uint32_t template_checksum;
+
+ uint32_t reserved_2;
+ uint32_t driver_info[3];
+
+ uint32_t saved_state[16];
+
+ uint32_t reserved_3[8];
+ uint32_t firmware_version[5];
+};
+
+#define TEMPLATE_TYPE_FWDUMP 99
+
+#define ENTRY_TYPE_NOP 0
+#define ENTRY_TYPE_TMP_END 255
+#define ENTRY_TYPE_RD_IOB_T1 256
+#define ENTRY_TYPE_WR_IOB_T1 257
+#define ENTRY_TYPE_RD_IOB_T2 258
+#define ENTRY_TYPE_WR_IOB_T2 259
+#define ENTRY_TYPE_RD_PCI 260
+#define ENTRY_TYPE_WR_PCI 261
+#define ENTRY_TYPE_RD_RAM 262
+#define ENTRY_TYPE_GET_QUEUE 263
+#define ENTRY_TYPE_GET_FCE 264
+#define ENTRY_TYPE_PSE_RISC 265
+#define ENTRY_TYPE_RST_RISC 266
+#define ENTRY_TYPE_DIS_INTR 267
+#define ENTRY_TYPE_GET_HBUF 268
+#define ENTRY_TYPE_SCRATCH 269
+#define ENTRY_TYPE_RDREMREG 270
+#define ENTRY_TYPE_WRREMREG 271
+#define ENTRY_TYPE_RDREMRAM 272
+#define ENTRY_TYPE_PCICFG 273
+
+#define CAPTURE_FLAG_PHYS_ONLY BIT_0
+#define CAPTURE_FLAG_PHYS_VIRT BIT_1
+
+#define DRIVER_FLAG_SKIP_ENTRY BIT_7
+
+struct __packed qla27xx_fwdt_entry {
+ struct __packed {
+ uint32_t entry_type;
+ uint32_t entry_size;
+ uint32_t reserved_1;
+
+ uint8_t capture_flags;
+ uint8_t reserved_2[2];
+ uint8_t driver_flags;
+ } hdr;
+ union __packed {
+ struct __packed {
+ } t0;
+
+ struct __packed {
+ } t255;
+
+ struct __packed {
+ uint32_t base_addr;
+ uint8_t reg_width;
+ uint16_t reg_count;
+ uint8_t pci_offset;
+ } t256;
+
+ struct __packed {
+ uint32_t base_addr;
+ uint32_t write_data;
+ uint8_t pci_offset;
+ uint8_t reserved[3];
+ } t257;
+
+ struct __packed {
+ uint32_t base_addr;
+ uint8_t reg_width;
+ uint16_t reg_count;
+ uint8_t pci_offset;
+ uint8_t banksel_offset;
+ uint8_t reserved[3];
+ uint32_t bank;
+ } t258;
+
+ struct __packed {
+ uint32_t base_addr;
+ uint32_t write_data;
+ uint8_t reserved[2];
+ uint8_t pci_offset;
+ uint8_t banksel_offset;
+ uint32_t bank;
+ } t259;
+
+ struct __packed {
+ uint8_t pci_addr;
+ uint8_t reserved[3];
+ } t260;
+
+ struct __packed {
+ uint8_t pci_addr;
+ uint8_t reserved[3];
+ uint32_t write_data;
+ } t261;
+
+ struct __packed {
+ uint8_t ram_area;
+ uint8_t reserved[3];
+ uint32_t start_addr;
+ uint32_t end_addr;
+ } t262;
+
+ struct __packed {
+ uint32_t num_queues;
+ uint8_t queue_type;
+ uint8_t reserved[3];
+ } t263;
+
+ struct __packed {
+ uint32_t fce_trace_size;
+ uint64_t write_pointer;
+ uint64_t base_pointer;
+ uint32_t fce_enable_mb0;
+ uint32_t fce_enable_mb2;
+ uint32_t fce_enable_mb3;
+ uint32_t fce_enable_mb4;
+ uint32_t fce_enable_mb5;
+ uint32_t fce_enable_mb6;
+ } t264;
+
+ struct __packed {
+ } t265;
+
+ struct __packed {
+ } t266;
+
+ struct __packed {
+ uint8_t pci_offset;
+ uint8_t reserved[3];
+ uint32_t data;
+ } t267;
+
+ struct __packed {
+ uint8_t buf_type;
+ uint8_t reserved[3];
+ uint32_t buf_size;
+ uint64_t start_addr;
+ } t268;
+
+ struct __packed {
+ uint32_t scratch_size;
+ } t269;
+
+ struct __packed {
+ uint32_t addr;
+ uint32_t count;
+ } t270;
+
+ struct __packed {
+ uint32_t addr;
+ uint32_t data;
+ } t271;
+
+ struct __packed {
+ uint32_t addr;
+ uint32_t count;
+ } t272;
+
+ struct __packed {
+ uint32_t addr;
+ uint32_t count;
+ } t273;
+ };
+};
+
+#define T262_RAM_AREA_CRITICAL_RAM 1
+#define T262_RAM_AREA_EXTERNAL_RAM 2
+#define T262_RAM_AREA_SHARED_RAM 3
+#define T262_RAM_AREA_DDR_RAM 4
+
+#define T263_QUEUE_TYPE_REQ 1
+#define T263_QUEUE_TYPE_RSP 2
+#define T263_QUEUE_TYPE_ATIO 3
+
+#define T268_BUF_TYPE_EXTD_TRACE 1
+#define T268_BUF_TYPE_EXCH_BUFOFF 2
+#define T268_BUF_TYPE_EXTD_LOGIN 3
+
+#endif
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 31d19535b015..e36b94712544 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.06.00.12-k"
+#define QLA2XXX_VERSION "8.07.00.02-k"
#define QLA_DRIVER_MAJOR_VER 8
-#define QLA_DRIVER_MINOR_VER 6
+#define QLA_DRIVER_MINOR_VER 7
#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 75a141bbe74d..788c4fe2b0c9 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -182,20 +182,6 @@ static int tcm_qla2xxx_npiv_parse_wwn(
return 0;
}
-static ssize_t tcm_qla2xxx_npiv_format_wwn(char *buf, size_t len,
- u64 wwpn, u64 wwnn)
-{
- u8 b[8], b2[8];
-
- put_unaligned_be64(wwpn, b);
- put_unaligned_be64(wwnn, b2);
- return snprintf(buf, len,
- "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x,"
- "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
- b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
- b2[0], b2[1], b2[2], b2[3], b2[4], b2[5], b2[6], b2[7]);
-}
-
static char *tcm_qla2xxx_npiv_get_fabric_name(void)
{
return "qla2xxx_npiv";
@@ -227,15 +213,6 @@ static char *tcm_qla2xxx_get_fabric_wwn(struct se_portal_group *se_tpg)
return lport->lport_naa_name;
}
-static char *tcm_qla2xxx_npiv_get_fabric_wwn(struct se_portal_group *se_tpg)
-{
- struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
- struct tcm_qla2xxx_tpg, se_tpg);
- struct tcm_qla2xxx_lport *lport = tpg->lport;
-
- return &lport->lport_npiv_name[0];
-}
-
static u16 tcm_qla2xxx_get_tag(struct se_portal_group *se_tpg)
{
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
@@ -941,15 +918,41 @@ static ssize_t tcm_qla2xxx_tpg_show_enable(
atomic_read(&tpg->lport_tpg_enabled));
}
+static void tcm_qla2xxx_depend_tpg(struct work_struct *work)
+{
+ struct tcm_qla2xxx_tpg *base_tpg = container_of(work,
+ struct tcm_qla2xxx_tpg, tpg_base_work);
+ struct se_portal_group *se_tpg = &base_tpg->se_tpg;
+ struct scsi_qla_host *base_vha = base_tpg->lport->qla_vha;
+
+ if (!configfs_depend_item(se_tpg->se_tpg_tfo->tf_subsys,
+ &se_tpg->tpg_group.cg_item)) {
+ atomic_set(&base_tpg->lport_tpg_enabled, 1);
+ qlt_enable_vha(base_vha);
+ }
+ complete(&base_tpg->tpg_base_comp);
+}
+
+static void tcm_qla2xxx_undepend_tpg(struct work_struct *work)
+{
+ struct tcm_qla2xxx_tpg *base_tpg = container_of(work,
+ struct tcm_qla2xxx_tpg, tpg_base_work);
+ struct se_portal_group *se_tpg = &base_tpg->se_tpg;
+ struct scsi_qla_host *base_vha = base_tpg->lport->qla_vha;
+
+ if (!qlt_stop_phase1(base_vha->vha_tgt.qla_tgt)) {
+ atomic_set(&base_tpg->lport_tpg_enabled, 0);
+ configfs_undepend_item(se_tpg->se_tpg_tfo->tf_subsys,
+ &se_tpg->tpg_group.cg_item);
+ }
+ complete(&base_tpg->tpg_base_comp);
+}
+
static ssize_t tcm_qla2xxx_tpg_store_enable(
struct se_portal_group *se_tpg,
const char *page,
size_t count)
{
- struct se_wwn *se_wwn = se_tpg->se_tpg_wwn;
- struct tcm_qla2xxx_lport *lport = container_of(se_wwn,
- struct tcm_qla2xxx_lport, lport_wwn);
- struct scsi_qla_host *vha = lport->qla_vha;
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
struct tcm_qla2xxx_tpg, se_tpg);
unsigned long op;
@@ -964,19 +967,28 @@ static ssize_t tcm_qla2xxx_tpg_store_enable(
pr_err("Illegal value for tpg_enable: %lu\n", op);
return -EINVAL;
}
-
if (op) {
- atomic_set(&tpg->lport_tpg_enabled, 1);
- qlt_enable_vha(vha);
+ if (atomic_read(&tpg->lport_tpg_enabled))
+ return -EEXIST;
+
+ INIT_WORK(&tpg->tpg_base_work, tcm_qla2xxx_depend_tpg);
} else {
- if (!vha->vha_tgt.qla_tgt) {
- pr_err("struct qla_hw_data *vha->vha_tgt.qla_tgt is NULL\n");
- return -ENODEV;
- }
- atomic_set(&tpg->lport_tpg_enabled, 0);
- qlt_stop_phase1(vha->vha_tgt.qla_tgt);
+ if (!atomic_read(&tpg->lport_tpg_enabled))
+ return count;
+
+ INIT_WORK(&tpg->tpg_base_work, tcm_qla2xxx_undepend_tpg);
}
+ init_completion(&tpg->tpg_base_comp);
+ schedule_work(&tpg->tpg_base_work);
+ wait_for_completion(&tpg->tpg_base_comp);
+ if (op) {
+ if (!atomic_read(&tpg->lport_tpg_enabled))
+ return -ENODEV;
+ } else {
+ if (atomic_read(&tpg->lport_tpg_enabled))
+ return -EPERM;
+ }
return count;
}
@@ -1053,11 +1065,64 @@ static void tcm_qla2xxx_drop_tpg(struct se_portal_group *se_tpg)
/*
* Clear local TPG=1 pointer for non NPIV mode.
*/
- lport->tpg_1 = NULL;
-
+ lport->tpg_1 = NULL;
kfree(tpg);
}
+static ssize_t tcm_qla2xxx_npiv_tpg_show_enable(
+ struct se_portal_group *se_tpg,
+ char *page)
+{
+ return tcm_qla2xxx_tpg_show_enable(se_tpg, page);
+}
+
+static ssize_t tcm_qla2xxx_npiv_tpg_store_enable(
+ struct se_portal_group *se_tpg,
+ const char *page,
+ size_t count)
+{
+ struct se_wwn *se_wwn = se_tpg->se_tpg_wwn;
+ struct tcm_qla2xxx_lport *lport = container_of(se_wwn,
+ struct tcm_qla2xxx_lport, lport_wwn);
+ struct scsi_qla_host *vha = lport->qla_vha;
+ struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
+ struct tcm_qla2xxx_tpg, se_tpg);
+ unsigned long op;
+ int rc;
+
+ rc = kstrtoul(page, 0, &op);
+ if (rc < 0) {
+ pr_err("kstrtoul() returned %d\n", rc);
+ return -EINVAL;
+ }
+ if ((op != 1) && (op != 0)) {
+ pr_err("Illegal value for tpg_enable: %lu\n", op);
+ return -EINVAL;
+ }
+ if (op) {
+ if (atomic_read(&tpg->lport_tpg_enabled))
+ return -EEXIST;
+
+ atomic_set(&tpg->lport_tpg_enabled, 1);
+ qlt_enable_vha(vha);
+ } else {
+ if (!atomic_read(&tpg->lport_tpg_enabled))
+ return count;
+
+ atomic_set(&tpg->lport_tpg_enabled, 0);
+ qlt_stop_phase1(vha->vha_tgt.qla_tgt);
+ }
+
+ return count;
+}
+
+TF_TPG_BASE_ATTR(tcm_qla2xxx_npiv, enable, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *tcm_qla2xxx_npiv_tpg_attrs[] = {
+ &tcm_qla2xxx_npiv_tpg_enable.attr,
+ NULL,
+};
+
static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg(
struct se_wwn *wwn,
struct config_group *group,
@@ -1650,6 +1715,9 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha,
struct scsi_qla_host *npiv_vha;
struct tcm_qla2xxx_lport *lport =
(struct tcm_qla2xxx_lport *)target_lport_ptr;
+ struct tcm_qla2xxx_lport *base_lport =
+ (struct tcm_qla2xxx_lport *)base_vha->vha_tgt.target_lport_ptr;
+ struct tcm_qla2xxx_tpg *base_tpg;
struct fc_vport_identifiers vport_id;
if (!qla_tgt_mode_enabled(base_vha)) {
@@ -1657,6 +1725,13 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha,
return -EPERM;
}
+ if (!base_lport || !base_lport->tpg_1 ||
+ !atomic_read(&base_lport->tpg_1->lport_tpg_enabled)) {
+ pr_err("qla2xxx base_lport or tpg_1 not available\n");
+ return -EPERM;
+ }
+ base_tpg = base_lport->tpg_1;
+
memset(&vport_id, 0, sizeof(vport_id));
vport_id.port_name = npiv_wwpn;
vport_id.node_name = npiv_wwnn;
@@ -1675,7 +1750,6 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha,
npiv_vha = (struct scsi_qla_host *)vport->dd_data;
npiv_vha->vha_tgt.target_lport_ptr = target_lport_ptr;
lport->qla_vha = npiv_vha;
-
scsi_host_get(npiv_vha->host);
return 0;
}
@@ -1714,8 +1788,6 @@ static struct se_wwn *tcm_qla2xxx_npiv_make_lport(
}
lport->lport_npiv_wwpn = npiv_wwpn;
lport->lport_npiv_wwnn = npiv_wwnn;
- tcm_qla2xxx_npiv_format_wwn(&lport->lport_npiv_name[0],
- TCM_QLA2XXX_NAMELEN, npiv_wwpn, npiv_wwnn);
sprintf(lport->lport_naa_name, "naa.%016llx", (unsigned long long) npiv_wwpn);
ret = tcm_qla2xxx_init_lport(lport);
@@ -1824,7 +1896,7 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = {
static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
.get_fabric_name = tcm_qla2xxx_npiv_get_fabric_name,
.get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident,
- .tpg_get_wwn = tcm_qla2xxx_npiv_get_fabric_wwn,
+ .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn,
.tpg_get_tag = tcm_qla2xxx_get_tag,
.tpg_get_default_depth = tcm_qla2xxx_get_default_depth,
.tpg_get_pr_transport_id = tcm_qla2xxx_get_pr_transport_id,
@@ -1935,7 +2007,7 @@ static int tcm_qla2xxx_register_configfs(void)
*/
npiv_fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_qla2xxx_wwn_attrs;
npiv_fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs =
- tcm_qla2xxx_tpg_attrs;
+ tcm_qla2xxx_npiv_tpg_attrs;
npiv_fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
npiv_fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
npiv_fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.h b/drivers/scsi/qla2xxx/tcm_qla2xxx.h
index 275d8b9a7a34..33aaac8c7d59 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.h
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.h
@@ -4,8 +4,6 @@
#define TCM_QLA2XXX_VERSION "v0.1"
/* length of ASCII WWPNs including pad */
#define TCM_QLA2XXX_NAMELEN 32
-/* lenth of ASCII NPIV 'WWPN+WWNN' including pad */
-#define TCM_QLA2XXX_NPIV_NAMELEN 66
#include "qla_target.h"
@@ -43,6 +41,9 @@ struct tcm_qla2xxx_tpg {
struct tcm_qla2xxx_tpg_attrib tpg_attrib;
/* Returned by tcm_qla2xxx_make_tpg() */
struct se_portal_group se_tpg;
+ /* Items for dealing with configfs_depend_item */
+ struct completion tpg_base_comp;
+ struct work_struct tpg_base_work;
};
struct tcm_qla2xxx_fc_loopid {
@@ -62,8 +63,6 @@ struct tcm_qla2xxx_lport {
char lport_name[TCM_QLA2XXX_NAMELEN];
/* ASCII formatted naa WWPN for VPD page 83 etc */
char lport_naa_name[TCM_QLA2XXX_NAMELEN];
- /* ASCII formatted WWPN+WWNN for NPIV FC Target Lport */
- char lport_npiv_name[TCM_QLA2XXX_NPIV_NAMELEN];
/* map for fc_port pointers in 24-bit FC Port ID space */
struct btree_head32 lport_fcport_map;
/* vmalloc-ed memory for fc_port pointers for 16-bit FC loop ID */
diff --git a/drivers/scsi/qla4xxx/ql4_83xx.c b/drivers/scsi/qla4xxx/ql4_83xx.c
index 919284834ad7..2eba35365920 100644
--- a/drivers/scsi/qla4xxx/ql4_83xx.c
+++ b/drivers/scsi/qla4xxx/ql4_83xx.c
@@ -1304,12 +1304,24 @@ static void qla4_83xx_process_init_seq(struct scsi_qla_host *ha)
static int qla4_83xx_restart(struct scsi_qla_host *ha)
{
int ret_val = QLA_SUCCESS;
+ uint32_t idc_ctrl;
qla4_83xx_process_stop_seq(ha);
- /* Collect minidump*/
- if (!test_and_clear_bit(AF_83XX_NO_FW_DUMP, &ha->flags))
+ /*
+ * Collect minidump.
+ * If IDC_CTRL BIT1 is set, clear it on going to INIT state and
+ * don't collect minidump
+ */
+ 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,
+ (idc_ctrl & ~GRACEFUL_RESET_BIT1));
+ ql4_printk(KERN_INFO, ha, "%s: Graceful RESET: Not collecting minidump\n",
+ __func__);
+ } else {
qla4_8xxx_get_minidump(ha);
+ }
qla4_83xx_process_init_seq(ha);
@@ -1664,3 +1676,23 @@ void qla4_83xx_disable_pause(struct scsi_qla_host *ha)
__qla4_83xx_disable_pause(ha);
ha->isp_ops->idc_unlock(ha);
}
+
+/**
+ * qla4_83xx_is_detached - Check if we are marked invisible.
+ * @ha: Pointer to host adapter structure.
+ **/
+int qla4_83xx_is_detached(struct scsi_qla_host *ha)
+{
+ uint32_t drv_active;
+
+ drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
+
+ if (test_bit(AF_INIT_DONE, &ha->flags) &&
+ !(drv_active & (1 << ha->func_num))) {
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: drv_active = 0x%X\n",
+ __func__, drv_active));
+ return QLA_SUCCESS;
+ }
+
+ return QLA_ERROR;
+}
diff --git a/drivers/scsi/qla4xxx/ql4_bsg.c b/drivers/scsi/qla4xxx/ql4_bsg.c
index 04a0027dbca0..9f92cbf96477 100644
--- a/drivers/scsi/qla4xxx/ql4_bsg.c
+++ b/drivers/scsi/qla4xxx/ql4_bsg.c
@@ -517,7 +517,7 @@ static int qla4_83xx_wait_for_loopback_config_comp(struct scsi_qla_host *ha,
(ha->idc_extend_tmo * HZ))) {
ha->notify_idc_comp = 0;
ha->notify_link_up_comp = 0;
- ql4_printk(KERN_WARNING, ha, "%s: IDC Complete notification not received",
+ ql4_printk(KERN_WARNING, ha, "%s: Aborting: IDC Complete notification not received",
__func__);
status = QLA_ERROR;
goto exit_wait;
@@ -538,7 +538,7 @@ static int qla4_83xx_wait_for_loopback_config_comp(struct scsi_qla_host *ha,
if (!wait_for_completion_timeout(&ha->link_up_comp,
(IDC_COMP_TOV * HZ))) {
ha->notify_link_up_comp = 0;
- ql4_printk(KERN_WARNING, ha, "%s: LINK UP notification not received",
+ ql4_printk(KERN_WARNING, ha, "%s: Aborting: LINK UP notification not received",
__func__);
status = QLA_ERROR;
goto exit_wait;
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index aa67bb9a4426..73a502288bde 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -194,7 +194,7 @@
#define ADAPTER_INIT_TOV 30
#define ADAPTER_RESET_TOV 180
#define EXTEND_CMD_TOV 60
-#define WAIT_CMD_TOV 30
+#define WAIT_CMD_TOV 5
#define EH_WAIT_CMD_TOV 120
#define FIRMWARE_UP_TOV 60
#define RESET_FIRMWARE_TOV 30
@@ -297,6 +297,8 @@ struct ddb_entry {
/* Driver Re-login */
unsigned long flags; /* DDB Flags */
+#define DDB_CONN_CLOSE_FAILURE 0 /* 0x00000001 */
+
uint16_t default_relogin_timeout; /* Max time to wait for
* relogin to complete */
atomic_t retry_relogin_timer; /* Min Time between relogins
@@ -580,7 +582,6 @@ struct scsi_qla_host {
#define AF_82XX_FW_DUMPED 24 /* 0x01000000 */
#define AF_8XXX_RST_OWNER 25 /* 0x02000000 */
#define AF_82XX_DUMP_READING 26 /* 0x04000000 */
-#define AF_83XX_NO_FW_DUMP 27 /* 0x08000000 */
#define AF_83XX_IOCB_INTR_ON 28 /* 0x10000000 */
#define AF_83XX_MBOX_INTR_ON 29 /* 0x20000000 */
@@ -595,10 +596,10 @@ struct scsi_qla_host {
#define DPC_AEN 9 /* 0x00000200 */
#define DPC_GET_DHCP_IP_ADDR 15 /* 0x00008000 */
#define DPC_LINK_CHANGED 18 /* 0x00040000 */
-#define DPC_RESET_ACTIVE 20 /* 0x00040000 */
-#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_RESET_ACTIVE 20 /* 0x00100000 */
+#define DPC_HA_UNRECOVERABLE 21 /* 0x00200000 ISP-82xx only*/
+#define DPC_HA_NEED_QUIESCENT 22 /* 0x00400000 ISP-82xx only*/
+#define DPC_POST_IDC_ACK 23 /* 0x00800000 */
#define DPC_RESTORE_ACB 24 /* 0x01000000 */
struct Scsi_Host *host; /* pointer to host data */
@@ -768,6 +769,7 @@ struct scsi_qla_host {
uint32_t fw_dump_capture_mask;
void *fw_dump_tmplt_hdr;
uint32_t fw_dump_tmplt_size;
+ uint32_t fw_dump_skip_size;
struct completion mbx_intr_comp;
@@ -910,7 +912,8 @@ static inline int is_qla80XX(struct scsi_qla_host *ha)
static inline int is_aer_supported(struct scsi_qla_host *ha)
{
return ((ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8022) ||
- (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8324));
+ (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8324) ||
+ (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8042));
}
static inline int adapter_up(struct scsi_qla_host *ha)
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
index 8d4092b33c07..209853ce0bbc 100644
--- a/drivers/scsi/qla4xxx/ql4_fw.h
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -390,6 +390,7 @@ struct qla_flt_region {
#define MBOX_CMD_CLEAR_DATABASE_ENTRY 0x0031
#define MBOX_CMD_CONN_OPEN 0x0074
#define MBOX_CMD_CONN_CLOSE_SESS_LOGOUT 0x0056
+#define DDB_NOT_LOGGED_IN 0x09
#define LOGOUT_OPTION_CLOSE_SESSION 0x0002
#define LOGOUT_OPTION_RELOGIN 0x0004
#define LOGOUT_OPTION_FREE_DDB 0x0008
@@ -505,9 +506,9 @@ struct qla_flt_region {
#define MBOX_ASTS_RESPONSE_QUEUE_FULL 0x8028
#define MBOX_ASTS_IP_ADDR_STATE_CHANGED 0x8029
#define MBOX_ASTS_IPV6_DEFAULT_ROUTER_CHANGED 0x802A
-#define MBOX_ASTS_IPV6_PREFIX_EXPIRED 0x802B
-#define MBOX_ASTS_IPV6_ND_PREFIX_IGNORED 0x802C
-#define MBOX_ASTS_IPV6_LCL_PREFIX_IGNORED 0x802D
+#define MBOX_ASTS_IPV6_LINK_MTU_CHANGE 0x802B
+#define MBOX_ASTS_IPV6_AUTO_PREFIX_IGNORED 0x802C
+#define MBOX_ASTS_IPV6_ND_LOCAL_PREFIX_IGNORED 0x802D
#define MBOX_ASTS_ICMPV6_ERROR_MSG_RCVD 0x802E
#define MBOX_ASTS_INITIALIZATION_FAILED 0x8031
#define MBOX_ASTS_SYSTEM_WARNING_EVENT 0x8036
@@ -528,14 +529,14 @@ struct qla_flt_region {
#define ACB_CONFIG_DISABLE 0x00
#define ACB_CONFIG_SET 0x01
-/* ACB State Defines */
-#define ACB_STATE_UNCONFIGURED 0x00
-#define ACB_STATE_INVALID 0x01
-#define ACB_STATE_ACQUIRING 0x02
-#define ACB_STATE_TENTATIVE 0x03
-#define ACB_STATE_DEPRICATED 0x04
-#define ACB_STATE_VALID 0x05
-#define ACB_STATE_DISABLING 0x06
+/* ACB/IP Address State Defines */
+#define IP_ADDRSTATE_UNCONFIGURED 0
+#define IP_ADDRSTATE_INVALID 1
+#define IP_ADDRSTATE_ACQUIRING 2
+#define IP_ADDRSTATE_TENTATIVE 3
+#define IP_ADDRSTATE_DEPRICATED 4
+#define IP_ADDRSTATE_PREFERRED 5
+#define IP_ADDRSTATE_DISABLING 6
/* FLASH offsets */
#define FLASH_SEGMENT_IFCB 0x04000000
@@ -698,14 +699,6 @@ struct addr_ctrl_blk {
uint8_t ipv6_lnk_lcl_addr_state;/* 222 */
uint8_t ipv6_addr0_state; /* 223 */
uint8_t ipv6_addr1_state; /* 224 */
-#define IP_ADDRSTATE_UNCONFIGURED 0
-#define IP_ADDRSTATE_INVALID 1
-#define IP_ADDRSTATE_ACQUIRING 2
-#define IP_ADDRSTATE_TENTATIVE 3
-#define IP_ADDRSTATE_DEPRICATED 4
-#define IP_ADDRSTATE_PREFERRED 5
-#define IP_ADDRSTATE_DISABLING 6
-
uint8_t ipv6_dflt_rtr_state; /* 225 */
#define IPV6_RTRSTATE_UNKNOWN 0
#define IPV6_RTRSTATE_MANUAL 1
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index d67c50e0b896..b1a19cd8d5b2 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -279,6 +279,8 @@ int qla4_83xx_ms_mem_write_128b(struct scsi_qla_host *ha,
uint8_t qla4xxx_set_ipaddr_state(uint8_t fw_ipaddr_state);
int qla4_83xx_get_port_config(struct scsi_qla_host *ha, uint32_t *config);
int qla4_83xx_set_port_config(struct scsi_qla_host *ha, uint32_t *config);
+int qla4_8xxx_check_init_adapter_retry(struct scsi_qla_host *ha);
+int qla4_83xx_is_detached(struct scsi_qla_host *ha);
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 7456eeb2e58a..28fbece7e08f 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -959,13 +959,8 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int is_reset)
qla4xxx_build_ddb_list(ha, is_reset);
set_bit(AF_ONLINE, &ha->flags);
-exit_init_hba:
- if (is_qla80XX(ha) && (status == QLA_ERROR)) {
- /* Since interrupts are registered in start_firmware for
- * 80XX, release them here if initialize_adapter fails */
- qla4xxx_free_irqs(ha);
- }
+exit_init_hba:
DEBUG2(printk("scsi%ld: initialize adapter: %s\n", ha->host_no,
status == QLA_ERROR ? "FAILED" : "SUCCEEDED"));
return status;
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index a3c8bc7706c2..b1925d195f41 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -385,9 +385,9 @@ static void qla4xxx_passthru_status_entry(struct scsi_qla_host *ha,
cls_conn = ddb_entry->conn;
conn = cls_conn->dd_data;
- spin_lock(&conn->session->lock);
+ spin_lock(&conn->session->back_lock);
task = iscsi_itt_to_task(conn, itt);
- spin_unlock(&conn->session->lock);
+ spin_unlock(&conn->session->back_lock);
if (task == NULL) {
ql4_printk(KERN_ERR, ha, "%s: Task is NULL\n", __func__);
@@ -635,6 +635,18 @@ static void qla4xxx_update_ipaddr_state(struct scsi_qla_host *ha,
}
}
+static void qla4xxx_default_router_changed(struct scsi_qla_host *ha,
+ uint32_t *mbox_sts)
+{
+ memcpy(&ha->ip_config.ipv6_default_router_addr.s6_addr32[0],
+ &mbox_sts[2], sizeof(uint32_t));
+ memcpy(&ha->ip_config.ipv6_default_router_addr.s6_addr32[1],
+ &mbox_sts[3], sizeof(uint32_t));
+ memcpy(&ha->ip_config.ipv6_default_router_addr.s6_addr32[2],
+ &mbox_sts[4], sizeof(uint32_t));
+ memcpy(&ha->ip_config.ipv6_default_router_addr.s6_addr32[3],
+ &mbox_sts[5], sizeof(uint32_t));
+}
/**
* qla4xxx_isr_decode_mailbox - decodes mailbox status
@@ -781,27 +793,44 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
mbox_sts[3]);
/* mbox_sts[2] = Old ACB state
* 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))) {
+ if ((mbox_sts[3] == IP_ADDRSTATE_PREFERRED) &&
+ ((mbox_sts[2] == IP_ADDRSTATE_TENTATIVE) ||
+ (mbox_sts[2] == IP_ADDRSTATE_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] == IP_ADDRSTATE_ACQUIRING) &&
+ (mbox_sts[2] == IP_ADDRSTATE_PREFERRED)) {
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_DISABLING) {
+ } else if (mbox_sts[3] == IP_ADDRSTATE_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)) {
+ } else if (mbox_sts[3] == IP_ADDRSTATE_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_IPV6_LINK_MTU_CHANGE:
+ case MBOX_ASTS_IPV6_AUTO_PREFIX_IGNORED:
+ case MBOX_ASTS_IPV6_ND_LOCAL_PREFIX_IGNORED:
+ /* No action */
+ DEBUG2(ql4_printk(KERN_INFO, ha, "scsi%ld: AEN %04x\n",
+ ha->host_no, mbox_status));
+ break;
+
+ case MBOX_ASTS_ICMPV6_ERROR_MSG_RCVD:
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "scsi%ld: AEN %04x, IPv6 ERROR, "
+ "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]));
+ break;
+
case MBOX_ASTS_MAC_ADDRESS_CHANGED:
case MBOX_ASTS_DNS:
/* No action */
@@ -939,6 +968,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
DEBUG2(ql4_printk(KERN_INFO, ha,
"scsi%ld: AEN %04x Received IPv6 default router changed notification\n",
ha->host_no, mbox_sts[0]));
+ qla4xxx_default_router_changed(ha, mbox_sts);
break;
case MBOX_ASTS_IDC_TIME_EXTEND_NOTIFICATION:
@@ -1022,7 +1052,8 @@ void qla4_82xx_interrupt_service_routine(struct scsi_qla_host *ha,
uint32_t intr_status)
{
/* Process response queue interrupt. */
- if (intr_status & HSRX_RISC_IOCB_INT)
+ if ((intr_status & HSRX_RISC_IOCB_INT) &&
+ test_bit(AF_INIT_DONE, &ha->flags))
qla4xxx_process_response_queue(ha);
/* Process mailbox/asynch event interrupt.*/
@@ -1399,6 +1430,7 @@ qla4_8xxx_msix_rsp_q(int irq, void *dev_id)
{
struct scsi_qla_host *ha = dev_id;
unsigned long flags;
+ int intr_status;
uint32_t ival = 0;
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -1412,8 +1444,15 @@ qla4_8xxx_msix_rsp_q(int irq, void *dev_id)
qla4xxx_process_response_queue(ha);
writel(0, &ha->qla4_83xx_reg->iocb_int_mask);
} else {
- qla4xxx_process_response_queue(ha);
- writel(0, &ha->qla4_82xx_reg->host_int);
+ intr_status = readl(&ha->qla4_82xx_reg->host_status);
+ if (intr_status & HSRX_RISC_IOCB_INT) {
+ qla4xxx_process_response_queue(ha);
+ writel(0, &ha->qla4_82xx_reg->host_int);
+ } else {
+ ql4_printk(KERN_INFO, ha, "%s: spurious iocb interrupt...\n",
+ __func__);
+ goto exit_msix_rsp_q;
+ }
}
ha->isr_count++;
exit_msix_rsp_q:
@@ -1488,6 +1527,7 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen)
int qla4xxx_request_irqs(struct scsi_qla_host *ha)
{
int ret;
+ int rval = QLA_ERROR;
if (is_qla40XX(ha))
goto try_intx;
@@ -1568,9 +1608,10 @@ irq_attached:
set_bit(AF_IRQ_ATTACHED, &ha->flags);
ha->host->irq = ha->pdev->irq;
ql4_printk(KERN_INFO, ha, "%s: irq %d attached\n",
- __func__, ha->pdev->irq);
+ __func__, ha->pdev->irq);
+ rval = QLA_SUCCESS;
irq_not_attached:
- return ret;
+ return rval;
}
void qla4xxx_free_irqs(struct scsi_qla_host *ha)
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index 9ae8ca3b69f9..0a6b782d6fdb 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -212,9 +212,8 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
ha->host_no, __func__));
goto mbox_exit;
}
- DEBUG2(printk("scsi%ld: Mailbox Cmd 0x%08X timed out ...,"
- " Scheduling Adapter Reset\n", ha->host_no,
- mbx_cmd[0]));
+ ql4_printk(KERN_WARNING, ha, "scsi%ld: Mailbox Cmd 0x%08X timed out, Scheduling Adapter Reset\n",
+ ha->host_no, mbx_cmd[0]);
ha->mailbox_timeout_count++;
mbx_sts[0] = (-1);
set_bit(DPC_RESET_HA, &ha->dpc_flags);
@@ -251,15 +250,16 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
break;
case MBOX_STS_BUSY:
- DEBUG2( printk("scsi%ld: %s: Cmd = %08X, ISP BUSY\n",
- ha->host_no, __func__, mbx_cmd[0]));
+ ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Cmd = %08X, ISP BUSY\n",
+ ha->host_no, __func__, mbx_cmd[0]);
ha->mailbox_timeout_count++;
break;
default:
- DEBUG2(printk("scsi%ld: %s: **** FAILED, cmd = %08X, "
- "sts = %08X ****\n", ha->host_no, __func__,
- mbx_cmd[0], mbx_sts[0]));
+ ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: FAILED, MBOX CMD = %08X, MBOX STS = %08X %08X %08X %08X %08X %08X %08X %08X\n",
+ ha->host_no, __func__, mbx_cmd[0], mbx_sts[0],
+ mbx_sts[1], mbx_sts[2], mbx_sts[3], mbx_sts[4],
+ mbx_sts[5], mbx_sts[6], mbx_sts[7]);
break;
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -383,7 +383,6 @@ qla4xxx_set_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
mbox_cmd[2] = LSDW(init_fw_cb_dma);
mbox_cmd[3] = MSDW(init_fw_cb_dma);
mbox_cmd[4] = sizeof(struct addr_ctrl_blk);
- mbox_cmd[5] = (IFCB_VER_MAX << 8) | IFCB_VER_MIN;
if (qla4xxx_mailbox_command(ha, 6, 6, mbox_cmd, mbox_sts) !=
QLA_SUCCESS) {
@@ -648,9 +647,6 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha)
goto exit_init_fw_cb;
}
- /* Initialize request and response queues. */
- qla4xxx_init_rings(ha);
-
/* Fill in the request and response queue information. */
init_fw_cb->rqq_consumer_idx = cpu_to_le16(ha->request_out);
init_fw_cb->compq_producer_idx = cpu_to_le16(ha->response_in);
@@ -1002,6 +998,10 @@ int qla4xxx_session_logout_ddb(struct scsi_qla_host *ha,
"%s: MBOX_CMD_CONN_CLOSE_SESS_LOGOUT "
"failed sts %04X %04X", __func__,
mbox_sts[0], mbox_sts[1]));
+ if ((mbox_sts[0] == MBOX_STS_COMMAND_ERROR) &&
+ (mbox_sts[1] == DDB_NOT_LOGGED_IN)) {
+ set_bit(DDB_CONN_CLOSE_FAILURE, &ddb_entry->flags);
+ }
}
return status;
@@ -1918,6 +1918,7 @@ int qla4xxx_disable_acb(struct scsi_qla_host *ha)
mbox_sts[0], mbox_sts[1], mbox_sts[2]));
} else {
if (is_qla8042(ha) &&
+ test_bit(DPC_POST_IDC_ACK, &ha->dpc_flags) &&
(mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE)) {
/*
* Disable ACB mailbox command takes time to complete
diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c
index d001202d3565..63328c812b70 100644
--- a/drivers/scsi/qla4xxx/ql4_nx.c
+++ b/drivers/scsi/qla4xxx/ql4_nx.c
@@ -2383,6 +2383,11 @@ static void qla4_8xxx_mark_entry_skipped(struct scsi_qla_host *ha,
"scsi(%ld): Skipping entry[%d]: ETYPE[0x%x]-ELEVEL[0x%x]\n",
ha->host_no, index, entry_hdr->entry_type,
entry_hdr->d_ctrl.entry_capture_mask));
+ /* If driver encounters a new entry type that it cannot process,
+ * it should just skip the entry and adjust the total buffer size by
+ * from subtracting the skipped bytes from it
+ */
+ ha->fw_dump_skip_size += entry_hdr->entry_capture_size;
}
/* ISP83xx functions to process new minidump entries... */
@@ -2590,6 +2595,7 @@ static int qla4_8xxx_collect_md_data(struct scsi_qla_host *ha)
uint64_t now;
uint32_t timestamp;
+ ha->fw_dump_skip_size = 0;
if (!ha->fw_dump) {
ql4_printk(KERN_INFO, ha, "%s(%ld) No buffer to dump\n",
__func__, ha->host_no);
@@ -2761,7 +2767,7 @@ skip_nxt_entry:
entry_hdr->entry_size);
}
- if (data_collected != ha->fw_dump_size) {
+ if ((data_collected + ha->fw_dump_skip_size) != 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);
@@ -2820,63 +2826,35 @@ void qla4_8xxx_get_minidump(struct scsi_qla_host *ha)
int qla4_8xxx_device_bootstrap(struct scsi_qla_host *ha)
{
int rval = QLA_ERROR;
- int i, timeout;
- uint32_t old_count, count, idc_ctrl;
- int need_reset = 0, peg_stuck = 1;
+ int i;
+ uint32_t old_count, count;
+ int need_reset = 0;
need_reset = ha->isp_ops->need_reset(ha);
- old_count = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_ALIVE_COUNTER);
-
- for (i = 0; i < 10; i++) {
- timeout = msleep_interruptible(200);
- if (timeout) {
- qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
- QLA8XXX_DEV_FAILED);
- return rval;
- }
-
- count = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_ALIVE_COUNTER);
- if (count != old_count)
- peg_stuck = 0;
- }
if (need_reset) {
/* We are trying to perform a recovery here. */
- if (peg_stuck)
+ if (test_bit(AF_FW_RECOVERY, &ha->flags))
ha->isp_ops->rom_lock_recovery(ha);
- goto dev_initialize;
} else {
- /* Start of day for this ha context. */
- if (peg_stuck) {
- /* Either we are the first or recovery in progress. */
- ha->isp_ops->rom_lock_recovery(ha);
- goto dev_initialize;
- } else {
- /* Firmware already running. */
- rval = QLA_SUCCESS;
- goto dev_ready;
+ old_count = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_ALIVE_COUNTER);
+ for (i = 0; i < 10; i++) {
+ msleep(200);
+ count = qla4_8xxx_rd_direct(ha,
+ QLA8XXX_PEG_ALIVE_COUNTER);
+ if (count != old_count) {
+ rval = QLA_SUCCESS;
+ goto dev_ready;
+ }
}
+ ha->isp_ops->rom_lock_recovery(ha);
}
-dev_initialize:
/* set to DEV_INITIALIZING */
ql4_printk(KERN_INFO, ha, "HW State: INITIALIZING\n");
qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
QLA8XXX_DEV_INITIALIZING);
- /*
- * For ISP8324 and ISP8042, if IDC_CTRL GRACEFUL_RESET_BIT1 is set,
- * reset it after device goes to INIT state.
- */
- 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,
- (idc_ctrl & ~GRACEFUL_RESET_BIT1));
- set_bit(AF_83XX_NO_FW_DUMP, &ha->flags);
- }
- }
-
ha->isp_ops->idc_unlock(ha);
if (is_qla8022(ha))
@@ -3209,6 +3187,10 @@ int qla4_8xxx_load_risc(struct scsi_qla_host *ha)
retval = qla4_8xxx_device_state_handler(ha);
+ /* Initialize request and response queues. */
+ if (retval == QLA_SUCCESS)
+ qla4xxx_init_rings(ha);
+
if (retval == QLA_SUCCESS && !test_bit(AF_IRQ_ATTACHED, &ha->flags))
retval = qla4xxx_request_irqs(ha);
@@ -3836,3 +3818,24 @@ qla4_8xxx_enable_msix(struct scsi_qla_host *ha)
msix_out:
return ret;
}
+
+int qla4_8xxx_check_init_adapter_retry(struct scsi_qla_host *ha)
+{
+ int status = QLA_SUCCESS;
+
+ /* Dont retry adapter initialization if IRQ allocation failed */
+ if (!test_bit(AF_IRQ_ATTACHED, &ha->flags)) {
+ ql4_printk(KERN_WARNING, ha, "%s: Skipping retry of adapter initialization as IRQs are not attached\n",
+ __func__);
+ status = QLA_ERROR;
+ goto exit_init_adapter_failure;
+ }
+
+ /* Since interrupts are registered in start_firmware for
+ * 8xxx, release them here if initialize_adapter fails
+ * and retry adapter initialization */
+ qla4xxx_free_irqs(ha);
+
+exit_init_adapter_failure:
+ return status;
+}
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index c21adc338cf1..459b9f7186fd 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -1670,16 +1670,13 @@ qla4xxx_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
struct sockaddr_in *addr;
struct sockaddr_in6 *addr6;
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
if (!shost) {
ret = -ENXIO;
- printk(KERN_ERR "%s: shost is NULL\n",
- __func__);
+ pr_err("%s: shost is NULL\n", __func__);
return ERR_PTR(ret);
}
ha = iscsi_host_priv(shost);
-
ep = iscsi_create_endpoint(sizeof(struct qla_endpoint));
if (!ep) {
ret = -ENOMEM;
@@ -1699,6 +1696,9 @@ qla4xxx_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
addr6 = (struct sockaddr_in6 *)&qla_ep->dst_addr;
DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI6\n", __func__,
(char *)&addr6->sin6_addr));
+ } else {
+ ql4_printk(KERN_WARNING, ha, "%s: Invalid endpoint\n",
+ __func__);
}
qla_ep->host = shost;
@@ -1712,9 +1712,9 @@ static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
struct scsi_qla_host *ha;
int ret = 0;
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
qla_ep = ep->dd_data;
ha = to_qla_host(qla_ep->host);
+ DEBUG2(pr_info_ratelimited("%s: host: %ld\n", __func__, ha->host_no));
if (adapter_up(ha) && !test_bit(AF_BUILD_DDB_LIST, &ha->flags))
ret = 1;
@@ -1724,7 +1724,13 @@ static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
static void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep)
{
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
+ struct qla_endpoint *qla_ep;
+ struct scsi_qla_host *ha;
+
+ qla_ep = ep->dd_data;
+ ha = to_qla_host(qla_ep->host);
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
+ ha->host_no));
iscsi_destroy_endpoint(ep);
}
@@ -1734,8 +1740,11 @@ static int qla4xxx_get_ep_param(struct iscsi_endpoint *ep,
{
struct qla_endpoint *qla_ep = ep->dd_data;
struct sockaddr *dst_addr;
+ struct scsi_qla_host *ha;
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
+ ha = to_qla_host(qla_ep->host);
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
+ ha->host_no));
switch (param) {
case ISCSI_PARAM_CONN_PORT:
@@ -1766,13 +1775,13 @@ static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn,
int ret;
dma_addr_t iscsi_stats_dma;
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
-
cls_sess = iscsi_conn_to_session(cls_conn);
sess = cls_sess->dd_data;
ddb_entry = sess->dd_data;
ha = ddb_entry->ha;
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
+ ha->host_no));
stats_size = PAGE_ALIGN(sizeof(struct ql_iscsi_stats));
/* Allocate memory */
ql_iscsi_stats = dma_alloc_coherent(&ha->pdev->dev, stats_size,
@@ -2100,7 +2109,8 @@ static void qla4xxx_set_ipv6(struct scsi_qla_host *ha,
cpu_to_le16(IPV6_TCPOPT_DELAYED_ACK_DISABLE);
else
init_fw_cb->ipv6_tcp_opts &=
- cpu_to_le16(~IPV6_TCPOPT_DELAYED_ACK_DISABLE);
+ cpu_to_le16(~IPV6_TCPOPT_DELAYED_ACK_DISABLE &
+ 0xFFFF);
break;
case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE:
if (iface_param->iface_num & 0x1)
@@ -2297,7 +2307,8 @@ static void qla4xxx_set_ipv4(struct scsi_qla_host *ha,
cpu_to_le16(TCPOPT_DELAYED_ACK_DISABLE);
else
init_fw_cb->ipv4_tcp_opts &=
- cpu_to_le16(~TCPOPT_DELAYED_ACK_DISABLE);
+ cpu_to_le16(~TCPOPT_DELAYED_ACK_DISABLE &
+ 0xFFFF);
break;
case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE:
if (iface_param->iface_num & 0x1)
@@ -3045,7 +3056,6 @@ qla4xxx_session_create(struct iscsi_endpoint *ep,
struct sockaddr *dst_addr;
int ret;
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
if (!ep) {
printk(KERN_ERR "qla4xxx: missing ep.\n");
return NULL;
@@ -3054,6 +3064,8 @@ qla4xxx_session_create(struct iscsi_endpoint *ep,
qla_ep = ep->dd_data;
dst_addr = (struct sockaddr *)&qla_ep->dst_addr;
ha = to_qla_host(qla_ep->host);
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
+ ha->host_no));
ret = qla4xxx_get_ddb_index(ha, &ddb_index);
if (ret == QLA_ERROR)
@@ -3074,6 +3086,7 @@ qla4xxx_session_create(struct iscsi_endpoint *ep,
ddb_entry->sess = cls_sess;
ddb_entry->unblock_sess = qla4xxx_unblock_ddb;
ddb_entry->ddb_change = qla4xxx_ddb_change;
+ clear_bit(DDB_CONN_CLOSE_FAILURE, &ddb_entry->flags);
cls_sess->recovery_tmo = ql4xsess_recovery_tmo;
ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry;
ha->tot_ddbs++;
@@ -3092,10 +3105,11 @@ static void qla4xxx_session_destroy(struct iscsi_cls_session *cls_sess)
uint32_t ddb_state;
int ret;
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
sess = cls_sess->dd_data;
ddb_entry = sess->dd_data;
ha = ddb_entry->ha;
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
+ ha->host_no));
fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
&fw_ddb_entry_dma, GFP_KERNEL);
@@ -3123,7 +3137,8 @@ static void qla4xxx_session_destroy(struct iscsi_cls_session *cls_sess)
destroy_session:
qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
-
+ if (test_and_clear_bit(DDB_CONN_CLOSE_FAILURE, &ddb_entry->flags))
+ clear_bit(ddb_entry->fw_ddb_index, ha->ddb_idx_map);
spin_lock_irqsave(&ha->hardware_lock, flags);
qla4xxx_free_ddb(ha, ddb_entry);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -3141,17 +3156,23 @@ qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx)
struct iscsi_cls_conn *cls_conn;
struct iscsi_session *sess;
struct ddb_entry *ddb_entry;
+ struct scsi_qla_host *ha;
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn),
conn_idx);
- if (!cls_conn)
+ if (!cls_conn) {
+ pr_info("%s: Can not create connection for conn_idx = %u\n",
+ __func__, conn_idx);
return NULL;
+ }
sess = cls_sess->dd_data;
ddb_entry = sess->dd_data;
ddb_entry->conn = cls_conn;
+ ha = ddb_entry->ha;
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: conn_idx = %u\n", __func__,
+ conn_idx));
return cls_conn;
}
@@ -3162,8 +3183,16 @@ static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session,
struct iscsi_conn *conn;
struct qla_conn *qla_conn;
struct iscsi_endpoint *ep;
+ struct ddb_entry *ddb_entry;
+ struct scsi_qla_host *ha;
+ struct iscsi_session *sess;
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
+ sess = cls_session->dd_data;
+ ddb_entry = sess->dd_data;
+ ha = ddb_entry->ha;
+
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: sid = %d, cid = %d\n", __func__,
+ cls_session->sid, cls_conn->cid));
if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
return -EINVAL;
@@ -3186,10 +3215,11 @@ static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn)
int ret = 0;
int status = QLA_SUCCESS;
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
sess = cls_sess->dd_data;
ddb_entry = sess->dd_data;
ha = ddb_entry->ha;
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: sid = %d, cid = %d\n", __func__,
+ cls_sess->sid, cls_conn->cid));
/* Check if we have matching FW DDB, if yes then do not
* login to this target. This could cause target to logout previous
@@ -3263,10 +3293,11 @@ static void qla4xxx_conn_destroy(struct iscsi_cls_conn *cls_conn)
struct ddb_entry *ddb_entry;
int options;
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
sess = cls_sess->dd_data;
ddb_entry = sess->dd_data;
ha = ddb_entry->ha;
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: cid = %d\n", __func__,
+ cls_conn->cid));
options = LOGOUT_OPTION_CLOSE_SESSION;
if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR)
@@ -4372,6 +4403,11 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
uint32_t dev_state;
uint32_t idc_ctrl;
+ if (is_qla8032(ha) &&
+ (qla4_83xx_is_detached(ha) == QLA_SUCCESS))
+ WARN_ONCE(1, "%s: iSCSI function %d marked invisible\n",
+ __func__, ha->func_num);
+
/* don't poll if reset is going on */
if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
@@ -4554,11 +4590,19 @@ static int qla4xxx_cmd_wait(struct scsi_qla_host *ha)
uint32_t index = 0;
unsigned long flags;
struct scsi_cmnd *cmd;
+ unsigned long wtime;
+ uint32_t wtmo;
+
+ if (is_qla40XX(ha))
+ wtmo = WAIT_CMD_TOV;
+ else
+ wtmo = ha->nx_reset_timeout / 2;
- unsigned long wtime = jiffies + (WAIT_CMD_TOV * HZ);
+ wtime = jiffies + (wtmo * HZ);
- DEBUG2(ql4_printk(KERN_INFO, ha, "Wait up to %d seconds for cmds to "
- "complete\n", WAIT_CMD_TOV));
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "Wait up to %u seconds for cmds to complete\n",
+ wtmo));
while (!time_after_eq(jiffies, wtime)) {
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -4861,11 +4905,11 @@ chip_reset:
qla4xxx_cmd_wait(ha);
qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
- qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
DEBUG2(ql4_printk(KERN_INFO, ha,
"scsi%ld: %s - Performing chip reset..\n",
ha->host_no, __func__));
status = ha->isp_ops->reset_chip(ha);
+ qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
}
/* Flush any pending ddb changed AENs */
@@ -4881,8 +4925,21 @@ recover_ha_init_adapter:
ssleep(6);
/* NOTE: AF_ONLINE flag set upon successful completion of
- * qla4xxx_initialize_adapter */
+ * qla4xxx_initialize_adapter */
status = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
+ if (is_qla80XX(ha) && (status == QLA_ERROR)) {
+ status = qla4_8xxx_check_init_adapter_retry(ha);
+ if (status == QLA_ERROR) {
+ ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Don't retry recover adapter\n",
+ ha->host_no, __func__);
+ qla4xxx_dead_adapter_cleanup(ha);
+ clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
+ clear_bit(DPC_RESET_HA, &ha->dpc_flags);
+ clear_bit(DPC_RESET_HA_FW_CONTEXT,
+ &ha->dpc_flags);
+ goto exit_recover;
+ }
+ }
}
/* Retry failed adapter initialization, if necessary
@@ -5228,9 +5285,9 @@ static void qla4xxx_do_dpc(struct work_struct *work)
container_of(work, struct scsi_qla_host, dpc_work);
int status = QLA_ERROR;
- DEBUG2(printk("scsi%ld: %s: DPC handler waking up."
- "flags = 0x%08lx, dpc_flags = 0x%08lx\n",
- ha->host_no, __func__, ha->flags, ha->dpc_flags))
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "scsi%ld: %s: DPC handler waking up. flags = 0x%08lx, dpc_flags = 0x%08lx\n",
+ ha->host_no, __func__, ha->flags, ha->dpc_flags));
/* Initialization not yet finished. Don't do anything yet. */
if (!test_bit(AF_INIT_DONE, &ha->flags))
@@ -8681,11 +8738,8 @@ static int qla4xxx_probe_adapter(struct pci_dev *pdev,
status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER);
/* Dont retry adapter initialization if IRQ allocation failed */
- if (is_qla80XX(ha) && !test_bit(AF_IRQ_ATTACHED, &ha->flags)) {
- ql4_printk(KERN_WARNING, ha, "%s: Skipping retry of adapter initialization\n",
- __func__);
+ if (is_qla80XX(ha) && (status == QLA_ERROR))
goto skip_retry_init;
- }
while ((!test_bit(AF_ONLINE, &ha->flags)) &&
init_retry_count++ < MAX_INIT_RETRIES) {
@@ -8709,6 +8763,10 @@ static int qla4xxx_probe_adapter(struct pci_dev *pdev,
continue;
status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER);
+ if (is_qla80XX(ha) && (status == QLA_ERROR)) {
+ if (qla4_8xxx_check_init_adapter_retry(ha) == QLA_ERROR)
+ goto skip_retry_init;
+ }
}
skip_retry_init:
@@ -8857,10 +8915,56 @@ static void qla4xxx_prevent_other_port_reinit(struct scsi_qla_host *ha)
}
}
+static void qla4xxx_destroy_ddb(struct scsi_qla_host *ha,
+ struct ddb_entry *ddb_entry)
+{
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ dma_addr_t fw_ddb_entry_dma;
+ unsigned long wtime;
+ uint32_t ddb_state;
+ int options;
+ int status;
+
+ 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__);
+ goto clear_ddb;
+ }
+
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ &fw_ddb_entry_dma, GFP_KERNEL);
+ if (!fw_ddb_entry) {
+ ql4_printk(KERN_ERR, ha,
+ "%s: Unable to allocate dma buffer\n", __func__);
+ goto clear_ddb;
+ }
+
+ wtime = jiffies + (HZ * LOGOUT_TOV);
+ do {
+ status = 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 (status == QLA_ERROR)
+ goto free_ddb;
+
+ if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) ||
+ (ddb_state == DDB_DS_SESSION_FAILED))
+ goto free_ddb;
+
+ schedule_timeout_uninterruptible(HZ);
+ } while ((time_after(wtime, jiffies)));
+
+free_ddb:
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ fw_ddb_entry, fw_ddb_entry_dma);
+clear_ddb:
+ qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
+}
+
static void qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host *ha)
{
struct ddb_entry *ddb_entry;
- int options;
int idx;
for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
@@ -8869,13 +8973,7 @@ static void qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host *ha)
if ((ddb_entry != NULL) &&
(ddb_entry->ddb_type == FLASH_DDB)) {
- 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__);
-
- qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
+ qla4xxx_destroy_ddb(ha, ddb_entry);
/*
* we have decremented the reference count of the driver
* when we setup the session to have the driver unload
@@ -9136,14 +9234,15 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd)
int ret = SUCCESS;
int wait = 0;
- ql4_printk(KERN_INFO, ha,
- "scsi%ld:%d:%d: Abort command issued cmd=%p\n",
- ha->host_no, id, lun, cmd);
+ ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%d: Abort command issued cmd=%p, cdb=0x%x\n",
+ ha->host_no, id, lun, cmd, cmd->cmnd[0]);
spin_lock_irqsave(&ha->hardware_lock, flags);
srb = (struct srb *) CMD_SP(cmd);
if (!srb) {
spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%d: Specified command has already completed.\n",
+ ha->host_no, id, lun);
return SUCCESS;
}
kref_get(&srb->srb_ref);
@@ -9560,28 +9659,36 @@ static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
}
fn = PCI_FUNC(ha->pdev->devfn);
- while (fn > 0) {
- fn--;
- ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Finding PCI device at "
- "func %x\n", ha->host_no, __func__, fn);
- /* Get the pci device given the domain, bus,
- * slot/function number */
- other_pdev =
- pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus),
- ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn),
- fn));
-
- if (!other_pdev)
- continue;
+ if (is_qla8022(ha)) {
+ while (fn > 0) {
+ fn--;
+ ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Finding PCI device at func %x\n",
+ ha->host_no, __func__, fn);
+ /* Get the pci device given the domain, bus,
+ * slot/function number */
+ other_pdev = pci_get_domain_bus_and_slot(
+ pci_domain_nr(ha->pdev->bus),
+ ha->pdev->bus->number,
+ PCI_DEVFN(PCI_SLOT(ha->pdev->devfn),
+ fn));
+
+ if (!other_pdev)
+ continue;
- if (atomic_read(&other_pdev->enable_cnt)) {
- ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Found PCI "
- "func in enabled state%x\n", ha->host_no,
- __func__, fn);
+ if (atomic_read(&other_pdev->enable_cnt)) {
+ ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Found PCI func in enabled state%x\n",
+ ha->host_no, __func__, fn);
+ pci_dev_put(other_pdev);
+ break;
+ }
pci_dev_put(other_pdev);
- break;
}
- pci_dev_put(other_pdev);
+ } else {
+ /* this case is meant for ISP83xx/ISP84xx only */
+ if (qla4_83xx_can_perform_reset(ha)) {
+ /* reset fn as iSCSI is going to perform the reset */
+ fn = 0;
+ }
}
/* The first function on the card, the reset owner will
@@ -9615,6 +9722,7 @@ static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
if (rval != QLA_SUCCESS) {
ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: "
"FAILED\n", ha->host_no, __func__);
+ qla4xxx_free_irqs(ha);
ha->isp_ops->idc_lock(ha);
qla4_8xxx_clear_drv_active(ha);
qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
@@ -9642,6 +9750,8 @@ static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
if (rval == QLA_SUCCESS)
ha->isp_ops->enable_intrs(ha);
+ else
+ qla4xxx_free_irqs(ha);
ha->isp_ops->idc_lock(ha);
qla4_8xxx_set_drv_active(ha);
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h
index 9b2946658683..c6ba0a6b8458 100644
--- a/drivers/scsi/qla4xxx/ql4_version.h
+++ b/drivers/scsi/qla4xxx/ql4_version.h
@@ -5,4 +5,4 @@
* See LICENSE.qla4xxx for copyright and licensing details.
*/
-#define QLA4XXX_DRIVER_VERSION "5.04.00-k3"
+#define QLA4XXX_DRIVER_VERSION "5.04.00-k4"
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index d8afec8317cf..c4d632c27a3e 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -161,47 +161,20 @@ static struct scsi_host_cmd_pool scsi_cmd_dma_pool = {
static DEFINE_MUTEX(host_cmd_pool_mutex);
/**
- * scsi_pool_alloc_command - internal function to get a fully allocated command
- * @pool: slab pool to allocate the command from
- * @gfp_mask: mask for the allocation
- *
- * Returns a fully allocated command (with the allied sense buffer) or
- * NULL on failure
- */
-static struct scsi_cmnd *
-scsi_pool_alloc_command(struct scsi_host_cmd_pool *pool, gfp_t gfp_mask)
-{
- struct scsi_cmnd *cmd;
-
- cmd = kmem_cache_zalloc(pool->cmd_slab, gfp_mask | pool->gfp_mask);
- if (!cmd)
- return NULL;
-
- cmd->sense_buffer = kmem_cache_alloc(pool->sense_slab,
- gfp_mask | pool->gfp_mask);
- if (!cmd->sense_buffer) {
- kmem_cache_free(pool->cmd_slab, cmd);
- return NULL;
- }
-
- return cmd;
-}
-
-/**
- * scsi_pool_free_command - internal function to release a command
- * @pool: slab pool to allocate the command from
+ * scsi_host_free_command - internal function to release a command
+ * @shost: host to free the command for
* @cmd: command to release
*
* the command must previously have been allocated by
- * scsi_pool_alloc_command.
+ * scsi_host_alloc_command.
*/
static void
-scsi_pool_free_command(struct scsi_host_cmd_pool *pool,
- struct scsi_cmnd *cmd)
+scsi_host_free_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
{
+ struct scsi_host_cmd_pool *pool = shost->cmd_pool;
+
if (cmd->prot_sdb)
kmem_cache_free(scsi_sdb_cache, cmd->prot_sdb);
-
kmem_cache_free(pool->sense_slab, cmd->sense_buffer);
kmem_cache_free(pool->cmd_slab, cmd);
}
@@ -217,22 +190,32 @@ scsi_pool_free_command(struct scsi_host_cmd_pool *pool,
static struct scsi_cmnd *
scsi_host_alloc_command(struct Scsi_Host *shost, gfp_t gfp_mask)
{
+ struct scsi_host_cmd_pool *pool = shost->cmd_pool;
struct scsi_cmnd *cmd;
- cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask);
+ cmd = kmem_cache_zalloc(pool->cmd_slab, gfp_mask | pool->gfp_mask);
if (!cmd)
- return NULL;
+ goto fail;
+
+ cmd->sense_buffer = kmem_cache_alloc(pool->sense_slab,
+ gfp_mask | pool->gfp_mask);
+ if (!cmd->sense_buffer)
+ goto fail_free_cmd;
if (scsi_host_get_prot(shost) >= SHOST_DIX_TYPE0_PROTECTION) {
cmd->prot_sdb = kmem_cache_zalloc(scsi_sdb_cache, gfp_mask);
-
- if (!cmd->prot_sdb) {
- scsi_pool_free_command(shost->cmd_pool, cmd);
- return NULL;
- }
+ if (!cmd->prot_sdb)
+ goto fail_free_sense;
}
return cmd;
+
+fail_free_sense:
+ kmem_cache_free(pool->sense_slab, cmd->sense_buffer);
+fail_free_cmd:
+ kmem_cache_free(pool->cmd_slab, cmd);
+fail:
+ return NULL;
}
/**
@@ -284,27 +267,19 @@ EXPORT_SYMBOL_GPL(__scsi_get_command);
*/
struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
{
- struct scsi_cmnd *cmd;
+ struct scsi_cmnd *cmd = __scsi_get_command(dev->host, gfp_mask);
+ unsigned long flags;
- /* Bail if we can't get a reference to the device */
- if (!get_device(&dev->sdev_gendev))
+ if (unlikely(cmd == NULL))
return NULL;
- cmd = __scsi_get_command(dev->host, gfp_mask);
-
- if (likely(cmd != NULL)) {
- unsigned long flags;
-
- cmd->device = dev;
- INIT_LIST_HEAD(&cmd->list);
- INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler);
- spin_lock_irqsave(&dev->list_lock, flags);
- list_add_tail(&cmd->list, &dev->cmd_list);
- spin_unlock_irqrestore(&dev->list_lock, flags);
- cmd->jiffies_at_alloc = jiffies;
- } else
- put_device(&dev->sdev_gendev);
-
+ cmd->device = dev;
+ INIT_LIST_HEAD(&cmd->list);
+ INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler);
+ spin_lock_irqsave(&dev->list_lock, flags);
+ list_add_tail(&cmd->list, &dev->cmd_list);
+ spin_unlock_irqrestore(&dev->list_lock, flags);
+ cmd->jiffies_at_alloc = jiffies;
return cmd;
}
EXPORT_SYMBOL(scsi_get_command);
@@ -313,25 +288,22 @@ EXPORT_SYMBOL(scsi_get_command);
* __scsi_put_command - Free a struct scsi_cmnd
* @shost: dev->host
* @cmd: Command to free
- * @dev: parent scsi device
*/
-void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd,
- struct device *dev)
+void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
{
unsigned long flags;
- /* changing locks here, don't need to restore the irq state */
- spin_lock_irqsave(&shost->free_list_lock, flags);
if (unlikely(list_empty(&shost->free_list))) {
- list_add(&cmd->list, &shost->free_list);
- cmd = NULL;
+ spin_lock_irqsave(&shost->free_list_lock, flags);
+ if (list_empty(&shost->free_list)) {
+ list_add(&cmd->list, &shost->free_list);
+ cmd = NULL;
+ }
+ spin_unlock_irqrestore(&shost->free_list_lock, flags);
}
- spin_unlock_irqrestore(&shost->free_list_lock, flags);
if (likely(cmd != NULL))
- scsi_pool_free_command(shost->cmd_pool, cmd);
-
- put_device(dev);
+ scsi_host_free_command(shost, cmd);
}
EXPORT_SYMBOL(__scsi_put_command);
@@ -345,7 +317,6 @@ EXPORT_SYMBOL(__scsi_put_command);
*/
void scsi_put_command(struct scsi_cmnd *cmd)
{
- struct scsi_device *sdev = cmd->device;
unsigned long flags;
/* serious error if the command hasn't come from a device list */
@@ -356,50 +327,107 @@ void scsi_put_command(struct scsi_cmnd *cmd)
cancel_delayed_work(&cmd->abort_work);
- __scsi_put_command(cmd->device->host, cmd, &sdev->sdev_gendev);
+ __scsi_put_command(cmd->device->host, cmd);
}
EXPORT_SYMBOL(scsi_put_command);
-static struct scsi_host_cmd_pool *scsi_get_host_cmd_pool(gfp_t gfp_mask)
+static struct scsi_host_cmd_pool *
+scsi_find_host_cmd_pool(struct Scsi_Host *shost)
+{
+ if (shost->hostt->cmd_size)
+ return shost->hostt->cmd_pool;
+ if (shost->unchecked_isa_dma)
+ return &scsi_cmd_dma_pool;
+ return &scsi_cmd_pool;
+}
+
+static void
+scsi_free_host_cmd_pool(struct scsi_host_cmd_pool *pool)
{
+ kfree(pool->sense_name);
+ kfree(pool->cmd_name);
+ kfree(pool);
+}
+
+static struct scsi_host_cmd_pool *
+scsi_alloc_host_cmd_pool(struct Scsi_Host *shost)
+{
+ struct scsi_host_template *hostt = shost->hostt;
+ struct scsi_host_cmd_pool *pool;
+
+ pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+ if (!pool)
+ return NULL;
+
+ pool->cmd_name = kasprintf(GFP_KERNEL, "%s_cmd", hostt->name);
+ pool->sense_name = kasprintf(GFP_KERNEL, "%s_sense", hostt->name);
+ if (!pool->cmd_name || !pool->sense_name) {
+ scsi_free_host_cmd_pool(pool);
+ return NULL;
+ }
+
+ pool->slab_flags = SLAB_HWCACHE_ALIGN;
+ if (shost->unchecked_isa_dma) {
+ pool->slab_flags |= SLAB_CACHE_DMA;
+ pool->gfp_mask = __GFP_DMA;
+ }
+ return pool;
+}
+
+static struct scsi_host_cmd_pool *
+scsi_get_host_cmd_pool(struct Scsi_Host *shost)
+{
+ struct scsi_host_template *hostt = shost->hostt;
struct scsi_host_cmd_pool *retval = NULL, *pool;
+ size_t cmd_size = sizeof(struct scsi_cmnd) + hostt->cmd_size;
+
/*
* Select a command slab for this host and create it if not
* yet existent.
*/
mutex_lock(&host_cmd_pool_mutex);
- pool = (gfp_mask & __GFP_DMA) ? &scsi_cmd_dma_pool :
- &scsi_cmd_pool;
+ pool = scsi_find_host_cmd_pool(shost);
+ if (!pool) {
+ pool = scsi_alloc_host_cmd_pool(shost);
+ if (!pool)
+ goto out;
+ }
+
if (!pool->users) {
- pool->cmd_slab = kmem_cache_create(pool->cmd_name,
- sizeof(struct scsi_cmnd), 0,
+ pool->cmd_slab = kmem_cache_create(pool->cmd_name, cmd_size, 0,
pool->slab_flags, NULL);
if (!pool->cmd_slab)
- goto fail;
+ goto out_free_pool;
pool->sense_slab = kmem_cache_create(pool->sense_name,
SCSI_SENSE_BUFFERSIZE, 0,
pool->slab_flags, NULL);
- if (!pool->sense_slab) {
- kmem_cache_destroy(pool->cmd_slab);
- goto fail;
- }
+ if (!pool->sense_slab)
+ goto out_free_slab;
}
pool->users++;
retval = pool;
- fail:
+out:
mutex_unlock(&host_cmd_pool_mutex);
return retval;
+
+out_free_slab:
+ kmem_cache_destroy(pool->cmd_slab);
+out_free_pool:
+ if (hostt->cmd_size)
+ scsi_free_host_cmd_pool(pool);
+ goto out;
}
-static void scsi_put_host_cmd_pool(gfp_t gfp_mask)
+static void scsi_put_host_cmd_pool(struct Scsi_Host *shost)
{
+ struct scsi_host_template *hostt = shost->hostt;
struct scsi_host_cmd_pool *pool;
mutex_lock(&host_cmd_pool_mutex);
- pool = (gfp_mask & __GFP_DMA) ? &scsi_cmd_dma_pool :
- &scsi_cmd_pool;
+ pool = scsi_find_host_cmd_pool(shost);
+
/*
* This may happen if a driver has a mismatched get and put
* of the command pool; the driver should be implicated in
@@ -410,67 +438,13 @@ static void scsi_put_host_cmd_pool(gfp_t gfp_mask)
if (!--pool->users) {
kmem_cache_destroy(pool->cmd_slab);
kmem_cache_destroy(pool->sense_slab);
+ if (hostt->cmd_size)
+ scsi_free_host_cmd_pool(pool);
}
mutex_unlock(&host_cmd_pool_mutex);
}
/**
- * scsi_allocate_command - get a fully allocated SCSI command
- * @gfp_mask: allocation mask
- *
- * This function is for use outside of the normal host based pools.
- * It allocates the relevant command and takes an additional reference
- * on the pool it used. This function *must* be paired with
- * scsi_free_command which also has the identical mask, otherwise the
- * free pool counts will eventually go wrong and you'll trigger a bug.
- *
- * This function should *only* be used by drivers that need a static
- * command allocation at start of day for internal functions.
- */
-struct scsi_cmnd *scsi_allocate_command(gfp_t gfp_mask)
-{
- struct scsi_host_cmd_pool *pool = scsi_get_host_cmd_pool(gfp_mask);
-
- if (!pool)
- return NULL;
-
- return scsi_pool_alloc_command(pool, gfp_mask);
-}
-EXPORT_SYMBOL(scsi_allocate_command);
-
-/**
- * scsi_free_command - free a command allocated by scsi_allocate_command
- * @gfp_mask: mask used in the original allocation
- * @cmd: command to free
- *
- * Note: using the original allocation mask is vital because that's
- * what determines which command pool we use to free the command. Any
- * mismatch will cause the system to BUG eventually.
- */
-void scsi_free_command(gfp_t gfp_mask, struct scsi_cmnd *cmd)
-{
- struct scsi_host_cmd_pool *pool = scsi_get_host_cmd_pool(gfp_mask);
-
- /*
- * this could trigger if the mask to scsi_allocate_command
- * doesn't match this mask. Otherwise we're guaranteed that this
- * succeeds because scsi_allocate_command must have taken a reference
- * on the pool
- */
- BUG_ON(!pool);
-
- scsi_pool_free_command(pool, cmd);
- /*
- * scsi_put_host_cmd_pool is called twice; once to release the
- * reference we took above, and once to release the reference
- * originally taken by scsi_allocate_command
- */
- scsi_put_host_cmd_pool(gfp_mask);
- scsi_put_host_cmd_pool(gfp_mask);
-}
-EXPORT_SYMBOL(scsi_free_command);
-
-/**
* scsi_setup_command_freelist - Setup the command freelist for a scsi host.
* @shost: host to allocate the freelist for.
*
@@ -482,14 +456,13 @@ EXPORT_SYMBOL(scsi_free_command);
*/
int scsi_setup_command_freelist(struct Scsi_Host *shost)
{
- struct scsi_cmnd *cmd;
const gfp_t gfp_mask = shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL;
+ struct scsi_cmnd *cmd;
spin_lock_init(&shost->free_list_lock);
INIT_LIST_HEAD(&shost->free_list);
- shost->cmd_pool = scsi_get_host_cmd_pool(gfp_mask);
-
+ shost->cmd_pool = scsi_get_host_cmd_pool(shost);
if (!shost->cmd_pool)
return -ENOMEM;
@@ -498,7 +471,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
*/
cmd = scsi_host_alloc_command(shost, gfp_mask);
if (!cmd) {
- scsi_put_host_cmd_pool(gfp_mask);
+ scsi_put_host_cmd_pool(shost);
shost->cmd_pool = NULL;
return -ENOMEM;
}
@@ -524,10 +497,10 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost)
cmd = list_entry(shost->free_list.next, struct scsi_cmnd, list);
list_del_init(&cmd->list);
- scsi_pool_free_command(shost->cmd_pool, cmd);
+ scsi_host_free_command(shost, cmd);
}
shost->cmd_pool = NULL;
- scsi_put_host_cmd_pool(shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL);
+ scsi_put_host_cmd_pool(shost);
}
#ifdef CONFIG_SCSI_LOGGING
@@ -954,7 +927,7 @@ EXPORT_SYMBOL(scsi_track_queue_full);
* This is an internal helper function. You probably want to use
* scsi_get_vpd_page instead.
*
- * Returns 0 on success or a negative error number.
+ * Returns size of the vpd page on success or a negative error number.
*/
static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
u8 page, unsigned len)
@@ -962,6 +935,9 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
int result;
unsigned char cmd[16];
+ if (len < 4)
+ return -EINVAL;
+
cmd[0] = INQUIRY;
cmd[1] = 1; /* EVPD */
cmd[2] = page;
@@ -976,13 +952,13 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer,
len, NULL, 30 * HZ, 3, NULL);
if (result)
- return result;
+ return -EIO;
/* Sanity check that we got the page back that we asked for */
if (buffer[1] != page)
return -EIO;
- return 0;
+ return get_unaligned_be16(&buffer[2]) + 4;
}
/**
@@ -1009,18 +985,18 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf,
/* Ask for all the pages supported by this device */
result = scsi_vpd_inquiry(sdev, buf, 0, buf_len);
- if (result)
+ if (result < 4)
goto fail;
/* If the user actually wanted this page, we can skip the rest */
if (page == 0)
return 0;
- for (i = 0; i < min((int)buf[3], buf_len - 4); i++)
- if (buf[i + 4] == page)
+ for (i = 4; i < min(result, buf_len); i++)
+ if (buf[i] == page)
goto found;
- if (i < buf[3] && i >= buf_len - 4)
+ if (i < result && i >= buf_len)
/* ran off the end of the buffer, give us benefit of doubt */
goto found;
/* The device claims it doesn't support the requested page */
@@ -1028,7 +1004,7 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf,
found:
result = scsi_vpd_inquiry(sdev, buf, page, buf_len);
- if (result)
+ if (result < 0)
goto fail;
return 0;
@@ -1039,6 +1015,93 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf,
EXPORT_SYMBOL_GPL(scsi_get_vpd_page);
/**
+ * scsi_attach_vpd - Attach Vital Product Data to a SCSI device structure
+ * @sdev: The device to ask
+ *
+ * Attach the 'Device Identification' VPD page (0x83) and the
+ * 'Unit Serial Number' VPD page (0x80) to a SCSI device
+ * structure. This information can be used to identify the device
+ * uniquely.
+ */
+void scsi_attach_vpd(struct scsi_device *sdev)
+{
+ int result, i;
+ int vpd_len = SCSI_VPD_PG_LEN;
+ int pg80_supported = 0;
+ int pg83_supported = 0;
+ unsigned char *vpd_buf;
+
+ if (sdev->skip_vpd_pages)
+ return;
+retry_pg0:
+ vpd_buf = kmalloc(vpd_len, GFP_KERNEL);
+ if (!vpd_buf)
+ return;
+
+ /* Ask for all the pages supported by this device */
+ result = scsi_vpd_inquiry(sdev, vpd_buf, 0, vpd_len);
+ if (result < 0) {
+ kfree(vpd_buf);
+ return;
+ }
+ if (result > vpd_len) {
+ vpd_len = result;
+ kfree(vpd_buf);
+ goto retry_pg0;
+ }
+
+ for (i = 4; i < result; i++) {
+ if (vpd_buf[i] == 0x80)
+ pg80_supported = 1;
+ if (vpd_buf[i] == 0x83)
+ pg83_supported = 1;
+ }
+ kfree(vpd_buf);
+ vpd_len = SCSI_VPD_PG_LEN;
+
+ if (pg80_supported) {
+retry_pg80:
+ vpd_buf = kmalloc(vpd_len, GFP_KERNEL);
+ if (!vpd_buf)
+ return;
+
+ result = scsi_vpd_inquiry(sdev, vpd_buf, 0x80, vpd_len);
+ if (result < 0) {
+ kfree(vpd_buf);
+ return;
+ }
+ if (result > vpd_len) {
+ vpd_len = result;
+ kfree(vpd_buf);
+ goto retry_pg80;
+ }
+ sdev->vpd_pg80_len = result;
+ sdev->vpd_pg80 = vpd_buf;
+ vpd_len = SCSI_VPD_PG_LEN;
+ }
+
+ if (pg83_supported) {
+retry_pg83:
+ vpd_buf = kmalloc(vpd_len, GFP_KERNEL);
+ if (!vpd_buf)
+ return;
+
+ result = scsi_vpd_inquiry(sdev, vpd_buf, 0x83, vpd_len);
+ if (result < 0) {
+ kfree(vpd_buf);
+ return;
+ }
+ if (result > vpd_len) {
+ vpd_len = result;
+ kfree(vpd_buf);
+ goto retry_pg83;
+ }
+ sdev->vpd_pg83_len = result;
+ sdev->vpd_pg83 = vpd_buf;
+ }
+}
+
+/**
* scsi_report_opcode - Find out if a given command opcode is supported
* @sdev: scsi device to query
* @buffer: scratch buffer (must be at least 20 bytes long)
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 2decc6417518..f3e9cc038d1d 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -64,6 +64,7 @@ static const char * scsi_debug_version_date = "20100324";
/* Additional Sense Code (ASC) */
#define NO_ADDITIONAL_SENSE 0x0
#define LOGICAL_UNIT_NOT_READY 0x4
+#define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
#define UNRECOVERED_READ_ERR 0x11
#define PARAMETER_LIST_LENGTH_ERR 0x1a
#define INVALID_OPCODE 0x20
@@ -195,6 +196,7 @@ static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH;
static bool scsi_debug_removable = DEF_REMOVABLE;
+static bool scsi_debug_clustering;
static int scsi_debug_cmnd_count = 0;
@@ -1780,7 +1782,6 @@ static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
be32_to_cpu(sdt->ref_tag) != ei_lba) {
pr_err("%s: REF check failed on sector %lu\n",
__func__, (unsigned long)sector);
- dif_errors++;
return 0x03;
}
return 0;
@@ -1789,23 +1790,27 @@ static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
unsigned int sectors, bool read)
{
- unsigned int i, resid;
- struct scatterlist *psgl;
+ size_t resid;
void *paddr;
const void *dif_store_end = dif_storep + sdebug_store_sectors;
+ struct sg_mapping_iter miter;
/* Bytes of protection data to copy into sgl */
resid = sectors * sizeof(*dif_storep);
- scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
- int len = min(psgl->length, resid);
+ sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
+ scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
+ (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
+
+ while (sg_miter_next(&miter) && resid > 0) {
+ size_t len = min(miter.length, resid);
void *start = dif_store(sector);
- int rest = 0;
+ size_t rest = 0;
if (dif_store_end < start + len)
rest = start + len - dif_store_end;
- paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
+ paddr = miter.addr;
if (read)
memcpy(paddr, start, len - rest);
@@ -1821,8 +1826,8 @@ static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
sector += len / sizeof(*dif_storep);
resid -= len;
- kunmap_atomic(paddr);
}
+ sg_miter_stop(&miter);
}
static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
@@ -1832,7 +1837,7 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
struct sd_dif_tuple *sdt;
sector_t sector;
- for (i = 0; i < sectors; i++) {
+ for (i = 0; i < sectors; i++, ei_lba++) {
int ret;
sector = start_sec + i;
@@ -1846,8 +1851,6 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
dif_errors++;
return ret;
}
-
- ei_lba++;
}
dif_copy_prot(SCpnt, start_sec, sectors, true);
@@ -1886,17 +1889,19 @@ static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
return check_condition_result;
}
+ read_lock_irqsave(&atomic_rw, iflags);
+
/* DIX + T10 DIF */
if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
if (prot_ret) {
+ read_unlock_irqrestore(&atomic_rw, iflags);
mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
return illegal_condition_result;
}
}
- read_lock_irqsave(&atomic_rw, iflags);
ret = do_device_access(SCpnt, devip, lba, num, 0);
read_unlock_irqrestore(&atomic_rw, iflags);
if (ret == -1)
@@ -1931,55 +1936,62 @@ void dump_sector(unsigned char *buf, int len)
static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
unsigned int sectors, u32 ei_lba)
{
- int i, j, ret;
+ int ret;
struct sd_dif_tuple *sdt;
- struct scatterlist *dsgl;
- struct scatterlist *psgl = scsi_prot_sglist(SCpnt);
- void *daddr, *paddr;
+ void *daddr;
sector_t sector = start_sec;
int ppage_offset;
+ int dpage_offset;
+ struct sg_mapping_iter diter;
+ struct sg_mapping_iter piter;
BUG_ON(scsi_sg_count(SCpnt) == 0);
BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
- ppage_offset = 0;
-
- /* For each data page */
- scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
- daddr = kmap_atomic(sg_page(dsgl)) + dsgl->offset;
- paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
-
- /* For each sector-sized chunk in data page */
- for (j = 0; j < dsgl->length; j += scsi_debug_sector_size) {
+ sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
+ scsi_prot_sg_count(SCpnt),
+ SG_MITER_ATOMIC | SG_MITER_FROM_SG);
+ sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
+ SG_MITER_ATOMIC | SG_MITER_FROM_SG);
+
+ /* For each protection page */
+ while (sg_miter_next(&piter)) {
+ dpage_offset = 0;
+ if (WARN_ON(!sg_miter_next(&diter))) {
+ ret = 0x01;
+ goto out;
+ }
+ for (ppage_offset = 0; ppage_offset < piter.length;
+ ppage_offset += sizeof(struct sd_dif_tuple)) {
/* If we're at the end of the current
- * protection page advance to the next one
+ * data page advance to the next one
*/
- if (ppage_offset >= psgl->length) {
- kunmap_atomic(paddr);
- psgl = sg_next(psgl);
- BUG_ON(psgl == NULL);
- paddr = kmap_atomic(sg_page(psgl))
- + psgl->offset;
- ppage_offset = 0;
+ if (dpage_offset >= diter.length) {
+ if (WARN_ON(!sg_miter_next(&diter))) {
+ ret = 0x01;
+ goto out;
+ }
+ dpage_offset = 0;
}
- sdt = paddr + ppage_offset;
+ sdt = piter.addr + ppage_offset;
+ daddr = diter.addr + dpage_offset;
- ret = dif_verify(sdt, daddr + j, sector, ei_lba);
+ ret = dif_verify(sdt, daddr, sector, ei_lba);
if (ret) {
- dump_sector(daddr + j, scsi_debug_sector_size);
+ dump_sector(daddr, scsi_debug_sector_size);
goto out;
}
sector++;
ei_lba++;
- ppage_offset += sizeof(struct sd_dif_tuple);
+ dpage_offset += scsi_debug_sector_size;
}
-
- kunmap_atomic(paddr);
- kunmap_atomic(daddr);
+ diter.consumed = dpage_offset;
+ sg_miter_stop(&diter);
}
+ sg_miter_stop(&piter);
dif_copy_prot(SCpnt, start_sec, sectors, false);
dix_writes++;
@@ -1988,8 +2000,8 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
out:
dif_errors++;
- kunmap_atomic(paddr);
- kunmap_atomic(daddr);
+ sg_miter_stop(&diter);
+ sg_miter_stop(&piter);
return ret;
}
@@ -2089,17 +2101,19 @@ static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
if (ret)
return ret;
+ write_lock_irqsave(&atomic_rw, iflags);
+
/* DIX + T10 DIF */
if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
if (prot_ret) {
+ write_unlock_irqrestore(&atomic_rw, iflags);
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
return illegal_condition_result;
}
}
- write_lock_irqsave(&atomic_rw, iflags);
ret = do_device_access(SCpnt, devip, lba, num, 1);
if (scsi_debug_lbp())
map_region(lba, num);
@@ -2178,6 +2192,7 @@ static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
struct unmap_block_desc *desc;
unsigned int i, payload_len, descriptors;
int ret;
+ unsigned long iflags;
ret = check_readiness(scmd, 1, devip);
if (ret)
@@ -2199,6 +2214,8 @@ static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
desc = (void *)&buf[8];
+ write_lock_irqsave(&atomic_rw, iflags);
+
for (i = 0 ; i < descriptors ; i++) {
unsigned long long lba = get_unaligned_be64(&desc[i].lba);
unsigned int num = get_unaligned_be32(&desc[i].blocks);
@@ -2213,6 +2230,7 @@ static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
ret = 0;
out:
+ write_unlock_irqrestore(&atomic_rw, iflags);
kfree(buf);
return ret;
@@ -2313,36 +2331,37 @@ static int resp_report_luns(struct scsi_cmnd * scp,
static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
unsigned int num, struct sdebug_dev_info *devip)
{
- int i, j, ret = -1;
+ int j;
unsigned char *kaddr, *buf;
unsigned int offset;
- struct scatterlist *sg;
struct scsi_data_buffer *sdb = scsi_in(scp);
+ struct sg_mapping_iter miter;
/* better not to use temporary buffer. */
buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
- if (!buf)
- return ret;
+ if (!buf) {
+ mk_sense_buffer(devip, NOT_READY,
+ LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
+ return check_condition_result;
+ }
scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
offset = 0;
- for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
- kaddr = (unsigned char *)kmap_atomic(sg_page(sg));
- if (!kaddr)
- goto out;
+ sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
+ SG_MITER_ATOMIC | SG_MITER_TO_SG);
- for (j = 0; j < sg->length; j++)
- *(kaddr + sg->offset + j) ^= *(buf + offset + j);
+ while (sg_miter_next(&miter)) {
+ kaddr = miter.addr;
+ for (j = 0; j < miter.length; j++)
+ *(kaddr + j) ^= *(buf + offset + j);
- offset += sg->length;
- kunmap_atomic(kaddr);
+ offset += miter.length;
}
- ret = 0;
-out:
+ sg_miter_stop(&miter);
kfree(buf);
- return ret;
+ return 0;
}
/* When timer goes off this function is called. */
@@ -2744,6 +2763,7 @@ static int schedule_resp(struct scsi_cmnd * cmnd,
*/
module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
+module_param_named(clustering, scsi_debug_clustering, bool, S_IRUGO | S_IWUSR);
module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
@@ -2787,6 +2807,7 @@ MODULE_VERSION(SCSI_DEBUG_VERSION);
MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
+MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
@@ -3248,7 +3269,7 @@ static struct attribute *sdebug_drv_attrs[] = {
};
ATTRIBUTE_GROUPS(sdebug_drv);
-struct device *pseudo_primary;
+static struct device *pseudo_primary;
static int __init scsi_debug_init(void)
{
@@ -3934,6 +3955,8 @@ static int sdebug_driver_probe(struct device * dev)
sdbg_host = to_sdebug_host(dev);
sdebug_driver_template.can_queue = scsi_debug_max_queue;
+ if (scsi_debug_clustering)
+ sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
if (NULL == hpnt) {
printk(KERN_ERR "%s: scsi_register failed\n", __func__);
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 78b004da2885..771c16bfdbac 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -2288,6 +2288,11 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
if (scsi_autopm_get_host(shost) < 0)
return FAILED;
+ if (!get_device(&dev->sdev_gendev)) {
+ rtn = FAILED;
+ goto out_put_autopm_host;
+ }
+
scmd = scsi_get_command(dev, GFP_KERNEL);
blk_rq_init(NULL, &req);
scmd->request = &req;
@@ -2345,6 +2350,7 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
scsi_run_host_queues(shost);
scsi_next_command(scmd);
+out_put_autopm_host:
scsi_autopm_put_host(shost);
return rtn;
}
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 7bd7f0d5f050..5681c05ac506 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -75,28 +75,6 @@ struct kmem_cache *scsi_sdb_cache;
*/
#define SCSI_QUEUE_DELAY 3
-/*
- * Function: scsi_unprep_request()
- *
- * Purpose: Remove all preparation done for a request, including its
- * associated scsi_cmnd, so that it can be requeued.
- *
- * Arguments: req - request to unprepare
- *
- * Lock status: Assumed that no locks are held upon entry.
- *
- * Returns: Nothing.
- */
-static void scsi_unprep_request(struct request *req)
-{
- struct scsi_cmnd *cmd = req->special;
-
- blk_unprep_request(req);
- req->special = NULL;
-
- scsi_put_command(cmd);
-}
-
/**
* __scsi_queue_insert - private queue insertion
* @cmd: The SCSI command being requeued
@@ -385,29 +363,12 @@ static inline int scsi_host_is_busy(struct Scsi_Host *shost)
return 0;
}
-/*
- * Function: scsi_run_queue()
- *
- * Purpose: Select a proper request queue to serve next
- *
- * Arguments: q - last request's queue
- *
- * Returns: Nothing
- *
- * Notes: The previous command was completely finished, start
- * a new one if possible.
- */
-static void scsi_run_queue(struct request_queue *q)
+static void scsi_starved_list_run(struct Scsi_Host *shost)
{
- struct scsi_device *sdev = q->queuedata;
- struct Scsi_Host *shost;
LIST_HEAD(starved_list);
+ struct scsi_device *sdev;
unsigned long flags;
- shost = sdev->host;
- if (scsi_target(sdev)->single_lun)
- scsi_single_lun_run(sdev);
-
spin_lock_irqsave(shost->host_lock, flags);
list_splice_init(&shost->starved_list, &starved_list);
@@ -459,6 +420,28 @@ static void scsi_run_queue(struct request_queue *q)
/* put any unprocessed entries back */
list_splice(&starved_list, &shost->starved_list);
spin_unlock_irqrestore(shost->host_lock, flags);
+}
+
+/*
+ * Function: scsi_run_queue()
+ *
+ * Purpose: Select a proper request queue to serve next
+ *
+ * Arguments: q - last request's queue
+ *
+ * Returns: Nothing
+ *
+ * Notes: The previous command was completely finished, start
+ * a new one if possible.
+ */
+static void scsi_run_queue(struct request_queue *q)
+{
+ struct scsi_device *sdev = q->queuedata;
+
+ if (scsi_target(sdev)->single_lun)
+ scsi_single_lun_run(sdev);
+ if (!list_empty(&sdev->host->starved_list))
+ scsi_starved_list_run(sdev->host);
blk_run_queue(q);
}
@@ -497,16 +480,10 @@ static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd)
struct request *req = cmd->request;
unsigned long flags;
- /*
- * We need to hold a reference on the device to avoid the queue being
- * killed after the unlock and before scsi_run_queue is invoked which
- * may happen because scsi_unprep_request() puts the command which
- * releases its reference on the device.
- */
- get_device(&sdev->sdev_gendev);
-
spin_lock_irqsave(q->queue_lock, flags);
- scsi_unprep_request(req);
+ blk_unprep_request(req);
+ req->special = NULL;
+ scsi_put_command(cmd);
blk_requeue_request(q, req);
spin_unlock_irqrestore(q->queue_lock, flags);
@@ -520,13 +497,9 @@ void scsi_next_command(struct scsi_cmnd *cmd)
struct scsi_device *sdev = cmd->device;
struct request_queue *q = sdev->request_queue;
- /* need to hold a reference on the device before we let go of the cmd */
- get_device(&sdev->sdev_gendev);
-
scsi_put_command(cmd);
scsi_run_queue(q);
- /* ok to remove device now */
put_device(&sdev->sdev_gendev);
}
@@ -788,6 +761,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
enum {ACTION_FAIL, ACTION_REPREP, ACTION_RETRY,
ACTION_DELAYED_RETRY} action;
char *description = NULL;
+ unsigned long wait_for = (cmd->allowed + 1) * req->timeout;
if (result) {
sense_valid = scsi_command_normalize_sense(cmd, &sshdr);
@@ -989,6 +963,12 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
action = ACTION_FAIL;
}
+ if (action != ACTION_FAIL &&
+ time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) {
+ action = ACTION_FAIL;
+ description = "Command timed out";
+ }
+
switch (action) {
case ACTION_FAIL:
/* Give up and fail the remainder of the request */
@@ -1111,6 +1091,7 @@ err_exit:
scsi_release_buffers(cmd);
cmd->request->special = NULL;
scsi_put_command(cmd);
+ put_device(&cmd->device->sdev_gendev);
return error;
}
EXPORT_SYMBOL(scsi_init_io);
@@ -1121,9 +1102,15 @@ static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
struct scsi_cmnd *cmd;
if (!req->special) {
+ /* Bail if we can't get a reference to the device */
+ if (!get_device(&sdev->sdev_gendev))
+ return NULL;
+
cmd = scsi_get_command(sdev, GFP_ATOMIC);
- if (unlikely(!cmd))
+ if (unlikely(!cmd)) {
+ put_device(&sdev->sdev_gendev);
return NULL;
+ }
req->special = cmd;
} else {
cmd = req->special;
@@ -1286,6 +1273,7 @@ int scsi_prep_return(struct request_queue *q, struct request *req, int ret)
struct scsi_cmnd *cmd = req->special;
scsi_release_buffers(cmd);
scsi_put_command(cmd);
+ put_device(&cmd->device->sdev_gendev);
req->special = NULL;
}
break;
@@ -1543,16 +1531,14 @@ static void scsi_softirq_done(struct request *rq)
* Lock status: IO request lock assumed to be held when called.
*/
static void scsi_request_fn(struct request_queue *q)
+ __releases(q->queue_lock)
+ __acquires(q->queue_lock)
{
struct scsi_device *sdev = q->queuedata;
struct Scsi_Host *shost;
struct scsi_cmnd *cmd;
struct request *req;
- if(!get_device(&sdev->sdev_gendev))
- /* We must be tearing the block queue down already */
- return;
-
/*
* To start with, we keep looping until the queue is empty, or until
* the host is no longer able to accept any more requests.
@@ -1641,7 +1627,7 @@ static void scsi_request_fn(struct request_queue *q)
goto out_delay;
}
- goto out;
+ return;
not_ready:
spin_unlock_irq(shost->host_lock);
@@ -1660,12 +1646,6 @@ static void scsi_request_fn(struct request_queue *q)
out_delay:
if (sdev->device_busy == 0)
blk_delay_queue(q, SCSI_QUEUE_DELAY);
-out:
- /* must be careful here...if we trigger the ->remove() function
- * we cannot be holding the q lock */
- spin_unlock_irq(q->queue_lock);
- put_device(&sdev->sdev_gendev);
- spin_lock_irq(q->queue_lock);
}
u64 scsi_calculate_bounce_limit(struct Scsi_Host *shost)
@@ -1684,7 +1664,7 @@ u64 scsi_calculate_bounce_limit(struct Scsi_Host *shost)
host_dev = scsi_get_device(shost);
if (host_dev && host_dev->dma_mask)
- bounce_limit = dma_max_pfn(host_dev) << PAGE_SHIFT;
+ bounce_limit = (u64)dma_max_pfn(host_dev) << PAGE_SHIFT;
return bounce_limit;
}
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 307a81137607..27f96d5b7680 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -320,6 +320,7 @@ static void scsi_target_destroy(struct scsi_target *starget)
struct Scsi_Host *shost = dev_to_shost(dev->parent);
unsigned long flags;
+ starget->state = STARGET_DEL;
transport_destroy_device(dev);
spin_lock_irqsave(shost->host_lock, flags);
if (shost->hostt->target_destroy)
@@ -371,6 +372,37 @@ static struct scsi_target *__scsi_find_target(struct device *parent,
}
/**
+ * scsi_target_reap_ref_release - remove target from visibility
+ * @kref: the reap_ref in the target being released
+ *
+ * Called on last put of reap_ref, which is the indication that no device
+ * under this target is visible anymore, so render the target invisible in
+ * sysfs. Note: we have to be in user context here because the target reaps
+ * should be done in places where the scsi device visibility is being removed.
+ */
+static void scsi_target_reap_ref_release(struct kref *kref)
+{
+ struct scsi_target *starget
+ = container_of(kref, struct scsi_target, reap_ref);
+
+ /*
+ * if we get here and the target is still in the CREATED state that
+ * means it was allocated but never made visible (because a scan
+ * turned up no LUNs), so don't call device_del() on it.
+ */
+ if (starget->state != STARGET_CREATED) {
+ transport_remove_device(&starget->dev);
+ device_del(&starget->dev);
+ }
+ scsi_target_destroy(starget);
+}
+
+static void scsi_target_reap_ref_put(struct scsi_target *starget)
+{
+ kref_put(&starget->reap_ref, scsi_target_reap_ref_release);
+}
+
+/**
* scsi_alloc_target - allocate a new or find an existing target
* @parent: parent of the target (need not be a scsi host)
* @channel: target channel number (zero if no channels)
@@ -392,7 +424,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
+ shost->transportt->target_size;
struct scsi_target *starget;
struct scsi_target *found_target;
- int error;
+ int error, ref_got;
starget = kzalloc(size, GFP_KERNEL);
if (!starget) {
@@ -401,7 +433,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
}
dev = &starget->dev;
device_initialize(dev);
- starget->reap_ref = 1;
+ kref_init(&starget->reap_ref);
dev->parent = get_device(parent);
dev_set_name(dev, "target%d:%d:%d", shost->host_no, channel, id);
dev->bus = &scsi_bus_type;
@@ -441,29 +473,36 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
return starget;
found:
- found_target->reap_ref++;
+ /*
+ * release routine already fired if kref is zero, so if we can still
+ * take the reference, the target must be alive. If we can't, it must
+ * be dying and we need to wait for a new target
+ */
+ ref_got = kref_get_unless_zero(&found_target->reap_ref);
+
spin_unlock_irqrestore(shost->host_lock, flags);
- if (found_target->state != STARGET_DEL) {
+ if (ref_got) {
put_device(dev);
return found_target;
}
- /* Unfortunately, we found a dying target; need to
- * wait until it's dead before we can get a new one */
+ /*
+ * Unfortunately, we found a dying target; need to wait until it's
+ * dead before we can get a new one. There is an anomaly here. We
+ * *should* call scsi_target_reap() to balance the kref_get() of the
+ * reap_ref above. However, since the target being released, it's
+ * already invisible and the reap_ref is irrelevant. If we call
+ * scsi_target_reap() we might spuriously do another device_del() on
+ * an already invisible target.
+ */
put_device(&found_target->dev);
- flush_scheduled_work();
+ /*
+ * length of time is irrelevant here, we just want to yield the CPU
+ * for a tick to avoid busy waiting for the target to die.
+ */
+ msleep(1);
goto retry;
}
-static void scsi_target_reap_usercontext(struct work_struct *work)
-{
- struct scsi_target *starget =
- container_of(work, struct scsi_target, ew.work);
-
- transport_remove_device(&starget->dev);
- device_del(&starget->dev);
- scsi_target_destroy(starget);
-}
-
/**
* scsi_target_reap - check to see if target is in use and destroy if not
* @starget: target to be checked
@@ -474,28 +513,13 @@ static void scsi_target_reap_usercontext(struct work_struct *work)
*/
void scsi_target_reap(struct scsi_target *starget)
{
- struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
- unsigned long flags;
- enum scsi_target_state state;
- int empty = 0;
-
- spin_lock_irqsave(shost->host_lock, flags);
- state = starget->state;
- if (--starget->reap_ref == 0 && list_empty(&starget->devices)) {
- empty = 1;
- starget->state = STARGET_DEL;
- }
- spin_unlock_irqrestore(shost->host_lock, flags);
-
- if (!empty)
- return;
-
- BUG_ON(state == STARGET_DEL);
- if (state == STARGET_CREATED)
- scsi_target_destroy(starget);
- else
- execute_in_process_context(scsi_target_reap_usercontext,
- &starget->ew);
+ /*
+ * serious problem if this triggers: STARGET_DEL is only set in the if
+ * the reap_ref drops to zero, so we're trying to do another final put
+ * on an already released kref
+ */
+ BUG_ON(starget->state == STARGET_DEL);
+ scsi_target_reap_ref_put(starget);
}
/**
@@ -946,6 +970,9 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
}
}
+ if (sdev->scsi_level >= SCSI_3)
+ scsi_attach_vpd(sdev);
+
sdev->max_queue_depth = sdev->queue_depth;
/*
@@ -1532,6 +1559,10 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
}
mutex_unlock(&shost->scan_mutex);
scsi_autopm_put_target(starget);
+ /*
+ * paired with scsi_alloc_target(). Target will be destroyed unless
+ * scsi_probe_and_add_lun made an underlying device visible
+ */
scsi_target_reap(starget);
put_device(&starget->dev);
@@ -1612,8 +1643,10 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel,
out_reap:
scsi_autopm_put_target(starget);
- /* now determine if the target has any children at all
- * and if not, nuke it */
+ /*
+ * paired with scsi_alloc_target(): determine if the target has
+ * any children at all and if not, nuke it
+ */
scsi_target_reap(starget);
put_device(&starget->dev);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 9117d0bf408e..074e8cc30955 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -300,7 +300,9 @@ store_shost_eh_deadline(struct device *dev, struct device_attribute *attr,
int ret = -EINVAL;
unsigned long deadline, flags;
- if (shost->transportt && shost->transportt->eh_strategy_handler)
+ if (shost->transportt &&
+ (shost->transportt->eh_strategy_handler ||
+ !shost->hostt->eh_host_reset_handler))
return ret;
if (!strncmp(buf, "off", strlen("off")))
@@ -383,17 +385,14 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
{
struct scsi_device *sdev;
struct device *parent;
- struct scsi_target *starget;
struct list_head *this, *tmp;
unsigned long flags;
sdev = container_of(work, struct scsi_device, ew.work);
parent = sdev->sdev_gendev.parent;
- starget = to_scsi_target(parent);
spin_lock_irqsave(sdev->host->host_lock, flags);
- starget->reap_ref++;
list_del(&sdev->siblings);
list_del(&sdev->same_target_siblings);
list_del(&sdev->starved_entry);
@@ -413,8 +412,8 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
/* NULL queue means the device can't be used */
sdev->request_queue = NULL;
- scsi_target_reap(scsi_target(sdev));
-
+ kfree(sdev->vpd_pg83);
+ kfree(sdev->vpd_pg80);
kfree(sdev->inquiry);
kfree(sdev);
@@ -579,7 +578,6 @@ static int scsi_sdev_check_buf_bit(const char *buf)
* Create the actual show/store functions and data structures.
*/
sdev_rd_attr (device_blocked, "%d\n");
-sdev_rd_attr (queue_depth, "%d\n");
sdev_rd_attr (device_busy, "%d\n");
sdev_rd_attr (type, "%d\n");
sdev_rd_attr (scsi_level, "%d\n");
@@ -649,23 +647,12 @@ store_rescan_field (struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field);
-static void sdev_store_delete_callback(struct device *dev)
-{
- scsi_remove_device(to_scsi_device(dev));
-}
-
static ssize_t
sdev_store_delete(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- int rc;
-
- /* An attribute cannot be unregistered by one of its own methods,
- * so we have to use this roundabout approach.
- */
- rc = device_schedule_callback(dev, sdev_store_delete_callback);
- if (rc)
- count = rc;
+ if (device_remove_file_self(dev, attr))
+ scsi_remove_device(to_scsi_device(dev));
return count;
};
static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete);
@@ -723,10 +710,64 @@ show_queue_type_field(struct device *dev, struct device_attribute *attr,
return snprintf(buf, 20, "%s\n", name);
}
-static DEVICE_ATTR(queue_type, S_IRUGO, show_queue_type_field, NULL);
+static ssize_t
+store_queue_type_field(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct scsi_host_template *sht = sdev->host->hostt;
+ int tag_type = 0, retval;
+ int prev_tag_type = scsi_get_tag_type(sdev);
+
+ if (!sdev->tagged_supported || !sht->change_queue_type)
+ return -EINVAL;
+
+ if (strncmp(buf, "ordered", 7) == 0)
+ tag_type = MSG_ORDERED_TAG;
+ else if (strncmp(buf, "simple", 6) == 0)
+ tag_type = MSG_SIMPLE_TAG;
+ else if (strncmp(buf, "none", 4) != 0)
+ return -EINVAL;
+
+ if (tag_type == prev_tag_type)
+ return count;
+
+ retval = sht->change_queue_type(sdev, tag_type);
+ if (retval < 0)
+ return retval;
+
+ return count;
+}
+
+static DEVICE_ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field,
+ store_queue_type_field);
+
+#define sdev_vpd_pg_attr(_page) \
+static ssize_t \
+show_vpd_##_page(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); \
+ struct scsi_device *sdev = to_scsi_device(dev); \
+ if (!sdev->vpd_##_page) \
+ return -EINVAL; \
+ return memory_read_from_buffer(buf, count, &off, \
+ sdev->vpd_##_page, \
+ sdev->vpd_##_page##_len); \
+} \
+static struct bin_attribute dev_attr_vpd_##_page = { \
+ .attr = {.name = __stringify(vpd_##_page), .mode = S_IRUGO }, \
+ .size = 0, \
+ .read = show_vpd_##_page, \
+};
+
+sdev_vpd_pg_attr(pg83);
+sdev_vpd_pg_attr(pg80);
static ssize_t
-show_iostat_counterbits(struct device *dev, struct device_attribute *attr, char *buf)
+show_iostat_counterbits(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
return snprintf(buf, 20, "%d\n", (int)sizeof(atomic_t) * 8);
}
@@ -797,46 +838,9 @@ 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[] = {
- &dev_attr_device_blocked.attr,
- &dev_attr_type.attr,
- &dev_attr_scsi_level.attr,
- &dev_attr_device_busy.attr,
- &dev_attr_vendor.attr,
- &dev_attr_model.attr,
- &dev_attr_rev.attr,
- &dev_attr_rescan.attr,
- &dev_attr_delete.attr,
- &dev_attr_state.attr,
- &dev_attr_timeout.attr,
- &dev_attr_eh_timeout.attr,
- &dev_attr_iocounterbits.attr,
- &dev_attr_iorequest_cnt.attr,
- &dev_attr_iodone_cnt.attr,
- &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
-};
-
-static struct attribute_group scsi_sdev_attr_group = {
- .attrs = scsi_sdev_attrs,
-};
-
-static const struct attribute_group *scsi_sdev_attr_groups[] = {
- &scsi_sdev_attr_group,
- NULL
-};
-
static ssize_t
-sdev_store_queue_depth_rw(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+sdev_store_queue_depth(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
int depth, retval;
struct scsi_device *sdev = to_scsi_device(dev);
@@ -859,10 +863,10 @@ sdev_store_queue_depth_rw(struct device *dev, struct device_attribute *attr,
return count;
}
+sdev_show_function(queue_depth, "%d\n");
-static struct device_attribute sdev_attr_queue_depth_rw =
- __ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth,
- sdev_store_queue_depth_rw);
+static DEVICE_ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth,
+ sdev_store_queue_depth);
static ssize_t
sdev_show_queue_ramp_up_period(struct device *dev,
@@ -890,40 +894,79 @@ sdev_store_queue_ramp_up_period(struct device *dev,
return period;
}
-static struct device_attribute sdev_attr_queue_ramp_up_period =
- __ATTR(queue_ramp_up_period, S_IRUGO | S_IWUSR,
- sdev_show_queue_ramp_up_period,
- sdev_store_queue_ramp_up_period);
+static DEVICE_ATTR(queue_ramp_up_period, S_IRUGO | S_IWUSR,
+ sdev_show_queue_ramp_up_period,
+ sdev_store_queue_ramp_up_period);
-static ssize_t
-sdev_store_queue_type_rw(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static umode_t scsi_sdev_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int i)
{
+ struct device *dev = container_of(kobj, struct device, kobj);
struct scsi_device *sdev = to_scsi_device(dev);
- struct scsi_host_template *sht = sdev->host->hostt;
- int tag_type = 0, retval;
- int prev_tag_type = scsi_get_tag_type(sdev);
- if (!sdev->tagged_supported || !sht->change_queue_type)
- return -EINVAL;
- if (strncmp(buf, "ordered", 7) == 0)
- tag_type = MSG_ORDERED_TAG;
- else if (strncmp(buf, "simple", 6) == 0)
- tag_type = MSG_SIMPLE_TAG;
- else if (strncmp(buf, "none", 4) != 0)
- return -EINVAL;
+ if (attr == &dev_attr_queue_depth.attr &&
+ !sdev->host->hostt->change_queue_depth)
+ return S_IRUGO;
- if (tag_type == prev_tag_type)
- return count;
+ if (attr == &dev_attr_queue_ramp_up_period.attr &&
+ !sdev->host->hostt->change_queue_depth)
+ return 0;
- retval = sht->change_queue_type(sdev, tag_type);
- if (retval < 0)
- return retval;
+ if (attr == &dev_attr_queue_type.attr &&
+ !sdev->host->hostt->change_queue_type)
+ return S_IRUGO;
- return count;
+ return attr->mode;
}
+/* Default template for device attributes. May NOT be modified */
+static struct attribute *scsi_sdev_attrs[] = {
+ &dev_attr_device_blocked.attr,
+ &dev_attr_type.attr,
+ &dev_attr_scsi_level.attr,
+ &dev_attr_device_busy.attr,
+ &dev_attr_vendor.attr,
+ &dev_attr_model.attr,
+ &dev_attr_rev.attr,
+ &dev_attr_rescan.attr,
+ &dev_attr_delete.attr,
+ &dev_attr_state.attr,
+ &dev_attr_timeout.attr,
+ &dev_attr_eh_timeout.attr,
+ &dev_attr_iocounterbits.attr,
+ &dev_attr_iorequest_cnt.attr,
+ &dev_attr_iodone_cnt.attr,
+ &dev_attr_ioerr_cnt.attr,
+ &dev_attr_modalias.attr,
+ &dev_attr_queue_depth.attr,
+ &dev_attr_queue_type.attr,
+ &dev_attr_queue_ramp_up_period.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
+};
+
+static struct bin_attribute *scsi_sdev_bin_attrs[] = {
+ &dev_attr_vpd_pg83,
+ &dev_attr_vpd_pg80,
+ NULL
+};
+static struct attribute_group scsi_sdev_attr_group = {
+ .attrs = scsi_sdev_attrs,
+ .bin_attrs = scsi_sdev_bin_attrs,
+ .is_visible = scsi_sdev_attr_is_visible,
+};
+
+static const struct attribute_group *scsi_sdev_attr_groups[] = {
+ &scsi_sdev_attr_group,
+ NULL
+};
+
static int scsi_target_add(struct scsi_target *starget)
{
int error;
@@ -946,10 +989,6 @@ static int scsi_target_add(struct scsi_target *starget)
return 0;
}
-static struct device_attribute sdev_attr_queue_type_rw =
- __ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field,
- sdev_store_queue_type_rw);
-
/**
* scsi_sysfs_add_sdev - add scsi device to sysfs
* @sdev: scsi_device to add
@@ -1003,25 +1042,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
transport_add_device(&sdev->sdev_gendev);
sdev->is_visible = 1;
- /* create queue files, which may be writable, depending on the host */
- if (sdev->host->hostt->change_queue_depth) {
- error = device_create_file(&sdev->sdev_gendev,
- &sdev_attr_queue_depth_rw);
- error = device_create_file(&sdev->sdev_gendev,
- &sdev_attr_queue_ramp_up_period);
- }
- else
- error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_depth);
- if (error)
- return error;
-
- if (sdev->host->hostt->change_queue_type)
- error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_type_rw);
- else
- error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_type);
- if (error)
- return error;
-
error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL, NULL);
if (error)
@@ -1071,6 +1091,13 @@ void __scsi_remove_device(struct scsi_device *sdev)
sdev->host->hostt->slave_destroy(sdev);
transport_destroy_device(dev);
+ /*
+ * Paired with the kref_get() in scsi_sysfs_initialize(). We have
+ * remoed sysfs visibility from the device, so make the target
+ * invisible if this was the last device underneath it.
+ */
+ scsi_target_reap(scsi_target(sdev));
+
put_device(dev);
}
@@ -1133,7 +1160,7 @@ void scsi_remove_target(struct device *dev)
continue;
if (starget->dev.parent == dev || &starget->dev == dev) {
/* assuming new targets arrive at the end */
- starget->reap_ref++;
+ kref_get(&starget->reap_ref);
spin_unlock_irqrestore(shost->host_lock, flags);
if (last)
scsi_target_reap(last);
@@ -1217,6 +1244,12 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev)
list_add_tail(&sdev->same_target_siblings, &starget->devices);
list_add_tail(&sdev->siblings, &shost->__devices);
spin_unlock_irqrestore(shost->host_lock, flags);
+ /*
+ * device can now only be removed via __scsi_remove_device() so hold
+ * the target. Target will be held in CREATED state until something
+ * beneath it becomes visible (in which case it moves to RUNNING)
+ */
+ kref_get(&starget->reap_ref);
}
int scsi_is_sdev_device(const struct device *dev)
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 84a1fdf67864..e51add05fb8d 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -155,7 +155,8 @@ void scsi_host_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
__blk_put_request(q, rq);
spin_unlock_irqrestore(q->queue_lock, flags);
- __scsi_put_command(shost, cmd, &shost->shost_gendev);
+ __scsi_put_command(shost, cmd);
+ put_device(&shost->shost_gendev);
}
EXPORT_SYMBOL_GPL(scsi_host_put_command);
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 4628fd5e0688..f80908f74ca9 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -261,6 +261,7 @@ static const struct {
{ FC_PORTSPEED_10GBIT, "10 Gbit" },
{ FC_PORTSPEED_8GBIT, "8 Gbit" },
{ FC_PORTSPEED_16GBIT, "16 Gbit" },
+ { FC_PORTSPEED_32GBIT, "32 Gbit" },
{ FC_PORTSPEED_NOT_NEGOTIATED, "Not Negotiated" },
};
fc_bitfield_name_search(port_speed, fc_port_speed_names)
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index fd8ffe6bcfdd..0102a2d70dd8 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -1225,7 +1225,7 @@ struct bus_type iscsi_flashnode_bus = {
* Adds a sysfs entry for the flashnode session attributes
*
* Returns:
- * pointer to allocated flashnode sess on sucess
+ * pointer to allocated flashnode sess on success
* %NULL on failure
*/
struct iscsi_bus_flash_session *
@@ -1423,7 +1423,7 @@ static int iscsi_iter_destroy_flashnode_conn_fn(struct device *dev, void *data)
}
/**
- * iscsi_destroy_flashnode_sess - destory flashnode session entry
+ * iscsi_destroy_flashnode_sess - destroy flashnode session entry
* @fnode_sess: pointer to flashnode session entry to be destroyed
*
* Deletes the flashnode session entry and all children flashnode connection
@@ -1453,7 +1453,7 @@ static int iscsi_iter_destroy_flashnode_fn(struct device *dev, void *data)
}
/**
- * iscsi_destroy_all_flashnode - destory all flashnode session entries
+ * iscsi_destroy_all_flashnode - destroy all flashnode session entries
* @shost: pointer to host data
*
* Destroys all the flashnode session entries and all corresponding children
diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c
index d47ffc8d3e43..13e898332e45 100644
--- a/drivers/scsi/scsi_transport_srp.c
+++ b/drivers/scsi/scsi_transport_srp.c
@@ -810,6 +810,7 @@ EXPORT_SYMBOL_GPL(srp_remove_host);
/**
* srp_stop_rport_timers - stop the transport layer recovery timers
+ * @rport: SRP remote port for which to stop the timers.
*
* Must be called after srp_remove_host() and scsi_remove_host(). The caller
* must hold a reference on the rport (rport->dev) and on the SCSI host
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 470954aba728..89e6c04ac595 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1463,8 +1463,8 @@ static int sd_sync_cache(struct scsi_disk *sdkp)
sd_print_sense_hdr(sdkp, &sshdr);
/* we need to evaluate the error return */
if (scsi_sense_valid(&sshdr) &&
- /* 0x3a is medium not present */
- sshdr.asc == 0x3a)
+ (sshdr.asc == 0x3a || /* medium not present */
+ sshdr.asc == 0x20)) /* invalid command */
/* this is no error here */
return 0;
@@ -2281,7 +2281,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)
set_disk_ro(sdkp->disk, 0);
if (sdp->skip_ms_page_3f) {
- sd_printk(KERN_NOTICE, sdkp, "Assuming Write Enabled\n");
+ sd_first_printk(KERN_NOTICE, sdkp, "Assuming Write Enabled\n");
return;
}
@@ -2313,7 +2313,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)
}
if (!scsi_status_is_good(res)) {
- sd_printk(KERN_WARNING, sdkp,
+ sd_first_printk(KERN_WARNING, sdkp,
"Test WP failed, assume Write Enabled\n");
} else {
sdkp->write_prot = ((data.device_specific & 0x80) != 0);
@@ -2381,7 +2381,8 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
if (!data.header_length) {
modepage = 6;
first_len = 0;
- sd_printk(KERN_ERR, sdkp, "Missing header in MODE_SENSE response\n");
+ sd_first_printk(KERN_ERR, sdkp,
+ "Missing header in MODE_SENSE response\n");
}
/* that went OK, now ask for the proper length */
@@ -2394,7 +2395,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
if (len < 3)
goto bad_sense;
else if (len > SD_BUF_SIZE) {
- sd_printk(KERN_NOTICE, sdkp, "Truncating mode parameter "
+ sd_first_printk(KERN_NOTICE, sdkp, "Truncating mode parameter "
"data from %d to %d bytes\n", len, SD_BUF_SIZE);
len = SD_BUF_SIZE;
}
@@ -2417,8 +2418,9 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
/* We're interested only in the first 3 bytes.
*/
if (len - offset <= 2) {
- sd_printk(KERN_ERR, sdkp, "Incomplete "
- "mode parameter data\n");
+ sd_first_printk(KERN_ERR, sdkp,
+ "Incomplete mode parameter "
+ "data\n");
goto defaults;
} else {
modepage = page_code;
@@ -2432,14 +2434,15 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
else if (!spf && len - offset > 1)
offset += 2 + buffer[offset+1];
else {
- sd_printk(KERN_ERR, sdkp, "Incomplete "
- "mode parameter data\n");
+ sd_first_printk(KERN_ERR, sdkp,
+ "Incomplete mode "
+ "parameter data\n");
goto defaults;
}
}
}
- sd_printk(KERN_ERR, sdkp, "No Caching mode page found\n");
+ sd_first_printk(KERN_ERR, sdkp, "No Caching mode page found\n");
goto defaults;
Page_found:
@@ -2453,7 +2456,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
sdkp->DPOFUA = (data.device_specific & 0x10) != 0;
if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw) {
- sd_printk(KERN_NOTICE, sdkp,
+ sd_first_printk(KERN_NOTICE, sdkp,
"Uses READ/WRITE(6), disabling FUA\n");
sdkp->DPOFUA = 0;
}
@@ -2475,16 +2478,19 @@ bad_sense:
sshdr.sense_key == ILLEGAL_REQUEST &&
sshdr.asc == 0x24 && sshdr.ascq == 0x0)
/* Invalid field in CDB */
- sd_printk(KERN_NOTICE, sdkp, "Cache data unavailable\n");
+ sd_first_printk(KERN_NOTICE, sdkp, "Cache data unavailable\n");
else
- sd_printk(KERN_ERR, sdkp, "Asking for cache data failed\n");
+ sd_first_printk(KERN_ERR, sdkp,
+ "Asking for cache data failed\n");
defaults:
if (sdp->wce_default_on) {
- sd_printk(KERN_NOTICE, sdkp, "Assuming drive cache: write back\n");
+ sd_first_printk(KERN_NOTICE, sdkp,
+ "Assuming drive cache: write back\n");
sdkp->WCE = 1;
} else {
- sd_printk(KERN_ERR, sdkp, "Assuming drive cache: write through\n");
+ sd_first_printk(KERN_ERR, sdkp,
+ "Assuming drive cache: write through\n");
sdkp->WCE = 0;
}
sdkp->RCD = 0;
@@ -2513,7 +2519,7 @@ static void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer)
if (!scsi_status_is_good(res) || !data.header_length ||
data.length < 6) {
- sd_printk(KERN_WARNING, sdkp,
+ sd_first_printk(KERN_WARNING, sdkp,
"getting Control mode page failed, assume no ATO\n");
if (scsi_sense_valid(&sshdr))
@@ -2525,7 +2531,7 @@ static void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer)
offset = data.header_length + data.block_descriptor_length;
if ((buffer[offset] & 0x3f) != 0x0a) {
- sd_printk(KERN_ERR, sdkp, "ATO Got wrong page\n");
+ sd_first_printk(KERN_ERR, sdkp, "ATO Got wrong page\n");
return;
}
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 26895ff247c5..620871efbf0a 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -104,6 +104,12 @@ static inline struct scsi_disk *scsi_disk(struct gendisk *disk)
(sdsk)->disk->disk_name, ##a) : \
sdev_printk(prefix, (sdsk)->device, fmt, ##a)
+#define sd_first_printk(prefix, sdsk, fmt, a...) \
+ do { \
+ if ((sdkp)->first_scan) \
+ sd_printk(prefix, sdsk, fmt, ##a); \
+ } while (0)
+
static inline int scsi_medium_access_command(struct scsi_cmnd *scmd)
{
switch (scmd->cmnd[0]) {
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index eba183c428cf..80bfece1a2de 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/enclosure.h>
+#include <asm/unaligned.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -448,27 +449,18 @@ static void ses_enclosure_data_process(struct enclosure_device *edev,
static void ses_match_to_enclosure(struct enclosure_device *edev,
struct scsi_device *sdev)
{
- unsigned char *buf;
unsigned char *desc;
- unsigned int vpd_len;
struct efd efd = {
.addr = 0,
};
- buf = kmalloc(INIT_ALLOC_SIZE, GFP_KERNEL);
- if (!buf || scsi_get_vpd_page(sdev, 0x83, buf, INIT_ALLOC_SIZE))
- goto free;
-
ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0);
- vpd_len = ((buf[2] << 8) | buf[3]) + 4;
- kfree(buf);
- buf = kmalloc(vpd_len, GFP_KERNEL);
- if (!buf ||scsi_get_vpd_page(sdev, 0x83, buf, vpd_len))
- goto free;
+ if (!sdev->vpd_pg83_len)
+ return;
- desc = buf + 4;
- while (desc < buf + vpd_len) {
+ desc = sdev->vpd_pg83 + 4;
+ while (desc < sdev->vpd_pg83 + sdev->vpd_pg83_len) {
enum scsi_protocol proto = desc[0] >> 4;
u8 code_set = desc[0] & 0x0f;
u8 piv = desc[1] & 0x80;
@@ -478,25 +470,15 @@ static void ses_match_to_enclosure(struct enclosure_device *edev,
if (piv && code_set == 1 && assoc == 1
&& proto == SCSI_PROTOCOL_SAS && type == 3 && len == 8)
- efd.addr = (u64)desc[4] << 56 |
- (u64)desc[5] << 48 |
- (u64)desc[6] << 40 |
- (u64)desc[7] << 32 |
- (u64)desc[8] << 24 |
- (u64)desc[9] << 16 |
- (u64)desc[10] << 8 |
- (u64)desc[11];
+ efd.addr = get_unaligned_be64(&desc[4]);
desc += len + 4;
}
- if (!efd.addr)
- goto free;
+ if (efd.addr) {
+ efd.dev = &sdev->sdev_gendev;
- efd.dev = &sdev->sdev_gendev;
-
- enclosure_for_each_device(ses_enclosure_find_by_addr, &efd);
- free:
- kfree(buf);
+ enclosure_for_each_device(ses_enclosure_find_by_addr, &efd);
+ }
}
static int ses_intf_add(struct device *cdev,
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index a1d6986261a3..afc834e172c6 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -2198,12 +2198,19 @@ static int st_set_options(struct scsi_tape *STp, long options)
struct st_modedef *STm;
char *name = tape_name(STp);
struct cdev *cd0, *cd1;
+ struct device *d0, *d1;
STm = &(STp->modes[STp->current_mode]);
if (!STm->defined) {
- cd0 = STm->cdevs[0]; cd1 = STm->cdevs[1];
+ cd0 = STm->cdevs[0];
+ cd1 = STm->cdevs[1];
+ d0 = STm->devs[0];
+ d1 = STm->devs[1];
memcpy(STm, &(STp->modes[0]), sizeof(struct st_modedef));
- STm->cdevs[0] = cd0; STm->cdevs[1] = cd1;
+ STm->cdevs[0] = cd0;
+ STm->cdevs[1] = cd1;
+ STm->devs[0] = d0;
+ STm->devs[1] = d1;
modes_defined = 1;
DEBC(printk(ST_DEB_MSG
"%s: Initialized mode %d definition from mode 0\n",
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 17d740427240..9969fa1ef7c4 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -1419,6 +1419,9 @@ static void storvsc_device_destroy(struct scsi_device *sdevice)
{
struct stor_mem_pools *memp = sdevice->hostdata;
+ if (!memp)
+ return;
+
mempool_destroy(memp->request_mempool);
kmem_cache_destroy(memp->request_pool);
kfree(memp);
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
index f1e4b4148c75..a4abce9d526e 100644
--- a/drivers/scsi/t128.c
+++ b/drivers/scsi/t128.c
@@ -259,7 +259,7 @@ found:
instance->irq = NCR5380_probe_irq(instance, T128_IRQS);
if (instance->irq != SCSI_IRQ_NONE)
- if (request_irq(instance->irq, t128_intr, IRQF_DISABLED, "t128",
+ if (request_irq(instance->irq, t128_intr, 0, "t128",
instance)) {
printk("scsi%d : IRQ%d not free, interrupts disabled\n",
instance->host_no, instance->irq);
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 9c216e563568..5a03bb3bcfef 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -873,7 +873,7 @@ static int port_detect \
/* Board detected, allocate its IRQ */
if (request_irq(irq, do_interrupt_handler,
- IRQF_DISABLED | ((subversion == ESA) ? IRQF_SHARED : 0),
+ (subversion == ESA) ? IRQF_SHARED : 0,
driver_name, (void *) &sha[j])) {
printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
goto freelock;
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
index b9755ec0e812..c88e1468aad7 100644
--- a/drivers/scsi/vmw_pvscsi.c
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -1,7 +1,7 @@
/*
* Linux driver for VMware's para-virtualized SCSI HBA.
*
- * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved.
+ * Copyright (C) 2008-2014, VMware, 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
@@ -32,6 +32,7 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
+#include <scsi/scsi_tcq.h>
#include "vmw_pvscsi.h"
@@ -44,7 +45,7 @@ MODULE_VERSION(PVSCSI_DRIVER_VERSION_STRING);
#define PVSCSI_DEFAULT_NUM_PAGES_PER_RING 8
#define PVSCSI_DEFAULT_NUM_PAGES_MSG_RING 1
-#define PVSCSI_DEFAULT_QUEUE_DEPTH 64
+#define PVSCSI_DEFAULT_QUEUE_DEPTH 254
#define SGL_SIZE PAGE_SIZE
struct pvscsi_sg_list {
@@ -62,6 +63,7 @@ struct pvscsi_ctx {
dma_addr_t dataPA;
dma_addr_t sensePA;
dma_addr_t sglPA;
+ struct completion *abort_cmp;
};
struct pvscsi_adapter {
@@ -71,6 +73,7 @@ struct pvscsi_adapter {
bool use_msi;
bool use_msix;
bool use_msg;
+ bool use_req_threshold;
spinlock_t hw_lock;
@@ -102,18 +105,22 @@ struct pvscsi_adapter {
/* Command line parameters */
-static int pvscsi_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_PER_RING;
+static int pvscsi_ring_pages;
static int pvscsi_msg_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_MSG_RING;
static int pvscsi_cmd_per_lun = PVSCSI_DEFAULT_QUEUE_DEPTH;
static bool pvscsi_disable_msi;
static bool pvscsi_disable_msix;
static bool pvscsi_use_msg = true;
+static bool pvscsi_use_req_threshold = true;
#define PVSCSI_RW (S_IRUSR | S_IWUSR)
module_param_named(ring_pages, pvscsi_ring_pages, int, PVSCSI_RW);
MODULE_PARM_DESC(ring_pages, "Number of pages per req/cmp ring - (default="
- __stringify(PVSCSI_DEFAULT_NUM_PAGES_PER_RING) ")");
+ __stringify(PVSCSI_DEFAULT_NUM_PAGES_PER_RING)
+ "[up to 16 targets],"
+ __stringify(PVSCSI_SETUP_RINGS_MAX_NUM_PAGES)
+ "[for 16+ targets])");
module_param_named(msg_ring_pages, pvscsi_msg_ring_pages, int, PVSCSI_RW);
MODULE_PARM_DESC(msg_ring_pages, "Number of pages for the msg ring - (default="
@@ -121,7 +128,7 @@ MODULE_PARM_DESC(msg_ring_pages, "Number of pages for the msg ring - (default="
module_param_named(cmd_per_lun, pvscsi_cmd_per_lun, int, PVSCSI_RW);
MODULE_PARM_DESC(cmd_per_lun, "Maximum commands per lun - (default="
- __stringify(PVSCSI_MAX_REQ_QUEUE_DEPTH) ")");
+ __stringify(PVSCSI_DEFAULT_QUEUE_DEPTH) ")");
module_param_named(disable_msi, pvscsi_disable_msi, bool, PVSCSI_RW);
MODULE_PARM_DESC(disable_msi, "Disable MSI use in driver - (default=0)");
@@ -132,6 +139,10 @@ MODULE_PARM_DESC(disable_msix, "Disable MSI-X use in driver - (default=0)");
module_param_named(use_msg, pvscsi_use_msg, bool, PVSCSI_RW);
MODULE_PARM_DESC(use_msg, "Use msg ring when available - (default=1)");
+module_param_named(use_req_threshold, pvscsi_use_req_threshold,
+ bool, PVSCSI_RW);
+MODULE_PARM_DESC(use_req_threshold, "Use driver-based request coalescing if configured - (default=1)");
+
static const struct pci_device_id pvscsi_pci_tbl[] = {
{ PCI_VDEVICE(VMWARE, PCI_DEVICE_ID_VMWARE_PVSCSI) },
{ 0 }
@@ -177,6 +188,7 @@ static void pvscsi_release_context(struct pvscsi_adapter *adapter,
struct pvscsi_ctx *ctx)
{
ctx->cmd = NULL;
+ ctx->abort_cmp = NULL;
list_add(&ctx->list, &adapter->cmd_pool);
}
@@ -280,10 +292,15 @@ static int scsi_is_rw(unsigned char op)
static void pvscsi_kick_io(const struct pvscsi_adapter *adapter,
unsigned char op)
{
- if (scsi_is_rw(op))
- pvscsi_kick_rw_io(adapter);
- else
+ if (scsi_is_rw(op)) {
+ struct PVSCSIRingsState *s = adapter->rings_state;
+
+ if (!adapter->use_req_threshold ||
+ s->reqProdIdx - s->reqConsIdx >= s->reqCallThreshold)
+ pvscsi_kick_rw_io(adapter);
+ } else {
pvscsi_process_request_ring(adapter);
+ }
}
static void ll_adapter_reset(const struct pvscsi_adapter *adapter)
@@ -487,6 +504,35 @@ static void pvscsi_setup_all_rings(const struct pvscsi_adapter *adapter)
}
}
+static int pvscsi_change_queue_depth(struct scsi_device *sdev,
+ int qdepth,
+ int reason)
+{
+ int max_depth;
+ struct Scsi_Host *shost = sdev->host;
+
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ /*
+ * We support only changing default.
+ */
+ return -EOPNOTSUPP;
+
+ max_depth = shost->can_queue;
+ if (!sdev->tagged_supported)
+ max_depth = 1;
+ if (qdepth > max_depth)
+ qdepth = max_depth;
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+
+ if (sdev->inquiry_len > 7)
+ sdev_printk(KERN_INFO, sdev,
+ "qdepth(%d), tagged(%d), simple(%d), ordered(%d), scsi_level(%d), cmd_que(%d)\n",
+ sdev->queue_depth, sdev->tagged_supported,
+ sdev->simple_tags, sdev->ordered_tags,
+ sdev->scsi_level, (sdev->inquiry[7] & 2) >> 1);
+ return sdev->queue_depth;
+}
+
/*
* Pull a completion descriptor off and pass the completion back
* to the SCSI mid layer.
@@ -496,15 +542,27 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter,
{
struct pvscsi_ctx *ctx;
struct scsi_cmnd *cmd;
+ struct completion *abort_cmp;
u32 btstat = e->hostStatus;
u32 sdstat = e->scsiStatus;
ctx = pvscsi_get_context(adapter, e->context);
cmd = ctx->cmd;
+ abort_cmp = ctx->abort_cmp;
pvscsi_unmap_buffers(adapter, ctx);
pvscsi_release_context(adapter, ctx);
- cmd->result = 0;
+ if (abort_cmp) {
+ /*
+ * The command was requested to be aborted. Just signal that
+ * the request completed and swallow the actual cmd completion
+ * here. The abort handler will post a completion for this
+ * command indicating that it got successfully aborted.
+ */
+ complete(abort_cmp);
+ return;
+ }
+ cmd->result = 0;
if (sdstat != SAM_STAT_GOOD &&
(btstat == BTSTAT_SUCCESS ||
btstat == BTSTAT_LINKED_COMMAND_COMPLETED ||
@@ -726,6 +784,8 @@ static int pvscsi_abort(struct scsi_cmnd *cmd)
struct pvscsi_adapter *adapter = shost_priv(cmd->device->host);
struct pvscsi_ctx *ctx;
unsigned long flags;
+ int result = SUCCESS;
+ DECLARE_COMPLETION_ONSTACK(abort_cmp);
scmd_printk(KERN_DEBUG, cmd, "task abort on host %u, %p\n",
adapter->host->host_no, cmd);
@@ -748,13 +808,40 @@ static int pvscsi_abort(struct scsi_cmnd *cmd)
goto out;
}
+ /*
+ * Mark that the command has been requested to be aborted and issue
+ * the abort.
+ */
+ ctx->abort_cmp = &abort_cmp;
+
pvscsi_abort_cmd(adapter, ctx);
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+ /* Wait for 2 secs for the completion. */
+ wait_for_completion_timeout(&abort_cmp, msecs_to_jiffies(2000));
+ spin_lock_irqsave(&adapter->hw_lock, flags);
- pvscsi_process_completion_ring(adapter);
+ if (!completion_done(&abort_cmp)) {
+ /*
+ * Failed to abort the command, unmark the fact that it
+ * was requested to be aborted.
+ */
+ ctx->abort_cmp = NULL;
+ result = FAILED;
+ scmd_printk(KERN_DEBUG, cmd,
+ "Failed to get completion for aborted cmd %p\n",
+ cmd);
+ goto out;
+ }
+
+ /*
+ * Successfully aborted the command.
+ */
+ cmd->result = (DID_ABORT << 16);
+ cmd->scsi_done(cmd);
out:
spin_unlock_irqrestore(&adapter->hw_lock, flags);
- return SUCCESS;
+ return result;
}
/*
@@ -911,6 +998,7 @@ static struct scsi_host_template pvscsi_template = {
.dma_boundary = UINT_MAX,
.max_sectors = 0xffff,
.use_clustering = ENABLE_CLUSTERING,
+ .change_queue_depth = pvscsi_change_queue_depth,
.eh_abort_handler = pvscsi_abort,
.eh_device_reset_handler = pvscsi_device_reset,
.eh_bus_reset_handler = pvscsi_bus_reset,
@@ -1034,6 +1122,34 @@ static int pvscsi_setup_msg_workqueue(struct pvscsi_adapter *adapter)
return 1;
}
+static bool pvscsi_setup_req_threshold(struct pvscsi_adapter *adapter,
+ bool enable)
+{
+ u32 val;
+
+ if (!pvscsi_use_req_threshold)
+ return false;
+
+ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_COMMAND,
+ PVSCSI_CMD_SETUP_REQCALLTHRESHOLD);
+ val = pvscsi_reg_read(adapter, PVSCSI_REG_OFFSET_COMMAND_STATUS);
+ if (val == -1) {
+ printk(KERN_INFO "vmw_pvscsi: device does not support req_threshold\n");
+ return false;
+ } else {
+ struct PVSCSICmdDescSetupReqCall cmd_msg = { 0 };
+ cmd_msg.enable = enable;
+ printk(KERN_INFO
+ "vmw_pvscsi: %sabling reqCallThreshold\n",
+ enable ? "en" : "dis");
+ pvscsi_write_cmd_desc(adapter,
+ PVSCSI_CMD_SETUP_REQCALLTHRESHOLD,
+ &cmd_msg, sizeof(cmd_msg));
+ return pvscsi_reg_read(adapter,
+ PVSCSI_REG_OFFSET_COMMAND_STATUS) != 0;
+ }
+}
+
static irqreturn_t pvscsi_isr(int irq, void *devp)
{
struct pvscsi_adapter *adapter = devp;
@@ -1236,11 +1352,12 @@ exit:
static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct pvscsi_adapter *adapter;
- struct Scsi_Host *host;
- struct device *dev;
+ struct pvscsi_adapter adapter_temp;
+ struct Scsi_Host *host = NULL;
unsigned int i;
unsigned long flags = 0;
int error;
+ u32 max_id;
error = -ENODEV;
@@ -1258,34 +1375,19 @@ static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_disable_device;
}
- pvscsi_template.can_queue =
- min(PVSCSI_MAX_NUM_PAGES_REQ_RING, pvscsi_ring_pages) *
- PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
- pvscsi_template.cmd_per_lun =
- min(pvscsi_template.can_queue, pvscsi_cmd_per_lun);
- host = scsi_host_alloc(&pvscsi_template, sizeof(struct pvscsi_adapter));
- if (!host) {
- printk(KERN_ERR "vmw_pvscsi: failed to allocate host\n");
- goto out_disable_device;
- }
-
- adapter = shost_priv(host);
+ /*
+ * Let's use a temp pvscsi_adapter struct until we find the number of
+ * targets on the adapter, after that we will switch to the real
+ * allocated struct.
+ */
+ adapter = &adapter_temp;
memset(adapter, 0, sizeof(*adapter));
adapter->dev = pdev;
- adapter->host = host;
-
- spin_lock_init(&adapter->hw_lock);
-
- host->max_channel = 0;
- host->max_id = 16;
- host->max_lun = 1;
- host->max_cmd_len = 16;
-
adapter->rev = pdev->revision;
if (pci_request_regions(pdev, "vmw_pvscsi")) {
printk(KERN_ERR "vmw_pvscsi: pci memory selection failed\n");
- goto out_free_host;
+ goto out_disable_device;
}
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
@@ -1301,7 +1403,7 @@ static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (i == DEVICE_COUNT_RESOURCE) {
printk(KERN_ERR
"vmw_pvscsi: adapter has no suitable MMIO region\n");
- goto out_release_resources;
+ goto out_release_resources_and_disable;
}
adapter->mmioBase = pci_iomap(pdev, i, PVSCSI_MEM_SPACE_SIZE);
@@ -1310,10 +1412,60 @@ static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
printk(KERN_ERR
"vmw_pvscsi: can't iomap for BAR %d memsize %lu\n",
i, PVSCSI_MEM_SPACE_SIZE);
- goto out_release_resources;
+ goto out_release_resources_and_disable;
}
pci_set_master(pdev);
+
+ /*
+ * Ask the device for max number of targets before deciding the
+ * default pvscsi_ring_pages value.
+ */
+ max_id = pvscsi_get_max_targets(adapter);
+ printk(KERN_INFO "vmw_pvscsi: max_id: %u\n", max_id);
+
+ if (pvscsi_ring_pages == 0)
+ /*
+ * Set the right default value. Up to 16 it is 8, above it is
+ * max.
+ */
+ pvscsi_ring_pages = (max_id > 16) ?
+ PVSCSI_SETUP_RINGS_MAX_NUM_PAGES :
+ PVSCSI_DEFAULT_NUM_PAGES_PER_RING;
+ printk(KERN_INFO
+ "vmw_pvscsi: setting ring_pages to %d\n",
+ pvscsi_ring_pages);
+
+ pvscsi_template.can_queue =
+ min(PVSCSI_MAX_NUM_PAGES_REQ_RING, pvscsi_ring_pages) *
+ PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
+ pvscsi_template.cmd_per_lun =
+ min(pvscsi_template.can_queue, pvscsi_cmd_per_lun);
+ host = scsi_host_alloc(&pvscsi_template, sizeof(struct pvscsi_adapter));
+ if (!host) {
+ printk(KERN_ERR "vmw_pvscsi: failed to allocate host\n");
+ goto out_release_resources_and_disable;
+ }
+
+ /*
+ * Let's use the real pvscsi_adapter struct here onwards.
+ */
+ adapter = shost_priv(host);
+ memset(adapter, 0, sizeof(*adapter));
+ adapter->dev = pdev;
+ adapter->host = host;
+ /*
+ * Copy back what we already have to the allocated adapter struct.
+ */
+ adapter->rev = adapter_temp.rev;
+ adapter->mmioBase = adapter_temp.mmioBase;
+
+ spin_lock_init(&adapter->hw_lock);
+ host->max_channel = 0;
+ host->max_lun = 1;
+ host->max_cmd_len = 16;
+ host->max_id = max_id;
+
pci_set_drvdata(pdev, host);
ll_adapter_reset(adapter);
@@ -1327,13 +1479,6 @@ static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
/*
- * Ask the device for max number of targets.
- */
- host->max_id = pvscsi_get_max_targets(adapter);
- dev = pvscsi_dev(adapter);
- dev_info(dev, "vmw_pvscsi: host->max_id: %u\n", host->max_id);
-
- /*
* From this point on we should reset the adapter if anything goes
* wrong.
*/
@@ -1373,6 +1518,10 @@ static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
flags = IRQF_SHARED;
}
+ adapter->use_req_threshold = pvscsi_setup_req_threshold(adapter, true);
+ printk(KERN_DEBUG "vmw_pvscsi: driver-based request coalescing %sabled\n",
+ adapter->use_req_threshold ? "en" : "dis");
+
error = request_irq(adapter->irq, pvscsi_isr, flags,
"vmw_pvscsi", adapter);
if (error) {
@@ -1402,12 +1551,15 @@ out_reset_adapter:
ll_adapter_reset(adapter);
out_release_resources:
pvscsi_release_resources(adapter);
-out_free_host:
scsi_host_put(host);
out_disable_device:
pci_disable_device(pdev);
return error;
+
+out_release_resources_and_disable:
+ pvscsi_release_resources(adapter);
+ goto out_disable_device;
}
static void __pvscsi_shutdown(struct pvscsi_adapter *adapter)
diff --git a/drivers/scsi/vmw_pvscsi.h b/drivers/scsi/vmw_pvscsi.h
index 3546e8662e30..ce4588851274 100644
--- a/drivers/scsi/vmw_pvscsi.h
+++ b/drivers/scsi/vmw_pvscsi.h
@@ -1,7 +1,7 @@
/*
* VMware PVSCSI header file
*
- * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved.
+ * Copyright (C) 2008-2014, VMware, 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
@@ -26,7 +26,7 @@
#include <linux/types.h>
-#define PVSCSI_DRIVER_VERSION_STRING "1.0.2.0-k"
+#define PVSCSI_DRIVER_VERSION_STRING "1.0.5.0-k"
#define PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT 128
@@ -117,8 +117,9 @@ enum PVSCSICommands {
PVSCSI_CMD_CONFIG = 7,
PVSCSI_CMD_SETUP_MSG_RING = 8,
PVSCSI_CMD_DEVICE_UNPLUG = 9,
+ PVSCSI_CMD_SETUP_REQCALLTHRESHOLD = 10,
- PVSCSI_CMD_LAST = 10 /* has to be last */
+ PVSCSI_CMD_LAST = 11 /* has to be last */
};
/*
@@ -141,6 +142,14 @@ struct PVSCSICmdDescConfigCmd {
u32 _pad;
} __packed;
+/*
+ * Command descriptor for PVSCSI_CMD_SETUP_REQCALLTHRESHOLD --
+ */
+
+struct PVSCSICmdDescSetupReqCall {
+ u32 enable;
+} __packed;
+
enum PVSCSIConfigPageType {
PVSCSI_CONFIG_PAGE_CONTROLLER = 0x1958,
PVSCSI_CONFIG_PAGE_PHY = 0x1959,
@@ -261,7 +270,9 @@ struct PVSCSIRingsState {
u32 cmpConsIdx;
u32 cmpNumEntriesLog2;
- u8 _pad[104];
+ u32 reqCallThreshold;
+
+ u8 _pad[100];
u32 msgProdIdx;
u32 msgConsIdx;
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index f9a6e4b0affe..32674236fec7 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -1252,7 +1252,7 @@ static int wd7000_init(Adapter * host)
return 0;
- if (request_irq(host->irq, wd7000_intr, IRQF_DISABLED, "wd7000", host)) {
+ if (request_irq(host->irq, wd7000_intr, 0, "wd7000", host)) {
printk("wd7000_init: can't get IRQ %d.\n", host->irq);
return (0);
}
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index ba9310bc9acb..efe1960af2b3 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -150,7 +150,7 @@ config SPI_BUTTERFLY
config SPI_CLPS711X
tristate "CLPS711X host SPI controller"
- depends on ARCH_CLPS711X
+ depends on ARCH_CLPS711X || COMPILE_TEST
help
This enables dedicated general purpose SPI/Microwire1-compatible
master mode interface (SSI1) for CLPS711X-based CPUs.
@@ -212,7 +212,6 @@ config SPI_IMX
tristate "Freescale i.MX SPI controllers"
depends on ARCH_MXC || COMPILE_TEST
select SPI_BITBANG
- default m if IMX_HAVE_PLATFORM_SPI_IMX
help
This enables using the Freescale i.MX SPI controllers in master
mode.
@@ -270,6 +269,7 @@ config SPI_FSL_SPI
config SPI_FSL_DSPI
tristate "Freescale DSPI controller"
select SPI_BITBANG
+ select REGMAP_MMIO
depends on SOC_VF610 || COMPILE_TEST
help
This enables support for the Freescale DSPI controller in master
@@ -307,7 +307,7 @@ config SPI_OMAP_UWIRE
config SPI_OMAP24XX
tristate "McSPI driver for OMAP"
- depends on ARM || ARM64 || AVR32 || HEXAGON || MIPS || SH
+ depends on ARM || ARM64 || AVR32 || HEXAGON || MIPS || SUPERH
depends on ARCH_OMAP2PLUS || COMPILE_TEST
help
SPI master controller for OMAP24XX and later Multichannel SPI
@@ -376,10 +376,23 @@ config SPI_PXA2XX_PCI
def_tristate SPI_PXA2XX && PCI
config SPI_RSPI
- tristate "Renesas RSPI controller"
+ tristate "Renesas RSPI/QSPI controller"
depends on (SUPERH && SH_DMAE_BASE) || ARCH_SHMOBILE
help
- SPI driver for Renesas RSPI blocks.
+ SPI driver for Renesas RSPI and QSPI blocks.
+
+config SPI_QUP
+ tristate "Qualcomm SPI controller with QUP interface"
+ depends on ARCH_MSM_DT || (ARM && COMPILE_TEST)
+ help
+ Qualcomm Universal Peripheral (QUP) core is an AHB slave that
+ provides a common data path (an output FIFO and an input FIFO)
+ for serial peripheral interface (SPI) mini-core. SPI in master
+ mode supports up to 50MHz, up to four chip selects, programmable
+ data path from 4 bits to 32 bits and numerous protocol variants.
+
+ This driver can also be built as a module. If so, the module
+ will be called spi_qup.
config SPI_S3C24XX
tristate "Samsung S3C24XX series SPI"
@@ -416,7 +429,6 @@ config SPI_SH_MSIOF
tristate "SuperH MSIOF SPI controller"
depends on HAVE_CLK
depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
- select SPI_BITBANG
help
SPI driver for SuperH and SH Mobile MSIOF blocks.
@@ -446,6 +458,19 @@ config SPI_SIRF
help
SPI driver for CSR SiRFprimaII SoCs
+config SPI_SUN4I
+ tristate "Allwinner A10 SoCs SPI controller"
+ depends on ARCH_SUNXI || COMPILE_TEST
+ help
+ SPI driver for Allwinner sun4i, sun5i and sun7i SoCs
+
+config SPI_SUN6I
+ tristate "Allwinner A31 SPI controller"
+ depends on ARCH_SUNXI || COMPILE_TEST
+ depends on RESET_CONTROLLER
+ help
+ This enables using the SPI controller on the Allwinner A31 SoCs.
+
config SPI_MXS
tristate "Freescale MXS SPI controller"
depends on ARCH_MXS
@@ -478,13 +503,6 @@ config SPI_TEGRA20_SLINK
help
SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface.
-config SPI_TI_SSP
- tristate "TI Sequencer Serial Port - SPI Support"
- depends on MFD_TI_SSP
- help
- This selects an SPI master implementation using a TI sequencer
- serial port.
-
config SPI_TOPCLIFF_PCH
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI"
depends on PCI
@@ -520,6 +538,19 @@ config SPI_XILINX
Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
+config SPI_XTENSA_XTFPGA
+ tristate "Xtensa SPI controller for xtfpga"
+ depends on (XTENSA && XTENSA_PLATFORM_XTFPGA) || COMPILE_TEST
+ select SPI_BITBANG
+ help
+ SPI driver for xtfpga SPI master controller.
+
+ This simple SPI master controller is built into xtfpga bitstreams
+ and is used to control daughterboard audio codec. It always transfers
+ 16 bit words in SPI mode 0, automatically asserting CS on transfer
+ start and deasserting on end.
+
+
config SPI_NUC900
tristate "Nuvoton NUC900 series SPI"
depends on ARCH_W90X900
@@ -546,7 +577,7 @@ config SPI_DW_MID_DMA
config SPI_DW_MMIO
tristate "Memory-mapped io interface driver for DW SPI core"
- depends on SPI_DESIGNWARE && HAVE_CLK
+ depends on SPI_DESIGNWARE
#
# There are lots of SPI device types, with sensors and memory
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 95af48d2d360..bd792669e563 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -59,6 +59,7 @@ spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_PXADMA) += spi-pxa2xx-pxadma.o
spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA) += spi-pxa2xx-dma.o
obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o
obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
+obj-$(CONFIG_SPI_QUP) += spi-qup.o
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
spi-s3c24xx-hw-y := spi-s3c24xx.o
@@ -70,12 +71,14 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
obj-$(CONFIG_SPI_SIRF) += spi-sirf.o
+obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o
+obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o
obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o
obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o
obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o
-obj-$(CONFIG_SPI_TI_SSP) += spi-ti-ssp.o
obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o
obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o
obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o
obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
+obj-$(CONFIG_SPI_XTENSA_XTFPGA) += spi-xtensa-xtfpga.o
diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c
index 5d7deaf62867..5b5709a5c957 100644
--- a/drivers/spi/spi-altera.c
+++ b/drivers/spi/spi-altera.c
@@ -13,7 +13,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/module.h>
@@ -200,7 +199,6 @@ 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 = dev_get_platdata(&pdev->dev);
struct altera_spi *hw;
struct spi_master *master;
struct resource *res;
@@ -214,6 +212,8 @@ 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->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
+ master->dev.of_node = pdev->dev.of_node;
hw = spi_master_get_devdata(master);
platform_set_drvdata(pdev, hw);
@@ -245,9 +245,6 @@ static int altera_spi_probe(struct platform_device *pdev)
if (err)
goto exit;
}
- /* find platform data */
- if (!platp)
- hw->bitbang.master->dev.of_node = pdev->dev.of_node;
/* register our spi controller */
err = spi_bitbang_start(&hw->bitbang);
diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c
index 31534b51715a..3898b0b9ee77 100644
--- a/drivers/spi/spi-ath79.c
+++ b/drivers/spi/spi-ath79.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
@@ -132,9 +131,9 @@ static int ath79_spi_setup_cs(struct spi_device *spi)
flags = GPIOF_DIR_OUT;
if (spi->mode & SPI_CS_HIGH)
- flags |= GPIOF_INIT_HIGH;
- else
flags |= GPIOF_INIT_LOW;
+ else
+ flags |= GPIOF_INIT_HIGH;
status = gpio_request_one(cdata->gpio, flags,
dev_name(&spi->dev));
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index b0842f751016..8005f9869481 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -9,7 +9,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -26,6 +25,7 @@
#include <linux/io.h>
#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
/* SPI register offsets */
#define SPI_CR 0x0000
@@ -993,13 +993,6 @@ static int atmel_spi_setup(struct spi_device *spi)
as = spi_master_get_devdata(spi->master);
- if (spi->chip_select > spi->master->num_chipselect) {
- dev_dbg(&spi->dev,
- "setup: invalid chipselect %u (%u defined)\n",
- spi->chip_select, spi->master->num_chipselect);
- return -EINVAL;
- }
-
/* see notes above re chipselect */
if (!atmel_spi_is_v2(as)
&& spi->chip_select == 0
@@ -1087,14 +1080,6 @@ static int atmel_spi_one_transfer(struct spi_master *master,
}
}
- if (xfer->bits_per_word > 8) {
- if (xfer->len % 2) {
- dev_dbg(&spi->dev,
- "buffer len should be 16 bits aligned\n");
- return -EINVAL;
- }
- }
-
/*
* DMA map early, for performance (empties dcache ASAP) and
* better fault reporting.
@@ -1221,9 +1206,6 @@ static int atmel_spi_transfer_one_message(struct spi_master *master,
dev_dbg(&spi->dev, "new message %p submitted for %s\n",
msg, dev_name(&spi->dev));
- if (unlikely(list_empty(&msg->transfers)))
- return -EINVAL;
-
atmel_spi_lock(as);
cs_activate(as, spi);
@@ -1244,10 +1226,10 @@ static int atmel_spi_transfer_one_message(struct spi_master *master,
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
dev_dbg(&spi->dev,
- " xfer %p: len %u tx %p/%08x rx %p/%08x\n",
+ " xfer %p: len %u tx %p/%pad rx %p/%pad\n",
xfer, xfer->len,
- xfer->tx_buf, xfer->tx_dma,
- xfer->rx_buf, xfer->rx_dma);
+ xfer->tx_buf, &xfer->tx_dma,
+ xfer->rx_buf, &xfer->rx_dma);
}
msg_done:
@@ -1303,6 +1285,9 @@ static int atmel_spi_probe(struct platform_device *pdev)
struct spi_master *master;
struct atmel_spi *as;
+ /* Select default pin state */
+ pinctrl_pm_select_default_state(&pdev->dev);
+
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs)
return -ENXIO;
@@ -1455,8 +1440,19 @@ static int atmel_spi_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct atmel_spi *as = spi_master_get_devdata(master);
+ int ret;
+
+ /* Stop the queue running */
+ ret = spi_master_suspend(master);
+ if (ret) {
+ dev_warn(dev, "cannot suspend master\n");
+ return ret;
+ }
clk_disable_unprepare(as->clk);
+
+ pinctrl_pm_select_sleep_state(dev);
+
return 0;
}
@@ -1464,9 +1460,18 @@ static int atmel_spi_resume(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct atmel_spi *as = spi_master_get_devdata(master);
+ int ret;
+
+ pinctrl_pm_select_default_state(dev);
clk_prepare_enable(as->clk);
- return 0;
+
+ /* Start the queue running */
+ ret = spi_master_resume(master);
+ if (ret)
+ dev_err(dev, "problem starting queue (%d)\n", ret);
+
+ return ret;
}
static SIMPLE_DEV_PM_OPS(atmel_spi_pm_ops, atmel_spi_suspend, atmel_spi_resume);
diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c
index c4141c92bcff..67375a11d4bd 100644
--- a/drivers/spi/spi-au1550.c
+++ b/drivers/spi/spi-au1550.c
@@ -55,8 +55,6 @@ struct au1550_spi {
volatile psc_spi_t __iomem *regs;
int irq;
- unsigned freq_max;
- unsigned freq_min;
unsigned len;
unsigned tx_count;
@@ -248,11 +246,8 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
hz = t->speed_hz;
}
- if (hz > spi->max_speed_hz || hz > hw->freq_max || hz < hw->freq_min) {
- dev_err(&spi->dev, "setupxfer: clock rate=%d out of range\n",
- hz);
+ if (!hz)
return -EINVAL;
- }
au1550_spi_bits_handlers_set(hw, spi->bits_per_word);
@@ -287,23 +282,6 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
return 0;
}
-static int au1550_spi_setup(struct spi_device *spi)
-{
- struct au1550_spi *hw = spi_master_get_devdata(spi->master);
-
- if (spi->max_speed_hz == 0)
- spi->max_speed_hz = hw->freq_max;
- if (spi->max_speed_hz > hw->freq_max
- || spi->max_speed_hz < hw->freq_min)
- return -EINVAL;
- /*
- * NOTE: cannot change speed and other hw settings immediately,
- * otherwise sharing of spi bus is not possible,
- * so do not call setupxfer(spi, NULL) here
- */
- return 0;
-}
-
/*
* for dma spi transfers, we have to setup rx channel, otherwise there is
* no reliable way how to recognize that spi transfer is done
@@ -838,7 +816,6 @@ static int au1550_spi_probe(struct platform_device *pdev)
hw->bitbang.master = hw->master;
hw->bitbang.setup_transfer = au1550_spi_setupxfer;
hw->bitbang.chipselect = au1550_spi_chipsel;
- hw->bitbang.master->setup = au1550_spi_setup;
hw->bitbang.txrx_bufs = au1550_spi_txrx_bufs;
if (hw->usedma) {
@@ -909,8 +886,9 @@ static int au1550_spi_probe(struct platform_device *pdev)
{
int min_div = (2 << 0) * (2 * (4 + 1));
int max_div = (2 << 3) * (2 * (63 + 1));
- hw->freq_max = hw->pdata->mainclk_hz / min_div;
- hw->freq_min = hw->pdata->mainclk_hz / (max_div + 1) + 1;
+ master->max_speed_hz = hw->pdata->mainclk_hz / min_div;
+ master->min_speed_hz =
+ hw->pdata->mainclk_hz / (max_div + 1) + 1;
}
au1550_spi_setup_psc_as_spi(hw);
@@ -999,6 +977,15 @@ static int __init au1550_spi_init(void)
* create memory device with 8 bits dev_devwidth
* needed for proper byte ordering to spi fifo
*/
+ switch (alchemy_get_cputype()) {
+ case ALCHEMY_CPU_AU1550:
+ case ALCHEMY_CPU_AU1200:
+ case ALCHEMY_CPU_AU1300:
+ break;
+ default:
+ return -ENODEV;
+ }
+
if (usedma) {
ddma_memid = au1xxx_ddma_add_device(&au1550_spi_mem_dbdev);
if (!ddma_memid)
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index 8a89dd1f2654..69167456ec1e 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -315,7 +315,6 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
master->mode_bits = BCM2835_SPI_MODE_BITS;
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;
master->dev.of_node = pdev->dev.of_node;
diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c
index b528f9fc8bc0..5a211e98383b 100644
--- a/drivers/spi/spi-bcm63xx-hsspi.c
+++ b/drivers/spi/spi-bcm63xx-hsspi.c
@@ -180,7 +180,7 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
while (pending > 0) {
int curr_step = min_t(int, step_size, pending);
- init_completion(&bs->done);
+ reinit_completion(&bs->done);
if (tx) {
memcpy_toio(bs->fifo + HSSPI_OPCODE_LEN, tx, curr_step);
tx += curr_step;
@@ -369,6 +369,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
bs->fifo = (u8 __iomem *)(bs->regs + HSSPI_FIFO_REG(0));
mutex_init(&bs->bus_mutex);
+ init_completion(&bs->done);
master->bus_num = HSSPI_BUS_NUM;
master->num_chipselect = 8;
@@ -453,9 +454,8 @@ static int bcm63xx_hsspi_resume(struct device *dev)
}
#endif
-static const struct dev_pm_ops bcm63xx_hsspi_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(bcm63xx_hsspi_suspend, bcm63xx_hsspi_resume)
-};
+static SIMPLE_DEV_PM_OPS(bcm63xx_hsspi_pm_ops, bcm63xx_hsspi_suspend,
+ bcm63xx_hsspi_resume);
static struct platform_driver bcm63xx_hsspi_driver = {
.driver = {
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index 77286aef2adf..0250fa721cea 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -20,7 +20,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -35,8 +34,6 @@
#include <bcm63xx_dev_spi.h>
-#define PFX KBUILD_MODNAME
-
#define BCM63XX_SPI_MAX_PREPEND 15
struct bcm63xx_spi {
@@ -169,7 +166,7 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
transfer_list);
}
- init_completion(&bs->done);
+ reinit_completion(&bs->done);
/* Fill in the Message control register */
msg_ctl = (len << SPI_BYTE_CNT_SHIFT);
@@ -353,6 +350,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
}
bs = spi_master_get_devdata(master);
+ init_completion(&bs->done);
platform_set_drvdata(pdev, master);
bs->pdev = pdev;
diff --git a/drivers/spi/spi-bfin-sport.c b/drivers/spi/spi-bfin-sport.c
index 38941e5920b5..f515c5e9db57 100644
--- a/drivers/spi/spi-bfin-sport.c
+++ b/drivers/spi/spi-bfin-sport.c
@@ -8,7 +8,6 @@
* Licensed under the GPL-2 or later.
*/
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/spi/spi-bfin-v3.c b/drivers/spi/spi-bfin-v3.c
index 8f8598834b30..4089d0e0d84e 100644
--- a/drivers/spi/spi-bfin-v3.c
+++ b/drivers/spi/spi-bfin-v3.c
@@ -822,7 +822,8 @@ static int bfin_spi_probe(struct platform_device *pdev)
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);
+ master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
+ SPI_BPW_MASK(8);
drv_data = spi_master_get_devdata(master);
drv_data->master = master;
diff --git a/drivers/spi/spi-bfin5xx.c b/drivers/spi/spi-bfin5xx.c
index f0f195af75d4..55e57c3eb9bd 100644
--- a/drivers/spi/spi-bfin5xx.c
+++ b/drivers/spi/spi-bfin5xx.c
@@ -350,7 +350,6 @@ static void *bfin_spi_next_transfer(struct bfin_spi_master_data *drv_data)
static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data)
{
struct bfin_spi_slave_data *chip = drv_data->cur_chip;
- struct spi_transfer *last_transfer;
unsigned long flags;
struct spi_message *msg;
@@ -362,9 +361,6 @@ static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data)
queue_work(drv_data->workqueue, &drv_data->pump_messages);
spin_unlock_irqrestore(&drv_data->lock, flags);
- last_transfer = list_entry(msg->transfers.prev,
- struct spi_transfer, transfer_list);
-
msg->state = NULL;
if (!drv_data->cs_change)
@@ -1030,10 +1026,6 @@ static int bfin_spi_setup(struct spi_device *spi)
}
/* translate common spi framework into our register */
- if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) {
- dev_err(&spi->dev, "unsupported spi modes detected\n");
- goto error;
- }
if (spi->mode & SPI_CPOL)
chip->ctl_reg |= BIT_CTL_CPOL;
if (spi->mode & SPI_CPHA)
diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c
index bd222f6b677d..dc7d2c2d643e 100644
--- a/drivers/spi/spi-bitbang.c
+++ b/drivers/spi/spi-bitbang.c
@@ -16,7 +16,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
@@ -467,11 +466,9 @@ EXPORT_SYMBOL_GPL(spi_bitbang_start);
/**
* spi_bitbang_stop - stops the task providing spi communication
*/
-int spi_bitbang_stop(struct spi_bitbang *bitbang)
+void spi_bitbang_stop(struct spi_bitbang *bitbang)
{
spi_unregister_master(bitbang->master);
-
- return 0;
}
EXPORT_SYMBOL_GPL(spi_bitbang_stop);
diff --git a/drivers/spi/spi-butterfly.c b/drivers/spi/spi-butterfly.c
index 8081f96bd1d5..ee4f91ccd8fd 100644
--- a/drivers/spi/spi-butterfly.c
+++ b/drivers/spi/spi-butterfly.c
@@ -309,7 +309,6 @@ done:
static void butterfly_detach(struct parport *p)
{
struct butterfly *pp;
- int status;
/* FIXME this global is ugly ... but, how to quickly get from
* the parport to the "struct butterfly" associated with it?
@@ -321,7 +320,7 @@ static void butterfly_detach(struct parport *p)
butterfly = NULL;
/* stop() unregisters child devices too */
- status = spi_bitbang_stop(&pp->bitbang);
+ spi_bitbang_stop(&pp->bitbang);
/* turn off VCC */
parport_write_data(pp->port, 0);
diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c
index 374ba4a48a9e..4cd62f636547 100644
--- a/drivers/spi/spi-clps711x.c
+++ b/drivers/spi/spi-clps711x.c
@@ -11,158 +11,125 @@
#include <linux/io.h>
#include <linux/clk.h>
-#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/clps711x.h>
#include <linux/spi/spi.h>
#include <linux/platform_data/spi-clps711x.h>
-#include <mach/hardware.h>
-
#define DRIVER_NAME "spi-clps711x"
-struct spi_clps711x_data {
- struct completion done;
+#define SYNCIO_FRMLEN(x) ((x) << 8)
+#define SYNCIO_TXFRMEN (1 << 14)
+struct spi_clps711x_data {
+ void __iomem *syncio;
+ struct regmap *syscon;
+ struct regmap *syscon1;
struct clk *spi_clk;
- u32 max_speed_hz;
u8 *tx_buf;
u8 *rx_buf;
- int count;
+ unsigned int bpw;
int len;
-
- int chipselect[0];
};
static int spi_clps711x_setup(struct spi_device *spi)
{
- struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
-
/* We are expect that SPI-device is not selected */
- gpio_direction_output(hw->chipselect[spi->chip_select],
- !(spi->mode & SPI_CS_HIGH));
+ gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
return 0;
}
-static void spi_clps711x_setup_mode(struct spi_device *spi)
-{
- /* Setup edge for transfer */
- if (spi->mode & SPI_CPHA)
- clps_writew(clps_readw(SYSCON3) | SYSCON3_ADCCKNSEN, SYSCON3);
- else
- clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCKNSEN, SYSCON3);
-}
-
-static int spi_clps711x_setup_xfer(struct spi_device *spi,
- struct spi_transfer *xfer)
+static void spi_clps711x_setup_xfer(struct spi_device *spi,
+ struct spi_transfer *xfer)
{
- u32 speed = xfer->speed_hz ? : spi->max_speed_hz;
- u8 bpw = xfer->bits_per_word;
- struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
-
- if (bpw != 8) {
- dev_err(&spi->dev, "Unsupported master bus width %i\n", bpw);
- return -EINVAL;
- }
+ struct spi_master *master = spi->master;
+ struct spi_clps711x_data *hw = spi_master_get_devdata(master);
/* Setup SPI frequency divider */
- if (!speed || (speed >= hw->max_speed_hz))
- clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
- SYSCON1_ADCKSEL(3), SYSCON1);
- else if (speed >= (hw->max_speed_hz / 2))
- clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
- SYSCON1_ADCKSEL(2), SYSCON1);
- else if (speed >= (hw->max_speed_hz / 8))
- clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
- SYSCON1_ADCKSEL(1), SYSCON1);
+ if (xfer->speed_hz >= master->max_speed_hz)
+ regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
+ SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(3));
+ else if (xfer->speed_hz >= (master->max_speed_hz / 2))
+ regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
+ SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(2));
+ else if (xfer->speed_hz >= (master->max_speed_hz / 8))
+ regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
+ SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(1));
else
- clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
- SYSCON1_ADCKSEL(0), SYSCON1);
-
- return 0;
+ regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
+ SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(0));
}
-static int spi_clps711x_transfer_one_message(struct spi_master *master,
- struct spi_message *msg)
+static int spi_clps711x_prepare_message(struct spi_master *master,
+ struct spi_message *msg)
{
struct spi_clps711x_data *hw = spi_master_get_devdata(master);
- struct spi_transfer *xfer;
- int status = 0, cs = hw->chipselect[msg->spi->chip_select];
- u32 data;
-
- spi_clps711x_setup_mode(msg->spi);
-
- list_for_each_entry(xfer, &msg->transfers, transfer_list) {
- if (spi_clps711x_setup_xfer(msg->spi, xfer)) {
- status = -EINVAL;
- goto out_xfr;
- }
+ struct spi_device *spi = msg->spi;
- gpio_set_value(cs, !!(msg->spi->mode & SPI_CS_HIGH));
-
- reinit_completion(&hw->done);
-
- hw->count = 0;
- hw->len = xfer->len;
- hw->tx_buf = (u8 *)xfer->tx_buf;
- hw->rx_buf = (u8 *)xfer->rx_buf;
-
- /* Initiate transfer */
- data = hw->tx_buf ? hw->tx_buf[hw->count] : 0;
- clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO);
-
- wait_for_completion(&hw->done);
+ /* Setup mode for transfer */
+ return regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCKNSEN,
+ (spi->mode & SPI_CPHA) ?
+ SYSCON3_ADCCKNSEN : 0);
+}
- if (xfer->delay_usecs)
- udelay(xfer->delay_usecs);
+static int spi_clps711x_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct spi_clps711x_data *hw = spi_master_get_devdata(master);
+ u8 data;
- if (xfer->cs_change ||
- list_is_last(&xfer->transfer_list, &msg->transfers))
- gpio_set_value(cs, !(msg->spi->mode & SPI_CS_HIGH));
+ spi_clps711x_setup_xfer(spi, xfer);
- msg->actual_length += xfer->len;
- }
+ hw->len = xfer->len;
+ hw->bpw = xfer->bits_per_word;
+ hw->tx_buf = (u8 *)xfer->tx_buf;
+ hw->rx_buf = (u8 *)xfer->rx_buf;
-out_xfr:
- msg->status = status;
- spi_finalize_current_message(master);
+ /* Initiate transfer */
+ data = hw->tx_buf ? *hw->tx_buf++ : 0;
+ writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, hw->syncio);
- return 0;
+ return 1;
}
static irqreturn_t spi_clps711x_isr(int irq, void *dev_id)
{
- struct spi_clps711x_data *hw = (struct spi_clps711x_data *)dev_id;
- u32 data;
+ struct spi_master *master = dev_id;
+ struct spi_clps711x_data *hw = spi_master_get_devdata(master);
+ u8 data;
/* Handle RX */
- data = clps_readb(SYNCIO);
+ data = readb(hw->syncio);
if (hw->rx_buf)
- hw->rx_buf[hw->count] = (u8)data;
-
- hw->count++;
+ *hw->rx_buf++ = data;
/* Handle TX */
- if (hw->count < hw->len) {
- data = hw->tx_buf ? hw->tx_buf[hw->count] : 0;
- clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO);
+ if (--hw->len > 0) {
+ data = hw->tx_buf ? *hw->tx_buf++ : 0;
+ writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN,
+ hw->syncio);
} else
- complete(&hw->done);
+ spi_finalize_current_transfer(master);
return IRQ_HANDLED;
}
static int spi_clps711x_probe(struct platform_device *pdev)
{
- int i, ret;
- struct spi_master *master;
struct spi_clps711x_data *hw;
struct spi_clps711x_pdata *pdata = dev_get_platdata(&pdev->dev);
+ struct spi_master *master;
+ struct resource *res;
+ int i, irq, ret;
if (!pdata) {
dev_err(&pdev->dev, "No platform data supplied\n");
@@ -174,33 +141,37 @@ static int spi_clps711x_probe(struct platform_device *pdev)
return -EINVAL;
}
- master = spi_alloc_master(&pdev->dev,
- sizeof(struct spi_clps711x_data) +
- sizeof(int) * pdata->num_chipselect);
- if (!master) {
- dev_err(&pdev->dev, "SPI allocating memory error\n");
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*hw));
+ if (!master)
return -ENOMEM;
+
+ master->cs_gpios = devm_kzalloc(&pdev->dev, sizeof(int) *
+ pdata->num_chipselect, GFP_KERNEL);
+ if (!master->cs_gpios) {
+ ret = -ENOMEM;
+ goto err_out;
}
master->bus_num = pdev->id;
master->mode_bits = SPI_CPHA | SPI_CS_HIGH;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 8);
master->num_chipselect = pdata->num_chipselect;
master->setup = spi_clps711x_setup;
- master->transfer_one_message = spi_clps711x_transfer_one_message;
+ master->prepare_message = spi_clps711x_prepare_message;
+ master->transfer_one = spi_clps711x_transfer_one;
hw = spi_master_get_devdata(master);
for (i = 0; i < master->num_chipselect; i++) {
- hw->chipselect[i] = pdata->chipselect[i];
- if (!gpio_is_valid(hw->chipselect[i])) {
- dev_err(&pdev->dev, "Invalid CS GPIO %i\n", i);
- ret = -EINVAL;
- goto err_out;
- }
- if (devm_gpio_request(&pdev->dev, hw->chipselect[i], NULL)) {
+ master->cs_gpios[i] = pdata->chipselect[i];
+ ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i],
+ DRIVER_NAME);
+ if (ret) {
dev_err(&pdev->dev, "Can't get CS GPIO %i\n", i);
- ret = -EINVAL;
goto err_out;
}
}
@@ -211,29 +182,45 @@ static int spi_clps711x_probe(struct platform_device *pdev)
ret = PTR_ERR(hw->spi_clk);
goto err_out;
}
- hw->max_speed_hz = clk_get_rate(hw->spi_clk);
+ master->max_speed_hz = clk_get_rate(hw->spi_clk);
- init_completion(&hw->done);
platform_set_drvdata(pdev, master);
+ hw->syscon = syscon_regmap_lookup_by_pdevname("syscon.3");
+ if (IS_ERR(hw->syscon)) {
+ ret = PTR_ERR(hw->syscon);
+ goto err_out;
+ }
+
+ hw->syscon1 = syscon_regmap_lookup_by_pdevname("syscon.1");
+ if (IS_ERR(hw->syscon1)) {
+ ret = PTR_ERR(hw->syscon1);
+ goto err_out;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hw->syncio = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(hw->syncio)) {
+ ret = PTR_ERR(hw->syncio);
+ goto err_out;
+ }
+
/* Disable extended mode due hardware problems */
- clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCON, SYSCON3);
+ regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCON, 0);
/* Clear possible pending interrupt */
- clps_readl(SYNCIO);
+ readl(hw->syncio);
- ret = devm_request_irq(&pdev->dev, IRQ_SSEOTI, spi_clps711x_isr, 0,
- dev_name(&pdev->dev), hw);
- if (ret) {
- dev_err(&pdev->dev, "Can't request IRQ\n");
+ ret = devm_request_irq(&pdev->dev, irq, spi_clps711x_isr, 0,
+ dev_name(&pdev->dev), master);
+ if (ret)
goto err_out;
- }
ret = devm_spi_register_master(&pdev->dev, master);
if (!ret) {
dev_info(&pdev->dev,
"SPI bus driver initialized. Master clock %u Hz\n",
- hw->max_speed_hz);
+ master->max_speed_hz);
return 0;
}
diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c
index cabed8f9119e..e2fa628e55e7 100644
--- a/drivers/spi/spi-coldfire-qspi.c
+++ b/drivers/spi/spi-coldfire-qspi.c
@@ -77,8 +77,6 @@ struct mcfqspi {
struct mcfqspi_cs_control *cs_control;
wait_queue_head_t waitq;
-
- struct device *dev;
};
static void mcfqspi_wr_qmr(struct mcfqspi *mcfqspi, u16 val)
@@ -135,13 +133,13 @@ static void mcfqspi_cs_deselect(struct mcfqspi *mcfqspi, u8 chip_select,
static int mcfqspi_cs_setup(struct mcfqspi *mcfqspi)
{
- return (mcfqspi->cs_control && mcfqspi->cs_control->setup) ?
+ return (mcfqspi->cs_control->setup) ?
mcfqspi->cs_control->setup(mcfqspi->cs_control) : 0;
}
static void mcfqspi_cs_teardown(struct mcfqspi *mcfqspi)
{
- if (mcfqspi->cs_control && mcfqspi->cs_control->teardown)
+ if (mcfqspi->cs_control->teardown)
mcfqspi->cs_control->teardown(mcfqspi->cs_control);
}
@@ -300,68 +298,45 @@ static void mcfqspi_transfer_msg16(struct mcfqspi *mcfqspi, unsigned count,
}
}
-static int mcfqspi_transfer_one_message(struct spi_master *master,
- struct spi_message *msg)
+static void mcfqspi_set_cs(struct spi_device *spi, bool enable)
{
- struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
- struct spi_device *spi = msg->spi;
- struct spi_transfer *t;
- int status = 0;
-
- list_for_each_entry(t, &msg->transfers, transfer_list) {
- bool cs_high = spi->mode & SPI_CS_HIGH;
- u16 qmr = MCFQSPI_QMR_MSTR;
-
- qmr |= t->bits_per_word << 10;
- if (spi->mode & SPI_CPHA)
- qmr |= MCFQSPI_QMR_CPHA;
- if (spi->mode & SPI_CPOL)
- qmr |= MCFQSPI_QMR_CPOL;
- if (t->speed_hz)
- qmr |= mcfqspi_qmr_baud(t->speed_hz);
- else
- qmr |= mcfqspi_qmr_baud(spi->max_speed_hz);
- mcfqspi_wr_qmr(mcfqspi, qmr);
+ struct mcfqspi *mcfqspi = spi_master_get_devdata(spi->master);
+ bool cs_high = spi->mode & SPI_CS_HIGH;
+ if (enable)
mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high);
+ else
+ mcfqspi_cs_deselect(mcfqspi, spi->chip_select, cs_high);
+}
- mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
- if (t->bits_per_word == 8)
- mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf,
- t->rx_buf);
- else
- mcfqspi_transfer_msg16(mcfqspi, t->len / 2, t->tx_buf,
- t->rx_buf);
- mcfqspi_wr_qir(mcfqspi, 0);
-
- if (t->delay_usecs)
- udelay(t->delay_usecs);
- if (t->cs_change) {
- if (!list_is_last(&t->transfer_list, &msg->transfers))
- mcfqspi_cs_deselect(mcfqspi, spi->chip_select,
- cs_high);
- } else {
- if (list_is_last(&t->transfer_list, &msg->transfers))
- mcfqspi_cs_deselect(mcfqspi, spi->chip_select,
- cs_high);
- }
- msg->actual_length += t->len;
- }
- msg->status = status;
- spi_finalize_current_message(master);
-
- return status;
+static int mcfqspi_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+ u16 qmr = MCFQSPI_QMR_MSTR;
+
+ qmr |= t->bits_per_word << 10;
+ if (spi->mode & SPI_CPHA)
+ qmr |= MCFQSPI_QMR_CPHA;
+ if (spi->mode & SPI_CPOL)
+ qmr |= MCFQSPI_QMR_CPOL;
+ qmr |= mcfqspi_qmr_baud(t->speed_hz);
+ mcfqspi_wr_qmr(mcfqspi, qmr);
+
+ mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
+ if (t->bits_per_word == 8)
+ mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf, t->rx_buf);
+ else
+ mcfqspi_transfer_msg16(mcfqspi, t->len / 2, t->tx_buf,
+ t->rx_buf);
+ mcfqspi_wr_qir(mcfqspi, 0);
+ return 0;
}
static int mcfqspi_setup(struct spi_device *spi)
{
- if (spi->chip_select >= spi->master->num_chipselect) {
- dev_dbg(&spi->dev, "%d chip select is out of range\n",
- spi->chip_select);
- return -EINVAL;
- }
-
mcfqspi_cs_deselect(spi_master_get_devdata(spi->master),
spi->chip_select, spi->mode & SPI_CS_HIGH);
@@ -388,6 +363,11 @@ static int mcfqspi_probe(struct platform_device *pdev)
return -ENOENT;
}
+ if (!pdata->cs_control) {
+ dev_dbg(&pdev->dev, "pdata->cs_control is NULL\n");
+ return -EINVAL;
+ }
+
master = spi_alloc_master(&pdev->dev, sizeof(*mcfqspi));
if (master == NULL) {
dev_dbg(&pdev->dev, "spi_alloc_master failed\n");
@@ -436,12 +416,12 @@ static int mcfqspi_probe(struct platform_device *pdev)
}
init_waitqueue_head(&mcfqspi->waitq);
- mcfqspi->dev = &pdev->dev;
master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
master->setup = mcfqspi_setup;
- master->transfer_one_message = mcfqspi_transfer_one_message;
+ master->set_cs = mcfqspi_set_cs;
+ master->transfer_one = mcfqspi_transfer_one;
master->auto_runtime_pm = true;
platform_set_drvdata(pdev, master);
@@ -451,7 +431,7 @@ static int mcfqspi_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "spi_register_master failed\n");
goto fail2;
}
- pm_runtime_enable(mcfqspi->dev);
+ pm_runtime_enable(&pdev->dev);
dev_info(&pdev->dev, "Coldfire QSPI bus driver\n");
@@ -473,9 +453,8 @@ static int mcfqspi_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- pm_runtime_disable(mcfqspi->dev);
+ pm_runtime_disable(&pdev->dev);
/* disable the hardware (set the baud rate to 0) */
mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR);
@@ -490,8 +469,11 @@ static int mcfqspi_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+ int ret;
- spi_master_suspend(master);
+ ret = spi_master_suspend(master);
+ if (ret)
+ return ret;
clk_disable(mcfqspi->clk);
@@ -503,18 +485,17 @@ static int mcfqspi_resume(struct device *dev)
struct spi_master *master = dev_get_drvdata(dev);
struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
- spi_master_resume(master);
-
clk_enable(mcfqspi->clk);
- return 0;
+ return spi_master_resume(master);
}
#endif
#ifdef CONFIG_PM_RUNTIME
static int mcfqspi_runtime_suspend(struct device *dev)
{
- struct mcfqspi *mcfqspi = dev_get_drvdata(dev);
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
clk_disable(mcfqspi->clk);
@@ -523,7 +504,8 @@ static int mcfqspi_runtime_suspend(struct device *dev)
static int mcfqspi_runtime_resume(struct device *dev)
{
- struct mcfqspi *mcfqspi = dev_get_drvdata(dev);
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
clk_enable(mcfqspi->clk);
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index 5e7389faa2a0..50f750989258 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.c
@@ -802,8 +802,7 @@ static int spi_davinci_get_pdata(struct platform_device *pdev,
pdata = &dspi->pdata;
pdata->version = SPI_VERSION_1;
- match = of_match_device(of_match_ptr(davinci_spi_of_match),
- &pdev->dev);
+ match = of_match_device(davinci_spi_of_match, &pdev->dev);
if (!match)
return -ENODEV;
@@ -824,7 +823,6 @@ static int spi_davinci_get_pdata(struct platform_device *pdev,
return 0;
}
#else
-#define davinci_spi_of_match NULL
static struct davinci_spi_platform_data
*spi_davinci_get_pdata(struct platform_device *pdev,
struct davinci_spi *dspi)
@@ -864,10 +862,6 @@ static int davinci_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master);
dspi = spi_master_get_devdata(master);
- if (dspi == NULL) {
- ret = -ENOENT;
- goto free_master;
- }
if (dev_get_platdata(&pdev->dev)) {
pdata = dev_get_platdata(&pdev->dev);
@@ -908,10 +902,6 @@ static int davinci_spi_probe(struct platform_device *pdev)
goto free_master;
dspi->bitbang.master = master;
- if (dspi->bitbang.master == NULL) {
- ret = -ENODEV;
- goto free_master;
- }
dspi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(dspi->clk)) {
@@ -1040,7 +1030,7 @@ static struct platform_driver davinci_spi_driver = {
.driver = {
.name = "spi_davinci",
.owner = THIS_MODULE,
- .of_match_table = davinci_spi_of_match,
+ .of_match_table = of_match_ptr(davinci_spi_of_match),
},
.probe = davinci_spi_probe,
.remove = davinci_spi_remove,
diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c
index 9af56cdf1540..1492f5ee9aaa 100644
--- a/drivers/spi/spi-dw-mmio.c
+++ b/drivers/spi/spi-dw-mmio.c
@@ -66,7 +66,7 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
if (ret)
return ret;
- dws->bus_num = 0;
+ dws->bus_num = pdev->id;
dws->num_cs = 4;
dws->max_freq = clk_get_rate(dwsmmio->clk);
diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c
index bf98d63d92b3..712ac5629cd4 100644
--- a/drivers/spi/spi-dw.c
+++ b/drivers/spi/spi-dw.c
@@ -276,8 +276,7 @@ static void giveback(struct dw_spi *dws)
queue_work(dws->workqueue, &dws->pump_messages);
spin_unlock_irqrestore(&dws->lock, flags);
- last_transfer = list_entry(msg->transfers.prev,
- struct spi_transfer,
+ last_transfer = list_last_entry(&msg->transfers, struct spi_transfer,
transfer_list);
if (!last_transfer->cs_change && dws->cs_control)
@@ -439,12 +438,6 @@ static void pump_transfers(unsigned long data)
if (transfer->speed_hz != speed) {
speed = transfer->speed_hz;
- if (speed > dws->max_freq) {
- printk(KERN_ERR "MRST SPI0: unsupported"
- "freq: %dHz\n", speed);
- message->status = -EIO;
- goto early_exit;
- }
/* clk_div doesn't support odd number */
clk_div = dws->max_freq / speed;
@@ -671,12 +664,6 @@ static int dw_spi_setup(struct spi_device *spi)
return 0;
}
-static void dw_spi_cleanup(struct spi_device *spi)
-{
- struct chip_data *chip = spi_get_ctldata(spi);
- kfree(chip);
-}
-
static int init_queue(struct dw_spi *dws)
{
INIT_LIST_HEAD(&dws->queue);
@@ -806,9 +793,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
master->bus_num = dws->bus_num;
master->num_chipselect = dws->num_cs;
- master->cleanup = dw_spi_cleanup;
master->setup = dw_spi_setup;
master->transfer = dw_spi_transfer;
+ master->max_speed_hz = dws->max_freq;
/* Basic HW init */
spi_hw_init(dws);
diff --git a/drivers/spi/spi-efm32.c b/drivers/spi/spi-efm32.c
index d4d3cc534792..be44a3eeb5e8 100644
--- a/drivers/spi/spi-efm32.c
+++ b/drivers/spi/spi-efm32.c
@@ -198,7 +198,7 @@ static int efm32_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
efm32_spi_filltx(ddata);
- init_completion(&ddata->done);
+ reinit_completion(&ddata->done);
efm32_spi_write32(ddata, REG_IF_TXBL | REG_IF_RXDATAV, REG_IEN);
@@ -287,17 +287,17 @@ static u32 efm32_spi_get_configured_location(struct efm32_spi_ddata *ddata)
return (reg & REG_ROUTE_LOCATION__MASK) >> __ffs(REG_ROUTE_LOCATION__MASK);
}
-static int efm32_spi_probe_dt(struct platform_device *pdev,
+static void 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);
+ ret = of_property_read_u32(np, "efm32,location", &location);
+ if (ret)
+ /* fall back to old and (wrongly) generic property "location" */
+ ret = of_property_read_u32(np, "location", &location);
if (!ret) {
dev_dbg(&pdev->dev, "using location %u\n", location);
} else {
@@ -308,11 +308,6 @@ static int efm32_spi_probe_dt(struct platform_device *pdev,
}
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)
@@ -322,9 +317,14 @@ static int efm32_spi_probe(struct platform_device *pdev)
int ret;
struct spi_master *master;
struct device_node *np = pdev->dev.of_node;
- unsigned int num_cs, i;
+ int num_cs, i;
+
+ if (!np)
+ return -EINVAL;
num_cs = of_gpio_named_count(np, "cs-gpios");
+ if (num_cs < 0)
+ return num_cs;
master = spi_alloc_master(&pdev->dev,
sizeof(*ddata) + num_cs * sizeof(unsigned));
@@ -349,6 +349,7 @@ static int efm32_spi_probe(struct platform_device *pdev)
ddata->bitbang.txrx_bufs = efm32_spi_txrx_bufs;
spin_lock_init(&ddata->lock);
+ init_completion(&ddata->done);
ddata->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(ddata->clk)) {
@@ -415,23 +416,7 @@ static int efm32_spi_probe(struct platform_device *pdev)
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_probe_dt(pdev, master, ddata);
efm32_spi_write32(ddata, 0, REG_IEN);
efm32_spi_write32(ddata, REG_ROUTE_TXPEN | REG_ROUTE_RXPEN |
@@ -487,6 +472,9 @@ static int efm32_spi_remove(struct platform_device *pdev)
static const struct of_device_id efm32_spi_dt_ids[] = {
{
+ .compatible = "energymicro,efm32-spi",
+ }, {
+ /* doesn't follow the "vendor,device" scheme, don't use */
.compatible = "efm32,spi",
}, {
/* sentinel */
diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c
index 1bfaed6e4073..2f675d32df0e 100644
--- a/drivers/spi/spi-ep93xx.c
+++ b/drivers/spi/spi-ep93xx.c
@@ -73,8 +73,6 @@
* @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
* @wait: wait here until given transfer is completed
* @current_msg: message that is currently processed (or %NULL if none)
* @tx: current byte in transfer to transmit
@@ -95,8 +93,6 @@ struct ep93xx_spi {
struct clk *clk;
void __iomem *regs_base;
unsigned long sspdr_phys;
- unsigned long min_rate;
- unsigned long max_rate;
struct completion wait;
struct spi_message *current_msg;
size_t tx;
@@ -199,9 +195,9 @@ static void ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi)
* @div_scr: pointer to return the scr divider
*/
static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
- unsigned long rate,
- u8 *div_cpsr, u8 *div_scr)
+ u32 rate, u8 *div_cpsr, u8 *div_scr)
{
+ struct spi_master *master = platform_get_drvdata(espi->pdev);
unsigned long spi_clk_rate = clk_get_rate(espi->clk);
int cpsr, scr;
@@ -210,7 +206,7 @@ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
* controller. Note that minimum value is already checked in
* ep93xx_spi_transfer_one_message().
*/
- rate = clamp(rate, espi->min_rate, espi->max_rate);
+ rate = clamp(rate, master->min_speed_hz, master->max_speed_hz);
/*
* Calculate divisors so that we can get speed according the
@@ -735,13 +731,6 @@ static int ep93xx_spi_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
{
struct ep93xx_spi *espi = spi_master_get_devdata(master);
- struct spi_transfer *t;
-
- /* first validate each transfer */
- list_for_each_entry(t, &msg->transfers, transfer_list) {
- if (t->speed_hz < espi->min_rate)
- return -EINVAL;
- }
msg->state = NULL;
msg->status = 0;
@@ -917,8 +906,8 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
* Calculate maximum and minimum supported clock rates
* for the controller.
*/
- espi->max_rate = clk_get_rate(espi->clk) / 2;
- espi->min_rate = clk_get_rate(espi->clk) / (254 * 256);
+ master->max_speed_hz = clk_get_rate(espi->clk) / 2;
+ master->min_speed_hz = clk_get_rate(espi->clk) / (254 * 256);
espi->pdev = pdev;
espi->sspdr_phys = res->start + SSPDR;
diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c
index dd5bd468e962..09965f069a1c 100644
--- a/drivers/spi/spi-falcon.c
+++ b/drivers/spi/spi-falcon.c
@@ -312,9 +312,6 @@ static int falcon_sflash_setup(struct spi_device *spi)
unsigned int i;
unsigned long flags;
- if (spi->chip_select > 0)
- return -ENODEV;
-
spin_lock_irqsave(&ebu_lock, flags);
if (spi->max_speed_hz >= CLOCK_100M) {
@@ -422,9 +419,7 @@ static int falcon_sflash_probe(struct platform_device *pdev)
priv->master = master;
master->mode_bits = SPI_MODE_3;
- master->num_chipselect = 1;
master->flags = SPI_MASTER_HALF_DUPLEX;
- master->bus_num = -1;
master->setup = falcon_sflash_setup;
master->prepare_transfer_hardware = falcon_sflash_prepare_xfer;
master->transfer_one_message = falcon_sflash_xfer_one;
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index ec79f726672a..d565eeee3bd8 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -18,6 +18,7 @@
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/io.h>
@@ -108,11 +109,11 @@ struct fsl_dspi {
struct spi_bitbang bitbang;
struct platform_device *pdev;
- void __iomem *base;
+ struct regmap *regmap;
int irq;
- struct clk *clk;
+ struct clk *clk;
- struct spi_transfer *cur_transfer;
+ struct spi_transfer *cur_transfer;
struct chip_data *cur_chip;
size_t len;
void *tx;
@@ -123,24 +124,17 @@ struct fsl_dspi {
u8 cs;
u16 void_write_data;
- wait_queue_head_t waitq;
- u32 waitflags;
+ 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;
-}
+ unsigned int val;
-static void set_bit_mode(struct fsl_dspi *dspi, unsigned char bits)
-{
- u32 temp;
+ regmap_read(dspi->regmap, SPI_CTAR(dspi->cs), &val);
- 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));
+ return ((val & SPI_FRAME_BITS_MASK) == SPI_FRAME_BITS(8)) ? 0 : 1;
}
static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
@@ -188,7 +182,8 @@ static int dspi_transfer_write(struct fsl_dspi *dspi)
*/
if (tx_word && (dspi->len == 1)) {
dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
- set_bit_mode(dspi, 8);
+ regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs),
+ SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8));
tx_word = 0;
}
@@ -238,7 +233,8 @@ static int dspi_transfer_write(struct fsl_dspi *dspi)
dspi_pushr |= SPI_PUSHR_CTCNT; /* clear counter */
}
- writel(dspi_pushr, dspi->base + SPI_PUSHR);
+ regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
+
tx_count++;
}
@@ -253,17 +249,23 @@ static int dspi_transfer_read(struct fsl_dspi *dspi)
while ((dspi->rx < dspi->rx_end)
&& (rx_count < DSPI_FIFO_SIZE)) {
if (rx_word) {
+ unsigned int val;
+
if ((dspi->rx_end - dspi->rx) == 1)
break;
- d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR));
+ regmap_read(dspi->regmap, SPI_POPR, &val);
+ d = SPI_POPR_RXDATA(val);
if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
*(u16 *)dspi->rx = d;
dspi->rx += 2;
} else {
- d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR));
+ unsigned int val;
+
+ regmap_read(dspi->regmap, SPI_POPR, &val);
+ d = SPI_POPR_RXDATA(val);
if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
*(u8 *)dspi->rx = d;
dspi->rx++;
@@ -295,13 +297,13 @@ static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t)
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);
+ regmap_write(dspi->regmap, SPI_MCR, dspi->cur_chip->mcr_val);
+ regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), dspi->cur_chip->ctar_val);
+ regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE);
if (t->speed_hz)
- writel(dspi->cur_chip->ctar_val,
- dspi->base + SPI_CTAR(dspi->cs));
+ regmap_write(dspi->regmap, SPI_CTAR(dspi->cs),
+ dspi->cur_chip->ctar_val);
dspi_transfer_write(dspi);
@@ -315,7 +317,9 @@ static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t)
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);
+ unsigned int pushr;
+
+ regmap_read(dspi->regmap, SPI_PUSHR, &pushr);
switch (value) {
case BITBANG_CS_ACTIVE:
@@ -326,7 +330,7 @@ static void dspi_chipselect(struct spi_device *spi, int value)
break;
}
- writel(pushr, dspi->base + SPI_PUSHR);
+ regmap_write(dspi->regmap, SPI_PUSHR, pushr);
}
static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
@@ -338,7 +342,8 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
/* Only alloc on first setup */
chip = spi_get_ctldata(spi);
if (chip == NULL) {
- chip = kcalloc(1, sizeof(struct chip_data), GFP_KERNEL);
+ chip = devm_kzalloc(&spi->dev, sizeof(struct chip_data),
+ GFP_KERNEL);
if (!chip)
return -ENOMEM;
}
@@ -349,7 +354,6 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
fmsz = spi->bits_per_word - 1;
} else {
pr_err("Invalid wordsize\n");
- kfree(chip);
return -ENODEV;
}
@@ -382,13 +386,15 @@ 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);
+ regmap_write(dspi->regmap, SPI_SR, SPI_SR_EOQF);
dspi_transfer_read(dspi);
if (!dspi->len) {
if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM)
- set_bit_mode(dspi, 16);
+ regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs),
+ SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(16));
+
dspi->waitflags = 1;
wake_up_interruptible(&dspi->waitq);
} else {
@@ -420,7 +426,6 @@ static int dspi_suspend(struct device *dev)
static int dspi_resume(struct device *dev)
{
-
struct spi_master *master = dev_get_drvdata(dev);
struct fsl_dspi *dspi = spi_master_get_devdata(master);
@@ -431,8 +436,13 @@ static int dspi_resume(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP */
-static const struct dev_pm_ops dspi_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(dspi_suspend, dspi_resume)
+static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume);
+
+static struct regmap_config dspi_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = 0x88,
};
static int dspi_probe(struct platform_device *pdev)
@@ -441,6 +451,7 @@ static int dspi_probe(struct platform_device *pdev)
struct spi_master *master;
struct fsl_dspi *dspi;
struct resource *res;
+ void __iomem *base;
int ret = 0, cs_num, bus_num;
master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi));
@@ -475,12 +486,24 @@ static int dspi_probe(struct platform_device *pdev)
master->bus_num = bus_num;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dspi->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(dspi->base)) {
- ret = PTR_ERR(dspi->base);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base)) {
+ ret = PTR_ERR(base);
goto out_master_put;
}
+ dspi_regmap_config.lock_arg = dspi;
+ dspi_regmap_config.val_format_endian =
+ of_property_read_bool(np, "big-endian")
+ ? REGMAP_ENDIAN_BIG : REGMAP_ENDIAN_DEFAULT;
+ dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dspi", base,
+ &dspi_regmap_config);
+ if (IS_ERR(dspi->regmap)) {
+ dev_err(&pdev->dev, "failed to init regmap: %ld\n",
+ PTR_ERR(dspi->regmap));
+ return PTR_ERR(dspi->regmap);
+ }
+
dspi->irq = platform_get_irq(pdev, 0);
if (dspi->irq < 0) {
dev_err(&pdev->dev, "can't get platform irq\n");
@@ -504,7 +527,7 @@ static int dspi_probe(struct platform_device *pdev)
clk_prepare_enable(dspi->clk);
init_waitqueue_head(&dspi->waitq);
- platform_set_drvdata(pdev, dspi);
+ platform_set_drvdata(pdev, master);
ret = spi_bitbang_start(&dspi->bitbang);
if (ret != 0) {
@@ -525,7 +548,8 @@ out_master_put:
static int dspi_remove(struct platform_device *pdev)
{
- struct fsl_dspi *dspi = platform_get_drvdata(pdev);
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct fsl_dspi *dspi = spi_master_get_devdata(master);
/* Disconnect from the SPI framework */
spi_bitbang_stop(&dspi->bitbang);
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 428dc7a6b62e..6fb2b75df821 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -219,13 +219,8 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base;
unsigned int len = t->len;
- u8 bits_per_word;
int ret;
- bits_per_word = spi->bits_per_word;
- if (t->bits_per_word)
- bits_per_word = t->bits_per_word;
-
mpc8xxx_spi->len = t->len;
len = roundup(len, 4) / 4;
diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c
index 0b75f26158ab..e5d45fca3551 100644
--- a/drivers/spi/spi-fsl-lib.c
+++ b/drivers/spi/spi-fsl-lib.c
@@ -200,7 +200,7 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
const void *prop;
int ret = -ENOMEM;
- pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
+ pinfo = devm_kzalloc(&ofdev->dev, sizeof(*pinfo), GFP_KERNEL);
if (!pinfo)
return -ENOMEM;
@@ -215,15 +215,13 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
pdata->sysclk = get_brgfreq();
if (pdata->sysclk == -1) {
pdata->sysclk = fsl_get_sys_freq();
- if (pdata->sysclk == -1) {
- ret = -ENODEV;
- goto err;
- }
+ if (pdata->sysclk == -1)
+ return -ENODEV;
}
#else
ret = of_property_read_u32(np, "clock-frequency", &pdata->sysclk);
if (ret)
- goto err;
+ return ret;
#endif
prop = of_get_property(np, "mode", NULL);
@@ -237,8 +235,4 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
pdata->flags = SPI_CPM_MODE | SPI_CPM1;
return 0;
-
-err:
- kfree(pinfo);
- return ret;
}
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c
index 119f7af94537..f35488ed62a9 100644
--- a/drivers/spi/spi-fsl-spi.c
+++ b/drivers/spi/spi-fsl-spi.c
@@ -239,12 +239,6 @@ static int fsl_spi_setup_transfer(struct spi_device *spi,
if (!bits_per_word)
bits_per_word = spi->bits_per_word;
- /* Make sure its a bit width we support [4..16, 32] */
- if ((bits_per_word < 4)
- || ((bits_per_word > 16) && (bits_per_word != 32))
- || (bits_per_word > mpc8xxx_spi->max_bits_per_word))
- return -EINVAL;
-
if (!hz)
hz = spi->max_speed_hz;
@@ -362,18 +356,28 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
static void fsl_spi_do_one_msg(struct spi_message *m)
{
struct spi_device *spi = m->spi;
- struct spi_transfer *t;
+ struct spi_transfer *t, *first;
unsigned int cs_change;
const int nsecs = 50;
int status;
- cs_change = 1;
- status = 0;
+ /* Don't allow changes if CS is active */
+ first = list_first_entry(&m->transfers, struct spi_transfer,
+ transfer_list);
list_for_each_entry(t, &m->transfers, transfer_list) {
- if (t->bits_per_word || t->speed_hz) {
- /* Don't allow changes if CS is active */
+ if ((first->bits_per_word != t->bits_per_word) ||
+ (first->speed_hz != t->speed_hz)) {
status = -EINVAL;
+ dev_err(&spi->dev,
+ "bits_per_word/speed_hz should be same for the same SPI transfer\n");
+ return;
+ }
+ }
+ cs_change = 1;
+ status = -EINVAL;
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ if (t->bits_per_word || t->speed_hz) {
if (cs_change)
status = fsl_spi_setup_transfer(spi, t);
if (status < 0)
@@ -641,6 +645,10 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
if (mpc8xxx_spi->type == TYPE_GRLIB)
fsl_spi_grlib_probe(dev);
+ master->bits_per_word_mask =
+ (SPI_BPW_RANGE_MASK(4, 16) | SPI_BPW_MASK(32)) &
+ SPI_BPW_RANGE_MASK(1, mpc8xxx_spi->max_bits_per_word);
+
if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
mpc8xxx_spi->set_shifts = fsl_spi_qe_cpu_set_shifts;
diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c
index 7beeb29472ac..09823076df88 100644
--- a/drivers/spi/spi-gpio.c
+++ b/drivers/spi/spi-gpio.c
@@ -19,7 +19,6 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of.h>
@@ -250,7 +249,7 @@ static int spi_gpio_setup(struct spi_device *spi)
/*
* ... otherwise, take it from spi->controller_data
*/
- cs = (unsigned int) spi->controller_data;
+ cs = (unsigned int)(uintptr_t) spi->controller_data;
}
if (!spi->controller_state) {
@@ -503,13 +502,12 @@ static int spi_gpio_remove(struct platform_device *pdev)
{
struct spi_gpio *spi_gpio;
struct spi_gpio_platform_data *pdata;
- int status;
spi_gpio = platform_get_drvdata(pdev);
pdata = dev_get_platdata(&pdev->dev);
/* stop() unregisters child devices too */
- status = spi_bitbang_stop(&spi_gpio->bitbang);
+ spi_bitbang_stop(&spi_gpio->bitbang);
if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
gpio_free(SPI_MISO_GPIO);
@@ -518,7 +516,7 @@ static int spi_gpio_remove(struct platform_device *pdev)
gpio_free(SPI_SCK_GPIO);
spi_master_put(spi_gpio->bitbang.master);
- return status;
+ return 0;
}
MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index a5474ef9d2a0..5daff2054ae4 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -23,7 +23,6 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -741,7 +740,7 @@ static int spi_imx_transfer(struct spi_device *spi,
spi_imx->count = transfer->len;
spi_imx->txfifo = 0;
- init_completion(&spi_imx->xfer_done);
+ reinit_completion(&spi_imx->xfer_done);
spi_imx_push(spi_imx);
@@ -880,12 +879,12 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx->irq = platform_get_irq(pdev, 0);
if (spi_imx->irq < 0) {
- ret = -EINVAL;
+ ret = spi_imx->irq;
goto out_master_put;
}
ret = devm_request_irq(&pdev->dev, spi_imx->irq, spi_imx_isr, 0,
- DRIVER_NAME, spi_imx);
+ dev_name(&pdev->dev), spi_imx);
if (ret) {
dev_err(&pdev->dev, "can't get irq%d: %d\n", spi_imx->irq, ret);
goto out_master_put;
@@ -948,8 +947,8 @@ static int spi_imx_remove(struct platform_device *pdev)
spi_bitbang_stop(&spi_imx->bitbang);
writel(0, spi_imx->base + MXC_CSPICTRL);
- clk_disable_unprepare(spi_imx->clk_ipg);
- clk_disable_unprepare(spi_imx->clk_per);
+ clk_unprepare(spi_imx->clk_ipg);
+ clk_unprepare(spi_imx->clk_per);
spi_master_put(master);
return 0;
diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c
index 5032141eeeec..3822eef2ef9d 100644
--- a/drivers/spi/spi-mpc512x-psc.c
+++ b/drivers/spi/spi-mpc512x-psc.c
@@ -16,7 +16,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/of_address.h>
@@ -466,10 +465,8 @@ static void mpc512x_spi_cs_control(struct spi_device *spi, bool onoff)
gpio_set_value(spi->cs_gpio, onoff);
}
-/* bus_num is used only for the case dev->platform_data == NULL */
static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
- u32 size, unsigned int irq,
- s16 bus_num)
+ u32 size, unsigned int irq)
{
struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
struct mpc512x_psc_spi *mps;
@@ -488,7 +485,6 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
if (pdata == NULL) {
mps->cs_control = mpc512x_spi_cs_control;
- master->bus_num = bus_num;
} else {
mps->cs_control = pdata->cs_control;
master->bus_num = pdata->bus_num;
@@ -574,7 +570,6 @@ static int mpc512x_psc_spi_of_probe(struct platform_device *op)
{
const u32 *regaddr_p;
u64 regaddr64, size64;
- s16 id = -1;
regaddr_p = of_get_address(op->dev.of_node, 0, &size64, NULL);
if (!regaddr_p) {
@@ -583,16 +578,8 @@ static int mpc512x_psc_spi_of_probe(struct platform_device *op)
}
regaddr64 = of_translate_address(op->dev.of_node, regaddr_p);
- /* get PSC id (0..11, used by port_config) */
- id = of_alias_get_id(op->dev.of_node, "spi");
- if (id < 0) {
- dev_err(&op->dev, "no alias id for %s\n",
- op->dev.of_node->full_name);
- return id;
- }
-
return mpc512x_psc_spi_do_probe(&op->dev, (u32) regaddr64, (u32) size64,
- irq_of_parse_and_map(op->dev.of_node, 0), id);
+ irq_of_parse_and_map(op->dev.of_node, 0));
}
static int mpc512x_psc_spi_of_remove(struct platform_device *op)
diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c
index 00ba910ab302..3d18d9351185 100644
--- a/drivers/spi/spi-mpc52xx-psc.c
+++ b/drivers/spi/spi-mpc52xx-psc.c
@@ -12,7 +12,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c
index 7c675fe83101..aac2a5ddd964 100644
--- a/drivers/spi/spi-mpc52xx.c
+++ b/drivers/spi/spi-mpc52xx.c
@@ -12,7 +12,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/errno.h>
#include <linux/of_platform.h>
#include <linux/interrupt.h>
@@ -357,20 +356,6 @@ static void mpc52xx_spi_wq(struct work_struct *work)
* spi_master ops
*/
-static int mpc52xx_spi_setup(struct spi_device *spi)
-{
- if (spi->bits_per_word % 8)
- return -EINVAL;
-
- if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST))
- return -EINVAL;
-
- if (spi->chip_select >= spi->master->num_chipselect)
- return -EINVAL;
-
- return 0;
-}
-
static int mpc52xx_spi_transfer(struct spi_device *spi, struct spi_message *m)
{
struct mpc52xx_spi *ms = spi_master_get_devdata(spi->master);
@@ -433,9 +418,9 @@ static int mpc52xx_spi_probe(struct platform_device *op)
goto err_alloc;
}
- master->setup = mpc52xx_spi_setup;
master->transfer = mpc52xx_spi_transfer;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
master->dev.of_node = op->dev.of_node;
platform_set_drvdata(op, master);
diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c
index 79e5aa2250c8..2884f0c2f5f0 100644
--- a/drivers/spi/spi-mxs.c
+++ b/drivers/spi/spi-mxs.c
@@ -29,7 +29,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -371,7 +370,7 @@ static int mxs_spi_transfer_one(struct spi_master *master,
{
struct mxs_spi *spi = spi_master_get_devdata(master);
struct mxs_ssp *ssp = &spi->ssp;
- struct spi_transfer *t, *tmp_t;
+ struct spi_transfer *t;
unsigned int flag;
int status = 0;
@@ -381,7 +380,7 @@ static int mxs_spi_transfer_one(struct spi_master *master,
writel(mxs_spi_cs_to_reg(m->spi->chip_select),
ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
- list_for_each_entry_safe(t, tmp_t, &m->transfers, transfer_list) {
+ list_for_each_entry(t, &m->transfers, transfer_list) {
status = mxs_spi_setup_transfer(m->spi, t);
if (status)
@@ -473,7 +472,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 (irq_err < 0)
- return -EINVAL;
+ return irq_err;
base = devm_ioremap_resource(&pdev->dev, iores);
if (IS_ERR(base))
diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c
index 50406306bc20..16e30de650b0 100644
--- a/drivers/spi/spi-nuc900.c
+++ b/drivers/spi/spi-nuc900.c
@@ -9,7 +9,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
@@ -38,7 +37,9 @@
/* usi register bit */
#define ENINT (0x01 << 17)
#define ENFLG (0x01 << 16)
+#define SLEEP (0x0f << 12)
#define TXNUM (0x03 << 8)
+#define TXBITLEN (0x1f << 3)
#define TXNEG (0x01 << 2)
#define RXNEG (0x01 << 1)
#define LSB (0x01 << 10)
@@ -58,11 +59,8 @@ struct nuc900_spi {
unsigned char *rx;
struct clk *clk;
struct spi_master *master;
- struct spi_device *curdev;
- struct device *dev;
struct nuc900_spi_info *pdata;
spinlock_t lock;
- struct resource *res;
};
static inline struct nuc900_spi *to_hw(struct spi_device *sdev)
@@ -119,19 +117,16 @@ static void nuc900_spi_chipsel(struct spi_device *spi, int value)
}
}
-static void nuc900_spi_setup_txnum(struct nuc900_spi *hw,
- unsigned int txnum)
+static void nuc900_spi_setup_txnum(struct nuc900_spi *hw, unsigned int txnum)
{
unsigned int val;
unsigned long flags;
spin_lock_irqsave(&hw->lock, flags);
- val = __raw_readl(hw->regs + USI_CNT);
+ val = __raw_readl(hw->regs + USI_CNT) & ~TXNUM;
- if (!txnum)
- val &= ~TXNUM;
- else
+ if (txnum)
val |= txnum << 0x08;
__raw_writel(val, hw->regs + USI_CNT);
@@ -148,7 +143,7 @@ static void nuc900_spi_setup_txbitlen(struct nuc900_spi *hw,
spin_lock_irqsave(&hw->lock, flags);
- val = __raw_readl(hw->regs + USI_CNT);
+ val = __raw_readl(hw->regs + USI_CNT) & ~TXBITLEN;
val |= (txbitlen << 0x03);
@@ -287,12 +282,11 @@ static void nuc900_set_sleep(struct nuc900_spi *hw, unsigned int sleep)
spin_lock_irqsave(&hw->lock, flags);
- val = __raw_readl(hw->regs + USI_CNT);
+ val = __raw_readl(hw->regs + USI_CNT) & ~SLEEP;
if (sleep)
val |= (sleep << 12);
- else
- val &= ~(0x0f << 12);
+
__raw_writel(val, hw->regs + USI_CNT);
spin_unlock_irqrestore(&hw->lock, flags);
@@ -338,6 +332,7 @@ static int nuc900_spi_probe(struct platform_device *pdev)
{
struct nuc900_spi *hw;
struct spi_master *master;
+ struct resource *res;
int err = 0;
master = spi_alloc_master(&pdev->dev, sizeof(struct nuc900_spi));
@@ -349,7 +344,6 @@ static int nuc900_spi_probe(struct platform_device *pdev)
hw = spi_master_get_devdata(master);
hw->master = master;
hw->pdata = dev_get_platdata(&pdev->dev);
- hw->dev = &pdev->dev;
if (hw->pdata == NULL) {
dev_err(&pdev->dev, "No platform data supplied\n");
@@ -361,14 +355,16 @@ static int nuc900_spi_probe(struct platform_device *pdev)
init_completion(&hw->done);
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ if (hw->pdata->lsb)
+ master->mode_bits |= SPI_LSB_FIRST;
master->num_chipselect = hw->pdata->num_cs;
master->bus_num = hw->pdata->bus_num;
hw->bitbang.master = hw->master;
hw->bitbang.chipselect = nuc900_spi_chipsel;
hw->bitbang.txrx_bufs = nuc900_spi_txrx;
- hw->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hw->regs = devm_ioremap_resource(&pdev->dev, hw->res);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hw->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hw->regs)) {
err = PTR_ERR(hw->regs);
goto err_pdata;
diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c
index f7c896e2981e..8998d11c7238 100644
--- a/drivers/spi/spi-oc-tiny.c
+++ b/drivers/spi/spi-oc-tiny.c
@@ -15,7 +15,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/module.h>
@@ -267,8 +266,6 @@ static int tiny_spi_probe(struct platform_device *pdev)
/* setup the state for the bitbang driver */
hw->bitbang.master = master;
- if (!hw->bitbang.master)
- return err;
hw->bitbang.setup_transfer = tiny_spi_setup_transfer;
hw->bitbang.chipselect = tiny_spi_chipselect;
hw->bitbang.txrx_bufs = tiny_spi_txrx_bufs;
diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c
index 67249a48b391..c5e2f718eebd 100644
--- a/drivers/spi/spi-octeon.c
+++ b/drivers/spi/spi-octeon.c
@@ -11,7 +11,6 @@
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/delay.h>
-#include <linux/init.h>
#include <linux/io.h>
#include <linux/of.h>
@@ -33,13 +32,6 @@ struct octeon_spi {
u64 cs_enax;
};
-struct octeon_spi_setup {
- u32 max_speed_hz;
- u8 chip_select;
- u8 mode;
- u8 bits_per_word;
-};
-
static void octeon_spi_wait_ready(struct octeon_spi *p)
{
union cvmx_mpi_sts mpi_sts;
@@ -57,6 +49,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
struct spi_transfer *xfer,
bool last_xfer)
{
+ struct spi_device *spi = msg->spi;
union cvmx_mpi_cfg mpi_cfg;
union cvmx_mpi_tx mpi_tx;
unsigned int clkdiv;
@@ -68,18 +61,11 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
int len;
int i;
- struct octeon_spi_setup *msg_setup = spi_get_ctldata(msg->spi);
-
- speed_hz = msg_setup->max_speed_hz;
- mode = msg_setup->mode;
+ mode = spi->mode;
cpha = mode & SPI_CPHA;
cpol = mode & SPI_CPOL;
- if (xfer->speed_hz)
- speed_hz = xfer->speed_hz;
-
- if (speed_hz > OCTEON_SPI_MAX_CLOCK_HZ)
- speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
+ speed_hz = xfer->speed_hz ? : spi->max_speed_hz;
clkdiv = octeon_get_io_clock_rate() / (2 * speed_hz);
@@ -93,8 +79,8 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
mpi_cfg.s.cslate = cpha ? 1 : 0;
mpi_cfg.s.enable = 1;
- if (msg_setup->chip_select < 4)
- p->cs_enax |= 1ull << (12 + msg_setup->chip_select);
+ if (spi->chip_select < 4)
+ p->cs_enax |= 1ull << (12 + spi->chip_select);
mpi_cfg.u64 |= p->cs_enax;
if (mpi_cfg.u64 != p->last_cfg) {
@@ -114,7 +100,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i), d);
}
mpi_tx.u64 = 0;
- mpi_tx.s.csid = msg_setup->chip_select;
+ mpi_tx.s.csid = spi->chip_select;
mpi_tx.s.leavecs = 1;
mpi_tx.s.txnum = tx_buf ? OCTEON_SPI_MAX_BYTES : 0;
mpi_tx.s.totnum = OCTEON_SPI_MAX_BYTES;
@@ -139,7 +125,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
}
mpi_tx.u64 = 0;
- mpi_tx.s.csid = msg_setup->chip_select;
+ mpi_tx.s.csid = spi->chip_select;
if (last_xfer)
mpi_tx.s.leavecs = xfer->cs_change;
else
@@ -169,17 +155,9 @@ static int octeon_spi_transfer_one_message(struct spi_master *master,
int status = 0;
struct spi_transfer *xfer;
- /*
- * We better have set the configuration via a call to .setup
- * before we get here.
- */
- if (spi_get_ctldata(msg->spi) == NULL) {
- status = -EINVAL;
- goto err;
- }
-
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
- bool last_xfer = &xfer->transfer_list == msg->transfers.prev;
+ bool last_xfer = list_is_last(&xfer->transfer_list,
+ &msg->transfers);
int r = octeon_spi_do_transfer(p, msg, xfer, last_xfer);
if (r < 0) {
status = r;
@@ -194,41 +172,6 @@ err:
return status;
}
-static struct octeon_spi_setup *octeon_spi_new_setup(struct spi_device *spi)
-{
- struct octeon_spi_setup *setup = kzalloc(sizeof(*setup), GFP_KERNEL);
- if (!setup)
- return NULL;
-
- setup->max_speed_hz = spi->max_speed_hz;
- setup->chip_select = spi->chip_select;
- setup->mode = spi->mode;
- setup->bits_per_word = spi->bits_per_word;
- return setup;
-}
-
-static int octeon_spi_setup(struct spi_device *spi)
-{
- struct octeon_spi_setup *new_setup;
- struct octeon_spi_setup *old_setup = spi_get_ctldata(spi);
-
- new_setup = octeon_spi_new_setup(spi);
- if (!new_setup)
- return -ENOMEM;
-
- spi_set_ctldata(spi, new_setup);
- kfree(old_setup);
-
- return 0;
-}
-
-static void octeon_spi_cleanup(struct spi_device *spi)
-{
- struct octeon_spi_setup *old_setup = spi_get_ctldata(spi);
- spi_set_ctldata(spi, NULL);
- kfree(old_setup);
-}
-
static int octeon_spi_probe(struct platform_device *pdev)
{
struct resource *res_mem;
@@ -257,8 +200,6 @@ static int octeon_spi_probe(struct platform_device *pdev)
p->register_base = (u64)devm_ioremap(&pdev->dev, res_mem->start,
resource_size(res_mem));
- /* Dynamic bus numbering */
- master->bus_num = -1;
master->num_chipselect = 4;
master->mode_bits = SPI_CPHA |
SPI_CPOL |
@@ -266,10 +207,9 @@ static int octeon_spi_probe(struct platform_device *pdev)
SPI_LSB_FIRST |
SPI_3WIRE;
- master->setup = octeon_spi_setup;
- master->cleanup = octeon_spi_cleanup;
master->transfer_one_message = octeon_spi_transfer_one_message;
master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
master->dev.of_node = pdev->dev.of_node;
err = devm_spi_register_master(&pdev->dev, master);
diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c
index 0d32054bfc0d..e7ffcded4e14 100644
--- a/drivers/spi/spi-omap-100k.c
+++ b/drivers/spi/spi-omap-100k.c
@@ -83,15 +83,11 @@
#define SPI_SHUTDOWN 1
struct omap1_spi100k {
- struct spi_master *master;
struct clk *ick;
struct clk *fck;
/* Virtual base address of the controller */
void __iomem *base;
-
- /* State of the SPI */
- unsigned int state;
};
struct omap1_spi100k_cs {
@@ -99,13 +95,6 @@ struct omap1_spi100k_cs {
int word_len;
};
-#define MOD_REG_BIT(val, mask, set) do { \
- if (set) \
- val |= mask; \
- else \
- val &= ~mask; \
-} while (0)
-
static void spi100k_enable_clock(struct spi_master *master)
{
unsigned int val;
@@ -139,7 +128,7 @@ static void spi100k_write_data(struct spi_master *master, int len, int data)
}
spi100k_enable_clock(master);
- writew( data , spi100k->base + SPI_TX_MSB);
+ writew(data , spi100k->base + SPI_TX_MSB);
writew(SPI_CTRL_SEN(0) |
SPI_CTRL_WORD_SIZE(len) |
@@ -147,7 +136,8 @@ static void spi100k_write_data(struct spi_master *master, int len, int data)
spi100k->base + SPI_CTRL);
/* Wait for bit ack send change */
- while((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_WE) != SPI_STATUS_WE);
+ while ((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_WE) != SPI_STATUS_WE)
+ ;
udelay(1000);
spi100k_disable_clock(master);
@@ -155,7 +145,7 @@ static void spi100k_write_data(struct spi_master *master, int len, int data)
static int spi100k_read_data(struct spi_master *master, int len)
{
- int dataH,dataL;
+ int dataH, dataL;
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
/* Always do at least 16 bits */
@@ -168,7 +158,8 @@ static int spi100k_read_data(struct spi_master *master, int len)
SPI_CTRL_RD,
spi100k->base + SPI_CTRL);
- while((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_RD) != SPI_STATUS_RD);
+ while ((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_RD) != SPI_STATUS_RD)
+ ;
udelay(1000);
dataL = readw(spi100k->base + SPI_RX_LSB);
@@ -204,12 +195,10 @@ static void omap1_spi100k_force_cs(struct omap1_spi100k *spi100k, int enable)
static unsigned
omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
{
- struct omap1_spi100k *spi100k;
struct omap1_spi100k_cs *cs = spi->controller_state;
unsigned int count, c;
int word_len;
- spi100k = spi_master_get_devdata(spi->master);
count = xfer->len;
c = count;
word_len = cs->word_len;
@@ -221,12 +210,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
rx = xfer->rx_buf;
tx = xfer->tx_buf;
do {
- c-=1;
+ c -= 1;
if (xfer->tx_buf != NULL)
spi100k_write_data(spi->master, word_len, *tx++);
if (xfer->rx_buf != NULL)
*rx++ = spi100k_read_data(spi->master, word_len);
- } while(c);
+ } while (c);
} else if (word_len <= 16) {
u16 *rx;
const u16 *tx;
@@ -234,12 +223,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
rx = xfer->rx_buf;
tx = xfer->tx_buf;
do {
- c-=2;
+ c -= 2;
if (xfer->tx_buf != NULL)
- spi100k_write_data(spi->master,word_len, *tx++);
+ spi100k_write_data(spi->master, word_len, *tx++);
if (xfer->rx_buf != NULL)
- *rx++ = spi100k_read_data(spi->master,word_len);
- } while(c);
+ *rx++ = spi100k_read_data(spi->master, word_len);
+ } while (c);
} else if (word_len <= 32) {
u32 *rx;
const u32 *tx;
@@ -247,12 +236,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
rx = xfer->rx_buf;
tx = xfer->tx_buf;
do {
- c-=4;
+ c -= 4;
if (xfer->tx_buf != NULL)
- spi100k_write_data(spi->master,word_len, *tx);
+ spi100k_write_data(spi->master, word_len, *tx);
if (xfer->rx_buf != NULL)
- *rx = spi100k_read_data(spi->master,word_len);
- } while(c);
+ *rx = spi100k_read_data(spi->master, word_len);
+ } while (c);
}
return count - c;
}
@@ -294,7 +283,7 @@ static int omap1_spi100k_setup(struct spi_device *spi)
spi100k = spi_master_get_devdata(spi->master);
if (!cs) {
- cs = kzalloc(sizeof *cs, GFP_KERNEL);
+ cs = devm_kzalloc(&spi->dev, sizeof(*cs), GFP_KERNEL);
if (!cs)
return -ENOMEM;
cs->base = spi100k->base + spi->chip_select * 0x14;
@@ -411,14 +400,14 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
if (!pdev->id)
return -EINVAL;
- master = spi_alloc_master(&pdev->dev, sizeof *spi100k);
+ master = spi_alloc_master(&pdev->dev, sizeof(*spi100k));
if (master == NULL) {
dev_dbg(&pdev->dev, "master allocation failed\n");
return -ENOMEM;
}
if (pdev->id != -1)
- master->bus_num = pdev->id;
+ master->bus_num = pdev->id;
master->setup = omap1_spi100k_setup;
master->transfer_one_message = omap1_spi100k_transfer_one_message;
@@ -434,7 +423,6 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master);
spi100k = spi_master_get_devdata(master);
- spi100k->master = master;
/*
* The memory region base address is taken as the platform_data.
@@ -461,8 +449,6 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
if (status < 0)
goto err;
- spi100k->state = SPI_RUNNING;
-
return status;
err:
diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c
index 9313fd3b413d..be2a2e108e2f 100644
--- a/drivers/spi/spi-omap-uwire.c
+++ b/drivers/spi/spi-omap-uwire.c
@@ -99,7 +99,6 @@ struct uwire_spi {
};
struct uwire_state {
- unsigned bits_per_word;
unsigned div1_idx;
};
@@ -210,9 +209,8 @@ static void uwire_chipselect(struct spi_device *spi, int value)
static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t)
{
- struct uwire_state *ust = spi->controller_state;
unsigned len = t->len;
- unsigned bits = ust->bits_per_word;
+ unsigned bits = t->bits_per_word ? : spi->bits_per_word;
unsigned bytes;
u16 val, w;
int status = 0;
@@ -220,10 +218,6 @@ static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t)
if (!t->tx_buf && !t->rx_buf)
return 0;
- /* Microwire doesn't read and write concurrently */
- if (t->tx_buf && t->rx_buf)
- return -EPERM;
-
w = spi->chip_select << 10;
w |= CS_CMD;
@@ -322,7 +316,6 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
struct uwire_state *ust = spi->controller_state;
struct uwire_spi *uwire;
unsigned flags = 0;
- unsigned bits;
unsigned hz;
unsigned long rate;
int div1_idx;
@@ -332,23 +325,6 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
uwire = spi_master_get_devdata(spi->master);
- if (spi->chip_select > 3) {
- pr_debug("%s: cs%d?\n", dev_name(&spi->dev), spi->chip_select);
- status = -ENODEV;
- goto done;
- }
-
- bits = spi->bits_per_word;
- if (t != NULL && t->bits_per_word)
- bits = t->bits_per_word;
-
- if (bits > 16) {
- pr_debug("%s: wordsize %d?\n", dev_name(&spi->dev), bits);
- status = -ENODEV;
- goto done;
- }
- ust->bits_per_word = bits;
-
/* mode 0..3, clock inverted separately;
* standard nCS signaling;
* don't treat DI=high as "not ready"
@@ -502,6 +478,7 @@ static int uwire_probe(struct platform_device *pdev)
status = PTR_ERR(uwire->ck);
dev_dbg(&pdev->dev, "no functional clock?\n");
spi_master_put(master);
+ iounmap(uwire_base);
return status;
}
clk_enable(uwire->ck);
@@ -515,7 +492,7 @@ static int uwire_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
-
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
master->flags = SPI_MASTER_HALF_DUPLEX;
master->bus_num = 2; /* "official" */
@@ -539,14 +516,13 @@ static int uwire_probe(struct platform_device *pdev)
static int uwire_remove(struct platform_device *pdev)
{
struct uwire_spi *uwire = platform_get_drvdata(pdev);
- int status;
// FIXME remove all child devices, somewhere ...
- status = spi_bitbang_stop(&uwire->bitbang);
+ spi_bitbang_stop(&uwire->bitbang);
uwire_off(uwire);
iounmap(uwire_base);
- return status;
+ return 0;
}
/* work with hotplug and coldplug */
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index a72127f08e39..2941c5b96ebc 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -22,7 +22,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/device.h>
@@ -45,6 +44,7 @@
#include <linux/platform_data/spi-omap2-mcspi.h>
#define OMAP2_MCSPI_MAX_FREQ 48000000
+#define OMAP2_MCSPI_MAX_DIVIDER 4096
#define OMAP2_MCSPI_MAX_FIFODEPTH 64
#define OMAP2_MCSPI_MAX_FIFOWCNT 0xFFFF
#define SPI_AUTOSUSPEND_TIMEOUT 2000
@@ -89,6 +89,7 @@
#define OMAP2_MCSPI_CHCONF_FORCE BIT(20)
#define OMAP2_MCSPI_CHCONF_FFET BIT(27)
#define OMAP2_MCSPI_CHCONF_FFER BIT(28)
+#define OMAP2_MCSPI_CHCONF_CLKG BIT(29)
#define OMAP2_MCSPI_CHSTAT_RXS BIT(0)
#define OMAP2_MCSPI_CHSTAT_TXS BIT(1)
@@ -96,6 +97,7 @@
#define OMAP2_MCSPI_CHSTAT_TXFFE BIT(3)
#define OMAP2_MCSPI_CHCTRL_EN BIT(0)
+#define OMAP2_MCSPI_CHCTRL_EXTCLK_MASK (0xff << 8)
#define OMAP2_MCSPI_WAKEUPENABLE_WKEN BIT(0)
@@ -149,7 +151,7 @@ struct omap2_mcspi_cs {
int word_len;
struct list_head node;
/* Context save and restore shadow register */
- u32 chconf0;
+ u32 chconf0, chctrl0;
};
static inline void mcspi_write_reg(struct spi_master *master,
@@ -230,10 +232,16 @@ static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
{
+ struct omap2_mcspi_cs *cs = spi->controller_state;
u32 l;
- l = enable ? OMAP2_MCSPI_CHCTRL_EN : 0;
- mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l);
+ l = cs->chctrl0;
+ if (enable)
+ l |= OMAP2_MCSPI_CHCTRL_EN;
+ else
+ l &= ~OMAP2_MCSPI_CHCTRL_EN;
+ cs->chctrl0 = l;
+ mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0);
/* Flash post-writes */
mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0);
}
@@ -840,7 +848,7 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
struct omap2_mcspi_cs *cs = spi->controller_state;
struct omap2_mcspi *mcspi;
struct spi_master *spi_cntrl;
- u32 l = 0, div = 0;
+ u32 l = 0, clkd = 0, div, extclk = 0, clkg = 0;
u8 word_len = spi->bits_per_word;
u32 speed_hz = spi->max_speed_hz;
@@ -856,7 +864,17 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
speed_hz = t->speed_hz;
speed_hz = min_t(u32, speed_hz, OMAP2_MCSPI_MAX_FREQ);
- div = omap2_mcspi_calc_divisor(speed_hz);
+ if (speed_hz < (OMAP2_MCSPI_MAX_FREQ / OMAP2_MCSPI_MAX_DIVIDER)) {
+ clkd = omap2_mcspi_calc_divisor(speed_hz);
+ speed_hz = OMAP2_MCSPI_MAX_FREQ >> clkd;
+ clkg = 0;
+ } else {
+ div = (OMAP2_MCSPI_MAX_FREQ + speed_hz - 1) / speed_hz;
+ speed_hz = OMAP2_MCSPI_MAX_FREQ / div;
+ clkd = (div - 1) & 0xf;
+ extclk = (div - 1) >> 4;
+ clkg = OMAP2_MCSPI_CHCONF_CLKG;
+ }
l = mcspi_cached_chconf0(spi);
@@ -885,7 +903,16 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
/* set clock divisor */
l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK;
- l |= div << 2;
+ l |= clkd << 2;
+
+ /* set clock granularity */
+ l &= ~OMAP2_MCSPI_CHCONF_CLKG;
+ l |= clkg;
+ if (clkg) {
+ cs->chctrl0 &= ~OMAP2_MCSPI_CHCTRL_EXTCLK_MASK;
+ cs->chctrl0 |= extclk << 8;
+ mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0);
+ }
/* set SPI mode 0..3 */
if (spi->mode & SPI_CPOL)
@@ -900,7 +927,7 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
mcspi_write_chconf0(spi, l);
dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s\n",
- OMAP2_MCSPI_MAX_FREQ >> div,
+ speed_hz,
(spi->mode & SPI_CPHA) ? "trailing" : "leading",
(spi->mode & SPI_CPOL) ? "inverted" : "normal");
@@ -972,6 +999,7 @@ static int omap2_mcspi_setup(struct spi_device *spi)
cs->base = mcspi->base + spi->chip_select * 0x14;
cs->phys = mcspi->phys + spi->chip_select * 0x14;
cs->chconf0 = 0;
+ cs->chctrl0 = 0;
spi->controller_state = cs;
/* Link this to context save list */
list_add_tail(&cs->node, &ctx->cs);
@@ -1057,12 +1085,15 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
status = -EINVAL;
break;
}
- if (par_override || t->speed_hz || t->bits_per_word) {
+ if (par_override ||
+ (t->speed_hz != spi->max_speed_hz) ||
+ (t->bits_per_word != spi->bits_per_word)) {
par_override = 1;
status = omap2_mcspi_setup_transfer(spi, t);
if (status < 0)
break;
- if (!t->speed_hz && !t->bits_per_word)
+ if (t->speed_hz == spi->max_speed_hz &&
+ t->bits_per_word == spi->bits_per_word)
par_override = 0;
}
if (cd && cd->cs_per_word) {
@@ -1176,16 +1207,12 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
m->actual_length = 0;
m->status = 0;
- /* reject invalid messages and transfers */
- if (list_empty(&m->transfers))
- 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 > OMAP2_MCSPI_MAX_FREQ
- || (len && !(rx_buf || tx_buf))) {
+ if ((len && !(rx_buf || tx_buf))) {
dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
t->speed_hz,
len,
@@ -1194,12 +1221,6 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
t->bits_per_word);
return -EINVAL;
}
- if (t->speed_hz && t->speed_hz < (OMAP2_MCSPI_MAX_FREQ >> 15)) {
- dev_dbg(mcspi->dev, "speed_hz %d below minimum %d Hz\n",
- t->speed_hz,
- OMAP2_MCSPI_MAX_FREQ >> 15);
- return -EINVAL;
- }
if (m->is_dma_mapped || len < DMA_MIN_BYTES)
continue;
@@ -1311,6 +1332,8 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
master->transfer_one_message = omap2_mcspi_transfer_one_message;
master->cleanup = omap2_mcspi_cleanup;
master->dev.of_node = node;
+ master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ;
+ master->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15;
platform_set_drvdata(pdev, master);
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index 7f2121fe2622..d018a4aac3a1 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -9,7 +9,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
@@ -43,8 +42,6 @@
struct orion_spi {
struct spi_master *master;
void __iomem *base;
- unsigned int max_speed;
- unsigned int min_speed;
struct clk *clk;
};
@@ -75,23 +72,6 @@ orion_spi_clrbits(struct orion_spi *orion_spi, u32 reg, u32 mask)
writel(val, reg_addr);
}
-static int orion_spi_set_transfer_size(struct orion_spi *orion_spi, int size)
-{
- if (size == 16) {
- orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
- ORION_SPI_IF_8_16_BIT_MODE);
- } else if (size == 8) {
- orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
- ORION_SPI_IF_8_16_BIT_MODE);
- } else {
- pr_debug("Bad bits per word value %d (only 8 or 16 are allowed).\n",
- size);
- return -EINVAL;
- }
-
- return 0;
-}
-
static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
{
u32 tclk_hz;
@@ -170,7 +150,14 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
if (rc)
return rc;
- return orion_spi_set_transfer_size(orion_spi, bits_per_word);
+ if (bits_per_word == 16)
+ orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
+ ORION_SPI_IF_8_16_BIT_MODE);
+ else
+ orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
+ ORION_SPI_IF_8_16_BIT_MODE);
+
+ return 0;
}
static void orion_spi_set_cs(struct orion_spi *orion_spi, int enable)
@@ -260,11 +247,9 @@ orion_spi_write_read_16bit(struct spi_device *spi,
static unsigned int
orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
{
- struct orion_spi *orion_spi;
unsigned int count;
int word_len;
- orion_spi = spi_master_get_devdata(spi->master);
word_len = spi->bits_per_word;
count = xfer->len;
@@ -310,27 +295,6 @@ static int orion_spi_transfer_one_message(struct spi_master *master,
goto msg_done;
list_for_each_entry(t, &m->transfers, transfer_list) {
- /* make sure buffer length is even when working in 16
- * bit mode*/
- if ((t->bits_per_word == 16) && (t->len & 1)) {
- dev_err(&spi->dev,
- "message rejected : "
- "odd data length %d while in 16 bit mode\n",
- t->len);
- status = -EIO;
- goto msg_done;
- }
-
- if (t->speed_hz && t->speed_hz < orion_spi->min_speed) {
- dev_err(&spi->dev,
- "message rejected : "
- "device min speed (%d Hz) exceeds "
- "required transfer speed (%d Hz)\n",
- orion_spi->min_speed, t->speed_hz);
- status = -EIO;
- goto msg_done;
- }
-
if (par_override || t->speed_hz || t->bits_per_word) {
par_override = 1;
status = orion_spi_setup_transfer(spi, t);
@@ -375,28 +339,6 @@ static int orion_spi_reset(struct orion_spi *orion_spi)
return 0;
}
-static int orion_spi_setup(struct spi_device *spi)
-{
- struct orion_spi *orion_spi;
-
- orion_spi = spi_master_get_devdata(spi->master);
-
- if ((spi->max_speed_hz == 0)
- || (spi->max_speed_hz > orion_spi->max_speed))
- spi->max_speed_hz = orion_spi->max_speed;
-
- if (spi->max_speed_hz < orion_spi->min_speed) {
- dev_err(&spi->dev, "setup: requested speed too low %d Hz\n",
- spi->max_speed_hz);
- return -EINVAL;
- }
-
- /*
- * baudrate & width will be set orion_spi_setup_transfer
- */
- return 0;
-}
-
static int orion_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
@@ -425,9 +367,9 @@ static int orion_spi_probe(struct platform_device *pdev)
/* we support only mode 0, and no options */
master->mode_bits = SPI_CPHA | SPI_CPOL;
- master->setup = orion_spi_setup;
master->transfer_one_message = orion_spi_transfer_one_message;
master->num_chipselect = ORION_NUM_CHIPSELECTS;
+ master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
platform_set_drvdata(pdev, master);
@@ -443,8 +385,8 @@ static int orion_spi_probe(struct platform_device *pdev)
clk_prepare(spi->clk);
clk_enable(spi->clk);
tclk_hz = clk_get_rate(spi->clk);
- spi->max_speed = DIV_ROUND_UP(tclk_hz, 4);
- spi->min_speed = DIV_ROUND_UP(tclk_hz, 30);
+ master->max_speed_hz = DIV_ROUND_UP(tclk_hz, 4);
+ master->min_speed_hz = DIV_ROUND_UP(tclk_hz, 30);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
spi->base = devm_ioremap_resource(&pdev->dev, r);
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index 2789b452e711..51d99779682f 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -459,9 +459,8 @@ static void giveback(struct pl022 *pl022)
struct spi_transfer *last_transfer;
pl022->next_msg_cs_active = false;
- last_transfer = list_entry(pl022->cur_msg->transfers.prev,
- struct spi_transfer,
- transfer_list);
+ last_transfer = list_last_entry(&pl022->cur_msg->transfers,
+ struct spi_transfer, transfer_list);
/* Delay if requested before any change in chip select */
if (last_transfer->delay_usecs)
@@ -2109,8 +2108,6 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
pl022->chipselects = devm_kzalloc(dev, num_cs * sizeof(int),
GFP_KERNEL);
- pinctrl_pm_select_default_state(dev);
-
/*
* Bus Number Which has been Assigned to this SSP controller
* on this board
@@ -2183,13 +2180,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
goto err_no_clk;
}
- status = clk_prepare(pl022->clk);
- if (status) {
- dev_err(&adev->dev, "could not prepare SSP/SPI bus clock\n");
- goto err_clk_prep;
- }
-
- status = clk_enable(pl022->clk);
+ status = clk_prepare_enable(pl022->clk);
if (status) {
dev_err(&adev->dev, "could not enable SSP/SPI bus clock\n");
goto err_no_clk_en;
@@ -2250,10 +2241,8 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
if (platform_info->enable_dma)
pl022_dma_remove(pl022);
err_no_irq:
- clk_disable(pl022->clk);
+ clk_disable_unprepare(pl022->clk);
err_no_clk_en:
- clk_unprepare(pl022->clk);
- err_clk_prep:
err_no_clk:
err_no_ioremap:
amba_release_regions(adev);
@@ -2281,42 +2270,13 @@ pl022_remove(struct amba_device *adev)
if (pl022->master_info->enable_dma)
pl022_dma_remove(pl022);
- clk_disable(pl022->clk);
- clk_unprepare(pl022->clk);
+ clk_disable_unprepare(pl022->clk);
amba_release_regions(adev);
tasklet_disable(&pl022->pump_transfers);
return 0;
}
-#if defined(CONFIG_SUSPEND) || defined(CONFIG_PM_RUNTIME)
-/*
- * These two functions are used from both suspend/resume and
- * the runtime counterparts to handle external resources like
- * clocks, pins and regulators when going to sleep.
- */
-static void pl022_suspend_resources(struct pl022 *pl022, bool runtime)
-{
- clk_disable(pl022->clk);
-
- if (runtime)
- pinctrl_pm_select_idle_state(&pl022->adev->dev);
- else
- pinctrl_pm_select_sleep_state(&pl022->adev->dev);
-}
-
-static void pl022_resume_resources(struct pl022 *pl022, bool runtime)
-{
- /* First go to the default state */
- pinctrl_pm_select_default_state(&pl022->adev->dev);
- if (!runtime)
- /* Then let's idle the pins until the next transfer happens */
- pinctrl_pm_select_idle_state(&pl022->adev->dev);
-
- clk_enable(pl022->clk);
-}
-#endif
-
-#ifdef CONFIG_SUSPEND
+#ifdef CONFIG_PM_SLEEP
static int pl022_suspend(struct device *dev)
{
struct pl022 *pl022 = dev_get_drvdata(dev);
@@ -2328,8 +2288,13 @@ static int pl022_suspend(struct device *dev)
return ret;
}
- pm_runtime_get_sync(dev);
- pl022_suspend_resources(pl022, false);
+ ret = pm_runtime_force_suspend(dev);
+ if (ret) {
+ spi_master_resume(pl022->master);
+ return ret;
+ }
+
+ pinctrl_pm_select_sleep_state(dev);
dev_dbg(dev, "suspended\n");
return 0;
@@ -2340,8 +2305,9 @@ static int pl022_resume(struct device *dev)
struct pl022 *pl022 = dev_get_drvdata(dev);
int ret;
- pl022_resume_resources(pl022, false);
- pm_runtime_put(dev);
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ dev_err(dev, "problem resuming\n");
/* Start the queue running */
ret = spi_master_resume(pl022->master);
@@ -2352,14 +2318,16 @@ static int pl022_resume(struct device *dev)
return ret;
}
-#endif /* CONFIG_PM */
+#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int pl022_runtime_suspend(struct device *dev)
{
struct pl022 *pl022 = dev_get_drvdata(dev);
- pl022_suspend_resources(pl022, true);
+ clk_disable_unprepare(pl022->clk);
+ pinctrl_pm_select_idle_state(dev);
+
return 0;
}
@@ -2367,14 +2335,16 @@ static int pl022_runtime_resume(struct device *dev)
{
struct pl022 *pl022 = dev_get_drvdata(dev);
- pl022_resume_resources(pl022, true);
+ pinctrl_pm_select_default_state(dev);
+ clk_prepare_enable(pl022->clk);
+
return 0;
}
#endif
static const struct dev_pm_ops pl022_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pl022_suspend, pl022_resume)
- SET_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL)
+ SET_PM_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL)
};
static struct vendor_data vendor_arm = {
diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c
index 5ee56726f8d0..80b8408ac3e3 100644
--- a/drivers/spi/spi-ppc4xx.c
+++ b/drivers/spi/spi-ppc4xx.c
@@ -24,7 +24,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c
index 3c0b55125f1e..713af4806f26 100644
--- a/drivers/spi/spi-pxa2xx-dma.c
+++ b/drivers/spi/spi-pxa2xx-dma.c
@@ -9,7 +9,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/init.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
diff --git a/drivers/spi/spi-pxa2xx-pxadma.c b/drivers/spi/spi-pxa2xx-pxadma.c
index 2916efc7cfe5..e8a26f25d5c0 100644
--- a/drivers/spi/spi-pxa2xx-pxadma.c
+++ b/drivers/spi/spi-pxa2xx-pxadma.c
@@ -18,7 +18,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index c702fc536a77..41185d0557fa 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -362,8 +362,7 @@ static void giveback(struct driver_data *drv_data)
drv_data->cur_msg = NULL;
drv_data->cur_transfer = NULL;
- last_transfer = list_entry(msg->transfers.prev,
- struct spi_transfer,
+ last_transfer = list_last_entry(&msg->transfers, struct spi_transfer,
transfer_list);
/* Delay if requested before any change in chip select */
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
new file mode 100644
index 000000000000..b032e8885e24
--- /dev/null
+++ b/drivers/spi/spi-qup.c
@@ -0,0 +1,779 @@
+/*
+ * Copyright (c) 2008-2014, 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 rev 2 and
+ * only rev 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/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/spi/spi.h>
+
+#define QUP_CONFIG 0x0000
+#define QUP_STATE 0x0004
+#define QUP_IO_M_MODES 0x0008
+#define QUP_SW_RESET 0x000c
+#define QUP_OPERATIONAL 0x0018
+#define QUP_ERROR_FLAGS 0x001c
+#define QUP_ERROR_FLAGS_EN 0x0020
+#define QUP_OPERATIONAL_MASK 0x0028
+#define QUP_HW_VERSION 0x0030
+#define QUP_MX_OUTPUT_CNT 0x0100
+#define QUP_OUTPUT_FIFO 0x0110
+#define QUP_MX_WRITE_CNT 0x0150
+#define QUP_MX_INPUT_CNT 0x0200
+#define QUP_MX_READ_CNT 0x0208
+#define QUP_INPUT_FIFO 0x0218
+
+#define SPI_CONFIG 0x0300
+#define SPI_IO_CONTROL 0x0304
+#define SPI_ERROR_FLAGS 0x0308
+#define SPI_ERROR_FLAGS_EN 0x030c
+
+/* QUP_CONFIG fields */
+#define QUP_CONFIG_SPI_MODE (1 << 8)
+#define QUP_CONFIG_CLOCK_AUTO_GATE BIT(13)
+#define QUP_CONFIG_NO_INPUT BIT(7)
+#define QUP_CONFIG_NO_OUTPUT BIT(6)
+#define QUP_CONFIG_N 0x001f
+
+/* QUP_STATE fields */
+#define QUP_STATE_VALID BIT(2)
+#define QUP_STATE_RESET 0
+#define QUP_STATE_RUN 1
+#define QUP_STATE_PAUSE 3
+#define QUP_STATE_MASK 3
+#define QUP_STATE_CLEAR 2
+
+#define QUP_HW_VERSION_2_1_1 0x20010001
+
+/* QUP_IO_M_MODES fields */
+#define QUP_IO_M_PACK_EN BIT(15)
+#define QUP_IO_M_UNPACK_EN BIT(14)
+#define QUP_IO_M_INPUT_MODE_MASK_SHIFT 12
+#define QUP_IO_M_OUTPUT_MODE_MASK_SHIFT 10
+#define QUP_IO_M_INPUT_MODE_MASK (3 << QUP_IO_M_INPUT_MODE_MASK_SHIFT)
+#define QUP_IO_M_OUTPUT_MODE_MASK (3 << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT)
+
+#define QUP_IO_M_OUTPUT_BLOCK_SIZE(x) (((x) & (0x03 << 0)) >> 0)
+#define QUP_IO_M_OUTPUT_FIFO_SIZE(x) (((x) & (0x07 << 2)) >> 2)
+#define QUP_IO_M_INPUT_BLOCK_SIZE(x) (((x) & (0x03 << 5)) >> 5)
+#define QUP_IO_M_INPUT_FIFO_SIZE(x) (((x) & (0x07 << 7)) >> 7)
+
+#define QUP_IO_M_MODE_FIFO 0
+#define QUP_IO_M_MODE_BLOCK 1
+#define QUP_IO_M_MODE_DMOV 2
+#define QUP_IO_M_MODE_BAM 3
+
+/* QUP_OPERATIONAL fields */
+#define QUP_OP_MAX_INPUT_DONE_FLAG BIT(11)
+#define QUP_OP_MAX_OUTPUT_DONE_FLAG BIT(10)
+#define QUP_OP_IN_SERVICE_FLAG BIT(9)
+#define QUP_OP_OUT_SERVICE_FLAG BIT(8)
+#define QUP_OP_IN_FIFO_FULL BIT(7)
+#define QUP_OP_OUT_FIFO_FULL BIT(6)
+#define QUP_OP_IN_FIFO_NOT_EMPTY BIT(5)
+#define QUP_OP_OUT_FIFO_NOT_EMPTY BIT(4)
+
+/* QUP_ERROR_FLAGS and QUP_ERROR_FLAGS_EN fields */
+#define QUP_ERROR_OUTPUT_OVER_RUN BIT(5)
+#define QUP_ERROR_INPUT_UNDER_RUN BIT(4)
+#define QUP_ERROR_OUTPUT_UNDER_RUN BIT(3)
+#define QUP_ERROR_INPUT_OVER_RUN BIT(2)
+
+/* SPI_CONFIG fields */
+#define SPI_CONFIG_HS_MODE BIT(10)
+#define SPI_CONFIG_INPUT_FIRST BIT(9)
+#define SPI_CONFIG_LOOPBACK BIT(8)
+
+/* SPI_IO_CONTROL fields */
+#define SPI_IO_C_FORCE_CS BIT(11)
+#define SPI_IO_C_CLK_IDLE_HIGH BIT(10)
+#define SPI_IO_C_MX_CS_MODE BIT(8)
+#define SPI_IO_C_CS_N_POLARITY_0 BIT(4)
+#define SPI_IO_C_CS_SELECT(x) (((x) & 3) << 2)
+#define SPI_IO_C_CS_SELECT_MASK 0x000c
+#define SPI_IO_C_TRISTATE_CS BIT(1)
+#define SPI_IO_C_NO_TRI_STATE BIT(0)
+
+/* SPI_ERROR_FLAGS and SPI_ERROR_FLAGS_EN fields */
+#define SPI_ERROR_CLK_OVER_RUN BIT(1)
+#define SPI_ERROR_CLK_UNDER_RUN BIT(0)
+
+#define SPI_NUM_CHIPSELECTS 4
+
+/* high speed mode is when bus rate is greater then 26MHz */
+#define SPI_HS_MIN_RATE 26000000
+#define SPI_MAX_RATE 50000000
+
+#define SPI_DELAY_THRESHOLD 1
+#define SPI_DELAY_RETRY 10
+
+struct spi_qup {
+ void __iomem *base;
+ struct device *dev;
+ struct clk *cclk; /* core clock */
+ struct clk *iclk; /* interface clock */
+ int irq;
+ spinlock_t lock;
+
+ int in_fifo_sz;
+ int out_fifo_sz;
+ int in_blk_sz;
+ int out_blk_sz;
+
+ struct spi_transfer *xfer;
+ struct completion done;
+ int error;
+ int w_size; /* bytes per SPI word */
+ int tx_bytes;
+ int rx_bytes;
+};
+
+
+static inline bool spi_qup_is_valid_state(struct spi_qup *controller)
+{
+ u32 opstate = readl_relaxed(controller->base + QUP_STATE);
+
+ return opstate & QUP_STATE_VALID;
+}
+
+static int spi_qup_set_state(struct spi_qup *controller, u32 state)
+{
+ unsigned long loop;
+ u32 cur_state;
+
+ loop = 0;
+ while (!spi_qup_is_valid_state(controller)) {
+
+ usleep_range(SPI_DELAY_THRESHOLD, SPI_DELAY_THRESHOLD * 2);
+
+ if (++loop > SPI_DELAY_RETRY)
+ return -EIO;
+ }
+
+ if (loop)
+ dev_dbg(controller->dev, "invalid state for %ld,us %d\n",
+ loop, state);
+
+ cur_state = readl_relaxed(controller->base + QUP_STATE);
+ /*
+ * Per spec: for PAUSE_STATE to RESET_STATE, two writes
+ * of (b10) are required
+ */
+ if (((cur_state & QUP_STATE_MASK) == QUP_STATE_PAUSE) &&
+ (state == QUP_STATE_RESET)) {
+ writel_relaxed(QUP_STATE_CLEAR, controller->base + QUP_STATE);
+ writel_relaxed(QUP_STATE_CLEAR, controller->base + QUP_STATE);
+ } else {
+ cur_state &= ~QUP_STATE_MASK;
+ cur_state |= state;
+ writel_relaxed(cur_state, controller->base + QUP_STATE);
+ }
+
+ loop = 0;
+ while (!spi_qup_is_valid_state(controller)) {
+
+ usleep_range(SPI_DELAY_THRESHOLD, SPI_DELAY_THRESHOLD * 2);
+
+ if (++loop > SPI_DELAY_RETRY)
+ return -EIO;
+ }
+
+ return 0;
+}
+
+
+static void spi_qup_fifo_read(struct spi_qup *controller,
+ struct spi_transfer *xfer)
+{
+ u8 *rx_buf = xfer->rx_buf;
+ u32 word, state;
+ int idx, shift, w_size;
+
+ w_size = controller->w_size;
+
+ while (controller->rx_bytes < xfer->len) {
+
+ state = readl_relaxed(controller->base + QUP_OPERATIONAL);
+ if (0 == (state & QUP_OP_IN_FIFO_NOT_EMPTY))
+ break;
+
+ word = readl_relaxed(controller->base + QUP_INPUT_FIFO);
+
+ if (!rx_buf) {
+ controller->rx_bytes += w_size;
+ continue;
+ }
+
+ for (idx = 0; idx < w_size; idx++, controller->rx_bytes++) {
+ /*
+ * The data format depends on bytes per SPI word:
+ * 4 bytes: 0x12345678
+ * 2 bytes: 0x00001234
+ * 1 byte : 0x00000012
+ */
+ shift = BITS_PER_BYTE;
+ shift *= (w_size - idx - 1);
+ rx_buf[controller->rx_bytes] = word >> shift;
+ }
+ }
+}
+
+static void spi_qup_fifo_write(struct spi_qup *controller,
+ struct spi_transfer *xfer)
+{
+ const u8 *tx_buf = xfer->tx_buf;
+ u32 word, state, data;
+ int idx, w_size;
+
+ w_size = controller->w_size;
+
+ while (controller->tx_bytes < xfer->len) {
+
+ state = readl_relaxed(controller->base + QUP_OPERATIONAL);
+ if (state & QUP_OP_OUT_FIFO_FULL)
+ break;
+
+ word = 0;
+ for (idx = 0; idx < w_size; idx++, controller->tx_bytes++) {
+
+ if (!tx_buf) {
+ controller->tx_bytes += w_size;
+ break;
+ }
+
+ data = tx_buf[controller->tx_bytes];
+ word |= data << (BITS_PER_BYTE * (3 - idx));
+ }
+
+ writel_relaxed(word, controller->base + QUP_OUTPUT_FIFO);
+ }
+}
+
+static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
+{
+ struct spi_qup *controller = dev_id;
+ struct spi_transfer *xfer;
+ u32 opflags, qup_err, spi_err;
+ unsigned long flags;
+ int error = 0;
+
+ spin_lock_irqsave(&controller->lock, flags);
+ xfer = controller->xfer;
+ controller->xfer = NULL;
+ spin_unlock_irqrestore(&controller->lock, flags);
+
+ qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS);
+ spi_err = readl_relaxed(controller->base + SPI_ERROR_FLAGS);
+ opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
+
+ writel_relaxed(qup_err, controller->base + QUP_ERROR_FLAGS);
+ writel_relaxed(spi_err, controller->base + SPI_ERROR_FLAGS);
+ writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
+
+ if (!xfer) {
+ dev_err_ratelimited(controller->dev, "unexpected irq %x08 %x08 %x08\n",
+ qup_err, spi_err, opflags);
+ return IRQ_HANDLED;
+ }
+
+ if (qup_err) {
+ if (qup_err & QUP_ERROR_OUTPUT_OVER_RUN)
+ dev_warn(controller->dev, "OUTPUT_OVER_RUN\n");
+ if (qup_err & QUP_ERROR_INPUT_UNDER_RUN)
+ dev_warn(controller->dev, "INPUT_UNDER_RUN\n");
+ if (qup_err & QUP_ERROR_OUTPUT_UNDER_RUN)
+ dev_warn(controller->dev, "OUTPUT_UNDER_RUN\n");
+ if (qup_err & QUP_ERROR_INPUT_OVER_RUN)
+ dev_warn(controller->dev, "INPUT_OVER_RUN\n");
+
+ error = -EIO;
+ }
+
+ if (spi_err) {
+ if (spi_err & SPI_ERROR_CLK_OVER_RUN)
+ dev_warn(controller->dev, "CLK_OVER_RUN\n");
+ if (spi_err & SPI_ERROR_CLK_UNDER_RUN)
+ dev_warn(controller->dev, "CLK_UNDER_RUN\n");
+
+ error = -EIO;
+ }
+
+ if (opflags & QUP_OP_IN_SERVICE_FLAG)
+ spi_qup_fifo_read(controller, xfer);
+
+ if (opflags & QUP_OP_OUT_SERVICE_FLAG)
+ spi_qup_fifo_write(controller, xfer);
+
+ spin_lock_irqsave(&controller->lock, flags);
+ controller->error = error;
+ controller->xfer = xfer;
+ spin_unlock_irqrestore(&controller->lock, flags);
+
+ if (controller->rx_bytes == xfer->len || error)
+ complete(&controller->done);
+
+ return IRQ_HANDLED;
+}
+
+
+/* set clock freq ... bits per word */
+static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
+{
+ struct spi_qup *controller = spi_master_get_devdata(spi->master);
+ u32 config, iomode, mode;
+ int ret, n_words, w_size;
+
+ if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) {
+ dev_err(controller->dev, "too big size for loopback %d > %d\n",
+ xfer->len, controller->in_fifo_sz);
+ return -EIO;
+ }
+
+ ret = clk_set_rate(controller->cclk, xfer->speed_hz);
+ if (ret) {
+ dev_err(controller->dev, "fail to set frequency %d",
+ xfer->speed_hz);
+ return -EIO;
+ }
+
+ if (spi_qup_set_state(controller, QUP_STATE_RESET)) {
+ dev_err(controller->dev, "cannot set RESET state\n");
+ return -EIO;
+ }
+
+ w_size = 4;
+ if (xfer->bits_per_word <= 8)
+ w_size = 1;
+ else if (xfer->bits_per_word <= 16)
+ w_size = 2;
+
+ n_words = xfer->len / w_size;
+ controller->w_size = w_size;
+
+ if (n_words <= controller->in_fifo_sz) {
+ mode = QUP_IO_M_MODE_FIFO;
+ writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT);
+ writel_relaxed(n_words, controller->base + QUP_MX_WRITE_CNT);
+ /* must be zero for FIFO */
+ writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT);
+ writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
+ } else {
+ mode = QUP_IO_M_MODE_BLOCK;
+ writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
+ writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT);
+ /* must be zero for BLOCK and BAM */
+ writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
+ writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
+ }
+
+ iomode = readl_relaxed(controller->base + QUP_IO_M_MODES);
+ /* Set input and output transfer mode */
+ iomode &= ~(QUP_IO_M_INPUT_MODE_MASK | QUP_IO_M_OUTPUT_MODE_MASK);
+ iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN);
+ iomode |= (mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
+ iomode |= (mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
+
+ writel_relaxed(iomode, controller->base + QUP_IO_M_MODES);
+
+ config = readl_relaxed(controller->base + SPI_CONFIG);
+
+ if (spi->mode & SPI_LOOP)
+ config |= SPI_CONFIG_LOOPBACK;
+ else
+ config &= ~SPI_CONFIG_LOOPBACK;
+
+ if (spi->mode & SPI_CPHA)
+ config &= ~SPI_CONFIG_INPUT_FIRST;
+ else
+ config |= SPI_CONFIG_INPUT_FIRST;
+
+ /*
+ * HS_MODE improves signal stability for spi-clk high rates,
+ * but is invalid in loop back mode.
+ */
+ if ((xfer->speed_hz >= SPI_HS_MIN_RATE) && !(spi->mode & SPI_LOOP))
+ config |= SPI_CONFIG_HS_MODE;
+ else
+ config &= ~SPI_CONFIG_HS_MODE;
+
+ writel_relaxed(config, controller->base + SPI_CONFIG);
+
+ config = readl_relaxed(controller->base + QUP_CONFIG);
+ config &= ~(QUP_CONFIG_NO_INPUT | QUP_CONFIG_NO_OUTPUT | QUP_CONFIG_N);
+ config |= xfer->bits_per_word - 1;
+ config |= QUP_CONFIG_SPI_MODE;
+ writel_relaxed(config, controller->base + QUP_CONFIG);
+
+ writel_relaxed(0, controller->base + QUP_OPERATIONAL_MASK);
+ return 0;
+}
+
+static void spi_qup_set_cs(struct spi_device *spi, bool enable)
+{
+ struct spi_qup *controller = spi_master_get_devdata(spi->master);
+
+ u32 iocontol, mask;
+
+ iocontol = readl_relaxed(controller->base + SPI_IO_CONTROL);
+
+ /* Disable auto CS toggle and use manual */
+ iocontol &= ~SPI_IO_C_MX_CS_MODE;
+ iocontol |= SPI_IO_C_FORCE_CS;
+
+ iocontol &= ~SPI_IO_C_CS_SELECT_MASK;
+ iocontol |= SPI_IO_C_CS_SELECT(spi->chip_select);
+
+ mask = SPI_IO_C_CS_N_POLARITY_0 << spi->chip_select;
+
+ if (enable)
+ iocontol |= mask;
+ else
+ iocontol &= ~mask;
+
+ writel_relaxed(iocontol, controller->base + SPI_IO_CONTROL);
+}
+
+static int spi_qup_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct spi_qup *controller = spi_master_get_devdata(master);
+ unsigned long timeout, flags;
+ int ret = -EIO;
+
+ ret = spi_qup_io_config(spi, xfer);
+ if (ret)
+ return ret;
+
+ timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC);
+ timeout = DIV_ROUND_UP(xfer->len * 8, timeout);
+ timeout = 100 * msecs_to_jiffies(timeout);
+
+ reinit_completion(&controller->done);
+
+ spin_lock_irqsave(&controller->lock, flags);
+ controller->xfer = xfer;
+ controller->error = 0;
+ controller->rx_bytes = 0;
+ controller->tx_bytes = 0;
+ spin_unlock_irqrestore(&controller->lock, flags);
+
+ if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
+ dev_warn(controller->dev, "cannot set RUN state\n");
+ goto exit;
+ }
+
+ if (spi_qup_set_state(controller, QUP_STATE_PAUSE)) {
+ dev_warn(controller->dev, "cannot set PAUSE state\n");
+ goto exit;
+ }
+
+ spi_qup_fifo_write(controller, xfer);
+
+ if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
+ dev_warn(controller->dev, "cannot set EXECUTE state\n");
+ goto exit;
+ }
+
+ if (!wait_for_completion_timeout(&controller->done, timeout))
+ ret = -ETIMEDOUT;
+exit:
+ spi_qup_set_state(controller, QUP_STATE_RESET);
+ spin_lock_irqsave(&controller->lock, flags);
+ controller->xfer = NULL;
+ if (!ret)
+ ret = controller->error;
+ spin_unlock_irqrestore(&controller->lock, flags);
+ return ret;
+}
+
+static int spi_qup_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct clk *iclk, *cclk;
+ struct spi_qup *controller;
+ struct resource *res;
+ struct device *dev;
+ void __iomem *base;
+ u32 data, max_freq, iomode;
+ int ret, irq, size;
+
+ dev = &pdev->dev;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ cclk = devm_clk_get(dev, "core");
+ if (IS_ERR(cclk))
+ return PTR_ERR(cclk);
+
+ iclk = devm_clk_get(dev, "iface");
+ if (IS_ERR(iclk))
+ return PTR_ERR(iclk);
+
+ /* This is optional parameter */
+ if (of_property_read_u32(dev->of_node, "spi-max-frequency", &max_freq))
+ max_freq = SPI_MAX_RATE;
+
+ if (!max_freq || max_freq > SPI_MAX_RATE) {
+ dev_err(dev, "invalid clock frequency %d\n", max_freq);
+ return -ENXIO;
+ }
+
+ ret = clk_prepare_enable(cclk);
+ if (ret) {
+ dev_err(dev, "cannot enable core clock\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(iclk);
+ if (ret) {
+ clk_disable_unprepare(cclk);
+ dev_err(dev, "cannot enable iface clock\n");
+ return ret;
+ }
+
+ data = readl_relaxed(base + QUP_HW_VERSION);
+
+ if (data < QUP_HW_VERSION_2_1_1) {
+ clk_disable_unprepare(cclk);
+ clk_disable_unprepare(iclk);
+ dev_err(dev, "v.%08x is not supported\n", data);
+ return -ENXIO;
+ }
+
+ master = spi_alloc_master(dev, sizeof(struct spi_qup));
+ if (!master) {
+ clk_disable_unprepare(cclk);
+ clk_disable_unprepare(iclk);
+ dev_err(dev, "cannot allocate master\n");
+ return -ENOMEM;
+ }
+
+ master->bus_num = pdev->id;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
+ master->num_chipselect = SPI_NUM_CHIPSELECTS;
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+ master->max_speed_hz = max_freq;
+ master->set_cs = spi_qup_set_cs;
+ master->transfer_one = spi_qup_transfer_one;
+ master->dev.of_node = pdev->dev.of_node;
+ master->auto_runtime_pm = true;
+
+ platform_set_drvdata(pdev, master);
+
+ controller = spi_master_get_devdata(master);
+
+ controller->dev = dev;
+ controller->base = base;
+ controller->iclk = iclk;
+ controller->cclk = cclk;
+ controller->irq = irq;
+
+ spin_lock_init(&controller->lock);
+ init_completion(&controller->done);
+
+ iomode = readl_relaxed(base + QUP_IO_M_MODES);
+
+ size = QUP_IO_M_OUTPUT_BLOCK_SIZE(iomode);
+ if (size)
+ controller->out_blk_sz = size * 16;
+ else
+ controller->out_blk_sz = 4;
+
+ size = QUP_IO_M_INPUT_BLOCK_SIZE(iomode);
+ if (size)
+ controller->in_blk_sz = size * 16;
+ else
+ controller->in_blk_sz = 4;
+
+ size = QUP_IO_M_OUTPUT_FIFO_SIZE(iomode);
+ controller->out_fifo_sz = controller->out_blk_sz * (2 << size);
+
+ size = QUP_IO_M_INPUT_FIFO_SIZE(iomode);
+ controller->in_fifo_sz = controller->in_blk_sz * (2 << size);
+
+ dev_info(dev, "v.%08x IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n",
+ data, controller->in_blk_sz, controller->in_fifo_sz,
+ controller->out_blk_sz, controller->out_fifo_sz);
+
+ writel_relaxed(1, base + QUP_SW_RESET);
+
+ ret = spi_qup_set_state(controller, QUP_STATE_RESET);
+ if (ret) {
+ dev_err(dev, "cannot set RESET state\n");
+ goto error;
+ }
+
+ writel_relaxed(0, base + QUP_OPERATIONAL);
+ writel_relaxed(0, base + QUP_IO_M_MODES);
+ writel_relaxed(0, base + QUP_OPERATIONAL_MASK);
+ writel_relaxed(SPI_ERROR_CLK_UNDER_RUN | SPI_ERROR_CLK_OVER_RUN,
+ base + SPI_ERROR_FLAGS_EN);
+
+ writel_relaxed(0, base + SPI_CONFIG);
+ writel_relaxed(SPI_IO_C_NO_TRI_STATE, base + SPI_IO_CONTROL);
+
+ ret = devm_request_irq(dev, irq, spi_qup_qup_irq,
+ IRQF_TRIGGER_HIGH, pdev->name, controller);
+ if (ret)
+ goto error;
+
+ ret = devm_spi_register_master(dev, master);
+ if (ret)
+ goto error;
+
+ pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ return 0;
+
+error:
+ clk_disable_unprepare(cclk);
+ clk_disable_unprepare(iclk);
+ spi_master_put(master);
+ return ret;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int spi_qup_pm_suspend_runtime(struct device *device)
+{
+ struct spi_master *master = dev_get_drvdata(device);
+ struct spi_qup *controller = spi_master_get_devdata(master);
+ u32 config;
+
+ /* Enable clocks auto gaiting */
+ config = readl(controller->base + QUP_CONFIG);
+ config |= QUP_CONFIG_CLOCK_AUTO_GATE;
+ writel_relaxed(config, controller->base + QUP_CONFIG);
+ return 0;
+}
+
+static int spi_qup_pm_resume_runtime(struct device *device)
+{
+ struct spi_master *master = dev_get_drvdata(device);
+ struct spi_qup *controller = spi_master_get_devdata(master);
+ u32 config;
+
+ /* Disable clocks auto gaiting */
+ config = readl_relaxed(controller->base + QUP_CONFIG);
+ config &= ~QUP_CONFIG_CLOCK_AUTO_GATE;
+ writel_relaxed(config, controller->base + QUP_CONFIG);
+ return 0;
+}
+#endif /* CONFIG_PM_RUNTIME */
+
+#ifdef CONFIG_PM_SLEEP
+static int spi_qup_suspend(struct device *device)
+{
+ struct spi_master *master = dev_get_drvdata(device);
+ struct spi_qup *controller = spi_master_get_devdata(master);
+ int ret;
+
+ ret = spi_master_suspend(master);
+ if (ret)
+ return ret;
+
+ ret = spi_qup_set_state(controller, QUP_STATE_RESET);
+ if (ret)
+ return ret;
+
+ clk_disable_unprepare(controller->cclk);
+ clk_disable_unprepare(controller->iclk);
+ return 0;
+}
+
+static int spi_qup_resume(struct device *device)
+{
+ struct spi_master *master = dev_get_drvdata(device);
+ struct spi_qup *controller = spi_master_get_devdata(master);
+ int ret;
+
+ ret = clk_prepare_enable(controller->iclk);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(controller->cclk);
+ if (ret)
+ return ret;
+
+ ret = spi_qup_set_state(controller, QUP_STATE_RESET);
+ if (ret)
+ return ret;
+
+ return spi_master_resume(master);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static int spi_qup_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = dev_get_drvdata(&pdev->dev);
+ struct spi_qup *controller = spi_master_get_devdata(master);
+ int ret;
+
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret)
+ return ret;
+
+ ret = spi_qup_set_state(controller, QUP_STATE_RESET);
+ if (ret)
+ return ret;
+
+ clk_disable_unprepare(controller->cclk);
+ clk_disable_unprepare(controller->iclk);
+
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ return 0;
+}
+
+static struct of_device_id spi_qup_dt_match[] = {
+ { .compatible = "qcom,spi-qup-v2.1.1", },
+ { .compatible = "qcom,spi-qup-v2.2.1", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, spi_qup_dt_match);
+
+static const struct dev_pm_ops spi_qup_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(spi_qup_suspend, spi_qup_resume)
+ SET_RUNTIME_PM_OPS(spi_qup_pm_suspend_runtime,
+ spi_qup_pm_resume_runtime,
+ NULL)
+};
+
+static struct platform_driver spi_qup_driver = {
+ .driver = {
+ .name = "spi_qup",
+ .owner = THIS_MODULE,
+ .pm = &spi_qup_dev_pm_ops,
+ .of_match_table = spi_qup_dt_match,
+ },
+ .probe = spi_qup_probe,
+ .remove = spi_qup_remove,
+};
+module_platform_driver(spi_qup_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:spi_qup");
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index 28987d9fcfe5..1fb0ad213324 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -1,7 +1,8 @@
/*
* SH RSPI driver
*
- * Copyright (C) 2012 Renesas Solutions Corp.
+ * Copyright (C) 2012, 2013 Renesas Solutions Corp.
+ * Copyright (C) 2014 Glider bvba
*
* Based on spi-sh.c:
* Copyright (C) 2011 Renesas Solutions Corp.
@@ -25,14 +26,14 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
-#include <linux/list.h>
-#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
#include <linux/sh_dma.h>
#include <linux/spi/spi.h>
#include <linux/spi/rspi.h>
@@ -49,7 +50,7 @@
#define RSPI_SPCKD 0x0c /* Clock Delay Register */
#define RSPI_SSLND 0x0d /* Slave Select Negation Delay Register */
#define RSPI_SPND 0x0e /* Next-Access Delay Register */
-#define RSPI_SPCR2 0x0f /* Control Register 2 */
+#define RSPI_SPCR2 0x0f /* Control Register 2 (SH only) */
#define RSPI_SPCMD0 0x10 /* Command Register 0 */
#define RSPI_SPCMD1 0x12 /* Command Register 1 */
#define RSPI_SPCMD2 0x14 /* Command Register 2 */
@@ -58,16 +59,23 @@
#define RSPI_SPCMD5 0x1a /* Command Register 5 */
#define RSPI_SPCMD6 0x1c /* Command Register 6 */
#define RSPI_SPCMD7 0x1e /* Command Register 7 */
+#define RSPI_SPCMD(i) (RSPI_SPCMD0 + (i) * 2)
+#define RSPI_NUM_SPCMD 8
+#define RSPI_RZ_NUM_SPCMD 4
+#define QSPI_NUM_SPCMD 4
+
+/* RSPI on RZ only */
#define RSPI_SPBFCR 0x20 /* Buffer Control Register */
#define RSPI_SPBFDR 0x22 /* Buffer Data Count Setting Register */
-/*qspi only */
+/* QSPI only */
#define QSPI_SPBFCR 0x18 /* Buffer Control Register */
#define QSPI_SPBDCR 0x1a /* Buffer Data Count Register */
#define QSPI_SPBMUL0 0x1c /* Transfer Data Length Multiplier Setting Register 0 */
#define QSPI_SPBMUL1 0x20 /* Transfer Data Length Multiplier Setting Register 1 */
#define QSPI_SPBMUL2 0x24 /* Transfer Data Length Multiplier Setting Register 2 */
#define QSPI_SPBMUL3 0x28 /* Transfer Data Length Multiplier Setting Register 3 */
+#define QSPI_SPBMUL(i) (QSPI_SPBMUL0 + (i) * 4)
/* SPCR - Control Register */
#define SPCR_SPRIE 0x80 /* Receive Interrupt Enable */
@@ -104,7 +112,7 @@
#define SPSR_PERF 0x08 /* Parity Error Flag */
#define SPSR_MODF 0x04 /* Mode Fault Error Flag */
#define SPSR_IDLNF 0x02 /* RSPI Idle Flag */
-#define SPSR_OVRF 0x01 /* Overrun Error Flag */
+#define SPSR_OVRF 0x01 /* Overrun Error Flag (RSPI only) */
/* SPSCR - Sequence Control Register */
#define SPSCR_SPSLN_MASK 0x07 /* Sequence Length Specification */
@@ -121,13 +129,13 @@
#define SPDCR_SPLWORD SPDCR_SPLW1
#define SPDCR_SPLBYTE SPDCR_SPLW0
#define SPDCR_SPLW 0x20 /* Access Width Specification (SH) */
-#define SPDCR_SPRDTD 0x10 /* Receive Transmit Data Select */
+#define SPDCR_SPRDTD 0x10 /* Receive Transmit Data Select (SH) */
#define SPDCR_SLSEL1 0x08
#define SPDCR_SLSEL0 0x04
-#define SPDCR_SLSEL_MASK 0x0c /* SSL1 Output Select */
+#define SPDCR_SLSEL_MASK 0x0c /* SSL1 Output Select (SH) */
#define SPDCR_SPFC1 0x02
#define SPDCR_SPFC0 0x01
-#define SPDCR_SPFC_MASK 0x03 /* Frame Count Setting (1-4) */
+#define SPDCR_SPFC_MASK 0x03 /* Frame Count Setting (1-4) (SH) */
/* SPCKD - Clock Delay Register */
#define SPCKD_SCKDL_MASK 0x07 /* Clock Delay Setting (1-8) */
@@ -151,7 +159,7 @@
#define SPCMD_LSBF 0x1000 /* LSB First */
#define SPCMD_SPB_MASK 0x0f00 /* Data Length Setting */
#define SPCMD_SPB_8_TO_16(bit) (((bit - 1) << 8) & SPCMD_SPB_MASK)
-#define SPCMD_SPB_8BIT 0x0000 /* qspi only */
+#define SPCMD_SPB_8BIT 0x0000 /* QSPI only */
#define SPCMD_SPB_16BIT 0x0100
#define SPCMD_SPB_20BIT 0x0000
#define SPCMD_SPB_24BIT 0x0100
@@ -170,8 +178,8 @@
#define SPCMD_CPHA 0x0001 /* Clock Phase Setting */
/* SPBFCR - Buffer Control Register */
-#define SPBFCR_TXRST 0x80 /* Transmit Buffer Data Reset (qspi only) */
-#define SPBFCR_RXRST 0x40 /* Receive Buffer Data Reset (qspi only) */
+#define SPBFCR_TXRST 0x80 /* Transmit Buffer Data Reset */
+#define SPBFCR_RXRST 0x40 /* Receive Buffer Data Reset */
#define SPBFCR_TXTRG_MASK 0x30 /* Transmit Buffer Data Triggering Number */
#define SPBFCR_RXTRG_MASK 0x07 /* Receive Buffer Data Triggering Number */
@@ -181,22 +189,21 @@ struct rspi_data {
void __iomem *addr;
u32 max_speed_hz;
struct spi_master *master;
- struct list_head queue;
- struct work_struct ws;
wait_queue_head_t wait;
- spinlock_t lock;
struct clk *clk;
- u8 spsr;
u16 spcmd;
+ u8 spsr;
+ u8 sppcr;
+ int rx_irq, tx_irq;
const struct spi_ops *ops;
/* for dmaengine */
struct dma_chan *chan_tx;
struct dma_chan *chan_rx;
- int irq;
unsigned dma_width_16bit:1;
unsigned dma_callbacked:1;
+ unsigned byte_access:1;
};
static void rspi_write8(const struct rspi_data *rspi, u8 data, u16 offset)
@@ -224,34 +231,47 @@ static u16 rspi_read16(const struct rspi_data *rspi, u16 offset)
return ioread16(rspi->addr + offset);
}
+static void rspi_write_data(const struct rspi_data *rspi, u16 data)
+{
+ if (rspi->byte_access)
+ rspi_write8(rspi, data, RSPI_SPDR);
+ else /* 16 bit */
+ rspi_write16(rspi, data, RSPI_SPDR);
+}
+
+static u16 rspi_read_data(const struct rspi_data *rspi)
+{
+ if (rspi->byte_access)
+ return rspi_read8(rspi, RSPI_SPDR);
+ else /* 16 bit */
+ return rspi_read16(rspi, RSPI_SPDR);
+}
+
/* optional functions */
struct spi_ops {
- int (*set_config_register)(const struct rspi_data *rspi,
- int access_size);
- int (*send_pio)(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t);
- int (*receive_pio)(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t);
-
+ int (*set_config_register)(struct rspi_data *rspi, int access_size);
+ int (*transfer_one)(struct spi_master *master, struct spi_device *spi,
+ struct spi_transfer *xfer);
+ u16 mode_bits;
};
/*
- * functions for RSPI
+ * functions for RSPI on legacy SH
*/
-static int rspi_set_config_register(const struct rspi_data *rspi,
- int access_size)
+static int rspi_set_config_register(struct rspi_data *rspi, int access_size)
{
int spbr;
- /* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
- rspi_write8(rspi, 0x00, RSPI_SPPCR);
+ /* Sets output mode, MOSI signal, and (optionally) loopback */
+ rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR);
/* Sets transfer bit rate */
spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1;
rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
- /* Sets number of frames to be used: 1 frame */
- rspi_write8(rspi, 0x00, RSPI_SPDCR);
+ /* Disable dummy transmission, set 16-bit word access, 1 frame */
+ rspi_write8(rspi, 0, RSPI_SPDCR);
+ rspi->byte_access = 0;
/* Sets RSPCK, SSL, next-access delay value */
rspi_write8(rspi, 0x00, RSPI_SPCKD);
@@ -262,8 +282,41 @@ static int rspi_set_config_register(const struct rspi_data *rspi,
rspi_write8(rspi, 0x00, RSPI_SPCR2);
/* Sets SPCMD */
- rspi_write16(rspi, SPCMD_SPB_8_TO_16(access_size) | rspi->spcmd,
- RSPI_SPCMD0);
+ rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size);
+ rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
+
+ /* Sets RSPI mode */
+ rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR);
+
+ return 0;
+}
+
+/*
+ * functions for RSPI on RZ
+ */
+static int rspi_rz_set_config_register(struct rspi_data *rspi, int access_size)
+{
+ int spbr;
+
+ /* Sets output mode, MOSI signal, and (optionally) loopback */
+ rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR);
+
+ /* Sets transfer bit rate */
+ spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1;
+ rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
+
+ /* Disable dummy transmission, set byte access */
+ rspi_write8(rspi, SPDCR_SPLBYTE, RSPI_SPDCR);
+ rspi->byte_access = 1;
+
+ /* Sets RSPCK, SSL, next-access delay value */
+ rspi_write8(rspi, 0x00, RSPI_SPCKD);
+ rspi_write8(rspi, 0x00, RSPI_SSLND);
+ rspi_write8(rspi, 0x00, RSPI_SPND);
+
+ /* Sets SPCMD */
+ rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size);
+ rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
/* Sets RSPI mode */
rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR);
@@ -274,21 +327,20 @@ static int rspi_set_config_register(const struct rspi_data *rspi,
/*
* functions for QSPI
*/
-static int qspi_set_config_register(const struct rspi_data *rspi,
- int access_size)
+static int qspi_set_config_register(struct rspi_data *rspi, int access_size)
{
- u16 spcmd;
int spbr;
- /* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
- rspi_write8(rspi, 0x00, RSPI_SPPCR);
+ /* Sets output mode, MOSI signal, and (optionally) loopback */
+ rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR);
/* Sets transfer bit rate */
spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz);
rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
- /* Sets number of frames to be used: 1 frame */
- rspi_write8(rspi, 0x00, RSPI_SPDCR);
+ /* Disable dummy transmission, set byte access */
+ rspi_write8(rspi, 0, RSPI_SPDCR);
+ rspi->byte_access = 1;
/* Sets RSPCK, SSL, next-access delay value */
rspi_write8(rspi, 0x00, RSPI_SPCKD);
@@ -297,13 +349,13 @@ static int qspi_set_config_register(const struct rspi_data *rspi,
/* Data Length Setting */
if (access_size == 8)
- spcmd = SPCMD_SPB_8BIT;
+ rspi->spcmd |= SPCMD_SPB_8BIT;
else if (access_size == 16)
- spcmd = SPCMD_SPB_16BIT;
+ rspi->spcmd |= SPCMD_SPB_16BIT;
else
- spcmd = SPCMD_SPB_32BIT;
+ rspi->spcmd |= SPCMD_SPB_32BIT;
- spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | rspi->spcmd | SPCMD_SPNDEN;
+ rspi->spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | SPCMD_SPNDEN;
/* Resets transfer data length */
rspi_write32(rspi, 0, QSPI_SPBMUL0);
@@ -314,9 +366,9 @@ static int qspi_set_config_register(const struct rspi_data *rspi,
rspi_write8(rspi, 0x00, QSPI_SPBFCR);
/* Sets SPCMD */
- rspi_write16(rspi, spcmd, RSPI_SPCMD0);
+ rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
- /* Enables SPI function in a master mode */
+ /* Enables SPI function in master mode */
rspi_write8(rspi, SPCR_SPE | SPCR_MSTR, RSPI_SPCR);
return 0;
@@ -340,6 +392,9 @@ static int rspi_wait_for_interrupt(struct rspi_data *rspi, u8 wait_mask,
int ret;
rspi->spsr = rspi_read8(rspi, RSPI_SPSR);
+ if (rspi->spsr & wait_mask)
+ return 0;
+
rspi_enable_irq(rspi, enable_bit);
ret = wait_event_timeout(rspi->wait, rspi->spsr & wait_mask, HZ);
if (ret == 0 && !(rspi->spsr & wait_mask))
@@ -348,78 +403,39 @@ static int rspi_wait_for_interrupt(struct rspi_data *rspi, u8 wait_mask,
return 0;
}
-static void rspi_assert_ssl(const struct rspi_data *rspi)
-{
- rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR);
-}
-
-static void rspi_negate_ssl(const struct rspi_data *rspi)
+static int rspi_data_out(struct rspi_data *rspi, u8 data)
{
- rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR);
+ if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
+ dev_err(&rspi->master->dev, "transmit timeout\n");
+ return -ETIMEDOUT;
+ }
+ rspi_write_data(rspi, data);
+ return 0;
}
-static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t)
+static int rspi_data_in(struct rspi_data *rspi)
{
- int remain = t->len;
- const u8 *data = t->tx_buf;
- while (remain > 0) {
- rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD,
- RSPI_SPCR);
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: tx empty timeout\n", __func__);
- return -ETIMEDOUT;
- }
+ u8 data;
- rspi_write16(rspi, *data, RSPI_SPDR);
- data++;
- remain--;
+ if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
+ dev_err(&rspi->master->dev, "receive timeout\n");
+ return -ETIMEDOUT;
}
-
- /* Waiting for the last transmission */
- rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
-
- return 0;
+ data = rspi_read_data(rspi);
+ return data;
}
-static int qspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t)
+static int rspi_data_out_in(struct rspi_data *rspi, u8 data)
{
- int remain = t->len;
- const u8 *data = t->tx_buf;
-
- rspi_write8(rspi, SPBFCR_TXRST, QSPI_SPBFCR);
- rspi_write8(rspi, 0x00, QSPI_SPBFCR);
-
- while (remain > 0) {
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: tx empty timeout\n", __func__);
- return -ETIMEDOUT;
- }
- rspi_write8(rspi, *data++, RSPI_SPDR);
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: receive timeout\n", __func__);
- return -ETIMEDOUT;
- }
- rspi_read8(rspi, RSPI_SPDR);
-
- remain--;
- }
+ int ret;
- /* Waiting for the last transmission */
- rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
+ ret = rspi_data_out(rspi, data);
+ if (ret < 0)
+ return ret;
- return 0;
+ return rspi_data_in(rspi);
}
-#define send_pio(spi, mesg, t) spi->ops->send_pio(spi, mesg, t)
-
static void rspi_dma_complete(void *arg)
{
struct rspi_data *rspi = arg;
@@ -471,7 +487,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t)
struct scatterlist sg;
const void *buf = NULL;
struct dma_async_tx_descriptor *desc;
- unsigned len;
+ unsigned int len;
int ret = 0;
if (rspi->dma_width_16bit) {
@@ -509,7 +525,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t)
* DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be
* called. So, this driver disables the IRQ while DMA transfer.
*/
- disable_irq(rspi->irq);
+ disable_irq(rspi->tx_irq);
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD, RSPI_SPCR);
rspi_enable_irq(rspi, SPCR_SPTIE);
@@ -528,7 +544,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t)
ret = -ETIMEDOUT;
rspi_disable_irq(rspi, SPCR_SPTIE);
- enable_irq(rspi->irq);
+ enable_irq(rspi->tx_irq);
end:
rspi_dma_unmap_sg(&sg, rspi->chan_tx, DMA_TO_DEVICE);
@@ -545,46 +561,17 @@ static void rspi_receive_init(const struct rspi_data *rspi)
spsr = rspi_read8(rspi, RSPI_SPSR);
if (spsr & SPSR_SPRF)
- rspi_read16(rspi, RSPI_SPDR); /* dummy read */
+ rspi_read_data(rspi); /* dummy read */
if (spsr & SPSR_OVRF)
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPSR) & ~SPSR_OVRF,
RSPI_SPSR);
}
-static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t)
+static void rspi_rz_receive_init(const struct rspi_data *rspi)
{
- int remain = t->len;
- u8 *data;
-
rspi_receive_init(rspi);
-
- data = t->rx_buf;
- while (remain > 0) {
- rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD,
- RSPI_SPCR);
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: tx empty timeout\n", __func__);
- return -ETIMEDOUT;
- }
- /* dummy write for generate clock */
- rspi_write16(rspi, DUMMY_DATA, RSPI_SPDR);
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: receive timeout\n", __func__);
- return -ETIMEDOUT;
- }
- /* SPDR allows 16 or 32-bit access only */
- *data = (u8)rspi_read16(rspi, RSPI_SPDR);
-
- data++;
- remain--;
- }
-
- return 0;
+ rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, RSPI_SPBFCR);
+ rspi_write8(rspi, 0, RSPI_SPBFCR);
}
static void qspi_receive_init(const struct rspi_data *rspi)
@@ -593,51 +580,17 @@ static void qspi_receive_init(const struct rspi_data *rspi)
spsr = rspi_read8(rspi, RSPI_SPSR);
if (spsr & SPSR_SPRF)
- rspi_read8(rspi, RSPI_SPDR); /* dummy read */
+ rspi_read_data(rspi); /* dummy read */
rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, QSPI_SPBFCR);
- rspi_write8(rspi, 0x00, QSPI_SPBFCR);
+ rspi_write8(rspi, 0, QSPI_SPBFCR);
}
-static int qspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t)
-{
- int remain = t->len;
- u8 *data;
-
- qspi_receive_init(rspi);
-
- data = t->rx_buf;
- while (remain > 0) {
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: tx empty timeout\n", __func__);
- return -ETIMEDOUT;
- }
- /* dummy write for generate clock */
- rspi_write8(rspi, DUMMY_DATA, RSPI_SPDR);
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: receive timeout\n", __func__);
- return -ETIMEDOUT;
- }
- /* SPDR allows 8, 16 or 32-bit access */
- *data++ = rspi_read8(rspi, RSPI_SPDR);
- remain--;
- }
-
- return 0;
-}
-
-#define receive_pio(spi, mesg, t) spi->ops->receive_pio(spi, mesg, t)
-
static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
{
struct scatterlist sg, sg_dummy;
void *dummy = NULL, *rx_buf = NULL;
struct dma_async_tx_descriptor *desc, *desc_dummy;
- unsigned len;
+ unsigned int len;
int ret = 0;
if (rspi->dma_width_16bit) {
@@ -695,7 +648,9 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
* DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be
* called. So, this driver disables the IRQ while DMA transfer.
*/
- disable_irq(rspi->irq);
+ disable_irq(rspi->tx_irq);
+ if (rspi->rx_irq != rspi->tx_irq)
+ disable_irq(rspi->rx_irq);
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD, RSPI_SPCR);
rspi_enable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE);
@@ -718,7 +673,9 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
ret = -ETIMEDOUT;
rspi_disable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE);
- enable_irq(rspi->irq);
+ enable_irq(rspi->tx_irq);
+ if (rspi->rx_irq != rspi->tx_irq)
+ enable_irq(rspi->rx_irq);
end:
rspi_dma_unmap_sg(&sg, rspi->chan_rx, DMA_FROM_DEVICE);
@@ -746,56 +703,175 @@ static int rspi_is_dma(const struct rspi_data *rspi, struct spi_transfer *t)
return 0;
}
-static void rspi_work(struct work_struct *work)
+static int rspi_transfer_out_in(struct rspi_data *rspi,
+ struct spi_transfer *xfer)
{
- struct rspi_data *rspi = container_of(work, struct rspi_data, ws);
- struct spi_message *mesg;
- struct spi_transfer *t;
- unsigned long flags;
- int ret;
+ int remain = xfer->len, ret;
+ const u8 *tx_buf = xfer->tx_buf;
+ u8 *rx_buf = xfer->rx_buf;
+ u8 spcr, data;
- 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);
-
- rspi_assert_ssl(rspi);
-
- list_for_each_entry(t, &mesg->transfers, transfer_list) {
- if (t->tx_buf) {
- if (rspi_is_dma(rspi, t))
- ret = rspi_send_dma(rspi, t);
- else
- ret = send_pio(rspi, mesg, t);
- if (ret < 0)
- goto error;
- }
- if (t->rx_buf) {
- if (rspi_is_dma(rspi, t))
- ret = rspi_receive_dma(rspi, t);
- else
- ret = receive_pio(rspi, mesg, t);
- if (ret < 0)
- goto error;
- }
- mesg->actual_length += t->len;
+ rspi_receive_init(rspi);
+
+ spcr = rspi_read8(rspi, RSPI_SPCR);
+ if (rx_buf)
+ spcr &= ~SPCR_TXMD;
+ else
+ spcr |= SPCR_TXMD;
+ rspi_write8(rspi, spcr, RSPI_SPCR);
+
+ while (remain > 0) {
+ data = tx_buf ? *tx_buf++ : DUMMY_DATA;
+ ret = rspi_data_out(rspi, data);
+ if (ret < 0)
+ return ret;
+ if (rx_buf) {
+ ret = rspi_data_in(rspi);
+ if (ret < 0)
+ return ret;
+ *rx_buf++ = ret;
}
- rspi_negate_ssl(rspi);
+ remain--;
+ }
+
+ /* Wait for the last transmission */
+ rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
+
+ return 0;
+}
+
+static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+ int ret;
+
+ if (!rspi_is_dma(rspi, xfer))
+ return rspi_transfer_out_in(rspi, xfer);
+
+ if (xfer->tx_buf) {
+ ret = rspi_send_dma(rspi, xfer);
+ if (ret < 0)
+ return ret;
+ }
+ if (xfer->rx_buf)
+ return rspi_receive_dma(rspi, xfer);
+
+ return 0;
+}
+
+static int rspi_rz_transfer_out_in(struct rspi_data *rspi,
+ struct spi_transfer *xfer)
+{
+ int remain = xfer->len, ret;
+ const u8 *tx_buf = xfer->tx_buf;
+ u8 *rx_buf = xfer->rx_buf;
+ u8 data;
+
+ rspi_rz_receive_init(rspi);
+
+ while (remain > 0) {
+ data = tx_buf ? *tx_buf++ : DUMMY_DATA;
+ ret = rspi_data_out_in(rspi, data);
+ if (ret < 0)
+ return ret;
+ if (rx_buf)
+ *rx_buf++ = ret;
+ remain--;
+ }
+
+ /* Wait for the last transmission */
+ rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
+
+ return 0;
+}
+
+static int rspi_rz_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+
+ return rspi_rz_transfer_out_in(rspi, xfer);
+}
+
+static int qspi_transfer_out_in(struct rspi_data *rspi,
+ struct spi_transfer *xfer)
+{
+ int remain = xfer->len, ret;
+ const u8 *tx_buf = xfer->tx_buf;
+ u8 *rx_buf = xfer->rx_buf;
+ u8 data;
- mesg->status = 0;
- mesg->complete(mesg->context);
+ qspi_receive_init(rspi);
+
+ while (remain > 0) {
+ data = tx_buf ? *tx_buf++ : DUMMY_DATA;
+ ret = rspi_data_out_in(rspi, data);
+ if (ret < 0)
+ return ret;
+ if (rx_buf)
+ *rx_buf++ = ret;
+ remain--;
+ }
+
+ /* Wait for the last transmission */
+ rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
+
+ return 0;
+}
+
+static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer)
+{
+ const u8 *buf = xfer->tx_buf;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < xfer->len; i++) {
+ ret = rspi_data_out(rspi, *buf++);
+ if (ret < 0)
+ return ret;
}
- return;
+ /* Wait for the last transmission */
+ rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
-error:
- mesg->status = ret;
- mesg->complete(mesg->context);
+ return 0;
+}
+
+static int qspi_transfer_in(struct rspi_data *rspi, struct spi_transfer *xfer)
+{
+ u8 *buf = xfer->rx_buf;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < xfer->len; i++) {
+ ret = rspi_data_in(rspi);
+ if (ret < 0)
+ return ret;
+ *buf++ = ret;
+ }
+
+ return 0;
+}
+
+static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+
+ if (spi->mode & SPI_LOOP) {
+ return qspi_transfer_out_in(rspi, xfer);
+ } else if (xfer->tx_buf && xfer->tx_nbits > SPI_NBITS_SINGLE) {
+ /* Quad or Dual SPI Write */
+ return qspi_transfer_out(rspi, xfer);
+ } else if (xfer->rx_buf && xfer->rx_nbits > SPI_NBITS_SINGLE) {
+ /* Quad or Dual SPI Read */
+ return qspi_transfer_in(rspi, xfer);
+ } else {
+ /* Single SPI Transfer */
+ return qspi_transfer_out_in(rspi, xfer);
+ }
}
static int rspi_setup(struct spi_device *spi)
@@ -810,32 +886,115 @@ static int rspi_setup(struct spi_device *spi)
if (spi->mode & SPI_CPHA)
rspi->spcmd |= SPCMD_CPHA;
+ /* CMOS output mode and MOSI signal from previous transfer */
+ rspi->sppcr = 0;
+ if (spi->mode & SPI_LOOP)
+ rspi->sppcr |= SPPCR_SPLP;
+
set_config_register(rspi, 8);
return 0;
}
-static int rspi_transfer(struct spi_device *spi, struct spi_message *mesg)
+static u16 qspi_transfer_mode(const struct spi_transfer *xfer)
{
- struct rspi_data *rspi = spi_master_get_devdata(spi->master);
- unsigned long flags;
+ if (xfer->tx_buf)
+ switch (xfer->tx_nbits) {
+ case SPI_NBITS_QUAD:
+ return SPCMD_SPIMOD_QUAD;
+ case SPI_NBITS_DUAL:
+ return SPCMD_SPIMOD_DUAL;
+ default:
+ return 0;
+ }
+ if (xfer->rx_buf)
+ switch (xfer->rx_nbits) {
+ case SPI_NBITS_QUAD:
+ return SPCMD_SPIMOD_QUAD | SPCMD_SPRW;
+ case SPI_NBITS_DUAL:
+ return SPCMD_SPIMOD_DUAL | SPCMD_SPRW;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
- mesg->actual_length = 0;
- mesg->status = -EINPROGRESS;
+static int qspi_setup_sequencer(struct rspi_data *rspi,
+ const struct spi_message *msg)
+{
+ const struct spi_transfer *xfer;
+ unsigned int i = 0, len = 0;
+ u16 current_mode = 0xffff, mode;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ mode = qspi_transfer_mode(xfer);
+ if (mode == current_mode) {
+ len += xfer->len;
+ continue;
+ }
+
+ /* Transfer mode change */
+ if (i) {
+ /* Set transfer data length of previous transfer */
+ rspi_write32(rspi, len, QSPI_SPBMUL(i - 1));
+ }
- spin_lock_irqsave(&rspi->lock, flags);
- list_add_tail(&mesg->queue, &rspi->queue);
- schedule_work(&rspi->ws);
- spin_unlock_irqrestore(&rspi->lock, flags);
+ if (i >= QSPI_NUM_SPCMD) {
+ dev_err(&msg->spi->dev,
+ "Too many different transfer modes");
+ return -EINVAL;
+ }
+
+ /* Program transfer mode for this transfer */
+ rspi_write16(rspi, rspi->spcmd | mode, RSPI_SPCMD(i));
+ current_mode = mode;
+ len = xfer->len;
+ i++;
+ }
+ if (i) {
+ /* Set final transfer data length and sequence length */
+ rspi_write32(rspi, len, QSPI_SPBMUL(i - 1));
+ rspi_write8(rspi, i - 1, RSPI_SPSCR);
+ }
return 0;
}
-static void rspi_cleanup(struct spi_device *spi)
+static int rspi_prepare_message(struct spi_master *master,
+ struct spi_message *msg)
{
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+ int ret;
+
+ if (msg->spi->mode &
+ (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)) {
+ /* Setup sequencer for messages with multiple transfer modes */
+ ret = qspi_setup_sequencer(rspi, msg);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Enable SPI function in master mode */
+ rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR);
+ return 0;
}
-static irqreturn_t rspi_irq(int irq, void *_sr)
+static int rspi_unprepare_message(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+
+ /* Disable SPI function */
+ rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR);
+
+ /* Reset sequencer for Single SPI Transfers */
+ rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
+ rspi_write8(rspi, 0, RSPI_SPSCR);
+ return 0;
+}
+
+static irqreturn_t rspi_irq_mux(int irq, void *_sr)
{
struct rspi_data *rspi = _sr;
u8 spsr;
@@ -857,6 +1016,36 @@ static irqreturn_t rspi_irq(int irq, void *_sr)
return ret;
}
+static irqreturn_t rspi_irq_rx(int irq, void *_sr)
+{
+ struct rspi_data *rspi = _sr;
+ u8 spsr;
+
+ rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR);
+ if (spsr & SPSR_SPRF) {
+ rspi_disable_irq(rspi, SPCR_SPRIE);
+ wake_up(&rspi->wait);
+ return IRQ_HANDLED;
+ }
+
+ return 0;
+}
+
+static irqreturn_t rspi_irq_tx(int irq, void *_sr)
+{
+ struct rspi_data *rspi = _sr;
+ u8 spsr;
+
+ rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR);
+ if (spsr & SPSR_SPTEF) {
+ rspi_disable_irq(rspi, SPCR_SPTIE);
+ wake_up(&rspi->wait);
+ return IRQ_HANDLED;
+ }
+
+ return 0;
+}
+
static int rspi_request_dma(struct rspi_data *rspi,
struct platform_device *pdev)
{
@@ -923,34 +1112,89 @@ static int rspi_remove(struct platform_device *pdev)
struct rspi_data *rspi = platform_get_drvdata(pdev);
rspi_release_dma(rspi);
- clk_disable(rspi->clk);
+ pm_runtime_disable(&pdev->dev);
return 0;
}
+static const struct spi_ops rspi_ops = {
+ .set_config_register = rspi_set_config_register,
+ .transfer_one = rspi_transfer_one,
+ .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP,
+};
+
+static const struct spi_ops rspi_rz_ops = {
+ .set_config_register = rspi_rz_set_config_register,
+ .transfer_one = rspi_rz_transfer_one,
+ .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP,
+};
+
+static const struct spi_ops qspi_ops = {
+ .set_config_register = qspi_set_config_register,
+ .transfer_one = qspi_transfer_one,
+ .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP |
+ SPI_TX_DUAL | SPI_TX_QUAD |
+ SPI_RX_DUAL | SPI_RX_QUAD,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id rspi_of_match[] = {
+ /* RSPI on legacy SH */
+ { .compatible = "renesas,rspi", .data = &rspi_ops },
+ /* RSPI on RZ/A1H */
+ { .compatible = "renesas,rspi-rz", .data = &rspi_rz_ops },
+ /* QSPI on R-Car Gen2 */
+ { .compatible = "renesas,qspi", .data = &qspi_ops },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, rspi_of_match);
+
+static int rspi_parse_dt(struct device *dev, struct spi_master *master)
+{
+ u32 num_cs;
+ int error;
+
+ /* Parse DT properties */
+ error = of_property_read_u32(dev->of_node, "num-cs", &num_cs);
+ if (error) {
+ dev_err(dev, "of_property_read_u32 num-cs failed %d\n", error);
+ return error;
+ }
+
+ master->num_chipselect = num_cs;
+ return 0;
+}
+#else
+#define rspi_of_match NULL
+static inline int rspi_parse_dt(struct device *dev, struct spi_master *master)
+{
+ return -EINVAL;
+}
+#endif /* CONFIG_OF */
+
+static int rspi_request_irq(struct device *dev, unsigned int irq,
+ irq_handler_t handler, const char *suffix,
+ void *dev_id)
+{
+ const char *base = dev_name(dev);
+ size_t len = strlen(base) + strlen(suffix) + 2;
+ char *name = devm_kzalloc(dev, len, GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+ snprintf(name, len, "%s:%s", base, suffix);
+ return devm_request_irq(dev, irq, handler, 0, name, dev_id);
+}
+
static int rspi_probe(struct platform_device *pdev)
{
struct resource *res;
struct spi_master *master;
struct rspi_data *rspi;
- int ret, irq;
- char clk_name[16];
- const struct rspi_plat_data *rspi_pd = dev_get_platdata(&pdev->dev);
+ int ret;
+ const struct of_device_id *of_id;
+ const struct rspi_plat_data *rspi_pd;
const struct spi_ops *ops;
- const struct platform_device_id *id_entry = pdev->id_entry;
-
- ops = (struct spi_ops *)id_entry->driver_data;
- /* ops parameter check */
- if (!ops->set_config_register) {
- dev_err(&pdev->dev, "there is no set_config_register\n");
- return -ENODEV;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "platform_get_irq error\n");
- return -ENODEV;
- }
master = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data));
if (master == NULL) {
@@ -958,6 +1202,28 @@ static int rspi_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ of_id = of_match_device(rspi_of_match, &pdev->dev);
+ if (of_id) {
+ ops = of_id->data;
+ ret = rspi_parse_dt(&pdev->dev, master);
+ if (ret)
+ goto error1;
+ } else {
+ ops = (struct spi_ops *)pdev->id_entry->driver_data;
+ rspi_pd = dev_get_platdata(&pdev->dev);
+ if (rspi_pd && rspi_pd->num_chipselect)
+ master->num_chipselect = rspi_pd->num_chipselect;
+ else
+ master->num_chipselect = 2; /* default */
+ };
+
+ /* ops parameter check */
+ if (!ops->set_config_register) {
+ dev_err(&pdev->dev, "there is no set_config_register\n");
+ ret = -ENODEV;
+ goto error1;
+ }
+
rspi = spi_master_get_devdata(master);
platform_set_drvdata(pdev, rspi);
rspi->ops = ops;
@@ -970,39 +1236,61 @@ static int rspi_probe(struct platform_device *pdev)
goto error1;
}
- snprintf(clk_name, sizeof(clk_name), "%s%d", id_entry->name, pdev->id);
- rspi->clk = devm_clk_get(&pdev->dev, clk_name);
+ rspi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(rspi->clk)) {
dev_err(&pdev->dev, "cannot get clock\n");
ret = PTR_ERR(rspi->clk);
goto error1;
}
- clk_enable(rspi->clk);
- INIT_LIST_HEAD(&rspi->queue);
- spin_lock_init(&rspi->lock);
- INIT_WORK(&rspi->ws, rspi_work);
- init_waitqueue_head(&rspi->wait);
+ pm_runtime_enable(&pdev->dev);
- if (rspi_pd && rspi_pd->num_chipselect)
- master->num_chipselect = rspi_pd->num_chipselect;
- else
- master->num_chipselect = 2; /* default */
+ init_waitqueue_head(&rspi->wait);
master->bus_num = pdev->id;
master->setup = rspi_setup;
- master->transfer = rspi_transfer;
- master->cleanup = rspi_cleanup;
- master->mode_bits = SPI_CPHA | SPI_CPOL;
+ master->auto_runtime_pm = true;
+ master->transfer_one = ops->transfer_one;
+ master->prepare_message = rspi_prepare_message;
+ master->unprepare_message = rspi_unprepare_message;
+ master->mode_bits = ops->mode_bits;
+ master->dev.of_node = pdev->dev.of_node;
+
+ ret = platform_get_irq_byname(pdev, "rx");
+ if (ret < 0) {
+ ret = platform_get_irq_byname(pdev, "mux");
+ if (ret < 0)
+ ret = platform_get_irq(pdev, 0);
+ if (ret >= 0)
+ rspi->rx_irq = rspi->tx_irq = ret;
+ } else {
+ rspi->rx_irq = ret;
+ ret = platform_get_irq_byname(pdev, "tx");
+ if (ret >= 0)
+ rspi->tx_irq = ret;
+ }
+ if (ret < 0) {
+ dev_err(&pdev->dev, "platform_get_irq error\n");
+ goto error2;
+ }
- ret = devm_request_irq(&pdev->dev, irq, rspi_irq, 0,
- dev_name(&pdev->dev), rspi);
+ if (rspi->rx_irq == rspi->tx_irq) {
+ /* Single multiplexed interrupt */
+ ret = rspi_request_irq(&pdev->dev, rspi->rx_irq, rspi_irq_mux,
+ "mux", rspi);
+ } else {
+ /* Multi-interrupt mode, only SPRI and SPTI are used */
+ ret = rspi_request_irq(&pdev->dev, rspi->rx_irq, rspi_irq_rx,
+ "rx", rspi);
+ if (!ret)
+ ret = rspi_request_irq(&pdev->dev, rspi->tx_irq,
+ rspi_irq_tx, "tx", rspi);
+ }
if (ret < 0) {
dev_err(&pdev->dev, "request_irq error\n");
goto error2;
}
- rspi->irq = irq;
ret = rspi_request_dma(rspi, pdev);
if (ret < 0) {
dev_err(&pdev->dev, "rspi_request_dma failed.\n");
@@ -1022,27 +1310,16 @@ static int rspi_probe(struct platform_device *pdev)
error3:
rspi_release_dma(rspi);
error2:
- clk_disable(rspi->clk);
+ pm_runtime_disable(&pdev->dev);
error1:
spi_master_put(master);
return ret;
}
-static struct spi_ops rspi_ops = {
- .set_config_register = rspi_set_config_register,
- .send_pio = rspi_send_pio,
- .receive_pio = rspi_receive_pio,
-};
-
-static struct spi_ops qspi_ops = {
- .set_config_register = qspi_set_config_register,
- .send_pio = qspi_send_pio,
- .receive_pio = qspi_receive_pio,
-};
-
static struct platform_device_id spi_driver_ids[] = {
{ "rspi", (kernel_ulong_t)&rspi_ops },
+ { "rspi-rz", (kernel_ulong_t)&rspi_rz_ops },
{ "qspi", (kernel_ulong_t)&qspi_ops },
{},
};
@@ -1056,6 +1333,7 @@ static struct platform_driver rspi_driver = {
.driver = {
.name = "renesas_spi",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(rspi_of_match),
},
};
module_platform_driver(rspi_driver);
diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c
index 746424aa5353..bed23384dfab 100644
--- a/drivers/spi/spi-s3c24xx.c
+++ b/drivers/spi/spi-s3c24xx.c
@@ -9,7 +9,6 @@
*
*/
-#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
@@ -123,25 +122,15 @@ static int s3c24xx_spi_update_state(struct spi_device *spi,
{
struct s3c24xx_spi *hw = to_hw(spi);
struct s3c24xx_spi_devstate *cs = spi->controller_state;
- unsigned int bpw;
unsigned int hz;
unsigned int div;
unsigned long clk;
- bpw = t ? t->bits_per_word : spi->bits_per_word;
hz = t ? t->speed_hz : spi->max_speed_hz;
- if (!bpw)
- bpw = 8;
-
if (!hz)
hz = spi->max_speed_hz;
- if (bpw != 8) {
- dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw);
- return -EINVAL;
- }
-
if (spi->mode != cs->mode) {
u8 spcon = SPCON_DEFAULT | S3C2410_SPCON_ENSCK;
@@ -544,6 +533,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev)
master->num_chipselect = hw->pdata->num_cs;
master->bus_num = pdata->bus_num;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
/* setup the state for the bitbang driver */
@@ -643,6 +633,11 @@ static int s3c24xx_spi_remove(struct platform_device *dev)
static int s3c24xx_spi_suspend(struct device *dev)
{
struct s3c24xx_spi *hw = dev_get_drvdata(dev);
+ int ret;
+
+ ret = spi_master_suspend(hw->master);
+ if (ret)
+ return ret;
if (hw->pdata && hw->pdata->gpio_setup)
hw->pdata->gpio_setup(hw->pdata, 0);
@@ -656,7 +651,7 @@ static int s3c24xx_spi_resume(struct device *dev)
struct s3c24xx_spi *hw = dev_get_drvdata(dev);
s3c24xx_spi_initialsetup(hw);
- return 0;
+ return spi_master_resume(hw->master);
}
static const struct dev_pm_ops s3c24xx_spi_pmops = {
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index ae907dde1371..f19cd97855e8 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -34,10 +34,6 @@
#include <linux/platform_data/spi-s3c64xx.h>
-#ifdef CONFIG_S3C_DMA
-#include <mach/dma.h>
-#endif
-
#define MAX_SPI_PORTS 3
#define S3C64XX_SPI_QUIRK_POLL (1 << 0)
@@ -200,9 +196,6 @@ struct s3c64xx_spi_driver_data {
unsigned cur_speed;
struct s3c64xx_spi_dma_data rx_dma;
struct s3c64xx_spi_dma_data tx_dma;
-#ifdef CONFIG_S3C_DMA
- struct samsung_dma_ops *ops;
-#endif
struct s3c64xx_spi_port_config *port_conf;
unsigned int port_id;
bool cs_gpio;
@@ -284,104 +277,8 @@ static void s3c64xx_spi_dmacb(void *data)
spin_unlock_irqrestore(&sdd->lock, flags);
}
-#ifdef CONFIG_S3C_DMA
-/* FIXME: remove this section once arch/arm/mach-s3c64xx uses dmaengine */
-
-static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
- .name = "samsung-spi-dma",
-};
-
-static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
- unsigned len, dma_addr_t buf)
-{
- struct s3c64xx_spi_driver_data *sdd;
- struct samsung_dma_prep info;
- struct samsung_dma_config config;
-
- if (dma->direction == DMA_DEV_TO_MEM) {
- sdd = container_of((void *)dma,
- struct s3c64xx_spi_driver_data, rx_dma);
- config.direction = sdd->rx_dma.direction;
- config.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
- config.width = sdd->cur_bpw / 8;
- sdd->ops->config((enum dma_ch)sdd->rx_dma.ch, &config);
- } else {
- sdd = container_of((void *)dma,
- struct s3c64xx_spi_driver_data, tx_dma);
- config.direction = sdd->tx_dma.direction;
- config.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
- config.width = sdd->cur_bpw / 8;
- sdd->ops->config((enum dma_ch)sdd->tx_dma.ch, &config);
- }
-
- info.cap = DMA_SLAVE;
- info.len = len;
- info.fp = s3c64xx_spi_dmacb;
- info.fp_param = dma;
- info.direction = dma->direction;
- info.buf = buf;
-
- sdd->ops->prepare((enum dma_ch)dma->ch, &info);
- sdd->ops->trigger((enum dma_ch)dma->ch);
-}
-
-static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
-{
- struct samsung_dma_req req;
- struct device *dev = &sdd->pdev->dev;
-
- sdd->ops = samsung_dma_get_ops();
-
- req.cap = DMA_SLAVE;
- req.client = &s3c64xx_spi_dma_client;
-
- 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;
-}
-
-static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
-{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
-
- /*
- * If DMA resource was not available during
- * probe, no need to continue with dma requests
- * else Acquire DMA channels
- */
- while (!is_polling(sdd) && !acquire_dma(sdd))
- usleep_range(10000, 11000);
-
- return 0;
-}
-
-static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
-{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
-
- /* Free DMA channels */
- if (!is_polling(sdd)) {
- sdd->ops->release((enum dma_ch)sdd->rx_dma.ch,
- &s3c64xx_spi_dma_client);
- sdd->ops->release((enum dma_ch)sdd->tx_dma.ch,
- &s3c64xx_spi_dma_client);
- }
-
- return 0;
-}
-
-static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd,
- struct s3c64xx_spi_dma_data *dma)
-{
- sdd->ops->stop((enum dma_ch)dma->ch);
-}
-#else
-
static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
- unsigned len, dma_addr_t buf)
+ struct sg_table *sgt)
{
struct s3c64xx_spi_driver_data *sdd;
struct dma_slave_config config;
@@ -407,8 +304,8 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
dmaengine_slave_config(dma->ch, &config);
}
- desc = dmaengine_prep_slave_single(dma->ch, buf, len,
- dma->direction, DMA_PREP_INTERRUPT);
+ desc = dmaengine_prep_slave_sg(dma->ch, sgt->sgl, sgt->nents,
+ dma->direction, DMA_PREP_INTERRUPT);
desc->callback = s3c64xx_spi_dmacb;
desc->callback_param = dma;
@@ -437,6 +334,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
ret = -EBUSY;
goto out;
}
+ spi->dma_rx = sdd->rx_dma.ch;
sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
(void *)sdd->tx_dma.dmach, dev, "tx");
@@ -445,6 +343,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
ret = -EBUSY;
goto out_rx;
}
+ spi->dma_tx = sdd->tx_dma.ch;
}
ret = pm_runtime_get_sync(&sdd->pdev->dev);
@@ -477,12 +376,14 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
return 0;
}
-static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd,
- struct s3c64xx_spi_dma_data *dma)
+static bool s3c64xx_spi_can_dma(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
{
- dmaengine_terminate_all(dma->ch);
+ struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+
+ return xfer->len > (FIFO_LVL_MASK(sdd) >> 1) + 1;
}
-#endif
static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
struct spi_device *spi,
@@ -515,7 +416,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
chcfg |= S3C64XX_SPI_CH_TXCH_ON;
if (dma_mode) {
modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
- prepare_dma(&sdd->tx_dma, xfer->len, xfer->tx_dma);
+ prepare_dma(&sdd->tx_dma, &xfer->tx_sg);
} else {
switch (sdd->cur_bpw) {
case 32:
@@ -547,7 +448,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
| S3C64XX_SPI_PACKET_CNT_EN,
regs + S3C64XX_SPI_PACKET_CNT);
- prepare_dma(&sdd->rx_dma, xfer->len, xfer->rx_dma);
+ prepare_dma(&sdd->rx_dma, &xfer->rx_sg);
}
}
@@ -555,23 +456,6 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
writel(chcfg, regs + S3C64XX_SPI_CH_CFG);
}
-static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd,
- struct spi_device *spi)
-{
- if (sdd->tgl_spi != NULL) { /* If last device toggled after mssg */
- if (sdd->tgl_spi != spi) { /* if last mssg on diff device */
- /* Deselect the last toggled device */
- if (spi->cs_gpio >= 0)
- gpio_set_value(spi->cs_gpio,
- spi->mode & SPI_CS_HIGH ? 0 : 1);
- }
- sdd->tgl_spi = NULL;
- }
-
- if (spi->cs_gpio >= 0)
- gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 1 : 0);
-}
-
static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd,
int timeout_ms)
{
@@ -593,112 +477,111 @@ static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd,
return RX_FIFO_LVL(status, sdd);
}
-static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
- struct spi_transfer *xfer, int dma_mode)
+static int wait_for_dma(struct s3c64xx_spi_driver_data *sdd,
+ struct spi_transfer *xfer)
{
void __iomem *regs = sdd->regs;
unsigned long val;
+ u32 status;
int ms;
/* millisecs to xfer 'len' bytes @ 'cur_speed' */
ms = xfer->len * 8 * 1000 / sdd->cur_speed;
ms += 10; /* some tolerance */
- if (dma_mode) {
- val = msecs_to_jiffies(ms) + 10;
- val = wait_for_completion_timeout(&sdd->xfer_completion, val);
- } else {
- u32 status;
- val = msecs_to_loops(ms);
- do {
+ val = msecs_to_jiffies(ms) + 10;
+ val = wait_for_completion_timeout(&sdd->xfer_completion, val);
+
+ /*
+ * If the previous xfer was completed within timeout, then
+ * proceed further else return -EIO.
+ * DmaTx returns after simply writing data in the FIFO,
+ * w/o waiting for real transmission on the bus to finish.
+ * DmaRx returns only after Dma read data from FIFO which
+ * needs bus transmission to finish, so we don't worry if
+ * Xfer involved Rx(with or without Tx).
+ */
+ if (val && !xfer->rx_buf) {
+ val = msecs_to_loops(10);
+ status = readl(regs + S3C64XX_SPI_STATUS);
+ while ((TX_FIFO_LVL(status, sdd)
+ || !S3C64XX_SPI_ST_TX_DONE(status, sdd))
+ && --val) {
+ cpu_relax();
status = readl(regs + S3C64XX_SPI_STATUS);
- } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val);
+ }
+
}
- if (dma_mode) {
- u32 status;
-
- /*
- * If the previous xfer was completed within timeout, then
- * proceed further else return -EIO.
- * DmaTx returns after simply writing data in the FIFO,
- * w/o waiting for real transmission on the bus to finish.
- * DmaRx returns only after Dma read data from FIFO which
- * needs bus transmission to finish, so we don't worry if
- * Xfer involved Rx(with or without Tx).
- */
- if (val && !xfer->rx_buf) {
- val = msecs_to_loops(10);
- status = readl(regs + S3C64XX_SPI_STATUS);
- while ((TX_FIFO_LVL(status, sdd)
- || !S3C64XX_SPI_ST_TX_DONE(status, sdd))
- && --val) {
- cpu_relax();
- status = readl(regs + S3C64XX_SPI_STATUS);
- }
+ /* If timed out while checking rx/tx status return error */
+ if (!val)
+ return -EIO;
- }
+ return 0;
+}
- /* If timed out while checking rx/tx status return error */
- if (!val)
- return -EIO;
- } else {
- int loops;
- u32 cpy_len;
- u8 *buf;
-
- /* If it was only Tx */
- if (!xfer->rx_buf) {
- sdd->state &= ~TXBUSY;
- return 0;
- }
+static int wait_for_pio(struct s3c64xx_spi_driver_data *sdd,
+ struct spi_transfer *xfer)
+{
+ void __iomem *regs = sdd->regs;
+ unsigned long val;
+ u32 status;
+ int loops;
+ u32 cpy_len;
+ u8 *buf;
+ int ms;
- /*
- * If the receive length is bigger than the controller fifo
- * size, calculate the loops and read the fifo as many times.
- * loops = length / max fifo size (calculated by using the
- * fifo mask).
- * For any size less than the fifo size the below code is
- * executed atleast once.
- */
- loops = xfer->len / ((FIFO_LVL_MASK(sdd) >> 1) + 1);
- buf = xfer->rx_buf;
- do {
- /* wait for data to be received in the fifo */
- cpy_len = s3c64xx_spi_wait_for_timeout(sdd,
- (loops ? ms : 0));
+ /* millisecs to xfer 'len' bytes @ 'cur_speed' */
+ ms = xfer->len * 8 * 1000 / sdd->cur_speed;
+ ms += 10; /* some tolerance */
- switch (sdd->cur_bpw) {
- case 32:
- ioread32_rep(regs + S3C64XX_SPI_RX_DATA,
- buf, cpy_len / 4);
- break;
- case 16:
- ioread16_rep(regs + S3C64XX_SPI_RX_DATA,
- buf, cpy_len / 2);
- break;
- default:
- ioread8_rep(regs + S3C64XX_SPI_RX_DATA,
- buf, cpy_len);
- break;
- }
+ val = msecs_to_loops(ms);
+ do {
+ status = readl(regs + S3C64XX_SPI_STATUS);
+ } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val);
- buf = buf + cpy_len;
- } while (loops--);
- sdd->state &= ~RXBUSY;
+
+ /* If it was only Tx */
+ if (!xfer->rx_buf) {
+ sdd->state &= ~TXBUSY;
+ return 0;
}
- return 0;
-}
+ /*
+ * If the receive length is bigger than the controller fifo
+ * size, calculate the loops and read the fifo as many times.
+ * loops = length / max fifo size (calculated by using the
+ * fifo mask).
+ * For any size less than the fifo size the below code is
+ * executed atleast once.
+ */
+ loops = xfer->len / ((FIFO_LVL_MASK(sdd) >> 1) + 1);
+ buf = xfer->rx_buf;
+ do {
+ /* wait for data to be received in the fifo */
+ cpy_len = s3c64xx_spi_wait_for_timeout(sdd,
+ (loops ? ms : 0));
+
+ switch (sdd->cur_bpw) {
+ case 32:
+ ioread32_rep(regs + S3C64XX_SPI_RX_DATA,
+ buf, cpy_len / 4);
+ break;
+ case 16:
+ ioread16_rep(regs + S3C64XX_SPI_RX_DATA,
+ buf, cpy_len / 2);
+ break;
+ default:
+ ioread8_rep(regs + S3C64XX_SPI_RX_DATA,
+ buf, cpy_len);
+ break;
+ }
-static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
- struct spi_device *spi)
-{
- if (sdd->tgl_spi == spi)
- sdd->tgl_spi = NULL;
+ buf = buf + cpy_len;
+ } while (loops--);
+ sdd->state &= ~RXBUSY;
- if (spi->cs_gpio >= 0)
- gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 0 : 1);
+ return 0;
}
static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
@@ -774,81 +657,6 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
#define XFER_DMAADDR_INVALID DMA_BIT_MASK(32)
-static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
- struct spi_message *msg)
-{
- struct device *dev = &sdd->pdev->dev;
- struct spi_transfer *xfer;
-
- if (is_polling(sdd) || msg->is_dma_mapped)
- return 0;
-
- /* First mark all xfer unmapped */
- list_for_each_entry(xfer, &msg->transfers, transfer_list) {
- xfer->rx_dma = XFER_DMAADDR_INVALID;
- xfer->tx_dma = XFER_DMAADDR_INVALID;
- }
-
- /* Map until end or first fail */
- list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-
- if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1))
- continue;
-
- if (xfer->tx_buf != NULL) {
- xfer->tx_dma = dma_map_single(dev,
- (void *)xfer->tx_buf, xfer->len,
- DMA_TO_DEVICE);
- if (dma_mapping_error(dev, xfer->tx_dma)) {
- dev_err(dev, "dma_map_single Tx failed\n");
- xfer->tx_dma = XFER_DMAADDR_INVALID;
- return -ENOMEM;
- }
- }
-
- if (xfer->rx_buf != NULL) {
- xfer->rx_dma = dma_map_single(dev, xfer->rx_buf,
- xfer->len, DMA_FROM_DEVICE);
- if (dma_mapping_error(dev, xfer->rx_dma)) {
- dev_err(dev, "dma_map_single Rx failed\n");
- dma_unmap_single(dev, xfer->tx_dma,
- xfer->len, DMA_TO_DEVICE);
- xfer->tx_dma = XFER_DMAADDR_INVALID;
- xfer->rx_dma = XFER_DMAADDR_INVALID;
- return -ENOMEM;
- }
- }
- }
-
- return 0;
-}
-
-static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd,
- struct spi_message *msg)
-{
- struct device *dev = &sdd->pdev->dev;
- struct spi_transfer *xfer;
-
- if (is_polling(sdd) || msg->is_dma_mapped)
- return;
-
- list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-
- if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1))
- continue;
-
- if (xfer->rx_buf != NULL
- && xfer->rx_dma != XFER_DMAADDR_INVALID)
- dma_unmap_single(dev, xfer->rx_dma,
- xfer->len, DMA_FROM_DEVICE);
-
- if (xfer->tx_buf != NULL
- && xfer->tx_dma != XFER_DMAADDR_INVALID)
- dma_unmap_single(dev, xfer->tx_dma,
- xfer->len, DMA_TO_DEVICE);
- }
-}
-
static int s3c64xx_spi_prepare_message(struct spi_master *master,
struct spi_message *msg)
{
@@ -866,13 +674,6 @@ static int s3c64xx_spi_prepare_message(struct spi_master *master,
s3c64xx_spi_config(sdd);
}
- /* Map all the transfers if needed */
- if (s3c64xx_spi_map_mssg(sdd, msg)) {
- dev_err(&spi->dev,
- "Xfer: Unable to map message buffers!\n");
- return -ENOMEM;
- }
-
/* Configure feedback delay */
writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK);
@@ -896,13 +697,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
bpw = xfer->bits_per_word;
speed = xfer->speed_hz ? : spi->max_speed_hz;
- if (xfer->len % (bpw / 8)) {
- dev_err(&spi->dev,
- "Xfer length(%u) not a multiple of word size(%u)\n",
- xfer->len, bpw / 8);
- return -EIO;
- }
-
if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) {
sdd->cur_bpw = bpw;
sdd->cur_speed = speed;
@@ -929,7 +723,10 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
spin_unlock_irqrestore(&sdd->lock, flags);
- status = wait_for_xfer(sdd, xfer, use_dma);
+ if (use_dma)
+ status = wait_for_dma(sdd, xfer);
+ else
+ status = wait_for_pio(sdd, xfer);
if (status) {
dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
@@ -941,10 +738,10 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
if (use_dma) {
if (xfer->tx_buf != NULL
&& (sdd->state & TXBUSY))
- s3c64xx_spi_dma_stop(sdd, &sdd->tx_dma);
+ dmaengine_terminate_all(sdd->tx_dma.ch);
if (xfer->rx_buf != NULL
&& (sdd->state & RXBUSY))
- s3c64xx_spi_dma_stop(sdd, &sdd->rx_dma);
+ dmaengine_terminate_all(sdd->rx_dma.ch);
}
} else {
flush_fifo(sdd);
@@ -953,16 +750,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
return status;
}
-static int s3c64xx_spi_unprepare_message(struct spi_master *master,
- struct spi_message *msg)
-{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
-
- s3c64xx_spi_unmap_mssg(sdd, msg);
-
- return 0;
-}
-
static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
struct spi_device *spi)
{
@@ -1092,14 +879,12 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
pm_runtime_put(&sdd->pdev->dev);
writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
- disable_cs(sdd, spi);
return 0;
setup_exit:
pm_runtime_put(&sdd->pdev->dev);
/* setup() returns with device de-selected */
writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
- disable_cs(sdd, spi);
gpio_free(cs->line);
spi_set_ctldata(spi, NULL);
@@ -1338,7 +1123,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer;
master->prepare_message = s3c64xx_spi_prepare_message;
master->transfer_one = s3c64xx_spi_transfer_one;
- master->unprepare_message = s3c64xx_spi_unprepare_message;
master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
master->num_chipselect = sci->num_cs;
master->dma_alignment = 8;
@@ -1347,6 +1131,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->auto_runtime_pm = true;
+ if (!is_polling(sdd))
+ master->can_dma = s3c64xx_spi_can_dma;
sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res);
if (IS_ERR(sdd->regs)) {
diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c
index 121c2e1dea36..237f2e7a7179 100644
--- a/drivers/spi/spi-sc18is602.c
+++ b/drivers/spi/spi-sc18is602.c
@@ -183,17 +183,9 @@ static int sc18is602_setup_transfer(struct sc18is602 *hw, u32 hz, u8 mode)
static int sc18is602_check_transfer(struct spi_device *spi,
struct spi_transfer *t, int tlen)
{
- uint32_t hz;
-
if (t && t->len + tlen > SC18IS602_BUFSIZ)
return -EINVAL;
- hz = spi->max_speed_hz;
- if (t && t->speed_hz)
- hz = t->speed_hz;
- if (hz == 0)
- return -EINVAL;
-
return 0;
}
@@ -205,22 +197,15 @@ static int sc18is602_transfer_one(struct spi_master *master,
struct spi_transfer *t;
int status = 0;
- /* SC18IS602 does not support CS2 */
- if (hw->id == sc18is602 && spi->chip_select == 2) {
- status = -ENXIO;
- goto error;
- }
-
hw->tlen = 0;
list_for_each_entry(t, &m->transfers, transfer_list) {
- u32 hz = t->speed_hz ? : spi->max_speed_hz;
bool do_transfer;
status = sc18is602_check_transfer(spi, t, hw->tlen);
if (status < 0)
break;
- status = sc18is602_setup_transfer(hw, hz, spi->mode);
+ status = sc18is602_setup_transfer(hw, t->speed_hz, spi->mode);
if (status < 0)
break;
@@ -238,7 +223,6 @@ static int sc18is602_transfer_one(struct spi_master *master,
if (t->delay_usecs)
udelay(t->delay_usecs);
}
-error:
m->status = status;
spi_finalize_current_message(master);
@@ -247,10 +231,13 @@ error:
static int sc18is602_setup(struct spi_device *spi)
{
- if (spi->mode & ~(SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST))
- return -EINVAL;
+ struct sc18is602 *hw = spi_master_get_devdata(spi->master);
- return sc18is602_check_transfer(spi, NULL, 0);
+ /* SC18IS602 does not support CS2 */
+ if (hw->id == sc18is602 && spi->chip_select == 2)
+ return -ENXIO;
+
+ return 0;
}
static int sc18is602_probe(struct i2c_client *client,
@@ -309,6 +296,8 @@ static int sc18is602_probe(struct i2c_client *client,
master->setup = sc18is602_setup;
master->transfer_one_message = sc18is602_transfer_one;
master->dev.of_node = np;
+ master->min_speed_hz = hw->freq / 128;
+ master->max_speed_hz = hw->freq / 4;
error = devm_spi_register_master(dev, master);
if (error)
diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c
index 82d2f922ffa0..9009456bdf4d 100644
--- a/drivers/spi/spi-sh-hspi.c
+++ b/drivers/spi/spi-sh-hspi.c
@@ -46,8 +46,6 @@
/* SPSR */
#define RXFL (1 << 2)
-#define hspi2info(h) (h->dev->platform_data)
-
struct hspi_priv {
void __iomem *addr;
struct spi_master *master;
@@ -113,14 +111,9 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
{
struct spi_device *spi = msg->spi;
struct device *dev = hspi->dev;
- u32 target_rate;
u32 spcr, idiv_clk;
u32 rate, best_rate, min, tmp;
- target_rate = t ? t->speed_hz : 0;
- if (!target_rate)
- target_rate = spi->max_speed_hz;
-
/*
* find best IDIV/CLKCx settings
*/
@@ -140,7 +133,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
rate /= (((idiv_clk & 0x1F) + 1) * 2);
/* save best settings */
- tmp = abs(target_rate - rate);
+ tmp = abs(t->speed_hz - rate);
if (tmp < min) {
min = tmp;
spcr = idiv_clk;
@@ -153,7 +146,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
if (spi->mode & SPI_CPOL)
spcr |= 1 << 6;
- dev_dbg(dev, "speed %d/%d\n", target_rate, best_rate);
+ dev_dbg(dev, "speed %d/%d\n", t->speed_hz, best_rate);
hspi_write(hspi, SPCR, spcr);
hspi_write(hspi, SPSR, 0x0);
@@ -230,29 +223,6 @@ static int hspi_transfer_one_message(struct spi_master *master,
return ret;
}
-static int hspi_setup(struct spi_device *spi)
-{
- struct hspi_priv *hspi = spi_master_get_devdata(spi->master);
- struct device *dev = hspi->dev;
-
- if (8 != spi->bits_per_word) {
- dev_err(dev, "bits_per_word should be 8\n");
- return -EIO;
- }
-
- dev_dbg(dev, "%s setup\n", spi->modalias);
-
- return 0;
-}
-
-static void hspi_cleanup(struct spi_device *spi)
-{
- struct hspi_priv *hspi = spi_master_get_devdata(spi->master);
- struct device *dev = hspi->dev;
-
- dev_dbg(dev, "%s cleanup\n", spi->modalias);
-}
-
static int hspi_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -298,22 +268,23 @@ static int hspi_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
- master->num_chipselect = 1;
master->bus_num = pdev->id;
- master->setup = hspi_setup;
- master->cleanup = hspi_cleanup;
master->mode_bits = SPI_CPOL | SPI_CPHA;
master->dev.of_node = pdev->dev.of_node;
master->auto_runtime_pm = true;
master->transfer_one_message = hspi_transfer_one_message;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+
ret = devm_spi_register_master(&pdev->dev, master);
if (ret < 0) {
dev_err(&pdev->dev, "spi_register_master error.\n");
- goto error1;
+ goto error2;
}
return 0;
+ error2:
+ pm_runtime_disable(&pdev->dev);
error1:
clk_put(clk);
error0:
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index 81cc02f5f9b0..e850d03e7190 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -15,59 +15,108 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spi/sh_msiof.h>
#include <linux/spi/spi.h>
-#include <linux/spi/spi_bitbang.h>
#include <asm/unaligned.h>
+
+struct sh_msiof_chipdata {
+ u16 tx_fifo_size;
+ u16 rx_fifo_size;
+ u16 master_flags;
+};
+
struct sh_msiof_spi_priv {
- struct spi_bitbang bitbang; /* must be first for spi_bitbang.c */
void __iomem *mapbase;
struct clk *clk;
struct platform_device *pdev;
+ const struct sh_msiof_chipdata *chipdata;
struct sh_msiof_spi_info *info;
struct completion done;
- unsigned long flags;
int tx_fifo_size;
int rx_fifo_size;
};
-#define TMDR1 0x00
-#define TMDR2 0x04
-#define TMDR3 0x08
-#define RMDR1 0x10
-#define RMDR2 0x14
-#define RMDR3 0x18
-#define TSCR 0x20
-#define RSCR 0x22
-#define CTR 0x28
-#define FCTR 0x30
-#define STR 0x40
-#define IER 0x44
-#define TDR1 0x48
-#define TDR2 0x4c
-#define TFDR 0x50
-#define RDR1 0x58
-#define RDR2 0x5c
-#define RFDR 0x60
-
-#define CTR_TSCKE (1 << 15)
-#define CTR_TFSE (1 << 14)
-#define CTR_TXE (1 << 9)
-#define CTR_RXE (1 << 8)
-
-#define STR_TEOF (1 << 23)
-#define STR_REOF (1 << 7)
+#define TMDR1 0x00 /* Transmit Mode Register 1 */
+#define TMDR2 0x04 /* Transmit Mode Register 2 */
+#define TMDR3 0x08 /* Transmit Mode Register 3 */
+#define RMDR1 0x10 /* Receive Mode Register 1 */
+#define RMDR2 0x14 /* Receive Mode Register 2 */
+#define RMDR3 0x18 /* Receive Mode Register 3 */
+#define TSCR 0x20 /* Transmit Clock Select Register */
+#define RSCR 0x22 /* Receive Clock Select Register (SH, A1, APE6) */
+#define CTR 0x28 /* Control Register */
+#define FCTR 0x30 /* FIFO Control Register */
+#define STR 0x40 /* Status Register */
+#define IER 0x44 /* Interrupt Enable Register */
+#define TDR1 0x48 /* Transmit Control Data Register 1 (SH, A1) */
+#define TDR2 0x4c /* Transmit Control Data Register 2 (SH, A1) */
+#define TFDR 0x50 /* Transmit FIFO Data Register */
+#define RDR1 0x58 /* Receive Control Data Register 1 (SH, A1) */
+#define RDR2 0x5c /* Receive Control Data Register 2 (SH, A1) */
+#define RFDR 0x60 /* Receive FIFO Data Register */
+
+/* TMDR1 and RMDR1 */
+#define MDR1_TRMD 0x80000000 /* Transfer Mode (1 = Master mode) */
+#define MDR1_SYNCMD_MASK 0x30000000 /* SYNC Mode */
+#define MDR1_SYNCMD_SPI 0x20000000 /* Level mode/SPI */
+#define MDR1_SYNCMD_LR 0x30000000 /* L/R mode */
+#define MDR1_SYNCAC_SHIFT 25 /* Sync Polarity (1 = Active-low) */
+#define MDR1_BITLSB_SHIFT 24 /* MSB/LSB First (1 = LSB first) */
+#define MDR1_FLD_MASK 0x000000c0 /* Frame Sync Signal Interval (0-3) */
+#define MDR1_FLD_SHIFT 2
+#define MDR1_XXSTP 0x00000001 /* Transmission/Reception Stop on FIFO */
+/* TMDR1 */
+#define TMDR1_PCON 0x40000000 /* Transfer Signal Connection */
+
+/* TMDR2 and RMDR2 */
+#define MDR2_BITLEN1(i) (((i) - 1) << 24) /* Data Size (8-32 bits) */
+#define MDR2_WDLEN1(i) (((i) - 1) << 16) /* Word Count (1-64/256 (SH, A1))) */
+#define MDR2_GRPMASK1 0x00000001 /* Group Output Mask 1 (SH, A1) */
+
+/* TSCR and RSCR */
+#define SCR_BRPS_MASK 0x1f00 /* Prescaler Setting (1-32) */
+#define SCR_BRPS(i) (((i) - 1) << 8)
+#define SCR_BRDV_MASK 0x0007 /* Baud Rate Generator's Division Ratio */
+#define SCR_BRDV_DIV_2 0x0000
+#define SCR_BRDV_DIV_4 0x0001
+#define SCR_BRDV_DIV_8 0x0002
+#define SCR_BRDV_DIV_16 0x0003
+#define SCR_BRDV_DIV_32 0x0004
+#define SCR_BRDV_DIV_1 0x0007
+
+/* CTR */
+#define CTR_TSCKIZ_MASK 0xc0000000 /* Transmit Clock I/O Polarity Select */
+#define CTR_TSCKIZ_SCK 0x80000000 /* Disable SCK when TX disabled */
+#define CTR_TSCKIZ_POL_SHIFT 30 /* Transmit Clock Polarity */
+#define CTR_RSCKIZ_MASK 0x30000000 /* Receive Clock Polarity Select */
+#define CTR_RSCKIZ_SCK 0x20000000 /* Must match CTR_TSCKIZ_SCK */
+#define CTR_RSCKIZ_POL_SHIFT 28 /* Receive Clock Polarity */
+#define CTR_TEDG_SHIFT 27 /* Transmit Timing (1 = falling edge) */
+#define CTR_REDG_SHIFT 26 /* Receive Timing (1 = falling edge) */
+#define CTR_TXDIZ_MASK 0x00c00000 /* Pin Output When TX is Disabled */
+#define CTR_TXDIZ_LOW 0x00000000 /* 0 */
+#define CTR_TXDIZ_HIGH 0x00400000 /* 1 */
+#define CTR_TXDIZ_HIZ 0x00800000 /* High-impedance */
+#define CTR_TSCKE 0x00008000 /* Transmit Serial Clock Output Enable */
+#define CTR_TFSE 0x00004000 /* Transmit Frame Sync Signal Output Enable */
+#define CTR_TXE 0x00000200 /* Transmit Enable */
+#define CTR_RXE 0x00000100 /* Receive Enable */
+
+/* STR and IER */
+#define STR_TEOF 0x00800000 /* Frame Transmission End */
+#define STR_REOF 0x00000080 /* Frame Reception End */
+
static u32 sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs)
{
@@ -131,22 +180,21 @@ static struct {
unsigned short div;
unsigned short scr;
} const sh_msiof_spi_clk_table[] = {
- { 1, 0x0007 },
- { 2, 0x0000 },
- { 4, 0x0001 },
- { 8, 0x0002 },
- { 16, 0x0003 },
- { 32, 0x0004 },
- { 64, 0x1f00 },
- { 128, 0x1f01 },
- { 256, 0x1f02 },
- { 512, 0x1f03 },
- { 1024, 0x1f04 },
+ { 1, SCR_BRPS( 1) | SCR_BRDV_DIV_1 },
+ { 2, SCR_BRPS( 1) | SCR_BRDV_DIV_2 },
+ { 4, SCR_BRPS( 1) | SCR_BRDV_DIV_4 },
+ { 8, SCR_BRPS( 1) | SCR_BRDV_DIV_8 },
+ { 16, SCR_BRPS( 1) | SCR_BRDV_DIV_16 },
+ { 32, SCR_BRPS( 1) | SCR_BRDV_DIV_32 },
+ { 64, SCR_BRPS(32) | SCR_BRDV_DIV_2 },
+ { 128, SCR_BRPS(32) | SCR_BRDV_DIV_4 },
+ { 256, SCR_BRPS(32) | SCR_BRDV_DIV_8 },
+ { 512, SCR_BRPS(32) | SCR_BRDV_DIV_16 },
+ { 1024, SCR_BRPS(32) | SCR_BRDV_DIV_32 },
};
static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
- unsigned long parent_rate,
- unsigned long spi_hz)
+ unsigned long parent_rate, u32 spi_hz)
{
unsigned long div = 1024;
size_t k;
@@ -164,7 +212,8 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_clk_table) - 1);
sh_msiof_write(p, TSCR, sh_msiof_spi_clk_table[k].scr);
- sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr);
+ if (!(p->chipdata->master_flags & SPI_MASTER_MUST_TX))
+ sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr);
}
static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
@@ -183,21 +232,25 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
*/
sh_msiof_write(p, FCTR, 0);
- tmp = 0;
- tmp |= !cs_high << 25;
- tmp |= lsb_first << 24;
- sh_msiof_write(p, TMDR1, 0xe0000005 | tmp);
- sh_msiof_write(p, RMDR1, 0x20000005 | tmp);
+ tmp = MDR1_SYNCMD_SPI | 1 << MDR1_FLD_SHIFT | MDR1_XXSTP;
+ tmp |= !cs_high << MDR1_SYNCAC_SHIFT;
+ tmp |= lsb_first << MDR1_BITLSB_SHIFT;
+ sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON);
+ if (p->chipdata->master_flags & SPI_MASTER_MUST_TX) {
+ /* These bits are reserved if RX needs TX */
+ tmp &= ~0x0000ffff;
+ }
+ sh_msiof_write(p, RMDR1, tmp);
- tmp = 0xa0000000;
- tmp |= cpol << 30; /* TSCKIZ */
- tmp |= cpol << 28; /* RSCKIZ */
+ tmp = 0;
+ tmp |= CTR_TSCKIZ_SCK | cpol << CTR_TSCKIZ_POL_SHIFT;
+ tmp |= CTR_RSCKIZ_SCK | cpol << CTR_RSCKIZ_POL_SHIFT;
edge = cpol ^ !cpha;
- tmp |= edge << 27; /* TEDG */
- tmp |= edge << 26; /* REDG */
- tmp |= (tx_hi_z ? 2 : 0) << 22; /* TXDIZ */
+ tmp |= edge << CTR_TEDG_SHIFT;
+ tmp |= edge << CTR_REDG_SHIFT;
+ tmp |= tx_hi_z ? CTR_TXDIZ_HIZ : CTR_TXDIZ_LOW;
sh_msiof_write(p, CTR, tmp);
}
@@ -205,12 +258,12 @@ static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p,
const void *tx_buf, void *rx_buf,
u32 bits, u32 words)
{
- u32 dr2 = ((bits - 1) << 24) | ((words - 1) << 16);
+ u32 dr2 = MDR2_BITLEN1(bits) | MDR2_WDLEN1(words);
- if (tx_buf)
+ if (tx_buf || (p->chipdata->master_flags & SPI_MASTER_MUST_TX))
sh_msiof_write(p, TMDR2, dr2);
else
- sh_msiof_write(p, TMDR2, dr2 | 1);
+ sh_msiof_write(p, TMDR2, dr2 | MDR2_GRPMASK1);
if (rx_buf)
sh_msiof_write(p, RMDR2, dr2);
@@ -363,77 +416,45 @@ static void sh_msiof_spi_read_fifo_s32u(struct sh_msiof_spi_priv *p,
put_unaligned(swab32(sh_msiof_read(p, RFDR) >> fs), &buf_32[k]);
}
-static int sh_msiof_spi_bits(struct spi_device *spi, struct spi_transfer *t)
+static int sh_msiof_spi_setup(struct spi_device *spi)
{
- int bits;
-
- bits = t ? t->bits_per_word : 0;
- if (!bits)
- bits = spi->bits_per_word;
- return bits;
-}
-
-static unsigned long sh_msiof_spi_hz(struct spi_device *spi,
- struct spi_transfer *t)
-{
- unsigned long hz;
-
- hz = t ? t->speed_hz : 0;
- if (!hz)
- hz = spi->max_speed_hz;
- return hz;
-}
+ struct device_node *np = spi->master->dev.of_node;
+ struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
-static int sh_msiof_spi_setup_transfer(struct spi_device *spi,
- struct spi_transfer *t)
-{
- int bits;
+ if (!np) {
+ /*
+ * Use spi->controller_data for CS (same strategy as spi_gpio),
+ * if any. otherwise let HW control CS
+ */
+ spi->cs_gpio = (uintptr_t)spi->controller_data;
+ }
- /* noting to check hz values against since parent clock is disabled */
+ /* Configure pins before deasserting CS */
+ sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
+ !!(spi->mode & SPI_CPHA),
+ !!(spi->mode & SPI_3WIRE),
+ !!(spi->mode & SPI_LSB_FIRST),
+ !!(spi->mode & SPI_CS_HIGH));
- bits = sh_msiof_spi_bits(spi, t);
- if (bits < 8)
- return -EINVAL;
- if (bits > 32)
- return -EINVAL;
+ if (spi->cs_gpio >= 0)
+ gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
- return spi_bitbang_setup_transfer(spi, t);
+ return 0;
}
-static void sh_msiof_spi_chipselect(struct spi_device *spi, int is_on)
+static int sh_msiof_prepare_message(struct spi_master *master,
+ struct spi_message *msg)
{
- struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
- int value;
-
- /* chip select is active low unless SPI_CS_HIGH is set */
- if (spi->mode & SPI_CS_HIGH)
- value = (is_on == BITBANG_CS_ACTIVE) ? 1 : 0;
- else
- value = (is_on == BITBANG_CS_ACTIVE) ? 0 : 1;
-
- if (is_on == BITBANG_CS_ACTIVE) {
- if (!test_and_set_bit(0, &p->flags)) {
- pm_runtime_get_sync(&p->pdev->dev);
- clk_enable(p->clk);
- }
-
- /* Configure pins before asserting CS */
- sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
- !!(spi->mode & SPI_CPHA),
- !!(spi->mode & SPI_3WIRE),
- !!(spi->mode & SPI_LSB_FIRST),
- !!(spi->mode & SPI_CS_HIGH));
- }
+ struct sh_msiof_spi_priv *p = spi_master_get_devdata(master);
+ const struct spi_device *spi = msg->spi;
- /* use spi->controller data for CS (same strategy as spi_gpio) */
- gpio_set_value((uintptr_t)spi->controller_data, value);
-
- if (is_on == BITBANG_CS_INACTIVE) {
- if (test_and_clear_bit(0, &p->flags)) {
- clk_disable(p->clk);
- pm_runtime_put(&p->pdev->dev);
- }
- }
+ /* Configure pins before asserting CS */
+ sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
+ !!(spi->mode & SPI_CPHA),
+ !!(spi->mode & SPI_3WIRE),
+ !!(spi->mode & SPI_LSB_FIRST),
+ !!(spi->mode & SPI_CS_HIGH));
+ return 0;
}
static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
@@ -487,7 +508,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
/* clear status bits */
sh_msiof_reset_str(p);
- /* shut down frame, tx/tx and clock signals */
+ /* shut down frame, rx/tx and clock signals */
ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0);
ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_TXE, 0);
if (rx_buf)
@@ -505,9 +526,11 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
return ret;
}
-static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
+static int sh_msiof_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *t)
{
- struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
+ struct sh_msiof_spi_priv *p = spi_master_get_devdata(master);
void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int);
void (*rx_fifo)(struct sh_msiof_spi_priv *, void *, int, int);
int bits;
@@ -517,7 +540,7 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
int n;
bool swab;
- bits = sh_msiof_spi_bits(spi, t);
+ bits = t->bits_per_word;
if (bits <= 8 && t->len > 15 && !(t->len & 3)) {
bits = 32;
@@ -567,8 +590,7 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
}
/* setup clocks (clock already enabled in chipselect()) */
- sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk),
- sh_msiof_spi_hz(spi, t));
+ sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz);
/* transfer in fifo sized chunks */
words = t->len / bytes_per_word;
@@ -588,22 +610,36 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
words -= n;
}
- return bytes_done;
-}
-
-static u32 sh_msiof_spi_txrx_word(struct spi_device *spi, unsigned nsecs,
- u32 word, u8 bits)
-{
- BUG(); /* unused but needed by bitbang code */
return 0;
}
+static const struct sh_msiof_chipdata sh_data = {
+ .tx_fifo_size = 64,
+ .rx_fifo_size = 64,
+ .master_flags = 0,
+};
+
+static const struct sh_msiof_chipdata r8a779x_data = {
+ .tx_fifo_size = 64,
+ .rx_fifo_size = 256,
+ .master_flags = SPI_MASTER_MUST_TX,
+};
+
+static const struct of_device_id sh_msiof_match[] = {
+ { .compatible = "renesas,sh-msiof", .data = &sh_data },
+ { .compatible = "renesas,sh-mobile-msiof", .data = &sh_data },
+ { .compatible = "renesas,msiof-r8a7790", .data = &r8a779x_data },
+ { .compatible = "renesas,msiof-r8a7791", .data = &r8a779x_data },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sh_msiof_match);
+
#ifdef CONFIG_OF
static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
{
struct sh_msiof_spi_info *info;
struct device_node *np = dev->of_node;
- u32 num_cs = 0;
+ u32 num_cs = 1;
info = devm_kzalloc(dev, sizeof(struct sh_msiof_spi_info), GFP_KERNEL);
if (!info) {
@@ -633,6 +669,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
{
struct resource *r;
struct spi_master *master;
+ const struct of_device_id *of_id;
struct sh_msiof_spi_priv *p;
int i;
int ret;
@@ -646,10 +683,15 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
p = spi_master_get_devdata(master);
platform_set_drvdata(pdev, p);
- if (pdev->dev.of_node)
+
+ of_id = of_match_device(sh_msiof_match, &pdev->dev);
+ if (of_id) {
+ p->chipdata = of_id->data;
p->info = sh_msiof_spi_parse_dt(&pdev->dev);
- else
+ } else {
+ p->chipdata = (const void *)pdev->id_entry->driver_data;
p->info = dev_get_platdata(&pdev->dev);
+ }
if (!p->info) {
dev_err(&pdev->dev, "failed to obtain device info\n");
@@ -687,49 +729,40 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
goto err1;
}
- ret = clk_prepare(p->clk);
- if (ret < 0) {
- dev_err(&pdev->dev, "unable to prepare clock\n");
- goto err1;
- }
-
p->pdev = pdev;
pm_runtime_enable(&pdev->dev);
- /* The standard version of MSIOF use 64 word FIFOs */
- p->tx_fifo_size = 64;
- p->rx_fifo_size = 64;
-
/* Platform data may override FIFO sizes */
+ p->tx_fifo_size = p->chipdata->tx_fifo_size;
+ p->rx_fifo_size = p->chipdata->rx_fifo_size;
if (p->info->tx_fifo_override)
p->tx_fifo_size = p->info->tx_fifo_override;
if (p->info->rx_fifo_override)
p->rx_fifo_size = p->info->rx_fifo_override;
- /* init master and bitbang code */
+ /* init master code */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE;
- master->flags = 0;
+ master->flags = p->chipdata->master_flags;
master->bus_num = pdev->id;
+ master->dev.of_node = pdev->dev.of_node;
master->num_chipselect = p->info->num_chipselect;
- master->setup = spi_bitbang_setup;
- master->cleanup = spi_bitbang_cleanup;
-
- p->bitbang.master = master;
- p->bitbang.chipselect = sh_msiof_spi_chipselect;
- p->bitbang.setup_transfer = sh_msiof_spi_setup_transfer;
- p->bitbang.txrx_bufs = sh_msiof_spi_txrx;
- p->bitbang.txrx_word[SPI_MODE_0] = sh_msiof_spi_txrx_word;
- p->bitbang.txrx_word[SPI_MODE_1] = sh_msiof_spi_txrx_word;
- p->bitbang.txrx_word[SPI_MODE_2] = sh_msiof_spi_txrx_word;
- p->bitbang.txrx_word[SPI_MODE_3] = sh_msiof_spi_txrx_word;
-
- ret = spi_bitbang_start(&p->bitbang);
- if (ret == 0)
- return 0;
+ master->setup = sh_msiof_spi_setup;
+ master->prepare_message = sh_msiof_prepare_message;
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32);
+ master->auto_runtime_pm = true;
+ master->transfer_one = sh_msiof_transfer_one;
+
+ ret = devm_spi_register_master(&pdev->dev, master);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "spi_register_master error.\n");
+ goto err2;
+ }
+ return 0;
+
+ err2:
pm_runtime_disable(&pdev->dev);
- clk_unprepare(p->clk);
err1:
spi_master_put(master);
return ret;
@@ -737,30 +770,22 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
static int sh_msiof_spi_remove(struct platform_device *pdev)
{
- struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev);
- int ret;
-
- ret = spi_bitbang_stop(&p->bitbang);
- if (!ret) {
- pm_runtime_disable(&pdev->dev);
- clk_unprepare(p->clk);
- spi_master_put(p->bitbang.master);
- }
- return ret;
+ pm_runtime_disable(&pdev->dev);
+ return 0;
}
-#ifdef CONFIG_OF
-static const struct of_device_id sh_msiof_match[] = {
- { .compatible = "renesas,sh-msiof", },
- { .compatible = "renesas,sh-mobile-msiof", },
+static struct platform_device_id spi_driver_ids[] = {
+ { "spi_sh_msiof", (kernel_ulong_t)&sh_data },
+ { "spi_r8a7790_msiof", (kernel_ulong_t)&r8a779x_data },
+ { "spi_r8a7791_msiof", (kernel_ulong_t)&r8a779x_data },
{},
};
-MODULE_DEVICE_TABLE(of, sh_msiof_match);
-#endif
+MODULE_DEVICE_TABLE(platform, spi_driver_ids);
static struct platform_driver sh_msiof_spi_drv = {
.probe = sh_msiof_spi_probe,
.remove = sh_msiof_spi_remove,
+ .id_table = spi_driver_ids,
.driver = {
.name = "spi_sh_msiof",
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c
index 38eb24df796c..8b44b71f5024 100644
--- a/drivers/spi/spi-sh-sci.c
+++ b/drivers/spi/spi-sh-sci.c
@@ -14,7 +14,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
@@ -109,7 +108,7 @@ static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
{
struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
- if (sp->info && sp->info->chip_select)
+ if (sp->info->chip_select)
(sp->info->chip_select)(sp->info, dev->chip_select, value);
}
@@ -131,6 +130,11 @@ static int sh_sci_spi_probe(struct platform_device *dev)
platform_set_drvdata(dev, sp);
sp->info = dev_get_platdata(&dev->dev);
+ if (!sp->info) {
+ dev_err(&dev->dev, "platform data is missing\n");
+ ret = -ENOENT;
+ goto err1;
+ }
/* setup spi bitbang adaptor */
sp->bitbang.master = master;
diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c
index e430689c3837..1a77ad52812f 100644
--- a/drivers/spi/spi-sirf.c
+++ b/drivers/spi/spi-sirf.c
@@ -22,7 +22,6 @@
#include <linux/dmaengine.h>
#include <linux/dma-direction.h>
#include <linux/dma-mapping.h>
-#include <linux/sirfsoc_dma.h>
#define DRIVER_NAME "sirfsoc_spi"
@@ -132,6 +131,8 @@
#define IS_DMA_VALID(x) (x && ALIGNED(x->tx_buf) && ALIGNED(x->rx_buf) && \
ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE))
+#define SIRFSOC_MAX_CMD_BYTES 4
+
struct sirfsoc_spi {
struct spi_bitbang bitbang;
struct completion rx_done;
@@ -162,6 +163,12 @@ struct sirfsoc_spi {
void *dummypage;
int word_width; /* in bytes */
+ /*
+ * if tx size is not more than 4 and rx size is NULL, use
+ * command model
+ */
+ bool tx_by_cmd;
+
int chipselect[0];
};
@@ -260,6 +267,12 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
writel(spi_stat, sspi->base + SIRFSOC_SPI_INT_STATUS);
+ if (sspi->tx_by_cmd && (spi_stat & SIRFSOC_SPI_FRM_END)) {
+ complete(&sspi->tx_done);
+ writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
+ return IRQ_HANDLED;
+ }
+
/* Error Conditions */
if (spi_stat & SIRFSOC_SPI_RX_OFLOW ||
spi_stat & SIRFSOC_SPI_TX_UFLOW) {
@@ -310,6 +323,34 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t)
writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS);
+ /*
+ * fill tx_buf into command register and wait for its completion
+ */
+ if (sspi->tx_by_cmd) {
+ u32 cmd;
+ memcpy(&cmd, sspi->tx, t->len);
+
+ if (sspi->word_width == 1 && !(spi->mode & SPI_LSB_FIRST))
+ cmd = cpu_to_be32(cmd) >>
+ ((SIRFSOC_MAX_CMD_BYTES - t->len) * 8);
+ if (sspi->word_width == 2 && t->len == 4 &&
+ (!(spi->mode & SPI_LSB_FIRST)))
+ cmd = ((cmd & 0xffff) << 16) | (cmd >> 16);
+
+ writel(cmd, sspi->base + SIRFSOC_SPI_CMD);
+ writel(SIRFSOC_SPI_FRM_END_INT_EN,
+ sspi->base + SIRFSOC_SPI_INT_EN);
+ writel(SIRFSOC_SPI_CMD_TX_EN,
+ sspi->base + SIRFSOC_SPI_TX_RX_EN);
+
+ if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) {
+ dev_err(&spi->dev, "transfer timeout\n");
+ return 0;
+ }
+
+ return t->len;
+ }
+
if (sspi->left_tx_word == 1) {
writel(readl(sspi->base + SIRFSOC_SPI_CTRL) |
SIRFSOC_SPI_ENA_AUTO_CLR,
@@ -459,11 +500,6 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_8;
sspi->rx_word = spi_sirfsoc_rx_word_u8;
sspi->tx_word = spi_sirfsoc_tx_word_u8;
- txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- 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:
@@ -471,26 +507,22 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
SIRFSOC_SPI_TRAN_DAT_FORMAT_16;
sspi->rx_word = spi_sirfsoc_rx_word_u16;
sspi->tx_word = spi_sirfsoc_tx_word_u16;
- txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- 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;
sspi->rx_word = spi_sirfsoc_rx_word_u32;
sspi->tx_word = spi_sirfsoc_tx_word_u32;
- txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- 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();
}
+ sspi->word_width = DIV_ROUND_UP(bits_per_word, 8);
+ txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
+ sspi->word_width;
+ rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
+ sspi->word_width;
+
if (!(spi->mode & SPI_CS_HIGH))
regval |= SIRFSOC_SPI_CS_IDLE_STAT;
if (!(spi->mode & SPI_LSB_FIRST))
@@ -519,6 +551,14 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
writel(txfifo_ctrl, sspi->base + SIRFSOC_SPI_TXFIFO_CTRL);
writel(rxfifo_ctrl, sspi->base + SIRFSOC_SPI_RXFIFO_CTRL);
+ if (t && t->tx_buf && !t->rx_buf && (t->len <= SIRFSOC_MAX_CMD_BYTES)) {
+ regval |= (SIRFSOC_SPI_CMD_BYTE_NUM((t->len - 1)) |
+ SIRFSOC_SPI_CMD_MODE);
+ sspi->tx_by_cmd = true;
+ } else {
+ regval &= ~SIRFSOC_SPI_CMD_MODE;
+ sspi->tx_by_cmd = false;
+ }
writel(regval, sspi->base + SIRFSOC_SPI_CTRL);
if (IS_DMA_VALID(t)) {
@@ -548,8 +588,6 @@ 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;
@@ -560,20 +598,6 @@ 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");
@@ -637,18 +661,13 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
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);
+ sspi->rx_chan = dma_request_slave_channel(&pdev->dev, "rx");
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);
+ sspi->tx_chan = dma_request_slave_channel(&pdev->dev, "tx");
if (!sspi->tx_chan) {
dev_err(&pdev->dev, "can not allocate tx dma channel\n");
ret = -ENODEV;
@@ -724,11 +743,16 @@ static int spi_sirfsoc_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int spi_sirfsoc_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct sirfsoc_spi *sspi = spi_master_get_devdata(master);
+ int ret;
+
+ ret = spi_master_suspend(master);
+ if (ret)
+ return ret;
clk_disable(sspi->clk);
return 0;
@@ -745,15 +769,13 @@ static int spi_sirfsoc_resume(struct device *dev)
writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
- return 0;
+ return spi_master_resume(master);
}
-
-static const struct dev_pm_ops spi_sirfsoc_pm_ops = {
- .suspend = spi_sirfsoc_suspend,
- .resume = spi_sirfsoc_resume,
-};
#endif
+static SIMPLE_DEV_PM_OPS(spi_sirfsoc_pm_ops, spi_sirfsoc_suspend,
+ spi_sirfsoc_resume);
+
static const struct of_device_id spi_sirfsoc_of_match[] = {
{ .compatible = "sirf,prima2-spi", },
{ .compatible = "sirf,marco-spi", },
@@ -765,9 +787,7 @@ static struct platform_driver spi_sirfsoc_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
.pm = &spi_sirfsoc_pm_ops,
-#endif
.of_match_table = spi_sirfsoc_of_match,
},
.probe = spi_sirfsoc_probe,
diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
new file mode 100644
index 000000000000..d266a8702067
--- /dev/null
+++ b/drivers/spi/spi-sun4i.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2012 - 2014 Allwinner Tech
+ * Pan Nan <pannan@allwinnertech.com>
+ *
+ * Copyright (C) 2014 Maxime Ripard
+ * Maxime Ripard <maxime.ripard@free-electrons.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/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/workqueue.h>
+
+#include <linux/spi/spi.h>
+
+#define SUN4I_FIFO_DEPTH 64
+
+#define SUN4I_RXDATA_REG 0x00
+
+#define SUN4I_TXDATA_REG 0x04
+
+#define SUN4I_CTL_REG 0x08
+#define SUN4I_CTL_ENABLE BIT(0)
+#define SUN4I_CTL_MASTER BIT(1)
+#define SUN4I_CTL_CPHA BIT(2)
+#define SUN4I_CTL_CPOL BIT(3)
+#define SUN4I_CTL_CS_ACTIVE_LOW BIT(4)
+#define SUN4I_CTL_LMTF BIT(6)
+#define SUN4I_CTL_TF_RST BIT(8)
+#define SUN4I_CTL_RF_RST BIT(9)
+#define SUN4I_CTL_XCH BIT(10)
+#define SUN4I_CTL_CS_MASK 0x3000
+#define SUN4I_CTL_CS(cs) (((cs) << 12) & SUN4I_CTL_CS_MASK)
+#define SUN4I_CTL_DHB BIT(15)
+#define SUN4I_CTL_CS_MANUAL BIT(16)
+#define SUN4I_CTL_CS_LEVEL BIT(17)
+#define SUN4I_CTL_TP BIT(18)
+
+#define SUN4I_INT_CTL_REG 0x0c
+#define SUN4I_INT_CTL_TC BIT(16)
+
+#define SUN4I_INT_STA_REG 0x10
+
+#define SUN4I_DMA_CTL_REG 0x14
+
+#define SUN4I_WAIT_REG 0x18
+
+#define SUN4I_CLK_CTL_REG 0x1c
+#define SUN4I_CLK_CTL_CDR2_MASK 0xff
+#define SUN4I_CLK_CTL_CDR2(div) ((div) & SUN4I_CLK_CTL_CDR2_MASK)
+#define SUN4I_CLK_CTL_CDR1_MASK 0xf
+#define SUN4I_CLK_CTL_CDR1(div) (((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8)
+#define SUN4I_CLK_CTL_DRS BIT(12)
+
+#define SUN4I_BURST_CNT_REG 0x20
+#define SUN4I_BURST_CNT(cnt) ((cnt) & 0xffffff)
+
+#define SUN4I_XMIT_CNT_REG 0x24
+#define SUN4I_XMIT_CNT(cnt) ((cnt) & 0xffffff)
+
+#define SUN4I_FIFO_STA_REG 0x28
+#define SUN4I_FIFO_STA_RF_CNT_MASK 0x7f
+#define SUN4I_FIFO_STA_RF_CNT_BITS 0
+#define SUN4I_FIFO_STA_TF_CNT_MASK 0x7f
+#define SUN4I_FIFO_STA_TF_CNT_BITS 16
+
+struct sun4i_spi {
+ struct spi_master *master;
+ void __iomem *base_addr;
+ struct clk *hclk;
+ struct clk *mclk;
+
+ struct completion done;
+
+ const u8 *tx_buf;
+ u8 *rx_buf;
+ int len;
+};
+
+static inline u32 sun4i_spi_read(struct sun4i_spi *sspi, u32 reg)
+{
+ return readl(sspi->base_addr + reg);
+}
+
+static inline void sun4i_spi_write(struct sun4i_spi *sspi, u32 reg, u32 value)
+{
+ writel(value, sspi->base_addr + reg);
+}
+
+static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len)
+{
+ u32 reg, cnt;
+ u8 byte;
+
+ /* See how much data is available */
+ reg = sun4i_spi_read(sspi, SUN4I_FIFO_STA_REG);
+ reg &= SUN4I_FIFO_STA_RF_CNT_MASK;
+ cnt = reg >> SUN4I_FIFO_STA_RF_CNT_BITS;
+
+ if (len > cnt)
+ len = cnt;
+
+ while (len--) {
+ byte = readb(sspi->base_addr + SUN4I_RXDATA_REG);
+ if (sspi->rx_buf)
+ *sspi->rx_buf++ = byte;
+ }
+}
+
+static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len)
+{
+ u8 byte;
+
+ if (len > sspi->len)
+ len = sspi->len;
+
+ while (len--) {
+ byte = sspi->tx_buf ? *sspi->tx_buf++ : 0;
+ writeb(byte, sspi->base_addr + SUN4I_TXDATA_REG);
+ sspi->len--;
+ }
+}
+
+static void sun4i_spi_set_cs(struct spi_device *spi, bool enable)
+{
+ struct sun4i_spi *sspi = spi_master_get_devdata(spi->master);
+ u32 reg;
+
+ reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
+
+ reg &= ~SUN4I_CTL_CS_MASK;
+ reg |= SUN4I_CTL_CS(spi->chip_select);
+
+ if (enable)
+ reg |= SUN4I_CTL_CS_LEVEL;
+ else
+ reg &= ~SUN4I_CTL_CS_LEVEL;
+
+ /*
+ * Even though this looks irrelevant since we are supposed to
+ * be controlling the chip select manually, this bit also
+ * controls the levels of the chip select for inactive
+ * devices.
+ *
+ * If we don't set it, the chip select level will go low by
+ * default when the device is idle, which is not really
+ * expected in the common case where the chip select is active
+ * low.
+ */
+ if (spi->mode & SPI_CS_HIGH)
+ reg &= ~SUN4I_CTL_CS_ACTIVE_LOW;
+ else
+ reg |= SUN4I_CTL_CS_ACTIVE_LOW;
+
+ sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
+}
+
+static int sun4i_spi_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+ struct sun4i_spi *sspi = spi_master_get_devdata(master);
+ unsigned int mclk_rate, div, timeout;
+ unsigned int tx_len = 0;
+ int ret = 0;
+ u32 reg;
+
+ /* We don't support transfer larger than the FIFO */
+ if (tfr->len > SUN4I_FIFO_DEPTH)
+ return -EINVAL;
+
+ reinit_completion(&sspi->done);
+ sspi->tx_buf = tfr->tx_buf;
+ sspi->rx_buf = tfr->rx_buf;
+ sspi->len = tfr->len;
+
+ /* Clear pending interrupts */
+ sun4i_spi_write(sspi, SUN4I_INT_STA_REG, ~0);
+
+
+ reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
+
+ /* Reset FIFOs */
+ sun4i_spi_write(sspi, SUN4I_CTL_REG,
+ reg | SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST);
+
+ /*
+ * Setup the transfer control register: Chip Select,
+ * polarities, etc.
+ */
+ if (spi->mode & SPI_CPOL)
+ reg |= SUN4I_CTL_CPOL;
+ else
+ reg &= ~SUN4I_CTL_CPOL;
+
+ if (spi->mode & SPI_CPHA)
+ reg |= SUN4I_CTL_CPHA;
+ else
+ reg &= ~SUN4I_CTL_CPHA;
+
+ if (spi->mode & SPI_LSB_FIRST)
+ reg |= SUN4I_CTL_LMTF;
+ else
+ reg &= ~SUN4I_CTL_LMTF;
+
+
+ /*
+ * If it's a TX only transfer, we don't want to fill the RX
+ * FIFO with bogus data
+ */
+ if (sspi->rx_buf)
+ reg &= ~SUN4I_CTL_DHB;
+ else
+ reg |= SUN4I_CTL_DHB;
+
+ /* We want to control the chip select manually */
+ reg |= SUN4I_CTL_CS_MANUAL;
+
+ sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
+
+ /* Ensure that we have a parent clock fast enough */
+ mclk_rate = clk_get_rate(sspi->mclk);
+ if (mclk_rate < (2 * spi->max_speed_hz)) {
+ clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz);
+ mclk_rate = clk_get_rate(sspi->mclk);
+ }
+
+ /*
+ * Setup clock divider.
+ *
+ * We have two choices there. Either we can use the clock
+ * divide rate 1, which is calculated thanks to this formula:
+ * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1))
+ * Or we can use CDR2, which is calculated with the formula:
+ * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
+ * Wether we use the former or the latter is set through the
+ * DRS bit.
+ *
+ * First try CDR2, and if we can't reach the expected
+ * frequency, fall back to CDR1.
+ */
+ div = mclk_rate / (2 * spi->max_speed_hz);
+ if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) {
+ if (div > 0)
+ div--;
+
+ reg = SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS;
+ } else {
+ div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz);
+ reg = SUN4I_CLK_CTL_CDR1(div);
+ }
+
+ sun4i_spi_write(sspi, SUN4I_CLK_CTL_REG, reg);
+
+ /* Setup the transfer now... */
+ if (sspi->tx_buf)
+ tx_len = tfr->len;
+
+ /* Setup the counters */
+ sun4i_spi_write(sspi, SUN4I_BURST_CNT_REG, SUN4I_BURST_CNT(tfr->len));
+ sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len));
+
+ /* Fill the TX FIFO */
+ sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH);
+
+ /* Enable the interrupts */
+ sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC);
+
+ /* Start the transfer */
+ reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
+ sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);
+
+ timeout = wait_for_completion_timeout(&sspi->done,
+ msecs_to_jiffies(1000));
+ if (!timeout) {
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
+
+out:
+ sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, 0);
+
+ return ret;
+}
+
+static irqreturn_t sun4i_spi_handler(int irq, void *dev_id)
+{
+ struct sun4i_spi *sspi = dev_id;
+ u32 status = sun4i_spi_read(sspi, SUN4I_INT_STA_REG);
+
+ /* Transfer complete */
+ if (status & SUN4I_INT_CTL_TC) {
+ sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TC);
+ complete(&sspi->done);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int sun4i_spi_runtime_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct sun4i_spi *sspi = spi_master_get_devdata(master);
+ int ret;
+
+ ret = clk_prepare_enable(sspi->hclk);
+ if (ret) {
+ dev_err(dev, "Couldn't enable AHB clock\n");
+ goto out;
+ }
+
+ ret = clk_prepare_enable(sspi->mclk);
+ if (ret) {
+ dev_err(dev, "Couldn't enable module clock\n");
+ goto err;
+ }
+
+ sun4i_spi_write(sspi, SUN4I_CTL_REG,
+ SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | SUN4I_CTL_TP);
+
+ return 0;
+
+err:
+ clk_disable_unprepare(sspi->hclk);
+out:
+ return ret;
+}
+
+static int sun4i_spi_runtime_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct sun4i_spi *sspi = spi_master_get_devdata(master);
+
+ clk_disable_unprepare(sspi->mclk);
+ clk_disable_unprepare(sspi->hclk);
+
+ return 0;
+}
+
+static int sun4i_spi_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct sun4i_spi *sspi;
+ struct resource *res;
+ int ret = 0, irq;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct sun4i_spi));
+ if (!master) {
+ dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, master);
+ sspi = spi_master_get_devdata(master);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ sspi->base_addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(sspi->base_addr)) {
+ ret = PTR_ERR(sspi->base_addr);
+ goto err_free_master;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "No spi IRQ specified\n");
+ ret = -ENXIO;
+ goto err_free_master;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, sun4i_spi_handler,
+ 0, "sun4i-spi", sspi);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot request IRQ\n");
+ goto err_free_master;
+ }
+
+ sspi->master = master;
+ master->set_cs = sun4i_spi_set_cs;
+ master->transfer_one = sun4i_spi_transfer_one;
+ master->num_chipselect = 4;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->dev.of_node = pdev->dev.of_node;
+ master->auto_runtime_pm = true;
+
+ sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
+ if (IS_ERR(sspi->hclk)) {
+ dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
+ ret = PTR_ERR(sspi->hclk);
+ goto err_free_master;
+ }
+
+ sspi->mclk = devm_clk_get(&pdev->dev, "mod");
+ if (IS_ERR(sspi->mclk)) {
+ dev_err(&pdev->dev, "Unable to acquire module clock\n");
+ ret = PTR_ERR(sspi->mclk);
+ goto err_free_master;
+ }
+
+ init_completion(&sspi->done);
+
+ /*
+ * This wake-up/shutdown pattern is to be able to have the
+ * device woken up, even if runtime_pm is disabled
+ */
+ ret = sun4i_spi_runtime_resume(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't resume the device\n");
+ goto err_free_master;
+ }
+
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_idle(&pdev->dev);
+
+ ret = devm_spi_register_master(&pdev->dev, master);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot register SPI master\n");
+ goto err_pm_disable;
+ }
+
+ return 0;
+
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+ sun4i_spi_runtime_suspend(&pdev->dev);
+err_free_master:
+ spi_master_put(master);
+ return ret;
+}
+
+static int sun4i_spi_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id sun4i_spi_match[] = {
+ { .compatible = "allwinner,sun4i-a10-spi", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sun4i_spi_match);
+
+static const struct dev_pm_ops sun4i_spi_pm_ops = {
+ .runtime_resume = sun4i_spi_runtime_resume,
+ .runtime_suspend = sun4i_spi_runtime_suspend,
+};
+
+static struct platform_driver sun4i_spi_driver = {
+ .probe = sun4i_spi_probe,
+ .remove = sun4i_spi_remove,
+ .driver = {
+ .name = "sun4i-spi",
+ .owner = THIS_MODULE,
+ .of_match_table = sun4i_spi_match,
+ .pm = &sun4i_spi_pm_ops,
+ },
+};
+module_platform_driver(sun4i_spi_driver);
+
+MODULE_AUTHOR("Pan Nan <pannan@allwinnertech.com>");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A1X/A20 SPI controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
new file mode 100644
index 000000000000..b3e3498a7e6f
--- /dev/null
+++ b/drivers/spi/spi-sun6i.c
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2012 - 2014 Allwinner Tech
+ * Pan Nan <pannan@allwinnertech.com>
+ *
+ * Copyright (C) 2014 Maxime Ripard
+ * Maxime Ripard <maxime.ripard@free-electrons.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/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/workqueue.h>
+
+#include <linux/spi/spi.h>
+
+#define SUN6I_FIFO_DEPTH 128
+
+#define SUN6I_GBL_CTL_REG 0x04
+#define SUN6I_GBL_CTL_BUS_ENABLE BIT(0)
+#define SUN6I_GBL_CTL_MASTER BIT(1)
+#define SUN6I_GBL_CTL_TP BIT(7)
+#define SUN6I_GBL_CTL_RST BIT(31)
+
+#define SUN6I_TFR_CTL_REG 0x08
+#define SUN6I_TFR_CTL_CPHA BIT(0)
+#define SUN6I_TFR_CTL_CPOL BIT(1)
+#define SUN6I_TFR_CTL_SPOL BIT(2)
+#define SUN6I_TFR_CTL_CS_MASK 0x30
+#define SUN6I_TFR_CTL_CS(cs) (((cs) << 4) & SUN6I_TFR_CTL_CS_MASK)
+#define SUN6I_TFR_CTL_CS_MANUAL BIT(6)
+#define SUN6I_TFR_CTL_CS_LEVEL BIT(7)
+#define SUN6I_TFR_CTL_DHB BIT(8)
+#define SUN6I_TFR_CTL_FBS BIT(12)
+#define SUN6I_TFR_CTL_XCH BIT(31)
+
+#define SUN6I_INT_CTL_REG 0x10
+#define SUN6I_INT_CTL_RF_OVF BIT(8)
+#define SUN6I_INT_CTL_TC BIT(12)
+
+#define SUN6I_INT_STA_REG 0x14
+
+#define SUN6I_FIFO_CTL_REG 0x18
+#define SUN6I_FIFO_CTL_RF_RST BIT(15)
+#define SUN6I_FIFO_CTL_TF_RST BIT(31)
+
+#define SUN6I_FIFO_STA_REG 0x1c
+#define SUN6I_FIFO_STA_RF_CNT_MASK 0x7f
+#define SUN6I_FIFO_STA_RF_CNT_BITS 0
+#define SUN6I_FIFO_STA_TF_CNT_MASK 0x7f
+#define SUN6I_FIFO_STA_TF_CNT_BITS 16
+
+#define SUN6I_CLK_CTL_REG 0x24
+#define SUN6I_CLK_CTL_CDR2_MASK 0xff
+#define SUN6I_CLK_CTL_CDR2(div) (((div) & SUN6I_CLK_CTL_CDR2_MASK) << 0)
+#define SUN6I_CLK_CTL_CDR1_MASK 0xf
+#define SUN6I_CLK_CTL_CDR1(div) (((div) & SUN6I_CLK_CTL_CDR1_MASK) << 8)
+#define SUN6I_CLK_CTL_DRS BIT(12)
+
+#define SUN6I_BURST_CNT_REG 0x30
+#define SUN6I_BURST_CNT(cnt) ((cnt) & 0xffffff)
+
+#define SUN6I_XMIT_CNT_REG 0x34
+#define SUN6I_XMIT_CNT(cnt) ((cnt) & 0xffffff)
+
+#define SUN6I_BURST_CTL_CNT_REG 0x38
+#define SUN6I_BURST_CTL_CNT_STC(cnt) ((cnt) & 0xffffff)
+
+#define SUN6I_TXDATA_REG 0x200
+#define SUN6I_RXDATA_REG 0x300
+
+struct sun6i_spi {
+ struct spi_master *master;
+ void __iomem *base_addr;
+ struct clk *hclk;
+ struct clk *mclk;
+ struct reset_control *rstc;
+
+ struct completion done;
+
+ const u8 *tx_buf;
+ u8 *rx_buf;
+ int len;
+};
+
+static inline u32 sun6i_spi_read(struct sun6i_spi *sspi, u32 reg)
+{
+ return readl(sspi->base_addr + reg);
+}
+
+static inline void sun6i_spi_write(struct sun6i_spi *sspi, u32 reg, u32 value)
+{
+ writel(value, sspi->base_addr + reg);
+}
+
+static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len)
+{
+ u32 reg, cnt;
+ u8 byte;
+
+ /* See how much data is available */
+ reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
+ reg &= SUN6I_FIFO_STA_RF_CNT_MASK;
+ cnt = reg >> SUN6I_FIFO_STA_RF_CNT_BITS;
+
+ if (len > cnt)
+ len = cnt;
+
+ while (len--) {
+ byte = readb(sspi->base_addr + SUN6I_RXDATA_REG);
+ if (sspi->rx_buf)
+ *sspi->rx_buf++ = byte;
+ }
+}
+
+static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi, int len)
+{
+ u8 byte;
+
+ if (len > sspi->len)
+ len = sspi->len;
+
+ while (len--) {
+ byte = sspi->tx_buf ? *sspi->tx_buf++ : 0;
+ writeb(byte, sspi->base_addr + SUN6I_TXDATA_REG);
+ sspi->len--;
+ }
+}
+
+static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
+{
+ struct sun6i_spi *sspi = spi_master_get_devdata(spi->master);
+ u32 reg;
+
+ reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
+ reg &= ~SUN6I_TFR_CTL_CS_MASK;
+ reg |= SUN6I_TFR_CTL_CS(spi->chip_select);
+
+ if (enable)
+ reg |= SUN6I_TFR_CTL_CS_LEVEL;
+ else
+ reg &= ~SUN6I_TFR_CTL_CS_LEVEL;
+
+ sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
+}
+
+
+static int sun6i_spi_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+ struct sun6i_spi *sspi = spi_master_get_devdata(master);
+ unsigned int mclk_rate, div, timeout;
+ unsigned int tx_len = 0;
+ int ret = 0;
+ u32 reg;
+
+ /* We don't support transfer larger than the FIFO */
+ if (tfr->len > SUN6I_FIFO_DEPTH)
+ return -EINVAL;
+
+ reinit_completion(&sspi->done);
+ sspi->tx_buf = tfr->tx_buf;
+ sspi->rx_buf = tfr->rx_buf;
+ sspi->len = tfr->len;
+
+ /* Clear pending interrupts */
+ sun6i_spi_write(sspi, SUN6I_INT_STA_REG, ~0);
+
+ /* Reset FIFO */
+ sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
+ SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST);
+
+ /*
+ * Setup the transfer control register: Chip Select,
+ * polarities, etc.
+ */
+ reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
+
+ if (spi->mode & SPI_CPOL)
+ reg |= SUN6I_TFR_CTL_CPOL;
+ else
+ reg &= ~SUN6I_TFR_CTL_CPOL;
+
+ if (spi->mode & SPI_CPHA)
+ reg |= SUN6I_TFR_CTL_CPHA;
+ else
+ reg &= ~SUN6I_TFR_CTL_CPHA;
+
+ if (spi->mode & SPI_LSB_FIRST)
+ reg |= SUN6I_TFR_CTL_FBS;
+ else
+ reg &= ~SUN6I_TFR_CTL_FBS;
+
+ /*
+ * If it's a TX only transfer, we don't want to fill the RX
+ * FIFO with bogus data
+ */
+ if (sspi->rx_buf)
+ reg &= ~SUN6I_TFR_CTL_DHB;
+ else
+ reg |= SUN6I_TFR_CTL_DHB;
+
+ /* We want to control the chip select manually */
+ reg |= SUN6I_TFR_CTL_CS_MANUAL;
+
+ sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
+
+ /* Ensure that we have a parent clock fast enough */
+ mclk_rate = clk_get_rate(sspi->mclk);
+ if (mclk_rate < (2 * spi->max_speed_hz)) {
+ clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz);
+ mclk_rate = clk_get_rate(sspi->mclk);
+ }
+
+ /*
+ * Setup clock divider.
+ *
+ * We have two choices there. Either we can use the clock
+ * divide rate 1, which is calculated thanks to this formula:
+ * SPI_CLK = MOD_CLK / (2 ^ cdr)
+ * Or we can use CDR2, which is calculated with the formula:
+ * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
+ * Wether we use the former or the latter is set through the
+ * DRS bit.
+ *
+ * First try CDR2, and if we can't reach the expected
+ * frequency, fall back to CDR1.
+ */
+ div = mclk_rate / (2 * spi->max_speed_hz);
+ if (div <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
+ if (div > 0)
+ div--;
+
+ reg = SUN6I_CLK_CTL_CDR2(div) | SUN6I_CLK_CTL_DRS;
+ } else {
+ div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz);
+ reg = SUN6I_CLK_CTL_CDR1(div);
+ }
+
+ sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
+
+ /* Setup the transfer now... */
+ if (sspi->tx_buf)
+ tx_len = tfr->len;
+
+ /* Setup the counters */
+ sun6i_spi_write(sspi, SUN6I_BURST_CNT_REG, SUN6I_BURST_CNT(tfr->len));
+ sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, SUN6I_XMIT_CNT(tx_len));
+ sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG,
+ SUN6I_BURST_CTL_CNT_STC(tx_len));
+
+ /* Fill the TX FIFO */
+ sun6i_spi_fill_fifo(sspi, SUN6I_FIFO_DEPTH);
+
+ /* Enable the interrupts */
+ sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
+
+ /* Start the transfer */
+ reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
+ sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
+
+ timeout = wait_for_completion_timeout(&sspi->done,
+ msecs_to_jiffies(1000));
+ if (!timeout) {
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH);
+
+out:
+ sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0);
+
+ return ret;
+}
+
+static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
+{
+ struct sun6i_spi *sspi = dev_id;
+ u32 status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
+
+ /* Transfer complete */
+ if (status & SUN6I_INT_CTL_TC) {
+ sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC);
+ complete(&sspi->done);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int sun6i_spi_runtime_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct sun6i_spi *sspi = spi_master_get_devdata(master);
+ int ret;
+
+ ret = clk_prepare_enable(sspi->hclk);
+ if (ret) {
+ dev_err(dev, "Couldn't enable AHB clock\n");
+ goto out;
+ }
+
+ ret = clk_prepare_enable(sspi->mclk);
+ if (ret) {
+ dev_err(dev, "Couldn't enable module clock\n");
+ goto err;
+ }
+
+ ret = reset_control_deassert(sspi->rstc);
+ if (ret) {
+ dev_err(dev, "Couldn't deassert the device from reset\n");
+ goto err2;
+ }
+
+ sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG,
+ SUN6I_GBL_CTL_BUS_ENABLE | SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP);
+
+ return 0;
+
+err2:
+ clk_disable_unprepare(sspi->mclk);
+err:
+ clk_disable_unprepare(sspi->hclk);
+out:
+ return ret;
+}
+
+static int sun6i_spi_runtime_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct sun6i_spi *sspi = spi_master_get_devdata(master);
+
+ reset_control_assert(sspi->rstc);
+ clk_disable_unprepare(sspi->mclk);
+ clk_disable_unprepare(sspi->hclk);
+
+ return 0;
+}
+
+static int sun6i_spi_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct sun6i_spi *sspi;
+ struct resource *res;
+ int ret = 0, irq;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi));
+ if (!master) {
+ dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, master);
+ sspi = spi_master_get_devdata(master);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ sspi->base_addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(sspi->base_addr)) {
+ ret = PTR_ERR(sspi->base_addr);
+ goto err_free_master;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "No spi IRQ specified\n");
+ ret = -ENXIO;
+ goto err_free_master;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, sun6i_spi_handler,
+ 0, "sun6i-spi", sspi);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot request IRQ\n");
+ goto err_free_master;
+ }
+
+ sspi->master = master;
+ master->set_cs = sun6i_spi_set_cs;
+ master->transfer_one = sun6i_spi_transfer_one;
+ master->num_chipselect = 4;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->dev.of_node = pdev->dev.of_node;
+ master->auto_runtime_pm = true;
+
+ sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
+ if (IS_ERR(sspi->hclk)) {
+ dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
+ ret = PTR_ERR(sspi->hclk);
+ goto err_free_master;
+ }
+
+ sspi->mclk = devm_clk_get(&pdev->dev, "mod");
+ if (IS_ERR(sspi->mclk)) {
+ dev_err(&pdev->dev, "Unable to acquire module clock\n");
+ ret = PTR_ERR(sspi->mclk);
+ goto err_free_master;
+ }
+
+ init_completion(&sspi->done);
+
+ sspi->rstc = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(sspi->rstc)) {
+ dev_err(&pdev->dev, "Couldn't get reset controller\n");
+ ret = PTR_ERR(sspi->rstc);
+ goto err_free_master;
+ }
+
+ /*
+ * This wake-up/shutdown pattern is to be able to have the
+ * device woken up, even if runtime_pm is disabled
+ */
+ ret = sun6i_spi_runtime_resume(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't resume the device\n");
+ goto err_free_master;
+ }
+
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_idle(&pdev->dev);
+
+ ret = devm_spi_register_master(&pdev->dev, master);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot register SPI master\n");
+ goto err_pm_disable;
+ }
+
+ return 0;
+
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+ sun6i_spi_runtime_suspend(&pdev->dev);
+err_free_master:
+ spi_master_put(master);
+ return ret;
+}
+
+static int sun6i_spi_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id sun6i_spi_match[] = {
+ { .compatible = "allwinner,sun6i-a31-spi", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sun6i_spi_match);
+
+static const struct dev_pm_ops sun6i_spi_pm_ops = {
+ .runtime_resume = sun6i_spi_runtime_resume,
+ .runtime_suspend = sun6i_spi_runtime_suspend,
+};
+
+static struct platform_driver sun6i_spi_driver = {
+ .probe = sun6i_spi_probe,
+ .remove = sun6i_spi_remove,
+ .driver = {
+ .name = "sun6i-spi",
+ .owner = THIS_MODULE,
+ .of_match_table = sun6i_spi_match,
+ .pm = &sun6i_spi_pm_ops,
+ },
+};
+module_platform_driver(sun6i_spi_driver);
+
+MODULE_AUTHOR("Pan Nan <pannan@allwinnertech.com>");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A31 SPI controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 413c71843492..400649595505 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -23,7 +23,6 @@
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/err.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
@@ -172,7 +171,6 @@ struct tegra_spi_data {
void __iomem *base;
phys_addr_t phys;
unsigned irq;
- u32 spi_max_frequency;
u32 cur_speed;
struct spi_device *cur_spi;
@@ -761,11 +759,6 @@ static int tegra_spi_setup(struct spi_device *spi)
spi->mode & SPI_CPHA ? "" : "~",
spi->max_speed_hz);
- BUG_ON(spi->chip_select >= MAX_CHIP_SELECT);
-
- /* Set speed to the spi max fequency if spi device has not set */
- spi->max_speed_hz = spi->max_speed_hz ? : tspi->spi_max_frequency;
-
ret = pm_runtime_get_sync(tspi->dev);
if (ret < 0) {
dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
@@ -853,8 +846,8 @@ complete_xfer:
SPI_COMMAND1);
tegra_spi_transfer_delay(xfer->delay_usecs);
goto exit;
- } else if (msg->transfers.prev == &xfer->transfer_list) {
- /* This is the last transfer in message */
+ } else if (list_is_last(&xfer->transfer_list,
+ &msg->transfers)) {
if (xfer->cs_change)
tspi->cs_control = spi;
else {
@@ -1019,16 +1012,6 @@ static irqreturn_t tegra_spi_isr(int irq, void *context_data)
return IRQ_WAKE_THREAD;
}
-static void tegra_spi_parse_dt(struct platform_device *pdev,
- struct tegra_spi_data *tspi)
-{
- struct device_node *np = pdev->dev.of_node;
-
- if (of_property_read_u32(np, "spi-max-frequency",
- &tspi->spi_max_frequency))
- tspi->spi_max_frequency = 25000000; /* 25MHz */
-}
-
static struct of_device_id tegra_spi_of_match[] = {
{ .compatible = "nvidia,tegra114-spi", },
{}
@@ -1050,15 +1033,15 @@ static int tegra_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master);
tspi = spi_master_get_devdata(master);
- /* Parse DT */
- tegra_spi_parse_dt(pdev, tspi);
+ if (of_property_read_u32(pdev->dev.of_node, "spi-max-frequency",
+ &master->max_speed_hz))
+ master->max_speed_hz = 25000000; /* 25MHz */
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->setup = tegra_spi_setup;
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;
diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c
index 08794977f21a..47869ea636e1 100644
--- a/drivers/spi/spi-tegra20-sflash.c
+++ b/drivers/spi/spi-tegra20-sflash.c
@@ -22,7 +22,6 @@
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
@@ -121,7 +120,6 @@ struct tegra_sflash_data {
struct reset_control *rst;
void __iomem *base;
unsigned irq;
- u32 spi_max_frequency;
u32 cur_speed;
struct spi_device *cur_spi;
@@ -315,15 +313,6 @@ static int tegra_sflash_start_transfer_one(struct spi_device *spi,
return tegra_sflash_start_cpu_based_transfer(tsd, t);
}
-static int tegra_sflash_setup(struct spi_device *spi)
-{
- struct tegra_sflash_data *tsd = spi_master_get_devdata(spi->master);
-
- /* Set speed to the spi max fequency if spi device has not set */
- spi->max_speed_hz = spi->max_speed_hz ? : tsd->spi_max_frequency;
- return 0;
-}
-
static int tegra_sflash_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
{
@@ -430,15 +419,6 @@ static irqreturn_t tegra_sflash_isr(int irq, void *context_data)
return handle_cpu_based_xfer(tsd);
}
-static void tegra_sflash_parse_dt(struct tegra_sflash_data *tsd)
-{
- struct device_node *np = tsd->dev->of_node;
-
- if (of_property_read_u32(np, "spi-max-frequency",
- &tsd->spi_max_frequency))
- tsd->spi_max_frequency = 25000000; /* 25MHz */
-}
-
static struct of_device_id tegra_sflash_of_match[] = {
{ .compatible = "nvidia,tegra20-sflash", },
{}
@@ -467,11 +447,9 @@ static int tegra_sflash_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
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;
platform_set_drvdata(pdev, master);
tsd = spi_master_get_devdata(master);
@@ -479,7 +457,9 @@ static int tegra_sflash_probe(struct platform_device *pdev)
tsd->dev = &pdev->dev;
spin_lock_init(&tsd->lock);
- tegra_sflash_parse_dt(tsd);
+ if (of_property_read_u32(tsd->dev->of_node, "spi-max-frequency",
+ &master->max_speed_hz))
+ master->max_speed_hz = 25000000; /* 25MHz */
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
tsd->base = devm_ioremap_resource(&pdev->dev, r);
diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c
index be3a069879c3..e3c1b93e45d1 100644
--- a/drivers/spi/spi-tegra20-slink.c
+++ b/drivers/spi/spi-tegra20-slink.c
@@ -23,7 +23,6 @@
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/err.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
@@ -171,7 +170,6 @@ struct tegra_slink_data {
void __iomem *base;
phys_addr_t phys;
unsigned irq;
- u32 spi_max_frequency;
u32 cur_speed;
struct spi_device *cur_spi;
@@ -761,10 +759,6 @@ static int tegra_slink_setup(struct spi_device *spi)
spi->mode & SPI_CPHA ? "" : "~",
spi->max_speed_hz);
- BUG_ON(spi->chip_select >= MAX_CHIP_SELECT);
-
- /* Set speed to the spi max fequency if spi device has not set */
- spi->max_speed_hz = spi->max_speed_hz ? : tspi->spi_max_frequency;
ret = pm_runtime_get_sync(tspi->dev);
if (ret < 0) {
dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
@@ -999,15 +993,6 @@ static irqreturn_t tegra_slink_isr(int irq, void *context_data)
return IRQ_WAKE_THREAD;
}
-static void tegra_slink_parse_dt(struct tegra_slink_data *tspi)
-{
- struct device_node *np = tspi->dev->of_node;
-
- if (of_property_read_u32(np, "spi-max-frequency",
- &tspi->spi_max_frequency))
- tspi->spi_max_frequency = 25000000; /* 25MHz */
-}
-
static const struct tegra_slink_chip_data tegra30_spi_cdata = {
.cs_hold_time = true,
};
@@ -1053,7 +1038,6 @@ static int tegra_slink_probe(struct platform_device *pdev)
master->unprepare_message = tegra_slink_unprepare_message;
master->auto_runtime_pm = true;
master->num_chipselect = MAX_CHIP_SELECT;
- master->bus_num = -1;
platform_set_drvdata(pdev, master);
tspi = spi_master_get_devdata(master);
@@ -1062,7 +1046,9 @@ static int tegra_slink_probe(struct platform_device *pdev)
tspi->chip_data = cdata;
spin_lock_init(&tspi->lock);
- tegra_slink_parse_dt(tspi);
+ if (of_property_read_u32(tspi->dev->of_node, "spi-max-frequency",
+ &master->max_speed_hz))
+ master->max_speed_hz = 25000000; /* 25MHz */
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c
index 3d09265b5133..6c211d1910b0 100644
--- a/drivers/spi/spi-ti-qspi.c
+++ b/drivers/spi/spi-ti-qspi.c
@@ -429,13 +429,13 @@ static int ti_qspi_probe(struct platform_device *pdev)
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD;
- 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);
+ master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
+ SPI_BPW_MASK(8);
if (!of_property_read_u32(np, "num-cs", &num_cs))
master->num_chipselect = num_cs;
@@ -461,7 +461,6 @@ static int ti_qspi_probe(struct platform_device *pdev)
if (res_mmap == NULL) {
dev_err(&pdev->dev,
"memory mapped resource not required\n");
- return -ENODEV;
}
}
diff --git a/drivers/spi/spi-ti-ssp.c b/drivers/spi/spi-ti-ssp.c
deleted file mode 100644
index 7d20e121e4c1..000000000000
--- a/drivers/spi/spi-ti-ssp.c
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Sequencer Serial Port (SSP) based SPI master driver
- *
- * Copyright (C) 2010 Texas Instruments Inc
- *
- * 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/err.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/mfd/ti_ssp.h>
-
-#define MODE_BITS (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH)
-
-struct ti_ssp_spi {
- struct spi_master *master;
- struct device *dev;
- spinlock_t lock;
- struct list_head msg_queue;
- struct completion complete;
- bool shutdown;
- struct workqueue_struct *workqueue;
- struct work_struct work;
- u8 mode, bpw;
- int cs_active;
- u32 pc_en, pc_dis, pc_wr, pc_rd;
- void (*select)(int cs);
-};
-
-static u32 ti_ssp_spi_rx(struct ti_ssp_spi *hw)
-{
- u32 ret;
-
- ti_ssp_run(hw->dev, hw->pc_rd, 0, &ret);
- return ret;
-}
-
-static void ti_ssp_spi_tx(struct ti_ssp_spi *hw, u32 data)
-{
- ti_ssp_run(hw->dev, hw->pc_wr, data << (32 - hw->bpw), NULL);
-}
-
-static int ti_ssp_spi_txrx(struct ti_ssp_spi *hw, struct spi_message *msg,
- struct spi_transfer *t)
-{
- int count;
-
- if (hw->bpw <= 8) {
- u8 *rx = t->rx_buf;
- const u8 *tx = t->tx_buf;
-
- for (count = 0; count < t->len; count += 1) {
- if (t->tx_buf)
- ti_ssp_spi_tx(hw, *tx++);
- if (t->rx_buf)
- *rx++ = ti_ssp_spi_rx(hw);
- }
- } else if (hw->bpw <= 16) {
- u16 *rx = t->rx_buf;
- const u16 *tx = t->tx_buf;
-
- for (count = 0; count < t->len; count += 2) {
- if (t->tx_buf)
- ti_ssp_spi_tx(hw, *tx++);
- if (t->rx_buf)
- *rx++ = ti_ssp_spi_rx(hw);
- }
- } else {
- u32 *rx = t->rx_buf;
- const u32 *tx = t->tx_buf;
-
- for (count = 0; count < t->len; count += 4) {
- if (t->tx_buf)
- ti_ssp_spi_tx(hw, *tx++);
- if (t->rx_buf)
- *rx++ = ti_ssp_spi_rx(hw);
- }
- }
-
- msg->actual_length += count; /* bytes transferred */
-
- dev_dbg(&msg->spi->dev, "xfer %s%s, %d bytes, %d bpw, count %d%s\n",
- t->tx_buf ? "tx" : "", t->rx_buf ? "rx" : "", t->len,
- hw->bpw, count, (count < t->len) ? " (under)" : "");
-
- return (count < t->len) ? -EIO : 0; /* left over data */
-}
-
-static void ti_ssp_spi_chip_select(struct ti_ssp_spi *hw, int cs_active)
-{
- cs_active = !!cs_active;
- if (cs_active == hw->cs_active)
- return;
- ti_ssp_run(hw->dev, cs_active ? hw->pc_en : hw->pc_dis, 0, NULL);
- hw->cs_active = cs_active;
-}
-
-#define __SHIFT_OUT(bits) (SSP_OPCODE_SHIFT | SSP_OUT_MODE | \
- cs_en | clk | SSP_COUNT((bits) * 2 - 1))
-#define __SHIFT_IN(bits) (SSP_OPCODE_SHIFT | SSP_IN_MODE | \
- cs_en | clk | SSP_COUNT((bits) * 2 - 1))
-
-static int ti_ssp_spi_setup_transfer(struct ti_ssp_spi *hw, u8 bpw, u8 mode)
-{
- int error, idx = 0;
- u32 seqram[16];
- u32 cs_en, cs_dis, clk;
- u32 topbits, botbits;
-
- mode &= MODE_BITS;
- if (mode == hw->mode && bpw == hw->bpw)
- return 0;
-
- cs_en = (mode & SPI_CS_HIGH) ? SSP_CS_HIGH : SSP_CS_LOW;
- cs_dis = (mode & SPI_CS_HIGH) ? SSP_CS_LOW : SSP_CS_HIGH;
- clk = (mode & SPI_CPOL) ? SSP_CLK_HIGH : SSP_CLK_LOW;
-
- /* Construct instructions */
-
- /* Disable Chip Select */
- hw->pc_dis = idx;
- seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_dis | clk;
- seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_dis | clk;
-
- /* Enable Chip Select */
- hw->pc_en = idx;
- seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_en | clk;
- seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
-
- /* Reads and writes need to be split for bpw > 16 */
- topbits = (bpw > 16) ? 16 : bpw;
- botbits = bpw - topbits;
-
- /* Write */
- hw->pc_wr = idx;
- seqram[idx++] = __SHIFT_OUT(topbits) | SSP_ADDR_REG;
- if (botbits)
- seqram[idx++] = __SHIFT_OUT(botbits) | SSP_DATA_REG;
- seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
-
- /* Read */
- hw->pc_rd = idx;
- if (botbits)
- seqram[idx++] = __SHIFT_IN(botbits) | SSP_ADDR_REG;
- seqram[idx++] = __SHIFT_IN(topbits) | SSP_DATA_REG;
- seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
-
- error = ti_ssp_load(hw->dev, 0, seqram, idx);
- if (error < 0)
- return error;
-
- error = ti_ssp_set_mode(hw->dev, ((mode & SPI_CPHA) ?
- 0 : SSP_EARLY_DIN));
- if (error < 0)
- return error;
-
- hw->bpw = bpw;
- hw->mode = mode;
-
- return error;
-}
-
-static void ti_ssp_spi_work(struct work_struct *work)
-{
- struct ti_ssp_spi *hw = container_of(work, struct ti_ssp_spi, work);
-
- spin_lock(&hw->lock);
-
- while (!list_empty(&hw->msg_queue)) {
- struct spi_message *m;
- struct spi_device *spi;
- struct spi_transfer *t = NULL;
- int status = 0;
-
- m = container_of(hw->msg_queue.next, struct spi_message,
- queue);
-
- list_del_init(&m->queue);
-
- spin_unlock(&hw->lock);
-
- spi = m->spi;
-
- if (hw->select)
- hw->select(spi->chip_select);
-
- list_for_each_entry(t, &m->transfers, transfer_list) {
- int bpw = spi->bits_per_word;
- int xfer_status;
-
- if (t->bits_per_word)
- bpw = t->bits_per_word;
-
- if (ti_ssp_spi_setup_transfer(hw, bpw, spi->mode) < 0)
- break;
-
- ti_ssp_spi_chip_select(hw, 1);
-
- xfer_status = ti_ssp_spi_txrx(hw, m, t);
- if (xfer_status < 0)
- status = xfer_status;
-
- if (t->delay_usecs)
- udelay(t->delay_usecs);
-
- if (t->cs_change)
- ti_ssp_spi_chip_select(hw, 0);
- }
-
- ti_ssp_spi_chip_select(hw, 0);
- m->status = status;
- m->complete(m->context);
-
- spin_lock(&hw->lock);
- }
-
- if (hw->shutdown)
- complete(&hw->complete);
-
- spin_unlock(&hw->lock);
-}
-
-static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m)
-{
- struct ti_ssp_spi *hw;
- struct spi_transfer *t;
- int error = 0;
-
- m->actual_length = 0;
- m->status = -EINPROGRESS;
-
- hw = spi_master_get_devdata(spi->master);
-
- if (list_empty(&m->transfers) || !m->complete)
- return -EINVAL;
-
- list_for_each_entry(t, &m->transfers, transfer_list) {
- if (t->len && !(t->rx_buf || t->tx_buf)) {
- dev_err(&spi->dev, "invalid xfer, no buffer\n");
- return -EINVAL;
- }
-
- if (t->len && t->rx_buf && t->tx_buf) {
- dev_err(&spi->dev, "invalid xfer, full duplex\n");
- return -EINVAL;
- }
- }
-
- spin_lock(&hw->lock);
- if (hw->shutdown) {
- error = -ESHUTDOWN;
- goto error_unlock;
- }
- list_add_tail(&m->queue, &hw->msg_queue);
- queue_work(hw->workqueue, &hw->work);
-error_unlock:
- spin_unlock(&hw->lock);
- return error;
-}
-
-static int ti_ssp_spi_probe(struct platform_device *pdev)
-{
- const struct ti_ssp_spi_data *pdata;
- struct ti_ssp_spi *hw;
- struct spi_master *master;
- struct device *dev = &pdev->dev;
- int error = 0;
-
- pdata = dev_get_platdata(dev);
- if (!pdata) {
- dev_err(dev, "platform data not found\n");
- return -EINVAL;
- }
-
- master = spi_alloc_master(dev, sizeof(struct ti_ssp_spi));
- if (!master) {
- dev_err(dev, "cannot allocate SPI master\n");
- return -ENOMEM;
- }
-
- hw = spi_master_get_devdata(master);
- platform_set_drvdata(pdev, hw);
-
- hw->master = master;
- hw->dev = dev;
- hw->select = pdata->select;
-
- spin_lock_init(&hw->lock);
- init_completion(&hw->complete);
- INIT_LIST_HEAD(&hw->msg_queue);
- INIT_WORK(&hw->work, ti_ssp_spi_work);
-
- hw->workqueue = create_singlethread_workqueue(dev_name(dev));
- if (!hw->workqueue) {
- error = -ENOMEM;
- dev_err(dev, "work queue creation failed\n");
- goto error_wq;
- }
-
- error = ti_ssp_set_iosel(hw->dev, pdata->iosel);
- if (error < 0) {
- dev_err(dev, "io setup failed\n");
- goto error_iosel;
- }
-
- master->bus_num = pdev->id;
- master->num_chipselect = pdata->num_cs;
- master->mode_bits = MODE_BITS;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
- master->flags = SPI_MASTER_HALF_DUPLEX;
- master->transfer = ti_ssp_spi_transfer;
-
- error = spi_register_master(master);
- if (error) {
- dev_err(dev, "master registration failed\n");
- goto error_reg;
- }
-
- return 0;
-
-error_reg:
-error_iosel:
- destroy_workqueue(hw->workqueue);
-error_wq:
- spi_master_put(master);
- return error;
-}
-
-static int ti_ssp_spi_remove(struct platform_device *pdev)
-{
- struct ti_ssp_spi *hw = platform_get_drvdata(pdev);
- int error;
-
- hw->shutdown = 1;
- while (!list_empty(&hw->msg_queue)) {
- error = wait_for_completion_interruptible(&hw->complete);
- if (error < 0) {
- hw->shutdown = 0;
- return error;
- }
- }
- destroy_workqueue(hw->workqueue);
- spi_unregister_master(hw->master);
-
- return 0;
-}
-
-static struct platform_driver ti_ssp_spi_driver = {
- .probe = ti_ssp_spi_probe,
- .remove = ti_ssp_spi_remove,
- .driver = {
- .name = "ti-ssp-spi",
- .owner = THIS_MODULE,
- },
-};
-module_platform_driver(ti_ssp_spi_driver);
-
-MODULE_DESCRIPTION("SSP SPI Master");
-MODULE_AUTHOR("Cyril Chemparathy");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:ti-ssp-spi");
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index 2e7f38c7a961..f406b30af961 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -332,7 +332,7 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val,
data->transfer_active = false;
wake_up(&data->wait);
} else {
- dev_err(&data->master->dev,
+ dev_vdbg(&data->master->dev,
"%s : Transfer is not completed",
__func__);
}
@@ -464,20 +464,6 @@ static void pch_spi_reset(struct spi_master *master)
pch_spi_writereg(master, PCH_SRST, 0x0);
}
-static int pch_spi_setup(struct spi_device *pspi)
-{
- /* Check baud rate setting */
- /* if baud rate of chip is greater than
- max we can support,return error */
- if ((pspi->max_speed_hz) > PCH_MAX_BAUDRATE)
- pspi->max_speed_hz = PCH_MAX_BAUDRATE;
-
- dev_dbg(&pspi->dev, "%s MODE = %x\n", __func__,
- (pspi->mode) & (SPI_CPOL | SPI_CPHA));
-
- return 0;
-}
-
static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
{
@@ -486,23 +472,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
int retval;
unsigned long flags;
- /* validate spi message and baud rate */
- if (unlikely(list_empty(&pmsg->transfers) == 1)) {
- dev_err(&pspi->dev, "%s list empty\n", __func__);
- retval = -EINVAL;
- goto err_out;
- }
-
- if (unlikely(pspi->max_speed_hz == 0)) {
- dev_err(&pspi->dev, "%s pch_spi_transfer maxspeed=%d\n",
- __func__, pspi->max_speed_hz);
- retval = -EINVAL;
- goto err_out;
- }
-
- dev_dbg(&pspi->dev,
- "%s Transfer List not empty. Transfer Speed is set.\n", __func__);
-
spin_lock_irqsave(&data->lock, flags);
/* validate Tx/Rx buffers and Transfer length */
list_for_each_entry(transfer, &pmsg->transfers, transfer_list) {
@@ -523,10 +492,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
dev_dbg(&pspi->dev,
"%s Tx/Rx buffer valid. Transfer length valid\n",
__func__);
-
- /* if baud rate has been specified validate the same */
- if (transfer->speed_hz > PCH_MAX_BAUDRATE)
- transfer->speed_hz = PCH_MAX_BAUDRATE;
}
spin_unlock_irqrestore(&data->lock, flags);
@@ -915,7 +880,7 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw)
/* Set Tx DMA */
param = &dma->param_tx;
param->dma_dev = &dma_dev->dev;
- param->chan_id = data->master->bus_num * 2; /* Tx = 0, 2 */
+ param->chan_id = data->ch * 2; /* Tx = 0, 2 */;
param->tx_reg = data->io_base_addr + PCH_SPDWR;
param->width = width;
chan = dma_request_channel(mask, pch_spi_filter, param);
@@ -930,7 +895,7 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw)
/* Set Rx DMA */
param = &dma->param_rx;
param->dma_dev = &dma_dev->dev;
- param->chan_id = data->master->bus_num * 2 + 1; /* Rx = Tx + 1 */
+ param->chan_id = data->ch * 2 + 1; /* Rx = Tx + 1 */;
param->rx_reg = data->io_base_addr + PCH_SPDRR;
param->width = width;
chan = dma_request_channel(mask, pch_spi_filter, param);
@@ -1151,8 +1116,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
dma->nent = num;
dma->desc_tx = desc_tx;
- dev_dbg(&data->master->dev, "\n%s:Pulling down SSN low - writing "
- "0x2 to SSNXCR\n", __func__);
+ dev_dbg(&data->master->dev, "%s:Pulling down SSN low - writing 0x2 to SSNXCR\n", __func__);
spin_lock_irqsave(&data->lock, flags);
pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW);
@@ -1418,10 +1382,10 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
/* initialize members of SPI master */
master->num_chipselect = PCH_MAX_CS;
- master->setup = pch_spi_setup;
master->transfer = pch_spi_transfer;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
+ master->max_speed_hz = PCH_MAX_BAUDRATE;
data->board_dat = board_dat;
data->plat_dev = plat_dev;
@@ -1452,6 +1416,11 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
pch_spi_set_master_mode(master);
+ if (use_dma) {
+ dev_info(&plat_dev->dev, "Use DMA for data transfers\n");
+ pch_alloc_dma_buf(board_dat, data);
+ }
+
ret = spi_register_master(master);
if (ret != 0) {
dev_err(&plat_dev->dev,
@@ -1459,14 +1428,10 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
goto err_spi_register_master;
}
- if (use_dma) {
- dev_info(&plat_dev->dev, "Use DMA for data transfers\n");
- pch_alloc_dma_buf(board_dat, data);
- }
-
return 0;
err_spi_register_master:
+ pch_free_dma_buf(board_dat, data);
free_irq(board_dat->pdev->irq, data);
err_request_irq:
pch_spi_free_resources(board_dat, data);
@@ -1604,8 +1569,7 @@ static struct platform_driver pch_spi_pd_driver = {
.resume = pch_spi_pd_resume
};
-static int pch_spi_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
+static int pch_spi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct pch_spi_board_data *board_dat;
struct platform_device *pd_dev = NULL;
@@ -1675,6 +1639,8 @@ static int pch_spi_probe(struct pci_dev *pdev,
return 0;
err_platform_device:
+ while (--i >= 0)
+ platform_device_unregister(pd_dev_save->pd_save[i]);
pci_disable_device(pdev);
pci_enable_device:
pci_release_regions(pdev);
diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c
index 6191ced514b2..820b499816f8 100644
--- a/drivers/spi/spi-txx9.c
+++ b/drivers/spi/spi-txx9.c
@@ -80,7 +80,6 @@ struct txx9spi {
void __iomem *membase;
int baseclk;
struct clk *clk;
- u32 max_speed_hz, min_speed_hz;
int last_chipselect;
int last_chipselect_val;
};
@@ -117,9 +116,7 @@ static int txx9spi_setup(struct spi_device *spi)
{
struct txx9spi *c = spi_master_get_devdata(spi->master);
- if (!spi->max_speed_hz
- || spi->max_speed_hz > c->max_speed_hz
- || spi->max_speed_hz < c->min_speed_hz)
+ if (!spi->max_speed_hz)
return -EINVAL;
if (gpio_direction_output(spi->chip_select,
@@ -309,15 +306,8 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
/* check each transfer's parameters */
list_for_each_entry(t, &m->transfers, transfer_list) {
- u32 speed_hz = t->speed_hz ? : spi->max_speed_hz;
- u8 bits_per_word = t->bits_per_word;
-
if (!t->tx_buf && !t->rx_buf && t->len)
return -EINVAL;
- if (t->len & ((bits_per_word >> 3) - 1))
- return -EINVAL;
- if (speed_hz < c->min_speed_hz || speed_hz > c->max_speed_hz)
- return -EINVAL;
}
spin_lock_irqsave(&c->lock, flags);
@@ -360,17 +350,12 @@ static int txx9spi_probe(struct platform_device *dev)
goto exit;
}
c->baseclk = clk_get_rate(c->clk);
- c->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1);
- c->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1);
+ master->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1);
+ master->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1);
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (!res)
- goto exit_busy;
- if (!devm_request_mem_region(&dev->dev, res->start, resource_size(res),
- "spi_txx9"))